@cplieger/deadset-ts 8.0.0-dev.2 → 8.0.0-dev.20
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 +2 -7
- package/dist/src/amd.js +81 -0
- package/dist/src/analysis.js +269 -432
- 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/calls.js +279 -43
- 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 +1 -1
- 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 +1369 -0
- package/dist/src/contract/report.generated.js +866 -0
- package/dist/src/dependencies.js +164 -121
- 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/enum-group.js +3 -10
- package/dist/src/erased-stores.js +4 -6
- package/dist/src/exempt-classes.js +1 -63
- package/dist/src/exempt.js +21 -66
- 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/framework-lifecycle.js +46 -19
- 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/generated-file.js +174 -28
- 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.js +2 -2
- package/dist/src/indexed-access.js +523 -478
- package/dist/src/injection-container.js +2 -2
- package/dist/src/interface-satisfaction.js +1 -1
- 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 +47 -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/serialization-contract.js +601 -22
- 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/template-field.js +9 -19
- 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 +7 -5
- 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 +2 -9
- package/src/amd.ts +130 -0
- package/src/analysis.ts +424 -650
- package/src/augmentations.ts +93 -4
- package/src/automatic-types.ts +12 -30
- package/src/bindings.ts +460 -0
- package/src/calls.ts +338 -46
- 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 +1 -1
- 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 +1452 -0
- package/src/contract/report.generated.ts +1241 -0
- package/src/dependencies.ts +222 -127
- 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/enum-group.ts +2 -11
- package/src/erased-stores.ts +3 -7
- package/src/exempt-classes.ts +1 -75
- package/src/exempt.ts +70 -98
- 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/framework-lifecycle.ts +47 -19
- package/src/fs/document.ts +70 -0
- package/src/fs/manifest.ts +96 -0
- package/src/fs/tree.ts +110 -0
- package/src/generated-file.ts +242 -35
- 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.ts +2 -2
- package/src/indexed-access.ts +570 -527
- package/src/injection-container.ts +2 -2
- package/src/interface-satisfaction.ts +2 -2
- 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 +92 -0
- 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} +27 -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/serialization-contract.ts +769 -23
- 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/template-field.ts +15 -25
- 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 +7 -5
- 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/conventions.js +0 -937
- package/dist/src/discover.js +0 -468
- package/dist/src/entry-points.js +0 -529
- 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/setup-failure.js +0 -23
- package/dist/src/sweep.js +0 -224
- package/dist/src/test-joins.js +0 -101
- package/dist/src/version.js +0 -7
- package/dist/src/workflow-steps.js +0 -185
- package/src/base-url.ts +0 -24
- package/src/discover.ts +0 -653
- package/src/entry-points.ts +0 -687
- 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/setup-failure.ts +0 -39
- package/src/sweep.ts +0 -347
- package/src/test-joins.ts +0 -120
- package/src/version.ts +0 -7
- package/src/workflow-steps.ts +0 -216
|
@@ -1,58 +1,44 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The root set of one project: every declaration
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* that names a caller is live under reference counting as well, which the sweep
|
|
7
|
-
* decides; the published API only supposes a consumer, so a published export is live
|
|
8
|
-
* under reachability and still a candidate under reference counting.
|
|
2
|
+
* The root set of one project: every declaration kept live without a reference, and why.
|
|
3
|
+
* Every root seeds reachability and none counts as a reference; a root of a kind that
|
|
4
|
+
* names a caller is live under reference counting too, which the sweep decides, so a
|
|
5
|
+
* published export, which only supposes a consumer, stays a reference-counting candidate.
|
|
9
6
|
*/
|
|
10
7
|
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
isPropertyDeclaration,
|
|
19
|
-
isVariableDeclaration,
|
|
20
|
-
isVariableStatement,
|
|
21
|
-
type Node,
|
|
22
|
-
type SourceFile,
|
|
23
|
-
} from "@typescript/native/ast";
|
|
24
|
-
import { aliasChains } from "./alias-chain.ts";
|
|
25
|
-
import {
|
|
26
|
-
filesNamedBy,
|
|
27
|
-
outsideChain,
|
|
28
|
-
relativeSpecifiers,
|
|
29
|
-
type ParseFile,
|
|
30
|
-
} from "./configuration-files.ts";
|
|
31
|
-
import { conventionEntries, type Conventions } from "./conventions.ts";
|
|
32
|
-
import { entryPoints, type EntryRule } from "./entry-points.ts";
|
|
33
|
-
import { globExpression } from "./glob.ts";
|
|
34
|
-
import type { Host } from "./host.ts";
|
|
35
|
-
import { nodeKey, type Inventory, type InventorySymbol } from "./inventory.ts";
|
|
8
|
+
import type { SourceFile } from "@typescript/native/ast";
|
|
9
|
+
import { aliasChains } from "../alias-chain.ts";
|
|
10
|
+
import { filesNamedBy, outsideChain, type ParseFile } from "../entries/configuration-files.ts";
|
|
11
|
+
import type { EntryRule, SourceFacts } from "../entries/sources.ts";
|
|
12
|
+
import { relativeSpecifiers } from "../entries/static-module.ts";
|
|
13
|
+
import type { Host } from "../host.ts";
|
|
14
|
+
import { nodeKey, type Inventory } from "../inventory.ts";
|
|
36
15
|
import type { Manifest, ManifestEntry } from "./manifest.ts";
|
|
37
|
-
import {
|
|
38
|
-
import { byPosition } from "
|
|
39
|
-
import { UNANSWERED } from "
|
|
40
|
-
import type { ProjectView } from "
|
|
41
|
-
import
|
|
42
|
-
import {
|
|
43
|
-
import {
|
|
16
|
+
import { ancestors, dirnamePath, relativePath, resolvePath } from "../paths.ts";
|
|
17
|
+
import { byPosition } from "../position.ts";
|
|
18
|
+
import { UNANSWERED } from "../query.ts";
|
|
19
|
+
import type { ProjectView } from "../session.ts";
|
|
20
|
+
import { sourceFilesOf, type SourceFiles } from "../source-files.ts";
|
|
21
|
+
import { typeQueryAliases } from "../type-query-alias.ts";
|
|
22
|
+
import { bytewise } from "../text/compare.ts";
|
|
23
|
+
import { holdsManifest } from "../fs/manifest.ts";
|
|
24
|
+
import { globExpression } from "../text/glob.ts";
|
|
25
|
+
import { heldWords, type HeldText } from "../commands/held.ts";
|
|
26
|
+
import { spelledFiles } from "../text/named-files.ts";
|
|
27
|
+
import type { Workflows } from "../entries/workflow-steps.ts";
|
|
28
|
+
import { extensionOf, OUTPUT_EXTENSIONS } from "../extensions.ts";
|
|
29
|
+
import { publishedAPI, releaseTagged } from "./published-reach.ts";
|
|
30
|
+
import { skippedRoots, type Skip } from "../type-errors.ts";
|
|
31
|
+
import { mergedGlobalInterfaces } from "../augmentations.ts";
|
|
44
32
|
|
|
45
33
|
/** Why one declaration is a root. */
|
|
46
34
|
export type RootKind =
|
|
47
35
|
/** A file `ts.entry_files` names, and what it exports. */
|
|
48
36
|
| "entry-file"
|
|
49
|
-
/** A file an applied convention row's globs match, and what it exports. */
|
|
50
|
-
| "convention"
|
|
51
37
|
/** A file the manifest names as an importable entry point, and what it exports outside the published API. */
|
|
52
38
|
| "manifest-entry"
|
|
53
39
|
/** A file the manifest names as a command, and what it exports outside the published API. */
|
|
54
40
|
| "manifest-binary"
|
|
55
|
-
/** A file a
|
|
41
|
+
/** A file a manifest's script names or runs, as `commands/read.ts` reads it, and what it exports. */
|
|
56
42
|
| "script"
|
|
57
43
|
/**
|
|
58
44
|
* A global a declaration file declares as an alias of a module's export, and the
|
|
@@ -67,6 +53,8 @@ export type RootKind =
|
|
|
67
53
|
| "pattern"
|
|
68
54
|
/** A declaration of a function or statement a type error skipped, and what it may have selected. */
|
|
69
55
|
| "type-error"
|
|
56
|
+
/** An ambient global interface merging into one declared outside the target, and its holders. */
|
|
57
|
+
| "global-augmentation"
|
|
70
58
|
/** A file a tool or the platform enters by its own convention, and what it exports where the tool reads it. */
|
|
71
59
|
| EntryRule;
|
|
72
60
|
|
|
@@ -87,14 +75,9 @@ export interface Root {
|
|
|
87
75
|
/** One project's roots, and every configured string that named nothing in it. */
|
|
88
76
|
export interface Roots {
|
|
89
77
|
/**
|
|
90
|
-
* Every root of this project, ordered by the site of the
|
|
91
|
-
* then by kind, then by the string that named it. A declaration
|
|
92
|
-
*
|
|
93
|
-
* reason it is live.
|
|
94
|
-
*
|
|
95
|
-
* The member says which relation the set feeds: every declaration here is live
|
|
96
|
-
* under reachability. A root of a kind that names a caller is also live under
|
|
97
|
-
* reference counting, which the sweep decides.
|
|
78
|
+
* Every root of this project, live under reachability, ordered by the site of the
|
|
79
|
+
* declaration it names, then by kind, then by the string that named it. A declaration
|
|
80
|
+
* rooted for several reasons appears once per reason, so an explanation names each.
|
|
98
81
|
*/
|
|
99
82
|
readonly liveUnderReachability: readonly Root[];
|
|
100
83
|
/**
|
|
@@ -106,11 +89,24 @@ export interface Roots {
|
|
|
106
89
|
/**
|
|
107
90
|
* Every declaration of the project, where the checker left the module or export table
|
|
108
91
|
* of an entry or a published file unanswered, since which of them that file exports is
|
|
109
|
-
* unknown; otherwise each one an unanswered published type name may name.
|
|
92
|
+
* unknown; otherwise each one an unanswered published type name may name. Beside them, each
|
|
93
|
+
* file of {@link heldScripts} and every declaration its export table names.
|
|
110
94
|
*/
|
|
111
95
|
readonly unanswered: readonly string[];
|
|
112
96
|
/** Every manifest entry naming a file to import or run that reads back to no file of this project. */
|
|
113
97
|
readonly unmappedEntries: readonly ManifestEntry[];
|
|
98
|
+
/** Every package whose command strings, in what no command reader understands, name an own file no root enters with all it exports. */
|
|
99
|
+
readonly heldScripts: readonly HeldScripts[];
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** One package's command strings, and the own files they name that no root enters with all they export. */
|
|
103
|
+
export interface HeldScripts {
|
|
104
|
+
/** The package's directory, absolute. */
|
|
105
|
+
readonly dir: string;
|
|
106
|
+
/** Each file, by its path below the target root. */
|
|
107
|
+
readonly files: readonly string[];
|
|
108
|
+
/** Whether a word that may write the file a command runs writes no path text (`roots.13`). */
|
|
109
|
+
readonly unwritten: boolean;
|
|
114
110
|
}
|
|
115
111
|
|
|
116
112
|
/** What decides the roots beside the declarations themselves. */
|
|
@@ -128,10 +124,10 @@ export interface RootOptions {
|
|
|
128
124
|
readonly patterns: readonly string[];
|
|
129
125
|
/** `ts.entry_files` from the resolved configuration. */
|
|
130
126
|
readonly entryFiles: readonly string[];
|
|
131
|
-
/**
|
|
132
|
-
readonly
|
|
133
|
-
/**
|
|
134
|
-
readonly
|
|
127
|
+
/** What the project's entry sources enter, read once. */
|
|
128
|
+
readonly sources: SourceFacts;
|
|
129
|
+
/** The type errors that skipped a unit of the project's own files. */
|
|
130
|
+
readonly skips: readonly Skip[];
|
|
135
131
|
/** The parser the configuration files no program holds are read with, where they are read. */
|
|
136
132
|
readonly parse?: ParseFile | undefined;
|
|
137
133
|
/** Whether the target is a library, so a consumer outside it reaches its published API. */
|
|
@@ -141,7 +137,7 @@ export interface RootOptions {
|
|
|
141
137
|
* inside the target whose entries are published API whatever the target's kind.
|
|
142
138
|
*/
|
|
143
139
|
readonly publishedMembers?: ReadonlySet<string> | undefined;
|
|
144
|
-
/**
|
|
140
|
+
/** The files the configurations read from a file hold, so a file another configuration compiles is no outside file. */
|
|
145
141
|
readonly runFiles?: ReadonlySet<string> | undefined;
|
|
146
142
|
}
|
|
147
143
|
|
|
@@ -174,23 +170,13 @@ const READ_BACK_RULES: ReadonlySet<EntryRule> = new Set([
|
|
|
174
170
|
"html-entry",
|
|
175
171
|
]);
|
|
176
172
|
|
|
177
|
-
/** The extensions a manifest target's name drops: the ones a build writes. */
|
|
178
|
-
const OUTPUT_EXTENSION = /\.(?:d\.ts|d\.mts|d\.cts|js|mjs|cjs|jsx)$/u;
|
|
179
|
-
|
|
180
173
|
/** The extension a source file's name drops. */
|
|
181
174
|
const SOURCE_EXTENSION = /\.(?:d\.)?[cm]?[jt]sx?$/u;
|
|
182
175
|
|
|
183
176
|
/** Whether no `package.json` sits between one file and the manifest's directory, which holds it. */
|
|
184
177
|
function ofPackage(host: Host, dir: string, file: string): boolean {
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
relativePath(dir, at) === undefined ||
|
|
188
|
-
host.kindOf(joinPath(at, "package.json")) === "file"
|
|
189
|
-
) {
|
|
190
|
-
return false;
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
return true;
|
|
178
|
+
const between = ancestors(dirnamePath(file), dir);
|
|
179
|
+
return between.length > 0 && !between.slice(0, -1).some((at) => holdsManifest(host, at));
|
|
194
180
|
}
|
|
195
181
|
|
|
196
182
|
/**
|
|
@@ -211,7 +197,11 @@ function readBackByName(
|
|
|
211
197
|
return [];
|
|
212
198
|
}
|
|
213
199
|
const cut = below.indexOf("/");
|
|
214
|
-
const
|
|
200
|
+
const written = cut === -1 ? below : below.slice(cut + 1);
|
|
201
|
+
const name = written.slice(
|
|
202
|
+
0,
|
|
203
|
+
written.length - (extensionOf(written, OUTPUT_EXTENSIONS)?.length ?? 0),
|
|
204
|
+
);
|
|
215
205
|
if (name === "") {
|
|
216
206
|
return [];
|
|
217
207
|
}
|
|
@@ -316,87 +306,68 @@ export function matchRef(pattern: string, ref: string): boolean {
|
|
|
316
306
|
return matchGlob(Array.from(pattern), Array.from(ref));
|
|
317
307
|
}
|
|
318
308
|
|
|
319
|
-
/** Two strings ordered bytewise, which is the order every set of a run is read in. */
|
|
320
|
-
function compare(a: string, b: string): number {
|
|
321
|
-
if (a === b) {
|
|
322
|
-
return 0;
|
|
323
|
-
}
|
|
324
|
-
return a < b ? -1 : 1;
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
/** The members of one declaration, indexed by the container that holds them. */
|
|
328
|
-
function childrenOf(held: Inventory): ReadonlyMap<string, readonly InventorySymbol[]> {
|
|
329
|
-
const byParent = new Map<string, InventorySymbol[]>();
|
|
330
|
-
for (const symbol of held.symbols) {
|
|
331
|
-
const siblings = byParent.get(symbol.parent);
|
|
332
|
-
if (siblings === undefined) {
|
|
333
|
-
byParent.set(symbol.parent, [symbol]);
|
|
334
|
-
} else {
|
|
335
|
-
siblings.push(symbol);
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
return byParent;
|
|
339
|
-
}
|
|
340
|
-
|
|
341
309
|
/**
|
|
342
|
-
*
|
|
343
|
-
*
|
|
344
|
-
*
|
|
345
|
-
*
|
|
346
|
-
*
|
|
347
|
-
*
|
|
348
|
-
* In a library, what a published file exports is rooted by the published API alone.
|
|
349
|
-
* A file a runtime executes without reading its exports, a test file or a worker, is
|
|
350
|
-
* a root by itself.
|
|
310
|
+
* Per package, the own files the words of its held texts name, as `spelledFiles` reads them,
|
|
311
|
+
* but those a root enters with all they export: a command can use no more of such a file than
|
|
312
|
+
* the root keeps live. A manifest's are its entries' held texts, and the target root's package
|
|
313
|
+
* has the workflow steps, git hooks and makefile recipes beside its own, with the values of
|
|
314
|
+
* each file they are read from. A package is listed too where a word that may write the file
|
|
315
|
+
* a command runs writes no path text.
|
|
351
316
|
*/
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
317
|
+
function scriptHolds(
|
|
318
|
+
entries: readonly ManifestEntry[],
|
|
319
|
+
files: SourceFiles,
|
|
320
|
+
entered: readonly Entered[],
|
|
321
|
+
host: Host,
|
|
355
322
|
targetRoot: string,
|
|
356
|
-
|
|
357
|
-
):
|
|
358
|
-
const
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
323
|
+
workflows: Workflows,
|
|
324
|
+
): readonly HeldScripts[] {
|
|
325
|
+
const rooted = new Set(
|
|
326
|
+
entered.filter((one) => one.exports && one.names === undefined).map((one) => one.file.fileName),
|
|
327
|
+
);
|
|
328
|
+
const spelled = [...files.byName.values()]
|
|
329
|
+
.filter((file) => !rooted.has(file.fileName))
|
|
330
|
+
.map((file) => ({ file, paths: [file.fileName, ...files.writtenAs(file)] }));
|
|
331
|
+
const cwd = host.workingDirectory();
|
|
332
|
+
const root = resolvePath(cwd, targetRoot);
|
|
333
|
+
const commands = new Map<string, HeldText[]>([[root, [...workflows.held]]]);
|
|
334
|
+
for (const entry of entries) {
|
|
335
|
+
if (entry.held !== undefined) {
|
|
336
|
+
const dir = resolvePath(cwd, entry.dir);
|
|
337
|
+
commands.set(dir, [...(commands.get(dir) ?? []), ...entry.held]);
|
|
365
338
|
}
|
|
366
339
|
}
|
|
367
|
-
const
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
340
|
+
const held: HeldScripts[] = [];
|
|
341
|
+
for (const [dir, texts] of commands) {
|
|
342
|
+
const named = spelledFiles(heldWords(texts), dir, root, spelled);
|
|
343
|
+
if (named.files.length > 0 || named.unwritten) {
|
|
344
|
+
const paths = named.files.map(
|
|
345
|
+
(file) => relativePath(targetRoot, file.fileName) ?? file.fileName,
|
|
346
|
+
);
|
|
347
|
+
held.push({ dir, files: paths, unwritten: named.unwritten });
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
return held;
|
|
351
|
+
}
|
|
371
352
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
file: SourceFile,
|
|
381
|
-
kind: RootKind,
|
|
382
|
-
source: string,
|
|
383
|
-
exports: boolean,
|
|
384
|
-
names?: readonly string[],
|
|
385
|
-
): void => {
|
|
386
|
-
entered.push({ file, kind, source, exports, ...(names === undefined ? {} : { names }) });
|
|
387
|
-
};
|
|
353
|
+
/** One file a source enters, with the export names it roots where it roots only some. */
|
|
354
|
+
interface Entered {
|
|
355
|
+
readonly file: SourceFile;
|
|
356
|
+
readonly kind: RootKind;
|
|
357
|
+
readonly source: string;
|
|
358
|
+
readonly exports: boolean;
|
|
359
|
+
readonly names?: readonly string[];
|
|
360
|
+
}
|
|
388
361
|
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
const published: SourceFile[] = [];
|
|
399
|
-
const entries = [
|
|
362
|
+
/** One manifest entry, and whether a consumer outside the target reaches what it names. */
|
|
363
|
+
interface PackageEntry {
|
|
364
|
+
readonly entry: ManifestEntry;
|
|
365
|
+
readonly publishes: boolean;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/** The target's manifest entries, then those of its other packages. */
|
|
369
|
+
function packageEntries(options: RootOptions): readonly PackageEntry[] {
|
|
370
|
+
return [
|
|
400
371
|
...options.manifest.entries.map((entry) => ({
|
|
401
372
|
entry,
|
|
402
373
|
publishes:
|
|
@@ -411,24 +382,21 @@ export function roots<Brand>(
|
|
|
411
382
|
(options.publishedAPI || options.publishedMembers?.has(entry.dir) === true),
|
|
412
383
|
})),
|
|
413
384
|
];
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
return found;
|
|
430
|
-
};
|
|
431
|
-
const readEntryFiles = (entry: ManifestEntry): readonly SourceFile[] => {
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* The program files one manifest entry names, read once per entry: its path, else its
|
|
389
|
+
* output's source, else a rooted file of `readBackTo` by name, else the chain it starts
|
|
390
|
+
* outside every program.
|
|
391
|
+
*/
|
|
392
|
+
function entryFileReader(
|
|
393
|
+
options: RootOptions,
|
|
394
|
+
targetRoot: string,
|
|
395
|
+
files: SourceFiles,
|
|
396
|
+
readBackTo: readonly SourceFile[],
|
|
397
|
+
): (entry: ManifestEntry) => readonly SourceFile[] {
|
|
398
|
+
const read = new Map<ManifestEntry, readonly SourceFile[]>();
|
|
399
|
+
const readEntry = (entry: ManifestEntry): readonly SourceFile[] => {
|
|
432
400
|
const named = files.named(entry.path);
|
|
433
401
|
if (named.length > 0 || entry.role === "script") {
|
|
434
402
|
return named;
|
|
@@ -441,14 +409,20 @@ export function roots<Brand>(
|
|
|
441
409
|
const byName = readBackByName(options.host, entry, readBackTo);
|
|
442
410
|
return byName.length > 0 ? byName : throughOutside(options, targetRoot, files, entry);
|
|
443
411
|
};
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
}
|
|
449
|
-
|
|
412
|
+
return (entry) => {
|
|
413
|
+
const known = read.get(entry) ?? readEntry(entry);
|
|
414
|
+
read.set(entry, known);
|
|
415
|
+
return known;
|
|
416
|
+
};
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
/** The files `ts.entry_files` names, each with the pattern that names it. */
|
|
420
|
+
function patternedFiles(
|
|
421
|
+
files: SourceFiles,
|
|
422
|
+
patterns: readonly string[],
|
|
423
|
+
): readonly { file: SourceFile; pattern: string }[] {
|
|
450
424
|
const patterned: { file: SourceFile; pattern: string }[] = [];
|
|
451
|
-
for (const pattern of
|
|
425
|
+
for (const pattern of patterns) {
|
|
452
426
|
const expression = globExpression(pattern);
|
|
453
427
|
for (const [path, file] of files.byPath) {
|
|
454
428
|
if (expression.test(path)) {
|
|
@@ -456,9 +430,48 @@ export function roots<Brand>(
|
|
|
456
430
|
}
|
|
457
431
|
}
|
|
458
432
|
}
|
|
433
|
+
return patterned;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* The files every root source enters, in the order manifest entries, entry-file patterns,
|
|
438
|
+
* entry sources; the files whose exports a consumer outside the target reaches; and the
|
|
439
|
+
* entries that name no file even read back by name to another entered file.
|
|
440
|
+
*/
|
|
441
|
+
function enteredFiles(
|
|
442
|
+
options: RootOptions,
|
|
443
|
+
targetRoot: string,
|
|
444
|
+
files: SourceFiles,
|
|
445
|
+
entries: readonly PackageEntry[],
|
|
446
|
+
): {
|
|
447
|
+
entered: readonly Entered[];
|
|
448
|
+
published: readonly SourceFile[];
|
|
449
|
+
unmappedEntries: readonly ManifestEntry[];
|
|
450
|
+
} {
|
|
451
|
+
const points = options.sources.entered;
|
|
452
|
+
const scripted = entries.flatMap(({ entry }) =>
|
|
453
|
+
entry.role === "script" && entry.held === undefined ? files.named(entry.path) : [],
|
|
454
|
+
);
|
|
455
|
+
const entryFiles = entryFileReader(options, targetRoot, files, [
|
|
456
|
+
...scripted,
|
|
457
|
+
...points.filter((point) => READ_BACK_RULES.has(point.rule)).map((point) => point.file),
|
|
458
|
+
]);
|
|
459
|
+
const published = entries.flatMap(({ entry, publishes }) => (publishes ? entryFiles(entry) : []));
|
|
460
|
+
if (options.publishedAPI) {
|
|
461
|
+
// A library's bundle hands what its entry exports to every program that loads it.
|
|
462
|
+
published.push(
|
|
463
|
+
...points.filter((point) => point.rule === "bundler-entry").map((point) => point.file),
|
|
464
|
+
);
|
|
465
|
+
}
|
|
466
|
+
const publishedNames = new Set(published.map((file) => file.fileName));
|
|
467
|
+
const patterned = patternedFiles(files, options.entryFiles);
|
|
468
|
+
const entered: Entered[] = [];
|
|
459
469
|
const unmapped: ManifestEntry[] = [];
|
|
460
470
|
const mapped = patterned.map(({ file }) => file);
|
|
461
471
|
for (const { entry } of entries) {
|
|
472
|
+
if (entry.held !== undefined) {
|
|
473
|
+
continue;
|
|
474
|
+
}
|
|
462
475
|
const named = entryFiles(entry);
|
|
463
476
|
if (named.length === 0 && entry.role !== "script") {
|
|
464
477
|
unmapped.push(entry);
|
|
@@ -466,23 +479,41 @@ export function roots<Brand>(
|
|
|
466
479
|
mapped.push(...named);
|
|
467
480
|
for (const file of named) {
|
|
468
481
|
const kind = ENTRY_KINDS[entry.role];
|
|
469
|
-
|
|
482
|
+
entered.push({
|
|
483
|
+
file,
|
|
484
|
+
kind,
|
|
485
|
+
source: entry.member,
|
|
486
|
+
exports: !publishedNames.has(file.fileName),
|
|
487
|
+
});
|
|
470
488
|
}
|
|
471
489
|
}
|
|
472
|
-
const unmappedEntries = unmapped.filter(
|
|
473
|
-
(entry) => readBackByName(options.host, entry, mapped).length === 0,
|
|
474
|
-
);
|
|
475
490
|
for (const { file, pattern } of patterned) {
|
|
476
|
-
|
|
477
|
-
}
|
|
478
|
-
for (const { file, row } of options.conventions === undefined
|
|
479
|
-
? []
|
|
480
|
-
: conventionEntries(options.conventions, files)) {
|
|
481
|
-
enter(file, "convention", row, true);
|
|
491
|
+
entered.push({ file, kind: "entry-file", source: pattern, exports: true });
|
|
482
492
|
}
|
|
483
493
|
for (const point of points) {
|
|
484
|
-
|
|
494
|
+
entered.push({
|
|
495
|
+
file: point.file,
|
|
496
|
+
kind: point.rule,
|
|
497
|
+
source: point.source,
|
|
498
|
+
exports: point.exports,
|
|
499
|
+
...(point.names === undefined ? {} : { names: point.names }),
|
|
500
|
+
});
|
|
485
501
|
}
|
|
502
|
+
return {
|
|
503
|
+
entered,
|
|
504
|
+
published,
|
|
505
|
+
unmappedEntries: unmapped.filter(
|
|
506
|
+
(entry) => readBackByName(options.host, entry, mapped).length === 0,
|
|
507
|
+
),
|
|
508
|
+
};
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
/** Every declaration and container of a `typeof import(...)` global, with the type's text. */
|
|
512
|
+
function typeQueryRoots(
|
|
513
|
+
files: SourceFiles,
|
|
514
|
+
declared: Inventory["declarations"],
|
|
515
|
+
add: (id: string, kind: RootKind, source: string) => void,
|
|
516
|
+
): void {
|
|
486
517
|
for (const file of files.byPath.values()) {
|
|
487
518
|
for (const alias of typeQueryAliases(file)) {
|
|
488
519
|
const source = alias.type.getText().replace(/\s+/gu, " ");
|
|
@@ -494,6 +525,60 @@ export function roots<Brand>(
|
|
|
494
525
|
}
|
|
495
526
|
}
|
|
496
527
|
}
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
/** The roots in the order {@link Roots.liveUnderReachability} states. */
|
|
531
|
+
function orderedRoots(found: Iterable<Root>, held: Inventory): readonly Root[] {
|
|
532
|
+
const sites = new Map(held.symbols.map((symbol) => [symbol.id, symbol.position]));
|
|
533
|
+
return [...found].sort((a, b) => {
|
|
534
|
+
const left = sites.get(a.id);
|
|
535
|
+
const right = sites.get(b.id);
|
|
536
|
+
const site = left === undefined || right === undefined ? 0 : byPosition(left, right);
|
|
537
|
+
return site || bytewise(a.kind, b.kind) || bytewise(a.source, b.source);
|
|
538
|
+
});
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
/**
|
|
542
|
+
* The roots one project holds, and every configured string that named nothing in it. A
|
|
543
|
+
* file a manifest member, an entry-file pattern or a tool's configuration names is a root
|
|
544
|
+
* with each name of its export table and every re-export link to what it carries; in a
|
|
545
|
+
* library, the published API alone roots what a published file exports. A test file is a
|
|
546
|
+
* root by itself, and so is each declaration a type error's skip keeps and each global
|
|
547
|
+
* interface merging into one declared outside the project.
|
|
548
|
+
*/
|
|
549
|
+
export function rootSet<Brand>(
|
|
550
|
+
project: ProjectView<Brand>,
|
|
551
|
+
held: Inventory,
|
|
552
|
+
targetRoot: string,
|
|
553
|
+
options: RootOptions,
|
|
554
|
+
): Roots {
|
|
555
|
+
const files = sourceFilesOf(project, targetRoot);
|
|
556
|
+
const fileIds = new Map<string, string>();
|
|
557
|
+
for (const file of files.byName.values()) {
|
|
558
|
+
const id = held.declarations.get(nodeKey(file, file));
|
|
559
|
+
if (id !== undefined) {
|
|
560
|
+
fileIds.set(file.fileName, id);
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
const found = new Map<string, Root>();
|
|
564
|
+
const add = (id: string, kind: RootKind, source: string): void => {
|
|
565
|
+
found.set([id, kind, source].join("\u0000"), { id, kind, source });
|
|
566
|
+
};
|
|
567
|
+
|
|
568
|
+
const entries = packageEntries(options);
|
|
569
|
+
const { entered, published, unmappedEntries } = enteredFiles(options, targetRoot, files, entries);
|
|
570
|
+
const heldScripts = scriptHolds(
|
|
571
|
+
entries.map(({ entry }) => entry),
|
|
572
|
+
files,
|
|
573
|
+
entered,
|
|
574
|
+
options.host,
|
|
575
|
+
targetRoot,
|
|
576
|
+
options.sources.workflows,
|
|
577
|
+
);
|
|
578
|
+
const heldFiles = [...new Set(heldScripts.flatMap((one) => one.files))].flatMap(
|
|
579
|
+
(path) => files.byPath.get(path) ?? [],
|
|
580
|
+
);
|
|
581
|
+
typeQueryRoots(files, held.declarations, add);
|
|
497
582
|
|
|
498
583
|
const {
|
|
499
584
|
tables: exportsOf,
|
|
@@ -502,6 +587,7 @@ export function roots<Brand>(
|
|
|
502
587
|
} = exportTables(project, held, [
|
|
503
588
|
...entered.filter((entry) => entry.exports).map((entry) => entry.file),
|
|
504
589
|
...published,
|
|
590
|
+
...heldFiles,
|
|
505
591
|
]);
|
|
506
592
|
for (const entry of entered) {
|
|
507
593
|
const id = fileIds.get(entry.file.fileName);
|
|
@@ -534,20 +620,27 @@ export function roots<Brand>(
|
|
|
534
620
|
}
|
|
535
621
|
|
|
536
622
|
const unmatched = configured(held, options.patterns, add);
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
return site || compare(a.kind, b.kind) || compare(a.source, b.source);
|
|
544
|
-
});
|
|
623
|
+
for (const id of skippedRoots(project, held, options.skips)) {
|
|
624
|
+
add(id, "type-error", "");
|
|
625
|
+
}
|
|
626
|
+
for (const id of mergedGlobalInterfaces(project, held, files).kept) {
|
|
627
|
+
add(id, "global-augmentation", "");
|
|
628
|
+
}
|
|
545
629
|
|
|
546
630
|
return {
|
|
547
|
-
liveUnderReachability:
|
|
631
|
+
liveUnderReachability: orderedRoots(found.values(), held),
|
|
548
632
|
unmatched,
|
|
549
|
-
unanswered:
|
|
633
|
+
unanswered: [
|
|
634
|
+
...(answered ? api.guessed : held.symbols.map((symbol) => symbol.id)),
|
|
635
|
+
// A command runs a held file and may read any export of it, so the file, which reaches its
|
|
636
|
+
// top level, and its exports are held; a declaration neither reaches is still dead.
|
|
637
|
+
...heldFiles.flatMap((file) => {
|
|
638
|
+
const id = fileIds.get(file.fileName);
|
|
639
|
+
return [...(id === undefined ? [] : [id]), ...(exportsOf.get(file.fileName) ?? [])];
|
|
640
|
+
}),
|
|
641
|
+
],
|
|
550
642
|
unmappedEntries,
|
|
643
|
+
heldScripts,
|
|
551
644
|
};
|
|
552
645
|
}
|
|
553
646
|
|
|
@@ -610,279 +703,6 @@ function exportTables<Brand>(
|
|
|
610
703
|
return { tables, named, answered };
|
|
611
704
|
}
|
|
612
705
|
|
|
613
|
-
/** A release tag of a documentation comment: `@` and its name, between white space or the ends. */
|
|
614
|
-
const RELEASE_TAG = /(?:^|\s)@(?:public|beta|alpha)(?=\s|$)/u;
|
|
615
|
-
|
|
616
|
-
/**
|
|
617
|
-
* Whether the documentation comment of the statement that starts at `start`, the last
|
|
618
|
-
* `/** *\/` comment before it with only white space between the two, holds a release tag.
|
|
619
|
-
*/
|
|
620
|
-
function releaseTagIn(text: string, from: number, start: number): boolean {
|
|
621
|
-
const leading = text.slice(from, start);
|
|
622
|
-
const open = leading.lastIndexOf("/**");
|
|
623
|
-
const close = open < 0 ? -1 : leading.indexOf("*/", open + 3);
|
|
624
|
-
if (close < 0 || leading.slice(close + 2).trim() !== "") {
|
|
625
|
-
return false;
|
|
626
|
-
}
|
|
627
|
-
return RELEASE_TAG.test(leading.slice(open + 3, close));
|
|
628
|
-
}
|
|
629
|
-
|
|
630
|
-
/** The exported top-level declarations of the program's files a release tag marks. */
|
|
631
|
-
function releaseTagged(
|
|
632
|
-
held: Inventory,
|
|
633
|
-
files: { readonly byPath: ReadonlyMap<string, SourceFile> },
|
|
634
|
-
): readonly string[] {
|
|
635
|
-
const exported = new Set(held.symbols.filter((symbol) => symbol.exported).map((one) => one.id));
|
|
636
|
-
const found: string[] = [];
|
|
637
|
-
for (const file of files.byPath.values()) {
|
|
638
|
-
for (const statement of file.statements) {
|
|
639
|
-
if (!releaseTagIn(file.text, statement.pos, statement.getStart())) {
|
|
640
|
-
continue;
|
|
641
|
-
}
|
|
642
|
-
const nodes: readonly Node[] = isVariableStatement(statement)
|
|
643
|
-
? statement.declarationList.declarations
|
|
644
|
-
: [statement];
|
|
645
|
-
for (const node of nodes) {
|
|
646
|
-
const id = held.declarations.get(nodeKey(file, node));
|
|
647
|
-
if (id !== undefined && exported.has(id)) {
|
|
648
|
-
found.push(id);
|
|
649
|
-
}
|
|
650
|
-
}
|
|
651
|
-
}
|
|
652
|
-
}
|
|
653
|
-
return found;
|
|
654
|
-
}
|
|
655
|
-
|
|
656
|
-
/** The kinds of container whose export table, not its members' visibility, says what it publishes. */
|
|
657
|
-
const EXPORTING_CONTAINERS: ReadonlySet<string> = new Set(["file", "namespace"]);
|
|
658
|
-
|
|
659
|
-
/**
|
|
660
|
-
* Every declaration a consumer of the library can name: what the published files export,
|
|
661
|
-
* and below each the members a consumer writes, a namespace's exported ones and any other
|
|
662
|
-
* declaration's public and protected ones. A declaration a published one's type names is
|
|
663
|
-
* published too, and so is an exported declaration a release tag marks. A type name the
|
|
664
|
-
* checker leaves unanswered publishes every declaration spelled as it is, as `guessed`. A
|
|
665
|
-
* published file is not itself published.
|
|
666
|
-
*/
|
|
667
|
-
function publishedAPI<Brand>(
|
|
668
|
-
project: ProjectView<Brand>,
|
|
669
|
-
published: readonly SourceFile[],
|
|
670
|
-
exportsOf: ReadonlyMap<string, readonly string[]>,
|
|
671
|
-
held: Inventory,
|
|
672
|
-
byPath: ReadonlyMap<string, SourceFile>,
|
|
673
|
-
tagged: readonly string[],
|
|
674
|
-
): { readonly ids: readonly string[]; readonly guessed: readonly string[] } {
|
|
675
|
-
const byId = new Map(held.symbols.map((symbol) => [symbol.id, symbol]));
|
|
676
|
-
const children = childrenOf(held);
|
|
677
|
-
const nodes = declarationNodes(held, byPath);
|
|
678
|
-
const chains = aliasChains(project, held);
|
|
679
|
-
const reached = new Set<string>();
|
|
680
|
-
const entered = new Set<string>();
|
|
681
|
-
const guessed = new Set<string>();
|
|
682
|
-
const pending: string[] = [];
|
|
683
|
-
const reach = (id: string): void => {
|
|
684
|
-
const file = byId.get(id)?.kind === "file";
|
|
685
|
-
if (!(file ? entered : reached).has(id)) {
|
|
686
|
-
(file ? entered : reached).add(id);
|
|
687
|
-
pending.push(id);
|
|
688
|
-
}
|
|
689
|
-
};
|
|
690
|
-
for (const id of tagged) {
|
|
691
|
-
reach(id);
|
|
692
|
-
}
|
|
693
|
-
for (const file of published) {
|
|
694
|
-
for (const id of exportsOf.get(file.fileName) ?? []) {
|
|
695
|
-
reach(id);
|
|
696
|
-
}
|
|
697
|
-
}
|
|
698
|
-
while (pending.length > 0) {
|
|
699
|
-
const round: string[] = [];
|
|
700
|
-
for (let next = pending.shift(); next !== undefined; next = pending.shift()) {
|
|
701
|
-
round.push(next);
|
|
702
|
-
const exporting = EXPORTING_CONTAINERS.has(byId.get(next)?.kind ?? "");
|
|
703
|
-
for (const member of children.get(next) ?? []) {
|
|
704
|
-
const reachable = exporting
|
|
705
|
-
? member.exported
|
|
706
|
-
: member.visibility !== "private" && member.visibility !== "private-name";
|
|
707
|
-
if (member.kind !== "type-parameter" && reachable) {
|
|
708
|
-
reach(member.id);
|
|
709
|
-
}
|
|
710
|
-
}
|
|
711
|
-
}
|
|
712
|
-
const named = round.flatMap((id) => {
|
|
713
|
-
const symbol = byId.get(id);
|
|
714
|
-
return symbol === undefined || symbol.kind === "file" ? [] : nodes.typeNamesOf(symbol);
|
|
715
|
-
});
|
|
716
|
-
for (const symbol of inferredTypeSymbols(
|
|
717
|
-
project,
|
|
718
|
-
round.flatMap((id) => {
|
|
719
|
-
const symbol = byId.get(id);
|
|
720
|
-
return symbol === undefined ? [] : nodes.nodesOf(symbol);
|
|
721
|
-
}),
|
|
722
|
-
)) {
|
|
723
|
-
for (const target of chains.chainOf(symbol)) {
|
|
724
|
-
reach(target.id);
|
|
725
|
-
}
|
|
726
|
-
}
|
|
727
|
-
project.symbolsAt(named.map((node) => project.handle(node))).forEach((symbol, index) => {
|
|
728
|
-
if (symbol === UNANSWERED) {
|
|
729
|
-
for (const id of held.byName.get(named[index]?.getText() ?? "") ?? []) {
|
|
730
|
-
guessed.add(id);
|
|
731
|
-
reach(id);
|
|
732
|
-
}
|
|
733
|
-
} else if (symbol !== undefined) {
|
|
734
|
-
for (const target of chains.chainOf(symbol)) {
|
|
735
|
-
reach(target.id);
|
|
736
|
-
}
|
|
737
|
-
}
|
|
738
|
-
});
|
|
739
|
-
}
|
|
740
|
-
return { ids: [...reached], guessed: [...guessed] };
|
|
741
|
-
}
|
|
742
|
-
|
|
743
|
-
/** The type names declarations of the inventory write, each file walked once, when first asked. */
|
|
744
|
-
function declarationNodes(
|
|
745
|
-
held: Inventory,
|
|
746
|
-
byPath: ReadonlyMap<string, SourceFile>,
|
|
747
|
-
): {
|
|
748
|
-
typeNamesOf(symbol: InventorySymbol): readonly Node[];
|
|
749
|
-
nodesOf(symbol: InventorySymbol): readonly Node[];
|
|
750
|
-
} {
|
|
751
|
-
const walked = new Map<string, { byId: Map<string, Node[]>; nodes: Set<Node> }>();
|
|
752
|
-
const nodesIn = (path: string): { byId: Map<string, Node[]>; nodes: Set<Node> } => {
|
|
753
|
-
const known = walked.get(path);
|
|
754
|
-
if (known !== undefined) {
|
|
755
|
-
return known;
|
|
756
|
-
}
|
|
757
|
-
const found = { byId: new Map<string, Node[]>(), nodes: new Set<Node>() };
|
|
758
|
-
const file = byPath.get(path);
|
|
759
|
-
if (file !== undefined) {
|
|
760
|
-
const visit = (node: Node): void => {
|
|
761
|
-
const id = held.declarations.get(nodeKey(file, node));
|
|
762
|
-
if (id !== undefined) {
|
|
763
|
-
found.nodes.add(node);
|
|
764
|
-
found.byId.set(id, [...(found.byId.get(id) ?? []), node]);
|
|
765
|
-
}
|
|
766
|
-
node.forEachChild(visit);
|
|
767
|
-
};
|
|
768
|
-
visit(file);
|
|
769
|
-
}
|
|
770
|
-
walked.set(path, found);
|
|
771
|
-
return found;
|
|
772
|
-
};
|
|
773
|
-
return {
|
|
774
|
-
typeNamesOf: (symbol) => {
|
|
775
|
-
const { byId, nodes } = nodesIn(symbol.position.path);
|
|
776
|
-
return (byId.get(symbol.id) ?? []).flatMap((declaration) => typeNamesOf(declaration, nodes));
|
|
777
|
-
},
|
|
778
|
-
nodesOf: (symbol) => nodesIn(symbol.position.path).byId.get(symbol.id) ?? [],
|
|
779
|
-
};
|
|
780
|
-
}
|
|
781
|
-
|
|
782
|
-
/** How deep the type arguments and constituents of an inferred type are followed. */
|
|
783
|
-
const INFERRED_DEPTH = 4;
|
|
784
|
-
|
|
785
|
-
/**
|
|
786
|
-
* The declarations of the types the compiler infers where a declaration writes none: the
|
|
787
|
-
* type of a variable or a property with no annotation, and the result of a function or a
|
|
788
|
-
* method with no result annotation, each with the types its type arguments and its union
|
|
789
|
-
* or intersection constituents name, to a fixed depth. A question the checker leaves
|
|
790
|
-
* unanswered names nothing.
|
|
791
|
-
*/
|
|
792
|
-
function inferredTypeSymbols<Brand>(
|
|
793
|
-
project: ProjectView<Brand>,
|
|
794
|
-
declarations: readonly Node[],
|
|
795
|
-
): readonly TSSymbol[] {
|
|
796
|
-
const { queries } = project;
|
|
797
|
-
const valued = declarations.flatMap((node) =>
|
|
798
|
-
(isVariableDeclaration(node) || isPropertyDeclaration(node)) &&
|
|
799
|
-
node.type === undefined &&
|
|
800
|
-
!isFunctionLikeDeclaration(node.initializer ?? node)
|
|
801
|
-
? [node.name]
|
|
802
|
-
: [],
|
|
803
|
-
);
|
|
804
|
-
const types: Type[] = [];
|
|
805
|
-
queries.typesAt(valued).forEach((type) => {
|
|
806
|
-
if (type !== UNANSWERED && type !== undefined) {
|
|
807
|
-
types.push(type);
|
|
808
|
-
}
|
|
809
|
-
});
|
|
810
|
-
for (const node of declarations) {
|
|
811
|
-
const signature = isFunctionLikeDeclaration(node)
|
|
812
|
-
? node
|
|
813
|
-
: isVariableDeclaration(node) &&
|
|
814
|
-
node.type === undefined &&
|
|
815
|
-
node.initializer !== undefined &&
|
|
816
|
-
isFunctionLikeDeclaration(node.initializer)
|
|
817
|
-
? node.initializer
|
|
818
|
-
: undefined;
|
|
819
|
-
if (signature === undefined || signature.type !== undefined || signature.body === undefined) {
|
|
820
|
-
continue;
|
|
821
|
-
}
|
|
822
|
-
const typed = queries.signatureOf(signature);
|
|
823
|
-
const result =
|
|
824
|
-
typed === UNANSWERED || typed === undefined ? undefined : queries.returnTypeOf(typed);
|
|
825
|
-
if (result !== UNANSWERED && result !== undefined) {
|
|
826
|
-
types.push(result);
|
|
827
|
-
}
|
|
828
|
-
}
|
|
829
|
-
const found = new Map<number, TSSymbol>();
|
|
830
|
-
const seen = new Set<Type>();
|
|
831
|
-
const visit = (type: Type, depth: number): void => {
|
|
832
|
-
if (depth > INFERRED_DEPTH || seen.has(type)) {
|
|
833
|
-
return;
|
|
834
|
-
}
|
|
835
|
-
seen.add(type);
|
|
836
|
-
const symbol = queries.symbolOfType(type);
|
|
837
|
-
if (symbol !== UNANSWERED && symbol !== undefined) {
|
|
838
|
-
found.set(symbol.id, symbol);
|
|
839
|
-
}
|
|
840
|
-
const parts = queries.constituents(type);
|
|
841
|
-
const args = queries.typeArguments(type);
|
|
842
|
-
for (const next of [
|
|
843
|
-
...(parts === UNANSWERED || (parts.length === 1 && parts[0] === type) ? [] : parts),
|
|
844
|
-
...(args === UNANSWERED ? [] : args),
|
|
845
|
-
]) {
|
|
846
|
-
visit(next, depth + 1);
|
|
847
|
-
}
|
|
848
|
-
};
|
|
849
|
-
types.forEach((type) => {
|
|
850
|
-
visit(type, 0);
|
|
851
|
-
});
|
|
852
|
-
return [...found.values()];
|
|
853
|
-
}
|
|
854
|
-
|
|
855
|
-
/**
|
|
856
|
-
* The names of types one declaration's own syntax writes: in a type reference, a
|
|
857
|
-
* heritage clause or a type query. A function body is not read, and neither is a
|
|
858
|
-
* declaration nested in this one, which `nested` holds and which is read on its own.
|
|
859
|
-
*/
|
|
860
|
-
function typeNamesOf(declaration: Node, nested: ReadonlySet<Node>): readonly Node[] {
|
|
861
|
-
const found: Node[] = [];
|
|
862
|
-
const visit = (node: Node): void => {
|
|
863
|
-
if (node !== declaration && nested.has(node)) {
|
|
864
|
-
return;
|
|
865
|
-
}
|
|
866
|
-
if (isTypeReferenceNode(node)) {
|
|
867
|
-
found.push(isQualifiedName(node.typeName) ? node.typeName.right : node.typeName);
|
|
868
|
-
} else if (isExpressionWithTypeArguments(node)) {
|
|
869
|
-
found.push(
|
|
870
|
-
isPropertyAccessExpression(node.expression) ? node.expression.name : node.expression,
|
|
871
|
-
);
|
|
872
|
-
} else if (isTypeQueryNode(node)) {
|
|
873
|
-
found.push(isQualifiedName(node.exprName) ? node.exprName.right : node.exprName);
|
|
874
|
-
}
|
|
875
|
-
const body = isFunctionLikeDeclaration(node) ? node.body : undefined;
|
|
876
|
-
node.forEachChild((child) => {
|
|
877
|
-
if (child !== body) {
|
|
878
|
-
visit(child);
|
|
879
|
-
}
|
|
880
|
-
});
|
|
881
|
-
};
|
|
882
|
-
visit(declaration);
|
|
883
|
-
return found;
|
|
884
|
-
}
|
|
885
|
-
|
|
886
706
|
/**
|
|
887
707
|
* Keeps every declaration the configuration names and returns every string that
|
|
888
708
|
* named none, in configuration order. A string the configuration lists twice is one
|
|
@@ -911,13 +731,10 @@ function configured(
|
|
|
911
731
|
}
|
|
912
732
|
|
|
913
733
|
/**
|
|
914
|
-
* Every configured string that named no declaration in
|
|
915
|
-
* configuration order and each once.
|
|
916
|
-
*
|
|
917
|
-
*
|
|
918
|
-
* declaration, so there is one per run: a string that names a declaration of one
|
|
919
|
-
* project has named something, and the projects it named nothing in are not a
|
|
920
|
-
* finding. A run with no project names nothing with any of them.
|
|
734
|
+
* Every configured string that named no declaration in any project of the run, in
|
|
735
|
+
* configuration order and each once. The finding is about the configuration, so a string
|
|
736
|
+
* naming a declaration of one project has named something, and a run with no project
|
|
737
|
+
* names nothing with any of them.
|
|
921
738
|
*/
|
|
922
739
|
export function unmatchedEverywhere(
|
|
923
740
|
patterns: readonly string[],
|