-
Notifications
You must be signed in to change notification settings - Fork 222
feat: new rule scalar-property-missing-example #705
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
efc7613
feat: new rule scalar-property-missing-example
RomanHotsiy 9e999be
fix: fail job if tests fail
roman-sainchuk c8986e2
chore: make CI fail on failing tests
tatomyr f3e8156
chore: test coverage
roman-sainchuk 24bbdd1
chore: add typecheck step
roman-sainchuk daba96f
docs: add description to the scalar-property-missing-example rule
tatomyr b23f224
chore: redundand env variable
roman-sainchuk 27bd554
chore: try without test script
roman-sainchuk e781ed8
chore: revert try without test-script
roman-sainchuk 43281a8
Update docs/resources/built-in-rules.md
ivana-isadora 7c59f63
chore: write unit tests
tatomyr 5d285f8
chore: update imports
tatomyr 6ed01e9
chore: use jest from installed deps
roman-sainchuk 027a263
chore: revert CI changes
tatomyr 47c0cf6
chore: revert package.json
tatomyr File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
207 changes: 207 additions & 0 deletions
207
packages/core/src/rules/common/__tests__/scalar-property-missing-example.test.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,207 @@ | ||
| import { outdent } from 'outdent'; | ||
| import { lintDocument } from '../../../lint'; | ||
| import { parseYamlToDocument, replaceSourceWithRef, makeConfig } from '../../../../__tests__/utils'; | ||
| import { BaseResolver } from '../../../resolve'; | ||
|
|
||
| describe('Oas3 scalar-property-missing-example', () => { | ||
| it('should report on a scalar property missing example', async () => { | ||
| const document = parseYamlToDocument( | ||
| outdent` | ||
| openapi: 3.0.0 | ||
| components: | ||
| schemas: | ||
| User: | ||
| type: object | ||
| properties: | ||
| email: | ||
| description: User email address | ||
| type: string | ||
| format: email | ||
| `, | ||
| 'foobar.yaml', | ||
| ); | ||
|
|
||
| const results = await lintDocument({ | ||
| externalRefResolver: new BaseResolver(), | ||
| document, | ||
| config: await makeConfig({ 'scalar-property-missing-example': 'error' }), | ||
| }); | ||
|
|
||
| expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(` | ||
| Array [ | ||
| Object { | ||
| "location": Array [ | ||
| Object { | ||
| "pointer": "#/components/schemas/User/properties/email", | ||
| "reportOnKey": true, | ||
| "source": "foobar.yaml", | ||
| }, | ||
| ], | ||
| "message": "Scalar property should have \\"example\\" defined.", | ||
| "ruleId": "scalar-property-missing-example", | ||
| "severity": "error", | ||
| "suggest": Array [], | ||
| }, | ||
| ] | ||
| `); | ||
| }); | ||
| }); | ||
|
|
||
| describe('Oas3.1 scalar-property-missing-example', () => { | ||
| it('should report on a scalar property missing example', async () => { | ||
| const document = parseYamlToDocument( | ||
| outdent` | ||
| openapi: 3.1.0 | ||
| components: | ||
| schemas: | ||
| User: | ||
| type: object | ||
| properties: | ||
| email: | ||
| description: User email address | ||
| type: string | ||
| format: email | ||
| `, | ||
| 'foobar.yaml', | ||
| ); | ||
|
|
||
| const results = await lintDocument({ | ||
| externalRefResolver: new BaseResolver(), | ||
| document, | ||
| config: await makeConfig({ 'scalar-property-missing-example': 'error' }), | ||
| }); | ||
|
|
||
| expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(` | ||
| Array [ | ||
| Object { | ||
| "location": Array [ | ||
| Object { | ||
| "pointer": "#/components/schemas/User/properties/email", | ||
| "reportOnKey": true, | ||
| "source": "foobar.yaml", | ||
| }, | ||
| ], | ||
| "message": "Scalar property should have \\"example\\" or \\"examples\\" defined.", | ||
| "ruleId": "scalar-property-missing-example", | ||
| "severity": "error", | ||
| "suggest": Array [], | ||
| }, | ||
| ] | ||
| `); | ||
| }); | ||
|
|
||
| it('should not report on a scalar property with an example', async () => { | ||
| const document = parseYamlToDocument( | ||
| outdent` | ||
| openapi: 3.1.0 | ||
| components: | ||
| schemas: | ||
| User: | ||
| type: object | ||
| properties: | ||
| email: | ||
| description: User email address | ||
| type: string | ||
| format: email | ||
| example: john.smith@example.com | ||
| `, | ||
| 'foobar.yaml', | ||
| ); | ||
|
|
||
| const results = await lintDocument({ | ||
| externalRefResolver: new BaseResolver(), | ||
| document, | ||
| config: await makeConfig({ 'scalar-property-missing-example': 'error' }), | ||
| }); | ||
|
|
||
| expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`Array []`); | ||
| }); | ||
|
|
||
| it('should not report on a scalar property with an examples', async () => { | ||
| const document = parseYamlToDocument( | ||
| outdent` | ||
| openapi: 3.1.0 | ||
| components: | ||
| schemas: | ||
| User: | ||
| type: object | ||
| properties: | ||
| email: | ||
| description: User email address | ||
| type: string | ||
| format: email | ||
| examples: | ||
| - john.smith@example.com | ||
| - other@example.com | ||
| `, | ||
| 'foobar.yaml', | ||
| ); | ||
|
|
||
| const results = await lintDocument({ | ||
| externalRefResolver: new BaseResolver(), | ||
| document, | ||
| config: await makeConfig({ 'scalar-property-missing-example': 'error' }), | ||
| }); | ||
|
|
||
| expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`Array []`); | ||
| }); | ||
|
|
||
| it('should not report on a non-scalar property missing an example', async () => { | ||
| const document = parseYamlToDocument( | ||
| outdent` | ||
| openapi: 3.1.0 | ||
| components: | ||
| schemas: | ||
| Pet: | ||
| type: object | ||
| required: | ||
| - photoUrls | ||
| properties: | ||
| photoUrls: | ||
| description: The list of URL to a cute photos featuring pet | ||
| type: array | ||
| maxItems: 20 | ||
| xml: | ||
| name: photoUrl | ||
| wrapped: true | ||
| items: | ||
| type: string | ||
| format: url | ||
| `, | ||
| 'foobar.yaml', | ||
| ); | ||
|
|
||
| const results = await lintDocument({ | ||
| externalRefResolver: new BaseResolver(), | ||
| document, | ||
| config: await makeConfig({ 'scalar-property-missing-example': 'error' }), | ||
| }); | ||
|
|
||
| expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`Array []`); | ||
| }); | ||
|
|
||
| it('should not report on a scalar property of binary format missing an example', async () => { | ||
| const document = parseYamlToDocument( | ||
| outdent` | ||
| openapi: 3.1.0 | ||
| components: | ||
| schemas: | ||
| User: | ||
| type: object | ||
| properties: | ||
| responses: | ||
| type: string | ||
| format: binary | ||
| `, | ||
| 'foobar.yaml', | ||
| ); | ||
|
|
||
| const results = await lintDocument({ | ||
| externalRefResolver: new BaseResolver(), | ||
| document, | ||
| config: await makeConfig({ 'scalar-property-missing-example': 'error' }), | ||
| }); | ||
|
|
||
| expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`Array []`); | ||
| }); | ||
| }); |
55 changes: 55 additions & 0 deletions
55
packages/core/src/rules/common/scalar-property-missing-example.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| import type { Oas2Rule, Oas3Rule } from '../../visitors'; | ||
| import type { UserContext } from '../../walk'; | ||
| import type { Oas2Schema } from '../../typings/swagger'; | ||
| import type { Oas3Schema, Oas3_1Schema } from '../../typings/openapi'; | ||
| import { OasVersion } from '../../oas-types'; | ||
|
|
||
| const SCALAR_TYPES = ['string', 'integer', 'number', 'boolean', 'null']; | ||
|
|
||
| export const ScalarPropertyMissingExample: Oas3Rule | Oas2Rule = () => { | ||
| return { | ||
| SchemaProperties( | ||
| properties: { [name: string]: Oas2Schema | Oas3Schema | Oas3_1Schema }, | ||
| { report, location, oasVersion, resolve }: UserContext, | ||
| ) { | ||
| for (const propName of Object.keys(properties)) { | ||
| const propSchema = resolve(properties[propName]).node; | ||
|
|
||
| if (!propSchema || !isScalarSchema(propSchema)) { | ||
| continue; | ||
| } | ||
|
|
||
| if (!propSchema.example && !(propSchema as Oas3_1Schema).examples) { | ||
| report({ | ||
| message: `Scalar property should have "example"${ | ||
| oasVersion === OasVersion.Version3_1 ? ' or "examples"' : '' | ||
| } defined.`, | ||
| location: location.child(propName).key(), | ||
| }); | ||
| } | ||
| } | ||
| }, | ||
| }; | ||
| }; | ||
|
|
||
| function isScalarSchema(schema: Oas2Schema | Oas3Schema | Oas3_1Schema) { | ||
| if (!schema.type) { | ||
| return false; | ||
| } | ||
|
|
||
| if (schema.allOf || (schema as Oas3Schema).anyOf || (schema as Oas3Schema).oneOf) { | ||
| // Skip allOf/oneOf/anyOf as it's complicated to validate it right now. | ||
| // We need core support for checking contrstrains through those keywords. | ||
| return false; | ||
| } | ||
|
|
||
| if (schema.format === 'binary') { | ||
| return false; | ||
| } | ||
|
|
||
| if (Array.isArray(schema.type)) { | ||
| return schema.type.every((t) => SCALAR_TYPES.includes(t)); | ||
| } | ||
|
|
||
| return SCALAR_TYPES.includes(schema.type); | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.