Skip to content

Commit 5c7f731

Browse files
committed
js-core-1.3.4 - fix not parsing paths of additional context
1 parent 4fc5e29 commit 5c7f731

23 files changed

Lines changed: 1937 additions & 1850 deletions

docs/package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
"@mdx-js/react": "3.1.0",
2121
"@monaco-editor/react": "4.6.0",
2222
"@nlighten/json-transform": "^1.3.3",
23-
"@nlighten/json-transform-core": "^1.3.2",
23+
"@nlighten/json-transform-core": "^1.3.4",
2424
"buffer": "^6.0.3",
2525
"clsx": "2.1.0",
2626
"crypto-browserify": "^3.12.1",

docs/src/components/monaco/Monaco.init.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { loader, type Monaco } from "@monaco-editor/react";
22
import * as monaco from 'monaco-editor';
33
import type { IRange, languages } from "monaco-editor";
4-
import { functions, getFunctionInlineSignature, getFunctionObjectSignature } from "@nlighten/json-transform-core";
4+
import { functionsParser, getFunctionInlineSignature, getFunctionObjectSignature } from "@nlighten/json-transform-core";
55
import {formatSchemaType} from "@nlighten/json-schema-utils";
66
import jsonVariablesTokensProvider from "./jsonVariablesTokensProvider";
77
import registerHoverProvider from "./jsonHoverProvider";
@@ -50,7 +50,7 @@ const initMonaco = (monaco: Monaco) => {
5050
let kind = monaco.languages.CompletionItemKind.Field;
5151
let tags: any = undefined;
5252
if (inline && v[0] === "$" && v[1] === "$") {
53-
const inlineFunction = functions.get(v.substring(2));
53+
const inlineFunction = functionsParser.get(v.substring(2));
5454
if (inlineFunction) {
5555
if (inlineFunction.deprecated) {
5656
tags = [monaco.languages.CompletionItemTag.Deprecated];
@@ -68,7 +68,7 @@ const initMonaco = (monaco: Monaco) => {
6868
documentation = inlineFunction.description;
6969
}
7070
} else if (!inline && v[0] === "$" && v[1] === "$") {
71-
const objectFunction = functions.get(v.substring(2));
71+
const objectFunction = functionsParser.get(v.substring(2));
7272
if (objectFunction) {
7373
let counter = 1;
7474
label = v + " (object)";
@@ -93,8 +93,8 @@ const initMonaco = (monaco: Monaco) => {
9393
tags,
9494
};
9595
};
96-
const functionSuggestions = functions.getNames()
97-
.filter(x => !functions.get(x).deprecated)
96+
const functionSuggestions = functionsParser.getNames()
97+
.filter(x => !functionsParser.get(x).deprecated)
9898
.map(x => `$$${x}`);
9999

100100
monaco.languages.registerCompletionItemProvider("json", {
@@ -124,7 +124,7 @@ const initMonaco = (monaco: Monaco) => {
124124
});
125125

126126
monaco.editor.registerCommand("docs", function (accessor: any, arg: any) {
127-
window.open(functions.resolveDocsUrl(arg.func, arg.type), "_blank");
127+
window.open(functionsParser.resolveDocsUrl(arg.func, arg.type), "_blank");
128128
});
129129

130130
registerHoverProvider(monaco, { resolveSuggestions });

docs/src/components/monaco/jsonHoverProvider.ts

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { Monaco } from "@monaco-editor/react";
22
import { formatSchemaType, type TypeSchema } from "@nlighten/json-schema-utils";
3-
import { functions, getFunctionInlineSignature, parseArgs, transformUtils } from "@nlighten/json-transform-core";
3+
import { functionsParser, getFunctionInlineSignature, parseArgs, transformUtils } from "@nlighten/json-transform-core";
44

55
const registerHoverProvider = (
66
monaco: Monaco,
@@ -31,16 +31,18 @@ const registerHoverProvider = (
3131
endColumn: word.endColumn + 1,
3232
});
3333
const funcName = word.word.match(/^\$\$([^:(]+)/)?.[1];
34-
if (!funcName || !functions.get(funcName)) return;
34+
if (!funcName || !functionsParser.get(funcName)) return;
3535
const funcType = charBefore === '"' && charAfter === '"' ? "object" : "inline";
36-
let func = functions.get(funcName);
36+
let func = functionsParser.get(funcName);
3737
if (!func) return;
38-
if (func.argBased) {
39-
const argBasedType =
40-
funcType === "inline"
41-
? func.argBased(parseArgs(func, word.word.match(/\(([^)]*)/)?.[1] ?? ""))
42-
: func.argBased({}); // TODO: is there a way to get the definition?
43-
if (argBasedType) func = argBasedType;
38+
if (func.overrides && funcType === "inline") { // TODO: is there a way to get the definition for object?
39+
const args = parseArgs(func, word.word.match(/\(([^)]*)/)?.[1] ?? "");
40+
for (const override of func.overrides) {
41+
if (override.if.every(c => args[c.argument]?.toString().toUpperCase() === c.equals)) {
42+
func = { ...func, ...override.then }; // replace func instance based on args
43+
break;
44+
}
45+
}
4446
}
4547
const sig = getFunctionInlineSignature(funcName, func);
4648
return resolve({

docs/src/components/monaco/jsonTransformerTokenizer.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { functions, JsonPathFunctionRegex, transformUtils } from "@nlighten/json-transform-core";
1+
import { functionsParser, JsonPathFunctionRegex, transformUtils } from "@nlighten/json-transform-core";
22

33
const FunctionContextRegExp = /##([a-z]+[a-z_\d]*)(((\.(?![-\w$]+\()[-\w$]+)|(\[[^\]\n]+]))+|(?=[^\w.]|$))/g;
44
const InlineFunctionArgsPunctuationRegExp = /^\(|,\s*|\)$/g;
@@ -35,14 +35,14 @@ export type TokenizationState = {
3535

3636
export const tokenizeLine = (line: string, lineNumber: number, ts: TokenizationState) => {
3737
// OBJECT FUNCTIONS
38-
let iter: IterableIterator<RegExpMatchArray> = functions.matchAllObjectFunctionsInLine(line);
38+
let iter: IterableIterator<RegExpMatchArray> = functionsParser.matchAllObjectFunctionsInLine(line);
3939
for (
4040
let iterResult = iter.next(), match: RegExpMatchArray | null = iterResult.value;
4141
!iterResult.done;
4242
iterResult = iter.next(), match = iterResult.value as RegExpMatchArray | null
4343
) {
4444
if (!match || typeof match.index === "undefined") continue;
45-
const func = functions.get(match[1])
45+
const func = functionsParser.get(match[1])
4646
const deprecated = func?.deprecated;
4747

4848
ts.tokens.push({
@@ -54,14 +54,14 @@ export const tokenizeLine = (line: string, lineNumber: number, ts: TokenizationS
5454
});
5555
}
5656
// INLINE FUNCTIONS (name and args symbols)
57-
iter = functions.matchAllInlineFunctionsInLine(line);
57+
iter = functionsParser.matchAllInlineFunctionsInLine(line);
5858
for (
5959
let iterResult = iter.next(), match: RegExpMatchArray | null = iterResult.value;
6060
!iterResult.done;
6161
iterResult = iter.next(), match = iterResult.value as RegExpMatchArray | null
6262
) {
6363
if (!match || typeof match.index === "undefined") continue;
64-
const func = functions.get(match[1]);
64+
const func = functionsParser.get(match[1]);
6565
const deprecated = func?.deprecated;
6666

6767
ts.tokens.push({

docs/src/components/transformerToMarkmap.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {IPureNode} from "markmap-common";
2-
import { functions } from "@nlighten/json-transform-core";
2+
import { functionsParser } from "@nlighten/json-transform-core";
33

44
const valueStringify = (value: any) => {
55
return `<b>${JSON.stringify(value)}</b>`;
@@ -33,7 +33,7 @@ export default function transformerToMarkmap(value: any, key: string): IPureNode
3333
if (typeof value === "string") {
3434
if (value.startsWith("$$")) {
3535
let foundFunc: string, foundInlineFunctionValue: string, foundArgs: Record<string, any>;
36-
functions.matchInline(value, (funcName, func, inlineFunctionValue, args) => {
36+
functionsParser.matchInline(value, (funcName, func, inlineFunctionValue, args) => {
3737
foundFunc = funcName;
3838
foundInlineFunctionValue = inlineFunctionValue;
3939
foundArgs = args;
@@ -59,7 +59,7 @@ export default function transformerToMarkmap(value: any, key: string): IPureNode
5959
return transformerToMarkmap(item, `[${index}]`);
6060
});
6161
} else if (typeof value === "object" && value !== null) {
62-
const func = functions.matchObject(value);
62+
const func = functionsParser.matchObject(value);
6363
if (func) {
6464
for (const key in value) {
6565
if (key === "$$" + func.name) continue;

javascript/json-transform-core/package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

javascript/json-transform-core/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@nlighten/json-transform-core",
33
"description": "Core types and utilities for handling JSON transformers",
4-
"version": "1.3.2",
4+
"version": "1.3.4",
55
"main": "dist/json-transform-core.js",
66
"umd:main": "dist/json-transform-core.umd.js",
77
"module": "dist/json-transform-core.module.js",

javascript/json-transform-core/src/ParseContext.ts

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,49 @@
1-
import { TypeSchema } from "@nlighten/json-schema-utils";
1+
import { isValidPropertyPath, TypeSchema } from "@nlighten/json-schema-utils";
22
import { ContextVariablesSchemas } from "./functions/context";
33
import { FunctionDescriptor } from "./functions/types";
44

55
export class ParseContext {
66
paths?: Record<string, TypeSchema> = {};
77
additionalContext?: Record<string, TypeSchema>;
8+
knownVariables: Set<string>;
89

9-
constructor(paths?: Record<string, TypeSchema>, additionalContext?: Record<string, TypeSchema>) {
10+
constructor(
11+
paths?: Record<string, TypeSchema>,
12+
additionalContext?: Record<string, TypeSchema>,
13+
previousPaths?: string[],
14+
) {
1015
this.paths = paths;
1116
this.additionalContext = additionalContext ?? ContextVariablesSchemas;
17+
this.knownVariables = new Set();
18+
if (paths) {
19+
for (const path in paths) {
20+
const v = path.split(/[.[]/, 1)[0];
21+
this.knownVariables.add(v);
22+
}
23+
}
24+
if (additionalContext) {
25+
for (const path in additionalContext) {
26+
const v = path.split(/[.[]/, 1)[0];
27+
this.knownVariables.add(v);
28+
}
29+
}
30+
if (previousPaths) {
31+
for (const path of previousPaths) {
32+
const v = path.split(/[.[]/, 1)[0];
33+
this.knownVariables.add(v);
34+
}
35+
}
1236
}
1337

1438
resolve(key: string) {
1539
return this.additionalContext?.[key] ?? this.paths?.[key];
1640
}
41+
42+
isJsonPathReference(path: any): boolean {
43+
if (typeof path !== "string") return false;
44+
const v = path.split(/[.[]/, 1)[0];
45+
return path === v || path.startsWith(v + ".") || path.startsWith(v + "[");
46+
}
1747
}
1848

1949
export type ParseMethod = (

javascript/json-transform-core/src/__tests__/functions.test.ts renamed to javascript/json-transform-core/src/__tests__/functionsParser.test.ts

Lines changed: 57 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,8 @@
1-
import assert from "node:assert";
21
import { describe, expect, test } from "vitest";
32
import { cleanParsedSchemaProperty, type TypeSchema } from "@nlighten/json-schema-utils";
43
import { EmbeddedTransformerFunction, EmbeddedTransformerFunctions } from "../functions/types";
54
import { parseTransformer } from "../parse";
6-
import { functions } from "../functions/functions";
7-
import {
8-
CsvParseFunctionArgBasedSchemas,
9-
DateFunctionArgBasedSchemas,
10-
DigestFunctionArgBasedSchemas,
11-
} from "../functions/embeddedFunctions";
5+
import { functionsParser } from "../functions/functionsParser";
126

137
const transformerResult = (
148
transformer: Record<string, string | Record<string, any>>,
@@ -44,7 +38,7 @@ const NULL: TypeSchema = { type: "null" },
4438

4539
describe("functions schema detection", () => {
4640
for (const funcName of EmbeddedTransformerFunctions) {
47-
const func = functions.get(funcName);
41+
const func = functionsParser.get(funcName);
4842
const alias = `$$${funcName}`;
4943
const outputSchema = func.outputSchema;
5044

@@ -613,64 +607,65 @@ describe("functions schema detection", () => {
613607
);
614608
break;
615609
}
616-
// static arg based
617-
case EmbeddedTransformerFunction.csvparse:
618-
case EmbeddedTransformerFunction.digest:
619-
case EmbeddedTransformerFunction.date: {
620-
const paramName = func.arguments?.find(p => p.position === 0)?.name ?? "";
621-
const expected: Record<string, TypeSchema> = {};
622-
const outputProperties: Record<string, TypeSchema> = {};
623-
const schemas =
624-
funcName === EmbeddedTransformerFunction.date
625-
? DateFunctionArgBasedSchemas
626-
: funcName === EmbeddedTransformerFunction.digest
627-
? DigestFunctionArgBasedSchemas
628-
: funcName === EmbeddedTransformerFunction.csvparse
629-
? CsvParseFunctionArgBasedSchemas
630-
: {};
631-
const transformer = Object.entries(schemas).reduce((a, kv) => {
632-
a["inline_" + kv[0]] = `${alias}(${kv[0]}):irrelevant`;
633-
a["object_" + kv[0]] = {
634-
[alias]: "irrelevant",
635-
[paramName]: kv[0],
636-
};
637-
if (kv[1].outputSchema) {
638-
expected["$.inline_" + kv[0]] = kv[1].outputSchema;
639-
outputProperties["inline_" + kv[0]] = kv[1].outputSchema;
640-
expected["$.object_" + kv[0]] = kv[1].outputSchema;
641-
outputProperties["object_" + kv[0]] = kv[1].outputSchema;
642-
if (kv[1].outputSchema.type === "array" && kv[1].outputSchema.items) {
643-
const firstLevelItems = kv[1].outputSchema.items as TypeSchema;
644-
expected["$.inline_" + kv[0] + "[]"] = firstLevelItems;
645-
expected["$.object_" + kv[0] + "[]"] = firstLevelItems;
646-
if (firstLevelItems.type === "array" && firstLevelItems.items) {
647-
expected["$.inline_" + kv[0] + "[][]"] = firstLevelItems.items as TypeSchema;
648-
expected["$.object_" + kv[0] + "[][]"] = firstLevelItems.items as TypeSchema;
610+
// static output schema
611+
default: {
612+
if (func.overrides) {
613+
// static conditional
614+
const paramName = func.arguments?.find(p => p.position === 0)?.name ?? "";
615+
const expected: Record<string, TypeSchema> = {};
616+
const outputProperties: Record<string, TypeSchema> = {};
617+
const transformer = func.overrides.reduce((a, kv) => {
618+
const argValue = kv.if[0].equals; // TODO: this is not generic
619+
a["inline_" + argValue] = `${alias}(${argValue}):irrelevant`;
620+
a["object_" + argValue] = {
621+
[alias]: "irrelevant",
622+
[paramName]: argValue,
623+
};
624+
const argOutputSchema = kv.then.outputSchema;
625+
if (argOutputSchema) {
626+
expected["$.inline_" + argValue] = argOutputSchema;
627+
outputProperties["inline_" + argValue] = argOutputSchema;
628+
expected["$.object_" + argValue] = argOutputSchema;
629+
outputProperties["object_" + argValue] = argOutputSchema;
630+
if (
631+
argOutputSchema.type === "array" &&
632+
argOutputSchema.items &&
633+
!Array.isArray(argOutputSchema.items)
634+
) {
635+
const firstLevelItems = argOutputSchema.items;
636+
expected["$.inline_" + argValue + "[]"] = firstLevelItems;
637+
expected["$.object_" + argValue + "[]"] = firstLevelItems;
638+
if (
639+
firstLevelItems.type === "array" &&
640+
firstLevelItems.items &&
641+
!Array.isArray(firstLevelItems.items)
642+
) {
643+
expected["$.inline_" + argValue + "[][]"] = firstLevelItems.items;
644+
expected["$.object_" + argValue + "[][]"] = firstLevelItems.items;
645+
}
649646
}
650647
}
651-
}
652-
return a;
653-
}, {} as any);
654-
expect(transformerResult(transformer)).toStrictEqual(
655-
createFlowTraversalResult({
656-
paths: {
657-
$: {
658-
additionalProperties: false,
659-
properties: outputProperties,
660-
type: "object",
648+
return a;
649+
}, {} as any);
650+
expect(transformerResult(transformer)).toStrictEqual(
651+
createFlowTraversalResult({
652+
paths: {
653+
$: {
654+
additionalProperties: false,
655+
properties: outputProperties,
656+
type: "object",
657+
},
658+
...expected,
661659
},
662-
...expected,
663-
},
664-
}),
665-
);
666-
break;
667-
}
668-
// static output schema
669-
default: {
670-
assert(outputSchema);
671-
assert(!func.argBased, "missing object arg based check");
660+
}),
661+
);
662+
break;
663+
}
664+
665+
// static output schema
666+
expect(outputSchema).toBeTruthy();
672667
const expected: Record<string, TypeSchema> = {};
673-
const funcOutputPaths = functions.get(funcName).parsedOutputSchema?.paths ?? [];
668+
const funcOutputPaths = functionsParser.get(funcName).parsedOutputSchema?.paths ?? [];
674669

675670
funcOutputPaths.forEach(p => {
676671
const suffix = !p.$path ? "" : (p.$path[0] === "[" ? "" : ".") + p.$path;

0 commit comments

Comments
 (0)