@nlighten/json-transform-core
Version:
Core types and utilities for handling JSON transformers
207 lines • 8.7 kB
JavaScript
;
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