@stackables/bridge 1.4.2 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ExecutionTree.d.ts","sourceRoot":"","sources":["../src/ExecutionTree.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,MAAM,EAEN,WAAW,EACX,OAAO,EAGP,OAAO,EAER,MAAM,YAAY,CAAC;AAGpB,gFAAgF;AAChF,UAAU,IAAI;IACZ,QAAQ,CAAC,IAAI,EAAE,IAAI,GAAG,SAAS,CAAC;IAChC,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;CACvC;AAED,KAAK,KAAK,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAsChF,qBAAa,aAAa;IAQf,KAAK,EAAE,KAAK;IACnB,OAAO,CAAC,YAAY;IACpB,OAAO,CAAC,OAAO,CAAC;IAChB,OAAO,CAAC,OAAO,CAAC;IAChB,OAAO,CAAC,MAAM,CAAC;IAXjB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAM;IAChC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,OAAO,CAAC,YAAY,CAAwC;IAC5D,OAAO,CAAC,YAAY,CAA0C;IAC9D,OAAO,CAAC,aAAa,CAAsE;gBAGlF,KAAK,EAAE,KAAK,EACX,YAAY,EAAE,WAAW,EAAE,EAC3B,OAAO,CAAC,EAAE,OAAO,YAAA,EACjB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,YAAA,EAC7B,MAAM,CAAC,EAAE,aAAa,YAAA;IA8BhC,oCAAoC;IACpC,OAAO,CAAC,WAAW;IAKnB;uGACmG;IACnG,OAAO,CAAC,YAAY;IAsBpB,oEAAoE;IACpE,OAAO,CAAC,oBAAoB;IA8D5B,mEAAmE;YACrD,gBAAgB;IA0B9B,2EAA2E;YAC7D,iBAAiB;
|
|
1
|
+
{"version":3,"file":"ExecutionTree.d.ts","sourceRoot":"","sources":["../src/ExecutionTree.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,MAAM,EAEN,WAAW,EACX,OAAO,EAGP,OAAO,EAER,MAAM,YAAY,CAAC;AAGpB,gFAAgF;AAChF,UAAU,IAAI;IACZ,QAAQ,CAAC,IAAI,EAAE,IAAI,GAAG,SAAS,CAAC;IAChC,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;CACvC;AAED,KAAK,KAAK,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAsChF,qBAAa,aAAa;IAQf,KAAK,EAAE,KAAK;IACnB,OAAO,CAAC,YAAY;IACpB,OAAO,CAAC,OAAO,CAAC;IAChB,OAAO,CAAC,OAAO,CAAC;IAChB,OAAO,CAAC,MAAM,CAAC;IAXjB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAM;IAChC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,OAAO,CAAC,YAAY,CAAwC;IAC5D,OAAO,CAAC,YAAY,CAA0C;IAC9D,OAAO,CAAC,aAAa,CAAsE;gBAGlF,KAAK,EAAE,KAAK,EACX,YAAY,EAAE,WAAW,EAAE,EAC3B,OAAO,CAAC,EAAE,OAAO,YAAA,EACjB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,YAAA,EAC7B,MAAM,CAAC,EAAE,aAAa,YAAA;IA8BhC,oCAAoC;IACpC,OAAO,CAAC,WAAW;IAKnB;uGACmG;IACnG,OAAO,CAAC,YAAY;IAsBpB,oEAAoE;IACpE,OAAO,CAAC,oBAAoB;IA8D5B,mEAAmE;YACrD,gBAAgB;IA0B9B,2EAA2E;YAC7D,iBAAiB;IAyC/B,kDAAkD;IAClD,OAAO,CAAC,cAAc;IAgCtB,QAAQ,CAAC,MAAM,EAAE,KAAK,GAAG,GAAG;IA8F5B,MAAM,IAAI,aAAa;YAUT,UAAU;IAmClB,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC;IAqCzC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IAI9B,6DAA6D;IAC7D,aAAa,IAAI,IAAI;IAqBrB;;oFAEgF;IAChF,OAAO,CAAC,YAAY;IA8Cd,QAAQ,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC;CA+E1D"}
|
package/build/ExecutionTree.js
CHANGED
|
@@ -186,10 +186,23 @@ export class ExecutionTree {
|
|
|
186
186
|
throw new Error(`Unknown source "${handle}" in tool "${toolDef.name}"`);
|
|
187
187
|
let value;
|
|
188
188
|
if (dep.kind === "context") {
|
|
189
|
-
|
|
189
|
+
// Walk the full parent chain for context
|
|
190
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
191
|
+
let cursor = this;
|
|
192
|
+
while (cursor && value === undefined) {
|
|
193
|
+
value = cursor.context;
|
|
194
|
+
cursor = cursor.parent;
|
|
195
|
+
}
|
|
190
196
|
}
|
|
191
197
|
else if (dep.kind === "const") {
|
|
192
|
-
|
|
198
|
+
// Walk the full parent chain for const state
|
|
199
|
+
const constKey = trunkKey({ module: SELF_MODULE, type: "Const", field: "const" });
|
|
200
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
201
|
+
let cursor = this;
|
|
202
|
+
while (cursor && value === undefined) {
|
|
203
|
+
value = cursor.state[constKey];
|
|
204
|
+
cursor = cursor.parent;
|
|
205
|
+
}
|
|
193
206
|
}
|
|
194
207
|
else if (dep.kind === "tool") {
|
|
195
208
|
value = await this.resolveToolDep(dep.tool);
|
|
@@ -258,10 +271,23 @@ export class ExecutionTree {
|
|
|
258
271
|
if (toolDef) {
|
|
259
272
|
await this.resolveToolWires(toolDef, input);
|
|
260
273
|
}
|
|
261
|
-
// Resolve bridge wires and apply on top
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
274
|
+
// Resolve bridge wires and apply on top.
|
|
275
|
+
// Group wires by target path so that || (null-fallback) and ??
|
|
276
|
+
// (error-fallback) semantics are honoured via resolveWires().
|
|
277
|
+
const wireGroups = new Map();
|
|
278
|
+
for (const w of bridgeWires) {
|
|
279
|
+
const key = w.to.path.join(".");
|
|
280
|
+
let group = wireGroups.get(key);
|
|
281
|
+
if (!group) {
|
|
282
|
+
group = [];
|
|
283
|
+
wireGroups.set(key, group);
|
|
284
|
+
}
|
|
285
|
+
group.push(w);
|
|
286
|
+
}
|
|
287
|
+
const groupEntries = Array.from(wireGroups.entries());
|
|
288
|
+
const resolved = await Promise.all(groupEntries.map(async ([, group]) => {
|
|
289
|
+
const value = await this.resolveWires(group);
|
|
290
|
+
return [group[0].to.path, value];
|
|
265
291
|
}));
|
|
266
292
|
for (const [path, value] of resolved) {
|
|
267
293
|
if (path.length === 0 && value != null && typeof value === "object") {
|
|
@@ -307,7 +333,14 @@ export class ExecutionTree {
|
|
|
307
333
|
}
|
|
308
334
|
async pullSingle(ref) {
|
|
309
335
|
const key = trunkKey(ref);
|
|
310
|
-
|
|
336
|
+
// Walk the full parent chain — shadow trees may be nested multiple levels
|
|
337
|
+
let value = undefined;
|
|
338
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
339
|
+
let cursor = this;
|
|
340
|
+
while (cursor && value === undefined) {
|
|
341
|
+
value = cursor.state[key];
|
|
342
|
+
cursor = cursor.parent;
|
|
343
|
+
}
|
|
311
344
|
if (value === undefined) {
|
|
312
345
|
this.state[key] = this.schedule(ref);
|
|
313
346
|
value = this.state[key];
|
|
@@ -458,6 +491,30 @@ export class ExecutionTree {
|
|
|
458
491
|
return s;
|
|
459
492
|
});
|
|
460
493
|
}
|
|
494
|
+
// Fallback: if this shadow tree has stored element data, resolve the
|
|
495
|
+
// requested field directly from it. This handles passthrough arrays
|
|
496
|
+
// where the bridge maps an inner array (e.g. `.stops <- j.stops`) but
|
|
497
|
+
// doesn't explicitly wire each scalar field on the element type.
|
|
498
|
+
if (this.parent) {
|
|
499
|
+
const elementKey = trunkKey({ ...this.trunk, element: true });
|
|
500
|
+
const elementData = this.state[elementKey];
|
|
501
|
+
if (elementData != null && typeof elementData === "object" && !Array.isArray(elementData)) {
|
|
502
|
+
const fieldName = cleanPath[cleanPath.length - 1];
|
|
503
|
+
if (fieldName !== undefined && fieldName in elementData) {
|
|
504
|
+
const value = elementData[fieldName];
|
|
505
|
+
if (array && Array.isArray(value)) {
|
|
506
|
+
// Nested array: wrap items in shadow trees so they can
|
|
507
|
+
// resolve their own fields via this same fallback path.
|
|
508
|
+
return value.map((item) => {
|
|
509
|
+
const s = this.shadow();
|
|
510
|
+
s.state[elementKey] = item;
|
|
511
|
+
return s;
|
|
512
|
+
});
|
|
513
|
+
}
|
|
514
|
+
return value;
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
}
|
|
461
518
|
// Return self to trigger downstream resolvers
|
|
462
519
|
return this;
|
|
463
520
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bridge-format.d.ts","sourceRoot":"","sources":["../src/bridge-format.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAKR,WAAW,EAMd,MAAM,YAAY,CAAC;AA8CpB,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,EAAE,CA0FvD;
|
|
1
|
+
{"version":3,"file":"bridge-format.d.ts","sourceRoot":"","sources":["../src/bridge-format.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAKR,WAAW,EAMd,MAAM,YAAY,CAAC;AA8CpB,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,EAAE,CA0FvD;AAmxCD;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAchD;AAID;;GAEG;AACH,wBAAgB,eAAe,CAAC,YAAY,EAAE,WAAW,EAAE,GAAG,MAAM,CA8BnE"}
|
package/build/bridge-format.js
CHANGED
|
@@ -409,6 +409,7 @@ function parseBridgeBlock(block, lineOffset, previousInstructions) {
|
|
|
409
409
|
const [, targetStr, quotedValue, unquotedValue] = constantMatch;
|
|
410
410
|
const value = quotedValue ?? unquotedValue;
|
|
411
411
|
const toRef = resolveAddress(targetStr, handleRes, bridgeType, bridgeField, ln(i));
|
|
412
|
+
assertNoTargetIndices(toRef, ln(i));
|
|
412
413
|
wires.push({ value, to: toRef });
|
|
413
414
|
continue;
|
|
414
415
|
}
|
|
@@ -427,6 +428,7 @@ function parseBridgeBlock(block, lineOffset, previousInstructions) {
|
|
|
427
428
|
assertNotReserved(iterHandle, ln(i), "iterator handle");
|
|
428
429
|
const fromRef = resolveAddress(fromClean, handleRes, bridgeType, bridgeField, ln(i));
|
|
429
430
|
const toRef = resolveAddress(targetStr, handleRes, bridgeType, bridgeField, ln(i));
|
|
431
|
+
assertNoTargetIndices(toRef, ln(i));
|
|
430
432
|
wires.push({ from: fromRef, to: toRef });
|
|
431
433
|
currentArrayToPath = toRef.path;
|
|
432
434
|
currentIterHandle = iterHandle;
|
|
@@ -469,6 +471,7 @@ function parseBridgeBlock(block, lineOffset, previousInstructions) {
|
|
|
469
471
|
fallbackInternalWires = wires.splice(preLen);
|
|
470
472
|
}
|
|
471
473
|
const toRef = resolveAddress(targetStr, handleRes, bridgeType, bridgeField, ln(i));
|
|
474
|
+
assertNoTargetIndices(toRef, ln(i));
|
|
472
475
|
for (let ci = 0; ci < sourceParts.length; ci++) {
|
|
473
476
|
const isFirst = ci === 0;
|
|
474
477
|
const isLast = ci === sourceParts.length - 1;
|
|
@@ -927,6 +930,14 @@ function resolveAddress(address, handles, bridgeType, bridgeField, lineNum) {
|
|
|
927
930
|
throw new Error(`${lineNum != null ? `Line ${lineNum}: ` : ""}Undeclared handle "${prefix}". ` +
|
|
928
931
|
`Add 'with ${prefix}' or 'with ${prefix} as ${prefix}' to the bridge header.`);
|
|
929
932
|
}
|
|
933
|
+
/** Reject explicit array indices on the target (LHS) of a wire. */
|
|
934
|
+
function assertNoTargetIndices(ref, lineNum) {
|
|
935
|
+
if (ref.path.some((seg) => /^\d+$/.test(seg))) {
|
|
936
|
+
throw new Error(`${lineNum != null ? `Line ${lineNum}: ` : ""}` +
|
|
937
|
+
`Explicit array index in wire target is not supported. ` +
|
|
938
|
+
`Use array mapping (\`[] as iter { }\`) instead.`);
|
|
939
|
+
}
|
|
940
|
+
}
|
|
930
941
|
// ── Const block parser ──────────────────────────────────────────────────────
|
|
931
942
|
/**
|
|
932
943
|
* Parse `const` declarations into ConstDef instructions.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bridge-transform.d.ts","sourceRoot":"","sources":["../src/bridge-transform.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,KAAK,aAAa,EAEnB,MAAM,SAAS,CAAC;AAGjB,OAAO,KAAK,EAAE,WAAW,EAAc,OAAO,EAAE,MAAM,YAAY,CAAC;AAGnE,MAAM,MAAM,aAAa,GAAG;IAC1B;;;kDAG8C;IAC9C,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB;qEACiE;IACjE,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CACvD,CAAC;AAEF,gFAAgF;AAChF,MAAM,MAAM,iBAAiB,GACzB,WAAW,EAAE,GACb,CAAC,CAAC,OAAO,EAAE,GAAG,KAAK,WAAW,EAAE,CAAC,CAAC;AAEtC,wBAAgB,eAAe,CAC7B,MAAM,EAAE,aAAa,EACrB,YAAY,EAAE,iBAAiB,EAC/B,OAAO,CAAC,EAAE,aAAa,GACtB,aAAa,
|
|
1
|
+
{"version":3,"file":"bridge-transform.d.ts","sourceRoot":"","sources":["../src/bridge-transform.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,KAAK,aAAa,EAEnB,MAAM,SAAS,CAAC;AAGjB,OAAO,KAAK,EAAE,WAAW,EAAc,OAAO,EAAE,MAAM,YAAY,CAAC;AAGnE,MAAM,MAAM,aAAa,GAAG;IAC1B;;;kDAG8C;IAC9C,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB;qEACiE;IACjE,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CACvD,CAAC;AAEF,gFAAgF;AAChF,MAAM,MAAM,iBAAiB,GACzB,WAAW,EAAE,GACb,CAAC,CAAC,OAAO,EAAE,GAAG,KAAK,WAAW,EAAE,CAAC,CAAC;AAEtC,wBAAgB,eAAe,CAC7B,MAAM,EAAE,aAAa,EACrB,YAAY,EAAE,iBAAiB,EAC/B,OAAO,CAAC,EAAE,aAAa,GACtB,aAAa,CA+Ef"}
|
|
@@ -44,6 +44,11 @@ export function bridgeTransform(schema, instructions, options) {
|
|
|
44
44
|
}
|
|
45
45
|
// Kick off forced wires (<-!) at the root entry point
|
|
46
46
|
if (source instanceof ExecutionTree && !info.path.prev) {
|
|
47
|
+
// Ensure input state exists even with no args (prevents
|
|
48
|
+
// recursive scheduling of the input trunk → stack overflow).
|
|
49
|
+
if (!args || Object.keys(args).length === 0) {
|
|
50
|
+
source.push({});
|
|
51
|
+
}
|
|
47
52
|
source.executeForced();
|
|
48
53
|
}
|
|
49
54
|
if (source instanceof ExecutionTree) {
|
package/package.json
CHANGED
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stackables/bridge",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"description": "Declarative dataflow for GraphQL",
|
|
5
5
|
"main": "./build/index.js",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"types": "./build/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"development": "./src/index.ts",
|
|
11
|
+
"import": "./build/index.js",
|
|
12
|
+
"types": "./build/index.d.ts"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
8
15
|
"files": [
|
|
9
16
|
"build",
|
|
10
17
|
"README.md"
|