@cplieger/deadset-ts 8.0.0-dev.2 → 8.0.0-dev.21
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/README.md +3 -1
- package/THIRD_PARTY_NOTICES.md +27 -0
- package/dist/bin/mapper-connection.js +2 -1
- package/dist/bin/node-host.js +24 -5
- package/dist/src/alias-chain.js +35 -9
- package/dist/src/amd.js +81 -0
- package/dist/src/analysis.js +274 -496
- package/dist/src/augmentations.js +64 -3
- package/dist/src/automatic-types.js +10 -29
- package/dist/src/bindings.js +382 -0
- package/dist/src/commands/held.js +499 -0
- package/dist/src/commands/read.js +161 -0
- package/dist/src/commands/shell.js +169 -0
- package/dist/src/commands/tools.js +1847 -0
- package/dist/src/component-files.js +3 -2
- package/dist/src/component-layer.js +4 -2
- package/dist/src/config.js +6 -82
- package/dist/src/conformance-record.js +2 -2
- package/dist/src/consumers.js +10 -38
- package/dist/src/contextual-uses.js +57 -26
- package/dist/src/contract/config.generated.js +561 -0
- package/dist/src/contract/contract.generated.js +1370 -0
- package/dist/src/contract/report.generated.js +866 -0
- package/dist/src/dependencies.js +165 -122
- package/dist/src/destructuring.js +1 -19
- package/dist/src/edges.js +38 -122
- package/dist/src/element-access.js +181 -168
- package/dist/src/entries/build-scripts.js +222 -0
- package/dist/src/{configuration-files.js → entries/configuration-files.js} +52 -256
- package/dist/src/{convention-rows.js → entries/convention-rows.js} +170 -30
- package/dist/src/entries/conventions.js +740 -0
- package/dist/src/{html-entries.js → entries/html-entries.js} +12 -42
- package/dist/src/{mdx-entries.js → entries/mdx-entries.js} +5 -28
- package/dist/src/entries/run-directories.js +77 -0
- package/dist/src/entries/sources.js +144 -0
- package/dist/src/entries/static-module.js +670 -0
- package/dist/src/entries/test-runners.js +650 -0
- package/dist/src/entries/workflow-steps.js +345 -0
- package/dist/src/exemptions/argument-places.js +131 -0
- package/dist/src/exemptions/calls.js +338 -0
- package/dist/src/exemptions/classes.js +13 -0
- package/dist/src/{decorator.js → exemptions/decorator.js} +19 -30
- package/dist/src/exemptions/detectors.js +48 -0
- package/dist/src/{enum-group.js → exemptions/enum-group.js} +9 -16
- package/dist/src/{erased-stores.js → exemptions/erased-stores.js} +7 -11
- package/dist/src/{framework-lifecycle.js → exemptions/framework-lifecycle.js} +76 -54
- package/dist/src/exemptions/generated-file.js +241 -0
- package/dist/src/{injection-container.js → exemptions/injection-container.js} +20 -26
- package/dist/src/exemptions/installed-globals.js +173 -0
- package/dist/src/{interface-satisfaction.js → exemptions/interface-satisfaction.js} +52 -121
- package/dist/src/exemptions/lifecycle.js +150 -0
- package/dist/src/{reflective-lookup.js → exemptions/reflective-lookup.js} +3 -3
- package/dist/src/exemptions/serialization-contract.js +1276 -0
- package/dist/src/exemptions/sites.js +182 -0
- package/dist/src/{template-field.js → exemptions/template-field.js} +13 -23
- package/dist/src/{value-reach.js → exemptions/value-reach.js} +14 -7
- package/dist/src/exposure.js +400 -0
- package/dist/src/extensions.js +37 -0
- package/dist/src/facts.js +38 -0
- package/dist/src/failure.js +36 -0
- package/dist/src/file-facts.js +3 -26
- package/dist/src/findings/completion.js +109 -56
- package/dist/src/findings/dependencies-and-module-machinery.js +4 -5
- package/dist/src/findings/emitters.js +27 -41
- package/dist/src/{implementations.js → findings/implementations.js} +3 -3
- package/dist/src/{in-operands.js → findings/in-operands.js} +3 -2
- package/dist/src/findings/interfaces.js +4 -5
- package/dist/src/findings/intra-function.js +16 -13
- package/dist/src/findings/non-code-artifacts.js +17 -12
- package/dist/src/findings/reads-and-writes.js +86 -27
- package/dist/src/findings/self-check.js +44 -30
- package/dist/src/findings/unused-declarations.js +29 -45
- package/dist/src/findings/visibility-narrowing.js +23 -31
- package/dist/src/findings-pass.js +13 -21
- package/dist/src/fs/document.js +52 -0
- package/dist/src/fs/manifest.js +67 -0
- package/dist/src/fs/tree.js +88 -0
- package/dist/src/git-ignore.js +39 -26
- package/dist/src/import-bindings.js +73 -28
- package/dist/src/index/sites.js +557 -0
- package/dist/src/index/values.js +124 -0
- package/dist/src/index.js +2 -2
- package/dist/src/indexed-access.js +523 -478
- package/dist/src/intra-function-parts.js +63 -43
- package/dist/src/inventory/commonjs.js +507 -0
- package/dist/src/inventory/enumerate.js +167 -0
- package/dist/src/inventory/syntax.js +236 -0
- package/dist/src/inventory.js +323 -724
- package/dist/src/javascript-file.js +48 -0
- package/dist/src/json-document.js +198 -67
- package/dist/src/keyof-comparisons.js +126 -107
- package/dist/src/kinds.js +3 -366
- package/dist/src/{components.js → liveness/components.js} +2 -3
- package/dist/src/{graph.js → liveness/graph.js} +52 -28
- package/dist/src/liveness/matrix.js +99 -0
- package/dist/src/liveness/sweep.js +558 -0
- package/dist/src/load/classify.js +289 -0
- package/dist/src/load/diagnostics.js +87 -0
- package/dist/src/load/discover.js +285 -0
- package/dist/src/{emit-map.js → load/emit-map.js} +1 -1
- package/dist/src/load/expected-module.js +136 -0
- package/dist/src/load/load.js +27 -0
- package/dist/src/load/module-lookup.js +37 -0
- package/dist/src/load/package-scope.js +56 -0
- package/dist/src/load/plan.js +313 -0
- package/dist/src/load/specifiers.js +113 -0
- package/dist/src/load/synthesize.js +152 -0
- package/dist/src/load/test-globals.js +207 -0
- package/dist/src/load/test-joins.js +82 -0
- package/dist/src/{workspace-manifests.js → load/workspace-manifests.js} +4 -4
- package/dist/src/{workspace-programs.js → load/workspace-programs.js} +89 -66
- package/dist/src/{workspace-resolution.js → load/workspace-resolution.js} +24 -66
- package/dist/src/{workspace-run.js → load/workspace-run.js} +7 -7
- package/dist/src/{workspace.js → load/workspace.js} +62 -124
- package/dist/src/module-declarations.js +70 -85
- package/dist/src/overrides.js +134 -112
- package/dist/src/partial.js +2 -1
- package/dist/src/paths.js +82 -16
- package/dist/src/platform-calls.js +78 -0
- package/dist/src/platform-symbols.js +134 -0
- package/dist/src/position.js +43 -1
- package/dist/src/print.js +11 -79
- package/dist/src/product.js +13 -0
- package/dist/src/query.js +95 -0
- package/dist/src/ref.js +12 -20
- package/dist/src/references/read-rule.js +1 -0
- package/dist/src/references/read-rules.js +48 -0
- package/dist/src/references/sink.js +237 -0
- package/dist/src/references/sources.js +450 -0
- package/dist/src/references.js +117 -1074
- package/dist/src/report-schema.js +51 -0
- package/dist/src/report.js +57 -41
- package/dist/src/reporters/annotations.js +15 -8
- package/dist/src/reporters/sarif.js +16 -10
- package/dist/src/reporters/template.js +4 -19
- package/dist/src/resolve.js +246 -730
- package/dist/src/{configured-declarations.js → roots/configured-declarations.js} +22 -24
- package/dist/src/{entry-point-gaps.js → roots/entry-point-gaps.js} +6 -15
- package/dist/src/roots/manifest.js +216 -0
- package/dist/src/roots/published-reach.js +412 -0
- package/dist/src/roots/root-set.js +487 -0
- package/dist/src/roots/unseen-loads.js +236 -0
- package/dist/src/run.js +66 -77
- package/dist/src/schema.js +320 -343
- package/dist/src/scope.js +38 -115
- package/dist/src/session.js +37 -29
- package/dist/src/source-files.js +6 -10
- package/dist/src/stores.js +4 -2
- package/dist/src/suppress-file.js +25 -28
- package/dist/src/suppress-inline.js +36 -83
- package/dist/src/suppress.js +50 -71
- package/dist/src/symbol-keys.js +92 -88
- package/dist/src/tests/file-class.js +76 -0
- package/dist/src/{outside-tests.js → tests/outside.js} +7 -7
- package/dist/src/{test-support.js → tests/support.js} +5 -12
- package/dist/src/text/compare.js +26 -0
- package/dist/src/text/glob.js +194 -0
- package/dist/src/text/named-files.js +298 -0
- package/dist/src/text/yaml.js +684 -0
- package/dist/src/type-errors.js +11 -232
- package/dist/src/type-parameter-reads.js +178 -139
- package/dist/src/unimplemented-callees.js +262 -242
- package/dist/src/unwrap.js +23 -0
- package/dist/src/usage.js +10 -0
- package/dist/src/vendor/unbash/ansi-c.js +132 -0
- package/dist/src/vendor/unbash/arithmetic-parts.js +37 -0
- package/dist/src/vendor/unbash/arithmetic.js +591 -0
- package/dist/src/vendor/unbash/assignment.js +131 -0
- package/dist/src/vendor/unbash/chars.js +48 -0
- package/dist/src/vendor/unbash/command.js +41 -0
- package/dist/src/vendor/unbash/expansion.js +80 -0
- package/dist/src/vendor/unbash/glob.js +268 -0
- package/dist/src/vendor/unbash/heredoc.js +27 -0
- package/dist/src/vendor/unbash/internal-types.js +1 -0
- package/dist/src/vendor/unbash/lexer.js +4274 -0
- package/dist/src/vendor/unbash/limits.js +3 -0
- package/dist/src/vendor/unbash/parser.js +1366 -0
- package/dist/src/vendor/unbash/parts.js +57 -0
- package/dist/src/vendor/unbash/substitution-context.js +8 -0
- package/dist/src/vendor/unbash/traversal.js +212 -0
- package/dist/src/vendor/unbash/types.js +1 -0
- package/dist/src/vendor/unbash/word-value.js +61 -0
- package/dist/src/vendor/unbash/word.js +40 -0
- package/dist/src/verbs/analyze.js +194 -127
- package/dist/src/verbs/describe.js +13 -18
- package/dist/src/verbs/explain.js +85 -139
- package/dist/src/verbs/print-config.js +2 -1
- package/dist/src/verbs/print-projects.js +6 -4
- package/dist/src/verbs/print-retained.js +30 -6
- package/dist/src/verbs/print-roots.js +4 -2
- package/dist/src/verbs/verb.js +1 -5
- package/dist/src/verbs/version.js +14 -3
- package/jsr.json +2 -1
- package/package.json +14 -8
- package/src/alias-chain.ts +40 -11
- package/src/amd.ts +130 -0
- package/src/analysis.ts +426 -733
- package/src/augmentations.ts +93 -4
- package/src/automatic-types.ts +12 -30
- package/src/bindings.ts +460 -0
- package/src/commands/held.ts +632 -0
- package/src/commands/read.ts +242 -0
- package/src/commands/shell.ts +228 -0
- package/src/commands/tools.ts +2382 -0
- package/src/component-files.ts +4 -2
- package/src/component-layer.ts +4 -2
- package/src/config.ts +31 -302
- package/src/conformance-record.ts +2 -2
- package/src/consumers.ts +16 -66
- package/src/contextual-uses.ts +66 -34
- package/src/contract/config.generated.ts +821 -0
- package/src/contract/contract.generated.ts +1453 -0
- package/src/contract/report.generated.ts +1241 -0
- package/src/dependencies.ts +223 -128
- package/src/destructuring.ts +1 -31
- package/src/edges.ts +41 -140
- package/src/element-access.ts +190 -187
- package/src/entries/build-scripts.ts +292 -0
- package/src/{configuration-files.ts → entries/configuration-files.ts} +68 -278
- package/src/{convention-rows.ts → entries/convention-rows.ts} +227 -31
- package/src/{conventions.ts → entries/conventions.ts} +367 -583
- package/src/{html-entries.ts → entries/html-entries.ts} +22 -48
- package/src/{mdx-entries.ts → entries/mdx-entries.ts} +7 -30
- package/src/entries/run-directories.ts +108 -0
- package/src/entries/sources.ts +266 -0
- package/src/entries/static-module.ts +858 -0
- package/src/entries/test-runners.ts +835 -0
- package/src/entries/workflow-steps.ts +432 -0
- package/src/exemptions/argument-places.ts +198 -0
- package/src/exemptions/calls.ts +483 -0
- package/src/exemptions/classes.ts +49 -0
- package/src/exemptions/decorator.ts +56 -0
- package/src/exemptions/detectors.ts +75 -0
- package/src/{enum-group.ts → exemptions/enum-group.ts} +10 -19
- package/src/{erased-stores.ts → exemptions/erased-stores.ts} +7 -14
- package/src/{framework-lifecycle.ts → exemptions/framework-lifecycle.ts} +85 -66
- package/src/exemptions/generated-file.ts +318 -0
- package/src/{injection-container.ts → exemptions/injection-container.ts} +29 -34
- package/src/exemptions/installed-globals.ts +255 -0
- package/src/{interface-satisfaction.ts → exemptions/interface-satisfaction.ts} +69 -160
- package/src/exemptions/lifecycle.ts +286 -0
- package/src/{reflective-lookup.ts → exemptions/reflective-lookup.ts} +5 -5
- package/src/exemptions/serialization-contract.ts +1729 -0
- package/src/exemptions/sites.ts +293 -0
- package/src/{template-field.ts → exemptions/template-field.ts} +22 -32
- package/src/{value-reach.ts → exemptions/value-reach.ts} +16 -8
- package/src/exposure.ts +492 -0
- package/src/extensions.ts +45 -0
- package/src/facts.ts +46 -0
- package/src/failure.ts +63 -0
- package/src/file-facts.ts +15 -25
- package/src/finding.ts +10 -10
- package/src/findings/boundary.ts +11 -0
- package/src/findings/completion.ts +133 -64
- package/src/findings/dependencies-and-module-machinery.ts +4 -7
- package/src/findings/emitter.ts +9 -10
- package/src/findings/emitters.ts +38 -52
- package/src/{implementations.ts → findings/implementations.ts} +4 -4
- package/src/{in-operands.ts → findings/in-operands.ts} +4 -3
- package/src/findings/interfaces.ts +7 -9
- package/src/findings/intra-function.ts +16 -14
- package/src/findings/non-code-artifacts.ts +24 -15
- package/src/findings/reads-and-writes.ts +118 -41
- package/src/findings/self-check.ts +51 -38
- package/src/findings/unused-declarations.ts +31 -49
- package/src/findings/visibility-narrowing.ts +36 -40
- package/src/findings-pass.ts +15 -31
- package/src/fs/document.ts +70 -0
- package/src/fs/manifest.ts +96 -0
- package/src/fs/tree.ts +110 -0
- package/src/git-ignore.ts +50 -26
- package/src/host.ts +12 -5
- package/src/import-bindings.ts +98 -29
- package/src/index/sites.ts +781 -0
- package/src/index/values.ts +170 -0
- package/src/index.ts +2 -2
- package/src/indexed-access.ts +570 -527
- package/src/intra-function-parts.ts +73 -44
- package/src/inventory/commonjs.ts +696 -0
- package/src/inventory/enumerate.ts +203 -0
- package/src/inventory/syntax.ts +311 -0
- package/src/inventory.ts +442 -895
- package/src/javascript-file.ts +54 -0
- package/src/json-document.ts +241 -76
- package/src/keyof-comparisons.ts +133 -122
- package/src/kinds.ts +5 -413
- package/src/{components.ts → liveness/components.ts} +4 -6
- package/src/{graph.ts → liveness/graph.ts} +100 -35
- package/src/liveness/matrix.ts +162 -0
- package/src/liveness/sweep.ts +855 -0
- package/src/load/classify.ts +433 -0
- package/src/load/diagnostics.ts +154 -0
- package/src/load/discover.ts +471 -0
- package/src/{emit-map.ts → load/emit-map.ts} +1 -1
- package/src/load/expected-module.ts +194 -0
- package/src/load/load.ts +73 -0
- package/src/load/module-lookup.ts +50 -0
- package/src/load/package-scope.ts +74 -0
- package/src/load/plan.ts +513 -0
- package/src/load/specifiers.ts +171 -0
- package/src/load/synthesize.ts +230 -0
- package/src/load/test-globals.ts +251 -0
- package/src/load/test-joins.ts +98 -0
- package/src/{workspace-manifests.ts → load/workspace-manifests.ts} +5 -5
- package/src/{workspace-programs.ts → load/workspace-programs.ts} +128 -85
- package/src/{workspace-resolution.ts → load/workspace-resolution.ts} +41 -77
- package/src/{workspace-run.ts → load/workspace-run.ts} +18 -16
- package/src/{workspace.ts → load/workspace.ts} +90 -134
- package/src/module-declarations.ts +74 -98
- package/src/overrides.ts +162 -134
- package/src/partial.ts +3 -2
- package/src/paths.ts +92 -16
- package/src/platform-calls.ts +119 -0
- package/src/platform-symbols.ts +189 -0
- package/src/position.ts +44 -1
- package/src/print.ts +12 -92
- package/src/product.ts +18 -0
- package/src/query.ts +201 -10
- package/src/ref.ts +12 -20
- package/src/references/read-rule.ts +60 -0
- package/src/references/read-rules.ts +55 -0
- package/src/references/sink.ts +314 -0
- package/src/references/sources.ts +632 -0
- package/src/references.ts +187 -1450
- package/src/report-schema.ts +68 -0
- package/src/report.ts +103 -226
- package/src/reporters/annotations.ts +22 -11
- package/src/reporters/json.ts +1 -1
- package/src/reporters/reporter.ts +2 -4
- package/src/reporters/reporters.ts +1 -1
- package/src/reporters/sarif.ts +29 -16
- package/src/reporters/template.ts +4 -20
- package/src/reporters/text.ts +3 -3
- package/src/resolve.ts +284 -1115
- package/src/{configured-declarations.ts → roots/configured-declarations.ts} +26 -29
- package/src/{entry-point-gaps.ts → roots/entry-point-gaps.ts} +7 -16
- package/src/roots/manifest.ts +303 -0
- package/src/roots/published-reach.ts +486 -0
- package/src/{roots.ts → roots/root-set.ts} +286 -469
- package/src/roots/unseen-loads.ts +345 -0
- package/src/run.ts +75 -91
- package/src/schema.ts +391 -388
- package/src/scope.ts +46 -138
- package/src/session.ts +87 -55
- package/src/source-files.ts +6 -11
- package/src/stores.ts +15 -3
- package/src/suppress-file.ts +24 -33
- package/src/suppress-inline.ts +55 -91
- package/src/suppress.ts +78 -79
- package/src/symbol-keys.ts +104 -107
- package/src/tests/file-class.ts +135 -0
- package/src/{outside-tests.ts → tests/outside.ts} +16 -10
- package/src/{test-support.ts → tests/support.ts} +15 -21
- package/src/text/compare.ts +27 -0
- package/src/text/glob.ts +210 -0
- package/src/text/named-files.ts +388 -0
- package/src/text/yaml.ts +747 -0
- package/src/type-errors.ts +18 -288
- package/src/type-parameter-reads.ts +187 -158
- package/src/unimplemented-callees.ts +297 -280
- package/src/unwrap.ts +34 -0
- package/src/usage.ts +10 -0
- package/src/vendor/unbash/LICENSE +15 -0
- package/src/vendor/unbash/VENDORED.md +16 -0
- package/src/vendor/unbash/ansi-c.ts +132 -0
- package/src/vendor/unbash/arithmetic-parts.ts +53 -0
- package/src/vendor/unbash/arithmetic.ts +641 -0
- package/src/vendor/unbash/assignment.ts +163 -0
- package/src/vendor/unbash/chars.ts +48 -0
- package/src/vendor/unbash/command.ts +47 -0
- package/src/vendor/unbash/expansion.ts +144 -0
- package/src/vendor/unbash/glob.ts +284 -0
- package/src/vendor/unbash/heredoc.ts +34 -0
- package/src/vendor/unbash/internal-types.ts +94 -0
- package/src/vendor/unbash/lexer.ts +4352 -0
- package/src/vendor/unbash/limits.ts +3 -0
- package/src/vendor/unbash/parser.ts +1612 -0
- package/src/vendor/unbash/parts.ts +96 -0
- package/src/vendor/unbash/substitution-context.ts +20 -0
- package/src/vendor/unbash/traversal.ts +182 -0
- package/src/vendor/unbash/types.ts +660 -0
- package/src/vendor/unbash/word-value.ts +64 -0
- package/src/vendor/unbash/word.ts +50 -0
- package/src/verbs/analyze.ts +255 -164
- package/src/verbs/describe.ts +19 -17
- package/src/verbs/explain.ts +93 -169
- package/src/verbs/print-config.ts +2 -1
- package/src/verbs/print-projects.ts +6 -4
- package/src/verbs/print-retained.ts +36 -6
- package/src/verbs/print-roots.ts +4 -2
- package/src/verbs/verb.ts +2 -8
- package/src/verbs/version.ts +15 -3
- package/dist/src/base-url.js +0 -18
- package/dist/src/calls.js +0 -155
- package/dist/src/conventions.js +0 -937
- package/dist/src/discover.js +0 -468
- package/dist/src/entry-points.js +0 -529
- package/dist/src/exempt-classes.js +0 -75
- package/dist/src/exempt.js +0 -209
- package/dist/src/generated-file.js +0 -95
- package/dist/src/glob.js +0 -65
- package/dist/src/manifest.js +0 -165
- package/dist/src/matrix.js +0 -246
- package/dist/src/pnpm-workspace.js +0 -120
- package/dist/src/roots.js +0 -672
- package/dist/src/serialization-contract.js +0 -611
- package/dist/src/setup-failure.js +0 -23
- package/dist/src/sweep.js +0 -224
- package/dist/src/test-joins.js +0 -101
- package/dist/src/value-flow.js +0 -74
- package/dist/src/version.js +0 -7
- package/dist/src/workflow-steps.js +0 -185
- package/src/base-url.ts +0 -24
- package/src/calls.ts +0 -225
- package/src/decorator.ts +0 -78
- package/src/discover.ts +0 -653
- package/src/entry-points.ts +0 -687
- package/src/exempt-classes.ts +0 -123
- package/src/exempt.ts +0 -323
- package/src/generated-file.ts +0 -111
- package/src/glob.ts +0 -67
- package/src/manifest.ts +0 -234
- package/src/matrix.ts +0 -423
- package/src/pnpm-workspace.ts +0 -135
- package/src/serialization-contract.ts +0 -849
- package/src/setup-failure.ts +0 -39
- package/src/sweep.ts +0 -347
- package/src/test-joins.ts +0 -120
- package/src/value-flow.ts +0 -104
- package/src/version.ts +0 -7
- package/src/workflow-steps.ts +0 -216
package/src/manifest.ts
DELETED
|
@@ -1,234 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The entry points a package manifest names, which are roots because something
|
|
3
|
-
* outside the analyzed program reaches them: a consumer importing the package, or a
|
|
4
|
-
* shell running its command or one of its scripts. {@link readManifest} reads one
|
|
5
|
-
* directory's manifest, {@link packageEntries} those of the packages below the target root.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import type { Host } from "./host.ts";
|
|
9
|
-
import { isAbsolutePath, joinPath, relativePath, resolvePath } from "./paths.ts";
|
|
10
|
-
|
|
11
|
-
/** The manifest's own name. */
|
|
12
|
-
const MANIFEST = "package.json";
|
|
13
|
-
|
|
14
|
-
/** The three members that name an entry point beside `exports` and `bin`. */
|
|
15
|
-
const LEGACY_MEMBERS = ["main", "module", "types"] as const;
|
|
16
|
-
|
|
17
|
-
/** What reaches one entry point the manifest names. */
|
|
18
|
-
type EntryRole =
|
|
19
|
-
/** A consumer importing the package, which is a caller the analysis cannot see. */
|
|
20
|
-
| "import"
|
|
21
|
-
/** A shell running the package's command, which is a caller that exists. */
|
|
22
|
-
| "run"
|
|
23
|
-
/** A token of one of the package's scripts, which the package manager runs. */
|
|
24
|
-
| "script";
|
|
25
|
-
|
|
26
|
-
/** One entry point the manifest names. */
|
|
27
|
-
export interface ManifestEntry {
|
|
28
|
-
/**
|
|
29
|
-
* The member that named it, spelled as a reader of the manifest reads one:
|
|
30
|
-
* `main`, `bin["deadset-ts"]`, `exports["."]["import"]`. It is what a maintainer
|
|
31
|
-
* edits, so it is what a root reports as the string that named it.
|
|
32
|
-
*/
|
|
33
|
-
readonly member: string;
|
|
34
|
-
/** The target the member carries, resolved against the manifest's directory. */
|
|
35
|
-
readonly path: string;
|
|
36
|
-
readonly role: EntryRole;
|
|
37
|
-
/**
|
|
38
|
-
* Whether the member declares what a consumer may import, which is `exports` and
|
|
39
|
-
* the three members that preceded it. A command is published too, and is not this:
|
|
40
|
-
* `exports` is the surface a library's published API is read from.
|
|
41
|
-
*/
|
|
42
|
-
readonly published: boolean;
|
|
43
|
-
/** The directory of the manifest that names it, which `path` was resolved against. */
|
|
44
|
-
readonly dir: string;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
48
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Whether one member's value names a file of this package rather than another
|
|
53
|
-
* package or a URL. A target written with no leading dot is a path too, which is
|
|
54
|
-
* how the members that preceded `exports` are written.
|
|
55
|
-
*/
|
|
56
|
-
function isTarget(value: string, requireDot: boolean): boolean {
|
|
57
|
-
if (value === "" || isAbsolutePath(value) || value.includes("://")) {
|
|
58
|
-
return false;
|
|
59
|
-
}
|
|
60
|
-
return !requireDot || value.startsWith("./");
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/** Where a script's command line splits into tokens: white space and the shell's operators. */
|
|
64
|
-
const SCRIPT_SEPARATORS = /\s+|&&|\|\||;|\|/u;
|
|
65
|
-
|
|
66
|
-
/** A token written inside one pair of quotes. */
|
|
67
|
-
const QUOTED = /^(["'])(.*)\1$/su;
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Every token one script's command line holds, each with one pair of enclosing quotes
|
|
71
|
-
* removed. A token holding a wildcard is a pattern rather than a path, and names no
|
|
72
|
-
* entry point.
|
|
73
|
-
*/
|
|
74
|
-
export function scriptTokens(command: string): readonly string[] {
|
|
75
|
-
return command
|
|
76
|
-
.split(SCRIPT_SEPARATORS)
|
|
77
|
-
.map((token) => token.replace(QUOTED, "$2"))
|
|
78
|
-
.filter((token) => token !== "" && !token.includes("*"));
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/** One member's spelling below another: `exports` then `exports["."]`. */
|
|
82
|
-
function below(member: string, key: string): string {
|
|
83
|
-
return `${member}[${JSON.stringify(key)}]`;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Every target one `exports` value carries, at the member each is written under.
|
|
88
|
-
*
|
|
89
|
-
* The value nests strings, subpath or condition objects and alternative arrays to
|
|
90
|
-
* any depth; a `null` blocks a subpath. Every level is walked, because each
|
|
91
|
-
* condition names its own entry file, and a key's meaning is never read.
|
|
92
|
-
*/
|
|
93
|
-
function exportTargets(value: unknown, member: string, found: Omit<ManifestEntry, "dir">[]): void {
|
|
94
|
-
if (typeof value === "string") {
|
|
95
|
-
if (isTarget(value, true)) {
|
|
96
|
-
found.push({ member, path: value, role: "import", published: true });
|
|
97
|
-
}
|
|
98
|
-
return;
|
|
99
|
-
}
|
|
100
|
-
if (Array.isArray(value)) {
|
|
101
|
-
value.forEach((alternative, index) => {
|
|
102
|
-
exportTargets(alternative, below(member, String(index)), found);
|
|
103
|
-
});
|
|
104
|
-
return;
|
|
105
|
-
}
|
|
106
|
-
if (!isRecord(value)) {
|
|
107
|
-
return;
|
|
108
|
-
}
|
|
109
|
-
for (const [key, held] of Object.entries(value)) {
|
|
110
|
-
exportTargets(held, below(member, key), found);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/** The manifest at the target root, decoded, or undefined where there is none to read. */
|
|
115
|
-
function manifestOf(host: Host, targetRoot: string): Record<string, unknown> | undefined {
|
|
116
|
-
let text: string;
|
|
117
|
-
try {
|
|
118
|
-
text = host.readFile(joinPath(targetRoot, MANIFEST));
|
|
119
|
-
} catch {
|
|
120
|
-
return undefined;
|
|
121
|
-
}
|
|
122
|
-
let value: unknown;
|
|
123
|
-
try {
|
|
124
|
-
value = JSON.parse(text);
|
|
125
|
-
} catch {
|
|
126
|
-
// A manifest this program cannot read names no entry point, which is the same
|
|
127
|
-
// answer as an absent one. What a manifest's contents say is not refused here:
|
|
128
|
-
// the package manager owns that refusal, and an analysis of a tree it rejects
|
|
129
|
-
// is not the run's subject.
|
|
130
|
-
return undefined;
|
|
131
|
-
}
|
|
132
|
-
return isRecord(value) ? value : undefined;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
/** What one manifest declares about where its package is entered. */
|
|
136
|
-
export interface Manifest {
|
|
137
|
-
/**
|
|
138
|
-
* Every entry point the manifest names, in the order the members are read: `main`,
|
|
139
|
-
* `module`, `types`, then each `bin` command, then every target of `exports`, then
|
|
140
|
-
* every token of each script, which names a file only where one is at its path. Each
|
|
141
|
-
* path is absolute.
|
|
142
|
-
*/
|
|
143
|
-
readonly entries: readonly ManifestEntry[];
|
|
144
|
-
/**
|
|
145
|
-
* Whether an `exports` member is written at all. A package that declares one has
|
|
146
|
-
* said exactly what a consumer may import, so its published API is what `exports`
|
|
147
|
-
* reaches; a package that declares none publishes whatever the members that
|
|
148
|
-
* preceded it name.
|
|
149
|
-
*/
|
|
150
|
-
readonly declaresExports: boolean;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
/**
|
|
154
|
-
* What the manifest in `targetRoot` declares about where its package is entered.
|
|
155
|
-
*
|
|
156
|
-
* A target is taken as written. It is not resolved to a source file here, because
|
|
157
|
-
* which file a target names is a fact about the compiler configuration that emits
|
|
158
|
-
* it and there is one such configuration per project, while there is one manifest.
|
|
159
|
-
*/
|
|
160
|
-
export function readManifest(host: Host, targetRoot: string): Manifest {
|
|
161
|
-
const manifest = manifestOf(host, targetRoot);
|
|
162
|
-
if (manifest === undefined) {
|
|
163
|
-
return { entries: [], declaresExports: false };
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
const found: Omit<ManifestEntry, "dir">[] = [];
|
|
167
|
-
for (const member of LEGACY_MEMBERS) {
|
|
168
|
-
const value = manifest[member];
|
|
169
|
-
if (typeof value === "string" && isTarget(value, false)) {
|
|
170
|
-
found.push({ member, path: value, role: "import", published: true });
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
const bin = manifest["bin"];
|
|
175
|
-
if (typeof bin === "string" && isTarget(bin, false)) {
|
|
176
|
-
found.push({ member: "bin", path: bin, role: "run", published: false });
|
|
177
|
-
} else if (isRecord(bin)) {
|
|
178
|
-
for (const [command, value] of Object.entries(bin)) {
|
|
179
|
-
if (typeof value === "string" && isTarget(value, false)) {
|
|
180
|
-
found.push({ member: below("bin", command), path: value, role: "run", published: false });
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
exportTargets(manifest["exports"], "exports", found);
|
|
186
|
-
|
|
187
|
-
const scripts = manifest["scripts"];
|
|
188
|
-
if (isRecord(scripts)) {
|
|
189
|
-
for (const [name, command] of Object.entries(scripts)) {
|
|
190
|
-
if (typeof command !== "string") {
|
|
191
|
-
continue;
|
|
192
|
-
}
|
|
193
|
-
for (const token of new Set(scriptTokens(command))) {
|
|
194
|
-
found.push({
|
|
195
|
-
member: below("scripts", name),
|
|
196
|
-
path: token,
|
|
197
|
-
role: "script",
|
|
198
|
-
published: false,
|
|
199
|
-
});
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
return {
|
|
205
|
-
entries: found.map((entry) => ({
|
|
206
|
-
...entry,
|
|
207
|
-
path: resolvePath(targetRoot, entry.path),
|
|
208
|
-
dir: targetRoot,
|
|
209
|
-
})),
|
|
210
|
-
declaresExports: manifest["exports"] !== undefined,
|
|
211
|
-
};
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
/**
|
|
215
|
-
* The entry points the manifests of the nested packages in `dirs` name. Each entry is
|
|
216
|
-
* spelled under its manifest's path below the target root, and is published by its own
|
|
217
|
-
* manifest's rule, as the target's own entries are.
|
|
218
|
-
*/
|
|
219
|
-
export function packageEntries(
|
|
220
|
-
host: Host,
|
|
221
|
-
targetRoot: string,
|
|
222
|
-
dirs: readonly string[],
|
|
223
|
-
): readonly ManifestEntry[] {
|
|
224
|
-
return dirs.flatMap((dir) => {
|
|
225
|
-
const manifest = readManifest(host, dir);
|
|
226
|
-
const where = `${relativePath(targetRoot, dir) ?? dir}/${MANIFEST}`;
|
|
227
|
-
return manifest.entries.map((entry) => ({
|
|
228
|
-
...entry,
|
|
229
|
-
member: `${where} ${entry.member}`,
|
|
230
|
-
published:
|
|
231
|
-
entry.published && (!manifest.declaresExports || entry.member.startsWith("exports")),
|
|
232
|
-
}));
|
|
233
|
-
});
|
|
234
|
-
}
|
package/src/matrix.ts
DELETED
|
@@ -1,423 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* One run's projects as one matrix: every declaration any project holds, keyed by its
|
|
3
|
-
* position and carrying the configurations that hold it, swept once per configuration
|
|
4
|
-
* and intersected, with the dead components computed once over every configuration.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { componentsOf, type Component, type Positional } from "./components.ts";
|
|
8
|
-
import { graphOf, OUTSIDE, type Graph } from "./graph.ts";
|
|
9
|
-
import type { InventorySymbol } from "./inventory.ts";
|
|
10
|
-
import { byPosition } from "./position.ts";
|
|
11
|
-
import type { Reference } from "./references.ts";
|
|
12
|
-
import type { Root } from "./roots.ts";
|
|
13
|
-
import {
|
|
14
|
-
reachedWithTheTests,
|
|
15
|
-
sweep,
|
|
16
|
-
type Candidate,
|
|
17
|
-
type Liveness,
|
|
18
|
-
type Relation,
|
|
19
|
-
type SweepInput,
|
|
20
|
-
} from "./sweep.ts";
|
|
21
|
-
|
|
22
|
-
/** What the passes answered for one configuration of the run. */
|
|
23
|
-
export interface Configured {
|
|
24
|
-
/** The name discovery gives the configuration's project. */
|
|
25
|
-
readonly configuration: string;
|
|
26
|
-
readonly symbols: readonly InventorySymbol[];
|
|
27
|
-
readonly references: readonly Reference[];
|
|
28
|
-
readonly roots: readonly Root[];
|
|
29
|
-
/** The paths the reference pass classified as test files. */
|
|
30
|
-
readonly testFiles: readonly string[];
|
|
31
|
-
/** The paths of the test-support files, which only test code imports. */
|
|
32
|
-
readonly supportFiles?: readonly string[] | undefined;
|
|
33
|
-
/** The paths of the files only tests reach that are no test-support file. */
|
|
34
|
-
readonly testUsedFiles?: readonly string[] | undefined;
|
|
35
|
-
/** The ids of the ambient declarations, which describe code the target does not implement. */
|
|
36
|
-
readonly ambient?: ReadonlySet<string> | undefined;
|
|
37
|
-
/**
|
|
38
|
-
* The paths of the workspace-package files the configuration holds but does not
|
|
39
|
-
* compile itself. Their declarations count in its graph and its verdict on them is no
|
|
40
|
-
* finding.
|
|
41
|
-
*/
|
|
42
|
-
readonly referenceOnly?: readonly string[] | undefined;
|
|
43
|
-
/** Each declaration's dependents, by id, as the configuration's inventory states them. */
|
|
44
|
-
readonly dependents?: ReadonlyMap<string, readonly string[]> | undefined;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/** The run's configurations, indexed for the sweep. */
|
|
48
|
-
export interface Matrix {
|
|
49
|
-
/** The configurations, in the run's order. */
|
|
50
|
-
readonly configurations: readonly string[];
|
|
51
|
-
/** Per configuration, in the same order, the graph of what that configuration holds. */
|
|
52
|
-
readonly graphs: readonly Graph[];
|
|
53
|
-
/**
|
|
54
|
-
* The graph over every configuration at once: every declaration a configuration
|
|
55
|
-
* holds in a file it does not hold only for its references, once per position and in
|
|
56
|
-
* site order, and every reference any configuration makes, a reference several
|
|
57
|
-
* configurations make at one position counted once.
|
|
58
|
-
*/
|
|
59
|
-
readonly union: Graph;
|
|
60
|
-
/**
|
|
61
|
-
* Per declaration of {@link Matrix.union}, at its position there, the configurations
|
|
62
|
-
* whose project holds it, in the run's order.
|
|
63
|
-
*/
|
|
64
|
-
readonly heldIn: readonly (readonly string[])[];
|
|
65
|
-
/**
|
|
66
|
-
* Per declaration of {@link Matrix.union}, whether a file only tests reach that is no
|
|
67
|
-
* test-support file holds it in some configuration: production code only tests use.
|
|
68
|
-
*/
|
|
69
|
-
readonly testUsed: readonly boolean[];
|
|
70
|
-
/** Each declaration's dependents, by id, as the first configuration holding it states them. */
|
|
71
|
-
readonly dependents: ReadonlyMap<string, readonly string[]>;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/** One declaration dead in every configuration that holds it. */
|
|
75
|
-
export interface MatrixCandidate extends Candidate {
|
|
76
|
-
/** The configurations the declaration is dead in, which are every one that holds it. */
|
|
77
|
-
readonly configurations: readonly string[];
|
|
78
|
-
/**
|
|
79
|
-
* The declaration of test-support code that test code references, outside the
|
|
80
|
-
* test-of-dead-code rule, that is or contains this one, the outermost where two do.
|
|
81
|
-
* Such a declaration is not dead while test code references it, so neither it nor a
|
|
82
|
-
* declaration it contains is a member of a dead component.
|
|
83
|
-
*/
|
|
84
|
-
readonly heldByTests: string | undefined;
|
|
85
|
-
/**
|
|
86
|
-
* Whether a test file declares it, no test of dead code, and the run that counts test
|
|
87
|
-
* references does not reach it: it is reported as a production declaration of its
|
|
88
|
-
* shape nothing references would be.
|
|
89
|
-
*/
|
|
90
|
-
readonly unreferencedTest: boolean;
|
|
91
|
-
/**
|
|
92
|
-
* Whether it is dead only because code only tests use is: production code only tests
|
|
93
|
-
* use holds it and the run that counts test references reaches it, or such a
|
|
94
|
-
* declaration reaches it through dead declarations.
|
|
95
|
-
*/
|
|
96
|
-
readonly testUsed: boolean;
|
|
97
|
-
/**
|
|
98
|
-
* Whether test code the run that counts test references reaches, and that is no test of
|
|
99
|
-
* dead code, references it: a test that stays keeps it.
|
|
100
|
-
*/
|
|
101
|
-
readonly keptByTests: boolean;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
/** One run's sweep. */
|
|
105
|
-
export interface SweepResult {
|
|
106
|
-
/**
|
|
107
|
-
* Per declaration, the relations that hold it live in at least one configuration,
|
|
108
|
-
* reference counting first. A declaration no relation holds live anywhere has no entry.
|
|
109
|
-
*/
|
|
110
|
-
readonly liveUnder: ReadonlyMap<string, readonly Relation[]>;
|
|
111
|
-
/** The declarations dead in every configuration that holds them, in site order. */
|
|
112
|
-
readonly candidates: readonly MatrixCandidate[];
|
|
113
|
-
/** The dead components, each before every component it reaches, each identifier once per run. */
|
|
114
|
-
readonly components: readonly Component[];
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* What makes one reference one reference, whichever configuration made it. A consumer's
|
|
119
|
-
* position is rendered against its own root, so the consumer is part of what it names.
|
|
120
|
-
*/
|
|
121
|
-
export function referenceKey(reference: Reference): string {
|
|
122
|
-
const { path, line, column } = reference.position;
|
|
123
|
-
return [
|
|
124
|
-
reference.consumer ?? "",
|
|
125
|
-
reference.from,
|
|
126
|
-
reference.to,
|
|
127
|
-
path,
|
|
128
|
-
String(line),
|
|
129
|
-
String(column),
|
|
130
|
-
reference.use,
|
|
131
|
-
].join("\u0000");
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Indexes what the passes answered for each configuration of one run, in the run's order.
|
|
136
|
-
* A declaration is keyed by its rendered position, with the fields of the first
|
|
137
|
-
* configuration that judges it; one in a file every holder holds only for its references
|
|
138
|
-
* is judged by none and is not in the union. One reference at one position of a file
|
|
139
|
-
* several configurations compile is one reference; two one configuration makes are two.
|
|
140
|
-
*/
|
|
141
|
-
export function matrixOf(per: readonly Configured[]): Matrix {
|
|
142
|
-
const symbols: InventorySymbol[] = [];
|
|
143
|
-
const holders = new Map<string, string[]>();
|
|
144
|
-
const references: Reference[] = [];
|
|
145
|
-
const firstSeen = new Map<string, number>();
|
|
146
|
-
const judged = new Set<string>();
|
|
147
|
-
const dependents = new Map<string, readonly string[]>();
|
|
148
|
-
per.forEach((one, index) => {
|
|
149
|
-
for (const [id, after] of one.dependents ?? []) {
|
|
150
|
-
if (!dependents.has(id)) {
|
|
151
|
-
dependents.set(id, after);
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
const referenceOnly = new Set(one.referenceOnly);
|
|
155
|
-
for (const symbol of one.symbols) {
|
|
156
|
-
const held = holders.get(symbol.id);
|
|
157
|
-
if (held === undefined) {
|
|
158
|
-
holders.set(symbol.id, [one.configuration]);
|
|
159
|
-
} else if (!held.includes(one.configuration)) {
|
|
160
|
-
held.push(one.configuration);
|
|
161
|
-
}
|
|
162
|
-
if (!referenceOnly.has(symbol.position.path) && !judged.has(symbol.id)) {
|
|
163
|
-
judged.add(symbol.id);
|
|
164
|
-
symbols.push(symbol);
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
for (const reference of one.references) {
|
|
168
|
-
const key = referenceKey(reference);
|
|
169
|
-
const seen = firstSeen.get(key);
|
|
170
|
-
if (seen === undefined) {
|
|
171
|
-
firstSeen.set(key, index);
|
|
172
|
-
} else if (seen !== index) {
|
|
173
|
-
continue;
|
|
174
|
-
}
|
|
175
|
-
references.push(reference);
|
|
176
|
-
}
|
|
177
|
-
});
|
|
178
|
-
symbols.sort((a, b) => byPosition(a.position, b.position));
|
|
179
|
-
const testUsed = new Set(per.flatMap((one) => one.testUsedFiles ?? []));
|
|
180
|
-
|
|
181
|
-
return {
|
|
182
|
-
configurations: per.map((one) => one.configuration),
|
|
183
|
-
graphs: per.map((one) =>
|
|
184
|
-
graphOf(one.symbols, one.references, one.roots, one.testFiles, one.supportFiles, one.ambient),
|
|
185
|
-
),
|
|
186
|
-
union: graphOf(
|
|
187
|
-
symbols,
|
|
188
|
-
references,
|
|
189
|
-
per.flatMap((one) => one.roots),
|
|
190
|
-
[...new Set(per.flatMap((one) => one.testFiles))],
|
|
191
|
-
[...new Set(per.flatMap((one) => one.supportFiles ?? []))],
|
|
192
|
-
new Set(per.flatMap((one) => [...(one.ambient ?? [])])),
|
|
193
|
-
),
|
|
194
|
-
heldIn: symbols.map((symbol) => holders.get(symbol.id) ?? []),
|
|
195
|
-
testUsed: symbols.map((symbol) => testUsed.has(symbol.position.path)),
|
|
196
|
-
dependents,
|
|
197
|
-
};
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
/**
|
|
201
|
-
* Answers which declarations of the run are dead in every configuration that holds them.
|
|
202
|
-
*
|
|
203
|
-
* Liveness is a question about one configuration, because a file another configuration
|
|
204
|
-
* does not compile makes no reference there and a root it does not hold seeds nothing
|
|
205
|
-
* there, so each configuration is swept on its own graph under the run's input. A
|
|
206
|
-
* declaration is a candidate when every configuration holding it judged it one: a
|
|
207
|
-
* reference under one configuration is a reference, so what one project uses is never
|
|
208
|
-
* reported, and a configuration that does not hold a declaration says nothing about it.
|
|
209
|
-
* The candidate's relation is reference counting where every configuration found it so,
|
|
210
|
-
* and reachability otherwise; its counts are the union's, one per reference.
|
|
211
|
-
*
|
|
212
|
-
* The components are computed once, over the union and the intersected dead set, so one
|
|
213
|
-
* dead component is one entry of the run with one identifier.
|
|
214
|
-
*/
|
|
215
|
-
export function sweepMatrix(matrix: Matrix, input: SweepInput): SweepResult {
|
|
216
|
-
const per = matrix.graphs.map((graph) => sweep(graph, input));
|
|
217
|
-
const byConfiguration = new Map<string, ReadonlyMap<string, Candidate>>(
|
|
218
|
-
matrix.configurations.map((configuration, index) => [
|
|
219
|
-
configuration,
|
|
220
|
-
new Map((per[index]?.candidates ?? []).map((candidate) => [candidate.id, candidate])),
|
|
221
|
-
]),
|
|
222
|
-
);
|
|
223
|
-
|
|
224
|
-
const union = matrix.union;
|
|
225
|
-
const heldBy: (string | undefined)[] = union.symbols.map(() => undefined);
|
|
226
|
-
const testReached = reachedWithTheTests(union, [
|
|
227
|
-
...input.marked,
|
|
228
|
-
...(input.exempt ?? []).map((record) => record.id),
|
|
229
|
-
...(input.unanswered ?? []),
|
|
230
|
-
]);
|
|
231
|
-
const judged = union.symbols.map((symbol, at): readonly Candidate[] | undefined => {
|
|
232
|
-
const held = matrix.heldIn[at] ?? [];
|
|
233
|
-
const found = held.map((configuration) => byConfiguration.get(configuration)?.get(symbol.id));
|
|
234
|
-
return held.length === 0 || found.some((candidate) => candidate === undefined)
|
|
235
|
-
? undefined
|
|
236
|
-
: found.filter((candidate): candidate is Candidate => candidate !== undefined);
|
|
237
|
-
});
|
|
238
|
-
// A configuration that does not hold a test's subject's caller finds the subject dead,
|
|
239
|
-
// so a test is of dead code only where every production subject it names is dead in
|
|
240
|
-
// every configuration that holds it.
|
|
241
|
-
const subjectsDead = (at: number): boolean =>
|
|
242
|
-
(union.out[at] ?? []).every(
|
|
243
|
-
(edge) =>
|
|
244
|
-
union.test[edge.to] === true ||
|
|
245
|
-
union.support[edge.to] === true ||
|
|
246
|
-
union.ambient[edge.to] === true ||
|
|
247
|
-
union.subject[edge.to] !== true ||
|
|
248
|
-
judged[edge.to] !== undefined,
|
|
249
|
-
);
|
|
250
|
-
const admittedAt = (at: number): boolean =>
|
|
251
|
-
judged[at]?.every((candidate) => candidate.testOfDeadCode) === true && subjectsDead(at);
|
|
252
|
-
const kept = keptByTests(union, testReached, admittedAt);
|
|
253
|
-
const testUsed = testUsedReach(
|
|
254
|
-
union,
|
|
255
|
-
union.symbols.map((_symbol, at) => matrix.testUsed[at] === true && testReached[at] === true),
|
|
256
|
-
judged.map((one) => one !== undefined),
|
|
257
|
-
);
|
|
258
|
-
const candidates: MatrixCandidate[] = [];
|
|
259
|
-
union.symbols.forEach((symbol, at) => {
|
|
260
|
-
const all = judged[at];
|
|
261
|
-
if (all === undefined) {
|
|
262
|
-
return;
|
|
263
|
-
}
|
|
264
|
-
const held = matrix.heldIn[at] ?? [];
|
|
265
|
-
const admitted = admittedAt(at);
|
|
266
|
-
const testRefs = union.made[at]?.test ?? 0;
|
|
267
|
-
const heldByTests =
|
|
268
|
-
heldBy[union.parent[at] ?? OUTSIDE] ??
|
|
269
|
-
(union.support[at] === true && testRefs > 0 && !admitted ? symbol.id : undefined);
|
|
270
|
-
const unreferenced = union.test[at] === true && !admitted && testReached[at] !== true;
|
|
271
|
-
heldBy[at] = heldByTests;
|
|
272
|
-
const productionRefs = union.made[at]?.production ?? 0;
|
|
273
|
-
const counted = all.every((candidate) => candidate.relation === "reference-counting");
|
|
274
|
-
candidates.push({
|
|
275
|
-
id: symbol.id,
|
|
276
|
-
productionRefs,
|
|
277
|
-
testRefs,
|
|
278
|
-
// The run that judges a test-file declaration counts its test references.
|
|
279
|
-
relation: (unreferenced ? productionRefs + testRefs === 0 : counted)
|
|
280
|
-
? "reference-counting"
|
|
281
|
-
: "reachability",
|
|
282
|
-
testOfDeadCode: admitted,
|
|
283
|
-
configurations: held,
|
|
284
|
-
heldByTests,
|
|
285
|
-
unreferencedTest: unreferenced,
|
|
286
|
-
testUsed: testUsed[at] === true,
|
|
287
|
-
keptByTests: kept[at] === true,
|
|
288
|
-
});
|
|
289
|
-
});
|
|
290
|
-
|
|
291
|
-
const liveUnder = liveAnywhere(union.symbols, per);
|
|
292
|
-
return {
|
|
293
|
-
liveUnder,
|
|
294
|
-
candidates,
|
|
295
|
-
components: deadComponents(matrix, { liveUnder, candidates }, new Set()),
|
|
296
|
-
};
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
/** Per declaration of the union, whether one of `seeds` is it or reaches it through `dead` declarations. */
|
|
300
|
-
function testUsedReach(
|
|
301
|
-
union: Graph,
|
|
302
|
-
seeds: readonly boolean[],
|
|
303
|
-
dead: readonly boolean[],
|
|
304
|
-
): readonly boolean[] {
|
|
305
|
-
// A file is no candidate, and its top level is what reaches what it alone calls.
|
|
306
|
-
const reached = seeds.map((seed, at) => seed && dead[at] === true);
|
|
307
|
-
const queue = seeds.flatMap((one, at) => (one ? [at] : []));
|
|
308
|
-
for (let at = queue.pop(); at !== undefined; at = queue.pop()) {
|
|
309
|
-
for (const edge of union.out[at] ?? []) {
|
|
310
|
-
if (dead[edge.to] === true && reached[edge.to] !== true) {
|
|
311
|
-
reached[edge.to] = true;
|
|
312
|
-
queue.push(edge.to);
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
return reached;
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
/** Per declaration of the union, whether test code `reached` holds and `admitted` rejects references it. */
|
|
320
|
-
function keptByTests(
|
|
321
|
-
union: Graph,
|
|
322
|
-
reached: readonly boolean[],
|
|
323
|
-
admitted: (at: number) => boolean,
|
|
324
|
-
): readonly boolean[] {
|
|
325
|
-
const kept = union.symbols.map(() => false);
|
|
326
|
-
union.out.forEach((edges, from) => {
|
|
327
|
-
const testCode = union.test[from] === true || union.support[from] === true;
|
|
328
|
-
if (!testCode || reached[from] !== true || admitted(from)) {
|
|
329
|
-
return;
|
|
330
|
-
}
|
|
331
|
-
for (const edge of edges) {
|
|
332
|
-
if (edge.test) {
|
|
333
|
-
kept[edge.to] = true;
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
});
|
|
337
|
-
return kept;
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
/**
|
|
341
|
-
* The dead components of one sweep over the union, with the file declarations at `files`
|
|
342
|
-
* dead as well: a file that is deleted whole takes the declarations it holds and every
|
|
343
|
-
* dead declaration only its top level references with it.
|
|
344
|
-
*/
|
|
345
|
-
export function deadComponents(
|
|
346
|
-
matrix: Matrix,
|
|
347
|
-
result: Pick<SweepResult, "liveUnder" | "candidates">,
|
|
348
|
-
files: ReadonlySet<number>,
|
|
349
|
-
): readonly Component[] {
|
|
350
|
-
const union = matrix.union;
|
|
351
|
-
const byId = new Map(result.candidates.map((candidate) => [candidate.id, candidate]));
|
|
352
|
-
const candidateAt = (at: number): MatrixCandidate | undefined =>
|
|
353
|
-
byId.get(union.symbols[at]?.id ?? "");
|
|
354
|
-
return componentsOf(
|
|
355
|
-
union,
|
|
356
|
-
union.symbols.map((_symbol, at) => {
|
|
357
|
-
const candidate = candidateAt(at);
|
|
358
|
-
return files.has(at) || (candidate !== undefined && candidate.heldByTests === undefined);
|
|
359
|
-
}),
|
|
360
|
-
union.symbols.map((_symbol, at) => candidateAt(at)?.testOfDeadCode === true),
|
|
361
|
-
union.symbols.map((_symbol, at) => candidateAt(at)?.unreferencedTest === true),
|
|
362
|
-
positionsOf(union, matrix.dependents, result.liveUnder),
|
|
363
|
-
);
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
/**
|
|
367
|
-
* The file declarations at `paths`, below the target root, that one sweep holds live
|
|
368
|
-
* under both relations, the rule a judged declaration is live by.
|
|
369
|
-
*/
|
|
370
|
-
export function liveFilesAt(
|
|
371
|
-
matrix: Matrix,
|
|
372
|
-
result: SweepResult,
|
|
373
|
-
paths: ReadonlySet<string>,
|
|
374
|
-
): readonly InventorySymbol[] {
|
|
375
|
-
return matrix.union.symbols.filter(
|
|
376
|
-
(symbol) =>
|
|
377
|
-
symbol.kind === "file" &&
|
|
378
|
-
paths.has(symbol.position.path) &&
|
|
379
|
-
(result.liveUnder.get(symbol.id)?.length ?? 0) === RELATIONS.length,
|
|
380
|
-
);
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
/**
|
|
384
|
-
* Each declaration's dependents by its place in the union, and per place whether the
|
|
385
|
-
* declaration is live under reachability in some configuration.
|
|
386
|
-
*/
|
|
387
|
-
function positionsOf(
|
|
388
|
-
union: Graph,
|
|
389
|
-
dependents: ReadonlyMap<string, readonly string[]>,
|
|
390
|
-
liveUnder: ReadonlyMap<string, readonly Relation[]>,
|
|
391
|
-
): Positional {
|
|
392
|
-
return {
|
|
393
|
-
dependents: union.symbols.map((symbol) =>
|
|
394
|
-
(dependents.get(symbol.id) ?? []).map((id) => union.at(id)).filter((at) => at !== OUTSIDE),
|
|
395
|
-
),
|
|
396
|
-
live: union.symbols.map(
|
|
397
|
-
(symbol) => liveUnder.get(symbol.id)?.includes("reachability") === true,
|
|
398
|
-
),
|
|
399
|
-
};
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
/** The relations in the order a declaration's entry lists them. */
|
|
403
|
-
const RELATIONS: readonly Relation[] = ["reference-counting", "reachability"];
|
|
404
|
-
|
|
405
|
-
/**
|
|
406
|
-
* Per declaration, in site order, every relation that holds it live in at least one
|
|
407
|
-
* configuration.
|
|
408
|
-
*/
|
|
409
|
-
function liveAnywhere(
|
|
410
|
-
symbols: readonly InventorySymbol[],
|
|
411
|
-
per: readonly Liveness[],
|
|
412
|
-
): ReadonlyMap<string, readonly Relation[]> {
|
|
413
|
-
const live = new Map<string, readonly Relation[]>();
|
|
414
|
-
for (const symbol of symbols) {
|
|
415
|
-
const relations = RELATIONS.filter((relation) =>
|
|
416
|
-
per.some((liveness) => (liveness.liveUnder.get(symbol.id) ?? []).includes(relation)),
|
|
417
|
-
);
|
|
418
|
-
if (relations.length > 0) {
|
|
419
|
-
live.set(symbol.id, relations);
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
return live;
|
|
423
|
-
}
|