UNPKG

@har-sdk/openapi-sampler

Version:

[![Maintainability](https://api.codeclimate.com/v1/badges/4acaec95c82465cb2c3d/maintainability)](https://codeclimate.com/github/NeuraLegion/har-sdk/maintainability) [![Test Coverage](https://api.codeclimate.com/v1/badges/4acaec95c82465cb2c3d/test_coverage

213 lines 7.86 kB
import { SchemaExampleExtractor } from './SchemaExampleExtractor'; import { firstArrayElement, getReplacementForCircular, isReference, mergeDeep } from '../utils'; import JsonPointer from 'json-pointer'; const schemaKeywordTypes = { multipleOf: 'number', maximum: 'number', exclusiveMaximum: 'number', minimum: 'number', exclusiveMinimum: 'number', maxLength: 'string', minLength: 'string', pattern: 'string', items: 'array', maxItems: 'array', minItems: 'array', uniqueItems: 'array', additionalItems: 'array', maxProperties: 'object', minProperties: 'object', required: 'object', additionalProperties: 'object', properties: 'object', patternProperties: 'object', dependencies: 'object' }; export class DefaultTraverse { constructor(sampleValueExtractor = new SchemaExampleExtractor()) { this.sampleValueExtractor = sampleValueExtractor; this.NULL = 'null'; this.refCache = {}; this.schemasStack = []; } get samplers() { return this._samplers; } set samplers(samplers) { this._samplers = samplers; } clearCache() { this.refCache = {}; this.schemasStack = []; } // eslint-disable-next-line complexity traverse(schema, options, spec) { var _a, _b; if (!this.samplers || this.samplers.size === 0) { throw Error('Samplers must be set'); } if (this.checkIfCircleRef(schema, options)) { return this.getReplacementForCircular(schema); } this.pushSchemaStack(schema); if (isReference(schema)) { return this.inferRef(spec, schema, options); } return ((_b = (_a = this.findSchemaExample(schema, options)) !== null && _a !== void 0 ? _a : this.tryTraverseSubSchema(schema, options, spec)) !== null && _b !== void 0 ? _b : this.createSchemaExample(schema, options, spec)); } createSchemaExample(schema, options, spec) { const type = schema.type; let value = this.sampleValueExtractor.extractFromProperties(schema); value = value === undefined ? this.createSampleValueFromInferredType(schema, options, spec) : value; this.popSchemaStack(); const { readOnly, writeOnly } = schema; return { type, readOnly, writeOnly, value }; } createSampleValueFromInferredType(schema, options, spec) { var _a; let type = schema.type; if (Array.isArray(type)) { type = (_a = type.find((x) => x !== this.NULL)) !== null && _a !== void 0 ? _a : type.find((x) => x === this.NULL); } if (!type) { type = this.inferType(schema); } const sampler = this.samplers.get(type || this.NULL); let value; if (sampler) { value = sampler.sample(schema, spec, options); } return value; } tryTraverseSubSchema(schema, options, spec) { var _a, _b; return ((_b = (_a = this.tryTraverseAllOf(schema, options, spec)) !== null && _a !== void 0 ? _a : this.tryTraverseOneOf(schema, options, spec)) !== null && _b !== void 0 ? _b : this.tryTraverseAnyOf(schema, options, spec)); } tryTraverseAllOf(schema, options, spec) { if (schema.allOf) { this.popSchemaStack(); return this.allOfSample({ ...schema, allOf: undefined }, schema.allOf, options, spec); } } tryTraverseOneOf(schema, options, spec) { if (schema.oneOf && schema.oneOf.length) { if (schema.anyOf && !options.quiet) { // eslint-disable-next-line no-console console.warn('oneOf and anyOf are not supported on the same level. Skipping anyOf'); } this.popSchemaStack(); return this.traverse(firstArrayElement(schema.oneOf), options, spec); } } tryTraverseAnyOf(schema, options, spec) { if (schema.anyOf && schema.anyOf.length) { this.popSchemaStack(); return this.traverse(firstArrayElement(schema.anyOf), options, spec); } } findSchemaExample(schema, options) { const value = this.sampleValueExtractor.extractFromExamples(schema, options); if (value !== undefined) { const { type, readOnly, writeOnly } = schema; this.popSchemaStack(); return { type, readOnly, writeOnly, value }; } } pushSchemaStack(schema) { this.schemasStack.push(schema); } checkIfCircleRef(schema, options) { return (this.schemasStack.includes(schema) && this.schemasStack.length > options.maxSampleDepth); } inferRef(spec, schema, options) { if (!spec) { throw new Error('Your schema contains $ref. You must provide specification in the third parameter.'); } let ref = decodeURIComponent(schema.$ref); if (ref.startsWith('#')) { ref = ref.substring(1); } const referenced = JsonPointer.get(spec, ref); let result; if (!this.refCache[ref]) { this.refCache[ref] = true; result = this.traverse(referenced, options, spec); this.refCache[ref] = false; } else { result = this.getReplacementForCircular(referenced); } this.popSchemaStack(); return result; } getReplacementForCircular(referenced) { const referencedType = this.inferType(referenced); return getReplacementForCircular(referencedType); } popSchemaStack() { this.schemasStack.pop(); } inferType(schema) { const keywords = Object.keys(schemaKeywordTypes); for (let i = 0; i < keywords.length; i++) { const keyword = keywords[i]; const type = schemaKeywordTypes[keyword]; if (schema[keyword]) { return type; } } return null; } // eslint-disable-next-line complexity allOfSample(into, children, options, spec) { const res = this.traverse(into, options, spec); const subSamples = []; for (const subSchema of children) { const { type, readOnly, writeOnly, value } = this.traverse(subSchema, options, spec); if (res.type && type && type !== res.type) { throw new Error(`allOf: schemas with different types can't be merged`); } res.type = res.type || type; res.readOnly = res.readOnly || readOnly; res.writeOnly = res.writeOnly || writeOnly; if (value != null) { subSamples.push(value); } } switch (res.type) { case 'object': res.value = mergeDeep(res.value || {}, ...subSamples); break; case 'array': if (!options.quiet) { // eslint-disable-next-line no-console console.warn('OpenAPI Sampler: found allOf with "array" type. Result may be incorrect'); } // eslint-disable-next-line no-case-declarations const arraySchema = mergeDeep(...children); res.value = this.traverse(arraySchema, options, spec).value; break; default: // eslint-disable-next-line no-case-declarations const lastSample = subSamples[subSamples.length - 1]; res.value = lastSample != null ? lastSample : res.value; } return res; } } //# sourceMappingURL=DefaultTraverse.js.map