sf-agentpmd 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/agentpmd/analyze.js +1 -1
- package/dist/commands/agentpmd/analyze.js.map +1 -1
- package/dist/commands/agentpmd/install-skill.js +18 -4
- package/dist/commands/agentpmd/install-skill.js.map +2 -2
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/oclif.manifest.json +2 -2
- package/package.json +1 -1
package/dist/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/analyzer/analyze.ts", "../vendor/agentscript-parser-javascript/dist/cst-node.js", "../vendor/agentscript-parser-javascript/dist/token.js", "../node_modules/tiny-invariant/dist/esm/tiny-invariant.js", "../vendor/agentscript-parser-javascript/dist/lexer.js", "../vendor/agentscript-parser-javascript/dist/errors.js", "../vendor/agentscript-parser-javascript/dist/recovery.js", "../vendor/agentscript-parser-javascript/dist/expressions.js", "../vendor/agentscript-parser-javascript/dist/parse-statements.js", "../vendor/agentscript-parser-javascript/dist/parse-templates.js", "../vendor/agentscript-parser-javascript/dist/parse-mapping.js", "../vendor/agentscript-parser-javascript/dist/parse-sequence.js", "../vendor/agentscript-parser-javascript/dist/parser.js", "../vendor/agentscript-parser-javascript/dist/index.js", "../src/analyzer/parse.ts", "../src/analyzer/action-references.ts", "../src/analyzer/apex-analyze.ts", "../src/analyzer/apex-complexity.ts", "../src/analyzer/apex-parse.ts", "../src/analyzer/apex-resolve.ts", "../src/analyzer/complexity.ts", "../src/commands/agentpmd/analyze.ts", "../src/analyzer/project.ts", "../src/renderers/csv.ts", "../src/renderers/markdown.ts", "../src/renderers/sarif.ts", "../src/renderers/text.ts", "../src/renderers/index.ts"],
|
|
4
|
-
"sourcesContent": ["import { readdir , readFile, stat } from 'node:fs/promises';\nimport { basename, dirname, join, relative, resolve } from 'node:path';\n\nimport type {\n ActionDeclaration,\n ActionReference,\n ActionTargetKind,\n AnalysisReport,\n FileReport,\n} from './types.js';\n\nimport { collectDeclarations, collectReferences } from './action-references.js';\nimport { analyzeReferencedApex } from './apex-analyze.js';\nimport { collectScopes, complexityForFile } from './complexity.js';\nimport { extractDeveloperName, parseAgentSource } from './parse.js';\n\nexport interface AnalyzeOptions {\n /** Override location for apex:// resolution. Optional. */\n apexSourceOverride?: string;\n /**\n * Filter to specific agent bundles by API name. Each entry is matched\n * against (a) the bundle directory name and (b) `config.developer_name`\n * inside the .agent file. When omitted or empty, all discovered bundles\n * are analyzed.\n */\n apiNames?: string[];\n /**\n * Base directory for relative paths in the report. Defaults to the source\n * root (or, when multiple roots are supplied, the longest common ancestor).\n */\n reportBase?: string;\n}\n\n/**\n * Error thrown when --api-name filters produce no matches. Carries the\n * candidate list so callers can show a useful hint.\n */\nexport class NoMatchingBundlesError extends Error {\n constructor(\n public readonly requested: string[],\n public readonly available: BundleIdentity[],\n ) {\n super(\n `No agent bundle matched ${requested.map(n => `'${n}'`).join(', ')}. ` +\n `Available: ${available.map((b) => formatBundleIdentity(b)).join(', ')}`,\n );\n this.name = 'NoMatchingBundlesError';\n }\n}\n\nexport interface BundleIdentity {\n /** The config.developer_name value, if present. */\n developerName: string | undefined;\n /** The bundle's directory name (parent of the .agent file). */\n dirName: string;\n /** Absolute path of the .agent file. */\n path: string;\n}\n\nfunction formatBundleIdentity(b: BundleIdentity): string {\n if (b.developerName && b.developerName !== b.dirName) {\n return `${b.developerName} (dir: ${b.dirName})`;\n }\n\n return b.dirName;\n}\n\n/**\n * Analyze AgentScript bundles under one or more source roots.\n *\n * Backward-compatible: pass a single path (string) for the legacy\n * single-root case. Pass an array of paths for multi-root analysis\n * (e.g. multiple `packageDirectories` in an sfdx project).\n */\nexport async function analyzeSource(\n rootPathOrPaths: string | string[],\n options: AnalyzeOptions = {},\n): Promise<AnalysisReport> {\n const rawRoots = Array.isArray(rootPathOrPaths)\n ? rootPathOrPaths\n : [rootPathOrPaths];\n if (rawRoots.length === 0) {\n throw new Error('analyzeSource requires at least one source path');\n }\n\n const absRoots = rawRoots.map(p => resolve(p));\n const reportBase = options.reportBase\n ? resolve(options.reportBase)\n : absRoots.length === 1\n ? absRoots[0]\n : longestCommonAncestor(absRoots);\n\n const allFiles: string[] = [];\n for (const root of absRoots) {\n const files = await findAgentFiles(root);\n for (const f of files) if (!allFiles.includes(f)) allFiles.push(f);\n }\n\n allFiles.sort();\n\n const filteredFiles = await filterByApiNames(allFiles, options.apiNames);\n\n const fileReports: FileReport[] = [];\n for (const file of filteredFiles) {\n fileReports.push(await analyzeFile(file, reportBase));\n }\n\n const apex = await analyzeReferencedApex({\n agentAbsPaths: filteredFiles,\n apexSourceOverride: options.apexSourceOverride,\n fileReports,\n sourceDirRoot: reportBase,\n });\n\n const report: AnalysisReport = {\n apexClasses: apex.classes,\n byTargetKind: tallyTargets(fileReports),\n files: fileReports,\n totalApexComplexity: apex.classes.reduce((acc, c) => acc + c.classComplexity, 0),\n totalComplexity: fileReports.reduce((acc, f) => acc + f.fileComplexity, 0),\n totalDeclarations: fileReports.reduce((acc, f) => acc + f.declarations.length, 0),\n totalReferences: fileReports.reduce((acc, f) => acc + f.references.length, 0),\n unresolvedApexTargets: apex.unresolved,\n };\n return report;\n}\n\nexport async function analyzeFile(absPath: string, base: string): Promise<FileReport> {\n const source = await readFile(absPath, 'utf8');\n const root = parseAgentSource(source);\n\n const cc = complexityForFile(root);\n const {procedures} = cc;\n\n const scopes = collectScopes(root);\n const declarations: ActionDeclaration[] = [];\n const references: ActionReference[] = [];\n for (const s of scopes) {\n declarations.push(...collectDeclarations(s));\n references.push(...collectReferences(s));\n }\n\n return {\n declarations,\n fileComplexity: cc.total,\n parseErrors: [], // CST is error-tolerant; surface diagnostics in a later iteration.\n path: relative(base, absPath),\n procedures,\n references,\n };\n}\n\nasync function findAgentFiles(root: string): Promise<string[]> {\n const s = await stat(root).catch(() => {});\n if (!s) throw new Error(`source path does not exist: ${root}`);\n if (s.isFile()) return root.endsWith('.agent') ? [root] : [];\n\n const out: string[] = [];\n const visit = async (dir: string) => {\n const entries = await readdir(dir, { withFileTypes: true });\n for (const e of entries) {\n if (e.name.startsWith('.')) continue;\n if (e.name === 'node_modules' || e.name === 'vendor' || e.name === 'lib') continue;\n const full = join(dir, e.name);\n if (e.isDirectory()) await visit(full);\n else if (e.isFile() && e.name.endsWith('.agent')) out.push(full);\n }\n };\n\n await visit(root);\n out.sort();\n return out;\n}\n\nfunction tallyTargets(files: FileReport[]): Record<ActionTargetKind, number> {\n const acc: Record<ActionTargetKind, number> = {\n apex: 0,\n flow: 0,\n prompt: 0,\n unknown: 0,\n utils: 0,\n };\n for (const f of files) for (const d of f.declarations) acc[d.targetKind]++;\n return acc;\n}\n\n/**\n * Filter the discovered .agent file list by the supplied `--api-name`\n * values. A bundle matches if (a) its directory name equals a requested\n * name, or (b) its `config.developer_name` equals one. Bundles whose dir\n * name already matches are kept without parsing; only the remainder are\n * parsed for `developer_name` resolution.\n *\n * Throws NoMatchingBundlesError when filters were supplied but nothing\n * matched, so callers can show the available list.\n */\nasync function filterByApiNames(\n files: string[],\n apiNames: string[] | undefined,\n): Promise<string[]> {\n if (!apiNames || apiNames.length === 0) return files;\n const wanted = new Set(apiNames);\n\n const matches: string[] = [];\n const unmatched: string[] = [];\n for (const file of files) {\n const dirName = basename(dirname(file));\n if (wanted.has(dirName)) {\n matches.push(file);\n } else {\n unmatched.push(file);\n }\n }\n\n if (matches.length === files.length || unmatched.length === 0) {\n return matches;\n }\n\n // Slow path: parse the still-unmatched files to read developer_name.\n const identities: BundleIdentity[] = [];\n for (const file of unmatched) {\n const dirName = basename(dirname(file));\n const developerName = await readDeveloperName(file);\n identities.push({ developerName, dirName, path: file });\n if (developerName && wanted.has(developerName)) {\n matches.push(file);\n }\n }\n\n if (matches.length === 0) {\n // Build the full candidate list (matched dirs + parsed unmatched) for\n // the error message.\n const all: BundleIdentity[] = [];\n for (const file of files) {\n const existing = identities.find(i => i.path === file);\n if (existing) {\n all.push(existing);\n } else {\n all.push({\n developerName: await readDeveloperName(file),\n dirName: basename(dirname(file)),\n path: file,\n });\n }\n }\n\n all.sort((a, b) => a.dirName.localeCompare(b.dirName));\n throw new NoMatchingBundlesError(apiNames, all);\n }\n\n matches.sort();\n return matches;\n}\n\nasync function readDeveloperName(file: string): Promise<string | undefined> {\n const source = await readFile(file, 'utf8');\n const root = parseAgentSource(source);\n return extractDeveloperName(root);\n}\n\nfunction longestCommonAncestor(paths: string[]): string {\n if (paths.length === 0) return process.cwd();\n if (paths.length === 1) return paths[0];\n const split = paths.map(p => p.split('/'));\n const minLen = Math.min(...split.map(s => s.length));\n const common: string[] = [];\n for (let i = 0; i < minLen; i++) {\n const seg = split[0][i];\n if (split.every(s => s[i] === seg)) common.push(seg);\n else break;\n }\n\n const joined = common.join('/') || '/';\n return joined;\n}\n", "/*\n * Copyright (c) 2026, Salesforce, Inc.\n * All rights reserved.\n * SPDX-License-Identifier: Apache-2.0\n * For full license text, see the LICENSE file in the repo root or https://www.apache.org/licenses/LICENSE-2.0\n */\n/** Shared empty array for leaf nodes \u2014 avoids allocating [] per node. */\nconst EMPTY_CHILDREN = Object.freeze([]);\nexport class CSTNode {\n type;\n /** Whether this is a \"named\" node (true) or anonymous punctuation/keyword (false). */\n isNamed;\n isError;\n isMissing;\n startOffset;\n endOffset;\n // Flat position storage \u2014 avoids object allocations per node.\n // Also exposed as startPosition/endPosition getters for compat.\n startRow;\n startCol;\n endRow;\n endCol;\n /** Lazy children array \u2014 null for leaf nodes, allocated on first appendChild. */\n _children = null;\n parent = null;\n /** Index of this node within its parent's children array. -1 if no parent. */\n _childIndex = -1;\n /** Field name \u2192 child indices. Lazy: null until first field is added. */\n _fields = null;\n /** Reverse map: child index \u2192 field name. Built lazily. */\n _childFieldNames = null;\n /** Cached named children. */\n _namedChildren = null;\n /** The original source string, shared across all nodes in a tree. */\n _source;\n constructor(type, source, startOffset, endOffset, startPosition, endPosition, isNamed = true, isError = false, isMissing = false) {\n this.type = type;\n this._source = source;\n this.startOffset = startOffset;\n this.endOffset = endOffset;\n this.startRow = startPosition.row;\n this.startCol = startPosition.column;\n this.endRow = endPosition.row;\n this.endCol = endPosition.column;\n this.isNamed = isNamed;\n this.isError = isError;\n this.isMissing = isMissing;\n }\n get text() {\n return this._source.slice(this.startOffset, this.endOffset);\n }\n get startPosition() {\n return { row: this.startRow, column: this.startCol };\n }\n set startPosition(pos) {\n this.startRow = pos.row;\n this.startCol = pos.column;\n }\n get endPosition() {\n return { row: this.endRow, column: this.endCol };\n }\n set endPosition(pos) {\n this.endRow = pos.row;\n this.endCol = pos.column;\n }\n get children() {\n return (this._children ?? EMPTY_CHILDREN);\n }\n set children(value) {\n this._children = value;\n }\n get namedChildren() {\n if (!this._namedChildren) {\n this._namedChildren = this.children.filter(c => c.isNamed);\n }\n return this._namedChildren;\n }\n get previousSibling() {\n if (!this.parent || this._childIndex <= 0)\n return null;\n return this.parent.children[this._childIndex - 1];\n }\n get nextSibling() {\n if (!this.parent)\n return null;\n const siblings = this.parent.children;\n return this._childIndex < siblings.length - 1\n ? siblings[this._childIndex + 1]\n : null;\n }\n childForFieldName(name) {\n if (!this._fields)\n return null;\n const indices = this._fields.get(name);\n if (!indices || indices.length === 0)\n return null;\n return this.children[indices[0]] ?? null;\n }\n childrenForFieldName(name) {\n if (!this._fields)\n return [];\n const indices = this._fields.get(name);\n if (!indices)\n return [];\n return indices.map(i => this.children[i]).filter(Boolean);\n }\n /** True if this node or any descendant has an error or missing node. */\n get hasError() {\n if (this.isError || this.isMissing)\n return true;\n return this.children.some(c => c.hasError);\n }\n /** Get the field name for a child at a given index. */\n fieldNameForChild(index) {\n if (!this._fields)\n return null;\n if (!this._childFieldNames) {\n this._childFieldNames = new Map();\n for (const [fieldName, indices] of this._fields) {\n for (const idx of indices) {\n this._childFieldNames.set(idx, fieldName);\n }\n }\n }\n return this._childFieldNames.get(index) ?? null;\n }\n /** Add a child node, optionally associating it with a field name. */\n appendChild(child, fieldName) {\n if (!this._children)\n this._children = [];\n const idx = this._children.length;\n child.parent = this;\n child._childIndex = idx;\n this._children.push(child);\n // Track end position incrementally\n this.endRow = child.endRow;\n this.endCol = child.endCol;\n this.endOffset = child.endOffset;\n if (fieldName) {\n if (!this._fields)\n this._fields = new Map();\n let arr = this._fields.get(fieldName);\n if (!arr) {\n arr = [];\n this._fields.set(fieldName, arr);\n }\n arr.push(idx);\n }\n }\n /** @deprecated No-op: appendChild() tracks end position incrementally. */\n finalize() {\n // No-op \u2014 appendChild() updates endOffset/endPosition incrementally.\n }\n /** Serialize to s-expression format for testing (named nodes only, no text). */\n toSExp() {\n return nodeToSExp(this);\n }\n /**\n * Serialize to verbose s-expression format that includes ALL nodes\n * (both named and anonymous) with truncated text content.\n * Matches the source-of-truth format in sot/source.s-expression.\n */\n toVerboseSExp() {\n return nodeToVerboseSExp(this, 0);\n }\n}\n/** Create a leaf node (no children) from a token. */\nexport function leafNode(type, source, startOffset, endOffset, startPosition, endPosition, isNamed = true, isError = false, isMissing = false) {\n return new CSTNode(type, source, startOffset, endOffset, startPosition, endPosition, isNamed, isError, isMissing);\n}\n/**\n * Serialize a CST to s-expression format matching tree-sitter output.\n * Only named nodes appear; anonymous nodes (punctuation, keywords) are hidden.\n * Field names appear as `field: (node)`.\n */\nfunction nodeToSExp(node) {\n const parts = [];\n for (let i = 0; i < node.children.length; i++) {\n const child = node.children[i];\n if (!child.isNamed && !child.isError && !child.isMissing)\n continue; // Skip anonymous tokens\n const fieldName = node.fieldNameForChild(i);\n const childStr = child.children.length > 0 || child.isError\n ? nodeToSExp(child)\n : child.isMissing\n ? `(MISSING ${child.type})`\n : `(${child.type})`;\n if (fieldName) {\n parts.push(`${fieldName}: ${childStr}`);\n }\n else {\n parts.push(childStr);\n }\n }\n if (node.isError) {\n if (parts.length === 0) {\n return `(ERROR)`;\n }\n return `(ERROR ${parts.join(' ')})`;\n }\n if (node.isMissing) {\n return `(MISSING ${node.type})`;\n }\n if (parts.length === 0) {\n return `(${node.type})`;\n }\n return `(${node.type} ${parts.join(' ')})`;\n}\n/**\n * Verbose s-expression: includes ALL nodes (named + anonymous) with text.\n * Leaf text is truncated to 20 chars with `\u2026`.\n * Format: (type \"text\") for leaves, (type children...) for branches.\n */\nfunction nodeToVerboseSExp(node, depth) {\n const indent = ' '.repeat(depth);\n // MISSING nodes always render as (MISSING \"type\")\n if (node.isMissing) {\n return `${indent}(MISSING ${JSON.stringify(node.type)})`;\n }\n // ERROR nodes\n if (node.isError && node.children.length === 0) {\n return `${indent}(ERROR)`;\n }\n if (node.children.length === 0) {\n // Leaf node \u2014 show text\n const rawText = node.text;\n const truncated = rawText.length > 20 ? rawText.slice(0, 20) + '\u2026' : rawText;\n const escaped = JSON.stringify(truncated);\n return `${indent}(${node.type} ${escaped})`;\n }\n // Branch node \u2014 recurse\n const childLines = [];\n for (const child of node.children) {\n childLines.push(nodeToVerboseSExp(child, depth + 1));\n }\n return `${indent}(${node.type}\\n${childLines.join('\\n')})`;\n}\n//# sourceMappingURL=cst-node.js.map", "/*\n * Copyright (c) 2026, Salesforce, Inc.\n * All rights reserved.\n * SPDX-License-Identifier: Apache-2.0\n * For full license text, see the LICENSE file in the repo root or https://www.apache.org/licenses/LICENSE-2.0\n */\n/** Token kinds produced by the lexer. */\nexport var TokenKind;\n(function (TokenKind) {\n // Synthetic indentation tokens\n TokenKind[\"NEWLINE\"] = \"NEWLINE\";\n TokenKind[\"INDENT\"] = \"INDENT\";\n TokenKind[\"DEDENT\"] = \"DEDENT\";\n TokenKind[\"EOF\"] = \"EOF\";\n // Identifiers & literals\n TokenKind[\"ID\"] = \"ID\";\n TokenKind[\"NUMBER\"] = \"NUMBER\";\n TokenKind[\"STRING\"] = \"STRING\";\n TokenKind[\"STRING_CONTENT\"] = \"STRING_CONTENT\";\n TokenKind[\"ESCAPE_SEQUENCE\"] = \"ESCAPE_SEQUENCE\";\n TokenKind[\"DATETIME\"] = \"DATETIME\";\n TokenKind[\"TEMPLATE_CONTENT\"] = \"TEMPLATE_CONTENT\";\n // Operators\n TokenKind[\"PLUS\"] = \"PLUS\";\n TokenKind[\"MINUS\"] = \"MINUS\";\n TokenKind[\"STAR\"] = \"STAR\";\n TokenKind[\"SLASH\"] = \"SLASH\";\n TokenKind[\"DOT\"] = \"DOT\";\n TokenKind[\"COMMA\"] = \"COMMA\";\n TokenKind[\"COLON\"] = \"COLON\";\n TokenKind[\"EQ\"] = \"EQ\";\n TokenKind[\"EQEQ\"] = \"EQEQ\";\n TokenKind[\"NEQ\"] = \"NEQ\";\n TokenKind[\"LT\"] = \"LT\";\n TokenKind[\"GT\"] = \"GT\";\n TokenKind[\"LTE\"] = \"LTE\";\n TokenKind[\"GTE\"] = \"GTE\";\n TokenKind[\"ARROW\"] = \"ARROW\";\n TokenKind[\"ELLIPSIS\"] = \"ELLIPSIS\";\n TokenKind[\"PERCENT\"] = \"PERCENT\";\n TokenKind[\"PIPE\"] = \"PIPE\";\n TokenKind[\"AT\"] = \"AT\";\n // Delimiters\n TokenKind[\"LPAREN\"] = \"LPAREN\";\n TokenKind[\"RPAREN\"] = \"RPAREN\";\n TokenKind[\"LBRACKET\"] = \"LBRACKET\";\n TokenKind[\"RBRACKET\"] = \"RBRACKET\";\n TokenKind[\"LBRACE\"] = \"LBRACE\";\n TokenKind[\"RBRACE\"] = \"RBRACE\";\n TokenKind[\"TEMPLATE_EXPR_START\"] = \"TEMPLATE_EXPR_START\";\n // Sequence\n TokenKind[\"DASH_SPACE\"] = \"DASH_SPACE\";\n // Quote characters (for CST fidelity)\n TokenKind[\"DQUOTE\"] = \"DQUOTE\";\n // Special\n TokenKind[\"COMMENT\"] = \"COMMENT\";\n TokenKind[\"ERROR_TOKEN\"] = \"ERROR_TOKEN\";\n})(TokenKind || (TokenKind = {}));\nexport function isTokenKind(token, kind) {\n return token.kind === kind;\n}\n//# sourceMappingURL=token.js.map", "var isProduction = process.env.NODE_ENV === 'production';\nvar prefix = 'Invariant failed';\nfunction invariant(condition, message) {\n if (condition) {\n return;\n }\n if (isProduction) {\n throw new Error(prefix);\n }\n var provided = typeof message === 'function' ? message() : message;\n var value = provided ? \"\".concat(prefix, \": \").concat(provided) : prefix;\n throw new Error(value);\n}\n\nexport { invariant as default };\n", "/*\n * Copyright (c) 2026, Salesforce, Inc.\n * All rights reserved.\n * SPDX-License-Identifier: Apache-2.0\n * For full license text, see the LICENSE file in the repo root or https://www.apache.org/licenses/LICENSE-2.0\n */\n/**\n * Indentation-aware lexer for AgentScript.\n *\n * Produces a flat Token[] array including synthetic INDENT, DEDENT, and NEWLINE\n * tokens. Keywords are emitted as ID \u2014 the parser checks token text.\n *\n * Indentation: space = 1 unit, tab = 3 units (matching scanner.c).\n */\nimport invariant from 'tiny-invariant';\nimport { TokenKind } from './token.js';\n// ---------------------------------------------------------------------------\n// Character classification via charCode (replaces regex hot-path checks)\n// ---------------------------------------------------------------------------\nconst CH_TAB = 9; // \\t\nconst CH_LF = 10; // \\n\nconst CH_CR = 13; // \\r\nconst CH_SPACE = 32;\nconst CH_BANG = 33; // !\nconst CH_DQUOTE = 34; // \"\nconst CH_HASH = 35; // #\nconst CH_DASH = 45; // -\nconst CH_DOT = 46; // .\nconst CH_0 = 48;\nconst CH_9 = 57;\nconst CH_LT = 60; // <\nconst CH_EQ = 61; // =\nconst CH_GT = 62; // >\nconst CH_A = 65;\nconst CH_Z = 90;\nconst CH_BACKSLASH = 92; // \\\nconst CH_UNDERSCORE = 95; // _\nconst CH_a = 97;\nconst CH_z = 122;\nconst CH_LBRACE = 123; // {\nconst CH_NUL = 0;\nfunction isIdStart(c) {\n return ((c >= CH_A && c <= CH_Z) || (c >= CH_a && c <= CH_z) || c === CH_UNDERSCORE);\n}\nfunction isIdCont(c) {\n return isIdStart(c) || (c >= CH_0 && c <= CH_9);\n}\nfunction isDigit(c) {\n return c >= CH_0 && c <= CH_9;\n}\nfunction isHorizontalWs(c) {\n return c === CH_SPACE || c === CH_TAB;\n}\n// ---------------------------------------------------------------------------\n// charCode-indexed single-char token lookup (replaces Record<string, TokenKind>)\n// ---------------------------------------------------------------------------\nconst SINGLE_CHAR_TOKENS = new Array(128).fill(0);\nSINGLE_CHAR_TOKENS[43] = TokenKind.PLUS; // +\nSINGLE_CHAR_TOKENS[CH_DASH] = TokenKind.MINUS; // -\nSINGLE_CHAR_TOKENS[42] = TokenKind.STAR; // *\nSINGLE_CHAR_TOKENS[47] = TokenKind.SLASH; // /\n// % is not a valid operator in AgentScript (tree-sitter parity)\nSINGLE_CHAR_TOKENS[CH_DOT] = TokenKind.DOT; // .\nSINGLE_CHAR_TOKENS[44] = TokenKind.COMMA; // ,\nSINGLE_CHAR_TOKENS[58] = TokenKind.COLON; // :\nSINGLE_CHAR_TOKENS[61] = TokenKind.EQ; // =\nSINGLE_CHAR_TOKENS[60] = TokenKind.LT; // <\nSINGLE_CHAR_TOKENS[CH_GT] = TokenKind.GT; // >\nSINGLE_CHAR_TOKENS[124] = TokenKind.PIPE; // |\nSINGLE_CHAR_TOKENS[64] = TokenKind.AT; // @\nSINGLE_CHAR_TOKENS[40] = TokenKind.LPAREN; // (\nSINGLE_CHAR_TOKENS[41] = TokenKind.RPAREN; // )\nSINGLE_CHAR_TOKENS[91] = TokenKind.LBRACKET; // [\nSINGLE_CHAR_TOKENS[93] = TokenKind.RBRACKET; // ]\nSINGLE_CHAR_TOKENS[CH_LBRACE] = TokenKind.LBRACE; // {\nSINGLE_CHAR_TOKENS[125] = TokenKind.RBRACE; // }\nexport class Lexer {\n source;\n offset = 0;\n row = 0;\n col = 0;\n tokens = [];\n indentStack = [0];\n /** True when the current line started with `|` (template line). */\n onTemplateLine = false;\n /** Indent level of the line containing `|`. Content deeper than this is template content. */\n templateBaseIndent = -1;\n /** Nested brace depth inside a template expression (for `{` inside `{!...}`). -1 means not inside a template expression. */\n templateExprBraceDepth = -1;\n get inTemplateExpr() {\n return this.templateExprBraceDepth >= 0;\n }\n /** Parenthesis depth \u2014 suppresses INDENT/DEDENT/NEWLINE when > 0 to support multi-line call expressions. */\n bracketDepth = 0;\n constructor(source) {\n this.source = source;\n }\n tokenize() {\n // Pre-allocate token array backing store for large inputs\n this.tokens = [];\n const estimate = (this.source.length / 8) | 0;\n if (estimate > 64) {\n this.tokens.length = estimate;\n this.tokens.length = 0;\n }\n this.offset = 0;\n this.row = 0;\n this.col = 0;\n this.indentStack = [0];\n this.bracketDepth = 0;\n while (this.hasMore) {\n this.tokenizeLine();\n }\n // Emit remaining DEDENTs\n while (this.indentStack.length > 1) {\n this.indentStack.pop();\n this.emitVirtual(TokenKind.DEDENT);\n }\n this.emitVirtual(TokenKind.EOF);\n return this.tokens;\n }\n tokenizeLine() {\n // Note: onTemplateLine persists across continuation lines and is only\n // reset when indentation decreases (DEDENT) in emitIndentation().\n // Measure leading indentation\n const indentLength = this.consumeIndentation();\n if (this.consumeNewline()) {\n return;\n }\n const c = this.peekCharCode();\n // Comment-only line: tree-sitter's scanner skips past comment-only lines\n // when deciding INDENT/DEDENT. If this comment is at deeper indent than\n // current but no real content follows at that depth, emit NEWLINE instead.\n // Similarly, if a comment is at shallower indent but the next real content\n // is back at the current block's depth, suppress the DEDENT.\n // When on a template line, only treat `#` as a comment if it's at or below\n // the template's base indent (outside the template content area).\n if (c === CH_HASH &&\n (!this.onTemplateLine || indentLength <= this.templateBaseIndent)) {\n const currentIndent = this.indentStack[this.indentStack.length - 1];\n if (indentLength > currentIndent) {\n const nextContentIndent = this.peekNextContentIndent();\n if (nextContentIndent < indentLength) {\n // No real content at this depth \u2014 suppress INDENT\n this.emitIndentation(currentIndent);\n return this.tokenizeComment();\n }\n }\n else if (indentLength < currentIndent) {\n const nextContentIndent = this.peekNextContentIndent();\n if (nextContentIndent > indentLength) {\n // Next real content is at a deeper indent than the comment.\n // Emit indentation based on where the next content is, not\n // where the comment sits, so we only close the blocks that\n // actually end (not the ones the comment just happens to be\n // outside of).\n this.emitIndentation(nextContentIndent);\n return this.tokenizeComment();\n }\n }\n else {\n // Comment at same indent as current block. If next real content\n // is deeper (i.e. the comment sits between a key and its indented\n // body), suppress NEWLINE so the body's INDENT fires on the next\n // iteration. Example:\n // a:\n // # comment \u2190 same indent as current block\n // body: \"x\" \u2190 should INDENT into a's body\n const nextContentIndent = this.peekNextContentIndent();\n if (nextContentIndent > indentLength) {\n return this.tokenizeComment();\n }\n }\n this.emitIndentation(indentLength);\n return this.tokenizeComment();\n }\n // Normal line \u2014 emit indentation tokens.\n // Template continuation lines (deeper than templateBaseIndent) should\n // not cause INDENT/DEDENT when their indent varies relative to other\n // template lines. The initial INDENT into the template block is needed\n // (it establishes the template_content grammar rule), but subsequent\n // indent variation within the template corrupts the indent stack and\n // breaks downstream blocks. Detect \"already inside template block\" by\n // checking if the indent stack top is already deeper than templateBaseIndent.\n const currentIndent = this.indentStack[this.indentStack.length - 1];\n if (this.onTemplateLine &&\n indentLength > this.templateBaseIndent &&\n currentIndent > this.templateBaseIndent &&\n indentLength !== currentIndent) {\n this.emitIndentation(currentIndent);\n }\n else {\n this.emitIndentation(indentLength);\n }\n // Check for \"- \" sequence element at start of content\n if (this.bracketDepth === 0 && c === CH_DASH) {\n const nc = this.peekCharCode(1); // NaN at EOF \u2014 won't match any CH_*\n const atEOF = this.offset + 1 >= this.source.length;\n if (nc === CH_SPACE || this.atNewline(1) || atEOF) {\n this.emit(TokenKind.DASH_SPACE, nc === CH_SPACE ? '- ' : '-');\n }\n }\n // Tokenize the rest of the line\n while (this.hasMore) {\n const c = this.peekCharCode();\n // Newline ends the line\n if (this.consumeNewline()) {\n return;\n }\n if (c === CH_CR) {\n // Not followed with line feed (otherwise this.consumeLine() would be true)\n invariant(!this.atNewline());\n this.advance();\n continue;\n }\n // Skip horizontal whitespace\n if (isHorizontalWs(c)) {\n this.advance();\n continue;\n }\n // Line continuation\n if (c === CH_BACKSLASH) {\n if (this.atNewline(1)) {\n this.advance(); // skip backslash\n invariant(this.consumeNewline());\n // Skip leading whitespace on continuation line\n while (isHorizontalWs(this.peekCharCode())) {\n this.advance();\n }\n continue;\n }\n }\n // Comment (but not on template content lines where # is literal text)\n if (c === CH_HASH && !this.onTemplateLine) {\n return this.tokenizeComment();\n }\n this.tokenizeToken();\n }\n }\n emitIndentation(indentLength) {\n if (this.bracketDepth > 0)\n return;\n const currentIndent = this.indentStack[this.indentStack.length - 1];\n if (indentLength > currentIndent) {\n this.indentStack.push(indentLength);\n this.emitVirtual(TokenKind.INDENT);\n }\n else if (indentLength < currentIndent) {\n // Emit DEDENTs and a NEWLINE; leave template context only when\n // indentation drops to or below the template's base indent level.\n if (indentLength <= this.templateBaseIndent) {\n this.onTemplateLine = false;\n this.templateExprBraceDepth = -1;\n }\n while (this.indentStack.length > 1 &&\n this.indentStack[this.indentStack.length - 1] > indentLength) {\n this.indentStack.pop();\n this.emitVirtual(TokenKind.DEDENT);\n }\n this.emitVirtual(TokenKind.NEWLINE);\n }\n else {\n // Same indent \u2014 emit NEWLINE (line separator) unless we're at the start.\n // Leave template context only when at or below the template's base indent.\n if (indentLength <= this.templateBaseIndent) {\n this.onTemplateLine = false;\n this.templateExprBraceDepth = -1;\n }\n if (this.tokens.length > 0) {\n this.emitVirtual(TokenKind.NEWLINE);\n }\n }\n }\n tokenizeToken() {\n const c = this.peekCharCode();\n // Datetimes or numbers\n if (isDigit(c)) {\n // Datetime literal: YYYY-MM-DD...\n // Must check before numbers since datetimes start with digits\n if (this.tryDatetime()) {\n return;\n }\n this.tokenizeNumber();\n return;\n }\n // Identifier\n if (isIdStart(c)) {\n this.tokenizeId();\n return;\n }\n // String (double-quoted always, single-quoted only if not a contraction)\n // Inside template lines (after |), quotes are literal characters \u2014 don't\n // start string tokenization unless we're inside a {!...} expression.\n if (!this.onTemplateLine || this.inTemplateExpr) {\n if (c === CH_DQUOTE) {\n this.tokenizeString();\n return;\n }\n }\n // Template expression start {!\n if (c === CH_LBRACE && this.peekCharCode(1) === CH_BANG) {\n this.templateExprBraceDepth = 0;\n this.emit(TokenKind.TEMPLATE_EXPR_START, '{!');\n return;\n }\n // Tokens beginning with .\n if (c === CH_DOT) {\n if (this.peekCharCode(1) === CH_DOT && this.peekCharCode(2) === CH_DOT) {\n this.emit(TokenKind.ELLIPSIS, '...');\n return;\n }\n // Leading-dot number (e.g., .5, .123) \u2014 but not after identifiers\n // (which would be member access like @variable.5)\n if (isDigit(this.peekCharCode(1))) {\n const prev = this.tokens[this.tokens.length - 1];\n const isMemberAccess = prev !== undefined &&\n (prev.kind === TokenKind.ID ||\n prev.kind === TokenKind.NUMBER ||\n prev.kind === TokenKind.RPAREN ||\n prev.kind === TokenKind.RBRACKET);\n if (!isMemberAccess) {\n this.tokenizeNumber();\n return;\n }\n }\n }\n if (c === CH_DASH) {\n if (this.peekCharCode(1) === CH_GT) {\n return this.emit(TokenKind.ARROW, '->');\n }\n }\n // == != <= >=\n const nc = this.peekCharCode(1);\n if (nc === CH_EQ) {\n // next is '='\n if (c === CH_EQ) {\n return this.emit(TokenKind.EQEQ, '==');\n }\n if (c === CH_BANG) {\n return this.emit(TokenKind.NEQ, '!=');\n }\n if (c === CH_LT) {\n return this.emit(TokenKind.LTE, '<=');\n }\n if (c === CH_GT) {\n return this.emit(TokenKind.GTE, '>=');\n }\n }\n // Single-char tokens (charCode-indexed lookup)\n const kind = c < 128 ? SINGLE_CHAR_TOKENS[c] : 0;\n if (kind) {\n this.emitSpan(kind, 1);\n switch (kind) {\n // Track template lines: `|` starts a template context for this line\n // and continuation lines indented deeper than this level.\n case TokenKind.PIPE:\n this.onTemplateLine = true;\n this.templateBaseIndent =\n this.indentStack[this.indentStack.length - 1];\n break;\n // Track parenthesis depth to suppress structural tokens inside\n // multi-line call expressions. Skip when inside a template line \u2014\n // parens in template content are literal text and must not suppress\n // INDENT/DEDENT emission (unmatched parens would eat the rest of\n // the file).\n case TokenKind.LPAREN:\n if (!this.onTemplateLine)\n this.bracketDepth++;\n break;\n case TokenKind.RPAREN:\n if (!this.onTemplateLine)\n this.bracketDepth--;\n break;\n // Track brace depth inside {!...} template expressions so that nested\n // braces (e.g. JSON objects) don't prematurely close the expression.\n case TokenKind.LBRACE:\n if (this.inTemplateExpr) {\n this.templateExprBraceDepth++;\n }\n break;\n case TokenKind.RBRACE:\n if (this.inTemplateExpr) {\n this.templateExprBraceDepth--;\n }\n break;\n }\n return;\n }\n // Unknown character \u2014 emit error token\n this.emitSpan(TokenKind.ERROR_TOKEN, 1);\n }\n tokenizeId() {\n let i = 0;\n for (;; i++) {\n const c = this.peekCharCode(i);\n if (!isIdCont(c))\n break;\n }\n this.emitSpan(TokenKind.ID, i);\n }\n tokenizeNumber() {\n let tokenLength = 0;\n // Leading dot (e.g., .5) \u2014 consume the `.` first\n const leadingDot = this.peekCharCode(tokenLength) === CH_DOT;\n if (leadingDot) {\n tokenLength++;\n }\n // Integer part \u2014 inline advance (digits never contain newlines)\n while (isDigit(this.peekCharCode(tokenLength))) {\n tokenLength++;\n }\n // Decimal part \u2014 only consume `.` if followed by a digit (and no leading dot)\n if (!leadingDot && this.peekCharCode(tokenLength) === CH_DOT) {\n tokenLength++;\n }\n while (isDigit(this.peekCharCode(tokenLength))) {\n tokenLength++;\n }\n this.emitSpan(TokenKind.NUMBER, tokenLength);\n }\n tryDatetime() {\n // ISO 8601: YYYY-MM-DD optionally followed by time\n // Need at least YYYY-MM-DD = 10 chars\n const remaining = this.source.length - this.offset;\n if (remaining < 10)\n return false;\n // Fast reject: most numbers aren't datetimes. Check the fixed '-' positions\n // before allocating a slice or running the regex.\n if (this.source.charCodeAt(this.offset + 4) !== CH_DASH ||\n this.source.charCodeAt(this.offset + 7) !== CH_DASH) {\n return false;\n }\n const slice = this.source.slice(this.offset, this.offset + 30);\n const match = slice.match(/^\\d{4}-\\d{2}-\\d{2}(T\\d{1,2}(:\\d{2})?(:\\d{2})?(\\.\\d+)?Z?)?/);\n if (!match)\n return false;\n // Only treat as datetime if it has the full YYYY-MM-DD pattern\n // and the character after isn't an identifier character\n const matchText = match[0];\n if (matchText.length < 10)\n return false; // Must have at least YYYY-MM-DD\n this.emit(TokenKind.DATETIME, matchText);\n return true;\n }\n tokenizeString() {\n const start = this.position;\n const startOffset = this.offset;\n const quoteCode = this.peekCharCode(); // \" or '\n // Opening quote\n this.advance();\n while (this.hasMore) {\n const c = this.peekCharCode();\n if (c === quoteCode) {\n this.advance(); // closing quote\n const text = this.source.slice(startOffset, this.offset);\n this.tokens.push(this.makeToken(TokenKind.STRING, text, start, this.position, startOffset));\n return;\n }\n if (c === CH_BACKSLASH) {\n this.advance(2);\n continue;\n }\n if (this.atNewline()) {\n // Unclosed string \u2014 stop at newline for error recovery\n break;\n }\n if (c === CH_CR) {\n // Bare \\r inside string \u2014 treat as content\n invariant(!this.atNewline());\n this.advance();\n continue;\n }\n if (c === CH_NUL) {\n // Null byte \u2014 tree-sitter rejects these in string content\n break;\n }\n this.advance();\n }\n // Unclosed string\n const text = this.source.slice(startOffset, this.offset);\n this.tokens.push(this.makeToken(TokenKind.STRING, text, start, this.position, startOffset));\n }\n tokenizeComment() {\n const start = this.position;\n const startOffset = this.offset;\n // Consume # and everything until end of line or EOF\n while (this.hasMore && !this.atNewline()) {\n this.advance();\n }\n const text = this.source.slice(startOffset, this.offset);\n this.tokens.push(this.makeToken(TokenKind.COMMENT, text, start, this.position, startOffset));\n this.consumeNewline();\n }\n consumeIndentation() {\n let indentLength = 0;\n while (this.hasMore) {\n const c = this.peekCharCode();\n if (c === CH_SPACE) {\n indentLength += 1;\n this.advance();\n }\n else if (c === CH_TAB) {\n indentLength += 3;\n this.advance();\n }\n else if (c === CH_CR) {\n // Bare \\r (not followed by \\n) resets indent to 0,\n // matching tree-sitter scanner.c behavior (line 140-142)\n indentLength = 0;\n this.advance();\n }\n else {\n break;\n }\n }\n return indentLength;\n }\n /**\n * Scan ahead (without advancing) past comment/blank lines to find the indent\n * of the next line with real (non-comment) content. Returns -1 if only\n * comments, blanks, or EOF remain. Matches tree-sitter scanner behavior which\n * skips past comment-only lines when computing INDENT/DEDENT.\n */\n peekNextContentIndent() {\n const startPosition = this.position;\n const startOffset = this.offset;\n // Skip past the current comment line\n while (this.hasMore) {\n if (this.consumeNewline())\n break;\n this.advance();\n }\n // Scan subsequent lines\n while (this.hasMore) {\n // Measure indent\n const lineIndent = this.consumeIndentation();\n // Blank line \u2014 skip\n if (this.consumeNewline())\n continue;\n // Comment line \u2014 skip\n const c = this.peekCharCode();\n if (c === CH_HASH) {\n while (this.hasMore) {\n if (this.consumeNewline())\n break;\n this.advance();\n }\n continue;\n }\n this.offset = startOffset;\n this.row = startPosition.row;\n this.col = startPosition.column;\n // Real content \u2014 return its indent\n return lineIndent;\n }\n this.offset = startOffset;\n this.row = startPosition.row;\n this.col = startPosition.column;\n return -1;\n }\n // --- Utility methods ---\n peekCharCode(additiveOffset = 0) {\n return this.source.charCodeAt(this.offset + additiveOffset);\n }\n get hasMore() {\n return this.offset < this.source.length && this.offset >= 0;\n }\n /**\n * Attempt to advance n characters.\n * @returns how many characters were advanced.\n */\n advance(n = 1) {\n n = Math.max(0, Math.min(n, this.source.length - this.offset));\n this.col += n;\n for (let i = 0; i < n; i++) {\n if (this.peekCharCode(i) === CH_LF) {\n this.row++;\n this.col = n - i - 1;\n }\n }\n this.offset += n;\n return n;\n }\n /**\n * Attempt to consume a newline.\n * @returns whether a newline was consumed.\n */\n consumeNewline() {\n const newChars = this.atNewline();\n if (newChars > 0) {\n invariant(this.advance(newChars));\n return true;\n }\n return false;\n }\n /**\n * Checks if the current position is at a newline.\n * @param additiveOffset\n * @returns 0 if not at a newline, 1 if at an LF newline, 2 if at a CR LF newline.\n */\n atNewline(additiveOffset = 0) {\n const firstChar = this.peekCharCode(additiveOffset);\n if (firstChar === CH_LF)\n return 1;\n if (firstChar === CH_CR && this.peekCharCode(additiveOffset + 1) === CH_LF)\n return 2;\n return 0;\n }\n get position() {\n return { row: this.row, column: this.col };\n }\n emitSpan(kind, length) {\n const text = this.source.slice(this.offset, this.offset + length);\n return this.emit(kind, text);\n }\n emit(kind, text) {\n const startPosition = this.position;\n const startOffset = this.offset;\n invariant(text === this.source.slice(startOffset, startOffset + text.length), `expected '${text}' but got ${this.source.slice(startOffset, startOffset + text.length)} at offset ${startOffset}`);\n this.advance(text.length);\n this.tokens.push(this.makeToken(kind, text, startPosition, this.position, startOffset));\n }\n emitVirtual(kind) {\n return this.emit(kind, '');\n }\n makeToken(kind, text, start, end, startOffset) {\n return { kind, text, start, end, startOffset };\n }\n}\n//# sourceMappingURL=lexer.js.map", "/*\n * Copyright (c) 2026, Salesforce, Inc.\n * All rights reserved.\n * SPDX-License-Identifier: Apache-2.0\n * For full license text, see the LICENSE file in the repo root or https://www.apache.org/licenses/LICENSE-2.0\n */\n/**\n * Error recovery utilities for the parser.\n *\n * Core invariant: NEWLINE and DEDENT are unconditional synchronization points.\n * No error ever cascades past them.\n */\nimport { TokenKind } from './token.js';\nimport { CSTNode } from './cst-node.js';\n/**\n * Create an ERROR node wrapping the given children.\n */\nexport function makeErrorNode(source, children, startOffset, endOffset, startPosition, endPosition) {\n const node = new CSTNode('ERROR', source, startOffset, endOffset, startPosition, endPosition, true, true);\n for (const child of children) {\n node.appendChild(child);\n }\n return node;\n}\n/**\n * Create a MISSING node \u2014 a node that was expected but not present in the source.\n */\nexport function makeMissingNode(type, source, position, offset) {\n return new CSTNode(type, source, offset, offset, position, position, true, false, true);\n}\n/**\n * Create a leaf node from a token.\n */\nexport function tokenToLeaf(token, source, isNamed, offset) {\n return new CSTNode(tokenTypeToNodeType(token), source, offset, offset + token.text.length, token.start, token.end, isNamed);\n}\n/** Named token kinds \u2014 tokens that become named CST children. */\nconst NAMED_TOKEN_KINDS = new Set([\n TokenKind.ID,\n TokenKind.NUMBER,\n TokenKind.STRING,\n TokenKind.DATETIME,\n TokenKind.COMMENT,\n TokenKind.ELLIPSIS,\n]);\n/** Create a leaf CST node from a token, auto-determining isNamed from its kind. */\nexport function tokenToAutoLeaf(token, source, offset) {\n return tokenToLeaf(token, source, NAMED_TOKEN_KINDS.has(token.kind), offset);\n}\nfunction tokenTypeToNodeType(token) {\n switch (token.kind) {\n case TokenKind.ID:\n return 'id';\n case TokenKind.NUMBER:\n return 'number';\n case TokenKind.STRING:\n return 'string';\n case TokenKind.DATETIME:\n return 'datetime_literal';\n case TokenKind.COMMENT:\n return 'comment';\n case TokenKind.ELLIPSIS:\n return 'ellipsis';\n default:\n return token.text;\n }\n}\n/** Check if a token kind is a synchronization point. */\nexport function isSyncPoint(kind) {\n return (kind === TokenKind.NEWLINE ||\n kind === TokenKind.DEDENT ||\n kind === TokenKind.EOF);\n}\n//# sourceMappingURL=errors.js.map", "/*\n * Copyright (c) 2026, Salesforce, Inc.\n * All rights reserved.\n * SPDX-License-Identifier: Apache-2.0\n * For full license text, see the LICENSE file in the repo root or https://www.apache.org/licenses/LICENSE-2.0\n */\n/**\n * Recovery and utility functions extracted from parser.ts.\n *\n * All functions take a ParserContext as their first argument,\n * following the free-function pattern established by expressions.ts.\n */\nimport { TokenKind } from './token.js';\nimport { CSTNode } from './cst-node.js';\nimport { makeErrorNode, tokenToAutoLeaf } from './errors.js';\n// --- Error recovery ---\n/** Create an empty ERROR node at the current position. */\nexport function makeEmptyError(ctx) {\n const offset = ctx.peekOffset();\n const pos = ctx.peek().start;\n return new CSTNode('ERROR', ctx.source, offset, offset, pos, pos, true, true);\n}\n/** Insert a missing target: `target: (expression (atom (ERROR)))` */\nexport function addMissingTarget(ctx, node) {\n const errAtom = makeEmptyError(ctx);\n const atom = new CSTNode('atom', ctx.source, errAtom.startOffset, errAtom.endOffset, errAtom.startPosition, errAtom.endPosition);\n atom.appendChild(errAtom);\n const expr = new CSTNode('expression', ctx.source, atom.startOffset, atom.endOffset, atom.startPosition, atom.endPosition);\n expr.appendChild(atom);\n node.appendChild(expr, 'target');\n}\n/** Create a MISSING node \u2014 an expected token/node that wasn't found in source. */\nexport function makeMissing(ctx, type) {\n const offset = ctx.peekOffset();\n const pos = ctx.peek().start;\n return new CSTNode(type, ctx.source, offset, offset, pos, pos, true, false, true);\n}\n/**\n * Parse a standalone else/elif/for (without a preceding if, or unsupported).\n * Wraps the entire block in an ERROR node, preserving parsed statements inside.\n *\n * @param parseProcedure - callback to parse procedure bodies, avoiding circular\n * dependency with parse-statements.ts\n */\nexport function parseOrphanBlock(ctx, parseProcedure) {\n const startOffset = ctx.peekOffset();\n const startPos = ctx.peek().start;\n const children = [];\n // Consume keyword and any tokens up to colon/newline.\n // Capture consumed tokens as children of the ERROR for dialect recovery.\n const keywordTok = ctx.consume();\n const kwOffset = ctx.currentOffset();\n children.push(new CSTNode(keywordTok.text, ctx.source, kwOffset, kwOffset + keywordTok.text.length, keywordTok.start, keywordTok.end, false));\n while (!ctx.isAtSyncPoint() &&\n !isAtEnd(ctx) &&\n ctx.peekKind() !== TokenKind.COLON) {\n ctx.consume(); // consume but don't add as named children \u2014 they're noise\n }\n // Consume colon if present\n if (ctx.peekKind() === TokenKind.COLON)\n ctx.consume();\n // Consume the body block\n if (ctx.peekKind() === TokenKind.INDENT) {\n ctx.consume();\n const proc = parseProcedure(ctx);\n if (proc) {\n for (const child of proc.namedChildren) {\n children.push(child);\n }\n }\n // Consume trailing comments left by parseProcedure's isTrailingCommentOnly guard\n while (ctx.peekKind() === TokenKind.COMMENT ||\n ctx.peekKind() === TokenKind.NEWLINE) {\n if (ctx.peekKind() === TokenKind.COMMENT) {\n children.push(ctx.consumeNamed('comment'));\n }\n else {\n ctx.consume();\n }\n }\n if (ctx.peekKind() === TokenKind.DEDENT)\n ctx.consume();\n }\n if (ctx.peekKind() === TokenKind.NEWLINE)\n ctx.consume();\n const endOffset = children.length > 0\n ? children[children.length - 1].endOffset\n : ctx.peekOffset();\n const endPos = children.length > 0\n ? children[children.length - 1].endPosition\n : ctx.peek().start;\n return makeErrorNode(ctx.source, children, startOffset, endOffset, startPos, endPos);\n}\n/**\n * Consume any leftover tokens in an indented block (before DEDENT) as ERROR\n * nodes. Prevents cascading failures when parseBlockValue() only partially\n * consumes the block content (e.g., unquoted multi-word text).\n */\nexport function recoverToBlockEnd(ctx, parent) {\n while (!isAtEnd(ctx) && ctx.peekKind() !== TokenKind.DEDENT) {\n if (ctx.peekKind() === TokenKind.NEWLINE) {\n ctx.consume();\n continue;\n }\n // Skip over nested indented blocks within the error zone\n if (ctx.peekKind() === TokenKind.INDENT) {\n ctx.consume();\n recoverToBlockEnd(ctx, parent);\n if (ctx.peekKind() === TokenKind.DEDENT)\n ctx.consume();\n continue;\n }\n const err = synchronize(ctx);\n if (err) {\n parent.appendChild(err);\n }\n else {\n break;\n }\n }\n}\n/**\n * Synchronize: skip tokens until a stopping condition is met.\n * Returns an ERROR node wrapping the skipped content, or null if\n * nothing was consumed.\n *\n * @param extraStop - optional predicate for additional stop conditions\n * beyond the default sync points (NEWLINE/DEDENT/EOF)\n */\nexport function synchronizeUntil(ctx, extraStop) {\n if (ctx.isAtSyncPoint() || isAtEnd(ctx))\n return null;\n if (extraStop && extraStop(ctx.peekKind(), ctx.peek().start.row))\n return null;\n const startOffset = ctx.peekOffset();\n const startPos = ctx.peek().start;\n const children = [];\n while (!ctx.isAtSyncPoint() &&\n !isAtEnd(ctx) &&\n !(extraStop && extraStop(ctx.peekKind(), ctx.peek().start.row))) {\n const tok = ctx.consume();\n children.push(tokenToAutoLeaf(tok, ctx.source, ctx.currentOffset()));\n }\n if (children.length === 0)\n return null;\n const last = children[children.length - 1];\n return makeErrorNode(ctx.source, children, startOffset, last.endOffset, startPos, last.endPosition);\n}\n/** Skip tokens on the given row until a sync point, INDENT, or COLON. */\nexport function synchronizeRowUntilColon(ctx, row) {\n return synchronizeUntil(ctx, (kind, r) => kind === TokenKind.INDENT || kind === TokenKind.COLON || r !== row);\n}\n/** Skip tokens on the given row until a sync point or INDENT. */\nexport function synchronizeRow(ctx, row) {\n return synchronizeUntil(ctx, (kind, r) => kind === TokenKind.INDENT || r !== row);\n}\n/** Skip tokens until the next sync point (NEWLINE/DEDENT/EOF). */\nexport function synchronize(ctx) {\n return synchronizeUntil(ctx);\n}\n// --- Utility ---\nexport function skipNewlines(ctx) {\n while (ctx.peekKind() === TokenKind.NEWLINE) {\n ctx.consume();\n }\n}\n/** Consume comment and newline tokens and attach to parent node. */\nexport function consumeCommentsAndSkipNewlines(ctx, parent) {\n while (true) {\n if (ctx.peekKind() === TokenKind.COMMENT) {\n parent.appendChild(ctx.consumeNamed('comment'));\n }\n else if (ctx.peekKind() === TokenKind.NEWLINE) {\n ctx.consume();\n }\n else {\n break;\n }\n }\n}\nexport function isAtEnd(ctx) {\n return ctx.peekKind() === TokenKind.EOF;\n}\n/** Check if from current position, there are only comments, newlines, and then EOF/DEDENT. */\nexport function isTrailingCommentOnly(ctx) {\n let i = 0;\n while (i < 50) {\n const tok = ctx.peekAt(i);\n if (tok.kind === TokenKind.EOF || tok.kind === TokenKind.DEDENT)\n return true;\n if (tok.kind === TokenKind.COMMENT || tok.kind === TokenKind.NEWLINE) {\n i++;\n continue;\n }\n return false;\n }\n return false; // Exceeded lookahead limit\n}\n//# sourceMappingURL=recovery.js.map", "/*\n * Copyright (c) 2026, Salesforce, Inc.\n * All rights reserved.\n * SPDX-License-Identifier: Apache-2.0\n * For full license text, see the LICENSE file in the repo root or https://www.apache.org/licenses/LICENSE-2.0\n */\n/**\n * Pratt expression parser for AgentScript.\n *\n * Precedence levels (matching grammar.js):\n * 0: ternary (X if C else Y) \u2014 right-associative\n * 1: or\n * 2: and\n * 3: not (prefix)\n * 4: ==, !=, <, >, <=, >=, is, is not, = (comparison)\n * 5: +, - (binary)\n * 6: *, /\n * 7: +, - (unary prefix)\n * 8: call, member, subscript (postfix)\n * 9: parenthesized (atomic)\n */\nimport { TokenKind } from './token.js';\nimport { CSTNode } from './cst-node.js';\n// Hoisted constants \u2014 avoid per-call allocation\n// Must match ESCAPE_TABLE in @agentscript/language (packages/language/src/core/string-escapes.ts)\nconst VALID_ESCAPES = new Set(['\"', \"'\", '\\\\', 'n', 'r', 't', '0']);\nconst KEY_STOP_KEYWORDS = new Set([\n 'if',\n 'elif',\n 'else',\n 'run',\n 'set',\n 'with',\n 'to',\n 'transition',\n 'available',\n 'and',\n 'or',\n 'not',\n 'is',\n 'True',\n 'False',\n 'None',\n 'mutable',\n 'linked',\n 'empty',\n]);\n/** Create a MISSING id wrapped in atom \u2192 expression at the current parser position. */\nfunction makeMissingArgument(ctx) {\n const offset = ctx.peekOffset();\n const pos = ctx.peek().start;\n const missingId = new CSTNode('id', ctx.source, offset, offset, pos, pos, true, false, true);\n const atom = new CSTNode('atom', ctx.source, offset, offset, pos, pos);\n atom.appendChild(missingId);\n const expr = new CSTNode('expression', ctx.source, offset, offset, pos, pos);\n expr.appendChild(atom);\n return expr;\n}\n/** Create an empty ERROR node at the current parser position. */\nfunction makeEmptyError(ctx) {\n const tok = ctx.peek();\n const offset = ctx.peekOffset();\n return new CSTNode('ERROR', ctx.source, offset, offset, tok.start, tok.start, true, true);\n}\nexport function parseExpression(ctx, minPrec = 0) {\n let left = parsePrefix(ctx);\n if (!left)\n return null;\n while (true) {\n // Fast path: sync points (NEWLINE/DEDENT/EOF) are never infix operators.\n // This avoids the infixPrecedence() lookup in the most common case for mappings.\n const nextKind = ctx.peekKind();\n if (nextKind === TokenKind.NEWLINE ||\n nextKind === TokenKind.DEDENT ||\n nextKind === TokenKind.EOF)\n break;\n const prec = infixPrecedence(ctx);\n if (prec < minPrec)\n break;\n const result = parseInfix(ctx, left, prec);\n if (!result)\n break;\n left = result;\n }\n return left;\n}\nfunction parsePrefix(ctx) {\n const tok = ctx.peek();\n // not (precedence 3)\n if (tok.kind === TokenKind.ID && tok.text === 'not') {\n return parseUnary(ctx, 'not', 3);\n }\n // Unary + / - (precedence 7)\n if (tok.kind === TokenKind.PLUS || tok.kind === TokenKind.MINUS) {\n const op = tok.text;\n return parseUnary(ctx, op, 7);\n }\n // Spread *expr (precedence 7)\n if (tok.kind === TokenKind.STAR) {\n return parseSpread(ctx);\n }\n // Parenthesized expression\n if (tok.kind === TokenKind.LPAREN) {\n return parseParenthesized(ctx);\n }\n // Atom\n return parseAtom(ctx);\n}\nfunction parseUnary(ctx, _op, prec) {\n const startTok = ctx.peek();\n const node = ctx.startNode('unary_expression');\n ctx.addAnonymousChild(node, ctx.consume()); // operator\n const operand = parseExpression(ctx, prec + 1);\n if (operand) {\n node.appendChild(wrapExpression(ctx, operand));\n }\n ctx.finishNode(node, startTok);\n return node;\n}\nfunction parseSpread(ctx) {\n const startTok = ctx.peek();\n const node = ctx.startNode('spread_expression');\n ctx.addAnonymousChild(node, ctx.consume()); // *\n // Bind at precedence 8 (same as postfix call/member/subscript) so\n // *@variables.x parses as *(variables.x), not (*variables).x\n const operand = parseExpression(ctx, 8);\n if (operand) {\n node.appendChild(wrapExpression(ctx, operand), 'expression');\n }\n ctx.finishNode(node, startTok);\n return node;\n}\nfunction parseParenthesized(ctx) {\n const startTok = ctx.peek();\n const node = ctx.startNode('parenthesized_expression');\n ctx.addAnonymousChild(node, ctx.consume()); // (\n const expr = parseExpression(ctx, 0);\n if (expr) {\n node.appendChild(wrapExpression(ctx, expr), 'expression');\n }\n else if (ctx.peekKind() === TokenKind.RPAREN) {\n // Empty parens () \u2192 insert MISSING id\n node.appendChild(makeMissingArgument(ctx), 'expression');\n }\n if (ctx.peekKind() === TokenKind.RPAREN) {\n ctx.addAnonymousChild(node, ctx.consume()); // )\n }\n else {\n // Unclosed paren \u2192 add ERROR node\n node.appendChild(makeEmptyError(ctx));\n }\n ctx.finishNode(node, startTok);\n return node;\n}\nfunction parseAtom(ctx) {\n const tok = ctx.peek();\n // Boolean / None constants\n if (tok.kind === TokenKind.ID &&\n (tok.text === 'True' || tok.text === 'False' || tok.text === 'None')) {\n const node = ctx.startNode('atom');\n ctx.addAnonymousChild(node, ctx.consume());\n ctx.finishNode(node, tok);\n return node;\n }\n // empty keyword\n if (tok.kind === TokenKind.ID && tok.text === 'empty') {\n const node = ctx.startNode('empty_keyword');\n ctx.addAnonymousChild(node, ctx.consume());\n ctx.finishNode(node, tok);\n return node;\n }\n // @id\n if (tok.kind === TokenKind.AT) {\n return parseAtId(ctx);\n }\n // id\n if (tok.kind === TokenKind.ID) {\n return ctx.consumeNamed('id');\n }\n // number\n if (tok.kind === TokenKind.NUMBER) {\n return ctx.consumeNamed('number');\n }\n // datetime\n if (tok.kind === TokenKind.DATETIME) {\n return ctx.consumeNamed('datetime_literal');\n }\n // string\n if (tok.kind === TokenKind.STRING) {\n return parseString(ctx);\n }\n // ellipsis\n if (tok.kind === TokenKind.ELLIPSIS) {\n return ctx.consumeNamed('ellipsis');\n }\n // list [...]\n if (tok.kind === TokenKind.LBRACKET) {\n return parseList(ctx);\n }\n // dictionary {...}\n if (tok.kind === TokenKind.LBRACE) {\n return parseDictionary(ctx);\n }\n return null;\n}\nfunction parseAtId(ctx) {\n const startTok = ctx.peek();\n const node = ctx.startNode('at_id');\n ctx.addAnonymousChild(node, ctx.consume()); // @\n if (ctx.peekKind() === TokenKind.ID) {\n node.appendChild(ctx.consumeNamed('id'));\n }\n else {\n // @ with no identifier \u2192 ERROR\n node.appendChild(makeEmptyError(ctx));\n }\n ctx.finishNode(node, startTok);\n return node;\n}\nexport function parseString(ctx) {\n const tok = ctx.peek();\n const startTok = tok;\n const node = ctx.startNode('string');\n // The lexer gives us the whole string as one token.\n // We need to break it into children: opening quote, string_content/escape_sequence, closing quote.\n const text = tok.text;\n const tokenOffset = ctx.peekOffset();\n ctx.consume(); // consume the full string token\n const baseRow = startTok.start.row;\n const baseCol = startTok.start.column;\n // Opening quote\n node.appendChild(new CSTNode('\"', ctx.source, tokenOffset, tokenOffset + 1, { row: baseRow, column: baseCol }, { row: baseRow, column: baseCol + 1 }, false));\n // Parse content between quotes\n let i = 1; // skip opening \"\n const quoteChar = text[0]; // \" or '\n const hasClosingQuote = text.length > 1 && text[text.length - 1] === quoteChar;\n const contentEnd = hasClosingQuote ? text.length - 1 : text.length;\n let contentStart = i;\n while (i < contentEnd) {\n if (text[i] === '\\\\' &&\n i + 1 < contentEnd &&\n VALID_ESCAPES.has(text[i + 1])) {\n // Emit any accumulated content before the escape\n if (i > contentStart) {\n node.appendChild(new CSTNode('string_content', ctx.source, tokenOffset + contentStart, tokenOffset + i, { row: baseRow, column: baseCol + contentStart }, { row: baseRow, column: baseCol + i }));\n }\n // Emit escape sequence\n const escLen = 2;\n node.appendChild(new CSTNode('escape_sequence', ctx.source, tokenOffset + i, tokenOffset + i + escLen, { row: baseRow, column: baseCol + i }, { row: baseRow, column: baseCol + i + escLen }));\n i += escLen;\n contentStart = i;\n }\n else if (text[i] === '\\\\' &&\n i + 1 < contentEnd &&\n !VALID_ESCAPES.has(text[i + 1])) {\n // Invalid escape sequence \u2014 emit accumulated content, then ERROR\n if (i > contentStart) {\n node.appendChild(new CSTNode('string_content', ctx.source, tokenOffset + contentStart, tokenOffset + i, { row: baseRow, column: baseCol + contentStart }, { row: baseRow, column: baseCol + i }));\n }\n // Find the extent of the invalid escape: \\x followed by remaining word chars\n const escStart = i;\n i += 2; // skip \\ and the invalid char\n while (i < contentEnd && /[a-zA-Z0-9_]/.test(text[i])) {\n i++;\n }\n const errNode = new CSTNode('ERROR', ctx.source, tokenOffset + escStart, tokenOffset + i, { row: baseRow, column: baseCol + escStart }, { row: baseRow, column: baseCol + i }, true, true);\n node.appendChild(errNode);\n contentStart = i;\n }\n else {\n i++;\n }\n }\n // Emit remaining content\n if (i > contentStart) {\n node.appendChild(new CSTNode('string_content', ctx.source, tokenOffset + contentStart, tokenOffset + i, { row: baseRow, column: baseCol + contentStart }, { row: baseRow, column: baseCol + i }));\n }\n // Closing quote\n if (hasClosingQuote) {\n node.appendChild(new CSTNode(quoteChar, ctx.source, tokenOffset + text.length - 1, tokenOffset + text.length, { row: baseRow, column: baseCol + text.length - 1 }, { row: baseRow, column: baseCol + text.length }, false));\n }\n else {\n // Unclosed string \u2192 MISSING closing quote\n // Position at end of string content (where the quote should have been),\n // not at the next token which may be on the next line.\n const missingOffset = tokenOffset + text.length;\n const missingPos = { row: baseRow, column: baseCol + text.length };\n node.appendChild(new CSTNode(quoteChar, ctx.source, missingOffset, missingOffset, missingPos, missingPos, false, false, true));\n }\n ctx.finishNode(node, startTok);\n return node;\n}\nfunction parseList(ctx) {\n const startTok = ctx.peek();\n const node = ctx.startNode('list');\n ctx.addAnonymousChild(node, ctx.consume()); // [\n // Lists can span multiple lines \u2014 skip whitespace tokens inside [...]\n let _listIndentDepth = 0;\n while (ctx.peekKind() !== TokenKind.RBRACKET &&\n ctx.peekKind() !== TokenKind.EOF) {\n if (ctx.peekKind() === TokenKind.NEWLINE) {\n ctx.consume();\n continue;\n }\n if (ctx.peekKind() === TokenKind.INDENT) {\n _listIndentDepth++;\n ctx.consume();\n continue;\n }\n if (ctx.peekKind() === TokenKind.DEDENT) {\n _listIndentDepth--;\n ctx.consume();\n continue;\n }\n const expr = parseExpression(ctx, 0);\n if (expr) {\n node.appendChild(wrapExpression(ctx, expr));\n }\n else {\n break;\n }\n if (ctx.peekKind() === TokenKind.COMMA) {\n ctx.addAnonymousChild(node, ctx.consume());\n }\n else {\n break;\n }\n }\n // Skip whitespace tokens to find the closing ]\n while (ctx.peekKind() === TokenKind.NEWLINE ||\n ctx.peekKind() === TokenKind.INDENT ||\n ctx.peekKind() === TokenKind.DEDENT) {\n ctx.consume();\n }\n if (ctx.peekKind() === TokenKind.RBRACKET) {\n ctx.addAnonymousChild(node, ctx.consume());\n }\n else {\n node.appendChild(makeEmptyError(ctx));\n }\n ctx.finishNode(node, startTok);\n return node;\n}\nfunction parseDictionary(ctx) {\n const startTok = ctx.peek();\n const node = ctx.startNode('dictionary');\n ctx.addAnonymousChild(node, ctx.consume()); // {\n // Dictionaries can span multiple lines\n while (ctx.peekKind() !== TokenKind.RBRACE &&\n ctx.peekKind() !== TokenKind.EOF) {\n if (ctx.peekKind() === TokenKind.NEWLINE ||\n ctx.peekKind() === TokenKind.INDENT ||\n ctx.peekKind() === TokenKind.DEDENT) {\n ctx.consume();\n continue;\n }\n const pair = parseDictionaryPair(ctx);\n if (pair) {\n node.appendChild(pair);\n }\n else {\n break;\n }\n if (ctx.peekKind() === TokenKind.COMMA) {\n ctx.addAnonymousChild(node, ctx.consume());\n }\n else {\n break;\n }\n }\n if (ctx.peekKind() === TokenKind.RBRACE) {\n ctx.addAnonymousChild(node, ctx.consume());\n }\n else {\n node.appendChild(makeEmptyError(ctx));\n }\n ctx.finishNode(node, startTok);\n return node;\n}\nfunction parseDictionaryPair(ctx) {\n const startTok = ctx.peek();\n if (!isKeyStart(ctx))\n return null;\n const node = ctx.startNode('dictionary_pair');\n const key = parseKey(ctx);\n if (key)\n node.appendChild(key, 'key');\n if (ctx.peekKind() === TokenKind.COLON) {\n ctx.addAnonymousChild(node, ctx.consume());\n }\n const value = parseExpression(ctx, 0);\n if (value)\n node.appendChild(wrapExpression(ctx, value), 'value');\n ctx.finishNode(node, startTok);\n return node;\n}\n// --- Infix parsing ---\n// Precedence lookup tables (O(1) instead of 20+ if-statements)\nconst INFIX_PREC_BY_KIND = new Map([\n [TokenKind.LPAREN, 8],\n [TokenKind.DOT, 8],\n [TokenKind.LBRACKET, 8],\n [TokenKind.EQEQ, 4],\n [TokenKind.NEQ, 4],\n [TokenKind.LT, 4],\n [TokenKind.GT, 4],\n [TokenKind.LTE, 4],\n [TokenKind.GTE, 4],\n [TokenKind.PLUS, 5],\n [TokenKind.MINUS, 5],\n [TokenKind.STAR, 6],\n [TokenKind.SLASH, 6],\n]);\nconst INFIX_KEYWORD_PREC = new Map([\n ['if', 0],\n ['or', 1],\n ['and', 2],\n ['is', 4],\n]);\nfunction infixPrecedence(ctx) {\n const tok = ctx.peek();\n if (tok.kind === TokenKind.ID)\n return INFIX_KEYWORD_PREC.get(tok.text) ?? -2;\n return INFIX_PREC_BY_KIND.get(tok.kind) ?? -2;\n}\nfunction parseInfix(ctx, left, prec) {\n const tok = ctx.peek();\n // Call expression: expr(args)\n if (tok.kind === TokenKind.LPAREN && prec === 8) {\n return parseCall(ctx, left);\n }\n // Member expression: expr.id\n if (tok.kind === TokenKind.DOT && prec === 8) {\n return parseMember(ctx, left);\n }\n // Subscript expression: expr[expr]\n if (tok.kind === TokenKind.LBRACKET && prec === 8) {\n return parseSubscript(ctx, left);\n }\n // Ternary: consequence if condition else alternative\n if (tok.kind === TokenKind.ID && tok.text === 'if') {\n return parseTernary(ctx, left);\n }\n // \"is not\" compound operator\n if (tok.kind === TokenKind.ID && tok.text === 'is') {\n return parseIsExpression(ctx, left);\n }\n // Binary / comparison\n return parseBinaryOrComparison(ctx, left, prec);\n}\nfunction parseCall(ctx, func) {\n const startTok = ctx.peek();\n const node = ctx.startNodeAt('call_expression', func);\n node.appendChild(wrapExpression(ctx, func), 'function');\n ctx.addAnonymousChild(node, ctx.consume()); // (\n while (ctx.peekKind() !== TokenKind.RPAREN && !ctx.isAtSyncPoint()) {\n const arg = parseExpression(ctx, 0);\n if (arg) {\n node.appendChild(wrapExpression(ctx, arg), 'argument');\n }\n else {\n break;\n }\n if (ctx.peekKind() === TokenKind.COMMA) {\n ctx.addAnonymousChild(node, ctx.consume());\n // Trailing comma: if `)` follows, insert MISSING id argument\n if (ctx.peekKind() === TokenKind.RPAREN) {\n node.appendChild(makeMissingArgument(ctx), 'argument');\n break;\n }\n }\n else {\n break;\n }\n }\n if (ctx.peekKind() === TokenKind.RPAREN) {\n ctx.addAnonymousChild(node, ctx.consume());\n }\n else {\n node.appendChild(makeEmptyError(ctx));\n }\n ctx.finishNode(node, startTok);\n return node;\n}\nfunction parseMember(ctx, object) {\n const startTok = ctx.peek();\n const node = ctx.startNodeAt('member_expression', object);\n node.appendChild(wrapExpression(ctx, object));\n ctx.addAnonymousChild(node, ctx.consume()); // .\n if (ctx.peekKind() === TokenKind.ID) {\n node.appendChild(ctx.consumeNamed('id'));\n }\n else if (ctx.peekKind() === TokenKind.NUMBER) {\n // Error 19: member access with number like @var.123\n const numNode = ctx.consumeNamed('number');\n const errNode = new CSTNode('ERROR', ctx.source, numNode.startOffset, numNode.endOffset, numNode.startPosition, numNode.endPosition, true, true);\n errNode.appendChild(numNode);\n node.appendChild(errNode);\n }\n else {\n // Trailing dot with nothing after \u2192 ERROR\n node.appendChild(makeEmptyError(ctx));\n }\n ctx.finishNode(node, startTok);\n return node;\n}\nfunction parseSubscript(ctx, object) {\n const startTok = ctx.peek();\n const node = ctx.startNodeAt('subscript_expression', object);\n node.appendChild(wrapExpression(ctx, object));\n ctx.addAnonymousChild(node, ctx.consume()); // [\n const index = parseExpression(ctx, 0);\n if (index) {\n node.appendChild(wrapExpression(ctx, index));\n }\n if (ctx.peekKind() === TokenKind.RBRACKET) {\n ctx.addAnonymousChild(node, ctx.consume());\n }\n else {\n node.appendChild(makeEmptyError(ctx));\n }\n ctx.finishNode(node, startTok);\n return node;\n}\nfunction parseTernary(ctx, consequence) {\n const startTok = ctx.peek();\n const node = ctx.startNodeAt('ternary_expression', consequence);\n node.appendChild(wrapExpression(ctx, consequence), 'consequence');\n ctx.addAnonymousChild(node, ctx.consume()); // if\n const condition = parseExpression(ctx, 1); // above 'or'\n if (condition) {\n node.appendChild(wrapExpression(ctx, condition), 'condition');\n }\n if (ctx.peekKind() === TokenKind.ID && ctx.peek().text === 'else') {\n ctx.addAnonymousChild(node, ctx.consume()); // else\n const alt = parseExpression(ctx, 0); // right-associative: parse at 0\n if (alt) {\n node.appendChild(wrapExpression(ctx, alt), 'alternative');\n }\n }\n else {\n // Incomplete ternary: \"a if condition\" without else \u2192 ERROR\n node.appendChild(makeEmptyError(ctx));\n }\n ctx.finishNode(node, startTok);\n return node;\n}\nfunction parseIsExpression(ctx, left) {\n const startTok = ctx.peek();\n // Check for \"is not\"\n const isNot = ctx.peekAt(1).kind === TokenKind.ID && ctx.peekAt(1).text === 'not';\n const nodeType = 'comparison_expression';\n const node = ctx.startNodeAt(nodeType, left);\n node.appendChild(wrapExpression(ctx, left));\n ctx.addAnonymousChild(node, ctx.consume()); // is\n if (isNot) {\n ctx.addAnonymousChild(node, ctx.consume()); // not\n }\n const right = parseExpression(ctx, 5); // above binary +/-\n if (right) {\n node.appendChild(wrapExpression(ctx, right));\n }\n ctx.finishNode(node, startTok);\n return node;\n}\nfunction parseBinaryOrComparison(ctx, left, prec) {\n const tok = ctx.peek();\n const startTok = tok;\n // Determine if this is a comparison or binary expression\n const isComparison = tok.kind === TokenKind.EQEQ ||\n tok.kind === TokenKind.NEQ ||\n tok.kind === TokenKind.LT ||\n tok.kind === TokenKind.GT ||\n tok.kind === TokenKind.LTE ||\n tok.kind === TokenKind.GTE ||\n tok.kind === TokenKind.EQ;\n const nodeType = isComparison ? 'comparison_expression' : 'binary_expression';\n const node = ctx.startNodeAt(nodeType, left);\n node.appendChild(wrapExpression(ctx, left));\n ctx.addAnonymousChild(node, ctx.consume()); // operator\n const right = parseExpression(ctx, prec + 1); // left-associative\n if (right) {\n node.appendChild(wrapExpression(ctx, right));\n }\n else {\n // Incomplete binary/comparison: `3 +` or `@var ==` with no right operand\n node.appendChild(makeEmptyError(ctx));\n }\n ctx.finishNode(node, startTok);\n return node;\n}\n// --- Helpers ---\n/**\n * Types that are already wrapped or structural \u2014 should NOT get an expression wrapper.\n * Everything else produced by expression parsing gets wrapped.\n */\nconst SKIP_WRAP_TYPES = new Set(['expression', 'ERROR']);\n/**\n * Leaf/literal types that need an intermediate `atom` wrapper before the `expression` wrapper.\n */\nexport const ATOM_TYPES = new Set([\n 'id',\n 'number',\n 'string',\n 'datetime_literal',\n 'at_id',\n 'list',\n 'dictionary',\n 'ellipsis',\n]);\n/**\n * Wrap an expression in an `expression` supertype node if it isn't already one.\n * Tree-sitter wraps most expression children in an (expression ...) wrapper.\n */\nexport function wrapExpression(ctx, inner) {\n if (SKIP_WRAP_TYPES.has(inner.type)) {\n return inner;\n }\n // For atoms, wrap in atom first then expression\n let wrapped = inner;\n if (ATOM_TYPES.has(inner.type)) {\n const atom = new CSTNode('atom', ctx.source, inner.startOffset, inner.endOffset, inner.startPosition, inner.endPosition);\n atom.appendChild(inner);\n wrapped = atom;\n }\n // Now wrap in expression\n const expr = new CSTNode('expression', ctx.source, wrapped.startOffset, wrapped.endOffset, wrapped.startPosition, wrapped.endPosition);\n expr.appendChild(wrapped);\n return expr;\n}\nexport function isKeyStart(ctx) {\n const tok = ctx.peek();\n return isKeyTokenStart(tok.kind);\n}\n/** Can this token kind begin a key? (ID, STRING, or NUMBER for digit-prefixed keys like `3var`) */\nexport function isKeyTokenStart(kind) {\n return (kind === TokenKind.ID ||\n kind === TokenKind.STRING ||\n kind === TokenKind.NUMBER);\n}\n/** Can this token kind appear within a multi-part key? (key-start tokens plus MINUS/DOT for `my-var`, `a.b`) */\nexport function isKeyTokenContinuation(kind) {\n return (isKeyTokenStart(kind) || kind === TokenKind.MINUS || kind === TokenKind.DOT);\n}\nexport function parseKey(ctx) {\n if (!isKeyStart(ctx))\n return null;\n const startTok = ctx.peek();\n const node = ctx.startNode('key');\n // First name \u2014 may be a number (digit-starting key like \"3var\")\n if (ctx.peekKind() === TokenKind.NUMBER) {\n // Digit-starting key: wrap number in ERROR\n const numNode = ctx.consumeNamed('number');\n const errNode = new CSTNode('ERROR', ctx.source, numNode.startOffset, numNode.endOffset, numNode.startPosition, numNode.endPosition, true, true);\n node.appendChild(errNode);\n // Consume the ID part if present\n if (ctx.peekKind() === TokenKind.ID) {\n node.appendChild(ctx.consumeNamed('id'));\n }\n }\n else if (ctx.peekKind() === TokenKind.STRING) {\n node.appendChild(parseString(ctx));\n }\n else {\n node.appendChild(ctx.consumeNamed('id'));\n }\n // Optional second name (two-word keys like \"topic greeting\")\n // The second word must be on the same line with exactly immediate adjacency\n // (the grammar uses token.immediate(' '))\n if (ctx.peekKind() === TokenKind.ID &&\n !ctx.isAtSyncPoint() &&\n ctx.peek().start.row === startTok.start.row) {\n // Check if this could be a keyword that starts a value/statement\n const nextText = ctx.peek().text;\n if (!KEY_STOP_KEYWORDS.has(nextText)) {\n node.appendChild(ctx.consumeNamed('id'));\n }\n }\n ctx.finishNode(node, startTok);\n return node;\n}\n//# sourceMappingURL=expressions.js.map", "/*\n * Copyright (c) 2026, Salesforce, Inc.\n * All rights reserved.\n * SPDX-License-Identifier: Apache-2.0\n * For full license text, see the LICENSE file in the repo root or https://www.apache.org/licenses/LICENSE-2.0\n */\n/**\n * Statement-parsing functions extracted from Parser class.\n *\n * Each function takes a ParserContext as its first parameter, following\n * the same free-function pattern as recovery.ts and expressions.ts.\n *\n * Functions that call parseProcedure (which in turn calls parseStatement,\n * which may delegate to parseTemplate) accept an optional parseTemplate\n * callback to avoid circular dependency with parser.ts.\n */\nimport { isTokenKind, TokenKind } from './token.js';\nimport { CSTNode } from './cst-node.js';\nimport { makeErrorNode, tokenToAutoLeaf } from './errors.js';\nimport { makeEmptyError, addMissingTarget, makeMissing, synchronize, synchronizeRow, synchronizeRowUntilColon, consumeCommentsAndSkipNewlines, skipNewlines, isAtEnd, isTrailingCommentOnly, parseOrphanBlock, } from './recovery.js';\nimport { parseExpression, wrapExpression, parseString } from './expressions.js';\n// ---------------------------------------------------------------------------\n// Statement detection\n// ---------------------------------------------------------------------------\nexport function isStatementStart(ctx) {\n const tok = ctx.peek();\n if (tok.kind !== TokenKind.ID)\n return false;\n switch (tok.text) {\n case 'if':\n case 'run':\n case 'set':\n case 'transition':\n return true;\n case 'with':\n // \"with\" is a statement only if not followed by colon (which would make it a key)\n return ctx.peekAt(1).kind !== TokenKind.COLON;\n case 'available':\n return (ctx.peekAt(1).kind === TokenKind.ID && ctx.peekAt(1).text === 'when');\n default:\n return false;\n }\n}\n// ---------------------------------------------------------------------------\n// Procedure & statement dispatch\n// ---------------------------------------------------------------------------\nexport function parseProcedure(ctx, parseTemplate) {\n const startTok = ctx.peek();\n const node = ctx.startNode('procedure');\n while (!isAtEnd(ctx) && ctx.peekKind() !== TokenKind.DEDENT) {\n skipNewlines(ctx);\n if (isAtEnd(ctx) || ctx.peekKind() === TokenKind.DEDENT)\n break;\n // Don't consume trailing comments that belong to the parent scope\n // (tree-sitter parity: extras at block boundaries attach to the parent).\n if (ctx.peekKind() === TokenKind.COMMENT && isTrailingCommentOnly(ctx)) {\n break;\n }\n const stmt = parseStatement(ctx, parseTemplate);\n if (stmt) {\n node.appendChild(stmt);\n }\n else {\n const err = synchronize(ctx);\n if (err) {\n node.appendChild(err);\n }\n else if (!isAtEnd(ctx) && ctx.peekKind() !== TokenKind.DEDENT) {\n ctx.consume();\n }\n }\n }\n // If the procedure is empty, add an ERROR node (Error 07, 34)\n if (node.namedChildren.length === 0) {\n node.appendChild(makeEmptyError(ctx));\n }\n ctx.finishNode(node, startTok);\n return node;\n}\nexport function parseStatement(ctx, parseTemplate) {\n const tok = ctx.peek();\n if (tok.kind === TokenKind.ID) {\n switch (tok.text) {\n case 'if':\n return parseIfStatement(ctx, parseTemplate);\n case 'run':\n return parseRunStatement(ctx, parseTemplate);\n case 'set':\n return parseSetStatement(ctx);\n case 'transition':\n return parseTransitionStatement(ctx);\n case 'with':\n return parseWithStatement(ctx);\n case 'available': {\n if (ctx.peekAt(1).kind === TokenKind.ID &&\n ctx.peekAt(1).text === 'when') {\n return parseAvailableWhenStatement(ctx);\n }\n break;\n }\n case 'else':\n case 'elif':\n case 'for':\n // Orphan else/elif (without if) or unsupported for \u2192 wrap in ERROR\n return parseOrphanBlock(ctx, c => parseProcedure(c, parseTemplate));\n }\n }\n if (tok.kind === TokenKind.PIPE && parseTemplate) {\n return parseTemplate(ctx);\n }\n if (tok.kind === TokenKind.COMMENT) {\n const comment = ctx.consumeNamed('comment');\n if (ctx.peekKind() === TokenKind.NEWLINE)\n ctx.consume();\n return comment;\n }\n // Fallback: try parsing as a bare expression (e.g., `...` inside a procedure)\n // This keeps expressions as proper expression nodes instead of ERROR-wrapped tokens.\n const expr = parseExpression(ctx, 0);\n if (expr) {\n const wrapped = wrapExpression(ctx, expr);\n if (ctx.peekKind() === TokenKind.NEWLINE)\n ctx.consume();\n return wrapped;\n }\n return null;\n}\n// ---------------------------------------------------------------------------\n// Shared colon \u2192 procedure body\n// ---------------------------------------------------------------------------\n/**\n * Shared colon \u2192 procedure body sequence for if/elif/else.\n * Consumes colon (with recovery), inline comment, extra inline tokens,\n * then INDENT \u2192 procedure \u2192 DEDENT, and trailing NEWLINE.\n *\n * @param errorOnMissingBody - if true, insert ERROR when colon has no\n * indented body (used by `if`; elif/else silently accept missing body).\n */\nfunction parseColonAndProcedureBody(ctx, node, row, errorOnMissingBody, parseTemplate) {\n // Colon (or recovery)\n if (ctx.peekKind() === TokenKind.COLON) {\n ctx.addAnonymousChild(node, ctx.consume());\n }\n else if (errorOnMissingBody) {\n node.appendChild(makeEmptyError(ctx));\n }\n // Inline comment after colon\n if (ctx.peekKind() === TokenKind.COMMENT) {\n node.appendChild(ctx.consumeNamed('comment'));\n }\n // Absorb extra inline tokens after colon on the same row\n const inlineErr = synchronizeRow(ctx, row);\n if (inlineErr)\n node.appendChild(inlineErr);\n // Consequence block\n if (ctx.peekKind() === TokenKind.INDENT) {\n ctx.consume();\n const proc = parseProcedure(ctx, parseTemplate);\n if (proc)\n node.appendChild(proc, 'consequence');\n consumeCommentsAndSkipNewlines(ctx, node);\n if (ctx.peekKind() === TokenKind.DEDENT)\n ctx.consume();\n }\n else if (errorOnMissingBody &&\n (ctx.peekKind() === TokenKind.NEWLINE || ctx.isAtSyncPoint())) {\n node.appendChild(makeEmptyError(ctx));\n }\n if (ctx.peekKind() === TokenKind.NEWLINE)\n ctx.consume();\n}\n// ---------------------------------------------------------------------------\n// Individual statement parsers\n// ---------------------------------------------------------------------------\nexport function parseIfStatement(ctx, parseTemplate) {\n const startTok = ctx.peek();\n const node = ctx.startNode('if_statement');\n ctx.addAnonymousChild(node, ctx.consume()); // if\n // Condition\n let condition = parseExpression(ctx, 0);\n // Handle single `=` typo (should be `==`): wrap `=` in ERROR,\n // build comparison_expression, then continue parsing normally\n if (condition && ctx.peekKind() === TokenKind.EQ) {\n const eqTok = ctx.consume(); // =\n const right = parseExpression(ctx, 5); // parse right side above comparison\n if (right) {\n // Build: (comparison_expression (expr left) (ERROR =) (expr right))\n const cmp = ctx.startNodeAt('comparison_expression', condition);\n cmp.appendChild(wrapExpression(ctx, condition));\n // Wrap `=` in ERROR\n const eqChild = new CSTNode('=', ctx.source, eqTok.startOffset, eqTok.startOffset + 1, eqTok.start, eqTok.end, false);\n const eqErr = makeErrorNode(ctx.source, [eqChild], eqTok.startOffset, eqTok.startOffset + 1, eqTok.start, eqTok.end);\n cmp.appendChild(eqErr);\n cmp.appendChild(wrapExpression(ctx, right));\n cmp.finalize();\n condition = cmp;\n }\n }\n if (condition)\n node.appendChild(wrapExpression(ctx, condition), 'condition');\n // Absorb extra tokens between condition and colon on the same row.\n if (condition &&\n ctx.peekKind() !== TokenKind.COLON &&\n !ctx.isAtSyncPoint() &&\n ctx.peekKind() !== TokenKind.INDENT) {\n const condRow = startTok.start.row;\n const err = synchronizeRowUntilColon(ctx, condRow);\n if (err)\n node.appendChild(err);\n }\n parseColonAndProcedureBody(ctx, node, startTok.start.row, true, parseTemplate);\n // elif clauses (including misspelled 'elseif')\n while (ctx.peekKind() === TokenKind.ID &&\n (ctx.peek().text === 'elif' || ctx.peek().text === 'elseif')) {\n const elif = parseElifClause(ctx, parseTemplate);\n if (elif)\n node.appendChild(elif, 'alternative');\n }\n // else clause\n if (ctx.peekKind() === TokenKind.ID && ctx.peek().text === 'else') {\n const elseClause = parseElseClause(ctx, parseTemplate);\n if (elseClause)\n node.appendChild(elseClause, 'alternative');\n }\n ctx.finishNode(node, startTok);\n return node;\n}\nfunction parseElifClause(ctx, parseTemplate) {\n const startTok = ctx.peek();\n const node = ctx.startNode('elif_clause');\n const kw = ctx.consume(); // elif or elseif\n if (kw.text === 'elseif') {\n // Wrap misspelled keyword in ERROR\n const kwEnd = kw.startOffset + kw.text.length;\n const leaf = tokenToAutoLeaf(kw, ctx.source, kw.startOffset);\n const errNode = makeErrorNode(ctx.source, [leaf], kw.startOffset, kwEnd, kw.start, kw.end);\n node.appendChild(errNode);\n }\n else {\n ctx.addAnonymousChild(node, kw);\n }\n const condition = parseExpression(ctx, 0);\n if (condition)\n node.appendChild(wrapExpression(ctx, condition), 'condition');\n // Absorb extra tokens between condition and colon (same as if)\n if (condition &&\n ctx.peekKind() !== TokenKind.COLON &&\n !ctx.isAtSyncPoint() &&\n ctx.peekKind() !== TokenKind.INDENT) {\n const condRow = startTok.start.row;\n const err = synchronizeRowUntilColon(ctx, condRow);\n if (err)\n node.appendChild(err);\n }\n parseColonAndProcedureBody(ctx, node, startTok.start.row, false, parseTemplate);\n ctx.finishNode(node, startTok);\n return node;\n}\nfunction parseElseClause(ctx, parseTemplate) {\n const startTok = ctx.peek();\n const node = ctx.startNode('else_clause');\n ctx.addAnonymousChild(node, ctx.consume()); // else\n parseColonAndProcedureBody(ctx, node, startTok.start.row, false, parseTemplate);\n ctx.finishNode(node, startTok);\n return node;\n}\nexport function parseRunStatement(ctx, parseTemplate) {\n const startTok = ctx.peek();\n const node = ctx.startNode('run_statement');\n ctx.addAnonymousChild(node, ctx.consume()); // run\n // Target expression\n if (!ctx.isAtSyncPoint()) {\n const target = parseExpression(ctx, 0);\n if (target) {\n node.appendChild(wrapExpression(ctx, target), 'target');\n }\n else {\n addMissingTarget(ctx, node);\n }\n }\n else {\n // `run` with no target at all \u2192 insert ERROR placeholder\n addMissingTarget(ctx, node);\n }\n // Optional indented block (procedure)\n if (ctx.peekKind() === TokenKind.INDENT) {\n ctx.consume();\n // Comments before procedure body attach to run_statement\n consumeCommentsAndSkipNewlines(ctx, node);\n const proc = parseProcedure(ctx, parseTemplate);\n if (proc) {\n // If procedure contains an ERROR with `with` keyword (invalid with clause),\n // attach children directly to run_statement so the dialect's\n // error recovery can find them (it looks at run_statement.children).\n const hasWithError = proc.namedChildren.some(c => c.isError && c.children.some(cc => cc.type === 'with'));\n if (hasWithError) {\n for (const child of proc.namedChildren) {\n node.appendChild(child);\n }\n }\n else {\n node.appendChild(proc, 'block_value');\n }\n }\n consumeCommentsAndSkipNewlines(ctx, node);\n if (ctx.peekKind() === TokenKind.DEDENT)\n ctx.consume();\n }\n if (ctx.peekKind() === TokenKind.NEWLINE)\n ctx.consume();\n ctx.finishNode(node, startTok);\n return node;\n}\nexport function parseSetStatement(ctx) {\n const startTok = ctx.peek();\n const node = ctx.startNode('set_statement');\n ctx.addAnonymousChild(node, ctx.consume()); // set\n // Parse target at precedence 5 (above comparison/=) so = and == aren't consumed\n const target = parseExpression(ctx, 5);\n if (ctx.peekKind() === TokenKind.EQEQ) {\n // set @var == \"value\" \u2192 ERROR: == instead of =\n // Build comparison_expression(target, ==, rhs) and wrap in ERROR\n // Don't add target to node \u2014 we're returning an ERROR node instead\n const eqTok = ctx.consume(); // ==\n const rhs = parseExpression(ctx, 0);\n if (target && rhs) {\n const cmp = ctx.startNodeAt('comparison_expression', wrapExpression(ctx, target));\n cmp.appendChild(wrapExpression(ctx, target));\n cmp.appendChild(new CSTNode(eqTok.text, ctx.source, eqTok.startOffset, eqTok.startOffset + 2, eqTok.start, eqTok.end, false));\n cmp.appendChild(wrapExpression(ctx, rhs));\n cmp.finalize();\n const wrappedCmp = wrapExpression(ctx, cmp);\n if (ctx.peekKind() === TokenKind.NEWLINE)\n ctx.consume();\n // Return ERROR instead of set_statement\n return makeErrorNode(ctx.source, [wrappedCmp], wrappedCmp.startOffset, wrappedCmp.endOffset, wrappedCmp.startPosition, wrappedCmp.endPosition);\n }\n }\n // Add target to node only after ruling out the == error case\n if (target)\n node.appendChild(wrapExpression(ctx, target), 'target');\n if (ctx.peekKind() === TokenKind.EQ) {\n ctx.addAnonymousChild(node, ctx.consume()); // =\n const value = parseExpression(ctx, 0);\n if (value)\n node.appendChild(wrapExpression(ctx, value), 'value');\n }\n if (ctx.peekKind() === TokenKind.NEWLINE)\n ctx.consume();\n ctx.finishNode(node, startTok);\n return node;\n}\nexport function parseTransitionStatement(ctx) {\n const startTok = ctx.peek();\n const node = ctx.startNode('transition_statement');\n ctx.addAnonymousChild(node, ctx.consume()); // transition\n // Optional with/to statement list\n const withToList = tryParseWithToStatementList(ctx);\n if (withToList) {\n node.appendChild(withToList, 'with_to_statement_list');\n }\n else if (!ctx.isAtSyncPoint() &&\n ctx.peekKind() !== TokenKind.NEWLINE &&\n ctx.peekKind() !== TokenKind.EOF) {\n // No with/to list found but there are tokens remaining on the same line \u2014\n // likely a missing 'to' keyword (e.g. \"transition @topic.greeting\").\n // Insert a synthetic with_to_statement_list containing a to_statement\n // with a MISSING 'to' node.\n const listNode = ctx.startNode('with_to_statement_list');\n const toNode = ctx.startNode('to_statement');\n toNode.appendChild(makeMissing(ctx, 'to'));\n const target = parseExpression(ctx, 0);\n if (target)\n toNode.appendChild(wrapExpression(ctx, target), 'target');\n toNode.finalize();\n listNode.appendChild(toNode);\n listNode.finalize();\n node.appendChild(listNode, 'with_to_statement_list');\n }\n if (ctx.peekKind() === TokenKind.NEWLINE)\n ctx.consume();\n ctx.finishNode(node, startTok);\n return node;\n}\nexport function parseWithStatement(ctx) {\n const startTok = ctx.peek();\n // Check if `with` is followed by a valid param (ID/STRING).\n // If not (e.g., `with ...`), create ERROR containing `with` keyword.\n // The remaining tokens (e.g. `...`) stay unconsumed for the caller.\n if (ctx.peekAt(1).kind !== TokenKind.ID &&\n ctx.peekAt(1).kind !== TokenKind.STRING) {\n const withTok = ctx.consume();\n const kwOffset = ctx.currentOffset();\n const withChild = new CSTNode('with', ctx.source, kwOffset, kwOffset + 4, withTok.start, withTok.end, false);\n return makeErrorNode(ctx.source, [withChild], kwOffset, kwOffset + 4, withTok.start, withTok.end);\n }\n const node = ctx.startNode('with_statement');\n ctx.addAnonymousChild(node, ctx.consume()); // with\n // Parse param=value pairs\n parseWithParams(ctx, node);\n // Inline comment on the with line (e.g. `with city=x # comment`)\n if (ctx.peekKind() === TokenKind.COMMENT) {\n node.appendChild(ctx.consumeNamed('comment'));\n }\n if (ctx.peekKind() === TokenKind.NEWLINE)\n ctx.consume();\n ctx.finishNode(node, startTok);\n return node;\n}\nfunction parseWithParams(ctx, node) {\n while (!ctx.isAtSyncPoint()) {\n // param\n if (ctx.peekKind() === TokenKind.ID ||\n ctx.peekKind() === TokenKind.STRING) {\n if (ctx.peekKind() === TokenKind.STRING) {\n node.appendChild(parseString(ctx), 'param');\n }\n else {\n node.appendChild(ctx.consumeNamed('id'), 'param');\n }\n }\n else {\n // Not a valid param \u2014 wrap remaining tokens in ERROR inside with_statement\n const err = synchronize(ctx);\n if (err)\n node.appendChild(err);\n return;\n }\n // =\n if (ctx.peekKind() === TokenKind.EQ) {\n ctx.addAnonymousChild(node, ctx.consume());\n }\n else {\n // Missing = \u2192 insert MISSING\n node.appendChild(makeMissing(ctx, '='));\n }\n // value\n const value = parseExpression(ctx, 0);\n if (value)\n node.appendChild(wrapExpression(ctx, value), 'value');\n // comma\n if (ctx.peekKind() === TokenKind.COMMA) {\n ctx.addAnonymousChild(node, ctx.consume());\n }\n else {\n break;\n }\n }\n}\nexport function parseAvailableWhenStatement(ctx) {\n const startTok = ctx.peek();\n const node = ctx.startNode('available_when_statement');\n ctx.addAnonymousChild(node, ctx.consume()); // available\n ctx.addAnonymousChild(node, ctx.consume()); // when\n const condition = parseExpression(ctx, 0);\n if (condition)\n node.appendChild(wrapExpression(ctx, condition), 'condition');\n if (ctx.peekKind() === TokenKind.NEWLINE)\n ctx.consume();\n ctx.finishNode(node, startTok);\n return node;\n}\n// ---------------------------------------------------------------------------\n// With/To statement list\n// ---------------------------------------------------------------------------\nexport function tryParseWithToStatementList(ctx) {\n const tok = ctx.peek();\n if (!isTokenKind(tok, TokenKind.ID))\n return null;\n if (!['with', 'to'].includes(tok.text))\n return null;\n const startTok = tok;\n const node = ctx.startNode('with_to_statement_list');\n while (!ctx.isAtSyncPoint()) {\n if (ctx.peekKind() === TokenKind.ID && ctx.peek().text === 'with') {\n node.appendChild(parseInlineWithStatement(ctx));\n }\n else if (ctx.peekKind() === TokenKind.ID && ctx.peek().text === 'to') {\n node.appendChild(parseToStatement(ctx));\n }\n else {\n break;\n }\n if (ctx.peekKind() === TokenKind.COMMA) {\n ctx.addAnonymousChild(node, ctx.consume());\n }\n else {\n break;\n }\n }\n if (node.children.length === 0)\n return null;\n ctx.finishNode(node, startTok);\n return node;\n}\nexport function parseInlineWithStatement(ctx) {\n const startTok = ctx.peek();\n const node = ctx.startNode('with_statement');\n ctx.addAnonymousChild(node, ctx.consume()); // with\n parseWithParams(ctx, node);\n ctx.finishNode(node, startTok);\n return node;\n}\nexport function parseToStatement(ctx) {\n const startTok = ctx.peek();\n const node = ctx.startNode('to_statement');\n ctx.addAnonymousChild(node, ctx.consume()); // to\n const target = parseExpression(ctx, 0);\n if (target) {\n node.appendChild(wrapExpression(ctx, target), 'target');\n }\n else {\n // Missing target \u2192 ERROR\n node.appendChild(makeEmptyError(ctx));\n }\n ctx.finishNode(node, startTok);\n return node;\n}\n//# sourceMappingURL=parse-statements.js.map", "/*\n * Copyright (c) 2026, Salesforce, Inc.\n * All rights reserved.\n * SPDX-License-Identifier: Apache-2.0\n * For full license text, see the LICENSE file in the repo root or https://www.apache.org/licenses/LICENSE-2.0\n */\n/**\n * Template-parsing functions extracted from Parser class.\n *\n * Each function takes a ParserContext as its first parameter, following\n * the same free-function pattern as parse-statements.ts and expressions.ts.\n *\n * Template indentation state (templateOuterIndent) is computed locally in\n * parseTemplate and passed as an explicit parameter to templateContinues.\n */\nimport { TokenKind } from './token.js';\nimport { CSTNode } from './cst-node.js';\nimport { makeEmptyError, makeMissing, synchronize, isAtEnd, } from './recovery.js';\nimport { parseExpression, wrapExpression } from './expressions.js';\n// ---------------------------------------------------------------------------\n// Exported template parsers\n// ---------------------------------------------------------------------------\n/**\n * Parse a template starting with `|`.\n * Consumes tokens from the lexer stream, treating everything as template content\n * except `{!...}` breaks which are parsed as template expressions.\n */\nexport function parseTemplate(ctx) {\n const startTok = ctx.peek();\n const node = ctx.startNode('template');\n // Compute the indent level of the line containing `|`.\n // Tree-sitter uses *array_back(&scanner->indents) \u2014 the top of the indent\n // stack, which equals the line indent. We scan backward in the source to\n // measure the leading whitespace on this line.\n const pipeOffset = ctx.peekOffset();\n let lineStart = pipeOffset;\n while (lineStart > 0 &&\n ctx.source.charCodeAt(lineStart - 1) !== 10 /* \\n */) {\n lineStart--;\n }\n let templateOuterIndent = 0;\n for (let i = lineStart; i < pipeOffset; i++) {\n const ch = ctx.source.charCodeAt(i);\n if (ch === 32 /* space */)\n templateOuterIndent += 1;\n else if (ch === 9 /* tab */)\n templateOuterIndent += 3;\n else\n break;\n }\n // Consume the | token and track position right after it\n const pipeToken = ctx.consume();\n ctx.addAnonymousChild(node, pipeToken);\n // If there are tokens on the same line after |, pass afterPipeOffset\n // so whitespace between | and {! is captured as template_content.\n // If the line is empty after |, don't pass it (avoids phantom content).\n const hasContentOnSameLine = !isAtEnd(ctx) &&\n ctx.peekKind() !== TokenKind.NEWLINE &&\n ctx.peekKind() !== TokenKind.INDENT &&\n ctx.peekKind() !== TokenKind.DEDENT;\n if (hasContentOnSameLine) {\n const afterPipeOffset = pipeToken.startOffset + 1;\n gatherTemplateContentLine(ctx, node, afterPipeOffset);\n }\n // Consume NEWLINE if present\n if (ctx.peekKind() === TokenKind.NEWLINE) {\n ctx.consume();\n }\n // If there's an INDENT, the template continues on indented lines.\n // Templates consume ALL indented content until we fully return to the\n // base indent. We track indent depth: each INDENT increments, each\n // DEDENT decrements. When depth reaches 0, a final DEDENT exits.\n // Mid-template DEDENTs (under-indented continuation lines) are consumed\n // as content.\n if (ctx.peekKind() === TokenKind.INDENT) {\n ctx.consume(); // outer INDENT\n let indentDepth = 1;\n while (!isAtEnd(ctx)) {\n const tok = ctx.peek();\n if (tok.kind === TokenKind.DEDENT) {\n indentDepth--;\n ctx.consume();\n if (indentDepth <= 0) {\n // Check if template continues with under-indented content.\n // If the next meaningful token is content (not EOF/DEDENT),\n // the template has under-indented continuation lines.\n if (templateContinues(ctx, templateOuterIndent)) {\n // Re-enter: consume content at the new (lower) indent\n indentDepth = 0; // will re-increment on next INDENT\n continue;\n }\n break;\n }\n }\n else if (tok.kind === TokenKind.INDENT) {\n indentDepth++;\n ctx.consume();\n }\n else if (tok.kind === TokenKind.NEWLINE) {\n ctx.consume();\n }\n else {\n // When at the template's base indent depth, check if the next\n // token should continue the template (e.g. comments at the base\n // level should not be absorbed as template content).\n if (indentDepth <= 0 && !templateContinues(ctx, templateOuterIndent)) {\n break;\n }\n // For continuation lines, start the content from the end of the\n // last template child so that newlines + indentation between a\n // template_expression and the next template_content are preserved\n // in the source text. (mergeTemplateContent handles this for\n // consecutive template_content nodes, but not across expressions.)\n const lastChild = node.children.length > 0\n ? node.children[node.children.length - 1]\n : null;\n const gapOffset = lastChild && lastChild.endOffset < ctx.peekOffset()\n ? lastChild.endOffset\n : undefined;\n const gapPos = gapOffset !== undefined ? lastChild.endPosition : undefined;\n gatherTemplateContentLine(ctx, node, gapOffset, gapPos);\n }\n }\n }\n // Merge consecutive template_content children into single nodes.\n // Tree-sitter produces one template_content per contiguous text span;\n // our line-by-line parsing creates one per line.\n mergeTemplateContent(ctx, node);\n ctx.finishNode(node, startTok);\n return node;\n}\n/**\n * Parse a template in colinear position (after a colon on the same line).\n * Currently identical to parseTemplate; kept as a separate entry point\n * for semantic clarity and potential future divergence.\n */\nexport function parseTemplateAsColinear(ctx) {\n return parseTemplate(ctx);\n}\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n/**\n * Check if the template continues with under-indented content.\n * After a DEDENT brings us to depth 0, if the next meaningful token\n * is content (not EOF, not DEDENT, not a mapping key pattern), the\n * template has continuation lines.\n */\nfunction templateContinues(ctx, templateOuterIndent) {\n let i = 0;\n while (ctx.peekAt(i).kind === TokenKind.NEWLINE)\n i++;\n const tok = ctx.peekAt(i);\n // If we see content (ID, etc.) that's NOT a mapping key pattern, continue\n if (tok.kind === TokenKind.EOF || tok.kind === TokenKind.DEDENT)\n return false;\n // Content deeper than the template's base indent is always template content,\n // regardless of keywords. Matches tree-sitter scanner behavior where\n // indent_length > out_of_template_indent_length keeps content in the template.\n if (tok.start.column > templateOuterIndent)\n return true;\n // Another pipe starts a new template \u2014 don't absorb it\n if (tok.kind === TokenKind.PIPE)\n return false;\n // If it looks like a mapping key (ID followed by COLON), template is done\n if (tok.kind === TokenKind.ID || tok.kind === TokenKind.STRING) {\n const after = ctx.peekAt(i + 1);\n if (after.kind === TokenKind.COLON)\n return false;\n // Two-word key check\n if (after.kind === TokenKind.ID) {\n const afterAfter = ctx.peekAt(i + 2);\n if (afterAfter.kind === TokenKind.COLON)\n return false;\n }\n }\n // Statement keywords terminate template continuation \u2014 they're\n // sibling statements, not template content\n if (tok.kind === TokenKind.ID) {\n switch (tok.text) {\n case 'if':\n case 'elif':\n case 'else':\n case 'run':\n case 'set':\n case 'transition':\n return false;\n case 'with':\n // \"with\" not followed by colon is a statement\n if (ctx.peekAt(i + 1).kind !== TokenKind.COLON)\n return false;\n break;\n case 'available':\n if (ctx.peekAt(i + 1).kind === TokenKind.ID &&\n ctx.peekAt(i + 1).text === 'when')\n return false;\n break;\n }\n }\n // If it looks like a dash (sequence), template is done\n if (tok.kind === TokenKind.DASH_SPACE)\n return false;\n // Comments at the template's base indent level are not template content\n if (tok.kind === TokenKind.COMMENT)\n return false;\n // Otherwise, assume it's template continuation\n return true;\n}\n/** Merge consecutive template_content children into single nodes. */\nfunction mergeTemplateContent(ctx, template) {\n const merged = [];\n let i = 0;\n while (i < template.children.length) {\n const child = template.children[i];\n if (child.type === 'template_content') {\n // Find the run of consecutive template_content nodes\n let end = i + 1;\n while (end < template.children.length &&\n template.children[end].type === 'template_content') {\n end++;\n }\n if (end > i + 1) {\n // Merge into one node\n const first = template.children[i];\n const last = template.children[end - 1];\n const mergedNode = new CSTNode('template_content', ctx.source, first.startOffset, last.endOffset, first.startPosition, last.endPosition);\n mergedNode.parent = template;\n merged.push(mergedNode);\n i = end;\n }\n else {\n merged.push(child);\n i++;\n }\n }\n else {\n merged.push(child);\n i++;\n }\n }\n template.children = merged;\n}\n/**\n * Gather tokens on the current line as template content.\n * Recognizes {! ... } as template expression breaks.\n * Everything else (including inter-token whitespace) becomes template_content.\n * Uses source-level offsets so whitespace between tokens is preserved.\n */\nfunction gatherTemplateContentLine(ctx, parent, initialOffset, initialPos) {\n // Track the source range of content before/after template expressions.\n // If initialOffset is provided, use it (captures whitespace after |).\n // Otherwise start from the current token position.\n let contentStartOffset = initialOffset ?? ctx.peekOffset();\n let contentStartPos = initialPos ?? ctx.peek().start;\n let lastConsumedEndOffset = contentStartOffset;\n let lastConsumedEndPos = contentStartPos;\n while (!isAtEnd(ctx)) {\n const tok = ctx.peek();\n if (tok.kind === TokenKind.NEWLINE ||\n tok.kind === TokenKind.DEDENT ||\n tok.kind === TokenKind.INDENT ||\n tok.kind === TokenKind.EOF) {\n break;\n }\n // Template expression start\n if (tok.kind === TokenKind.TEMPLATE_EXPR_START) {\n // Flush accumulated content up to the {!\n const exprOffset = ctx.peekOffset();\n if (exprOffset > contentStartOffset) {\n parent.appendChild(new CSTNode('template_content', ctx.source, contentStartOffset, exprOffset, contentStartPos, tok.start));\n }\n // Parse template expression\n const exprNode = parseTemplateExpression(ctx);\n parent.appendChild(exprNode);\n // Content after } continues from the end of the expression node\n // (not from the next token \u2014 that would skip whitespace between } and next content)\n contentStartOffset = exprNode.endOffset;\n contentStartPos = exprNode.endPosition;\n lastConsumedEndOffset = exprNode.endOffset;\n lastConsumedEndPos = exprNode.endPosition;\n continue;\n }\n // Track end of this token for accurate content span\n const tokOffset = ctx.peekOffset();\n lastConsumedEndOffset = tokOffset + tok.text.length;\n lastConsumedEndPos = tok.end;\n ctx.consume();\n }\n // Flush remaining content \u2014 use end of last consumed token (not next token offset,\n // which would include blank lines between this content and the next line)\n if (lastConsumedEndOffset > contentStartOffset) {\n parent.appendChild(new CSTNode('template_content', ctx.source, contentStartOffset, lastConsumedEndOffset, contentStartPos, lastConsumedEndPos));\n }\n}\nfunction parseTemplateExpression(ctx) {\n const startTok = ctx.peek();\n const node = ctx.startNode('template_expression');\n ctx.addAnonymousChild(node, ctx.consume()); // {!\n const expr = parseExpression(ctx, 0);\n if (expr) {\n node.appendChild(wrapExpression(ctx, expr), 'expression');\n }\n else {\n // Empty template expression {!} \u2192 ERROR for missing expression\n node.appendChild(makeEmptyError(ctx));\n }\n // Consume any extra tokens before } (e.g., unclosed {!@var.name world)\n if (ctx.peekKind() !== TokenKind.RBRACE && !ctx.isAtSyncPoint()) {\n const err = synchronize(ctx);\n if (err)\n node.appendChild(err);\n }\n if (ctx.peekKind() === TokenKind.RBRACE) {\n ctx.addAnonymousChild(node, ctx.consume()); // }\n }\n else {\n // Unclosed template expression \u2192 MISSING }\n node.appendChild(makeMissing(ctx, '}'));\n }\n ctx.finishNode(node, startTok);\n return node;\n}\n//# sourceMappingURL=parse-templates.js.map", "/*\n * Copyright (c) 2026, Salesforce, Inc.\n * All rights reserved.\n * SPDX-License-Identifier: Apache-2.0\n * For full license text, see the LICENSE file in the repo root or https://www.apache.org/licenses/LICENSE-2.0\n */\n/**\n * Mapping, block-value, and colinear parsing functions extracted from Parser class.\n *\n * Each function takes a ParserContext as its first parameter, following\n * the same free-function pattern as parse-statements.ts and expressions.ts.\n *\n * To avoid circular dependencies with parse-sequence.ts, parseBlockValue\n * receives parseSequence as a callback parameter.\n */\nimport { isTokenKind, TokenKind } from './token.js';\nimport { CSTNode } from './cst-node.js';\nimport { makeErrorNode, tokenToAutoLeaf } from './errors.js';\nimport { makeEmptyError, makeMissing, synchronize, synchronizeRow, recoverToBlockEnd, parseOrphanBlock, skipNewlines, consumeCommentsAndSkipNewlines, isAtEnd, isTrailingCommentOnly, } from './recovery.js';\nimport { parseExpression, wrapExpression, isKeyStart, isKeyTokenStart, isKeyTokenContinuation, parseKey, ATOM_TYPES, } from './expressions.js';\nimport { isStatementStart, parseProcedure, parseSetStatement, parseTransitionStatement, parseWithStatement, parseAvailableWhenStatement, tryParseWithToStatementList, parseIfStatement, parseRunStatement, } from './parse-statements.js';\nimport { parseTemplate, parseTemplateAsColinear } from './parse-templates.js';\nimport invariant from 'tiny-invariant';\n/**\n * Maximum tokens to scan ahead when distinguishing a mapping key from an\n * expression. Keys are typically 1-3 words; 10 handles any realistic case\n * with margin. The loop terminates early on COLON, NEWLINE, or non-key tokens,\n * so this limit is a safety cap, not a performance concern.\n */\nconst MAX_KEY_LOOKAHEAD = 10;\n// ---------------------------------------------------------------------------\n// Exported mapping parsers\n// ---------------------------------------------------------------------------\n/**\n * Parse a mapping-or-expression at the top level.\n * If the current position starts a mapping, delegates to parseMapping;\n * otherwise parses an expression (possibly an assignment).\n */\nexport function parseMappingOrExpression(ctx, parseSequence) {\n // Look ahead: if we see ID/STRING followed by COLON, it's a mapping\n if (isMappingStart(ctx)) {\n return parseMapping(ctx, parseSequence);\n }\n // Otherwise, try expression (or assignment_expression)\n const expr = parseExpression(ctx, 0);\n if (!expr)\n return null;\n // Check for assignment: expr = expr\n if (isTokenKind(ctx.peek(), TokenKind.EQ)) {\n const node = ctx.startNodeAt('assignment_expression', expr);\n node.appendChild(wrapExpression(ctx, expr), 'left');\n ctx.addAnonymousChild(node, ctx.consumeKind(TokenKind.EQ));\n const right = parseExpression(ctx, 0);\n if (right)\n node.appendChild(wrapExpression(ctx, right), 'right');\n return node;\n }\n return wrapExpression(ctx, expr);\n}\n/**\n * Lookahead to determine if the current position starts a mapping (key-value\n * pairs) rather than an expression.\n *\n * Keys are at most a few tokens (1-3 words, possibly with hyphens/dots), so\n * we only need a small lookahead window. The limit exists as a safety cap \u2014\n * it should never be reached on valid input.\n */\nexport function isMappingStart(ctx) {\n const tok = ctx.peek();\n // Comment at start can begin a mapping (comments are valid mapping items)\n if (tok.kind === TokenKind.COMMENT)\n return true;\n // Template pipe at start can begin a mapping item (template as statement)\n if (tok.kind === TokenKind.PIPE)\n return true;\n // Statement keywords (not followed by colon) start mappings\n if (tok.kind === TokenKind.ID && isStatementStart(ctx))\n return true;\n // First token must be able to start a key; bail early otherwise.\n if (!isKeyTokenStart(tok.kind))\n return false;\n // Scan forward on the same line past key-like tokens (ID, STRING, NUMBER,\n // MINUS, DOT) looking for COLON (normal case), INDENT/ARROW (missing-colon\n // recovery), AT (missing-colon with @-expression value), or STRING/NUMBER\n // after a single ID key (missing-colon with literal value).\n const startRow = tok.start.row;\n for (let i = 1; i < MAX_KEY_LOOKAHEAD; i++) {\n const t = ctx.peekAt(i);\n if (t.kind === TokenKind.COLON ||\n t.kind === TokenKind.INDENT ||\n t.kind === TokenKind.ARROW ||\n t.kind === TokenKind.AT)\n return true;\n // A STRING or NUMBER immediately after a single ID key suggests\n // a missing colon (e.g., `agent_name \"WeatherBot\"`).\n // Only trigger this on the first lookahead position (i === 1) to\n // avoid false positives with multi-word keys.\n if (i === 1 && (t.kind === TokenKind.STRING || t.kind === TokenKind.NUMBER))\n return true;\n if (t.kind === TokenKind.EOF || t.start.row !== startRow)\n return false;\n if (!isKeyTokenContinuation(t.kind))\n return false;\n }\n return false;\n}\n/**\n * Parse a mapping (sequence of key-value pairs).\n */\nexport function parseMapping(ctx, parseSequence) {\n const node = ctx.startNode('mapping');\n while (!isAtEnd(ctx)) {\n skipNewlines(ctx);\n const tok = ctx.peek();\n if (tok.kind === TokenKind.DEDENT || tok.kind === TokenKind.EOF)\n break;\n // Don't consume trailing comments that belong to the parent scope.\n if (tok.kind === TokenKind.COMMENT && isTrailingCommentOnly(ctx)) {\n break;\n }\n const item = parseMappingItem(ctx, parseSequence);\n if (item) {\n node.appendChild(item);\n }\n else {\n // Can't parse \u2014 synchronize (skip to next line)\n const err = synchronize(ctx);\n if (err) {\n node.appendChild(err);\n }\n else if (!isAtEnd(ctx) && ctx.peekKind() !== TokenKind.DEDENT) {\n // Consume at least one token to avoid infinite loop\n ctx.consume();\n }\n }\n }\n return node;\n}\n/**\n * Parse a single mapping item (statement, template, comment, or key:value element).\n */\nexport function parseMappingItem(ctx, parseSequence) {\n const tok = ctx.peek();\n // Statement keywords always take the statement path (tree-sitter parity).\n // Keywords cannot be used as mapping keys.\n if (tok.kind === TokenKind.ID) {\n switch (tok.text) {\n case 'if':\n return parseIfStatement(ctx, c => parseTemplate(c));\n case 'run':\n return parseRunStatement(ctx, c => parseTemplate(c));\n case 'set':\n return parseSetStatement(ctx);\n case 'transition':\n return parseTransitionStatement(ctx);\n case 'with': {\n if (ctx.peekAt(1).kind !== TokenKind.COLON) {\n return parseWithStatement(ctx);\n }\n break;\n }\n case 'available': {\n if (ctx.peekAt(1).kind === TokenKind.ID &&\n ctx.peekAt(1).text === 'when') {\n return parseAvailableWhenStatement(ctx);\n }\n break;\n }\n }\n }\n // Template\n if (tok.kind === TokenKind.PIPE) {\n return parseTemplate(ctx);\n }\n // Comment\n if (tok.kind === TokenKind.COMMENT) {\n return ctx.consumeNamed('comment');\n }\n // Standalone else/elif/for \u2014 wrap in ERROR with parsed body\n if (tok.kind === TokenKind.ID &&\n (tok.text === 'else' || tok.text === 'elif' || tok.text === 'for')) {\n return parseOrphanBlock(ctx, c => parseProcedure(c, c2 => parseTemplate(c2)));\n }\n // Mapping element (key: value)\n if (isKeyStart(ctx)) {\n return parseMappingElement(ctx, parseSequence);\n }\n return null;\n}\n// ---------------------------------------------------------------------------\n// Exported helpers needed by parse-sequence.ts (T04)\n// ---------------------------------------------------------------------------\n/**\n * Check if the current position starts a colinear mapping element (key: value\n * on same line after \"- \").\n */\nexport function isColinearMappingElement(ctx) {\n // key: value on same line after \"- \"\n if (!isKeyStart(ctx))\n return false;\n const tok = ctx.peek();\n // Look ahead: ID/STRING then COLON on same line\n const lookahead = 1;\n // Two-word key?\n if (ctx.peekAt(lookahead).kind === TokenKind.ID &&\n ctx.peekAt(lookahead).start.row === tok.start.row) {\n const afterSecond = ctx.peekAt(lookahead + 1);\n if (afterSecond.kind === TokenKind.COLON &&\n afterSecond.start.row === tok.start.row) {\n return true;\n }\n // Don't eagerly consume two-word key if first word is followed by colon\n }\n const next = ctx.peekAt(lookahead);\n return next.kind === TokenKind.COLON && next.start.row === tok.start.row;\n}\n/**\n * Parse a colinear mapping element (key: value on the same line as \"- \").\n */\nexport function parseColinearMappingElement(ctx) {\n const startTok = ctx.peek();\n const node = ctx.startNode('mapping_element');\n const key = parseKey(ctx);\n if (key)\n node.appendChild(key, 'key');\n if (ctx.peekKind() === TokenKind.COLON) {\n ctx.addAnonymousChild(node, ctx.consume());\n }\n const colinear = tryParseColinearValue(ctx);\n if (colinear) {\n if (colinear.errorPrefix)\n node.appendChild(colinear.errorPrefix);\n node.appendChild(colinear.value, 'colinear_value');\n }\n ctx.finishNode(node, startTok);\n return node;\n}\n/**\n * Try to parse a colinear value (template, variable declaration, or expression).\n * Returns the parsed value node and optional error prefix, or null if nothing\n * can be parsed.\n */\nexport function tryParseColinearValue(ctx) {\n const tok = ctx.peek();\n // Template\n if (tok.kind === TokenKind.PIPE) {\n return { value: parseTemplateAsColinear(ctx) };\n }\n // Variable declaration: mutable/linked\n if (tok.kind === TokenKind.ID &&\n (tok.text === 'mutable' || tok.text === 'linked')) {\n return { value: parseVariableDeclaration(ctx) };\n }\n // Fuzzy modifier: close misspelling of mutable/linked \u2192 parse as variable_declaration\n // with the misspelled token wrapped in ERROR\n if (tok.kind === TokenKind.ID && isFuzzyModifier(tok.text)) {\n return { value: parseFuzzyVariableDeclaration(ctx) };\n }\n // expression_with_to: expression followed by optional with/to clauses\n const expr = parseExpression(ctx, 0);\n if (!expr)\n return null;\n // Check for error prefix: if the expression is a number or digit-starting ID\n // (like \"123\" or \"123bad\") AND the next token is an ID on the same line,\n // the first is an error prefix and the second is the real value.\n // Wrap the first in ERROR and re-parse the rest.\n if ((expr.type === 'number' ||\n (expr.type === 'id' && /^[0-9]/.test(expr.text))) &&\n ctx.peekKind() === TokenKind.ID &&\n ctx.peek().start.row === expr.startRow) {\n // Wrap number/digit-starting ID in ERROR\n const errNode = makeErrorNode(ctx.source, [wrapExpression(ctx, expr)], expr.startOffset, expr.endOffset, expr.startPosition, expr.endPosition);\n // Now re-parse the real colinear value (could be variable_declaration or expression)\n const realValue = tryParseColinearValue(ctx);\n // If we got a real value, return it with the error prefix for the caller to handle.\n if (realValue) {\n return { value: realValue.value, errorPrefix: errNode };\n }\n // No real value \u2014 just return the expression as-is\n }\n // Check for with/to statement list\n const withToList = tryParseWithToStatementList(ctx);\n if (withToList) {\n const ewt = ctx.startNodeAt('expression_with_to', expr);\n ewt.appendChild(wrapExpression(ctx, expr), 'expression');\n ewt.appendChild(withToList, 'with_to_statement_list');\n ewt.finalize();\n return { value: ewt };\n }\n // Check for assignment: expr = expr\n if (ctx.peekKind() === TokenKind.EQ) {\n const assign = ctx.startNodeAt('assignment_expression', expr);\n assign.appendChild(wrapExpression(ctx, expr), 'left');\n ctx.addAnonymousChild(assign, ctx.consume()); // =\n const right = parseExpression(ctx, 0);\n if (right)\n assign.appendChild(wrapExpression(ctx, right), 'right');\n assign.finalize();\n return { value: assign };\n }\n // Plain expression_with_to (just expression, no with/to)\n const ewt = ctx.startNodeAt('expression_with_to', expr);\n ewt.appendChild(wrapExpression(ctx, expr), 'expression');\n return { value: ewt };\n}\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n/**\n * Compute Levenshtein distance between two strings.\n */\nfunction levenshteinDistance(a, b) {\n const m = a.length;\n const n = b.length;\n const dp = Array.from({ length: m + 1 }, () => Array.from({ length: n + 1 }).fill(0));\n for (let i = 0; i <= m; i++)\n dp[i][0] = i;\n for (let j = 0; j <= n; j++)\n dp[0][j] = j;\n for (let i = 1; i <= m; i++) {\n for (let j = 1; j <= n; j++) {\n const cost = a[i - 1] === b[j - 1] ? 0 : 1;\n dp[i][j] = Math.min(dp[i - 1][j] + 1, dp[i][j - 1] + 1, dp[i - 1][j - 1] + cost);\n }\n }\n return dp[m][n];\n}\n/**\n * Check if a string is a likely misspelling of 'mutable' or 'linked' (Levenshtein \u2264 2).\n */\nfunction isFuzzyModifier(text) {\n return (levenshteinDistance(text, 'mutable') <= 2 ||\n levenshteinDistance(text, 'linked') <= 2);\n}\n/**\n * Parse a variable declaration with a misspelled modifier.\n * The misspelled modifier token is wrapped in ERROR, while the rest\n * (type expression + optional default) is parsed normally.\n */\nfunction parseFuzzyVariableDeclaration(ctx) {\n const startTok = ctx.peek();\n const node = ctx.startNode('variable_declaration');\n // Consume misspelled modifier and wrap in ERROR\n const misspelled = ctx.consume();\n const misspelledEnd = misspelled.startOffset + misspelled.text.length;\n const leaf = tokenToAutoLeaf(misspelled, ctx.source, misspelled.startOffset);\n const errNode = makeErrorNode(ctx.source, [leaf], misspelled.startOffset, misspelledEnd, misspelled.start, misspelled.end);\n node.appendChild(errNode);\n // type expression\n const typeExpr = parseExpression(ctx, 0);\n if (typeExpr)\n node.appendChild(wrapExpression(ctx, typeExpr), 'type');\n // Optional default: = expr\n if (ctx.peekKind() === TokenKind.EQ) {\n ctx.addAnonymousChild(node, ctx.consume()); // =\n const defaultExpr = parseExpression(ctx, 0);\n if (defaultExpr)\n node.appendChild(wrapExpression(ctx, defaultExpr), 'default');\n }\n ctx.finishNode(node, startTok);\n return node;\n}\nfunction parseMappingElement(ctx, parseSequence) {\n const startTok = ctx.peek();\n const node = ctx.startNode('mapping_element');\n const key = parseKey(ctx);\n invariant(key != null, 'We must be at a key start');\n node.appendChild(key, 'key');\n // Colon handling\n if (ctx.peekKind() === TokenKind.COLON) {\n // Consume real colon\n ctx.addAnonymousChild(node, ctx.consumeKind(TokenKind.COLON));\n }\n else if (ctx.peekKind() === TokenKind.INDENT ||\n ctx.peekKind() === TokenKind.ARROW ||\n ctx.peekKind() === TokenKind.ID ||\n ctx.peekKind() === TokenKind.AT ||\n ctx.peekKind() === TokenKind.STRING ||\n ctx.peekKind() === TokenKind.NUMBER) {\n // Insert MISSING colon for recovery\n node.appendChild(makeMissing(ctx, ':'));\n }\n else {\n // No colon, no recovery, no value\n return node;\n }\n if (ctx.peekKind() === TokenKind.ARROW) {\n parseArrowBody(ctx, node);\n }\n else if (ctx.peekKind() === TokenKind.INDENT) {\n parseIndentedBlockValue(ctx, node, parseSequence);\n }\n else {\n parseColinearAndBlock(ctx, node, startTok.start.row, parseSequence);\n }\n return node;\n}\n/**\n * Parse optional colinear value, inline comment, error synchronization,\n * and trailing indented block or continuation `to` clause.\n */\nfunction parseColinearAndBlock(ctx, node, startRow, parseSequence) {\n const colinear = tryParseColinearValue(ctx);\n if (colinear) {\n if (colinear.errorPrefix)\n node.appendChild(colinear.errorPrefix);\n node.appendChild(colinear.value, 'colinear_value');\n }\n if (ctx.peekKind() === TokenKind.COMMENT) {\n node.appendChild(ctx.consumeNamed('comment'));\n }\n // Absorb trailing junk on same row after colinear value (e.g., a broken\n // `tz` that was meant to be `to`).\n if (colinear) {\n const err = synchronizeRow(ctx, startRow);\n if (err)\n node.appendChild(err);\n }\n else if (!ctx.isAtSyncPoint() && ctx.peekKind() !== TokenKind.INDENT) {\n const err = synchronize(ctx);\n if (err)\n node.appendChild(err);\n }\n // Continuation: indented `to` clause on expression_with_to\n // (e.g., `go: @utils.transition\\n to @topic.next`).\n // NOTE: we only absorb `to`, not `with` \u2014 an indented `with` is typically\n // a with_statement in a block_value mapping, not a with clause on the expression.\n if (colinear?.value.type === 'expression_with_to' &&\n !colinear.value.childForFieldName('with_to_statement_list') &&\n ctx.peekKind() === TokenKind.INDENT &&\n ctx.peekAt(1).kind === TokenKind.ID &&\n ctx.peekAt(1).text === 'to') {\n ctx.consumeKind(TokenKind.INDENT);\n const withToList = tryParseWithToStatementList(ctx);\n if (withToList) {\n colinear.value.appendChild(withToList, 'with_to_statement_list');\n node.endOffset = colinear.value.endOffset;\n node.endPosition = colinear.value.endPosition;\n }\n ctx.consumeKind(TokenKind.DEDENT);\n }\n else if (ctx.peekKind() === TokenKind.INDENT) {\n parseIndentedBlockValue(ctx, node, parseSequence);\n }\n}\n/** Consume `->` and its indented procedure body (shared by normal and missing-colon paths). */\nfunction parseArrowBody(ctx, node) {\n ctx.addAnonymousChild(node, ctx.consume()); // ->\n // Inline comment after -> (e.g., `instructions: -> # comment`)\n if (ctx.peekKind() === TokenKind.COMMENT) {\n node.appendChild(ctx.consumeNamed('comment'));\n }\n if (ctx.peekKind() === TokenKind.INDENT) {\n ctx.consume(); // INDENT\n // Comments between -> and procedure body attach to mapping_element\n consumeCommentsAndSkipNewlines(ctx, node);\n const proc = parseProcedure(ctx, c => parseTemplate(c));\n if (proc)\n node.appendChild(proc, 'block_value');\n // Trailing comments after procedure attach to mapping_element\n consumeCommentsAndSkipNewlines(ctx, node);\n if (ctx.peekKind() === TokenKind.DEDENT)\n ctx.consume();\n }\n else {\n // Arrow with no indented body \u2192 empty procedure with ERROR\n const emptyProc = ctx.startNode('procedure');\n emptyProc.appendChild(makeEmptyError(ctx));\n ctx.finishNode(emptyProc, ctx.peek());\n node.appendChild(emptyProc, 'block_value');\n }\n}\nfunction parseVariableDeclaration(ctx) {\n const startTok = ctx.peek();\n const node = ctx.startNode('variable_declaration');\n // mutable or linked\n ctx.addAnonymousChild(node, ctx.consume());\n // Check for duplicate modifier (error case: \"mutable linked\")\n if (ctx.peekKind() === TokenKind.ID &&\n (ctx.peek().text === 'mutable' || ctx.peek().text === 'linked')) {\n // Wrap the extra modifier in ERROR\n const errExpr = parseExpression(ctx, 0);\n if (errExpr) {\n const wrapped = wrapExpression(ctx, errExpr);\n const errNode = makeErrorNode(ctx.source, [wrapped], wrapped.startOffset, wrapped.endOffset, wrapped.startPosition, wrapped.endPosition);\n node.appendChild(errNode);\n }\n }\n // type expression\n const typeExpr = parseExpression(ctx, 0);\n if (typeExpr)\n node.appendChild(wrapExpression(ctx, typeExpr), 'type');\n // Optional default: = expr\n if (ctx.peekKind() === TokenKind.EQ) {\n ctx.addAnonymousChild(node, ctx.consume()); // =\n const defaultExpr = parseExpression(ctx, 0);\n if (defaultExpr)\n node.appendChild(wrapExpression(ctx, defaultExpr), 'default');\n }\n ctx.finishNode(node, startTok);\n return node;\n}\n// --- Block value ---\n/** Consume INDENT, parse block value with surrounding comments, recover leftovers, consume DEDENT. */\nfunction parseIndentedBlockValue(ctx, parent, parseSequence) {\n ctx.consume(); // INDENT\n consumeCommentsAndSkipNewlines(ctx, parent);\n const blockValue = parseBlockValue(ctx, parseSequence);\n if (blockValue)\n parent.appendChild(blockValue, 'block_value');\n consumeCommentsAndSkipNewlines(ctx, parent);\n recoverToBlockEnd(ctx, parent);\n if (ctx.peekKind() === TokenKind.DEDENT)\n ctx.consume();\n}\nfunction parseBlockValue(ctx, parseSequence) {\n const tok = ctx.peek();\n // Sequence\n if (tok.kind === TokenKind.DASH_SPACE) {\n return parseSequence(ctx);\n }\n // Empty keyword\n if (tok.kind === TokenKind.ID && tok.text === 'empty') {\n const emptyNode = ctx.startNode('empty_keyword');\n ctx.addAnonymousChild(emptyNode, ctx.consume());\n ctx.finishNode(emptyNode, tok);\n return emptyNode;\n }\n // Mapping \u2014 either key:value or statement-starting content\n // isMappingStart() already checks isStatementStart() internally\n if (isMappingStart(ctx)) {\n return parseMapping(ctx, parseSequence);\n }\n // Atom (standalone value in block position)\n return parseAtomBlockValue(ctx);\n}\nfunction parseAtomBlockValue(ctx) {\n const expr = parseExpression(ctx, 0);\n if (!expr)\n return null;\n // tree-sitter's block_value rule wraps atom-type children in (atom ...)\n if (ATOM_TYPES.has(expr.type)) {\n const atom = new CSTNode('atom', ctx.source, expr.startOffset, expr.endOffset, expr.startPosition, expr.endPosition);\n atom.appendChild(expr);\n return atom;\n }\n return expr;\n}\n//# sourceMappingURL=parse-mapping.js.map", "/*\n * Copyright (c) 2026, Salesforce, Inc.\n * All rights reserved.\n * SPDX-License-Identifier: Apache-2.0\n * For full license text, see the LICENSE file in the repo root or https://www.apache.org/licenses/LICENSE-2.0\n */\n/**\n * Sequence parsing functions extracted from Parser class.\n *\n * Each function takes a ParserContext as its first parameter, following\n * the same free-function pattern as parse-mapping.ts and parse-templates.ts.\n */\nimport { TokenKind } from './token.js';\nimport { makeErrorNode } from './errors.js';\nimport { synchronize, skipNewlines, isAtEnd } from './recovery.js';\nimport { parseMapping, parseMappingItem, tryParseColinearValue, isColinearMappingElement, parseColinearMappingElement, } from './parse-mapping.js';\n/**\n * Parse a YAML-style sequence (list of `- item` entries).\n *\n * Exported for use by parser.ts dispatch and by parse-mapping.ts\n * via ParseSequenceFn callback.\n */\nexport function parseSequence(ctx) {\n const startTok = ctx.peek();\n const node = ctx.startNode('sequence');\n while (ctx.peekKind() === TokenKind.DASH_SPACE) {\n const elem = parseSequenceElement(ctx);\n if (elem)\n node.appendChild(elem);\n skipNewlines(ctx);\n }\n // Non-sequence items remaining at same indent \u2192 wrap in ERROR inside sequence\n while (!isAtEnd(ctx) &&\n ctx.peekKind() !== TokenKind.DEDENT &&\n ctx.peekKind() !== TokenKind.DASH_SPACE) {\n skipNewlines(ctx);\n if (isAtEnd(ctx) || ctx.peekKind() === TokenKind.DEDENT)\n break;\n // Try to parse as mapping item and wrap in ERROR\n const parseSeq = (_ctx) => parseSequence(_ctx);\n const item = parseMappingItem(ctx, parseSeq);\n if (item) {\n const errNode = makeErrorNode(ctx.source, [item], item.startOffset, item.endOffset, item.startPosition, item.endPosition);\n node.appendChild(errNode);\n }\n else {\n const err = synchronize(ctx);\n if (err) {\n node.appendChild(err);\n }\n else {\n ctx.consume();\n }\n }\n }\n ctx.finishNode(node, startTok);\n return node;\n}\n/**\n * Parse a single sequence element: `- <value>`.\n */\nfunction parseSequenceElement(ctx) {\n const startTok = ctx.peek();\n const node = ctx.startNode('sequence_element');\n // Consume \"- \" or \"-\"\n ctx.addAnonymousChild(node, ctx.consume());\n const parseSeq = (_ctx) => parseSequence(_ctx);\n // Check for colinear mapping element (key: value on same line)\n if (isColinearMappingElement(ctx)) {\n const mappingElem = parseColinearMappingElement(ctx);\n if (mappingElem)\n node.appendChild(mappingElem, 'colinear_mapping_element');\n // Optional block value (indented mapping below)\n if (ctx.peekKind() === TokenKind.NEWLINE)\n ctx.consume();\n if (ctx.peekKind() === TokenKind.INDENT) {\n ctx.consume();\n const blockValue = parseMapping(ctx, parseSeq);\n if (blockValue)\n node.appendChild(blockValue, 'block_value');\n if (ctx.peekKind() === TokenKind.DEDENT)\n ctx.consume();\n }\n }\n else if (ctx.peekKind() === TokenKind.NEWLINE ||\n ctx.peekKind() === TokenKind.EOF ||\n ctx.peekKind() === TokenKind.INDENT) {\n // Bare dash with optional block value below (or immediately indented)\n if (ctx.peekKind() === TokenKind.NEWLINE)\n ctx.consume();\n if (ctx.peekKind() === TokenKind.INDENT) {\n ctx.consume();\n const blockValue = parseMapping(ctx, parseSeq);\n if (blockValue)\n node.appendChild(blockValue, 'block_value');\n if (ctx.peekKind() === TokenKind.DEDENT)\n ctx.consume();\n }\n }\n else {\n // Colinear value\n const colinear = tryParseColinearValue(ctx);\n if (colinear) {\n if (colinear.errorPrefix)\n node.appendChild(colinear.errorPrefix);\n node.appendChild(colinear.value, 'colinear_value');\n }\n // Inline comment after value\n if (ctx.peekKind() === TokenKind.COMMENT) {\n node.appendChild(ctx.consumeNamed('comment'));\n }\n if (ctx.peekKind() === TokenKind.NEWLINE)\n ctx.consume();\n }\n ctx.finishNode(node, startTok);\n return node;\n}\n//# sourceMappingURL=parse-sequence.js.map", "/*\n * Copyright (c) 2026, Salesforce, Inc.\n * All rights reserved.\n * SPDX-License-Identifier: Apache-2.0\n * For full license text, see the LICENSE file in the repo root or https://www.apache.org/licenses/LICENSE-2.0\n */\n/**\n * Recursive descent parser for AgentScript.\n *\n * Core invariant: NEWLINE and DEDENT are unconditional synchronization points.\n * Every parse function that encounters an unexpected token calls synchronize()\n * which skips to the next NEWLINE/DEDENT/EOF.\n */\nimport { isTokenKind, TokenKind } from './token.js';\nimport { Lexer } from './lexer.js';\nimport { CSTNode } from './cst-node.js';\nimport { isSyncPoint } from './errors.js';\nimport { synchronize, skipNewlines, consumeCommentsAndSkipNewlines, isAtEnd, } from './recovery.js';\nimport { parseMappingOrExpression } from './parse-mapping.js';\nimport { parseSequence } from './parse-sequence.js';\nimport invariant from 'tiny-invariant';\nexport class Parser {\n source;\n tokens;\n pos = 0;\n _eof;\n constructor(source) {\n this.source = source;\n const lexer = new Lexer(source);\n this.tokens = lexer.tokenize();\n }\n parse() {\n const root = this.parseSourceFile();\n return root;\n }\n // --- ParserContext implementation ---\n peek() {\n return this.peekAt(0);\n }\n peekAt(offset) {\n // n.b. (Allen): Because this is called so frequently, these invariants cause significant runtime overhead.\n // invariant(this.pos + offset >= 0, 'peekAt too small');\n // invariant(this.pos + offset <= this.tokens.length, 'peekAt too large');\n return this.peekAtIndex(this.pos + offset);\n }\n peekAtIndex(idx) {\n return this.tokens[idx] ?? this.eofToken();\n }\n peekKind() {\n return this.peek().kind;\n }\n consume() {\n const tok = this.peek();\n this.pos++;\n return tok;\n }\n consumeKind(kind) {\n const tok = this.peek();\n invariant(isTokenKind(tok, kind), `Expected token kind ${kind} but got ${tok.kind}`);\n this.pos++;\n return tok;\n }\n consumeNamed(type) {\n const tok = this.consume();\n const offset = tok.startOffset;\n return new CSTNode(type, this.source, offset, offset + tok.text.length, tok.start, tok.end);\n }\n currentOffset() {\n const idx = this.pos > 0 ? this.pos - 1 : 0;\n return this.peekAtIndex(idx).startOffset;\n }\n peekOffset() {\n return this.peek().startOffset;\n }\n isAtSyncPoint() {\n return isSyncPoint(this.peekKind());\n }\n startNode(type) {\n const tok = this.peek();\n const offset = tok.startOffset;\n return new CSTNode(type, this.source, offset, offset, tok.start, tok.end);\n }\n startNodeAt(type, existingChild) {\n return new CSTNode(type, this.source, existingChild.startOffset, existingChild.endOffset, existingChild.startPosition, existingChild.endPosition);\n }\n finishNode(_node, _startTok) {\n // No-op: appendChild() tracks end position incrementally.\n }\n addAnonymousChild(parent, token) {\n const offset = token.startOffset;\n const child = new CSTNode(token.text, this.source, offset, offset + token.text.length, token.start, token.end, false);\n parent.appendChild(child);\n }\n // --- Top-level parsing ---\n parseSourceFile() {\n const node = this.startNode('source_file');\n // Skip leading newlines and indentation (handles template literals with leading whitespace)\n skipNewlines(this);\n if (this.peekKind() === TokenKind.INDENT) {\n this.consume();\n }\n // Consume leading comments at source_file level (tree-sitter treats them as extras)\n consumeCommentsAndSkipNewlines(this, node);\n // Determine what kind of source file this is\n if (this.peekKind() === TokenKind.DASH_SPACE) {\n // Sequence\n node.appendChild(parseSequence(this));\n }\n else {\n // Mapping or expression\n // n.b. (Allen): Originally we didn't permit expressions at the top level, but\n // we did that to make testing easier in tree-sitter so I suppose\n // we can just make this a feature of the language.\n const content = parseMappingOrExpression(this, _ctx => parseSequence(_ctx));\n if (content)\n node.appendChild(content);\n }\n // Consume trailing comments at source_file level\n consumeCommentsAndSkipNewlines(this, node);\n // Catch-all: if there are unconsumed tokens, wrap them in ERROR nodes.\n // This ensures every byte of source is represented in the CST.\n while (!isAtEnd(this)) {\n if (this.peekKind() === TokenKind.NEWLINE ||\n this.peekKind() === TokenKind.DEDENT) {\n this.consume();\n continue;\n }\n if (this.peekKind() === TokenKind.COMMENT) {\n node.appendChild(this.consumeNamed('comment'));\n continue;\n }\n const err = synchronize(this);\n if (err) {\n node.appendChild(err);\n }\n else {\n // Consume one token to guarantee progress\n this.consume();\n }\n }\n // Root node must span entire source (matches tree-sitter invariant)\n node.startOffset = 0;\n node.startPosition = { row: 0, column: 0 };\n node.endOffset = this.source.length;\n node.endPosition = this.eofToken().end;\n return node;\n }\n eofToken() {\n if (!this._eof) {\n const lastToken = this.tokens[this.tokens.length - 1];\n const pos = lastToken ? lastToken.end : { row: 0, column: 0 };\n this._eof = {\n kind: TokenKind.EOF,\n text: '',\n start: pos,\n end: pos,\n startOffset: this.source.length,\n };\n }\n return this._eof;\n }\n}\n//# sourceMappingURL=parser.js.map", "/*\n * Copyright (c) 2026, Salesforce, Inc.\n * All rights reserved.\n * SPDX-License-Identifier: Apache-2.0\n * For full license text, see the LICENSE file in the repo root or https://www.apache.org/licenses/LICENSE-2.0\n */\n/**\n * @agentscript/parser-javascript \u2014 Hand-written TypeScript parser for AgentScript.\n *\n * Error-tolerant: NEWLINE and DEDENT are unconditional recovery points.\n */\nexport { CSTNode } from './cst-node.js';\nexport { TokenKind } from './token.js';\nexport { highlight } from './highlighter.js';\nimport { Parser } from './parser.js';\nimport { highlight } from './highlighter.js';\n/**\n * Parse AgentScript source code and return a CST.\n * The returned rootNode implements the SyntaxNode interface\n * used by all consumers (dialect, LSP, monaco, agentforce).\n */\nexport function parse(source) {\n const parser = new Parser(source);\n return { rootNode: parser.parse() };\n}\n/**\n * Parse and highlight source code in one call.\n * Returns captures compatible with the QueryCapture format\n * used by LSP semantic tokens.\n */\nexport function parseAndHighlight(source) {\n const { rootNode } = parse(source);\n return highlight(rootNode);\n}\n//# sourceMappingURL=index.js.map", "import type { SyntaxNode } from '@agentscript/types';\n\nimport { parse as parseAgent } from '@agentscript/parser-javascript';\n\nexport function parseAgentSource(source: string): SyntaxNode {\n return parseAgent(source).rootNode;\n}\n\nexport function locOf(n: SyntaxNode) {\n return {\n endCol: n.endCol,\n endRow: n.endRow,\n startCol: n.startCol,\n startRow: n.startRow,\n };\n}\n\nexport function walk(node: SyntaxNode, visit: (n: SyntaxNode) => void): void {\n visit(node);\n for (const c of node.namedChildren) walk(c, visit);\n}\n\nexport function* descendants(node: SyntaxNode): Generator<SyntaxNode> {\n yield node;\n for (const c of node.namedChildren) yield* descendants(c);\n}\n\n/**\n * The block header for a `key` node. AgentScript keys can be plain (`config`)\n * or named (`topic case_creation`, `start_agent customer_verification`).\n * We return the first whitespace-delimited token as the key kind, and the\n * remainder (if any) as the instance label.\n */\nexport function keyHeader(n: SyntaxNode): null | { kind: string; label?: string } {\n if (n.type !== 'key') return null;\n const head = n.text.split('\\n', 1)[0];\n const colon = head.indexOf(':');\n const lhs = (colon === -1 ? head : head.slice(0, colon)).trim();\n const parts = lhs.split(/\\s+/);\n return { kind: parts[0], label: parts.length > 1 ? parts.slice(1).join(' ') : undefined };\n}\n\n/**\n * The CST shapes a key/value pair as `mapping_element { key, ':', value }`.\n * Given the mapping_element node, return its key kind + label.\n */\nexport function mappingKeyHeader(m: SyntaxNode): null | { kind: string; label?: string } {\n if (m.type !== 'mapping_element') return null;\n const keyNode = m.childForFieldName('key');\n if (!keyNode) {\n // Fall back: first namedChild of type 'key'.\n for (const c of m.namedChildren) {\n if (c.type === 'key') return keyHeader(c);\n }\n\n return null;\n }\n\n return keyHeader(keyNode);\n}\n\n/**\n * The value-bearing child of a mapping_element. Could be `mapping` (sub-block),\n * `expression_with_to` (scalar/expression), `colinear_value`, `procedure`,\n * `variable_declaration`, etc.\n *\n * A mapping_element can interleave leading `comment` nodes between the `:`/`->`\n * markers and the actual value-bearing child. Skip them so we don't return a\n * comment as the \"value.\"\n */\nconst NON_VALUE_NAMED_TYPES = new Set(['comment', 'key']);\n\nexport function mappingValue(m: SyntaxNode): SyntaxNode | undefined {\n if (m.type !== 'mapping_element') return undefined;\n for (const c of m.namedChildren) {\n if (!NON_VALUE_NAMED_TYPES.has(c.type)) return c;\n }\n\n return undefined;\n}\n\n/**\n * Within a scope whose body is a `mapping` (the typical case for topic/\n * start_agent/subagent blocks), find the mapping_element whose key matches\n * `kind`, and return its value subtree.\n */\nexport function findMappingEntry(parentBody: SyntaxNode, kind: string): SyntaxNode | undefined {\n for (const c of parentBody.namedChildren) {\n if (c.type !== 'mapping_element') continue;\n const h = mappingKeyHeader(c);\n if (h && h.kind === kind) return mappingValue(c);\n }\n\n return undefined;\n}\n\n/**\n * Walk a scope-key node (topic / start_agent / subagent at top level) and\n * return its body \u2014 the `mapping` that holds before_reasoning, after_reasoning,\n * reasoning, actions, etc. The scope-key itself lives inside a mapping_element\n * at the source-file level; the body is the sibling value.\n */\nexport function bodyOf(scopeKey: SyntaxNode): SyntaxNode | undefined {\n const {parent} = scopeKey;\n if (!parent) return undefined;\n return mappingValue(parent);\n}\n\n/**\n * Read the `developer_name:` value from the `config:` block of a parsed\n * .agent file. This is the canonical API name of the agent (matches what\n * `sf agent generate authoring-bundle --api-name X` produces). Returns\n * undefined when the field is absent or empty.\n */\nexport function extractDeveloperName(root: SyntaxNode): string | undefined {\n const topMapping = root.namedChildren.find(c => c.type === 'mapping') ?? root;\n for (const c of topMapping.namedChildren) {\n if (c.type !== 'mapping_element') continue;\n const keyNode =\n c.childForFieldName('key') ?? c.namedChildren.find(n => n.type === 'key');\n if (!keyNode) continue;\n const h = keyHeader(keyNode);\n if (!h || h.kind !== 'config') continue;\n const body = mappingValue(c);\n if (!body) return undefined;\n const devNameVal = findMappingEntry(body, 'developer_name');\n if (!devNameVal) return undefined;\n return extractStringLiteral(devNameVal);\n }\n\n return undefined;\n}\n\n/** Convenience: extract a leaf string literal text (without surrounding quotes). */\nexport function extractStringLiteral(n: SyntaxNode): string | undefined {\n for (const d of descendants(n)) {\n if (d.type === 'string') {\n const t = d.text;\n if (t.startsWith('\"') && t.endsWith('\"')) return t.slice(1, -1);\n if (t.startsWith(\"'\") && t.endsWith(\"'\")) return t.slice(1, -1);\n return t;\n }\n }\n\n return undefined;\n}\n", "import type { SyntaxNode } from '@agentscript/types';\n\nimport type { AgentScope } from './complexity.js';\nimport type { ActionDeclaration, ActionReference, ActionTargetKind } from './types.js';\n\nimport {\n descendants,\n extractStringLiteral,\n findMappingEntry,\n locOf,\n mappingKeyHeader,\n mappingValue,\n} from './parse.js';\n\nconst TARGET_SCHEME = /^([a-z][a-z0-9+.-]*):\\/\\//i;\n\nfunction classifyTarget(uri: string | undefined): ActionTargetKind {\n if (!uri) return 'unknown';\n const m = TARGET_SCHEME.exec(uri);\n if (!m) return 'unknown';\n const scheme = m[1].toLowerCase();\n if (scheme === 'apex') return 'apex';\n if (scheme === 'flow') return 'flow';\n if (scheme.startsWith('prompt')) return 'prompt';\n return 'unknown';\n}\n\n/**\n * Within a scope body (the value of a `topic` or `start_agent`/`subagent`\n * mapping_element), the `actions:` entry holds a mapping of named action\n * declarations. Each declaration is itself a mapping with metadata fields\n * like `target:`, `label:`, `inputs:`, `outputs:`.\n */\nexport function collectDeclarations(scope: AgentScope): ActionDeclaration[] {\n const decls: ActionDeclaration[] = [];\n const actionsBlock = findMappingEntry(scope.body, 'actions');\n if (!actionsBlock) return decls;\n for (const child of actionsBlock.namedChildren) {\n if (child.type !== 'mapping_element') continue;\n const h = mappingKeyHeader(child);\n if (!h) continue;\n const declName = h.kind;\n const declBody = mappingValue(child);\n if (!declBody) {\n decls.push({\n location: locOf(child),\n name: declName,\n scope: scope.label,\n target: undefined,\n targetKind: 'unknown',\n });\n continue;\n }\n\n const targetVal = findMappingEntry(declBody, 'target');\n const targetStr = targetVal ? extractStringLiteral(targetVal) : undefined;\n decls.push({\n location: locOf(child),\n name: declName,\n scope: scope.label,\n target: targetStr,\n targetKind: classifyTarget(targetStr),\n });\n }\n\n return decls;\n}\n\n/**\n * Collect every member_expression of the form `@actions.X` *outside* the\n * `actions:` declaration block. We treat them as references \u2014 i.e. usages of\n * the declared actions in reasoning / before / after blocks.\n *\n * Context discrimination:\n * \u2022 inside reasoning > actions \u2192 'reasoning_actions'\n * \u2022 inside after_reasoning \u2192 'after_reasoning_run'\n * \u2022 inside before_reasoning \u2192 'before_reasoning_run'\n * \u2022 inside transition_statement \u2192 'transition'\n */\nexport function collectReferences(scope: AgentScope): ActionReference[] {\n const refs: ActionReference[] = [];\n\n const explore = (body: SyntaxNode | undefined, context: ActionReference['context']) => {\n if (!body) return;\n for (const n of descendants(body)) {\n if (n.type !== 'member_expression') continue;\n // member_expression text is the full chain (\"@actions.Foo[.Bar]\");\n // text matching is more robust than peeking through the wrapper\n // chain (expression \u2192 atom \u2192 at_id).\n if (!n.text.startsWith('@actions.')) continue;\n const name = actionNameFromMember(n);\n if (!name) continue;\n // Differentiate when we're inside a transition_statement.\n const ctx = isInsideTransition(n) ? 'transition' : context;\n refs.push({\n context: ctx,\n location: locOf(n),\n name,\n scope: scope.label,\n });\n }\n };\n\n explore(findMappingEntry(scope.body, 'before_reasoning'), 'before_reasoning_run');\n explore(findMappingEntry(scope.body, 'after_reasoning'), 'after_reasoning_run');\n const reasoning = findMappingEntry(scope.body, 'reasoning');\n if (reasoning) {\n // `reasoning.actions:` \u2014 the declarative action contract block;\n // refs here describe what the LLM is allowed to call.\n explore(findMappingEntry(reasoning, 'actions'), 'reasoning_actions');\n // `reasoning.instructions: ->` \u2014 refs here are `run @actions.X`\n // invocations the LLM evaluates as part of its instructions.\n // Per the whitepaper, these execute non-deterministically.\n explore(findMappingEntry(reasoning, 'instructions'), 'reasoning_instructions_run');\n }\n\n return refs;\n}\n\nfunction actionNameFromMember(n: SyntaxNode): string | undefined {\n // member_expression text is \"@actions.Foo_Bar\" \u2014 strip the prefix.\n const t = n.text;\n const dot = t.indexOf('.');\n if (dot === -1) return undefined;\n const rest = t.slice(dot + 1);\n // Take the leading identifier, in case of further chained access.\n const m = /^([A-Za-z_][A-Za-z0-9_]*)/.exec(rest);\n return m?.[1];\n}\n\nfunction isInsideTransition(n: SyntaxNode): boolean {\n let p = n.parent;\n while (p) {\n if (p.type === 'transition_statement') return true;\n p = p.parent;\n }\n\n return false;\n}\n", "import { readFile } from 'node:fs/promises';\nimport { basename, relative } from 'node:path';\n\nimport type {\n ApexClassReport,\n ApexMethodCC,\n FileReport,\n} from './types.js';\n\nimport { complexityOfMethod, methodsInCompilationUnit } from './apex-complexity.js';\nimport { parseApexSource } from './apex-parse.js';\nimport {\n extractApexClassName,\n resolveApexClassPath,\n} from './apex-resolve.js';\n\n/** Inputs needed to resolve and analyze every apex:// target in the bundle. */\nexport interface ApexAnalyzeInputs {\n /** Absolute paths of every .agent file analyzed, parallel to fileReports. */\n agentAbsPaths: string[];\n apexSourceOverride?: string;\n fileReports: FileReport[];\n sourceDirRoot: string;\n}\n\nexport interface ApexAnalyzeOutputs {\n classes: ApexClassReport[];\n unresolved: string[];\n}\n\nexport async function analyzeReferencedApex(\n inputs: ApexAnalyzeInputs,\n): Promise<ApexAnalyzeOutputs> {\n const byPath = new Map<string, ApexClassReport>();\n const unresolved = new Set<string>();\n\n for (let i = 0; i < inputs.fileReports.length; i++) {\n const fr = inputs.fileReports[i];\n const agentAbs = inputs.agentAbsPaths[i];\n for (const decl of fr.declarations) {\n if (decl.targetKind !== 'apex' || !decl.target) continue;\n const className = extractApexClassName(decl.target);\n if (!className) {\n unresolved.add(decl.target);\n continue;\n }\n\n const path = await resolveApexClassPath(className, {\n agentFilePath: agentAbs,\n apexSourceOverride: inputs.apexSourceOverride,\n sourceDirRoot: inputs.sourceDirRoot,\n });\n if (!path) {\n unresolved.add(decl.target);\n continue;\n }\n\n const existing = byPath.get(path);\n if (existing) {\n if (!existing.referencedBy.includes(fr.path)) {\n existing.referencedBy.push(fr.path);\n }\n\n continue;\n }\n\n const report = await analyzeApexClass(path, className, [fr.path], inputs.sourceDirRoot);\n byPath.set(path, report);\n }\n }\n\n return {\n classes: [...byPath.values()].sort((a, b) => a.className.localeCompare(b.className)),\n unresolved: [...unresolved].sort(),\n };\n}\n\nasync function analyzeApexClass(\n absPath: string,\n className: string,\n referencedBy: string[],\n sourceDirRoot: string,\n): Promise<ApexClassReport> {\n const source = await readFile(absPath, 'utf8');\n const cu = parseApexSource(source);\n const methodCtxs = methodsInCompilationUnit(cu);\n const methods: ApexMethodCC[] = methodCtxs.map((m) => complexityOfMethod(m));\n const classComplexity = methods.reduce((acc, m) => acc + m.complexity, 0);\n\n return {\n classComplexity,\n className: className || basename(absPath, '.cls'),\n methods,\n parseErrors: [],\n path: relative(sourceDirRoot, absPath),\n referencedBy,\n };\n}\n", "import {\n CatchClauseContext,\n type CompilationUnitContext,\n CondExpressionContext,\n ConstructorDeclarationContext,\n DoWhileStatementContext,\n type FormalParametersContext,\n ForStatementContext,\n IfStatementContext,\n LogAndExpressionContext,\n LogOrExpressionContext,\n MethodDeclarationContext,\n WhenControlContext,\n WhileStatementContext,\n} from '@apexdevtools/apex-parser';\n\nimport type {\n ApexCCContributor,\n ApexCCContributorKind,\n ApexMethodCC,\n} from './types.js';\n\nimport { type ApexRuleNode, locOfCtx, walkParseTree } from './apex-parse.js';\n\n/**\n * Standard McCabe Cyclomatic Complexity for Apex, per the SonarQube /\n * PMD CyclomaticComplexity convention used in the categorization\n * whitepaper \u00A7 7:\n *\n * CC = 1\n * + count(if)\n * + count(for) // includes enhanced-for (for-each)\n * + count(while)\n * + count(do-while)\n * + count(when arm) // each switch `when X { ... }`; `when else` excluded\n * + count(catch) // each catch clause\n * + count(ternary ?:)\n * + count(&&)\n * + count(||)\n *\n * Not counted: else, when else, finally, try itself.\n */\nexport function complexityOfMethod(\n methodCtx: ConstructorDeclarationContext | MethodDeclarationContext,\n): ApexMethodCC {\n const body = methodCtx.block();\n const contributors: ApexCCContributor[] = [];\n\n if (body) {\n walkParseTree(body, node => {\n // Don't descend into nested methods/constructors \u2014 they have their\n // own CC counted separately.\n if (\n node !== methodCtx &&\n (node instanceof MethodDeclarationContext ||\n node instanceof ConstructorDeclarationContext)\n ) {\n // walkParseTree will still recurse into this node's subtree.\n // We can't easily prune, so we filter by parentage: skip\n // contributors whose nearest enclosing method/ctor is not us.\n return;\n }\n\n const kind = classifyContributor(node);\n if (kind !== undefined && enclosingMethod(node) === methodCtx) {\n contributors.push({ kind, location: locOfCtx(node) });\n }\n });\n }\n\n const name =\n methodCtx instanceof ConstructorDeclarationContext\n ? methodCtx.qualifiedName()?.getText() ?? '<ctor>'\n : (methodCtx as MethodDeclarationContext).id()?.getText() ?? '<anon>';\n\n const signature = renderSignature(methodCtx, name);\n\n return {\n complexity: 1 + contributors.length,\n contributors,\n kind: methodCtx instanceof ConstructorDeclarationContext ? 'constructor' : 'method',\n location: locOfCtx(methodCtx),\n name,\n signature,\n };\n}\n\nfunction classifyContributor(node: ApexRuleNode): ApexCCContributorKind | undefined {\n if (node instanceof IfStatementContext) return 'if_statement';\n if (node instanceof ForStatementContext) return 'for_statement';\n if (node instanceof WhileStatementContext) return 'while_statement';\n if (node instanceof DoWhileStatementContext) return 'do_while_statement';\n if (node instanceof WhenControlContext) {\n // `when else { ... }` is the default arm \u2192 don't count it.\n const wv = node.whenValue();\n const elseTok = wv && typeof wv.ELSE === 'function' ? wv.ELSE() : undefined;\n return elseTok ? undefined : 'when_arm';\n }\n\n if (node instanceof CatchClauseContext) return 'catch_clause';\n if (node instanceof CondExpressionContext) return 'ternary';\n if (node instanceof LogAndExpressionContext) return 'short_circuit_and';\n if (node instanceof LogOrExpressionContext) return 'short_circuit_or';\n return undefined;\n}\n\nfunction enclosingMethod(\n node: ApexRuleNode,\n): ConstructorDeclarationContext | MethodDeclarationContext | undefined {\n let p: ApexRuleNode | undefined = node.parentCtx;\n while (p) {\n if (p instanceof MethodDeclarationContext || p instanceof ConstructorDeclarationContext) {\n return p;\n }\n\n p = p.parentCtx;\n }\n\n return undefined;\n}\n\nfunction renderSignature(\n ctx: ConstructorDeclarationContext | MethodDeclarationContext,\n name: string,\n): string {\n const paramsText = renderFormalParameters(ctx.formalParameters());\n if (ctx instanceof MethodDeclarationContext) {\n const retType = ctx.typeRef()?.getText() ?? (ctx.VOID() ? 'void' : '');\n return `${retType ? retType + ' ' : ''}${name}${paramsText}`;\n }\n\n return `${name}${paramsText}`;\n}\n\n/**\n * ANTLR's `getText()` concatenates child tokens with no whitespace, which\n * mangles parameter lists like `List<Request> requests` into\n * `List<Request>requests`. Walk the structured children and rebuild a\n * properly-spaced signature.\n */\nfunction renderFormalParameters(params: FormalParametersContext | null): string {\n if (!params) return '()';\n const list = params.formalParameterList();\n if (!list) return '()';\n const parts = list.formalParameter_list().map(p => {\n const type = p.typeRef()?.getText() ?? '';\n const id = p.id()?.getText() ?? '';\n return type && id ? `${type} ${id}` : type || id;\n });\n return `(${parts.join(', ')})`;\n}\n\n/**\n * Enumerate every method and constructor in a compilation unit, including\n * those nested inside inner classes. Each gets its own CC entry per the\n * v2 scope (\"all methods in any class touched by apex://\").\n */\nexport function methodsInCompilationUnit(cu: CompilationUnitContext): Array<\n ConstructorDeclarationContext | MethodDeclarationContext\n> {\n const out: Array<ConstructorDeclarationContext | MethodDeclarationContext> = [];\n walkParseTree(cu, node => {\n if (\n (node instanceof MethodDeclarationContext ||\n node instanceof ConstructorDeclarationContext) &&\n node.block()\n ) {\n out.push(node);\n }\n });\n return out;\n}\n", "import {\n ApexParserFactory,\n CompilationUnitContext,\n} from '@apexdevtools/apex-parser';\n\n/**\n * Structural view of an ANTLR parse-tree node covering only the members this\n * analyzer touches. `@apexdevtools/apex-parser` 5.x ships generated context\n * types that extend antlr4's `ParserRuleContext`, but antlr4 4.13.x does not\n * surface `ParserRuleContext` (nor its inherited `getText`/`getChild`) through\n * its NodeNext `.d.cts` re-export chain, so importing it directly fails to\n * resolve. We model the contract locally instead \u2014 the runtime objects carry\n * all of these methods.\n */\nexport interface ApexRuleNode {\n getChild(i: number): unknown;\n getChildCount(): number;\n getText(): string;\n parentCtx?: ApexRuleNode | undefined;\n start?: { column?: number; line?: number; text?: string };\n stop?: { column?: number; line?: number; text?: string };\n}\n\nexport function parseApexSource(source: string): CompilationUnitContext {\n const parser = ApexParserFactory.createParser(source);\n return parser.compilationUnit();\n}\n\nexport function locOfCtx(ctx: ApexRuleNode) {\n const {start} = ctx;\n const stop = ctx.stop ?? ctx.start;\n return {\n endCol: (stop?.column ?? 0) + (stop?.text?.length ?? 0),\n endRow: stop?.line ?? 0,\n startCol: start?.column ?? 0,\n startRow: start?.line ?? 0,\n };\n}\n\n/**\n * Walk an ANTLR parse-tree node depth-first, invoking the visitor on every\n * descendant (including the start node). Terminal/error nodes have no\n * children and are visited like any other node \u2014 caller filters by type.\n */\nexport function walkParseTree(\n node: ApexRuleNode,\n visit: (n: ApexRuleNode) => void,\n): void {\n visit(node);\n const childCount =\n typeof node.getChildCount === 'function' ? node.getChildCount() : 0;\n for (let i = 0; i < childCount; i++) {\n const c = node.getChild(i);\n // Filter to ParserRuleContext children only \u2014 terminals don't carry rules.\n if (c && typeof (c as ApexRuleNode).getChildCount === 'function') {\n walkParseTree(c as ApexRuleNode, visit);\n }\n }\n}\n", "import { stat } from 'node:fs/promises';\nimport { dirname, isAbsolute, join, resolve, sep } from 'node:path';\n\nconst APEX_SCHEME = /^apex:\\/\\/(.+)$/;\n\nexport function extractApexClassName(uri: string): string | undefined {\n const m = APEX_SCHEME.exec(uri);\n if (!m) return undefined;\n // `apex://Foo` or `apex://namespace__Foo`; take the trailing simple name.\n const raw = m[1].trim();\n const dot = raw.lastIndexOf('.');\n return dot === -1 ? raw : raw.slice(dot + 1);\n}\n\nexport interface ResolveOptions {\n /**\n * The .agent file that holds the apex:// reference. Used as the seed for\n * the upward walk.\n */\n agentFilePath: string;\n /**\n * Optional `--apex-source` override. When set, classes are looked up here\n * before falling back to the upward walk.\n */\n apexSourceOverride?: string;\n /**\n * The CLI `--source-dir` value. We never walk above this directory.\n */\n sourceDirRoot: string;\n}\n\n/**\n * Find `classes/<ClassName>.cls` by walking up from the .agent file. The walk\n * stops at the CLI's source-dir root so we never escape it. Returns the\n * absolute path or undefined.\n *\n * Path conventions covered:\n * - sfdx default: <pkg>/main/default/classes/<X>.cls, with the .agent in\n * <pkg>/main/default/aiAuthoringBundles/<Bundle>/<X>.agent\n * - flat fixtures: <root>/classes/<X>.cls, with .agent under\n * <root>/aiAuthoringBundles/<Bundle>/<X>.agent\n * - explicit override: --apex-source <dir>/<X>.cls\n */\nexport async function resolveApexClassPath(\n className: string,\n opts: ResolveOptions,\n): Promise<string | undefined> {\n const candidates: string[] = [];\n\n if (opts.apexSourceOverride) {\n const override = isAbsolute(opts.apexSourceOverride)\n ? opts.apexSourceOverride\n : resolve(opts.apexSourceOverride);\n candidates.push(\n join(override, `${className}.cls`),\n join(override, 'classes', `${className}.cls`),\n );\n }\n\n const stop = resolve(opts.sourceDirRoot);\n let dir = dirname(resolve(opts.agentFilePath));\n while (true) {\n candidates.push(join(dir, 'classes', `${className}.cls`));\n if (dir === stop) break;\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n\n for (const c of candidates) {\n const s = await stat(c).catch(() => {});\n if (s?.isFile()) return c;\n }\n\n return undefined;\n}\n\n/** True if `child` is the same as or a subpath of `parent` (path-segment safe). */\nexport function isUnder(child: string, parent: string): boolean {\n const c = resolve(child);\n const p = resolve(parent);\n if (c === p) return true;\n return c.startsWith(p.endsWith(sep) ? p : p + sep);\n}\n", "import type { SyntaxNode } from '@agentscript/types';\n\nimport type { CCContributor, ProcedureCC, SourceLocation } from './types.js';\n\nimport { bodyOf, descendants, findMappingEntry, keyHeader, locOf } from './parse.js';\n\n/**\n * Standard McCabe CC, applied to AgentScript control-flow nodes.\n *\n * Per the categorization whitepaper (\u00A7 7) the convention mirrors\n * SonarQube/PMD/Checkstyle for the relevant language:\n *\n * CC = 1\n * + count(if_statement)\n * + count(elif_clause)\n * + count(ternary_expression)\n * + count(binary_expression where operator \u2208 {and, or})\n *\n * We do NOT count: else_clause, comparison_expression, set/run/transition,\n * try/catch (AgentScript has none), default branches.\n */\nconst SHORT_CIRCUIT_OPS = new Set(['and', 'or']);\n\nexport function complexityOf(body: SyntaxNode, scope: string, kind: ProcedureCC['kind']): ProcedureCC {\n const contributors: CCContributor[] = [];\n for (const n of descendants(body)) {\n switch (n.type) {\n case 'binary_expression': {\n const op = binaryOperator(n);\n if (op === 'and') contributors.push({ kind: 'short_circuit_and', location: locOf(n) });\n else if (op === 'or') contributors.push({ kind: 'short_circuit_or', location: locOf(n) });\n break;\n }\n\n case 'elif_clause': {\n contributors.push({ kind: 'elif_clause', location: locOf(n) });\n break;\n }\n\n case 'if_statement': {\n contributors.push({ kind: 'if_statement', location: locOf(n) });\n break;\n }\n\n case 'ternary_expression': {\n contributors.push({ kind: 'ternary_expression', location: locOf(n) });\n break;\n }\n }\n }\n\n return {\n complexity: 1 + contributors.length,\n contributors,\n kind,\n location: locOf(body),\n scope,\n };\n}\n\nfunction binaryOperator(n: SyntaxNode): string | undefined {\n for (const c of n.children) {\n if (!c.isNamed && SHORT_CIRCUIT_OPS.has(c.type)) return c.type;\n if (!c.isNamed && (c.type === '+' || c.type === '-' || c.type === '*' || c.type === '/')) return c.type;\n }\n\n return undefined;\n}\n\n/**\n * Identify the procedure-bearing blocks in a single topic / start_agent /\n * subagent scope. AgentScript's three control-flow surfaces are:\n * \u2022 before_reasoning: <procedure> (deterministic, pre-LLM)\n * \u2022 after_reasoning: <procedure> (deterministic, post-LLM)\n * \u2022 reasoning.instructions: -> <template body> (LLM-evaluated)\n *\n * v1 walks all three for CC. (instructions: -> body holds Reasoning Logic per\n * whitepaper \u00A7 4 but the CC convention itself is language-neutral.)\n */\nexport function collectProcedures(scopeBody: SyntaxNode, scopeLabel: string): ProcedureCC[] {\n const out: ProcedureCC[] = [];\n\n const before = findMappingEntry(scopeBody, 'before_reasoning');\n if (before) out.push(complexityOf(before, scopeLabel, 'before_reasoning'));\n\n const after = findMappingEntry(scopeBody, 'after_reasoning');\n if (after) out.push(complexityOf(after, scopeLabel, 'after_reasoning'));\n\n const reasoning = findMappingEntry(scopeBody, 'reasoning');\n if (reasoning) {\n const instructions = findMappingEntry(reasoning, 'instructions');\n if (instructions) {\n out.push(complexityOf(instructions, scopeLabel, 'reasoning_instructions'));\n }\n }\n\n return out;\n}\n\n/** Scopes that contain procedure-bearing blocks. */\nconst PROCEDURE_SCOPES = new Set(['start_agent', 'subagent', 'topic']);\n\nexport interface AgentScope {\n body: SyntaxNode;\n kind: string;\n label: string;\n}\n\n/**\n * Find topic/start_agent/subagent scopes anywhere in the tree. They appear\n * at the source-file level as mapping_elements whose key kind matches.\n */\nexport function collectScopes(root: SyntaxNode): AgentScope[] {\n const scopes: AgentScope[] = [];\n // The source_file has a single top-level `mapping` child holding the agent\n // declarations (system, config, variables, start_agent X, topic Y, \u2026).\n const topMapping = root.namedChildren.find(c => c.type === 'mapping') ?? root;\n for (const c of topMapping.namedChildren) {\n if (c.type !== 'mapping_element') continue;\n const keyNode = c.childForFieldName('key') ?? c.namedChildren.find(n => n.type === 'key');\n if (!keyNode) continue;\n const h = keyHeader(keyNode);\n if (!h || !PROCEDURE_SCOPES.has(h.kind)) continue;\n const body = bodyOf(keyNode);\n if (!body) continue;\n scopes.push({ body, kind: h.kind, label: `${h.kind} ${h.label ?? ''}`.trim() });\n }\n\n return scopes;\n}\n\nexport interface FileComplexity {\n procedures: ProcedureCC[];\n total: number;\n}\n\nexport function complexityForFile(root: SyntaxNode): FileComplexity {\n const procedures: ProcedureCC[] = [];\n for (const s of collectScopes(root)) {\n procedures.push(...collectProcedures(s.body, s.label));\n }\n\n const total = procedures.reduce((acc, p) => acc + p.complexity, 0);\n return { procedures, total };\n}\n\nexport function dummyLoc(): SourceLocation {\n return { endCol: 0, endRow: 0, startCol: 0, startRow: 0 };\n}\n", "import { Flags, SfCommand } from '@salesforce/sf-plugins-core';\n\nimport type { AnalysisReport } from '../../analyzer/types.js';\nimport type { RenderFormat } from '../../renderers/index.js';\n\nimport { analyzeSource } from '../../analyzer/analyze.js';\nimport { discoverSfdxProject } from '../../analyzer/project.js';\nimport { render } from '../../renderers/index.js';\n\nconst FORMATS: ReadonlyArray<RenderFormat> = ['text', 'markdown', 'sarif', 'csv'];\n\nexport default class AgentpmdAnalyze extends SfCommand<AnalysisReport> {\n public static readonly description = `Walks .agent source files under --source-dir and emits per-procedure\ncyclomatic complexity totals (before_reasoning, after_reasoning, and\nreasoning.instructions blocks), plus an inventory of declared and used\n@actions.X targets. For every apex:// target, resolves the .cls file\nand computes per-method Apex CC.\n\nDefault output is human-readable text. --json emits the SF CLI envelope\nwith the full structured report. --format <markdown|sarif|csv> emits the\nnamed format on stdout for piping into PR comments, GitHub Code Scanning,\nor spreadsheet pivots.`;\npublic static readonly examples = [\n '<%= config.bin %> <%= command.id %> --source-dir force-app/main/default',\n '<%= config.bin %> <%= command.id %> --source-dir force-app/main/default --json',\n '<%= config.bin %> <%= command.id %> --source-dir force-app/main/default --format markdown > report.md',\n '<%= config.bin %> <%= command.id %> --source-dir force-app/main/default --format sarif > report.sarif',\n ];\npublic static readonly flags = {\n 'apex-source': Flags.string({\n summary:\n 'Override directory to look up apex:// targets. By default we walk up from each .agent file looking for a sibling classes/ folder.',\n }),\n 'api-name': Flags.string({\n char: 'n',\n multiple: true,\n summary:\n 'Filter to specific agent bundles. Matched against the bundle directory name and the config.developer_name field. Repeatable.',\n }),\n ascii: Flags.boolean({\n default: false,\n summary:\n 'Force ASCII-only output in the text renderer (no Unicode box chars, no emoji).',\n }),\n 'fail-on': Flags.integer({\n min: 1,\n summary:\n 'Exit non-zero if combined agent+Apex CC meets or exceeds this threshold.',\n }),\n format: Flags.string({\n default: 'text',\n options: [...FORMATS],\n summary:\n 'Non-JSON output format. --json takes precedence per SF CLI convention.',\n }),\n 'no-color': Flags.boolean({\n default: false,\n summary: 'Disable ANSI color in the text renderer. NO_COLOR env also disables.',\n }),\n 'sarif-error': Flags.integer({\n min: 1,\n summary: 'SARIF \"error\" level threshold. Default 20.',\n }),\n 'sarif-warning': Flags.integer({\n min: 1,\n summary: 'SARIF \"warning\" level threshold. Default 10.',\n }),\n 'source-dir': Flags.string({\n char: 'd',\n summary:\n 'Directory or single .agent file to analyze. Defaults to the packageDirectories of the nearest sfdx-project.json.',\n }),\n width: Flags.integer({\n default: 60,\n min: 20,\n summary: 'Rule width for the text renderer.',\n }),\n };\npublic static readonly summary =\n 'Compute McCabe cyclomatic complexity and action-reference inventory for AgentScript bundles and their Apex backing logic.';\n\n public async run(): Promise<AnalysisReport> {\n const { flags } = await this.parse(AgentpmdAnalyze);\n\n const { reportBase, roots, sourceDescription } = await resolveSources(\n flags['source-dir'],\n );\n if (!this.jsonEnabled() && sourceDescription) {\n this.log(sourceDescription);\n }\n\n const report = await analyzeSource(roots, {\n apexSourceOverride: flags['apex-source'],\n apiNames: flags['api-name'],\n reportBase,\n });\n\n if (!this.jsonEnabled()) {\n const format = flags.format as RenderFormat;\n const text = render(format, report, {\n ascii: flags.ascii || undefined,\n color: flags['no-color'] ? false : undefined,\n sarifErrorThreshold: flags['sarif-error'],\n sarifWarningThreshold: flags['sarif-warning'],\n width: flags.width,\n });\n this.log(text);\n }\n\n const combined = report.totalComplexity + report.totalApexComplexity;\n if (flags['fail-on'] !== undefined && combined >= flags['fail-on']) {\n this.error(\n `Combined cyclomatic complexity ${combined} (agent ${report.totalComplexity} + apex ${report.totalApexComplexity}) \u2265 threshold ${flags['fail-on']}`,\n { exit: 2 },\n );\n }\n\n return report;\n }\n}\n\ninterface ResolvedSources {\n reportBase: string | undefined;\n roots: string[];\n /** Optional human-readable note about where sources came from. */\n sourceDescription?: string;\n}\n\n/**\n * Resolve the directories we should scan. Explicit `--source-dir` wins.\n * Otherwise, walk up from cwd looking for `sfdx-project.json` and use its\n * `packageDirectories`. If neither is available, fail with a clear message.\n */\nasync function resolveSources(\n sourceDirFlag: string | undefined,\n): Promise<ResolvedSources> {\n if (sourceDirFlag) {\n return { reportBase: undefined, roots: [sourceDirFlag] };\n }\n\n const project = await discoverSfdxProject(process.cwd());\n if (!project) {\n throw new Error(\n 'No --source-dir was provided and no sfdx-project.json was found in the ' +\n 'current directory or any ancestor. Pass --source-dir <path> or run from ' +\n 'inside an sfdx project.',\n );\n }\n\n if (project.packageDirectories.length === 0) {\n throw new Error(\n `sfdx-project.json at ${project.root} declares no packageDirectories. ` +\n 'Pass --source-dir <path> explicitly.',\n );\n }\n\n return {\n reportBase: project.root,\n roots: project.packageDirectories,\n sourceDescription: `Analyzing sfdx project ${project.root} (${project.packageDirectories.length} package director${project.packageDirectories.length === 1 ? 'y' : 'ies'}).`,\n };\n}\n", "import { readFile, stat } from 'node:fs/promises';\nimport { dirname, isAbsolute, join, resolve } from 'node:path';\n\nexport interface SfdxProject {\n /** Absolute paths of every `packageDirectories[].path`, in declaration order. */\n packageDirectories: string[];\n /** Absolute path of the project root (the directory containing sfdx-project.json). */\n root: string;\n}\n\n/**\n * Walk up from `startDir` until we find a directory containing\n * `sfdx-project.json`, then return its root + resolved package directories.\n * Returns undefined when no project is found.\n */\nexport async function discoverSfdxProject(\n startDir: string,\n): Promise<SfdxProject | undefined> {\n let dir = resolve(startDir);\n while (true) {\n const candidate = join(dir, 'sfdx-project.json');\n const s = await stat(candidate).catch(() => {});\n if (s?.isFile()) {\n return readProject(dir, candidate);\n }\n\n const parent = dirname(dir);\n if (parent === dir) return undefined;\n dir = parent;\n }\n}\n\nasync function readProject(root: string, jsonPath: string): Promise<SfdxProject> {\n const raw = await readFile(jsonPath, 'utf8');\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch (error) {\n throw new Error(\n `failed to parse ${jsonPath}: ${(error as Error).message}`,\n );\n }\n\n const pkgs = extractPackageDirectories(parsed, root);\n return { packageDirectories: pkgs, root };\n}\n\nfunction extractPackageDirectories(parsed: unknown, root: string): string[] {\n if (!parsed || typeof parsed !== 'object') return [];\n const obj = parsed as { packageDirectories?: unknown };\n if (!Array.isArray(obj.packageDirectories)) return [];\n const out: string[] = [];\n for (const entry of obj.packageDirectories) {\n if (!entry || typeof entry !== 'object') continue;\n const pathField = (entry as { path?: unknown }).path;\n if (typeof pathField !== 'string' || pathField.length === 0) continue;\n out.push(isAbsolute(pathField) ? pathField : resolve(root, pathField));\n }\n\n return out;\n}\n", "import type {\n AnalysisReport,\n ApexCCContributor,\n CCContributor,\n} from '../analyzer/types.js';\n\n/**\n * Single CSV with all per-procedure and per-method rows so a spreadsheet\n * can pivot on `type` and `file`. RFC 4180-quoted; first row is the header.\n */\nexport function renderCsv(report: AnalysisReport): string {\n const lines: string[] = [];\n lines.push(\n [\n 'type',\n 'file',\n 'scope_or_class',\n 'name',\n 'complexity',\n 'start_row',\n 'start_col',\n 'contributors',\n ]\n .map((c) => csvCell(c))\n .join(','),\n );\n\n for (const f of report.files) {\n for (const p of f.procedures) {\n lines.push(\n [\n 'agent_procedure',\n f.path,\n p.scope,\n p.kind,\n String(p.complexity),\n String(p.location.startRow),\n String(p.location.startCol),\n breakdownProc(p.contributors),\n ]\n .map((c) => csvCell(c))\n .join(','),\n );\n }\n }\n\n for (const cls of report.apexClasses) {\n for (const m of cls.methods) {\n lines.push(\n [\n 'apex_method',\n cls.path,\n cls.className,\n m.signature,\n String(m.complexity),\n String(m.location.startRow),\n String(m.location.startCol),\n breakdownApex(m.contributors),\n ]\n .map((c) => csvCell(c))\n .join(','),\n );\n }\n }\n\n return lines.join('\\n');\n}\n\nfunction csvCell(v: string): string {\n // Always quote \u2014 keeps the output uniform and lets cells contain\n // commas, quotes, and newlines without per-cell branching.\n return `\"${v.replaceAll('\"', '\"\"')}\"`;\n}\n\nfunction breakdownProc(contributors: CCContributor[]): string {\n if (contributors.length === 0) return 'base';\n const counts: Record<string, number> = {};\n for (const c of contributors) counts[c.kind] = (counts[c.kind] ?? 0) + 1;\n return Object.entries(counts)\n .map(([k, n]) => `${k}=${n}`)\n .join(';');\n}\n\nfunction breakdownApex(contributors: ApexCCContributor[]): string {\n if (contributors.length === 0) return 'base';\n const counts: Record<string, number> = {};\n for (const c of contributors) counts[c.kind] = (counts[c.kind] ?? 0) + 1;\n return Object.entries(counts)\n .map(([k, n]) => `${k}=${n}`)\n .join(';');\n}\n", "import type {\n AnalysisReport,\n ApexCCContributor,\n \n CCContributor,\n FileReport,\n ProcedureCC,\n} from '../analyzer/types.js';\n\nconst KIND_LABEL: Record<ProcedureCC['kind'], string> = {\n after_reasoning: 'after_reasoning',\n available_when: 'available_when',\n before_reasoning: 'before_reasoning',\n other: 'other',\n reasoning_instructions: 'reasoning.instructions',\n};\n\n/**\n * Renders a GFM Markdown report with a Mermaid bar chart at the top\n * (agent CC vs Apex CC per bundle) followed by per-bundle and per-class\n * drilldown tables. Designed to be portable into PR descriptions, gists,\n * Slack snippets, and whitepaper appendices.\n *\n * Palette is whitepaper \u00A7 1: Reasoning hot (#a82820), Conversation amber\n * (#c4942a), Deterministic green (#6b8c52), Scaffolding cool gray (#9aa5ad).\n */\nexport function renderMarkdown(report: AnalysisReport): string {\n const lines: string[] = [];\n lines.push('# AgentForce PMD \u2014 Cyclomatic Complexity (McCabe)', '', \n 'Per the categorization rule \u00A7 7, CC is reported by the standard ' +\n 'McCabe convention used in SonarQube / PMD / Checkstyle for the ' +\n 'relevant language.', ''\n );\n\n if (report.files.length === 0) {\n lines.push('_(no `.agent` files found)_');\n return lines.join('\\n');\n }\n\n // \u2500\u2500 CC by location chart \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n lines.push('## CC by location', '',\n renderMermaid(report), '',\n `| | AgentScript | Apex | Combined |\\n` +\n `| --- | ---: | ---: | ---: |\\n` +\n `| **Totals** | ${report.totalComplexity} | ${report.totalApexComplexity} | ${report.totalComplexity + report.totalApexComplexity} |`, ''\n , '## Per-bundle (`.agent` files)', '');\n for (const f of report.files) {\n lines.push(`### \\`${f.path}\\` \u2014 CC = ${f.fileComplexity}`, '');\n if (f.procedures.length === 0) {\n lines.push('_(no procedure-bearing scopes)_');\n } else {\n lines.push('| Scope | Procedure | CC | Contributors |', '| --- | --- | ---: | --- |');\n for (const p of f.procedures) {\n lines.push(\n `| ${escapeCell(p.scope)} | ${KIND_LABEL[p.kind]} | ${p.complexity} | ${escapeCell(breakdownProc(p.contributors))} |`,\n );\n }\n }\n\n lines.push('');\n\n if (f.declarations.length > 0) {\n lines.push('**Action references**', '', '| Action | Target kind | Target | Uses |', '| --- | --- | --- | ---: |');\n const usage = countReferences(f);\n for (const d of f.declarations) {\n const used = usage.get(d.name) ?? 0;\n lines.push(\n `| \\`${d.name}\\` | ${d.targetKind} | ${d.target ?? '_n/a_'} | ${used} |`,\n );\n }\n\n const undeclared = listUndeclaredRefs(f);\n if (undeclared.length > 0) {\n lines.push(\n '',\n 'Referenced but not declared in-file: ' + undeclared.map(u => `\\`${u}\\``).join(', '),\n );\n }\n\n lines.push('');\n }\n }\n\n // \u2500\u2500 Apex backing logic \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n if (report.apexClasses.length > 0 || report.unresolvedApexTargets.length > 0) {\n lines.push('## Apex backing logic', '');\n for (const cls of report.apexClasses) {\n lines.push(\n `### \\`${cls.path}\\` \u2014 class CC = ${cls.classComplexity}`, '',\n `Referenced by: ${cls.referencedBy.map(r => `\\`${r}\\``).join(', ') || '_none_'}`, '',\n );\n if (cls.methods.length === 0) {\n lines.push('_(no methods with bodies)_');\n } else {\n lines.push('| Method | CC | Contributors |', '| --- | ---: | --- |');\n for (const m of cls.methods) {\n lines.push(\n `| \\`${escapeCell(m.signature)}\\` | ${m.complexity} | ${escapeCell(breakdownApex(m.contributors))} |`,\n );\n }\n }\n\n lines.push('');\n }\n\n if (report.unresolvedApexTargets.length > 0) {\n lines.push('### Unresolved `apex://` targets', '');\n for (const u of report.unresolvedApexTargets) {\n lines.push(`- \\`${u}\\` \u2014 no matching \\`.cls\\` under \\`--source-dir\\` or \\`--apex-source\\``);\n }\n\n lines.push('');\n }\n }\n\n // \u2500\u2500 Footer \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n lines.push('---', '', \n `Action declarations: **${report.totalDeclarations}** ` +\n `(apex ${report.byTargetKind.apex}, flow ${report.byTargetKind.flow}, ` +\n `prompt ${report.byTargetKind.prompt}, unknown ${report.byTargetKind.unknown}). ` +\n `Action references: **${report.totalReferences}**.`,\n );\n\n return lines.join('\\n');\n}\n\nfunction renderMermaid(report: AnalysisReport): string {\n // Per-bundle agent CC + the sum of Apex CC for classes that bundle\n // references. We compute that mapping rather than counting classes\n // globally so each bundle's bar reflects its full \"implementation\n // CC\" footprint.\n const apexByBundle = new Map<string, number>();\n for (const cls of report.apexClasses) {\n for (const ref of cls.referencedBy) {\n apexByBundle.set(ref, (apexByBundle.get(ref) ?? 0) + cls.classComplexity);\n }\n }\n\n const labels: string[] = [];\n const agentVals: number[] = [];\n const apexVals: number[] = [];\n for (const f of report.files) {\n labels.push(shortBundleLabel(f.path));\n agentVals.push(f.fileComplexity);\n apexVals.push(apexByBundle.get(f.path) ?? 0);\n }\n\n // Mermaid xychart-beta supports stacked-bar style via two series.\n // Palette: AgentScript = Reasoning red (#a82820); Apex = Deterministic green (#6b8c52).\n return [\n '```mermaid',\n '%%{init: {\"theme\":\"base\",\"themeVariables\":{\"xyChart\":{\"plotColorPalette\":\"#a82820, #6b8c52\"}}}}%%',\n 'xychart-beta',\n ' title \"CC by location, per .agent bundle\"',\n ` x-axis [${labels.map(l => `\"${l}\"`).join(', ')}]`,\n ` y-axis \"Cyclomatic complexity\"`,\n ` bar [${agentVals.join(', ')}]`,\n ` bar [${apexVals.join(', ')}]`,\n '```',\n '',\n '<sub>Series: **AgentScript CC** (red, whitepaper \"Reasoning Logic\") \u00B7 **Apex CC** (green, whitepaper \"Deterministic Logic\"). Apex CC per bundle is the sum of the CC of every `apex://` class that bundle references; classes referenced by multiple bundles contribute to each.</sub>',\n ].join('\\n');\n}\n\nfunction shortBundleLabel(path: string): string {\n // Strip \"aiAuthoringBundles/\" and the trailing \".agent\" to keep x-axis tight.\n const stripped = path\n .replace(/^.*aiAuthoringBundles\\//, '')\n .replace(/\\.agent$/, '');\n // Use only the basename if it appears twice (Bundle/Bundle.agent \u2192 Bundle).\n const parts = stripped.split('/');\n if (parts.length === 2 && parts[0] === parts[1]) return parts[0];\n return parts.join('/');\n}\n\nfunction breakdownProc(contributors: CCContributor[]): string {\n if (contributors.length === 0) return '(base only)';\n const counts: Record<string, number> = {};\n for (const c of contributors) counts[c.kind] = (counts[c.kind] ?? 0) + 1;\n return Object.entries(counts)\n .map(([k, n]) => `${shortKind(k)}=${n}`)\n .join(' ');\n}\n\nfunction breakdownApex(contributors: ApexCCContributor[]): string {\n if (contributors.length === 0) return '(base only)';\n const counts: Record<string, number> = {};\n for (const c of contributors) counts[c.kind] = (counts[c.kind] ?? 0) + 1;\n return Object.entries(counts)\n .map(([k, n]) => `${shortApexKind(k)}=${n}`)\n .join(' ');\n}\n\nfunction shortKind(k: string): string {\n switch (k) {\n case 'elif_clause': {\n return 'elif';\n }\n\n case 'if_statement': {\n return 'if';\n }\n\n case 'short_circuit_and': {\n return 'and';\n }\n\n case 'short_circuit_or': {\n return 'or';\n }\n\n case 'ternary_expression': {\n return 'ternary';\n }\n\n default: {\n return k;\n }\n }\n}\n\nfunction shortApexKind(k: string): string {\n switch (k) {\n case 'catch_clause': {\n return 'catch';\n }\n\n case 'do_while_statement': {\n return 'do-while';\n }\n\n case 'for_statement': {\n return 'for';\n }\n\n case 'if_statement': {\n return 'if';\n }\n\n case 'short_circuit_and': {\n return '&&';\n }\n\n case 'short_circuit_or': {\n return '||';\n }\n\n case 'ternary': {\n return 'ternary';\n }\n\n case 'when_arm': {\n return 'when';\n }\n\n case 'while_statement': {\n return 'while';\n }\n\n default: {\n return k;\n }\n }\n}\n\nfunction countReferences(f: FileReport): Map<string, number> {\n const m = new Map<string, number>();\n for (const r of f.references) m.set(r.name, (m.get(r.name) ?? 0) + 1);\n return m;\n}\n\nfunction listUndeclaredRefs(f: FileReport): string[] {\n const declared = new Set(f.declarations.map(d => d.name));\n const seen = new Set<string>();\n const out: string[] = [];\n for (const r of f.references) {\n if (declared.has(r.name)) continue;\n if (seen.has(r.name)) continue;\n seen.add(r.name);\n out.push(r.name);\n }\n\n return out;\n}\n\nfunction escapeCell(s: string): string {\n // GFM table cells: escape pipes and turn embedded newlines into <br>.\n return s.replaceAll('|', String.raw`\\|`).replaceAll('\\n', '<br>');\n}\n\n// re-export for tree-shaking unused warnings; ApexClassReport is referenced\n// indirectly via report.apexClasses[number].\n\n\nexport {type ApexClassReport} from '../analyzer/types.js';", "import type {\n AnalysisReport,\n ApexClassReport,\n ApexMethodCC,\n FileReport,\n ProcedureCC,\n} from '../analyzer/types.js';\nimport type { RenderOptions } from './options.js';\n\ninterface SarifLog {\n $schema: 'https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json';\n runs: SarifRun[];\n version: '2.1.0';\n}\n\ninterface SarifRun {\n results: SarifResult[];\n tool: { driver: SarifDriver };\n}\n\ninterface SarifDriver {\n informationUri: string;\n name: 'sf-agentpmd';\n rules: SarifRule[];\n semanticVersion: string;\n}\n\ninterface SarifRule {\n defaultConfiguration?: { level: 'error' | 'note' | 'warning' };\n fullDescription: { text: string };\n helpUri?: string;\n id: string;\n name: string;\n shortDescription: { text: string };\n}\n\ninterface SarifResult {\n level: 'error' | 'note' | 'warning';\n locations: SarifLocation[];\n message: { text: string };\n properties: { complexity: number; kind: string };\n ruleId: string;\n}\n\ninterface SarifLocation {\n physicalLocation: {\n artifactLocation: { uri: string };\n region: { endColumn: number; endLine: number; startColumn: number; startLine: number; };\n };\n}\n\nconst DEFAULT_WARNING = 10;\nconst DEFAULT_ERROR = 20;\n\nconst RULE_AGENT_CC: SarifRule = {\n defaultConfiguration: { level: 'note' },\n fullDescription: {\n text:\n 'Reports cyclomatic complexity (McCabe) of an AgentScript before_reasoning, ' +\n 'after_reasoning, or reasoning.instructions block. Computed as 1 + ' +\n 'count(if) + count(elif) + count(ternary) + count(and) + count(or).',\n },\n helpUri:\n 'https://github.com/bobbywhitesfdc/sf-agentpmd/blob/main/docs/agent-loc-categorization-skill-v2.md#-7--cyclomatic-complexity',\n id: 'AGENTPMD.AgentScriptCyclomaticComplexity',\n name: 'AgentScriptCyclomaticComplexity',\n shortDescription: {\n text: 'McCabe cyclomatic complexity of an AgentScript procedure.',\n },\n};\n\nconst RULE_APEX_CC: SarifRule = {\n defaultConfiguration: { level: 'note' },\n fullDescription: {\n text:\n 'Reports cyclomatic complexity (McCabe) of an Apex method or ' +\n 'constructor body, mirroring SonarQube / PMD CyclomaticComplexity.',\n },\n helpUri:\n 'https://github.com/bobbywhitesfdc/sf-agentpmd/blob/main/docs/agent-loc-categorization-skill-v2.md#-7--cyclomatic-complexity',\n id: 'AGENTPMD.ApexCyclomaticComplexity',\n name: 'ApexCyclomaticComplexity',\n shortDescription: {\n text: 'McCabe cyclomatic complexity of an Apex method or constructor.',\n },\n};\n\nexport function renderSarif(report: AnalysisReport, opts?: RenderOptions): string {\n const warn = opts?.sarifWarningThreshold ?? DEFAULT_WARNING;\n const err = opts?.sarifErrorThreshold ?? DEFAULT_ERROR;\n\n const results: SarifResult[] = [];\n for (const f of report.files) {\n for (const p of f.procedures) {\n results.push(buildAgentResult(f, p, warn, err));\n }\n }\n\n for (const cls of report.apexClasses) {\n for (const m of cls.methods) {\n results.push(buildApexResult(cls, m, warn, err));\n }\n }\n\n const log: SarifLog = {\n $schema:\n 'https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json',\n runs: [\n {\n results,\n tool: {\n driver: {\n informationUri: 'https://github.com/bobbywhitesfdc/sf-agentpmd',\n name: 'sf-agentpmd',\n rules: [RULE_AGENT_CC, RULE_APEX_CC],\n semanticVersion: pluginVersion(),\n },\n },\n },\n ],\n version: '2.1.0',\n };\n\n return JSON.stringify(log, null, 2);\n}\n\nfunction buildAgentResult(\n f: FileReport,\n p: ProcedureCC,\n warn: number,\n err: number,\n): SarifResult {\n return {\n level: levelFor(p.complexity, warn, err),\n locations: [\n {\n physicalLocation: {\n artifactLocation: { uri: f.path },\n // AgentScript CST locations are 0-based \u2014 bump to SARIF 1-based.\n region: regionFromZeroBased(p.location),\n },\n },\n ],\n message: {\n text:\n `Procedure '${p.kind}' in '${p.scope}' has cyclomatic complexity ` +\n `${p.complexity}.`,\n },\n properties: { complexity: p.complexity, kind: p.kind },\n ruleId: RULE_AGENT_CC.id,\n };\n}\n\nfunction buildApexResult(\n cls: ApexClassReport,\n m: ApexMethodCC,\n warn: number,\n err: number,\n): SarifResult {\n return {\n level: levelFor(m.complexity, warn, err),\n locations: [\n {\n physicalLocation: {\n artifactLocation: { uri: cls.path },\n // ANTLR token positions are 1-based for line, 0-based for column;\n // SARIF wants 1-based for both.\n region: regionFromAntlr(m.location),\n },\n },\n ],\n message: {\n text: `${m.kind} '${m.name}' has cyclomatic complexity ${m.complexity}.`,\n },\n properties: { complexity: m.complexity, kind: m.kind },\n ruleId: RULE_APEX_CC.id,\n };\n}\n\nfunction levelFor(cc: number, warn: number, err: number): SarifResult['level'] {\n if (cc >= err) return 'error';\n if (cc >= warn) return 'warning';\n return 'note';\n}\n\nfunction regionFromZeroBased(loc: ProcedureCC['location']) {\n return {\n endColumn: loc.endCol + 1,\n endLine: loc.endRow + 1,\n startColumn: loc.startCol + 1,\n startLine: loc.startRow + 1,\n };\n}\n\nfunction regionFromAntlr(loc: ProcedureCC['location']) {\n return {\n endColumn: loc.endCol + 1,\n endLine: Math.max(1, loc.endRow),\n startColumn: loc.startCol + 1,\n startLine: Math.max(1, loc.startRow),\n };\n}\n\nfunction pluginVersion(): string {\n // Avoid a JSON-file dep at runtime; this stays in sync with package.json\n // manually. Bumping the plugin should bump this string.\n return '0.1.1';\n}\n", "import pc from 'picocolors';\n\nimport type {\n AnalysisReport,\n ApexCCContributor,\n FileReport,\n ProcedureCC,\n} from '../analyzer/types.js';\nimport type { RenderOptions } from './options.js';\n\nconst KIND_LABEL: Record<ProcedureCC['kind'], string> = {\n after_reasoning: 'after_reasoning',\n available_when: 'available_when',\n before_reasoning: 'before_reasoning',\n other: 'other',\n reasoning_instructions: 'reasoning.instructions',\n};\n\ninterface Glyphs {\n agentFile: string;\n apexFile: string;\n ruleHeavy: string;\n ruleLight: string;\n}\n\nconst UNICODE_GLYPHS: Glyphs = {\n agentFile: '\uD83D\uDCC4',\n apexFile: '\uD83D\uDCDC',\n ruleHeavy: '\u2550',\n ruleLight: '\u2500',\n};\n\nconst ASCII_GLYPHS: Glyphs = {\n agentFile: '[agent]',\n apexFile: '[apex] ',\n ruleHeavy: '=',\n ruleLight: '-',\n};\n\ninterface ResolvedOptions {\n ascii: boolean;\n color: boolean;\n width: number;\n}\n\nfunction resolveOptions(opts: RenderOptions | undefined): ResolvedOptions {\n // Auto-detect: text + emoji unless explicitly disabled, color on TTY only\n // and respecting the well-known NO_COLOR env var.\n const stdoutIsTty = Boolean(process.stdout.isTTY);\n const noColorEnv = Boolean(process.env.NO_COLOR);\n return {\n ascii: opts?.ascii ?? !stdoutIsTty,\n color: opts?.color ?? (stdoutIsTty && !noColorEnv),\n width: opts?.width ?? 60,\n };\n}\n\nexport function renderText(report: AnalysisReport, opts?: RenderOptions): string {\n const r = resolveOptions(opts);\n const g = r.ascii ? ASCII_GLYPHS : UNICODE_GLYPHS;\n const c = colorize(r.color);\n const lines: string[] = [];\n\n lines.push(\n c.title('AgentForce PMD \u2014 Cyclomatic Complexity (McCabe)'),\n g.ruleHeavy.repeat(r.width),\n );\n\n if (report.files.length === 0) {\n lines.push(' (no .agent files found)');\n return lines.join('\\n');\n }\n\n for (const f of report.files) {\n lines.push(\n '',\n `${g.agentFile} ${c.path(f.path)} CC=${c.cc(f.fileComplexity)}`,\n g.ruleLight.repeat(r.width),\n );\n\n if (f.procedures.length === 0) {\n lines.push(' (no procedure-bearing scopes)');\n } else {\n const scopes = groupByScope(f.procedures);\n for (const [scope, procs] of scopes) {\n const scopeTotal = procs.reduce((a, p) => a + p.complexity, 0);\n lines.push(` ${c.scope(scope)} subtotal CC=${c.cc(scopeTotal)}`);\n for (const p of procs) {\n lines.push(\n ` ${pad(KIND_LABEL[p.kind], 24)} CC=${c.cc(p.complexity)} ` +\n c.breakdown(breakdownProc(p)),\n );\n }\n }\n }\n\n if (f.declarations.length > 0 || f.references.length > 0) {\n lines.push(\n '',\n ' Action references',\n ' ' + g.ruleLight.repeat(Math.max(0, r.width - 2)),\n );\n const usage = countReferences(f);\n for (const d of f.declarations) {\n const used = usage.get(d.name) ?? 0;\n const tgt = d.target ?? '(no target)';\n lines.push(\n ` ${pad(d.name, 32)} [${pad(d.targetKind, 6)}] used ${used}x \u2192 ${tgt}`,\n );\n }\n\n const undeclared = listUndeclaredRefs(f);\n if (undeclared.length > 0) {\n lines.push('', ' Referenced but not declared in-file:');\n for (const u of undeclared) {\n lines.push(` ${u}`);\n }\n }\n }\n }\n\n if (report.apexClasses.length > 0 || report.unresolvedApexTargets.length > 0) {\n lines.push(\n '',\n c.title('Apex backing logic (resolved via apex:// targets)'),\n g.ruleHeavy.repeat(r.width),\n );\n for (const cls of report.apexClasses) {\n lines.push(\n '',\n `${g.apexFile} ${c.path(cls.path)} class CC=${c.cc(cls.classComplexity)}`,\n ` referenced by: ${cls.referencedBy.join(', ') || '(none)'}`,\n g.ruleLight.repeat(r.width),\n );\n if (cls.methods.length === 0) {\n lines.push(' (no methods with bodies)');\n } else {\n for (const m of cls.methods) {\n lines.push(\n ` ${pad(m.signature, 44)} CC=${c.cc(m.complexity)} ${c.breakdown(breakdownApex(m.contributors))}`,\n );\n }\n }\n }\n\n if (report.unresolvedApexTargets.length > 0) {\n lines.push('', 'Unresolved apex:// targets:');\n for (const u of report.unresolvedApexTargets) {\n lines.push(\n ` - ${u} (no matching .cls under source-dir or --apex-source)`,\n );\n }\n }\n }\n\n lines.push(\n '',\n g.ruleHeavy.repeat(r.width),\n c.title('CC by location (whitepaper \u00A7 7)'),\n ` AgentScript: ${c.cc(report.totalComplexity)}` +\n ` Apex: ${c.cc(report.totalApexComplexity)}` +\n ` Combined: ${c.cc(report.totalComplexity + report.totalApexComplexity)}`,\n `Action declarations: ${report.totalDeclarations} ` +\n `(apex ${report.byTargetKind.apex}, flow ${report.byTargetKind.flow}, ` +\n `prompt ${report.byTargetKind.prompt}, unknown ${report.byTargetKind.unknown})`, `Action references: ${report.totalReferences}`\n \n );\n return lines.join('\\n');\n}\n\ninterface Colorizer {\n breakdown: (s: string) => string;\n cc: (n: number) => string;\n path: (s: string) => string;\n scope: (s: string) => string;\n title: (s: string) => string;\n}\n\nfunction colorize(on: boolean): Colorizer {\n if (!on) {\n return {\n breakdown: s => s,\n cc: String,\n path: s => s,\n scope: s => s,\n title: s => s,\n };\n }\n\n return {\n breakdown: pc.gray,\n cc(n: number) {\n // Palette echoes whitepaper temperature: cool for low, hot for high.\n const s = String(n);\n if (n >= 20) return pc.red(s);\n if (n >= 10) return pc.yellow(s);\n if (n >= 5) return pc.green(s);\n return pc.gray(s);\n },\n path: pc.cyan,\n scope: pc.bold,\n title: pc.bold,\n };\n}\n\nfunction breakdownProc(p: ProcedureCC): string {\n if (p.contributors.length === 0) return '(base only)';\n const counts: Record<string, number> = {};\n for (const c of p.contributors) counts[c.kind] = (counts[c.kind] ?? 0) + 1;\n return Object.entries(counts)\n .map(([k, n]) => `${shortKind(k)}=${n}`)\n .join(' ');\n}\n\nfunction breakdownApex(contributors: ApexCCContributor[]): string {\n if (contributors.length === 0) return '(base only)';\n const counts: Record<string, number> = {};\n for (const c of contributors) counts[c.kind] = (counts[c.kind] ?? 0) + 1;\n return Object.entries(counts)\n .map(([k, n]) => `${shortApexKind(k)}=${n}`)\n .join(' ');\n}\n\nfunction shortKind(k: string): string {\n switch (k) {\n case 'elif_clause': {\n return 'elif';\n }\n\n case 'if_statement': {\n return 'if';\n }\n\n case 'short_circuit_and': {\n return 'and';\n }\n\n case 'short_circuit_or': {\n return 'or';\n }\n\n case 'ternary_expression': {\n return 'ternary';\n }\n\n default: {\n return k;\n }\n }\n}\n\nfunction shortApexKind(k: string): string {\n switch (k) {\n case 'catch_clause': {\n return 'catch';\n }\n\n case 'do_while_statement': {\n return 'do-while';\n }\n\n case 'for_statement': {\n return 'for';\n }\n\n case 'if_statement': {\n return 'if';\n }\n\n case 'short_circuit_and': {\n return '&&';\n }\n\n case 'short_circuit_or': {\n return '||';\n }\n\n case 'ternary': {\n return 'ternary';\n }\n\n case 'when_arm': {\n return 'when';\n }\n\n case 'while_statement': {\n return 'while';\n }\n\n default: {\n return k;\n }\n }\n}\n\nfunction groupByScope(procs: ProcedureCC[]): Map<string, ProcedureCC[]> {\n const m = new Map<string, ProcedureCC[]>();\n for (const p of procs) {\n let arr = m.get(p.scope);\n if (!arr) {\n arr = [];\n m.set(p.scope, arr);\n }\n\n arr.push(p);\n }\n\n return m;\n}\n\nfunction pad(s: string, n: number): string {\n if (s.length >= n) return s;\n return s + ' '.repeat(n - s.length);\n}\n\nfunction countReferences(f: FileReport): Map<string, number> {\n const m = new Map<string, number>();\n for (const r of f.references) m.set(r.name, (m.get(r.name) ?? 0) + 1);\n return m;\n}\n\nfunction listUndeclaredRefs(f: FileReport): string[] {\n const declared = new Set(f.declarations.map(d => d.name));\n const seen = new Set<string>();\n const out: string[] = [];\n for (const r of f.references) {\n if (declared.has(r.name)) continue;\n if (seen.has(r.name)) continue;\n seen.add(r.name);\n out.push(r.name);\n }\n\n return out;\n}\n", "import type { AnalysisReport } from '../analyzer/types.js';\nimport type { RenderFormat, RenderOptions } from './options.js';\n\nimport { renderCsv } from './csv.js';\nimport { renderMarkdown } from './markdown.js';\nimport { renderSarif } from './sarif.js';\nimport { renderText } from './text.js';\n\nexport function render(\n format: RenderFormat,\n report: AnalysisReport,\n options?: RenderOptions,\n): string {\n switch (format) {\n case 'csv': {\n return renderCsv(report);\n }\n\n case 'markdown': {\n return renderMarkdown(report);\n }\n\n case 'sarif': {\n return renderSarif(report, options);\n }\n\n case 'text': {\n return renderText(report, options);\n }\n }\n}\n\nexport { renderCsv } from './csv.js';\nexport { renderMarkdown } from './markdown.js';\nexport type { RenderFormat, RenderOptions } from './options.js';\nexport { renderSarif } from './sarif.js';\nexport { renderText } from './text.js';\n"],
|
|
4
|
+
"sourcesContent": ["import { readdir , readFile, stat } from 'node:fs/promises';\nimport { basename, dirname, join, relative, resolve } from 'node:path';\n\nimport type {\n ActionDeclaration,\n ActionReference,\n ActionTargetKind,\n AnalysisReport,\n FileReport,\n} from './types.js';\n\nimport { collectDeclarations, collectReferences } from './action-references.js';\nimport { analyzeReferencedApex } from './apex-analyze.js';\nimport { collectScopes, complexityForFile } from './complexity.js';\nimport { extractDeveloperName, parseAgentSource } from './parse.js';\n\nexport interface AnalyzeOptions {\n /** Override location for apex:// resolution. Optional. */\n apexSourceOverride?: string;\n /**\n * Filter to specific agent bundles by API name. Each entry is matched\n * against (a) the bundle directory name and (b) `config.developer_name`\n * inside the .agent file. When omitted or empty, all discovered bundles\n * are analyzed.\n */\n apiNames?: string[];\n /**\n * Base directory for relative paths in the report. Defaults to the source\n * root (or, when multiple roots are supplied, the longest common ancestor).\n */\n reportBase?: string;\n}\n\n/**\n * Error thrown when --api-name filters produce no matches. Carries the\n * candidate list so callers can show a useful hint.\n */\nexport class NoMatchingBundlesError extends Error {\n constructor(\n public readonly requested: string[],\n public readonly available: BundleIdentity[],\n ) {\n super(\n `No agent bundle matched ${requested.map(n => `'${n}'`).join(', ')}. ` +\n `Available: ${available.map((b) => formatBundleIdentity(b)).join(', ')}`,\n );\n this.name = 'NoMatchingBundlesError';\n }\n}\n\nexport interface BundleIdentity {\n /** The config.developer_name value, if present. */\n developerName: string | undefined;\n /** The bundle's directory name (parent of the .agent file). */\n dirName: string;\n /** Absolute path of the .agent file. */\n path: string;\n}\n\nfunction formatBundleIdentity(b: BundleIdentity): string {\n if (b.developerName && b.developerName !== b.dirName) {\n return `${b.developerName} (dir: ${b.dirName})`;\n }\n\n return b.dirName;\n}\n\n/**\n * Analyze AgentScript bundles under one or more source roots.\n *\n * Backward-compatible: pass a single path (string) for the legacy\n * single-root case. Pass an array of paths for multi-root analysis\n * (e.g. multiple `packageDirectories` in an sfdx project).\n */\nexport async function analyzeSource(\n rootPathOrPaths: string | string[],\n options: AnalyzeOptions = {},\n): Promise<AnalysisReport> {\n const rawRoots = Array.isArray(rootPathOrPaths)\n ? rootPathOrPaths\n : [rootPathOrPaths];\n if (rawRoots.length === 0) {\n throw new Error('analyzeSource requires at least one source path');\n }\n\n const absRoots = rawRoots.map(p => resolve(p));\n const reportBase = options.reportBase\n ? resolve(options.reportBase)\n : absRoots.length === 1\n ? absRoots[0]\n : longestCommonAncestor(absRoots);\n\n const allFiles: string[] = [];\n for (const root of absRoots) {\n const files = await findAgentFiles(root);\n for (const f of files) if (!allFiles.includes(f)) allFiles.push(f);\n }\n\n allFiles.sort();\n\n const filteredFiles = await filterByApiNames(allFiles, options.apiNames);\n\n const fileReports: FileReport[] = [];\n for (const file of filteredFiles) {\n fileReports.push(await analyzeFile(file, reportBase));\n }\n\n const apex = await analyzeReferencedApex({\n agentAbsPaths: filteredFiles,\n apexSourceOverride: options.apexSourceOverride,\n fileReports,\n sourceDirRoot: reportBase,\n });\n\n const report: AnalysisReport = {\n apexClasses: apex.classes,\n byTargetKind: tallyTargets(fileReports),\n files: fileReports,\n totalApexComplexity: apex.classes.reduce((acc, c) => acc + c.classComplexity, 0),\n totalComplexity: fileReports.reduce((acc, f) => acc + f.fileComplexity, 0),\n totalDeclarations: fileReports.reduce((acc, f) => acc + f.declarations.length, 0),\n totalReferences: fileReports.reduce((acc, f) => acc + f.references.length, 0),\n unresolvedApexTargets: apex.unresolved,\n };\n return report;\n}\n\nexport async function analyzeFile(absPath: string, base: string): Promise<FileReport> {\n const source = await readFile(absPath, 'utf8');\n const root = parseAgentSource(source);\n\n const cc = complexityForFile(root);\n const {procedures} = cc;\n\n const scopes = collectScopes(root);\n const declarations: ActionDeclaration[] = [];\n const references: ActionReference[] = [];\n for (const s of scopes) {\n declarations.push(...collectDeclarations(s));\n references.push(...collectReferences(s));\n }\n\n return {\n declarations,\n fileComplexity: cc.total,\n parseErrors: [], // CST is error-tolerant; surface diagnostics in a later iteration.\n path: relative(base, absPath),\n procedures,\n references,\n };\n}\n\nasync function findAgentFiles(root: string): Promise<string[]> {\n const s = await stat(root).catch(() => {});\n if (!s) throw new Error(`source path does not exist: ${root}`);\n if (s.isFile()) return root.endsWith('.agent') ? [root] : [];\n\n const out: string[] = [];\n const visit = async (dir: string) => {\n const entries = await readdir(dir, { withFileTypes: true });\n for (const e of entries) {\n if (e.name.startsWith('.')) continue;\n if (e.name === 'node_modules' || e.name === 'vendor' || e.name === 'lib') continue;\n const full = join(dir, e.name);\n if (e.isDirectory()) await visit(full);\n else if (e.isFile() && e.name.endsWith('.agent')) out.push(full);\n }\n };\n\n await visit(root);\n out.sort();\n return out;\n}\n\nfunction tallyTargets(files: FileReport[]): Record<ActionTargetKind, number> {\n const acc: Record<ActionTargetKind, number> = {\n apex: 0,\n flow: 0,\n prompt: 0,\n unknown: 0,\n utils: 0,\n };\n for (const f of files) for (const d of f.declarations) acc[d.targetKind]++;\n return acc;\n}\n\n/**\n * Filter the discovered .agent file list by the supplied `--api-name`\n * values. A bundle matches if (a) its directory name equals a requested\n * name, or (b) its `config.developer_name` equals one. Bundles whose dir\n * name already matches are kept without parsing; only the remainder are\n * parsed for `developer_name` resolution.\n *\n * Throws NoMatchingBundlesError when filters were supplied but nothing\n * matched, so callers can show the available list.\n */\nasync function filterByApiNames(\n files: string[],\n apiNames: string[] | undefined,\n): Promise<string[]> {\n if (!apiNames || apiNames.length === 0) return files;\n const wanted = new Set(apiNames);\n\n const matches: string[] = [];\n const unmatched: string[] = [];\n for (const file of files) {\n const dirName = basename(dirname(file));\n if (wanted.has(dirName)) {\n matches.push(file);\n } else {\n unmatched.push(file);\n }\n }\n\n if (matches.length === files.length || unmatched.length === 0) {\n return matches;\n }\n\n // Slow path: parse the still-unmatched files to read developer_name.\n const identities: BundleIdentity[] = [];\n for (const file of unmatched) {\n const dirName = basename(dirname(file));\n const developerName = await readDeveloperName(file);\n identities.push({ developerName, dirName, path: file });\n if (developerName && wanted.has(developerName)) {\n matches.push(file);\n }\n }\n\n if (matches.length === 0) {\n // Build the full candidate list (matched dirs + parsed unmatched) for\n // the error message.\n const all: BundleIdentity[] = [];\n for (const file of files) {\n const existing = identities.find(i => i.path === file);\n if (existing) {\n all.push(existing);\n } else {\n all.push({\n developerName: await readDeveloperName(file),\n dirName: basename(dirname(file)),\n path: file,\n });\n }\n }\n\n all.sort((a, b) => a.dirName.localeCompare(b.dirName));\n throw new NoMatchingBundlesError(apiNames, all);\n }\n\n matches.sort();\n return matches;\n}\n\nasync function readDeveloperName(file: string): Promise<string | undefined> {\n const source = await readFile(file, 'utf8');\n const root = parseAgentSource(source);\n return extractDeveloperName(root);\n}\n\nfunction longestCommonAncestor(paths: string[]): string {\n if (paths.length === 0) return process.cwd();\n if (paths.length === 1) return paths[0];\n const split = paths.map(p => p.split('/'));\n const minLen = Math.min(...split.map(s => s.length));\n const common: string[] = [];\n for (let i = 0; i < minLen; i++) {\n const seg = split[0][i];\n if (split.every(s => s[i] === seg)) common.push(seg);\n else break;\n }\n\n const joined = common.join('/') || '/';\n return joined;\n}\n", "/*\n * Copyright (c) 2026, Salesforce, Inc.\n * All rights reserved.\n * SPDX-License-Identifier: Apache-2.0\n * For full license text, see the LICENSE file in the repo root or https://www.apache.org/licenses/LICENSE-2.0\n */\n/** Shared empty array for leaf nodes \u2014 avoids allocating [] per node. */\nconst EMPTY_CHILDREN = Object.freeze([]);\nexport class CSTNode {\n type;\n /** Whether this is a \"named\" node (true) or anonymous punctuation/keyword (false). */\n isNamed;\n isError;\n isMissing;\n startOffset;\n endOffset;\n // Flat position storage \u2014 avoids object allocations per node.\n // Also exposed as startPosition/endPosition getters for compat.\n startRow;\n startCol;\n endRow;\n endCol;\n /** Lazy children array \u2014 null for leaf nodes, allocated on first appendChild. */\n _children = null;\n parent = null;\n /** Index of this node within its parent's children array. -1 if no parent. */\n _childIndex = -1;\n /** Field name \u2192 child indices. Lazy: null until first field is added. */\n _fields = null;\n /** Reverse map: child index \u2192 field name. Built lazily. */\n _childFieldNames = null;\n /** Cached named children. */\n _namedChildren = null;\n /** The original source string, shared across all nodes in a tree. */\n _source;\n constructor(type, source, startOffset, endOffset, startPosition, endPosition, isNamed = true, isError = false, isMissing = false) {\n this.type = type;\n this._source = source;\n this.startOffset = startOffset;\n this.endOffset = endOffset;\n this.startRow = startPosition.row;\n this.startCol = startPosition.column;\n this.endRow = endPosition.row;\n this.endCol = endPosition.column;\n this.isNamed = isNamed;\n this.isError = isError;\n this.isMissing = isMissing;\n }\n get text() {\n return this._source.slice(this.startOffset, this.endOffset);\n }\n get startPosition() {\n return { row: this.startRow, column: this.startCol };\n }\n set startPosition(pos) {\n this.startRow = pos.row;\n this.startCol = pos.column;\n }\n get endPosition() {\n return { row: this.endRow, column: this.endCol };\n }\n set endPosition(pos) {\n this.endRow = pos.row;\n this.endCol = pos.column;\n }\n get children() {\n return (this._children ?? EMPTY_CHILDREN);\n }\n set children(value) {\n this._children = value;\n }\n get namedChildren() {\n if (!this._namedChildren) {\n this._namedChildren = this.children.filter(c => c.isNamed);\n }\n return this._namedChildren;\n }\n get previousSibling() {\n if (!this.parent || this._childIndex <= 0)\n return null;\n return this.parent.children[this._childIndex - 1];\n }\n get nextSibling() {\n if (!this.parent)\n return null;\n const siblings = this.parent.children;\n return this._childIndex < siblings.length - 1\n ? siblings[this._childIndex + 1]\n : null;\n }\n childForFieldName(name) {\n if (!this._fields)\n return null;\n const indices = this._fields.get(name);\n if (!indices || indices.length === 0)\n return null;\n return this.children[indices[0]] ?? null;\n }\n childrenForFieldName(name) {\n if (!this._fields)\n return [];\n const indices = this._fields.get(name);\n if (!indices)\n return [];\n return indices.map(i => this.children[i]).filter(Boolean);\n }\n /** True if this node or any descendant has an error or missing node. */\n get hasError() {\n if (this.isError || this.isMissing)\n return true;\n return this.children.some(c => c.hasError);\n }\n /** Get the field name for a child at a given index. */\n fieldNameForChild(index) {\n if (!this._fields)\n return null;\n if (!this._childFieldNames) {\n this._childFieldNames = new Map();\n for (const [fieldName, indices] of this._fields) {\n for (const idx of indices) {\n this._childFieldNames.set(idx, fieldName);\n }\n }\n }\n return this._childFieldNames.get(index) ?? null;\n }\n /** Add a child node, optionally associating it with a field name. */\n appendChild(child, fieldName) {\n if (!this._children)\n this._children = [];\n const idx = this._children.length;\n child.parent = this;\n child._childIndex = idx;\n this._children.push(child);\n // Track end position incrementally\n this.endRow = child.endRow;\n this.endCol = child.endCol;\n this.endOffset = child.endOffset;\n if (fieldName) {\n if (!this._fields)\n this._fields = new Map();\n let arr = this._fields.get(fieldName);\n if (!arr) {\n arr = [];\n this._fields.set(fieldName, arr);\n }\n arr.push(idx);\n }\n }\n /** @deprecated No-op: appendChild() tracks end position incrementally. */\n finalize() {\n // No-op \u2014 appendChild() updates endOffset/endPosition incrementally.\n }\n /** Serialize to s-expression format for testing (named nodes only, no text). */\n toSExp() {\n return nodeToSExp(this);\n }\n /**\n * Serialize to verbose s-expression format that includes ALL nodes\n * (both named and anonymous) with truncated text content.\n * Matches the source-of-truth format in sot/source.s-expression.\n */\n toVerboseSExp() {\n return nodeToVerboseSExp(this, 0);\n }\n}\n/** Create a leaf node (no children) from a token. */\nexport function leafNode(type, source, startOffset, endOffset, startPosition, endPosition, isNamed = true, isError = false, isMissing = false) {\n return new CSTNode(type, source, startOffset, endOffset, startPosition, endPosition, isNamed, isError, isMissing);\n}\n/**\n * Serialize a CST to s-expression format matching tree-sitter output.\n * Only named nodes appear; anonymous nodes (punctuation, keywords) are hidden.\n * Field names appear as `field: (node)`.\n */\nfunction nodeToSExp(node) {\n const parts = [];\n for (let i = 0; i < node.children.length; i++) {\n const child = node.children[i];\n if (!child.isNamed && !child.isError && !child.isMissing)\n continue; // Skip anonymous tokens\n const fieldName = node.fieldNameForChild(i);\n const childStr = child.children.length > 0 || child.isError\n ? nodeToSExp(child)\n : child.isMissing\n ? `(MISSING ${child.type})`\n : `(${child.type})`;\n if (fieldName) {\n parts.push(`${fieldName}: ${childStr}`);\n }\n else {\n parts.push(childStr);\n }\n }\n if (node.isError) {\n if (parts.length === 0) {\n return `(ERROR)`;\n }\n return `(ERROR ${parts.join(' ')})`;\n }\n if (node.isMissing) {\n return `(MISSING ${node.type})`;\n }\n if (parts.length === 0) {\n return `(${node.type})`;\n }\n return `(${node.type} ${parts.join(' ')})`;\n}\n/**\n * Verbose s-expression: includes ALL nodes (named + anonymous) with text.\n * Leaf text is truncated to 20 chars with `\u2026`.\n * Format: (type \"text\") for leaves, (type children...) for branches.\n */\nfunction nodeToVerboseSExp(node, depth) {\n const indent = ' '.repeat(depth);\n // MISSING nodes always render as (MISSING \"type\")\n if (node.isMissing) {\n return `${indent}(MISSING ${JSON.stringify(node.type)})`;\n }\n // ERROR nodes\n if (node.isError && node.children.length === 0) {\n return `${indent}(ERROR)`;\n }\n if (node.children.length === 0) {\n // Leaf node \u2014 show text\n const rawText = node.text;\n const truncated = rawText.length > 20 ? rawText.slice(0, 20) + '\u2026' : rawText;\n const escaped = JSON.stringify(truncated);\n return `${indent}(${node.type} ${escaped})`;\n }\n // Branch node \u2014 recurse\n const childLines = [];\n for (const child of node.children) {\n childLines.push(nodeToVerboseSExp(child, depth + 1));\n }\n return `${indent}(${node.type}\\n${childLines.join('\\n')})`;\n}\n//# sourceMappingURL=cst-node.js.map", "/*\n * Copyright (c) 2026, Salesforce, Inc.\n * All rights reserved.\n * SPDX-License-Identifier: Apache-2.0\n * For full license text, see the LICENSE file in the repo root or https://www.apache.org/licenses/LICENSE-2.0\n */\n/** Token kinds produced by the lexer. */\nexport var TokenKind;\n(function (TokenKind) {\n // Synthetic indentation tokens\n TokenKind[\"NEWLINE\"] = \"NEWLINE\";\n TokenKind[\"INDENT\"] = \"INDENT\";\n TokenKind[\"DEDENT\"] = \"DEDENT\";\n TokenKind[\"EOF\"] = \"EOF\";\n // Identifiers & literals\n TokenKind[\"ID\"] = \"ID\";\n TokenKind[\"NUMBER\"] = \"NUMBER\";\n TokenKind[\"STRING\"] = \"STRING\";\n TokenKind[\"STRING_CONTENT\"] = \"STRING_CONTENT\";\n TokenKind[\"ESCAPE_SEQUENCE\"] = \"ESCAPE_SEQUENCE\";\n TokenKind[\"DATETIME\"] = \"DATETIME\";\n TokenKind[\"TEMPLATE_CONTENT\"] = \"TEMPLATE_CONTENT\";\n // Operators\n TokenKind[\"PLUS\"] = \"PLUS\";\n TokenKind[\"MINUS\"] = \"MINUS\";\n TokenKind[\"STAR\"] = \"STAR\";\n TokenKind[\"SLASH\"] = \"SLASH\";\n TokenKind[\"DOT\"] = \"DOT\";\n TokenKind[\"COMMA\"] = \"COMMA\";\n TokenKind[\"COLON\"] = \"COLON\";\n TokenKind[\"EQ\"] = \"EQ\";\n TokenKind[\"EQEQ\"] = \"EQEQ\";\n TokenKind[\"NEQ\"] = \"NEQ\";\n TokenKind[\"LT\"] = \"LT\";\n TokenKind[\"GT\"] = \"GT\";\n TokenKind[\"LTE\"] = \"LTE\";\n TokenKind[\"GTE\"] = \"GTE\";\n TokenKind[\"ARROW\"] = \"ARROW\";\n TokenKind[\"ELLIPSIS\"] = \"ELLIPSIS\";\n TokenKind[\"PERCENT\"] = \"PERCENT\";\n TokenKind[\"PIPE\"] = \"PIPE\";\n TokenKind[\"AT\"] = \"AT\";\n // Delimiters\n TokenKind[\"LPAREN\"] = \"LPAREN\";\n TokenKind[\"RPAREN\"] = \"RPAREN\";\n TokenKind[\"LBRACKET\"] = \"LBRACKET\";\n TokenKind[\"RBRACKET\"] = \"RBRACKET\";\n TokenKind[\"LBRACE\"] = \"LBRACE\";\n TokenKind[\"RBRACE\"] = \"RBRACE\";\n TokenKind[\"TEMPLATE_EXPR_START\"] = \"TEMPLATE_EXPR_START\";\n // Sequence\n TokenKind[\"DASH_SPACE\"] = \"DASH_SPACE\";\n // Quote characters (for CST fidelity)\n TokenKind[\"DQUOTE\"] = \"DQUOTE\";\n // Special\n TokenKind[\"COMMENT\"] = \"COMMENT\";\n TokenKind[\"ERROR_TOKEN\"] = \"ERROR_TOKEN\";\n})(TokenKind || (TokenKind = {}));\nexport function isTokenKind(token, kind) {\n return token.kind === kind;\n}\n//# sourceMappingURL=token.js.map", "var isProduction = process.env.NODE_ENV === 'production';\nvar prefix = 'Invariant failed';\nfunction invariant(condition, message) {\n if (condition) {\n return;\n }\n if (isProduction) {\n throw new Error(prefix);\n }\n var provided = typeof message === 'function' ? message() : message;\n var value = provided ? \"\".concat(prefix, \": \").concat(provided) : prefix;\n throw new Error(value);\n}\n\nexport { invariant as default };\n", "/*\n * Copyright (c) 2026, Salesforce, Inc.\n * All rights reserved.\n * SPDX-License-Identifier: Apache-2.0\n * For full license text, see the LICENSE file in the repo root or https://www.apache.org/licenses/LICENSE-2.0\n */\n/**\n * Indentation-aware lexer for AgentScript.\n *\n * Produces a flat Token[] array including synthetic INDENT, DEDENT, and NEWLINE\n * tokens. Keywords are emitted as ID \u2014 the parser checks token text.\n *\n * Indentation: space = 1 unit, tab = 3 units (matching scanner.c).\n */\nimport invariant from 'tiny-invariant';\nimport { TokenKind } from './token.js';\n// ---------------------------------------------------------------------------\n// Character classification via charCode (replaces regex hot-path checks)\n// ---------------------------------------------------------------------------\nconst CH_TAB = 9; // \\t\nconst CH_LF = 10; // \\n\nconst CH_CR = 13; // \\r\nconst CH_SPACE = 32;\nconst CH_BANG = 33; // !\nconst CH_DQUOTE = 34; // \"\nconst CH_HASH = 35; // #\nconst CH_DASH = 45; // -\nconst CH_DOT = 46; // .\nconst CH_0 = 48;\nconst CH_9 = 57;\nconst CH_LT = 60; // <\nconst CH_EQ = 61; // =\nconst CH_GT = 62; // >\nconst CH_A = 65;\nconst CH_Z = 90;\nconst CH_BACKSLASH = 92; // \\\nconst CH_UNDERSCORE = 95; // _\nconst CH_a = 97;\nconst CH_z = 122;\nconst CH_LBRACE = 123; // {\nconst CH_NUL = 0;\nfunction isIdStart(c) {\n return ((c >= CH_A && c <= CH_Z) || (c >= CH_a && c <= CH_z) || c === CH_UNDERSCORE);\n}\nfunction isIdCont(c) {\n return isIdStart(c) || (c >= CH_0 && c <= CH_9);\n}\nfunction isDigit(c) {\n return c >= CH_0 && c <= CH_9;\n}\nfunction isHorizontalWs(c) {\n return c === CH_SPACE || c === CH_TAB;\n}\n// ---------------------------------------------------------------------------\n// charCode-indexed single-char token lookup (replaces Record<string, TokenKind>)\n// ---------------------------------------------------------------------------\nconst SINGLE_CHAR_TOKENS = new Array(128).fill(0);\nSINGLE_CHAR_TOKENS[43] = TokenKind.PLUS; // +\nSINGLE_CHAR_TOKENS[CH_DASH] = TokenKind.MINUS; // -\nSINGLE_CHAR_TOKENS[42] = TokenKind.STAR; // *\nSINGLE_CHAR_TOKENS[47] = TokenKind.SLASH; // /\n// % is not a valid operator in AgentScript (tree-sitter parity)\nSINGLE_CHAR_TOKENS[CH_DOT] = TokenKind.DOT; // .\nSINGLE_CHAR_TOKENS[44] = TokenKind.COMMA; // ,\nSINGLE_CHAR_TOKENS[58] = TokenKind.COLON; // :\nSINGLE_CHAR_TOKENS[61] = TokenKind.EQ; // =\nSINGLE_CHAR_TOKENS[60] = TokenKind.LT; // <\nSINGLE_CHAR_TOKENS[CH_GT] = TokenKind.GT; // >\nSINGLE_CHAR_TOKENS[124] = TokenKind.PIPE; // |\nSINGLE_CHAR_TOKENS[64] = TokenKind.AT; // @\nSINGLE_CHAR_TOKENS[40] = TokenKind.LPAREN; // (\nSINGLE_CHAR_TOKENS[41] = TokenKind.RPAREN; // )\nSINGLE_CHAR_TOKENS[91] = TokenKind.LBRACKET; // [\nSINGLE_CHAR_TOKENS[93] = TokenKind.RBRACKET; // ]\nSINGLE_CHAR_TOKENS[CH_LBRACE] = TokenKind.LBRACE; // {\nSINGLE_CHAR_TOKENS[125] = TokenKind.RBRACE; // }\nexport class Lexer {\n source;\n offset = 0;\n row = 0;\n col = 0;\n tokens = [];\n indentStack = [0];\n /** True when the current line started with `|` (template line). */\n onTemplateLine = false;\n /** Indent level of the line containing `|`. Content deeper than this is template content. */\n templateBaseIndent = -1;\n /** Nested brace depth inside a template expression (for `{` inside `{!...}`). -1 means not inside a template expression. */\n templateExprBraceDepth = -1;\n get inTemplateExpr() {\n return this.templateExprBraceDepth >= 0;\n }\n /** Parenthesis depth \u2014 suppresses INDENT/DEDENT/NEWLINE when > 0 to support multi-line call expressions. */\n bracketDepth = 0;\n constructor(source) {\n this.source = source;\n }\n tokenize() {\n // Pre-allocate token array backing store for large inputs\n this.tokens = [];\n const estimate = (this.source.length / 8) | 0;\n if (estimate > 64) {\n this.tokens.length = estimate;\n this.tokens.length = 0;\n }\n this.offset = 0;\n this.row = 0;\n this.col = 0;\n this.indentStack = [0];\n this.bracketDepth = 0;\n while (this.hasMore) {\n this.tokenizeLine();\n }\n // Emit remaining DEDENTs\n while (this.indentStack.length > 1) {\n this.indentStack.pop();\n this.emitVirtual(TokenKind.DEDENT);\n }\n this.emitVirtual(TokenKind.EOF);\n return this.tokens;\n }\n tokenizeLine() {\n // Note: onTemplateLine persists across continuation lines and is only\n // reset when indentation decreases (DEDENT) in emitIndentation().\n // Measure leading indentation\n const indentLength = this.consumeIndentation();\n if (this.consumeNewline()) {\n return;\n }\n const c = this.peekCharCode();\n // Comment-only line: tree-sitter's scanner skips past comment-only lines\n // when deciding INDENT/DEDENT. If this comment is at deeper indent than\n // current but no real content follows at that depth, emit NEWLINE instead.\n // Similarly, if a comment is at shallower indent but the next real content\n // is back at the current block's depth, suppress the DEDENT.\n // When on a template line, only treat `#` as a comment if it's at or below\n // the template's base indent (outside the template content area).\n if (c === CH_HASH &&\n (!this.onTemplateLine || indentLength <= this.templateBaseIndent)) {\n const currentIndent = this.indentStack[this.indentStack.length - 1];\n if (indentLength > currentIndent) {\n const nextContentIndent = this.peekNextContentIndent();\n if (nextContentIndent < indentLength) {\n // No real content at this depth \u2014 suppress INDENT\n this.emitIndentation(currentIndent);\n return this.tokenizeComment();\n }\n }\n else if (indentLength < currentIndent) {\n const nextContentIndent = this.peekNextContentIndent();\n if (nextContentIndent > indentLength) {\n // Next real content is at a deeper indent than the comment.\n // Emit indentation based on where the next content is, not\n // where the comment sits, so we only close the blocks that\n // actually end (not the ones the comment just happens to be\n // outside of).\n this.emitIndentation(nextContentIndent);\n return this.tokenizeComment();\n }\n }\n else {\n // Comment at same indent as current block. If next real content\n // is deeper (i.e. the comment sits between a key and its indented\n // body), suppress NEWLINE so the body's INDENT fires on the next\n // iteration. Example:\n // a:\n // # comment \u2190 same indent as current block\n // body: \"x\" \u2190 should INDENT into a's body\n const nextContentIndent = this.peekNextContentIndent();\n if (nextContentIndent > indentLength) {\n return this.tokenizeComment();\n }\n }\n this.emitIndentation(indentLength);\n return this.tokenizeComment();\n }\n // Normal line \u2014 emit indentation tokens.\n // Template continuation lines (deeper than templateBaseIndent) should\n // not cause INDENT/DEDENT when their indent varies relative to other\n // template lines. The initial INDENT into the template block is needed\n // (it establishes the template_content grammar rule), but subsequent\n // indent variation within the template corrupts the indent stack and\n // breaks downstream blocks. Detect \"already inside template block\" by\n // checking if the indent stack top is already deeper than templateBaseIndent.\n const currentIndent = this.indentStack[this.indentStack.length - 1];\n if (this.onTemplateLine &&\n indentLength > this.templateBaseIndent &&\n currentIndent > this.templateBaseIndent &&\n indentLength !== currentIndent) {\n this.emitIndentation(currentIndent);\n }\n else {\n this.emitIndentation(indentLength);\n }\n // Check for \"- \" sequence element at start of content\n if (this.bracketDepth === 0 && c === CH_DASH) {\n const nc = this.peekCharCode(1); // NaN at EOF \u2014 won't match any CH_*\n const atEOF = this.offset + 1 >= this.source.length;\n if (nc === CH_SPACE || this.atNewline(1) || atEOF) {\n this.emit(TokenKind.DASH_SPACE, nc === CH_SPACE ? '- ' : '-');\n }\n }\n // Tokenize the rest of the line\n while (this.hasMore) {\n const c = this.peekCharCode();\n // Newline ends the line\n if (this.consumeNewline()) {\n return;\n }\n if (c === CH_CR) {\n // Not followed with line feed (otherwise this.consumeLine() would be true)\n invariant(!this.atNewline());\n this.advance();\n continue;\n }\n // Skip horizontal whitespace\n if (isHorizontalWs(c)) {\n this.advance();\n continue;\n }\n // Line continuation\n if (c === CH_BACKSLASH) {\n if (this.atNewline(1)) {\n this.advance(); // skip backslash\n invariant(this.consumeNewline());\n // Skip leading whitespace on continuation line\n while (isHorizontalWs(this.peekCharCode())) {\n this.advance();\n }\n continue;\n }\n }\n // Comment (but not on template content lines where # is literal text)\n if (c === CH_HASH && !this.onTemplateLine) {\n return this.tokenizeComment();\n }\n this.tokenizeToken();\n }\n }\n emitIndentation(indentLength) {\n if (this.bracketDepth > 0)\n return;\n const currentIndent = this.indentStack[this.indentStack.length - 1];\n if (indentLength > currentIndent) {\n this.indentStack.push(indentLength);\n this.emitVirtual(TokenKind.INDENT);\n }\n else if (indentLength < currentIndent) {\n // Emit DEDENTs and a NEWLINE; leave template context only when\n // indentation drops to or below the template's base indent level.\n if (indentLength <= this.templateBaseIndent) {\n this.onTemplateLine = false;\n this.templateExprBraceDepth = -1;\n }\n while (this.indentStack.length > 1 &&\n this.indentStack[this.indentStack.length - 1] > indentLength) {\n this.indentStack.pop();\n this.emitVirtual(TokenKind.DEDENT);\n }\n this.emitVirtual(TokenKind.NEWLINE);\n }\n else {\n // Same indent \u2014 emit NEWLINE (line separator) unless we're at the start.\n // Leave template context only when at or below the template's base indent.\n if (indentLength <= this.templateBaseIndent) {\n this.onTemplateLine = false;\n this.templateExprBraceDepth = -1;\n }\n if (this.tokens.length > 0) {\n this.emitVirtual(TokenKind.NEWLINE);\n }\n }\n }\n tokenizeToken() {\n const c = this.peekCharCode();\n // Datetimes or numbers\n if (isDigit(c)) {\n // Datetime literal: YYYY-MM-DD...\n // Must check before numbers since datetimes start with digits\n if (this.tryDatetime()) {\n return;\n }\n this.tokenizeNumber();\n return;\n }\n // Identifier\n if (isIdStart(c)) {\n this.tokenizeId();\n return;\n }\n // String (double-quoted always, single-quoted only if not a contraction)\n // Inside template lines (after |), quotes are literal characters \u2014 don't\n // start string tokenization unless we're inside a {!...} expression.\n if (!this.onTemplateLine || this.inTemplateExpr) {\n if (c === CH_DQUOTE) {\n this.tokenizeString();\n return;\n }\n }\n // Template expression start {!\n if (c === CH_LBRACE && this.peekCharCode(1) === CH_BANG) {\n this.templateExprBraceDepth = 0;\n this.emit(TokenKind.TEMPLATE_EXPR_START, '{!');\n return;\n }\n // Tokens beginning with .\n if (c === CH_DOT) {\n if (this.peekCharCode(1) === CH_DOT && this.peekCharCode(2) === CH_DOT) {\n this.emit(TokenKind.ELLIPSIS, '...');\n return;\n }\n // Leading-dot number (e.g., .5, .123) \u2014 but not after identifiers\n // (which would be member access like @variable.5)\n if (isDigit(this.peekCharCode(1))) {\n const prev = this.tokens[this.tokens.length - 1];\n const isMemberAccess = prev !== undefined &&\n (prev.kind === TokenKind.ID ||\n prev.kind === TokenKind.NUMBER ||\n prev.kind === TokenKind.RPAREN ||\n prev.kind === TokenKind.RBRACKET);\n if (!isMemberAccess) {\n this.tokenizeNumber();\n return;\n }\n }\n }\n if (c === CH_DASH) {\n if (this.peekCharCode(1) === CH_GT) {\n return this.emit(TokenKind.ARROW, '->');\n }\n }\n // == != <= >=\n const nc = this.peekCharCode(1);\n if (nc === CH_EQ) {\n // next is '='\n if (c === CH_EQ) {\n return this.emit(TokenKind.EQEQ, '==');\n }\n if (c === CH_BANG) {\n return this.emit(TokenKind.NEQ, '!=');\n }\n if (c === CH_LT) {\n return this.emit(TokenKind.LTE, '<=');\n }\n if (c === CH_GT) {\n return this.emit(TokenKind.GTE, '>=');\n }\n }\n // Single-char tokens (charCode-indexed lookup)\n const kind = c < 128 ? SINGLE_CHAR_TOKENS[c] : 0;\n if (kind) {\n this.emitSpan(kind, 1);\n switch (kind) {\n // Track template lines: `|` starts a template context for this line\n // and continuation lines indented deeper than this level.\n case TokenKind.PIPE:\n this.onTemplateLine = true;\n this.templateBaseIndent =\n this.indentStack[this.indentStack.length - 1];\n break;\n // Track parenthesis depth to suppress structural tokens inside\n // multi-line call expressions. Skip when inside a template line \u2014\n // parens in template content are literal text and must not suppress\n // INDENT/DEDENT emission (unmatched parens would eat the rest of\n // the file).\n case TokenKind.LPAREN:\n if (!this.onTemplateLine)\n this.bracketDepth++;\n break;\n case TokenKind.RPAREN:\n if (!this.onTemplateLine)\n this.bracketDepth--;\n break;\n // Track brace depth inside {!...} template expressions so that nested\n // braces (e.g. JSON objects) don't prematurely close the expression.\n case TokenKind.LBRACE:\n if (this.inTemplateExpr) {\n this.templateExprBraceDepth++;\n }\n break;\n case TokenKind.RBRACE:\n if (this.inTemplateExpr) {\n this.templateExprBraceDepth--;\n }\n break;\n }\n return;\n }\n // Unknown character \u2014 emit error token\n this.emitSpan(TokenKind.ERROR_TOKEN, 1);\n }\n tokenizeId() {\n let i = 0;\n for (;; i++) {\n const c = this.peekCharCode(i);\n if (!isIdCont(c))\n break;\n }\n this.emitSpan(TokenKind.ID, i);\n }\n tokenizeNumber() {\n let tokenLength = 0;\n // Leading dot (e.g., .5) \u2014 consume the `.` first\n const leadingDot = this.peekCharCode(tokenLength) === CH_DOT;\n if (leadingDot) {\n tokenLength++;\n }\n // Integer part \u2014 inline advance (digits never contain newlines)\n while (isDigit(this.peekCharCode(tokenLength))) {\n tokenLength++;\n }\n // Decimal part \u2014 only consume `.` if followed by a digit (and no leading dot)\n if (!leadingDot && this.peekCharCode(tokenLength) === CH_DOT) {\n tokenLength++;\n }\n while (isDigit(this.peekCharCode(tokenLength))) {\n tokenLength++;\n }\n this.emitSpan(TokenKind.NUMBER, tokenLength);\n }\n tryDatetime() {\n // ISO 8601: YYYY-MM-DD optionally followed by time\n // Need at least YYYY-MM-DD = 10 chars\n const remaining = this.source.length - this.offset;\n if (remaining < 10)\n return false;\n // Fast reject: most numbers aren't datetimes. Check the fixed '-' positions\n // before allocating a slice or running the regex.\n if (this.source.charCodeAt(this.offset + 4) !== CH_DASH ||\n this.source.charCodeAt(this.offset + 7) !== CH_DASH) {\n return false;\n }\n const slice = this.source.slice(this.offset, this.offset + 30);\n const match = slice.match(/^\\d{4}-\\d{2}-\\d{2}(T\\d{1,2}(:\\d{2})?(:\\d{2})?(\\.\\d+)?Z?)?/);\n if (!match)\n return false;\n // Only treat as datetime if it has the full YYYY-MM-DD pattern\n // and the character after isn't an identifier character\n const matchText = match[0];\n if (matchText.length < 10)\n return false; // Must have at least YYYY-MM-DD\n this.emit(TokenKind.DATETIME, matchText);\n return true;\n }\n tokenizeString() {\n const start = this.position;\n const startOffset = this.offset;\n const quoteCode = this.peekCharCode(); // \" or '\n // Opening quote\n this.advance();\n while (this.hasMore) {\n const c = this.peekCharCode();\n if (c === quoteCode) {\n this.advance(); // closing quote\n const text = this.source.slice(startOffset, this.offset);\n this.tokens.push(this.makeToken(TokenKind.STRING, text, start, this.position, startOffset));\n return;\n }\n if (c === CH_BACKSLASH) {\n this.advance(2);\n continue;\n }\n if (this.atNewline()) {\n // Unclosed string \u2014 stop at newline for error recovery\n break;\n }\n if (c === CH_CR) {\n // Bare \\r inside string \u2014 treat as content\n invariant(!this.atNewline());\n this.advance();\n continue;\n }\n if (c === CH_NUL) {\n // Null byte \u2014 tree-sitter rejects these in string content\n break;\n }\n this.advance();\n }\n // Unclosed string\n const text = this.source.slice(startOffset, this.offset);\n this.tokens.push(this.makeToken(TokenKind.STRING, text, start, this.position, startOffset));\n }\n tokenizeComment() {\n const start = this.position;\n const startOffset = this.offset;\n // Consume # and everything until end of line or EOF\n while (this.hasMore && !this.atNewline()) {\n this.advance();\n }\n const text = this.source.slice(startOffset, this.offset);\n this.tokens.push(this.makeToken(TokenKind.COMMENT, text, start, this.position, startOffset));\n this.consumeNewline();\n }\n consumeIndentation() {\n let indentLength = 0;\n while (this.hasMore) {\n const c = this.peekCharCode();\n if (c === CH_SPACE) {\n indentLength += 1;\n this.advance();\n }\n else if (c === CH_TAB) {\n indentLength += 3;\n this.advance();\n }\n else if (c === CH_CR) {\n // Bare \\r (not followed by \\n) resets indent to 0,\n // matching tree-sitter scanner.c behavior (line 140-142)\n indentLength = 0;\n this.advance();\n }\n else {\n break;\n }\n }\n return indentLength;\n }\n /**\n * Scan ahead (without advancing) past comment/blank lines to find the indent\n * of the next line with real (non-comment) content. Returns -1 if only\n * comments, blanks, or EOF remain. Matches tree-sitter scanner behavior which\n * skips past comment-only lines when computing INDENT/DEDENT.\n */\n peekNextContentIndent() {\n const startPosition = this.position;\n const startOffset = this.offset;\n // Skip past the current comment line\n while (this.hasMore) {\n if (this.consumeNewline())\n break;\n this.advance();\n }\n // Scan subsequent lines\n while (this.hasMore) {\n // Measure indent\n const lineIndent = this.consumeIndentation();\n // Blank line \u2014 skip\n if (this.consumeNewline())\n continue;\n // Comment line \u2014 skip\n const c = this.peekCharCode();\n if (c === CH_HASH) {\n while (this.hasMore) {\n if (this.consumeNewline())\n break;\n this.advance();\n }\n continue;\n }\n this.offset = startOffset;\n this.row = startPosition.row;\n this.col = startPosition.column;\n // Real content \u2014 return its indent\n return lineIndent;\n }\n this.offset = startOffset;\n this.row = startPosition.row;\n this.col = startPosition.column;\n return -1;\n }\n // --- Utility methods ---\n peekCharCode(additiveOffset = 0) {\n return this.source.charCodeAt(this.offset + additiveOffset);\n }\n get hasMore() {\n return this.offset < this.source.length && this.offset >= 0;\n }\n /**\n * Attempt to advance n characters.\n * @returns how many characters were advanced.\n */\n advance(n = 1) {\n n = Math.max(0, Math.min(n, this.source.length - this.offset));\n this.col += n;\n for (let i = 0; i < n; i++) {\n if (this.peekCharCode(i) === CH_LF) {\n this.row++;\n this.col = n - i - 1;\n }\n }\n this.offset += n;\n return n;\n }\n /**\n * Attempt to consume a newline.\n * @returns whether a newline was consumed.\n */\n consumeNewline() {\n const newChars = this.atNewline();\n if (newChars > 0) {\n invariant(this.advance(newChars));\n return true;\n }\n return false;\n }\n /**\n * Checks if the current position is at a newline.\n * @param additiveOffset\n * @returns 0 if not at a newline, 1 if at an LF newline, 2 if at a CR LF newline.\n */\n atNewline(additiveOffset = 0) {\n const firstChar = this.peekCharCode(additiveOffset);\n if (firstChar === CH_LF)\n return 1;\n if (firstChar === CH_CR && this.peekCharCode(additiveOffset + 1) === CH_LF)\n return 2;\n return 0;\n }\n get position() {\n return { row: this.row, column: this.col };\n }\n emitSpan(kind, length) {\n const text = this.source.slice(this.offset, this.offset + length);\n return this.emit(kind, text);\n }\n emit(kind, text) {\n const startPosition = this.position;\n const startOffset = this.offset;\n invariant(text === this.source.slice(startOffset, startOffset + text.length), `expected '${text}' but got ${this.source.slice(startOffset, startOffset + text.length)} at offset ${startOffset}`);\n this.advance(text.length);\n this.tokens.push(this.makeToken(kind, text, startPosition, this.position, startOffset));\n }\n emitVirtual(kind) {\n return this.emit(kind, '');\n }\n makeToken(kind, text, start, end, startOffset) {\n return { kind, text, start, end, startOffset };\n }\n}\n//# sourceMappingURL=lexer.js.map", "/*\n * Copyright (c) 2026, Salesforce, Inc.\n * All rights reserved.\n * SPDX-License-Identifier: Apache-2.0\n * For full license text, see the LICENSE file in the repo root or https://www.apache.org/licenses/LICENSE-2.0\n */\n/**\n * Error recovery utilities for the parser.\n *\n * Core invariant: NEWLINE and DEDENT are unconditional synchronization points.\n * No error ever cascades past them.\n */\nimport { TokenKind } from './token.js';\nimport { CSTNode } from './cst-node.js';\n/**\n * Create an ERROR node wrapping the given children.\n */\nexport function makeErrorNode(source, children, startOffset, endOffset, startPosition, endPosition) {\n const node = new CSTNode('ERROR', source, startOffset, endOffset, startPosition, endPosition, true, true);\n for (const child of children) {\n node.appendChild(child);\n }\n return node;\n}\n/**\n * Create a MISSING node \u2014 a node that was expected but not present in the source.\n */\nexport function makeMissingNode(type, source, position, offset) {\n return new CSTNode(type, source, offset, offset, position, position, true, false, true);\n}\n/**\n * Create a leaf node from a token.\n */\nexport function tokenToLeaf(token, source, isNamed, offset) {\n return new CSTNode(tokenTypeToNodeType(token), source, offset, offset + token.text.length, token.start, token.end, isNamed);\n}\n/** Named token kinds \u2014 tokens that become named CST children. */\nconst NAMED_TOKEN_KINDS = new Set([\n TokenKind.ID,\n TokenKind.NUMBER,\n TokenKind.STRING,\n TokenKind.DATETIME,\n TokenKind.COMMENT,\n TokenKind.ELLIPSIS,\n]);\n/** Create a leaf CST node from a token, auto-determining isNamed from its kind. */\nexport function tokenToAutoLeaf(token, source, offset) {\n return tokenToLeaf(token, source, NAMED_TOKEN_KINDS.has(token.kind), offset);\n}\nfunction tokenTypeToNodeType(token) {\n switch (token.kind) {\n case TokenKind.ID:\n return 'id';\n case TokenKind.NUMBER:\n return 'number';\n case TokenKind.STRING:\n return 'string';\n case TokenKind.DATETIME:\n return 'datetime_literal';\n case TokenKind.COMMENT:\n return 'comment';\n case TokenKind.ELLIPSIS:\n return 'ellipsis';\n default:\n return token.text;\n }\n}\n/** Check if a token kind is a synchronization point. */\nexport function isSyncPoint(kind) {\n return (kind === TokenKind.NEWLINE ||\n kind === TokenKind.DEDENT ||\n kind === TokenKind.EOF);\n}\n//# sourceMappingURL=errors.js.map", "/*\n * Copyright (c) 2026, Salesforce, Inc.\n * All rights reserved.\n * SPDX-License-Identifier: Apache-2.0\n * For full license text, see the LICENSE file in the repo root or https://www.apache.org/licenses/LICENSE-2.0\n */\n/**\n * Recovery and utility functions extracted from parser.ts.\n *\n * All functions take a ParserContext as their first argument,\n * following the free-function pattern established by expressions.ts.\n */\nimport { TokenKind } from './token.js';\nimport { CSTNode } from './cst-node.js';\nimport { makeErrorNode, tokenToAutoLeaf } from './errors.js';\n// --- Error recovery ---\n/** Create an empty ERROR node at the current position. */\nexport function makeEmptyError(ctx) {\n const offset = ctx.peekOffset();\n const pos = ctx.peek().start;\n return new CSTNode('ERROR', ctx.source, offset, offset, pos, pos, true, true);\n}\n/** Insert a missing target: `target: (expression (atom (ERROR)))` */\nexport function addMissingTarget(ctx, node) {\n const errAtom = makeEmptyError(ctx);\n const atom = new CSTNode('atom', ctx.source, errAtom.startOffset, errAtom.endOffset, errAtom.startPosition, errAtom.endPosition);\n atom.appendChild(errAtom);\n const expr = new CSTNode('expression', ctx.source, atom.startOffset, atom.endOffset, atom.startPosition, atom.endPosition);\n expr.appendChild(atom);\n node.appendChild(expr, 'target');\n}\n/** Create a MISSING node \u2014 an expected token/node that wasn't found in source. */\nexport function makeMissing(ctx, type) {\n const offset = ctx.peekOffset();\n const pos = ctx.peek().start;\n return new CSTNode(type, ctx.source, offset, offset, pos, pos, true, false, true);\n}\n/**\n * Parse a standalone else/elif/for (without a preceding if, or unsupported).\n * Wraps the entire block in an ERROR node, preserving parsed statements inside.\n *\n * @param parseProcedure - callback to parse procedure bodies, avoiding circular\n * dependency with parse-statements.ts\n */\nexport function parseOrphanBlock(ctx, parseProcedure) {\n const startOffset = ctx.peekOffset();\n const startPos = ctx.peek().start;\n const children = [];\n // Consume keyword and any tokens up to colon/newline.\n // Capture consumed tokens as children of the ERROR for dialect recovery.\n const keywordTok = ctx.consume();\n const kwOffset = ctx.currentOffset();\n children.push(new CSTNode(keywordTok.text, ctx.source, kwOffset, kwOffset + keywordTok.text.length, keywordTok.start, keywordTok.end, false));\n while (!ctx.isAtSyncPoint() &&\n !isAtEnd(ctx) &&\n ctx.peekKind() !== TokenKind.COLON) {\n ctx.consume(); // consume but don't add as named children \u2014 they're noise\n }\n // Consume colon if present\n if (ctx.peekKind() === TokenKind.COLON)\n ctx.consume();\n // Consume the body block\n if (ctx.peekKind() === TokenKind.INDENT) {\n ctx.consume();\n const proc = parseProcedure(ctx);\n if (proc) {\n for (const child of proc.namedChildren) {\n children.push(child);\n }\n }\n // Consume trailing comments left by parseProcedure's isTrailingCommentOnly guard\n while (ctx.peekKind() === TokenKind.COMMENT ||\n ctx.peekKind() === TokenKind.NEWLINE) {\n if (ctx.peekKind() === TokenKind.COMMENT) {\n children.push(ctx.consumeNamed('comment'));\n }\n else {\n ctx.consume();\n }\n }\n if (ctx.peekKind() === TokenKind.DEDENT)\n ctx.consume();\n }\n if (ctx.peekKind() === TokenKind.NEWLINE)\n ctx.consume();\n const endOffset = children.length > 0\n ? children[children.length - 1].endOffset\n : ctx.peekOffset();\n const endPos = children.length > 0\n ? children[children.length - 1].endPosition\n : ctx.peek().start;\n return makeErrorNode(ctx.source, children, startOffset, endOffset, startPos, endPos);\n}\n/**\n * Consume any leftover tokens in an indented block (before DEDENT) as ERROR\n * nodes. Prevents cascading failures when parseBlockValue() only partially\n * consumes the block content (e.g., unquoted multi-word text).\n */\nexport function recoverToBlockEnd(ctx, parent) {\n while (!isAtEnd(ctx) && ctx.peekKind() !== TokenKind.DEDENT) {\n if (ctx.peekKind() === TokenKind.NEWLINE) {\n ctx.consume();\n continue;\n }\n // Skip over nested indented blocks within the error zone\n if (ctx.peekKind() === TokenKind.INDENT) {\n ctx.consume();\n recoverToBlockEnd(ctx, parent);\n if (ctx.peekKind() === TokenKind.DEDENT)\n ctx.consume();\n continue;\n }\n const err = synchronize(ctx);\n if (err) {\n parent.appendChild(err);\n }\n else {\n break;\n }\n }\n}\n/**\n * Synchronize: skip tokens until a stopping condition is met.\n * Returns an ERROR node wrapping the skipped content, or null if\n * nothing was consumed.\n *\n * @param extraStop - optional predicate for additional stop conditions\n * beyond the default sync points (NEWLINE/DEDENT/EOF)\n */\nexport function synchronizeUntil(ctx, extraStop) {\n if (ctx.isAtSyncPoint() || isAtEnd(ctx))\n return null;\n if (extraStop && extraStop(ctx.peekKind(), ctx.peek().start.row))\n return null;\n const startOffset = ctx.peekOffset();\n const startPos = ctx.peek().start;\n const children = [];\n while (!ctx.isAtSyncPoint() &&\n !isAtEnd(ctx) &&\n !(extraStop && extraStop(ctx.peekKind(), ctx.peek().start.row))) {\n const tok = ctx.consume();\n children.push(tokenToAutoLeaf(tok, ctx.source, ctx.currentOffset()));\n }\n if (children.length === 0)\n return null;\n const last = children[children.length - 1];\n return makeErrorNode(ctx.source, children, startOffset, last.endOffset, startPos, last.endPosition);\n}\n/** Skip tokens on the given row until a sync point, INDENT, or COLON. */\nexport function synchronizeRowUntilColon(ctx, row) {\n return synchronizeUntil(ctx, (kind, r) => kind === TokenKind.INDENT || kind === TokenKind.COLON || r !== row);\n}\n/** Skip tokens on the given row until a sync point or INDENT. */\nexport function synchronizeRow(ctx, row) {\n return synchronizeUntil(ctx, (kind, r) => kind === TokenKind.INDENT || r !== row);\n}\n/** Skip tokens until the next sync point (NEWLINE/DEDENT/EOF). */\nexport function synchronize(ctx) {\n return synchronizeUntil(ctx);\n}\n// --- Utility ---\nexport function skipNewlines(ctx) {\n while (ctx.peekKind() === TokenKind.NEWLINE) {\n ctx.consume();\n }\n}\n/** Consume comment and newline tokens and attach to parent node. */\nexport function consumeCommentsAndSkipNewlines(ctx, parent) {\n while (true) {\n if (ctx.peekKind() === TokenKind.COMMENT) {\n parent.appendChild(ctx.consumeNamed('comment'));\n }\n else if (ctx.peekKind() === TokenKind.NEWLINE) {\n ctx.consume();\n }\n else {\n break;\n }\n }\n}\nexport function isAtEnd(ctx) {\n return ctx.peekKind() === TokenKind.EOF;\n}\n/** Check if from current position, there are only comments, newlines, and then EOF/DEDENT. */\nexport function isTrailingCommentOnly(ctx) {\n let i = 0;\n while (i < 50) {\n const tok = ctx.peekAt(i);\n if (tok.kind === TokenKind.EOF || tok.kind === TokenKind.DEDENT)\n return true;\n if (tok.kind === TokenKind.COMMENT || tok.kind === TokenKind.NEWLINE) {\n i++;\n continue;\n }\n return false;\n }\n return false; // Exceeded lookahead limit\n}\n//# sourceMappingURL=recovery.js.map", "/*\n * Copyright (c) 2026, Salesforce, Inc.\n * All rights reserved.\n * SPDX-License-Identifier: Apache-2.0\n * For full license text, see the LICENSE file in the repo root or https://www.apache.org/licenses/LICENSE-2.0\n */\n/**\n * Pratt expression parser for AgentScript.\n *\n * Precedence levels (matching grammar.js):\n * 0: ternary (X if C else Y) \u2014 right-associative\n * 1: or\n * 2: and\n * 3: not (prefix)\n * 4: ==, !=, <, >, <=, >=, is, is not, = (comparison)\n * 5: +, - (binary)\n * 6: *, /\n * 7: +, - (unary prefix)\n * 8: call, member, subscript (postfix)\n * 9: parenthesized (atomic)\n */\nimport { TokenKind } from './token.js';\nimport { CSTNode } from './cst-node.js';\n// Hoisted constants \u2014 avoid per-call allocation\n// Must match ESCAPE_TABLE in @agentscript/language (packages/language/src/core/string-escapes.ts)\nconst VALID_ESCAPES = new Set(['\"', \"'\", '\\\\', 'n', 'r', 't', '0']);\nconst KEY_STOP_KEYWORDS = new Set([\n 'if',\n 'elif',\n 'else',\n 'run',\n 'set',\n 'with',\n 'to',\n 'transition',\n 'available',\n 'and',\n 'or',\n 'not',\n 'is',\n 'True',\n 'False',\n 'None',\n 'mutable',\n 'linked',\n 'empty',\n]);\n/** Create a MISSING id wrapped in atom \u2192 expression at the current parser position. */\nfunction makeMissingArgument(ctx) {\n const offset = ctx.peekOffset();\n const pos = ctx.peek().start;\n const missingId = new CSTNode('id', ctx.source, offset, offset, pos, pos, true, false, true);\n const atom = new CSTNode('atom', ctx.source, offset, offset, pos, pos);\n atom.appendChild(missingId);\n const expr = new CSTNode('expression', ctx.source, offset, offset, pos, pos);\n expr.appendChild(atom);\n return expr;\n}\n/** Create an empty ERROR node at the current parser position. */\nfunction makeEmptyError(ctx) {\n const tok = ctx.peek();\n const offset = ctx.peekOffset();\n return new CSTNode('ERROR', ctx.source, offset, offset, tok.start, tok.start, true, true);\n}\nexport function parseExpression(ctx, minPrec = 0) {\n let left = parsePrefix(ctx);\n if (!left)\n return null;\n while (true) {\n // Fast path: sync points (NEWLINE/DEDENT/EOF) are never infix operators.\n // This avoids the infixPrecedence() lookup in the most common case for mappings.\n const nextKind = ctx.peekKind();\n if (nextKind === TokenKind.NEWLINE ||\n nextKind === TokenKind.DEDENT ||\n nextKind === TokenKind.EOF)\n break;\n const prec = infixPrecedence(ctx);\n if (prec < minPrec)\n break;\n const result = parseInfix(ctx, left, prec);\n if (!result)\n break;\n left = result;\n }\n return left;\n}\nfunction parsePrefix(ctx) {\n const tok = ctx.peek();\n // not (precedence 3)\n if (tok.kind === TokenKind.ID && tok.text === 'not') {\n return parseUnary(ctx, 'not', 3);\n }\n // Unary + / - (precedence 7)\n if (tok.kind === TokenKind.PLUS || tok.kind === TokenKind.MINUS) {\n const op = tok.text;\n return parseUnary(ctx, op, 7);\n }\n // Spread *expr (precedence 7)\n if (tok.kind === TokenKind.STAR) {\n return parseSpread(ctx);\n }\n // Parenthesized expression\n if (tok.kind === TokenKind.LPAREN) {\n return parseParenthesized(ctx);\n }\n // Atom\n return parseAtom(ctx);\n}\nfunction parseUnary(ctx, _op, prec) {\n const startTok = ctx.peek();\n const node = ctx.startNode('unary_expression');\n ctx.addAnonymousChild(node, ctx.consume()); // operator\n const operand = parseExpression(ctx, prec + 1);\n if (operand) {\n node.appendChild(wrapExpression(ctx, operand));\n }\n ctx.finishNode(node, startTok);\n return node;\n}\nfunction parseSpread(ctx) {\n const startTok = ctx.peek();\n const node = ctx.startNode('spread_expression');\n ctx.addAnonymousChild(node, ctx.consume()); // *\n // Bind at precedence 8 (same as postfix call/member/subscript) so\n // *@variables.x parses as *(variables.x), not (*variables).x\n const operand = parseExpression(ctx, 8);\n if (operand) {\n node.appendChild(wrapExpression(ctx, operand), 'expression');\n }\n ctx.finishNode(node, startTok);\n return node;\n}\nfunction parseParenthesized(ctx) {\n const startTok = ctx.peek();\n const node = ctx.startNode('parenthesized_expression');\n ctx.addAnonymousChild(node, ctx.consume()); // (\n const expr = parseExpression(ctx, 0);\n if (expr) {\n node.appendChild(wrapExpression(ctx, expr), 'expression');\n }\n else if (ctx.peekKind() === TokenKind.RPAREN) {\n // Empty parens () \u2192 insert MISSING id\n node.appendChild(makeMissingArgument(ctx), 'expression');\n }\n if (ctx.peekKind() === TokenKind.RPAREN) {\n ctx.addAnonymousChild(node, ctx.consume()); // )\n }\n else {\n // Unclosed paren \u2192 add ERROR node\n node.appendChild(makeEmptyError(ctx));\n }\n ctx.finishNode(node, startTok);\n return node;\n}\nfunction parseAtom(ctx) {\n const tok = ctx.peek();\n // Boolean / None constants\n if (tok.kind === TokenKind.ID &&\n (tok.text === 'True' || tok.text === 'False' || tok.text === 'None')) {\n const node = ctx.startNode('atom');\n ctx.addAnonymousChild(node, ctx.consume());\n ctx.finishNode(node, tok);\n return node;\n }\n // empty keyword\n if (tok.kind === TokenKind.ID && tok.text === 'empty') {\n const node = ctx.startNode('empty_keyword');\n ctx.addAnonymousChild(node, ctx.consume());\n ctx.finishNode(node, tok);\n return node;\n }\n // @id\n if (tok.kind === TokenKind.AT) {\n return parseAtId(ctx);\n }\n // id\n if (tok.kind === TokenKind.ID) {\n return ctx.consumeNamed('id');\n }\n // number\n if (tok.kind === TokenKind.NUMBER) {\n return ctx.consumeNamed('number');\n }\n // datetime\n if (tok.kind === TokenKind.DATETIME) {\n return ctx.consumeNamed('datetime_literal');\n }\n // string\n if (tok.kind === TokenKind.STRING) {\n return parseString(ctx);\n }\n // ellipsis\n if (tok.kind === TokenKind.ELLIPSIS) {\n return ctx.consumeNamed('ellipsis');\n }\n // list [...]\n if (tok.kind === TokenKind.LBRACKET) {\n return parseList(ctx);\n }\n // dictionary {...}\n if (tok.kind === TokenKind.LBRACE) {\n return parseDictionary(ctx);\n }\n return null;\n}\nfunction parseAtId(ctx) {\n const startTok = ctx.peek();\n const node = ctx.startNode('at_id');\n ctx.addAnonymousChild(node, ctx.consume()); // @\n if (ctx.peekKind() === TokenKind.ID) {\n node.appendChild(ctx.consumeNamed('id'));\n }\n else {\n // @ with no identifier \u2192 ERROR\n node.appendChild(makeEmptyError(ctx));\n }\n ctx.finishNode(node, startTok);\n return node;\n}\nexport function parseString(ctx) {\n const tok = ctx.peek();\n const startTok = tok;\n const node = ctx.startNode('string');\n // The lexer gives us the whole string as one token.\n // We need to break it into children: opening quote, string_content/escape_sequence, closing quote.\n const text = tok.text;\n const tokenOffset = ctx.peekOffset();\n ctx.consume(); // consume the full string token\n const baseRow = startTok.start.row;\n const baseCol = startTok.start.column;\n // Opening quote\n node.appendChild(new CSTNode('\"', ctx.source, tokenOffset, tokenOffset + 1, { row: baseRow, column: baseCol }, { row: baseRow, column: baseCol + 1 }, false));\n // Parse content between quotes\n let i = 1; // skip opening \"\n const quoteChar = text[0]; // \" or '\n const hasClosingQuote = text.length > 1 && text[text.length - 1] === quoteChar;\n const contentEnd = hasClosingQuote ? text.length - 1 : text.length;\n let contentStart = i;\n while (i < contentEnd) {\n if (text[i] === '\\\\' &&\n i + 1 < contentEnd &&\n VALID_ESCAPES.has(text[i + 1])) {\n // Emit any accumulated content before the escape\n if (i > contentStart) {\n node.appendChild(new CSTNode('string_content', ctx.source, tokenOffset + contentStart, tokenOffset + i, { row: baseRow, column: baseCol + contentStart }, { row: baseRow, column: baseCol + i }));\n }\n // Emit escape sequence\n const escLen = 2;\n node.appendChild(new CSTNode('escape_sequence', ctx.source, tokenOffset + i, tokenOffset + i + escLen, { row: baseRow, column: baseCol + i }, { row: baseRow, column: baseCol + i + escLen }));\n i += escLen;\n contentStart = i;\n }\n else if (text[i] === '\\\\' &&\n i + 1 < contentEnd &&\n !VALID_ESCAPES.has(text[i + 1])) {\n // Invalid escape sequence \u2014 emit accumulated content, then ERROR\n if (i > contentStart) {\n node.appendChild(new CSTNode('string_content', ctx.source, tokenOffset + contentStart, tokenOffset + i, { row: baseRow, column: baseCol + contentStart }, { row: baseRow, column: baseCol + i }));\n }\n // Find the extent of the invalid escape: \\x followed by remaining word chars\n const escStart = i;\n i += 2; // skip \\ and the invalid char\n while (i < contentEnd && /[a-zA-Z0-9_]/.test(text[i])) {\n i++;\n }\n const errNode = new CSTNode('ERROR', ctx.source, tokenOffset + escStart, tokenOffset + i, { row: baseRow, column: baseCol + escStart }, { row: baseRow, column: baseCol + i }, true, true);\n node.appendChild(errNode);\n contentStart = i;\n }\n else {\n i++;\n }\n }\n // Emit remaining content\n if (i > contentStart) {\n node.appendChild(new CSTNode('string_content', ctx.source, tokenOffset + contentStart, tokenOffset + i, { row: baseRow, column: baseCol + contentStart }, { row: baseRow, column: baseCol + i }));\n }\n // Closing quote\n if (hasClosingQuote) {\n node.appendChild(new CSTNode(quoteChar, ctx.source, tokenOffset + text.length - 1, tokenOffset + text.length, { row: baseRow, column: baseCol + text.length - 1 }, { row: baseRow, column: baseCol + text.length }, false));\n }\n else {\n // Unclosed string \u2192 MISSING closing quote\n // Position at end of string content (where the quote should have been),\n // not at the next token which may be on the next line.\n const missingOffset = tokenOffset + text.length;\n const missingPos = { row: baseRow, column: baseCol + text.length };\n node.appendChild(new CSTNode(quoteChar, ctx.source, missingOffset, missingOffset, missingPos, missingPos, false, false, true));\n }\n ctx.finishNode(node, startTok);\n return node;\n}\nfunction parseList(ctx) {\n const startTok = ctx.peek();\n const node = ctx.startNode('list');\n ctx.addAnonymousChild(node, ctx.consume()); // [\n // Lists can span multiple lines \u2014 skip whitespace tokens inside [...]\n let _listIndentDepth = 0;\n while (ctx.peekKind() !== TokenKind.RBRACKET &&\n ctx.peekKind() !== TokenKind.EOF) {\n if (ctx.peekKind() === TokenKind.NEWLINE) {\n ctx.consume();\n continue;\n }\n if (ctx.peekKind() === TokenKind.INDENT) {\n _listIndentDepth++;\n ctx.consume();\n continue;\n }\n if (ctx.peekKind() === TokenKind.DEDENT) {\n _listIndentDepth--;\n ctx.consume();\n continue;\n }\n const expr = parseExpression(ctx, 0);\n if (expr) {\n node.appendChild(wrapExpression(ctx, expr));\n }\n else {\n break;\n }\n if (ctx.peekKind() === TokenKind.COMMA) {\n ctx.addAnonymousChild(node, ctx.consume());\n }\n else {\n break;\n }\n }\n // Skip whitespace tokens to find the closing ]\n while (ctx.peekKind() === TokenKind.NEWLINE ||\n ctx.peekKind() === TokenKind.INDENT ||\n ctx.peekKind() === TokenKind.DEDENT) {\n ctx.consume();\n }\n if (ctx.peekKind() === TokenKind.RBRACKET) {\n ctx.addAnonymousChild(node, ctx.consume());\n }\n else {\n node.appendChild(makeEmptyError(ctx));\n }\n ctx.finishNode(node, startTok);\n return node;\n}\nfunction parseDictionary(ctx) {\n const startTok = ctx.peek();\n const node = ctx.startNode('dictionary');\n ctx.addAnonymousChild(node, ctx.consume()); // {\n // Dictionaries can span multiple lines\n while (ctx.peekKind() !== TokenKind.RBRACE &&\n ctx.peekKind() !== TokenKind.EOF) {\n if (ctx.peekKind() === TokenKind.NEWLINE ||\n ctx.peekKind() === TokenKind.INDENT ||\n ctx.peekKind() === TokenKind.DEDENT) {\n ctx.consume();\n continue;\n }\n const pair = parseDictionaryPair(ctx);\n if (pair) {\n node.appendChild(pair);\n }\n else {\n break;\n }\n if (ctx.peekKind() === TokenKind.COMMA) {\n ctx.addAnonymousChild(node, ctx.consume());\n }\n else {\n break;\n }\n }\n if (ctx.peekKind() === TokenKind.RBRACE) {\n ctx.addAnonymousChild(node, ctx.consume());\n }\n else {\n node.appendChild(makeEmptyError(ctx));\n }\n ctx.finishNode(node, startTok);\n return node;\n}\nfunction parseDictionaryPair(ctx) {\n const startTok = ctx.peek();\n if (!isKeyStart(ctx))\n return null;\n const node = ctx.startNode('dictionary_pair');\n const key = parseKey(ctx);\n if (key)\n node.appendChild(key, 'key');\n if (ctx.peekKind() === TokenKind.COLON) {\n ctx.addAnonymousChild(node, ctx.consume());\n }\n const value = parseExpression(ctx, 0);\n if (value)\n node.appendChild(wrapExpression(ctx, value), 'value');\n ctx.finishNode(node, startTok);\n return node;\n}\n// --- Infix parsing ---\n// Precedence lookup tables (O(1) instead of 20+ if-statements)\nconst INFIX_PREC_BY_KIND = new Map([\n [TokenKind.LPAREN, 8],\n [TokenKind.DOT, 8],\n [TokenKind.LBRACKET, 8],\n [TokenKind.EQEQ, 4],\n [TokenKind.NEQ, 4],\n [TokenKind.LT, 4],\n [TokenKind.GT, 4],\n [TokenKind.LTE, 4],\n [TokenKind.GTE, 4],\n [TokenKind.PLUS, 5],\n [TokenKind.MINUS, 5],\n [TokenKind.STAR, 6],\n [TokenKind.SLASH, 6],\n]);\nconst INFIX_KEYWORD_PREC = new Map([\n ['if', 0],\n ['or', 1],\n ['and', 2],\n ['is', 4],\n]);\nfunction infixPrecedence(ctx) {\n const tok = ctx.peek();\n if (tok.kind === TokenKind.ID)\n return INFIX_KEYWORD_PREC.get(tok.text) ?? -2;\n return INFIX_PREC_BY_KIND.get(tok.kind) ?? -2;\n}\nfunction parseInfix(ctx, left, prec) {\n const tok = ctx.peek();\n // Call expression: expr(args)\n if (tok.kind === TokenKind.LPAREN && prec === 8) {\n return parseCall(ctx, left);\n }\n // Member expression: expr.id\n if (tok.kind === TokenKind.DOT && prec === 8) {\n return parseMember(ctx, left);\n }\n // Subscript expression: expr[expr]\n if (tok.kind === TokenKind.LBRACKET && prec === 8) {\n return parseSubscript(ctx, left);\n }\n // Ternary: consequence if condition else alternative\n if (tok.kind === TokenKind.ID && tok.text === 'if') {\n return parseTernary(ctx, left);\n }\n // \"is not\" compound operator\n if (tok.kind === TokenKind.ID && tok.text === 'is') {\n return parseIsExpression(ctx, left);\n }\n // Binary / comparison\n return parseBinaryOrComparison(ctx, left, prec);\n}\nfunction parseCall(ctx, func) {\n const startTok = ctx.peek();\n const node = ctx.startNodeAt('call_expression', func);\n node.appendChild(wrapExpression(ctx, func), 'function');\n ctx.addAnonymousChild(node, ctx.consume()); // (\n while (ctx.peekKind() !== TokenKind.RPAREN && !ctx.isAtSyncPoint()) {\n const arg = parseExpression(ctx, 0);\n if (arg) {\n node.appendChild(wrapExpression(ctx, arg), 'argument');\n }\n else {\n break;\n }\n if (ctx.peekKind() === TokenKind.COMMA) {\n ctx.addAnonymousChild(node, ctx.consume());\n // Trailing comma: if `)` follows, insert MISSING id argument\n if (ctx.peekKind() === TokenKind.RPAREN) {\n node.appendChild(makeMissingArgument(ctx), 'argument');\n break;\n }\n }\n else {\n break;\n }\n }\n if (ctx.peekKind() === TokenKind.RPAREN) {\n ctx.addAnonymousChild(node, ctx.consume());\n }\n else {\n node.appendChild(makeEmptyError(ctx));\n }\n ctx.finishNode(node, startTok);\n return node;\n}\nfunction parseMember(ctx, object) {\n const startTok = ctx.peek();\n const node = ctx.startNodeAt('member_expression', object);\n node.appendChild(wrapExpression(ctx, object));\n ctx.addAnonymousChild(node, ctx.consume()); // .\n if (ctx.peekKind() === TokenKind.ID) {\n node.appendChild(ctx.consumeNamed('id'));\n }\n else if (ctx.peekKind() === TokenKind.NUMBER) {\n // Error 19: member access with number like @var.123\n const numNode = ctx.consumeNamed('number');\n const errNode = new CSTNode('ERROR', ctx.source, numNode.startOffset, numNode.endOffset, numNode.startPosition, numNode.endPosition, true, true);\n errNode.appendChild(numNode);\n node.appendChild(errNode);\n }\n else {\n // Trailing dot with nothing after \u2192 ERROR\n node.appendChild(makeEmptyError(ctx));\n }\n ctx.finishNode(node, startTok);\n return node;\n}\nfunction parseSubscript(ctx, object) {\n const startTok = ctx.peek();\n const node = ctx.startNodeAt('subscript_expression', object);\n node.appendChild(wrapExpression(ctx, object));\n ctx.addAnonymousChild(node, ctx.consume()); // [\n const index = parseExpression(ctx, 0);\n if (index) {\n node.appendChild(wrapExpression(ctx, index));\n }\n if (ctx.peekKind() === TokenKind.RBRACKET) {\n ctx.addAnonymousChild(node, ctx.consume());\n }\n else {\n node.appendChild(makeEmptyError(ctx));\n }\n ctx.finishNode(node, startTok);\n return node;\n}\nfunction parseTernary(ctx, consequence) {\n const startTok = ctx.peek();\n const node = ctx.startNodeAt('ternary_expression', consequence);\n node.appendChild(wrapExpression(ctx, consequence), 'consequence');\n ctx.addAnonymousChild(node, ctx.consume()); // if\n const condition = parseExpression(ctx, 1); // above 'or'\n if (condition) {\n node.appendChild(wrapExpression(ctx, condition), 'condition');\n }\n if (ctx.peekKind() === TokenKind.ID && ctx.peek().text === 'else') {\n ctx.addAnonymousChild(node, ctx.consume()); // else\n const alt = parseExpression(ctx, 0); // right-associative: parse at 0\n if (alt) {\n node.appendChild(wrapExpression(ctx, alt), 'alternative');\n }\n }\n else {\n // Incomplete ternary: \"a if condition\" without else \u2192 ERROR\n node.appendChild(makeEmptyError(ctx));\n }\n ctx.finishNode(node, startTok);\n return node;\n}\nfunction parseIsExpression(ctx, left) {\n const startTok = ctx.peek();\n // Check for \"is not\"\n const isNot = ctx.peekAt(1).kind === TokenKind.ID && ctx.peekAt(1).text === 'not';\n const nodeType = 'comparison_expression';\n const node = ctx.startNodeAt(nodeType, left);\n node.appendChild(wrapExpression(ctx, left));\n ctx.addAnonymousChild(node, ctx.consume()); // is\n if (isNot) {\n ctx.addAnonymousChild(node, ctx.consume()); // not\n }\n const right = parseExpression(ctx, 5); // above binary +/-\n if (right) {\n node.appendChild(wrapExpression(ctx, right));\n }\n ctx.finishNode(node, startTok);\n return node;\n}\nfunction parseBinaryOrComparison(ctx, left, prec) {\n const tok = ctx.peek();\n const startTok = tok;\n // Determine if this is a comparison or binary expression\n const isComparison = tok.kind === TokenKind.EQEQ ||\n tok.kind === TokenKind.NEQ ||\n tok.kind === TokenKind.LT ||\n tok.kind === TokenKind.GT ||\n tok.kind === TokenKind.LTE ||\n tok.kind === TokenKind.GTE ||\n tok.kind === TokenKind.EQ;\n const nodeType = isComparison ? 'comparison_expression' : 'binary_expression';\n const node = ctx.startNodeAt(nodeType, left);\n node.appendChild(wrapExpression(ctx, left));\n ctx.addAnonymousChild(node, ctx.consume()); // operator\n const right = parseExpression(ctx, prec + 1); // left-associative\n if (right) {\n node.appendChild(wrapExpression(ctx, right));\n }\n else {\n // Incomplete binary/comparison: `3 +` or `@var ==` with no right operand\n node.appendChild(makeEmptyError(ctx));\n }\n ctx.finishNode(node, startTok);\n return node;\n}\n// --- Helpers ---\n/**\n * Types that are already wrapped or structural \u2014 should NOT get an expression wrapper.\n * Everything else produced by expression parsing gets wrapped.\n */\nconst SKIP_WRAP_TYPES = new Set(['expression', 'ERROR']);\n/**\n * Leaf/literal types that need an intermediate `atom` wrapper before the `expression` wrapper.\n */\nexport const ATOM_TYPES = new Set([\n 'id',\n 'number',\n 'string',\n 'datetime_literal',\n 'at_id',\n 'list',\n 'dictionary',\n 'ellipsis',\n]);\n/**\n * Wrap an expression in an `expression` supertype node if it isn't already one.\n * Tree-sitter wraps most expression children in an (expression ...) wrapper.\n */\nexport function wrapExpression(ctx, inner) {\n if (SKIP_WRAP_TYPES.has(inner.type)) {\n return inner;\n }\n // For atoms, wrap in atom first then expression\n let wrapped = inner;\n if (ATOM_TYPES.has(inner.type)) {\n const atom = new CSTNode('atom', ctx.source, inner.startOffset, inner.endOffset, inner.startPosition, inner.endPosition);\n atom.appendChild(inner);\n wrapped = atom;\n }\n // Now wrap in expression\n const expr = new CSTNode('expression', ctx.source, wrapped.startOffset, wrapped.endOffset, wrapped.startPosition, wrapped.endPosition);\n expr.appendChild(wrapped);\n return expr;\n}\nexport function isKeyStart(ctx) {\n const tok = ctx.peek();\n return isKeyTokenStart(tok.kind);\n}\n/** Can this token kind begin a key? (ID, STRING, or NUMBER for digit-prefixed keys like `3var`) */\nexport function isKeyTokenStart(kind) {\n return (kind === TokenKind.ID ||\n kind === TokenKind.STRING ||\n kind === TokenKind.NUMBER);\n}\n/** Can this token kind appear within a multi-part key? (key-start tokens plus MINUS/DOT for `my-var`, `a.b`) */\nexport function isKeyTokenContinuation(kind) {\n return (isKeyTokenStart(kind) || kind === TokenKind.MINUS || kind === TokenKind.DOT);\n}\nexport function parseKey(ctx) {\n if (!isKeyStart(ctx))\n return null;\n const startTok = ctx.peek();\n const node = ctx.startNode('key');\n // First name \u2014 may be a number (digit-starting key like \"3var\")\n if (ctx.peekKind() === TokenKind.NUMBER) {\n // Digit-starting key: wrap number in ERROR\n const numNode = ctx.consumeNamed('number');\n const errNode = new CSTNode('ERROR', ctx.source, numNode.startOffset, numNode.endOffset, numNode.startPosition, numNode.endPosition, true, true);\n node.appendChild(errNode);\n // Consume the ID part if present\n if (ctx.peekKind() === TokenKind.ID) {\n node.appendChild(ctx.consumeNamed('id'));\n }\n }\n else if (ctx.peekKind() === TokenKind.STRING) {\n node.appendChild(parseString(ctx));\n }\n else {\n node.appendChild(ctx.consumeNamed('id'));\n }\n // Optional second name (two-word keys like \"topic greeting\")\n // The second word must be on the same line with exactly immediate adjacency\n // (the grammar uses token.immediate(' '))\n if (ctx.peekKind() === TokenKind.ID &&\n !ctx.isAtSyncPoint() &&\n ctx.peek().start.row === startTok.start.row) {\n // Check if this could be a keyword that starts a value/statement\n const nextText = ctx.peek().text;\n if (!KEY_STOP_KEYWORDS.has(nextText)) {\n node.appendChild(ctx.consumeNamed('id'));\n }\n }\n ctx.finishNode(node, startTok);\n return node;\n}\n//# sourceMappingURL=expressions.js.map", "/*\n * Copyright (c) 2026, Salesforce, Inc.\n * All rights reserved.\n * SPDX-License-Identifier: Apache-2.0\n * For full license text, see the LICENSE file in the repo root or https://www.apache.org/licenses/LICENSE-2.0\n */\n/**\n * Statement-parsing functions extracted from Parser class.\n *\n * Each function takes a ParserContext as its first parameter, following\n * the same free-function pattern as recovery.ts and expressions.ts.\n *\n * Functions that call parseProcedure (which in turn calls parseStatement,\n * which may delegate to parseTemplate) accept an optional parseTemplate\n * callback to avoid circular dependency with parser.ts.\n */\nimport { isTokenKind, TokenKind } from './token.js';\nimport { CSTNode } from './cst-node.js';\nimport { makeErrorNode, tokenToAutoLeaf } from './errors.js';\nimport { makeEmptyError, addMissingTarget, makeMissing, synchronize, synchronizeRow, synchronizeRowUntilColon, consumeCommentsAndSkipNewlines, skipNewlines, isAtEnd, isTrailingCommentOnly, parseOrphanBlock, } from './recovery.js';\nimport { parseExpression, wrapExpression, parseString } from './expressions.js';\n// ---------------------------------------------------------------------------\n// Statement detection\n// ---------------------------------------------------------------------------\nexport function isStatementStart(ctx) {\n const tok = ctx.peek();\n if (tok.kind !== TokenKind.ID)\n return false;\n switch (tok.text) {\n case 'if':\n case 'run':\n case 'set':\n case 'transition':\n return true;\n case 'with':\n // \"with\" is a statement only if not followed by colon (which would make it a key)\n return ctx.peekAt(1).kind !== TokenKind.COLON;\n case 'available':\n return (ctx.peekAt(1).kind === TokenKind.ID && ctx.peekAt(1).text === 'when');\n default:\n return false;\n }\n}\n// ---------------------------------------------------------------------------\n// Procedure & statement dispatch\n// ---------------------------------------------------------------------------\nexport function parseProcedure(ctx, parseTemplate) {\n const startTok = ctx.peek();\n const node = ctx.startNode('procedure');\n while (!isAtEnd(ctx) && ctx.peekKind() !== TokenKind.DEDENT) {\n skipNewlines(ctx);\n if (isAtEnd(ctx) || ctx.peekKind() === TokenKind.DEDENT)\n break;\n // Don't consume trailing comments that belong to the parent scope\n // (tree-sitter parity: extras at block boundaries attach to the parent).\n if (ctx.peekKind() === TokenKind.COMMENT && isTrailingCommentOnly(ctx)) {\n break;\n }\n const stmt = parseStatement(ctx, parseTemplate);\n if (stmt) {\n node.appendChild(stmt);\n }\n else {\n const err = synchronize(ctx);\n if (err) {\n node.appendChild(err);\n }\n else if (!isAtEnd(ctx) && ctx.peekKind() !== TokenKind.DEDENT) {\n ctx.consume();\n }\n }\n }\n // If the procedure is empty, add an ERROR node (Error 07, 34)\n if (node.namedChildren.length === 0) {\n node.appendChild(makeEmptyError(ctx));\n }\n ctx.finishNode(node, startTok);\n return node;\n}\nexport function parseStatement(ctx, parseTemplate) {\n const tok = ctx.peek();\n if (tok.kind === TokenKind.ID) {\n switch (tok.text) {\n case 'if':\n return parseIfStatement(ctx, parseTemplate);\n case 'run':\n return parseRunStatement(ctx, parseTemplate);\n case 'set':\n return parseSetStatement(ctx);\n case 'transition':\n return parseTransitionStatement(ctx);\n case 'with':\n return parseWithStatement(ctx);\n case 'available': {\n if (ctx.peekAt(1).kind === TokenKind.ID &&\n ctx.peekAt(1).text === 'when') {\n return parseAvailableWhenStatement(ctx);\n }\n break;\n }\n case 'else':\n case 'elif':\n case 'for':\n // Orphan else/elif (without if) or unsupported for \u2192 wrap in ERROR\n return parseOrphanBlock(ctx, c => parseProcedure(c, parseTemplate));\n }\n }\n if (tok.kind === TokenKind.PIPE && parseTemplate) {\n return parseTemplate(ctx);\n }\n if (tok.kind === TokenKind.COMMENT) {\n const comment = ctx.consumeNamed('comment');\n if (ctx.peekKind() === TokenKind.NEWLINE)\n ctx.consume();\n return comment;\n }\n // Fallback: try parsing as a bare expression (e.g., `...` inside a procedure)\n // This keeps expressions as proper expression nodes instead of ERROR-wrapped tokens.\n const expr = parseExpression(ctx, 0);\n if (expr) {\n const wrapped = wrapExpression(ctx, expr);\n if (ctx.peekKind() === TokenKind.NEWLINE)\n ctx.consume();\n return wrapped;\n }\n return null;\n}\n// ---------------------------------------------------------------------------\n// Shared colon \u2192 procedure body\n// ---------------------------------------------------------------------------\n/**\n * Shared colon \u2192 procedure body sequence for if/elif/else.\n * Consumes colon (with recovery), inline comment, extra inline tokens,\n * then INDENT \u2192 procedure \u2192 DEDENT, and trailing NEWLINE.\n *\n * @param errorOnMissingBody - if true, insert ERROR when colon has no\n * indented body (used by `if`; elif/else silently accept missing body).\n */\nfunction parseColonAndProcedureBody(ctx, node, row, errorOnMissingBody, parseTemplate) {\n // Colon (or recovery)\n if (ctx.peekKind() === TokenKind.COLON) {\n ctx.addAnonymousChild(node, ctx.consume());\n }\n else if (errorOnMissingBody) {\n node.appendChild(makeEmptyError(ctx));\n }\n // Inline comment after colon\n if (ctx.peekKind() === TokenKind.COMMENT) {\n node.appendChild(ctx.consumeNamed('comment'));\n }\n // Absorb extra inline tokens after colon on the same row\n const inlineErr = synchronizeRow(ctx, row);\n if (inlineErr)\n node.appendChild(inlineErr);\n // Consequence block\n if (ctx.peekKind() === TokenKind.INDENT) {\n ctx.consume();\n const proc = parseProcedure(ctx, parseTemplate);\n if (proc)\n node.appendChild(proc, 'consequence');\n consumeCommentsAndSkipNewlines(ctx, node);\n if (ctx.peekKind() === TokenKind.DEDENT)\n ctx.consume();\n }\n else if (errorOnMissingBody &&\n (ctx.peekKind() === TokenKind.NEWLINE || ctx.isAtSyncPoint())) {\n node.appendChild(makeEmptyError(ctx));\n }\n if (ctx.peekKind() === TokenKind.NEWLINE)\n ctx.consume();\n}\n// ---------------------------------------------------------------------------\n// Individual statement parsers\n// ---------------------------------------------------------------------------\nexport function parseIfStatement(ctx, parseTemplate) {\n const startTok = ctx.peek();\n const node = ctx.startNode('if_statement');\n ctx.addAnonymousChild(node, ctx.consume()); // if\n // Condition\n let condition = parseExpression(ctx, 0);\n // Handle single `=` typo (should be `==`): wrap `=` in ERROR,\n // build comparison_expression, then continue parsing normally\n if (condition && ctx.peekKind() === TokenKind.EQ) {\n const eqTok = ctx.consume(); // =\n const right = parseExpression(ctx, 5); // parse right side above comparison\n if (right) {\n // Build: (comparison_expression (expr left) (ERROR =) (expr right))\n const cmp = ctx.startNodeAt('comparison_expression', condition);\n cmp.appendChild(wrapExpression(ctx, condition));\n // Wrap `=` in ERROR\n const eqChild = new CSTNode('=', ctx.source, eqTok.startOffset, eqTok.startOffset + 1, eqTok.start, eqTok.end, false);\n const eqErr = makeErrorNode(ctx.source, [eqChild], eqTok.startOffset, eqTok.startOffset + 1, eqTok.start, eqTok.end);\n cmp.appendChild(eqErr);\n cmp.appendChild(wrapExpression(ctx, right));\n cmp.finalize();\n condition = cmp;\n }\n }\n if (condition)\n node.appendChild(wrapExpression(ctx, condition), 'condition');\n // Absorb extra tokens between condition and colon on the same row.\n if (condition &&\n ctx.peekKind() !== TokenKind.COLON &&\n !ctx.isAtSyncPoint() &&\n ctx.peekKind() !== TokenKind.INDENT) {\n const condRow = startTok.start.row;\n const err = synchronizeRowUntilColon(ctx, condRow);\n if (err)\n node.appendChild(err);\n }\n parseColonAndProcedureBody(ctx, node, startTok.start.row, true, parseTemplate);\n // elif clauses (including misspelled 'elseif')\n while (ctx.peekKind() === TokenKind.ID &&\n (ctx.peek().text === 'elif' || ctx.peek().text === 'elseif')) {\n const elif = parseElifClause(ctx, parseTemplate);\n if (elif)\n node.appendChild(elif, 'alternative');\n }\n // else clause\n if (ctx.peekKind() === TokenKind.ID && ctx.peek().text === 'else') {\n const elseClause = parseElseClause(ctx, parseTemplate);\n if (elseClause)\n node.appendChild(elseClause, 'alternative');\n }\n ctx.finishNode(node, startTok);\n return node;\n}\nfunction parseElifClause(ctx, parseTemplate) {\n const startTok = ctx.peek();\n const node = ctx.startNode('elif_clause');\n const kw = ctx.consume(); // elif or elseif\n if (kw.text === 'elseif') {\n // Wrap misspelled keyword in ERROR\n const kwEnd = kw.startOffset + kw.text.length;\n const leaf = tokenToAutoLeaf(kw, ctx.source, kw.startOffset);\n const errNode = makeErrorNode(ctx.source, [leaf], kw.startOffset, kwEnd, kw.start, kw.end);\n node.appendChild(errNode);\n }\n else {\n ctx.addAnonymousChild(node, kw);\n }\n const condition = parseExpression(ctx, 0);\n if (condition)\n node.appendChild(wrapExpression(ctx, condition), 'condition');\n // Absorb extra tokens between condition and colon (same as if)\n if (condition &&\n ctx.peekKind() !== TokenKind.COLON &&\n !ctx.isAtSyncPoint() &&\n ctx.peekKind() !== TokenKind.INDENT) {\n const condRow = startTok.start.row;\n const err = synchronizeRowUntilColon(ctx, condRow);\n if (err)\n node.appendChild(err);\n }\n parseColonAndProcedureBody(ctx, node, startTok.start.row, false, parseTemplate);\n ctx.finishNode(node, startTok);\n return node;\n}\nfunction parseElseClause(ctx, parseTemplate) {\n const startTok = ctx.peek();\n const node = ctx.startNode('else_clause');\n ctx.addAnonymousChild(node, ctx.consume()); // else\n parseColonAndProcedureBody(ctx, node, startTok.start.row, false, parseTemplate);\n ctx.finishNode(node, startTok);\n return node;\n}\nexport function parseRunStatement(ctx, parseTemplate) {\n const startTok = ctx.peek();\n const node = ctx.startNode('run_statement');\n ctx.addAnonymousChild(node, ctx.consume()); // run\n // Target expression\n if (!ctx.isAtSyncPoint()) {\n const target = parseExpression(ctx, 0);\n if (target) {\n node.appendChild(wrapExpression(ctx, target), 'target');\n }\n else {\n addMissingTarget(ctx, node);\n }\n }\n else {\n // `run` with no target at all \u2192 insert ERROR placeholder\n addMissingTarget(ctx, node);\n }\n // Optional indented block (procedure)\n if (ctx.peekKind() === TokenKind.INDENT) {\n ctx.consume();\n // Comments before procedure body attach to run_statement\n consumeCommentsAndSkipNewlines(ctx, node);\n const proc = parseProcedure(ctx, parseTemplate);\n if (proc) {\n // If procedure contains an ERROR with `with` keyword (invalid with clause),\n // attach children directly to run_statement so the dialect's\n // error recovery can find them (it looks at run_statement.children).\n const hasWithError = proc.namedChildren.some(c => c.isError && c.children.some(cc => cc.type === 'with'));\n if (hasWithError) {\n for (const child of proc.namedChildren) {\n node.appendChild(child);\n }\n }\n else {\n node.appendChild(proc, 'block_value');\n }\n }\n consumeCommentsAndSkipNewlines(ctx, node);\n if (ctx.peekKind() === TokenKind.DEDENT)\n ctx.consume();\n }\n if (ctx.peekKind() === TokenKind.NEWLINE)\n ctx.consume();\n ctx.finishNode(node, startTok);\n return node;\n}\nexport function parseSetStatement(ctx) {\n const startTok = ctx.peek();\n const node = ctx.startNode('set_statement');\n ctx.addAnonymousChild(node, ctx.consume()); // set\n // Parse target at precedence 5 (above comparison/=) so = and == aren't consumed\n const target = parseExpression(ctx, 5);\n if (ctx.peekKind() === TokenKind.EQEQ) {\n // set @var == \"value\" \u2192 ERROR: == instead of =\n // Build comparison_expression(target, ==, rhs) and wrap in ERROR\n // Don't add target to node \u2014 we're returning an ERROR node instead\n const eqTok = ctx.consume(); // ==\n const rhs = parseExpression(ctx, 0);\n if (target && rhs) {\n const cmp = ctx.startNodeAt('comparison_expression', wrapExpression(ctx, target));\n cmp.appendChild(wrapExpression(ctx, target));\n cmp.appendChild(new CSTNode(eqTok.text, ctx.source, eqTok.startOffset, eqTok.startOffset + 2, eqTok.start, eqTok.end, false));\n cmp.appendChild(wrapExpression(ctx, rhs));\n cmp.finalize();\n const wrappedCmp = wrapExpression(ctx, cmp);\n if (ctx.peekKind() === TokenKind.NEWLINE)\n ctx.consume();\n // Return ERROR instead of set_statement\n return makeErrorNode(ctx.source, [wrappedCmp], wrappedCmp.startOffset, wrappedCmp.endOffset, wrappedCmp.startPosition, wrappedCmp.endPosition);\n }\n }\n // Add target to node only after ruling out the == error case\n if (target)\n node.appendChild(wrapExpression(ctx, target), 'target');\n if (ctx.peekKind() === TokenKind.EQ) {\n ctx.addAnonymousChild(node, ctx.consume()); // =\n const value = parseExpression(ctx, 0);\n if (value)\n node.appendChild(wrapExpression(ctx, value), 'value');\n }\n if (ctx.peekKind() === TokenKind.NEWLINE)\n ctx.consume();\n ctx.finishNode(node, startTok);\n return node;\n}\nexport function parseTransitionStatement(ctx) {\n const startTok = ctx.peek();\n const node = ctx.startNode('transition_statement');\n ctx.addAnonymousChild(node, ctx.consume()); // transition\n // Optional with/to statement list\n const withToList = tryParseWithToStatementList(ctx);\n if (withToList) {\n node.appendChild(withToList, 'with_to_statement_list');\n }\n else if (!ctx.isAtSyncPoint() &&\n ctx.peekKind() !== TokenKind.NEWLINE &&\n ctx.peekKind() !== TokenKind.EOF) {\n // No with/to list found but there are tokens remaining on the same line \u2014\n // likely a missing 'to' keyword (e.g. \"transition @topic.greeting\").\n // Insert a synthetic with_to_statement_list containing a to_statement\n // with a MISSING 'to' node.\n const listNode = ctx.startNode('with_to_statement_list');\n const toNode = ctx.startNode('to_statement');\n toNode.appendChild(makeMissing(ctx, 'to'));\n const target = parseExpression(ctx, 0);\n if (target)\n toNode.appendChild(wrapExpression(ctx, target), 'target');\n toNode.finalize();\n listNode.appendChild(toNode);\n listNode.finalize();\n node.appendChild(listNode, 'with_to_statement_list');\n }\n if (ctx.peekKind() === TokenKind.NEWLINE)\n ctx.consume();\n ctx.finishNode(node, startTok);\n return node;\n}\nexport function parseWithStatement(ctx) {\n const startTok = ctx.peek();\n // Check if `with` is followed by a valid param (ID/STRING).\n // If not (e.g., `with ...`), create ERROR containing `with` keyword.\n // The remaining tokens (e.g. `...`) stay unconsumed for the caller.\n if (ctx.peekAt(1).kind !== TokenKind.ID &&\n ctx.peekAt(1).kind !== TokenKind.STRING) {\n const withTok = ctx.consume();\n const kwOffset = ctx.currentOffset();\n const withChild = new CSTNode('with', ctx.source, kwOffset, kwOffset + 4, withTok.start, withTok.end, false);\n return makeErrorNode(ctx.source, [withChild], kwOffset, kwOffset + 4, withTok.start, withTok.end);\n }\n const node = ctx.startNode('with_statement');\n ctx.addAnonymousChild(node, ctx.consume()); // with\n // Parse param=value pairs\n parseWithParams(ctx, node);\n // Inline comment on the with line (e.g. `with city=x # comment`)\n if (ctx.peekKind() === TokenKind.COMMENT) {\n node.appendChild(ctx.consumeNamed('comment'));\n }\n if (ctx.peekKind() === TokenKind.NEWLINE)\n ctx.consume();\n ctx.finishNode(node, startTok);\n return node;\n}\nfunction parseWithParams(ctx, node) {\n while (!ctx.isAtSyncPoint()) {\n // param\n if (ctx.peekKind() === TokenKind.ID ||\n ctx.peekKind() === TokenKind.STRING) {\n if (ctx.peekKind() === TokenKind.STRING) {\n node.appendChild(parseString(ctx), 'param');\n }\n else {\n node.appendChild(ctx.consumeNamed('id'), 'param');\n }\n }\n else {\n // Not a valid param \u2014 wrap remaining tokens in ERROR inside with_statement\n const err = synchronize(ctx);\n if (err)\n node.appendChild(err);\n return;\n }\n // =\n if (ctx.peekKind() === TokenKind.EQ) {\n ctx.addAnonymousChild(node, ctx.consume());\n }\n else {\n // Missing = \u2192 insert MISSING\n node.appendChild(makeMissing(ctx, '='));\n }\n // value\n const value = parseExpression(ctx, 0);\n if (value)\n node.appendChild(wrapExpression(ctx, value), 'value');\n // comma\n if (ctx.peekKind() === TokenKind.COMMA) {\n ctx.addAnonymousChild(node, ctx.consume());\n }\n else {\n break;\n }\n }\n}\nexport function parseAvailableWhenStatement(ctx) {\n const startTok = ctx.peek();\n const node = ctx.startNode('available_when_statement');\n ctx.addAnonymousChild(node, ctx.consume()); // available\n ctx.addAnonymousChild(node, ctx.consume()); // when\n const condition = parseExpression(ctx, 0);\n if (condition)\n node.appendChild(wrapExpression(ctx, condition), 'condition');\n if (ctx.peekKind() === TokenKind.NEWLINE)\n ctx.consume();\n ctx.finishNode(node, startTok);\n return node;\n}\n// ---------------------------------------------------------------------------\n// With/To statement list\n// ---------------------------------------------------------------------------\nexport function tryParseWithToStatementList(ctx) {\n const tok = ctx.peek();\n if (!isTokenKind(tok, TokenKind.ID))\n return null;\n if (!['with', 'to'].includes(tok.text))\n return null;\n const startTok = tok;\n const node = ctx.startNode('with_to_statement_list');\n while (!ctx.isAtSyncPoint()) {\n if (ctx.peekKind() === TokenKind.ID && ctx.peek().text === 'with') {\n node.appendChild(parseInlineWithStatement(ctx));\n }\n else if (ctx.peekKind() === TokenKind.ID && ctx.peek().text === 'to') {\n node.appendChild(parseToStatement(ctx));\n }\n else {\n break;\n }\n if (ctx.peekKind() === TokenKind.COMMA) {\n ctx.addAnonymousChild(node, ctx.consume());\n }\n else {\n break;\n }\n }\n if (node.children.length === 0)\n return null;\n ctx.finishNode(node, startTok);\n return node;\n}\nexport function parseInlineWithStatement(ctx) {\n const startTok = ctx.peek();\n const node = ctx.startNode('with_statement');\n ctx.addAnonymousChild(node, ctx.consume()); // with\n parseWithParams(ctx, node);\n ctx.finishNode(node, startTok);\n return node;\n}\nexport function parseToStatement(ctx) {\n const startTok = ctx.peek();\n const node = ctx.startNode('to_statement');\n ctx.addAnonymousChild(node, ctx.consume()); // to\n const target = parseExpression(ctx, 0);\n if (target) {\n node.appendChild(wrapExpression(ctx, target), 'target');\n }\n else {\n // Missing target \u2192 ERROR\n node.appendChild(makeEmptyError(ctx));\n }\n ctx.finishNode(node, startTok);\n return node;\n}\n//# sourceMappingURL=parse-statements.js.map", "/*\n * Copyright (c) 2026, Salesforce, Inc.\n * All rights reserved.\n * SPDX-License-Identifier: Apache-2.0\n * For full license text, see the LICENSE file in the repo root or https://www.apache.org/licenses/LICENSE-2.0\n */\n/**\n * Template-parsing functions extracted from Parser class.\n *\n * Each function takes a ParserContext as its first parameter, following\n * the same free-function pattern as parse-statements.ts and expressions.ts.\n *\n * Template indentation state (templateOuterIndent) is computed locally in\n * parseTemplate and passed as an explicit parameter to templateContinues.\n */\nimport { TokenKind } from './token.js';\nimport { CSTNode } from './cst-node.js';\nimport { makeEmptyError, makeMissing, synchronize, isAtEnd, } from './recovery.js';\nimport { parseExpression, wrapExpression } from './expressions.js';\n// ---------------------------------------------------------------------------\n// Exported template parsers\n// ---------------------------------------------------------------------------\n/**\n * Parse a template starting with `|`.\n * Consumes tokens from the lexer stream, treating everything as template content\n * except `{!...}` breaks which are parsed as template expressions.\n */\nexport function parseTemplate(ctx) {\n const startTok = ctx.peek();\n const node = ctx.startNode('template');\n // Compute the indent level of the line containing `|`.\n // Tree-sitter uses *array_back(&scanner->indents) \u2014 the top of the indent\n // stack, which equals the line indent. We scan backward in the source to\n // measure the leading whitespace on this line.\n const pipeOffset = ctx.peekOffset();\n let lineStart = pipeOffset;\n while (lineStart > 0 &&\n ctx.source.charCodeAt(lineStart - 1) !== 10 /* \\n */) {\n lineStart--;\n }\n let templateOuterIndent = 0;\n for (let i = lineStart; i < pipeOffset; i++) {\n const ch = ctx.source.charCodeAt(i);\n if (ch === 32 /* space */)\n templateOuterIndent += 1;\n else if (ch === 9 /* tab */)\n templateOuterIndent += 3;\n else\n break;\n }\n // Consume the | token and track position right after it\n const pipeToken = ctx.consume();\n ctx.addAnonymousChild(node, pipeToken);\n // If there are tokens on the same line after |, pass afterPipeOffset\n // so whitespace between | and {! is captured as template_content.\n // If the line is empty after |, don't pass it (avoids phantom content).\n const hasContentOnSameLine = !isAtEnd(ctx) &&\n ctx.peekKind() !== TokenKind.NEWLINE &&\n ctx.peekKind() !== TokenKind.INDENT &&\n ctx.peekKind() !== TokenKind.DEDENT;\n if (hasContentOnSameLine) {\n const afterPipeOffset = pipeToken.startOffset + 1;\n gatherTemplateContentLine(ctx, node, afterPipeOffset);\n }\n // Consume NEWLINE if present\n if (ctx.peekKind() === TokenKind.NEWLINE) {\n ctx.consume();\n }\n // If there's an INDENT, the template continues on indented lines.\n // Templates consume ALL indented content until we fully return to the\n // base indent. We track indent depth: each INDENT increments, each\n // DEDENT decrements. When depth reaches 0, a final DEDENT exits.\n // Mid-template DEDENTs (under-indented continuation lines) are consumed\n // as content.\n if (ctx.peekKind() === TokenKind.INDENT) {\n ctx.consume(); // outer INDENT\n let indentDepth = 1;\n while (!isAtEnd(ctx)) {\n const tok = ctx.peek();\n if (tok.kind === TokenKind.DEDENT) {\n indentDepth--;\n ctx.consume();\n if (indentDepth <= 0) {\n // Check if template continues with under-indented content.\n // If the next meaningful token is content (not EOF/DEDENT),\n // the template has under-indented continuation lines.\n if (templateContinues(ctx, templateOuterIndent)) {\n // Re-enter: consume content at the new (lower) indent\n indentDepth = 0; // will re-increment on next INDENT\n continue;\n }\n break;\n }\n }\n else if (tok.kind === TokenKind.INDENT) {\n indentDepth++;\n ctx.consume();\n }\n else if (tok.kind === TokenKind.NEWLINE) {\n ctx.consume();\n }\n else {\n // When at the template's base indent depth, check if the next\n // token should continue the template (e.g. comments at the base\n // level should not be absorbed as template content).\n if (indentDepth <= 0 && !templateContinues(ctx, templateOuterIndent)) {\n break;\n }\n // For continuation lines, start the content from the end of the\n // last template child so that newlines + indentation between a\n // template_expression and the next template_content are preserved\n // in the source text. (mergeTemplateContent handles this for\n // consecutive template_content nodes, but not across expressions.)\n const lastChild = node.children.length > 0\n ? node.children[node.children.length - 1]\n : null;\n const gapOffset = lastChild && lastChild.endOffset < ctx.peekOffset()\n ? lastChild.endOffset\n : undefined;\n const gapPos = gapOffset !== undefined ? lastChild.endPosition : undefined;\n gatherTemplateContentLine(ctx, node, gapOffset, gapPos);\n }\n }\n }\n // Merge consecutive template_content children into single nodes.\n // Tree-sitter produces one template_content per contiguous text span;\n // our line-by-line parsing creates one per line.\n mergeTemplateContent(ctx, node);\n ctx.finishNode(node, startTok);\n return node;\n}\n/**\n * Parse a template in colinear position (after a colon on the same line).\n * Currently identical to parseTemplate; kept as a separate entry point\n * for semantic clarity and potential future divergence.\n */\nexport function parseTemplateAsColinear(ctx) {\n return parseTemplate(ctx);\n}\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n/**\n * Check if the template continues with under-indented content.\n * After a DEDENT brings us to depth 0, if the next meaningful token\n * is content (not EOF, not DEDENT, not a mapping key pattern), the\n * template has continuation lines.\n */\nfunction templateContinues(ctx, templateOuterIndent) {\n let i = 0;\n while (ctx.peekAt(i).kind === TokenKind.NEWLINE)\n i++;\n const tok = ctx.peekAt(i);\n // If we see content (ID, etc.) that's NOT a mapping key pattern, continue\n if (tok.kind === TokenKind.EOF || tok.kind === TokenKind.DEDENT)\n return false;\n // Content deeper than the template's base indent is always template content,\n // regardless of keywords. Matches tree-sitter scanner behavior where\n // indent_length > out_of_template_indent_length keeps content in the template.\n if (tok.start.column > templateOuterIndent)\n return true;\n // Another pipe starts a new template \u2014 don't absorb it\n if (tok.kind === TokenKind.PIPE)\n return false;\n // If it looks like a mapping key (ID followed by COLON), template is done\n if (tok.kind === TokenKind.ID || tok.kind === TokenKind.STRING) {\n const after = ctx.peekAt(i + 1);\n if (after.kind === TokenKind.COLON)\n return false;\n // Two-word key check\n if (after.kind === TokenKind.ID) {\n const afterAfter = ctx.peekAt(i + 2);\n if (afterAfter.kind === TokenKind.COLON)\n return false;\n }\n }\n // Statement keywords terminate template continuation \u2014 they're\n // sibling statements, not template content\n if (tok.kind === TokenKind.ID) {\n switch (tok.text) {\n case 'if':\n case 'elif':\n case 'else':\n case 'run':\n case 'set':\n case 'transition':\n return false;\n case 'with':\n // \"with\" not followed by colon is a statement\n if (ctx.peekAt(i + 1).kind !== TokenKind.COLON)\n return false;\n break;\n case 'available':\n if (ctx.peekAt(i + 1).kind === TokenKind.ID &&\n ctx.peekAt(i + 1).text === 'when')\n return false;\n break;\n }\n }\n // If it looks like a dash (sequence), template is done\n if (tok.kind === TokenKind.DASH_SPACE)\n return false;\n // Comments at the template's base indent level are not template content\n if (tok.kind === TokenKind.COMMENT)\n return false;\n // Otherwise, assume it's template continuation\n return true;\n}\n/** Merge consecutive template_content children into single nodes. */\nfunction mergeTemplateContent(ctx, template) {\n const merged = [];\n let i = 0;\n while (i < template.children.length) {\n const child = template.children[i];\n if (child.type === 'template_content') {\n // Find the run of consecutive template_content nodes\n let end = i + 1;\n while (end < template.children.length &&\n template.children[end].type === 'template_content') {\n end++;\n }\n if (end > i + 1) {\n // Merge into one node\n const first = template.children[i];\n const last = template.children[end - 1];\n const mergedNode = new CSTNode('template_content', ctx.source, first.startOffset, last.endOffset, first.startPosition, last.endPosition);\n mergedNode.parent = template;\n merged.push(mergedNode);\n i = end;\n }\n else {\n merged.push(child);\n i++;\n }\n }\n else {\n merged.push(child);\n i++;\n }\n }\n template.children = merged;\n}\n/**\n * Gather tokens on the current line as template content.\n * Recognizes {! ... } as template expression breaks.\n * Everything else (including inter-token whitespace) becomes template_content.\n * Uses source-level offsets so whitespace between tokens is preserved.\n */\nfunction gatherTemplateContentLine(ctx, parent, initialOffset, initialPos) {\n // Track the source range of content before/after template expressions.\n // If initialOffset is provided, use it (captures whitespace after |).\n // Otherwise start from the current token position.\n let contentStartOffset = initialOffset ?? ctx.peekOffset();\n let contentStartPos = initialPos ?? ctx.peek().start;\n let lastConsumedEndOffset = contentStartOffset;\n let lastConsumedEndPos = contentStartPos;\n while (!isAtEnd(ctx)) {\n const tok = ctx.peek();\n if (tok.kind === TokenKind.NEWLINE ||\n tok.kind === TokenKind.DEDENT ||\n tok.kind === TokenKind.INDENT ||\n tok.kind === TokenKind.EOF) {\n break;\n }\n // Template expression start\n if (tok.kind === TokenKind.TEMPLATE_EXPR_START) {\n // Flush accumulated content up to the {!\n const exprOffset = ctx.peekOffset();\n if (exprOffset > contentStartOffset) {\n parent.appendChild(new CSTNode('template_content', ctx.source, contentStartOffset, exprOffset, contentStartPos, tok.start));\n }\n // Parse template expression\n const exprNode = parseTemplateExpression(ctx);\n parent.appendChild(exprNode);\n // Content after } continues from the end of the expression node\n // (not from the next token \u2014 that would skip whitespace between } and next content)\n contentStartOffset = exprNode.endOffset;\n contentStartPos = exprNode.endPosition;\n lastConsumedEndOffset = exprNode.endOffset;\n lastConsumedEndPos = exprNode.endPosition;\n continue;\n }\n // Track end of this token for accurate content span\n const tokOffset = ctx.peekOffset();\n lastConsumedEndOffset = tokOffset + tok.text.length;\n lastConsumedEndPos = tok.end;\n ctx.consume();\n }\n // Flush remaining content \u2014 use end of last consumed token (not next token offset,\n // which would include blank lines between this content and the next line)\n if (lastConsumedEndOffset > contentStartOffset) {\n parent.appendChild(new CSTNode('template_content', ctx.source, contentStartOffset, lastConsumedEndOffset, contentStartPos, lastConsumedEndPos));\n }\n}\nfunction parseTemplateExpression(ctx) {\n const startTok = ctx.peek();\n const node = ctx.startNode('template_expression');\n ctx.addAnonymousChild(node, ctx.consume()); // {!\n const expr = parseExpression(ctx, 0);\n if (expr) {\n node.appendChild(wrapExpression(ctx, expr), 'expression');\n }\n else {\n // Empty template expression {!} \u2192 ERROR for missing expression\n node.appendChild(makeEmptyError(ctx));\n }\n // Consume any extra tokens before } (e.g., unclosed {!@var.name world)\n if (ctx.peekKind() !== TokenKind.RBRACE && !ctx.isAtSyncPoint()) {\n const err = synchronize(ctx);\n if (err)\n node.appendChild(err);\n }\n if (ctx.peekKind() === TokenKind.RBRACE) {\n ctx.addAnonymousChild(node, ctx.consume()); // }\n }\n else {\n // Unclosed template expression \u2192 MISSING }\n node.appendChild(makeMissing(ctx, '}'));\n }\n ctx.finishNode(node, startTok);\n return node;\n}\n//# sourceMappingURL=parse-templates.js.map", "/*\n * Copyright (c) 2026, Salesforce, Inc.\n * All rights reserved.\n * SPDX-License-Identifier: Apache-2.0\n * For full license text, see the LICENSE file in the repo root or https://www.apache.org/licenses/LICENSE-2.0\n */\n/**\n * Mapping, block-value, and colinear parsing functions extracted from Parser class.\n *\n * Each function takes a ParserContext as its first parameter, following\n * the same free-function pattern as parse-statements.ts and expressions.ts.\n *\n * To avoid circular dependencies with parse-sequence.ts, parseBlockValue\n * receives parseSequence as a callback parameter.\n */\nimport { isTokenKind, TokenKind } from './token.js';\nimport { CSTNode } from './cst-node.js';\nimport { makeErrorNode, tokenToAutoLeaf } from './errors.js';\nimport { makeEmptyError, makeMissing, synchronize, synchronizeRow, recoverToBlockEnd, parseOrphanBlock, skipNewlines, consumeCommentsAndSkipNewlines, isAtEnd, isTrailingCommentOnly, } from './recovery.js';\nimport { parseExpression, wrapExpression, isKeyStart, isKeyTokenStart, isKeyTokenContinuation, parseKey, ATOM_TYPES, } from './expressions.js';\nimport { isStatementStart, parseProcedure, parseSetStatement, parseTransitionStatement, parseWithStatement, parseAvailableWhenStatement, tryParseWithToStatementList, parseIfStatement, parseRunStatement, } from './parse-statements.js';\nimport { parseTemplate, parseTemplateAsColinear } from './parse-templates.js';\nimport invariant from 'tiny-invariant';\n/**\n * Maximum tokens to scan ahead when distinguishing a mapping key from an\n * expression. Keys are typically 1-3 words; 10 handles any realistic case\n * with margin. The loop terminates early on COLON, NEWLINE, or non-key tokens,\n * so this limit is a safety cap, not a performance concern.\n */\nconst MAX_KEY_LOOKAHEAD = 10;\n// ---------------------------------------------------------------------------\n// Exported mapping parsers\n// ---------------------------------------------------------------------------\n/**\n * Parse a mapping-or-expression at the top level.\n * If the current position starts a mapping, delegates to parseMapping;\n * otherwise parses an expression (possibly an assignment).\n */\nexport function parseMappingOrExpression(ctx, parseSequence) {\n // Look ahead: if we see ID/STRING followed by COLON, it's a mapping\n if (isMappingStart(ctx)) {\n return parseMapping(ctx, parseSequence);\n }\n // Otherwise, try expression (or assignment_expression)\n const expr = parseExpression(ctx, 0);\n if (!expr)\n return null;\n // Check for assignment: expr = expr\n if (isTokenKind(ctx.peek(), TokenKind.EQ)) {\n const node = ctx.startNodeAt('assignment_expression', expr);\n node.appendChild(wrapExpression(ctx, expr), 'left');\n ctx.addAnonymousChild(node, ctx.consumeKind(TokenKind.EQ));\n const right = parseExpression(ctx, 0);\n if (right)\n node.appendChild(wrapExpression(ctx, right), 'right');\n return node;\n }\n return wrapExpression(ctx, expr);\n}\n/**\n * Lookahead to determine if the current position starts a mapping (key-value\n * pairs) rather than an expression.\n *\n * Keys are at most a few tokens (1-3 words, possibly with hyphens/dots), so\n * we only need a small lookahead window. The limit exists as a safety cap \u2014\n * it should never be reached on valid input.\n */\nexport function isMappingStart(ctx) {\n const tok = ctx.peek();\n // Comment at start can begin a mapping (comments are valid mapping items)\n if (tok.kind === TokenKind.COMMENT)\n return true;\n // Template pipe at start can begin a mapping item (template as statement)\n if (tok.kind === TokenKind.PIPE)\n return true;\n // Statement keywords (not followed by colon) start mappings\n if (tok.kind === TokenKind.ID && isStatementStart(ctx))\n return true;\n // First token must be able to start a key; bail early otherwise.\n if (!isKeyTokenStart(tok.kind))\n return false;\n // Scan forward on the same line past key-like tokens (ID, STRING, NUMBER,\n // MINUS, DOT) looking for COLON (normal case), INDENT/ARROW (missing-colon\n // recovery), AT (missing-colon with @-expression value), or STRING/NUMBER\n // after a single ID key (missing-colon with literal value).\n const startRow = tok.start.row;\n for (let i = 1; i < MAX_KEY_LOOKAHEAD; i++) {\n const t = ctx.peekAt(i);\n if (t.kind === TokenKind.COLON ||\n t.kind === TokenKind.INDENT ||\n t.kind === TokenKind.ARROW ||\n t.kind === TokenKind.AT)\n return true;\n // A STRING or NUMBER immediately after a single ID key suggests\n // a missing colon (e.g., `agent_name \"WeatherBot\"`).\n // Only trigger this on the first lookahead position (i === 1) to\n // avoid false positives with multi-word keys.\n if (i === 1 && (t.kind === TokenKind.STRING || t.kind === TokenKind.NUMBER))\n return true;\n if (t.kind === TokenKind.EOF || t.start.row !== startRow)\n return false;\n if (!isKeyTokenContinuation(t.kind))\n return false;\n }\n return false;\n}\n/**\n * Parse a mapping (sequence of key-value pairs).\n */\nexport function parseMapping(ctx, parseSequence) {\n const node = ctx.startNode('mapping');\n while (!isAtEnd(ctx)) {\n skipNewlines(ctx);\n const tok = ctx.peek();\n if (tok.kind === TokenKind.DEDENT || tok.kind === TokenKind.EOF)\n break;\n // Don't consume trailing comments that belong to the parent scope.\n if (tok.kind === TokenKind.COMMENT && isTrailingCommentOnly(ctx)) {\n break;\n }\n const item = parseMappingItem(ctx, parseSequence);\n if (item) {\n node.appendChild(item);\n }\n else {\n // Can't parse \u2014 synchronize (skip to next line)\n const err = synchronize(ctx);\n if (err) {\n node.appendChild(err);\n }\n else if (!isAtEnd(ctx) && ctx.peekKind() !== TokenKind.DEDENT) {\n // Consume at least one token to avoid infinite loop\n ctx.consume();\n }\n }\n }\n return node;\n}\n/**\n * Parse a single mapping item (statement, template, comment, or key:value element).\n */\nexport function parseMappingItem(ctx, parseSequence) {\n const tok = ctx.peek();\n // Statement keywords always take the statement path (tree-sitter parity).\n // Keywords cannot be used as mapping keys.\n if (tok.kind === TokenKind.ID) {\n switch (tok.text) {\n case 'if':\n return parseIfStatement(ctx, c => parseTemplate(c));\n case 'run':\n return parseRunStatement(ctx, c => parseTemplate(c));\n case 'set':\n return parseSetStatement(ctx);\n case 'transition':\n return parseTransitionStatement(ctx);\n case 'with': {\n if (ctx.peekAt(1).kind !== TokenKind.COLON) {\n return parseWithStatement(ctx);\n }\n break;\n }\n case 'available': {\n if (ctx.peekAt(1).kind === TokenKind.ID &&\n ctx.peekAt(1).text === 'when') {\n return parseAvailableWhenStatement(ctx);\n }\n break;\n }\n }\n }\n // Template\n if (tok.kind === TokenKind.PIPE) {\n return parseTemplate(ctx);\n }\n // Comment\n if (tok.kind === TokenKind.COMMENT) {\n return ctx.consumeNamed('comment');\n }\n // Standalone else/elif/for \u2014 wrap in ERROR with parsed body\n if (tok.kind === TokenKind.ID &&\n (tok.text === 'else' || tok.text === 'elif' || tok.text === 'for')) {\n return parseOrphanBlock(ctx, c => parseProcedure(c, c2 => parseTemplate(c2)));\n }\n // Mapping element (key: value)\n if (isKeyStart(ctx)) {\n return parseMappingElement(ctx, parseSequence);\n }\n return null;\n}\n// ---------------------------------------------------------------------------\n// Exported helpers needed by parse-sequence.ts (T04)\n// ---------------------------------------------------------------------------\n/**\n * Check if the current position starts a colinear mapping element (key: value\n * on same line after \"- \").\n */\nexport function isColinearMappingElement(ctx) {\n // key: value on same line after \"- \"\n if (!isKeyStart(ctx))\n return false;\n const tok = ctx.peek();\n // Look ahead: ID/STRING then COLON on same line\n const lookahead = 1;\n // Two-word key?\n if (ctx.peekAt(lookahead).kind === TokenKind.ID &&\n ctx.peekAt(lookahead).start.row === tok.start.row) {\n const afterSecond = ctx.peekAt(lookahead + 1);\n if (afterSecond.kind === TokenKind.COLON &&\n afterSecond.start.row === tok.start.row) {\n return true;\n }\n // Don't eagerly consume two-word key if first word is followed by colon\n }\n const next = ctx.peekAt(lookahead);\n return next.kind === TokenKind.COLON && next.start.row === tok.start.row;\n}\n/**\n * Parse a colinear mapping element (key: value on the same line as \"- \").\n */\nexport function parseColinearMappingElement(ctx) {\n const startTok = ctx.peek();\n const node = ctx.startNode('mapping_element');\n const key = parseKey(ctx);\n if (key)\n node.appendChild(key, 'key');\n if (ctx.peekKind() === TokenKind.COLON) {\n ctx.addAnonymousChild(node, ctx.consume());\n }\n const colinear = tryParseColinearValue(ctx);\n if (colinear) {\n if (colinear.errorPrefix)\n node.appendChild(colinear.errorPrefix);\n node.appendChild(colinear.value, 'colinear_value');\n }\n ctx.finishNode(node, startTok);\n return node;\n}\n/**\n * Try to parse a colinear value (template, variable declaration, or expression).\n * Returns the parsed value node and optional error prefix, or null if nothing\n * can be parsed.\n */\nexport function tryParseColinearValue(ctx) {\n const tok = ctx.peek();\n // Template\n if (tok.kind === TokenKind.PIPE) {\n return { value: parseTemplateAsColinear(ctx) };\n }\n // Variable declaration: mutable/linked\n if (tok.kind === TokenKind.ID &&\n (tok.text === 'mutable' || tok.text === 'linked')) {\n return { value: parseVariableDeclaration(ctx) };\n }\n // Fuzzy modifier: close misspelling of mutable/linked \u2192 parse as variable_declaration\n // with the misspelled token wrapped in ERROR\n if (tok.kind === TokenKind.ID && isFuzzyModifier(tok.text)) {\n return { value: parseFuzzyVariableDeclaration(ctx) };\n }\n // expression_with_to: expression followed by optional with/to clauses\n const expr = parseExpression(ctx, 0);\n if (!expr)\n return null;\n // Check for error prefix: if the expression is a number or digit-starting ID\n // (like \"123\" or \"123bad\") AND the next token is an ID on the same line,\n // the first is an error prefix and the second is the real value.\n // Wrap the first in ERROR and re-parse the rest.\n if ((expr.type === 'number' ||\n (expr.type === 'id' && /^[0-9]/.test(expr.text))) &&\n ctx.peekKind() === TokenKind.ID &&\n ctx.peek().start.row === expr.startRow) {\n // Wrap number/digit-starting ID in ERROR\n const errNode = makeErrorNode(ctx.source, [wrapExpression(ctx, expr)], expr.startOffset, expr.endOffset, expr.startPosition, expr.endPosition);\n // Now re-parse the real colinear value (could be variable_declaration or expression)\n const realValue = tryParseColinearValue(ctx);\n // If we got a real value, return it with the error prefix for the caller to handle.\n if (realValue) {\n return { value: realValue.value, errorPrefix: errNode };\n }\n // No real value \u2014 just return the expression as-is\n }\n // Check for with/to statement list\n const withToList = tryParseWithToStatementList(ctx);\n if (withToList) {\n const ewt = ctx.startNodeAt('expression_with_to', expr);\n ewt.appendChild(wrapExpression(ctx, expr), 'expression');\n ewt.appendChild(withToList, 'with_to_statement_list');\n ewt.finalize();\n return { value: ewt };\n }\n // Check for assignment: expr = expr\n if (ctx.peekKind() === TokenKind.EQ) {\n const assign = ctx.startNodeAt('assignment_expression', expr);\n assign.appendChild(wrapExpression(ctx, expr), 'left');\n ctx.addAnonymousChild(assign, ctx.consume()); // =\n const right = parseExpression(ctx, 0);\n if (right)\n assign.appendChild(wrapExpression(ctx, right), 'right');\n assign.finalize();\n return { value: assign };\n }\n // Plain expression_with_to (just expression, no with/to)\n const ewt = ctx.startNodeAt('expression_with_to', expr);\n ewt.appendChild(wrapExpression(ctx, expr), 'expression');\n return { value: ewt };\n}\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n/**\n * Compute Levenshtein distance between two strings.\n */\nfunction levenshteinDistance(a, b) {\n const m = a.length;\n const n = b.length;\n const dp = Array.from({ length: m + 1 }, () => Array.from({ length: n + 1 }).fill(0));\n for (let i = 0; i <= m; i++)\n dp[i][0] = i;\n for (let j = 0; j <= n; j++)\n dp[0][j] = j;\n for (let i = 1; i <= m; i++) {\n for (let j = 1; j <= n; j++) {\n const cost = a[i - 1] === b[j - 1] ? 0 : 1;\n dp[i][j] = Math.min(dp[i - 1][j] + 1, dp[i][j - 1] + 1, dp[i - 1][j - 1] + cost);\n }\n }\n return dp[m][n];\n}\n/**\n * Check if a string is a likely misspelling of 'mutable' or 'linked' (Levenshtein \u2264 2).\n */\nfunction isFuzzyModifier(text) {\n return (levenshteinDistance(text, 'mutable') <= 2 ||\n levenshteinDistance(text, 'linked') <= 2);\n}\n/**\n * Parse a variable declaration with a misspelled modifier.\n * The misspelled modifier token is wrapped in ERROR, while the rest\n * (type expression + optional default) is parsed normally.\n */\nfunction parseFuzzyVariableDeclaration(ctx) {\n const startTok = ctx.peek();\n const node = ctx.startNode('variable_declaration');\n // Consume misspelled modifier and wrap in ERROR\n const misspelled = ctx.consume();\n const misspelledEnd = misspelled.startOffset + misspelled.text.length;\n const leaf = tokenToAutoLeaf(misspelled, ctx.source, misspelled.startOffset);\n const errNode = makeErrorNode(ctx.source, [leaf], misspelled.startOffset, misspelledEnd, misspelled.start, misspelled.end);\n node.appendChild(errNode);\n // type expression\n const typeExpr = parseExpression(ctx, 0);\n if (typeExpr)\n node.appendChild(wrapExpression(ctx, typeExpr), 'type');\n // Optional default: = expr\n if (ctx.peekKind() === TokenKind.EQ) {\n ctx.addAnonymousChild(node, ctx.consume()); // =\n const defaultExpr = parseExpression(ctx, 0);\n if (defaultExpr)\n node.appendChild(wrapExpression(ctx, defaultExpr), 'default');\n }\n ctx.finishNode(node, startTok);\n return node;\n}\nfunction parseMappingElement(ctx, parseSequence) {\n const startTok = ctx.peek();\n const node = ctx.startNode('mapping_element');\n const key = parseKey(ctx);\n invariant(key != null, 'We must be at a key start');\n node.appendChild(key, 'key');\n // Colon handling\n if (ctx.peekKind() === TokenKind.COLON) {\n // Consume real colon\n ctx.addAnonymousChild(node, ctx.consumeKind(TokenKind.COLON));\n }\n else if (ctx.peekKind() === TokenKind.INDENT ||\n ctx.peekKind() === TokenKind.ARROW ||\n ctx.peekKind() === TokenKind.ID ||\n ctx.peekKind() === TokenKind.AT ||\n ctx.peekKind() === TokenKind.STRING ||\n ctx.peekKind() === TokenKind.NUMBER) {\n // Insert MISSING colon for recovery\n node.appendChild(makeMissing(ctx, ':'));\n }\n else {\n // No colon, no recovery, no value\n return node;\n }\n if (ctx.peekKind() === TokenKind.ARROW) {\n parseArrowBody(ctx, node);\n }\n else if (ctx.peekKind() === TokenKind.INDENT) {\n parseIndentedBlockValue(ctx, node, parseSequence);\n }\n else {\n parseColinearAndBlock(ctx, node, startTok.start.row, parseSequence);\n }\n return node;\n}\n/**\n * Parse optional colinear value, inline comment, error synchronization,\n * and trailing indented block or continuation `to` clause.\n */\nfunction parseColinearAndBlock(ctx, node, startRow, parseSequence) {\n const colinear = tryParseColinearValue(ctx);\n if (colinear) {\n if (colinear.errorPrefix)\n node.appendChild(colinear.errorPrefix);\n node.appendChild(colinear.value, 'colinear_value');\n }\n if (ctx.peekKind() === TokenKind.COMMENT) {\n node.appendChild(ctx.consumeNamed('comment'));\n }\n // Absorb trailing junk on same row after colinear value (e.g., a broken\n // `tz` that was meant to be `to`).\n if (colinear) {\n const err = synchronizeRow(ctx, startRow);\n if (err)\n node.appendChild(err);\n }\n else if (!ctx.isAtSyncPoint() && ctx.peekKind() !== TokenKind.INDENT) {\n const err = synchronize(ctx);\n if (err)\n node.appendChild(err);\n }\n // Continuation: indented `to` clause on expression_with_to\n // (e.g., `go: @utils.transition\\n to @topic.next`).\n // NOTE: we only absorb `to`, not `with` \u2014 an indented `with` is typically\n // a with_statement in a block_value mapping, not a with clause on the expression.\n if (colinear?.value.type === 'expression_with_to' &&\n !colinear.value.childForFieldName('with_to_statement_list') &&\n ctx.peekKind() === TokenKind.INDENT &&\n ctx.peekAt(1).kind === TokenKind.ID &&\n ctx.peekAt(1).text === 'to') {\n ctx.consumeKind(TokenKind.INDENT);\n const withToList = tryParseWithToStatementList(ctx);\n if (withToList) {\n colinear.value.appendChild(withToList, 'with_to_statement_list');\n node.endOffset = colinear.value.endOffset;\n node.endPosition = colinear.value.endPosition;\n }\n ctx.consumeKind(TokenKind.DEDENT);\n }\n else if (ctx.peekKind() === TokenKind.INDENT) {\n parseIndentedBlockValue(ctx, node, parseSequence);\n }\n}\n/** Consume `->` and its indented procedure body (shared by normal and missing-colon paths). */\nfunction parseArrowBody(ctx, node) {\n ctx.addAnonymousChild(node, ctx.consume()); // ->\n // Inline comment after -> (e.g., `instructions: -> # comment`)\n if (ctx.peekKind() === TokenKind.COMMENT) {\n node.appendChild(ctx.consumeNamed('comment'));\n }\n if (ctx.peekKind() === TokenKind.INDENT) {\n ctx.consume(); // INDENT\n // Comments between -> and procedure body attach to mapping_element\n consumeCommentsAndSkipNewlines(ctx, node);\n const proc = parseProcedure(ctx, c => parseTemplate(c));\n if (proc)\n node.appendChild(proc, 'block_value');\n // Trailing comments after procedure attach to mapping_element\n consumeCommentsAndSkipNewlines(ctx, node);\n if (ctx.peekKind() === TokenKind.DEDENT)\n ctx.consume();\n }\n else {\n // Arrow with no indented body \u2192 empty procedure with ERROR\n const emptyProc = ctx.startNode('procedure');\n emptyProc.appendChild(makeEmptyError(ctx));\n ctx.finishNode(emptyProc, ctx.peek());\n node.appendChild(emptyProc, 'block_value');\n }\n}\nfunction parseVariableDeclaration(ctx) {\n const startTok = ctx.peek();\n const node = ctx.startNode('variable_declaration');\n // mutable or linked\n ctx.addAnonymousChild(node, ctx.consume());\n // Check for duplicate modifier (error case: \"mutable linked\")\n if (ctx.peekKind() === TokenKind.ID &&\n (ctx.peek().text === 'mutable' || ctx.peek().text === 'linked')) {\n // Wrap the extra modifier in ERROR\n const errExpr = parseExpression(ctx, 0);\n if (errExpr) {\n const wrapped = wrapExpression(ctx, errExpr);\n const errNode = makeErrorNode(ctx.source, [wrapped], wrapped.startOffset, wrapped.endOffset, wrapped.startPosition, wrapped.endPosition);\n node.appendChild(errNode);\n }\n }\n // type expression\n const typeExpr = parseExpression(ctx, 0);\n if (typeExpr)\n node.appendChild(wrapExpression(ctx, typeExpr), 'type');\n // Optional default: = expr\n if (ctx.peekKind() === TokenKind.EQ) {\n ctx.addAnonymousChild(node, ctx.consume()); // =\n const defaultExpr = parseExpression(ctx, 0);\n if (defaultExpr)\n node.appendChild(wrapExpression(ctx, defaultExpr), 'default');\n }\n ctx.finishNode(node, startTok);\n return node;\n}\n// --- Block value ---\n/** Consume INDENT, parse block value with surrounding comments, recover leftovers, consume DEDENT. */\nfunction parseIndentedBlockValue(ctx, parent, parseSequence) {\n ctx.consume(); // INDENT\n consumeCommentsAndSkipNewlines(ctx, parent);\n const blockValue = parseBlockValue(ctx, parseSequence);\n if (blockValue)\n parent.appendChild(blockValue, 'block_value');\n consumeCommentsAndSkipNewlines(ctx, parent);\n recoverToBlockEnd(ctx, parent);\n if (ctx.peekKind() === TokenKind.DEDENT)\n ctx.consume();\n}\nfunction parseBlockValue(ctx, parseSequence) {\n const tok = ctx.peek();\n // Sequence\n if (tok.kind === TokenKind.DASH_SPACE) {\n return parseSequence(ctx);\n }\n // Empty keyword\n if (tok.kind === TokenKind.ID && tok.text === 'empty') {\n const emptyNode = ctx.startNode('empty_keyword');\n ctx.addAnonymousChild(emptyNode, ctx.consume());\n ctx.finishNode(emptyNode, tok);\n return emptyNode;\n }\n // Mapping \u2014 either key:value or statement-starting content\n // isMappingStart() already checks isStatementStart() internally\n if (isMappingStart(ctx)) {\n return parseMapping(ctx, parseSequence);\n }\n // Atom (standalone value in block position)\n return parseAtomBlockValue(ctx);\n}\nfunction parseAtomBlockValue(ctx) {\n const expr = parseExpression(ctx, 0);\n if (!expr)\n return null;\n // tree-sitter's block_value rule wraps atom-type children in (atom ...)\n if (ATOM_TYPES.has(expr.type)) {\n const atom = new CSTNode('atom', ctx.source, expr.startOffset, expr.endOffset, expr.startPosition, expr.endPosition);\n atom.appendChild(expr);\n return atom;\n }\n return expr;\n}\n//# sourceMappingURL=parse-mapping.js.map", "/*\n * Copyright (c) 2026, Salesforce, Inc.\n * All rights reserved.\n * SPDX-License-Identifier: Apache-2.0\n * For full license text, see the LICENSE file in the repo root or https://www.apache.org/licenses/LICENSE-2.0\n */\n/**\n * Sequence parsing functions extracted from Parser class.\n *\n * Each function takes a ParserContext as its first parameter, following\n * the same free-function pattern as parse-mapping.ts and parse-templates.ts.\n */\nimport { TokenKind } from './token.js';\nimport { makeErrorNode } from './errors.js';\nimport { synchronize, skipNewlines, isAtEnd } from './recovery.js';\nimport { parseMapping, parseMappingItem, tryParseColinearValue, isColinearMappingElement, parseColinearMappingElement, } from './parse-mapping.js';\n/**\n * Parse a YAML-style sequence (list of `- item` entries).\n *\n * Exported for use by parser.ts dispatch and by parse-mapping.ts\n * via ParseSequenceFn callback.\n */\nexport function parseSequence(ctx) {\n const startTok = ctx.peek();\n const node = ctx.startNode('sequence');\n while (ctx.peekKind() === TokenKind.DASH_SPACE) {\n const elem = parseSequenceElement(ctx);\n if (elem)\n node.appendChild(elem);\n skipNewlines(ctx);\n }\n // Non-sequence items remaining at same indent \u2192 wrap in ERROR inside sequence\n while (!isAtEnd(ctx) &&\n ctx.peekKind() !== TokenKind.DEDENT &&\n ctx.peekKind() !== TokenKind.DASH_SPACE) {\n skipNewlines(ctx);\n if (isAtEnd(ctx) || ctx.peekKind() === TokenKind.DEDENT)\n break;\n // Try to parse as mapping item and wrap in ERROR\n const parseSeq = (_ctx) => parseSequence(_ctx);\n const item = parseMappingItem(ctx, parseSeq);\n if (item) {\n const errNode = makeErrorNode(ctx.source, [item], item.startOffset, item.endOffset, item.startPosition, item.endPosition);\n node.appendChild(errNode);\n }\n else {\n const err = synchronize(ctx);\n if (err) {\n node.appendChild(err);\n }\n else {\n ctx.consume();\n }\n }\n }\n ctx.finishNode(node, startTok);\n return node;\n}\n/**\n * Parse a single sequence element: `- <value>`.\n */\nfunction parseSequenceElement(ctx) {\n const startTok = ctx.peek();\n const node = ctx.startNode('sequence_element');\n // Consume \"- \" or \"-\"\n ctx.addAnonymousChild(node, ctx.consume());\n const parseSeq = (_ctx) => parseSequence(_ctx);\n // Check for colinear mapping element (key: value on same line)\n if (isColinearMappingElement(ctx)) {\n const mappingElem = parseColinearMappingElement(ctx);\n if (mappingElem)\n node.appendChild(mappingElem, 'colinear_mapping_element');\n // Optional block value (indented mapping below)\n if (ctx.peekKind() === TokenKind.NEWLINE)\n ctx.consume();\n if (ctx.peekKind() === TokenKind.INDENT) {\n ctx.consume();\n const blockValue = parseMapping(ctx, parseSeq);\n if (blockValue)\n node.appendChild(blockValue, 'block_value');\n if (ctx.peekKind() === TokenKind.DEDENT)\n ctx.consume();\n }\n }\n else if (ctx.peekKind() === TokenKind.NEWLINE ||\n ctx.peekKind() === TokenKind.EOF ||\n ctx.peekKind() === TokenKind.INDENT) {\n // Bare dash with optional block value below (or immediately indented)\n if (ctx.peekKind() === TokenKind.NEWLINE)\n ctx.consume();\n if (ctx.peekKind() === TokenKind.INDENT) {\n ctx.consume();\n const blockValue = parseMapping(ctx, parseSeq);\n if (blockValue)\n node.appendChild(blockValue, 'block_value');\n if (ctx.peekKind() === TokenKind.DEDENT)\n ctx.consume();\n }\n }\n else {\n // Colinear value\n const colinear = tryParseColinearValue(ctx);\n if (colinear) {\n if (colinear.errorPrefix)\n node.appendChild(colinear.errorPrefix);\n node.appendChild(colinear.value, 'colinear_value');\n }\n // Inline comment after value\n if (ctx.peekKind() === TokenKind.COMMENT) {\n node.appendChild(ctx.consumeNamed('comment'));\n }\n if (ctx.peekKind() === TokenKind.NEWLINE)\n ctx.consume();\n }\n ctx.finishNode(node, startTok);\n return node;\n}\n//# sourceMappingURL=parse-sequence.js.map", "/*\n * Copyright (c) 2026, Salesforce, Inc.\n * All rights reserved.\n * SPDX-License-Identifier: Apache-2.0\n * For full license text, see the LICENSE file in the repo root or https://www.apache.org/licenses/LICENSE-2.0\n */\n/**\n * Recursive descent parser for AgentScript.\n *\n * Core invariant: NEWLINE and DEDENT are unconditional synchronization points.\n * Every parse function that encounters an unexpected token calls synchronize()\n * which skips to the next NEWLINE/DEDENT/EOF.\n */\nimport { isTokenKind, TokenKind } from './token.js';\nimport { Lexer } from './lexer.js';\nimport { CSTNode } from './cst-node.js';\nimport { isSyncPoint } from './errors.js';\nimport { synchronize, skipNewlines, consumeCommentsAndSkipNewlines, isAtEnd, } from './recovery.js';\nimport { parseMappingOrExpression } from './parse-mapping.js';\nimport { parseSequence } from './parse-sequence.js';\nimport invariant from 'tiny-invariant';\nexport class Parser {\n source;\n tokens;\n pos = 0;\n _eof;\n constructor(source) {\n this.source = source;\n const lexer = new Lexer(source);\n this.tokens = lexer.tokenize();\n }\n parse() {\n const root = this.parseSourceFile();\n return root;\n }\n // --- ParserContext implementation ---\n peek() {\n return this.peekAt(0);\n }\n peekAt(offset) {\n // n.b. (Allen): Because this is called so frequently, these invariants cause significant runtime overhead.\n // invariant(this.pos + offset >= 0, 'peekAt too small');\n // invariant(this.pos + offset <= this.tokens.length, 'peekAt too large');\n return this.peekAtIndex(this.pos + offset);\n }\n peekAtIndex(idx) {\n return this.tokens[idx] ?? this.eofToken();\n }\n peekKind() {\n return this.peek().kind;\n }\n consume() {\n const tok = this.peek();\n this.pos++;\n return tok;\n }\n consumeKind(kind) {\n const tok = this.peek();\n invariant(isTokenKind(tok, kind), `Expected token kind ${kind} but got ${tok.kind}`);\n this.pos++;\n return tok;\n }\n consumeNamed(type) {\n const tok = this.consume();\n const offset = tok.startOffset;\n return new CSTNode(type, this.source, offset, offset + tok.text.length, tok.start, tok.end);\n }\n currentOffset() {\n const idx = this.pos > 0 ? this.pos - 1 : 0;\n return this.peekAtIndex(idx).startOffset;\n }\n peekOffset() {\n return this.peek().startOffset;\n }\n isAtSyncPoint() {\n return isSyncPoint(this.peekKind());\n }\n startNode(type) {\n const tok = this.peek();\n const offset = tok.startOffset;\n return new CSTNode(type, this.source, offset, offset, tok.start, tok.end);\n }\n startNodeAt(type, existingChild) {\n return new CSTNode(type, this.source, existingChild.startOffset, existingChild.endOffset, existingChild.startPosition, existingChild.endPosition);\n }\n finishNode(_node, _startTok) {\n // No-op: appendChild() tracks end position incrementally.\n }\n addAnonymousChild(parent, token) {\n const offset = token.startOffset;\n const child = new CSTNode(token.text, this.source, offset, offset + token.text.length, token.start, token.end, false);\n parent.appendChild(child);\n }\n // --- Top-level parsing ---\n parseSourceFile() {\n const node = this.startNode('source_file');\n // Skip leading newlines and indentation (handles template literals with leading whitespace)\n skipNewlines(this);\n if (this.peekKind() === TokenKind.INDENT) {\n this.consume();\n }\n // Consume leading comments at source_file level (tree-sitter treats them as extras)\n consumeCommentsAndSkipNewlines(this, node);\n // Determine what kind of source file this is\n if (this.peekKind() === TokenKind.DASH_SPACE) {\n // Sequence\n node.appendChild(parseSequence(this));\n }\n else {\n // Mapping or expression\n // n.b. (Allen): Originally we didn't permit expressions at the top level, but\n // we did that to make testing easier in tree-sitter so I suppose\n // we can just make this a feature of the language.\n const content = parseMappingOrExpression(this, _ctx => parseSequence(_ctx));\n if (content)\n node.appendChild(content);\n }\n // Consume trailing comments at source_file level\n consumeCommentsAndSkipNewlines(this, node);\n // Catch-all: if there are unconsumed tokens, wrap them in ERROR nodes.\n // This ensures every byte of source is represented in the CST.\n while (!isAtEnd(this)) {\n if (this.peekKind() === TokenKind.NEWLINE ||\n this.peekKind() === TokenKind.DEDENT) {\n this.consume();\n continue;\n }\n if (this.peekKind() === TokenKind.COMMENT) {\n node.appendChild(this.consumeNamed('comment'));\n continue;\n }\n const err = synchronize(this);\n if (err) {\n node.appendChild(err);\n }\n else {\n // Consume one token to guarantee progress\n this.consume();\n }\n }\n // Root node must span entire source (matches tree-sitter invariant)\n node.startOffset = 0;\n node.startPosition = { row: 0, column: 0 };\n node.endOffset = this.source.length;\n node.endPosition = this.eofToken().end;\n return node;\n }\n eofToken() {\n if (!this._eof) {\n const lastToken = this.tokens[this.tokens.length - 1];\n const pos = lastToken ? lastToken.end : { row: 0, column: 0 };\n this._eof = {\n kind: TokenKind.EOF,\n text: '',\n start: pos,\n end: pos,\n startOffset: this.source.length,\n };\n }\n return this._eof;\n }\n}\n//# sourceMappingURL=parser.js.map", "/*\n * Copyright (c) 2026, Salesforce, Inc.\n * All rights reserved.\n * SPDX-License-Identifier: Apache-2.0\n * For full license text, see the LICENSE file in the repo root or https://www.apache.org/licenses/LICENSE-2.0\n */\n/**\n * @agentscript/parser-javascript \u2014 Hand-written TypeScript parser for AgentScript.\n *\n * Error-tolerant: NEWLINE and DEDENT are unconditional recovery points.\n */\nexport { CSTNode } from './cst-node.js';\nexport { TokenKind } from './token.js';\nexport { highlight } from './highlighter.js';\nimport { Parser } from './parser.js';\nimport { highlight } from './highlighter.js';\n/**\n * Parse AgentScript source code and return a CST.\n * The returned rootNode implements the SyntaxNode interface\n * used by all consumers (dialect, LSP, monaco, agentforce).\n */\nexport function parse(source) {\n const parser = new Parser(source);\n return { rootNode: parser.parse() };\n}\n/**\n * Parse and highlight source code in one call.\n * Returns captures compatible with the QueryCapture format\n * used by LSP semantic tokens.\n */\nexport function parseAndHighlight(source) {\n const { rootNode } = parse(source);\n return highlight(rootNode);\n}\n//# sourceMappingURL=index.js.map", "import type { SyntaxNode } from '@agentscript/types';\n\nimport { parse as parseAgent } from '@agentscript/parser-javascript';\n\nexport function parseAgentSource(source: string): SyntaxNode {\n return parseAgent(source).rootNode;\n}\n\nexport function locOf(n: SyntaxNode) {\n return {\n endCol: n.endCol,\n endRow: n.endRow,\n startCol: n.startCol,\n startRow: n.startRow,\n };\n}\n\nexport function walk(node: SyntaxNode, visit: (n: SyntaxNode) => void): void {\n visit(node);\n for (const c of node.namedChildren) walk(c, visit);\n}\n\nexport function* descendants(node: SyntaxNode): Generator<SyntaxNode> {\n yield node;\n for (const c of node.namedChildren) yield* descendants(c);\n}\n\n/**\n * The block header for a `key` node. AgentScript keys can be plain (`config`)\n * or named (`topic case_creation`, `start_agent customer_verification`).\n * We return the first whitespace-delimited token as the key kind, and the\n * remainder (if any) as the instance label.\n */\nexport function keyHeader(n: SyntaxNode): null | { kind: string; label?: string } {\n if (n.type !== 'key') return null;\n const head = n.text.split('\\n', 1)[0];\n const colon = head.indexOf(':');\n const lhs = (colon === -1 ? head : head.slice(0, colon)).trim();\n const parts = lhs.split(/\\s+/);\n return { kind: parts[0], label: parts.length > 1 ? parts.slice(1).join(' ') : undefined };\n}\n\n/**\n * The CST shapes a key/value pair as `mapping_element { key, ':', value }`.\n * Given the mapping_element node, return its key kind + label.\n */\nexport function mappingKeyHeader(m: SyntaxNode): null | { kind: string; label?: string } {\n if (m.type !== 'mapping_element') return null;\n const keyNode = m.childForFieldName('key');\n if (!keyNode) {\n // Fall back: first namedChild of type 'key'.\n for (const c of m.namedChildren) {\n if (c.type === 'key') return keyHeader(c);\n }\n\n return null;\n }\n\n return keyHeader(keyNode);\n}\n\n/**\n * The value-bearing child of a mapping_element. Could be `mapping` (sub-block),\n * `expression_with_to` (scalar/expression), `colinear_value`, `procedure`,\n * `variable_declaration`, etc.\n *\n * A mapping_element can interleave leading `comment` nodes between the `:`/`->`\n * markers and the actual value-bearing child. Skip them so we don't return a\n * comment as the \"value.\"\n */\nconst NON_VALUE_NAMED_TYPES = new Set(['comment', 'key']);\n\nexport function mappingValue(m: SyntaxNode): SyntaxNode | undefined {\n if (m.type !== 'mapping_element') return undefined;\n for (const c of m.namedChildren) {\n if (!NON_VALUE_NAMED_TYPES.has(c.type)) return c;\n }\n\n return undefined;\n}\n\n/**\n * Within a scope whose body is a `mapping` (the typical case for topic/\n * start_agent/subagent blocks), find the mapping_element whose key matches\n * `kind`, and return its value subtree.\n */\nexport function findMappingEntry(parentBody: SyntaxNode, kind: string): SyntaxNode | undefined {\n for (const c of parentBody.namedChildren) {\n if (c.type !== 'mapping_element') continue;\n const h = mappingKeyHeader(c);\n if (h && h.kind === kind) return mappingValue(c);\n }\n\n return undefined;\n}\n\n/**\n * Walk a scope-key node (topic / start_agent / subagent at top level) and\n * return its body \u2014 the `mapping` that holds before_reasoning, after_reasoning,\n * reasoning, actions, etc. The scope-key itself lives inside a mapping_element\n * at the source-file level; the body is the sibling value.\n */\nexport function bodyOf(scopeKey: SyntaxNode): SyntaxNode | undefined {\n const {parent} = scopeKey;\n if (!parent) return undefined;\n return mappingValue(parent);\n}\n\n/**\n * Read the `developer_name:` value from the `config:` block of a parsed\n * .agent file. This is the canonical API name of the agent (matches what\n * `sf agent generate authoring-bundle --api-name X` produces). Returns\n * undefined when the field is absent or empty.\n */\nexport function extractDeveloperName(root: SyntaxNode): string | undefined {\n const topMapping = root.namedChildren.find(c => c.type === 'mapping') ?? root;\n for (const c of topMapping.namedChildren) {\n if (c.type !== 'mapping_element') continue;\n const keyNode =\n c.childForFieldName('key') ?? c.namedChildren.find(n => n.type === 'key');\n if (!keyNode) continue;\n const h = keyHeader(keyNode);\n if (!h || h.kind !== 'config') continue;\n const body = mappingValue(c);\n if (!body) return undefined;\n const devNameVal = findMappingEntry(body, 'developer_name');\n if (!devNameVal) return undefined;\n return extractStringLiteral(devNameVal);\n }\n\n return undefined;\n}\n\n/** Convenience: extract a leaf string literal text (without surrounding quotes). */\nexport function extractStringLiteral(n: SyntaxNode): string | undefined {\n for (const d of descendants(n)) {\n if (d.type === 'string') {\n const t = d.text;\n if (t.startsWith('\"') && t.endsWith('\"')) return t.slice(1, -1);\n if (t.startsWith(\"'\") && t.endsWith(\"'\")) return t.slice(1, -1);\n return t;\n }\n }\n\n return undefined;\n}\n", "import type { SyntaxNode } from '@agentscript/types';\n\nimport type { AgentScope } from './complexity.js';\nimport type { ActionDeclaration, ActionReference, ActionTargetKind } from './types.js';\n\nimport {\n descendants,\n extractStringLiteral,\n findMappingEntry,\n locOf,\n mappingKeyHeader,\n mappingValue,\n} from './parse.js';\n\nconst TARGET_SCHEME = /^([a-z][a-z0-9+.-]*):\\/\\//i;\n\nfunction classifyTarget(uri: string | undefined): ActionTargetKind {\n if (!uri) return 'unknown';\n const m = TARGET_SCHEME.exec(uri);\n if (!m) return 'unknown';\n const scheme = m[1].toLowerCase();\n if (scheme === 'apex') return 'apex';\n if (scheme === 'flow') return 'flow';\n if (scheme.startsWith('prompt')) return 'prompt';\n return 'unknown';\n}\n\n/**\n * Within a scope body (the value of a `topic` or `start_agent`/`subagent`\n * mapping_element), the `actions:` entry holds a mapping of named action\n * declarations. Each declaration is itself a mapping with metadata fields\n * like `target:`, `label:`, `inputs:`, `outputs:`.\n */\nexport function collectDeclarations(scope: AgentScope): ActionDeclaration[] {\n const decls: ActionDeclaration[] = [];\n const actionsBlock = findMappingEntry(scope.body, 'actions');\n if (!actionsBlock) return decls;\n for (const child of actionsBlock.namedChildren) {\n if (child.type !== 'mapping_element') continue;\n const h = mappingKeyHeader(child);\n if (!h) continue;\n const declName = h.kind;\n const declBody = mappingValue(child);\n if (!declBody) {\n decls.push({\n location: locOf(child),\n name: declName,\n scope: scope.label,\n target: undefined,\n targetKind: 'unknown',\n });\n continue;\n }\n\n const targetVal = findMappingEntry(declBody, 'target');\n const targetStr = targetVal ? extractStringLiteral(targetVal) : undefined;\n decls.push({\n location: locOf(child),\n name: declName,\n scope: scope.label,\n target: targetStr,\n targetKind: classifyTarget(targetStr),\n });\n }\n\n return decls;\n}\n\n/**\n * Collect every member_expression of the form `@actions.X` *outside* the\n * `actions:` declaration block. We treat them as references \u2014 i.e. usages of\n * the declared actions in reasoning / before / after blocks.\n *\n * Context discrimination:\n * \u2022 inside reasoning > actions \u2192 'reasoning_actions'\n * \u2022 inside after_reasoning \u2192 'after_reasoning_run'\n * \u2022 inside before_reasoning \u2192 'before_reasoning_run'\n * \u2022 inside transition_statement \u2192 'transition'\n */\nexport function collectReferences(scope: AgentScope): ActionReference[] {\n const refs: ActionReference[] = [];\n\n const explore = (body: SyntaxNode | undefined, context: ActionReference['context']) => {\n if (!body) return;\n for (const n of descendants(body)) {\n if (n.type !== 'member_expression') continue;\n // member_expression text is the full chain (\"@actions.Foo[.Bar]\");\n // text matching is more robust than peeking through the wrapper\n // chain (expression \u2192 atom \u2192 at_id).\n if (!n.text.startsWith('@actions.')) continue;\n const name = actionNameFromMember(n);\n if (!name) continue;\n // Differentiate when we're inside a transition_statement.\n const ctx = isInsideTransition(n) ? 'transition' : context;\n refs.push({\n context: ctx,\n location: locOf(n),\n name,\n scope: scope.label,\n });\n }\n };\n\n explore(findMappingEntry(scope.body, 'before_reasoning'), 'before_reasoning_run');\n explore(findMappingEntry(scope.body, 'after_reasoning'), 'after_reasoning_run');\n const reasoning = findMappingEntry(scope.body, 'reasoning');\n if (reasoning) {\n // `reasoning.actions:` \u2014 the declarative action contract block;\n // refs here describe what the LLM is allowed to call.\n explore(findMappingEntry(reasoning, 'actions'), 'reasoning_actions');\n // `reasoning.instructions: ->` \u2014 refs here are `run @actions.X`\n // invocations the LLM evaluates as part of its instructions.\n // Per the whitepaper, these execute non-deterministically.\n explore(findMappingEntry(reasoning, 'instructions'), 'reasoning_instructions_run');\n }\n\n return refs;\n}\n\nfunction actionNameFromMember(n: SyntaxNode): string | undefined {\n // member_expression text is \"@actions.Foo_Bar\" \u2014 strip the prefix.\n const t = n.text;\n const dot = t.indexOf('.');\n if (dot === -1) return undefined;\n const rest = t.slice(dot + 1);\n // Take the leading identifier, in case of further chained access.\n const m = /^([A-Za-z_][A-Za-z0-9_]*)/.exec(rest);\n return m?.[1];\n}\n\nfunction isInsideTransition(n: SyntaxNode): boolean {\n let p = n.parent;\n while (p) {\n if (p.type === 'transition_statement') return true;\n p = p.parent;\n }\n\n return false;\n}\n", "import { readFile } from 'node:fs/promises';\nimport { basename, relative } from 'node:path';\n\nimport type {\n ApexClassReport,\n ApexMethodCC,\n FileReport,\n} from './types.js';\n\nimport { complexityOfMethod, methodsInCompilationUnit } from './apex-complexity.js';\nimport { parseApexSource } from './apex-parse.js';\nimport {\n extractApexClassName,\n resolveApexClassPath,\n} from './apex-resolve.js';\n\n/** Inputs needed to resolve and analyze every apex:// target in the bundle. */\nexport interface ApexAnalyzeInputs {\n /** Absolute paths of every .agent file analyzed, parallel to fileReports. */\n agentAbsPaths: string[];\n apexSourceOverride?: string;\n fileReports: FileReport[];\n sourceDirRoot: string;\n}\n\nexport interface ApexAnalyzeOutputs {\n classes: ApexClassReport[];\n unresolved: string[];\n}\n\nexport async function analyzeReferencedApex(\n inputs: ApexAnalyzeInputs,\n): Promise<ApexAnalyzeOutputs> {\n const byPath = new Map<string, ApexClassReport>();\n const unresolved = new Set<string>();\n\n for (let i = 0; i < inputs.fileReports.length; i++) {\n const fr = inputs.fileReports[i];\n const agentAbs = inputs.agentAbsPaths[i];\n for (const decl of fr.declarations) {\n if (decl.targetKind !== 'apex' || !decl.target) continue;\n const className = extractApexClassName(decl.target);\n if (!className) {\n unresolved.add(decl.target);\n continue;\n }\n\n const path = await resolveApexClassPath(className, {\n agentFilePath: agentAbs,\n apexSourceOverride: inputs.apexSourceOverride,\n sourceDirRoot: inputs.sourceDirRoot,\n });\n if (!path) {\n unresolved.add(decl.target);\n continue;\n }\n\n const existing = byPath.get(path);\n if (existing) {\n if (!existing.referencedBy.includes(fr.path)) {\n existing.referencedBy.push(fr.path);\n }\n\n continue;\n }\n\n const report = await analyzeApexClass(path, className, [fr.path], inputs.sourceDirRoot);\n byPath.set(path, report);\n }\n }\n\n return {\n classes: [...byPath.values()].sort((a, b) => a.className.localeCompare(b.className)),\n unresolved: [...unresolved].sort(),\n };\n}\n\nasync function analyzeApexClass(\n absPath: string,\n className: string,\n referencedBy: string[],\n sourceDirRoot: string,\n): Promise<ApexClassReport> {\n const source = await readFile(absPath, 'utf8');\n const cu = parseApexSource(source);\n const methodCtxs = methodsInCompilationUnit(cu);\n const methods: ApexMethodCC[] = methodCtxs.map((m) => complexityOfMethod(m));\n const classComplexity = methods.reduce((acc, m) => acc + m.complexity, 0);\n\n return {\n classComplexity,\n className: className || basename(absPath, '.cls'),\n methods,\n parseErrors: [],\n path: relative(sourceDirRoot, absPath),\n referencedBy,\n };\n}\n", "import {\n CatchClauseContext,\n type CompilationUnitContext,\n CondExpressionContext,\n ConstructorDeclarationContext,\n DoWhileStatementContext,\n type FormalParametersContext,\n ForStatementContext,\n IfStatementContext,\n LogAndExpressionContext,\n LogOrExpressionContext,\n MethodDeclarationContext,\n WhenControlContext,\n WhileStatementContext,\n} from '@apexdevtools/apex-parser';\n\nimport type {\n ApexCCContributor,\n ApexCCContributorKind,\n ApexMethodCC,\n} from './types.js';\n\nimport { type ApexRuleNode, locOfCtx, walkParseTree } from './apex-parse.js';\n\n/**\n * Standard McCabe Cyclomatic Complexity for Apex, per the SonarQube /\n * PMD CyclomaticComplexity convention used in the categorization\n * whitepaper \u00A7 7:\n *\n * CC = 1\n * + count(if)\n * + count(for) // includes enhanced-for (for-each)\n * + count(while)\n * + count(do-while)\n * + count(when arm) // each switch `when X { ... }`; `when else` excluded\n * + count(catch) // each catch clause\n * + count(ternary ?:)\n * + count(&&)\n * + count(||)\n *\n * Not counted: else, when else, finally, try itself.\n */\nexport function complexityOfMethod(\n methodCtx: ConstructorDeclarationContext | MethodDeclarationContext,\n): ApexMethodCC {\n const body = methodCtx.block();\n const contributors: ApexCCContributor[] = [];\n\n if (body) {\n walkParseTree(body, node => {\n // Don't descend into nested methods/constructors \u2014 they have their\n // own CC counted separately.\n if (\n node !== methodCtx &&\n (node instanceof MethodDeclarationContext ||\n node instanceof ConstructorDeclarationContext)\n ) {\n // walkParseTree will still recurse into this node's subtree.\n // We can't easily prune, so we filter by parentage: skip\n // contributors whose nearest enclosing method/ctor is not us.\n return;\n }\n\n const kind = classifyContributor(node);\n if (kind !== undefined && enclosingMethod(node) === methodCtx) {\n contributors.push({ kind, location: locOfCtx(node) });\n }\n });\n }\n\n const name =\n methodCtx instanceof ConstructorDeclarationContext\n ? methodCtx.qualifiedName()?.getText() ?? '<ctor>'\n : (methodCtx as MethodDeclarationContext).id()?.getText() ?? '<anon>';\n\n const signature = renderSignature(methodCtx, name);\n\n return {\n complexity: 1 + contributors.length,\n contributors,\n kind: methodCtx instanceof ConstructorDeclarationContext ? 'constructor' : 'method',\n location: locOfCtx(methodCtx),\n name,\n signature,\n };\n}\n\nfunction classifyContributor(node: ApexRuleNode): ApexCCContributorKind | undefined {\n if (node instanceof IfStatementContext) return 'if_statement';\n if (node instanceof ForStatementContext) return 'for_statement';\n if (node instanceof WhileStatementContext) return 'while_statement';\n if (node instanceof DoWhileStatementContext) return 'do_while_statement';\n if (node instanceof WhenControlContext) {\n // `when else { ... }` is the default arm \u2192 don't count it.\n const wv = node.whenValue();\n const elseTok = wv && typeof wv.ELSE === 'function' ? wv.ELSE() : undefined;\n return elseTok ? undefined : 'when_arm';\n }\n\n if (node instanceof CatchClauseContext) return 'catch_clause';\n if (node instanceof CondExpressionContext) return 'ternary';\n if (node instanceof LogAndExpressionContext) return 'short_circuit_and';\n if (node instanceof LogOrExpressionContext) return 'short_circuit_or';\n return undefined;\n}\n\nfunction enclosingMethod(\n node: ApexRuleNode,\n): ConstructorDeclarationContext | MethodDeclarationContext | undefined {\n let p: ApexRuleNode | undefined = node.parentCtx;\n while (p) {\n if (p instanceof MethodDeclarationContext || p instanceof ConstructorDeclarationContext) {\n return p;\n }\n\n p = p.parentCtx;\n }\n\n return undefined;\n}\n\nfunction renderSignature(\n ctx: ConstructorDeclarationContext | MethodDeclarationContext,\n name: string,\n): string {\n const paramsText = renderFormalParameters(ctx.formalParameters());\n if (ctx instanceof MethodDeclarationContext) {\n const retType = ctx.typeRef()?.getText() ?? (ctx.VOID() ? 'void' : '');\n return `${retType ? retType + ' ' : ''}${name}${paramsText}`;\n }\n\n return `${name}${paramsText}`;\n}\n\n/**\n * ANTLR's `getText()` concatenates child tokens with no whitespace, which\n * mangles parameter lists like `List<Request> requests` into\n * `List<Request>requests`. Walk the structured children and rebuild a\n * properly-spaced signature.\n */\nfunction renderFormalParameters(params: FormalParametersContext | null): string {\n if (!params) return '()';\n const list = params.formalParameterList();\n if (!list) return '()';\n const parts = list.formalParameter_list().map(p => {\n const type = p.typeRef()?.getText() ?? '';\n const id = p.id()?.getText() ?? '';\n return type && id ? `${type} ${id}` : type || id;\n });\n return `(${parts.join(', ')})`;\n}\n\n/**\n * Enumerate every method and constructor in a compilation unit, including\n * those nested inside inner classes. Each gets its own CC entry per the\n * v2 scope (\"all methods in any class touched by apex://\").\n */\nexport function methodsInCompilationUnit(cu: CompilationUnitContext): Array<\n ConstructorDeclarationContext | MethodDeclarationContext\n> {\n const out: Array<ConstructorDeclarationContext | MethodDeclarationContext> = [];\n walkParseTree(cu, node => {\n if (\n (node instanceof MethodDeclarationContext ||\n node instanceof ConstructorDeclarationContext) &&\n node.block()\n ) {\n out.push(node);\n }\n });\n return out;\n}\n", "import {\n ApexParserFactory,\n CompilationUnitContext,\n} from '@apexdevtools/apex-parser';\n\n/**\n * Structural view of an ANTLR parse-tree node covering only the members this\n * analyzer touches. `@apexdevtools/apex-parser` 5.x ships generated context\n * types that extend antlr4's `ParserRuleContext`, but antlr4 4.13.x does not\n * surface `ParserRuleContext` (nor its inherited `getText`/`getChild`) through\n * its NodeNext `.d.cts` re-export chain, so importing it directly fails to\n * resolve. We model the contract locally instead \u2014 the runtime objects carry\n * all of these methods.\n */\nexport interface ApexRuleNode {\n getChild(i: number): unknown;\n getChildCount(): number;\n getText(): string;\n parentCtx?: ApexRuleNode | undefined;\n start?: { column?: number; line?: number; text?: string };\n stop?: { column?: number; line?: number; text?: string };\n}\n\nexport function parseApexSource(source: string): CompilationUnitContext {\n const parser = ApexParserFactory.createParser(source);\n return parser.compilationUnit();\n}\n\nexport function locOfCtx(ctx: ApexRuleNode) {\n const {start} = ctx;\n const stop = ctx.stop ?? ctx.start;\n return {\n endCol: (stop?.column ?? 0) + (stop?.text?.length ?? 0),\n endRow: stop?.line ?? 0,\n startCol: start?.column ?? 0,\n startRow: start?.line ?? 0,\n };\n}\n\n/**\n * Walk an ANTLR parse-tree node depth-first, invoking the visitor on every\n * descendant (including the start node). Terminal/error nodes have no\n * children and are visited like any other node \u2014 caller filters by type.\n */\nexport function walkParseTree(\n node: ApexRuleNode,\n visit: (n: ApexRuleNode) => void,\n): void {\n visit(node);\n const childCount =\n typeof node.getChildCount === 'function' ? node.getChildCount() : 0;\n for (let i = 0; i < childCount; i++) {\n const c = node.getChild(i);\n // Filter to ParserRuleContext children only \u2014 terminals don't carry rules.\n if (c && typeof (c as ApexRuleNode).getChildCount === 'function') {\n walkParseTree(c as ApexRuleNode, visit);\n }\n }\n}\n", "import { stat } from 'node:fs/promises';\nimport { dirname, isAbsolute, join, resolve, sep } from 'node:path';\n\nconst APEX_SCHEME = /^apex:\\/\\/(.+)$/;\n\nexport function extractApexClassName(uri: string): string | undefined {\n const m = APEX_SCHEME.exec(uri);\n if (!m) return undefined;\n // `apex://Foo` or `apex://namespace__Foo`; take the trailing simple name.\n const raw = m[1].trim();\n const dot = raw.lastIndexOf('.');\n return dot === -1 ? raw : raw.slice(dot + 1);\n}\n\nexport interface ResolveOptions {\n /**\n * The .agent file that holds the apex:// reference. Used as the seed for\n * the upward walk.\n */\n agentFilePath: string;\n /**\n * Optional `--apex-source` override. When set, classes are looked up here\n * before falling back to the upward walk.\n */\n apexSourceOverride?: string;\n /**\n * The CLI `--source-dir` value. We never walk above this directory.\n */\n sourceDirRoot: string;\n}\n\n/**\n * Find `classes/<ClassName>.cls` by walking up from the .agent file. The walk\n * stops at the CLI's source-dir root so we never escape it. Returns the\n * absolute path or undefined.\n *\n * Path conventions covered:\n * - sfdx default: <pkg>/main/default/classes/<X>.cls, with the .agent in\n * <pkg>/main/default/aiAuthoringBundles/<Bundle>/<X>.agent\n * - flat fixtures: <root>/classes/<X>.cls, with .agent under\n * <root>/aiAuthoringBundles/<Bundle>/<X>.agent\n * - explicit override: --apex-source <dir>/<X>.cls\n */\nexport async function resolveApexClassPath(\n className: string,\n opts: ResolveOptions,\n): Promise<string | undefined> {\n const candidates: string[] = [];\n\n if (opts.apexSourceOverride) {\n const override = isAbsolute(opts.apexSourceOverride)\n ? opts.apexSourceOverride\n : resolve(opts.apexSourceOverride);\n candidates.push(\n join(override, `${className}.cls`),\n join(override, 'classes', `${className}.cls`),\n );\n }\n\n const stop = resolve(opts.sourceDirRoot);\n let dir = dirname(resolve(opts.agentFilePath));\n while (true) {\n candidates.push(join(dir, 'classes', `${className}.cls`));\n if (dir === stop) break;\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n\n for (const c of candidates) {\n const s = await stat(c).catch(() => {});\n if (s?.isFile()) return c;\n }\n\n return undefined;\n}\n\n/** True if `child` is the same as or a subpath of `parent` (path-segment safe). */\nexport function isUnder(child: string, parent: string): boolean {\n const c = resolve(child);\n const p = resolve(parent);\n if (c === p) return true;\n return c.startsWith(p.endsWith(sep) ? p : p + sep);\n}\n", "import type { SyntaxNode } from '@agentscript/types';\n\nimport type { CCContributor, ProcedureCC, SourceLocation } from './types.js';\n\nimport { bodyOf, descendants, findMappingEntry, keyHeader, locOf } from './parse.js';\n\n/**\n * Standard McCabe CC, applied to AgentScript control-flow nodes.\n *\n * Per the categorization whitepaper (\u00A7 7) the convention mirrors\n * SonarQube/PMD/Checkstyle for the relevant language:\n *\n * CC = 1\n * + count(if_statement)\n * + count(elif_clause)\n * + count(ternary_expression)\n * + count(binary_expression where operator \u2208 {and, or})\n *\n * We do NOT count: else_clause, comparison_expression, set/run/transition,\n * try/catch (AgentScript has none), default branches.\n */\nconst SHORT_CIRCUIT_OPS = new Set(['and', 'or']);\n\nexport function complexityOf(body: SyntaxNode, scope: string, kind: ProcedureCC['kind']): ProcedureCC {\n const contributors: CCContributor[] = [];\n for (const n of descendants(body)) {\n switch (n.type) {\n case 'binary_expression': {\n const op = binaryOperator(n);\n if (op === 'and') contributors.push({ kind: 'short_circuit_and', location: locOf(n) });\n else if (op === 'or') contributors.push({ kind: 'short_circuit_or', location: locOf(n) });\n break;\n }\n\n case 'elif_clause': {\n contributors.push({ kind: 'elif_clause', location: locOf(n) });\n break;\n }\n\n case 'if_statement': {\n contributors.push({ kind: 'if_statement', location: locOf(n) });\n break;\n }\n\n case 'ternary_expression': {\n contributors.push({ kind: 'ternary_expression', location: locOf(n) });\n break;\n }\n }\n }\n\n return {\n complexity: 1 + contributors.length,\n contributors,\n kind,\n location: locOf(body),\n scope,\n };\n}\n\nfunction binaryOperator(n: SyntaxNode): string | undefined {\n for (const c of n.children) {\n if (!c.isNamed && SHORT_CIRCUIT_OPS.has(c.type)) return c.type;\n if (!c.isNamed && (c.type === '+' || c.type === '-' || c.type === '*' || c.type === '/')) return c.type;\n }\n\n return undefined;\n}\n\n/**\n * Identify the procedure-bearing blocks in a single topic / start_agent /\n * subagent scope. AgentScript's three control-flow surfaces are:\n * \u2022 before_reasoning: <procedure> (deterministic, pre-LLM)\n * \u2022 after_reasoning: <procedure> (deterministic, post-LLM)\n * \u2022 reasoning.instructions: -> <template body> (LLM-evaluated)\n *\n * v1 walks all three for CC. (instructions: -> body holds Reasoning Logic per\n * whitepaper \u00A7 4 but the CC convention itself is language-neutral.)\n */\nexport function collectProcedures(scopeBody: SyntaxNode, scopeLabel: string): ProcedureCC[] {\n const out: ProcedureCC[] = [];\n\n const before = findMappingEntry(scopeBody, 'before_reasoning');\n if (before) out.push(complexityOf(before, scopeLabel, 'before_reasoning'));\n\n const after = findMappingEntry(scopeBody, 'after_reasoning');\n if (after) out.push(complexityOf(after, scopeLabel, 'after_reasoning'));\n\n const reasoning = findMappingEntry(scopeBody, 'reasoning');\n if (reasoning) {\n const instructions = findMappingEntry(reasoning, 'instructions');\n if (instructions) {\n out.push(complexityOf(instructions, scopeLabel, 'reasoning_instructions'));\n }\n }\n\n return out;\n}\n\n/** Scopes that contain procedure-bearing blocks. */\nconst PROCEDURE_SCOPES = new Set(['start_agent', 'subagent', 'topic']);\n\nexport interface AgentScope {\n body: SyntaxNode;\n kind: string;\n label: string;\n}\n\n/**\n * Find topic/start_agent/subagent scopes anywhere in the tree. They appear\n * at the source-file level as mapping_elements whose key kind matches.\n */\nexport function collectScopes(root: SyntaxNode): AgentScope[] {\n const scopes: AgentScope[] = [];\n // The source_file has a single top-level `mapping` child holding the agent\n // declarations (system, config, variables, start_agent X, topic Y, \u2026).\n const topMapping = root.namedChildren.find(c => c.type === 'mapping') ?? root;\n for (const c of topMapping.namedChildren) {\n if (c.type !== 'mapping_element') continue;\n const keyNode = c.childForFieldName('key') ?? c.namedChildren.find(n => n.type === 'key');\n if (!keyNode) continue;\n const h = keyHeader(keyNode);\n if (!h || !PROCEDURE_SCOPES.has(h.kind)) continue;\n const body = bodyOf(keyNode);\n if (!body) continue;\n scopes.push({ body, kind: h.kind, label: `${h.kind} ${h.label ?? ''}`.trim() });\n }\n\n return scopes;\n}\n\nexport interface FileComplexity {\n procedures: ProcedureCC[];\n total: number;\n}\n\nexport function complexityForFile(root: SyntaxNode): FileComplexity {\n const procedures: ProcedureCC[] = [];\n for (const s of collectScopes(root)) {\n procedures.push(...collectProcedures(s.body, s.label));\n }\n\n const total = procedures.reduce((acc, p) => acc + p.complexity, 0);\n return { procedures, total };\n}\n\nexport function dummyLoc(): SourceLocation {\n return { endCol: 0, endRow: 0, startCol: 0, startRow: 0 };\n}\n", "import { Flags, SfCommand } from '@salesforce/sf-plugins-core';\n\nimport type { AnalysisReport } from '../../analyzer/types.js';\nimport type { RenderFormat } from '../../renderers/index.js';\n\nimport { analyzeSource } from '../../analyzer/analyze.js';\nimport { discoverSfdxProject } from '../../analyzer/project.js';\nimport { render } from '../../renderers/index.js';\n\nconst FORMATS: ReadonlyArray<RenderFormat> = ['text', 'markdown', 'sarif', 'csv'];\n\nexport default class AgentpmdAnalyze extends SfCommand<AnalysisReport> {\n public static readonly description = `Walks .agent source files under --source-dir and emits per-procedure\ncyclomatic complexity totals (before_reasoning, after_reasoning, and\nreasoning.instructions blocks), plus an inventory of declared and used\n@actions.X targets. For every apex:// target, resolves the .cls file\nand computes per-method Apex CC.\n\nDefault output is human-readable text. --json emits the SF CLI envelope\nwith the full structured report. --format <markdown|sarif|csv> emits the\nnamed format on stdout for piping into PR comments, GitHub Code Scanning,\nor spreadsheet pivots.`;\npublic static readonly examples = [\n '<%= config.bin %> <%= command.id %> --source-dir force-app/main/default',\n '<%= config.bin %> <%= command.id %> --source-dir force-app/main/default --json',\n '<%= config.bin %> <%= command.id %> --source-dir force-app/main/default --format markdown > report.md',\n '<%= config.bin %> <%= command.id %> --source-dir force-app/main/default --format sarif > report.sarif',\n ];\npublic static readonly flags = {\n 'apex-source': Flags.string({\n summary:\n 'Override directory to look up apex:// targets. By default we walk up from each .agent file looking for a sibling classes/ folder.',\n }),\n 'api-name': Flags.string({\n char: 'n',\n multiple: true,\n summary:\n 'Filter to specific agent bundles. Matched against the bundle directory name and the config.developer_name field. Repeatable.',\n }),\n ascii: Flags.boolean({\n default: false,\n summary:\n 'Force ASCII-only output in the text renderer (no Unicode box chars, no emoji).',\n }),\n 'fail-on': Flags.integer({\n min: 1,\n summary:\n 'Exit non-zero if combined agent+Apex CC meets or exceeds this threshold.',\n }),\n format: Flags.string({\n default: 'text',\n options: [...FORMATS],\n summary:\n 'Non-JSON output format. --json takes precedence per SF CLI convention.',\n }),\n 'no-color': Flags.boolean({\n default: false,\n summary: 'Disable ANSI color in the text renderer. NO_COLOR env also disables.',\n }),\n 'sarif-error': Flags.integer({\n min: 1,\n summary: 'SARIF \"error\" level threshold. Default 20.',\n }),\n 'sarif-warning': Flags.integer({\n min: 1,\n summary: 'SARIF \"warning\" level threshold. Default 10.',\n }),\n 'source-dir': Flags.string({\n char: 'd',\n summary:\n 'Directory or single .agent file to analyze. Defaults to the packageDirectories of the nearest sfdx-project.json.',\n }),\n width: Flags.integer({\n default: 60,\n min: 20,\n summary: 'Rule width for the text renderer.',\n }),\n };\npublic static readonly summary =\n 'Compute McCabe cyclomatic complexity and action-reference inventory for AgentScript bundles and their Apex backing logic.';\n\n public async run(): Promise<AnalysisReport> {\n const { flags } = await this.parse(AgentpmdAnalyze);\n\n const { reportBase, roots, sourceDescription } = await resolveSources(\n flags['source-dir'],\n );\n if (!this.jsonEnabled() && sourceDescription) {\n this.log(sourceDescription);\n }\n\n const report = await analyzeSource(roots, {\n apexSourceOverride: flags['apex-source'],\n apiNames: flags['api-name'],\n reportBase,\n });\n\n if (!this.jsonEnabled()) {\n const format = flags.format as RenderFormat;\n const text = render(format, report, {\n ascii: flags.ascii || undefined,\n color: flags['no-color'] ? false : undefined,\n sarifErrorThreshold: flags['sarif-error'],\n sarifWarningThreshold: flags['sarif-warning'],\n width: flags.width,\n });\n this.log(text);\n }\n\n const combined = report.totalComplexity + report.totalApexComplexity;\n if (flags['fail-on'] !== undefined && combined >= flags['fail-on']) {\n this.error(\n `Combined cyclomatic complexity ${combined} (agent ${report.totalComplexity} + apex ${report.totalApexComplexity}) \u2265 threshold ${flags['fail-on']}`,\n { exit: 2 },\n );\n }\n\n return report;\n }\n}\n\ninterface ResolvedSources {\n reportBase: string | undefined;\n roots: string[];\n /** Optional human-readable note about where sources came from. */\n sourceDescription?: string;\n}\n\n/**\n * Resolve the directories we should scan. Explicit `--source-dir` wins.\n * Otherwise, walk up from cwd looking for `sfdx-project.json` and use its\n * `packageDirectories`. If neither is available, fail with a clear message.\n */\nasync function resolveSources(\n sourceDirFlag: string | undefined,\n): Promise<ResolvedSources> {\n if (sourceDirFlag) {\n return { reportBase: undefined, roots: [sourceDirFlag] };\n }\n\n const project = await discoverSfdxProject(process.cwd());\n if (!project) {\n throw new Error(\n 'No --source-dir was provided and no sfdx-project.json was found in the ' +\n 'current directory or any ancestor. Pass --source-dir <path> or run from ' +\n 'inside an sfdx project.',\n );\n }\n\n if (project.packageDirectories.length === 0) {\n throw new Error(\n `sfdx-project.json at ${project.root} declares no packageDirectories. ` +\n 'Pass --source-dir <path> explicitly.',\n );\n }\n\n return {\n reportBase: project.root,\n roots: project.packageDirectories,\n sourceDescription: `Analyzing sfdx project ${project.root} (${project.packageDirectories.length} package director${project.packageDirectories.length === 1 ? 'y' : 'ies'}).`,\n };\n}\n", "import { readFile, stat } from 'node:fs/promises';\nimport { dirname, isAbsolute, join, resolve } from 'node:path';\n\nexport interface SfdxProject {\n /** Absolute paths of every `packageDirectories[].path`, in declaration order. */\n packageDirectories: string[];\n /** Absolute path of the project root (the directory containing sfdx-project.json). */\n root: string;\n}\n\n/**\n * Walk up from `startDir` until we find a directory containing\n * `sfdx-project.json`, then return its root + resolved package directories.\n * Returns undefined when no project is found.\n */\nexport async function discoverSfdxProject(\n startDir: string,\n): Promise<SfdxProject | undefined> {\n let dir = resolve(startDir);\n while (true) {\n const candidate = join(dir, 'sfdx-project.json');\n const s = await stat(candidate).catch(() => {});\n if (s?.isFile()) {\n return readProject(dir, candidate);\n }\n\n const parent = dirname(dir);\n if (parent === dir) return undefined;\n dir = parent;\n }\n}\n\nasync function readProject(root: string, jsonPath: string): Promise<SfdxProject> {\n const raw = await readFile(jsonPath, 'utf8');\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch (error) {\n throw new Error(\n `failed to parse ${jsonPath}: ${(error as Error).message}`,\n );\n }\n\n const pkgs = extractPackageDirectories(parsed, root);\n return { packageDirectories: pkgs, root };\n}\n\nfunction extractPackageDirectories(parsed: unknown, root: string): string[] {\n if (!parsed || typeof parsed !== 'object') return [];\n const obj = parsed as { packageDirectories?: unknown };\n if (!Array.isArray(obj.packageDirectories)) return [];\n const out: string[] = [];\n for (const entry of obj.packageDirectories) {\n if (!entry || typeof entry !== 'object') continue;\n const pathField = (entry as { path?: unknown }).path;\n if (typeof pathField !== 'string' || pathField.length === 0) continue;\n out.push(isAbsolute(pathField) ? pathField : resolve(root, pathField));\n }\n\n return out;\n}\n", "import type {\n AnalysisReport,\n ApexCCContributor,\n CCContributor,\n} from '../analyzer/types.js';\n\n/**\n * Single CSV with all per-procedure and per-method rows so a spreadsheet\n * can pivot on `type` and `file`. RFC 4180-quoted; first row is the header.\n */\nexport function renderCsv(report: AnalysisReport): string {\n const lines: string[] = [];\n lines.push(\n [\n 'type',\n 'file',\n 'scope_or_class',\n 'name',\n 'complexity',\n 'start_row',\n 'start_col',\n 'contributors',\n ]\n .map((c) => csvCell(c))\n .join(','),\n );\n\n for (const f of report.files) {\n for (const p of f.procedures) {\n lines.push(\n [\n 'agent_procedure',\n f.path,\n p.scope,\n p.kind,\n String(p.complexity),\n String(p.location.startRow),\n String(p.location.startCol),\n breakdownProc(p.contributors),\n ]\n .map((c) => csvCell(c))\n .join(','),\n );\n }\n }\n\n for (const cls of report.apexClasses) {\n for (const m of cls.methods) {\n lines.push(\n [\n 'apex_method',\n cls.path,\n cls.className,\n m.signature,\n String(m.complexity),\n String(m.location.startRow),\n String(m.location.startCol),\n breakdownApex(m.contributors),\n ]\n .map((c) => csvCell(c))\n .join(','),\n );\n }\n }\n\n return lines.join('\\n');\n}\n\nfunction csvCell(v: string): string {\n // Always quote \u2014 keeps the output uniform and lets cells contain\n // commas, quotes, and newlines without per-cell branching.\n return `\"${v.replaceAll('\"', '\"\"')}\"`;\n}\n\nfunction breakdownProc(contributors: CCContributor[]): string {\n if (contributors.length === 0) return 'base';\n const counts: Record<string, number> = {};\n for (const c of contributors) counts[c.kind] = (counts[c.kind] ?? 0) + 1;\n return Object.entries(counts)\n .map(([k, n]) => `${k}=${n}`)\n .join(';');\n}\n\nfunction breakdownApex(contributors: ApexCCContributor[]): string {\n if (contributors.length === 0) return 'base';\n const counts: Record<string, number> = {};\n for (const c of contributors) counts[c.kind] = (counts[c.kind] ?? 0) + 1;\n return Object.entries(counts)\n .map(([k, n]) => `${k}=${n}`)\n .join(';');\n}\n", "import type {\n AnalysisReport,\n ApexCCContributor,\n \n CCContributor,\n FileReport,\n ProcedureCC,\n} from '../analyzer/types.js';\n\nconst KIND_LABEL: Record<ProcedureCC['kind'], string> = {\n after_reasoning: 'after_reasoning',\n available_when: 'available_when',\n before_reasoning: 'before_reasoning',\n other: 'other',\n reasoning_instructions: 'reasoning.instructions',\n};\n\n/**\n * Renders a GFM Markdown report with a Mermaid bar chart at the top\n * (agent CC vs Apex CC per bundle) followed by per-bundle and per-class\n * drilldown tables. Designed to be portable into PR descriptions, gists,\n * Slack snippets, and whitepaper appendices.\n *\n * Palette is whitepaper \u00A7 1: Reasoning hot (#a82820), Conversation amber\n * (#c4942a), Deterministic green (#6b8c52), Scaffolding cool gray (#9aa5ad).\n */\nexport function renderMarkdown(report: AnalysisReport): string {\n const lines: string[] = [];\n lines.push('# AgentForce PMD \u2014 Cyclomatic Complexity (McCabe)', '', \n 'Per the categorization rule \u00A7 7, CC is reported by the standard ' +\n 'McCabe convention used in SonarQube / PMD / Checkstyle for the ' +\n 'relevant language.', ''\n );\n\n if (report.files.length === 0) {\n lines.push('_(no `.agent` files found)_');\n return lines.join('\\n');\n }\n\n // \u2500\u2500 CC by location chart \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n lines.push('## CC by location', '',\n renderMermaid(report), '',\n `| | AgentScript | Apex | Combined |\\n` +\n `| --- | ---: | ---: | ---: |\\n` +\n `| **Totals** | ${report.totalComplexity} | ${report.totalApexComplexity} | ${report.totalComplexity + report.totalApexComplexity} |`, ''\n , '## Per-bundle (`.agent` files)', '');\n for (const f of report.files) {\n lines.push(`### \\`${f.path}\\` \u2014 CC = ${f.fileComplexity}`, '');\n if (f.procedures.length === 0) {\n lines.push('_(no procedure-bearing scopes)_');\n } else {\n lines.push('| Scope | Procedure | CC | Contributors |', '| --- | --- | ---: | --- |');\n for (const p of f.procedures) {\n lines.push(\n `| ${escapeCell(p.scope)} | ${KIND_LABEL[p.kind]} | ${p.complexity} | ${escapeCell(breakdownProc(p.contributors))} |`,\n );\n }\n }\n\n lines.push('');\n\n if (f.declarations.length > 0) {\n lines.push('**Action references**', '', '| Action | Target kind | Target | Uses |', '| --- | --- | --- | ---: |');\n const usage = countReferences(f);\n for (const d of f.declarations) {\n const used = usage.get(d.name) ?? 0;\n lines.push(\n `| \\`${d.name}\\` | ${d.targetKind} | ${d.target ?? '_n/a_'} | ${used} |`,\n );\n }\n\n const undeclared = listUndeclaredRefs(f);\n if (undeclared.length > 0) {\n lines.push(\n '',\n 'Referenced but not declared in-file: ' + undeclared.map(u => `\\`${u}\\``).join(', '),\n );\n }\n\n lines.push('');\n }\n }\n\n // \u2500\u2500 Apex backing logic \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n if (report.apexClasses.length > 0 || report.unresolvedApexTargets.length > 0) {\n lines.push('## Apex backing logic', '');\n for (const cls of report.apexClasses) {\n lines.push(\n `### \\`${cls.path}\\` \u2014 class CC = ${cls.classComplexity}`, '',\n `Referenced by: ${cls.referencedBy.map(r => `\\`${r}\\``).join(', ') || '_none_'}`, '',\n );\n if (cls.methods.length === 0) {\n lines.push('_(no methods with bodies)_');\n } else {\n lines.push('| Method | CC | Contributors |', '| --- | ---: | --- |');\n for (const m of cls.methods) {\n lines.push(\n `| \\`${escapeCell(m.signature)}\\` | ${m.complexity} | ${escapeCell(breakdownApex(m.contributors))} |`,\n );\n }\n }\n\n lines.push('');\n }\n\n if (report.unresolvedApexTargets.length > 0) {\n lines.push('### Unresolved `apex://` targets', '');\n for (const u of report.unresolvedApexTargets) {\n lines.push(`- \\`${u}\\` \u2014 no matching \\`.cls\\` under \\`--source-dir\\` or \\`--apex-source\\``);\n }\n\n lines.push('');\n }\n }\n\n // \u2500\u2500 Footer \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n lines.push('---', '', \n `Action declarations: **${report.totalDeclarations}** ` +\n `(apex ${report.byTargetKind.apex}, flow ${report.byTargetKind.flow}, ` +\n `prompt ${report.byTargetKind.prompt}, unknown ${report.byTargetKind.unknown}). ` +\n `Action references: **${report.totalReferences}**.`,\n );\n\n return lines.join('\\n');\n}\n\nfunction renderMermaid(report: AnalysisReport): string {\n // Per-bundle agent CC + the sum of Apex CC for classes that bundle\n // references. We compute that mapping rather than counting classes\n // globally so each bundle's bar reflects its full \"implementation\n // CC\" footprint.\n const apexByBundle = new Map<string, number>();\n for (const cls of report.apexClasses) {\n for (const ref of cls.referencedBy) {\n apexByBundle.set(ref, (apexByBundle.get(ref) ?? 0) + cls.classComplexity);\n }\n }\n\n const labels: string[] = [];\n const agentVals: number[] = [];\n const apexVals: number[] = [];\n for (const f of report.files) {\n labels.push(shortBundleLabel(f.path));\n agentVals.push(f.fileComplexity);\n apexVals.push(apexByBundle.get(f.path) ?? 0);\n }\n\n // Mermaid xychart-beta supports stacked-bar style via two series.\n // Palette: AgentScript = Reasoning red (#a82820); Apex = Deterministic green (#6b8c52).\n return [\n '```mermaid',\n '%%{init: {\"theme\":\"base\",\"themeVariables\":{\"xyChart\":{\"plotColorPalette\":\"#a82820, #6b8c52\"}}}}%%',\n 'xychart-beta',\n ' title \"CC by location, per .agent bundle\"',\n ` x-axis [${labels.map(l => `\"${l}\"`).join(', ')}]`,\n ` y-axis \"Cyclomatic complexity\"`,\n ` bar [${agentVals.join(', ')}]`,\n ` bar [${apexVals.join(', ')}]`,\n '```',\n '',\n '<sub>Series: **AgentScript CC** (red, whitepaper \"Reasoning Logic\") \u00B7 **Apex CC** (green, whitepaper \"Deterministic Logic\"). Apex CC per bundle is the sum of the CC of every `apex://` class that bundle references; classes referenced by multiple bundles contribute to each.</sub>',\n ].join('\\n');\n}\n\nfunction shortBundleLabel(path: string): string {\n // Strip \"aiAuthoringBundles/\" and the trailing \".agent\" to keep x-axis tight.\n const stripped = path\n .replace(/^.*aiAuthoringBundles\\//, '')\n .replace(/\\.agent$/, '');\n // Use only the basename if it appears twice (Bundle/Bundle.agent \u2192 Bundle).\n const parts = stripped.split('/');\n if (parts.length === 2 && parts[0] === parts[1]) return parts[0];\n return parts.join('/');\n}\n\nfunction breakdownProc(contributors: CCContributor[]): string {\n if (contributors.length === 0) return '(base only)';\n const counts: Record<string, number> = {};\n for (const c of contributors) counts[c.kind] = (counts[c.kind] ?? 0) + 1;\n return Object.entries(counts)\n .map(([k, n]) => `${shortKind(k)}=${n}`)\n .join(' ');\n}\n\nfunction breakdownApex(contributors: ApexCCContributor[]): string {\n if (contributors.length === 0) return '(base only)';\n const counts: Record<string, number> = {};\n for (const c of contributors) counts[c.kind] = (counts[c.kind] ?? 0) + 1;\n return Object.entries(counts)\n .map(([k, n]) => `${shortApexKind(k)}=${n}`)\n .join(' ');\n}\n\nfunction shortKind(k: string): string {\n switch (k) {\n case 'elif_clause': {\n return 'elif';\n }\n\n case 'if_statement': {\n return 'if';\n }\n\n case 'short_circuit_and': {\n return 'and';\n }\n\n case 'short_circuit_or': {\n return 'or';\n }\n\n case 'ternary_expression': {\n return 'ternary';\n }\n\n default: {\n return k;\n }\n }\n}\n\nfunction shortApexKind(k: string): string {\n switch (k) {\n case 'catch_clause': {\n return 'catch';\n }\n\n case 'do_while_statement': {\n return 'do-while';\n }\n\n case 'for_statement': {\n return 'for';\n }\n\n case 'if_statement': {\n return 'if';\n }\n\n case 'short_circuit_and': {\n return '&&';\n }\n\n case 'short_circuit_or': {\n return '||';\n }\n\n case 'ternary': {\n return 'ternary';\n }\n\n case 'when_arm': {\n return 'when';\n }\n\n case 'while_statement': {\n return 'while';\n }\n\n default: {\n return k;\n }\n }\n}\n\nfunction countReferences(f: FileReport): Map<string, number> {\n const m = new Map<string, number>();\n for (const r of f.references) m.set(r.name, (m.get(r.name) ?? 0) + 1);\n return m;\n}\n\nfunction listUndeclaredRefs(f: FileReport): string[] {\n const declared = new Set(f.declarations.map(d => d.name));\n const seen = new Set<string>();\n const out: string[] = [];\n for (const r of f.references) {\n if (declared.has(r.name)) continue;\n if (seen.has(r.name)) continue;\n seen.add(r.name);\n out.push(r.name);\n }\n\n return out;\n}\n\nfunction escapeCell(s: string): string {\n // GFM table cells: escape pipes and turn embedded newlines into <br>.\n return s.replaceAll('|', String.raw`\\|`).replaceAll('\\n', '<br>');\n}\n\n// re-export for tree-shaking unused warnings; ApexClassReport is referenced\n// indirectly via report.apexClasses[number].\n\n\nexport {type ApexClassReport} from '../analyzer/types.js';", "import type {\n AnalysisReport,\n ApexClassReport,\n ApexMethodCC,\n FileReport,\n ProcedureCC,\n} from '../analyzer/types.js';\nimport type { RenderOptions } from './options.js';\n\ninterface SarifLog {\n $schema: 'https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json';\n runs: SarifRun[];\n version: '2.1.0';\n}\n\ninterface SarifRun {\n results: SarifResult[];\n tool: { driver: SarifDriver };\n}\n\ninterface SarifDriver {\n informationUri: string;\n name: 'sf-agentpmd';\n rules: SarifRule[];\n semanticVersion: string;\n}\n\ninterface SarifRule {\n defaultConfiguration?: { level: 'error' | 'note' | 'warning' };\n fullDescription: { text: string };\n helpUri?: string;\n id: string;\n name: string;\n shortDescription: { text: string };\n}\n\ninterface SarifResult {\n level: 'error' | 'note' | 'warning';\n locations: SarifLocation[];\n message: { text: string };\n properties: { complexity: number; kind: string };\n ruleId: string;\n}\n\ninterface SarifLocation {\n physicalLocation: {\n artifactLocation: { uri: string };\n region: { endColumn: number; endLine: number; startColumn: number; startLine: number; };\n };\n}\n\nconst DEFAULT_WARNING = 10;\nconst DEFAULT_ERROR = 20;\n\nconst RULE_AGENT_CC: SarifRule = {\n defaultConfiguration: { level: 'note' },\n fullDescription: {\n text:\n 'Reports cyclomatic complexity (McCabe) of an AgentScript before_reasoning, ' +\n 'after_reasoning, or reasoning.instructions block. Computed as 1 + ' +\n 'count(if) + count(elif) + count(ternary) + count(and) + count(or).',\n },\n helpUri:\n 'https://github.com/bobbywhitesfdc/sf-agentpmd/blob/main/docs/agent-loc-categorization-skill-v2.md#-7--cyclomatic-complexity',\n id: 'AGENTPMD.AgentScriptCyclomaticComplexity',\n name: 'AgentScriptCyclomaticComplexity',\n shortDescription: {\n text: 'McCabe cyclomatic complexity of an AgentScript procedure.',\n },\n};\n\nconst RULE_APEX_CC: SarifRule = {\n defaultConfiguration: { level: 'note' },\n fullDescription: {\n text:\n 'Reports cyclomatic complexity (McCabe) of an Apex method or ' +\n 'constructor body, mirroring SonarQube / PMD CyclomaticComplexity.',\n },\n helpUri:\n 'https://github.com/bobbywhitesfdc/sf-agentpmd/blob/main/docs/agent-loc-categorization-skill-v2.md#-7--cyclomatic-complexity',\n id: 'AGENTPMD.ApexCyclomaticComplexity',\n name: 'ApexCyclomaticComplexity',\n shortDescription: {\n text: 'McCabe cyclomatic complexity of an Apex method or constructor.',\n },\n};\n\nexport function renderSarif(report: AnalysisReport, opts?: RenderOptions): string {\n const warn = opts?.sarifWarningThreshold ?? DEFAULT_WARNING;\n const err = opts?.sarifErrorThreshold ?? DEFAULT_ERROR;\n\n const results: SarifResult[] = [];\n for (const f of report.files) {\n for (const p of f.procedures) {\n results.push(buildAgentResult(f, p, warn, err));\n }\n }\n\n for (const cls of report.apexClasses) {\n for (const m of cls.methods) {\n results.push(buildApexResult(cls, m, warn, err));\n }\n }\n\n const log: SarifLog = {\n $schema:\n 'https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json',\n runs: [\n {\n results,\n tool: {\n driver: {\n informationUri: 'https://github.com/bobbywhitesfdc/sf-agentpmd',\n name: 'sf-agentpmd',\n rules: [RULE_AGENT_CC, RULE_APEX_CC],\n semanticVersion: pluginVersion(),\n },\n },\n },\n ],\n version: '2.1.0',\n };\n\n return JSON.stringify(log, null, 2);\n}\n\nfunction buildAgentResult(\n f: FileReport,\n p: ProcedureCC,\n warn: number,\n err: number,\n): SarifResult {\n return {\n level: levelFor(p.complexity, warn, err),\n locations: [\n {\n physicalLocation: {\n artifactLocation: { uri: f.path },\n // AgentScript CST locations are 0-based \u2014 bump to SARIF 1-based.\n region: regionFromZeroBased(p.location),\n },\n },\n ],\n message: {\n text:\n `Procedure '${p.kind}' in '${p.scope}' has cyclomatic complexity ` +\n `${p.complexity}.`,\n },\n properties: { complexity: p.complexity, kind: p.kind },\n ruleId: RULE_AGENT_CC.id,\n };\n}\n\nfunction buildApexResult(\n cls: ApexClassReport,\n m: ApexMethodCC,\n warn: number,\n err: number,\n): SarifResult {\n return {\n level: levelFor(m.complexity, warn, err),\n locations: [\n {\n physicalLocation: {\n artifactLocation: { uri: cls.path },\n // ANTLR token positions are 1-based for line, 0-based for column;\n // SARIF wants 1-based for both.\n region: regionFromAntlr(m.location),\n },\n },\n ],\n message: {\n text: `${m.kind} '${m.name}' has cyclomatic complexity ${m.complexity}.`,\n },\n properties: { complexity: m.complexity, kind: m.kind },\n ruleId: RULE_APEX_CC.id,\n };\n}\n\nfunction levelFor(cc: number, warn: number, err: number): SarifResult['level'] {\n if (cc >= err) return 'error';\n if (cc >= warn) return 'warning';\n return 'note';\n}\n\nfunction regionFromZeroBased(loc: ProcedureCC['location']) {\n return {\n endColumn: loc.endCol + 1,\n endLine: loc.endRow + 1,\n startColumn: loc.startCol + 1,\n startLine: loc.startRow + 1,\n };\n}\n\nfunction regionFromAntlr(loc: ProcedureCC['location']) {\n return {\n endColumn: loc.endCol + 1,\n endLine: Math.max(1, loc.endRow),\n startColumn: loc.startCol + 1,\n startLine: Math.max(1, loc.startRow),\n };\n}\n\nfunction pluginVersion(): string {\n // Avoid a JSON-file dep at runtime; this stays in sync with package.json\n // manually. Bumping the plugin should bump this string.\n return '0.1.2';\n}\n", "import pc from 'picocolors';\n\nimport type {\n AnalysisReport,\n ApexCCContributor,\n FileReport,\n ProcedureCC,\n} from '../analyzer/types.js';\nimport type { RenderOptions } from './options.js';\n\nconst KIND_LABEL: Record<ProcedureCC['kind'], string> = {\n after_reasoning: 'after_reasoning',\n available_when: 'available_when',\n before_reasoning: 'before_reasoning',\n other: 'other',\n reasoning_instructions: 'reasoning.instructions',\n};\n\ninterface Glyphs {\n agentFile: string;\n apexFile: string;\n ruleHeavy: string;\n ruleLight: string;\n}\n\nconst UNICODE_GLYPHS: Glyphs = {\n agentFile: '\uD83D\uDCC4',\n apexFile: '\uD83D\uDCDC',\n ruleHeavy: '\u2550',\n ruleLight: '\u2500',\n};\n\nconst ASCII_GLYPHS: Glyphs = {\n agentFile: '[agent]',\n apexFile: '[apex] ',\n ruleHeavy: '=',\n ruleLight: '-',\n};\n\ninterface ResolvedOptions {\n ascii: boolean;\n color: boolean;\n width: number;\n}\n\nfunction resolveOptions(opts: RenderOptions | undefined): ResolvedOptions {\n // Auto-detect: text + emoji unless explicitly disabled, color on TTY only\n // and respecting the well-known NO_COLOR env var.\n const stdoutIsTty = Boolean(process.stdout.isTTY);\n const noColorEnv = Boolean(process.env.NO_COLOR);\n return {\n ascii: opts?.ascii ?? !stdoutIsTty,\n color: opts?.color ?? (stdoutIsTty && !noColorEnv),\n width: opts?.width ?? 60,\n };\n}\n\nexport function renderText(report: AnalysisReport, opts?: RenderOptions): string {\n const r = resolveOptions(opts);\n const g = r.ascii ? ASCII_GLYPHS : UNICODE_GLYPHS;\n const c = colorize(r.color);\n const lines: string[] = [];\n\n lines.push(\n c.title('AgentForce PMD \u2014 Cyclomatic Complexity (McCabe)'),\n g.ruleHeavy.repeat(r.width),\n );\n\n if (report.files.length === 0) {\n lines.push(' (no .agent files found)');\n return lines.join('\\n');\n }\n\n for (const f of report.files) {\n lines.push(\n '',\n `${g.agentFile} ${c.path(f.path)} CC=${c.cc(f.fileComplexity)}`,\n g.ruleLight.repeat(r.width),\n );\n\n if (f.procedures.length === 0) {\n lines.push(' (no procedure-bearing scopes)');\n } else {\n const scopes = groupByScope(f.procedures);\n for (const [scope, procs] of scopes) {\n const scopeTotal = procs.reduce((a, p) => a + p.complexity, 0);\n lines.push(` ${c.scope(scope)} subtotal CC=${c.cc(scopeTotal)}`);\n for (const p of procs) {\n lines.push(\n ` ${pad(KIND_LABEL[p.kind], 24)} CC=${c.cc(p.complexity)} ` +\n c.breakdown(breakdownProc(p)),\n );\n }\n }\n }\n\n if (f.declarations.length > 0 || f.references.length > 0) {\n lines.push(\n '',\n ' Action references',\n ' ' + g.ruleLight.repeat(Math.max(0, r.width - 2)),\n );\n const usage = countReferences(f);\n for (const d of f.declarations) {\n const used = usage.get(d.name) ?? 0;\n const tgt = d.target ?? '(no target)';\n lines.push(\n ` ${pad(d.name, 32)} [${pad(d.targetKind, 6)}] used ${used}x \u2192 ${tgt}`,\n );\n }\n\n const undeclared = listUndeclaredRefs(f);\n if (undeclared.length > 0) {\n lines.push('', ' Referenced but not declared in-file:');\n for (const u of undeclared) {\n lines.push(` ${u}`);\n }\n }\n }\n }\n\n if (report.apexClasses.length > 0 || report.unresolvedApexTargets.length > 0) {\n lines.push(\n '',\n c.title('Apex backing logic (resolved via apex:// targets)'),\n g.ruleHeavy.repeat(r.width),\n );\n for (const cls of report.apexClasses) {\n lines.push(\n '',\n `${g.apexFile} ${c.path(cls.path)} class CC=${c.cc(cls.classComplexity)}`,\n ` referenced by: ${cls.referencedBy.join(', ') || '(none)'}`,\n g.ruleLight.repeat(r.width),\n );\n if (cls.methods.length === 0) {\n lines.push(' (no methods with bodies)');\n } else {\n for (const m of cls.methods) {\n lines.push(\n ` ${pad(m.signature, 44)} CC=${c.cc(m.complexity)} ${c.breakdown(breakdownApex(m.contributors))}`,\n );\n }\n }\n }\n\n if (report.unresolvedApexTargets.length > 0) {\n lines.push('', 'Unresolved apex:// targets:');\n for (const u of report.unresolvedApexTargets) {\n lines.push(\n ` - ${u} (no matching .cls under source-dir or --apex-source)`,\n );\n }\n }\n }\n\n lines.push(\n '',\n g.ruleHeavy.repeat(r.width),\n c.title('CC by location (whitepaper \u00A7 7)'),\n ` AgentScript: ${c.cc(report.totalComplexity)}` +\n ` Apex: ${c.cc(report.totalApexComplexity)}` +\n ` Combined: ${c.cc(report.totalComplexity + report.totalApexComplexity)}`,\n `Action declarations: ${report.totalDeclarations} ` +\n `(apex ${report.byTargetKind.apex}, flow ${report.byTargetKind.flow}, ` +\n `prompt ${report.byTargetKind.prompt}, unknown ${report.byTargetKind.unknown})`, `Action references: ${report.totalReferences}`\n \n );\n return lines.join('\\n');\n}\n\ninterface Colorizer {\n breakdown: (s: string) => string;\n cc: (n: number) => string;\n path: (s: string) => string;\n scope: (s: string) => string;\n title: (s: string) => string;\n}\n\nfunction colorize(on: boolean): Colorizer {\n if (!on) {\n return {\n breakdown: s => s,\n cc: String,\n path: s => s,\n scope: s => s,\n title: s => s,\n };\n }\n\n return {\n breakdown: pc.gray,\n cc(n: number) {\n // Palette echoes whitepaper temperature: cool for low, hot for high.\n const s = String(n);\n if (n >= 20) return pc.red(s);\n if (n >= 10) return pc.yellow(s);\n if (n >= 5) return pc.green(s);\n return pc.gray(s);\n },\n path: pc.cyan,\n scope: pc.bold,\n title: pc.bold,\n };\n}\n\nfunction breakdownProc(p: ProcedureCC): string {\n if (p.contributors.length === 0) return '(base only)';\n const counts: Record<string, number> = {};\n for (const c of p.contributors) counts[c.kind] = (counts[c.kind] ?? 0) + 1;\n return Object.entries(counts)\n .map(([k, n]) => `${shortKind(k)}=${n}`)\n .join(' ');\n}\n\nfunction breakdownApex(contributors: ApexCCContributor[]): string {\n if (contributors.length === 0) return '(base only)';\n const counts: Record<string, number> = {};\n for (const c of contributors) counts[c.kind] = (counts[c.kind] ?? 0) + 1;\n return Object.entries(counts)\n .map(([k, n]) => `${shortApexKind(k)}=${n}`)\n .join(' ');\n}\n\nfunction shortKind(k: string): string {\n switch (k) {\n case 'elif_clause': {\n return 'elif';\n }\n\n case 'if_statement': {\n return 'if';\n }\n\n case 'short_circuit_and': {\n return 'and';\n }\n\n case 'short_circuit_or': {\n return 'or';\n }\n\n case 'ternary_expression': {\n return 'ternary';\n }\n\n default: {\n return k;\n }\n }\n}\n\nfunction shortApexKind(k: string): string {\n switch (k) {\n case 'catch_clause': {\n return 'catch';\n }\n\n case 'do_while_statement': {\n return 'do-while';\n }\n\n case 'for_statement': {\n return 'for';\n }\n\n case 'if_statement': {\n return 'if';\n }\n\n case 'short_circuit_and': {\n return '&&';\n }\n\n case 'short_circuit_or': {\n return '||';\n }\n\n case 'ternary': {\n return 'ternary';\n }\n\n case 'when_arm': {\n return 'when';\n }\n\n case 'while_statement': {\n return 'while';\n }\n\n default: {\n return k;\n }\n }\n}\n\nfunction groupByScope(procs: ProcedureCC[]): Map<string, ProcedureCC[]> {\n const m = new Map<string, ProcedureCC[]>();\n for (const p of procs) {\n let arr = m.get(p.scope);\n if (!arr) {\n arr = [];\n m.set(p.scope, arr);\n }\n\n arr.push(p);\n }\n\n return m;\n}\n\nfunction pad(s: string, n: number): string {\n if (s.length >= n) return s;\n return s + ' '.repeat(n - s.length);\n}\n\nfunction countReferences(f: FileReport): Map<string, number> {\n const m = new Map<string, number>();\n for (const r of f.references) m.set(r.name, (m.get(r.name) ?? 0) + 1);\n return m;\n}\n\nfunction listUndeclaredRefs(f: FileReport): string[] {\n const declared = new Set(f.declarations.map(d => d.name));\n const seen = new Set<string>();\n const out: string[] = [];\n for (const r of f.references) {\n if (declared.has(r.name)) continue;\n if (seen.has(r.name)) continue;\n seen.add(r.name);\n out.push(r.name);\n }\n\n return out;\n}\n", "import type { AnalysisReport } from '../analyzer/types.js';\nimport type { RenderFormat, RenderOptions } from './options.js';\n\nimport { renderCsv } from './csv.js';\nimport { renderMarkdown } from './markdown.js';\nimport { renderSarif } from './sarif.js';\nimport { renderText } from './text.js';\n\nexport function render(\n format: RenderFormat,\n report: AnalysisReport,\n options?: RenderOptions,\n): string {\n switch (format) {\n case 'csv': {\n return renderCsv(report);\n }\n\n case 'markdown': {\n return renderMarkdown(report);\n }\n\n case 'sarif': {\n return renderSarif(report, options);\n }\n\n case 'text': {\n return renderText(report, options);\n }\n }\n}\n\nexport { renderCsv } from './csv.js';\nexport { renderMarkdown } from './markdown.js';\nexport type { RenderFormat, RenderOptions } from './options.js';\nexport { renderSarif } from './sarif.js';\nexport { renderText } from './text.js';\n"],
|
|
5
5
|
"mappings": "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",
|
|
6
6
|
"names": ["readFile", "stat", "basename", "dirname", "join", "relative", "resolve", "TokenKind", "currentIndent", "c", "text", "parseProcedure", "makeEmptyError", "parseTemplate", "parseSequence", "ewt", "resolve", "readFile", "relative", "stat", "join", "basename", "dirname", "readFile", "stat", "dirname", "isAbsolute", "join", "resolve", "breakdownProc", "breakdownApex", "KIND_LABEL", "breakdownProc", "countReferences", "listUndeclaredRefs", "breakdownApex", "shortKind", "shortApexKind"]
|
|
7
7
|
}
|