oas-toolkit 0.7.4 → 0.7.6

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.
package/components.js CHANGED
@@ -2,6 +2,7 @@ const traverse = require("traverse");
2
2
  const isEqual = require("lodash.isequal");
3
3
  const difference = require("lodash.difference");
4
4
  const intersection = require("lodash.intersection");
5
+ const uniqWith = require("lodash.uniqwith");
5
6
 
6
7
  function removeUnusedComponents(oas) {
7
8
  const used = getReferencedComponents(oas);
@@ -90,20 +91,79 @@ function getDefinedComponents(oas) {
90
91
  }, []);
91
92
  }
92
93
 
94
+ // This is a horrible global hack, but it works
95
+ const referencesTo = {};
93
96
  function getUnusedComponents(all, referenced, oas) {
94
97
  const unused = difference(all, referenced);
95
98
 
99
+ if (!oas) {
100
+ return unused;
101
+ }
102
+
96
103
  // If we have a component that is only referenced by itself, it's unused
97
104
  const used = intersection(all, referenced);
98
105
  for (let component of used) {
106
+ if (component.startsWith("components.securitySchemes")) {
107
+ continue;
108
+ }
109
+
99
110
  const references = getReferencesToComponent(oas, component);
100
111
  if (references.length == 1 && references[0] === component) {
101
112
  unused.push(component);
102
113
  }
114
+
115
+ // If there's a circular dependency and nothing else, it can be removed
116
+ for (let ref of references) {
117
+ referencesTo[ref] = getRecursiveReferencesToComponent(oas, ref);
118
+ // Add all the references for each reference to build a complete list
119
+ referencesTo[ref] = referencesTo[ref].concat(
120
+ referencesTo[ref].flatMap((r) => {
121
+ if (!referencesTo[r]) {
122
+ return [];
123
+ }
124
+ return referencesTo[r];
125
+ })
126
+ );
127
+ referencesTo[ref] = uniqWith(referencesTo[ref], isEqual);
128
+ }
129
+
130
+ let shouldRemove = true;
131
+ for (let ref of references) {
132
+ if (!isEqual(referencesTo[component], referencesTo[ref])) {
133
+ shouldRemove = false;
134
+ }
135
+ }
136
+ if (shouldRemove) {
137
+ unused.push(component);
138
+ }
103
139
  }
104
140
  return unused;
105
141
  }
106
142
 
143
+ const recursiveCache = {};
144
+ function getRecursiveReferencesToComponent(oas, component, originalComponents) {
145
+ if (recursiveCache[component]) {
146
+ return recursiveCache[component];
147
+ }
148
+
149
+ if (!originalComponents) {
150
+ originalComponents = [];
151
+ }
152
+ originalComponents.push(component);
153
+ let refs = getReferencesToComponent(oas, component);
154
+ for (const ref of refs) {
155
+ if (!originalComponents.includes(ref)) {
156
+ refs = refs.concat(
157
+ getRecursiveReferencesToComponent(oas, ref, originalComponents)
158
+ );
159
+ }
160
+ }
161
+ refs.sort();
162
+
163
+ recursiveCache[component] = refs;
164
+ return refs;
165
+ }
166
+
107
167
  module.exports = {
108
168
  getReferencedComponents,
109
169
  getDefinedComponents,
@@ -253,7 +253,7 @@ describe("#components", () => {
253
253
  });
254
254
  });
255
255
 
256
- it("Removes schemas that are circular", () => {
256
+ it("Removes schemas that are circular (self reference)", () => {
257
257
  expect(
258
258
  c.removeUnusedComponents({
259
259
  info: { title: "One" },
@@ -276,6 +276,42 @@ describe("#components", () => {
276
276
  });
277
277
  });
278
278
 
279
+ it("Removes schemas that are circular (loop)", () => {
280
+ expect(
281
+ c.removeUnusedComponents({
282
+ info: { title: "One" },
283
+ components: {
284
+ schemas: {
285
+ SchemaA: {
286
+ properties: {
287
+ subSchema: {
288
+ $ref: "#/components/schemas/SchemaC",
289
+ },
290
+ },
291
+ },
292
+ SchemaB: {
293
+ properties: {
294
+ subSchema: {
295
+ $ref: "#/components/schemas/SchemaA",
296
+ },
297
+ },
298
+ },
299
+ SchemaC: {
300
+ properties: {
301
+ subSchema: {
302
+ $ref: "#/components/schemas/SchemaB",
303
+ },
304
+ },
305
+ },
306
+ },
307
+ },
308
+ })
309
+ ).toEqual({
310
+ info: { title: "One" },
311
+ components: {},
312
+ });
313
+ });
314
+
279
315
  it("Does not remove circular schemas that are also referenced elsewhere", () => {
280
316
  expect(
281
317
  c.removeUnusedComponents({
package/merger.test.js CHANGED
@@ -491,7 +491,7 @@ describe("returns unique items for:", () => {
491
491
  });
492
492
  });
493
493
 
494
- fit("handles keys that don't exist in both specs", () => {
494
+ it("handles keys that don't exist in both specs", () => {
495
495
  expect(
496
496
  merger([
497
497
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oas-toolkit",
3
- "version": "0.7.4",
3
+ "version": "0.7.6",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "bin": {