@ansible-flow/core 0.86.0 → 0.88.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/README.md +1 -1
  2. package/dist/ai/describe.js +8 -7
  3. package/dist/ai/handlers.js +27 -25
  4. package/dist/ai/handlers.js.map +1 -1
  5. package/dist/ai/ops.js +8 -7
  6. package/dist/ai/reference.js +2 -2
  7. package/dist/ai/scenarios.js +12 -8
  8. package/dist/awx/import.js +7 -6
  9. package/dist/catalog/draft.d.ts +2 -0
  10. package/dist/catalog/draft.js +23 -4
  11. package/dist/catalog/draft.js.map +2 -2
  12. package/dist/chunks/{chunk-BXHI5EQM.js → chunk-2DT5DOSO.js} +43 -1
  13. package/dist/chunks/chunk-2DT5DOSO.js.map +7 -0
  14. package/dist/chunks/{chunk-DHU774ES.js → chunk-2KB3J3R5.js} +2 -2
  15. package/dist/chunks/{chunk-EAJFZKPB.js → chunk-37FKZNRN.js} +3 -3
  16. package/dist/chunks/{chunk-TPRZZHXA.js → chunk-57KJYXWA.js} +7 -7
  17. package/dist/chunks/{chunk-JTWR3TGG.js → chunk-7ALTNZCI.js} +4 -4
  18. package/dist/chunks/{chunk-UXIXXEIW.js → chunk-APBEHKCF.js} +2 -2
  19. package/dist/chunks/{chunk-ZAYNYPCX.js → chunk-ARA3VJR2.js} +2 -2
  20. package/dist/chunks/{chunk-7GLSXIZ3.js → chunk-BSX6G7QY.js} +5 -5
  21. package/dist/chunks/{chunk-H7Z2FBRD.js → chunk-CATQHJS6.js} +8 -8
  22. package/dist/chunks/{chunk-J7KCGVHU.js → chunk-CCWUUVSG.js} +2 -2
  23. package/dist/chunks/{chunk-C6SQEXL5.js → chunk-CNQ7M7HA.js} +2 -2
  24. package/dist/chunks/{chunk-NT62IE3Y.js → chunk-CNYGDBID.js} +2 -2
  25. package/dist/chunks/chunk-FIKPXL6E.js +23 -0
  26. package/dist/chunks/chunk-FIKPXL6E.js.map +7 -0
  27. package/dist/chunks/{chunk-CM23ODBB.js → chunk-J5LYSQ3L.js} +2 -2
  28. package/dist/chunks/{chunk-72LO6GQE.js → chunk-KXD6FX2Z.js} +2 -2
  29. package/dist/chunks/{chunk-4RMWFRWG.js → chunk-LELKMVJG.js} +45 -7
  30. package/dist/chunks/chunk-LELKMVJG.js.map +7 -0
  31. package/dist/chunks/{chunk-XOPGOWNQ.js → chunk-O5Y3AZ4X.js} +1 -1
  32. package/dist/chunks/chunk-O5Y3AZ4X.js.map +7 -0
  33. package/dist/chunks/{chunk-5XGAGNH5.js → chunk-OGNFHW5O.js} +7 -13
  34. package/dist/chunks/chunk-OGNFHW5O.js.map +7 -0
  35. package/dist/chunks/chunk-OJZSZBHW.js +45 -0
  36. package/dist/chunks/chunk-OJZSZBHW.js.map +7 -0
  37. package/dist/chunks/{chunk-R4MW3DRT.js → chunk-OW32YCZ6.js} +2 -2
  38. package/dist/chunks/{chunk-2QQC4IZ7.js → chunk-PNLY5IWM.js} +8 -8
  39. package/dist/chunks/chunk-PNLY5IWM.js.map +7 -0
  40. package/dist/chunks/{chunk-76T45V37.js → chunk-TBFB7A2Z.js} +5 -1
  41. package/dist/chunks/{chunk-76T45V37.js.map → chunk-TBFB7A2Z.js.map} +2 -2
  42. package/dist/chunks/{chunk-BXJOUAXV.js → chunk-TEJARYAE.js} +3 -3
  43. package/dist/chunks/{chunk-T5UB4MBB.js → chunk-TOTSB4HG.js} +41 -1
  44. package/dist/chunks/chunk-TOTSB4HG.js.map +7 -0
  45. package/dist/chunks/{chunk-MZ6IJWB2.js → chunk-TPMACJFA.js} +4 -4
  46. package/dist/chunks/{chunk-CXVJWFGT.js → chunk-WTVGCMGV.js} +8 -4
  47. package/dist/chunks/chunk-WTVGCMGV.js.map +7 -0
  48. package/dist/chunks/{chunk-6MLYGFT6.js → chunk-XJAMBKE3.js} +6 -2
  49. package/dist/chunks/chunk-XJAMBKE3.js.map +7 -0
  50. package/dist/chunks/{chunk-ABYJBONR.js → chunk-ZXUXX3YY.js} +4 -4
  51. package/dist/engine/binding.js +3 -1
  52. package/dist/engine/bypass.js +4 -2
  53. package/dist/engine/engines.js +9 -5
  54. package/dist/engine/files.js +9 -5
  55. package/dist/engine/optionA.js +8 -4
  56. package/dist/engine/partial.js +3 -1
  57. package/dist/engine/partial.js.map +1 -1
  58. package/dist/engine/preview.js +9 -5
  59. package/dist/engine/preview.js.map +1 -1
  60. package/dist/engine/writePlan.js +12 -9
  61. package/dist/export/drawio.js +3 -3
  62. package/dist/export/layoutCheck.js +3 -3
  63. package/dist/export/scene.js +2 -2
  64. package/dist/export/svg.js +4 -4
  65. package/dist/flow/commands.d.ts +10 -0
  66. package/dist/flow/commands.js +3 -1
  67. package/dist/flow/facts.d.ts +6 -0
  68. package/dist/flow/facts.js +13 -0
  69. package/dist/flow/facts.js.map +7 -0
  70. package/dist/flow/findingCodes.js +1 -1
  71. package/dist/flow/localFiles.d.ts +17 -0
  72. package/dist/flow/localFiles.js +14 -0
  73. package/dist/flow/localFiles.js.map +7 -0
  74. package/dist/flow/save.js +3 -1
  75. package/dist/flow/save.js.map +1 -1
  76. package/dist/flow/validate.js +3 -2
  77. package/dist/import/outline.js +9 -7
  78. package/dist/import/playbook.js +6 -5
  79. package/dist/import/source.js +3 -2
  80. package/dist/lens/caption.js +1 -1
  81. package/dist/lens/data.js +3 -1
  82. package/dist/lens/index.js +11 -9
  83. package/dist/lens/index.js.map +1 -1
  84. package/dist/lens/types.d.ts +2 -0
  85. package/dist/lens/types.js +1 -1
  86. package/dist/messageCheck.js +2 -0
  87. package/dist/messageCheck.js.map +2 -2
  88. package/dist/protocol.d.ts +29 -0
  89. package/dist/run/command.d.ts +13 -4
  90. package/dist/run/command.js +19 -0
  91. package/dist/run/command.js.map +3 -3
  92. package/dist/scenario/live.js +11 -7
  93. package/dist/scenario/simulate.js +10 -6
  94. package/dist/view/flowFacts.js +12 -9
  95. package/dist/view/flowFacts.js.map +1 -1
  96. package/dist/view/route.d.ts +3 -1
  97. package/dist/view/route.js +1 -1
  98. package/dist/view/serverChange.d.ts +23 -0
  99. package/dist/view/serverChange.js +48 -0
  100. package/dist/view/serverChange.js.map +7 -0
  101. package/package.json +1 -1
  102. package/dist/chunks/chunk-2QQC4IZ7.js.map +0 -7
  103. package/dist/chunks/chunk-4RMWFRWG.js.map +0 -7
  104. package/dist/chunks/chunk-5XGAGNH5.js.map +0 -7
  105. package/dist/chunks/chunk-6MLYGFT6.js.map +0 -7
  106. package/dist/chunks/chunk-BXHI5EQM.js.map +0 -7
  107. package/dist/chunks/chunk-CXVJWFGT.js.map +0 -7
  108. package/dist/chunks/chunk-T5UB4MBB.js.map +0 -7
  109. package/dist/chunks/chunk-XOPGOWNQ.js.map +0 -7
  110. /package/dist/chunks/{chunk-DHU774ES.js.map → chunk-2KB3J3R5.js.map} +0 -0
  111. /package/dist/chunks/{chunk-EAJFZKPB.js.map → chunk-37FKZNRN.js.map} +0 -0
  112. /package/dist/chunks/{chunk-TPRZZHXA.js.map → chunk-57KJYXWA.js.map} +0 -0
  113. /package/dist/chunks/{chunk-JTWR3TGG.js.map → chunk-7ALTNZCI.js.map} +0 -0
  114. /package/dist/chunks/{chunk-UXIXXEIW.js.map → chunk-APBEHKCF.js.map} +0 -0
  115. /package/dist/chunks/{chunk-ZAYNYPCX.js.map → chunk-ARA3VJR2.js.map} +0 -0
  116. /package/dist/chunks/{chunk-7GLSXIZ3.js.map → chunk-BSX6G7QY.js.map} +0 -0
  117. /package/dist/chunks/{chunk-H7Z2FBRD.js.map → chunk-CATQHJS6.js.map} +0 -0
  118. /package/dist/chunks/{chunk-J7KCGVHU.js.map → chunk-CCWUUVSG.js.map} +0 -0
  119. /package/dist/chunks/{chunk-C6SQEXL5.js.map → chunk-CNQ7M7HA.js.map} +0 -0
  120. /package/dist/chunks/{chunk-NT62IE3Y.js.map → chunk-CNYGDBID.js.map} +0 -0
  121. /package/dist/chunks/{chunk-CM23ODBB.js.map → chunk-J5LYSQ3L.js.map} +0 -0
  122. /package/dist/chunks/{chunk-72LO6GQE.js.map → chunk-KXD6FX2Z.js.map} +0 -0
  123. /package/dist/chunks/{chunk-R4MW3DRT.js.map → chunk-OW32YCZ6.js.map} +0 -0
  124. /package/dist/chunks/{chunk-BXJOUAXV.js.map → chunk-TEJARYAE.js.map} +0 -0
  125. /package/dist/chunks/{chunk-MZ6IJWB2.js.map → chunk-TPMACJFA.js.map} +0 -0
  126. /package/dist/chunks/{chunk-ABYJBONR.js.map → chunk-ZXUXX3YY.js.map} +0 -0
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../../../src/core/flow/validate.ts"],
4
- "sourcesContent": ["// Semantic checks on a flow document. Findings carry YAML paths; the host maps them to ranges.\n\nimport { takesFreeKeys } from '../catalog/freeKeys';\nimport type { Path } from '../yaml/parse';\nimport { successors } from './adjacency';\nimport { fedByBubbling, levelTaken, untaken } from './bubbling';\nimport { idGaps, withIds } from './completeIds';\nimport { fromRegister, outputVar, registerName } from './dataNames';\nimport { enclosing, liftOf, resolveFrom, upstreamNodes } from './dataRefs';\nimport { acceptedAll, acceptedOf, checkWhat } from './decisions';\nimport { canDisable, disabledBy, disabledIds } from './disabled';\nimport { durationSeconds } from './duration';\nimport { healPlan } from './heal';\nimport { conditionHasBraces, exprRefs, refsIn, singleRef, templated } from './jinja';\nimport { BARE_PARAMS, keywordReads } from './keywords';\nimport { formatOf } from './migrate';\nimport { buildModel, type FlowModel, ROOT } from './model';\nimport { openFailPorts } from './openPorts';\nimport { isRollback } from './patterns';\nimport { isFailPort, isPortLegal, LEGACY_PORTS, portDirection, portsFor } from './ports';\nimport { refDesign } from './refs';\nimport { rollingObstacles } from './rolling';\nimport type { SchemaIssue } from './schema';\nimport { planSegments } from './segments';\nimport { hasStatus, runtimeKind, statusFor } from './status';\nimport type { FlowDocument, FlowNode, PortRef, Ulid } from './types';\nimport { comparesWholeResult } from './until';\nimport { varNameProblem } from './varNames';\n\nexport type Severity = 'error' | 'warning' | 'info';\n\nexport interface Finding {\n code: string;\n severity: Severity;\n message: string;\n path: Path;\n node?: Ulid;\n port?: string;\n edge?: Ulid;\n /** What the finding is about when a node can have several (a variable name): with the code and\n * the node, what an accepted problem names (AFD-51). */\n subject?: string;\n}\n\nexport function pointerToPath(pointer: string): Path {\n if (pointer === '/' || pointer === '') return [];\n return pointer\n .slice(1)\n .split('/')\n .map((s) => s.replaceAll('~1', '/').replaceAll('~0', '~'))\n .map((s) => (/^[0-9]+$/.test(s) ? Number(s) : s));\n}\n\nfunction label(node: FlowNode | undefined): string {\n return node ? `\"${node.title ?? node.key}\"` : 'unknown node';\n}\n\n/** A YAML true/false written as a boolean or a word (`yes`, `\"false\"`). */\nfunction literal(value: unknown, want: boolean): boolean {\n if (typeof value === 'boolean') return value === want;\n if (typeof value !== 'string') return false;\n const word = value.trim().toLowerCase();\n return want ? ['true', 'yes', 'on'].includes(word) : ['false', 'no', 'off'].includes(word);\n}\n\n/** AFD-211: a step bound with ignore_errors: true or failed_when: false. */\nfunction ignoresErrors(node: FlowNode | undefined): boolean {\n const kw = node?.impl?.keywords;\n return !!kw && (literal(kw.ignore_errors, true) || literal(kw.failed_when, false));\n}\n\nexport interface ValidationResult {\n model: FlowModel;\n findings: Finding[];\n}\n\n/**\n * AFD-242: a disabled node the hosts cannot pass through. It goes on only when exactly one of its\n * main outputs leads somewhere (core/flow/heal); otherwise the hosts that reach it stop there.\n */\nfunction checkDisabled(model: FlowModel, add: (f: Finding) => void): void {\n for (const id of disabledIds(model)) {\n const entry = model.nodes.get(id);\n if (!entry || disabledBy(model, entry.level)) continue;\n if (!canDisable(entry.node)) {\n add({\n code: 'disabled-not-allowed',\n severity: 'error',\n message: `${label(entry.node)} is a ${entry.node.type} node and cannot be disabled`,\n path: [...entry.path, 'disabled'],\n node: id,\n });\n continue;\n }\n const level = model.levels.get(entry.level);\n const into = (level?.edges ?? []).filter((e) => e?.to?.node === id);\n const parent = level?.parent ? model.nodes.get(level.parent)?.node : undefined;\n const entryStep = parent?.subflow?.boundary?.in === id;\n if (into.length === 0 && !entryStep) continue;\n const plan = healPlan(model, [id]);\n const through = plan.wires.length + plan.exits.length + plan.entries.length;\n if (through > 0) continue;\n add({\n code: 'disabled-ends-path',\n severity: 'warning',\n message: `${label(entry.node)} is disabled and does not go on to one next step, so the hosts that reach it stop there: wire its main output, or enable it`,\n path: [...entry.path, 'disabled'],\n node: id,\n });\n }\n}\n\nexport function validateFlow(\n doc: FlowDocument,\n schemaIssues: SchemaIssue[] = [],\n): ValidationResult {\n // A file written by hand may lack IDs (AFD-19): each gap is an error, and every other check runs\n // on the flow with the gaps filled, so the rest of the design is checked as usual.\n const gaps = idGaps(doc);\n const checked = gaps.length > 0 ? withIds(doc) : doc;\n const model = buildModel(checked);\n const findings: Finding[] = schemaIssues.map((i) => ({\n code: i.code ?? 'schema',\n severity: 'error',\n message: i.code ? i.message : `Schema: ${i.message}`,\n path: pointerToPath(i.pointer),\n }));\n const add = (f: Finding) => findings.push(f);\n for (const gap of gaps)\n add({\n code: gap.unresolved ? 'unknown-key' : 'missing-id',\n severity: 'error',\n message: gap.unresolved ? gap.message : `${gap.message}: Complete IDs adds it`,\n path: gap.path,\n });\n\n checkIdentity(model, add);\n checkEdges(model, add);\n checkNodes(model, add);\n checkReferences(model, add);\n checkDecisions(model, add);\n checkUnreachableRollback(model, add);\n checkTargets(model, add);\n checkAnnotations(model, add);\n checkVarNames(model, add);\n\n for (const open of openFailPorts(model)) {\n const entry = model.nodes.get(open.node);\n // AFD-211: a step that ignores its errors fails only where Ansible will not ignore them (an\n // undefined variable, a module that cannot run): still listed, not a warning per step.\n const quiet = open.port === 'failed_hosts' && ignoresErrors(entry?.node);\n add({\n code: 'open-fail-port',\n severity: quiet ? 'info' : 'warning',\n // AFD-72: what happens to the hosts, and the two ways out, in plain words.\n message: quiet\n ? `Open fail port: ${label(entry?.node)} \u00B7 ${open.port} has nowhere to go; the step ignores errors (ignore_errors or failed_when: false), so only an undefined variable or a module that cannot run fails its hosts`\n : `Open fail port: ${label(entry?.node)} \u00B7 ${open.port} has nowhere to go, so its hosts fail the run. Wire a failure pattern to it, or Accept with Reason\u2026 to keep it open`,\n path: entry?.path ?? [],\n node: open.node,\n port: open.port,\n });\n }\n\n checkDisabled(model, add);\n // AFD-242: a disabled node does nothing, so warnings about what it would do (its binding, its\n // open fail ports, its inputs) say nothing useful: only errors and what disabling itself causes.\n const about = new Set(['disabled-ends-path', 'reads-disabled', 'disabled-not-allowed']);\n for (let i = findings.length - 1; i >= 0; i--) {\n const f = findings[i];\n if (f?.node && f.severity !== 'error' && !about.has(f.code) && disabledBy(model, f.node))\n findings.splice(i, 1);\n }\n\n const ids = new Set(model.nodes.keys());\n for (const id of Object.keys(checked.layout ?? {})) {\n if (!ids.has(id)) {\n add({\n code: 'layout-orphan',\n severity: 'info',\n message: `Layout entry for a node that does not exist: ${id}`,\n path: ['layout', id],\n });\n }\n }\n // AFD-51: warnings accepted with a reason (format 2) stay out of the problems.\n const checks = acceptedAll(checked).filter((a) => a.area === 'check');\n // AFD-184: an accepted check no warning matches hides nothing (a wrong key, or fixed since).\n for (const a of checks) {\n const entry = a.node ? model.nodes.get(a.node) : undefined;\n if (!entry) continue;\n if (\n findings.some(\n (f) => f.severity === 'warning' && f.node === a.node && acceptMatches(a.what, f),\n )\n )\n continue;\n findings.push({\n code: 'stale-decision',\n severity: 'warning',\n message: `Accepted problem ${a.what} for ${label(entry.node)} matches no warning: it hides nothing (unaccept it, or accept the key the warning shows)`,\n path: ['decisions', a.index],\n node: a.node,\n });\n }\n const kept = checks.length\n ? findings.filter(\n (f) =>\n f.severity !== 'warning' ||\n !checks.some((a) => a.node === f.node && acceptMatches(a.what, f)),\n )\n : findings;\n return { model, findings: kept };\n}\n\n/**\n * AFD-184: what an accepted check decision covers: its exact key (`<code>:<subject>`, the port\n * for port warnings), or with the code alone every subject of that code on the node.\n */\nexport function acceptMatches(what: string, f: Finding): boolean {\n return what === f.code || what === checkWhat(f.code, f.subject ?? f.port);\n}\n\n/** AFD-184: the `finding` string an accept op takes for a warning (check:<code>[:<subject>]). */\nexport function acceptKey(f: Finding): string {\n return `check:${checkWhat(f.code, f.subject ?? f.port)}`;\n}\n\nfunction checkIdentity(model: FlowModel, add: (f: Finding) => void): void {\n const seen = new Map<string, string>();\n const claim = (id: string | undefined, path: Path) => {\n if (!id) return;\n const where = path.join('.');\n const first = seen.get(id);\n if (first !== undefined) {\n add({\n code: 'duplicate-id',\n severity: 'error',\n message: `Duplicate ID ${id} (also at ${first})`,\n path,\n });\n } else {\n seen.set(id, where);\n }\n };\n claim(model.doc.flow?.id, ['flow', 'id']);\n for (const level of model.levels.values()) {\n const keys = new Map<string, number>();\n level.nodes.forEach((n, i) => {\n if (!n) return;\n claim(n.id, [...level.nodesPath, i, 'id']);\n if (keys.has(n.key)) {\n add({\n code: 'duplicate-key',\n severity: 'error',\n message: `Duplicate key \"${n.key}\" in this level`,\n path: [...level.nodesPath, i, 'key'],\n node: n.id,\n });\n } else {\n keys.set(n.key, i);\n }\n });\n level.edges.forEach((e, i) => {\n claim(e?.id, [...level.edgesPath, i, 'id']);\n });\n // AFD-64: annotations share the ID space (the canvas draws them all), keys are per level.\n const annotationKeys = new Set<string>();\n level.annotations.forEach((a, i) => {\n if (!a) return;\n claim(a.id, [...level.annotationsPath, i, 'id']);\n if (!a.key) return;\n if (annotationKeys.has(a.key))\n add({\n code: 'duplicate-key',\n severity: 'error',\n message: `Duplicate annotation key \"${a.key}\" in this level`,\n path: [...level.annotationsPath, i, 'key'],\n });\n annotationKeys.add(a.key);\n });\n }\n}\n\n/** AFD-64: a Note on a node that is not on its level; annotations in a format 1 file. */\nfunction checkAnnotations(model: FlowModel, add: (f: Finding) => void): void {\n const v2 = formatOf(model.doc) >= 2;\n for (const level of model.levels.values())\n level.annotations.forEach((a, i) => {\n if (!a || typeof a !== 'object') return;\n const path = [...level.annotationsPath, i];\n if (!v2 && i === 0)\n add({\n code: 'annotation-target-missing',\n severity: 'warning',\n message: 'Annotations are format 2: Upgrade Flow Format',\n path: level.annotationsPath,\n });\n if (a.on === undefined) return;\n const target = model.nodes.get(a.on);\n if ((a.kind ?? 'note') !== 'note' || !target || target.level !== level.id)\n add({\n code: 'annotation-target-missing',\n severity: 'warning',\n message:\n (a.kind ?? 'note') !== 'note'\n ? `${a.kind} \"${a.key ?? a.id}\" is on a node, which only a note can be: Detach it`\n : `Note \"${a.key ?? a.id}\" is on a node that is not on its level: Detach it, or attach it again`,\n path: [...path, 'on'],\n subject: a.id,\n });\n });\n}\n\nfunction checkEdges(model: FlowModel, add: (f: Finding) => void): void {\n for (const level of model.levels.values()) {\n const used = new Map<string, Ulid>();\n level.edges.forEach((edge, i) => {\n if (!edge?.from || !edge.to) return;\n const path = [...level.edgesPath, i];\n for (const [end, ref] of [\n ['from', edge.from],\n ['to', edge.to],\n ] as const) {\n const target = model.nodes.get(ref.node);\n if (!target) {\n add({\n code: 'edge-missing-node',\n severity: 'error',\n message: `Edge ${end} refers to a node that does not exist: ${ref.node}`,\n path: [...path, end, 'node'],\n edge: edge.id,\n });\n continue;\n }\n if (target.level !== level.id) {\n add({\n code: 'edge-cross-level',\n severity: 'error',\n message: `Edge ${end} ${label(target.node)} is in another level; use the subflow boundary`,\n path: [...path, end, 'node'],\n edge: edge.id,\n });\n continue;\n }\n const expected = end === 'from' ? 'out' : 'in';\n if (!isPortLegal(target.node, ref.port)) {\n add({\n code: 'edge-bad-port',\n severity: 'error',\n message: `${label(target.node)} (${target.node.type}) has no port \"${ref.port}\"`,\n path: [...path, end, 'port'],\n edge: edge.id,\n });\n } else if (portDirection(ref.port) !== expected) {\n add({\n code: 'edge-direction',\n severity: 'error',\n message: `Edge ${end} uses ${ref.port}, which is an ${portDirection(ref.port)}put port`,\n path: [...path, end, 'port'],\n edge: edge.id,\n });\n } else if (!portsFor(target.node).some((p) => p.name === ref.port)) {\n add({\n code: 'edge-port-not-enabled',\n severity: 'warning',\n message: `Port ${ref.port} of ${label(target.node)} is used but not enabled in ports:`,\n path: [...path, end, 'port'],\n edge: edge.id,\n });\n }\n }\n const fromKey = `${edge.from.node}|${edge.from.port}`;\n if (used.has(fromKey)) {\n add({\n code: 'port-multiple-edges',\n severity: 'error',\n message: `Output port ${edge.from.port} has more than one edge; use a parallel node to fan out`,\n path,\n edge: edge.id,\n });\n } else {\n used.set(fromKey, edge.id);\n }\n });\n }\n}\n\n/**\n * AFD-160: inputs, outputs and registers become Ansible variables. Only the commands checked\n * their names, so a hand- or AI-written `retry-count` reached a play's vars and Ansible refused the\n * playbook; a host_list named `web-servers` read as `web - servers` in the start pattern.\n */\nfunction checkVarNames(model: FlowModel, add: (f: Finding) => void): void {\n const check = (name: string, path: Path, node?: Ulid) => {\n const problem = varNameProblem(name);\n if (problem) add({ code: 'bad-name', severity: 'error', message: problem, path, node });\n };\n for (const name of Object.keys(model.doc.flow?.inputs ?? {}))\n check(name, ['flow', 'inputs', name]);\n for (const { node, path } of model.nodes.values()) {\n for (const side of ['inputs', 'outputs'] as const)\n for (const name of Object.keys(node[side] ?? {})) check(name, [...path, side, name], node.id);\n const register = node.impl?.register;\n if (typeof register === 'string' && register)\n check(register, [...path, 'impl', 'register'], node.id);\n }\n}\n\nfunction checkNodes(model: FlowModel, add: (f: Finding) => void): void {\n const v2 = formatOf(model.doc) >= 2;\n for (const { node, path, level } of model.nodes.values()) {\n for (const p of node.ports ?? []) {\n if (!isPortLegal(node, p)) {\n add({\n code: 'port-not-supported',\n severity: 'warning',\n message: `${label(node)} (${node.type}) does not support port \"${p}\"`,\n path: [...path, 'ports'],\n node: node.id,\n });\n }\n }\n // AFD-54: undo and cancelled were never built; the upgrade removes them and their wires.\n for (const [i, port] of (node.ports ?? []).entries()) {\n if (!LEGACY_PORTS.has(port)) continue;\n add({\n code: 'legacy-port',\n severity: 'warning',\n message: `${label(node)}: the ${port} port was never built (${port === 'undo' ? 'Rollback wires explicit undo steps' : 'a cancelled job routes no host'}); ${formatOf(model.doc) >= 2 ? 'remove it and its wires' : 'Upgrade Flow Format removes it and its wires'}`,\n path: [...path, 'ports', i],\n node: node.id,\n port,\n });\n }\n if (\n node.settings?.inventory_target?.trim() &&\n node.type !== 'task' &&\n node.type !== 'subflow'\n ) {\n add({\n code: 'inventory-target-ignored',\n severity: 'warning',\n message: `${label(node)} (${node.type}) runs on the hosts that arrive: inventory_target applies to tasks and subflows only`,\n path: [...path, 'settings', 'inventory_target'],\n node: node.id,\n });\n }\n const hasInner = (node.subflow?.nodes?.length ?? 0) > 0;\n // Format 2 (AFD-52): the AWX template has one set of credentials and one environment.\n if (v2 && (node.settings?.credential || node.settings?.execution_environment))\n add({\n code: 'setting-on-flow',\n severity: 'warning',\n message: `${label(node)}: credential and execution environment belong to the flow in format 2 (its runtime)`,\n path: [...path, 'settings'],\n node: node.id,\n });\n // AFD-61: Re-import flags the steps whose source task is gone; it never deletes them.\n if (node.origin?.gone)\n add({\n code: 'import-gone',\n severity: 'warning',\n message: `${label(node)}: its task (${node.origin.task}) is no longer in the source: delete the step, or keep it as this flow's own`,\n path: [...path, 'origin'],\n node: node.id,\n });\n // AFD-60: a shared subflow is a copy; edits belong in its source flow.\n if (node.ref && refDesign(node) !== node.ref.design)\n add({\n code: 'shared-edited',\n severity: 'warning',\n message: `${label(node)} was changed here since version ${node.ref.version} of ${node.ref.from}: Update brings the source back over these edits, Unlink keeps them as this flow's own`,\n path: [...path, 'subflow'],\n node: node.id,\n });\n if (node.ref && !v2)\n add({\n code: 'shared-edited',\n severity: 'warning',\n message: `${label(node)}: shared subflows are format 2; Upgrade Flow Format`,\n path: [...path, 'ref'],\n node: node.id,\n });\n // AFD-55: a rolling subflow's steps run in one play; some steps need plays of their own.\n if (node.settings?.rolling !== undefined) {\n if (node.type !== 'subflow')\n add({\n code: 'rolling-unsupported',\n severity: 'warning',\n message: `${label(node)}: rolling batches the steps inside a subflow; on a ${node.type} it does nothing (use serial)`,\n path: [...path, 'settings', 'rolling'],\n node: node.id,\n });\n else\n for (const o of rollingObstacles(model, node))\n add({\n code: 'rolling-unsupported',\n severity: 'error',\n message: `${label(node)} cannot roll: ${label(o.node)}: ${o.why}. Its steps run play by play`,\n path: [...path, 'settings', 'rolling'],\n node: o.node.id,\n });\n }\n // Format 2 (AFD-52): `handler` is called purpose, so it is not read as an Ansible handler.\n if (v2 && node.handler !== undefined)\n add({\n code: 'renamed-field',\n severity: 'warning',\n message: `${label(node)}: handler is called purpose in format 2`,\n path: [...path, 'handler'],\n node: node.id,\n });\n // Format 2 (AFD-52): become_user is a setting, which a subflow passes to its steps.\n if (v2 && node.impl?.keywords && 'become_user' in node.impl.keywords)\n add({\n code: 'keyword-is-setting',\n severity: 'warning',\n message: `${label(node)}: become_user is a setting in format 2 (Execution \u203A Privilege)`,\n path: [...path, 'impl', 'keywords', 'become_user'],\n node: node.id,\n });\n // Format 2 (AFD-50): the status is the one the content gives; a hand edit can still disagree.\n if (v2 && hasStatus(node)) {\n const have = node.status ?? 'draft';\n const want = statusFor(model.doc, node);\n if (have === 'tested' && !node.tested)\n add({\n code: 'tested-without-record',\n severity: 'warning',\n message: `${label(node)} is tested but has no record of the run or the reason`,\n path: [...path, 'status'],\n node: node.id,\n });\n else if (have !== want)\n add({\n code: 'status-out-of-step',\n severity: 'info',\n message: `${label(node)} is ${have}, but what it has makes it ${want}`,\n path: [...path, 'status'],\n node: node.id,\n });\n }\n if (\n !v2 &&\n (node.status === 'implemented' || node.status === 'tested') &&\n !node.impl &&\n !hasInner\n ) {\n add({\n code: 'status-overclaim',\n severity: 'warning',\n message: `${label(node)} is ${node.status} but has no implementation binding`,\n path: [...path, 'status'],\n node: node.id,\n });\n }\n if (\n !v2 &&\n node.status === 'specified' &&\n Object.keys(node.inputs ?? {}).length + Object.keys(node.outputs ?? {}).length === 0\n ) {\n add({\n code: 'status-overclaim',\n severity: 'warning',\n message: `${label(node)} is specified but declares no inputs or outputs`,\n path: [...path, 'status'],\n node: node.id,\n });\n }\n for (const [name, field] of Object.entries(node.inputs ?? {})) {\n if (field?.type === 'host_list') {\n add({\n code: 'host-list-input',\n severity: 'info',\n message: `Input \"${name}\" of ${label(node)}: the hosts arriving on \"in\" are the targets; this host_list is informational`,\n path: [...path, 'inputs', name],\n node: node.id,\n });\n }\n }\n if (node.type === 'approval') checkApprovalSplit(model, node, level, path, add);\n checkEnginePorts(node, path, hasInner, add);\n }\n}\n\n/** Ports the Option A engine cannot drive for this node (ADR-0009, M3 spike). */\nfunction checkEnginePorts(\n node: FlowNode,\n path: Path,\n hasInner: boolean,\n add: (f: Finding) => void,\n): void {\n if (node.type !== 'task' && node.type !== 'subflow') return;\n const enabled = new Set(portsFor(node).map((p) => p.name));\n if (node.impl?.kind === 'role' && !hasInner) {\n for (const port of ['unreachable', 'unchanged']) {\n if (!enabled.has(port)) continue;\n add({\n code: 'port-role-unroutable',\n severity: 'warning',\n message:\n port === 'unreachable'\n ? `${label(node)} runs a role: hosts that become unreachable inside it drop out of the run and cannot take \"unreachable\". Put the connecting step in its own module node or a subflow`\n : `${label(node)} runs a role: Ansible gives no per-host \"changed\" for a role, so \"unchanged\" never fires`,\n path: [...path, 'ports'],\n node: node.id,\n port,\n });\n }\n }\n // AFD-103: a timeout codegen cannot read is left out of the task without a word. AFD-112: a\n // template is read at run time (an approval's: checkTimingInputs).\n const timeout = node.settings?.timeout;\n if (\n !hasInner &&\n timeout !== undefined &&\n String(timeout).trim() &&\n !templated(timeout) &&\n durationSeconds(timeout) === undefined\n ) {\n add({\n code: 'timeout-unreadable',\n severity: 'warning',\n message: `${label(node)} timeout \"${timeout}\" is not a duration (30s, 15m, 1h30m), so the step runs without one`,\n path: [...path, 'settings', 'timeout'],\n node: node.id,\n });\n }\n if (enabled.has('timeout') && !hasInner && !node.settings?.timeout) {\n add({\n code: 'timeout-without-setting',\n severity: 'warning',\n message: `${label(node)} enables \"timeout\" but sets no settings.timeout, so it never fires`,\n path: [...path, 'ports'],\n node: node.id,\n port: 'timeout',\n });\n }\n}\n\nfunction checkTargets(model: FlowModel, add: (f: Finding) => void): void {\n // A list default that is a string (default: edge) is joined letter by letter (AFD-27).\n for (const [name, f] of Object.entries(model.doc.flow?.inputs ?? {}))\n if ((f?.type === 'host_list' || f?.type === 'list') && typeof f.default === 'string')\n add({\n code: 'input-default-type',\n severity: 'warning',\n message: `Flow input ${name} is a ${f.type} but its default is the string \"${f.default}\": write it as a list, [${f.default}]`,\n path: ['flow', 'inputs', name, 'default'],\n });\n const inputs = Object.values(model.doc.flow?.inputs ?? {});\n if (inputs.some((f) => f?.type === 'host_list')) return;\n add({\n code: 'no-targets',\n severity: 'warning',\n message: 'The flow has no host_list input, so start has no hosts and no code can be generated',\n path: ['flow', 'inputs'],\n });\n}\n\nfunction checkApprovalSplit(\n model: FlowModel,\n node: FlowNode,\n levelId: string,\n path: Path,\n add: (f: Finding) => void,\n): void {\n const edges = model.levels.get(levelId)?.edges ?? [];\n const target = (port: string) =>\n edges.find((e) => e?.from?.node === node.id && e.from.port === port)?.to.node;\n const rejected = target('rejected');\n const timeout = target('timeout');\n if (rejected && timeout && rejected !== timeout) {\n add({\n code: 'approval-split',\n severity: 'warning',\n message: `${label(node)}: AWX cannot tell rejected from timeout; both follow one failure path`,\n path,\n node: node.id,\n });\n }\n}\n\n/** Variables every task can read: Ansible's magic and connection variables, loop items, omit. */\nexport const MAGIC_VARS =\n /^(ansible_[a-z0-9_]*|inventory_hostname(_short)?|inventory_dir|inventory_file|hostvars|groups|group_names|play_hosts|playbook_dir|role_path|role_name|omit|item|ansible_loop_var|lookup|query|q|now|range|dict|namespace|loop|afd_[a-z0-9_]*|awx_[a-z0-9_]*|tower_[a-z0-9_]*)$/;\n\nexport function bareParams(impl: NonNullable<FlowNode['impl']>): unknown[] {\n if (impl.kind !== 'module') return [];\n const short = impl.ref.replace(/^ansible\\.(builtin|legacy)\\./, '');\n return (BARE_PARAMS[short] ?? []).map((k) => impl.params?.[k]).filter((v) => v !== undefined);\n}\n\n/**\n * Where a name a node reads could come from, as the fix (AFD-21): the enclosing subflow's input, an\n * upstream output, or an output of a step inside an upstream subflow (which the tools lift).\n */\nfunction hintFor(model: FlowModel, node: FlowNode, level: string, name: string): string {\n for (const sub of enclosing(model, level))\n if (sub.inputs && name in sub.inputs)\n return `; subflow ${sub.key} has it as an input: add input ${name} (from: ${sub.key}.${name})`;\n const upstream = upstreamNodes(model, node.id);\n for (const up of upstream)\n if (up.outputs && name in up.outputs) return `; add input ${name} (from: ${up.key}.${name})`;\n const inside = (sub: FlowNode, path: string): string | undefined => {\n for (const step of sub.subflow?.nodes ?? []) {\n if (!step?.key) continue;\n if (step.outputs && name in step.outputs) return `${path}/${step.key}`;\n const deeper = step.subflow ? inside(step, `${path}/${step.key}`) : undefined;\n if (deeper) return deeper;\n }\n return undefined;\n };\n for (const up of upstream) {\n const at = up.type === 'subflow' ? inside(up, up.key) : undefined;\n if (at)\n return `; ${at} sets it: add input ${name} from ${at}.${name} with the AI tools or the @ picker, which lift it to ${up.key}`;\n }\n return '';\n}\n\n/**\n * Binding parameters read node inputs (chips, D-26). A read of anything else works only by luck\n * (a flow extra var, another node's fact), and the design does not show the data dependency.\n * Bare expressions (assert `that`) are read too (AFD-21).\n */\nfunction checkBindingVars(\n model: FlowModel,\n node: FlowNode,\n level: string,\n path: Path,\n flowInputs: Set<string>,\n external: Set<string>,\n add: (f: Finding) => void,\n): void {\n const impl = node.impl;\n if (!impl) return;\n const inputs = new Set(Object.keys(node.inputs ?? {}));\n // Task keywords read inputs too (AFD-26); loop variables and task vars are their own names, and\n // changed_when / failed_when may read the step's result.\n const kw = keywordReads(impl);\n const known = new Set([\n ...kw.own,\n ...(impl.kind === 'module' ? [registerName(node)] : []),\n ...setFactNames(impl),\n ...external,\n ]);\n const reads: [Set<string>, Path][] = [\n [\n new Set([...refsIn(impl.params ?? {}), ...exprRefs(bareParams(impl))]),\n [...path, 'impl', 'params'],\n ],\n [new Set([...kw.templated, ...kw.bare]), [...path, 'impl', 'keywords']],\n ];\n const reported = new Set<string>();\n const bindingText = JSON.stringify([impl.params ?? {}, impl.keywords ?? {}]);\n for (const [read, where] of reads)\n for (const name of read) {\n if (inputs.has(name) || known.has(name) || MAGIC_VARS.test(name) || reported.has(name))\n continue;\n reported.add(name);\n const flow = flowInputs.has(name);\n // AFD-185: a value read only with a fallback (| default, is defined) cannot fail the task.\n const optional = !flow && onlyGuarded(bindingText, name);\n add({\n code: 'binding-unknown-var',\n severity: flow || optional ? 'info' : 'warning',\n message: flow\n ? `${label(node)} reads flow input \"${name}\" directly: add it as a node input (from: flow.${name}) to show the dependency`\n : optional\n ? `${label(node)} reads \"${name}\" only with a fallback (default or is defined): fine when nothing sets it; an input, or flow.external_vars, shows where it comes from`\n : `${label(node)} reads \"${name}\", which is not an input of this node${hintFor(model, node, level, name)}`,\n path: where,\n node: node.id,\n subject: name,\n });\n }\n const keywords = impl.keywords && typeof impl.keywords === 'object' ? impl.keywords : undefined;\n if (keywords && Object.keys(keywords).length > 0 && impl.kind === 'playbook')\n add({\n code: 'keyword-ignored',\n severity: 'warning',\n message: `${label(node)} runs a playbook: task keywords cannot apply to import_playbook, so they are ignored`,\n path: [...path, 'impl', 'keywords'],\n node: node.id,\n });\n else if (keywords?.vars !== undefined && impl.kind === 'role')\n add({\n code: 'keyword-ignored',\n severity: 'warning',\n message: `${label(node)} runs a role: role variables belong in params, so keywords.vars is ignored`,\n path: [...path, 'impl', 'keywords', 'vars'],\n node: node.id,\n });\n}\n\n/** Decision conditions and `until` read node inputs too (AFD-21); `until` also the step's result. */\nfunction checkConditions(\n model: FlowModel,\n node: FlowNode,\n level: string,\n path: Path,\n flowInputs: Set<string>,\n external: Set<string>,\n add: (f: Finding) => void,\n): void {\n const inputs = new Set(Object.keys(node.inputs ?? {}));\n const check = (expr: string, where: Path, what: string, result?: string) => {\n for (const name of exprRefs(expr)) {\n if (inputs.has(name) || name === result || MAGIC_VARS.test(name) || external.has(name))\n continue;\n const flow = flowInputs.has(name);\n add({\n code: 'condition-unknown-var',\n severity: flow ? 'info' : 'warning',\n message: flow\n ? `${label(node)} ${what} reads flow input \"${name}\" directly: add it as a node input (from: flow.${name}) to show the dependency`\n : `${label(node)} ${what} reads \"${name}\", which is not ${result ? `its result (${result}) or ` : ''}an input of this node${hintFor(model, node, level, name)}`,\n path: where,\n node: node.id,\n subject: name,\n });\n }\n };\n if (node.type === 'decision' && typeof node.condition === 'string') {\n check(node.condition, [...path, 'condition'], 'condition');\n // AFD-146: the generator puts the condition inside a Jinja expression of its own.\n if (conditionHasBraces(node.condition))\n add({\n code: 'condition-braces',\n severity: 'error',\n message: `${label(node)} condition has {{ }} or {% %} inside it: write it as a when: is written, without them (x == 1, not {{ x }} == 1)`,\n path: [...path, 'condition'],\n node: node.id,\n });\n }\n const until = node.settings?.until;\n if (typeof until !== 'string' || !until.trim()) return;\n if (node.impl?.kind === 'role' || node.impl?.kind === 'playbook')\n add({\n code: 'until-not-module',\n severity: 'warning',\n message: `${label(node)} runs a ${node.impl.kind}: until applies to a module step only, so it is ignored`,\n path: [...path, 'settings', 'until'],\n node: node.id,\n });\n else {\n const result = registerName(node);\n check(until, [...path, 'settings', 'until'], 'until', result);\n // AFD-103 (round 3: R2): the whole result is a dict, so comparing it with a value never holds.\n if (comparesWholeResult(until, result))\n add({\n code: 'until-whole-result',\n severity: 'warning',\n message: `${label(node)} until compares the whole result ${result} with a value, so it never holds: test a field of it, like ${result}.stdout or ${result}.rc`,\n path: [...path, 'settings', 'until'],\n node: node.id,\n });\n }\n}\n\n/** The Timing settings a step may take at run time (AFD-112, round 4: Q4). */\nconst RUN_TIME_TIMING = ['retries', 'delay', 'timeout'] as const;\n\n/**\n * AFD-112 (round 4: Q4): Retries, Delay and Timeout given at run time read the step's inputs, as\n * Until does: a name that is no input is not there when Ansible renders the template, and an\n * input that holds no number fails the task.\n */\nfunction checkTimingInputs(\n model: FlowModel,\n node: FlowNode,\n level: string,\n path: Path,\n flowInputs: Set<string>,\n external: Set<string>,\n add: (f: Finding) => void,\n): void {\n if (node.type === 'approval') {\n const timeout = node.settings?.timeout;\n if (templated(timeout))\n add({\n code: 'timeout-unreadable',\n severity: 'warning',\n message: `${label(node)} timeout \"${timeout}\" is given at run time, but an AWX approval needs a fixed duration (30m, 4h), so it gets none`,\n path: [...path, 'settings', 'timeout'],\n node: node.id,\n });\n return;\n }\n const inputs = node.inputs ?? {};\n for (const key of RUN_TIME_TIMING) {\n const value = node.settings?.[key];\n if (!templated(value)) continue;\n const where = [...path, 'settings', key];\n for (const name of exprRefs(value)) {\n if (name in inputs || MAGIC_VARS.test(name) || external.has(name)) continue;\n const flow = flowInputs.has(name);\n add({\n code: 'setting-unknown-var',\n severity: flow ? 'info' : 'warning',\n message: flow\n ? `${label(node)} ${key} reads flow input \"${name}\" directly: add it as a node input (from: flow.${name}) to show the dependency`\n : `${label(node)} ${key} reads \"${name}\", which is not an input of this node${hintFor(model, node, level, name)}`,\n path: where,\n node: node.id,\n subject: name,\n });\n }\n const one = singleRef(value);\n const type = one ? inputs[one]?.type : undefined;\n if (type && ['boolean', 'list', 'dict', 'host_list'].includes(type))\n add({\n code: 'setting-input-type',\n severity: 'warning',\n message: `${label(node)} ${key} reads ${one}, a ${type.replace('_', ' ')}: Ansible needs a whole number${key === 'retries' ? '' : ' of seconds'} there, so the task fails`,\n path: where,\n node: node.id,\n subject: one,\n });\n }\n}\n\n/**\n * AFD-106 (round 3: R7): a step input that nothing feeds. The participant typed a step's register\n * name into a later step; that step got an input with no `from`, and the flow validated clean while\n * the value never passed the designer's way. A default feeds it; a host list is the targets'; a\n * subflow's input feeds its inner steps.\n */\nfunction checkUnfed(\n model: FlowModel,\n node: FlowNode,\n level: string,\n path: Path,\n name: string,\n flowInputs: Set<string>,\n add: (f: Finding) => void,\n): void {\n if (node.type !== 'task' && node.type !== 'approval') return;\n const field = node.inputs?.[name];\n if (!field || field.default !== undefined || field.optional || field.type === 'host_list') return;\n const flow = flowInputs.has(name);\n const registers = upstreamNodes(model, node.id).find(\n (up) => up.impl?.kind === 'module' && registerName(up) === name,\n );\n const hint = flow\n ? `: flow input \"${name}\" has the same name: set from: flow.${name}`\n : registers\n ? `: ${label(registers)} registers ${name}: make it an output there (Expose as node output) and pick it with @`\n : hintFor(model, node, level, name);\n add({\n code: 'input-unfed',\n severity: flow ? 'info' : 'warning',\n message: `${label(node)} inputs.${name}: nothing gives it a value (no from, no default)${hint}`,\n path: [...path, 'inputs', name],\n node: node.id,\n subject: name,\n });\n}\n\n/** A subflow output without from lifts the inner output of the same name (AFD-21). */\nfunction checkLifts(node: FlowNode, path: Path, add: (f: Finding) => void): void {\n if (node.type !== 'subflow' || !node.subflow?.nodes?.length) return;\n for (const [name, field] of Object.entries(node.outputs ?? {})) {\n if (field?.from) continue;\n const lift = liftOf(node, name);\n if (lift && 'inner' in lift) continue;\n add({\n code: 'subflow-output-unset',\n severity: 'warning',\n message: lift\n ? `Subflow ${label(node)} output ${name}: ${lift.ambiguous.join(' and ')} all have it; name one in from (${lift.ambiguous[0]}.${name})`\n : `Subflow ${label(node)} output ${name}: no inner step has an output ${name}, so nothing sets it; name the inner output it lifts in from (<step>.<output>)`,\n path: [...path, 'outputs', name],\n node: node.id,\n });\n }\n}\n\nfunction checkReferences(model: FlowModel, add: (f: Finding) => void): void {\n const flowInputs = new Set(Object.keys(model.doc.flow?.inputs ?? {}));\n const external = externalVars(model);\n for (const { node, path, level } of model.nodes.values()) {\n for (const side of ['inputs', 'outputs'] as const) {\n for (const [name, field] of Object.entries(node[side] ?? {})) {\n const from = field?.from;\n if (typeof from !== 'string' || !from) {\n if (side === 'inputs') checkUnfed(model, node, level, path, name, flowInputs, add);\n continue;\n }\n const src = resolveFrom(model, node, level, side, from);\n // AFD-242: a disabled step makes nothing; what reads it has no value at run time.\n const off = src.kind === 'output' ? disabledBy(model, src.node.id) : undefined;\n if (off && !disabledBy(model, node.id))\n add({\n code: 'reads-disabled',\n severity: 'warning',\n message: `${label(node)} ${side}.${name} reads \"${from}\", but ${label(off)} is disabled and makes nothing: give it a default, or enable ${label(off)}`,\n path: [...path, side, name, 'from'],\n node: node.id,\n subject: name,\n });\n if (src.kind === 'output' && side === 'inputs') {\n const at: Path = [...path, side, name, 'from'];\n checkCollision(model, node, src.node, src.name, from, at, name, add);\n checkShadowed(model, node, src.node, from, at, name, add);\n if (field.default === undefined && !field.optional && !guarded(node, name))\n checkProducerRuns(model, node, src.node, src.name, from, at, name, add);\n }\n if (src.kind !== 'unresolved') continue;\n add({\n code: 'from-unresolved',\n severity: 'warning',\n message: `${label(node)} ${side}.${name}: \"${from}\" ${src.why}`,\n path: [...path, side, name, 'from'],\n node: node.id,\n subject: name,\n });\n }\n }\n checkLifts(node, path, add);\n }\n checkTopLevelOutcomes(model, add);\n for (const { node, path, level } of model.nodes.values()) {\n checkBindingVars(model, node, level, path, flowInputs, external, add);\n checkConditions(model, node, level, path, flowInputs, external, add);\n checkTimingInputs(model, node, level, path, flowInputs, external, add);\n checkPlaybookDir(node, path, add);\n // AFD-273: who decides is a question only an approval asks.\n if (node.approval && node.type !== 'approval')\n add({\n code: 'approval-fields',\n severity: 'warning',\n message: `\"${node.title}\" is not an approval: its approvers, notify and message mean nothing`,\n path: [...path, 'approval'],\n node: node.id,\n });\n }\n const runtime = model.doc.flow?.runtime?.kind;\n const v2 = formatOf(model.doc) >= 2;\n // AWX workflows split at top-level approvals (AFD-11, ADR-0016).\n const plan = planSegments(model);\n for (const p of plan?.problems ?? [])\n add({\n code: 'awx-segments',\n severity: runtime === 'awx_workflow' ? 'error' : 'warning',\n message: `${p.message}. Local and skeleton runs approve automatically`,\n path: p.node ? (model.nodes.get(p.node)?.path ?? []) : ['nodes'],\n node: p.node,\n });\n if (v2 && runtime)\n add({\n code: 'runtime-kind',\n severity: 'info',\n message: `In format 2 the flow's runtime is worked out from the flow (it is ${runtimeKind(model)}): runtime.kind can go`,\n path: ['flow', 'runtime', 'kind'],\n });\n else if (runtime && runtime !== 'ansible_playbook') {\n const split = !!plan && plan.problems.length === 0 && plan.segments.length > 0;\n const inferred = split ? 'awx_workflow' : 'awx_job';\n if (runtime !== inferred) {\n add({\n code: 'runtime-kind',\n severity: 'info',\n message: `runtime.kind is ${runtime}, but the compiled engine produces ${inferred} for this flow`,\n path: ['flow', 'runtime', 'kind'],\n });\n }\n }\n for (const level of model.levels.values()) {\n if (level.id === ROOT) continue;\n const parent = model.nodes.get(level.parent ?? '')?.node;\n if (parent) checkBoundaryFlow(model, parent, level.nodes, level.edges, add);\n const boundary = parent?.subflow?.boundary;\n if (!parent || !boundary) continue;\n const base = model.nodes.get(parent.id)?.path ?? [];\n const inner = new Set(level.nodes.map((n) => n?.id));\n if (boundary.in && !inner.has(boundary.in)) {\n add({\n code: 'boundary-ref',\n severity: 'warning',\n message: `Subflow ${label(parent)}: boundary.in is not an inner node`,\n path: [...base, 'subflow', 'boundary', 'in'],\n node: parent.id,\n });\n }\n const parentPorts = new Set(portsFor(parent).map((p) => p.name));\n for (const [port, refs] of Object.entries(boundary.outputs ?? {})) {\n if (!parentPorts.has(port)) {\n add({\n code: 'boundary-ref',\n severity: 'warning',\n message: `Subflow ${label(parent)}: boundary output \"${port}\" is not a port of the subflow node`,\n path: [...base, 'subflow', 'boundary', 'outputs', port],\n node: parent.id,\n });\n }\n for (const ref of refs ?? []) {\n const from = level.nodes.find((n) => n?.id === ref?.node);\n if (!from) {\n add({\n code: 'boundary-ref',\n severity: 'warning',\n message: `Subflow ${label(parent)}: boundary output \"${port}\" refers to a node outside the subflow`,\n path: [...base, 'subflow', 'boundary', 'outputs', port],\n node: parent.id,\n });\n } else if (!isPortLegal(from, ref.port) || portDirection(ref.port) !== 'out') {\n add({\n code: 'boundary-ref',\n severity: 'warning',\n message: `Subflow ${label(parent)}: ${label(from)} has no output \"${ref.port}\" to leave through \"${port}\"`,\n path: [...base, 'subflow', 'boundary', 'outputs', port],\n node: parent.id,\n });\n } else if (\n level.edges.some((e) => e?.from?.node === ref.node && e.from.port === ref.port)\n ) {\n add({\n code: 'boundary-ref',\n severity: 'warning',\n message: `Subflow ${label(parent)}: ${label(from)} \u00B7 ${ref.port} is wired inside and also leaves through \"${port}\"`,\n path: [...base, 'subflow', 'boundary', 'outputs', port],\n node: parent.id,\n });\n }\n }\n }\n }\n}\n\n/**\n * 03 \"Subflow boundary\": hosts must be able to enter the inner graph, every enabled output of the\n * subflow must be fed from inside (an exit, or a fail port that bubbles up), and an inner outcome\n * that neither continues inside nor leaves the subflow strands its hosts (D-23).\n */\nfunction checkBoundaryFlow(\n model: FlowModel,\n parent: FlowNode,\n nodes: FlowNode[],\n edges: { from: PortRef; to: PortRef }[],\n add: (f: Finding) => void,\n): void {\n const inner = nodes.filter((n): n is FlowNode => !!n?.id);\n if (inner.length === 0) return;\n const base = model.nodes.get(parent.id)?.path ?? [];\n const boundary = parent.subflow?.boundary;\n if (!boundary?.in) {\n add({\n code: 'boundary-no-entry',\n severity: 'warning',\n message: `Subflow ${label(parent)} has no entry step: hosts reaching it never run its inner steps`,\n path: [...base, 'subflow'],\n node: parent.id,\n });\n }\n const taken = levelTaken(edges, parent);\n for (const port of portsFor(parent)) {\n if (port.direction !== 'out' || port.name === 'cancelled') continue;\n const fed =\n (boundary?.outputs?.[port.name] ?? []).length > 0 ||\n fedByBubbling(parent, port.name, inner, taken);\n if (!fed) {\n add({\n code: 'boundary-port-unfed',\n severity: 'warning',\n message: `Subflow ${label(parent)} \u00B7 ${port.name} is never taken: no inner step leaves through it`,\n path: [...base, 'subflow'],\n node: parent.id,\n port: port.name,\n });\n }\n }\n for (const n of inner) {\n for (const p of portsFor(n)) {\n if (p.direction !== 'out' || p.fail || p.name === 'cancelled') continue;\n if (!untaken(n.id, p.name, taken)) continue;\n add({\n code: 'inner-exit-unmapped',\n severity: 'warning',\n message: `${label(n)} \u00B7 ${p.name} inside ${label(parent)} leads nowhere: its hosts never reach an outer port`,\n path: model.nodes.get(n.id)?.path ?? [],\n node: n.id,\n port: p.name,\n });\n }\n }\n}\n\n/**\n * An outcome on the top level that leads nowhere strands its hosts, as an unmapped inner exit\n * does inside a subflow (AFD-31: warned at every level).\n */\nfunction checkTopLevelOutcomes(model: FlowModel, add: (f: Finding) => void): void {\n const level = model.levels.get(ROOT);\n if (!level) return;\n const wired = new Set(level.edges.map((e) => `${e?.from?.node}|${e?.from?.port}`));\n for (const n of level.nodes) {\n if (!n?.id) continue;\n for (const p of portsFor(n)) {\n if (p.direction !== 'out' || p.fail || p.name === 'cancelled') continue;\n if (wired.has(`${n.id}|${p.name}`)) continue;\n add({\n code: 'success-port-unwired',\n severity: 'warning',\n message: `${label(n)} \u00B7 ${p.name} leads nowhere: its hosts stop there without reaching an end node`,\n path: model.nodes.get(n.id)?.path ?? [],\n node: n.id,\n port: p.name,\n });\n }\n }\n}\n\n/**\n * Every use of an input in the binding goes through `| default(\u2026)`, as the handlers an import\n * writes do (`(x_result | default({})) is changed`): a missing value is expected there.\n */\n/**\n * Every read of `name` in the text goes through `| default` or tests whether it is defined, so a\n * missing value is handled where it is read (AFD-185, AFD-187).\n */\nfunction onlyGuarded(text: string, name: string): boolean {\n const uses = text.match(new RegExp(`\\\\b${name}\\\\b`, 'g'))?.length ?? 0;\n const safe =\n (text.match(new RegExp(`\\\\b${name}\\\\s*\\\\|\\\\s*default\\\\b`, 'g'))?.length ?? 0) +\n (text.match(new RegExp(`\\\\b${name}\\\\s+is\\\\s+(not\\\\s+)?(defined|undefined|none)\\\\b`, 'g'))\n ?.length ?? 0);\n return uses > 0 && uses <= safe;\n}\n\nfunction guarded(node: FlowNode, input: string): boolean {\n // A when (or a list item of it) that tests the input guards the whole step.\n const when = node.impl?.keywords?.when;\n const tests = new RegExp(`\\\\b${input}\\\\s+is\\\\s+defined\\\\b`);\n if ((Array.isArray(when) ? when : [when]).some((w) => typeof w === 'string' && tests.test(w)))\n return true;\n const text = JSON.stringify([\n node.impl?.params ?? {},\n node.impl?.keywords ?? {},\n node.condition ?? '',\n node.settings?.until ?? '',\n ]);\n const uses = text.match(new RegExp(`\\\\b${input}\\\\b`, 'g'))?.length ?? 0;\n const safe =\n (text.match(new RegExp(`\\\\b${input}\\\\s*\\\\|\\\\s*default\\\\b`, 'g'))?.length ?? 0) +\n (text.match(new RegExp(`\\\\b${input}\\\\s+is\\\\s+(not\\\\s+)?(defined|undefined|none)\\\\b`, 'g'))\n ?.length ?? 0);\n return uses > 0 && uses <= safe;\n}\n\n/** The step that really sets a node's output: a subflow output follows its lift inward. */\nfunction producerOf(node: FlowNode, output: string, depth = 0): FlowNode {\n if (node.type !== 'subflow' || depth > 16) return node;\n const lift = liftOf(node, output);\n return lift && 'inner' in lift ? producerOf(lift.inner, lift.output, depth + 1) : node;\n}\n\n/**\n * The host variables steps write, by step: every module step's register, and the variables\n * outputs land in (a register, or the step's own captured variable, AFD-53).\n */\nfunction hostVariables(model: FlowModel): Map<string, Set<Ulid>> {\n const vars = new Map<string, Set<Ulid>>();\n const add = (root: string, id: Ulid) => vars.set(root, (vars.get(root) ?? new Set()).add(id));\n for (const { node } of model.nodes.values()) {\n if (node.type === 'subflow') continue;\n if (node.impl?.kind === 'module') add(registerName(node), node.id);\n for (const out of Object.keys(node.outputs ?? {}))\n add(outputVar(model, node, out).split('.')[0] ?? out, node.id);\n }\n return vars;\n}\n\nconst variablesOf = new WeakMap<FlowModel, Map<string, Set<Ulid>>>();\n\n/**\n * `from: a.result` reads a host variable (AFD-31). Outputs other than registers are captured into\n * the step's own variable (AFD-53); a register is named by the flow, so another step registering the\n * same name, or a flow input (an extra var) of that name, changes what the reader gets: an error.\n */\nfunction checkCollision(\n model: FlowModel,\n reader: FlowNode,\n target: FlowNode,\n output: string,\n from: string,\n path: Path,\n input: string,\n add: (f: Finding) => void,\n): void {\n const producer = producerOf(target, output);\n const root = outputVar(model, target, output).split('.')[0] ?? output;\n let vars = variablesOf.get(model);\n if (!vars) {\n vars = hostVariables(model);\n variablesOf.set(model, vars);\n }\n const others = [...(vars.get(root) ?? [])]\n .filter((id) => id !== producer.id)\n .map((id) => label(model.nodes.get(id)?.node));\n const flowInput = root in (model.doc.flow?.inputs ?? {});\n if (others.length === 0 && !flowInput) return;\n const who = [...(flowInput ? [`the flow input ${root}`] : []), ...others].join(', ');\n add({\n code: 'register-collision',\n severity: 'error',\n message: `${label(reader)} inputs.${input}: \"${from}\" reads the register ${root}, which ${who} also set${others.length + (flowInput ? 1 : 0) > 1 ? '' : 's'}: it reads ${flowInput ? 'the flow input' : 'whichever ran last'}`,\n path,\n node: reader.id,\n });\n}\n\n/** The nodes reachable on a level from `start` over its wires, never passing `skip`. */\nfunction reachable(\n edges: { from: PortRef; to: PortRef }[],\n start: Ulid[],\n skip?: Ulid,\n blocked?: Set<string>,\n): Set<Ulid> {\n const seen = new Set<Ulid>(start.filter((s) => s !== skip));\n const queue = [...seen];\n const open = blocked?.size\n ? edges.filter((e) => !blocked.has(`${e?.from?.node}|${e?.from?.port}`))\n : edges;\n // AFD-162: wires by node, built once per level, instead of every wire per visited node.\n for (let i = 0; i < queue.length; i++)\n for (const to of successors(open, queue[i] as Ulid)) {\n if (to === skip || seen.has(to)) continue;\n seen.add(to);\n queue.push(to);\n }\n return seen;\n}\n\ntype ModelLevel = NonNullable<ReturnType<FlowModel['levels']['get']>>;\n\n/** Where a `from:` is checked: the producer's level, the reader (or the subflow around it) on it. */\nfunction producerPlace(\n model: FlowModel,\n reader: FlowNode,\n producer: FlowNode,\n): { level: ModelLevel; target: Ulid; entries: Ulid[] } | undefined {\n const where = model.nodes.get(producer.id)?.level;\n const level = where ? model.levels.get(where) : undefined;\n if (!level) return undefined;\n let at = model.nodes.get(reader.id);\n while (at && at.level !== where) at = model.nodes.get(at.level);\n if (!at || at.node.id === producer.id) return undefined;\n const parent = level.parent ? model.nodes.get(level.parent)?.node : undefined;\n const entries =\n level.id === ROOT\n ? level.nodes.filter((n) => n?.type === 'start').map((n) => n.id)\n : parent?.subflow?.boundary?.in\n ? [parent.subflow.boundary.in]\n : [];\n return { level, target: at.node.id, entries };\n}\n\n/**\n * AFD-212: whether a step sets a host variable of this name: its register, a set_fact of it, or an\n * output of that name (a step's output is a fact of its own name, AFD-53). Generated plays pass an\n * input as a play var, and Ansible ranks set_fact and register above play vars: once a step has\n * set the input's name, the reader gets that fact, whatever its `from:` names.\n */\nfunction setsName(node: FlowNode, name: string): boolean {\n if (node.type === 'subflow') return false;\n const impl = node.impl;\n if (impl?.kind === 'module' && (registerName(node) === name || setFactNames(impl).includes(name)))\n return true;\n return !!node.outputs && name in node.outputs && !fromRegister(node, name);\n}\n\n/** The steps that set a name, and those with every subflow around them (which may set it). */\ninterface NameSetters {\n sets: Set<Ulid>;\n may: Set<Ulid>;\n}\n\nconst settersByModel = new WeakMap<FlowModel, Map<string, NameSetters>>();\n\nfunction nameSetters(model: FlowModel, name: string): NameSetters {\n let byName = settersByModel.get(model);\n if (!byName) {\n byName = new Map();\n settersByModel.set(model, byName);\n }\n let found = byName.get(name);\n if (!found) {\n found = { sets: new Set(), may: new Set() };\n for (const { node } of model.nodes.values()) {\n if (!setsName(node, name)) continue;\n found.sets.add(node.id);\n for (let at = model.nodes.get(node.id); at; at = model.nodes.get(at.level))\n found.may.add(at.node.id);\n }\n byName.set(name, found);\n }\n return found;\n}\n\n/** Where a node's wires lead from its success ports (not its fail ports). */\nfunction okTargets(level: ModelLevel, node: Ulid): Ulid[] {\n return level.edges\n .filter((e) => e?.from?.node === node && !isFailPort(e.from.port))\n .map((e) => e.to.node);\n}\n\n/**\n * The step a `from:` reads must have run, and succeeded, for every host that gets here (AFD-31):\n * on its level it lies on every path from the entry to the reader (or the subflow holding it), and\n * no path from its fail ports leads there. AFD-212: a step on that level that sets the input's own\n * name does as well, since the reader gets that fact (see setsName).\n */\nfunction checkProducerRuns(\n model: FlowModel,\n reader: FlowNode,\n producer: FlowNode,\n output: string | undefined,\n from: string,\n path: Path,\n input: string,\n add: (f: Finding) => void,\n): void {\n const place = producerPlace(model, reader, producer);\n if (!place) return;\n const { level, target, entries } = place;\n const setters = nameSetters(model, input);\n const others = level.nodes.filter(\n (n): n is FlowNode =>\n !!n &&\n n.id !== producer.id &&\n n.id !== target &&\n (setters.sets.has(n.id) || (n.type === 'subflow' && input in (n.outputs ?? {}))),\n );\n const covers = new Set([producer.id, ...others.map((n) => n.id)]);\n const by = others.length\n ? `${label(producer)} or ${others.map(label).join(', ')} (which set ${input} too)`\n : label(producer);\n const say = (why: string) =>\n add({\n code: 'ref-may-be-undefined',\n severity: 'warning',\n message: `${label(reader)} inputs.${input}: \"${from}\" ${why}: those hosts arrive without the value`,\n path,\n node: reader.id,\n subject: input,\n });\n // AFD-187: a decision that tests the value is defined keeps hosts without it off its true side.\n const guards = definedGuards(level.nodes, [input, ...(output ? [output] : [])]);\n // Past a step that sets the value, a host has it; one that fails in it has what it had before.\n const notRun = new Set(guards);\n const notSet = new Set(guards);\n for (const e of level.edges) {\n if (!e?.from || !covers.has(e.from.node)) continue;\n const key = `${e.from.node}|${e.from.port}`;\n notRun.add(key);\n if (!isFailPort(e.from.port)) notSet.add(key);\n }\n if (entries.length > 0 && reachable(level.edges, entries, undefined, notRun).has(target)) {\n say(`is set by ${by}, which some paths to here do not run`);\n return;\n }\n const failed = level.edges\n .filter((e) => e?.from && covers.has(e.from.node) && isFailPort(e.from.port))\n .map((e) => e.to.node);\n const starts = entries.length > 0 ? entries : failed;\n if (failed.length > 0 && reachable(level.edges, starts, undefined, notSet).has(target))\n say(`is set by ${by}, and hosts that fail in it still get here`);\n}\n\n/**\n * AFD-212: another step sets the input's own name where it wins over the `from:` (see setsName):\n * after the `from:` step when that step sets the name too, else anywhere before the reader.\n */\nfunction checkShadowed(\n model: FlowModel,\n reader: FlowNode,\n producer: FlowNode,\n from: string,\n path: Path,\n input: string,\n add: (f: Finding) => void,\n): void {\n const setters = nameSetters(model, input);\n if (setters.may.size === 0) return;\n const place = producerPlace(model, reader, producer);\n if (!place) return;\n const { level, target, entries } = place;\n const producerSets = setters.may.has(producer.id);\n const before = producerSets\n ? reachable(level.edges, okTargets(level, producer.id))\n : reachable(level.edges, entries);\n const later = level.nodes.filter(\n (n): n is FlowNode =>\n !!n &&\n n.id !== producer.id &&\n n.id !== target &&\n setters.may.has(n.id) &&\n before.has(n.id) &&\n reachable(level.edges, okTargets(level, n.id)).has(target),\n );\n if (later.length === 0) return;\n const names = later.map(label).join(', ');\n add({\n code: 'input-shadowed',\n severity: 'warning',\n message: `${label(reader)} inputs.${input}: \"${from}\" is not what the step reads after ${names}: ${later.length > 1 ? 'they set' : 'it sets'} ${input} too, and a set_fact or register wins over the input, so the step reads the value set last`,\n path,\n node: reader.id,\n subject: input,\n });\n}\n\n/** D-09: you cannot roll back a device you cannot reach. */\nfunction checkUnreachableRollback(model: FlowModel, add: (f: Finding) => void): void {\n for (const { edge, path } of model.edges.values()) {\n if (edge?.from?.port !== 'unreachable') continue;\n const target = model.nodes.get(edge.to?.node)?.node;\n if (!isRollback(target)) continue;\n const source = model.nodes.get(edge.from.node)?.node;\n add({\n code: 'rollback-unreachable',\n severity: 'warning',\n message: `${label(source)} \u00B7 unreachable goes to ${label(target)}: unreachable hosts cannot be rolled back; notify or retry instead`,\n path,\n edge: edge.id,\n });\n }\n}\n\n/**\n * Decisions in either format (AFD-51): each names something that exists and says why. Ports also\n * get the AFD-15 checks (a fail port, one decision, not wired).\n */\nfunction checkDecisions(model: FlowModel, add: (f: Finding) => void): void {\n const seen = new Set<string>();\n (model.doc.decisions ?? []).forEach((d, i) => {\n const a = acceptedOf(d, i);\n if (!a) return;\n const path: Path = ['decisions', i];\n const entry = a.node ? model.nodes.get(a.node) : undefined;\n const what =\n a.area === 'port'\n ? 'Open-on-purpose decision'\n : a.area === 'drift'\n ? 'Ignored drift item'\n : a.area === 'lens'\n ? `Accepted finding ${a.what}`\n : `Accepted problem ${a.what}`;\n if (a.node && !entry) {\n add({\n code: 'stale-decision',\n severity: 'warning',\n message: `${what} refers to a node that does not exist: ${a.node}`,\n path,\n });\n return;\n }\n if (a.area === 'port') {\n if (!entry || !portsFor(entry.node).some((p) => p.name === a.what)) {\n add({\n code: 'stale-decision',\n severity: 'warning',\n message: `Decision refers to a port that does not exist: ${a.node} \u00B7 ${a.what}`,\n path,\n });\n return;\n }\n const id = `${a.node}|${a.what}`;\n if (seen.has(id))\n add({\n code: 'duplicate-decision',\n severity: 'warning',\n message: `${label(entry.node)} \u00B7 ${a.what} has more than one decision`,\n path,\n node: a.node,\n });\n seen.add(id);\n if (!isFailPort(a.what))\n add({\n code: 'decision-not-fail',\n severity: 'info',\n message: `${label(entry.node)} \u00B7 ${a.what} is not a fail port; open on purpose has no effect`,\n path,\n node: a.node,\n });\n const edges = model.levels.get(entry.level)?.edges ?? [];\n if (edges.some((e) => e?.from?.node === a.node && e.from.port === a.what))\n add({\n code: 'decision-on-connected',\n severity: 'info',\n message: `${label(entry.node)} \u00B7 ${a.what} is wired; its open-on-purpose decision has no effect`,\n path,\n node: a.node,\n });\n }\n if (!a.reason?.trim())\n add({\n code: 'decision-no-reason',\n severity: 'warning',\n message:\n a.area === 'port' && entry\n ? `Open-on-purpose decision for ${label(entry.node)} \u00B7 ${a.what} has no reason`\n : `${what}${entry ? ` for ${label(entry.node)}` : ''} has no reason`,\n path,\n ...(a.node ? { node: a.node } : {}),\n });\n });\n}\n\n/**\n * AFD-187: the true ports of decisions that test one of `names` is defined (`x is defined`, not\n * negated): hosts without the value take false there, so paths through true do not count.\n */\nfunction definedGuards(nodes: (FlowNode | undefined)[], names: string[]): Set<string> {\n const out = new Set<string>();\n for (const n of nodes) {\n if (n?.type !== 'decision' || typeof n.condition !== 'string') continue;\n for (const name of names)\n if (new RegExp(`\\\\b${name}\\\\s+is\\\\s+defined\\\\b`).test(n.condition)) out.add(`${n.id}|true`);\n }\n return out;\n}\n\n/** AFD-183: the facts a set_fact step sets, which its own parameters may read (accumulators). */\nfunction setFactNames(impl: NonNullable<FlowNode['impl']>): string[] {\n if (impl.kind !== 'module' || !takesFreeKeys(impl.ref)) return [];\n return Object.keys(impl.params ?? {}).filter((k) => k !== 'cacheable');\n}\n\n/** AFD-185: variables the flow says are set outside it at run time (flow.external_vars). */\nfunction externalVars(model: FlowModel): Set<string> {\n const ext = model.doc.flow?.external_vars;\n return new Set(ext && typeof ext === 'object' ? Object.keys(ext) : []);\n}\n\n/**\n * AFD-176: generated plays run from generated/, so a parameter that reads playbook_dir finds\n * nothing the source kept next to its playbook. afd_repo_root is the repository root.\n */\nfunction checkPlaybookDir(node: FlowNode, path: Path, add: (f: Finding) => void): void {\n const impl = node.impl;\n if (!impl || impl.kind === 'playbook') return;\n if (!/\\bplaybook_dir\\b/.test(JSON.stringify([impl.params ?? null, impl.keywords ?? null])))\n return;\n add({\n code: 'binding-playbook-dir',\n severity: 'warning',\n message: `${label(node)} reads playbook_dir, which is the flow's generated/ folder when it runs: write repository paths from {{ afd_repo_root }}, the repository root the generated play sets`,\n path: [...path, 'impl'],\n node: node.id,\n });\n}\n"],
5
- "mappings": "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",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../../../src/core/view/route.ts"],
4
- "sourcesContent": ["// Wires that step round nodes (AFD-70). A wire is React Flow's smooth step from port to port, as\n// before, wherever that clears every node box. Where it would run through one (a wire that skips a\n// step, or one back up the flow), it takes an orthogonal route round the boxes instead: short, few\n// turns, clear of the boxes, drawn with the same stubs and rounded corners. The canvas edge, the\n// export scenes and the layout check all route here, so every picture of a level shows the same\n// wires.\nimport { getSmoothStepPath, Position as Side } from '@xyflow/system';\nimport type { Position } from '../flow/types';\n\nexport interface Box {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\nexport interface Route {\n /** SVG path in canvas pixels. */\n path: string;\n /** Where the wire's label sits. */\n label: Position;\n /** A route round boxes: its corners between the two ends (draw.io waypoints). */\n bends?: Position[];\n}\n\n/** getSmoothStepPath's defaults: the stub out of a port and the corner radius. */\nconst OFFSET = 20;\nconst RADIUS = 5;\n/** A wire that only grazes a box edge is not through it: boxes shrink by this much first. */\nexport const INSET = 2;\n/** Routes keep as far from a box as a stub keeps from its node (handle face 5 + stub 20)... */\nconst CLEAR = 25;\n/** ...and, in a narrow gap, never come closer than this. */\nconst GAP = 8;\n/** A bend costs as much as this much more wire... */\nconst BEND = 40;\n/** ...and wire closer to a box than CLEAR costs this much more again... */\nconst NEAR = 1;\n/**\n * ...and wire off the two lines through its stub ends a little more, so of equal routes it takes\n * the one that turns onto its stubs: wires into one port then share their last stretch.\n */\nconst DRIFT = 0.01;\n\n/** Directions of travel, clockwise from up; a port's side is the way its stub leaves. */\nconst DIRS: Position[] = [\n { x: 0, y: -1 },\n { x: 1, y: 0 },\n { x: 0, y: 1 },\n { x: -1, y: 0 },\n];\nconst DIR_OF: Record<Side, number> = {\n [Side.Top]: 0,\n [Side.Right]: 1,\n [Side.Bottom]: 2,\n [Side.Left]: 3,\n};\n\n// ---- geometry shared with the layout check ------------------------------------------------------\n\n/** The corners a stepped path passes: its M, L and Q points in order (Q's control is a corner). */\nexport function pointsOf(path: string): Position[] {\n const n = path.match(/-?\\d+(\\.\\d+)?(e-?\\d+)?/g)?.map(Number) ?? [];\n const out: Position[] = [];\n for (let i = 0; i + 1 < n.length; i += 2) out.push({ x: n[i] as number, y: n[i + 1] as number });\n return out;\n}\n\nexport const overlaps = (a: Box, b: Box) =>\n a.x < b.x + b.width && b.x < a.x + a.width && a.y < b.y + b.height && b.y < a.y + a.height;\n\n/** The box shrunk by `by` on every side (grown when negative). */\nexport const inset = (b: Box, by: number): Box => ({\n x: b.x + by,\n y: b.y + by,\n width: Math.max(0, b.width - 2 * by),\n height: Math.max(0, b.height - 2 * by),\n});\n\n/** Whether segment a\u2013b passes through the box (Liang\u2013Barsky clipping). */\nexport function segmentHits(a: Position, b: Position, r: Box): boolean {\n let t0 = 0;\n let t1 = 1;\n const dx = b.x - a.x;\n const dy = b.y - a.y;\n const edges: [number, number][] = [\n [-dx, a.x - r.x],\n [dx, r.x + r.width - a.x],\n [-dy, a.y - r.y],\n [dy, r.y + r.height - a.y],\n ];\n for (const [p, q] of edges) {\n if (p === 0) {\n if (q < 0) return false;\n continue;\n }\n const t = q / p;\n if (p < 0) t0 = Math.max(t0, t);\n else t1 = Math.min(t1, t);\n if (t0 > t1) return false;\n }\n return true;\n}\n\n/** Whether a polyline runs through any of the boxes. */\nexport function runsThrough(points: Position[], boxes: readonly Box[]): boolean {\n for (const box of boxes) {\n const r = inset(box, INSET);\n for (let i = 0; i + 1 < points.length; i++)\n if (segmentHits(points[i] as Position, points[i + 1] as Position, r)) return true;\n }\n return false;\n}\n\n/** A wire label as the canvas draws it: 10 px mono text (6 px a character) on a padded background. */\nexport function labelBox(text: string, at: Position): Box {\n const w = [...text].length * 6 + 8;\n return { x: at.x - w / 2, y: at.y - 8, width: w, height: 16 };\n}\n\n// ---- routing ------------------------------------------------------------------------------------\n\n/**\n * The wire from `a` (leaving by side `from`) to `b` (entered by side `to`) among the node boxes of\n * its level, its own two included. `label` is the text it shows, kept off the boxes on a route.\n */\nexport function routeWire(\n a: Position,\n from: Side,\n b: Position,\n to: Side,\n boxes: readonly Box[],\n label?: string,\n): Route {\n const [path, x, y] = getSmoothStepPath({\n sourceX: a.x,\n sourceY: a.y,\n sourcePosition: from,\n targetX: b.x,\n targetY: b.y,\n targetPosition: to,\n });\n const step = { path, label: { x, y } };\n if (!runsThrough(pointsOf(path), boxes)) return step;\n // Boxed in (a node on a port, or no gap wide enough): the smooth step, as before.\n const points = roundBoxes(a, DIR_OF[from], b, DIR_OF[to], boxes);\n if (!points) return step;\n return { path: pathOf(points), label: labelOn(points, boxes, label), bends: points.slice(1, -1) };\n}\n\n/** Grid lines: the stub ends, the lines CLEAR off each box edge, and the middle of a gap too narrow for those. */\nfunction lines(s: number, t: number, edges: [number, number][]): number[] {\n const all = edges.flat().sort((p, q) => p - q);\n const out = [s, t];\n for (const [lo, hi] of edges) out.push(lo - CLEAR, hi + CLEAR);\n for (let i = 0; i + 1 < all.length; i++) {\n const gap = (all[i + 1] as number) - (all[i] as number);\n if (gap > 2 * GAP && gap < 2 * CLEAR)\n out.push(((all[i] as number) + (all[i + 1] as number)) / 2);\n }\n return [...new Set(out)].sort((p, q) => p - q);\n}\n\n/**\n * The route's corners, from `a` to `b`, keeping the smooth step's stubs: it leaves the source stub\n * heading out and enters the target stub heading in. Nodes far off the two ends are left out of\n * the search; when that finds nothing, it runs again with every node.\n */\nfunction roundBoxes(\n a: Position,\n from: number,\n b: Position,\n to: number,\n boxes: readonly Box[],\n): Position[] | undefined {\n const out = DIRS[from] as Position;\n const back = DIRS[to] as Position;\n const s = { x: a.x + out.x * OFFSET, y: a.y + out.y * OFFSET };\n const t = { x: b.x + back.x * OFFSET, y: b.y + back.y * OFFSET };\n if (runsThrough([a, s], boxes) || runsThrough([t, b], boxes)) return undefined;\n for (const reach of [REACH, Number.POSITIVE_INFINITY]) {\n const near = nearby(s, t, boxes, reach);\n const found = search(s, from, t, (to + 2) % 4, near);\n if (found) return corners([a, ...found, b]);\n if (near.length === boxes.length) break;\n }\n return undefined;\n}\n\n/** How far round the two ends a first search looks: about two node widths. */\nconst REACH = 400;\n\n/**\n * The boxes within `reach` of the box spanning s and t, and then every box the search grid they\n * make would reach, so a grid segment can never jump a box it does not know.\n */\nfunction nearby(s: Position, t: Position, boxes: readonly Box[], reach: number): readonly Box[] {\n if (!Number.isFinite(reach)) return boxes;\n const span = (pts: Position[], pad: number): Box => {\n const xs = pts.map((p) => p.x);\n const ys = pts.map((p) => p.y);\n const [x, y] = [Math.min(...xs) - pad, Math.min(...ys) - pad];\n return { x, y, width: Math.max(...xs) + pad - x, height: Math.max(...ys) + pad - y };\n };\n let near = boxes.filter((r) => overlaps(r, span([s, t], reach)));\n for (;;) {\n const grid = span(\n [s, t, ...near.flatMap((r) => [r, { x: r.x + r.width, y: r.y + r.height }])],\n CLEAR + GAP,\n );\n const more = boxes.filter((r) => near.includes(r) || overlaps(r, grid));\n if (more.length === near.length) return near;\n near = more;\n }\n}\n\n/**\n * A* over a grid of lines in (point, direction) states: cost is length (more near a box) plus\n * BEND a turn, and no U-turns. A stretch into a box is not taken. From s heading `from` to t heading `into`; the grid points passed.\n */\nfunction search(\n s: Position,\n from: number,\n t: Position,\n into: number,\n boxes: readonly Box[],\n): Position[] | undefined {\n const xs = lines(\n s.x,\n t.x,\n boxes.map((r) => [r.x, r.x + r.width]),\n );\n const ys = lines(\n s.y,\n t.y,\n boxes.map((r) => [r.y, r.y + r.height]),\n );\n const nx = xs.length;\n const ny = ys.length;\n // Per stretch between neighbouring grid points, across (i,j)-(i+1,j) and down (i,j)-(i,j+1):\n // -1 when it enters a box grown by GAP, else how much of it runs closer to a box than CLEAR.\n const across = new Float32Array(nx * ny);\n const down = new Float32Array(nx * ny);\n const mark = (\n to: Float32Array,\n k: number,\n lo: number,\n hi: number,\n g0: number,\n g1: number,\n c0: number,\n c1: number,\n inside: boolean,\n ) => {\n if (hi <= c0 || lo >= c1 || (to[k] as number) < 0) return;\n if (inside && hi > g0 && lo < g1) to[k] = -1;\n else to[k] = Math.max(to[k] as number, Math.min(hi, c1) - Math.max(lo, c0));\n };\n for (const r of boxes) {\n const [gx0, gx1, gy0, gy1] = [r.x - GAP, r.x + r.width + GAP, r.y - GAP, r.y + r.height + GAP];\n const [cx0, cx1, cy0, cy1] = [\n r.x - CLEAR,\n r.x + r.width + CLEAR,\n r.y - CLEAR,\n r.y + r.height + CLEAR,\n ];\n for (let j = 0; j < ny; j++) {\n const y = ys[j] as number;\n if (y <= cy0 || y >= cy1) continue;\n for (let i = 0; i + 1 < nx; i++)\n mark(\n across,\n i * ny + j,\n xs[i] as number,\n xs[i + 1] as number,\n gx0,\n gx1,\n cx0,\n cx1,\n y > gy0 && y < gy1,\n );\n }\n for (let i = 0; i < nx; i++) {\n const x = xs[i] as number;\n if (x <= cx0 || x >= cx1) continue;\n for (let j = 0; j + 1 < ny; j++)\n mark(\n down,\n i * ny + j,\n ys[j] as number,\n ys[j + 1] as number,\n gy0,\n gy1,\n cy0,\n cy1,\n x > gx0 && x < gx1,\n );\n }\n }\n const inBox = (p: Position) =>\n boxes.some(\n (r) =>\n p.x > r.x - GAP &&\n p.x < r.x + r.width + GAP &&\n p.y > r.y - GAP &&\n p.y < r.y + r.height + GAP,\n );\n if (inBox(s) || inBox(t)) return undefined;\n const si = xs.indexOf(s.x);\n const sj = ys.indexOf(s.y);\n const ti = xs.indexOf(t.x);\n const tj = ys.indexOf(t.y);\n const states = nx * ny * 4;\n const cost = new Float64Array(states).fill(Number.POSITIVE_INFINITY);\n const prev = new Int32Array(states).fill(-1);\n // Distance left, plus the turns any route from here must still make (a lower bound, so A*\n // stays exact): none straight ahead in the right heading, one from a heading across it, else two.\n // At t itself none: the step onto t paid for its last turn.\n const h = (i: number, j: number, d: number) => {\n const dx = t.x - (xs[i] as number);\n const dy = t.y - (ys[j] as number);\n if (dx === 0 && dy === 0) return 0;\n const step = DIRS[d] as Position;\n const turns =\n d === into\n ? dx * step.y === dy * step.x && dx * step.x + dy * step.y >= 0\n ? 0\n : 2\n : d === (into + 2) % 4\n ? 2\n : 1;\n return Math.abs(dx) + Math.abs(dy) + turns * BEND;\n };\n const heap = new Heap();\n const start = (si * ny + sj) * 4 + from;\n cost[start] = 0;\n heap.push(h(si, sj, from), 0, start);\n let goal = -1;\n while (heap.size > 0) {\n const { key: f, value: k } = heap.pop();\n const d = k % 4;\n const p = (k - d) / 4;\n const i = Math.floor(p / ny);\n const j = p % ny;\n if (f > (cost[k] as number) + h(i, j, d)) continue;\n if (i === ti && j === tj) {\n goal = k;\n break;\n }\n for (let nd = 0; nd < 4; nd++) {\n if (nd === (d + 2) % 4) continue;\n const step = DIRS[nd] as Position;\n const ni = i + step.x;\n const nj = j + step.y;\n if (ni < 0 || nj < 0 || ni >= nx || nj >= ny) continue;\n const flat = nd % 2 === 1;\n const near = flat\n ? (across[Math.min(i, ni) * ny + j] as number)\n : (down[i * ny + Math.min(j, nj)] as number);\n if (near < 0) continue;\n const x = xs[i] as number;\n const y = ys[j] as number;\n const len = flat ? Math.abs((xs[ni] as number) - x) : Math.abs((ys[nj] as number) - y);\n const stub = flat ? y === s.y || y === t.y : x === s.x || x === t.x;\n let c =\n (cost[k] as number) + len * (stub ? 1 : 1 + DRIFT) + near * NEAR + (nd === d ? 0 : BEND);\n const nk = (ni * ny + nj) * 4 + nd;\n if (ni === ti && nj === tj) {\n if (nd === (into + 2) % 4) continue;\n if (nd !== into) c += BEND;\n }\n if (c < (cost[nk] as number)) {\n cost[nk] = c;\n prev[nk] = k;\n heap.push(c + h(ni, nj, nd), c, nk);\n }\n }\n }\n if (goal < 0) return undefined;\n const path: Position[] = [];\n for (let k = goal; k >= 0; k = prev[k] as number) {\n const p = (k - (k % 4)) / 4;\n path.push({ x: xs[Math.floor(p / ny)] as number, y: ys[p % ny] as number });\n }\n return path.reverse();\n}\n\n/** The points where the route turns, with its two ends. */\nfunction corners(points: Position[]): Position[] {\n const out: Position[] = [];\n for (const p of points) {\n const q = out.at(-1);\n if (q && q.x === p.x && q.y === p.y) continue;\n const o = out.at(-2);\n if (o && q && ((o.x === q.x && q.x === p.x) || (o.y === q.y && q.y === p.y))) out.pop();\n out.push(p);\n }\n return out;\n}\n\n/** The route as getSmoothStepPath draws its own points: rounded corners of radius RADIUS. */\nfunction pathOf(points: Position[]): string {\n const first = points[0] as Position;\n const last = points.at(-1) as Position;\n let path = `M${first.x} ${first.y}`;\n for (let i = 1; i < points.length - 1; i++)\n path += bendAt(points[i - 1] as Position, points[i] as Position, points[i + 1] as Position);\n return `${path}L${last.x} ${last.y}`;\n}\n\n/** @xyflow/system's getBend (not exported), so a route's corners match a smooth step's. */\nfunction bendAt(a: Position, b: Position, c: Position): string {\n const size = Math.min(\n Math.hypot(a.x - b.x, a.y - b.y) / 2,\n Math.hypot(b.x - c.x, b.y - c.y) / 2,\n RADIUS,\n );\n const { x, y } = b;\n if ((a.x === x && x === c.x) || (a.y === y && y === c.y)) return `L${x} ${y}`;\n if (a.y === y) {\n const xDir = a.x < c.x ? -1 : 1;\n const yDir = a.y < c.y ? 1 : -1;\n return `L ${x + size * xDir},${y}Q ${x},${y} ${x},${y + size * yDir}`;\n }\n const xDir = a.x < c.x ? 1 : -1;\n const yDir = a.y < c.y ? -1 : 1;\n return `L ${x},${y + size * yDir}Q ${x},${y} ${x + size * xDir},${y}`;\n}\n\n/** Length of a straight stretch. */\nconst length = (p: Position, q: Position) => Math.abs(q.x - p.x) + Math.abs(q.y - p.y);\n\n/**\n * Where a route's label goes: on the first stretch from the source that holds it clear of every\n * box, as near that stretch's middle as it can, so a label names the port its wire leaves by.\n * Without a clear spot, half way along.\n */\nfunction labelOn(points: Position[], boxes: readonly Box[], text: string | undefined): Position {\n for (let i = 0; text && i + 1 < points.length; i++) {\n const p = points[i] as Position;\n const q = points[i + 1] as Position;\n const len = length(p, q);\n const along = p.y === q.y ? labelBox(text, p).width : 16;\n const room = (len - along - 8) / 2;\n const ux = Math.sign(q.x - p.x);\n const uy = Math.sign(q.y - p.y);\n for (let k = 0; k <= room; k += 8)\n for (const sign of k ? [-1, 1] : [1]) {\n const o = len / 2 + sign * k;\n const at = { x: p.x + ux * o, y: p.y + uy * o };\n const box = labelBox(text, at);\n if (!boxes.some((r) => overlaps(box, r))) return at;\n }\n }\n const legs = points.slice(1).map((q, i) => length(points[i] as Position, q));\n let rest = legs.reduce((sum, len) => sum + len, 0) / 2;\n for (let i = 0; i + 1 < points.length; i++) {\n const p = points[i] as Position;\n const q = points[i + 1] as Position;\n const len = legs[i] as number;\n if (rest <= len)\n return { x: p.x + Math.sign(q.x - p.x) * rest, y: p.y + Math.sign(q.y - p.y) * rest };\n rest -= len;\n }\n return points[0] as Position;\n}\n\n/**\n * A binary min-heap of states by priority. Of equal priorities the one furthest along goes first\n * (else A* widens over every equally short path on a grid), then the first pushed, so a route is\n * the same wherever it is drawn. The heap holds entry numbers; an entry's fields are stored once.\n */\nclass Heap {\n private heap: number[] = [];\n private keys: number[] = [];\n private depths: number[] = [];\n private values: number[] = [];\n\n get size(): number {\n return this.heap.length;\n }\n\n push(key: number, depth: number, value: number): void {\n const e = this.keys.length;\n this.keys.push(key);\n this.depths.push(depth);\n this.values.push(value);\n const h = this.heap;\n let i = h.length;\n h.push(e);\n while (i > 0) {\n const up = (i - 1) >> 1;\n if (!this.before(e, h[up] as number)) break;\n h[i] = h[up] as number;\n i = up;\n }\n h[i] = e;\n }\n\n /** Takes the first entry off: its priority and value. */\n pop(): { key: number; value: number } {\n const h = this.heap;\n const top = h[0] as number;\n const last = h.pop() as number;\n if (h.length > 0) {\n let i = 0;\n for (;;) {\n const l = 2 * i + 1;\n if (l >= h.length) break;\n const r = l + 1;\n const c = r < h.length && this.before(h[r] as number, h[l] as number) ? r : l;\n if (!this.before(h[c] as number, last)) break;\n h[i] = h[c] as number;\n i = c;\n }\n h[i] = last;\n }\n return { key: this.keys[top] as number, value: this.values[top] as number };\n }\n\n private before(a: number, b: number): boolean {\n const ka = this.keys[a] as number;\n const kb = this.keys[b] as number;\n if (ka !== kb) return ka < kb;\n const da = this.depths[a] as number;\n const db = this.depths[b] as number;\n return da !== db ? da > db : a < b;\n }\n}\n"],
5
- "mappings": ";AAMA,SAAS,mBAAmB,YAAY,YAAY;AAoBpD,IAAM,SAAS;AACf,IAAM,SAAS;AAER,IAAM,QAAQ;AAErB,IAAM,QAAQ;AAEd,IAAM,MAAM;AAEZ,IAAM,OAAO;AAEb,IAAM,OAAO;AAKb,IAAM,QAAQ;AAGd,IAAM,OAAmB;AAAA,EACvB,EAAE,GAAG,GAAG,GAAG,GAAG;AAAA,EACd,EAAE,GAAG,GAAG,GAAG,EAAE;AAAA,EACb,EAAE,GAAG,GAAG,GAAG,EAAE;AAAA,EACb,EAAE,GAAG,IAAI,GAAG,EAAE;AAChB;AACA,IAAM,SAA+B;AAAA,EACnC,CAAC,KAAK,GAAG,GAAG;AAAA,EACZ,CAAC,KAAK,KAAK,GAAG;AAAA,EACd,CAAC,KAAK,MAAM,GAAG;AAAA,EACf,CAAC,KAAK,IAAI,GAAG;AACf;AAKO,SAAS,SAAS,MAA0B;AACjD,QAAM,IAAI,KAAK,MAAM,yBAAyB,GAAG,IAAI,MAAM,KAAK,CAAC;AACjE,QAAM,MAAkB,CAAC;AACzB,WAAS,IAAI,GAAG,IAAI,IAAI,EAAE,QAAQ,KAAK,EAAG,KAAI,KAAK,EAAE,GAAG,EAAE,CAAC,GAAa,GAAG,EAAE,IAAI,CAAC,EAAY,CAAC;AAC/F,SAAO;AACT;AAEO,IAAM,WAAW,CAAC,GAAQ,MAC/B,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,IAAI,EAAE;AAG/E,IAAM,QAAQ,CAAC,GAAQ,QAAqB;AAAA,EACjD,GAAG,EAAE,IAAI;AAAA,EACT,GAAG,EAAE,IAAI;AAAA,EACT,OAAO,KAAK,IAAI,GAAG,EAAE,QAAQ,IAAI,EAAE;AAAA,EACnC,QAAQ,KAAK,IAAI,GAAG,EAAE,SAAS,IAAI,EAAE;AACvC;AAGO,SAAS,YAAY,GAAa,GAAa,GAAiB;AACrE,MAAI,KAAK;AACT,MAAI,KAAK;AACT,QAAM,KAAK,EAAE,IAAI,EAAE;AACnB,QAAM,KAAK,EAAE,IAAI,EAAE;AACnB,QAAM,QAA4B;AAAA,IAChC,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC;AAAA,IACf,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;AAAA,IACxB,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC;AAAA,IACf,CAAC,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;AAAA,EAC3B;AACA,aAAW,CAAC,GAAG,CAAC,KAAK,OAAO;AAC1B,QAAI,MAAM,GAAG;AACX,UAAI,IAAI,EAAG,QAAO;AAClB;AAAA,IACF;AACA,UAAM,IAAI,IAAI;AACd,QAAI,IAAI,EAAG,MAAK,KAAK,IAAI,IAAI,CAAC;AAAA,QACzB,MAAK,KAAK,IAAI,IAAI,CAAC;AACxB,QAAI,KAAK,GAAI,QAAO;AAAA,EACtB;AACA,SAAO;AACT;AAGO,SAAS,YAAY,QAAoB,OAAgC;AAC9E,aAAW,OAAO,OAAO;AACvB,UAAM,IAAI,MAAM,KAAK,KAAK;AAC1B,aAAS,IAAI,GAAG,IAAI,IAAI,OAAO,QAAQ;AACrC,UAAI,YAAY,OAAO,CAAC,GAAe,OAAO,IAAI,CAAC,GAAe,CAAC,EAAG,QAAO;AAAA,EACjF;AACA,SAAO;AACT;AAGO,SAAS,SAAS,MAAc,IAAmB;AACxD,QAAM,IAAI,CAAC,GAAG,IAAI,EAAE,SAAS,IAAI;AACjC,SAAO,EAAE,GAAG,GAAG,IAAI,IAAI,GAAG,GAAG,GAAG,IAAI,GAAG,OAAO,GAAG,QAAQ,GAAG;AAC9D;AAQO,SAAS,UACd,GACA,MACA,GACA,IACA,OACA,OACO;AACP,QAAM,CAAC,MAAM,GAAG,CAAC,IAAI,kBAAkB;AAAA,IACrC,SAAS,EAAE;AAAA,IACX,SAAS,EAAE;AAAA,IACX,gBAAgB;AAAA,IAChB,SAAS,EAAE;AAAA,IACX,SAAS,EAAE;AAAA,IACX,gBAAgB;AAAA,EAClB,CAAC;AACD,QAAM,OAAO,EAAE,MAAM,OAAO,EAAE,GAAG,EAAE,EAAE;AACrC,MAAI,CAAC,YAAY,SAAS,IAAI,GAAG,KAAK,EAAG,QAAO;AAEhD,QAAM,SAAS,WAAW,GAAG,OAAO,IAAI,GAAG,GAAG,OAAO,EAAE,GAAG,KAAK;AAC/D,MAAI,CAAC,OAAQ,QAAO;AACpB,SAAO,EAAE,MAAM,OAAO,MAAM,GAAG,OAAO,QAAQ,QAAQ,OAAO,KAAK,GAAG,OAAO,OAAO,MAAM,GAAG,EAAE,EAAE;AAClG;AAGA,SAAS,MAAM,GAAW,GAAW,OAAqC;AACxE,QAAM,MAAM,MAAM,KAAK,EAAE,KAAK,CAAC,GAAG,MAAM,IAAI,CAAC;AAC7C,QAAM,MAAM,CAAC,GAAG,CAAC;AACjB,aAAW,CAAC,IAAI,EAAE,KAAK,MAAO,KAAI,KAAK,KAAK,OAAO,KAAK,KAAK;AAC7D,WAAS,IAAI,GAAG,IAAI,IAAI,IAAI,QAAQ,KAAK;AACvC,UAAM,MAAO,IAAI,IAAI,CAAC,IAAgB,IAAI,CAAC;AAC3C,QAAI,MAAM,IAAI,OAAO,MAAM,IAAI;AAC7B,UAAI,MAAO,IAAI,CAAC,IAAgB,IAAI,IAAI,CAAC,KAAgB,CAAC;AAAA,EAC9D;AACA,SAAO,CAAC,GAAG,IAAI,IAAI,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,MAAM,IAAI,CAAC;AAC/C;AAOA,SAAS,WACP,GACA,MACA,GACA,IACA,OACwB;AACxB,QAAM,MAAM,KAAK,IAAI;AACrB,QAAM,OAAO,KAAK,EAAE;AACpB,QAAM,IAAI,EAAE,GAAG,EAAE,IAAI,IAAI,IAAI,QAAQ,GAAG,EAAE,IAAI,IAAI,IAAI,OAAO;AAC7D,QAAM,IAAI,EAAE,GAAG,EAAE,IAAI,KAAK,IAAI,QAAQ,GAAG,EAAE,IAAI,KAAK,IAAI,OAAO;AAC/D,MAAI,YAAY,CAAC,GAAG,CAAC,GAAG,KAAK,KAAK,YAAY,CAAC,GAAG,CAAC,GAAG,KAAK,EAAG,QAAO;AACrE,aAAW,SAAS,CAAC,OAAO,OAAO,iBAAiB,GAAG;AACrD,UAAM,OAAO,OAAO,GAAG,GAAG,OAAO,KAAK;AACtC,UAAM,QAAQ,OAAO,GAAG,MAAM,IAAI,KAAK,KAAK,GAAG,IAAI;AACnD,QAAI,MAAO,QAAO,QAAQ,CAAC,GAAG,GAAG,OAAO,CAAC,CAAC;AAC1C,QAAI,KAAK,WAAW,MAAM,OAAQ;AAAA,EACpC;AACA,SAAO;AACT;AAGA,IAAM,QAAQ;AAMd,SAAS,OAAO,GAAa,GAAa,OAAuB,OAA+B;AAC9F,MAAI,CAAC,OAAO,SAAS,KAAK,EAAG,QAAO;AACpC,QAAM,OAAO,CAAC,KAAiB,QAAqB;AAClD,UAAM,KAAK,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;AAC7B,UAAM,KAAK,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;AAC7B,UAAM,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,IAAI,GAAG,EAAE,IAAI,KAAK,KAAK,IAAI,GAAG,EAAE,IAAI,GAAG;AAC5D,WAAO,EAAE,GAAG,GAAG,OAAO,KAAK,IAAI,GAAG,EAAE,IAAI,MAAM,GAAG,QAAQ,KAAK,IAAI,GAAG,EAAE,IAAI,MAAM,EAAE;AAAA,EACrF;AACA,MAAI,OAAO,MAAM,OAAO,CAAC,MAAM,SAAS,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC;AAC/D,aAAS;AACP,UAAM,OAAO;AAAA,MACX,CAAC,GAAG,GAAG,GAAG,KAAK,QAAQ,CAAC,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,GAAG,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;AAAA,MAC3E,QAAQ;AAAA,IACV;AACA,UAAM,OAAO,MAAM,OAAO,CAAC,MAAM,KAAK,SAAS,CAAC,KAAK,SAAS,GAAG,IAAI,CAAC;AACtE,QAAI,KAAK,WAAW,KAAK,OAAQ,QAAO;AACxC,WAAO;AAAA,EACT;AACF;AAMA,SAAS,OACP,GACA,MACA,GACA,MACA,OACwB;AACxB,QAAM,KAAK;AAAA,IACT,EAAE;AAAA,IACF,EAAE;AAAA,IACF,MAAM,IAAI,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,KAAK,CAAC;AAAA,EACvC;AACA,QAAM,KAAK;AAAA,IACT,EAAE;AAAA,IACF,EAAE;AAAA,IACF,MAAM,IAAI,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,CAAC;AAAA,EACxC;AACA,QAAM,KAAK,GAAG;AACd,QAAM,KAAK,GAAG;AAGd,QAAM,SAAS,IAAI,aAAa,KAAK,EAAE;AACvC,QAAM,OAAO,IAAI,aAAa,KAAK,EAAE;AACrC,QAAM,OAAO,CACX,IACA,GACA,IACA,IACA,IACA,IACA,IACA,IACA,WACG;AACH,QAAI,MAAM,MAAM,MAAM,MAAO,GAAG,CAAC,IAAe,EAAG;AACnD,QAAI,UAAU,KAAK,MAAM,KAAK,GAAI,IAAG,CAAC,IAAI;AAAA,QACrC,IAAG,CAAC,IAAI,KAAK,IAAI,GAAG,CAAC,GAAa,KAAK,IAAI,IAAI,EAAE,IAAI,KAAK,IAAI,IAAI,EAAE,CAAC;AAAA,EAC5E;AACA,aAAW,KAAK,OAAO;AACrB,UAAM,CAAC,KAAK,KAAK,KAAK,GAAG,IAAI,CAAC,EAAE,IAAI,KAAK,EAAE,IAAI,EAAE,QAAQ,KAAK,EAAE,IAAI,KAAK,EAAE,IAAI,EAAE,SAAS,GAAG;AAC7F,UAAM,CAAC,KAAK,KAAK,KAAK,GAAG,IAAI;AAAA,MAC3B,EAAE,IAAI;AAAA,MACN,EAAE,IAAI,EAAE,QAAQ;AAAA,MAChB,EAAE,IAAI;AAAA,MACN,EAAE,IAAI,EAAE,SAAS;AAAA,IACnB;AACA,aAAS,IAAI,GAAG,IAAI,IAAI,KAAK;AAC3B,YAAM,IAAI,GAAG,CAAC;AACd,UAAI,KAAK,OAAO,KAAK,IAAK;AAC1B,eAAS,IAAI,GAAG,IAAI,IAAI,IAAI;AAC1B;AAAA,UACE;AAAA,UACA,IAAI,KAAK;AAAA,UACT,GAAG,CAAC;AAAA,UACJ,GAAG,IAAI,CAAC;AAAA,UACR;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA,IAAI,OAAO,IAAI;AAAA,QACjB;AAAA,IACJ;AACA,aAAS,IAAI,GAAG,IAAI,IAAI,KAAK;AAC3B,YAAM,IAAI,GAAG,CAAC;AACd,UAAI,KAAK,OAAO,KAAK,IAAK;AAC1B,eAAS,IAAI,GAAG,IAAI,IAAI,IAAI;AAC1B;AAAA,UACE;AAAA,UACA,IAAI,KAAK;AAAA,UACT,GAAG,CAAC;AAAA,UACJ,GAAG,IAAI,CAAC;AAAA,UACR;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA,IAAI,OAAO,IAAI;AAAA,QACjB;AAAA,IACJ;AAAA,EACF;AACA,QAAM,QAAQ,CAAC,MACb,MAAM;AAAA,IACJ,CAAC,MACC,EAAE,IAAI,EAAE,IAAI,OACZ,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,OACtB,EAAE,IAAI,EAAE,IAAI,OACZ,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS;AAAA,EAC3B;AACF,MAAI,MAAM,CAAC,KAAK,MAAM,CAAC,EAAG,QAAO;AACjC,QAAM,KAAK,GAAG,QAAQ,EAAE,CAAC;AACzB,QAAM,KAAK,GAAG,QAAQ,EAAE,CAAC;AACzB,QAAM,KAAK,GAAG,QAAQ,EAAE,CAAC;AACzB,QAAM,KAAK,GAAG,QAAQ,EAAE,CAAC;AACzB,QAAM,SAAS,KAAK,KAAK;AACzB,QAAM,OAAO,IAAI,aAAa,MAAM,EAAE,KAAK,OAAO,iBAAiB;AACnE,QAAM,OAAO,IAAI,WAAW,MAAM,EAAE,KAAK,EAAE;AAI3C,QAAM,IAAI,CAAC,GAAW,GAAW,MAAc;AAC7C,UAAM,KAAK,EAAE,IAAK,GAAG,CAAC;AACtB,UAAM,KAAK,EAAE,IAAK,GAAG,CAAC;AACtB,QAAI,OAAO,KAAK,OAAO,EAAG,QAAO;AACjC,UAAM,OAAO,KAAK,CAAC;AACnB,UAAM,QACJ,MAAM,OACF,KAAK,KAAK,MAAM,KAAK,KAAK,KAAK,KAAK,KAAK,IAAI,KAAK,KAAK,KAAK,IAC1D,IACA,IACF,OAAO,OAAO,KAAK,IACjB,IACA;AACR,WAAO,KAAK,IAAI,EAAE,IAAI,KAAK,IAAI,EAAE,IAAI,QAAQ;AAAA,EAC/C;AACA,QAAM,OAAO,IAAI,KAAK;AACtB,QAAM,SAAS,KAAK,KAAK,MAAM,IAAI;AACnC,OAAK,KAAK,IAAI;AACd,OAAK,KAAK,EAAE,IAAI,IAAI,IAAI,GAAG,GAAG,KAAK;AACnC,MAAI,OAAO;AACX,SAAO,KAAK,OAAO,GAAG;AACpB,UAAM,EAAE,KAAK,GAAG,OAAO,EAAE,IAAI,KAAK,IAAI;AACtC,UAAM,IAAI,IAAI;AACd,UAAM,KAAK,IAAI,KAAK;AACpB,UAAM,IAAI,KAAK,MAAM,IAAI,EAAE;AAC3B,UAAM,IAAI,IAAI;AACd,QAAI,IAAK,KAAK,CAAC,IAAe,EAAE,GAAG,GAAG,CAAC,EAAG;AAC1C,QAAI,MAAM,MAAM,MAAM,IAAI;AACxB,aAAO;AACP;AAAA,IACF;AACA,aAAS,KAAK,GAAG,KAAK,GAAG,MAAM;AAC7B,UAAI,QAAQ,IAAI,KAAK,EAAG;AACxB,YAAM,OAAO,KAAK,EAAE;AACpB,YAAM,KAAK,IAAI,KAAK;AACpB,YAAM,KAAK,IAAI,KAAK;AACpB,UAAI,KAAK,KAAK,KAAK,KAAK,MAAM,MAAM,MAAM,GAAI;AAC9C,YAAM,OAAO,KAAK,MAAM;AACxB,YAAM,OAAO,OACR,OAAO,KAAK,IAAI,GAAG,EAAE,IAAI,KAAK,CAAC,IAC/B,KAAK,IAAI,KAAK,KAAK,IAAI,GAAG,EAAE,CAAC;AAClC,UAAI,OAAO,EAAG;AACd,YAAM,IAAI,GAAG,CAAC;AACd,YAAM,IAAI,GAAG,CAAC;AACd,YAAM,MAAM,OAAO,KAAK,IAAK,GAAG,EAAE,IAAe,CAAC,IAAI,KAAK,IAAK,GAAG,EAAE,IAAe,CAAC;AACrF,YAAM,OAAO,OAAO,MAAM,EAAE,KAAK,MAAM,EAAE,IAAI,MAAM,EAAE,KAAK,MAAM,EAAE;AAClE,UAAI,IACD,KAAK,CAAC,IAAe,OAAO,OAAO,IAAI,IAAI,SAAS,OAAO,QAAQ,OAAO,IAAI,IAAI;AACrF,YAAM,MAAM,KAAK,KAAK,MAAM,IAAI;AAChC,UAAI,OAAO,MAAM,OAAO,IAAI;AAC1B,YAAI,QAAQ,OAAO,KAAK,EAAG;AAC3B,YAAI,OAAO,KAAM,MAAK;AAAA,MACxB;AACA,UAAI,IAAK,KAAK,EAAE,GAAc;AAC5B,aAAK,EAAE,IAAI;AACX,aAAK,EAAE,IAAI;AACX,aAAK,KAAK,IAAI,EAAE,IAAI,IAAI,EAAE,GAAG,GAAG,EAAE;AAAA,MACpC;AAAA,IACF;AAAA,EACF;AACA,MAAI,OAAO,EAAG,QAAO;AACrB,QAAM,OAAmB,CAAC;AAC1B,WAAS,IAAI,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,GAAa;AAChD,UAAM,KAAK,IAAK,IAAI,KAAM;AAC1B,SAAK,KAAK,EAAE,GAAG,GAAG,KAAK,MAAM,IAAI,EAAE,CAAC,GAAa,GAAG,GAAG,IAAI,EAAE,EAAY,CAAC;AAAA,EAC5E;AACA,SAAO,KAAK,QAAQ;AACtB;AAGA,SAAS,QAAQ,QAAgC;AAC/C,QAAM,MAAkB,CAAC;AACzB,aAAW,KAAK,QAAQ;AACtB,UAAM,IAAI,IAAI,GAAG,EAAE;AACnB,QAAI,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,EAAG;AACrC,UAAM,IAAI,IAAI,GAAG,EAAE;AACnB,QAAI,KAAK,MAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAK,KAAI,IAAI;AACtF,QAAI,KAAK,CAAC;AAAA,EACZ;AACA,SAAO;AACT;AAGA,SAAS,OAAO,QAA4B;AAC1C,QAAM,QAAQ,OAAO,CAAC;AACtB,QAAM,OAAO,OAAO,GAAG,EAAE;AACzB,MAAI,OAAO,IAAI,MAAM,CAAC,IAAI,MAAM,CAAC;AACjC,WAAS,IAAI,GAAG,IAAI,OAAO,SAAS,GAAG;AACrC,YAAQ,OAAO,OAAO,IAAI,CAAC,GAAe,OAAO,CAAC,GAAe,OAAO,IAAI,CAAC,CAAa;AAC5F,SAAO,GAAG,IAAI,IAAI,KAAK,CAAC,IAAI,KAAK,CAAC;AACpC;AAGA,SAAS,OAAO,GAAa,GAAa,GAAqB;AAC7D,QAAM,OAAO,KAAK;AAAA,IAChB,KAAK,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,IAAI;AAAA,IACnC,KAAK,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,IAAI;AAAA,IACnC;AAAA,EACF;AACA,QAAM,EAAE,GAAG,EAAE,IAAI;AACjB,MAAK,EAAE,MAAM,KAAK,MAAM,EAAE,KAAO,EAAE,MAAM,KAAK,MAAM,EAAE,EAAI,QAAO,IAAI,CAAC,IAAI,CAAC;AAC3E,MAAI,EAAE,MAAM,GAAG;AACb,UAAMA,QAAO,EAAE,IAAI,EAAE,IAAI,KAAK;AAC9B,UAAMC,QAAO,EAAE,IAAI,EAAE,IAAI,IAAI;AAC7B,WAAO,KAAK,IAAI,OAAOD,KAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,OAAOC,KAAI;AAAA,EACrE;AACA,QAAM,OAAO,EAAE,IAAI,EAAE,IAAI,IAAI;AAC7B,QAAM,OAAO,EAAE,IAAI,EAAE,IAAI,KAAK;AAC9B,SAAO,KAAK,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,IAAI,CAAC;AACrE;AAGA,IAAM,SAAS,CAAC,GAAa,MAAgB,KAAK,IAAI,EAAE,IAAI,EAAE,CAAC,IAAI,KAAK,IAAI,EAAE,IAAI,EAAE,CAAC;AAOrF,SAAS,QAAQ,QAAoB,OAAuB,MAAoC;AAC9F,WAAS,IAAI,GAAG,QAAQ,IAAI,IAAI,OAAO,QAAQ,KAAK;AAClD,UAAM,IAAI,OAAO,CAAC;AAClB,UAAM,IAAI,OAAO,IAAI,CAAC;AACtB,UAAM,MAAM,OAAO,GAAG,CAAC;AACvB,UAAM,QAAQ,EAAE,MAAM,EAAE,IAAI,SAAS,MAAM,CAAC,EAAE,QAAQ;AACtD,UAAM,QAAQ,MAAM,QAAQ,KAAK;AACjC,UAAM,KAAK,KAAK,KAAK,EAAE,IAAI,EAAE,CAAC;AAC9B,UAAM,KAAK,KAAK,KAAK,EAAE,IAAI,EAAE,CAAC;AAC9B,aAAS,IAAI,GAAG,KAAK,MAAM,KAAK;AAC9B,iBAAW,QAAQ,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG;AACpC,cAAM,IAAI,MAAM,IAAI,OAAO;AAC3B,cAAM,KAAK,EAAE,GAAG,EAAE,IAAI,KAAK,GAAG,GAAG,EAAE,IAAI,KAAK,EAAE;AAC9C,cAAM,MAAM,SAAS,MAAM,EAAE;AAC7B,YAAI,CAAC,MAAM,KAAK,CAAC,MAAM,SAAS,KAAK,CAAC,CAAC,EAAG,QAAO;AAAA,MACnD;AAAA,EACJ;AACA,QAAM,OAAO,OAAO,MAAM,CAAC,EAAE,IAAI,CAAC,GAAG,MAAM,OAAO,OAAO,CAAC,GAAe,CAAC,CAAC;AAC3E,MAAI,OAAO,KAAK,OAAO,CAAC,KAAK,QAAQ,MAAM,KAAK,CAAC,IAAI;AACrD,WAAS,IAAI,GAAG,IAAI,IAAI,OAAO,QAAQ,KAAK;AAC1C,UAAM,IAAI,OAAO,CAAC;AAClB,UAAM,IAAI,OAAO,IAAI,CAAC;AACtB,UAAM,MAAM,KAAK,CAAC;AAClB,QAAI,QAAQ;AACV,aAAO,EAAE,GAAG,EAAE,IAAI,KAAK,KAAK,EAAE,IAAI,EAAE,CAAC,IAAI,MAAM,GAAG,EAAE,IAAI,KAAK,KAAK,EAAE,IAAI,EAAE,CAAC,IAAI,KAAK;AACtF,YAAQ;AAAA,EACV;AACA,SAAO,OAAO,CAAC;AACjB;AAOA,IAAM,OAAN,MAAW;AAAA,EACD,OAAiB,CAAC;AAAA,EAClB,OAAiB,CAAC;AAAA,EAClB,SAAmB,CAAC;AAAA,EACpB,SAAmB,CAAC;AAAA,EAE5B,IAAI,OAAe;AACjB,WAAO,KAAK,KAAK;AAAA,EACnB;AAAA,EAEA,KAAK,KAAa,OAAe,OAAqB;AACpD,UAAM,IAAI,KAAK,KAAK;AACpB,SAAK,KAAK,KAAK,GAAG;AAClB,SAAK,OAAO,KAAK,KAAK;AACtB,SAAK,OAAO,KAAK,KAAK;AACtB,UAAM,IAAI,KAAK;AACf,QAAI,IAAI,EAAE;AACV,MAAE,KAAK,CAAC;AACR,WAAO,IAAI,GAAG;AACZ,YAAM,KAAM,IAAI,KAAM;AACtB,UAAI,CAAC,KAAK,OAAO,GAAG,EAAE,EAAE,CAAW,EAAG;AACtC,QAAE,CAAC,IAAI,EAAE,EAAE;AACX,UAAI;AAAA,IACN;AACA,MAAE,CAAC,IAAI;AAAA,EACT;AAAA;AAAA,EAGA,MAAsC;AACpC,UAAM,IAAI,KAAK;AACf,UAAM,MAAM,EAAE,CAAC;AACf,UAAM,OAAO,EAAE,IAAI;AACnB,QAAI,EAAE,SAAS,GAAG;AAChB,UAAI,IAAI;AACR,iBAAS;AACP,cAAM,IAAI,IAAI,IAAI;AAClB,YAAI,KAAK,EAAE,OAAQ;AACnB,cAAM,IAAI,IAAI;AACd,cAAM,IAAI,IAAI,EAAE,UAAU,KAAK,OAAO,EAAE,CAAC,GAAa,EAAE,CAAC,CAAW,IAAI,IAAI;AAC5E,YAAI,CAAC,KAAK,OAAO,EAAE,CAAC,GAAa,IAAI,EAAG;AACxC,UAAE,CAAC,IAAI,EAAE,CAAC;AACV,YAAI;AAAA,MACN;AACA,QAAE,CAAC,IAAI;AAAA,IACT;AACA,WAAO,EAAE,KAAK,KAAK,KAAK,GAAG,GAAa,OAAO,KAAK,OAAO,GAAG,EAAY;AAAA,EAC5E;AAAA,EAEQ,OAAO,GAAW,GAAoB;AAC5C,UAAM,KAAK,KAAK,KAAK,CAAC;AACtB,UAAM,KAAK,KAAK,KAAK,CAAC;AACtB,QAAI,OAAO,GAAI,QAAO,KAAK;AAC3B,UAAM,KAAK,KAAK,OAAO,CAAC;AACxB,UAAM,KAAK,KAAK,OAAO,CAAC;AACxB,WAAO,OAAO,KAAK,KAAK,KAAK,IAAI;AAAA,EACnC;AACF;",
6
- "names": ["xDir", "yDir"]
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../../../src/core/import/source.ts"],
4
- "sourcesContent": ["// Playbooks, task files and roles as import sources (AFD-26): one normalized tree per playbook.\n// Tasks take their module and arguments apart (action:, local_action:, free-form and k=v forms),\n// inherit their play's and blocks' keywords as Ansible does, and literal includes and imports are\n// read in. What a flow cannot hold is listed per item, so the mapper can say so.\n// Ansible's own loader (the probe, ADR-0012) needs an environment, flattens blocks and drops\n// arguments, conditions and loops; this reader works anywhere and keeps them.\nimport { templated } from '../flow/jinja';\nimport { isAllowedKeyword } from '../flow/keywords';\nimport { builtinFqcn, shortName } from './builtins';\nimport {\n type AnsibleConfig,\n basename,\n dirname,\n exists,\n isMapping,\n isTemplated,\n isVaultFile,\n join,\n lineOf,\n normalize,\n type Plain,\n type PlainMap,\n parseAnsible,\n parseConfig,\n type SourceIO,\n toValue,\n} from './read';\n\nexport interface Origin {\n path: string;\n line?: number;\n}\n\nexport interface TaskForm {\n kind: 'task';\n name: string;\n /** As written (`copy`, `cisco.ios.ios_config`). */\n module: string;\n /** Fully qualified when known. */\n fqcn?: string;\n params: Record<string, unknown>;\n /** Task keywords a binding carries (impl.keywords), inherited ones included. */\n keywords: Record<string, unknown>;\n register?: string;\n notify: string[];\n /** Handlers: the topics they listen to besides their name. */\n listen: string[];\n tags: string[];\n become?: boolean;\n /** Whole seconds, or a template given at run time (AFD-112). */\n timeout?: number | string;\n retries?: number | string;\n delay?: number | string;\n until?: string;\n ignoreUnreachable?: boolean;\n /** Keywords with no place in a flow. */\n dropped: string[];\n /** Local files the task reads (template src, ...): where Ansible finds them, or missing. */\n files: LocalFile[];\n origin: Origin;\n}\n\nexport interface LocalFile {\n /** The parameter, or `cmd` for a script's first word. */\n param: string;\n written: string;\n /** Repository path, when found. */\n path?: string;\n}\n\nexport interface VarsFile {\n file: string;\n path?: string;\n /** Top-level variable names in it (none when encrypted or missing). */\n keys: string[];\n}\n\nexport interface BlockForm {\n kind: 'block';\n name: string;\n items: Item[];\n rescue: Item[];\n always: Item[];\n origin: Origin;\n}\n\nexport interface IncludeForm {\n kind: 'include';\n name: string;\n /** The file as written. */\n file: string;\n /** Read in: the file's items (a literal path that exists). */\n path?: string;\n items?: Item[];\n /** Why it is not read in (a templated path, a loop, missing). */\n dynamic?: string;\n /**\n * AFD-149: an include_tasks' own `when`, which Ansible checks once for the include (not on each\n * task in the file, as for import_tasks). Its parts are ANDed.\n */\n when?: unknown[];\n keywords: Record<string, unknown>;\n tags: string[];\n /** AFD-187: the include's own vars (they also reach every task read in). */\n vars?: Record<string, unknown>;\n /**\n * AFD-177: what keeps a file that runs as include_tasks from working in generated/ (it reads\n * playbook_dir, or includes files found only next to the playbook).\n */\n portability?: string[];\n origin: Origin;\n}\n\n/** A task file of a split role: one step per file (decision 2). */\nexport interface RoleStep {\n /** include_role tasks_from: the file under tasks/ without its extension. */\n tasksFrom: string;\n name: string;\n keywords: Record<string, unknown>;\n tags: string[];\n}\n\nexport interface RoleForm {\n kind: 'role';\n name: string;\n /** What include_role names: the role name, or an FQCN for a collection role. */\n ref: string;\n /** Folder of the role, when found. */\n dir?: string;\n /** Whether generated plays find it (roles_path of the repository's ansible.cfg, collections). */\n onRolesPath: boolean;\n /** Role variables and include options (tasks_from, vars_from, ...). */\n params: Record<string, unknown>;\n keywords: Record<string, unknown>;\n tags: string[];\n become?: boolean;\n split?: RoleStep[];\n /** Variables the role registers or sets (read statically), so later steps can read them. */\n outputs: string[];\n dropped: string[];\n origin: Origin;\n}\n\nexport interface MetaForm {\n kind: 'meta';\n name: string;\n action: string;\n keywords: Record<string, unknown>;\n origin: Origin;\n}\n\nexport type Item = TaskForm | BlockForm | IncludeForm | RoleForm | MetaForm;\n\nexport interface VarPrompt {\n name: string;\n private: boolean;\n default?: unknown;\n prompt?: string;\n}\n\nexport interface PlayForm {\n kind: 'play';\n name: string;\n hosts: string;\n gatherFacts: boolean;\n gatherParams: Record<string, unknown>;\n become?: boolean;\n serial?: string | number;\n maxFailPercentage?: number;\n anyErrorsFatal?: boolean;\n collections: string[];\n vars: Record<string, unknown>;\n varsFiles: VarsFile[];\n varsPrompt: VarPrompt[];\n preTasks: Item[];\n roles: Item[];\n tasks: Item[];\n postTasks: Item[];\n handlers: Item[];\n dropped: string[];\n origin: Origin;\n}\n\nexport interface ImportPlaybookForm {\n kind: 'import_playbook';\n name: string;\n file: string;\n playbook?: PlaybookForm;\n /** Why it is not read in. */\n missing?: string;\n keywords: Record<string, unknown>;\n origin: Origin;\n}\n\nexport interface PlaybookForm {\n path: string;\n plays: (PlayForm | ImportPlaybookForm)[];\n}\n\nexport interface ReadOptions {\n /** Short module name + the play's collections \u2192 FQCN (the catalog, when the host has one). */\n resolveModule?(name: string, collections: string[]): string | undefined;\n}\n\nexport interface ReadResult {\n playbook?: PlaybookForm;\n /** What did not read one to one, for the user. */\n notes: string[];\n /** Every file read, repository paths. */\n files: string[];\n config?: AnsibleConfig;\n}\n\n// ---- keywords ------------------------------------------------------------------------------------\n\n/** Every key a task may have besides its module (Ansible's Task attributes). */\nconst TASK_KEYS = new Set([\n 'name',\n 'action',\n 'local_action',\n 'args',\n 'async',\n 'poll',\n 'become',\n 'become_exe',\n 'become_flags',\n 'become_method',\n 'become_user',\n 'changed_when',\n 'check_mode',\n 'collections',\n 'connection',\n 'debugger',\n 'delay',\n 'delegate_facts',\n 'delegate_to',\n 'diff',\n 'environment',\n 'failed_when',\n 'ignore_errors',\n 'ignore_unreachable',\n 'loop',\n 'loop_control',\n 'module_defaults',\n 'no_log',\n 'notify',\n 'listen',\n 'port',\n 'register',\n 'remote_user',\n 'retries',\n 'run_once',\n 'tags',\n 'throttle',\n 'timeout',\n 'until',\n 'vars',\n 'when',\n 'any_errors_fatal',\n 'block',\n 'rescue',\n 'always',\n]);\n\nconst isTaskKey = (k: string) => TASK_KEYS.has(k) || /^with_[a-z_]+$/.test(k);\n\n/** What blocks and plays hand down to their tasks. */\ninterface Scope {\n keywords: Record<string, unknown>;\n when: unknown[];\n tags: string[];\n become?: boolean;\n ignoreUnreachable?: boolean;\n /** Keywords that have no place, inherited. */\n dropped: string[];\n}\n\nconst EMPTY_SCOPE: Scope = { keywords: {}, when: [], tags: [], dropped: [] };\n\n/** Keywords a block or play hands down (their own `when`, tags and become are kept apart). */\nconst INHERITED = new Set([\n 'become_user',\n 'become_method',\n 'become_flags',\n 'become_exe',\n 'environment',\n 'connection',\n 'remote_user',\n 'port',\n 'ignore_errors',\n 'no_log',\n 'check_mode',\n 'diff',\n 'delegate_to',\n 'delegate_facts',\n 'run_once',\n 'throttle',\n 'module_defaults',\n 'debugger',\n 'vars',\n]);\n\nconst asList = (v: unknown): string[] =>\n v === undefined || v === null\n ? []\n : (Array.isArray(v) ? v : String(v).split(',')).map((x) => String(x).trim()).filter(Boolean);\n\nconst asBool = (v: unknown): boolean | undefined =>\n typeof v === 'boolean'\n ? v\n : typeof v === 'string' && /^(yes|true|on|1)$/i.test(v)\n ? true\n : typeof v === 'string' && /^(no|false|off|0)$/i.test(v)\n ? false\n : undefined;\n\nconst asInt = (v: unknown): number | undefined =>\n typeof v === 'number' && Number.isInteger(v)\n ? v\n : typeof v === 'string' && /^[0-9]+$/.test(v.trim())\n ? Number(v)\n : undefined;\n\n/**\n * A number, or a whole template the flow keeps as a value given at run time (AFD-112: a templated\n * retries, delay or timeout used to be dropped on import).\n */\nconst asIntOrTemplate = (v: unknown): number | string | undefined =>\n asInt(v) ?? (templated(v) ? v.trim() : undefined);\n\n/** A block's or play's own keys added to what its parent handed down. */\nfunction narrow(parent: Scope, raw: PlainMap, own: 'block' | 'play'): Scope {\n const keywords = { ...parent.keywords };\n // A play's vars become flow inputs; a block's vars reach its tasks.\n for (const k of INHERITED)\n if (raw[k] !== undefined && !(own === 'play' && k === 'vars')) {\n const v = toValue(raw[k] as Plain);\n keywords[k] =\n k === 'vars' && isMapping(keywords.vars) && isMapping(v) ? { ...keywords.vars, ...v } : v;\n }\n const dropped = [...parent.dropped];\n if (own === 'block' && raw.any_errors_fatal !== undefined) dropped.push('any_errors_fatal');\n return {\n keywords,\n when: own === 'block' && raw.when !== undefined ? [...parent.when, raw.when] : parent.when,\n tags: [...parent.tags, ...asList(raw.tags)],\n become: asBool(raw.become) ?? parent.become,\n ignoreUnreachable: asBool(raw.ignore_unreachable) ?? parent.ignoreUnreachable,\n dropped,\n };\n}\n\n/** A task's keywords over what it inherits; `when` lists are ANDed in order. */\nfunction taskKeywords(\n scope: Scope,\n raw: PlainMap,\n): { keywords: Record<string, unknown>; dropped: string[] } {\n const keywords: Record<string, unknown> = { ...scope.keywords };\n const dropped = [...scope.dropped];\n for (const [k, v] of Object.entries(raw)) {\n if (!isTaskKey(k) || k === 'when') continue;\n if (\n [\n 'name',\n 'action',\n 'local_action',\n 'args',\n 'register',\n 'notify',\n 'listen',\n 'tags',\n 'become',\n 'timeout',\n 'retries',\n 'delay',\n 'until',\n 'ignore_unreachable',\n 'block',\n 'rescue',\n 'always',\n 'collections',\n ].includes(k)\n )\n continue;\n if (k === 'with_items' || k === 'with_list') keywords.loop = toValue(v);\n else if (k === 'vars' && isMapping(keywords.vars) && isMapping(v))\n keywords.vars = { ...keywords.vars, ...(toValue(v) as Record<string, unknown>) };\n else if (isAllowedKeyword(k)) keywords[k] = toValue(v);\n else dropped.push(k);\n }\n const when = [...scope.when, ...(raw.when !== undefined ? [raw.when] : [])]\n .flatMap((w) => (Array.isArray(w) ? w : [w]))\n .map((w) => toValue(w as Plain));\n if (when.length === 1) keywords.when = when[0];\n else if (when.length > 1) keywords.when = when;\n return { keywords, dropped: [...new Set(dropped)] };\n}\n\n// ---- module arguments ----------------------------------------------------------------------------\n\n/** `src=a dest=\"b c\" mode=0644` \u2192 {src, dest, mode}; quotes and `{{ }}` keep their spaces. */\nexport function parseKv(text: string): { args: Record<string, string>; rest: string } {\n const args: Record<string, string> = {};\n const rest: string[] = [];\n const tokens: string[] = [];\n let cur = '';\n let quote = '';\n let depth = 0;\n for (let i = 0; i < text.length; i++) {\n const c = text[i] as string;\n if (quote) {\n cur += c;\n if (c === quote && text[i - 1] !== '\\\\') quote = '';\n } else if (c === '\"' || c === \"'\") {\n quote = c;\n cur += c;\n } else if (text.startsWith('{{', i) || text.startsWith('{%', i)) {\n depth++;\n cur += text.slice(i, i + 2);\n i++;\n } else if ((text.startsWith('}}', i) || text.startsWith('%}', i)) && depth > 0) {\n depth--;\n cur += text.slice(i, i + 2);\n i++;\n } else if (/\\s/.test(c) && depth === 0) {\n if (cur) tokens.push(cur);\n cur = '';\n } else cur += c;\n }\n if (cur) tokens.push(cur);\n // Ansible's parse_kv drops the quotes and decodes escapes (`content=\"done\\n\"` ends in a newline).\n const ESC: Record<string, string> = { n: '\\n', t: '\\t', r: '\\r', '\\\\': '\\\\', '\"': '\"', \"'\": \"'\" };\n const unquote = (s: string) =>\n (/^([\"']).*\\1$/s.test(s) ? s.slice(1, -1) : s).replace(\n /\\\\([ntr\\\\\"'])/g,\n (_, c: string) => ESC[c] ?? c,\n );\n for (const t of tokens) {\n const m = /^([A-Za-z_][A-Za-z0-9_]*)=(.*)$/s.exec(t);\n if (m?.[1]) args[m[1]] = unquote(m[2] ?? '');\n else rest.push(t);\n }\n return { args, rest: rest.join(' ') };\n}\n\n/** Modules whose arguments are a command line, and the options Ansible takes out of it. */\nconst FREE_FORM: Record<string, string> = {\n command: 'cmd',\n shell: 'cmd',\n script: 'cmd',\n raw: '_raw_params',\n win_command: '_raw_params',\n win_shell: '_raw_params',\n};\nconst FREE_OPTIONS = new Set(['chdir', 'creates', 'removes', 'executable', 'stdin', 'warn']);\n\n/** Module arguments from the task value: a map, k=v text, or a free-form command line. */\nfunction moduleArgs(module: string, value: unknown, extra: unknown): Record<string, unknown> {\n const short = shortName(module).replace(/^ansible\\.windows\\./, '');\n let params: Record<string, unknown> = {};\n if (isMapping(value)) params = toValue(value) as Record<string, unknown>;\n else if (typeof value === 'string' && value.trim()) {\n const free = FREE_FORM[short];\n if (free) {\n const { args, rest } = parseKv(value);\n const options = Object.fromEntries(Object.entries(args).filter(([k]) => FREE_OPTIONS.has(k)));\n const kept = Object.entries(args)\n .filter(([k]) => !FREE_OPTIONS.has(k))\n .map(([k, v]) => `${k}=${v}`);\n params = { [free]: [rest, ...kept].filter(Boolean).join(' '), ...options };\n } else if (short === 'include_vars') params = { file: value.trim() };\n else {\n const { args, rest } = parseKv(value);\n params = rest ? { ...args, _raw_params: rest } : args;\n }\n }\n if (isMapping(extra)) params = { ...params, ...(toValue(extra) as Record<string, unknown>) };\n return params;\n}\n\n/** The module key and its value: a lone non-keyword key, or action / local_action. */\nfunction moduleOf(raw: PlainMap): { module: string; value: unknown; local: boolean } | undefined {\n for (const key of ['action', 'local_action'] as const) {\n const a = raw[key];\n if (a === undefined) continue;\n if (typeof a === 'string') {\n const [module = '', ...rest] = a.trim().split(/\\s+/);\n return { module, value: rest.join(' '), local: key === 'local_action' };\n }\n if (isMapping(a) && typeof a.module === 'string') {\n const { module, ...rest } = a;\n return { module: module as string, value: rest, local: key === 'local_action' };\n }\n }\n const keys = Object.keys(raw).filter((k) => !isTaskKey(k));\n if (!keys[0]) return undefined;\n return { module: keys[0], value: raw[keys[0]], local: false };\n}\n\nconst INCLUDES = new Set(['include_tasks', 'import_tasks', 'include']);\n\n/** Modules that read a local file, the parameter naming it and the subfolder Ansible looks in. */\nconst LOCAL_FILES: Record<string, { param: string; sub: string }> = {\n template: { param: 'src', sub: 'templates' },\n win_template: { param: 'src', sub: 'templates' },\n copy: { param: 'src', sub: 'files' },\n win_copy: { param: 'src', sub: 'files' },\n unarchive: { param: 'src', sub: 'files' },\n script: { param: 'cmd', sub: 'files' },\n include_vars: { param: 'file', sub: 'vars' },\n};\nconst ROLE_INCLUDES = new Set(['include_role', 'import_role']);\n// ---- the reader ----------------------------------------------------------------------------------\n\ninterface RoleInfo {\n dir?: string;\n onRolesPath: boolean;\n split?: RoleStep[];\n outputs: string[];\n}\n\nclass Reader {\n readonly notes: string[] = [];\n readonly files = new Set<string>();\n private readonly roles = new Map<string, Promise<RoleInfo>>();\n /** Task files being read in, to stop an include cycle. */\n private readonly including: string[] = [];\n /** AFD-179: task files that include themselves, at any depth; they run as include_tasks. */\n private readonly cyclic = new Set<string>();\n private config?: AnsibleConfig;\n private collections: string[] = [];\n\n constructor(\n private readonly io: SourceIO,\n private readonly opts: ReadOptions,\n ) {}\n\n /** The repository's ansible.cfg (the one runs use, ADR-0005). */\n async loadConfig(): Promise<AnsibleConfig | undefined> {\n const text = await this.io.read('ansible.cfg');\n if (text !== undefined) this.config = parseConfig(text, '');\n return this.config;\n }\n\n private async readYaml(path: string): Promise<Plain | undefined> {\n const text = await this.io.read(path);\n if (text === undefined) return undefined;\n this.files.add(path);\n if (isVaultFile(text)) {\n this.notes.push(`${path} is encrypted with Ansible Vault as a whole: not read.`);\n return undefined;\n }\n const { value, error } = parseAnsible(text);\n if (error) {\n this.notes.push(`${path} is not valid YAML (${error}): not read.`);\n return undefined;\n }\n return value;\n }\n\n async playbook(path: string, stack: string[] = []): Promise<PlaybookForm | undefined> {\n const data = await this.readYaml(path);\n if (data === undefined) return undefined;\n if (!Array.isArray(data)) {\n this.notes.push(`${path} is not a playbook (no list of plays).`);\n return undefined;\n }\n const plays: PlaybookForm['plays'] = [];\n for (const raw of data) {\n if (!isMapping(raw)) continue;\n const origin = { path, line: lineOf(raw) };\n const imp = raw.import_playbook ?? raw['ansible.builtin.import_playbook'];\n if (imp !== undefined) {\n plays.push(await this.importPlaybook(raw, String(imp), path, origin, stack));\n continue;\n }\n if (raw.hosts === undefined) {\n this.notes.push(`${path}:${origin.line ?? '?'}: a play without hosts was skipped.`);\n continue;\n }\n plays.push(await this.play(raw, path, origin));\n }\n return { path, plays };\n }\n\n private async importPlaybook(\n raw: PlainMap,\n file: string,\n from: string,\n origin: Origin,\n stack: string[],\n ): Promise<ImportPlaybookForm> {\n const keywords: Record<string, unknown> = {};\n if (raw.vars !== undefined) keywords.vars = toValue(raw.vars);\n if (raw.when !== undefined) keywords.when = toValue(raw.when);\n const form: ImportPlaybookForm = {\n kind: 'import_playbook',\n name: typeof raw.name === 'string' ? raw.name : basename(file).replace(/\\.ya?ml$/, ''),\n file,\n keywords,\n origin,\n };\n if (isTemplated(file)) {\n form.missing = 'its path is templated';\n return form;\n }\n const path = join(dirname(from), file);\n if (stack.includes(path) || stack.length >= 8) {\n form.missing = stack.includes(path) ? 'it imports itself' : 'imports nest deeper than 8';\n return form;\n }\n form.playbook = await this.playbook(path, [...stack, from]);\n if (!form.playbook) form.missing = `${path} was not found or not read`;\n return form;\n }\n\n private async play(raw: PlainMap, path: string, origin: Origin): Promise<PlayForm> {\n this.collections = asList(raw.collections);\n const scope = narrow(EMPTY_SCOPE, raw, 'play');\n const dropped = ['strategy', 'order', 'force_handlers'].filter((k) => raw[k] !== undefined);\n const gather = asBool(raw.gather_facts);\n const gatherParams: Record<string, unknown> = {};\n if (raw.gather_subset !== undefined) gatherParams.gather_subset = toValue(raw.gather_subset);\n if (raw.gather_timeout !== undefined) gatherParams.gather_timeout = toValue(raw.gather_timeout);\n const dir = dirname(path);\n const section = async (key: string) =>\n this.items(Array.isArray(raw[key]) ? (raw[key] as Plain[]) : [], scope, dir, dir, path);\n const prompts = Array.isArray(raw.vars_prompt) ? raw.vars_prompt : [];\n return {\n kind: 'play',\n name: typeof raw.name === 'string' ? raw.name : '',\n hosts: Array.isArray(raw.hosts)\n ? raw.hosts.map(String).join(',')\n : String(raw.hosts ?? 'all'),\n gatherFacts: gather ?? this.config?.gathering !== 'explicit',\n gatherParams,\n become: scope.become,\n serial:\n typeof raw.serial === 'number' || typeof raw.serial === 'string' ? raw.serial : undefined,\n maxFailPercentage: asInt(raw.max_fail_percentage),\n anyErrorsFatal: asBool(raw.any_errors_fatal),\n collections: this.collections,\n vars: isMapping(raw.vars) ? (toValue(raw.vars) as Record<string, unknown>) : {},\n varsFiles: await this.varsFiles(raw.vars_files, dir),\n varsPrompt: prompts.filter(isMapping).map((p) => ({\n name: String(p.name ?? ''),\n private: asBool(p.private) ?? true,\n ...(p.default !== undefined ? { default: toValue(p.default) } : {}),\n ...(typeof p.prompt === 'string' ? { prompt: p.prompt } : {}),\n })),\n preTasks: await section('pre_tasks'),\n roles: await this.playRoles(raw.roles, scope, path),\n tasks: await section('tasks'),\n postTasks: await section('post_tasks'),\n handlers: await section('handlers'),\n dropped: [...new Set([...dropped, ...scope.dropped])],\n origin,\n };\n }\n\n /** The `roles:` section: strings or maps with role/name, vars, keywords and old-style vars. */\n private async playRoles(value: Plain | undefined, scope: Scope, path: string): Promise<Item[]> {\n const out: Item[] = [];\n for (const entry of Array.isArray(value) ? value : []) {\n const raw: PlainMap = isMapping(entry) ? entry : { role: entry as Plain };\n const name = String(raw.role ?? raw.name ?? '');\n if (!name) continue;\n const params: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(raw))\n if (!['role', 'name'].includes(k) && !isTaskKey(k)) params[k] = toValue(v);\n if (isMapping(raw.vars)) Object.assign(params, toValue(raw.vars));\n out.push(\n await this.role(name, params, { ...raw, vars: null } as PlainMap, scope, path, {\n path,\n line: lineOf(entry),\n }),\n );\n }\n return out;\n }\n\n async items(\n list: Plain[],\n scope: Scope,\n dir: string,\n playDir: string,\n file: string,\n depth = 0,\n ): Promise<Item[]> {\n const out: Item[] = [];\n for (const raw of list) {\n if (!isMapping(raw)) continue;\n const item = await this.item(raw, scope, dir, playDir, file, depth);\n if (item) out.push(item);\n }\n return out;\n }\n\n private async item(\n raw: PlainMap,\n scope: Scope,\n dir: string,\n playDir: string,\n file: string,\n depth: number,\n ): Promise<Item | undefined> {\n const origin = { path: file, line: lineOf(raw) };\n const name = typeof raw.name === 'string' ? raw.name : '';\n if (Array.isArray(raw.block)) {\n const inner = narrow(scope, raw, 'block');\n const list = async (key: string) =>\n this.items(\n Array.isArray(raw[key]) ? (raw[key] as Plain[]) : [],\n inner,\n dir,\n playDir,\n file,\n depth,\n );\n return {\n kind: 'block',\n name,\n items: await list('block'),\n rescue: await list('rescue'),\n always: await list('always'),\n origin,\n };\n }\n const found = moduleOf(raw);\n if (!found) {\n this.notes.push(`${file}:${origin.line ?? '?'}: a task without a module was skipped.`);\n return undefined;\n }\n const short = shortName(found.module);\n const { keywords, dropped } = taskKeywords(scope, raw);\n if (found.local) keywords.delegate_to = 'localhost';\n const tags = [...scope.tags, ...asList(raw.tags)];\n if (INCLUDES.has(short))\n return this.include(\n raw,\n found.value,\n name,\n keywords,\n tags,\n dir,\n playDir,\n origin,\n scope,\n depth,\n short === 'import_tasks',\n );\n if (ROLE_INCLUDES.has(short)) {\n const args = moduleArgs(found.module, found.value, raw.args);\n const roleName = String(args.name ?? '');\n const params: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(args)) if (k !== 'name' && k !== 'apply') params[k] = v;\n if (isMapping(raw.vars)) Object.assign(params, toValue(raw.vars));\n const apply = isMapping(args.apply) ? (args.apply as PlainMap) : {};\n const role = await this.role(\n roleName,\n params,\n { ...raw, ...apply, vars: null } as PlainMap,\n scope,\n file,\n origin,\n );\n role.name = name || role.name;\n return role;\n }\n if (short === 'meta') {\n return { kind: 'meta', name, action: String(found.value ?? '').trim(), keywords, origin };\n }\n const params = moduleArgs(found.module, found.value, raw.args);\n const fqcn =\n builtinFqcn(found.module) ?? this.opts.resolveModule?.(found.module, this.collections);\n const become = asBool(raw.become) ?? scope.become;\n return {\n kind: 'task',\n name,\n module: found.module,\n ...(fqcn ? { fqcn } : {}),\n params,\n keywords,\n ...(typeof raw.register === 'string' && raw.register ? { register: raw.register } : {}),\n notify: asList(raw.notify),\n listen: asList(raw.listen),\n tags,\n ...(become !== undefined ? { become } : {}),\n ...(asIntOrTemplate(raw.timeout) ? { timeout: asIntOrTemplate(raw.timeout) } : {}),\n ...(asIntOrTemplate(raw.retries) !== undefined\n ? { retries: asIntOrTemplate(raw.retries) }\n : {}),\n ...(asIntOrTemplate(raw.delay) !== undefined ? { delay: asIntOrTemplate(raw.delay) } : {}),\n ...(typeof raw.until === 'string' ? { until: raw.until } : {}),\n ...((asBool(raw.ignore_unreachable) ?? scope.ignoreUnreachable)\n ? { ignoreUnreachable: true }\n : {}),\n dropped: [\n ...dropped,\n ...(raw.retries !== undefined && asIntOrTemplate(raw.retries) === undefined\n ? ['retries']\n : []),\n ...(raw.delay !== undefined && asIntOrTemplate(raw.delay) === undefined ? ['delay'] : []),\n ...(raw.timeout !== undefined && !asIntOrTemplate(raw.timeout) ? ['timeout'] : []),\n ],\n files: await this.localFiles(found.module, params, dir, playDir),\n origin,\n };\n }\n\n /** Where Ansible would find the local files a task names, searched as it does. */\n private async localFiles(\n module: string,\n params: Record<string, unknown>,\n dir: string,\n playDir: string,\n ): Promise<LocalFile[]> {\n const short = shortName(module).replace(/^ansible\\.windows\\./, '');\n const spec = LOCAL_FILES[short];\n if (!spec || asBool(params.remote_src)) return [];\n let written = params[spec.param];\n if (short === 'script' && typeof written === 'string') written = written.trim().split(/\\s+/)[0];\n if (typeof written !== 'string' || !written || isTemplated(written) || written.startsWith('/'))\n return [];\n const bases = [...new Set([dir, playDir])];\n const candidates = bases.flatMap((b) => [join(b, spec.sub, written), join(b, written)]);\n for (const path of candidates)\n if (await exists(this.io, path)) return [{ param: spec.param, written, path }];\n return [{ param: spec.param, written }];\n }\n\n private async varsFiles(value: Plain | undefined, dir: string): Promise<VarsFile[]> {\n const out: VarsFile[] = [];\n for (const entry of Array.isArray(value) ? value : []) {\n const file = Array.isArray(entry) ? entry[0] : entry;\n if (typeof file !== 'string') continue;\n if (isTemplated(file) || file.startsWith('/')) {\n out.push({ file, keys: [] });\n continue;\n }\n const path = join(dir, file);\n const data = (await exists(this.io, path)) ? await this.readYaml(path) : undefined;\n out.push({\n file,\n ...(data !== undefined ? { path } : {}),\n keys: isMapping(data) ? Object.keys(data) : [],\n });\n }\n return out;\n }\n\n private async include(\n raw: PlainMap,\n value: unknown,\n name: string,\n keywords: Record<string, unknown>,\n tags: string[],\n dir: string,\n playDir: string,\n origin: Origin,\n scope: Scope,\n depth: number,\n /** import_tasks: static; include_tasks (and the old include): dynamic (AFD-149). */\n isStatic = false,\n ): Promise<IncludeForm> {\n const args = isMapping(value) ? (toValue(value) as Record<string, unknown>) : {};\n const target =\n typeof value === 'string' ? value.trim() : String(args.file ?? args._raw_params ?? '');\n const form: IncludeForm = { kind: 'include', name, file: target, keywords, tags, origin };\n if (isMapping(raw.vars)) form.vars = toValue(raw.vars) as Record<string, unknown>;\n if (!target || isTemplated(target)) {\n form.dynamic = 'its file name is templated';\n return form;\n }\n // AFD-179: the file is found first, so an include that cannot be read in can still run it.\n const candidates = [...new Set([join(dir, target), join(playDir, target)])];\n let path: string | undefined;\n for (const c of candidates)\n if (await exists(this.io, c)) {\n path = c;\n break;\n }\n const runAsIs = async (why: string) => {\n form.dynamic = why;\n if (path) {\n form.path = path;\n form.portability = await this.portability(path, playDir);\n }\n return form;\n };\n if (keywords.loop !== undefined || Object.keys(keywords).some((k) => k.startsWith('with_')))\n return runAsIs('it runs in a loop');\n if (depth >= 8) return runAsIs('includes nest deeper than 8');\n if (path && this.including.includes(path)) {\n this.cyclic.add(path);\n return runAsIs(`${path} includes itself`);\n }\n for (const p of path ? [path] : []) {\n const data = await this.readYaml(p);\n if (data === undefined) break;\n form.path = p;\n // import_tasks: its keywords reach every task in the file. include_tasks (AFD-149): its own\n // `when` is checked once and its tags select the include itself; only its vars and `apply`\n // (keywords for the tasks inside) reach them.\n let inner: Scope;\n if (isStatic) inner = narrow(scope, raw, 'block');\n else {\n const base = narrow(\n scope,\n (raw.vars !== undefined ? { vars: raw.vars } : {}) as PlainMap,\n 'block',\n );\n inner = isMapping(args.apply) ? narrow(base, args.apply as PlainMap, 'block') : base;\n if (raw.when !== undefined)\n form.when = (Array.isArray(raw.when) ? raw.when : [raw.when]).map((w) =>\n toValue(w as Plain),\n );\n }\n this.including.push(p);\n const items = await this.items(\n Array.isArray(data) ? data : [],\n inner,\n dirname(p),\n playDir,\n p,\n depth + 1,\n );\n this.including.pop();\n // A file that includes itself, here or deeper, runs as include_tasks: a copy read in one\n // level deep would not run as the source does.\n if (this.cyclic.has(p)) return runAsIs(`${p} includes itself`);\n form.items = items;\n form.keywords = {};\n return form;\n }\n form.dynamic = `${candidates[0]} was not found`;\n return form;\n }\n\n /**\n * AFD-177: why a task file would not work from generated/: it reads playbook_dir, or includes a\n * file Ansible finds only next to the playbook (not next to the file itself).\n */\n private async portability(path: string, playDir: string): Promise<string[]> {\n const text = (await this.io.read(path)) ?? '';\n const found: string[] = [];\n if (/\\bplaybook_dir\\b/.test(text)) found.push('reads playbook_dir');\n const data = await this.readYaml(path);\n const nested = new Set<string>();\n const walk = (v: unknown) => {\n if (Array.isArray(v)) v.forEach(walk);\n else if (isMapping(v))\n for (const [k, x] of Object.entries(v)) {\n if (INCLUDES.has(shortName(k))) {\n const f = typeof x === 'string' ? x : isMapping(x) ? (x.file ?? x._raw_params) : '';\n if (typeof f === 'string' && f && !isTemplated(f) && !f.startsWith('/'))\n nested.add(f.trim());\n } else walk(x);\n }\n };\n walk(data);\n for (const f of nested)\n if (\n !(await exists(this.io, join(dirname(path), f))) &&\n (await exists(this.io, join(playDir, f)))\n )\n found.push(`includes ${f} relative to the playbook`);\n return found;\n }\n\n private async role(\n name: string,\n params: Record<string, unknown>,\n raw: PlainMap,\n scope: Scope,\n file: string,\n origin: Origin,\n ): Promise<RoleForm> {\n // Role variables are params; every other keyword applies to the role's tasks.\n const { keywords, dropped } = taskKeywords(scope, raw);\n delete keywords.vars;\n const info = await this.roleInfo(name, dirname(file));\n const tags = [...scope.tags, ...asList(raw.tags)];\n const become = asBool(raw.become) ?? scope.become;\n return {\n kind: 'role',\n name: name.includes('/') ? basename(name) : name,\n ref: name.includes('/') && info.dir ? basename(info.dir) : name,\n ...(info.dir ? { dir: info.dir } : {}),\n onRolesPath: info.onRolesPath,\n params,\n keywords,\n tags,\n ...(become !== undefined ? { become } : {}),\n ...(info.split && !params.tasks_from ? { split: info.split } : {}),\n outputs: info.outputs,\n dropped,\n origin,\n };\n }\n\n /** Where a role lives, whether runs find it, its split and what it registers. */\n roleInfo(name: string, fromDir: string): Promise<RoleInfo> {\n const key = `${fromDir}|${name}`;\n let found = this.roles.get(key);\n if (!found) {\n found = this.findRole(name, fromDir);\n this.roles.set(key, found);\n }\n return found;\n }\n\n private async findRole(name: string, fromDir: string): Promise<RoleInfo> {\n const parts = name.split('.');\n const cfgRoles = this.config?.rolesPath ?? [];\n let candidates: { dir: string; onRolesPath: boolean }[];\n if (!name.includes('/') && parts.length === 3) {\n const [ns, coll, role] = parts;\n const bases = [\n 'collections',\n ...(this.config?.collectionsPath ?? []).map((p) => normalize(p)),\n ];\n candidates = [...new Set([...bases, join(fromDir, 'collections')])].map((b) => ({\n dir: join(b, 'ansible_collections', ns ?? '', coll ?? '', 'roles', role ?? ''),\n onRolesPath: true,\n }));\n } else {\n // Ansible's order: roles/ next to the playbook, then roles_path, then the playbook's folder.\n candidates = [\n { dir: join(fromDir, 'roles', name), onRolesPath: false },\n ...cfgRoles.map((p) => ({ dir: join(p, name), onRolesPath: true })),\n { dir: join('roles', name), onRolesPath: false },\n { dir: join(fromDir, name), onRolesPath: false },\n ];\n }\n for (const c of candidates) {\n for (const main of ['tasks/main.yml', 'tasks/main.yaml', 'meta/main.yml'])\n if (await exists(this.io, join(c.dir, main))) {\n const onRolesPath = c.onRolesPath || cfgRoles.includes(dirname(c.dir));\n return { dir: c.dir, onRolesPath, ...(await this.roleTasks(c.dir)) };\n }\n }\n // A collection role not in the repository is still bound by name: the EE may have it.\n return { onRolesPath: parts.length === 3, outputs: [] };\n }\n\n /** A split role (main only includes literal files) and the variables its tasks set. */\n private async roleTasks(dir: string): Promise<{ split?: RoleStep[]; outputs: string[] }> {\n const tasksDir = join(dir, 'tasks');\n const outputs = new Set<string>();\n const seen = new Set<string>();\n const walk = async (path: string, depth: number): Promise<Plain[] | undefined> => {\n if (seen.has(path) || depth > 4) return undefined;\n seen.add(path);\n const text = await this.io.read(path);\n if (text === undefined || isVaultFile(text)) return undefined;\n const { value } = parseAnsible(text);\n if (!Array.isArray(value)) return undefined;\n const visit = async (list: Plain[]) => {\n for (const t of list) {\n if (!isMapping(t)) continue;\n if (typeof t.register === 'string') outputs.add(t.register);\n for (const b of ['block', 'rescue', 'always'])\n if (Array.isArray(t[b])) await visit(t[b] as Plain[]);\n const m = moduleOf(t);\n const short = m ? shortName(m.module) : '';\n if (short === 'set_fact' && isMapping(m?.value))\n for (const k of Object.keys(m.value)) if (k !== 'cacheable') outputs.add(k);\n const target = INCLUDES.has(short)\n ? typeof m?.value === 'string'\n ? m.value\n : (m?.value as PlainMap)?.file\n : undefined;\n if (typeof target === 'string' && !isTemplated(target))\n await walk(join(dirname(path), target), depth + 1);\n }\n };\n await visit(value);\n return value;\n };\n let mainPath = join(tasksDir, 'main.yml');\n if (!(await exists(this.io, mainPath))) mainPath = join(tasksDir, 'main.yaml');\n const main = await walk(mainPath, 0);\n let split: RoleStep[] | undefined;\n if (main && main.length >= 2) {\n split = [];\n for (const t of main) {\n const m = isMapping(t) ? moduleOf(t) : undefined;\n const short = m ? shortName(m.module) : '';\n const target =\n typeof m?.value === 'string' ? m.value.trim() : (m?.value as PlainMap | undefined)?.file;\n const extra = isMapping(t)\n ? Object.keys(t).filter((k) => isTaskKey(k) && !['name', 'tags', 'when'].includes(k))\n : ['?'];\n if (\n !m ||\n !INCLUDES.has(short) ||\n typeof target !== 'string' ||\n isTemplated(target) ||\n extra.length\n ) {\n split = undefined;\n break;\n }\n const rel = normalize(join(dirname(mainPath.slice(tasksDir.length + 1)), target));\n split.push({\n tasksFrom: rel.replace(/\\.ya?ml$/, ''),\n name:\n typeof (t as PlainMap).name === 'string'\n ? ((t as PlainMap).name as string)\n : basename(rel).replace(/\\.ya?ml$/, ''),\n keywords:\n (t as PlainMap).when !== undefined\n ? { when: toValue((t as PlainMap).when as Plain) }\n : {},\n tags: asList((t as PlainMap).tags),\n });\n }\n }\n return { ...(split ? { split } : {}), outputs: [...outputs].sort() };\n }\n}\n\n/** Reads a playbook with everything it imports and includes. */\nexport async function readPlaybook(\n io: SourceIO,\n path: string,\n opts: ReadOptions = {},\n): Promise<ReadResult> {\n const reader = new Reader(io, opts);\n const config = await reader.loadConfig();\n const playbook = await reader.playbook(normalize(path));\n return { playbook, notes: reader.notes, files: [...reader.files], ...(config ? { config } : {}) };\n}\n\n// ---- folders -------------------------------------------------------------------------------------\n\n/** Folders a scan never enters: tooling, generated code, and Ansible content that is not a playbook. */\nconst SKIP_DIRS = new Set([\n 'node_modules',\n 'generated',\n 'out',\n 'dist',\n 'venv',\n 'roles',\n 'group_vars',\n 'host_vars',\n 'collections',\n 'flows',\n 'molecule',\n '__pycache__',\n]);\n\nconst PLAY_HINT = /^[ \\t]*-?[ \\t]*(hosts|(ansible\\.builtin\\.)?import_playbook)[ \\t]*:/m;\n\nexport interface FolderPlaybook {\n path: string;\n /** The first play's name, else the file name. */\n title: string;\n /** Not imported by another playbook in the folder: offered first. */\n entry: boolean;\n /** Who imports it, when not an entry. */\n importedBy?: string;\n}\n\nexport interface FolderScan {\n playbooks: FolderPlaybook[];\n /** Roles under roles/ (and roles_path) with whether each is split. */\n roles: { name: string; dir: string; split: boolean }[];\n truncated: boolean;\n}\n\n/** The playbooks of a folder (and below), which ones are entries, and its roles. */\nexport async function scanFolder(io: SourceIO, dir: string, maxFiles = 2000): Promise<FolderScan> {\n const files: string[] = [];\n let truncated = false;\n const walk = async (d: string, depth: number) => {\n if (depth > 6) return;\n for (const e of await io.list(d)) {\n if (files.length >= maxFiles) {\n truncated = true;\n return;\n }\n if (e.name.startsWith('.')) continue;\n const path = join(d, e.name);\n if (e.dir) {\n if (!SKIP_DIRS.has(e.name)) await walk(path, depth + 1);\n } else if (/\\.ya?ml$/.test(e.name) && !e.name.endsWith('.flow.yaml')) files.push(path);\n }\n };\n await walk(normalize(dir), 0);\n const playbooks: FolderPlaybook[] = [];\n const imports = new Map<string, string>();\n for (const path of files) {\n const text = await io.read(path);\n if (text === undefined || !PLAY_HINT.test(text) || isVaultFile(text)) continue;\n const { value } = parseAnsible(text);\n if (!Array.isArray(value)) continue;\n const items = value.filter(isMapping);\n const plays = items.filter((p) => p.hosts !== undefined);\n const imported = items\n .map((p) => p.import_playbook ?? p['ansible.builtin.import_playbook'])\n .filter((f): f is string => typeof f === 'string' && !isTemplated(f));\n if (!plays.length && !imported.length) continue;\n for (const f of imported) imports.set(join(dirname(path), f), path);\n const first = plays.find((p) => typeof p.name === 'string');\n playbooks.push({\n path,\n title: typeof first?.name === 'string' ? first.name : basename(path),\n entry: true,\n });\n }\n for (const p of playbooks) {\n const by = imports.get(p.path);\n if (by) {\n p.entry = false;\n p.importedBy = by;\n }\n }\n const roles: FolderScan['roles'] = [];\n const reader = new Reader(io, {});\n const config = await reader.loadConfig();\n const roleDirs = [...new Set([join(dir, 'roles'), 'roles', ...(config?.rolesPath ?? [])])];\n for (const base of roleDirs)\n for (const e of await io.list(base))\n if (e.dir && !e.name.startsWith('.') && !roles.some((r) => r.dir === join(base, e.name))) {\n const r = await reader.roleInfo(e.name, dirname(base));\n if (r.dir) roles.push({ name: e.name, dir: r.dir, split: !!r.split });\n }\n playbooks.sort((a, b) => Number(b.entry) - Number(a.entry) || a.path.localeCompare(b.path));\n return { playbooks, roles, truncated };\n}\n"],
5
- "mappings": "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",
6
- "names": ["params"]
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../../../src/core/engine/binding.ts"],
4
- "sourcesContent": ["// What a bound node runs and how data reaches it (M5, ADR-0011): the module task or include_role\n// Option A emits, the play vars that pass upstream outputs in as node inputs, and set_fact\n// placeholders that let an unbound node's outputs flow through a skeleton run.\n\nimport { outputVar, registerName } from '../flow/dataNames';\nimport { resolveFrom } from '../flow/dataRefs';\nimport { ROLE_TASK_KEYWORDS, WITH } from '../flow/keywords';\nimport type { FlowModel } from '../flow/model';\nimport type { ContractType, FlowNode, ImplBinding } from '../flow/types';\nimport { jinjaLiteral } from './util';\nimport { flow, type Out, type OutMap, oneLine, writeBlock } from './yamlWriter';\n\n/** include_role options; every other role param becomes a role var. */\nexport const INCLUDE_OPTIONS = new Set([\n 'tasks_from',\n 'vars_from',\n 'defaults_from',\n 'handlers_from',\n 'public',\n 'allow_duplicates',\n 'rolespec_validate',\n]);\n\n/** Keywords ansible-core accepts on include_tasks itself; the others go into its apply. */\nconst INCLUDE_TASK_KEYWORDS: ReadonlySet<string> = new Set([\n 'when',\n 'loop',\n 'loop_control',\n 'vars',\n 'ignore_errors',\n 'no_log',\n 'run_once',\n 'debugger',\n]);\n\n/** A binding that runs a task file at run time (its tasks are not known to the flow). */\nexport function isIncludeTasks(ref: string | undefined): boolean {\n return /^(ansible\\.(builtin|legacy)\\.)?include_tasks$/.test(ref ?? '');\n}\n\n/** The module task or include_role of a bound node (without Option A's routing around it). */\nexport function bindingTask(node: FlowNode, impl: ImplBinding, timeout?: number | string): OutMap {\n const tag = `node_${node.id}`;\n const keywords = Object.entries(impl.keywords ?? {});\n if (impl.kind === 'role') {\n const options: OutMap = { name: impl.ref };\n const roleVars: OutMap = {};\n for (const [k, v] of Object.entries(impl.params ?? {}))\n (INCLUDE_OPTIONS.has(k) ? options : roleVars)[k] = v as Out;\n // Task keywords (AFD-26): conditions and loops stay on include_role; the rest reach every task\n // of the role through apply, as a static roles: entry would. Role variables live in params.\n const onTask: OutMap = {};\n const applied: OutMap = {};\n for (const [k, v] of keywords) {\n if (k === 'vars') continue;\n (ROLE_TASK_KEYWORDS.has(k) || WITH.test(k) ? onTask : applied)[k] = v as Out;\n }\n options.apply = { tags: flow([tag]), timeout, ...applied };\n return {\n name: `[${node.key}] Apply role`,\n 'ansible.builtin.include_role': options,\n ...onTask,\n vars: Object.keys(roleVars).length > 0 ? roleVars : undefined,\n };\n }\n const reg = registerName(node, impl);\n if (isIncludeTasks(impl.ref)) {\n // AFD-179: ansible-core refuses keywords outside its include list on include_tasks (no\n // ignore_unreachable, retries or until). Conditions, loops and vars stay on the include; the\n // rest reach every included task through apply, with the node's tag, as for a role.\n const onTask: OutMap = {};\n const applied: OutMap = {};\n for (const [k, v] of keywords)\n (INCLUDE_TASK_KEYWORDS.has(k) || WITH.test(k) ? onTask : applied)[k] = v as Out;\n const params = typeof impl.params === 'string' ? { file: impl.params } : (impl.params ?? {});\n return {\n name: `[${node.key}] ${jinjaLiteral(oneLine(node.title))}`,\n [impl.ref]: { ...(params as OutMap), apply: { tags: flow([tag]), timeout, ...applied } },\n ...onTask,\n register: reg,\n };\n }\n const { retries, delay, until } = node.settings ?? {};\n // A polling step stops when `until` holds (AFD-21); plain retries stop on the first success.\n const condition = until?.trim() || (retries ? `${reg} is succeeded` : undefined);\n return {\n name: `[${node.key}] ${jinjaLiteral(oneLine(node.title))}`,\n [impl.ref]: (impl.params ?? {}) as Out,\n ...(Object.fromEntries(keywords) as OutMap),\n register: reg,\n ignore_unreachable: true,\n timeout,\n retries,\n delay: condition ? delay : undefined,\n until: condition,\n };\n}\n\n/** The generated task as text, for the properties view (\"Generated task\", mockup 11). */\nexport function bindingTaskText(node: FlowNode, impl: ImplBinding): string {\n if (impl.kind === 'playbook')\n return writeBlock(\n [{ import_playbook: impl.ref, vars: { afd_hosts: '<hosts arriving here>' } }],\n 0,\n ).join('\\n');\n const task = bindingTask(node, impl);\n if (impl.kind === 'module') {\n // The preview shows what the user configured; Option A adds ignore_unreachable for routing.\n delete task.ignore_unreachable;\n task.tags = flow([`node_${node.id}`]);\n }\n return writeBlock([task], 0).join('\\n');\n}\n\n/**\n * The expression a `from:` reads, and whether it is a host variable of the producing host (an\n * output) rather than an extra var. Inside a subflow, `<subflow>.<input>` follows the subflow's\n * input to where it comes from (AFD-21); an input without `from` is read by its own name.\n */\nexport function sourceExpr(\n model: FlowModel,\n node: FlowNode,\n level: string,\n from: string,\n depth = 0,\n): { expr: string; host: boolean } | undefined {\n const src = resolveFrom(model, node, level, 'inputs', from);\n switch (src.kind) {\n case 'flow':\n return { expr: [src.name, ...src.path].join('.'), host: false };\n case 'output':\n return src.name\n ? { expr: [outputVar(model, src.node, src.name), ...src.path].join('.'), host: true }\n : undefined;\n case 'subflowInput': {\n const up = src.field.from?.trim();\n const at = model.nodes.get(src.node.id)?.level;\n const inner =\n up && at && depth < 16 ? sourceExpr(model, src.node, at, up, depth + 1) : undefined;\n if (!inner) return { expr: [src.name, ...src.path].join('.'), host: false };\n return { expr: [inner.expr, ...src.path].join('.'), host: inner.host };\n }\n case 'unresolved': {\n // The validator reports it; the code reads the name, as it did before AFD-21.\n const [head, name = '', ...path] = from.split('.');\n if (src.target && name)\n return { expr: [outputVar(model, src.target, name), ...path].join('.'), host: true };\n return head === 'flow' && name ? { expr: [name, ...path].join('.'), host: false } : undefined;\n }\n default:\n return undefined;\n }\n}\n\n/**\n * Play vars for a node's inputs (05 \u00A74): `from: <key>.<output>[.path]` reads the upstream node's\n * output variable (hostvars persist across plays and imported levels in one run), `from:\n * flow.<input>` reads the extra var. Same-name references need no var (and `x: \"{{ x }}\"` would\n * recurse). `via` reads upstream outputs from another host's hostvars: a node that runs on its\n * inventory_target reads them from the first arriving host (AFD-14).\n */\nexport function inputVars(model: FlowModel, level: string, node: FlowNode, via?: string): OutMap {\n const vars: OutMap = {};\n for (const [name, field] of Object.entries(node.inputs ?? {})) {\n const from = field?.from?.trim();\n // AFD-187: an input's default is what the step gets when its source left nothing; before, the\n // checker counted it as fed while the code never saw it.\n const fallback = field?.default;\n if (!from) {\n if (fallback !== undefined) vars[name] = fallback as Out;\n continue;\n }\n const src = sourceExpr(model, node, level, from);\n const expr = src && (src.host && via ? `${via}.${src.expr}` : src.expr);\n if (!expr || expr === name) continue;\n vars[name] =\n fallback === undefined ? `{{ ${expr} }}` : `{{ ${expr} | default(${jinjaValue(fallback)}) }}`;\n }\n return vars;\n}\n\n/** A YAML value as a Jinja literal: strings quoted, null as none, lists and dicts element-wise. */\nexport function jinjaValue(value: unknown): string {\n if (value === null || value === undefined) return 'none';\n if (typeof value === 'string')\n return `'${value.replaceAll('\\\\', '\\\\\\\\').replaceAll(\"'\", \"\\\\'\")}'`;\n if (typeof value === 'number' || typeof value === 'boolean') return String(value);\n if (Array.isArray(value)) return `[${value.map(jinjaValue).join(', ')}]`;\n if (typeof value === 'object')\n return `{${Object.entries(value as Record<string, unknown>)\n .map(([k, v]) => `${jinjaValue(k)}: ${jinjaValue(v)}`)\n .join(', ')}}`;\n return 'none';\n}\n\nconst PLACEHOLDER: Record<ContractType, Out> = {\n string: 'TODO',\n integer: 0,\n boolean: false,\n list: [],\n dict: {},\n host_list: [],\n any: 'TODO',\n};\n\n/** set_fact placeholders for the outputs of an unbound node, so downstream inputs resolve. */\nexport function stubFacts(node: FlowNode): OutMap | undefined {\n const outputs = Object.entries(node.outputs ?? {});\n if (outputs.length === 0) return undefined;\n const facts: OutMap = {};\n for (const [name, field] of outputs) {\n const value = field?.default ?? PLACEHOLDER[field?.type ?? 'any'] ?? 'TODO';\n facts[name] = value as Out;\n }\n return { name: `[${node.key}] TODO outputs`, 'ansible.builtin.set_fact': facts };\n}\n"],
5
- "mappings": "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",
6
- "names": []
7
- }