@uipath/skills 1.199.0 → 1.200.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 (345) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CODEOWNERS +14 -8
  4. package/README.md +18 -3
  5. package/assets/skill-status.json +9 -1
  6. package/assets/uip-catalog-snapshot.json +227 -21
  7. package/package.json +11 -2
  8. package/scripts/npm-package-lifecycle.mjs +46 -0
  9. package/skills/uipath-admin/SKILL.md +5 -1
  10. package/skills/uipath-admin/references/audit-commands.md +1 -1
  11. package/skills/uipath-admin/references/audit-workflow-guide.md +9 -0
  12. package/skills/uipath-agents/SKILL.md +2 -2
  13. package/skills/uipath-agents/references/lowcode/capabilities/context/index.md +7 -0
  14. package/skills/uipath-agents/references/lowcode/capabilities/integration-service/integration-service.md +5 -6
  15. package/skills/uipath-agents/references/lowcode/critical-rules/critical-rules.md +1 -1
  16. package/skills/uipath-agents/references/lowcode/evaluations/evaluation-sets.md +5 -0
  17. package/skills/uipath-agents/references/lowcode/project-lifecycle.md +3 -3
  18. package/skills/uipath-agents/references/lowcode/prompting/autonomous-agent-prompting-guide.md +3 -2
  19. package/skills/uipath-api-workflow/SKILL.md +2 -1
  20. package/skills/uipath-api-workflow/references/cli-reference.md +3 -3
  21. package/skills/uipath-coded-apps/SKILL.md +3 -2
  22. package/skills/uipath-coded-apps/assets/fixtures/governance-dashboard-starter-kit.tar.gz +0 -0
  23. package/skills/uipath-coded-apps/assets/templates/web-app-template.md +1 -1
  24. package/skills/uipath-coded-apps/references/create-web-app.md +60 -48
  25. package/skills/uipath-coded-apps/references/dashboards/CAPABILITY.md +2 -2
  26. package/skills/uipath-coded-apps/references/dashboards/plugins/build/impl.md +2 -2
  27. package/skills/uipath-coded-apps/references/dashboards/primitives/tier-resolution.md +16 -16
  28. package/skills/uipath-coded-apps/references/oauth-scopes.md +28 -272
  29. package/skills/uipath-coded-apps/references/sdk/action-center.md +26 -243
  30. package/skills/uipath-coded-apps/references/sdk/agents.md +20 -130
  31. package/skills/uipath-coded-apps/references/sdk/conversational-agent.md +52 -706
  32. package/skills/uipath-coded-apps/references/sdk/data-fabric.md +20 -237
  33. package/skills/uipath-coded-apps/references/sdk/feedback.md +4 -139
  34. package/skills/uipath-coded-apps/references/sdk/governance-traces.md +7 -55
  35. package/skills/uipath-coded-apps/references/sdk/governance.md +4 -44
  36. package/skills/uipath-coded-apps/references/sdk/imports.md +77 -35
  37. package/skills/uipath-coded-apps/references/sdk/maestro.md +29 -406
  38. package/skills/uipath-coded-apps/references/sdk/orchestrator.md +30 -324
  39. package/skills/uipath-coded-apps/references/sdk/pagination.md +9 -67
  40. package/skills/uipath-coded-apps/references/sdk/traces.md +8 -43
  41. package/skills/uipath-functions/SKILL.md +23 -23
  42. package/skills/uipath-governance/SKILL.md +5 -4
  43. package/skills/uipath-governance/references/cli-cheatsheet.md +2 -1
  44. package/skills/uipath-governance/references/compliance-pack/coverage/impl.md +143 -58
  45. package/skills/uipath-governance/references/compliance-pack/restore/impl.md +61 -0
  46. package/skills/uipath-human-in-the-loop/SKILL.md +4 -2
  47. package/skills/uipath-insights/SKILL.md +17 -18
  48. package/skills/uipath-ixp/SKILL.md +12 -7
  49. package/skills/uipath-ixp/references/cli-reference.md +71 -9
  50. package/skills/uipath-ixp/references/improve-prompts-guide.md +23 -9
  51. package/skills/uipath-ixp/references/label-documents-guide.md +33 -5
  52. package/skills/uipath-maestro-bpmn/SKILL.md +15 -14
  53. package/skills/uipath-maestro-bpmn/references/cli-conventions.md +15 -6
  54. package/skills/uipath-maestro-bpmn/references/structural-bpmn.md +18 -17
  55. package/skills/uipath-maestro-case/SKILL.md +46 -33
  56. package/skills/uipath-maestro-case/assets/templates/sdd-template.md +77 -37
  57. package/skills/uipath-maestro-case/assets/templates/sdd-viewer.html +0 -2
  58. package/skills/uipath-maestro-case/references/bindings-and-expressions.md +3 -1
  59. package/skills/uipath-maestro-case/references/bindings-v2-sync.md +2 -2
  60. package/skills/uipath-maestro-case/references/brownfield.md +15 -5
  61. package/skills/uipath-maestro-case/references/case-commands.md +19 -3
  62. package/skills/uipath-maestro-case/references/case-editing-operations.md +24 -21
  63. package/skills/uipath-maestro-case/references/case-schema.md +38 -16
  64. package/skills/uipath-maestro-case/references/connector-trigger-common.md +15 -8
  65. package/skills/uipath-maestro-case/references/evals/evals.json +35 -18
  66. package/skills/uipath-maestro-case/references/implementation.md +86 -71
  67. package/skills/uipath-maestro-case/references/phase-0-interview.md +92 -23
  68. package/skills/uipath-maestro-case/references/phased-execution.md +70 -55
  69. package/skills/uipath-maestro-case/references/placeholder-tasks.md +5 -5
  70. package/skills/uipath-maestro-case/references/planning.md +57 -9
  71. package/skills/uipath-maestro-case/references/plugins/case/impl-json.md +7 -5
  72. package/skills/uipath-maestro-case/references/plugins/case/planning.md +1 -1
  73. package/skills/uipath-maestro-case/references/plugins/conditions/case-exit-conditions/impl-json.md +5 -5
  74. package/skills/uipath-maestro-case/references/plugins/conditions/stage-entry-conditions/impl-json.md +41 -5
  75. package/skills/uipath-maestro-case/references/plugins/conditions/stage-entry-conditions/planning.md +27 -3
  76. package/skills/uipath-maestro-case/references/plugins/conditions/stage-exit-conditions/impl-json.md +6 -6
  77. package/skills/uipath-maestro-case/references/plugins/conditions/stage-exit-conditions/planning.md +3 -1
  78. package/skills/uipath-maestro-case/references/plugins/conditions/task-entry-conditions/impl-json.md +20 -7
  79. package/skills/uipath-maestro-case/references/plugins/conditions/task-entry-conditions/planning.md +37 -4
  80. package/skills/uipath-maestro-case/references/plugins/sla/impl-json.md +24 -13
  81. package/skills/uipath-maestro-case/references/plugins/sla/planning.md +9 -3
  82. package/skills/uipath-maestro-case/references/plugins/stages/impl-json.md +4 -0
  83. package/skills/uipath-maestro-case/references/plugins/stages/planning.md +4 -1
  84. package/skills/uipath-maestro-case/references/plugins/tasks/action/impl-json.md +3 -1
  85. package/skills/uipath-maestro-case/references/plugins/tasks/action/planning.md +2 -0
  86. package/skills/uipath-maestro-case/references/plugins/tasks/agent/impl-json.md +3 -2
  87. package/skills/uipath-maestro-case/references/plugins/tasks/agent/planning.md +4 -2
  88. package/skills/uipath-maestro-case/references/plugins/tasks/api-workflow/impl-json.md +3 -2
  89. package/skills/uipath-maestro-case/references/plugins/tasks/api-workflow/planning.md +4 -2
  90. package/skills/uipath-maestro-case/references/plugins/tasks/case-management/impl-json.md +3 -2
  91. package/skills/uipath-maestro-case/references/plugins/tasks/case-management/planning.md +4 -2
  92. package/skills/uipath-maestro-case/references/plugins/tasks/connector-activity/impl-json.md +1 -1
  93. package/skills/uipath-maestro-case/references/plugins/tasks/connector-activity/planning.md +2 -0
  94. package/skills/uipath-maestro-case/references/plugins/tasks/connector-trigger/impl-json.md +1 -1
  95. package/skills/uipath-maestro-case/references/plugins/tasks/connector-trigger/planning.md +2 -0
  96. package/skills/uipath-maestro-case/references/plugins/tasks/create-inline-common.md +1 -1
  97. package/skills/uipath-maestro-case/references/plugins/tasks/process/impl-json.md +3 -2
  98. package/skills/uipath-maestro-case/references/plugins/tasks/process/planning.md +6 -4
  99. package/skills/uipath-maestro-case/references/plugins/tasks/rpa/impl-json.md +3 -2
  100. package/skills/uipath-maestro-case/references/plugins/tasks/rpa/planning.md +4 -2
  101. package/skills/uipath-maestro-case/references/plugins/tasks/wait-for-timer/impl-json.md +4 -3
  102. package/skills/uipath-maestro-case/references/plugins/tasks/wait-for-timer/planning.md +4 -0
  103. package/skills/uipath-maestro-case/references/plugins/triggers/event/impl-json.md +17 -14
  104. package/skills/uipath-maestro-case/references/plugins/triggers/event/planning.md +1 -1
  105. package/skills/uipath-maestro-case/references/plugins/triggers/manual/impl-json.md +13 -10
  106. package/skills/uipath-maestro-case/references/plugins/triggers/timer/impl-json.md +18 -16
  107. package/skills/uipath-maestro-case/references/plugins/triggers/timer/planning.md +2 -2
  108. package/skills/uipath-maestro-case/references/plugins/variables/bindings/impl-json.md +1 -1
  109. package/skills/uipath-maestro-case/references/plugins/variables/global-vars/impl-json.md +11 -9
  110. package/skills/uipath-maestro-case/references/plugins/variables/io-binding/impl-json.md +6 -2
  111. package/skills/uipath-maestro-case/references/plugins/variables/io-binding/planning.md +19 -1
  112. package/skills/uipath-maestro-case/references/registry-discovery.md +3 -3
  113. package/skills/uipath-maestro-case/references/sdd-generation-rules.md +155 -51
  114. package/skills/uipath-maestro-case/references/sla-response-shapes.md +74 -0
  115. package/skills/uipath-maestro-flow/SKILL.md +4 -3
  116. package/skills/uipath-maestro-flow/references/author/CAPABILITY.md +3 -0
  117. package/skills/uipath-maestro-flow/references/author/references/editing-operations-json.md +10 -17
  118. package/skills/uipath-maestro-flow/references/author/references/editing-operations.md +1 -1
  119. package/skills/uipath-maestro-flow/references/author/references/greenfield.md +8 -6
  120. package/skills/uipath-maestro-flow/references/author/references/planning-impl.md +1 -1
  121. package/skills/uipath-maestro-flow/references/author/references/plugins/agent/impl.md +4 -9
  122. package/skills/uipath-maestro-flow/references/author/references/plugins/agentic-process/impl.md +3 -7
  123. package/skills/uipath-maestro-flow/references/author/references/plugins/api-workflow/impl.md +5 -8
  124. package/skills/uipath-maestro-flow/references/author/references/plugins/connector/impl.md +11 -4
  125. package/skills/uipath-maestro-flow/references/author/references/plugins/flow/impl.md +3 -7
  126. package/skills/uipath-maestro-flow/references/author/references/plugins/inline-agent/impl.md +14 -17
  127. package/skills/uipath-maestro-flow/references/author/references/plugins/ixp/impl.md +60 -13
  128. package/skills/uipath-maestro-flow/references/author/references/plugins/queue/impl.md +2 -14
  129. package/skills/uipath-maestro-flow/references/author/references/plugins/rpa/impl.md +4 -9
  130. package/skills/uipath-maestro-flow/references/author/references/plugins/script/impl.md +3 -0
  131. package/skills/uipath-maestro-flow/references/author/references/plugins/subflow/impl.md +5 -9
  132. package/skills/uipath-maestro-flow/references/author/references/plugins/transform/impl.md +13 -0
  133. package/skills/uipath-maestro-flow/references/shared/action-nodes.md +2 -2
  134. package/skills/uipath-maestro-flow/references/shared/file-format.md +16 -12
  135. package/skills/uipath-maestro-flow/references/shared/variables-and-expressions.md +3 -3
  136. package/skills/uipath-planner/SKILL.md +1 -1
  137. package/skills/uipath-planner/references/non-pdd-lane-guide.md +1 -1
  138. package/skills/uipath-platform/SKILL.md +1 -1
  139. package/skills/uipath-platform/references/data-fabric/bulk-import.md +10 -27
  140. package/skills/uipath-platform/references/data-fabric/choice-sets.md +7 -64
  141. package/skills/uipath-platform/references/data-fabric/data-fabric.md +76 -267
  142. package/skills/uipath-platform/references/data-fabric/entity-schema.md +23 -99
  143. package/skills/uipath-platform/references/data-fabric/file-attachments.md +5 -28
  144. package/skills/uipath-platform/references/data-fabric/filter-platform-contract.md +2 -2
  145. package/skills/uipath-platform/references/data-fabric/records-query.md +11 -32
  146. package/skills/uipath-platform/references/integration-service/reference-resolution.md +6 -2
  147. package/skills/uipath-platform/references/licensing/consumables-report.md +18 -0
  148. package/skills/uipath-platform/references/licensing/licensing.md +1 -1
  149. package/skills/uipath-platform/references/orchestrator/run-jobs.md +9 -2
  150. package/skills/uipath-platform/references/orchestrator/setup-environment.md +9 -0
  151. package/skills/uipath-platform/references/traces/feedback.md +4 -1
  152. package/skills/uipath-process-mining/SKILL.md +97 -0
  153. package/skills/uipath-process-mining/references/app-types.md +66 -0
  154. package/skills/uipath-process-mining/references/data-model.md +130 -0
  155. package/skills/uipath-process-mining/references/lifecycle-and-rbac.md +67 -0
  156. package/skills/uipath-process-mining/references/model-editing.md +112 -0
  157. package/skills/uipath-process-mining/references/pre-flight.md +119 -0
  158. package/skills/uipath-process-mining/references/querying.md +66 -0
  159. package/skills/uipath-process-mining/references/transformations.md +80 -0
  160. package/skills/uipath-process-mining/references/uip-pm-cli.md +145 -0
  161. package/skills/uipath-review/SKILL.md +23 -18
  162. package/skills/uipath-review/references/agents/agent-grading-rubric.md +1 -1
  163. package/skills/uipath-review/references/agents/agent-review-checklist.md +0 -4
  164. package/skills/uipath-review/references/agents/agents-coded-rules.md +1 -10
  165. package/skills/uipath-review/references/agents/agents-lowcode-rules.md +3 -6
  166. package/skills/uipath-review/references/agents/guardrails/coded-guardrails-review.md +62 -14
  167. package/skills/uipath-review/references/agents/guardrails/guardrails-review.md +60 -4
  168. package/skills/uipath-review/references/review-workflow-guide.md +3 -2
  169. package/skills/uipath-review/references/rule-catalog-workflow.md +4 -5
  170. package/skills/uipath-rpa/.maintenance/pattern-card-maintenance.md +20 -0
  171. package/skills/uipath-rpa/SKILL.md +57 -55
  172. package/skills/uipath-rpa/agents/uipath-project-discovery-agent.md +75 -19
  173. package/skills/uipath-rpa/assets/codedworkflow-template.md +245 -11
  174. package/skills/uipath-rpa/references/cli-reference.md +229 -6
  175. package/skills/uipath-rpa/references/coded/codedworkflow-reference.md +158 -2
  176. package/skills/uipath-rpa/references/coded/integration-service-guide.md +6 -5
  177. package/skills/uipath-rpa/references/coded/operations-guide.md +273 -5
  178. package/skills/uipath-rpa/references/coded-vs-xaml-guide.md +3 -3
  179. package/skills/uipath-rpa/references/common-pattern-card.md +303 -0
  180. package/skills/uipath-rpa/references/data-manipulation-guide.md +18 -3
  181. package/skills/uipath-rpa/references/debugging.md +0 -2
  182. package/skills/uipath-rpa/references/environment-setup.md +309 -1
  183. package/skills/uipath-rpa/references/error-handling-guide.md +1 -1
  184. package/skills/uipath-rpa/references/execution-maps-guide.md +110 -0
  185. package/skills/uipath-rpa/references/is-connector-xaml-guide.md +58 -4
  186. package/skills/uipath-rpa/references/legacy/activity-docs/Excel.md +1 -1
  187. package/skills/uipath-rpa/references/legacy/activity-docs/_DU-PROCESS.md +0 -2
  188. package/skills/uipath-rpa/references/legacy/activity-docs/_INDEX.md +2 -2
  189. package/skills/uipath-rpa/references/legacy/activity-docs/_PATTERNS.md +1 -1
  190. package/skills/uipath-rpa/references/legacy/activity-docs/_REFRAMEWORK.md +2 -7
  191. package/skills/uipath-rpa/references/legacy/cli-reference.md +599 -0
  192. package/skills/uipath-rpa/references/legacy/error-handling-guide.md +2 -2
  193. package/skills/uipath-rpa/references/legacy/legacy-mode-guide.md +16 -16
  194. package/skills/uipath-rpa/references/legacy/project-organization-guide.md +2 -2
  195. package/skills/uipath-rpa/references/legacy/selector-guide.md +163 -1
  196. package/skills/uipath-rpa/references/legacy/testing-guide.md +246 -3
  197. package/skills/uipath-rpa/references/legacy/xaml-basics-and-rules.md +267 -2
  198. package/skills/uipath-rpa/references/library-authoring-guide.md +4 -3
  199. package/skills/uipath-rpa/references/testing-guide.md +2 -28
  200. package/skills/uipath-rpa/references/trigger-pattern-guide.md +1 -1
  201. package/skills/uipath-rpa/references/xaml/canvas-layout-guide.md +140 -33
  202. package/skills/uipath-rpa/references/xaml/common-pitfalls.md +57 -240
  203. package/skills/uipath-rpa/references/xaml/csharp-activity-binding-guide.md +42 -2
  204. package/skills/uipath-rpa/references/xaml/long-running-workflow-guide.md +1 -1
  205. package/skills/uipath-rpa/references/xaml/xaml-basics-and-rules.md +194 -228
  206. package/skills/uipath-solution/references/activate-and-manage.md +22 -0
  207. package/skills/uipath-solution/references/develop-solution.md +26 -2
  208. package/skills/uipath-solution/references/pack-and-deploy.md +43 -9
  209. package/skills/uipath-test/SKILL.md +4 -4
  210. package/skills/uipath-test/references/playwright-first-mile-guide.md +5 -4
  211. package/skills/uipath-test/references/publish-and-link-guide.md +2 -2
  212. package/skills/uipath-troubleshoot/references/activity-packages/classic-activities/playbooks/click-silent-no-op.md +5 -5
  213. package/skills/uipath-troubleshoot/references/activity-packages/classic-activities/playbooks/queue-operation-failed.md +20 -4
  214. package/skills/uipath-troubleshoot/references/activity-packages/classic-activities/summary.md +1 -1
  215. package/skills/uipath-troubleshoot/references/activity-packages/csv-activities/playbooks/read-csv-file-not-found.md +12 -0
  216. package/skills/uipath-troubleshoot/references/activity-packages/mail-activities/playbooks/send-outlook-mail-failures.md +12 -1
  217. package/skills/uipath-troubleshoot/references/activity-packages/system-activities/playbooks/get-asset-activity-bug-silent-failure.md +2 -1
  218. package/skills/uipath-troubleshoot/references/activity-packages/terminal-activities/playbooks/terminal-session-connection-failed.md +5 -1
  219. package/skills/uipath-troubleshoot/references/activity-packages/ui-automation/playbooks/click-silent-no-op.md +5 -5
  220. package/skills/uipath-troubleshoot/references/activity-packages/ui-automation/playbooks/dependency-version-conflict.md +27 -6
  221. package/skills/uipath-troubleshoot/references/activity-packages/ui-automation/playbooks/napplicationcard-view-generation-failed.md +10 -0
  222. package/skills/uipath-troubleshoot/references/activity-packages/ui-automation/playbooks/scope-container-wrong-page.md +1 -1
  223. package/skills/uipath-troubleshoot/references/activity-packages/ui-automation/summary.md +1 -1
  224. package/skills/uipath-troubleshoot/references/activity-packages/web-activities/overview.md +4 -0
  225. package/skills/uipath-troubleshoot/references/activity-packages/web-activities/playbooks/http-request-auth-401-403.md +44 -0
  226. package/skills/uipath-troubleshoot/references/activity-packages/web-activities/playbooks/http-request-connection-failure.md +2 -1
  227. package/skills/uipath-troubleshoot/references/activity-packages/web-activities/playbooks/http-request-content-type-rejected.md +37 -0
  228. package/skills/uipath-troubleshoot/references/activity-packages/web-activities/playbooks/http-request-proxy-blocked.md +39 -0
  229. package/skills/uipath-troubleshoot/references/activity-packages/web-activities/playbooks/package-version-mismatch.md +42 -0
  230. package/skills/uipath-troubleshoot/references/activity-packages/web-activities/playbooks/securestring-misuse-analyzer.md +41 -0
  231. package/skills/uipath-troubleshoot/references/activity-packages/web-activities/summary.md +5 -0
  232. package/skills/uipath-troubleshoot/references/products/integration-service/playbooks/connector-null-reference.md +14 -1
  233. package/skills/uipath-troubleshoot/references/products/integration-service/playbooks/connector-runtime-exception.md +2 -0
  234. package/skills/uipath-troubleshoot/references/products/integration-service/playbooks/is-activities-prerelease-not-found.md +39 -0
  235. package/skills/uipath-troubleshoot/references/products/integration-service/playbooks/response-content-too-large.md +41 -0
  236. package/skills/uipath-troubleshoot/references/products/integration-service/summary.md +9 -0
  237. package/skills/uipath-troubleshoot/references/products/orchestrator/playbooks/console-conflict-login-to-console.md +40 -0
  238. package/skills/uipath-troubleshoot/references/products/orchestrator/playbooks/credential-store-unavailable.md +42 -0
  239. package/skills/uipath-troubleshoot/references/products/orchestrator/playbooks/executor-start-transient-rerun.md +49 -0
  240. package/skills/uipath-troubleshoot/references/products/orchestrator/playbooks/job-consecutive-system-exceptions.md +47 -0
  241. package/skills/uipath-troubleshoot/references/products/orchestrator/playbooks/job-faulted-session-timeout.md +19 -19
  242. package/skills/uipath-troubleshoot/references/products/orchestrator/playbooks/job-output-too-large.md +47 -0
  243. package/skills/uipath-troubleshoot/references/products/orchestrator/playbooks/job-stopped-generic-exit-code.md +55 -0
  244. package/skills/uipath-troubleshoot/references/products/orchestrator/playbooks/known-issue-robot-defect.md +40 -0
  245. package/skills/uipath-troubleshoot/references/products/orchestrator/playbooks/platform-incident-correlation.md +45 -0
  246. package/skills/uipath-troubleshoot/references/products/orchestrator/playbooks/screen-capture-handle-invalid.md +43 -0
  247. package/skills/uipath-troubleshoot/references/products/orchestrator/playbooks/serverless-license-quota.md +43 -0
  248. package/skills/uipath-troubleshoot/references/products/orchestrator/playbooks/serverless-time-limit-exceeded.md +34 -0
  249. package/skills/uipath-troubleshoot/references/products/orchestrator/playbooks/workstation-in-use-machine-slots.md +40 -0
  250. package/skills/uipath-troubleshoot/references/products/orchestrator/summary.md +13 -1
  251. package/version-manifest.json +2 -2
  252. package/skills/uipath-maestro-bpmn/validator/README.md +0 -224
  253. package/skills/uipath-maestro-bpmn/validator/model.mjs +0 -419
  254. package/skills/uipath-maestro-bpmn/validator/package.json +0 -17
  255. package/skills/uipath-maestro-bpmn/validator/rules.mjs +0 -1403
  256. package/skills/uipath-maestro-bpmn/validator/samples/invalid-conditional-and-variable.bpmn +0 -25
  257. package/skills/uipath-maestro-bpmn/validator/samples/valid-baseline.bpmn +0 -52
  258. package/skills/uipath-maestro-bpmn/validator/test/fixtures/expected-findings/A.2.0.bpmn +0 -157
  259. package/skills/uipath-maestro-bpmn/validator/test/fixtures/expected-findings/A.2.1.bpmn +0 -333
  260. package/skills/uipath-maestro-bpmn/validator/test/fixtures/expected-findings/B.1.0.bpmn +0 -598
  261. package/skills/uipath-maestro-bpmn/validator/test/fixtures/expected-findings/B.2.0.bpmn +0 -1709
  262. package/skills/uipath-maestro-bpmn/validator/test/fixtures/expected-findings/C.2.0.bpmn +0 -564
  263. package/skills/uipath-maestro-bpmn/validator/test/fixtures/expected-findings/C.3.0.bpmn +0 -671
  264. package/skills/uipath-maestro-bpmn/validator/test/fixtures/expected-findings/C.4.0.bpmn +0 -1045
  265. package/skills/uipath-maestro-bpmn/validator/test/fixtures/expected-findings/C.5.0.bpmn +0 -1176
  266. package/skills/uipath-maestro-bpmn/validator/test/fixtures/expected-findings/C.6.0.bpmn +0 -670
  267. package/skills/uipath-maestro-bpmn/validator/test/fixtures/expected-findings/C.7.0.bpmn +0 -466
  268. package/skills/uipath-maestro-bpmn/validator/test/fixtures/expected-findings/Can_Parse_Complex_Process_With_Task_Gateway_BoundaryEvent_etc.bpmn +0 -74
  269. package/skills/uipath-maestro-bpmn/validator/test/fixtures/expected-findings/ExclusiveGatewayDefaultFlow.bpmn +0 -32
  270. package/skills/uipath-maestro-bpmn/validator/test/fixtures/expected-findings/ExternalAgentWorkflow.bpmn +0 -62
  271. package/skills/uipath-maestro-bpmn/validator/test/fixtures/expected-findings/Golden_Scenario.initial.bpmn +0 -361
  272. package/skills/uipath-maestro-bpmn/validator/test/fixtures/expected-findings/InclusiveJoinRouteAwayBranch.bpmn +0 -62
  273. package/skills/uipath-maestro-bpmn/validator/test/fixtures/expected-findings/Parse_AsyncExecution_And_Create_CorrectModel.bpmn +0 -74
  274. package/skills/uipath-maestro-bpmn/validator/test/fixtures/expected-findings/Parse_IXP_ExtractionValidation_And_Create_CorrectModel.bpmn +0 -35
  275. package/skills/uipath-maestro-bpmn/validator/test/fixtures/expected-findings/Parse_IXP_Extraction_FileUpload_And_Create_CorrectModel.bpmn +0 -33
  276. package/skills/uipath-maestro-bpmn/validator/test/fixtures/expected-findings/Parse_IXP_Extraction_JobAttachment_And_Create_CorrectModel.bpmn +0 -35
  277. package/skills/uipath-maestro-bpmn/validator/test/fixtures/expected-findings/Parse_SubProcess_With_Multiple_Element_Types.bpmn +0 -76
  278. package/skills/uipath-maestro-bpmn/validator/test/fixtures/expected-findings/StartEventWithOutputs.bpmn +0 -36
  279. package/skills/uipath-maestro-bpmn/validator/test/fixtures/expected-findings/StartGatewayEnd.bpmn +0 -44
  280. package/skills/uipath-maestro-bpmn/validator/test/fixtures/expected-findings/all elements.bpmn +0 -516
  281. package/skills/uipath-maestro-bpmn/validator/test/fixtures/expected-findings/all_sequence_flow_types.bpmn +0 -173
  282. package/skills/uipath-maestro-bpmn/validator/test/fixtures/expected-findings/demo.bpmn +0 -181
  283. package/skills/uipath-maestro-bpmn/validator/test/fixtures/expected-findings/subprocess-example-001-collapsed.bpmn +0 -126
  284. package/skills/uipath-maestro-bpmn/validator/test/fixtures/expected-findings/subprocess-example-001-expanded.bpmn +0 -122
  285. package/skills/uipath-maestro-bpmn/validator/test/fixtures/expected-findings/subprocess-example-003-collapsed_deeply-nested.bpmn +0 -438
  286. package/skills/uipath-maestro-bpmn/validator/test/fixtures/known-good/A.1.0.bpmn +0 -87
  287. package/skills/uipath-maestro-bpmn/validator/test/fixtures/known-good/A.3.0.bpmn +0 -165
  288. package/skills/uipath-maestro-bpmn/validator/test/fixtures/known-good/ApiWorkflow.bpmn +0 -39
  289. package/skills/uipath-maestro-bpmn/validator/test/fixtures/known-good/BpmnNestedSubProcessTests.bpmn +0 -102
  290. package/skills/uipath-maestro-bpmn/validator/test/fixtures/known-good/BpmnTimerBoundaryEvents.bpmn +0 -160
  291. package/skills/uipath-maestro-bpmn/validator/test/fixtures/known-good/BpmnXmlWithCatchAllErrorEventSubProcess.bpmn +0 -45
  292. package/skills/uipath-maestro-bpmn/validator/test/fixtures/known-good/BpmnXmlWithSpecificErrorEventSubProcess.bpmn +0 -46
  293. package/skills/uipath-maestro-bpmn/validator/test/fixtures/known-good/CaseManagementWithConstantIdentifier.bpmn +0 -218
  294. package/skills/uipath-maestro-bpmn/validator/test/fixtures/known-good/ErrorBoundary.bpmn +0 -78
  295. package/skills/uipath-maestro-bpmn/validator/test/fixtures/known-good/ErrorPropagationInEventSubprocess.bpmn +0 -340
  296. package/skills/uipath-maestro-bpmn/validator/test/fixtures/known-good/EventBasedGatewayFirstCatcherWins.bpmn +0 -56
  297. package/skills/uipath-maestro-bpmn/validator/test/fixtures/known-good/Example-EventBasedGateway.bpmn +0 -117
  298. package/skills/uipath-maestro-bpmn/validator/test/fixtures/known-good/ExclusiveGatewayConditional.bpmn +0 -45
  299. package/skills/uipath-maestro-bpmn/validator/test/fixtures/known-good/ExclusiveGatewaySharedEndEvent.bpmn +0 -45
  300. package/skills/uipath-maestro-bpmn/validator/test/fixtures/known-good/ExclusiveWithParallelGateway.bpmn +0 -68
  301. package/skills/uipath-maestro-bpmn/validator/test/fixtures/known-good/FourScriptTasks.bpmn +0 -84
  302. package/skills/uipath-maestro-bpmn/validator/test/fixtures/known-good/HitlTaskOnly.bpmn +0 -55
  303. package/skills/uipath-maestro-bpmn/validator/test/fixtures/known-good/InclusiveGatewayForkJoin.bpmn +0 -69
  304. package/skills/uipath-maestro-bpmn/validator/test/fixtures/known-good/Parse_BPMN_Elements_And_Create_CorrectModel.bpmn +0 -20
  305. package/skills/uipath-maestro-bpmn/validator/test/fixtures/known-good/Parse_HttpRequest_ServiceTask_And_Create_Correct_Model.bpmn +0 -34
  306. package/skills/uipath-maestro-bpmn/validator/test/fixtures/known-good/Parse_MessageBoundaryEvent_And_Create_CorrectModel.bpmn +0 -87
  307. package/skills/uipath-maestro-bpmn/validator/test/fixtures/known-good/Parse_Script_Task_V2_And_Create_Correct_Model.bpmn +0 -31
  308. package/skills/uipath-maestro-bpmn/validator/test/fixtures/known-good/Parse_Sets_Containers_Properly.bpmn +0 -129
  309. package/skills/uipath-maestro-bpmn/validator/test/fixtures/known-good/ScriptWritesVariableThenGatewayBranches.bpmn +0 -59
  310. package/skills/uipath-maestro-bpmn/validator/test/fixtures/known-good/boundaryevent.bpmn +0 -30
  311. package/skills/uipath-maestro-bpmn/validator/test/fixtures/known-good/collapsed-subprocess.bpmn +0 -83
  312. package/skills/uipath-maestro-bpmn/validator/test/fixtures/known-good/connectable-types.bpmn +0 -85
  313. package/skills/uipath-maestro-bpmn/validator/test/fixtures/known-good/extensions-orchestrator-start-job.bpmn +0 -80
  314. package/skills/uipath-maestro-bpmn/validator/test/fixtures/known-good/multiparticipantpool.bpmn +0 -77
  315. package/skills/uipath-maestro-bpmn/validator/test/fixtures/known-good/nestedsubprocess.bpmn +0 -36
  316. package/skills/uipath-maestro-bpmn/validator/test/fixtures/known-good/simple.bpmn +0 -59
  317. package/skills/uipath-maestro-bpmn/validator/test/integration.test.mjs +0 -146
  318. package/skills/uipath-maestro-bpmn/validator/test/model-helpers.mjs +0 -42
  319. package/skills/uipath-maestro-bpmn/validator/test/ported-rule-tests.mjs +0 -983
  320. package/skills/uipath-maestro-bpmn/validator/test/run-tests.mjs +0 -530
  321. package/skills/uipath-maestro-bpmn/validator/uipath-moddle.v1.json +0 -715
  322. package/skills/uipath-maestro-bpmn/validator/validate-bpmn.mjs +0 -164
  323. package/skills/uipath-review/references/agents/agents-common-rules.md +0 -32
  324. package/skills/uipath-rpa/assets/before-after-hooks-template.md +0 -115
  325. package/skills/uipath-rpa/assets/helper-utility-template.md +0 -22
  326. package/skills/uipath-rpa/assets/testcase-template.md +0 -92
  327. package/skills/uipath-rpa/references/coded/coding-guidelines.md +0 -255
  328. package/skills/uipath-rpa/references/coded/inspect-package-guide.md +0 -80
  329. package/skills/uipath-rpa/references/coded/third-party-packages-guide.md +0 -67
  330. package/skills/uipath-rpa/references/connector-capabilities.md +0 -79
  331. package/skills/uipath-rpa/references/legacy/activity-docs/Testing.md +0 -95
  332. package/skills/uipath-rpa/references/legacy/activity-docs/UIAutomation.md +0 -159
  333. package/skills/uipath-rpa/references/legacy/common-pitfalls.md +0 -318
  334. package/skills/uipath-rpa/references/legacy/discovery-workflow.md +0 -147
  335. package/skills/uipath-rpa/references/legacy/environment-setup.md +0 -78
  336. package/skills/uipath-rpa/references/legacy/project-structure.md +0 -206
  337. package/skills/uipath-rpa/references/legacy/test-data-guide.md +0 -142
  338. package/skills/uipath-rpa/references/legacy/validation-and-fixing.md +0 -154
  339. package/skills/uipath-rpa/references/project-structure-guide.md +0 -168
  340. package/skills/uipath-rpa/references/project-structure.md +0 -135
  341. package/skills/uipath-rpa/references/publishing-guide.md +0 -80
  342. package/skills/uipath-rpa/references/validation-guide.md +0 -170
  343. package/skills/uipath-rpa/references/xaml/csharp-expression-pitfalls.md +0 -43
  344. package/skills/uipath-rpa/references/xaml/flowchart-guide.md +0 -113
  345. package/skills/uipath-rpa/references/xaml/workflow-guide.md +0 -258
@@ -1,983 +0,0 @@
1
- // Ported per-rule tests — a 1:1 translation of the PO.Frontend rule unit tests
2
- // (PO.Frontend/src/services/validation/bpmn/rules/*.test.ts) against OUR rule
3
- // engine (rules.mjs). Each case carries a `// FE:` comment mapping it to the
4
- // originating frontend test (file + test name). The frontend tests construct
5
- // synthetic Node[]/Edge[]/CanvasState graphs and call the rule directly; we do
6
- // the same so the comparison is exact.
7
- //
8
- // Where our port intentionally diverges from a frontend test, the divergence is
9
- // called out inline with a `// DRIFT:` comment and verified against the
10
- // frontend's *actual observable behavior* (not just its unit test), per the
11
- // drift-resolution policy. See README "Drift log".
12
- //
13
- // Returns { passed, failed, failures: [...] }.
14
-
15
- import {
16
- buildValidationLookupMaps,
17
- validateConditionalSequenceFlow,
18
- validateConnections,
19
- validateDuplicateErrorEventSubprocess,
20
- validateEventSubProcessStart,
21
- validateErrorBoundaryEvents,
22
- validateDuplicateErrorBoundaryEvents,
23
- validateErrorEndEvents,
24
- validateFakeJoins,
25
- validateMessageFlowCrossPool,
26
- validateMissingResource,
27
- validateMissingRootVariables,
28
- validateNoAssignmentsInExpressions,
29
- validateRequiredFields,
30
- validateSequenceFlowPoolCrossing,
31
- validateSequenceFlowSubProcessCrossing,
32
- validateSingleBlankStartEvent,
33
- validateSingleStartEventInEventSubProcess,
34
- validateSuperfluousGateway,
35
- validateTaskTimerRange,
36
- validateTimerDuration,
37
- validateVariableExistence,
38
- validateVariableNotSet,
39
- } from "../rules.mjs";
40
- import { node, edge, canvasState, maps } from "./model-helpers.mjs";
41
-
42
- const results = { passed: 0, failed: 0, failures: [], firedCodes: new Set() };
43
- let currentSuite = "";
44
- function suite(name) {
45
- currentSuite = name;
46
- }
47
- function check(name, condition, detail = "") {
48
- if (condition) {
49
- results.passed++;
50
- } else {
51
- results.failed++;
52
- results.failures.push(`[${currentSuite}] ${name}${detail ? " :: " + detail : ""}`);
53
- }
54
- }
55
- // assert exactly `n` findings of `code`
56
- function expectCodeCount(name, findings, code, n) {
57
- const got = findings.filter((f) => f.code === code).length;
58
- if (n > 0 && got === n) results.firedCodes.add(code); // track positive coverage
59
- check(name, got === n, `expected ${n}x ${code}, got ${got} (all: [${findings.map((f) => f.code).join(",")}])`);
60
- }
61
- function expectNone(name, findings, code) {
62
- const got = findings.filter((f) => f.code === code).length;
63
- check(name, got === 0, `expected 0x ${code}, got ${got}`);
64
- }
65
- function expectEmpty(name, findings) {
66
- check(name, findings.length === 0, `expected [], got [${findings.map((f) => f.code).join(",")}]`);
67
- }
68
-
69
- // Convenience: run a graph-rule with freshly built lookup maps.
70
- const run = (fn, nodes, edges) => fn(nodes, edges, buildValidationLookupMaps(nodes, edges));
71
-
72
- // ===========================================================================
73
- // 1. ConditionalFlowRule (MISSING_CONDITION_EXPRESSION)
74
- // ===========================================================================
75
- suite("ConditionalFlowRule");
76
- {
77
- // FE: "should return no errors for non-gateway nodes"
78
- expectEmpty("non-gateway node", run(validateConditionalSequenceFlow, [node("task1", "bpmn:Task")], []));
79
-
80
- // FE: "should return no errors for exclusive gateway with proper conditions"
81
- {
82
- const nodes = [node("gateway1", "bpmn:ExclusiveGateway"), node("task1", "bpmn:Task"), node("task2", "bpmn:Task")];
83
- const edges = [
84
- edge("flow1", "gateway1", "task1", { data: { conditionExpression: "x > 0" } }),
85
- edge("flow2", "gateway1", "task2", { data: { defaultFlow: true } }),
86
- ];
87
- expectEmpty("xor with conditions+default", run(validateConditionalSequenceFlow, nodes, edges));
88
- }
89
-
90
- // FE: "should detect missing conditions on exclusive gateway" (3 findings)
91
- {
92
- const nodes = [node("gateway1", "bpmn:ExclusiveGateway"), node("t1", "bpmn:Task"), node("t2", "bpmn:Task"), node("t3", "bpmn:Task")];
93
- const edges = [edge("flow1", "gateway1", "t1"), edge("flow2", "gateway1", "t2"), edge("flow3", "gateway1", "t3")];
94
- expectCodeCount("3 missing conditions", run(validateConditionalSequenceFlow, nodes, edges), "MISSING_CONDITION_EXPRESSION", 3);
95
- }
96
-
97
- // FE: "should not validate inclusive gateway flows anymore" (0 findings)
98
- {
99
- const nodes = [node("gateway1", "bpmn:InclusiveGateway"), node("t1", "bpmn:Task"), node("t2", "bpmn:Task"), node("t3", "bpmn:Task")];
100
- const edges = [edge("flow1", "gateway1", "t1"), edge("flow2", "gateway1", "t2"), edge("flow3", "gateway1", "t3")];
101
- expectEmpty("inclusive gateway not validated", run(validateConditionalSequenceFlow, nodes, edges));
102
- }
103
-
104
- // FE: "should validate condition type is conditionExpression not condition" — single outgoing → not a split
105
- {
106
- const nodes = [node("gateway1", "bpmn:ExclusiveGateway"), node("task1", "bpmn:Task")];
107
- const edges = [edge("flow1", "gateway1", "task1", { data: { conditionExpression: "x > 0" } })];
108
- expectEmpty("single outgoing not a split", run(validateConditionalSequenceFlow, nodes, edges));
109
- }
110
-
111
- // FE: "should flag exactly one flow without condition..." scenario 2 → 2 findings
112
- {
113
- const nodes = [node("gateway2", "bpmn:ExclusiveGateway"), node("t1", "bpmn:Task"), node("t2", "bpmn:Task"), node("t3", "bpmn:Task")];
114
- const edges = [
115
- edge("flow1", "gateway2", "t1", { data: { conditionExpression: "x > 0" } }),
116
- edge("flow2", "gateway2", "t2"),
117
- edge("flow3", "gateway2", "t3"),
118
- ];
119
- expectCodeCount("two flows missing condition", run(validateConditionalSequenceFlow, nodes, edges), "MISSING_CONDITION_EXPRESSION", 2);
120
- }
121
-
122
- // FE: "should handle text annotation" — only outgoing is an Association to a TextAnnotation → 0
123
- {
124
- const nodes = [node("g", "bpmn:ExclusiveGateway"), node("anno", "bpmn:TextAnnotation")];
125
- const edges = [edge("g_anno", "g", "anno", { type: "bpmn:Association" })];
126
- expectEmpty("text annotation target ignored", run(validateConditionalSequenceFlow, nodes, edges));
127
- }
128
-
129
- // FE: "should handle empty nodes and edges arrays"
130
- expectEmpty("empty graph", run(validateConditionalSequenceFlow, [], []));
131
-
132
- // FE chained: "should correctly validate an XOR gateway that splits..." — 2 findings, both from XOR_A
133
- {
134
- const nodes = [node("XOR_A", "bpmn:ExclusiveGateway"), node("XOR_B", "bpmn:ExclusiveGateway"), node("Task_C", "bpmn:Task"), node("Task_D", "bpmn:Task")];
135
- const edges = [edge("Flow1_A_to_B", "XOR_A", "XOR_B"), edge("Flow2_A_to_C", "XOR_A", "Task_C"), edge("Flow3_B_to_D", "XOR_B", "Task_D")];
136
- const f = run(validateConditionalSequenceFlow, nodes, edges);
137
- expectCodeCount("chained gateways: 2 findings", f, "MISSING_CONDITION_EXPRESSION", 2);
138
- check("chained gateways: both sourceId XOR_A", f.every((e) => e.sourceId === "XOR_A"), JSON.stringify(f.map((e) => e.sourceId)));
139
- }
140
- }
141
-
142
- // ===========================================================================
143
- // 2. ConnectionRule (INVALID_CONNECTION / INVALID_CONNECTION_TYPE)
144
- // FE asserts by message substring; we assert the equivalent code.
145
- // ===========================================================================
146
- suite("ConnectionRule");
147
- {
148
- // FE: "should validate empty graph without errors"
149
- expectEmpty("empty graph", run(validateConnections, [], []));
150
-
151
- // FE: "should allow valid connections between nodes" — StartEvent -> Task
152
- {
153
- const nodes = [node("1", "bpmn:StartEvent"), node("2", "bpmn:Task")];
154
- expectEmpty("start->task allowed", run(validateConnections, nodes, [edge("e1", "1", "2")]));
155
- }
156
-
157
- // FE: "should detect edges with missing nodes" — Broken flow line
158
- {
159
- const nodes = [node("1", "bpmn:StartEvent")];
160
- const f = run(validateConnections, nodes, [edge("e1", "1", "nonexistent")]);
161
- expectCodeCount("broken flow line -> INVALID_CONNECTION", f, "INVALID_CONNECTION", 1);
162
- }
163
-
164
- // FE: "should not allow a connection to have the same source and target"
165
- {
166
- const nodes = [node("1", "bpmn:StartEvent")];
167
- const f = run(validateConnections, nodes, [edge("e1", "1", "1")]);
168
- expectCodeCount("self loop -> INVALID_CONNECTION", f, "INVALID_CONNECTION", 1);
169
- }
170
-
171
- // FE: "should validate node type compatibility" — verbatim frontend input:
172
- // unknown source type "output" → unknown target "input". canNodeTypesBeConnected
173
- // (BPMNTypesUtils.ts:51-82) finds no matching rule and returns false, so the
174
- // edge is INVALID_CONNECTION_TYPE. (Restored from a prior doctored EndEvent->Task
175
- // substitute; matches ConnectionRule.test.ts:33-43.)
176
- {
177
- const nodes = [node("1", "output"), node("2", "input")];
178
- const f = run(validateConnections, nodes, [edge("e1", "1", "2")]);
179
- expectCodeCount("unknown output->input -> INVALID_CONNECTION_TYPE", f, "INVALID_CONNECTION_TYPE", 1);
180
- }
181
- }
182
-
183
- // ===========================================================================
184
- // 3. DuplicateErrorEventSubprocessRule
185
- // ===========================================================================
186
- suite("DuplicateErrorEventSubprocessRule");
187
- {
188
- const esp = (id, parentId) => node(id, "bpmn:SubProcess", { triggeredByEvent: true }, { parentId });
189
- const errStart = (id, parentId, errorRef) =>
190
- node(id, "bpmn:StartEvent", { eventDefinition: { type: "bpmn:ErrorEventDefinition", ...(errorRef ? { errorRef } : {}) } }, { parentId });
191
-
192
- // FE: "multiple catch-all error event subprocesses at same scope" — 2 findings
193
- {
194
- const nodes = [esp("sp1", undefined), errStart("s1", "sp1"), esp("sp2", undefined), errStart("s2", "sp2")];
195
- const cs = canvasState({ errors: [] });
196
- const f = validateDuplicateErrorEventSubprocess(nodes, cs, maps(nodes, []));
197
- expectCodeCount("2 catch-all ESP", f, "MULTIPLE_CATCH_ALL_ERROR_EVENT_SUBPROCESS", 2);
198
- }
199
-
200
- // FE: "multiple error event subprocesses with same error code at same scope" — 2 findings
201
- {
202
- const nodes = [esp("sp1", undefined), errStart("s1", "sp1", "error1"), esp("sp2", undefined), errStart("s2", "sp2", "error2")];
203
- const cs = canvasState({ errors: [{ id: "error1", errorCode: "501" }, { id: "error2", errorCode: "501" }] });
204
- const f = validateDuplicateErrorEventSubprocess(nodes, cs, maps(nodes, []));
205
- expectCodeCount("same error code ESP", f, "DUPLICATE_ERROR_EVENT_SUBPROCESS", 2);
206
- }
207
-
208
- // FE: "different error codes at same scope" — []
209
- {
210
- const nodes = [esp("sp1", undefined), errStart("s1", "sp1", "error1"), esp("sp2", undefined), errStart("s2", "sp2", "error2")];
211
- const cs = canvasState({ errors: [{ id: "error1", errorCode: "501" }, { id: "error2", errorCode: "502" }] });
212
- expectEmpty("different error codes ESP", validateDuplicateErrorEventSubprocess(nodes, cs, maps(nodes, [])));
213
- }
214
-
215
- // FE: "same error code at different scopes" — []
216
- {
217
- const nodes = [esp("sp1", "scope1"), errStart("s1", "sp1", "error1"), esp("sp2", "scope2"), errStart("s2", "sp2", "error1")];
218
- const cs = canvasState({ errors: [{ id: "error1", errorCode: "501" }] });
219
- expectEmpty("same code different scope ESP", validateDuplicateErrorEventSubprocess(nodes, cs, maps(nodes, [])));
220
- }
221
-
222
- // FE: "catch-all error event subprocesses at different scopes" — []
223
- {
224
- const nodes = [esp("sp1", "scope1"), errStart("s1", "sp1"), esp("sp2", "scope2"), errStart("s2", "sp2")];
225
- expectEmpty("catch-all different scope ESP", validateDuplicateErrorEventSubprocess(nodes, canvasState(), maps(nodes, [])));
226
- }
227
- }
228
-
229
- // ===========================================================================
230
- // 4. EmptyStartEventDefinitionInSubProcessRule
231
- // ===========================================================================
232
- suite("EmptyStartEventDefinitionInSubProcessRule");
233
- {
234
- const sp = (id, triggeredByEvent) => node(id, "bpmn:SubProcess", triggeredByEvent ? { triggeredByEvent: true } : {});
235
- const start = (id, parentId, ed) => node(id, "bpmn:StartEvent", ed ? { eventDefinition: ed } : {}, { parentId });
236
-
237
- // FE: "should allow blank start event in subprocess" (regular)
238
- {
239
- const nodes = [sp("subprocess1", false), start("start1", "subprocess1")];
240
- expectEmpty("blank start in regular subprocess", run(validateEventSubProcessStart, nodes, []));
241
- }
242
- // FE: "should detect start event with event definition in regular subprocess"
243
- {
244
- const nodes = [sp("subprocess1", false), start("start1", "subprocess1", { id: "timer1", type: "bpmn:TimerEventDefinition" })];
245
- expectCodeCount("def in regular subprocess", run(validateEventSubProcessStart, nodes, []), "START_EVENT_WITH_DEFINITION_IN_SUBPROCESS", 1);
246
- }
247
- // FE: "should allow start event with timer event definition in event subprocess"
248
- {
249
- const nodes = [sp("subprocess1", true), start("start1", "subprocess1", { type: "bpmn:TimerEventDefinition" })];
250
- expectEmpty("timer def in event subprocess", run(validateEventSubProcessStart, nodes, []));
251
- }
252
- // FE: "should allow start event with message event definition in event subprocess"
253
- {
254
- const nodes = [sp("subprocess1", true), start("start1", "subprocess1", { type: "bpmn:MessageEventDefinition" })];
255
- expectEmpty("message def in event subprocess", run(validateEventSubProcessStart, nodes, []));
256
- }
257
- // FE: "should detect start event without event definition in event subprocess"
258
- {
259
- const nodes = [sp("subprocess1", true), start("start1", "subprocess1")];
260
- expectCodeCount("no def in event subprocess", run(validateEventSubProcessStart, nodes, []), "START_EVENT_WITHOUT_DEFINITION_IN_EVENT_SUBPROCESS", 1);
261
- }
262
- // FE: "should detect start event with invalid event definition in event subprocess"
263
- {
264
- const nodes = [sp("subprocess1", true), start("start1", "subprocess1", { type: "bpmn:ConditionalEventDefinition" })];
265
- expectCodeCount("invalid def in event subprocess", run(validateEventSubProcessStart, nodes, []), "INVALID_EVENT_DEFINITION_IN_EVENT_SUBPROCESS", 1);
266
- }
267
- }
268
-
269
- // ===========================================================================
270
- // 5. ErrorBoundaryEventRule (validate + duplicate)
271
- // ===========================================================================
272
- suite("ErrorBoundaryEventRule");
273
- {
274
- const be = (id, ed, attachedToId = "task1") => node(id, "bpmn:BoundaryEvent", { eventDefinition: ed, attachedToId });
275
-
276
- // FE: "should not report errors when there are no boundary events"
277
- expectEmpty("no boundary events", validateErrorBoundaryEvents([], canvasState()));
278
- // FE: "should not report errors for boundary events without error definitions"
279
- expectEmpty("non-error boundary def", validateErrorBoundaryEvents([be("boundary1", { type: "bpmn:SignalEventDefinition" })], canvasState()));
280
- // FE: "should detect empty error reference in boundary event" (errorRef:"")
281
- {
282
- const f = validateErrorBoundaryEvents([be("boundary1", { type: "bpmn:ErrorEventDefinition", errorRef: "" })], canvasState());
283
- expectCodeCount("empty error ref", f, "ERROR_BOUNDARY_EVENT_EMPTY_ERROR_REF", 1);
284
- }
285
- // FE: "should detect missing error code when referencing an error"
286
- {
287
- const cs = canvasState({ errors: [{ id: "error1", name: "CustomerError", errorCode: "" }] });
288
- const f = validateErrorBoundaryEvents([be("boundary1", { type: "bpmn:ErrorEventDefinition", errorRef: "error1" })], cs);
289
- expectCodeCount("missing error code", f, "ERROR_BOUNDARY_EVENT_REQUIRES_ERROR_CODE", 1);
290
- }
291
- // FE: "should not report errors when error has valid error code"
292
- {
293
- const cs = canvasState({ errors: [{ id: "error1", name: "CustomerError", errorCode: "ERR-001" }] });
294
- expectEmpty("valid error code", validateErrorBoundaryEvents([be("boundary1", { type: "bpmn:ErrorEventDefinition", errorRef: "error1" })], cs));
295
- }
296
- // FE: "multiple catch-all boundary events on same task" — 2 findings
297
- {
298
- const nodes = [be("b1", { type: "bpmn:ErrorEventDefinition" }, "task1"), be("b2", { type: "bpmn:ErrorEventDefinition" }, "task1")];
299
- expectCodeCount("2 catch-all on task", validateDuplicateErrorBoundaryEvents(nodes, canvasState()), "MULTIPLE_CATCH_ALL_BOUNDARY_EVENTS_ON_TASK", 2);
300
- }
301
- // FE: "multiple boundary events with same error code on same task" — 2 findings
302
- {
303
- const nodes = [be("b1", { type: "bpmn:ErrorEventDefinition", errorRef: "error1" }, "task1"), be("b2", { type: "bpmn:ErrorEventDefinition", errorRef: "error2" }, "task1")];
304
- const cs = canvasState({ errors: [{ id: "error1", errorCode: "501" }, { id: "error2", errorCode: "501" }] });
305
- expectCodeCount("same code on task", validateDuplicateErrorBoundaryEvents(nodes, cs), "DUPLICATE_ERROR_BOUNDARY_EVENT_ON_TASK", 2);
306
- }
307
- // FE: "different error codes on same task" — []
308
- {
309
- const nodes = [be("b1", { type: "bpmn:ErrorEventDefinition", errorRef: "error1" }, "task1"), be("b2", { type: "bpmn:ErrorEventDefinition", errorRef: "error2" }, "task1")];
310
- const cs = canvasState({ errors: [{ id: "error1", errorCode: "501" }, { id: "error2", errorCode: "502" }] });
311
- expectEmpty("different codes on task", validateDuplicateErrorBoundaryEvents(nodes, cs));
312
- }
313
- // FE: "same error code on different tasks" — []
314
- {
315
- const nodes = [be("b1", { type: "bpmn:ErrorEventDefinition", errorRef: "error1" }, "task1"), be("b2", { type: "bpmn:ErrorEventDefinition", errorRef: "error1" }, "task2")];
316
- const cs = canvasState({ errors: [{ id: "error1", errorCode: "501" }] });
317
- expectEmpty("same code different tasks", validateDuplicateErrorBoundaryEvents(nodes, cs));
318
- }
319
- // FE: "catch-all boundary events on different tasks" — []
320
- {
321
- const nodes = [be("b1", { type: "bpmn:ErrorEventDefinition" }, "task1"), be("b2", { type: "bpmn:ErrorEventDefinition" }, "task2")];
322
- expectEmpty("catch-all different tasks", validateDuplicateErrorBoundaryEvents(nodes, canvasState()));
323
- }
324
- }
325
-
326
- // ===========================================================================
327
- // 6. ErrorEndEventRule
328
- // ===========================================================================
329
- suite("ErrorEndEventRule");
330
- {
331
- const end = (id, ed) => node(id, "bpmn:EndEvent", ed ? { eventDefinition: ed } : {});
332
- expectEmpty("no end events", validateErrorEndEvents([]));
333
- expectEmpty("end without def", validateErrorEndEvents([end("end1")]));
334
- expectEmpty("end with signal def", validateErrorEndEvents([end("end1", { type: "bpmn:SignalEventDefinition" })]));
335
- // FE: "should report error when error end event has no errorRef"
336
- expectCodeCount("error end no errorRef", validateErrorEndEvents([end("end1", { type: "bpmn:ErrorEventDefinition" })]), "ERROR_END_EVENT_MISSING_EXCEPTION", 1);
337
- // FE: "should report error when error end event has empty errorRef"
338
- expectCodeCount("error end empty errorRef", validateErrorEndEvents([end("end1", { type: "bpmn:ErrorEventDefinition", errorRef: "" })]), "ERROR_END_EVENT_MISSING_EXCEPTION", 1);
339
- // FE: "should not report error when error end event has a valid errorRef"
340
- expectEmpty("error end valid errorRef", validateErrorEndEvents([end("end1", { type: "bpmn:ErrorEventDefinition", errorRef: "error1" })]));
341
- // FE: "multiple error end events missing errorRef" — 2 findings (end1, end3)
342
- {
343
- const nodes = [end("end1", { type: "bpmn:ErrorEventDefinition" }), end("end2", { type: "bpmn:ErrorEventDefinition", errorRef: "error1" }), end("end3", { type: "bpmn:ErrorEventDefinition" })];
344
- const f = validateErrorEndEvents(nodes);
345
- expectCodeCount("2 error ends missing ref", f, "ERROR_END_EVENT_MISSING_EXCEPTION", 2);
346
- check("error ends are end1,end3", f.map((e) => e.elementId).join(",") === "end1,end3", f.map((e) => e.elementId).join(","));
347
- }
348
- // FE: "should ignore non-end-event nodes"
349
- expectEmpty("ignore boundary error event", validateErrorEndEvents([node("boundary1", "bpmn:BoundaryEvent", { eventDefinition: { type: "bpmn:ErrorEventDefinition" } })]));
350
- }
351
-
352
- // ===========================================================================
353
- // 7. FakeJoinRule
354
- // DRIFT (resolved by matching the frontend's *actual* behavior): the frontend
355
- // rule matches only literal "bpmn:Activity"/"bpmn:Event" node types. On the real
356
- // canvas every node carries its CONCRETE type (bpmn:Task, bpmn:EndEvent, ...),
357
- // so the rule is dormant on exported BPMN. Our port mirrors that exactly. The
358
- // FE unit tests below feed literal abstract types — we reproduce them verbatim,
359
- // AND add concrete-type cases proving we do NOT over-fire on real BPMN (which an
360
- // earlier hand-port did). See README "Drift log #2".
361
- // ===========================================================================
362
- suite("FakeJoinRule");
363
- {
364
- // FE: "should return empty array for null or undefined inputs"
365
- expectEmpty("null nodes", validateFakeJoins(null, [], maps([], [])));
366
- expectEmpty("null edges", validateFakeJoins([], null, maps([], [])));
367
- expectEmpty("undefined both", validateFakeJoins(undefined, undefined, maps([], [])));
368
- // FE: "should return empty array when no fake joins exist"
369
- {
370
- const nodes = [node("1", "bpmn:Activity"), node("2", "bpmn:Event")];
371
- expectEmpty("no fake joins", run(validateFakeJoins, nodes, [edge("e1", "1", "2")]));
372
- }
373
- // FE: "should detect fake joins in activities" (literal bpmn:Activity, 2 incoming)
374
- {
375
- const nodes = [node("1", "bpmn:Activity"), node("2", "bpmn:Activity"), node("3", "bpmn:Activity")];
376
- const edges = [edge("e1", "1", "3"), edge("e2", "2", "3")];
377
- expectCodeCount("fake join in activity", run(validateFakeJoins, nodes, edges), "FAKE_JOIN", 1);
378
- }
379
- // FE: "should detect fake joins in events" (literal bpmn:Event)
380
- {
381
- const nodes = [node("1", "bpmn:Activity"), node("2", "bpmn:Activity"), node("3", "bpmn:Event")];
382
- const edges = [edge("e1", "1", "3"), edge("e2", "2", "3")];
383
- expectCodeCount("fake join in event", run(validateFakeJoins, nodes, edges), "FAKE_JOIN", 1);
384
- }
385
- // FE: "should ignore non-activity/event nodes" (gateway with multiple incoming)
386
- {
387
- const nodes = [node("1", "bpmn:Activity"), node("2", "bpmn:Activity"), node("3", "bpmn:Gateway")];
388
- const edges = [edge("e1", "1", "3"), edge("e2", "2", "3")];
389
- expectEmpty("gateway multiple incoming allowed", run(validateFakeJoins, nodes, edges));
390
- }
391
- // PORT PARITY: concrete-typed task with 2 incoming must NOT fire (matches the
392
- // frontend's dormant-on-real-BPMN behavior; an earlier hand-port over-fired).
393
- {
394
- const nodes = [node("a", "bpmn:Task"), node("b", "bpmn:Task"), node("c", "bpmn:Task")];
395
- const edges = [edge("e1", "a", "c"), edge("e2", "b", "c")];
396
- expectNone("concrete task join does not over-fire", run(validateFakeJoins, nodes, edges), "FAKE_JOIN");
397
- }
398
- }
399
-
400
- // ===========================================================================
401
- // 8. MessageFlowObjectsPoolRule
402
- // ===========================================================================
403
- suite("MessageFlowObjectsPoolRule");
404
- {
405
- const part = (id) => node(id, "bpmn:Participant");
406
- const inPool = (id, parentId) => node(id, "bpmn:Task", {}, { parentId });
407
- const mf = (id, s, t) => edge(id, s, t, { type: "bpmn:MessageFlow" });
408
-
409
- // FE: "should return empty array when no pools exist"
410
- expectEmpty("no pools", run(validateMessageFlowCrossPool, [inPool("task1"), inPool("task2")], [mf("flow1", "task1", "task2")]));
411
- // FE: "should allow message flow between different pools"
412
- {
413
- const nodes = [part("pool1"), part("pool2"), inPool("task1", "pool1"), inPool("task2", "pool2")];
414
- expectEmpty("cross-pool mf allowed", run(validateMessageFlowCrossPool, nodes, [mf("flow1", "task1", "task2")]));
415
- }
416
- // FE: "should detect message flow within the same pool" — 1 finding
417
- {
418
- const nodes = [part("pool1"), inPool("task1", "pool1"), inPool("task2", "pool1")];
419
- expectCodeCount("same-pool mf", run(validateMessageFlowCrossPool, nodes, [mf("flow1", "task1", "task2")]), "SAME_POOL_MESSAGE_FLOW", 1);
420
- }
421
- // FE: "should handle nested elements in pools"
422
- {
423
- const nodes = [part("pool1"), node("subprocess1", "bpmn:SubProcess", {}, { parentId: "pool1" }), inPool("task1", "subprocess1"), inPool("task2", "subprocess1")];
424
- expectCodeCount("nested same-pool mf", run(validateMessageFlowCrossPool, nodes, [mf("flow1", "task1", "task2")]), "SAME_POOL_MESSAGE_FLOW", 1);
425
- }
426
- // FE: "should ignore non-message flows"
427
- {
428
- const nodes = [part("pool1"), inPool("task1", "pool1"), inPool("task2", "pool1")];
429
- expectEmpty("sequence flow ignored by mf rule", run(validateMessageFlowCrossPool, nodes, [edge("flow1", "task1", "task2", { type: "bpmn:SequenceFlow" })]));
430
- }
431
- // FE: "should handle multiple message flows" — 1 finding (only same-pool flow1)
432
- {
433
- const nodes = [part("pool1"), part("pool2"), inPool("task1", "pool1"), inPool("task2", "pool1"), inPool("task3", "pool2")];
434
- const edges = [mf("flow1", "task1", "task2"), mf("flow2", "task1", "task3")];
435
- expectCodeCount("multiple mf, one same-pool", run(validateMessageFlowCrossPool, nodes, edges), "SAME_POOL_MESSAGE_FLOW", 1);
436
- }
437
- // FE: "should handle elements in deeply nested subprocesses"
438
- {
439
- const nodes = [
440
- part("pool1"),
441
- node("subprocess1", "bpmn:SubProcess", {}, { parentId: "pool1" }),
442
- node("subprocess2", "bpmn:SubProcess", {}, { parentId: "subprocess1" }),
443
- inPool("task1", "subprocess2"),
444
- inPool("task2", "subprocess2"),
445
- ];
446
- expectCodeCount("deeply nested same-pool mf", run(validateMessageFlowCrossPool, nodes, [mf("flow1", "task1", "task2")]), "SAME_POOL_MESSAGE_FLOW", 1);
447
- }
448
- }
449
-
450
- // ===========================================================================
451
- // 9. MissingResourceRule (WARNING)
452
- // ===========================================================================
453
- suite("MissingResourceRule");
454
- {
455
- const svc = (id, uipath, label = "Task", type = "bpmn:ServiceTask") => node(id, type, { label, uipath });
456
-
457
- // FE: "ignores nodes without a uipath service type"
458
- expectEmpty("no service type", run(validateMissingResource, [svc("1", {})], []));
459
- // FE: "ignores service types that do not require a bound resource" (ScriptTask)
460
- expectEmpty("scriptTask ignored", run(validateMissingResource, [svc("1", { serviceType: "BPMN.ScriptTask" })], []));
461
- // FE: "flags an agent task when no resource is bound"
462
- expectCodeCount("agent no binding", run(validateMissingResource, [svc("agent-1", { serviceType: "Orchestrator.StartAgentJob", version: "v2" }, "Agent (placeholder)")], []), "MISSING_RESOURCE", 1);
463
- // FE: "does not flag an agent task with a v1 releaseKey binding"
464
- expectEmpty("agent releaseKey binding", run(validateMissingResource, [svc("agent-1", { serviceType: "Orchestrator.StartAgentJob", context: [{ name: "releaseKey", type: "string", value: "binding-id" }] })], []));
465
- // FE: "does not flag a v2 task with a name binding"
466
- expectEmpty("v2 name binding", run(validateMissingResource, [svc("queue-1", { serviceType: "Orchestrator.CreateAndWaitForQueueItem", version: "v2", context: [{ name: "name", value: "MyQueue" }, { name: "folderPath", value: "Shared" }] })], []));
467
- // FE: "flags when context exists but has no releaseKey or name"
468
- expectCodeCount("hitl no binding fields", run(validateMissingResource, [svc("hitl-1", { serviceType: "Actions.HITL", context: [{ name: "taskTitle", type: "string", value: "Approve" }] })], []), "MISSING_RESOURCE", 1);
469
- // FE: "returns one warning per unbound task across multiple nodes" (script-1 not checked)
470
- {
471
- const nodes = [svc("agent-1", { serviceType: "Orchestrator.StartAgentJob" }), svc("queue-1", { serviceType: "Orchestrator.CreateQueueItem" }), svc("script-1", { serviceType: "BPMN.ScriptTask" })];
472
- const f = run(validateMissingResource, nodes, []);
473
- check("one warning per unbound task", f.map((e) => e.elementId).sort().join(",") === "agent-1,queue-1", f.map((e) => e.elementId).join(","));
474
- }
475
- // FE: "flags an unbound call activity action %s" (4 case manager / agentic types)
476
- for (const st of ["Orchestrator.StartAgenticProcess", "Orchestrator.StartAgenticProcessAsync", "Orchestrator.StartCaseMgmtProcess", "Orchestrator.StartCaseMgmtProcessAsync"]) {
477
- expectCodeCount(`call activity ${st}`, run(validateMissingResource, [svc("call-1", { serviceType: st, version: "v2" }, "Call activity", "bpmn:CallActivity")], []), "MISSING_RESOURCE", 1);
478
- }
479
- }
480
-
481
- // ===========================================================================
482
- // 10. MissingRootVariableRule (WARNING)
483
- // Uses validateMissingRootVariables(nodes, canvasState). Our port reads
484
- // canvasState.root.data.uipath.variables (inputOutputs+outputs), resolves a
485
- // node output's `var` against root + enclosing-subprocess scope via
486
- // node.data.parentElement chain & canvasState.diagramsById.
487
- // ===========================================================================
488
- suite("MissingRootVariableRule");
489
- {
490
- const task = (id, outputs, parentElement) => node(id, "bpmn:Task", { label: id, uipath: { outputs }, ...(parentElement ? { parentElement } : {}) });
491
- const subp = (id, variables, parentElement) => node(id, "bpmn:SubProcess", { isExpanded: true, uipath: { variables }, ...(parentElement ? { parentElement } : {}) });
492
- // Build a canvasState whose diagram contains the given nodes and whose root has the given vars.
493
- const cs = (rootInputOutputs = [], rootOutputs = [], diagramNodes = []) =>
494
- canvasState({ rootVariables: { inputs: [], inputOutputs: rootInputOutputs, outputs: rootOutputs }, diagramNodes });
495
-
496
- // FE root 1: missing from root
497
- {
498
- const t = task("Task_1", [{ name: "response", type: "any", var: "var_missing" }]);
499
- expectCodeCount("root: missing var", validateMissingRootVariables([t], cs([], [], [t])), "MISSING_ROOT_VARIABLE", 1);
500
- }
501
- // FE root 2: exists in root inputOutputs
502
- {
503
- const t = task("Task_1", [{ var: "var_1" }]);
504
- expectEmpty("root: var exists", validateMissingRootVariables([t], cs([{ id: "var_1", name: "response", type: "any" }], [], [t])));
505
- }
506
- // FE root 3: one warning per node even if multiple outputs missing
507
- {
508
- const t = task("Task_1", [{ var: "var_a" }, { var: "var_b" }, { var: "var_c" }]);
509
- expectCodeCount("root: one per node", validateMissingRootVariables([t], cs([], [], [t])), "MISSING_ROOT_VARIABLE", 1);
510
- }
511
- // FE root 4: only the unhealthy node flagged
512
- {
513
- const t1 = task("Task_1", [{ var: "var_1" }]);
514
- const t2 = task("Task_2", [{ var: "var_missing" }]);
515
- const f = validateMissingRootVariables([t1, t2], cs([{ id: "var_1" }], [], [t1, t2]));
516
- expectCodeCount("root: only unhealthy", f, "MISSING_ROOT_VARIABLE", 1);
517
- check("root: flagged node is Task_2", f[0]?.elementId === "Task_2", f[0]?.elementId);
518
- }
519
- // FE root 5: root outputs also count
520
- {
521
- const e = task("EndEvent_1", [{ var: "var_out" }]);
522
- expectEmpty("root: outputs count", validateMissingRootVariables([e], cs([], [{ id: "var_out", name: "out", type: "string" }], [e])));
523
- }
524
- // FE subprocess 1: task in subprocess references root-scoped var
525
- {
526
- const sp = subp("SubProcess_1", { inputOutputs: [{ id: "var_sub" }] });
527
- const t = task("Task_1", [{ var: "var_root_only" }], { id: "SubProcess_1", type: "bpmn:SubProcess" });
528
- expectEmpty("sub: resolves at root", validateMissingRootVariables([sp, t], cs([{ id: "var_root_only" }], [], [sp, t])));
529
- }
530
- // FE subprocess 2: missing from all scopes
531
- {
532
- const sp = subp("SubProcess_1", { inputOutputs: [{ id: "var_sub" }] });
533
- const t = task("Task_1", [{ var: "var_nowhere" }], { id: "SubProcess_1", type: "bpmn:SubProcess" });
534
- expectCodeCount("sub: missing everywhere", validateMissingRootVariables([sp, t], cs([], [], [sp, t])), "MISSING_ROOT_VARIABLE", 1);
535
- }
536
- // FE subprocess 3: resolves at subprocess scope
537
- {
538
- const sp = subp("SubProcess_1", { inputOutputs: [{ id: "var_sub" }] });
539
- const t = task("Task_1", [{ var: "var_sub" }], { id: "SubProcess_1", type: "bpmn:SubProcess" });
540
- expectEmpty("sub: resolves at subprocess", validateMissingRootVariables([sp, t], cs([], [], [sp, t])));
541
- }
542
- // FE nested 2: resolves at intermediate subprocess scope
543
- {
544
- const outer = subp("SubProcess_outer", { inputOutputs: [{ id: "var_outer" }] });
545
- const inner = subp("SubProcess_inner", { inputOutputs: [] }, { id: "SubProcess_outer", type: "bpmn:SubProcess" });
546
- const t = task("Task_1", [{ var: "var_outer" }], { id: "SubProcess_inner", type: "bpmn:SubProcess" });
547
- expectEmpty("nested: resolves at outer", validateMissingRootVariables([outer, inner, t], cs([], [], [outer, inner, t])));
548
- }
549
- // FE nested 3: missing from all scopes
550
- {
551
- const outer = subp("SubProcess_outer", { inputOutputs: [{ id: "var_outer" }] });
552
- const inner = subp("SubProcess_inner", { inputOutputs: [{ id: "var_inner" }] }, { id: "SubProcess_outer", type: "bpmn:SubProcess" });
553
- const t = task("Task_1", [{ var: "var_nowhere" }], { id: "SubProcess_inner", type: "bpmn:SubProcess" });
554
- expectCodeCount("nested: missing everywhere", validateMissingRootVariables([outer, inner, t], cs([], [], [outer, inner, t])), "MISSING_ROOT_VARIABLE", 1);
555
- }
556
- }
557
-
558
- // ===========================================================================
559
- // 11. NoAssignmentsRule (WARNING)
560
- // ===========================================================================
561
- suite("NoAssignmentsRule");
562
- {
563
- const en = (cond) => edge("edge-1", "node-1", "node-2", { data: { conditionExpression: cond } });
564
- const nm = (errorMapping) => node("node-1", "bpmn:Activity", { uipath: { errorMapping } });
565
-
566
- expectEmpty("null nodes", validateNoAssignmentsInExpressions(null, []));
567
- expectEmpty("null edges", validateNoAssignmentsInExpressions([], null));
568
- expectEmpty("empty", validateNoAssignmentsInExpressions([], []));
569
- // FE: "should detect assignment in edge condition expression"
570
- expectCodeCount("edge assignment", validateNoAssignmentsInExpressions([], [en("=x = 5")]), "ASSIGNMENT_NOT_ALLOWED", 1);
571
- // FE: "should skip edges with no condition expression"
572
- expectEmpty("edge no cond", validateNoAssignmentsInExpressions([], [edge("edge-1", "node-1", "node-2", { data: {} })]));
573
- // FE: "should not flag comparison operators in edge expressions"
574
- expectEmpty("edge comparison", validateNoAssignmentsInExpressions([], [en("=x === y && z >= 10")]));
575
- // FE: "should detect compound assignment operators (??=)"
576
- expectCodeCount("edge compound assign", validateNoAssignmentsInExpressions([], [en("=x ??= 5")]), "ASSIGNMENT_NOT_ALLOWED", 1);
577
- // FE: "should detect errors across multiple edges"
578
- expectCodeCount("multiple edge assigns", validateNoAssignmentsInExpressions([], [edge("edge-1", "a", "b", { data: { conditionExpression: "=a = 1" } }), edge("edge-2", "c", "d", { data: { conditionExpression: "=b = 2" } })]), "ASSIGNMENT_NOT_ALLOWED", 2);
579
- // FE: "should not check node inputs for assignments"
580
- expectEmpty("node inputs not checked", validateNoAssignmentsInExpressions([node("node-1", "bpmn:Activity", { uipath: { inputs: [{ name: "myInput", var: "var-1", value: "=x = 5", type: "string" }] } })], []));
581
- // FE: "should not check node outputs for assignments"
582
- expectEmpty("node outputs not checked", validateNoAssignmentsInExpressions([node("node-1", "bpmn:Activity", { uipath: { outputs: [{ name: "myOutput", var: "out-1", source: "=x = 5", type: "string" }] } })], []));
583
- // FE: "should produce no errors for clean edge expressions" (arrow fn)
584
- expectEmpty("arrow fn not assignment", validateNoAssignmentsInExpressions([], [en("=() => x + 1")]));
585
- // FE: "should detect assignment in error mapping condition"
586
- expectCodeCount("error mapping assign", validateNoAssignmentsInExpressions([nm([{ id: "ErrorMapping_1", condition: "=x = 5" }])], []), "ASSIGNMENT_NOT_ALLOWED", 1);
587
- // FE: "should skip error mappings with no condition"
588
- expectEmpty("error mapping no cond", validateNoAssignmentsInExpressions([nm([{ id: "ErrorMapping_1" }])], []));
589
- // FE: "should not flag comparison operators in error mapping conditions"
590
- expectEmpty("error mapping comparison", validateNoAssignmentsInExpressions([nm([{ condition: "=x === y" }])], []));
591
- // FE: "should detect assignments across multiple error mappings"
592
- expectCodeCount("multiple error mapping assigns", validateNoAssignmentsInExpressions([nm([{ condition: "=a = 1" }, { condition: "=b = 2" }])], []), "ASSIGNMENT_NOT_ALLOWED", 2);
593
- // FE: "should detect assignments in both edges and error mappings"
594
- expectCodeCount("edge + error mapping assigns", validateNoAssignmentsInExpressions([nm([{ condition: "=x = 1" }])], [en("=y = 2")]), "ASSIGNMENT_NOT_ALLOWED", 2);
595
- }
596
-
597
- // ===========================================================================
598
- // 12. RequiredFieldsRule
599
- // FE marks fields `required:true` inline. Our model recovers `required` from
600
- // the registry by field-name match; here we set it directly (same shape the
601
- // rule consumes) to reproduce the FE scenarios 1:1.
602
- // ===========================================================================
603
- suite("RequiredFieldsRule");
604
- {
605
- const n = (id, uipath, label = "Test Activity") => node(id, "bpmn:ServiceTask", { label, uipath });
606
- expectEmpty("null nodes", validateRequiredFields(null));
607
- // FE: "no required fields empty"
608
- expectEmpty("no empty required", validateRequiredFields([n("1", { context: [{ required: true, name: "field1", value: "value1" }], inputs: [{ required: true, name: "input1", value: "value2" }], outputs: [{ name: "output1", value: "" }] })]));
609
- // FE: "empty required field in context" (2 nodes) → 2 findings
610
- {
611
- const nodes = [n("1", { context: [{ required: true, name: "field1", value: "" }, { required: false, name: "field2", value: "" }] }), n("2", { context: [{ required: true, name: "field1", value: "" }, { required: false, name: "field2", value: "" }] })];
612
- expectCodeCount("context empty required", validateRequiredFields(nodes), "EMPTY_REQUIRED_FIELD", 2);
613
- }
614
- // FE: "empty required field in inputs"
615
- expectCodeCount("inputs empty required", validateRequiredFields([n("1", { inputs: [{ required: true, name: "input1", value: null }, { required: false, name: "input2", value: "" }] })]), "EMPTY_REQUIRED_FIELD", 1);
616
- // FE: "empty required field in outputs"
617
- expectCodeCount("outputs empty required", validateRequiredFields([n("1", { outputs: [{ required: true, name: "output1", value: undefined }, { required: false, name: "output2", value: "" }] })]), "EMPTY_REQUIRED_FIELD", 1);
618
- // FE: "handle nodes without uipath data"
619
- expectEmpty("no uipath", validateRequiredFields([node("1", "bpmn:ServiceTask", {})]));
620
- // FE: "multiple empty required fields in different sections" → 1 finding (per-node)
621
- {
622
- const f = validateRequiredFields([n("1", { context: [{ required: true, name: "field1", value: "" }], inputs: [{ required: true, name: "input1", value: null }], outputs: [{ required: true, name: "output1", value: undefined }] })]);
623
- expectCodeCount("per-node single finding", f, "EMPTY_REQUIRED_FIELD", 1);
624
- }
625
- // PORT PARITY (absent required field): On canvas, every required field exists
626
- // in node data, so an unbound one is present-with-empty-value and the frontend
627
- // fires `field.required && isNilOrEmpty(field.value)` (ValidateRequiredFieldsInData.ts:15-16).
628
- // Offline, an unbound required field is ABSENT from the serialized data; the
629
- // model attaches the serviceType's required-field names as `requiredFieldNames`
630
- // so the rule treats an absent name as present-with-empty (same observable result).
631
- {
632
- // 'method' required by registry but not serialized at all → fires.
633
- const node1 = n("1", { context: [{ name: "url", value: "https://x" }], requiredFieldNames: ["method", "url"] });
634
- expectCodeCount("absent required field fires", validateRequiredFields([node1]), "EMPTY_REQUIRED_FIELD", 1);
635
- }
636
- {
637
- // All registry-required names present and non-empty → no finding.
638
- const node1 = n("1", { context: [{ name: "method", value: "GET" }, { name: "url", value: "https://x" }], requiredFieldNames: ["method", "url"] });
639
- expectEmpty("all required present", validateRequiredFields([node1]));
640
- }
641
- {
642
- // No requiredFieldNames (dynamic IS-connector type, required-ness only known
643
- // after registry enrichment) → conservative: absence not flagged (frontend
644
- // shares this — it also needs the enrichment to know the field is required).
645
- const node1 = n("1", { context: [{ name: "someField", value: "v" }] });
646
- expectEmpty("no requiredFieldNames → conservative", validateRequiredFields([node1]));
647
- }
648
- }
649
-
650
- // ===========================================================================
651
- // 13. SequenceFlowPoolCrossingRule
652
- // ===========================================================================
653
- suite("SequenceFlowPoolCrossingRule");
654
- {
655
- const part = (id) => node(id, "bpmn:Participant");
656
- const inPool = (id, parentId, type = "bpmn:Task") => node(id, type, {}, { parentId });
657
- const sf = (id, s, t) => edge(id, s, t, { type: "bpmn:SequenceFlow" });
658
-
659
- // FE: "should allow sequence flow within same pool"
660
- {
661
- const nodes = [part("pool1"), inPool("task1", "pool1"), inPool("task2", "pool1")];
662
- expectEmpty("same pool sf", run(validateSequenceFlowPoolCrossing, nodes, [sf("flow1", "task1", "task2")]));
663
- }
664
- // FE: "should detect sequence flow crossing pool boundaries"
665
- {
666
- const nodes = [part("pool1"), part("pool2"), inPool("task1", "pool1"), inPool("task2", "pool2")];
667
- expectCodeCount("cross pool sf", run(validateSequenceFlowPoolCrossing, nodes, [sf("flow1", "task1", "task2")]), "CROSSING_POOL_BOUNDARY", 1);
668
- }
669
- // FE: "should handle nested elements in pools"
670
- {
671
- const nodes = [part("pool1"), part("pool2"), inPool("subprocess1", "pool1", "bpmn:SubProcess"), inPool("subprocess2", "pool2", "bpmn:SubProcess"), inPool("task1", "subprocess1"), inPool("task2", "subprocess2")];
672
- expectCodeCount("nested cross pool sf", run(validateSequenceFlowPoolCrossing, nodes, [sf("flow1", "task1", "task2")]), "CROSSING_POOL_BOUNDARY", 1);
673
- }
674
- }
675
-
676
- // ===========================================================================
677
- // 14. SequenceFlowSubProcessCrossingRule
678
- // ===========================================================================
679
- suite("SequenceFlowSubProcessCrossingRule");
680
- {
681
- const sp = (id) => node(id, "bpmn:SubProcess");
682
- const inSp = (id, parentId) => node(id, "bpmn:Task", {}, { parentId });
683
- // FE helper: boundary node has parentId = attachedTo AND data.attachedToId = attachedTo
684
- const boundary = (id, attachedTo) => node(id, "bpmn:BoundaryEvent", { attachedToId: attachedTo }, { parentId: attachedTo });
685
- const sf = (id, s, t) => edge(id, s, t, { type: "bpmn:SequenceFlow" });
686
-
687
- // FE: "should allow sequence flow within same scope"
688
- {
689
- const nodes = [sp("subprocess1"), inSp("task1", "subprocess1"), inSp("task2", "subprocess1")];
690
- expectEmpty("same scope sf", run(validateSequenceFlowSubProcessCrossing, nodes, [sf("flow1", "task1", "task2")]));
691
- }
692
- // FE: "should detect sequence flow crossing subprocess boundary"
693
- {
694
- const nodes = [sp("subprocess1"), sp("subprocess2"), inSp("task1", "subprocess1"), inSp("task2", "subprocess2")];
695
- expectCodeCount("cross subprocess sf", run(validateSequenceFlowSubProcessCrossing, nodes, [sf("flow1", "task1", "task2")]), "CROSSING_SUBPROCESS_BOUNDARY", 1);
696
- }
697
- // FE: "should ignore non-sequence flows"
698
- {
699
- const nodes = [sp("subprocess1"), sp("subprocess2"), inSp("task1", "subprocess1"), inSp("task2", "subprocess2")];
700
- expectEmpty("association ignored", run(validateSequenceFlowSubProcessCrossing, nodes, [edge("association1", "task1", "task2", { type: "bpmn:Association" })]));
701
- }
702
- // FE: "boundary attached to child node connected within same subprocess" — allowed
703
- {
704
- const nodes = [sp("subprocess1"), boundary("boundaryEvent", "task1"), inSp("task1", "subprocess1"), inSp("task2", "subprocess1")];
705
- expectEmpty("boundary on child, same subprocess", run(validateSequenceFlowSubProcessCrossing, nodes, [sf("flow1", "boundaryEvent", "task2")]));
706
- }
707
- // FE: "subprocess-attached boundary connected into the subprocess" — crossing
708
- {
709
- const nodes = [sp("subprocess1"), boundary("boundaryEvent", "subprocess1"), inSp("task1", "subprocess1")];
710
- expectCodeCount("boundary on subprocess into child", run(validateSequenceFlowSubProcessCrossing, nodes, [sf("flow1", "boundaryEvent", "task1")]), "CROSSING_SUBPROCESS_BOUNDARY", 1);
711
- }
712
- // FE: "subprocess-attached boundary connected into a different subprocess" — crossing
713
- {
714
- const nodes = [sp("subprocess1"), boundary("boundaryEvent", "subprocess1"), sp("subprocess2"), inSp("task1", "subprocess2")];
715
- expectCodeCount("boundary on subprocess into other subprocess", run(validateSequenceFlowSubProcessCrossing, nodes, [sf("flow1", "boundaryEvent", "task1")]), "CROSSING_SUBPROCESS_BOUNDARY", 1);
716
- }
717
- }
718
-
719
- // ===========================================================================
720
- // 15. SingleBlankStartEventRule
721
- // Our port keys scopes off bpmn:Process / bpmn:SubProcess container nodes and
722
- // groups start events by parentId. We add a container Process node (the FE tests
723
- // include one via createNode("process1","bpmn:Process")).
724
- // ===========================================================================
725
- suite("SingleBlankStartEventRule");
726
- {
727
- const proc = node("process1", "bpmn:Process");
728
- const start = (id, parentId, ed) => node(id, "bpmn:StartEvent", ed ? { eventDefinition: ed } : {}, { parentId });
729
- const sp = (id) => node(id, "bpmn:SubProcess");
730
-
731
- expectEmpty("null/empty", run(validateSingleBlankStartEvent, [], []));
732
- // FE: "single blank start in root process"
733
- expectEmpty("single blank root", run(validateSingleBlankStartEvent, [proc, start("start1")], []));
734
- // FE: "multiple blank start events in root process" — 1 finding on process1
735
- {
736
- const f = run(validateSingleBlankStartEvent, [proc, start("start1"), start("start2")], []);
737
- expectCodeCount("multiple blank root", f, "MULTIPLE_BLANK_START_EVENTS", 1);
738
- check("blank root elementId process1", f[0]?.elementId === "process1", f[0]?.elementId);
739
- }
740
- // FE: "single blank start in subprocess"
741
- expectEmpty("single blank subprocess", run(validateSingleBlankStartEvent, [proc, sp("subprocess1"), start("start1", "subprocess1")], []));
742
- // FE: "multiple blank start events in subprocess" — 1 finding on subprocess1
743
- {
744
- const f = run(validateSingleBlankStartEvent, [proc, sp("subprocess1"), start("start1", "subprocess1"), start("start2", "subprocess1")], []);
745
- expectCodeCount("multiple blank subprocess", f, "MULTIPLE_BLANK_START_EVENTS", 1);
746
- check("blank subprocess elementId subprocess1", f[0]?.elementId === "subprocess1", f[0]?.elementId);
747
- }
748
- // FE: "should not count non-blank start events"
749
- expectEmpty("non-blank not counted", run(validateSingleBlankStartEvent, [proc, start("start1"), start("start2", undefined, { id: "timer1", type: "bpmn:TimerEventDefinition" })], []));
750
- // FE: "independent scopes"
751
- {
752
- const nodes = [proc, sp("subprocess1"), sp("subprocess2"), start("start1"), start("start2", "subprocess1"), start("start3", "subprocess2")];
753
- expectEmpty("independent scopes one blank each", run(validateSingleBlankStartEvent, nodes, []));
754
- }
755
- }
756
-
757
- // ===========================================================================
758
- // 16. SingleStartEventInEventSubProcessRule
759
- // ===========================================================================
760
- suite("SingleStartEventInEventSubProcessRule");
761
- {
762
- const sp = (id, triggeredByEvent) => node(id, "bpmn:SubProcess", triggeredByEvent ? { triggeredByEvent: true } : {});
763
- const start = (id, parentId, ed) => node(id, "bpmn:StartEvent", ed ? { eventDefinition: ed } : {}, { parentId });
764
-
765
- // FE: "should allow event subprocess with one start event"
766
- expectEmpty("one start in event subprocess", run(validateSingleStartEventInEventSubProcess, [sp("subprocess1", true), start("start1", "subprocess1", { type: "bpmn:TimerEventDefinition" })], []));
767
- // FE: "should allow regular subprocess with multiple start events"
768
- expectEmpty("regular subprocess multiple starts", run(validateSingleStartEventInEventSubProcess, [sp("subprocess1", false), start("start1", "subprocess1"), start("start2", "subprocess1")], []));
769
- // FE: "should detect multiple start events in event subprocess"
770
- {
771
- const nodes = [sp("subprocess1", true), start("start1", "subprocess1", { type: "bpmn:TimerEventDefinition" }), start("start2", "subprocess1", { type: "bpmn:MessageEventDefinition" })];
772
- expectCodeCount("two starts event subprocess", run(validateSingleStartEventInEventSubProcess, nodes, []), "MULTIPLE_START_EVENTS_IN_EVENT_SUBPROCESS", 1);
773
- }
774
- // FE: "...with three start events"
775
- {
776
- const nodes = [sp("subprocess1", true), start("s1", "subprocess1", { type: "bpmn:TimerEventDefinition" }), start("s2", "subprocess1", { type: "bpmn:MessageEventDefinition" }), start("s3", "subprocess1", { type: "bpmn:ErrorEventDefinition" })];
777
- expectCodeCount("three starts event subprocess", run(validateSingleStartEventInEventSubProcess, nodes, []), "MULTIPLE_START_EVENTS_IN_EVENT_SUBPROCESS", 1);
778
- }
779
- // FE: "should not flag event subprocess with no start events"
780
- expectEmpty("no starts event subprocess", run(validateSingleStartEventInEventSubProcess, [sp("subprocess1", true)], []));
781
- }
782
-
783
- // ===========================================================================
784
- // 17. SuperfluousGatewayRule
785
- // ===========================================================================
786
- suite("SuperfluousGatewayRule");
787
- {
788
- expectEmpty("null nodes", validateSuperfluousGateway(null, [], maps([], [])));
789
- expectEmpty("null edges", validateSuperfluousGateway([], null, maps([], [])));
790
- // FE: "should return empty array when no gateways present"
791
- expectEmpty("no gateways", run(validateSuperfluousGateway, [node("1", "bpmn:Task")], []));
792
- // FE: "should detect superfluous gateway with exactly one input and output"
793
- {
794
- const nodes = [node("gateway1", "bpmn:ExclusiveGateway")];
795
- const edges = [edge("e1", "start", "gateway1"), edge("e2", "gateway1", "end")];
796
- expectCodeCount("superfluous 1in1out", run(validateSuperfluousGateway, nodes, edges), "SUPERFLUOUS_GATEWAY", 1);
797
- }
798
- // FE: "should not flag gateway with multiple inputs"
799
- {
800
- const nodes = [node("gateway1", "bpmn:ParallelGateway")];
801
- const edges = [edge("e1", "start1", "gateway1"), edge("e2", "start2", "gateway1"), edge("e3", "gateway1", "end")];
802
- expectEmpty("multiple inputs", run(validateSuperfluousGateway, nodes, edges));
803
- }
804
- // FE: "should not flag gateway with multiple outputs"
805
- {
806
- const nodes = [node("gateway1", "bpmn:InclusiveGateway")];
807
- const edges = [edge("e1", "start", "gateway1"), edge("e2", "gateway1", "end1"), edge("e3", "gateway1", "end2")];
808
- expectEmpty("multiple outputs", run(validateSuperfluousGateway, nodes, edges));
809
- }
810
- // FE: "should handle multiple gateways correctly"
811
- {
812
- const nodes = [node("gateway1", "bpmn:ExclusiveGateway"), node("gateway2", "bpmn:ParallelGateway")];
813
- const edges = [edge("e1", "start", "gateway1"), edge("e2", "gateway1", "gateway2"), edge("e3", "x", "gateway2"), edge("e4", "gateway2", "end1"), edge("e5", "gateway2", "end2")];
814
- // gateway1: 1 in (e1), 1 out (e2) -> superfluous. gateway2: 2 in (e2,e3), 2 out -> fine.
815
- const f = run(validateSuperfluousGateway, nodes, edges);
816
- expectCodeCount("multiple gateways", f, "SUPERFLUOUS_GATEWAY", 1);
817
- check("superfluous is gateway1", f[0]?.elementId === "gateway1", f[0]?.elementId);
818
- }
819
- }
820
-
821
- // ===========================================================================
822
- // 18. TaskTimerRule (WARNING)
823
- // ===========================================================================
824
- suite("TaskTimerRule");
825
- {
826
- const action = (timerValue, label = "My Action", id = "node-1") =>
827
- node(id, "bpmn:ServiceTask", { label, uipath: { serviceType: "actions", context: timerValue !== undefined ? [{ name: "Timer", value: String(timerValue), type: "number" }] : [] } });
828
-
829
- expectEmpty("null nodes", validateTaskTimerRange(null));
830
- expectEmpty("empty nodes", validateTaskTimerRange([]));
831
- // FE: "ignores nodes that are not action service tasks"
832
- expectEmpty("non-action service task", validateTaskTimerRange([node("node-1", "bpmn:ServiceTask", { uipath: { serviceType: "automation", context: [{ name: "Timer", value: "5", type: "number" }] } })]));
833
- // FE: "ignores action nodes with no Timer context entry"
834
- expectEmpty("no Timer entry", validateTaskTimerRange([action(undefined)]));
835
- // FE: "ignores empty Timer value"
836
- expectEmpty("empty Timer", validateTaskTimerRange([action("")]));
837
- // FE: "ignores Timer set to a variable reference (@)"
838
- expectEmpty("@ Timer", validateTaskTimerRange([action("@in_timerMinutes")]));
839
- // FE: "ignores Timer set to an expression (=)"
840
- expectEmpty("= Timer", validateTaskTimerRange([action("=someExpression")]));
841
- // FE: min/max/in-range valid
842
- expectEmpty("min 15", validateTaskTimerRange([action(15)]));
843
- expectEmpty("max 129600", validateTaskTimerRange([action(129600)]));
844
- expectEmpty("in range 60", validateTaskTimerRange([action(60)]));
845
- expectEmpty("numeric string 1440", validateTaskTimerRange([action("1440")]));
846
- // FE: out-of-range warnings
847
- expectCodeCount("below min 14", validateTaskTimerRange([action(14)]), "TASK_TIMER_OUT_OF_RANGE", 1);
848
- expectCodeCount("zero", validateTaskTimerRange([action(0)]), "TASK_TIMER_OUT_OF_RANGE", 1);
849
- expectCodeCount("above max 129601", validateTaskTimerRange([action(129601)]), "TASK_TIMER_OUT_OF_RANGE", 1);
850
- // FE: "only warns on out-of-range action nodes, not valid ones"
851
- expectCodeCount("mixed only out-of-range", validateTaskTimerRange([action(5, "a", "n1"), action(60, "b", "n2"), action(129601, "c", "n3")]), "TASK_TIMER_OUT_OF_RANGE", 2);
852
- // FE: "ignores non-numeric Timer values"
853
- expectEmpty("non-numeric", validateTaskTimerRange([action("not-a-number")]));
854
- }
855
-
856
- // ===========================================================================
857
- // 19. TimerDurationRule
858
- // ===========================================================================
859
- suite("TimerDurationRule");
860
- {
861
- const timer = (timeDuration, id = "node-1", timerType = "timeDuration") =>
862
- node(id, "bpmn:IntermediateCatchEvent", { label: "My Timer", eventDefinition: { timerType, timeDuration } });
863
-
864
- expectEmpty("null nodes", validateTimerDuration(null));
865
- expectEmpty("empty nodes", validateTimerDuration([]));
866
- // FE: "ignores nodes without an eventDefinition"
867
- expectEmpty("no eventDefinition", validateTimerDuration([node("n1", "bpmn:Task", { label: "Task" })]));
868
- // FE: "ignores timer events whose timerType is not timeDuration"
869
- expectEmpty("non-timeDuration timerType", validateTimerDuration([timer("P5W", "n1", "timeDate")]));
870
- // FE: "ignores an empty duration value"
871
- expectEmpty("empty duration", validateTimerDuration([timer("")]));
872
- // FE: "ignores = and @ prefixed"
873
- expectEmpty("= duration", validateTimerDuration([timer("=myVar")]));
874
- expectEmpty("@ duration", validateTimerDuration([timer("@in_duration")]));
875
- // FE: "valid ISO 8601 duration"
876
- expectEmpty("valid PT15M", validateTimerDuration([timer("PT15M")]));
877
- // FE: "malformed -> TIMER_DURATION_INVALID (ERROR)"
878
- expectCodeCount("malformed P5X", validateTimerDuration([timer("P5X")]), "TIMER_DURATION_INVALID", 1);
879
- // FE: "week designator -> TIMER_DURATION_WEEK_UNSUPPORTED (WARNING)"
880
- expectCodeCount("week P5W", validateTimerDuration([timer("P5W")]), "TIMER_DURATION_WEEK_UNSUPPORTED", 1);
881
- }
882
-
883
- // ===========================================================================
884
- // 20. Variable existence — result.X element-local validity
885
- // (VariableUtil.isResultVariableValidForElement:166-178; the non-existing split
886
- // at :758-782; getVariablesInExpression treating an unresolved result ref as
887
- // non-existing at :263). result.X is valid ONLY if X names one of the
888
- // referencing element's OWN outputs; otherwise VARIABLE_DOES_NOT_EXIST fires.
889
- // ===========================================================================
890
- suite("ResultVariableExistence");
891
- {
892
- // FE: "should not return a validation error for result namespace when it matches current element outputs"
893
- // node1 declares output var "outputVar" → result.outputVar is valid.
894
- {
895
- const n1 = node("node1", "bpmn:ServiceTask", { uipath: { outputs: [{ name: "outputVar", var: "outputVar", custom: true, source: "=result.outputVar", type: "string" }] } });
896
- const f = validateVariableExistence([n1], [], new Set());
897
- expectNone("result.X matches own output → no DOES_NOT_EXIST", f, "VARIABLE_DOES_NOT_EXIST");
898
- }
899
- // FE: "should return a validation error for result namespace when it does not match current element outputs"
900
- // node1 has output "outputVar" but references result.missingVar → invalid.
901
- {
902
- const n1 = node("node1", "bpmn:ServiceTask", { uipath: { inputs: [{ name: "i", value: "=result.missingVar" }], outputs: [{ name: "outputVar", var: "outputVar" }] } });
903
- const f = validateVariableExistence([n1], [], new Set());
904
- expectCodeCount("result.X not an output → DOES_NOT_EXIST", f, "VARIABLE_DOES_NOT_EXIST", 1);
905
- }
906
- // FE: getVariablesInExpression "should return the correct result variable in the expression"
907
- // An edge condition has no element-local outputs → result.myVar is non-existing.
908
- {
909
- const e1 = edge("edge1", "a", "b", { data: { conditionExpression: "=result.myVar" } });
910
- const f = validateVariableExistence([], [e1], new Set());
911
- expectCodeCount("edge result.X → DOES_NOT_EXIST", f, "VARIABLE_DOES_NOT_EXIST", 1);
912
- }
913
- }
914
-
915
- // ===========================================================================
916
- // 21. VARIABLE_NOT_SET — flow-order reachability (WARNING)
917
- // Port of validateVariablesInExpression:758-866 (the reachability half). A
918
- // DECLARED variable referenced where no flow path reaches its producer fires
919
- // VARIABLE_NOT_SET. Tested at the model level (allNodes/allEdges/knownIds/cs),
920
- // mirroring validateVariablesInAllNodesAndEdges.
921
- // ===========================================================================
922
- suite("VariableNotSet");
923
- {
924
- // Helper: canvasState with given root vars + diagram nodes/edges.
925
- const csFor = (rootInputOutputs, nodes, edges) => canvasState({ rootVariables: { inputs: [], inputOutputs: rootInputOutputs, outputs: [] }, diagramNodes: nodes, diagramEdges: edges });
926
-
927
- // FE: "should return a validation error if a variable is used before it is set"
928
- // edge node1->node2 references vars.myVar; myVar is declared (known) but not
929
- // produced on any path reaching the edge → exactly 1 VARIABLE_NOT_SET.
930
- {
931
- const n1 = node("node1", "bpmn:Task", {});
932
- const n2 = node("node2", "bpmn:Task", {});
933
- const e1 = edge("edge1", "node1", "node2", { data: { conditionExpression: "=vars.myVar" } });
934
- const known = new Set(["myVar"]); // declared somewhere, but not reachable here
935
- const cs = csFor([], [n1, n2], [e1]);
936
- const f = validateVariableNotSet([n1, n2], [e1], known, cs);
937
- expectCodeCount("used before set → NOT_SET", f, "VARIABLE_NOT_SET", 1);
938
- }
939
- // FE: "should not return a validation error if a variable used is a root variable"
940
- // Same graph but myVar is a ROOT variable → globally available → no NOT_SET.
941
- {
942
- const n1 = node("node1", "bpmn:Task", {});
943
- const n2 = node("node2", "bpmn:Task", {});
944
- const e1 = edge("edge1", "node1", "node2", { data: { conditionExpression: "=vars.myVar" } });
945
- const known = new Set(["myVar"]);
946
- const cs = csFor([{ id: "myVar", name: "myVarName", type: "string" }], [n1, n2], [e1]);
947
- const f = validateVariableNotSet([n1, n2], [e1], known, cs);
948
- expectNone("root variable → no NOT_SET", f, "VARIABLE_NOT_SET");
949
- }
950
- // Reachable producer → no NOT_SET: node A produces var, node B (downstream)
951
- // references it; B's backward walk reaches A.
952
- {
953
- const a = node("A", "bpmn:ServiceTask", { uipath: { outputs: [{ name: "o", var: "produced", custom: true, source: "x", type: "string" }] } });
954
- const b = node("B", "bpmn:ServiceTask", { uipath: { inputs: [{ name: "i", value: "=vars.produced" }] } });
955
- const e1 = edge("A_B", "A", "B", { data: {} });
956
- const known = new Set(["produced"]);
957
- const cs = csFor([], [a, b], [e1]);
958
- const f = validateVariableNotSet([a, b], [e1], known, cs);
959
- expectNone("reachable producer → no NOT_SET", f, "VARIABLE_NOT_SET");
960
- }
961
- // Producer downstream → NOT_SET: node A (upstream) references a var produced by
962
- // node B (downstream), unreachable at A.
963
- {
964
- const a = node("A", "bpmn:ServiceTask", { uipath: { inputs: [{ name: "i", value: "=vars.fromB" }] } });
965
- const b = node("B", "bpmn:ServiceTask", { uipath: { outputs: [{ name: "o", var: "fromB", custom: true, source: "x", type: "string" }] } });
966
- const e1 = edge("A_B", "A", "B", { data: {} });
967
- const known = new Set(["fromB"]);
968
- const cs = csFor([], [a, b], [e1]);
969
- const f = validateVariableNotSet([a, b], [e1], known, cs);
970
- expectCodeCount("downstream producer → NOT_SET at A", f, "VARIABLE_NOT_SET", 1);
971
- }
972
- // Case Management is skipped entirely (VariableUtil.ts:826-828).
973
- {
974
- const n1 = node("node1", "bpmn:Task", {});
975
- const n2 = node("node2", "bpmn:Task", {});
976
- const e1 = edge("edge1", "node1", "node2", { data: { conditionExpression: "=vars.myVar" } });
977
- const cs = csFor([], [n1, n2], [e1]);
978
- const f = validateVariableNotSet([n1, n2], [e1], new Set(["myVar"]), cs, { isCaseManagement: true });
979
- expectEmpty("case management skipped", f);
980
- }
981
- }
982
-
983
- export default results;