diff --git a/javascript/json-transform/src/JsonHelpers.ts b/javascript/json-transform/src/JsonHelpers.ts index cd05668..7eaa41e 100644 --- a/javascript/json-transform/src/JsonHelpers.ts +++ b/javascript/json-transform/src/JsonHelpers.ts @@ -10,6 +10,7 @@ const JSONPATH_ROOT = "$", JSONPATH_ALT_PREFIX_ESC = "\\#"; const isNullOrUndefined = (value: any): value is null | undefined => value == null || typeof value === "undefined"; +const isMap = (value: any): value is Record => value && typeof value === "object" && !Array.isArray(value); const getAsString = (value: any): null | string => { if (isNullOrUndefined(value)) { @@ -189,6 +190,7 @@ const isEqual = (value: any, other: any): boolean => { export { isNullOrUndefined, + isMap, createPayloadResolver, getAsString, compareTo, diff --git a/javascript/json-transform/src/__tests__/functions/TransformerFunctionFlat.test.ts b/javascript/json-transform/src/__tests__/functions/TransformerFunctionFlat.test.ts new file mode 100644 index 0000000..c3a297a --- /dev/null +++ b/javascript/json-transform/src/__tests__/functions/TransformerFunctionFlat.test.ts @@ -0,0 +1,50 @@ +import { describe, test } from "vitest"; +import { assertTransformation } from "../BaseTransformationTest"; + +describe("TransformerFunctionFlat", () => { + test("object", async () => { + const arr = ["a", "b", "c"]; + const arr2 = ["d", "e", "f"]; + const arr3 = [arr, arr2]; + const flatCombined = arr3.flatMap(x => x); + const flatArr = arr.slice(); + await assertTransformation( + arr3, + { + $$flat: ["$[0]", "$[1]"], + }, + flatCombined, + ); + await assertTransformation( + arr3, + { + $$flat: ["$[0]", "$.pointingToNowhere"], + }, + flatArr, + ); + await assertTransformation( + arr3, + { + $$flat: [ + ["a", "b", "c"], + ["d", "e", "f"], + ], + }, + flatCombined, + ); + await assertTransformation( + arr, + { + $$flat: [["a", "b", "c"], []], + }, + flatArr, + ); + await assertTransformation( + arr, + { + $$flat: [["a", "b", "c"], null], + }, + flatArr, + ); + }); +}); diff --git a/javascript/json-transform/src/__tests__/functions/TransformerFunctionFlatten.test.ts b/javascript/json-transform/src/__tests__/functions/TransformerFunctionFlatten.test.ts new file mode 100644 index 0000000..9396760 --- /dev/null +++ b/javascript/json-transform/src/__tests__/functions/TransformerFunctionFlatten.test.ts @@ -0,0 +1,36 @@ +import { describe, test } from "vitest"; +import { assertTransformation } from "../BaseTransformationTest"; + +describe("TransformerFunctionFlat", () => { + test("object", async () => { + const arr = { value: "bbb" }; + await assertTransformation( + arr, + { + $$flatten: { a: { a1: 123, a2: [1, 2, 3, { c: true }] }, b: "$.value" }, + array_prefix: "\\$", + }, + { "a.a1": 123, "a.a2.$0": 1, "a.a2.$1": 2, "a.a2.$2": 3, "a.a2.$3.c": true, b: "bbb" }, + ); + + await assertTransformation( + arr, + { + $$flatten: { a: { a1: 123, a2: [1, 2, 3, { c: true }] }, b: "$.value" }, + prefix: "xxx", + array_prefix: "", + }, + { "xxx.a.a1": 123, "xxx.a.a2.0": 1, "xxx.a.a2.1": 2, "xxx.a.a2.2": 3, "xxx.a.a2.3.c": true, "xxx.b": "bbb" }, + ); + + await assertTransformation( + arr, + { + $$flatten: { a: { a1: 123, a2: [1, 2, 3, { c: true }] }, b: "$.value" }, + prefix: "xxx", + array_prefix: "#null", + }, + { "xxx.a.a1": 123, "xxx.a.a2": [1, 2, 3, { c: true }], "xxx.b": "bbb" }, + ); + }); +}); diff --git a/javascript/json-transform/src/__tests__/functions/TransformerFunctionForm.test.ts b/javascript/json-transform/src/__tests__/functions/TransformerFunctionForm.test.ts new file mode 100644 index 0000000..821e221 --- /dev/null +++ b/javascript/json-transform/src/__tests__/functions/TransformerFunctionForm.test.ts @@ -0,0 +1,48 @@ +import { describe, test } from "vitest"; +import { assertTransformation } from "../BaseTransformationTest"; + +describe("TransformerFunctionCsv", () => { + test("inline", async () => { + await assertTransformation( + { + a: 1, + b: "B", + c: true, + }, + "$$form:$", + "a=1&b=B&c=true", + ); + + // arrays + await assertTransformation( + { + a: [1, 2], + c: true, + }, + "$$form:$", + "a=1&a=2&c=true", + ); + }); + + test("object", async () => { + await assertTransformation( + { + a: 1, + b: "B", + c: true, + }, + { $$form: "$" }, + "a=1&b=B&c=true", + ); + + // arrays + await assertTransformation( + { + a: [1, 2], + c: true, + }, + { $$form: "$" }, + "a=1&a=2&c=true", + ); + }); +}); diff --git a/javascript/json-transform/src/__tests__/functions/TransformerFunctionFormParse.test.ts b/javascript/json-transform/src/__tests__/functions/TransformerFunctionFormParse.test.ts new file mode 100644 index 0000000..ed52926 --- /dev/null +++ b/javascript/json-transform/src/__tests__/functions/TransformerFunctionFormParse.test.ts @@ -0,0 +1,46 @@ +import { describe, test } from "vitest"; +import { assertTransformation } from "../BaseTransformationTest"; + +describe("TransformerFunctionCsv", () => { + test("inline", async () => { + await assertTransformation("a=1&b=B&c", "$$formparse:$", { + a: "1", + a$$: ["1"], + b: "B", + b$$: ["B"], + c: "true", + c$$: ["true"], + }); + + // arrays + await assertTransformation("a=1&a=2", "$$formparse:$", { + a: "1", + a$$: ["1", "2"], + }); + }); + + test("object", async () => { + await assertTransformation( + "a=1&b=B&c", + { $$formparse: "$" }, + { + a: "1", + a$$: ["1"], + b: "B", + b$$: ["B"], + c: "true", + c$$: ["true"], + }, + ); + + // arrays + await assertTransformation( + "a=1&a=2", + { $$formparse: "$" }, + { + a: "1", + a$$: ["1", "2"], + }, + ); + }); +}); diff --git a/javascript/json-transform/src/__tests__/functions/TransformerFunctionIsNull.test.ts b/javascript/json-transform/src/__tests__/functions/TransformerFunctionIsNull.test.ts new file mode 100644 index 0000000..fe5f067 --- /dev/null +++ b/javascript/json-transform/src/__tests__/functions/TransformerFunctionIsNull.test.ts @@ -0,0 +1,12 @@ +import { describe, test } from "vitest"; +import { assertTransformation } from "../BaseTransformationTest"; + +describe("TransformerFunctionIsNull", () => { + test("nullTest", async () => { + await assertTransformation(null, "$$isnull:$", true); + await assertTransformation(undefined, "$$isnull:$", true); + await assertTransformation(0, "$$isnull():$", false); + await assertTransformation("", "$$isnull:$", false); + await assertTransformation(false, "$$isnull:$", false); + }); +}); diff --git a/javascript/json-transform/src/formats/FormatDeserializer.ts b/javascript/json-transform/src/formats/FormatDeserializer.ts index 390fd31..f165d18 100644 --- a/javascript/json-transform/src/formats/FormatDeserializer.ts +++ b/javascript/json-transform/src/formats/FormatDeserializer.ts @@ -1,3 +1,3 @@ export interface FormatDeserializer { - deserialize(input: string): Record; -} \ No newline at end of file + deserialize(input: string | null): any; +} diff --git a/javascript/json-transform/src/formats/FormatSerializer.ts b/javascript/json-transform/src/formats/FormatSerializer.ts index a0b9a21..8ac0e74 100644 --- a/javascript/json-transform/src/formats/FormatSerializer.ts +++ b/javascript/json-transform/src/formats/FormatSerializer.ts @@ -1,3 +1,3 @@ export interface FormatSerializer { - serialize(payload: any): string; -} \ No newline at end of file + serialize(payload: any): string | null; +} diff --git a/javascript/json-transform/src/formats/csv/CsvFormat.ts b/javascript/json-transform/src/formats/csv/CsvFormat.ts index 2258570..4d03f02 100644 --- a/javascript/json-transform/src/formats/csv/CsvFormat.ts +++ b/javascript/json-transform/src/formats/csv/CsvFormat.ts @@ -1,6 +1,6 @@ -import {getAsString, isNullOrUndefined} from "../../JsonHelpers"; -import {FormatSerializer} from "../FormatSerializer"; -import {FormatDeserializer} from "../FormatDeserializer"; +import { getAsString, isMap, isNullOrUndefined } from "../../JsonHelpers"; +import { FormatSerializer } from "../FormatSerializer"; +import { FormatDeserializer } from "../FormatDeserializer"; const MIN_SUPPLEMENTARY_CODE_POINT = 0x010000; function charCount(codePoint: number) { @@ -10,11 +10,11 @@ function charCount(codePoint: number) { class CsvFormat implements FormatSerializer, FormatDeserializer { private static readonly COMMA = ","; private static readonly DEFAULT_SEPARATOR = CsvFormat.COMMA; - private static readonly DOUBLE_QUOTES = "\""; - private static readonly EMBEDDED_DOUBLE_QUOTES = "\"\""; + private static readonly DOUBLE_QUOTES = '"'; + private static readonly EMBEDDED_DOUBLE_QUOTES = '""'; private static readonly NEW_LINE_UNIX = "\n"; - private static readonly LINE_FEED = '\n'.codePointAt(0); - private static readonly CARRIAGE_RETURN = '\r'.codePointAt(0); + private static readonly LINE_FEED = "\n".codePointAt(0); + private static readonly CARRIAGE_RETURN = "\r".codePointAt(0); private static readonly NEW_LINE_WINDOWS = "\r\n"; private readonly names?: string[]; @@ -22,7 +22,12 @@ class CsvFormat implements FormatSerializer, FormatDeserializer { private readonly forceQuote: boolean; private readonly separator: string; - constructor(names?: string[] | null, noHeaders?: boolean | null, forceQuote?: boolean | null, separator?: string | null) { + constructor( + names?: string[] | null, + noHeaders?: boolean | null, + forceQuote?: boolean | null, + separator?: string | null, + ) { this.names = names ?? undefined; this.noHeaders = isNullOrUndefined(noHeaders) ? false : noHeaders; this.forceQuote = isNullOrUndefined(forceQuote) ? false : forceQuote; @@ -36,15 +41,17 @@ class CsvFormat implements FormatSerializer, FormatDeserializer { } else { value = getAsString(val) ?? ""; } - if (this.forceQuote || + if ( + this.forceQuote || value.includes(CsvFormat.COMMA) || value.includes(CsvFormat.DOUBLE_QUOTES) || value.includes(CsvFormat.NEW_LINE_UNIX) || value.includes(CsvFormat.NEW_LINE_WINDOWS) || value.startsWith(" ") || - value.endsWith(" ")) { + value.endsWith(" ") + ) { sb.append(CsvFormat.DOUBLE_QUOTES); - sb.append(value.replace(new RegExp(CsvFormat.DOUBLE_QUOTES, 'g'), CsvFormat.EMBEDDED_DOUBLE_QUOTES)); + sb.append(value.replace(new RegExp(CsvFormat.DOUBLE_QUOTES, "g"), CsvFormat.EMBEDDED_DOUBLE_QUOTES)); sb.append(CsvFormat.DOUBLE_QUOTES); } else { sb.append(value); @@ -67,7 +74,7 @@ class CsvFormat implements FormatSerializer, FormatDeserializer { private appendRow(sb: StringBuilder, names: string[] | null | undefined, value: any): void { if (!Array.isArray(value) && names) { - if (typeof value !== 'object' || value === null) return; + if (typeof value !== "object" || value === null) return; let first = true; for (const name of names) { if (!first) { @@ -91,7 +98,7 @@ class CsvFormat implements FormatSerializer, FormatDeserializer { sb.append("\n"); } - serialize(payload: any): string { + serialize(payload: any): string | null { const sb = new StringBuilder(); let headers = this.names; if (headers) { @@ -99,7 +106,7 @@ class CsvFormat implements FormatSerializer, FormatDeserializer { } if (Array.isArray(payload)) { - if (!headers && payload.length > 0 && typeof payload[0] === 'object' && !Array.isArray(payload[0])) { + if (!headers && payload.length > 0 && isMap(payload[0])) { headers = Object.keys(payload[0]); this.appendHeaders(sb, headers); } @@ -124,11 +131,14 @@ class CsvFormat implements FormatSerializer, FormatDeserializer { return; } if (!isNullOrUndefined(context.names)) { - const item : Record = {}; + const item: Record = {}; let i = 0; for (i = 0; i < context.names.length; i++) { const name = getAsString(context.names[i]) ?? ""; - if ((context.extractNames === null || Object.prototype.hasOwnProperty.call(context.extractNames, name)) && values.length > i) { + if ( + (context.extractNames === null || Object.prototype.hasOwnProperty.call(context.extractNames, name)) && + values.length > i + ) { item[name] = values[i]; } } @@ -141,8 +151,11 @@ class CsvFormat implements FormatSerializer, FormatDeserializer { } } - deserialize(input: string): any { - const result : any[] = []; + deserialize(input: string | null): any { + if (input === null) { + return null; + } + const result: any[] = []; const context = new CsvParserContext(); if (this.noHeaders && !isNullOrUndefined(this.names)) { const names: string[] = []; @@ -159,7 +172,7 @@ class CsvFormat implements FormatSerializer, FormatDeserializer { while (offset < len) { const cur = input.codePointAt(offset) as number; const curSize = charCount(cur); - const next = offset + curSize < len ? input.codePointAt(offset + curSize) as number : -1; + const next = offset + curSize < len ? (input.codePointAt(offset + curSize) as number) : -1; const curAndNextSize = curSize + charCount(next); if (cur === this.separator.codePointAt(0)) { @@ -230,7 +243,7 @@ class StringBuilder { } public toString(): string { - return this.strings.join(''); + return this.strings.join(""); } public clear(): void { @@ -242,4 +255,4 @@ class StringBuilder { } } -export default CsvFormat; \ No newline at end of file +export default CsvFormat; diff --git a/javascript/json-transform/src/formats/formurlencoded/FormUrlEncodedFormat.ts b/javascript/json-transform/src/formats/formurlencoded/FormUrlEncodedFormat.ts new file mode 100644 index 0000000..0f992fe --- /dev/null +++ b/javascript/json-transform/src/formats/formurlencoded/FormUrlEncodedFormat.ts @@ -0,0 +1,41 @@ +import { FormatSerializer } from "../FormatSerializer"; +import { FormatDeserializer } from "../FormatDeserializer"; +import { isNullOrUndefined } from "../../JsonHelpers"; + +class FormUrlEncodedFormat implements FormatSerializer, FormatDeserializer { + serialize(payload: any): string | null { + if (isNullOrUndefined(payload)) { + return null; + } + const params = new URLSearchParams(); + for (const key in payload) { + if (Object.prototype.hasOwnProperty.call(payload, key)) { + const value = payload[key]; + if (Array.isArray(value)) { + for (const item of value) { + params.append(key, item); + } + } else { + params.append(key, value); + } + } + } + return params.toString(); + } + + deserialize(input: string): any { + if (isNullOrUndefined(input)) { + throw new Error("Input is null"); + } + const params = new URLSearchParams(input); + const result: Record = {}; + for (const key of params.keys()) { + const value = params.getAll(key); + result[key] = value[0] || "true"; + result[key + "$$"] = value.map(v => v || "true"); + } + return result; + } +} + +export default FormUrlEncodedFormat; diff --git a/javascript/json-transform/src/functions/TransformerFunctionFlat.ts b/javascript/json-transform/src/functions/TransformerFunctionFlat.ts new file mode 100644 index 0000000..cb9d035 --- /dev/null +++ b/javascript/json-transform/src/functions/TransformerFunctionFlat.ts @@ -0,0 +1,41 @@ +import { asAsyncSequence, asyncSequenceOf, emptyAsyncSequence } from "@wortise/sequency"; +import TransformerFunction from "./common/TransformerFunction"; +import { ArgType } from "./common/ArgType"; +import { FunctionDescription } from "./common/FunctionDescription"; +import FunctionContext from "./common/FunctionContext"; +import { isNullOrUndefined } from "../JsonHelpers"; +import JsonElementStreamer from "../JsonElementStreamer"; + +const DESCRIPTION: FunctionDescription = { + aliases: ["flat"], + inputType: ArgType.Array, + description: "", + outputType: ArgType.Array, +}; +class TransformerFunctionFlat extends TransformerFunction { + constructor() { + super(DESCRIPTION); + } + + override async apply(context: FunctionContext): Promise { + const streamer = await context.getJsonElementStreamer(null); + if (streamer == null) return null; + + return JsonElementStreamer.fromTransformedStream( + context, + streamer + .stream() + .flatMap(itm => { + if (isNullOrUndefined(itm)) { + return emptyAsyncSequence(); + } else if (Array.isArray(itm)) { + return asAsyncSequence(itm); + } + return asyncSequenceOf(itm); + }) + .filter(el => !isNullOrUndefined(el)), + ); + } +} + +export default TransformerFunctionFlat; diff --git a/javascript/json-transform/src/functions/TransformerFunctionFlatten.ts b/javascript/json-transform/src/functions/TransformerFunctionFlatten.ts new file mode 100644 index 0000000..a4bd780 --- /dev/null +++ b/javascript/json-transform/src/functions/TransformerFunctionFlatten.ts @@ -0,0 +1,82 @@ +import TransformerFunction from "./common/TransformerFunction"; +import { ArgType } from "./common/ArgType"; +import { FunctionDescription } from "./common/FunctionDescription"; +import FunctionContext from "./common/FunctionContext"; +import { isMap, isNullOrUndefined } from "../JsonHelpers"; + +const DESCRIPTION: FunctionDescription = { + aliases: ["flatten"], + inputType: ArgType.Object, + description: "", + arguments: { + target: { + type: ArgType.Object, + position: 0, + description: "A target to merge into", + defaultIsNull: true, + }, + prefix: { + type: ArgType.String, + position: 1, + description: "A prefix to add to the base", + defaultIsNull: true, + }, + array_prefix: { + type: ArgType.String, + position: 2, + description: "Sets how array elements should be prefixed, leave null to not flatten arrays", + defaultString: "$", + }, + }, + outputType: ArgType.Any, +}; +class TransformerFunctionFlatten extends TransformerFunction { + constructor() { + super(DESCRIPTION); + } + + override async apply(context: FunctionContext): Promise { + const jeTarget = await context.getJsonElement("target"); + let target; + if (isMap(jeTarget)) { + target = jeTarget; + } else { + target = {}; + } + + return flatten( + await context.getJsonElement(null, true), + target, + (await context.getString("prefix")) ?? undefined, + (await context.getString("array_prefix")) ?? undefined, + ); + } +} + +function flatten(source: any, target: Record, prefix?: string, arrayPrefix?: string) { + if (isNullOrUndefined(source)) { + return target; + } + if (isMap(source)) { + Object.entries(source).forEach(([key, val]) => + flatten(val, target, prefix == null ? key : prefix + "." + key, arrayPrefix), + ); + } else if (Array.isArray(source)) { + if (arrayPrefix != null) { + const size = source.length; + for (let i = 0; i < size; i++) { + flatten(source[i], target, (prefix == null ? "" : prefix + ".") + arrayPrefix + i, arrayPrefix); + } + } else if (prefix != null) { + target[prefix] = source; + } + } else { + if (prefix == null || prefix === "") { + return source; + } + target[prefix] = source; + } + return target; +} + +export default TransformerFunctionFlatten; diff --git a/javascript/json-transform/src/functions/TransformerFunctionForm.ts b/javascript/json-transform/src/functions/TransformerFunctionForm.ts new file mode 100644 index 0000000..084eb61 --- /dev/null +++ b/javascript/json-transform/src/functions/TransformerFunctionForm.ts @@ -0,0 +1,26 @@ +import TransformerFunction from "./common/TransformerFunction"; +import { ArgType } from "./common/ArgType"; +import FunctionContext from "./common/FunctionContext"; +import { FunctionDescription } from "./common/FunctionDescription"; +import FormUrlEncodedFormat from "../formats/formurlencoded/FormUrlEncodedFormat"; + +const DESCRIPTION: FunctionDescription = { + aliases: ["form"], + description: "", + inputType: ArgType.Object, + outputType: ArgType.String, +}; +class TransformerFunctionForm extends TransformerFunction { + private static readonly FORM_URL_ENCODED_FORMAT = new FormUrlEncodedFormat(); + + constructor() { + super(DESCRIPTION); + } + + override async apply(context: FunctionContext): Promise { + const value = await context.getUnwrapped(null); + return TransformerFunctionForm.FORM_URL_ENCODED_FORMAT.serialize(value); + } +} + +export default TransformerFunctionForm; diff --git a/javascript/json-transform/src/functions/TransformerFunctionFormParse.ts b/javascript/json-transform/src/functions/TransformerFunctionFormParse.ts new file mode 100644 index 0000000..559aad0 --- /dev/null +++ b/javascript/json-transform/src/functions/TransformerFunctionFormParse.ts @@ -0,0 +1,27 @@ +import TransformerFunction from "./common/TransformerFunction"; +import { ArgType } from "./common/ArgType"; +import FunctionContext from "./common/FunctionContext"; +import { FunctionDescription } from "./common/FunctionDescription"; +import FormUrlEncodedFormat from "../formats/formurlencoded/FormUrlEncodedFormat"; + +const DESCRIPTION: FunctionDescription = { + aliases: ["formparse"], + description: "", + inputType: ArgType.String, + outputType: ArgType.Object, +}; +class TransformerFunctionFormParse extends TransformerFunction { + private static readonly FORM_URL_ENCODED_FORMAT = new FormUrlEncodedFormat(); + + constructor() { + super(DESCRIPTION); + } + + override async apply(context: FunctionContext): Promise { + const value = await context.getString(null); + if (value === null) return null; + return TransformerFunctionFormParse.FORM_URL_ENCODED_FORMAT.deserialize(value); + } +} + +export default TransformerFunctionFormParse; diff --git a/javascript/json-transform/src/functions/TransformerFunctionIsNull.ts b/javascript/json-transform/src/functions/TransformerFunctionIsNull.ts new file mode 100644 index 0000000..31b7745 --- /dev/null +++ b/javascript/json-transform/src/functions/TransformerFunctionIsNull.ts @@ -0,0 +1,24 @@ +import TransformerFunction from "./common/TransformerFunction"; +import { ArgType } from "./common/ArgType"; +import FunctionContext from "./common/FunctionContext"; +import { FunctionDescription } from "./common/FunctionDescription"; +import { isNullOrUndefined } from "../JsonHelpers"; + +const DESCRIPTION: FunctionDescription = { + aliases: ["isnull"], + description: "", + inputType: ArgType.Any, + outputType: ArgType.Boolean, +}; +class TransformerFunctionIsNull extends TransformerFunction { + constructor() { + super(DESCRIPTION); + } + + override async apply(context: FunctionContext): Promise { + const value = await context.getJsonElement(null); + return isNullOrUndefined(value); + } +} + +export default TransformerFunctionIsNull; diff --git a/javascript/json-transform/src/functions/TransformerFunctionJsonParse.ts b/javascript/json-transform/src/functions/TransformerFunctionJsonParse.ts index c4529f5..d0f2714 100644 --- a/javascript/json-transform/src/functions/TransformerFunctionJsonParse.ts +++ b/javascript/json-transform/src/functions/TransformerFunctionJsonParse.ts @@ -4,7 +4,7 @@ import { FunctionDescription } from "./common/FunctionDescription"; import FunctionContext from "./common/FunctionContext"; const DESCRIPTION: FunctionDescription = { - aliases: ["jsonparse", "json"], + aliases: ["jsonparse"], inputType: ArgType.String, description: "", outputType: ArgType.Any, diff --git a/javascript/json-transform/src/functions/common/FunctionContext.ts b/javascript/json-transform/src/functions/common/FunctionContext.ts index 73f9a8a..56b2c67 100644 --- a/javascript/json-transform/src/functions/common/FunctionContext.ts +++ b/javascript/json-transform/src/functions/common/FunctionContext.ts @@ -1,7 +1,7 @@ import TransformerFunction from "./TransformerFunction"; import { ParameterResolver } from "../../ParameterResolver"; import { JsonTransformerFunction } from "../../JsonTransformerFunction"; -import { compareTo, isNullOrUndefined, getAsString, getDocumentContext } from "../../JsonHelpers"; +import { compareTo, isNullOrUndefined, getAsString, getDocumentContext, isMap } from "../../JsonHelpers"; import { BigDecimal } from "./FunctionHelpers"; import JsonElementStreamer from "../../JsonElementStreamer"; @@ -40,7 +40,7 @@ class FunctionContext { ): ParameterResolver { if (definition?.[FunctionContext.CONTEXT_KEY]) { const contextElement = definition[FunctionContext.CONTEXT_KEY]; - if (typeof contextElement === "object") { + if (isMap(contextElement)) { const addCtx = Object.entries(contextElement).reduce( (a, [key, value]) => { a[key] = getDocumentContext(extractor.transform(value, resolver, false)); diff --git a/javascript/json-transform/src/transformerFunctions.ts b/javascript/json-transform/src/transformerFunctions.ts index b770290..0653409 100644 --- a/javascript/json-transform/src/transformerFunctions.ts +++ b/javascript/json-transform/src/transformerFunctions.ts @@ -9,10 +9,6 @@ import TransformerFunctionAt from "./functions/TransformerFunctionAt"; import TransformerFunctionAvg from "./functions/TransformerFunctionAvg"; import TransformerFunctionBase64 from "./functions/TransformerFunctionBase64"; import TransformerFunctionBoolean from "./functions/TransformerFunctionBoolean"; - -import TransformerFunctionLower from "./functions/TransformerFunctionLower"; -import TransformerFunctionUpper from "./functions/TransformerFunctionUpper"; -import TransformerFunctionIs from "./functions/TransformerFunctionIs"; import TransformerFunctionCoalesce from "./functions/TransformerFunctionCoalesce"; import TransformerFunctionConcat from "./functions/TransformerFunctionConcat"; import TransformerFunctionContains from "./functions/TransformerFunctionContains"; @@ -25,13 +21,21 @@ import TransformerFunctionDistinct from "./functions/TransformerFunctionDistinct import TransformerFunctionEntries from "./functions/TransformerFunctionEntries"; import TransformerFunctionEval from "./functions/TransformerFunctionEval"; import TransformerFunctionFilter from "./functions/TransformerFunctionFilter"; -import TransformerFunctionTest from "./functions/TransformerFunctionTest"; import TransformerFunctionFind from "./functions/TransformerFunctionFind"; +import TransformerFunctionIs from "./functions/TransformerFunctionIs"; +import TransformerFunctionIsNull from "./functions/TransformerFunctionIsNull"; +import TransformerFunctionFlat from "./functions/TransformerFunctionFlat"; +import TransformerFunctionForm from "./functions/TransformerFunctionForm"; +import TransformerFunctionFormParse from "./functions/TransformerFunctionFormParse"; import TransformerFunctionJoin from "./functions/TransformerFunctionJoin"; import TransformerFunctionJsonParse from "./functions/TransformerFunctionJsonParse"; +import TransformerFunctionTest from "./functions/TransformerFunctionTest"; +import TransformerFunctionLower from "./functions/TransformerFunctionLower"; +import TransformerFunctionUpper from "./functions/TransformerFunctionUpper"; +import TransformerFunctionFlatten from "./functions/TransformerFunctionFlatten"; class FunctionMatchResult { - private result; + private readonly result; constructor(result: any) { this.result = result; @@ -73,20 +77,19 @@ export class TransformerFunctions { digest: new TransformerFunctionDigest(), distinct: new TransformerFunctionDistinct(), entries: new TransformerFunctionEntries(), - eval: new TransformerFunctionEval(), // TODO: run tests + eval: new TransformerFunctionEval(), filter: new TransformerFunctionFilter(), find: new TransformerFunctionFind(), first: new TransformerFunctionCoalesce(), // * alias for coalesce - flat: new TransformerFunction(UNIMPLEMENTED), // TODO: new TransformerFunctionFlat(), - flatten: new TransformerFunction(UNIMPLEMENTED), // TODO: new TransformerFunctionFlatten(), - form: new TransformerFunction(UNIMPLEMENTED), // TODO: new TransformerFunctionForm(), - formparse: new TransformerFunction(UNIMPLEMENTED), // TODO: new TransformerFunctionFormParse(), + flat: new TransformerFunctionFlat(), + flatten: new TransformerFunctionFlatten(), + form: new TransformerFunctionForm(), + formparse: new TransformerFunctionFormParse(), group: new TransformerFunction(UNIMPLEMENTED), // TODO: new TransformerFunctionGroup(), if: new TransformerFunction(UNIMPLEMENTED), // TODO: new TransformerFunctionIf(), is: new TransformerFunctionIs(), - isnull: new TransformerFunction(UNIMPLEMENTED), // TODO: new TransformerFunctionIsNull(), + isnull: new TransformerFunctionIsNull(), join: new TransformerFunctionJoin(), - json: new TransformerFunctionJsonParse(), // * alias for jsonparse jsonparse: new TransformerFunctionJsonParse(), jsonpatch: new TransformerFunction(UNIMPLEMENTED), // TODO: new TransformerFunctionJsonPatch(), jsonpath: new TransformerFunction(UNIMPLEMENTED), // TODO: new TransformerFunctionJsonPath(),