@backland/schema
Version:
TypeScript schema declaration and validation library with static type inference
191 lines (188 loc) • 5.2 kB
JavaScript
;
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