Replace oas2-unused-definition with az-unused-definition

This commit is contained in:
Mike Kistler 2024-04-01 09:04:15 -05:00
Родитель c8abf06444
Коммит 28dde0808b
3 изменённых файлов: 225 добавлений и 0 удалений

Просмотреть файл

@ -0,0 +1,44 @@
// Check all definitions in the document to see if they are used
// Use the spectral unreferencedReusableObject to find its list of unused definitions,
// and then remove any that `allOf` a used schema.
const { unreferencedReusableObject } = require('@stoplight/spectral-functions');
const isObject = (obj) => obj && typeof obj === 'object';
// given should point to the member holding the potential reusable objects.
module.exports = (given, _, context) => {
if (!isObject(given)) {
return [];
}
const opts = {
reusableObjectsLocation: '#/definitions',
};
const unreferencedDefinitionErrors = unreferencedReusableObject(given, opts, context);
const unusedDefinitions = unreferencedDefinitionErrors.map((error) => error.path[1]);
const allOfsUsedSchema = (schemaName) => {
const schema = given[schemaName];
if (!isObject(schema) || !Array.isArray(schema.allOf)) {
return false;
}
return schema.allOf.some((subSchema) => {
if (!isObject(subSchema) || !subSchema.$ref) {
return false;
}
const reffedSchema = subSchema.$ref.split('/').pop();
if (unusedDefinitions.includes(reffedSchema)) {
return false;
}
return true;
});
};
return unreferencedDefinitionErrors.filter(
(error) => !allOfsUsedSchema(error.path[1]),
);
};

Просмотреть файл

@ -22,12 +22,14 @@ functions:
- security-definitions
- security-requirements
- schema-type-and-format
- unused-definition
- version-policy
rules:
info-contact: off
no-$ref-siblings: off
oas2-api-host: off
oas2-api-schemes: off
oas2-unused-definition: off
openapi-tags: off
operation-description: off
operation-tags: off
@ -706,6 +708,15 @@ rules:
field: schema
function: truthy
az-unused-definition:
description: Potentially unused definition has been detected.
severity: warn
formats: ['oas2']
resolved: false
given: $.definitions
then:
function: unused-definition
az-version-convention:
description: API version should be a date in YYYY-MM-DD format, optionally suffixed with '-preview'.
severity: error

Просмотреть файл

@ -0,0 +1,170 @@
const { linterForRule } = require('./utils');
let linter;
beforeAll(async () => {
linter = await linterForRule('az-unused-definition');
return linter;
});
test('az-unused-definition should find errors', () => {
const oasDoc = {
swagger: '2.0',
paths: {
'/test1': {
post: {
parameters: [
{
in: 'body',
name: 'body',
schema: {
type: 'string',
},
},
],
responses: {
200: {
description: 'Success',
schema: {
type: 'string',
},
},
},
},
},
},
definitions: {
Model1: {
type: 'object',
allOf: [
{
$ref: '#/definitions/Model3',
},
],
},
Model2: {
type: 'object',
properties: {
id: {
type: 'string',
},
},
},
Model3: {
type: 'object',
properties: {
foo: {
type: 'string',
},
},
},
},
};
return linter.run(oasDoc).then((results) => {
expect(results.length).toBe(1);
// Note: Model3 is not flagged as unused because it is used in Model1,
// even though Model1 is not used. And the new logic now filters out the
// error for Model1 because it allOfs Model3.
expect(results[0].path.join('.')).toBe('definitions.Model2');
});
});
test('az-unused-definition should not find errors', () => {
const oasDoc = {
swagger: '2.0',
paths: {
'/test1': {
post: {
parameters: [
{
in: 'body',
name: 'body',
schema: {
$ref: '#/definitions/Model1',
},
},
],
responses: {
200: {
description: 'Success',
schema: {
$ref: '#/definitions/Model2',
},
},
},
},
},
'/test2': {
post: {
parameters: [
{
in: 'body',
name: 'body',
schema: {
$ref: '#/definitions/Model4',
},
},
],
responses: {
200: {
description: 'Success',
schema: {
$ref: '#/definitions/Model3',
},
},
},
},
},
},
definitions: {
Model1: {
type: 'object',
allOf: [
{
$ref: '#/definitions/Model3',
},
],
},
Model2: {
type: 'object',
properties: {
id: {
type: 'string',
},
},
},
Model3: {
type: 'object',
properties: {
foo: {
type: 'string',
},
},
},
Model4: {
type: 'object',
properties: {
id: {
type: 'string',
},
},
},
Model5: {
type: 'object',
properties: {
bar: {
type: 'string',
},
},
allOf: [
{
$ref: '#/definitions/Model4',
},
],
},
},
};
return linter.run(oasDoc).then((results) => {
expect(results.length).toBe(0);
});
});