UNPKG

@bizone-ai/json-transform-utils

Version:

Utilities for handling JSON transformers

233 lines 10 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.FunctionsParser = exports.getFunctionObjectSignature = exports.getFunctionInlineSignature = void 0; const parseDefinitions_1 = __importDefault(require("./parseDefinitions")); const functions_1 = __importDefault(require("./functions")); const json_transform_1 = require("@bizone-ai/json-transform"); const JSONStringEndFinder = /(?:[^"\\]|\\.)*"/; 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.type === "const" ? a.const : 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() { 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; } 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)); } } 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://bizone-ai.github.io/json-transform/functions/${name}`; } matchInline(data, callback) { if (typeof data !== "string") return null; const m = json_transform_1.InlineFunctionTokenizer.tokenize(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, }; } } } matchAllFunctionsInLine(line) { const matches = []; const inputLine = line.trimEnd(); let inputLineOffset = 0; while (inputLineOffset < line.length) { let line = inputLine.substring(inputLineOffset); let indexOffset = line.indexOf("$$"); if (indexOffset === -1) { break; // no more functions in line } if (line[indexOffset - 1] === '"') { // function might be quoted, find next indexOf " (and then cut the quotes and escape apostrophes) const jsonStringEnd = JSONStringEndFinder.exec(line.slice(indexOffset)); if (jsonStringEnd?.[0]) { line = line .slice(0, indexOffset + jsonStringEnd[0].length - 1) // .replace(/\\'/g, "\\\\'"); //.replace(/(\\)?'/g, "$1\\'"); } } else { inputLineOffset += indexOffset + 2; // skip this $$ and find the next one break; } let match; let str = line.substring(indexOffset); let newInputOffset = -1; while ((match = json_transform_1.InlineFunctionTokenizer.tokenize(str))) { if (!exports.functionsParser.get(match.name)) { // not a known function name (so not a function), skip it on next iteration newInputOffset = inputLineOffset + match.keyLength; break; } match.index = inputLineOffset + indexOffset; // add index to match match.args?.forEach(arg => { arg.index += inputLineOffset + indexOffset; // arg.value = arg.value? ?? null; const delta = arg.value?.match(/(?<=\\)'/g)?.length ?? 0; arg.length -= delta; indexOffset -= delta; }); if (match.input) { match.input.index += inputLineOffset + indexOffset; // match.input.value = match.input.value?.replace(/\\'/g, "'") ?? null; const delta = match.input.value?.match(/(?<=\\)'/g)?.length ?? 0; match.input.length -= delta; indexOffset -= delta; } if (matches.length) { const last = matches[matches.length - 1]; if (last.index === match.index) { console.warn(`Detected a parsing loop, stopping at (${last.index})`); newInputOffset = inputLine.length; break; } } matches.push(match); if (newInputOffset < 0) { newInputOffset = match.input ? match.input.index + match.input.length : match.args ? match.args.reduce((a, c) => a + c.index + c.length + 1, -1) : match.index + match.keyLength; } if (!match.input || !match.input.value?.startsWith("$$")) { break; } indexOffset = match.input.index - inputLineOffset; str = line.substring(indexOffset); } if (newInputOffset < 0) { break; // did not match in this iteration } inputLineOffset = newInputOffset; newInputOffset = -1; } return matches; } } exports.FunctionsParser = FunctionsParser; 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