@intentius/chant 0.124.12 → 0.124.14
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/bin/chant +11 -0
- package/dist/agents/checks.js +326 -0
- package/dist/agents/discover.js +885 -0
- package/dist/agents/importer.js +17 -0
- package/dist/agents/index.js +12 -0
- package/dist/agents/types.js +19 -0
- package/dist/apply.js +151 -0
- package/dist/attrref.js +70 -0
- package/dist/audit/catalog.js +350 -0
- package/dist/audit/core.js +252 -0
- package/dist/audit/discover.js +633 -0
- package/dist/audit/fetch.js +666 -0
- package/dist/audit/lineage.js +91 -0
- package/dist/audit/nginx.js +366 -0
- package/dist/audit/prior-art.js +132 -0
- package/dist/audit/proof.js +321 -0
- package/dist/audit/report-html.js +194 -0
- package/dist/audit/report-model.js +198 -0
- package/dist/audit/report.js +102 -0
- package/dist/audit/rules-doc.js +144 -0
- package/dist/audit/secrets.js +405 -0
- package/dist/audit/terraform-state.js +140 -0
- package/dist/audit/wrangler.js +262 -0
- package/dist/behaviour-delta.js +401 -0
- package/dist/behaviour-engine.js +357 -0
- package/dist/behaviour-graph.js +83 -0
- package/dist/behaviour-http.js +188 -0
- package/dist/behaviour-kinds.js +172 -0
- package/dist/behaviour-overlay.js +50 -0
- package/dist/behaviour-predict.js +188 -0
- package/dist/behaviour-request.js +194 -0
- package/dist/behaviour.js +1325 -0
- package/dist/build-params.js +108 -0
- package/dist/build.js +668 -0
- package/dist/builder.js +44 -0
- package/dist/cdk/advise.js +30 -0
- package/dist/cdk/assembly.js +122 -0
- package/dist/cdk/graph.js +444 -0
- package/dist/cdk/tier-map.js +64 -0
- package/dist/cdk/types.js +24 -0
- package/dist/change-set.js +312 -0
- package/dist/child-project.js +21 -0
- package/dist/claimed-fields.js +135 -0
- package/dist/cli/build-options.js +70 -0
- package/dist/cli/build-params-cli.js +139 -0
- package/dist/cli/command-group.js +123 -0
- package/dist/cli/commands/audit-agents.js +326 -0
- package/dist/cli/commands/audit.js +571 -0
- package/dist/cli/commands/build.js +920 -0
- package/dist/cli/commands/carve-apply.js +153 -0
- package/dist/cli/commands/carve-bridge.js +201 -0
- package/dist/cli/commands/carve-emit.js +332 -0
- package/dist/cli/commands/carve-status.js +119 -0
- package/dist/cli/commands/carve.js +204 -0
- package/dist/cli/commands/check-lexicon-docs.js +79 -0
- package/dist/cli/commands/check-lexicon-examples.js +177 -0
- package/dist/cli/commands/check-lexicon-intrinsics.js +291 -0
- package/dist/cli/commands/check-lexicon-mcp.js +82 -0
- package/dist/cli/commands/check-lexicon-plugin.d.ts.map +1 -1
- package/dist/cli/commands/check-lexicon-plugin.js +104 -0
- package/dist/cli/commands/check-lexicon.js +766 -0
- package/dist/cli/commands/describe.js +85 -0
- package/dist/cli/commands/diff.js +175 -0
- package/dist/cli/commands/doctor.js +350 -0
- package/dist/cli/commands/import-agents.js +155 -0
- package/dist/cli/commands/import.js +670 -0
- package/dist/cli/commands/init-lexicon/templates/codegen.js +194 -0
- package/dist/cli/commands/init-lexicon/templates/docs.js +100 -0
- package/dist/cli/commands/init-lexicon/templates/examples.js +29 -0
- package/dist/cli/commands/init-lexicon/templates/lint.js +34 -0
- package/dist/cli/commands/init-lexicon/templates/lsp.js +37 -0
- package/dist/cli/commands/init-lexicon/templates/plugin.js +108 -0
- package/dist/cli/commands/init-lexicon/templates/project.js +240 -0
- package/dist/cli/commands/init-lexicon/templates/spec.js +56 -0
- package/dist/cli/commands/init-lexicon/templates/tests.js +66 -0
- package/dist/cli/commands/init-lexicon.js +172 -0
- package/dist/cli/commands/init.js +381 -0
- package/dist/cli/commands/lexicon-rolling-upgrade.js +145 -0
- package/dist/cli/commands/lexicon-surface-diff.js +145 -0
- package/dist/cli/commands/licenses.js +125 -0
- package/dist/cli/commands/lint.d.ts.map +1 -1
- package/dist/cli/commands/lint.js +948 -0
- package/dist/cli/commands/list.js +63 -0
- package/dist/cli/commands/migrate.d.ts.map +1 -1
- package/dist/cli/commands/migrate.js +423 -0
- package/dist/cli/commands/onboard.js +403 -0
- package/dist/cli/commands/pinned-upgrade.js +191 -0
- package/dist/cli/commands/update.js +194 -0
- package/dist/cli/commands/vendor.js +217 -0
- package/dist/cli/conflict-check.js +104 -0
- package/dist/cli/debug.js +8 -0
- package/dist/cli/format.js +104 -0
- package/dist/cli/handlers/build.js +267 -0
- package/dist/cli/handlers/carve-apply.js +30 -0
- package/dist/cli/handlers/carve-bridge.js +28 -0
- package/dist/cli/handlers/carve-emit.js +50 -0
- package/dist/cli/handlers/carve-status.js +26 -0
- package/dist/cli/handlers/carve.js +40 -0
- package/dist/cli/handlers/change-set.js +46 -0
- package/dist/cli/handlers/components.js +730 -0
- package/dist/cli/handlers/dev.js +113 -0
- package/dist/cli/handlers/emulator.js +233 -0
- package/dist/cli/handlers/explain.js +54 -0
- package/dist/cli/handlers/fan-out.js +422 -0
- package/dist/cli/handlers/gate-resume.js +275 -0
- package/dist/cli/handlers/generate.js +84 -0
- package/dist/cli/handlers/graph.js +969 -0
- package/dist/cli/handlers/init.js +102 -0
- package/dist/cli/handlers/lifecycle.js +1727 -0
- package/dist/cli/handlers/lint.js +62 -0
- package/dist/cli/handlers/migrate.js +48 -0
- package/dist/cli/handlers/misc.js +391 -0
- package/dist/cli/handlers/operator.js +1162 -0
- package/dist/cli/handlers/override-approve.js +102 -0
- package/dist/cli/handlers/pr.js +503 -0
- package/dist/cli/handlers/promote.js +342 -0
- package/dist/cli/handlers/run-generate.js +206 -0
- package/dist/cli/handlers/run-wave.js +66 -0
- package/dist/cli/handlers/run.js +1191 -0
- package/dist/cli/handlers/scenario.js +325 -0
- package/dist/cli/handlers/search.js +924 -0
- package/dist/cli/handlers/serve.js +32 -0
- package/dist/cli/handlers/vendor.js +154 -0
- package/dist/cli/index.js +3 -0
- package/dist/cli/is-entry-point.js +23 -0
- package/dist/cli/lsp/capabilities.js +28 -0
- package/dist/cli/lsp/diagnostics.js +34 -0
- package/dist/cli/lsp/server.js +329 -0
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/main.js +2540 -0
- package/dist/cli/mcp/lifecycle-tools.js +80 -0
- package/dist/cli/mcp/op-tools.js +306 -0
- package/dist/cli/mcp/resource-handlers.js +258 -0
- package/dist/cli/mcp/resources/context.js +85 -0
- package/dist/cli/mcp/server.js +353 -0
- package/dist/cli/mcp/tools/build.js +111 -0
- package/dist/cli/mcp/tools/composites.js +95 -0
- package/dist/cli/mcp/tools/explain.js +166 -0
- package/dist/cli/mcp/tools/import.js +49 -0
- package/dist/cli/mcp/tools/lint.js +41 -0
- package/dist/cli/mcp/tools/scaffold.js +111 -0
- package/dist/cli/mcp/tools/search.js +112 -0
- package/dist/cli/mcp/types.js +1 -0
- package/dist/cli/mcp/workspace-plugins.js +91 -0
- package/dist/cli/mcp/workspace-tools.d.ts +1 -1
- package/dist/cli/mcp/workspace-tools.js +564 -0
- package/dist/cli/mcp-config.js +70 -0
- package/dist/cli/plugins.js +313 -0
- package/dist/cli/registry.js +23 -0
- package/dist/cli/reporters/stylish.js +329 -0
- package/dist/cli/version.js +15 -0
- package/dist/cli/watch.js +79 -0
- package/dist/codegen/bound-property-types.js +82 -0
- package/dist/codegen/coverage.js +119 -0
- package/dist/codegen/docs-file-markers.js +60 -0
- package/dist/codegen/docs-pages.js +115 -0
- package/dist/codegen/docs-rule-scanning.js +164 -0
- package/dist/codegen/docs-rules.js +76 -0
- package/dist/codegen/docs-sections.js +117 -0
- package/dist/codegen/docs-sidebar.js +65 -0
- package/dist/codegen/docs-types.js +4 -0
- package/dist/codegen/docs.js +356 -0
- package/dist/codegen/fetch.js +340 -0
- package/dist/codegen/generate-post-synth-barrel.js +63 -0
- package/dist/codegen/generate-registry.js +71 -0
- package/dist/codegen/generate-runtime-index.js +56 -0
- package/dist/codegen/generate-typescript.js +119 -0
- package/dist/codegen/generate.js +115 -0
- package/dist/codegen/json-patch.js +141 -0
- package/dist/codegen/json-schema-to-ts.js +344 -0
- package/dist/codegen/json-schema.js +246 -0
- package/dist/codegen/lexicon-regen.js +412 -0
- package/dist/codegen/naming.js +217 -0
- package/dist/codegen/okf-lexicon.js +245 -0
- package/dist/codegen/package.js +150 -0
- package/dist/codegen/pinned-upgrade.d.ts.map +1 -1
- package/dist/codegen/pinned-upgrade.js +494 -0
- package/dist/codegen/registry.js +60 -0
- package/dist/codegen/rehype-base-url.mjs +68 -0
- package/dist/codegen/rolling-upgrade.js +217 -0
- package/dist/codegen/surface-snapshot.js +537 -0
- package/dist/codegen/testdata/postgres-tags.json +242 -0
- package/dist/codegen/topo-sort.js +36 -0
- package/dist/codegen/typecheck.js +115 -0
- package/dist/codegen/validate.js +200 -0
- package/dist/codegen/version-bump.js +35 -0
- package/dist/components/auto-release.js +143 -0
- package/dist/components/builders.js +47 -0
- package/dist/components/capability-plugin-loader.js +175 -0
- package/dist/components/capability-plugin-schema.js +46 -0
- package/dist/components/capability-plugin.js +99 -0
- package/dist/components/capability.js +60 -0
- package/dist/components/changed-files.js +72 -0
- package/dist/components/cli-support.js +427 -0
- package/dist/components/component.js +120 -0
- package/dist/components/component.schema.json +271 -0
- package/dist/components/config-defaults.js +130 -0
- package/dist/components/deploy-units.js +60 -0
- package/dist/components/discover.d.ts.map +1 -1
- package/dist/components/discover.js +189 -0
- package/dist/components/driver-output.js +86 -0
- package/dist/components/driver.js +728 -0
- package/dist/components/fan-out-output.js +165 -0
- package/dist/components/fan-out-record.js +94 -0
- package/dist/components/fan-out-run.js +373 -0
- package/dist/components/fan-out-support.js +60 -0
- package/dist/components/fan-out.js +273 -0
- package/dist/components/gate-plan.js +41 -0
- package/dist/components/gated-wave-pipeline.js +46 -0
- package/dist/components/index.js +24 -0
- package/dist/components/layers.js +28 -0
- package/dist/components/manifest-persistence.js +108 -0
- package/dist/components/pilots/alb-ecs.pilot.js +59 -0
- package/dist/components/pilots/dynamodb.pilot.js +51 -0
- package/dist/components/pilots/jar-emr.pilot.js +65 -0
- package/dist/components/pilots/lambda.pilot.js +52 -0
- package/dist/components/pilots/neo4j-fanout.pilot.js +68 -0
- package/dist/components/pilots/project.js +12 -0
- package/dist/components/pr-pipeline.js +134 -0
- package/dist/components/pr-run.js +363 -0
- package/dist/components/presets/ecs-fargate.js +72 -0
- package/dist/components/presets/index.js +28 -0
- package/dist/components/presets/lambda.js +34 -0
- package/dist/components/presets/single-host-compose.js +41 -0
- package/dist/components/promote.js +549 -0
- package/dist/components/registry.js +34 -0
- package/dist/components/run-progress.js +33 -0
- package/dist/components/sandbox/driver.d.ts.map +1 -1
- package/dist/components/sandbox/driver.js +93 -0
- package/dist/components/sandbox/run.js +115 -0
- package/dist/components/starter-plugin.js +104 -0
- package/dist/components/verbs/__tests__/mock-cloud-executor.js +68 -0
- package/dist/components/verbs/__tests__/mock-process-runner.js +45 -0
- package/dist/components/verbs/__tests__/mock-sbom-generator.js +56 -0
- package/dist/components/verbs/bom-writer.js +287 -0
- package/dist/components/verbs/build-archive.js +188 -0
- package/dist/components/verbs/build.js +142 -0
- package/dist/components/verbs/cloud-executor.js +110 -0
- package/dist/components/verbs/component-bom.js +125 -0
- package/dist/components/verbs/ensure-secret.js +50 -0
- package/dist/components/verbs/index.js +61 -0
- package/dist/components/verbs/license-policy.js +75 -0
- package/dist/components/verbs/lockfile-sbom-generator.js +191 -0
- package/dist/components/verbs/process-runner.js +78 -0
- package/dist/components/verbs/r2-sync.js +93 -0
- package/dist/components/verbs/reproducibility.js +62 -0
- package/dist/components/verbs/run-agent.js +577 -0
- package/dist/components/verbs/sbom-generator.js +119 -0
- package/dist/components/verbs/sbom.js +97 -0
- package/dist/components/verbs/shell.js +32 -0
- package/dist/components/verbs/sign.js +221 -0
- package/dist/components/verbs/stub.js +28 -0
- package/dist/components/verbs/tool-sbom-generator.js +154 -0
- package/dist/components/verbs/verify.js +112 -0
- package/dist/components/verbs/vex.js +131 -0
- package/dist/components/verbs/vuln-gate.js +152 -0
- package/dist/components/verbs/vuln-scan.js +288 -0
- package/dist/components/verbs/wait-verify.js +106 -0
- package/dist/components/verbs/wrangler.js +179 -0
- package/dist/components/wave-plan.js +102 -0
- package/dist/composite.js +305 -0
- package/dist/config-import.d.ts.map +1 -1
- package/dist/config-import.js +22 -0
- package/dist/config-sandbox.js +122 -0
- package/dist/config-static.js +206 -0
- package/dist/config.js +605 -0
- package/dist/content-digest.js +23 -0
- package/dist/declarable.js +114 -0
- package/dist/deep-observation.js +437 -0
- package/dist/detectLexicon.js +54 -0
- package/dist/discovery/cache.js +70 -0
- package/dist/discovery/collect.js +208 -0
- package/dist/discovery/cycles.js +95 -0
- package/dist/discovery/entity-wire-codec.js +391 -0
- package/dist/discovery/entity-wire.js +42 -0
- package/dist/discovery/files.js +121 -0
- package/dist/discovery/fold-import.d.ts.map +1 -1
- package/dist/discovery/fold-import.js +4178 -0
- package/dist/discovery/fold-rank.js +292 -0
- package/dist/discovery/graph.js +115 -0
- package/dist/discovery/import.d.ts.map +1 -1
- package/dist/discovery/import.js +65 -0
- package/dist/discovery/index.js +333 -0
- package/dist/discovery/param-deps.js +487 -0
- package/dist/discovery/resolve.js +39 -0
- package/dist/discovery/sandbox/bundle.js +214 -0
- package/dist/discovery/sandbox/child-errors.js +26 -0
- package/dist/discovery/sandbox/config-run.js +100 -0
- package/dist/discovery/sandbox/config-wire.js +183 -0
- package/dist/discovery/sandbox/driver.d.ts.map +1 -1
- package/dist/discovery/sandbox/driver.js +333 -0
- package/dist/discovery/sandbox/fork.js +229 -0
- package/dist/discovery/sandbox/policy-run.js +142 -0
- package/dist/discovery/sandbox/policy-wire.js +152 -0
- package/dist/discovery/sandbox/run.js +77 -0
- package/dist/discovery/specifier-resolve.js +320 -0
- package/dist/discovery/walk.js +284 -0
- package/dist/effect-receipt.js +340 -0
- package/dist/env.js +55 -0
- package/dist/errors.js +62 -0
- package/dist/fold/fold.js +1434 -0
- package/dist/fold/foldable-helpers.js +229 -0
- package/dist/fold/subset.js +696 -0
- package/dist/fold-provenance.js +414 -0
- package/dist/gate-decision.d.ts +36 -4
- package/dist/gate-decision.d.ts.map +1 -1
- package/dist/gate-decision.js +260 -0
- package/dist/gate-resume-run.js +154 -0
- package/dist/gated-waves.js +165 -0
- package/dist/governance.js +43 -0
- package/dist/graph-declared.js +45 -0
- package/dist/graph-detail.js +207 -0
- package/dist/graph-dot.js +54 -0
- package/dist/graph-effective.js +107 -0
- package/dist/graph-ir.js +623 -0
- package/dist/graph-layout.js +184 -0
- package/dist/graph-lens.js +105 -0
- package/dist/graph-mermaid.js +83 -0
- package/dist/graph-ops.js +39 -0
- package/dist/graph-refs.js +156 -0
- package/dist/held-elsewhere.js +87 -0
- package/dist/identity.js +251 -0
- package/dist/import/base-parser.js +34 -0
- package/dist/import/embedded.js +255 -0
- package/dist/import/generator.js +1 -0
- package/dist/import/ir-utils.js +85 -0
- package/dist/import/parser-options.js +45 -0
- package/dist/import/parser.js +1 -0
- package/dist/index.js +118 -0
- package/dist/intrinsic-interpolation.js +73 -0
- package/dist/intrinsic.js +31 -0
- package/dist/join-key.js +35 -0
- package/dist/kubectl-context.js +150 -0
- package/dist/lexicon-config.js +58 -0
- package/dist/lexicon-integrity.js +47 -0
- package/dist/lexicon-manifest.js +70 -0
- package/dist/lexicon-module.d.ts.map +1 -1
- package/dist/lexicon-module.js +241 -0
- package/dist/lexicon-output.js +218 -0
- package/dist/lexicon-plugin-helpers.js +104 -0
- package/dist/lexicon-schema.js +136 -0
- package/dist/lexicon.js +130 -0
- package/dist/lifecycle/affected.js +224 -0
- package/dist/lifecycle/assert-live.js +110 -0
- package/dist/lifecycle/build-ledger-store.js +160 -0
- package/dist/lifecycle/build-ledger.js +155 -0
- package/dist/lifecycle/change-set.js +356 -0
- package/dist/lifecycle/converge-ledger.js +161 -0
- package/dist/lifecycle/deep-diff.js +233 -0
- package/dist/lifecycle/deep-observe.js +147 -0
- package/dist/lifecycle/digest.js +143 -0
- package/dist/lifecycle/disruption.js +135 -0
- package/dist/lifecycle/gate-applied.js +113 -0
- package/dist/lifecycle/gate-audit.js +341 -0
- package/dist/lifecycle/gate-ledger-select.js +89 -0
- package/dist/lifecycle/gate-ledger.d.ts +8 -0
- package/dist/lifecycle/gate-ledger.d.ts.map +1 -1
- package/dist/lifecycle/gate-ledger.js +193 -0
- package/dist/lifecycle/gate-origin.js +117 -0
- package/dist/lifecycle/gate-pending.js +58 -0
- package/dist/lifecycle/git.js +1182 -0
- package/dist/lifecycle/identity.js +58 -0
- package/dist/lifecycle/index.js +26 -0
- package/dist/lifecycle/lease.js +283 -0
- package/dist/lifecycle/ledger-port.js +1 -0
- package/dist/lifecycle/legacy-digest.js +91 -0
- package/dist/lifecycle/live-diff.js +274 -0
- package/dist/lifecycle/local-note.js +15 -0
- package/dist/lifecycle/member-ledger.js +122 -0
- package/dist/lifecycle/observation-baseline.js +155 -0
- package/dist/lifecycle/observe.js +375 -0
- package/dist/lifecycle/oras-referrer-lookup.js +82 -0
- package/dist/lifecycle/override-ledger.js +54 -0
- package/dist/lifecycle/plan-digest.js +110 -0
- package/dist/lifecycle/plan-ledger.js +129 -0
- package/dist/lifecycle/receipt-plan.js +192 -0
- package/dist/lifecycle/release-ledger.js +155 -0
- package/dist/lifecycle/release-read.js +64 -0
- package/dist/lifecycle/replay.js +193 -0
- package/dist/lifecycle/rollback.js +102 -0
- package/dist/lifecycle/run-ledger.js +183 -0
- package/dist/lifecycle/scenario-eval.js +204 -0
- package/dist/lifecycle/scenario.js +214 -0
- package/dist/lifecycle/snapshot.js +239 -0
- package/dist/lifecycle/status.js +447 -0
- package/dist/lifecycle/symptoms.js +117 -0
- package/dist/lifecycle/teardown.js +255 -0
- package/dist/lifecycle/types.js +1 -0
- package/dist/lifecycle/unobserved-gate.js +33 -0
- package/dist/lifecycle/wave-plans.js +68 -0
- package/dist/lifecycle/work-item-id.js +36 -0
- package/dist/lifecycle/work-lease.js +393 -0
- package/dist/lint/component-checks.js +87 -0
- package/dist/lint/config.js +483 -0
- package/dist/lint/declarative.js +122 -0
- package/dist/lint/discover.d.ts.map +1 -1
- package/dist/lint/discover.js +138 -0
- package/dist/lint/engine.js +246 -0
- package/dist/lint/knowledge-checks.js +64 -0
- package/dist/lint/named-checks.js +22 -0
- package/dist/lint/output-checks.js +87 -0
- package/dist/lint/output-docs.js +163 -0
- package/dist/lint/parser.js +33 -0
- package/dist/lint/pipeline-change-gate.js +70 -0
- package/dist/lint/policy-import.d.ts +1 -1
- package/dist/lint/policy-import.d.ts.map +1 -1
- package/dist/lint/policy-import.js +62 -0
- package/dist/lint/policy-sandbox.js +86 -0
- package/dist/lint/policy.js +122 -0
- package/dist/lint/post-synth.js +87 -0
- package/dist/lint/presets/relaxed.json +26 -0
- package/dist/lint/presets/strict.json +24 -24
- package/dist/lint/receipt-checks.js +83 -0
- package/dist/lint/rule-loader.d.ts.map +1 -1
- package/dist/lint/rule-loader.js +89 -0
- package/dist/lint/rule-registry.js +86 -0
- package/dist/lint/rule.js +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-a.component.js +7 -0
- package/dist/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-b.component.js +7 -0
- package/dist/lint/rules/__fixtures__/comp/comp001/fail/orphan-lib.component.js +9 -0
- package/dist/lint/rules/__fixtures__/comp/comp001/pass/emr-job.component.js +11 -0
- package/dist/lint/rules/__fixtures__/comp/comp001/pass/jar-lib.component.js +9 -0
- package/dist/lint/rules/__fixtures__/comp/comp002/fail/search-service.component.js +25 -0
- package/dist/lint/rules/__fixtures__/comp/comp002/pass/jar-lib.component.js +8 -0
- package/dist/lint/rules/__fixtures__/comp/comp002/pass/search-service.component.js +21 -0
- package/dist/lint/rules/__fixtures__/comp/comp003/fail/migrator.component.js +8 -0
- package/dist/lint/rules/__fixtures__/comp/comp003/pass/agent-turn.component.js +24 -0
- package/dist/lint/rules/__fixtures__/comp/comp003/pass/migrator.component.js +17 -0
- package/dist/lint/rules/__fixtures__/comp/comp003/pass/orders-table.component.js +8 -0
- package/dist/lint/rules/__fixtures__/comp/comp004/fail/neo4j-cluster.component.js +18 -0
- package/dist/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.js +20 -0
- package/dist/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.js +8 -0
- package/dist/lint/rules/__fixtures__/comp/comp005/fail/search-service.component.js +12 -0
- package/dist/lint/rules/__fixtures__/comp/comp005/pass/search-service.component.js +16 -0
- package/dist/lint/rules/__fixtures__/comp/comp006/fail/legacy-tool.component.js +8 -0
- package/dist/lint/rules/__fixtures__/comp/comp006/pass/legacy-tool.component.js +12 -0
- package/dist/lint/rules/__fixtures__/comp/comp007/fail/inventory-table.component.js +11 -0
- package/dist/lint/rules/__fixtures__/comp/comp007/fail/orders-table.component.js +11 -0
- package/dist/lint/rules/__fixtures__/comp/comp007/pass/orders-table.component.js +10 -0
- package/dist/lint/rules/__fixtures__/comp/comp007/pass/search-service.component.js +16 -0
- package/dist/lint/rules/comp/comp001-publishes-never-applies.js +69 -0
- package/dist/lint/rules/comp/comp002-dangling-wiring-ref.js +84 -0
- package/dist/lint/rules/comp/comp003-mutating-no-rollback.js +103 -0
- package/dist/lint/rules/comp/comp004-gate-needs-durable-runtime.js +70 -0
- package/dist/lint/rules/comp/comp005-capability-kind-is-noun.js +109 -0
- package/dist/lint/rules/comp/comp006-shell-needs-reason.js +49 -0
- package/dist/lint/rules/comp/comp007-composition-sprawl.js +64 -0
- package/dist/lint/rules/comp/index.js +33 -0
- package/dist/lint/rules/comp/support.js +129 -0
- package/dist/lint/rules/composite-scope.js +51 -0
- package/dist/lint/rules/cor017-composite-name-match.js +93 -0
- package/dist/lint/rules/cor018-composite-prefer-lexicon-type.js +136 -0
- package/dist/lint/rules/cor021-env-literal-name.js +100 -0
- package/dist/lint/rules/cor022-receipt-leaf.js +118 -0
- package/dist/lint/rules/cor024-receipt-secret-pointer.js +199 -0
- package/dist/lint/rules/declarable-naming-convention.js +62 -0
- package/dist/lint/rules/evl001-non-literal-expression.js +66 -0
- package/dist/lint/rules/evl002-control-flow-resource.js +69 -0
- package/dist/lint/rules/evl003-dynamic-property-access.js +44 -0
- package/dist/lint/rules/evl004-spread-non-const.js +94 -0
- package/dist/lint/rules/evl005-resource-block-body.js +41 -0
- package/dist/lint/rules/evl007-invalid-siblings.js +105 -0
- package/dist/lint/rules/evl009-composite-no-constant.js +158 -0
- package/dist/lint/rules/evl010-composite-no-transform.js +59 -0
- package/dist/lint/rules/evl011-symbolic-in-template.js +106 -0
- package/dist/lint/rules/export-required.js +115 -0
- package/dist/lint/rules/file-declarable-limit.js +88 -0
- package/dist/lint/rules/flat-declarations.js +62 -0
- package/dist/lint/rules/index.js +90 -0
- package/dist/lint/rules/no-cyclic-declarable-ref.js +138 -0
- package/dist/lint/rules/no-redundant-type-import.js +76 -0
- package/dist/lint/rules/no-redundant-value-cast.js +41 -0
- package/dist/lint/rules/no-string-ref.js +59 -0
- package/dist/lint/rules/no-unused-declarable-import.js +75 -0
- package/dist/lint/rules/no-unused-declarable.js +142 -0
- package/dist/lint/rules/op/index.js +28 -0
- package/dist/lint/rules/op/ops012-activity-contract.js +54 -0
- package/dist/lint/rules/op/ops013-step-output-ref.js +88 -0
- package/dist/lint/rules/op/ops014-converge-rule-refusals.js +114 -0
- package/dist/lint/rules/op/ops015-gate-approval.js +45 -0
- package/dist/lint/rules/op/support.js +11 -0
- package/dist/lint/rules/op/sys010-key-over-plain-http.js +100 -0
- package/dist/lint/rules/property-kind.js +56 -0
- package/dist/lint/rules/single-concern-file.js +71 -0
- package/dist/lint/rules/sys001-no-literal-key.js +60 -0
- package/dist/lint/selectors.js +168 -0
- package/dist/lint/suppressions.js +129 -0
- package/dist/lint/typescript.js +17 -0
- package/dist/live-endpoint.js +113 -0
- package/dist/live-read-session.js +76 -0
- package/dist/lsp/lexicon-providers.js +163 -0
- package/dist/lsp/types.js +5 -0
- package/dist/managed-fields.js +293 -0
- package/dist/mcp/types.js +4 -0
- package/dist/notify-verify.js +0 -1
- package/dist/notify.js +0 -1
- package/dist/notify.schema.json +72 -0
- package/dist/observation.js +266 -0
- package/dist/okf-read.js +134 -0
- package/dist/okf.js +275 -0
- package/dist/op/__fixtures__/decide-stub-backend.js +125 -0
- package/dist/op/activities/activity-contracts.js +313 -0
- package/dist/op/activities/apply.js +582 -0
- package/dist/op/activities/build.js +18 -0
- package/dist/op/activities/change-coverage.js +40 -0
- package/dist/op/activities/change-set.js +64 -0
- package/dist/op/activities/converge.js +492 -0
- package/dist/op/activities/decide.js +211 -0
- package/dist/op/activities/env-teardown.js +110 -0
- package/dist/op/activities/factory.js +591 -0
- package/dist/op/activities/forge-pull-request.js +82 -0
- package/dist/op/activities/gh-host.js +78 -0
- package/dist/op/activities/guard-validate.js +165 -0
- package/dist/op/activities/http-check.js +40 -0
- package/dist/op/activities/index.js +59 -0
- package/dist/op/activities/lexicon-upgrade.js +629 -0
- package/dist/op/activities/lifecycle.js +109 -0
- package/dist/op/activities/pipeline-audit.js +147 -0
- package/dist/op/activities/policy.js +26 -0
- package/dist/op/activities/predict-behaviour.js +341 -0
- package/dist/op/activities/propose-upgrade.js +165 -0
- package/dist/op/activities/reconcile.js +997 -0
- package/dist/op/activities/shell.js +118 -0
- package/dist/op/activities/source-release.js +97 -0
- package/dist/op/activities/source-rollback.js +165 -0
- package/dist/op/activities/teardown.js +17 -0
- package/dist/op/activities/util.js +6 -0
- package/dist/op/activities/wait.js +51 -0
- package/dist/op/activities/work-evidence.js +35 -0
- package/dist/op/activities/workflow-audit.js +133 -0
- package/dist/op/activity-contract-registry.js +106 -0
- package/dist/op/activity-contract.js +232 -0
- package/dist/op/activity-failure.js +31 -0
- package/dist/op/activity-profiles.js +129 -0
- package/dist/op/activity-registry.js +105 -0
- package/dist/op/activity-runtime.js +28 -0
- package/dist/op/builders.js +801 -0
- package/dist/op/change-signal.js +118 -0
- package/dist/op/composites/apply-op.js +151 -0
- package/dist/op/composites/behaviour-op.js +65 -0
- package/dist/op/composites/converge-op.js +141 -0
- package/dist/op/composites/index.js +19 -0
- package/dist/op/composites/lexicon-upgrade-op.js +107 -0
- package/dist/op/composites/pipeline-audit-op.js +50 -0
- package/dist/op/composites/reconcile-op.js +84 -0
- package/dist/op/composites/watch-op.js +69 -0
- package/dist/op/composites/workflow-audit-op.js +57 -0
- package/dist/op/converge-rule.js +205 -0
- package/dist/op/cron.js +146 -0
- package/dist/op/decide-backend.js +181 -0
- package/dist/op/decide-config.js +68 -0
- package/dist/op/decide-read-inputs.js +141 -0
- package/dist/op/discover.d.ts.map +1 -1
- package/dist/op/discover.js +213 -0
- package/dist/op/duration.js +21 -0
- package/dist/op/emulator-freshness.js +80 -0
- package/dist/op/emulator-lifecycle.js +269 -0
- package/dist/op/factory.js +83 -0
- package/dist/op/gate-approval.js +172 -0
- package/dist/op/gate-name.js +86 -0
- package/dist/op/gate-plan-context.js +167 -0
- package/dist/op/gate-point-run.js +67 -0
- package/dist/op/gate-point.js +111 -0
- package/dist/op/gate-resume-plan.js +155 -0
- package/dist/op/gate-resume.js +31 -0
- package/dist/op/gate-review.js +290 -0
- package/dist/op/gate-run-locator.js +85 -0
- package/dist/op/gate-summary.js +100 -0
- package/dist/op/gate-wait.js +56 -0
- package/dist/op/gate.js +449 -0
- package/dist/op/generate-pipeline.js +124 -0
- package/dist/op/index.js +51 -0
- package/dist/op/lifecycle-receipt-store.js +45 -0
- package/dist/op/local-executor.js +1164 -0
- package/dist/op/local-output.js +140 -0
- package/dist/op/op-ir.js +317 -0
- package/dist/op/op-verb-class.js +131 -0
- package/dist/op/op-waves-notify.js +136 -0
- package/dist/op/op-waves-run.d.ts +1 -1
- package/dist/op/op-waves-run.d.ts.map +1 -1
- package/dist/op/op-waves-run.js +1657 -0
- package/dist/op/op-waves.js +409 -0
- package/dist/op/operator.js +743 -0
- package/dist/op/receipt-store.js +94 -0
- package/dist/op/resource.js +23 -0
- package/dist/op/run-context.js +28 -0
- package/dist/op/run-live.js +256 -0
- package/dist/op/runtime.js +21 -0
- package/dist/op/runtimes/local.js +195 -0
- package/dist/op/source-archive.js +131 -0
- package/dist/op/step-output-ref.js +397 -0
- package/dist/op/steward-beside.js +169 -0
- package/dist/op/steward-points.js +138 -0
- package/dist/op/steward-turn.js +59 -0
- package/dist/op/steward.js +317 -0
- package/dist/op/types.js +25 -0
- package/dist/op/work-lease-decl.js +81 -0
- package/dist/op/work-lease-run.js +393 -0
- package/dist/override-gate.js +284 -0
- package/dist/owner-chain.js +74 -0
- package/dist/ownership.js +92 -0
- package/dist/params.js +61 -0
- package/dist/plan-summary.js +711 -0
- package/dist/point-decision.js +211 -0
- package/dist/pr-forge.js +810 -0
- package/dist/pr-loop.js +203 -0
- package/dist/project-codegen.js +191 -0
- package/dist/project-root.js +74 -0
- package/dist/project-validation.js +50 -0
- package/dist/provenance.js +157 -0
- package/dist/pseudo-parameter.js +40 -0
- package/dist/reconcile.js +450 -0
- package/dist/resource-attributes.js +33 -0
- package/dist/runtime-adapter.js +77 -0
- package/dist/runtime.js +66 -0
- package/dist/secret-materialization.js +153 -0
- package/dist/secret-provenance.js +250 -0
- package/dist/serializer-walker.js +112 -0
- package/dist/serializer.js +1 -0
- package/dist/sort.js +45 -0
- package/dist/stack-output.js +115 -0
- package/dist/telemetry-attribution.js +149 -0
- package/dist/terraform/__fixtures__/build-graph.js +63 -0
- package/dist/terraform/adopt-state.js +40 -0
- package/dist/terraform/aws-resources.js +384 -0
- package/dist/terraform/bridge.js +204 -0
- package/dist/terraform/carve-provider.js +155 -0
- package/dist/terraform/carve.js +138 -0
- package/dist/terraform/data-source-shape.js +57 -0
- package/dist/terraform/emit-source.js +36 -0
- package/dist/terraform/excise.js +123 -0
- package/dist/terraform/graduate.js +128 -0
- package/dist/terraform/graph.js +435 -0
- package/dist/terraform/hcl2json.js +60 -0
- package/dist/terraform/manifest.js +149 -0
- package/dist/terraform/parse.js +81 -0
- package/dist/terraform/providers/aws.js +146 -0
- package/dist/terraform/providers/gcp.js +294 -0
- package/dist/terraform/providers/index.js +17 -0
- package/dist/terraform/providers/kubernetes.js +253 -0
- package/dist/terraform/score.js +151 -0
- package/dist/terraform/state.js +67 -0
- package/dist/terraform/tier-map.js +74 -0
- package/dist/terraform/types.js +13 -0
- package/dist/terraform/unified-diff.js +132 -0
- package/dist/testing.js +295 -0
- package/dist/toml-emit.js +153 -0
- package/dist/toml-parse.js +355 -0
- package/dist/toml-utils.js +60 -0
- package/dist/toml.js +428 -0
- package/dist/ts-loader.d.ts +46 -0
- package/dist/ts-loader.d.ts.map +1 -0
- package/dist/ts-loader.js +103 -0
- package/dist/types.js +1 -0
- package/dist/utils.js +61 -0
- package/dist/validation.js +20 -0
- package/dist/vendor/js-yaml-load.js +1662 -0
- package/dist/workspace/__fixtures__/contract-repo.js +103 -0
- package/dist/workspace/__fixtures__/decide-workspace.js +112 -0
- package/dist/workspace/__fixtures__/sessions.js +91 -0
- package/dist/workspace/__fixtures__/two-member-workspace.js +34 -0
- package/dist/workspace/agent-cli.js +99 -0
- package/dist/workspace/agent.schema.json +390 -0
- package/dist/workspace/answers-ledger.js +89 -0
- package/dist/workspace/box-cli.js +142 -0
- package/dist/workspace/box-factory-write.js +196 -0
- package/dist/workspace/box-factory-write.schema.json +342 -0
- package/dist/workspace/box-factory.js +88 -0
- package/dist/workspace/box-intent.js +126 -0
- package/dist/workspace/box-isolation.js +169 -0
- package/dist/workspace/box-listing-write.schema.json +204 -0
- package/dist/workspace/box-listing.js +298 -0
- package/dist/workspace/box-publish.js +352 -0
- package/dist/workspace/box-publish.schema.json +498 -0
- package/dist/workspace/box-services.js +39 -0
- package/dist/workspace/broker-protocol.js +359 -0
- package/dist/workspace/broker-protocol.schema.json +228 -0
- package/dist/workspace/change-set.schema.json +460 -0
- package/dist/workspace/changes-cli.js +56 -0
- package/dist/workspace/changes.js +446 -0
- package/dist/workspace/changes.schema.json +642 -0
- package/dist/workspace/chant-migrations/chud-lexicon-exit-fly-site.js +198 -0
- package/dist/workspace/chant-migrations/chud-lexicon-exit-live-names.js +155 -0
- package/dist/workspace/chant-migrations/chud-lexicon-exit-rollback.js +214 -0
- package/dist/workspace/chant-migrations/chud-lexicon-exit-ship-inputs.js +180 -0
- package/dist/workspace/chant-migrations/chud-lexicon-exit-ship-policy.js +99 -0
- package/dist/workspace/chant-migrations/chud-lexicon-exit.js +847 -0
- package/dist/workspace/chant-migrations.js +113 -0
- package/dist/workspace/check.schema.json +433 -0
- package/dist/workspace/checks/box-isolation.js +62 -0
- package/dist/workspace/checks/boxes.js +491 -0
- package/dist/workspace/checks/diagrams.js +104 -0
- package/dist/workspace/checks/generated.js +419 -0
- package/dist/workspace/checks/ledgers.js +212 -0
- package/dist/workspace/checks/links.js +191 -0
- package/dist/workspace/checks/live.js +100 -0
- package/dist/workspace/checks/pipelines.js +188 -0
- package/dist/workspace/checks/records.js +169 -0
- package/dist/workspace/checks.js +426 -0
- package/dist/workspace/ci-green-cli.js +125 -0
- package/dist/workspace/ci-green-forge.js +83 -0
- package/dist/workspace/ci-green-workflow.js +199 -0
- package/dist/workspace/ci-green.js +325 -0
- package/dist/workspace/ci-last-green.schema.json +158 -0
- package/dist/workspace/compose-graph.js +235 -0
- package/dist/workspace/compose-reports.js +146 -0
- package/dist/workspace/composites.js +264 -0
- package/dist/workspace/composites.schema.json +617 -0
- package/dist/workspace/conformance/__fixture__/app/package.json +7 -0
- package/dist/workspace/conformance/__fixture__/app/src/server.mjs +29 -0
- package/dist/workspace/conformance/__fixture__/decisions/decision.kind.mjs +54 -0
- package/dist/workspace/conformance/__fixture__/decisions/decision.schema.json +512 -0
- package/dist/workspace/conformance/__fixture__/decisions/fix-001-how-the-app-is-deployed.md +40 -0
- package/dist/workspace/conformance/__fixture__/delivery/chant.config.ts +7 -0
- package/dist/workspace/conformance/__fixture__/delivery/lexicon/index.ts +26 -0
- package/dist/workspace/conformance/__fixture__/delivery/package.json +7 -0
- package/dist/workspace/conformance/__fixture__/delivery/src/app.component.ts +14 -0
- package/dist/workspace/conformance/__fixture__/delivery/src/app.ts +4 -0
- package/dist/workspace/conformance/__fixtures__/reference-broker.js +205 -0
- package/dist/workspace/conformance/__writer_fixture__/answers/answer.kind.mjs +32 -0
- package/dist/workspace/conformance/__writer_fixture__/answers/answer.schema.json +135 -0
- package/dist/workspace/conformance/__writer_fixture__/contracts/contract.kind.mjs +37 -0
- package/dist/workspace/conformance/__writer_fixture__/contracts/contract.schema.json +213 -0
- package/dist/workspace/conformance/__writer_fixture__/decisions/points.json +228 -0
- package/dist/workspace/conformance/__writer_fixture__/drivers/driver.kind.mjs +15 -0
- package/dist/workspace/conformance/__writer_fixture__/drivers/driver.schema.json +38 -0
- package/dist/workspace/conformance/__writer_fixture__/sessions/session.kind.mjs +54 -0
- package/dist/workspace/conformance/__writer_fixture__/sessions/session.schema.json +289 -0
- package/dist/workspace/conformance/__writer_fixture__/work/W-001-the-writer-suite-works-this-item.md +25 -0
- package/dist/workspace/conformance/__writer_fixture__/work/work.kind.mjs +60 -0
- package/dist/workspace/conformance/__writer_fixture__/work/work.schema.json +603 -0
- package/dist/workspace/conformance/broker.js +736 -0
- package/dist/workspace/conformance/index.js +673 -0
- package/dist/workspace/conformance/vitest.js +108 -0
- package/dist/workspace/conformance/writer.js +1080 -0
- package/dist/workspace/decide.js +879 -0
- package/dist/workspace/decision-points.schema.json +135 -135
- package/dist/workspace/declaration-write-cli.js +74 -0
- package/dist/workspace/declaration-write.js +238 -0
- package/dist/workspace/declaration.js +938 -0
- package/dist/workspace/declaration.schema.json +1413 -1413
- package/dist/workspace/declared-kinds.js +106 -0
- package/dist/workspace/environments.js +164 -0
- package/dist/workspace/evidence.schema.json +279 -0
- package/dist/workspace/export-cli.js +185 -0
- package/dist/workspace/export.js +499 -0
- package/dist/workspace/factory-rules.js +175 -0
- package/dist/workspace/generated-files.js +92 -0
- package/dist/workspace/glob.js +45 -0
- package/dist/workspace/graph-cache.js +352 -0
- package/dist/workspace/graph-cli.js +348 -0
- package/dist/workspace/graph.schema.json +1338 -0
- package/dist/workspace/identity-gate-rule.d.ts +65 -0
- package/dist/workspace/identity-gate-rule.d.ts.map +1 -0
- package/dist/workspace/identity-gate-rule.js +75 -0
- package/dist/workspace/identity.d.ts +4 -2
- package/dist/workspace/identity.d.ts.map +1 -1
- package/dist/workspace/identity.js +126 -0
- package/dist/workspace/import.js +283 -0
- package/dist/workspace/init.js +620 -0
- package/dist/workspace/intent-cli.js +263 -0
- package/dist/workspace/intent-joins.js +201 -0
- package/dist/workspace/intent-record.js +352 -0
- package/dist/workspace/intent-record.schema.json +864 -0
- package/dist/workspace/intent.js +1582 -0
- package/dist/workspace/intent.schema.json +2420 -0
- package/dist/workspace/json-edit.js +221 -0
- package/dist/workspace/jsonc.js +235 -0
- package/dist/workspace/kind-readers.js +103 -0
- package/dist/workspace/kinds.js +587 -0
- package/dist/workspace/lexicon-symbols.js +112 -0
- package/dist/workspace/lineage-adopt-cli.js +102 -0
- package/dist/workspace/lineage-adopt.js +360 -0
- package/dist/workspace/lineage-check.js +282 -0
- package/dist/workspace/lineage-cli.js +121 -0
- package/dist/workspace/lineage-hash-index.js +284 -0
- package/dist/workspace/lineage-init.js +507 -0
- package/dist/workspace/lineage-lock.js +387 -0
- package/dist/workspace/lineage-merge.js +45 -0
- package/dist/workspace/lineage-migrations.d.ts.map +1 -1
- package/dist/workspace/lineage-migrations.js +329 -0
- package/dist/workspace/lineage-provenance.js +36 -0
- package/dist/workspace/lineage-update.js +138 -0
- package/dist/workspace/lineage-upgrade-cli.js +131 -0
- package/dist/workspace/lineage-upgrade.js +889 -0
- package/dist/workspace/lineage-vendor.js +171 -0
- package/dist/workspace/lineage-version.js +128 -0
- package/dist/workspace/lineage-versions.js +275 -0
- package/dist/workspace/links.js +330 -0
- package/dist/workspace/ls-generated.js +95 -0
- package/dist/workspace/ls.js +277 -0
- package/dist/workspace/ls.schema.json +333 -0
- package/dist/workspace/member-commands.js +508 -0
- package/dist/workspace/member-handles.js +216 -0
- package/dist/workspace/member-pipeline.js +258 -0
- package/dist/workspace/member-run.js +117 -0
- package/dist/workspace/member-write.schema.json +193 -0
- package/dist/workspace/nested-graph.js +156 -0
- package/dist/workspace/nesting.js +38 -0
- package/dist/workspace/patch.js +301 -0
- package/dist/workspace/patch.schema.json +321 -0
- package/dist/workspace/pin-cli.js +55 -0
- package/dist/workspace/pin-integrity.js +100 -0
- package/dist/workspace/plan-summary.schema.json +155 -0
- package/dist/workspace/point-answer.schema.json +129 -129
- package/dist/workspace/points-cli.js +291 -0
- package/dist/workspace/points-write.schema.json +660 -0
- package/dist/workspace/points.js +521 -0
- package/dist/workspace/points.schema.json +916 -0
- package/dist/workspace/pr-report.schema.json +108 -0
- package/dist/workspace/principal-classes.d.ts +3 -14
- package/dist/workspace/principal-classes.d.ts.map +1 -1
- package/dist/workspace/principal-classes.js +245 -0
- package/dist/workspace/reason-codes.js +326 -0
- package/dist/workspace/record-assets.js +151 -0
- package/dist/workspace/record-decided.js +105 -0
- package/dist/workspace/record-sessions.js +96 -0
- package/dist/workspace/record-source.js +114 -0
- package/dist/workspace/records-amend.schema.json +284 -0
- package/dist/workspace/records-checkout.js +76 -0
- package/dist/workspace/records-cli.js +707 -0
- package/dist/workspace/records-close.js +116 -0
- package/dist/workspace/records-close.schema.json +278 -0
- package/dist/workspace/records-new.schema.json +202 -0
- package/dist/workspace/records-review.schema.json +367 -0
- package/dist/workspace/records-since.js +317 -0
- package/dist/workspace/records-since.schema.json +218 -0
- package/dist/workspace/records-write.js +1229 -0
- package/dist/workspace/records.js +1345 -0
- package/dist/workspace/records.schema.json +604 -0
- package/dist/workspace/reference-kinds/app/package.json +10 -0
- package/dist/workspace/reference-kinds/app/workspace-kinds.json +45 -0
- package/dist/workspace/returns.js +303 -0
- package/dist/workspace/root-refusal.js +75 -0
- package/dist/workspace/run-statement.schema.json +622 -0
- package/dist/workspace/runs-cli.js +584 -0
- package/dist/workspace/runs-write.schema.json +994 -0
- package/dist/workspace/runs.js +708 -0
- package/dist/workspace/runs.schema.json +1257 -0
- package/dist/workspace/runtimes.js +76 -0
- package/dist/workspace/session-kinds.js +83 -0
- package/dist/workspace/signers.schema.json +206 -0
- package/dist/workspace/source-block.js +125 -0
- package/dist/workspace/squash.js +177 -0
- package/dist/workspace/status-gates.js +162 -0
- package/dist/workspace/status-stewards.js +330 -0
- package/dist/workspace/status.js +514 -0
- package/dist/workspace/status.schema.json +998 -0
- package/dist/workspace/steward-index.js +191 -0
- package/dist/workspace/symbols.js +188 -0
- package/dist/workspace/template-manifest.js +227 -0
- package/dist/workspace/template-pins.js +115 -0
- package/dist/workspace/trailer-joins.js +65 -0
- package/dist/workspace/trailers.js +111 -0
- package/dist/workspace/tree.js +136 -0
- package/dist/workspace/trust/attestor.js +63 -0
- package/dist/workspace/trust/dsse.js +108 -0
- package/dist/workspace/trust/evidence-cli.js +175 -0
- package/dist/workspace/trust/evidence.js +161 -0
- package/dist/workspace/trust/gate-seal.js +226 -0
- package/dist/workspace/trust/policy.js +190 -0
- package/dist/workspace/trust/provenance.js +180 -0
- package/dist/workspace/trust/rotation.js +298 -0
- package/dist/workspace/trust/run-commits.js +101 -0
- package/dist/workspace/trust/run-statement.js +182 -0
- package/dist/workspace/trust/seal.js +272 -0
- package/dist/workspace/trust/signers-cli.js +152 -0
- package/dist/workspace/trust/ssh-commit.js +178 -0
- package/dist/workspace/trust/test-repo.js +118 -0
- package/dist/workspace/trust/trust-files.js +193 -0
- package/dist/workspace/trust/verify-cli.js +63 -0
- package/dist/workspace/trust/verify.js +192 -0
- package/dist/workspace/which-chant.js +141 -0
- package/dist/workspace/wip-cli.js +95 -0
- package/dist/workspace/wip-write.schema.json +504 -0
- package/dist/workspace/wip.js +631 -0
- package/dist/workspace/wip.schema.json +334 -0
- package/dist/workspace/work-cli.js +448 -0
- package/dist/workspace/work-evidence.js +122 -0
- package/dist/workspace/work-evidence.schema.json +222 -0
- package/dist/workspace/work-history.schema.json +421 -0
- package/dist/workspace/work-lease.schema.json +246 -0
- package/dist/workspace/work-size.js +77 -0
- package/dist/workspace/work.js +283 -0
- package/dist/workspace/workspace-kinds.schema.json +259 -259
- package/dist/workspace/workspace-principals.schema.json +53 -53
- package/dist/workspace/write-lock-cli.js +105 -0
- package/dist/workspace/write-lock.js +424 -0
- package/dist/workspace/write-lock.schema.json +172 -0
- package/dist/workspace/write-scope.js +484 -0
- package/dist/yaml.js +459 -0
- package/package.json +2 -2
- package/src/cli/commands/check-lexicon-plugin.ts +2 -0
- package/src/cli/commands/lint.ts +36 -6
- package/src/cli/commands/migrate.ts +2 -0
- package/src/cli/compiled-cli.e2e.test.ts +165 -0
- package/src/cli/main.ts +121 -27
- package/src/cli/mcp/workspace-tools.ts +1 -1
- package/src/codegen/pinned-upgrade.ts +2 -0
- package/src/components/discover.ts +2 -0
- package/src/components/sandbox/driver.ts +3 -1
- package/src/config-import.ts +3 -0
- package/src/discovery/fold-import.ts +23 -14
- package/src/discovery/import.ts +2 -0
- package/src/discovery/sandbox/driver.ts +3 -1
- package/src/gate-decision-bundle.test.ts +3 -2
- package/src/gate-decision-identity.test.ts +176 -0
- package/src/gate-decision.ts +100 -22
- package/src/lexicon-module.ts +3 -0
- package/src/lifecycle/gate-ledger.ts +8 -0
- package/src/lint/config.ts +1 -1
- package/src/lint/discover.ts +28 -8
- package/src/lint/policy-import.ts +4 -1
- package/src/lint/rule-loader.ts +2 -0
- package/src/op/discover.ts +3 -0
- package/src/op/op-waves-point.test.ts +1 -0
- package/src/op/op-waves-run.ts +5 -4
- package/src/op/op-waves.test.ts +14 -0
- package/src/ts-loader.test.ts +23 -0
- package/src/ts-loader.ts +122 -0
- package/src/workspace/chant-migrations/chud-lexicon-exit.ts +1 -1
- package/src/workspace/declaration.ts +1 -1
- package/src/workspace/identity-gate-rule.ts +109 -0
- package/src/workspace/identity.ts +8 -18
- package/src/workspace/kinds.ts +1 -1
- package/src/workspace/lineage-migrations.ts +2 -0
- package/src/workspace/points.ts +1 -1
- package/src/workspace/principal-classes.ts +5 -30
|
@@ -0,0 +1,1434 @@
|
|
|
1
|
+
import * as ts from "typescript";
|
|
2
|
+
import { relative } from "node:path";
|
|
3
|
+
import { intrinsicCallFolds, intrinsicCallFoldsEagerly, intrinsicTagFolds } from "../lexicon.js";
|
|
4
|
+
import { SUPPORTED_BINARY_OPERATORS, SUPPORTED_UNARY_OPERATORS, UNSUPPORTED_OBJECT_MEMBER_MESSAGE, UNSUPPORTED_UNARY_MESSAGE, briefNodeText, callExpressionMessage, computedPropertyNameMessage, dynamicElementAccessMessage, isLiteralElementKey, isLiteralPropertyName, unsupportedBinaryMessage, unsupportedExpressionMessage, } from "./subset.js";
|
|
5
|
+
import { isFoldableHelperName } from "./foldable-helpers.js";
|
|
6
|
+
/**
|
|
7
|
+
* Symbolic reference produced when a property/element access resolves to an
|
|
8
|
+
* attribute of another `const`-declared resource in the same file, e.g.
|
|
9
|
+
* `bucket.name` (or `bucket["name"]`) where `bucket` is
|
|
10
|
+
* `const bucket = new S3Bucket({...})`.
|
|
11
|
+
*
|
|
12
|
+
* This is the SAME envelope `AttrRef.prototype.toJSON()` produces at
|
|
13
|
+
* runtime ({@link "../attrref"}) — `serializer-walker.ts`'s `walkValue`
|
|
14
|
+
* already recognizes a plain `{ __attrRef }` object as an AttrRef envelope
|
|
15
|
+
* (it doesn't require a live `AttrRef` instance), so this is not an
|
|
16
|
+
* invented shape: it's the existing envelope, produced without running the
|
|
17
|
+
* module that would otherwise construct the real `AttrRef`.
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* Which symbolic envelope a folded value is, in words a message can use — or
|
|
21
|
+
* `undefined` for a value that has an honest string form.
|
|
22
|
+
*
|
|
23
|
+
* These are the shapes `fold()` produces for things the build resolves later:
|
|
24
|
+
* a resource attribute, a lexicon intrinsic in either of its two forms, a
|
|
25
|
+
* registered authoring helper, a nested construction used as a value, and a
|
|
26
|
+
* composite `.step`. None of them can be concatenated into a string here,
|
|
27
|
+
* because what they stand for is not known until the build runs.
|
|
28
|
+
*
|
|
29
|
+
* Five of the six envelope kinds. `__symbol` is the sixth and is deliberately
|
|
30
|
+
* absent: it is produced only inside an intrinsic's interior and cannot reach
|
|
31
|
+
* a plain template span, so a case for it would be unreachable code claiming
|
|
32
|
+
* to guard something (#2397).
|
|
33
|
+
*/
|
|
34
|
+
export function symbolicEnvelopeKind(value) {
|
|
35
|
+
if (typeof value !== "object" || value === null)
|
|
36
|
+
return undefined;
|
|
37
|
+
const v = value;
|
|
38
|
+
if ("__attrRef" in v) {
|
|
39
|
+
const ref = v.__attrRef;
|
|
40
|
+
const named = typeof ref?.entity === "string" && typeof ref?.attribute === "string"
|
|
41
|
+
? ` (${ref.entity}.${ref.attribute})`
|
|
42
|
+
: "";
|
|
43
|
+
return `a resource attribute reference${named}`;
|
|
44
|
+
}
|
|
45
|
+
if ("__intrinsic" in v && typeof v.__intrinsic === "string")
|
|
46
|
+
return `the intrinsic \`${v.__intrinsic}\``;
|
|
47
|
+
if ("__helper" in v && typeof v.__helper === "string")
|
|
48
|
+
return `the helper \`${v.__helper}\``;
|
|
49
|
+
// A nested construction used as a value (#1169). The run path builds a real
|
|
50
|
+
// instance here, whose default `toString` is `"[object Object]"` too, so
|
|
51
|
+
// fold and run agreed and the differential stayed silent — the same shape
|
|
52
|
+
// as #2349 itself (#2397).
|
|
53
|
+
if ("__resource" in v && typeof v.__resource === "string")
|
|
54
|
+
return `a nested \`new ${v.__resource}\``;
|
|
55
|
+
// The `.step` idiom (#1174).
|
|
56
|
+
if ("__compositeStep" in v && typeof v.__compositeStep === "string") {
|
|
57
|
+
return `the composite step \`${v.__compositeStep}(…).step\``;
|
|
58
|
+
}
|
|
59
|
+
return undefined;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Error thrown when a node cannot be folded to a value without executing
|
|
63
|
+
* code. Carries the node's source position (1-based, matching `LintError`)
|
|
64
|
+
* so callers can report a located diagnostic, and the id of the EVL rule
|
|
65
|
+
* that flags the same construct (#1024) — "EVL001" (the general
|
|
66
|
+
* not-statically-evaluable umbrella) unless the rejection is specifically a
|
|
67
|
+
* dynamic element-access key, which is "EVL003"'s construct. A rejection
|
|
68
|
+
* with no EVL equivalent (unresolved identifier, unregistered intrinsic tag,
|
|
69
|
+
* spread of a value that turns out not to be an object/array — all
|
|
70
|
+
* environment/value-dependent, see {@link "./subset"}'s module doc) still
|
|
71
|
+
* defaults to "EVL001" since that's the closest umbrella rule, even though
|
|
72
|
+
* EVL can't actually detect it ahead of a real fold.
|
|
73
|
+
*
|
|
74
|
+
* chant #1020 hang fix — every `FoldError` is thrown for a routine, EXPECTED
|
|
75
|
+
* outcome (this node's shape isn't in the fold subset) and is ALWAYS caught
|
|
76
|
+
* a few frames up (`tryFoldFileCore`'s own top-level catch, ultimately),
|
|
77
|
+
* reduced to `.message`; `.stack` is never read anywhere on this path. V8
|
|
78
|
+
* still eagerly walks live JS frames to populate the (lazy) `.stack` getter's
|
|
79
|
+
* backing data at CONSTRUCTION time regardless of whether it's ever read —
|
|
80
|
+
* cheap for a shallow call stack, but expensive once the surrounding
|
|
81
|
+
* functions are hot enough for V8 to aggressively inline them (every corpus
|
|
82
|
+
* entry re-triggers the same call shapes across `foldFileMemoized` ->
|
|
83
|
+
* `buildExternals` -> `tryFoldFileCore` -> `resolveDeclaratorValue` ->
|
|
84
|
+
* `resolveLiveValue` -> `resolveCallExpression`/`fold`, chant #1020's
|
|
85
|
+
* cross-file resolution making that chain several layers deeper than the
|
|
86
|
+
* pre-#1020 single-file fold ever needed): capturing a stack from deep,
|
|
87
|
+
* optimized/inlined frames requires V8 to reconstruct them from deopt
|
|
88
|
+
* metadata, confirmed via `sample` to dominate CPU during the observed
|
|
89
|
+
* multi-minute stall (`Isolate::CaptureAndSetErrorStack` /
|
|
90
|
+
* `OptimizedJSFrame::Summarize` / `DeoptTranslationIterator`). Most files in
|
|
91
|
+
* the corpus (77/98 entries have at least one run-fallback file) throw one
|
|
92
|
+
* of these, so the cost compounds across a build. `Error.stackTraceLimit = 0`
|
|
93
|
+
* for the duration of `super()` makes V8 capture zero frames — free
|
|
94
|
+
* regardless of stack depth/optimization state — then the limit is restored
|
|
95
|
+
* immediately, so it doesn't suppress a real stack trace anywhere else in
|
|
96
|
+
* the process.
|
|
97
|
+
*/
|
|
98
|
+
export class FoldError extends Error {
|
|
99
|
+
constructor(message, line, column, ruleId = "EVL001", refusedAtDepth = false) {
|
|
100
|
+
const prevStackTraceLimit = Error.stackTraceLimit;
|
|
101
|
+
Error.stackTraceLimit = 0;
|
|
102
|
+
super(`${line}:${column} - ${message}`);
|
|
103
|
+
Error.stackTraceLimit = prevStackTraceLimit;
|
|
104
|
+
this.name = "FoldError";
|
|
105
|
+
this.line = line;
|
|
106
|
+
this.column = column;
|
|
107
|
+
this.ruleId = ruleId;
|
|
108
|
+
this.refusedAtDepth = refusedAtDepth;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* A project-local function `fold()` can CALL — chant #1373.
|
|
113
|
+
*
|
|
114
|
+
* Produced by ../discovery/fold-import.ts for every top-level function a
|
|
115
|
+
* project file declares (`export function f(...) {...}`, `export const f =
|
|
116
|
+
* (...) => ...`, and their non-exported siblings) and placed in the folding
|
|
117
|
+
* file's `externals` under the function's name, so a call through a bare
|
|
118
|
+
* identifier bound to one evaluates STATICALLY: the arguments fold in the
|
|
119
|
+
* caller's scope, the parameters are bound, and the body folds in the
|
|
120
|
+
* DEFINING module's scope (`consts`/`externals` here are that module's, not
|
|
121
|
+
* the caller's). Nothing is imported and nothing runs — this is the same
|
|
122
|
+
* "evaluate the source instead of the module" move #1023 makes for a
|
|
123
|
+
* composite factory body, applied to a plain function.
|
|
124
|
+
*
|
|
125
|
+
* Why this exists: the advice every chant project gets is to read build
|
|
126
|
+
* parameters through a small helper (`optionalAccountId(params.accountId)`)
|
|
127
|
+
* so defaulting and validation live in one place. Before #1373 a call to
|
|
128
|
+
* that helper was "a function call as a value" and unfoldable, and because
|
|
129
|
+
* fallback is per file and taint propagates along imports, ONE helper call
|
|
130
|
+
* at the top of a parameter file demoted every stack that imported it.
|
|
131
|
+
*
|
|
132
|
+
* The value is a marker, never a real function: a folded file's export
|
|
133
|
+
* namespace may carry one (an importer's `buildExternals` picks it up by
|
|
134
|
+
* name), and `fold()` refuses it anywhere a VALUE is expected — a function
|
|
135
|
+
* object cannot be serialized, and the run path's export namespace holds the
|
|
136
|
+
* real function the collector ignores, so ignoring the marker matches.
|
|
137
|
+
*
|
|
138
|
+
* Not a `FoldedValue`: it never appears inside a folded tree.
|
|
139
|
+
*/
|
|
140
|
+
export class FoldableFunction {
|
|
141
|
+
constructor(
|
|
142
|
+
/** The binding name, for diagnostics. */
|
|
143
|
+
name, fn,
|
|
144
|
+
/** Absolute path of the defining module, for diagnostics. */
|
|
145
|
+
file,
|
|
146
|
+
/**
|
|
147
|
+
* The defining module's top-level `const` initializers, with every
|
|
148
|
+
* `new`-bound one already REMOVED — a body that mentions one reads the
|
|
149
|
+
* live instance out of `externals` instead (the same object the module's
|
|
150
|
+
* own fold registered), never a by-name `{__attrRef}` that would name an
|
|
151
|
+
* entity of the wrong file once revived in the caller.
|
|
152
|
+
*/
|
|
153
|
+
consts,
|
|
154
|
+
/** The defining module's resolved imports, its own pre-built resources, and its own sibling functions. Read live, never copied, so a function declared before a const it reads still sees that const's value. */
|
|
155
|
+
externals,
|
|
156
|
+
/** Why an import of the defining module did NOT resolve, by local name — enriches an "unresolved identifier" inside the body. */
|
|
157
|
+
failures) {
|
|
158
|
+
this.name = name;
|
|
159
|
+
this.fn = fn;
|
|
160
|
+
this.file = file;
|
|
161
|
+
this.consts = consts;
|
|
162
|
+
this.externals = externals;
|
|
163
|
+
this.failures = failures;
|
|
164
|
+
/**
|
|
165
|
+
* Set once a call to this function has RETURNED a live object (a value
|
|
166
|
+
* with a prototype — a pre-built resource instance of the defining module,
|
|
167
|
+
* say) into a caller. The caller then shares that object's identity with
|
|
168
|
+
* the defining module exactly as an imported resource binding would, and
|
|
169
|
+
* fold-import.ts records the same `liveSources` edge for it so the two
|
|
170
|
+
* files fold or run together. A function that returns only plain data never
|
|
171
|
+
* sets this, which is what keeps a parameter helper from tainting anything.
|
|
172
|
+
*/
|
|
173
|
+
this.leakedIdentity = false;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
/** True when `value` (or anything inside it, through plain objects and arrays) carries a prototype other than Object/Array — i.e. is a live instance, not folded data. */
|
|
177
|
+
function carriesLiveObject(value, seen = new Set()) {
|
|
178
|
+
if (value === null || typeof value !== "object")
|
|
179
|
+
return typeof value === "function";
|
|
180
|
+
if (seen.has(value))
|
|
181
|
+
return false;
|
|
182
|
+
seen.add(value);
|
|
183
|
+
const proto = Object.getPrototypeOf(value);
|
|
184
|
+
if (proto !== Object.prototype && proto !== Array.prototype && proto !== null)
|
|
185
|
+
return true;
|
|
186
|
+
for (const inner of Object.values(value)) {
|
|
187
|
+
if (carriesLiveObject(inner, seen))
|
|
188
|
+
return true;
|
|
189
|
+
}
|
|
190
|
+
return false;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* True when a module-level `const` is (transitively) bound to a `new Type(...)`.
|
|
194
|
+
* Follows an identifier chain (`const a = new T(); const b = a;`) so aliasing
|
|
195
|
+
* cannot smuggle a module-level resource into a function body.
|
|
196
|
+
*
|
|
197
|
+
* chant#2436 moved this here from ../discovery/fold-import.ts so the two places
|
|
198
|
+
* that build {@link FoldableFunction}s share one implementation rather than two
|
|
199
|
+
* that can drift.
|
|
200
|
+
*/
|
|
201
|
+
export function constResolvesToResource(consts, name, seen = new Set()) {
|
|
202
|
+
if (seen.has(name))
|
|
203
|
+
return false;
|
|
204
|
+
seen.add(name);
|
|
205
|
+
const init = consts.get(name);
|
|
206
|
+
if (init === undefined)
|
|
207
|
+
return false;
|
|
208
|
+
if (ts.isNewExpression(init))
|
|
209
|
+
return true;
|
|
210
|
+
if (ts.isIdentifier(init))
|
|
211
|
+
return constResolvesToResource(consts, init.text, seen);
|
|
212
|
+
return false;
|
|
213
|
+
}
|
|
214
|
+
/** `const f = (…) => …`, through parentheses / `as` / `satisfies`. */
|
|
215
|
+
function unwrapFunctionInitializer(node) {
|
|
216
|
+
let current = node;
|
|
217
|
+
while (ts.isParenthesizedExpression(current) || ts.isAsExpression(current) || ts.isSatisfiesExpression(current)) {
|
|
218
|
+
current = current.expression;
|
|
219
|
+
}
|
|
220
|
+
return ts.isArrowFunction(current) || ts.isFunctionExpression(current) ? current : undefined;
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Every top-level function a file declares, exported or not, as a
|
|
224
|
+
* {@link FoldableFunction}: `function f(...) {...}` and `const f = (...) => …`.
|
|
225
|
+
*
|
|
226
|
+
* The markers carry `externals` BY REFERENCE, so the caller may keep filling it
|
|
227
|
+
* after this returns (which is how a sibling function, or a resource built
|
|
228
|
+
* later, becomes reachable from a body).
|
|
229
|
+
*
|
|
230
|
+
* `consts` drops every `new`-bound const, transitively through aliases: a body
|
|
231
|
+
* that mentions one must read the live instance out of `externals`, the same
|
|
232
|
+
* object the module's own fold registered, never re-fold the initializer and
|
|
233
|
+
* construct a duplicate of a resource discovery already has.
|
|
234
|
+
*
|
|
235
|
+
* chant#2436 — one implementation, called both by ../discovery/fold-import.ts
|
|
236
|
+
* during a build and by {@link fold} when a unit-level fold has no externals of
|
|
237
|
+
* its own. Getting the `new`-bound stripping wrong yields a wrong value rather
|
|
238
|
+
* than a fallback to run, which is why there is only one copy of it.
|
|
239
|
+
*/
|
|
240
|
+
export function collectSameFileFunctions(sourceFile, consts, file, externals, failures) {
|
|
241
|
+
const bodyConsts = new Map(consts);
|
|
242
|
+
for (const [name] of [...bodyConsts]) {
|
|
243
|
+
if (constResolvesToResource(consts, name, new Set()))
|
|
244
|
+
bodyConsts.delete(name);
|
|
245
|
+
}
|
|
246
|
+
const functions = new Map();
|
|
247
|
+
const add = (name, fn) => {
|
|
248
|
+
functions.set(name, new FoldableFunction(name, fn, file, bodyConsts, externals, failures));
|
|
249
|
+
};
|
|
250
|
+
for (const statement of sourceFile.statements) {
|
|
251
|
+
if (ts.isFunctionDeclaration(statement)) {
|
|
252
|
+
if (statement.name && statement.body)
|
|
253
|
+
add(statement.name.text, statement);
|
|
254
|
+
continue;
|
|
255
|
+
}
|
|
256
|
+
if (!ts.isVariableStatement(statement))
|
|
257
|
+
continue;
|
|
258
|
+
if ((statement.declarationList.flags & ts.NodeFlags.Const) === 0)
|
|
259
|
+
continue;
|
|
260
|
+
for (const decl of statement.declarationList.declarations) {
|
|
261
|
+
if (!ts.isIdentifier(decl.name) || !decl.initializer)
|
|
262
|
+
continue;
|
|
263
|
+
const fn = unwrapFunctionInitializer(decl.initializer);
|
|
264
|
+
if (fn)
|
|
265
|
+
add(decl.name.text, fn);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
return functions;
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* The same-file functions in scope at `node`, for a fold with no `externals`.
|
|
272
|
+
*
|
|
273
|
+
* Memoized per (source file, consts map), both of which are objects the caller
|
|
274
|
+
* holds for the duration of a fold, so a file with many calls walks its
|
|
275
|
+
* statements once. `undefined` when the node has no file to read, which is the
|
|
276
|
+
* pre-#2436 answer: the call is not foldable.
|
|
277
|
+
*
|
|
278
|
+
* The map is its own `externals`, so a function can call a sibling.
|
|
279
|
+
*/
|
|
280
|
+
function sameFileFunctions(node, consts) {
|
|
281
|
+
let sourceFile;
|
|
282
|
+
try {
|
|
283
|
+
sourceFile = node.getSourceFile();
|
|
284
|
+
}
|
|
285
|
+
catch {
|
|
286
|
+
return undefined;
|
|
287
|
+
}
|
|
288
|
+
if (!sourceFile)
|
|
289
|
+
return undefined;
|
|
290
|
+
let byConsts = sameFileFunctionCache.get(sourceFile);
|
|
291
|
+
if (!byConsts) {
|
|
292
|
+
byConsts = new WeakMap();
|
|
293
|
+
sameFileFunctionCache.set(sourceFile, byConsts);
|
|
294
|
+
}
|
|
295
|
+
const cached = byConsts.get(consts);
|
|
296
|
+
if (cached)
|
|
297
|
+
return cached;
|
|
298
|
+
const scope = new Map();
|
|
299
|
+
const functions = collectSameFileFunctions(sourceFile, consts, sourceFile.fileName, scope);
|
|
300
|
+
for (const [name, fn] of functions)
|
|
301
|
+
scope.set(name, fn);
|
|
302
|
+
byConsts.set(consts, functions);
|
|
303
|
+
return functions;
|
|
304
|
+
}
|
|
305
|
+
const sameFileFunctionCache = new WeakMap();
|
|
306
|
+
export function isFoldableFunction(value) {
|
|
307
|
+
return value instanceof FoldableFunction;
|
|
308
|
+
}
|
|
309
|
+
/** A binding element a folded function can bind plainly: `{ a }` / `{ a: b }`, no rest, default, or nested pattern. */
|
|
310
|
+
function plainBindingKey(el) {
|
|
311
|
+
if (el.dotDotDotToken || el.initializer || !ts.isIdentifier(el.name))
|
|
312
|
+
return undefined;
|
|
313
|
+
const key = el.propertyName ?? el.name;
|
|
314
|
+
if (ts.isIdentifier(key) || ts.isStringLiteral(key) || ts.isNumericLiteral(key))
|
|
315
|
+
return key.text;
|
|
316
|
+
return undefined;
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* The SHAPE half of what makes a project-local function foldable (chant
|
|
320
|
+
* #1373) — a reason string, or `undefined` when the function is admissible.
|
|
321
|
+
* Deliberately the same statement-level contract #1023 gives a composite
|
|
322
|
+
* factory body: parameters bound plainly (an identifier, optionally
|
|
323
|
+
* defaulted, or a flat object pattern), and a body that is either a single
|
|
324
|
+
* expression or `const` declarations followed by one `return`. Every
|
|
325
|
+
* expression inside is then folded by {@link fold} itself, so the expression
|
|
326
|
+
* subset is defined exactly once — with the additions {@link fold} refuses
|
|
327
|
+
* INSIDE a function body (a `new`, a tagged template, a registered helper or
|
|
328
|
+
* intrinsic call), because each of those reduces to an envelope revived
|
|
329
|
+
* against the CALLER's imports, which are not the scope the body was written
|
|
330
|
+
* in.
|
|
331
|
+
*/
|
|
332
|
+
export function findFunctionSubsetViolation(fn) {
|
|
333
|
+
if (fn.asteriskToken)
|
|
334
|
+
return "a generator function is not foldable";
|
|
335
|
+
if (fn.modifiers?.some((m) => m.kind === ts.SyntaxKind.AsyncKeyword))
|
|
336
|
+
return "an async function is not foldable";
|
|
337
|
+
if (!fn.body)
|
|
338
|
+
return "a function without a body (an overload signature) is not foldable";
|
|
339
|
+
for (const param of fn.parameters) {
|
|
340
|
+
if (param.dotDotDotToken)
|
|
341
|
+
return "a rest parameter is not foldable";
|
|
342
|
+
if (ts.isIdentifier(param.name))
|
|
343
|
+
continue;
|
|
344
|
+
if (ts.isObjectBindingPattern(param.name)) {
|
|
345
|
+
for (const el of param.name.elements) {
|
|
346
|
+
if (plainBindingKey(el) === undefined) {
|
|
347
|
+
return "a destructured parameter with a rest, default, or nested element is not foldable";
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
continue;
|
|
351
|
+
}
|
|
352
|
+
return "an array-destructured parameter is not foldable";
|
|
353
|
+
}
|
|
354
|
+
if (!ts.isBlock(fn.body))
|
|
355
|
+
return undefined;
|
|
356
|
+
const statements = fn.body.statements;
|
|
357
|
+
for (let i = 0; i < statements.length; i += 1) {
|
|
358
|
+
const statement = statements[i];
|
|
359
|
+
const last = i === statements.length - 1;
|
|
360
|
+
if (ts.isReturnStatement(statement)) {
|
|
361
|
+
if (!last)
|
|
362
|
+
return "an early `return` is not foldable";
|
|
363
|
+
continue;
|
|
364
|
+
}
|
|
365
|
+
if (!ts.isVariableStatement(statement)) {
|
|
366
|
+
return `\`${ts.SyntaxKind[statement.kind]}\` in a function body is not foldable — only \`const\` declarations and a final \`return\` are`;
|
|
367
|
+
}
|
|
368
|
+
if ((statement.declarationList.flags & ts.NodeFlags.Const) === 0) {
|
|
369
|
+
return "`let`/`var` in a function body is not foldable";
|
|
370
|
+
}
|
|
371
|
+
for (const decl of statement.declarationList.declarations) {
|
|
372
|
+
if (!decl.initializer)
|
|
373
|
+
return "an uninitialized `const` in a function body is not foldable";
|
|
374
|
+
if (ts.isIdentifier(decl.name))
|
|
375
|
+
continue;
|
|
376
|
+
if (ts.isObjectBindingPattern(decl.name)) {
|
|
377
|
+
for (const el of decl.name.elements) {
|
|
378
|
+
if (plainBindingKey(el) === undefined) {
|
|
379
|
+
return "a destructured `const` with a rest, default, or nested element is not foldable";
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
continue;
|
|
383
|
+
}
|
|
384
|
+
return "an array-destructured `const` in a function body is not foldable";
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
return undefined;
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* How many project-local function bodies are being folded around the current
|
|
391
|
+
* `fold()` call — 0 at a file's own top level. Two jobs: terminate a function
|
|
392
|
+
* that (directly or through another) calls itself, which has no fixpoint and
|
|
393
|
+
* no file boundary for fold-import's cycle detection to notice; and tell the
|
|
394
|
+
* envelope-producing branches of {@link fold} that they are inside a body,
|
|
395
|
+
* where an envelope must not be produced (see {@link findFunctionSubsetViolation}).
|
|
396
|
+
*/
|
|
397
|
+
let functionBodyDepth = 0;
|
|
398
|
+
const MAX_FUNCTION_CALL_DEPTH = 32;
|
|
399
|
+
function insideFunctionBody(node, what) {
|
|
400
|
+
if (functionBodyDepth === 0)
|
|
401
|
+
return undefined;
|
|
402
|
+
return foldError(node, `${what} inside a folded function body is not foldable`, "EVL001", true);
|
|
403
|
+
}
|
|
404
|
+
function fileLabel(file) {
|
|
405
|
+
const rel = relative(process.cwd(), file);
|
|
406
|
+
return rel.startsWith("..") ? file : rel;
|
|
407
|
+
}
|
|
408
|
+
/**
|
|
409
|
+
* Evaluate a call to a project-local function (chant #1373) — see
|
|
410
|
+
* {@link FoldableFunction}. Arguments fold in the caller's scope (`consts`/
|
|
411
|
+
* `externals`); the body folds in the callee's, with the parameters bound on
|
|
412
|
+
* top. Any failure inside the body is re-thrown at the CALL site, naming the
|
|
413
|
+
* callee, its file and the position inside it, and the reason — so the
|
|
414
|
+
* `[fold:run]` line for the importing file says which helper to fix and why,
|
|
415
|
+
* rather than the bare "function call as a value" it said before.
|
|
416
|
+
*/
|
|
417
|
+
function callFoldableFunction(callee, node, consts, intrinsics, externals) {
|
|
418
|
+
const label = `call to "${callee.name}" (${fileLabel(callee.file)})`;
|
|
419
|
+
const violation = findFunctionSubsetViolation(callee.fn);
|
|
420
|
+
if (violation)
|
|
421
|
+
throw foldError(node, `${label} is not foldable: ${violation}`);
|
|
422
|
+
if (functionBodyDepth >= MAX_FUNCTION_CALL_DEPTH) {
|
|
423
|
+
throw foldError(node, `${label} is not foldable: call depth exceeded — is it recursive?`);
|
|
424
|
+
}
|
|
425
|
+
const args = [];
|
|
426
|
+
for (const arg of node.arguments) {
|
|
427
|
+
if (ts.isSpreadElement(arg))
|
|
428
|
+
throw foldError(arg, `${label} is not foldable: a spread argument is not foldable`);
|
|
429
|
+
args.push(fold(arg, consts, intrinsics, externals));
|
|
430
|
+
}
|
|
431
|
+
const bodyConsts = new Map(callee.consts);
|
|
432
|
+
const bodyExternals = new Map(callee.externals);
|
|
433
|
+
const bind = (name, value) => {
|
|
434
|
+
// A parameter or body binding SHADOWS a module-level const of the same
|
|
435
|
+
// name — `fold()` consults `consts` before `externals`.
|
|
436
|
+
bodyConsts.delete(name);
|
|
437
|
+
bodyExternals.set(name, value);
|
|
438
|
+
};
|
|
439
|
+
const destructure = (pattern, value) => {
|
|
440
|
+
if (value === null || typeof value !== "object") {
|
|
441
|
+
throw foldError(pattern, `destructured source in \`${briefNodeText(pattern)}\` is not an object`);
|
|
442
|
+
}
|
|
443
|
+
for (const el of pattern.elements) {
|
|
444
|
+
bind(el.name.text, value[plainBindingKey(el)]);
|
|
445
|
+
}
|
|
446
|
+
};
|
|
447
|
+
functionBodyDepth += 1;
|
|
448
|
+
try {
|
|
449
|
+
const result = evaluateFunctionBody(callee, args, bodyConsts, bodyExternals, intrinsics, bind, destructure);
|
|
450
|
+
// Live objects that ARRIVED through the arguments are the caller's own
|
|
451
|
+
// already; only one the body produced from its module's scope is new.
|
|
452
|
+
if (!callee.leakedIdentity && carriesLiveObject(result) && !args.some((arg) => carriesLiveObject(arg))) {
|
|
453
|
+
callee.leakedIdentity = true;
|
|
454
|
+
}
|
|
455
|
+
return result;
|
|
456
|
+
}
|
|
457
|
+
catch (err) {
|
|
458
|
+
if (!(err instanceof FoldError))
|
|
459
|
+
throw err;
|
|
460
|
+
// The inner message is positioned inside the CALLEE file. Strip that
|
|
461
|
+
// prefix and re-anchor at the call site: callee, its file and position,
|
|
462
|
+
// then the reason.
|
|
463
|
+
const prefix = `${err.line}:${err.column} - `;
|
|
464
|
+
const inner = err.message.startsWith(prefix) ? err.message.slice(prefix.length) : err.message;
|
|
465
|
+
let reason = inner;
|
|
466
|
+
const unresolved = /^unresolved identifier: (\w+)$/.exec(inner);
|
|
467
|
+
if (unresolved && callee.failures?.has(unresolved[1])) {
|
|
468
|
+
reason = `${inner} (${callee.failures.get(unresolved[1])})`;
|
|
469
|
+
}
|
|
470
|
+
throw foldError(node, `${label} is not foldable: ${fileLabel(callee.file)}:${err.line}:${err.column} - ${reason}`, err.ruleId,
|
|
471
|
+
// chant#2441 — the refusal happened inside the callee's body and this
|
|
472
|
+
// frame is the CALL site, so without carrying the flag the caller sees
|
|
473
|
+
// an ordinary failure and falls back to invoking.
|
|
474
|
+
err.refusedAtDepth);
|
|
475
|
+
}
|
|
476
|
+
finally {
|
|
477
|
+
functionBodyDepth -= 1;
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
function evaluateFunctionBody(callee, args, bodyConsts, bodyExternals, intrinsics, bind, destructure) {
|
|
481
|
+
callee.fn.parameters.forEach((param, i) => {
|
|
482
|
+
let value = args[i];
|
|
483
|
+
if (value === undefined && param.initializer) {
|
|
484
|
+
value = fold(param.initializer, bodyConsts, intrinsics, bodyExternals);
|
|
485
|
+
}
|
|
486
|
+
if (ts.isIdentifier(param.name))
|
|
487
|
+
bind(param.name.text, value);
|
|
488
|
+
else
|
|
489
|
+
destructure(param.name, value);
|
|
490
|
+
});
|
|
491
|
+
const body = callee.fn.body;
|
|
492
|
+
if (!ts.isBlock(body))
|
|
493
|
+
return fold(body, bodyConsts, intrinsics, bodyExternals);
|
|
494
|
+
for (const statement of body.statements) {
|
|
495
|
+
if (ts.isReturnStatement(statement)) {
|
|
496
|
+
return statement.expression ? fold(statement.expression, bodyConsts, intrinsics, bodyExternals) : undefined;
|
|
497
|
+
}
|
|
498
|
+
for (const decl of statement.declarationList.declarations) {
|
|
499
|
+
const value = fold(decl.initializer, bodyConsts, intrinsics, bodyExternals);
|
|
500
|
+
if (ts.isIdentifier(decl.name))
|
|
501
|
+
bind(decl.name.text, value);
|
|
502
|
+
else
|
|
503
|
+
destructure(decl.name, value);
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
// A block body with no `return` evaluates to `undefined`, as it would run.
|
|
507
|
+
return undefined;
|
|
508
|
+
}
|
|
509
|
+
/**
|
|
510
|
+
* Resolve a node's 1-based line/column via its owning `SourceFile`. Exported
|
|
511
|
+
* (chant #1020) so fold-import.ts can build its own located `FoldError`s
|
|
512
|
+
* (e.g. an import-cycle diagnostic pointing at the specific `import`
|
|
513
|
+
* statement that closes the cycle) using the exact same position math
|
|
514
|
+
* `foldError` uses here, rather than a second hand-rolled implementation.
|
|
515
|
+
*/
|
|
516
|
+
export function locate(node) {
|
|
517
|
+
const sourceFile = node.getSourceFile();
|
|
518
|
+
const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart());
|
|
519
|
+
return { line: line + 1, column: character + 1 };
|
|
520
|
+
}
|
|
521
|
+
function foldError(node, message, ruleId = "EVL001", refusedAtDepth = false) {
|
|
522
|
+
const { line, column } = locate(node);
|
|
523
|
+
return new FoldError(message, line, column, ruleId, refusedAtDepth);
|
|
524
|
+
}
|
|
525
|
+
/**
|
|
526
|
+
* Collect every top-level `const x = <initializer>` in a source file into a
|
|
527
|
+
* name -> initializer map. Single-file only (cross-file is #1020).
|
|
528
|
+
*/
|
|
529
|
+
export function collectConsts(sourceFile) {
|
|
530
|
+
const consts = new Map();
|
|
531
|
+
for (const statement of sourceFile.statements) {
|
|
532
|
+
if (!ts.isVariableStatement(statement))
|
|
533
|
+
continue;
|
|
534
|
+
if ((statement.declarationList.flags & ts.NodeFlags.Const) === 0)
|
|
535
|
+
continue;
|
|
536
|
+
for (const decl of statement.declarationList.declarations) {
|
|
537
|
+
if (ts.isIdentifier(decl.name) && decl.initializer) {
|
|
538
|
+
consts.set(decl.name.text, decl.initializer);
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
return consts;
|
|
543
|
+
}
|
|
544
|
+
/**
|
|
545
|
+
* A property/element key foldable without execution: identifier, string, or
|
|
546
|
+
* numeric literal.
|
|
547
|
+
*
|
|
548
|
+
* Exported for chant #1023's composite-factory interpreter
|
|
549
|
+
* (../discovery/fold-import.ts), which walks object literals itself — a
|
|
550
|
+
* factory body may construct a resource inside one, which {@link fold} has no
|
|
551
|
+
* case for — and must reject a computed key with the identical message
|
|
552
|
+
* {@link fold} would, rather than growing a second, silently divergent copy of
|
|
553
|
+
* this rule.
|
|
554
|
+
*/
|
|
555
|
+
export function propName(node) {
|
|
556
|
+
if (isLiteralPropertyName(node))
|
|
557
|
+
return node.text;
|
|
558
|
+
throw foldError(node, computedPropertyNameMessage(node));
|
|
559
|
+
}
|
|
560
|
+
/**
|
|
561
|
+
* An element-access key foldable without execution: a string or numeric
|
|
562
|
+
* LITERAL only (EVL003 semantics — a variable or expression key is a
|
|
563
|
+
* dynamic key and is rejected).
|
|
564
|
+
*/
|
|
565
|
+
function elementKey(node) {
|
|
566
|
+
if (isLiteralElementKey(node))
|
|
567
|
+
return node.text;
|
|
568
|
+
throw foldError(node, dynamicElementAccessMessage(node), "EVL003");
|
|
569
|
+
}
|
|
570
|
+
/** True when `ident` is a `const` bound to a `new Type(...)` resource constructor. */
|
|
571
|
+
function resolvesToResource(consts, ident) {
|
|
572
|
+
const init = consts.get(ident.text);
|
|
573
|
+
return init !== undefined && ts.isNewExpression(init);
|
|
574
|
+
}
|
|
575
|
+
/**
|
|
576
|
+
* True when `node` is a call through a bare identifier that isn't ALREADY
|
|
577
|
+
* one of `fold()`'s other three call shapes — a registered authoring helper,
|
|
578
|
+
* a registered call-form intrinsic, or a project-local {@link FoldableFunction}
|
|
579
|
+
* — i.e. exactly the callee the `CallExpression` branch below would
|
|
580
|
+
* otherwise throw {@link callExpressionMessage} for. Used only by the
|
|
581
|
+
* `.step` narrowing in the property-access branch (chant #1174,
|
|
582
|
+
* {@link FoldedCompositeStepCall}): checked from the OUTSIDE, at the
|
|
583
|
+
* property-access node, so `Checkout({...})` alone (no `.step`) still falls
|
|
584
|
+
* through to the ordinary `CallExpression` throw, unchanged.
|
|
585
|
+
*/
|
|
586
|
+
function isUnclaimedBareCall(node, consts, intrinsics, externals) {
|
|
587
|
+
if (!ts.isCallExpression(node) || !ts.isIdentifier(node.expression))
|
|
588
|
+
return false;
|
|
589
|
+
const name = node.expression.text;
|
|
590
|
+
if (consts.has(name))
|
|
591
|
+
return false;
|
|
592
|
+
if (isFoldableHelperName(name))
|
|
593
|
+
return false;
|
|
594
|
+
if (intrinsics.some((i) => i.name === name && intrinsicCallFolds(i)))
|
|
595
|
+
return false;
|
|
596
|
+
if (isFoldableFunction(externals?.get(name)))
|
|
597
|
+
return false;
|
|
598
|
+
return true;
|
|
599
|
+
}
|
|
600
|
+
/** True when a folded value is a {@link FoldedResource} envelope (a `new Type(...)` that nothing constructed yet). */
|
|
601
|
+
function isFoldedResource(value) {
|
|
602
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) && "__resource" in value;
|
|
603
|
+
}
|
|
604
|
+
/**
|
|
605
|
+
* True when `value` is one of `fold()`'s own symbolic envelope shapes — a
|
|
606
|
+
* stand-in for a value nothing has constructed or revived yet, not the value
|
|
607
|
+
* itself. A method call (see the `CallExpression` branch's property-access
|
|
608
|
+
* case below) must refuse one rather than silently falling through to
|
|
609
|
+
* `Object.prototype`'s own inherited methods — `toString` chief among them —
|
|
610
|
+
* which would answer with the placeholder's shape instead of what the real,
|
|
611
|
+
* eventually-revived value would produce.
|
|
612
|
+
*/
|
|
613
|
+
function isFoldSymbolicEnvelope(value) {
|
|
614
|
+
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
615
|
+
return false;
|
|
616
|
+
return ("__attrRef" in value ||
|
|
617
|
+
"__intrinsic" in value ||
|
|
618
|
+
"__helper" in value ||
|
|
619
|
+
"__resource" in value ||
|
|
620
|
+
"__compositeStep" in value);
|
|
621
|
+
}
|
|
622
|
+
/**
|
|
623
|
+
* chant #1535 — an attribute read whose object folded to a resource ENVELOPE
|
|
624
|
+
* rather than resolving through {@link resolvesToResource}. That happens when
|
|
625
|
+
* the const's initializer is not a bare `new` but an expression that yields
|
|
626
|
+
* one: `const provider = flag ? new OIDCProvider({...}) : undefined;` then
|
|
627
|
+
* `provider.Arn`. Indexing the envelope (`{__resource, props}`) by the
|
|
628
|
+
* attribute name returns `undefined`, and the property vanished from the
|
|
629
|
+
* output without a word — a trust policy built with `Principal: { Federated:
|
|
630
|
+
* provider.Arn }` landed in CloudFormation as `Principal: {}`.
|
|
631
|
+
*
|
|
632
|
+
* When the object is a plain identifier, the answer is the same symbolic
|
|
633
|
+
* `{__attrRef}` the bare-`new` case produces — the serializer resolves it by
|
|
634
|
+
* the const's name, exactly as it would have for `const provider = new
|
|
635
|
+
* OIDCProvider({...})`. Any other expression shape has no name to key the
|
|
636
|
+
* ref on, so it refuses and the file falls back to run rather than emitting
|
|
637
|
+
* something wrong.
|
|
638
|
+
*/
|
|
639
|
+
function attrRefOnFoldedResource(node, attribute) {
|
|
640
|
+
if (ts.isIdentifier(node.expression)) {
|
|
641
|
+
return { __attrRef: { entity: node.expression.text, attribute } };
|
|
642
|
+
}
|
|
643
|
+
throw foldError(node, `attribute "${attribute}" read on an inline resource expression is not foldable — bind the resource to a const first (falls back to run)`);
|
|
644
|
+
}
|
|
645
|
+
/**
|
|
646
|
+
* chant #2328 — the marker an optional-chain link leaves behind when it
|
|
647
|
+
* short-circuits, carried up the rest of the chain and unwrapped to
|
|
648
|
+
* `undefined` at its end.
|
|
649
|
+
*
|
|
650
|
+
* `a?.b` on a nullish `a` is DEFINED to be `undefined` in JavaScript, and so
|
|
651
|
+
* is every link after it: `a?.b.c` is `undefined` too, not a `TypeError` on
|
|
652
|
+
* `undefined.c`. A non-optional `a.b` on a nullish `a` throws. Both shapes
|
|
653
|
+
* reach the property-access branch below with the same nullish object, so
|
|
654
|
+
* telling them apart needs the answer to "did an EARLIER link short-circuit?"
|
|
655
|
+
* — which a plain `undefined` return cannot carry, because a genuine
|
|
656
|
+
* `undefined` looks identical: `({}).b.c` is `undefined` at the first link
|
|
657
|
+
* and running it DOES throw at the second.
|
|
658
|
+
*
|
|
659
|
+
* This marker carries it. {@link shortCircuited} produces it only where
|
|
660
|
+
* {@link continuesOptionalChain} says the parent node is the next link of the
|
|
661
|
+
* same chain, so the parent always consumes it, and turns it back into
|
|
662
|
+
* `undefined` at the last link — which is where JavaScript's own
|
|
663
|
+
* short-circuit lands. It never escapes {@link fold}'s return to a caller.
|
|
664
|
+
*/
|
|
665
|
+
const CHAIN_SHORT_CIRCUIT = Symbol("chant.fold.optional-chain-short-circuit");
|
|
666
|
+
/** True when `value` is the {@link CHAIN_SHORT_CIRCUIT} marker. */
|
|
667
|
+
function isChainShortCircuit(value) {
|
|
668
|
+
return value === CHAIN_SHORT_CIRCUIT;
|
|
669
|
+
}
|
|
670
|
+
/**
|
|
671
|
+
* The value a chain that short-circuited at or before `node` has AT `node`:
|
|
672
|
+
* the {@link CHAIN_SHORT_CIRCUIT} marker while another link follows,
|
|
673
|
+
* `undefined` once `node` is the last one.
|
|
674
|
+
*/
|
|
675
|
+
function shortCircuited(node) {
|
|
676
|
+
return continuesOptionalChain(node) ? CHAIN_SHORT_CIRCUIT : undefined;
|
|
677
|
+
}
|
|
678
|
+
/**
|
|
679
|
+
* True when `node`'s parent is the next link of the SAME optional chain, so a
|
|
680
|
+
* short-circuit at `node` must keep travelling rather than becoming
|
|
681
|
+
* `undefined` here.
|
|
682
|
+
*
|
|
683
|
+
* TypeScript flags every access/call node after a `?.` as part of that chain
|
|
684
|
+
* and stops flagging at the first construct that ends it, so this needs no
|
|
685
|
+
* bookkeeping of its own: `(a?.b).c` — where the parentheses end the chain
|
|
686
|
+
* and running really does throw on `.c` — is not a continuation, and neither
|
|
687
|
+
* is `(a?.b as X).c`. A `NonNullChain` (`a?.b!.c`) is transparent, exactly as
|
|
688
|
+
* {@link fold}'s own non-null unwrapping is.
|
|
689
|
+
*/
|
|
690
|
+
function continuesOptionalChain(node) {
|
|
691
|
+
const parent = node.parent;
|
|
692
|
+
if (parent === undefined)
|
|
693
|
+
return false;
|
|
694
|
+
if (ts.isNonNullExpression(parent) && ts.isOptionalChain(parent))
|
|
695
|
+
return continuesOptionalChain(parent);
|
|
696
|
+
return ((ts.isPropertyAccessExpression(parent) || ts.isElementAccessExpression(parent) || ts.isCallExpression(parent)) &&
|
|
697
|
+
parent.expression === node &&
|
|
698
|
+
ts.isOptionalChain(parent));
|
|
699
|
+
}
|
|
700
|
+
/**
|
|
701
|
+
* chant #2328 — a property or element read whose object folded to `null` or
|
|
702
|
+
* `undefined`. Folding it to `undefined` (what both branches did from #1026
|
|
703
|
+
* until now) drops the property from the output and lets the build carry on,
|
|
704
|
+
* while RUNNING the same expression throws `TypeError: Cannot read properties
|
|
705
|
+
* of undefined` — the fold/run disagreement #1535 already ruled unacceptable
|
|
706
|
+
* one branch over, where an attribute read on a resource envelope folded away
|
|
707
|
+
* and a trust policy shipped as `Principal: {}`.
|
|
708
|
+
*
|
|
709
|
+
* So it refuses, and the file falls back to run — where the real `TypeError`
|
|
710
|
+
* happens at the line that caused it, naming the property the way it would
|
|
711
|
+
* without `--fold` at all. The usual cause is a typo in a nested path
|
|
712
|
+
* (`cfg.nett.vpcId`); a genuinely optional read says so with `?.`, which
|
|
713
|
+
* short-circuits above instead of reaching this message.
|
|
714
|
+
*/
|
|
715
|
+
function nullishAccessMessage(member, obj) {
|
|
716
|
+
return (`property "${member}" read on ${String(obj)} is not foldable — running this expression throws a TypeError, ` +
|
|
717
|
+
`so the file falls back to run (write \`?.\` if the value is genuinely optional)`);
|
|
718
|
+
}
|
|
719
|
+
/**
|
|
720
|
+
* True when `node` is an identifier, or a dotted/bracketed access chain
|
|
721
|
+
* rooted at an identifier, that neither `consts` nor `externals` can resolve
|
|
722
|
+
* — e.g. `AWS.StackName` from an imported pseudo-parameter namespace inside
|
|
723
|
+
* a lexicon package (still #1063). Nothing here can say what it refers to,
|
|
724
|
+
* so an intrinsic's interior keeps it symbolically rather than rejecting it.
|
|
725
|
+
*
|
|
726
|
+
* `externals` (chant #1020) is consulted so a root that fold CAN resolve is
|
|
727
|
+
* not treated as unresolved: `Ref(environment)`, where `environment` is a
|
|
728
|
+
* `Parameter` imported from a sibling project file, must fold to the REAL,
|
|
729
|
+
* already-constructed Declarable the fold session made for that file, not to
|
|
730
|
+
* a `{__symbol}` the bridge later re-imports — re-importing the defining
|
|
731
|
+
* module builds a second, differently-identified instance of the same
|
|
732
|
+
* resource, which is exactly the shared-identity property #1020 exists to
|
|
733
|
+
* preserve (see fold-import.ts's module doc).
|
|
734
|
+
*/
|
|
735
|
+
function isUnresolvedSymbolChain(node, consts, externals) {
|
|
736
|
+
if (ts.isIdentifier(node)) {
|
|
737
|
+
return node.text !== "undefined" && !consts.has(node.text) && !externals?.has(node.text);
|
|
738
|
+
}
|
|
739
|
+
if (ts.isPropertyAccessExpression(node))
|
|
740
|
+
return isUnresolvedSymbolChain(node.expression, consts, externals);
|
|
741
|
+
if (ts.isElementAccessExpression(node))
|
|
742
|
+
return isUnresolvedSymbolChain(node.expression, consts, externals);
|
|
743
|
+
if (ts.isNonNullExpression(node))
|
|
744
|
+
return isUnresolvedSymbolChain(node.expression, consts, externals);
|
|
745
|
+
return false;
|
|
746
|
+
}
|
|
747
|
+
/**
|
|
748
|
+
* Fold one sub-expression of a registered intrinsic's interior — an
|
|
749
|
+
* interpolation of its tagged-template form, or (chant #1044) an argument of
|
|
750
|
+
* its plain-call form. Identical to {@link fold}, except a symbol chain
|
|
751
|
+
* nothing can resolve (a pseudo-parameter-style access into a lexicon
|
|
752
|
+
* package, `AWS.StackName`) folds to a {@link SymbolicValue} instead of
|
|
753
|
+
* throwing — the run path resolves it once the module actually imports and
|
|
754
|
+
* runs; fold preserves it symbolically rather than stringifying or rejecting
|
|
755
|
+
* it, and fold-import.ts's `resolveSymbolicValue` resolves it for real
|
|
756
|
+
* before the intrinsic is constructed.
|
|
757
|
+
*
|
|
758
|
+
* `externals` (chant #1020) takes precedence over the symbolic path: see
|
|
759
|
+
* {@link isUnresolvedSymbolChain} for why an already-resolved cross-file
|
|
760
|
+
* binding must reach the intrinsic as the real, shared object rather than as
|
|
761
|
+
* a symbol the bridge re-imports.
|
|
762
|
+
*/
|
|
763
|
+
function foldIntrinsicValue(node, consts, intrinsics, externals) {
|
|
764
|
+
if (isUnresolvedSymbolChain(node, consts, externals)) {
|
|
765
|
+
return { __symbol: node.getText() };
|
|
766
|
+
}
|
|
767
|
+
return fold(node, consts, intrinsics, externals);
|
|
768
|
+
}
|
|
769
|
+
/**
|
|
770
|
+
* A template part's raw text, as `TemplateStringsArray.raw` holds it. The
|
|
771
|
+
* parser sets `rawText` on every literal it reads; the fallback takes the
|
|
772
|
+
* source between the delimiters for a node without one. Line terminators are
|
|
773
|
+
* normalized the way the language does for `raw` (`\r\n` and `\r` become
|
|
774
|
+
* `\n`), which TypeScript's `rawText` does not do.
|
|
775
|
+
*/
|
|
776
|
+
function rawTemplateText(part) {
|
|
777
|
+
let raw = part.rawText;
|
|
778
|
+
if (raw === undefined) {
|
|
779
|
+
const text = part.getText();
|
|
780
|
+
const close = ts.isTemplateHead(part) || ts.isTemplateMiddle(part) ? 2 : 1;
|
|
781
|
+
raw = text.slice(1, text.length - close);
|
|
782
|
+
}
|
|
783
|
+
return raw.replace(/\r\n?/g, "\n");
|
|
784
|
+
}
|
|
785
|
+
/**
|
|
786
|
+
* True when a raw template part holds an escape a tagged template allows but
|
|
787
|
+
* cannot cook (`\u{zz}`, `\xg`, `\1`, `\01`). Its cooked string is
|
|
788
|
+
* `undefined` at run time, while TypeScript's `text` carries a string, so
|
|
789
|
+
* folding it would hand the tag something running never does.
|
|
790
|
+
*/
|
|
791
|
+
function hasInvalidTemplateEscape(raw) {
|
|
792
|
+
for (let i = 0; i < raw.length; i++) {
|
|
793
|
+
if (raw[i] !== "\\")
|
|
794
|
+
continue;
|
|
795
|
+
const rest = raw.slice(i + 1);
|
|
796
|
+
const c = rest[0];
|
|
797
|
+
if (c === "x") {
|
|
798
|
+
if (!/^x[0-9a-fA-F]{2}/.test(rest))
|
|
799
|
+
return true;
|
|
800
|
+
}
|
|
801
|
+
else if (c === "u") {
|
|
802
|
+
const m = /^u(?:[0-9a-fA-F]{4}|\{([0-9a-fA-F]+)\})/.exec(rest);
|
|
803
|
+
if (!m || (m[1] !== undefined && parseInt(m[1], 16) > 0x10ffff))
|
|
804
|
+
return true;
|
|
805
|
+
}
|
|
806
|
+
else if (c !== undefined && c >= "1" && c <= "9") {
|
|
807
|
+
return true;
|
|
808
|
+
}
|
|
809
|
+
else if (c === "0" && rest[1] !== undefined && rest[1] >= "0" && rest[1] <= "9") {
|
|
810
|
+
return true;
|
|
811
|
+
}
|
|
812
|
+
i += 1;
|
|
813
|
+
}
|
|
814
|
+
return false;
|
|
815
|
+
}
|
|
816
|
+
/**
|
|
817
|
+
* Fold a `TaggedTemplateExpression` whose tag is a registered, foldable
|
|
818
|
+
* lexicon intrinsic ({@link intrinsicTagFolds}, `../lexicon.ts`) to its node
|
|
819
|
+
* form. An unregistered — or registered-but-not-foldable — tag throws a
|
|
820
|
+
* located {@link FoldError}.
|
|
821
|
+
*
|
|
822
|
+
* Checks the TAG-form predicate specifically (chant #1044): an intrinsic
|
|
823
|
+
* whose lexicon opted its plain-call form in is not thereby usable as a
|
|
824
|
+
* tagged template, and `` Ref`...` `` stays a rejection.
|
|
825
|
+
*
|
|
826
|
+
* The envelope carries both the cooked parts and the raw ones (#3196), so the
|
|
827
|
+
* revived call receives the `TemplateStringsArray` a real tagged call does. A
|
|
828
|
+
* tag that reads `strings.raw` (a SQL tag keeping `'\d+'` as written) would
|
|
829
|
+
* otherwise build different text folded than run.
|
|
830
|
+
*/
|
|
831
|
+
function foldTaggedTemplate(node, consts, intrinsics, externals) {
|
|
832
|
+
const tagName = node.tag.getText();
|
|
833
|
+
const isRegistered = intrinsics.some((i) => i.name === tagName && intrinsicTagFolds(i));
|
|
834
|
+
if (!isRegistered) {
|
|
835
|
+
throw foldError(node, `unregistered tagged template intrinsic: ${briefNodeText(node.tag)}\`...\``);
|
|
836
|
+
}
|
|
837
|
+
const template = node.template;
|
|
838
|
+
const parts = ts.isNoSubstitutionTemplateLiteral(template)
|
|
839
|
+
? [template]
|
|
840
|
+
: [template.head, ...template.templateSpans.map((span) => span.literal)];
|
|
841
|
+
const raw = parts.map(rawTemplateText);
|
|
842
|
+
if (raw.some(hasInvalidTemplateEscape)) {
|
|
843
|
+
throw foldError(node, `${briefNodeText(node.tag)}\`...\` holds an escape sequence with no cooked value — not foldable, falls back to run`);
|
|
844
|
+
}
|
|
845
|
+
const strings = parts.map((part) => part.text);
|
|
846
|
+
const values = ts.isNoSubstitutionTemplateLiteral(template)
|
|
847
|
+
? []
|
|
848
|
+
: template.templateSpans.map((span) => foldIntrinsicValue(span.expression, consts, intrinsics, externals));
|
|
849
|
+
return { __intrinsic: tagName, strings, raw, values };
|
|
850
|
+
}
|
|
851
|
+
/**
|
|
852
|
+
* Fold a single expression node to a value. Throws {@link FoldError} for
|
|
853
|
+
* anything outside the supported subset — including any `CallExpression`
|
|
854
|
+
* that is neither a registered chant authoring helper nor a registered,
|
|
855
|
+
* call-form-opted-in lexicon intrinsic (see the module doc).
|
|
856
|
+
*
|
|
857
|
+
* @param intrinsics - The active lexicons' registered intrinsics. A tagged
|
|
858
|
+
* template whose tag isn't in this list, or is in it without
|
|
859
|
+
* {@link intrinsicTagFolds}, is rejected; a plain call is rejected unless
|
|
860
|
+
* its callee is in this list with {@link intrinsicCallFolds} (chant
|
|
861
|
+
* #1044). Defaults to none — pass the target lexicon's manifest
|
|
862
|
+
* `intrinsics` to recognize either form.
|
|
863
|
+
* @param externals - chant #1020: pre-resolved imported bindings, consulted
|
|
864
|
+
* only when an identifier isn't in `consts`. See the module doc above.
|
|
865
|
+
* `undefined` (the default) preserves the exact pre-#1020 single-file
|
|
866
|
+
* behavior — every identifier not in `consts` is unresolved.
|
|
867
|
+
*/
|
|
868
|
+
export function fold(node, consts, intrinsics = [], externals) {
|
|
869
|
+
if (ts.isParenthesizedExpression(node) ||
|
|
870
|
+
ts.isAsExpression(node) ||
|
|
871
|
+
ts.isSatisfiesExpression(node) ||
|
|
872
|
+
ts.isNonNullExpression(node)) {
|
|
873
|
+
return fold(node.expression, consts, intrinsics, externals);
|
|
874
|
+
}
|
|
875
|
+
if (ts.isArrowFunction(node) || ts.isFunctionExpression(node)) {
|
|
876
|
+
// chant #1373 — a function is callable here (see {@link FoldableFunction})
|
|
877
|
+
// but never a VALUE: nothing downstream can serialize one.
|
|
878
|
+
throw foldError(node, "a function used as a value is not foldable");
|
|
879
|
+
}
|
|
880
|
+
if (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node)) {
|
|
881
|
+
return node.text;
|
|
882
|
+
}
|
|
883
|
+
if (ts.isNumericLiteral(node)) {
|
|
884
|
+
return Number(node.text);
|
|
885
|
+
}
|
|
886
|
+
if (node.kind === ts.SyntaxKind.TrueKeyword)
|
|
887
|
+
return true;
|
|
888
|
+
if (node.kind === ts.SyntaxKind.FalseKeyword)
|
|
889
|
+
return false;
|
|
890
|
+
if (node.kind === ts.SyntaxKind.NullKeyword)
|
|
891
|
+
return null;
|
|
892
|
+
if (ts.isIdentifier(node) && node.text === "undefined")
|
|
893
|
+
return undefined;
|
|
894
|
+
if (ts.isTaggedTemplateExpression(node)) {
|
|
895
|
+
const inside = insideFunctionBody(node, "a tagged template intrinsic");
|
|
896
|
+
if (inside)
|
|
897
|
+
throw inside;
|
|
898
|
+
return foldTaggedTemplate(node, consts, intrinsics, externals);
|
|
899
|
+
}
|
|
900
|
+
if (ts.isTemplateExpression(node)) {
|
|
901
|
+
let out = node.head.text;
|
|
902
|
+
for (const span of node.templateSpans) {
|
|
903
|
+
const value = fold(span.expression, consts, intrinsics, externals);
|
|
904
|
+
// A symbolic envelope has no string form. `String({__attrRef: …})` is
|
|
905
|
+
// `"[object Object]"`, and so is `String(attrRef)` on the run path,
|
|
906
|
+
// because `../attrref.ts` defines no `toString` — so the two paths
|
|
907
|
+
// agreed on a wrong answer and the differential saw nothing (#2349).
|
|
908
|
+
// Refused here rather than stringified, for the same reason the
|
|
909
|
+
// eager-intrinsic branch refuses a deferred envelope (#1966).
|
|
910
|
+
const symbolic = symbolicEnvelopeKind(value);
|
|
911
|
+
if (symbolic) {
|
|
912
|
+
throw foldError(span.expression, `${symbolic} interpolated into a plain template literal, which would stringify it as ` +
|
|
913
|
+
'"[object Object]". A symbolic value has no string form until the build resolves it, so a ' +
|
|
914
|
+
"plain template cannot carry one. Use the lexicon's own intrinsic, whose interior handles " +
|
|
915
|
+
"envelopes — `Sub`${…}`` for CloudFormation — or move the reference out of the template.");
|
|
916
|
+
}
|
|
917
|
+
out += String(value) + span.literal.text;
|
|
918
|
+
}
|
|
919
|
+
return out;
|
|
920
|
+
}
|
|
921
|
+
if (ts.isObjectLiteralExpression(node)) {
|
|
922
|
+
const obj = {};
|
|
923
|
+
for (const prop of node.properties) {
|
|
924
|
+
if (ts.isPropertyAssignment(prop)) {
|
|
925
|
+
obj[propName(prop.name)] = fold(prop.initializer, consts, intrinsics, externals);
|
|
926
|
+
}
|
|
927
|
+
else if (ts.isShorthandPropertyAssignment(prop)) {
|
|
928
|
+
obj[prop.name.text] = fold(prop.name, consts, intrinsics, externals);
|
|
929
|
+
}
|
|
930
|
+
else if (ts.isSpreadAssignment(prop)) {
|
|
931
|
+
const src = fold(prop.expression, consts, intrinsics, externals);
|
|
932
|
+
if (src === null || typeof src !== "object") {
|
|
933
|
+
throw foldError(prop, "spread source not an object");
|
|
934
|
+
}
|
|
935
|
+
Object.assign(obj, src);
|
|
936
|
+
}
|
|
937
|
+
else {
|
|
938
|
+
throw foldError(prop, UNSUPPORTED_OBJECT_MEMBER_MESSAGE);
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
return obj;
|
|
942
|
+
}
|
|
943
|
+
if (ts.isArrayLiteralExpression(node)) {
|
|
944
|
+
const arr = [];
|
|
945
|
+
for (const el of node.elements) {
|
|
946
|
+
if (ts.isSpreadElement(el)) {
|
|
947
|
+
const src = fold(el.expression, consts, intrinsics, externals);
|
|
948
|
+
if (!Array.isArray(src)) {
|
|
949
|
+
throw foldError(el, "spread source not an array");
|
|
950
|
+
}
|
|
951
|
+
arr.push(...src);
|
|
952
|
+
}
|
|
953
|
+
else {
|
|
954
|
+
arr.push(fold(el, consts, intrinsics, externals));
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
return arr;
|
|
958
|
+
}
|
|
959
|
+
if (ts.isIdentifier(node)) {
|
|
960
|
+
if (!consts.has(node.text)) {
|
|
961
|
+
// chant #1020 — an imported binding fold-import.ts already resolved
|
|
962
|
+
// (to a plain value, or the real live Declarable/CompositeInstance a
|
|
963
|
+
// sibling file's own fold produced) is returned as-is: for a plain
|
|
964
|
+
// value this is exactly like resolving a local const; for a real live
|
|
965
|
+
// object, the property-access branches below just index it like any
|
|
966
|
+
// other object, which is what makes a real, correctly-identified
|
|
967
|
+
// `AttrRef` fall out of `network.vpc.VpcId` with zero special-casing
|
|
968
|
+
// here (see fold-import.ts's module doc).
|
|
969
|
+
if (externals?.has(node.text)) {
|
|
970
|
+
const external = externals.get(node.text);
|
|
971
|
+
if (isFoldableFunction(external)) {
|
|
972
|
+
throw foldError(node, `function "${node.text}" used as a value is not foldable`);
|
|
973
|
+
}
|
|
974
|
+
// chant #1966 — a registered eager-fold lexicon helper (see the
|
|
975
|
+
// CallExpression branch below) is callable, never a bare value:
|
|
976
|
+
// nothing downstream can serialize a function.
|
|
977
|
+
if (typeof external === "function" &&
|
|
978
|
+
intrinsics.some((i) => i.name === node.text && intrinsicCallFoldsEagerly(i))) {
|
|
979
|
+
throw foldError(node, `function "${node.text}" used as a value is not foldable — call it instead`);
|
|
980
|
+
}
|
|
981
|
+
return external;
|
|
982
|
+
}
|
|
983
|
+
// chant #1064 — a bare `process` reference is ALWAYS an ambient
|
|
984
|
+
// environment read (`process.env.X`, `process.argv`, …), never
|
|
985
|
+
// something a future resolution pass could fold: it's Node's global,
|
|
986
|
+
// not a local const or an importable module export. Point at the
|
|
987
|
+
// supported alternative instead of leaving the author to infer the fix
|
|
988
|
+
// from the generic "unresolved identifier" message — see
|
|
989
|
+
// ../build-params.ts/../params.ts.
|
|
990
|
+
if (node.text === "process") {
|
|
991
|
+
throw foldError(node, `ambient "process" read is not foldable — declare a build-time parameter instead ` +
|
|
992
|
+
`(chant.config.ts's buildParams + \`chant build --param name=value\`/\`--params-file\`) and reference ` +
|
|
993
|
+
`it via \`import { params } from "@intentius/chant/params"\`, rather than reading process.env directly`);
|
|
994
|
+
}
|
|
995
|
+
throw foldError(node, `unresolved identifier: ${node.text}`);
|
|
996
|
+
}
|
|
997
|
+
const initializer = consts.get(node.text);
|
|
998
|
+
// chant #1169 — a BARE reference to a same-file `const x = new T(...)` is a
|
|
999
|
+
// reference to THAT resource instance, and the ONE thing it must never
|
|
1000
|
+
// become is a second one. Re-folding the initializer here would do exactly
|
|
1001
|
+
// that now that the `new` branch below constructs: the consumer would get a
|
|
1002
|
+
// duplicate object discovery never registered, whose `AttrRef`s could never
|
|
1003
|
+
// be assigned a logical name ("Cannot serialize AttrRef …: logical name not
|
|
1004
|
+
// set") and whose `Ref` would silently inline instead of referencing. A
|
|
1005
|
+
// crash or wrong output, not drift.
|
|
1006
|
+
//
|
|
1007
|
+
// So `externals` — and ONLY `externals` — answers this one. A caller with a
|
|
1008
|
+
// module graph (../discovery/fold-import.ts) pre-resolves each of this
|
|
1009
|
+
// file's `new`-valued consts to ONE instance, in source order, before any
|
|
1010
|
+
// declarator is folded, and puts it here; every reference in the file then
|
|
1011
|
+
// reads that same object, exactly as running the module top-to-bottom
|
|
1012
|
+
// would. A caller without one (`foldModule`, a unit test) has no way to
|
|
1013
|
+
// construct anything, so the reference stays a rejection and the file falls
|
|
1014
|
+
// back to run.
|
|
1015
|
+
//
|
|
1016
|
+
// `bucket.name` is a different question and keeps its answer regardless: the
|
|
1017
|
+
// property-access branch below consults `consts` first, so a sibling
|
|
1018
|
+
// attribute reference is still the symbolic `{__attrRef}` the serializer
|
|
1019
|
+
// resolves by NAME. Nothing about the existing envelope changes.
|
|
1020
|
+
//
|
|
1021
|
+
// chant #3196 — the same holds for a same-file `const x = tag\`...\``
|
|
1022
|
+
// whose tag returns an entity (a SQL `table`): re-folding the initializer
|
|
1023
|
+
// would call the tag again and build a second entity discovery never
|
|
1024
|
+
// registers. The caller pre-resolves those too; without it the
|
|
1025
|
+
// initializer re-folds as before.
|
|
1026
|
+
//
|
|
1027
|
+
// chant#3325 — and a same-file `const x = Composite({...})` that a
|
|
1028
|
+
// composite call's props name: the caller resolves it on the live spine
|
|
1029
|
+
// and puts the instance here. Without it the call is refused below.
|
|
1030
|
+
if ((ts.isTaggedTemplateExpression(initializer) || ts.isCallExpression(initializer)) &&
|
|
1031
|
+
externals?.has(node.text)) {
|
|
1032
|
+
return externals.get(node.text);
|
|
1033
|
+
}
|
|
1034
|
+
if (ts.isNewExpression(initializer)) {
|
|
1035
|
+
if (externals?.has(node.text))
|
|
1036
|
+
return externals.get(node.text);
|
|
1037
|
+
throw foldError(node, `same-file resource \`${node.text}\` used as a value is not foldable — falls back to run`);
|
|
1038
|
+
}
|
|
1039
|
+
return fold(initializer, consts, intrinsics, externals);
|
|
1040
|
+
}
|
|
1041
|
+
if (ts.isPropertyAccessExpression(node)) {
|
|
1042
|
+
if (ts.isIdentifier(node.expression) && resolvesToResource(consts, node.expression)) {
|
|
1043
|
+
return { __attrRef: { entity: node.expression.text, attribute: node.name.text } };
|
|
1044
|
+
}
|
|
1045
|
+
// chant #1174 — `<Identifier>(...).step`, the composite-consumer idiom
|
|
1046
|
+
// (`Checkout({...}).step`) — see FoldedCompositeStepCall's doc. Checked
|
|
1047
|
+
// here, at the property-access node, rather than inside the
|
|
1048
|
+
// CallExpression branch: a bare `Checkout({...})` with no `.step` still
|
|
1049
|
+
// has no case there and throws exactly as before.
|
|
1050
|
+
if (node.name.text === "step" && isUnclaimedBareCall(node.expression, consts, intrinsics, externals)) {
|
|
1051
|
+
const call = node.expression;
|
|
1052
|
+
const calleeName = call.expression.text;
|
|
1053
|
+
const inside = insideFunctionBody(node, `composite call \`${calleeName}(...).step\``);
|
|
1054
|
+
if (inside)
|
|
1055
|
+
throw inside;
|
|
1056
|
+
return {
|
|
1057
|
+
__compositeStep: calleeName,
|
|
1058
|
+
args: call.arguments.map((arg) => fold(arg, consts, intrinsics, externals)),
|
|
1059
|
+
};
|
|
1060
|
+
}
|
|
1061
|
+
const obj = fold(node.expression, consts, intrinsics, externals);
|
|
1062
|
+
// chant #2328 — see {@link nullishAccessMessage}. An earlier `?.` that
|
|
1063
|
+
// short-circuited carries the whole chain to `undefined`; a `?.` here does
|
|
1064
|
+
// the same for a nullish object; a plain `.` on one is the refusal.
|
|
1065
|
+
if (isChainShortCircuit(obj))
|
|
1066
|
+
return shortCircuited(node);
|
|
1067
|
+
if (obj === null || obj === undefined) {
|
|
1068
|
+
if (node.questionDotToken)
|
|
1069
|
+
return shortCircuited(node);
|
|
1070
|
+
throw foldError(node, nullishAccessMessage(node.name.text, obj));
|
|
1071
|
+
}
|
|
1072
|
+
if (isFoldedResource(obj))
|
|
1073
|
+
return attrRefOnFoldedResource(node, node.name.text);
|
|
1074
|
+
return obj[node.name.text];
|
|
1075
|
+
}
|
|
1076
|
+
if (ts.isElementAccessExpression(node)) {
|
|
1077
|
+
const key = elementKey(node.argumentExpression);
|
|
1078
|
+
if (ts.isIdentifier(node.expression) && resolvesToResource(consts, node.expression)) {
|
|
1079
|
+
return { __attrRef: { entity: node.expression.text, attribute: key } };
|
|
1080
|
+
}
|
|
1081
|
+
const obj = fold(node.expression, consts, intrinsics, externals);
|
|
1082
|
+
// chant #2328 — identical to the property-access branch above; `a?.["k"]`
|
|
1083
|
+
// is the bracketed spelling of the same short-circuit.
|
|
1084
|
+
if (isChainShortCircuit(obj))
|
|
1085
|
+
return shortCircuited(node);
|
|
1086
|
+
if (obj === null || obj === undefined) {
|
|
1087
|
+
if (node.questionDotToken)
|
|
1088
|
+
return shortCircuited(node);
|
|
1089
|
+
throw foldError(node, nullishAccessMessage(key, obj));
|
|
1090
|
+
}
|
|
1091
|
+
if (isFoldedResource(obj))
|
|
1092
|
+
return attrRefOnFoldedResource(node, key);
|
|
1093
|
+
return obj[key];
|
|
1094
|
+
}
|
|
1095
|
+
if (ts.isPrefixUnaryExpression(node)) {
|
|
1096
|
+
if (!SUPPORTED_UNARY_OPERATORS.has(node.operator)) {
|
|
1097
|
+
throw foldError(node, UNSUPPORTED_UNARY_MESSAGE);
|
|
1098
|
+
}
|
|
1099
|
+
const value = fold(node.operand, consts, intrinsics, externals);
|
|
1100
|
+
if (node.operator === ts.SyntaxKind.ExclamationToken)
|
|
1101
|
+
return !value;
|
|
1102
|
+
return -value; // ts.SyntaxKind.MinusToken — the only other supported operator
|
|
1103
|
+
}
|
|
1104
|
+
if (ts.isBinaryExpression(node)) {
|
|
1105
|
+
const opKind = node.operatorToken.kind;
|
|
1106
|
+
const S = ts.SyntaxKind;
|
|
1107
|
+
if (opKind === S.AmpersandAmpersandToken) {
|
|
1108
|
+
const left = fold(node.left, consts, intrinsics, externals);
|
|
1109
|
+
return left ? fold(node.right, consts, intrinsics, externals) : left;
|
|
1110
|
+
}
|
|
1111
|
+
if (opKind === S.BarBarToken) {
|
|
1112
|
+
const left = fold(node.left, consts, intrinsics, externals);
|
|
1113
|
+
return left ? left : fold(node.right, consts, intrinsics, externals);
|
|
1114
|
+
}
|
|
1115
|
+
if (opKind === S.QuestionQuestionToken) {
|
|
1116
|
+
const left = fold(node.left, consts, intrinsics, externals);
|
|
1117
|
+
return left === null || left === undefined ? fold(node.right, consts, intrinsics, externals) : left;
|
|
1118
|
+
}
|
|
1119
|
+
if (!SUPPORTED_BINARY_OPERATORS.has(opKind)) {
|
|
1120
|
+
throw foldError(node, unsupportedBinaryMessage(opKind));
|
|
1121
|
+
}
|
|
1122
|
+
const left = fold(node.left, consts, intrinsics, externals);
|
|
1123
|
+
const right = fold(node.right, consts, intrinsics, externals);
|
|
1124
|
+
switch (opKind) {
|
|
1125
|
+
case S.PlusToken:
|
|
1126
|
+
return left + right;
|
|
1127
|
+
case S.MinusToken:
|
|
1128
|
+
return left - right;
|
|
1129
|
+
case S.AsteriskToken:
|
|
1130
|
+
return left * right;
|
|
1131
|
+
case S.SlashToken:
|
|
1132
|
+
return left / right;
|
|
1133
|
+
case S.EqualsEqualsEqualsToken:
|
|
1134
|
+
return left === right;
|
|
1135
|
+
case S.ExclamationEqualsEqualsToken:
|
|
1136
|
+
return left !== right;
|
|
1137
|
+
case S.GreaterThanToken:
|
|
1138
|
+
return left > right;
|
|
1139
|
+
case S.LessThanToken:
|
|
1140
|
+
return left < right;
|
|
1141
|
+
case S.GreaterThanEqualsToken:
|
|
1142
|
+
return left >= right;
|
|
1143
|
+
case S.LessThanEqualsToken:
|
|
1144
|
+
return left <= right;
|
|
1145
|
+
default:
|
|
1146
|
+
// Unreachable given the SUPPORTED_BINARY_OPERATORS guard above —
|
|
1147
|
+
// kept as a defensive fallback in case that set and this switch
|
|
1148
|
+
// ever fall out of sync.
|
|
1149
|
+
throw foldError(node, unsupportedBinaryMessage(opKind));
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
if (ts.isConditionalExpression(node)) {
|
|
1153
|
+
return fold(node.condition, consts, intrinsics, externals)
|
|
1154
|
+
? fold(node.whenTrue, consts, intrinsics, externals)
|
|
1155
|
+
: fold(node.whenFalse, consts, intrinsics, externals);
|
|
1156
|
+
}
|
|
1157
|
+
if (ts.isNewExpression(node)) {
|
|
1158
|
+
// chant #1169 — a nested `new Type({...})` used as a property VALUE folds
|
|
1159
|
+
// to the SAME {@link FoldedResource} envelope a top-level resource
|
|
1160
|
+
// declaration does, and is constructed for real by the same bridge.
|
|
1161
|
+
//
|
|
1162
|
+
// This used to be an unconditional rejection, and the reason it was is
|
|
1163
|
+
// worth keeping in view: `fold()` alone can only produce the envelope, and
|
|
1164
|
+
// an envelope that reaches serialization is the wrong value — the #1025
|
|
1165
|
+
// differential caught exactly that on gitlab/multi-stage-deploy, where
|
|
1166
|
+
// `new Image({...})` as a job's `image:` must serialize as the constructed
|
|
1167
|
+
// Image's own shape, not as `{__resource, props}`. What changed is not the
|
|
1168
|
+
// envelope's safety but who consumes it: ../discovery/fold-import.ts's
|
|
1169
|
+
// `reviveFoldedValue` now REVIVES a `{__resource}` node into a real
|
|
1170
|
+
// instance, built by the class the file's own `import` names, resolved
|
|
1171
|
+
// through the same provenance-checked machinery that already constructs a
|
|
1172
|
+
// top-level resource (and that #1023's factory interpreter already uses to
|
|
1173
|
+
// construct a nested `new` inside a factory body — the asymmetry that
|
|
1174
|
+
// motivated this change). Nothing symbolic survives into the serializer:
|
|
1175
|
+
// the value the outer constructor receives is the same object the run path
|
|
1176
|
+
// would have handed it, with the same prototype, the same `props`, and the
|
|
1177
|
+
// same `toJSON`/`kind` the serializer's walker dispatches on.
|
|
1178
|
+
//
|
|
1179
|
+
// Only a PLAIN IDENTIFIER constructor is admissible. `new ns.Type(...)`
|
|
1180
|
+
// cannot be resolved to a live class through the file's named imports, so
|
|
1181
|
+
// it stays a rejection rather than folding to an envelope nothing can
|
|
1182
|
+
// revive — the same bare-identifier rule #1023's `checkFactoryExpression`
|
|
1183
|
+
// applies to a body-level construction, and the same one `fold()` applies
|
|
1184
|
+
// to an intrinsic call and an authoring helper.
|
|
1185
|
+
if (!ts.isIdentifier(node.expression)) {
|
|
1186
|
+
throw foldError(node, `nested \`new ${briefNodeText(node.expression)}(...)\` as a value needs a plain imported constructor — falls back to run`);
|
|
1187
|
+
}
|
|
1188
|
+
const inside = insideFunctionBody(node, `\`new ${node.expression.text}(...)\``);
|
|
1189
|
+
if (inside)
|
|
1190
|
+
throw inside;
|
|
1191
|
+
return foldResource(node, consts, intrinsics, externals);
|
|
1192
|
+
}
|
|
1193
|
+
if (ts.isCallExpression(node)) {
|
|
1194
|
+
// chant #1082 — the ONE call shape that folds: a registered chant
|
|
1195
|
+
// authoring helper ({@link FOLDABLE_AUTHORING_HELPERS}), called through a
|
|
1196
|
+
// bare identifier that this file hasn't shadowed with its own `const`.
|
|
1197
|
+
// Nothing is executed here — the call reduces to a symbolic
|
|
1198
|
+
// {@link FoldedHelperCall} envelope, exactly as a registered intrinsic
|
|
1199
|
+
// tagged template reduces to a {@link FoldedIntrinsic} one, and for the
|
|
1200
|
+
// same reason: the real function lives in another module, and resolving
|
|
1201
|
+
// + invoking it is the async bridge's job (../discovery/fold-import.ts's
|
|
1202
|
+
// `reviveFoldedValue`), which also verifies the name is actually bound to
|
|
1203
|
+
// an import of chant's own before invoking anything. Every other call —
|
|
1204
|
+
// a user's function, a method call, a call to something declared in this
|
|
1205
|
+
// file — still has no case and throws, unchanged.
|
|
1206
|
+
if (ts.isIdentifier(node.expression) &&
|
|
1207
|
+
isFoldableHelperName(node.expression.text) &&
|
|
1208
|
+
!consts.has(node.expression.text)) {
|
|
1209
|
+
const inside = insideFunctionBody(node, `authoring helper call \`${node.expression.text}(...)\``);
|
|
1210
|
+
if (inside)
|
|
1211
|
+
throw inside;
|
|
1212
|
+
return {
|
|
1213
|
+
__helper: node.expression.text,
|
|
1214
|
+
args: node.arguments.map((arg) => fold(arg, consts, intrinsics, externals)),
|
|
1215
|
+
};
|
|
1216
|
+
}
|
|
1217
|
+
// chant #1044 — the other call shape that folds: a lexicon intrinsic in
|
|
1218
|
+
// PLAIN-CALL form (`Ref(bucket)`, `Concat("a", b)`), where that lexicon
|
|
1219
|
+
// registered it AND opted its call form in ({@link intrinsicCallFolds},
|
|
1220
|
+
// ../lexicon.ts — default off, never inferred). Reduces to the same
|
|
1221
|
+
// `{__intrinsic}` envelope family the tagged-template form produces, with
|
|
1222
|
+
// positional `args`; nothing is executed here, for the same reason as the
|
|
1223
|
+
// tag form — the real function lives in the lexicon module, and resolving
|
|
1224
|
+
// it through this file's own imports and invoking it is the async
|
|
1225
|
+
// bridge's job (../discovery/fold-import.ts's `reviveFoldedValue`).
|
|
1226
|
+
//
|
|
1227
|
+
// Arguments fold through {@link foldIntrinsicValue}, exactly like a tag's
|
|
1228
|
+
// interpolations: an intrinsic's interior is where a pseudo-parameter
|
|
1229
|
+
// chain (`GetAZs(AWS.Region)`) legitimately appears, and it stays
|
|
1230
|
+
// symbolic rather than rejecting.
|
|
1231
|
+
//
|
|
1232
|
+
// The door does not open any wider than this. A bare-identifier callee
|
|
1233
|
+
// only, so `ns.Ref(...)` and `arr.map(...)` are untouched; the file's own
|
|
1234
|
+
// `const` shadowing wins, so a local `Ref` is not the lexicon's; and a
|
|
1235
|
+
// name absent from the active lexicons' registered set — or registered
|
|
1236
|
+
// without the opt-in — falls straight through to the throw below.
|
|
1237
|
+
if (ts.isIdentifier(node.expression) && !consts.has(node.expression.text)) {
|
|
1238
|
+
const calleeName = node.expression.text;
|
|
1239
|
+
if (intrinsics.some((i) => i.name === calleeName && intrinsicCallFolds(i))) {
|
|
1240
|
+
const inside = insideFunctionBody(node, `intrinsic call \`${calleeName}(...)\``);
|
|
1241
|
+
if (inside)
|
|
1242
|
+
throw inside;
|
|
1243
|
+
return {
|
|
1244
|
+
__intrinsic: calleeName,
|
|
1245
|
+
args: node.arguments.map((arg) => foldIntrinsicValue(arg, consts, intrinsics, externals)),
|
|
1246
|
+
};
|
|
1247
|
+
}
|
|
1248
|
+
}
|
|
1249
|
+
// chant #1373 — the third call shape, and the only open-ended one: a
|
|
1250
|
+
// PROJECT-LOCAL function (declared in this file or imported from a
|
|
1251
|
+
// sibling project file) whose body is itself foldable. fold-import.ts
|
|
1252
|
+
// places a {@link FoldableFunction} marker in `externals` for each such
|
|
1253
|
+
// declaration (a same-file `const f = () => …` is in `consts` too, which
|
|
1254
|
+
// is why this is not gated on `consts` like the two above); the call is
|
|
1255
|
+
// evaluated right here, statically, against the defining module's scope
|
|
1256
|
+
// — see {@link callFoldableFunction}. Checked AFTER the two registered
|
|
1257
|
+
// shapes so a registered name keeps its registered meaning; a package
|
|
1258
|
+
// export never produces a marker, so `node_modules` stays out.
|
|
1259
|
+
if (ts.isIdentifier(node.expression)) {
|
|
1260
|
+
const callee = externals?.get(node.expression.text);
|
|
1261
|
+
if (isFoldableFunction(callee)) {
|
|
1262
|
+
return callFoldableFunction(callee, node, consts, intrinsics, externals);
|
|
1263
|
+
}
|
|
1264
|
+
// chant#2436 — the same shape, reached without a build. A caller that
|
|
1265
|
+
// supplied no `externals` has no module graph and so no markers, and a
|
|
1266
|
+
// same-file call fell through to the throw below even though a build
|
|
1267
|
+
// folds it. Derive the file's own functions and call one.
|
|
1268
|
+
//
|
|
1269
|
+
// Only when `externals` is absent. A caller that passed one is managing
|
|
1270
|
+
// its own bindings (a build, which already put the markers there before
|
|
1271
|
+
// folding anything), and second-guessing it here could bind a name it
|
|
1272
|
+
// deliberately left out. A same-file function only: an imported one needs
|
|
1273
|
+
// module resolution, which this module does not do and will not start.
|
|
1274
|
+
if (externals === undefined) {
|
|
1275
|
+
const local = sameFileFunctions(node, consts)?.get(node.expression.text);
|
|
1276
|
+
if (local)
|
|
1277
|
+
return callFoldableFunction(local, node, consts, intrinsics, local.externals);
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1280
|
+
// chant #1966 — the fourth call shape: a lexicon-package function its
|
|
1281
|
+
// lexicon registered with {@link intrinsicCallFoldsEagerly} (../lexicon.ts),
|
|
1282
|
+
// resolved into `externals` by ../discovery/fold-import.ts's
|
|
1283
|
+
// `resolveActiveLexiconExport` exactly like a plain data export
|
|
1284
|
+
// (`Azure.ResourceGroupLocation`, chant #1063), except callable. Unlike
|
|
1285
|
+
// the intrinsic-call shape above, this one is EVALUATED right here rather
|
|
1286
|
+
// than enveloped: a lexicon's own string-building helper (`matrix("os")`,
|
|
1287
|
+
// github lexicon) is typically embedded directly in a template literal
|
|
1288
|
+
// (`` `${matrix("os")}` ``), which coerces its result via native
|
|
1289
|
+
// `String()` at fold time — an envelope deferred to later revival would
|
|
1290
|
+
// stringify as "[object Object]" there. Evaluating eagerly, with the
|
|
1291
|
+
// folded arguments, produces the real, already-live return value instead
|
|
1292
|
+
// — the same guarantee a live external's own getter execution already
|
|
1293
|
+
// gives {@link fold}'s property-access branch.
|
|
1294
|
+
if (ts.isIdentifier(node.expression) &&
|
|
1295
|
+
!consts.has(node.expression.text) &&
|
|
1296
|
+
intrinsics.some((i) => i.name === node.expression.text && intrinsicCallFoldsEagerly(i))) {
|
|
1297
|
+
const callee = externals?.get(node.expression.text);
|
|
1298
|
+
if (typeof callee !== "function") {
|
|
1299
|
+
throw foldError(node, `"${node.expression.text}" did not resolve to a function — falls back to run`);
|
|
1300
|
+
}
|
|
1301
|
+
const args = node.arguments.map((arg) => fold(arg, consts, intrinsics, externals));
|
|
1302
|
+
return callee(...args);
|
|
1303
|
+
}
|
|
1304
|
+
// chant #1966 — a method call whose RECEIVER is itself foldable: property
|
|
1305
|
+
// access on a live external (`github.actor.toString()`), a call folded by
|
|
1306
|
+
// one of the shapes above (`matrix("os").toString()`), or fold's own
|
|
1307
|
+
// array/object literal (`[...].join(",")`). The method is never checked
|
|
1308
|
+
// by name — only that the receiver is a REAL value (not one of fold's own
|
|
1309
|
+
// symbolic envelopes, see {@link isFoldSymbolicEnvelope}) and that the
|
|
1310
|
+
// named property on it is actually a function. Calling it with the folded
|
|
1311
|
+
// arguments is then no different from what running the file would do:
|
|
1312
|
+
// the receiver is the same real object either way.
|
|
1313
|
+
if (ts.isPropertyAccessExpression(node.expression)) {
|
|
1314
|
+
const methodName = node.expression.name.text;
|
|
1315
|
+
const receiver = fold(node.expression.expression, consts, intrinsics, externals);
|
|
1316
|
+
// chant #2328 — a call is a link of an optional chain like any other:
|
|
1317
|
+
// `a?.b()` and `a?.b.c()` on a nullish `a` are `undefined` in
|
|
1318
|
+
// JavaScript, not a call on nothing. Only a non-optional receiver keeps
|
|
1319
|
+
// the refusal this branch has made since #1966.
|
|
1320
|
+
if (isChainShortCircuit(receiver))
|
|
1321
|
+
return shortCircuited(node);
|
|
1322
|
+
if (receiver === null || receiver === undefined) {
|
|
1323
|
+
if (node.expression.questionDotToken)
|
|
1324
|
+
return shortCircuited(node);
|
|
1325
|
+
throw foldError(node, `cannot call ".${methodName}(...)" on ${String(receiver)}`);
|
|
1326
|
+
}
|
|
1327
|
+
if (isFoldSymbolicEnvelope(receiver)) {
|
|
1328
|
+
throw foldError(node, `method call \`.${methodName}(...)\` on an unresolved value is not foldable — falls back to run`);
|
|
1329
|
+
}
|
|
1330
|
+
const method = receiver[methodName];
|
|
1331
|
+
if (typeof method !== "function") {
|
|
1332
|
+
throw foldError(node, `"${methodName}" is not a callable method on the folded value — falls back to run`);
|
|
1333
|
+
}
|
|
1334
|
+
const args = node.arguments.map((arg) => fold(arg, consts, intrinsics, externals));
|
|
1335
|
+
return method.apply(receiver, args);
|
|
1336
|
+
}
|
|
1337
|
+
throw foldError(node, callExpressionMessage(node));
|
|
1338
|
+
}
|
|
1339
|
+
throw foldError(node, unsupportedExpressionMessage(node));
|
|
1340
|
+
}
|
|
1341
|
+
/**
|
|
1342
|
+
* Fold a resource constructor call to its spec.
|
|
1343
|
+
*
|
|
1344
|
+
* The common `createResource` shape (../runtime.ts) is `new Type({ ...props
|
|
1345
|
+
* })` or `new Type({ ...props }, { ...attributes })` — CFN-style resource
|
|
1346
|
+
* attributes (`DependsOn`, `Condition`, `DeletionPolicy`, …) second — and
|
|
1347
|
+
* that shape reduces to `props` (+ `attributes`) exactly as before.
|
|
1348
|
+
*
|
|
1349
|
+
* chant #1082 — but that is a convention, not a rule every lexicon class
|
|
1350
|
+
* follows. AWS's deploy-time `Parameter` is `(type, props)`
|
|
1351
|
+
* (lexicons/aws/src/parameter.ts): the props object is the SECOND argument
|
|
1352
|
+
* and the first is a plain string. `foldResource` used to require argument 0
|
|
1353
|
+
* to be an object literal, so no `new Parameter(...)` anywhere could ever
|
|
1354
|
+
* fold, whatever surrounded it. The general case now folds every argument in
|
|
1355
|
+
* source order into {@link FoldedResource.args}, which the caller constructs
|
|
1356
|
+
* the entity from verbatim — no positional assumption at all. `props` is
|
|
1357
|
+
* still reported (the first object-literal argument, for callers that read
|
|
1358
|
+
* it) but is a VIEW onto `args`, not the thing constructed from.
|
|
1359
|
+
*/
|
|
1360
|
+
export function foldResource(node, consts, intrinsics = [], externals) {
|
|
1361
|
+
const typeName = node.expression.getText();
|
|
1362
|
+
const args = node.arguments ?? [];
|
|
1363
|
+
const [firstArg, secondArg] = args;
|
|
1364
|
+
const foldArg = (arg) => fold(arg, consts, intrinsics, externals);
|
|
1365
|
+
if (!firstArg) {
|
|
1366
|
+
return { __resource: typeName, props: {} };
|
|
1367
|
+
}
|
|
1368
|
+
// The classic (props) / (props, attributes) shape — reported without an
|
|
1369
|
+
// `args` list so the spec of an ordinary resource is unchanged.
|
|
1370
|
+
if (ts.isObjectLiteralExpression(firstArg)) {
|
|
1371
|
+
const props = foldArg(firstArg);
|
|
1372
|
+
if (args.length === 1) {
|
|
1373
|
+
return { __resource: typeName, props };
|
|
1374
|
+
}
|
|
1375
|
+
if (args.length === 2 && ts.isObjectLiteralExpression(secondArg)) {
|
|
1376
|
+
return { __resource: typeName, props, attributes: foldArg(secondArg) };
|
|
1377
|
+
}
|
|
1378
|
+
}
|
|
1379
|
+
// Anything else: fold every argument positionally. Each one still has to be
|
|
1380
|
+
// in the fold subset on its own terms — a non-foldable argument throws from
|
|
1381
|
+
// `fold()` exactly as a non-foldable prop value does.
|
|
1382
|
+
const folded = args.map(foldArg);
|
|
1383
|
+
const propsIndex = args.findIndex((arg) => ts.isObjectLiteralExpression(arg));
|
|
1384
|
+
const props = (propsIndex === -1 ? {} : folded[propsIndex]);
|
|
1385
|
+
return { __resource: typeName, props, args: folded };
|
|
1386
|
+
}
|
|
1387
|
+
function hasExportModifier(statement) {
|
|
1388
|
+
return statement.modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword) ?? false;
|
|
1389
|
+
}
|
|
1390
|
+
/**
|
|
1391
|
+
* Fold every exported `const X = new Type({...})` resource declaration in a
|
|
1392
|
+
* source file to its spec, with no module execution.
|
|
1393
|
+
*
|
|
1394
|
+
* Non-resource `const` exports (anything whose initializer isn't a `new`
|
|
1395
|
+
* expression) are left out of the result rather than folded or errored —
|
|
1396
|
+
* `new`-less resource forms (composite factory calls) are epic Phase 5
|
|
1397
|
+
* (#1023) and are not attempted here.
|
|
1398
|
+
*
|
|
1399
|
+
* @param intrinsics - Lexicon-registered intrinsic tags, forwarded to
|
|
1400
|
+
* {@link fold} for every resource. See {@link fold}'s `intrinsics` param.
|
|
1401
|
+
*/
|
|
1402
|
+
export function foldModule(source, fileName = "module.ts", intrinsics = []) {
|
|
1403
|
+
const sourceFile = ts.createSourceFile(fileName, source, ts.ScriptTarget.Latest, /* setParentNodes */ true);
|
|
1404
|
+
const consts = collectConsts(sourceFile);
|
|
1405
|
+
const result = {};
|
|
1406
|
+
for (const statement of sourceFile.statements) {
|
|
1407
|
+
if (!ts.isVariableStatement(statement))
|
|
1408
|
+
continue;
|
|
1409
|
+
if (!hasExportModifier(statement))
|
|
1410
|
+
continue;
|
|
1411
|
+
if ((statement.declarationList.flags & ts.NodeFlags.Const) === 0)
|
|
1412
|
+
continue;
|
|
1413
|
+
for (const decl of statement.declarationList.declarations) {
|
|
1414
|
+
if (!ts.isIdentifier(decl.name) || !decl.initializer)
|
|
1415
|
+
continue;
|
|
1416
|
+
if (!ts.isNewExpression(decl.initializer))
|
|
1417
|
+
continue;
|
|
1418
|
+
const name = decl.name.text;
|
|
1419
|
+
try {
|
|
1420
|
+
const spec = foldResource(decl.initializer, consts, intrinsics);
|
|
1421
|
+
result[name] = { ok: true, spec };
|
|
1422
|
+
}
|
|
1423
|
+
catch (err) {
|
|
1424
|
+
if (err instanceof FoldError) {
|
|
1425
|
+
result[name] = { ok: false, error: err.message, ruleId: err.ruleId, line: err.line, column: err.column };
|
|
1426
|
+
}
|
|
1427
|
+
else {
|
|
1428
|
+
throw err;
|
|
1429
|
+
}
|
|
1430
|
+
}
|
|
1431
|
+
}
|
|
1432
|
+
}
|
|
1433
|
+
return result;
|
|
1434
|
+
}
|