@redocly/openapi-core 1.0.0-beta.108 → 1.0.0-beta.109

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 (132) hide show
  1. package/lib/benchmark/benches/resolve-with-no-external.bench.js +1 -1
  2. package/lib/bundle.d.ts +1 -1
  3. package/lib/bundle.js +4 -4
  4. package/lib/config/all.js +3 -1
  5. package/lib/config/config-resolvers.js +1 -1
  6. package/lib/config/minimal.js +3 -1
  7. package/lib/config/recommended.js +3 -1
  8. package/lib/config/rules.js +1 -1
  9. package/lib/config/types.d.ts +7 -0
  10. package/lib/config/utils.d.ts +2 -2
  11. package/lib/config/utils.js +42 -4
  12. package/lib/decorators/common/registry-dependencies.js +1 -1
  13. package/lib/format/format.d.ts +1 -1
  14. package/lib/format/format.js +22 -1
  15. package/lib/lint.js +2 -2
  16. package/lib/redocly/registry-api.d.ts +0 -1
  17. package/lib/redocly/registry-api.js +5 -4
  18. package/lib/resolve.js +3 -1
  19. package/lib/rules/common/no-ambiguous-paths.js +1 -1
  20. package/lib/rules/common/no-identical-paths.js +1 -1
  21. package/lib/rules/common/operation-2xx-response.js +1 -1
  22. package/lib/rules/common/operation-4xx-response.js +1 -1
  23. package/lib/rules/common/operation-operationId.js +1 -1
  24. package/lib/rules/common/operation-tag-defined.js +1 -1
  25. package/lib/rules/common/path-not-include-query.js +1 -1
  26. package/lib/rules/common/security-defined.d.ts +2 -0
  27. package/lib/rules/common/{operation-security-defined.js → security-defined.js} +18 -4
  28. package/lib/rules/common/spec.js +12 -1
  29. package/lib/rules/common/tags-alphabetical.js +1 -1
  30. package/lib/rules/oas2/index.d.ts +1 -1
  31. package/lib/rules/oas2/index.js +2 -2
  32. package/lib/rules/oas2/remove-unused-components.js +1 -1
  33. package/lib/rules/oas2/request-mime-type.js +1 -1
  34. package/lib/rules/oas2/response-mime-type.js +1 -1
  35. package/lib/rules/oas3/index.js +6 -2
  36. package/lib/rules/oas3/no-empty-servers.js +1 -1
  37. package/lib/rules/oas3/no-server-variables-empty-enum.js +1 -1
  38. package/lib/rules/oas3/no-unused-components.js +1 -1
  39. package/lib/rules/oas3/operation-4xx-problem-details-rfc7807.d.ts +5 -0
  40. package/lib/rules/oas3/operation-4xx-problem-details-rfc7807.js +36 -0
  41. package/lib/rules/oas3/remove-unused-components.js +1 -1
  42. package/lib/rules/oas3/request-mime-type.js +1 -1
  43. package/lib/rules/oas3/response-mime-type.js +1 -1
  44. package/lib/rules/oas3/spec-components-invalid-map-name.d.ts +2 -0
  45. package/lib/rules/oas3/spec-components-invalid-map-name.js +46 -0
  46. package/lib/rules/other/stats.d.ts +2 -2
  47. package/lib/rules/other/stats.js +2 -2
  48. package/lib/types/oas2.js +5 -5
  49. package/lib/types/oas3.js +27 -20
  50. package/lib/types/oas3_1.js +3 -3
  51. package/lib/types/redocly-yaml.js +46 -55
  52. package/lib/utils.d.ts +3 -3
  53. package/lib/utils.js +5 -5
  54. package/lib/visitors.d.ts +11 -11
  55. package/lib/visitors.js +13 -1
  56. package/package.json +1 -1
  57. package/src/__tests__/__snapshots__/bundle.test.ts.snap +3 -3
  58. package/src/__tests__/fixtures/extension.js +3 -3
  59. package/src/__tests__/format.test.ts +76 -0
  60. package/src/__tests__/lint.test.ts +106 -131
  61. package/src/__tests__/resolve-http.test.ts +1 -1
  62. package/src/__tests__/resolve.test.ts +9 -9
  63. package/src/__tests__/walk.test.ts +78 -10
  64. package/src/benchmark/benches/resolve-with-no-external.bench.ts +1 -1
  65. package/src/bundle.ts +4 -4
  66. package/src/config/__tests__/__snapshots__/config-resolvers.test.ts.snap +6 -2
  67. package/src/config/__tests__/fixtures/plugin-config.yaml +2 -3
  68. package/src/config/__tests__/fixtures/resolve-config/api/nested-config.yaml +11 -12
  69. package/src/config/__tests__/fixtures/resolve-config/local-config-with-circular.yaml +7 -8
  70. package/src/config/__tests__/fixtures/resolve-config/local-config-with-file.yaml +18 -19
  71. package/src/config/__tests__/fixtures/resolve-config/local-config.yaml +9 -10
  72. package/src/config/__tests__/fixtures/resolve-remote-configs/nested-remote-config.yaml +3 -4
  73. package/src/config/__tests__/fixtures/resolve-remote-configs/remote-config.yaml +4 -5
  74. package/src/config/__tests__/load.test.ts +12 -15
  75. package/src/config/__tests__/utils.test.ts +64 -4
  76. package/src/config/all.ts +3 -1
  77. package/src/config/config-resolvers.ts +2 -2
  78. package/src/config/load.ts +3 -2
  79. package/src/config/minimal.ts +3 -1
  80. package/src/config/recommended.ts +3 -1
  81. package/src/config/rules.ts +2 -2
  82. package/src/config/types.ts +11 -0
  83. package/src/config/utils.ts +102 -13
  84. package/src/decorators/common/registry-dependencies.ts +1 -1
  85. package/src/format/format.ts +32 -2
  86. package/src/lint.ts +2 -2
  87. package/src/redocly/registry-api.ts +5 -4
  88. package/src/resolve.ts +3 -1
  89. package/src/rules/__tests__/utils.test.ts +1 -1
  90. package/src/rules/common/__tests__/no-enum-type-mismatch.test.ts +1 -0
  91. package/src/rules/common/__tests__/operation-2xx-response.test.ts +1 -1
  92. package/src/rules/common/__tests__/operation-4xx-response.test.ts +26 -3
  93. package/src/rules/common/__tests__/security-defined.test.ts +175 -0
  94. package/src/rules/common/__tests__/spec.test.ts +79 -0
  95. package/src/rules/common/assertions/__tests__/utils.test.ts +2 -2
  96. package/src/rules/common/no-ambiguous-paths.ts +1 -1
  97. package/src/rules/common/no-identical-paths.ts +1 -1
  98. package/src/rules/common/operation-2xx-response.ts +1 -1
  99. package/src/rules/common/operation-4xx-response.ts +1 -1
  100. package/src/rules/common/operation-operationId.ts +1 -1
  101. package/src/rules/common/operation-tag-defined.ts +1 -1
  102. package/src/rules/common/path-not-include-query.ts +1 -1
  103. package/src/rules/common/{operation-security-defined.ts → security-defined.ts} +19 -4
  104. package/src/rules/common/spec.ts +15 -1
  105. package/src/rules/common/tags-alphabetical.ts +1 -1
  106. package/src/rules/oas2/index.ts +2 -2
  107. package/src/rules/oas2/remove-unused-components.ts +1 -1
  108. package/src/rules/oas2/request-mime-type.ts +1 -1
  109. package/src/rules/oas2/response-mime-type.ts +1 -1
  110. package/src/rules/oas3/__tests__/operation-4xx-problem-details-rfc7807.test.ts +145 -0
  111. package/src/rules/oas3/__tests__/spec/spec.test.ts +10 -0
  112. package/src/rules/oas3/__tests__/spec-components-invalid-map-name.test.ts +217 -0
  113. package/src/rules/oas3/index.ts +6 -2
  114. package/src/rules/oas3/no-empty-servers.ts +1 -1
  115. package/src/rules/oas3/no-server-variables-empty-enum.ts +1 -1
  116. package/src/rules/oas3/no-unused-components.ts +1 -1
  117. package/src/rules/oas3/operation-4xx-problem-details-rfc7807.ts +36 -0
  118. package/src/rules/oas3/remove-unused-components.ts +1 -1
  119. package/src/rules/oas3/request-mime-type.ts +1 -1
  120. package/src/rules/oas3/response-mime-type.ts +1 -1
  121. package/src/rules/oas3/spec-components-invalid-map-name.ts +53 -0
  122. package/src/rules/other/stats.ts +2 -2
  123. package/src/types/index.ts +2 -2
  124. package/src/types/oas2.ts +5 -5
  125. package/src/types/oas3.ts +27 -20
  126. package/src/types/oas3_1.ts +3 -3
  127. package/src/types/redocly-yaml.ts +52 -40
  128. package/src/utils.ts +11 -7
  129. package/src/visitors.ts +29 -13
  130. package/tsconfig.tsbuildinfo +1 -1
  131. package/lib/rules/common/operation-security-defined.d.ts +0 -2
  132. package/src/rules/common/__tests__/operation-security-defined.test.ts +0 -69
@@ -16,7 +16,7 @@ function measureAsync() {
16
16
  return resolve_1.resolveDocument({
17
17
  rootDocument: rebillyDocument,
18
18
  externalRefResolver,
19
- rootType: types_1.normalizeTypes(oas3_1.Oas3Types).DefinitionRoot,
19
+ rootType: types_1.normalizeTypes(oas3_1.Oas3Types).Root,
20
20
  });
21
21
  }
22
22
  exports.measureAsync = measureAsync;
package/lib/bundle.d.ts CHANGED
@@ -44,4 +44,4 @@ export declare function bundleDocument(opts: {
44
44
  refTypes: Map<string, NormalizedNodeType> | undefined;
45
45
  visitorsData: Record<string, Record<string, unknown>>;
46
46
  }>;
47
- export declare function mapTypeToComponent(typeName: string, version: OasMajorVersion): "headers" | "definitions" | "parameters" | "examples" | "responses" | "schemas" | "requestBodies" | "securitySchemes" | "links" | "callbacks" | null;
47
+ export declare function mapTypeToComponent(typeName: string, version: OasMajorVersion): "headers" | "definitions" | "parameters" | "examples" | "responses" | "schemas" | "requestBodies" | "links" | "callbacks" | "securitySchemes" | null;
package/lib/bundle.js CHANGED
@@ -76,7 +76,7 @@ function bundleDocument(opts) {
76
76
  }
77
77
  const resolvedRefMap = yield resolve_1.resolveDocument({
78
78
  rootDocument: document,
79
- rootType: types.DefinitionRoot,
79
+ rootType: types.Root,
80
80
  externalRefResolver,
81
81
  });
82
82
  const bundleVisitor = visitors_1.normalizeVisitors([
@@ -90,7 +90,7 @@ function bundleDocument(opts) {
90
90
  ], types);
91
91
  walk_1.walkDocument({
92
92
  document,
93
- rootType: types.DefinitionRoot,
93
+ rootType: types.Root,
94
94
  normalizedVisitors: bundleVisitor,
95
95
  resolvedRefMap,
96
96
  ctx,
@@ -99,7 +99,7 @@ function bundleDocument(opts) {
99
99
  bundle: document,
100
100
  problems: ctx.problems.map((problem) => config.addProblemToIgnore(problem)),
101
101
  fileDependencies: externalRefResolver.getFiles(),
102
- rootType: types.DefinitionRoot,
102
+ rootType: types.Root,
103
103
  refTypes: ctx.refTypes,
104
104
  visitorsData: ctx.visitorsData,
105
105
  };
@@ -184,7 +184,7 @@ function makeBundleVisitor(version, dereference, skipRedoclyRegistryRefs, rootDo
184
184
  }
185
185
  },
186
186
  },
187
- DefinitionRoot: {
187
+ Root: {
188
188
  enter(root) {
189
189
  if (version === oas_types_1.OasMajorVersion.Version3) {
190
190
  components = root.components = root.components || {};
package/lib/config/all.js CHANGED
@@ -26,7 +26,7 @@ exports.default = {
26
26
  'operation-operationId-url-safe': 'error',
27
27
  'operation-parameters-unique': 'error',
28
28
  'operation-tag-defined': 'error',
29
- 'operation-security-defined': 'error',
29
+ 'security-defined': 'error',
30
30
  'operation-singular-tag': 'error',
31
31
  'no-unresolved-refs': 'error',
32
32
  'no-enum-type-mismatch': 'error',
@@ -52,6 +52,7 @@ exports.default = {
52
52
  'no-unused-components': 'error',
53
53
  'no-undefined-server-variable': 'error',
54
54
  'no-server-variables-empty-enum': 'error',
55
+ 'operation-4xx-problem-details-rfc7807': 'error',
55
56
  },
56
57
  oas3_1Rules: {
57
58
  'no-server-example.com': 'error',
@@ -61,5 +62,6 @@ exports.default = {
61
62
  'no-unused-components': 'error',
62
63
  'no-undefined-server-variable': 'error',
63
64
  'no-server-variables-empty-enum': 'error',
65
+ 'operation-4xx-problem-details-rfc7807': 'error',
64
66
  },
65
67
  };
@@ -135,7 +135,7 @@ function resolvePlugins(plugins, configPath = '') {
135
135
  }
136
136
  return plugin;
137
137
  })
138
- .filter(utils_2.notUndefined);
138
+ .filter(utils_2.isDefined);
139
139
  }
140
140
  exports.resolvePlugins = resolvePlugins;
141
141
  function resolveApis({ rawConfig, configPath = '', resolver, }) {
@@ -24,7 +24,7 @@ exports.default = {
24
24
  'operation-operationId-unique': 'warn',
25
25
  'operation-parameters-unique': 'warn',
26
26
  'operation-tag-defined': 'off',
27
- 'operation-security-defined': 'warn',
27
+ 'security-defined': 'warn',
28
28
  'operation-operationId-url-safe': 'warn',
29
29
  'operation-singular-tag': 'off',
30
30
  'no-unresolved-refs': 'error',
@@ -45,6 +45,7 @@ exports.default = {
45
45
  'no-unused-components': 'warn',
46
46
  'no-undefined-server-variable': 'warn',
47
47
  'no-server-variables-empty-enum': 'error',
48
+ 'spec-components-invalid-map-name': 'warn',
48
49
  },
49
50
  oas3_1Rules: {
50
51
  'no-invalid-media-type-examples': 'warn',
@@ -55,5 +56,6 @@ exports.default = {
55
56
  'no-unused-components': 'warn',
56
57
  'no-undefined-server-variable': 'warn',
57
58
  'no-server-variables-empty-enum': 'error',
59
+ 'spec-components-invalid-map-name': 'warn',
58
60
  },
59
61
  };
@@ -25,7 +25,7 @@ exports.default = {
25
25
  'operation-operationId-url-safe': 'error',
26
26
  'operation-parameters-unique': 'error',
27
27
  'operation-tag-defined': 'off',
28
- 'operation-security-defined': 'error',
28
+ 'security-defined': 'error',
29
29
  'operation-singular-tag': 'off',
30
30
  'no-unresolved-refs': 'error',
31
31
  'no-enum-type-mismatch': 'error',
@@ -45,6 +45,7 @@ exports.default = {
45
45
  'no-unused-components': 'warn',
46
46
  'no-undefined-server-variable': 'error',
47
47
  'no-server-variables-empty-enum': 'error',
48
+ 'spec-components-invalid-map-name': 'error',
48
49
  },
49
50
  oas3_1Rules: {
50
51
  'no-invalid-media-type-examples': 'warn',
@@ -55,5 +56,6 @@ exports.default = {
55
56
  'no-unused-components': 'warn',
56
57
  'no-undefined-server-variable': 'error',
57
58
  'no-server-variables-empty-enum': 'error',
59
+ 'spec-components-invalid-map-name': 'error',
58
60
  },
59
61
  };
@@ -29,6 +29,6 @@ function initRules(rules, config, type, oasVersion) {
29
29
  };
30
30
  }))
31
31
  .flatMap((visitor) => visitor)
32
- .filter(utils_1.notUndefined);
32
+ .filter(utils_1.isDefined);
33
33
  }
34
34
  exports.initRules = initRules;
@@ -72,6 +72,7 @@ export declare type ResolveHeader = {
72
72
  };
73
73
  export declare type RawResolveConfig = {
74
74
  http?: Partial<HttpResolveConfig>;
75
+ doNotResolveExamples?: boolean;
75
76
  };
76
77
  export declare type HttpResolveConfig = {
77
78
  headers: ResolveHeader[];
@@ -87,6 +88,7 @@ export declare type AccessTokens = {
87
88
  export declare type DeprecatedInRawConfig = {
88
89
  apiDefinitions?: Record<string, string>;
89
90
  lint?: StyleguideRawConfig;
91
+ styleguide?: StyleguideRawConfig;
90
92
  referenceDocs?: Record<string, any>;
91
93
  apis?: Record<string, Api & DeprecatedInApi>;
92
94
  };
@@ -107,6 +109,11 @@ export declare type RawConfig = {
107
109
  region?: Region;
108
110
  organization?: string;
109
111
  } & FeaturesConfig;
112
+ export declare type FlatApi = Omit<Api, 'styleguide'> & Omit<ApiStyleguideRawConfig, 'doNotResolveExamples'>;
113
+ export declare type FlatRawConfig = Omit<RawConfig, 'styleguide' | 'resolve' | 'apis'> & Omit<StyleguideRawConfig, 'doNotResolveExamples'> & {
114
+ resolve?: RawResolveConfig;
115
+ apis?: Record<string, FlatApi>;
116
+ };
110
117
  export declare type ResolvedConfig = Omit<RawConfig, 'apis' | 'styleguide'> & {
111
118
  apis: Record<string, ResolvedApi>;
112
119
  styleguide: ResolvedStyleguideConfig;
@@ -1,5 +1,5 @@
1
1
  import { Config } from './config';
2
- import type { Api, DeprecatedInRawConfig, Plugin, RawConfig, RawResolveConfig, ResolveConfig, ResolvedStyleguideConfig, RulesFields } from './types';
2
+ import type { Api, DeprecatedInRawConfig, FlatRawConfig, Plugin, RawConfig, RawResolveConfig, ResolveConfig, ResolvedStyleguideConfig, RulesFields } from './types';
3
3
  export declare function parsePresetName(presetName: string): {
4
4
  pluginId: string;
5
5
  configName: string;
@@ -8,6 +8,6 @@ export declare function transformApiDefinitionsToApis(apiDefinitions?: Deprecate
8
8
  export declare function prefixRules<T extends Record<string, any>>(rules: T, prefix: string): any;
9
9
  export declare function mergeExtends(rulesConfList: ResolvedStyleguideConfig[]): Omit<ResolvedStyleguideConfig, RulesFields> & Required<Pick<ResolvedStyleguideConfig, RulesFields>>;
10
10
  export declare function getMergedConfig(config: Config, apiName?: string): Config;
11
- export declare function transformConfig(rawConfig: DeprecatedInRawConfig & RawConfig): RawConfig;
11
+ export declare function transformConfig(rawConfig: DeprecatedInRawConfig & RawConfig & FlatRawConfig): RawConfig;
12
12
  export declare function getResolveConfig(resolve?: RawResolveConfig): ResolveConfig;
13
13
  export declare function getUniquePlugins(plugins: Plugin[]): Plugin[];
@@ -35,13 +35,46 @@ function transformApiDefinitionsToApis(apiDefinitions) {
35
35
  return apis;
36
36
  }
37
37
  exports.transformApiDefinitionsToApis = transformApiDefinitionsToApis;
38
+ function extractFlatConfig(_a) {
39
+ var _b;
40
+ var { plugins, extends: _extends, rules, oas2Rules, oas3_0Rules, oas3_1Rules, preprocessors, oas2Preprocessors, oas3_0Preprocessors, oas3_1Preprocessors, decorators, oas2Decorators, oas3_0Decorators, oas3_1Decorators } = _a, rawConfigRest = __rest(_a, ["plugins", "extends", "rules", "oas2Rules", "oas3_0Rules", "oas3_1Rules", "preprocessors", "oas2Preprocessors", "oas3_0Preprocessors", "oas3_1Preprocessors", "decorators", "oas2Decorators", "oas3_0Decorators", "oas3_1Decorators"]);
41
+ const styleguideConfig = {
42
+ plugins,
43
+ extends: _extends,
44
+ rules,
45
+ oas2Rules,
46
+ oas3_0Rules,
47
+ oas3_1Rules,
48
+ preprocessors,
49
+ oas2Preprocessors,
50
+ oas3_0Preprocessors,
51
+ oas3_1Preprocessors,
52
+ decorators,
53
+ oas2Decorators,
54
+ oas3_0Decorators,
55
+ oas3_1Decorators,
56
+ doNotResolveExamples: (_b = rawConfigRest.resolve) === null || _b === void 0 ? void 0 : _b.doNotResolveExamples,
57
+ };
58
+ if ((rawConfigRest.lint && rawConfigRest.styleguide) ||
59
+ (Object.values(styleguideConfig).some(utils_1.isDefined) &&
60
+ (rawConfigRest.lint || rawConfigRest.styleguide))) {
61
+ throw new Error(`Do not use 'lint', 'styleguide' and flat syntax together. \nSee more about the configuration in the docs: https://redocly.com/docs/cli/configuration/ \n`);
62
+ }
63
+ return {
64
+ styleguideConfig: Object.values(styleguideConfig).some(utils_1.isDefined)
65
+ ? styleguideConfig
66
+ : undefined,
67
+ rawConfigRest,
68
+ };
69
+ }
38
70
  function transformApis(legacyApis) {
39
71
  if (!legacyApis)
40
72
  return undefined;
41
73
  const apis = {};
42
74
  for (let _a of Object.entries(legacyApis)) {
43
75
  const [apiName, _b] = _a, { lint } = _b, apiContent = __rest(_b, ["lint"]);
44
- apis[apiName] = Object.assign({ styleguide: lint }, apiContent);
76
+ const { styleguideConfig, rawConfigRest } = extractFlatConfig(apiContent);
77
+ apis[apiName] = Object.assign({ styleguide: styleguideConfig || lint }, rawConfigRest);
45
78
  }
46
79
  return apis;
47
80
  }
@@ -130,7 +163,10 @@ exports.getMergedConfig = getMergedConfig;
130
163
  function checkForDeprecatedFields(deprecatedField, updatedField, rawConfig) {
131
164
  const isDeprecatedFieldInApis = rawConfig.apis &&
132
165
  Object.values(rawConfig.apis).some((api) => api[deprecatedField]);
133
- if (rawConfig[deprecatedField] && rawConfig[updatedField]) {
166
+ if (rawConfig[deprecatedField] && updatedField === null) {
167
+ utils_1.showWarningForDeprecatedField(deprecatedField);
168
+ }
169
+ if (rawConfig[deprecatedField] && updatedField && rawConfig[updatedField]) {
134
170
  utils_1.showErrorForDeprecatedField(deprecatedField, updatedField);
135
171
  }
136
172
  if (rawConfig[deprecatedField] || isDeprecatedFieldInApis) {
@@ -141,13 +177,15 @@ function transformConfig(rawConfig) {
141
177
  const migratedFields = [
142
178
  ['apiDefinitions', 'apis'],
143
179
  ['referenceDocs', 'features.openapi'],
144
- ['lint', 'styleguide'], // TODO: update docs
180
+ ['lint', undefined],
181
+ ['styleguide', undefined],
145
182
  ];
146
183
  for (const [deprecatedField, updatedField] of migratedFields) {
147
184
  checkForDeprecatedFields(deprecatedField, updatedField, rawConfig);
148
185
  }
149
186
  const { apis, apiDefinitions, referenceDocs, lint } = rawConfig, rest = __rest(rawConfig, ["apis", "apiDefinitions", "referenceDocs", "lint"]);
150
- return Object.assign({ 'features.openapi': referenceDocs, apis: transformApis(apis) || transformApiDefinitionsToApis(apiDefinitions), styleguide: lint }, rest);
187
+ const { styleguideConfig, rawConfigRest } = extractFlatConfig(rest);
188
+ return Object.assign({ 'features.openapi': referenceDocs, apis: transformApis(apis) || transformApiDefinitionsToApis(apiDefinitions), styleguide: styleguideConfig || lint }, rawConfigRest);
151
189
  }
152
190
  exports.transformConfig = transformConfig;
153
191
  function getResolveConfig(resolve) {
@@ -5,7 +5,7 @@ const redocly_1 = require("../../redocly");
5
5
  const RegistryDependencies = () => {
6
6
  const registryDependencies = new Set();
7
7
  return {
8
- DefinitionRoot: {
8
+ Root: {
9
9
  leave(_, ctx) {
10
10
  const data = ctx.getVisitorData();
11
11
  data.links = Array.from(registryDependencies);
@@ -4,7 +4,7 @@ export declare type Totals = {
4
4
  warnings: number;
5
5
  ignored: number;
6
6
  };
7
- export declare type OutputFormat = 'codeframe' | 'stylish' | 'json' | 'checkstyle' | 'codeclimate';
7
+ export declare type OutputFormat = 'codeframe' | 'stylish' | 'json' | 'checkstyle' | 'codeclimate' | 'summary';
8
8
  export declare function getTotals(problems: (NormalizedProblem & {
9
9
  ignored?: boolean;
10
10
  })[]): Totals;
@@ -99,6 +99,9 @@ function formatProblems(problems, opts) {
99
99
  case 'codeclimate':
100
100
  outputForCodeClimate();
101
101
  break;
102
+ case 'summary':
103
+ formatSummary(problems);
104
+ break;
102
105
  }
103
106
  if (totalProblems - ignoredProblems > maxProblems) {
104
107
  logger_1.logger.info(`< ... ${totalProblems - maxProblems} more problems hidden > ${logger_1.colorize.gray('increase with `--max-problems N`')}\n`);
@@ -183,13 +186,31 @@ function formatProblems(problems, opts) {
183
186
  }
184
187
  }
185
188
  exports.formatProblems = formatProblems;
189
+ function formatSummary(problems) {
190
+ const counts = {};
191
+ for (const problem of problems) {
192
+ counts[problem.ruleId] = counts[problem.ruleId] || { count: 0, severity: problem.severity };
193
+ counts[problem.ruleId].count++;
194
+ }
195
+ const sorted = Object.entries(counts).sort(([, a], [, b]) => {
196
+ const severityDiff = severityToNumber(a.severity) - severityToNumber(b.severity);
197
+ return severityDiff || b.count - a.count;
198
+ });
199
+ for (const [ruleId, info] of sorted) {
200
+ const color = COLORS[info.severity];
201
+ const severityName = color(SEVERITY_NAMES[info.severity].toLowerCase().padEnd(7));
202
+ logger_1.logger.info(`${severityName} ${ruleId}: ${info.count}\n`);
203
+ }
204
+ logger_1.logger.info('\n');
205
+ }
186
206
  function formatFrom(cwd, location) {
187
207
  if (!location)
188
208
  return '';
189
209
  const relativePath = path.relative(cwd, location.source.absoluteRef);
190
210
  const loc = codeframes_1.getLineColLocation(location);
191
211
  const fileWithLoc = `${relativePath}:${loc.start.line}:${loc.start.col}`;
192
- return `referenced from ${logger_1.colorize.blue(fileWithLoc)}\n\n`;
212
+ const atPointer = location.pointer ? logger_1.colorize.gray(`at ${location.pointer}`) : '';
213
+ return `referenced from ${logger_1.colorize.blue(fileWithLoc)} ${atPointer} \n\n`;
193
214
  }
194
215
  function formatDidYouMean(problem) {
195
216
  if (problem.suggest.length === 0)
package/lib/lint.js CHANGED
@@ -60,12 +60,12 @@ function lintDocument(opts) {
60
60
  const normalizedVisitors = visitors_1.normalizeVisitors([...preprocessors, ...regularRules], types);
61
61
  const resolvedRefMap = yield resolve_1.resolveDocument({
62
62
  rootDocument: document,
63
- rootType: types.DefinitionRoot,
63
+ rootType: types.Root,
64
64
  externalRefResolver,
65
65
  });
66
66
  walk_1.walkDocument({
67
67
  document,
68
- rootType: types.DefinitionRoot,
68
+ rootType: types.Root,
69
69
  normalizedVisitors,
70
70
  resolvedRefMap,
71
71
  ctx,
@@ -1,6 +1,5 @@
1
1
  import type { PrepareFileuploadOKResponse, PrepareFileuploadParams, PushApiParams } from './registry-api-types';
2
2
  import type { AccessTokens, Region } from '../config/types';
3
- export declare const currentCommand: string;
4
3
  export declare class RegistryApi {
5
4
  private accessTokens;
6
5
  private region;
@@ -8,14 +8,12 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  step((generator = generator.apply(thisArg, _arguments || [])).next());
9
9
  });
10
10
  };
11
- var _a;
12
11
  Object.defineProperty(exports, "__esModule", { value: true });
13
- exports.RegistryApi = exports.currentCommand = void 0;
12
+ exports.RegistryApi = void 0;
14
13
  const node_fetch_1 = require("node-fetch");
15
14
  const config_1 = require("../config/config");
16
15
  const utils_1 = require("../utils");
17
16
  const version = require('../../package.json').version;
18
- exports.currentCommand = typeof process !== 'undefined' ? ((_a = process.env) === null || _a === void 0 ? void 0 : _a.REDOCLY_CLI_COMMAND) || '' : '';
19
17
  class RegistryApi {
20
18
  constructor(accessTokens, region) {
21
19
  this.accessTokens = accessTokens;
@@ -32,10 +30,13 @@ class RegistryApi {
32
30
  return this;
33
31
  }
34
32
  request(path = '', options = {}, region) {
33
+ var _a, _b;
35
34
  return __awaiter(this, void 0, void 0, function* () {
35
+ const currentCommand = typeof process !== 'undefined' ? ((_a = process.env) === null || _a === void 0 ? void 0 : _a.REDOCLY_CLI_COMMAND) || '' : '';
36
+ const redoclyEnv = typeof process !== 'undefined' ? ((_b = process.env) === null || _b === void 0 ? void 0 : _b.REDOCLY_ENVIRONMENT) || '' : '';
36
37
  const headers = Object.assign({}, options.headers || {}, {
37
38
  'x-redocly-cli-version': version,
38
- 'user-agent': `redocly-cli / ${version} ${exports.currentCommand}`,
39
+ 'user-agent': `redocly-cli / ${version} ${currentCommand} ${redoclyEnv}`,
39
40
  });
40
41
  if (!headers.hasOwnProperty('authorization')) {
41
42
  throw new Error('Unauthorized');
package/lib/resolve.js CHANGED
@@ -110,7 +110,9 @@ class BaseResolver {
110
110
  return new Source(absoluteRef, body, mimeType);
111
111
  }
112
112
  else {
113
- return new Source(absoluteRef, yield fs.promises.readFile(absoluteRef, 'utf-8'));
113
+ const content = yield fs.promises.readFile(absoluteRef, 'utf-8');
114
+ // In some cases file have \r\n line delimeters like on windows, we should skip it.
115
+ return new Source(absoluteRef, content.replace(/\r\n/g, '\n'));
114
116
  }
115
117
  }
116
118
  catch (error) {
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.NoAmbiguousPaths = void 0;
4
4
  const NoAmbiguousPaths = () => {
5
5
  return {
6
- PathMap(pathMap, { report, location }) {
6
+ PathsMap(pathMap, { report, location }) {
7
7
  const seenPaths = [];
8
8
  for (const currentPath of Object.keys(pathMap)) {
9
9
  const ambiguousPath = seenPaths.find((seenPath) => arePathsAmbiguous(seenPath, currentPath));
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.NoIdenticalPaths = void 0;
4
4
  const NoIdenticalPaths = () => {
5
5
  return {
6
- PathMap(pathMap, { report, location }) {
6
+ PathsMap(pathMap, { report, location }) {
7
7
  const pathsMap = new Map();
8
8
  for (const pathName of Object.keys(pathMap)) {
9
9
  const id = pathName.replace(/{.+?}/g, '{VARIABLE}');
@@ -7,7 +7,7 @@ const Operation2xxResponse = () => {
7
7
  const codes = Object.keys(responses);
8
8
  if (!codes.some((code) => code === 'default' || /2[Xx0-9]{2}/.test(code))) {
9
9
  report({
10
- message: 'Operation must have at least one `2xx` response.',
10
+ message: 'Operation must have at least one `2XX` response.',
11
11
  location: { reportOnKey: true },
12
12
  });
13
13
  }
@@ -7,7 +7,7 @@ const Operation4xxResponse = () => {
7
7
  const codes = Object.keys(responses);
8
8
  if (!codes.some((code) => /4[Xx0-9]{2}/.test(code))) {
9
9
  report({
10
- message: 'Operation must have at least one `4xx` response.',
10
+ message: 'Operation must have at least one `4XX` response.',
11
11
  location: { reportOnKey: true },
12
12
  });
13
13
  }
@@ -4,7 +4,7 @@ exports.OperationOperationId = void 0;
4
4
  const utils_1 = require("../utils");
5
5
  const OperationOperationId = () => {
6
6
  return {
7
- DefinitionRoot: {
7
+ Root: {
8
8
  PathItem: {
9
9
  Operation(operation, ctx) {
10
10
  utils_1.validateDefinedAndNonEmpty('operationId', operation, ctx);
@@ -4,7 +4,7 @@ exports.OperationTagDefined = void 0;
4
4
  const OperationTagDefined = () => {
5
5
  let definedTags;
6
6
  return {
7
- DefinitionRoot(root) {
7
+ Root(root) {
8
8
  var _a;
9
9
  definedTags = new Set(((_a = root.tags) !== null && _a !== void 0 ? _a : []).map((t) => t.name));
10
10
  },
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.PathNotIncludeQuery = void 0;
4
4
  const PathNotIncludeQuery = () => {
5
5
  return {
6
- PathMap: {
6
+ PathsMap: {
7
7
  PathItem(_operation, { report, key }) {
8
8
  if (key.toString().includes('?')) {
9
9
  report({
@@ -0,0 +1,2 @@
1
+ import { Oas3Rule, Oas2Rule } from '../../visitors';
2
+ export declare const SecurityDefined: Oas3Rule | Oas2Rule;
@@ -1,11 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.OperationSecurityDefined = void 0;
4
- const OperationSecurityDefined = () => {
3
+ exports.SecurityDefined = void 0;
4
+ const SecurityDefined = () => {
5
5
  const referencedSchemes = new Map();
6
+ let eachOperationHasSecurity = true;
6
7
  return {
7
8
  DefinitionRoot: {
8
- leave(_, { report }) {
9
+ leave(root, { report }) {
9
10
  for (const [name, scheme] of referencedSchemes.entries()) {
10
11
  if (scheme.defined)
11
12
  continue;
@@ -16,6 +17,14 @@ const OperationSecurityDefined = () => {
16
17
  });
17
18
  }
18
19
  }
20
+ if (root.security || eachOperationHasSecurity) {
21
+ return;
22
+ }
23
+ else {
24
+ report({
25
+ message: `Every API should have security defined on the root level or for each operation.`,
26
+ });
27
+ }
19
28
  },
20
29
  },
21
30
  SecurityScheme(_securityScheme, { key }) {
@@ -33,6 +42,11 @@ const OperationSecurityDefined = () => {
33
42
  }
34
43
  }
35
44
  },
45
+ Operation(operation) {
46
+ if (!(operation === null || operation === void 0 ? void 0 : operation.security)) {
47
+ eachOperationHasSecurity = false;
48
+ }
49
+ },
36
50
  };
37
51
  };
38
- exports.OperationSecurityDefined = OperationSecurityDefined;
52
+ exports.SecurityDefined = SecurityDefined;
@@ -7,13 +7,15 @@ const ref_utils_1 = require("../../ref-utils");
7
7
  const utils_2 = require("../../utils");
8
8
  const OasSpec = () => {
9
9
  return {
10
- any(node, { report, type, location, key, resolve, ignoreNextVisitorsOnNode }) {
10
+ any(node, { report, type, location, rawLocation, key, resolve, ignoreNextVisitorsOnNode }) {
11
11
  var _a, _b, _c, _d;
12
12
  const nodeType = utils_1.oasTypeOf(node);
13
+ const refLocation = rawLocation !== location ? rawLocation : undefined;
13
14
  if (type.items) {
14
15
  if (nodeType !== 'array') {
15
16
  report({
16
17
  message: `Expected type \`${type.name}\` (array) but got \`${nodeType}\``,
18
+ from: refLocation,
17
19
  });
18
20
  ignoreNextVisitorsOnNode();
19
21
  }
@@ -22,6 +24,7 @@ const OasSpec = () => {
22
24
  else if (nodeType !== 'object') {
23
25
  report({
24
26
  message: `Expected type \`${type.name}\` (object) but got \`${nodeType}\``,
27
+ from: refLocation,
25
28
  });
26
29
  ignoreNextVisitorsOnNode();
27
30
  return;
@@ -31,6 +34,7 @@ const OasSpec = () => {
31
34
  if (!node.hasOwnProperty(propName)) {
32
35
  report({
33
36
  message: `The field \`${propName}\` must be present on this level.`,
37
+ from: refLocation,
34
38
  location: [{ reportOnKey: true }],
35
39
  });
36
40
  }
@@ -45,6 +49,7 @@ const OasSpec = () => {
45
49
  }
46
50
  report({
47
51
  message: `The field \`${propName}\` is not allowed here.`,
52
+ from: refLocation,
48
53
  location: location.child([propName]).key(),
49
54
  });
50
55
  }
@@ -60,6 +65,7 @@ const OasSpec = () => {
60
65
  if (!hasProperty)
61
66
  report({
62
67
  message: `Must contain at least one of the following fields: ${(_b = type.requiredOneOf) === null || _b === void 0 ? void 0 : _b.join(', ')}.`,
68
+ from: refLocation,
63
69
  location: [{ reportOnKey: true }],
64
70
  });
65
71
  }
@@ -82,6 +88,7 @@ const OasSpec = () => {
82
88
  report({
83
89
  message: `Property \`${propName}\` is not expected here.`,
84
90
  suggest: utils_1.getSuggest(propName, Object.keys(type.properties)),
91
+ from: refLocation,
85
92
  location: propLocation.key(),
86
93
  });
87
94
  continue;
@@ -99,6 +106,7 @@ const OasSpec = () => {
99
106
  message: `\`${propName}\` can be one of the following only: ${propSchema.enum
100
107
  .map((i) => `"${i}"`)
101
108
  .join(', ')}.`,
109
+ from: refLocation,
102
110
  suggest: utils_1.getSuggest(propValue, propSchema.enum),
103
111
  });
104
112
  }
@@ -106,6 +114,7 @@ const OasSpec = () => {
106
114
  else if (propSchema.type && !utils_1.matchesJsonSchemaType(propValue, propSchema.type, false)) {
107
115
  report({
108
116
  message: `Expected type \`${propSchema.type}\` but got \`${propValueType}\`.`,
117
+ from: refLocation,
109
118
  location: propLocation,
110
119
  });
111
120
  }
@@ -116,6 +125,7 @@ const OasSpec = () => {
116
125
  if (!utils_1.matchesJsonSchemaType(item, itemsType, false)) {
117
126
  report({
118
127
  message: `Expected type \`${itemsType}\` but got \`${utils_1.oasTypeOf(item)}\`.`,
128
+ from: refLocation,
119
129
  location: propLocation.child([i]),
120
130
  });
121
131
  }
@@ -125,6 +135,7 @@ const OasSpec = () => {
125
135
  if (propSchema.minimum > node[propName]) {
126
136
  report({
127
137
  message: `The value of the ${propName} field must be greater than or equal to ${propSchema.minimum}`,
138
+ from: refLocation,
128
139
  location: location.child([propName]),
129
140
  });
130
141
  }
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.TagsAlphabetical = void 0;
4
4
  const TagsAlphabetical = () => {
5
5
  return {
6
- DefinitionRoot(root, { report, location }) {
6
+ Root(root, { report, location }) {
7
7
  if (!root.tags)
8
8
  return;
9
9
  for (let i = 0; i < root.tags.length - 1; i++) {
@@ -29,7 +29,7 @@ export declare const rules: {
29
29
  'path-params-defined': Oas2Rule;
30
30
  'parameter-description': Oas2Rule;
31
31
  'operation-singular-tag': Oas2Rule;
32
- 'operation-security-defined': Oas2Rule;
32
+ 'security-defined': Oas2Rule;
33
33
  'no-unresolved-refs': Oas2Rule;
34
34
  'no-identical-paths': Oas2Rule;
35
35
  'no-ambiguous-paths': Oas2Rule;
@@ -27,7 +27,7 @@ const operation_description_1 = require("../common/operation-description");
27
27
  const path_not_include_query_1 = require("../common/path-not-include-query");
28
28
  const parameter_description_1 = require("../common/parameter-description");
29
29
  const operation_singular_tag_1 = require("../common/operation-singular-tag");
30
- const operation_security_defined_1 = require("../common/operation-security-defined");
30
+ const security_defined_1 = require("../common/security-defined");
31
31
  const no_unresolved_refs_1 = require("../no-unresolved-refs");
32
32
  const path_http_verbs_order_1 = require("../common/path-http-verbs-order");
33
33
  const no_identical_paths_1 = require("../common/no-identical-paths");
@@ -72,7 +72,7 @@ exports.rules = {
72
72
  'path-params-defined': path_params_defined_1.PathParamsDefined,
73
73
  'parameter-description': parameter_description_1.ParameterDescription,
74
74
  'operation-singular-tag': operation_singular_tag_1.OperationSingularTag,
75
- 'operation-security-defined': operation_security_defined_1.OperationSecurityDefined,
75
+ 'security-defined': security_defined_1.SecurityDefined,
76
76
  'no-unresolved-refs': no_unresolved_refs_1.NoUnresolvedRefs,
77
77
  'no-identical-paths': no_identical_paths_1.NoIdenticalPaths,
78
78
  'no-ambiguous-paths': no_ambiguous_paths_1.NoAmbiguousPaths,