@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
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The command strings beside a target root's packages: a CI workflow's `run:` steps, the git
|
|
3
|
+
* hooks, the hook managers' commands and scripts and the makefile's recipe lines, each with the
|
|
4
|
+
* directory it runs in. A workflow or hook manager file is read by `text/yaml.ts`, and one it does not
|
|
5
|
+
* read gives no command; each command is read by `commands/read.ts`.
|
|
6
|
+
*/
|
|
7
|
+
import { pathsNamed, readCommands } from "../commands/read.js";
|
|
8
|
+
import { PART } from "../commands/shell.js";
|
|
9
|
+
import { isRecord } from "../json-document.js";
|
|
10
|
+
import { joinPath, resolvePath } from "../paths.js";
|
|
11
|
+
import { filesIn } from "../fs/tree.js";
|
|
12
|
+
import { yamlDocument } from "../text/yaml.js";
|
|
13
|
+
const WORKFLOWS = ".github/workflows";
|
|
14
|
+
/** The directories whose every file is a git hook script, run as the shell runs it. */
|
|
15
|
+
const HOOK_DIRS = [".husky", ".githooks"];
|
|
16
|
+
/** The key setting the directory a workflow step, or each step a `defaults.run` covers, runs in. */
|
|
17
|
+
const WORKING_DIRECTORY = "working-directory";
|
|
18
|
+
const HOOK_MANAGERS = [
|
|
19
|
+
{ name: ".pre-commit-config.yaml", key: "entry" },
|
|
20
|
+
...["lefthook.yml", "lefthook.yaml", ".lefthook.yml"].map((name) => ({
|
|
21
|
+
name,
|
|
22
|
+
key: "run",
|
|
23
|
+
dirKey: "root",
|
|
24
|
+
scripts: true,
|
|
25
|
+
})),
|
|
26
|
+
];
|
|
27
|
+
/**
|
|
28
|
+
* The directories lefthook searches for a hook's scripts after the file's `source_dir` and
|
|
29
|
+
* `source_dir_local`: https://github.com/evilmartians/lefthook/blob/master/internal/command/run.go
|
|
30
|
+
*/
|
|
31
|
+
const LEFTHOOK_DIRS = [".config/lefthook", ".config/lefthook-local"];
|
|
32
|
+
/** The names GNU make reads a makefile under, in the order it tries them. */
|
|
33
|
+
const MAKEFILES = ["GNUmakefile", "makefile", "Makefile"];
|
|
34
|
+
function readText(host, path) {
|
|
35
|
+
try {
|
|
36
|
+
return host.readFile(path);
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/** The text a YAML scalar's value stands for, or `undefined` for a collection or a null. */
|
|
43
|
+
function scalarText(value) {
|
|
44
|
+
return typeof value === "string" || typeof value === "number" || typeof value === "boolean"
|
|
45
|
+
? String(value)
|
|
46
|
+
: undefined;
|
|
47
|
+
}
|
|
48
|
+
/** The `defaults.run.working-directory` one mapping writes, as YAML decodes it. */
|
|
49
|
+
function defaultDirectory(mapping) {
|
|
50
|
+
const defaults = mapping["defaults"];
|
|
51
|
+
const run = isRecord(defaults) ? defaults["run"] : undefined;
|
|
52
|
+
return isRecord(run) ? scalarText(run[WORKING_DIRECTORY]) : undefined;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Every command one workflow or hook manager file writes under `key`, in every mapping of the
|
|
56
|
+
* document, each with the directory it runs in: its mapping's `dirKey` value, else, in a workflow
|
|
57
|
+
* file, the innermost `defaults.run.working-directory` of a mapping holding it, else `root`. A
|
|
58
|
+
* file `yamlDocument` does not read gives none.
|
|
59
|
+
*/
|
|
60
|
+
function keyedCommands(text, root, key, dirKey) {
|
|
61
|
+
const found = [];
|
|
62
|
+
const visit = (node, inherited) => {
|
|
63
|
+
if (Array.isArray(node)) {
|
|
64
|
+
for (const item of node) {
|
|
65
|
+
visit(item, inherited);
|
|
66
|
+
}
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
if (!isRecord(node)) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
const here = (dirKey === WORKING_DIRECTORY ? defaultDirectory(node) : undefined) ?? inherited;
|
|
73
|
+
const command = scalarText(node[key]);
|
|
74
|
+
if (command !== undefined && command.trim() !== "") {
|
|
75
|
+
const written = (dirKey === undefined ? undefined : scalarText(node[dirKey])) ?? here;
|
|
76
|
+
found.push({
|
|
77
|
+
text: command,
|
|
78
|
+
dir: written === undefined
|
|
79
|
+
? root
|
|
80
|
+
: written.includes("${{")
|
|
81
|
+
? undefined
|
|
82
|
+
: resolvePath(root, written),
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
for (const value of Object.values(node)) {
|
|
86
|
+
visit(value, here);
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
visit(yamlDocument(text), undefined);
|
|
90
|
+
return found;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* The command lefthook runs for each script a lefthook file's hooks name, each key of a hook's
|
|
94
|
+
* `scripts` and each `script` of a job in its `jobs`, a group's among them, from each directory
|
|
95
|
+
* it searches: its `runner`, then the path `<dir>/<hook>/<name>` quoted as lefthook quotes it,
|
|
96
|
+
* run in the target root: https://lefthook.dev/configuration/Scripts/
|
|
97
|
+
*/
|
|
98
|
+
function lefthookScripts(text, root) {
|
|
99
|
+
const document = yamlDocument(text);
|
|
100
|
+
if (!isRecord(document)) {
|
|
101
|
+
return [];
|
|
102
|
+
}
|
|
103
|
+
const dirs = [
|
|
104
|
+
scalarText(document["source_dir"]) ?? ".lefthook/",
|
|
105
|
+
scalarText(document["source_dir_local"]) ?? ".lefthook-local/",
|
|
106
|
+
...LEFTHOOK_DIRS,
|
|
107
|
+
];
|
|
108
|
+
const found = [];
|
|
109
|
+
const add = (hook, name, runner) => {
|
|
110
|
+
for (const dir of dirs) {
|
|
111
|
+
const path = `'${joinPath(dir, hook, name).replaceAll("'", "'\\''")}'`;
|
|
112
|
+
found.push({
|
|
113
|
+
text: runner === undefined || runner.trim() === "" ? path : `${runner} ${path}`,
|
|
114
|
+
dir: root,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
const jobs = (hook, list) => {
|
|
119
|
+
for (const job of Array.isArray(list) ? list : []) {
|
|
120
|
+
const script = isRecord(job) ? scalarText(job["script"]) : undefined;
|
|
121
|
+
if (isRecord(job) && script !== undefined) {
|
|
122
|
+
add(hook, script, scalarText(job["runner"]));
|
|
123
|
+
}
|
|
124
|
+
const group = isRecord(job) ? job["group"] : undefined;
|
|
125
|
+
jobs(hook, isRecord(group) ? group["jobs"] : undefined);
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
for (const [hook, value] of Object.entries(document)) {
|
|
129
|
+
const scripts = isRecord(value) ? value["scripts"] : undefined;
|
|
130
|
+
for (const [name, options] of Object.entries(isRecord(scripts) ? scripts : {})) {
|
|
131
|
+
add(hook, name, isRecord(options) ? scalarText(options["runner"]) : undefined);
|
|
132
|
+
}
|
|
133
|
+
jobs(hook, isRecord(value) ? value["jobs"] : undefined);
|
|
134
|
+
}
|
|
135
|
+
return found;
|
|
136
|
+
}
|
|
137
|
+
/** The path of each git hook script at `root`, every file in {@link HOOK_DIRS}. */
|
|
138
|
+
function hookScripts(host, root) {
|
|
139
|
+
return HOOK_DIRS.flatMap((dir) => filesIn(host, joinPath(root, dir), () => true).map((name) => joinPath(root, dir, name)));
|
|
140
|
+
}
|
|
141
|
+
/** The makefile make reads at `root`, the first of {@link MAKEFILES} there. */
|
|
142
|
+
function makefileAt(host, root) {
|
|
143
|
+
return MAKEFILES.map((name) => joinPath(root, name)).find((candidate) => host.kindOf(candidate) === "file");
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* One recipe line as make hands it to the shell: each `$$` a `$`, and each reference to a
|
|
147
|
+
* variable or a function, which make expands first, a part only the run knows:
|
|
148
|
+
* https://www.gnu.org/software/make/manual/html_node/Reference.html
|
|
149
|
+
*/
|
|
150
|
+
function expandedByMake(line) {
|
|
151
|
+
let expanded = "";
|
|
152
|
+
for (let at = 0; at < line.length; at += 1) {
|
|
153
|
+
const char = line.charAt(at);
|
|
154
|
+
const next = line.charAt(at + 1);
|
|
155
|
+
if (char !== "$") {
|
|
156
|
+
expanded += char;
|
|
157
|
+
}
|
|
158
|
+
else if (next === "$") {
|
|
159
|
+
expanded += "$";
|
|
160
|
+
at += 1;
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
let end = at + 1;
|
|
164
|
+
if (next === "(" || next === "{") {
|
|
165
|
+
const close = next === "(" ? ")" : "}";
|
|
166
|
+
for (let depth = 0; end < line.length; end += 1) {
|
|
167
|
+
depth += line.charAt(end) === next ? 1 : line.charAt(end) === close ? -1 : 0;
|
|
168
|
+
if (depth === 0) {
|
|
169
|
+
break;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
expanded += PART;
|
|
174
|
+
at = Math.min(end, line.length);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
return expanded;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Each recipe line of the target root's makefile: a line that starts with a tab, joined with
|
|
181
|
+
* the lines a trailing `\` continues it onto, less the `@`, `-` and `+` make reads before it,
|
|
182
|
+
* as make expands it. Make runs each line in a shell of its own.
|
|
183
|
+
*/
|
|
184
|
+
function recipeLines(host, root) {
|
|
185
|
+
const path = makefileAt(host, root);
|
|
186
|
+
const text = path === undefined ? undefined : readText(host, path);
|
|
187
|
+
return (text ?? "")
|
|
188
|
+
.replace(/\\\r?\n/gu, " ")
|
|
189
|
+
.split(/\r?\n/u)
|
|
190
|
+
.filter((line) => line.startsWith("\t"))
|
|
191
|
+
.map((line) => ({
|
|
192
|
+
text: expandedByMake(line.slice(1).replace(/^[@+-]+/u, "")),
|
|
193
|
+
dir: root,
|
|
194
|
+
}));
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Every command the target root's workflow steps, git hooks, hook managers and makefile run:
|
|
198
|
+
* the `run:` steps of the workflow files in `.github/workflows`, each file in `.husky` and
|
|
199
|
+
* `.githooks` as one shell script, the `entry:` commands of `.pre-commit-config.yaml`, the
|
|
200
|
+
* `run:` commands and the scripts of a lefthook file and the makefile's recipe lines.
|
|
201
|
+
*/
|
|
202
|
+
export function workflowCommands(host, targetRoot) {
|
|
203
|
+
const root = resolvePath(host.workingDirectory(), targetRoot);
|
|
204
|
+
const workflows = filesIn(host, joinPath(root, WORKFLOWS), (name) => /\.ya?ml$/u.test(name));
|
|
205
|
+
return [
|
|
206
|
+
...workflows.flatMap((name) => keyedCommands(readText(host, joinPath(root, WORKFLOWS, name)) ?? "", root, "run", WORKING_DIRECTORY)),
|
|
207
|
+
...hookScripts(host, root).map((path) => ({
|
|
208
|
+
text: readText(host, path) ?? "",
|
|
209
|
+
dir: root,
|
|
210
|
+
})),
|
|
211
|
+
...HOOK_MANAGERS.flatMap(({ name, key, dirKey, scripts }) => {
|
|
212
|
+
const text = readText(host, joinPath(root, name)) ?? "";
|
|
213
|
+
return [
|
|
214
|
+
...keyedCommands(text, root, key, dirKey),
|
|
215
|
+
...(scripts === true ? lefthookScripts(text, root) : []),
|
|
216
|
+
];
|
|
217
|
+
}),
|
|
218
|
+
...recipeLines(host, root),
|
|
219
|
+
];
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* The whole text of each file {@link workflowCommands} reads a command from, each workflow file,
|
|
223
|
+
* git hook, hook manager file and makefile at the target root, which the dependency rule reads.
|
|
224
|
+
*/
|
|
225
|
+
export function commandFileTexts(host, targetRoot) {
|
|
226
|
+
return commandFiles(host, targetRoot).flatMap(({ path }) => readText(host, path) ?? []);
|
|
227
|
+
}
|
|
228
|
+
/** Each file {@link workflowCommands} reads a command from, with the key a YAML file writes its commands under. */
|
|
229
|
+
function commandFiles(host, targetRoot) {
|
|
230
|
+
const root = resolvePath(host.workingDirectory(), targetRoot);
|
|
231
|
+
return [
|
|
232
|
+
...filesIn(host, joinPath(root, WORKFLOWS), (name) => /\.ya?ml$/u.test(name)).map((name) => ({
|
|
233
|
+
path: joinPath(root, WORKFLOWS, name),
|
|
234
|
+
key: "run",
|
|
235
|
+
})),
|
|
236
|
+
...hookScripts(host, root).map((path) => ({ path, key: undefined })),
|
|
237
|
+
...HOOK_MANAGERS.map(({ name, key }) => ({ path: joinPath(root, name), key })),
|
|
238
|
+
...[makefileAt(host, root) ?? []].flat().map((path) => ({ path, key: undefined })),
|
|
239
|
+
];
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* The filters of a workflow's `on` key, which name the files and refs whose change triggers it
|
|
243
|
+
* and run none: https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-syntax#onpushpull_requestpull_request_targetpathspaths-ignore
|
|
244
|
+
*/
|
|
245
|
+
const TRIGGER_FILTERS = new Set([
|
|
246
|
+
"paths",
|
|
247
|
+
"paths-ignore",
|
|
248
|
+
"branches",
|
|
249
|
+
"branches-ignore",
|
|
250
|
+
"tags",
|
|
251
|
+
"tags-ignore",
|
|
252
|
+
]);
|
|
253
|
+
/**
|
|
254
|
+
* The values of one YAML file that are no command, each with its key: every scalar but one
|
|
255
|
+
* written under `key`, which is read as a command string, and one of a trigger filter. A file
|
|
256
|
+
* `yamlDocument` does not read is one value, its whole text. No key and no comment is a value.
|
|
257
|
+
*/
|
|
258
|
+
function yamlValues(text, key) {
|
|
259
|
+
const document = yamlDocument(text);
|
|
260
|
+
if (document === undefined) {
|
|
261
|
+
return [{ text, shell: false }];
|
|
262
|
+
}
|
|
263
|
+
const found = [];
|
|
264
|
+
// `trigger` is 1 for the value of the top-level `on`, a map of events, and 2 for an event's.
|
|
265
|
+
const visit = (node, under, trigger = 0) => {
|
|
266
|
+
if (Array.isArray(node)) {
|
|
267
|
+
for (const item of node) {
|
|
268
|
+
visit(item, under);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
else if (isRecord(node)) {
|
|
272
|
+
for (const [name, value] of Object.entries(node)) {
|
|
273
|
+
const on = node === document && (name === "on" || name === "true");
|
|
274
|
+
if ((name !== key || scalarText(value) === undefined) &&
|
|
275
|
+
!(trigger === 2 && TRIGGER_FILTERS.has(name))) {
|
|
276
|
+
visit(value, name, on ? 1 : trigger === 1 ? 2 : 0);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
else {
|
|
281
|
+
const value = scalarText(node);
|
|
282
|
+
if (value !== undefined) {
|
|
283
|
+
found.push({ text: value, shell: false, ...(under === undefined ? {} : { key: under }) });
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
};
|
|
287
|
+
visit(document, undefined);
|
|
288
|
+
return found;
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* The lines of a makefile that are no recipe line, joined with the lines a trailing `\`
|
|
292
|
+
* continues them onto, each without the comment a `#` make does not read as escaped starts.
|
|
293
|
+
*/
|
|
294
|
+
function makefileValues(text) {
|
|
295
|
+
return text
|
|
296
|
+
.replace(/\\\r?\n/gu, " ")
|
|
297
|
+
.split(/\r?\n/u)
|
|
298
|
+
.filter((line) => !line.startsWith("\t"))
|
|
299
|
+
.map((line) => line.replace(/(?<!\\)#.*$/u, ""))
|
|
300
|
+
.filter((line) => line.trim() !== "")
|
|
301
|
+
.map((line) => ({ text: line, shell: false }));
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* The texts layer 3 reads of the target root's command files: each command string, and each
|
|
305
|
+
* value of a workflow file, a hook manager file and the makefile that is no command.
|
|
306
|
+
*/
|
|
307
|
+
function heldTexts(host, targetRoot) {
|
|
308
|
+
const makefile = makefileAt(host, resolvePath(host.workingDirectory(), targetRoot));
|
|
309
|
+
return [
|
|
310
|
+
...workflowCommands(host, targetRoot).map(({ text }) => ({ text, shell: true })),
|
|
311
|
+
...commandFiles(host, targetRoot).flatMap(({ path, key }) => {
|
|
312
|
+
const text = readText(host, path);
|
|
313
|
+
return text === undefined
|
|
314
|
+
? []
|
|
315
|
+
: key !== undefined
|
|
316
|
+
? yamlValues(text, key)
|
|
317
|
+
: path === makefile
|
|
318
|
+
? makefileValues(text)
|
|
319
|
+
: [];
|
|
320
|
+
}),
|
|
321
|
+
];
|
|
322
|
+
}
|
|
323
|
+
/** Reads the target root's workflow steps, git hooks, hook managers and makefile. */
|
|
324
|
+
export function readWorkflows(host, targetRoot) {
|
|
325
|
+
return {
|
|
326
|
+
readings: workflowCommands(host, targetRoot).map(({ text, dir }) => readCommands(text, dir)),
|
|
327
|
+
texts: commandFileTexts(host, targetRoot),
|
|
328
|
+
held: heldTexts(host, targetRoot),
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* The own files the target root's workflow steps, git hooks and recipes run or name, as
|
|
333
|
+
* `pathsNamed` reads each command.
|
|
334
|
+
*/
|
|
335
|
+
export function workflowEntries(workflows, files) {
|
|
336
|
+
const found = [];
|
|
337
|
+
for (const reading of workflows.readings) {
|
|
338
|
+
for (const { path, written } of pathsNamed(reading)) {
|
|
339
|
+
for (const file of files.named(path)) {
|
|
340
|
+
found.push({ file, source: written });
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
return found;
|
|
345
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which parameter place each argument of a call binds, the one reading every question
|
|
3
|
+
* about a call's arguments asks. A plain argument fills the next place, and a spread or
|
|
4
|
+
* an `apply` list typed as a tuple whose elements are all required fills one place per
|
|
5
|
+
* element. Any other spread or list has no known length: from its first place on, each of
|
|
6
|
+
* its element types, and every later argument, may fill any place, so a value is never
|
|
7
|
+
* read as missing a parameter only because its place could not be read. The type at each
|
|
8
|
+
* place is the checker's answer for it, so this reading names places and never types them.
|
|
9
|
+
*/
|
|
10
|
+
import { isSpreadElement } from "@typescript/native/ast";
|
|
11
|
+
import { ElementFlags } from "@typescript/native/sync";
|
|
12
|
+
import { must } from "../query.js";
|
|
13
|
+
/** The element flags of a tuple type; none for another type. */
|
|
14
|
+
function elementFlags(project, type) {
|
|
15
|
+
const target = type.isTupleType() ? must(project.queries.targetOf(type)) : undefined;
|
|
16
|
+
return target?.isTupleTypeTarget() === true ? target.elementFlags : [];
|
|
17
|
+
}
|
|
18
|
+
/** What a spread argument puts at the places it fills, and how many it fills at least. */
|
|
19
|
+
function spread(project, type) {
|
|
20
|
+
const { queries } = project;
|
|
21
|
+
if (type === undefined) {
|
|
22
|
+
return { types: [undefined], fixed: false, least: 0 };
|
|
23
|
+
}
|
|
24
|
+
if (type.isTupleType()) {
|
|
25
|
+
const flags = elementFlags(project, type);
|
|
26
|
+
return {
|
|
27
|
+
types: must(queries.typeArguments(type)).slice(0, flags.length),
|
|
28
|
+
fixed: flags.every((flag) => (flag & ElementFlags.Required) !== 0),
|
|
29
|
+
least: flags.filter((flag) => (flag & ElementFlags.Required) !== 0).length,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
if (must(queries.isArray(type))) {
|
|
33
|
+
return { types: must(queries.typeArguments(type)), fixed: false, least: 0 };
|
|
34
|
+
}
|
|
35
|
+
// Another iterable's elements are read off its type arguments, as `Set<T>` holds `T`.
|
|
36
|
+
return { types: [type, ...must(queries.typeArguments(type))], fixed: false, least: 0 };
|
|
37
|
+
}
|
|
38
|
+
/** The element types of a tuple of `count` required elements; none for another type. */
|
|
39
|
+
export function knownElements(project, type, count) {
|
|
40
|
+
if (!type.isTupleType()) {
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
const elements = spread(project, type);
|
|
44
|
+
return elements.fixed && elements.types.length === count ? elements.types : undefined;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* The places each argument fills, `types` holding the type of each argument's value; it
|
|
48
|
+
* may be empty where no argument is a spread and no given type is read. `listed` reads
|
|
49
|
+
* the last argument as a list whose elements the places bind.
|
|
50
|
+
*/
|
|
51
|
+
export function spansOf(project, args, listed, types) {
|
|
52
|
+
const spans = [];
|
|
53
|
+
let place = 0;
|
|
54
|
+
let open = false;
|
|
55
|
+
for (const [at, argument] of args.entries()) {
|
|
56
|
+
const type = types[at];
|
|
57
|
+
if (!isSpreadElement(argument) && !(listed && at === args.length - 1)) {
|
|
58
|
+
spans.push({ argument: at, first: place, given: [type], open, spread: false });
|
|
59
|
+
place += 1;
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
const elements = spread(project, type);
|
|
63
|
+
open ||= !elements.fixed;
|
|
64
|
+
spans.push({ argument: at, first: place, given: elements.types, open, spread: true });
|
|
65
|
+
place += elements.least;
|
|
66
|
+
}
|
|
67
|
+
return spans;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* The places of one signature as the checker counts them: one per parameter, and in
|
|
71
|
+
* place of a rest as many as the `length` the checker answers for its type, where that
|
|
72
|
+
* is a number literal or a union of them. Any other `length`, an array's or an array-like
|
|
73
|
+
* interface's `number` among them, leaves the rest open.
|
|
74
|
+
*/
|
|
75
|
+
export function layoutOf(project, signature) {
|
|
76
|
+
const { queries } = project;
|
|
77
|
+
const fixed = signature.parameters.length;
|
|
78
|
+
const rest = must(queries.restTypeOf(signature));
|
|
79
|
+
if (rest === undefined) {
|
|
80
|
+
return { count: fixed, repeats: false };
|
|
81
|
+
}
|
|
82
|
+
const length = must(queries.propertyTypeOf(rest, "length"));
|
|
83
|
+
const lengths = length === undefined ? [] : must(queries.constituents(length));
|
|
84
|
+
const bounds = lengths.flatMap((one) => (one.isNumberLiteralType() ? [one.value] : []));
|
|
85
|
+
if (bounds.length > 0 && bounds.length === lengths.length) {
|
|
86
|
+
return { count: fixed - 1 + Math.max(...bounds), repeats: false };
|
|
87
|
+
}
|
|
88
|
+
return { count: fixed, repeats: true };
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* The parameter place each argument binds in a signature of `layout`, with the type it
|
|
92
|
+
* gives there. A span of unknown length binds every place from its first to the last the
|
|
93
|
+
* layout counts, and past them, where the rest is open, one `rest` placement for every
|
|
94
|
+
* later place, or else its first place alone. A place past every place of a layout that
|
|
95
|
+
* does not repeat is `uncovered`.
|
|
96
|
+
*/
|
|
97
|
+
export function placesIn(spans, layout) {
|
|
98
|
+
const placed = [];
|
|
99
|
+
const add = (span, place, rest) => {
|
|
100
|
+
const uncovered = place >= layout.count && !layout.repeats;
|
|
101
|
+
const elements = span.open
|
|
102
|
+
? span.given.map((given, element) => ({ given, element }))
|
|
103
|
+
: [{ given: span.given[place - span.first], element: place - span.first }];
|
|
104
|
+
placed.push(...elements.map((one) => ({ argument: span.argument, place, uncovered, rest, ...one })));
|
|
105
|
+
};
|
|
106
|
+
for (const span of spans) {
|
|
107
|
+
const open = span.open && layout.repeats;
|
|
108
|
+
const end = !span.open
|
|
109
|
+
? span.first + span.given.length
|
|
110
|
+
: Math.max(layout.count, open ? span.first : span.first + 1);
|
|
111
|
+
for (let place = span.first; place < end; place += 1) {
|
|
112
|
+
add(span, place, false);
|
|
113
|
+
}
|
|
114
|
+
if (open) {
|
|
115
|
+
add(span, Math.max(layout.count, span.first), true);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return placed;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Whether a span fills the parameter declared at `index`, a rest parameter every place
|
|
122
|
+
* from it on; with `element`, whether that element of a span that is not open does.
|
|
123
|
+
*/
|
|
124
|
+
export function fills(span, index, rest, element) {
|
|
125
|
+
if (element !== undefined && !span.open) {
|
|
126
|
+
const place = span.first + element;
|
|
127
|
+
return rest ? place >= index : place === index;
|
|
128
|
+
}
|
|
129
|
+
const last = span.open ? Number.POSITIVE_INFINITY : span.first + span.given.length - 1;
|
|
130
|
+
return rest ? last >= index : span.first <= index && index <= last;
|
|
131
|
+
}
|