Feature: Add component-name-unique rule (#1134)

This commit is contained in:
Patrick Boos
2023-07-03 15:10:00 +02:00
committed by GitHub
parent 0ce9cab59a
commit 63067e9d0d
10 changed files with 1121 additions and 0 deletions

View File

@@ -0,0 +1,109 @@
# component-name-unique
Verifies component names are unique.
|OAS|Compatibility|
|---|--|
|2.0|❌|
|3.0|✅|
|3.1|✅|
## API design principles
When generating code based on an OpenAPI definition, there are various different problems when component names are not
unique through the whole spec.
- schema: The code generator creates a class for each schema.
If they are not uniquely named, the generator appends numbers. These numbers are non-deterministic.
By adding a new schema with the same component name it could change the name (appended number) of another one.
- parameter: The code generator creates a class for each parameter.
If they are not uniquely named, the generator appends numbers. These numbers are non-deterministic.
By adding a new parameter with the same component name it could change the name (appended number) of another one.
- response: The code generator tends to reuse the first one and drops the other ones with the same component name.
- requestBody: The code generator tends to reuse the first one and drops the other ones with the same component name.
This clearly is not optimal. Having unique component names prevents these problems.
## Configuration
| Option |Type| Description |
|---------------|---|------------------------------------------------------------------------------------------|
| severity |string| Possible values: `off`, `warn`, `error`. Default `off` (in `recommended` configuration). |
| schemas |string| Possible values: `off`, `warn`, `error`. Default: not set. |
| parameters |string| Possible values: `off`, `warn`, `error`. Default: not set. |
| responses |string| Possible values: `off`, `warn`, `error`. Default: not set. |
| requestBodies |string| Possible values: `off`, `warn`, `error`. Default: not set. |
An example configuration:
```yaml
rules:
component-name-unique:
schemas: error
parameters: off
responses: warn
requestBodies: warn
```
## Examples
Given this configuration:
```yaml
rules:
component-name-unique: error
```
### Example of **incorrect** schema files
file1.yaml:
```yaml
components:
schemas:
FooSchema:
type: object
properties:
field:
$ref: './file2.yaml#/components/schemas/FooSchema'
```
file2.yaml:
```yaml
components:
schemas:
FooSchema:
type: object
properties:
otherField:
type: string
```
### Example of **correct** schema files
file1.yaml:
```yaml
components:
schemas:
FooSchema:
type: object
properties:
field:
$ref: './file2.yaml#/components/schemas/AnotherFooSchema'
```
file2.yaml:
```yaml
components:
schemas:
AnotherFooSchema:
type: object
properties:
otherField:
type: string
```
## Relates rules
- [no-unused-components](./no-unused-components.md)

View File

@@ -38,6 +38,7 @@ Object {
"rules": Object {
"assertions": "warn",
"boolean-parameter-prefixes": "error",
"component-name-unique": "off",
"info-contact": "off",
"info-license": "warn",
"info-license-url": "warn",
@@ -128,6 +129,7 @@ Object {
},
],
"boolean-parameter-prefixes": "error",
"component-name-unique": "off",
"info-contact": "off",
"info-license": "warn",
"info-license-url": "warn",

View File

@@ -49,6 +49,7 @@ export default {
'no-invalid-parameter-examples': 'error',
'scalar-property-missing-example': 'error',
'spec-strict-refs': 'error',
'component-name-unique': 'error',
},
oas3_0Rules: {
'no-invalid-media-type-examples': 'error',

View File

@@ -32,6 +32,7 @@ export default {
'paths-kebab-case': 'off',
spec: 'error',
'spec-strict-refs': 'off',
'component-name-unique': 'off',
},
oas3_0Rules: {
'no-invalid-media-type-examples': {

View File

@@ -32,6 +32,7 @@ export default {
'paths-kebab-case': 'off',
spec: 'error',
'spec-strict-refs': 'off',
'component-name-unique': 'off',
},
oas3_0Rules: {
'no-invalid-media-type-examples': {

View File

@@ -0,0 +1,823 @@
import { outdent } from 'outdent';
import { parseYamlToDocument, replaceSourceWithRef } from '../../../../__tests__/utils';
import { lintDocumentForTest } from './utils/lint-document-for-test';
describe('Oas3 component-name-unique', () => {
describe('schema', () => {
it('should report on multiple schemas with same name', async () => {
const document = parseYamlToDocument(
outdent`
openapi: 3.0.0
components:
schemas:
SomeSchema:
type: object
Test:
type: object
properties:
there:
$ref: '/test.yaml#/components/schemas/SomeSchema'
`,
'/foobar.yaml'
);
const additionalDocuments = [
{
absoluteRef: '/test.yaml',
body: outdent`
openapi: 3.0.0
components:
schemas:
SomeSchema:
type: object
`,
},
];
const results = await lintDocumentForTest(
{ 'component-name-unique': 'error' },
document,
additionalDocuments
);
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
Array [
Object {
"location": Array [
Object {
"pointer": "#/",
"reportOnKey": false,
"source": "/foobar.yaml",
},
],
"message": "Component 'schemas/SomeSchema' is not unique. It is defined at:
- /foobar.yaml#/components/schemas/SomeSchema
- /test.yaml#/components/schemas/SomeSchema",
"ruleId": "component-name-unique",
"severity": "error",
"suggest": Array [],
},
]
`);
});
it('should report on multiple schemas with same name - filename', async () => {
const document = parseYamlToDocument(
outdent`
openapi: 3.0.0
components:
schemas:
SomeSchema:
type: object
Test:
type: object
properties:
there:
$ref: '/SomeSchema.yaml'
`,
'/foobar.yaml'
);
const additionalDocuments = [
{
absoluteRef: '/SomeSchema.yaml',
body: outdent`
type: object
properties:
test:
type: number
`,
},
];
const results = await lintDocumentForTest(
{ 'component-name-unique': 'error' },
document,
additionalDocuments
);
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
Array [
Object {
"location": Array [
Object {
"pointer": "#/",
"reportOnKey": false,
"source": "/foobar.yaml",
},
],
"message": "Component 'schemas/SomeSchema' is not unique. It is defined at:
- /foobar.yaml#/components/schemas/SomeSchema
- /SomeSchema.yaml",
"ruleId": "component-name-unique",
"severity": "error",
"suggest": Array [],
},
]
`);
});
it('should not report on multiple schemas with different names', async () => {
const document = parseYamlToDocument(
outdent`
openapi: 3.0.0
components:
schemas:
SomeSchema:
type: object
Test:
type: object
properties:
there:
$ref: '/test.yaml#/components/schemas/OtherSchema'
`,
'/foobar.yaml'
);
const additionalDocuments = [
{
absoluteRef: '/test.yaml',
body: outdent`
openapi: 3.0.0
components:
schemas:
OtherSchema:
type: object
`,
},
];
const results = await lintDocumentForTest(
{ 'component-name-unique': 'error' },
document,
additionalDocuments
);
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot('Array []');
});
});
describe('parameter', () => {
it('should report if multiple parameters have same component name', async () => {
const document = parseYamlToDocument(
outdent`
openapi: 3.0.0
paths:
/test:
get:
parameters:
- $ref: '#/components/parameters/ParameterOne'
- $ref: '/test.yaml#/components/parameters/ParameterOne'
components:
parameters:
ParameterOne:
name: parameterOne
in: query
schema:
type: integer
`,
'/foobar.yaml'
);
const additionalDocuments = [
{
absoluteRef: '/test.yaml',
body: outdent`
openapi: 3.0.0
components:
parameters:
ParameterOne:
name: oneParameter
in: query
schema:
type: integer
`,
},
];
const results = await lintDocumentForTest(
{ 'component-name-unique': 'error' },
document,
additionalDocuments
);
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
Array [
Object {
"location": Array [
Object {
"pointer": "#/",
"reportOnKey": false,
"source": "/foobar.yaml",
},
],
"message": "Component 'parameters/ParameterOne' is not unique. It is defined at:
- /foobar.yaml#/components/parameters/ParameterOne
- /test.yaml#/components/parameters/ParameterOne",
"ruleId": "component-name-unique",
"severity": "error",
"suggest": Array [],
},
]
`);
});
it('should report on multiple parameters with same component name - filename', async () => {
const document = parseYamlToDocument(
outdent`
openapi: 3.0.0
paths:
/test:
get:
parameters:
- $ref: '#/components/parameters/ParameterOne'
- $ref: '/ParameterOne.yaml'
components:
parameters:
ParameterOne:
name: parameterOne
in: query
schema:
type: integer
`,
'/foobar.yaml'
);
const additionalDocuments = [
{
absoluteRef: '/ParameterOne.yaml',
body: outdent`
name: oneParameter
in: query
schema:
type: integer
`,
},
];
const results = await lintDocumentForTest(
{ 'component-name-unique': 'error' },
document,
additionalDocuments
);
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
Array [
Object {
"location": Array [
Object {
"pointer": "#/",
"reportOnKey": false,
"source": "/foobar.yaml",
},
],
"message": "Component 'parameters/ParameterOne' is not unique. It is defined at:
- /foobar.yaml#/components/parameters/ParameterOne
- /ParameterOne.yaml",
"ruleId": "component-name-unique",
"severity": "error",
"suggest": Array [],
},
]
`);
});
it('should not report on multiple parameters with different component names', async () => {
const document = parseYamlToDocument(
outdent`
openapi: 3.0.0
paths:
/test:
get:
parameters:
- $ref: '#/components/parameters/ParameterOne'
- $ref: '/test.yaml#/components/parameters/OneParameter'
components:
parameters:
ParameterOne:
name: parameterOne
in: query
schema:
type: integer
`,
'/foobar.yaml'
);
const additionalDocuments = [
{
absoluteRef: '/test.yaml',
body: outdent`
openapi: 3.0.0
components:
parameters:
OneParameter:
name: oneParameter
in: query
schema:
type: integer
`,
},
];
const results = await lintDocumentForTest(
{ 'component-name-unique': 'error' },
document,
additionalDocuments
);
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot('Array []');
});
});
describe('response', () => {
it('should report if multiple responses have same component name', async () => {
const document = parseYamlToDocument(
outdent`
openapi: 3.0.0
paths:
/test:
get:
responses:
'200':
$ref: '#/components/responses/SuccessResponse'
/test2:
get:
responses:
'200':
$ref: '/test.yaml#/components/responses/SuccessResponse'
components:
responses:
SuccessResponse:
description: Successful response
content:
application/json:
schema:
type: string
`,
'/foobar.yaml'
);
const additionalDocuments = [
{
absoluteRef: '/test.yaml',
body: outdent`
openapi: 3.0.0
components:
responses:
SuccessResponse:
description: Successful response
content:
application/json:
schema:
type: string
`,
},
];
const results = await lintDocumentForTest(
{ 'component-name-unique': 'error' },
document,
additionalDocuments
);
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
Array [
Object {
"location": Array [
Object {
"pointer": "#/",
"reportOnKey": false,
"source": "/foobar.yaml",
},
],
"message": "Component 'responses/SuccessResponse' is not unique. It is defined at:
- /foobar.yaml#/components/responses/SuccessResponse
- /test.yaml#/components/responses/SuccessResponse",
"ruleId": "component-name-unique",
"severity": "error",
"suggest": Array [],
},
]
`);
});
it('should report on multiple responses with same component name - filename', async () => {
const document = parseYamlToDocument(
outdent`
openapi: 3.0.0
paths:
/test:
get:
responses:
'200':
$ref: '#/components/responses/SuccessResponse'
/test2:
get:
responses:
'200':
$ref: '/SuccessResponse.yaml'
components:
responses:
SuccessResponse:
description: Successful response
content:
application/json:
schema:
type: string
`,
'/foobar.yaml'
);
const additionalDocuments = [
{
absoluteRef: '/SuccessResponse.yaml',
body: outdent`
description: Successful response
content:
application/json:
schema:
type: string
`,
},
];
const results = await lintDocumentForTest(
{ 'component-name-unique': 'error' },
document,
additionalDocuments
);
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
Array [
Object {
"location": Array [
Object {
"pointer": "#/",
"reportOnKey": false,
"source": "/foobar.yaml",
},
],
"message": "Component 'responses/SuccessResponse' is not unique. It is defined at:
- /foobar.yaml#/components/responses/SuccessResponse
- /SuccessResponse.yaml",
"ruleId": "component-name-unique",
"severity": "error",
"suggest": Array [],
},
]
`);
});
it('should not report on multiple responses with different component names', async () => {
const document = parseYamlToDocument(
outdent`
openapi: 3.0.0
paths:
/test:
get:
responses:
'200':
$ref: '#/components/responses/TestSuccessResponse'
/test2:
get:
responses:
'200':
$ref: '/test.yaml#/components/responses/Test2SuccessResponse'
components:
responses:
TestSuccessResponse:
description: Successful response
content:
application/json:
schema:
type: string
`,
'/foobar.yaml'
);
const additionalDocuments = [
{
absoluteRef: '/test.yaml',
body: outdent`
openapi: 3.0.0
components:
responses:
Test2SuccessResponse:
description: Successful response
content:
application/json:
schema:
type: string
`,
},
];
const results = await lintDocumentForTest(
{ 'component-name-unique': 'error' },
document,
additionalDocuments
);
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot('Array []');
});
});
describe('request-body', () => {
it('should report if multiple request bodies have same component name', async () => {
const document = parseYamlToDocument(
outdent`
openapi: 3.0.0
paths:
/test:
post:
requestBody:
$ref: '#/components/requestBodies/MyRequestBody'
/test2:
post:
requestBody:
$ref: '/test.yaml#/components/requestBodies/MyRequestBody'
components:
requestBodies:
MyRequestBody:
required: true
content:
application/json:
schema:
type: string
`,
'/foobar.yaml'
);
const additionalDocuments = [
{
absoluteRef: '/test.yaml',
body: outdent`
components:
requestBodies:
MyRequestBody:
required: true
content:
application/json:
schema:
type: string
`,
},
];
const results = await lintDocumentForTest(
{ 'component-name-unique': 'error' },
document,
additionalDocuments
);
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
Array [
Object {
"location": Array [
Object {
"pointer": "#/",
"reportOnKey": false,
"source": "/foobar.yaml",
},
],
"message": "Component 'requestBodies/MyRequestBody' is not unique. It is defined at:
- /foobar.yaml#/components/requestBodies/MyRequestBody
- /test.yaml#/components/requestBodies/MyRequestBody",
"ruleId": "component-name-unique",
"severity": "error",
"suggest": Array [],
},
]
`);
});
it('should report on multiple responses with same component name - filename', async () => {
const document = parseYamlToDocument(
outdent`
openapi: 3.0.0
paths:
/test:
post:
requestBody:
$ref: '#/components/requestBodies/MyRequestBody'
/test2:
post:
requestBody:
$ref: '/MyRequestBody.yaml'
components:
requestBodies:
MyRequestBody:
required: true
content:
application/json:
schema:
type: string
`,
'/foobar.yaml'
);
const additionalDocuments = [
{
absoluteRef: '/MyRequestBody.yaml',
body: outdent`
components:
requestBodies:
MyRequestBody:
required: true
content:
application/json:
schema:
type: string
`,
},
];
const results = await lintDocumentForTest(
{ 'component-name-unique': 'error' },
document,
additionalDocuments
);
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
Array [
Object {
"location": Array [
Object {
"pointer": "#/",
"reportOnKey": false,
"source": "/foobar.yaml",
},
],
"message": "Component 'requestBodies/MyRequestBody' is not unique. It is defined at:
- /foobar.yaml#/components/requestBodies/MyRequestBody
- /MyRequestBody.yaml",
"ruleId": "component-name-unique",
"severity": "error",
"suggest": Array [],
},
]
`);
});
it('should not report on multiple responses with different component names', async () => {
const document = parseYamlToDocument(
outdent`
openapi: 3.0.0
paths:
/test:
post:
requestBody:
$ref: '#/components/requestBodies/TestRequestBody'
/test2:
post:
requestBody:
$ref: '/test.yaml#/components/requestBodies/Test2RequestBody'
components:
requestBodies:
TestRequestBody:
required: true
content:
application/json:
schema:
type: string
`,
'/foobar.yaml'
);
const additionalDocuments = [
{
absoluteRef: '/test.yaml',
body: outdent`
components:
requestBodies:
Test2RequestBody:
required: true
content:
application/json:
schema:
type: string
`,
},
];
const results = await lintDocumentForTest(
{ 'component-name-unique': 'error' },
document,
additionalDocuments
);
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot('Array []');
});
});
describe('different severities', () => {
const document = parseYamlToDocument(
outdent`
openapi: 3.0.0
paths:
/test:
post:
requestBody:
$ref: '#/components/requestBodies/MyRequestBody'
/test2:
post:
requestBody:
$ref: '/test.yaml#/components/requestBodies/MyRequestBody'
components:
schemas:
SomeSchema:
type: object
Test:
type: object
properties:
there:
$ref: '/test.yaml#/components/schemas/SomeSchema'
requestBodies:
MyRequestBody:
required: true
content:
application/json:
schema:
type: string
`,
'/foobar.yaml'
);
const additionalDocuments = [
{
absoluteRef: '/test.yaml',
body: outdent`
components:
schemas:
SomeSchema:
type: object
requestBodies:
MyRequestBody:
required: true
content:
application/json:
schema:
type: string
`,
},
];
it('should report both schema and request body', async () => {
const results = await lintDocumentForTest(
{ 'component-name-unique': 'error' },
document,
additionalDocuments
);
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
Array [
Object {
"location": Array [
Object {
"pointer": "#/",
"reportOnKey": false,
"source": "/foobar.yaml",
},
],
"message": "Component 'requestBodies/MyRequestBody' is not unique. It is defined at:
- /foobar.yaml#/components/requestBodies/MyRequestBody
- /test.yaml#/components/requestBodies/MyRequestBody",
"ruleId": "component-name-unique",
"severity": "error",
"suggest": Array [],
},
Object {
"location": Array [
Object {
"pointer": "#/",
"reportOnKey": false,
"source": "/foobar.yaml",
},
],
"message": "Component 'schemas/SomeSchema' is not unique. It is defined at:
- /foobar.yaml#/components/schemas/SomeSchema
- /test.yaml#/components/schemas/SomeSchema",
"ruleId": "component-name-unique",
"severity": "error",
"suggest": Array [],
},
]
`);
});
it('should not report if severity is off for specific component type', async () => {
const results = await lintDocumentForTest(
{ 'component-name-unique': { severity: 'error', schemas: 'off' } },
document,
additionalDocuments
);
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
Array [
Object {
"location": Array [
Object {
"pointer": "#/",
"reportOnKey": false,
"source": "/foobar.yaml",
},
],
"message": "Component 'requestBodies/MyRequestBody' is not unique. It is defined at:
- /foobar.yaml#/components/requestBodies/MyRequestBody
- /test.yaml#/components/requestBodies/MyRequestBody",
"ruleId": "component-name-unique",
"severity": "error",
"suggest": Array [],
},
]
`);
});
});
});

View File

@@ -0,0 +1,23 @@
import { BaseResolver, Document } from '../../../../resolve';
import { makeConfig, parseYamlToDocument } from '../../../../../__tests__/utils';
import { lintDocument } from '../../../../lint';
import { RuleConfig } from '../../../../config';
export async function lintDocumentForTest(
rules: Record<string, RuleConfig>,
document: Document,
additionalDocuments: { absoluteRef: string; body: string }[]
) {
const baseResolver = new BaseResolver();
additionalDocuments.forEach((item) =>
baseResolver.cache.set(
item.absoluteRef,
Promise.resolve(parseYamlToDocument(item.body, item.absoluteRef))
)
);
return await lintDocument({
externalRefResolver: baseResolver,
document,
config: await makeConfig(rules),
});
}

View File

@@ -0,0 +1,158 @@
import { Problem, UserContext } from '../../walk';
import { Oas2Rule, Oas3Rule, Oas3Visitor } from '../../visitors';
import {
Oas3Definition,
Oas3Parameter,
Oas3RequestBody,
Oas3Response,
Oas3Schema,
OasRef,
} from '../../typings/openapi';
const TYPE_NAME_SCHEMA = 'Schema';
const TYPE_NAME_PARAMETER = 'Parameter';
const TYPE_NAME_RESPONSE = 'Response';
const TYPE_NAME_REQUEST_BODY = 'RequestBody';
const TYPE_NAME_TO_OPTION_COMPONENT_NAME: { [key: string]: string } = {
[TYPE_NAME_SCHEMA]: 'schemas',
[TYPE_NAME_PARAMETER]: 'parameters',
[TYPE_NAME_RESPONSE]: 'responses',
[TYPE_NAME_REQUEST_BODY]: 'requestBodies',
};
export const ComponentNameUnique: Oas3Rule | Oas2Rule = (options) => {
const components = new Map<string, Set<string>>();
const typeNames: string[] = [];
if (options.schemas !== 'off') {
typeNames.push(TYPE_NAME_SCHEMA);
}
if (options.parameters !== 'off') {
typeNames.push(TYPE_NAME_PARAMETER);
}
if (options.responses !== 'off') {
typeNames.push(TYPE_NAME_RESPONSE);
}
if (options.requestBodies !== 'off') {
typeNames.push(TYPE_NAME_REQUEST_BODY);
}
const rule: Oas3Visitor = {
ref: {
leave(ref: OasRef, { type, resolve }: UserContext) {
const typeName = type.name;
if (typeNames.includes(typeName)) {
const resolvedRef = resolve(ref);
if (!resolvedRef.location) return;
addComponentFromAbsoluteLocation(
typeName,
resolvedRef.location.absolutePointer.toString()
);
}
},
},
Root: {
leave(root: Oas3Definition, ctx: UserContext) {
components.forEach((value, key, _) => {
if (value.size > 1) {
const component = getComponentFromKey(key);
const optionComponentName = getOptionComponentNameForTypeName(component.typeName);
const definitions = Array.from(value)
.map((v) => `- ${v}`)
.join('\n');
const problem: Problem = {
message: `Component '${optionComponentName}/${component.componentName}' is not unique. It is defined at:\n${definitions}`,
};
const componentSeverity = optionComponentName ? options[optionComponentName] : null;
if (componentSeverity) {
problem.forceSeverity = componentSeverity;
}
ctx.report(problem);
}
});
},
},
};
if (options.schemas != 'off') {
rule.NamedSchemas = {
Schema(_: Oas3Schema, { location }: UserContext) {
addComponentFromAbsoluteLocation(TYPE_NAME_SCHEMA, location.absolutePointer.toString());
},
};
}
if (options.responses != 'off') {
rule.NamedResponses = {
Response(_: Oas3Response, { location }: UserContext) {
addComponentFromAbsoluteLocation(TYPE_NAME_RESPONSE, location.absolutePointer.toString());
},
};
}
if (options.parameters != 'off') {
rule.NamedParameters = {
Parameter(_: Oas3Parameter, { location }: UserContext) {
addComponentFromAbsoluteLocation(TYPE_NAME_PARAMETER, location.absolutePointer.toString());
},
};
}
if (options.requestBodies != 'off') {
rule.NamedRequestBodies = {
RequestBody(_: Oas3RequestBody, { location }: UserContext) {
addComponentFromAbsoluteLocation(
TYPE_NAME_REQUEST_BODY,
location.absolutePointer.toString()
);
},
};
}
return rule;
function getComponentNameFromAbsoluteLocation(absoluteLocation: string): string {
const componentName = absoluteLocation.split('/').slice(-1)[0];
if (
componentName.endsWith('.yml') ||
componentName.endsWith('.yaml') ||
componentName.endsWith('.json')
) {
return componentName.slice(0, componentName.lastIndexOf('.'));
}
return componentName;
}
function addFoundComponent(
typeName: string,
componentName: string,
absoluteLocation: string
): void {
const key = getKeyForComponent(typeName, componentName);
const locations = components.get(key) ?? new Set();
locations.add(absoluteLocation);
components.set(key, locations);
}
function addComponentFromAbsoluteLocation(typeName: string, absoluteLocation: string): void {
const componentName = getComponentNameFromAbsoluteLocation(absoluteLocation);
addFoundComponent(typeName, componentName, absoluteLocation);
}
};
function getOptionComponentNameForTypeName(typeName: string): string | null {
return TYPE_NAME_TO_OPTION_COMPONENT_NAME[typeName] ?? null;
}
function getKeyForComponent(typeName: string, componentName: string): string {
return `${typeName}/${componentName}`;
}
function getComponentFromKey(key: string): { typeName: string; componentName: string } {
const [typeName, componentName] = key.split('/');
return { typeName, componentName };
}

View File

@@ -51,6 +51,7 @@ import { SpecComponentsInvalidMapName } from './spec-components-invalid-map-name
import { Operation4xxProblemDetailsRfc7807 } from './operation-4xx-problem-details-rfc7807';
import { RequiredStringPropertyMissingMinLength } from '../common/required-string-property-missing-min-length';
import { SpecStrictRefs } from '../common/spec-strict-refs';
import { ComponentNameUnique } from './component-name-unique';
export const rules = {
spec: OasSpec,
@@ -106,6 +107,7 @@ export const rules = {
'spec-components-invalid-map-name': SpecComponentsInvalidMapName,
'required-string-property-missing-min-length': RequiredStringPropertyMissingMinLength,
'spec-strict-refs': SpecStrictRefs,
'component-name-unique': ComponentNameUnique,
} as Oas3RuleSet;
export const preprocessors = {};

View File

@@ -67,6 +67,7 @@ const builtInRulesList = [
'spec-components-invalid-map-name',
'required-string-property-missing-min-length',
'spec-strict-refs',
'component-name-unique',
];
const nodeTypesList = [
'any',