Skip to content

Commit 1c99eab

Browse files
committed
feat(codegen): introduce better format for traversal zones
1 parent 13bc7da commit 1c99eab

File tree

10 files changed

+333
-353
lines changed

10 files changed

+333
-353
lines changed

src/__tests__/codegen.test.mjs

+113-70
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ describe('Code Generator', () => {
1313
'$.info',
1414
'$.info.contact',
1515
'$.info.contact.*',
16+
'$[servers,paths][*]',
1617
'$.servers[*].url',
1718
'$.servers[0:2]',
1819
'$.servers[:5]',
@@ -24,36 +25,38 @@ describe('Code Generator', () => {
2425
]),
2526
).to.eq(`import {Scope, isObject} from "nimma/runtime";
2627
const zones = {
27-
"info": {
28-
"contact": {
29-
"*": {}
28+
keys: ["info", "servers", "paths", "channels"],
29+
zones: [{
30+
keys: ["contact"],
31+
zones: [{
32+
zone: {}
33+
}]
34+
}, {
35+
zone: {
36+
keys: ["url"],
37+
zones: [{}]
3038
}
31-
},
32-
"servers": {
33-
"*": {
34-
"url": {}
35-
}
36-
},
37-
"paths": {
38-
"*": {
39-
"202": {},
40-
"404": {}
39+
}, {
40+
zone: {
41+
keys: [404, 202],
42+
zones: [{}, {}]
4143
}
42-
},
43-
"channels": {
44-
"*": {
45-
"publish": {
46-
"*": {
47-
"payload": {}
44+
}, {
45+
zone: {
46+
keys: ["publish", "subscribe"],
47+
zones: [{
48+
zone: {
49+
keys: ["payload"],
50+
zones: [{}]
4851
}
49-
},
50-
"subscribe": {
51-
"*": {
52-
"payload": {}
52+
}, {
53+
zone: {
54+
keys: ["payload"],
55+
zones: [{}]
5356
}
54-
}
57+
}]
5558
}
56-
}
59+
}]
5760
};
5861
const tree = {
5962
"$.info": function (scope) {
@@ -76,6 +79,11 @@ const tree = {
7679
if (scope.path[1] !== "contact") return;
7780
scope.emit("$.info.contact.*", 0, false);
7881
},
82+
"$[servers,paths][*]": function (scope) {
83+
if (scope.path.length !== 2) return;
84+
if (scope.path[0] !== "servers" && scope.path[0] !== "paths") return;
85+
scope.emit("$[servers,paths][*]", 0, false);
86+
},
7987
"$.servers[*].url": function (scope) {
8088
if (scope.path.length !== 3) return;
8189
if (scope.path[0] !== "servers") return;
@@ -148,6 +156,7 @@ export default function (input, callbacks) {
148156
const state0 = scope.allocState();
149157
scope.traverse(() => {
150158
tree["$.info.contact.*"](scope);
159+
tree["$[servers,paths][*]"](scope);
151160
tree["$.servers[*].url"](scope);
152161
tree["$.servers[0:2]"](scope);
153162
tree["$.servers[:5]"](scope);
@@ -166,11 +175,13 @@ export default function (input, callbacks) {
166175
expect(generate(['$.info~', '$.servers[*].url~', '$.servers[:5]~'])).to
167176
.eq(`import {Scope, isObject} from "nimma/runtime";
168177
const zones = {
169-
"servers": {
170-
"*": {
171-
"url": {}
178+
keys: ["servers"],
179+
zones: [{
180+
zone: {
181+
keys: ["url"],
182+
zones: [{}]
172183
}
173-
}
184+
}]
174185
};
175186
const tree = {
176187
"$.info~": function (scope) {
@@ -595,7 +606,7 @@ export default function (input, callbacks) {
595606
expect(generate(['$[*]', '$.*', '$[*]^', '$[*]~'])).to
596607
.eq(`import {Scope} from "nimma/runtime";
597608
const zones = {
598-
"*": {}
609+
zone: {}
599610
};
600611
const tree = {
601612
"$[*]": function (scope) {
@@ -698,7 +709,7 @@ export default function (input, callbacks) {
698709
]),
699710
).to.eq(`import {Scope, inBounds} from "nimma/runtime";
700711
const zones = {
701-
"*": {}
712+
zone: {}
702713
};
703714
const tree = {
704715
"$[0:2]": function (scope) {
@@ -816,9 +827,8 @@ export default function (input, callbacks) {
816827
expect(generate(['$.store..[price,bar,baz]', '$.book'])).to
817828
.eq(`import {Scope, isObject} from "nimma/runtime";
818829
const zones = {
819-
"store": {
820-
"**": null
821-
}
830+
keys: ["store"],
831+
zones: [null]
822832
};
823833
const tree = {
824834
"$.store..[price,bar,baz]": function (scope) {
@@ -857,11 +867,12 @@ export default function (input, callbacks) {
857867
]),
858868
).to.eq(`import {Scope} from "nimma/runtime";
859869
const zones = {
860-
"paths": {
861-
"*": {
862-
"**": null
870+
keys: ["paths"],
871+
zones: [{
872+
zone: {
873+
zone: null
863874
}
864-
}
875+
}]
865876
};
866877
const tree = {
867878
"$.paths[*][*]..content[*].examples[*]": function (scope) {
@@ -897,18 +908,15 @@ export default function (input, callbacks) {
897908
expect(generate(['$.data[*][*][city,street]..id'])).to
898909
.eq(`import {Scope} from "nimma/runtime";
899910
const zones = {
900-
"data": {
901-
"*": {
902-
"*": {
903-
"city": {
904-
"**": null
905-
},
906-
"street": {
907-
"**": null
908-
}
911+
keys: ["data"],
912+
zones: [{
913+
zone: {
914+
zone: {
915+
keys: ["city", "street"],
916+
zones: [null, null]
909917
}
910918
}
911-
}
919+
}]
912920
};
913921
const tree = {
914922
"$.data[*][*][city,street]..id": function (scope) {
@@ -944,28 +952,28 @@ export default function (input, callbacks) {
944952
]),
945953
).to.eq(`import {Scope} from "nimma/runtime";
946954
const zones = {
947-
"paths": {
948-
"*": {
949-
"*": {
950-
"tags": {
951-
"*": {}
952-
},
953-
"operationId": {}
955+
keys: ["paths", "abc"],
956+
zones: [{
957+
zone: {
958+
zone: {
959+
keys: ["tags", "operationId"],
960+
zones: [{
961+
zone: {}
962+
}, {}]
954963
}
955964
}
956-
},
957-
"abc": {
958-
"*": {
959-
"*": {
960-
"*": {
961-
"*": {
962-
"baz": {},
963-
"bar": {}
965+
}, {
966+
zone: {
967+
zone: {
968+
zone: {
969+
zone: {
970+
keys: ["baz", "bar"],
971+
zones: [{}, {}]
964972
}
965973
}
966974
}
967975
}
968-
}
976+
}]
969977
};
970978
const tree = {
971979
"$.paths[*][*].tags[*]": function (scope) {
@@ -1020,6 +1028,39 @@ export default function (input, callbacks) {
10201028
scope.destroy();
10211029
}
10221030
}
1031+
`);
1032+
});
1033+
1034+
it('* and ** used as member property keys', () => {
1035+
expect(generate(['$.test[*]["*"]'])).to
1036+
.eq(`import {Scope} from "nimma/runtime";
1037+
const zones = {
1038+
keys: ["test"],
1039+
zones: [{
1040+
zone: {
1041+
keys: ["*"],
1042+
zones: [{}]
1043+
}
1044+
}]
1045+
};
1046+
const tree = {
1047+
"$.test[*][\\"*\\"]": function (scope) {
1048+
if (scope.path.length !== 3) return;
1049+
if (scope.path[0] !== "test") return;
1050+
if (scope.path[2] !== "*") return;
1051+
scope.emit("$.test[*][\\"*\\"]", 0, false);
1052+
}
1053+
};
1054+
export default function (input, callbacks) {
1055+
const scope = new Scope(input, callbacks);
1056+
try {
1057+
scope.traverse(() => {
1058+
tree["$.test[*][\\"*\\"]"](scope);
1059+
}, zones);
1060+
} finally {
1061+
scope.destroy();
1062+
}
1063+
}
10231064
`);
10241065
});
10251066
});
@@ -1075,7 +1116,7 @@ export default function (input, callbacks) {
10751116
]),
10761117
).to.eq(`import {Scope} from "nimma/runtime";
10771118
const zones = {
1078-
"*": {}
1119+
zone: {}
10791120
};
10801121
const tree = {
10811122
"$[?(index(@)=='key')]": function (scope) {
@@ -1181,11 +1222,13 @@ export default function (input, callbacks) {
11811222
}),
11821223
).to.eq(`import {Scope} from "nimma/runtime";
11831224
const zones = {
1184-
"components": {
1185-
"schemas": {
1186-
"**": null
1187-
}
1188-
}
1225+
keys: ["components"],
1226+
zones: [{
1227+
keys: ["schemas"],
1228+
zones: [{
1229+
zone: null
1230+
}]
1231+
}]
11891232
};
11901233
const tree = {
11911234
"$.components.schemas[*]..@@schema()": function (scope) {

src/__tests__/index.test.mjs

-37
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
/* eslint-disable no-undef */
22
import { expect } from 'chai';
3-
import forEach from 'mocha-each';
43

54
import Nimma from '../index.mjs';
65
import { RuntimeError } from '../runtime/errors/index.mjs';
@@ -1452,42 +1451,6 @@ describe('Nimma', () => {
14521451
});
14531452
});
14541453

1455-
forEach([
1456-
Object.preventExtensions({
1457-
shirts: Object.seal({
1458-
color: 'red',
1459-
size: 'xl',
1460-
a: Object.freeze({
1461-
size: 'xl',
1462-
}),
1463-
b: Object.freeze({
1464-
size: 'm',
1465-
}),
1466-
}),
1467-
}),
1468-
{
1469-
shirts: {
1470-
color: 'red',
1471-
size: 'xl',
1472-
a: Object.seal({
1473-
size: 'xl',
1474-
}),
1475-
b: {
1476-
size: 'm',
1477-
},
1478-
},
1479-
},
1480-
]).it('frozen/sealed/non-extensible', document => {
1481-
const collected = collect(document, ['$.shirts[a,b].size']);
1482-
1483-
expect(collected).to.deep.eq({
1484-
'$.shirts[a,b].size': [
1485-
['xl', ['shirts', 'a', 'size']],
1486-
['m', ['shirts', 'b', 'size']],
1487-
],
1488-
});
1489-
});
1490-
14911454
it('given runtime errors, throws AggregateError', () => {
14921455
const n = new Nimma(['$.a', '$.b', '$.c', '$.d', '$.e', '$.f']);
14931456

src/codegen/baseline/index.mjs

+3-4
Original file line numberDiff line numberDiff line change
@@ -77,11 +77,12 @@ export default function baseline(jsonPaths, opts) {
7777
]
7878
: [];
7979

80-
const zone = tree.traversalZones.create();
80+
let zone = tree.traversalZones.create();
8181

8282
for (const node of iterator) {
8383
if (isDeep(node)) {
84-
zone?.allIn();
84+
zone?.unbind();
85+
zone = null;
8586
}
8687

8788
switch (node.type) {
@@ -115,8 +116,6 @@ export default function baseline(jsonPaths, opts) {
115116
} else {
116117
tree.addTreeMethod(ctx.id, b.blockStatement(branch), 'traverse');
117118
}
118-
119-
zone?.attach();
120119
}
121120

122121
return tree;

src/codegen/fast-paths/only-filter-script-expression.mjs

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ export default (nodes, tree, ctx) => {
3636
);
3737

3838
if (!isDeep(nodes[0])) {
39-
tree.traversalZones.create()?.resize().attach();
39+
tree.traversalZones.create()?.resize();
4040
}
4141

4242
return true;

0 commit comments

Comments
 (0)