-
Notifications
You must be signed in to change notification settings - Fork 5k
node:module: list node:test in builtinModules #39700
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
robobun
wants to merge
4
commits into
main
Choose a base branch
from
farm/dd1f684a/builtin-modules-node-test
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+91
−5
Open
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
8baf99b
node:module: list node:test in builtinModules
robobun 08b77b7
Lint the builtin module tables against each other
robobun f815c68
Shorten the builtinModuleNames comment
robobun f06a92c
Only correct the first sentence of the builtinModuleNames comment
robobun File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| import { expect, test } from "bun:test"; | ||
| import { readFileSync } from "node:fs"; | ||
| import path from "node:path"; | ||
|
|
||
| // The names of the builtin modules live in three hand-written tables: | ||
| // | ||
| // - builtinModuleNames in src/jsc/modules/NodeModuleModule.cpp is module.builtinModules. | ||
| // - builtinModuleNamesSortedLength in src/jsc/bindings/isBuiltinModule.cpp is what module.isBuiltin() | ||
| // accepts (and what Bun.plugin refuses to override). | ||
| // - node_entry_only_prefix!() in src/resolve_builtins/HardcodedModule.rs marks the builtins that the module | ||
| // loader resolves with the "node:" prefix only. Node lists those in builtinModules with the prefix. | ||
| // | ||
| // Nothing else compares them. A new module tends to land in the last two and not in the first: "node:test" | ||
| // was missing from builtinModules for over a year while isBuiltin("node:test") was true. This lint requires | ||
| // every name isBuiltin() accepts to be listed in builtinModules, unless notListed says why it is not. | ||
|
|
||
| // isBuiltin() names that builtinModules leaves out on purpose, with the reason. The lint fails while an entry | ||
| // here is listed after all, or is no longer accepted by isBuiltin(). | ||
| const internalPlumbing = | ||
| "internal plumbing, not a public module (#31831). isBuiltin() accepts it so that Bun.plugin refuses to override it."; | ||
| const notListed: Record<string, string> = { | ||
| "bun:main": internalPlumbing, | ||
| "bun:wrap": internalPlumbing, | ||
| "node:quic": "experimental. Stock Node 26 builds do not list it either: QUIC is compiled out of them.", | ||
| }; | ||
|
|
||
| const builtinModulesFile = "src/jsc/modules/NodeModuleModule.cpp"; | ||
| const isBuiltinFile = "src/jsc/bindings/isBuiltinModule.cpp"; | ||
| const resolverFile = "src/resolve_builtins/HardcodedModule.rs"; | ||
| const root = path.resolve(import.meta.dir, "..", "..", ".."); | ||
|
|
||
| function asciiLiteralTable(file: string, name: string): Set<string> { | ||
| const source = readFileSync(path.join(root, file), "utf8"); | ||
| const table = new RegExp(String.raw`\b${name}\[\] = \{([^}]*)\};`).exec(source); | ||
| if (table === null) throw new Error(`${file} no longer defines the table ${name}[]`); | ||
| const names = new Set(Array.from(table[1].matchAll(/"([^"]+)"_s/g), m => m[1])); | ||
| if (names.size === 0) throw new Error(`${file}: the table ${name}[] has no "..."_s entries`); | ||
| return names; | ||
| } | ||
|
|
||
| const builtinModules = asciiLiteralTable(builtinModulesFile, "builtinModuleNames"); | ||
| const isBuiltin = asciiLiteralTable(isBuiltinFile, "builtinModuleNamesSortedLength"); | ||
| const onlyPrefix = Array.from( | ||
| readFileSync(path.join(root, resolverFile), "utf8").matchAll(/\bnode_entry_only_prefix!\("([^"]+)"\)/g), | ||
| m => m[1], | ||
| ); | ||
| if (onlyPrefix.length === 0) throw new Error(`${resolverFile} has no node_entry_only_prefix!() entries`); | ||
|
|
||
| test(`${builtinModulesFile} lists every name ${isBuiltinFile} accepts, unless notListed says why not`, () => { | ||
| const missing = [...isBuiltin].filter(name => !builtinModules.has(name) && !Object.hasOwn(notListed, name)).sort(); | ||
| expect(missing).toEqual([]); | ||
| }); | ||
|
|
||
| test(`${isBuiltinFile} accepts every name ${builtinModulesFile} lists`, () => { | ||
| const unknown = [...builtinModules].filter(name => !isBuiltin.has(name)).sort(); | ||
| expect(unknown).toEqual([]); | ||
| }); | ||
|
|
||
| test(`${isBuiltinFile} accepts every prefix-only builtin of ${resolverFile} under its prefixed name`, () => { | ||
| const unknown = onlyPrefix.filter(name => !isBuiltin.has(name)).sort(); | ||
| expect(unknown).toEqual([]); | ||
| }); | ||
|
|
||
| test("notListed names only entries that isBuiltin() still accepts and builtinModules still leaves out", () => { | ||
| const stale = Object.keys(notListed) | ||
| .flatMap(name => { | ||
| if (!isBuiltin.has(name)) return [`${name} is no longer in ${isBuiltinFile}; delete its entry`]; | ||
| if (builtinModules.has(name)) return [`${name} is listed in ${builtinModulesFile} now; delete its entry`]; | ||
| return []; | ||
| }) | ||
| .sort(); | ||
| expect(stale).toEqual([]); | ||
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.