compress some comments

This commit is contained in:
Oleksii Bulenok
2026-09-03 21:00:42 +02:00
parent 4a9d2ee7b0
commit 7c62429270
@@ -1,26 +1,17 @@
/* /*
* Tests for babel-plugin-lexicon-leaf-imports, in three layers: * Tests for babel-plugin-lexicon-leaf-imports, in three layers:
* *
* 1. Transform unit tests: run the plugin alone over small snippets against * 1. Transform unit tests: rewrite / bail behavior on small snippets.
* the real src/lexicons tree and assert the rewrite / bail behavior.
* *
* 2. App-source proof: enumerate every chain reachable through the barrels' * 2. App-source proof: enumerate every chain the barrels expose, transform a
* own `export * as` graph (the only chains user code can write), generate * probe referencing all of them, and typecheck it with the app tsconfig -
* a probe file referencing all of them, transform it, and typecheck the * proving every rewritten specifier resolves to a real module.
* output with the app tsconfig. This proves every rewritten specifier
* resolves to a real module. The transform itself also exercises the
* plugin's verifyChain proof for every single chain.
* *
* 3. SDK dist proof: the plugin also rewrites @bsky/sdk's compiled output * 3. SDK dist proof: transform @bsky/sdk's compiled JS and typecheck it with
* (plain JS). Transform every dist file that imports the lexicon barrel * checkJs against the shipped .d.ts, via a temp mirror resolved back into
* and typecheck the result with checkJs, where imports resolve to the * the real dist with rootDirs (tsc never checks JS under node_modules).
* SDK's shipped .d.ts files - so unresolvable specifiers (TS2307) and * checkJs is noisy on compiled output, so diagnostics are diffed against
* missing members on a rewritten leaf namespace (TS2339) both surface. * an untransformed baseline: only plugin-introduced ones fail.
* tsc never checks JS under node_modules, so transformed files are
* written to a temp mirror and resolved back into the real dist via
* rootDirs. checkJs has inherent noise on compiled output, so the shadow
* diagnostics are compared against a baseline run of the untransformed
* files: only diagnostics introduced by the plugin fail the test.
*/ */
const {transformSync} = require('@babel/core') const {transformSync} = require('@babel/core')
const {parse} = require('@babel/parser') const {parse} = require('@babel/parser')
@@ -135,9 +126,8 @@ describe('transform', () => {
}) })
/* /*
* The plugin memoizes filesystem stats, barrel export maps, and verified * The plugin's module-level caches outlive individual transforms, so a
* chains in module-level caches that outlive individual transforms. A lexicon * lexicon regen inside a long-lived worker (Metro, jest --watch) must
* regen inside a long-lived worker (Metro dev server, jest --watch) must
* invalidate them - the plugin uses the root index mtime as the epoch. * invalidate them - the plugin uses the root index mtime as the epoch.
*/ */
describe('cache invalidation across a lexicon regen', () => { describe('cache invalidation across a lexicon regen', () => {
@@ -183,9 +173,8 @@ describe('cache invalidation across a lexicon regen', () => {
) )
/* /*
* Simulate `lex build --clear` deepening the leaf into a barrel. Codegen * Simulate `lex build --clear` deepening the leaf into a barrel; bump the
* rewrites the whole tree, so the root index mtime always moves; force it * root index mtime explicitly since same-millisecond writes would hide it.
* forward explicitly since same-millisecond writes would hide the change.
*/ */
write( write(
'lexicons/app/bsky/feed/like.ts', 'lexicons/app/bsky/feed/like.ts',
@@ -199,9 +188,8 @@ describe('cache invalidation across a lexicon regen', () => {
fs.utimesSync(path.join(lexRoot, 'index.ts'), bumped, bumped) fs.utimesSync(path.join(lexRoot, 'index.ts'), bumped, bumped)
/* /*
* The chain now stops at a barrel, so the correct result is a bail that * The chain now stops at a barrel: fresh caches bail, stale caches would
* keeps the barrel import. Stale caches would instead replay the rewrite * replay the rewrite against the old layout.
* against the old layout.
*/ */
const out = transform() const out = transform()
expect(out).toContain(`from './lexicons'`) expect(out).toContain(`from './lexicons'`)
@@ -210,10 +198,9 @@ describe('cache invalidation across a lexicon regen', () => {
}) })
/** /**
* Enumerate every leaf chain by following `export * as <name> from '...'` * Follow `export * as` through the barrel graph, mirroring the plugin's own
* through the barrel graph, mirroring the plugin's own leaf/barrel rule: a * leaf/barrel rule (a sibling directory means barrel). Yields chains like
* target with a sibling directory is a barrel to recurse into, otherwise a * ['app', 'bsky', 'feed', 'like'].
* leaf. Chains come out as e.g. ['app', 'bsky', 'feed', 'like'].
*/ */
function collectLeafChains(rootDir) { function collectLeafChains(rootDir) {
const chains = [] const chains = []
@@ -307,10 +294,7 @@ describe('app sources: every barrel chain rewrites and typechecks', () => {
chains.map(c => `void ${c.join('.')}`).join('\n') + chains.map(c => `void ${c.join('.')}`).join('\n') +
'\n' '\n'
/* /* Also runs the plugin's verifyChain proof for every chain. */
* This also runs the plugin's verifyChain proof for every chain: any
* filesystem/barrel divergence throws here.
*/
const out = applyPlugin(probeSource, PROBE_FILE) const out = applyPlugin(probeSource, PROBE_FILE)
expect(out).not.toContain(`from './lexicons'`) expect(out).not.toContain(`from './lexicons'`)
@@ -318,9 +302,8 @@ describe('app sources: every barrel chain rewrites and typechecks', () => {
expect(leafImports).toHaveLength(chains.length) expect(leafImports).toHaveLength(chains.length)
/* /*
* Typecheck the transformed probe with the app tsconfig. The probe is * Typecheck the probe overlaid at a virtual src/ path, so its relative
* overlaid at a virtual path inside src/ so its relative leaf imports * leaf imports resolve against the real tree.
* resolve against the real tree.
*/ */
const options = loadAppCompilerOptions() const options = loadAppCompilerOptions()
const host = createOverlayHost(options, new Map([[PROBE_FILE, out]])) const host = createOverlayHost(options, new Map([[PROBE_FILE, out]]))
@@ -335,8 +318,8 @@ describe('app sources: every barrel chain rewrites and typechecks', () => {
} }
/* /*
* Canary: prove this program setup actually flags a bad specifier, so * Canary: a bad specifier must be flagged, so a broken overlay host
* a broken overlay host cannot produce a vacuous pass. * cannot produce a vacuous pass.
*/ */
const canary = const canary =
out + `import * as _bad from './lexicons/app/bsky/feed/__nope__'\n` out + `import * as _bad from './lexicons/app/bsky/feed/__nope__'\n`
@@ -434,9 +417,8 @@ describe('@bsky/sdk dist: rewrites typecheck against shipped .d.ts', () => {
module: ts.ModuleKind.ESNext, module: ts.ModuleKind.ESNext,
moduleResolution: ts.ModuleResolutionKind.Bundler, moduleResolution: ts.ModuleResolutionKind.Bundler,
/* /*
* Relative imports in the mirror (both untouched ones like * Relative imports in the mirror resolve into the real dist,
* './api.js' and the plugin's '../lexicons/...' rewrites) resolve * landing on its .d.ts files.
* into the real dist, landing on its .d.ts files.
*/ */
rootDirs: [path.join(mirrors[kind], 'dist'), SDK_DIST], rootDirs: [path.join(mirrors[kind], 'dist'), SDK_DIST],
} }
@@ -454,10 +436,8 @@ describe('@bsky/sdk dist: rewrites typecheck against shipped .d.ts', () => {
} }
/* /*
* Canary: prove the checkJs machinery actually checks members through * Canary: a known-bad member access must be flagged, proving checkJs
* the SDK's .d.ts files. If this setup ever degrades to not-checking, * actually checks through the SDK's .d.ts files.
* a real regression would pass silently - so require a known-bad
* member access to be flagged.
*/ */
{ {
const canary = path.join(mirrors.shadow, 'dist', '__canary__.js') const canary = path.join(mirrors.shadow, 'dist', '__canary__.js')
@@ -508,24 +488,16 @@ describe('app callsites: transformed sources typecheck', () => {
/* /*
* The real-usage complement to the probe: transform every app file that * The real-usage complement to the probe: transform every app file that
* imports the barrel - with babel-plugin-module-resolver ahead of the * imports the barrel - with babel-plugin-module-resolver ahead of the
* plugin, as in babel.config.js, so the '#/lexicons' -> relative-path * plugin, as in babel.config.js - and typecheck the output in place of the
* interop and ordering are exercised - and typecheck the transformed files * originals.
* in place of the originals.
* *
* Types are kept (no preset-typescript) so tsc has something to check. * Types are kept (no preset-typescript), so unlike production the type
* One behavioral difference follows: in the real pipeline type-only * positions still need a specifier the plugin drops; those names are
* references are stripped before the plugin's Program exit, so removing a * re-added as a type-only barrel import - their production status anyway.
* fully-rewritten specifier is always safe there. Here type positions
* survive, and Babel's scope does not count them as references - so when
* the plugin drops a specifier the type positions still need it. Those
* names are re-added as a type-only barrel import, which is exactly their
* production status: erased at runtime, checked against the barrel.
* *
* checked-vs-baseline: diagnostics of each transformed file are compared * Diagnostics are diffed against a baseline of the same file through the
* against the same file run through the identical parse/print pipeline * identical pipeline without the plugin, so reprinting artifacts affect
* WITHOUT the leaf plugin. Reprinting artifacts (e.g. a reflowed * both sides equally and diff out - only plugin-caused differences fail.
* ts-expect-error directive missing its line) then affect both sides
* equally and diff out - only differences the plugin caused can fail.
*/ */
test( test(
'every file importing the barrel', 'every file importing the barrel',
@@ -595,9 +567,8 @@ describe('app callsites: transformed sources typecheck', () => {
} }
/* /*
* Files whose shadow output is byte-identical to the baseline output * A shadow byte-identical to its baseline cannot produce a diagnostics
* cannot produce a diagnostics diff, so only changed files are overlaid, * diff, so only changed files are overlaid and checked.
* typechecked, and compared - a bit under half of the consumers.
*/ */
const shadowOverlays = new Map() const shadowOverlays = new Map()
const baselineOverlays = new Map() const baselineOverlays = new Map()
@@ -618,16 +589,11 @@ describe('app callsites: transformed sources typecheck', () => {
const options = loadAppCompilerOptions() const options = loadAppCompilerOptions()
/* /*
* One program holds both versions of every changed consumer: the * One program holds both versions: the baseline at the real path, the
* baseline at the file's real path and the shadow at a virtual * shadow at a virtual `.__shadow__.` sibling (same dir and extension,
* `.__shadow__.` sibling path - same directory and extension, so every * so import resolution behaves identically). This parses the shared
* relative/aliased import and platform-extension resolution behaves as * app + node_modules closure once - the dominant cost - where separate
* it would from the real file. The two versions differ only in these * programs would each redo it.
* consumer files; everything they import resolves to the same modules.
* A single program therefore parses and binds the shared app +
* node_modules closure once, where separate baseline and shadow
* programs would each redo it - that closure, not checking the roots,
* dominates the cost.
*/ */
const shadowPath = f => f.replace(/\.(tsx?)$/, '.__shadow__.$1') const shadowPath = f => f.replace(/\.(tsx?)$/, '.__shadow__.$1')
const overlays = new Map() const overlays = new Map()
@@ -639,9 +605,8 @@ describe('app callsites: transformed sources typecheck', () => {
const program = ts.createProgram([...overlays.keys()], options, host) const program = ts.createProgram([...overlays.keys()], options, host)
/* /*
* Shadow-file diagnostics may spell the virtual path inside messages; * Normalize the virtual path spelling inside messages so it alone
* normalize it away so a diagnostic differing only in that spelling * never counts as a regression.
* does not count as a regression.
*/ */
const diagKey = d => const diagKey = d =>
`TS${d.code}: ${ts `TS${d.code}: ${ts