@cplieger/deadset-ts 8.0.0-dev.2 → 8.0.0-dev.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/THIRD_PARTY_NOTICES.md +27 -0
- package/dist/bin/mapper-connection.js +2 -1
- package/dist/bin/node-host.js +24 -5
- package/dist/src/alias-chain.js +35 -9
- package/dist/src/amd.js +81 -0
- package/dist/src/analysis.js +274 -496
- package/dist/src/augmentations.js +64 -3
- package/dist/src/automatic-types.js +10 -29
- package/dist/src/bindings.js +382 -0
- package/dist/src/commands/held.js +499 -0
- package/dist/src/commands/read.js +161 -0
- package/dist/src/commands/shell.js +169 -0
- package/dist/src/commands/tools.js +1847 -0
- package/dist/src/component-files.js +3 -2
- package/dist/src/component-layer.js +4 -2
- package/dist/src/config.js +6 -82
- package/dist/src/conformance-record.js +2 -2
- package/dist/src/consumers.js +10 -38
- package/dist/src/contextual-uses.js +57 -26
- package/dist/src/contract/config.generated.js +561 -0
- package/dist/src/contract/contract.generated.js +1370 -0
- package/dist/src/contract/report.generated.js +866 -0
- package/dist/src/dependencies.js +165 -122
- package/dist/src/destructuring.js +1 -19
- package/dist/src/edges.js +38 -122
- package/dist/src/element-access.js +181 -168
- package/dist/src/entries/build-scripts.js +222 -0
- package/dist/src/{configuration-files.js → entries/configuration-files.js} +52 -256
- package/dist/src/{convention-rows.js → entries/convention-rows.js} +170 -30
- package/dist/src/entries/conventions.js +740 -0
- package/dist/src/{html-entries.js → entries/html-entries.js} +12 -42
- package/dist/src/{mdx-entries.js → entries/mdx-entries.js} +5 -28
- package/dist/src/entries/run-directories.js +77 -0
- package/dist/src/entries/sources.js +144 -0
- package/dist/src/entries/static-module.js +670 -0
- package/dist/src/entries/test-runners.js +650 -0
- package/dist/src/entries/workflow-steps.js +345 -0
- package/dist/src/exemptions/argument-places.js +131 -0
- package/dist/src/exemptions/calls.js +338 -0
- package/dist/src/exemptions/classes.js +13 -0
- package/dist/src/{decorator.js → exemptions/decorator.js} +19 -30
- package/dist/src/exemptions/detectors.js +48 -0
- package/dist/src/{enum-group.js → exemptions/enum-group.js} +9 -16
- package/dist/src/{erased-stores.js → exemptions/erased-stores.js} +7 -11
- package/dist/src/{framework-lifecycle.js → exemptions/framework-lifecycle.js} +76 -54
- package/dist/src/exemptions/generated-file.js +241 -0
- package/dist/src/{injection-container.js → exemptions/injection-container.js} +20 -26
- package/dist/src/exemptions/installed-globals.js +173 -0
- package/dist/src/{interface-satisfaction.js → exemptions/interface-satisfaction.js} +52 -121
- package/dist/src/exemptions/lifecycle.js +150 -0
- package/dist/src/{reflective-lookup.js → exemptions/reflective-lookup.js} +3 -3
- package/dist/src/exemptions/serialization-contract.js +1276 -0
- package/dist/src/exemptions/sites.js +182 -0
- package/dist/src/{template-field.js → exemptions/template-field.js} +13 -23
- package/dist/src/{value-reach.js → exemptions/value-reach.js} +14 -7
- package/dist/src/exposure.js +400 -0
- package/dist/src/extensions.js +37 -0
- package/dist/src/facts.js +38 -0
- package/dist/src/failure.js +36 -0
- package/dist/src/file-facts.js +3 -26
- package/dist/src/findings/completion.js +109 -56
- package/dist/src/findings/dependencies-and-module-machinery.js +4 -5
- package/dist/src/findings/emitters.js +27 -41
- package/dist/src/{implementations.js → findings/implementations.js} +3 -3
- package/dist/src/{in-operands.js → findings/in-operands.js} +3 -2
- package/dist/src/findings/interfaces.js +4 -5
- package/dist/src/findings/intra-function.js +16 -13
- package/dist/src/findings/non-code-artifacts.js +17 -12
- package/dist/src/findings/reads-and-writes.js +86 -27
- package/dist/src/findings/self-check.js +44 -30
- package/dist/src/findings/unused-declarations.js +29 -45
- package/dist/src/findings/visibility-narrowing.js +23 -31
- package/dist/src/findings-pass.js +13 -21
- package/dist/src/fs/document.js +52 -0
- package/dist/src/fs/manifest.js +67 -0
- package/dist/src/fs/tree.js +88 -0
- package/dist/src/git-ignore.js +39 -26
- package/dist/src/import-bindings.js +73 -28
- package/dist/src/index/sites.js +557 -0
- package/dist/src/index/values.js +124 -0
- package/dist/src/index.js +2 -2
- package/dist/src/indexed-access.js +523 -478
- package/dist/src/intra-function-parts.js +63 -43
- package/dist/src/inventory/commonjs.js +507 -0
- package/dist/src/inventory/enumerate.js +167 -0
- package/dist/src/inventory/syntax.js +236 -0
- package/dist/src/inventory.js +323 -724
- package/dist/src/javascript-file.js +48 -0
- package/dist/src/json-document.js +198 -67
- package/dist/src/keyof-comparisons.js +126 -107
- package/dist/src/kinds.js +3 -366
- package/dist/src/{components.js → liveness/components.js} +2 -3
- package/dist/src/{graph.js → liveness/graph.js} +52 -28
- package/dist/src/liveness/matrix.js +99 -0
- package/dist/src/liveness/sweep.js +558 -0
- package/dist/src/load/classify.js +289 -0
- package/dist/src/load/diagnostics.js +87 -0
- package/dist/src/load/discover.js +285 -0
- package/dist/src/{emit-map.js → load/emit-map.js} +1 -1
- package/dist/src/load/expected-module.js +136 -0
- package/dist/src/load/load.js +27 -0
- package/dist/src/load/module-lookup.js +37 -0
- package/dist/src/load/package-scope.js +56 -0
- package/dist/src/load/plan.js +313 -0
- package/dist/src/load/specifiers.js +113 -0
- package/dist/src/load/synthesize.js +152 -0
- package/dist/src/load/test-globals.js +207 -0
- package/dist/src/load/test-joins.js +82 -0
- package/dist/src/{workspace-manifests.js → load/workspace-manifests.js} +4 -4
- package/dist/src/{workspace-programs.js → load/workspace-programs.js} +89 -66
- package/dist/src/{workspace-resolution.js → load/workspace-resolution.js} +24 -66
- package/dist/src/{workspace-run.js → load/workspace-run.js} +7 -7
- package/dist/src/{workspace.js → load/workspace.js} +62 -124
- package/dist/src/module-declarations.js +70 -85
- package/dist/src/overrides.js +134 -112
- package/dist/src/partial.js +2 -1
- package/dist/src/paths.js +82 -16
- package/dist/src/platform-calls.js +78 -0
- package/dist/src/platform-symbols.js +134 -0
- package/dist/src/position.js +43 -1
- package/dist/src/print.js +11 -79
- package/dist/src/product.js +13 -0
- package/dist/src/query.js +95 -0
- package/dist/src/ref.js +12 -20
- package/dist/src/references/read-rule.js +1 -0
- package/dist/src/references/read-rules.js +48 -0
- package/dist/src/references/sink.js +237 -0
- package/dist/src/references/sources.js +450 -0
- package/dist/src/references.js +117 -1074
- package/dist/src/report-schema.js +51 -0
- package/dist/src/report.js +57 -41
- package/dist/src/reporters/annotations.js +15 -8
- package/dist/src/reporters/sarif.js +16 -10
- package/dist/src/reporters/template.js +4 -19
- package/dist/src/resolve.js +246 -730
- package/dist/src/{configured-declarations.js → roots/configured-declarations.js} +22 -24
- package/dist/src/{entry-point-gaps.js → roots/entry-point-gaps.js} +6 -15
- package/dist/src/roots/manifest.js +216 -0
- package/dist/src/roots/published-reach.js +412 -0
- package/dist/src/roots/root-set.js +487 -0
- package/dist/src/roots/unseen-loads.js +236 -0
- package/dist/src/run.js +66 -77
- package/dist/src/schema.js +320 -343
- package/dist/src/scope.js +38 -115
- package/dist/src/session.js +37 -29
- package/dist/src/source-files.js +6 -10
- package/dist/src/stores.js +4 -2
- package/dist/src/suppress-file.js +25 -28
- package/dist/src/suppress-inline.js +36 -83
- package/dist/src/suppress.js +50 -71
- package/dist/src/symbol-keys.js +92 -88
- package/dist/src/tests/file-class.js +76 -0
- package/dist/src/{outside-tests.js → tests/outside.js} +7 -7
- package/dist/src/{test-support.js → tests/support.js} +5 -12
- package/dist/src/text/compare.js +26 -0
- package/dist/src/text/glob.js +194 -0
- package/dist/src/text/named-files.js +298 -0
- package/dist/src/text/yaml.js +684 -0
- package/dist/src/type-errors.js +11 -232
- package/dist/src/type-parameter-reads.js +178 -139
- package/dist/src/unimplemented-callees.js +262 -242
- package/dist/src/unwrap.js +23 -0
- package/dist/src/usage.js +10 -0
- package/dist/src/vendor/unbash/ansi-c.js +132 -0
- package/dist/src/vendor/unbash/arithmetic-parts.js +37 -0
- package/dist/src/vendor/unbash/arithmetic.js +591 -0
- package/dist/src/vendor/unbash/assignment.js +131 -0
- package/dist/src/vendor/unbash/chars.js +48 -0
- package/dist/src/vendor/unbash/command.js +41 -0
- package/dist/src/vendor/unbash/expansion.js +80 -0
- package/dist/src/vendor/unbash/glob.js +268 -0
- package/dist/src/vendor/unbash/heredoc.js +27 -0
- package/dist/src/vendor/unbash/internal-types.js +1 -0
- package/dist/src/vendor/unbash/lexer.js +4274 -0
- package/dist/src/vendor/unbash/limits.js +3 -0
- package/dist/src/vendor/unbash/parser.js +1366 -0
- package/dist/src/vendor/unbash/parts.js +57 -0
- package/dist/src/vendor/unbash/substitution-context.js +8 -0
- package/dist/src/vendor/unbash/traversal.js +212 -0
- package/dist/src/vendor/unbash/types.js +1 -0
- package/dist/src/vendor/unbash/word-value.js +61 -0
- package/dist/src/vendor/unbash/word.js +40 -0
- package/dist/src/verbs/analyze.js +194 -127
- package/dist/src/verbs/describe.js +13 -18
- package/dist/src/verbs/explain.js +85 -139
- package/dist/src/verbs/print-config.js +2 -1
- package/dist/src/verbs/print-projects.js +6 -4
- package/dist/src/verbs/print-retained.js +30 -6
- package/dist/src/verbs/print-roots.js +4 -2
- package/dist/src/verbs/verb.js +1 -5
- package/dist/src/verbs/version.js +14 -3
- package/jsr.json +2 -1
- package/package.json +14 -8
- package/src/alias-chain.ts +40 -11
- package/src/amd.ts +130 -0
- package/src/analysis.ts +426 -733
- package/src/augmentations.ts +93 -4
- package/src/automatic-types.ts +12 -30
- package/src/bindings.ts +460 -0
- package/src/commands/held.ts +632 -0
- package/src/commands/read.ts +242 -0
- package/src/commands/shell.ts +228 -0
- package/src/commands/tools.ts +2382 -0
- package/src/component-files.ts +4 -2
- package/src/component-layer.ts +4 -2
- package/src/config.ts +31 -302
- package/src/conformance-record.ts +2 -2
- package/src/consumers.ts +16 -66
- package/src/contextual-uses.ts +66 -34
- package/src/contract/config.generated.ts +821 -0
- package/src/contract/contract.generated.ts +1453 -0
- package/src/contract/report.generated.ts +1241 -0
- package/src/dependencies.ts +223 -128
- package/src/destructuring.ts +1 -31
- package/src/edges.ts +41 -140
- package/src/element-access.ts +190 -187
- package/src/entries/build-scripts.ts +292 -0
- package/src/{configuration-files.ts → entries/configuration-files.ts} +68 -278
- package/src/{convention-rows.ts → entries/convention-rows.ts} +227 -31
- package/src/{conventions.ts → entries/conventions.ts} +367 -583
- package/src/{html-entries.ts → entries/html-entries.ts} +22 -48
- package/src/{mdx-entries.ts → entries/mdx-entries.ts} +7 -30
- package/src/entries/run-directories.ts +108 -0
- package/src/entries/sources.ts +266 -0
- package/src/entries/static-module.ts +858 -0
- package/src/entries/test-runners.ts +835 -0
- package/src/entries/workflow-steps.ts +432 -0
- package/src/exemptions/argument-places.ts +198 -0
- package/src/exemptions/calls.ts +483 -0
- package/src/exemptions/classes.ts +49 -0
- package/src/exemptions/decorator.ts +56 -0
- package/src/exemptions/detectors.ts +75 -0
- package/src/{enum-group.ts → exemptions/enum-group.ts} +10 -19
- package/src/{erased-stores.ts → exemptions/erased-stores.ts} +7 -14
- package/src/{framework-lifecycle.ts → exemptions/framework-lifecycle.ts} +85 -66
- package/src/exemptions/generated-file.ts +318 -0
- package/src/{injection-container.ts → exemptions/injection-container.ts} +29 -34
- package/src/exemptions/installed-globals.ts +255 -0
- package/src/{interface-satisfaction.ts → exemptions/interface-satisfaction.ts} +69 -160
- package/src/exemptions/lifecycle.ts +286 -0
- package/src/{reflective-lookup.ts → exemptions/reflective-lookup.ts} +5 -5
- package/src/exemptions/serialization-contract.ts +1729 -0
- package/src/exemptions/sites.ts +293 -0
- package/src/{template-field.ts → exemptions/template-field.ts} +22 -32
- package/src/{value-reach.ts → exemptions/value-reach.ts} +16 -8
- package/src/exposure.ts +492 -0
- package/src/extensions.ts +45 -0
- package/src/facts.ts +46 -0
- package/src/failure.ts +63 -0
- package/src/file-facts.ts +15 -25
- package/src/finding.ts +10 -10
- package/src/findings/boundary.ts +11 -0
- package/src/findings/completion.ts +133 -64
- package/src/findings/dependencies-and-module-machinery.ts +4 -7
- package/src/findings/emitter.ts +9 -10
- package/src/findings/emitters.ts +38 -52
- package/src/{implementations.ts → findings/implementations.ts} +4 -4
- package/src/{in-operands.ts → findings/in-operands.ts} +4 -3
- package/src/findings/interfaces.ts +7 -9
- package/src/findings/intra-function.ts +16 -14
- package/src/findings/non-code-artifacts.ts +24 -15
- package/src/findings/reads-and-writes.ts +118 -41
- package/src/findings/self-check.ts +51 -38
- package/src/findings/unused-declarations.ts +31 -49
- package/src/findings/visibility-narrowing.ts +36 -40
- package/src/findings-pass.ts +15 -31
- package/src/fs/document.ts +70 -0
- package/src/fs/manifest.ts +96 -0
- package/src/fs/tree.ts +110 -0
- package/src/git-ignore.ts +50 -26
- package/src/host.ts +12 -5
- package/src/import-bindings.ts +98 -29
- package/src/index/sites.ts +781 -0
- package/src/index/values.ts +170 -0
- package/src/index.ts +2 -2
- package/src/indexed-access.ts +570 -527
- package/src/intra-function-parts.ts +73 -44
- package/src/inventory/commonjs.ts +696 -0
- package/src/inventory/enumerate.ts +203 -0
- package/src/inventory/syntax.ts +311 -0
- package/src/inventory.ts +442 -895
- package/src/javascript-file.ts +54 -0
- package/src/json-document.ts +241 -76
- package/src/keyof-comparisons.ts +133 -122
- package/src/kinds.ts +5 -413
- package/src/{components.ts → liveness/components.ts} +4 -6
- package/src/{graph.ts → liveness/graph.ts} +100 -35
- package/src/liveness/matrix.ts +162 -0
- package/src/liveness/sweep.ts +855 -0
- package/src/load/classify.ts +433 -0
- package/src/load/diagnostics.ts +154 -0
- package/src/load/discover.ts +471 -0
- package/src/{emit-map.ts → load/emit-map.ts} +1 -1
- package/src/load/expected-module.ts +194 -0
- package/src/load/load.ts +73 -0
- package/src/load/module-lookup.ts +50 -0
- package/src/load/package-scope.ts +74 -0
- package/src/load/plan.ts +513 -0
- package/src/load/specifiers.ts +171 -0
- package/src/load/synthesize.ts +230 -0
- package/src/load/test-globals.ts +251 -0
- package/src/load/test-joins.ts +98 -0
- package/src/{workspace-manifests.ts → load/workspace-manifests.ts} +5 -5
- package/src/{workspace-programs.ts → load/workspace-programs.ts} +128 -85
- package/src/{workspace-resolution.ts → load/workspace-resolution.ts} +41 -77
- package/src/{workspace-run.ts → load/workspace-run.ts} +18 -16
- package/src/{workspace.ts → load/workspace.ts} +90 -134
- package/src/module-declarations.ts +74 -98
- package/src/overrides.ts +162 -134
- package/src/partial.ts +3 -2
- package/src/paths.ts +92 -16
- package/src/platform-calls.ts +119 -0
- package/src/platform-symbols.ts +189 -0
- package/src/position.ts +44 -1
- package/src/print.ts +12 -92
- package/src/product.ts +18 -0
- package/src/query.ts +201 -10
- package/src/ref.ts +12 -20
- package/src/references/read-rule.ts +60 -0
- package/src/references/read-rules.ts +55 -0
- package/src/references/sink.ts +314 -0
- package/src/references/sources.ts +632 -0
- package/src/references.ts +187 -1450
- package/src/report-schema.ts +68 -0
- package/src/report.ts +103 -226
- package/src/reporters/annotations.ts +22 -11
- package/src/reporters/json.ts +1 -1
- package/src/reporters/reporter.ts +2 -4
- package/src/reporters/reporters.ts +1 -1
- package/src/reporters/sarif.ts +29 -16
- package/src/reporters/template.ts +4 -20
- package/src/reporters/text.ts +3 -3
- package/src/resolve.ts +284 -1115
- package/src/{configured-declarations.ts → roots/configured-declarations.ts} +26 -29
- package/src/{entry-point-gaps.ts → roots/entry-point-gaps.ts} +7 -16
- package/src/roots/manifest.ts +303 -0
- package/src/roots/published-reach.ts +486 -0
- package/src/{roots.ts → roots/root-set.ts} +286 -469
- package/src/roots/unseen-loads.ts +345 -0
- package/src/run.ts +75 -91
- package/src/schema.ts +391 -388
- package/src/scope.ts +46 -138
- package/src/session.ts +87 -55
- package/src/source-files.ts +6 -11
- package/src/stores.ts +15 -3
- package/src/suppress-file.ts +24 -33
- package/src/suppress-inline.ts +55 -91
- package/src/suppress.ts +78 -79
- package/src/symbol-keys.ts +104 -107
- package/src/tests/file-class.ts +135 -0
- package/src/{outside-tests.ts → tests/outside.ts} +16 -10
- package/src/{test-support.ts → tests/support.ts} +15 -21
- package/src/text/compare.ts +27 -0
- package/src/text/glob.ts +210 -0
- package/src/text/named-files.ts +388 -0
- package/src/text/yaml.ts +747 -0
- package/src/type-errors.ts +18 -288
- package/src/type-parameter-reads.ts +187 -158
- package/src/unimplemented-callees.ts +297 -280
- package/src/unwrap.ts +34 -0
- package/src/usage.ts +10 -0
- package/src/vendor/unbash/LICENSE +15 -0
- package/src/vendor/unbash/VENDORED.md +16 -0
- package/src/vendor/unbash/ansi-c.ts +132 -0
- package/src/vendor/unbash/arithmetic-parts.ts +53 -0
- package/src/vendor/unbash/arithmetic.ts +641 -0
- package/src/vendor/unbash/assignment.ts +163 -0
- package/src/vendor/unbash/chars.ts +48 -0
- package/src/vendor/unbash/command.ts +47 -0
- package/src/vendor/unbash/expansion.ts +144 -0
- package/src/vendor/unbash/glob.ts +284 -0
- package/src/vendor/unbash/heredoc.ts +34 -0
- package/src/vendor/unbash/internal-types.ts +94 -0
- package/src/vendor/unbash/lexer.ts +4352 -0
- package/src/vendor/unbash/limits.ts +3 -0
- package/src/vendor/unbash/parser.ts +1612 -0
- package/src/vendor/unbash/parts.ts +96 -0
- package/src/vendor/unbash/substitution-context.ts +20 -0
- package/src/vendor/unbash/traversal.ts +182 -0
- package/src/vendor/unbash/types.ts +660 -0
- package/src/vendor/unbash/word-value.ts +64 -0
- package/src/vendor/unbash/word.ts +50 -0
- package/src/verbs/analyze.ts +255 -164
- package/src/verbs/describe.ts +19 -17
- package/src/verbs/explain.ts +93 -169
- package/src/verbs/print-config.ts +2 -1
- package/src/verbs/print-projects.ts +6 -4
- package/src/verbs/print-retained.ts +36 -6
- package/src/verbs/print-roots.ts +4 -2
- package/src/verbs/verb.ts +2 -8
- package/src/verbs/version.ts +15 -3
- package/dist/src/base-url.js +0 -18
- package/dist/src/calls.js +0 -155
- package/dist/src/conventions.js +0 -937
- package/dist/src/discover.js +0 -468
- package/dist/src/entry-points.js +0 -529
- package/dist/src/exempt-classes.js +0 -75
- package/dist/src/exempt.js +0 -209
- package/dist/src/generated-file.js +0 -95
- package/dist/src/glob.js +0 -65
- package/dist/src/manifest.js +0 -165
- package/dist/src/matrix.js +0 -246
- package/dist/src/pnpm-workspace.js +0 -120
- package/dist/src/roots.js +0 -672
- package/dist/src/serialization-contract.js +0 -611
- package/dist/src/setup-failure.js +0 -23
- package/dist/src/sweep.js +0 -224
- package/dist/src/test-joins.js +0 -101
- package/dist/src/value-flow.js +0 -74
- package/dist/src/version.js +0 -7
- package/dist/src/workflow-steps.js +0 -185
- package/src/base-url.ts +0 -24
- package/src/calls.ts +0 -225
- package/src/decorator.ts +0 -78
- package/src/discover.ts +0 -653
- package/src/entry-points.ts +0 -687
- package/src/exempt-classes.ts +0 -123
- package/src/exempt.ts +0 -323
- package/src/generated-file.ts +0 -111
- package/src/glob.ts +0 -67
- package/src/manifest.ts +0 -234
- package/src/matrix.ts +0 -423
- package/src/pnpm-workspace.ts +0 -135
- package/src/serialization-contract.ts +0 -849
- package/src/setup-failure.ts +0 -39
- package/src/sweep.ts +0 -347
- package/src/test-joins.ts +0 -120
- package/src/value-flow.ts +0 -104
- package/src/version.ts +0 -7
- package/src/workflow-steps.ts +0 -216
package/dist/src/edges.js
CHANGED
|
@@ -4,153 +4,69 @@
|
|
|
4
4
|
* never resolves the paired symbol: the other language's analyzer decides whether the
|
|
5
5
|
* pairing is a use, and the merge reads the two evaluations together.
|
|
6
6
|
*/
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
7
|
+
import { EDGES_SCHEMA } from "./contract/config.generated.js";
|
|
8
|
+
import { readTargetDocument } from "./fs/document.js";
|
|
9
|
+
import { dotted, placeIn, positionAt, readStrict, StrictJSONError } from "./json-document.js";
|
|
10
10
|
import { positionKey } from "./position.js";
|
|
11
|
+
import { firstRefusal } from "./schema.js";
|
|
11
12
|
import { isPartSubject } from "./suppress.js";
|
|
13
|
+
import { bytewise } from "./text/compare.js";
|
|
14
|
+
import { UsageError } from "./usage.js";
|
|
12
15
|
/** The name and the location the Contract fixes for the edges document. */
|
|
13
16
|
export const EDGES_FILE = "deadset-edges.json";
|
|
14
17
|
/** The language prefix of every reference this analyzer evaluates. */
|
|
15
18
|
const OWN_PREFIX = "ts://";
|
|
16
|
-
/** The closed key list of the document and of one edge. */
|
|
17
|
-
const DOCUMENT_KEYS = new Set(["description", "edges"]);
|
|
18
|
-
const EDGE_KEYS = new Set(["id", "because", "provides", "used_by"]);
|
|
19
|
-
/** An edge identifier: solidus-separated segments of ASCII letters, digits, `_`, `.` and `-`. */
|
|
20
|
-
const ID_FORM = /^[A-Za-z0-9_.-]+(?:\/[A-Za-z0-9_.-]+)*$/u;
|
|
21
|
-
/** A reference naming one symbol of some language: `<language>://<scope>#<fragment>`. */
|
|
22
|
-
const REFERENCE_FORM = /^[a-z][a-z0-9]*:\/\/[^ \t\r\n#]+#[^ \t\r\n]*$/u;
|
|
23
|
-
const DOCUMENT_WANT = "an object carrying the edges array, and an optional description";
|
|
24
|
-
const EDGE_WANT = "an edge naming id, provides and used_by, each a string, and an optional because";
|
|
25
|
-
const ID_WANT = "one or more solidus-separated segments of ASCII letters, digits, underscore, full stop and hyphen";
|
|
26
|
-
const REFERENCE_WANT = "a stable symbol reference naming one symbol exactly, <language>://<scope>#<fragment>";
|
|
27
19
|
/** An edges document the Contract refuses: a malformed input, answered with the usage code. */
|
|
28
|
-
class EdgesError extends
|
|
29
|
-
constructor(at,
|
|
30
|
-
super(
|
|
20
|
+
class EdgesError extends UsageError {
|
|
21
|
+
constructor(at, reason) {
|
|
22
|
+
super(`${at}: ${reason}`);
|
|
31
23
|
this.name = "EdgesError";
|
|
32
24
|
}
|
|
33
25
|
}
|
|
34
|
-
/**
|
|
35
|
-
|
|
36
|
-
* would name a set of symbols rather than one.
|
|
37
|
-
*/
|
|
38
|
-
function carriesWildcard(ref) {
|
|
39
|
-
let quoted = false;
|
|
40
|
-
let computed = false;
|
|
41
|
-
let escaped = false;
|
|
42
|
-
for (const char of ref) {
|
|
43
|
-
if (escaped) {
|
|
44
|
-
escaped = false;
|
|
45
|
-
}
|
|
46
|
-
else if (quoted && char === "\\") {
|
|
47
|
-
escaped = true;
|
|
48
|
-
}
|
|
49
|
-
else if (quoted) {
|
|
50
|
-
quoted = char !== "'";
|
|
51
|
-
}
|
|
52
|
-
else if (computed) {
|
|
53
|
-
computed = char !== "]";
|
|
54
|
-
}
|
|
55
|
-
else if (char === "'") {
|
|
56
|
-
quoted = true;
|
|
57
|
-
}
|
|
58
|
-
else if (char === "[") {
|
|
59
|
-
computed = true;
|
|
60
|
-
}
|
|
61
|
-
else if (char === "*") {
|
|
62
|
-
return true;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
return false;
|
|
66
|
-
}
|
|
67
|
-
function isObject(value) {
|
|
68
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
69
|
-
}
|
|
70
|
-
/** One edge, checked: the closed key list, the value types and the value forms. */
|
|
71
|
-
function readEdge(value, at) {
|
|
72
|
-
const refuse = (text, want) => {
|
|
73
|
-
throw new EdgesError(at, text, want);
|
|
74
|
-
};
|
|
75
|
-
if (!isObject(value)) {
|
|
76
|
-
return refuse(JSON.stringify(value), EDGE_WANT);
|
|
77
|
-
}
|
|
78
|
-
for (const [key, held] of Object.entries(value)) {
|
|
79
|
-
if (!EDGE_KEYS.has(key) || typeof held !== "string") {
|
|
80
|
-
refuse(`the member ${JSON.stringify(key)} holding ${JSON.stringify(held)}`, EDGE_WANT);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
const edge = value;
|
|
84
|
-
const id = edge["id"] ?? refuse("an edge naming no id", EDGE_WANT);
|
|
85
|
-
const provides = edge["provides"] ?? refuse("an edge naming no provides side", EDGE_WANT);
|
|
86
|
-
const usedBy = edge["used_by"] ?? refuse("an edge naming no used_by side", EDGE_WANT);
|
|
87
|
-
if (!ID_FORM.test(id)) {
|
|
88
|
-
refuse(JSON.stringify(id), ID_WANT);
|
|
89
|
-
}
|
|
90
|
-
for (const ref of [provides, usedBy]) {
|
|
91
|
-
if (!REFERENCE_FORM.test(ref) || carriesWildcard(ref)) {
|
|
92
|
-
refuse(JSON.stringify(ref), REFERENCE_WANT);
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
return { id, provides, usedBy };
|
|
96
|
-
}
|
|
26
|
+
/** The sides of one edge, in the order a reader yields them. */
|
|
27
|
+
const SIDE_NAMES = ["provides", "used_by"];
|
|
97
28
|
/**
|
|
98
29
|
* Every side of a declared edge that names a symbol of this language, in document order,
|
|
99
30
|
* `provides` before `used_by` within an edge. An absent document declares no edge. The
|
|
100
|
-
* document is strict JSON
|
|
101
|
-
* {@link EdgesError}.
|
|
31
|
+
* document is strict JSON held to the Contract's edges schema, and a defect in it is an
|
|
32
|
+
* {@link EdgesError} at the line and column of the edge it is in, where it is in one.
|
|
102
33
|
*/
|
|
103
34
|
export function readEdgeSides(host, targetRoot) {
|
|
104
|
-
const
|
|
105
|
-
if (
|
|
35
|
+
const text = readTargetDocument(host, targetRoot, EDGES_FILE);
|
|
36
|
+
if (text === undefined) {
|
|
106
37
|
return [];
|
|
107
38
|
}
|
|
108
|
-
|
|
109
|
-
let parsed;
|
|
39
|
+
let read;
|
|
110
40
|
try {
|
|
111
|
-
|
|
41
|
+
read = readStrict(text, "edges");
|
|
112
42
|
}
|
|
113
43
|
catch (error) {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
throw new EdgesError(EDGES_FILE,
|
|
118
|
-
}
|
|
119
|
-
const walk = walkDocument(text, "edges");
|
|
120
|
-
if (walk.twice !== undefined) {
|
|
121
|
-
throw new EdgesError(positionKey(positionAt(text, EDGES_FILE, walk.twice.offset)), `the member ${JSON.stringify(walk.twice.name)} is written twice, so neither value is chosen`, DOCUMENT_WANT);
|
|
44
|
+
if (!(error instanceof StrictJSONError)) {
|
|
45
|
+
throw error;
|
|
46
|
+
}
|
|
47
|
+
throw new EdgesError(positionKey(positionAt(text, EDGES_FILE, error.offset)), error.message);
|
|
122
48
|
}
|
|
123
|
-
const
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
49
|
+
const value = read.value;
|
|
50
|
+
const refused = firstRefusal(EDGES_SCHEMA, value);
|
|
51
|
+
if (refused !== undefined) {
|
|
52
|
+
const place = placeIn(value, refused.pointer, refused.member);
|
|
53
|
+
const offset = place.length > 1 ? read.starts.get(place[1] ?? "") : undefined;
|
|
54
|
+
const at = offset === undefined ? EDGES_FILE : positionKey(positionAt(text, EDGES_FILE, offset));
|
|
55
|
+
const where = dotted(place);
|
|
56
|
+
throw new EdgesError(at, where === "" ? refused.reason : `${where}: ${refused.reason}`);
|
|
130
57
|
}
|
|
58
|
+
const edges = value.edges;
|
|
131
59
|
const sides = [];
|
|
132
|
-
|
|
133
|
-
const
|
|
134
|
-
const
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
["used_by", edge.usedBy],
|
|
139
|
-
];
|
|
140
|
-
for (const [side, symbol] of named) {
|
|
141
|
-
if (symbol.startsWith(OWN_PREFIX)) {
|
|
142
|
-
sides.push({ edge: edge.id, side, symbol });
|
|
60
|
+
for (const id of read.starts.keys()) {
|
|
61
|
+
const edge = String(id);
|
|
62
|
+
for (const side of SIDE_NAMES) {
|
|
63
|
+
const symbol = edges[edge]?.[side];
|
|
64
|
+
if (symbol?.startsWith(OWN_PREFIX) === true) {
|
|
65
|
+
sides.push({ edge, side, symbol });
|
|
143
66
|
}
|
|
144
67
|
}
|
|
145
|
-
});
|
|
146
|
-
return sides;
|
|
147
|
-
}
|
|
148
|
-
/** Two strings ordered bytewise. */
|
|
149
|
-
function compare(a, b) {
|
|
150
|
-
if (a === b) {
|
|
151
|
-
return 0;
|
|
152
68
|
}
|
|
153
|
-
return
|
|
69
|
+
return sides;
|
|
154
70
|
}
|
|
155
71
|
/**
|
|
156
72
|
* Evaluates every declared side of this language over the run's findings. A side naming a
|
|
@@ -191,6 +107,6 @@ export function evaluateEdges(findings, sides, symbols) {
|
|
|
191
107
|
return { ...side, state: "dead", finding };
|
|
192
108
|
});
|
|
193
109
|
});
|
|
194
|
-
evaluations.sort((a, b) =>
|
|
110
|
+
evaluations.sort((a, b) => bytewise(a.edge, b.edge) || bytewise(a.side, b.side));
|
|
195
111
|
return { findings: findings.filter((_finding, at) => !pending.has(at)), evaluations };
|
|
196
112
|
}
|
|
@@ -5,9 +5,8 @@
|
|
|
5
5
|
* target holds, the members are read at each call, by the type of the argument it passes.
|
|
6
6
|
*/
|
|
7
7
|
import { isArrayLiteralExpression, isArrowFunction, isBinaryExpression, isCallExpression, isElementAccessExpression, isForInStatement, isForOfStatement, isFunctionDeclaration, isFunctionExpression, isIdentifier, isNoSubstitutionTemplateLiteral, isNumericLiteral, isObjectLiteralExpression, isParenthesizedExpression, isPostfixUnaryExpression, isPrefixUnaryExpression, isPropertyAssignment, isShorthandPropertyAssignment, isSpreadAssignment, isSpreadElement, isStringLiteral, isVariableDeclaration, isVariableDeclarationList, isVariableStatement, NodeFlags, SyntaxKind, } from "@typescript/native/ast";
|
|
8
|
-
import { nodeKey } from "./inventory.js";
|
|
9
|
-
import { renderPosition } from "./position.js";
|
|
10
8
|
import { UNANSWERED } from "./query.js";
|
|
9
|
+
import { parenthesesRemoved } from "./unwrap.js";
|
|
11
10
|
/** The assignment operators that read their target before they write it. */
|
|
12
11
|
const COMPOUND = new Set([
|
|
13
12
|
SyntaxKind.PlusEqualsToken,
|
|
@@ -47,12 +46,9 @@ function useOf(node) {
|
|
|
47
46
|
}
|
|
48
47
|
return "read";
|
|
49
48
|
}
|
|
50
|
-
function unwrapped(node) {
|
|
51
|
-
return isParenthesizedExpression(node) ? unwrapped(node.expression) : node;
|
|
52
|
-
}
|
|
53
49
|
/** Whether an index is a literal the checker resolves to a member by its own text. */
|
|
54
50
|
function isLiteralIndex(node) {
|
|
55
|
-
const at =
|
|
51
|
+
const at = parenthesesRemoved(node);
|
|
56
52
|
return isStringLiteral(at) || isNumericLiteral(at) || isNoSubstitutionTemplateLiteral(at);
|
|
57
53
|
}
|
|
58
54
|
/**
|
|
@@ -155,174 +151,191 @@ function assigns(body, name) {
|
|
|
155
151
|
return found;
|
|
156
152
|
}
|
|
157
153
|
/**
|
|
158
|
-
* The
|
|
159
|
-
*
|
|
154
|
+
* The reads the element accesses of a side's files make of the members their index's literal
|
|
155
|
+
* type names, each made by the declaration holding the access or the call. A type the checker
|
|
156
|
+
* leaves unanswered holds what its answer could have read.
|
|
160
157
|
*/
|
|
161
|
-
export
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
if (isElementAccessExpression(node) && !isLiteralIndex(node.argumentExpression)) {
|
|
174
|
-
candidates.push({ file, from: holder, access: node, use: useOf(node) });
|
|
175
|
-
}
|
|
176
|
-
if (isCallExpression(node)) {
|
|
177
|
-
calls.set(node, { file, from: holder });
|
|
178
|
-
}
|
|
179
|
-
if (isIdentifier(node)) {
|
|
180
|
-
names.push(node);
|
|
181
|
-
}
|
|
182
|
-
node.forEachChild((child) => {
|
|
183
|
-
visit(child, holder);
|
|
184
|
-
});
|
|
185
|
-
};
|
|
186
|
-
file.forEachChild((child) => {
|
|
187
|
-
visit(child, fileId);
|
|
188
|
-
});
|
|
189
|
-
}
|
|
190
|
-
if (candidates.length === 0) {
|
|
191
|
-
return [];
|
|
192
|
-
}
|
|
193
|
-
// A parameter index is decided at the calls only where the function is a callable every
|
|
194
|
-
// use of which is a call, so the symbols of the parameters and of every name are read.
|
|
195
|
-
const parameterOf = new Map();
|
|
196
|
-
const byCallable = new Map();
|
|
197
|
-
for (const candidate of candidates) {
|
|
198
|
-
const index = unwrapped(candidate.access.argumentExpression);
|
|
199
|
-
const fn = isIdentifier(index) ? enclosingFunction(candidate.access) : undefined;
|
|
200
|
-
const callable = fn === undefined ? undefined : callableOf(fn);
|
|
201
|
-
if (callable === undefined || !isIdentifier(index)) {
|
|
202
|
-
continue;
|
|
203
|
-
}
|
|
204
|
-
const at = callable.parameters.findIndex((parameter) => isIdentifier(parameter.name) && parameter.name.text === index.text);
|
|
205
|
-
if (at < 0 || assigns(callable.body, index.text)) {
|
|
206
|
-
continue;
|
|
207
|
-
}
|
|
208
|
-
parameterOf.set(candidate, { callable, at });
|
|
209
|
-
byCallable.set(callable.name, [...(byCallable.get(callable.name) ?? []), candidate]);
|
|
210
|
-
}
|
|
211
|
-
const callableNames = [...byCallable.keys()];
|
|
212
|
-
const spelled = new Set(callableNames.map((name) => name.text));
|
|
213
|
-
const sameName = names.filter((name) => spelled.has(name.text));
|
|
214
|
-
const symbols = queries.symbolsAt([...callableNames, ...sameName]);
|
|
215
|
-
const symbolOf = new Map();
|
|
216
|
-
[...callableNames, ...sameName].forEach((node, at) => {
|
|
217
|
-
const symbol = symbols[at];
|
|
218
|
-
if (symbol !== UNANSWERED && symbol !== undefined) {
|
|
219
|
-
symbolOf.set(node, symbol);
|
|
220
|
-
}
|
|
221
|
-
});
|
|
222
|
-
const callsOf = new Map();
|
|
223
|
-
for (const name of callableNames) {
|
|
224
|
-
const symbol = symbolOf.get(name);
|
|
225
|
-
let found = symbol === undefined ? undefined : [];
|
|
226
|
-
for (const use of sameName) {
|
|
227
|
-
if (found === undefined) {
|
|
228
|
-
break;
|
|
229
|
-
}
|
|
230
|
-
if (use === name || symbolOf.get(use) !== symbol) {
|
|
231
|
-
continue;
|
|
232
|
-
}
|
|
233
|
-
const parent = use.parent;
|
|
234
|
-
found =
|
|
235
|
-
isCallExpression(parent) && parent.expression === use ? [...found, parent] : undefined;
|
|
236
|
-
}
|
|
237
|
-
callsOf.set(name, found);
|
|
238
|
-
}
|
|
239
|
-
const lookups = [];
|
|
240
|
-
for (const candidate of candidates) {
|
|
241
|
-
const deferred = parameterOf.get(candidate);
|
|
242
|
-
const sites = deferred === undefined ? undefined : callsOf.get(deferred.callable.name);
|
|
243
|
-
if (deferred === undefined || sites === undefined) {
|
|
244
|
-
lookups.push({
|
|
245
|
-
file: candidate.file,
|
|
246
|
-
from: candidate.from,
|
|
247
|
-
at: candidate.access.argumentExpression,
|
|
248
|
-
object: candidate.access.expression,
|
|
249
|
-
index: candidate.access.argumentExpression,
|
|
250
|
-
use: candidate.use,
|
|
251
|
-
});
|
|
252
|
-
continue;
|
|
253
|
-
}
|
|
254
|
-
// An object that is a parameter too is read as the argument each call passes there.
|
|
255
|
-
const object = unwrapped(candidate.access.expression);
|
|
256
|
-
const objectAt = isIdentifier(object)
|
|
257
|
-
? deferred.callable.parameters.findIndex((parameter) => isIdentifier(parameter.name) && parameter.name.text === object.text)
|
|
258
|
-
: -1;
|
|
259
|
-
for (const call of sites) {
|
|
260
|
-
const parameter = deferred.callable.parameters[deferred.at];
|
|
261
|
-
const index = call.arguments[deferred.at] ?? parameter?.initializer;
|
|
262
|
-
const site = calls.get(call);
|
|
263
|
-
if (index === undefined || site === undefined) {
|
|
264
|
-
continue;
|
|
265
|
-
}
|
|
266
|
-
lookups.push({
|
|
267
|
-
file: site.file,
|
|
268
|
-
from: site.from,
|
|
269
|
-
at: call,
|
|
270
|
-
object: (objectAt < 0 ? undefined : call.arguments[objectAt]) ?? candidate.access.expression,
|
|
271
|
-
index,
|
|
272
|
-
use: candidate.use,
|
|
273
|
-
});
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
const nodes = lookups.flatMap((one) => [one.index, one.object]);
|
|
277
|
-
const types = queries.typesAt(nodes);
|
|
278
|
-
const typeOf = (node, at) => {
|
|
279
|
-
const type = types[at];
|
|
280
|
-
return nodes[at] === node && type !== UNANSWERED ? type : undefined;
|
|
281
|
-
};
|
|
282
|
-
// A type parameter's body serves every instantiation, so it reads what its constraint admits.
|
|
283
|
-
const keysOf = (type) => {
|
|
284
|
-
if (!type.isTypeParameter()) {
|
|
285
|
-
return type;
|
|
286
|
-
}
|
|
287
|
-
const constraint = queries.constraintOf(type);
|
|
288
|
-
return constraint === UNANSWERED || constraint === undefined ? type : constraint;
|
|
289
|
-
};
|
|
290
|
-
const partsOf = (type) => {
|
|
291
|
-
const parts = queries.constituents(type);
|
|
292
|
-
return parts === UNANSWERED ? [type] : parts;
|
|
293
|
-
};
|
|
294
|
-
const found = [];
|
|
295
|
-
lookups.forEach((lookup, at) => {
|
|
296
|
-
const indexType = typeOf(lookup.index, 2 * at);
|
|
297
|
-
const objectType = typeOf(lookup.object, 2 * at + 1);
|
|
298
|
-
const literals = indexType === undefined ? undefined : literalNames(partsOf(keysOf(indexType)));
|
|
299
|
-
if (objectType === undefined || literals === undefined) {
|
|
300
|
-
return;
|
|
301
|
-
}
|
|
302
|
-
const position = renderPosition(lookup.file, root, lookup.at.getStart());
|
|
303
|
-
for (const part of partsOf(objectType)) {
|
|
304
|
-
const properties = queries.propertiesOf(part);
|
|
305
|
-
for (const property of properties === UNANSWERED ? [] : properties) {
|
|
306
|
-
if (!literals.has(property.escapedName)) {
|
|
307
|
-
continue;
|
|
158
|
+
export const elementAccess = {
|
|
159
|
+
start() {
|
|
160
|
+
const candidates = [];
|
|
161
|
+
const calls = new Map();
|
|
162
|
+
const names = [];
|
|
163
|
+
return {
|
|
164
|
+
visit(node, { file, from }) {
|
|
165
|
+
if (isElementAccessExpression(node) && !isLiteralIndex(node.argumentExpression)) {
|
|
166
|
+
candidates.push({ file, from, access: node, use: useOf(node) });
|
|
167
|
+
}
|
|
168
|
+
if (isCallExpression(node)) {
|
|
169
|
+
calls.set(node, { file, from });
|
|
308
170
|
}
|
|
309
|
-
|
|
310
|
-
|
|
171
|
+
if (isIdentifier(node)) {
|
|
172
|
+
names.push(node);
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
reads({ project, chains }) {
|
|
176
|
+
const found = [];
|
|
177
|
+
if (candidates.length === 0) {
|
|
178
|
+
return found;
|
|
179
|
+
}
|
|
180
|
+
const queries = project.queries;
|
|
181
|
+
// A parameter index is decided at the calls only where the function is a callable every
|
|
182
|
+
// use of which is a call, so the symbols of the parameters and of every name are read.
|
|
183
|
+
const parameterOf = new Map();
|
|
184
|
+
const byCallable = new Map();
|
|
185
|
+
for (const candidate of candidates) {
|
|
186
|
+
const index = parenthesesRemoved(candidate.access.argumentExpression);
|
|
187
|
+
const fn = isIdentifier(index) ? enclosingFunction(candidate.access) : undefined;
|
|
188
|
+
const callable = fn === undefined ? undefined : callableOf(fn);
|
|
189
|
+
if (callable === undefined || !isIdentifier(index)) {
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
const at = callable.parameters.findIndex((parameter) => isIdentifier(parameter.name) && parameter.name.text === index.text);
|
|
193
|
+
if (at < 0 || assigns(callable.body, index.text)) {
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
parameterOf.set(candidate, { callable, at });
|
|
197
|
+
byCallable.set(callable.name, [...(byCallable.get(callable.name) ?? []), candidate]);
|
|
198
|
+
}
|
|
199
|
+
const callableNames = [...byCallable.keys()];
|
|
200
|
+
const spelled = new Set(callableNames.map((name) => name.text));
|
|
201
|
+
const sameName = names.filter((name) => spelled.has(name.text));
|
|
202
|
+
const asked = [...callableNames, ...sameName];
|
|
203
|
+
const symbols = queries.symbolsAt(asked);
|
|
204
|
+
const symbolOf = new Map();
|
|
205
|
+
asked.forEach((node, at) => {
|
|
206
|
+
const symbol = symbols[at];
|
|
207
|
+
if (symbol !== undefined) {
|
|
208
|
+
symbolOf.set(node, symbol);
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
const callsOf = new Map();
|
|
212
|
+
for (const name of callableNames) {
|
|
213
|
+
const symbol = symbolOf.get(name);
|
|
214
|
+
let sites = symbol === undefined || symbol === UNANSWERED ? undefined : [];
|
|
215
|
+
for (const use of sameName) {
|
|
216
|
+
if (sites === undefined) {
|
|
217
|
+
break;
|
|
218
|
+
}
|
|
219
|
+
const other = symbolOf.get(use);
|
|
220
|
+
if (use === name || (other !== symbol && other !== UNANSWERED)) {
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
// A use the checker could not resolve may be the function's, read where it is not called.
|
|
224
|
+
const parent = use.parent;
|
|
225
|
+
sites =
|
|
226
|
+
other !== UNANSWERED && isCallExpression(parent) && parent.expression === use
|
|
227
|
+
? [...sites, parent]
|
|
228
|
+
: undefined;
|
|
229
|
+
}
|
|
230
|
+
callsOf.set(name, sites);
|
|
231
|
+
}
|
|
232
|
+
const lookups = [];
|
|
233
|
+
for (const candidate of candidates) {
|
|
234
|
+
const deferred = parameterOf.get(candidate);
|
|
235
|
+
const sites = deferred === undefined ? undefined : callsOf.get(deferred.callable.name);
|
|
236
|
+
if (deferred === undefined || sites === undefined) {
|
|
237
|
+
lookups.push({
|
|
238
|
+
file: candidate.file,
|
|
239
|
+
from: candidate.from,
|
|
240
|
+
at: candidate.access.argumentExpression,
|
|
241
|
+
object: candidate.access.expression,
|
|
242
|
+
index: candidate.access.argumentExpression,
|
|
243
|
+
use: candidate.use,
|
|
244
|
+
});
|
|
245
|
+
continue;
|
|
246
|
+
}
|
|
247
|
+
// An object that is a parameter too is read as the argument each call passes there.
|
|
248
|
+
const object = parenthesesRemoved(candidate.access.expression);
|
|
249
|
+
const objectAt = isIdentifier(object)
|
|
250
|
+
? deferred.callable.parameters.findIndex((parameter) => isIdentifier(parameter.name) && parameter.name.text === object.text)
|
|
251
|
+
: -1;
|
|
252
|
+
for (const call of sites) {
|
|
253
|
+
const parameter = deferred.callable.parameters[deferred.at];
|
|
254
|
+
const index = call.arguments[deferred.at] ?? parameter?.initializer;
|
|
255
|
+
const site = calls.get(call);
|
|
256
|
+
if (index === undefined || site === undefined) {
|
|
257
|
+
continue;
|
|
258
|
+
}
|
|
259
|
+
lookups.push({
|
|
260
|
+
file: site.file,
|
|
261
|
+
from: site.from,
|
|
262
|
+
at: call,
|
|
263
|
+
object: (objectAt < 0 ? undefined : call.arguments[objectAt]) ??
|
|
264
|
+
candidate.access.expression,
|
|
265
|
+
index,
|
|
266
|
+
use: candidate.use,
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
const nodes = lookups.flatMap((one) => [one.index, one.object]);
|
|
271
|
+
const types = queries.typesAt(nodes);
|
|
272
|
+
// A type parameter's body serves every instantiation, so it reads what its constraint admits.
|
|
273
|
+
const keysOf = (type) => {
|
|
274
|
+
if (!type.isTypeParameter()) {
|
|
275
|
+
return type;
|
|
276
|
+
}
|
|
277
|
+
const constraint = queries.constraintOf(type);
|
|
278
|
+
return constraint === UNANSWERED || constraint === undefined ? type : constraint;
|
|
279
|
+
};
|
|
280
|
+
const partsOf = (type) => {
|
|
281
|
+
const parts = queries.constituents(type);
|
|
282
|
+
return parts === UNANSWERED ? [type] : parts;
|
|
283
|
+
};
|
|
284
|
+
lookups.forEach((lookup, at) => {
|
|
285
|
+
const indexType = types[2 * at];
|
|
286
|
+
const objectType = types[2 * at + 1];
|
|
287
|
+
const literals = indexType === undefined || indexType === UNANSWERED
|
|
288
|
+
? undefined
|
|
289
|
+
: literalNames(partsOf(keysOf(indexType)));
|
|
290
|
+
if (indexType === UNANSWERED || objectType === UNANSWERED) {
|
|
311
291
|
found.push({
|
|
292
|
+
kind: "held",
|
|
312
293
|
from: lookup.from,
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
294
|
+
...(literals === undefined ? {} : { names: [...literals] }),
|
|
295
|
+
...(objectType === UNANSWERED || objectType === undefined
|
|
296
|
+
? literals === undefined
|
|
297
|
+
? { members: true }
|
|
298
|
+
: {}
|
|
299
|
+
: { types: partsOf(objectType) }),
|
|
318
300
|
});
|
|
301
|
+
return;
|
|
319
302
|
}
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
303
|
+
if (objectType === undefined || literals === undefined) {
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
for (const part of partsOf(objectType)) {
|
|
307
|
+
const properties = queries.propertiesOf(part);
|
|
308
|
+
if (properties === UNANSWERED) {
|
|
309
|
+
found.push({ kind: "held", from: lookup.from, names: [...literals] });
|
|
310
|
+
continue;
|
|
311
|
+
}
|
|
312
|
+
for (const property of properties) {
|
|
313
|
+
if (!literals.has(property.escapedName)) {
|
|
314
|
+
continue;
|
|
315
|
+
}
|
|
316
|
+
for (const to of chains.declarationsOf(property)) {
|
|
317
|
+
for (const use of lookup.use === "both"
|
|
318
|
+
? ["read", "write"]
|
|
319
|
+
: [lookup.use]) {
|
|
320
|
+
found.push({
|
|
321
|
+
kind: "named",
|
|
322
|
+
from: lookup.from,
|
|
323
|
+
to,
|
|
324
|
+
file: lookup.file,
|
|
325
|
+
at: lookup.at,
|
|
326
|
+
use,
|
|
327
|
+
via: "keyed",
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
});
|
|
334
|
+
return found;
|
|
335
|
+
},
|
|
336
|
+
};
|
|
337
|
+
},
|
|
338
|
+
};
|
|
326
339
|
/** The names a union of literal types spells, or none where a constituent is no string or number literal. */
|
|
327
340
|
function literalNames(parts) {
|
|
328
341
|
const names = new Set();
|