UNPKG

@nlighten/json-transform-core

Version:

Core types and utilities for handling JSON transformers

207 lines 8.7 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.getSubfunction = exports.functionsParser = exports.getFunctionObjectSignature = exports.getFunctionInlineSignature = void 0; const parseDefinitions_1 = __importDefault(require("./parseDefinitions")); const functions_1 = __importDefault(require("./functions")); const tokenizeInlineFunction_1 = require("./tokenizeInlineFunction"); function compareArgumentPosition(a, b) { return (a.position ?? Infinity) - (b.position ?? Infinity); } const getFunctionInlineSignature = (name, func, requiredOnly) => { return ("$$" + name + (func.arguments?.some(a => a.position === 0 && a.required) ? "(" + func.arguments .filter(a => typeof a.position === "number" && (!requiredOnly || a.required)) .sort(compareArgumentPosition) .map(a => (a.required ? "{" + a.name + "}" : "[" + a.name + "]")) .join(",") + ")" : "")); }; exports.getFunctionInlineSignature = getFunctionInlineSignature; const getFunctionObjectSignature = (name, func) => { return `{ "\\$\\$${name}": {input} ${func.arguments?.some(a => a.position === 0 && a.required) ? "," + func.arguments .filter(a => typeof a.position === "number" && a.required) .sort(compareArgumentPosition) .map(a => `"${a.name}": {${a.name}}`) .join(", ") : ""}}`; }; exports.getFunctionObjectSignature = getFunctionObjectSignature; class FunctionsParser { constructor() { /** * Match Groups: DO NOT CHANGE * 0 - Everything * 1 - Function name (no $$) * 2 - Args with parenthesis * 3 - Args without parenthesis * 4 - Colon (or something else) * 5 - What comes after the colon (value) -- only when 'noArgs' = false */ this.inlineFunctionRegexFactory = (names) => new RegExp(`\\$\\$(${names.join("|")})(\\((.*?)\\))?(:([^"]*)|$|")`, "g"); this.objectFunctionRegexFactory = (names) => new RegExp(`(?<=")\\$\\$(${names.join("|")})":`, "g"); this.clientFunctions = {}; const functionNames = new Set(Object.keys(functions_1.default)); // add aliases for (const name of functionNames) { if (functions_1.default[name].aliases) { functions_1.default[name].aliases?.forEach(alias => functionNames.add(alias)); } } this.allFunctionsNames = functionNames; const names = Array.from(this.allFunctionsNames); this.objectFunctionRegex = this.objectFunctionRegexFactory(names); this.inlineFunctionRegex = this.inlineFunctionRegexFactory(names); } setClientFunctions(clientFunctions, handler, docsUrlResolver) { this.clientFunctions = (0, parseDefinitions_1.default)(clientFunctions, true); this.clientDocsUrlResolver = docsUrlResolver; for (const name in clientFunctions) { this.allFunctionsNames.add(name); if (clientFunctions[name].aliases) { clientFunctions[name].aliases?.forEach(alias => this.allFunctionsNames.add(alias)); } } const names = Array.from(this.allFunctionsNames); this.objectFunctionRegex = this.objectFunctionRegexFactory(names); this.inlineFunctionRegex = this.inlineFunctionRegexFactory(names); this.handleClientFunction = handler; } get(name, args) { return this.clientFunctions?.[name] ?? functions_1.default[name]; } getNames() { return this.allFunctionsNames; } resolveDocsUrl(funcName, functionDescriptor) { const name = functionDescriptor?.aliasTo ?? funcName; if (functionDescriptor?.custom && this.clientDocsUrlResolver) { const url = this.clientDocsUrlResolver(name); if (url) { return url; } } return `https://nlighten-oss.github.io/json-transform/functions/${name}`; } matchInline(data, callback) { if (typeof data !== "string") return null; const m = (0, tokenizeInlineFunction_1.tokenizeInlineFunction)(data); if (!m) { return null; } let funcName = m.name; let func = exports.functionsParser.get(funcName); if (!func) return null; if (func.aliasTo) funcName = func.aliasTo; if (func.subfunctions || callback) { const args = m.args?.reduce((a, c, i) => { func.arguments?.forEach(fa => { if (fa.position === i && fa.name) { a[fa.name] = c.value; } }); return a; }, {}) ?? {}; func = (0, exports.getSubfunction)(func, args); if (callback) { const inlineFunctionValue = m.input?.value; callback(funcName, func, inlineFunctionValue, args); } } return func; } matchObject(data, extractOutputTypeRecursively) { if (!data || typeof data !== "object") return; for (const funcName of this.allFunctionsNames) { const key = "$$" + funcName; const value = data[key]; if (typeof value !== "undefined") { if (extractOutputTypeRecursively && this.get(funcName).pipedType) { const match = this.matchObject(value, true); if (match) return match; } const func = (0, exports.getSubfunction)(this.get(funcName), data); const args = { ...data }; delete args[key]; // remove the function key from args if (func.argumentsAsInputSchema && Object.keys(args).length === 0 && Array.isArray(value)) { value.forEach((argVal, position) => { const arg = func.arguments?.find(a => a.position === position); if (arg) { args[arg.name] = argVal; } }); } return { name: func.aliasTo ?? funcName, func, value, args, }; } } } matchAllObjectFunctionsInLine(line) { return line.matchAll(this.objectFunctionRegex); } matchAllInlineFunctionsInLine(line) { const matches = []; let match; let indexOffset = line.indexOf("$$"); line = line.trimEnd(); if (line[indexOffset - 1] === '"' && line.at(-1) === '"') { line = line.slice(0, -1).replace(/\\'/g, "\\\\'"); } let str = line.substring(indexOffset); while ((match = (0, tokenizeInlineFunction_1.tokenizeInlineFunction)(str))) { if (!exports.functionsParser.get(match.name)) { break; // not a known function name (so not a function) } match.index = indexOffset; // add index to match match.args?.forEach(arg => { arg.index += indexOffset; const delta = arg.value?.match(/'/g)?.length ?? 0; arg.length -= delta; indexOffset -= delta; }); if (match.input) { match.input.index += indexOffset; const delta = match.input.value?.match(/'/g)?.length ?? 0; match.input.length -= delta; indexOffset -= delta; } matches.push(match); if (!match.input || !match.input.value?.startsWith("$$")) { break; } indexOffset = match.input.index; str = line.substring(match.input.index); } return matches; } } exports.functionsParser = new FunctionsParser(); const getSubfunction = (func, args) => { if (!func.subfunctions || !args) return func; for (const subFunc of func.subfunctions) { if (subFunc.if.every(c => (args[c.argument] ?? subFunc.then.defaultValues?.[c.argument])?.toString().toUpperCase() === c.equals)) { return subFunc.then; // replace func instance based on args } } return func; }; exports.getSubfunction = getSubfunction; //# sourceMappingURL=functionsParser.js.map