source: node_modules/swagger-client/lib/specmap/index.js

main
Last change on this file was d24f17c, checked in by Aleksandar Panovski <apano77@…>, 15 months ago

Initial commit

  • Property mode set to 100644
File size: 11.6 KB
RevLine 
[d24f17c]1"use strict";
2
3var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault").default;
4exports.__esModule = true;
5exports.SpecMap = void 0;
6exports.default = mapSpec;
7exports.plugins = void 0;
8var _index = _interopRequireDefault(require("./lib/index.js"));
9var _refs = _interopRequireDefault(require("./lib/refs.js"));
10var _allOf = _interopRequireDefault(require("./lib/all-of.js"));
11var _parameters = _interopRequireDefault(require("./lib/parameters.js"));
12var _properties = _interopRequireDefault(require("./lib/properties.js"));
13var _contextTree = _interopRequireDefault(require("./lib/context-tree.js"));
14const HARD_LIMIT = 100;
15const noop = () => {};
16class SpecMap {
17 static getPluginName(plugin) {
18 return plugin.pluginName;
19 }
20 static getPatchesOfType(patches, fn) {
21 return patches.filter(fn);
22 }
23 constructor(opts) {
24 Object.assign(this, {
25 spec: '',
26 debugLevel: 'info',
27 plugins: [],
28 pluginHistory: {},
29 errors: [],
30 mutations: [],
31 promisedPatches: [],
32 state: {},
33 patches: [],
34 context: {},
35 contextTree: new _contextTree.default(),
36 showDebug: false,
37 allPatches: [],
38 // only populated if showDebug is true
39 pluginProp: 'specMap',
40 libMethods: Object.assign(Object.create(this), _index.default, {
41 getInstance: () => this
42 }),
43 allowMetaPatches: false
44 }, opts);
45
46 // Lib methods bound
47 this.get = this._get.bind(this); // eslint-disable-line no-underscore-dangle
48 this.getContext = this._getContext.bind(this); // eslint-disable-line no-underscore-dangle
49 this.hasRun = this._hasRun.bind(this); // eslint-disable-line no-underscore-dangle
50
51 this.wrappedPlugins = this.plugins.map(this.wrapPlugin.bind(this)).filter(_index.default.isFunction);
52
53 // Initial patch(s)
54 this.patches.push(_index.default.add([], this.spec));
55 this.patches.push(_index.default.context([], this.context));
56 this.updatePatches(this.patches);
57 }
58 debug(level, ...args) {
59 if (this.debugLevel === level) {
60 console.log(...args); // eslint-disable-line no-console
61 }
62 }
63 verbose(header, ...args) {
64 if (this.debugLevel === 'verbose') {
65 console.log(`[${header}] `, ...args); // eslint-disable-line no-console
66 }
67 }
68 wrapPlugin(plugin, name) {
69 const {
70 pathDiscriminator
71 } = this;
72 let ctx = null;
73 let fn;
74 if (plugin[this.pluginProp]) {
75 ctx = plugin;
76 fn = plugin[this.pluginProp];
77 } else if (_index.default.isFunction(plugin)) {
78 fn = plugin;
79 } else if (_index.default.isObject(plugin)) {
80 fn = createKeyBasedPlugin(plugin);
81 }
82 return Object.assign(fn.bind(ctx), {
83 pluginName: plugin.name || name,
84 isGenerator: _index.default.isGenerator(fn)
85 });
86
87 // Expected plugin interface: {key: string, plugin: fn*}
88 // This traverses depth-first and immediately applies yielded patches.
89 // This strategy should work well for most plugins (including the built-ins).
90 // We might consider making this (traversing & application) configurable later.
91 function createKeyBasedPlugin(pluginObj) {
92 const isSubPath = (path, tested) => {
93 if (!Array.isArray(path)) {
94 return true;
95 }
96 return path.every((val, i) => val === tested[i]);
97 };
98 return function* generator(patches, specmap) {
99 const refCache = {};
100
101 // eslint-disable-next-line no-restricted-syntax
102 for (const patch of patches.filter(_index.default.isAdditiveMutation)) {
103 yield* traverse(patch.value, patch.path, patch);
104 }
105 function* traverse(obj, path, patch) {
106 if (!_index.default.isObject(obj)) {
107 if (pluginObj.key === path[path.length - 1]) {
108 yield pluginObj.plugin(obj, pluginObj.key, path, specmap);
109 }
110 } else {
111 const parentIndex = path.length - 1;
112 const parent = path[parentIndex];
113 const indexOfFirstProperties = path.indexOf('properties');
114 const isRootProperties = parent === 'properties' && parentIndex === indexOfFirstProperties;
115 const traversed = specmap.allowMetaPatches && refCache[obj.$$ref];
116
117 // eslint-disable-next-line no-restricted-syntax
118 for (const key of Object.keys(obj)) {
119 const val = obj[key];
120 const updatedPath = path.concat(key);
121 const isObj = _index.default.isObject(val);
122 const objRef = obj.$$ref;
123 if (!traversed) {
124 if (isObj) {
125 // Only store the ref if it exists
126 if (specmap.allowMetaPatches && objRef) {
127 refCache[objRef] = true;
128 }
129 yield* traverse(val, updatedPath, patch);
130 }
131 }
132 if (!isRootProperties && key === pluginObj.key) {
133 const isWithinPathDiscriminator = isSubPath(pathDiscriminator, path);
134 if (!pathDiscriminator || isWithinPathDiscriminator) {
135 yield pluginObj.plugin(val, key, updatedPath, specmap, patch);
136 }
137 }
138 }
139 }
140 }
141 };
142 }
143 }
144 nextPlugin() {
145 return this.wrappedPlugins.find(plugin => {
146 const mutations = this.getMutationsForPlugin(plugin);
147 return mutations.length > 0;
148 });
149 }
150 nextPromisedPatch() {
151 if (this.promisedPatches.length > 0) {
152 return Promise.race(this.promisedPatches.map(patch => patch.value));
153 }
154 return undefined;
155 }
156 getPluginHistory(plugin) {
157 const name = this.constructor.getPluginName(plugin);
158 return this.pluginHistory[name] || [];
159 }
160 getPluginRunCount(plugin) {
161 return this.getPluginHistory(plugin).length;
162 }
163 getPluginHistoryTip(plugin) {
164 const history = this.getPluginHistory(plugin);
165 const val = history && history[history.length - 1];
166 return val || {};
167 }
168 getPluginMutationIndex(plugin) {
169 const mi = this.getPluginHistoryTip(plugin).mutationIndex;
170 return typeof mi !== 'number' ? -1 : mi;
171 }
172 updatePluginHistory(plugin, val) {
173 const name = this.constructor.getPluginName(plugin);
174 this.pluginHistory[name] = this.pluginHistory[name] || [];
175 this.pluginHistory[name].push(val);
176 }
177 updatePatches(patches) {
178 _index.default.normalizeArray(patches).forEach(patch => {
179 if (patch instanceof Error) {
180 this.errors.push(patch);
181 return;
182 }
183 try {
184 if (!_index.default.isObject(patch)) {
185 this.debug('updatePatches', 'Got a non-object patch', patch);
186 return;
187 }
188 if (this.showDebug) {
189 this.allPatches.push(patch);
190 }
191 if (_index.default.isPromise(patch.value)) {
192 this.promisedPatches.push(patch);
193 this.promisedPatchThen(patch);
194 return;
195 }
196 if (_index.default.isContextPatch(patch)) {
197 this.setContext(patch.path, patch.value);
198 return;
199 }
200 if (_index.default.isMutation(patch)) {
201 this.updateMutations(patch);
202 }
203 } catch (e) {
204 console.error(e); // eslint-disable-line no-console
205 this.errors.push(e);
206 }
207 });
208 }
209 updateMutations(patch) {
210 if (typeof patch.value === 'object' && !Array.isArray(patch.value) && this.allowMetaPatches) {
211 patch.value = {
212 ...patch.value
213 };
214 }
215 const result = _index.default.applyPatch(this.state, patch, {
216 allowMetaPatches: this.allowMetaPatches
217 });
218 if (result) {
219 this.mutations.push(patch);
220 this.state = result;
221 }
222 }
223 removePromisedPatch(patch) {
224 const index = this.promisedPatches.indexOf(patch);
225 if (index < 0) {
226 this.debug("Tried to remove a promisedPatch that isn't there!");
227 return;
228 }
229 this.promisedPatches.splice(index, 1);
230 }
231 promisedPatchThen(patch) {
232 patch.value = patch.value.then(val => {
233 const promisedPatch = {
234 ...patch,
235 value: val
236 };
237 this.removePromisedPatch(patch);
238 this.updatePatches(promisedPatch);
239 }).catch(e => {
240 this.removePromisedPatch(patch);
241 this.updatePatches(e);
242 });
243 return patch.value;
244 }
245 getMutations(from, to) {
246 from = from || 0;
247 if (typeof to !== 'number') {
248 to = this.mutations.length;
249 }
250 return this.mutations.slice(from, to);
251 }
252 getCurrentMutations() {
253 return this.getMutationsForPlugin(this.getCurrentPlugin());
254 }
255 getMutationsForPlugin(plugin) {
256 const tip = this.getPluginMutationIndex(plugin);
257 return this.getMutations(tip + 1);
258 }
259 getCurrentPlugin() {
260 return this.currentPlugin;
261 }
262 getLib() {
263 return this.libMethods;
264 }
265
266 // eslint-disable-next-line no-underscore-dangle
267 _get(path) {
268 return _index.default.getIn(this.state, path);
269 }
270
271 // eslint-disable-next-line no-underscore-dangle
272 _getContext(path) {
273 return this.contextTree.get(path);
274 }
275 setContext(path, value) {
276 return this.contextTree.set(path, value);
277 }
278
279 // eslint-disable-next-line no-underscore-dangle
280 _hasRun(count) {
281 const times = this.getPluginRunCount(this.getCurrentPlugin());
282 return times > (count || 0);
283 }
284 dispatch() {
285 const that = this;
286 const plugin = this.nextPlugin();
287 if (!plugin) {
288 const nextPromise = this.nextPromisedPatch();
289 if (nextPromise) {
290 return nextPromise.then(() => this.dispatch()).catch(() => this.dispatch());
291 }
292
293 // We're done!
294 const result = {
295 spec: this.state,
296 errors: this.errors
297 };
298 if (this.showDebug) {
299 result.patches = this.allPatches;
300 }
301 return Promise.resolve(result);
302 }
303
304 // Makes sure plugin isn't running an endless loop
305 that.pluginCount = that.pluginCount || {};
306 that.pluginCount[plugin] = (that.pluginCount[plugin] || 0) + 1;
307 if (that.pluginCount[plugin] > HARD_LIMIT) {
308 return Promise.resolve({
309 spec: that.state,
310 errors: that.errors.concat(new Error(`We've reached a hard limit of ${HARD_LIMIT} plugin runs`))
311 });
312 }
313
314 // A different plugin runs, wait for all promises to resolve, then retry
315 if (plugin !== this.currentPlugin && this.promisedPatches.length) {
316 const promises = this.promisedPatches.map(p => p.value);
317
318 // Waits for all to settle instead of Promise.all which stops on rejection
319 return Promise.all(promises.map(promise => promise.then(noop, noop))).then(() => this.dispatch());
320 }
321
322 // Ok, run the plugin
323 return executePlugin();
324 function executePlugin() {
325 that.currentPlugin = plugin;
326 const mutations = that.getCurrentMutations();
327 const lastMutationIndex = that.mutations.length - 1;
328 try {
329 if (plugin.isGenerator) {
330 // eslint-disable-next-line no-restricted-syntax
331 for (const yieldedPatches of plugin(mutations, that.getLib())) {
332 updatePatches(yieldedPatches);
333 }
334 } else {
335 const newPatches = plugin(mutations, that.getLib());
336 updatePatches(newPatches);
337 }
338 } catch (e) {
339 console.error(e); // eslint-disable-line no-console
340 updatePatches([Object.assign(Object.create(e), {
341 plugin
342 })]);
343 } finally {
344 that.updatePluginHistory(plugin, {
345 mutationIndex: lastMutationIndex
346 });
347 }
348 return that.dispatch();
349 }
350 function updatePatches(patches) {
351 if (patches) {
352 patches = _index.default.fullyNormalizeArray(patches);
353 that.updatePatches(patches, plugin);
354 }
355 }
356 }
357}
358exports.SpecMap = SpecMap;
359function mapSpec(opts) {
360 return new SpecMap(opts).dispatch();
361}
362const plugins = exports.plugins = {
363 refs: _refs.default,
364 allOf: _allOf.default,
365 parameters: _parameters.default,
366 properties: _properties.default
367};
Note: See TracBrowser for help on using the repository browser.