diff --git a/package-lock.json b/package-lock.json index 301b682d..9676ac09 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1436,6 +1436,10 @@ "resolved": "recipes/process-main-module", "link": true }, + "node_modules/@nodejs/repl-builtin-modules": { + "resolved": "recipes/repl-builtin-modules", + "link": true + }, "node_modules/@nodejs/rmdir": { "resolved": "recipes/rmdir", "link": true @@ -2033,9 +2037,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001727", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001727.tgz", - "integrity": "sha512-pB68nIHmbN6L/4C6MH1DokyR3bYqFwjaSs/sWDHGj4CTcFtQUQMuJftVwWkXq7mNWOybD3KhUv3oWHoGxgP14Q==", + "version": "1.0.30001731", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001731.tgz", + "integrity": "sha512-lDdp2/wrOmTRWuoB5DpfNkC0rJDU8DqRa6nYL6HK6sytw70QMopt/NIc/9SM7ylItlBWfACXk0tEn37UWM/+mg==", "funding": [ { "type": "opencollective", @@ -2351,9 +2355,9 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.191", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.191.tgz", - "integrity": "sha512-xcwe9ELcuxYLUFqZZxL19Z6HVKcvNkIwhbHUz7L3us6u12yR+7uY89dSl570f/IqNthx8dAw3tojG7i4Ni4tDA==", + "version": "1.5.192", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.192.tgz", + "integrity": "sha512-rP8Ez0w7UNw/9j5eSXCe10o1g/8B1P5SM90PCCMVkIRQn2R0LEHWz4Eh9RnxkniuDe1W0cTSOB3MLlkTGDcuCg==", "license": "ISC" }, "node_modules/emoji-regex": { @@ -3364,9 +3368,9 @@ } }, "node_modules/openai/node_modules/@types/node": { - "version": "18.19.120", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.120.tgz", - "integrity": "sha512-WtCGHFXnVI8WHLxDAt5TbnCM4eSE+nI0QN2NJtwzcgMhht2eNz6V9evJrk+lwC8bCY8OWV5Ym8Jz7ZEyGnKnMA==", + "version": "18.19.121", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.121.tgz", + "integrity": "sha512-bHOrbyztmyYIi4f1R0s17QsPs1uyyYnGcXeZoGEd227oZjry0q6XQBQxd82X1I57zEfwO8h9Xo+Kl5gX1d9MwQ==", "license": "MIT", "dependencies": { "undici-types": "~5.26.4" @@ -4236,6 +4240,17 @@ "@codemod.com/jssg-types": "^1.0.9" } }, + "recipes/repl-builtin-modules": { + "name": "@nodejs/repl-builtin-modules", + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@nodejs/codemod-utils": "*" + }, + "devDependencies": { + "@codemod.com/jssg-types": "^1.0.3" + } + }, "recipes/rmdir": { "name": "@nodejs/rmdir", "version": "1.1.0", diff --git a/recipes/repl-builtin-modules/README.md b/recipes/repl-builtin-modules/README.md new file mode 100644 index 00000000..e33811b9 --- /dev/null +++ b/recipes/repl-builtin-modules/README.md @@ -0,0 +1,23 @@ +# `repl.builtinModules` DEP0191 + +This recipe provides a guide for migrating from the deprecated `repl.builtinModules` & `repl._builtinLibs` to the new `module.builtinModules` property in Node.js. + +See [DEP0191](https://nodejs.org/api/deprecations.html#DEP0191) and [DEP0142](https://nodejs.org/api/deprecations.html#DEP0142) + +## Examples + +**Before:** +```js +import repl from 'node:repl'; + +console.log(repl.builtinModules); +console.log(repl._builtinLibs); +``` + +**After:** +```js +import module from 'node:module'; + +console.log(module.builtinModules); +console.log(module.builtinModules); +``` diff --git a/recipes/repl-builtin-modules/codemod.yaml b/recipes/repl-builtin-modules/codemod.yaml new file mode 100644 index 00000000..d4f0e97d --- /dev/null +++ b/recipes/repl-builtin-modules/codemod.yaml @@ -0,0 +1,22 @@ +schema_version: "1.0" +name: "@nodejs/repl-builtin-modules" +version: 1.0.0 +description: Handle DEP0191 via transforming `repl.builtinModules` usage to `module.builtinModules`. +author: Augustin Mauroy +license: MIT +workflow: workflow.yaml +category: migration + +targets: + languages: + - javascript + - typescript + +keywords: + - transformation + - migration + - deprecation + +registry: + access: public + visibility: public diff --git a/recipes/repl-builtin-modules/package.json b/recipes/repl-builtin-modules/package.json new file mode 100644 index 00000000..33b01b2c --- /dev/null +++ b/recipes/repl-builtin-modules/package.json @@ -0,0 +1,25 @@ +{ + "name": "@nodejs/repl-builtin-modules", + "version": "1.0.0", + "description": "Handle DEP0191 via transforming `repl.builtinModules` usage to `module.builtinModules`.", + "type": "module", + "scripts": { + "test": "npx codemod@next jssg test -l typescript ./src/workflow.ts ./", + "test:update-snapshots": "npx codemod@next jssg test --update-snapshots -l typescript ./src/workflow.ts ./ " + }, + "repository": { + "type": "git", + "url": "git+https://github.com/nodejs/userland-migrations.git", + "directory": "recipes/repl-builtin-modules", + "bugs": "https://github.com/nodejs/userland-migrations/issues" + }, + "author": "Augustin Mauroy", + "license": "MIT", + "homepage": "https://github.com/nodejs/userland-migrations/blob/main/recipes/repl-builtin-modules/README.md", + "devDependencies": { + "@codemod.com/jssg-types": "^1.0.3" + }, + "dependencies": { + "@nodejs/codemod-utils": "*" + } +} diff --git a/recipes/repl-builtin-modules/src/workflow.ts b/recipes/repl-builtin-modules/src/workflow.ts new file mode 100644 index 00000000..25c4a899 --- /dev/null +++ b/recipes/repl-builtin-modules/src/workflow.ts @@ -0,0 +1,404 @@ +import { EOL } from "node:os"; +import { getNodeImportStatements } from "@nodejs/codemod-utils/ast-grep/import-statement"; +import { getNodeRequireCalls } from "@nodejs/codemod-utils/ast-grep/require-call"; +import { resolveBindingPath } from "@nodejs/codemod-utils/ast-grep/resolve-binding-path"; +import type { SgRoot, Edit, SgNode } from "@codemod.com/jssg-types/main"; +import type JS from "@codemod.com/jssg-types/langs/javascript"; + +/** + * Transform function that converts deprecated repl.builtinModules and repl._builtinLibs + * to module.builtinModules API. + * + * See https://nodejs.org/api/deprecations.html#DEP0191 + * + * Handles: + * 1. const repl = require('node:repl'); repl.builtinModules → const module = require('node:module'); module.builtinModules + * 2. const { builtinModules } = require('node:repl'); → const { builtinModules } = require('node:module'); + * 3. const { builtinModules, foo } = require('node:repl'); → const { foo } = require('node:repl'); const { builtinModules } = require('node:module'); + * 4. import { builtinModules } from 'node:repl'; → import { builtinModules } from 'node:module'; + * 5. import { builtinModules, foo } from 'node:repl'; → import { foo } from 'node:repl'; import { builtinModules } from 'node:module'; + * 6. const repl = require('node:repl'); repl._builtinLibs → const module = require('node:module'); module.builtinModules + * 7. const { _builtinLibs } = require('node:repl'); → const { builtinModules } = require('node:module'); + * 8. import { _builtinLibs } from 'node:repl'; → import { builtinModules } from 'node:module'; + */ +export default function transform(root: SgRoot): string | null { + const rootNode = root.root(); + const edits: Edit[] = []; + // Reusable quoted module specifier for generating new statements + const newModule = "'node:module'"; + + // Step 1: Handle require statements + const replRequireStatements = getNodeRequireCalls(root, "repl"); + + for (const statement of replRequireStatements) { + const objectPattern = statement.find({ rule: { kind: "object_pattern" } }); + + if (objectPattern) { + const originalText = objectPattern.text(); + + if (containsBuiltinProperties(originalText)) { + const properties = objectPattern.findAll({ + rule: { kind: "shorthand_property_identifier_pattern" } + }); + const pairProperties = objectPattern.findAll({ + rule: { kind: "pair_pattern" } + }); + + // Check if only builtin properties are destructured + const builtinShorthandCount = properties.filter(p => + containsBuiltinProperties(p.text()) + ).length; + + const builtinPairCount = pairProperties.filter(p => + containsBuiltinProperties(p.text()) + ).length; + + const totalBuiltinCount = builtinShorthandCount + builtinPairCount; + const totalCount = properties.length + pairProperties.length; + + const isOnlyBuiltin = totalCount > 0 && totalBuiltinCount === totalCount; + + if (isOnlyBuiltin) { + // Replace entire require statement + updateModuleSpecifier(statement, edits); + + if (originalText.includes("_builtinLibs")) { + const newText = originalText.replace("_builtinLibs", "builtinModules"); + edits.push(objectPattern.replace(newText)); + replaceStandaloneBuiltinLibsReferences(rootNode, edits); + } + } else { + // Split into two statements + const propertiesToKeep: string[] = []; + const builtinAliases: string[] = []; // Change to array to handle multiple aliases + + for (const prop of properties) { + const propText = prop.text(); + if (propText !== "builtinModules" && propText !== "_builtinLibs") { + propertiesToKeep.push(propText); + } + } + + for (const prop of pairProperties) { + const propText = prop.text(); + + if (containsBuiltinProperties(propText)) { + // Extract alias from pair pattern like "builtinModules: alias" or "_builtinLibs: alias" + const keyNode = prop.find({ rule: { kind: "property_identifier" } }); + const valueNode = prop.find({ rule: { kind: "identifier" } }); + + if ( + keyNode && + valueNode && + containsBuiltinProperties(keyNode.text()) + ) { + builtinAliases.push(valueNode.text()); + } + } else { + propertiesToKeep.push(propText); + } + } + + if (propertiesToKeep.length > 0) { + const variableDeclaration = statement.parent(); + const moduleSpecifier = statement.find({ rule: { kind: "string" } }); + + if (variableDeclaration && moduleSpecifier) { + const currentModule = moduleSpecifier.text(); + + const reconstructedText = `{ ${propertiesToKeep.join(", ")} }`; + const firstStatement = `const ${reconstructedText} = require(${currentModule});`; + + // Always use builtinModules without alias for the new module import + const secondStatement = `const { builtinModules } = require(${newModule});`; + const replacementText = `${firstStatement}${EOL}${secondStatement}`; + + edits.push(variableDeclaration.replace(replacementText)); + + // Replace all alias references to use builtinModules + for (const alias of builtinAliases) { + const aliasReferences = rootNode.findAll({ + rule: { pattern: alias } + }); + + for (const ref of aliasReferences) { + const parent = ref.parent(); + + if ( + parent && + parent.kind() !== "object_pattern" && + parent.kind() !== "pair_pattern" && + parent.kind() !== "variable_declarator" + ) { + edits.push(ref.replace("builtinModules")); + } + } + } + + if (originalText.includes("_builtinLibs")) { + replaceStandaloneBuiltinLibsReferences(rootNode, edits); + } + } + } + } + } + } else { + // Handle namespace require (const repl = require('node:repl')) + const variableDeclarator = statement.find({ rule: { kind: "variable_declarator" } }); + + if (variableDeclarator) { + const builtinModulesPath = resolveBindingPath(variableDeclarator, "$.builtinModules"); + const builtinLibsPath = resolveBindingPath(variableDeclarator, "$._builtinLibs"); + + const usages = rootNode.findAll({ + rule: { + any: [ + { pattern: builtinModulesPath }, + { pattern: builtinLibsPath } + ] + } + }); + + if (usages.length > 0) { + const identifier = variableDeclarator.find({ + rule: { kind: "identifier" } + }); + + if (identifier) { + edits.push(identifier.replace("module")); + updateModuleSpecifier(statement, edits); + + for (const memberExpr of usages) { + edits.push(memberExpr.replace("module.builtinModules")); + } + } + } + } + } + } + + // Step 2: Handle import statements + const replImportStatements = getNodeImportStatements(root, "repl"); + + for (const statement of replImportStatements) { + const namedImports = statement.find({ rule: { kind: "named_imports" } }); + + if (namedImports) { + const originalText = namedImports.text(); + + if (containsBuiltinProperties(originalText)) { + const importSpecifiers = namedImports.findAll({ + rule: { kind: "import_specifier" } + }); + + const isOnlyBuiltin = importSpecifiers.length === 1 && + containsBuiltinProperties(importSpecifiers[0].text()); + + if (isOnlyBuiltin) { + // Replace entire import statement + updateModuleSpecifier(statement, edits); + + if (originalText.includes("_builtinLibs")) { + const newText = originalText.replace("_builtinLibs", "builtinModules"); + edits.push(namedImports.replace(newText)); + replaceStandaloneBuiltinLibsReferences(rootNode, edits); + } + } else { + // Split into two statements + const newText = originalText + .replace(/,?\s*(builtinModules|_builtinLibs)\s*(as\s+\w+)?\s*,?/g, "") + .replace(/,\s*$/, "") + .replace(/^\s*,/, ""); + edits.push(namedImports.replace(newText)); + + const moduleSpecifier = statement.find({ rule: { kind: "string" } }); + + if (moduleSpecifier) { + const aliasMatch = originalText.match(/(builtinModules|_builtinLibs)\s*(as\s+\w+)/); + const aliasText = aliasMatch ? ` ${aliasMatch[2]}` : ""; + const newStatement = `import { builtinModules${aliasText} } from ${newModule};`; + const statementEnd = statement.range().end; + + edits.push({ + startPos: statementEnd.index, + endPos: statementEnd.index, + insertedText: `${EOL}${newStatement}` + }); + + if (originalText.includes("_builtinLibs") && !aliasText) { + replaceStandaloneBuiltinLibsReferences(rootNode, edits); + } + } + } + } + } else { + // Handle default/namespace imports + const importClause = statement.find({ rule: { kind: "import_clause" } }); + if (!importClause) continue; + + // Use resolveBindingPath to determine how builtinModules should be accessed + const builtinModulesPath = resolveBindingPath(importClause, "$.builtinModules"); + const builtinLibsPath = resolveBindingPath(importClause, "$._builtinLibs"); + + const expressions = rootNode.findAll({ + rule: { + any: [ + { pattern: builtinModulesPath }, + { pattern: builtinLibsPath } + ] + } + }); + + if (expressions.length > 0) { + updateModuleSpecifier(statement, edits); + + // Get the namespace identifier to maintain consistency + let importIdentifier = importClause.find({ rule: { kind: "identifier" } }); + if (!importIdentifier) { + const namespaceImport = importClause.find({ + rule: { kind: "namespace_import" } + }); + + if (namespaceImport) { + importIdentifier = namespaceImport.find({ rule: { kind: "identifier" } }); + } + } + + const varName = importIdentifier?.text() || "module"; + for (const memberExpr of expressions) { + edits.push(memberExpr.replace(`${varName}.builtinModules`)); + } + } + } + } + + // Step 3: Handle dynamic imports + const dynamicImportDeclarators = rootNode.findAll({ + rule: { + kind: "variable_declarator", + has: { + field: "value", + kind: "await_expression", + has: { + kind: "call_expression", + all: [ + { + has: { + field: "function", + kind: "import" + } + }, + { + has: { + field: "arguments", + kind: "arguments", + has: { + kind: "string", + has: { + kind: "string_fragment", + regex: "(node:)?repl$" + } + } + } + } + ] + } + } + } + }); + + for (const variableDeclarator of dynamicImportDeclarators) { + // Find the string fragment to replace + const stringFragment = variableDeclarator.find({ + rule: { + kind: "string_fragment", + regex: "(node:)?repl$" + } + }); + + if (stringFragment) { + edits.push(stringFragment.replace("node:module")); + } + + // Handle the variable assignment for dynamic imports + const objectPattern = variableDeclarator.find({ + rule: { kind: "object_pattern" } + }); + + if (objectPattern) { + // For cases like: const { builtinModules } = await import('node:repl'); + const originalText = objectPattern.text(); + if (containsBuiltinProperties(originalText)) { + if (originalText.includes("_builtinLibs")) { + const newText = originalText.replace("_builtinLibs", "builtinModules"); + edits.push(objectPattern.replace(newText)); + replaceStandaloneBuiltinLibsReferences(rootNode, edits); + } + } + } else { + // For cases like: const repl = await import('node:repl'); + const identifier = variableDeclarator.find({ + rule: { kind: "identifier" } + }); + + if (identifier) { + const builtinModulesPath = resolveBindingPath(variableDeclarator, "$.builtinModules"); + const builtinLibsPath = resolveBindingPath(variableDeclarator, "$._builtinLibs"); + + const usages = rootNode.findAll({ + rule: { + any: [ + { pattern: builtinModulesPath }, + { pattern: builtinLibsPath } + ] + } + }); + + if (usages.length > 0) { + // Replace variable name from 'repl' to 'module' + edits.push(identifier.replace("module")); + + // Replace all usages to use builtinModules + for (const usage of usages) { + edits.push(usage.replace("module.builtinModules")); + } + } + } + } + } + + if (!edits.length) return null; + + return rootNode.commitEdits(edits); +} + +const replaceStandaloneBuiltinLibsReferences = (rootNode: SgNode, edits: Edit[]): void => { + const standaloneReferences = rootNode.findAll({ + rule: { pattern: "_builtinLibs" } + }); + + for (const ref of standaloneReferences) { + const parent = ref.parent(); + + if ( + parent + && parent.kind() !== "object_pattern" + && parent.kind() !== "member_expression" + && parent.kind() !== "named_imports" + ) { + edits.push(ref.replace("builtinModules")); + } + } +}; + +const containsBuiltinProperties = (text: string): boolean => + text.includes("builtinModules") || text.includes("_builtinLibs"); + +const updateModuleSpecifier = (statement: SgNode, edits: Edit[]): void => { + const moduleSpecifier = statement.find({ rule: { kind: "string_fragment" } }); + + if (moduleSpecifier) { + // Always use 'node:module' + edits.push(moduleSpecifier.replace('node:module')); + } + }; diff --git a/recipes/repl-builtin-modules/tests/expected/file-1.js b/recipes/repl-builtin-modules/tests/expected/file-1.js new file mode 100644 index 00000000..ed06d798 --- /dev/null +++ b/recipes/repl-builtin-modules/tests/expected/file-1.js @@ -0,0 +1,4 @@ +const module = require('node:module'); + +console.log(module.builtinModules); +console.log(module.builtinModules); diff --git a/recipes/repl-builtin-modules/tests/expected/file-2.js b/recipes/repl-builtin-modules/tests/expected/file-2.js new file mode 100644 index 00000000..9e801c95 --- /dev/null +++ b/recipes/repl-builtin-modules/tests/expected/file-2.js @@ -0,0 +1,5 @@ +const { builtinModules } = require('node:module'); +const { builtinModules } = require('node:module'); + +console.log(builtinModules); +console.log(builtinModules); diff --git a/recipes/repl-builtin-modules/tests/expected/file-3.js b/recipes/repl-builtin-modules/tests/expected/file-3.js new file mode 100644 index 00000000..0e74922b --- /dev/null +++ b/recipes/repl-builtin-modules/tests/expected/file-3.js @@ -0,0 +1,3 @@ +const { builtinModules: nodeBuiltinModules } = require('node:module'); + +console.log(nodeBuiltinModules); diff --git a/recipes/repl-builtin-modules/tests/expected/file-4.js b/recipes/repl-builtin-modules/tests/expected/file-4.js new file mode 100644 index 00000000..bac625ee --- /dev/null +++ b/recipes/repl-builtin-modules/tests/expected/file-4.js @@ -0,0 +1,7 @@ +const { foo } = require('node:repl'); +const { builtinModules } = require('node:module'); + +console.log(builtinModules); +console.log(builtinModules); + +foo(); // does something else diff --git a/recipes/repl-builtin-modules/tests/expected/file-5.js b/recipes/repl-builtin-modules/tests/expected/file-5.js new file mode 100644 index 00000000..bac625ee --- /dev/null +++ b/recipes/repl-builtin-modules/tests/expected/file-5.js @@ -0,0 +1,7 @@ +const { foo } = require('node:repl'); +const { builtinModules } = require('node:module'); + +console.log(builtinModules); +console.log(builtinModules); + +foo(); // does something else diff --git a/recipes/repl-builtin-modules/tests/expected/file-6.mjs b/recipes/repl-builtin-modules/tests/expected/file-6.mjs new file mode 100644 index 00000000..970e5bc7 --- /dev/null +++ b/recipes/repl-builtin-modules/tests/expected/file-6.mjs @@ -0,0 +1,7 @@ +import { foo } from 'node:repl'; +import { builtinModules } from 'node:module'; + +console.log(builtinModules); +console.log(builtinModules); + +foo(); // does something else diff --git a/recipes/repl-builtin-modules/tests/expected/file-7.mjs b/recipes/repl-builtin-modules/tests/expected/file-7.mjs new file mode 100644 index 00000000..5782c64d --- /dev/null +++ b/recipes/repl-builtin-modules/tests/expected/file-7.mjs @@ -0,0 +1,5 @@ +import repl from 'node:module'; +import * as nodeRepl from 'node:module'; + +console.log(repl.builtinModules); +console.log(nodeRepl.builtinModules); diff --git a/recipes/repl-builtin-modules/tests/expected/file-8.mjs b/recipes/repl-builtin-modules/tests/expected/file-8.mjs new file mode 100644 index 00000000..fd67a170 --- /dev/null +++ b/recipes/repl-builtin-modules/tests/expected/file-8.mjs @@ -0,0 +1,3 @@ +import { builtinModules as nodeBuiltinModules } from 'node:module'; + +console.log(nodeBuiltinModules); diff --git a/recipes/repl-builtin-modules/tests/expected/file-9.mjs b/recipes/repl-builtin-modules/tests/expected/file-9.mjs new file mode 100644 index 00000000..9ca0454d --- /dev/null +++ b/recipes/repl-builtin-modules/tests/expected/file-9.mjs @@ -0,0 +1,6 @@ +const { builtinModules } = await import('node:module'); +const module = await import('node:module'); + +console.log(builtinModules); +console.log(module.builtinModules); +console.log(module.builtinModules); diff --git a/recipes/repl-builtin-modules/tests/input/file-1.js b/recipes/repl-builtin-modules/tests/input/file-1.js new file mode 100644 index 00000000..1234f9c7 --- /dev/null +++ b/recipes/repl-builtin-modules/tests/input/file-1.js @@ -0,0 +1,4 @@ +const repl = require('node:repl'); + +console.log(repl.builtinModules); +console.log(repl._builtinLibs); diff --git a/recipes/repl-builtin-modules/tests/input/file-2.js b/recipes/repl-builtin-modules/tests/input/file-2.js new file mode 100644 index 00000000..a1994a4f --- /dev/null +++ b/recipes/repl-builtin-modules/tests/input/file-2.js @@ -0,0 +1,5 @@ +const { builtinModules } = require('node:repl'); +const { _builtinLibs } = require('node:repl'); + +console.log(builtinModules); +console.log(_builtinLibs); diff --git a/recipes/repl-builtin-modules/tests/input/file-3.js b/recipes/repl-builtin-modules/tests/input/file-3.js new file mode 100644 index 00000000..07dc1558 --- /dev/null +++ b/recipes/repl-builtin-modules/tests/input/file-3.js @@ -0,0 +1,3 @@ +const { builtinModules: nodeBuiltinModules } = require('node:repl'); + +console.log(nodeBuiltinModules); diff --git a/recipes/repl-builtin-modules/tests/input/file-4.js b/recipes/repl-builtin-modules/tests/input/file-4.js new file mode 100644 index 00000000..66742ecc --- /dev/null +++ b/recipes/repl-builtin-modules/tests/input/file-4.js @@ -0,0 +1,6 @@ +const { builtinModules, foo, _builtinLibs } = require('node:repl'); + +console.log(builtinModules); +console.log(_builtinLibs); + +foo(); // does something else diff --git a/recipes/repl-builtin-modules/tests/input/file-5.js b/recipes/repl-builtin-modules/tests/input/file-5.js new file mode 100644 index 00000000..71c08aef --- /dev/null +++ b/recipes/repl-builtin-modules/tests/input/file-5.js @@ -0,0 +1,6 @@ +const { builtinModules: quez, foo, _builtinLibs: quux } = require('node:repl'); + +console.log(quez); +console.log(quux); + +foo(); // does something else diff --git a/recipes/repl-builtin-modules/tests/input/file-6.mjs b/recipes/repl-builtin-modules/tests/input/file-6.mjs new file mode 100644 index 00000000..c7948e42 --- /dev/null +++ b/recipes/repl-builtin-modules/tests/input/file-6.mjs @@ -0,0 +1,6 @@ +import { builtinModules, _builtinLibs, foo } from 'node:repl'; + +console.log(builtinModules); +console.log(_builtinLibs); + +foo(); // does something else diff --git a/recipes/repl-builtin-modules/tests/input/file-7.mjs b/recipes/repl-builtin-modules/tests/input/file-7.mjs new file mode 100644 index 00000000..29086500 --- /dev/null +++ b/recipes/repl-builtin-modules/tests/input/file-7.mjs @@ -0,0 +1,5 @@ +import repl from 'node:repl'; +import * as nodeRepl from 'node:repl'; + +console.log(repl.builtinModules); +console.log(nodeRepl.builtinModules); diff --git a/recipes/repl-builtin-modules/tests/input/file-8.mjs b/recipes/repl-builtin-modules/tests/input/file-8.mjs new file mode 100644 index 00000000..d1cb4a7f --- /dev/null +++ b/recipes/repl-builtin-modules/tests/input/file-8.mjs @@ -0,0 +1,3 @@ +import { builtinModules as nodeBuiltinModules } from 'node:repl'; + +console.log(nodeBuiltinModules); diff --git a/recipes/repl-builtin-modules/tests/input/file-9.mjs b/recipes/repl-builtin-modules/tests/input/file-9.mjs new file mode 100644 index 00000000..e860ca44 --- /dev/null +++ b/recipes/repl-builtin-modules/tests/input/file-9.mjs @@ -0,0 +1,6 @@ +const { builtinModules } = await import('node:repl'); +const repl = await import('node:repl'); + +console.log(builtinModules); +console.log(repl.builtinModules); +console.log(repl._builtinLibs); diff --git a/recipes/repl-builtin-modules/tsconfig.json b/recipes/repl-builtin-modules/tsconfig.json new file mode 100644 index 00000000..8ec57821 --- /dev/null +++ b/recipes/repl-builtin-modules/tsconfig.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "allowImportingTsExtensions": true, + "allowJs": true, + "alwaysStrict": true, + "baseUrl": "", + "declaration": true, + "declarationMap": true, + "emitDeclarationOnly": true, + "lib": ["ESNext", "DOM"], + "module": "NodeNext", + "moduleResolution": "NodeNext", + "noImplicitThis": true, + "removeComments": true, + "strict": true, + "stripInternal": true, + "target": "esnext" + }, + "include": [""], + "exclude": [ + "tests/**" + ] +} diff --git a/recipes/repl-builtin-modules/workflow.yaml b/recipes/repl-builtin-modules/workflow.yaml new file mode 100644 index 00000000..87d56100 --- /dev/null +++ b/recipes/repl-builtin-modules/workflow.yaml @@ -0,0 +1,25 @@ +version: "1" + +nodes: + - id: apply-transforms + name: Apply AST Transformations + type: automatic + runtime: + type: direct + steps: + - name: Handle DEP0191 via transforming `repl.builtinModules` usage to `module.builtinModules`. + js-ast-grep: + js_file: src/workflow.ts + base_path: . + include: + - "**/*.js" + - "**/*.jsx" + - "**/*.mjs" + - "**/*.cjs" + - "**/*.cts" + - "**/*.mts" + - "**/*.ts" + - "**/*.tsx" + exclude: + - "**/node_modules/**" + language: typescript