Skip to content

Commit b6c265d

Browse files
committed
refactor, use Sequency for streams
1 parent e14e7b8 commit b6c265d

24 files changed

+753
-65
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
name: JavaScript json-transform Test
2+
3+
on:
4+
pull_request:
5+
branches:
6+
- main
7+
paths:
8+
- javascript/json-transform/**
9+
10+
# cancel previous tests if new commit is pushed to PR branch
11+
concurrency:
12+
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
13+
cancel-in-progress: true
14+
15+
jobs:
16+
test:
17+
runs-on: ubuntu-latest
18+
steps:
19+
- uses: actions/checkout@v4
20+
21+
- uses: actions/setup-node@v4
22+
with:
23+
node-version: 18
24+
cache: npm
25+
cache-dependency-path: ./javascript/json-transform/package-lock.json
26+
27+
- name: Install dependencies
28+
working-directory: ./javascript/json-transform
29+
run: npm ci
30+
31+
- name: Run tests
32+
working-directory: ./javascript/json-transform
33+
run: npm test

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

+7-7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

javascript/json-transform-core/package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,10 @@
4040
},
4141
"homepage": "https://github.com/nlighten-oss/json-transform#readme",
4242
"peerDependencies": {
43-
"@nlighten/json-schema-utils": "^1.0.0"
43+
"@nlighten/json-schema-utils": "^1.0.2"
4444
},
4545
"devDependencies": {
46-
"@nlighten/json-schema-utils": "^1.0.0",
46+
"@nlighten/json-schema-utils": "^1.0.2",
4747
"microbundle": "^0.15.1",
4848
"prettier": "3.1.1",
4949
"typescript": "^5.3.3",

javascript/json-transform/package-lock.json

+27-7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

javascript/json-transform/package.json

+6-2
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,12 @@
4040
},
4141
"homepage": "https://github.com/nlighten-oss/json-transform#readme",
4242
"peerDependencies": {
43-
"@nlighten/json-schema-utils": "^1.0.0",
43+
"@nlighten/json-schema-utils": "^1.0.2",
4444
"jsonpath": "^1.1.1",
4545
"uuid": "^10.0.0"
4646
},
4747
"devDependencies": {
48-
"@nlighten/json-schema-utils": "^1.0.0",
48+
"@nlighten/json-schema-utils": "^1.0.2",
4949
"@types/jsonpath": "^0.2.4",
5050
"@types/uuid": "^10.0.0",
5151
"jsonpath": "^1.1.1",
@@ -54,5 +54,9 @@
5454
"typescript": "^5.3.3",
5555
"uuid": "^10.0.0",
5656
"vitest": "1.2.2"
57+
},
58+
"dependencies": {
59+
"bignumber.js": "^9.1.2",
60+
"sequency": "^0.20.0"
5761
}
5862
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import FunctionContext from "./functions/common/FunctionContext";
2+
import Sequence, { asSequence, emptySequence } from "sequency";
3+
4+
class JsonElementStreamer {
5+
private readonly context: FunctionContext;
6+
private readonly transformed: boolean;
7+
private readonly value?: any[];
8+
private readonly _stream?: Sequence<any>;
9+
10+
private constructor(context: FunctionContext, value: any[] | Sequence<any>, transformed: boolean) {
11+
this.context = context;
12+
this.transformed = transformed;
13+
if (Array.isArray(value)) {
14+
this.value = value;
15+
this._stream = undefined;
16+
} else {
17+
this.value = undefined;
18+
this._stream = value;
19+
}
20+
}
21+
22+
public knownAsEmpty() {
23+
return this.value && this.value.length == 0;
24+
}
25+
26+
public stream(skip: number = 0, limit: number = -1) {
27+
if (this._stream != null) {
28+
const skipped = skip > 0 ? this._stream.drop(skip) : this._stream;
29+
return limit > -1 ? skipped.take(limit) : skipped;
30+
}
31+
if (this.value == null) {
32+
return emptySequence();
33+
}
34+
let valueStream = asSequence(this.value);
35+
if (skip > 0) {
36+
valueStream = valueStream.drop(skip);
37+
}
38+
if (limit > -1) {
39+
valueStream = valueStream.take(limit);
40+
}
41+
if (!this.transformed) {
42+
valueStream = valueStream.map(el => this.context.transform(el));
43+
}
44+
return valueStream;
45+
}
46+
47+
public static fromJsonArray(context: FunctionContext, value: any[], transformed: boolean) {
48+
return new JsonElementStreamer(context, value, transformed);
49+
}
50+
51+
public static fromTransformedStream(context: FunctionContext, stream: Sequence<any>) {
52+
return new JsonElementStreamer(context, stream, true);
53+
}
54+
55+
public toJsonArray() {
56+
if (this.value) {
57+
return this.value;
58+
}
59+
const ja: any[] = [];
60+
if (this._stream) {
61+
this._stream.forEach(item => ja.push(item));
62+
}
63+
return ja;
64+
}
65+
}
66+
67+
export default JsonElementStreamer;

javascript/json-transform/src/JsonHelpers.ts

+26-9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import { v4 as uuidv4 } from 'uuid';
22
import DocumentContext from "./DocumentContext";
3+
import {BigDecimal} from "./functions/common/FunctionHelpers";
4+
import {areSimilar} from "@nlighten/json-schema-utils";
35

46
const JSONPATH_ROOT = "$",
57
JSONPATH_ROOT_ESC = "\\$",
@@ -29,15 +31,17 @@ const numberCompare = (a: number, b: number) => {
2931
return a < b ? -1 : (a === b ? 0 : 1);
3032
}
3133

34+
const numberType = (a: any) => typeof a === 'number' || typeof a === 'bigint' || a instanceof BigDecimal;
35+
3236
const compareTo = (a: any, b: any) => {
3337
if (Array.isArray(a) && Array.isArray(b)) {
3438
return numberCompare(a.length, b.length);
3539
} else if (a && b && typeof a === 'object' && typeof b === 'object') {
3640
return numberCompare(Object.keys(a).length, Object.keys(b).length);
3741
} else if (typeof a === 'string' && typeof b === 'string') {
3842
return a.localeCompare(b);
39-
} else if (typeof a === 'number' && typeof b === 'number') {
40-
return numberCompare(a, b);
43+
} else if (numberType(a) && numberType(b)) {
44+
return BigDecimal(a).comparedTo(BigDecimal(b));
4145
} else if (typeof a === 'boolean' && typeof b === 'boolean') {
4246
return a === b ? 0 : (a ? 1 : -1);
4347
} else if (isNullOrUndefined(a) && !isNullOrUndefined(b)) {
@@ -143,29 +147,42 @@ const lenientJsonParse = (input: string) => {
143147

144148
const BIGINT_ZERO = BigInt(0);
145149
const isTruthy = (value: any, javascriptStyle?: boolean) => {
146-
if (Array.isArray(value)) {
147-
return value.length > 0;
148-
} else if (value && typeof value === 'object') {
149-
return Object.keys(value).length > 0;
150-
}
151150
if (typeof value === 'boolean') {
152151
return value;
153152
} else if (typeof value === 'number') {
154153
return value != 0;
155154
} else if (typeof value === 'bigint') {
156155
return value !== BIGINT_ZERO;
156+
} else if (value instanceof BigDecimal) {
157+
return !value.isZero();
157158
} else if (typeof value === 'string') {
158-
return javascriptStyle ? value !== '' : value === 'true';
159+
return javascriptStyle ? Boolean(value) : value.toLowerCase() === 'true';
160+
} else if (Array.isArray(value)) {
161+
return value.length > 0;
162+
} else if (value && typeof value === 'object') {
163+
return Object.keys(value).length > 0;
159164
}
160165
return !isNullOrUndefined(value);
161166
}
162167

168+
const isEqual = (value: any, other: any): boolean => {
169+
if (value === other) {
170+
return true;
171+
}
172+
if (numberType(value) && numberType(other)) {
173+
return BigDecimal(value).eq(BigDecimal(other));
174+
}
175+
return areSimilar(value, other);
176+
}
177+
178+
163179
export {
164180
isNullOrUndefined,
165181
createPayloadResolver,
166182
getAsString,
167183
compareTo,
168184
getDocumentContext,
169185
lenientJsonParse,
170-
isTruthy
186+
isTruthy,
187+
isEqual
171188
};

javascript/json-transform/src/JsonTransformer.ts

+10-3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {JsonTransformerFunction} from "./JsonTransformerFunction";
33
import {ParameterResolver} from "./ParameterResolver";
44
import {createPayloadResolver, isNullOrUndefined} from "./JsonHelpers";
55
import transformerFunctions, { TransformerFunctions } from "./transformerFunctions";
6+
import JsonElementStreamer from "./JsonElementStreamer";
67

78
class JsonTransformer implements Transformer {
89

@@ -32,13 +33,16 @@ class JsonTransformer implements Transformer {
3233

3334
fromJsonPrimitive(definition: any, resolver: ParameterResolver, allowReturningStreams: boolean) : any {
3435
if (typeof definition !== 'string') {
35-
return definition;
36+
return definition ?? null;
3637
}
3738
try {
3839
// test for inline function (e.g. $$function:...)
3940
const match = this.transformerFunctions.matchInline(definition, resolver, this.JSON_TRANSFORMER);
4041
if (match != null) {
41-
// TODO: add streams support
42+
const matchResult = match.getResult();
43+
if (matchResult instanceof JsonElementStreamer) {
44+
return allowReturningStreams ? matchResult : matchResult.toJsonArray();
45+
}
4246
return match.getResult();
4347
}
4448
// jsonpath / context
@@ -52,7 +56,10 @@ class JsonTransformer implements Transformer {
5256
fromJsonObject(definition: any, resolver: ParameterResolver, allowReturningStreams: boolean) : any {
5357
const match = this.transformerFunctions.matchObject(definition, resolver, this.JSON_TRANSFORMER);
5458
if (match != null) {
55-
// TODO: add streams support
59+
const res = match.getResult();
60+
if (res instanceof JsonElementStreamer) {
61+
return allowReturningStreams ? res : res.toJsonArray();
62+
}
5663
return match.getResult();
5764
}
5865

javascript/json-transform/src/__tests__/JsonTransformer.test.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,8 @@ describe("JsonTransformer", () => {
108108
});
109109
});
110110

111-
test("InputExtractorSpreadDontRemoveByNull", () => {
111+
// skipped since it doesn't work the same in javascript (null are being treated as values)
112+
test.skip("InputExtractorSpreadDontRemoveByNull", () => {
112113
assertTransformation({
113114
"a": "A",
114115
"b": "B"

0 commit comments

Comments
 (0)