@endora-commerce/cli 0.100.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +37 -0
- package/dist/bin/endora.d.ts +28 -0
- package/dist/bin/endora.d.ts.map +1 -0
- package/dist/bin/endora.js +926 -0
- package/dist/bin/endora.js.map +1 -0
- package/dist/check/estate.d.ts +189 -0
- package/dist/check/estate.d.ts.map +1 -0
- package/dist/check/estate.js +1037 -0
- package/dist/check/estate.js.map +1 -0
- package/dist/check/hosts.d.ts +25 -0
- package/dist/check/hosts.d.ts.map +1 -0
- package/dist/check/hosts.js +1347 -0
- package/dist/check/hosts.js.map +1 -0
- package/dist/check/index.d.ts +60 -0
- package/dist/check/index.d.ts.map +1 -0
- package/dist/check/index.js +111 -0
- package/dist/check/index.js.map +1 -0
- package/dist/check/layout.d.ts +136 -0
- package/dist/check/layout.d.ts.map +1 -0
- package/dist/check/layout.js +262 -0
- package/dist/check/layout.js.map +1 -0
- package/dist/check/ledger.d.ts +98 -0
- package/dist/check/ledger.d.ts.map +1 -0
- package/dist/check/ledger.js +173 -0
- package/dist/check/ledger.js.map +1 -0
- package/dist/check/peer-owners.d.ts +116 -0
- package/dist/check/peer-owners.d.ts.map +1 -0
- package/dist/check/peer-owners.js +225 -0
- package/dist/check/peer-owners.js.map +1 -0
- package/dist/check/report.d.ts +33 -0
- package/dist/check/report.d.ts.map +1 -0
- package/dist/check/report.js +107 -0
- package/dist/check/report.js.map +1 -0
- package/dist/check/run.d.ts +147 -0
- package/dist/check/run.d.ts.map +1 -0
- package/dist/check/run.js +111 -0
- package/dist/check/run.js.map +1 -0
- package/dist/checks.d.ts +17 -0
- package/dist/checks.d.ts.map +1 -0
- package/dist/checks.js +17 -0
- package/dist/checks.js.map +1 -0
- package/dist/dev/index.d.ts +83 -0
- package/dist/dev/index.d.ts.map +1 -0
- package/dist/dev/index.js +298 -0
- package/dist/dev/index.js.map +1 -0
- package/dist/generate/divergence.d.ts +38 -0
- package/dist/generate/divergence.d.ts.map +1 -0
- package/dist/generate/divergence.js +237 -0
- package/dist/generate/divergence.js.map +1 -0
- package/dist/generate/index.d.ts +90 -0
- package/dist/generate/index.d.ts.map +1 -0
- package/dist/generate/index.js +369 -0
- package/dist/generate/index.js.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +35 -0
- package/dist/index.js.map +1 -0
- package/dist/inputs/declaration.d.ts +18 -0
- package/dist/inputs/declaration.d.ts.map +1 -0
- package/dist/inputs/declaration.js +64 -0
- package/dist/inputs/declaration.js.map +1 -0
- package/dist/inputs/env-file.d.ts +73 -0
- package/dist/inputs/env-file.d.ts.map +1 -0
- package/dist/inputs/env-file.js +134 -0
- package/dist/inputs/env-file.js.map +1 -0
- package/dist/inputs/prompt.d.ts +21 -0
- package/dist/inputs/prompt.d.ts.map +1 -0
- package/dist/inputs/prompt.js +59 -0
- package/dist/inputs/prompt.js.map +1 -0
- package/dist/inputs/resolve.d.ts +163 -0
- package/dist/inputs/resolve.d.ts.map +1 -0
- package/dist/inputs/resolve.js +290 -0
- package/dist/inputs/resolve.js.map +1 -0
- package/dist/install/host.d.ts +27 -0
- package/dist/install/host.d.ts.map +1 -0
- package/dist/install/host.js +90 -0
- package/dist/install/host.js.map +1 -0
- package/dist/install/index.d.ts +173 -0
- package/dist/install/index.d.ts.map +1 -0
- package/dist/install/index.js +793 -0
- package/dist/install/index.js.map +1 -0
- package/dist/install/wizard.d.ts +144 -0
- package/dist/install/wizard.d.ts.map +1 -0
- package/dist/install/wizard.js +362 -0
- package/dist/install/wizard.js.map +1 -0
- package/dist/lib/admin-artefacts.d.ts +70 -0
- package/dist/lib/admin-artefacts.d.ts.map +1 -0
- package/dist/lib/admin-artefacts.js +354 -0
- package/dist/lib/admin-artefacts.js.map +1 -0
- package/dist/lib/admin-surfaces.d.ts +298 -0
- package/dist/lib/admin-surfaces.d.ts.map +1 -0
- package/dist/lib/admin-surfaces.js +669 -0
- package/dist/lib/admin-surfaces.js.map +1 -0
- package/dist/lib/delegated-composer.d.ts +85 -0
- package/dist/lib/delegated-composer.d.ts.map +1 -0
- package/dist/lib/delegated-composer.js +241 -0
- package/dist/lib/delegated-composer.js.map +1 -0
- package/dist/lib/divergence-artefacts.d.ts +305 -0
- package/dist/lib/divergence-artefacts.d.ts.map +1 -0
- package/dist/lib/divergence-artefacts.js +828 -0
- package/dist/lib/divergence-artefacts.js.map +1 -0
- package/dist/lib/divergence.d.ts +337 -0
- package/dist/lib/divergence.d.ts.map +1 -0
- package/dist/lib/divergence.js +1005 -0
- package/dist/lib/divergence.js.map +1 -0
- package/dist/lib/docs-artefacts.d.ts +395 -0
- package/dist/lib/docs-artefacts.d.ts.map +1 -0
- package/dist/lib/docs-artefacts.js +781 -0
- package/dist/lib/docs-artefacts.js.map +1 -0
- package/dist/lib/emitted-exports.d.ts +21 -0
- package/dist/lib/emitted-exports.d.ts.map +1 -0
- package/dist/lib/emitted-exports.js +96 -0
- package/dist/lib/emitted-exports.js.map +1 -0
- package/dist/lib/emitted-freshness.d.ts +112 -0
- package/dist/lib/emitted-freshness.d.ts.map +1 -0
- package/dist/lib/emitted-freshness.js +288 -0
- package/dist/lib/emitted-freshness.js.map +1 -0
- package/dist/lib/entity-index-artefact.d.ts +95 -0
- package/dist/lib/entity-index-artefact.d.ts.map +1 -0
- package/dist/lib/entity-index-artefact.js +210 -0
- package/dist/lib/entity-index-artefact.js.map +1 -0
- package/dist/lib/instance-build-inputs.d.ts +108 -0
- package/dist/lib/instance-build-inputs.d.ts.map +1 -0
- package/dist/lib/instance-build-inputs.js +165 -0
- package/dist/lib/instance-build-inputs.js.map +1 -0
- package/dist/lib/module-docs.d.ts +473 -0
- package/dist/lib/module-docs.d.ts.map +1 -0
- package/dist/lib/module-docs.js +711 -0
- package/dist/lib/module-docs.js.map +1 -0
- package/dist/lib/module-package-subpaths.d.ts +56 -0
- package/dist/lib/module-package-subpaths.d.ts.map +1 -0
- package/dist/lib/module-package-subpaths.js +223 -0
- package/dist/lib/module-package-subpaths.js.map +1 -0
- package/dist/lib/module-packages.d.ts +200 -0
- package/dist/lib/module-packages.d.ts.map +1 -0
- package/dist/lib/module-packages.js +580 -0
- package/dist/lib/module-packages.js.map +1 -0
- package/dist/lib/module-population.d.ts +129 -0
- package/dist/lib/module-population.d.ts.map +1 -0
- package/dist/lib/module-population.js +172 -0
- package/dist/lib/module-population.js.map +1 -0
- package/dist/lib/module-roots.d.ts +337 -0
- package/dist/lib/module-roots.d.ts.map +1 -0
- package/dist/lib/module-roots.js +586 -0
- package/dist/lib/module-roots.js.map +1 -0
- package/dist/lib/nested-checkouts.d.ts +33 -0
- package/dist/lib/nested-checkouts.d.ts.map +1 -0
- package/dist/lib/nested-checkouts.js +160 -0
- package/dist/lib/nested-checkouts.js.map +1 -0
- package/dist/lib/platform-root.d.ts +43 -0
- package/dist/lib/platform-root.d.ts.map +1 -0
- package/dist/lib/platform-root.js +134 -0
- package/dist/lib/platform-root.js.map +1 -0
- package/dist/lib/platform-surface.d.ts +235 -0
- package/dist/lib/platform-surface.d.ts.map +1 -0
- package/dist/lib/platform-surface.js +393 -0
- package/dist/lib/platform-surface.js.map +1 -0
- package/dist/lib/port-registrations.d.ts +223 -0
- package/dist/lib/port-registrations.d.ts.map +1 -0
- package/dist/lib/port-registrations.js +532 -0
- package/dist/lib/port-registrations.js.map +1 -0
- package/dist/lib/read-size.d.ts +154 -0
- package/dist/lib/read-size.d.ts.map +1 -0
- package/dist/lib/read-size.js +182 -0
- package/dist/lib/read-size.js.map +1 -0
- package/dist/lib/registration-owners.d.ts +79 -0
- package/dist/lib/registration-owners.d.ts.map +1 -0
- package/dist/lib/registration-owners.js +77 -0
- package/dist/lib/registration-owners.js.map +1 -0
- package/dist/lib/release-index.d.ts +53 -0
- package/dist/lib/release-index.d.ts.map +1 -0
- package/dist/lib/release-index.js +162 -0
- package/dist/lib/release-index.js.map +1 -0
- package/dist/lib/repeating-timers.d.ts +79 -0
- package/dist/lib/repeating-timers.d.ts.map +1 -0
- package/dist/lib/repeating-timers.js +189 -0
- package/dist/lib/repeating-timers.js.map +1 -0
- package/dist/lib/source-text.d.ts +34 -0
- package/dist/lib/source-text.d.ts.map +1 -0
- package/dist/lib/source-text.js +80 -0
- package/dist/lib/source-text.js.map +1 -0
- package/dist/lib/specifiers.d.ts +20 -0
- package/dist/lib/specifiers.d.ts.map +1 -0
- package/dist/lib/specifiers.js +130 -0
- package/dist/lib/specifiers.js.map +1 -0
- package/dist/lib/sql-tables.d.ts +166 -0
- package/dist/lib/sql-tables.d.ts.map +1 -0
- package/dist/lib/sql-tables.js +464 -0
- package/dist/lib/sql-tables.js.map +1 -0
- package/dist/lib/switchable-modules.d.ts +54 -0
- package/dist/lib/switchable-modules.d.ts.map +1 -0
- package/dist/lib/switchable-modules.js +104 -0
- package/dist/lib/switchable-modules.js.map +1 -0
- package/dist/lib/tailwind-sources.d.ts +136 -0
- package/dist/lib/tailwind-sources.d.ts.map +1 -0
- package/dist/lib/tailwind-sources.js +307 -0
- package/dist/lib/tailwind-sources.js.map +1 -0
- package/dist/lib/ui-layer.d.ts +54 -0
- package/dist/lib/ui-layer.d.ts.map +1 -0
- package/dist/lib/ui-layer.js +57 -0
- package/dist/lib/ui-layer.js.map +1 -0
- package/dist/lib/workspace-packages.d.ts +186 -0
- package/dist/lib/workspace-packages.d.ts.map +1 -0
- package/dist/lib/workspace-packages.js +351 -0
- package/dist/lib/workspace-packages.js.map +1 -0
- package/dist/new-instance/deploy.d.ts +211 -0
- package/dist/new-instance/deploy.d.ts.map +1 -0
- package/dist/new-instance/deploy.js +1381 -0
- package/dist/new-instance/deploy.js.map +1 -0
- package/dist/new-instance/docs-toolchain.d.ts +66 -0
- package/dist/new-instance/docs-toolchain.d.ts.map +1 -0
- package/dist/new-instance/docs-toolchain.js +69 -0
- package/dist/new-instance/docs-toolchain.js.map +1 -0
- package/dist/new-instance/host.d.ts +124 -0
- package/dist/new-instance/host.d.ts.map +1 -0
- package/dist/new-instance/host.js +276 -0
- package/dist/new-instance/host.js.map +1 -0
- package/dist/new-instance/index.d.ts +118 -0
- package/dist/new-instance/index.d.ts.map +1 -0
- package/dist/new-instance/index.js +567 -0
- package/dist/new-instance/index.js.map +1 -0
- package/dist/new-instance/modules.d.ts +188 -0
- package/dist/new-instance/modules.d.ts.map +1 -0
- package/dist/new-instance/modules.js +392 -0
- package/dist/new-instance/modules.js.map +1 -0
- package/dist/new-instance/template.d.ts +505 -0
- package/dist/new-instance/template.d.ts.map +1 -0
- package/dist/new-instance/template.js +1886 -0
- package/dist/new-instance/template.js.map +1 -0
- package/dist/new-module/emit.d.ts +67 -0
- package/dist/new-module/emit.d.ts.map +1 -0
- package/dist/new-module/emit.js +1393 -0
- package/dist/new-module/emit.js.map +1 -0
- package/dist/new-module/host.d.ts +67 -0
- package/dist/new-module/host.d.ts.map +1 -0
- package/dist/new-module/host.js +224 -0
- package/dist/new-module/host.js.map +1 -0
- package/dist/new-module/index.d.ts +32 -0
- package/dist/new-module/index.d.ts.map +1 -0
- package/dist/new-module/index.js +193 -0
- package/dist/new-module/index.js.map +1 -0
- package/dist/new-module/spec.d.ts +188 -0
- package/dist/new-module/spec.d.ts.map +1 -0
- package/dist/new-module/spec.js +404 -0
- package/dist/new-module/spec.js.map +1 -0
- package/dist/new-module/text.d.ts +15 -0
- package/dist/new-module/text.d.ts.map +1 -0
- package/dist/new-module/text.js +22 -0
- package/dist/new-module/text.js.map +1 -0
- package/dist/new-storefront/dockerfile.d.ts +20 -0
- package/dist/new-storefront/dockerfile.d.ts.map +1 -0
- package/dist/new-storefront/dockerfile.js +131 -0
- package/dist/new-storefront/dockerfile.js.map +1 -0
- package/dist/new-storefront/gitignore.d.ts +23 -0
- package/dist/new-storefront/gitignore.d.ts.map +1 -0
- package/dist/new-storefront/gitignore.js +39 -0
- package/dist/new-storefront/gitignore.js.map +1 -0
- package/dist/new-storefront/index.d.ts +93 -0
- package/dist/new-storefront/index.d.ts.map +1 -0
- package/dist/new-storefront/index.js +329 -0
- package/dist/new-storefront/index.js.map +1 -0
- package/dist/new-storefront/npmrc.d.ts +98 -0
- package/dist/new-storefront/npmrc.d.ts.map +1 -0
- package/dist/new-storefront/npmrc.js +217 -0
- package/dist/new-storefront/npmrc.js.map +1 -0
- package/dist/new-storefront/reference.d.ts +189 -0
- package/dist/new-storefront/reference.d.ts.map +1 -0
- package/dist/new-storefront/reference.js +430 -0
- package/dist/new-storefront/reference.js.map +1 -0
- package/dist/new-storefront/rewrite.d.ts +171 -0
- package/dist/new-storefront/rewrite.d.ts.map +1 -0
- package/dist/new-storefront/rewrite.js +701 -0
- package/dist/new-storefront/rewrite.js.map +1 -0
- package/dist/release-index.json +284 -0
- package/dist/rules/action-route-permissions.d.ts +141 -0
- package/dist/rules/action-route-permissions.d.ts.map +1 -0
- package/dist/rules/action-route-permissions.js +556 -0
- package/dist/rules/action-route-permissions.js.map +1 -0
- package/dist/rules/bundle-pairing.d.ts +74 -0
- package/dist/rules/bundle-pairing.d.ts.map +1 -0
- package/dist/rules/bundle-pairing.js +281 -0
- package/dist/rules/bundle-pairing.js.map +1 -0
- package/dist/rules/channel-resolution.d.ts +17 -0
- package/dist/rules/channel-resolution.d.ts.map +1 -0
- package/dist/rules/channel-resolution.js +382 -0
- package/dist/rules/channel-resolution.js.map +1 -0
- package/dist/rules/command-coverage.d.ts +210 -0
- package/dist/rules/command-coverage.d.ts.map +1 -0
- package/dist/rules/command-coverage.js +714 -0
- package/dist/rules/command-coverage.js.map +1 -0
- package/dist/rules/container-imports.d.ts +60 -0
- package/dist/rules/container-imports.d.ts.map +1 -0
- package/dist/rules/container-imports.js +158 -0
- package/dist/rules/container-imports.js.map +1 -0
- package/dist/rules/default-language-prose.d.ts +212 -0
- package/dist/rules/default-language-prose.d.ts.map +1 -0
- package/dist/rules/default-language-prose.js +710 -0
- package/dist/rules/default-language-prose.js.map +1 -0
- package/dist/rules/diacritic-folds.d.ts +238 -0
- package/dist/rules/diacritic-folds.d.ts.map +1 -0
- package/dist/rules/diacritic-folds.js +681 -0
- package/dist/rules/diacritic-folds.js.map +1 -0
- package/dist/rules/entity-tenant-classification.d.ts +171 -0
- package/dist/rules/entity-tenant-classification.d.ts.map +1 -0
- package/dist/rules/entity-tenant-classification.js +323 -0
- package/dist/rules/entity-tenant-classification.js.map +1 -0
- package/dist/rules/entry-presence.d.ts +142 -0
- package/dist/rules/entry-presence.d.ts.map +1 -0
- package/dist/rules/entry-presence.js +339 -0
- package/dist/rules/entry-presence.js.map +1 -0
- package/dist/rules/entry-scope.d.ts +91 -0
- package/dist/rules/entry-scope.d.ts.map +1 -0
- package/dist/rules/entry-scope.js +404 -0
- package/dist/rules/entry-scope.js.map +1 -0
- package/dist/rules/env-inputs.d.ts +222 -0
- package/dist/rules/env-inputs.d.ts.map +1 -0
- package/dist/rules/env-inputs.js +951 -0
- package/dist/rules/env-inputs.js.map +1 -0
- package/dist/rules/kernel-boundary.d.ts +37 -0
- package/dist/rules/kernel-boundary.d.ts.map +1 -0
- package/dist/rules/kernel-boundary.js +195 -0
- package/dist/rules/kernel-boundary.js.map +1 -0
- package/dist/rules/nul-bytes.d.ts +233 -0
- package/dist/rules/nul-bytes.d.ts.map +1 -0
- package/dist/rules/nul-bytes.js +332 -0
- package/dist/rules/nul-bytes.js.map +1 -0
- package/dist/rules/platform-surface.d.ts +479 -0
- package/dist/rules/platform-surface.d.ts.map +1 -0
- package/dist/rules/platform-surface.js +749 -0
- package/dist/rules/platform-surface.js.map +1 -0
- package/dist/rules/port-catches.d.ts +225 -0
- package/dist/rules/port-catches.d.ts.map +1 -0
- package/dist/rules/port-catches.js +1374 -0
- package/dist/rules/port-catches.js.map +1 -0
- package/dist/rules/port-shape.d.ts +213 -0
- package/dist/rules/port-shape.d.ts.map +1 -0
- package/dist/rules/port-shape.js +670 -0
- package/dist/rules/port-shape.js.map +1 -0
- package/dist/rules/queue-names.d.ts +108 -0
- package/dist/rules/queue-names.d.ts.map +1 -0
- package/dist/rules/queue-names.js +395 -0
- package/dist/rules/queue-names.js.map +1 -0
- package/dist/rules/singleton-identity.d.ts +205 -0
- package/dist/rules/singleton-identity.d.ts.map +1 -0
- package/dist/rules/singleton-identity.js +830 -0
- package/dist/rules/singleton-identity.js.map +1 -0
- package/dist/rules/subscribe-seam.d.ts +121 -0
- package/dist/rules/subscribe-seam.d.ts.map +1 -0
- package/dist/rules/subscribe-seam.js +594 -0
- package/dist/rules/subscribe-seam.js.map +1 -0
- package/dist/rules/transaction-context.d.ts +40 -0
- package/dist/rules/transaction-context.d.ts.map +1 -0
- package/dist/rules/transaction-context.js +294 -0
- package/dist/rules/transaction-context.js.map +1 -0
- package/package.json +59 -0
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a package's **peers** own — the one input Phase 3's owner-map rules share
|
|
3
|
+
* (`specs/101-endora-check/contracts/package-scope-layout.md` §2, the `owner
|
|
4
|
+
* maps` row, and §5's Tier B).
|
|
5
|
+
*
|
|
6
|
+
* ## The measurement that made this file necessary
|
|
7
|
+
*
|
|
8
|
+
* `check:port-catches` was assessed as needing no peer input at all, on the
|
|
9
|
+
* reasoning that its alias table is *"a fixpoint over port-carrying values"*
|
|
10
|
+
* seeded on a resolution — and a consuming package writes its own resolutions.
|
|
11
|
+
* That reasoning is wrong, and the code says where: the seed is
|
|
12
|
+
* `lazyPort(ctx, '<name>')` **whose name is already in `portOwners`**, and
|
|
13
|
+
* `portOwners` is built from `di.providePort` in a file that declares
|
|
14
|
+
* `registerModule` — the **owner's** file, not the consumer's. A package that
|
|
15
|
+
* only consumes ports has an empty seed.
|
|
16
|
+
*
|
|
17
|
+
* Measured over this repository's module packages, because the hazard is worth
|
|
18
|
+
* having as evidence rather than as an assertion: the whole-tree run attributes
|
|
19
|
+
* **226** guarded-port sites to 41 packages; the same analysis run over each
|
|
20
|
+
* package **in isolation** finds **19**, in 10 packages. **31 of the 41 lose
|
|
21
|
+
* every site**, and they include all four PIM connectors (17–19 sites each) and
|
|
22
|
+
* `product_feeds` (24) — which is to say the integration-heavy modules a
|
|
23
|
+
* package-scope host exists to judge, the ones whose ports are almost all
|
|
24
|
+
* somebody else's. A package-scope host without this input would have printed
|
|
25
|
+
* `violations=0` over exactly the packages it was built to judge.
|
|
26
|
+
*
|
|
27
|
+
* The reasoning that produced the wrong assessment is worth naming too, since it
|
|
28
|
+
* is not specific to this rule: it came from **the rule's header comment**, which
|
|
29
|
+
* describes the alias table as a fixpoint over port-carrying values and is
|
|
30
|
+
* accurate — and says nothing about the seed. The predicate is six lines of
|
|
31
|
+
* `isProxyCall`. A written statement trusted in place of the thing it describes is
|
|
32
|
+
* the failure this whole estate exists against, and it reaches the people
|
|
33
|
+
* building the estate too.
|
|
34
|
+
*
|
|
35
|
+
* ## Both discovery halves are needed, and a reader will not notice deleting one
|
|
36
|
+
*
|
|
37
|
+
* Stated here because neither tree alone shows it: the **installed** walk finds
|
|
38
|
+
* nothing in this repository, because every module package is a workspace member
|
|
39
|
+
* symlinked into `node_modules` and the walk correctly rejects a candidate whose
|
|
40
|
+
* real path leaves the `node_modules` it was reached through. The **workspace**
|
|
41
|
+
* walk finds nothing in a client instance, which has no workspace. So a reader
|
|
42
|
+
* who deletes either half sees a green run in whichever tree they are standing
|
|
43
|
+
* in, and the other tree's hosts go quietly blind.
|
|
44
|
+
*
|
|
45
|
+
* ## Why this is synchronous, takes no new dependency, and duplicates nothing
|
|
46
|
+
*
|
|
47
|
+
* The obvious route — resolve `@endora-commerce/platform/packages` out of the
|
|
48
|
+
* subject's tree and call `scanNodeModulesRoots` — is async, and
|
|
49
|
+
* {@link PackageRuleHost} is synchronous by Phase 1's design. It is also
|
|
50
|
+
* unnecessary: `lib/module-packages.ts` already carries an **installed** walk
|
|
51
|
+
* beside its workspace one, with its own recorded reason for being separate from
|
|
52
|
+
* the platform's boot walk and an explicit agreement on the three rules that
|
|
53
|
+
* decide an answer. So the discovery exists, in this package, and this file adds
|
|
54
|
+
* none of its own.
|
|
55
|
+
*
|
|
56
|
+
* What it adds is the *reading*: a peer's registrations come out of its emitted
|
|
57
|
+
* `./backend`-ish artefact as **text through the compiler API**, using the same
|
|
58
|
+
* `providedPortNames` / `registeredNames` the repository hosts use over source.
|
|
59
|
+
* No import of a stranger's composition, no platform, no ORM, no `await`.
|
|
60
|
+
*
|
|
61
|
+
* ## Two sources, because a peer can be either
|
|
62
|
+
*
|
|
63
|
+
* A peer is a workspace member (this checkout, and a stranger's monorepo) **or**
|
|
64
|
+
* a package installed under a `node_modules` (a stranger's instance). That is
|
|
65
|
+
* `module-roots.ts`' own two-sourced derivation with the population narrowed, and
|
|
66
|
+
* both halves are needed: in *this* repository every module package is a
|
|
67
|
+
* workspace member symlinked into `node_modules`, which the installed walk
|
|
68
|
+
* correctly rejects as `links-out-of-node-modules`, so the installed half alone
|
|
69
|
+
* would find nothing here and the workspace half alone would find nothing in a
|
|
70
|
+
* client instance.
|
|
71
|
+
*
|
|
72
|
+
* ## It never answers "nobody owns it"
|
|
73
|
+
*
|
|
74
|
+
* A name no peer provides is **not attributed to nobody** — it is *unattributed*,
|
|
75
|
+
* and the count of those is what a rule turns into `sources=owners:<n>/<m>` on
|
|
76
|
+
* its own `read:` line and, when `n` is zero, into `unreadable`. That is the
|
|
77
|
+
* whole of §5's *"a port whose owner module is not installed is `unreadable` for
|
|
78
|
+
* that edge, never `unowned`"*, expressed in the idiom the estate already prints
|
|
79
|
+
* rather than in a sentence a reader has to trust.
|
|
80
|
+
*/
|
|
81
|
+
import { type ModulePackage } from '../lib/module-packages.js';
|
|
82
|
+
import type { PackageLayout } from './layout.js';
|
|
83
|
+
/** A peer whose declarations could not be read, named with the reason. */
|
|
84
|
+
export interface UnreadablePeer {
|
|
85
|
+
readonly name: string;
|
|
86
|
+
readonly moduleId: string;
|
|
87
|
+
/** In the words the rule's own line uses. */
|
|
88
|
+
readonly reason: string;
|
|
89
|
+
}
|
|
90
|
+
export interface PeerOwners {
|
|
91
|
+
/** Peer module packages found, the subject excluded. */
|
|
92
|
+
readonly peers: readonly ModulePackage[];
|
|
93
|
+
/** Gated port name → the module id whose artefact provides it. */
|
|
94
|
+
readonly portOwners: ReadonlyMap<string, string>;
|
|
95
|
+
/** Container registration name → the module id whose artefact registers it. */
|
|
96
|
+
readonly containerOwners: ReadonlyMap<string, string>;
|
|
97
|
+
/** Emitted artefacts opened — the `files=` contribution. */
|
|
98
|
+
readonly filesRead: number;
|
|
99
|
+
/** Peers that claimed to be modules and could not be read. Never a silent zero. */
|
|
100
|
+
readonly unreadable: readonly UnreadablePeer[];
|
|
101
|
+
/** Which half, or halves, the peers came from. Printed, so a zero is legible. */
|
|
102
|
+
readonly discovery: 'installed' | 'workspace' | 'both' | 'none';
|
|
103
|
+
}
|
|
104
|
+
/** The empty answer — a package standing alone, with nothing installed beside it. */
|
|
105
|
+
export declare const NO_PEER_OWNERS: PeerOwners;
|
|
106
|
+
/**
|
|
107
|
+
* Read what the subject's peers own.
|
|
108
|
+
*
|
|
109
|
+
* Every failure is named. A peer that publishes no composing artefact is
|
|
110
|
+
* *readable and empty* — it registers nothing, by its own `exports` map — while a
|
|
111
|
+
* peer whose artefact is absent is **unreadable**, because a package that was
|
|
112
|
+
* never built is a package whose registrations this run cannot see and must not
|
|
113
|
+
* credit with none.
|
|
114
|
+
*/
|
|
115
|
+
export declare function readPeerOwners(layout: PackageLayout): PeerOwners;
|
|
116
|
+
//# sourceMappingURL=peer-owners.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"peer-owners.d.ts","sourceRoot":"","sources":["../../src/check/peer-owners.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+EG;AAKH,OAAO,EAGL,KAAK,aAAa,EACnB,MAAM,2BAA2B,CAAC;AAInC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,0EAA0E;AAC1E,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,6CAA6C;IAC7C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,UAAU;IACzB,wDAAwD;IACxD,QAAQ,CAAC,KAAK,EAAE,SAAS,aAAa,EAAE,CAAC;IACzC,kEAAkE;IAClE,QAAQ,CAAC,UAAU,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjD,+EAA+E;IAC/E,QAAQ,CAAC,eAAe,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtD,4DAA4D;IAC5D,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,mFAAmF;IACnF,QAAQ,CAAC,UAAU,EAAE,SAAS,cAAc,EAAE,CAAC;IAC/C,iFAAiF;IACjF,QAAQ,CAAC,SAAS,EAAE,WAAW,GAAG,WAAW,GAAG,MAAM,GAAG,MAAM,CAAC;CACjE;AAED,qFAAqF;AACrF,eAAO,MAAM,cAAc,EAAE,UAO5B,CAAC;AA6CF;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,aAAa,GAAG,UAAU,CAiFhE"}
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a package's **peers** own — the one input Phase 3's owner-map rules share
|
|
3
|
+
* (`specs/101-endora-check/contracts/package-scope-layout.md` §2, the `owner
|
|
4
|
+
* maps` row, and §5's Tier B).
|
|
5
|
+
*
|
|
6
|
+
* ## The measurement that made this file necessary
|
|
7
|
+
*
|
|
8
|
+
* `check:port-catches` was assessed as needing no peer input at all, on the
|
|
9
|
+
* reasoning that its alias table is *"a fixpoint over port-carrying values"*
|
|
10
|
+
* seeded on a resolution — and a consuming package writes its own resolutions.
|
|
11
|
+
* That reasoning is wrong, and the code says where: the seed is
|
|
12
|
+
* `lazyPort(ctx, '<name>')` **whose name is already in `portOwners`**, and
|
|
13
|
+
* `portOwners` is built from `di.providePort` in a file that declares
|
|
14
|
+
* `registerModule` — the **owner's** file, not the consumer's. A package that
|
|
15
|
+
* only consumes ports has an empty seed.
|
|
16
|
+
*
|
|
17
|
+
* Measured over this repository's module packages, because the hazard is worth
|
|
18
|
+
* having as evidence rather than as an assertion: the whole-tree run attributes
|
|
19
|
+
* **226** guarded-port sites to 41 packages; the same analysis run over each
|
|
20
|
+
* package **in isolation** finds **19**, in 10 packages. **31 of the 41 lose
|
|
21
|
+
* every site**, and they include all four PIM connectors (17–19 sites each) and
|
|
22
|
+
* `product_feeds` (24) — which is to say the integration-heavy modules a
|
|
23
|
+
* package-scope host exists to judge, the ones whose ports are almost all
|
|
24
|
+
* somebody else's. A package-scope host without this input would have printed
|
|
25
|
+
* `violations=0` over exactly the packages it was built to judge.
|
|
26
|
+
*
|
|
27
|
+
* The reasoning that produced the wrong assessment is worth naming too, since it
|
|
28
|
+
* is not specific to this rule: it came from **the rule's header comment**, which
|
|
29
|
+
* describes the alias table as a fixpoint over port-carrying values and is
|
|
30
|
+
* accurate — and says nothing about the seed. The predicate is six lines of
|
|
31
|
+
* `isProxyCall`. A written statement trusted in place of the thing it describes is
|
|
32
|
+
* the failure this whole estate exists against, and it reaches the people
|
|
33
|
+
* building the estate too.
|
|
34
|
+
*
|
|
35
|
+
* ## Both discovery halves are needed, and a reader will not notice deleting one
|
|
36
|
+
*
|
|
37
|
+
* Stated here because neither tree alone shows it: the **installed** walk finds
|
|
38
|
+
* nothing in this repository, because every module package is a workspace member
|
|
39
|
+
* symlinked into `node_modules` and the walk correctly rejects a candidate whose
|
|
40
|
+
* real path leaves the `node_modules` it was reached through. The **workspace**
|
|
41
|
+
* walk finds nothing in a client instance, which has no workspace. So a reader
|
|
42
|
+
* who deletes either half sees a green run in whichever tree they are standing
|
|
43
|
+
* in, and the other tree's hosts go quietly blind.
|
|
44
|
+
*
|
|
45
|
+
* ## Why this is synchronous, takes no new dependency, and duplicates nothing
|
|
46
|
+
*
|
|
47
|
+
* The obvious route — resolve `@endora-commerce/platform/packages` out of the
|
|
48
|
+
* subject's tree and call `scanNodeModulesRoots` — is async, and
|
|
49
|
+
* {@link PackageRuleHost} is synchronous by Phase 1's design. It is also
|
|
50
|
+
* unnecessary: `lib/module-packages.ts` already carries an **installed** walk
|
|
51
|
+
* beside its workspace one, with its own recorded reason for being separate from
|
|
52
|
+
* the platform's boot walk and an explicit agreement on the three rules that
|
|
53
|
+
* decide an answer. So the discovery exists, in this package, and this file adds
|
|
54
|
+
* none of its own.
|
|
55
|
+
*
|
|
56
|
+
* What it adds is the *reading*: a peer's registrations come out of its emitted
|
|
57
|
+
* `./backend`-ish artefact as **text through the compiler API**, using the same
|
|
58
|
+
* `providedPortNames` / `registeredNames` the repository hosts use over source.
|
|
59
|
+
* No import of a stranger's composition, no platform, no ORM, no `await`.
|
|
60
|
+
*
|
|
61
|
+
* ## Two sources, because a peer can be either
|
|
62
|
+
*
|
|
63
|
+
* A peer is a workspace member (this checkout, and a stranger's monorepo) **or**
|
|
64
|
+
* a package installed under a `node_modules` (a stranger's instance). That is
|
|
65
|
+
* `module-roots.ts`' own two-sourced derivation with the population narrowed, and
|
|
66
|
+
* both halves are needed: in *this* repository every module package is a
|
|
67
|
+
* workspace member symlinked into `node_modules`, which the installed walk
|
|
68
|
+
* correctly rejects as `links-out-of-node-modules`, so the installed half alone
|
|
69
|
+
* would find nothing here and the workspace half alone would find nothing in a
|
|
70
|
+
* client instance.
|
|
71
|
+
*
|
|
72
|
+
* ## It never answers "nobody owns it"
|
|
73
|
+
*
|
|
74
|
+
* A name no peer provides is **not attributed to nobody** — it is *unattributed*,
|
|
75
|
+
* and the count of those is what a rule turns into `sources=owners:<n>/<m>` on
|
|
76
|
+
* its own `read:` line and, when `n` is zero, into `unreadable`. That is the
|
|
77
|
+
* whole of §5's *"a port whose owner module is not installed is `unreadable` for
|
|
78
|
+
* that edge, never `unowned`"*, expressed in the idiom the estate already prints
|
|
79
|
+
* rather than in a sentence a reader has to trust.
|
|
80
|
+
*/
|
|
81
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
82
|
+
import { dirname, join, resolve } from 'node:path';
|
|
83
|
+
import { discoverModulePackages, scanInstalledModulePackages, } from '../lib/module-packages.js';
|
|
84
|
+
import { declaresRegisterModule } from '../lib/module-roots.js';
|
|
85
|
+
import { providedPortNames, registeredNames } from '../lib/port-registrations.js';
|
|
86
|
+
/** The empty answer — a package standing alone, with nothing installed beside it. */
|
|
87
|
+
export const NO_PEER_OWNERS = {
|
|
88
|
+
peers: [],
|
|
89
|
+
portOwners: new Map(),
|
|
90
|
+
containerOwners: new Map(),
|
|
91
|
+
filesRead: 0,
|
|
92
|
+
unreadable: [],
|
|
93
|
+
discovery: 'none',
|
|
94
|
+
};
|
|
95
|
+
/**
|
|
96
|
+
* Every ancestor of the package that could hold peers, nearest first.
|
|
97
|
+
*
|
|
98
|
+
* "Could hold peers" is *has a `node_modules`* or *declares a workspace* — both
|
|
99
|
+
* questions about the tree rather than about a path anybody spells. The walk
|
|
100
|
+
* stops at the filesystem root; a package in a temp directory yields none, which
|
|
101
|
+
* is the honest answer and the one the fixtures rely on.
|
|
102
|
+
*/
|
|
103
|
+
function candidateRoots(packageRoot) {
|
|
104
|
+
const roots = [];
|
|
105
|
+
let dir = resolve(packageRoot);
|
|
106
|
+
for (;;) {
|
|
107
|
+
if (existsSync(join(dir, 'node_modules')) || existsSync(join(dir, 'pnpm-workspace.yaml'))) {
|
|
108
|
+
roots.push(dir);
|
|
109
|
+
}
|
|
110
|
+
const parent = dirname(dir);
|
|
111
|
+
if (parent === dir)
|
|
112
|
+
return roots;
|
|
113
|
+
dir = parent;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* The subpath whose artefact **composes** the peer, derived rather than spelled.
|
|
118
|
+
*
|
|
119
|
+
* `declaresRegisterModule` is `generate-composer.ts`'s own marker, so the
|
|
120
|
+
* composer, the repository hosts and this file cannot disagree about which file
|
|
121
|
+
* composes a module. Nothing here names `./backend` (D-100): the composing
|
|
122
|
+
* artefact is whichever declared target says so about itself.
|
|
123
|
+
*/
|
|
124
|
+
function composingArtefact(pkg) {
|
|
125
|
+
for (const target of pkg.exports.values()) {
|
|
126
|
+
const path = join(pkg.dir, ...target.replace(/^\.\//, '').split('/'));
|
|
127
|
+
let text;
|
|
128
|
+
try {
|
|
129
|
+
text = readFileSync(path, 'utf8');
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
if (declaresRegisterModule(text))
|
|
135
|
+
return { path, text };
|
|
136
|
+
}
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Read what the subject's peers own.
|
|
141
|
+
*
|
|
142
|
+
* Every failure is named. A peer that publishes no composing artefact is
|
|
143
|
+
* *readable and empty* — it registers nothing, by its own `exports` map — while a
|
|
144
|
+
* peer whose artefact is absent is **unreadable**, because a package that was
|
|
145
|
+
* never built is a package whose registrations this run cannot see and must not
|
|
146
|
+
* credit with none.
|
|
147
|
+
*/
|
|
148
|
+
export function readPeerOwners(layout) {
|
|
149
|
+
const byId = new Map();
|
|
150
|
+
let installed = false;
|
|
151
|
+
let workspace = false;
|
|
152
|
+
const unreadable = [];
|
|
153
|
+
for (const root of candidateRoots(layout.packageRoot)) {
|
|
154
|
+
const scan = scanInstalledModulePackages(root);
|
|
155
|
+
for (const pkg of scan.packages) {
|
|
156
|
+
if (pkg.moduleId === layout.moduleId)
|
|
157
|
+
continue;
|
|
158
|
+
if (!byId.has(pkg.moduleId)) {
|
|
159
|
+
byId.set(pkg.moduleId, pkg);
|
|
160
|
+
installed = true;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
try {
|
|
164
|
+
for (const pkg of discoverModulePackages(root)) {
|
|
165
|
+
if (pkg.moduleId === layout.moduleId)
|
|
166
|
+
continue;
|
|
167
|
+
if (!byId.has(pkg.moduleId)) {
|
|
168
|
+
byId.set(pkg.moduleId, pkg);
|
|
169
|
+
workspace = true;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
catch (error) {
|
|
174
|
+
// Two workspace members claiming one module id. It is a real defect and it
|
|
175
|
+
// is not the subject's, so it is reported as an unreadable peer set rather
|
|
176
|
+
// than thrown: a stranger's malformed workspace must not abort their run,
|
|
177
|
+
// and crediting it with no peers would be the silence this file exists
|
|
178
|
+
// against.
|
|
179
|
+
unreadable.push({
|
|
180
|
+
name: root,
|
|
181
|
+
moduleId: '(workspace)',
|
|
182
|
+
reason: `its workspace could not be enumerated (${error instanceof Error ? error.message : String(error)})`,
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
const portOwners = new Map();
|
|
187
|
+
const containerOwners = new Map();
|
|
188
|
+
let filesRead = 0;
|
|
189
|
+
for (const pkg of [...byId.values()].sort((a, b) => a.moduleId.localeCompare(b.moduleId))) {
|
|
190
|
+
const artefact = composingArtefact(pkg);
|
|
191
|
+
if (artefact === null) {
|
|
192
|
+
// Readable and empty vs unreadable, decided by the package's own map: a
|
|
193
|
+
// peer that declares subpaths whose targets are not on disk was never
|
|
194
|
+
// built, and its registrations are unread rather than absent.
|
|
195
|
+
const declaresTargets = [...pkg.exports.values()].some((target) => existsSync(join(pkg.dir, ...target.replace(/^\.\//, '').split('/'))));
|
|
196
|
+
if (pkg.exports.size > 0 && !declaresTargets) {
|
|
197
|
+
unreadable.push({
|
|
198
|
+
name: pkg.name,
|
|
199
|
+
moduleId: pkg.moduleId,
|
|
200
|
+
reason: 'none of the targets its `exports` map declares is on disk, so the ports and ' +
|
|
201
|
+
'container names it registers cannot be read — it was never built',
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
continue;
|
|
205
|
+
}
|
|
206
|
+
filesRead += 1;
|
|
207
|
+
for (const name of providedPortNames(artefact.text, artefact.path)) {
|
|
208
|
+
if (!portOwners.has(name))
|
|
209
|
+
portOwners.set(name, pkg.moduleId);
|
|
210
|
+
}
|
|
211
|
+
for (const name of registeredNames(artefact.text, artefact.path)) {
|
|
212
|
+
if (!containerOwners.has(name))
|
|
213
|
+
containerOwners.set(name, pkg.moduleId);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
return {
|
|
217
|
+
peers: [...byId.values()],
|
|
218
|
+
portOwners,
|
|
219
|
+
containerOwners,
|
|
220
|
+
filesRead,
|
|
221
|
+
unreadable,
|
|
222
|
+
discovery: installed && workspace ? 'both' : installed ? 'installed' : workspace ? 'workspace' : 'none',
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
//# sourceMappingURL=peer-owners.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"peer-owners.js","sourceRoot":"","sources":["../../src/check/peer-owners.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The report — one line per rule, then the arithmetic
|
|
3
|
+
* (`specs/101-endora-check/contracts/exit-reduction.md` §3).
|
|
4
|
+
*
|
|
5
|
+
* Formatting only. Every decision is made in `run.ts` and every verdict in
|
|
6
|
+
* `hosts.ts`; a reporter that could change either would be a second place the
|
|
7
|
+
* exit code is decided.
|
|
8
|
+
*
|
|
9
|
+
* Two properties are contract rather than presentation:
|
|
10
|
+
*
|
|
11
|
+
* * **every rule appears**, whatever the aggregate found. That is what makes
|
|
12
|
+
* the reduction's `max` honest — the information a masked finding is about
|
|
13
|
+
* is on its own line, not something a reader infers from a scroll;
|
|
14
|
+
* * **`findings=<n>` is printed even when the exit code is 2** (FR-014). It is
|
|
15
|
+
* the whole of §4.4's answer to the masking objection, and it is normative.
|
|
16
|
+
*/
|
|
17
|
+
import { coverageToken } from '../lib/read-size.js';
|
|
18
|
+
import type { LedgerRead } from './ledger.js';
|
|
19
|
+
import type { RunReport } from './run.js';
|
|
20
|
+
/**
|
|
21
|
+
* The arithmetic line, last.
|
|
22
|
+
*
|
|
23
|
+
* A narrowed run prints `selected=<n>/<estate>` **in place of** `estate=<n>`, so
|
|
24
|
+
* it cannot be mistaken for a full run's (§6). That is the only difference.
|
|
25
|
+
*/
|
|
26
|
+
export declare function arithmeticLine(report: RunReport): string;
|
|
27
|
+
/** The sentence after the counts — why the run exited as it did. */
|
|
28
|
+
export declare function verdictSentence(report: RunReport): string;
|
|
29
|
+
/** The whole report, as the lines the command writes to stdout. */
|
|
30
|
+
export declare function formatReport(report: RunReport, ledger: LedgerRead): readonly string[];
|
|
31
|
+
/** The `sources=` token, re-exported so a caller need not reach past this file. */
|
|
32
|
+
export { coverageToken };
|
|
33
|
+
//# sourceMappingURL=report.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../../src/check/report.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,aAAa,EAAgB,MAAM,qBAAqB,CAAC;AAElE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,OAAO,KAAK,EAAE,SAAS,EAAc,MAAM,UAAU,CAAC;AAuCtD;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,SAAS,GAAG,MAAM,CAWxD;AAED,oEAAoE;AACpE,wBAAgB,eAAe,CAAC,MAAM,EAAE,SAAS,GAAG,MAAM,CA0BzD;AAED,mEAAmE;AACnE,wBAAgB,YAAY,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,GAAG,SAAS,MAAM,EAAE,CAYrF;AAED,mFAAmF;AACnF,OAAO,EAAE,aAAa,EAAE,CAAC"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The report — one line per rule, then the arithmetic
|
|
3
|
+
* (`specs/101-endora-check/contracts/exit-reduction.md` §3).
|
|
4
|
+
*
|
|
5
|
+
* Formatting only. Every decision is made in `run.ts` and every verdict in
|
|
6
|
+
* `hosts.ts`; a reporter that could change either would be a second place the
|
|
7
|
+
* exit code is decided.
|
|
8
|
+
*
|
|
9
|
+
* Two properties are contract rather than presentation:
|
|
10
|
+
*
|
|
11
|
+
* * **every rule appears**, whatever the aggregate found. That is what makes
|
|
12
|
+
* the reduction's `max` honest — the information a masked finding is about
|
|
13
|
+
* is on its own line, not something a reader infers from a scroll;
|
|
14
|
+
* * **`findings=<n>` is printed even when the exit code is 2** (FR-014). It is
|
|
15
|
+
* the whole of §4.4's answer to the masking objection, and it is normative.
|
|
16
|
+
*/
|
|
17
|
+
import { coverageToken, readSizeLine } from '../lib/read-size.js';
|
|
18
|
+
import { reasonFor } from './ledger.js';
|
|
19
|
+
const VERDICT_WIDTH = 15;
|
|
20
|
+
const ID_WIDTH = 34;
|
|
21
|
+
function pad(text, width) {
|
|
22
|
+
return text.length >= width ? text : text + ' '.repeat(width - text.length);
|
|
23
|
+
}
|
|
24
|
+
/** `ran` splits into the two sub-states a reader cares about. */
|
|
25
|
+
function verdictWord(result) {
|
|
26
|
+
if (result.verdict !== 'ran')
|
|
27
|
+
return result.verdict;
|
|
28
|
+
return result.findings.length === 0 ? 'clean' : `findings=${result.findings.length}`;
|
|
29
|
+
}
|
|
30
|
+
function ruleLines(result, ledger) {
|
|
31
|
+
const lines = [];
|
|
32
|
+
const head = ` ${pad(result.id, ID_WIDTH)} ${pad(verdictWord(result), VERDICT_WIDTH)}`;
|
|
33
|
+
lines.push(result.readSize === null ? `${head}${result.explanation}` : `${head}${readSizeLine(result.readSize)}`);
|
|
34
|
+
if (result.readSize !== null && result.explanation.length > 0) {
|
|
35
|
+
lines.push(` ${result.explanation}`);
|
|
36
|
+
}
|
|
37
|
+
for (const signal of result.unevaluatedSignals) {
|
|
38
|
+
lines.push(` not evaluated — ${signal.signal}: ${signal.reason}`);
|
|
39
|
+
}
|
|
40
|
+
for (const finding of result.findings) {
|
|
41
|
+
lines.push(` ${finding.location ?? result.id} ${finding.message}`);
|
|
42
|
+
}
|
|
43
|
+
for (const finding of result.acknowledged) {
|
|
44
|
+
lines.push(` acknowledged ${finding.location ?? result.id} ${finding.message}`);
|
|
45
|
+
lines.push(` reason: ${reasonFor(ledger, finding)}`);
|
|
46
|
+
}
|
|
47
|
+
return lines;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* The arithmetic line, last.
|
|
51
|
+
*
|
|
52
|
+
* A narrowed run prints `selected=<n>/<estate>` **in place of** `estate=<n>`, so
|
|
53
|
+
* it cannot be mistaken for a full run's (§6). That is the only difference.
|
|
54
|
+
*/
|
|
55
|
+
export function arithmeticLine(report) {
|
|
56
|
+
const counts = report.counts;
|
|
57
|
+
const scope = report.selected === null
|
|
58
|
+
? `estate=${counts.estate}`
|
|
59
|
+
: `selected=${report.selected.selected}/${report.selected.estate}`;
|
|
60
|
+
return (`endora check: ${scope} ran=${counts.ran} clean=${counts.clean} ` +
|
|
61
|
+
`findings=${counts.findings} not-applicable=${counts.notApplicable} ` +
|
|
62
|
+
`unreadable=${counts.unreadable} pending=${counts.pending}`);
|
|
63
|
+
}
|
|
64
|
+
/** The sentence after the counts — why the run exited as it did. */
|
|
65
|
+
export function verdictSentence(report) {
|
|
66
|
+
const counts = report.counts;
|
|
67
|
+
if (report.arithmeticFailures.length > 0) {
|
|
68
|
+
return ` → 2 ${report.arithmeticFailures.join(' ')}`;
|
|
69
|
+
}
|
|
70
|
+
const causes = [];
|
|
71
|
+
if (counts.pending > 0) {
|
|
72
|
+
const phases = [
|
|
73
|
+
...new Set(report.results
|
|
74
|
+
.filter((result) => result.verdict === 'pending')
|
|
75
|
+
.map((result) => result.explanation)),
|
|
76
|
+
];
|
|
77
|
+
causes.push(`${counts.pending} rule(s) have no package-scope host in this build (${phases.join('; ')})`);
|
|
78
|
+
}
|
|
79
|
+
if (counts.unreadable > 0) {
|
|
80
|
+
causes.push(`${counts.unreadable} rule(s) could not read an input this package must supply`);
|
|
81
|
+
}
|
|
82
|
+
if (causes.length > 0)
|
|
83
|
+
return ` → 2 ${causes.join('; ')}`;
|
|
84
|
+
if (counts.findings > 0 || report.ledgerFindings.length > 0) {
|
|
85
|
+
return ` → 1 ${counts.findings} rule(s) reported a finding`;
|
|
86
|
+
}
|
|
87
|
+
return ' → 0 the estate was completely evaluated and found nothing';
|
|
88
|
+
}
|
|
89
|
+
/** The whole report, as the lines the command writes to stdout. */
|
|
90
|
+
export function formatReport(report, ledger) {
|
|
91
|
+
const lines = [
|
|
92
|
+
`endora check: ${report.packageName}@${report.packageVersion}`,
|
|
93
|
+
'',
|
|
94
|
+
];
|
|
95
|
+
for (const result of report.results)
|
|
96
|
+
lines.push(...ruleLines(result, ledger));
|
|
97
|
+
if (report.ledgerFindings.length > 0) {
|
|
98
|
+
lines.push('');
|
|
99
|
+
for (const finding of report.ledgerFindings)
|
|
100
|
+
lines.push(` ledger: ${finding}`);
|
|
101
|
+
}
|
|
102
|
+
lines.push('', arithmeticLine(report), verdictSentence(report));
|
|
103
|
+
return lines;
|
|
104
|
+
}
|
|
105
|
+
/** The `sources=` token, re-exported so a caller need not reach past this file. */
|
|
106
|
+
export { coverageToken };
|
|
107
|
+
//# sourceMappingURL=report.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"report.js","sourceRoot":"","sources":["../../src/check/report.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The verdicts, the arithmetic and the reduction
|
|
3
|
+
* (`specs/101-endora-check/contracts/exit-reduction.md` §1, §3, §4).
|
|
4
|
+
*
|
|
5
|
+
* ## The reduction is `max`, and that is not a new decision
|
|
6
|
+
*
|
|
7
|
+
* `0` and `1` are statements about the **tree**; `2` is a statement about the
|
|
8
|
+
* **run**. So the aggregate's job is to make each code a *complete* statement:
|
|
9
|
+
*
|
|
10
|
+
* * **2** — the picture is incomplete. There may or may not be findings under
|
|
11
|
+
* it; repair the picture.
|
|
12
|
+
* * **1** — the picture is complete and there are findings.
|
|
13
|
+
* * **0** — the picture is complete and there are none.
|
|
14
|
+
*
|
|
15
|
+
* Every member of this estate already reduces this way internally, over many
|
|
16
|
+
* signals and many files: `check:module-boundary` exits 2 on an owner map that
|
|
17
|
+
* resolved zero tables even when its walk found real unledgered reaches. An
|
|
18
|
+
* aggregate reducing differently would be a second derivation of one convention.
|
|
19
|
+
*
|
|
20
|
+
* The masking objection — *"one unreadable input hides every real finding"* — is
|
|
21
|
+
* answered where it lives: it masks them **in the exit code and nowhere else**.
|
|
22
|
+
* Every rule prints its own line regardless, and {@link countsOf}'s `findings`
|
|
23
|
+
* is printed on the arithmetic line **even when the code is 2**. That is
|
|
24
|
+
* normative (FR-014), not cosmetic.
|
|
25
|
+
*
|
|
26
|
+
* ## The identities have to be able to fail
|
|
27
|
+
*
|
|
28
|
+
* {@link countsOf} takes the estate's size as an argument rather than deriving it
|
|
29
|
+
* from the results it was handed. A count computed by summing the results a run
|
|
30
|
+
* happens to hold can never detect a lost rule — it is a tautology, and the
|
|
31
|
+
* whole point of §3's first identity is that losing a rule is the failure this
|
|
32
|
+
* command exists to make impossible. The second identity fails on a malformed
|
|
33
|
+
* host: a result that is not `ran` and still carries a finding.
|
|
34
|
+
*/
|
|
35
|
+
import type { ReadSizeInput } from '../lib/read-size.js';
|
|
36
|
+
import type { PartialSignal } from './estate.js';
|
|
37
|
+
/** One thing a rule found. */
|
|
38
|
+
export interface Finding {
|
|
39
|
+
/** The estate id of the rule that found it. */
|
|
40
|
+
readonly rule: string;
|
|
41
|
+
/**
|
|
42
|
+
* The rule's own key shape for this finding — what a package ledger entry
|
|
43
|
+
* names. Never a line number where the rule's repository-side ledger keys on
|
|
44
|
+
* a digest: a line-keyed entry reds on any insertion above the site.
|
|
45
|
+
*/
|
|
46
|
+
readonly key: string;
|
|
47
|
+
/** The sentence the author reads. */
|
|
48
|
+
readonly message: string;
|
|
49
|
+
/** Package-relative, or `null` where the finding is about the package. */
|
|
50
|
+
readonly location: string | null;
|
|
51
|
+
}
|
|
52
|
+
export type Verdict = 'ran' | 'not-applicable' | 'unreadable' | 'pending';
|
|
53
|
+
export interface RuleResult {
|
|
54
|
+
/** Matches {@link EstateEntry.id}. */
|
|
55
|
+
readonly id: string;
|
|
56
|
+
readonly verdict: Verdict;
|
|
57
|
+
/** Empty for every verdict but `ran`. */
|
|
58
|
+
readonly findings: readonly Finding[];
|
|
59
|
+
/**
|
|
60
|
+
* Findings a package ledger entry matched. Excluded from the author's exit
|
|
61
|
+
* code, included under `--as-platform` (`contracts/package-ledger.md` §4).
|
|
62
|
+
*/
|
|
63
|
+
readonly acknowledged: readonly Finding[];
|
|
64
|
+
/** `null` only for `not-applicable` and `pending`. */
|
|
65
|
+
readonly readSize: ReadSizeInput | null;
|
|
66
|
+
/**
|
|
67
|
+
* Required for every verdict but `ran`, and that requirement **is** the
|
|
68
|
+
* design: a rule that did not run and cannot say why is the silent skip.
|
|
69
|
+
* Making the field non-optional is the cheapest place to make that
|
|
70
|
+
* unreachable.
|
|
71
|
+
*/
|
|
72
|
+
readonly explanation: string;
|
|
73
|
+
/** Printed on the rule's own line. */
|
|
74
|
+
readonly unevaluatedSignals: readonly PartialSignal[];
|
|
75
|
+
}
|
|
76
|
+
export interface RunCounts {
|
|
77
|
+
readonly estate: number;
|
|
78
|
+
readonly ran: number;
|
|
79
|
+
readonly clean: number;
|
|
80
|
+
readonly findings: number;
|
|
81
|
+
readonly notApplicable: number;
|
|
82
|
+
readonly unreadable: number;
|
|
83
|
+
readonly pending: number;
|
|
84
|
+
}
|
|
85
|
+
/** `null` for a full run; the pair for a `--rule` run. */
|
|
86
|
+
export interface Selection {
|
|
87
|
+
readonly selected: number;
|
|
88
|
+
readonly estate: number;
|
|
89
|
+
}
|
|
90
|
+
export interface RunReport {
|
|
91
|
+
/** As read from the package's own manifest. */
|
|
92
|
+
readonly packageName: string;
|
|
93
|
+
readonly packageVersion: string;
|
|
94
|
+
readonly results: readonly RuleResult[];
|
|
95
|
+
readonly selected: Selection | null;
|
|
96
|
+
readonly counts: RunCounts;
|
|
97
|
+
/**
|
|
98
|
+
* Ledger entries that describe no finding this run produced, that carry no
|
|
99
|
+
* reason, or that are expressed as a count. Each makes the run exit 1; none
|
|
100
|
+
* of them is an estate member, so none disturbs §3's arithmetic.
|
|
101
|
+
*/
|
|
102
|
+
readonly ledgerFindings: readonly string[];
|
|
103
|
+
/** Why §3's identities do not hold, or empty. */
|
|
104
|
+
readonly arithmeticFailures: readonly string[];
|
|
105
|
+
/** Computed by {@link reduce} and by nothing else. */
|
|
106
|
+
readonly exitCode: number;
|
|
107
|
+
}
|
|
108
|
+
/** Which findings count against the exit code, for this reader. */
|
|
109
|
+
export declare function effectiveFindings(result: RuleResult, asPlatform: boolean): readonly Finding[];
|
|
110
|
+
/**
|
|
111
|
+
* The counts, over the results and an **independently supplied** estate size.
|
|
112
|
+
*
|
|
113
|
+
* `estateSize` is a parameter rather than `results.length` on purpose — see the
|
|
114
|
+
* header. `clean` and `findings` are each counted directly rather than one being
|
|
115
|
+
* derived from the other, so §3's second identity is a real comparison.
|
|
116
|
+
*/
|
|
117
|
+
export declare function countsOf(results: readonly RuleResult[], estateSize: number, asPlatform?: boolean): RunCounts;
|
|
118
|
+
/**
|
|
119
|
+
* Why §3's identities do not hold, or an empty list.
|
|
120
|
+
*
|
|
121
|
+
* A narrowed run suppresses the first — it is meaningless over a subset — and
|
|
122
|
+
* keeps the second, which is about the results themselves.
|
|
123
|
+
*/
|
|
124
|
+
export declare function arithmeticFailures(counts: RunCounts, narrowed: boolean): readonly string[];
|
|
125
|
+
/**
|
|
126
|
+
* The exit code. `max` over the members' own codes, with `pending` folded into 2.
|
|
127
|
+
*
|
|
128
|
+
* ```
|
|
129
|
+
* exit 2 if unreadable > 0 or pending > 0 or either identity fails
|
|
130
|
+
* exit 1 else if findings > 0 or a ledger entry is stale
|
|
131
|
+
* exit 0 else
|
|
132
|
+
* ```
|
|
133
|
+
*/
|
|
134
|
+
export declare function reduce(counts: RunCounts, failures: readonly string[], ledgerFindings: readonly string[]): number;
|
|
135
|
+
export interface RunReportInput {
|
|
136
|
+
readonly packageName: string;
|
|
137
|
+
readonly packageVersion: string;
|
|
138
|
+
readonly results: readonly RuleResult[];
|
|
139
|
+
/** The estate's size — never `results.length` (see the header). */
|
|
140
|
+
readonly estateSize: number;
|
|
141
|
+
/** `null` for a full run. */
|
|
142
|
+
readonly selected: Selection | null;
|
|
143
|
+
readonly ledgerFindings?: readonly string[];
|
|
144
|
+
readonly asPlatform?: boolean;
|
|
145
|
+
}
|
|
146
|
+
export declare function buildRunReport(input: RunReportInput): RunReport;
|
|
147
|
+
//# sourceMappingURL=run.d.ts.map
|