@synergenius/flow-weaver 0.33.1 → 0.44.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -226
- package/NOTICE +13 -0
- package/README.md +152 -244
- package/dist/agent/agent-loop.d.ts +4 -2
- package/dist/agent/cli-session.d.ts +3 -3
- package/dist/agent/cli-session.js +511 -438
- package/dist/agent/cli-spawn-config.d.ts +4 -4
- package/dist/agent/gate.d.ts +164 -0
- package/dist/agent/index.d.ts +4 -4
- package/dist/agent/index.js +174 -28
- package/dist/agent/mcp-bridge.d.ts +1 -1
- package/dist/agent/mcp-bridge.js +114 -128
- package/dist/agent/mcp-tool-server.d.ts +2 -2
- package/dist/agent/mcp-tool-server.js +147 -189
- package/dist/agent/profiles.d.ts +69 -0
- package/dist/agent/providers/anthropic.d.ts +2 -4
- package/dist/agent/providers/claude-cli.d.ts +4 -5
- package/dist/agent/providers/openai-compat.d.ts +8 -1
- package/dist/agent/streaming.d.ts +2 -2
- package/dist/agent/types.d.ts +16 -10
- package/dist/api/builder.d.ts +3 -3
- package/dist/api/compile.d.ts +9 -4
- package/dist/api/durable-validation.d.ts +15 -0
- package/dist/api/generate-in-place.d.ts +21 -19
- package/dist/api/generate.d.ts +21 -16
- package/dist/api/generated-module/local-node-functions.d.ts +24 -0
- package/dist/api/generated-module/module-format.d.ts +23 -0
- package/dist/api/generated-module/module-writer.d.ts +34 -0
- package/dist/api/generated-module/node-type-imports.d.ts +39 -0
- package/dist/api/generated-module/preamble.d.ts +16 -0
- package/dist/api/generated-module/workflow-functions.d.ts +29 -0
- package/dist/api/graph-identity.d.ts +39 -0
- package/dist/api/helpers.d.ts +4 -60
- package/dist/api/in-place/built-in-nodes.d.ts +18 -0
- package/dist/api/in-place/function-body.d.ts +21 -0
- package/dist/api/in-place/fw-imports.d.ts +30 -0
- package/dist/api/in-place/macro-coverage.d.ts +14 -0
- package/dist/api/in-place/node-type-functions.d.ts +18 -0
- package/dist/api/in-place/node-type-jsdoc.d.ts +20 -0
- package/dist/api/in-place/orphaned-node-types.d.ts +16 -0
- package/dist/api/in-place/runtime-section.d.ts +16 -0
- package/dist/api/in-place/signature.d.ts +47 -0
- package/dist/api/in-place/source-file.d.ts +19 -0
- package/dist/api/in-place/workflow-jsdoc.d.ts +19 -0
- package/dist/api/index.d.ts +18 -21
- package/dist/api/index.js +259 -53
- package/dist/api/inline-engine.generated.d.ts +3 -0
- package/dist/api/inline-runtime.d.ts +10 -2
- package/dist/api/manipulation/connections.d.ts +1 -1
- package/dist/api/manipulation/index.d.ts +8 -8
- package/dist/api/manipulation/node-types.d.ts +1 -1
- package/dist/api/manipulation/nodes.d.ts +3 -13
- package/dist/api/manipulation/ports.d.ts +1 -1
- package/dist/api/manipulation/scopes.d.ts +1 -1
- package/dist/api/manipulation/workflow.d.ts +1 -1
- package/dist/api/modify-operation.d.ts +0 -2
- package/dist/api/parse.d.ts +22 -1
- package/dist/api/port-references.d.ts +66 -0
- package/dist/api/query.d.ts +18 -2
- package/dist/api/templates.d.ts +1 -1
- package/dist/api/transform.d.ts +1 -1
- package/dist/api/validate.d.ts +1 -1
- package/dist/api/validation-registry.d.ts +2 -2
- package/dist/artifacts/brief.d.ts +43 -0
- package/dist/artifacts/index.d.ts +31 -0
- package/dist/artifacts/pdf.d.ts +19 -0
- package/dist/ast/builder.d.ts +3 -3
- package/dist/ast/index.d.ts +4 -4
- package/dist/ast/index.js +60 -5
- package/dist/ast/serialization-node.d.ts +1 -1
- package/dist/ast/serialization.d.ts +1 -1
- package/dist/ast/types.d.ts +82 -291
- package/dist/ast/workflow-utils.d.ts +4 -4
- package/dist/built-in-nodes/coercion-types.d.ts +1 -1
- package/dist/built-in-nodes/delay.d.ts +3 -1
- package/dist/built-in-nodes/generated-registry.d.ts +1 -1
- package/dist/built-in-nodes/index.d.ts +6 -5
- package/dist/built-in-nodes/index.js +79 -5
- package/dist/built-in-nodes/invoke-workflow.d.ts +2 -1
- package/dist/built-in-nodes/mock-types.d.ts +45 -14
- package/dist/built-in-nodes/sleep.d.ts +12 -0
- package/dist/built-in-nodes/wait-for-agent.d.ts +2 -1
- package/dist/built-in-nodes/wait-for-event.d.ts +2 -1
- package/dist/chevrotain-parser/coerce-parser.d.ts +1 -1
- package/dist/chevrotain-parser/connect-parser.d.ts +1 -1
- package/dist/chevrotain-parser/grammar-diagrams.d.ts +1 -1
- package/dist/chevrotain-parser/index.d.ts +20 -23
- package/dist/chevrotain-parser/node-parser.d.ts +7 -8
- package/dist/chevrotain-parser/parse-line.d.ts +54 -0
- package/dist/chevrotain-parser/tokens.d.ts +0 -17
- package/dist/chevrotain-parser/trigger-cancel-parser.d.ts +6 -1
- package/dist/chunks/chunk-4EUSHAY6.js +298 -0
- package/dist/chunks/chunk-4KDUEOFD.js +197 -0
- package/dist/chunks/chunk-5Y3AIUWY.js +911 -0
- package/dist/chunks/chunk-6KMVP6AU.js +20 -0
- package/dist/chunks/chunk-6PNJORFL.js +128 -0
- package/dist/chunks/chunk-7AAQNGRH.js +2001 -0
- package/dist/chunks/chunk-7YYKTPJ5.js +22705 -0
- package/dist/chunks/chunk-A5MBOFVY.js +33 -0
- package/dist/chunks/chunk-AXNQRVJB.js +18 -0
- package/dist/chunks/chunk-B6HQ6YS5.js +572 -0
- package/dist/chunks/chunk-CY3RNVML.js +296 -0
- package/dist/chunks/chunk-CYHYDLV4.js +653 -0
- package/dist/chunks/chunk-CZBCCK4Y.js +82 -0
- package/dist/chunks/chunk-DCMGQP5V.js +505 -0
- package/dist/chunks/chunk-DIAA66GL.js +72 -0
- package/dist/chunks/chunk-DUO6H5PR.js +20 -0
- package/dist/chunks/chunk-E5WN7IGO.js +125 -0
- package/dist/chunks/chunk-EFGFXXQF.js +184 -0
- package/dist/chunks/chunk-F3RTZV2A.js +2811 -0
- package/dist/chunks/chunk-FMTLP5ZX.js +1397 -0
- package/dist/chunks/chunk-HKZLQJDV.js +79 -0
- package/dist/chunks/chunk-INDEVYEC.js +146 -0
- package/dist/chunks/chunk-JQTF4R5L.js +390 -0
- package/dist/chunks/chunk-KMCAYNUM.js +331 -0
- package/dist/chunks/chunk-KMWCCOUJ.js +1444 -0
- package/dist/chunks/chunk-KU3CLJI2.js +338 -0
- package/dist/chunks/chunk-NDSTGMKR.js +3300 -0
- package/dist/chunks/chunk-NQNLUAPO.js +505 -0
- package/dist/chunks/chunk-O2U2LO57.js +466 -0
- package/dist/chunks/chunk-OOQG7UPP.js +457 -0
- package/dist/chunks/chunk-OZQAW5ZG.js +112 -0
- package/dist/chunks/chunk-P2CVDGHR.js +487 -0
- package/dist/chunks/chunk-P44RIZ7C.js +592 -0
- package/dist/chunks/chunk-PEZCT37T.js +1475 -0
- package/dist/chunks/chunk-PKWSAW6O.js +152 -0
- package/dist/chunks/chunk-Q6MDDZMT.js +4373 -0
- package/dist/chunks/chunk-QDE4Z7KW.js +6 -0
- package/dist/chunks/chunk-QJDAVSNY.js +8 -0
- package/dist/chunks/chunk-QYPORSLO.js +7552 -0
- package/dist/chunks/chunk-R4QGNK34.js +183 -0
- package/dist/chunks/chunk-REEYC73I.js +3002 -0
- package/dist/chunks/chunk-SEWDMQ6Q.js +46 -0
- package/dist/chunks/chunk-TAIUWKZB.js +3057 -0
- package/dist/chunks/chunk-TN4YZ3O7.js +196 -0
- package/dist/chunks/chunk-TRMFB43C.js +143 -0
- package/dist/chunks/chunk-VO4QXG2X.js +1016 -0
- package/dist/chunks/chunk-VP2P3BPA.js +1002 -0
- package/dist/chunks/chunk-VQ7H33J4.js +2176 -0
- package/dist/chunks/chunk-VWA7MCV2.js +105 -0
- package/dist/chunks/chunk-XAV22WD7.js +253 -0
- package/dist/chunks/chunk-YSPBPZDV.js +148 -0
- package/dist/chunks/chunk-ZKEGXO73.js +282 -0
- package/dist/chunks/chunk-ZMGN6F3S.js +4256 -0
- package/dist/chunks/grammar-diagrams-AI7VDXOM.js +14 -0
- package/dist/chunks/index.min-ECJD6GZC.js +37 -0
- package/dist/chunks/manifest-EPTR5MYH.js +21 -0
- package/dist/chunks/openapi-document-6TCGVDUW.js +69 -0
- package/dist/chunks/registry-K2U5KUTY.js +23 -0
- package/dist/chunks/serialization-node-UGY6CFH6.js +38 -0
- package/dist/chunks/validate-GEKSZPIN.js +24 -0
- package/dist/chunks/validation-registry-IQZX3UE3.js +7 -0
- package/dist/chunks/validator-VXFHLPDW.js +26 -0
- package/dist/chunks/workflow-executor-KBGFKHNR.js +36 -0
- package/dist/cli/commands/agents.d.ts +16 -0
- package/dist/cli/commands/artifact.d.ts +10 -0
- package/dist/cli/commands/compile.d.ts +0 -30
- package/dist/cli/commands/console.d.ts +32 -0
- package/dist/cli/commands/context.d.ts +0 -3
- package/dist/cli/commands/describe.js +386 -352
- package/dist/cli/commands/dev.d.ts +9 -4
- package/dist/cli/commands/diagram.d.ts +3 -5
- package/dist/cli/commands/doctor.d.ts +27 -4
- package/dist/cli/commands/doctor.js +3307 -633
- package/dist/cli/commands/export.d.ts +6 -4
- package/dist/cli/commands/grammar.d.ts +0 -3
- package/dist/cli/commands/implement.d.ts +1 -1
- package/dist/cli/commands/init/agent-handoff.d.ts +28 -0
- package/dist/cli/commands/init/config.d.ts +3 -0
- package/dist/cli/commands/init/files.d.ts +12 -0
- package/dist/cli/commands/init/naming.d.ts +13 -0
- package/dist/cli/commands/init/output.d.ts +12 -0
- package/dist/cli/commands/init/setup.d.ts +21 -0
- package/dist/cli/commands/init/types.d.ts +53 -0
- package/dist/cli/commands/init-personas.d.ts +9 -1
- package/dist/cli/commands/init.d.ts +24 -88
- package/dist/cli/commands/market.d.ts +1 -1
- package/dist/cli/commands/mcp-setup.d.ts +1 -4
- package/dist/cli/commands/modify.d.ts +0 -5
- package/dist/cli/commands/openapi.d.ts +9 -11
- package/dist/cli/commands/run.d.ts +0 -4
- package/dist/cli/commands/serve.d.ts +24 -26
- package/dist/cli/commands/status.d.ts +1 -1
- package/dist/cli/exports.d.ts +3 -4
- package/dist/cli/exports.js +124 -23
- package/dist/cli/flow-weaver-agents-H653446S.mjs +81 -0
- package/dist/cli/flow-weaver-artifact-WBFYTW76.mjs +58 -0
- package/dist/cli/flow-weaver-chunk-265CEK74.mjs +2 -0
- package/dist/cli/flow-weaver-chunk-2C7PZCV5.mjs +186 -0
- package/dist/cli/flow-weaver-chunk-3BSYCWPL.mjs +3109 -0
- package/dist/cli/flow-weaver-chunk-3MKUQP3D.mjs +547 -0
- package/dist/cli/flow-weaver-chunk-3ZLMPQTH.mjs +27 -0
- package/dist/cli/flow-weaver-chunk-4DVY73ML.mjs +280 -0
- package/dist/cli/flow-weaver-chunk-54M4KNEL.mjs +200 -0
- package/dist/cli/flow-weaver-chunk-55QMUZIA.mjs +256 -0
- package/dist/cli/flow-weaver-chunk-6ZUJ7LMX.mjs +2003 -0
- package/dist/cli/flow-weaver-chunk-7ET6N32V.mjs +419 -0
- package/dist/cli/flow-weaver-chunk-7G63RR4K.mjs +8880 -0
- package/dist/cli/flow-weaver-chunk-A6M5K3W7.mjs +4418 -0
- package/dist/cli/flow-weaver-chunk-AA3NATMX.mjs +154 -0
- package/dist/cli/flow-weaver-chunk-APX6MQ5A.mjs +5652 -0
- package/dist/cli/flow-weaver-chunk-BHCC5FE5.mjs +17 -0
- package/dist/cli/flow-weaver-chunk-DM4BBRRU.mjs +35 -0
- package/dist/cli/flow-weaver-chunk-DRN7KPWY.mjs +168 -0
- package/dist/cli/flow-weaver-chunk-EKWF27G6.mjs +23 -0
- package/dist/cli/flow-weaver-chunk-EM5HWQ4R.mjs +338 -0
- package/dist/cli/flow-weaver-chunk-FPPPU2DG.mjs +226 -0
- package/dist/cli/flow-weaver-chunk-GAQXZHNO.mjs +3005 -0
- package/dist/cli/flow-weaver-chunk-GBUNNP33.mjs +1329 -0
- package/dist/cli/flow-weaver-chunk-HMAKDE55.mjs +636 -0
- package/dist/cli/flow-weaver-chunk-HQ3ZAN44.mjs +367 -0
- package/dist/cli/flow-weaver-chunk-I4APCXYN.mjs +21442 -0
- package/dist/cli/flow-weaver-chunk-IJJ4JXTL.mjs +2297 -0
- package/dist/cli/flow-weaver-chunk-J7EPZW2I.mjs +33 -0
- package/dist/cli/flow-weaver-chunk-KOEMJHLG.mjs +83 -0
- package/dist/cli/flow-weaver-chunk-M6CBWQKJ.mjs +271 -0
- package/dist/cli/flow-weaver-chunk-MHJ4N652.mjs +1580 -0
- package/dist/cli/flow-weaver-chunk-MKAFQWLP.mjs +202 -0
- package/dist/cli/flow-weaver-chunk-MMV2XGD3.mjs +3291 -0
- package/dist/cli/flow-weaver-chunk-MSI2UJES.mjs +125 -0
- package/dist/cli/flow-weaver-chunk-N767YRAI.mjs +48 -0
- package/dist/cli/flow-weaver-chunk-NQKKWDGF.mjs +56 -0
- package/dist/cli/flow-weaver-chunk-NYZDQYFU.mjs +45 -0
- package/dist/cli/flow-weaver-chunk-OMVWSNHJ.mjs +14 -0
- package/dist/cli/flow-weaver-chunk-PUWZ47H5.mjs +2188 -0
- package/dist/cli/flow-weaver-chunk-QOPRVDES.mjs +46 -0
- package/dist/cli/flow-weaver-chunk-RIWE7YTR.mjs +216 -0
- package/dist/cli/flow-weaver-chunk-S63Q3JIU.mjs +789 -0
- package/dist/cli/flow-weaver-chunk-T7X5A23H.mjs +558 -0
- package/dist/cli/flow-weaver-chunk-TLV3VZUN.mjs +2 -0
- package/dist/cli/flow-weaver-chunk-TS5P3PIN.mjs +194 -0
- package/dist/cli/flow-weaver-chunk-U3EO3X4B.mjs +649 -0
- package/dist/cli/flow-weaver-chunk-UNFS3NQP.mjs +34 -0
- package/dist/cli/flow-weaver-chunk-V6DHWFQG.mjs +2811 -0
- package/dist/cli/flow-weaver-chunk-VXWNLYQU.mjs +9 -0
- package/dist/cli/flow-weaver-chunk-W3YNK26P.mjs +149 -0
- package/dist/cli/flow-weaver-chunk-XG2WKXYZ.mjs +324 -0
- package/dist/cli/flow-weaver-chunk-YLSRZWFK.mjs +2219 -0
- package/dist/cli/flow-weaver-chunk-YVPURWS6.mjs +40 -0
- package/dist/cli/flow-weaver-chunk-Z44JK332.mjs +582 -0
- package/dist/cli/flow-weaver-chunk-Z5ZJPNSY.mjs +517 -0
- package/dist/cli/flow-weaver-chunk-ZQALO25T.mjs +594 -0
- package/dist/cli/flow-weaver-compile-A2CABDSB.mjs +37 -0
- package/dist/cli/flow-weaver-console-6EBHDBTN.mjs +71 -0
- package/dist/cli/flow-weaver-context-ECLYANFF.mjs +17 -0
- package/dist/cli/flow-weaver-context-ZRUMW2KE.mjs +69 -0
- package/dist/cli/flow-weaver-create-WIP4EFNP.mjs +124 -0
- package/dist/cli/flow-weaver-deployment-WJJRK7NO.mjs +14 -0
- package/dist/cli/flow-weaver-describe-XDIFF5LI.mjs +41 -0
- package/dist/cli/flow-weaver-dev-LG2NSQAU.mjs +196 -0
- package/dist/cli/flow-weaver-diagram-3EVQARQE.mjs +52 -0
- package/dist/cli/flow-weaver-diagram-7LR7O4M2.mjs +44 -0
- package/dist/cli/flow-weaver-diff-USF7DJLU.mjs +85 -0
- package/dist/cli/flow-weaver-docs-QU2ZOXKH.mjs +96 -0
- package/dist/cli/flow-weaver-doctor-K447YWHR.mjs +43 -0
- package/dist/cli/flow-weaver-export-LAS6N56Y.mjs +140 -0
- package/dist/cli/flow-weaver-grammar-RIRUS3Q6.mjs +49 -0
- package/dist/cli/flow-weaver-grammar-diagrams-WXRTW5SK.mjs +15 -0
- package/dist/cli/flow-weaver-implement-5JG6BCFZ.mjs +114 -0
- package/dist/cli/flow-weaver-index.min-OR5SIHXD.mjs +39 -0
- package/dist/cli/flow-weaver-init-34YZNPQX.mjs +972 -0
- package/dist/cli/flow-weaver-init-personas-NOGZTQQ2.mjs +48 -0
- package/dist/cli/flow-weaver-manifest-4JNUSEB3.mjs +18 -0
- package/dist/cli/flow-weaver-market-WA4CKHKV.mjs +444 -0
- package/dist/cli/flow-weaver-mcp-setup-O26MGXSD.mjs +22 -0
- package/dist/cli/flow-weaver-migrate-VFVEUTPH.mjs +119 -0
- package/dist/cli/flow-weaver-modify-VM3JP5K6.mjs +97 -0
- package/dist/cli/flow-weaver-openapi-IRBWI3HM.mjs +71 -0
- package/dist/cli/flow-weaver-openapi-document-7N6YMPG3.mjs +30 -0
- package/dist/cli/flow-weaver-pack-commands-OS2QRXAK.mjs +146 -0
- package/dist/cli/flow-weaver-registry-5MLFRPPT.mjs +25 -0
- package/dist/cli/flow-weaver-run-DSTLSTHR.mjs +555 -0
- package/dist/cli/flow-weaver-serialization-node-LE6PCG4M.mjs +50 -0
- package/dist/cli/flow-weaver-serve-NVLCLSOW.mjs +192 -0
- package/dist/cli/flow-weaver-server-7IERLVXE.mjs +2925 -0
- package/dist/cli/flow-weaver-server-KWF4PXYC.mjs +19112 -0
- package/dist/cli/flow-weaver-status-75W2S3YB.mjs +138 -0
- package/dist/cli/flow-weaver-strip-AZPXUYVA.mjs +79 -0
- package/dist/cli/flow-weaver-templates-DSNMB6K7.mjs +72 -0
- package/dist/cli/flow-weaver-validate-A4UWDQN6.mjs +19 -0
- package/dist/cli/flow-weaver-validate-GRBZ5W4C.mjs +296 -0
- package/dist/cli/flow-weaver-validation-registry-BINGUNXX.mjs +9 -0
- package/dist/cli/flow-weaver-validator-TY56CI42.mjs +21 -0
- package/dist/cli/flow-weaver-watch-OPPERXL6.mjs +114 -0
- package/dist/cli/flow-weaver-workflow-executor-6AHYPXAN.mjs +26 -0
- package/dist/cli/flow-weaver.mjs +3557 -89498
- package/dist/cli/index.d.ts +5 -2
- package/dist/cli/pack-commands-needed.d.ts +12 -0
- package/dist/cli/program.d.ts +14 -0
- package/dist/cli/templates/ai/mock-provider.d.ts +1 -1
- package/dist/cli/templates/index.d.ts +1 -8
- package/dist/cli/templates/nodes/agent-router.d.ts +1 -1
- package/dist/cli/templates/nodes/aggregator.d.ts +1 -1
- package/dist/cli/templates/nodes/conversation-memory.d.ts +1 -1
- package/dist/cli/templates/nodes/http.d.ts +1 -1
- package/dist/cli/templates/nodes/human-approval.d.ts +1 -1
- package/dist/cli/templates/nodes/json-extractor.d.ts +1 -1
- package/dist/cli/templates/nodes/llm-call.d.ts +1 -1
- package/dist/cli/templates/nodes/prompt-template.d.ts +1 -1
- package/dist/cli/templates/nodes/rag-retriever.d.ts +1 -1
- package/dist/cli/templates/nodes/tool-executor.d.ts +1 -1
- package/dist/cli/templates/nodes/transformer.d.ts +1 -1
- package/dist/cli/templates/nodes/validator.d.ts +1 -1
- package/dist/cli/templates/shared/approval-types.d.ts +1 -1
- package/dist/cli/templates/shared/case.d.ts +14 -0
- package/dist/cli/templates/shared/llm-types.d.ts +4 -4
- package/dist/cli/templates/workflows/aggregator.d.ts +1 -1
- package/dist/cli/templates/workflows/ai-agent.d.ts +1 -1
- package/dist/cli/templates/workflows/ai-chat.d.ts +1 -1
- package/dist/cli/templates/workflows/ai-rag.d.ts +1 -1
- package/dist/cli/templates/workflows/ai-react.d.ts +1 -1
- package/dist/cli/templates/workflows/approval.d.ts +10 -0
- package/dist/cli/templates/workflows/conditional.d.ts +2 -2
- package/dist/cli/templates/workflows/error-handler.d.ts +2 -2
- package/dist/cli/templates/workflows/foreach.d.ts +1 -1
- package/dist/cli/templates/workflows/sequential.d.ts +1 -1
- package/dist/cli/templates/workflows/webhook.d.ts +1 -1
- package/dist/cli/utils/interactive.d.ts +6 -0
- package/dist/cli/utils/json-option.d.ts +8 -0
- package/dist/cli/utils/logger.d.ts +2 -0
- package/dist/compiler/durable-source-proof.d.ts +23 -0
- package/dist/compiler/executable-artifact.d.ts +29 -0
- package/dist/compiler/index.d.ts +4 -0
- package/dist/compiler/index.js +36 -0
- package/dist/console/app.js +106 -0
- package/dist/console/assets/synergenius.svg +18 -0
- package/dist/console/author.d.ts +32 -0
- package/dist/console/cli-catalog.d.ts +21 -0
- package/dist/console/cli-run.d.ts +35 -0
- package/dist/console/cli-run.js +46 -0
- package/dist/console/debug.d.ts +67 -0
- package/dist/console/diff-view.d.ts +96 -0
- package/dist/console/export.d.ts +36 -0
- package/dist/console/git.d.ts +27 -0
- package/dist/console/index.d.ts +4 -0
- package/dist/console/index.html +16 -0
- package/dist/console/index.js +203 -0
- package/dist/console/packs.d.ts +100 -0
- package/dist/console/request-guard.d.ts +10 -0
- package/dist/console/respond.d.ts +16 -0
- package/dist/console/router.d.ts +64 -0
- package/dist/console/routes-agents.d.ts +14 -0
- package/dist/console/routes-project.d.ts +3 -0
- package/dist/console/routes-runs.d.ts +3 -0
- package/dist/console/routes-services.d.ts +7 -0
- package/dist/console/routes-tools.d.ts +3 -0
- package/dist/console/runs.d.ts +69 -0
- package/dist/console/scan.d.ts +49 -0
- package/dist/console/schema.d.ts +74 -0
- package/dist/console/server.d.ts +34 -0
- package/dist/console/server.js +43264 -0
- package/dist/console/services.d.ts +119 -0
- package/dist/console/source.d.ts +23 -0
- package/dist/console/status.d.ts +68 -0
- package/dist/console/styles.css +1023 -0
- package/dist/console/terminals.d.ts +22 -0
- package/dist/console/workflow-view.d.ts +153 -0
- package/dist/constants.d.ts +5 -1
- package/dist/constants.js +56 -167
- package/dist/context/index.d.ts +10 -0
- package/dist/context/index.js +14 -191
- package/dist/coordinator/agent-gate.d.ts +107 -0
- package/dist/coordinator/bundle-digest.d.ts +20 -0
- package/dist/coordinator/clock-tick.d.ts +4 -0
- package/dist/coordinator/effect-receipts.d.ts +10 -0
- package/dist/coordinator/errors.d.ts +31 -0
- package/dist/coordinator/file-store.d.ts +3 -0
- package/dist/coordinator/gate-labeling.d.ts +33 -0
- package/dist/coordinator/gate-resolution.d.ts +28 -0
- package/dist/coordinator/index.d.ts +12 -0
- package/dist/coordinator/index.js +107 -0
- package/dist/coordinator/memory-store.d.ts +3 -0
- package/dist/coordinator/params.d.ts +18 -0
- package/dist/coordinator/run-annotations.d.ts +6 -0
- package/dist/coordinator/run-context.d.ts +11 -0
- package/dist/coordinator/run-ending.d.ts +5 -0
- package/dist/coordinator/run-outcome.d.ts +31 -0
- package/dist/coordinator/run-resume.d.ts +6 -0
- package/dist/coordinator/run-start.d.ts +4 -0
- package/dist/coordinator/run-store.d.ts +275 -0
- package/dist/coordinator/run-trace.d.ts +41 -0
- package/dist/coordinator/run-views.d.ts +12 -0
- package/dist/coordinator/runs-dir.d.ts +26 -0
- package/dist/coordinator/store.d.ts +67 -0
- package/dist/coordinator/time.d.ts +39 -0
- package/dist/coordinator/workflow-selection.d.ts +6 -0
- package/dist/deployment/index.d.ts +11 -16
- package/dist/deployment/index.js +541 -50
- package/dist/deployment/targets/base.d.ts +11 -13
- package/dist/deployment/targets/openapi-parts.d.ts +92 -0
- package/dist/diagram/arms.d.ts +70 -0
- package/dist/diagram/ascii-renderer.d.ts +1 -1
- package/dist/diagram/geometry.d.ts +22 -29
- package/dist/diagram/graph/bounds.d.ts +30 -0
- package/dist/diagram/graph/metrics.d.ts +21 -0
- package/dist/diagram/graph/nodes.d.ts +33 -0
- package/dist/diagram/graph/placement.d.ts +22 -0
- package/dist/diagram/graph/ports.d.ts +23 -0
- package/dist/diagram/graph/routing.d.ts +40 -0
- package/dist/diagram/graph/scopes.d.ts +30 -0
- package/dist/diagram/index.d.ts +15 -23
- package/dist/diagram/index.js +632 -111
- package/dist/diagram/labels.d.ts +12 -0
- package/dist/diagram/lanes.d.ts +93 -0
- package/dist/diagram/layout.d.ts +1 -1
- package/dist/diagram/material-symbols.d.ts +7 -0
- package/dist/diagram/orthogonal-router.d.ts +15 -51
- package/dist/diagram/process-view.d.ts +79 -0
- package/dist/diagram/spine.d.ts +25 -0
- package/dist/diagram/theme.d.ts +3 -5
- package/dist/diagram/types.d.ts +6 -20
- package/dist/diff/index.js +53 -9
- package/dist/diff/types.d.ts +1 -5
- package/dist/doc-metadata/extractors/annotations.d.ts +0 -4
- package/dist/doc-metadata/extractors/cli-commands.d.ts +2 -1
- package/dist/doc-metadata/extractors/core-metadata.d.ts +19 -4
- package/dist/doc-metadata/extractors/error-codes.d.ts +1 -1
- package/dist/doc-metadata/extractors/mcp-tools.d.ts +7 -3
- package/dist/doc-metadata/index.d.ts +1 -2
- package/dist/doc-metadata/index.js +2368 -9
- package/dist/doc-metadata/types.d.ts +7 -24
- package/dist/docs/guide.d.ts +33 -0
- package/dist/docs/index.d.ts +7 -4
- package/dist/docs/index.js +298 -298
- package/dist/docs/pack-topics.d.ts +18 -0
- package/dist/editor-completions/annotationValues.d.ts +1 -1
- package/dist/editor-completions/contextParser.d.ts +3 -2
- package/dist/editor-completions/dataTypes.d.ts +1 -1
- package/dist/editor-completions/goToDefinition.d.ts +1 -1
- package/dist/editor-completions/index.d.ts +8 -8
- package/dist/editor-completions/index.js +1244 -175
- package/dist/editor-completions/jsDocAnnotations.d.ts +1 -1
- package/dist/editor-completions/modifierCompletions.d.ts +1 -1
- package/dist/export/index.d.ts +7 -1
- package/dist/generated-branding.js +8 -21
- package/dist/generated-version.d.ts +1 -1
- package/dist/generated-version.js +7 -3
- package/dist/generator/annotation-generator.d.ts +84 -0
- package/dist/generator/async-detection.d.ts +1 -1
- package/dist/{body-generator.d.ts → generator/body-generator.d.ts} +7 -3
- package/dist/generator/code-utils.d.ts +15 -60
- package/dist/generator/connection-reads.d.ts +94 -0
- package/dist/generator/control-flow-plan.d.ts +74 -0
- package/dist/generator/control-flow.d.ts +1 -1
- package/dist/generator/exit-assembly.d.ts +11 -0
- package/dist/generator/index.d.ts +4 -5
- package/dist/generator/index.js +34 -11
- package/dist/generator/input-port-values.d.ts +22 -0
- package/dist/generator/{scope-function-generator.d.ts → node-arguments.d.ts} +76 -1
- package/dist/generator/node-invocation.d.ts +74 -0
- package/dist/{node-types-generator.d.ts → generator/node-types-generator.d.ts} +3 -2
- package/dist/generator/scope-closure.d.ts +23 -0
- package/dist/generator/scoped-child.d.ts +49 -0
- package/dist/{sugar-optimizer.d.ts → generator/sugar-optimizer.d.ts} +1 -1
- package/dist/generator/unified.d.ts +14 -2
- package/dist/generator/workflow-generator.d.ts +37 -0
- package/dist/index.d.ts +29 -26
- package/dist/index.js +1322 -92
- package/dist/jsdoc-port-sync/apply-diff.d.ts +15 -0
- package/dist/jsdoc-port-sync/callback-signature.d.ts +17 -0
- package/dist/jsdoc-port-sync/diff.d.ts +5 -7
- package/dist/jsdoc-port-sync/incomplete-lines.d.ts +41 -0
- package/dist/jsdoc-port-sync/index.d.ts +11 -11
- package/dist/jsdoc-port-sync/index.js +88 -45
- package/dist/jsdoc-port-sync/jsdoc-to-signature.d.ts +66 -0
- package/dist/jsdoc-port-sync/port-parser.d.ts +6 -24
- package/dist/jsdoc-port-sync/port-tag-placement.d.ts +55 -0
- package/dist/jsdoc-port-sync/scoped-ports.d.ts +21 -0
- package/dist/jsdoc-port-sync/signature-parser.d.ts +8 -1
- package/dist/jsdoc-port-sync/signature-to-jsdoc.d.ts +77 -0
- package/dist/jsdoc-port-sync/sync.d.ts +4 -1
- package/dist/marketplace/index.d.ts +5 -3
- package/dist/marketplace/index.js +62 -10
- package/dist/marketplace/install.d.ts +24 -0
- package/dist/marketplace/manifest.d.ts +1 -1
- package/dist/marketplace/npmrc.d.ts +24 -0
- package/dist/marketplace/registry.d.ts +46 -11
- package/dist/marketplace/types.d.ts +41 -24
- package/dist/marketplace/validator.d.ts +1 -1
- package/dist/mcp/debug-session.d.ts +2 -4
- package/dist/mcp/dist-imports.d.ts +12 -0
- package/dist/mcp/response-utils.d.ts +11 -9
- package/dist/mcp/server.d.ts +0 -1
- package/dist/mcp/tools-context.d.ts +11 -0
- package/dist/mcp/tools-diagram.d.ts +1 -2
- package/dist/mcp/tools-export.d.ts +2 -2
- package/dist/mcp/tools-marketplace.d.ts +1 -1
- package/dist/mcp/tools-run.d.ts +17 -0
- package/dist/mcp/tools-workflow.d.ts +3 -0
- package/dist/mcp/types.d.ts +4 -14
- package/dist/mcp/workflow-executor.d.ts +57 -19
- package/dist/npm-packages.d.ts +1 -1
- package/dist/npm-packages.js +10 -473
- package/dist/parser/annotation-parser.d.ts +88 -0
- package/dist/parser/annotation-suggestion.d.ts +23 -0
- package/dist/parser/durable-effect-contract.d.ts +10 -0
- package/dist/parser/expression-references.d.ts +101 -0
- package/dist/parser/external-node-types.d.ts +69 -0
- package/dist/{function-like.d.ts → parser/function-like.d.ts} +10 -3
- package/dist/parser/generated-sections.d.ts +25 -0
- package/dist/parser/import-resolution.d.ts +67 -0
- package/dist/parser/import-stub.d.ts +29 -0
- package/dist/parser/jsdoc/config-types.d.ts +209 -0
- package/dist/parser/jsdoc/graph-tags.d.ts +54 -0
- package/dist/parser/jsdoc/node-type-block.d.ts +23 -0
- package/dist/parser/jsdoc/parse-line-once.d.ts +11 -0
- package/dist/parser/jsdoc/port-tags.d.ts +42 -0
- package/dist/parser/jsdoc/runtime-tags.d.ts +65 -0
- package/dist/parser/jsdoc/signature-types.d.ts +52 -0
- package/dist/parser/jsdoc/workflow-block.d.ts +22 -0
- package/dist/parser/jsdoc-parser.d.ts +23 -0
- package/dist/parser/macro-expansion.d.ts +80 -0
- package/dist/parser/module-resolution.d.ts +38 -0
- package/dist/parser/node-inference.d.ts +39 -0
- package/dist/parser/npm-node-types.d.ts +24 -0
- package/dist/parser/pack-handlers.d.ts +12 -0
- package/dist/parser/path-data-resolution.d.ts +75 -0
- package/dist/parser/port-inference.d.ts +15 -0
- package/dist/{resolve-package-types.d.ts → parser/resolve-package-types.d.ts} +4 -0
- package/dist/parser/serialize-deploy-annotations.d.ts +19 -0
- package/dist/parser/tag-registry.d.ts +22 -0
- package/dist/parser/workflow-extraction.d.ts +39 -0
- package/dist/runtime/ExecutionContext.d.ts +87 -99
- package/dist/runtime/continuation-core.d.ts +147 -0
- package/dist/runtime/continuation.d.ts +48 -0
- package/dist/runtime/debug-controller.d.ts +7 -22
- package/dist/runtime/durable-execution.d.ts +176 -0
- package/dist/runtime/events.d.ts +16 -1
- package/dist/runtime/executable-module-contract.d.ts +16 -0
- package/dist/runtime/index.d.ts +13 -10
- package/dist/runtime/index.js +947 -9
- package/dist/runtime/strict-json.d.ts +15 -0
- package/dist/server/access.d.ts +12 -0
- package/dist/server/api.d.ts +126 -0
- package/dist/server/callback-delivery.d.ts +62 -0
- package/dist/server/callback-url.d.ts +44 -0
- package/dist/server/context.d.ts +35 -0
- package/dist/server/http-error.d.ts +10 -0
- package/dist/server/index.d.ts +7 -1
- package/dist/server/index.js +125 -6
- package/dist/server/openapi-document.d.ts +33 -0
- package/dist/server/openapi.d.ts +32 -0
- package/dist/server/respond.d.ts +35 -0
- package/dist/server/route-params.d.ts +17 -0
- package/dist/server/route-plan.d.ts +41 -0
- package/dist/server/routes-catalog.d.ts +5 -0
- package/dist/server/routes-declared.d.ts +12 -0
- package/dist/server/routes-runs.d.ts +8 -0
- package/dist/server/run-driver.d.ts +58 -0
- package/dist/server/run-view.d.ts +26 -0
- package/dist/server/transport.d.ts +35 -0
- package/dist/server/types.d.ts +143 -52
- package/dist/server/webhook-server.d.ts +12 -38
- package/dist/server/workflow-registry.d.ts +7 -4
- package/dist/service-registry.d.ts +49 -0
- package/dist/service-registry.js +123 -0
- package/dist/testing/assertions.d.ts +2 -2
- package/dist/testing/index.d.ts +14 -13
- package/dist/testing/index.js +582 -24
- package/dist/testing/mock-approval.d.ts +3 -5
- package/dist/testing/mock-llm.d.ts +2 -3
- package/dist/testing/recorder.d.ts +5 -6
- package/dist/testing/replayer.d.ts +6 -7
- package/dist/testing/run-store-check.d.ts +3 -0
- package/dist/testing/token-tracker.d.ts +2 -2
- package/dist/{type-mappings.d.ts → types/type-mappings.d.ts} +13 -1
- package/dist/utils/error-utils.d.ts +4 -2
- package/dist/utils/port-ordering.d.ts +2 -2
- package/dist/utils/port-tag-utils.d.ts +1 -1
- package/dist/validation/agent-detection.d.ts +17 -5
- package/dist/validation/agent-rules.d.ts +6 -7
- package/dist/validation/core-rules.d.ts +49 -0
- package/dist/validation/design-rules.d.ts +9 -3
- package/dist/validation/rule-registry.d.ts +3 -3
- package/dist/validation/rules/connections.d.ts +27 -0
- package/dist/validation/rules/context.d.ts +11 -0
- package/dist/validation/rules/cycles.d.ts +17 -0
- package/dist/validation/rules/data-flow.d.ts +19 -0
- package/dist/validation/rules/scope-topology.d.ts +35 -0
- package/dist/validation/rules/type-compatibility.d.ts +30 -0
- package/dist/validation/type-checker.d.ts +39 -0
- package/dist/validation/validator-helpers.d.ts +31 -0
- package/dist/validation/validator.d.ts +30 -0
- package/docs/reference/advanced-annotations.md +277 -60
- package/docs/reference/built-in-nodes.md +164 -94
- package/docs/reference/cancellation.md +44 -0
- package/docs/reference/cli-reference.md +252 -234
- package/docs/reference/compilation.md +36 -109
- package/docs/reference/concepts.md +80 -63
- package/docs/reference/console.md +169 -0
- package/docs/reference/debugging.md +26 -57
- package/docs/reference/deployment.md +217 -143
- package/docs/reference/durable-gates.md +445 -0
- package/docs/reference/error-codes.md +90 -43
- package/docs/reference/export-interface.md +91 -26
- package/docs/reference/iterative-development.md +50 -28
- package/docs/reference/jsdoc-grammar.md +66 -311
- package/docs/reference/library.md +250 -0
- package/docs/reference/marketplace.md +301 -152
- package/docs/reference/mcp-tools.md +102 -0
- package/docs/reference/node-conversion.md +84 -59
- package/docs/reference/orientation.md +68 -0
- package/docs/reference/scaffold.md +5 -4
- package/docs/reference/tutorial.md +106 -166
- package/docs/reference/visual-reference.md +1 -1
- package/package.json +85 -50
- package/dist/agent/agent-loop.js +0 -156
- package/dist/agent/cli-spawn-config.js +0 -65
- package/dist/agent/device-connection.d.ts +0 -79
- package/dist/agent/device-connection.js +0 -184
- package/dist/agent/env-allowlist.js +0 -60
- package/dist/agent/providers/anthropic.js +0 -198
- package/dist/agent/providers/claude-cli.js +0 -161
- package/dist/agent/providers/openai-compat.js +0 -205
- package/dist/agent/providers/platform.d.ts +0 -23
- package/dist/agent/providers/platform.js +0 -132
- package/dist/agent/streaming.js +0 -186
- package/dist/agent/types.js +0 -20
- package/dist/annotation-generator.d.ts +0 -50
- package/dist/annotation-generator.js +0 -743
- package/dist/api/builder.js +0 -345
- package/dist/api/command-runner.js +0 -787
- package/dist/api/compile.js +0 -148
- package/dist/api/extract-types.js +0 -57
- package/dist/api/generate-in-place.js +0 -1477
- package/dist/api/generate.js +0 -514
- package/dist/api/helpers.js +0 -285
- package/dist/api/inline-runtime.js +0 -526
- package/dist/api/manipulation/connections.js +0 -151
- package/dist/api/manipulation/index.js +0 -41
- package/dist/api/manipulation/node-types.js +0 -200
- package/dist/api/manipulation/nodes.js +0 -355
- package/dist/api/manipulation/ports.js +0 -228
- package/dist/api/manipulation/scopes.js +0 -156
- package/dist/api/manipulation/workflow.js +0 -116
- package/dist/api/modify-operation.js +0 -177
- package/dist/api/parse.js +0 -115
- package/dist/api/patterns.d.ts +0 -112
- package/dist/api/patterns.js +0 -303
- package/dist/api/query.js +0 -840
- package/dist/api/templates.js +0 -117
- package/dist/api/transform.js +0 -40
- package/dist/api/validate.js +0 -64
- package/dist/api/validation-registry.js +0 -10
- package/dist/api/workflow-file-operations.js +0 -180
- package/dist/ast/builder.js +0 -395
- package/dist/ast/serialization-node.js +0 -30
- package/dist/ast/serialization.js +0 -134
- package/dist/ast/types.js +0 -2
- package/dist/ast/workflow-utils.js +0 -114
- package/dist/body-generator.js +0 -35
- package/dist/built-in-nodes/coercion-types.js +0 -61
- package/dist/built-in-nodes/delay.js +0 -29
- package/dist/built-in-nodes/generated-registry.js +0 -299
- package/dist/built-in-nodes/invoke-workflow.js +0 -36
- package/dist/built-in-nodes/mock-types.js +0 -42
- package/dist/built-in-nodes/wait-for-agent.js +0 -31
- package/dist/built-in-nodes/wait-for-event.js +0 -25
- package/dist/chevrotain-parser/coerce-parser.js +0 -103
- package/dist/chevrotain-parser/connect-parser.js +0 -136
- package/dist/chevrotain-parser/fan-parser.js +0 -149
- package/dist/chevrotain-parser/grammar-diagrams.js +0 -273
- package/dist/chevrotain-parser/index.js +0 -31
- package/dist/chevrotain-parser/map-parser.js +0 -130
- package/dist/chevrotain-parser/node-parser.js +0 -558
- package/dist/chevrotain-parser/path-parser.js +0 -140
- package/dist/chevrotain-parser/port-parser.js +0 -519
- package/dist/chevrotain-parser/position-parser.d.ts +0 -20
- package/dist/chevrotain-parser/position-parser.js +0 -83
- package/dist/chevrotain-parser/scope-parser.js +0 -104
- package/dist/chevrotain-parser/tokens.js +0 -429
- package/dist/chevrotain-parser/trigger-cancel-parser.js +0 -291
- package/dist/cli/commands/account.d.ts +0 -4
- package/dist/cli/commands/account.js +0 -50
- package/dist/cli/commands/ai-credentials.d.ts +0 -12
- package/dist/cli/commands/ai-credentials.js +0 -95
- package/dist/cli/commands/apikey.d.ts +0 -4
- package/dist/cli/commands/apikey.js +0 -64
- package/dist/cli/commands/auth.d.ts +0 -9
- package/dist/cli/commands/auth.js +0 -255
- package/dist/cli/commands/compile.js +0 -331
- package/dist/cli/commands/connect.d.ts +0 -4
- package/dist/cli/commands/connect.js +0 -163
- package/dist/cli/commands/context.js +0 -51
- package/dist/cli/commands/create.js +0 -139
- package/dist/cli/commands/deploy.d.ts +0 -6
- package/dist/cli/commands/deploy.js +0 -74
- package/dist/cli/commands/dev.js +0 -227
- package/dist/cli/commands/diagram.js +0 -39
- package/dist/cli/commands/diff.js +0 -57
- package/dist/cli/commands/docs.js +0 -74
- package/dist/cli/commands/export.js +0 -153
- package/dist/cli/commands/grammar.js +0 -40
- package/dist/cli/commands/implement.js +0 -91
- package/dist/cli/commands/init-personas.js +0 -541
- package/dist/cli/commands/init.js +0 -797
- package/dist/cli/commands/market.js +0 -440
- package/dist/cli/commands/mcp-setup.js +0 -433
- package/dist/cli/commands/migrate.js +0 -91
- package/dist/cli/commands/modify.js +0 -58
- package/dist/cli/commands/openapi.js +0 -71
- package/dist/cli/commands/org.d.ts +0 -8
- package/dist/cli/commands/org.js +0 -136
- package/dist/cli/commands/pattern.d.ts +0 -34
- package/dist/cli/commands/pattern.js +0 -186
- package/dist/cli/commands/plugin.d.ts +0 -16
- package/dist/cli/commands/plugin.js +0 -176
- package/dist/cli/commands/run.js +0 -742
- package/dist/cli/commands/serve.js +0 -93
- package/dist/cli/commands/status.js +0 -123
- package/dist/cli/commands/strip.js +0 -61
- package/dist/cli/commands/templates.js +0 -58
- package/dist/cli/commands/validate.js +0 -267
- package/dist/cli/commands/watch.js +0 -71
- package/dist/cli/config/credentials.d.ts +0 -15
- package/dist/cli/config/credentials.js +0 -43
- package/dist/cli/config/platform-client.d.ts +0 -123
- package/dist/cli/config/platform-client.js +0 -248
- package/dist/cli/env-setup.js +0 -12
- package/dist/cli/index.js +0 -850
- package/dist/cli/pack-commands.js +0 -122
- package/dist/cli/postinstall.d.ts +0 -16
- package/dist/cli/postinstall.js +0 -119
- package/dist/cli/templates/ai/mock-provider.js +0 -64
- package/dist/cli/templates/ai/types.js +0 -5
- package/dist/cli/templates/approvals/index.d.ts +0 -15
- package/dist/cli/templates/approvals/index.js +0 -241
- package/dist/cli/templates/index.js +0 -123
- package/dist/cli/templates/nodes/agent-router.js +0 -114
- package/dist/cli/templates/nodes/aggregator.js +0 -63
- package/dist/cli/templates/nodes/conversation-memory.js +0 -85
- package/dist/cli/templates/nodes/http.js +0 -80
- package/dist/cli/templates/nodes/human-approval.js +0 -109
- package/dist/cli/templates/nodes/json-extractor.js +0 -119
- package/dist/cli/templates/nodes/llm-call.js +0 -106
- package/dist/cli/templates/nodes/prompt-template.js +0 -52
- package/dist/cli/templates/nodes/rag-retriever.js +0 -128
- package/dist/cli/templates/nodes/tool-executor.js +0 -108
- package/dist/cli/templates/nodes/transformer.js +0 -68
- package/dist/cli/templates/nodes/validator.js +0 -62
- package/dist/cli/templates/pack-loader.js +0 -58
- package/dist/cli/templates/providers/index.js +0 -239
- package/dist/cli/templates/shared/approval-types.js +0 -31
- package/dist/cli/templates/shared/llm-types.js +0 -109
- package/dist/cli/templates/workflows/aggregator.js +0 -101
- package/dist/cli/templates/workflows/ai-agent.js +0 -326
- package/dist/cli/templates/workflows/ai-chat.js +0 -167
- package/dist/cli/templates/workflows/ai-rag.js +0 -184
- package/dist/cli/templates/workflows/ai-react.js +0 -293
- package/dist/cli/templates/workflows/conditional.js +0 -139
- package/dist/cli/templates/workflows/error-handler.js +0 -145
- package/dist/cli/templates/workflows/foreach.js +0 -140
- package/dist/cli/templates/workflows/sequential.js +0 -200
- package/dist/cli/templates/workflows/webhook.js +0 -158
- package/dist/cli/utils/cli-helpers.d.ts +0 -44
- package/dist/cli/utils/cli-helpers.js +0 -99
- package/dist/cli/utils/logger.js +0 -126
- package/dist/cli/utils/parse-int-strict.js +0 -17
- package/dist/cli/utils/safe-write.js +0 -54
- package/dist/deployment/config/defaults.d.ts +0 -29
- package/dist/deployment/config/defaults.js +0 -98
- package/dist/deployment/config/loader.d.ts +0 -24
- package/dist/deployment/config/loader.js +0 -237
- package/dist/deployment/config/types.d.ts +0 -117
- package/dist/deployment/config/types.js +0 -5
- package/dist/deployment/core/adapters.d.ts +0 -66
- package/dist/deployment/core/adapters.js +0 -156
- package/dist/deployment/core/executor.d.ts +0 -62
- package/dist/deployment/core/executor.js +0 -197
- package/dist/deployment/core/formatters.d.ts +0 -42
- package/dist/deployment/core/formatters.js +0 -146
- package/dist/deployment/openapi/generator.d.ts +0 -146
- package/dist/deployment/openapi/generator.js +0 -347
- package/dist/deployment/openapi/schema-converter.d.ts +0 -49
- package/dist/deployment/openapi/schema-converter.js +0 -192
- package/dist/deployment/targets/base.js +0 -855
- package/dist/deployment/types.d.ts +0 -140
- package/dist/deployment/types.js +0 -8
- package/dist/diagram/ascii-renderer.js +0 -528
- package/dist/diagram/geometry.js +0 -1267
- package/dist/diagram/html-viewer.d.ts +0 -21
- package/dist/diagram/html-viewer.js +0 -1689
- package/dist/diagram/layout.js +0 -143
- package/dist/diagram/orthogonal-router.js +0 -568
- package/dist/diagram/renderer.d.ts +0 -3
- package/dist/diagram/renderer.js +0 -266
- package/dist/diagram/theme.js +0 -282
- package/dist/diagram/types.js +0 -2
- package/dist/diff/WorkflowDiffer.js +0 -429
- package/dist/diff/formatDiff.js +0 -239
- package/dist/diff/impact.js +0 -119
- package/dist/diff/types.js +0 -35
- package/dist/doc-metadata/extractors/annotations.js +0 -638
- package/dist/doc-metadata/extractors/cli-commands.js +0 -326
- package/dist/doc-metadata/extractors/core-metadata.js +0 -61
- package/dist/doc-metadata/extractors/error-codes.js +0 -372
- package/dist/doc-metadata/extractors/grammar-rules.js +0 -51
- package/dist/doc-metadata/extractors/mcp-tools.js +0 -705
- package/dist/doc-metadata/extractors/plugin-api.d.ts +0 -19
- package/dist/doc-metadata/extractors/plugin-api.js +0 -279
- package/dist/doc-metadata/types.js +0 -5
- package/dist/editor-completions/annotationValues.js +0 -146
- package/dist/editor-completions/contextParser.js +0 -410
- package/dist/editor-completions/dataTypes.js +0 -95
- package/dist/editor-completions/goToDefinition.js +0 -112
- package/dist/editor-completions/jsDocAnnotations.js +0 -359
- package/dist/editor-completions/modifierCompletions.js +0 -197
- package/dist/editor-completions/types.js +0 -8
- package/dist/export/index.js +0 -212
- package/dist/extensions/index.d.ts +0 -16
- package/dist/extensions/index.js +0 -17
- package/dist/friendly-errors.js +0 -761
- package/dist/function-like.js +0 -84
- package/dist/generator/async-detection.js +0 -56
- package/dist/generator/code-utils.js +0 -551
- package/dist/generator/compile-target-registry.d.ts +0 -20
- package/dist/generator/compile-target-registry.js +0 -20
- package/dist/generator/control-flow.js +0 -358
- package/dist/generator/dev-mode-registry.d.ts +0 -27
- package/dist/generator/dev-mode-registry.js +0 -20
- package/dist/generator/scope-function-generator.js +0 -397
- package/dist/generator/unified.js +0 -1831
- package/dist/generator.d.ts +0 -54
- package/dist/generator.js +0 -101
- package/dist/jsdoc-parser.d.ts +0 -377
- package/dist/jsdoc-parser.js +0 -1189
- package/dist/jsdoc-port-sync/constants.js +0 -103
- package/dist/jsdoc-port-sync/diff.js +0 -319
- package/dist/jsdoc-port-sync/port-parser.js +0 -579
- package/dist/jsdoc-port-sync/rename.js +0 -256
- package/dist/jsdoc-port-sync/signature-parser.js +0 -559
- package/dist/jsdoc-port-sync/sync.js +0 -653
- package/dist/marketplace/manifest.js +0 -194
- package/dist/marketplace/registry.js +0 -198
- package/dist/marketplace/types.js +0 -9
- package/dist/marketplace/validator.js +0 -150
- package/dist/mcp/agent-channel.d.ts +0 -35
- package/dist/mcp/agent-channel.js +0 -61
- package/dist/mcp/auto-registration.d.ts +0 -3
- package/dist/mcp/auto-registration.js +0 -62
- package/dist/mcp/debug-session.js +0 -25
- package/dist/mcp/index.d.ts +0 -11
- package/dist/mcp/index.js +0 -10
- package/dist/mcp/pack-tools.js +0 -59
- package/dist/mcp/prompts.js +0 -68
- package/dist/mcp/response-utils.js +0 -97
- package/dist/mcp/run-registry.d.ts +0 -29
- package/dist/mcp/run-registry.js +0 -24
- package/dist/mcp/server.js +0 -63
- package/dist/mcp/tools-context.js +0 -51
- package/dist/mcp/tools-debug.js +0 -451
- package/dist/mcp/tools-diagram.js +0 -97
- package/dist/mcp/tools-docs.js +0 -62
- package/dist/mcp/tools-export.js +0 -222
- package/dist/mcp/tools-marketplace.js +0 -132
- package/dist/mcp/tools-model.d.ts +0 -3
- package/dist/mcp/tools-model.js +0 -279
- package/dist/mcp/tools-pattern.d.ts +0 -3
- package/dist/mcp/tools-pattern.js +0 -604
- package/dist/mcp/tools-query.js +0 -377
- package/dist/mcp/tools-resources.js +0 -41
- package/dist/mcp/tools-template.js +0 -119
- package/dist/mcp/tools-workflow-run.d.ts +0 -40
- package/dist/mcp/tools-workflow-run.js +0 -150
- package/dist/mcp/types.js +0 -2
- package/dist/mcp/workflow-executor.js +0 -242
- package/dist/migration/registry.js +0 -29
- package/dist/node-types-generator.js +0 -139
- package/dist/parser/tag-registry.js +0 -57
- package/dist/parser.d.ts +0 -232
- package/dist/parser.js +0 -2500
- package/dist/plugin/PluginPanel.d.ts +0 -12
- package/dist/plugin/PluginPanel.js +0 -5
- package/dist/plugin/index.d.ts +0 -13
- package/dist/plugin/index.js +0 -14
- package/dist/plugin/types.d.ts +0 -75
- package/dist/plugin/types.js +0 -8
- package/dist/resolve-package-types.js +0 -123
- package/dist/runtime/CancellationError.js +0 -20
- package/dist/runtime/ExecutionContext.js +0 -280
- package/dist/runtime/builtin-functions.js +0 -549
- package/dist/runtime/checkpoint.d.ts +0 -84
- package/dist/runtime/checkpoint.js +0 -225
- package/dist/runtime/debug-controller.js +0 -247
- package/dist/runtime/events.js +0 -2
- package/dist/runtime/function-registry.js +0 -66
- package/dist/runtime/parameter-resolver.js +0 -113
- package/dist/server/types.js +0 -5
- package/dist/server/webhook-server.js +0 -269
- package/dist/server/workflow-registry.js +0 -202
- package/dist/shared-project.js +0 -28
- package/dist/sugar-optimizer.js +0 -498
- package/dist/testing/assertions.js +0 -127
- package/dist/testing/mock-approval.js +0 -98
- package/dist/testing/mock-llm.js +0 -119
- package/dist/testing/recorder.js +0 -70
- package/dist/testing/replayer.js +0 -143
- package/dist/testing/token-tracker.js +0 -94
- package/dist/type-checker.d.ts +0 -42
- package/dist/type-checker.js +0 -190
- package/dist/type-mappings.js +0 -131
- package/dist/types/branded-ports.d.ts +0 -151
- package/dist/types/branded-ports.js +0 -121
- package/dist/types/index.d.ts +0 -5
- package/dist/types/index.js +0 -5
- package/dist/types.d.ts +0 -139
- package/dist/types.js +0 -15
- package/dist/utils/error-utils.js +0 -27
- package/dist/utils/lru-cache.js +0 -40
- package/dist/utils/port-ordering.js +0 -81
- package/dist/utils/port-tag-utils.js +0 -41
- package/dist/utils/string-distance.js +0 -56
- package/dist/validation/agent-detection.js +0 -115
- package/dist/validation/agent-rules.js +0 -262
- package/dist/validation/design-rules.js +0 -377
- package/dist/validation/rule-registry.js +0 -37
- package/dist/validator.d.ts +0 -113
- package/dist/validator.js +0 -1631
- package/docs/reference/patterns.md +0 -159
- package/scripts/postinstall.cjs +0 -86
- /package/dist/{shared-project.d.ts → parser/shared-project.d.ts} +0 -0
- /package/dist/{friendly-errors.d.ts → validation/friendly-errors.d.ts} +0 -0
|
@@ -0,0 +1,2297 @@
|
|
|
1
|
+
import { createRequire as __createRequire } from "module";
|
|
2
|
+
const require = __createRequire(import.meta.url);
|
|
3
|
+
import {
|
|
4
|
+
VALID_NODE_ICONS
|
|
5
|
+
} from "./flow-weaver-chunk-55QMUZIA.mjs";
|
|
6
|
+
import {
|
|
7
|
+
findClosestMatches,
|
|
8
|
+
isValidPortType
|
|
9
|
+
} from "./flow-weaver-chunk-APX6MQ5A.mjs";
|
|
10
|
+
import {
|
|
11
|
+
EXECUTION_STRATEGIES,
|
|
12
|
+
RESERVED_NODE_NAMES,
|
|
13
|
+
VALID_NODE_COLORS,
|
|
14
|
+
isExecutePort,
|
|
15
|
+
isExitNode,
|
|
16
|
+
isPseudoNode,
|
|
17
|
+
isReservedNodeName,
|
|
18
|
+
isStartNode
|
|
19
|
+
} from "./flow-weaver-chunk-DRN7KPWY.mjs";
|
|
20
|
+
|
|
21
|
+
// src/validation/core-rules.ts
|
|
22
|
+
import * as ts from "typescript";
|
|
23
|
+
|
|
24
|
+
// src/jsdoc-port-sync/constants.ts
|
|
25
|
+
var FUNC_DECL_START = /(?:async\s+)?function\s+\w+\s*\(/;
|
|
26
|
+
var ARROW_START = /(?:const|let|var)\s+\w+\s*=\s*(?:async\s*)?\(/;
|
|
27
|
+
function findBalancedClose(text, startIndex) {
|
|
28
|
+
const openChar = text[startIndex];
|
|
29
|
+
const closeChar = openChar === "(" ? ")" : openChar === "{" ? "}" : "]";
|
|
30
|
+
let depth = 1;
|
|
31
|
+
for (let i = startIndex + 1; i < text.length; i++) {
|
|
32
|
+
if (text[i] === openChar) depth++;
|
|
33
|
+
else if (text[i] === closeChar) {
|
|
34
|
+
depth--;
|
|
35
|
+
if (depth === 0) return i;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return -1;
|
|
39
|
+
}
|
|
40
|
+
function splitParams(paramsStr) {
|
|
41
|
+
const result = [];
|
|
42
|
+
let current = "";
|
|
43
|
+
let braceDepth = 0;
|
|
44
|
+
let angleDepth = 0;
|
|
45
|
+
let parenDepth = 0;
|
|
46
|
+
for (const char of paramsStr) {
|
|
47
|
+
if (char === "{") braceDepth++;
|
|
48
|
+
else if (char === "}") braceDepth--;
|
|
49
|
+
else if (char === "<") angleDepth++;
|
|
50
|
+
else if (char === ">" && angleDepth > 0) angleDepth--;
|
|
51
|
+
else if (char === "(") parenDepth++;
|
|
52
|
+
else if (char === ")") parenDepth--;
|
|
53
|
+
else if (char === "," && braceDepth === 0 && angleDepth === 0 && parenDepth === 0) {
|
|
54
|
+
result.push(current);
|
|
55
|
+
current = "";
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
current += char;
|
|
59
|
+
}
|
|
60
|
+
if (current.trim()) {
|
|
61
|
+
result.push(current);
|
|
62
|
+
}
|
|
63
|
+
return result;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// src/jsdoc-port-sync/signature-parser.ts
|
|
67
|
+
function parseFunctionSignature(functionText) {
|
|
68
|
+
const params = [];
|
|
69
|
+
let functionType = "expression";
|
|
70
|
+
let paramsStr = "";
|
|
71
|
+
const funcDeclMatch = functionText.match(FUNC_DECL_START);
|
|
72
|
+
if (funcDeclMatch && funcDeclMatch.index !== void 0) {
|
|
73
|
+
functionType = "declaration";
|
|
74
|
+
const openParenIndex = funcDeclMatch.index + funcDeclMatch[0].length - 1;
|
|
75
|
+
const closeParenIndex = findBalancedClose(functionText, openParenIndex);
|
|
76
|
+
if (closeParenIndex !== -1) {
|
|
77
|
+
paramsStr = functionText.substring(openParenIndex + 1, closeParenIndex);
|
|
78
|
+
}
|
|
79
|
+
} else {
|
|
80
|
+
const arrowMatch = functionText.match(ARROW_START);
|
|
81
|
+
if (arrowMatch && arrowMatch.index !== void 0) {
|
|
82
|
+
functionType = "arrow";
|
|
83
|
+
const openParenIndex = arrowMatch.index + arrowMatch[0].length - 1;
|
|
84
|
+
const closeParenIndex = findBalancedClose(functionText, openParenIndex);
|
|
85
|
+
if (closeParenIndex !== -1) {
|
|
86
|
+
paramsStr = functionText.substring(openParenIndex + 1, closeParenIndex);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (!paramsStr.trim()) {
|
|
91
|
+
return { params, functionType };
|
|
92
|
+
}
|
|
93
|
+
const paramTokens = splitParams(paramsStr);
|
|
94
|
+
paramTokens.forEach((paramStr, index) => {
|
|
95
|
+
const param = parseParam(paramStr.trim(), index);
|
|
96
|
+
if (param) {
|
|
97
|
+
params.push(param);
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
return { params, functionType };
|
|
101
|
+
}
|
|
102
|
+
function parseParam(paramStr, position) {
|
|
103
|
+
if (!paramStr) return null;
|
|
104
|
+
const trimmed = paramStr.trim();
|
|
105
|
+
if (!trimmed) return null;
|
|
106
|
+
const nameMatch = trimmed.match(/^(\w+)(\?)?/);
|
|
107
|
+
if (!nameMatch) return null;
|
|
108
|
+
const name = nameMatch[1];
|
|
109
|
+
const questionMark = nameMatch[2];
|
|
110
|
+
let rest = trimmed.substring(nameMatch[0].length).trim();
|
|
111
|
+
let tsType;
|
|
112
|
+
let defaultValue;
|
|
113
|
+
if (rest.startsWith(":")) {
|
|
114
|
+
rest = rest.substring(1).trim();
|
|
115
|
+
let depth = 0;
|
|
116
|
+
let typeEnd = rest.length;
|
|
117
|
+
for (let i = 0; i < rest.length; i++) {
|
|
118
|
+
const ch = rest[i];
|
|
119
|
+
if (ch === "(" || ch === "{" || ch === "[" || ch === "<") {
|
|
120
|
+
depth++;
|
|
121
|
+
} else if (ch === ")" || ch === "}" || ch === "]" || ch === ">") {
|
|
122
|
+
depth--;
|
|
123
|
+
} else if (ch === "=" && depth === 0) {
|
|
124
|
+
if (rest[i + 1] === ">") {
|
|
125
|
+
i++;
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
typeEnd = i;
|
|
129
|
+
break;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
tsType = rest.substring(0, typeEnd).trim();
|
|
133
|
+
rest = rest.substring(typeEnd).trim();
|
|
134
|
+
}
|
|
135
|
+
if (rest.startsWith("=")) {
|
|
136
|
+
defaultValue = rest.substring(1).trim();
|
|
137
|
+
}
|
|
138
|
+
const hasDefault = defaultValue !== void 0;
|
|
139
|
+
const optional = !!questionMark || hasDefault;
|
|
140
|
+
return {
|
|
141
|
+
name,
|
|
142
|
+
tsType: tsType || void 0,
|
|
143
|
+
optional,
|
|
144
|
+
defaultValue,
|
|
145
|
+
position
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// src/diagram/material-symbols.ts
|
|
150
|
+
var NAMES = [
|
|
151
|
+
"10k 10mp 11mp 123 12mp 13mp 14mp 15mp 16mp 17mp 18_up_rating 18mp 19mp 1k 1k_plus 1x_mobiledata",
|
|
152
|
+
"1x_mobiledata_badge 20mp 21mp 22mp 23mp 24fps_select 24mp 2d 2d_2 2k 2k_plus 2mp 30fps 30fps_select 360 3d",
|
|
153
|
+
"3d_2 3d_rotation 3g_mobiledata 3g_mobiledata_badge 3k 3k_plus 3mp 3p 4g_mobiledata 4g_mobiledata_badge",
|
|
154
|
+
"4g_plus_mobiledata 4k 4k_plus 4mp 50mp 5g 5g_mobiledata_badge 5k 5k_plus 5mp 60fps 60fps_select 6_ft_apart 6k",
|
|
155
|
+
"6k_plus 6mp 7k 7k_plus 7mp 8k 8k_plus 8mp 9k 9k_plus 9mp abc ac_unit access_alarm access_alarms access_time",
|
|
156
|
+
"access_time_filled accessibility accessibility_new accessible accessible_forward accessible_menu",
|
|
157
|
+
"account_balance account_balance_wallet account_box account_child account_child_invert account_circle",
|
|
158
|
+
"account_circle_filled account_circle_off account_tree action_key activity_zone acupuncture acute ad ad_group",
|
|
159
|
+
"ad_group_off ad_off ad_units adaptive_audio_mic adaptive_audio_mic_off adb add add_2 add_a_photo add_ad",
|
|
160
|
+
"add_alarm add_alert add_box add_business add_call add_card add_chart add_circle add_circle_outline",
|
|
161
|
+
"add_column_left add_column_right add_comment add_diamond add_home add_home_work add_ic_call add_link",
|
|
162
|
+
"add_location add_location_alt add_moderator add_notes add_photo_alternate add_reaction add_road add_row_above",
|
|
163
|
+
"add_row_below add_shopping_cart add_task add_to_drive add_to_home_screen add_to_photos add_to_queue",
|
|
164
|
+
"add_triangle addchart adf_scanner adjust admin_meds admin_panel_settings ads_click agender agriculture air",
|
|
165
|
+
"air_freshener air_purifier air_purifier_gen airline_seat_flat airline_seat_flat_angled",
|
|
166
|
+
"airline_seat_individual_suite airline_seat_legroom_extra airline_seat_legroom_normal",
|
|
167
|
+
"airline_seat_legroom_reduced airline_seat_recline_extra airline_seat_recline_normal airline_stops airlines",
|
|
168
|
+
"airplane_ticket airplanemode_active airplanemode_inactive airplay airport_shuttle airware airwave alarm",
|
|
169
|
+
"alarm_add alarm_off alarm_on alarm_pause alarm_smart_wake album align_center align_end align_flex_center",
|
|
170
|
+
"align_flex_end align_flex_start align_horizontal_center align_horizontal_left align_horizontal_right",
|
|
171
|
+
"align_items_stretch align_justify_center align_justify_flex_end align_justify_flex_start",
|
|
172
|
+
"align_justify_space_around align_justify_space_between align_justify_space_even align_justify_stretch",
|
|
173
|
+
"align_self_stretch align_space_around align_space_between align_space_even align_start align_stretch",
|
|
174
|
+
"align_vertical_bottom align_vertical_center align_vertical_top all_inbox all_inclusive all_match all_out",
|
|
175
|
+
"allergies allergy alt_route alternate_email altitude ambient_screen ambulance amend amp_stories analytics",
|
|
176
|
+
"anchor android android_cell_4_bar android_cell_4_bar_alert android_cell_4_bar_off android_cell_4_bar_plus",
|
|
177
|
+
"android_cell_5_bar android_cell_5_bar_alert android_cell_5_bar_off android_cell_5_bar_plus",
|
|
178
|
+
"android_cell_dual_4_bar android_cell_dual_4_bar_alert android_cell_dual_4_bar_plus android_cell_dual_5_bar",
|
|
179
|
+
"android_cell_dual_5_bar_alert android_cell_dual_5_bar_plus android_wifi_3_bar android_wifi_3_bar_alert",
|
|
180
|
+
"android_wifi_3_bar_lock android_wifi_3_bar_off android_wifi_3_bar_plus android_wifi_3_bar_question",
|
|
181
|
+
"android_wifi_4_bar android_wifi_4_bar_alert android_wifi_4_bar_lock android_wifi_4_bar_off",
|
|
182
|
+
"android_wifi_4_bar_plus android_wifi_4_bar_question animated_images animation announcement antigravity aod",
|
|
183
|
+
"aod_tablet aod_watch apartment api apk_document apk_install app_badging app_blocking app_promo",
|
|
184
|
+
"app_registration app_settings_alt app_shortcut apparel approval approval_delegation approval_delegation_off",
|
|
185
|
+
"apps apps_outage aq aq_indoor ar_on_you ar_stickers architecture archive area_chart arming_countdown",
|
|
186
|
+
"arrow_and_edge arrow_back arrow_back_2 arrow_back_ios arrow_back_ios_new arrow_circle_down arrow_circle_left",
|
|
187
|
+
"arrow_circle_right arrow_circle_up arrow_cool_down arrow_downward arrow_downward_alt arrow_drop_down",
|
|
188
|
+
"arrow_drop_down_circle arrow_drop_up arrow_forward arrow_forward_ios arrow_insert arrow_left arrow_left_alt",
|
|
189
|
+
"arrow_menu_close arrow_menu_open arrow_or_edge arrow_outward arrow_range arrow_right arrow_right_alt",
|
|
190
|
+
"arrow_selector_tool arrow_shape_up arrow_shape_up_stack arrow_shape_up_stack_2 arrow_split arrow_top_left",
|
|
191
|
+
"arrow_top_right arrow_upload_progress arrow_upload_ready arrow_upward arrow_upward_alt arrow_warm_up",
|
|
192
|
+
"arrows_input arrows_left_right_circle arrows_more_down arrows_more_up arrows_output arrows_outward",
|
|
193
|
+
"arrows_up_down_circle art_track article article_person article_shortcut artist aspect_ratio assessment",
|
|
194
|
+
"assignment assignment_add assignment_globe assignment_ind assignment_late assignment_return",
|
|
195
|
+
"assignment_returned assignment_turned_in assist_walker assistant assistant_device assistant_direction",
|
|
196
|
+
"assistant_navigation assistant_on_hub assistant_photo assured_workload asterisk astrophotography_auto",
|
|
197
|
+
"astrophotography_off atm atr attach_email attach_file attach_file_add attach_file_off attach_money attachment",
|
|
198
|
+
"attractions attribution audio_capture audio_description audio_file audio_video_receiver audiotrack",
|
|
199
|
+
"auto_activity_zone auto_awesome auto_awesome_mosaic auto_awesome_motion auto_delete auto_detect_voice",
|
|
200
|
+
"auto_draw_solid auto_fix auto_fix_high auto_fix_normal auto_fix_off auto_graph auto_label auto_meeting_room",
|
|
201
|
+
"auto_mode auto_read_pause auto_read_play auto_schedule auto_stories auto_stories_off auto_timer auto_towing",
|
|
202
|
+
"auto_transmission auto_videocam autofps_select automation autopause autopay autoplay autorenew autostop av1",
|
|
203
|
+
"av_timer avc avg_pace avg_time avocado_bean award_meal award_star azm b_circle baby_changing_station back_hand",
|
|
204
|
+
"back_to_tab background_dot_large background_dot_small background_grid_small background_replace backlight_high",
|
|
205
|
+
"backlight_high_off backlight_low backpack backspace backup backup_table badge badge_critical_battery badminton",
|
|
206
|
+
"bakery_dining balance balcony ballot bar_chart bar_chart_4_bars bar_chart_off barcode barcode_reader",
|
|
207
|
+
"barcode_scanner barefoot batch_prediction bath_bedrock bath_outdoor bath_private bath_public_large bath_soak",
|
|
208
|
+
"bathroom bathtub battery_0_bar battery_1_bar battery_20 battery_2_bar battery_30 battery_3_bar battery_4_bar",
|
|
209
|
+
"battery_50 battery_5_bar battery_60 battery_6_bar battery_80 battery_90 battery_alert battery_android_0",
|
|
210
|
+
"battery_android_1 battery_android_2 battery_android_3 battery_android_4 battery_android_5 battery_android_6",
|
|
211
|
+
"battery_android_alert battery_android_bolt battery_android_frame_1 battery_android_frame_2",
|
|
212
|
+
"battery_android_frame_3 battery_android_frame_4 battery_android_frame_5 battery_android_frame_6",
|
|
213
|
+
"battery_android_frame_alert battery_android_frame_bolt battery_android_frame_full battery_android_frame_plus",
|
|
214
|
+
"battery_android_frame_question battery_android_frame_share battery_android_frame_shield battery_android_full",
|
|
215
|
+
"battery_android_plus battery_android_question battery_android_share battery_android_shield battery_change",
|
|
216
|
+
"battery_charging_20 battery_charging_20_2 battery_charging_30 battery_charging_30_2 battery_charging_50",
|
|
217
|
+
"battery_charging_50_2 battery_charging_60 battery_charging_60_2 battery_charging_80 battery_charging_80_2",
|
|
218
|
+
"battery_charging_90 battery_charging_full battery_charging_full_2 battery_error battery_full battery_full_alt",
|
|
219
|
+
"battery_horiz_000 battery_horiz_050 battery_horiz_075 battery_low battery_plus battery_profile battery_saver",
|
|
220
|
+
"battery_share battery_status_good battery_std battery_unknown battery_vert_005 battery_vert_020",
|
|
221
|
+
"battery_vert_050 battery_very_low beach_access bed bedroom_baby bedroom_child bedroom_parent bedtime",
|
|
222
|
+
"bedtime_off beenhere beer_meal bento bia bid_landscape bid_landscape_disabled bigtop_updates bike_dock",
|
|
223
|
+
"bike_lane bike_scooter biotech blanket blender blind blinds blinds_2 blinds_2_closed blinds_closed block",
|
|
224
|
+
"blood_pressure bloodtype bluetooth bluetooth_audio bluetooth_connected bluetooth_disabled bluetooth_drive",
|
|
225
|
+
"bluetooth_searching blur_circular blur_linear blur_medium blur_off blur_on blur_short boat_bus boat_railway",
|
|
226
|
+
"body_fat body_system bolt bolt_boost bomb book book_2 book_3 book_4 book_5 book_6 book_online book_ribbon",
|
|
227
|
+
"bookmark bookmark_add bookmark_added bookmark_bag bookmark_border bookmark_check bookmark_flag bookmark_heart",
|
|
228
|
+
"bookmark_manager bookmark_remove bookmark_stacks bookmark_star bookmarks books_movies_and_music border_all",
|
|
229
|
+
"border_bottom border_clear border_color border_horizontal border_inner border_left border_outer border_right",
|
|
230
|
+
"border_style border_top border_vertical borg bottom_app_bar bottom_drawer bottom_navigation bottom_panel_close",
|
|
231
|
+
"bottom_panel_open bottom_right_click bottom_sheets box box_add box_edit boy brand_awareness brand_family",
|
|
232
|
+
"branding_watermark breakfast_dining breaking_news breaking_news_alt_1 breastfeeding brick briefcase_meal",
|
|
233
|
+
"brightness_1 brightness_2 brightness_3 brightness_4 brightness_5 brightness_6 brightness_7 brightness_alert",
|
|
234
|
+
"brightness_auto brightness_empty brightness_high brightness_low brightness_medium bring_your_own_ip",
|
|
235
|
+
"broadcast_on_home broadcast_on_personal broken_image browse browse_activity browse_gallery",
|
|
236
|
+
"browser_not_supported browser_updated brunch_dining brush bubble bubble_chart bubbles bucket_check bug_report",
|
|
237
|
+
"build build_circle bullet_chart bungalow burst_mode bus_alert bus_map_pin bus_railway business business_center",
|
|
238
|
+
"business_chip business_messages buttons_alt cabin cable cable_car cached cadence cake cake_add calculate",
|
|
239
|
+
"calendar_add_on calendar_apps_script calendar_check calendar_clock calendar_lock calendar_meal calendar_meal_2",
|
|
240
|
+
"calendar_month calendar_today calendar_view_day calendar_view_month calendar_view_week call call_end",
|
|
241
|
+
"call_end_alt call_log call_made call_merge call_missed call_missed_outgoing call_quality call_received",
|
|
242
|
+
"call_split call_to_action camera camera_alt camera_enhance camera_front camera_indoor camera_outdoor",
|
|
243
|
+
"camera_rear camera_roll camera_video cameraswitch campaign camping cancel cancel_presentation",
|
|
244
|
+
"cancel_schedule_send candle candlestick_chart cannabis captive_portal capture car_crash car_defrost_left",
|
|
245
|
+
"car_defrost_low_left car_defrost_low_right car_defrost_mid_left car_defrost_mid_low_left",
|
|
246
|
+
"car_defrost_mid_low_right car_defrost_mid_right car_defrost_right car_fan_low_left car_fan_low_mid_left",
|
|
247
|
+
"car_fan_low_right car_fan_mid_left car_fan_mid_low_right car_fan_mid_right car_fan_recirculate",
|
|
248
|
+
"car_fan_recirculate_2 car_gear car_lock car_mirror_heat car_rental car_repair car_seat_off car_tag",
|
|
249
|
+
"card_giftcard card_membership card_travel cardio_load cardiology cards cards_stack cards_star carpenter",
|
|
250
|
+
"carry_on_bag carry_on_bag_checked carry_on_bag_inactive carry_on_bag_question cases casino cast cast_connected",
|
|
251
|
+
"cast_for_education cast_pause cast_warning castle category category_search celebration cell_merge cell_tower",
|
|
252
|
+
"cell_wifi center_focus_strong center_focus_weak chair chair_alt chair_counter chair_fireplace chair_umbrella",
|
|
253
|
+
"chalet change_circle change_history charger charging_station chart_data chat chat_add_on chat_apps_script",
|
|
254
|
+
"chat_bubble chat_bubble_off chat_bubble_outline chat_dashed chat_error chat_info chat_paste_go chat_paste_go_2",
|
|
255
|
+
"check check_alert check_box check_box_outline_blank check_circle check_circle_filled check_circle_outline",
|
|
256
|
+
"check_circle_unread check_in_out check_indeterminate_small check_small checkbook checked_bag",
|
|
257
|
+
"checked_bag_question checklist checklist_rtl checkroom cheer chef_hat chess chess_bishop chess_bishop_2",
|
|
258
|
+
"chess_king chess_king_2 chess_knight chess_pawn chess_pawn_2 chess_queen chess_rook chevron_backward",
|
|
259
|
+
"chevron_forward chevron_left chevron_line_up chevron_right child_care child_friendly child_hat chip_extraction",
|
|
260
|
+
"chips chrome_reader_mode chromecast_2 chromecast_device chronic church cinematic_blur circle circle_circle",
|
|
261
|
+
"circle_notifications circles circles_ext clarify class clean_hands cleaning cleaning_bucket cleaning_services",
|
|
262
|
+
"clear clear_all clear_day clear_night climate_mini_split clinical_notes clock_arrow_down clock_arrow_up",
|
|
263
|
+
"clock_loader_10 clock_loader_20 clock_loader_40 clock_loader_60 clock_loader_80 clock_loader_90 close",
|
|
264
|
+
"close_fullscreen close_small closed_caption closed_caption_add closed_caption_disabled closed_caption_off",
|
|
265
|
+
"cloud cloud_alert cloud_circle cloud_done cloud_download cloud_lock cloud_off cloud_queue cloud_sync",
|
|
266
|
+
"cloud_upload cloudy cloudy_filled cloudy_snowing co2 co_present code code_blocks code_off code_xml coffee",
|
|
267
|
+
"coffee_maker cognition cognition_2 collapse_all collapse_content collections collections_bookmark color_lens",
|
|
268
|
+
"colorize colors combine_columns comedy_mask comic_bubble comment comment_bank comments_disabled commit",
|
|
269
|
+
"communication communities communities_filled commute compare compare_arrows compass_calibration",
|
|
270
|
+
"component_exchange compost compress computer computer_arrow_up computer_cancel computer_sound concierge",
|
|
271
|
+
"conditions confirmation_number congenital connect_without_contact connected_tv connecting_airports",
|
|
272
|
+
"construction contact_emergency contact_mail contact_page contact_phone contact_phone_filled contact_support",
|
|
273
|
+
"contactless contactless_off contacts contacts_product content_copy content_cut content_paste content_paste_go",
|
|
274
|
+
"content_paste_off content_paste_search contextual_token contextual_token_add contract contract_delete",
|
|
275
|
+
"contract_edit contrast contrast_circle contrast_rtl_off contrast_square control_camera control_point",
|
|
276
|
+
"control_point_duplicate controller_gen conversation conversion_path conversion_path_off convert_to_text",
|
|
277
|
+
"conveyor_belt cookie cookie_off cooking cool_to_dry copy_all copyright coronavirus corporate_fare cottage",
|
|
278
|
+
"counter_0 counter_1 counter_2 counter_3 counter_4 counter_5 counter_6 counter_7 counter_8 counter_9",
|
|
279
|
+
"countertops create create_new_folder credit_card credit_card_clock credit_card_gear credit_card_heart",
|
|
280
|
+
"credit_card_off credit_score crib crisis_alert crop crop_16_9 crop_21_9 crop_2_3 crop_3_2 crop_5_4 crop_7_5",
|
|
281
|
+
"crop_9_16 crop_din crop_free crop_landscape crop_original crop_portrait crop_rotate crop_square crossword",
|
|
282
|
+
"crowdsource crown cruelty_free css csv currency_bitcoin currency_exchange currency_franc currency_lira",
|
|
283
|
+
"currency_pound currency_ruble currency_rupee currency_rupee_circle currency_yen currency_yuan curtains",
|
|
284
|
+
"curtains_closed custom_typography cut cycle cyclone dangerous dark_mode dashboard dashboard_2 dashboard_2_add",
|
|
285
|
+
"dashboard_2_edit dashboard_2_gear dashboard_customize data_alert data_array data_check data_exploration",
|
|
286
|
+
"data_info_alert data_loss_prevention data_object data_saver_off data_saver_on data_table data_thresholding",
|
|
287
|
+
"data_usage database database_off database_search database_upload dataset dataset_linked date_range deblur",
|
|
288
|
+
"deceased decimal_decrease decimal_increase deck dehaze delete delete_forever delete_history delete_outline",
|
|
289
|
+
"delete_sweep delivery_dining delivery_truck_bolt delivery_truck_speed demography density_large density_medium",
|
|
290
|
+
"density_small dentistry departure_board deployed_code deployed_code_account deployed_code_alert",
|
|
291
|
+
"deployed_code_history deployed_code_update dermatology description deselect design_services desk deskphone",
|
|
292
|
+
"desktop_access_disabled desktop_cloud desktop_cloud_stack desktop_landscape desktop_landscape_add desktop_mac",
|
|
293
|
+
"desktop_portrait desktop_windows destruction details detection_and_zone detection_and_zone_off detector",
|
|
294
|
+
"detector_alarm detector_battery detector_co detector_offline detector_smoke detector_status developer_board",
|
|
295
|
+
"developer_board_off developer_guide developer_mode developer_mode_tv device_band device_hub device_reset",
|
|
296
|
+
"device_swoosh_star device_thermostat device_unknown devices devices_fold devices_fold_2 devices_off",
|
|
297
|
+
"devices_other devices_wearables dew_point diagnosis diagonal_line dialer_sip dialogs dialpad diamond",
|
|
298
|
+
"diamond_shine dictionary difference digital_out_of_home digital_wellbeing dine_heart dine_in dine_lamp dining",
|
|
299
|
+
"dinner_dining directions directions_alt directions_alt_off directions_bike directions_boat",
|
|
300
|
+
"directions_boat_filled directions_bus directions_bus_filled directions_car directions_car_filled",
|
|
301
|
+
"directions_off directions_railway directions_railway_2 directions_railway_filled directions_run",
|
|
302
|
+
"directions_subway directions_subway_filled directions_transit directions_transit_filled directions_walk",
|
|
303
|
+
"directory_sync dirty_lens disabled_by_default disabled_visible disc_full discover_tune dishwasher",
|
|
304
|
+
"dishwasher_gen display_add display_external_input display_settings distance diversity_1 diversity_2",
|
|
305
|
+
"diversity_3 diversity_4 dns do_disturb do_disturb_alt do_disturb_off do_disturb_on do_not_disturb",
|
|
306
|
+
"do_not_disturb_alt do_not_disturb_off do_not_disturb_on do_not_disturb_on_total_silence do_not_step",
|
|
307
|
+
"do_not_touch dock dock_to_bottom dock_to_left dock_to_right docs docs_add_on docs_apps_script document_scanner",
|
|
308
|
+
"document_search domain domain_add domain_disabled domain_disabled_check domain_verification",
|
|
309
|
+
"domain_verification_off domino_mask done done_all done_outline donut_large donut_small door_back door_front",
|
|
310
|
+
"door_open door_sensor door_sliding doorbell doorbell_3p doorbell_chime double_arrow downhill_skiing download",
|
|
311
|
+
"download_2 download_done download_for_offline downloading draft draft_orders drafts drag_click drag_handle",
|
|
312
|
+
"drag_indicator drag_pan draw draw_abstract draw_collage drawing_recognition dresser drive_eta drive_export",
|
|
313
|
+
"drive_file_move drive_file_move_outline drive_file_move_rtl drive_file_rename drive_file_rename_outline",
|
|
314
|
+
"drive_folder_upload drone drone_2 dropdown dropdown_menu dropper_eye dry dry_cleaning dual_screen duo dvr",
|
|
315
|
+
"dynamic_feed dynamic_form e911_avatar e911_emergency e_mobiledata e_mobiledata_badge ear_sound earbud_case",
|
|
316
|
+
"earbud_left earbud_right earbuds earbuds_2 earbuds_battery early_on earthquake east ecg ecg_heart eco eda",
|
|
317
|
+
"edgesensor_high edgesensor_low edit edit_arrow_down edit_arrow_up edit_attributes edit_audio edit_calendar",
|
|
318
|
+
"edit_document edit_location edit_location_alt edit_note edit_notifications edit_off edit_road edit_square",
|
|
319
|
+
"editor_choice egg egg_alt eject elderly elderly_woman electric_bike electric_bolt electric_car electric_meter",
|
|
320
|
+
"electric_moped electric_rickshaw electric_scooter electrical_services elevation elevator email emergency",
|
|
321
|
+
"emergency_heat emergency_heat_2 emergency_home emergency_recording emergency_share emergency_share_off",
|
|
322
|
+
"emoji_emotions emoji_events emoji_flags emoji_food_beverage emoji_language emoji_nature emoji_objects",
|
|
323
|
+
"emoji_people emoji_symbols emoji_transportation emoticon empty_dashboard enable encrypted encrypted_add",
|
|
324
|
+
"encrypted_add_circle encrypted_minus_circle encrypted_off endocrinology energy energy_program_saving",
|
|
325
|
+
"energy_program_time_used energy_savings_leaf engineering enhanced_encryption ent enterprise enterprise_off",
|
|
326
|
+
"equal equalizer eraser_size_1 eraser_size_2 eraser_size_3 eraser_size_4 eraser_size_5 error",
|
|
327
|
+
"error_circle_rounded error_med error_outline escalator escalator_warning euro euro_symbol ev_charger",
|
|
328
|
+
"ev_mobiledata_badge ev_shadow ev_shadow_add ev_shadow_minus ev_station event event_available event_busy",
|
|
329
|
+
"event_list event_note event_repeat event_seat event_upcoming exclamation exercise exit_to_app expand",
|
|
330
|
+
"expand_all expand_circle_down expand_circle_right expand_circle_up expand_content expand_less expand_more",
|
|
331
|
+
"expansion_panels expension_panels experiment explicit explore explore_nearby explore_off explosion",
|
|
332
|
+
"export_notes exposure exposure_neg_1 exposure_neg_2 exposure_plus_1 exposure_plus_2 exposure_zero extension",
|
|
333
|
+
"extension_off eye_tracking eyebrow eyeglasses eyeglasses_2 eyeglasses_2_sound eyeglasses_3 face face_2 face_3",
|
|
334
|
+
"face_4 face_5 face_6 face_down face_left face_nod face_retouching_natural face_retouching_off face_right",
|
|
335
|
+
"face_shake face_unlock face_up fact_check factory falling familiar_face_and_zone family_group family_history",
|
|
336
|
+
"family_home family_link family_restroom family_star fan_focus fan_indirect farsight_digital fast_forward",
|
|
337
|
+
"fast_rewind fastfood faucet favorite favorite_border fax feature_search featured_play_list",
|
|
338
|
+
"featured_seasonal_and_gifts featured_video feed feedback female femur femur_alt fence fertile festival",
|
|
339
|
+
"fiber_dvr fiber_manual_record fiber_new fiber_pin fiber_smart_record file_copy file_copy_off file_download",
|
|
340
|
+
"file_download_done file_download_off file_export file_json file_map file_map_stack file_open file_png",
|
|
341
|
+
"file_present file_save file_save_off file_upload file_upload_off files filter filter_1 filter_2 filter_3",
|
|
342
|
+
"filter_4 filter_5 filter_6 filter_7 filter_8 filter_9 filter_9_plus filter_alt filter_alt_off",
|
|
343
|
+
"filter_arrow_right filter_b_and_w filter_center_focus filter_drama filter_frames filter_hdr filter_list",
|
|
344
|
+
"filter_list_alt filter_list_off filter_none filter_retrolux filter_tilt_shift filter_vintage finance",
|
|
345
|
+
"finance_chip finance_mode find_in_page find_replace fingerprint fingerprint_off fire_check fire_extinguisher",
|
|
346
|
+
"fire_hydrant fire_truck fireplace first_page fit_page fit_page_height fit_page_width fit_screen fit_width",
|
|
347
|
+
"fitness_center fitness_tracker fitness_trackers flag flag_2 flag_check flag_circle flag_filled flaky flare",
|
|
348
|
+
"flash_auto flash_off flash_on flashlight_off flashlight_on flatware flex_direction flex_no_wrap flex_wrap",
|
|
349
|
+
"flight flight_class flight_land flight_takeoff flights_and_hotels flightsmode flip flip_camera_android",
|
|
350
|
+
"flip_camera_ios flip_to_back flip_to_front float_landscape_2 float_portrait_2 flood floor floor_lamp",
|
|
351
|
+
"flourescent flowchart flowsheet fluid fluid_balance fluid_med fluorescent flutter flutter_dash flyover fmd_bad",
|
|
352
|
+
"fmd_good foggy folded_hands folder folder_check folder_check_2 folder_code folder_copy folder_data",
|
|
353
|
+
"folder_delete folder_eye folder_info folder_limited folder_managed folder_match folder_off folder_open",
|
|
354
|
+
"folder_shared folder_special folder_supervised folder_zip follow_the_signs font_download font_download_off",
|
|
355
|
+
"food_bank foot_bones footprint for_you forest fork_chart fork_left fork_right fork_spoon forklift",
|
|
356
|
+
"format_align_center format_align_justify format_align_left format_align_right format_bold format_clear",
|
|
357
|
+
"format_color_fill format_color_reset format_color_text format_h1 format_h2 format_h3 format_h4 format_h5",
|
|
358
|
+
"format_h6 format_image_back format_image_break_left format_image_break_right format_image_front",
|
|
359
|
+
"format_image_inline_left format_image_inline_right format_image_left format_image_right format_indent_decrease",
|
|
360
|
+
"format_indent_increase format_ink_highlighter format_italic format_letter_spacing format_letter_spacing_2",
|
|
361
|
+
"format_letter_spacing_standard format_letter_spacing_wide format_letter_spacing_wider format_line_spacing",
|
|
362
|
+
"format_list_bulleted format_list_bulleted_add format_list_numbered format_list_numbered_rtl format_overline",
|
|
363
|
+
"format_paint format_paint_off format_paragraph format_quote format_quote_off format_shapes format_size",
|
|
364
|
+
"format_strikethrough format_text_clip format_text_overflow format_text_wrap format_textdirection_l_to_r",
|
|
365
|
+
"format_textdirection_r_to_l format_textdirection_vertical format_underlined format_underlined_squiggle",
|
|
366
|
+
"forms_add_on forms_apps_script fort forum forward forward_10 forward_30 forward_5 forward_circle forward_media",
|
|
367
|
+
"forward_to_inbox foundation fragrance frame_bug frame_exclamation frame_inspect frame_person frame_person_mic",
|
|
368
|
+
"frame_person_off frame_reload frame_source free_breakfast free_cancellation front_hand front_loader",
|
|
369
|
+
"full_coverage full_hd full_stacked_bar_chart fullscreen fullscreen_exit fullscreen_portrait function functions",
|
|
370
|
+
"funicular g_mobiledata g_mobiledata_badge g_translate gallery_thumbnail game_bumper_left game_bumper_right",
|
|
371
|
+
"game_button_l game_button_l1 game_button_l2 game_button_r game_button_r1 game_button_r2 game_button_zl",
|
|
372
|
+
"game_button_zr game_stick_l3 game_stick_left game_stick_r3 game_stick_right game_trigger_left",
|
|
373
|
+
"game_trigger_right gamepad gamepad_circle_down gamepad_circle_left gamepad_circle_right gamepad_circle_up",
|
|
374
|
+
"gamepad_down gamepad_left gamepad_right gamepad_up games garage garage_check garage_door garage_door_open",
|
|
375
|
+
"garage_home garage_money garden_cart gas_meter gastroenterology gate gavel general_device generating_tokens",
|
|
376
|
+
"genetics genres gesture gesture_select get_app gif gif_2 gif_box girl gite glass_cup globe globe_2_cancel",
|
|
377
|
+
"globe_2_question globe_asia globe_book globe_clock globe_location_pin globe_uk glucose glyphs go_to_line",
|
|
378
|
+
"golf_course gondola_lift google_home_devices google_plus_reshare google_tv_remote google_wifi gpp_bad gpp_good",
|
|
379
|
+
"gpp_maybe gps_fixed gps_not_fixed gps_off grade gradient grading grain graph_1 graph_2 graph_3 graph_4 graph_5",
|
|
380
|
+
"graph_6 graph_7 graph_8 graphic_eq graphic_eq_off grass grid_3x3 grid_3x3_off grid_4x4 grid_goldenratio",
|
|
381
|
+
"grid_guides grid_layout_side grid_off grid_on grid_view grocery group group_add group_off group_remove",
|
|
382
|
+
"group_search group_work grouped_bar_chart groups groups_2 groups_3 guardian gynecology h_mobiledata",
|
|
383
|
+
"h_mobiledata_badge h_plus_mobiledata h_plus_mobiledata_badge hail hallway hanami_dango hand_bones hand_gesture",
|
|
384
|
+
"hand_gesture_off hand_meal hand_package handheld_controller handshake handwriting_recognition handyman",
|
|
385
|
+
"hangout_video hangout_video_off hard_disk hard_drive hard_drive_2 hardware hd hdr_auto hdr_auto_select",
|
|
386
|
+
"hdr_enhanced_select hdr_off hdr_off_select hdr_on hdr_on_select hdr_plus hdr_plus_off hdr_strong hdr_weak",
|
|
387
|
+
"head_mounted_device headphones headphones_battery headset headset_mic headset_off healing health_and_beauty",
|
|
388
|
+
"health_and_safety health_cross health_metrics heap_snapshot_large heap_snapshot_multiple",
|
|
389
|
+
"heap_snapshot_thumbnail hearing hearing_aid hearing_aid_disabled hearing_aid_disabled_left hearing_aid_left",
|
|
390
|
+
"hearing_disabled heart_broken heart_check heart_minus heart_plus heart_smile heat heat_pump heat_pump_balance",
|
|
391
|
+
"height helicopter help help_center help_clinic help_outline hematology hevc hexagon hide hide_image",
|
|
392
|
+
"hide_source high_chair high_density high_quality high_quality_off high_res highlight highlight_alt",
|
|
393
|
+
"highlight_keyboard_focus highlight_mouse_cursor highlight_off highlight_text_cursor highlighter_size_1",
|
|
394
|
+
"highlighter_size_2 highlighter_size_3 highlighter_size_4 highlighter_size_5 hiking history history_2",
|
|
395
|
+
"history_edu history_off history_toggle_off hive hls hls_off holiday_village home home_and_garden home_app_logo",
|
|
396
|
+
"home_filled home_health home_improvement_and_tools home_iot_device home_max home_max_dots home_mini home_pin",
|
|
397
|
+
"home_repair_service home_speaker home_storage home_storage_gear home_work horizontal_align_center",
|
|
398
|
+
"horizontal_align_left horizontal_align_right horizontal_distribute horizontal_rule horizontal_split host",
|
|
399
|
+
"hot_tub hotel hotel_class hourglass hourglass_arrow_down hourglass_arrow_up hourglass_bottom hourglass_check",
|
|
400
|
+
"hourglass_disabled hourglass_empty hourglass_full hourglass_pause hourglass_top house house_siding",
|
|
401
|
+
"house_with_shield houseboat household_supplies hov how_to_reg how_to_vote hr_resting html http https hub",
|
|
402
|
+
"humerus humerus_alt humidity_high humidity_indoor humidity_low humidity_mid humidity_percentage hvac",
|
|
403
|
+
"hvac_max_defrost ice_skating icecream id_card id_card_2 identity_aware_proxy identity_platform ifl iframe",
|
|
404
|
+
"iframe_off image image_arrow_up image_aspect_ratio image_inset image_not_supported image_search",
|
|
405
|
+
"imagesearch_roller imagesmode immunology import_contacts import_export important_devices in_home_mode",
|
|
406
|
+
"inactive_order inbox inbox_customize inbox_text inbox_text_asterisk inbox_text_person inbox_text_share",
|
|
407
|
+
"incomplete_circle indeterminate_check_box indeterminate_question_box info info_i infrared ink_eraser",
|
|
408
|
+
"ink_eraser_off ink_highlighter ink_highlighter_move ink_highlighter_off ink_marker ink_pen ink_selection",
|
|
409
|
+
"inpatient input input_circle insert_chart insert_chart_filled insert_chart_outlined insert_comment",
|
|
410
|
+
"insert_drive_file insert_emoticon insert_invitation insert_link insert_page_break insert_photo insert_text",
|
|
411
|
+
"insights install_desktop install_mobile instant_mix integration_instructions interactive_space interests",
|
|
412
|
+
"interpreter_mode inventory inventory_2 invert_colors invert_colors_off ios ios_share iron iso jamboard_kiosk",
|
|
413
|
+
"japanese_curry japanese_flag javascript jewelry join join_full join_inner join_left join_right joystick",
|
|
414
|
+
"jump_to_element kanji_alcohol kayaking kebab_dining keep keep_off keep_pin keep_public kettle key key_off",
|
|
415
|
+
"key_vertical key_visualizer keyboard keyboard_alt keyboard_arrow_down keyboard_arrow_left keyboard_arrow_right",
|
|
416
|
+
"keyboard_arrow_up keyboard_backspace keyboard_capslock keyboard_capslock_badge keyboard_command_key",
|
|
417
|
+
"keyboard_control_key keyboard_double_arrow_down keyboard_double_arrow_left keyboard_double_arrow_right",
|
|
418
|
+
"keyboard_double_arrow_up keyboard_external_input keyboard_full keyboard_hide keyboard_keys keyboard_lock",
|
|
419
|
+
"keyboard_lock_off keyboard_off keyboard_onscreen keyboard_option_key keyboard_previous_language",
|
|
420
|
+
"keyboard_return keyboard_tab keyboard_tab_rtl keyboard_voice kid_star king_bed kitchen kitesurfing lab_panel",
|
|
421
|
+
"lab_profile lab_research label label_important label_important_outline label_off label_outline labs lan",
|
|
422
|
+
"landscape landscape_2 landscape_2_edit landscape_2_off landslide language language_chinese_array",
|
|
423
|
+
"language_chinese_cangjie language_chinese_dayi language_chinese_pinyin language_chinese_quick",
|
|
424
|
+
"language_chinese_wubi language_french language_gb_english language_international language_japanese_kana",
|
|
425
|
+
"language_korean_latin language_pinyin language_spanish language_us language_us_colemak language_us_dvorak laps",
|
|
426
|
+
"laptop laptop_car laptop_chromebook laptop_mac laptop_windows lasso_select last_page launch laundry layers",
|
|
427
|
+
"layers_clear lda leaderboard leak_add leak_remove left_click left_panel_close left_panel_open legend_toggle",
|
|
428
|
+
"lens lens_blur letter_switch library_add library_add_check library_books library_music license lift_to_talk",
|
|
429
|
+
"light light_group light_group_2 light_mode light_mode_auto light_off lightbulb lightbulb_2 lightbulb_circle",
|
|
430
|
+
"lightbulb_outline lightning_stand lightstrip line_axis line_curve line_end line_end_arrow line_end_arrow_notch",
|
|
431
|
+
"line_end_circle line_end_diamond line_end_square line_start line_start_arrow line_start_arrow_notch",
|
|
432
|
+
"line_start_circle line_start_diamond line_start_square line_style line_weight linear_scale link link_2",
|
|
433
|
+
"link_off linked_camera linked_services lips liquor list list_2 list_alt list_alt_add list_alt_check list_arrow",
|
|
434
|
+
"lists live_help live_tv living local_activity local_airport local_atm local_bar local_cafe local_car_wash",
|
|
435
|
+
"local_convenience_store local_dining local_drink local_fire_department local_florist local_gas_station",
|
|
436
|
+
"local_grocery_store local_hospital local_hotel local_laundry_service local_library local_mall local_movies",
|
|
437
|
+
"local_offer local_parking local_pharmacy local_phone local_pizza local_play local_police local_post_office",
|
|
438
|
+
"local_printshop local_see local_shipping local_taxi location_automation location_away location_chip",
|
|
439
|
+
"location_city location_disabled location_home location_off location_on location_pin location_searching",
|
|
440
|
+
"locator_tag lock lock_clock lock_open lock_open_circle lock_open_right lock_outline lock_person lock_reset",
|
|
441
|
+
"login logo_dev logout looks looks_3 looks_4 looks_5 looks_6 looks_one looks_two loop loupe low_density",
|
|
442
|
+
"low_priority lowercase loyalty lte_mobiledata lte_mobiledata_badge lte_plus_mobiledata",
|
|
443
|
+
"lte_plus_mobiledata_badge luggage lunch_dining lyrics macro_auto macro_off magic_button magic_exchange",
|
|
444
|
+
"magic_tether magnification_large magnification_small magnify_docked magnify_fullscreen mail mail_asterisk",
|
|
445
|
+
"mail_lock mail_off mail_outline mail_shield male man man_2 man_3 man_4 manage_accounts manage_history",
|
|
446
|
+
"manage_search manga manufacturing map map_pin_heart map_pin_review map_search maps_home_work maps_ugc margin",
|
|
447
|
+
"mark_as_unread mark_chat_read mark_chat_unread mark_email_read mark_email_unread mark_unread_chat_alt markdown",
|
|
448
|
+
"markdown_copy markdown_paste markunread markunread_mailbox masked_transitions masked_transitions_add masks",
|
|
449
|
+
"massage match_case match_case_off match_word matter maximize meal_dinner meal_lunch measuring_tape",
|
|
450
|
+
"media_bluetooth_off media_bluetooth_on media_link media_output media_output_off mediation medical_information",
|
|
451
|
+
"medical_mask medical_services medication medication_liquid meeting_room memory memory_alt menstrual_health",
|
|
452
|
+
"menu menu_book menu_book_2 menu_open merge merge_type message metabolism metro mfg_nest_yale_lock mic",
|
|
453
|
+
"mic_alert mic_double mic_external_off mic_external_on mic_gear mic_none mic_off microbiology microwave",
|
|
454
|
+
"microwave_gen military_tech mimo mimo_disconnect mindfulness minimize minor_crash mintmark missed_video_call",
|
|
455
|
+
"missed_video_call_filled missing_controller mist mitre mixture_med mms mobile mobile_2 mobile_3 mobile_alert",
|
|
456
|
+
"mobile_arrow_down mobile_arrow_right mobile_arrow_up_right mobile_block mobile_camera mobile_camera_front",
|
|
457
|
+
"mobile_camera_rear mobile_cancel mobile_cast mobile_charge mobile_chat mobile_check mobile_code mobile_dock",
|
|
458
|
+
"mobile_dots mobile_friendly mobile_gear mobile_hand mobile_hand_left mobile_hand_left_off mobile_hand_off",
|
|
459
|
+
"mobile_info mobile_landscape mobile_layout mobile_lock_landscape mobile_lock_portrait mobile_loupe mobile_menu",
|
|
460
|
+
"mobile_off mobile_question mobile_rotate mobile_rotate_lock mobile_screen_share mobile_screensaver",
|
|
461
|
+
"mobile_sensor_hi mobile_sensor_lo mobile_share mobile_share_stack mobile_sound mobile_sound_2 mobile_sound_off",
|
|
462
|
+
"mobile_speaker mobile_tap mobile_text mobile_text_2 mobile_theft mobile_ticket mobile_unlock mobile_vibrate",
|
|
463
|
+
"mobile_wrench mobiledata_arrows mobiledata_off mode mode_comment mode_cool mode_cool_off mode_dual mode_edit",
|
|
464
|
+
"mode_edit_outline mode_fan mode_fan_2 mode_fan_off mode_heat mode_heat_cool mode_heat_off mode_night",
|
|
465
|
+
"mode_of_travel mode_off_on mode_standby model_training modeling monetization_on money money_bag money_off",
|
|
466
|
+
"money_off_csred money_range monitor monitor_heart monitor_weight monitor_weight_gain monitor_weight_loss",
|
|
467
|
+
"monitoring monochrome_photos monorail mood mood_bad mood_heart moon_stars mop moped moped_package more",
|
|
468
|
+
"more_down more_horiz more_time more_up more_vert mosque motion_blur motion_mode motion_photos_auto",
|
|
469
|
+
"motion_photos_off motion_photos_on motion_photos_pause motion_photos_paused motion_play motion_sensor_active",
|
|
470
|
+
"motion_sensor_alert motion_sensor_idle motion_sensor_urgent motorcycle mountain_flag mountain_steam mouse",
|
|
471
|
+
"mouse_lock mouse_lock_off move move_down move_group move_item move_location move_selection_down",
|
|
472
|
+
"move_selection_left move_selection_right move_selection_up move_to_inbox move_up moved_location movie",
|
|
473
|
+
"movie_creation movie_edit movie_edit_off movie_filter movie_info movie_off movie_speaker moving moving_beds",
|
|
474
|
+
"moving_ministry mp multicooker multiline_chart multimodal_hand_eye multiple_airports multiple_stop museum",
|
|
475
|
+
"music_cast music_history music_note music_note_2 music_note_add music_off music_video my_location mystery nat",
|
|
476
|
+
"nature nature_people navigate_before navigate_next navigation near_me near_me_disabled nearby nearby_error",
|
|
477
|
+
"nearby_off nephrology nest_audio nest_cam_floodlight nest_cam_indoor nest_cam_iq nest_cam_iq_outdoor",
|
|
478
|
+
"nest_cam_magnet_mount nest_cam_outdoor nest_cam_stand nest_cam_wall_mount nest_cam_wired_stand",
|
|
479
|
+
"nest_clock_farsight_analog nest_clock_farsight_digital nest_connect nest_detect nest_display nest_display_max",
|
|
480
|
+
"nest_doorbell_visitor nest_eco_leaf nest_farsight_cool nest_farsight_dual nest_farsight_eco nest_farsight_heat",
|
|
481
|
+
"nest_farsight_seasonal nest_farsight_weather nest_found_savings nest_gale_wifi nest_heat_link_e",
|
|
482
|
+
"nest_heat_link_gen_3 nest_hello_doorbell nest_locator_tag nest_mini nest_multi_room nest_protect nest_remote",
|
|
483
|
+
"nest_remote_comfort_sensor nest_secure_alarm nest_sunblock nest_tag nest_thermostat nest_thermostat_e_eu",
|
|
484
|
+
"nest_thermostat_gen_3 nest_thermostat_sensor nest_thermostat_sensor_eu nest_thermostat_zirconium_eu",
|
|
485
|
+
"nest_true_radiant nest_wake_on_approach nest_wake_on_press nest_wifi_gale nest_wifi_mistral nest_wifi_point",
|
|
486
|
+
"nest_wifi_point_vento nest_wifi_pro nest_wifi_pro_2 nest_wifi_router network_cell network_check",
|
|
487
|
+
"network_intel_node network_intelligence network_intelligence_history network_intelligence_update",
|
|
488
|
+
"network_locked network_manage network_node network_ping network_wifi network_wifi_1_bar",
|
|
489
|
+
"network_wifi_1_bar_locked network_wifi_2_bar network_wifi_2_bar_locked network_wifi_3_bar",
|
|
490
|
+
"network_wifi_3_bar_locked network_wifi_locked neurology new_label new_releases new_window news newsmode",
|
|
491
|
+
"newspaper newsstand next_plan next_week nfc nfc_off night_shelter night_sight_auto night_sight_auto_off",
|
|
492
|
+
"night_sight_max nightlife nightlight nightlight_round nights_stay no_accounts no_adult_content no_backpack",
|
|
493
|
+
"no_crash no_drinks no_encryption no_encryption_gmailerrorred no_flash no_food no_luggage no_meals",
|
|
494
|
+
"no_meeting_room no_photography no_sim no_sound no_stroller no_transfer noise_aware noise_control_off",
|
|
495
|
+
"noise_control_on nordic_walking north north_east north_west not_accessible not_accessible_forward",
|
|
496
|
+
"not_interested not_listed_location not_started note note_add note_alt note_stack note_stack_add notes",
|
|
497
|
+
"notification_add notification_audio notification_audio_off notification_important notification_multiple",
|
|
498
|
+
"notification_settings notification_sound notifications notifications_active notifications_none",
|
|
499
|
+
"notifications_off notifications_paused notifications_unread numbers nutrition ods odt offline_bolt offline_pin",
|
|
500
|
+
"offline_pin_off offline_share oil_barrel okonomiyaki on_device_training on_hub_device oncology ondemand_video",
|
|
501
|
+
"online_prediction onsen opacity open_in_browser open_in_full open_in_new open_in_new_down open_in_new_off",
|
|
502
|
+
"open_in_phone open_jam open_run open_with ophthalmology oral_disease orbit order_approve order_play orders",
|
|
503
|
+
"orthopedics other_admission other_houses outbound outbox outbox_alt outdoor_garden outdoor_grill outgoing_mail",
|
|
504
|
+
"outlet outlined_flag outpatient outpatient_med output output_circle oven oven_gen overview overview_key owl",
|
|
505
|
+
"oxygen_saturation p2p pace pacemaker package package_2 padding padel page_control page_footer page_header",
|
|
506
|
+
"page_info page_menu_ios pageless pages pageview paid palette pallet pan_tool pan_tool_alt pan_zoom panorama",
|
|
507
|
+
"panorama_fish_eye panorama_horizontal panorama_photosphere panorama_vertical panorama_wide_angle paragliding",
|
|
508
|
+
"parent_child_dining park parking_meter parking_sign parking_valet partly_cloudy_day partly_cloudy_night",
|
|
509
|
+
"partner_exchange partner_heart partner_reports party_mode passkey passport password password_2 password_2_off",
|
|
510
|
+
"patient_list pattern pause pause_circle pause_circle_filled pause_circle_outline pause_presentation payment",
|
|
511
|
+
"payment_arrow_down payment_card payments pedal_bike pediatrics pen_size_1 pen_size_2 pen_size_3 pen_size_4",
|
|
512
|
+
"pen_size_5 pending pending_actions pentagon people people_alt people_outline people_size_decrease",
|
|
513
|
+
"people_size_increase percent percent_discount performance_max pergola perm_camera_mic perm_contact_calendar",
|
|
514
|
+
"perm_data_setting perm_device_information perm_identity perm_media perm_phone_msg perm_scan_wifi person",
|
|
515
|
+
"person_2 person_3 person_4 person_add person_add_alt person_add_disabled person_alert person_apron person_book",
|
|
516
|
+
"person_cancel person_celebrate person_check person_edit person_filled person_heart person_off person_outline",
|
|
517
|
+
"person_pin person_pin_circle person_play person_raised_hand person_remove person_search person_shield",
|
|
518
|
+
"person_text personal_bag personal_bag_off personal_bag_question personal_injury personal_places personal_video",
|
|
519
|
+
"pest_control pest_control_rodent pet_supplies pets phishing phone phone_alt phone_android",
|
|
520
|
+
"phone_bluetooth_speaker phone_callback phone_cancel phone_disabled phone_enabled phone_forwarded phone_in_talk",
|
|
521
|
+
"phone_iphone phone_locked phone_missed phone_paused phonelink phonelink_erase phonelink_lock phonelink_off",
|
|
522
|
+
"phonelink_ring phonelink_ring_off phonelink_setup photo photo_album photo_auto_merge photo_camera",
|
|
523
|
+
"photo_camera_back photo_camera_front photo_filter photo_frame photo_library photo_prints",
|
|
524
|
+
"photo_size_select_actual photo_size_select_large photo_size_select_small php physical_therapy piano piano_off",
|
|
525
|
+
"pickleball picture_as_pdf picture_in_picture picture_in_picture_alt picture_in_picture_center",
|
|
526
|
+
"picture_in_picture_large picture_in_picture_medium picture_in_picture_mobile picture_in_picture_off",
|
|
527
|
+
"picture_in_picture_small pie_chart pie_chart_filled pie_chart_outline pie_chart_outlined pill pill_off pin",
|
|
528
|
+
"pin_drop pin_end pin_history pin_invoke pin_road pin_road_2 pinboard pinboard_unread pinch pinch_zoom_in",
|
|
529
|
+
"pinch_zoom_out pip pip_exit pivot_table_chart place place_item plagiarism plane_contrails planet",
|
|
530
|
+
"planner_banner_ad_pt planner_review play_arrow play_circle play_disabled play_for_work play_lesson play_music",
|
|
531
|
+
"play_pause play_shapes playground playground_2 playing_cards playlist_add playlist_add_check",
|
|
532
|
+
"playlist_add_check_circle playlist_add_circle playlist_play playlist_remove plug_connect plumbing plus_one",
|
|
533
|
+
"podcasts podiatry podium point_of_sale point_scan poker_chip policy policy_alert poll polyline polymer pool",
|
|
534
|
+
"portable_wifi_off portrait position_bottom_left position_bottom_right position_top_right post post_add",
|
|
535
|
+
"potted_plant power power_input power_off power_rounded power_settings_circle power_settings_new prayer_times",
|
|
536
|
+
"precision_manufacturing pregnancy pregnant_woman preliminary prescriptions present_to_all preview preview_off",
|
|
537
|
+
"price_change price_check print print_add print_connect print_disabled print_error print_lock priority",
|
|
538
|
+
"priority_high privacy privacy_tip private_connectivity problem procedure process_chart",
|
|
539
|
+
"production_quantity_limits productivity progress_activity prompt_suggestion propane propane_tank psychiatry",
|
|
540
|
+
"psychology psychology_alt public public_off publish published_with_changes pulmonology pulse_alert punch_clock",
|
|
541
|
+
"push_pin qr_code qr_code_2 qr_code_2_add qr_code_scanner query_builder query_stats question_answer",
|
|
542
|
+
"question_exchange question_mark queue queue_music queue_play_next quick_phrases quick_reference",
|
|
543
|
+
"quick_reference_all quick_reorder quickreply quiet_time quiet_time_active quiz r_mobiledata radar radio",
|
|
544
|
+
"radio_button_checked radio_button_partial radio_button_unchecked radiology railway_alert railway_alert_2 rainy",
|
|
545
|
+
"rainy_heavy rainy_light rainy_snow ramen_dining ramp_left ramp_right range_hood rate_review rate_review_rtl",
|
|
546
|
+
"raven raw_off raw_on read_more readiness_score real_estate_agent rear_camera rebase rebase_edit receipt",
|
|
547
|
+
"receipt_long receipt_long_off recent_actors recent_patient recenter recommend record_voice_over rectangle",
|
|
548
|
+
"rectangle_add recycling redeem redo reduce_capacity refresh regular_expression relax release_alert remember_me",
|
|
549
|
+
"reminder reminders_alt remote_gen remove remove_circle remove_circle_outline remove_done remove_from_queue",
|
|
550
|
+
"remove_moderator remove_red_eye remove_road remove_selection remove_shopping_cart reopen_window reorder",
|
|
551
|
+
"repartition repeat repeat_on repeat_one repeat_one_on replace_audio replace_image replace_video replay",
|
|
552
|
+
"replay_10 replay_30 replay_5 replay_circle_filled reply reply_all report report_gmailerrorred report_off",
|
|
553
|
+
"report_problem request_page request_quote reset_brightness reset_colors reset_exposure reset_focus reset_image",
|
|
554
|
+
"reset_iso reset_settings reset_shadow reset_shutter_speed reset_tv reset_white_balance reset_wrench resize",
|
|
555
|
+
"resize_window respiratory_rate responsive_layout rest_area restart_alt restaurant restaurant_menu restore",
|
|
556
|
+
"restore_from_trash restore_page resume reviews rewarded_ads rheumatology rib_cage rice_bowl right_click",
|
|
557
|
+
"right_panel_close right_panel_open ring_volume ring_volume_filled ripples road robot robot_2 rocket",
|
|
558
|
+
"rocket_launch roller_shades roller_shades_closed roller_skating roofing room room_preferences room_service",
|
|
559
|
+
"rotate_90_degrees_ccw rotate_90_degrees_cw rotate_auto rotate_left rotate_right roundabout_left",
|
|
560
|
+
"roundabout_right rounded_corner route router router_off routine rowing rss_feed rsvp rtt rubric rule",
|
|
561
|
+
"rule_folder rule_settings run_circle running_with_errors rv_hookup safety_check safety_check_off",
|
|
562
|
+
"safety_divider sailing salinity sanitizer satellite satellite_alt sauna save save_alt save_as save_clock",
|
|
563
|
+
"saved_search savings scale scan scan_delete scanner scatter_plot scene schedule schedule_send schema school",
|
|
564
|
+
"science science_off scooter score scoreboard screen_lock_landscape screen_lock_portrait screen_lock_rotation",
|
|
565
|
+
"screen_record screen_rotation screen_rotation_alt screen_rotation_up screen_search_desktop screen_share",
|
|
566
|
+
"screenshot screenshot_frame screenshot_frame_2 screenshot_keyboard screenshot_monitor screenshot_region",
|
|
567
|
+
"screenshot_tablet script scrollable_header scuba_diving sd sd_card sd_card_alert sd_storage sdk search",
|
|
568
|
+
"search_activity search_check search_check_2 search_gear search_hands_free search_insights search_off",
|
|
569
|
+
"seat_cool_left seat_cool_right seat_heat_left seat_heat_right seat_read seat_vent_left seat_vent_right",
|
|
570
|
+
"seat_window security security_key security_update security_update_good security_update_warning segment select",
|
|
571
|
+
"select_all select_check_box select_to_speak select_window select_window_2 select_window_off self_care",
|
|
572
|
+
"self_improvement sell sell_cloud send send_and_archive send_money send_time_extension send_to_mobile",
|
|
573
|
+
"sensor_door sensor_occupied sensor_window sensors sensors_krx sensors_krx_off sensors_off sentiment_calm",
|
|
574
|
+
"sentiment_content sentiment_dissatisfied sentiment_excited sentiment_extremely_dissatisfied",
|
|
575
|
+
"sentiment_frustrated sentiment_neutral sentiment_sad sentiment_satisfied sentiment_satisfied_alt",
|
|
576
|
+
"sentiment_stressed sentiment_very_dissatisfied sentiment_very_satisfied sentiment_worried serif server_person",
|
|
577
|
+
"service_toolbox set_meal settings settings_accessibility settings_account_box settings_alert",
|
|
578
|
+
"settings_applications settings_b_roll settings_backup_restore settings_bluetooth settings_brightness",
|
|
579
|
+
"settings_cell settings_cinematic_blur settings_ethernet settings_heart settings_input_antenna",
|
|
580
|
+
"settings_input_component settings_input_composite settings_input_hdmi settings_input_svideo",
|
|
581
|
+
"settings_motion_mode settings_night_sight settings_overscan settings_panorama settings_phone",
|
|
582
|
+
"settings_photo_camera settings_power settings_remote settings_screen settings_seating settings_slow_motion",
|
|
583
|
+
"settings_suggest settings_system_daydream settings_timelapse settings_video_camera settings_voice",
|
|
584
|
+
"settop_component severe_cold shades shades_closed shadow shadow_add shadow_minus shape_line shape_recognition",
|
|
585
|
+
"shapes share share_eta share_location share_off share_reviews share_windows shaved_ice sheets_rtl",
|
|
586
|
+
"shelf_auto_hide shelf_position shelves shield shield_card shield_lock shield_locked shield_moon shield_person",
|
|
587
|
+
"shield_question shield_radar shield_toggle shield_watch shield_with_heart shield_with_house shift shift_lock",
|
|
588
|
+
"shift_lock_off shoe_cleats shop shop_2 shop_two shopping_bag shopping_bag_speed shopping_basket shopping_cart",
|
|
589
|
+
"shopping_cart_checkout shopping_cart_off shoppingmode short_stay short_text shortcut show_chart shower shuffle",
|
|
590
|
+
"shuffle_on shutter_speed shutter_speed_add shutter_speed_minus sick side_navigation sign_language",
|
|
591
|
+
"sign_language_2 sign_language_off signal_cellular_0_bar signal_cellular_1_bar signal_cellular_2_bar",
|
|
592
|
+
"signal_cellular_3_bar signal_cellular_4_bar signal_cellular_add signal_cellular_alt signal_cellular_alt_1_bar",
|
|
593
|
+
"signal_cellular_alt_2_bar signal_cellular_alt_off signal_cellular_connected_no_internet_0_bar",
|
|
594
|
+
"signal_cellular_connected_no_internet_4_bar signal_cellular_no_sim signal_cellular_nodata signal_cellular_null",
|
|
595
|
+
"signal_cellular_off signal_cellular_pause signal_disconnected signal_wifi_0_bar signal_wifi_4_bar",
|
|
596
|
+
"signal_wifi_4_bar_lock signal_wifi_bad signal_wifi_connected_no_internet_4 signal_wifi_off",
|
|
597
|
+
"signal_wifi_statusbar_4_bar signal_wifi_statusbar_not_connected signal_wifi_statusbar_null signature signpost",
|
|
598
|
+
"sim_card sim_card_alert sim_card_download sim_card_lock simulation single_arrow single_bed sip siren",
|
|
599
|
+
"siren_check siren_open siren_question skateboarding skeleton skillet skillet_cooktop skip_next skip_previous",
|
|
600
|
+
"skull skull_list slab_serif sledding sleep sleep_score slide_library sliders slideshow slow_motion_video",
|
|
601
|
+
"smart_button smart_card_reader smart_card_reader_off smart_display smart_outlet smart_screen smart_toy",
|
|
602
|
+
"smartphone smartphone_camera smb_share smoke_free smoking_rooms sms sms_failed snail snippet_folder snooze",
|
|
603
|
+
"snowboarding snowflake snowing snowing_heavy snowmobile snowshoeing soap soba social_distance",
|
|
604
|
+
"social_leaderboard solar_power solo_dining sort sort_by_alpha sos sound_detection_dog_barking",
|
|
605
|
+
"sound_detection_glass_break sound_detection_loud_sound sound_sampler soundbar soup_kitchen source",
|
|
606
|
+
"source_environment source_notes south south_america south_east south_west spa space_bar space_dashboard",
|
|
607
|
+
"space_dashboard_2 spatial_audio spatial_audio_off spatial_gallery spatial_speaker spatial_tracking speaker",
|
|
608
|
+
"speaker_2 speaker_3 speaker_group speaker_notes speaker_notes_off speaker_phone special_character",
|
|
609
|
+
"specific_gravity speech_to_text speech_to_text_2 speed speed_0_25 speed_0_2x speed_0_5 speed_0_5x speed_0_75",
|
|
610
|
+
"speed_0_7x speed_1_2 speed_1_25 speed_1_2x speed_1_5 speed_1_5x speed_1_75 speed_1_7x speed_2 speed_2x speed_3",
|
|
611
|
+
"speed_4 speed_camera spellcheck split_scene split_scene_2 split_scene_down split_scene_left split_scene_right",
|
|
612
|
+
"split_scene_up splitscreen splitscreen_add splitscreen_bottom splitscreen_landscape splitscreen_landscape_add",
|
|
613
|
+
"splitscreen_left splitscreen_portrait splitscreen_right splitscreen_top splitscreen_vertical_add spo2 spoke",
|
|
614
|
+
"sports sports_and_outdoors sports_bar sports_baseball sports_basketball sports_cricket sports_esports",
|
|
615
|
+
"sports_football sports_golf sports_gymnastics sports_handball sports_hockey sports_kabaddi sports_martial_arts",
|
|
616
|
+
"sports_mma sports_motorsports sports_rugby sports_score sports_soccer sports_tennis sports_volleyball",
|
|
617
|
+
"sprinkler sprint sql square square_circle square_dot square_foot ssid_chart stack stack_group stack_hexagon",
|
|
618
|
+
"stack_off stack_star stacked_bar_chart stacked_email stacked_inbox stacked_line_chart stacks stadia_controller",
|
|
619
|
+
"stadium stairs stairs_2 star star_border star_border_purple500 star_half star_outline star_purple500 star_rate",
|
|
620
|
+
"star_rate_half star_shine stars stars_2 start stat_0 stat_1 stat_2 stat_3 stat_minus_1 stat_minus_2",
|
|
621
|
+
"stat_minus_3 stay_current_landscape stay_current_portrait stay_primary_landscape stay_primary_portrait",
|
|
622
|
+
"steering_wheel_cool steering_wheel_heat step step_into step_out step_over steppers steps stethoscope",
|
|
623
|
+
"stethoscope_arrow stethoscope_check sticker sticker_add sticky_note sticky_note_2 stock_media stockpot stop",
|
|
624
|
+
"stop_circle stop_screen_share storage store store_mall_directory storefront storm straight straighten strategy",
|
|
625
|
+
"stream stream_apps streetview stress_management strikethrough_s stroke_full stroke_partial stroller style",
|
|
626
|
+
"styler stylus stylus_brush stylus_fountain_pen stylus_highlighter stylus_laser_pointer stylus_note stylus_pen",
|
|
627
|
+
"stylus_pencil subdirectory_arrow_left subdirectory_arrow_right subheader subject subscript subscriptions",
|
|
628
|
+
"subtitles subtitles_gear subtitles_off subway subway_walk subwoofer summarize sunny sunny_snowing superscript",
|
|
629
|
+
"supervised_user_circle supervised_user_circle_off supervisor_account support support_agent surfing surgical",
|
|
630
|
+
"surround_sound swap_calls swap_driving_apps swap_driving_apps_wheel swap_horiz swap_horizontal_circle",
|
|
631
|
+
"swap_vert swap_vertical_circle sweep swipe swipe_down swipe_down_alt swipe_left swipe_left_2 swipe_left_alt",
|
|
632
|
+
"swipe_right swipe_right_2 swipe_right_alt swipe_up swipe_up_alt swipe_vertical switch switch_access",
|
|
633
|
+
"switch_access_2 switch_access_3 switch_access_shortcut switch_access_shortcut_add switch_account switch_camera",
|
|
634
|
+
"switch_left switch_off switch_right switch_video switches sword_rose swords symptoms synagogue sync sync_alt",
|
|
635
|
+
"sync_arrow_down sync_arrow_up sync_desktop sync_disabled sync_lock sync_problem sync_saved_locally",
|
|
636
|
+
"sync_saved_locally_off syringe system_security_update system_security_update_good",
|
|
637
|
+
"system_security_update_warning system_update system_update_alt tab tab_close tab_close_inactive",
|
|
638
|
+
"tab_close_right tab_duplicate tab_group tab_inactive tab_move tab_new_right tab_recent tab_search",
|
|
639
|
+
"tab_unselected table table_bar table_chart table_chart_view table_convert table_edit table_eye table_lamp",
|
|
640
|
+
"table_large table_restaurant table_rows table_rows_narrow table_sign table_view tablet tablet_android",
|
|
641
|
+
"tablet_camera tablet_mac tabs tactic tag tag_faces takeout_dining takeout_dining_2 tamper_detection_off",
|
|
642
|
+
"tamper_detection_on tap_and_play tapas target target_check task task_alt tatami_seat taunt taxi_alert",
|
|
643
|
+
"team_dashboard temp_preferences_custom temp_preferences_eco temple_buddhist temple_hindu tenancy terminal",
|
|
644
|
+
"terminal_2 terminal_add terrain text_ad text_ad_off text_compare text_decrease text_fields text_fields_alt",
|
|
645
|
+
"text_format text_increase text_rotate_up text_rotate_vertical text_rotation_angledown text_rotation_angleup",
|
|
646
|
+
"text_rotation_down text_rotation_none text_select_end text_select_jump_to_beginning text_select_jump_to_end",
|
|
647
|
+
"text_select_move_back_character text_select_move_back_word text_select_move_down",
|
|
648
|
+
"text_select_move_forward_character text_select_move_forward_word text_select_move_up text_select_start",
|
|
649
|
+
"text_snippet text_to_speech text_up textsms texture texture_add texture_minus theater_comedy theaters",
|
|
650
|
+
"thermometer thermometer_add thermometer_alert thermometer_gain thermometer_loss thermometer_minus thermostat",
|
|
651
|
+
"thermostat_arrow_down thermostat_arrow_up thermostat_auto thermostat_carbon things_to_do thread_unread",
|
|
652
|
+
"threat_intelligence thumb_down thumb_down_alt thumb_down_filled thumb_down_off thumb_down_off_alt thumb_up",
|
|
653
|
+
"thumb_up_alt thumb_up_filled thumb_up_off thumb_up_off_alt thumbnail_bar thumbs_up_double thumbs_up_down",
|
|
654
|
+
"thunderstorm tibia tibia_alt tile_large tile_medium tile_small tilt_arrow_down tilt_arrow_up time_auto",
|
|
655
|
+
"time_to_leave timelapse timeline timer timer_1 timer_10 timer_10_alt_1 timer_10_select timer_2 timer_3",
|
|
656
|
+
"timer_3_alt_1 timer_3_select timer_5 timer_5_shutter timer_arrow_down timer_arrow_up timer_off timer_pause",
|
|
657
|
+
"timer_play tips_and_updates tire_repair title titlecase toast toc today toggle_off toggle_on token toll",
|
|
658
|
+
"tonality tonality_2 toolbar tools_flat_head tools_installation_kit tools_ladder tools_level tools_phillips",
|
|
659
|
+
"tools_pliers_wire_stripper tools_power_drill tools_wrench tooltip tooltip_2 top_panel_close top_panel_open",
|
|
660
|
+
"topic tornado total_dissolved_solids touch_app touch_double touch_double_2 touch_long touch_triple",
|
|
661
|
+
"touchpad_mouse touchpad_mouse_off tour toys toys_and_games toys_fan track_changes trackpad_input",
|
|
662
|
+
"trackpad_input_2 trackpad_input_3 traffic traffic_jam trail_length trail_length_medium trail_length_short",
|
|
663
|
+
"train tram transcribe transfer_within_a_station transform transgender transit_enterexit transit_ticket",
|
|
664
|
+
"transition_chop transition_dissolve transition_fade transition_push transition_slide translate translate_indic",
|
|
665
|
+
"transportation travel travel_explore travel_luggage_and_bags trending_down trending_flat trending_up",
|
|
666
|
+
"triangle_circle trip trip_origin trolley trolley_cable_car trophy troubleshoot try tsunami tsv tty tune",
|
|
667
|
+
"tungsten turn_left turn_right turn_sharp_left turn_sharp_right turn_slight_left turn_slight_right turned_in",
|
|
668
|
+
"turned_in_not tv tv_displays tv_gen tv_guide tv_next tv_off tv_options_edit_channels tv_options_input_settings",
|
|
669
|
+
"tv_remote tv_signin tv_with_assistant two_pager two_pager_store two_wheeler type_specimen u_turn_left",
|
|
670
|
+
"u_turn_right udon ulna_radius ulna_radius_alt umbrella unarchive undereye undo unfold_less unfold_less_double",
|
|
671
|
+
"unfold_more unfold_more_double ungroup universal_currency universal_currency_alt universal_local unknown_2",
|
|
672
|
+
"unknown_5 unknown_7 unknown_document unknown_med unlicense unpaved_road unpin unpublished unsubscribe upcoming",
|
|
673
|
+
"update update_disabled upgrade upi_pay upload upload_2 upload_file uppercase urology usb usb_off",
|
|
674
|
+
"user_attributes vaccines vacuum vacuum_2 vacuum_2_on valve vape_free vaping_rooms variable_add variable_insert",
|
|
675
|
+
"variable_remove variables ventilator verified verified_off verified_user vertical_align_bottom",
|
|
676
|
+
"vertical_align_center vertical_align_top vertical_distribute vertical_shades vertical_shades_closed",
|
|
677
|
+
"vertical_split vibration video_call video_camera_back video_camera_back_add video_camera_front",
|
|
678
|
+
"video_camera_front_off video_chat video_file video_frame_copy video_frame_save video_label video_library",
|
|
679
|
+
"video_search video_settings video_stable video_template videocam videocam_alert videocam_off videogame_asset",
|
|
680
|
+
"videogame_asset_off view_agenda view_apps view_array view_carousel view_column view_column_2 view_comfy",
|
|
681
|
+
"view_comfy_alt view_compact view_compact_alt view_cozy view_day view_headline view_in_ar view_in_ar_new",
|
|
682
|
+
"view_in_ar_off view_kanban view_list view_module view_object_track view_quilt view_real_size view_sidebar",
|
|
683
|
+
"view_stream view_timeline view_week vignette vignette_2 villa visibility visibility_lock visibility_off",
|
|
684
|
+
"vital_signs vitals vo2_max voice_chat voice_chat_off voice_over_off voice_selection voice_selection_off",
|
|
685
|
+
"voicemail voicemail_2 volcano volume_down volume_down_alt volume_mute volume_off volume_up volunteer_activism",
|
|
686
|
+
"voting_chip vpn_key vpn_key_alert vpn_key_off vpn_lock vpn_lock_2 vr180_create2d vr180_create2d_off vrpano",
|
|
687
|
+
"walk_bike wall_art wall_lamp wallet wallpaper wallpaper_slideshow wand_shine wand_stars ward warehouse warning",
|
|
688
|
+
"warning_amber warning_off wash washoku watch watch_alert watch_arrow watch_arrow_down watch_button",
|
|
689
|
+
"watch_button_press watch_check watch_later watch_lock watch_off watch_screentime watch_vibration watch_wake",
|
|
690
|
+
"water water_bottle water_bottle_large water_damage water_do water_drop water_drops water_ec water_full",
|
|
691
|
+
"water_heater water_lock water_loss water_lux water_medium water_orp water_ph water_pump water_voc",
|
|
692
|
+
"waterfall_chart waves waving_hand wb_auto wb_cloudy wb_incandescent wb_iridescent wb_shade wb_sunny",
|
|
693
|
+
"wb_twilight wb_twilight_2 wc weather_hail weather_mix weather_snowy web web_asset web_asset_off web_stories",
|
|
694
|
+
"web_traffic webhook weekend weight west whatshot wheat wheelchair_pickup where_to_vote widget_medium",
|
|
695
|
+
"widget_menu widget_small widget_width widgets width width_full width_normal width_wide wifi wifi_1_bar",
|
|
696
|
+
"wifi_2_bar wifi_add wifi_calling wifi_calling_1 wifi_calling_2 wifi_calling_3 wifi_calling_bar_1",
|
|
697
|
+
"wifi_calling_bar_2 wifi_calling_bar_3 wifi_channel wifi_device wifi_find wifi_home wifi_lock wifi_notification",
|
|
698
|
+
"wifi_off wifi_password wifi_protected_setup wifi_proxy wifi_tethering wifi_tethering_error wifi_tethering_off",
|
|
699
|
+
"wind_power window window_closed window_open window_sensor windshield_defrost_auto windshield_defrost_front",
|
|
700
|
+
"windshield_defrost_rear windshield_heat_front wine_bar woman woman_2 work work_alert work_history work_off",
|
|
701
|
+
"work_outline work_update workflow workspace_premium workspaces workspaces_outline wounds_injuries wrap_text",
|
|
702
|
+
"wrist wrong_location wysiwyg x_circle y_circle yakitori yard yoshoku your_trips youtube_activity",
|
|
703
|
+
"youtube_searched_for zone_person_alert zone_person_idle zone_person_urgent zoom_in zoom_in_map zoom_out",
|
|
704
|
+
"zoom_out_map"
|
|
705
|
+
].join(" ").split(" ");
|
|
706
|
+
var MATERIAL_SYMBOLS = new Set(NAMES);
|
|
707
|
+
var toSymbolName = (name) => name.replace(/([a-z0-9])([A-Z])/g, "$1_$2").toLowerCase();
|
|
708
|
+
var isMaterialSymbol = (name) => MATERIAL_SYMBOLS.has(toSymbolName(name));
|
|
709
|
+
|
|
710
|
+
// src/validation/validator-helpers.ts
|
|
711
|
+
var COERCE_OUTPUT_TYPE = {
|
|
712
|
+
string: "STRING",
|
|
713
|
+
number: "NUMBER",
|
|
714
|
+
boolean: "BOOLEAN",
|
|
715
|
+
json: "STRING",
|
|
716
|
+
object: "OBJECT"
|
|
717
|
+
};
|
|
718
|
+
var COERCE_TYPE_FOR_DATA_TYPE = {
|
|
719
|
+
STRING: "string",
|
|
720
|
+
NUMBER: "number",
|
|
721
|
+
BOOLEAN: "boolean",
|
|
722
|
+
OBJECT: "object"
|
|
723
|
+
};
|
|
724
|
+
function suggestCoerceType(targetType) {
|
|
725
|
+
return COERCE_TYPE_FOR_DATA_TYPE[targetType] ?? "<type>";
|
|
726
|
+
}
|
|
727
|
+
function resolveNodeType(ast, instance) {
|
|
728
|
+
return ast.nodeTypes.find(
|
|
729
|
+
(nt) => nt.name === instance.nodeType || nt.functionName === instance.nodeType
|
|
730
|
+
);
|
|
731
|
+
}
|
|
732
|
+
function getOutgoing(ast, nodeId, portName) {
|
|
733
|
+
return ast.connections.filter((c) => {
|
|
734
|
+
if (c.from.node !== nodeId) return false;
|
|
735
|
+
if (portName && c.from.port !== portName) return false;
|
|
736
|
+
return true;
|
|
737
|
+
});
|
|
738
|
+
}
|
|
739
|
+
function getInstanceLocation(workflow, instanceId) {
|
|
740
|
+
const instance = workflow.instances.find((inst) => inst.id === instanceId);
|
|
741
|
+
return instance?.sourceLocation;
|
|
742
|
+
}
|
|
743
|
+
function getConnectionLocation(conn) {
|
|
744
|
+
return conn.sourceLocation;
|
|
745
|
+
}
|
|
746
|
+
function formatType(dataType, tsType) {
|
|
747
|
+
if (tsType) {
|
|
748
|
+
return `${tsType} (${dataType})`;
|
|
749
|
+
}
|
|
750
|
+
return dataType;
|
|
751
|
+
}
|
|
752
|
+
function normalizeTypeString(type) {
|
|
753
|
+
let n = type;
|
|
754
|
+
n = n.replace(/\s+/g, "");
|
|
755
|
+
n = n.replace(/Array<(.+?)>/g, "$1[]");
|
|
756
|
+
n = n.replace(/;(?=[}\]])/g, "");
|
|
757
|
+
n = n.toLowerCase();
|
|
758
|
+
return n;
|
|
759
|
+
}
|
|
760
|
+
function areMutuallyExclusive(sourceNodes, workflow, instanceMap) {
|
|
761
|
+
if (sourceNodes.length < 2) return false;
|
|
762
|
+
const reverseMap = /* @__PURE__ */ new Map();
|
|
763
|
+
for (const conn of workflow.connections) {
|
|
764
|
+
if (!reverseMap.has(conn.to.node)) {
|
|
765
|
+
reverseMap.set(conn.to.node, []);
|
|
766
|
+
}
|
|
767
|
+
reverseMap.get(conn.to.node).push({ fromNode: conn.from.node, fromPort: conn.from.port });
|
|
768
|
+
}
|
|
769
|
+
const findBranchAncestor = (nodeId) => {
|
|
770
|
+
const visited = /* @__PURE__ */ new Set();
|
|
771
|
+
const queue = [nodeId];
|
|
772
|
+
while (queue.length > 0) {
|
|
773
|
+
const current = queue.shift();
|
|
774
|
+
if (visited.has(current)) continue;
|
|
775
|
+
visited.add(current);
|
|
776
|
+
const incomingEdges = reverseMap.get(current);
|
|
777
|
+
if (!incomingEdges) continue;
|
|
778
|
+
for (const edge of incomingEdges) {
|
|
779
|
+
if (edge.fromPort === "onSuccess" || edge.fromPort === "onFailure") {
|
|
780
|
+
const parentNodeType = instanceMap.get(edge.fromNode);
|
|
781
|
+
if (parentNodeType?.hasSuccessPort && parentNodeType?.hasFailurePort) {
|
|
782
|
+
return { branchNode: edge.fromNode, branch: edge.fromPort };
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
queue.push(edge.fromNode);
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
return null;
|
|
789
|
+
};
|
|
790
|
+
const branchInfos = sourceNodes.map(findBranchAncestor);
|
|
791
|
+
if (branchInfos.some((info) => info === null)) return false;
|
|
792
|
+
const branchNode = branchInfos[0].branchNode;
|
|
793
|
+
if (!branchInfos.every((info) => info.branchNode === branchNode)) return false;
|
|
794
|
+
const branches = new Set(branchInfos.map((info) => info.branch));
|
|
795
|
+
return branches.size > 1;
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
// src/validation/rules/connections.ts
|
|
799
|
+
function didYouMean(name, candidates) {
|
|
800
|
+
const suggestions = findClosestMatches(name, candidates);
|
|
801
|
+
return suggestions.length > 0 ? ` Did you mean "${suggestions[0]}"?` : "";
|
|
802
|
+
}
|
|
803
|
+
function checkSourceNode(ctx, conn, instanceMap) {
|
|
804
|
+
const fromNode = conn.from.node;
|
|
805
|
+
if (isStartNode(fromNode) || isPseudoNode(fromNode) || instanceMap.has(fromNode)) return;
|
|
806
|
+
ctx.errors.push({
|
|
807
|
+
type: "error",
|
|
808
|
+
code: "UNKNOWN_SOURCE_NODE",
|
|
809
|
+
message: `Connection references unknown source node: "${fromNode}"${didYouMean(fromNode, [...instanceMap.keys()])}`,
|
|
810
|
+
connection: conn,
|
|
811
|
+
location: getConnectionLocation(conn)
|
|
812
|
+
});
|
|
813
|
+
}
|
|
814
|
+
function checkTargetNode(ctx, conn, instanceMap) {
|
|
815
|
+
const toNode = conn.to.node;
|
|
816
|
+
if (isExitNode(toNode) || instanceMap.has(toNode)) return;
|
|
817
|
+
ctx.errors.push({
|
|
818
|
+
type: "error",
|
|
819
|
+
code: "UNKNOWN_TARGET_NODE",
|
|
820
|
+
message: `Connection references unknown target node: "${toNode}"${didYouMean(toNode, [...instanceMap.keys()])}`,
|
|
821
|
+
connection: conn,
|
|
822
|
+
location: getConnectionLocation(conn)
|
|
823
|
+
});
|
|
824
|
+
}
|
|
825
|
+
function checkSourcePort(ctx, conn, instanceMap) {
|
|
826
|
+
const { node: fromNode, port: fromPort } = conn.from;
|
|
827
|
+
const sourceNode = instanceMap.get(fromNode);
|
|
828
|
+
if (!sourceNode || Object.prototype.hasOwnProperty.call(sourceNode.outputs, fromPort)) return;
|
|
829
|
+
ctx.errors.push({
|
|
830
|
+
type: "error",
|
|
831
|
+
code: "UNKNOWN_SOURCE_PORT",
|
|
832
|
+
message: `Node "${fromNode}" does not have output port "${fromPort}"${didYouMean(fromPort, Object.keys(sourceNode.outputs))}`,
|
|
833
|
+
node: fromNode,
|
|
834
|
+
connection: conn,
|
|
835
|
+
location: getConnectionLocation(conn)
|
|
836
|
+
});
|
|
837
|
+
}
|
|
838
|
+
function checkStartPort(ctx, workflow, conn) {
|
|
839
|
+
const { node: fromNode, port: fromPort } = conn.from;
|
|
840
|
+
const validStartPorts = /* @__PURE__ */ new Set(["execute", ...Object.keys(workflow.startPorts)]);
|
|
841
|
+
if (validStartPorts.has(fromPort)) return;
|
|
842
|
+
const suggestions = findClosestMatches(fromPort, Array.from(validStartPorts));
|
|
843
|
+
const hint = suggestions.length > 0 ? ` Did you mean "${suggestions[0]}"?` : `
|
|
844
|
+
Add '@param ${fromPort}' to the workflow JSDoc and include it in the params object:
|
|
845
|
+
(execute: boolean, params: { ${fromPort}: type, ... })`;
|
|
846
|
+
ctx.errors.push({
|
|
847
|
+
type: "error",
|
|
848
|
+
code: "UNKNOWN_SOURCE_PORT",
|
|
849
|
+
message: `Start node does not have output port "${fromPort}".${hint}`,
|
|
850
|
+
node: fromNode,
|
|
851
|
+
connection: conn,
|
|
852
|
+
location: getConnectionLocation(conn)
|
|
853
|
+
});
|
|
854
|
+
}
|
|
855
|
+
function checkTargetPort(ctx, conn, instanceMap) {
|
|
856
|
+
const { node: toNode, port: toPort } = conn.to;
|
|
857
|
+
const targetNode = instanceMap.get(toNode);
|
|
858
|
+
if (!targetNode || Object.prototype.hasOwnProperty.call(targetNode.inputs, toPort)) return;
|
|
859
|
+
ctx.errors.push({
|
|
860
|
+
type: "error",
|
|
861
|
+
code: "UNKNOWN_TARGET_PORT",
|
|
862
|
+
message: `Node "${toNode}" does not have input port "${toPort}"${didYouMean(toPort, Object.keys(targetNode.inputs))}`,
|
|
863
|
+
node: toNode,
|
|
864
|
+
connection: conn,
|
|
865
|
+
location: getConnectionLocation(conn)
|
|
866
|
+
});
|
|
867
|
+
}
|
|
868
|
+
function checkExitPort(ctx, workflow, conn) {
|
|
869
|
+
const { node: toNode, port: toPort } = conn.to;
|
|
870
|
+
const validExitPorts = /* @__PURE__ */ new Set(["onSuccess", "onFailure", ...Object.keys(workflow.exitPorts)]);
|
|
871
|
+
if (validExitPorts.has(toPort)) return;
|
|
872
|
+
ctx.errors.push({
|
|
873
|
+
type: "error",
|
|
874
|
+
code: "UNKNOWN_TARGET_PORT",
|
|
875
|
+
message: `Exit node does not have input port "${toPort}"${didYouMean(toPort, Array.from(validExitPorts))}`,
|
|
876
|
+
node: toNode,
|
|
877
|
+
connection: conn,
|
|
878
|
+
location: getConnectionLocation(conn)
|
|
879
|
+
});
|
|
880
|
+
}
|
|
881
|
+
function validateConnections(ctx, workflow, instanceMap) {
|
|
882
|
+
workflow.connections.forEach((conn) => {
|
|
883
|
+
checkSourceNode(ctx, conn, instanceMap);
|
|
884
|
+
checkTargetNode(ctx, conn, instanceMap);
|
|
885
|
+
if (isStartNode(conn.from.node)) {
|
|
886
|
+
checkStartPort(ctx, workflow, conn);
|
|
887
|
+
} else {
|
|
888
|
+
checkSourcePort(ctx, conn, instanceMap);
|
|
889
|
+
}
|
|
890
|
+
if (isExitNode(conn.to.node)) {
|
|
891
|
+
checkExitPort(ctx, workflow, conn);
|
|
892
|
+
} else {
|
|
893
|
+
checkTargetPort(ctx, conn, instanceMap);
|
|
894
|
+
}
|
|
895
|
+
});
|
|
896
|
+
}
|
|
897
|
+
function validateDuplicateConnections(ctx, workflow) {
|
|
898
|
+
const seen = /* @__PURE__ */ new Set();
|
|
899
|
+
for (const conn of workflow.connections) {
|
|
900
|
+
const key = `${conn.from.node}.${conn.from.port}->${conn.to.node}.${conn.to.port}`;
|
|
901
|
+
if (seen.has(key)) {
|
|
902
|
+
ctx.errors.push({
|
|
903
|
+
type: "error",
|
|
904
|
+
code: "DUPLICATE_CONNECTION",
|
|
905
|
+
message: `Duplicate connection: ${key}`,
|
|
906
|
+
connection: conn,
|
|
907
|
+
location: getConnectionLocation(conn)
|
|
908
|
+
});
|
|
909
|
+
}
|
|
910
|
+
seen.add(key);
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
function validateMultipleInputConnections(ctx, workflow, instanceMap) {
|
|
914
|
+
const inputConnections = /* @__PURE__ */ new Map();
|
|
915
|
+
for (const conn of workflow.connections) {
|
|
916
|
+
const targetKey = `${conn.to.node}.${conn.to.port}`;
|
|
917
|
+
if (isExitNode(conn.to.node)) continue;
|
|
918
|
+
if (conn.derived) continue;
|
|
919
|
+
const targetNodeType = instanceMap.get(conn.to.node);
|
|
920
|
+
if (!targetNodeType) continue;
|
|
921
|
+
if (!isStartNode(conn.from.node) && !isPseudoNode(conn.from.node) && !instanceMap.has(conn.from.node)) continue;
|
|
922
|
+
const targetPortDef = targetNodeType.inputs[conn.to.port];
|
|
923
|
+
if (targetPortDef?.dataType === "STEP") continue;
|
|
924
|
+
if (targetPortDef?.mergeStrategy) continue;
|
|
925
|
+
if (!inputConnections.has(targetKey)) {
|
|
926
|
+
inputConnections.set(targetKey, []);
|
|
927
|
+
}
|
|
928
|
+
inputConnections.get(targetKey).push(conn);
|
|
929
|
+
}
|
|
930
|
+
for (const [, connections] of inputConnections) {
|
|
931
|
+
if (connections.length > 1) {
|
|
932
|
+
const [firstConn] = connections;
|
|
933
|
+
const sources = connections.map((c) => `${c.from.node}.${c.from.port}`).join(", ");
|
|
934
|
+
ctx.errors.push({
|
|
935
|
+
type: "error",
|
|
936
|
+
code: "MULTIPLE_CONNECTIONS_TO_INPUT",
|
|
937
|
+
message: `Input port "${firstConn.to.port}" on node "${firstConn.to.node}" has ${connections.length} connections (${sources}). Only one value can be received.`,
|
|
938
|
+
node: firstConn.to.node,
|
|
939
|
+
connection: firstConn,
|
|
940
|
+
location: getConnectionLocation(firstConn)
|
|
941
|
+
});
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
// src/validation/type-checker.ts
|
|
947
|
+
var SAFE_COERCIONS = [
|
|
948
|
+
["NUMBER", "STRING"],
|
|
949
|
+
["BOOLEAN", "STRING"]
|
|
950
|
+
];
|
|
951
|
+
function isRuntimeCoercible(sourceText, targetText) {
|
|
952
|
+
const sourceUpper = sourceText.toUpperCase();
|
|
953
|
+
const targetUpper = targetText.toUpperCase();
|
|
954
|
+
for (const [from, to] of SAFE_COERCIONS) {
|
|
955
|
+
if (sourceUpper === from && targetUpper === to) {
|
|
956
|
+
return true;
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
return false;
|
|
960
|
+
}
|
|
961
|
+
var OPAQUE_OBJECT_TYPES = /* @__PURE__ */ new Set([
|
|
962
|
+
"object",
|
|
963
|
+
"{}",
|
|
964
|
+
"Record<string,unknown>",
|
|
965
|
+
"Record<string,any>",
|
|
966
|
+
"{[key:string]:unknown}",
|
|
967
|
+
"{[key:string]:any}",
|
|
968
|
+
"{[k:string]:unknown}",
|
|
969
|
+
"{[k:string]:any}"
|
|
970
|
+
]);
|
|
971
|
+
function isOpaqueObjectType(typeText) {
|
|
972
|
+
return OPAQUE_OBJECT_TYPES.has(typeText.replace(/\s+/g, ""));
|
|
973
|
+
}
|
|
974
|
+
function checkTypeCompatibilityFromStrings(sourceText, targetText) {
|
|
975
|
+
if (sourceText === targetText) {
|
|
976
|
+
return {
|
|
977
|
+
isCompatible: true,
|
|
978
|
+
reason: "exact",
|
|
979
|
+
sourceType: sourceText,
|
|
980
|
+
targetType: targetText
|
|
981
|
+
};
|
|
982
|
+
}
|
|
983
|
+
if (sourceText === "any" || targetText === "any") {
|
|
984
|
+
return {
|
|
985
|
+
isCompatible: true,
|
|
986
|
+
reason: "assignable",
|
|
987
|
+
sourceType: sourceText,
|
|
988
|
+
targetType: targetText
|
|
989
|
+
};
|
|
990
|
+
}
|
|
991
|
+
if (isOpaqueObjectType(sourceText) || isOpaqueObjectType(targetText) || targetText.trim() === "unknown") {
|
|
992
|
+
return {
|
|
993
|
+
isCompatible: true,
|
|
994
|
+
reason: "assignable",
|
|
995
|
+
sourceType: sourceText,
|
|
996
|
+
targetType: targetText
|
|
997
|
+
};
|
|
998
|
+
}
|
|
999
|
+
if (isRuntimeCoercible(sourceText, targetText)) {
|
|
1000
|
+
return {
|
|
1001
|
+
isCompatible: true,
|
|
1002
|
+
reason: "coercible",
|
|
1003
|
+
sourceType: sourceText,
|
|
1004
|
+
targetType: targetText
|
|
1005
|
+
};
|
|
1006
|
+
}
|
|
1007
|
+
return {
|
|
1008
|
+
isCompatible: false,
|
|
1009
|
+
reason: "incompatible",
|
|
1010
|
+
sourceType: sourceText,
|
|
1011
|
+
targetType: targetText,
|
|
1012
|
+
errorMessage: `Type '${sourceText}' is not assignable to type '${targetText}'`
|
|
1013
|
+
};
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
// src/validation/rules/type-compatibility.ts
|
|
1017
|
+
var LOSSY_COERCIONS = [
|
|
1018
|
+
["STRING", "NUMBER", "May result in NaN if string is not a valid number"],
|
|
1019
|
+
["STRING", "BOOLEAN", "Will use JavaScript truthy/falsy conversion"],
|
|
1020
|
+
["OBJECT", "STRING", "Will use JSON.stringify()"],
|
|
1021
|
+
["ARRAY", "STRING", "Will use JSON.stringify()"]
|
|
1022
|
+
];
|
|
1023
|
+
var UNUSUAL_COERCIONS = [
|
|
1024
|
+
["NUMBER", "BOOLEAN", "Will use JavaScript truthy/falsy conversion (0 = false, non-zero = true)"],
|
|
1025
|
+
["BOOLEAN", "NUMBER", "Will convert false to 0, true to 1"],
|
|
1026
|
+
["STRING", "OBJECT", "May fail if string is not valid JSON"],
|
|
1027
|
+
["STRING", "ARRAY", "May fail if string is not valid JSON array"]
|
|
1028
|
+
];
|
|
1029
|
+
function resolveTypedConnection(conn, instanceMap) {
|
|
1030
|
+
const { node: fromNode, port: fromPort } = conn.from;
|
|
1031
|
+
const { node: toNode, port: toPort } = conn.to;
|
|
1032
|
+
const location = getConnectionLocation(conn);
|
|
1033
|
+
if (conn.derived) return null;
|
|
1034
|
+
if (isStartNode(fromNode) || isExitNode(toNode)) return null;
|
|
1035
|
+
const sourceNode = instanceMap.get(fromNode);
|
|
1036
|
+
const targetNode = instanceMap.get(toNode);
|
|
1037
|
+
if (!sourceNode || !targetNode) return null;
|
|
1038
|
+
const source = sourceNode.outputs[fromPort];
|
|
1039
|
+
const target = targetNode.inputs[toPort];
|
|
1040
|
+
if (!source || !target) return null;
|
|
1041
|
+
return { conn, fromNode, fromPort, toNode, toPort, source, target, location };
|
|
1042
|
+
}
|
|
1043
|
+
function reportTypeIssue(ctx, strictTypes, issue) {
|
|
1044
|
+
if (strictTypes) {
|
|
1045
|
+
ctx.errors.push({ ...issue, type: "error", code: "TYPE_INCOMPATIBLE" });
|
|
1046
|
+
} else {
|
|
1047
|
+
ctx.warnings.push(issue);
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
function checkStepPorts(ctx, c) {
|
|
1051
|
+
const sourceType = c.source.dataType;
|
|
1052
|
+
const targetType = c.target.dataType;
|
|
1053
|
+
if (sourceType === "STEP" && targetType !== "STEP") {
|
|
1054
|
+
ctx.errors.push({
|
|
1055
|
+
type: "error",
|
|
1056
|
+
code: "STEP_PORT_TYPE_MISMATCH",
|
|
1057
|
+
message: `STEP port "${c.fromPort}" on node "${c.fromNode}" cannot connect to non-STEP port "${c.toPort}" (${formatType(targetType, c.target.tsType)}) on node "${c.toNode}"`,
|
|
1058
|
+
connection: c.conn,
|
|
1059
|
+
location: c.location
|
|
1060
|
+
});
|
|
1061
|
+
return true;
|
|
1062
|
+
}
|
|
1063
|
+
if (targetType === "STEP" && sourceType !== "STEP") {
|
|
1064
|
+
ctx.errors.push({
|
|
1065
|
+
type: "error",
|
|
1066
|
+
code: "STEP_PORT_TYPE_MISMATCH",
|
|
1067
|
+
message: `Non-STEP port "${c.fromPort}" (${formatType(sourceType, c.source.tsType)}) on node "${c.fromNode}" cannot connect to STEP port "${c.toPort}" on node "${c.toNode}"`,
|
|
1068
|
+
connection: c.conn,
|
|
1069
|
+
location: c.location
|
|
1070
|
+
});
|
|
1071
|
+
return true;
|
|
1072
|
+
}
|
|
1073
|
+
return sourceType === "STEP" && targetType === "STEP";
|
|
1074
|
+
}
|
|
1075
|
+
function checkCoerceOnFunction(ctx, c) {
|
|
1076
|
+
const { coerce } = c.conn;
|
|
1077
|
+
if (!coerce || c.source.dataType !== "FUNCTION" && c.target.dataType !== "FUNCTION") return false;
|
|
1078
|
+
ctx.errors.push({
|
|
1079
|
+
type: "error",
|
|
1080
|
+
code: "COERCE_ON_FUNCTION_PORT",
|
|
1081
|
+
message: `Coercion \`as ${coerce}\` cannot be used on FUNCTION ports in connection "${c.fromNode}.${c.fromPort}" \u2192 "${c.toNode}.${c.toPort}". FUNCTION values cannot be meaningfully coerced.`,
|
|
1082
|
+
connection: c.conn,
|
|
1083
|
+
location: c.location
|
|
1084
|
+
});
|
|
1085
|
+
return true;
|
|
1086
|
+
}
|
|
1087
|
+
function checkSameType(ctx, c) {
|
|
1088
|
+
const sourceType = c.source.dataType;
|
|
1089
|
+
if (sourceType !== c.target.dataType) return false;
|
|
1090
|
+
if (c.conn.coerce) {
|
|
1091
|
+
ctx.warnings.push({
|
|
1092
|
+
type: "warning",
|
|
1093
|
+
code: "REDUNDANT_COERCE",
|
|
1094
|
+
message: `Coercion \`as ${c.conn.coerce}\` on connection "${c.fromNode}.${c.fromPort}" \u2192 "${c.toNode}.${c.toPort}" is redundant because source and target are both ${sourceType}.`,
|
|
1095
|
+
connection: c.conn,
|
|
1096
|
+
location: c.location
|
|
1097
|
+
});
|
|
1098
|
+
return true;
|
|
1099
|
+
}
|
|
1100
|
+
const sourceTs = c.source.tsType;
|
|
1101
|
+
const targetTs = c.target.tsType;
|
|
1102
|
+
if (sourceType === "OBJECT" && sourceTs && targetTs && normalizeTypeString(sourceTs) !== normalizeTypeString(targetTs)) {
|
|
1103
|
+
if (!checkTypeCompatibilityFromStrings(sourceTs, targetTs).isCompatible) {
|
|
1104
|
+
ctx.warnings.push({
|
|
1105
|
+
type: "warning",
|
|
1106
|
+
code: "OBJECT_TYPE_MISMATCH",
|
|
1107
|
+
message: `Structural type mismatch: ${c.fromNode}.${c.fromPort} outputs "${sourceTs}" but ${c.toNode}.${c.toPort} expects "${targetTs}". Verify the object shapes are compatible.`,
|
|
1108
|
+
connection: c.conn,
|
|
1109
|
+
location: c.location
|
|
1110
|
+
});
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
return true;
|
|
1114
|
+
}
|
|
1115
|
+
function checkExplicitCoerce(ctx, strictTypes, c) {
|
|
1116
|
+
const { coerce } = c.conn;
|
|
1117
|
+
if (!coerce) return false;
|
|
1118
|
+
const producedType = COERCE_OUTPUT_TYPE[coerce];
|
|
1119
|
+
const targetType = c.target.dataType;
|
|
1120
|
+
if (producedType === targetType) return true;
|
|
1121
|
+
reportTypeIssue(ctx, strictTypes, {
|
|
1122
|
+
type: "warning",
|
|
1123
|
+
code: "COERCE_TYPE_MISMATCH",
|
|
1124
|
+
message: `Coercion \`as ${coerce}\` produces ${producedType} but target port "${c.toPort}" on "${c.toNode}" expects ${targetType}. Use \`as ${suggestCoerceType(targetType)}\` instead.`,
|
|
1125
|
+
connection: c.conn,
|
|
1126
|
+
location: c.location
|
|
1127
|
+
});
|
|
1128
|
+
return true;
|
|
1129
|
+
}
|
|
1130
|
+
function checkImplicitCoercion(ctx, strictTypes, c) {
|
|
1131
|
+
const sourceType = c.source.dataType;
|
|
1132
|
+
const targetType = c.target.dataType;
|
|
1133
|
+
const from = formatType(sourceType, c.source.tsType);
|
|
1134
|
+
const to = formatType(targetType, c.target.tsType);
|
|
1135
|
+
const route = `${c.fromNode}.${c.fromPort} \u2192 ${c.toNode}.${c.toPort}`;
|
|
1136
|
+
if (SAFE_COERCIONS.some(([s, t]) => sourceType === s && targetType === t)) return;
|
|
1137
|
+
const lossy = LOSSY_COERCIONS.find(([s, t]) => sourceType === s && targetType === t);
|
|
1138
|
+
if (lossy) {
|
|
1139
|
+
reportTypeIssue(ctx, strictTypes, {
|
|
1140
|
+
type: "warning",
|
|
1141
|
+
code: "LOSSY_TYPE_COERCION",
|
|
1142
|
+
message: `Lossy type coercion from ${from} to ${to} in connection ${route}. ${lossy[2]}. Add @strictTypes to your workflow annotation to enforce type safety.`,
|
|
1143
|
+
connection: c.conn,
|
|
1144
|
+
location: c.location
|
|
1145
|
+
});
|
|
1146
|
+
return;
|
|
1147
|
+
}
|
|
1148
|
+
const unusual = UNUSUAL_COERCIONS.find(([s, t]) => sourceType === s && targetType === t);
|
|
1149
|
+
if (unusual) {
|
|
1150
|
+
reportTypeIssue(ctx, strictTypes, {
|
|
1151
|
+
type: "warning",
|
|
1152
|
+
code: "UNUSUAL_TYPE_COERCION",
|
|
1153
|
+
message: `Unusual type coercion from ${from} to ${to} in connection ${route}. ${unusual[2]}.`,
|
|
1154
|
+
connection: c.conn,
|
|
1155
|
+
location: c.location
|
|
1156
|
+
});
|
|
1157
|
+
return;
|
|
1158
|
+
}
|
|
1159
|
+
reportTypeIssue(ctx, strictTypes, {
|
|
1160
|
+
type: "warning",
|
|
1161
|
+
code: "TYPE_MISMATCH",
|
|
1162
|
+
message: `Type mismatch in connection ${c.fromNode}.${c.fromPort} (${from}) \u2192 ${c.toNode}.${c.toPort} (${to}). Runtime coercion will be attempted.`,
|
|
1163
|
+
connection: c.conn,
|
|
1164
|
+
location: c.location
|
|
1165
|
+
});
|
|
1166
|
+
}
|
|
1167
|
+
function validateTypeCompatibility(ctx, workflow, instanceMap) {
|
|
1168
|
+
const strictTypes = ctx.strictMode || workflow.options?.strictTypes === true;
|
|
1169
|
+
workflow.connections.forEach((conn) => {
|
|
1170
|
+
const c = resolveTypedConnection(conn, instanceMap);
|
|
1171
|
+
if (!c) return;
|
|
1172
|
+
if (checkStepPorts(ctx, c)) return;
|
|
1173
|
+
if (checkCoerceOnFunction(ctx, c)) return;
|
|
1174
|
+
if (checkSameType(ctx, c)) return;
|
|
1175
|
+
if (c.source.dataType === "ANY" || c.target.dataType === "ANY") return;
|
|
1176
|
+
if (checkExplicitCoerce(ctx, strictTypes, c)) return;
|
|
1177
|
+
checkImplicitCoercion(ctx, strictTypes, c);
|
|
1178
|
+
});
|
|
1179
|
+
}
|
|
1180
|
+
|
|
1181
|
+
// src/validation/rules/data-flow.ts
|
|
1182
|
+
function warnUnusedOutputPorts(ctx, workflow, instanceMap) {
|
|
1183
|
+
const connectedOutputPorts = /* @__PURE__ */ new Set();
|
|
1184
|
+
workflow.connections.forEach((conn) => {
|
|
1185
|
+
connectedOutputPorts.add(`${conn.from.node}.${conn.from.port}`);
|
|
1186
|
+
});
|
|
1187
|
+
instanceMap.forEach((nodeType, instanceId) => {
|
|
1188
|
+
Object.keys(nodeType.outputs).forEach((portName) => {
|
|
1189
|
+
const portDef = nodeType.outputs[portName];
|
|
1190
|
+
if (portDef.isControlFlow || portDef.failure) return;
|
|
1191
|
+
if (portDef.scope) return;
|
|
1192
|
+
if (connectedOutputPorts.has(`${instanceId}.${portName}`)) return;
|
|
1193
|
+
ctx.warnings.push({
|
|
1194
|
+
type: "warning",
|
|
1195
|
+
code: "UNUSED_OUTPUT_PORT",
|
|
1196
|
+
message: `Output port "${portName}" of node "${instanceId}" is never connected. Data will be discarded.`,
|
|
1197
|
+
node: instanceId,
|
|
1198
|
+
location: getInstanceLocation(workflow, instanceId)
|
|
1199
|
+
});
|
|
1200
|
+
});
|
|
1201
|
+
});
|
|
1202
|
+
}
|
|
1203
|
+
function groupExitConnections(workflow) {
|
|
1204
|
+
const exitPortConnections = /* @__PURE__ */ new Map();
|
|
1205
|
+
workflow.connections.forEach((conn) => {
|
|
1206
|
+
if (isExitNode(conn.to.node)) {
|
|
1207
|
+
const port = conn.to.port;
|
|
1208
|
+
if (!exitPortConnections.has(port)) {
|
|
1209
|
+
exitPortConnections.set(port, []);
|
|
1210
|
+
}
|
|
1211
|
+
exitPortConnections.get(port).push(conn);
|
|
1212
|
+
}
|
|
1213
|
+
});
|
|
1214
|
+
return exitPortConnections;
|
|
1215
|
+
}
|
|
1216
|
+
function warnUnreachableExitPorts(ctx, workflow, exitPortConnections) {
|
|
1217
|
+
Object.entries(workflow.exitPorts).forEach(([portName, portDef]) => {
|
|
1218
|
+
if (portDef.isControlFlow) return;
|
|
1219
|
+
if (exitPortConnections.has(portName)) return;
|
|
1220
|
+
ctx.warnings.push({
|
|
1221
|
+
type: "warning",
|
|
1222
|
+
code: "UNREACHABLE_EXIT_PORT",
|
|
1223
|
+
message: `Exit port "${portName}" has no incoming connection. Return value will be undefined.`
|
|
1224
|
+
});
|
|
1225
|
+
});
|
|
1226
|
+
}
|
|
1227
|
+
function warnMultipleExitConnections(ctx, workflow, instanceMap, exitPortConnections) {
|
|
1228
|
+
exitPortConnections.forEach((connections, portName) => {
|
|
1229
|
+
if (connections.length <= 1) return;
|
|
1230
|
+
const exitPort = workflow.exitPorts[portName];
|
|
1231
|
+
if (exitPort?.isControlFlow || exitPort?.dataType === "STEP") return;
|
|
1232
|
+
if (areMutuallyExclusive(connections.map((c) => c.from.node), workflow, instanceMap)) return;
|
|
1233
|
+
const sources = connections.map((c) => `${c.from.node}.${c.from.port}`).join(", ");
|
|
1234
|
+
ctx.warnings.push({
|
|
1235
|
+
type: "warning",
|
|
1236
|
+
code: "MULTIPLE_EXIT_CONNECTIONS",
|
|
1237
|
+
message: `Exit port "${portName}" has ${connections.length} incoming connections (${sources}). Only one value will be used - consider using separate Exit ports.`
|
|
1238
|
+
});
|
|
1239
|
+
});
|
|
1240
|
+
}
|
|
1241
|
+
function checkHttpRouteParams(ctx, workflow) {
|
|
1242
|
+
const paramNames = new Set(Object.keys(workflow.startPorts).filter((p) => p !== "execute"));
|
|
1243
|
+
for (const route of workflow.options?.http ?? []) {
|
|
1244
|
+
for (const seg of route.path.split("/")) {
|
|
1245
|
+
if (!seg.startsWith(":")) continue;
|
|
1246
|
+
const name = seg.slice(1);
|
|
1247
|
+
if (!paramNames.has(name)) {
|
|
1248
|
+
ctx.errors.push({
|
|
1249
|
+
type: "error",
|
|
1250
|
+
code: "HTTP_PARAM_UNKNOWN",
|
|
1251
|
+
message: `@http ${route.method} ${route.path}: ":${name}" is not a parameter of this workflow${paramNames.size ? ` (parameters: ${[...paramNames].join(", ")})` : ""}.`
|
|
1252
|
+
});
|
|
1253
|
+
}
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1257
|
+
function validateDataFlow(ctx, workflow, instanceMap) {
|
|
1258
|
+
warnUnusedOutputPorts(ctx, workflow, instanceMap);
|
|
1259
|
+
const exitPortConnections = groupExitConnections(workflow);
|
|
1260
|
+
warnUnreachableExitPorts(ctx, workflow, exitPortConnections);
|
|
1261
|
+
warnMultipleExitConnections(ctx, workflow, instanceMap, exitPortConnections);
|
|
1262
|
+
checkHttpRouteParams(ctx, workflow);
|
|
1263
|
+
}
|
|
1264
|
+
|
|
1265
|
+
// src/validation/rules/cycles.ts
|
|
1266
|
+
function groupInstancesByLayer(workflow) {
|
|
1267
|
+
const instancesByParent = /* @__PURE__ */ new Map();
|
|
1268
|
+
instancesByParent.set(null, []);
|
|
1269
|
+
for (const instance of workflow.instances) {
|
|
1270
|
+
const parentId = instance.parent?.id || null;
|
|
1271
|
+
if (!instancesByParent.has(parentId)) {
|
|
1272
|
+
instancesByParent.set(parentId, []);
|
|
1273
|
+
}
|
|
1274
|
+
instancesByParent.get(parentId).push(instance);
|
|
1275
|
+
}
|
|
1276
|
+
return instancesByParent;
|
|
1277
|
+
}
|
|
1278
|
+
function groupConnectionsByLayer(workflow) {
|
|
1279
|
+
const connectionsByParent = /* @__PURE__ */ new Map();
|
|
1280
|
+
connectionsByParent.set(null, []);
|
|
1281
|
+
for (const connection of workflow.connections) {
|
|
1282
|
+
const sourceInstance = workflow.instances.find((n) => n.id === connection.from.node);
|
|
1283
|
+
const targetInstance = workflow.instances.find((n) => n.id === connection.to.node);
|
|
1284
|
+
if (!sourceInstance || !targetInstance) continue;
|
|
1285
|
+
const sourceParent = sourceInstance.parent?.id || null;
|
|
1286
|
+
const targetParent = targetInstance.parent?.id || null;
|
|
1287
|
+
if (sourceParent === targetParent) {
|
|
1288
|
+
if (!connectionsByParent.has(sourceParent)) {
|
|
1289
|
+
connectionsByParent.set(sourceParent, []);
|
|
1290
|
+
}
|
|
1291
|
+
connectionsByParent.get(sourceParent).push(connection);
|
|
1292
|
+
}
|
|
1293
|
+
}
|
|
1294
|
+
return connectionsByParent;
|
|
1295
|
+
}
|
|
1296
|
+
function reportCycle(search, nodeName, path) {
|
|
1297
|
+
const cyclePath = [...path.slice(path.indexOf(nodeName)), nodeName];
|
|
1298
|
+
const cycleKey = [...cyclePath.slice(0, -1)].sort().join(",");
|
|
1299
|
+
if (search.reportedCycles.has(cycleKey)) return;
|
|
1300
|
+
search.reportedCycles.add(cycleKey);
|
|
1301
|
+
const parentContext = search.parentId ? ` in scope "${search.parentId}"` : "";
|
|
1302
|
+
const instance = search.instances.find((n) => n.id === nodeName);
|
|
1303
|
+
search.ctx.errors.push({
|
|
1304
|
+
type: "error",
|
|
1305
|
+
code: "CYCLE_DETECTED",
|
|
1306
|
+
message: `Loop detected${parentContext}: ${cyclePath.join(" -> ")}`,
|
|
1307
|
+
node: nodeName,
|
|
1308
|
+
location: instance?.sourceLocation
|
|
1309
|
+
});
|
|
1310
|
+
}
|
|
1311
|
+
function visit(search, nodeName, path) {
|
|
1312
|
+
if (search.recursionStack.has(nodeName)) {
|
|
1313
|
+
if (search.selfLoopNodes.has(nodeName)) return false;
|
|
1314
|
+
reportCycle(search, nodeName, path);
|
|
1315
|
+
return true;
|
|
1316
|
+
}
|
|
1317
|
+
if (search.visited.has(nodeName)) return false;
|
|
1318
|
+
search.recursionStack.add(nodeName);
|
|
1319
|
+
if (!search.instances.find((n) => n.id === nodeName)) {
|
|
1320
|
+
search.recursionStack.delete(nodeName);
|
|
1321
|
+
return false;
|
|
1322
|
+
}
|
|
1323
|
+
const newPath = [...path, nodeName];
|
|
1324
|
+
let hasCycle = false;
|
|
1325
|
+
for (const conn of search.edges.filter((c) => c.from.node === nodeName)) {
|
|
1326
|
+
if (visit(search, conn.to.node, newPath)) {
|
|
1327
|
+
hasCycle = true;
|
|
1328
|
+
}
|
|
1329
|
+
}
|
|
1330
|
+
search.recursionStack.delete(nodeName);
|
|
1331
|
+
if (!hasCycle) {
|
|
1332
|
+
search.visited.add(nodeName);
|
|
1333
|
+
}
|
|
1334
|
+
return hasCycle;
|
|
1335
|
+
}
|
|
1336
|
+
function detectCyclesInLayer(ctx, parentId, instances, connections) {
|
|
1337
|
+
const search = {
|
|
1338
|
+
ctx,
|
|
1339
|
+
parentId,
|
|
1340
|
+
instances,
|
|
1341
|
+
edges: connections.filter((c) => c.from.node !== c.to.node),
|
|
1342
|
+
selfLoopNodes: new Set(connections.filter((c) => c.from.node === c.to.node).map((c) => c.from.node)),
|
|
1343
|
+
visited: /* @__PURE__ */ new Set(),
|
|
1344
|
+
recursionStack: /* @__PURE__ */ new Set(),
|
|
1345
|
+
reportedCycles: /* @__PURE__ */ new Set()
|
|
1346
|
+
};
|
|
1347
|
+
for (const instance of instances) {
|
|
1348
|
+
if (!search.visited.has(instance.id)) {
|
|
1349
|
+
visit(search, instance.id, []);
|
|
1350
|
+
}
|
|
1351
|
+
}
|
|
1352
|
+
}
|
|
1353
|
+
function validateCycles(ctx, workflow) {
|
|
1354
|
+
const instancesByParent = groupInstancesByLayer(workflow);
|
|
1355
|
+
const connectionsByParent = groupConnectionsByLayer(workflow);
|
|
1356
|
+
for (const [parentId, instances] of instancesByParent.entries()) {
|
|
1357
|
+
detectCyclesInLayer(ctx, parentId, instances, connectionsByParent.get(parentId) || []);
|
|
1358
|
+
}
|
|
1359
|
+
}
|
|
1360
|
+
|
|
1361
|
+
// src/validation/rules/scope-topology.ts
|
|
1362
|
+
function checkScopeConsistency(ctx, workflow) {
|
|
1363
|
+
if (!workflow.scopes) return;
|
|
1364
|
+
const instanceToScope = /* @__PURE__ */ new Map();
|
|
1365
|
+
for (const [scopeKey, childIds] of Object.entries(workflow.scopes)) {
|
|
1366
|
+
for (const childId of childIds) {
|
|
1367
|
+
const existing = instanceToScope.get(childId);
|
|
1368
|
+
if (existing && existing !== scopeKey) {
|
|
1369
|
+
ctx.errors.push({
|
|
1370
|
+
type: "error",
|
|
1371
|
+
code: "SCOPE_INCONSISTENT",
|
|
1372
|
+
message: `Instance "${childId}" appears in multiple scopes: "${existing}" and "${scopeKey}". A node can only belong to one scope.`,
|
|
1373
|
+
node: childId,
|
|
1374
|
+
location: getInstanceLocation(workflow, childId)
|
|
1375
|
+
});
|
|
1376
|
+
}
|
|
1377
|
+
instanceToScope.set(childId, scopeKey);
|
|
1378
|
+
}
|
|
1379
|
+
}
|
|
1380
|
+
}
|
|
1381
|
+
function collectScopeNames(nodeType) {
|
|
1382
|
+
const scopeNames = /* @__PURE__ */ new Set();
|
|
1383
|
+
for (const portDef of Object.values(nodeType.outputs)) {
|
|
1384
|
+
if (portDef.scope) scopeNames.add(portDef.scope);
|
|
1385
|
+
}
|
|
1386
|
+
for (const portDef of Object.values(nodeType.inputs)) {
|
|
1387
|
+
if (portDef.scope) scopeNames.add(portDef.scope);
|
|
1388
|
+
}
|
|
1389
|
+
return scopeNames;
|
|
1390
|
+
}
|
|
1391
|
+
function checkScopeQualifiers(ctx, workflow, instanceId, scopeNames) {
|
|
1392
|
+
const available = () => [...scopeNames].join(", ");
|
|
1393
|
+
for (const conn of workflow.connections) {
|
|
1394
|
+
if (conn.from.scope && conn.from.node === instanceId && !scopeNames.has(conn.from.scope)) {
|
|
1395
|
+
ctx.errors.push({
|
|
1396
|
+
type: "error",
|
|
1397
|
+
code: "SCOPE_WRONG_SCOPE_NAME",
|
|
1398
|
+
message: `Connection from "${instanceId}.${conn.from.port}" uses scope qualifier ":${conn.from.scope}" but node "${instanceId}" does not define scope "${conn.from.scope}". Available scopes: ${available()}.`,
|
|
1399
|
+
connection: conn,
|
|
1400
|
+
location: getConnectionLocation(conn)
|
|
1401
|
+
});
|
|
1402
|
+
}
|
|
1403
|
+
if (conn.to.scope && conn.to.node === instanceId && !scopeNames.has(conn.to.scope)) {
|
|
1404
|
+
ctx.errors.push({
|
|
1405
|
+
type: "error",
|
|
1406
|
+
code: "SCOPE_WRONG_SCOPE_NAME",
|
|
1407
|
+
message: `Connection to "${instanceId}.${conn.to.port}" uses scope qualifier ":${conn.to.scope}" but node "${instanceId}" does not define scope "${conn.to.scope}". Available scopes: ${available()}.`,
|
|
1408
|
+
connection: conn,
|
|
1409
|
+
location: getConnectionLocation(conn)
|
|
1410
|
+
});
|
|
1411
|
+
}
|
|
1412
|
+
}
|
|
1413
|
+
}
|
|
1414
|
+
function findScopeChildren(workflow, parentId, scopeName) {
|
|
1415
|
+
const childIds = [];
|
|
1416
|
+
for (const child of workflow.instances) {
|
|
1417
|
+
if (child.parent && child.parent.id === parentId && child.parent.scope === scopeName) {
|
|
1418
|
+
childIds.push(child.id);
|
|
1419
|
+
}
|
|
1420
|
+
}
|
|
1421
|
+
return childIds;
|
|
1422
|
+
}
|
|
1423
|
+
function collectScopedConnections(workflow, parentId, scopeName, childIds) {
|
|
1424
|
+
return workflow.connections.filter(
|
|
1425
|
+
(conn) => conn.from.scope === scopeName && conn.from.node === parentId || conn.to.scope === scopeName && conn.to.node === parentId || conn.from.scope === scopeName && childIds.includes(conn.from.node) || conn.to.scope === scopeName && childIds.includes(conn.to.node)
|
|
1426
|
+
);
|
|
1427
|
+
}
|
|
1428
|
+
function atParent(scope, conn, side) {
|
|
1429
|
+
return conn[side].node === scope.parentId && conn[side].scope === scope.scopeName;
|
|
1430
|
+
}
|
|
1431
|
+
function checkParentScopedPort(ctx, scope, conn, side) {
|
|
1432
|
+
const { parentId, scopeName } = scope;
|
|
1433
|
+
const ports = side === "from" ? scope.nodeType.outputs : scope.nodeType.inputs;
|
|
1434
|
+
const noun = side === "from" ? "output" : "input";
|
|
1435
|
+
const portName = conn[side].port;
|
|
1436
|
+
const portDef = ports[portName];
|
|
1437
|
+
if (!portDef) {
|
|
1438
|
+
const availablePorts = Object.entries(ports).filter(([, p]) => p.scope === scopeName).map(([n]) => n);
|
|
1439
|
+
ctx.errors.push({
|
|
1440
|
+
type: "error",
|
|
1441
|
+
code: "SCOPE_UNKNOWN_PORT",
|
|
1442
|
+
message: `Scoped connection references non-existent ${noun} port "${portName}" on "${parentId}" in scope "${scopeName}". Available scoped ${noun}s: ${availablePorts.join(", ") || "none"}.`,
|
|
1443
|
+
connection: conn,
|
|
1444
|
+
location: getConnectionLocation(conn)
|
|
1445
|
+
});
|
|
1446
|
+
} else if (portDef.scope !== scopeName) {
|
|
1447
|
+
const Noun = side === "from" ? "Output" : "Input";
|
|
1448
|
+
ctx.errors.push({
|
|
1449
|
+
type: "error",
|
|
1450
|
+
code: "SCOPE_UNKNOWN_PORT",
|
|
1451
|
+
message: `${Noun} port "${portName}" on "${parentId}" is not a scoped port of scope "${scopeName}"${portDef.scope ? ` (it belongs to scope "${portDef.scope}")` : " (it is an unscoped port)"}.`,
|
|
1452
|
+
connection: conn,
|
|
1453
|
+
location: getConnectionLocation(conn)
|
|
1454
|
+
});
|
|
1455
|
+
}
|
|
1456
|
+
}
|
|
1457
|
+
function checkScopedPortReferences(ctx, scope) {
|
|
1458
|
+
for (const conn of scope.scopedConnections) {
|
|
1459
|
+
if (atParent(scope, conn, "from")) checkParentScopedPort(ctx, scope, conn, "from");
|
|
1460
|
+
if (atParent(scope, conn, "to")) checkParentScopedPort(ctx, scope, conn, "to");
|
|
1461
|
+
}
|
|
1462
|
+
}
|
|
1463
|
+
function checkScopeBoundary(ctx, scope) {
|
|
1464
|
+
const { parentId, scopeName, childIds } = scope;
|
|
1465
|
+
const inside = (node) => node === parentId || childIds.includes(node);
|
|
1466
|
+
for (const conn of scope.scopedConnections) {
|
|
1467
|
+
if (conn.from.scope === scopeName && childIds.includes(conn.from.node) && !inside(conn.to.node)) {
|
|
1468
|
+
ctx.errors.push({
|
|
1469
|
+
type: "error",
|
|
1470
|
+
code: "SCOPE_CONNECTION_OUTSIDE",
|
|
1471
|
+
message: `Scoped connection from "${conn.from.node}.${conn.from.port}" targets "${conn.to.node}" which is not inside scope "${scopeName}" of "${parentId}".`,
|
|
1472
|
+
connection: conn,
|
|
1473
|
+
location: getConnectionLocation(conn)
|
|
1474
|
+
});
|
|
1475
|
+
}
|
|
1476
|
+
if (conn.to.scope === scopeName && childIds.includes(conn.to.node) && !inside(conn.from.node)) {
|
|
1477
|
+
ctx.errors.push({
|
|
1478
|
+
type: "error",
|
|
1479
|
+
code: "SCOPE_CONNECTION_OUTSIDE",
|
|
1480
|
+
message: `Scoped connection to "${conn.to.node}.${conn.to.port}" sources from "${conn.from.node}" which is not inside scope "${scopeName}" of "${parentId}".`,
|
|
1481
|
+
connection: conn,
|
|
1482
|
+
location: getConnectionLocation(conn)
|
|
1483
|
+
});
|
|
1484
|
+
}
|
|
1485
|
+
}
|
|
1486
|
+
}
|
|
1487
|
+
function warnScopedTypeMismatch(ctx, scopeName, conn, source, target) {
|
|
1488
|
+
if (!source || !target || source.dataType === "STEP" || target.dataType === "STEP") return;
|
|
1489
|
+
if (source.dataType === target.dataType || source.dataType === "ANY" || target.dataType === "ANY") return;
|
|
1490
|
+
ctx.warnings.push({
|
|
1491
|
+
type: "warning",
|
|
1492
|
+
code: "SCOPE_PORT_TYPE_MISMATCH",
|
|
1493
|
+
message: `Type mismatch in scope "${scopeName}": "${conn.from.node}.${conn.from.port}" outputs ${formatType(source.dataType, source.tsType)} but "${conn.to.node}.${conn.to.port}" expects ${formatType(target.dataType, target.tsType)}.`,
|
|
1494
|
+
connection: conn,
|
|
1495
|
+
location: getConnectionLocation(conn)
|
|
1496
|
+
});
|
|
1497
|
+
}
|
|
1498
|
+
function checkScopedPortTypes(ctx, scope) {
|
|
1499
|
+
const { nodeType, instanceMap, scopeName } = scope;
|
|
1500
|
+
for (const conn of scope.scopedConnections) {
|
|
1501
|
+
if (atParent(scope, conn, "from")) {
|
|
1502
|
+
warnScopedTypeMismatch(ctx, scopeName, conn, nodeType.outputs[conn.from.port], instanceMap.get(conn.to.node)?.inputs[conn.to.port]);
|
|
1503
|
+
}
|
|
1504
|
+
if (atParent(scope, conn, "to")) {
|
|
1505
|
+
warnScopedTypeMismatch(ctx, scopeName, conn, instanceMap.get(conn.from.node)?.outputs[conn.from.port], nodeType.inputs[conn.to.port]);
|
|
1506
|
+
}
|
|
1507
|
+
}
|
|
1508
|
+
}
|
|
1509
|
+
function checkChildRequiredInputs(ctx, scope) {
|
|
1510
|
+
const { workflow, instanceMap, parentId, scopeName } = scope;
|
|
1511
|
+
for (const childId of scope.childIds) {
|
|
1512
|
+
const childType = instanceMap.get(childId);
|
|
1513
|
+
if (!childType) continue;
|
|
1514
|
+
const childInstance = workflow.instances.find((i) => i.id === childId);
|
|
1515
|
+
for (const [portName, portConfig] of Object.entries(childType.inputs)) {
|
|
1516
|
+
if (isExecutePort(portName)) continue;
|
|
1517
|
+
if (portConfig.scope) continue;
|
|
1518
|
+
if (portConfig.optional || portConfig.default !== void 0) continue;
|
|
1519
|
+
const instancePortConfig = childInstance?.config?.portConfigs?.find(
|
|
1520
|
+
(pc) => pc.portName === portName && (pc.direction == null || pc.direction === "INPUT")
|
|
1521
|
+
);
|
|
1522
|
+
if (portConfig.expression || instancePortConfig?.expression !== void 0) continue;
|
|
1523
|
+
const isConnected = workflow.connections.some((conn) => conn.to.node === childId && conn.to.port === portName);
|
|
1524
|
+
if (!isConnected) {
|
|
1525
|
+
ctx.errors.push({
|
|
1526
|
+
type: "error",
|
|
1527
|
+
code: "SCOPE_MISSING_REQUIRED_INPUT",
|
|
1528
|
+
message: `Scoped child "${childId}" has unconnected required input "${portName}" within scope "${scopeName}" of "${parentId}".`,
|
|
1529
|
+
node: childId,
|
|
1530
|
+
location: childInstance?.sourceLocation
|
|
1531
|
+
});
|
|
1532
|
+
}
|
|
1533
|
+
}
|
|
1534
|
+
}
|
|
1535
|
+
}
|
|
1536
|
+
function warnUnusedScopedInputs(ctx, scope) {
|
|
1537
|
+
const { workflow, parentId, scopeName } = scope;
|
|
1538
|
+
const scopedInputPorts = Object.entries(scope.nodeType.inputs).filter(([_, portDef]) => portDef.scope === scopeName);
|
|
1539
|
+
for (const [portName] of scopedInputPorts) {
|
|
1540
|
+
const hasConnection = scope.scopedConnections.some((conn) => atParent(scope, conn, "to") && conn.to.port === portName);
|
|
1541
|
+
if (!hasConnection) {
|
|
1542
|
+
ctx.warnings.push({
|
|
1543
|
+
type: "warning",
|
|
1544
|
+
code: "SCOPE_UNUSED_INPUT",
|
|
1545
|
+
message: `Scoped input port "${portName}" of "${parentId}" (scope "${scopeName}") has no connection from inner nodes. Data will not flow back from the scope.`,
|
|
1546
|
+
node: parentId,
|
|
1547
|
+
location: getInstanceLocation(workflow, parentId)
|
|
1548
|
+
});
|
|
1549
|
+
}
|
|
1550
|
+
}
|
|
1551
|
+
}
|
|
1552
|
+
function warnOrphanedChildren(ctx, scope) {
|
|
1553
|
+
const { workflow, parentId, scopeName } = scope;
|
|
1554
|
+
for (const childId of scope.childIds) {
|
|
1555
|
+
const connectedToParent = scope.scopedConnections.some(
|
|
1556
|
+
(conn) => atParent(scope, conn, "from") && conn.to.node === childId || atParent(scope, conn, "to") && conn.from.node === childId
|
|
1557
|
+
);
|
|
1558
|
+
if (!connectedToParent) {
|
|
1559
|
+
ctx.warnings.push({
|
|
1560
|
+
type: "warning",
|
|
1561
|
+
code: "SCOPE_ORPHANED_CHILD",
|
|
1562
|
+
message: `Child node "${childId}" is declared inside scope "${scopeName}" of "${parentId}" but has no scoped connections to or from the parent. It is disconnected from the scope's data flow.`,
|
|
1563
|
+
node: childId,
|
|
1564
|
+
location: getInstanceLocation(workflow, childId)
|
|
1565
|
+
});
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1568
|
+
}
|
|
1569
|
+
function checkScopedInstance(ctx, workflow, instanceMap, parentId, nodeType) {
|
|
1570
|
+
const scopeNames = collectScopeNames(nodeType);
|
|
1571
|
+
if (scopeNames.size === 0) return;
|
|
1572
|
+
checkScopeQualifiers(ctx, workflow, parentId, scopeNames);
|
|
1573
|
+
for (const scopeName of scopeNames) {
|
|
1574
|
+
const childIds = findScopeChildren(workflow, parentId, scopeName);
|
|
1575
|
+
if (childIds.length === 0) {
|
|
1576
|
+
ctx.warnings.push({
|
|
1577
|
+
type: "warning",
|
|
1578
|
+
code: "SCOPE_EMPTY",
|
|
1579
|
+
message: `Scope "${scopeName}" on node "${parentId}" has no child nodes.`,
|
|
1580
|
+
node: parentId,
|
|
1581
|
+
location: getInstanceLocation(workflow, parentId)
|
|
1582
|
+
});
|
|
1583
|
+
continue;
|
|
1584
|
+
}
|
|
1585
|
+
const scope = {
|
|
1586
|
+
workflow,
|
|
1587
|
+
instanceMap,
|
|
1588
|
+
parentId,
|
|
1589
|
+
nodeType,
|
|
1590
|
+
scopeName,
|
|
1591
|
+
childIds,
|
|
1592
|
+
scopedConnections: collectScopedConnections(workflow, parentId, scopeName, childIds)
|
|
1593
|
+
};
|
|
1594
|
+
checkScopedPortReferences(ctx, scope);
|
|
1595
|
+
checkScopeBoundary(ctx, scope);
|
|
1596
|
+
checkScopedPortTypes(ctx, scope);
|
|
1597
|
+
checkChildRequiredInputs(ctx, scope);
|
|
1598
|
+
warnUnusedScopedInputs(ctx, scope);
|
|
1599
|
+
warnOrphanedChildren(ctx, scope);
|
|
1600
|
+
}
|
|
1601
|
+
}
|
|
1602
|
+
function findScopedParentIds(workflow, instanceMap) {
|
|
1603
|
+
const scopedParentIds = /* @__PURE__ */ new Set();
|
|
1604
|
+
for (const inst of workflow.instances) {
|
|
1605
|
+
const nt = instanceMap.get(inst.id);
|
|
1606
|
+
if (!nt) continue;
|
|
1607
|
+
const hasScopedPorts = [...Object.values(nt.inputs ?? {}), ...Object.values(nt.outputs ?? {})].some((p) => p.scope);
|
|
1608
|
+
if (hasScopedPorts) scopedParentIds.add(inst.id);
|
|
1609
|
+
}
|
|
1610
|
+
return scopedParentIds;
|
|
1611
|
+
}
|
|
1612
|
+
function checkCrossScopeConnections(ctx, workflow, instanceMap) {
|
|
1613
|
+
const parentOf = /* @__PURE__ */ new Map();
|
|
1614
|
+
for (const inst of workflow.instances) {
|
|
1615
|
+
parentOf.set(inst.id, inst.parent ?? void 0);
|
|
1616
|
+
}
|
|
1617
|
+
const scopedParentIds = findScopedParentIds(workflow, instanceMap);
|
|
1618
|
+
for (const conn of workflow.connections) {
|
|
1619
|
+
if (conn.from.scope || conn.to.scope) continue;
|
|
1620
|
+
if (!parentOf.has(conn.from.node) || !parentOf.has(conn.to.node)) continue;
|
|
1621
|
+
const fromParent = parentOf.get(conn.from.node);
|
|
1622
|
+
const toParent = parentOf.get(conn.to.node);
|
|
1623
|
+
if (!fromParent && !toParent) continue;
|
|
1624
|
+
const fromInScopedParent = fromParent && scopedParentIds.has(fromParent.id);
|
|
1625
|
+
const toInScopedParent = toParent && scopedParentIds.has(toParent.id);
|
|
1626
|
+
if (!fromInScopedParent && !toInScopedParent) continue;
|
|
1627
|
+
const fromIsParentOfTo = toParent && toParent.id === conn.from.node;
|
|
1628
|
+
const toIsParentOfFrom = fromParent && fromParent.id === conn.to.node;
|
|
1629
|
+
if (fromIsParentOfTo || toIsParentOfFrom) continue;
|
|
1630
|
+
const sameScope = fromParent && toParent && fromParent.id === toParent.id && fromParent.scope === toParent.scope;
|
|
1631
|
+
if (!sameScope) {
|
|
1632
|
+
const fromCtx = fromParent ? `${fromParent.id}.${fromParent.scope}` : "root";
|
|
1633
|
+
const toCtx = toParent ? `${toParent.id}.${toParent.scope}` : "root";
|
|
1634
|
+
ctx.errors.push({
|
|
1635
|
+
type: "error",
|
|
1636
|
+
code: "CROSS_SCOPE_CONNECTION",
|
|
1637
|
+
message: `Connection from "${conn.from.node}.${conn.from.port}" (in ${fromCtx}) to "${conn.to.node}.${conn.to.port}" (in ${toCtx}) crosses scope boundaries. Nodes in different scopes cannot connect directly.`,
|
|
1638
|
+
connection: conn,
|
|
1639
|
+
location: getConnectionLocation(conn)
|
|
1640
|
+
});
|
|
1641
|
+
}
|
|
1642
|
+
}
|
|
1643
|
+
}
|
|
1644
|
+
function validateScopeTopology(ctx, workflow, instanceMap) {
|
|
1645
|
+
checkScopeConsistency(ctx, workflow);
|
|
1646
|
+
for (const instance of workflow.instances) {
|
|
1647
|
+
const nodeType = instanceMap.get(instance.id);
|
|
1648
|
+
if (!nodeType) continue;
|
|
1649
|
+
checkScopedInstance(ctx, workflow, instanceMap, instance.id, nodeType);
|
|
1650
|
+
}
|
|
1651
|
+
checkCrossScopeConnections(ctx, workflow, instanceMap);
|
|
1652
|
+
}
|
|
1653
|
+
|
|
1654
|
+
// src/validation/core-rules.ts
|
|
1655
|
+
function validateStructure(ctx, workflow) {
|
|
1656
|
+
if (!workflow.name) {
|
|
1657
|
+
ctx.errors.push({
|
|
1658
|
+
type: "error",
|
|
1659
|
+
code: "MISSING_WORKFLOW_NAME",
|
|
1660
|
+
message: "Workflow must have a name"
|
|
1661
|
+
});
|
|
1662
|
+
}
|
|
1663
|
+
if (!workflow.functionName) {
|
|
1664
|
+
ctx.errors.push({
|
|
1665
|
+
type: "error",
|
|
1666
|
+
code: "MISSING_FUNCTION_NAME",
|
|
1667
|
+
message: "Workflow must have a functionName"
|
|
1668
|
+
});
|
|
1669
|
+
}
|
|
1670
|
+
}
|
|
1671
|
+
function validateDuplicateNodeNames(ctx, workflow) {
|
|
1672
|
+
const nodeNames = /* @__PURE__ */ new Set();
|
|
1673
|
+
workflow.nodeTypes.forEach((nodeType) => {
|
|
1674
|
+
if (nodeNames.has(nodeType.functionName)) {
|
|
1675
|
+
ctx.errors.push({
|
|
1676
|
+
type: "error",
|
|
1677
|
+
code: "DUPLICATE_NODE_NAME",
|
|
1678
|
+
message: `Duplicate node type name: "${nodeType.functionName}"`,
|
|
1679
|
+
node: nodeType.functionName,
|
|
1680
|
+
location: nodeType.sourceLocation
|
|
1681
|
+
});
|
|
1682
|
+
}
|
|
1683
|
+
nodeNames.add(nodeType.functionName);
|
|
1684
|
+
});
|
|
1685
|
+
}
|
|
1686
|
+
function validateMutableBindings(ctx, workflow) {
|
|
1687
|
+
workflow.nodeTypes.forEach((nodeType) => {
|
|
1688
|
+
if (nodeType.declarationKind && nodeType.declarationKind !== "const") {
|
|
1689
|
+
ctx.warnings.push({
|
|
1690
|
+
type: "warning",
|
|
1691
|
+
code: "MUTABLE_NODE_TYPE_BINDING",
|
|
1692
|
+
message: `Node type "${nodeType.functionName}" is declared with "${nodeType.declarationKind}" instead of "const". Use "const" to prevent accidental reassignment.`,
|
|
1693
|
+
node: nodeType.functionName,
|
|
1694
|
+
location: nodeType.sourceLocation
|
|
1695
|
+
});
|
|
1696
|
+
}
|
|
1697
|
+
});
|
|
1698
|
+
}
|
|
1699
|
+
function validateReservedNames(ctx, workflow, nodeTypeMap) {
|
|
1700
|
+
nodeTypeMap.forEach((nodeType, nodeName) => {
|
|
1701
|
+
if (isReservedNodeName(nodeName)) {
|
|
1702
|
+
ctx.errors.push({
|
|
1703
|
+
type: "error",
|
|
1704
|
+
code: "RESERVED_NODE_NAME",
|
|
1705
|
+
message: `Node type name "${nodeName}" is reserved. Reserved node names: ${Object.values(RESERVED_NODE_NAMES).join(", ")}`,
|
|
1706
|
+
node: nodeName,
|
|
1707
|
+
location: nodeType.sourceLocation
|
|
1708
|
+
});
|
|
1709
|
+
}
|
|
1710
|
+
});
|
|
1711
|
+
workflow.instances.forEach((instance) => {
|
|
1712
|
+
if (isReservedNodeName(instance.id)) {
|
|
1713
|
+
ctx.errors.push({
|
|
1714
|
+
type: "error",
|
|
1715
|
+
code: "RESERVED_INSTANCE_ID",
|
|
1716
|
+
message: `Instance ID "${instance.id}" is reserved. Reserved names: ${Object.values(RESERVED_NODE_NAMES).join(", ")}`,
|
|
1717
|
+
node: instance.id,
|
|
1718
|
+
location: instance.sourceLocation
|
|
1719
|
+
});
|
|
1720
|
+
}
|
|
1721
|
+
});
|
|
1722
|
+
}
|
|
1723
|
+
function validateScopeNames(ctx, workflow) {
|
|
1724
|
+
const identifier = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
|
|
1725
|
+
for (const nodeType of workflow.nodeTypes) {
|
|
1726
|
+
const ports = [...Object.entries(nodeType.inputs), ...Object.entries(nodeType.outputs)];
|
|
1727
|
+
for (const [portName, portDef] of ports) {
|
|
1728
|
+
if (portDef.scope === void 0 || identifier.test(portDef.scope)) continue;
|
|
1729
|
+
ctx.errors.push({
|
|
1730
|
+
type: "error",
|
|
1731
|
+
code: "INVALID_SCOPE_NAME",
|
|
1732
|
+
message: `Port "${portName}" on node type "${nodeType.functionName}" has invalid scope name "${portDef.scope}". Scope names must be valid JavaScript identifiers (letters, numbers, underscore, dollar sign, and cannot start with a number).`,
|
|
1733
|
+
node: nodeType.functionName,
|
|
1734
|
+
location: nodeType.sourceLocation
|
|
1735
|
+
});
|
|
1736
|
+
}
|
|
1737
|
+
}
|
|
1738
|
+
}
|
|
1739
|
+
function validateRequiredInputs(ctx, workflow, instanceMap) {
|
|
1740
|
+
instanceMap.forEach((nodeType, instanceId) => {
|
|
1741
|
+
const instance = workflow.instances.find((inst) => inst.id === instanceId);
|
|
1742
|
+
if (instance?.parent) return;
|
|
1743
|
+
Object.entries(nodeType.inputs).forEach(([portName, portConfig]) => {
|
|
1744
|
+
if (isExecutePort(portName)) return;
|
|
1745
|
+
if (portConfig.scope) return;
|
|
1746
|
+
const instancePortConfig = instance?.config?.portConfigs?.find(
|
|
1747
|
+
(pc) => pc.portName === portName && (pc.direction == null || pc.direction === "INPUT")
|
|
1748
|
+
);
|
|
1749
|
+
const hasInstanceExpression = instancePortConfig?.expression !== void 0;
|
|
1750
|
+
const isRequired = !portConfig.optional && portConfig.default === void 0 && !portConfig.expression && !hasInstanceExpression;
|
|
1751
|
+
if (isRequired) {
|
|
1752
|
+
const isConnected = workflow.connections.some((conn) => {
|
|
1753
|
+
return conn.to.node === instanceId && conn.to.port === portName;
|
|
1754
|
+
});
|
|
1755
|
+
if (!isConnected) {
|
|
1756
|
+
ctx.errors.push({
|
|
1757
|
+
type: "error",
|
|
1758
|
+
code: "MISSING_REQUIRED_INPUT",
|
|
1759
|
+
message: `Node "${instanceId}" has unconnected required input port "${portName}". Connect a value to it, or mark it optional with @input [${portName}].`,
|
|
1760
|
+
node: instanceId,
|
|
1761
|
+
location: instance?.sourceLocation
|
|
1762
|
+
});
|
|
1763
|
+
}
|
|
1764
|
+
}
|
|
1765
|
+
});
|
|
1766
|
+
});
|
|
1767
|
+
}
|
|
1768
|
+
function detectUnusedNodes(ctx, workflow, instanceMap) {
|
|
1769
|
+
const usedNodes = /* @__PURE__ */ new Set();
|
|
1770
|
+
workflow.connections.forEach((conn) => {
|
|
1771
|
+
const fromNode = conn.from.node;
|
|
1772
|
+
const toNode = conn.to.node;
|
|
1773
|
+
if (!isStartNode(fromNode) && !isExitNode(fromNode)) {
|
|
1774
|
+
usedNodes.add(fromNode);
|
|
1775
|
+
}
|
|
1776
|
+
if (!isStartNode(toNode) && !isExitNode(toNode)) {
|
|
1777
|
+
usedNodes.add(toNode);
|
|
1778
|
+
}
|
|
1779
|
+
});
|
|
1780
|
+
instanceMap.forEach((_nodeType, instanceId) => {
|
|
1781
|
+
if (!usedNodes.has(instanceId)) {
|
|
1782
|
+
ctx.warnings.push({
|
|
1783
|
+
type: "warning",
|
|
1784
|
+
code: "UNUSED_NODE",
|
|
1785
|
+
message: `Node "${instanceId}" is defined but never used in workflow`,
|
|
1786
|
+
node: instanceId,
|
|
1787
|
+
location: getInstanceLocation(workflow, instanceId)
|
|
1788
|
+
});
|
|
1789
|
+
}
|
|
1790
|
+
});
|
|
1791
|
+
}
|
|
1792
|
+
function validateStartAndExit(ctx, workflow) {
|
|
1793
|
+
const hasStartConnections = workflow.connections.some((conn) => {
|
|
1794
|
+
return isStartNode(conn.from.node);
|
|
1795
|
+
});
|
|
1796
|
+
if (!hasStartConnections) {
|
|
1797
|
+
ctx.warnings.push({
|
|
1798
|
+
type: "warning",
|
|
1799
|
+
code: "NO_START_CONNECTIONS",
|
|
1800
|
+
message: "Workflow has no connections from Start node"
|
|
1801
|
+
});
|
|
1802
|
+
}
|
|
1803
|
+
const hasExitConnections = workflow.connections.some((conn) => {
|
|
1804
|
+
return isExitNode(conn.to.node);
|
|
1805
|
+
});
|
|
1806
|
+
if (!hasExitConnections) {
|
|
1807
|
+
ctx.warnings.push({
|
|
1808
|
+
type: "warning",
|
|
1809
|
+
code: "NO_EXIT_CONNECTIONS",
|
|
1810
|
+
message: "Workflow has no connections to Exit node (no return value)"
|
|
1811
|
+
});
|
|
1812
|
+
}
|
|
1813
|
+
if (workflow.exitPorts.onSuccess) {
|
|
1814
|
+
if (workflow.exitPorts.onSuccess.dataType !== "STEP") {
|
|
1815
|
+
ctx.errors.push({
|
|
1816
|
+
type: "error",
|
|
1817
|
+
code: "INVALID_EXIT_PORT_TYPE",
|
|
1818
|
+
message: "Exit port 'onSuccess' must be of type STEP (control flow), found: " + workflow.exitPorts.onSuccess.dataType
|
|
1819
|
+
});
|
|
1820
|
+
}
|
|
1821
|
+
}
|
|
1822
|
+
if (workflow.exitPorts.onFailure) {
|
|
1823
|
+
if (workflow.exitPorts.onFailure.dataType !== "STEP") {
|
|
1824
|
+
ctx.errors.push({
|
|
1825
|
+
type: "error",
|
|
1826
|
+
code: "INVALID_EXIT_PORT_TYPE",
|
|
1827
|
+
message: "Exit port 'onFailure' must be of type STEP (control flow), found: " + workflow.exitPorts.onFailure.dataType
|
|
1828
|
+
});
|
|
1829
|
+
}
|
|
1830
|
+
}
|
|
1831
|
+
}
|
|
1832
|
+
function validateAnnotationSignatureConsistency(ctx, workflow) {
|
|
1833
|
+
for (const nodeType of workflow.nodeTypes) {
|
|
1834
|
+
if (!nodeType.functionText) continue;
|
|
1835
|
+
let sigParams;
|
|
1836
|
+
try {
|
|
1837
|
+
const sig = parseFunctionSignature(nodeType.functionText);
|
|
1838
|
+
sigParams = sig.params;
|
|
1839
|
+
} catch {
|
|
1840
|
+
continue;
|
|
1841
|
+
}
|
|
1842
|
+
const sigParamMap = /* @__PURE__ */ new Map();
|
|
1843
|
+
for (const p of sigParams.slice(1)) {
|
|
1844
|
+
sigParamMap.set(p.name, p);
|
|
1845
|
+
}
|
|
1846
|
+
for (const [portName, portDef] of Object.entries(nodeType.inputs)) {
|
|
1847
|
+
if (portName === "execute") continue;
|
|
1848
|
+
const sigParam = sigParamMap.get(portName);
|
|
1849
|
+
if (!sigParam) continue;
|
|
1850
|
+
if (!portDef.optional && sigParam.optional) {
|
|
1851
|
+
ctx.warnings.push({
|
|
1852
|
+
type: "warning",
|
|
1853
|
+
code: "ANNOTATION_SIGNATURE_MISMATCH",
|
|
1854
|
+
message: `Port "${portName}" in node type "${nodeType.functionName}" is optional in signature but required in annotation. Consider using @input [${portName}] to mark it optional.`,
|
|
1855
|
+
node: nodeType.functionName,
|
|
1856
|
+
location: nodeType.sourceLocation
|
|
1857
|
+
});
|
|
1858
|
+
}
|
|
1859
|
+
if (portDef.tsType && sigParam.tsType) {
|
|
1860
|
+
const annotationType = normalizeTypeString(portDef.tsType);
|
|
1861
|
+
const signatureType = normalizeTypeString(sigParam.tsType);
|
|
1862
|
+
if (!signatureType || signatureType === "any") continue;
|
|
1863
|
+
if (annotationType !== signatureType) {
|
|
1864
|
+
ctx.warnings.push({
|
|
1865
|
+
type: "warning",
|
|
1866
|
+
code: "ANNOTATION_SIGNATURE_TYPE_MISMATCH",
|
|
1867
|
+
message: `Port "${portName}" in node type "${nodeType.functionName}" has type "${portDef.tsType}" in annotation but "${sigParam.tsType}" in function signature.`,
|
|
1868
|
+
node: nodeType.functionName,
|
|
1869
|
+
location: nodeType.sourceLocation
|
|
1870
|
+
});
|
|
1871
|
+
}
|
|
1872
|
+
}
|
|
1873
|
+
}
|
|
1874
|
+
}
|
|
1875
|
+
}
|
|
1876
|
+
function validateDuplicateInstanceIds(ctx, workflow) {
|
|
1877
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1878
|
+
for (const instance of workflow.instances) {
|
|
1879
|
+
if (seen.has(instance.id)) {
|
|
1880
|
+
ctx.errors.push({
|
|
1881
|
+
type: "error",
|
|
1882
|
+
code: "DUPLICATE_INSTANCE_ID",
|
|
1883
|
+
message: `Duplicate instance ID "${instance.id}" in workflow. Each @node must have a unique ID.`,
|
|
1884
|
+
node: instance.id,
|
|
1885
|
+
location: instance.sourceLocation
|
|
1886
|
+
});
|
|
1887
|
+
}
|
|
1888
|
+
seen.add(instance.id);
|
|
1889
|
+
}
|
|
1890
|
+
}
|
|
1891
|
+
function validateVisualAnnotations(ctx, workflow, _instanceMap) {
|
|
1892
|
+
const validColors = VALID_NODE_COLORS;
|
|
1893
|
+
const validIcons = { includes: (icon) => isMaterialSymbol(icon) || VALID_NODE_ICONS.includes(icon) };
|
|
1894
|
+
const iconNames = [...VALID_NODE_ICONS, ...MATERIAL_SYMBOLS];
|
|
1895
|
+
for (const nodeType of workflow.nodeTypes) {
|
|
1896
|
+
const color = nodeType.visuals?.color;
|
|
1897
|
+
const icon = nodeType.visuals?.icon;
|
|
1898
|
+
if (color && !validColors.includes(color)) {
|
|
1899
|
+
const suggestions = findClosestMatches(color, [...validColors]);
|
|
1900
|
+
const hint = suggestions.length > 0 ? ` Did you mean "${suggestions[0]}"?` : "";
|
|
1901
|
+
ctx.warnings.push({
|
|
1902
|
+
type: "warning",
|
|
1903
|
+
code: "INVALID_COLOR",
|
|
1904
|
+
message: `Node type "${nodeType.functionName}" has invalid color "${color}".${hint} Valid colors: ${validColors.join(", ")}.`,
|
|
1905
|
+
node: nodeType.functionName,
|
|
1906
|
+
location: nodeType.sourceLocation
|
|
1907
|
+
});
|
|
1908
|
+
}
|
|
1909
|
+
if (icon && !validIcons.includes(icon)) {
|
|
1910
|
+
const suggestions = findClosestMatches(icon, iconNames);
|
|
1911
|
+
const hint = suggestions.length > 0 ? ` Did you mean "${suggestions[0]}"?` : "";
|
|
1912
|
+
ctx.warnings.push({
|
|
1913
|
+
type: "warning",
|
|
1914
|
+
code: "INVALID_ICON",
|
|
1915
|
+
message: `Node type "${nodeType.functionName}" has invalid icon "${icon}".${hint} Icons are Material Symbols names, as flag or swap_horiz (swapHoriz works too).`,
|
|
1916
|
+
node: nodeType.functionName,
|
|
1917
|
+
location: nodeType.sourceLocation
|
|
1918
|
+
});
|
|
1919
|
+
}
|
|
1920
|
+
}
|
|
1921
|
+
for (const instance of workflow.instances) {
|
|
1922
|
+
if (instance.config?.color && !validColors.includes(instance.config.color)) {
|
|
1923
|
+
const suggestions = findClosestMatches(instance.config.color, [...validColors]);
|
|
1924
|
+
const hint = suggestions.length > 0 ? ` Did you mean "${suggestions[0]}"?` : "";
|
|
1925
|
+
ctx.warnings.push({
|
|
1926
|
+
type: "warning",
|
|
1927
|
+
code: "INVALID_COLOR",
|
|
1928
|
+
message: `Instance "${instance.id}" has invalid color "${instance.config.color}".${hint} Valid colors: ${validColors.join(", ")}.`,
|
|
1929
|
+
node: instance.id,
|
|
1930
|
+
location: instance.sourceLocation
|
|
1931
|
+
});
|
|
1932
|
+
}
|
|
1933
|
+
if (instance.config?.icon && !validIcons.includes(instance.config.icon)) {
|
|
1934
|
+
const suggestions = findClosestMatches(instance.config.icon, iconNames);
|
|
1935
|
+
const hint = suggestions.length > 0 ? ` Did you mean "${suggestions[0]}"?` : "";
|
|
1936
|
+
ctx.warnings.push({
|
|
1937
|
+
type: "warning",
|
|
1938
|
+
code: "INVALID_ICON",
|
|
1939
|
+
message: `Instance "${instance.id}" has invalid icon "${instance.config.icon}".${hint} Icons are Material Symbols names, as flag or swap_horiz (swapHoriz works too).`,
|
|
1940
|
+
node: instance.id,
|
|
1941
|
+
location: instance.sourceLocation
|
|
1942
|
+
});
|
|
1943
|
+
}
|
|
1944
|
+
}
|
|
1945
|
+
}
|
|
1946
|
+
function validatePortTypes(ctx, workflow) {
|
|
1947
|
+
for (const nodeType of workflow.nodeTypes) {
|
|
1948
|
+
for (const [portName, portDef] of Object.entries(nodeType.inputs)) {
|
|
1949
|
+
if (!isValidPortType(portDef.dataType)) {
|
|
1950
|
+
ctx.warnings.push({
|
|
1951
|
+
type: "warning",
|
|
1952
|
+
code: "INVALID_PORT_TYPE",
|
|
1953
|
+
message: `Port "${portName}" on node type "${nodeType.functionName}" has invalid type "${portDef.dataType}".`,
|
|
1954
|
+
node: nodeType.functionName,
|
|
1955
|
+
location: nodeType.sourceLocation
|
|
1956
|
+
});
|
|
1957
|
+
}
|
|
1958
|
+
}
|
|
1959
|
+
for (const [portName, portDef] of Object.entries(nodeType.outputs)) {
|
|
1960
|
+
if (!isValidPortType(portDef.dataType)) {
|
|
1961
|
+
ctx.warnings.push({
|
|
1962
|
+
type: "warning",
|
|
1963
|
+
code: "INVALID_PORT_TYPE",
|
|
1964
|
+
message: `Port "${portName}" on node type "${nodeType.functionName}" has invalid type "${portDef.dataType}".`,
|
|
1965
|
+
node: nodeType.functionName,
|
|
1966
|
+
location: nodeType.sourceLocation
|
|
1967
|
+
});
|
|
1968
|
+
}
|
|
1969
|
+
}
|
|
1970
|
+
}
|
|
1971
|
+
}
|
|
1972
|
+
function validatePortConfigReferences(ctx, workflow, instanceMap) {
|
|
1973
|
+
for (const instance of workflow.instances) {
|
|
1974
|
+
const portConfigs = instance.config?.portConfigs;
|
|
1975
|
+
if (!portConfigs) continue;
|
|
1976
|
+
const nodeType = instanceMap.get(instance.id);
|
|
1977
|
+
if (!nodeType) continue;
|
|
1978
|
+
const allPorts = /* @__PURE__ */ new Set([
|
|
1979
|
+
...Object.keys(nodeType.inputs),
|
|
1980
|
+
...Object.keys(nodeType.outputs)
|
|
1981
|
+
]);
|
|
1982
|
+
for (const pc of portConfigs) {
|
|
1983
|
+
if (!allPorts.has(pc.portName)) {
|
|
1984
|
+
const suggestions = findClosestMatches(pc.portName, [...allPorts]);
|
|
1985
|
+
const hint = suggestions.length > 0 ? ` Did you mean "${suggestions[0]}"?` : "";
|
|
1986
|
+
ctx.warnings.push({
|
|
1987
|
+
type: "warning",
|
|
1988
|
+
code: "INVALID_PORT_CONFIG_REF",
|
|
1989
|
+
message: `Instance "${instance.id}" references port "${pc.portName}" in portConfig, but this port does not exist on node type "${instance.nodeType}".${hint}`,
|
|
1990
|
+
node: instance.id,
|
|
1991
|
+
location: instance.sourceLocation
|
|
1992
|
+
});
|
|
1993
|
+
}
|
|
1994
|
+
}
|
|
1995
|
+
}
|
|
1996
|
+
}
|
|
1997
|
+
function expressionSyntaxProblem(expression) {
|
|
1998
|
+
const text = expression.trim();
|
|
1999
|
+
if (text.length === 0) return null;
|
|
2000
|
+
const { diagnostics } = ts.transpileModule(`(${text});`, {
|
|
2001
|
+
reportDiagnostics: true,
|
|
2002
|
+
compilerOptions: { target: ts.ScriptTarget.Latest, module: ts.ModuleKind.ESNext }
|
|
2003
|
+
});
|
|
2004
|
+
if (!diagnostics || diagnostics.length === 0) return null;
|
|
2005
|
+
const reason = ts.flattenDiagnosticMessageText(diagnostics[0].messageText, " ");
|
|
2006
|
+
const looksLikeText = /^[A-Za-z0-9][\w\s.,:%/-]*$/.test(text) && !/^[A-Za-z_$][\w$]*(\.[\w$]+)*$/.test(text);
|
|
2007
|
+
const hint = looksLikeText ? ` If you meant the text ${JSON.stringify(text)}, quote it inside the attribute: ="'${text}'".` : "";
|
|
2008
|
+
return `${reason}.${hint}`;
|
|
2009
|
+
}
|
|
2010
|
+
function validateExpressionSyntax(ctx, workflow) {
|
|
2011
|
+
for (const instance of workflow.instances) {
|
|
2012
|
+
for (const pc of instance.config?.portConfigs ?? []) {
|
|
2013
|
+
if (pc.expression === void 0) continue;
|
|
2014
|
+
const problem = expressionSyntaxProblem(pc.expression);
|
|
2015
|
+
if (!problem) continue;
|
|
2016
|
+
ctx.errors.push({
|
|
2017
|
+
type: "error",
|
|
2018
|
+
code: "EXPRESSION_SYNTAX",
|
|
2019
|
+
message: `The [expr:] binding for "${pc.portName}" on "${instance.id}" is not a JavaScript expression: ${pc.expression}. ${problem}`,
|
|
2020
|
+
node: instance.id,
|
|
2021
|
+
location: instance.sourceLocation
|
|
2022
|
+
});
|
|
2023
|
+
}
|
|
2024
|
+
}
|
|
2025
|
+
for (const nodeType of workflow.nodeTypes) {
|
|
2026
|
+
for (const [portName, port] of Object.entries(nodeType.inputs)) {
|
|
2027
|
+
if (port.expression === void 0) continue;
|
|
2028
|
+
const problem = expressionSyntaxProblem(port.expression);
|
|
2029
|
+
if (!problem) continue;
|
|
2030
|
+
ctx.errors.push({
|
|
2031
|
+
type: "error",
|
|
2032
|
+
code: "EXPRESSION_SYNTAX",
|
|
2033
|
+
message: `The Expression: default of input "${portName}" on node type "${nodeType.functionName}" is not a JavaScript expression: ${port.expression}. ${problem}`,
|
|
2034
|
+
location: nodeType.sourceLocation
|
|
2035
|
+
});
|
|
2036
|
+
}
|
|
2037
|
+
}
|
|
2038
|
+
}
|
|
2039
|
+
function validateExecuteWhen(ctx, workflow) {
|
|
2040
|
+
const validStrategies = Object.values(EXECUTION_STRATEGIES);
|
|
2041
|
+
for (const nodeType of workflow.nodeTypes) {
|
|
2042
|
+
if (nodeType.executeWhen && !validStrategies.includes(nodeType.executeWhen)) {
|
|
2043
|
+
const suggestions = findClosestMatches(nodeType.executeWhen, validStrategies);
|
|
2044
|
+
const hint = suggestions.length > 0 ? ` Did you mean "${suggestions[0]}"?` : "";
|
|
2045
|
+
ctx.warnings.push({
|
|
2046
|
+
type: "warning",
|
|
2047
|
+
code: "INVALID_EXECUTE_WHEN",
|
|
2048
|
+
message: `Node type "${nodeType.functionName}" has invalid @executeWhen value "${nodeType.executeWhen}".${hint} Valid values: ${validStrategies.join(", ")}.`,
|
|
2049
|
+
node: nodeType.functionName,
|
|
2050
|
+
location: nodeType.sourceLocation
|
|
2051
|
+
});
|
|
2052
|
+
}
|
|
2053
|
+
}
|
|
2054
|
+
}
|
|
2055
|
+
|
|
2056
|
+
// src/validation/validator.ts
|
|
2057
|
+
var DOCS_BASE = "https://github.com/synergenius-fw/flow-weaver/blob/main/docs/reference";
|
|
2058
|
+
var doc = (topic, anchor) => `${DOCS_BASE}/${topic}.md${anchor ? `#${anchor}` : ""}`;
|
|
2059
|
+
var ERROR_DOC_URLS = {
|
|
2060
|
+
UNKNOWN_NODE_TYPE: doc("concepts", "node-registration"),
|
|
2061
|
+
UNKNOWN_SOURCE_PORT: doc("error-codes"),
|
|
2062
|
+
UNKNOWN_TARGET_PORT: doc("error-codes"),
|
|
2063
|
+
TYPE_MISMATCH: doc("error-codes"),
|
|
2064
|
+
INVALID_SCOPE_NAME: doc("error-codes"),
|
|
2065
|
+
INFERRED_NODE_TYPE: doc("node-conversion"),
|
|
2066
|
+
DUPLICATE_CONNECTION: doc("error-codes"),
|
|
2067
|
+
STUB_NODE: doc("scaffold"),
|
|
2068
|
+
COERCE_TYPE_MISMATCH: doc("compilation"),
|
|
2069
|
+
REDUNDANT_COERCE: doc("compilation"),
|
|
2070
|
+
COERCE_ON_FUNCTION_PORT: doc("compilation")
|
|
2071
|
+
};
|
|
2072
|
+
var CASCADING_CODES = /* @__PURE__ */ new Set(["UNKNOWN_SOURCE_NODE", "UNKNOWN_TARGET_NODE", "MISSING_REQUIRED_INPUT"]);
|
|
2073
|
+
function findNodeType(workflow, nodeTypeName) {
|
|
2074
|
+
return workflow.nodeTypes.find((nt) => nt.name === nodeTypeName || nt.functionName === nodeTypeName);
|
|
2075
|
+
}
|
|
2076
|
+
function indexNodeTypes(workflow) {
|
|
2077
|
+
const nodeTypeMap = /* @__PURE__ */ new Map();
|
|
2078
|
+
workflow.nodeTypes.forEach((nodeType) => {
|
|
2079
|
+
nodeTypeMap.set(nodeType.functionName, nodeType);
|
|
2080
|
+
if (nodeType.name !== nodeType.functionName) {
|
|
2081
|
+
nodeTypeMap.set(nodeType.name, nodeType);
|
|
2082
|
+
}
|
|
2083
|
+
});
|
|
2084
|
+
return nodeTypeMap;
|
|
2085
|
+
}
|
|
2086
|
+
function resolveInstances(ctx, workflow) {
|
|
2087
|
+
const instanceMap = /* @__PURE__ */ new Map();
|
|
2088
|
+
workflow.instances.forEach((instance) => {
|
|
2089
|
+
const nodeType = findNodeType(workflow, instance.nodeType);
|
|
2090
|
+
if (nodeType) {
|
|
2091
|
+
instanceMap.set(instance.id, nodeType);
|
|
2092
|
+
return;
|
|
2093
|
+
}
|
|
2094
|
+
const isUnannotatedFunction = workflow.availableFunctionNames?.includes(instance.nodeType) ?? false;
|
|
2095
|
+
let hint;
|
|
2096
|
+
if (isUnannotatedFunction) {
|
|
2097
|
+
hint = ` Function "${instance.nodeType}" exists but has no @flowWeaver nodeType annotation. Add /** @flowWeaver nodeType */ above it.`;
|
|
2098
|
+
} else {
|
|
2099
|
+
const availableTypes = workflow.nodeTypes.map((nt) => nt.functionName);
|
|
2100
|
+
const suggestions = findClosestMatches(instance.nodeType, availableTypes);
|
|
2101
|
+
hint = suggestions.length > 0 ? ` Did you mean "${suggestions[0]}"?` : "";
|
|
2102
|
+
}
|
|
2103
|
+
ctx.errors.push({
|
|
2104
|
+
type: "error",
|
|
2105
|
+
code: "UNKNOWN_NODE_TYPE",
|
|
2106
|
+
message: `Node "${instance.id}" references unknown node type "${instance.nodeType}".${hint}`,
|
|
2107
|
+
node: instance.id,
|
|
2108
|
+
location: instance.sourceLocation
|
|
2109
|
+
});
|
|
2110
|
+
});
|
|
2111
|
+
return instanceMap;
|
|
2112
|
+
}
|
|
2113
|
+
function reportInferredNodeTypes(ctx, workflow) {
|
|
2114
|
+
workflow.instances.forEach((instance) => {
|
|
2115
|
+
const nodeType = findNodeType(workflow, instance.nodeType);
|
|
2116
|
+
if (nodeType?.inferred && nodeType.variant !== "STUB") {
|
|
2117
|
+
ctx.warnings.push({
|
|
2118
|
+
type: "warning",
|
|
2119
|
+
code: "INFERRED_NODE_TYPE",
|
|
2120
|
+
message: `Node type "${instance.nodeType}" was auto-inferred from function signature (expression mode). Add @flowWeaver nodeType for explicit port control.`,
|
|
2121
|
+
node: instance.id,
|
|
2122
|
+
location: instance.sourceLocation
|
|
2123
|
+
});
|
|
2124
|
+
}
|
|
2125
|
+
});
|
|
2126
|
+
}
|
|
2127
|
+
function reportStubNodes(ctx, workflow) {
|
|
2128
|
+
workflow.instances.forEach((instance) => {
|
|
2129
|
+
const nodeType = findNodeType(workflow, instance.nodeType);
|
|
2130
|
+
if (nodeType?.variant === "STUB") {
|
|
2131
|
+
ctx.errors.push({
|
|
2132
|
+
type: "error",
|
|
2133
|
+
code: "STUB_NODE",
|
|
2134
|
+
message: `Node "${instance.id}" uses stub type "${instance.nodeType}" which has no implementation. Use draft mode to validate structure, or implement the node.`,
|
|
2135
|
+
node: instance.id,
|
|
2136
|
+
location: instance.sourceLocation
|
|
2137
|
+
});
|
|
2138
|
+
}
|
|
2139
|
+
});
|
|
2140
|
+
}
|
|
2141
|
+
function runCoreRules(ctx, workflow, nodeTypeMap, instanceMap) {
|
|
2142
|
+
const rules = [
|
|
2143
|
+
// Structural validation
|
|
2144
|
+
{ name: "structure", run: () => validateStructure(ctx, workflow) },
|
|
2145
|
+
{ name: "duplicateNodeNames", run: () => validateDuplicateNodeNames(ctx, workflow) },
|
|
2146
|
+
{ name: "duplicateInstanceIds", run: () => validateDuplicateInstanceIds(ctx, workflow) },
|
|
2147
|
+
{ name: "mutableBindings", run: () => validateMutableBindings(ctx, workflow) },
|
|
2148
|
+
// Connection and node validation
|
|
2149
|
+
{ name: "reservedNames", run: () => validateReservedNames(ctx, workflow, nodeTypeMap) },
|
|
2150
|
+
{ name: "connections", run: () => validateConnections(ctx, workflow, instanceMap) },
|
|
2151
|
+
{ name: "duplicateConnections", run: () => validateDuplicateConnections(ctx, workflow) },
|
|
2152
|
+
{ name: "scopeNames", run: () => validateScopeNames(ctx, workflow) },
|
|
2153
|
+
{ name: "typeCompatibility", run: () => validateTypeCompatibility(ctx, workflow, instanceMap) },
|
|
2154
|
+
{ name: "requiredInputs", run: () => validateRequiredInputs(ctx, workflow, instanceMap) },
|
|
2155
|
+
{ name: "unusedNodes", run: () => detectUnusedNodes(ctx, workflow, instanceMap) },
|
|
2156
|
+
{ name: "startAndExit", run: () => validateStartAndExit(ctx, workflow) },
|
|
2157
|
+
{ name: "dataFlow", run: () => validateDataFlow(ctx, workflow, instanceMap) },
|
|
2158
|
+
{ name: "cycles", run: () => validateCycles(ctx, workflow) },
|
|
2159
|
+
{ name: "multipleInputConnections", run: () => validateMultipleInputConnections(ctx, workflow, instanceMap) },
|
|
2160
|
+
{ name: "annotationSignatureConsistency", run: () => validateAnnotationSignatureConsistency(ctx, workflow) },
|
|
2161
|
+
{ name: "visualAnnotations", run: () => validateVisualAnnotations(ctx, workflow, instanceMap) },
|
|
2162
|
+
{ name: "portTypes", run: () => validatePortTypes(ctx, workflow) },
|
|
2163
|
+
{ name: "portConfigReferences", run: () => validatePortConfigReferences(ctx, workflow, instanceMap) },
|
|
2164
|
+
{ name: "expressionSyntax", run: () => validateExpressionSyntax(ctx, workflow) },
|
|
2165
|
+
{ name: "executeWhen", run: () => validateExecuteWhen(ctx, workflow) },
|
|
2166
|
+
{ name: "scopeTopology", run: () => validateScopeTopology(ctx, workflow, instanceMap) }
|
|
2167
|
+
];
|
|
2168
|
+
for (const rule of rules) {
|
|
2169
|
+
rule.run();
|
|
2170
|
+
}
|
|
2171
|
+
}
|
|
2172
|
+
function dropCascadingErrors(ctx, workflow, nodeTypeMap) {
|
|
2173
|
+
const unknownTypeInstanceIds = new Set(
|
|
2174
|
+
workflow.instances.filter((inst) => !nodeTypeMap.has(inst.nodeType)).map((inst) => inst.id)
|
|
2175
|
+
);
|
|
2176
|
+
if (unknownTypeInstanceIds.size === 0) return;
|
|
2177
|
+
ctx.errors = ctx.errors.filter((error) => {
|
|
2178
|
+
if (error.code === "UNKNOWN_NODE_TYPE") return true;
|
|
2179
|
+
if (!CASCADING_CODES.has(error.code)) return true;
|
|
2180
|
+
if (error.node && unknownTypeInstanceIds.has(error.node)) return false;
|
|
2181
|
+
if (error.connection) {
|
|
2182
|
+
if (unknownTypeInstanceIds.has(error.connection.from.node)) return false;
|
|
2183
|
+
if (unknownTypeInstanceIds.has(error.connection.to.node)) return false;
|
|
2184
|
+
}
|
|
2185
|
+
return true;
|
|
2186
|
+
});
|
|
2187
|
+
}
|
|
2188
|
+
function demoteStubErrors(ctx, workflow) {
|
|
2189
|
+
const stubTypes = workflow.nodeTypes.filter((nt) => nt.variant === "STUB");
|
|
2190
|
+
const stubTypeNames = new Set(stubTypes.map((nt) => nt.functionName));
|
|
2191
|
+
stubTypes.forEach((nt) => {
|
|
2192
|
+
stubTypeNames.add(nt.name);
|
|
2193
|
+
});
|
|
2194
|
+
const stubInstanceIds = new Set(
|
|
2195
|
+
workflow.instances.filter((inst) => stubTypeNames.has(inst.nodeType)).map((inst) => inst.id)
|
|
2196
|
+
);
|
|
2197
|
+
const promoted = [];
|
|
2198
|
+
ctx.errors = ctx.errors.filter((err) => {
|
|
2199
|
+
if (err.code === "STUB_NODE") {
|
|
2200
|
+
promoted.push({ ...err, type: "warning" });
|
|
2201
|
+
return false;
|
|
2202
|
+
}
|
|
2203
|
+
if (err.code === "MISSING_REQUIRED_INPUT" && err.node && stubInstanceIds.has(err.node)) {
|
|
2204
|
+
promoted.push({ ...err, type: "warning" });
|
|
2205
|
+
return false;
|
|
2206
|
+
}
|
|
2207
|
+
return true;
|
|
2208
|
+
});
|
|
2209
|
+
ctx.warnings.push(...promoted);
|
|
2210
|
+
}
|
|
2211
|
+
function applyWarningSuppressions(ctx, workflow) {
|
|
2212
|
+
const suppressMap = /* @__PURE__ */ new Map();
|
|
2213
|
+
for (const inst of workflow.instances) {
|
|
2214
|
+
if (inst.config?.suppressWarnings?.length) {
|
|
2215
|
+
suppressMap.set(inst.id, new Set(inst.config.suppressWarnings));
|
|
2216
|
+
}
|
|
2217
|
+
}
|
|
2218
|
+
if (suppressMap.size === 0) return;
|
|
2219
|
+
ctx.warnings = ctx.warnings.filter((w) => {
|
|
2220
|
+
if (!w.node) return true;
|
|
2221
|
+
const codes = suppressMap.get(w.node);
|
|
2222
|
+
return !codes || !codes.has(w.code);
|
|
2223
|
+
});
|
|
2224
|
+
}
|
|
2225
|
+
function attachDocUrls(ctx) {
|
|
2226
|
+
for (const diag of [...ctx.errors, ...ctx.warnings]) {
|
|
2227
|
+
if (!diag.docUrl && ERROR_DOC_URLS[diag.code]) {
|
|
2228
|
+
diag.docUrl = ERROR_DOC_URLS[diag.code];
|
|
2229
|
+
}
|
|
2230
|
+
}
|
|
2231
|
+
}
|
|
2232
|
+
var WorkflowValidator = class {
|
|
2233
|
+
ctx = { errors: [], warnings: [], strictMode: false, draftMode: false };
|
|
2234
|
+
/**
|
|
2235
|
+
* The scope-name problems of a single node type, as messages. The same
|
|
2236
|
+
* check runs inside validate() as the INVALID_SCOPE_NAME rule; this is the
|
|
2237
|
+
* standalone form for callers that hold a node type and no workflow.
|
|
2238
|
+
*
|
|
2239
|
+
* Scoped OUTPUT ports become callback parameters (data flows to children)
|
|
2240
|
+
* and scoped INPUT ports become callback return values (data flows from
|
|
2241
|
+
* children); the ports may carry any data type.
|
|
2242
|
+
*/
|
|
2243
|
+
validateNodeType(nodeType) {
|
|
2244
|
+
const ctx = { errors: [], warnings: [], strictMode: false, draftMode: false };
|
|
2245
|
+
validateScopeNames(ctx, {
|
|
2246
|
+
type: "Workflow",
|
|
2247
|
+
name: nodeType.name,
|
|
2248
|
+
functionName: nodeType.functionName,
|
|
2249
|
+
sourceFile: nodeType.sourceLocation?.file ?? "",
|
|
2250
|
+
nodeTypes: [nodeType],
|
|
2251
|
+
instances: [],
|
|
2252
|
+
connections: [],
|
|
2253
|
+
startPorts: {},
|
|
2254
|
+
exitPorts: {},
|
|
2255
|
+
imports: []
|
|
2256
|
+
});
|
|
2257
|
+
return ctx.errors.map((e) => e.message);
|
|
2258
|
+
}
|
|
2259
|
+
/**
|
|
2260
|
+
* Validate a workflow: resolve its instances, run the core rules in their
|
|
2261
|
+
* fixed order, then post-process the diagnostics (drop cascading errors,
|
|
2262
|
+
* demote stub errors in draft mode, apply suppressions, attach doc URLs).
|
|
2263
|
+
*/
|
|
2264
|
+
validate(workflow, options) {
|
|
2265
|
+
this.ctx = {
|
|
2266
|
+
errors: [],
|
|
2267
|
+
warnings: [],
|
|
2268
|
+
strictMode: options?.strictMode ?? options?.mode === "strict",
|
|
2269
|
+
draftMode: options?.mode === "draft"
|
|
2270
|
+
};
|
|
2271
|
+
const ctx = this.ctx;
|
|
2272
|
+
const nodeTypeMap = indexNodeTypes(workflow);
|
|
2273
|
+
const instanceMap = resolveInstances(ctx, workflow);
|
|
2274
|
+
reportInferredNodeTypes(ctx, workflow);
|
|
2275
|
+
reportStubNodes(ctx, workflow);
|
|
2276
|
+
runCoreRules(ctx, workflow, nodeTypeMap, instanceMap);
|
|
2277
|
+
dropCascadingErrors(ctx, workflow, nodeTypeMap);
|
|
2278
|
+
if (ctx.draftMode) {
|
|
2279
|
+
demoteStubErrors(ctx, workflow);
|
|
2280
|
+
}
|
|
2281
|
+
applyWarningSuppressions(ctx, workflow);
|
|
2282
|
+
attachDocUrls(ctx);
|
|
2283
|
+
return {
|
|
2284
|
+
valid: ctx.errors.length === 0,
|
|
2285
|
+
errors: ctx.errors,
|
|
2286
|
+
warnings: ctx.warnings
|
|
2287
|
+
};
|
|
2288
|
+
}
|
|
2289
|
+
};
|
|
2290
|
+
var validator = new WorkflowValidator();
|
|
2291
|
+
|
|
2292
|
+
export {
|
|
2293
|
+
COERCE_TYPE_FOR_DATA_TYPE,
|
|
2294
|
+
resolveNodeType,
|
|
2295
|
+
getOutgoing,
|
|
2296
|
+
validator
|
|
2297
|
+
};
|