@intentius/chant 0.101.0 → 0.104.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/core.d.ts +2 -0
- package/dist/audit/core.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/builder.d.ts.map +1 -1
- package/dist/change-set.d.ts +232 -0
- package/dist/change-set.d.ts.map +1 -0
- package/dist/cli/commands/audit.d.ts +7 -0
- package/dist/cli/commands/audit.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/build.d.ts.map +1 -1
- package/dist/cli/handlers/change-set.d.ts +11 -0
- package/dist/cli/handlers/change-set.d.ts.map +1 -0
- package/dist/cli/handlers/dev.d.ts.map +1 -1
- package/dist/cli/handlers/fan-out.d.ts +33 -0
- 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 +16 -0
- package/dist/cli/handlers/operator.d.ts.map +1 -1
- package/dist/cli/handlers/pr.d.ts +31 -0
- package/dist/cli/handlers/pr.d.ts.map +1 -0
- 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/op-tools.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 +4 -3
- package/dist/cli/mcp/workspace-tools.d.ts.map +1 -1
- package/dist/cli/registry.d.ts +74 -3
- 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/auto-release.d.ts +16 -0
- package/dist/components/auto-release.d.ts.map +1 -1
- package/dist/components/capability-plugin-loader.d.ts.map +1 -1
- package/dist/components/capability.d.ts +53 -0
- package/dist/components/capability.d.ts.map +1 -1
- package/dist/components/changed-files.d.ts +31 -0
- package/dist/components/changed-files.d.ts.map +1 -0
- package/dist/components/cli-support.d.ts +9 -1
- package/dist/components/cli-support.d.ts.map +1 -1
- package/dist/components/component.d.ts +24 -0
- package/dist/components/component.d.ts.map +1 -1
- package/dist/components/deploy-units.d.ts.map +1 -1
- package/dist/components/driver.d.ts +13 -0
- package/dist/components/driver.d.ts.map +1 -1
- package/dist/components/fan-out-output.d.ts +6 -0
- package/dist/components/fan-out-output.d.ts.map +1 -1
- package/dist/components/fan-out-record.d.ts +41 -0
- package/dist/components/fan-out-record.d.ts.map +1 -0
- package/dist/components/fan-out-run.d.ts +65 -0
- package/dist/components/fan-out-run.d.ts.map +1 -1
- package/dist/components/fan-out-support.d.ts +2 -0
- package/dist/components/fan-out-support.d.ts.map +1 -1
- package/dist/components/fan-out.d.ts +6 -0
- package/dist/components/fan-out.d.ts.map +1 -1
- package/dist/components/gated-wave-pipeline.d.ts +50 -0
- package/dist/components/gated-wave-pipeline.d.ts.map +1 -0
- package/dist/components/index.d.ts +1 -1
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/layers.d.ts +25 -0
- package/dist/components/layers.d.ts.map +1 -0
- package/dist/components/pr-pipeline.d.ts +61 -0
- package/dist/components/pr-pipeline.d.ts.map +1 -0
- package/dist/components/pr-run.d.ts +119 -0
- package/dist/components/pr-run.d.ts.map +1 -0
- package/dist/components/promote.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/shell.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/components/wave-plan.d.ts +49 -0
- package/dist/components/wave-plan.d.ts.map +1 -0
- package/dist/composite.d.ts.map +1 -1
- package/dist/config.d.ts +19 -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/gated-waves.d.ts +147 -0
- package/dist/gated-waves.d.ts.map +1 -0
- 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/index.d.ts +1 -0
- package/dist/index.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 +103 -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 +22 -0
- package/dist/lifecycle/gate-ledger.d.ts.map +1 -1
- package/dist/lifecycle/git.d.ts +46 -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-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 +8 -8
- package/dist/lint/engine.d.ts +6 -0
- package/dist/lint/engine.d.ts.map +1 -1
- package/dist/lint/post-synth.d.ts +18 -0
- package/dist/lint/post-synth.d.ts.map +1 -1
- package/dist/lsp/lexicon-providers.d.ts.map +1 -1
- package/dist/op/activities/activity-contracts.d.ts +137 -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/change-set.d.ts +62 -0
- package/dist/op/activities/change-set.d.ts.map +1 -0
- package/dist/op/activities/decide.d.ts +2 -0
- package/dist/op/activities/decide.d.ts.map +1 -1
- package/dist/op/activities/factory.d.ts +137 -0
- package/dist/op/activities/factory.d.ts.map +1 -0
- package/dist/op/activities/index.d.ts +5 -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/activity-contract.d.ts +1 -1
- package/dist/op/activity-contract.d.ts.map +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 +11 -0
- 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 +5 -1
- package/dist/op/decide-backend.d.ts.map +1 -1
- package/dist/op/decide-read-inputs.d.ts +4 -2
- 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/factory.d.ts +83 -0
- package/dist/op/factory.d.ts.map +1 -0
- 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 +6 -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/op-ir.d.ts +2 -0
- package/dist/op/op-ir.d.ts.map +1 -1
- package/dist/op/op-verb-class.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 +16 -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/plan-summary.d.ts +207 -0
- package/dist/plan-summary.d.ts.map +1 -0
- package/dist/pr-forge.d.ts +105 -0
- package/dist/pr-forge.d.ts.map +1 -0
- package/dist/pr-loop.d.ts +178 -0
- package/dist/pr-loop.d.ts.map +1 -0
- 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/telemetry-attribution.d.ts +31 -0
- package/dist/telemetry-attribution.d.ts.map +1 -1
- package/dist/terraform/emit-source.d.ts.map +1 -1
- package/dist/terraform/hcl2json.d.ts +45 -0
- package/dist/terraform/hcl2json.d.ts.map +1 -0
- package/dist/terraform/parse.d.ts +4 -40
- 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 +5 -0
- package/dist/workspace/agent-cli.d.ts.map +1 -1
- package/dist/workspace/box-cli.d.ts +12 -0
- package/dist/workspace/box-cli.d.ts.map +1 -0
- package/dist/workspace/box-factory.d.ts +97 -0
- package/dist/workspace/box-factory.d.ts.map +1 -0
- package/dist/workspace/box-listing.d.ts +85 -0
- package/dist/workspace/box-listing.d.ts.map +1 -0
- package/dist/workspace/box-publish.d.ts +147 -0
- package/dist/workspace/box-publish.d.ts.map +1 -0
- package/dist/workspace/broker-protocol.d.ts +190 -0
- package/dist/workspace/broker-protocol.d.ts.map +1 -0
- 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.d.ts +5 -0
- package/dist/workspace/checks.d.ts.map +1 -1
- package/dist/workspace/compose-graph.d.ts +10 -0
- package/dist/workspace/compose-graph.d.ts.map +1 -1
- package/dist/workspace/composites.d.ts +2 -2
- package/dist/workspace/composites.d.ts.map +1 -1
- package/dist/workspace/conformance/__fixtures__/reference-broker.d.ts +17 -0
- package/dist/workspace/conformance/__fixtures__/reference-broker.d.ts.map +1 -0
- package/dist/workspace/conformance/broker.d.ts +202 -0
- package/dist/workspace/conformance/broker.d.ts.map +1 -0
- package/dist/workspace/conformance/index.d.ts +68 -6
- package/dist/workspace/conformance/index.d.ts.map +1 -1
- package/dist/workspace/conformance/vitest.d.ts +19 -3
- package/dist/workspace/conformance/vitest.d.ts.map +1 -1
- package/dist/workspace/conformance/writer.d.ts +462 -0
- package/dist/workspace/conformance/writer.d.ts.map +1 -0
- package/dist/workspace/decide.d.ts +126 -12
- package/dist/workspace/decide.d.ts.map +1 -1
- package/dist/workspace/decision-points.schema.json +11 -4
- package/dist/workspace/declaration.d.ts +156 -4
- package/dist/workspace/declaration.d.ts.map +1 -1
- package/dist/workspace/declaration.schema.json +383 -5
- package/dist/workspace/environments.d.ts +36 -10
- package/dist/workspace/environments.d.ts.map +1 -1
- package/dist/workspace/factory-rules.d.ts +180 -0
- package/dist/workspace/factory-rules.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/init.d.ts +21 -0
- package/dist/workspace/init.d.ts.map +1 -1
- 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 +36 -2
- package/dist/workspace/intent-record.d.ts.map +1 -1
- package/dist/workspace/intent.d.ts +249 -8
- package/dist/workspace/intent.d.ts.map +1 -1
- package/dist/workspace/json-edit.d.ts +24 -0
- package/dist/workspace/json-edit.d.ts.map +1 -0
- package/dist/workspace/jsonc.d.ts +11 -0
- package/dist/workspace/jsonc.d.ts.map +1 -1
- package/dist/workspace/kinds.d.ts +66 -4
- package/dist/workspace/kinds.d.ts.map +1 -1
- package/dist/workspace/lexicon-symbols.d.ts +29 -0
- package/dist/workspace/lexicon-symbols.d.ts.map +1 -0
- package/dist/workspace/lineage-hash-index.d.ts.map +1 -1
- package/dist/workspace/lineage-lock.d.ts +2 -2
- package/dist/workspace/lineage-lock.d.ts.map +1 -1
- package/dist/workspace/lineage-upgrade.d.ts +31 -2
- package/dist/workspace/lineage-upgrade.d.ts.map +1 -1
- package/dist/workspace/links.d.ts.map +1 -1
- package/dist/workspace/point-answer.schema.json +42 -2
- package/dist/workspace/points-cli.d.ts +10 -3
- package/dist/workspace/points-cli.d.ts.map +1 -1
- package/dist/workspace/points.d.ts +66 -5
- 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 +53 -4
- 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 +5 -7
- 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 +34 -1
- package/dist/workspace/records-cli.d.ts.map +1 -1
- package/dist/workspace/records-close.d.ts +7 -3
- 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 +68 -7
- package/dist/workspace/records-write.d.ts.map +1 -1
- package/dist/workspace/records.d.ts +43 -9
- package/dist/workspace/records.d.ts.map +1 -1
- package/dist/workspace/runs-cli.d.ts +296 -0
- package/dist/workspace/runs-cli.d.ts.map +1 -0
- package/dist/workspace/runs.d.ts +544 -0
- package/dist/workspace/runs.d.ts.map +1 -0
- package/dist/workspace/session-kinds.d.ts +1 -1
- package/dist/workspace/session-kinds.d.ts.map +1 -1
- package/dist/workspace/source-block.d.ts +1 -1
- package/dist/workspace/source-block.d.ts.map +1 -1
- package/dist/workspace/squash.d.ts +80 -0
- package/dist/workspace/squash.d.ts.map +1 -0
- package/dist/workspace/status-gates.d.ts +17 -3
- package/dist/workspace/status-gates.d.ts.map +1 -1
- package/dist/workspace/status.d.ts +64 -0
- package/dist/workspace/status.d.ts.map +1 -1
- package/dist/workspace/symbols.d.ts +63 -0
- package/dist/workspace/symbols.d.ts.map +1 -0
- 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.map +1 -1
- package/dist/workspace/trust/rotation.d.ts.map +1 -1
- package/dist/workspace/trust/run-commits.d.ts +46 -0
- package/dist/workspace/trust/run-commits.d.ts.map +1 -0
- package/dist/workspace/trust/run-statement.d.ts +128 -0
- package/dist/workspace/trust/run-statement.d.ts.map +1 -0
- package/dist/workspace/trust/seal.d.ts +38 -0
- package/dist/workspace/trust/seal.d.ts.map +1 -1
- package/dist/workspace/trust/test-repo.d.ts.map +1 -1
- package/dist/workspace/trust/verify-cli.d.ts +1 -1
- package/dist/workspace/trust/verify.d.ts +16 -2
- package/dist/workspace/trust/verify.d.ts.map +1 -1
- package/dist/workspace/wip-cli.d.ts +21 -0
- package/dist/workspace/wip-cli.d.ts.map +1 -0
- package/dist/workspace/wip.d.ts +268 -0
- package/dist/workspace/wip.d.ts.map +1 -0
- 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-size.d.ts +55 -0
- package/dist/workspace/work-size.d.ts.map +1 -0
- package/dist/workspace/work.d.ts +26 -1
- package/dist/workspace/work.d.ts.map +1 -1
- package/dist/workspace/workspace-kinds.schema.json +122 -0
- package/dist/workspace/workspace-principals.schema.json +60 -0
- package/dist/workspace/write-lock-cli.d.ts +60 -0
- package/dist/workspace/write-lock-cli.d.ts.map +1 -0
- package/dist/workspace/write-lock.d.ts +152 -0
- package/dist/workspace/write-lock.d.ts.map +1 -0
- package/dist/workspace/write-scope.d.ts +83 -19
- package/dist/workspace/write-scope.d.ts.map +1 -1
- package/dist/yaml.d.ts +21 -39
- package/dist/yaml.d.ts.map +1 -1
- package/package.json +7 -2
- package/src/__fixtures__/change-set/lifecycle-plan.floci.json +59 -0
- package/src/__fixtures__/change-set/lifecycle-v1.ts.txt +4 -0
- package/src/__fixtures__/change-set/lifecycle-v2.ts.txt +4 -0
- package/src/__fixtures__/change-set/lifecycle.change-set.golden.json +95 -0
- package/src/__fixtures__/change-set/warden.change-set.golden.json +106 -0
- package/src/__fixtures__/change-set/warden.plan.json +44 -0
- package/src/__fixtures__/plan-summary/normalization-vectors.json +1593 -0
- package/src/__fixtures__/pr-loop/pr-apply-applied.note.golden.md +31 -0
- package/src/__fixtures__/pr-loop/pr-apply-refused.note.golden.md +31 -0
- package/src/__fixtures__/pr-loop/pr-plan.golden.json +127 -0
- package/src/__fixtures__/pr-loop/pr-plan.note.golden.md +37 -0
- package/src/audit/core.test.ts +15 -0
- package/src/audit/core.ts +8 -2
- package/src/audit/discover.test.ts +11 -0
- package/src/audit/discover.ts +7 -2
- package/src/audit/prior-art.ts +15 -0
- package/src/change-set-bundle.test.ts +57 -0
- package/src/change-set.test.ts +215 -0
- package/src/change-set.ts +445 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/package.json +1 -1
- package/src/cli/commands/audit-opt-in.test.ts +54 -0
- package/src/cli/commands/audit.ts +29 -2
- package/src/cli/commands/build.test.ts +19 -0
- package/src/cli/commands/build.ts +3 -2
- 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 +18 -0
- package/src/cli/commands/import-parser-options.test.ts +133 -0
- package/src/cli/commands/import.ts +21 -3
- 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/build.ts +13 -1
- package/src/cli/handlers/change-set.test.ts +56 -0
- package/src/cli/handlers/change-set.ts +44 -0
- package/src/cli/handlers/components.ts +2 -2
- package/src/cli/handlers/dev.ts +8 -6
- package/src/cli/handlers/fan-out.test.ts +221 -2
- package/src/cli/handlers/fan-out.ts +165 -75
- package/src/cli/handlers/graph.ts +3 -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.test.ts +21 -0
- package/src/cli/handlers/operator.ts +121 -6
- package/src/cli/handlers/pr.ts +373 -0
- package/src/cli/handlers/run.test.ts +111 -0
- package/src/cli/handlers/run.ts +86 -24
- package/src/cli/handlers/scenario.ts +2 -2
- package/src/cli/main.test.ts +21 -0
- package/src/cli/main.ts +246 -30
- package/src/cli/mcp/never-over-mcp.test.ts +101 -0
- package/src/cli/mcp/op-tools.ts +24 -2
- package/src/cli/mcp/workspace-tools.test.ts +5 -2
- package/src/cli/mcp/workspace-tools.ts +62 -7
- package/src/cli/registry.ts +74 -3
- 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/testdata/postgres-tags.json +242 -0
- package/src/components/auto-release.ts +1 -1
- package/src/components/capability.ts +55 -0
- package/src/components/changed-files.ts +66 -0
- package/src/components/cli-support.ts +28 -5
- package/src/components/component.schema.json +17 -0
- package/src/components/component.ts +25 -0
- package/src/components/deploy-units.ts +3 -0
- package/src/components/driver.test.ts +52 -0
- package/src/components/driver.ts +31 -13
- package/src/components/fan-out-output.ts +42 -1
- package/src/components/fan-out-record.ts +69 -0
- package/src/components/fan-out-run.test.ts +17 -0
- package/src/components/fan-out-run.ts +304 -1
- package/src/components/fan-out-support.ts +3 -0
- package/src/components/fan-out-waves.test.ts +375 -0
- package/src/components/fan-out.ts +18 -17
- package/src/components/gated-wave-pipeline.ts +82 -0
- package/src/components/index.ts +1 -0
- package/src/components/layers.ts +30 -0
- package/src/components/pr-pipeline.ts +91 -0
- package/src/components/pr-run.test.ts +205 -0
- package/src/components/pr-run.ts +280 -0
- package/src/components/promote.ts +5 -0
- package/src/components/verbs/shell.test.ts +11 -0
- package/src/components/verbs/shell.ts +7 -3
- package/src/components/wave-plan.ts +124 -0
- package/src/config.test.ts +21 -0
- package/src/config.ts +15 -0
- 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/sandbox/bundle.ts +1 -1
- 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/gated-waves-bundle.test.ts +62 -0
- package/src/gated-waves.test.ts +118 -0
- package/src/gated-waves.ts +240 -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/index.ts +1 -0
- package/src/lexicon.ts +106 -3
- package/src/lifecycle/gate-ledger.ts +23 -0
- package/src/lifecycle/git.ts +102 -16
- package/src/lifecycle/observe.test.ts +18 -0
- package/src/lifecycle/observe.ts +6 -4
- 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/lint/post-synth.test.ts +19 -0
- package/src/lint/post-synth.ts +19 -1
- package/src/meta/declared-imports.test.ts +1 -1
- package/src/op/activities/activity-contracts.ts +84 -0
- package/src/op/activities/apply.test.ts +189 -5
- package/src/op/activities/apply.ts +230 -8
- package/src/op/activities/change-set.ts +114 -0
- package/src/op/activities/decide.ts +3 -0
- package/src/op/activities/factory.ts +675 -0
- package/src/op/activities/index.ts +9 -0
- package/src/op/activities/lexicon-upgrade.test.ts +160 -6
- package/src/op/activities/lexicon-upgrade.ts +154 -51
- package/src/op/activity-contract.test.ts +21 -1
- package/src/op/activity-contract.ts +19 -9
- package/src/op/builders.ts +23 -0
- 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/decide-backend.ts +5 -1
- package/src/op/decide-read-inputs.ts +33 -5
- package/src/op/emulator-lifecycle.test.ts +23 -0
- package/src/op/emulator-lifecycle.ts +52 -14
- package/src/op/factory.e2e.test.ts +232 -0
- package/src/op/factory.ts +118 -0
- package/src/op/gate-approval.test.ts +74 -0
- package/src/op/gate-approval.ts +5 -1
- package/src/op/gate.ts +31 -5
- package/src/op/index.ts +11 -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/op-ir.test.ts +9 -0
- package/src/op/op-ir.ts +4 -0
- package/src/op/op-verb-class.ts +3 -0
- 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 +16 -3
- package/src/op/work-lease-run.test.ts +47 -0
- package/src/op/work-lease-run.ts +76 -11
- package/src/plan-summary.test.ts +263 -0
- package/src/plan-summary.ts +845 -0
- package/src/pr-forge.test.ts +237 -0
- package/src/pr-forge.ts +332 -0
- package/src/pr-loop-bundle.test.ts +46 -0
- package/src/pr-loop.test.ts +171 -0
- package/src/pr-loop.ts +324 -0
- package/src/provenance.ts +35 -0
- package/src/telemetry-attribution.test.ts +23 -1
- package/src/telemetry-attribution.ts +51 -0
- package/src/terraform/hcl2json.test.ts +21 -0
- package/src/terraform/hcl2json.ts +81 -0
- package/src/terraform/parse.ts +11 -74
- package/src/workspace/agent-cli.ts +7 -3
- package/src/workspace/agent.schema.json +22 -0
- package/src/workspace/app-kind.test.ts +196 -0
- package/src/workspace/box-cli.ts +113 -0
- package/src/workspace/box-factory.test.ts +323 -0
- package/src/workspace/box-factory.ts +136 -0
- package/src/workspace/box-listing-write.schema.json +204 -0
- package/src/workspace/box-listing.test.ts +234 -0
- package/src/workspace/box-listing.ts +324 -0
- package/src/workspace/box-publish.schema.json +498 -0
- package/src/workspace/box-publish.test.ts +204 -0
- package/src/workspace/box-publish.ts +420 -0
- package/src/workspace/box-ship.test.ts +96 -0
- package/src/workspace/broker-protocol.schema.json +186 -0
- package/src/workspace/broker-protocol.test.ts +122 -0
- package/src/workspace/broker-protocol.ts +317 -0
- package/src/workspace/builder-tiers.test.ts +146 -0
- package/src/workspace/change-set.schema.json +460 -0
- package/src/workspace/changes.schema.json +12 -20
- package/src/workspace/changes.ts +4 -1
- package/src/workspace/chant-migrations.e2e.test.ts +17 -5
- package/src/workspace/checks/boxes.test.ts +5 -0
- package/src/workspace/checks.ts +39 -8
- package/src/workspace/component-environments.test.ts +105 -0
- package/src/workspace/compose-graph.ts +7 -0
- package/src/workspace/composites.schema.json +23 -4
- package/src/workspace/composites.test.ts +8 -8
- package/src/workspace/composites.ts +13 -2
- package/src/workspace/conformance/__fixture__/decisions/decision.schema.json +2 -2
- package/src/workspace/conformance/__fixtures__/reference-broker.ts +207 -0
- package/src/workspace/conformance/__writer_fixture__/answers/answer.kind.mjs +32 -0
- package/src/workspace/conformance/__writer_fixture__/answers/answer.schema.json +135 -0
- package/src/workspace/conformance/__writer_fixture__/contracts/contract.kind.mjs +37 -0
- package/src/workspace/conformance/__writer_fixture__/contracts/contract.schema.json +213 -0
- package/src/workspace/conformance/__writer_fixture__/decisions/points.json +228 -0
- package/src/workspace/conformance/__writer_fixture__/drivers/driver.kind.mjs +15 -0
- package/src/workspace/conformance/__writer_fixture__/drivers/driver.schema.json +38 -0
- package/src/workspace/conformance/__writer_fixture__/sessions/session.kind.mjs +54 -0
- package/src/workspace/conformance/__writer_fixture__/sessions/session.schema.json +289 -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 +603 -0
- package/src/workspace/conformance/broker.test.ts +122 -0
- package/src/workspace/conformance/broker.ts +792 -0
- package/src/workspace/conformance/conformance.e2e.test.ts +36 -3
- package/src/workspace/conformance/index.mjs +51 -3
- package/src/workspace/conformance/index.ts +107 -15
- package/src/workspace/conformance/vitest.ts +76 -2
- package/src/workspace/conformance/writer-conformance.e2e.test.ts +177 -0
- package/src/workspace/conformance/writer.test.ts +186 -0
- package/src/workspace/conformance/writer.ts +1191 -0
- package/src/workspace/decide.test.ts +208 -4
- package/src/workspace/decide.ts +433 -73
- package/src/workspace/decision-points.schema.json +11 -4
- package/src/workspace/declaration.schema.json +383 -5
- package/src/workspace/declaration.ts +315 -10
- package/src/workspace/environments.ts +66 -14
- package/src/workspace/factory-rules.test.ts +62 -0
- package/src/workspace/factory-rules.ts +218 -0
- package/src/workspace/graph-cli.ts +6 -3
- package/src/workspace/graph.schema.json +314 -0
- package/src/workspace/identity.test.ts +219 -0
- package/src/workspace/identity.ts +186 -0
- package/src/workspace/init.ts +82 -2
- package/src/workspace/intent-cli.ts +84 -13
- package/src/workspace/intent-patch-id.test.ts +162 -0
- package/src/workspace/intent-record.schema.json +336 -1
- package/src/workspace/intent-record.ts +96 -16
- package/src/workspace/intent-reviews.test.ts +76 -0
- package/src/workspace/intent-squash.test.ts +213 -0
- package/src/workspace/intent-why.test.ts +274 -0
- package/src/workspace/intent.schema.json +950 -9
- package/src/workspace/intent.test.ts +11 -2
- package/src/workspace/intent.ts +722 -65
- package/src/workspace/json-edit.test.ts +121 -0
- package/src/workspace/json-edit.ts +142 -0
- package/src/workspace/jsonc.ts +20 -0
- package/src/workspace/kinds.ts +201 -39
- package/src/workspace/lexicon-symbols.test.ts +148 -0
- package/src/workspace/lexicon-symbols.ts +125 -0
- package/src/workspace/lineage-upgrade.test.ts +63 -0
- package/src/workspace/lineage-upgrade.ts +146 -5
- package/src/workspace/plan-summary.schema.json +155 -0
- package/src/workspace/point-answer.schema.json +42 -2
- package/src/workspace/points-cli.ts +42 -16
- package/src/workspace/points-write.schema.json +163 -4
- package/src/workspace/points.schema.json +157 -2
- package/src/workspace/points.test.ts +13 -1
- package/src/workspace/points.ts +118 -12
- package/src/workspace/pr-report.schema.json +95 -0
- package/src/workspace/principal-classes.test.ts +175 -0
- package/src/workspace/principal-classes.ts +307 -0
- package/src/workspace/profiles.test.ts +159 -0
- package/src/workspace/read-contract.test.ts +2 -2
- package/src/workspace/reason-codes.test.ts +23 -3
- package/src/workspace/reason-codes.ts +61 -4
- package/src/workspace/record-sessions.ts +9 -8
- package/src/workspace/records-amend.schema.json +80 -0
- package/src/workspace/records-checkout.ts +106 -0
- package/src/workspace/records-cli.ts +123 -17
- package/src/workspace/records-close.schema.json +79 -0
- package/src/workspace/records-close.ts +31 -7
- package/src/workspace/records-concurrent.e2e.test.ts +135 -0
- package/src/workspace/records-concurrent.test.ts +145 -0
- package/src/workspace/records-formats.test.ts +46 -10
- package/src/workspace/records-new.schema.json +9 -0
- package/src/workspace/records-review.schema.json +80 -0
- package/src/workspace/records-sessions-write.test.ts +69 -0
- package/src/workspace/records-sessions.test.ts +22 -0
- package/src/workspace/records-uncommitted.test.ts +171 -0
- package/src/workspace/records-write.ts +219 -30
- package/src/workspace/records.schema.json +88 -1
- package/src/workspace/records.ts +76 -8
- package/src/workspace/reference-kinds/app/package.json +10 -0
- package/src/workspace/reference-kinds/app/workspace-kinds.json +45 -0
- package/src/workspace/run-statement.schema.json +622 -0
- package/src/workspace/runs-cli.ts +710 -0
- package/src/workspace/runs-statement.test.ts +239 -0
- package/src/workspace/runs-write.schema.json +994 -0
- package/src/workspace/runs.schema.json +1257 -0
- package/src/workspace/runs.test.ts +281 -0
- package/src/workspace/runs.ts +970 -0
- package/src/workspace/session-kinds.ts +3 -3
- package/src/workspace/squash.ts +198 -0
- package/src/workspace/status-contract.test.ts +10 -2
- package/src/workspace/status-gates.ts +25 -9
- package/src/workspace/status.schema.json +252 -4
- package/src/workspace/status.ts +110 -1
- package/src/workspace/symbols.ts +191 -0
- 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/run-commits.ts +115 -0
- package/src/workspace/trust/run-statement.ts +226 -0
- package/src/workspace/trust/seal.ts +58 -1
- package/src/workspace/trust/verify-cli.ts +6 -5
- package/src/workspace/trust/verify.ts +39 -6
- package/src/workspace/wip-cli.ts +97 -0
- package/src/workspace/wip-write.schema.json +504 -0
- package/src/workspace/wip.schema.json +334 -0
- package/src/workspace/wip.test.ts +294 -0
- package/src/workspace/wip.ts +753 -0
- package/src/workspace/work-cli.e2e.test.ts +28 -1
- package/src/workspace/work-cli.ts +136 -8
- package/src/workspace/work-evidence.schema.json +5 -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-size.test.ts +77 -0
- package/src/workspace/work-size.ts +93 -0
- package/src/workspace/work.ts +82 -0
- package/src/workspace/workspace-kinds.schema.json +122 -0
- package/src/workspace/workspace-principals.schema.json +60 -0
- package/src/workspace/write-lock-cli.ts +131 -0
- package/src/workspace/write-lock.schema.json +172 -0
- package/src/workspace/write-lock.test.ts +189 -0
- package/src/workspace/write-lock.ts +474 -0
- package/src/workspace/write-scope.test.ts +144 -3
- package/src/workspace/write-scope.ts +192 -45
- package/src/yaml.test.ts +111 -1
- package/src/yaml.ts +141 -549
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Editing one property of a JSON or JSONC document in place (#3308): the
|
|
3
|
+
* rest of the text is left as it was, comments and trailing commas included.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { describe, expect, test } from "vitest";
|
|
7
|
+
import { removeProperty, setProperty, valueAt } from "./json-edit";
|
|
8
|
+
import { parseJsonText } from "./jsonc";
|
|
9
|
+
|
|
10
|
+
const read = (text: string, jsonc = false) => {
|
|
11
|
+
const r = parseJsonText(text, { jsonc });
|
|
12
|
+
if (!r.ok) throw new Error(r.message);
|
|
13
|
+
return r.value;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const JSON_TEXT = `{
|
|
17
|
+
"name": "w",
|
|
18
|
+
"members": [
|
|
19
|
+
{ "name": "a", "box": { "services": [] } },
|
|
20
|
+
{
|
|
21
|
+
"name": "b",
|
|
22
|
+
"box": {
|
|
23
|
+
"intent": "ws-001"
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
]
|
|
27
|
+
}
|
|
28
|
+
`;
|
|
29
|
+
|
|
30
|
+
const JSONC_TEXT = `{
|
|
31
|
+
// the workspace
|
|
32
|
+
"name": "w",
|
|
33
|
+
"members": [
|
|
34
|
+
{
|
|
35
|
+
"name": "b",
|
|
36
|
+
"box": {
|
|
37
|
+
"listing": {
|
|
38
|
+
"title": "Old", // kept as is
|
|
39
|
+
"line": "one line",
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
],
|
|
44
|
+
}
|
|
45
|
+
`;
|
|
46
|
+
|
|
47
|
+
describe("setProperty", () => {
|
|
48
|
+
test("replaces a value in place and leaves every other byte", () => {
|
|
49
|
+
const out = setProperty(JSON_TEXT, false, "/members/1/box", "intent", "ws-002");
|
|
50
|
+
expect(out).toBe(JSON_TEXT.replace('"ws-001"', '"ws-002"'));
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
test("adds a key after the last one, indented like it, and an object value on its own lines", () => {
|
|
54
|
+
const out = setProperty(JSON_TEXT, false, "/members/1/box", "listing", { title: "B", published: false });
|
|
55
|
+
expect(out).toContain(` "intent": "ws-001",\n "listing": {\n "title": "B",\n "published": false\n }\n }`);
|
|
56
|
+
expect(read(out)).toEqual({ ...(read(JSON_TEXT) as object), members: [{ name: "a", box: { services: [] } }, { name: "b", box: { intent: "ws-001", listing: { title: "B", published: false } } }] });
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
test("keeps an object on one line on one line", () => {
|
|
60
|
+
const out = setProperty(JSON_TEXT, false, "/members/0/box", "listing", { title: "A" });
|
|
61
|
+
expect(out).toContain(`{ "name": "a", "box": { "services": [], "listing": {"title":"A"} } }`);
|
|
62
|
+
expect(valueAt(read(out), "/members/0/box/listing")).toEqual({ title: "A" });
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
test("fills an empty object", () => {
|
|
66
|
+
const out = setProperty('{\n "box": {}\n}\n', false, "/box", "listing", { title: "T" });
|
|
67
|
+
expect(out).toBe('{\n "box": {\n "listing": {\n "title": "T"\n }\n }\n}\n');
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
test("in JSONC, keeps comments with their lines and the trailing comma style", () => {
|
|
71
|
+
const out = setProperty(JSONC_TEXT, true, "/members/0/box/listing", "published", false);
|
|
72
|
+
expect(out).toContain(` "line": "one line",\n "published": false,\n },`);
|
|
73
|
+
const out2 = setProperty(JSONC_TEXT, true, "/members/0/box/listing", "title", "New");
|
|
74
|
+
expect(out2).toBe(JSONC_TEXT.replace('"Old"', '"New"'));
|
|
75
|
+
expect(out2).toContain("// kept as is");
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
test("puts a new key after a comment that ends the last property's line", () => {
|
|
79
|
+
const text = '{\n "a": 1, // one\n "b": 2 // two\n}\n';
|
|
80
|
+
const out = setProperty(text, true, "", "c", 3);
|
|
81
|
+
expect(out).toBe('{\n "a": 1, // one\n "b": 2, // two\n "c": 3\n}\n');
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
test("keeps CRLF line endings", () => {
|
|
85
|
+
const text = '{\r\n "box": {\r\n "intent": "x"\r\n }\r\n}\r\n';
|
|
86
|
+
const out = setProperty(text, false, "/box", "listing", { title: "T" });
|
|
87
|
+
expect(out).toBe('{\r\n "box": {\r\n "intent": "x",\r\n "listing": {\r\n "title": "T"\r\n }\r\n }\r\n}\r\n');
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
test("refuses when there is no object at the pointer", () => {
|
|
91
|
+
expect(() => setProperty(JSON_TEXT, false, "/members/5/box", "listing", {})).toThrow(/no object at \/members\/5\/box/);
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
describe("removeProperty", () => {
|
|
96
|
+
test("removes a key with the comma after it, and its line", () => {
|
|
97
|
+
const text = '{\n "a": 1,\n "b": 2,\n "c": 3\n}\n';
|
|
98
|
+
expect(removeProperty(text, false, "", "b")).toBe('{\n "a": 1,\n "c": 3\n}\n');
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
test("removes the last key with the comma before it", () => {
|
|
102
|
+
const text = '{\n "a": 1,\n "b": 2\n}\n';
|
|
103
|
+
expect(removeProperty(text, false, "", "b")).toBe('{\n "a": 1\n}\n');
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
test("removes a key on a one-line object", () => {
|
|
107
|
+
expect(removeProperty('{ "a": 1, "b": 2 }', false, "", "a")).toBe('{ "b": 2 }');
|
|
108
|
+
expect(removeProperty('{ "a": 1, "b": 2 }', false, "", "b")).toBe('{ "a": 1 }');
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
test("leaves {} when the only key goes, and the text unchanged when the key is not there", () => {
|
|
112
|
+
expect(removeProperty('{\n "box": {\n "listing": {\n "a": 1\n }\n }\n}', false, "/box/listing", "a")).toBe('{\n "box": {\n "listing": {}\n }\n}');
|
|
113
|
+
expect(removeProperty('{ "a": 1 }', false, "", "z")).toBe('{ "a": 1 }');
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
test("in JSONC, removes a key with its trailing comma and keeps the comments of the others", () => {
|
|
117
|
+
const out = removeProperty(JSONC_TEXT, true, "/members/0/box/listing", "line");
|
|
118
|
+
expect(out).toContain(`"title": "Old", // kept as is\n },`);
|
|
119
|
+
expect(valueAt(read(out, true), "/members/0/box/listing")).toEqual({ title: "Old" });
|
|
120
|
+
});
|
|
121
|
+
});
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Edit one property of a JSON or JSONC document in place (#3308), for the
|
|
3
|
+
* write commands that change a field of the workspace declaration.
|
|
4
|
+
*
|
|
5
|
+
* Only the text of the property changed is touched: the rest of the file
|
|
6
|
+
* keeps its indentation, key order, line endings, comments and trailing
|
|
7
|
+
* commas. A new property goes after the last one of its object, indented
|
|
8
|
+
* like it. The caller re-parses the result and compares it with the value it
|
|
9
|
+
* meant to write, so an edit this module gets wrong is never written.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { parseJsonText, pointerToken } from "./jsonc";
|
|
13
|
+
|
|
14
|
+
export class JsonEditError extends Error {
|
|
15
|
+
constructor(message: string) {
|
|
16
|
+
super(message);
|
|
17
|
+
this.name = "JsonEditError";
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
type Parsed = Extract<ReturnType<typeof parseJsonText>, { ok: true }>;
|
|
22
|
+
|
|
23
|
+
function parse(text: string, jsonc: boolean): Parsed {
|
|
24
|
+
const r = parseJsonText(text, { jsonc });
|
|
25
|
+
if (!r.ok) throw new JsonEditError(`the file does not parse: ${r.message} at line ${r.location.line}, column ${r.location.column}`);
|
|
26
|
+
return r;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** The value at a JSON Pointer, or undefined. */
|
|
30
|
+
export function valueAt(root: unknown, pointer: string): unknown {
|
|
31
|
+
if (pointer === "") return root;
|
|
32
|
+
let at: unknown = root;
|
|
33
|
+
for (const raw of pointer.slice(1).split("/")) {
|
|
34
|
+
const token = raw.replace(/~1/g, "/").replace(/~0/g, "~");
|
|
35
|
+
if (at === null || typeof at !== "object") return undefined;
|
|
36
|
+
if (Array.isArray(at)) at = at[Number(token)];
|
|
37
|
+
else at = Object.prototype.hasOwnProperty.call(at, token) ? (at as Record<string, unknown>)[token] : undefined;
|
|
38
|
+
}
|
|
39
|
+
return at;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const isObject = (v: unknown): v is Record<string, unknown> => v !== null && typeof v === "object" && !Array.isArray(v);
|
|
43
|
+
|
|
44
|
+
/** The text's line ending, and the indentation one level adds (the first indented line's, else two spaces). */
|
|
45
|
+
function style(text: string): { eol: string; unit: string } {
|
|
46
|
+
const eol = text.includes("\r\n") ? "\r\n" : "\n";
|
|
47
|
+
const m = /\n([ \t]+)\S/.exec(text);
|
|
48
|
+
return { eol, unit: m ? (m[1].startsWith("\t") ? "\t" : m[1]) : " " };
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function lineStart(text: string, offset: number): number {
|
|
52
|
+
return text.lastIndexOf("\n", offset - 1) + 1;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function lineIndent(text: string, offset: number): string {
|
|
56
|
+
const start = lineStart(text, offset);
|
|
57
|
+
return /^[ \t]*/.exec(text.slice(start))![0];
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** The offset of the next character after `from` that is not whitespace or a comment. */
|
|
61
|
+
function skipTrivia(text: string, from: number): number {
|
|
62
|
+
let i = from;
|
|
63
|
+
for (;;) {
|
|
64
|
+
const c = text[i];
|
|
65
|
+
if (c === " " || c === "\t" || c === "\n" || c === "\r") i++;
|
|
66
|
+
else if (c === "/" && text[i + 1] === "/") {
|
|
67
|
+
while (i < text.length && text[i] !== "\n") i++;
|
|
68
|
+
} else if (c === "/" && text[i + 1] === "*") {
|
|
69
|
+
const end = text.indexOf("*/", i + 2);
|
|
70
|
+
i = end < 0 ? text.length : end + 2;
|
|
71
|
+
} else return i;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function render(value: unknown, indent: string, unit: string, eol: string): string {
|
|
76
|
+
return JSON.stringify(value, null, unit).split("\n").join(eol + indent);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Set `key` of the object at `objectPointer` to `value`: replace the value's
|
|
81
|
+
* text when the key is there, else add the key after the object's last one.
|
|
82
|
+
* Throws a {@link JsonEditError} when there is no object at the pointer.
|
|
83
|
+
*/
|
|
84
|
+
export function setProperty(text: string, jsonc: boolean, objectPointer: string, key: string, value: unknown): string {
|
|
85
|
+
const r = parse(text, jsonc);
|
|
86
|
+
const parent = valueAt(r.value, objectPointer);
|
|
87
|
+
if (!isObject(parent)) throw new JsonEditError(`there is no object at ${objectPointer || "the root"}`);
|
|
88
|
+
const { eol, unit } = style(text);
|
|
89
|
+
const child = r.span(`${objectPointer}/${pointerToken(key)}`);
|
|
90
|
+
if (child) return text.slice(0, child.start) + render(value, lineIndent(text, child.key ?? child.start), unit, eol) + text.slice(child.end);
|
|
91
|
+
|
|
92
|
+
const obj = r.span(objectPointer)!;
|
|
93
|
+
const parentIndent = lineIndent(text, obj.key ?? obj.start);
|
|
94
|
+
const keys = Object.keys(parent);
|
|
95
|
+
if (keys.length === 0) {
|
|
96
|
+
const indent = parentIndent + unit;
|
|
97
|
+
return `${text.slice(0, obj.start)}{${eol}${indent}${JSON.stringify(key)}: ${render(value, indent, unit, eol)}${eol}${parentIndent}}${text.slice(obj.end)}`;
|
|
98
|
+
}
|
|
99
|
+
const last = r.span(`${objectPointer}/${pointerToken(keys[keys.length - 1])}`)!;
|
|
100
|
+
const next = skipTrivia(text, last.end);
|
|
101
|
+
const trailingComma = text[next] === ",";
|
|
102
|
+
if (lineStart(text, last.key!) === lineStart(text, obj.start)) {
|
|
103
|
+
// An object on one line stays on one line.
|
|
104
|
+
const entry = `${JSON.stringify(key)}: ${JSON.stringify(value)}`;
|
|
105
|
+
return trailingComma ? `${text.slice(0, next + 1)} ${entry},${text.slice(next + 1)}` : `${text.slice(0, last.end)}, ${entry}${text.slice(last.end)}`;
|
|
106
|
+
}
|
|
107
|
+
const indent = lineIndent(text, last.key!);
|
|
108
|
+
const after = trailingComma ? next + 1 : last.end;
|
|
109
|
+
// After a comment that ends the last property's line, so the comment stays with it.
|
|
110
|
+
const eolAt = text.indexOf("\n", after);
|
|
111
|
+
const lineEnd = eolAt < 0 ? text.length : text[eolAt - 1] === "\r" ? eolAt - 1 : eolAt;
|
|
112
|
+
const at = /^[ \t]*(\/\/.*)?$/.test(text.slice(after, lineEnd)) ? lineEnd : after;
|
|
113
|
+
const entry = `${eol}${indent}${JSON.stringify(key)}: ${render(value, indent, unit, eol)}`;
|
|
114
|
+
if (trailingComma) return `${text.slice(0, at)}${entry},${text.slice(at)}`;
|
|
115
|
+
return `${text.slice(0, last.end)},${text.slice(last.end, at)}${entry}${text.slice(at)}`;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/** Remove `key` from the object at `objectPointer`, with the comma that went with it. Unchanged when the key is not there. */
|
|
119
|
+
export function removeProperty(text: string, jsonc: boolean, objectPointer: string, key: string): string {
|
|
120
|
+
const r = parse(text, jsonc);
|
|
121
|
+
const parent = valueAt(r.value, objectPointer);
|
|
122
|
+
if (!isObject(parent)) throw new JsonEditError(`there is no object at ${objectPointer || "the root"}`);
|
|
123
|
+
const child = r.span(`${objectPointer}/${pointerToken(key)}`);
|
|
124
|
+
if (!child) return text;
|
|
125
|
+
const keys = Object.keys(parent);
|
|
126
|
+
const obj = r.span(objectPointer)!;
|
|
127
|
+
if (keys.length === 1) return `${text.slice(0, obj.start)}{}${text.slice(obj.end)}`;
|
|
128
|
+
const next = skipTrivia(text, child.end);
|
|
129
|
+
if (text[next] === ",") {
|
|
130
|
+
const start = lineStart(text, child.key!);
|
|
131
|
+
const ownLine = /^[ \t]*$/.test(text.slice(start, child.key!));
|
|
132
|
+
let to = next + 1;
|
|
133
|
+
const eolAt = text.indexOf("\n", to);
|
|
134
|
+
if (ownLine && /^[ \t\r]*$/.test(text.slice(to, eolAt < 0 ? text.length : eolAt))) to = eolAt < 0 ? text.length : eolAt + 1;
|
|
135
|
+
else while (text[to] === " ") to++;
|
|
136
|
+
return text.slice(0, ownLine ? start : child.key!) + text.slice(to);
|
|
137
|
+
}
|
|
138
|
+
// The last property, with no trailing comma: remove from the comma after the one before it.
|
|
139
|
+
const prev = r.span(`${objectPointer}/${pointerToken(keys[keys.indexOf(key) - 1])}`)!;
|
|
140
|
+
const comma = skipTrivia(text, prev.end);
|
|
141
|
+
return text.slice(0, comma) + text.slice(child.end);
|
|
142
|
+
}
|
package/src/workspace/jsonc.ts
CHANGED
|
@@ -31,6 +31,13 @@ export type JsonParseResult =
|
|
|
31
31
|
* `key` is set. Falls back to the nearest ancestor that has a position.
|
|
32
32
|
*/
|
|
33
33
|
locate(pointer: string, key?: boolean): TextLocation;
|
|
34
|
+
/**
|
|
35
|
+
* Where the value at `pointer` is in the text, as offsets: its key's
|
|
36
|
+
* opening quote (null for an array item or the root), the value's first
|
|
37
|
+
* character, and the offset just past its last. Undefined when there is
|
|
38
|
+
* no value at `pointer`. For editing the text in place (#3308).
|
|
39
|
+
*/
|
|
40
|
+
span(pointer: string): { key: number | null; start: number; end: number } | undefined;
|
|
34
41
|
}
|
|
35
42
|
| { ok: false; message: string; location: TextLocation };
|
|
36
43
|
|
|
@@ -63,6 +70,7 @@ export function parseJsonText(text: string, options: JsonParseOptions): JsonPars
|
|
|
63
70
|
};
|
|
64
71
|
|
|
65
72
|
const values = new Map<string, number>();
|
|
73
|
+
const ends = new Map<string, number>();
|
|
66
74
|
const keys = new Map<string, number>();
|
|
67
75
|
let i = text.charCodeAt(0) === 0xfeff ? 1 : 0;
|
|
68
76
|
|
|
@@ -113,6 +121,12 @@ export function parseJsonText(text: string, options: JsonParseOptions): JsonPars
|
|
|
113
121
|
function parseValue(pointer: string): unknown {
|
|
114
122
|
skip();
|
|
115
123
|
values.set(pointer, i);
|
|
124
|
+
const value = parseAt(pointer);
|
|
125
|
+
ends.set(pointer, i);
|
|
126
|
+
return value;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function parseAt(pointer: string): unknown {
|
|
116
130
|
const c = text[i];
|
|
117
131
|
if (c === "{") return parseObject(pointer);
|
|
118
132
|
if (c === "[") return parseArray(pointer);
|
|
@@ -223,6 +237,12 @@ export function parseJsonText(text: string, options: JsonParseOptions): JsonPars
|
|
|
223
237
|
if (p === "") return toLocation(0);
|
|
224
238
|
}
|
|
225
239
|
},
|
|
240
|
+
span(pointer) {
|
|
241
|
+
const start = values.get(pointer);
|
|
242
|
+
const end = ends.get(pointer);
|
|
243
|
+
if (start === undefined || end === undefined) return undefined;
|
|
244
|
+
return { key: keys.get(pointer) ?? null, start, end };
|
|
245
|
+
},
|
|
226
246
|
};
|
|
227
247
|
} catch (err) {
|
|
228
248
|
if (!(err instanceof JsonSyntaxError)) throw err;
|
package/src/workspace/kinds.ts
CHANGED
|
@@ -45,8 +45,34 @@ export interface FileProbe {
|
|
|
45
45
|
* `live {` block is found without parsing HCL (#2545).
|
|
46
46
|
*/
|
|
47
47
|
anyBlock?: { in: string[]; blocks: string[] };
|
|
48
|
+
/**
|
|
49
|
+
* A file directly in the directory whose name matches one of `in` parses
|
|
50
|
+
* as JSON and has a value at one of `pointers`, each a JSON Pointer. This
|
|
51
|
+
* is how an app member's `package.json` with a `start` script is found
|
|
52
|
+
* without claiming every Node package (#3151).
|
|
53
|
+
*/
|
|
54
|
+
anyJsonKey?: { in: string[]; pointers: string[] };
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** A string, integer or boolean field a kind declares for its members (#3151). */
|
|
58
|
+
export interface ScalarKindField {
|
|
59
|
+
type: "string" | "integer" | "boolean";
|
|
60
|
+
description: string;
|
|
61
|
+
/** The value a member that doesn't set the field gets; null when the kind gives none. */
|
|
62
|
+
default?: string | number | boolean;
|
|
63
|
+
/** For a string field, a regular expression the value must match. */
|
|
64
|
+
pattern?: string;
|
|
48
65
|
}
|
|
49
66
|
|
|
67
|
+
/** An object field: named scalar fields, each with its own default (#3151). */
|
|
68
|
+
export interface ObjectKindField {
|
|
69
|
+
type: "object";
|
|
70
|
+
description: string;
|
|
71
|
+
properties: Record<string, ScalarKindField>;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export type KindField = ScalarKindField | ObjectKindField;
|
|
75
|
+
|
|
50
76
|
/** What a kind's probe checks in a directory. */
|
|
51
77
|
export type KindProbe =
|
|
52
78
|
/** Files, or blocks in files, sit directly in the directory. */
|
|
@@ -99,6 +125,8 @@ export interface MemberKind {
|
|
|
99
125
|
packageDir?: string;
|
|
100
126
|
/** How `workspace graph` reads a member of this kind (#2874); unset, the member is `kind-not-run`. */
|
|
101
127
|
graph?: KindGraph;
|
|
128
|
+
/** The fields a member entry of this kind may set, with their defaults (#3151); unset, the kind declares none. */
|
|
129
|
+
fields?: Record<string, KindField>;
|
|
102
130
|
}
|
|
103
131
|
|
|
104
132
|
export interface KindRegistry {
|
|
@@ -187,8 +215,18 @@ export function builtinKindRegistry(): KindRegistry {
|
|
|
187
215
|
export function probeKind(kind: MemberKind, tree: WorkspaceTree, dir: string): boolean {
|
|
188
216
|
if ("directory" in kind.probe) return true;
|
|
189
217
|
if ("chantProject" in kind.probe) return holdsChantProject(tree, dir);
|
|
190
|
-
const { anyFile, anyBlock } = kind.probe;
|
|
218
|
+
const { anyFile, anyBlock, anyJsonKey } = kind.probe;
|
|
191
219
|
if (anyFile && filesMatching(tree, dir, anyFile).length > 0) return true;
|
|
220
|
+
if (anyJsonKey) {
|
|
221
|
+
for (const file of filesMatching(tree, dir, anyJsonKey.in)) {
|
|
222
|
+
try {
|
|
223
|
+
const json = JSON.parse(tree.read(file)) as unknown;
|
|
224
|
+
if (anyJsonKey.pointers.some((p) => atPointer(json, p) !== undefined)) return true;
|
|
225
|
+
} catch {
|
|
226
|
+
// A file that isn't JSON is no evidence either way.
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
192
230
|
if (anyBlock) {
|
|
193
231
|
const opener = new RegExp(`^\\s*(?:${anyBlock.blocks.map(escapeRegExp).join("|")})\\s*\\{`, "m");
|
|
194
232
|
for (const file of filesMatching(tree, dir, anyBlock.in)) {
|
|
@@ -227,6 +265,17 @@ function filesMatching(tree: WorkspaceTree, dir: string, names: readonly string[
|
|
|
227
265
|
return out.sort();
|
|
228
266
|
}
|
|
229
267
|
|
|
268
|
+
/** The value at JSON Pointer `pointer` in `json`, or undefined when there is none. */
|
|
269
|
+
function atPointer(json: unknown, pointer: string): unknown {
|
|
270
|
+
let at: unknown = json;
|
|
271
|
+
for (const raw of pointer.split("/").slice(1)) {
|
|
272
|
+
const token = raw.replace(/~1/g, "/").replace(/~0/g, "~");
|
|
273
|
+
if (at === null || typeof at !== "object" || !Object.prototype.hasOwnProperty.call(at, token)) return undefined;
|
|
274
|
+
at = (at as Record<string, unknown>)[token];
|
|
275
|
+
}
|
|
276
|
+
return at;
|
|
277
|
+
}
|
|
278
|
+
|
|
230
279
|
function escapeRegExp(text: string): string {
|
|
231
280
|
return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
232
281
|
}
|
|
@@ -337,7 +386,7 @@ export function parseKindData(text: string, source: string): KindData {
|
|
|
337
386
|
const problems: string[] = [];
|
|
338
387
|
const kinds: MemberKind[] = [];
|
|
339
388
|
const seen = new Set<string>();
|
|
340
|
-
for (const k of (raw as { kinds: { name: string; description: string; precedence: number; probe: FileProbe; outputs?: string[]; graph?: KindGraph }[] }).kinds) {
|
|
389
|
+
for (const k of (raw as { kinds: { name: string; description: string; precedence: number; probe: FileProbe; outputs?: string[]; graph?: KindGraph; fields?: Record<string, KindField> }[] }).kinds) {
|
|
341
390
|
if (BUILTIN_KIND_NAMES.includes(k.name)) {
|
|
342
391
|
problems.push(`${source}: kind ${k.name} is built in and can't be supplied by a package`);
|
|
343
392
|
continue;
|
|
@@ -353,13 +402,16 @@ export function parseKindData(text: string, source: string): KindData {
|
|
|
353
402
|
probe: {
|
|
354
403
|
...(k.probe.anyFile ? { anyFile: [...k.probe.anyFile] } : {}),
|
|
355
404
|
...(k.probe.anyBlock ? { anyBlock: { in: [...k.probe.anyBlock.in], blocks: [...k.probe.anyBlock.blocks] } } : {}),
|
|
405
|
+
...(k.probe.anyJsonKey ? { anyJsonKey: { in: [...k.probe.anyJsonKey.in], pointers: [...k.probe.anyJsonKey.pointers] } } : {}),
|
|
356
406
|
},
|
|
357
407
|
precedence: k.precedence,
|
|
358
408
|
shape: "member",
|
|
359
409
|
outputs: { from: "declared", names: [...(k.outputs ?? [])] },
|
|
360
410
|
source,
|
|
361
411
|
...(k.graph ? { graph: { lexicon: k.graph.lexicon, config: structuredClone(k.graph.config) } } : {}),
|
|
412
|
+
...(k.fields ? { fields: structuredClone(k.fields) } : {}),
|
|
362
413
|
});
|
|
414
|
+
for (const problem of fieldDefaultProblems(k.fields ?? {})) problems.push(`${source}: kind ${k.name} ${problem}`);
|
|
363
415
|
}
|
|
364
416
|
return { kinds, problems };
|
|
365
417
|
}
|
|
@@ -370,14 +422,15 @@ export interface PackageKinds extends KindData {
|
|
|
370
422
|
}
|
|
371
423
|
|
|
372
424
|
/**
|
|
373
|
-
* Where a package's `exports` send `./workspace-kinds
|
|
374
|
-
*
|
|
375
|
-
*
|
|
425
|
+
* Where a package's `exports` send `./workspace-kinds` (or another data
|
|
426
|
+
* subpath, such as `./workspace-principals`), or undefined when the package
|
|
427
|
+
* doesn't export it. Only the literal key counts: a `./*` pattern maps the
|
|
428
|
+
* subpath to code, which chant never runs for plugin data.
|
|
376
429
|
*/
|
|
377
|
-
export function kindsExportTarget(pkg: Record<string, unknown
|
|
430
|
+
export function kindsExportTarget(pkg: Record<string, unknown>, subpath: string = KINDS_SUBPATH): string | undefined | { problem: string } {
|
|
378
431
|
const exports = pkg.exports;
|
|
379
432
|
if (!exports || typeof exports !== "object" || Array.isArray(exports)) return undefined;
|
|
380
|
-
const entry = (exports as Record<string, unknown>)[
|
|
433
|
+
const entry = (exports as Record<string, unknown>)[subpath];
|
|
381
434
|
if (entry === undefined) return undefined;
|
|
382
435
|
let target: unknown = entry;
|
|
383
436
|
if (target && typeof target === "object" && !Array.isArray(target)) {
|
|
@@ -385,10 +438,10 @@ export function kindsExportTarget(pkg: Record<string, unknown>): string | undefi
|
|
|
385
438
|
target = conditions.default ?? conditions.import ?? conditions.require;
|
|
386
439
|
}
|
|
387
440
|
if (typeof target !== "string") {
|
|
388
|
-
return { problem: `exports["${
|
|
441
|
+
return { problem: `exports["${subpath}"] must name one file, as a string or a "default" condition` };
|
|
389
442
|
}
|
|
390
443
|
if (!target.startsWith("./") || !target.endsWith(".json")) {
|
|
391
|
-
return { problem: `exports["${
|
|
444
|
+
return { problem: `exports["${subpath}"] is ${target}; it must name a .json file inside the package, since chant reads plugin data as data and never runs a package's code` };
|
|
392
445
|
}
|
|
393
446
|
return target;
|
|
394
447
|
}
|
|
@@ -499,6 +552,37 @@ export interface LoadedKinds {
|
|
|
499
552
|
problems: KindLoadProblem[];
|
|
500
553
|
}
|
|
501
554
|
|
|
555
|
+
/**
|
|
556
|
+
* The directory a pin's plugin data is read from: an installed package at
|
|
557
|
+
* the pinned version, looked up from `workspaceRoot`, or a path pin's
|
|
558
|
+
* directory, checked against its integrity digest when it has one. Null for
|
|
559
|
+
* a pin that names neither. Shared by the kinds and the principal classes
|
|
560
|
+
* (#3080), so both read a pin the same way.
|
|
561
|
+
*/
|
|
562
|
+
export function pinnedPackageDir(pin: PinLike, workspaceRoot: string): { dir: string; source: string } | { problem: string } | null {
|
|
563
|
+
if (pin.package) {
|
|
564
|
+
const dir = findInstalledPackage(pin.package, workspaceRoot);
|
|
565
|
+
if (!dir) return { problem: `pinned package ${pin.package} is not installed; install it to read the kinds it supplies` };
|
|
566
|
+
let installed: unknown;
|
|
567
|
+
try {
|
|
568
|
+
installed = (JSON.parse(readFileSync(join(dir, "package.json"), "utf-8")) as { version?: unknown }).version;
|
|
569
|
+
} catch {
|
|
570
|
+
installed = undefined;
|
|
571
|
+
}
|
|
572
|
+
if (pin.version && installed !== pin.version) return { problem: `${pin.package} is pinned at ${pin.version}, and ${String(installed ?? "an unknown version")} is installed` };
|
|
573
|
+
return { dir, source: pin.package };
|
|
574
|
+
}
|
|
575
|
+
if (pin.path) {
|
|
576
|
+
const dir = join(workspaceRoot, ...pin.path.split("/"));
|
|
577
|
+
if (pin.integrity) {
|
|
578
|
+
const checked = checkPinIntegrity(dir, pin.integrity, pin.path);
|
|
579
|
+
if (!checked.ok) return { problem: checked.message };
|
|
580
|
+
}
|
|
581
|
+
return { dir, source: pin.path };
|
|
582
|
+
}
|
|
583
|
+
return null;
|
|
584
|
+
}
|
|
585
|
+
|
|
502
586
|
/**
|
|
503
587
|
* Build the registry for a workspace: the built-in kinds plus the kinds
|
|
504
588
|
* every pin publishes. `workspaceRoot` is the absolute workspace root; a
|
|
@@ -514,38 +598,13 @@ export function loadKindRegistry(pins: readonly PinLike[], workspaceRoot: string
|
|
|
514
598
|
const owner = new Map<string, string>();
|
|
515
599
|
const clashing = new Set<string>();
|
|
516
600
|
pins.forEach((pin, i) => {
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
if (
|
|
520
|
-
|
|
521
|
-
dir = findInstalledPackage(pin.package, workspaceRoot);
|
|
522
|
-
if (!dir) {
|
|
523
|
-
problems.push({ pin: i, message: `pinned package ${pin.package} is not installed; install it to read the kinds it supplies` });
|
|
524
|
-
return;
|
|
525
|
-
}
|
|
526
|
-
let installed: unknown;
|
|
527
|
-
try {
|
|
528
|
-
installed = (JSON.parse(readFileSync(join(dir, "package.json"), "utf-8")) as { version?: unknown }).version;
|
|
529
|
-
} catch {
|
|
530
|
-
installed = undefined;
|
|
531
|
-
}
|
|
532
|
-
if (pin.version && installed !== pin.version) {
|
|
533
|
-
problems.push({ pin: i, message: `${pin.package} is pinned at ${pin.version}, and ${String(installed ?? "an unknown version")} is installed` });
|
|
534
|
-
return;
|
|
535
|
-
}
|
|
536
|
-
} else if (pin.path) {
|
|
537
|
-
source = pin.path;
|
|
538
|
-
dir = join(workspaceRoot, ...pin.path.split("/"));
|
|
539
|
-
if (pin.integrity) {
|
|
540
|
-
const checked = checkPinIntegrity(dir, pin.integrity, pin.path);
|
|
541
|
-
if (!checked.ok) {
|
|
542
|
-
problems.push({ pin: i, message: checked.message });
|
|
543
|
-
return;
|
|
544
|
-
}
|
|
545
|
-
}
|
|
546
|
-
} else {
|
|
601
|
+
const found = pinnedPackageDir(pin, workspaceRoot);
|
|
602
|
+
if (found === null) return;
|
|
603
|
+
if ("problem" in found) {
|
|
604
|
+
problems.push({ pin: i, message: found.problem });
|
|
547
605
|
return;
|
|
548
606
|
}
|
|
607
|
+
const { dir, source } = found;
|
|
549
608
|
const read = readPackageKinds(dir, source);
|
|
550
609
|
for (const p of read.problems) problems.push({ pin: i, message: p });
|
|
551
610
|
for (const k of read.kinds) {
|
|
@@ -583,3 +642,106 @@ export function kindsFileShips(packageDir: string, file: string): boolean {
|
|
|
583
642
|
return rel === e || rel.startsWith(`${e}/`);
|
|
584
643
|
});
|
|
585
644
|
}
|
|
645
|
+
|
|
646
|
+
// ── Member fields (#3151) ────────────────────────────────────────────────────
|
|
647
|
+
|
|
648
|
+
/** A value a member sets, or a kind's default: what a scalar field holds. */
|
|
649
|
+
export type FieldValue = string | number | boolean;
|
|
650
|
+
|
|
651
|
+
/** Why a value doesn't fit `field`, phrased to follow "the value", or undefined when it fits. */
|
|
652
|
+
function scalarProblem(field: ScalarKindField, value: unknown): string | undefined {
|
|
653
|
+
const ok = field.type === "integer" ? typeof value === "number" && Number.isInteger(value) : typeof value === field.type;
|
|
654
|
+
if (!ok) return `is ${JSON.stringify(value)}, and the field is ${field.type === "integer" ? "an integer" : `a ${field.type}`}`;
|
|
655
|
+
if (field.pattern !== undefined && typeof value === "string") {
|
|
656
|
+
let re: RegExp;
|
|
657
|
+
try {
|
|
658
|
+
re = new RegExp(field.pattern, "u");
|
|
659
|
+
} catch {
|
|
660
|
+
return undefined; // Reported once, against the kind, by fieldDefaultProblems.
|
|
661
|
+
}
|
|
662
|
+
if (!re.test(value)) return `is ${JSON.stringify(value)}, which does not match ${field.pattern}`;
|
|
663
|
+
}
|
|
664
|
+
return undefined;
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
/** What is wrong with a kind's own field declarations: a pattern that isn't a regular expression, or a default of the wrong type. */
|
|
668
|
+
function fieldDefaultProblems(fields: Record<string, KindField>): string[] {
|
|
669
|
+
const out: string[] = [];
|
|
670
|
+
const scalar = (name: string, f: ScalarKindField) => {
|
|
671
|
+
if (f.pattern !== undefined) {
|
|
672
|
+
try {
|
|
673
|
+
new RegExp(f.pattern, "u");
|
|
674
|
+
} catch {
|
|
675
|
+
out.push(`declares field ${name} with pattern ${f.pattern}, which is not a regular expression`);
|
|
676
|
+
return;
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
if (f.default === undefined) return;
|
|
680
|
+
const problem = scalarProblem(f, f.default);
|
|
681
|
+
if (problem) out.push(`declares field ${name} whose default ${problem}`);
|
|
682
|
+
};
|
|
683
|
+
for (const [name, f] of Object.entries(fields)) {
|
|
684
|
+
if (f.type === "object") for (const [inner, g] of Object.entries(f.properties)) scalar(`${name}.${inner}`, g);
|
|
685
|
+
else scalar(name, f);
|
|
686
|
+
}
|
|
687
|
+
return out;
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
/** One problem with a member's fields: the field's path under `fields` (`scripts/start`), and why. */
|
|
691
|
+
export interface MemberFieldProblem {
|
|
692
|
+
path: string;
|
|
693
|
+
message: string;
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
export interface MemberFields {
|
|
697
|
+
/** Every field the kind declares, set from the entry or its default (null when it has none); null when the kind declares no fields. */
|
|
698
|
+
fields: Record<string, FieldValue | null | Record<string, FieldValue | null>> | null;
|
|
699
|
+
problems: MemberFieldProblem[];
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
/**
|
|
703
|
+
* A member's fields (#3151): the ones its entry sets, checked against what
|
|
704
|
+
* its kind declares, with every other declared field at its default. A field
|
|
705
|
+
* the kind doesn't declare, or a value of the wrong type, is a problem, and
|
|
706
|
+
* the field reads as its default. A kind no registry knows has no fields to
|
|
707
|
+
* check against, so it reads as null with no problem (WSP003 reports it).
|
|
708
|
+
*/
|
|
709
|
+
export function resolveMemberFields(kind: MemberKind | undefined, given: Record<string, unknown> | null): MemberFields {
|
|
710
|
+
if (kind === undefined) return { fields: null, problems: [] };
|
|
711
|
+
const declared = kind.fields;
|
|
712
|
+
const problems: MemberFieldProblem[] = [];
|
|
713
|
+
if (declared === undefined) {
|
|
714
|
+
if (given !== null) problems.push({ path: "", message: `kind ${kind.name} declares no fields, and the entry sets ${Object.keys(given).join(", ") || "an empty fields block"}` });
|
|
715
|
+
return { fields: null, problems };
|
|
716
|
+
}
|
|
717
|
+
const set = given ?? {};
|
|
718
|
+
for (const name of Object.keys(set)) {
|
|
719
|
+
if (!(name in declared)) problems.push({ path: name, message: `kind ${kind.name} declares no field ${name}; its fields are ${Object.keys(declared).join(", ")}` });
|
|
720
|
+
}
|
|
721
|
+
const scalar = (path: string, field: ScalarKindField, value: unknown): FieldValue | null => {
|
|
722
|
+
if (value !== undefined) {
|
|
723
|
+
const problem = scalarProblem(field, value);
|
|
724
|
+
if (!problem) return value as FieldValue;
|
|
725
|
+
problems.push({ path, message: `field ${path.replace("/", ".")} ${problem}` });
|
|
726
|
+
}
|
|
727
|
+
return field.default ?? null;
|
|
728
|
+
};
|
|
729
|
+
const fields: NonNullable<MemberFields["fields"]> = {};
|
|
730
|
+
for (const [name, field] of Object.entries(declared)) {
|
|
731
|
+
if (field.type !== "object") {
|
|
732
|
+
fields[name] = scalar(name, field, set[name]);
|
|
733
|
+
continue;
|
|
734
|
+
}
|
|
735
|
+
const raw = set[name];
|
|
736
|
+
let inner: Record<string, unknown> = {};
|
|
737
|
+
if (raw !== undefined) {
|
|
738
|
+
if (raw !== null && typeof raw === "object" && !Array.isArray(raw)) inner = raw as Record<string, unknown>;
|
|
739
|
+
else problems.push({ path: name, message: `field ${name} is ${JSON.stringify(raw)}, and the field is an object` });
|
|
740
|
+
}
|
|
741
|
+
for (const key of Object.keys(inner)) {
|
|
742
|
+
if (!(key in field.properties)) problems.push({ path: `${name}/${key}`, message: `kind ${kind.name} declares no field ${name}.${key}; ${name} has ${Object.keys(field.properties).join(", ")}` });
|
|
743
|
+
}
|
|
744
|
+
fields[name] = Object.fromEntries(Object.entries(field.properties).map(([key, f]) => [key, scalar(`${name}/${key}`, f, inner[key])]));
|
|
745
|
+
}
|
|
746
|
+
return { fields, problems };
|
|
747
|
+
}
|