@lotics/cli 0.187.1 → 0.188.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.
- package/dist/src/cli.js +193 -212
- package/package.json +1 -1
package/dist/src/cli.js
CHANGED
|
@@ -45875,7 +45875,7 @@ function resultSideEffects(result) {
|
|
|
45875
45875
|
}
|
|
45876
45876
|
|
|
45877
45877
|
// src/version.ts
|
|
45878
|
-
var VERSION = "0.
|
|
45878
|
+
var VERSION = "0.188.0";
|
|
45879
45879
|
|
|
45880
45880
|
// src/timezone.ts
|
|
45881
45881
|
function machineTimezone() {
|
|
@@ -46584,7 +46584,7 @@ function buildStarterTemplate(args) {
|
|
|
46584
46584
|
import { defineConfig } from "vite";
|
|
46585
46585
|
import type { Plugin } from "vite";
|
|
46586
46586
|
import react from "@vitejs/plugin-react";
|
|
46587
|
-
import { loticsOptimizeDeps, loticsResolve } from "@lotics/ui/vite";
|
|
46587
|
+
import { loticsOptimizeDeps, loticsOptimizeExclude, loticsResolve } from "@lotics/ui/vite";
|
|
46588
46588
|
|
|
46589
46589
|
// @lotics/ui/icon.tsx deep-imports \`lucide-react-native/dist/esm/icons/<name>\`.
|
|
46590
46590
|
// lucide-react-native's \`exports\` map lists only "." and "./icons", so a strict
|
|
@@ -46646,6 +46646,11 @@ export default defineConfig({
|
|
|
46646
46646
|
// require across a major bump \u2014 the per-family rationale lives in that module.
|
|
46647
46647
|
// To add app-specific entries, spread: include: [...loticsOptimizeDeps, "my-dep"].
|
|
46648
46648
|
include: loticsOptimizeDeps,
|
|
46649
|
+
// The kit is ONE module graph, so it must never be pre-bundled: the optimizer
|
|
46650
|
+
// auto-discovers each @lotics/ui subpath and inlines a private copy of every
|
|
46651
|
+
// context-owning module it reaches (locale, tooltip, portal, popover), leaving
|
|
46652
|
+
// the provider filling one context and the component reading another.
|
|
46653
|
+
exclude: loticsOptimizeExclude,
|
|
46649
46654
|
// The dep optimizer pre-bundles deps with a SEPARATE esbuild pass that
|
|
46650
46655
|
// top-level \`define\` doesn't always reach, so a pre-bundled RN dep can
|
|
46651
46656
|
// still hit \`__DEV__ is not defined\` under \`lotics app dev\`. Define it
|
|
@@ -66481,10 +66486,9 @@ var pathSegmentSchema = zod_default.discriminatedUnion("at", [
|
|
|
66481
66486
|
at: zod_default.literal("linked"),
|
|
66482
66487
|
via: zod_default.string().min(1),
|
|
66483
66488
|
/**
|
|
66484
|
-
*
|
|
66485
|
-
* `"each"`
|
|
66486
|
-
*
|
|
66487
|
-
* single linked record (same descent semantics as the numeric form).
|
|
66489
|
+
* Which linked rows the fetch yields. A literal or computed index picks
|
|
66490
|
+
* one row — `linked(P)[i]`, one fetch. `"each"` is the bare `linked(P)`:
|
|
66491
|
+
* every row in order, holding a `null` where one is deleted or unreadable.
|
|
66488
66492
|
*/
|
|
66489
66493
|
index: zod_default.union([
|
|
66490
66494
|
zod_default.number().int().nonnegative(),
|
|
@@ -68970,6 +68974,8 @@ var RESERVED_ROOTS = /* @__PURE__ */ new Set([
|
|
|
68970
68974
|
"trigger",
|
|
68971
68975
|
"index"
|
|
68972
68976
|
]);
|
|
68977
|
+
var LINKED_CALL = "linked";
|
|
68978
|
+
var GRAMMAR_NAME_SHAPE = `${LINKED_CALL}(record["fld_link"])[0] fetches one linked row`;
|
|
68973
68979
|
var RUNTIME_KEYS = /* @__PURE__ */ new Set([
|
|
68974
68980
|
"timezone",
|
|
68975
68981
|
"workflow_id",
|
|
@@ -69159,6 +69165,30 @@ var RESERVED_CALLABLE_NAMES = /* @__PURE__ */ new Set([
|
|
|
69159
69165
|
"Math",
|
|
69160
69166
|
"Boolean"
|
|
69161
69167
|
]);
|
|
69168
|
+
function assertNotReservedName(node, name2, label, toolNames) {
|
|
69169
|
+
if (RESERVED_ROOTS.has(name2)) {
|
|
69170
|
+
fail(node, `${label} uses the reserved identifier "${name2}".`);
|
|
69171
|
+
}
|
|
69172
|
+
if (name2 === LINKED_CALL) {
|
|
69173
|
+
fail(node, `${label} names grammar: ${GRAMMAR_NAME_SHAPE}.`, "reserved_grammar_name");
|
|
69174
|
+
}
|
|
69175
|
+
if (toolNames?.has(name2)) {
|
|
69176
|
+
fail(node, `${label} collides with the tool "${name2}".`);
|
|
69177
|
+
}
|
|
69178
|
+
if (isHelper(name2)) {
|
|
69179
|
+
fail(node, `${label} collides with the built-in helper "${name2}".`);
|
|
69180
|
+
}
|
|
69181
|
+
if (RESERVED_CALLABLE_NAMES.has(name2)) {
|
|
69182
|
+
fail(node, `${label} collides with "${name2}", which the subset already gives a meaning.`);
|
|
69183
|
+
}
|
|
69184
|
+
}
|
|
69185
|
+
var LINKED_ARITY = `${LINKED_CALL}(...) takes exactly one argument \u2014 the read of the link field, e.g. ${LINKED_CALL}(record["fld_link"])[0] for one row or ${LINKED_CALL}(record["fld_link"]) for every row.`;
|
|
69186
|
+
var LINKED_ARGUMENT_SHAPE = `The argument of ${LINKED_CALL}(...) must END on the link field, because that field is what it follows \u2014 ${LINKED_CALL}(record["fld_link"])[0]. A value that names no field (a binding, a literal, a helper result) cannot say which link to follow; read the field on it: ${LINKED_CALL}(ids["fld_link"]).`;
|
|
69187
|
+
var LINKED_OPTIONAL_RESULT = `${LINKED_CALL}(...) always returns an array, never null, so \`?.\` on its result can never fire. The argument takes a guard \u2014 ${LINKED_CALL}(record?.["fld_link"])[0] \u2014 and so does the fetched row, which is null where the linked record is deleted or unreadable: ${LINKED_CALL}(record["fld_link"])[0]?.["fld_x"].`;
|
|
69188
|
+
var LINKED_METHOD_FORM = `${LINKED_CALL} has no method form \u2014 write ${LINKED_CALL}(record["fld_link"])[0], with the link read as the argument.`;
|
|
69189
|
+
var LINKED_ON_NON_RECORD = `${LINKED_CALL}(...) follows a link field on a record, and this value is not one. Read the record first, then follow the link: ${LINKED_CALL}(record["fld_link"])[0].`;
|
|
69190
|
+
var LINKED_ON_CHANGES = `A change diff is not a record, so ${LINKED_CALL}(...) cannot follow a link off it. Read the post-state with ${LINKED_CALL}(record["fld_link"]) or the pre-state with ${LINKED_CALL}(prev_record["fld_link"]).`;
|
|
69191
|
+
var OPTIONAL_CALL_MESSAGE = "Optional calls (`x?.()`) are not supported. Use `?.` on member access only.";
|
|
69162
69192
|
var MAX_EXPRESSION_DEPTH = 500;
|
|
69163
69193
|
function walkExpression(node, scope) {
|
|
69164
69194
|
const depth = scope.depth + 1;
|
|
@@ -69405,11 +69435,10 @@ function walkHelperCall(node, scope) {
|
|
|
69405
69435
|
fail(callee, LAMBDA_POSITION_HINT, "lambda_position");
|
|
69406
69436
|
}
|
|
69407
69437
|
if (node.type === "OptionalCallExpression" && node.optional === true) {
|
|
69408
|
-
fail(
|
|
69409
|
-
|
|
69410
|
-
|
|
69411
|
-
|
|
69412
|
-
);
|
|
69438
|
+
fail(node, OPTIONAL_CALL_MESSAGE, "optional_call");
|
|
69439
|
+
}
|
|
69440
|
+
if (callee.type === "Identifier" && callee.name === LINKED_CALL) {
|
|
69441
|
+
return walkRead(node, scope);
|
|
69413
69442
|
}
|
|
69414
69443
|
if ((callee.type === "MemberExpression" || callee.type === "OptionalMemberExpression") && callee.object.type === "Identifier" && callee.object.name === "Math" && !callee.computed && callee.property.type === "Identifier") {
|
|
69415
69444
|
const mathFn = callee.property.name;
|
|
@@ -69486,6 +69515,9 @@ function walkMethodForm(node, callee, scope) {
|
|
|
69486
69515
|
}
|
|
69487
69516
|
methodName = callee.property.name;
|
|
69488
69517
|
}
|
|
69518
|
+
if (methodName === LINKED_CALL) {
|
|
69519
|
+
fail(callee, LINKED_METHOD_FORM, "linked_method_form");
|
|
69520
|
+
}
|
|
69489
69521
|
const receiver = walkExpression(callee.object, scope);
|
|
69490
69522
|
const methodOptional = callee.type === "OptionalMemberExpression" && callee.optional === true;
|
|
69491
69523
|
const liftedGuards = [];
|
|
@@ -69612,12 +69644,7 @@ function walkLambda(node, scope) {
|
|
|
69612
69644
|
if (p.type !== "Identifier") {
|
|
69613
69645
|
fail(p, "Lambda parameters must be plain identifiers (no destructuring or defaults).");
|
|
69614
69646
|
}
|
|
69615
|
-
|
|
69616
|
-
fail(p, `${p.name} is reserved and cannot be a lambda parameter.`);
|
|
69617
|
-
}
|
|
69618
|
-
if (scope.toolNames.has(p.name) || isHelper(p.name)) {
|
|
69619
|
-
fail(p, `Lambda parameter "${p.name}" collides with a tool or helper.`);
|
|
69620
|
-
}
|
|
69647
|
+
assertNotReservedName(p, p.name, `Lambda parameter "${p.name}"`, scope.toolNames);
|
|
69621
69648
|
if (scope.functions.has(p.name)) {
|
|
69622
69649
|
fail(p, `Lambda parameter "${p.name}" collides with a function declared in this workflow.`);
|
|
69623
69650
|
}
|
|
@@ -69690,7 +69717,7 @@ function collectFunctionDeclarations(body, toolNames) {
|
|
|
69690
69717
|
failFunctionDeclaration(stmt, "A function declaration must be named.");
|
|
69691
69718
|
}
|
|
69692
69719
|
const name2 = stmt.id.name;
|
|
69693
|
-
|
|
69720
|
+
assertNotReservedName(stmt.id, name2, `Function "${name2}"`, toolNames);
|
|
69694
69721
|
if (functions.has(name2)) {
|
|
69695
69722
|
fail(stmt.id, `Function "${name2}" is already declared in this workflow.`);
|
|
69696
69723
|
}
|
|
@@ -69712,7 +69739,7 @@ function collectFunctionDeclarations(body, toolNames) {
|
|
|
69712
69739
|
);
|
|
69713
69740
|
}
|
|
69714
69741
|
const paramName = p.left.name;
|
|
69715
|
-
|
|
69742
|
+
assertNotReservedName(p.left, paramName, `Parameter "${paramName}"`, toolNames);
|
|
69716
69743
|
if (seen.has(paramName)) {
|
|
69717
69744
|
fail(p.left, `Parameter "${paramName}" of function "${name2}" is declared twice.`);
|
|
69718
69745
|
}
|
|
@@ -69738,20 +69765,6 @@ function collectFunctionDeclarations(body, toolNames) {
|
|
|
69738
69765
|
}
|
|
69739
69766
|
return functions;
|
|
69740
69767
|
}
|
|
69741
|
-
function assertFunctionName(node, name2, label, toolNames) {
|
|
69742
|
-
if (RESERVED_ROOTS.has(name2)) {
|
|
69743
|
-
fail(node, `${label} uses the reserved identifier "${name2}".`);
|
|
69744
|
-
}
|
|
69745
|
-
if (toolNames.has(name2)) {
|
|
69746
|
-
fail(node, `${label} collides with the tool "${name2}".`);
|
|
69747
|
-
}
|
|
69748
|
-
if (isHelper(name2)) {
|
|
69749
|
-
fail(node, `${label} collides with the built-in helper "${name2}".`);
|
|
69750
|
-
}
|
|
69751
|
-
if (RESERVED_CALLABLE_NAMES.has(name2)) {
|
|
69752
|
-
fail(node, `${label} collides with "${name2}", which the subset already gives a meaning.`);
|
|
69753
|
-
}
|
|
69754
|
-
}
|
|
69755
69768
|
function inlineFunctionCall(node, decl, scope) {
|
|
69756
69769
|
if (scope.inline.stack.includes(decl.name)) {
|
|
69757
69770
|
fail(
|
|
@@ -69806,6 +69819,7 @@ function functionBodyScope(scope, name2, args) {
|
|
|
69806
69819
|
depth: scope.depth
|
|
69807
69820
|
};
|
|
69808
69821
|
}
|
|
69822
|
+
var READ_ROOT_HINT = `Reads must start from a reserved identifier (record, prev_record, changes, runtime, trigger, index), a foreach bind name, a step-id, or ${LINKED_CALL}(record["fld_link"]).`;
|
|
69809
69823
|
function flattenChain(node, scope) {
|
|
69810
69824
|
let cur = node;
|
|
69811
69825
|
const reverse2 = [];
|
|
@@ -69845,8 +69859,11 @@ function flattenChain(node, scope) {
|
|
|
69845
69859
|
}
|
|
69846
69860
|
cur = cur.object;
|
|
69847
69861
|
}
|
|
69862
|
+
if (cur.type === "CallExpression" || cur.type === "OptionalCallExpression") {
|
|
69863
|
+
return flattenLinkedCall(cur, reverse2, scope);
|
|
69864
|
+
}
|
|
69848
69865
|
if (cur.type !== "Identifier") {
|
|
69849
|
-
fail(cur,
|
|
69866
|
+
fail(cur, READ_ROOT_HINT, "read_root");
|
|
69850
69867
|
}
|
|
69851
69868
|
return {
|
|
69852
69869
|
rootName: cur.name,
|
|
@@ -69854,6 +69871,58 @@ function flattenChain(node, scope) {
|
|
|
69854
69871
|
segments: reverse2.reverse()
|
|
69855
69872
|
};
|
|
69856
69873
|
}
|
|
69874
|
+
function flattenLinkedCall(node, reverse2, scope) {
|
|
69875
|
+
const callee = node.callee;
|
|
69876
|
+
if ((callee.type === "MemberExpression" || callee.type === "OptionalMemberExpression") && (!callee.computed && callee.property.type === "Identifier" && callee.property.name === LINKED_CALL || callee.computed && callee.property.type === "StringLiteral" && callee.property.value === LINKED_CALL)) {
|
|
69877
|
+
fail(callee, LINKED_METHOD_FORM, "linked_method_form");
|
|
69878
|
+
}
|
|
69879
|
+
if (callee.type !== "Identifier" || callee.name !== LINKED_CALL) {
|
|
69880
|
+
fail(node, READ_ROOT_HINT, "read_root");
|
|
69881
|
+
}
|
|
69882
|
+
if (node.type === "OptionalCallExpression" && node.optional === true) {
|
|
69883
|
+
fail(node, OPTIONAL_CALL_MESSAGE, "optional_call");
|
|
69884
|
+
}
|
|
69885
|
+
if (node.arguments.length !== 1) {
|
|
69886
|
+
fail(node, LINKED_ARITY, "linked_arity");
|
|
69887
|
+
}
|
|
69888
|
+
const arg = node.arguments[0];
|
|
69889
|
+
if (arg.type !== "MemberExpression" && arg.type !== "OptionalMemberExpression") {
|
|
69890
|
+
fail(arg, LINKED_ARGUMENT_SHAPE, "linked_argument_shape");
|
|
69891
|
+
}
|
|
69892
|
+
const onResult = reverse2[reverse2.length - 1];
|
|
69893
|
+
if (onResult?.optional === true) {
|
|
69894
|
+
fail(onResult.node, LINKED_OPTIONAL_RESULT, "linked_optional_result");
|
|
69895
|
+
}
|
|
69896
|
+
const folded = onResult?.kind === "bracket-number" ? onResult.index : onResult?.kind === "bracket-expr" ? onResult.expr : void 0;
|
|
69897
|
+
const linkedIndex = folded ?? "each";
|
|
69898
|
+
const afterCall = folded === void 0 ? reverse2 : reverse2.slice(0, -1);
|
|
69899
|
+
const argScope = { ...scope, depth: scope.depth + 1 };
|
|
69900
|
+
if (argScope.depth > MAX_EXPRESSION_DEPTH) {
|
|
69901
|
+
fail(node, `Expression nesting is too deep (max ${MAX_EXPRESSION_DEPTH} levels).`, "depth_limit");
|
|
69902
|
+
}
|
|
69903
|
+
const inner = flattenChain(arg, argScope);
|
|
69904
|
+
const via = inner.segments[inner.segments.length - 1];
|
|
69905
|
+
if (!via || via.kind !== "dot" && via.kind !== "bracket-string") {
|
|
69906
|
+
fail(arg, LINKED_ARGUMENT_SHAPE, "linked_argument_shape");
|
|
69907
|
+
}
|
|
69908
|
+
return {
|
|
69909
|
+
rootName: inner.rootName,
|
|
69910
|
+
rootNode: inner.rootNode,
|
|
69911
|
+
segments: [
|
|
69912
|
+
...inner.segments.slice(0, -1),
|
|
69913
|
+
// `linked(record?.["fld_link"])` guards the RECEIVER of the link read, so
|
|
69914
|
+
// the guard belongs on the segment the call became.
|
|
69915
|
+
{
|
|
69916
|
+
kind: "linked",
|
|
69917
|
+
via: via.key,
|
|
69918
|
+
index: linkedIndex,
|
|
69919
|
+
optional: via.optional === true,
|
|
69920
|
+
node: arg
|
|
69921
|
+
},
|
|
69922
|
+
...[...afterCall].reverse()
|
|
69923
|
+
]
|
|
69924
|
+
};
|
|
69925
|
+
}
|
|
69857
69926
|
function wrapOptionalGuards(chain2, buildRead) {
|
|
69858
69927
|
const firstOpt = chain2.segments.findIndex((s) => s.optional);
|
|
69859
69928
|
if (firstOpt === -1) return buildRead(chain2.segments);
|
|
@@ -69916,7 +69985,7 @@ function walkRead(node, scope) {
|
|
|
69916
69985
|
const base = inlined;
|
|
69917
69986
|
return wrapOptionalGuards(chain2, (segments) => ({
|
|
69918
69987
|
...base,
|
|
69919
|
-
path: [...base.path, ...
|
|
69988
|
+
path: [...base.path, ...pathFor(base.source, segments)]
|
|
69920
69989
|
}));
|
|
69921
69990
|
}
|
|
69922
69991
|
if (root === "record" || root === "prev_record") {
|
|
@@ -69983,19 +70052,20 @@ function walkRead(node, scope) {
|
|
|
69983
70052
|
);
|
|
69984
70053
|
}
|
|
69985
70054
|
function readFromRecord(from, chain2) {
|
|
70055
|
+
const root = from === "trigger_record" ? "record" : "prev_record";
|
|
69986
70056
|
return wrapOptionalGuards(chain2, (segments) => {
|
|
69987
70057
|
if (segments.length === 0) {
|
|
69988
70058
|
return { kind: "read", source: { from }, path: [] };
|
|
69989
70059
|
}
|
|
69990
70060
|
const first3 = segments[0];
|
|
69991
70061
|
if (first3.kind === "bracket-number" || first3.kind === "bracket-expr") {
|
|
69992
|
-
fail(
|
|
70062
|
+
fail(
|
|
70063
|
+
first3.node,
|
|
70064
|
+
`A record is keyed by field, not by index \u2014 ${root}["fld_\u2026"]. To fetch a linked row write ${LINKED_CALL}(${root}["fld_link"])[0].`
|
|
70065
|
+
);
|
|
69993
70066
|
}
|
|
69994
|
-
|
|
69995
|
-
|
|
69996
|
-
source: { from },
|
|
69997
|
-
path: classifyRecordPath(segments)
|
|
69998
|
-
};
|
|
70067
|
+
const source = { from };
|
|
70068
|
+
return { kind: "read", source, path: pathFor(source, segments) };
|
|
69999
70069
|
});
|
|
70000
70070
|
}
|
|
70001
70071
|
function readFromChanges(chain2) {
|
|
@@ -70007,17 +70077,8 @@ function readFromChanges(chain2) {
|
|
|
70007
70077
|
if (first3.kind === "bracket-number" || first3.kind === "bracket-expr") {
|
|
70008
70078
|
fail(first3.node, "changes is keyed by field name, not numeric index.");
|
|
70009
70079
|
}
|
|
70010
|
-
const
|
|
70011
|
-
|
|
70012
|
-
if (seg.kind === "bracket-number") {
|
|
70013
|
-
path13.push({ at: "index", index: seg.index });
|
|
70014
|
-
} else if (seg.kind === "bracket-expr") {
|
|
70015
|
-
path13.push({ at: "index", index: seg.expr });
|
|
70016
|
-
} else {
|
|
70017
|
-
path13.push({ at: "key", key: seg.key });
|
|
70018
|
-
}
|
|
70019
|
-
}
|
|
70020
|
-
return { kind: "read", source: { from: "trigger_changes" }, path: path13 };
|
|
70080
|
+
const source = { from: "trigger_changes" };
|
|
70081
|
+
return { kind: "read", source, path: pathFor(source, segments) };
|
|
70021
70082
|
});
|
|
70022
70083
|
}
|
|
70023
70084
|
var TRIGGER_RECORD_VIEWS = /* @__PURE__ */ new Map([
|
|
@@ -70035,17 +70096,8 @@ function readFromTrigger(chain2) {
|
|
|
70035
70096
|
return view === "trigger_changes" ? readFromChanges(lowered) : readFromRecord(view, lowered);
|
|
70036
70097
|
}
|
|
70037
70098
|
return wrapOptionalGuards(chain2, (segments) => {
|
|
70038
|
-
const
|
|
70039
|
-
|
|
70040
|
-
if (seg.kind === "bracket-number") {
|
|
70041
|
-
path13.push({ at: "index", index: seg.index });
|
|
70042
|
-
} else if (seg.kind === "bracket-expr") {
|
|
70043
|
-
path13.push({ at: "index", index: seg.expr });
|
|
70044
|
-
} else {
|
|
70045
|
-
path13.push({ at: "key", key: seg.key });
|
|
70046
|
-
}
|
|
70047
|
-
}
|
|
70048
|
-
return { kind: "read", source: { from: "trigger" }, path: path13 };
|
|
70099
|
+
const source = { from: "trigger" };
|
|
70100
|
+
return { kind: "read", source, path: pathFor(source, segments) };
|
|
70049
70101
|
});
|
|
70050
70102
|
}
|
|
70051
70103
|
function readFromRuntime(chain2) {
|
|
@@ -70057,112 +70109,79 @@ function readFromRuntime(chain2) {
|
|
|
70057
70109
|
fail(chain2.rootNode, "runtime needs a key (e.g., runtime.timezone).");
|
|
70058
70110
|
}
|
|
70059
70111
|
const first3 = segments[0];
|
|
70112
|
+
if (first3.kind === "linked") {
|
|
70113
|
+
fail(first3.node, LINKED_ON_NON_RECORD, "linked_on_non_record");
|
|
70114
|
+
}
|
|
70060
70115
|
if (first3.kind !== "dot" && first3.kind !== "bracket-string") {
|
|
70061
70116
|
fail(first3.node, "runtime is keyed by name (runtime.timezone, runtime.now, ...).");
|
|
70062
70117
|
}
|
|
70063
|
-
const key = first3.key
|
|
70118
|
+
const key = first3.key;
|
|
70064
70119
|
if (!isRuntimeKey(key)) {
|
|
70065
70120
|
fail(first3.node, `Unknown runtime key "${key}". Allowed: ${READABLE_RUNTIME_KEYS.join(", ")}.`);
|
|
70066
70121
|
}
|
|
70067
70122
|
const parked = PARKED_RUNTIME_KEYS.get(key);
|
|
70068
70123
|
if (parked) fail(first3.node, parked, parkedRuntimeKeyConstruct(key));
|
|
70069
70124
|
const source = { from: "runtime", key };
|
|
70070
|
-
|
|
70071
|
-
for (const seg of segments.slice(1)) {
|
|
70072
|
-
if (seg.kind === "bracket-number") {
|
|
70073
|
-
path13.push({ at: "index", index: seg.index });
|
|
70074
|
-
} else if (seg.kind === "bracket-expr") {
|
|
70075
|
-
path13.push({ at: "index", index: seg.expr });
|
|
70076
|
-
} else {
|
|
70077
|
-
path13.push({ at: "key", key: seg.key });
|
|
70078
|
-
}
|
|
70079
|
-
}
|
|
70080
|
-
return { kind: "read", source, path: path13 };
|
|
70125
|
+
return { kind: "read", source, path: pathFor(source, segments.slice(1)) };
|
|
70081
70126
|
});
|
|
70082
70127
|
}
|
|
70083
70128
|
function readFromForeachItem(name2, chain2) {
|
|
70084
|
-
return wrapOptionalGuards(chain2, (segments) =>
|
|
70085
|
-
|
|
70086
|
-
|
|
70087
|
-
|
|
70088
|
-
// collections matched nothing while the workflow reported success.
|
|
70089
|
-
source: { from: "foreach_item", name: name2 },
|
|
70090
|
-
path: classifyRecordPath(segments)
|
|
70091
|
-
}));
|
|
70129
|
+
return wrapOptionalGuards(chain2, (segments) => {
|
|
70130
|
+
const source = { from: "foreach_item", name: name2 };
|
|
70131
|
+
return { kind: "read", source, path: pathFor(source, segments) };
|
|
70132
|
+
});
|
|
70092
70133
|
}
|
|
70093
70134
|
function readFromLambdaParam(name2, chain2) {
|
|
70094
|
-
return wrapOptionalGuards(chain2, (segments) =>
|
|
70095
|
-
|
|
70096
|
-
|
|
70097
|
-
|
|
70098
|
-
// `find`, `sortBy`), so use the same path classifier as foreach_item:
|
|
70099
|
-
// `x.Field` is a key/field read, `x.LinkedField[0]` collapses to a
|
|
70100
|
-
// `linked` segment. The resolver promotes `at: "key"` → `at: "field"`
|
|
70101
|
-
// when it can infer the param's table from the enclosing helper call.
|
|
70102
|
-
path: classifyRecordPath(segments)
|
|
70103
|
-
}));
|
|
70135
|
+
return wrapOptionalGuards(chain2, (segments) => {
|
|
70136
|
+
const source = { from: "lambda_param", name: name2 };
|
|
70137
|
+
return { kind: "read", source, path: pathFor(source, segments) };
|
|
70138
|
+
});
|
|
70104
70139
|
}
|
|
70105
70140
|
function readFromLexical(name2, chain2) {
|
|
70106
70141
|
return wrapOptionalGuards(chain2, (segments) => {
|
|
70107
|
-
|
|
70108
|
-
|
|
70109
|
-
}
|
|
70110
|
-
return {
|
|
70111
|
-
kind: "read",
|
|
70112
|
-
source: { from: "lexical", name: name2 },
|
|
70113
|
-
path: classifyRecordPath(segments)
|
|
70114
|
-
};
|
|
70142
|
+
const source = { from: "lexical", name: name2 };
|
|
70143
|
+
return { kind: "read", source, path: pathFor(source, segments) };
|
|
70115
70144
|
});
|
|
70116
70145
|
}
|
|
70117
70146
|
function readFromStepOutput(stepId, chain2) {
|
|
70118
70147
|
return wrapOptionalGuards(chain2, (segments) => {
|
|
70119
|
-
const
|
|
70120
|
-
|
|
70121
|
-
if (seg.kind === "bracket-number") {
|
|
70122
|
-
path13.push({ at: "index", index: seg.index });
|
|
70123
|
-
} else if (seg.kind === "bracket-expr") {
|
|
70124
|
-
path13.push({ at: "index", index: seg.expr });
|
|
70125
|
-
} else {
|
|
70126
|
-
path13.push({ at: "key", key: seg.key });
|
|
70127
|
-
}
|
|
70128
|
-
}
|
|
70129
|
-
return { kind: "read", source: { from: "step_output", step_id: stepId }, path: path13 };
|
|
70148
|
+
const source = { from: "step_output", step_id: stepId };
|
|
70149
|
+
return { kind: "read", source, path: pathFor(source, segments) };
|
|
70130
70150
|
});
|
|
70131
70151
|
}
|
|
70132
|
-
|
|
70133
|
-
|
|
70134
|
-
|
|
70135
|
-
|
|
70136
|
-
|
|
70137
|
-
|
|
70138
|
-
|
|
70139
|
-
|
|
70140
|
-
|
|
70141
|
-
|
|
70142
|
-
|
|
70143
|
-
|
|
70144
|
-
|
|
70145
|
-
|
|
70146
|
-
|
|
70147
|
-
|
|
70148
|
-
|
|
70149
|
-
|
|
70150
|
-
|
|
70151
|
-
|
|
70152
|
-
|
|
70153
|
-
|
|
70154
|
-
|
|
70155
|
-
|
|
70156
|
-
|
|
70157
|
-
|
|
70152
|
+
var LINKED_REFUSAL = {
|
|
70153
|
+
trigger_record: null,
|
|
70154
|
+
trigger_record_prev: null,
|
|
70155
|
+
foreach_item: null,
|
|
70156
|
+
lambda_param: null,
|
|
70157
|
+
lexical: null,
|
|
70158
|
+
step_output: null,
|
|
70159
|
+
trigger: LINKED_ON_NON_RECORD,
|
|
70160
|
+
trigger_changes: LINKED_ON_CHANGES,
|
|
70161
|
+
runtime: LINKED_ON_NON_RECORD,
|
|
70162
|
+
foreach_index: LINKED_ON_NON_RECORD
|
|
70163
|
+
};
|
|
70164
|
+
function pathFor(source, segs) {
|
|
70165
|
+
const refusal = LINKED_REFUSAL[source.from];
|
|
70166
|
+
return segs.map((seg) => {
|
|
70167
|
+
switch (seg.kind) {
|
|
70168
|
+
case "bracket-number":
|
|
70169
|
+
return { at: "index", index: seg.index };
|
|
70170
|
+
case "bracket-expr":
|
|
70171
|
+
return { at: "index", index: seg.expr };
|
|
70172
|
+
case "linked":
|
|
70173
|
+
if (refusal !== null) fail(seg.node, refusal, "linked_on_non_record");
|
|
70174
|
+
return { at: "linked", via: seg.via, index: seg.index };
|
|
70175
|
+
case "dot":
|
|
70176
|
+
case "bracket-string":
|
|
70177
|
+
return { at: "key", key: seg.key };
|
|
70158
70178
|
}
|
|
70159
|
-
|
|
70160
|
-
i2 += 1;
|
|
70161
|
-
}
|
|
70162
|
-
return out;
|
|
70179
|
+
});
|
|
70163
70180
|
}
|
|
70164
70181
|
|
|
70165
70182
|
// ../shared/src/parse_workflow_js.ts
|
|
70183
|
+
var LINKED_STATEMENT = `${LINKED_CALL}(...) reads linked rows; it is not a step. Iterate them \u2014 for (const r of ${LINKED_CALL}(record["fld_link"])) { ... } \u2014 or index one: ${LINKED_CALL}(record["fld_link"])[0]["fld_x"].`;
|
|
70184
|
+
var LINKED_AWAIT = `${LINKED_CALL}(...) is grammar, not a tool, and takes no await \u2014 it reads linked rows in place. Write ${LINKED_CALL}(record["fld_link"])[0]["fld_x"], or iterate them: for (const r of ${LINKED_CALL}(record["fld_link"])) { ... }.`;
|
|
70166
70185
|
var MAX_SOURCE_LENGTH = 512 * 1024;
|
|
70167
70186
|
function checkSourceLength(source) {
|
|
70168
70187
|
if (source.length > MAX_SOURCE_LENGTH) {
|
|
@@ -70301,6 +70320,7 @@ function walkStatement(stmt, scope, stepIds, opts, nextSyntheticId, depth) {
|
|
|
70301
70320
|
function walkStatementInner(stmt, scope, stepIds, opts, nextSyntheticId, depth) {
|
|
70302
70321
|
const { id: explicitId, description } = readLeadingComments(stmt);
|
|
70303
70322
|
if (explicitId !== void 0) {
|
|
70323
|
+
assertNotReservedName(stmt, explicitId, `Step id "${explicitId}"`, opts.toolNames);
|
|
70304
70324
|
assertNoFunctionCollision(stmt, explicitId, scope, "Step id");
|
|
70305
70325
|
}
|
|
70306
70326
|
switch (stmt.type) {
|
|
@@ -70422,12 +70442,7 @@ function walkConstDeclarator(decl, scope, stepIds, opts, explicitId, description
|
|
|
70422
70442
|
fail(decl.id, "Bindings must use an identifier or `{ ... }` / `[ ... ]` destructuring.");
|
|
70423
70443
|
}
|
|
70424
70444
|
const id = decl.id.name;
|
|
70425
|
-
|
|
70426
|
-
fail(decl.id, `${id} is reserved.`);
|
|
70427
|
-
}
|
|
70428
|
-
if (opts.toolNames && opts.toolNames.has(id) || isHelper(id)) {
|
|
70429
|
-
fail(decl.id, `Cannot bind to "${id}" \u2014 name collides with a tool or helper.`);
|
|
70430
|
-
}
|
|
70445
|
+
assertNotReservedName(decl.id, id, `Binding "${id}"`, opts.toolNames);
|
|
70431
70446
|
assertNoFunctionCollision(decl.id, id, scope, "Binding");
|
|
70432
70447
|
if (stepIds.has(id)) {
|
|
70433
70448
|
fail(decl.id, `Step id "${id}" is already used.`);
|
|
@@ -70599,12 +70614,7 @@ function walkPatternBinding(decl, scope, stepIds, opts, explicitId, description,
|
|
|
70599
70614
|
makeBase = (segment) => ({ ...rhs, path: [...rhs.path, segment] });
|
|
70600
70615
|
}
|
|
70601
70616
|
for (const entry of walkPatternEntries(pattern, scope)) {
|
|
70602
|
-
|
|
70603
|
-
fail(entry.node, `${entry.name} is reserved.`);
|
|
70604
|
-
}
|
|
70605
|
-
if (opts.toolNames && opts.toolNames.has(entry.name) || isHelper(entry.name)) {
|
|
70606
|
-
fail(entry.node, `Cannot bind to "${entry.name}" \u2014 name collides with a tool or helper.`);
|
|
70607
|
-
}
|
|
70617
|
+
assertNotReservedName(entry.node, entry.name, `Binding "${entry.name}"`, opts.toolNames);
|
|
70608
70618
|
assertNoFunctionCollision(entry.node, entry.name, scope, "Binding");
|
|
70609
70619
|
if (stepIds.has(entry.name)) {
|
|
70610
70620
|
fail(entry.node, `Step id "${entry.name}" is already used.`);
|
|
@@ -70643,12 +70653,7 @@ function walkLetDeclaration(stmt, scope, stepIds, opts, explicitId, description)
|
|
|
70643
70653
|
const frame = scope.lexicalBindings[scope.lexicalBindings.length - 1];
|
|
70644
70654
|
for (const entry of walkPatternEntries(decl.id, scope)) {
|
|
70645
70655
|
const name3 = entry.name;
|
|
70646
|
-
|
|
70647
|
-
fail(entry.node, `${name3} is reserved and cannot be a let binding name.`);
|
|
70648
|
-
}
|
|
70649
|
-
if (opts.toolNames && opts.toolNames.has(name3) || isHelper(name3)) {
|
|
70650
|
-
fail(entry.node, `let binding "${name3}" collides with a tool or helper.`);
|
|
70651
|
-
}
|
|
70656
|
+
assertNotReservedName(entry.node, name3, `let binding "${name3}"`, opts.toolNames);
|
|
70652
70657
|
assertNoFunctionCollision(entry.node, name3, scope, "let binding");
|
|
70653
70658
|
if (stepIds.has(name3)) {
|
|
70654
70659
|
fail(entry.node, `let binding "${name3}" collides with a step id.`);
|
|
@@ -70674,12 +70679,7 @@ function walkLetDeclaration(stmt, scope, stepIds, opts, explicitId, description)
|
|
|
70674
70679
|
fail(decl.id, "let bindings require a plain identifier name.");
|
|
70675
70680
|
}
|
|
70676
70681
|
const name2 = decl.id.name;
|
|
70677
|
-
|
|
70678
|
-
fail(decl.id, `${name2} is reserved and cannot be a let binding name.`);
|
|
70679
|
-
}
|
|
70680
|
-
if (opts.toolNames && opts.toolNames.has(name2) || isHelper(name2)) {
|
|
70681
|
-
fail(decl.id, `let binding "${name2}" collides with a tool or helper.`);
|
|
70682
|
-
}
|
|
70682
|
+
assertNotReservedName(decl.id, name2, `let binding "${name2}"`, opts.toolNames);
|
|
70683
70683
|
assertNoFunctionCollision(decl.id, name2, scope, "let binding");
|
|
70684
70684
|
if (stepIds.has(name2)) {
|
|
70685
70685
|
fail(decl.id, `let binding "${name2}" collides with a step id.`);
|
|
@@ -70726,24 +70726,21 @@ function walkExpressionStatement(stmt, scope, stepIds, opts, stepId, description
|
|
|
70726
70726
|
stepIds.add(stepId);
|
|
70727
70727
|
return walkAgentInvocation(inner, scope, stepId, description);
|
|
70728
70728
|
}
|
|
70729
|
-
|
|
70730
|
-
|
|
70731
|
-
|
|
70732
|
-
|
|
70733
|
-
|
|
70734
|
-
|
|
70735
|
-
|
|
70736
|
-
|
|
70737
|
-
|
|
70738
|
-
|
|
70739
|
-
|
|
70740
|
-
|
|
70741
|
-
|
|
70742
|
-
|
|
70743
|
-
|
|
70744
|
-
};
|
|
70745
|
-
}
|
|
70746
|
-
fail(callee, unknownToolMessage(name2, opts.toolNames) + " Tools must be registered.");
|
|
70729
|
+
const { tool_name, input } = walkToolInvocation(
|
|
70730
|
+
inner,
|
|
70731
|
+
scope,
|
|
70732
|
+
opts,
|
|
70733
|
+
/*allowWaits*/
|
|
70734
|
+
true
|
|
70735
|
+
);
|
|
70736
|
+
stepIds.add(stepId);
|
|
70737
|
+
return {
|
|
70738
|
+
id: stepId,
|
|
70739
|
+
description: description ?? tool_name,
|
|
70740
|
+
type: "tool_call",
|
|
70741
|
+
tool_name,
|
|
70742
|
+
input
|
|
70743
|
+
};
|
|
70747
70744
|
}
|
|
70748
70745
|
if (e.type === "CallExpression" && e.callee.type === "MemberExpression" && !e.callee.computed && e.callee.property.type === "Identifier" && e.callee.property.name === "push") {
|
|
70749
70746
|
return walkPushStatement(e, scope, stepId, description);
|
|
@@ -70767,6 +70764,9 @@ function walkExpressionStatement(stmt, scope, stepIds, opts, stepId, description
|
|
|
70767
70764
|
if (callee.type === "Identifier" && WAIT_TOOLS.has(callee.name)) {
|
|
70768
70765
|
fail(e, `${callee.name} must be awaited: write "await ${callee.name}({...})".`);
|
|
70769
70766
|
}
|
|
70767
|
+
if (callee.type === "Identifier" && callee.name === LINKED_CALL) {
|
|
70768
|
+
fail(e, LINKED_STATEMENT, "linked_statement");
|
|
70769
|
+
}
|
|
70770
70770
|
if (callee.type === "Identifier" && isHelper(callee.name)) {
|
|
70771
70771
|
fail(e, `Helpers may only appear inside expressions, not as standalone statements.`);
|
|
70772
70772
|
}
|
|
@@ -70789,9 +70789,7 @@ function walkAssignmentStatement(e, scope, stepId, description) {
|
|
|
70789
70789
|
fail(e.left, "Assignment targets must be a plain identifier referring to a `let` binding.");
|
|
70790
70790
|
}
|
|
70791
70791
|
const name2 = e.left.name;
|
|
70792
|
-
|
|
70793
|
-
fail(e.left, `${name2} is reserved and cannot be reassigned.`);
|
|
70794
|
-
}
|
|
70792
|
+
assertNotReservedName(e.left, name2, `Assignment target "${name2}"`, scope.toolNames);
|
|
70795
70793
|
if (!findLexicalBinding(scope, name2)) {
|
|
70796
70794
|
fail(e.left, `Cannot assign to "${name2}" \u2014 no enclosing \`let\` declaration in scope.`);
|
|
70797
70795
|
}
|
|
@@ -70824,9 +70822,7 @@ function walkUpdateStatement(e, scope, stepId, description) {
|
|
|
70824
70822
|
fail(e.argument, "Update operators (++/--) require a plain identifier referring to a `let` binding.");
|
|
70825
70823
|
}
|
|
70826
70824
|
const name2 = e.argument.name;
|
|
70827
|
-
|
|
70828
|
-
fail(e.argument, `${name2} is reserved.`);
|
|
70829
|
-
}
|
|
70825
|
+
assertNotReservedName(e.argument, name2, `Update target "${name2}"`, scope.toolNames);
|
|
70830
70826
|
if (!findLexicalBinding(scope, name2)) {
|
|
70831
70827
|
fail(e.argument, `Cannot update "${name2}" \u2014 no enclosing \`let\` declaration in scope.`);
|
|
70832
70828
|
}
|
|
@@ -71002,17 +70998,12 @@ function walkForOf(stmt, scope, stepIds, opts, stepId, description, nextSyntheti
|
|
|
71002
70998
|
} else {
|
|
71003
70999
|
fail(decl.id, "for-of must bind an identifier or a `{ ... }` / `[ ... ]` pattern.");
|
|
71004
71000
|
}
|
|
71005
|
-
|
|
71006
|
-
fail(decl.id, `${bindName} is reserved and cannot be a foreach bind name.`);
|
|
71007
|
-
}
|
|
71001
|
+
assertNotReservedName(decl.id, bindName, `Foreach bind name "${bindName}"`, opts.toolNames);
|
|
71008
71002
|
if (stepIds.has(bindName)) {
|
|
71009
71003
|
fail(decl.id, `Foreach bind name "${bindName}" collides with a step id.`);
|
|
71010
71004
|
}
|
|
71011
|
-
if (opts.toolNames && opts.toolNames.has(bindName) || isHelper(bindName)) {
|
|
71012
|
-
fail(decl.id, `Foreach bind name "${bindName}" collides with a tool or helper.`);
|
|
71013
|
-
}
|
|
71014
71005
|
assertNoFunctionCollision(decl.id, bindName, scope, "Foreach bind name");
|
|
71015
|
-
const items =
|
|
71006
|
+
const items = walkExpression(stmt.right, scope);
|
|
71016
71007
|
const innerScope = {
|
|
71017
71008
|
...scope,
|
|
71018
71009
|
foreachBinds: [...scope.foreachBinds, bindName],
|
|
@@ -71025,12 +71016,7 @@ function walkForOf(stmt, scope, stepIds, opts, stepId, description, nextSyntheti
|
|
|
71025
71016
|
const innerSteps = [];
|
|
71026
71017
|
if (patternEntries) {
|
|
71027
71018
|
for (const entry of patternEntries) {
|
|
71028
|
-
|
|
71029
|
-
fail(entry.node, `${entry.name} is reserved.`);
|
|
71030
|
-
}
|
|
71031
|
-
if (opts.toolNames && opts.toolNames.has(entry.name) || isHelper(entry.name)) {
|
|
71032
|
-
fail(entry.node, `Cannot bind to "${entry.name}" \u2014 name collides with a tool or helper.`);
|
|
71033
|
-
}
|
|
71019
|
+
assertNotReservedName(entry.node, entry.name, `Binding "${entry.name}"`, opts.toolNames);
|
|
71034
71020
|
assertNoFunctionCollision(entry.node, entry.name, scope, "Binding");
|
|
71035
71021
|
if (stepIds.has(entry.name)) {
|
|
71036
71022
|
fail(entry.node, `Step id "${entry.name}" is already used.`);
|
|
@@ -71067,9 +71053,6 @@ function walkForOf(stmt, scope, stepIds, opts, stepId, description, nextSyntheti
|
|
|
71067
71053
|
steps: innerSteps
|
|
71068
71054
|
};
|
|
71069
71055
|
}
|
|
71070
|
-
function walkForOfRight(node, scope) {
|
|
71071
|
-
return walkExpression(node, scope);
|
|
71072
|
-
}
|
|
71073
71056
|
function walkWhile(stmt, scope, stepIds, opts, stepId, description, nextSyntheticId, depth) {
|
|
71074
71057
|
if (stmt.body.type !== "BlockStatement") {
|
|
71075
71058
|
fail(stmt.body, "while body must be a { ... } block.");
|
|
@@ -71212,12 +71195,7 @@ function walkTry(stmt, scope, stepIds, opts, stepId, description, nextSyntheticI
|
|
|
71212
71195
|
fail(handler.param, "Catch parameter must be a plain identifier.");
|
|
71213
71196
|
}
|
|
71214
71197
|
const errorBinding = handler.param.name;
|
|
71215
|
-
|
|
71216
|
-
fail(handler.param, `${errorBinding} is reserved and cannot be a catch binding.`);
|
|
71217
|
-
}
|
|
71218
|
-
if (opts.toolNames && opts.toolNames.has(errorBinding) || isHelper(errorBinding)) {
|
|
71219
|
-
fail(handler.param, `Catch binding "${errorBinding}" collides with a tool or helper.`);
|
|
71220
|
-
}
|
|
71198
|
+
assertNotReservedName(handler.param, errorBinding, `Catch binding "${errorBinding}"`, opts.toolNames);
|
|
71221
71199
|
assertNoFunctionCollision(handler.param, errorBinding, scope, "Catch binding");
|
|
71222
71200
|
if (stepIds.has(errorBinding)) {
|
|
71223
71201
|
fail(handler.param, `Catch binding "${errorBinding}" collides with an existing step id.`);
|
|
@@ -71407,6 +71385,9 @@ function walkToolInvocation(call, scope, opts, allowWaits) {
|
|
|
71407
71385
|
if (allowWaits && WAIT_TOOLS.has(name2)) {
|
|
71408
71386
|
fail(call, `${name2} is a wait step, not a tool. Use "await ${name2}({...})" as a standalone statement.`);
|
|
71409
71387
|
}
|
|
71388
|
+
if (name2 === LINKED_CALL) {
|
|
71389
|
+
fail(call, LINKED_AWAIT, "linked_statement");
|
|
71390
|
+
}
|
|
71410
71391
|
if (opts.toolNames && !opts.toolNames.has(name2)) {
|
|
71411
71392
|
fail(callee, unknownToolMessage(name2, opts.toolNames));
|
|
71412
71393
|
}
|