@cplieger/deadset-ts 8.0.0-dev.2 → 8.0.0-dev.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/THIRD_PARTY_NOTICES.md +27 -0
- package/dist/bin/mapper-connection.js +2 -1
- package/dist/bin/node-host.js +24 -5
- package/dist/src/alias-chain.js +2 -7
- package/dist/src/amd.js +81 -0
- package/dist/src/analysis.js +269 -432
- package/dist/src/augmentations.js +64 -3
- package/dist/src/automatic-types.js +10 -29
- package/dist/src/bindings.js +382 -0
- package/dist/src/calls.js +279 -43
- package/dist/src/commands/held.js +499 -0
- package/dist/src/commands/read.js +161 -0
- package/dist/src/commands/shell.js +169 -0
- package/dist/src/commands/tools.js +1847 -0
- package/dist/src/component-files.js +3 -2
- package/dist/src/component-layer.js +4 -2
- package/dist/src/config.js +6 -82
- package/dist/src/conformance-record.js +1 -1
- package/dist/src/consumers.js +10 -38
- package/dist/src/contextual-uses.js +57 -26
- package/dist/src/contract/config.generated.js +561 -0
- package/dist/src/contract/contract.generated.js +1369 -0
- package/dist/src/contract/report.generated.js +866 -0
- package/dist/src/dependencies.js +164 -121
- package/dist/src/destructuring.js +1 -19
- package/dist/src/edges.js +38 -122
- package/dist/src/element-access.js +181 -168
- package/dist/src/entries/build-scripts.js +222 -0
- package/dist/src/{configuration-files.js → entries/configuration-files.js} +52 -256
- package/dist/src/{convention-rows.js → entries/convention-rows.js} +170 -30
- package/dist/src/entries/conventions.js +740 -0
- package/dist/src/{html-entries.js → entries/html-entries.js} +12 -42
- package/dist/src/{mdx-entries.js → entries/mdx-entries.js} +5 -28
- package/dist/src/entries/run-directories.js +77 -0
- package/dist/src/entries/sources.js +144 -0
- package/dist/src/entries/static-module.js +670 -0
- package/dist/src/entries/test-runners.js +650 -0
- package/dist/src/entries/workflow-steps.js +345 -0
- package/dist/src/enum-group.js +3 -10
- package/dist/src/erased-stores.js +4 -6
- package/dist/src/exempt-classes.js +1 -63
- package/dist/src/exempt.js +21 -66
- package/dist/src/exposure.js +400 -0
- package/dist/src/extensions.js +37 -0
- package/dist/src/facts.js +38 -0
- package/dist/src/failure.js +36 -0
- package/dist/src/file-facts.js +3 -26
- package/dist/src/findings/completion.js +109 -56
- package/dist/src/findings/dependencies-and-module-machinery.js +4 -5
- package/dist/src/findings/emitters.js +27 -41
- package/dist/src/{implementations.js → findings/implementations.js} +3 -3
- package/dist/src/{in-operands.js → findings/in-operands.js} +3 -2
- package/dist/src/findings/interfaces.js +4 -5
- package/dist/src/findings/intra-function.js +16 -13
- package/dist/src/findings/non-code-artifacts.js +17 -12
- package/dist/src/findings/reads-and-writes.js +86 -27
- package/dist/src/findings/self-check.js +44 -30
- package/dist/src/findings/unused-declarations.js +29 -45
- package/dist/src/findings/visibility-narrowing.js +23 -31
- package/dist/src/findings-pass.js +13 -21
- package/dist/src/framework-lifecycle.js +46 -19
- package/dist/src/fs/document.js +52 -0
- package/dist/src/fs/manifest.js +67 -0
- package/dist/src/fs/tree.js +88 -0
- package/dist/src/generated-file.js +174 -28
- package/dist/src/git-ignore.js +39 -26
- package/dist/src/import-bindings.js +73 -28
- package/dist/src/index/sites.js +557 -0
- package/dist/src/index.js +2 -2
- package/dist/src/indexed-access.js +523 -478
- package/dist/src/injection-container.js +2 -2
- package/dist/src/interface-satisfaction.js +1 -1
- package/dist/src/intra-function-parts.js +63 -43
- package/dist/src/inventory/commonjs.js +507 -0
- package/dist/src/inventory/enumerate.js +167 -0
- package/dist/src/inventory/syntax.js +236 -0
- package/dist/src/inventory.js +323 -724
- package/dist/src/javascript-file.js +48 -0
- package/dist/src/json-document.js +198 -67
- package/dist/src/keyof-comparisons.js +126 -107
- package/dist/src/kinds.js +3 -366
- package/dist/src/{components.js → liveness/components.js} +2 -3
- package/dist/src/{graph.js → liveness/graph.js} +52 -28
- package/dist/src/liveness/matrix.js +99 -0
- package/dist/src/liveness/sweep.js +558 -0
- package/dist/src/load/classify.js +289 -0
- package/dist/src/load/diagnostics.js +87 -0
- package/dist/src/load/discover.js +285 -0
- package/dist/src/{emit-map.js → load/emit-map.js} +1 -1
- package/dist/src/load/expected-module.js +136 -0
- package/dist/src/load/load.js +27 -0
- package/dist/src/load/module-lookup.js +37 -0
- package/dist/src/load/package-scope.js +56 -0
- package/dist/src/load/plan.js +313 -0
- package/dist/src/load/specifiers.js +113 -0
- package/dist/src/load/synthesize.js +152 -0
- package/dist/src/load/test-globals.js +207 -0
- package/dist/src/load/test-joins.js +82 -0
- package/dist/src/{workspace-manifests.js → load/workspace-manifests.js} +4 -4
- package/dist/src/{workspace-programs.js → load/workspace-programs.js} +89 -66
- package/dist/src/{workspace-resolution.js → load/workspace-resolution.js} +24 -66
- package/dist/src/{workspace-run.js → load/workspace-run.js} +7 -7
- package/dist/src/{workspace.js → load/workspace.js} +62 -124
- package/dist/src/module-declarations.js +70 -85
- package/dist/src/overrides.js +134 -112
- package/dist/src/partial.js +2 -1
- package/dist/src/paths.js +82 -16
- package/dist/src/platform-calls.js +78 -0
- package/dist/src/platform-symbols.js +134 -0
- package/dist/src/position.js +43 -1
- package/dist/src/print.js +11 -79
- package/dist/src/product.js +13 -0
- package/dist/src/query.js +47 -0
- package/dist/src/ref.js +12 -20
- package/dist/src/references/read-rule.js +1 -0
- package/dist/src/references/read-rules.js +48 -0
- package/dist/src/references/sink.js +237 -0
- package/dist/src/references/sources.js +450 -0
- package/dist/src/references.js +117 -1074
- package/dist/src/report-schema.js +51 -0
- package/dist/src/report.js +57 -41
- package/dist/src/reporters/annotations.js +15 -8
- package/dist/src/reporters/sarif.js +16 -10
- package/dist/src/reporters/template.js +4 -19
- package/dist/src/resolve.js +246 -730
- package/dist/src/{configured-declarations.js → roots/configured-declarations.js} +22 -24
- package/dist/src/{entry-point-gaps.js → roots/entry-point-gaps.js} +6 -15
- package/dist/src/roots/manifest.js +216 -0
- package/dist/src/roots/published-reach.js +412 -0
- package/dist/src/roots/root-set.js +487 -0
- package/dist/src/roots/unseen-loads.js +236 -0
- package/dist/src/run.js +66 -77
- package/dist/src/schema.js +320 -343
- package/dist/src/scope.js +38 -115
- package/dist/src/serialization-contract.js +601 -22
- package/dist/src/session.js +37 -29
- package/dist/src/source-files.js +6 -10
- package/dist/src/stores.js +4 -2
- package/dist/src/suppress-file.js +25 -28
- package/dist/src/suppress-inline.js +36 -83
- package/dist/src/suppress.js +50 -71
- package/dist/src/symbol-keys.js +92 -88
- package/dist/src/template-field.js +9 -19
- package/dist/src/tests/file-class.js +76 -0
- package/dist/src/{outside-tests.js → tests/outside.js} +7 -7
- package/dist/src/{test-support.js → tests/support.js} +5 -12
- package/dist/src/text/compare.js +26 -0
- package/dist/src/text/glob.js +194 -0
- package/dist/src/text/named-files.js +298 -0
- package/dist/src/text/yaml.js +684 -0
- package/dist/src/type-errors.js +11 -232
- package/dist/src/type-parameter-reads.js +178 -139
- package/dist/src/unimplemented-callees.js +262 -242
- package/dist/src/unwrap.js +23 -0
- package/dist/src/usage.js +10 -0
- package/dist/src/vendor/unbash/ansi-c.js +132 -0
- package/dist/src/vendor/unbash/arithmetic-parts.js +37 -0
- package/dist/src/vendor/unbash/arithmetic.js +591 -0
- package/dist/src/vendor/unbash/assignment.js +131 -0
- package/dist/src/vendor/unbash/chars.js +48 -0
- package/dist/src/vendor/unbash/command.js +41 -0
- package/dist/src/vendor/unbash/expansion.js +80 -0
- package/dist/src/vendor/unbash/glob.js +268 -0
- package/dist/src/vendor/unbash/heredoc.js +27 -0
- package/dist/src/vendor/unbash/internal-types.js +1 -0
- package/dist/src/vendor/unbash/lexer.js +4274 -0
- package/dist/src/vendor/unbash/limits.js +3 -0
- package/dist/src/vendor/unbash/parser.js +1366 -0
- package/dist/src/vendor/unbash/parts.js +57 -0
- package/dist/src/vendor/unbash/substitution-context.js +8 -0
- package/dist/src/vendor/unbash/traversal.js +212 -0
- package/dist/src/vendor/unbash/types.js +1 -0
- package/dist/src/vendor/unbash/word-value.js +61 -0
- package/dist/src/vendor/unbash/word.js +40 -0
- package/dist/src/verbs/analyze.js +194 -127
- package/dist/src/verbs/describe.js +13 -18
- package/dist/src/verbs/explain.js +85 -139
- package/dist/src/verbs/print-config.js +2 -1
- package/dist/src/verbs/print-projects.js +6 -4
- package/dist/src/verbs/print-retained.js +7 -5
- package/dist/src/verbs/print-roots.js +4 -2
- package/dist/src/verbs/verb.js +1 -5
- package/dist/src/verbs/version.js +14 -3
- package/jsr.json +2 -1
- package/package.json +14 -8
- package/src/alias-chain.ts +2 -9
- package/src/amd.ts +130 -0
- package/src/analysis.ts +424 -650
- package/src/augmentations.ts +93 -4
- package/src/automatic-types.ts +12 -30
- package/src/bindings.ts +460 -0
- package/src/calls.ts +338 -46
- package/src/commands/held.ts +632 -0
- package/src/commands/read.ts +242 -0
- package/src/commands/shell.ts +228 -0
- package/src/commands/tools.ts +2382 -0
- package/src/component-files.ts +4 -2
- package/src/component-layer.ts +4 -2
- package/src/config.ts +31 -302
- package/src/conformance-record.ts +1 -1
- package/src/consumers.ts +16 -66
- package/src/contextual-uses.ts +66 -34
- package/src/contract/config.generated.ts +821 -0
- package/src/contract/contract.generated.ts +1452 -0
- package/src/contract/report.generated.ts +1241 -0
- package/src/dependencies.ts +222 -127
- package/src/destructuring.ts +1 -31
- package/src/edges.ts +41 -140
- package/src/element-access.ts +190 -187
- package/src/entries/build-scripts.ts +292 -0
- package/src/{configuration-files.ts → entries/configuration-files.ts} +68 -278
- package/src/{convention-rows.ts → entries/convention-rows.ts} +227 -31
- package/src/{conventions.ts → entries/conventions.ts} +367 -583
- package/src/{html-entries.ts → entries/html-entries.ts} +22 -48
- package/src/{mdx-entries.ts → entries/mdx-entries.ts} +7 -30
- package/src/entries/run-directories.ts +108 -0
- package/src/entries/sources.ts +266 -0
- package/src/entries/static-module.ts +858 -0
- package/src/entries/test-runners.ts +835 -0
- package/src/entries/workflow-steps.ts +432 -0
- package/src/enum-group.ts +2 -11
- package/src/erased-stores.ts +3 -7
- package/src/exempt-classes.ts +1 -75
- package/src/exempt.ts +70 -98
- package/src/exposure.ts +492 -0
- package/src/extensions.ts +45 -0
- package/src/facts.ts +46 -0
- package/src/failure.ts +63 -0
- package/src/file-facts.ts +15 -25
- package/src/finding.ts +10 -10
- package/src/findings/boundary.ts +11 -0
- package/src/findings/completion.ts +133 -64
- package/src/findings/dependencies-and-module-machinery.ts +4 -7
- package/src/findings/emitter.ts +9 -10
- package/src/findings/emitters.ts +38 -52
- package/src/{implementations.ts → findings/implementations.ts} +4 -4
- package/src/{in-operands.ts → findings/in-operands.ts} +4 -3
- package/src/findings/interfaces.ts +7 -9
- package/src/findings/intra-function.ts +16 -14
- package/src/findings/non-code-artifacts.ts +24 -15
- package/src/findings/reads-and-writes.ts +118 -41
- package/src/findings/self-check.ts +51 -38
- package/src/findings/unused-declarations.ts +31 -49
- package/src/findings/visibility-narrowing.ts +36 -40
- package/src/findings-pass.ts +15 -31
- package/src/framework-lifecycle.ts +47 -19
- package/src/fs/document.ts +70 -0
- package/src/fs/manifest.ts +96 -0
- package/src/fs/tree.ts +110 -0
- package/src/generated-file.ts +242 -35
- package/src/git-ignore.ts +50 -26
- package/src/host.ts +12 -5
- package/src/import-bindings.ts +98 -29
- package/src/index/sites.ts +781 -0
- package/src/index.ts +2 -2
- package/src/indexed-access.ts +570 -527
- package/src/injection-container.ts +2 -2
- package/src/interface-satisfaction.ts +2 -2
- package/src/intra-function-parts.ts +73 -44
- package/src/inventory/commonjs.ts +696 -0
- package/src/inventory/enumerate.ts +203 -0
- package/src/inventory/syntax.ts +311 -0
- package/src/inventory.ts +442 -895
- package/src/javascript-file.ts +54 -0
- package/src/json-document.ts +241 -76
- package/src/keyof-comparisons.ts +133 -122
- package/src/kinds.ts +5 -413
- package/src/{components.ts → liveness/components.ts} +4 -6
- package/src/{graph.ts → liveness/graph.ts} +100 -35
- package/src/liveness/matrix.ts +162 -0
- package/src/liveness/sweep.ts +855 -0
- package/src/load/classify.ts +433 -0
- package/src/load/diagnostics.ts +154 -0
- package/src/load/discover.ts +471 -0
- package/src/{emit-map.ts → load/emit-map.ts} +1 -1
- package/src/load/expected-module.ts +194 -0
- package/src/load/load.ts +73 -0
- package/src/load/module-lookup.ts +50 -0
- package/src/load/package-scope.ts +74 -0
- package/src/load/plan.ts +513 -0
- package/src/load/specifiers.ts +171 -0
- package/src/load/synthesize.ts +230 -0
- package/src/load/test-globals.ts +251 -0
- package/src/load/test-joins.ts +98 -0
- package/src/{workspace-manifests.ts → load/workspace-manifests.ts} +5 -5
- package/src/{workspace-programs.ts → load/workspace-programs.ts} +128 -85
- package/src/{workspace-resolution.ts → load/workspace-resolution.ts} +41 -77
- package/src/{workspace-run.ts → load/workspace-run.ts} +18 -16
- package/src/{workspace.ts → load/workspace.ts} +90 -134
- package/src/module-declarations.ts +74 -98
- package/src/overrides.ts +162 -134
- package/src/partial.ts +3 -2
- package/src/paths.ts +92 -16
- package/src/platform-calls.ts +119 -0
- package/src/platform-symbols.ts +189 -0
- package/src/position.ts +44 -1
- package/src/print.ts +12 -92
- package/src/product.ts +18 -0
- package/src/query.ts +92 -0
- package/src/ref.ts +12 -20
- package/src/references/read-rule.ts +60 -0
- package/src/references/read-rules.ts +55 -0
- package/src/references/sink.ts +314 -0
- package/src/references/sources.ts +632 -0
- package/src/references.ts +187 -1450
- package/src/report-schema.ts +68 -0
- package/src/report.ts +103 -226
- package/src/reporters/annotations.ts +22 -11
- package/src/reporters/json.ts +1 -1
- package/src/reporters/reporter.ts +2 -4
- package/src/reporters/reporters.ts +1 -1
- package/src/reporters/sarif.ts +29 -16
- package/src/reporters/template.ts +4 -20
- package/src/reporters/text.ts +3 -3
- package/src/resolve.ts +284 -1115
- package/src/{configured-declarations.ts → roots/configured-declarations.ts} +27 -29
- package/src/{entry-point-gaps.ts → roots/entry-point-gaps.ts} +7 -16
- package/src/roots/manifest.ts +303 -0
- package/src/roots/published-reach.ts +486 -0
- package/src/{roots.ts → roots/root-set.ts} +286 -469
- package/src/roots/unseen-loads.ts +345 -0
- package/src/run.ts +75 -91
- package/src/schema.ts +391 -388
- package/src/scope.ts +46 -138
- package/src/serialization-contract.ts +769 -23
- package/src/session.ts +87 -55
- package/src/source-files.ts +6 -11
- package/src/stores.ts +15 -3
- package/src/suppress-file.ts +24 -33
- package/src/suppress-inline.ts +55 -91
- package/src/suppress.ts +78 -79
- package/src/symbol-keys.ts +104 -107
- package/src/template-field.ts +15 -25
- package/src/tests/file-class.ts +135 -0
- package/src/{outside-tests.ts → tests/outside.ts} +16 -10
- package/src/{test-support.ts → tests/support.ts} +15 -21
- package/src/text/compare.ts +27 -0
- package/src/text/glob.ts +210 -0
- package/src/text/named-files.ts +388 -0
- package/src/text/yaml.ts +747 -0
- package/src/type-errors.ts +18 -288
- package/src/type-parameter-reads.ts +187 -158
- package/src/unimplemented-callees.ts +297 -280
- package/src/unwrap.ts +34 -0
- package/src/usage.ts +10 -0
- package/src/vendor/unbash/LICENSE +15 -0
- package/src/vendor/unbash/VENDORED.md +16 -0
- package/src/vendor/unbash/ansi-c.ts +132 -0
- package/src/vendor/unbash/arithmetic-parts.ts +53 -0
- package/src/vendor/unbash/arithmetic.ts +641 -0
- package/src/vendor/unbash/assignment.ts +163 -0
- package/src/vendor/unbash/chars.ts +48 -0
- package/src/vendor/unbash/command.ts +47 -0
- package/src/vendor/unbash/expansion.ts +144 -0
- package/src/vendor/unbash/glob.ts +284 -0
- package/src/vendor/unbash/heredoc.ts +34 -0
- package/src/vendor/unbash/internal-types.ts +94 -0
- package/src/vendor/unbash/lexer.ts +4352 -0
- package/src/vendor/unbash/limits.ts +3 -0
- package/src/vendor/unbash/parser.ts +1612 -0
- package/src/vendor/unbash/parts.ts +96 -0
- package/src/vendor/unbash/substitution-context.ts +20 -0
- package/src/vendor/unbash/traversal.ts +182 -0
- package/src/vendor/unbash/types.ts +660 -0
- package/src/vendor/unbash/word-value.ts +64 -0
- package/src/vendor/unbash/word.ts +50 -0
- package/src/verbs/analyze.ts +255 -164
- package/src/verbs/describe.ts +19 -17
- package/src/verbs/explain.ts +93 -169
- package/src/verbs/print-config.ts +2 -1
- package/src/verbs/print-projects.ts +6 -4
- package/src/verbs/print-retained.ts +7 -5
- package/src/verbs/print-roots.ts +4 -2
- package/src/verbs/verb.ts +2 -8
- package/src/verbs/version.ts +15 -3
- package/dist/src/base-url.js +0 -18
- package/dist/src/conventions.js +0 -937
- package/dist/src/discover.js +0 -468
- package/dist/src/entry-points.js +0 -529
- package/dist/src/glob.js +0 -65
- package/dist/src/manifest.js +0 -165
- package/dist/src/matrix.js +0 -246
- package/dist/src/pnpm-workspace.js +0 -120
- package/dist/src/roots.js +0 -672
- package/dist/src/setup-failure.js +0 -23
- package/dist/src/sweep.js +0 -224
- package/dist/src/test-joins.js +0 -101
- package/dist/src/version.js +0 -7
- package/dist/src/workflow-steps.js +0 -185
- package/src/base-url.ts +0 -24
- package/src/discover.ts +0 -653
- package/src/entry-points.ts +0 -687
- package/src/glob.ts +0 -67
- package/src/manifest.ts +0 -234
- package/src/matrix.ts +0 -423
- package/src/pnpm-workspace.ts +0 -135
- package/src/setup-failure.ts +0 -39
- package/src/sweep.ts +0 -347
- package/src/test-joins.ts +0 -120
- package/src/version.ts +0 -7
- package/src/workflow-steps.ts +0 -216
|
@@ -3,27 +3,20 @@
|
|
|
3
3
|
* applied and the declared edges evaluated, and the stale suppressions, the totals and the
|
|
4
4
|
* verdict a report carries beside them.
|
|
5
5
|
*/
|
|
6
|
+
import { EXIT_CLEAN, EXIT_FINDINGS, EXIT_PENDING } from "./contract/contract.generated.js";
|
|
6
7
|
import { fails } from "./config.js";
|
|
7
8
|
import { decidedFindings } from "./findings/emitters.js";
|
|
8
9
|
import { fileRefsOf, staleSuppressions, } from "./findings/self-check.js";
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
export const EXIT_PENDING = 4;
|
|
13
|
-
/** Two strings ordered bytewise. */
|
|
14
|
-
function compare(a, b) {
|
|
15
|
-
if (a === b) {
|
|
16
|
-
return 0;
|
|
17
|
-
}
|
|
18
|
-
return a < b ? -1 : 1;
|
|
19
|
-
}
|
|
10
|
+
import { namesKind, pairs, suppressionCounts } from "./suppress.js";
|
|
11
|
+
import { bytewise } from "./text/compare.js";
|
|
12
|
+
import { PRODUCT } from "./product.js";
|
|
20
13
|
/** The canonical order: path, line, column, code, then the symbol reference. */
|
|
21
14
|
function canonical(a, b) {
|
|
22
|
-
return (
|
|
15
|
+
return (bytewise(a.position.path, b.position.path) ||
|
|
23
16
|
a.position.line - b.position.line ||
|
|
24
17
|
a.position.column - b.position.column ||
|
|
25
|
-
|
|
26
|
-
|
|
18
|
+
bytewise(a.code, b.code) ||
|
|
19
|
+
bytewise(a.symbol.ref, b.symbol.ref));
|
|
27
20
|
}
|
|
28
21
|
/**
|
|
29
22
|
* The pass over one run. The emitter table decides every record against every finding the
|
|
@@ -73,20 +66,19 @@ export function verdictOf(result, config) {
|
|
|
73
66
|
if (result.totals.staleSuppressions > 0) {
|
|
74
67
|
return EXIT_FINDINGS;
|
|
75
68
|
}
|
|
76
|
-
const failing = result.findings.some((finding) => fails(finding.severity, config.reporters.
|
|
69
|
+
const failing = result.findings.some((finding) => fails(finding.severity, config.reporters.fail_on));
|
|
77
70
|
return failing ? EXIT_FINDINGS : EXIT_CLEAN;
|
|
78
71
|
}
|
|
79
72
|
/**
|
|
80
73
|
* The rows one round of a baseline write records from its findings, in their order. A
|
|
81
|
-
* finding
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
* once.
|
|
74
|
+
* finding no baseline row can name is not recorded: a row recording it would be stale on
|
|
75
|
+
* the first read back. Two findings that would record the same row, two parts of one
|
|
76
|
+
* declaration under one code, record it once.
|
|
85
77
|
*/
|
|
86
78
|
export function recordedFindings(findings) {
|
|
87
79
|
const rows = new Map();
|
|
88
80
|
for (const finding of findings) {
|
|
89
|
-
if (
|
|
81
|
+
if (!namesKind(finding.symbol.kind, "baseline")) {
|
|
90
82
|
continue;
|
|
91
83
|
}
|
|
92
84
|
const row = { code: finding.code, symbol: finding.symbol.ref, path: finding.position.path };
|
|
@@ -100,5 +92,5 @@ export function rowKey(row) {
|
|
|
100
92
|
}
|
|
101
93
|
/** The analyzer identity a baseline this analyzer writes names as its rows' provenance. */
|
|
102
94
|
export function analyzerProvenance(version) {
|
|
103
|
-
return { analyzer:
|
|
95
|
+
return { analyzer: PRODUCT, version };
|
|
104
96
|
}
|
|
@@ -1,23 +1,47 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The framework-lifecycle class: a member a
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* through a chain, a class its `bases` name.
|
|
6
|
-
*
|
|
2
|
+
* The framework-lifecycle class: a member a lifecycle contract lists is held back on each
|
|
3
|
+
* class that is the contract's component, being a class a decorator or a call the
|
|
4
|
+
* contract's `components` name is attached to or passes, or one extending, directly or
|
|
5
|
+
* through a chain, a class its `bases` name. The contracts are the platform's custom
|
|
6
|
+
* elements and each `ts.lifecycle_contracts` entry. A component's members are its type's,
|
|
7
|
+
* so a member a base class declares answers for every subclass.
|
|
7
8
|
*/
|
|
8
9
|
import { isClassDeclaration, isClassExpression, isHeritageClause, SyntaxKind, } from "@typescript/native/ast";
|
|
9
10
|
import { aliasChains } from "./alias-chain.js";
|
|
10
11
|
import { calleeName, callsOf, classesPassed, decoratedClasses, decoratorCallee } from "./calls.js";
|
|
11
12
|
import { classMembers, memberComponent, typesAt } from "./class-members.js";
|
|
12
|
-
import { entriesAt, names, namesADeclaration, resolveEntries, spelledEntry, } from "./configured-declarations.js";
|
|
13
|
+
import { entriesAt, names, namesADeclaration, resolveEntries, spelledEntry, } from "./roots/configured-declarations.js";
|
|
13
14
|
import { nodeKey } from "./inventory.js";
|
|
14
15
|
import { renderPosition } from "./position.js";
|
|
15
16
|
import { must } from "./query.js";
|
|
17
|
+
/**
|
|
18
|
+
* The platform's own contract (references-ts.38): `CustomElementRegistry.define` reads
|
|
19
|
+
* these members off the class it registers, its constructor's and its prototype's
|
|
20
|
+
* (https://html.spec.whatwg.org/multipage/custom-elements.html#dom-customelementregistry-define),
|
|
21
|
+
* and calls each callback as a custom element reaction.
|
|
22
|
+
*/
|
|
23
|
+
const CUSTOM_ELEMENTS = {
|
|
24
|
+
components: [{ global: "CustomElementRegistry.define" }],
|
|
25
|
+
members: [
|
|
26
|
+
"observedAttributes:static",
|
|
27
|
+
"disabledFeatures:static",
|
|
28
|
+
"formAssociated:static",
|
|
29
|
+
"connectedCallback",
|
|
30
|
+
"disconnectedCallback",
|
|
31
|
+
"connectedMoveCallback",
|
|
32
|
+
"adoptedCallback",
|
|
33
|
+
"attributeChangedCallback",
|
|
34
|
+
"formAssociatedCallback",
|
|
35
|
+
"formResetCallback",
|
|
36
|
+
"formDisabledCallback",
|
|
37
|
+
"formStateRestoreCallback",
|
|
38
|
+
],
|
|
39
|
+
};
|
|
16
40
|
/** Every contract's components and bases, resolved in one pass over the entries. */
|
|
17
41
|
function resolveContracts(project, held, contracts) {
|
|
18
42
|
const entries = contracts.flatMap((contract) => [
|
|
19
|
-
...contract.components,
|
|
20
|
-
...contract.bases,
|
|
43
|
+
...(contract.components ?? []),
|
|
44
|
+
...(contract.bases ?? []),
|
|
21
45
|
]);
|
|
22
46
|
const resolved = resolveEntries(project, held, entries);
|
|
23
47
|
let next = 0;
|
|
@@ -28,8 +52,8 @@ function resolveContracts(project, held, contracts) {
|
|
|
28
52
|
};
|
|
29
53
|
return contracts.map((contract) => ({
|
|
30
54
|
contract,
|
|
31
|
-
components: take(contract.components
|
|
32
|
-
bases: take(contract.bases
|
|
55
|
+
components: take(contract.components?.length ?? 0),
|
|
56
|
+
bases: take(contract.bases?.length ?? 0),
|
|
33
57
|
}));
|
|
34
58
|
}
|
|
35
59
|
/** The classes a decorator or a call the contracts' components name makes a component. */
|
|
@@ -155,16 +179,17 @@ function byBases(project, held, chains, contracts) {
|
|
|
155
179
|
}
|
|
156
180
|
/**
|
|
157
181
|
* The framework-lifecycle detector: each member a contract lists, on each class that
|
|
158
|
-
* is a component of that contract's framework, recorded where the class
|
|
159
|
-
* be one.
|
|
182
|
+
* is a component of that contract's framework, recorded once per place where the class
|
|
183
|
+
* was found to be one.
|
|
160
184
|
*/
|
|
161
185
|
export function frameworkLifecycle(input) {
|
|
162
186
|
const { project, held, targetRoot } = input;
|
|
163
|
-
|
|
187
|
+
const declared = [CUSTOM_ELEMENTS, ...input.ts.lifecycle_contracts];
|
|
188
|
+
const contracts = resolveContracts(project, held, declared);
|
|
189
|
+
if (contracts.every((one) => one.components.length === 0 && one.bases.length === 0)) {
|
|
164
190
|
return [];
|
|
165
191
|
}
|
|
166
192
|
const chains = aliasChains(project, held);
|
|
167
|
-
const contracts = resolveContracts(project, held, input.ts.lifecycleContracts);
|
|
168
193
|
const components = [
|
|
169
194
|
...byComponents(project, held, chains, contracts),
|
|
170
195
|
...byBases(project, held, chains, contracts),
|
|
@@ -173,22 +198,24 @@ export function frameworkLifecycle(input) {
|
|
|
173
198
|
return [];
|
|
174
199
|
}
|
|
175
200
|
const ids = new Set(components.map((one) => one.id));
|
|
176
|
-
const sides =
|
|
201
|
+
const sides = declared.some((contract) => contract.members.some((name) => name.endsWith(":static")))
|
|
177
202
|
? ["instance", "static"]
|
|
178
203
|
: ["instance"];
|
|
179
204
|
const members = sides.map((side) => classMembers(project, held, ids, side));
|
|
180
205
|
const byId = new Map(held.symbols.map((symbol) => [symbol.id, symbol]));
|
|
181
|
-
const found =
|
|
206
|
+
const found = new Map();
|
|
182
207
|
for (const component of components) {
|
|
183
208
|
const listed = new Set(component.contract.members);
|
|
184
209
|
const site = renderPosition(component.site.getSourceFile(), targetRoot, component.site.getStart());
|
|
185
210
|
for (const member of members.flatMap((side) => side.get(component.id) ?? [])) {
|
|
186
211
|
const symbol = byId.get(member.id);
|
|
187
212
|
const spelled = symbol === undefined ? undefined : memberComponent(symbol, byId);
|
|
188
|
-
|
|
189
|
-
|
|
213
|
+
// A configured contract may name the platform's registry too; one record answers both.
|
|
214
|
+
const key = `${member.id}\0${component.detail}\0${site.path}:${String(site.line)}:${String(site.column)}`;
|
|
215
|
+
if (spelled !== undefined && listed.has(spelled) && !found.has(key)) {
|
|
216
|
+
found.set(key, { id: member.id, detail: component.detail, site });
|
|
190
217
|
}
|
|
191
218
|
}
|
|
192
219
|
}
|
|
193
|
-
return found;
|
|
220
|
+
return [...found.values()];
|
|
194
221
|
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one read of a document the target holds at its root, which a checkout under analysis
|
|
3
|
+
* controls: the repository configuration, the ignore file, the baseline and the edges
|
|
4
|
+
* document. The read stays inside the target root, takes a regular file alone, and holds no
|
|
5
|
+
* more of it than the Contract's document bound.
|
|
6
|
+
*/
|
|
7
|
+
import { CONFIG_MAX_BYTES } from "../contract/config.generated.js";
|
|
8
|
+
import { failureExit } from "../failure.js";
|
|
9
|
+
import { joinPath, relativePath } from "../paths.js";
|
|
10
|
+
import { message } from "../product.js";
|
|
11
|
+
import { utf8Bytes } from "../reporters/sha256.js";
|
|
12
|
+
import { UsageError } from "../usage.js";
|
|
13
|
+
function unreadable(label, reason) {
|
|
14
|
+
return failureExit("unreadable-document", `${label}: ${reason}: make it a regular file inside the target root that the run can read, or remove it`);
|
|
15
|
+
}
|
|
16
|
+
/** Refuses a document past the Contract's bound with the usage code, naming it `label`. */
|
|
17
|
+
export function refuseOverBound(label, text) {
|
|
18
|
+
if (utf8Bytes(text).length > CONFIG_MAX_BYTES) {
|
|
19
|
+
throw new UsageError(`${label}: holds more than ${String(CONFIG_MAX_BYTES)} bytes`);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* The text of the document `name` at the absolute `targetRoot`, undefined where nothing is
|
|
24
|
+
* there. One whose name resolves outside the target root or to anything but a regular file,
|
|
25
|
+
* or whose read fails, is refused by `refuse` naming it `label`, nothing read from it. A
|
|
26
|
+
* document past the bound is read one byte past it and refused as {@link refuseOverBound} does.
|
|
27
|
+
*/
|
|
28
|
+
export function readTargetDocument(host, targetRoot, name, label = name, refuse = unreadable) {
|
|
29
|
+
const attempt = (read) => {
|
|
30
|
+
try {
|
|
31
|
+
return read();
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
throw refuse(label, message(error));
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
const path = joinPath(targetRoot, name);
|
|
38
|
+
const kind = attempt(() => host.kindOf(path));
|
|
39
|
+
if (kind === "absent") {
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
42
|
+
const real = attempt(() => host.realPath(path));
|
|
43
|
+
if (relativePath(attempt(() => host.realPath(targetRoot)), real) === undefined) {
|
|
44
|
+
throw refuse(label, `resolves to ${real}, outside the target root`);
|
|
45
|
+
}
|
|
46
|
+
if (kind !== "file") {
|
|
47
|
+
throw refuse(label, "is not a regular file");
|
|
48
|
+
}
|
|
49
|
+
const text = attempt(() => host.readFile(real, CONFIG_MAX_BYTES + 1));
|
|
50
|
+
refuseOverBound(label, text);
|
|
51
|
+
return text;
|
|
52
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { isRecord } from "../json-document.js";
|
|
2
|
+
import { joinPath } from "../paths.js";
|
|
3
|
+
import { message } from "../product.js";
|
|
4
|
+
/** The file a package's manifest is read from. */
|
|
5
|
+
export const MANIFEST = "package.json";
|
|
6
|
+
/** The directory a package manager installs packages into, whose files are no project's own. */
|
|
7
|
+
export const INSTALLED_PACKAGES = "node_modules";
|
|
8
|
+
/** The manifest members a package declares the packages it depends on under. */
|
|
9
|
+
export const DEPENDENCY_SECTIONS = [
|
|
10
|
+
"dependencies",
|
|
11
|
+
"devDependencies",
|
|
12
|
+
"peerDependencies",
|
|
13
|
+
"optionalDependencies",
|
|
14
|
+
];
|
|
15
|
+
/** Whether one path passes through an installed-packages directory. */
|
|
16
|
+
export function inInstalledPackages(path) {
|
|
17
|
+
return path.split("/").includes(INSTALLED_PACKAGES);
|
|
18
|
+
}
|
|
19
|
+
/** One JSON file, read and parsed, as {@link JSONRead} tells its states apart. */
|
|
20
|
+
export function readJSONFile(host, path) {
|
|
21
|
+
let text;
|
|
22
|
+
try {
|
|
23
|
+
text = host.readFile(path);
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
return { kind: "unread", reason: message(error) };
|
|
27
|
+
}
|
|
28
|
+
try {
|
|
29
|
+
return { kind: "read", text, value: JSON.parse(text) };
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return { kind: "malformed" };
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/** One JSON file's text and decoded value, or undefined where it cannot be read or parsed. */
|
|
36
|
+
export function readDocument(host, path) {
|
|
37
|
+
const read = readJSONFile(host, path);
|
|
38
|
+
return read.kind === "read" ? { text: read.text, value: read.value } : undefined;
|
|
39
|
+
}
|
|
40
|
+
/** One JSON file's decoded value, or undefined where it cannot be read or parsed. */
|
|
41
|
+
export function readJSON(host, path) {
|
|
42
|
+
return readDocument(host, path)?.value;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* The manifest in one directory, decoded, or undefined where none reads as an object. A
|
|
46
|
+
* manifest this program cannot read declares nothing, the same answer as an absent one:
|
|
47
|
+
* the package manager owns the refusal of a manifest it rejects.
|
|
48
|
+
*/
|
|
49
|
+
export function manifestAt(host, dir) {
|
|
50
|
+
const value = readJSON(host, joinPath(dir, MANIFEST));
|
|
51
|
+
return isRecord(value) ? value : undefined;
|
|
52
|
+
}
|
|
53
|
+
/** The manifest in one directory, as {@link ManifestRead} tells its states apart. */
|
|
54
|
+
export function readManifestAt(host, dir) {
|
|
55
|
+
if (!holdsManifest(host, dir)) {
|
|
56
|
+
return { kind: "absent" };
|
|
57
|
+
}
|
|
58
|
+
const read = readJSONFile(host, joinPath(dir, MANIFEST));
|
|
59
|
+
if (read.kind !== "read") {
|
|
60
|
+
return read;
|
|
61
|
+
}
|
|
62
|
+
return isRecord(read.value) ? { kind: "read", manifest: read.value } : { kind: "malformed" };
|
|
63
|
+
}
|
|
64
|
+
/** Whether one directory holds a manifest file. */
|
|
65
|
+
export function holdsManifest(host, dir) {
|
|
66
|
+
return host.kindOf(joinPath(dir, MANIFEST)) === "file";
|
|
67
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { ancestors, joinPath, resolvePath } from "../paths.js";
|
|
2
|
+
import { LANGUAGE_ROWS } from "../contract/contract.generated.js";
|
|
3
|
+
import { LANGUAGE } from "../product.js";
|
|
4
|
+
import { bytewise } from "../text/compare.js";
|
|
5
|
+
import { globExpression } from "../text/glob.js";
|
|
6
|
+
/** The directories no walk of the tree enters, by the patterns the language's row names. */
|
|
7
|
+
const SKIPPED_DIRECTORIES = LANGUAGE_ROWS[LANGUAGE].skippedDirectories.map(globExpression);
|
|
8
|
+
function skipped(name) {
|
|
9
|
+
return SKIPPED_DIRECTORIES.some((pattern) => pattern.test(name));
|
|
10
|
+
}
|
|
11
|
+
/** One file's text without its line ending, or undefined where it cannot be read. */
|
|
12
|
+
function lineOf(host, path) {
|
|
13
|
+
try {
|
|
14
|
+
return host.readFile(path).replace(/\r?\n$/u, "");
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* The repository whose working tree holds `dir`: the nearest directory at or above it with a
|
|
22
|
+
* `.git`. A `.git` file, which a linked worktree or a submodule holds, names the repository's
|
|
23
|
+
* directory on its `gitdir:` line; that directory's `commondir` file, where it has one, names
|
|
24
|
+
* the directory shared with the main worktree, which holds `info/exclude`:
|
|
25
|
+
* https://git-scm.com/docs/gitrepository-layout
|
|
26
|
+
*/
|
|
27
|
+
export function repositoryOf(host, dir) {
|
|
28
|
+
for (const root of ancestors(dir)) {
|
|
29
|
+
const dotGit = joinPath(root, ".git");
|
|
30
|
+
const kind = host.kindOf(dotGit);
|
|
31
|
+
if (kind === "directory") {
|
|
32
|
+
return { root, exclude: joinPath(dotGit, "info/exclude") };
|
|
33
|
+
}
|
|
34
|
+
if (kind === "file") {
|
|
35
|
+
const named = /^gitdir: (.+)$/u.exec(lineOf(host, dotGit) ?? "")?.[1];
|
|
36
|
+
const gitDir = named === undefined ? undefined : resolvePath(root, named);
|
|
37
|
+
const common = gitDir === undefined ? undefined : lineOf(host, joinPath(gitDir, "commondir"));
|
|
38
|
+
const shared = gitDir === undefined || common === undefined ? gitDir : resolvePath(gitDir, common);
|
|
39
|
+
return { root, exclude: shared === undefined ? undefined : joinPath(shared, "info/exclude") };
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
/** The entries of one directory, none where it cannot be read. */
|
|
45
|
+
export function entriesOf(host, dir) {
|
|
46
|
+
try {
|
|
47
|
+
return host.readDirectory(dir);
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return [];
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/** The names of the files directly in `dir` whose name `accepts`, in bytewise order. */
|
|
54
|
+
export function filesIn(host, dir, accepts) {
|
|
55
|
+
return entriesOf(host, dir)
|
|
56
|
+
.filter((entry) => !entry.directory && accepts(entry.name))
|
|
57
|
+
.map((entry) => entry.name)
|
|
58
|
+
.sort(bytewise);
|
|
59
|
+
}
|
|
60
|
+
/** The names of the directories directly in `dir` a walk enters, in bytewise order. */
|
|
61
|
+
export function directoriesIn(host, dir) {
|
|
62
|
+
return entriesOf(host, dir)
|
|
63
|
+
.filter((entry) => entry.directory && !skipped(entry.name))
|
|
64
|
+
.map((entry) => entry.name)
|
|
65
|
+
.sort(bytewise);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Every file below `root` whose name `accepts`, by its path relative to `root` in bytewise
|
|
69
|
+
* order, read in no skipped directory.
|
|
70
|
+
*/
|
|
71
|
+
export function filesBelow(host, root, accepts) {
|
|
72
|
+
const found = [];
|
|
73
|
+
const pending = [""];
|
|
74
|
+
for (let dir = pending.pop(); dir !== undefined; dir = pending.pop()) {
|
|
75
|
+
for (const entry of entriesOf(host, joinPath(root, dir))) {
|
|
76
|
+
const path = dir === "" ? entry.name : `${dir}/${entry.name}`;
|
|
77
|
+
if (!entry.directory) {
|
|
78
|
+
if (accepts(entry.name)) {
|
|
79
|
+
found.push(path);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
else if (!skipped(entry.name)) {
|
|
83
|
+
pending.push(path);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return found.sort(bytewise);
|
|
88
|
+
}
|
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The generated-file class on TypeScript: every declaration in a file that marks itself
|
|
3
|
-
* generated,
|
|
4
|
-
* retained, because a generator owns the file and a deletion there is undone at the next
|
|
5
|
-
* generation.
|
|
3
|
+
* generated, below a directory an applied convention row names as generated, or minified,
|
|
4
|
+
* is retained, because a generator owns the file and a deletion there is undone at the next
|
|
5
|
+
* generation. The same decision is each `generated` entry of the facts document.
|
|
6
6
|
*/
|
|
7
|
+
import { isIdentifier, isImportDeclaration, isPropertyAssignment, isStringLiteralLikeNode, isVariableStatement, NodeFlags, } from "@typescript/native/ast";
|
|
8
|
+
import { GENERATORS } from "./contract/contract.generated.js";
|
|
9
|
+
import { minifiedBy } from "./javascript-file.js";
|
|
10
|
+
import { bytewise } from "./text/compare.js";
|
|
11
|
+
import { satisfies } from "./version-range.js";
|
|
7
12
|
/** The generated-code header, matched against each line of a leading comment. */
|
|
8
13
|
const HEADER_LINE = /^\/\/ Code generated .* DO NOT EDIT\.$/u;
|
|
9
14
|
/** The documentation tag `@generated` as a word of a comment. */
|
|
@@ -14,9 +19,17 @@ const GENERATED_BY = /^\/\/ Generated by \S/u;
|
|
|
14
19
|
const GENERATED_WORD = /\bgenerated\b/iu;
|
|
15
20
|
/** The phrases a generator's notice asks a reader not to edit the file by. */
|
|
16
21
|
const KEEP_OUT = /\b(?:do not edit|will be overwritten|should not make any changes)\b/iu;
|
|
17
|
-
/** The comments before a text's first token, a leading hashbang line skipped. */
|
|
22
|
+
/** The comments before a text's first token, a leading hashbang line skipped, each as its lines. */
|
|
18
23
|
function leadingComments(text) {
|
|
19
24
|
const comments = [];
|
|
25
|
+
const lineAt = (offset) => text.slice(0, offset).split(/\r\n|[\n\r\u2028\u2029]/u).length;
|
|
26
|
+
const lines = (from, to) => {
|
|
27
|
+
const first = lineAt(from);
|
|
28
|
+
return text
|
|
29
|
+
.slice(from, to)
|
|
30
|
+
.split(/\r\n|[\n\r\u2028\u2029]/u)
|
|
31
|
+
.map((one, index) => ({ text: one, line: first + index }));
|
|
32
|
+
};
|
|
20
33
|
let at = text.startsWith("\uFEFF") ? 1 : 0;
|
|
21
34
|
if (text.startsWith("#!", at)) {
|
|
22
35
|
const end = text.indexOf("\n", at);
|
|
@@ -29,7 +42,7 @@ function leadingComments(text) {
|
|
|
29
42
|
if (text.startsWith("//", at)) {
|
|
30
43
|
const end = text.slice(at).search(/[\r\n\u2028\u2029]/u);
|
|
31
44
|
const stop = end === -1 ? text.length : at + end;
|
|
32
|
-
comments.push(
|
|
45
|
+
comments.push(lines(at, stop));
|
|
33
46
|
at = stop;
|
|
34
47
|
}
|
|
35
48
|
else if (text.startsWith("/*", at)) {
|
|
@@ -37,7 +50,7 @@ function leadingComments(text) {
|
|
|
37
50
|
if (end === -1) {
|
|
38
51
|
return comments;
|
|
39
52
|
}
|
|
40
|
-
comments.push(
|
|
53
|
+
comments.push(lines(at, end + 2));
|
|
41
54
|
at = end + 2;
|
|
42
55
|
}
|
|
43
56
|
else {
|
|
@@ -45,41 +58,168 @@ function leadingComments(text) {
|
|
|
45
58
|
}
|
|
46
59
|
}
|
|
47
60
|
}
|
|
48
|
-
/** The
|
|
49
|
-
export function
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
61
|
+
/** The mark one file's leading comments make it generated by, or undefined where they mark nothing. */
|
|
62
|
+
export function generatedMark(text) {
|
|
63
|
+
const lines = leadingComments(text).flat();
|
|
64
|
+
const header = lines.find((one) => HEADER_LINE.test(one.text));
|
|
65
|
+
if (header !== undefined) {
|
|
66
|
+
return { evidence: "header", line: header.line, detail: header.text };
|
|
53
67
|
}
|
|
54
|
-
|
|
55
|
-
|
|
68
|
+
const tag = lines.find((one) => GENERATED_TAG.test(one.text));
|
|
69
|
+
if (tag !== undefined) {
|
|
70
|
+
return { evidence: "tag", line: tag.line, detail: tag.text };
|
|
56
71
|
}
|
|
57
|
-
const
|
|
58
|
-
if (GENERATED_BY.test(
|
|
59
|
-
|
|
60
|
-
|
|
72
|
+
const [first] = lines;
|
|
73
|
+
if (first !== undefined && GENERATED_BY.test(first.text)) {
|
|
74
|
+
return { evidence: "notice", line: first.line, detail: first.text };
|
|
75
|
+
}
|
|
76
|
+
const notice = lines.map((one) => one.text).join("\n");
|
|
77
|
+
if (GENERATED_WORD.test(notice) && KEEP_OUT.test(notice)) {
|
|
78
|
+
const marked = lines.find((one) => GENERATED_WORD.test(one.text) || KEEP_OUT.test(one.text));
|
|
79
|
+
return marked === undefined
|
|
80
|
+
? undefined
|
|
81
|
+
: { evidence: "notice", line: marked.line, detail: marked.text };
|
|
82
|
+
}
|
|
83
|
+
return undefined;
|
|
84
|
+
}
|
|
85
|
+
/** What one form's first group captures, for each line the form matches. */
|
|
86
|
+
function after(lines, form) {
|
|
87
|
+
return lines.flatMap((one) => form.exec(one.text)?.[1] ?? []);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Where each plugin's output states its version and its schema files, as `references-ts.36`
|
|
91
|
+
* states: a plugin missing here states no version, and one with no schema form names none.
|
|
92
|
+
*/
|
|
93
|
+
const STATEMENTS = {
|
|
94
|
+
"protoc-gen-es": {
|
|
95
|
+
version: /^\/\/ @generated by protoc-gen-es (\S+)/u,
|
|
96
|
+
schemaFiles: /^\/\/ @generated from file (\S+)/u,
|
|
97
|
+
},
|
|
98
|
+
"protoc-gen-connect-es": {
|
|
99
|
+
version: /^\/\/ @generated by protoc-gen-connect-es (\S+)/u,
|
|
100
|
+
schemaFiles: /^\/\/ @generated from file (\S+)/u,
|
|
101
|
+
},
|
|
102
|
+
"protobuf-ts": {
|
|
103
|
+
version: /^\/\/ @generated by protobuf-ts (\S+)/u,
|
|
104
|
+
schemaFiles: /^\/\/ @generated from protobuf file "([^"]+)"/u,
|
|
105
|
+
},
|
|
106
|
+
"ts-proto": {
|
|
107
|
+
version: /^\/\/\s+protoc-gen-ts_proto\s+(\S+)$/u,
|
|
108
|
+
schemaFiles: /^\/\/ source: (.+)$/u,
|
|
109
|
+
},
|
|
110
|
+
"protoc-gen-grpc-web": {
|
|
111
|
+
version: /^\/\/\s+protoc-gen-grpc-web\s+(\S+)$/u,
|
|
112
|
+
schemaFiles: /^\/\/ source: (.+)$/u,
|
|
113
|
+
},
|
|
114
|
+
"protoc-gen-js": { schemaFiles: /^\/\/ source: (.+)$/u },
|
|
115
|
+
"ts-protoc-gen": { schemaFiles: /^\/\/ file: (.+)$/u },
|
|
116
|
+
};
|
|
117
|
+
/** A ts-proto service path literal: `/<package>.<service>/<method>`. */
|
|
118
|
+
const SERVICE_PATH = /^\/(?:\w+\.)+\w+\/\w+$/u;
|
|
119
|
+
/** Whether one ts-proto file writes a service path, as `references-ts.36` reads one. */
|
|
120
|
+
function writesServicePath(file) {
|
|
121
|
+
const named = file.statements.some((statement) => isVariableStatement(statement) &&
|
|
122
|
+
(statement.declarationList.flags & NodeFlags.Const) !== 0 &&
|
|
123
|
+
statement.declarationList.declarations.some((one) => isIdentifier(one.name) &&
|
|
124
|
+
one.name.text.endsWith("ServiceName") &&
|
|
125
|
+
one.initializer !== undefined &&
|
|
126
|
+
isStringLiteralLikeNode(one.initializer)));
|
|
127
|
+
let found = named;
|
|
128
|
+
const visit = (node) => {
|
|
129
|
+
if (found) {
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
if (isPropertyAssignment(node) &&
|
|
133
|
+
isIdentifier(node.name) &&
|
|
134
|
+
node.name.text === "path" &&
|
|
135
|
+
isStringLiteralLikeNode(node.initializer) &&
|
|
136
|
+
SERVICE_PATH.test(node.initializer.text)) {
|
|
137
|
+
found = true;
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
node.forEachChild(visit);
|
|
141
|
+
};
|
|
142
|
+
file.forEachChild(visit);
|
|
143
|
+
return found;
|
|
144
|
+
}
|
|
145
|
+
/** Whether one file imports a module by its specifier. */
|
|
146
|
+
function imports(file, module) {
|
|
147
|
+
return file.statements.some((statement) => isImportDeclaration(statement) &&
|
|
148
|
+
isStringLiteralLikeNode(statement.moduleSpecifier) &&
|
|
149
|
+
statement.moduleSpecifier.text === module);
|
|
150
|
+
}
|
|
151
|
+
/** The option sets the rows of `references-ts.36` name, by row; every other row's is met by any output. */
|
|
152
|
+
const OPTION_SETS = {
|
|
153
|
+
"ts-proto-2-output-schema": (file) => imports(file, "ts-proto-descriptors"),
|
|
154
|
+
"ts-proto-2": writesServicePath,
|
|
155
|
+
"ts-proto-2-types": (file) => !writesServicePath(file),
|
|
156
|
+
};
|
|
157
|
+
/** The first generator row one file matches, in `generators.json`'s order, as `bindings.3` reads it. */
|
|
158
|
+
export function generatorOf(file) {
|
|
159
|
+
const lines = leadingComments(file.text).flat();
|
|
160
|
+
for (const row of GENERATORS) {
|
|
161
|
+
const header = new RegExp(row.header, "u");
|
|
162
|
+
if (!lines.some((one) => header.test(one.text))) {
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
const statements = STATEMENTS[row.plugin] ?? {};
|
|
166
|
+
const [version] = statements.version === undefined ? [] : after(lines, statements.version);
|
|
167
|
+
if ("versions" in row &&
|
|
168
|
+
(version === undefined ||
|
|
169
|
+
!satisfies(version.replace(/^v/u, ""), `>=${row.versions.min.replace(/^v/u, "")} <=${row.versions.max.replace(/^v/u, "")}`))) {
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
if (OPTION_SETS[row.id]?.(file) === false) {
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
const schemaFiles = statements.schemaFiles === undefined
|
|
176
|
+
? []
|
|
177
|
+
: [
|
|
178
|
+
...new Set(after(lines, statements.schemaFiles).filter((one) => one.endsWith(".proto"))),
|
|
179
|
+
].sort(bytewise);
|
|
180
|
+
return { row: row.id, ...(version === undefined ? {} : { version }), schemaFiles };
|
|
61
181
|
}
|
|
62
182
|
return undefined;
|
|
63
183
|
}
|
|
64
184
|
/**
|
|
65
|
-
* Every own file of one project that is generated, by its path below the target root,
|
|
66
|
-
*
|
|
67
|
-
*
|
|
185
|
+
* Every own file of one project that is generated, by its path below the target root, with
|
|
186
|
+
* what decided it: its leading comments' mark, else the row naming its directory as
|
|
187
|
+
* generated, else its minified name or text; and the generator row it matches.
|
|
68
188
|
*/
|
|
69
189
|
export function generatedFilesOf(files, byRow) {
|
|
70
190
|
const found = new Map();
|
|
71
191
|
for (const [path, file] of files.byPath) {
|
|
72
192
|
const row = byRow.get(path);
|
|
73
|
-
const
|
|
193
|
+
const minified = row === undefined ? minifiedBy(file.fileName, file.text) : undefined;
|
|
194
|
+
const fact = generatedMark(file.text) ??
|
|
74
195
|
(row === undefined
|
|
75
|
-
? undefined
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
196
|
+
? minified === undefined
|
|
197
|
+
? undefined
|
|
198
|
+
: { evidence: "minified", line: 1, detail: minified }
|
|
199
|
+
: { evidence: "convention", line: 1, detail: row });
|
|
200
|
+
if (fact === undefined) {
|
|
201
|
+
continue;
|
|
79
202
|
}
|
|
203
|
+
const generator = generatorOf(file);
|
|
204
|
+
found.set(path, generator === undefined ? fact : { ...fact, generator });
|
|
80
205
|
}
|
|
81
206
|
return found;
|
|
82
207
|
}
|
|
208
|
+
/** The detail a retention in a generated file names, from what decided the file. */
|
|
209
|
+
function retentionDetail(fact) {
|
|
210
|
+
switch (fact.evidence) {
|
|
211
|
+
case "header":
|
|
212
|
+
return "generated by the header line its leading comments hold";
|
|
213
|
+
case "tag":
|
|
214
|
+
return "generated by the @generated tag its leading comments hold";
|
|
215
|
+
case "notice":
|
|
216
|
+
return "generated by the notice its leading comments hold";
|
|
217
|
+
case "convention":
|
|
218
|
+
return `generated below a directory the convention row ${fact.detail} names`;
|
|
219
|
+
case "minified":
|
|
220
|
+
return "generated as a minified JavaScript file";
|
|
221
|
+
}
|
|
222
|
+
}
|
|
83
223
|
/** The generated-file detector, recording each file's first line. */
|
|
84
224
|
export function generatedFile(input) {
|
|
85
225
|
const generated = input.generated;
|
|
@@ -87,9 +227,15 @@ export function generatedFile(input) {
|
|
|
87
227
|
return [];
|
|
88
228
|
}
|
|
89
229
|
return input.held.symbols.flatMap((symbol) => {
|
|
90
|
-
const
|
|
91
|
-
return symbol.kind === "file" ||
|
|
230
|
+
const fact = generated.get(symbol.position.path);
|
|
231
|
+
return symbol.kind === "file" || fact === undefined
|
|
92
232
|
? []
|
|
93
|
-
: [
|
|
233
|
+
: [
|
|
234
|
+
{
|
|
235
|
+
id: symbol.id,
|
|
236
|
+
detail: retentionDetail(fact),
|
|
237
|
+
site: { path: symbol.position.path, line: 1, column: 1 },
|
|
238
|
+
},
|
|
239
|
+
];
|
|
94
240
|
});
|
|
95
241
|
}
|