@intentius/chant 0.100.0 → 0.102.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/checks.d.ts.map +1 -1
- package/dist/attrref.d.ts.map +1 -1
- package/dist/audit/discover.d.ts.map +1 -1
- package/dist/audit/nginx.d.ts.map +1 -1
- package/dist/audit/prior-art.d.ts +48 -0
- package/dist/audit/prior-art.d.ts.map +1 -1
- package/dist/behaviour-kinds.d.ts.map +1 -1
- package/dist/build.d.ts +6 -0
- package/dist/build.d.ts.map +1 -1
- package/dist/builder.d.ts.map +1 -1
- package/dist/cli/build-options.d.ts +2 -0
- package/dist/cli/build-options.d.ts.map +1 -1
- package/dist/cli/commands/build.d.ts.map +1 -1
- package/dist/cli/commands/carve-emit.d.ts.map +1 -1
- package/dist/cli/commands/check-lexicon.d.ts +16 -0
- package/dist/cli/commands/check-lexicon.d.ts.map +1 -1
- package/dist/cli/commands/import.d.ts +8 -0
- package/dist/cli/commands/import.d.ts.map +1 -1
- package/dist/cli/commands/init-lexicon.d.ts.map +1 -1
- package/dist/cli/commands/init.d.ts +19 -0
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/onboard.d.ts +9 -0
- package/dist/cli/commands/onboard.d.ts.map +1 -1
- package/dist/cli/commands/pinned-upgrade.d.ts +19 -5
- package/dist/cli/commands/pinned-upgrade.d.ts.map +1 -1
- package/dist/cli/handlers/dev.d.ts.map +1 -1
- package/dist/cli/handlers/fan-out.d.ts.map +1 -1
- package/dist/cli/handlers/lifecycle.d.ts.map +1 -1
- package/dist/cli/handlers/misc.d.ts.map +1 -1
- package/dist/cli/handlers/operator.d.ts +9 -0
- package/dist/cli/handlers/operator.d.ts.map +1 -1
- package/dist/cli/handlers/run.d.ts.map +1 -1
- package/dist/cli/lsp/server.d.ts.map +1 -1
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/mcp/server.d.ts.map +1 -1
- package/dist/cli/mcp/tools/build.d.ts.map +1 -1
- package/dist/cli/mcp/tools/composites.d.ts.map +1 -1
- package/dist/cli/mcp/tools/explain.d.ts.map +1 -1
- package/dist/cli/mcp/tools/import.d.ts.map +1 -1
- package/dist/cli/mcp/tools/lint.d.ts.map +1 -1
- package/dist/cli/mcp/tools/scaffold.d.ts.map +1 -1
- package/dist/cli/mcp/tools/search.d.ts.map +1 -1
- package/dist/cli/mcp/workspace-tools.d.ts +9 -1
- package/dist/cli/mcp/workspace-tools.d.ts.map +1 -1
- package/dist/cli/registry.d.ts +33 -2
- package/dist/cli/registry.d.ts.map +1 -1
- package/dist/codegen/fetch.d.ts.map +1 -1
- package/dist/codegen/naming.d.ts.map +1 -1
- package/dist/codegen/pinned-upgrade.d.ts +67 -3
- package/dist/codegen/pinned-upgrade.d.ts.map +1 -1
- package/dist/codegen/registry.d.ts.map +1 -1
- package/dist/components/capability-plugin-loader.d.ts.map +1 -1
- package/dist/components/capability.d.ts.map +1 -1
- package/dist/components/driver.d.ts.map +1 -1
- package/dist/components/fan-out.d.ts.map +1 -1
- package/dist/components/starter-plugin.d.ts.map +1 -1
- package/dist/components/verbs/process-runner.d.ts.map +1 -1
- package/dist/components/verbs/r2-sync.d.ts.map +1 -1
- package/dist/components/verbs/run-agent.d.ts.map +1 -1
- package/dist/components/verbs/sbom-generator.d.ts.map +1 -1
- package/dist/components/verbs/sign.d.ts.map +1 -1
- package/dist/components/verbs/verify.d.ts.map +1 -1
- package/dist/components/verbs/vuln-gate.d.ts.map +1 -1
- package/dist/components/verbs/vuln-scan.d.ts.map +1 -1
- package/dist/components/verbs/wrangler.d.ts.map +1 -1
- package/dist/composite.d.ts.map +1 -1
- package/dist/config.d.ts +30 -7
- package/dist/config.d.ts.map +1 -1
- package/dist/declarable.d.ts +16 -0
- package/dist/declarable.d.ts.map +1 -1
- package/dist/discovery/cache.d.ts.map +1 -1
- package/dist/discovery/fold-import.d.ts +15 -5
- package/dist/discovery/fold-import.d.ts.map +1 -1
- package/dist/discovery/param-deps.d.ts +16 -0
- package/dist/discovery/param-deps.d.ts.map +1 -1
- package/dist/discovery/sandbox/policy-wire.d.ts.map +1 -1
- package/dist/discovery/specifier-resolve.d.ts +37 -0
- package/dist/discovery/specifier-resolve.d.ts.map +1 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/fold/fold.d.ts +3 -1
- package/dist/fold/fold.d.ts.map +1 -1
- package/dist/graph-detail.d.ts.map +1 -1
- package/dist/graph-ir.d.ts.map +1 -1
- package/dist/graph-layout.d.ts.map +1 -1
- package/dist/import/base-parser.d.ts.map +1 -1
- package/dist/import/embedded.d.ts +7 -0
- package/dist/import/embedded.d.ts.map +1 -1
- package/dist/import/parser-options.d.ts +14 -0
- package/dist/import/parser-options.d.ts.map +1 -0
- package/dist/import/parser.d.ts +17 -0
- package/dist/import/parser.d.ts.map +1 -1
- package/dist/kubectl-context.d.ts.map +1 -1
- package/dist/lexicon-output.d.ts.map +1 -1
- package/dist/lexicon-schema.d.ts +3 -3
- package/dist/lexicon.d.ts +78 -3
- package/dist/lexicon.d.ts.map +1 -1
- package/dist/lifecycle/assert-live.d.ts.map +1 -1
- package/dist/lifecycle/gate-ledger.d.ts +15 -0
- package/dist/lifecycle/gate-ledger.d.ts.map +1 -1
- package/dist/lifecycle/git.d.ts.map +1 -1
- package/dist/lifecycle/member-ledger.d.ts.map +1 -1
- package/dist/lifecycle/observe.d.ts.map +1 -1
- package/dist/lifecycle/plan-digest.d.ts +26 -5
- package/dist/lifecycle/plan-digest.d.ts.map +1 -1
- package/dist/lifecycle/plan-ledger.d.ts.map +1 -1
- package/dist/lifecycle/release-ledger.d.ts.map +1 -1
- package/dist/lifecycle/scenario.d.ts.map +1 -1
- package/dist/lifecycle/status.d.ts.map +1 -1
- package/dist/lifecycle/work-lease.d.ts +61 -2
- package/dist/lifecycle/work-lease.d.ts.map +1 -1
- package/dist/lint/config.d.ts +4 -4
- package/dist/lint/engine.d.ts +6 -0
- package/dist/lint/engine.d.ts.map +1 -1
- package/dist/lsp/lexicon-providers.d.ts.map +1 -1
- package/dist/op/activities/activity-contracts.d.ts +12 -11
- package/dist/op/activities/activity-contracts.d.ts.map +1 -1
- package/dist/op/activities/apply.d.ts +79 -9
- package/dist/op/activities/apply.d.ts.map +1 -1
- package/dist/op/activities/decide.d.ts.map +1 -1
- package/dist/op/activities/index.d.ts +1 -1
- package/dist/op/activities/index.d.ts.map +1 -1
- package/dist/op/activities/lexicon-upgrade.d.ts +44 -12
- package/dist/op/activities/lexicon-upgrade.d.ts.map +1 -1
- package/dist/op/activities/propose-upgrade.d.ts +2 -0
- package/dist/op/activities/propose-upgrade.d.ts.map +1 -1
- package/dist/op/activity-contract.d.ts +1 -1
- package/dist/op/activity-failure.d.ts.map +1 -1
- package/dist/op/activity-profiles.d.ts.map +1 -1
- package/dist/op/builders.d.ts.map +1 -1
- package/dist/op/composites/apply-op.d.ts +12 -5
- package/dist/op/composites/apply-op.d.ts.map +1 -1
- package/dist/op/composites/lexicon-upgrade-op.d.ts +22 -6
- package/dist/op/composites/lexicon-upgrade-op.d.ts.map +1 -1
- package/dist/op/decide-backend.d.ts.map +1 -1
- package/dist/op/decide-read-inputs.d.ts.map +1 -1
- package/dist/op/emulator-lifecycle.d.ts +21 -2
- package/dist/op/emulator-lifecycle.d.ts.map +1 -1
- package/dist/op/gate-approval.d.ts +5 -1
- package/dist/op/gate-approval.d.ts.map +1 -1
- package/dist/op/gate-wait.d.ts.map +1 -1
- package/dist/op/gate.d.ts +19 -3
- package/dist/op/gate.d.ts.map +1 -1
- package/dist/op/index.d.ts +3 -1
- package/dist/op/index.d.ts.map +1 -1
- package/dist/op/local-executor.d.ts +6 -0
- package/dist/op/local-executor.d.ts.map +1 -1
- package/dist/op/operator.d.ts.map +1 -1
- package/dist/op/run-context.d.ts +39 -0
- package/dist/op/run-context.d.ts.map +1 -0
- package/dist/op/run-live.d.ts.map +1 -1
- package/dist/op/runtimes/local.d.ts.map +1 -1
- package/dist/op/source-archive.d.ts.map +1 -1
- package/dist/op/steward-beside.d.ts.map +1 -1
- package/dist/op/steward-points.d.ts.map +1 -1
- package/dist/op/steward.d.ts.map +1 -1
- package/dist/op/types.d.ts +8 -3
- package/dist/op/types.d.ts.map +1 -1
- package/dist/op/work-lease-run.d.ts +24 -4
- package/dist/op/work-lease-run.d.ts.map +1 -1
- package/dist/project-root.d.ts.map +1 -1
- package/dist/provenance.d.ts +21 -0
- package/dist/provenance.d.ts.map +1 -1
- package/dist/pseudo-parameter.d.ts.map +1 -1
- package/dist/reconcile.d.ts.map +1 -1
- package/dist/secret-materialization.d.ts.map +1 -1
- package/dist/serializer.d.ts +8 -0
- package/dist/serializer.d.ts.map +1 -1
- package/dist/telemetry-attribution.d.ts +77 -0
- package/dist/telemetry-attribution.d.ts.map +1 -0
- package/dist/terraform/emit-source.d.ts.map +1 -1
- package/dist/terraform/parse.d.ts.map +1 -1
- package/dist/testing.d.ts.map +1 -1
- package/dist/workspace/__fixtures__/contract-repo.d.ts.map +1 -1
- package/dist/workspace/__fixtures__/decide-workspace.d.ts +1 -1
- package/dist/workspace/__fixtures__/decide-workspace.d.ts.map +1 -1
- package/dist/workspace/agent-cli.d.ts +88 -0
- package/dist/workspace/agent-cli.d.ts.map +1 -0
- package/dist/workspace/box-factory.d.ts +73 -0
- package/dist/workspace/box-factory.d.ts.map +1 -0
- package/dist/workspace/changes-cli.d.ts.map +1 -1
- package/dist/workspace/changes.d.ts +8 -1
- package/dist/workspace/changes.d.ts.map +1 -1
- package/dist/workspace/chant-migrations/chud-lexicon-exit.d.ts.map +1 -1
- package/dist/workspace/checks/boxes.d.ts.map +1 -1
- package/dist/workspace/checks/links.d.ts +1 -0
- package/dist/workspace/checks/links.d.ts.map +1 -1
- package/dist/workspace/checks/live.d.ts +40 -0
- package/dist/workspace/checks/live.d.ts.map +1 -0
- package/dist/workspace/checks.d.ts +26 -2
- package/dist/workspace/checks.d.ts.map +1 -1
- package/dist/workspace/compose-graph.d.ts +73 -0
- package/dist/workspace/compose-graph.d.ts.map +1 -1
- package/dist/workspace/conformance/index.d.ts +67 -6
- package/dist/workspace/conformance/index.d.ts.map +1 -1
- package/dist/workspace/conformance/vitest.d.ts +12 -3
- package/dist/workspace/conformance/vitest.d.ts.map +1 -1
- package/dist/workspace/conformance/writer.d.ts +368 -0
- package/dist/workspace/conformance/writer.d.ts.map +1 -0
- package/dist/workspace/decide.d.ts +1 -1
- package/dist/workspace/decide.d.ts.map +1 -1
- package/dist/workspace/declaration.d.ts +119 -0
- package/dist/workspace/declaration.d.ts.map +1 -1
- package/dist/workspace/declaration.schema.json +368 -4
- package/dist/workspace/export-cli.d.ts +12 -0
- package/dist/workspace/export-cli.d.ts.map +1 -0
- package/dist/workspace/export.d.ts +145 -0
- package/dist/workspace/export.d.ts.map +1 -0
- package/dist/workspace/generated-files.d.ts.map +1 -1
- package/dist/workspace/graph-cache.d.ts.map +1 -1
- package/dist/workspace/graph-cli.d.ts +2 -0
- package/dist/workspace/graph-cli.d.ts.map +1 -1
- package/dist/workspace/identity.d.ts +111 -0
- package/dist/workspace/identity.d.ts.map +1 -0
- package/dist/workspace/import.d.ts +73 -0
- package/dist/workspace/import.d.ts.map +1 -0
- package/dist/workspace/intent-cli.d.ts +7 -4
- package/dist/workspace/intent-cli.d.ts.map +1 -1
- package/dist/workspace/intent-record.d.ts +8 -1
- package/dist/workspace/intent-record.d.ts.map +1 -1
- package/dist/workspace/intent.d.ts +149 -5
- package/dist/workspace/intent.d.ts.map +1 -1
- package/dist/workspace/kinds.d.ts +24 -6
- package/dist/workspace/kinds.d.ts.map +1 -1
- package/dist/workspace/lineage-adopt-cli.d.ts +15 -0
- package/dist/workspace/lineage-adopt-cli.d.ts.map +1 -0
- package/dist/workspace/lineage-adopt.d.ts +106 -0
- package/dist/workspace/lineage-adopt.d.ts.map +1 -0
- package/dist/workspace/lineage-check.d.ts +9 -2
- package/dist/workspace/lineage-check.d.ts.map +1 -1
- package/dist/workspace/lineage-cli.d.ts +6 -1
- package/dist/workspace/lineage-cli.d.ts.map +1 -1
- package/dist/workspace/lineage-hash-index.d.ts +110 -0
- package/dist/workspace/lineage-hash-index.d.ts.map +1 -0
- package/dist/workspace/lineage-init.d.ts +10 -0
- package/dist/workspace/lineage-init.d.ts.map +1 -1
- package/dist/workspace/lineage-lock.d.ts +149 -2
- package/dist/workspace/lineage-lock.d.ts.map +1 -1
- package/dist/workspace/lineage-migrations.d.ts +15 -3
- package/dist/workspace/lineage-migrations.d.ts.map +1 -1
- package/dist/workspace/lineage-provenance.d.ts +18 -0
- package/dist/workspace/lineage-provenance.d.ts.map +1 -0
- package/dist/workspace/lineage-upgrade-cli.d.ts +2 -0
- package/dist/workspace/lineage-upgrade-cli.d.ts.map +1 -1
- package/dist/workspace/lineage-upgrade.d.ts +30 -1
- package/dist/workspace/lineage-upgrade.d.ts.map +1 -1
- package/dist/workspace/lineage-versions.d.ts +116 -0
- package/dist/workspace/lineage-versions.d.ts.map +1 -0
- package/dist/workspace/links.d.ts +31 -5
- package/dist/workspace/links.d.ts.map +1 -1
- package/dist/workspace/ls-generated.d.ts +37 -0
- package/dist/workspace/ls-generated.d.ts.map +1 -0
- package/dist/workspace/ls.d.ts +4 -0
- package/dist/workspace/ls.d.ts.map +1 -1
- package/dist/workspace/member-commands.d.ts.map +1 -1
- package/dist/workspace/nested-graph.d.ts +56 -0
- package/dist/workspace/nested-graph.d.ts.map +1 -0
- package/dist/workspace/nesting.d.ts +21 -0
- package/dist/workspace/nesting.d.ts.map +1 -0
- package/dist/workspace/pin-cli.d.ts +10 -0
- package/dist/workspace/pin-cli.d.ts.map +1 -0
- package/dist/workspace/pin-integrity.d.ts +51 -0
- package/dist/workspace/pin-integrity.d.ts.map +1 -0
- package/dist/workspace/points.d.ts.map +1 -1
- package/dist/workspace/principal-classes.d.ts +114 -0
- package/dist/workspace/principal-classes.d.ts.map +1 -0
- package/dist/workspace/reason-codes.d.ts +47 -3
- package/dist/workspace/reason-codes.d.ts.map +1 -1
- package/dist/workspace/record-assets.d.ts.map +1 -1
- package/dist/workspace/record-sessions.d.ts +7 -11
- package/dist/workspace/record-sessions.d.ts.map +1 -1
- package/dist/workspace/records-checkout.d.ts +54 -0
- package/dist/workspace/records-checkout.d.ts.map +1 -0
- package/dist/workspace/records-cli.d.ts +57 -2
- package/dist/workspace/records-cli.d.ts.map +1 -1
- package/dist/workspace/records-close.d.ts +5 -2
- package/dist/workspace/records-close.d.ts.map +1 -1
- package/dist/workspace/records-since.d.ts.map +1 -1
- package/dist/workspace/records-write.d.ts +23 -4
- package/dist/workspace/records-write.d.ts.map +1 -1
- package/dist/workspace/records.d.ts +58 -5
- package/dist/workspace/records.d.ts.map +1 -1
- package/dist/workspace/returns.d.ts +129 -0
- package/dist/workspace/returns.d.ts.map +1 -0
- package/dist/workspace/runs-cli.d.ts +164 -0
- package/dist/workspace/runs-cli.d.ts.map +1 -0
- package/dist/workspace/runs.d.ts +423 -0
- package/dist/workspace/runs.d.ts.map +1 -0
- package/dist/workspace/source-block.d.ts +1 -1
- package/dist/workspace/source-block.d.ts.map +1 -1
- package/dist/workspace/status-gates.d.ts +15 -3
- package/dist/workspace/status-gates.d.ts.map +1 -1
- package/dist/workspace/status.d.ts +10 -0
- package/dist/workspace/status.d.ts.map +1 -1
- package/dist/workspace/symbols.d.ts +52 -0
- package/dist/workspace/symbols.d.ts.map +1 -0
- package/dist/workspace/template-manifest.d.ts +11 -3
- package/dist/workspace/template-manifest.d.ts.map +1 -1
- package/dist/workspace/trailer-joins.d.ts +46 -0
- package/dist/workspace/trailer-joins.d.ts.map +1 -0
- package/dist/workspace/trailers.d.ts +89 -0
- package/dist/workspace/trailers.d.ts.map +1 -0
- package/dist/workspace/trust/attestor.d.ts +8 -0
- package/dist/workspace/trust/attestor.d.ts.map +1 -1
- package/dist/workspace/trust/dsse.d.ts +58 -0
- package/dist/workspace/trust/dsse.d.ts.map +1 -0
- package/dist/workspace/trust/evidence-cli.d.ts +66 -0
- package/dist/workspace/trust/evidence-cli.d.ts.map +1 -0
- package/dist/workspace/trust/evidence.d.ts +93 -0
- package/dist/workspace/trust/evidence.d.ts.map +1 -0
- package/dist/workspace/trust/policy.d.ts +54 -1
- package/dist/workspace/trust/policy.d.ts.map +1 -1
- package/dist/workspace/trust/provenance.d.ts +21 -1
- package/dist/workspace/trust/provenance.d.ts.map +1 -1
- package/dist/workspace/trust/rotation.d.ts +132 -0
- package/dist/workspace/trust/rotation.d.ts.map +1 -0
- package/dist/workspace/trust/seal.d.ts +33 -0
- package/dist/workspace/trust/seal.d.ts.map +1 -1
- package/dist/workspace/trust/signers-cli.d.ts +49 -0
- package/dist/workspace/trust/signers-cli.d.ts.map +1 -0
- package/dist/workspace/trust/ssh-commit.d.ts +12 -0
- package/dist/workspace/trust/ssh-commit.d.ts.map +1 -1
- package/dist/workspace/trust/test-repo.d.ts +13 -0
- package/dist/workspace/trust/test-repo.d.ts.map +1 -1
- package/dist/workspace/trust/verify.d.ts +15 -0
- package/dist/workspace/trust/verify.d.ts.map +1 -1
- package/dist/workspace/work-cli.d.ts +39 -3
- package/dist/workspace/work-cli.d.ts.map +1 -1
- package/dist/workspace/work-evidence.d.ts +1 -1
- package/dist/workspace/work-evidence.d.ts.map +1 -1
- package/dist/workspace/work.d.ts +26 -1
- package/dist/workspace/work.d.ts.map +1 -1
- package/dist/workspace/workspace-principals.schema.json +60 -0
- package/dist/workspace/write-scope.d.ts +259 -0
- package/dist/workspace/write-scope.d.ts.map +1 -0
- package/dist/yaml.d.ts +21 -39
- package/dist/yaml.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/audit/prior-art.ts +15 -0
- package/src/build.ts +8 -0
- package/src/cli/build-options.ts +4 -1
- package/src/cli/commands/__fixtures__/init-lexicon-output/package.json +1 -1
- package/src/cli/commands/build.ts +2 -0
- package/src/cli/commands/carve-emit-state.test.ts +4 -0
- package/src/cli/commands/carve-emit.ts +5 -19
- package/src/cli/commands/check-lexicon.test.ts +62 -1
- package/src/cli/commands/check-lexicon.ts +36 -6
- package/src/cli/commands/import-live.test.ts +87 -1
- package/src/cli/commands/import-parser-options.test.ts +133 -0
- package/src/cli/commands/import.ts +69 -25
- package/src/cli/commands/init-lexicon/templates/project.ts +1 -1
- package/src/cli/commands/init.test.ts +8 -1
- package/src/cli/commands/init.ts +23 -8
- package/src/cli/commands/lint.test.ts +37 -0
- package/src/cli/commands/onboard.test.ts +53 -3
- package/src/cli/commands/onboard.ts +52 -4
- package/src/cli/commands/pinned-upgrade.ts +73 -33
- package/src/cli/handlers/__snapshots__/build-member.test.ts.snap +2 -2
- package/src/cli/handlers/components.ts +2 -2
- package/src/cli/handlers/dev.ts +8 -6
- package/src/cli/handlers/fan-out.test.ts +6 -6
- package/src/cli/handlers/fan-out.ts +2 -1
- package/src/cli/handlers/graph.test.ts +42 -0
- package/src/cli/handlers/graph.ts +22 -0
- package/src/cli/handlers/lifecycle.test.ts +67 -0
- package/src/cli/handlers/lifecycle.ts +6 -5
- package/src/cli/handlers/misc.ts +2 -0
- package/src/cli/handlers/operator.ts +88 -4
- package/src/cli/handlers/run.test.ts +111 -0
- package/src/cli/handlers/run.ts +85 -24
- package/src/cli/handlers/scenario.ts +2 -2
- package/src/cli/main.test.ts +33 -0
- package/src/cli/main.ts +168 -17
- package/src/cli/mcp/workspace-tools.test.ts +5 -2
- package/src/cli/mcp/workspace-tools.ts +62 -4
- package/src/cli/registry.ts +33 -2
- package/src/cli/serve-mcp-workspace.test.ts +1 -1
- package/src/codegen/pinned-upgrade-multi.test.ts +157 -0
- package/src/codegen/pinned-upgrade-tags.test.ts +112 -0
- package/src/codegen/pinned-upgrade.test.ts +104 -0
- package/src/codegen/pinned-upgrade.ts +250 -56
- package/src/codegen/release-wiring.test.ts +5 -1
- package/src/codegen/testdata/postgres-tags.json +242 -0
- package/src/components/fan-out-output.test.ts +1 -1
- package/src/components/fan-out.test.ts +1 -1
- package/src/components/promote.test.ts +1 -1
- package/src/config.test.ts +21 -0
- package/src/config.ts +27 -0
- package/src/content-digest.test.ts +2 -2
- package/src/declarable.test.ts +21 -0
- package/src/declarable.ts +19 -0
- package/src/discovery/fold-composite.test.ts +41 -5
- package/src/discovery/fold-import.test.ts +129 -0
- package/src/discovery/fold-import.ts +643 -131
- package/src/discovery/fold-package-composite.test.ts +264 -0
- package/src/discovery/fold-specifiers.test.ts +191 -0
- package/src/discovery/param-deps.test.ts +66 -1
- package/src/discovery/param-deps.ts +45 -0
- package/src/discovery/specifier-resolve.ts +344 -0
- package/src/fold/fold.test.ts +39 -1
- package/src/fold/fold.ts +83 -9
- package/src/fold-provenance.test.ts +140 -0
- package/src/graph-ir.test.ts +83 -0
- package/src/graph-ir.ts +29 -0
- package/src/import/embedded.test.ts +20 -0
- package/src/import/embedded.ts +13 -0
- package/src/import/parser-options.ts +46 -0
- package/src/import/parser.ts +20 -0
- package/src/lexicon.ts +79 -3
- package/src/lifecycle/gate-ledger.test.ts +14 -0
- package/src/lifecycle/gate-ledger.ts +18 -1
- package/src/lifecycle/observe.test.ts +18 -0
- package/src/lifecycle/observe.ts +6 -4
- package/src/lifecycle/plan-digest.test.ts +54 -3
- package/src/lifecycle/plan-digest.ts +38 -8
- package/src/lifecycle/snapshot.ts +2 -2
- package/src/lifecycle/work-lease.test.ts +1 -1
- package/src/lifecycle/work-lease.ts +93 -2
- package/src/lint/engine.test.ts +55 -0
- package/src/lint/engine.ts +30 -4
- package/src/lint/output-docs.test.ts +59 -56
- package/src/op/activities/activity-contracts.ts +1 -0
- package/src/op/activities/apply.test.ts +189 -5
- package/src/op/activities/apply.ts +230 -8
- package/src/op/activities/index.ts +3 -0
- package/src/op/activities/lexicon-upgrade.test.ts +160 -6
- package/src/op/activities/lexicon-upgrade.ts +154 -51
- package/src/op/activities/propose-upgrade.ts +8 -5
- package/src/op/composites/apply-op.ts +12 -5
- package/src/op/composites/composites.test.ts +30 -3
- package/src/op/composites/lexicon-upgrade-op.test.ts +7 -2
- package/src/op/composites/lexicon-upgrade-op.ts +29 -8
- package/src/op/emulator-lifecycle.test.ts +23 -0
- package/src/op/emulator-lifecycle.ts +52 -14
- package/src/op/gate-approval.test.ts +91 -0
- package/src/op/gate-approval.ts +5 -1
- package/src/op/gate.ts +34 -8
- package/src/op/index.ts +3 -1
- package/src/op/local-executor.test.ts +15 -0
- package/src/op/local-executor.ts +40 -12
- package/src/op/local-output.ts +1 -1
- package/src/op/operator.ts +4 -0
- package/src/op/run-context.test.ts +141 -0
- package/src/op/run-context.ts +51 -0
- package/src/op/runtimes/local.test.ts +14 -0
- package/src/op/runtimes/local.ts +2 -0
- package/src/op/steward-beside.ts +2 -0
- package/src/op/types.ts +8 -3
- package/src/op/work-lease-run.test.ts +47 -0
- package/src/op/work-lease-run.ts +73 -11
- package/src/provenance.ts +35 -0
- package/src/serializer.ts +9 -0
- package/src/telemetry-attribution.test.ts +91 -0
- package/src/telemetry-attribution.ts +145 -0
- package/src/workspace/__fixtures__/studio-template-84c8b21.json +1 -1
- package/src/workspace/agent-cli.ts +138 -0
- package/src/workspace/agent.schema.json +378 -0
- package/src/workspace/behold-kinds.test.ts +1 -1
- package/src/workspace/box-factory.test.ts +320 -0
- package/src/workspace/box-factory.ts +103 -0
- package/src/workspace/changes-cli.ts +5 -0
- package/src/workspace/changes.schema.json +171 -1
- package/src/workspace/changes.ts +61 -4
- package/src/workspace/check-live.test.ts +192 -0
- package/src/workspace/check.schema.json +64 -0
- package/src/workspace/checks/boxes.test.ts +2 -0
- package/src/workspace/checks/links.ts +23 -2
- package/src/workspace/checks/live.ts +113 -0
- package/src/workspace/checks.test.ts +2 -2
- package/src/workspace/checks.ts +49 -8
- package/src/workspace/compose-graph.test.ts +47 -0
- package/src/workspace/compose-graph.ts +127 -3
- package/src/workspace/conformance/__fixture__/decisions/decision.kind.mjs +7 -1
- package/src/workspace/conformance/__fixture__/decisions/decision.schema.json +5 -0
- package/src/workspace/conformance/__writer_fixture__/answers/answer.kind.mjs +27 -0
- package/src/workspace/conformance/__writer_fixture__/answers/answer.schema.json +95 -0
- package/src/workspace/conformance/__writer_fixture__/decisions/points.json +132 -0
- package/src/workspace/conformance/__writer_fixture__/sessions/session.kind.mjs +48 -0
- package/src/workspace/conformance/__writer_fixture__/sessions/session.schema.json +108 -0
- package/src/workspace/conformance/__writer_fixture__/work/W-001-the-writer-suite-works-this-item.md +25 -0
- package/src/workspace/conformance/__writer_fixture__/work/work.kind.mjs +60 -0
- package/src/workspace/conformance/__writer_fixture__/work/work.schema.json +578 -0
- package/src/workspace/conformance/conformance.e2e.test.ts +35 -3
- package/src/workspace/conformance/index.mjs +30 -3
- package/src/workspace/conformance/index.ts +103 -15
- package/src/workspace/conformance/vitest.ts +44 -2
- package/src/workspace/conformance/writer-conformance.e2e.test.ts +131 -0
- package/src/workspace/conformance/writer.test.ts +156 -0
- package/src/workspace/conformance/writer.ts +880 -0
- package/src/workspace/decide.ts +7 -1
- package/src/workspace/declaration.schema.json +368 -4
- package/src/workspace/declaration.ts +270 -1
- package/src/workspace/declared-kinds.test.ts +33 -0
- package/src/workspace/evidence.schema.json +279 -0
- package/src/workspace/export-cli.ts +180 -0
- package/src/workspace/export-import.test.ts +282 -0
- package/src/workspace/export.ts +486 -0
- package/src/workspace/graph-cli.ts +51 -2
- package/src/workspace/graph-contract.test.ts +89 -4
- package/src/workspace/graph.schema.json +453 -1
- package/src/workspace/identity.test.ts +196 -0
- package/src/workspace/identity.ts +186 -0
- package/src/workspace/import.ts +325 -0
- package/src/workspace/intent-cli.ts +64 -10
- package/src/workspace/intent-record.schema.json +208 -0
- package/src/workspace/intent-record.ts +35 -1
- package/src/workspace/intent-why.test.ts +274 -0
- package/src/workspace/intent.schema.json +718 -7
- package/src/workspace/intent.test.ts +11 -2
- package/src/workspace/intent.ts +495 -32
- package/src/workspace/kinds.test.ts +5 -5
- package/src/workspace/kinds.ts +62 -33
- package/src/workspace/lineage-adopt-cli.ts +103 -0
- package/src/workspace/lineage-adopt.test.ts +552 -0
- package/src/workspace/lineage-adopt.ts +452 -0
- package/src/workspace/lineage-check.ts +26 -5
- package/src/workspace/lineage-cli.ts +12 -2
- package/src/workspace/lineage-hash-index.ts +305 -0
- package/src/workspace/lineage-init.test.ts +9 -0
- package/src/workspace/lineage-init.ts +29 -9
- package/src/workspace/lineage-lock.ts +54 -0
- package/src/workspace/lineage-migrations.test.ts +27 -0
- package/src/workspace/lineage-migrations.ts +44 -14
- package/src/workspace/lineage-provenance.ts +40 -0
- package/src/workspace/lineage-upgrade-cli.ts +9 -5
- package/src/workspace/lineage-upgrade.test.ts +92 -1
- package/src/workspace/lineage-upgrade.ts +111 -16
- package/src/workspace/lineage-versions.ts +348 -0
- package/src/workspace/links.test.ts +121 -2
- package/src/workspace/links.ts +97 -6
- package/src/workspace/ls-contract.test.ts +84 -1
- package/src/workspace/ls-generated.ts +111 -0
- package/src/workspace/ls.schema.json +19 -0
- package/src/workspace/ls.ts +8 -1
- package/src/workspace/member-commands.ts +3 -1
- package/src/workspace/nested-graph.test.ts +176 -0
- package/src/workspace/nested-graph.ts +169 -0
- package/src/workspace/nesting.ts +37 -0
- package/src/workspace/pin-cli.test.ts +71 -0
- package/src/workspace/pin-cli.ts +57 -0
- package/src/workspace/pin-integrity.test.ts +121 -0
- package/src/workspace/pin-integrity.ts +104 -0
- package/src/workspace/points-write.schema.json +2 -0
- package/src/workspace/principal-classes.test.ts +175 -0
- package/src/workspace/principal-classes.ts +307 -0
- package/src/workspace/read-contract.test.ts +24 -0
- package/src/workspace/reason-codes.test.ts +20 -2
- package/src/workspace/reason-codes.ts +53 -3
- package/src/workspace/record-sessions.ts +12 -14
- package/src/workspace/records-amend.schema.json +6 -0
- package/src/workspace/records-checkout.ts +106 -0
- package/src/workspace/records-cli.ts +195 -22
- package/src/workspace/records-close.schema.json +7 -2
- package/src/workspace/records-close.ts +10 -2
- package/src/workspace/records-formats.test.ts +13 -5
- package/src/workspace/records-new.schema.json +6 -0
- package/src/workspace/records-review.schema.json +6 -0
- package/src/workspace/records-sessions.test.ts +23 -6
- package/src/workspace/records-uncommitted.test.ts +171 -0
- package/src/workspace/records-write.test.ts +65 -8
- package/src/workspace/records-write.ts +92 -6
- package/src/workspace/records.schema.json +127 -4
- package/src/workspace/records.ts +123 -5
- package/src/workspace/returns.ts +328 -0
- package/src/workspace/runs-cli.ts +381 -0
- package/src/workspace/runs-write.schema.json +583 -0
- package/src/workspace/runs.schema.json +810 -0
- package/src/workspace/runs.test.ts +242 -0
- package/src/workspace/runs.ts +709 -0
- package/src/workspace/signers.schema.json +206 -0
- package/src/workspace/status-contract.test.ts +5 -0
- package/src/workspace/status-gates.ts +24 -9
- package/src/workspace/status.schema.json +127 -2
- package/src/workspace/status.ts +21 -1
- package/src/workspace/symbols.ts +180 -0
- package/src/workspace/template-manifest.ts +22 -4
- package/src/workspace/trailer-joins.test.ts +171 -0
- package/src/workspace/trailer-joins.ts +82 -0
- package/src/workspace/trailers.ts +148 -0
- package/src/workspace/trust/attestor.ts +15 -0
- package/src/workspace/trust/dsse.ts +134 -0
- package/src/workspace/trust/evidence-cli.ts +195 -0
- package/src/workspace/trust/evidence.test.ts +241 -0
- package/src/workspace/trust/evidence.ts +207 -0
- package/src/workspace/trust/policy.ts +110 -3
- package/src/workspace/trust/provenance.ts +41 -4
- package/src/workspace/trust/record-seal.test.ts +1 -1
- package/src/workspace/trust/rotation.test.ts +258 -0
- package/src/workspace/trust/rotation.ts +336 -0
- package/src/workspace/trust/seal.ts +63 -1
- package/src/workspace/trust/signers-cli.ts +178 -0
- package/src/workspace/trust/ssh-commit.ts +53 -4
- package/src/workspace/trust/test-repo.ts +18 -0
- package/src/workspace/trust/trust.test.ts +8 -2
- package/src/workspace/trust/verify-cli.ts +1 -0
- package/src/workspace/trust/verify.ts +22 -0
- package/src/workspace/work-cli.e2e.test.ts +28 -1
- package/src/workspace/work-cli.ts +133 -8
- package/src/workspace/work-evidence.schema.json +6 -0
- package/src/workspace/work-history.schema.json +73 -1
- package/src/workspace/work-history.test.ts +48 -5
- package/src/workspace/work-kind-fields.test.ts +154 -0
- package/src/workspace/work-lease.schema.json +14 -1
- package/src/workspace/work.ts +82 -0
- package/src/workspace/workspace-principals.schema.json +60 -0
- package/src/workspace/write-scope.test.ts +466 -0
- package/src/workspace/write-scope.ts +573 -0
- package/src/yaml.test.ts +111 -1
- package/src/yaml.ts +141 -549
|
@@ -106,6 +106,36 @@ export async function coverageReportCheck(plugin: LexiconPlugin | undefined): Pr
|
|
|
106
106
|
};
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
+
/**
|
|
110
|
+
* #3104 — how many composites a lexicon ships.
|
|
111
|
+
*
|
|
112
|
+
* This counted every `.ts` file in `src/composites/` except `index.ts`, so
|
|
113
|
+
* `catalog.ts`, `catalog.test.ts`, `composites.test.ts` and helper modules all
|
|
114
|
+
* counted: otel reported "4 composite(s)" for `NodeAgent` alone. The same rule
|
|
115
|
+
* as #1342 applies: a capability is what the plugin exposes, and a lexicon
|
|
116
|
+
* with composites exposes them through `composites()`, the catalog generated
|
|
117
|
+
* from its real exports (#2662). Ask that when it is there. Only a lexicon
|
|
118
|
+
* without it falls back to the files, and then not to tests, the catalog, the
|
|
119
|
+
* barrel or helper modules.
|
|
120
|
+
*/
|
|
121
|
+
export function countComposites(
|
|
122
|
+
plugin: LexiconPlugin | undefined,
|
|
123
|
+
dir: string,
|
|
124
|
+
): { count: number; detail: string } {
|
|
125
|
+
if (registers(plugin, "composites")) {
|
|
126
|
+
const { items, error } = safeList(plugin!.composites!.bind(plugin));
|
|
127
|
+
if (error !== undefined) return { count: 0, detail: `composites() threw: ${error}` };
|
|
128
|
+
const names = new Set(items.map((e) => e.name));
|
|
129
|
+
return { count: names.size, detail: `${names.size} composite(s) in composites()` };
|
|
130
|
+
}
|
|
131
|
+
const files = listTsFiles(join(dir, "src/composites"), ["index.ts", "catalog.ts", "helpers.ts", "shared.ts"])
|
|
132
|
+
.filter((f) => !f.endsWith(".test.ts") && !f.endsWith(".d.ts") && !f.endsWith("-helpers.ts"));
|
|
133
|
+
return {
|
|
134
|
+
count: files.length,
|
|
135
|
+
detail: `${files.length} composite file(s) in src/composites/; the plugin has no composites()`,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
109
139
|
/**
|
|
110
140
|
* #2535 — a lexicon that supplies member kinds publishes them as data at a
|
|
111
141
|
* `./workspace-kinds` subpath (ws-031). The file must be JSON, validate as
|
|
@@ -551,12 +581,12 @@ export async function checkLexicon(dir: string): Promise<CheckResult> {
|
|
|
551
581
|
: "reads no config namespace of its own",
|
|
552
582
|
});
|
|
553
583
|
|
|
554
|
-
const
|
|
584
|
+
const composites = countComposites(plugin, dir);
|
|
555
585
|
items.push({
|
|
556
|
-
name: "At least 1 composite
|
|
586
|
+
name: "At least 1 composite",
|
|
557
587
|
tier: 2,
|
|
558
|
-
pass:
|
|
559
|
-
detail:
|
|
588
|
+
pass: composites.count > 0,
|
|
589
|
+
detail: composites.detail,
|
|
560
590
|
});
|
|
561
591
|
|
|
562
592
|
items.push({
|
|
@@ -678,8 +708,8 @@ export async function checkLexicon(dir: string): Promise<CheckResult> {
|
|
|
678
708
|
items.push({
|
|
679
709
|
name: "At least 5 composites",
|
|
680
710
|
tier: 3,
|
|
681
|
-
pass:
|
|
682
|
-
detail:
|
|
711
|
+
pass: composites.count >= 5,
|
|
712
|
+
detail: composites.detail,
|
|
683
713
|
});
|
|
684
714
|
|
|
685
715
|
const hasActions = existsSync(join(dir, "src/actions")) &&
|
|
@@ -6,7 +6,8 @@ import { join } from "node:path";
|
|
|
6
6
|
import { tmpdir } from "node:os";
|
|
7
7
|
import type { LexiconPlugin, ExportedTemplate, ResourceSelector } from "../../lexicon";
|
|
8
8
|
import type { TypeScriptGenerator } from "../../import/generator";
|
|
9
|
-
import type { TemplateIR } from "../../import/parser";
|
|
9
|
+
import type { TemplateIR, ParseContext } from "../../import/parser";
|
|
10
|
+
import type { EmbeddedContentImporter } from "../../import/embedded";
|
|
10
11
|
|
|
11
12
|
const generator: TypeScriptGenerator = {
|
|
12
13
|
generate(ir: TemplateIR) {
|
|
@@ -105,6 +106,24 @@ describe("liveImportFromPlugins (#114)", () => {
|
|
|
105
106
|
expect(result.error).toContain("live export");
|
|
106
107
|
});
|
|
107
108
|
|
|
109
|
+
test("warnings an exporter returns reach the result (#3336)", async () => {
|
|
110
|
+
const withWarnings: ExportedTemplate = { ...sampleIR, warnings: ["bucket is kept by Terraform; left out"] };
|
|
111
|
+
const result = await liveImportFromPlugins([fakeExporter("fake", withWarnings)], {
|
|
112
|
+
environment: "prod",
|
|
113
|
+
output: outputDir,
|
|
114
|
+
force: true,
|
|
115
|
+
});
|
|
116
|
+
expect(result.success).toBe(true);
|
|
117
|
+
expect(result.warnings).toContain("bucket is kept by Terraform; left out");
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
test("warnings from an export with no resources are kept on the error result (#3336)", async () => {
|
|
121
|
+
const empty = fakeExporter("fake", { resources: [], parameters: [], warnings: ["everything is kept by Prisma"] });
|
|
122
|
+
const result = await liveImportFromPlugins([empty], { environment: "prod", output: outputDir });
|
|
123
|
+
expect(result.success).toBe(false);
|
|
124
|
+
expect(result.warnings).toContain("everything is kept by Prisma");
|
|
125
|
+
});
|
|
126
|
+
|
|
108
127
|
test("--lexicon narrows to the named exporter", async () => {
|
|
109
128
|
const result = await liveImportFromPlugins(
|
|
110
129
|
[fakeExporter("a", sampleIR), fakeExporter("b", sampleIR)],
|
|
@@ -151,4 +170,71 @@ describe("liveImportFromPlugins (#114)", () => {
|
|
|
151
170
|
expect(result.success).toBe(true);
|
|
152
171
|
expect(seenStack).toBe("loom-backend");
|
|
153
172
|
});
|
|
173
|
+
|
|
174
|
+
// #2995: an export with `reparse` goes through the same embedded-content
|
|
175
|
+
// delegation as file import.
|
|
176
|
+
describe("embedded content (#2995)", () => {
|
|
177
|
+
const configText = "service:\n pipelines: {}\n";
|
|
178
|
+
|
|
179
|
+
function hostExporter(): LexiconPlugin {
|
|
180
|
+
const parse = (context?: ParseContext): TemplateIR => {
|
|
181
|
+
const ref = context?.embedded?.resolve({
|
|
182
|
+
host: "fake",
|
|
183
|
+
hostType: "Fake::ConfigMap",
|
|
184
|
+
location: "ConfigMap cfg data[\"config.yaml\"]",
|
|
185
|
+
directory: "cfg",
|
|
186
|
+
text: configText,
|
|
187
|
+
expectedOwner: { lexicon: "owner", what: "an owner config" },
|
|
188
|
+
});
|
|
189
|
+
return {
|
|
190
|
+
resources: [{ logicalId: "cfg", type: "Fake::ConfigMap", properties: { data: ref ?? configText } }],
|
|
191
|
+
parameters: [],
|
|
192
|
+
};
|
|
193
|
+
};
|
|
194
|
+
return {
|
|
195
|
+
...fakeExporter("fake", { resources: [], parameters: [] }),
|
|
196
|
+
async exportResources(): Promise<ExportedTemplate> {
|
|
197
|
+
return { ...parse(), reparse: (context) => parse(context) };
|
|
198
|
+
},
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const importer: EmbeddedContentImporter = {
|
|
203
|
+
what: "an owner config",
|
|
204
|
+
matches: (c) => typeof c.document === "object" && c.document !== null && "service" in c.document,
|
|
205
|
+
import: () => ({
|
|
206
|
+
files: [{ path: "config.ts", content: "export const config = {};\n" }],
|
|
207
|
+
value: { bindings: [{ from: "config.ts", name: "config" }], shape: "single" },
|
|
208
|
+
}),
|
|
209
|
+
};
|
|
210
|
+
const owner: LexiconPlugin = {
|
|
211
|
+
name: "owner",
|
|
212
|
+
serializer: {} as never,
|
|
213
|
+
generate: async () => {},
|
|
214
|
+
validate: async () => {},
|
|
215
|
+
coverage: async () => {},
|
|
216
|
+
package: async () => {},
|
|
217
|
+
embeddedImporters: () => [importer],
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
test("a loaded owner imports the content and its modules are written beside the host's", async () => {
|
|
221
|
+
const result = await liveImportFromPlugins([hostExporter(), owner], { environment: "prod", output: outputDir, force: true });
|
|
222
|
+
expect(result.success).toBe(true);
|
|
223
|
+
expect(result.warnings).toEqual([]);
|
|
224
|
+
expect(result.generatedFiles).toEqual(["main.ts", "cfg/config.ts"]);
|
|
225
|
+
const main = await readFile(join(outputDir, "main.ts"), "utf-8");
|
|
226
|
+
expect(main).toContain('"$embedded"');
|
|
227
|
+
expect(main).toContain('"from":"cfg/config.ts"');
|
|
228
|
+
expect(await readFile(join(outputDir, "cfg/config.ts"), "utf-8")).toContain("export const config");
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
test("with no owner the content is kept as read, with a warning", async () => {
|
|
232
|
+
const result = await liveImportFromPlugins([hostExporter()], { environment: "prod", output: outputDir, force: true });
|
|
233
|
+
expect(result.success).toBe(true);
|
|
234
|
+
expect(result.generatedFiles).toEqual(["main.ts"]);
|
|
235
|
+
expect(result.warnings.join("\n")).toContain("no installed lexicon imports it");
|
|
236
|
+
const main = await readFile(join(outputDir, "main.ts"), "utf-8");
|
|
237
|
+
expect(main).toContain(JSON.stringify(configText));
|
|
238
|
+
});
|
|
239
|
+
});
|
|
154
240
|
});
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { describe, test, expect, beforeEach, afterEach, vi } from "vitest";
|
|
2
|
+
import { mkdir, rm, writeFile } from "node:fs/promises";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
5
|
+
import type { LexiconPlugin } from "../../lexicon";
|
|
6
|
+
import type { ParserOptions } from "../../import/parser";
|
|
7
|
+
import { resolveParserOptions } from "../../import/parser-options";
|
|
8
|
+
import { parseArgs } from "../main";
|
|
9
|
+
import { importCommand, importFromContent } from "./import";
|
|
10
|
+
|
|
11
|
+
const { seen, withOptions, withoutOptions } = vi.hoisted(() => {
|
|
12
|
+
const seen: unknown[] = [];
|
|
13
|
+
const parser = {
|
|
14
|
+
parse: () => ({ resources: [], parameters: [], warnings: ["parsed"] }),
|
|
15
|
+
};
|
|
16
|
+
const generator = { generate: () => [{ path: "x.ts", content: "export {};\n" }] };
|
|
17
|
+
const withOptions = {
|
|
18
|
+
name: "with-options",
|
|
19
|
+
detectTemplate: (d: unknown) => typeof d === "object" && d !== null && "marker" in d,
|
|
20
|
+
parserOptions: () => [
|
|
21
|
+
{ name: "flag", type: "boolean", description: "a switch" },
|
|
22
|
+
{ name: "level", type: "number", description: "a number" },
|
|
23
|
+
{ name: "label", type: "string", description: "a string" },
|
|
24
|
+
],
|
|
25
|
+
templateParser: (options?: ParserOptions) => {
|
|
26
|
+
seen.push(options);
|
|
27
|
+
return parser;
|
|
28
|
+
},
|
|
29
|
+
templateGenerator: () => generator,
|
|
30
|
+
} as unknown as LexiconPlugin;
|
|
31
|
+
const withoutOptions = {
|
|
32
|
+
name: "without-options",
|
|
33
|
+
templateParser: () => parser,
|
|
34
|
+
templateGenerator: () => generator,
|
|
35
|
+
} as unknown as LexiconPlugin;
|
|
36
|
+
return { seen, withOptions, withoutOptions };
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
vi.mock("../plugins", () => ({
|
|
40
|
+
resolveProjectLexicons: async () => ["with-options"],
|
|
41
|
+
loadPlugins: async (names: string[]) => names.map((n) => (n === "without-options" ? withoutOptions : withOptions)),
|
|
42
|
+
}));
|
|
43
|
+
|
|
44
|
+
describe("resolveParserOptions (#2994)", () => {
|
|
45
|
+
const specs = withOptions as Pick<LexiconPlugin, "name" | "parserOptions">;
|
|
46
|
+
|
|
47
|
+
test("no entries is an empty record", () => {
|
|
48
|
+
expect(resolveParserOptions(specs, undefined)).toEqual({ options: {} });
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test("converts to the declared types; a bare boolean is true", () => {
|
|
52
|
+
expect(resolveParserOptions(specs, ["flag", "level=3", "label=a=b"])).toEqual({
|
|
53
|
+
options: { flag: true, level: 3, label: "a=b" },
|
|
54
|
+
});
|
|
55
|
+
expect(resolveParserOptions(specs, ["flag=false"])).toEqual({ options: { flag: false } });
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test("refuses an unknown name and lists what the lexicon accepts", () => {
|
|
59
|
+
const r = resolveParserOptions(specs, ["nope"]);
|
|
60
|
+
expect(r).toMatchObject({ error: expect.stringContaining('Unknown parser option "nope" for lexicon "with-options"') });
|
|
61
|
+
expect((r as { error: string }).error).toContain("flag (boolean): a switch");
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test("a lexicon with no options says so", () => {
|
|
65
|
+
const r = resolveParserOptions({ name: "plain" }, ["x"]);
|
|
66
|
+
expect((r as { error: string }).error).toBe('Unknown parser option "x" for lexicon "plain"; lexicon "plain" declares no parser options.');
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test("refuses a bad value", () => {
|
|
70
|
+
expect(resolveParserOptions(specs, ["flag=maybe"])).toHaveProperty("error");
|
|
71
|
+
expect(resolveParserOptions(specs, ["level=abc"])).toHaveProperty("error");
|
|
72
|
+
expect(resolveParserOptions(specs, ["level"])).toHaveProperty("error");
|
|
73
|
+
expect(resolveParserOptions(specs, ["label"])).toHaveProperty("error");
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
describe("chant import --parser-option (#2994)", () => {
|
|
78
|
+
let dir: string;
|
|
79
|
+
let templatePath: string;
|
|
80
|
+
|
|
81
|
+
beforeEach(async () => {
|
|
82
|
+
seen.length = 0;
|
|
83
|
+
dir = join(tmpdir(), `chant-import-parser-options-${Date.now()}-${Math.random()}`);
|
|
84
|
+
await mkdir(dir, { recursive: true });
|
|
85
|
+
templatePath = join(dir, "t.json");
|
|
86
|
+
await writeFile(templatePath, JSON.stringify({ marker: true }));
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
afterEach(async () => {
|
|
90
|
+
await rm(dir, { recursive: true, force: true });
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
test("the flag is parsed, repeatable", () => {
|
|
94
|
+
const args = parseArgs(["import", "t.json", "--lexicon", "x", "--parser-option", "a", "--parser-option", "b=1"]);
|
|
95
|
+
expect(args.parserOption).toEqual(["a", "b=1"]);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
test("--lexicon: the parser receives the typed options", async () => {
|
|
99
|
+
const result = await importCommand({
|
|
100
|
+
templatePath, output: join(dir, "out"), lexicon: "with-options", parserOptions: ["flag", "level=2"],
|
|
101
|
+
});
|
|
102
|
+
expect(result.success).toBe(true);
|
|
103
|
+
expect(seen).toEqual([{ flag: true, level: 2 }]);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
test("detection: the options go to the detected lexicon", async () => {
|
|
107
|
+
const result = await importCommand({ templatePath, output: join(dir, "out"), parserOptions: ["label=x"] });
|
|
108
|
+
expect(result.success).toBe(true);
|
|
109
|
+
expect(seen).toEqual([{ label: "x" }]);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
test("no options: the parser gets an empty record", async () => {
|
|
113
|
+
await importCommand({ templatePath, output: join(dir, "out"), lexicon: "with-options" });
|
|
114
|
+
expect(seen).toEqual([{}]);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
test("an unknown option is refused before parsing", async () => {
|
|
118
|
+
const result = await importCommand({
|
|
119
|
+
templatePath, output: join(dir, "out"), lexicon: "with-options", parserOptions: ["bogus"],
|
|
120
|
+
});
|
|
121
|
+
expect(result.success).toBe(false);
|
|
122
|
+
expect(result.error).toContain('Unknown parser option "bogus"');
|
|
123
|
+
expect(seen).toEqual([]);
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
test("content import refuses an option on a lexicon that declares none", async () => {
|
|
127
|
+
const result = await importFromContent({
|
|
128
|
+
content: "{}", lexicon: "without-options", output: join(dir, "out"), parserOptions: ["x"],
|
|
129
|
+
});
|
|
130
|
+
expect(result.success).toBe(false);
|
|
131
|
+
expect(result.error).toContain('lexicon "without-options" declares no parser options');
|
|
132
|
+
});
|
|
133
|
+
});
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, writeFileSync, readFileSync, readdirSync } from "fs";
|
|
2
2
|
import { join, resolve, basename, dirname } from "path";
|
|
3
3
|
import { formatSuccess, formatWarning, formatError } from "../format";
|
|
4
|
-
import type { TemplateIR, ResourceIR, ParameterIR,
|
|
4
|
+
import type { TemplateIR, ResourceIR, ParameterIR, ParseContext } from "../../import/parser";
|
|
5
5
|
import type { GeneratedFile, TypeScriptGenerator } from "../../import/generator";
|
|
6
6
|
import { listInstalledLexicons, loadPlugin, loadPlugins, resolveProjectLexicons } from "../plugins";
|
|
7
|
-
import type { LexiconPlugin, ResourceSelector } from "../../lexicon";
|
|
7
|
+
import type { ExportedTemplate, LexiconPlugin, ResourceSelector } from "../../lexicon";
|
|
8
8
|
import { parseYAMLDocument, splitYAMLDocuments } from "../../yaml";
|
|
9
9
|
import { importLexiconPackage } from "../../lexicon-module";
|
|
10
|
+
import { resolveParserOptions } from "../../import/parser-options";
|
|
10
11
|
import { EmbeddedImports, type EmbeddedContent, type RegisteredEmbeddedImporter } from "../../import/embedded";
|
|
11
12
|
|
|
12
13
|
/**
|
|
@@ -24,6 +25,12 @@ export interface ImportOptions {
|
|
|
24
25
|
* JSON/YAML check: the raw content goes straight to that plugin's parser.
|
|
25
26
|
*/
|
|
26
27
|
lexicon?: string;
|
|
28
|
+
/**
|
|
29
|
+
* `--parser-option` entries (`key` or `key=value`) for the lexicon's parser
|
|
30
|
+
* (#2994). Checked against the lexicon's `parserOptions()`; an unknown name
|
|
31
|
+
* fails the import before anything is parsed.
|
|
32
|
+
*/
|
|
33
|
+
parserOptions?: string[];
|
|
27
34
|
}
|
|
28
35
|
|
|
29
36
|
/**
|
|
@@ -345,6 +352,7 @@ export async function importCommand(options: ImportOptions): Promise<ImportResul
|
|
|
345
352
|
lexicon: options.lexicon,
|
|
346
353
|
output: options.output,
|
|
347
354
|
force: options.force,
|
|
355
|
+
parserOptions: options.parserOptions,
|
|
348
356
|
});
|
|
349
357
|
}
|
|
350
358
|
|
|
@@ -383,7 +391,7 @@ export async function importCommand(options: ImportOptions): Promise<ImportResul
|
|
|
383
391
|
);
|
|
384
392
|
}
|
|
385
393
|
|
|
386
|
-
const result = await parseAndWrite(plugin, content, outputDir, options.force, warnings, generatedFiles, plugin.name, projectDir);
|
|
394
|
+
const result = await parseAndWrite(plugin, content, outputDir, options.force, warnings, generatedFiles, plugin.name, projectDir, options.parserOptions);
|
|
387
395
|
return { ...result, detected: true };
|
|
388
396
|
}
|
|
389
397
|
|
|
@@ -402,6 +410,8 @@ export interface ContentImportOptions {
|
|
|
402
410
|
lexicon: string;
|
|
403
411
|
output?: string;
|
|
404
412
|
force?: boolean;
|
|
413
|
+
/** `--parser-option` entries for the lexicon's parser (#2994); see {@link ImportOptions.parserOptions}. */
|
|
414
|
+
parserOptions?: string[];
|
|
405
415
|
}
|
|
406
416
|
|
|
407
417
|
export async function importFromContent(options: ContentImportOptions): Promise<ImportResult> {
|
|
@@ -422,19 +432,20 @@ export async function importFromContent(options: ContentImportOptions): Promise<
|
|
|
422
432
|
return { success: false, generatedFiles: [], warnings: [], error: `Lexicon "${options.lexicon}" not available.` };
|
|
423
433
|
}
|
|
424
434
|
const projectDir = resolve(options.output ? dirname(options.output) : ".");
|
|
425
|
-
return parseAndWrite(plugin, options.content, outputDir, options.force, [], [], plugin.name, projectDir);
|
|
435
|
+
return parseAndWrite(plugin, options.content, outputDir, options.force, [], [], plugin.name, projectDir, options.parserOptions);
|
|
426
436
|
}
|
|
427
437
|
|
|
428
438
|
/**
|
|
429
439
|
* The importers for the content a host's parser offered (#2962): those of the
|
|
430
|
-
* project's lexicons, and of each installed
|
|
431
|
-
* recognizes one of the offered documents
|
|
440
|
+
* plugins already loaded, of the project's lexicons, and of each installed
|
|
441
|
+
* lexicon whose `detectTemplate` recognizes one of the offered documents
|
|
442
|
+
* (#2995 adds the loaded ones). The recognizing is done with the
|
|
432
443
|
* lexicon's light `/detect` module, so a lexicon is loaded in full only when
|
|
433
444
|
* it may own something; one that fails to load is skipped.
|
|
434
445
|
*/
|
|
435
446
|
async function embeddedImportersFor(
|
|
436
447
|
offered: readonly EmbeddedContent[],
|
|
437
|
-
|
|
448
|
+
loaded: readonly LexiconPlugin[],
|
|
438
449
|
projectDir: string,
|
|
439
450
|
): Promise<RegisteredEmbeddedImporter[]> {
|
|
440
451
|
const documents = offered.map((c) => c.document).filter((d) => typeof d === "object" && d !== null);
|
|
@@ -446,7 +457,8 @@ async function embeddedImportersFor(
|
|
|
446
457
|
} catch {
|
|
447
458
|
projectNames = [];
|
|
448
459
|
}
|
|
449
|
-
|
|
460
|
+
// Plugins already loaded (the host, or live import's exporters) are asked too.
|
|
461
|
+
const candidates: string[] = [...new Set([...loaded.map((p) => p.name), ...projectNames])];
|
|
450
462
|
for (const name of listInstalledLexicons(projectDir)) {
|
|
451
463
|
if (candidates.includes(name)) continue;
|
|
452
464
|
try {
|
|
@@ -471,7 +483,7 @@ async function embeddedImportersFor(
|
|
|
471
483
|
for (const name of candidates) {
|
|
472
484
|
let plugin: LexiconPlugin;
|
|
473
485
|
try {
|
|
474
|
-
plugin =
|
|
486
|
+
plugin = loaded.find((p) => p.name === name) ?? (await loadPlugin(name));
|
|
475
487
|
} catch {
|
|
476
488
|
continue;
|
|
477
489
|
}
|
|
@@ -488,22 +500,24 @@ async function embeddedImportersFor(
|
|
|
488
500
|
|
|
489
501
|
/**
|
|
490
502
|
* Parse, resolving embedded content (#2962). A first parse with a probe
|
|
491
|
-
* collects what the
|
|
492
|
-
* importers are loaded and
|
|
493
|
-
*
|
|
503
|
+
* collects what the parsers offer; when they offer anything, the owners'
|
|
504
|
+
* importers are loaded and each is parsed again with them, through one
|
|
505
|
+
* resolver so their directories stay distinct. A parse is a template
|
|
506
|
+
* parser over a file's content, or an export's `reparse` (#2995). Parsers
|
|
507
|
+
* that offer nothing are parsed once, and nothing is loaded. `loaded` are
|
|
508
|
+
* plugins already loaded, reused when one of them owns content.
|
|
494
509
|
*/
|
|
495
510
|
async function parseWithEmbedded(
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
content: string,
|
|
511
|
+
parses: ReadonlyArray<(context: ParseContext) => TemplateIR>,
|
|
512
|
+
loaded: readonly LexiconPlugin[],
|
|
499
513
|
projectDir: string,
|
|
500
|
-
): Promise<{
|
|
514
|
+
): Promise<{ irs: TemplateIR[]; embedded?: EmbeddedImports }> {
|
|
501
515
|
const probe = new EmbeddedImports([], { quiet: true });
|
|
502
|
-
const
|
|
503
|
-
if (probe.offered.length === 0) return {
|
|
504
|
-
const importers = await embeddedImportersFor(probe.offered,
|
|
516
|
+
const irs = parses.map((parse) => parse({ embedded: probe }));
|
|
517
|
+
if (probe.offered.length === 0) return { irs };
|
|
518
|
+
const importers = await embeddedImportersFor(probe.offered, loaded, projectDir);
|
|
505
519
|
const embedded = new EmbeddedImports(importers);
|
|
506
|
-
return {
|
|
520
|
+
return { irs: parses.map((parse) => parse({ embedded })), embedded };
|
|
507
521
|
}
|
|
508
522
|
|
|
509
523
|
/** The shared tail of every template import: parse → generate → write. */
|
|
@@ -516,6 +530,7 @@ async function parseAndWrite(
|
|
|
516
530
|
generatedFiles: string[],
|
|
517
531
|
lexicon: string,
|
|
518
532
|
projectDir: string,
|
|
533
|
+
parserOptionEntries?: readonly string[],
|
|
519
534
|
): Promise<ImportResult> {
|
|
520
535
|
// A lexicon can recognize a template (detectTemplate) without being able to
|
|
521
536
|
// import it (grafana had no parser until #2945). Every path funnels through here, so
|
|
@@ -530,12 +545,19 @@ async function parseAndWrite(
|
|
|
530
545
|
};
|
|
531
546
|
}
|
|
532
547
|
|
|
548
|
+
const resolved = resolveParserOptions(plugin, parserOptionEntries);
|
|
549
|
+
if ("error" in resolved) {
|
|
550
|
+
return { success: false, generatedFiles: [], warnings: [], error: resolved.error, lexicon: plugin.name };
|
|
551
|
+
}
|
|
552
|
+
|
|
533
553
|
// Parse template
|
|
534
554
|
let ir: TemplateIR;
|
|
535
555
|
let embedded: EmbeddedImports | undefined;
|
|
536
556
|
try {
|
|
537
|
-
const parser = plugin.templateParser();
|
|
538
|
-
|
|
557
|
+
const parser = plugin.templateParser(resolved.options);
|
|
558
|
+
let irs: TemplateIR[];
|
|
559
|
+
({ irs, embedded } = await parseWithEmbedded([(context) => parser.parse(content, context)], [plugin], projectDir));
|
|
560
|
+
ir = irs[0];
|
|
539
561
|
} catch (err) {
|
|
540
562
|
return {
|
|
541
563
|
success: false,
|
|
@@ -701,6 +723,7 @@ export async function liveImportFromPlugins(
|
|
|
701
723
|
options: LiveImportOptions,
|
|
702
724
|
): Promise<ImportResult> {
|
|
703
725
|
const outputDir = resolve(options.output ?? "./infra/");
|
|
726
|
+
const projectDir = resolve(options.output ? dirname(options.output) : ".");
|
|
704
727
|
const warnings: string[] = [];
|
|
705
728
|
|
|
706
729
|
let exporters = plugins.filter((p) => p.exportResources && p.templateGenerator);
|
|
@@ -720,10 +743,10 @@ export async function liveImportFromPlugins(
|
|
|
720
743
|
}
|
|
721
744
|
|
|
722
745
|
// Collect IR from every exporter, tagging which lexicon produced output.
|
|
723
|
-
|
|
746
|
+
let irParts: ExportedTemplate[] = [];
|
|
724
747
|
let generatorLexicon: LexiconPlugin | undefined;
|
|
725
748
|
for (const plugin of exporters) {
|
|
726
|
-
let ir:
|
|
749
|
+
let ir: ExportedTemplate;
|
|
727
750
|
try {
|
|
728
751
|
ir = await plugin.exportResources!({
|
|
729
752
|
environment: options.environment,
|
|
@@ -736,6 +759,8 @@ export async function liveImportFromPlugins(
|
|
|
736
759
|
warnings.push(`${plugin.name}: live export failed — ${err instanceof Error ? err.message : String(err)}`);
|
|
737
760
|
continue;
|
|
738
761
|
}
|
|
762
|
+
// What the exporter left out or could not carry (#3336).
|
|
763
|
+
if (ir.warnings) warnings.push(...ir.warnings);
|
|
739
764
|
if (ir.resources.length === 0) continue;
|
|
740
765
|
irParts.push(ir);
|
|
741
766
|
generatorLexicon ??= plugin;
|
|
@@ -754,6 +779,23 @@ export async function liveImportFromPlugins(
|
|
|
754
779
|
warnings.push("Multiple lexicons exported resources; generated with the first. Use --lexicon to target one.");
|
|
755
780
|
}
|
|
756
781
|
|
|
782
|
+
// Content embedded in exported resources goes to the lexicon that owns it,
|
|
783
|
+
// as in file import (#2995). An export without `reparse` keeps it as read.
|
|
784
|
+
let embedded: EmbeddedImports | undefined;
|
|
785
|
+
if (irParts.some((part) => part.reparse)) {
|
|
786
|
+
try {
|
|
787
|
+
const parses = irParts.map((part) => part.reparse ?? (() => part));
|
|
788
|
+
let irs: TemplateIR[];
|
|
789
|
+
({ irs, embedded } = await parseWithEmbedded(parses, plugins, projectDir));
|
|
790
|
+
irParts = irs;
|
|
791
|
+
} catch (err) {
|
|
792
|
+
warnings.push(
|
|
793
|
+
`Embedded content is kept as written, because resolving it failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
794
|
+
);
|
|
795
|
+
}
|
|
796
|
+
if (embedded) warnings.push(...embedded.warnings);
|
|
797
|
+
}
|
|
798
|
+
|
|
757
799
|
const ir = mergeIR(irParts);
|
|
758
800
|
const generator = generatorLexicon.templateGenerator!();
|
|
759
801
|
|
|
@@ -761,8 +803,10 @@ export async function liveImportFromPlugins(
|
|
|
761
803
|
mkdirSync(outputDir, { recursive: true });
|
|
762
804
|
}
|
|
763
805
|
|
|
764
|
-
const { files, warnings: layoutWarnings } = generateOrganizedFiles(ir, generator);
|
|
806
|
+
const { files: hostFiles, warnings: layoutWarnings } = generateOrganizedFiles(ir, generator);
|
|
765
807
|
warnings.push(...layoutWarnings);
|
|
808
|
+
// The owners' modules for embedded content, each in a directory of its own.
|
|
809
|
+
const files = [...hostFiles, ...(embedded?.files ?? [])];
|
|
766
810
|
const generatedFiles: string[] = [];
|
|
767
811
|
for (const file of files) {
|
|
768
812
|
const filePath = join(outputDir, file.path);
|
|
@@ -37,7 +37,7 @@ export function generatePackageJson(name: string, names: { packageName: string }
|
|
|
37
37
|
// (the `workspace:` protocol is rejected outside a workspace).
|
|
38
38
|
"@intentius/chant": "*",
|
|
39
39
|
"tsc-alias": "^1.8.17",
|
|
40
|
-
typescript: "^5.9.3",
|
|
40
|
+
typescript: "^5.9.3 || ^7.0.0",
|
|
41
41
|
},
|
|
42
42
|
};
|
|
43
43
|
|
|
@@ -87,7 +87,9 @@ describe("initCommand", () => {
|
|
|
87
87
|
|
|
88
88
|
expect(pkg.dependencies["@intentius/chant"]).toBeDefined();
|
|
89
89
|
expect(pkg.dependencies["@intentius/chant-lexicon-aws"]).toBeDefined();
|
|
90
|
-
|
|
90
|
+
// #3089: the project's TypeScript admits 7, and @types/node backs `types: ["node"]`.
|
|
91
|
+
expect(pkg.devDependencies["typescript"]).toBe("^5.9.3 || ^7.0.0");
|
|
92
|
+
expect(pkg.devDependencies["@types/node"]).toBeDefined();
|
|
91
93
|
expect(pkg.scripts.build).toBe("chant build src --lexicon aws");
|
|
92
94
|
expect(pkg.scripts.dev).toBe("chant build src --lexicon aws --watch");
|
|
93
95
|
expect(pkg.scripts.lint).toBe("chant lint src");
|
|
@@ -115,6 +117,11 @@ describe("initCommand", () => {
|
|
|
115
117
|
expect(tsconfig.compilerOptions.rootDir).toBe("./src");
|
|
116
118
|
expect(tsconfig.include).toContain("src");
|
|
117
119
|
expect(tsconfig.compilerOptions.paths).toBeUndefined();
|
|
120
|
+
// #3089: bundler resolution accepts the extensionless `./config` imports
|
|
121
|
+
// the templates use; NodeNext rejects them (TS2835).
|
|
122
|
+
expect(tsconfig.compilerOptions.module).toBe("esnext");
|
|
123
|
+
expect(tsconfig.compilerOptions.moduleResolution).toBe("bundler");
|
|
124
|
+
expect(tsconfig.compilerOptions.types).toEqual(["node"]);
|
|
118
125
|
});
|
|
119
126
|
});
|
|
120
127
|
|
package/src/cli/commands/init.ts
CHANGED
|
@@ -62,6 +62,16 @@ export interface InitResult {
|
|
|
62
62
|
lexiconModule?: string;
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
+
/**
|
|
66
|
+
* The devDependencies a scaffolded project gets, from `chant init` and from
|
|
67
|
+
* `chant carve` (#3233). The project's TypeScript is for its editor and `tsc`
|
|
68
|
+
* only; chant parses with its own copy, so any 5.9+ or 7 release works (#3089).
|
|
69
|
+
*/
|
|
70
|
+
export const SCAFFOLD_DEV_DEPENDENCIES = {
|
|
71
|
+
"@types/node": "^24.0.0",
|
|
72
|
+
typescript: "^5.9.3 || ^7.0.0",
|
|
73
|
+
} as const;
|
|
74
|
+
|
|
65
75
|
/**
|
|
66
76
|
* Generate package.json content
|
|
67
77
|
*/
|
|
@@ -88,23 +98,28 @@ function generatePackageJson(
|
|
|
88
98
|
...extraScripts,
|
|
89
99
|
},
|
|
90
100
|
dependencies,
|
|
91
|
-
devDependencies: {
|
|
92
|
-
typescript: "^5.0.0",
|
|
93
|
-
},
|
|
101
|
+
devDependencies: { ...SCAFFOLD_DEV_DEPENDENCIES },
|
|
94
102
|
};
|
|
95
103
|
|
|
96
104
|
return JSON.stringify(pkg, null, 2);
|
|
97
105
|
}
|
|
98
106
|
|
|
99
107
|
/**
|
|
100
|
-
* Generate tsconfig.json content
|
|
108
|
+
* Generate tsconfig.json content.
|
|
109
|
+
*
|
|
110
|
+
* `bundler` resolution, because chant resolves a project's imports the way tsx
|
|
111
|
+
* and fold do: `./config` with no extension. NodeNext rejects that form
|
|
112
|
+
* (TS2835), and its suggested `./config.js` makes fold fall back to running the
|
|
113
|
+
* file (#3089). `types` names node because TypeScript 6 and later no longer load
|
|
114
|
+
* every `@types` package by default.
|
|
101
115
|
*/
|
|
102
|
-
function generateTsConfig(
|
|
116
|
+
export function generateTsConfig(): string {
|
|
103
117
|
const config = {
|
|
104
118
|
compilerOptions: {
|
|
105
119
|
target: "ES2022",
|
|
106
|
-
module: "
|
|
107
|
-
moduleResolution: "
|
|
120
|
+
module: "esnext",
|
|
121
|
+
moduleResolution: "bundler",
|
|
122
|
+
types: ["node"],
|
|
108
123
|
strict: true,
|
|
109
124
|
esModuleInterop: true,
|
|
110
125
|
skipLibCheck: true,
|
|
@@ -307,7 +322,7 @@ export async function initCommand(options: InitOptions): Promise<InitResult> {
|
|
|
307
322
|
// Generate tsconfig.json
|
|
308
323
|
writeIfNotExists(
|
|
309
324
|
join(targetDir, "tsconfig.json"),
|
|
310
|
-
generateTsConfig(
|
|
325
|
+
generateTsConfig(),
|
|
311
326
|
"tsconfig.json",
|
|
312
327
|
createdFiles,
|
|
313
328
|
warnings,
|
|
@@ -281,6 +281,43 @@ export const b = new Bucket({ config: { y: 2 } });
|
|
|
281
281
|
expect(result.diagnostics.some(d => d.ruleId === "COR001")).toBe(true);
|
|
282
282
|
expect(result.diagnostics.filter(d => d.ruleId === "COR001")).toHaveLength(2);
|
|
283
283
|
});
|
|
284
|
+
|
|
285
|
+
// #2511: a project-local rule that throws is an error, never a clean pass.
|
|
286
|
+
test("a project-local rule that throws fails the lint and names the rule, file and message", async () => {
|
|
287
|
+
await mkdir(join(testDir, ".chant", "rules"), { recursive: true });
|
|
288
|
+
await writeFile(
|
|
289
|
+
join(testDir, ".chant", "rules", "local.ts"),
|
|
290
|
+
`
|
|
291
|
+
export const boom = {
|
|
292
|
+
id: "LOCAL_BOOM",
|
|
293
|
+
severity: "warning",
|
|
294
|
+
category: "correctness",
|
|
295
|
+
check() { throw new Error("cannot read sibling file"); },
|
|
296
|
+
};
|
|
297
|
+
export const fine = {
|
|
298
|
+
id: "LOCAL_FINE",
|
|
299
|
+
severity: "warning",
|
|
300
|
+
category: "correctness",
|
|
301
|
+
check(ctx) {
|
|
302
|
+
return [{ file: ctx.filePath, line: 1, column: 1, ruleId: "LOCAL_FINE", severity: "warning", message: "fine ran" }];
|
|
303
|
+
},
|
|
304
|
+
};
|
|
305
|
+
`,
|
|
306
|
+
);
|
|
307
|
+
const file = join(testDir, "clean.ts");
|
|
308
|
+
await writeFile(file, `// chant-disable\nexport const config = { a: 1 };\n`);
|
|
309
|
+
|
|
310
|
+
const result = await lintCommand({ path: testDir, format: "stylish" });
|
|
311
|
+
|
|
312
|
+
expect(result.success).toBe(false);
|
|
313
|
+
const threw = result.diagnostics.filter((d) => d.ruleId === "LOCAL_BOOM");
|
|
314
|
+
expect(threw).toHaveLength(1);
|
|
315
|
+
expect(threw[0].severity).toBe("error");
|
|
316
|
+
expect(threw[0].file).toBe(file);
|
|
317
|
+
expect(threw[0].message).toContain("LOCAL_BOOM");
|
|
318
|
+
expect(threw[0].message).toContain(file);
|
|
319
|
+
expect(threw[0].message).toContain("cannot read sibling file");
|
|
320
|
+
});
|
|
284
321
|
});
|
|
285
322
|
|
|
286
323
|
describe("isLintRule", () => {
|