@redocly/openapi-core 1.0.0-beta.75 → 1.0.0-beta.79

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 (42) hide show
  1. package/lib/bundle.d.ts +4 -0
  2. package/lib/bundle.js +32 -9
  3. package/lib/config/config.d.ts +2 -9
  4. package/lib/format/format.d.ts +1 -1
  5. package/lib/format/format.js +39 -1
  6. package/lib/index.d.ts +1 -1
  7. package/lib/index.js +2 -1
  8. package/lib/resolve.d.ts +1 -0
  9. package/lib/resolve.js +7 -3
  10. package/lib/rules/builtin.d.ts +2 -0
  11. package/lib/rules/common/remove-x-internal.d.ts +2 -0
  12. package/lib/rules/common/remove-x-internal.js +58 -0
  13. package/lib/rules/oas2/index.d.ts +1 -0
  14. package/lib/rules/oas2/index.js +2 -0
  15. package/lib/rules/oas2/remove-unused-components.d.ts +2 -0
  16. package/lib/rules/oas2/remove-unused-components.js +73 -0
  17. package/lib/rules/oas3/index.d.ts +1 -0
  18. package/lib/rules/oas3/index.js +2 -0
  19. package/lib/rules/oas3/remove-unused-components.d.ts +2 -0
  20. package/lib/rules/oas3/remove-unused-components.js +83 -0
  21. package/lib/typings/swagger.d.ts +14 -0
  22. package/lib/utils.d.ts +2 -0
  23. package/lib/utils.js +9 -1
  24. package/lib/walk.js +5 -8
  25. package/package.json +1 -1
  26. package/src/bundle.ts +38 -9
  27. package/src/config/config.ts +2 -3
  28. package/src/format/format.ts +47 -2
  29. package/src/index.ts +1 -1
  30. package/src/resolve.ts +6 -6
  31. package/src/rules/__tests__/config.ts +5 -4
  32. package/src/rules/__tests__/hide-internals.test.ts +317 -0
  33. package/src/rules/common/remove-x-internal.ts +59 -0
  34. package/src/rules/oas2/index.ts +3 -1
  35. package/src/rules/oas2/remove-unused-components.ts +76 -0
  36. package/src/rules/oas3/index.ts +2 -0
  37. package/src/rules/oas3/remove-unused-components.ts +84 -0
  38. package/src/types/oas2.ts +0 -3
  39. package/src/typings/swagger.ts +7 -0
  40. package/src/utils.ts +8 -0
  41. package/src/walk.ts +6 -13
  42. package/tsconfig.tsbuildinfo +1 -1
package/lib/bundle.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { BaseResolver, Document } from './resolve';
2
2
  import { Oas3Rule } from './visitors';
3
3
  import { NormalizedNodeType, NodeType } from './types';
4
+ import { OasMajorVersion } from './oas-types';
4
5
  import type { Config, LintConfig } from './config/config';
5
6
  export declare type Oas3RuleSet = Record<string, Oas3Rule>;
6
7
  export declare enum OasVersion {
@@ -16,6 +17,7 @@ export declare function bundle(opts: {
16
17
  dereference?: boolean;
17
18
  base?: string;
18
19
  skipRedoclyRegistryRefs?: boolean;
20
+ removeUnusedComponents?: boolean;
19
21
  }): Promise<{
20
22
  bundle: Document;
21
23
  problems: import("./walk").NormalizedProblem[];
@@ -31,6 +33,7 @@ export declare function bundleDocument(opts: {
31
33
  externalRefResolver: BaseResolver;
32
34
  dereference?: boolean;
33
35
  skipRedoclyRegistryRefs?: boolean;
36
+ removeUnusedComponents?: boolean;
34
37
  }): Promise<{
35
38
  bundle: Document;
36
39
  problems: import("./walk").NormalizedProblem[];
@@ -39,3 +42,4 @@ export declare function bundleDocument(opts: {
39
42
  refTypes: Map<string, NormalizedNodeType> | undefined;
40
43
  visitorsData: Record<string, Record<string, unknown>>;
41
44
  }>;
45
+ export declare function mapTypeToComponent(typeName: string, version: OasMajorVersion): "headers" | "responses" | "definitions" | "parameters" | "schemas" | "examples" | "requestBodies" | "securitySchemes" | "links" | "callbacks" | null;
package/lib/bundle.js CHANGED
@@ -9,7 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  });
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.bundleDocument = exports.bundle = exports.OasVersion = void 0;
12
+ exports.mapTypeToComponent = exports.bundleDocument = exports.bundle = exports.OasVersion = void 0;
13
13
  const isEqual = require("lodash.isequal");
14
14
  const resolve_1 = require("./resolve");
15
15
  const visitors_1 = require("./visitors");
@@ -24,6 +24,8 @@ const rules_1 = require("./config/rules");
24
24
  const no_unresolved_refs_1 = require("./rules/no-unresolved-refs");
25
25
  const utils_1 = require("./utils");
26
26
  const redocly_1 = require("./redocly");
27
+ const remove_unused_components_1 = require("./rules/oas2/remove-unused-components");
28
+ const remove_unused_components_2 = require("./rules/oas3/remove-unused-components");
27
29
  var OasVersion;
28
30
  (function (OasVersion) {
29
31
  OasVersion["Version2"] = "oas2";
@@ -46,7 +48,7 @@ function bundle(opts) {
46
48
  exports.bundle = bundle;
47
49
  function bundleDocument(opts) {
48
50
  return __awaiter(this, void 0, void 0, function* () {
49
- const { document, config, customTypes, externalRefResolver, dereference = false, skipRedoclyRegistryRefs = false, } = opts;
51
+ const { document, config, customTypes, externalRefResolver, dereference = false, skipRedoclyRegistryRefs = false, removeUnusedComponents = false, } = opts;
50
52
  const oasVersion = oas_types_1.detectOpenAPI(document.parsed);
51
53
  const oasMajorVersion = oas_types_1.openAPIMajor(oasVersion);
52
54
  const rules = config.getRulesForOasVersion(oasMajorVersion);
@@ -63,20 +65,29 @@ function bundleDocument(opts) {
63
65
  refTypes: new Map(),
64
66
  visitorsData: {},
65
67
  };
68
+ if (removeUnusedComponents) {
69
+ decorators.push({
70
+ severity: 'error',
71
+ ruleId: 'remove-unused-components',
72
+ visitor: oasMajorVersion === oas_types_1.OasMajorVersion.Version2
73
+ ? remove_unused_components_1.RemoveUnusedComponents({})
74
+ : remove_unused_components_2.RemoveUnusedComponents({})
75
+ });
76
+ }
77
+ const resolvedRefMap = yield resolve_1.resolveDocument({
78
+ rootDocument: document,
79
+ rootType: types.DefinitionRoot,
80
+ externalRefResolver,
81
+ });
66
82
  const bundleVisitor = visitors_1.normalizeVisitors([
67
83
  ...preprocessors,
68
84
  {
69
85
  severity: 'error',
70
86
  ruleId: 'bundler',
71
- visitor: makeBundleVisitor(oasMajorVersion, dereference, skipRedoclyRegistryRefs, document),
87
+ visitor: makeBundleVisitor(oasMajorVersion, dereference, skipRedoclyRegistryRefs, document, resolvedRefMap),
72
88
  },
73
89
  ...decorators,
74
90
  ], types);
75
- const resolvedRefMap = yield resolve_1.resolveDocument({
76
- rootDocument: document,
77
- rootType: types.DefinitionRoot,
78
- externalRefResolver,
79
- });
80
91
  walk_1.walkDocument({
81
92
  document,
82
93
  rootType: types.DefinitionRoot,
@@ -133,8 +144,9 @@ function mapTypeToComponent(typeName, version) {
133
144
  }
134
145
  }
135
146
  }
147
+ exports.mapTypeToComponent = mapTypeToComponent;
136
148
  // function oas3Move
137
- function makeBundleVisitor(version, dereference, skipRedoclyRegistryRefs, rootDocument) {
149
+ function makeBundleVisitor(version, dereference, skipRedoclyRegistryRefs, rootDocument, resolvedRefMap) {
138
150
  let components;
139
151
  const visitor = {
140
152
  ref: {
@@ -163,6 +175,7 @@ function makeBundleVisitor(version, dereference, skipRedoclyRegistryRefs, rootDo
163
175
  }
164
176
  else {
165
177
  node.$ref = saveComponent(componentType, resolved, ctx);
178
+ resolveBundledComponent(node, resolved, ctx);
166
179
  }
167
180
  }
168
181
  },
@@ -199,6 +212,16 @@ function makeBundleVisitor(version, dereference, skipRedoclyRegistryRefs, rootDo
199
212
  },
200
213
  };
201
214
  }
215
+ function resolveBundledComponent(node, resolved, ctx) {
216
+ const newRefId = resolve_1.makeRefId(ctx.location.source.absoluteRef, node.$ref);
217
+ resolvedRefMap.set(newRefId, {
218
+ document: rootDocument,
219
+ isRemote: false,
220
+ node: resolved.node,
221
+ nodePointer: node.$ref,
222
+ resolved: true,
223
+ });
224
+ }
202
225
  function replaceRef(ref, resolved, ctx) {
203
226
  if (!utils_1.isPlainObject(resolved.node)) {
204
227
  ctx.parent[ctx.key] = resolved.node;
@@ -5,10 +5,9 @@ export declare const IGNORE_FILE = ".redocly.lint-ignore.yaml";
5
5
  export declare type RuleConfig = ProblemSeverity | 'off' | ({
6
6
  severity?: ProblemSeverity;
7
7
  } & Record<string, any>);
8
- export declare type PreprocessorConfig = ProblemSeverity | 'off' | 'on' | {
8
+ export declare type PreprocessorConfig = ProblemSeverity | 'off' | 'on' | ({
9
9
  severity?: ProblemSeverity;
10
- options?: Record<string, any>;
11
- };
10
+ } & Record<string, any>);
12
11
  export declare type DecoratorConfig = PreprocessorConfig;
13
12
  export declare type LintRawConfig = {
14
13
  plugins?: (string | Plugin)[];
@@ -107,15 +106,9 @@ export declare class LintConfig {
107
106
  };
108
107
  getPreprocessorSettings(ruleId: string, oasVersion: OasVersion): {
109
108
  severity: ProblemSeverity | "off";
110
- } | {
111
- severity: ProblemSeverity;
112
- options?: Record<string, any> | undefined;
113
109
  };
114
110
  getDecoratorSettings(ruleId: string, oasVersion: OasVersion): {
115
111
  severity: ProblemSeverity | "off";
116
- } | {
117
- severity: ProblemSeverity;
118
- options?: Record<string, any> | undefined;
119
112
  };
120
113
  getUnusedRules(): {
121
114
  rules: string[];
@@ -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';
7
+ export declare type OutputFormat = 'codeframe' | 'stylish' | 'json' | 'checkstyle';
8
8
  export declare function getTotals(problems: (NormalizedProblem & {
9
9
  ignored?: boolean;
10
10
  })[]): Totals;
@@ -66,7 +66,7 @@ function formatProblems(problems, opts) {
66
66
  process.stderr.write(`${formatCodeframe(problem, i)}\n`);
67
67
  }
68
68
  break;
69
- case 'stylish':
69
+ case 'stylish': {
70
70
  const groupedByFile = groupByFiles(problems);
71
71
  for (const [file, { ruleIdPad, locationPad: positionPad, fileProblems }] of Object.entries(groupedByFile)) {
72
72
  process.stderr.write(`${colorette_1.blue(path.relative(cwd, file))}:\n`);
@@ -77,6 +77,19 @@ function formatProblems(problems, opts) {
77
77
  process.stderr.write('\n');
78
78
  }
79
79
  break;
80
+ }
81
+ case 'checkstyle': {
82
+ const groupedByFile = groupByFiles(problems);
83
+ process.stdout.write('<?xml version="1.0" encoding="UTF-8"?>\n');
84
+ process.stdout.write('<checkstyle version="4.3">\n');
85
+ for (const [file, { fileProblems }] of Object.entries(groupedByFile)) {
86
+ process.stdout.write(`<file name="${xmlEscape(path.relative(cwd, file))}">\n`);
87
+ fileProblems.forEach(formatCheckstyle);
88
+ process.stdout.write(`</file>\n`);
89
+ }
90
+ process.stdout.write(`</checkstyle>\n`);
91
+ break;
92
+ }
80
93
  }
81
94
  if (totalProblems - ignoredProblems > maxProblems) {
82
95
  process.stderr.write(`< ... ${totalProblems - maxProblems} more problems hidden > ${colorette_1.gray('increase with `--max-problems N`')}\n`);
@@ -131,6 +144,13 @@ function formatProblems(problems, opts) {
131
144
  const { start } = problem.location[0];
132
145
  return ` ${`${start.line}:${start.col}`.padEnd(locationPad)} ${severityName} ${problem.ruleId.padEnd(ruleIdPad)} ${problem.message}`;
133
146
  }
147
+ function formatCheckstyle(problem) {
148
+ const { line, col } = problem.location[0].start;
149
+ const severity = problem.severity == 'warn' ? 'warning' : 'error';
150
+ const message = xmlEscape(problem.message);
151
+ const source = xmlEscape(problem.ruleId);
152
+ process.stdout.write(`<error line="${line}" column="${col}" severity="${severity}" message="${message}" source="${source}" />\n`);
153
+ }
134
154
  }
135
155
  exports.formatProblems = formatProblems;
136
156
  function formatFrom(cwd, location) {
@@ -167,3 +187,21 @@ const groupByFiles = (problems) => {
167
187
  }
168
188
  return fileGroups;
169
189
  };
190
+ function xmlEscape(s) {
191
+ return s.replace(/[<>&"'\x00-\x1F\x7F\u0080-\uFFFF]/gu, (char) => {
192
+ switch (char) {
193
+ case '<':
194
+ return '&lt;';
195
+ case '>':
196
+ return '&gt;';
197
+ case '&':
198
+ return '&amp;';
199
+ case '"':
200
+ return '&quot;';
201
+ case "'":
202
+ return '&apos;';
203
+ default:
204
+ return `&#${char.charCodeAt(0)};`;
205
+ }
206
+ });
207
+ }
package/lib/index.d.ts CHANGED
@@ -20,4 +20,4 @@ export { WalkContext, walkDocument, NormalizedProblem, ProblemSeverity, LineColL
20
20
  export { getAstNodeByPointer, getLineColLocation } from './format/codeframes';
21
21
  export { formatProblems, OutputFormat, getTotals, Totals } from './format/format';
22
22
  export { lint, lint as validate, lintDocument, lintFromString, lintConfig } from './lint';
23
- export { bundle, bundleDocument } from './bundle';
23
+ export { bundle, bundleDocument, mapTypeToComponent } from './bundle';
package/lib/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.bundleDocument = exports.bundle = exports.lintConfig = exports.lintFromString = exports.lintDocument = exports.validate = exports.lint = exports.getTotals = exports.formatProblems = exports.getLineColLocation = exports.getAstNodeByPointer = exports.walkDocument = exports.normalizeVisitors = exports.OasVersion = exports.openAPIMajor = exports.OasMajorVersion = exports.detectOpenAPI = exports.unescapePointer = exports.stringifyYaml = exports.parseYaml = exports.makeDocumentFromString = exports.YamlParseError = exports.ResolveError = exports.resolveDocument = exports.BaseResolver = exports.Source = exports.RedoclyClient = exports.loadConfig = exports.IGNORE_FILE = exports.LintConfig = exports.Config = exports.Stats = exports.normalizeTypes = exports.ConfigTypes = exports.Oas2Types = exports.Oas3Types = exports.Oas3_1Types = exports.slash = exports.readFileFromUrl = void 0;
3
+ exports.mapTypeToComponent = exports.bundleDocument = exports.bundle = exports.lintConfig = exports.lintFromString = exports.lintDocument = exports.validate = exports.lint = exports.getTotals = exports.formatProblems = exports.getLineColLocation = exports.getAstNodeByPointer = exports.walkDocument = exports.normalizeVisitors = exports.OasVersion = exports.openAPIMajor = exports.OasMajorVersion = exports.detectOpenAPI = exports.unescapePointer = exports.stringifyYaml = exports.parseYaml = exports.makeDocumentFromString = exports.YamlParseError = exports.ResolveError = exports.resolveDocument = exports.BaseResolver = exports.Source = exports.RedoclyClient = exports.loadConfig = exports.IGNORE_FILE = exports.LintConfig = exports.Config = exports.Stats = exports.normalizeTypes = exports.ConfigTypes = exports.Oas2Types = exports.Oas3Types = exports.Oas3_1Types = exports.slash = exports.readFileFromUrl = void 0;
4
4
  var utils_1 = require("./utils");
5
5
  Object.defineProperty(exports, "readFileFromUrl", { enumerable: true, get: function () { return utils_1.readFileFromUrl; } });
6
6
  Object.defineProperty(exports, "slash", { enumerable: true, get: function () { return utils_1.slash; } });
@@ -60,3 +60,4 @@ Object.defineProperty(exports, "lintConfig", { enumerable: true, get: function (
60
60
  var bundle_1 = require("./bundle");
61
61
  Object.defineProperty(exports, "bundle", { enumerable: true, get: function () { return bundle_1.bundle; } });
62
62
  Object.defineProperty(exports, "bundleDocument", { enumerable: true, get: function () { return bundle_1.bundleDocument; } });
63
+ Object.defineProperty(exports, "mapTypeToComponent", { enumerable: true, get: function () { return bundle_1.mapTypeToComponent; } });
package/lib/resolve.d.ts CHANGED
@@ -27,6 +27,7 @@ export declare type Document = {
27
27
  source: Source;
28
28
  parsed: any;
29
29
  };
30
+ export declare function makeRefId(absoluteRef: string, pointer: string): string;
30
31
  export declare function makeDocumentFromString(sourceString: string, absoluteRef: string): {
31
32
  source: Source;
32
33
  parsed: unknown;
package/lib/resolve.js CHANGED
@@ -9,7 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  });
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.resolveDocument = exports.BaseResolver = exports.makeDocumentFromString = exports.YamlParseError = exports.ResolveError = exports.Source = void 0;
12
+ exports.resolveDocument = exports.BaseResolver = exports.makeDocumentFromString = exports.makeRefId = exports.YamlParseError = exports.ResolveError = exports.Source = void 0;
13
13
  const fs = require("fs");
14
14
  const path = require("path");
15
15
  const url = require("url");
@@ -69,6 +69,10 @@ class YamlParseError extends Error {
69
69
  }
70
70
  }
71
71
  exports.YamlParseError = YamlParseError;
72
+ function makeRefId(absoluteRef, pointer) {
73
+ return absoluteRef + '::' + pointer;
74
+ }
75
+ exports.makeRefId = makeRefId;
72
76
  function makeDocumentFromString(sourceString, absoluteRef) {
73
77
  const source = new Source(absoluteRef, sourceString);
74
78
  try {
@@ -255,7 +259,7 @@ function resolveDocument(opts) {
255
259
  document: undefined,
256
260
  error: error,
257
261
  };
258
- const refId = document.source.absoluteRef + '::' + ref.$ref;
262
+ const refId = makeRefId(document.source.absoluteRef, ref.$ref);
259
263
  resolvedRefMap.set(refId, resolvedRef);
260
264
  return resolvedRef;
261
265
  }
@@ -294,7 +298,7 @@ function resolveDocument(opts) {
294
298
  }
295
299
  resolvedRef.node = target;
296
300
  resolvedRef.document = targetDoc;
297
- const refId = document.source.absoluteRef + '::' + ref.$ref;
301
+ const refId = makeRefId(document.source.absoluteRef, ref.$ref);
298
302
  if (resolvedRef.document && ref_utils_1.isRef(target)) {
299
303
  resolvedRef = yield followRef(resolvedRef.document, target, pushRef(refStack, target));
300
304
  }
@@ -10,11 +10,13 @@ export declare const decorators: {
10
10
  'operation-description-override': import("../visitors").Oas3Decorator;
11
11
  'tag-description-override': import("../visitors").Oas3Decorator;
12
12
  'info-description-override': import("../visitors").Oas3Decorator;
13
+ 'remove-x-internal': import("../visitors").Oas3Decorator;
13
14
  };
14
15
  oas2: {
15
16
  'registry-dependencies': import("../visitors").Oas2Decorator;
16
17
  'operation-description-override': import("../visitors").Oas2Decorator;
17
18
  'tag-description-override': import("../visitors").Oas2Decorator;
18
19
  'info-description-override': import("../visitors").Oas2Decorator;
20
+ 'remove-x-internal': import("../visitors").Oas2Decorator;
19
21
  };
20
22
  };
@@ -0,0 +1,2 @@
1
+ import { Oas3Decorator, Oas2Decorator } from '../../visitors';
2
+ export declare const RemoveXInternal: Oas3Decorator | Oas2Decorator;
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RemoveXInternal = void 0;
4
+ const utils_1 = require("../../utils");
5
+ const ref_utils_1 = require("../../ref-utils");
6
+ const DEFAULT_INTERNAL_PROPERTY_NAME = 'x-internal';
7
+ const RemoveXInternal = ({ internalFlagProperty }) => {
8
+ const hiddenTag = internalFlagProperty || DEFAULT_INTERNAL_PROPERTY_NAME;
9
+ function removeInternal(node, ctx) {
10
+ var _a, _b, _c, _d;
11
+ const { parent, key } = ctx;
12
+ let didDelete = false;
13
+ if (Array.isArray(node)) {
14
+ for (let i = 0; i < node.length; i++) {
15
+ if (ref_utils_1.isRef(node[i])) {
16
+ const resolved = ctx.resolve(node[i]);
17
+ if ((_a = resolved.node) === null || _a === void 0 ? void 0 : _a[hiddenTag]) {
18
+ node.splice(i, 1);
19
+ didDelete = true;
20
+ i--;
21
+ }
22
+ }
23
+ if ((_b = node[i]) === null || _b === void 0 ? void 0 : _b[hiddenTag]) {
24
+ node.splice(i, 1);
25
+ didDelete = true;
26
+ i--;
27
+ }
28
+ }
29
+ }
30
+ else if (utils_1.isPlainObject(node)) {
31
+ for (const key of Object.keys(node)) {
32
+ node = node;
33
+ if (ref_utils_1.isRef(node[key])) {
34
+ const resolved = ctx.resolve(node[key]);
35
+ if ((_c = resolved.node) === null || _c === void 0 ? void 0 : _c[hiddenTag]) {
36
+ delete node[key];
37
+ didDelete = true;
38
+ }
39
+ }
40
+ if ((_d = node[key]) === null || _d === void 0 ? void 0 : _d[hiddenTag]) {
41
+ delete node[key];
42
+ didDelete = true;
43
+ }
44
+ }
45
+ }
46
+ if (didDelete && (utils_1.isEmptyObject(node) || utils_1.isEmptyArray(node))) {
47
+ delete parent[key];
48
+ }
49
+ }
50
+ return {
51
+ any: {
52
+ enter: (node, ctx) => {
53
+ removeInternal(node, ctx);
54
+ }
55
+ }
56
+ };
57
+ };
58
+ exports.RemoveXInternal = RemoveXInternal;
@@ -45,4 +45,5 @@ export declare const decorators: {
45
45
  'operation-description-override': Oas2Decorator;
46
46
  'tag-description-override': Oas2Decorator;
47
47
  'info-description-override': Oas2Decorator;
48
+ 'remove-x-internal': Oas2Decorator;
48
49
  };
@@ -42,6 +42,7 @@ const path_segment_plural_1 = require("../common/path-segment-plural");
42
42
  const operation_description_override_1 = require("../common/operation-description-override");
43
43
  const tag_description_override_1 = require("../common/tag-description-override");
44
44
  const info_description_override_1 = require("../common/info-description-override");
45
+ const remove_x_internal_1 = require("../common/remove-x-internal");
45
46
  exports.rules = {
46
47
  spec: spec_1.OasSpec,
47
48
  'no-invalid-schema-examples': no_invalid_schema_examples_1.NoInvalidSchemaExamples,
@@ -88,4 +89,5 @@ exports.decorators = {
88
89
  'operation-description-override': operation_description_override_1.OperationDescriptionOverride,
89
90
  'tag-description-override': tag_description_override_1.TagDescriptionOverride,
90
91
  'info-description-override': info_description_override_1.InfoDescriptionOverride,
92
+ 'remove-x-internal': remove_x_internal_1.RemoveXInternal
91
93
  };
@@ -0,0 +1,2 @@
1
+ import { Oas2Rule } from '../../visitors';
2
+ export declare const RemoveUnusedComponents: Oas2Rule;
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RemoveUnusedComponents = void 0;
4
+ const utils_1 = require("../../utils");
5
+ const RemoveUnusedComponents = () => {
6
+ let components = new Map();
7
+ function registerComponent(location, componentType, name) {
8
+ var _a;
9
+ components.set(location.absolutePointer, {
10
+ used: ((_a = components.get(location.absolutePointer)) === null || _a === void 0 ? void 0 : _a.used) || false,
11
+ componentType,
12
+ name,
13
+ });
14
+ }
15
+ return {
16
+ ref: {
17
+ leave(ref, { type, resolve, key }) {
18
+ if (['Schema', 'Parameter', 'Response', 'SecurityScheme'].includes(type.name)) {
19
+ const resolvedRef = resolve(ref);
20
+ if (!resolvedRef.location)
21
+ return;
22
+ components.set(resolvedRef.location.absolutePointer, {
23
+ used: true,
24
+ name: key.toString(),
25
+ });
26
+ }
27
+ }
28
+ },
29
+ DefinitionRoot: {
30
+ leave(root, ctx) {
31
+ const data = ctx.getVisitorData();
32
+ data.removedCount = 0;
33
+ let rootComponents = new Set();
34
+ components.forEach(usageInfo => {
35
+ const { used, name, componentType } = usageInfo;
36
+ if (!used && componentType) {
37
+ rootComponents.add(componentType);
38
+ delete root[componentType][name];
39
+ data.removedCount++;
40
+ }
41
+ });
42
+ for (const component of rootComponents) {
43
+ if (utils_1.isEmptyObject(root[component])) {
44
+ delete root[component];
45
+ }
46
+ }
47
+ },
48
+ },
49
+ NamedSchemas: {
50
+ Schema(schema, { location, key }) {
51
+ if (!schema.allOf) {
52
+ registerComponent(location, 'definitions', key.toString());
53
+ }
54
+ },
55
+ },
56
+ NamedParameters: {
57
+ Parameter(_parameter, { location, key }) {
58
+ registerComponent(location, 'parameters', key.toString());
59
+ },
60
+ },
61
+ NamedResponses: {
62
+ Response(_response, { location, key }) {
63
+ registerComponent(location, 'responses', key.toString());
64
+ },
65
+ },
66
+ NamedSecuritySchemes: {
67
+ SecurityScheme(_securityScheme, { location, key }) {
68
+ registerComponent(location, 'securityDefinitions', key.toString());
69
+ },
70
+ }
71
+ };
72
+ };
73
+ exports.RemoveUnusedComponents = RemoveUnusedComponents;
@@ -7,4 +7,5 @@ export declare const decorators: {
7
7
  'operation-description-override': Oas3Decorator;
8
8
  'tag-description-override': Oas3Decorator;
9
9
  'info-description-override': Oas3Decorator;
10
+ 'remove-x-internal': Oas3Decorator;
10
11
  };
@@ -50,6 +50,7 @@ const info_description_override_1 = require("../common/info-description-override
50
50
  const path_excludes_patterns_1 = require("../common/path-excludes-patterns");
51
51
  const no_invalid_schema_examples_1 = require("../common/no-invalid-schema-examples");
52
52
  const no_invalid_parameter_examples_1 = require("../common/no-invalid-parameter-examples");
53
+ const remove_x_internal_1 = require("../common/remove-x-internal");
53
54
  exports.rules = {
54
55
  spec: spec_1.OasSpec,
55
56
  'info-description': info_description_1.InfoDescription,
@@ -104,4 +105,5 @@ exports.decorators = {
104
105
  'operation-description-override': operation_description_override_1.OperationDescriptionOverride,
105
106
  'tag-description-override': tag_description_override_1.TagDescriptionOverride,
106
107
  'info-description-override': info_description_override_1.InfoDescriptionOverride,
108
+ 'remove-x-internal': remove_x_internal_1.RemoveXInternal
107
109
  };
@@ -0,0 +1,2 @@
1
+ import { Oas3Rule } from '../../visitors';
2
+ export declare const RemoveUnusedComponents: Oas3Rule;
@@ -0,0 +1,83 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RemoveUnusedComponents = void 0;
4
+ const utils_1 = require("../../utils");
5
+ const RemoveUnusedComponents = () => {
6
+ let components = new Map();
7
+ function registerComponent(location, componentType, name) {
8
+ var _a;
9
+ components.set(location.absolutePointer, {
10
+ used: ((_a = components.get(location.absolutePointer)) === null || _a === void 0 ? void 0 : _a.used) || false,
11
+ componentType,
12
+ name,
13
+ });
14
+ }
15
+ return {
16
+ ref: {
17
+ leave(ref, { type, resolve, key }) {
18
+ if (['Schema', 'Header', 'Parameter', 'Response', 'Example', 'RequestBody'].includes(type.name)) {
19
+ const resolvedRef = resolve(ref);
20
+ if (!resolvedRef.location)
21
+ return;
22
+ components.set(resolvedRef.location.absolutePointer, {
23
+ used: true,
24
+ name: key.toString(),
25
+ });
26
+ }
27
+ }
28
+ },
29
+ DefinitionRoot: {
30
+ leave(root, ctx) {
31
+ const data = ctx.getVisitorData();
32
+ data.removedCount = 0;
33
+ components.forEach(usageInfo => {
34
+ const { used, componentType, name } = usageInfo;
35
+ if (!used && componentType) {
36
+ let componentChild = root.components[componentType];
37
+ delete componentChild[name];
38
+ data.removedCount++;
39
+ if (utils_1.isEmptyObject(componentChild)) {
40
+ delete root.components[componentType];
41
+ }
42
+ }
43
+ });
44
+ if (utils_1.isEmptyObject(root.components)) {
45
+ delete root.components;
46
+ }
47
+ },
48
+ },
49
+ NamedSchemas: {
50
+ Schema(schema, { location, key }) {
51
+ if (!schema.allOf) {
52
+ registerComponent(location, 'schemas', key.toString());
53
+ }
54
+ },
55
+ },
56
+ NamedParameters: {
57
+ Parameter(_parameter, { location, key }) {
58
+ registerComponent(location, 'parameters', key.toString());
59
+ },
60
+ },
61
+ NamedResponses: {
62
+ Response(_response, { location, key }) {
63
+ registerComponent(location, 'responses', key.toString());
64
+ },
65
+ },
66
+ NamedExamples: {
67
+ Example(_example, { location, key }) {
68
+ registerComponent(location, 'examples', key.toString());
69
+ },
70
+ },
71
+ NamedRequestBodies: {
72
+ RequestBody(_requestBody, { location, key }) {
73
+ registerComponent(location, 'requestBodies', key.toString());
74
+ },
75
+ },
76
+ NamedHeaders: {
77
+ Header(_header, { location, key }) {
78
+ registerComponent(location, 'headers', key.toString());
79
+ },
80
+ },
81
+ };
82
+ };
83
+ exports.RemoveUnusedComponents = RemoveUnusedComponents;
@@ -16,6 +16,20 @@ export interface Oas2Definition {
16
16
  tags?: Oas2Tag[];
17
17
  externalDocs?: Oas2ExternalDocs;
18
18
  }
19
+ export interface Oas2Components {
20
+ definitions?: {
21
+ [name: string]: Record<string, Oas2Schema>;
22
+ };
23
+ securityDefinitions?: {
24
+ [name: string]: Record<string, Oas2SecurityScheme>;
25
+ };
26
+ responses?: {
27
+ [name: string]: Record<string, Oas2Response>;
28
+ };
29
+ parameters?: {
30
+ [name: string]: Record<string, Oas2Parameter>;
31
+ };
32
+ }
19
33
  export interface Oas2Info {
20
34
  title: string;
21
35
  version: string;
package/lib/utils.d.ts CHANGED
@@ -16,6 +16,8 @@ export declare type BundleOutputFormat = 'json' | 'yml' | 'yaml';
16
16
  export declare function loadYaml(filename: string): Promise<unknown>;
17
17
  export declare function notUndefined<T>(x: T | undefined): x is T;
18
18
  export declare function isPlainObject(value: any): value is object;
19
+ export declare function isEmptyObject(value: any): value is object;
20
+ export declare function isEmptyArray(value: any): boolean;
19
21
  export declare function readFileFromUrl(url: string, config: HttpResolveConfig): Promise<{
20
22
  body: any;
21
23
  mimeType: any;
package/lib/utils.js CHANGED
@@ -9,7 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  });
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.isNotEmptyObject = exports.slash = exports.isPathParameter = exports.readFileAsStringSync = exports.isSingular = exports.validateMimeTypeOAS3 = exports.validateMimeType = exports.splitCamelCaseIntoWords = exports.omitObjectProps = exports.pickObjectProps = exports.match = exports.readFileFromUrl = exports.isPlainObject = exports.notUndefined = exports.loadYaml = exports.popStack = exports.pushStack = exports.stringifyYaml = exports.parseYaml = void 0;
12
+ exports.isNotEmptyObject = exports.slash = exports.isPathParameter = exports.readFileAsStringSync = exports.isSingular = exports.validateMimeTypeOAS3 = exports.validateMimeType = exports.splitCamelCaseIntoWords = exports.omitObjectProps = exports.pickObjectProps = exports.match = exports.readFileFromUrl = exports.isEmptyArray = exports.isEmptyObject = exports.isPlainObject = exports.notUndefined = exports.loadYaml = exports.popStack = exports.pushStack = exports.stringifyYaml = exports.parseYaml = void 0;
13
13
  const fs = require("fs");
14
14
  const minimatch = require("minimatch");
15
15
  const node_fetch_1 = require("node-fetch");
@@ -42,6 +42,14 @@ function isPlainObject(value) {
42
42
  return value !== null && typeof value === 'object' && !Array.isArray(value);
43
43
  }
44
44
  exports.isPlainObject = isPlainObject;
45
+ function isEmptyObject(value) {
46
+ return isPlainObject(value) && Object.keys(value).length === 0;
47
+ }
48
+ exports.isEmptyObject = isEmptyObject;
49
+ function isEmptyArray(value) {
50
+ return Array.isArray(value) && value.length === 0;
51
+ }
52
+ exports.isEmptyArray = isEmptyArray;
45
53
  function readFileFromUrl(url, config) {
46
54
  return __awaiter(this, void 0, void 0, function* () {
47
55
  const headers = {};