Replace oas2-unused-definition with az-unused-definition
This commit is contained in:
Родитель
c8abf06444
Коммит
28dde0808b
|
@ -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);
|
||||
});
|
||||
});
|
Загрузка…
Ссылка в новой задаче