You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 0ea3822
Browse filesBrowse the repository at this point in the historyBrowse files
The pre-push test selection attributes a change inside a named export list (`export { a, b as c } from '…'`) to the names on the changed lines, so adding one name to a package barrel no longer selects every test that reaches the barrel. A change to the list's braces, its `from` clause, a one-line list or an `export *` still makes the whole file affected.
Copy file name to clipboardExpand all lines: apps/cli/specs/self-hosting.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -108,7 +108,7 @@ An ordinary modification selects none of them. `apps/cli/tests/lib/pre-push-scan
108
108
109
109
**Resolution is the TypeScript compiler's, not a text scan.** A regular expression can read the specifier `'./demo.js'`; it cannot know the file on disk is `demo.ts`. This repository writes 482 of its 1275 relative import specifiers with the extension the EMIT will have, which is what TypeScript's own ESM guidance says to do — and every one of those edges was absent from the regex graph, across 144 importer files and 104 distinct targets. The visible symptom: a change to `apps/cli/src/commands/demo.ts` selected no test at all, though `apps/cli/tests/demo.test.ts` imports it by name. A selector that drops edges does not over-select; it silently under-selects, and its reported reductions are lost edges wearing precision's clothes. `lib/ts-module-graph.ts` now resolves every specifier with `ts.resolveModuleName` and follows each imported name to its defining file along the checker's own alias chain, hop by hop, so a re-export chain and a cross-package barrel both resolve to the file that actually defines the name. The compiler is resolved at runtime from the repository under analysis (`createRequire`), never bundled into the published artifact and never added to an adopter's install; a repository without it falls back to the text-scan graph, which is a strict over-approximation.
110
110
111
-
**Selection follows the changed exported NAMES, not the changed file.**`lib/changed-names.ts` attributes each diff hunk to the top-level declarations it touches — on both sides of the diff, so a deleted declaration is attributed too — and closes that set backwards over intra-file references, since a change to a local helper affects every exported declaration that uses it. A test is selected when its import closure reaches a USE of an affected name. Any hunk that cannot be attributed to exactly one declaration — module-scope code, an `import`/`export` statement, an `export *`, `export default`, a destructuring binding, an unparseable region, a range outside every declaration — makes the whole file affected, which is the file-level answer; so is a changed file whose names were never computed. Narrowing is something the selector has to earn, every time.
111
+
**Selection follows the changed exported NAMES, not the changed file.** `lib/changed-names.ts` attributes each diff hunk to the top-level declarations it touches — on both sides of the diff, so a deleted declaration is attributed too — and closes that set backwards over intra-file references, since a change to a local helper affects every exported declaration that uses it. A test is selected when its import closure reaches a USE of an affected name. A hunk inside a named export list — `export { a, b as c } from '…'` or `export { a, b }` — is attributed to the specifiers written on its lines, by the name each EXPORTS (`c`, the `as` alias, not `b`), so a one-name addition to a package barrel selects only the tests that import that name, which before the change is none; a local list's exported name is also affected whenever the declaration it names is. Only the lines strictly between the list's braces narrow: a hunk on the `export {` line, the `}` line, the `from` clause or the module specifier re-points every name the statement exports, and so does a one-line list, whose single line holds all of them. Any other hunk that cannot be attributed to exactly one declaration — module-scope code, an `import` statement, an `export` statement outside a named list's specifier lines, an `export *`, `export default`, a destructuring binding, an unparseable region, a range outside every declaration — makes the whole file affected, which is the file-level answer; so is a changed file whose names were never computed. Narrowing is something the selector has to earn, every time.
112
112
113
113
A bare workspace-package import is not treated as a dependency on the whole package: the imported NAMES are resolved through the target package's declared entrypoint (`exports`/`main`, handed to the compiler as `paths` so the answer does not depend on the install layout) and its named, aliased, star and cross-package re-export graph, to the files that actually define them. Every shape the compiler cannot prove keeps the whole-package edge — a namespace, default, side-effect or dynamic import, an `export *` supplying one name from two sources, `import x = require(...)`, an alias chain that does not terminate in a declaration, or a package whose entrypoint cannot be derived from its manifest — so the refinement can over-select but never omits a truly affected test.
0 commit comments