From 55f9f2dcc94e7653320bf71d98e7720697f1b371 Mon Sep 17 00:00:00 2001 From: Augustin Mauroy <97875033+AugustinMauroy@users.noreply.github.com> Date: Thu, 13 Aug 2026 11:55:14 +0200 Subject: [PATCH 1/2] feat(migrate-library-target-to-library-object): introduce --- .changeset/slick-files-jump.md | 5 + .../README.md | 78 +++++++++ .../codemod.yaml | 21 +++ .../package.json | 13 ++ .../src/workflow.ts | 151 ++++++++++++++++++ .../tests/test-1/expected.ts | 8 + .../tests/test-1/input.ts | 6 + .../tests/test-2/expected.ts | 9 ++ .../tests/test-2/input.ts | 7 + .../tests/test-3/expected.ts | 8 + .../tests/test-3/input.ts | 5 + .../tests/test-4/expected.ts | 9 ++ .../tests/test-4/input.ts | 7 + .../workflow.yaml | 23 +++ package-lock.json | 13 +- 15 files changed, 362 insertions(+), 1 deletion(-) create mode 100644 .changeset/slick-files-jump.md create mode 100644 codemods/migrate-library-target-to-library-object/README.md create mode 100644 codemods/migrate-library-target-to-library-object/codemod.yaml create mode 100644 codemods/migrate-library-target-to-library-object/package.json create mode 100644 codemods/migrate-library-target-to-library-object/src/workflow.ts create mode 100644 codemods/migrate-library-target-to-library-object/tests/test-1/expected.ts create mode 100644 codemods/migrate-library-target-to-library-object/tests/test-1/input.ts create mode 100644 codemods/migrate-library-target-to-library-object/tests/test-2/expected.ts create mode 100644 codemods/migrate-library-target-to-library-object/tests/test-2/input.ts create mode 100644 codemods/migrate-library-target-to-library-object/tests/test-3/expected.ts create mode 100644 codemods/migrate-library-target-to-library-object/tests/test-3/input.ts create mode 100644 codemods/migrate-library-target-to-library-object/tests/test-4/expected.ts create mode 100644 codemods/migrate-library-target-to-library-object/tests/test-4/input.ts create mode 100644 codemods/migrate-library-target-to-library-object/workflow.yaml diff --git a/.changeset/slick-files-jump.md b/.changeset/slick-files-jump.md new file mode 100644 index 0000000..fc26f80 --- /dev/null +++ b/.changeset/slick-files-jump.md @@ -0,0 +1,5 @@ +--- +"@webpack/migrate-library-target-to-library-object": major +--- + +Introduce the codemod, by copy pasting it here from `codemod/webpack-codemods` diff --git a/codemods/migrate-library-target-to-library-object/README.md b/codemods/migrate-library-target-to-library-object/README.md new file mode 100644 index 0000000..bc8571d --- /dev/null +++ b/codemods/migrate-library-target-to-library-object/README.md @@ -0,0 +1,78 @@ +# migrate-library-target-to-library-object + +This codemod migrates the `output.library` and `output.libraryTarget` properties in Webpack configurations to the new format required by Webpack 5. It changes `output.library` to `output.library.name` and `output.libraryTarget` to `output.library.type`. + +## Example + +```diff +- module.exports = { +- output: { +- library: "MyLibrary", +- libraryTarget: "commonjs2", +- }, +- }; ++ module.exports = { ++ output: { ++ library: { ++ name: "MyLibrary", ++ type: "commonjs2", ++ }, ++ }, ++ }; +``` + +```diff +- module.exports = { +- output: { +- library: "MyLibrary", +- libraryTarget: "commonjs2", +- filename: "bundle.js", +- }, +- }; ++ module.exports = { ++ output: { ++ library: { ++ name: "MyLibrary", ++ type: "commonjs2", ++ }, ++ ++ filename: "bundle.js", ++ }, ++ }; +``` + +```diff +- module.exports = { +- output: { +- library: "MyLibrary", +- }, +- }; ++ module.exports = { ++ output: { ++ library: { ++ name: "MyLibrary", ++ type: undefined, ++ }, ++ }, ++ }; +``` + +```diff +- module.exports = { +- output: { +- library: "MyLibrary", +- libraryTarget: "umd", +- path: "./dist", +- }, +- }; ++ module.exports = { ++ output: { ++ library: { ++ name: "MyLibrary", ++ type: "umd", ++ }, ++ ++ path: "./dist", ++ }, ++ }; +``` diff --git a/codemods/migrate-library-target-to-library-object/codemod.yaml b/codemods/migrate-library-target-to-library-object/codemod.yaml new file mode 100644 index 0000000..83e21e2 --- /dev/null +++ b/codemods/migrate-library-target-to-library-object/codemod.yaml @@ -0,0 +1,21 @@ +schema_version: "1.0" +name: "@webpack/migrate-library-target-to-library-object" +version: 1.0.0 +description: Transform Webpack 'library' and 'libraryTarget' to the new object format. +author: akash-kumar-dev +license: MIT +workflow: workflow.yaml +repository: "https://github.com/webpack/codemods/tree/HEAD/codemods/migrate-library-target-to-library-object" +category: migration + +targets: + languages: + - javascript + - typescript + +keywords: + - webpack + +registry: + access: public + visibility: public \ No newline at end of file diff --git a/codemods/migrate-library-target-to-library-object/package.json b/codemods/migrate-library-target-to-library-object/package.json new file mode 100644 index 0000000..f69b16e --- /dev/null +++ b/codemods/migrate-library-target-to-library-object/package.json @@ -0,0 +1,13 @@ +{ + "name": "@webpack/migrate-library-target-to-library-object", + "private": true, + "version": "1.0.0", + "description": "Transform Webpack 'library' and 'libraryTarget' to the new object format.", + "type": "module", + "scripts": { + "test": "npx codemod jssg test -l typescript ./src/workflow.ts" + }, + "devDependencies": { + "@codemod.com/jssg-types": "^1.6.3" + } +} diff --git a/codemods/migrate-library-target-to-library-object/src/workflow.ts b/codemods/migrate-library-target-to-library-object/src/workflow.ts new file mode 100644 index 0000000..8967f72 --- /dev/null +++ b/codemods/migrate-library-target-to-library-object/src/workflow.ts @@ -0,0 +1,151 @@ +import type { Codemod, Edit } from "codemod:ast-grep"; +import type Js from "@codemod.com/jssg-types/langs/javascript"; + +const transform: Codemod = async (root) => { + const rootNode = root.root(); + const edits: Edit[] = []; + + // Find all module.exports assignments + const moduleExports = rootNode.findAll({ + rule: { + kind: "assignment_expression", + has: { + kind: "member_expression", + has: { + field: "object", + kind: "identifier", + regex: "^module$", + }, + }, + }, + }); + + for (const moduleExport of moduleExports) { + // Find the right side of the assignment (the configuration object) + const rightSide = moduleExport.find({ + rule: { + kind: "object", + }, + }); + + if (!rightSide) continue; + + // Find the output property + const outputProperty = rightSide.find({ + rule: { + kind: "pair", + has: { + field: "key", + kind: "property_identifier", + regex: "^output$", + }, + }, + }); + + if (!outputProperty) continue; + + // Find the output object value + const outputObject = outputProperty.find({ + rule: { + kind: "object", + }, + }); + + if (!outputObject) continue; + + // Find library and libraryTarget properties + const libraryProperty = outputObject.find({ + rule: { + kind: "pair", + has: { + field: "key", + kind: "property_identifier", + regex: "^library$", + }, + }, + }); + + const libraryTargetProperty = outputObject.find({ + rule: { + kind: "pair", + has: { + field: "key", + kind: "property_identifier", + regex: "^libraryTarget$", + }, + }, + }); + + if (!libraryProperty) continue; + + // Get the library value + const libraryValue = libraryProperty.find({ + rule: { + kind: "string", + }, + }); + + if (!libraryValue) continue; + + const libraryName = libraryValue.text(); + + // Get the libraryTarget value if it exists + let libraryType = "undefined"; + if (libraryTargetProperty) { + const libraryTargetValue = libraryTargetProperty.find({ + rule: { + kind: "string", + }, + }); + if (libraryTargetValue) { + libraryType = libraryTargetValue.text(); + } + } + + // Get all properties in the output object to reconstruct it properly + const allProperties = outputObject.findAll({ + rule: { + kind: "pair", + }, + }); + + // Build new output object content with preserved tabs and trailing commas per property + const newProperties: string[] = []; + + for (const property of allProperties) { + const keyNode = property.find({ + rule: { + kind: "property_identifier", + }, + }); + + if (!keyNode) continue; + + const keyName = keyNode.text(); + + if (keyName === "library") { + // Replace with new library object, keep trailing comma + newProperties.push( + `library: {\n\t\t\tname: ${libraryName},\n\t\t\ttype: ${libraryType === "undefined" ? "undefined" : libraryType},\n\t\t},`, + ); + } else if (keyName === "libraryTarget") { + // Skip libraryTarget property - it's being moved into library.type + // (no-op) + } else { + // Keep other properties and add trailing comma + newProperties.push(`${property.text()},`); + } + } + + // Replace the entire output object with tab-indented content to match source style + const newOutputObject = `{\n\t\t${newProperties.join("\n\t\t")}\n\t}`; + + edits.push(outputObject.replace(newOutputObject)); + } + + if (!edits.length) return null; + + return rootNode.commitEdits(edits); +} + +export default transform; \ No newline at end of file diff --git a/codemods/migrate-library-target-to-library-object/tests/test-1/expected.ts b/codemods/migrate-library-target-to-library-object/tests/test-1/expected.ts new file mode 100644 index 0000000..2f8dc56 --- /dev/null +++ b/codemods/migrate-library-target-to-library-object/tests/test-1/expected.ts @@ -0,0 +1,8 @@ +module.exports = { + output: { + library: { + name: "MyLibrary", + type: "commonjs2", + }, + }, +}; diff --git a/codemods/migrate-library-target-to-library-object/tests/test-1/input.ts b/codemods/migrate-library-target-to-library-object/tests/test-1/input.ts new file mode 100644 index 0000000..6cd5d45 --- /dev/null +++ b/codemods/migrate-library-target-to-library-object/tests/test-1/input.ts @@ -0,0 +1,6 @@ +module.exports = { + output: { + library: "MyLibrary", + libraryTarget: "commonjs2", + }, +}; diff --git a/codemods/migrate-library-target-to-library-object/tests/test-2/expected.ts b/codemods/migrate-library-target-to-library-object/tests/test-2/expected.ts new file mode 100644 index 0000000..3c3975b --- /dev/null +++ b/codemods/migrate-library-target-to-library-object/tests/test-2/expected.ts @@ -0,0 +1,9 @@ +module.exports = { + output: { + library: { + name: "MyLibrary", + type: "commonjs2", + }, + filename: "bundle.js", + }, +}; diff --git a/codemods/migrate-library-target-to-library-object/tests/test-2/input.ts b/codemods/migrate-library-target-to-library-object/tests/test-2/input.ts new file mode 100644 index 0000000..4eff7af --- /dev/null +++ b/codemods/migrate-library-target-to-library-object/tests/test-2/input.ts @@ -0,0 +1,7 @@ +module.exports = { + output: { + library: "MyLibrary", + libraryTarget: "commonjs2", + filename: "bundle.js", + }, +}; diff --git a/codemods/migrate-library-target-to-library-object/tests/test-3/expected.ts b/codemods/migrate-library-target-to-library-object/tests/test-3/expected.ts new file mode 100644 index 0000000..3e984ce --- /dev/null +++ b/codemods/migrate-library-target-to-library-object/tests/test-3/expected.ts @@ -0,0 +1,8 @@ +module.exports = { + output: { + library: { + name: "MyLibrary", + type: undefined, + }, + }, +}; diff --git a/codemods/migrate-library-target-to-library-object/tests/test-3/input.ts b/codemods/migrate-library-target-to-library-object/tests/test-3/input.ts new file mode 100644 index 0000000..be71ad1 --- /dev/null +++ b/codemods/migrate-library-target-to-library-object/tests/test-3/input.ts @@ -0,0 +1,5 @@ +module.exports = { + output: { + library: "MyLibrary", + }, +}; diff --git a/codemods/migrate-library-target-to-library-object/tests/test-4/expected.ts b/codemods/migrate-library-target-to-library-object/tests/test-4/expected.ts new file mode 100644 index 0000000..6b02aa3 --- /dev/null +++ b/codemods/migrate-library-target-to-library-object/tests/test-4/expected.ts @@ -0,0 +1,9 @@ +module.exports = { + output: { + library: { + name: "MyLibrary", + type: "umd", + }, + path: "./dist", + }, +}; diff --git a/codemods/migrate-library-target-to-library-object/tests/test-4/input.ts b/codemods/migrate-library-target-to-library-object/tests/test-4/input.ts new file mode 100644 index 0000000..a8ac10a --- /dev/null +++ b/codemods/migrate-library-target-to-library-object/tests/test-4/input.ts @@ -0,0 +1,7 @@ +module.exports = { + output: { + library: "MyLibrary", + libraryTarget: "umd", + path: "./dist", + }, +}; diff --git a/codemods/migrate-library-target-to-library-object/workflow.yaml b/codemods/migrate-library-target-to-library-object/workflow.yaml new file mode 100644 index 0000000..9066873 --- /dev/null +++ b/codemods/migrate-library-target-to-library-object/workflow.yaml @@ -0,0 +1,23 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/codemod-com/codemod/refs/heads/main/schemas/workflow.json + +version: "1" + +nodes: + - id: apply-transforms + name: Apply AST Transformations + type: automatic + steps: + - name: Transform Webpack 'library' and 'libraryTarget' to the new object format. + js-ast-grep: + js_file: src/workflow.ts + base_path: . + include: + - "**/*.tsx" + - "**/*.ts" + - "**/*.jsx" + - "**/*.js" + - "**/*.cts" + - "**/*.mts" + exclude: + - "**/node_modules/**" + language: typescript \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 3f0ce0f..125c5b3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,7 +23,7 @@ }, "codemods/css-plugins-to-native-css": { "name": "@webpack/css-plugins-to-native-css", - "version": "0.0.0", + "version": "1.0.0", "license": "MIT", "dependencies": { "@webpack/codemod-utils": "*" @@ -32,6 +32,13 @@ "@codemod.com/jssg-types": "^1.6.2" } }, + "codemods/migrate-library-target-to-library-object": { + "name": "@webpack/migrate-library-target-to-library-object", + "version": "1.0.0", + "devDependencies": { + "@codemod.com/jssg-types": "^1.6.3" + } + }, "node_modules/@babel/runtime": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz", @@ -1029,6 +1036,10 @@ "resolved": "codemods/css-plugins-to-native-css", "link": true }, + "node_modules/@webpack/migrate-library-target-to-library-object": { + "resolved": "codemods/migrate-library-target-to-library-object", + "link": true + }, "node_modules/acorn": { "version": "8.18.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.18.0.tgz", From ce6722b701aece059bf6d3e03daab31d5bfa3e14 Mon Sep 17 00:00:00 2001 From: Augustin Mauroy <97875033+AugustinMauroy@users.noreply.github.com> Date: Thu, 13 Aug 2026 11:55:41 +0200 Subject: [PATCH 2/2] new line --- codemods/migrate-library-target-to-library-object/codemod.yaml | 2 +- .../migrate-library-target-to-library-object/src/workflow.ts | 2 +- codemods/migrate-library-target-to-library-object/workflow.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/codemods/migrate-library-target-to-library-object/codemod.yaml b/codemods/migrate-library-target-to-library-object/codemod.yaml index 83e21e2..10adeee 100644 --- a/codemods/migrate-library-target-to-library-object/codemod.yaml +++ b/codemods/migrate-library-target-to-library-object/codemod.yaml @@ -18,4 +18,4 @@ keywords: registry: access: public - visibility: public \ No newline at end of file + visibility: public diff --git a/codemods/migrate-library-target-to-library-object/src/workflow.ts b/codemods/migrate-library-target-to-library-object/src/workflow.ts index 8967f72..691a671 100644 --- a/codemods/migrate-library-target-to-library-object/src/workflow.ts +++ b/codemods/migrate-library-target-to-library-object/src/workflow.ts @@ -148,4 +148,4 @@ const transform: Codemod = async (root) => { return rootNode.commitEdits(edits); } -export default transform; \ No newline at end of file +export default transform; diff --git a/codemods/migrate-library-target-to-library-object/workflow.yaml b/codemods/migrate-library-target-to-library-object/workflow.yaml index 9066873..a187618 100644 --- a/codemods/migrate-library-target-to-library-object/workflow.yaml +++ b/codemods/migrate-library-target-to-library-object/workflow.yaml @@ -20,4 +20,4 @@ nodes: - "**/*.mts" exclude: - "**/node_modules/**" - language: typescript \ No newline at end of file + language: typescript