UNPKG

@backland/schema

Version:

TypeScript schema declaration and validation library with static type inference

191 lines (188 loc) 5.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.createTSFYContext = createTSFYContext; exports.createTSfyRef = createTSfyRef; exports.getTSFyIdentifier = getTSFyIdentifier; exports.tsfy = tsfy; exports.tsfy_defaults = void 0; var _utils = require("@backland/utils"); var _CircularDeps = require("../CircularDeps"); var _GraphType = require("../GraphType/GraphType"); var _ObjectType = require("../ObjectType"); var _fieldTypes = require("../fields/fieldTypes"); var _parseTSFyValue = require("./parseTSFyValue"); const tsfy_defaults = { iterationLimit: 5000 }; exports.tsfy_defaults = tsfy_defaults; function tsfy(input, config) { const context = createTSFYContext(config || {}); const { groupInTypeThreshold, iterationLimit, many } = context.config; const header = new Set(); const footer = new Set(); const entries = (() => { if (many) { if (Array.isArray(input)) { return input; } else { throw new Error(`tsfy: expected input value to be an array when options.many is true.`); } } return [input]; })(); async function getParts() { const body = await (async () => { // async function runPart(part) { const ref = await (0, _parseTSFyValue.parseTSFyValue)(part, context); return resolvePart(ref, undefined, 0); } const parts = await awaitAll(entries.map(runPart)); return parts.join('\n'); })(); Object.values(context.header).forEach(el => header.add(el)); return { header, body, footer }; } async function toString(options) { const { name, prettier, wrapper = ['', ''] } = options || {}; const { footer, header, body } = await getParts(); if (name) { return [wrapper[0], ...header.values(), `export type ${name} = ${body};`, ...footer.values(), wrapper[1]].filter(Boolean).join('\n'); } const res = [wrapper[0], ...header.values(), ...footer.values(), wrapper[1]].filter(Boolean).join('\n'); if (prettier) { return _CircularDeps.CircularDeps.prettier.format(res, { parser: 'typescript' }); } return res; } function resolvePart(ref, hash, count) { if (count > iterationLimit) { throw new Error(`tsfy: Maximum number of iterations (${iterationLimit}) exceeded.`); } else { count += 1; } const contextRef = hash ? context.refs[hash] : undefined; if (contextRef) { if (contextRef.result !== undefined) return contextRef.result; } if (Array.isArray(ref)) { const res = ref.map(rr => resolvePart(rr, undefined, count)); const body = res.join(''); if (contextRef) { contextRef.result = body; } return body; } const value = (() => { if (typeof ref === 'string') return ref; if (ref.result !== undefined) return ref.result; /** * Complex ref */ const parts = ref.parts; const res = resolvePart(parts, ref.hash, count); ref.result = res; const shouldGroupInOneType = ref.count >= groupInTypeThreshold; if (shouldGroupInOneType || ref.identifier) { const hashed = `${(0, _utils.hashString)(ref.result)}`.slice(0, 6); const named = ref.identifier || `T${hashed}`; const prefix = ref.identifier ? `export type ${ref.identifier} = ` : `type ${named} = `; if (ref.identifier) { header.add(`${prefix} ${res};\n`); } else { footer.add(`${prefix} ${res};`); } return named; } return res; })(); if (hash) { context.refs[hash].result = value; } return value; } return { toString, getParts }; } function getTSFyIdentifier(value) { if (!value) return undefined; if (typeof value !== 'object') return undefined; if (value.__isEntity === true) { return `T${value.name}Entity`; } if (_GraphType.GraphType.is(value) && value.optionalId) { return `T${value.optionalId}Type`; } if (_ObjectType.ObjectType.is(value)) { return value.id ? `T${value.id}Object` : undefined; } if ((0, _fieldTypes.isFieldTypeName)(value.type) && typeof value.name === 'string') { return `T${value.name}Field`; } return undefined; } function createTSfyRef(hash, identifier) { const ref = { identifier, hash, result: undefined, count: 1, parts: [] }; return ref; } function createTSFYContext(config) { const { iterationLimit = tsfy_defaults.iterationLimit, many = false, groupInTypeThreshold = 2 } = config || {}; const context = { refs: {}, header: {}, config: { context: undefined, groupInTypeThreshold, iterationLimit, many, ...config }, ...config.context }; context.config.context = context; return context; } async function awaitAll(promises) { for (const key in promises) { promises[key] = await promises[key]; } return promises; } // export type _ResolveParts = (options: { // ref: TSFYPart; // hash: string | undefined; // count: number; // }) => Promise<string>; //# sourceMappingURL=tsfy.js.map