@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,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* An entry point with no caller **decides** presence before it works
|
|
3
|
+
* (issue #126; Constitution XVII).
|
|
4
|
+
*
|
|
5
|
+
* Routes are gated at the `ctx.routes` seam, workers at `defineModuleWorker`,
|
|
6
|
+
* subscriptions at `ctx.subscribe` — and each of those seams has a static check.
|
|
7
|
+
* A timer a module starts in its own plugin body had none: `defineModuleRoutes`
|
|
8
|
+
* gates *requests* through an `onRequest` hook, and a plugin body is not a
|
|
9
|
+
* request, so it runs at boot whatever the module's effective state and the
|
|
10
|
+
* callback keeps firing every five minutes after an operator switches the module
|
|
11
|
+
* off. In `price_lists` that meant price lists went on activating and expiring on
|
|
12
|
+
* a timer — it changed what customers are charged, not merely what a log said.
|
|
13
|
+
*
|
|
14
|
+
* The rule this enforces is the one in `AGENTS.md`, "Module enable/disable",
|
|
15
|
+
* item 3: **where nothing can catch the throw, presence is decided before the
|
|
16
|
+
* work, not caught after it.**
|
|
17
|
+
*
|
|
18
|
+
* The whole of the reasoning — the four constructs, why a mixed boot hook is
|
|
19
|
+
* reported rather than probed, and what this analysis deliberately cannot see —
|
|
20
|
+
* is in `backend/scripts/check-entry-presence.ts`, the repository-scope host,
|
|
21
|
+
* whose header it has always been. Two things live there rather than here and
|
|
22
|
+
* both are deliberate:
|
|
23
|
+
*
|
|
24
|
+
* * **the ledgers.** `TIMERS_WITHOUT_PRESENCE` and
|
|
25
|
+
* `BOOT_HOOKS_WITHOUT_PRESENCE` are entries about *these* modules, and a
|
|
26
|
+
* third-party package is in no such ledger — the same placement
|
|
27
|
+
* `check:command-coverage`'s `MIGRATED_MODULES` has. It is also load-bearing
|
|
28
|
+
* for a second reason: `check:lock-claims`' population includes
|
|
29
|
+
* `backend/scripts/check-*.ts` precisely because that is where a check's own
|
|
30
|
+
* ledger reasons live, so moving these two out of that tree would take them
|
|
31
|
+
* out of that check's population without anything saying so.
|
|
32
|
+
* * **the default for `checkEntryPresence`'s ledger argument.** It has none
|
|
33
|
+
* here: a host must state which ledger it is judging against, because
|
|
34
|
+
* "whichever one the library happened to carry" is how a package inherits
|
|
35
|
+
* this repository's exemptions.
|
|
36
|
+
*
|
|
37
|
+
* `specs/101-endora-check/contracts/package-scope-layout.md` §6 — one analysis,
|
|
38
|
+
* two hosts.
|
|
39
|
+
*/
|
|
40
|
+
import ts from 'typescript';
|
|
41
|
+
import { type HostResidentModules } from '../lib/module-population.js';
|
|
42
|
+
/** The entry-point construct this finding is about. */
|
|
43
|
+
export type EntryConstruct = 'setInterval' | 'setTimeout' | 'process.on' | 'ctx.onBoot';
|
|
44
|
+
/** Why the site fails the rule. Each maps to its own line in the failure output. */
|
|
45
|
+
export type EntryFinding =
|
|
46
|
+
/** Nothing in the callback asks `isPresent`. */
|
|
47
|
+
'no-presence-decision'
|
|
48
|
+
/** It asks, but from inside a `try` — where a switched-off module and a failed
|
|
49
|
+
* tick end up in the same `catch`. */
|
|
50
|
+
| 'presence-decided-inside-try'
|
|
51
|
+
/** It asks about a different module than the one that owns the file. */
|
|
52
|
+
| 'presence-decided-for-another-module'
|
|
53
|
+
/**
|
|
54
|
+
* A boot hook that **does work and contributes** in one body. Neither answer
|
|
55
|
+
* fits: probing it stops the contribution, leaving it unprobed keeps the work.
|
|
56
|
+
* The remedy is a split, and the reported kind says so rather than repeating
|
|
57
|
+
* the probe advice that is wrong here (D-68).
|
|
58
|
+
*/
|
|
59
|
+
| 'mixed-boot-hook';
|
|
60
|
+
export interface UngatedEntry {
|
|
61
|
+
/** Path under `src/`, POSIX separators. */
|
|
62
|
+
readonly file: string;
|
|
63
|
+
readonly line: number;
|
|
64
|
+
readonly moduleId: string;
|
|
65
|
+
readonly construct: EntryConstruct;
|
|
66
|
+
/**
|
|
67
|
+
* The enclosing named function, or `<module scope>` — part of the ledger key.
|
|
68
|
+
* A boot hook has no enclosing name worth keying on (every one of them sits in
|
|
69
|
+
* `registerModule`), so it uses `onBoot#<n>`, its ordinal among the hooks the
|
|
70
|
+
* file registers. That is stable under everything except reordering the hooks
|
|
71
|
+
* themselves, which is a change to what each one is.
|
|
72
|
+
*/
|
|
73
|
+
readonly scheduler: string;
|
|
74
|
+
readonly finding: EntryFinding;
|
|
75
|
+
}
|
|
76
|
+
/** `<file>:<scheduler>:<construct>` — the ledger key, and the identity of a site. */
|
|
77
|
+
export declare function keyOf(found: UngatedEntry): string;
|
|
78
|
+
export interface EntryPresenceInput {
|
|
79
|
+
/** Every source under `src/`, keyed by path relative to `src/`. */
|
|
80
|
+
readonly sources: ReadonlyMap<string, string>;
|
|
81
|
+
/**
|
|
82
|
+
* Modules whose manifest declares `activation.nonDeactivatable`, from
|
|
83
|
+
* `lib/switchable-modules.ts`. Their boot hooks are out of the population: no
|
|
84
|
+
* undeclared absence lets one run while the module is absent, and a declared
|
|
85
|
+
* one ships neither the hook nor the module (D-101). Timers stay
|
|
86
|
+
* in — `_lifecycle`'s lease heartbeat is ledgered rather than exempted, and
|
|
87
|
+
* that entry is what documents the circularity behind it.
|
|
88
|
+
*
|
|
89
|
+
* Defaulting to empty widens the population rather than narrowing it, so a
|
|
90
|
+
* caller that forgets it over-reports instead of going quietly blind.
|
|
91
|
+
*/
|
|
92
|
+
readonly lockedModules?: ReadonlySet<string> | undefined;
|
|
93
|
+
/**
|
|
94
|
+
* Directories whose files belong to a module that no `modules/<id>/` segment
|
|
95
|
+
* names — `lib/module-roots.ts`' `hostResidentModules` (feature 080, T040b).
|
|
96
|
+
*
|
|
97
|
+
* Without it `_lifecycle`'s lease heartbeat attributes to `null` and this
|
|
98
|
+
* rule skips it as "not a module's file", which is the ledger entry below
|
|
99
|
+
* going stale while the timer it describes is still there.
|
|
100
|
+
*/
|
|
101
|
+
readonly hostResidentModules?: HostResidentModules | undefined;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Does this hook body **do work** — the question that decides whether it owes a
|
|
105
|
+
* presence probe?
|
|
106
|
+
*
|
|
107
|
+
* Syntactic, like every other shape here: an `await` anywhere in the body, a
|
|
108
|
+
* call on the module's own `emFactory` / `em` / `redis` / `.handle`, or a call on
|
|
109
|
+
* something the body just constructed (`new Reconciler(em).run()`).
|
|
110
|
+
*/
|
|
111
|
+
export declare function bootHookDoesWork(body: ts.Node): boolean;
|
|
112
|
+
/**
|
|
113
|
+
* Does this hook body also **contribute** — push a descriptor into a registry
|
|
114
|
+
* some other module reads?
|
|
115
|
+
*
|
|
116
|
+
* A `registry.register(…)` / `.push(…)` call, or a helper whose name says so
|
|
117
|
+
* (`registerBlogAssetReferences(…)`). Both spellings shipped in the two mixed
|
|
118
|
+
* hooks D-68 had to split.
|
|
119
|
+
*/
|
|
120
|
+
export declare function bootHookContributes(body: ts.Node): boolean;
|
|
121
|
+
/** Every uncatchable entry point in a module's sources that fails the rule. */
|
|
122
|
+
export declare function findUngatedEntries(input: EntryPresenceInput): UngatedEntry[];
|
|
123
|
+
export interface CheckResult {
|
|
124
|
+
readonly total: number;
|
|
125
|
+
readonly violations: readonly UngatedEntry[];
|
|
126
|
+
readonly ledgered: readonly UngatedEntry[];
|
|
127
|
+
/** Ledger keys that no longer describe an ungated entry point. */
|
|
128
|
+
readonly stale: readonly string[];
|
|
129
|
+
}
|
|
130
|
+
export declare function checkEntryPresence(input: EntryPresenceInput, ledger: Readonly<Record<string, string>>): CheckResult;
|
|
131
|
+
export declare const EXPLANATION: Readonly<Record<EntryFinding, string>>;
|
|
132
|
+
/** The sentence an author reads for one site. One spelling, two hosts. */
|
|
133
|
+
export declare function remedyFor(found: UngatedEntry): string;
|
|
134
|
+
/**
|
|
135
|
+
* Every source this rule reads under `roots`.
|
|
136
|
+
*
|
|
137
|
+
* One spelling, both hosts: the repository host supplies its source roots and the
|
|
138
|
+
* package host supplies one package's, and neither gets to differ about which
|
|
139
|
+
* files are in the population.
|
|
140
|
+
*/
|
|
141
|
+
export declare function collectPresenceFiles(roots: readonly string[], out?: string[]): string[];
|
|
142
|
+
//# sourceMappingURL=entry-presence.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entry-presence.d.ts","sourceRoot":"","sources":["../../src/rules/entry-presence.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAKH,OAAO,EAAE,MAAM,YAAY,CAAC;AAE5B,OAAO,EAEL,KAAK,mBAAmB,EACzB,MAAM,6BAA6B,CAAC;AA6BrC,uDAAuD;AACvD,MAAM,MAAM,cAAc,GAAG,aAAa,GAAG,YAAY,GAAG,YAAY,GAAG,YAAY,CAAC;AAExF,oFAAoF;AACpF,MAAM,MAAM,YAAY;AACtB,gDAAgD;AAC9C,sBAAsB;AACxB;uCACuC;GACrC,6BAA6B;AAC/B,wEAAwE;GACtE,qCAAqC;AACvC;;;;;GAKG;GACD,iBAAiB,CAAC;AAEtB,MAAM,WAAW,YAAY;IAC3B,2CAA2C;IAC3C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,cAAc,CAAC;IACnC;;;;;;OAMG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAC;CAChC;AAED,qFAAqF;AACrF,wBAAgB,KAAK,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM,CAEjD;AAED,MAAM,WAAW,kBAAkB;IACjC,mEAAmE;IACnE,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9C;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,GAAG,SAAS,CAAC;IACzD;;;;;;;OAOG;IACH,QAAQ,CAAC,mBAAmB,CAAC,EAAE,mBAAmB,GAAG,SAAS,CAAC;CAChE;AA+ED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,GAAG,OAAO,CAgBvD;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,GAAG,OAAO,CAQ1D;AAyCD,+EAA+E;AAC/E,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,kBAAkB,GAAG,YAAY,EAAE,CAwF5E;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,SAAS,YAAY,EAAE,CAAC;IAC7C,QAAQ,CAAC,QAAQ,EAAE,SAAS,YAAY,EAAE,CAAC;IAC3C,kEAAkE;IAClE,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CACnC;AAED,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,kBAAkB,EACzB,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GACvC,WAAW,CASb;AAED,eAAO,MAAM,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,CAiB9D,CAAC;AAGF,0EAA0E;AAC1E,wBAAgB,SAAS,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM,CAErD;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,EAAE,GAAG,GAAE,MAAM,EAAO,GAAG,MAAM,EAAE,CAc3F"}
|
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* An entry point with no caller **decides** presence before it works
|
|
3
|
+
* (issue #126; Constitution XVII).
|
|
4
|
+
*
|
|
5
|
+
* Routes are gated at the `ctx.routes` seam, workers at `defineModuleWorker`,
|
|
6
|
+
* subscriptions at `ctx.subscribe` — and each of those seams has a static check.
|
|
7
|
+
* A timer a module starts in its own plugin body had none: `defineModuleRoutes`
|
|
8
|
+
* gates *requests* through an `onRequest` hook, and a plugin body is not a
|
|
9
|
+
* request, so it runs at boot whatever the module's effective state and the
|
|
10
|
+
* callback keeps firing every five minutes after an operator switches the module
|
|
11
|
+
* off. In `price_lists` that meant price lists went on activating and expiring on
|
|
12
|
+
* a timer — it changed what customers are charged, not merely what a log said.
|
|
13
|
+
*
|
|
14
|
+
* The rule this enforces is the one in `AGENTS.md`, "Module enable/disable",
|
|
15
|
+
* item 3: **where nothing can catch the throw, presence is decided before the
|
|
16
|
+
* work, not caught after it.**
|
|
17
|
+
*
|
|
18
|
+
* The whole of the reasoning — the four constructs, why a mixed boot hook is
|
|
19
|
+
* reported rather than probed, and what this analysis deliberately cannot see —
|
|
20
|
+
* is in `backend/scripts/check-entry-presence.ts`, the repository-scope host,
|
|
21
|
+
* whose header it has always been. Two things live there rather than here and
|
|
22
|
+
* both are deliberate:
|
|
23
|
+
*
|
|
24
|
+
* * **the ledgers.** `TIMERS_WITHOUT_PRESENCE` and
|
|
25
|
+
* `BOOT_HOOKS_WITHOUT_PRESENCE` are entries about *these* modules, and a
|
|
26
|
+
* third-party package is in no such ledger — the same placement
|
|
27
|
+
* `check:command-coverage`'s `MIGRATED_MODULES` has. It is also load-bearing
|
|
28
|
+
* for a second reason: `check:lock-claims`' population includes
|
|
29
|
+
* `backend/scripts/check-*.ts` precisely because that is where a check's own
|
|
30
|
+
* ledger reasons live, so moving these two out of that tree would take them
|
|
31
|
+
* out of that check's population without anything saying so.
|
|
32
|
+
* * **the default for `checkEntryPresence`'s ledger argument.** It has none
|
|
33
|
+
* here: a host must state which ledger it is judging against, because
|
|
34
|
+
* "whichever one the library happened to carry" is how a package inherits
|
|
35
|
+
* this repository's exemptions.
|
|
36
|
+
*
|
|
37
|
+
* `specs/101-endora-check/contracts/package-scope-layout.md` §6 — one analysis,
|
|
38
|
+
* two hosts.
|
|
39
|
+
*/
|
|
40
|
+
import { existsSync, readdirSync, statSync } from 'node:fs';
|
|
41
|
+
import { join } from 'node:path';
|
|
42
|
+
import ts from 'typescript';
|
|
43
|
+
import { NO_HOST_RESIDENT_MODULES, } from '../lib/module-population.js';
|
|
44
|
+
import { moduleOf } from '../lib/port-registrations.js';
|
|
45
|
+
import { callbackOf, calleeName, enclosingName, findRepeatingTimerSites, localFunctions, MODULE_SCOPE, parseScript, receiverName, stringLiteralOf, } from '../lib/repeating-timers.js';
|
|
46
|
+
/** Process-lifecycle events: a handler for one of these has no caller either. */
|
|
47
|
+
const PROCESS_EVENTS = new Set([
|
|
48
|
+
'SIGINT',
|
|
49
|
+
'SIGTERM',
|
|
50
|
+
'SIGHUP',
|
|
51
|
+
'SIGQUIT',
|
|
52
|
+
'SIGUSR1',
|
|
53
|
+
'SIGUSR2',
|
|
54
|
+
'beforeExit',
|
|
55
|
+
'exit',
|
|
56
|
+
'uncaughtException',
|
|
57
|
+
'unhandledRejection',
|
|
58
|
+
]);
|
|
59
|
+
/** `<file>:<scheduler>:<construct>` — the ledger key, and the identity of a site. */
|
|
60
|
+
export function keyOf(found) {
|
|
61
|
+
return `${found.file}:${found.scheduler}:${found.construct}`;
|
|
62
|
+
}
|
|
63
|
+
/** Is `node` under a `try` that is itself inside `root`? */
|
|
64
|
+
function underTry(node, root) {
|
|
65
|
+
for (let cursor = node.parent; cursor && cursor !== root; cursor = cursor.parent) {
|
|
66
|
+
if (ts.isTryStatement(cursor))
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
function presenceDecisionIn(callback, moduleId) {
|
|
72
|
+
let decidesOwnModule = false;
|
|
73
|
+
let decidesOtherModule = false;
|
|
74
|
+
let insideTry = false;
|
|
75
|
+
const visit = (node) => {
|
|
76
|
+
if (ts.isCallExpression(node) && calleeName(node) === 'isPresent') {
|
|
77
|
+
const [argument] = node.arguments;
|
|
78
|
+
const asked = argument === undefined ? null : stringLiteralOf(argument);
|
|
79
|
+
if (asked === moduleId) {
|
|
80
|
+
if (underTry(node, callback))
|
|
81
|
+
insideTry = true;
|
|
82
|
+
else
|
|
83
|
+
decidesOwnModule = true;
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
decidesOtherModule = true;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
node.forEachChild(visit);
|
|
90
|
+
};
|
|
91
|
+
visit(callback);
|
|
92
|
+
return { decidesOwnModule, decidesOtherModule, insideTry };
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Names whose *use as a receiver* marks a hook body as doing work rather than
|
|
96
|
+
* contributing: the module's own database factory, its Redis client and the
|
|
97
|
+
* service handle its plugin returns. Passing one along (`seed(emFactory)`) is
|
|
98
|
+
* not a call on it and does not count — see the header's blind spots.
|
|
99
|
+
*/
|
|
100
|
+
const WORK_RECEIVERS = new Set(['emFactory', 'em', 'redis', 'handle']);
|
|
101
|
+
/** Verbs a contribution uses to push a descriptor into somebody else's table. */
|
|
102
|
+
const CONTRIBUTION_VERBS = new Set(['register', 'push', 'unshift', 'add']);
|
|
103
|
+
/** Does any node under `root` satisfy `predicate`? */
|
|
104
|
+
function anyNode(root, predicate) {
|
|
105
|
+
let hit = false;
|
|
106
|
+
const visit = (node) => {
|
|
107
|
+
if (hit)
|
|
108
|
+
return;
|
|
109
|
+
if (predicate(node)) {
|
|
110
|
+
hit = true;
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
node.forEachChild(visit);
|
|
114
|
+
};
|
|
115
|
+
visit(root);
|
|
116
|
+
return hit;
|
|
117
|
+
}
|
|
118
|
+
/** Every identifier in a callee's property-access chain, innermost last. */
|
|
119
|
+
function calleeChain(node) {
|
|
120
|
+
const names = [];
|
|
121
|
+
let cursor = node.expression;
|
|
122
|
+
while (ts.isPropertyAccessExpression(cursor)) {
|
|
123
|
+
names.push(cursor.name.text);
|
|
124
|
+
cursor = cursor.expression;
|
|
125
|
+
}
|
|
126
|
+
if (ts.isIdentifier(cursor))
|
|
127
|
+
names.push(cursor.text);
|
|
128
|
+
if (ts.isCallExpression(cursor))
|
|
129
|
+
names.push(...calleeChain(cursor));
|
|
130
|
+
return names;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Does this hook body **do work** — the question that decides whether it owes a
|
|
134
|
+
* presence probe?
|
|
135
|
+
*
|
|
136
|
+
* Syntactic, like every other shape here: an `await` anywhere in the body, a
|
|
137
|
+
* call on the module's own `emFactory` / `em` / `redis` / `.handle`, or a call on
|
|
138
|
+
* something the body just constructed (`new Reconciler(em).run()`).
|
|
139
|
+
*/
|
|
140
|
+
export function bootHookDoesWork(body) {
|
|
141
|
+
return anyNode(body, (node) => {
|
|
142
|
+
if (ts.isAwaitExpression(node))
|
|
143
|
+
return true;
|
|
144
|
+
if (!ts.isCallExpression(node))
|
|
145
|
+
return false;
|
|
146
|
+
if (ts.isNewExpression(node.expression))
|
|
147
|
+
return true;
|
|
148
|
+
if (ts.isPropertyAccessExpression(node.expression) &&
|
|
149
|
+
ts.isNewExpression(node.expression.expression)) {
|
|
150
|
+
return true;
|
|
151
|
+
}
|
|
152
|
+
const chain = calleeChain(node);
|
|
153
|
+
// `emFactory()` itself is only a fork; what counts is a call *through* one of
|
|
154
|
+
// these, which is why the receiver names are read from the chain's tail.
|
|
155
|
+
return chain.slice(1).some((name) => WORK_RECEIVERS.has(name));
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Does this hook body also **contribute** — push a descriptor into a registry
|
|
160
|
+
* some other module reads?
|
|
161
|
+
*
|
|
162
|
+
* A `registry.register(…)` / `.push(…)` call, or a helper whose name says so
|
|
163
|
+
* (`registerBlogAssetReferences(…)`). Both spellings shipped in the two mixed
|
|
164
|
+
* hooks D-68 had to split.
|
|
165
|
+
*/
|
|
166
|
+
export function bootHookContributes(body) {
|
|
167
|
+
return anyNode(body, (node) => {
|
|
168
|
+
if (!ts.isCallExpression(node))
|
|
169
|
+
return false;
|
|
170
|
+
const name = calleeName(node);
|
|
171
|
+
if (name === null)
|
|
172
|
+
return false;
|
|
173
|
+
if (CONTRIBUTION_VERBS.has(name))
|
|
174
|
+
return true;
|
|
175
|
+
return /^register[A-Z]/.test(name);
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Every `onBoot(...)` registration in a file, in source order.
|
|
180
|
+
*
|
|
181
|
+
* The receiver is not required to be `ctx`: an overlay module composes through
|
|
182
|
+
* the feature-057 factory and may name its context differently, and a hook this
|
|
183
|
+
* check cannot see is exactly the hole it exists to close.
|
|
184
|
+
*/
|
|
185
|
+
function findBootHookSites(sf, bindings) {
|
|
186
|
+
const sites = [];
|
|
187
|
+
const visit = (node) => {
|
|
188
|
+
if (ts.isCallExpression(node) && calleeName(node) === 'onBoot') {
|
|
189
|
+
const body = callbackOf(node.arguments[0], bindings);
|
|
190
|
+
if (body !== null) {
|
|
191
|
+
sites.push({
|
|
192
|
+
call: node,
|
|
193
|
+
body,
|
|
194
|
+
line: sf.getLineAndCharacterOfPosition(node.getStart(sf)).line + 1,
|
|
195
|
+
ordinal: sites.length + 1,
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
node.forEachChild(visit);
|
|
200
|
+
};
|
|
201
|
+
sf.forEachChild(visit);
|
|
202
|
+
return sites;
|
|
203
|
+
}
|
|
204
|
+
/** Every uncatchable entry point in a module's sources that fails the rule. */
|
|
205
|
+
export function findUngatedEntries(input) {
|
|
206
|
+
const found = [];
|
|
207
|
+
const locked = input.lockedModules ?? new Set();
|
|
208
|
+
const hostResident = input.hostResidentModules ?? NO_HOST_RESIDENT_MODULES;
|
|
209
|
+
for (const [file, text] of input.sources) {
|
|
210
|
+
const moduleId = moduleOf(`/src/${file}`, hostResident);
|
|
211
|
+
// Only a module has an effective state to gate on. A file outside one — the
|
|
212
|
+
// kernel, `http/`, `db/`, a composition root — is not this rule's business.
|
|
213
|
+
if (moduleId === null)
|
|
214
|
+
continue;
|
|
215
|
+
const sf = parseScript(file, text);
|
|
216
|
+
const bindings = localFunctions(sf);
|
|
217
|
+
const report = (node, construct, finding, at) => {
|
|
218
|
+
found.push({
|
|
219
|
+
file,
|
|
220
|
+
line: at?.line ?? sf.getLineAndCharacterOfPosition(node.getStart(sf)).line + 1,
|
|
221
|
+
moduleId,
|
|
222
|
+
construct,
|
|
223
|
+
scheduler: at?.scheduler ?? enclosingName(node) ?? MODULE_SCOPE,
|
|
224
|
+
finding,
|
|
225
|
+
});
|
|
226
|
+
};
|
|
227
|
+
const judge = (node, construct, callback, at) => {
|
|
228
|
+
const decision = presenceDecisionIn(callback, moduleId);
|
|
229
|
+
if (decision.decidesOwnModule)
|
|
230
|
+
return;
|
|
231
|
+
if (decision.insideTry)
|
|
232
|
+
return report(node, construct, 'presence-decided-inside-try', at);
|
|
233
|
+
if (decision.decidesOtherModule) {
|
|
234
|
+
return report(node, construct, 'presence-decided-for-another-module', at);
|
|
235
|
+
}
|
|
236
|
+
report(node, construct, 'no-presence-decision', at);
|
|
237
|
+
};
|
|
238
|
+
// Repeating timers come from the shared recognizer (issue #128), so this
|
|
239
|
+
// check and `check-entry-scope` cannot disagree about what one is.
|
|
240
|
+
for (const site of findRepeatingTimerSites(sf)) {
|
|
241
|
+
const at = { line: site.line, scheduler: site.scheduler };
|
|
242
|
+
// An unreadable callback is a finding, not a skip: what the check cannot
|
|
243
|
+
// see, it must not vouch for.
|
|
244
|
+
if (site.callback === null)
|
|
245
|
+
report(site.call, site.construct, 'no-presence-decision', at);
|
|
246
|
+
else
|
|
247
|
+
judge(site.call, site.construct, site.callback, at);
|
|
248
|
+
}
|
|
249
|
+
// Process-lifecycle handlers are this check's alone: they have no caller to
|
|
250
|
+
// answer either, but they start no repeating execution, so they are not the
|
|
251
|
+
// shared shape.
|
|
252
|
+
const visit = (node) => {
|
|
253
|
+
if (ts.isCallExpression(node) && calleeName(node) === 'on' && receiverName(node) === 'process') {
|
|
254
|
+
const event = node.arguments[0] ? stringLiteralOf(node.arguments[0]) : null;
|
|
255
|
+
const handler = callbackOf(node.arguments[1], bindings);
|
|
256
|
+
if (event !== null && PROCESS_EVENTS.has(event)) {
|
|
257
|
+
if (handler === null)
|
|
258
|
+
report(node, 'process.on', 'no-presence-decision');
|
|
259
|
+
else
|
|
260
|
+
judge(node, 'process.on', handler);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
node.forEachChild(visit);
|
|
264
|
+
};
|
|
265
|
+
sf.forEachChild(visit);
|
|
266
|
+
// Boot hooks — the fourth construct (D-68). A module the orchestrator
|
|
267
|
+
// refuses to switch off has no absent state for a hook to run in, so it is
|
|
268
|
+
// out of the population; the derivation is shared with `check-port-catches`
|
|
269
|
+
// so withdrawing a lock re-reds both checks on the same run.
|
|
270
|
+
if (locked.has(moduleId))
|
|
271
|
+
continue;
|
|
272
|
+
for (const site of findBootHookSites(sf, bindings)) {
|
|
273
|
+
if (!bootHookDoesWork(site.body))
|
|
274
|
+
continue;
|
|
275
|
+
const at = { line: site.line, scheduler: `onBoot#${site.ordinal}` };
|
|
276
|
+
if (bootHookContributes(site.body)) {
|
|
277
|
+
report(site.call, 'ctx.onBoot', 'mixed-boot-hook', at);
|
|
278
|
+
continue;
|
|
279
|
+
}
|
|
280
|
+
judge(site.call, 'ctx.onBoot', site.body, at);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
found.sort((a, b) => (a.file === b.file ? a.line - b.line : a.file.localeCompare(b.file)));
|
|
284
|
+
return found;
|
|
285
|
+
}
|
|
286
|
+
export function checkEntryPresence(input, ledger) {
|
|
287
|
+
const all = findUngatedEntries(input);
|
|
288
|
+
const keys = new Set(all.map(keyOf));
|
|
289
|
+
return {
|
|
290
|
+
total: all.length,
|
|
291
|
+
violations: all.filter((entry) => ledger[keyOf(entry)] === undefined),
|
|
292
|
+
ledgered: all.filter((entry) => ledger[keyOf(entry)] !== undefined),
|
|
293
|
+
stale: Object.keys(ledger).filter((key) => !keys.has(key)),
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
export const EXPLANATION = {
|
|
297
|
+
'no-presence-decision': 'asks nothing about the module before it works — add ' +
|
|
298
|
+
"`if (!effectiveState.isPresent('<module>')) return;` as the callback's first statement",
|
|
299
|
+
'presence-decided-inside-try': 'asks inside a `try`, so a switched-off module and a failed tick share one `catch` — ' +
|
|
300
|
+
'move the question outside it',
|
|
301
|
+
'presence-decided-for-another-module': 'asks about a different module than the one that owns the file',
|
|
302
|
+
'mixed-boot-hook': 'does work **and** contributes a descriptor to another module in one hook — do NOT put a ' +
|
|
303
|
+
'presence check at the top of it. Split it in two first: the contribution hook stays ' +
|
|
304
|
+
'unprobed (the host filters it by contributor, and probing it would make runtime ' +
|
|
305
|
+
'activation require a restart, or worse — an asset-reference scanner that stops scanning ' +
|
|
306
|
+
'lets an operator delete data a switched-off module still points at), the work hook gets ' +
|
|
307
|
+
'the probe. `backend/src/modules/blog/backend.ts` and `product_feeds/backend.ts` ship the ' +
|
|
308
|
+
'shape',
|
|
309
|
+
};
|
|
310
|
+
/** The sentence an author reads for one site. One spelling, two hosts. */
|
|
311
|
+
export function remedyFor(found) {
|
|
312
|
+
return `${found.construct} in ${found.file} (${found.scheduler}) ${EXPLANATION[found.finding]}`;
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Every source this rule reads under `roots`.
|
|
316
|
+
*
|
|
317
|
+
* One spelling, both hosts: the repository host supplies its source roots and the
|
|
318
|
+
* package host supplies one package's, and neither gets to differ about which
|
|
319
|
+
* files are in the population.
|
|
320
|
+
*/
|
|
321
|
+
export function collectPresenceFiles(roots, out = []) {
|
|
322
|
+
for (const root of roots) {
|
|
323
|
+
if (!existsSync(root))
|
|
324
|
+
continue;
|
|
325
|
+
for (const name of readdirSync(root)) {
|
|
326
|
+
const full = join(root, name);
|
|
327
|
+
if (statSync(full).isDirectory()) {
|
|
328
|
+
if (name === 'node_modules' || name === 'dist')
|
|
329
|
+
continue;
|
|
330
|
+
collectPresenceFiles([full], out);
|
|
331
|
+
}
|
|
332
|
+
else if (name.endsWith('.ts') && !name.endsWith('.test.ts') && !name.endsWith('.d.ts')) {
|
|
333
|
+
out.push(full);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
return out;
|
|
338
|
+
}
|
|
339
|
+
//# sourceMappingURL=entry-presence.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entry-presence.js","sourceRoot":"","sources":["../../src/rules/entry-presence.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
export type EntryKind = 'cli' | 'program' | 'worker' | 'interval' | 'message' | 'process';
|
|
2
|
+
/**
|
|
3
|
+
* The construct a site was built from, spelled the way the source spells it.
|
|
4
|
+
*
|
|
5
|
+
* Part of the ledger key, so `setInterval` and a self-rescheduling `setTimeout`
|
|
6
|
+
* are different sites even in the same function — they are different code. The
|
|
7
|
+
* two file-level classes carry their own kind here: their construct *is* the
|
|
8
|
+
* file.
|
|
9
|
+
*/
|
|
10
|
+
export type EntryConstruct = 'cli' | 'program' | 'new Worker' | 'setInterval' | 'setTimeout' | "on('message')" | 'process.on' | 'process.once';
|
|
11
|
+
/** The scheduler slot of a file-level site: the file's own top-level execution. */
|
|
12
|
+
export declare const FILE_SCOPE = "<file>";
|
|
13
|
+
export interface EntrySite {
|
|
14
|
+
/** Path as {@link relative} reports it — `src/...`, the spelling the ledger uses. */
|
|
15
|
+
readonly file: string;
|
|
16
|
+
readonly kind: EntryKind;
|
|
17
|
+
readonly construct: EntryConstruct;
|
|
18
|
+
/** The nearest enclosing named function, `<module scope>`, or `<file>`. */
|
|
19
|
+
readonly scheduler: string;
|
|
20
|
+
/** 1-based line of the construct. */
|
|
21
|
+
readonly line: number;
|
|
22
|
+
readonly scoped: boolean;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* `<file>:<scheduler>:<construct>` — the ledger key, and the identity of a site.
|
|
26
|
+
*
|
|
27
|
+
* Line-independent, in the idiom of `check-entry-presence.ts`'s `keyOf`: moving
|
|
28
|
+
* code inside a file does not invalidate an entry, and re-opening the hole
|
|
29
|
+
* somewhere else does not silently inherit one.
|
|
30
|
+
*
|
|
31
|
+
* A key may cover **more than one site**: `index.ts` registers `SIGINT` and
|
|
32
|
+
* `SIGTERM` in the same function with the same construct, and one entry
|
|
33
|
+
* answering for both is what a reader wants there. It is deliberate, and it is
|
|
34
|
+
* the granularity's floor — two sites the key cannot tell apart are two sites
|
|
35
|
+
* one reason has to be true of.
|
|
36
|
+
*/
|
|
37
|
+
export declare function keyOf(site: EntrySite): string;
|
|
38
|
+
/**
|
|
39
|
+
* Every TypeScript source under `dir` — colocated tests included, which is the
|
|
40
|
+
* one difference from the other walks in this estate and is deliberate: a test
|
|
41
|
+
* that starts a worker is an entry point too.
|
|
42
|
+
*
|
|
43
|
+
* Exported because the population is part of the rule, not part of a host.
|
|
44
|
+
*/
|
|
45
|
+
export declare function collectEntryScopeSources(dir: string, out?: string[]): string[];
|
|
46
|
+
/**
|
|
47
|
+
* The `src/` files `package.json` runs as a process of their own.
|
|
48
|
+
*
|
|
49
|
+
* Read out of the **command**, not out of the script name: `seed:dev` is
|
|
50
|
+
* `pnpm run migration:up && tsx --env-file-if-exists=.env src/seeds/…`, so the
|
|
51
|
+
* entry point is the second of two commands behind three flags. `dist/` paths
|
|
52
|
+
* are ignored (this check reads sources) and so are `scripts/` paths outside
|
|
53
|
+
* `src/`, which the walk never sees.
|
|
54
|
+
*/
|
|
55
|
+
export declare function declaredProgramEntryPoints(packageJson: string): string[];
|
|
56
|
+
/**
|
|
57
|
+
* The path as the ledger spells it: everything from the last `/src/` on.
|
|
58
|
+
* Derived from the path itself rather than from `SRC_ROOT` so the predicates
|
|
59
|
+
* here are testable without knowing where the checkout lives.
|
|
60
|
+
*
|
|
61
|
+
* **It is the default and no longer the only answer** (feature 080, T040a). A
|
|
62
|
+
* module that has become a workspace package lives at
|
|
63
|
+
* `packages/modules/<id>/src/…`, where "everything from the last `/src/` on"
|
|
64
|
+
* drops the module and leaves `src/services/x.ts` — a key two packages would
|
|
65
|
+
* share. The CLI therefore passes `resolveModuleLayout().displayOf`, which
|
|
66
|
+
* keeps the application's own spelling byte-for-byte and answers repo-relative
|
|
67
|
+
* for anything outside it. The default stays for the predicates' own tests,
|
|
68
|
+
* which have no checkout to resolve.
|
|
69
|
+
*/
|
|
70
|
+
export declare function relative(file: string): string;
|
|
71
|
+
/** How a walked file becomes the key a site and a ledger entry are spelled with. */
|
|
72
|
+
export type PathSpelling = (file: string) => string;
|
|
73
|
+
/**
|
|
74
|
+
* Which file-level class this file belongs to, or `null` for neither.
|
|
75
|
+
*
|
|
76
|
+
* A file under `scripts/` that is *also* declared stays `cli`: fourteen of the
|
|
77
|
+
* fifteen are both, and moving them would make the count move for no reason.
|
|
78
|
+
*/
|
|
79
|
+
export declare function fileLevelKind(file: string, declared?: ReadonlySet<string>, pathOf?: PathSpelling): 'cli' | 'program' | null;
|
|
80
|
+
/**
|
|
81
|
+
* Every entry site in one file, with its own scope answer.
|
|
82
|
+
*
|
|
83
|
+
* The top of the analysis: source **text** in, sites out. A caller — a test
|
|
84
|
+
* especially — decides what the repository says it runs by passing `declared`,
|
|
85
|
+
* the set `declaredProgramEntryPoints` returned.
|
|
86
|
+
*/
|
|
87
|
+
export declare function findEntrySites(file: string, source: string, declared?: ReadonlySet<string>, pathOf?: PathSpelling): EntrySite[];
|
|
88
|
+
export declare function violationsOf(sites: readonly EntrySite[], allowed: Readonly<Record<string, string>>): EntrySite[];
|
|
89
|
+
/** Ledger entries that no longer name an unscoped entry site. */
|
|
90
|
+
export declare function staleAllowances(sites: readonly EntrySite[], allowed: Readonly<Record<string, string>>): string[];
|
|
91
|
+
//# sourceMappingURL=entry-scope.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entry-scope.d.ts","sourceRoot":"","sources":["../../src/rules/entry-scope.ts"],"names":[],"mappings":"AAoKA,MAAM,MAAM,SAAS,GAAG,KAAK,GAAG,SAAS,GAAG,QAAQ,GAAG,UAAU,GAAG,SAAS,GAAG,SAAS,CAAC;AAE1F;;;;;;;GAOG;AACH,MAAM,MAAM,cAAc,GACtB,KAAK,GACL,SAAS,GACT,YAAY,GACZ,aAAa,GACb,YAAY,GACZ,eAAe,GACf,YAAY,GACZ,cAAc,CAAC;AAEnB,mFAAmF;AACnF,eAAO,MAAM,UAAU,WAAW,CAAC;AAEnC,MAAM,WAAW,SAAS;IACxB,qFAAqF;IACrF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,SAAS,EAAE,cAAc,CAAC;IACnC,2EAA2E;IAC3E,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,qCAAqC;IACrC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CAC1B;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,KAAK,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,CAE7C;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,GAAE,MAAM,EAAO,GAAG,MAAM,EAAE,CAWlF;AAuBD;;;;;;;;GAQG;AACH,wBAAgB,0BAA0B,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,EAAE,CAOxE;AAID;;;;;;;;;;;;;GAaG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAG7C;AAED,oFAAoF;AACpF,MAAM,MAAM,YAAY,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;AAEpD;;;;;GAKG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,MAAM,EACZ,QAAQ,GAAE,WAAW,CAAC,MAAM,CAAoB,EAChD,MAAM,GAAE,YAAuB,GAC9B,KAAK,GAAG,SAAS,GAAG,IAAI,CAI1B;AAmHD;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,QAAQ,GAAE,WAAW,CAAC,MAAM,CAAoB,EAChD,MAAM,GAAE,YAAuB,GAC9B,SAAS,EAAE,CAoDb;AAED,wBAAgB,YAAY,CAC1B,KAAK,EAAE,SAAS,SAAS,EAAE,EAC3B,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GACxC,SAAS,EAAE,CAEb;AAED,iEAAiE;AACjE,wBAAgB,eAAe,CAC7B,KAAK,EAAE,SAAS,SAAS,EAAE,EAC3B,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GACxC,MAAM,EAAE,CAGV"}
|