|
| 1 | +/* eslint max-statements-per-line: ["error", { "max": 2 }] */ |
| 2 | +import eachSchema from "../eachSchema"; |
| 3 | +import remotes from "../../remotes"; |
| 4 | +import joinScope from "./joinScope"; |
| 5 | +import getRef from "./getRef"; |
| 6 | +const COMPILED = "__compiled"; |
| 7 | +const COMPILED_REF = "__ref"; |
| 8 | +const GET_REF = "getRef"; |
| 9 | +const GET_ROOT = "getRoot"; |
| 10 | +const suffixes = /(#|\/)+$/g; |
| 11 | +export default function compile(rootSchema, force = false) { |
| 12 | + if (rootSchema[COMPILED] !== undefined) { |
| 13 | + return rootSchema; |
| 14 | + } // eslint-disable-line |
| 15 | + const context = { ids: {}, remotes: Object.assign({}, remotes) }; |
| 16 | + const rootSchemaAsString = JSON.stringify(rootSchema); |
| 17 | + rootSchema = JSON.parse(rootSchemaAsString); |
| 18 | + Object.defineProperty(rootSchema, COMPILED, { enumerable: false, value: true }); |
| 19 | + Object.defineProperty(rootSchema, GET_REF, { enumerable: false, value: getRef.bind(null, context, rootSchema) }); |
| 20 | + // Object.defineProperty(rootSchema, "debug", { enumerable: false, value: schema => { |
| 21 | + // console.log(JSON.stringify(context.ids, null, 2)); |
| 22 | + // console.log("remotes", Object.keys(remotes)); |
| 23 | + // console.log(JSON.stringify(rootSchema, null, 2)); |
| 24 | + // } }); |
| 25 | + if (force === false && rootSchemaAsString.includes("$ref") === false) { |
| 26 | + // bail early, when no $refs are defined |
| 27 | + return rootSchema; |
| 28 | + } |
| 29 | + const scopes = {}; |
| 30 | + const getRoot = () => rootSchema; |
| 31 | + eachSchema(rootSchema, (schema, pointer) => { |
| 32 | + if (schema.id) { |
| 33 | + context.ids[schema.id.replace(suffixes, "")] = pointer; |
| 34 | + } |
| 35 | + // build up scopes and add them to $ref-resolution map |
| 36 | + pointer = `#${pointer}`.replace(/##+/, "#"); |
| 37 | + const previousPointer = pointer.replace(/\/[^/]+$/, ""); |
| 38 | + const parentPointer = pointer.replace(/\/[^/]+\/[^/]+$/, ""); |
| 39 | + const previousScope = scopes[previousPointer] || scopes[parentPointer]; |
| 40 | + const scope = joinScope(previousScope, schema.id); |
| 41 | + scopes[pointer] = scope; |
| 42 | + if (context.ids[scope] == null) { |
| 43 | + context.ids[scope] = pointer; |
| 44 | + } |
| 45 | + if (schema.$ref) { |
| 46 | + Object.defineProperty(schema, COMPILED_REF, { enumerable: false, value: joinScope(scope, schema.$ref) }); |
| 47 | + // @todo currently not used: |
| 48 | + Object.defineProperty(schema, GET_ROOT, { enumerable: false, value: getRoot }); |
| 49 | + // console.log("compiled ref", scope, schema.$ref, "=>", joinScope(scope, schema.$ref)); |
| 50 | + } |
| 51 | + }); |
| 52 | + // console.log(JSON.stringify(context.ids, null, 2)); |
| 53 | + return rootSchema; |
| 54 | +} |
0 commit comments