UNPKG

typeparse

Version:

Runtime object transformation, parsing and validation with inferred static TypeScript typing.

324 lines (323 loc) 10.8 kB
"use strict"; /*--------------------------------------------------------------------------------------------- * Copyright (c) Kenneth Herrera. All rights reserved. * Licensed under the MIT License. See LICENSE in the project root for license information. *--------------------------------------------------------------------------------------------*/ Object.defineProperty(exports, "__esModule", { value: true }); exports.Types = exports.TypeParse = void 0; const Error_1 = require("./Error"); const Utils_1 = require("./Utils"); class TypeParse { constructor(parseConfig) { this.config = parseConfig; } parse(input, config) { try { const parsed = this._parse(input, this.config); if (config === null || config === void 0 ? void 0 : config.safeParse) return { success: true, data: parsed, }; return parsed; } catch (error) { if (config === null || config === void 0 ? void 0 : config.safeParse) { return { success: false, error: error.toString(), }; } throw error; } } _parse(input, config, relativePath) { switch (config.as) { case "object": return this.parseObject(input, config, relativePath); case "array": return this.parseArray(input, config, relativePath); case "string": return this.parseString(input, config, relativePath); case "number": return this.parseNumber(input, config, relativePath); case "boolean": return this.parseBoolean(input, config, relativePath); case "union": return this.parseUnion(input, config, relativePath); case "custom": return this.parseCustom(input, config, relativePath); default: return this.parseAny(input, config, relativePath); } } parseString(input, config, relativePath) { var _a; if (config.from) input = (0, Utils_1.get)(input, config.from); else input = (0, Utils_1.get)(input, relativePath); if (typeof input === "string") return input; if (typeof input === "number" || typeof input === "boolean") return `${input}`; if (config.defaultValue !== undefined) { return config.defaultValue; } else if (config.isOptional) { return undefined; } else { throw new Error_1.TypeParseError({ expectedType: "string", typeFound: input, key: (_a = config.from) !== null && _a !== void 0 ? _a : relativePath, }); } } parseNumber(input, config, relativePath) { var _a; if (config.from) input = (0, Utils_1.get)(input, config.from); else input = (0, Utils_1.get)(input, relativePath); if (typeof input === "number") return input; if (typeof input === "string") { const result = Number.parseFloat(input); if (!isNaN(result)) { return result; } } if (config.defaultValue !== undefined) { return config.defaultValue; } else if (config.isOptional) { return undefined; } else { throw new Error_1.TypeParseError({ expectedType: "number", typeFound: input, key: (_a = config.from) !== null && _a !== void 0 ? _a : relativePath, }); } } parseBoolean(input, config, relativePath) { var _a; if (config.from) input = (0, Utils_1.get)(input, config.from); else input = (0, Utils_1.get)(input, relativePath); if (typeof input === "boolean") return input; if (!config.strict && typeof input !== "undefined") return !!input; if (config.defaultValue !== undefined) { return config.defaultValue; } else if (config.isOptional) { return undefined; } else { throw new Error_1.TypeParseError({ expectedType: "boolean", typeFound: input, key: (_a = config.from) !== null && _a !== void 0 ? _a : relativePath, }); } } parseAny(input, config, relativePath) { var _a; if (typeof input !== "object") return input; if (config.from) input = (0, Utils_1.get)(input, config.from); else input = (0, Utils_1.get)(input, relativePath); return (_a = input !== null && input !== void 0 ? input : config.defaultValue) !== null && _a !== void 0 ? _a : input; } parseCustom(input, config, relativePath) { if (config.from) input = (0, Utils_1.get)(input, config.from); else input = (0, Utils_1.get)(input, relativePath); try { return config.parseFunction(input); } catch (error) { if (config.isOptional) { return undefined; } else { throw new Error_1.TypeParseError({ expectedType: "unknown", customError: error, }); } } } parseArray(input, config, relativePath) { var _a; if (config.from) input = (0, Utils_1.get)(input, config.from); else input = (0, Utils_1.get)(input, relativePath); if (!Array.isArray(input)) { if (config.isOptional) return undefined; throw new Error_1.TypeParseError({ expectedType: "array", typeFound: input, key: (_a = config.from) !== null && _a !== void 0 ? _a : relativePath, }); } const results = []; input.forEach((element) => { const parsed = this._parse(element, config.type); if (parsed !== undefined) results.push(parsed); }); return results; } parseObject(input, config, relativePath) { if (config.from) relativePath = config.from; if (typeof input !== "object") { if (config.isOptional) return undefined; throw new Error_1.TypeParseError({ expectedType: "object", typeFound: input, key: relativePath, }); } const result = {}; try { Object.entries(config.properties).forEach(([key, value]) => { result[key] = this._parse(input, value, relativePath ? `${relativePath}.${key}` : key); }); } catch (error) { if (config.isOptional) return undefined; throw error; } return result; } parseUnion(input, config, relativePath) { for (const value of config.types) { try { return this._parse(input, value, relativePath); } catch (_a) { continue; } } if (config.isOptional) { return undefined; } else { throw new Error("Cannot parse to match any type of union"); } } } exports.TypeParse = TypeParse; const optional = (option) => { return Object.assign(Object.assign({}, option), { isOptional: true, optional: undefined }); }; exports.Types = { String: (config) => { return { $static: undefined, as: "string", defaultValue: config === null || config === void 0 ? void 0 : config.defaultValue, isOptional: false, optional: function () { return optional(this); }, from: config === null || config === void 0 ? void 0 : config.path, }; }, Number: (config) => { return { $static: undefined, as: "number", defaultValue: config === null || config === void 0 ? void 0 : config.defaultValue, isOptional: false, optional: function () { return optional(this); }, from: config === null || config === void 0 ? void 0 : config.path, }; }, Boolean: (config) => { return { $static: undefined, as: "boolean", defaultValue: config === null || config === void 0 ? void 0 : config.defaultValue, strict: (config === null || config === void 0 ? void 0 : config.strict) !== undefined ? config.strict : true, isOptional: false, optional: function () { return optional(this); }, from: config === null || config === void 0 ? void 0 : config.path, }; }, Any: (config) => { return { $static: undefined, as: "any", isOptional: false, from: config === null || config === void 0 ? void 0 : config.path, defaultValue: config === null || config === void 0 ? void 0 : config.defaultValue, }; }, Array: (type, config) => { return { $static: undefined, as: "array", isOptional: false, optional: function () { return optional(this); }, from: config === null || config === void 0 ? void 0 : config.path, type, }; }, Object: (properties, config) => { return { $static: undefined, as: "object", isOptional: false, optional: function () { return optional(this); }, properties, from: config === null || config === void 0 ? void 0 : config.path, }; }, Union: (types) => { return { $static: undefined, as: "union", isOptional: false, optional: function () { return optional(this); }, types, }; }, Custom: (func, config) => { return { $static: undefined, as: "custom", isOptional: false, optional: function () { return optional(this); }, parseFunction: func, from: config === null || config === void 0 ? void 0 : config.path, }; }, };