@cplieger/deadset-ts 8.0.0-dev.14 → 8.0.0-dev.16

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.
Files changed (149) hide show
  1. package/dist/src/alias-chain.js +2 -2
  2. package/dist/src/analysis.js +43 -38
  3. package/dist/src/commands/read.js +6 -7
  4. package/dist/src/conformance-record.js +1 -1
  5. package/dist/src/consumers.js +4 -2
  6. package/dist/src/contract/config.generated.js +1 -1
  7. package/dist/src/contract/contract.generated.js +120 -2
  8. package/dist/src/dependencies.js +81 -49
  9. package/dist/src/entries/build-scripts.js +222 -0
  10. package/dist/src/{configuration-files.js → entries/configuration-files.js} +20 -58
  11. package/dist/src/{convention-rows.js → entries/convention-rows.js} +120 -27
  12. package/dist/src/entries/conventions.js +739 -0
  13. package/dist/src/{html-entries.js → entries/html-entries.js} +3 -3
  14. package/dist/src/{mdx-entries.js → entries/mdx-entries.js} +2 -2
  15. package/dist/src/entries/run-directories.js +77 -0
  16. package/dist/src/entries/sources.js +144 -0
  17. package/dist/src/entries/static-module.js +669 -0
  18. package/dist/src/entries/test-runners.js +684 -0
  19. package/dist/src/{workflow-steps.js → entries/workflow-steps.js} +18 -8
  20. package/dist/src/extensions.js +37 -0
  21. package/dist/src/facts.js +38 -0
  22. package/dist/src/file-facts.js +1 -1
  23. package/dist/src/findings/emitters.js +5 -8
  24. package/dist/src/findings/self-check.js +36 -20
  25. package/dist/src/findings-pass.js +5 -6
  26. package/dist/src/framework-lifecycle.js +1 -1
  27. package/dist/src/fs/manifest.js +15 -20
  28. package/dist/src/generated-file.js +172 -29
  29. package/dist/src/graph.js +2 -5
  30. package/dist/src/index.js +1 -1
  31. package/dist/src/injection-container.js +1 -1
  32. package/dist/src/inventory/commonjs.js +507 -0
  33. package/dist/src/inventory/enumerate.js +167 -0
  34. package/dist/src/inventory/syntax.js +236 -0
  35. package/dist/src/inventory.js +305 -705
  36. package/dist/src/javascript-file.js +26 -11
  37. package/dist/src/load/classify.js +28 -9
  38. package/dist/src/load/diagnostics.js +8 -1
  39. package/dist/src/load/discover.js +16 -8
  40. package/dist/src/load/package-scope.js +56 -0
  41. package/dist/src/load/plan.js +2 -2
  42. package/dist/src/load/synthesize.js +5 -5
  43. package/dist/src/load/workspace-manifests.js +1 -1
  44. package/dist/src/matrix.js +6 -13
  45. package/dist/src/outside-tests.js +1 -1
  46. package/dist/src/paths.js +16 -0
  47. package/dist/src/platform-calls.js +78 -0
  48. package/dist/src/platform-symbols.js +140 -0
  49. package/dist/src/position.js +41 -0
  50. package/dist/src/ref.js +11 -20
  51. package/dist/src/references.js +281 -50
  52. package/dist/src/resolve.js +1 -1
  53. package/dist/src/{configured-declarations.js → roots/configured-declarations.js} +4 -4
  54. package/dist/src/{entry-point-gaps.js → roots/entry-point-gaps.js} +5 -8
  55. package/dist/src/{manifest.js → roots/manifest.js} +4 -4
  56. package/dist/src/roots/published-reach.js +412 -0
  57. package/dist/src/roots/root-set.js +489 -0
  58. package/dist/src/roots/unseen-loads.js +208 -0
  59. package/dist/src/serialization-contract.js +1 -1
  60. package/dist/src/session.js +3 -0
  61. package/dist/src/source-files.js +5 -9
  62. package/dist/src/suppress-inline.js +33 -81
  63. package/dist/src/suppress.js +30 -32
  64. package/dist/src/test-support.js +4 -2
  65. package/dist/src/verbs/analyze.js +13 -1
  66. package/dist/src/verbs/describe.js +5 -3
  67. package/jsr.json +1 -1
  68. package/package.json +3 -3
  69. package/src/alias-chain.ts +2 -2
  70. package/src/analysis.ts +77 -53
  71. package/src/automatic-types.ts +1 -1
  72. package/src/commands/read.ts +6 -8
  73. package/src/conformance-record.ts +1 -1
  74. package/src/consumers.ts +5 -1
  75. package/src/contract/config.generated.ts +1 -1
  76. package/src/contract/contract.generated.ts +139 -2
  77. package/src/dependencies.ts +98 -50
  78. package/src/entries/build-scripts.ts +292 -0
  79. package/src/{configuration-files.ts → entries/configuration-files.ts} +23 -75
  80. package/src/{convention-rows.ts → entries/convention-rows.ts} +167 -28
  81. package/src/{conventions.ts → entries/conventions.ts} +347 -522
  82. package/src/{html-entries.ts → entries/html-entries.ts} +5 -5
  83. package/src/{mdx-entries.ts → entries/mdx-entries.ts} +4 -4
  84. package/src/entries/run-directories.ts +108 -0
  85. package/src/entries/sources.ts +266 -0
  86. package/src/entries/static-module.ts +857 -0
  87. package/src/entries/test-runners.ts +868 -0
  88. package/src/{workflow-steps.ts → entries/workflow-steps.ts} +29 -11
  89. package/src/exempt.ts +3 -2
  90. package/src/extensions.ts +45 -0
  91. package/src/facts.ts +44 -0
  92. package/src/file-facts.ts +2 -2
  93. package/src/findings/emitters.ts +14 -10
  94. package/src/findings/self-check.ts +41 -22
  95. package/src/findings/visibility-narrowing.ts +1 -1
  96. package/src/findings-pass.ts +5 -12
  97. package/src/framework-lifecycle.ts +1 -1
  98. package/src/fs/manifest.ts +25 -21
  99. package/src/generated-file.ts +240 -36
  100. package/src/graph.ts +3 -6
  101. package/src/index.ts +1 -1
  102. package/src/injection-container.ts +1 -1
  103. package/src/inventory/commonjs.ts +696 -0
  104. package/src/inventory/enumerate.ts +203 -0
  105. package/src/inventory/syntax.ts +311 -0
  106. package/src/inventory.ts +424 -878
  107. package/src/javascript-file.ts +29 -12
  108. package/src/load/classify.ts +49 -13
  109. package/src/load/diagnostics.ts +11 -1
  110. package/src/load/discover.ts +28 -12
  111. package/src/load/package-scope.ts +74 -0
  112. package/src/load/plan.ts +11 -2
  113. package/src/load/synthesize.ts +6 -6
  114. package/src/load/test-globals.ts +1 -1
  115. package/src/load/workspace-manifests.ts +1 -1
  116. package/src/load/workspace-run.ts +1 -1
  117. package/src/matrix.ts +7 -14
  118. package/src/outside-tests.ts +1 -1
  119. package/src/paths.ts +18 -0
  120. package/src/platform-calls.ts +119 -0
  121. package/src/platform-symbols.ts +205 -0
  122. package/src/position.ts +42 -0
  123. package/src/ref.ts +11 -20
  124. package/src/references.ts +383 -73
  125. package/src/report.ts +1 -1
  126. package/src/resolve.ts +1 -1
  127. package/src/{configured-declarations.ts → roots/configured-declarations.ts} +7 -7
  128. package/src/{entry-point-gaps.ts → roots/entry-point-gaps.ts} +5 -8
  129. package/src/{manifest.ts → roots/manifest.ts} +5 -5
  130. package/src/roots/published-reach.ts +481 -0
  131. package/src/{roots.ts → roots/root-set.ts} +203 -630
  132. package/src/roots/unseen-loads.ts +307 -0
  133. package/src/serialization-contract.ts +1 -1
  134. package/src/session.ts +17 -1
  135. package/src/source-files.ts +5 -10
  136. package/src/suppress-inline.ts +53 -89
  137. package/src/suppress.ts +48 -33
  138. package/src/test-support.ts +8 -3
  139. package/src/verbs/analyze.ts +17 -4
  140. package/src/verbs/describe.ts +5 -2
  141. package/src/verbs/explain.ts +1 -1
  142. package/dist/src/build-scripts.js +0 -418
  143. package/dist/src/conventions.js +0 -907
  144. package/dist/src/entry-points.js +0 -513
  145. package/dist/src/roots.js +0 -865
  146. package/dist/src/unseen-loads.js +0 -100
  147. package/src/build-scripts.ts +0 -536
  148. package/src/entry-points.ts +0 -661
  149. package/src/unseen-loads.ts +0 -134
@@ -0,0 +1,205 @@
1
+ /**
2
+ * The platform's names read through a program's checker: its `require` and `URL`, as
3
+ * `platform-calls.ts` decides them, its worker constructors and `navigator`, and Node's
4
+ * `Worker`.
5
+ */
6
+
7
+ import {
8
+ isArrowFunction,
9
+ isClassDeclaration,
10
+ isClassExpression,
11
+ isFunctionDeclaration,
12
+ isFunctionExpression,
13
+ isMethodDeclaration,
14
+ isModuleDeclaration,
15
+ isPropertyAssignment,
16
+ isPropertyDeclaration,
17
+ isSourceFile,
18
+ isStringLiteralLikeNode,
19
+ isVariableDeclaration,
20
+ type Identifier,
21
+ type Node,
22
+ } from "@typescript/native/ast";
23
+ import { SymbolFlags, type Symbol as TSSymbol } from "@typescript/native/sync";
24
+ import { UNANSWERED, type Answer } from "./query.ts";
25
+ import type { ProjectView } from "./session.ts";
26
+ import { boundExports, NAMESPACE } from "./entries/static-module.ts";
27
+ import { isAmbient } from "./inventory.ts";
28
+ import { callsPlatformBy, carriedNames, type BindingOf, type Bound } from "./platform-calls.ts";
29
+ import { unwrapped } from "./unwrap.ts";
30
+
31
+ /** Counts one request a platform decision puts to the checker. */
32
+ type Asked = () => void;
33
+
34
+ /** The symbol one symbol names through its aliases, or the symbol itself where it is none. */
35
+ function dealiased<Brand>(
36
+ project: ProjectView<Brand>,
37
+ symbol: TSSymbol,
38
+ asked: Asked,
39
+ ): Answer<TSSymbol> {
40
+ if ((symbol.flags & SymbolFlags.Alias) === 0) {
41
+ return symbol;
42
+ }
43
+ asked();
44
+ return project.queries.aliased(symbol);
45
+ }
46
+
47
+ /** Each declaration of `symbol` in a file of the target, read in this project's program. */
48
+ function ownDeclarations<Brand>(project: ProjectView<Brand>, symbol: TSSymbol): readonly Node[] {
49
+ const own = project.ownPaths();
50
+ return symbol.declarations.flatMap((handle) => {
51
+ const node = own.has(handle.path) ? project.declarationAt(handle)?.node : undefined;
52
+ return node === undefined ? [] : [node];
53
+ });
54
+ }
55
+
56
+ /**
57
+ * Whether one declaration writes a function or a class with a body (roots.23): a function
58
+ * or method declaration with a body, a class declaration, or a variable, a property or a
59
+ * class field whose initializer is a function, an arrow function or a class expression,
60
+ * under no `declare` modifier and in no declaration file.
61
+ */
62
+ function writesBody(node: Node): boolean {
63
+ const value =
64
+ (isVariableDeclaration(node) || isPropertyAssignment(node) || isPropertyDeclaration(node)) &&
65
+ node.initializer !== undefined
66
+ ? unwrapped(node.initializer)
67
+ : node;
68
+ return (
69
+ (isFunctionDeclaration(value) || isMethodDeclaration(value)
70
+ ? value.body !== undefined
71
+ : isFunctionExpression(value) ||
72
+ isArrowFunction(value) ||
73
+ isClassDeclaration(value) ||
74
+ isClassExpression(value)) && !isAmbient(value.getSourceFile(), value)
75
+ );
76
+ }
77
+
78
+ /**
79
+ * What the checker binds `symbol` to, one alias step at a time: every name a step of the
80
+ * chain carries it by, and the declarations of the target its last step reaches, which
81
+ * prove it the target's own where one {@link writesBody}. A chain that ends at no
82
+ * declaration, or that the checker leaves unanswered, reaches none.
83
+ */
84
+ function boundBy<Brand>(
85
+ project: ProjectView<Brand>,
86
+ symbol: Answer<TSSymbol> | undefined,
87
+ asked: Asked,
88
+ ): Bound | undefined {
89
+ if (typeof symbol !== "object") {
90
+ return undefined;
91
+ }
92
+ const names = new Set<string>();
93
+ const stepped = new Set<number>();
94
+ for (let at: TSSymbol | undefined = symbol; at !== undefined && !stepped.has(at.id);) {
95
+ stepped.add(at.id);
96
+ names.add(at.name);
97
+ const own = ownDeclarations(project, at);
98
+ for (const node of own) {
99
+ carriedNames(node).forEach((one) => names.add(one));
100
+ }
101
+ if ((at.flags & SymbolFlags.Alias) === 0) {
102
+ return { names, own, provenOwn: own.some(writesBody) };
103
+ }
104
+ asked();
105
+ const next = project.aliasStepOf(at);
106
+ at = typeof next === "object" ? next : undefined;
107
+ }
108
+ return { names, own: [], provenOwn: false };
109
+ }
110
+
111
+ /** Each written name's binding, as this project's checker answers it. */
112
+ function checkerBinding<Brand>(project: ProjectView<Brand>, asked: Asked): BindingOf {
113
+ return (written) => {
114
+ asked();
115
+ return boundBy(project, project.symbolsAt([project.handle(written)])[0], asked);
116
+ };
117
+ }
118
+
119
+ /**
120
+ * Whether a call or construction through `callee`, the batch's answer for which is `symbol`,
121
+ * is one of the platform's `require` or `URL` (roots.23, references-ts.1), as
122
+ * {@link callsPlatformBy} decides it over this project's checker, each request it puts
123
+ * counted by `asked`.
124
+ */
125
+ export function callsPlatform<Brand>(
126
+ project: ProjectView<Brand>,
127
+ name: "require" | "URL",
128
+ callee: Identifier,
129
+ symbol: Answer<TSSymbol> | undefined,
130
+ asked: Asked,
131
+ ): boolean {
132
+ const others = checkerBinding(project, asked);
133
+ return callsPlatformBy(name, callee, (written) =>
134
+ written === callee ? boundBy(project, symbol, asked) : others(written),
135
+ );
136
+ }
137
+
138
+ /**
139
+ * Whether a worker's constructor or `navigator`, the batch's answer for which is `symbol`, is
140
+ * the platform's (references-ts.2): a name the checker leaves unanswered, or one whose symbol
141
+ * is no alias and has a declaration outside the target's files.
142
+ */
143
+ export function isPlatformGlobal<Brand>(
144
+ project: ProjectView<Brand>,
145
+ symbol: Answer<TSSymbol> | undefined,
146
+ ): boolean {
147
+ if (symbol === UNANSWERED) {
148
+ return true;
149
+ }
150
+ const own = project.ownPaths();
151
+ return (
152
+ symbol !== undefined &&
153
+ (symbol.flags & SymbolFlags.Alias) === 0 &&
154
+ symbol.declarations.some((handle) => !own.has(handle.path))
155
+ );
156
+ }
157
+
158
+ /** The module names Node's worker threads are imported by. */
159
+ const THREADS: ReadonlySet<string> = new Set(["worker_threads", "node:worker_threads"]);
160
+
161
+ function namesThreads(node: Node | undefined): boolean {
162
+ return node !== undefined && isStringLiteralLikeNode(node) && THREADS.has(node.text);
163
+ }
164
+
165
+ /** Whether one declaration is written in the body of `declare module "worker_threads"`. */
166
+ function inThreadsModule(node: Node): boolean {
167
+ for (let at = node; !isSourceFile(at); at = at.parent) {
168
+ if (isModuleDeclaration(at) && namesThreads(at.name)) {
169
+ return true;
170
+ }
171
+ }
172
+ return false;
173
+ }
174
+
175
+ /**
176
+ * Whether a `Worker` constructor, the batch's answer for which is `symbol`, is Node's
177
+ * (references-ts.2): its symbol resolves to a declaration of `worker_threads`, or one of its
178
+ * own declarations binds the module's `Worker`, or `holder`, the namespace it is read
179
+ * through, binds the module, each binding read as {@link boundExports} reads one, which
180
+ * decides where the module has no declaration. Each request it puts is counted by `asked`.
181
+ */
182
+ export function startsThread<Brand>(
183
+ project: ProjectView<Brand>,
184
+ symbol: Answer<TSSymbol> | undefined,
185
+ holder: Answer<TSSymbol> | undefined,
186
+ asked: Asked,
187
+ ): boolean {
188
+ const bindingOf = checkerBinding(project, asked);
189
+ const declared = (one: Answer<TSSymbol> | undefined, member: string): boolean =>
190
+ typeof one === "object" &&
191
+ ownDeclarations(project, one).some((node) =>
192
+ boundExports(node, (specifier) => THREADS.has(specifier), bindingOf).includes(member),
193
+ );
194
+ if (declared(symbol, "Worker") || declared(holder, NAMESPACE)) {
195
+ return true;
196
+ }
197
+ const named = typeof symbol === "object" ? dealiased(project, symbol, asked) : undefined;
198
+ return (
199
+ typeof named === "object" &&
200
+ named.declarations.some((handle) => {
201
+ const node = project.declarationAt(handle)?.node;
202
+ return node !== undefined && inThreadsModule(node);
203
+ })
204
+ );
205
+ }
package/src/position.ts CHANGED
@@ -48,6 +48,48 @@ export function writtenLength(file: SourceFile): number {
48
48
  return isComponentFile(file) ? file.originalText.length : file.text.length;
49
49
  }
50
50
 
51
+ /** Whether one character ends a line, under the language's line terminators. */
52
+ function endsLine(char: string | undefined): boolean {
53
+ return char === "\n" || char === "\r" || char === "\u2028" || char === "\u2029";
54
+ }
55
+
56
+ /** The offset where the line holding `from` ends. */
57
+ export function lineEnd(text: string, from: number): number {
58
+ let at = from;
59
+ while (at < text.length && !endsLine(text[at])) {
60
+ at += 1;
61
+ }
62
+ return at;
63
+ }
64
+
65
+ /**
66
+ * The offset of the first token at or after `from`: whitespace, comments and a leading
67
+ * hashbang are trivia.
68
+ */
69
+ export function tokenStart(text: string, from: number): number {
70
+ let at = from;
71
+ if (at === 0 && text.startsWith("#!")) {
72
+ at = lineEnd(text, 0);
73
+ }
74
+ for (;;) {
75
+ if (/\s/u.test(text[at] ?? "")) {
76
+ at += 1;
77
+ } else if (text.startsWith("//", at)) {
78
+ at = lineEnd(text, at);
79
+ } else if (text.startsWith("/*", at)) {
80
+ const close = text.indexOf("*/", at + 2);
81
+ at = close < 0 ? text.length : close + 2;
82
+ } else {
83
+ return at;
84
+ }
85
+ }
86
+ }
87
+
88
+ /** The line, counted from one, of the first token at or after one offset of one file. */
89
+ export function startLine(file: SourceFile, offset: number): number {
90
+ return file.getLineAndCharacterOfPosition(tokenStart(file.text, offset)).line + 1;
91
+ }
92
+
51
93
  /**
52
94
  * The position of one offset of one file, rendered against the target root.
53
95
  *
package/src/ref.ts CHANGED
@@ -1,13 +1,9 @@
1
1
  /**
2
- * The stable symbol reference: the identifier that names one declaration across
3
- * runs, across reports, in an ignore entry, in a configured root and in a
4
- * cross-language edge. It is built from names and containers only, so an edit above
5
- * a declaration leaves it unchanged, and it is compared as bytes, so there is one
6
- * canonical spelling per declaration and this module is where that spelling is
7
- * written.
8
- *
9
- * The position key of {@link ./position.ts} is the other identifier and has the
10
- * other job: it locates a finding inside one run, and the two never mix.
2
+ * The stable symbol reference: the identifier that names one declaration across runs,
3
+ * reports, ignore entries, configured roots and cross-language edges. It is built from
4
+ * names and containers only, so an edit above a declaration leaves it unchanged, and it
5
+ * is compared as bytes, so this module writes the one canonical spelling. The position
6
+ * key of {@link ./position.ts} locates a finding inside one run; the two never mix.
11
7
  */
12
8
 
13
9
  /** The language prefix, which namespaces every reference this analyzer emits. */
@@ -34,16 +30,10 @@ const SCOPE = `${PREFIX}${TS_PACKAGE}/${TS_FILE}`;
34
30
  const MANIFEST_SCOPE = `${PREFIX}${TS_PACKAGE}/${TS_DIRS}package\\.json`;
35
31
 
36
32
  /**
37
- * One expression per form the grammar defines, each anchored and each the whole of
38
- * a reference. Several forms share one expression because they differ in what the
39
- * symbol is rather than in how the reference is spelled, so the list is the set of
40
- * spellings and not the set of subjects. A reference is valid when it matches one.
41
- *
42
- * They are written here rather than read from the Contract at run time: the Contract
43
- * is data a reader outside this program consults, and a product that read it while
44
- * running would need it installed beside itself. A test compares this list against
45
- * the release this analyzer is written against, so a grammar that grows a form
46
- * arrives here as a failing test.
33
+ * One anchored expression per spelling the grammar defines; a reference is valid when it
34
+ * matches one. They are written here rather than read from the Contract at run time, so
35
+ * the product needs no Contract installed beside it; a test compares this list against
36
+ * the release this analyzer implements, so a grammar that grows a form fails it.
47
37
  */
48
38
  export const REF_EXPRESSIONS: readonly string[] = [
49
39
  `^${SCOPE}#$`,
@@ -170,7 +160,8 @@ export function aliasFragment(name: string, block?: string): string {
170
160
  return `${head}${nameComponent(name)}:alias`;
171
161
  }
172
162
 
173
- function spell(component: Component): string {
163
+ /** The canonical spelling of one component: a name, or a computed key. */
164
+ export function spell(component: Component): string {
174
165
  return component.computed ? computedComponent(component.text) : nameComponent(component.text);
175
166
  }
176
167