@intentius/chant 0.13.1 → 0.15.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/audit/catalog.d.ts +45 -5
- package/dist/audit/catalog.d.ts.map +1 -1
- package/dist/audit/proof.d.ts +3 -0
- package/dist/audit/proof.d.ts.map +1 -1
- package/dist/audit/report-model.d.ts +4 -1
- package/dist/audit/report-model.d.ts.map +1 -1
- package/dist/audit/report.d.ts +3 -0
- package/dist/audit/report.d.ts.map +1 -1
- package/dist/audit/rules-doc.d.ts +8 -2
- package/dist/audit/rules-doc.d.ts.map +1 -1
- package/dist/cli/commands/audit.d.ts.map +1 -1
- package/dist/cli/commands/doctor.d.ts.map +1 -1
- package/dist/cli/commands/lexicon-rolling-upgrade.d.ts +37 -0
- package/dist/cli/commands/lexicon-rolling-upgrade.d.ts.map +1 -0
- package/dist/cli/commands/lexicon-surface-diff.d.ts +48 -0
- package/dist/cli/commands/lexicon-surface-diff.d.ts.map +1 -0
- package/dist/cli/commands/lint.d.ts.map +1 -1
- package/dist/cli/commands/pinned-upgrade.d.ts +41 -0
- package/dist/cli/commands/pinned-upgrade.d.ts.map +1 -0
- package/dist/cli/handlers/build.d.ts.map +1 -1
- package/dist/cli/handlers/components.d.ts +39 -0
- package/dist/cli/handlers/components.d.ts.map +1 -0
- package/dist/cli/handlers/dev.d.ts +3 -0
- package/dist/cli/handlers/dev.d.ts.map +1 -1
- package/dist/cli/handlers/graph.d.ts +4 -2
- package/dist/cli/handlers/graph.d.ts.map +1 -1
- package/dist/cli/handlers/misc.d.ts.map +1 -1
- package/dist/cli/handlers/run.d.ts +49 -0
- package/dist/cli/handlers/run.d.ts.map +1 -1
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/registry.d.ts +35 -0
- package/dist/cli/registry.d.ts.map +1 -1
- package/dist/codegen/fetch.d.ts +22 -0
- package/dist/codegen/fetch.d.ts.map +1 -1
- package/dist/codegen/lexicon-regen.d.ts +110 -0
- package/dist/codegen/lexicon-regen.d.ts.map +1 -0
- package/dist/codegen/pinned-upgrade.d.ts +153 -0
- package/dist/codegen/pinned-upgrade.d.ts.map +1 -0
- package/dist/codegen/rolling-upgrade.d.ts +138 -0
- package/dist/codegen/rolling-upgrade.d.ts.map +1 -0
- package/dist/codegen/surface-snapshot.d.ts +173 -0
- package/dist/codegen/surface-snapshot.d.ts.map +1 -0
- package/dist/codegen/version-bump.d.ts +21 -0
- package/dist/codegen/version-bump.d.ts.map +1 -0
- package/dist/components/auto-release.d.ts +93 -0
- package/dist/components/auto-release.d.ts.map +1 -0
- package/dist/components/builders.d.ts +37 -0
- package/dist/components/builders.d.ts.map +1 -0
- package/dist/components/capability-plugin-loader.d.ts +111 -0
- package/dist/components/capability-plugin-loader.d.ts.map +1 -0
- package/dist/components/capability-plugin-schema.d.ts +24 -0
- package/dist/components/capability-plugin-schema.d.ts.map +1 -0
- package/dist/components/capability-plugin.d.ts +85 -0
- package/dist/components/capability-plugin.d.ts.map +1 -0
- package/dist/components/capability.d.ts +89 -0
- package/dist/components/capability.d.ts.map +1 -0
- package/dist/components/cli-support.d.ts +204 -0
- package/dist/components/cli-support.d.ts.map +1 -0
- package/dist/components/component.d.ts +179 -0
- package/dist/components/component.d.ts.map +1 -0
- package/dist/components/config-defaults.d.ts +41 -0
- package/dist/components/config-defaults.d.ts.map +1 -0
- package/dist/components/discover.d.ts +60 -0
- package/dist/components/discover.d.ts.map +1 -0
- package/dist/components/driver-output.d.ts +20 -0
- package/dist/components/driver-output.d.ts.map +1 -0
- package/dist/components/driver.d.ts +209 -0
- package/dist/components/driver.d.ts.map +1 -0
- package/dist/components/index.d.ts +22 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/manifest-persistence.d.ts +79 -0
- package/dist/components/manifest-persistence.d.ts.map +1 -0
- package/dist/components/pilots/alb-ecs.pilot.d.ts +27 -0
- package/dist/components/pilots/alb-ecs.pilot.d.ts.map +1 -0
- package/dist/components/pilots/dynamodb.pilot.d.ts +22 -0
- package/dist/components/pilots/dynamodb.pilot.d.ts.map +1 -0
- package/dist/components/pilots/jar-emr.pilot.d.ts +37 -0
- package/dist/components/pilots/jar-emr.pilot.d.ts.map +1 -0
- package/dist/components/pilots/lambda.pilot.d.ts +35 -0
- package/dist/components/pilots/lambda.pilot.d.ts.map +1 -0
- package/dist/components/pilots/neo4j-fanout.pilot.d.ts +17 -0
- package/dist/components/pilots/neo4j-fanout.pilot.d.ts.map +1 -0
- package/dist/components/pilots/project.d.ts +13 -0
- package/dist/components/pilots/project.d.ts.map +1 -0
- package/dist/components/presets/ecs-fargate.d.ts +59 -0
- package/dist/components/presets/ecs-fargate.d.ts.map +1 -0
- package/dist/components/presets/index.d.ts +29 -0
- package/dist/components/presets/index.d.ts.map +1 -0
- package/dist/components/presets/lambda.d.ts +35 -0
- package/dist/components/presets/lambda.d.ts.map +1 -0
- package/dist/components/presets/single-host-compose.d.ts +43 -0
- package/dist/components/presets/single-host-compose.d.ts.map +1 -0
- package/dist/components/registry.d.ts +29 -0
- package/dist/components/registry.d.ts.map +1 -0
- package/dist/components/starter-plugin.d.ts +51 -0
- package/dist/components/starter-plugin.d.ts.map +1 -0
- package/dist/components/temporal-codegen-loader.d.ts +27 -0
- package/dist/components/temporal-codegen-loader.d.ts.map +1 -0
- package/dist/components/verbs/__tests__/mock-cloud-executor.d.ts +35 -0
- package/dist/components/verbs/__tests__/mock-cloud-executor.d.ts.map +1 -0
- package/dist/components/verbs/__tests__/mock-process-runner.d.ts +45 -0
- package/dist/components/verbs/__tests__/mock-process-runner.d.ts.map +1 -0
- package/dist/components/verbs/__tests__/mock-sbom-generator.d.ts +33 -0
- package/dist/components/verbs/__tests__/mock-sbom-generator.d.ts.map +1 -0
- package/dist/components/verbs/bom-writer.d.ts +155 -0
- package/dist/components/verbs/bom-writer.d.ts.map +1 -0
- package/dist/components/verbs/build-archive.d.ts +205 -0
- package/dist/components/verbs/build-archive.d.ts.map +1 -0
- package/dist/components/verbs/build.d.ts +150 -0
- package/dist/components/verbs/build.d.ts.map +1 -0
- package/dist/components/verbs/cloud-executor.d.ts +88 -0
- package/dist/components/verbs/cloud-executor.d.ts.map +1 -0
- package/dist/components/verbs/component-bom.d.ts +103 -0
- package/dist/components/verbs/component-bom.d.ts.map +1 -0
- package/dist/components/verbs/index.d.ts +49 -0
- package/dist/components/verbs/index.d.ts.map +1 -0
- package/dist/components/verbs/license-policy.d.ts +56 -0
- package/dist/components/verbs/license-policy.d.ts.map +1 -0
- package/dist/components/verbs/lockfile-sbom-generator.d.ts +81 -0
- package/dist/components/verbs/lockfile-sbom-generator.d.ts.map +1 -0
- package/dist/components/verbs/process-runner.d.ts +64 -0
- package/dist/components/verbs/process-runner.d.ts.map +1 -0
- package/dist/components/verbs/reproducibility.d.ts +80 -0
- package/dist/components/verbs/reproducibility.d.ts.map +1 -0
- package/dist/components/verbs/sbom-generator.d.ts +157 -0
- package/dist/components/verbs/sbom-generator.d.ts.map +1 -0
- package/dist/components/verbs/sbom.d.ts +79 -0
- package/dist/components/verbs/sbom.d.ts.map +1 -0
- package/dist/components/verbs/shell.d.ts +35 -0
- package/dist/components/verbs/shell.d.ts.map +1 -0
- package/dist/components/verbs/sign.d.ts +222 -0
- package/dist/components/verbs/sign.d.ts.map +1 -0
- package/dist/components/verbs/stub.d.ts +18 -0
- package/dist/components/verbs/stub.d.ts.map +1 -0
- package/dist/components/verbs/tool-sbom-generator.d.ts +51 -0
- package/dist/components/verbs/tool-sbom-generator.d.ts.map +1 -0
- package/dist/components/verbs/verify.d.ts +106 -0
- package/dist/components/verbs/verify.d.ts.map +1 -0
- package/dist/components/verbs/vex.d.ts +65 -0
- package/dist/components/verbs/vex.d.ts.map +1 -0
- package/dist/components/verbs/vuln-gate.d.ts +91 -0
- package/dist/components/verbs/vuln-gate.d.ts.map +1 -0
- package/dist/components/verbs/vuln-scan.d.ts +116 -0
- package/dist/components/verbs/vuln-scan.d.ts.map +1 -0
- package/dist/components/verbs/wait-verify.d.ts +85 -0
- package/dist/components/verbs/wait-verify.d.ts.map +1 -0
- package/dist/config.d.ts +205 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/lexicon.d.ts +78 -0
- package/dist/lexicon.d.ts.map +1 -1
- package/dist/lifecycle/build-ledger-store.d.ts +121 -0
- package/dist/lifecycle/build-ledger-store.d.ts.map +1 -0
- package/dist/lifecycle/build-ledger.d.ts +225 -0
- package/dist/lifecycle/build-ledger.d.ts.map +1 -0
- package/dist/lifecycle/git.d.ts +84 -0
- package/dist/lifecycle/git.d.ts.map +1 -1
- package/dist/lifecycle/index.d.ts +5 -0
- package/dist/lifecycle/index.d.ts.map +1 -1
- package/dist/lifecycle/oras-referrer-lookup.d.ts +41 -0
- package/dist/lifecycle/oras-referrer-lookup.d.ts.map +1 -0
- package/dist/lifecycle/release-ledger.d.ts +122 -0
- package/dist/lifecycle/release-ledger.d.ts.map +1 -0
- package/dist/lifecycle/status.d.ts +150 -0
- package/dist/lifecycle/status.d.ts.map +1 -0
- package/dist/lint/component-checks.d.ts +95 -0
- package/dist/lint/component-checks.d.ts.map +1 -0
- package/dist/lint/engine.d.ts +23 -0
- package/dist/lint/engine.d.ts.map +1 -1
- package/dist/lint/presets/strict.json +8 -1
- package/dist/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-a.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-a.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-b.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-b.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp001/fail/orphan-lib.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp001/fail/orphan-lib.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp001/pass/emr-job.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp001/pass/emr-job.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp001/pass/jar-lib.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp001/pass/jar-lib.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp002/fail/search-service.component.d.ts +10 -0
- package/dist/lint/rules/__fixtures__/comp/comp002/fail/search-service.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp002/pass/jar-lib.component.d.ts +3 -0
- package/dist/lint/rules/__fixtures__/comp/comp002/pass/jar-lib.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp002/pass/search-service.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp002/pass/search-service.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp003/fail/migrator.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp003/fail/migrator.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp003/pass/migrator.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp003/pass/migrator.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp003/pass/orders-table.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp003/pass/orders-table.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp004/fail/neo4j-cluster.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp004/fail/neo4j-cluster.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp005/fail/search-service.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp005/fail/search-service.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp005/pass/search-service.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp005/pass/search-service.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp006/fail/legacy-tool.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp006/fail/legacy-tool.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp006/pass/legacy-tool.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp006/pass/legacy-tool.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp007/fail/inventory-table.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp007/fail/inventory-table.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp007/fail/orders-table.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp007/fail/orders-table.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp007/pass/orders-table.component.d.ts +3 -0
- package/dist/lint/rules/__fixtures__/comp/comp007/pass/orders-table.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp007/pass/search-service.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp007/pass/search-service.component.d.ts.map +1 -0
- package/dist/lint/rules/comp/comp001-publishes-never-applies.d.ts +20 -0
- package/dist/lint/rules/comp/comp001-publishes-never-applies.d.ts.map +1 -0
- package/dist/lint/rules/comp/comp002-dangling-wiring-ref.d.ts +28 -0
- package/dist/lint/rules/comp/comp002-dangling-wiring-ref.d.ts.map +1 -0
- package/dist/lint/rules/comp/comp003-mutating-no-rollback.d.ts +39 -0
- package/dist/lint/rules/comp/comp003-mutating-no-rollback.d.ts.map +1 -0
- package/dist/lint/rules/comp/comp004-gate-needs-temporal.d.ts +37 -0
- package/dist/lint/rules/comp/comp004-gate-needs-temporal.d.ts.map +1 -0
- package/dist/lint/rules/comp/comp005-capability-kind-is-noun.d.ts +43 -0
- package/dist/lint/rules/comp/comp005-capability-kind-is-noun.d.ts.map +1 -0
- package/dist/lint/rules/comp/comp006-shell-needs-reason.d.ts +22 -0
- package/dist/lint/rules/comp/comp006-shell-needs-reason.d.ts.map +1 -0
- package/dist/lint/rules/comp/comp007-composition-sprawl.d.ts +33 -0
- package/dist/lint/rules/comp/comp007-composition-sprawl.d.ts.map +1 -0
- package/dist/lint/rules/comp/index.d.ts +18 -0
- package/dist/lint/rules/comp/index.d.ts.map +1 -0
- package/dist/lint/rules/comp/support.d.ts +71 -0
- package/dist/lint/rules/comp/support.d.ts.map +1 -0
- package/dist/lsp/lexicon-providers.d.ts.map +1 -1
- package/dist/op/activity-registry.d.ts +11 -6
- package/dist/op/activity-registry.d.ts.map +1 -1
- package/dist/op/activity-runtime.d.ts +24 -0
- package/dist/op/activity-runtime.d.ts.map +1 -0
- package/dist/op/builders.d.ts +56 -0
- package/dist/op/builders.d.ts.map +1 -1
- package/dist/op/index.d.ts +2 -1
- package/dist/op/index.d.ts.map +1 -1
- package/dist/ownership.d.ts +20 -14
- package/dist/ownership.d.ts.map +1 -1
- package/package.json +14 -1
- package/src/audit/catalog.test.ts +74 -22
- package/src/audit/catalog.ts +74 -471
- package/src/audit/proof.ts +4 -2
- package/src/audit/report-html.test.ts +14 -7
- package/src/audit/report-model.ts +20 -9
- package/src/audit/report.test.ts +36 -13
- package/src/audit/report.ts +2 -0
- package/src/audit/rules-doc.test.ts +8 -6
- package/src/audit/rules-doc.ts +13 -5
- package/src/cli/commands/audit.ts +23 -18
- package/src/cli/commands/component-lint.test.ts +158 -0
- package/src/cli/commands/doctor.test.ts +116 -2
- package/src/cli/commands/doctor.ts +46 -0
- package/src/cli/commands/lexicon-rolling-upgrade.ts +198 -0
- package/src/cli/commands/lexicon-surface-diff.test.ts +104 -0
- package/src/cli/commands/lexicon-surface-diff.ts +185 -0
- package/src/cli/commands/lint.ts +142 -1
- package/src/cli/commands/pinned-upgrade.ts +204 -0
- package/src/cli/handlers/build.ts +58 -1
- package/src/cli/handlers/components.test.ts +504 -0
- package/src/cli/handlers/components.ts +404 -0
- package/src/cli/handlers/dev.ts +60 -1
- package/src/cli/handlers/graph.ts +47 -2
- package/src/cli/handlers/misc.ts +45 -1
- package/src/cli/handlers/run.test.ts +967 -3
- package/src/cli/handlers/run.ts +618 -11
- package/src/cli/main.test.ts +66 -0
- package/src/cli/main.ts +105 -2
- package/src/cli/registry.ts +35 -0
- package/src/codegen/fetch.test.ts +84 -3
- package/src/codegen/fetch.ts +76 -2
- package/src/codegen/lexicon-regen.test.ts +298 -0
- package/src/codegen/lexicon-regen.ts +545 -0
- package/src/codegen/pinned-upgrade.test.ts +399 -0
- package/src/codegen/pinned-upgrade.ts +423 -0
- package/src/codegen/rolling-upgrade.test.ts +333 -0
- package/src/codegen/rolling-upgrade.ts +320 -0
- package/src/codegen/surface-snapshot.test.ts +461 -0
- package/src/codegen/surface-snapshot.ts +546 -0
- package/src/codegen/version-bump.test.ts +47 -0
- package/src/codegen/version-bump.ts +39 -0
- package/src/components/README.md +130 -0
- package/src/components/SPRAWL-VALIDATION.md +181 -0
- package/src/components/__fixtures__/alb-ecs-service.json +51 -0
- package/src/components/__fixtures__/dynamodb-infra.json +32 -0
- package/src/components/__fixtures__/emr-job-consumer.json +26 -0
- package/src/components/__fixtures__/jar-lib-producer.json +16 -0
- package/src/components/__fixtures__/lambda-image-processor.json +28 -0
- package/src/components/__fixtures__/neo4j-fanout.json +34 -0
- package/src/components/__fixtures__/single-host-compose.json +29 -0
- package/src/components/auto-release.test.ts +217 -0
- package/src/components/auto-release.ts +216 -0
- package/src/components/builders.test.ts +45 -0
- package/src/components/builders.ts +71 -0
- package/src/components/capability-plugin-loader.ts +218 -0
- package/src/components/capability-plugin-schema.ts +56 -0
- package/src/components/capability-plugin.test.ts +235 -0
- package/src/components/capability-plugin.ts +108 -0
- package/src/components/capability.ts +117 -0
- package/src/components/cli-support.test.ts +579 -0
- package/src/components/cli-support.ts +481 -0
- package/src/components/component-schema.test.ts +265 -0
- package/src/components/component.schema.json +235 -0
- package/src/components/component.test.ts +251 -0
- package/src/components/component.ts +255 -0
- package/src/components/config-defaults.test.ts +263 -0
- package/src/components/config-defaults.ts +145 -0
- package/src/components/discover.test.ts +352 -0
- package/src/components/discover.ts +167 -0
- package/src/components/driver-output.ts +71 -0
- package/src/components/driver.test.ts +638 -0
- package/src/components/driver.ts +690 -0
- package/src/components/index.ts +113 -0
- package/src/components/manifest-persistence.test.ts +152 -0
- package/src/components/manifest-persistence.ts +164 -0
- package/src/components/pilots/README.md +33 -0
- package/src/components/pilots/alb-ecs.pilot.ts +63 -0
- package/src/components/pilots/dynamodb.pilot.ts +59 -0
- package/src/components/pilots/jar-emr.pilot.ts +69 -0
- package/src/components/pilots/lambda.pilot.ts +55 -0
- package/src/components/pilots/neo4j-fanout.pilot.ts +92 -0
- package/src/components/pilots/pilots-lint-clean.test.ts +78 -0
- package/src/components/pilots/pilots.test.ts +126 -0
- package/src/components/pilots/project.ts +13 -0
- package/src/components/presets/comp007-reduction.test.ts +122 -0
- package/src/components/presets/ecs-fargate.test.ts +84 -0
- package/src/components/presets/ecs-fargate.ts +103 -0
- package/src/components/presets/index.ts +32 -0
- package/src/components/presets/lambda.test.ts +35 -0
- package/src/components/presets/lambda.ts +53 -0
- package/src/components/presets/single-host-compose.test.ts +65 -0
- package/src/components/presets/single-host-compose.ts +64 -0
- package/src/components/registry.test.ts +112 -0
- package/src/components/registry.ts +37 -0
- package/src/components/starter-plugin.ts +105 -0
- package/src/components/temporal-codegen-loader.ts +41 -0
- package/src/components/verbs/__fixtures__/package-lock.json +45 -0
- package/src/components/verbs/__fixtures__/pom.xml +37 -0
- package/src/components/verbs/__fixtures__/schemas/cyclonedx-1.5.schema.json +3800 -0
- package/src/components/verbs/__fixtures__/schemas/cyclonedx-spdx-license.schema.json +621 -0
- package/src/components/verbs/__fixtures__/schemas/jsf-0.82.schema.json +240 -0
- package/src/components/verbs/__fixtures__/schemas/spdx-2.3.schema.json +740 -0
- package/src/components/verbs/__tests__/mock-cloud-executor.ts +102 -0
- package/src/components/verbs/__tests__/mock-process-runner.ts +79 -0
- package/src/components/verbs/__tests__/mock-sbom-generator.ts +85 -0
- package/src/components/verbs/bom-writer.test.ts +331 -0
- package/src/components/verbs/bom-writer.ts +386 -0
- package/src/components/verbs/build-archive.test.ts +251 -0
- package/src/components/verbs/build-archive.ts +296 -0
- package/src/components/verbs/build.test.ts +222 -0
- package/src/components/verbs/build.ts +252 -0
- package/src/components/verbs/cloud-executor.ts +181 -0
- package/src/components/verbs/component-bom.test.ts +219 -0
- package/src/components/verbs/component-bom.ts +189 -0
- package/src/components/verbs/index.ts +49 -0
- package/src/components/verbs/license-policy.ts +115 -0
- package/src/components/verbs/lockfile-sbom-generator.test.ts +195 -0
- package/src/components/verbs/lockfile-sbom-generator.ts +236 -0
- package/src/components/verbs/process-runner.test.ts +79 -0
- package/src/components/verbs/process-runner.ts +113 -0
- package/src/components/verbs/reproducibility.test.ts +24 -0
- package/src/components/verbs/reproducibility.ts +100 -0
- package/src/components/verbs/sbom-generator.test.ts +96 -0
- package/src/components/verbs/sbom-generator.ts +209 -0
- package/src/components/verbs/sbom.test.ts +184 -0
- package/src/components/verbs/sbom.ts +152 -0
- package/src/components/verbs/shell.test.ts +36 -0
- package/src/components/verbs/shell.ts +51 -0
- package/src/components/verbs/sign.test.ts +210 -0
- package/src/components/verbs/sign.ts +350 -0
- package/src/components/verbs/stub.ts +34 -0
- package/src/components/verbs/tool-sbom-generator.test.ts +194 -0
- package/src/components/verbs/tool-sbom-generator.ts +192 -0
- package/src/components/verbs/verify.test.ts +159 -0
- package/src/components/verbs/verify.ts +179 -0
- package/src/components/verbs/vex.ts +182 -0
- package/src/components/verbs/vuln-gate.test.ts +201 -0
- package/src/components/verbs/vuln-gate.ts +170 -0
- package/src/components/verbs/vuln-scan.test.ts +145 -0
- package/src/components/verbs/vuln-scan.ts +266 -0
- package/src/components/verbs/wait-verify.test.ts +111 -0
- package/src/components/verbs/wait-verify.ts +171 -0
- package/src/config.test.ts +74 -1
- package/src/config.ts +219 -0
- package/src/index.ts +32 -0
- package/src/lexicon.ts +88 -0
- package/src/lifecycle/build-ledger-store.test.ts +217 -0
- package/src/lifecycle/build-ledger-store.ts +165 -0
- package/src/lifecycle/build-ledger.test.ts +349 -0
- package/src/lifecycle/build-ledger.ts +305 -0
- package/src/lifecycle/git.test.ts +118 -0
- package/src/lifecycle/git.ts +149 -14
- package/src/lifecycle/index.ts +5 -0
- package/src/lifecycle/oras-referrer-lookup.test.ts +116 -0
- package/src/lifecycle/oras-referrer-lookup.ts +110 -0
- package/src/lifecycle/release-ledger.test.ts +209 -0
- package/src/lifecycle/release-ledger.ts +185 -0
- package/src/lifecycle/status.test.ts +330 -0
- package/src/lifecycle/status.ts +278 -0
- package/src/lint/component-checks.ts +148 -0
- package/src/lint/config.test.ts +21 -0
- package/src/lint/engine.ts +11 -2
- package/src/lint/presets/relaxed.json +8 -1
- package/src/lint/presets/strict.json +8 -1
- package/src/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-a.component.ts +9 -0
- package/src/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-b.component.ts +9 -0
- package/src/lint/rules/__fixtures__/comp/comp001/fail/orphan-lib.component.ts +11 -0
- package/src/lint/rules/__fixtures__/comp/comp001/pass/emr-job.component.ts +13 -0
- package/src/lint/rules/__fixtures__/comp/comp001/pass/jar-lib.component.ts +11 -0
- package/src/lint/rules/__fixtures__/comp/comp002/fail/search-service.component.ts +27 -0
- package/src/lint/rules/__fixtures__/comp/comp002/pass/jar-lib.component.ts +10 -0
- package/src/lint/rules/__fixtures__/comp/comp002/pass/search-service.component.ts +23 -0
- package/src/lint/rules/__fixtures__/comp/comp003/fail/migrator.component.ts +10 -0
- package/src/lint/rules/__fixtures__/comp/comp003/pass/migrator.component.ts +19 -0
- package/src/lint/rules/__fixtures__/comp/comp003/pass/orders-table.component.ts +10 -0
- package/src/lint/rules/__fixtures__/comp/comp004/fail/neo4j-cluster.component.ts +20 -0
- package/src/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.ts +23 -0
- package/src/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.ts +10 -0
- package/src/lint/rules/__fixtures__/comp/comp005/fail/search-service.component.ts +14 -0
- package/src/lint/rules/__fixtures__/comp/comp005/pass/search-service.component.ts +18 -0
- package/src/lint/rules/__fixtures__/comp/comp006/fail/legacy-tool.component.ts +10 -0
- package/src/lint/rules/__fixtures__/comp/comp006/pass/legacy-tool.component.ts +14 -0
- package/src/lint/rules/__fixtures__/comp/comp007/fail/inventory-table.component.ts +13 -0
- package/src/lint/rules/__fixtures__/comp/comp007/fail/orders-table.component.ts +13 -0
- package/src/lint/rules/__fixtures__/comp/comp007/pass/orders-table.component.ts +12 -0
- package/src/lint/rules/__fixtures__/comp/comp007/pass/search-service.component.ts +18 -0
- package/src/lint/rules/comp/comp.test.ts +378 -0
- package/src/lint/rules/comp/comp001-publishes-never-applies.ts +78 -0
- package/src/lint/rules/comp/comp002-dangling-wiring-ref.ts +94 -0
- package/src/lint/rules/comp/comp003-mutating-no-rollback.ts +115 -0
- package/src/lint/rules/comp/comp004-gate-needs-temporal.ts +66 -0
- package/src/lint/rules/comp/comp005-capability-kind-is-noun.ts +113 -0
- package/src/lint/rules/comp/comp006-shell-needs-reason.ts +55 -0
- package/src/lint/rules/comp/comp007-composition-sprawl.ts +71 -0
- package/src/lint/rules/comp/index.ts +37 -0
- package/src/lint/rules/comp/support.ts +173 -0
- package/src/lsp/lexicon-providers.test.ts +55 -0
- package/src/lsp/lexicon-providers.ts +13 -3
- package/src/op/activity-registry.test.ts +38 -0
- package/src/op/activity-registry.ts +31 -12
- package/src/op/activity-runtime.ts +73 -0
- package/src/op/builders.ts +92 -0
- package/src/op/index.ts +3 -1
- package/src/ownership.test.ts +24 -26
- package/src/ownership.ts +26 -38
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Discovery tests for the typed `Component` authoring form (#560, epic #551).
|
|
3
|
+
*
|
|
4
|
+
* Mirrors `../discovery/index.test.ts`'s style (write real `.ts` fixture
|
|
5
|
+
* files to a temp dir, run the discovery entrypoint, assert on the returned
|
|
6
|
+
* map) rather than `../op/discover.test.ts`'s (which discovers from the git
|
|
7
|
+
* root against real example files) since `discoverComponents`, like
|
|
8
|
+
* `discover()`, takes an explicit path rather than always walking from the
|
|
9
|
+
* repo root.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { describe, test, expect, beforeEach, afterEach } from "vitest";
|
|
13
|
+
import { mkdir, writeFile, rm } from "node:fs/promises";
|
|
14
|
+
import { join } from "node:path";
|
|
15
|
+
import { tmpdir } from "node:os";
|
|
16
|
+
import { discoverComponents } from "./discover";
|
|
17
|
+
|
|
18
|
+
describe("discoverComponents", () => {
|
|
19
|
+
let testDir: string;
|
|
20
|
+
|
|
21
|
+
beforeEach(async () => {
|
|
22
|
+
testDir = join(tmpdir(), `chant-component-discover-test-${Date.now()}-${Math.random()}`);
|
|
23
|
+
await mkdir(testDir, { recursive: true });
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
afterEach(async () => {
|
|
27
|
+
await rm(testDir, { recursive: true, force: true });
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test("returns empty result for an empty directory", async () => {
|
|
31
|
+
const result = await discoverComponents(testDir);
|
|
32
|
+
expect(result.components.size).toBe(0);
|
|
33
|
+
expect(result.sourceFiles).toEqual([]);
|
|
34
|
+
expect(result.errors).toEqual([]);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test("discovers a component from a single *.component.ts file", async () => {
|
|
38
|
+
await writeFile(
|
|
39
|
+
join(testDir, "search.component.ts"),
|
|
40
|
+
`
|
|
41
|
+
export const searchService = {
|
|
42
|
+
name: "search-service",
|
|
43
|
+
dependsOn: [],
|
|
44
|
+
deploy: [{ phase: "Apply", steps: [{ kind: "shell", command: "echo ok" }] }],
|
|
45
|
+
};
|
|
46
|
+
`,
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
const result = await discoverComponents(testDir);
|
|
50
|
+
|
|
51
|
+
expect(result.errors).toEqual([]);
|
|
52
|
+
expect(result.components.size).toBe(1);
|
|
53
|
+
expect(result.components.has("search-service")).toBe(true);
|
|
54
|
+
expect(result.components.get("search-service")?.exportName).toBe("searchService");
|
|
55
|
+
expect(result.sourceFiles).toHaveLength(1);
|
|
56
|
+
expect(result.sourceFiles[0]).toMatch(/search\.component\.ts$/);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
test("discovers multiple components across multiple files, keyed by component.name not export name", async () => {
|
|
60
|
+
await writeFile(
|
|
61
|
+
join(testDir, "a.component.ts"),
|
|
62
|
+
`
|
|
63
|
+
export const foo = {
|
|
64
|
+
name: "svc-a",
|
|
65
|
+
dependsOn: [],
|
|
66
|
+
deploy: [{ phase: "Apply", steps: [{ kind: "shell" }] }],
|
|
67
|
+
};
|
|
68
|
+
`,
|
|
69
|
+
);
|
|
70
|
+
await writeFile(
|
|
71
|
+
join(testDir, "b.component.ts"),
|
|
72
|
+
`
|
|
73
|
+
export const bar = {
|
|
74
|
+
name: "svc-b",
|
|
75
|
+
dependsOn: ["svc-a"],
|
|
76
|
+
deploy: [{ phase: "Apply", steps: [{ kind: "shell" }] }],
|
|
77
|
+
};
|
|
78
|
+
`,
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
const result = await discoverComponents(testDir);
|
|
82
|
+
|
|
83
|
+
expect(result.errors).toEqual([]);
|
|
84
|
+
expect(result.components.size).toBe(2);
|
|
85
|
+
expect([...result.components.keys()].sort()).toEqual(["svc-a", "svc-b"]);
|
|
86
|
+
expect(result.sourceFiles).toHaveLength(2);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
test("discovers multiple components exported from one file (any export name, not just default)", async () => {
|
|
90
|
+
await writeFile(
|
|
91
|
+
join(testDir, "multi.component.ts"),
|
|
92
|
+
`
|
|
93
|
+
export const first = {
|
|
94
|
+
name: "first-comp",
|
|
95
|
+
dependsOn: [],
|
|
96
|
+
deploy: [{ phase: "Apply", steps: [{ kind: "shell" }] }],
|
|
97
|
+
};
|
|
98
|
+
export const second = {
|
|
99
|
+
name: "second-comp",
|
|
100
|
+
dependsOn: [],
|
|
101
|
+
deploy: [{ phase: "Apply", steps: [{ kind: "shell" }] }],
|
|
102
|
+
};
|
|
103
|
+
`,
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
const result = await discoverComponents(testDir);
|
|
107
|
+
|
|
108
|
+
expect(result.errors).toEqual([]);
|
|
109
|
+
expect(result.components.size).toBe(2);
|
|
110
|
+
expect(result.components.has("first-comp")).toBe(true);
|
|
111
|
+
expect(result.components.has("second-comp")).toBe(true);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
test("ignores non-.component.ts files, even if they export a Component-shaped value", async () => {
|
|
115
|
+
await writeFile(
|
|
116
|
+
join(testDir, "not-a-component.ts"),
|
|
117
|
+
`
|
|
118
|
+
export const sneaky = {
|
|
119
|
+
name: "sneaky",
|
|
120
|
+
dependsOn: [],
|
|
121
|
+
deploy: [{ phase: "Apply", steps: [{ kind: "shell" }] }],
|
|
122
|
+
};
|
|
123
|
+
`,
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
const result = await discoverComponents(testDir);
|
|
127
|
+
|
|
128
|
+
expect(result.components.size).toBe(0);
|
|
129
|
+
expect(result.sourceFiles).toEqual([]);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
test("excludes .test.component.ts / .spec.component.ts files", async () => {
|
|
133
|
+
await writeFile(
|
|
134
|
+
join(testDir, "real.component.ts"),
|
|
135
|
+
`
|
|
136
|
+
export const real = {
|
|
137
|
+
name: "real",
|
|
138
|
+
dependsOn: [],
|
|
139
|
+
deploy: [{ phase: "Apply", steps: [{ kind: "shell" }] }],
|
|
140
|
+
};
|
|
141
|
+
`,
|
|
142
|
+
);
|
|
143
|
+
await writeFile(
|
|
144
|
+
join(testDir, "fixture.test.component.ts"),
|
|
145
|
+
`
|
|
146
|
+
export const testOnly = {
|
|
147
|
+
name: "test-only",
|
|
148
|
+
dependsOn: [],
|
|
149
|
+
deploy: [{ phase: "Apply", steps: [{ kind: "shell" }] }],
|
|
150
|
+
};
|
|
151
|
+
`,
|
|
152
|
+
);
|
|
153
|
+
|
|
154
|
+
const result = await discoverComponents(testDir);
|
|
155
|
+
|
|
156
|
+
expect(result.components.size).toBe(1);
|
|
157
|
+
expect(result.components.has("real")).toBe(true);
|
|
158
|
+
expect(result.components.has("test-only")).toBe(false);
|
|
159
|
+
expect(result.sourceFiles).toHaveLength(1);
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
test("ignores non-Component-shaped exports from a *.component.ts file", async () => {
|
|
163
|
+
await writeFile(
|
|
164
|
+
join(testDir, "mixed.component.ts"),
|
|
165
|
+
`
|
|
166
|
+
export const realComponent = {
|
|
167
|
+
name: "real-component",
|
|
168
|
+
dependsOn: [],
|
|
169
|
+
deploy: [{ phase: "Apply", steps: [{ kind: "shell" }] }],
|
|
170
|
+
};
|
|
171
|
+
export const helper = { foo: "bar" };
|
|
172
|
+
export const CONST = 42;
|
|
173
|
+
`,
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
const result = await discoverComponents(testDir);
|
|
177
|
+
|
|
178
|
+
expect(result.components.size).toBe(1);
|
|
179
|
+
expect(result.components.has("real-component")).toBe(true);
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
test("recurses into nested directories", async () => {
|
|
183
|
+
const subDir = join(testDir, "services", "search");
|
|
184
|
+
await mkdir(subDir, { recursive: true });
|
|
185
|
+
await writeFile(
|
|
186
|
+
join(subDir, "search.component.ts"),
|
|
187
|
+
`
|
|
188
|
+
export const searchService = {
|
|
189
|
+
name: "search-service",
|
|
190
|
+
dependsOn: [],
|
|
191
|
+
deploy: [{ phase: "Apply", steps: [{ kind: "shell" }] }],
|
|
192
|
+
};
|
|
193
|
+
`,
|
|
194
|
+
);
|
|
195
|
+
|
|
196
|
+
const result = await discoverComponents(testDir);
|
|
197
|
+
|
|
198
|
+
expect(result.components.size).toBe(1);
|
|
199
|
+
expect(result.components.has("search-service")).toBe(true);
|
|
200
|
+
expect(result.sourceFiles[0]).toMatch(/search\.component\.ts$/);
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
test("skips node_modules", async () => {
|
|
204
|
+
const nm = join(testDir, "node_modules", "some-pkg");
|
|
205
|
+
await mkdir(nm, { recursive: true });
|
|
206
|
+
await writeFile(
|
|
207
|
+
join(nm, "vendored.component.ts"),
|
|
208
|
+
`
|
|
209
|
+
export const vendored = {
|
|
210
|
+
name: "vendored",
|
|
211
|
+
dependsOn: [],
|
|
212
|
+
deploy: [{ phase: "Apply", steps: [{ kind: "shell" }] }],
|
|
213
|
+
};
|
|
214
|
+
`,
|
|
215
|
+
);
|
|
216
|
+
|
|
217
|
+
const result = await discoverComponents(testDir);
|
|
218
|
+
|
|
219
|
+
expect(result.components.size).toBe(0);
|
|
220
|
+
expect(result.sourceFiles).toEqual([]);
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
test("reports a duplicate component name across two files as a resolution error", async () => {
|
|
224
|
+
await writeFile(
|
|
225
|
+
join(testDir, "one.component.ts"),
|
|
226
|
+
`
|
|
227
|
+
export const svc = {
|
|
228
|
+
name: "dup",
|
|
229
|
+
dependsOn: [],
|
|
230
|
+
deploy: [{ phase: "Apply", steps: [{ kind: "shell" }] }],
|
|
231
|
+
};
|
|
232
|
+
`,
|
|
233
|
+
);
|
|
234
|
+
await writeFile(
|
|
235
|
+
join(testDir, "two.component.ts"),
|
|
236
|
+
`
|
|
237
|
+
export const svcAgain = {
|
|
238
|
+
name: "dup",
|
|
239
|
+
dependsOn: [],
|
|
240
|
+
deploy: [{ phase: "Apply", steps: [{ kind: "shell" }] }],
|
|
241
|
+
};
|
|
242
|
+
`,
|
|
243
|
+
);
|
|
244
|
+
|
|
245
|
+
const result = await discoverComponents(testDir);
|
|
246
|
+
|
|
247
|
+
expect(result.errors.length).toBeGreaterThan(0);
|
|
248
|
+
expect(result.errors[0]?.type).toBe("resolution");
|
|
249
|
+
expect(result.errors[0]?.message).toMatch(/Duplicate component name "dup"/);
|
|
250
|
+
// The first one found is kept; discovery continues rather than aborting.
|
|
251
|
+
expect(result.components.has("dup")).toBe(true);
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
test("collects an import error (syntax error) and continues processing other files", async () => {
|
|
255
|
+
await writeFile(
|
|
256
|
+
join(testDir, "good.component.ts"),
|
|
257
|
+
`
|
|
258
|
+
export const good = {
|
|
259
|
+
name: "good",
|
|
260
|
+
dependsOn: [],
|
|
261
|
+
deploy: [{ phase: "Apply", steps: [{ kind: "shell" }] }],
|
|
262
|
+
};
|
|
263
|
+
`,
|
|
264
|
+
);
|
|
265
|
+
await writeFile(
|
|
266
|
+
join(testDir, "bad.component.ts"),
|
|
267
|
+
`
|
|
268
|
+
export const bad = {
|
|
269
|
+
name: "bad"
|
|
270
|
+
dependsOn: [],
|
|
271
|
+
};
|
|
272
|
+
`,
|
|
273
|
+
);
|
|
274
|
+
|
|
275
|
+
const result = await discoverComponents(testDir);
|
|
276
|
+
|
|
277
|
+
expect(result.components.has("good")).toBe(true);
|
|
278
|
+
expect(result.errors.some((e) => e.type === "import")).toBe(true);
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
test("the first chant.config.ts encountered becomes the source root and is still scanned", async () => {
|
|
282
|
+
// Matches findInfraFiles's own rule: the *first* config directory found
|
|
283
|
+
// becomes `sourceRoot` and is descended into, same as any other
|
|
284
|
+
// directory — the skip only applies to a *second* nested config found
|
|
285
|
+
// after that (see the next test).
|
|
286
|
+
const childDir = join(testDir, "child-project");
|
|
287
|
+
await mkdir(childDir, { recursive: true });
|
|
288
|
+
await writeFile(join(childDir, "chant.config.ts"), `export default {};`);
|
|
289
|
+
await writeFile(
|
|
290
|
+
join(childDir, "child.component.ts"),
|
|
291
|
+
`
|
|
292
|
+
export const childSvc = {
|
|
293
|
+
name: "child-svc",
|
|
294
|
+
dependsOn: [],
|
|
295
|
+
deploy: [{ phase: "Apply", steps: [{ kind: "shell" }] }],
|
|
296
|
+
};
|
|
297
|
+
`,
|
|
298
|
+
);
|
|
299
|
+
await writeFile(
|
|
300
|
+
join(testDir, "root.component.ts"),
|
|
301
|
+
`
|
|
302
|
+
export const rootSvc = {
|
|
303
|
+
name: "root-svc",
|
|
304
|
+
dependsOn: [],
|
|
305
|
+
deploy: [{ phase: "Apply", steps: [{ kind: "shell" }] }],
|
|
306
|
+
};
|
|
307
|
+
`,
|
|
308
|
+
);
|
|
309
|
+
|
|
310
|
+
const result = await discoverComponents(testDir);
|
|
311
|
+
|
|
312
|
+
expect(result.components.has("root-svc")).toBe(true);
|
|
313
|
+
expect(result.components.has("child-svc")).toBe(true);
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
test("a second nested chant.config.ts (a true child project) is not descended into", async () => {
|
|
317
|
+
const firstConfigDir = join(testDir, "first-config");
|
|
318
|
+
const nestedChildProject = join(firstConfigDir, "nested-child-project");
|
|
319
|
+
await mkdir(nestedChildProject, { recursive: true });
|
|
320
|
+
await writeFile(join(firstConfigDir, "chant.config.ts"), `export default {};`);
|
|
321
|
+
await writeFile(join(nestedChildProject, "chant.config.ts"), `export default {};`);
|
|
322
|
+
await writeFile(
|
|
323
|
+
join(firstConfigDir, "first.component.ts"),
|
|
324
|
+
`
|
|
325
|
+
export const firstSvc = {
|
|
326
|
+
name: "first-svc",
|
|
327
|
+
dependsOn: [],
|
|
328
|
+
deploy: [{ phase: "Apply", steps: [{ kind: "shell" }] }],
|
|
329
|
+
};
|
|
330
|
+
`,
|
|
331
|
+
);
|
|
332
|
+
await writeFile(
|
|
333
|
+
join(nestedChildProject, "nested.component.ts"),
|
|
334
|
+
`
|
|
335
|
+
export const nestedSvc = {
|
|
336
|
+
name: "nested-svc",
|
|
337
|
+
dependsOn: [],
|
|
338
|
+
deploy: [{ phase: "Apply", steps: [{ kind: "shell" }] }],
|
|
339
|
+
};
|
|
340
|
+
`,
|
|
341
|
+
);
|
|
342
|
+
|
|
343
|
+
const result = await discoverComponents(testDir);
|
|
344
|
+
|
|
345
|
+
// first-config/ has no config above it, so it becomes the source root
|
|
346
|
+
// and is scanned; nested-child-project/'s own chant.config.ts is the
|
|
347
|
+
// *second* config encountered, so it is treated as a separate project
|
|
348
|
+
// scope and not descended into.
|
|
349
|
+
expect(result.components.has("first-svc")).toBe(true);
|
|
350
|
+
expect(result.components.has("nested-svc")).toBe(false);
|
|
351
|
+
});
|
|
352
|
+
});
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Component discovery — Phase 2 (#560, epic #551).
|
|
3
|
+
*
|
|
4
|
+
* Mirrors chant's existing declarable discovery
|
|
5
|
+
* (`../discovery/index.ts`'s `discover()`, built on `findInfraFiles`) as
|
|
6
|
+
* closely as a structurally distinct type allows, and borrows its
|
|
7
|
+
* file-suffix convention from Op discovery
|
|
8
|
+
* (`../op/discover.ts`'s `discoverOps()`, `*.op.ts`): a component is any
|
|
9
|
+
* `Component`-shaped value (see `./component.ts`'s `isComponent`) exported
|
|
10
|
+
* (by any export name, not just `default`) from a `*.component.ts` file.
|
|
11
|
+
*
|
|
12
|
+
* Why a dedicated convention rather than folding into `discover()`:
|
|
13
|
+
* `Declarable` (`../declarable.ts`) is a lexicon-resource marker —
|
|
14
|
+
* `{ lexicon, entityType, kind, [DECLARABLE_MARKER]: true }` — and a
|
|
15
|
+
* `Component` has none of that shape (no `lexicon`, and its `deploy`
|
|
16
|
+
* composition is data the capability driver interprets, not a serializable
|
|
17
|
+
* lexicon resource). Reusing `collectEntities`/`isDeclarable` would mean
|
|
18
|
+
* either stretching the `Declarable` marker to cover an unrelated shape or
|
|
19
|
+
* silently ignoring components during the existing walk. A parallel,
|
|
20
|
+
* purpose-built collector keeps both conventions simple: `*.ts` + the
|
|
21
|
+
* `Declarable` marker for resources, `*.component.ts` + the `Component`
|
|
22
|
+
* shape for components — exactly how `*.op.ts` is already a parallel,
|
|
23
|
+
* purpose-built convention for Ops.
|
|
24
|
+
*
|
|
25
|
+
* Filename convention (`*.component.ts`) is documented here rather than
|
|
26
|
+
* inferred from export shape alone so a project can `grep` for its
|
|
27
|
+
* components the same way it can for `*.op.ts` files, and so discovery does
|
|
28
|
+
* not have to import (and risk side-effecting) every `.ts` file in the
|
|
29
|
+
* project looking for stray `Component`-shaped objects.
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
import { readdir } from "node:fs/promises";
|
|
33
|
+
import { join, resolve } from "node:path";
|
|
34
|
+
import { pathToFileURL } from "node:url";
|
|
35
|
+
import { existsSync } from "node:fs";
|
|
36
|
+
import { DiscoveryError } from "../errors";
|
|
37
|
+
import { isComponent, type Component } from "./component";
|
|
38
|
+
|
|
39
|
+
/** One discovered component, paired with the file it was exported from. */
|
|
40
|
+
export interface DiscoveredComponent {
|
|
41
|
+
component: Component;
|
|
42
|
+
/** The export name the component was found under (informational; components are keyed by their own `.name`, not this). */
|
|
43
|
+
exportName: string;
|
|
44
|
+
filePath: string;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface ComponentDiscoveryResult {
|
|
48
|
+
/** Discovered components, keyed by `component.name` (the schema identity), not by export name or file. */
|
|
49
|
+
components: Map<string, DiscoveredComponent>;
|
|
50
|
+
/** Every `*.component.ts` file that was scanned. */
|
|
51
|
+
sourceFiles: string[];
|
|
52
|
+
errors: DiscoveryError[];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Recursively find every `*.component.ts` file under `path`, the same
|
|
57
|
+
* child-project boundary rule `findInfraFiles` (`../discovery/files.ts`)
|
|
58
|
+
* uses: a subdirectory with its own `chant.config.ts` is a separate scope
|
|
59
|
+
* once the outer project's own source root has been established.
|
|
60
|
+
*/
|
|
61
|
+
async function findComponentFiles(path: string): Promise<string[]> {
|
|
62
|
+
const files: string[] = [];
|
|
63
|
+
let sourceRoot: string | null = null;
|
|
64
|
+
|
|
65
|
+
async function scanDirectory(dir: string): Promise<void> {
|
|
66
|
+
let entries;
|
|
67
|
+
try {
|
|
68
|
+
entries = await readdir(dir, { withFileTypes: true });
|
|
69
|
+
} catch {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
for (const entry of entries) {
|
|
74
|
+
const fullPath = join(dir, entry.name);
|
|
75
|
+
|
|
76
|
+
if (entry.isDirectory()) {
|
|
77
|
+
// Skip dependency and tool/VCS directories: component sources never live
|
|
78
|
+
// in them, and descending in is both wasted work and a correctness bug —
|
|
79
|
+
// e.g. a CI runner like gitlab-ci-local stages a copy of the project
|
|
80
|
+
// under `.gitlab-ci-local/`, which discovery would otherwise pick up as
|
|
81
|
+
// duplicate component names alongside the originals.
|
|
82
|
+
if (entry.name === "node_modules" || entry.name.startsWith(".")) continue;
|
|
83
|
+
|
|
84
|
+
const configPath = join(fullPath, "chant.config.ts");
|
|
85
|
+
if (existsSync(configPath)) {
|
|
86
|
+
if (sourceRoot === null) {
|
|
87
|
+
sourceRoot = fullPath;
|
|
88
|
+
} else {
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
await scanDirectory(fullPath);
|
|
93
|
+
} else if (
|
|
94
|
+
entry.isFile() &&
|
|
95
|
+
entry.name.endsWith(".component.ts") &&
|
|
96
|
+
!entry.name.endsWith(".test.component.ts") &&
|
|
97
|
+
!entry.name.endsWith(".spec.component.ts")
|
|
98
|
+
) {
|
|
99
|
+
files.push(fullPath);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
await scanDirectory(path);
|
|
105
|
+
return files;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Discover every `Component` declared under `path`: scan for `*.component.ts`
|
|
110
|
+
* files, import each, and collect every export whose value satisfies
|
|
111
|
+
* `isComponent` (any export name — not just `default` — so a file may
|
|
112
|
+
* declare several related components, matching how a resource file can
|
|
113
|
+
* export several `Declarable`s). Duplicate `component.name` across files (or
|
|
114
|
+
* within one file) is a discovery error, matching `collectEntities`'s
|
|
115
|
+
* duplicate-export handling and `discoverOps`'s duplicate-Op-name handling —
|
|
116
|
+
* except the identity compared is the schema-level `name` field, since two
|
|
117
|
+
* different export bindings could otherwise declare the same component name
|
|
118
|
+
* and silently collide at deploy time.
|
|
119
|
+
*/
|
|
120
|
+
export async function discoverComponents(path: string): Promise<ComponentDiscoveryResult> {
|
|
121
|
+
const errors: DiscoveryError[] = [];
|
|
122
|
+
const sourceFiles = await findComponentFiles(path);
|
|
123
|
+
const components = new Map<string, DiscoveredComponent>();
|
|
124
|
+
const nameToFile = new Map<string, string>();
|
|
125
|
+
|
|
126
|
+
for (const filePath of sourceFiles) {
|
|
127
|
+
let exports: Record<string, unknown>;
|
|
128
|
+
try {
|
|
129
|
+
// Resolve to an absolute file:// URL before importing. A relative
|
|
130
|
+
// `filePath` (e.g. from `chant build --components --generate`, which passes
|
|
131
|
+
// a bare "." path) would otherwise be treated by `import()` as a bare
|
|
132
|
+
// package specifier and fail with "Cannot find package 'x.component.ts'".
|
|
133
|
+
exports = await import(pathToFileURL(resolve(filePath)).href);
|
|
134
|
+
} catch (err) {
|
|
135
|
+
errors.push(new DiscoveryError(filePath, err instanceof Error ? err.message : String(err), "import"));
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
for (const [exportName, value] of Object.entries(exports)) {
|
|
140
|
+
if (!isComponent(value)) continue;
|
|
141
|
+
|
|
142
|
+
const existingFile = nameToFile.get(value.name);
|
|
143
|
+
if (existingFile && existingFile !== filePath) {
|
|
144
|
+
errors.push(
|
|
145
|
+
new DiscoveryError(
|
|
146
|
+
filePath,
|
|
147
|
+
`Duplicate component name "${value.name}" in ${filePath} and ${existingFile}`,
|
|
148
|
+
"resolution",
|
|
149
|
+
),
|
|
150
|
+
);
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
const existing = components.get(value.name);
|
|
154
|
+
if (existing && existing.component !== value) {
|
|
155
|
+
errors.push(
|
|
156
|
+
new DiscoveryError(filePath, `Duplicate component name "${value.name}" in ${filePath}`, "resolution"),
|
|
157
|
+
);
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
nameToFile.set(value.name, filePath);
|
|
162
|
+
components.set(value.name, { component: value, exportName, filePath });
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return { components, sourceFiles, errors };
|
|
167
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Renderers for `chant run --components` (#585) — the interpret driver's CLI
|
|
3
|
+
* output. Mirrors `../op/local-output.ts`'s `renderHuman`/`renderJson` pair
|
|
4
|
+
* for Ops: both consume the same `DriverRunResult` (`./driver.ts`);
|
|
5
|
+
* `renderDriverHuman` is the default (logs to stderr), `renderDriverJson`
|
|
6
|
+
* prints the machine-readable result as JSON on stdout and nothing else.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { DriverRunResult, DriverStepRecord } from "./driver";
|
|
10
|
+
|
|
11
|
+
type Writer = (line: string) => void;
|
|
12
|
+
|
|
13
|
+
const stderr: Writer = (line) => process.stderr.write(line + "\n");
|
|
14
|
+
const stdout: Writer = (line) => process.stdout.write(line + "\n");
|
|
15
|
+
|
|
16
|
+
function formatDuration(ms: number): string {
|
|
17
|
+
return ms < 1000 ? `${ms}ms` : `${(ms / 1000).toFixed(1)}s`;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function statusMark(status: DriverStepRecord["status"]): string {
|
|
21
|
+
switch (status) {
|
|
22
|
+
case "ok":
|
|
23
|
+
return "✓";
|
|
24
|
+
case "fail":
|
|
25
|
+
return "✗";
|
|
26
|
+
case "rolled-back":
|
|
27
|
+
return "↺";
|
|
28
|
+
default:
|
|
29
|
+
return "•";
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Render an interpret-driver run result as human-readable progress. Defaults
|
|
35
|
+
* to stderr so stdout stays clean for piping (the `--json` renderer owns
|
|
36
|
+
* stdout). Groups records by component, then by phase, matching the driver's
|
|
37
|
+
* own wave/phase/step nesting.
|
|
38
|
+
*/
|
|
39
|
+
export function renderDriverHuman(result: DriverRunResult, write: Writer = stderr): void {
|
|
40
|
+
for (const componentResult of result.results) {
|
|
41
|
+
write(`[component] ${componentResult.component}`);
|
|
42
|
+
let currentPhase: string | undefined;
|
|
43
|
+
for (const record of componentResult.records) {
|
|
44
|
+
if (record.phase !== currentPhase) {
|
|
45
|
+
currentPhase = record.phase;
|
|
46
|
+
write(` [phase] ${currentPhase}`);
|
|
47
|
+
}
|
|
48
|
+
const mark = statusMark(record.status);
|
|
49
|
+
if (record.status === "skipped") {
|
|
50
|
+
write(` ${mark} ${record.kind} skipped`);
|
|
51
|
+
} else {
|
|
52
|
+
write(` ${mark} ${record.kind} ${formatDuration(record.durationMs)}`);
|
|
53
|
+
}
|
|
54
|
+
if (record.error) {
|
|
55
|
+
write(` ${record.error}`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
write(componentResult.ok ? ` component "${componentResult.component}" completed` : ` component "${componentResult.component}" failed`);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (result.ok) {
|
|
62
|
+
write(`interpret run completed (${result.order.length} component(s))`);
|
|
63
|
+
} else {
|
|
64
|
+
write(`interpret run failed at component "${result.failedComponent}"`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** Render an interpret-driver run result as JSON on stdout (and nothing else on stdout). */
|
|
69
|
+
export function renderDriverJson(result: DriverRunResult, write: Writer = stdout): void {
|
|
70
|
+
write(JSON.stringify(result));
|
|
71
|
+
}
|