@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
|
@@ -1,611 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The serialization-contract class: the data members and `toJSON` of every type a value's
|
|
3
|
-
* static type reaches, where the value reaches `JSON.stringify` or a call `ts.serializers`
|
|
4
|
-
* names, and `toString` too where it reaches an erased parameter of a function outside the
|
|
5
|
-
* analysis, or an erased property of a type the program does not declare. A function of
|
|
6
|
-
* the project handing such a parameter to a destination is one, to a fixpoint, and a
|
|
7
|
-
* function invoked through `call`, `apply` or `bind` is the callee.
|
|
8
|
-
*/
|
|
9
|
-
import { isArrayLiteralExpression, isArrowFunction, isAsExpression, isCallExpression, isClassDeclaration, isClassExpression, isClassStaticBlockDeclaration, isFunctionDeclaration, isFunctionExpression, isGetAccessorDeclaration, isIdentifier, isInterfaceDeclaration, isMethodDeclaration, isNoSubstitutionTemplateLiteral, isNumericLiteral, isObjectLiteralExpression, isParenthesizedExpression, isPropertyAccessExpression, isPropertyDeclaration, isSatisfiesExpression, isSetAccessorDeclaration, isSpreadElement, isStringLiteral, isTypeLiteralNode, isVariableDeclaration, ModifierFlags, NodeFlags, SyntaxKind, } from "@typescript/native/ast";
|
|
10
|
-
import { SignatureKind, SymbolFlags, TypeFlags, } from "@typescript/native/sync";
|
|
11
|
-
import { aliasChains } from "./alias-chain.js";
|
|
12
|
-
import { calleeName, resolvedTargets, valuesPassed } from "./calls.js";
|
|
13
|
-
import { classMembers, memberComponent, typesAt } from "./class-members.js";
|
|
14
|
-
import { names, namesADeclaration, resolveEntries, spelledEntry, } from "./configured-declarations.js";
|
|
15
|
-
import { nodeKey } from "./inventory.js";
|
|
16
|
-
import { renderPosition } from "./position.js";
|
|
17
|
-
import { must } from "./query.js";
|
|
18
|
-
import { erasedStores } from "./erased-stores.js";
|
|
19
|
-
import { checkedTypes, CONVERSION_MEMBERS, valueReach } from "./value-reach.js";
|
|
20
|
-
/** The serializer every run reads, whatever the configuration names. */
|
|
21
|
-
const JSON_STRINGIFY = { shape: "global", global: "JSON.stringify" };
|
|
22
|
-
/** The methods a serializer and a formatter resolve by name on a value that left the analysis. */
|
|
23
|
-
const CONVERSIONS = new Set(["toJSON", "toString"]);
|
|
24
|
-
/** The method a serializer calls on a value that carries one, wherever the value goes. */
|
|
25
|
-
const SERIALIZED_CONVERSION = "toJSON";
|
|
26
|
-
/** The parameter types that keep nothing of the value they are given. */
|
|
27
|
-
const ERASED = TypeFlags.Any | TypeFlags.Unknown;
|
|
28
|
-
/** How deep a callee's result is searched for a type parameter: `Promise<Box<T>>` is two levels. */
|
|
29
|
-
const MENTION_DEPTH = 3;
|
|
30
|
-
/** The wider of two reaches, where either may be absent. */
|
|
31
|
-
function wider(a, b) {
|
|
32
|
-
return a === "conversions" || b === "conversions" ? "conversions" : (a ?? b);
|
|
33
|
-
}
|
|
34
|
-
/** Whether one node declares a static member, whose `this` is the class itself. */
|
|
35
|
-
function isStatic(node) {
|
|
36
|
-
const flags = node.modifierFlags ?? 0;
|
|
37
|
-
return (flags & ModifierFlags.Static) !== 0;
|
|
38
|
-
}
|
|
39
|
-
/** Whether one node opens a body whose `this` is not an instance of the enclosing class. */
|
|
40
|
-
function resetsThis(node) {
|
|
41
|
-
return (isFunctionDeclaration(node) ||
|
|
42
|
-
isFunctionExpression(node) ||
|
|
43
|
-
isClassStaticBlockDeclaration(node) ||
|
|
44
|
-
isStatic(node) ||
|
|
45
|
-
((isMethodDeclaration(node) ||
|
|
46
|
-
isGetAccessorDeclaration(node) ||
|
|
47
|
-
isSetAccessorDeclaration(node)) &&
|
|
48
|
-
isObjectLiteralExpression(node.parent)));
|
|
49
|
-
}
|
|
50
|
-
/** The parameters and declaring node of one function-like declaration of the project. */
|
|
51
|
-
function functionOf(node) {
|
|
52
|
-
if (isFunctionDeclaration(node) ||
|
|
53
|
-
(isMethodDeclaration(node) && !isObjectLiteralExpression(node.parent))) {
|
|
54
|
-
return { declared: node, parameters: node.parameters };
|
|
55
|
-
}
|
|
56
|
-
if (isVariableDeclaration(node) &&
|
|
57
|
-
node.initializer !== undefined &&
|
|
58
|
-
(isArrowFunction(node.initializer) || isFunctionExpression(node.initializer))) {
|
|
59
|
-
return { declared: node, parameters: node.initializer.parameters };
|
|
60
|
-
}
|
|
61
|
-
return undefined;
|
|
62
|
-
}
|
|
63
|
-
/** Whether one parameter is a `this` parameter, which types `this` and binds no argument. */
|
|
64
|
-
function isThisParameter(parameter) {
|
|
65
|
-
return isIdentifier(parameter.name) && parameter.name.text === "this";
|
|
66
|
-
}
|
|
67
|
-
/** Whether an argument is written in a form that holds no class instance, which saves a type. */
|
|
68
|
-
function holdsNoInstance(argument) {
|
|
69
|
-
return (isArrowFunction(argument) ||
|
|
70
|
-
isFunctionExpression(argument) ||
|
|
71
|
-
isStringLiteral(argument) ||
|
|
72
|
-
isNumericLiteral(argument) ||
|
|
73
|
-
isNoSubstitutionTemplateLiteral(argument) ||
|
|
74
|
-
argument.kind === SyntaxKind.TemplateExpression);
|
|
75
|
-
}
|
|
76
|
-
/** The expression an argument evaluates, through parentheses and a spread. */
|
|
77
|
-
function evaluated(argument) {
|
|
78
|
-
const value = isSpreadElement(argument) ? argument.expression : argument;
|
|
79
|
-
return isParenthesizedExpression(value) ? evaluated(value.expression) : value;
|
|
80
|
-
}
|
|
81
|
-
/** The methods of `Function.prototype` that invoke a function with arguments of their own. */
|
|
82
|
-
const FUNCTION_METHODS = new Set(["call", "apply", "bind"]);
|
|
83
|
-
/** The interfaces of the standard library that declare those methods for a function value. */
|
|
84
|
-
const FUNCTION_INTERFACES = new Set([
|
|
85
|
-
"Function",
|
|
86
|
-
"CallableFunction",
|
|
87
|
-
"NewableFunction",
|
|
88
|
-
]);
|
|
89
|
-
function unparenthesized(expression) {
|
|
90
|
-
return isParenthesizedExpression(expression)
|
|
91
|
-
? unparenthesized(expression.expression)
|
|
92
|
-
: expression;
|
|
93
|
-
}
|
|
94
|
-
/**
|
|
95
|
-
* The invocation a call writes through a method of `Function.prototype`, read from
|
|
96
|
-
* the syntax alone: `f.call(self, a)`, `f.apply(self, [a])`, `f.bind(self, a)`, which
|
|
97
|
-
* binds `a`, and `f.bind(self, a)(b)`, which passes `b` after it. An `apply` argument
|
|
98
|
-
* that is no array literal is the value of the first parameter, whose elements it
|
|
99
|
-
* carries. Whether the method is the prototype's is resolution's to say.
|
|
100
|
-
*/
|
|
101
|
-
function throughMethod(call) {
|
|
102
|
-
const expression = unparenthesized(call.expression);
|
|
103
|
-
if (isPropertyAccessExpression(expression) && FUNCTION_METHODS.has(expression.name.text)) {
|
|
104
|
-
const [, ...rest] = call.arguments;
|
|
105
|
-
let passed = rest;
|
|
106
|
-
if (expression.name.text === "apply") {
|
|
107
|
-
const list = rest[0] === undefined ? undefined : unparenthesized(rest[0]);
|
|
108
|
-
passed = list === undefined ? [] : isArrayLiteralExpression(list) ? list.elements : [list];
|
|
109
|
-
}
|
|
110
|
-
return {
|
|
111
|
-
method: expression.name,
|
|
112
|
-
invocation: { callee: expression.expression, arguments: passed, indirect: true },
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
if (isCallExpression(expression)) {
|
|
116
|
-
const bound = unparenthesized(expression.expression);
|
|
117
|
-
if (isPropertyAccessExpression(bound) && bound.name.text === "bind") {
|
|
118
|
-
return {
|
|
119
|
-
method: bound.name,
|
|
120
|
-
invocation: {
|
|
121
|
-
callee: bound.expression,
|
|
122
|
-
arguments: [...expression.arguments.slice(1), ...call.arguments],
|
|
123
|
-
indirect: true,
|
|
124
|
-
},
|
|
125
|
-
};
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
return undefined;
|
|
129
|
-
}
|
|
130
|
-
/**
|
|
131
|
-
* Every call of the project's own files with the class `this` stands for there, and
|
|
132
|
-
* every identifier-named parameter of every function, method and function-valued
|
|
133
|
-
* variable the project declares, at the position of the argument it binds.
|
|
134
|
-
*/
|
|
135
|
-
function walkProject(project, held) {
|
|
136
|
-
const sites = [];
|
|
137
|
-
const parameters = [];
|
|
138
|
-
for (const file of project.ownSourceFiles()) {
|
|
139
|
-
const visit = (node, self) => {
|
|
140
|
-
let inner = self;
|
|
141
|
-
if (isClassDeclaration(node) || isClassExpression(node)) {
|
|
142
|
-
inner = held.declarations.get(nodeKey(file, node));
|
|
143
|
-
}
|
|
144
|
-
else if (resetsThis(node)) {
|
|
145
|
-
inner = undefined;
|
|
146
|
-
}
|
|
147
|
-
if (node.kind === SyntaxKind.CallExpression) {
|
|
148
|
-
sites.push({ call: node, self });
|
|
149
|
-
}
|
|
150
|
-
const fn = functionOf(node);
|
|
151
|
-
const id = fn === undefined ? undefined : held.declarations.get(nodeKey(file, fn.declared));
|
|
152
|
-
if (fn !== undefined && id !== undefined) {
|
|
153
|
-
fn.parameters
|
|
154
|
-
.filter((parameter) => !isThisParameter(parameter))
|
|
155
|
-
.forEach((parameter, index) => {
|
|
156
|
-
if (isIdentifier(parameter.name)) {
|
|
157
|
-
parameters.push({
|
|
158
|
-
fn: id,
|
|
159
|
-
index,
|
|
160
|
-
rest: parameter.dotDotDotToken !== undefined,
|
|
161
|
-
name: parameter.name,
|
|
162
|
-
});
|
|
163
|
-
}
|
|
164
|
-
});
|
|
165
|
-
}
|
|
166
|
-
node.forEachChild((child) => {
|
|
167
|
-
visit(child, inner);
|
|
168
|
-
});
|
|
169
|
-
};
|
|
170
|
-
file.forEachChild((child) => {
|
|
171
|
-
visit(child, undefined);
|
|
172
|
-
});
|
|
173
|
-
}
|
|
174
|
-
return { sites, parameters };
|
|
175
|
-
}
|
|
176
|
-
/**
|
|
177
|
-
* The parameters that keep nothing of the value they are given: one typed `unknown` or
|
|
178
|
-
* `any`, and a rest parameter whose elements are, each by its symbol.
|
|
179
|
-
*/
|
|
180
|
-
function erasedParameters(project, parameters) {
|
|
181
|
-
const types = typesAt(project, parameters.map((parameter) => parameter.name));
|
|
182
|
-
const erased = parameters.filter((parameter, index) => {
|
|
183
|
-
const type = types[index];
|
|
184
|
-
if (type === undefined) {
|
|
185
|
-
return false;
|
|
186
|
-
}
|
|
187
|
-
if (!parameter.rest) {
|
|
188
|
-
return (type.flags & ERASED) !== 0;
|
|
189
|
-
}
|
|
190
|
-
const [element] = must(project.queries.typeArguments(type));
|
|
191
|
-
return element !== undefined && (element.flags & ERASED) !== 0;
|
|
192
|
-
});
|
|
193
|
-
const bySymbol = new Map();
|
|
194
|
-
project
|
|
195
|
-
.symbolsAt(erased.map((parameter) => project.handle(parameter.name)))
|
|
196
|
-
.map(must)
|
|
197
|
-
.forEach((symbol, index) => {
|
|
198
|
-
const parameter = erased[index];
|
|
199
|
-
if (symbol !== undefined && parameter !== undefined) {
|
|
200
|
-
bySymbol.set(symbol.id, parameter);
|
|
201
|
-
}
|
|
202
|
-
});
|
|
203
|
-
return bySymbol;
|
|
204
|
-
}
|
|
205
|
-
/** Each place a call's argument passes one of the erased parameters it can see. */
|
|
206
|
-
function handedOn(project, sites, erased, invocationOf) {
|
|
207
|
-
const spellings = new Set([...erased.values()].map((parameter) => parameter.name.getText()));
|
|
208
|
-
const candidates = sites.flatMap((site) => invocationOf(site.call).arguments.flatMap((argument, index) => valuesPassed(argument)
|
|
209
|
-
.filter((value) => spellings.has(value.name.getText()))
|
|
210
|
-
.map((value) => ({ site, argument: index, value }))));
|
|
211
|
-
const plain = candidates.filter((one) => !one.value.shorthand);
|
|
212
|
-
const resolved = project.symbolsAt(plain.map((one) => project.handle(one.value.name))).map(must);
|
|
213
|
-
const symbolOf = new Map(plain.map((one, index) => [one, resolved[index]]));
|
|
214
|
-
return candidates.flatMap((one) => {
|
|
215
|
-
const symbol = one.value.shorthand
|
|
216
|
-
? must(project.shorthandValueAt(project.handle(one.value.name)))
|
|
217
|
-
: symbolOf.get(one);
|
|
218
|
-
const parameter = symbol === undefined ? undefined : erased.get(symbol.id);
|
|
219
|
-
return parameter === undefined ? [] : [{ parameter, site: one.site, argument: one.argument }];
|
|
220
|
-
});
|
|
221
|
-
}
|
|
222
|
-
/**
|
|
223
|
-
* The symbols of the interfaces and object types code of the analysis implements: those a
|
|
224
|
-
* class's `implements` and `extends` clauses name, those an object literal is typed as by
|
|
225
|
-
* a variable or property annotation or a `satisfies` or `as` expression, and every type
|
|
226
|
-
* each of those extends. Read at the first call, which asks the checker.
|
|
227
|
-
*/
|
|
228
|
-
function implementedOwners(project, inAnalysis) {
|
|
229
|
-
let owners;
|
|
230
|
-
return () => {
|
|
231
|
-
if (owners !== undefined) {
|
|
232
|
-
return owners;
|
|
233
|
-
}
|
|
234
|
-
const found = new Set();
|
|
235
|
-
const queries = project.queries;
|
|
236
|
-
const own = project.ownPaths();
|
|
237
|
-
const files = [
|
|
238
|
-
...project.ownSourceFiles(),
|
|
239
|
-
...project.program
|
|
240
|
-
.getSourceFileNames()
|
|
241
|
-
.filter((name) => !own.has(name) && inAnalysis(name))
|
|
242
|
-
.flatMap((name) => project.program.getSourceFile(name) ?? []),
|
|
243
|
-
];
|
|
244
|
-
const naming = [];
|
|
245
|
-
const visit = (node) => {
|
|
246
|
-
if (isClassDeclaration(node) || isClassExpression(node)) {
|
|
247
|
-
naming.push(...(node.heritageClauses ?? []).flatMap((clause) => [...clause.types]));
|
|
248
|
-
}
|
|
249
|
-
else if ((isVariableDeclaration(node) || isPropertyDeclaration(node)) &&
|
|
250
|
-
node.type !== undefined &&
|
|
251
|
-
node.initializer !== undefined &&
|
|
252
|
-
isObjectLiteralExpression(evaluated(node.initializer))) {
|
|
253
|
-
naming.push(node.type);
|
|
254
|
-
}
|
|
255
|
-
else if ((isSatisfiesExpression(node) || isAsExpression(node)) &&
|
|
256
|
-
isObjectLiteralExpression(evaluated(node.expression))) {
|
|
257
|
-
naming.push(node.type);
|
|
258
|
-
}
|
|
259
|
-
node.forEachChild(visit);
|
|
260
|
-
};
|
|
261
|
-
for (const file of files) {
|
|
262
|
-
file.forEachChild(visit);
|
|
263
|
-
}
|
|
264
|
-
const pending = typesAt(project, naming).filter((type) => type !== undefined);
|
|
265
|
-
const seen = new Set();
|
|
266
|
-
for (let type = pending.pop(); type !== undefined; type = pending.pop()) {
|
|
267
|
-
for (const part of must(queries.constituents(type))) {
|
|
268
|
-
const target = must(queries.targetOf(part));
|
|
269
|
-
if (!seen.has(target.id)) {
|
|
270
|
-
seen.add(target.id);
|
|
271
|
-
const symbol = must(queries.symbolOfType(target));
|
|
272
|
-
if (symbol !== undefined) {
|
|
273
|
-
found.add(symbol.id);
|
|
274
|
-
}
|
|
275
|
-
pending.push(...must(queries.baseTypes(target)));
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
owners = found;
|
|
280
|
-
return owners;
|
|
281
|
-
};
|
|
282
|
-
}
|
|
283
|
-
/**
|
|
284
|
-
* The destinations of one project's calls. A call is one at every argument where its
|
|
285
|
-
* callee is a serializer an entry names; at the arguments its resolved signature types
|
|
286
|
-
* `unknown` or `any` where its callee is declared outside the analysis or only ambiently
|
|
287
|
-
* with no implementation in it; and, where its callee is a function of the project, at each
|
|
288
|
-
* parameter the function hands on to a destination, holding back the widest of what those
|
|
289
|
-
* destinations hold back, which is settled by widening until no parameter moves.
|
|
290
|
-
*/
|
|
291
|
-
function destinations(input, chains, walked) {
|
|
292
|
-
const { project, held } = input;
|
|
293
|
-
const queries = project.queries;
|
|
294
|
-
const own = project.ownPaths();
|
|
295
|
-
const named = resolveEntries(project, held, [JSON_STRINGIFY, ...input.ts.serializers]).filter(namesADeclaration);
|
|
296
|
-
const forms = new Map();
|
|
297
|
-
for (const site of walked.sites) {
|
|
298
|
-
const form = throughMethod(site.call);
|
|
299
|
-
if (form !== undefined) {
|
|
300
|
-
forms.set(site.call, form);
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
const callees = resolvedTargets(project, [
|
|
304
|
-
...walked.sites.flatMap((site) => calleeName(site.call.expression) ?? []),
|
|
305
|
-
...[...forms.values()].flatMap((form) => {
|
|
306
|
-
const name = calleeName(form.invocation.callee);
|
|
307
|
-
return name === undefined ? [form.method] : [form.method, name];
|
|
308
|
-
}),
|
|
309
|
-
]);
|
|
310
|
-
const erased = erasedParameters(project, walked.parameters);
|
|
311
|
-
const byFunction = new Map();
|
|
312
|
-
for (const parameter of erased.values()) {
|
|
313
|
-
byFunction.set(parameter.fn, [...(byFunction.get(parameter.fn) ?? []), parameter]);
|
|
314
|
-
}
|
|
315
|
-
const inAnalysis = (path) => own.has(path) || input.consumers.some((root) => path === root || path.startsWith(`${root}/`));
|
|
316
|
-
const implemented = implementedOwners(project, inAnalysis);
|
|
317
|
-
/**
|
|
318
|
-
* Whether every one of `declarations`, all of the callee's by default, is outside the
|
|
319
|
-
* analysis or ambient. An ambient declaration has no body, so the code that runs is
|
|
320
|
-
* outside the analysis, unless it is a member of an interface or an object type a class
|
|
321
|
-
* or a typed object literal of the analysis implements; `settled` false skips that
|
|
322
|
-
* question, which asks the checker.
|
|
323
|
-
*/
|
|
324
|
-
const outside = (target, settled, declarations = target.declarations) => declarations.length > 0 &&
|
|
325
|
-
declarations.every((handle) => {
|
|
326
|
-
if (!inAnalysis(handle.path)) {
|
|
327
|
-
return true;
|
|
328
|
-
}
|
|
329
|
-
const node = project.declarationAt(handle)?.node;
|
|
330
|
-
if (node === undefined || (node.flags & NodeFlags.Ambient) === 0) {
|
|
331
|
-
return false;
|
|
332
|
-
}
|
|
333
|
-
if (!settled || !(isInterfaceDeclaration(node.parent) || isTypeLiteralNode(node.parent))) {
|
|
334
|
-
return true;
|
|
335
|
-
}
|
|
336
|
-
const owner = must(queries.parentOf(target));
|
|
337
|
-
return owner === undefined || !implemented().has(owner.id);
|
|
338
|
-
});
|
|
339
|
-
/**
|
|
340
|
-
* Whether some one declaration of a callee is outside the analysis or ambient, without
|
|
341
|
-
* asking the checker. A project's declaration merged into a library's symbol leaves the
|
|
342
|
-
* library's beside it, so a call can still resolve to the library's.
|
|
343
|
-
*/
|
|
344
|
-
const mayBeOutside = (target) => target.declarations.some((handle) => outside(target, false, [handle]));
|
|
345
|
-
const invocation = (call) => {
|
|
346
|
-
const form = forms.get(call);
|
|
347
|
-
const method = form === undefined ? undefined : callees.get(form.method);
|
|
348
|
-
// Only the standard library's function methods pass their arguments on: the
|
|
349
|
-
// program's own `call` and `Reflect.apply` invoke nothing here.
|
|
350
|
-
if (form !== undefined &&
|
|
351
|
-
method !== undefined &&
|
|
352
|
-
mayBeOutside(method) &&
|
|
353
|
-
FUNCTION_INTERFACES.has(must(project.queries.parentOf(method))?.name ?? "")) {
|
|
354
|
-
return form.invocation;
|
|
355
|
-
}
|
|
356
|
-
return { callee: call.expression, arguments: call.arguments, indirect: false };
|
|
357
|
-
};
|
|
358
|
-
const calleeOf = (call) => {
|
|
359
|
-
const name = calleeName(invocation(call).callee);
|
|
360
|
-
return name === undefined ? undefined : callees.get(name);
|
|
361
|
-
};
|
|
362
|
-
const signatures = new Map();
|
|
363
|
-
const resolvedOf = (call) => {
|
|
364
|
-
if (!signatures.has(call)) {
|
|
365
|
-
signatures.set(call, must(queries.resolvedSignature(call)));
|
|
366
|
-
}
|
|
367
|
-
return signatures.get(call);
|
|
368
|
-
};
|
|
369
|
-
/**
|
|
370
|
-
* The declarations of a callee that the declaration of a direct call's resolved
|
|
371
|
-
* signature lies in, or all of them where it lies in none: a declaration merged into
|
|
372
|
-
* the callee's symbol that the call does not resolve to does not decide where it runs.
|
|
373
|
-
*/
|
|
374
|
-
const calledDeclarations = (call, target) => {
|
|
375
|
-
const declaration = invocation(call).indirect ? undefined : resolvedOf(call)?.declaration;
|
|
376
|
-
const signature = declaration === undefined ? undefined : project.declarationAt(declaration)?.node;
|
|
377
|
-
if (declaration === undefined || signature === undefined) {
|
|
378
|
-
return target.declarations;
|
|
379
|
-
}
|
|
380
|
-
const containing = target.declarations.filter((handle) => {
|
|
381
|
-
const node = handle.path === declaration.path ? project.declarationAt(handle)?.node : undefined;
|
|
382
|
-
return node !== undefined && node.pos <= signature.pos && signature.end <= node.end;
|
|
383
|
-
});
|
|
384
|
-
return containing.length === 0 ? target.declarations : containing;
|
|
385
|
-
};
|
|
386
|
-
/** Whether a type names a type parameter, through constituents, type arguments and call signatures. */
|
|
387
|
-
const mentions = (type, parameter, depth) => {
|
|
388
|
-
// A conditional type an alias names, `Awaited<T>` among them, carries its arguments
|
|
389
|
-
// only on the alias the client's type object reports.
|
|
390
|
-
const aliased = type
|
|
391
|
-
.aliasTypeArguments;
|
|
392
|
-
if (type.id === parameter.id || aliased?.includes(parameter.id) === true) {
|
|
393
|
-
return true;
|
|
394
|
-
}
|
|
395
|
-
if (depth >= MENTION_DEPTH) {
|
|
396
|
-
return false;
|
|
397
|
-
}
|
|
398
|
-
const inner = [
|
|
399
|
-
...(type.isUnionType() || type.isIntersectionType() ? must(queries.constituents(type)) : []),
|
|
400
|
-
...must(queries.typeArguments(type)),
|
|
401
|
-
...must(queries.signaturesOf(type, SignatureKind.Call)).flatMap((signature) => [
|
|
402
|
-
...signature.parameters.map((_parameter, at) => must(queries.typeAtPosition(signature, at))),
|
|
403
|
-
...[must(queries.returnTypeOf(signature))].filter((one) => one !== undefined),
|
|
404
|
-
]),
|
|
405
|
-
];
|
|
406
|
-
return inner.some((one) => mentions(one, parameter, depth + 1));
|
|
407
|
-
};
|
|
408
|
-
const erasedArguments = new Map();
|
|
409
|
-
const erasedAt = (call, argument) => {
|
|
410
|
-
let indexes = erasedArguments.get(call);
|
|
411
|
-
if (indexes === undefined) {
|
|
412
|
-
const invoked = invocation(call);
|
|
413
|
-
// Through a method of the prototype the resolved signature is the method's, so
|
|
414
|
-
// the parameters are read off the callee's own signatures, any one erasing.
|
|
415
|
-
const type = invoked.indirect ? must(queries.typeAt(invoked.callee)) : undefined;
|
|
416
|
-
const signatures = invoked.indirect
|
|
417
|
-
? type === undefined
|
|
418
|
-
? []
|
|
419
|
-
: must(queries.signaturesOf(type, SignatureKind.Call))
|
|
420
|
-
: [resolvedOf(call)].filter((one) => one !== undefined);
|
|
421
|
-
// A type parameter of the callee that nothing constrains and its result does not name
|
|
422
|
-
// keeps nothing of the value either: the instantiated signature names the value's own
|
|
423
|
-
// type there instead, and a result that names it hands the value back.
|
|
424
|
-
const generic = invoked.indirect ? undefined : resolvedOf(call);
|
|
425
|
-
const declared = generic === undefined ? undefined : must(queries.genericOf(generic));
|
|
426
|
-
const unconstrained = (index) => {
|
|
427
|
-
const parameter = declared === undefined ? undefined : must(queries.parameterType(declared, index));
|
|
428
|
-
const parts = parameter === undefined
|
|
429
|
-
? []
|
|
430
|
-
: parameter.isUnionType()
|
|
431
|
-
? must(queries.constituents(parameter))
|
|
432
|
-
: [parameter];
|
|
433
|
-
const result = declared === undefined ? undefined : must(queries.returnTypeOf(declared));
|
|
434
|
-
return parts.some((part) => {
|
|
435
|
-
if (!part.isTypeParameter() || (result !== undefined && mentions(result, part, 0))) {
|
|
436
|
-
return false;
|
|
437
|
-
}
|
|
438
|
-
const constraint = must(queries.constraintOf(part));
|
|
439
|
-
return constraint === undefined || (constraint.flags & ERASED) !== 0;
|
|
440
|
-
});
|
|
441
|
-
};
|
|
442
|
-
indexes = new Set(invoked.arguments.flatMap((_unused, index) => unconstrained(index) ||
|
|
443
|
-
signatures.some((signature) => {
|
|
444
|
-
const parameter = must(queries.parameterType(signature, index));
|
|
445
|
-
return parameter !== undefined && (parameter.flags & ERASED) !== 0;
|
|
446
|
-
})
|
|
447
|
-
? [index]
|
|
448
|
-
: []));
|
|
449
|
-
erasedArguments.set(call, indexes);
|
|
450
|
-
}
|
|
451
|
-
return indexes.has(argument);
|
|
452
|
-
};
|
|
453
|
-
const forwards = new Map();
|
|
454
|
-
const keyOf = (parameter) => `${parameter.fn}\u0000${String(parameter.index)}`;
|
|
455
|
-
const at = (call, argument) => {
|
|
456
|
-
const target = calleeOf(call);
|
|
457
|
-
if (target === undefined) {
|
|
458
|
-
return undefined;
|
|
459
|
-
}
|
|
460
|
-
const entry = named.find((one) => names(one, target, chains));
|
|
461
|
-
if (entry !== undefined) {
|
|
462
|
-
return { reach: "properties", callee: spelledEntry(entry.entry, held) };
|
|
463
|
-
}
|
|
464
|
-
if (outside(target, true, calledDeclarations(call, target))) {
|
|
465
|
-
return erasedAt(call, argument)
|
|
466
|
-
? {
|
|
467
|
-
reach: "conversions",
|
|
468
|
-
callee: invocation(call).callee.getText().replace(/\s+/gu, ""),
|
|
469
|
-
}
|
|
470
|
-
: undefined;
|
|
471
|
-
}
|
|
472
|
-
for (const fn of chains.declarationsOf(target)) {
|
|
473
|
-
const parameter = (byFunction.get(fn) ?? []).find((one) => one.index === argument || (one.rest && one.index <= argument));
|
|
474
|
-
const reach = parameter === undefined ? undefined : forwards.get(keyOf(parameter));
|
|
475
|
-
if (reach !== undefined) {
|
|
476
|
-
return { reach, callee: held.symbols.find((symbol) => symbol.id === fn)?.name ?? fn };
|
|
477
|
-
}
|
|
478
|
-
}
|
|
479
|
-
return undefined;
|
|
480
|
-
};
|
|
481
|
-
const forwarded = handedOn(project, walked.sites, erased, invocation);
|
|
482
|
-
for (let moved = true; moved;) {
|
|
483
|
-
moved = false;
|
|
484
|
-
for (const one of forwarded) {
|
|
485
|
-
const key = keyOf(one.parameter);
|
|
486
|
-
const before = forwards.get(key);
|
|
487
|
-
const after = wider(before, at(one.site.call, one.argument)?.reach);
|
|
488
|
-
if (after !== undefined && after !== before) {
|
|
489
|
-
forwards.set(key, after);
|
|
490
|
-
moved = true;
|
|
491
|
-
}
|
|
492
|
-
}
|
|
493
|
-
}
|
|
494
|
-
const mayReceive = (call) => {
|
|
495
|
-
const target = calleeOf(call);
|
|
496
|
-
if (target === undefined) {
|
|
497
|
-
return false;
|
|
498
|
-
}
|
|
499
|
-
if (named.some((one) => names(one, target, chains)) || mayBeOutside(target)) {
|
|
500
|
-
return true;
|
|
501
|
-
}
|
|
502
|
-
return chains
|
|
503
|
-
.declarationsOf(target)
|
|
504
|
-
.some((fn) => (byFunction.get(fn) ?? []).some((parameter) => forwards.has(keyOf(parameter))));
|
|
505
|
-
};
|
|
506
|
-
return { invocation, at, mayReceive };
|
|
507
|
-
}
|
|
508
|
-
/** What two reaches carry together. */
|
|
509
|
-
function joined(a, b) {
|
|
510
|
-
return { classes: new Set([...a.classes, ...b.classes]), members: [...a.members, ...b.members] };
|
|
511
|
-
}
|
|
512
|
-
/** Each argument of a call that can receive one whose value carries a class of the target. */
|
|
513
|
-
function flowsOf(project, held, sites, to, stores) {
|
|
514
|
-
const reach = valueReach(project, held, stores.inside);
|
|
515
|
-
const arguments_ = sites.flatMap((site) => to.mayReceive(site.call)
|
|
516
|
-
? to.invocation(site.call).arguments.flatMap((argument, index) => {
|
|
517
|
-
const value = evaluated(argument);
|
|
518
|
-
return holdsNoInstance(value) ? [] : [{ site, argument: index, value }];
|
|
519
|
-
})
|
|
520
|
-
: []);
|
|
521
|
-
const asked = arguments_.filter((one) => one.value.kind !== SyntaxKind.ThisKeyword);
|
|
522
|
-
const types = typesAt(project, asked.map((one) => one.value));
|
|
523
|
-
const typeOf = new Map(asked.map((one, index) => [one.value, types[index]]));
|
|
524
|
-
const checked = checkedTypes(project, arguments_.map((one) => one.value));
|
|
525
|
-
const passed = arguments_.flatMap((one, index) => {
|
|
526
|
-
const type = typeOf.get(one.value);
|
|
527
|
-
let reached = { classes: new Set(), members: [] };
|
|
528
|
-
if (one.value.kind === SyntaxKind.ThisKeyword) {
|
|
529
|
-
reached = {
|
|
530
|
-
classes: new Set(one.site.self === undefined ? [] : [one.site.self]),
|
|
531
|
-
members: [],
|
|
532
|
-
};
|
|
533
|
-
}
|
|
534
|
-
else if (type !== undefined) {
|
|
535
|
-
reached = reach.reachedFrom(type);
|
|
536
|
-
}
|
|
537
|
-
for (const stored of [...(checked[index] ?? []), ...(stores.ofVariable(one.value) ?? [])]) {
|
|
538
|
-
reached = joined(reached, reach.reachedFrom(stored));
|
|
539
|
-
}
|
|
540
|
-
const carries = reached.classes.size > 0 || reached.members.length > 0;
|
|
541
|
-
const destination = carries ? to.at(one.site.call, one.argument) : undefined;
|
|
542
|
-
return destination === undefined
|
|
543
|
-
? []
|
|
544
|
-
: [
|
|
545
|
-
{
|
|
546
|
-
site: one.value,
|
|
547
|
-
classes: reached.classes,
|
|
548
|
-
members: reached.members,
|
|
549
|
-
to: destination,
|
|
550
|
-
detail: `passed to ${destination.callee}`,
|
|
551
|
-
},
|
|
552
|
-
];
|
|
553
|
-
});
|
|
554
|
-
const left = stores.outside.flatMap((store) => {
|
|
555
|
-
const reached = reach.reachedFrom(store.type);
|
|
556
|
-
return reached.classes.size === 0 && reached.members.length === 0
|
|
557
|
-
? []
|
|
558
|
-
: [
|
|
559
|
-
{
|
|
560
|
-
site: store.value,
|
|
561
|
-
classes: reached.classes,
|
|
562
|
-
members: reached.members,
|
|
563
|
-
to: { reach: "conversions", callee: store.property },
|
|
564
|
-
detail: `stored in the property ${store.property} of a type the program does not declare`,
|
|
565
|
-
},
|
|
566
|
-
];
|
|
567
|
-
});
|
|
568
|
-
return [...passed, ...left];
|
|
569
|
-
}
|
|
570
|
-
/**
|
|
571
|
-
* The serialization-contract detector: each data member and `toJSON` of each class,
|
|
572
|
-
* interface and object type a value that reaches a destination carries, and `toString`
|
|
573
|
-
* as well where the destination is outside the analysis, recorded at the argument with
|
|
574
|
-
* the callee named.
|
|
575
|
-
*/
|
|
576
|
-
export function serializationContract(input) {
|
|
577
|
-
const { project, held, targetRoot } = input;
|
|
578
|
-
const walked = walkProject(project, held);
|
|
579
|
-
const chains = aliasChains(project, held);
|
|
580
|
-
const flows = flowsOf(project, held, walked.sites, destinations(input, chains, walked), erasedStores(project));
|
|
581
|
-
if (flows.length === 0) {
|
|
582
|
-
return [];
|
|
583
|
-
}
|
|
584
|
-
const members = classMembers(project, held, new Set(flows.flatMap((flow) => [...flow.classes])), "instance");
|
|
585
|
-
const byId = new Map(held.symbols.map((symbol) => [symbol.id, symbol]));
|
|
586
|
-
// A destination holds back a data member and `toJSON`, and `toString` as well where
|
|
587
|
-
// the value left the analysis.
|
|
588
|
-
const holdsBack = (flags, name, to) => (flags & SymbolFlags.Property) !== 0 ||
|
|
589
|
-
((flags & CONVERSION_MEMBERS) !== 0 &&
|
|
590
|
-
(name === SERIALIZED_CONVERSION || (to.reach === "conversions" && CONVERSIONS.has(name))));
|
|
591
|
-
const found = [];
|
|
592
|
-
for (const flow of flows) {
|
|
593
|
-
const site = renderPosition(flow.site.getSourceFile(), targetRoot, flow.site.getStart());
|
|
594
|
-
const { detail } = flow;
|
|
595
|
-
for (const member of [...flow.classes].flatMap((id) => members.get(id) ?? [])) {
|
|
596
|
-
const symbol = byId.get(member.id);
|
|
597
|
-
const name = symbol === undefined ? "" : (memberComponent(symbol, byId) ?? "");
|
|
598
|
-
if (holdsBack(member.flags, name, flow.to)) {
|
|
599
|
-
found.push({ id: member.id, detail, site });
|
|
600
|
-
}
|
|
601
|
-
}
|
|
602
|
-
for (const member of flow.members) {
|
|
603
|
-
if (holdsBack(member.flags, member.name, flow.to)) {
|
|
604
|
-
for (const id of chains.declarationsOf(member)) {
|
|
605
|
-
found.push({ id, detail, site });
|
|
606
|
-
}
|
|
607
|
-
}
|
|
608
|
-
}
|
|
609
|
-
}
|
|
610
|
-
return found;
|
|
611
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* A setup failure: a file or a component the analysis needs and the project does not
|
|
3
|
-
* provide. Each one names what is missing and the fix, on one line of the error stream
|
|
4
|
-
* that starts with its class.
|
|
5
|
-
*/
|
|
6
|
-
/** The failure as the one line of the error stream that names it. */
|
|
7
|
-
export function setupLine(failure) {
|
|
8
|
-
return `setup failure: ${failure.setupClass}: ${failure.detail}`;
|
|
9
|
-
}
|
|
10
|
-
/**
|
|
11
|
-
* A run that met a setup failure where none may be dropped: in a configuration the
|
|
12
|
-
* configuration document or the scope declares, in a declared consumer, or in every
|
|
13
|
-
* configuration discovery derived. It ends the run with the failure code and no finding
|
|
14
|
-
* list.
|
|
15
|
-
*/
|
|
16
|
-
export class SetupError extends Error {
|
|
17
|
-
failures;
|
|
18
|
-
constructor(failures) {
|
|
19
|
-
super(failures.map(setupLine).join("\n"));
|
|
20
|
-
this.name = "SetupError";
|
|
21
|
-
this.failures = failures;
|
|
22
|
-
}
|
|
23
|
-
}
|