@redocly/openapi-core 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/lib/bundle.d.ts +2 -2
  3. package/lib/bundle.js +24 -22
  4. package/lib/config/builtIn.js +4 -0
  5. package/lib/config/config-resolvers.js +19 -6
  6. package/lib/config/config.d.ts +9 -9
  7. package/lib/config/config.js +32 -17
  8. package/lib/config/rules.d.ts +2 -2
  9. package/lib/config/types.d.ts +9 -3
  10. package/lib/index.d.ts +1 -1
  11. package/lib/index.js +7 -6
  12. package/lib/lint.js +10 -16
  13. package/lib/oas-types.d.ts +16 -10
  14. package/lib/oas-types.js +52 -26
  15. package/lib/rules/async2/channels-kebab-case.d.ts +2 -0
  16. package/lib/rules/async2/channels-kebab-case.js +19 -0
  17. package/lib/rules/async2/index.d.ts +12 -0
  18. package/lib/rules/async2/index.js +22 -0
  19. package/lib/rules/async2/no-channel-trailing-slash.d.ts +2 -0
  20. package/lib/rules/async2/no-channel-trailing-slash.js +16 -0
  21. package/lib/rules/common/scalar-property-missing-example.js +1 -1
  22. package/lib/rules/common/spec.d.ts +2 -2
  23. package/lib/rules/common/spec.js +3 -3
  24. package/lib/rules/oas2/index.js +1 -1
  25. package/lib/rules/oas3/index.js +1 -1
  26. package/lib/types/asyncapi.d.ts +2 -0
  27. package/lib/types/asyncapi.js +1027 -0
  28. package/lib/types/redocly-yaml.js +3 -0
  29. package/lib/typings/asyncapi.d.ts +21 -0
  30. package/lib/typings/asyncapi.js +2 -0
  31. package/lib/visitors.d.ts +12 -0
  32. package/lib/walk.d.ts +3 -3
  33. package/package.json +2 -1
  34. package/src/__tests__/lint.test.ts +36 -6
  35. package/src/bundle.ts +27 -28
  36. package/src/config/__tests__/__snapshots__/config.test.ts.snap +24 -0
  37. package/src/config/__tests__/config.test.ts +15 -4
  38. package/src/config/builtIn.ts +4 -0
  39. package/src/config/config-resolvers.ts +25 -6
  40. package/src/config/config.ts +51 -27
  41. package/src/config/rules.ts +2 -2
  42. package/src/config/types.ts +14 -4
  43. package/src/index.ts +7 -1
  44. package/src/lint.ts +13 -22
  45. package/src/oas-types.ts +59 -21
  46. package/src/rules/async2/__tests__/channels-kebab-case.test.ts +141 -0
  47. package/src/rules/async2/__tests__/no-channel-trailing-slash.test.ts +97 -0
  48. package/src/rules/async2/channels-kebab-case.ts +18 -0
  49. package/src/rules/async2/index.ts +22 -0
  50. package/src/rules/async2/no-channel-trailing-slash.ts +15 -0
  51. package/src/rules/common/scalar-property-missing-example.ts +2 -2
  52. package/src/rules/common/spec.ts +2 -2
  53. package/src/rules/oas2/index.ts +2 -2
  54. package/src/rules/oas3/index.ts +2 -2
  55. package/src/types/asyncapi.ts +1136 -0
  56. package/src/types/redocly-yaml.ts +3 -0
  57. package/src/typings/asyncapi.ts +26 -0
  58. package/src/visitors.ts +22 -0
  59. package/src/walk.ts +3 -3
  60. package/tsconfig.tsbuildinfo +1 -1
@@ -0,0 +1,97 @@
1
+ import { outdent } from 'outdent';
2
+ import { lintDocument } from '../../../lint';
3
+ import { parseYamlToDocument, replaceSourceWithRef, makeConfig } from '../../../../__tests__/utils';
4
+ import { BaseResolver } from '../../../resolve';
5
+
6
+ describe('no-channel-trailing-slash', () => {
7
+ it('should report on trailing slash in a channel path', async () => {
8
+ const document = parseYamlToDocument(
9
+ outdent`
10
+ asyncapi: '2.6.0'
11
+ info:
12
+ title: Excellent API
13
+ version: 1.0.0
14
+ channels:
15
+ /trailing/:
16
+ subscribe:
17
+ message:
18
+ messageId: Message1
19
+ `,
20
+ 'asyncapi.yaml'
21
+ );
22
+
23
+ const results = await lintDocument({
24
+ externalRefResolver: new BaseResolver(),
25
+ document,
26
+ config: await makeConfig({ 'no-channel-trailing-slash': 'error' }),
27
+ });
28
+
29
+ expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
30
+ Array [
31
+ Object {
32
+ "location": Array [
33
+ Object {
34
+ "pointer": "#/channels/~1trailing~1",
35
+ "reportOnKey": true,
36
+ "source": "asyncapi.yaml",
37
+ },
38
+ ],
39
+ "message": "\`/trailing/\` should not have a trailing slash.",
40
+ "ruleId": "no-channel-trailing-slash",
41
+ "severity": "error",
42
+ "suggest": Array [],
43
+ },
44
+ ]
45
+ `);
46
+ });
47
+
48
+ it('should not report on if no trailing slash in path', async () => {
49
+ const document = parseYamlToDocument(
50
+ outdent`
51
+ asyncapi: '2.6.0'
52
+ info:
53
+ title: Excellent API
54
+ version: 1.0.0
55
+ channels:
56
+ /expected:
57
+ subscribe:
58
+ message:
59
+ messageId: Message1
60
+ `,
61
+ 'asyncapi.yaml'
62
+ );
63
+
64
+ const results = await lintDocument({
65
+ externalRefResolver: new BaseResolver(),
66
+ document,
67
+ config: await makeConfig({ 'no-channel-trailing-slash': 'error' }),
68
+ });
69
+
70
+ expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`Array []`);
71
+ });
72
+
73
+ it('should not report on trailing slash in path if the path is root', async () => {
74
+ const document = parseYamlToDocument(
75
+ outdent`
76
+ asyncapi: '2.6.0'
77
+ info:
78
+ title: Excellent API
79
+ version: 1.0.0
80
+ channels:
81
+ /:
82
+ subscribe:
83
+ message:
84
+ messageId: Message1
85
+ `,
86
+ 'foobar.yaml'
87
+ );
88
+
89
+ const results = await lintDocument({
90
+ externalRefResolver: new BaseResolver(),
91
+ document,
92
+ config: await makeConfig({ 'no-channel-trailing-slash': 'error' }),
93
+ });
94
+
95
+ expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`Array []`);
96
+ });
97
+ });
@@ -0,0 +1,18 @@
1
+ import { Async2Rule } from '../../visitors';
2
+ import { UserContext } from '../../walk';
3
+
4
+ export const ChannelsKebabCase: Async2Rule = () => {
5
+ return {
6
+ Channel(_channel: object, { report, key }: UserContext) {
7
+ const segments = (key as string)
8
+ .split(/[/.:]/) // split on / or : as likely channel namespacers
9
+ .filter((s) => s !== ''); // filter out empty segments
10
+ if (!segments.every((segment) => /^{.+}$/.test(segment) || /^[a-z0-9-.]+$/.test(segment))) {
11
+ report({
12
+ message: `\`${key}\` does not use kebab-case.`,
13
+ location: { reportOnKey: true },
14
+ });
15
+ }
16
+ },
17
+ };
18
+ };
@@ -0,0 +1,22 @@
1
+ import { Async2Rule } from '../../visitors';
2
+ import { Assertions } from '../common/assertions';
3
+ import { Spec } from '../common/spec';
4
+ import { InfoContact } from '../common/info-contact';
5
+ import { OperationOperationId } from '../common/operation-operationId';
6
+ import { TagDescription } from '../common/tag-description';
7
+ import { TagsAlphabetical } from '../common/tags-alphabetical';
8
+ import { ChannelsKebabCase } from './channels-kebab-case';
9
+ import { NoChannelTrailingSlash } from './no-channel-trailing-slash';
10
+
11
+ export const rules = {
12
+ spec: Spec as Async2Rule,
13
+ assertions: Assertions,
14
+ 'info-contact': InfoContact,
15
+ 'operation-operationId': OperationOperationId,
16
+ 'channels-kebab-case': ChannelsKebabCase,
17
+ 'no-channel-trailing-slash': NoChannelTrailingSlash,
18
+ 'tag-description': TagDescription,
19
+ 'tags-alphabetical': TagsAlphabetical,
20
+ };
21
+
22
+ export const preprocessors = {};
@@ -0,0 +1,15 @@
1
+ import { Async2Rule } from '../../visitors';
2
+ import { UserContext } from '../../walk';
3
+
4
+ export const NoChannelTrailingSlash: Async2Rule = () => {
5
+ return {
6
+ Channel(_channel: any, { report, key, location }: UserContext) {
7
+ if ((key as string).endsWith('/') && key !== '/') {
8
+ report({
9
+ message: `\`${key}\` should not have a trailing slash.`,
10
+ location: location.key(),
11
+ });
12
+ }
13
+ },
14
+ };
15
+ };
@@ -2,7 +2,7 @@ import type { Oas2Rule, Oas3Rule } from '../../visitors';
2
2
  import type { UserContext } from '../../walk';
3
3
  import type { Oas2Schema } from '../../typings/swagger';
4
4
  import type { Oas3Schema, Oas3_1Schema } from '../../typings/openapi';
5
- import { OasVersion } from '../../oas-types';
5
+ import { SpecVersion } from '../../oas-types';
6
6
 
7
7
  const SCALAR_TYPES = ['string', 'integer', 'number', 'boolean', 'null'];
8
8
 
@@ -25,7 +25,7 @@ export const ScalarPropertyMissingExample: Oas3Rule | Oas2Rule = () => {
25
25
  ) {
26
26
  report({
27
27
  message: `Scalar property should have "example"${
28
- oasVersion === OasVersion.Version3_1 ? ' or "examples"' : ''
28
+ oasVersion === SpecVersion.OAS3_1 ? ' or "examples"' : ''
29
29
  } defined.`,
30
30
  location: location.child(propName).key(),
31
31
  });
@@ -1,11 +1,11 @@
1
- import type { Oas3Rule, Oas2Rule } from '../../visitors';
1
+ import type { Oas3Rule, Oas2Rule, Async2Rule } from '../../visitors';
2
2
  import { isNamedType, SpecExtension } from '../../types';
3
3
  import { oasTypeOf, matchesJsonSchemaType, getSuggest, validateSchemaEnumType } from '../utils';
4
4
  import { isRef } from '../../ref-utils';
5
5
  import { isPlainObject } from '../../utils';
6
6
  import { UserContext } from '../../walk';
7
7
 
8
- export const OasSpec: Oas3Rule | Oas2Rule = () => {
8
+ export const Spec: Oas3Rule | Oas2Rule | Async2Rule = () => {
9
9
  return {
10
10
  any(
11
11
  node: any,
@@ -1,5 +1,5 @@
1
1
  import { Oas2Rule } from '../../visitors';
2
- import { OasSpec } from '../common/spec';
2
+ import { Spec } from '../common/spec';
3
3
  import { NoInvalidSchemaExamples } from '../common/no-invalid-schema-examples';
4
4
  import { NoInvalidParameterExamples } from '../common/no-invalid-parameter-examples';
5
5
  import { InfoContact } from '../common/info-contact';
@@ -43,7 +43,7 @@ import { RequiredStringPropertyMissingMinLength } from '../common/required-strin
43
43
  import { SpecStrictRefs } from '../common/spec-strict-refs';
44
44
 
45
45
  export const rules = {
46
- spec: OasSpec as Oas2Rule,
46
+ spec: Spec as Oas2Rule,
47
47
  'no-invalid-schema-examples': NoInvalidSchemaExamples,
48
48
  'no-invalid-parameter-examples': NoInvalidParameterExamples,
49
49
  'info-contact': InfoContact as Oas2Rule,
@@ -1,5 +1,5 @@
1
1
  import { Oas3RuleSet } from '../../oas-types';
2
- import { OasSpec } from '../common/spec';
2
+ import { Spec } from '../common/spec';
3
3
  import { Operation2xxResponse } from '../common/operation-2xx-response';
4
4
  import { Operation4xxResponse } from '../common/operation-4xx-response';
5
5
  import { Assertions } from '../common/assertions';
@@ -54,7 +54,7 @@ import { SpecStrictRefs } from '../common/spec-strict-refs';
54
54
  import { ComponentNameUnique } from './component-name-unique';
55
55
 
56
56
  export const rules = {
57
- spec: OasSpec,
57
+ spec: Spec,
58
58
  'info-contact': InfoContact,
59
59
  'info-license': InfoLicense,
60
60
  'info-license-url': InfoLicenseUrl,