UNPKG

@angular-devkit/core

Version:

Angular DevKit - Core Utility Library

147 lines (146 loc) 6.5 kB
"use strict"; /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.dev/license */ Object.defineProperty(exports, "__esModule", { value: true }); exports.visitJson = visitJson; exports.visitJsonSchema = visitJsonSchema; const rxjs_1 = require("rxjs"); const pointer_1 = require("./pointer"); function _getObjectSubSchema(schema, key) { if (typeof schema !== 'object' || schema === null) { return undefined; } // Is it an object schema? if (typeof schema.properties == 'object' || schema.type == 'object') { if (typeof schema.properties == 'object' && typeof schema.properties[key] == 'object') { return schema.properties[key]; } if (typeof schema.additionalProperties == 'object') { return schema.additionalProperties; } return undefined; } // Is it an array schema? if (typeof schema.items == 'object' || schema.type == 'array') { return typeof schema.items == 'object' ? schema.items : undefined; } return undefined; } function _visitJsonRecursive(json, visitor, ptr, schema, refResolver, context, root) { if (schema === true || schema === false) { // There's no schema definition, so just visit the JSON recursively. schema = undefined; } // eslint-disable-next-line no-prototype-builtins if (schema && schema.hasOwnProperty('$ref') && typeof schema['$ref'] == 'string') { if (refResolver) { const resolved = refResolver(schema['$ref'], context); schema = resolved.schema; context = resolved.context; } } const value = visitor(json, ptr, schema, root); return ((0, rxjs_1.isObservable)(value) ? value : (0, rxjs_1.of)(value)).pipe((0, rxjs_1.concatMap)((value) => { if (Array.isArray(value)) { return (0, rxjs_1.concat)((0, rxjs_1.from)(value).pipe((0, rxjs_1.mergeMap)((item, i) => { return _visitJsonRecursive(item, visitor, (0, pointer_1.joinJsonPointer)(ptr, '' + i), _getObjectSubSchema(schema, '' + i), refResolver, context, root || value).pipe((0, rxjs_1.tap)((x) => (value[i] = x))); }), (0, rxjs_1.ignoreElements)()), (0, rxjs_1.of)(value)); } else if (typeof value == 'object' && value !== null) { return (0, rxjs_1.concat)((0, rxjs_1.from)(Object.getOwnPropertyNames(value)).pipe((0, rxjs_1.mergeMap)((key) => { return _visitJsonRecursive(value[key], visitor, (0, pointer_1.joinJsonPointer)(ptr, key), _getObjectSubSchema(schema, key), refResolver, context, root || value).pipe((0, rxjs_1.tap)((x) => { const descriptor = Object.getOwnPropertyDescriptor(value, key); if (descriptor && descriptor.writable && value[key] !== x) { value[key] = x; } })); }), (0, rxjs_1.ignoreElements)()), (0, rxjs_1.of)(value)); } else { return (0, rxjs_1.of)(value); } })); } /** * Visit all the properties in a JSON object, allowing to transform them. It supports calling * properties synchronously or asynchronously (through Observables). * The original object can be mutated or replaced entirely. In case where it's replaced, the new * value is returned. When it's mutated though the original object will be changed. * * Please note it is possible to have an infinite loop here (which will result in a stack overflow) * if you return 2 objects that references each others (or the same object all the time). * * @param {JsonValue} json The Json value to visit. * @param {JsonVisitor} visitor A function that will be called on every items. * @param {JsonObject} schema A JSON schema to pass through to the visitor (where possible). * @param refResolver a function to resolve references in the schema. * @returns {Observable< | undefined>} The observable of the new root, if the root changed. */ function visitJson(json, visitor, schema, refResolver, context) { return _visitJsonRecursive(json, visitor, (0, pointer_1.buildJsonPointer)([]), schema, refResolver, context); } function visitJsonSchema(schema, visitor) { if (schema === false || schema === true) { // Nothing to visit. return; } const keywords = { additionalItems: true, items: true, contains: true, additionalProperties: true, propertyNames: true, not: true, }; const arrayKeywords = { items: true, allOf: true, anyOf: true, oneOf: true, }; const propsKeywords = { definitions: true, properties: true, patternProperties: true, additionalProperties: true, dependencies: true, items: true, }; function _traverse(schema, jsonPtr, rootSchema, parentSchema, keyIndex) { if (schema && typeof schema == 'object' && !Array.isArray(schema)) { visitor(schema, jsonPtr, parentSchema, keyIndex); for (const key of Object.keys(schema)) { const sch = schema[key]; if (key in propsKeywords) { if (sch && typeof sch == 'object') { for (const prop of Object.keys(sch)) { _traverse(sch[prop], (0, pointer_1.joinJsonPointer)(jsonPtr, key, prop), rootSchema, schema, prop); } } } else if (key in keywords) { _traverse(sch, (0, pointer_1.joinJsonPointer)(jsonPtr, key), rootSchema, schema, key); } else if (key in arrayKeywords) { if (Array.isArray(sch)) { for (let i = 0; i < sch.length; i++) { _traverse(sch[i], (0, pointer_1.joinJsonPointer)(jsonPtr, key, '' + i), rootSchema, sch, '' + i); } } } else if (Array.isArray(sch)) { for (let i = 0; i < sch.length; i++) { _traverse(sch[i], (0, pointer_1.joinJsonPointer)(jsonPtr, key, '' + i), rootSchema, sch, '' + i); } } } } } _traverse(schema, (0, pointer_1.buildJsonPointer)([]), schema); }