@dforge-core/metadata 0.0.24 → 0.0.26

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,"sources":["../../src/dsl/lexer.ts","../../src/dsl/parse.ts","../../src/dsl/builtins.ts","../../src/dsl/check.ts"],"sourcesContent":["// Hand-rolled lexer for the dForge action DSL.\n//\n// Deliberately not the tree-sitter grammar: that one exists to be compiled into\n// Zed, and pulling a native parser (or a wasm runtime) into an npx-launched\n// language server — or into a validator that runs before a pack — costs far\n// more than it buys for the handful of constructs the rules need.\n\nexport type TokenKind =\n\t| \"ident\"\n\t| \"number\"\n\t| \"string\"\n\t| \"template\"\n\t| \"regex\"\n\t| \"punct\"\n\t| \"comment\";\n\nexport interface Token {\n\tkind: TokenKind;\n\t/** Source text, verbatim — quotes included for strings. */\n\ttext: string;\n\tstart: number;\n\tend: number;\n\tline: number;\n\tcharacter: number;\n\t/** True when a line break sits between this token and the previous one. */\n\tstartsLine: boolean;\n}\n\nconst PUNCT3 = [\"===\", \"!==\"];\nconst PUNCT2 = [\n\t\"==\", \"!=\", \"<=\", \">=\", \"&&\", \"||\", \"++\", \"--\",\n\t\"+=\", \"-=\", \"*=\", \"/=\", \"%=\", \"${\", \"=>\",\n];\n\n/**\n * Template literals and the `${…}` holes in them. Inside a template we are\n * reading literal text; inside a hole we are reading code again, and the brace\n * count says which `}` closes it.\n */\ntype Frame =\n\t| { kind: \"template\"; chunkStart: number }\n\t| { kind: \"interp\"; braces: number };\n\n/**\n * Keywords whose `(…)` holds a condition rather than a parameter list. What\n * follows that `)` is a statement — so a regex may open there, and the brace\n * after it is not a function body.\n */\nexport const CONTROL_KEYWORDS = new Set([\n\t\"if\",\n\t\"while\",\n\t\"for\",\n\t\"switch\",\n\t\"catch\",\n\t\"with\",\n]);\n\nexport function tokenize(text: string): Token[] {\n\tconst tokens: Token[] = [];\n\tlet i = 0;\n\tlet line = 0;\n\tlet lineStart = 0;\n\tlet pendingLineBreak = true;\n\tconst frames: Frame[] = [];\n\t// Whether each open paren belongs to a control condition, so that the `)`\n\t// closing it is known to be followed by a statement.\n\tconst parenIsControl: boolean[] = [];\n\tlet closedControlParen = false;\n\t// Whether each open brace began a statement block rather than an object,\n\t// so that the `}` closing it is known to leave a statement position.\n\tconst braceIsBlock: boolean[] = [];\n\tlet closedBlockBrace = false;\n\n\tconst push = (kind: TokenKind, start: number, end: number) => {\n\t\ttokens.push({\n\t\t\tkind,\n\t\t\ttext: text.slice(start, end),\n\t\t\tstart,\n\t\t\tend,\n\t\t\tline,\n\t\t\tcharacter: start - lineStart,\n\t\t\tstartsLine: pendingLineBreak,\n\t\t});\n\t\tpendingLineBreak = false;\n\t};\n\n\twhile (i < text.length) {\n\t\tconst frame = frames[frames.length - 1];\n\n\t\t// ── literal text inside a template ──────────────────────────────\n\t\t// Emitted as one token per chunk, so the analyzer sees the code in\n\t\t// `${…}` but never the prose around it. The `${` closes the chunk\n\t\t// before it and the `}` opens the chunk after, which keeps the brace\n\t\t// count of anything reading these tokens balanced.\n\t\tif (frame?.kind === \"template\") {\n\t\t\tconst startLine = line;\n\t\t\tconst startLineStart = lineStart;\n\t\t\twhile (i < text.length) {\n\t\t\t\tconst ch = text[i]!;\n\t\t\t\tif (ch === \"\\\\\") {\n\t\t\t\t\ti += 2;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (ch === \"`\" || (ch === \"$\" && text[i + 1] === \"{\")) break;\n\t\t\t\tif (ch === \"\\n\") {\n\t\t\t\t\tline++;\n\t\t\t\t\tlineStart = i + 1;\n\t\t\t\t}\n\t\t\t\ti++;\n\t\t\t}\n\t\t\tif (text[i] === \"`\") {\n\t\t\t\ti++;\n\t\t\t\tframes.pop();\n\t\t\t} else if (i < text.length) {\n\t\t\t\ti += 2;\n\t\t\t\tframes.push({ kind: \"interp\", braces: 0 });\n\t\t\t} else {\n\t\t\t\tframes.pop(); // unterminated\n\t\t\t}\n\t\t\tconst savedLine = line;\n\t\t\tconst savedLineStart = lineStart;\n\t\t\tline = startLine;\n\t\t\tlineStart = startLineStart;\n\t\t\tpush(\"template\", frame.chunkStart, i);\n\t\t\tline = savedLine;\n\t\t\tlineStart = savedLineStart;\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst c = text[i]!;\n\n\t\t// A leading BOM is not a column. The compiler strips it before anchoring\n\t\t// block headers at `^execute:`, so the first real token must still land\n\t\t// at character 0 here or every block-scoped rule stands down.\n\t\tif (c === \"\\uFEFF\" && i === 0) {\n\t\t\ti++;\n\t\t\tlineStart = i;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (c === \"\\n\") {\n\t\t\ti++;\n\t\t\tline++;\n\t\t\tlineStart = i;\n\t\t\tpendingLineBreak = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (c === \" \" || c === \"\\t\" || c === \"\\r\") {\n\t\t\ti++;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (c === \"/\" && text[i + 1] === \"/\") {\n\t\t\tconst start = i;\n\t\t\twhile (i < text.length && text[i] !== \"\\n\") i++;\n\t\t\tpush(\"comment\", start, i);\n\t\t\tcontinue;\n\t\t}\n\t\tif (c === \"/\" && text[i + 1] === \"*\") {\n\t\t\tconst start = i;\n\t\t\tconst startLine = line;\n\t\t\tconst startLineStart = lineStart;\n\t\t\ti += 2;\n\t\t\twhile (i < text.length && !(text[i] === \"*\" && text[i + 1] === \"/\")) {\n\t\t\t\tif (text[i] === \"\\n\") {\n\t\t\t\t\tline++;\n\t\t\t\t\tlineStart = i + 1;\n\t\t\t\t}\n\t\t\t\ti++;\n\t\t\t}\n\t\t\ti = Math.min(i + 2, text.length);\n\t\t\t// Report the comment at its opening position, not its end.\n\t\t\tconst savedLine = line;\n\t\t\tconst savedLineStart = lineStart;\n\t\t\tline = startLine;\n\t\t\tlineStart = startLineStart;\n\t\t\tpush(\"comment\", start, i);\n\t\t\tline = savedLine;\n\t\t\tlineStart = savedLineStart;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (c === \"'\" || c === '\"') {\n\t\t\tconst start = i;\n\t\t\tconst quote = c;\n\t\t\ti++;\n\t\t\twhile (i < text.length && text[i] !== quote && text[i] !== \"\\n\") {\n\t\t\t\tif (text[i] === \"\\\\\") i++;\n\t\t\t\ti++;\n\t\t\t}\n\t\t\tif (text[i] === quote) i++;\n\t\t\tpush(\"string\", start, i);\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (c === \"`\") {\n\t\t\tframes.push({ kind: \"template\", chunkStart: i });\n\t\t\ti++;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (\n\t\t\tc === \"/\" &&\n\t\t\tregexAllowedAfter(\n\t\t\t\ttokens[tokens.length - 1],\n\t\t\t\tclosedControlParen,\n\t\t\t\tclosedBlockBrace,\n\t\t\t)\n\t\t) {\n\t\t\tconst end = scanRegex(text, i);\n\t\t\tif (end > 0) {\n\t\t\t\tpush(\"regex\", i, end);\n\t\t\t\ti = end;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\tif (/[0-9]/.test(c)) {\n\t\t\tconst start = i;\n\t\t\twhile (i < text.length && /[0-9._eE]/.test(text[i]!)) i++;\n\t\t\tpush(\"number\", start, i);\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (/[A-Za-z_$]/.test(c)) {\n\t\t\tconst start = i;\n\t\t\twhile (i < text.length && /[A-Za-z0-9_$]/.test(text[i]!)) i++;\n\t\t\tpush(\"ident\", start, i);\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (c === \"(\") {\n\t\t\tconst prev = tokens[tokens.length - 1];\n\t\t\tparenIsControl.push(\n\t\t\t\tprev?.kind === \"ident\" && CONTROL_KEYWORDS.has(prev.text),\n\t\t\t);\n\t\t} else if (c === \")\") {\n\t\t\tclosedControlParen = parenIsControl.pop() ?? false;\n\t\t}\n\n\t\tif (frame?.kind === \"interp\") {\n\t\t\tif (c === \"}\" && frame.braces === 0) {\n\t\t\t\tframes.pop();\n\t\t\t\t// The `}` opens the next literal chunk rather than becoming a\n\t\t\t\t// token of its own — see the chunk comment above.\n\t\t\t\t(frames[frames.length - 1] as { chunkStart: number }).chunkStart = i;\n\t\t\t\ti++;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (c === \"{\") frame.braces++;\n\t\t\telse if (c === \"}\") frame.braces--;\n\t\t}\n\n\t\tif (c === \"{\") {\n\t\t\tbraceIsBlock.push(isBlockBrace(tokens[tokens.length - 1]));\n\t\t} else if (c === \"}\") {\n\t\t\tclosedBlockBrace = braceIsBlock.pop() ?? false;\n\t\t}\n\n\t\tconst three = text.slice(i, i + 3);\n\t\tif (PUNCT3.includes(three)) {\n\t\t\tpush(\"punct\", i, i + 3);\n\t\t\ti += 3;\n\t\t\tcontinue;\n\t\t}\n\t\tconst two = text.slice(i, i + 2);\n\t\tif (PUNCT2.includes(two)) {\n\t\t\tpush(\"punct\", i, i + 2);\n\t\t\ti += 2;\n\t\t\tcontinue;\n\t\t}\n\t\tpush(\"punct\", i, i + 1);\n\t\ti++;\n\t}\n\n\treturn tokens;\n}\n\n/**\n * Whether a `/` here opens a regex literal rather than dividing. The usual\n * rule: a regex may start where an expression may start, so it follows an\n * operator or a keyword but not a value.\n *\n * A `)` depends on what it closed: after a control condition a statement\n * follows, so `if (x) /re/.test(s)` is a regex, while `(a + b) / 2` divides.\n * A template chunk likewise depends on which end it is — one that stops at\n * `${` opens an expression, one that ran to the closing backtick is a value.\n *\n * A `}` likewise depends on what it closed: ending a statement block leaves a\n * statement position, so `if (x) {}` may be followed by a regex, while an\n * object literal is a value and divides.\n */\nfunction regexAllowedAfter(\n\tprev: Token | undefined,\n\tclosedControlParen: boolean,\n\tclosedBlockBrace: boolean,\n): boolean {\n\tif (!prev) return true;\n\tif (prev.kind === \"number\" || prev.kind === \"string\") return false;\n\tif (prev.kind === \"template\") return prev.text.endsWith(\"${\");\n\tif (prev.kind === \"ident\") return REGEX_PRECEDING_KEYWORDS.has(prev.text);\n\tif (prev.kind === \"regex\") return false;\n\tif (prev.kind === \"comment\") return true;\n\tif (prev.text === \")\") return closedControlParen;\n\tif (prev.text === \"}\") return closedBlockBrace;\n\treturn !REGEX_BLOCKING_PUNCT.has(prev.text);\n}\n\n/**\n * Whether the `{` after `prev` opens a statement block rather than an object\n * literal. A block follows a condition, another block, a statement end or one\n * of the keywords that take a bare body; anything else — an `=`, a `(`, a `,`,\n * a `=>` — is expression position, where the brace is a value.\n */\nfunction isBlockBrace(prev: Token | undefined): boolean {\n\tif (!prev) return true;\n\tif (prev.kind === \"ident\") return BLOCK_PRECEDING_KEYWORDS.has(prev.text);\n\tif (prev.kind !== \"punct\") return false;\n\treturn prev.text === \")\" || prev.text === \"}\" || prev.text === \"{\" || prev.text === \";\";\n}\n\nconst BLOCK_PRECEDING_KEYWORDS = new Set([\"else\", \"do\", \"try\", \"finally\"]);\n\nconst REGEX_PRECEDING_KEYWORDS = new Set([\n\t\"return\", \"typeof\", \"instanceof\", \"in\", \"of\", \"new\", \"delete\", \"void\",\n\t\"case\", \"do\", \"else\", \"throw\", \"yield\", \"await\",\n]);\n\nconst REGEX_BLOCKING_PUNCT = new Set([\"]\", \"++\", \"--\"]);\n\n/**\n * End offset of the regex literal starting at `start`, or -1 if it is not one.\n * A `/` inside a character class does not close the literal, and a literal\n * never spans a line — hitting one means this was a division after all.\n */\nfunction scanRegex(text: string, start: number): number {\n\tlet i = start + 1;\n\tlet inClass = false;\n\t// An empty pattern would be the `//` comment the caller already handled.\n\tif (text[i] === \"/\" || text[i] === \"*\") return -1;\n\tfor (; i < text.length; i++) {\n\t\tconst c = text[i]!;\n\t\tif (c === \"\\\\\") {\n\t\t\ti++;\n\t\t\tcontinue;\n\t\t}\n\t\tif (c === \"\\n\") return -1;\n\t\tif (c === \"[\") inClass = true;\n\t\telse if (c === \"]\") inClass = false;\n\t\telse if (c === \"/\" && !inClass) {\n\t\t\ti++;\n\t\t\twhile (i < text.length && /[a-z]/.test(text[i]!)) i++;\n\t\t\treturn i;\n\t\t}\n\t}\n\treturn -1;\n}\n\n/** Strip the surrounding quotes from a string token's text. */\nexport function stringValue(token: Token): string {\n\tif (token.kind !== \"string\") return token.text;\n\tconst body = token.text.slice(1, token.text.endsWith(token.text[0]!) && token.text.length > 1 ? -1 : undefined);\n\treturn unescape(body);\n}\n\n/**\n * The literal text of one template chunk, delimiters removed. A chunk opens on\n * a backtick or on the `}` that closed the hole before it, and closes on a\n * backtick, on the `${` of the next hole, or on the end of the file.\n */\nexport function templateChunkValue(token: Token): string {\n\tif (token.kind !== \"template\") return token.text;\n\tconst body = token.text.slice(1);\n\tif (body.endsWith(\"${\")) return unescape(body.slice(0, -2));\n\tif (body.endsWith(\"`\")) return unescape(body.slice(0, -1));\n\treturn unescape(body);\n}\n\n// A switch, not a lookup table: the escaped character comes out of the script,\n// and an object would answer `\\c` from Object.prototype.\nfunction unescape(body: string): string {\n\treturn body.replace(/\\\\(.)/g, (_, ch: string) => {\n\t\tswitch (ch) {\n\t\t\tcase \"n\":\n\t\t\t\treturn \"\\n\";\n\t\t\tcase \"t\":\n\t\t\t\treturn \"\\t\";\n\t\t\tcase \"r\":\n\t\t\t\treturn \"\\r\";\n\t\t\tdefault:\n\t\t\t\treturn ch;\n\t\t}\n\t});\n}\n","// Structural scan of a .dsl file: blocks, param declarations, record-field\n// reads, ref navigation chains and built-in calls — everything the diagnostics,\n// completion, hover and definition features need, and nothing else.\n\nimport {\n\tCONTROL_KEYWORDS,\n\ttype Token,\n\tstringValue,\n\ttemplateChunkValue,\n\ttokenize,\n} from \"./lexer\";\n\n/**\n * In the order `ActionDslCompiler.ParseBlocks` expects them in a file.\n *\n * `BlockKind` derives from this array rather than standing beside it, so the\n * two cannot drift: the order check ranks a kind by its index here, and a kind\n * the array does not list could not have been produced in the first place.\n */\nexport const BLOCK_KINDS = [\n\t\"params\",\n\t\"canExecute\",\n\t\"schema\",\n\t\"onBeforeStart\",\n\t\"execute\",\n] as const;\n\nexport type BlockKind = (typeof BLOCK_KINDS)[number];\n\nconst BLOCK_BY_LOWER = new Map(BLOCK_KINDS.map((k) => [k.toLowerCase(), k]));\n\nexport interface Span {\n\tstart: number;\n\tend: number;\n}\n\nexport interface DslBlock {\n\tkind: BlockKind;\n\tlabel: Span;\n\t/** Span of the block body — label end to the next label (or EOF). */\n\tbody: Span;\n}\n\nexport interface DslParam {\n\tname: string;\n\tnameSpan: Span;\n\t/** fieldTypeCd, or the referenced entity code when `isRef`. */\n\ttype: string;\n\ttypeSpan: Span;\n\tisRef: boolean;\n\trequired: boolean;\n\tlabel?: string;\n}\n\n/**\n * A `[field]` read. `navigation` holds the property hops that follow it, each\n * remembering whether it was written `.[target]` or `.target`: the compiler\n * rewrites the FIRST hop either way, and then only a surviving `.[` is the\n * multi-hop compile error. A dotted tail is plain JavaScript on the value the\n * hop returned, so `[customer].[code]`, `[a].b.c` and `[plate].length` all\n * compile.\n */\nexport interface FieldRef {\n\tname: string;\n\tspan: Span;\n\t/** Span including the brackets. */\n\touterSpan: Span;\n\tnavigation: Array<{ name: string; span: Span; bracketed: boolean }>;\n\tblock: BlockKind | null;\n\t/**\n\t * False when the read is bound to a numbered record rather than the current\n\t * one — `records[0][status]`, which `RxRecordsFieldRead` rewrites ahead of\n\t * the generic `[field]` pass. The name is still a column of the entity, so\n\t * the column rules apply; the batch-mode rule does not.\n\t */\n\tisCurrentRecord: boolean;\n\t/** Index of the token that opens this read — the `[`. */\n\tstartIndex: number;\n\t/**\n\t * Index of the last token this read consumes, navigation included. A hop is\n\t * 2 tokens as `.prop` but 4 as `.[prop]`, so callers that need the token\n\t * after the read cannot compute it from `navigation.length`.\n\t */\n\tendIndex: number;\n}\n\n/** `params[x]` / `old[x]` — subscript reads off a DSL global. */\nexport interface GlobalRef {\n\tglobal: \"params\" | \"old\" | \"records\";\n\tproperty: string;\n\tspan: Span;\n\tblock: BlockKind | null;\n}\n\nexport interface CallRef {\n\tname: string;\n\tnameSpan: Span;\n\t/** First argument when it is a string or template literal — the entity code, usually. */\n\tfirstStringArg?: StringArg;\n\tblock: BlockKind | null;\n}\n\nexport interface StringArg {\n\tvalue: string;\n\tspan: Span;\n\t/**\n\t * A template literal with `${…}` holes, which `value` holds a space in\n\t * place of: literal text to read, but not a constant.\n\t */\n\tinterpolated: boolean;\n\t/** Index of the last token the literal consumes — its final chunk. */\n\tendIndex: number;\n}\n\nexport interface DslDocument {\n\tblocks: DslBlock[];\n\tparams: DslParam[];\n\tfieldRefs: FieldRef[];\n\tglobalRefs: GlobalRef[];\n\tcalls: CallRef[];\n\ttokens: Token[];\n\t/**\n\t * Every mention of `records`, subscript (`records[x]`) or bare\n\t * (`for x in records`). `globalRefs` only holds the subscript form, so a\n\t * rule that needs to point at the batch loop has nothing to anchor to.\n\t */\n\trecordsRefs: Span[];\n\t/** Names bound by `var`/`let`/`const` or a `for` head, plus declared params. */\n\tlocals: Set<string>;\n\t/**\n\t * Loop variables bound by `for x in records {` — `RxForLoop` and nothing\n\t * else, so an ordinary `for (var x of xs)` is not one. Their `x[field]`\n\t * subscripts read the entity's columns, which is why they come back as\n\t * field reads.\n\t */\n\trecordsLoopVars: Set<string>;\n}\n\nconst GLOBALS = new Set([\"params\", \"old\", \"records\"]);\n\nexport function parseDsl(text: string): DslDocument {\n\tconst all = tokenize(text);\n\tconst tokens = all.filter((t) => t.kind !== \"comment\");\n\n\tconst blocks = findBlocks(text, tokens);\n\tconst blockAt = (offset: number): BlockKind | null =>\n\t\tblocks.find((b) => offset >= b.body.start && offset < b.body.end)?.kind ??\n\t\tnull;\n\n\tconst params = parseParams(tokens, blocks);\n\tconst fieldRefs: FieldRef[] = [];\n\tconst globalRefs: GlobalRef[] = [];\n\tconst calls: CallRef[] = [];\n\tconst recordsRefs: Span[] = [];\n\tconst locals = collectLocals(tokens, params);\n\tconst recordsLoopVars = collectRecordsLoopVars(tokens);\n\n\tfor (let i = 0; i < tokens.length; i++) {\n\t\tconst t = tokens[i]!;\n\n\t\tif (t.kind === \"punct\" && t.text === \"[\" && isFieldAccessStart(text, t.start)) {\n\t\t\tconst name = tokens[i + 1];\n\t\t\tconst close = tokens[i + 2];\n\t\t\tif (name?.kind === \"ident\" && close?.text === \"]\") {\n\t\t\t\tconst ref: FieldRef = {\n\t\t\t\t\tname: name.text,\n\t\t\t\t\tspan: { start: name.start, end: name.end },\n\t\t\t\t\touterSpan: { start: t.start, end: close.end },\n\t\t\t\t\tnavigation: [],\n\t\t\t\t\tblock: blockAt(t.start),\n\t\t\t\t\tisCurrentRecord: true,\n\t\t\t\t\tstartIndex: i,\n\t\t\t\t\tendIndex: i + 2,\n\t\t\t\t};\n\t\t\t\tref.endIndex = collectNavigation(tokens, i + 2, ref);\n\t\t\t\ti = ref.endIndex;\n\t\t\t\tfieldRefs.push(ref);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\t// `x.records` is a property, not the batch global.\n\t\tif (t.kind === \"ident\" && t.text === \"records\" && tokens[i - 1]?.text !== \".\") {\n\t\t\trecordsRefs.push({ start: t.start, end: t.end });\n\n\t\t\t// `records[0][status]` is one read of a numbered record. Taken\n\t\t\t// apart, its tail looks exactly like a current-record read — which\n\t\t\t// is why the compiler rewrites this form first.\n\t\t\tconst field = indexedRecordField(tokens, i);\n\t\t\tif (field) {\n\t\t\t\tfieldRefs.push({\n\t\t\t\t\tname: field.name.text,\n\t\t\t\t\tspan: { start: field.name.start, end: field.name.end },\n\t\t\t\t\touterSpan: { start: field.open.start, end: field.close.end },\n\t\t\t\t\tnavigation: [],\n\t\t\t\t\tblock: blockAt(t.start),\n\t\t\t\t\tisCurrentRecord: false,\n\t\t\t\t\tstartIndex: field.openIndex,\n\t\t\t\t\tendIndex: field.openIndex + 2,\n\t\t\t\t});\n\t\t\t\ti = field.openIndex + 2;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\t// `x[field]` on a batch loop variable. The compiler rewrites it to\n\t\t// `x.get('field')` and checks the name against the entity's columns\n\t\t// exactly as it checks a bare `[field]`.\n\t\tif (t.kind === \"ident\" && recordsLoopVars.has(t.text)) {\n\t\t\tconst open = tokens[i + 1];\n\t\t\tconst name = tokens[i + 2];\n\t\t\tconst close = tokens[i + 3];\n\t\t\tif (open?.text === \"[\" && name?.kind === \"ident\" && close?.text === \"]\") {\n\t\t\t\tfieldRefs.push({\n\t\t\t\t\tname: name.text,\n\t\t\t\t\tspan: { start: name.start, end: name.end },\n\t\t\t\t\touterSpan: { start: open.start, end: close.end },\n\t\t\t\t\tnavigation: [],\n\t\t\t\t\tblock: blockAt(t.start),\n\t\t\t\t\tisCurrentRecord: false,\n\t\t\t\t\tstartIndex: i + 1,\n\t\t\t\t\tendIndex: i + 3,\n\t\t\t\t});\n\t\t\t\ti += 3;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\tif (t.kind === \"ident\" && GLOBALS.has(t.text)) {\n\t\t\tconst open = tokens[i + 1];\n\t\t\tconst prop = tokens[i + 2];\n\t\t\tconst close = tokens[i + 3];\n\t\t\tif (open?.text === \"[\" && prop?.kind === \"ident\" && close?.text === \"]\") {\n\t\t\t\tglobalRefs.push({\n\t\t\t\t\tglobal: t.text as GlobalRef[\"global\"],\n\t\t\t\t\tproperty: prop.text,\n\t\t\t\t\tspan: { start: prop.start, end: prop.end },\n\t\t\t\t\tblock: blockAt(t.start),\n\t\t\t\t});\n\t\t\t\ti += 3;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\tif (t.kind === \"ident\" && tokens[i + 1]?.text === \"(\") {\n\t\t\tconst prev = tokens[i - 1];\n\t\t\t// `.method(` is a call on a value, not a DSL built-in.\n\t\t\tif (prev?.text === \".\") continue;\n\t\t\tconst call: CallRef = {\n\t\t\t\tname: t.text,\n\t\t\t\tnameSpan: { start: t.start, end: t.end },\n\t\t\t\tblock: blockAt(t.start),\n\t\t\t};\n\t\t\tconst firstArg = tokens[i + 2];\n\t\t\tif (firstArg?.kind === \"string\") {\n\t\t\t\tcall.firstStringArg = {\n\t\t\t\t\tvalue: stringValue(firstArg),\n\t\t\t\t\tspan: { start: firstArg.start, end: firstArg.end },\n\t\t\t\t\tinterpolated: false,\n\t\t\t\t\tendIndex: i + 2,\n\t\t\t\t};\n\t\t\t} else if (firstArg?.kind === \"template\" && firstArg.text.startsWith(\"`\")) {\n\t\t\t\tcall.firstStringArg = templateArg(tokens, i + 2);\n\t\t\t}\n\t\t\tcalls.push(call);\n\t\t}\n\t}\n\n\treturn {\n\t\tblocks,\n\t\tparams,\n\t\tfieldRefs,\n\t\tglobalRefs,\n\t\tcalls,\n\t\ttokens,\n\t\trecordsRefs,\n\t\tlocals,\n\t\trecordsLoopVars,\n\t};\n}\n\n/**\n * `[` opens a record-field read unless a word character sits immediately\n * before it — the compiler's `(?<!\\w)\\[(\\w+)\\]`, character for character.\n *\n * It has to be the character and not the previous token: the lookbehind does\n * not skip whitespace, so `rec[qty]` is a subscript but `[qty]` opening a line\n * is a read however the line above ended. The same lookbehind is what keeps\n * `params[x]` and `old[x]` out of the field reads.\n *\n * A single-element array literal (`var ids = [orderId]`) is genuinely\n * ambiguous with a field read at this level: both are `[ident]` in expression\n * position, and `var total = [qty]` is a real field read. The disambiguation\n * needs to know whether the name is a column or a local, so it happens in the\n * diagnostics layer against `locals` rather than here.\n */\nfunction isFieldAccessStart(text: string, start: number): boolean {\n\treturn start === 0 || !/\\w/.test(text[start - 1]!);\n}\n\n/**\n * A template literal, read back from the chunks the lexer split it into. The\n * walk has to count nested templates, because one opened inside a `${…}` hole\n * emits chunks of its own between ours.\n *\n * Each hole becomes a single space. The callers read the text as SQL, and a\n * spliced value is not part of the statement they are reading — but the gap\n * has to stay a gap, or the words either side of it would run together.\n */\nfunction templateArg(tokens: Token[], start: number): StringArg {\n\tconst parts: string[] = [];\n\tlet depth = 0;\n\tlet interpolated = false;\n\tlet last = tokens[start]!;\n\tlet endIndex = start;\n\n\tfor (let j = start; j < tokens.length; j++) {\n\t\tconst t = tokens[j]!;\n\t\tif (t.kind !== \"template\") continue;\n\n\t\tconst opens = t.text.startsWith(\"`\");\n\t\tif (opens) depth++;\n\t\tif (depth === 1) {\n\t\t\tif (!opens) parts.push(\" \");\n\t\t\tparts.push(templateChunkValue(t));\n\t\t\tlast = t;\n\t\t\tendIndex = j;\n\t\t}\n\t\tif (t.text.endsWith(\"${\")) {\n\t\t\tif (depth === 1) interpolated = true;\n\t\t\tcontinue;\n\t\t}\n\t\t// Anything else ends the template: a closing backtick, or the end of\n\t\t// the file on an unterminated one.\n\t\tdepth--;\n\t\tif (depth === 0) break;\n\t}\n\n\treturn {\n\t\tvalue: parts.join(\"\"),\n\t\tspan: { start: tokens[start]!.start, end: last.end },\n\t\tinterpolated,\n\t\tendIndex,\n\t};\n}\n\n\n/**\n * The `[field]` half of a `records[n][field]` read starting at `i`, or null.\n *\n * Mirrors `RxRecordsFieldRead`'s `\\brecords\\[(\\d+)\\]\\[(\\w+)\\]`: a literal\n * digit index only. `records[i][x]` with a variable index is not this form for\n * the compiler either — it leaves `records[i]` alone and then rewrites the tail\n * as a current-record read.\n */\nfunction indexedRecordField(\n\ttokens: Token[],\n\ti: number,\n): { name: Token; open: Token; close: Token; openIndex: number } | null {\n\tconst index = tokens[i + 2];\n\tif (tokens[i + 1]?.text !== \"[\") return null;\n\tif (index?.kind !== \"number\" || !/^\\d+$/.test(index.text)) return null;\n\tif (tokens[i + 3]?.text !== \"]\") return null;\n\n\tconst open = tokens[i + 4];\n\tconst name = tokens[i + 5];\n\tconst close = tokens[i + 6];\n\tif (open?.text !== \"[\" || name?.kind !== \"ident\" || close?.text !== \"]\")\n\t\treturn null;\n\treturn { name, open, close, openIndex: i + 4 };\n}\n\n/** Walk `.prop` / `.[prop]` hops after a field read. Returns the last index consumed. */\nfunction collectNavigation(tokens: Token[], closeIdx: number, ref: FieldRef): number {\n\tlet i = closeIdx;\n\tfor (;;) {\n\t\tconst dot = tokens[i + 1];\n\t\tif (dot?.text !== \".\") return i;\n\t\tconst next = tokens[i + 2];\n\t\tif (next?.kind === \"ident\") {\n\t\t\t// A method call is not navigation — `[items].length` is, `[x].trim()` isn't.\n\t\t\tif (tokens[i + 3]?.text === \"(\") return i;\n\t\t\tref.navigation.push({\n\t\t\t\tname: next.text,\n\t\t\t\tspan: { start: next.start, end: next.end },\n\t\t\t\tbracketed: false,\n\t\t\t});\n\t\t\ti += 2;\n\t\t\tcontinue;\n\t\t}\n\t\tif (next?.text === \"[\") {\n\t\t\tconst name = tokens[i + 3];\n\t\t\tconst close = tokens[i + 4];\n\t\t\tif (name?.kind === \"ident\" && close?.text === \"]\") {\n\t\t\t\tref.navigation.push({\n\t\t\t\t\tname: name.text,\n\t\t\t\t\tspan: { start: name.start, end: name.end },\n\t\t\t\t\tbracketed: true,\n\t\t\t\t});\n\t\t\t\ti += 4;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\t\treturn i;\n\t}\n}\n\n/**\n * `for x in records {` — `RxForLoop`'s shape, brace included. A loop written\n * any other way is not a batch loop to the compiler either, and its variable\n * does not carry record fields.\n */\nfunction collectRecordsLoopVars(tokens: Token[]): Set<string> {\n\tconst vars = new Set<string>();\n\tfor (let i = 0; i < tokens.length - 4; i++) {\n\t\tif (tokens[i]!.text !== \"for\" || tokens[i]!.kind !== \"ident\") continue;\n\t\tconst name = tokens[i + 1]!;\n\t\tif (name.kind !== \"ident\") continue;\n\t\tif (tokens[i + 2]!.text !== \"in\" || tokens[i + 3]!.text !== \"records\") continue;\n\t\tif (tokens[i + 4]!.text !== \"{\") continue;\n\t\tvars.add(name.text);\n\t}\n\treturn vars;\n}\n\nconst DECLARATORS = new Set([\"var\", \"let\", \"const\"]);\n\n/**\n * Names bound in the script itself. Used to tell `var ids = [orderId]` (an\n * array literal holding a local) from `[qty]` (a record-field read) — the two\n * are indistinguishable by token shape alone.\n */\nfunction collectLocals(tokens: Token[], params: DslParam[]): Set<string> {\n\tconst locals = new Set<string>(params.map((p) => p.name));\n\tcollectFunctionParams(tokens, locals);\n\tfor (let i = 0; i < tokens.length; i++) {\n\t\tconst t = tokens[i]!;\n\t\tif (t.kind !== \"ident\") continue;\n\n\t\tif (DECLARATORS.has(t.text)) {\n\t\t\tcollectDeclarations(tokens, i + 1, locals);\n\t\t\tcontinue;\n\t\t}\n\n\t\t// `for x in records` / `for (var x of xs)` — the loop variable.\n\t\tif (t.text === \"for\") {\n\t\t\tlet j = i + 1;\n\t\t\tif (tokens[j]?.text === \"(\") j++;\n\t\t\tif (tokens[j]?.kind === \"ident\" && DECLARATORS.has(tokens[j]!.text)) j++;\n\t\t\tconst name = tokens[j];\n\t\t\tif (name?.kind === \"ident\" && !DECLARATORS.has(name.text)) locals.add(name.text);\n\t\t}\n\t}\n\treturn locals;\n}\n\n/**\n * Parameter names of every function in the script — declarations, expressions,\n * arrows and method shorthand. They bind names exactly as `var` does, so\n * `function wrap(value) { return [value] }` holds an array literal rather than\n * a field read.\n */\nfunction collectFunctionParams(tokens: Token[], locals: Set<string>): void {\n\tfor (let i = 0; i < tokens.length; i++) {\n\t\tconst t = tokens[i]!;\n\n\t\tif (t.kind === \"ident\" && t.text === \"function\") {\n\t\t\tlet j = i + 1;\n\t\t\tif (tokens[j]?.kind === \"ident\") j++; // the name, when it has one\n\t\t\tif (tokens[j]?.text === \"(\") collectParenIdents(tokens, j, locals);\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (t.text === \"=>\") {\n\t\t\tconst prev = tokens[i - 1];\n\t\t\t// `x => …` binds one name; `(x, y) => …` binds the list.\n\t\t\tif (prev?.kind === \"ident\") locals.add(prev.text);\n\t\t\telse if (prev?.text === \")\") {\n\t\t\t\tconst open = matchingOpenParen(tokens, i - 1);\n\t\t\t\tif (open >= 0) collectParenIdents(tokens, open, locals);\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Method shorthand `f(a, b) { … }`. The body brace is what tells it from\n\t\t// a call, and a control keyword's `(…)` is a condition, not a list.\n\t\tif (\n\t\t\tt.kind === \"ident\" &&\n\t\t\t!CONTROL_KEYWORDS.has(t.text) &&\n\t\t\ttokens[i + 1]?.text === \"(\"\n\t\t) {\n\t\t\tconst close = matchingCloseParen(tokens, i + 1);\n\t\t\tif (close >= 0 && tokens[close + 1]?.text === \"{\")\n\t\t\t\tcollectParenIdents(tokens, i + 1, locals);\n\t\t}\n\t}\n}\n\n/**\n * Every ident between the `(` at `openIndex` and its match. Over-collects a\n * default value's names (`f(x = y)`), which only ever suppresses a diagnostic —\n * the same fail-open trade `collectPattern` makes.\n */\nfunction collectParenIdents(\n\ttokens: Token[],\n\topenIndex: number,\n\tlocals: Set<string>,\n): void {\n\tlet depth = 0;\n\tfor (let i = openIndex; i < tokens.length; i++) {\n\t\tconst t = tokens[i]!;\n\t\tif (t.text === \"(\") depth++;\n\t\telse if (t.text === \")\") {\n\t\t\tdepth--;\n\t\t\tif (depth === 0) return;\n\t\t} else if (t.kind === \"ident\") locals.add(t.text);\n\t}\n}\n\nfunction matchingCloseParen(tokens: Token[], openIndex: number): number {\n\tlet depth = 0;\n\tfor (let i = openIndex; i < tokens.length; i++) {\n\t\tif (tokens[i]!.text === \"(\") depth++;\n\t\telse if (tokens[i]!.text === \")\" && --depth === 0) return i;\n\t}\n\treturn -1;\n}\n\nfunction matchingOpenParen(tokens: Token[], closeIndex: number): number {\n\tlet depth = 0;\n\tfor (let i = closeIndex; i >= 0; i--) {\n\t\tif (tokens[i]!.text === \")\") depth++;\n\t\telse if (tokens[i]!.text === \"(\" && --depth === 0) return i;\n\t}\n\treturn -1;\n}\n\n/**\n * The binding list after a declarator: `a = 1, b = 2`, where each binding is\n * either a name or a destructuring pattern. Scans ahead without moving the\n * caller's cursor, so a `var` nested in an initializer is still visited.\n */\nfunction collectDeclarations(tokens: Token[], start: number, locals: Set<string>): void {\n\tlet j = start;\n\tfor (;;) {\n\t\tconst head = tokens[j];\n\t\tif (!head) return;\n\n\t\tif (head.text === \"{\" || head.text === \"[\") {\n\t\t\tj = collectPattern(tokens, j, locals);\n\t\t} else if (head.kind === \"ident\" && !DECLARATORS.has(head.text)) {\n\t\t\tlocals.add(head.text);\n\t\t\tj++;\n\t\t} else return;\n\n\t\t// Skip this binding's initializer and stop at the comma opening the\n\t\t// next one. Commas inside the initializer sit at depth 1+ (`f(x, y)`),\n\t\t// which is what keeps its arguments out of `locals`.\n\t\tlet depth = 0;\n\t\tfor (; j < tokens.length; j++) {\n\t\t\tconst n = tokens[j]!;\n\t\t\tif (n.text === \"(\" || n.text === \"[\" || n.text === \"{\") depth++;\n\t\t\telse if (n.text === \")\" || n.text === \"]\" || n.text === \"}\") depth--;\n\t\t\tif (depth < 0) return;\n\t\t\tif (depth > 0) continue;\n\t\t\tif (n.text === \";\") return;\n\t\t\tif (n.text === \",\") break;\n\t\t\t// A new line at depth 0 ends the statement; the alternative is\n\t\t\t// running to end-of-file on a declaration with no terminator.\n\t\t\tif (n.startsLine) return;\n\t\t}\n\t\tif (j >= tokens.length) return;\n\t\tj++;\n\t}\n}\n\n/**\n * Every ident inside a `{…}` / `[…]` binding pattern; returns the index after\n * it. The names of a pattern sit at depth 1+, out of reach of the comma rule\n * in `collectDeclarations`. This over-collects — the `a` of `{ a: b }` binds\n * nothing — but a name in `locals` only ever suppresses a diagnostic, so the\n * error is in the fail-open direction.\n */\nfunction collectPattern(tokens: Token[], start: number, locals: Set<string>): number {\n\tlet depth = 0;\n\tlet i = start;\n\tfor (; i < tokens.length; i++) {\n\t\tconst t = tokens[i]!;\n\t\tif (t.text === \"{\" || t.text === \"[\") depth++;\n\t\telse if (t.text === \"}\" || t.text === \"]\") {\n\t\t\tdepth--;\n\t\t\tif (depth === 0) return i + 1;\n\t\t} else if (t.kind === \"ident\") locals.add(t.text);\n\t}\n\treturn i;\n}\n\n/**\n * The block kind labelled at `i`, wherever on the line it sits.\n *\n * `findBlocks` additionally requires column 0, which is what the compiler's\n * `^execute:` anchor means. The un-anchored form exists for the diagnostic\n * that reports an indented header — body text as far as the compiler is\n * concerned, leaving the block it meant to open empty.\n */\nexport function blockLabelAt(\n\ttokens: Token[],\n\ti: number,\n): { kind: BlockKind; span: Span } | null {\n\tconst t = tokens[i];\n\tif (!t || t.kind !== \"ident\" || !t.startsLine) return null;\n\tconst colon = tokens[i + 1];\n\t// `params :` does not match `^params:` either.\n\tif (colon?.text !== \":\" || colon.start !== t.end) return null;\n\tconst kind = BLOCK_BY_LOWER.get(t.text.toLowerCase());\n\treturn kind ? { kind, span: { start: t.start, end: colon.end } } : null;\n}\n\nfunction findBlocks(text: string, tokens: Token[]): DslBlock[] {\n\tconst labels: Array<{ kind: BlockKind; span: Span }> = [];\n\tfor (let i = 0; i < tokens.length; i++) {\n\t\tconst t = tokens[i]!;\n\t\t// Column 0, like the compiler's `^`-anchored headers: an indented\n\t\t// `params:` is an object key inside a block body, not a new block.\n\t\tif (t.character !== 0) continue;\n\t\tconst label = blockLabelAt(tokens, i);\n\t\tif (!label) continue;\n\t\tlabels.push(label);\n\t\t// `execute:` is `(.*?)\\z` — it runs to end-of-file, so a later header\n\t\t// is body text.\n\t\tif (label.kind === \"execute\") break;\n\t}\n\n\treturn labels.map((l, idx) => ({\n\t\tkind: l.kind,\n\t\tlabel: l.span,\n\t\tbody: {\n\t\t\tstart: l.span.end,\n\t\t\tend: labels[idx + 1]?.span.start ?? text.length,\n\t\t},\n\t}));\n}\n\nfunction parseParams(tokens: Token[], blocks: DslBlock[]): DslParam[] {\n\tconst block = blocks.find((b) => b.kind === \"params\");\n\tif (!block) return [];\n\n\tconst inBlock = tokens.filter(\n\t\t(t) => t.start >= block.body.start && t.start < block.body.end,\n\t);\n\tconst params: DslParam[] = [];\n\n\tfor (let i = 0; i < inBlock.length; i++) {\n\t\tconst name = inBlock[i]!;\n\t\t// One declaration per line — and `^params:\\s*` swallows the newline, so\n\t\t// the header's own line counts: `params: qty: number required` declares\n\t\t// qty exactly as an indented line below would.\n\t\tif ((!name.startsLine && i !== 0) || name.kind !== \"ident\") continue;\n\t\tif (inBlock[i + 1]?.text !== \":\") continue;\n\n\t\tlet j = i + 2;\n\t\tlet isRef = false;\n\t\tif (inBlock[j]?.kind === \"ident\" && inBlock[j]!.text === \"ref\") {\n\t\t\tisRef = true;\n\t\t\tj++;\n\t\t}\n\t\tconst type = inBlock[j];\n\t\tif (!type || type.kind !== \"ident\") continue;\n\t\t// RxParamDecl matches one trimmed line, so the type shares the name's\n\t\t// line. Without this a bare `execute:` swallows the next line's first\n\t\t// word as its type and passes for a declaration.\n\t\tif (type.line !== name.line) continue;\n\n\t\t// A `ref` target may be qualified and hyphenated: `ref fin-ch.invoice`.\n\t\t// The lexer splits on `-` and `.`, so glue back any pieces that are\n\t\t// physically adjacent — a space means the name ended.\n\t\tlet typeEnd = type.end;\n\t\tlet typeText = type.text;\n\t\tif (isRef) {\n\t\t\twhile (\n\t\t\t\tinBlock[j + 1] &&\n\t\t\t\t(inBlock[j + 1]!.text === \"-\" || inBlock[j + 1]!.text === \".\") &&\n\t\t\t\tinBlock[j + 2]?.kind === \"ident\" &&\n\t\t\t\tinBlock[j + 1]!.start === typeEnd &&\n\t\t\t\tinBlock[j + 2]!.start === inBlock[j + 1]!.end\n\t\t\t) {\n\t\t\t\ttypeText += inBlock[j + 1]!.text + inBlock[j + 2]!.text;\n\t\t\t\ttypeEnd = inBlock[j + 2]!.end;\n\t\t\t\tj += 2;\n\t\t\t}\n\t\t}\n\n\t\tlet required = false;\n\t\tlet label: string | undefined;\n\t\tfor (let k = j + 1; k < inBlock.length && !inBlock[k]!.startsLine; k++) {\n\t\t\tconst t = inBlock[k]!;\n\t\t\tif (t.kind === \"ident\" && t.text === \"required\") required = true;\n\t\t\tif (t.kind === \"string\" && label === undefined) label = stringValue(t);\n\t\t}\n\n\t\tparams.push({\n\t\t\tname: name.text,\n\t\t\tnameSpan: { start: name.start, end: name.end },\n\t\t\ttype: typeText,\n\t\t\ttypeSpan: { start: type.start, end: typeEnd },\n\t\t\tisRef,\n\t\t\trequired,\n\t\t\tlabel,\n\t\t});\n\t}\n\n\treturn params;\n}\n","// The DSL's platform globals. Signatures and prose track\n// dforge-mcp/skills/dforge-mcp-author/references/action-dsl.md — that file is\n// the source of truth; re-sync when it changes.\n\nexport interface Builtin {\n\tname: string;\n\tsignature: string;\n\treturns: string;\n\tdoc: string;\n\t/**\n\t * Index of the argument that names an entity, when the built-in takes one.\n\t * Drives entity-code completion and the qualify-your-codes diagnostic.\n\t */\n\tentityArg?: number;\n}\n\nexport const BUILTINS: Builtin[] = [\n\t// Data operations\n\t{\n\t\tname: \"insert\",\n\t\tsignature: \"insert(entity, fields)\",\n\t\treturns: \"object\",\n\t\tentityArg: 0,\n\t\tdoc: \"Insert a new record. Returns the full row including auto-filled columns (PK, audit, number sequences).\",\n\t},\n\t{\n\t\tname: \"select\",\n\t\tsignature: \"select(entity, opts?)\",\n\t\treturns: \"object[]\",\n\t\tentityArg: 0,\n\t\tdoc: \"Structured multi-row read. `opts` = `{columns, filter, orderBy, limit, offset}`. Prefer over `query()` for row-shaped reads.\",\n\t},\n\t{\n\t\tname: \"update\",\n\t\tsignature: \"update(entity, key, fields)\",\n\t\treturns: \"number\",\n\t\tentityArg: 0,\n\t\tdoc: \"Update the row(s) matched by `key`; returns rows affected. A value may be `{ inc: n }` to add to the column's current value — use that for every counter, balance and quantity.\",\n\t},\n\t{\n\t\tname: \"delete\",\n\t\tsignature: \"delete(entity, key)\",\n\t\treturns: \"number\",\n\t\tentityArg: 0,\n\t\tdoc: \"Delete the row(s) matched by `key`; returns rows affected.\",\n\t},\n\t{\n\t\tname: \"query\",\n\t\tsignature: \"query(sql, args?)\",\n\t\treturns: \"object[]\",\n\t\tdoc: \"Execute parameterized SQL with `@argName` placeholders and schema-qualified table names. Escape hatch — prefer `select()` / `update()` / `delete()` when the structured shape fits.\",\n\t},\n\t{\n\t\tname: \"getRecord\",\n\t\tsignature: \"getRecord(entity, key)\",\n\t\treturns: \"object\",\n\t\tentityArg: 0,\n\t\tdoc: \"Fetch a single record by key. **Throws** a localized not-found error when absent.\",\n\t},\n\t{\n\t\tname: \"getRecordOrNull\",\n\t\tsignature: \"getRecordOrNull(entity, key)\",\n\t\treturns: \"object | null\",\n\t\tentityArg: 0,\n\t\tdoc: \"Like `getRecord`, but returns `null` instead of throwing — for an expected absence, guarded with `if (rec == null)`.\",\n\t},\n\t{\n\t\tname: \"preloadRef\",\n\t\tsignature: \"preloadRef(fkColumn)\",\n\t\treturns: \"object\",\n\t\tdoc: \"Load the referenced record for a FK column. Read its fields with `ref.get('field')`.\",\n\t},\n\n\t// Messaging\n\t{\n\t\tname: \"error\",\n\t\tsignature: \"error(message)\",\n\t\treturns: \"never\",\n\t\tdoc: \"Abort the action and show an error. Rolls back all changes.\",\n\t},\n\t{ name: \"warn\", signature: \"warn(message)\", returns: \"void\", doc: \"Show a warning and continue.\" },\n\t{\n\t\tname: \"info\",\n\t\tsignature: \"info(message)\",\n\t\treturns: \"void\",\n\t\tdoc: \"Show an informational message — a receipt for work the action did, not a way to publish a computed value.\",\n\t},\n\t{\n\t\tname: \"exit\",\n\t\tsignature: \"exit(message?, level?)\",\n\t\treturns: \"never\",\n\t\tdoc: \"Stop the script early **without** error, keeping changes made so far. Level `'info'` (default) or `'warn'`. This is the DSL's early return — the block compiles to a bare script, so a `return` outside a function is a syntax error wherever it sits.\",\n\t},\n\t{\n\t\tname: \"notify\",\n\t\tsignature: \"notify(userId, message)\",\n\t\treturns: \"void\",\n\t\tdoc: \"Send an in-app notification to a specific user.\",\n\t},\n\t{\n\t\tname: \"sendEmail\",\n\t\tsignature: \"sendEmail(to, subjectOrTemplate, dataOrBody?)\",\n\t\treturns: \"void\",\n\t\tdoc: \"Queue an outbound email. Three arguments, and the **second** picks the mode: `sendEmail(to, 'order.shipped', { ref: [code] })` sends a template, `sendEmail(to, 'Your order shipped', '<p>…</p>')` sends raw HTML. A second argument with no spaces that contains `.` or `_` is read as a template code — so a raw subject like `'Shipped.'` silently becomes one; give a raw subject spaces. There is no fourth argument.\",\n\t},\n\n\t// External calls\n\t{\n\t\tname: \"callApi\",\n\t\tsignature: \"callApi(url, method, headers?, body?)\",\n\t\treturns: \"string\",\n\t\tdoc: \"HTTP request to an external API; returns the body as a string. Max 10 calls per script, 120s timeout, 5MB response.\",\n\t},\n\t{\n\t\tname: \"callService\",\n\t\tsignature: \"callService(name, args)\",\n\t\treturns: \"any\",\n\t\tdoc: \"Invoke a registered host service.\",\n\t},\n\t{\n\t\tname: \"callProc\",\n\t\tsignature: \"callProc(procName, args)\",\n\t\treturns: \"any\",\n\t\tdoc: \"Call a stored procedure with named parameters.\",\n\t},\n\n\t// Files, settings, extraction\n\t{\n\t\tname: \"getFileBase64\",\n\t\tsignature: \"getFileBase64(fileField)\",\n\t\treturns: \"string\",\n\t\tdoc: \"Read a file from storage as base64. Use with `callApi()` to send files to external APIs. Max 10 MB.\",\n\t},\n\t{\n\t\tname: \"getFileUrl\",\n\t\tsignature: \"getFileUrl(fileField)\",\n\t\treturns: \"string\",\n\t\tdoc: \"Temporary signed download URL (relative path) for a file field — for emails and notifications, not for `callApi()`.\",\n\t},\n\t{ name: \"getFileInfo\", signature: \"getFileInfo(fileField)\", returns: \"object | null\", doc: \"File metadata for a file field.\" },\n\t{\n\t\tname: \"download\",\n\t\tsignature: \"download(url, fileName?)\",\n\t\treturns: \"void\",\n\t\tdoc: \"Set a download URL on the action result; the browser opens it when the action returns. It fetches nothing and stores nothing — the URL must already serve the bytes, e.g. the `/api/temp-file/{token}` a service handed back. To put a remote file INTO storage, fetch it with `callApi()` and write it to a file column.\",\n\t},\n\t{\n\t\tname: \"getSetting\",\n\t\tsignature: \"getSetting(settingCd)\",\n\t\treturns: \"any\",\n\t\tdoc: \"Read a module setting, resolved through the folder chain (current folder → parents → module default).\",\n\t},\n\t{\n\t\tname: \"getSecret\",\n\t\tsignature: \"getSecret(secretCd)\",\n\t\treturns: \"string\",\n\t\tdoc: \"Retrieve a decrypted secret (API key, token). Managed in the admin UI.\",\n\t},\n\t{\n\t\tname: \"ocrExtract\",\n\t\tsignature: \"ocrExtract(fileField, endpointBaseUrl, schema?, opts?)\",\n\t\treturns: \"string (v1) | object (v2)\",\n\t\tdoc: \"Run OCR extraction against a document. **The return type follows the mode, and only `opts.mode` selects it** — a third argument alone never does. Without `opts.mode` (v1) the third argument is forwarded as `hints` and the result is the raw bundle as a JSON **string**: `JSON.parse()` it, or every property read is `undefined`. With `{ mode: 'extract' }` the third argument is a schema object and the result is already parsed — `{ fields, confidence?, unmatched, raw_text, meta }`. `{ mode: 'summary' }` needs no schema and returns `{ summary, raw_text, meta }` parsed. `{ profile: 'module_cd.profile_cd' }` uses a registered extraction profile, implies mode `extract`, and cannot be combined with an inline schema. The OCR host must be on `Dsl:Limits:AllowedHosts`.\",\n\t},\n\t{\n\t\tname: \"detectDocument\",\n\t\tsignature: \"detectDocument(rawText)\",\n\t\treturns: \"object | null\",\n\t\tdoc: \"Score text against reachable extraction profiles; returns the best match `{ profile, docType, score }` or `null`.\",\n\t},\n\t{\n\t\tname: \"applyProfile\",\n\t\tsignature: \"applyProfile(json, profile)\",\n\t\treturns: \"object\",\n\t\tdoc: \"Map already-extracted JSON to target fields and return the mapped object — it never writes, so the `insert()` / `update()` stays yours. `json` is the parsed extractor output (`JSON.parse(ocrExtract(...))`). `profile` must be an **inline object**, `{ map: { target: { from, transform?, pick? } }, lines?: { from, map, key? } }` — passing a profile code throws, as profile-by-code is a later slice. `from` is a path into the extraction; `transform` is one of `firstValid:<basis>`, `lookupRef:<entity.matchField>>returnField>`, `matchCatalog:<same>`, `parseMoney` or `parseDate`. Header targets come back at the top level and the 1:N block under its `key` (default `lines`); a missing source path omits the target. Not the same thing as `ocrExtract`'s registered `opts.profile` code.\",\n\t},\n\n\t// Utilities\n\t{ name: \"now\", signature: \"now()\", returns: \"datetime\", doc: \"Current date/time. Lowercase — this is the execute-block date function.\" },\n\t{ name: \"addDays\", signature: \"addDays(date, n)\", returns: \"date\", doc: \"Add `n` days to a date.\" },\n\t{ name: \"addMinutes\", signature: \"addMinutes(date, n)\", returns: \"datetime\", doc: \"Add `n` minutes.\" },\n\t{ name: \"addSeconds\", signature: \"addSeconds(date, n)\", returns: \"datetime\", doc: \"Add `n` seconds.\" },\n\t{ name: \"currentUserId\", signature: \"currentUserId()\", returns: \"long\", doc: \"The acting user's tenant user ID.\" },\n\t{ name: \"flush\", signature: \"flush()\", returns: \"void\", doc: \"Flush pending writes so a following read sees them.\" },\n\t{ name: \"tryParseJson\", signature: \"tryParseJson(value)\", returns: \"any | null\", doc: \"Parse JSON, returning `null` on failure instead of throwing.\" },\n\t{\n\t\tname: \"nextNumber\",\n\t\tsignature: \"nextNumber(entity)\",\n\t\treturns: \"string\",\n\t\tentityArg: 0,\n\t\tdoc: \"Generate the next value from a number sequence. Usually unnecessary — the platform auto-fills on `insert()`.\",\n\t},\n\t{\n\t\tname: \"entityLink\",\n\t\tsignature: \"entityLink(entityCd, record, description?)\",\n\t\treturns: \"link\",\n\t\tentityArg: 0,\n\t\tdoc: \"Build a clickable link to a record, for an `entitylink` column. Always pass a **qualified** code — `entity_cd` is only unique per module.\",\n\t},\n];\n\nexport const BUILTIN_BY_NAME = new Map(BUILTINS.map((b) => [b.name, b]));\n\n/** Bare identifiers the runtime injects — no parentheses. */\nexport const BUILTIN_VALUES: Record<string, string> = {\n\tuserId: \"The acting user's tenant user ID. A bare identifier — `userId()` is a compile error.\",\n\trecords: \"The selected records, in a `batch` action. Iterate with `for x in records { … }`.\",\n\tparams: \"Declared action parameters — read with `params[name]`.\",\n\told: \"Pre-change values, in a trigger-invoked action — read with `old[field]`. Read-only.\",\n};\n","// Static checks for an action DSL body (`logic/actions/*.dsl`).\n//\n// Every rule here mirrors something the platform only tells you at pack or\n// install time — a slow, tenant-bound round trip. The point is to move that\n// feedback to where the script is written, and to the validator that runs\n// before a pack, from one implementation rather than two.\n//\n// The rules that need to know about the module take it through `DslContext`,\n// which is small on purpose: a module code, the action, and the columns of the\n// entity behind the record context. Anything a host can't resolve it simply\n// omits, and the rules that depend on it stand down. See ./types.\n\nimport { BUILTIN_BY_NAME } from \"./builtins\";\nimport { CONTROL_KEYWORDS, type Token } from \"./lexer\";\nimport {\n\ttype BlockKind,\n\ttype DslDocument,\n\ttype Span,\n\tblockLabelAt,\n\tparseDsl,\n} from \"./parse\";\nimport type { ColumnLookup, DslContext, DslIssue, DslSeverity } from \"./types\";\n\n/**\n * Check a DSL body. Returns [] for a clean script.\n *\n * Issues come back in source-feature order (field reads, params, execution\n * mode, block spelling, built-ins, top-level returns, inline assignments)\n * rather than sorted by position — a host that wants them in file order can\n * sort on `start`.\n */\nexport function checkDsl(text: string, ctx: DslContext = {}): DslIssue[] {\n\tconst parsed = parseDsl(text);\n\tconst out: DslIssue[] = [];\n\tconst positionAt = lineIndexer(text);\n\n\tconst add = (\n\t\tspan: Span,\n\t\tmessage: string,\n\t\tseverity: DslSeverity,\n\t\trule: string,\n\t) => {\n\t\tconst { line, column } = positionAt(span.start);\n\t\tout.push({\n\t\t\trule,\n\t\t\tseverity,\n\t\t\tmessage,\n\t\t\tstart: span.start,\n\t\t\tend: span.end,\n\t\t\tline,\n\t\t\tcolumn,\n\t\t});\n\t};\n\n\tconst action = ctx.action;\n\tconst entity = ctx.currentEntity ?? null;\n\tconst isBatch = (action?.executionMode ?? \"single\") === \"batch\";\n\tconst hasColumn = columnMatcher(entity?.columns);\n\n\t// ── structure ────────────────────────────────────────────────────\n\t// ActionDslCompiler.ParseBlocks reads the headers before anything else, so\n\t// a file that loses a block here loses it wholesale: the body still looks\n\t// like code, and nothing runs.\n\tif (text.trim() === \"\") {\n\t\tadd(\n\t\t\t{ start: 0, end: text.length },\n\t\t\t\"A DSL body needs at least an execute: block — an empty file installs an action that does nothing.\",\n\t\t\t\"error\",\n\t\t\t\"dsl/empty-script\",\n\t\t);\n\t\treturn out;\n\t}\n\n\t// A file with no headers at all has no label to point at, and a zero-width\n\t// span renders as a caret before the first character — so fall back to the\n\t// first token, which is where the reader is already looking.\n\tconst firstToken = parsed.tokens[0];\n\tconst firstLabel = parsed.blocks[0]?.label ??\n\t\t(firstToken ? { start: firstToken.start, end: firstToken.end } : { start: 0, end: text.length });\n\tif (!parsed.blocks.some((b) => b.kind === \"execute\")) {\n\t\tadd(\n\t\t\tfirstLabel,\n\t\t\t\"No execute: block — it is the only required block, and the compiler runs nothing without it.\",\n\t\t\t\"error\",\n\t\t\t\"dsl/missing-execute\",\n\t\t);\n\t}\n\n\t// `execute:` is matched as `(.*?)\\z`, and its lookahead lists nothing — so it\n\t// runs to the end of the file and takes every header below it with it. The\n\t// block's own regex still finds it and it still runs; what breaks is\n\t// execute:, whose body now holds a header line and a formula or a param\n\t// list, parsed as JavaScript.\n\tconst executeBlock = parsed.blocks.find((b) => b.kind === \"execute\");\n\tif (executeBlock) {\n\t\tfor (let i = 0; i < parsed.tokens.length; i++) {\n\t\t\tconst token = parsed.tokens[i]!;\n\t\t\tif (token.start <= executeBlock.label.start) continue;\n\t\t\tif (token.character !== 0) continue;\n\t\t\tconst label = blockLabelAt(parsed.tokens, i);\n\t\t\tif (!label) continue;\n\t\t\t// A second execute: cannot be moved above the first. findBlocks\n\t\t\t// stops at the first one, so dsl/duplicate-block never sees this\n\t\t\t// and the wording has to come from here.\n\t\t\tadd(\n\t\t\t\tlabel.span,\n\t\t\t\tlabel.kind === \"execute\"\n\t\t\t\t\t? `\"execute:\" is declared more than once — the first one's body runs to the end of the file, so this header and everything under it are swallowed into it and parsed as JavaScript. Merge the two into one execute: block.`\n\t\t\t\t\t: `\"${label.kind}:\" is below execute:, whose body runs to the end of the file — the header and everything under it are swallowed into the execute: script and parsed as JavaScript. Move it above execute:.`,\n\t\t\t\t\"error\",\n\t\t\t\t\"dsl/block-after-execute\",\n\t\t\t);\n\t\t}\n\t}\n\n\tconst seenBlocks = new Set<string>();\n\tfor (let i = 0; i < parsed.blocks.length; i++) {\n\t\tconst block = parsed.blocks[i]!;\n\t\tif (seenBlocks.has(block.kind)) {\n\t\t\tadd(\n\t\t\t\tblock.label,\n\t\t\t\t`\"${block.kind}:\" is declared more than once — the compiler keeps one and silently drops the other.`,\n\t\t\t\t\"error\",\n\t\t\t\t\"dsl/duplicate-block\",\n\t\t\t);\n\t\t\t// No block's own lookahead lists itself, so the order rule below\n\t\t\t// would read a duplicate as misplaced and tell the author to move\n\t\t\t// it before itself.\n\t\t\tcontinue;\n\t\t}\n\t\tseenBlocks.add(block.kind);\n\n\t\t// Only the block immediately above can swallow this one: a block body\n\t\t// ends at the first header its own lookahead lists, and the nearest\n\t\t// header below it is this one. execute: is left to the rule above, which\n\t\t// says the same thing about it in better words.\n\t\tconst prev = parsed.blocks[i - 1];\n\t\tif (prev && prev.kind !== \"execute\" && !BLOCK_STOPS[prev.kind].has(block.kind)) {\n\t\t\tadd(\n\t\t\t\tblock.label,\n\t\t\t\t`\"${block.kind}:\" must come before \"${prev.kind}:\" — the compiler reads ${prev.kind}: up to the next header it recognises, and ${block.kind}: is not one of them, so this header and its body end up inside the ${prev.kind}: body.`,\n\t\t\t\t\"error\",\n\t\t\t\t\"dsl/block-order\",\n\t\t\t);\n\t\t}\n\t}\n\n\t// ── record fields ────────────────────────────────────────────────\n\tfor (const ref of parsed.fieldRefs) {\n\t\t// Neither block is rewritten by TransformLine, so brackets in them are\n\t\t// data rather than field reads: `schema:` is embedded as a JS object\n\t\t// literal, and `params:` is read by RxParamDecl — whose trailing\n\t\t// key=value pairs take a bracketed option list, `options=[cash]`.\n\t\tif (ref.block === \"schema\" || ref.block === \"params\") continue;\n\n\t\t// Single-hop is the DSL's own rewrite (`RxRefNav`), so the rule belongs\n\t\t// to the blocks that go through it. canExecute: reaches the formula\n\t\t// engine verbatim, and a formula walks a chain of any depth —\n\t\t// `[vehicle].[depot].[city_name]` resolves there and is tested.\n\t\tconst isDslBlock = ref.block === \"execute\" || ref.block === \"onBeforeStart\";\n\t\t// The compiler rewrites the first hop and then fails on a surviving\n\t\t// `.[` — so it is the bracket, not the hop count, that marks a second\n\t\t// reference. `[vehicle].plate.length` compiles to\n\t\t// `__ref_vehicle.get('plate').length`: one hop, then JavaScript.\n\t\tconst secondRef = ref.navigation.findIndex((h, idx) => idx > 0 && h.bracketed);\n\t\tif (isDslBlock && secondRef > 0) {\n\t\t\tconst first = ref.navigation[secondRef]!;\n\t\t\tconst last = ref.navigation[ref.navigation.length - 1]!;\n\t\t\tadd(\n\t\t\t\t{ start: first.span.start, end: last.span.end },\n\t\t\t\t`Ref navigation is single-hop in the DSL. Use getRecord() or select() to reach past \"${ref.navigation[0]!.name}\".`,\n\t\t\t\t\"error\",\n\t\t\t\t\"dsl/multi-hop-nav\",\n\t\t\t);\n\t\t}\n\n\t\t// Batch execute: applies no `[field]` rewrite at all, so `[true]` stays\n\t\t// the literal it is — and a keyword is never a column name anyway.\n\t\tif (isBatch && ref.block === \"execute\" && LITERAL_NAMES.has(ref.name))\n\t\t\tcontinue;\n\n\t\tif (!entity) continue;\n\t\tif (entity.columns.size === 0) continue;\n\t\tif (hasColumn(ref.name)) continue;\n\t\t// `var ids = [orderId]` is an array literal, not a field read. Only the\n\t\t// name tells the two apart, so a name bound in this script stands down —\n\t\t// the same fail-open the entity checks above use.\n\t\t//\n\t\t// Only the bare bracket is ambiguous. `r[stauts]` and\n\t\t// `records[0][stauts]` name a column outright — the compiler rewrites\n\t\t// each to `.get('stauts')` with the literal name — so a same-named\n\t\t// local says nothing about them.\n\t\tif (ref.isCurrentRecord && parsed.locals.has(ref.name)) continue;\n\n\t\tadd(\n\t\t\tref.span,\n\t\t\t`\"${ref.name}\" is not a column on ${entity.qualified}. [field] names are checked at pack time — this is a compile error, not an empty read.`,\n\t\t\t\"error\",\n\t\t\t\"dsl/unknown-column\",\n\t\t);\n\t}\n\n\t// `old[field]` names columns of the same entity — RxOldAccess feeds them\n\t// into the very same check — so a typo there is a compile error too.\n\tif (entity && entity.columns.size > 0) {\n\t\tfor (const ref of parsed.globalRefs) {\n\t\t\tif (ref.global !== \"old\") continue;\n\t\t\tif (ref.block !== \"execute\" && ref.block !== \"onBeforeStart\") continue;\n\t\t\tif (hasColumn(ref.property)) continue;\n\t\t\tadd(\n\t\t\t\tref.span,\n\t\t\t\t`\"${ref.property}\" is not a column on ${entity.qualified}. old[field] reads the pre-change value of a column, and the name is checked at pack time.`,\n\t\t\t\t\"error\",\n\t\t\t\t\"dsl/unknown-column\",\n\t\t\t);\n\t\t}\n\t}\n\n\t// ── params ───────────────────────────────────────────────────────\n\t// `ValidateParamUsages` compares with OrdinalIgnoreCase, so `params[Qty]`\n\t// against a declared `qty` compiles — flagging it would be a false error.\n\tconst declared = new Set(parsed.params.map((p) => p.name.toLowerCase()));\n\tconst hasParamsBlock = parsed.blocks.some((b) => b.kind === \"params\");\n\tfor (const ref of parsed.globalRefs) {\n\t\tif (ref.global !== \"params\") continue;\n\t\tif (!hasParamsBlock || declared.has(ref.property.toLowerCase())) continue;\n\t\tadd(\n\t\t\tref.span,\n\t\t\t`\"${ref.property}\" is not declared in the params: block.`,\n\t\t\t\"error\",\n\t\t\t\"dsl/unknown-param\",\n\t\t);\n\t}\n\n\t// ── execution mode ───────────────────────────────────────────────\n\tif (action) {\n\t\tconst mode = action.executionMode ?? \"single\";\n\t\t// `recordsRefs` covers both `records[x]` and the bare `for x in records`,\n\t\t// and comes from the lexer, so the word inside a string or a comment\n\t\t// does not count — nor does a script that binds its own `records`,\n\t\t// which shadows the batch global and says nothing about the mode.\n\t\tconst recordsSpan = parsed.locals.has(\"records\")\n\t\t\t? undefined\n\t\t\t: parsed.recordsRefs[0];\n\t\t// execute: alone. `onBeforeStart:` is compiled by CompilePerRecordBlock\n\t\t// whatever the mode — \"always per-record (no batch form)\" — so a bare\n\t\t// field is exactly how it is meant to be written there.\n\t\t//\n\t\t// Batch mode never applies the `[field]` rewrite at all, which is why\n\t\t// `var ids = [id]` survives as the array literal it looks like. Same\n\t\t// disambiguation as the column rule: a name bound in this script is a\n\t\t// local, not a column.\n\t\tconst bareFields = parsed.fieldRefs.filter(\n\t\t\t(r) =>\n\t\t\t\tr.block === \"execute\" &&\n\t\t\t\tr.isCurrentRecord &&\n\t\t\t\t!parsed.locals.has(r.name) &&\n\t\t\t\t!LITERAL_NAMES.has(r.name),\n\t\t);\n\n\t\tif (mode === \"batch\") {\n\t\t\t// Every one of them: an editor underlines what it is told to, and\n\t\t\t// reporting only the first hides the rest behind a re-check.\n\t\t\tfor (const field of bareFields) {\n\t\t\t\tadd(\n\t\t\t\t\tfield.outerSpan,\n\t\t\t\t\t`Action \"${action.code}\" runs in batch mode, which has no current record. Iterate instead: for x in records { x[${field.name}] }.`,\n\t\t\t\t\t\"error\",\n\t\t\t\t\t\"dsl/batch-bare-field\",\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tif (mode !== \"batch\" && recordsSpan) {\n\t\t\tadd(\n\t\t\t\trecordsSpan,\n\t\t\t\t`\"records\" only exists in batch mode; action \"${action.code}\" runs in \"${mode}\" mode.`,\n\t\t\t\t\"warning\",\n\t\t\t\t\"dsl/records-outside-batch\",\n\t\t\t);\n\t\t}\n\t}\n\n\t// ── block-specific spelling ──────────────────────────────────────\n\t// canExecute is parsed by the formula engine, execute by the JavaScript\n\t// compiler. They share more vocabulary than the docs suggest — NULL and\n\t// lowercase booleans work in both, and shipped modules rely on that — so\n\t// only the operators that genuinely have no formula spelling are flagged.\n\tfor (const token of parsed.tokens) {\n\t\tif (blockOf(parsed, token.start) !== \"canExecute\") continue;\n\t\tif (token.text !== \"&&\" && token.text !== \"||\") continue;\n\t\tadd(\n\t\t\t{ start: token.start, end: token.end },\n\t\t\t`canExecute is a formula, not JavaScript — write ${token.text === \"&&\" ? \"AND\" : \"OR\"}.`,\n\t\t\t\"warning\",\n\t\t\t\"dsl/js-in-formula\",\n\t\t);\n\t}\n\n\t// ── built-in misuse ──────────────────────────────────────────────\n\tfor (const call of parsed.calls) {\n\t\tif (call.name === \"userId\") {\n\t\t\tadd(\n\t\t\t\tcall.nameSpan,\n\t\t\t\t\"'userId' is a value, not a function — write userId without parentheses, or currentUserId(). \" +\n\t\t\t\t\t\"The compiler's bare-identifier rewrite fires either way, so userId() reaches Jint as a call against a number.\",\n\t\t\t\t\"error\",\n\t\t\t\t\"dsl/user-id-call\",\n\t\t\t);\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst builtin = BUILTIN_BY_NAME.get(call.name);\n\t\tif (!builtin || builtin.entityArg === undefined) continue;\n\t\tconst arg = call.firstStringArg;\n\t\tif (!arg) continue;\n\n\t\t// A hyphenated module code can't be schema-qualified, so the rule is\n\t\t// skipped there rather than reported as unfixable. Neither can a code\n\t\t// half of which is spliced in at run time be read here.\n\t\tif (arg.interpolated) continue;\n\t\tif (arg.value.includes(\".\") || ctx.moduleCode?.includes(\"-\")) continue;\n\t\tadd(\n\t\t\targ.span,\n\t\t\t`Qualify the entity code as \"${ctx.moduleCode ? `${ctx.moduleCode}.` : \"<module>.\"}${arg.value}\" — entity_cd is only unique per module, so a bare code can resolve to another module's entity.`,\n\t\t\t\"info\",\n\t\t\t\"dsl/unqualified-entity\",\n\t\t);\n\t}\n\n\t// ── indented headers, and returns outside a function ─────────────\n\t// An indented `params:` inside an object literal is an ordinary key, which\n\t// is the whole reason the compiler anchors headers at column 0 rather than\n\t// trusting the line — so that rule reads brace depth.\n\t//\n\t// `return` reads function scope instead. Both blocks compile to a bare\n\t// script, and Esprima's ParseScript rejects a return outside a function\n\t// wherever it sits: `if (x) { return }` and `if (x) return` fail exactly as\n\t// a return on its own line does.\n\tlet depth = 0;\n\tconst functionDepths: number[] = [];\n\t// Index of the `(` that the most recent `)` closed. Tracked with a stack\n\t// because the nearest open paren is not the matching one: in `if (now()) {`\n\t// it is `now`'s, and in `function f(x = (1)) {` it is the default value's.\n\tconst parenStack: number[] = [];\n\tlet matchingParenOpen = -1;\n\tfor (let i = 0; i < parsed.tokens.length; i++) {\n\t\tconst token = parsed.tokens[i]!;\n\n\t\tif (token.text === \"(\") parenStack.push(i);\n\t\telse if (token.text === \")\") matchingParenOpen = parenStack.pop() ?? -1;\n\n\t\tif (token.text === \"{\") {\n\t\t\tdepth++;\n\t\t\tif (opensFunctionBody(parsed.tokens, i, matchingParenOpen))\n\t\t\t\tfunctionDepths.push(depth);\n\t\t} else if (token.text === \"}\") {\n\t\t\tif (functionDepths[functionDepths.length - 1] === depth)\n\t\t\t\tfunctionDepths.pop();\n\t\t\tdepth = Math.max(0, depth - 1);\n\t\t}\n\n\t\tif (depth === 0 && token.character > 0) {\n\t\t\tconst label = blockLabelAt(parsed.tokens, i);\n\t\t\t// `execute: number` inside params: declares a param called execute.\n\t\t\t// RxParamDecl takes any `\\w+`, so a block name is a legal param\n\t\t\t// name — and a declaration the parser already read is not a header.\n\t\t\tconst isParamDecl = parsed.params.some(\n\t\t\t\t(p) => p.nameSpan.start === token.start,\n\t\t\t);\n\t\t\tif (label && !isParamDecl) {\n\t\t\t\tadd(\n\t\t\t\t\tlabel.span,\n\t\t\t\t\t`Block headers start at column 0. Indented, \"${label.kind}:\" is body text — the compiler never opens the block, and it runs as if empty.`,\n\t\t\t\t\t\"error\",\n\t\t\t\t\t\"dsl/indented-block-header\",\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif (token.kind !== \"ident\" || token.text !== \"return\") continue;\n\t\t// `return` is a reserved word, so it is a statement unless it is being\n\t\t// used as a name: `result.return` reads a property, `{ return: 1 }`\n\t\t// declares a key and `{ return() { … } }` declares a method. All three\n\t\t// are legal JavaScript.\n\t\tif (parsed.tokens[i - 1]?.text === \".\") continue;\n\t\tif (parsed.tokens[i + 1]?.text === \":\") continue;\n\t\tif (isMethodName(parsed.tokens, i)) continue;\n\t\tif (functionDepths.length > 0) continue;\n\t\tconst block = blockOf(parsed, token.start);\n\t\tif (block !== \"execute\" && block !== \"onBeforeStart\") continue;\n\t\tadd(\n\t\t\t{ start: token.start, end: token.end },\n\t\t\t`A return outside a function is a syntax error — ${block}: compiles to a bare script. Use exit(message, level) to stop early and keep the changes made so far.`,\n\t\t\t\"error\",\n\t\t\t\"dsl/top-level-return\",\n\t\t);\n\t}\n\n\t// ── formula-only functions in a JavaScript block ─────────────────\n\t// execute: and onBeforeStart: compile to a bare script and run on Jint;\n\t// the rest of the DSL is the formula engine. Install rejects these with\n\t// \"'TODAY' is not defined\".\n\tfor (const call of parsed.calls) {\n\t\tconst replacement = FORMULA_ONLY.get(call.name);\n\t\tif (!replacement) continue;\n\t\tif (call.block !== \"execute\" && call.block !== \"onBeforeStart\") continue;\n\t\tadd(\n\t\t\tcall.nameSpan,\n\t\t\t`${call.name}() is formula-only — in ${call.block}: it is undefined and install fails with \"'${call.name}' is not defined\". Write ${replacement}.`,\n\t\t\t\"error\",\n\t\t\t\"dsl/formula-only-function\",\n\t\t);\n\t}\n\n\t// Token position by start offset — the two rules below both need to read\n\t// what sits next to a call, and a scan per call is a scan of the file.\n\tconst tokenAt = new Map(parsed.tokens.map((t, i) => [t.start, i]));\n\n\t// ── SQL placeholders are @name, not :name ────────────────────────\n\tfor (const call of parsed.calls) {\n\t\tif (call.name !== \"query\" && call.name !== \"callProc\") continue;\n\t\tconst arg = call.firstStringArg;\n\t\tif (!arg) continue; // a variable or a built string — nothing to read\n\n\t\t// `::text` is a Postgres cast and `a:b` inside a literal is not a\n\t\t// placeholder either, so require a non-word, non-colon character before.\n\t\t// Quoted data and comments are not SQL to bind against at all —\n\t\t// `select ':draft' as status` names no placeholder.\n\t\t//\n\t\t// The leading character is captured rather than looked behind: lookbehind\n\t\t// is ES2018, and an unsupported one is a SyntaxError for the whole module\n\t\t// at parse time, not a failure of this rule.\n\t\tconst bad = /(^|[^:\\w]):([a-z][a-z0-9_]*)/i.exec(stripSqlNoise(arg.value));\n\t\tif (bad) {\n\t\t\tconst name = bad[2];\n\t\t\tadd(\n\t\t\t\targ.span,\n\t\t\t\t`SQL binds @name, not :name — rewrite ':${name}' as '@${name}' and pass { ${name}: value } as the params argument.`,\n\t\t\t\t\"error\",\n\t\t\t\t\"dsl/sql-placeholder\",\n\t\t\t);\n\t\t}\n\n\t\t// A `${…}` hole is the splice itself; a `+` after the literal is the\n\t\t// same splice written the other way.\n\t\tif (arg.interpolated || parsed.tokens[arg.endIndex + 1]?.text === \"+\") {\n\t\t\tconst built = arg.interpolated ? \"${…} interpolation\" : \"concatenation\";\n\t\t\tadd(\n\t\t\t\targ.span,\n\t\t\t\t// callProc's first argument is the procedure name, and an\n\t\t\t\t// identifier cannot be bound — the @placeholder advice cannot\n\t\t\t\t// be followed there.\n\t\t\t\tcall.name === \"callProc\"\n\t\t\t\t\t? `Procedure name built by ${built} — a name is an identifier, so it cannot be bound as a @placeholder. Choose between fixed names in the script rather than splicing a value into one.`\n\t\t\t\t\t: `SQL built by ${built} — pass @placeholders and a params object instead, so values are bound rather than spliced into the statement.`,\n\t\t\t\t\"warning\",\n\t\t\t\t\"dsl/sql-concat\",\n\t\t\t);\n\t\t}\n\t}\n\n\t// ── unknown host functions ───────────────────────────────────────\n\t// A warning, not an error: the catalog tracks the host's built-ins by hand,\n\t// so a name missing from it is more likely our gap than the author's typo.\n\t//\n\t// JavaScript blocks only. The catalog is Jint's host surface; canExecute:\n\t// is the formula engine, with a vocabulary of its own — and its infix\n\t// operators bring parentheses with them, so `… AND (x OR y)` reads as a\n\t// call to AND here and is no such thing.\n\tconst declaredFunctions = new Set<string>();\n\tfor (let i = 0; i < parsed.tokens.length; i++) {\n\t\tif (parsed.tokens[i]!.text !== \"function\") continue;\n\t\tconst name = parsed.tokens[i + 1];\n\t\tif (name?.kind === \"ident\") declaredFunctions.add(name.text);\n\t}\n\t// `parsed.calls` is every `name(` in the body, so a function's own\n\t// declaration head looks like a call to it: `function f(x)` and the method\n\t// shorthand `f(x) { … }` alike. Neither is an invocation of anything.\n\tconst reportedUnknown = new Set<string>();\n\tfor (const call of parsed.calls) {\n\t\tif (call.block !== \"execute\" && call.block !== \"onBeforeStart\") continue;\n\t\tconst name = call.name;\n\t\tconst idx = tokenAt.get(call.nameSpan.start);\n\t\tif (idx !== undefined) {\n\t\t\t// `new Foo()` names a constructor, not a host function — the\n\t\t\t// catalog never held one and has nothing to say about it.\n\t\t\tconst prev = parsed.tokens[idx - 1]?.text;\n\t\t\tif (prev === \"function\" || prev === \"new\") continue;\n\t\t\tif (isMethodName(parsed.tokens, idx)) continue;\n\t\t}\n\t\tif (\n\t\t\tBUILTIN_BY_NAME.has(name) ||\n\t\t\tCONTROL_KEYWORDS.has(name) ||\n\t\t\tKEYWORDS_BEFORE_PAREN.has(name) ||\n\t\t\tJS_GLOBALS.has(name) ||\n\t\t\tFORMULA_ONLY.has(name) ||\n\t\t\t// Its own rule reports this one, with better wording.\n\t\t\tname === \"userId\" ||\n\t\t\tdeclaredFunctions.has(name) ||\n\t\t\tparsed.locals.has(name) ||\n\t\t\treportedUnknown.has(name)\n\t\t) {\n\t\t\tcontinue;\n\t\t}\n\t\treportedUnknown.add(name);\n\t\tadd(\n\t\t\tcall.nameSpan,\n\t\t\t`\"${name}()\" is not a DSL host function, and nothing in this script declares it. Check it against the built-in catalog.`,\n\t\t\t\"warning\",\n\t\t\t\"dsl/unknown-builtin\",\n\t\t);\n\t}\n\n\t// ── a job's action has no current record ─────────────────────────\n\tif (ctx.action?.viaJob) {\n\t\t// `JobRegistrar.RequiresRecordContext` reads the compiled script for\n\t\t// three markers, not one: `__r.` from `[field]`, `__old.` from the\n\t\t// trigger-only `old[field]`, and `__records.` from the batch record set.\n\t\t// All three are rejected, so all three are reported.\n\t\tconst inScript = (block: BlockKind | null) =>\n\t\t\tblock === \"execute\" || block === \"onBeforeStart\";\n\t\tconst bound: Array<{ span: Span; read: string }> = [];\n\n\t\t// Same disambiguation the column rule makes, on the same terms: `[id]`\n\t\t// is an array literal when the script binds `id`, and `[true]` is one\n\t\t// in batch execute:, where no `[field]` rewrite runs to claim it.\n\t\tfor (const ref of parsed.fieldRefs) {\n\t\t\tif (!inScript(ref.block)) continue;\n\t\t\tif (isBatch && ref.block === \"execute\" && LITERAL_NAMES.has(ref.name))\n\t\t\t\tcontinue;\n\t\t\tif (ref.isCurrentRecord && parsed.locals.has(ref.name)) continue;\n\t\t\tbound.push({ span: ref.outerSpan, read: `[${ref.name}]` });\n\t\t}\n\t\tfor (const ref of parsed.globalRefs) {\n\t\t\tif (ref.global !== \"old\" || !inScript(ref.block)) continue;\n\t\t\tbound.push({ span: ref.span, read: `old[${ref.property}]` });\n\t\t}\n\t\tfor (const span of parsed.recordsRefs) {\n\t\t\tif (!inScript(blockOf(parsed, span.start))) continue;\n\t\t\tbound.push({ span, read: \"records\" });\n\t\t}\n\n\t\tconst first = bound.sort((a, b) => a.span.start - b.span.start)[0];\n\t\tif (first) {\n\t\t\tadd(\n\t\t\t\tfirst.span,\n\t\t\t\t`Action \"${ctx.action.code}\" is invoked by a scheduled job, which runs as the system user with no record bound — ${first.read} has nothing to read. Fetch rows with select() or query() instead.`,\n\t\t\t\t\"error\",\n\t\t\t\t\"dsl/job-record-context\",\n\t\t\t);\n\t\t}\n\t}\n\n\tout.push(...inlineAssignmentIssues(parsed, positionAt));\n\treturn out;\n}\n\n/**\n * Column matching is case-insensitive at the other end — `EntityColumnLookup`\n * hands the compiler an OrdinalIgnoreCase set — but a host passes us whatever\n * `Set` or `Map` it already holds, and a mixed-case column name is legal.\n *\n * So fold both sides: the names once per check when the lookup can enumerate\n * them (`Set` and `Map` both can), and the reference on the way in. A lookup\n * that can do neither falls back to trying the reference in lower case, which\n * is all that is left to try.\n */\nfunction columnMatcher(columns?: ColumnLookup): (name: string) => boolean {\n\tif (!columns) return () => true;\n\tif (typeof columns.keys !== \"function\")\n\t\treturn (name) => columns.has(name) || columns.has(name.toLowerCase());\n\n\tconst folded = new Set<string>();\n\tfor (const key of columns.keys()) folded.add(key.toLowerCase());\n\treturn (name) => folded.has(name.toLowerCase());\n}\n\n/**\n * Whether the name at `i` heads a method shorthand — `return() { … }`, whose\n * parameter list is followed by a body. `return (x + 1)` is a statement with a\n * parenthesized expression and has no brace after the closing paren, so the\n * two are told apart by what follows the parens rather than by what opens them.\n */\nfunction isMethodName(tokens: Token[], i: number): boolean {\n\tif (tokens[i + 1]?.text !== \"(\") return false;\n\tlet depth = 0;\n\tfor (let j = i + 1; j < tokens.length; j++) {\n\t\tconst text = tokens[j]!.text;\n\t\tif (text === \"(\") depth++;\n\t\telse if (text === \")\") {\n\t\t\tdepth--;\n\t\t\tif (depth === 0) return tokens[j + 1]?.text === \"{\";\n\t\t}\n\t}\n\treturn false;\n}\n\n/**\n * Whether the `{` at `i` opens a function body — where a `return` is legal.\n *\n * `=> {` is one. So is `) {` when the name in front of the matching `(` is not\n * a control keyword: that covers `function (x) {`, `function f(x) {` and the\n * `f() {` method shorthand, while leaving `if (x) {` and `for (…) {` alone.\n */\nfunction opensFunctionBody(\n\ttokens: Token[],\n\ti: number,\n\tmatchingParenOpen: number,\n): boolean {\n\tconst prev = tokens[i - 1];\n\tif (prev?.text === \"=>\") return true;\n\tif (prev?.text !== \")\" || matchingParenOpen < 0) return false;\n\tconst head = tokens[matchingParenOpen - 1];\n\treturn head?.kind === \"ident\" && !CONTROL_KEYWORDS.has(head.text);\n}\n\n/**\n * The headers each block's regex in `ParseBlocks` stops at — its body runs to\n * the first of these below it, or to the end of the file.\n *\n * The sets are not the same, and none of them is \"every other block\": a block\n * followed by one its own set omits swallows that block's text. `schema:`, the\n * only one every other set lists, may therefore sit anywhere before `execute:`.\n */\nconst BLOCK_STOPS: Record<BlockKind, ReadonlySet<BlockKind>> = {\n\tparams: new Set([\"schema\", \"canExecute\", \"onBeforeStart\", \"execute\"]),\n\tcanExecute: new Set([\"schema\", \"onBeforeStart\", \"execute\"]),\n\tschema: new Set([\"params\", \"canExecute\", \"onBeforeStart\", \"execute\"]),\n\tonBeforeStart: new Set([\"schema\", \"execute\"]),\n\texecute: new Set(),\n};\n\n/**\n * Formula-engine functions that are undefined in a JavaScript block, mapped to\n * the spelling that works there.\n *\n * A Map, not an object: the key is a name read out of the script, and on an\n * object `toString` and `constructor` would answer from the prototype — a\n * declared `function toString()` would be reported as formula-only, with the\n * native function's source offered as the replacement.\n */\nconst FORMULA_ONLY = new Map<string, string>([\n\t[\"TODAY\", \"now()\"],\n\t[\"NOW\", \"now()\"],\n\t[\"CURRENT_USER_ID\", \"currentUserId()\"],\n]);\n\n/**\n * Keywords a `(` may legally follow. `parsed.calls` is every `name(` in the\n * body, so these arrive looking like calls — `return (x)`, `typeof (v)` and\n * `for (x of (xs))` included — and are not calls to anything.\n */\nconst KEYWORDS_BEFORE_PAREN = new Set([\n\t\"function\", \"return\", \"typeof\", \"instanceof\", \"new\", \"delete\", \"void\",\n\t\"in\", \"of\", \"do\", \"else\", \"try\", \"throw\", \"yield\", \"await\",\n]);\n\n/** Globals Jint exposes. Real calls, and none of them ours to report. */\nconst JS_GLOBALS = new Set([\n\t\"parseInt\", \"parseFloat\", \"isNaN\", \"isFinite\", \"encodeURI\", \"decodeURI\",\n\t\"encodeURIComponent\", \"decodeURIComponent\", \"String\", \"Number\", \"Boolean\",\n\t\"Array\", \"Object\", \"Date\", \"Math\", \"JSON\", \"RegExp\", \"Error\", \"Set\", \"Map\",\n\t\"WeakSet\", \"WeakMap\", \"Promise\", \"Symbol\", \"BigInt\",\n]);\n\n/**\n * Keyword literals, which `[…]` can only be holding as array elements. Both\n * spellings: the DSL takes SQL-style `NULL`/`TRUE`/`FALSE` as well as the\n * JavaScript ones, and rewrites them to the latter.\n */\nconst LITERAL_NAMES = new Set([\n\t\"true\",\n\t\"false\",\n\t\"null\",\n\t\"TRUE\",\n\t\"FALSE\",\n\t\"NULL\",\n]);\n\n/**\n * SQL with its string literals and comments blanked out, so a scan for\n * placeholders reads only the statement. Same length in, same length out.\n *\n * Quotes double to escape themselves in SQL (`'it''s'`), which is why this\n * cannot be a regex the way the JavaScript lexer's strings can.\n */\nfunction stripSqlNoise(sql: string): string {\n\tlet out = \"\";\n\tlet i = 0;\n\twhile (i < sql.length) {\n\t\tconst c = sql[i]!;\n\n\t\tif (c === \"'\" || c === '\"') {\n\t\t\tconst quote = c;\n\t\t\tout += \" \";\n\t\t\ti++;\n\t\t\twhile (i < sql.length) {\n\t\t\t\tif (sql[i] === quote && sql[i + 1] === quote) {\n\t\t\t\t\tout += \" \";\n\t\t\t\t\ti += 2;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (sql[i] === quote) break;\n\t\t\t\tout += sql[i] === \"\\n\" ? \"\\n\" : \" \";\n\t\t\t\ti++;\n\t\t\t}\n\t\t\tif (i < sql.length) {\n\t\t\t\tout += \" \";\n\t\t\t\ti++;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (c === \"-\" && sql[i + 1] === \"-\") {\n\t\t\twhile (i < sql.length && sql[i] !== \"\\n\") {\n\t\t\t\tout += \" \";\n\t\t\t\ti++;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (c === \"/\" && sql[i + 1] === \"*\") {\n\t\t\tout += \" \";\n\t\t\ti += 2;\n\t\t\twhile (i < sql.length && !(sql[i] === \"*\" && sql[i + 1] === \"/\")) {\n\t\t\t\tout += sql[i] === \"\\n\" ? \"\\n\" : \" \";\n\t\t\t\ti++;\n\t\t\t}\n\t\t\tif (i < sql.length) {\n\t\t\t\tout += \" \";\n\t\t\t\ti += 2;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tout += c;\n\t\ti++;\n\t}\n\treturn out;\n}\n\nfunction blockOf(parsed: DslDocument, offset: number) {\n\treturn (\n\t\tparsed.blocks.find((b) => offset >= b.body.start && offset < b.body.end)\n\t\t\t?.kind ?? null\n\t);\n}\n\n/**\n * `if (…) { [field] = x }` on a single line mis-compiles — the assignment is\n * rewritten in place and the setter call is lost. One assignment per line.\n */\nfunction inlineAssignmentIssues(\n\tparsed: DslDocument,\n\tpositionAt: (offset: number) => { line: number; column: number },\n): DslIssue[] {\n\tconst out: DslIssue[] = [];\n\tfor (const ref of parsed.fieldRefs) {\n\t\t// `ref.endIndex` is where the parser stopped: a `.prop` hop is 2 tokens\n\t\t// but a `.[prop]` hop is 4, so the count cannot be derived here.\n\t\tconst assign = parsed.tokens[ref.endIndex + 1];\n\t\tif (!assign || assign.kind !== \"punct\" || assign.text !== \"=\") continue;\n\n\t\t// Walk back over this line only, looking for a brace that opened here.\n\t\tconst line = parsed.tokens[ref.startIndex]!.line;\n\t\tlet openedHere = false;\n\t\tfor (let i = ref.startIndex - 1; i >= 0; i--) {\n\t\t\tconst t = parsed.tokens[i]!;\n\t\t\tif (t.line !== line) break;\n\t\t\tif (t.text === \"{\") {\n\t\t\t\topenedHere = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (!openedHere) continue;\n\n\t\tconst pos = positionAt(ref.outerSpan.start);\n\t\tout.push({\n\t\t\trule: \"dsl/inline-assignment\",\n\t\t\tseverity: \"warning\",\n\t\t\tmessage:\n\t\t\t\t\"An assignment to a record field on the same line as the brace that opens its block mis-compiles. Put the assignment on its own line.\",\n\t\t\tstart: ref.outerSpan.start,\n\t\t\tend: ref.outerSpan.end,\n\t\t\tline: pos.line,\n\t\t\tcolumn: pos.column,\n\t\t});\n\t}\n\treturn out;\n}\n\n/**\n * Offset → 1-indexed line/column, over a line-start table built once per check.\n * Scanning the prefix per issue is O(n) each, and a body with many issues is\n * exactly the one where that shows.\n */\nfunction lineIndexer(text: string): (offset: number) => { line: number; column: number } {\n\tconst starts = [0];\n\tfor (let i = 0; i < text.length; i++) {\n\t\tif (text[i] === \"\\n\") starts.push(i + 1);\n\t}\n\treturn (offset: number) => {\n\t\t// Binary search for the last line start at or before `offset`.\n\t\tlet lo = 0;\n\t\tlet hi = starts.length - 1;\n\t\twhile (lo < hi) {\n\t\t\tconst mid = (lo + hi + 1) >> 1;\n\t\t\tif (starts[mid]! <= offset) lo = mid;\n\t\t\telse hi = mid - 1;\n\t\t}\n\t\treturn { line: lo + 1, column: offset - starts[lo]! + 1 };\n\t};\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/dsl/lexer.ts","../../src/dsl/parse.ts","../../src/dsl/builtins.ts","../../src/dsl/check.ts"],"sourcesContent":["// Hand-rolled lexer for the dForge action DSL.\n//\n// Deliberately not the tree-sitter grammar: that one exists to be compiled into\n// Zed, and pulling a native parser (or a wasm runtime) into an npx-launched\n// language server — or into a validator that runs before a pack — costs far\n// more than it buys for the handful of constructs the rules need.\n\nexport type TokenKind =\n\t| \"ident\"\n\t| \"number\"\n\t| \"string\"\n\t| \"template\"\n\t| \"regex\"\n\t| \"punct\"\n\t| \"comment\";\n\nexport interface Token {\n\tkind: TokenKind;\n\t/** Source text, verbatim — quotes included for strings. */\n\ttext: string;\n\tstart: number;\n\tend: number;\n\tline: number;\n\tcharacter: number;\n\t/** True when a line break sits between this token and the previous one. */\n\tstartsLine: boolean;\n}\n\nconst PUNCT3 = [\"===\", \"!==\"];\nconst PUNCT2 = [\n\t\"==\", \"!=\", \"<=\", \">=\", \"&&\", \"||\", \"++\", \"--\",\n\t\"+=\", \"-=\", \"*=\", \"/=\", \"%=\", \"${\", \"=>\",\n];\n\n/**\n * Template literals and the `${…}` holes in them. Inside a template we are\n * reading literal text; inside a hole we are reading code again, and the brace\n * count says which `}` closes it.\n */\ntype Frame =\n\t| { kind: \"template\"; chunkStart: number }\n\t| { kind: \"interp\"; braces: number };\n\n/**\n * Keywords whose `(…)` holds a condition rather than a parameter list. What\n * follows that `)` is a statement — so a regex may open there, and the brace\n * after it is not a function body.\n */\nexport const CONTROL_KEYWORDS = new Set([\n\t\"if\",\n\t\"while\",\n\t\"for\",\n\t\"switch\",\n\t\"catch\",\n\t\"with\",\n]);\n\nexport function tokenize(text: string): Token[] {\n\tconst tokens: Token[] = [];\n\tlet i = 0;\n\tlet line = 0;\n\tlet lineStart = 0;\n\tlet pendingLineBreak = true;\n\tconst frames: Frame[] = [];\n\t// Whether each open paren belongs to a control condition, so that the `)`\n\t// closing it is known to be followed by a statement.\n\tconst parenIsControl: boolean[] = [];\n\tlet closedControlParen = false;\n\t// Whether each open brace began a statement block rather than an object,\n\t// so that the `}` closing it is known to leave a statement position.\n\tconst braceIsBlock: boolean[] = [];\n\tlet closedBlockBrace = false;\n\n\tconst push = (kind: TokenKind, start: number, end: number) => {\n\t\ttokens.push({\n\t\t\tkind,\n\t\t\ttext: text.slice(start, end),\n\t\t\tstart,\n\t\t\tend,\n\t\t\tline,\n\t\t\tcharacter: start - lineStart,\n\t\t\tstartsLine: pendingLineBreak,\n\t\t});\n\t\tpendingLineBreak = false;\n\t};\n\n\twhile (i < text.length) {\n\t\tconst frame = frames[frames.length - 1];\n\n\t\t// ── literal text inside a template ──────────────────────────────\n\t\t// Emitted as one token per chunk, so the analyzer sees the code in\n\t\t// `${…}` but never the prose around it. The `${` closes the chunk\n\t\t// before it and the `}` opens the chunk after, which keeps the brace\n\t\t// count of anything reading these tokens balanced.\n\t\tif (frame?.kind === \"template\") {\n\t\t\tconst startLine = line;\n\t\t\tconst startLineStart = lineStart;\n\t\t\twhile (i < text.length) {\n\t\t\t\tconst ch = text[i]!;\n\t\t\t\tif (ch === \"\\\\\") {\n\t\t\t\t\ti += 2;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (ch === \"`\" || (ch === \"$\" && text[i + 1] === \"{\")) break;\n\t\t\t\tif (ch === \"\\n\") {\n\t\t\t\t\tline++;\n\t\t\t\t\tlineStart = i + 1;\n\t\t\t\t}\n\t\t\t\ti++;\n\t\t\t}\n\t\t\tif (text[i] === \"`\") {\n\t\t\t\ti++;\n\t\t\t\tframes.pop();\n\t\t\t} else if (i < text.length) {\n\t\t\t\ti += 2;\n\t\t\t\tframes.push({ kind: \"interp\", braces: 0 });\n\t\t\t} else {\n\t\t\t\tframes.pop(); // unterminated\n\t\t\t}\n\t\t\tconst savedLine = line;\n\t\t\tconst savedLineStart = lineStart;\n\t\t\tline = startLine;\n\t\t\tlineStart = startLineStart;\n\t\t\tpush(\"template\", frame.chunkStart, i);\n\t\t\tline = savedLine;\n\t\t\tlineStart = savedLineStart;\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst c = text[i]!;\n\n\t\t// A leading BOM is not a column. The compiler strips it before anchoring\n\t\t// block headers at `^execute:`, so the first real token must still land\n\t\t// at character 0 here or every block-scoped rule stands down.\n\t\tif (c === \"\\uFEFF\" && i === 0) {\n\t\t\ti++;\n\t\t\tlineStart = i;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (c === \"\\n\") {\n\t\t\ti++;\n\t\t\tline++;\n\t\t\tlineStart = i;\n\t\t\tpendingLineBreak = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (c === \" \" || c === \"\\t\" || c === \"\\r\") {\n\t\t\ti++;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (c === \"/\" && text[i + 1] === \"/\") {\n\t\t\tconst start = i;\n\t\t\twhile (i < text.length && text[i] !== \"\\n\") i++;\n\t\t\tpush(\"comment\", start, i);\n\t\t\tcontinue;\n\t\t}\n\t\tif (c === \"/\" && text[i + 1] === \"*\") {\n\t\t\tconst start = i;\n\t\t\tconst startLine = line;\n\t\t\tconst startLineStart = lineStart;\n\t\t\ti += 2;\n\t\t\twhile (i < text.length && !(text[i] === \"*\" && text[i + 1] === \"/\")) {\n\t\t\t\tif (text[i] === \"\\n\") {\n\t\t\t\t\tline++;\n\t\t\t\t\tlineStart = i + 1;\n\t\t\t\t}\n\t\t\t\ti++;\n\t\t\t}\n\t\t\ti = Math.min(i + 2, text.length);\n\t\t\t// Report the comment at its opening position, not its end.\n\t\t\tconst savedLine = line;\n\t\t\tconst savedLineStart = lineStart;\n\t\t\tline = startLine;\n\t\t\tlineStart = startLineStart;\n\t\t\tpush(\"comment\", start, i);\n\t\t\tline = savedLine;\n\t\t\tlineStart = savedLineStart;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (c === \"'\" || c === '\"') {\n\t\t\tconst start = i;\n\t\t\tconst quote = c;\n\t\t\ti++;\n\t\t\twhile (i < text.length && text[i] !== quote && text[i] !== \"\\n\") {\n\t\t\t\tif (text[i] === \"\\\\\") i++;\n\t\t\t\ti++;\n\t\t\t}\n\t\t\tif (text[i] === quote) i++;\n\t\t\tpush(\"string\", start, i);\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (c === \"`\") {\n\t\t\tframes.push({ kind: \"template\", chunkStart: i });\n\t\t\ti++;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (\n\t\t\tc === \"/\" &&\n\t\t\tregexAllowedAfter(\n\t\t\t\ttokens[tokens.length - 1],\n\t\t\t\tclosedControlParen,\n\t\t\t\tclosedBlockBrace,\n\t\t\t)\n\t\t) {\n\t\t\tconst end = scanRegex(text, i);\n\t\t\tif (end > 0) {\n\t\t\t\tpush(\"regex\", i, end);\n\t\t\t\ti = end;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\tif (/[0-9]/.test(c)) {\n\t\t\tconst start = i;\n\t\t\twhile (i < text.length && /[0-9._eE]/.test(text[i]!)) i++;\n\t\t\tpush(\"number\", start, i);\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (/[A-Za-z_$]/.test(c)) {\n\t\t\tconst start = i;\n\t\t\twhile (i < text.length && /[A-Za-z0-9_$]/.test(text[i]!)) i++;\n\t\t\tpush(\"ident\", start, i);\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (c === \"(\") {\n\t\t\tconst prev = tokens[tokens.length - 1];\n\t\t\tparenIsControl.push(\n\t\t\t\tprev?.kind === \"ident\" && CONTROL_KEYWORDS.has(prev.text),\n\t\t\t);\n\t\t} else if (c === \")\") {\n\t\t\tclosedControlParen = parenIsControl.pop() ?? false;\n\t\t}\n\n\t\tif (frame?.kind === \"interp\") {\n\t\t\tif (c === \"}\" && frame.braces === 0) {\n\t\t\t\tframes.pop();\n\t\t\t\t// The `}` opens the next literal chunk rather than becoming a\n\t\t\t\t// token of its own — see the chunk comment above.\n\t\t\t\t(frames[frames.length - 1] as { chunkStart: number }).chunkStart = i;\n\t\t\t\ti++;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (c === \"{\") frame.braces++;\n\t\t\telse if (c === \"}\") frame.braces--;\n\t\t}\n\n\t\tif (c === \"{\") {\n\t\t\tbraceIsBlock.push(isBlockBrace(tokens[tokens.length - 1]));\n\t\t} else if (c === \"}\") {\n\t\t\tclosedBlockBrace = braceIsBlock.pop() ?? false;\n\t\t}\n\n\t\tconst three = text.slice(i, i + 3);\n\t\tif (PUNCT3.includes(three)) {\n\t\t\tpush(\"punct\", i, i + 3);\n\t\t\ti += 3;\n\t\t\tcontinue;\n\t\t}\n\t\tconst two = text.slice(i, i + 2);\n\t\tif (PUNCT2.includes(two)) {\n\t\t\tpush(\"punct\", i, i + 2);\n\t\t\ti += 2;\n\t\t\tcontinue;\n\t\t}\n\t\tpush(\"punct\", i, i + 1);\n\t\ti++;\n\t}\n\n\treturn tokens;\n}\n\n/**\n * Whether a `/` here opens a regex literal rather than dividing. The usual\n * rule: a regex may start where an expression may start, so it follows an\n * operator or a keyword but not a value.\n *\n * A `)` depends on what it closed: after a control condition a statement\n * follows, so `if (x) /re/.test(s)` is a regex, while `(a + b) / 2` divides.\n * A template chunk likewise depends on which end it is — one that stops at\n * `${` opens an expression, one that ran to the closing backtick is a value.\n *\n * A `}` likewise depends on what it closed: ending a statement block leaves a\n * statement position, so `if (x) {}` may be followed by a regex, while an\n * object literal is a value and divides.\n */\nfunction regexAllowedAfter(\n\tprev: Token | undefined,\n\tclosedControlParen: boolean,\n\tclosedBlockBrace: boolean,\n): boolean {\n\tif (!prev) return true;\n\tif (prev.kind === \"number\" || prev.kind === \"string\") return false;\n\tif (prev.kind === \"template\") return prev.text.endsWith(\"${\");\n\tif (prev.kind === \"ident\") return REGEX_PRECEDING_KEYWORDS.has(prev.text);\n\tif (prev.kind === \"regex\") return false;\n\tif (prev.kind === \"comment\") return true;\n\tif (prev.text === \")\") return closedControlParen;\n\tif (prev.text === \"}\") return closedBlockBrace;\n\treturn !REGEX_BLOCKING_PUNCT.has(prev.text);\n}\n\n/**\n * Whether the `{` after `prev` opens a statement block rather than an object\n * literal. A block follows a condition, another block, a statement end or one\n * of the keywords that take a bare body; anything else — an `=`, a `(`, a `,`,\n * a `=>` — is expression position, where the brace is a value.\n */\nfunction isBlockBrace(prev: Token | undefined): boolean {\n\tif (!prev) return true;\n\tif (prev.kind === \"ident\") return BLOCK_PRECEDING_KEYWORDS.has(prev.text);\n\tif (prev.kind !== \"punct\") return false;\n\treturn prev.text === \")\" || prev.text === \"}\" || prev.text === \"{\" || prev.text === \";\";\n}\n\nconst BLOCK_PRECEDING_KEYWORDS = new Set([\"else\", \"do\", \"try\", \"finally\"]);\n\nconst REGEX_PRECEDING_KEYWORDS = new Set([\n\t\"return\", \"typeof\", \"instanceof\", \"in\", \"of\", \"new\", \"delete\", \"void\",\n\t\"case\", \"do\", \"else\", \"throw\", \"yield\", \"await\",\n]);\n\nconst REGEX_BLOCKING_PUNCT = new Set([\"]\", \"++\", \"--\"]);\n\n/**\n * End offset of the regex literal starting at `start`, or -1 if it is not one.\n * A `/` inside a character class does not close the literal, and a literal\n * never spans a line — hitting one means this was a division after all.\n */\nfunction scanRegex(text: string, start: number): number {\n\tlet i = start + 1;\n\tlet inClass = false;\n\t// An empty pattern would be the `//` comment the caller already handled.\n\tif (text[i] === \"/\" || text[i] === \"*\") return -1;\n\tfor (; i < text.length; i++) {\n\t\tconst c = text[i]!;\n\t\tif (c === \"\\\\\") {\n\t\t\ti++;\n\t\t\tcontinue;\n\t\t}\n\t\tif (c === \"\\n\") return -1;\n\t\tif (c === \"[\") inClass = true;\n\t\telse if (c === \"]\") inClass = false;\n\t\telse if (c === \"/\" && !inClass) {\n\t\t\ti++;\n\t\t\twhile (i < text.length && /[a-z]/.test(text[i]!)) i++;\n\t\t\treturn i;\n\t\t}\n\t}\n\treturn -1;\n}\n\n/** Strip the surrounding quotes from a string token's text. */\nexport function stringValue(token: Token): string {\n\tif (token.kind !== \"string\") return token.text;\n\tconst body = token.text.slice(1, token.text.endsWith(token.text[0]!) && token.text.length > 1 ? -1 : undefined);\n\treturn unescape(body);\n}\n\n/**\n * The literal text of one template chunk, delimiters removed. A chunk opens on\n * a backtick or on the `}` that closed the hole before it, and closes on a\n * backtick, on the `${` of the next hole, or on the end of the file.\n */\nexport function templateChunkValue(token: Token): string {\n\tif (token.kind !== \"template\") return token.text;\n\tconst body = token.text.slice(1);\n\tif (body.endsWith(\"${\")) return unescape(body.slice(0, -2));\n\tif (body.endsWith(\"`\")) return unescape(body.slice(0, -1));\n\treturn unescape(body);\n}\n\n// A switch, not a lookup table: the escaped character comes out of the script,\n// and an object would answer `\\c` from Object.prototype.\nfunction unescape(body: string): string {\n\treturn body.replace(/\\\\(.)/g, (_, ch: string) => {\n\t\tswitch (ch) {\n\t\t\tcase \"n\":\n\t\t\t\treturn \"\\n\";\n\t\t\tcase \"t\":\n\t\t\t\treturn \"\\t\";\n\t\t\tcase \"r\":\n\t\t\t\treturn \"\\r\";\n\t\t\tdefault:\n\t\t\t\treturn ch;\n\t\t}\n\t});\n}\n","// Structural scan of a .dsl file: blocks, param declarations, record-field\n// reads, ref navigation chains and built-in calls — everything the diagnostics,\n// completion, hover and definition features need, and nothing else.\n\nimport {\n\tCONTROL_KEYWORDS,\n\ttype Token,\n\tstringValue,\n\ttemplateChunkValue,\n\ttokenize,\n} from \"./lexer\";\n\n/**\n * In the order `ActionDslCompiler.ParseBlocks` expects them in a file.\n *\n * `BlockKind` derives from this array rather than standing beside it, so the\n * two cannot drift: the order check ranks a kind by its index here, and a kind\n * the array does not list could not have been produced in the first place.\n */\nexport const BLOCK_KINDS = [\n\t\"params\",\n\t\"canExecute\",\n\t\"schema\",\n\t\"onBeforeStart\",\n\t\"execute\",\n] as const;\n\nexport type BlockKind = (typeof BLOCK_KINDS)[number];\n\nconst BLOCK_BY_LOWER = new Map(BLOCK_KINDS.map((k) => [k.toLowerCase(), k]));\n\nexport interface Span {\n\tstart: number;\n\tend: number;\n}\n\nexport interface DslBlock {\n\tkind: BlockKind;\n\tlabel: Span;\n\t/** Span of the block body — label end to the next label (or EOF). */\n\tbody: Span;\n}\n\nexport interface DslParam {\n\tname: string;\n\tnameSpan: Span;\n\t/** fieldTypeCd, or the referenced entity code when `isRef`. */\n\ttype: string;\n\ttypeSpan: Span;\n\tisRef: boolean;\n\trequired: boolean;\n\tlabel?: string;\n}\n\n/**\n * A `[field]` read. `navigation` holds the property hops that follow it, each\n * remembering whether it was written `.[target]` or `.target`: the compiler\n * rewrites the FIRST hop either way, and then only a surviving `.[` is the\n * multi-hop compile error. A dotted tail is plain JavaScript on the value the\n * hop returned, so `[customer].[code]`, `[a].b.c` and `[plate].length` all\n * compile.\n */\nexport interface FieldRef {\n\tname: string;\n\tspan: Span;\n\t/** Span including the brackets. */\n\touterSpan: Span;\n\tnavigation: Array<{ name: string; span: Span; bracketed: boolean }>;\n\tblock: BlockKind | null;\n\t/**\n\t * False when the read is bound to a numbered record rather than the current\n\t * one — `records[0][status]`, which `RxRecordsFieldRead` rewrites ahead of\n\t * the generic `[field]` pass. The name is still a column of the entity, so\n\t * the column rules apply; the batch-mode rule does not.\n\t */\n\tisCurrentRecord: boolean;\n\t/** Index of the token that opens this read — the `[`. */\n\tstartIndex: number;\n\t/**\n\t * Index of the last token this read consumes, navigation included. A hop is\n\t * 2 tokens as `.prop` but 4 as `.[prop]`, so callers that need the token\n\t * after the read cannot compute it from `navigation.length`.\n\t */\n\tendIndex: number;\n}\n\n/** `params[x]` / `old[x]` — subscript reads off a DSL global. */\nexport interface GlobalRef {\n\tglobal: \"params\" | \"old\" | \"records\";\n\tproperty: string;\n\tspan: Span;\n\tblock: BlockKind | null;\n}\n\nexport interface CallRef {\n\tname: string;\n\tnameSpan: Span;\n\t/** First argument when it is a string or template literal — the entity code, usually. */\n\tfirstStringArg?: StringArg;\n\tblock: BlockKind | null;\n}\n\nexport interface StringArg {\n\tvalue: string;\n\tspan: Span;\n\t/**\n\t * A template literal with `${…}` holes, which `value` holds a space in\n\t * place of: literal text to read, but not a constant.\n\t */\n\tinterpolated: boolean;\n\t/** Index of the last token the literal consumes — its final chunk. */\n\tendIndex: number;\n}\n\nexport interface DslDocument {\n\tblocks: DslBlock[];\n\tparams: DslParam[];\n\tfieldRefs: FieldRef[];\n\tglobalRefs: GlobalRef[];\n\tcalls: CallRef[];\n\ttokens: Token[];\n\t/**\n\t * Every mention of `records`, subscript (`records[x]`) or bare\n\t * (`for x in records`). `globalRefs` only holds the subscript form, so a\n\t * rule that needs to point at the batch loop has nothing to anchor to.\n\t */\n\trecordsRefs: Span[];\n\t/** Names bound by `var`/`let`/`const` or a `for` head, plus declared params. */\n\tlocals: Set<string>;\n\t/**\n\t * Loop variables bound by `for x in records {` — `RxForLoop` and nothing\n\t * else, so an ordinary `for (var x of xs)` is not one. Their `x[field]`\n\t * subscripts read the entity's columns, which is why they come back as\n\t * field reads.\n\t */\n\trecordsLoopVars: Set<string>;\n}\n\nconst GLOBALS = new Set([\"params\", \"old\", \"records\"]);\n\nexport function parseDsl(text: string): DslDocument {\n\tconst all = tokenize(text);\n\tconst tokens = all.filter((t) => t.kind !== \"comment\");\n\n\tconst blocks = findBlocks(text, tokens);\n\tconst blockAt = (offset: number): BlockKind | null =>\n\t\tblocks.find((b) => offset >= b.body.start && offset < b.body.end)?.kind ??\n\t\tnull;\n\n\tconst params = parseParams(tokens, blocks);\n\tconst fieldRefs: FieldRef[] = [];\n\tconst globalRefs: GlobalRef[] = [];\n\tconst calls: CallRef[] = [];\n\tconst recordsRefs: Span[] = [];\n\tconst locals = collectLocals(tokens, params);\n\tconst recordsLoopVars = collectRecordsLoopVars(tokens);\n\n\tfor (let i = 0; i < tokens.length; i++) {\n\t\tconst t = tokens[i]!;\n\n\t\tif (t.kind === \"punct\" && t.text === \"[\" && isFieldAccessStart(text, t.start)) {\n\t\t\tconst name = tokens[i + 1];\n\t\t\tconst close = tokens[i + 2];\n\t\t\tif (name?.kind === \"ident\" && close?.text === \"]\") {\n\t\t\t\tconst ref: FieldRef = {\n\t\t\t\t\tname: name.text,\n\t\t\t\t\tspan: { start: name.start, end: name.end },\n\t\t\t\t\touterSpan: { start: t.start, end: close.end },\n\t\t\t\t\tnavigation: [],\n\t\t\t\t\tblock: blockAt(t.start),\n\t\t\t\t\tisCurrentRecord: true,\n\t\t\t\t\tstartIndex: i,\n\t\t\t\t\tendIndex: i + 2,\n\t\t\t\t};\n\t\t\t\tref.endIndex = collectNavigation(tokens, i + 2, ref);\n\t\t\t\ti = ref.endIndex;\n\t\t\t\tfieldRefs.push(ref);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\t// `x.records` is a property, not the batch global.\n\t\tif (t.kind === \"ident\" && t.text === \"records\" && tokens[i - 1]?.text !== \".\") {\n\t\t\trecordsRefs.push({ start: t.start, end: t.end });\n\n\t\t\t// `records[0][status]` is one read of a numbered record. Taken\n\t\t\t// apart, its tail looks exactly like a current-record read — which\n\t\t\t// is why the compiler rewrites this form first.\n\t\t\tconst field = indexedRecordField(tokens, i);\n\t\t\tif (field) {\n\t\t\t\tfieldRefs.push({\n\t\t\t\t\tname: field.name.text,\n\t\t\t\t\tspan: { start: field.name.start, end: field.name.end },\n\t\t\t\t\touterSpan: { start: field.open.start, end: field.close.end },\n\t\t\t\t\tnavigation: [],\n\t\t\t\t\tblock: blockAt(t.start),\n\t\t\t\t\tisCurrentRecord: false,\n\t\t\t\t\tstartIndex: field.openIndex,\n\t\t\t\t\tendIndex: field.openIndex + 2,\n\t\t\t\t});\n\t\t\t\ti = field.openIndex + 2;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\t// `x[field]` on a batch loop variable. The compiler rewrites it to\n\t\t// `x.get('field')` and checks the name against the entity's columns\n\t\t// exactly as it checks a bare `[field]`.\n\t\tif (t.kind === \"ident\" && recordsLoopVars.has(t.text)) {\n\t\t\tconst open = tokens[i + 1];\n\t\t\tconst name = tokens[i + 2];\n\t\t\tconst close = tokens[i + 3];\n\t\t\tif (open?.text === \"[\" && name?.kind === \"ident\" && close?.text === \"]\") {\n\t\t\t\tfieldRefs.push({\n\t\t\t\t\tname: name.text,\n\t\t\t\t\tspan: { start: name.start, end: name.end },\n\t\t\t\t\touterSpan: { start: open.start, end: close.end },\n\t\t\t\t\tnavigation: [],\n\t\t\t\t\tblock: blockAt(t.start),\n\t\t\t\t\tisCurrentRecord: false,\n\t\t\t\t\tstartIndex: i + 1,\n\t\t\t\t\tendIndex: i + 3,\n\t\t\t\t});\n\t\t\t\ti += 3;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\tif (t.kind === \"ident\" && GLOBALS.has(t.text)) {\n\t\t\tconst open = tokens[i + 1];\n\t\t\tconst prop = tokens[i + 2];\n\t\t\tconst close = tokens[i + 3];\n\t\t\tif (open?.text === \"[\" && prop?.kind === \"ident\" && close?.text === \"]\") {\n\t\t\t\tglobalRefs.push({\n\t\t\t\t\tglobal: t.text as GlobalRef[\"global\"],\n\t\t\t\t\tproperty: prop.text,\n\t\t\t\t\tspan: { start: prop.start, end: prop.end },\n\t\t\t\t\tblock: blockAt(t.start),\n\t\t\t\t});\n\t\t\t\ti += 3;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\tif (t.kind === \"ident\" && tokens[i + 1]?.text === \"(\") {\n\t\t\tconst prev = tokens[i - 1];\n\t\t\t// `.method(` is a call on a value, not a DSL built-in.\n\t\t\tif (prev?.text === \".\") continue;\n\t\t\tconst call: CallRef = {\n\t\t\t\tname: t.text,\n\t\t\t\tnameSpan: { start: t.start, end: t.end },\n\t\t\t\tblock: blockAt(t.start),\n\t\t\t};\n\t\t\tconst firstArg = tokens[i + 2];\n\t\t\tif (firstArg?.kind === \"string\") {\n\t\t\t\tcall.firstStringArg = {\n\t\t\t\t\tvalue: stringValue(firstArg),\n\t\t\t\t\tspan: { start: firstArg.start, end: firstArg.end },\n\t\t\t\t\tinterpolated: false,\n\t\t\t\t\tendIndex: i + 2,\n\t\t\t\t};\n\t\t\t} else if (firstArg?.kind === \"template\" && firstArg.text.startsWith(\"`\")) {\n\t\t\t\tcall.firstStringArg = templateArg(tokens, i + 2);\n\t\t\t}\n\t\t\tcalls.push(call);\n\t\t}\n\t}\n\n\treturn {\n\t\tblocks,\n\t\tparams,\n\t\tfieldRefs,\n\t\tglobalRefs,\n\t\tcalls,\n\t\ttokens,\n\t\trecordsRefs,\n\t\tlocals,\n\t\trecordsLoopVars,\n\t};\n}\n\n/**\n * `[` opens a record-field read unless a word character sits immediately\n * before it — the compiler's `(?<!\\w)\\[(\\w+)\\]`, character for character.\n *\n * It has to be the character and not the previous token: the lookbehind does\n * not skip whitespace, so `rec[qty]` is a subscript but `[qty]` opening a line\n * is a read however the line above ended. The same lookbehind is what keeps\n * `params[x]` and `old[x]` out of the field reads.\n *\n * A single-element array literal (`var ids = [orderId]`) is genuinely\n * ambiguous with a field read at this level: both are `[ident]` in expression\n * position, and `var total = [qty]` is a real field read. The disambiguation\n * needs to know whether the name is a column or a local, so it happens in the\n * diagnostics layer against `locals` rather than here.\n */\nfunction isFieldAccessStart(text: string, start: number): boolean {\n\treturn start === 0 || !/\\w/.test(text[start - 1]!);\n}\n\n/**\n * A template literal, read back from the chunks the lexer split it into. The\n * walk has to count nested templates, because one opened inside a `${…}` hole\n * emits chunks of its own between ours.\n *\n * Each hole becomes a single space. The callers read the text as SQL, and a\n * spliced value is not part of the statement they are reading — but the gap\n * has to stay a gap, or the words either side of it would run together.\n */\nfunction templateArg(tokens: Token[], start: number): StringArg {\n\tconst parts: string[] = [];\n\tlet depth = 0;\n\tlet interpolated = false;\n\tlet last = tokens[start]!;\n\tlet endIndex = start;\n\n\tfor (let j = start; j < tokens.length; j++) {\n\t\tconst t = tokens[j]!;\n\t\tif (t.kind !== \"template\") continue;\n\n\t\tconst opens = t.text.startsWith(\"`\");\n\t\tif (opens) depth++;\n\t\tif (depth === 1) {\n\t\t\tif (!opens) parts.push(\" \");\n\t\t\tparts.push(templateChunkValue(t));\n\t\t\tlast = t;\n\t\t\tendIndex = j;\n\t\t}\n\t\tif (t.text.endsWith(\"${\")) {\n\t\t\tif (depth === 1) interpolated = true;\n\t\t\tcontinue;\n\t\t}\n\t\t// Anything else ends the template: a closing backtick, or the end of\n\t\t// the file on an unterminated one.\n\t\tdepth--;\n\t\tif (depth === 0) break;\n\t}\n\n\treturn {\n\t\tvalue: parts.join(\"\"),\n\t\tspan: { start: tokens[start]!.start, end: last.end },\n\t\tinterpolated,\n\t\tendIndex,\n\t};\n}\n\n\n/**\n * The `[field]` half of a `records[n][field]` read starting at `i`, or null.\n *\n * Mirrors `RxRecordsFieldRead`'s `\\brecords\\[(\\d+)\\]\\[(\\w+)\\]`: a literal\n * digit index only. `records[i][x]` with a variable index is not this form for\n * the compiler either — it leaves `records[i]` alone and then rewrites the tail\n * as a current-record read.\n */\nfunction indexedRecordField(\n\ttokens: Token[],\n\ti: number,\n): { name: Token; open: Token; close: Token; openIndex: number } | null {\n\tconst index = tokens[i + 2];\n\tif (tokens[i + 1]?.text !== \"[\") return null;\n\tif (index?.kind !== \"number\" || !/^\\d+$/.test(index.text)) return null;\n\tif (tokens[i + 3]?.text !== \"]\") return null;\n\n\tconst open = tokens[i + 4];\n\tconst name = tokens[i + 5];\n\tconst close = tokens[i + 6];\n\tif (open?.text !== \"[\" || name?.kind !== \"ident\" || close?.text !== \"]\")\n\t\treturn null;\n\treturn { name, open, close, openIndex: i + 4 };\n}\n\n/** Walk `.prop` / `.[prop]` hops after a field read. Returns the last index consumed. */\nfunction collectNavigation(tokens: Token[], closeIdx: number, ref: FieldRef): number {\n\tlet i = closeIdx;\n\tfor (;;) {\n\t\tconst dot = tokens[i + 1];\n\t\tif (dot?.text !== \".\") return i;\n\t\tconst next = tokens[i + 2];\n\t\tif (next?.kind === \"ident\") {\n\t\t\t// A method call is not navigation — `[items].length` is, `[x].trim()` isn't.\n\t\t\tif (tokens[i + 3]?.text === \"(\") return i;\n\t\t\tref.navigation.push({\n\t\t\t\tname: next.text,\n\t\t\t\tspan: { start: next.start, end: next.end },\n\t\t\t\tbracketed: false,\n\t\t\t});\n\t\t\ti += 2;\n\t\t\tcontinue;\n\t\t}\n\t\tif (next?.text === \"[\") {\n\t\t\tconst name = tokens[i + 3];\n\t\t\tconst close = tokens[i + 4];\n\t\t\tif (name?.kind === \"ident\" && close?.text === \"]\") {\n\t\t\t\tref.navigation.push({\n\t\t\t\t\tname: name.text,\n\t\t\t\t\tspan: { start: name.start, end: name.end },\n\t\t\t\t\tbracketed: true,\n\t\t\t\t});\n\t\t\t\ti += 4;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\t\treturn i;\n\t}\n}\n\n/**\n * `for x in records {` — `RxForLoop`'s shape, brace included. A loop written\n * any other way is not a batch loop to the compiler either, and its variable\n * does not carry record fields.\n */\nfunction collectRecordsLoopVars(tokens: Token[]): Set<string> {\n\tconst vars = new Set<string>();\n\tfor (let i = 0; i < tokens.length - 4; i++) {\n\t\tif (tokens[i]!.text !== \"for\" || tokens[i]!.kind !== \"ident\") continue;\n\t\tconst name = tokens[i + 1]!;\n\t\tif (name.kind !== \"ident\") continue;\n\t\tif (tokens[i + 2]!.text !== \"in\" || tokens[i + 3]!.text !== \"records\") continue;\n\t\tif (tokens[i + 4]!.text !== \"{\") continue;\n\t\tvars.add(name.text);\n\t}\n\treturn vars;\n}\n\nconst DECLARATORS = new Set([\"var\", \"let\", \"const\"]);\n\n/**\n * Names bound in the script itself. Used to tell `var ids = [orderId]` (an\n * array literal holding a local) from `[qty]` (a record-field read) — the two\n * are indistinguishable by token shape alone.\n */\nfunction collectLocals(tokens: Token[], params: DslParam[]): Set<string> {\n\tconst locals = new Set<string>(params.map((p) => p.name));\n\tcollectFunctionParams(tokens, locals);\n\tfor (let i = 0; i < tokens.length; i++) {\n\t\tconst t = tokens[i]!;\n\t\tif (t.kind !== \"ident\") continue;\n\n\t\tif (DECLARATORS.has(t.text)) {\n\t\t\tcollectDeclarations(tokens, i + 1, locals);\n\t\t\tcontinue;\n\t\t}\n\n\t\t// `for x in records` / `for (var x of xs)` — the loop variable.\n\t\tif (t.text === \"for\") {\n\t\t\tlet j = i + 1;\n\t\t\tif (tokens[j]?.text === \"(\") j++;\n\t\t\tif (tokens[j]?.kind === \"ident\" && DECLARATORS.has(tokens[j]!.text)) j++;\n\t\t\tconst name = tokens[j];\n\t\t\tif (name?.kind === \"ident\" && !DECLARATORS.has(name.text)) locals.add(name.text);\n\t\t}\n\t}\n\treturn locals;\n}\n\n/**\n * Parameter names of every function in the script — declarations, expressions,\n * arrows and method shorthand. They bind names exactly as `var` does, so\n * `function wrap(value) { return [value] }` holds an array literal rather than\n * a field read.\n */\nfunction collectFunctionParams(tokens: Token[], locals: Set<string>): void {\n\tfor (let i = 0; i < tokens.length; i++) {\n\t\tconst t = tokens[i]!;\n\n\t\tif (t.kind === \"ident\" && t.text === \"function\") {\n\t\t\tlet j = i + 1;\n\t\t\tif (tokens[j]?.kind === \"ident\") j++; // the name, when it has one\n\t\t\tif (tokens[j]?.text === \"(\") collectParenIdents(tokens, j, locals);\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (t.text === \"=>\") {\n\t\t\tconst prev = tokens[i - 1];\n\t\t\t// `x => …` binds one name; `(x, y) => …` binds the list.\n\t\t\tif (prev?.kind === \"ident\") locals.add(prev.text);\n\t\t\telse if (prev?.text === \")\") {\n\t\t\t\tconst open = matchingOpenParen(tokens, i - 1);\n\t\t\t\tif (open >= 0) collectParenIdents(tokens, open, locals);\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Method shorthand `f(a, b) { … }`. The body brace is what tells it from\n\t\t// a call, and a control keyword's `(…)` is a condition, not a list.\n\t\tif (\n\t\t\tt.kind === \"ident\" &&\n\t\t\t!CONTROL_KEYWORDS.has(t.text) &&\n\t\t\ttokens[i + 1]?.text === \"(\"\n\t\t) {\n\t\t\tconst close = matchingCloseParen(tokens, i + 1);\n\t\t\tif (close >= 0 && tokens[close + 1]?.text === \"{\")\n\t\t\t\tcollectParenIdents(tokens, i + 1, locals);\n\t\t}\n\t}\n}\n\n/**\n * Every ident between the `(` at `openIndex` and its match. Over-collects a\n * default value's names (`f(x = y)`), which only ever suppresses a diagnostic —\n * the same fail-open trade `collectPattern` makes.\n */\nfunction collectParenIdents(\n\ttokens: Token[],\n\topenIndex: number,\n\tlocals: Set<string>,\n): void {\n\tlet depth = 0;\n\tfor (let i = openIndex; i < tokens.length; i++) {\n\t\tconst t = tokens[i]!;\n\t\tif (t.text === \"(\") depth++;\n\t\telse if (t.text === \")\") {\n\t\t\tdepth--;\n\t\t\tif (depth === 0) return;\n\t\t} else if (t.kind === \"ident\") locals.add(t.text);\n\t}\n}\n\nfunction matchingCloseParen(tokens: Token[], openIndex: number): number {\n\tlet depth = 0;\n\tfor (let i = openIndex; i < tokens.length; i++) {\n\t\tif (tokens[i]!.text === \"(\") depth++;\n\t\telse if (tokens[i]!.text === \")\" && --depth === 0) return i;\n\t}\n\treturn -1;\n}\n\nfunction matchingOpenParen(tokens: Token[], closeIndex: number): number {\n\tlet depth = 0;\n\tfor (let i = closeIndex; i >= 0; i--) {\n\t\tif (tokens[i]!.text === \")\") depth++;\n\t\telse if (tokens[i]!.text === \"(\" && --depth === 0) return i;\n\t}\n\treturn -1;\n}\n\n/**\n * The binding list after a declarator: `a = 1, b = 2`, where each binding is\n * either a name or a destructuring pattern. Scans ahead without moving the\n * caller's cursor, so a `var` nested in an initializer is still visited.\n */\nfunction collectDeclarations(tokens: Token[], start: number, locals: Set<string>): void {\n\tlet j = start;\n\tfor (;;) {\n\t\tconst head = tokens[j];\n\t\tif (!head) return;\n\n\t\tif (head.text === \"{\" || head.text === \"[\") {\n\t\t\tj = collectPattern(tokens, j, locals);\n\t\t} else if (head.kind === \"ident\" && !DECLARATORS.has(head.text)) {\n\t\t\tlocals.add(head.text);\n\t\t\tj++;\n\t\t} else return;\n\n\t\t// Skip this binding's initializer and stop at the comma opening the\n\t\t// next one. Commas inside the initializer sit at depth 1+ (`f(x, y)`),\n\t\t// which is what keeps its arguments out of `locals`.\n\t\tlet depth = 0;\n\t\tfor (; j < tokens.length; j++) {\n\t\t\tconst n = tokens[j]!;\n\t\t\tif (n.text === \"(\" || n.text === \"[\" || n.text === \"{\") depth++;\n\t\t\telse if (n.text === \")\" || n.text === \"]\" || n.text === \"}\") depth--;\n\t\t\tif (depth < 0) return;\n\t\t\tif (depth > 0) continue;\n\t\t\tif (n.text === \";\") return;\n\t\t\tif (n.text === \",\") break;\n\t\t\t// A new line at depth 0 ends the statement; the alternative is\n\t\t\t// running to end-of-file on a declaration with no terminator.\n\t\t\tif (n.startsLine) return;\n\t\t}\n\t\tif (j >= tokens.length) return;\n\t\tj++;\n\t}\n}\n\n/**\n * Every ident inside a `{…}` / `[…]` binding pattern; returns the index after\n * it. The names of a pattern sit at depth 1+, out of reach of the comma rule\n * in `collectDeclarations`. This over-collects — the `a` of `{ a: b }` binds\n * nothing — but a name in `locals` only ever suppresses a diagnostic, so the\n * error is in the fail-open direction.\n */\nfunction collectPattern(tokens: Token[], start: number, locals: Set<string>): number {\n\tlet depth = 0;\n\tlet i = start;\n\tfor (; i < tokens.length; i++) {\n\t\tconst t = tokens[i]!;\n\t\tif (t.text === \"{\" || t.text === \"[\") depth++;\n\t\telse if (t.text === \"}\" || t.text === \"]\") {\n\t\t\tdepth--;\n\t\t\tif (depth === 0) return i + 1;\n\t\t} else if (t.kind === \"ident\") locals.add(t.text);\n\t}\n\treturn i;\n}\n\n/**\n * The block kind labelled at `i`, wherever on the line it sits.\n *\n * `findBlocks` additionally requires column 0, which is what the compiler's\n * `^execute:` anchor means. The un-anchored form exists for the diagnostic\n * that reports an indented header — body text as far as the compiler is\n * concerned, leaving the block it meant to open empty.\n */\nexport function blockLabelAt(\n\ttokens: Token[],\n\ti: number,\n): { kind: BlockKind; span: Span } | null {\n\tconst t = tokens[i];\n\tif (!t || t.kind !== \"ident\" || !t.startsLine) return null;\n\tconst colon = tokens[i + 1];\n\t// `params :` does not match `^params:` either.\n\tif (colon?.text !== \":\" || colon.start !== t.end) return null;\n\tconst kind = BLOCK_BY_LOWER.get(t.text.toLowerCase());\n\treturn kind ? { kind, span: { start: t.start, end: colon.end } } : null;\n}\n\nfunction findBlocks(text: string, tokens: Token[]): DslBlock[] {\n\tconst labels: Array<{ kind: BlockKind; span: Span }> = [];\n\tfor (let i = 0; i < tokens.length; i++) {\n\t\tconst t = tokens[i]!;\n\t\t// Column 0, like the compiler's `^`-anchored headers: an indented\n\t\t// `params:` is an object key inside a block body, not a new block.\n\t\tif (t.character !== 0) continue;\n\t\tconst label = blockLabelAt(tokens, i);\n\t\tif (!label) continue;\n\t\tlabels.push(label);\n\t\t// `execute:` is `(.*?)\\z` — it runs to end-of-file, so a later header\n\t\t// is body text.\n\t\tif (label.kind === \"execute\") break;\n\t}\n\n\treturn labels.map((l, idx) => ({\n\t\tkind: l.kind,\n\t\tlabel: l.span,\n\t\tbody: {\n\t\t\tstart: l.span.end,\n\t\t\tend: labels[idx + 1]?.span.start ?? text.length,\n\t\t},\n\t}));\n}\n\nfunction parseParams(tokens: Token[], blocks: DslBlock[]): DslParam[] {\n\tconst block = blocks.find((b) => b.kind === \"params\");\n\tif (!block) return [];\n\n\tconst inBlock = tokens.filter(\n\t\t(t) => t.start >= block.body.start && t.start < block.body.end,\n\t);\n\tconst params: DslParam[] = [];\n\n\tfor (let i = 0; i < inBlock.length; i++) {\n\t\tconst name = inBlock[i]!;\n\t\t// One declaration per line — and `^params:\\s*` swallows the newline, so\n\t\t// the header's own line counts: `params: qty: number required` declares\n\t\t// qty exactly as an indented line below would.\n\t\tif ((!name.startsLine && i !== 0) || name.kind !== \"ident\") continue;\n\t\tif (inBlock[i + 1]?.text !== \":\") continue;\n\n\t\tlet j = i + 2;\n\t\tlet isRef = false;\n\t\tif (inBlock[j]?.kind === \"ident\" && inBlock[j]!.text === \"ref\") {\n\t\t\tisRef = true;\n\t\t\tj++;\n\t\t}\n\t\tconst type = inBlock[j];\n\t\tif (!type || type.kind !== \"ident\") continue;\n\t\t// RxParamDecl matches one trimmed line, so the type shares the name's\n\t\t// line. Without this a bare `execute:` swallows the next line's first\n\t\t// word as its type and passes for a declaration.\n\t\tif (type.line !== name.line) continue;\n\n\t\t// A `ref` target may be qualified and hyphenated: `ref fin-ch.invoice`.\n\t\t// The lexer splits on `-` and `.`, so glue back any pieces that are\n\t\t// physically adjacent — a space means the name ended.\n\t\tlet typeEnd = type.end;\n\t\tlet typeText = type.text;\n\t\tif (isRef) {\n\t\t\twhile (\n\t\t\t\tinBlock[j + 1] &&\n\t\t\t\t(inBlock[j + 1]!.text === \"-\" || inBlock[j + 1]!.text === \".\") &&\n\t\t\t\tinBlock[j + 2]?.kind === \"ident\" &&\n\t\t\t\tinBlock[j + 1]!.start === typeEnd &&\n\t\t\t\tinBlock[j + 2]!.start === inBlock[j + 1]!.end\n\t\t\t) {\n\t\t\t\ttypeText += inBlock[j + 1]!.text + inBlock[j + 2]!.text;\n\t\t\t\ttypeEnd = inBlock[j + 2]!.end;\n\t\t\t\tj += 2;\n\t\t\t}\n\t\t}\n\n\t\tlet required = false;\n\t\tlet label: string | undefined;\n\t\tfor (let k = j + 1; k < inBlock.length && !inBlock[k]!.startsLine; k++) {\n\t\t\tconst t = inBlock[k]!;\n\t\t\tif (t.kind === \"ident\" && t.text === \"required\") required = true;\n\t\t\tif (t.kind === \"string\" && label === undefined) label = stringValue(t);\n\t\t}\n\n\t\tparams.push({\n\t\t\tname: name.text,\n\t\t\tnameSpan: { start: name.start, end: name.end },\n\t\t\ttype: typeText,\n\t\t\ttypeSpan: { start: type.start, end: typeEnd },\n\t\t\tisRef,\n\t\t\trequired,\n\t\t\tlabel,\n\t\t});\n\t}\n\n\treturn params;\n}\n","// The DSL's platform globals. Signatures and prose track\n// dforge-mcp/skills/dforge-mcp-author/references/action-dsl.md — that file is\n// the source of truth; re-sync when it changes.\n\nexport interface Builtin {\n\tname: string;\n\tsignature: string;\n\treturns: string;\n\tdoc: string;\n\t/**\n\t * Index of the argument that names an entity, when the built-in takes one.\n\t * Drives entity-code completion and the qualify-your-codes diagnostic.\n\t */\n\tentityArg?: number;\n}\n\nexport const BUILTINS: Builtin[] = [\n\t// Data operations\n\t{\n\t\tname: \"insert\",\n\t\tsignature: \"insert(entity, fields)\",\n\t\treturns: \"object\",\n\t\tentityArg: 0,\n\t\tdoc: \"Insert a new record. Returns the full row including auto-filled columns (PK, audit, number sequences).\",\n\t},\n\t{\n\t\tname: \"select\",\n\t\tsignature: \"select(entity, opts?)\",\n\t\treturns: \"object[]\",\n\t\tentityArg: 0,\n\t\tdoc: \"Structured multi-row read. `opts` = `{columns, filter, orderBy, limit, offset}`. Prefer over `query()` for row-shaped reads.\",\n\t},\n\t{\n\t\tname: \"update\",\n\t\tsignature: \"update(entity, key, fields)\",\n\t\treturns: \"number\",\n\t\tentityArg: 0,\n\t\tdoc: \"Update the row(s) matched by `key`; returns rows affected. A value may be `{ inc: n }` to add to the column's current value — use that for every counter, balance and quantity.\",\n\t},\n\t{\n\t\tname: \"delete\",\n\t\tsignature: \"delete(entity, key)\",\n\t\treturns: \"number\",\n\t\tentityArg: 0,\n\t\tdoc: \"Delete the row(s) matched by `key`; returns rows affected.\",\n\t},\n\t{\n\t\tname: \"query\",\n\t\tsignature: \"query(sql, args?)\",\n\t\treturns: \"object[]\",\n\t\tdoc: \"Execute parameterized SQL with `@argName` placeholders and schema-qualified table names. Escape hatch — prefer `select()` / `update()` / `delete()` when the structured shape fits.\",\n\t},\n\t{\n\t\tname: \"getRecord\",\n\t\tsignature: \"getRecord(entity, key)\",\n\t\treturns: \"object\",\n\t\tentityArg: 0,\n\t\tdoc: \"Fetch a single record by key. **Throws** a localized not-found error when absent.\",\n\t},\n\t{\n\t\tname: \"getRecordOrNull\",\n\t\tsignature: \"getRecordOrNull(entity, key)\",\n\t\treturns: \"object | null\",\n\t\tentityArg: 0,\n\t\tdoc: \"Like `getRecord`, but returns `null` instead of throwing — for an expected absence, guarded with `if (rec == null)`.\",\n\t},\n\t{\n\t\tname: \"preloadRef\",\n\t\tsignature: \"preloadRef(fkColumn)\",\n\t\treturns: \"object\",\n\t\tdoc: \"Load the referenced record for a FK column. Read its fields with `ref.get('field')`.\",\n\t},\n\n\t// Messaging\n\t{\n\t\tname: \"error\",\n\t\tsignature: \"error(message)\",\n\t\treturns: \"never\",\n\t\tdoc: \"Abort the action and show an error. Rolls back all changes.\",\n\t},\n\t{ name: \"warn\", signature: \"warn(message)\", returns: \"void\", doc: \"Show a warning and continue.\" },\n\t{\n\t\tname: \"info\",\n\t\tsignature: \"info(message)\",\n\t\treturns: \"void\",\n\t\tdoc: \"Show an informational message — a receipt for work the action did, not a way to publish a computed value.\",\n\t},\n\t{\n\t\tname: \"exit\",\n\t\tsignature: \"exit(message?, level?)\",\n\t\treturns: \"never\",\n\t\tdoc: \"Stop the script early **without** error, keeping changes made so far. Level `'info'` (default) or `'warn'`. This is the DSL's early return — the block compiles to a bare script, so a `return` outside a function is a syntax error wherever it sits.\",\n\t},\n\t{\n\t\tname: \"notify\",\n\t\tsignature: \"notify(userId, message)\",\n\t\treturns: \"void\",\n\t\tdoc: \"Send an in-app notification to a specific user.\",\n\t},\n\t{\n\t\tname: \"sendEmail\",\n\t\tsignature: \"sendEmail(to, subjectOrTemplate, dataOrBody?)\",\n\t\treturns: \"void\",\n\t\tdoc: \"Queue an outbound email. Three arguments, and the **second** picks the mode: `sendEmail(to, 'order.shipped', { ref: [code] })` sends a template, `sendEmail(to, 'Your order shipped', '<p>…</p>')` sends raw HTML. A second argument with no spaces that contains `.` or `_` is read as a template code — so a raw subject like `'Shipped.'` silently becomes one; give a raw subject spaces. There is no fourth argument.\",\n\t},\n\n\t// External calls\n\t{\n\t\tname: \"callApi\",\n\t\tsignature: \"callApi(url, method, headers?, body?)\",\n\t\treturns: \"string\",\n\t\tdoc: \"HTTP request to an external API; returns the body as a string. Max 10 calls per script, 120s timeout, 5MB response.\",\n\t},\n\t{\n\t\tname: \"callService\",\n\t\tsignature: \"callService(name, args)\",\n\t\treturns: \"any\",\n\t\tdoc: \"Invoke a registered host service.\",\n\t},\n\t{\n\t\tname: \"callProc\",\n\t\tsignature: \"callProc(procName, args)\",\n\t\treturns: \"any\",\n\t\tdoc: \"Call a stored procedure with named parameters.\",\n\t},\n\n\t// Files, settings, extraction\n\t{\n\t\tname: \"getFileBase64\",\n\t\tsignature: \"getFileBase64(fileField)\",\n\t\treturns: \"string\",\n\t\tdoc: \"Read a file from storage as base64. Use with `callApi()` to send files to external APIs. Max 10 MB.\",\n\t},\n\t{\n\t\tname: \"getFileUrl\",\n\t\tsignature: \"getFileUrl(fileField)\",\n\t\treturns: \"string\",\n\t\tdoc: \"Temporary signed download URL (relative path) for a file field — for emails and notifications, not for `callApi()`.\",\n\t},\n\t{ name: \"getFileInfo\", signature: \"getFileInfo(fileField)\", returns: \"object | null\", doc: \"File metadata for a file field.\" },\n\t{\n\t\tname: \"download\",\n\t\tsignature: \"download(url, fileName?)\",\n\t\treturns: \"void\",\n\t\tdoc: \"Set a download URL on the action result; the browser opens it when the action returns. It fetches nothing and stores nothing — the URL must already serve the bytes, e.g. the `/api/temp-file/{token}` a service handed back. To put a remote file INTO storage, fetch it with `callApi()` and write it to a file column.\",\n\t},\n\t{\n\t\tname: \"getSetting\",\n\t\tsignature: \"getSetting(settingCd)\",\n\t\treturns: \"any\",\n\t\tdoc: \"Read a module setting, resolved through the folder chain (current folder → parents → module default).\",\n\t},\n\t{\n\t\tname: \"getSecret\",\n\t\tsignature: \"getSecret(secretCd)\",\n\t\treturns: \"string\",\n\t\tdoc: \"Retrieve a decrypted secret (API key, token). Managed in the admin UI.\",\n\t},\n\t{\n\t\tname: \"ocrExtract\",\n\t\tsignature: \"ocrExtract(fileField, endpointBaseUrl, schema?, opts?)\",\n\t\treturns: \"string (v1) | object (v2)\",\n\t\tdoc: \"Run OCR extraction against a document. **The return type follows the mode, and only `opts.mode` selects it** — a third argument alone never does. Without `opts.mode` (v1) the third argument is forwarded as `hints` and the result is the raw bundle as a JSON **string**: `JSON.parse()` it, or every property read is `undefined`. With `{ mode: 'extract' }` the third argument is a schema object and the result is already parsed — `{ fields, confidence?, unmatched, raw_text, meta }`. `{ mode: 'summary' }` needs no schema and returns `{ summary, raw_text, meta }` parsed. `{ profile: 'module_cd.profile_cd' }` uses a registered extraction profile, implies mode `extract`, and cannot be combined with an inline schema. The OCR host must be on `Dsl:Limits:AllowedHosts`.\",\n\t},\n\t{\n\t\tname: \"detectDocument\",\n\t\tsignature: \"detectDocument(rawText)\",\n\t\treturns: \"object | null\",\n\t\tdoc: \"Score text against reachable extraction profiles; returns the best match `{ profile, docType, score }` or `null`.\",\n\t},\n\t{\n\t\tname: \"applyProfile\",\n\t\tsignature: \"applyProfile(json, profile)\",\n\t\treturns: \"object\",\n\t\tdoc: \"Map already-extracted JSON to target fields and return the mapped object — it never writes, so the `insert()` / `update()` stays yours. `json` is the parsed extractor output (`JSON.parse(ocrExtract(...))`). `profile` must be an **inline object**, `{ map: { target: { from, transform?, pick? } }, lines?: { from, map, key? } }` — passing a profile code throws, as profile-by-code is a later slice. `from` is a path into the extraction; `transform` is one of `firstValid:<basis>`, `lookupRef:<entity.matchField>>returnField>`, `matchCatalog:<same>`, `parseMoney` or `parseDate`. Header targets come back at the top level and the 1:N block under its `key` (default `lines`); a missing source path omits the target. Not the same thing as `ocrExtract`'s registered `opts.profile` code.\",\n\t},\n\n\t// Utilities\n\t{ name: \"now\", signature: \"now()\", returns: \"datetime\", doc: \"Current date/time. Lowercase — this is the execute-block date function.\" },\n\t{ name: \"addDays\", signature: \"addDays(date, n)\", returns: \"date\", doc: \"Add `n` days to a date.\" },\n\t{ name: \"addMinutes\", signature: \"addMinutes(date, n)\", returns: \"datetime\", doc: \"Add `n` minutes.\" },\n\t{ name: \"addSeconds\", signature: \"addSeconds(date, n)\", returns: \"datetime\", doc: \"Add `n` seconds.\" },\n\t{ name: \"currentUserId\", signature: \"currentUserId()\", returns: \"long\", doc: \"The acting user's tenant user ID.\" },\n\t{ name: \"flush\", signature: \"flush()\", returns: \"void\", doc: \"Flush pending writes so a following read sees them.\" },\n\t{ name: \"tryParseJson\", signature: \"tryParseJson(value)\", returns: \"any | null\", doc: \"Parse JSON, returning `null` on failure instead of throwing.\" },\n\t{\n\t\tname: \"nextNumber\",\n\t\tsignature: \"nextNumber(entity)\",\n\t\treturns: \"string\",\n\t\tentityArg: 0,\n\t\tdoc: \"Generate the next value from a number sequence. Usually unnecessary — the platform auto-fills on `insert()`.\",\n\t},\n\t{\n\t\tname: \"entityLink\",\n\t\tsignature: \"entityLink(entityCd, record, description?)\",\n\t\treturns: \"link\",\n\t\tentityArg: 0,\n\t\tdoc: \"Build a clickable link to a record, for an `entitylink` column. Always pass a **qualified** code — `entity_cd` is only unique per module.\",\n\t},\n];\n\nexport const BUILTIN_BY_NAME = new Map(BUILTINS.map((b) => [b.name, b]));\n\n/** Bare identifiers the runtime injects — no parentheses. */\nexport const BUILTIN_VALUES: Record<string, string> = {\n\tuserId: \"The acting user's tenant user ID. A bare identifier — `userId()` is a compile error.\",\n\trecords: \"The selected records, in a `batch` action. Iterate with `for x in records { … }`.\",\n\tparams: \"Declared action parameters — read with `params[name]`.\",\n\told: \"Pre-change values, in a trigger-invoked action — read with `old[field]`. Read-only.\",\n};\n","// Static checks for an action DSL body (`logic/actions/*.dsl`).\n//\n// Every rule here mirrors something the platform only tells you at pack or\n// install time — a slow, tenant-bound round trip. The point is to move that\n// feedback to where the script is written, and to the validator that runs\n// before a pack, from one implementation rather than two.\n//\n// The rules that need to know about the module take it through `DslContext`,\n// which is small on purpose: a module code, the action, and the columns of the\n// entity behind the record context. Anything a host can't resolve it simply\n// omits, and the rules that depend on it stand down. See ./types.\n\nimport { BUILTIN_BY_NAME } from \"./builtins\";\nimport { CONTROL_KEYWORDS, type Token } from \"./lexer\";\nimport {\n\ttype BlockKind,\n\ttype DslDocument,\n\ttype Span,\n\tblockLabelAt,\n\tparseDsl,\n} from \"./parse\";\nimport type { ColumnLookup, DslContext, DslIssue, DslSeverity } from \"./types\";\n\n/**\n * Check a DSL body. Returns [] for a clean script.\n *\n * Issues come back in source-feature order (field reads, params, execution\n * mode, block spelling, built-ins, top-level returns, inline assignments)\n * rather than sorted by position — a host that wants them in file order can\n * sort on `start`.\n */\nexport function checkDsl(text: string, ctx: DslContext = {}): DslIssue[] {\n\tconst parsed = parseDsl(text);\n\tconst out: DslIssue[] = [];\n\tconst positionAt = lineIndexer(text);\n\n\tconst add = (\n\t\tspan: Span,\n\t\tmessage: string,\n\t\tseverity: DslSeverity,\n\t\trule: string,\n\t) => {\n\t\tconst { line, column } = positionAt(span.start);\n\t\tout.push({\n\t\t\trule,\n\t\t\tseverity,\n\t\t\tmessage,\n\t\t\tstart: span.start,\n\t\t\tend: span.end,\n\t\t\tline,\n\t\t\tcolumn,\n\t\t});\n\t};\n\n\tconst action = ctx.action;\n\tconst entity = ctx.currentEntity ?? null;\n\tconst isBatch = (action?.executionMode ?? \"single\") === \"batch\";\n\tconst hasColumn = columnMatcher(entity?.columns);\n\n\t// ── structure ────────────────────────────────────────────────────\n\t// ActionDslCompiler.ParseBlocks reads the headers before anything else, so\n\t// a file that loses a block here loses it wholesale: the body still looks\n\t// like code, and nothing runs.\n\tif (text.trim() === \"\") {\n\t\tadd(\n\t\t\t{ start: 0, end: text.length },\n\t\t\t\"A DSL body needs at least an execute: block — an empty file installs an action that does nothing.\",\n\t\t\t\"error\",\n\t\t\t\"dsl/empty-script\",\n\t\t);\n\t\treturn out;\n\t}\n\n\t// A file with no headers at all has no label to point at, and a zero-width\n\t// span renders as a caret before the first character — so fall back to the\n\t// first token, which is where the reader is already looking.\n\tconst firstToken = parsed.tokens[0];\n\tconst firstLabel = parsed.blocks[0]?.label ??\n\t\t(firstToken ? { start: firstToken.start, end: firstToken.end } : { start: 0, end: text.length });\n\tif (!parsed.blocks.some((b) => b.kind === \"execute\")) {\n\t\tadd(\n\t\t\tfirstLabel,\n\t\t\t\"No execute: block — it is the only required block, and the compiler runs nothing without it.\",\n\t\t\t\"error\",\n\t\t\t\"dsl/missing-execute\",\n\t\t);\n\t}\n\n\t// `execute:` is matched as `(.*?)\\z`, and its lookahead lists nothing — so it\n\t// runs to the end of the file and takes every header below it with it. The\n\t// block's own regex still finds it and it still runs; what breaks is\n\t// execute:, whose body now holds a header line and a formula or a param\n\t// list, parsed as JavaScript.\n\tconst executeBlock = parsed.blocks.find((b) => b.kind === \"execute\");\n\tif (executeBlock) {\n\t\tfor (let i = 0; i < parsed.tokens.length; i++) {\n\t\t\tconst token = parsed.tokens[i]!;\n\t\t\tif (token.start <= executeBlock.label.start) continue;\n\t\t\tif (token.character !== 0) continue;\n\t\t\tconst label = blockLabelAt(parsed.tokens, i);\n\t\t\tif (!label) continue;\n\t\t\t// A second execute: cannot be moved above the first. findBlocks\n\t\t\t// stops at the first one, so dsl/duplicate-block never sees this\n\t\t\t// and the wording has to come from here.\n\t\t\tadd(\n\t\t\t\tlabel.span,\n\t\t\t\tlabel.kind === \"execute\"\n\t\t\t\t\t? `\"execute:\" is declared more than once — the first one's body runs to the end of the file, so this header and everything under it are swallowed into it and parsed as JavaScript. Merge the two into one execute: block.`\n\t\t\t\t\t: `\"${label.kind}:\" is below execute:, whose body runs to the end of the file — the header and everything under it are swallowed into the execute: script and parsed as JavaScript. Move it above execute:.`,\n\t\t\t\t\"error\",\n\t\t\t\t\"dsl/block-after-execute\",\n\t\t\t);\n\t\t}\n\t}\n\n\tconst seenBlocks = new Set<string>();\n\tfor (let i = 0; i < parsed.blocks.length; i++) {\n\t\tconst block = parsed.blocks[i]!;\n\t\tif (seenBlocks.has(block.kind)) {\n\t\t\tadd(\n\t\t\t\tblock.label,\n\t\t\t\t`\"${block.kind}:\" is declared more than once — the compiler keeps one and silently drops the other.`,\n\t\t\t\t\"error\",\n\t\t\t\t\"dsl/duplicate-block\",\n\t\t\t);\n\t\t\t// No block's own lookahead lists itself, so the order rule below\n\t\t\t// would read a duplicate as misplaced and tell the author to move\n\t\t\t// it before itself.\n\t\t\tcontinue;\n\t\t}\n\t\tseenBlocks.add(block.kind);\n\n\t\t// Only the block immediately above can swallow this one: a block body\n\t\t// ends at the first header its own lookahead lists, and the nearest\n\t\t// header below it is this one. execute: is left to the rule above, which\n\t\t// says the same thing about it in better words.\n\t\tconst prev = parsed.blocks[i - 1];\n\t\tif (prev && prev.kind !== \"execute\" && !BLOCK_STOPS[prev.kind].has(block.kind)) {\n\t\t\tadd(\n\t\t\t\tblock.label,\n\t\t\t\t`\"${block.kind}:\" must come before \"${prev.kind}:\" — the compiler reads ${prev.kind}: up to the next header it recognises, and ${block.kind}: is not one of them, so this header and its body end up inside the ${prev.kind}: body.`,\n\t\t\t\t\"error\",\n\t\t\t\t\"dsl/block-order\",\n\t\t\t);\n\t\t}\n\t}\n\n\t// ── record fields ────────────────────────────────────────────────\n\tfor (const ref of parsed.fieldRefs) {\n\t\t// Neither block is rewritten by TransformLine, so brackets in them are\n\t\t// data rather than field reads: `schema:` is embedded as a JS object\n\t\t// literal, and `params:` is read by RxParamDecl — whose trailing\n\t\t// key=value pairs take a bracketed option list, `options=[cash]`.\n\t\tif (ref.block === \"schema\" || ref.block === \"params\") continue;\n\n\t\t// Single-hop is the DSL's own rewrite (`RxRefNav`), so the rule belongs\n\t\t// to the blocks that go through it. canExecute: reaches the formula\n\t\t// engine verbatim, and a formula walks a chain of any depth —\n\t\t// `[vehicle].[depot].[city_name]` resolves there and is tested.\n\t\tconst isDslBlock = ref.block === \"execute\" || ref.block === \"onBeforeStart\";\n\t\t// The compiler rewrites the first hop and then fails on a surviving\n\t\t// `.[` — so it is the bracket, not the hop count, that marks a second\n\t\t// reference. `[vehicle].plate.length` compiles to\n\t\t// `__ref_vehicle.get('plate').length`: one hop, then JavaScript.\n\t\tconst secondRef = ref.navigation.findIndex((h, idx) => idx > 0 && h.bracketed);\n\t\tif (isDslBlock && secondRef > 0) {\n\t\t\tconst first = ref.navigation[secondRef]!;\n\t\t\tconst last = ref.navigation[ref.navigation.length - 1]!;\n\t\t\tadd(\n\t\t\t\t{ start: first.span.start, end: last.span.end },\n\t\t\t\t`Ref navigation is single-hop in the DSL. Use getRecord() or select() to reach past \"${ref.navigation[0]!.name}\".`,\n\t\t\t\t\"error\",\n\t\t\t\t\"dsl/multi-hop-nav\",\n\t\t\t);\n\t\t}\n\n\t\t// Batch execute: applies no `[field]` rewrite at all, so `[true]` stays\n\t\t// the literal it is — and a keyword is never a column name anyway.\n\t\tif (isBatch && ref.block === \"execute\" && LITERAL_NAMES.has(ref.name))\n\t\t\tcontinue;\n\n\t\tif (!entity) continue;\n\t\tif (entity.columns.size === 0) continue;\n\t\tif (hasColumn(ref.name)) continue;\n\t\t// `var ids = [orderId]` is an array literal, not a field read. Only the\n\t\t// name tells the two apart, so a name bound in this script stands down —\n\t\t// the same fail-open the entity checks above use.\n\t\t//\n\t\t// Only the bare bracket is ambiguous. `r[stauts]` and\n\t\t// `records[0][stauts]` name a column outright — the compiler rewrites\n\t\t// each to `.get('stauts')` with the literal name — so a same-named\n\t\t// local says nothing about them.\n\t\tif (ref.isCurrentRecord && parsed.locals.has(ref.name)) continue;\n\n\t\tadd(\n\t\t\tref.span,\n\t\t\t`\"${ref.name}\" is not a column on ${entity.qualified}. [field] names are checked at pack time — this is a compile error, not an empty read.`,\n\t\t\t\"error\",\n\t\t\t\"dsl/unknown-column\",\n\t\t);\n\t}\n\n\t// `old[field]` names columns of the same entity — RxOldAccess feeds them\n\t// into the very same check — so a typo there is a compile error too.\n\tif (entity && entity.columns.size > 0) {\n\t\tfor (const ref of parsed.globalRefs) {\n\t\t\tif (ref.global !== \"old\") continue;\n\t\t\tif (ref.block !== \"execute\" && ref.block !== \"onBeforeStart\") continue;\n\t\t\tif (hasColumn(ref.property)) continue;\n\t\t\tadd(\n\t\t\t\tref.span,\n\t\t\t\t`\"${ref.property}\" is not a column on ${entity.qualified}. old[field] reads the pre-change value of a column, and the name is checked at pack time.`,\n\t\t\t\t\"error\",\n\t\t\t\t\"dsl/unknown-column\",\n\t\t\t);\n\t\t}\n\t}\n\n\t// ── params ───────────────────────────────────────────────────────\n\t// `ValidateParamUsages` compares with OrdinalIgnoreCase, so `params[Qty]`\n\t// against a declared `qty` compiles — flagging it would be a false error.\n\tconst declared = new Set(parsed.params.map((p) => p.name.toLowerCase()));\n\tconst hasParamsBlock = parsed.blocks.some((b) => b.kind === \"params\");\n\tfor (const ref of parsed.globalRefs) {\n\t\tif (ref.global !== \"params\") continue;\n\t\tif (!hasParamsBlock || declared.has(ref.property.toLowerCase())) continue;\n\t\tadd(\n\t\t\tref.span,\n\t\t\t`\"${ref.property}\" is not declared in the params: block.`,\n\t\t\t\"error\",\n\t\t\t\"dsl/unknown-param\",\n\t\t);\n\t}\n\n\t// ── execution mode ───────────────────────────────────────────────\n\tif (action) {\n\t\tconst mode = action.executionMode ?? \"single\";\n\t\t// `recordsRefs` covers both `records[x]` and the bare `for x in records`,\n\t\t// and comes from the lexer, so the word inside a string or a comment\n\t\t// does not count — nor does a script that binds its own `records`,\n\t\t// which shadows the batch global and says nothing about the mode.\n\t\tconst recordsSpan = parsed.locals.has(\"records\")\n\t\t\t? undefined\n\t\t\t: parsed.recordsRefs[0];\n\t\t// execute: alone. `onBeforeStart:` is compiled by CompilePerRecordBlock\n\t\t// whatever the mode — \"always per-record (no batch form)\" — so a bare\n\t\t// field is exactly how it is meant to be written there.\n\t\t//\n\t\t// Batch mode never applies the `[field]` rewrite at all, which is why\n\t\t// `var ids = [id]` survives as the array literal it looks like. Same\n\t\t// disambiguation as the column rule: a name bound in this script is a\n\t\t// local, not a column.\n\t\tconst bareFields = parsed.fieldRefs.filter(\n\t\t\t(r) =>\n\t\t\t\tr.block === \"execute\" &&\n\t\t\t\tr.isCurrentRecord &&\n\t\t\t\t!parsed.locals.has(r.name) &&\n\t\t\t\t!LITERAL_NAMES.has(r.name),\n\t\t);\n\n\t\tif (mode === \"batch\") {\n\t\t\t// Every one of them: an editor underlines what it is told to, and\n\t\t\t// reporting only the first hides the rest behind a re-check.\n\t\t\tfor (const field of bareFields) {\n\t\t\t\tadd(\n\t\t\t\t\tfield.outerSpan,\n\t\t\t\t\t`Action \"${action.code}\" runs in batch mode, which has no current record. Iterate instead: for x in records { x[${field.name}] }.`,\n\t\t\t\t\t\"error\",\n\t\t\t\t\t\"dsl/batch-bare-field\",\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tif (mode !== \"batch\" && recordsSpan) {\n\t\t\tadd(\n\t\t\t\trecordsSpan,\n\t\t\t\t`\"records\" only exists in batch mode; action \"${action.code}\" runs in \"${mode}\" mode.`,\n\t\t\t\t\"warning\",\n\t\t\t\t\"dsl/records-outside-batch\",\n\t\t\t);\n\t\t}\n\t}\n\n\t// ── block-specific spelling ──────────────────────────────────────\n\t// canExecute is parsed by the formula engine, execute by the JavaScript\n\t// compiler. They share more vocabulary than the docs suggest — NULL and\n\t// lowercase booleans work in both, and shipped modules rely on that — so\n\t// only the operators that genuinely have no formula spelling are flagged.\n\tfor (const token of parsed.tokens) {\n\t\tif (blockOf(parsed, token.start) !== \"canExecute\") continue;\n\t\tif (token.text !== \"&&\" && token.text !== \"||\") continue;\n\t\tadd(\n\t\t\t{ start: token.start, end: token.end },\n\t\t\t`canExecute is a formula, not JavaScript — write ${token.text === \"&&\" ? \"AND\" : \"OR\"}.`,\n\t\t\t\"warning\",\n\t\t\t\"dsl/js-in-formula\",\n\t\t);\n\t}\n\n\t// ── built-in misuse ──────────────────────────────────────────────\n\tfor (const call of parsed.calls) {\n\t\tif (call.name === \"userId\") {\n\t\t\tadd(\n\t\t\t\tcall.nameSpan,\n\t\t\t\t\"'userId' is a value, not a function — write userId without parentheses, or currentUserId(). \" +\n\t\t\t\t\t\"The compiler's bare-identifier rewrite fires either way, so userId() reaches Jint as a call against a number.\",\n\t\t\t\t\"error\",\n\t\t\t\t\"dsl/user-id-call\",\n\t\t\t);\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst builtin = BUILTIN_BY_NAME.get(call.name);\n\t\tif (!builtin || builtin.entityArg === undefined) continue;\n\t\tconst arg = call.firstStringArg;\n\t\tif (!arg) continue;\n\n\t\t// A hyphenated module code can't be schema-qualified, so the rule is\n\t\t// skipped there rather than reported as unfixable. Neither can a code\n\t\t// half of which is spliced in at run time be read here.\n\t\tif (arg.interpolated) continue;\n\t\tif (arg.value.includes(\".\") || ctx.moduleCode?.includes(\"-\")) continue;\n\t\tadd(\n\t\t\targ.span,\n\t\t\t`Qualify the entity code as \"${ctx.moduleCode ? `${ctx.moduleCode}.` : \"<module>.\"}${arg.value}\" — entity_cd is only unique per module, so a bare code can resolve to another module's entity.`,\n\t\t\t\"info\",\n\t\t\t\"dsl/unqualified-entity\",\n\t\t);\n\t}\n\n\t// ── indented headers, and returns outside a function ─────────────\n\t// An indented `params:` inside an object literal is an ordinary key, which\n\t// is the whole reason the compiler anchors headers at column 0 rather than\n\t// trusting the line — so that rule reads brace depth.\n\t//\n\t// `return` reads function scope instead. Both blocks compile to a bare\n\t// script, and Esprima's ParseScript rejects a return outside a function\n\t// wherever it sits: `if (x) { return }` and `if (x) return` fail exactly as\n\t// a return on its own line does.\n\tlet depth = 0;\n\tconst functionDepths: number[] = [];\n\t// Index of the `(` that the most recent `)` closed. Tracked with a stack\n\t// because the nearest open paren is not the matching one: in `if (now()) {`\n\t// it is `now`'s, and in `function f(x = (1)) {` it is the default value's.\n\tconst parenStack: number[] = [];\n\tlet matchingParenOpen = -1;\n\tfor (let i = 0; i < parsed.tokens.length; i++) {\n\t\tconst token = parsed.tokens[i]!;\n\n\t\tif (token.text === \"(\") parenStack.push(i);\n\t\telse if (token.text === \")\") matchingParenOpen = parenStack.pop() ?? -1;\n\n\t\tif (token.text === \"{\") {\n\t\t\tdepth++;\n\t\t\tif (opensFunctionBody(parsed.tokens, i, matchingParenOpen))\n\t\t\t\tfunctionDepths.push(depth);\n\t\t} else if (token.text === \"}\") {\n\t\t\tif (functionDepths[functionDepths.length - 1] === depth)\n\t\t\t\tfunctionDepths.pop();\n\t\t\tdepth = Math.max(0, depth - 1);\n\t\t}\n\n\t\tif (depth === 0 && token.character > 0) {\n\t\t\tconst label = blockLabelAt(parsed.tokens, i);\n\t\t\t// `execute: number` inside params: declares a param called execute.\n\t\t\t// RxParamDecl takes any `\\w+`, so a block name is a legal param\n\t\t\t// name — and a declaration the parser already read is not a header.\n\t\t\tconst isParamDecl = parsed.params.some(\n\t\t\t\t(p) => p.nameSpan.start === token.start,\n\t\t\t);\n\t\t\tif (label && !isParamDecl) {\n\t\t\t\tadd(\n\t\t\t\t\tlabel.span,\n\t\t\t\t\t`Block headers start at column 0. Indented, \"${label.kind}:\" is body text — the compiler never opens the block, and it runs as if empty.`,\n\t\t\t\t\t\"error\",\n\t\t\t\t\t\"dsl/indented-block-header\",\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif (token.kind !== \"ident\" || token.text !== \"return\") continue;\n\t\t// `return` is a reserved word, so it is a statement unless it is being\n\t\t// used as a name: `result.return` reads a property, `{ return: 1 }`\n\t\t// declares a key and `{ return() { … } }` declares a method. All three\n\t\t// are legal JavaScript.\n\t\tif (parsed.tokens[i - 1]?.text === \".\") continue;\n\t\tif (parsed.tokens[i + 1]?.text === \":\") continue;\n\t\tif (isMethodName(parsed.tokens, i)) continue;\n\t\tif (functionDepths.length > 0) continue;\n\t\tconst block = blockOf(parsed, token.start);\n\t\tif (block !== \"execute\" && block !== \"onBeforeStart\") continue;\n\t\tadd(\n\t\t\t{ start: token.start, end: token.end },\n\t\t\t`A return outside a function is a syntax error — ${block}: compiles to a bare script. Use exit(message, level) to stop early and keep the changes made so far.`,\n\t\t\t\"error\",\n\t\t\t\"dsl/top-level-return\",\n\t\t);\n\t}\n\n\t// ── formula-only functions in a JavaScript block ─────────────────\n\t// execute: and onBeforeStart: compile to a bare script and run on Jint;\n\t// the rest of the DSL is the formula engine. Install rejects these with\n\t// \"'TODAY' is not defined\".\n\tfor (const call of parsed.calls) {\n\t\tconst replacement = FORMULA_ONLY.get(call.name);\n\t\tif (!replacement) continue;\n\t\tif (call.block !== \"execute\" && call.block !== \"onBeforeStart\") continue;\n\t\tadd(\n\t\t\tcall.nameSpan,\n\t\t\t`${call.name}() is formula-only — in ${call.block}: it is undefined and install fails with \"'${call.name}' is not defined\". Write ${replacement}.`,\n\t\t\t\"error\",\n\t\t\t\"dsl/formula-only-function\",\n\t\t);\n\t}\n\n\t// Token position by start offset — the two rules below both need to read\n\t// what sits next to a call, and a scan per call is a scan of the file.\n\tconst tokenAt = new Map(parsed.tokens.map((t, i) => [t.start, i]));\n\n\t// ── SQL placeholders are @name, not :name ────────────────────────\n\tfor (const call of parsed.calls) {\n\t\tif (call.name !== \"query\" && call.name !== \"callProc\") continue;\n\t\tconst arg = call.firstStringArg;\n\t\tif (!arg) continue; // a variable or a built string — nothing to read\n\n\t\t// `::text` is a Postgres cast and `a:b` inside a literal is not a\n\t\t// placeholder either, so require a non-word, non-colon character before.\n\t\t// Quoted data and comments are not SQL to bind against at all —\n\t\t// `select ':draft' as status` names no placeholder.\n\t\t//\n\t\t// The leading character is captured rather than looked behind: lookbehind\n\t\t// is ES2018, and an unsupported one is a SyntaxError for the whole module\n\t\t// at parse time, not a failure of this rule.\n\t\tconst bad = /(^|[^:\\w]):([a-z][a-z0-9_]*)/i.exec(stripSqlNoise(arg.value));\n\t\tif (bad) {\n\t\t\tconst name = bad[2];\n\t\t\tadd(\n\t\t\t\targ.span,\n\t\t\t\t`SQL binds @name, not :name — rewrite ':${name}' as '@${name}' and pass { ${name}: value } as the params argument.`,\n\t\t\t\t\"error\",\n\t\t\t\t\"dsl/sql-placeholder\",\n\t\t\t);\n\t\t}\n\n\t\t// A `${…}` hole is the splice itself; a `+` after the literal is the\n\t\t// same splice written the other way.\n\t\tif (arg.interpolated || parsed.tokens[arg.endIndex + 1]?.text === \"+\") {\n\t\t\tconst built = arg.interpolated ? \"${…} interpolation\" : \"concatenation\";\n\t\t\tadd(\n\t\t\t\targ.span,\n\t\t\t\t// callProc's first argument is the procedure name, and an\n\t\t\t\t// identifier cannot be bound — the @placeholder advice cannot\n\t\t\t\t// be followed there.\n\t\t\t\tcall.name === \"callProc\"\n\t\t\t\t\t? `Procedure name built by ${built} — a name is an identifier, so it cannot be bound as a @placeholder. Choose between fixed names in the script rather than splicing a value into one.`\n\t\t\t\t\t: `SQL built by ${built} — pass @placeholders and a params object instead, so values are bound rather than spliced into the statement.`,\n\t\t\t\t\"warning\",\n\t\t\t\t\"dsl/sql-concat\",\n\t\t\t);\n\t\t}\n\t}\n\n\t// ── unknown host functions ───────────────────────────────────────\n\t// A warning, not an error: the catalog tracks the host's built-ins by hand,\n\t// so a name missing from it is more likely our gap than the author's typo.\n\t//\n\t// JavaScript blocks only. The catalog is Jint's host surface; canExecute:\n\t// is the formula engine, with a vocabulary of its own — and its infix\n\t// operators bring parentheses with them, so `… AND (x OR y)` reads as a\n\t// call to AND here and is no such thing.\n\t//\n\t// Declarations are block-scoped because the compiler is: execute: and\n\t// onBeforeStart: are compiled to separate scripts and each gets its own\n\t// `CheckUndefinedReferences` pass, so a helper declared in one is not\n\t// defined in the other. A declaration above the first header belongs to no\n\t// block and is left visible to both — nothing legal can sit there.\n\t// Every block it is declared in, not the last one: a helper both blocks need\n\t// has to be written out in both, which is the shape this scoping produces.\n\tconst declaredFunctions = new Map<string, Set<BlockKind | null>>();\n\tfor (let i = 0; i < parsed.tokens.length; i++) {\n\t\tconst token = parsed.tokens[i]!;\n\t\tif (token.text !== \"function\") continue;\n\t\tconst name = parsed.tokens[i + 1];\n\t\tif (name?.kind !== \"ident\") continue;\n\t\tconst blocks = declaredFunctions.get(name.text) ?? new Set();\n\t\tblocks.add(blockOf(parsed, token.start));\n\t\tdeclaredFunctions.set(name.text, blocks);\n\t}\n\tconst isDeclaredIn = (name: string, block: BlockKind | null) => {\n\t\tconst blocks = declaredFunctions.get(name);\n\t\treturn blocks !== undefined && (blocks.has(null) || blocks.has(block));\n\t};\n\t// `parsed.calls` is every `name(` in the body, so a function's own\n\t// declaration head looks like a call to it: `function f(x)` and the method\n\t// shorthand `f(x) { … }` alike. Neither is an invocation of anything.\n\tconst reportedUnknown = new Set<string>();\n\tfor (const call of parsed.calls) {\n\t\tif (call.block !== \"execute\" && call.block !== \"onBeforeStart\") continue;\n\t\tconst name = call.name;\n\t\tconst idx = tokenAt.get(call.nameSpan.start);\n\t\tif (idx !== undefined) {\n\t\t\t// `new Foo()` names a constructor, not a host function — the\n\t\t\t// catalog never held one and has nothing to say about it.\n\t\t\tconst prev = parsed.tokens[idx - 1]?.text;\n\t\t\tif (prev === \"function\" || prev === \"new\") continue;\n\t\t\tif (isMethodName(parsed.tokens, idx)) continue;\n\t\t}\n\t\tif (\n\t\t\tBUILTIN_BY_NAME.has(name) ||\n\t\t\tCONTROL_KEYWORDS.has(name) ||\n\t\t\tKEYWORDS_BEFORE_PAREN.has(name) ||\n\t\t\tJS_GLOBALS.has(name) ||\n\t\t\tFORMULA_ONLY.has(name) ||\n\t\t\t// Its own rule reports this one, with better wording.\n\t\t\tname === \"userId\" ||\n\t\t\tisDeclaredIn(name, call.block) ||\n\t\t\tparsed.locals.has(name) ||\n\t\t\treportedUnknown.has(name)\n\t\t) {\n\t\t\tcontinue;\n\t\t}\n\t\treportedUnknown.add(name);\n\t\tadd(\n\t\t\tcall.nameSpan,\n\t\t\t`\"${name}()\" is not a DSL host function, and nothing in this script declares it. Check it against the built-in catalog.`,\n\t\t\t\"warning\",\n\t\t\t\"dsl/unknown-builtin\",\n\t\t);\n\t}\n\n\t// ── a job's action has no current record ─────────────────────────\n\tif (ctx.action?.viaJob) {\n\t\t// `JobRegistrar.RequiresRecordContext` reads the compiled script for\n\t\t// three markers, not one: `__r.` from `[field]`, `__old.` from the\n\t\t// trigger-only `old[field]`, and `__records.` from the batch record set.\n\t\t// All three are rejected, so all three are reported.\n\t\tconst inScript = (block: BlockKind | null) =>\n\t\t\tblock === \"execute\" || block === \"onBeforeStart\";\n\t\tconst bound: Array<{ span: Span; read: string }> = [];\n\n\t\t// Same disambiguation the column rule makes, on the same terms: `[id]`\n\t\t// is an array literal when the script binds `id`, and `[true]` is one\n\t\t// in batch execute:, where no `[field]` rewrite runs to claim it.\n\t\tfor (const ref of parsed.fieldRefs) {\n\t\t\tif (!inScript(ref.block)) continue;\n\t\t\tif (isBatch && ref.block === \"execute\" && LITERAL_NAMES.has(ref.name))\n\t\t\t\tcontinue;\n\t\t\tif (ref.isCurrentRecord && parsed.locals.has(ref.name)) continue;\n\t\t\tbound.push({ span: ref.outerSpan, read: `[${ref.name}]` });\n\t\t}\n\t\tfor (const ref of parsed.globalRefs) {\n\t\t\tif (ref.global !== \"old\" || !inScript(ref.block)) continue;\n\t\t\tbound.push({ span: ref.span, read: `old[${ref.property}]` });\n\t\t}\n\t\t// Shadowed exactly as the execution-mode rule reads it: a script that\n\t\t// binds its own `records` is not touching the batch global — and\n\t\t// `var records = select(…)` is the very refactor this rule asks for.\n\t\tif (!parsed.locals.has(\"records\")) {\n\t\t\tfor (const span of parsed.recordsRefs) {\n\t\t\t\tif (!inScript(blockOf(parsed, span.start))) continue;\n\t\t\t\tbound.push({ span, read: \"records\" });\n\t\t\t}\n\t\t}\n\n\t\tconst first = bound.sort((a, b) => a.span.start - b.span.start)[0];\n\t\tif (first) {\n\t\t\tadd(\n\t\t\t\tfirst.span,\n\t\t\t\t`Action \"${ctx.action.code}\" is invoked by a scheduled job, which runs as the system user with no record bound — ${first.read} has nothing to read. Fetch rows with select() or query() instead.`,\n\t\t\t\t\"error\",\n\t\t\t\t\"dsl/job-record-context\",\n\t\t\t);\n\t\t}\n\t}\n\n\tout.push(...inlineAssignmentIssues(parsed, positionAt));\n\treturn out;\n}\n\n/**\n * Column matching is case-insensitive at the other end — `EntityColumnLookup`\n * hands the compiler an OrdinalIgnoreCase set — but a host passes us whatever\n * `Set` or `Map` it already holds, and a mixed-case column name is legal.\n *\n * So fold both sides: the names once per check when the lookup can enumerate\n * them (`Set` and `Map` both can), and the reference on the way in. A lookup\n * that can do neither falls back to trying the reference in lower case, which\n * is all that is left to try.\n */\nfunction columnMatcher(columns?: ColumnLookup): (name: string) => boolean {\n\tif (!columns) return () => true;\n\tif (typeof columns.keys !== \"function\")\n\t\treturn (name) => columns.has(name) || columns.has(name.toLowerCase());\n\n\tconst folded = new Set<string>();\n\tfor (const key of columns.keys()) folded.add(key.toLowerCase());\n\treturn (name) => folded.has(name.toLowerCase());\n}\n\n/**\n * Whether the name at `i` heads a method shorthand — `return() { … }`, whose\n * parameter list is followed by a body. `return (x + 1)` is a statement with a\n * parenthesized expression and has no brace after the closing paren, so the\n * two are told apart by what follows the parens rather than by what opens them.\n */\nfunction isMethodName(tokens: Token[], i: number): boolean {\n\tif (tokens[i + 1]?.text !== \"(\") return false;\n\tlet depth = 0;\n\tfor (let j = i + 1; j < tokens.length; j++) {\n\t\tconst text = tokens[j]!.text;\n\t\tif (text === \"(\") depth++;\n\t\telse if (text === \")\") {\n\t\t\tdepth--;\n\t\t\tif (depth === 0) return tokens[j + 1]?.text === \"{\";\n\t\t}\n\t}\n\treturn false;\n}\n\n/**\n * Whether the `{` at `i` opens a function body — where a `return` is legal.\n *\n * `=> {` is one. So is `) {` when the name in front of the matching `(` is not\n * a control keyword: that covers `function (x) {`, `function f(x) {` and the\n * `f() {` method shorthand, while leaving `if (x) {` and `for (…) {` alone.\n */\nfunction opensFunctionBody(\n\ttokens: Token[],\n\ti: number,\n\tmatchingParenOpen: number,\n): boolean {\n\tconst prev = tokens[i - 1];\n\tif (prev?.text === \"=>\") return true;\n\tif (prev?.text !== \")\" || matchingParenOpen < 0) return false;\n\tconst head = tokens[matchingParenOpen - 1];\n\treturn head?.kind === \"ident\" && !CONTROL_KEYWORDS.has(head.text);\n}\n\n/**\n * The headers each block's regex in `ParseBlocks` stops at — its body runs to\n * the first of these below it, or to the end of the file.\n *\n * The sets are not the same, and none of them is \"every other block\": a block\n * followed by one its own set omits swallows that block's text. `schema:`, the\n * only one every other set lists, may therefore sit anywhere before `execute:`.\n */\nconst BLOCK_STOPS: Record<BlockKind, ReadonlySet<BlockKind>> = {\n\tparams: new Set([\"schema\", \"canExecute\", \"onBeforeStart\", \"execute\"]),\n\tcanExecute: new Set([\"schema\", \"onBeforeStart\", \"execute\"]),\n\tschema: new Set([\"params\", \"canExecute\", \"onBeforeStart\", \"execute\"]),\n\tonBeforeStart: new Set([\"schema\", \"execute\"]),\n\texecute: new Set(),\n};\n\n/**\n * Formula-engine functions that are undefined in a JavaScript block, mapped to\n * the spelling that works there.\n *\n * A Map, not an object: the key is a name read out of the script, and on an\n * object `toString` and `constructor` would answer from the prototype — a\n * declared `function toString()` would be reported as formula-only, with the\n * native function's source offered as the replacement.\n */\nconst FORMULA_ONLY = new Map<string, string>([\n\t[\"TODAY\", \"now()\"],\n\t[\"NOW\", \"now()\"],\n\t[\"CURRENT_USER_ID\", \"currentUserId()\"],\n]);\n\n/**\n * Keywords a `(` may legally follow. `parsed.calls` is every `name(` in the\n * body, so these arrive looking like calls — `return (x)`, `typeof (v)` and\n * `for (x of (xs))` included — and are not calls to anything.\n */\nconst KEYWORDS_BEFORE_PAREN = new Set([\n\t\"function\", \"return\", \"typeof\", \"instanceof\", \"new\", \"delete\", \"void\",\n\t\"in\", \"of\", \"do\", \"else\", \"try\", \"throw\", \"yield\", \"await\",\n]);\n\n/** Globals Jint exposes. Real calls, and none of them ours to report. */\nconst JS_GLOBALS = new Set([\n\t\"parseInt\", \"parseFloat\", \"isNaN\", \"isFinite\", \"encodeURI\", \"decodeURI\",\n\t\"encodeURIComponent\", \"decodeURIComponent\", \"String\", \"Number\", \"Boolean\",\n\t\"Array\", \"Object\", \"Date\", \"Math\", \"JSON\", \"RegExp\", \"Error\", \"Set\", \"Map\",\n\t\"WeakSet\", \"WeakMap\", \"Promise\", \"Symbol\", \"BigInt\",\n]);\n\n/**\n * Keyword literals, which `[…]` can only be holding as array elements. Both\n * spellings: the DSL takes SQL-style `NULL`/`TRUE`/`FALSE` as well as the\n * JavaScript ones, and rewrites them to the latter.\n */\nconst LITERAL_NAMES = new Set([\n\t\"true\",\n\t\"false\",\n\t\"null\",\n\t\"TRUE\",\n\t\"FALSE\",\n\t\"NULL\",\n]);\n\n/**\n * SQL with its string literals and comments blanked out, so a scan for\n * placeholders reads only the statement. Same length in, same length out.\n *\n * Quotes double to escape themselves in SQL (`'it''s'`), which is why this\n * cannot be a regex the way the JavaScript lexer's strings can.\n */\nfunction stripSqlNoise(sql: string): string {\n\tlet out = \"\";\n\tlet i = 0;\n\twhile (i < sql.length) {\n\t\tconst c = sql[i]!;\n\n\t\tif (c === \"'\" || c === '\"') {\n\t\t\tconst quote = c;\n\t\t\tout += \" \";\n\t\t\ti++;\n\t\t\twhile (i < sql.length) {\n\t\t\t\tif (sql[i] === quote && sql[i + 1] === quote) {\n\t\t\t\t\tout += \" \";\n\t\t\t\t\ti += 2;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (sql[i] === quote) break;\n\t\t\t\tout += sql[i] === \"\\n\" ? \"\\n\" : \" \";\n\t\t\t\ti++;\n\t\t\t}\n\t\t\tif (i < sql.length) {\n\t\t\t\tout += \" \";\n\t\t\t\ti++;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (c === \"-\" && sql[i + 1] === \"-\") {\n\t\t\twhile (i < sql.length && sql[i] !== \"\\n\") {\n\t\t\t\tout += \" \";\n\t\t\t\ti++;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (c === \"/\" && sql[i + 1] === \"*\") {\n\t\t\tout += \" \";\n\t\t\ti += 2;\n\t\t\twhile (i < sql.length && !(sql[i] === \"*\" && sql[i + 1] === \"/\")) {\n\t\t\t\tout += sql[i] === \"\\n\" ? \"\\n\" : \" \";\n\t\t\t\ti++;\n\t\t\t}\n\t\t\tif (i < sql.length) {\n\t\t\t\tout += \" \";\n\t\t\t\ti += 2;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tout += c;\n\t\ti++;\n\t}\n\treturn out;\n}\n\nfunction blockOf(parsed: DslDocument, offset: number) {\n\treturn (\n\t\tparsed.blocks.find((b) => offset >= b.body.start && offset < b.body.end)\n\t\t\t?.kind ?? null\n\t);\n}\n\n/**\n * `if (…) { [field] = x }` on a single line mis-compiles — the assignment is\n * rewritten in place and the setter call is lost. One assignment per line.\n */\nfunction inlineAssignmentIssues(\n\tparsed: DslDocument,\n\tpositionAt: (offset: number) => { line: number; column: number },\n): DslIssue[] {\n\tconst out: DslIssue[] = [];\n\tfor (const ref of parsed.fieldRefs) {\n\t\t// `ref.endIndex` is where the parser stopped: a `.prop` hop is 2 tokens\n\t\t// but a `.[prop]` hop is 4, so the count cannot be derived here.\n\t\tconst assign = parsed.tokens[ref.endIndex + 1];\n\t\tif (!assign || assign.kind !== \"punct\" || assign.text !== \"=\") continue;\n\n\t\t// Walk back over this line only, looking for a brace that opened here.\n\t\tconst line = parsed.tokens[ref.startIndex]!.line;\n\t\tlet openedHere = false;\n\t\tfor (let i = ref.startIndex - 1; i >= 0; i--) {\n\t\t\tconst t = parsed.tokens[i]!;\n\t\t\tif (t.line !== line) break;\n\t\t\tif (t.text === \"{\") {\n\t\t\t\topenedHere = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (!openedHere) continue;\n\n\t\tconst pos = positionAt(ref.outerSpan.start);\n\t\tout.push({\n\t\t\trule: \"dsl/inline-assignment\",\n\t\t\tseverity: \"warning\",\n\t\t\tmessage:\n\t\t\t\t\"An assignment to a record field on the same line as the brace that opens its block mis-compiles. Put the assignment on its own line.\",\n\t\t\tstart: ref.outerSpan.start,\n\t\t\tend: ref.outerSpan.end,\n\t\t\tline: pos.line,\n\t\t\tcolumn: pos.column,\n\t\t});\n\t}\n\treturn out;\n}\n\n/**\n * Offset → 1-indexed line/column, over a line-start table built once per check.\n * Scanning the prefix per issue is O(n) each, and a body with many issues is\n * exactly the one where that shows.\n */\nfunction lineIndexer(text: string): (offset: number) => { line: number; column: number } {\n\tconst starts = [0];\n\tfor (let i = 0; i < text.length; i++) {\n\t\tif (text[i] === \"\\n\") starts.push(i + 1);\n\t}\n\treturn (offset: number) => {\n\t\t// Binary search for the last line start at or before `offset`.\n\t\tlet lo = 0;\n\t\tlet hi = starts.length - 1;\n\t\twhile (lo < hi) {\n\t\t\tconst mid = (lo + hi + 1) >> 1;\n\t\t\tif (starts[mid]! <= offset) lo = mid;\n\t\t\telse hi = mid - 1;\n\t\t}\n\t\treturn { line: lo + 1, column: offset - starts[lo]! + 1 };\n\t};\n}\n"],"mappings":"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","names":[]}