UNPKG

typedconverter

Version:

Convert object into classes match with TypeScript type annotation

98 lines (97 loc) 4.26 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Result = exports.pipeline = void 0; const tslib_1 = require("tslib"); const tinspector_1 = tslib_1.__importDefault(require("tinspector")); const converter_1 = require("./converter"); const invocation_1 = require("./invocation"); var Result; (function (Result) { function create(value) { return { value }; } Result.create = create; function error(value, path, message) { return { value, issues: [{ path, messages: Array.isArray(message) ? message : [message] }] }; } Result.error = error; })(Result || (Result = {})); exports.Result = Result; // --------------------------------------------------------------------- // // ------------------------------ HELPER ------------------------------- // // --------------------------------------------------------------------- // function getPath(path, name) { return path.length === 0 ? name : `${path}.${name}`; } const visitorMap = { "Primitive": primitiveVisitor, "Array": arrayVisitor, "Object": objectVisitor, }; function unableToConvert(value, type) { return `Unable to convert "${converter_1.safeToString(value)}" into ${type}`; } // --------------------------------------------------------------------- // // ------------------------------ VISITORS ----------------------------- // // --------------------------------------------------------------------- // function primitiveVisitor(value, ast, opt) { const result = ast.converter(value); if (result === undefined) return Result.error(value, opt.path, unableToConvert(value, ast.type.name)); else return Result.create(result); } function arrayVisitor(value, ast, opt) { const newValues = opt.guessArrayElement && !Array.isArray(value) ? [value] : value; if (!Array.isArray(newValues)) return Result.error(value, opt.path, unableToConvert(value, `Array<${ast.type.name}>`)); const result = []; const errors = []; for (let i = 0; i < newValues.length; i++) { const val = newValues[i]; const option = { path: getPath(opt.path, i.toString()), extension: opt.extension, decorators: opt.decorators, parent: opt.parent, guessArrayElement: opt.guessArrayElement }; const elValue = pipeline(val, ast.element, option); result.push(elValue.value); if (elValue.issues) errors.push(...elValue.issues); } return { value: result, issues: errors.length === 0 ? undefined : errors }; } function objectVisitor(value, ast, opt) { if (typeof value === "number" || typeof value === "string" || typeof value === "boolean") return Result.error(value, opt.path, unableToConvert(value, ast.type.name)); const instance = Object.create(ast.type.prototype); const meta = tinspector_1.default(ast.type); const errors = []; for (const property of meta.properties) { const node = ast.properties.get(property.name); const option = { path: getPath(opt.path, property.name), extension: opt.extension, decorators: property.decorators, parent: { value, type: ast.type, decorators: opt.decorators }, guessArrayElement: opt.guessArrayElement }; const propValue = pipeline(value[property.name], node, option); if (propValue.issues) errors.push(...propValue.issues); if (propValue.value == undefined || propValue.value === null) continue; instance[property.name] = propValue.value; } return { value: instance, issues: errors.length === 0 ? undefined : errors }; } function visitor(value, ast, opt) { if (value === undefined || value === null) return { value }; if (value.constructor === ast.type || ast.type === Object) return { value: ast.kind === "Array" && opt.guessArrayElement && !Array.isArray(value) ? [value] : value }; return visitorMap[ast.kind](value, ast, opt); } function pipeline(value, ast, opt) { const visitors = invocation_1.pipe(value, opt.path, ast, opt.decorators, opt.extension, () => visitor(value, ast, opt), opt.parent); return visitors.proceed(); } exports.pipeline = pipeline;