From 68de8e2864f9ae3313baa34b006044dcbf2b964c Mon Sep 17 00:00:00 2001 From: pshu Date: Mon, 23 Sep 2024 11:18:29 +0800 Subject: [PATCH 01/21] docs: change log 0923 (#1607) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * docs: 📝 change log * docs: 📝 change log 0923 * chore: ✏️ --- CHANGELOG.md | 8 ++++++++ CHANGELOG_zh-CN.md | 28 ++++++++++++++++++---------- 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b3069e03d..54e44edee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +## 0.8.13 + +`2024-09-23` + +* fix: chunk_loading_global by @xusd320 in https://github.com/umijs/mako/pull/1590 +* fix: devServer put static serve proxy after umi proxy middleware by @whyer11 in https://github.com/umijs/mako/pull/1558 +* revert: import namespace optimize by @stormslowly in https://github.com/umijs/mako/pull/1606 + ## 0.8.12 `2024-09-13` diff --git a/CHANGELOG_zh-CN.md b/CHANGELOG_zh-CN.md index 78fa9fc40..a308746f2 100644 --- a/CHANGELOG_zh-CN.md +++ b/CHANGELOG_zh-CN.md @@ -1,17 +1,25 @@ +## 0.8.13 + +`2024-09-23` + +* 修复: chunk_loading_global dev 内容未转义问题 by @xusd320 in https://github.com/umijs/mako/pull/1590 +* 修复: mako-bundler devServer 静态文件服务和 umi proxy 中间件执行顺序 by @whyer11 in https://github.com/umijs/mako/pull/1558 +* 回滚: `import * as` 的 tree shaking 优化 by @stormslowly in https://github.com/umijs/mako/pull/1606 + ## 0.8.12 `2024-09-13` -修复: 检测导出变量的副作用以进行 tree-shaking 优化 (by @stormslowly in #1579) -修复: 修复 chunk_loading_global 包含引号时的输出错误 (by @xusd320 in #1582) -其他: 添加用于调试模块/块图的 subdot cli 工具脚本 (by @stormslowly in #1585) -修复: 修复 Windows 下复制功能失效的问题 (by @sorrycc in #1587) -修复: 修复 Windows 下模块 ID 的路径问题 (by @sorrycc in #1588) -优化: 优化按需引入命名空间,减少冗余代码 (by @stormslowly in #1584) -修复 (已回滚): 修复 Mako 配置合并问题 (by @hualigushi in #1578) -修复: 修复清除依赖项时找不到模块导致程序崩溃的问题 (by @Jinbao1001 in #1581) -修复: 修复监视过多文件导致的错误 (by @Jinbao1001 in #1550) -新增: 支持数字模块 ID (by @Jinbao1001 in #1561) +* 修复: 检测导出变量的副作用以进行 tree-shaking 优化 (by @stormslowly in #1579) +* 修复: 修复 chunk_loading_global 包含引号时的输出错误 (by @xusd320 in #1582) +* 其他: 添加用于调试模块/块图的 subdot cli 工具脚本 (by @stormslowly in #1585) +* 修复: 修复 Windows 下复制功能失效的问题 (by @sorrycc in #1587) +* 修复: 修复 Windows 下模块 ID 的路径问题 (by @sorrycc in #1588) +* 优化: 优化按需引入命名空间,减少冗余代码 (by @stormslowly in #1584) +* 修复 (已回滚): 修复 Mako 配置合并问题 (by @hualigushi in #1578) +* 修复: 修复清除依赖项时找不到模块导致程序崩溃的问题 (by @Jinbao1001 in #1581) +* 修复: 修复监视过多文件导致的错误 (by @Jinbao1001 in #1550) +* 新增: 支持数字模块 ID (by @Jinbao1001 in #1561) ## 0.8.11 From e48ff2aa1c459d38afae8614185963786652da8c Mon Sep 17 00:00:00 2001 From: pshu Date: Wed, 25 Sep 2024 12:00:38 +0800 Subject: [PATCH 02/21] =?UTF-8?q?fix:=20=F0=9F=90=9B=20turn=20off=20expres?= =?UTF-8?q?s-http-proxy's=20keep=20alive=20(#1612)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: 🐛 turn off express-http-proxy's keep alive * refactor: 🔥 remove timeout config --- packages/bundler-mako/index.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/bundler-mako/index.js b/packages/bundler-mako/index.js index c9155ed36..318932b14 100644 --- a/packages/bundler-mako/index.js +++ b/packages/bundler-mako/index.js @@ -120,6 +120,12 @@ exports.dev = async function (opts) { app.use( proxy(`http://127.0.0.1:${hmrPort}`, { + proxyReqOptDecorator: function (proxyReqOpts) { + // keep alive is on by default https://nodejs.org/docs/latest/api/http.html#httpglobalagent + // 禁用 keep-alive + proxyReqOpts.agent = false; + return proxyReqOpts; + }, filter: function (req, res) { return req.method == 'GET' || req.method == 'HEAD'; }, From 5fd425fd624753185b86e83c60d32dbe925982be Mon Sep 17 00:00:00 2001 From: pshu Date: Wed, 25 Sep 2024 12:43:49 +0800 Subject: [PATCH 03/21] release: @umijs/mako@0.8.14 --- packages/bundler-mako/package.json | 2 +- packages/mako/npm/darwin-arm64/package.json | 2 +- packages/mako/npm/darwin-x64/package.json | 2 +- packages/mako/npm/linux-arm64-gnu/package.json | 2 +- .../mako/npm/linux-arm64-musl/package.json | 2 +- packages/mako/npm/linux-x64-gnu/package.json | 2 +- packages/mako/npm/linux-x64-musl/package.json | 2 +- packages/mako/npm/win32-ia32-msvc/package.json | 2 +- packages/mako/npm/win32-x64-msvc/package.json | 2 +- packages/mako/package.json | 18 +++++++++--------- 10 files changed, 18 insertions(+), 18 deletions(-) diff --git a/packages/bundler-mako/package.json b/packages/bundler-mako/package.json index e84d9a680..2699dad2c 100644 --- a/packages/bundler-mako/package.json +++ b/packages/bundler-mako/package.json @@ -3,7 +3,7 @@ "version": "0.8.13", "dependencies": { "@umijs/bundler-utils": "^4.0.81", - "@umijs/mako": "0.8.13", + "@umijs/mako": "0.8.14", "chalk": "^4.1.2", "compression": "^1.7.4", "connect-history-api-fallback": "^2.0.0", diff --git a/packages/mako/npm/darwin-arm64/package.json b/packages/mako/npm/darwin-arm64/package.json index f11dd650a..2971a72c2 100644 --- a/packages/mako/npm/darwin-arm64/package.json +++ b/packages/mako/npm/darwin-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@umijs/mako-darwin-arm64", - "version": "0.8.13", + "version": "0.8.14", "os": [ "darwin" ], diff --git a/packages/mako/npm/darwin-x64/package.json b/packages/mako/npm/darwin-x64/package.json index 21a0a4f27..23565c53e 100644 --- a/packages/mako/npm/darwin-x64/package.json +++ b/packages/mako/npm/darwin-x64/package.json @@ -1,6 +1,6 @@ { "name": "@umijs/mako-darwin-x64", - "version": "0.8.13", + "version": "0.8.14", "os": [ "darwin" ], diff --git a/packages/mako/npm/linux-arm64-gnu/package.json b/packages/mako/npm/linux-arm64-gnu/package.json index 77a6d7e65..95acdf33e 100644 --- a/packages/mako/npm/linux-arm64-gnu/package.json +++ b/packages/mako/npm/linux-arm64-gnu/package.json @@ -1,6 +1,6 @@ { "name": "@umijs/mako-linux-arm64-gnu", - "version": "0.8.13", + "version": "0.8.14", "os": [ "linux" ], diff --git a/packages/mako/npm/linux-arm64-musl/package.json b/packages/mako/npm/linux-arm64-musl/package.json index bb3e84d99..ffc864d12 100644 --- a/packages/mako/npm/linux-arm64-musl/package.json +++ b/packages/mako/npm/linux-arm64-musl/package.json @@ -1,6 +1,6 @@ { "name": "@umijs/mako-linux-arm64-musl", - "version": "0.8.13", + "version": "0.8.14", "os": [ "linux" ], diff --git a/packages/mako/npm/linux-x64-gnu/package.json b/packages/mako/npm/linux-x64-gnu/package.json index 43596f589..751072564 100644 --- a/packages/mako/npm/linux-x64-gnu/package.json +++ b/packages/mako/npm/linux-x64-gnu/package.json @@ -1,6 +1,6 @@ { "name": "@umijs/mako-linux-x64-gnu", - "version": "0.8.13", + "version": "0.8.14", "os": [ "linux" ], diff --git a/packages/mako/npm/linux-x64-musl/package.json b/packages/mako/npm/linux-x64-musl/package.json index 02faf49c9..d5bb89622 100644 --- a/packages/mako/npm/linux-x64-musl/package.json +++ b/packages/mako/npm/linux-x64-musl/package.json @@ -1,6 +1,6 @@ { "name": "@umijs/mako-linux-x64-musl", - "version": "0.8.13", + "version": "0.8.14", "os": [ "linux" ], diff --git a/packages/mako/npm/win32-ia32-msvc/package.json b/packages/mako/npm/win32-ia32-msvc/package.json index d725b4c9a..fd443e301 100644 --- a/packages/mako/npm/win32-ia32-msvc/package.json +++ b/packages/mako/npm/win32-ia32-msvc/package.json @@ -1,6 +1,6 @@ { "name": "@umijs/mako-win32-ia32-msvc", - "version": "0.8.13", + "version": "0.8.14", "os": [ "win32" ], diff --git a/packages/mako/npm/win32-x64-msvc/package.json b/packages/mako/npm/win32-x64-msvc/package.json index 311bb4faf..86f72537e 100644 --- a/packages/mako/npm/win32-x64-msvc/package.json +++ b/packages/mako/npm/win32-x64-msvc/package.json @@ -1,6 +1,6 @@ { "name": "@umijs/mako-win32-x64-msvc", - "version": "0.8.13", + "version": "0.8.14", "os": [ "win32" ], diff --git a/packages/mako/package.json b/packages/mako/package.json index 875b6f4e7..f82e45c5b 100644 --- a/packages/mako/package.json +++ b/packages/mako/package.json @@ -1,6 +1,6 @@ { "name": "@umijs/mako", - "version": "0.8.13", + "version": "0.8.14", "main": "dist/index.js", "types": "dist/index.d.ts", "bin": { @@ -77,14 +77,14 @@ "src:build": "father build" }, "optionalDependencies": { - "@umijs/mako-darwin-arm64": "0.8.13", - "@umijs/mako-linux-arm64-gnu": "0.8.13", - "@umijs/mako-linux-arm64-musl": "0.8.13", - "@umijs/mako-win32-ia32-msvc": "0.8.13", - "@umijs/mako-darwin-x64": "0.8.13", - "@umijs/mako-win32-x64-msvc": "0.8.13", - "@umijs/mako-linux-x64-gnu": "0.8.13", - "@umijs/mako-linux-x64-musl": "0.8.13" + "@umijs/mako-darwin-arm64": "0.8.14", + "@umijs/mako-linux-arm64-gnu": "0.8.14", + "@umijs/mako-linux-arm64-musl": "0.8.14", + "@umijs/mako-win32-ia32-msvc": "0.8.14", + "@umijs/mako-darwin-x64": "0.8.14", + "@umijs/mako-win32-x64-msvc": "0.8.14", + "@umijs/mako-linux-x64-gnu": "0.8.14", + "@umijs/mako-linux-x64-musl": "0.8.14" }, "repository": "git@github.com:umijs/mako.git" } \ No newline at end of file From 9ebbe1955a17c32b1882e8f653fae8a8f2c16ce7 Mon Sep 17 00:00:00 2001 From: pshu Date: Wed, 25 Sep 2024 13:18:38 +0800 Subject: [PATCH 04/21] chore: bundler-mako@0.8.14 --- packages/bundler-mako/package.json | 2 +- pnpm-lock.yaml | 66 +++++++++++++++--------------- 2 files changed, 34 insertions(+), 34 deletions(-) diff --git a/packages/bundler-mako/package.json b/packages/bundler-mako/package.json index 2699dad2c..2125c3eb4 100644 --- a/packages/bundler-mako/package.json +++ b/packages/bundler-mako/package.json @@ -1,6 +1,6 @@ { "name": "@umijs/bundler-mako", - "version": "0.8.13", + "version": "0.8.14", "dependencies": { "@umijs/bundler-utils": "^4.0.81", "@umijs/mako": "0.8.14", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bfcfdddd8..9fb266c53 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -436,7 +436,7 @@ importers: specifier: ^4.0.81 version: 4.1.6 '@umijs/mako': - specifier: 0.8.13 + specifier: 0.8.14 version: link:../mako chalk: specifier: ^4.1.2 @@ -537,29 +537,29 @@ importers: version: 21.1.1 optionalDependencies: '@umijs/mako-darwin-arm64': - specifier: 0.8.13 - version: 0.8.13 + specifier: 0.8.14 + version: 0.8.14 '@umijs/mako-darwin-x64': - specifier: 0.8.13 - version: 0.8.13 + specifier: 0.8.14 + version: 0.8.14 '@umijs/mako-linux-arm64-gnu': - specifier: 0.8.13 - version: 0.8.13 + specifier: 0.8.14 + version: 0.8.14 '@umijs/mako-linux-arm64-musl': - specifier: 0.8.13 - version: 0.8.13 + specifier: 0.8.14 + version: 0.8.14 '@umijs/mako-linux-x64-gnu': - specifier: 0.8.13 - version: 0.8.13 + specifier: 0.8.14 + version: 0.8.14 '@umijs/mako-linux-x64-musl': - specifier: 0.8.13 - version: 0.8.13 + specifier: 0.8.14 + version: 0.8.14 '@umijs/mako-win32-ia32-msvc': - specifier: 0.8.13 - version: 0.8.13 + specifier: 0.8.14 + version: 0.8.14 '@umijs/mako-win32-x64-msvc': - specifier: 0.8.13 - version: 0.8.13 + specifier: 0.8.14 + version: 0.8.14 devDependencies: '@napi-rs/cli': specifier: ^2.18.0 @@ -6512,8 +6512,8 @@ packages: dev: true optional: true - /@umijs/mako-darwin-arm64@0.8.13: - resolution: {integrity: sha512-PyFNH4GIUHJVXPNcs5g6GzHWoRpesBToNleYbsiih1hYNYX2nS6XDrufth4zhm10X/JZ/FCyW5rQOF57t5w+dw==} + /@umijs/mako-darwin-arm64@0.8.14: + resolution: {integrity: sha512-V64q7DqM26+cMKDGyK/3uC/Dw4AR3ILiUieda7N6nthRbG4m6KHfRM8Tr/loDiSscHCkSS+gNCs1Ylp7VpcJ+g==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] @@ -6530,8 +6530,8 @@ packages: dev: true optional: true - /@umijs/mako-darwin-x64@0.8.13: - resolution: {integrity: sha512-LS6XHhKiSn2fPdKa2Sb0W2o5Ftl93/AC+JNQdeM+ya7sCD+qn55HrT20s2/u7xIMKg7nsy7soGy2+gBrcPu1lQ==} + /@umijs/mako-darwin-x64@0.8.14: + resolution: {integrity: sha512-FlamYs2kddKQoU92+NNQ69u8luI1lmqzsqIZkNh3auJ/WKrcrIJakKBjvpvCXzrzPdwg4FFdatbSMj+Y3NtOHA==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] @@ -6539,8 +6539,8 @@ packages: dev: false optional: true - /@umijs/mako-linux-arm64-gnu@0.8.13: - resolution: {integrity: sha512-lvz8fnY5TzArfk9h+Kfuq+L586l8oEEa9s7BHzSf7Lpv0/BCvjusTt8UjhyryHGeC05O87XXhs16jO7vLhSbBQ==} + /@umijs/mako-linux-arm64-gnu@0.8.14: + resolution: {integrity: sha512-YoJTbQ9rIfWWrmK45diRVsa5y6g6zamydDLhnkjvxFRSl8BEtAqOzdOh7JAjOjxaQa7/x7kJZbg8QpDPYU793g==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] @@ -6548,8 +6548,8 @@ packages: dev: false optional: true - /@umijs/mako-linux-arm64-musl@0.8.13: - resolution: {integrity: sha512-iVChkN2Zf1UiXZEVjfYxmjZiMJp2IDbPiysP8zpF7Wl8NvtvrlT7w9V+7U/2CR7VLYzmwWUc7X94PJUXKAXdMw==} + /@umijs/mako-linux-arm64-musl@0.8.14: + resolution: {integrity: sha512-u/LZMIyMLFlLAtKZwrkqpSdF5jDFYeaQbx6zp6pGeeBHVYDnSKmPl0EVlsVZoDsN+TOPZfc47gJGuKdKJsXGpw==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] @@ -6566,8 +6566,8 @@ packages: dev: true optional: true - /@umijs/mako-linux-x64-gnu@0.8.13: - resolution: {integrity: sha512-0tLZ1vD3B9wRr0lruI8/520IlMbnFTbfzOArGyaAQechGmCaPQx1mQcw+KVWqGUxk5z6U/XNMrP/EC9629i3Sw==} + /@umijs/mako-linux-x64-gnu@0.8.14: + resolution: {integrity: sha512-5lAzXP842yD8IHvTQ6egTYu8ULwI4maEZBKO6wNS9IQgy586ijGFj/XsVc8Q9mx5xDmGnNs3BPpwbU/Rm1dgsw==} engines: {node: '>= 10'} cpu: [x64] os: [linux] @@ -6584,8 +6584,8 @@ packages: dev: true optional: true - /@umijs/mako-linux-x64-musl@0.8.13: - resolution: {integrity: sha512-Z+/mJ4cFCLLblK1dkVi3sfkOTnFFmHLF89YYF4tZ1OsO9709kQAooe4LVeKBUdVGbdldvHVSZscMRRLmDhp+/w==} + /@umijs/mako-linux-x64-musl@0.8.14: + resolution: {integrity: sha512-p4wuVRakorc192ucLz11hqFInsKmjTTsmGoLs7KQG2bP6KwZ2O2FNAmbPfLbHS0ORFsR/1HF38KW4o66nCTePA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] @@ -6593,8 +6593,8 @@ packages: dev: false optional: true - /@umijs/mako-win32-ia32-msvc@0.8.13: - resolution: {integrity: sha512-7thhScKlCaepDnppy2wGJsiz0yiBjRPT6KmYGi5dRMv/dsgv1Lfhy39wSBX6LiD3pIWgfYHCUUQgRc6yzDVrAA==} + /@umijs/mako-win32-ia32-msvc@0.8.14: + resolution: {integrity: sha512-dXMs4qVJ5cI+x07h4+hqtcIDYKJxA7xkIWOoZKXPr/PUUMBQdY5q6EspRKREUHKH1kxEOhsMqwlWxRoWzq3awA==} engines: {node: '>= 10'} cpu: [ia32] os: [win32] @@ -6602,8 +6602,8 @@ packages: dev: false optional: true - /@umijs/mako-win32-x64-msvc@0.8.13: - resolution: {integrity: sha512-Mxr12n0xGK0IdeQnVj+2rrl+3Yj3fSA87eMgAgWFr01fzQURYeV4RXMgLx+vtZWJFESUPxJbmBRwgRVEkqLH6A==} + /@umijs/mako-win32-x64-msvc@0.8.14: + resolution: {integrity: sha512-lw5FZIlWJ/Mk4VQpOtSI0PIuInXSd+SJdxtn6pWOOEBZ2LomGRhEEsPhNbibyoqXKtJ9vgIHCfYZRVZVkicr7w==} engines: {node: '>= 10'} cpu: [x64] os: [win32] From ea26506f9144f1efdf5a3b17bdacc7ca2b3b6cdd Mon Sep 17 00:00:00 2001 From: xusd320 Date: Wed, 25 Sep 2024 14:30:33 +0800 Subject: [PATCH 05/21] refactor: napi threadsafe function (#1608) * refactor: napi threadsafe function * chore: update binding typings * refactor: code pieces * fix: catch napi tsfn promise rejection * chore: update binding typings --- Cargo.lock | 39 +-- Cargo.toml | 2 + crates/binding/Cargo.toml | 9 +- crates/binding/src/js_hook.rs | 101 +++++++ crates/binding/src/js_plugin.rs | 51 +--- crates/binding/src/lib.rs | 14 +- crates/binding/src/threadsafe_function.rs | 333 ++++------------------ crates/binding/src/tsfn.rs | 285 ------------------ crates/mako/Cargo.toml | 2 +- crates/mako/src/utils.rs | 2 +- packages/mako/binding.d.ts | 10 +- 11 files changed, 208 insertions(+), 640 deletions(-) create mode 100644 crates/binding/src/js_hook.rs delete mode 100644 crates/binding/src/tsfn.rs diff --git a/Cargo.lock b/Cargo.lock index 6e34e9008..ddcbfa933 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2692,7 +2692,8 @@ dependencies = [ "napi", "napi-build", "napi-derive", - "rayon", + "oneshot", + "serde", "serde_json", "tikv-jemallocator", ] @@ -2935,9 +2936,9 @@ dependencies = [ [[package]] name = "napi" -version = "2.14.0" +version = "2.16.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9d90182620f32fe34b6ac9b52cba898af26e94c7f5abc01eb4094c417ae2e6c" +checksum = "53575dfa17f208dd1ce3a2da2da4659aae393b256a472f2738a8586a6c4107fd" dependencies = [ "bitflags 2.4.2", "ctor", @@ -2957,23 +2958,23 @@ checksum = "882a73d9ef23e8dc2ebbffb6a6ae2ef467c0f18ac10711e4cc59c5485d41df0e" [[package]] name = "napi-derive" -version = "2.14.1" +version = "2.16.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3619fa472d23cd5af94d63a2bae454a77a8863251f40230fbf59ce20eafa8a86" +checksum = "17435f7a00bfdab20b0c27d9c56f58f6499e418252253081bfff448099da31d1" dependencies = [ "cfg-if", "convert_case", "napi-derive-backend", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.50", ] [[package]] name = "napi-derive-backend" -version = "1.0.54" +version = "1.0.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecd3ea4b54020c73d591a49cd192f6334c5f37f71a63ead54dbc851fa991ef00" +checksum = "967c485e00f0bf3b1bdbe510a38a4606919cf1d34d9a37ad41f25a81aa077abe" dependencies = [ "convert_case", "once_cell", @@ -2981,14 +2982,14 @@ dependencies = [ "quote", "regex", "semver 1.0.23", - "syn 1.0.109", + "syn 2.0.50", ] [[package]] name = "napi-sys" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2503fa6af34dc83fb74888df8b22afe933b58d37daf7d80424b1c60c68196b8b" +checksum = "427802e8ec3a734331fec1035594a210ce1ff4dc5bc1950530920ab717964ea3" dependencies = [ "libloading 0.8.1", ] @@ -3308,6 +3309,12 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +[[package]] +name = "oneshot" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e296cf87e61c9cfc1a61c3c63a0f7f286ed4554e0e22be84e8a38e1d264a2a29" + [[package]] name = "open" version = "5.1.4" @@ -3861,9 +3868,9 @@ checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9" [[package]] name = "rayon" -version = "1.7.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" dependencies = [ "either", "rayon-core", @@ -3871,14 +3878,12 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.11.0" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" dependencies = [ - "crossbeam-channel", "crossbeam-deque", "crossbeam-utils", - "num_cpus", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index f5dbe9240..4438e1242 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,8 +3,10 @@ members = ["crates/*"] resolver = "2" [workspace.dependencies] +anyhow = "1.0.71" cached = "0.46.1" mimalloc-rust = { version = "=0.2.1" } +oneshot = "0.1.8" serde = { version = "1.0.171", features = ["derive"] } serde_json = "1.0.100" swc_core = { version = "=0.83.22", default-features = false } diff --git a/crates/binding/Cargo.toml b/crates/binding/Cargo.toml index df9adf485..dfa62c088 100644 --- a/crates/binding/Cargo.toml +++ b/crates/binding/Cargo.toml @@ -7,12 +7,13 @@ version = "0.0.0" crate-type = ["cdylib"] [dependencies] -anyhow = "1.0.71" +anyhow = { workspace = true } cached = { workspace = true } mako = { path = '../mako' } -napi = { version = "2.14.0", default-features = false, features = ["napi4", "napi5", "serde-json", "tokio_rt"] } -napi-derive = "2.14.0" -rayon = "1.7.0" +napi = { version = "2.16.11", default-features = false, features = ["async", "napi4", "serde-json"] } +napi-derive = "2.16.12" +oneshot = { workspace = true } +serde = { workspace = true } serde_json = { workspace = true } [target.'cfg(not(target_os = "linux"))'.dependencies] diff --git a/crates/binding/src/js_hook.rs b/crates/binding/src/js_hook.rs new file mode 100644 index 000000000..e36f21c82 --- /dev/null +++ b/crates/binding/src/js_hook.rs @@ -0,0 +1,101 @@ +use napi::bindgen_prelude::*; +use napi::NapiRaw; +use napi_derive::napi; +use serde_json::Value; + +use crate::threadsafe_function::ThreadsafeFunction; + +#[napi(object)] +pub struct JsHooks { + pub name: Option, + #[napi( + ts_type = "(filePath: string) => Promise<{ content: string, type: 'css'|'js' } | void> | void;" + )] + pub load: Option, + #[napi(ts_type = r#"(data: { + isFirstCompile: boolean; + time: number; + stats: { + hash: number; + builtAt: number; + rootPath: string; + outputPath: string; + assets: { type: string; name: string; path: string; size: number }[]; + chunkModules: { + type: string; + id: string; + chunks: string[]; + size: number; + }[]; + modules: Record< + string, + { id: string; dependents: string[]; dependencies: string[] } + >; + chunks: { + type: string; + id: string; + files: string[]; + entry: boolean; + modules: { type: string; id: string; size: number; chunks: string[] }[]; + siblings: string[]; + origin: { + module: string; + moduleIdentifier: string; + moduleName: string; + loc: string; + request: string; + }[]; + }[]; + entrypoints: Record; + rscClientComponents: { path; string; moduleId: string }[]; + rscCSSModules: { path; string; moduleId: string; modules: boolean }[]; + startTime: number; + endTime: number; + }; + }) => void"#)] + pub generate_end: Option, + #[napi(ts_type = "(path: string, content: Buffer) => Promise;")] + pub _on_generate_file: Option, + #[napi(ts_type = "() => Promise;")] + pub build_start: Option, +} + +pub struct TsFnHooks { + pub build_start: Option>, + pub generate_end: Option>, + pub load: Option>>, + pub _on_generate_file: Option>, +} + +impl TsFnHooks { + pub fn new(env: Env, hooks: &JsHooks) -> Self { + Self { + build_start: hooks.build_start.as_ref().map(|hook| unsafe { + ThreadsafeFunction::from_napi_value(env.raw(), hook.raw()).unwrap() + }), + generate_end: hooks.generate_end.as_ref().map(|hook| unsafe { + ThreadsafeFunction::from_napi_value(env.raw(), hook.raw()).unwrap() + }), + load: hooks.load.as_ref().map(|hook| unsafe { + ThreadsafeFunction::from_napi_value(env.raw(), hook.raw()).unwrap() + }), + _on_generate_file: hooks._on_generate_file.as_ref().map(|hook| unsafe { + ThreadsafeFunction::from_napi_value(env.raw(), hook.raw()).unwrap() + }), + } + } +} + +#[napi(object)] +pub struct WriteFile { + pub path: String, + #[napi(ts_type = "Buffer")] + pub content: Vec, +} + +#[napi(object, use_nullable = true)] +pub struct LoadResult { + pub content: String, + #[napi(js_name = "type")] + pub content_type: String, +} diff --git a/crates/binding/src/js_plugin.rs b/crates/binding/src/js_plugin.rs index 345157c9b..83a7792a0 100644 --- a/crates/binding/src/js_plugin.rs +++ b/crates/binding/src/js_plugin.rs @@ -1,7 +1,6 @@ -use std::sync::{mpsc, Arc}; +use std::sync::Arc; -use crate::threadsafe_function; -use crate::tsfn::{LoadResult, ReadMessage, TsFnHooks, WriteRequest}; +use crate::js_hook::{LoadResult, TsFnHooks, WriteFile}; pub struct JsPlugin { pub hooks: TsFnHooks, @@ -18,30 +17,14 @@ impl Plugin for JsPlugin { fn build_start(&self, _context: &Arc) -> Result<()> { if let Some(hook) = &self.hooks.build_start { - let (tx, rx) = mpsc::channel::>(); - hook.call( - ReadMessage { message: (), tx }, - threadsafe_function::ThreadsafeFunctionCallMode::Blocking, - ); - rx.recv() - .unwrap_or_else(|e| panic!("recv error: {:?}", e.to_string()))?; + hook.call(())? } Ok(()) } fn load(&self, param: &PluginLoadParam, _context: &Arc) -> Result> { if let Some(hook) = &self.hooks.load { - let (tx, rx) = mpsc::channel::>>(); - hook.call( - ReadMessage { - message: param.file.path.to_string_lossy().to_string(), - tx, - }, - threadsafe_function::ThreadsafeFunctionCallMode::Blocking, - ); - let x = rx - .recv() - .unwrap_or_else(|e| panic!("recv error: {:?}", e.to_string()))?; + let x: Option = hook.call(param.file.path.to_string_lossy().to_string())?; if let Some(x) = x { match x.content_type.as_str() { "js" | "ts" => { @@ -66,33 +49,17 @@ impl Plugin for JsPlugin { fn generate_end(&self, param: &PluginGenerateEndParams, _context: &Arc) -> Result<()> { if let Some(hook) = &self.hooks.generate_end { - let (tx, rx) = mpsc::channel::>(); - hook.call( - ReadMessage { - message: param.clone(), - tx, - }, - threadsafe_function::ThreadsafeFunctionCallMode::Blocking, - ); - rx.recv() - .unwrap_or_else(|e| panic!("recv error: {:?}", e.to_string()))?; + hook.call(serde_json::to_value(param)?)? } Ok(()) } fn before_write_fs(&self, path: &std::path::Path, content: &[u8]) -> Result<()> { if let Some(hook) = &self.hooks._on_generate_file { - let (tx, rx) = mpsc::channel::>(); - hook.call( - WriteRequest { - path: path.to_path_buf(), - content: content.to_vec(), - tx, - }, - threadsafe_function::ThreadsafeFunctionCallMode::Blocking, - ); - rx.recv() - .unwrap_or_else(|e| panic!("recv error: {:?}", e.to_string()))?; + hook.call(WriteFile { + path: path.to_string_lossy().to_string(), + content: content.to_vec(), + })?; } Ok(()) } diff --git a/crates/binding/src/lib.rs b/crates/binding/src/lib.rs index 596183407..79cd93143 100644 --- a/crates/binding/src/lib.rs +++ b/crates/binding/src/lib.rs @@ -1,24 +1,22 @@ #![deny(clippy::all)] -#[macro_use] -extern crate napi_derive; - use std::sync::{Arc, Once}; +use js_hook::{JsHooks, TsFnHooks}; use js_plugin::JsPlugin; use mako::compiler::{Args, Compiler}; use mako::config::Config; use mako::dev::DevServer; use mako::plugin::Plugin; use mako::utils::logger::init_logger; +use mako::utils::thread_pool; use napi::bindgen_prelude::*; use napi::{JsObject, Status}; -use tsfn::{JsHooks, TsFnHooks}; +use napi_derive::napi; +mod js_hook; mod js_plugin; -mod tsfn; - -pub(crate) mod threadsafe_function; +mod threadsafe_function; #[cfg(not(target_os = "linux"))] #[global_allocator] @@ -226,7 +224,7 @@ pub fn build(env: Env, build_params: BuildParams) -> napi::Result { Ok(promise) } else { let (deferred, promise) = env.create_deferred()?; - rayon::spawn(move || { + thread_pool::spawn(move || { let compiler = Compiler::new(config, root.clone(), Args { watch: false }, Some(plugins)) .map_err(|e| napi::Error::new(Status::GenericFailure, format!("{}", e))); diff --git a/crates/binding/src/threadsafe_function.rs b/crates/binding/src/threadsafe_function.rs index 5d25a06d3..21011a81f 100644 --- a/crates/binding/src/threadsafe_function.rs +++ b/crates/binding/src/threadsafe_function.rs @@ -1,302 +1,73 @@ -// Fork of threadsafe_function from napi-rs that allows calling JS function manually rather than -// only returning args. This enables us to use the return value of the function. - -#![allow(clippy::single_component_path_imports)] - -use std::convert::Into; -use std::ffi::CString; use std::marker::PhantomData; -use std::os::raw::c_void; -use std::ptr; -use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; -use std::sync::Arc; - -use napi::{check_status, sys, Env, JsError, JsFunction, NapiValue, Result, Status}; - -/// ThreadSafeFunction Context object -/// the `value` is the value passed to `call` method -pub struct ThreadSafeCallContext { - pub env: Env, - pub value: T, - pub callback: Option, -} - -#[repr(u8)] -pub enum ThreadsafeFunctionCallMode { - NonBlocking, - Blocking, -} - -impl From for sys::napi_threadsafe_function_call_mode { - fn from(value: ThreadsafeFunctionCallMode) -> Self { - match value { - ThreadsafeFunctionCallMode::Blocking => sys::ThreadsafeFunctionCallMode::blocking, - ThreadsafeFunctionCallMode::NonBlocking => sys::ThreadsafeFunctionCallMode::nonblocking, - } - } -} -/// Communicate with the addon's main thread by invoking a JavaScript function from other threads. -/// -/// ## Example -/// An example of using `ThreadsafeFunction`: -/// -/// ```rust -/// #[macro_use] -/// extern crate napi_derive; -/// -/// use std::thread; -/// -/// use napi::{ -/// threadsafe_function::{ -/// ThreadSafeCallContext, ThreadsafeFunctionCallMode, ThreadsafeFunctionReleaseMode, -/// }, -/// CallContext, Error, JsFunction, JsNumber, JsUndefined, Result, Status, -/// }; -/// -/// #[js_function(1)] -/// pub fn test_threadsafe_function(ctx: CallContext) -> Result { -/// let func = ctx.get::(0)?; -/// -/// let tsfn = -/// ctx -/// .env -/// .create_threadsafe_function(&func, 0, |ctx: ThreadSafeCallContext>| { -/// ctx.value -/// .iter() -/// .map(|v| ctx.env.create_uint32(*v)) -/// .collect::>>() -/// })?; -/// -/// let tsfn_cloned = tsfn.clone(); -/// -/// thread::spawn(move || { -/// let output: Vec = vec![0, 1, 2, 3]; -/// // It's okay to call a threadsafe function multiple times. -/// tsfn.call(Ok(output.clone()), ThreadsafeFunctionCallMode::Blocking); -/// }); -/// -/// thread::spawn(move || { -/// let output: Vec = vec![3, 2, 1, 0]; -/// // It's okay to call a threadsafe function multiple times. -/// tsfn_cloned.call(Ok(output.clone()), ThreadsafeFunctionCallMode::NonBlocking); -/// }); -/// -/// ctx.env.get_undefined() -/// } -/// ``` -pub struct ThreadsafeFunction { - raw_tsfn: sys::napi_threadsafe_function, - aborted: Arc, - ref_count: Arc, - _phantom: PhantomData, +use anyhow::{anyhow, Result}; +use napi::bindgen_prelude::{spawn, FromNapiValue, JsValuesTupleIntoVec, Promise}; +use napi::sys::{napi_env, napi_value}; +use napi::threadsafe_function::{ + ErrorStrategy, ThreadsafeFunction as Tsfn, ThreadsafeFunctionCallMode, +}; +use napi::JsUnknown; +use oneshot::channel; + +pub struct ThreadsafeFunction { + tsfn: Tsfn, + env: napi_env, + _phantom: PhantomData, } -impl Clone for ThreadsafeFunction { +impl Clone for ThreadsafeFunction { fn clone(&self) -> Self { - if !self.aborted.load(Ordering::Acquire) { - let acquire_status = unsafe { sys::napi_acquire_threadsafe_function(self.raw_tsfn) }; - debug_assert!( - acquire_status == sys::Status::napi_ok, - "Acquire threadsafe function failed in clone" - ); - } - Self { - raw_tsfn: self.raw_tsfn, - aborted: Arc::clone(&self.aborted), - ref_count: Arc::clone(&self.ref_count), + tsfn: self.tsfn.clone(), + env: self.env, _phantom: PhantomData, } } } -unsafe impl Send for ThreadsafeFunction {} -unsafe impl Sync for ThreadsafeFunction {} - -impl ThreadsafeFunction { - /// See [napi_create_threadsafe_function](https://nodejs.org/api/n-api.html#n_api_napi_create_threadsafe_function) - /// for more information. - pub(crate) fn create) -> Result<()>>( - env: sys::napi_env, - func: sys::napi_value, - max_queue_size: usize, - callback: R, - ) -> Result { - let mut async_resource_name = ptr::null_mut(); - let s = "napi_rs_threadsafe_function"; - let len = s.len(); - let s = CString::new(s)?; - check_status!(unsafe { - sys::napi_create_string_utf8(env, s.as_ptr(), len, &mut async_resource_name) - })?; - - let initial_thread_count = 1usize; - let mut raw_tsfn = ptr::null_mut(); - let ptr = Box::into_raw(Box::new(callback)) as *mut c_void; - check_status!(unsafe { - sys::napi_create_threadsafe_function( - env, - func, - ptr::null_mut(), - async_resource_name, - max_queue_size, - initial_thread_count, - ptr, - Some(thread_finalize_cb::), - ptr, - Some(call_js_cb::), - &mut raw_tsfn, - ) - })?; - - let aborted = Arc::new(AtomicBool::new(false)); - let aborted_ptr = Arc::into_raw(aborted.clone()) as *mut c_void; - check_status!(unsafe { - sys::napi_add_env_cleanup_hook(env, Some(cleanup_cb), aborted_ptr) - })?; - - Ok(ThreadsafeFunction { - raw_tsfn, - aborted, - ref_count: Arc::new(AtomicUsize::new(initial_thread_count)), +impl FromNapiValue for ThreadsafeFunction { + unsafe fn from_napi_value(env: napi_env, napi_val: napi_value) -> napi::Result { + let tsfn = Tsfn::from_napi_value(env, napi_val)?; + Ok(Self { + tsfn, + env, _phantom: PhantomData, }) } } -impl ThreadsafeFunction { - /// See [napi_call_threadsafe_function](https://nodejs.org/api/n-api.html#n_api_napi_call_threadsafe_function) - /// for more information. - pub fn call(&self, value: T, mode: ThreadsafeFunctionCallMode) -> Status { - if self.aborted.load(Ordering::Acquire) { - return Status::Closing; - } - unsafe { - sys::napi_call_threadsafe_function( - self.raw_tsfn, - Box::into_raw(Box::new(value)) as *mut _, - mode.into(), - ) - } - .into() - } -} - -impl Drop for ThreadsafeFunction { - fn drop(&mut self) { - if !self.aborted.load(Ordering::Acquire) && self.ref_count.load(Ordering::Acquire) > 0usize - { - let release_status = unsafe { - sys::napi_release_threadsafe_function( - self.raw_tsfn, - sys::ThreadsafeFunctionReleaseMode::release, - ) - }; - assert!( - release_status == sys::Status::napi_ok, - "Threadsafe Function release failed" - ); - } - } -} - -unsafe extern "C" fn cleanup_cb(cleanup_data: *mut c_void) { - let aborted = Arc::::from_raw(cleanup_data.cast()); - aborted.store(true, Ordering::SeqCst); -} - -unsafe extern "C" fn thread_finalize_cb( - _raw_env: sys::napi_env, - finalize_data: *mut c_void, - _finalize_hint: *mut c_void, -) where - R: 'static + Send + FnMut(ThreadSafeCallContext) -> Result<()>, -{ - // cleanup - drop(Box::::from_raw(finalize_data.cast())); -} - -unsafe extern "C" fn call_js_cb( - raw_env: sys::napi_env, - js_callback: sys::napi_value, - context: *mut c_void, - data: *mut c_void, -) where - R: 'static + Send + FnMut(ThreadSafeCallContext) -> Result<()>, -{ - // env and/or callback can be null when shutting down - if raw_env.is_null() { - return; - } - - let ctx: &mut R = &mut *context.cast::(); - let val: Result = Ok(*Box::::from_raw(data.cast())); - - let mut recv = ptr::null_mut(); - sys::napi_get_undefined(raw_env, &mut recv); - - let ret = val.and_then(|v| { - (ctx)(ThreadSafeCallContext { - env: Env::from_raw(raw_env), - value: v, - callback: if js_callback.is_null() { - None - } else { - Some(JsFunction::from_raw(raw_env, js_callback).unwrap()) // TODO: unwrap +impl ThreadsafeFunction { + pub fn call(&self, value: P) -> Result { + let (sender, receiver) = channel(); + self.tsfn.call_with_return_value( + value, + ThreadsafeFunctionCallMode::NonBlocking, + move |r: JsUnknown| { + if r.is_promise().unwrap() { + let promise = Promise::::from_unknown(r).unwrap(); + spawn(async move { + let r = promise.await; + sender + .send( + r.map_err(|e| anyhow!("Tsfn promise rejected {}.", e.to_string())), + ) + .expect("Failed to send napi returned value."); + }); + } else { + let r = R::from_unknown(r).unwrap(); + sender + .send(Ok(r)) + .expect("Failed to send napi returned value."); + } + Ok(()) }, - }) - }); - - let status = match ret { - Ok(()) => sys::Status::napi_ok, - Err(e) => sys::napi_fatal_exception(raw_env, JsError::from(e).into_value(raw_env)), - }; - if status == sys::Status::napi_ok { - return; - } - if status == sys::Status::napi_pending_exception { - let mut error_result = ptr::null_mut(); - assert_eq!( - sys::napi_get_and_clear_last_exception(raw_env, &mut error_result), - sys::Status::napi_ok ); - // When shutting down, napi_fatal_exception sometimes returns another exception - let stat = sys::napi_fatal_exception(raw_env, error_result); - assert!(stat == sys::Status::napi_ok || stat == sys::Status::napi_pending_exception); - } else { - let error_code: Status = status.into(); - let error_code_string = format!("{:?}", error_code); - let mut error_code_value = ptr::null_mut(); - assert_eq!( - sys::napi_create_string_utf8( - raw_env, - error_code_string.as_ptr() as *const _, - error_code_string.len(), - &mut error_code_value, - ), - sys::Status::napi_ok, - ); - let error_msg = "Call JavaScript callback failed in thread safe function"; - let mut error_msg_value = ptr::null_mut(); - assert_eq!( - sys::napi_create_string_utf8( - raw_env, - error_msg.as_ptr() as *const _, - error_msg.len(), - &mut error_msg_value, - ), - sys::Status::napi_ok, - ); - let mut error_value = ptr::null_mut(); - assert_eq!( - sys::napi_create_error(raw_env, error_code_value, error_msg_value, &mut error_value), - sys::Status::napi_ok, - ); - assert_eq!( - sys::napi_fatal_exception(raw_env, error_value), - sys::Status::napi_ok - ); + receiver + .recv() + .expect("Failed to receive napi returned value.") } } + +unsafe impl Sync for ThreadsafeFunction {} +unsafe impl Send for ThreadsafeFunction {} diff --git a/crates/binding/src/tsfn.rs b/crates/binding/src/tsfn.rs deleted file mode 100644 index 4fd5754e2..000000000 --- a/crates/binding/src/tsfn.rs +++ /dev/null @@ -1,285 +0,0 @@ -use std::path::PathBuf; -use std::str::from_utf8_unchecked; -use std::sync::mpsc::Sender; - -use mako::plugin::PluginGenerateEndParams; -use napi::bindgen_prelude::*; -use napi::{JsObject, JsString, JsUnknown, NapiRaw}; - -use crate::threadsafe_function; - -#[napi(object)] -pub struct JsHooks { - pub name: Option, - #[napi( - ts_type = "(filePath: string) => Promise<{ content: string, type: 'css'|'js' } | void> | void;" - )] - pub load: Option, - #[napi(ts_type = r#"(data: { - isFirstCompile: boolean; - time: number; - stats: { - hash: number; - builtAt: number; - rootPath: string; - outputPath: string; - assets: { type: string; name: string; path: string; size: number }[]; - chunkModules: { - type: string; - id: string; - chunks: string[]; - size: number; - }[]; - modules: Record< - string, - { id: string; dependents: string[]; dependencies: string[] } - >; - chunks: { - type: string; - id: string; - files: string[]; - entry: boolean; - modules: { type: string; id: string; size: number; chunks: string[] }[]; - siblings: string[]; - origin: { - module: string; - moduleIdentifier: string; - moduleName: string; - loc: string; - request: string; - }[]; - }[]; - entrypoints: Record; - rscClientComponents: { path; string; moduleId: string }[]; - rscCSSModules: { path; string; moduleId: string; modules: boolean }[]; - startTime: number; - endTime: number; - }; - }) => void"#)] - pub generate_end: Option, - #[napi(ts_type = "(path: string, content: Buffer) => Promise;")] - pub _on_generate_file: Option, - #[napi(ts_type = "() => Promise;")] - pub build_start: Option, -} - -pub struct TsFnHooks { - pub name: String, - pub build_start: Option>>, - pub generate_end: - Option>>, - pub load: - Option>>>, - pub _on_generate_file: Option>, -} - -impl TsFnHooks { - pub fn new(env: Env, hooks: &JsHooks) -> Self { - let name = if let Some(name) = &hooks.name { - name.clone() - } else { - "unnamed_js_plugin".to_string() - }; - Self { - name, - build_start: hooks.build_start.as_ref().map(|hook| { - threadsafe_function::ThreadsafeFunction::create( - env.raw(), - unsafe { hook.raw() }, - 0, - |ctx: threadsafe_function::ThreadSafeCallContext>| { - let obj = ctx.env.create_object()?; - let result = ctx.callback.unwrap().call(None, &[obj])?; - await_promise_with_void(ctx.env, result, ctx.value.tx).unwrap(); - Ok(()) - }, - ) - .unwrap() - }), - generate_end: hooks.generate_end.as_ref().map(|hook| { - threadsafe_function::ThreadsafeFunction::create( - env.raw(), - unsafe { hook.raw() }, - 0, - |ctx: threadsafe_function::ThreadSafeCallContext< - ReadMessage, - >| { - let obj = ctx - .env - .to_js_value(&serde_json::to_value(ctx.value.message)?)?; - let result = ctx.callback.unwrap().call(None, &[obj])?; - await_promise_with_void(ctx.env, result, ctx.value.tx).unwrap(); - Ok(()) - }, - ) - .unwrap() - }), - load: hooks.load.as_ref().map(|hook| { - threadsafe_function::ThreadsafeFunction::create( - env.raw(), - unsafe { hook.raw() }, - 0, - |ctx: threadsafe_function::ThreadSafeCallContext< - ReadMessage>, - >| { - let str = ctx.env.create_string(&ctx.value.message)?; - let result = ctx.callback.unwrap().call(None, &[str])?; - await_promise_js_object(ctx.env, result, ctx.value.tx).unwrap(); - Ok(()) - }, - ) - .unwrap() - }), - _on_generate_file: hooks._on_generate_file.as_ref().map(|hook| { - threadsafe_function::ThreadsafeFunction::create( - env.raw(), - unsafe { hook.raw() }, - 0, - |ctx: threadsafe_function::ThreadSafeCallContext| unsafe { - let path_str = ctx.value.path.to_str().unwrap(); - let str = ctx.env.create_string(path_str)?; - let buffer = ctx - .env - .create_string(from_utf8_unchecked(&ctx.value.content))?; - let result = ctx.callback.unwrap().call(None, &[str, buffer])?; - await_promise_with_void(ctx.env, result, ctx.value.tx).unwrap(); - Ok(()) - }, - ) - .unwrap() - }), - } - } -} - -#[allow(dead_code)] -fn await_promise( - env: Env, - result: JsUnknown, - tx: Sender>, -) -> napi::Result<()> { - // If the result is a promise, wait for it to resolve, and send the result to the channel. - // Otherwise, send the result immediately. - if result.is_promise()? { - let result: JsObject = result.try_into()?; - let then: JsFunction = result.get_named_property("then")?; - let tx2 = tx.clone(); - let cb = env.create_function_from_closure("callback", move |ctx| { - let res = ctx.get::(0)?.into_utf8()?; - let s = res.into_owned()?; - tx.send(Ok(s)).unwrap(); - ctx.env.get_undefined() - })?; - let eb = env.create_function_from_closure("error_callback", move |ctx| { - let res = ctx.get::(0)?; - tx2.send(Err(napi::Error::from(res))).unwrap(); - ctx.env.get_undefined() - })?; - then.call(Some(&result), &[cb, eb])?; - } else { - let result: JsString = result.try_into()?; - let utf8 = result.into_utf8()?; - let s = utf8.into_owned()?; - tx.send(Ok(s)).unwrap(); - } - - Ok(()) -} - -fn await_promise_js_object( - env: Env, - result: JsUnknown, - tx: Sender>>, -) -> napi::Result<()> { - // If the result is a promise, wait for it to resolve, and send the result to the channel. - // Otherwise, send the result immediately. - if result.is_promise()? { - let result: JsObject = result.try_into()?; - let then: JsFunction = result.get_named_property("then")?; - let tx2 = tx.clone(); - let cb = env.create_function_from_closure("callback", move |ctx| { - let res = ctx.get::(0)?; - if matches!(res.get_type()?, ValueType::Undefined) { - tx.send(Ok(None)).unwrap(); - return ctx.env.get_undefined(); - } - let res: JsObject = res.try_into()?; - // let s = res.into_owned()?; - // get res.content as string - // println!("res: {:}", res.get_element(0)?.into_utf8()?.into_owned()?); - let content: JsString = res.get_named_property("content")?; - let content_type: JsString = res.get_named_property("type")?; - tx.send(Ok(Some(LoadResult { - content: content.into_utf8()?.into_owned()?, - content_type: content_type.into_utf8()?.into_owned()?, - }))) - .unwrap(); - ctx.env.get_undefined() - })?; - let eb = env.create_function_from_closure("error_callback", move |ctx| { - let res = ctx.get::(0)?; - tx2.send(Err(napi::Error::from(res))).unwrap(); - ctx.env.get_undefined() - })?; - then.call(Some(&result), &[cb, eb])?; - } else { - if matches!(result.get_type()?, ValueType::Undefined) { - tx.send(Ok(None)).unwrap(); - return Ok(()); - } - let res: JsObject = result.try_into()?; - let content: JsString = res.get_named_property("content")?; - let content_type: JsString = res.get_named_property("type")?; - tx.send(Ok(Some(LoadResult { - content: content.into_utf8()?.into_owned()?, - content_type: content_type.into_utf8()?.into_owned()?, - }))) - .unwrap(); - } - - Ok(()) -} - -fn await_promise_with_void( - env: Env, - result: JsUnknown, - tx: Sender>, -) -> napi::Result<()> { - // If the result is a promise, wait for it to resolve, and send the result to the channel. - // Otherwise, send the result immediately. - if result.is_promise()? { - let result: JsObject = result.try_into()?; - let then: JsFunction = result.get_named_property("then")?; - let tx2 = tx.clone(); - let cb = env.create_function_from_closure("callback", move |ctx| { - tx.send(Ok(())).unwrap(); - ctx.env.get_undefined() - })?; - let eb = env.create_function_from_closure("error_callback", move |ctx| { - let res = ctx.get::(0)?; - tx2.send(Err(napi::Error::from(res))).unwrap(); - ctx.env.get_undefined() - })?; - then.call(Some(&result), &[cb, eb])?; - } else { - tx.send(Ok(())).unwrap(); - } - - Ok(()) -} - -pub struct ReadMessage { - pub message: T, - pub tx: Sender>, -} - -pub struct WriteRequest { - pub path: PathBuf, - pub content: Vec, - pub tx: Sender>, -} - -pub struct LoadResult { - pub content: String, - pub content_type: String, -} diff --git a/crates/mako/Cargo.toml b/crates/mako/Cargo.toml index f1f2ded89..e2608a694 100644 --- a/crates/mako/Cargo.toml +++ b/crates/mako/Cargo.toml @@ -71,7 +71,7 @@ swc_emotion = "0.51.0" swc_error_reporters = "0.16.1" swc_node_comments = "0.19.1" -anyhow = "1.0.71" +anyhow = { workspace = true } base64 = "0.22.1" chrono = "0.4.38" clap = { version = "4.3.11", features = ["derive"] } diff --git a/crates/mako/src/utils.rs b/crates/mako/src/utils.rs index 2d47f152c..75df86b0d 100644 --- a/crates/mako/src/utils.rs +++ b/crates/mako/src/utils.rs @@ -4,7 +4,7 @@ pub mod logger; pub mod profile_gui; #[cfg(test)] pub(crate) mod test_helper; -pub(crate) mod thread_pool; +pub mod thread_pool; pub mod tokio_runtime; use anyhow::{anyhow, Result}; diff --git a/packages/mako/binding.d.ts b/packages/mako/binding.d.ts index a9989c8a2..1972f583e 100644 --- a/packages/mako/binding.d.ts +++ b/packages/mako/binding.d.ts @@ -52,6 +52,14 @@ export interface JsHooks { onGenerateFile?: (path: string, content: Buffer) => Promise; buildStart?: () => Promise; } +export interface WriteFile { + path: string; + content: Buffer; +} +export interface LoadResult { + content: string; + type: string; +} export interface BuildParams { root: string; config: { @@ -223,4 +231,4 @@ export interface BuildParams { plugins: Array; watch: boolean; } -export function build(buildParams: BuildParams): Promise; +export declare function build(buildParams: BuildParams): Promise; From 8c3023b25ea7602370d891600b0537d6fe507194 Mon Sep 17 00:00:00 2001 From: pshu Date: Wed, 25 Sep 2024 14:37:43 +0800 Subject: [PATCH 06/21] =?UTF-8?q?docs:=20=F0=9F=93=9D=20=20change=20log=20?= =?UTF-8?q?20240925=20(#1613)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 6 ++++++ CHANGELOG_zh-CN.md | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 54e44edee..bf4c74ca5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## 0.8.14 + +`2024-09-25` + +* fix: bundler-mako dev server load chunks failed with 504 error code by [@stormslowly](https://github.com/stormslowly) in [#1612](https://github.com/umijs/mako/pull/1612) + ## 0.8.13 `2024-09-23` diff --git a/CHANGELOG_zh-CN.md b/CHANGELOG_zh-CN.md index a308746f2..c7c9649cb 100644 --- a/CHANGELOG_zh-CN.md +++ b/CHANGELOG_zh-CN.md @@ -1,3 +1,9 @@ +## 0.8.14 + +`2024-09-25` + +* 修复: dev 服务器加载 chunk 文件 504 错误 by [@stormslowly](https://github.com/stormslowly) in [#1612](https://github.com/umijs/mako/pull/1612) + ## 0.8.13 `2024-09-23` From 9a4c4d8a8ca766f93396a69d1388198d896257ee Mon Sep 17 00:00:00 2001 From: Jinbao1001 Date: Wed, 25 Sep 2024 15:42:30 +0800 Subject: [PATCH 07/21] feat: disable webp to base64 (#1602) * feat: init * fix: context * fix: no use * fix: typos * fix: typos * fix: typos * fix: typos --- crates/mako/src/build/load.rs | 17 +++++++++++++- crates/mako/src/config/config.rs | 2 ++ crates/mako/src/resolve.rs | 17 +++++--------- crates/mako/src/utils.rs | 5 +++++ docs/config.md | 21 ++++++++++++++++-- docs/config.zh-CN.md | 16 +++++++++++++ .../config.inline_excludes_regexes/expect.js | 8 +++++++ .../mako.config.json | 4 ++++ .../src/abc.webp | Bin 0 -> 117662 bytes .../src/index.tsx | 3 +++ 10 files changed, 79 insertions(+), 14 deletions(-) create mode 100644 e2e/fixtures/config.inline_excludes_regexes/expect.js create mode 100644 e2e/fixtures/config.inline_excludes_regexes/mako.config.json create mode 100644 e2e/fixtures/config.inline_excludes_regexes/src/abc.webp create mode 100644 e2e/fixtures/config.inline_excludes_regexes/src/index.tsx diff --git a/crates/mako/src/build/load.rs b/crates/mako/src/build/load.rs index 2ee205e1c..dfa2b95a9 100644 --- a/crates/mako/src/build/load.rs +++ b/crates/mako/src/build/load.rs @@ -4,6 +4,7 @@ use std::sync::Arc; use anyhow::{anyhow, Result}; use mdxjs::{compile, Options as MdxOptions}; +use regex::Regex; use serde_xml_rs::from_str as from_xml_str; use serde_yaml::{from_str as from_yaml_str, Value as YamlValue}; use thiserror::Error; @@ -14,6 +15,7 @@ use crate::ast::file::{Content, File, JsContent}; use crate::compiler::Context; use crate::config::Mode; use crate::plugin::PluginLoadParam; +use crate::utils::create_cached_regex; #[derive(Debug, Error)] enum LoadError { @@ -257,7 +259,20 @@ export function moduleToDom(css) { Ok(final_file_name) } }; - if !limit || file_size > context.config.inline_limit.try_into().unwrap() { + let inline_excludes_extensions = context + .config + .inline_excludes_extensions + .clone() + .iter() + .map(|s| create_cached_regex(s)) + .collect::>(); + let should_not_transform_base64 = inline_excludes_extensions + .iter() + .any(|regex| regex.is_match(&file.extname)); + if !limit + || file_size > context.config.inline_limit.try_into().unwrap() + || should_not_transform_base64 + { emit_assets() } else { let base64_result = file.get_base64(); diff --git a/crates/mako/src/config/config.rs b/crates/mako/src/config/config.rs index 80c56655a..0309648c7 100644 --- a/crates/mako/src/config/config.rs +++ b/crates/mako/src/config/config.rs @@ -525,6 +525,7 @@ pub struct Config { pub copy: Vec, pub public_path: String, pub inline_limit: usize, + pub inline_excludes_extensions: Vec, pub targets: HashMap, pub platform: Platform, pub module_id_strategy: ModuleIdStrategy, @@ -737,6 +738,7 @@ const DEFAULT_CONFIG: &str = r#" "providers": {}, "publicPath": "/", "inlineLimit": 10000, + "inlineExcludesExtensions": [], "targets": { "chrome": 80 }, "less": { "theme": {}, "lesscPath": "", javascriptEnabled: true }, "define": {}, diff --git a/crates/mako/src/resolve.rs b/crates/mako/src/resolve.rs index 89ffde4d5..19a62d2fe 100644 --- a/crates/mako/src/resolve.rs +++ b/crates/mako/src/resolve.rs @@ -4,10 +4,9 @@ use std::sync::Arc; use std::vec; use anyhow::{anyhow, Result}; -use cached::proc_macro::cached; use convert_case::{Case, Casing}; use oxc_resolver::{Alias, AliasValue, ResolveError as OxcResolveError, ResolveOptions, Resolver}; -use regex::{Captures, Regex}; +use regex::Captures; use thiserror::Error; use tracing::debug; @@ -22,6 +21,7 @@ use crate::config::{ }; use crate::features::rsc::Rsc; use crate::module::{Dependency, ResolveType}; +use crate::utils::create_cached_regex; #[derive(Debug, Error)] #[error("Resolve {path:?} failed from {from:?}")] @@ -73,11 +73,6 @@ pub fn resolve( do_resolve(path, source, resolver, Some(&context.config.externals)) } -#[cached(key = "String", convert = r#"{ re.to_string() }"#)] -fn create_external_regex(re: &str) -> Regex { - Regex::new(re).unwrap() -} - fn get_external_target( externals: &HashMap, source: &str, @@ -113,7 +108,7 @@ fn get_external_target( externals.iter().find_map(|(key, config)| { match config { ExternalConfig::Advanced(config) if config.subpath.is_some() => { - if let Some(caps) = create_external_regex(&format!( + if let Some(caps) = create_cached_regex(&format!( r#"(?:^|/node_modules/|[a-zA-Z\d]@){}(/|$)"#, key )) @@ -126,7 +121,7 @@ fn get_external_target( // skip if source is excluded Some(exclude) if exclude.iter().any(|e| { - create_external_regex(&format!("(^|/){}(/|$)", e)) + create_cached_regex(&format!("(^|/){}(/|$)", e)) .is_match(subpath.as_str()) }) => { @@ -146,7 +141,7 @@ fn get_external_target( // ex. import Button from 'antd/es/button'; // find matched subpath rule if let Some((rule, caps)) = subpath_config.rules.iter().find_map(|r| { - let regex = create_external_regex(r.regex.as_str()); + let regex = create_cached_regex(r.regex.as_str()); if regex.is_match(subpath.as_str()) { Some((r, regex.captures(subpath.as_str()).unwrap())) @@ -162,7 +157,7 @@ fn get_external_target( } // external to target template ExternalAdvancedSubpathTarget::Tpl(target) => { - let regex = create_external_regex(r"\$(\d+)"); + let regex = create_cached_regex(r"\$(\d+)"); // replace $1, $2, ... with captured groups let mut replaced = regex diff --git a/crates/mako/src/utils.rs b/crates/mako/src/utils.rs index 75df86b0d..fb3778fdf 100644 --- a/crates/mako/src/utils.rs +++ b/crates/mako/src/utils.rs @@ -10,6 +10,7 @@ pub mod tokio_runtime; use anyhow::{anyhow, Result}; use base64::engine::general_purpose; use base64::Engine; +use cached::proc_macro::cached; use regex::Regex; pub fn base64_encode>(raw: T) -> String { @@ -50,6 +51,10 @@ pub fn process_req_url(public_path: &str, req_url: &str) -> Result { Ok(req_url.to_string()) } +#[cached(key = "String", convert = r#"{ re.to_string() }"#)] +pub fn create_cached_regex(re: &str) -> Regex { + Regex::new(re).unwrap() +} #[cfg(test)] mod tests { use super::*; diff --git a/docs/config.md b/docs/config.md index b7eec7cd8..44205841e 100644 --- a/docs/config.md +++ b/docs/config.md @@ -392,11 +392,28 @@ Notice: This configuration can only be used with umd, because injecting CSS is n ### inlineLimit -- Type: `number` -- Default: `10000` +- Type: `string[]` +- Default: `[]` Specify the size limit of the assets file that needs to be converted to `base64` format. + +### inlineExcludesExtensions + +- Type: `string[]` +- Default: `[]` + +Excludes assets file extension list that don't need to be converted to `base64` format. + +e.g. + +```ts +{ + "inlineExcludesExtensions": ["webp"] +} +``` + + ### less - Type: `{ modifyVars?: Record, globalVars?: Record, sourceMap?: { sourceMapFileInline?: boolean, outputSourceFiles?: boolean }, math?: "always" | "strict" | "parens-division" | "parens" | "strict-legacy" | number, plugins?: ([string, Record]|string)[] }` diff --git a/docs/config.zh-CN.md b/docs/config.zh-CN.md index 819f92a78..152377c31 100644 --- a/docs/config.zh-CN.md +++ b/docs/config.zh-CN.md @@ -398,6 +398,22 @@ e.g. 指定需要转换为 `base64` 格式的资产文件的大小限制。 + +### inlineExcludesExtensions + +- 类型: `string[]` +- 默认值: `[]` + +指定不需要转换为 `base64` 格式的资产文件的后缀名列表。 + +例如: + +```ts +{ + "inlineExcludesExtensions": ["webp"] +} +``` + ### less - 类型:`{ modifyVars?: Record, globalVars?: Record, sourceMap?: { sourceMapFileInline?: boolean, outputSourceFiles?: boolean }, math?: "always" | "strict" | "parens-division" | "parens" | "strict-legacy" | number, plugins?: ([string, Record]|string)[] }` diff --git a/e2e/fixtures/config.inline_excludes_regexes/expect.js b/e2e/fixtures/config.inline_excludes_regexes/expect.js new file mode 100644 index 000000000..11b0ea09f --- /dev/null +++ b/e2e/fixtures/config.inline_excludes_regexes/expect.js @@ -0,0 +1,8 @@ +const assert = require("assert"); +const { parseBuildResult } = require("../../../scripts/test-utils"); +const { files } = parseBuildResult(__dirname); + +const names = Object.keys(files).join(","); + +// check files +assert.match(names, /abc.(.*).webp/, "should have origin webp"); diff --git a/e2e/fixtures/config.inline_excludes_regexes/mako.config.json b/e2e/fixtures/config.inline_excludes_regexes/mako.config.json new file mode 100644 index 000000000..1706e6daf --- /dev/null +++ b/e2e/fixtures/config.inline_excludes_regexes/mako.config.json @@ -0,0 +1,4 @@ +{ + "inlineExcludesExtensions": ["webp"], + "inlineLimit": 1000000 +} diff --git a/e2e/fixtures/config.inline_excludes_regexes/src/abc.webp b/e2e/fixtures/config.inline_excludes_regexes/src/abc.webp new file mode 100644 index 0000000000000000000000000000000000000000..71c4310e9901ee3a88934eb5ed11efbb840f4e6f GIT binary patch literal 117662 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 Date: Fri, 27 Sep 2024 17:59:39 +0800 Subject: [PATCH 08/21] fix(bundler-mako): experimental config should be merged deeply (#1617) --- packages/bundler-mako/index.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/bundler-mako/index.js b/packages/bundler-mako/index.js index 318932b14..43ff235df 100644 --- a/packages/bundler-mako/index.js +++ b/packages/bundler-mako/index.js @@ -636,6 +636,8 @@ async function getMakoConfig(opts) { plugins: opts.config.lessLoader?.plugins, }, analyze: analyze || process.env.ANALYZE ? {} : undefined, + sass: sassLoader, + ...mako, experimental: { webpackSyntaxValidate: [], requireContext: true, @@ -643,9 +645,8 @@ async function getMakoConfig(opts) { ignores: ['node_modules', '\\.umi'], graphviz: false, }, + ...mako.experimental, }, - sass: sassLoader, - ...mako, }; return makoConfig; From d9d25110ede1fa40b1ff6acf84dbfee0efda180c Mon Sep 17 00:00:00 2001 From: xusd320 Date: Fri, 27 Sep 2024 19:20:07 +0800 Subject: [PATCH 09/21] refactor: config codes organization (#1618) * refactor: config codes organization * fix: typos * refactor: config parse error --- crates/mako/src/config.rs | 491 +++++++- crates/mako/src/config/analyze.rs | 4 + crates/mako/src/config/code_splitting.rs | 145 +++ crates/mako/src/config/config.rs | 1093 ----------------- crates/mako/src/config/dev_server.rs | 12 + crates/mako/src/config/devtool.rs | 15 + .../src/config/duplicate_package_checker.rs | 18 + crates/mako/src/config/experimental.rs | 21 + crates/mako/src/config/external.rs | 77 ++ crates/mako/src/config/generic_usize.rs | 17 + crates/mako/src/config/hmr.rs | 9 + crates/mako/src/config/inline_css.rs | 8 + crates/mako/src/config/macros.rs | 33 + .../mako/src/config/mako.config.default.json | 79 ++ crates/mako/src/config/manifest.rs | 16 + crates/mako/src/config/minifish.rs | 27 + crates/mako/src/config/mode.rs | 16 + crates/mako/src/config/module_id_strategy.rs | 11 + crates/mako/src/config/optimization.rs | 12 + crates/mako/src/config/output.rs | 58 + crates/mako/src/config/progress.rs | 11 + crates/mako/src/config/provider.rs | 7 + crates/mako/src/config/px2rem.rs | 40 + crates/mako/src/config/react.rs | 19 + crates/mako/src/config/resolve.rs | 7 + crates/mako/src/config/rsc_client.rs | 20 + crates/mako/src/config/rsc_server.rs | 13 + crates/mako/src/config/stats.rs | 10 + crates/mako/src/config/transform_import.rs | 16 + crates/mako/src/config/tree_shaking.rs | 13 + crates/mako/src/config/umd.rs | 7 + crates/mako/src/config/watch.rs | 9 + crates/mako/src/generate/chunk_pot/util.rs | 3 +- crates/mako/src/utils.rs | 17 + 34 files changed, 1257 insertions(+), 1097 deletions(-) create mode 100644 crates/mako/src/config/analyze.rs create mode 100644 crates/mako/src/config/code_splitting.rs delete mode 100644 crates/mako/src/config/config.rs create mode 100644 crates/mako/src/config/dev_server.rs create mode 100644 crates/mako/src/config/devtool.rs create mode 100644 crates/mako/src/config/duplicate_package_checker.rs create mode 100644 crates/mako/src/config/experimental.rs create mode 100644 crates/mako/src/config/external.rs create mode 100644 crates/mako/src/config/generic_usize.rs create mode 100644 crates/mako/src/config/hmr.rs create mode 100644 crates/mako/src/config/inline_css.rs create mode 100644 crates/mako/src/config/macros.rs create mode 100644 crates/mako/src/config/mako.config.default.json create mode 100644 crates/mako/src/config/manifest.rs create mode 100644 crates/mako/src/config/minifish.rs create mode 100644 crates/mako/src/config/mode.rs create mode 100644 crates/mako/src/config/module_id_strategy.rs create mode 100644 crates/mako/src/config/optimization.rs create mode 100644 crates/mako/src/config/output.rs create mode 100644 crates/mako/src/config/progress.rs create mode 100644 crates/mako/src/config/provider.rs create mode 100644 crates/mako/src/config/px2rem.rs create mode 100644 crates/mako/src/config/react.rs create mode 100644 crates/mako/src/config/resolve.rs create mode 100644 crates/mako/src/config/rsc_client.rs create mode 100644 crates/mako/src/config/rsc_server.rs create mode 100644 crates/mako/src/config/stats.rs create mode 100644 crates/mako/src/config/transform_import.rs create mode 100644 crates/mako/src/config/tree_shaking.rs create mode 100644 crates/mako/src/config/umd.rs create mode 100644 crates/mako/src/config/watch.rs diff --git a/crates/mako/src/config.rs b/crates/mako/src/config.rs index 51be8ae37..1dbc8c3ef 100644 --- a/crates/mako/src/config.rs +++ b/crates/mako/src/config.rs @@ -1,3 +1,488 @@ -#[allow(clippy::module_inception)] -mod config; -pub use config::*; +mod analyze; +mod code_splitting; +mod dev_server; +mod devtool; +mod duplicate_package_checker; +mod experimental; +mod external; +mod generic_usize; +mod hmr; +mod inline_css; +mod macros; +mod manifest; +mod minifish; +mod mode; +mod module_id_strategy; +mod optimization; +mod output; +mod progress; +mod provider; +mod px2rem; +mod react; +mod resolve; +mod rsc_client; +mod rsc_server; +mod stats; +mod transform_import; +mod tree_shaking; +mod umd; +mod watch; + +use std::collections::HashMap; +use std::fmt; +use std::path::{Path, PathBuf}; + +pub use analyze::AnalyzeConfig; +use anyhow::{anyhow, Result}; +pub use code_splitting::*; +use colored::Colorize; +use config; +pub use dev_server::{deserialize_dev_server, DevServerConfig}; +pub use devtool::{deserialize_devtool, DevtoolConfig}; +pub use duplicate_package_checker::{ + deserialize_check_duplicate_package, DuplicatePackageCheckerConfig, +}; +use experimental::ExperimentalConfig; +pub use external::{ + ExternalAdvanced, ExternalAdvancedSubpath, ExternalAdvancedSubpathConverter, + ExternalAdvancedSubpathRule, ExternalAdvancedSubpathTarget, ExternalConfig, +}; +pub use generic_usize::GenericUsizeDefault; +pub use hmr::{deserialize_hmr, HmrConfig}; +pub use inline_css::{deserialize_inline_css, InlineCssConfig}; +pub use manifest::{deserialize_manifest, ManifestConfig}; +use miette::{miette, ByteOffset, Diagnostic, NamedSource, SourceOffset, SourceSpan}; +pub use minifish::{deserialize_minifish, MinifishConfig}; +pub use mode::Mode; +pub use module_id_strategy::ModuleIdStrategy; +pub use optimization::{deserialize_optimization, OptimizationConfig}; +use output::get_default_chunk_loading_global; +pub use output::{CrossOriginLoading, OutputConfig, OutputMode}; +pub use progress::{deserialize_progress, ProgressConfig}; +pub use provider::Providers; +pub use px2rem::{deserialize_px2rem, Px2RemConfig}; +pub use react::{ReactConfig, ReactRuntimeConfig}; +pub use resolve::ResolveConfig; +pub use rsc_client::{deserialize_rsc_client, LogServerComponent, RscClientConfig}; +pub use rsc_server::{deserialize_rsc_server, RscServerConfig}; +use serde::{Deserialize, Serialize}; +use serde_json::Value; +pub use stats::{deserialize_stats, StatsConfig}; +use thiserror::Error; +pub use transform_import::{TransformImportConfig, TransformImportStyle}; +pub use tree_shaking::{deserialize_tree_shaking, TreeShakingStrategy}; +pub use umd::{deserialize_umd, Umd}; +pub use watch::WatchConfig; + +use crate::features::node::Node; + +#[derive(Debug, Diagnostic)] +#[diagnostic(code("mako.config.json parsed failed"))] +struct ConfigParseError { + #[source_code] + src: NamedSource, + #[label("Error here.")] + span: SourceSpan, + message: String, +} + +impl std::error::Error for ConfigParseError {} + +impl fmt::Display for ConfigParseError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.message) + } +} + +fn validate_mako_config(abs_config_file: String) -> miette::Result<()> { + if Path::new(&abs_config_file).exists() { + let content = std::fs::read_to_string(abs_config_file.clone()) + .map_err(|e| miette!("Failed to read file '{}': {}", &abs_config_file, e))?; + let result: Result = serde_json::from_str(&content); + if let Err(e) = result { + let line = e.line(); + let column = e.column(); + let start = SourceOffset::from_location(&content, line, column); + let span = SourceSpan::new(start, (1 as ByteOffset).into()); + return Err(ConfigParseError { + src: NamedSource::new("mako.config.json", content), + span, + message: e.to_string(), + } + .into()); + } + } + Ok(()) +} + +#[derive(Deserialize, Serialize, Debug, PartialEq, Eq)] +pub enum Platform { + #[serde(rename = "browser")] + Browser, + #[serde(rename = "node")] + Node, +} + +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct Config { + pub entry: HashMap, + pub output: OutputConfig, + pub resolve: ResolveConfig, + #[serde(deserialize_with = "deserialize_manifest", default)] + pub manifest: Option, + pub mode: Mode, + pub minify: bool, + #[serde(deserialize_with = "deserialize_devtool")] + pub devtool: Option, + pub externals: HashMap, + pub providers: Providers, + pub copy: Vec, + pub public_path: String, + pub inline_limit: usize, + pub inline_excludes_extensions: Vec, + pub targets: HashMap, + pub platform: Platform, + pub module_id_strategy: ModuleIdStrategy, + pub define: HashMap, + pub analyze: Option, + pub stats: Option, + pub mdx: bool, + #[serde(deserialize_with = "deserialize_hmr")] + pub hmr: Option, + #[serde(deserialize_with = "deserialize_dev_server")] + pub dev_server: Option, + #[serde(deserialize_with = "deserialize_code_splitting", default)] + pub code_splitting: Option, + #[serde(deserialize_with = "deserialize_px2rem", default)] + pub px2rem: Option, + #[serde(deserialize_with = "deserialize_progress", default)] + pub progress: Option, + pub hash: bool, + #[serde(rename = "_treeShaking", deserialize_with = "deserialize_tree_shaking")] + pub _tree_shaking: Option, + #[serde(rename = "autoCSSModules")] + pub auto_css_modules: bool, + #[serde(rename = "ignoreCSSParserErrors")] + pub ignore_css_parser_errors: bool, + pub dynamic_import_to_require: bool, + #[serde(deserialize_with = "deserialize_umd", default)] + pub umd: Option, + pub cjs: bool, + pub write_to_disk: bool, + pub transform_import: Vec, + pub chunk_parallel: bool, + pub clean: bool, + pub node_polyfill: bool, + pub ignores: Vec, + #[serde( + rename = "_minifish", + deserialize_with = "deserialize_minifish", + default + )] + pub _minifish: Option, + #[serde(rename = "optimizePackageImports")] + pub optimize_package_imports: bool, + pub emotion: bool, + pub flex_bugs: bool, + #[serde(deserialize_with = "deserialize_optimization")] + pub optimization: Option, + pub react: ReactConfig, + pub emit_assets: bool, + #[serde(rename = "cssModulesExportOnlyLocales")] + pub css_modules_export_only_locales: bool, + #[serde( + rename = "inlineCSS", + deserialize_with = "deserialize_inline_css", + default + )] + pub inline_css: Option, + #[serde( + rename = "rscServer", + deserialize_with = "deserialize_rsc_server", + default + )] + pub rsc_server: Option, + #[serde( + rename = "rscClient", + deserialize_with = "deserialize_rsc_client", + default + )] + pub rsc_client: Option, + pub experimental: ExperimentalConfig, + pub watch: WatchConfig, + pub use_define_for_class_fields: bool, + pub emit_decorator_metadata: bool, + #[serde( + rename = "duplicatePackageChecker", + deserialize_with = "deserialize_check_duplicate_package", + default + )] + pub check_duplicate_package: Option, +} + +const CONFIG_FILE: &str = "mako.config.json"; +const DEFAULT_CONFIG: &str = include_str!("./config/mako.config.default.json"); + +impl Config { + pub fn new( + root: &Path, + default_config: Option<&str>, + cli_config: Option<&str>, + ) -> Result { + let abs_config_file = root.join(CONFIG_FILE); + let abs_config_file = abs_config_file.to_str().unwrap(); + let c = config::Config::builder(); + // default config + let c = c.add_source(config::File::from_str( + DEFAULT_CONFIG, + config::FileFormat::Json5, + )); + // default config from args + let c = if let Some(default_config) = default_config { + c.add_source(config::File::from_str( + default_config, + config::FileFormat::Json5, + )) + } else { + c + }; + // validate user config + validate_mako_config(abs_config_file.to_string()).map_err(|e| anyhow!("{}", e))?; + // user config + let c = c.add_source(config::File::with_name(abs_config_file).required(false)); + // cli config + let c = if let Some(cli_config) = cli_config { + c.add_source(config::File::from_str( + cli_config, + config::FileFormat::Json5, + )) + } else { + c + }; + + let c = c.build()?; + let mut ret = c.try_deserialize::(); + // normalize & check + if let Ok(config) = &mut ret { + // normalize output + if config.output.path.is_relative() { + config.output.path = root.join(config.output.path.to_string_lossy().to_string()); + } + + if config.output.chunk_loading_global.is_empty() { + config.output.chunk_loading_global = + get_default_chunk_loading_global(config.umd.clone(), root); + } + + let node_env_config_opt = config.define.get("NODE_ENV"); + if let Some(node_env_config) = node_env_config_opt { + if node_env_config.as_str() != Some(config.mode.to_string().as_str()) { + let warn_message = format!( + "{}: The configuration of {} conflicts with current {} and will be overwritten as {} ", + "warning".to_string().yellow(), + "NODE_ENV".to_string().yellow(), + "mode".to_string().yellow(), + config.mode.to_string().red() + ); + println!("{}", warn_message); + } + } + + if config.cjs && config.umd.is_some() { + return Err(anyhow!("cjs and umd cannot be used at the same time",)); + } + + if config.hmr.is_some() && config.dev_server.is_none() { + return Err(anyhow!("hmr can only be used with devServer",)); + } + + if config.inline_css.is_some() && config.umd.is_none() { + return Err(anyhow!("inlineCSS can only be used with umd",)); + } + + let mode = format!("\"{}\"", config.mode); + config + .define + .insert("NODE_ENV".to_string(), serde_json::Value::String(mode)); + + if config.public_path != "runtime" && !config.public_path.ends_with('/') { + return Err(anyhow!("public_path must end with '/' or be 'runtime'")); + } + + // 暂不支持 remote external + // 如果 config.externals 中有值是以「script 」开头,则 panic 报错 + let basic_external_values = config + .externals + .values() + .filter_map(|v| match v { + ExternalConfig::Basic(b) => Some(b), + _ => None, + }) + .collect::>(); + for v in basic_external_values { + if v.starts_with("script ") { + return Err(anyhow!( + "remote external is not supported yet, but we found {}", + v.to_string().red() + )); + } + } + + // support default entries + if config.entry.is_empty() { + let file_paths = vec!["src/index.tsx", "src/index.ts", "index.tsx", "index.ts"]; + for file_path in file_paths { + let file_path = root.join(file_path); + if file_path.exists() { + config.entry.insert("index".to_string(), file_path); + break; + } + } + if config.entry.is_empty() { + return Err(anyhow!("Entry is empty")); + } + } + + // normalize entry + let entry_tuples = config + .entry + .clone() + .into_iter() + .map(|(k, v)| { + if let Ok(entry_path) = root.join(v).canonicalize() { + Ok((k, entry_path)) + } else { + Err(anyhow!("entry:{} not found", k,)) + } + }) + .collect::>>()?; + config.entry = entry_tuples.into_iter().collect(); + + // support relative alias + config.resolve.alias = config + .resolve + .alias + .clone() + .into_iter() + .map(|(k, v)| { + let v = if v.starts_with('.') { + root.join(v).to_string_lossy().to_string() + } else { + v + }; + (k, v) + }) + .collect(); + + // dev 环境下不产生 hash, prod 环境下根据用户配置 + if config.mode == Mode::Development { + config.hash = false; + } + + // configure node platform + Node::modify_config(config); + } + ret.map_err(|e| anyhow!("{}: {}", "config error".red(), e.to_string().red())) + } +} + +impl Default for Config { + fn default() -> Self { + let c = config::Config::builder(); + let c = c.add_source(config::File::from_str( + DEFAULT_CONFIG, + config::FileFormat::Json5, + )); + let c = c.build().unwrap(); + c.try_deserialize::().unwrap() + } +} + +#[derive(Error, Debug)] +pub enum ConfigError { + #[error("define value '{0}' is not an Expression")] + InvalidateDefineConfig(String), +} + +#[cfg(test)] +mod tests { + use crate::config::{Config, Mode, Platform}; + + #[test] + fn test_config() { + let current_dir = std::env::current_dir().unwrap(); + let config = Config::new(¤t_dir.join("test/config/normal"), None, None).unwrap(); + println!("{:?}", config); + assert_eq!(config.platform, Platform::Node); + } + + #[test] + fn test_config_args_default() { + let current_dir = std::env::current_dir().unwrap(); + let config = Config::new( + ¤t_dir.join("test/config/normal"), + Some(r#"{"mode":"production"}"#), + None, + ) + .unwrap(); + println!("{:?}", config); + assert_eq!(config.mode, Mode::Production); + } + + #[test] + fn test_config_cli_args() { + let current_dir = std::env::current_dir().unwrap(); + let config = Config::new( + ¤t_dir.join("test/config/normal"), + None, + Some(r#"{"platform":"browser"}"#), + ) + .unwrap(); + println!("{:?}", config); + assert_eq!(config.platform, Platform::Browser); + } + + #[test] + fn test_node_env_conflicts_with_mode() { + let current_dir = std::env::current_dir().unwrap(); + let config = Config::new( + ¤t_dir.join("test/config/node-env"), + None, + Some(r#"{"mode":"development"}"#), + ) + .unwrap(); + assert_eq!( + config.define.get("NODE_ENV"), + Some(&serde_json::Value::String("\"development\"".to_string())) + ); + } + + #[test] + #[should_panic(expected = "public_path must end with '/' or be 'runtime'")] + fn test_config_invalid_public_path() { + let current_dir = std::env::current_dir().unwrap(); + Config::new( + ¤t_dir.join("test/config/normal"), + None, + Some(r#"{"publicPath":"abc"}"#), + ) + .unwrap(); + } + + #[test] + fn test_node_platform() { + let current_dir = std::env::current_dir().unwrap(); + let config = + Config::new(¤t_dir.join("test/config/node-platform"), None, None).unwrap(); + assert_eq!( + config.targets.get("node"), + Some(&14.0), + "use node targets by default if platform is node", + ); + assert!( + config.ignores.iter().any(|i| i.contains("|fs|")), + "ignore Node.js standard library by default if platform is node", + ); + } +} diff --git a/crates/mako/src/config/analyze.rs b/crates/mako/src/config/analyze.rs new file mode 100644 index 000000000..1a4655123 --- /dev/null +++ b/crates/mako/src/config/analyze.rs @@ -0,0 +1,4 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Deserialize, Serialize, Clone, Debug)] +pub struct AnalyzeConfig {} diff --git a/crates/mako/src/config/code_splitting.rs b/crates/mako/src/config/code_splitting.rs new file mode 100644 index 000000000..73e973f98 --- /dev/null +++ b/crates/mako/src/config/code_splitting.rs @@ -0,0 +1,145 @@ +use regex::Regex; +use serde::{Deserialize, Serialize}; + +use super::generic_usize::GenericUsizeDefault; +use crate::create_deserialize_fn; + +#[derive(Deserialize, Serialize, Clone, Debug, Default)] +pub enum OptimizeAllowChunks { + #[serde(rename = "all")] + All, + #[serde(rename = "entry")] + Entry, + #[serde(rename = "async")] + #[default] + Async, +} + +#[derive(Deserialize, Serialize, Clone, Debug)] +pub struct CodeSplitting { + pub strategy: CodeSplittingStrategy, + pub options: Option, +} + +#[derive(Deserialize, Serialize, Clone, Debug)] +pub enum CodeSplittingStrategy { + #[serde(rename = "auto")] + Auto, + #[serde(rename = "granular")] + Granular, + #[serde(rename = "advanced")] + Advanced, +} + +#[derive(Deserialize, Serialize, Clone, Debug)] +#[serde(untagged)] +pub enum CodeSplittingStrategyOptions { + Granular(CodeSplittingGranularOptions), + Advanced(CodeSplittingAdvancedOptions), +} + +#[derive(Deserialize, Serialize, Clone, Debug)] +#[serde(rename_all = "camelCase")] +pub struct CodeSplittingGranularOptions { + pub framework_packages: Vec, + #[serde(default = "GenericUsizeDefault::<160000>::value")] + pub lib_min_size: usize, +} + +#[derive(Deserialize, Serialize, Clone, Debug)] +#[serde(rename_all = "camelCase")] +pub struct CodeSplittingAdvancedOptions { + #[serde(default = "GenericUsizeDefault::<20000>::value")] + pub min_size: usize, + pub groups: Vec, +} + +impl Default for CodeSplittingAdvancedOptions { + fn default() -> Self { + CodeSplittingAdvancedOptions { + min_size: GenericUsizeDefault::<20000>::value(), + groups: vec![], + } + } +} + +#[derive(Deserialize, Serialize, Clone, Debug)] +pub enum OptimizeChunkNameSuffixStrategy { + #[serde(rename = "packageName")] + PackageName, + #[serde(rename = "dependentsHash")] + DependentsHash, +} + +#[derive(Deserialize, Serialize, Clone, Debug)] +#[serde(rename_all = "camelCase")] +pub struct OptimizeChunkGroup { + pub name: String, + #[serde(default)] + pub name_suffix: Option, + #[serde(default)] + pub allow_chunks: OptimizeAllowChunks, + #[serde(default = "GenericUsizeDefault::<1>::value")] + pub min_chunks: usize, + #[serde(default = "GenericUsizeDefault::<20000>::value")] + pub min_size: usize, + #[serde(default = "GenericUsizeDefault::<5000000>::value")] + pub max_size: usize, + #[serde(default)] + pub min_module_size: Option, + #[serde(default)] + pub priority: i8, + #[serde(default, with = "optimize_test_format")] + pub test: Option, +} + +impl Default for OptimizeChunkGroup { + fn default() -> Self { + Self { + allow_chunks: OptimizeAllowChunks::default(), + min_chunks: GenericUsizeDefault::<1>::value(), + min_size: GenericUsizeDefault::<20000>::value(), + max_size: GenericUsizeDefault::<5000000>::value(), + name: String::default(), + name_suffix: None, + min_module_size: None, + test: None, + priority: i8::default(), + } + } +} + +/** + * custom formatter for convert string to regex + * @see https://serde.rs/custom-date-format.html + */ +mod optimize_test_format { + use regex::Regex; + use serde::{self, Deserialize, Deserializer, Serializer}; + + pub fn serialize(v: &Option, serializer: S) -> Result + where + S: Serializer, + { + if let Some(v) = v { + serializer.serialize_str(&v.to_string()) + } else { + serializer.serialize_none() + } + } + + pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> + where + D: Deserializer<'de>, + { + let v = String::deserialize(deserializer)?; + + if v.is_empty() { + Ok(None) + } else { + Ok(Regex::new(v.as_str()).ok()) + } + } +} + +create_deserialize_fn!(deserialize_code_splitting, CodeSplitting); diff --git a/crates/mako/src/config/config.rs b/crates/mako/src/config/config.rs deleted file mode 100644 index 0309648c7..000000000 --- a/crates/mako/src/config/config.rs +++ /dev/null @@ -1,1093 +0,0 @@ -use std::collections::HashMap; -use std::fmt; -use std::path::{Path, PathBuf}; - -use anyhow::{anyhow, Result}; -use clap::ValueEnum; -use colored::Colorize; -use miette::{miette, ByteOffset, Diagnostic, NamedSource, SourceOffset, SourceSpan}; -use regex::Regex; -use serde::{Deserialize, Deserializer, Serialize}; -use serde_json::Value; -use swc_core::ecma::ast::EsVersion; -use thiserror::Error; -use {clap, config, thiserror}; - -use crate::features::node::Node; -use crate::{plugins, visitors}; - -#[derive(Debug, Diagnostic)] -#[diagnostic(code("mako.config.json parsed failed"))] -struct ConfigParseError { - #[source_code] - src: NamedSource, - #[label("Error here.")] - span: SourceSpan, - message: String, -} - -impl std::error::Error for ConfigParseError {} - -impl fmt::Display for ConfigParseError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.message) - } -} - -fn validate_mako_config(abs_config_file: String) -> miette::Result<()> { - if Path::new(&abs_config_file).exists() { - let content = std::fs::read_to_string(abs_config_file.clone()) - .map_err(|e| miette!("Failed to read file '{}': {}", &abs_config_file, e))?; - let result: Result = serde_json::from_str(&content); - if let Err(e) = result { - let line = e.line(); - let column = e.column(); - let start = SourceOffset::from_location(&content, line, column); - let span = SourceSpan::new(start, (1 as ByteOffset).into()); - return Err(ConfigParseError { - src: NamedSource::new("mako.config.json", content), - span, - message: e.to_string(), - } - .into()); - } - } - Ok(()) -} - -/** - * a macro to create deserialize function that allow false value for optional struct - */ -macro_rules! create_deserialize_fn { - ($fn_name:ident, $struct_type:ty) => { - pub fn $fn_name<'de, D>(deserializer: D) -> Result, D::Error> - where - D: Deserializer<'de>, - { - let value: serde_json::Value = serde_json::Value::deserialize(deserializer)?; - - match value { - // allow false value for optional struct - serde_json::Value::Bool(false) => Ok(None), - // try deserialize - serde_json::Value::Object(obj) => Ok(Some( - serde_json::from_value::<$struct_type>(serde_json::Value::Object(obj)) - .map_err(serde::de::Error::custom)?, - )), - serde_json::Value::String(s) => Ok(Some( - serde_json::from_value::<$struct_type>(serde_json::Value::String(s.clone())) - .map_err(serde::de::Error::custom)?, - )), - _ => Err(serde::de::Error::custom(format!( - "invalid `{}` value: {}", - stringify!($fn_name).replace("deserialize_", ""), - value - ))), - } - } - }; -} -create_deserialize_fn!(deserialize_hmr, HmrConfig); -create_deserialize_fn!(deserialize_dev_server, DevServerConfig); -create_deserialize_fn!(deserialize_manifest, ManifestConfig); -create_deserialize_fn!(deserialize_code_splitting, CodeSplitting); -create_deserialize_fn!(deserialize_px2rem, Px2RemConfig); -create_deserialize_fn!(deserialize_progress, ProgressConfig); -create_deserialize_fn!( - deserialize_check_duplicate_package, - DuplicatePackageCheckerConfig -); -create_deserialize_fn!(deserialize_umd, String); -create_deserialize_fn!(deserialize_devtool, DevtoolConfig); -create_deserialize_fn!(deserialize_tree_shaking, TreeShakingStrategy); -create_deserialize_fn!(deserialize_optimization, OptimizationConfig); -create_deserialize_fn!(deserialize_minifish, MinifishConfig); -create_deserialize_fn!(deserialize_inline_css, InlineCssConfig); -create_deserialize_fn!(deserialize_rsc_client, RscClientConfig); -create_deserialize_fn!(deserialize_rsc_server, RscServerConfig); -create_deserialize_fn!(deserialize_stats, StatsConfig); -create_deserialize_fn!(deserialize_detect_loop, DetectCircularDependence); -create_deserialize_fn!(deserialize_cross_origin_loading, CrossOriginLoading); - -#[derive(Deserialize, Serialize, Debug)] -#[serde(rename_all = "camelCase")] -pub struct OutputConfig { - pub path: PathBuf, - pub mode: OutputMode, - pub es_version: EsVersion, - pub meta: bool, - pub chunk_loading_global: String, - pub preserve_modules: bool, - pub preserve_modules_root: PathBuf, - pub skip_write: bool, - #[serde(deserialize_with = "deserialize_cross_origin_loading")] - pub cross_origin_loading: Option, - pub global_module_registry: bool, -} - -#[derive(Deserialize, Serialize, Debug, Clone)] -pub enum CrossOriginLoading { - #[serde(rename = "anonymous")] - Anonymous, - #[serde(rename = "use-credentials")] - UseCredentials, -} - -impl fmt::Display for CrossOriginLoading { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - CrossOriginLoading::Anonymous => write!(f, "anonymous"), - CrossOriginLoading::UseCredentials => write!(f, "use-credentials"), - } - } -} - -#[derive(Deserialize, Serialize, Debug)] -pub struct ManifestConfig { - #[serde( - rename(deserialize = "fileName"), - default = "plugins::manifest::default_manifest_file_name" - )] - pub file_name: String, - #[serde(rename(deserialize = "basePath"), default)] - pub base_path: String, -} - -#[derive(Deserialize, Serialize, Debug)] -pub struct ResolveConfig { - pub alias: Vec<(String, String)>, - pub extensions: Vec, -} - -// format: HashMap -// e.g. -// { "process": ("process", "") } -// { "Buffer": ("buffer", "Buffer") } -pub type Providers = HashMap; - -#[derive(Deserialize, Serialize, Debug, PartialEq, Eq, ValueEnum, Clone)] -pub enum Mode { - #[serde(rename = "development")] - Development, - #[serde(rename = "production")] - Production, -} - -#[derive(Deserialize, Serialize, Debug, PartialEq, Eq, ValueEnum, Clone)] -pub enum OutputMode { - #[serde(rename = "bundle")] - Bundle, - #[serde(rename = "bundless")] - Bundless, -} - -#[derive(Deserialize, Serialize, Debug, PartialEq, Eq)] -pub enum Platform { - #[serde(rename = "browser")] - Browser, - #[serde(rename = "node")] - Node, -} - -impl std::fmt::Display for Mode { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.to_possible_value().unwrap().get_name().fmt(f) - } -} - -#[derive(Deserialize, Serialize, Debug)] -pub enum DevtoolConfig { - /// Generate separate sourcemap file - #[serde(rename = "source-map")] - SourceMap, - /// Generate inline sourcemap - #[serde(rename = "inline-source-map")] - InlineSourceMap, -} - -#[derive(Deserialize, Serialize, Clone, Copy, Debug)] -pub enum ModuleIdStrategy { - #[serde(rename = "hashed")] - Hashed, - #[serde(rename = "named")] - Named, - #[serde(rename = "numeric")] - Numeric, -} - -#[derive(Deserialize, Serialize, Clone, Debug)] -#[serde(rename_all = "camelCase")] -pub struct CodeSplittingGranularOptions { - pub framework_packages: Vec, - #[serde(default = "GenericUsizeDefault::<160000>::value")] - pub lib_min_size: usize, -} - -#[derive(Deserialize, Serialize, Clone, Debug)] -pub struct StatsConfig { - pub modules: bool, -} - -#[derive(Deserialize, Serialize, Clone, Debug)] -pub struct AnalyzeConfig {} - -#[derive(Deserialize, Serialize, Clone, Debug)] -pub enum CodeSplittingStrategy { - #[serde(rename = "auto")] - Auto, - #[serde(rename = "granular")] - Granular, - #[serde(rename = "advanced")] - Advanced, -} - -#[derive(Deserialize, Serialize, Clone, Debug)] -#[serde(untagged)] -pub enum CodeSplittingStrategyOptions { - Granular(CodeSplittingGranularOptions), - Advanced(CodeSplittingAdvancedOptions), -} - -#[derive(Deserialize, Serialize, Clone, Debug)] -pub struct CodeSplitting { - pub strategy: CodeSplittingStrategy, - pub options: Option, -} - -#[derive(Deserialize, Serialize, Clone, Copy, Debug)] -pub enum TreeShakingStrategy { - #[serde(rename = "basic")] - Basic, - #[serde(rename = "advanced")] - Advanced, -} - -#[derive(Deserialize, Serialize, Clone, Debug)] -pub struct Px2RemConfig { - #[serde(default = "visitors::css_px2rem::default_root")] - pub root: f64, - #[serde(rename = "propBlackList", default)] - pub prop_blacklist: Vec, - #[serde(rename = "propWhiteList", default)] - pub prop_whitelist: Vec, - #[serde(rename = "selectorBlackList", default)] - pub selector_blacklist: Vec, - #[serde(rename = "selectorWhiteList", default)] - pub selector_whitelist: Vec, - #[serde(rename = "selectorDoubleList", default)] - pub selector_doublelist: Vec, - #[serde(rename = "minPixelValue", default)] - pub min_pixel_value: f64, - #[serde(rename = "mediaQuery", default)] - pub media_query: bool, -} - -#[derive(Deserialize, Serialize, Clone, Debug)] -pub struct ProgressConfig { - #[serde(rename = "progressChars", default)] - pub progress_chars: String, -} - -#[derive(Deserialize, Serialize, Clone, Debug)] -pub struct DuplicatePackageCheckerConfig { - #[serde(rename = "verbose", default)] - pub verbose: bool, - #[serde(rename = "emitError", default)] - pub emit_error: bool, - #[serde(rename = "showHelp", default)] - pub show_help: bool, -} - -impl Default for Px2RemConfig { - fn default() -> Self { - Px2RemConfig { - root: visitors::css_px2rem::default_root(), - prop_blacklist: vec![], - prop_whitelist: vec![], - selector_blacklist: vec![], - selector_whitelist: vec![], - selector_doublelist: vec![], - min_pixel_value: 0.0, - media_query: false, - } - } -} - -#[derive(Deserialize, Serialize, Clone, Debug)] -#[serde(untagged)] -pub enum TransformImportStyle { - Built(String), - Source(bool), -} - -#[derive(Deserialize, Serialize, Clone, Debug)] -#[serde(rename_all = "camelCase")] -pub struct TransformImportConfig { - pub library_name: String, - pub library_directory: Option, - pub style: Option, -} - -#[derive(Deserialize, Serialize, Debug, Hash)] -pub enum ExternalAdvancedSubpathConverter { - PascalCase, -} - -#[derive(Deserialize, Serialize, Debug, Hash)] -#[serde(untagged)] -pub enum ExternalAdvancedSubpathTarget { - Empty, - Tpl(String), -} - -#[derive(Deserialize, Serialize, Debug, Hash)] -pub struct ExternalAdvancedSubpathRule { - pub regex: String, - #[serde(with = "external_target_format")] - pub target: ExternalAdvancedSubpathTarget, - #[serde(rename = "targetConverter")] - pub target_converter: Option, -} - -/** - * custom formatter for convert $EMPTY to enum, because rename is not supported for $ symbol - * @see https://serde.rs/custom-date-format.html - */ -mod external_target_format { - use serde::{self, Deserialize, Deserializer, Serializer}; - - use super::ExternalAdvancedSubpathTarget; - - pub fn serialize(v: &ExternalAdvancedSubpathTarget, serializer: S) -> Result - where - S: Serializer, - { - match v { - ExternalAdvancedSubpathTarget::Empty => serializer.serialize_str("$EMPTY"), - ExternalAdvancedSubpathTarget::Tpl(s) => serializer.serialize_str(s), - } - } - - pub fn deserialize<'de, D>(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let v = String::deserialize(deserializer)?; - - if v == "$EMPTY" { - Ok(ExternalAdvancedSubpathTarget::Empty) - } else { - Ok(ExternalAdvancedSubpathTarget::Tpl(v)) - } - } -} - -#[derive(Deserialize, Serialize, Debug, Hash)] -pub struct ExternalAdvancedSubpath { - pub exclude: Option>, - pub rules: Vec, -} - -#[derive(Deserialize, Serialize, Debug, Hash)] -pub struct ExternalAdvanced { - pub root: String, - #[serde(rename = "type")] - pub module_type: Option, - pub script: Option, - pub subpath: Option, -} - -#[derive(Deserialize, Serialize, Debug, Hash)] -#[serde(untagged)] -pub enum ExternalConfig { - Basic(String), - Advanced(ExternalAdvanced), -} - -#[derive(Deserialize, Serialize, Debug)] -#[serde(rename_all = "camelCase")] -pub struct InjectItem { - pub from: String, - pub named: Option, - pub namespace: Option, - pub exclude: Option, - pub include: Option, - pub prefer_require: Option, -} - -#[derive(Deserialize, Serialize, Debug, Clone)] -pub enum ReactRuntimeConfig { - #[serde(rename = "automatic")] - Automatic, - #[serde(rename = "classic")] - Classic, -} - -#[derive(Deserialize, Serialize, Debug)] -pub struct ReactConfig { - pub pragma: String, - #[serde(rename = "importSource")] - pub import_source: String, - pub runtime: ReactRuntimeConfig, - #[serde(rename = "pragmaFrag")] - pub pragma_frag: String, -} - -#[derive(Deserialize, Serialize, Debug)] -#[serde(rename_all = "camelCase")] -pub struct MinifishConfig { - pub mapping: HashMap, - pub meta_path: Option, - pub inject: Option>, -} - -#[derive(Deserialize, Serialize, Debug)] -#[serde(rename_all = "camelCase")] -pub struct OptimizationConfig { - pub skip_modules: Option, - pub concatenate_modules: Option, -} - -#[derive(Deserialize, Serialize, Debug)] -pub struct InlineCssConfig {} - -#[derive(Deserialize, Serialize, Debug)] -#[serde(rename_all = "camelCase")] -pub struct RscServerConfig { - pub client_component_tpl: String, - #[serde(rename = "emitCSS")] - pub emit_css: bool, -} - -#[derive(Deserialize, Serialize, Debug, PartialEq, Eq, ValueEnum, Clone)] -pub enum LogServerComponent { - #[serde(rename = "error")] - Error, - #[serde(rename = "ignore")] - Ignore, -} - -#[derive(Deserialize, Serialize, Debug)] -#[serde(rename_all = "camelCase")] -pub struct RscClientConfig { - pub log_server_component: LogServerComponent, -} - -#[derive(Deserialize, Serialize, Debug)] -#[serde(rename_all = "camelCase")] -pub struct DetectCircularDependence { - pub ignores: Vec, - pub graphviz: bool, -} - -#[derive(Deserialize, Serialize, Debug)] -#[serde(rename_all = "camelCase")] -pub struct ExperimentalConfig { - pub webpack_syntax_validate: Vec, - pub require_context: bool, - #[serde(deserialize_with = "deserialize_detect_loop")] - pub detect_circular_dependence: Option, -} - -#[derive(Deserialize, Serialize, Debug)] -#[serde(rename_all = "camelCase")] -pub struct WatchConfig { - pub ignore_paths: Option>, - #[serde(rename = "_nodeModulesRegexes")] - pub node_modules_regexes: Option>, -} - -#[derive(Deserialize, Serialize, Debug)] -#[serde(rename_all = "camelCase")] -pub struct HmrConfig {} - -#[derive(Deserialize, Serialize, Debug)] -#[serde(rename_all = "camelCase")] -pub struct DevServerConfig { - pub host: String, - pub port: u16, -} - -#[derive(Deserialize, Serialize, Debug)] -#[serde(rename_all = "camelCase")] -pub struct Config { - pub entry: HashMap, - pub output: OutputConfig, - pub resolve: ResolveConfig, - #[serde(deserialize_with = "deserialize_manifest", default)] - pub manifest: Option, - pub mode: Mode, - pub minify: bool, - #[serde(deserialize_with = "deserialize_devtool")] - pub devtool: Option, - pub externals: HashMap, - pub providers: Providers, - pub copy: Vec, - pub public_path: String, - pub inline_limit: usize, - pub inline_excludes_extensions: Vec, - pub targets: HashMap, - pub platform: Platform, - pub module_id_strategy: ModuleIdStrategy, - pub define: HashMap, - pub analyze: Option, - pub stats: Option, - pub mdx: bool, - #[serde(deserialize_with = "deserialize_hmr")] - pub hmr: Option, - #[serde(deserialize_with = "deserialize_dev_server")] - pub dev_server: Option, - #[serde(deserialize_with = "deserialize_code_splitting", default)] - pub code_splitting: Option, - #[serde(deserialize_with = "deserialize_px2rem", default)] - pub px2rem: Option, - #[serde(deserialize_with = "deserialize_progress", default)] - pub progress: Option, - pub hash: bool, - #[serde(rename = "_treeShaking", deserialize_with = "deserialize_tree_shaking")] - pub _tree_shaking: Option, - #[serde(rename = "autoCSSModules")] - pub auto_css_modules: bool, - #[serde(rename = "ignoreCSSParserErrors")] - pub ignore_css_parser_errors: bool, - pub dynamic_import_to_require: bool, - #[serde(deserialize_with = "deserialize_umd", default)] - pub umd: Option, - pub cjs: bool, - pub write_to_disk: bool, - pub transform_import: Vec, - pub chunk_parallel: bool, - pub clean: bool, - pub node_polyfill: bool, - pub ignores: Vec, - #[serde( - rename = "_minifish", - deserialize_with = "deserialize_minifish", - default - )] - pub _minifish: Option, - #[serde(rename = "optimizePackageImports")] - pub optimize_package_imports: bool, - pub emotion: bool, - pub flex_bugs: bool, - #[serde(deserialize_with = "deserialize_optimization")] - pub optimization: Option, - pub react: ReactConfig, - pub emit_assets: bool, - #[serde(rename = "cssModulesExportOnlyLocales")] - pub css_modules_export_only_locales: bool, - #[serde( - rename = "inlineCSS", - deserialize_with = "deserialize_inline_css", - default - )] - pub inline_css: Option, - #[serde( - rename = "rscServer", - deserialize_with = "deserialize_rsc_server", - default - )] - pub rsc_server: Option, - #[serde( - rename = "rscClient", - deserialize_with = "deserialize_rsc_client", - default - )] - pub rsc_client: Option, - pub experimental: ExperimentalConfig, - pub watch: WatchConfig, - pub use_define_for_class_fields: bool, - pub emit_decorator_metadata: bool, - #[serde( - rename = "duplicatePackageChecker", - deserialize_with = "deserialize_check_duplicate_package", - default - )] - pub check_duplicate_package: Option, -} - -#[derive(Deserialize, Serialize, Clone, Debug, Default)] -pub enum OptimizeAllowChunks { - #[serde(rename = "all")] - All, - #[serde(rename = "entry")] - Entry, - #[serde(rename = "async")] - #[default] - Async, -} - -#[derive(Deserialize, Serialize, Clone, Debug)] -#[serde(rename_all = "camelCase")] -pub struct CodeSplittingAdvancedOptions { - #[serde(default = "GenericUsizeDefault::<20000>::value")] - pub min_size: usize, - pub groups: Vec, -} - -impl Default for CodeSplittingAdvancedOptions { - fn default() -> Self { - CodeSplittingAdvancedOptions { - min_size: GenericUsizeDefault::<20000>::value(), - groups: vec![], - } - } -} - -#[derive(Deserialize, Serialize, Clone, Debug)] -pub enum OptimizeChunkNameSuffixStrategy { - #[serde(rename = "packageName")] - PackageName, - #[serde(rename = "dependentsHash")] - DependentsHash, -} - -#[derive(Deserialize, Serialize, Clone, Debug)] -#[serde(rename_all = "camelCase")] -pub struct OptimizeChunkGroup { - pub name: String, - #[serde(default)] - pub name_suffix: Option, - #[serde(default)] - pub allow_chunks: OptimizeAllowChunks, - #[serde(default = "GenericUsizeDefault::<1>::value")] - pub min_chunks: usize, - #[serde(default = "GenericUsizeDefault::<20000>::value")] - pub min_size: usize, - #[serde(default = "GenericUsizeDefault::<5000000>::value")] - pub max_size: usize, - #[serde(default)] - pub min_module_size: Option, - #[serde(default)] - pub priority: i8, - #[serde(default, with = "optimize_test_format")] - pub test: Option, -} - -impl Default for OptimizeChunkGroup { - fn default() -> Self { - Self { - allow_chunks: OptimizeAllowChunks::default(), - min_chunks: GenericUsizeDefault::<1>::value(), - min_size: GenericUsizeDefault::<20000>::value(), - max_size: GenericUsizeDefault::<5000000>::value(), - name: String::default(), - name_suffix: None, - min_module_size: None, - test: None, - priority: i8::default(), - } - } -} - -/** - * custom formatter for convert string to regex - * @see https://serde.rs/custom-date-format.html - */ -mod optimize_test_format { - use regex::Regex; - use serde::{self, Deserialize, Deserializer, Serializer}; - - pub fn serialize(v: &Option, serializer: S) -> Result - where - S: Serializer, - { - if let Some(v) = v { - serializer.serialize_str(&v.to_string()) - } else { - serializer.serialize_none() - } - } - - pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> - where - D: Deserializer<'de>, - { - let v = String::deserialize(deserializer)?; - - if v.is_empty() { - Ok(None) - } else { - Ok(Regex::new(v.as_str()).ok()) - } - } -} - -const CONFIG_FILE: &str = "mako.config.json"; -const DEFAULT_CONFIG: &str = r#" -{ - "entry": {}, - "output": { - "path": "dist", - "mode": "bundle", - "esVersion": "es2022", - "meta": false, - "chunkLoadingGlobal": "", - "preserveModules": false, - "preserveModulesRoot": "", - "skipWrite": false, - "crossOriginLoading": false, - "globalModuleRegistry": false, - }, - "resolve": { "alias": [], "extensions": ["js", "jsx", "ts", "tsx"] }, - "mode": "development", - "minify": true, - "devtool": "source-map", - "externals": {}, - "copy": ["public"], - "providers": {}, - "publicPath": "/", - "inlineLimit": 10000, - "inlineExcludesExtensions": [], - "targets": { "chrome": 80 }, - "less": { "theme": {}, "lesscPath": "", javascriptEnabled: true }, - "define": {}, - "mdx": false, - "platform": "browser", - "hmr": {}, - "moduleIdStrategy": "named", - "hash": false, - "_treeShaking": "basic", - "autoCSSModules": false, - "ignoreCSSParserErrors": false, - "dynamicImportToRequire": false, - "writeToDisk": true, - "transformImport": [], - "chunkParallel": true, - "clean": true, - "nodePolyfill": true, - "ignores": [], - "optimizePackageImports": false, - "emotion": false, - "flexBugs": false, - "cjs": false, - "optimization": { "skipModules": true, "concatenateModules": true }, - "react": { - "pragma": "React.createElement", - "importSource": "react", - "runtime": "automatic", - "pragmaFrag": "React.Fragment" - }, - "progress": { - "progressChars": "▨▨" - }, - "duplicatePackageChecker": { - "verbose": false, - "showHelp": false, - "emitError": false, - }, - "emitAssets": true, - "cssModulesExportOnlyLocales": false, - "inlineCSS": false, - "rscServer": false, - "rscClient": false, - "experimental": { - "webpackSyntaxValidate": [], - "requireContext": true, - "detectCircularDependence": { "ignores": ["node_modules"], "graphviz": false } - }, - "useDefineForClassFields": true, - "emitDecoratorMetadata": false, - "watch": { "ignorePaths": [], "_nodeModulesRegexes": [] }, - "devServer": { "host": "127.0.0.1", "port": 3000 } -} -"#; - -impl Config { - pub fn new( - root: &Path, - default_config: Option<&str>, - cli_config: Option<&str>, - ) -> Result { - let abs_config_file = root.join(CONFIG_FILE); - let abs_config_file = abs_config_file.to_str().unwrap(); - let c = config::Config::builder(); - // default config - let c = c.add_source(config::File::from_str( - DEFAULT_CONFIG, - config::FileFormat::Json5, - )); - // default config from args - let c = if let Some(default_config) = default_config { - c.add_source(config::File::from_str( - default_config, - config::FileFormat::Json5, - )) - } else { - c - }; - // validate user config - validate_mako_config(abs_config_file.to_string()) - .map_err(|e| anyhow!("{}", format!("{:?}", e)))?; - // user config - let c = c.add_source(config::File::with_name(abs_config_file).required(false)); - // cli config - let c = if let Some(cli_config) = cli_config { - c.add_source(config::File::from_str( - cli_config, - config::FileFormat::Json5, - )) - } else { - c - }; - - let c = c.build()?; - let mut ret = c.try_deserialize::(); - // normalize & check - if let Ok(config) = &mut ret { - // normalize output - if config.output.path.is_relative() { - config.output.path = root.join(config.output.path.to_string_lossy().to_string()); - } - - if config.output.chunk_loading_global.is_empty() { - config.output.chunk_loading_global = - get_default_chunk_loading_global(config.umd.clone(), root); - } - - let node_env_config_opt = config.define.get("NODE_ENV"); - if let Some(node_env_config) = node_env_config_opt { - if node_env_config.as_str() != Some(config.mode.to_string().as_str()) { - let warn_message = format!( - "{}: The configuration of {} conflicts with current {} and will be overwritten as {} ", - "warning".to_string().yellow(), - "NODE_ENV".to_string().yellow(), - "mode".to_string().yellow(), - config.mode.to_string().red() - ); - println!("{}", warn_message); - } - } - - if config.cjs && config.umd.is_some() { - return Err(anyhow!("cjs and umd cannot be used at the same time",)); - } - - if config.hmr.is_some() && config.dev_server.is_none() { - return Err(anyhow!("hmr can only be used with devServer",)); - } - - if config.inline_css.is_some() && config.umd.is_none() { - return Err(anyhow!("inlineCSS can only be used with umd",)); - } - - let mode = format!("\"{}\"", config.mode); - config - .define - .insert("NODE_ENV".to_string(), serde_json::Value::String(mode)); - - if config.public_path != "runtime" && !config.public_path.ends_with('/') { - return Err(anyhow!("public_path must end with '/' or be 'runtime'")); - } - - // 暂不支持 remote external - // 如果 config.externals 中有值是以「script 」开头,则 panic 报错 - let basic_external_values = config - .externals - .values() - .filter_map(|v| match v { - ExternalConfig::Basic(b) => Some(b), - _ => None, - }) - .collect::>(); - for v in basic_external_values { - if v.starts_with("script ") { - return Err(anyhow!( - "remote external is not supported yet, but we found {}", - v.to_string().red() - )); - } - } - - // support default entries - if config.entry.is_empty() { - let file_paths = vec!["src/index.tsx", "src/index.ts", "index.tsx", "index.ts"]; - for file_path in file_paths { - let file_path = root.join(file_path); - if file_path.exists() { - config.entry.insert("index".to_string(), file_path); - break; - } - } - if config.entry.is_empty() { - return Err(anyhow!("Entry is empty")); - } - } - - // normalize entry - let entry_tuples = config - .entry - .clone() - .into_iter() - .map(|(k, v)| { - if let Ok(entry_path) = root.join(v).canonicalize() { - Ok((k, entry_path)) - } else { - Err(anyhow!("entry:{} not found", k,)) - } - }) - .collect::>>()?; - config.entry = entry_tuples.into_iter().collect(); - - // support relative alias - config.resolve.alias = config - .resolve - .alias - .clone() - .into_iter() - .map(|(k, v)| { - let v = if v.starts_with('.') { - root.join(v).to_string_lossy().to_string() - } else { - v - }; - (k, v) - }) - .collect(); - - // dev 环境下不产生 hash, prod 环境下根据用户配置 - if config.mode == Mode::Development { - config.hash = false; - } - - // configure node platform - Node::modify_config(config); - } - ret.map_err(|e| anyhow!("{}: {}", "config error".red(), e.to_string().red())) - } -} - -impl Default for Config { - fn default() -> Self { - let c = config::Config::builder(); - let c = c.add_source(config::File::from_str( - DEFAULT_CONFIG, - config::FileFormat::Json5, - )); - let c = c.build().unwrap(); - c.try_deserialize::().unwrap() - } -} - -pub(crate) fn get_pkg_name(root: &Path) -> Option { - let pkg_json_path = root.join("package.json"); - - if pkg_json_path.exists() { - let pkg_json = std::fs::read_to_string(pkg_json_path).unwrap(); - let pkg_json: serde_json::Value = serde_json::from_str(&pkg_json).unwrap(); - - pkg_json - .get("name") - .map(|name| name.as_str().unwrap().to_string()) - } else { - None - } -} - -fn get_default_chunk_loading_global(umd: Option, root: &Path) -> String { - let unique_name = umd.unwrap_or_else(|| get_pkg_name(root).unwrap_or("global".to_string())); - - format!("makoChunk_{}", unique_name) -} - -#[derive(Error, Debug)] -pub enum ConfigError { - #[error("define value '{0}' is not an Expression")] - InvalidateDefineConfig(String), -} - -pub struct GenericUsizeDefault; - -impl GenericUsizeDefault { - pub fn value() -> usize { - U - } -} - -#[cfg(test)] -mod tests { - use crate::config::config::GenericUsizeDefault; - use crate::config::{Config, Mode, Platform}; - - #[test] - fn test_config() { - let current_dir = std::env::current_dir().unwrap(); - let config = Config::new(¤t_dir.join("test/config/normal"), None, None).unwrap(); - println!("{:?}", config); - assert_eq!(config.platform, Platform::Node); - } - - #[test] - fn test_config_args_default() { - let current_dir = std::env::current_dir().unwrap(); - let config = Config::new( - ¤t_dir.join("test/config/normal"), - Some(r#"{"mode":"production"}"#), - None, - ) - .unwrap(); - println!("{:?}", config); - assert_eq!(config.mode, Mode::Production); - } - - #[test] - fn test_config_cli_args() { - let current_dir = std::env::current_dir().unwrap(); - let config = Config::new( - ¤t_dir.join("test/config/normal"), - None, - Some(r#"{"platform":"browser"}"#), - ) - .unwrap(); - println!("{:?}", config); - assert_eq!(config.platform, Platform::Browser); - } - - #[test] - fn test_node_env_conflicts_with_mode() { - let current_dir = std::env::current_dir().unwrap(); - let config = Config::new( - ¤t_dir.join("test/config/node-env"), - None, - Some(r#"{"mode":"development"}"#), - ) - .unwrap(); - assert_eq!( - config.define.get("NODE_ENV"), - Some(&serde_json::Value::String("\"development\"".to_string())) - ); - } - - #[test] - #[should_panic(expected = "public_path must end with '/' or be 'runtime'")] - fn test_config_invalid_public_path() { - let current_dir = std::env::current_dir().unwrap(); - Config::new( - ¤t_dir.join("test/config/normal"), - None, - Some(r#"{"publicPath":"abc"}"#), - ) - .unwrap(); - } - - #[test] - fn test_node_platform() { - let current_dir = std::env::current_dir().unwrap(); - let config = - Config::new(¤t_dir.join("test/config/node-platform"), None, None).unwrap(); - assert_eq!( - config.targets.get("node"), - Some(&14.0), - "use node targets by default if platform is node", - ); - assert!( - config.ignores.iter().any(|i| i.contains("|fs|")), - "ignore Node.js standard library by default if platform is node", - ); - } - - #[test] - fn test_generic_usize_default() { - assert!(GenericUsizeDefault::<100>::value() == 100usize) - } -} diff --git a/crates/mako/src/config/dev_server.rs b/crates/mako/src/config/dev_server.rs new file mode 100644 index 000000000..928fb7b8b --- /dev/null +++ b/crates/mako/src/config/dev_server.rs @@ -0,0 +1,12 @@ +use serde::{Deserialize, Serialize}; + +use crate::create_deserialize_fn; + +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct DevServerConfig { + pub host: String, + pub port: u16, +} + +create_deserialize_fn!(deserialize_dev_server, DevServerConfig); diff --git a/crates/mako/src/config/devtool.rs b/crates/mako/src/config/devtool.rs new file mode 100644 index 000000000..367d4b307 --- /dev/null +++ b/crates/mako/src/config/devtool.rs @@ -0,0 +1,15 @@ +use serde::{Deserialize, Serialize}; + +use crate::create_deserialize_fn; + +#[derive(Deserialize, Serialize, Debug)] +pub enum DevtoolConfig { + /// Generate separate sourcemap file + #[serde(rename = "source-map")] + SourceMap, + /// Generate inline sourcemap + #[serde(rename = "inline-source-map")] + InlineSourceMap, +} + +create_deserialize_fn!(deserialize_devtool, DevtoolConfig); diff --git a/crates/mako/src/config/duplicate_package_checker.rs b/crates/mako/src/config/duplicate_package_checker.rs new file mode 100644 index 000000000..14eedc9b3 --- /dev/null +++ b/crates/mako/src/config/duplicate_package_checker.rs @@ -0,0 +1,18 @@ +use serde::{Deserialize, Serialize}; + +use crate::create_deserialize_fn; + +#[derive(Deserialize, Serialize, Clone, Debug)] +pub struct DuplicatePackageCheckerConfig { + #[serde(rename = "verbose", default)] + pub verbose: bool, + #[serde(rename = "emitError", default)] + pub emit_error: bool, + #[serde(rename = "showHelp", default)] + pub show_help: bool, +} + +create_deserialize_fn!( + deserialize_check_duplicate_package, + DuplicatePackageCheckerConfig +); diff --git a/crates/mako/src/config/experimental.rs b/crates/mako/src/config/experimental.rs new file mode 100644 index 000000000..a3bee9264 --- /dev/null +++ b/crates/mako/src/config/experimental.rs @@ -0,0 +1,21 @@ +use serde::{Deserialize, Serialize}; + +use crate::create_deserialize_fn; + +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct ExperimentalConfig { + pub webpack_syntax_validate: Vec, + pub require_context: bool, + #[serde(deserialize_with = "deserialize_detect_loop")] + pub detect_circular_dependence: Option, +} + +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct DetectCircularDependence { + pub ignores: Vec, + pub graphviz: bool, +} + +create_deserialize_fn!(deserialize_detect_loop, DetectCircularDependence); diff --git a/crates/mako/src/config/external.rs b/crates/mako/src/config/external.rs new file mode 100644 index 000000000..922be0616 --- /dev/null +++ b/crates/mako/src/config/external.rs @@ -0,0 +1,77 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Deserialize, Serialize, Debug, Hash)] +#[serde(untagged)] +pub enum ExternalConfig { + Basic(String), + Advanced(ExternalAdvanced), +} + +#[derive(Deserialize, Serialize, Debug, Hash)] +pub struct ExternalAdvancedSubpath { + pub exclude: Option>, + pub rules: Vec, +} + +#[derive(Deserialize, Serialize, Debug, Hash)] +pub struct ExternalAdvanced { + pub root: String, + #[serde(rename = "type")] + pub module_type: Option, + pub script: Option, + pub subpath: Option, +} + +#[derive(Deserialize, Serialize, Debug, Hash)] +pub struct ExternalAdvancedSubpathRule { + pub regex: String, + #[serde(with = "external_target_format")] + pub target: ExternalAdvancedSubpathTarget, + #[serde(rename = "targetConverter")] + pub target_converter: Option, +} + +#[derive(Deserialize, Serialize, Debug, Hash)] +pub enum ExternalAdvancedSubpathConverter { + PascalCase, +} + +#[derive(Deserialize, Serialize, Debug, Hash)] +#[serde(untagged)] +pub enum ExternalAdvancedSubpathTarget { + Empty, + Tpl(String), +} + +/** + * custom formatter for convert $EMPTY to enum, because rename is not supported for $ symbol + * @see https://serde.rs/custom-date-format.html + */ +mod external_target_format { + use serde::{self, Deserialize, Deserializer, Serializer}; + + use super::ExternalAdvancedSubpathTarget; + + pub fn serialize(v: &ExternalAdvancedSubpathTarget, serializer: S) -> Result + where + S: Serializer, + { + match v { + ExternalAdvancedSubpathTarget::Empty => serializer.serialize_str("$EMPTY"), + ExternalAdvancedSubpathTarget::Tpl(s) => serializer.serialize_str(s), + } + } + + pub fn deserialize<'de, D>(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let v = String::deserialize(deserializer)?; + + if v == "$EMPTY" { + Ok(ExternalAdvancedSubpathTarget::Empty) + } else { + Ok(ExternalAdvancedSubpathTarget::Tpl(v)) + } + } +} diff --git a/crates/mako/src/config/generic_usize.rs b/crates/mako/src/config/generic_usize.rs new file mode 100644 index 000000000..8aa1074d7 --- /dev/null +++ b/crates/mako/src/config/generic_usize.rs @@ -0,0 +1,17 @@ +pub struct GenericUsizeDefault; + +impl GenericUsizeDefault { + pub fn value() -> usize { + U + } +} + +#[cfg(test)] +mod tests { + use crate::config::GenericUsizeDefault; + + #[test] + fn test_generic_usize_default() { + assert!(GenericUsizeDefault::<100>::value() == 100usize) + } +} diff --git a/crates/mako/src/config/hmr.rs b/crates/mako/src/config/hmr.rs new file mode 100644 index 000000000..005be10ee --- /dev/null +++ b/crates/mako/src/config/hmr.rs @@ -0,0 +1,9 @@ +use serde::{Deserialize, Serialize}; + +use crate::create_deserialize_fn; + +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct HmrConfig {} + +create_deserialize_fn!(deserialize_hmr, HmrConfig); diff --git a/crates/mako/src/config/inline_css.rs b/crates/mako/src/config/inline_css.rs new file mode 100644 index 000000000..af3c4ec94 --- /dev/null +++ b/crates/mako/src/config/inline_css.rs @@ -0,0 +1,8 @@ +use serde::{Deserialize, Serialize}; + +use crate::create_deserialize_fn; + +#[derive(Deserialize, Serialize, Debug)] +pub struct InlineCssConfig {} + +create_deserialize_fn!(deserialize_inline_css, InlineCssConfig); diff --git a/crates/mako/src/config/macros.rs b/crates/mako/src/config/macros.rs new file mode 100644 index 000000000..4acdd112a --- /dev/null +++ b/crates/mako/src/config/macros.rs @@ -0,0 +1,33 @@ +/** + * a macro to create deserialize function that allow false value for optional struct + */ +#[macro_export] +macro_rules! create_deserialize_fn { + ($fn_name:ident, $struct_type:ty) => { + pub fn $fn_name<'de, D>(deserializer: D) -> Result, D::Error> + where + D: serde::Deserializer<'de>, + { + let value: serde_json::Value = serde_json::Value::deserialize(deserializer)?; + + match value { + // allow false value for optional struct + serde_json::Value::Bool(false) => Ok(None), + // try deserialize + serde_json::Value::Object(obj) => Ok(Some( + serde_json::from_value::<$struct_type>(serde_json::Value::Object(obj)) + .map_err(serde::de::Error::custom)?, + )), + serde_json::Value::String(s) => Ok(Some( + serde_json::from_value::<$struct_type>(serde_json::Value::String(s.clone())) + .map_err(serde::de::Error::custom)?, + )), + _ => Err(serde::de::Error::custom(format!( + "invalid `{}` value: {}", + stringify!($fn_name).replace("deserialize_", ""), + value + ))), + } + } + }; +} diff --git a/crates/mako/src/config/mako.config.default.json b/crates/mako/src/config/mako.config.default.json new file mode 100644 index 000000000..bfbce56dd --- /dev/null +++ b/crates/mako/src/config/mako.config.default.json @@ -0,0 +1,79 @@ +{ + "entry": {}, + "output": { + "path": "dist", + "mode": "bundle", + "esVersion": "es2022", + "meta": false, + "chunkLoadingGlobal": "", + "preserveModules": false, + "preserveModulesRoot": "", + "skipWrite": false, + "crossOriginLoading": false, + "globalModuleRegistry": false + }, + "resolve": { "alias": [], "extensions": ["js", "jsx", "ts", "tsx"] }, + "mode": "development", + "minify": true, + "devtool": "source-map", + "externals": {}, + "copy": ["public"], + "providers": {}, + "publicPath": "/", + "inlineLimit": 10000, + "inlineExcludesExtensions": [], + "targets": { "chrome": 80 }, + "less": { "theme": {}, "lesscPath": "", "javascriptEnabled": true }, + "define": {}, + "mdx": false, + "platform": "browser", + "hmr": {}, + "moduleIdStrategy": "named", + "hash": false, + "_treeShaking": "basic", + "autoCSSModules": false, + "ignoreCSSParserErrors": false, + "dynamicImportToRequire": false, + "writeToDisk": true, + "transformImport": [], + "chunkParallel": true, + "clean": true, + "nodePolyfill": true, + "ignores": [], + "optimizePackageImports": false, + "emotion": false, + "flexBugs": false, + "cjs": false, + "optimization": { "skipModules": true, "concatenateModules": true }, + "react": { + "pragma": "React.createElement", + "importSource": "react", + "runtime": "automatic", + "pragmaFrag": "React.Fragment" + }, + "progress": { + "progressChars": "▨▨" + }, + "duplicatePackageChecker": { + "verbose": false, + "showHelp": false, + "emitError": false + }, + "emitAssets": true, + "cssModulesExportOnlyLocales": false, + "inlineCSS": false, + "rscServer": false, + "rscClient": false, + "experimental": { + "webpackSyntaxValidate": [], + "requireContext": true, + "detectCircularDependence": { + "ignores": ["node_modules"], + "graphviz": false + } + }, + "useDefineForClassFields": true, + "emitDecoratorMetadata": false, + "watch": { "ignorePaths": [], "_nodeModulesRegexes": [] }, + "devServer": { "host": "127.0.0.1", "port": 3000 } +} diff --git a/crates/mako/src/config/manifest.rs b/crates/mako/src/config/manifest.rs new file mode 100644 index 000000000..5581b8ee7 --- /dev/null +++ b/crates/mako/src/config/manifest.rs @@ -0,0 +1,16 @@ +use serde::{Deserialize, Serialize}; + +use crate::{create_deserialize_fn, plugins}; + +#[derive(Deserialize, Serialize, Debug)] +pub struct ManifestConfig { + #[serde( + rename(deserialize = "fileName"), + default = "plugins::manifest::default_manifest_file_name" + )] + pub file_name: String, + #[serde(rename(deserialize = "basePath"), default)] + pub base_path: String, +} + +create_deserialize_fn!(deserialize_manifest, ManifestConfig); diff --git a/crates/mako/src/config/minifish.rs b/crates/mako/src/config/minifish.rs new file mode 100644 index 000000000..7e25adbe1 --- /dev/null +++ b/crates/mako/src/config/minifish.rs @@ -0,0 +1,27 @@ +use std::collections::HashMap; +use std::path::PathBuf; + +use serde::{Deserialize, Serialize}; + +use crate::create_deserialize_fn; + +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct MinifishConfig { + pub mapping: HashMap, + pub meta_path: Option, + pub inject: Option>, +} + +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct InjectItem { + pub from: String, + pub named: Option, + pub namespace: Option, + pub exclude: Option, + pub include: Option, + pub prefer_require: Option, +} + +create_deserialize_fn!(deserialize_minifish, MinifishConfig); diff --git a/crates/mako/src/config/mode.rs b/crates/mako/src/config/mode.rs new file mode 100644 index 000000000..bf18c8d3c --- /dev/null +++ b/crates/mako/src/config/mode.rs @@ -0,0 +1,16 @@ +use clap::ValueEnum; +use serde::{Deserialize, Serialize}; + +#[derive(Deserialize, Serialize, Debug, PartialEq, Eq, ValueEnum, Clone)] +pub enum Mode { + #[serde(rename = "development")] + Development, + #[serde(rename = "production")] + Production, +} + +impl std::fmt::Display for Mode { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.to_possible_value().unwrap().get_name().fmt(f) + } +} diff --git a/crates/mako/src/config/module_id_strategy.rs b/crates/mako/src/config/module_id_strategy.rs new file mode 100644 index 000000000..801c8afb8 --- /dev/null +++ b/crates/mako/src/config/module_id_strategy.rs @@ -0,0 +1,11 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Deserialize, Serialize, Clone, Copy, Debug)] +pub enum ModuleIdStrategy { + #[serde(rename = "hashed")] + Hashed, + #[serde(rename = "named")] + Named, + #[serde(rename = "numeric")] + Numeric, +} diff --git a/crates/mako/src/config/optimization.rs b/crates/mako/src/config/optimization.rs new file mode 100644 index 000000000..8e57ca69e --- /dev/null +++ b/crates/mako/src/config/optimization.rs @@ -0,0 +1,12 @@ +use serde::{Deserialize, Serialize}; + +use crate::create_deserialize_fn; + +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct OptimizationConfig { + pub skip_modules: Option, + pub concatenate_modules: Option, +} + +create_deserialize_fn!(deserialize_optimization, OptimizationConfig); diff --git a/crates/mako/src/config/output.rs b/crates/mako/src/config/output.rs new file mode 100644 index 000000000..da3edb041 --- /dev/null +++ b/crates/mako/src/config/output.rs @@ -0,0 +1,58 @@ +use core::fmt; +use std::path::{Path, PathBuf}; + +use clap::ValueEnum; +use serde::{Deserialize, Serialize}; +use swc_core::ecma::ast::EsVersion; + +use crate::create_deserialize_fn; +use crate::utils::get_pkg_name; + +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct OutputConfig { + pub path: PathBuf, + pub mode: OutputMode, + pub es_version: EsVersion, + pub meta: bool, + pub chunk_loading_global: String, + pub preserve_modules: bool, + pub preserve_modules_root: PathBuf, + pub skip_write: bool, + #[serde(deserialize_with = "deserialize_cross_origin_loading")] + pub cross_origin_loading: Option, + pub global_module_registry: bool, +} + +#[derive(Deserialize, Serialize, Debug, PartialEq, Eq, ValueEnum, Clone)] +pub enum OutputMode { + #[serde(rename = "bundle")] + Bundle, + #[serde(rename = "bundless")] + Bundless, +} + +#[derive(Deserialize, Serialize, Debug, Clone)] +pub enum CrossOriginLoading { + #[serde(rename = "anonymous")] + Anonymous, + #[serde(rename = "use-credentials")] + UseCredentials, +} + +impl fmt::Display for CrossOriginLoading { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + CrossOriginLoading::Anonymous => write!(f, "anonymous"), + CrossOriginLoading::UseCredentials => write!(f, "use-credentials"), + } + } +} + +pub fn get_default_chunk_loading_global(umd: Option, root: &Path) -> String { + let unique_name = umd.unwrap_or_else(|| get_pkg_name(root).unwrap_or("global".to_string())); + + format!("makoChunk_{}", unique_name) +} + +create_deserialize_fn!(deserialize_cross_origin_loading, CrossOriginLoading); diff --git a/crates/mako/src/config/progress.rs b/crates/mako/src/config/progress.rs new file mode 100644 index 000000000..37588b740 --- /dev/null +++ b/crates/mako/src/config/progress.rs @@ -0,0 +1,11 @@ +use serde::{Deserialize, Serialize}; + +use crate::create_deserialize_fn; + +#[derive(Deserialize, Serialize, Clone, Debug)] +pub struct ProgressConfig { + #[serde(rename = "progressChars", default)] + pub progress_chars: String, +} + +create_deserialize_fn!(deserialize_progress, ProgressConfig); diff --git a/crates/mako/src/config/provider.rs b/crates/mako/src/config/provider.rs new file mode 100644 index 000000000..21f35463f --- /dev/null +++ b/crates/mako/src/config/provider.rs @@ -0,0 +1,7 @@ +use std::collections::HashMap; + +// format: HashMap +// e.g. +// { "process": ("process", "") } +// { "Buffer": ("buffer", "Buffer") } +pub type Providers = HashMap; diff --git a/crates/mako/src/config/px2rem.rs b/crates/mako/src/config/px2rem.rs new file mode 100644 index 000000000..3e3437710 --- /dev/null +++ b/crates/mako/src/config/px2rem.rs @@ -0,0 +1,40 @@ +use serde::{Deserialize, Serialize}; + +use crate::{create_deserialize_fn, visitors}; + +#[derive(Deserialize, Serialize, Clone, Debug)] +pub struct Px2RemConfig { + #[serde(default = "visitors::css_px2rem::default_root")] + pub root: f64, + #[serde(rename = "propBlackList", default)] + pub prop_blacklist: Vec, + #[serde(rename = "propWhiteList", default)] + pub prop_whitelist: Vec, + #[serde(rename = "selectorBlackList", default)] + pub selector_blacklist: Vec, + #[serde(rename = "selectorWhiteList", default)] + pub selector_whitelist: Vec, + #[serde(rename = "selectorDoubleList", default)] + pub selector_doublelist: Vec, + #[serde(rename = "minPixelValue", default)] + pub min_pixel_value: f64, + #[serde(rename = "mediaQuery", default)] + pub media_query: bool, +} + +impl Default for Px2RemConfig { + fn default() -> Self { + Px2RemConfig { + root: visitors::css_px2rem::default_root(), + prop_blacklist: vec![], + prop_whitelist: vec![], + selector_blacklist: vec![], + selector_whitelist: vec![], + selector_doublelist: vec![], + min_pixel_value: 0.0, + media_query: false, + } + } +} + +create_deserialize_fn!(deserialize_px2rem, Px2RemConfig); diff --git a/crates/mako/src/config/react.rs b/crates/mako/src/config/react.rs new file mode 100644 index 000000000..38cfa12c7 --- /dev/null +++ b/crates/mako/src/config/react.rs @@ -0,0 +1,19 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Deserialize, Serialize, Debug)] +pub struct ReactConfig { + pub pragma: String, + #[serde(rename = "importSource")] + pub import_source: String, + pub runtime: ReactRuntimeConfig, + #[serde(rename = "pragmaFrag")] + pub pragma_frag: String, +} + +#[derive(Deserialize, Serialize, Debug, Clone)] +pub enum ReactRuntimeConfig { + #[serde(rename = "automatic")] + Automatic, + #[serde(rename = "classic")] + Classic, +} diff --git a/crates/mako/src/config/resolve.rs b/crates/mako/src/config/resolve.rs new file mode 100644 index 000000000..dbe1b5029 --- /dev/null +++ b/crates/mako/src/config/resolve.rs @@ -0,0 +1,7 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Deserialize, Serialize, Debug)] +pub struct ResolveConfig { + pub alias: Vec<(String, String)>, + pub extensions: Vec, +} diff --git a/crates/mako/src/config/rsc_client.rs b/crates/mako/src/config/rsc_client.rs new file mode 100644 index 000000000..e3517c446 --- /dev/null +++ b/crates/mako/src/config/rsc_client.rs @@ -0,0 +1,20 @@ +use clap::ValueEnum; +use serde::{Deserialize, Serialize}; + +use crate::create_deserialize_fn; + +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct RscClientConfig { + pub log_server_component: LogServerComponent, +} + +#[derive(Deserialize, Serialize, Debug, PartialEq, Eq, ValueEnum, Clone)] +pub enum LogServerComponent { + #[serde(rename = "error")] + Error, + #[serde(rename = "ignore")] + Ignore, +} + +create_deserialize_fn!(deserialize_rsc_client, RscClientConfig); diff --git a/crates/mako/src/config/rsc_server.rs b/crates/mako/src/config/rsc_server.rs new file mode 100644 index 000000000..980216bde --- /dev/null +++ b/crates/mako/src/config/rsc_server.rs @@ -0,0 +1,13 @@ +use serde::{Deserialize, Serialize}; + +use crate::create_deserialize_fn; + +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct RscServerConfig { + pub client_component_tpl: String, + #[serde(rename = "emitCSS")] + pub emit_css: bool, +} + +create_deserialize_fn!(deserialize_rsc_server, RscServerConfig); diff --git a/crates/mako/src/config/stats.rs b/crates/mako/src/config/stats.rs new file mode 100644 index 000000000..9a3dcc04e --- /dev/null +++ b/crates/mako/src/config/stats.rs @@ -0,0 +1,10 @@ +use serde::{Deserialize, Serialize}; + +use crate::create_deserialize_fn; + +#[derive(Deserialize, Serialize, Clone, Debug)] +pub struct StatsConfig { + pub modules: bool, +} + +create_deserialize_fn!(deserialize_stats, StatsConfig); diff --git a/crates/mako/src/config/transform_import.rs b/crates/mako/src/config/transform_import.rs new file mode 100644 index 000000000..91384f621 --- /dev/null +++ b/crates/mako/src/config/transform_import.rs @@ -0,0 +1,16 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Deserialize, Serialize, Clone, Debug)] +#[serde(untagged)] +pub enum TransformImportStyle { + Built(String), + Source(bool), +} + +#[derive(Deserialize, Serialize, Clone, Debug)] +#[serde(rename_all = "camelCase")] +pub struct TransformImportConfig { + pub library_name: String, + pub library_directory: Option, + pub style: Option, +} diff --git a/crates/mako/src/config/tree_shaking.rs b/crates/mako/src/config/tree_shaking.rs new file mode 100644 index 000000000..e716201fa --- /dev/null +++ b/crates/mako/src/config/tree_shaking.rs @@ -0,0 +1,13 @@ +use serde::{Deserialize, Serialize}; + +use crate::create_deserialize_fn; + +#[derive(Deserialize, Serialize, Clone, Copy, Debug)] +pub enum TreeShakingStrategy { + #[serde(rename = "basic")] + Basic, + #[serde(rename = "advanced")] + Advanced, +} + +create_deserialize_fn!(deserialize_tree_shaking, TreeShakingStrategy); diff --git a/crates/mako/src/config/umd.rs b/crates/mako/src/config/umd.rs new file mode 100644 index 000000000..634c2c41a --- /dev/null +++ b/crates/mako/src/config/umd.rs @@ -0,0 +1,7 @@ +use serde::Deserialize; + +use crate::create_deserialize_fn; + +pub type Umd = String; + +create_deserialize_fn!(deserialize_umd, Umd); diff --git a/crates/mako/src/config/watch.rs b/crates/mako/src/config/watch.rs new file mode 100644 index 000000000..3587c5024 --- /dev/null +++ b/crates/mako/src/config/watch.rs @@ -0,0 +1,9 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct WatchConfig { + pub ignore_paths: Option>, + #[serde(rename = "_nodeModulesRegexes")] + pub node_modules_regexes: Option>, +} diff --git a/crates/mako/src/generate/chunk_pot/util.rs b/crates/mako/src/generate/chunk_pot/util.rs index 3fcb320df..094c91d8f 100644 --- a/crates/mako/src/generate/chunk_pot/util.rs +++ b/crates/mako/src/generate/chunk_pot/util.rs @@ -21,10 +21,11 @@ use twox_hash::XxHash64; use crate::ast::sourcemap::build_source_map_to_buf; use crate::compiler::Context; -use crate::config::{get_pkg_name, Mode}; +use crate::config::Mode; use crate::generate::chunk_pot::ChunkPot; use crate::generate::runtime::AppRuntimeTemplate; use crate::module::{relative_to_root, Module, ModuleAst}; +use crate::utils::get_pkg_name; pub(crate) fn render_module_js( ast: &SwcModule, diff --git a/crates/mako/src/utils.rs b/crates/mako/src/utils.rs index fb3778fdf..afde8941a 100644 --- a/crates/mako/src/utils.rs +++ b/crates/mako/src/utils.rs @@ -7,6 +7,8 @@ pub(crate) mod test_helper; pub mod thread_pool; pub mod tokio_runtime; +use std::path::Path; + use anyhow::{anyhow, Result}; use base64::engine::general_purpose; use base64::Engine; @@ -51,6 +53,21 @@ pub fn process_req_url(public_path: &str, req_url: &str) -> Result { Ok(req_url.to_string()) } +pub(crate) fn get_pkg_name(root: &Path) -> Option { + let pkg_json_path = root.join("package.json"); + + if pkg_json_path.exists() { + let pkg_json = std::fs::read_to_string(pkg_json_path).unwrap(); + let pkg_json: serde_json::Value = serde_json::from_str(&pkg_json).unwrap(); + + pkg_json + .get("name") + .map(|name| name.as_str().unwrap().to_string()) + } else { + None + } +} + #[cached(key = "String", convert = r#"{ re.to_string() }"#)] pub fn create_cached_regex(re: &str) -> Regex { Regex::new(re).unwrap() From 06524928ef345a7671cb12dd955f67f634d71594 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?chencheng=20=28=E4=BA=91=E8=B0=A6=29?= Date: Mon, 30 Sep 2024 16:20:37 +0800 Subject: [PATCH 10/21] fix: clickToComponent don't work (#1620) --- crates/mako/src/ast/js_ast.rs | 2 +- examples/dead-simple/app.tsx | 5 +++++ examples/dead-simple/index.ts | 9 ++++++--- 3 files changed, 12 insertions(+), 4 deletions(-) create mode 100644 examples/dead-simple/app.tsx diff --git a/crates/mako/src/ast/js_ast.rs b/crates/mako/src/ast/js_ast.rs index 303fd78aa..d08e37360 100644 --- a/crates/mako/src/ast/js_ast.rs +++ b/crates/mako/src/ast/js_ast.rs @@ -42,7 +42,7 @@ impl fmt::Debug for JsAst { impl JsAst { pub fn new(file: &File, context: Arc) -> Result { let fm = context.meta.script.cm.new_source_file( - FileName::Real(file.relative_path.to_path_buf()), + FileName::Real(file.path.to_path_buf()), file.get_content_raw(), ); let comments = context.meta.script.origin_comments.read().unwrap(); diff --git a/examples/dead-simple/app.tsx b/examples/dead-simple/app.tsx new file mode 100644 index 000000000..1a05af128 --- /dev/null +++ b/examples/dead-simple/app.tsx @@ -0,0 +1,5 @@ +import React from 'react'; + +export default function App() { + return
Hello, world!
; +} diff --git a/examples/dead-simple/index.ts b/examples/dead-simple/index.ts index e53c31d05..400ee215a 100644 --- a/examples/dead-simple/index.ts +++ b/examples/dead-simple/index.ts @@ -1,6 +1,9 @@ -import { foo } from './foo'; -import './foo/foo'; +// import { foo } from './foo'; +// import './foo/foo'; + +import App from './app'; + /** * abcd */ -console.log(foo); +console.log(App); From 34619ef427b9373c8ebb437d813f68f1f6bb4db7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?chencheng=20=28=E4=BA=91=E8=B0=A6=29?= Date: Mon, 30 Sep 2024 16:41:04 +0800 Subject: [PATCH 11/21] fix: duplicate_package_checker panic when no package.json is supplied (#1621) --- .../src/plugins/duplicate_package_checker.rs | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/crates/mako/src/plugins/duplicate_package_checker.rs b/crates/mako/src/plugins/duplicate_package_checker.rs index 2b3ee1b80..4f283a60b 100644 --- a/crates/mako/src/plugins/duplicate_package_checker.rs +++ b/crates/mako/src/plugins/duplicate_package_checker.rs @@ -99,17 +99,19 @@ impl DuplicatePackageCheckerPlugin { .as_ref() .and_then(|info| info.resolved_resource.as_ref()) { - let package_json = resource.0.package_json().unwrap(); - let raw_json = package_json.raw_json(); - if let Some(name) = package_json.name.clone() { - if let Some(version) = raw_json.as_object().unwrap().get("version") { - let package_info = PackageInfo { - name, - version: semver::Version::parse(version.as_str().unwrap()).unwrap(), - path: package_json.path.clone(), - }; - - packages.push(package_info); + if let Some(package_json) = resource.0.package_json() { + let raw_json = package_json.raw_json(); + if let Some(name) = package_json.name.clone() { + if let Some(version) = raw_json.as_object().unwrap().get("version") { + let package_info = PackageInfo { + name, + version: semver::Version::parse(version.as_str().unwrap()) + .unwrap(), + path: package_json.path.clone(), + }; + + packages.push(package_info); + } } } } From e0fbedf4fadbf722918296213367bdc0b70ec0e1 Mon Sep 17 00:00:00 2001 From: Jinbao1001 Date: Tue, 8 Oct 2024 16:33:03 +0800 Subject: [PATCH 12/21] fix: file_stem index out of bound (#1623) --- crates/mako/src/generate/generate_chunks.rs | 44 ++++++++++++--------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/crates/mako/src/generate/generate_chunks.rs b/crates/mako/src/generate/generate_chunks.rs index 68fe12e3e..e14946990 100644 --- a/crates/mako/src/generate/generate_chunks.rs +++ b/crates/mako/src/generate/generate_chunks.rs @@ -40,24 +40,7 @@ pub struct ChunkFile { impl ChunkFile { pub fn disk_name(&self) -> String { - // fixed os error 63 file name too long, reserve 48 bytes for _js-async、extension、.map and others - let reserve_file_name_length = 207; - let file_path = Path::new(&self.file_name); - let mut format_file_name = self.file_name.clone(); - if self.file_name.len() > reserve_file_name_length { - let mut hasher: XxHash64 = Default::default(); - hasher.write_str(self.file_name.as_str()); - let file_extension = file_path.extension().unwrap(); - let file_stem = file_path.file_stem().unwrap().to_string_lossy().to_string(); - let (_, reserve_file_path) = - file_stem.split_at(file_stem.len() - reserve_file_name_length); - format_file_name = format!( - "{}.{}.{}", - reserve_file_path, - &hasher.finish().to_string()[0..8], - file_extension.to_str().unwrap() - ); - } + let format_file_name = hash_too_long_file_name(&self.file_name); if let Some(hash) = &self.hash { hash_file_name(&format_file_name, hash) @@ -191,7 +174,7 @@ impl Compiler { hash_file_name(&js_filename, &placeholder), ); } else { - let js_filename = chunk_pot.js_name; + let js_filename = hash_too_long_file_name(&chunk_pot.js_name); if chunk_pot.stylesheet.is_some() { let css_filename = get_css_chunk_filename(&js_filename); @@ -408,3 +391,26 @@ fn hash_file_name(file_name: &String, hash: &String) -> String { format!("{}.{}.{}", file_stem, hash, file_extension) } + +fn hash_too_long_file_name(file_name: &String) -> String { + // fixed os error 63 file name too long, reserve 48 bytes for _js-async、extension、.map and others + let reserve_file_name_length = 207; + let file_path = Path::new(&file_name); + + let mut format_file_name = file_name.to_string(); + let file_stem = file_path.file_stem().unwrap().to_string_lossy().to_string(); + if file_stem.len() > reserve_file_name_length { + let mut hasher: XxHash64 = Default::default(); + hasher.write_str(file_name.as_str()); + let file_extension = file_path.extension().unwrap(); + let (_, reserve_file_path) = file_stem.split_at(file_stem.len() - reserve_file_name_length); + format_file_name = format!( + "{}.{}.{}", + reserve_file_path, + &hasher.finish().to_string()[0..8], + file_extension.to_str().unwrap() + ); + } + + format_file_name.to_string() +} From 9097f369e8a201dd4970f84bafddedf7226f2330 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?chencheng=20=28=E4=BA=91=E8=B0=A6=29?= Date: Thu, 10 Oct 2024 11:11:13 +0800 Subject: [PATCH 13/21] feat: add resolve_id plugin hook (#1625) * feat: add resolve_id plugin hook * chore: update docs * feat: add external --- crates/binding/src/js_hook.rs | 12 +++++ crates/binding/src/js_plugin.rs | 34 ++++++++++++- crates/mako/src/lib.rs | 2 +- crates/mako/src/plugin.rs | 26 +++++++++- crates/mako/src/resolve.rs | 19 +++++++- crates/mako/src/resolve/resolution.rs | 63 +++++++++++++++++++++++++ crates/mako/src/resolve/resource.rs | 2 +- docs/config.md | 1 + docs/config.zh-CN.md | 1 + e2e/fixtures/plugins/expect.js | 4 ++ e2e/fixtures/plugins/plugins.config.js | 14 +++++- e2e/fixtures/plugins/resolve_id_mock.js | 1 + e2e/fixtures/plugins/src/index.tsx | 2 + packages/mako/binding.d.ts | 5 ++ 14 files changed, 178 insertions(+), 8 deletions(-) create mode 100644 crates/mako/src/resolve/resolution.rs create mode 100644 e2e/fixtures/plugins/resolve_id_mock.js diff --git a/crates/binding/src/js_hook.rs b/crates/binding/src/js_hook.rs index e36f21c82..444b47681 100644 --- a/crates/binding/src/js_hook.rs +++ b/crates/binding/src/js_hook.rs @@ -58,12 +58,15 @@ pub struct JsHooks { pub _on_generate_file: Option, #[napi(ts_type = "() => Promise;")] pub build_start: Option, + #[napi(ts_type = "(source: string, importer: string) => Promise<{ id: string }>;")] + pub resolve_id: Option, } pub struct TsFnHooks { pub build_start: Option>, pub generate_end: Option>, pub load: Option>>, + pub resolve_id: Option>>, pub _on_generate_file: Option>, } @@ -79,6 +82,9 @@ impl TsFnHooks { load: hooks.load.as_ref().map(|hook| unsafe { ThreadsafeFunction::from_napi_value(env.raw(), hook.raw()).unwrap() }), + resolve_id: hooks.resolve_id.as_ref().map(|hook| unsafe { + ThreadsafeFunction::from_napi_value(env.raw(), hook.raw()).unwrap() + }), _on_generate_file: hooks._on_generate_file.as_ref().map(|hook| unsafe { ThreadsafeFunction::from_napi_value(env.raw(), hook.raw()).unwrap() }), @@ -99,3 +105,9 @@ pub struct LoadResult { #[napi(js_name = "type")] pub content_type: String, } + +#[napi(object, use_nullable = true)] +pub struct ResolveIdResult { + pub id: String, + pub external: Option, +} diff --git a/crates/binding/src/js_plugin.rs b/crates/binding/src/js_plugin.rs index 83a7792a0..6d6b47ee5 100644 --- a/crates/binding/src/js_plugin.rs +++ b/crates/binding/src/js_plugin.rs @@ -1,6 +1,7 @@ +use std::path::PathBuf; use std::sync::Arc; -use crate::js_hook::{LoadResult, TsFnHooks, WriteFile}; +use crate::js_hook::{LoadResult, ResolveIdResult, TsFnHooks, WriteFile}; pub struct JsPlugin { pub hooks: TsFnHooks, @@ -9,6 +10,7 @@ use anyhow::{anyhow, Result}; use mako::ast::file::{Content, JsContent}; use mako::compiler::Context; use mako::plugin::{Plugin, PluginGenerateEndParams, PluginLoadParam}; +use mako::resolve::{ExternalResource, Resolution, ResolvedResource, ResolverResource}; impl Plugin for JsPlugin { fn name(&self) -> &str { @@ -47,6 +49,36 @@ impl Plugin for JsPlugin { Ok(None) } + fn resolve_id( + &self, + source: &str, + importer: &str, + _context: &Arc, + ) -> Result> { + if let Some(hook) = &self.hooks.resolve_id { + let x: Option = + hook.call((source.to_string(), importer.to_string()))?; + if let Some(x) = x { + if let Some(true) = x.external { + return Ok(Some(ResolverResource::External(ExternalResource { + source: source.to_string(), + external: source.to_string(), + script: None, + }))); + } + return Ok(Some(ResolverResource::Resolved(ResolvedResource( + Resolution { + path: PathBuf::from(x.id), + query: None, + fragment: None, + package_json: None, + }, + )))); + } + } + Ok(None) + } + fn generate_end(&self, param: &PluginGenerateEndParams, _context: &Arc) -> Result<()> { if let Some(hook) = &self.hooks.generate_end { hook.call(serde_json::to_value(param)?)? diff --git a/crates/mako/src/lib.rs b/crates/mako/src/lib.rs index c4a9d15e5..2d3444c18 100644 --- a/crates/mako/src/lib.rs +++ b/crates/mako/src/lib.rs @@ -15,7 +15,7 @@ mod module; mod module_graph; pub mod plugin; mod plugins; -mod resolve; +pub mod resolve; pub mod share; pub mod stats; pub mod utils; diff --git a/crates/mako/src/plugin.rs b/crates/mako/src/plugin.rs index f33b568fc..1b4d27883 100644 --- a/crates/mako/src/plugin.rs +++ b/crates/mako/src/plugin.rs @@ -53,6 +53,15 @@ pub trait Plugin: Any + Send + Sync { Ok(None) } + fn resolve_id( + &self, + _source: &str, + _importer: &str, + _context: &Arc, + ) -> Result> { + Ok(None) + } + fn next_build(&self, _next_build_param: &NextBuildParam) -> bool { true } @@ -208,7 +217,6 @@ impl PluginDriver { Ok(None) } - #[allow(dead_code)] pub fn transform_js( &self, param: &PluginTransformJsParam, @@ -233,7 +241,6 @@ impl PluginDriver { Ok(()) } - #[allow(dead_code)] pub fn before_resolve( &self, param: &mut Vec, @@ -245,6 +252,21 @@ impl PluginDriver { Ok(()) } + pub fn resolve_id( + &self, + source: &str, + importer: &str, + context: &Arc, + ) -> Result> { + for plugin in &self.plugins { + let ret = plugin.resolve_id(source, importer, context)?; + if ret.is_some() { + return Ok(ret); + } + } + Ok(None) + } + pub fn before_generate(&self, context: &Arc) -> Result<()> { for plugin in &self.plugins { plugin.generate_begin(context)?; diff --git a/crates/mako/src/resolve.rs b/crates/mako/src/resolve.rs index 19a62d2fe..4a74f4462 100644 --- a/crates/mako/src/resolve.rs +++ b/crates/mako/src/resolve.rs @@ -10,8 +10,10 @@ use regex::Captures; use thiserror::Error; use tracing::debug; +mod resolution; mod resource; -pub(crate) use resource::{ExternalResource, ResolvedResource, ResolverResource}; +pub use resolution::Resolution; +pub use resource::{ExternalResource, ResolvedResource, ResolverResource}; use crate::ast::file::parse_path; use crate::compiler::Context; @@ -49,6 +51,14 @@ pub fn resolve( crate::mako_profile_function!(); crate::mako_profile_scope!("resolve", &dep.source); + // plugin first + if let Some(resolved) = context + .plugin_driver + .resolve_id(&dep.source, path, context)? + { + return Ok(resolved); + } + if dep.source.starts_with("virtual:") { return Ok(ResolverResource::Virtual(PathBuf::from(&dep.source))); } @@ -244,7 +254,12 @@ fn do_resolve( // TODO: 临时方案,需要改成删除文件时删 resolve cache 里的内容 // 比如把 util.ts 改名为 util.tsx,目前应该是还有问题的 if resolution.path().exists() { - Ok(ResolverResource::Resolved(ResolvedResource(resolution))) + Ok(ResolverResource::Resolved(ResolvedResource(Resolution { + package_json: resolution.package_json().cloned(), + path: resolution.clone().into_path_buf(), + query: resolution.query().map(|q| q.to_string()), + fragment: resolution.fragment().map(|f| f.to_string()), + }))) } else { Err(anyhow!(ResolveError { path: source.to_string(), diff --git a/crates/mako/src/resolve/resolution.rs b/crates/mako/src/resolve/resolution.rs new file mode 100644 index 000000000..52c93dfd1 --- /dev/null +++ b/crates/mako/src/resolve/resolution.rs @@ -0,0 +1,63 @@ +use std::fmt; +use std::path::{Path, PathBuf}; +use std::sync::Arc; + +use oxc_resolver::PackageJson; + +#[derive(Clone)] +pub struct Resolution { + pub path: PathBuf, + pub query: Option, + pub fragment: Option, + pub package_json: Option>, +} + +impl Resolution { + /// Returns the path without query and fragment + pub fn path(&self) -> &Path { + &self.path + } + + /// Returns the path without query and fragment + pub fn into_path_buf(self) -> PathBuf { + self.path + } + + /// Returns the path query `?query`, contains the leading `?` + pub fn query(&self) -> Option<&str> { + self.query.as_deref() + } + + /// Returns the path fragment `#fragment`, contains the leading `#` + pub fn fragment(&self) -> Option<&str> { + self.fragment.as_deref() + } + + /// Returns serialized package_json + pub fn package_json(&self) -> Option<&Arc> { + self.package_json.as_ref() + } + + /// Returns the full path with query and fragment + pub fn full_path(&self) -> PathBuf { + let mut path = self.path.clone().into_os_string(); + if let Some(query) = &self.query { + path.push(query); + } + if let Some(fragment) = &self.fragment { + path.push(fragment); + } + PathBuf::from(path) + } +} + +impl fmt::Debug for Resolution { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Resolution") + .field("path", &self.path) + .field("query", &self.query) + .field("fragment", &self.fragment) + .field("package_json", &self.package_json.as_ref().map(|p| &p.path)) + .finish() + } +} diff --git a/crates/mako/src/resolve/resource.rs b/crates/mako/src/resolve/resource.rs index 7de6e08af..6e9219481 100644 --- a/crates/mako/src/resolve/resource.rs +++ b/crates/mako/src/resolve/resource.rs @@ -1,6 +1,6 @@ use std::path::PathBuf; -use oxc_resolver::Resolution; +use crate::resolve::Resolution; #[derive(Debug, Clone)] pub struct ExternalResource { diff --git a/docs/config.md b/docs/config.md index 44205841e..869cc77d6 100644 --- a/docs/config.md +++ b/docs/config.md @@ -544,6 +544,7 @@ Specify the plugins to use. }; }) => void; load?: (filePath: string) => Promise<{ content: string, type: 'css'|'js'|'jsx'|'ts'|'tsx' }>; + resolveId?: (id: string, importer: string) => Promise<{ id: string, external: bool }>; } ``` diff --git a/docs/config.zh-CN.md b/docs/config.zh-CN.md index 152377c31..4e497031c 100644 --- a/docs/config.zh-CN.md +++ b/docs/config.zh-CN.md @@ -544,6 +544,7 @@ e.g. }; }) => void; load?: (filePath: string) => Promise<{ content: string, type: 'css'|'js'|'jsx'|'ts'|'tsx' }>; + resolveId?: (id: string, importer: string) => Promise<{ id: string, external: bool }>; } ``` diff --git a/e2e/fixtures/plugins/expect.js b/e2e/fixtures/plugins/expect.js index 848af158a..433942d89 100644 --- a/e2e/fixtures/plugins/expect.js +++ b/e2e/fixtures/plugins/expect.js @@ -8,3 +8,7 @@ assert(content.includes(`children: "foo.bar"`), `jsx in foo.bar works`); assert(content.includes(`children: ".bar"`), `jsx in hoo.bar works`); assert(content.includes(`children: ".haha"`), `plugin in node_modules works`); assert(content.includes(`children: ".hoo"`), `relative plugin works`); + +// resolve_id hook +assert(content.includes(`resolve_id mocked`), `resolve_id hook works`); +assert(content.includes(`module.exports = resolve_id_external;`), `resolve_id hook with external works`); diff --git a/e2e/fixtures/plugins/plugins.config.js b/e2e/fixtures/plugins/plugins.config.js index 5331b5b42..81e88e0bb 100644 --- a/e2e/fixtures/plugins/plugins.config.js +++ b/e2e/fixtures/plugins/plugins.config.js @@ -19,5 +19,17 @@ module.exports = [ }; } } - } + }, + { + async resolveId(source, importer) { + console.log('resolveId', source, importer); + if (source === 'resolve_id') { + return { id: require('path').join(__dirname, 'resolve_id_mock.js'), external: false }; + } + if (source === 'resolve_id_external') { + return { id: 'resolve_id_external', external: true }; + } + return null; + } + }, ]; diff --git a/e2e/fixtures/plugins/resolve_id_mock.js b/e2e/fixtures/plugins/resolve_id_mock.js new file mode 100644 index 000000000..39e08b0a5 --- /dev/null +++ b/e2e/fixtures/plugins/resolve_id_mock.js @@ -0,0 +1 @@ +console.log('resolve_id mocked'); diff --git a/e2e/fixtures/plugins/src/index.tsx b/e2e/fixtures/plugins/src/index.tsx index a936a668a..b53b90ae7 100644 --- a/e2e/fixtures/plugins/src/index.tsx +++ b/e2e/fixtures/plugins/src/index.tsx @@ -2,3 +2,5 @@ console.log(require('./foo.bar')); console.log(require('./hoo.bar')); console.log(require('./foo.haha')); console.log(require('./foo.hoo')); +console.log(require('resolve_id')); +console.log(require('resolve_id_external')); diff --git a/packages/mako/binding.d.ts b/packages/mako/binding.d.ts index 1972f583e..138b79371 100644 --- a/packages/mako/binding.d.ts +++ b/packages/mako/binding.d.ts @@ -51,6 +51,7 @@ export interface JsHooks { }) => void; onGenerateFile?: (path: string, content: Buffer) => Promise; buildStart?: () => Promise; + resolveId?: (source: string, importer: string) => Promise<{ id: string }>; } export interface WriteFile { path: string; @@ -60,6 +61,10 @@ export interface LoadResult { content: string; type: string; } +export interface ResolveIdResult { + id: string; + external: boolean | null; +} export interface BuildParams { root: string; config: { From c9b678630cda442678c685b5fdd697067a92fd93 Mon Sep 17 00:00:00 2001 From: sorrycc Date: Thu, 10 Oct 2024 14:53:50 +0800 Subject: [PATCH 14/21] release: @umijs/mako@0.8.15 --- packages/bundler-mako/package.json | 2 +- packages/mako/npm/darwin-arm64/package.json | 2 +- packages/mako/npm/darwin-x64/package.json | 2 +- packages/mako/npm/linux-arm64-gnu/package.json | 2 +- .../mako/npm/linux-arm64-musl/package.json | 2 +- packages/mako/npm/linux-x64-gnu/package.json | 2 +- packages/mako/npm/linux-x64-musl/package.json | 2 +- packages/mako/npm/win32-ia32-msvc/package.json | 2 +- packages/mako/npm/win32-x64-msvc/package.json | 2 +- packages/mako/package.json | 18 +++++++++--------- 10 files changed, 18 insertions(+), 18 deletions(-) diff --git a/packages/bundler-mako/package.json b/packages/bundler-mako/package.json index 2125c3eb4..f549112fb 100644 --- a/packages/bundler-mako/package.json +++ b/packages/bundler-mako/package.json @@ -3,7 +3,7 @@ "version": "0.8.14", "dependencies": { "@umijs/bundler-utils": "^4.0.81", - "@umijs/mako": "0.8.14", + "@umijs/mako": "0.8.15", "chalk": "^4.1.2", "compression": "^1.7.4", "connect-history-api-fallback": "^2.0.0", diff --git a/packages/mako/npm/darwin-arm64/package.json b/packages/mako/npm/darwin-arm64/package.json index 2971a72c2..51f885afa 100644 --- a/packages/mako/npm/darwin-arm64/package.json +++ b/packages/mako/npm/darwin-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@umijs/mako-darwin-arm64", - "version": "0.8.14", + "version": "0.8.15", "os": [ "darwin" ], diff --git a/packages/mako/npm/darwin-x64/package.json b/packages/mako/npm/darwin-x64/package.json index 23565c53e..131214861 100644 --- a/packages/mako/npm/darwin-x64/package.json +++ b/packages/mako/npm/darwin-x64/package.json @@ -1,6 +1,6 @@ { "name": "@umijs/mako-darwin-x64", - "version": "0.8.14", + "version": "0.8.15", "os": [ "darwin" ], diff --git a/packages/mako/npm/linux-arm64-gnu/package.json b/packages/mako/npm/linux-arm64-gnu/package.json index 95acdf33e..32dedc9f2 100644 --- a/packages/mako/npm/linux-arm64-gnu/package.json +++ b/packages/mako/npm/linux-arm64-gnu/package.json @@ -1,6 +1,6 @@ { "name": "@umijs/mako-linux-arm64-gnu", - "version": "0.8.14", + "version": "0.8.15", "os": [ "linux" ], diff --git a/packages/mako/npm/linux-arm64-musl/package.json b/packages/mako/npm/linux-arm64-musl/package.json index ffc864d12..0fa3d86d4 100644 --- a/packages/mako/npm/linux-arm64-musl/package.json +++ b/packages/mako/npm/linux-arm64-musl/package.json @@ -1,6 +1,6 @@ { "name": "@umijs/mako-linux-arm64-musl", - "version": "0.8.14", + "version": "0.8.15", "os": [ "linux" ], diff --git a/packages/mako/npm/linux-x64-gnu/package.json b/packages/mako/npm/linux-x64-gnu/package.json index 751072564..1a998460f 100644 --- a/packages/mako/npm/linux-x64-gnu/package.json +++ b/packages/mako/npm/linux-x64-gnu/package.json @@ -1,6 +1,6 @@ { "name": "@umijs/mako-linux-x64-gnu", - "version": "0.8.14", + "version": "0.8.15", "os": [ "linux" ], diff --git a/packages/mako/npm/linux-x64-musl/package.json b/packages/mako/npm/linux-x64-musl/package.json index d5bb89622..990c89d59 100644 --- a/packages/mako/npm/linux-x64-musl/package.json +++ b/packages/mako/npm/linux-x64-musl/package.json @@ -1,6 +1,6 @@ { "name": "@umijs/mako-linux-x64-musl", - "version": "0.8.14", + "version": "0.8.15", "os": [ "linux" ], diff --git a/packages/mako/npm/win32-ia32-msvc/package.json b/packages/mako/npm/win32-ia32-msvc/package.json index fd443e301..3b7d26795 100644 --- a/packages/mako/npm/win32-ia32-msvc/package.json +++ b/packages/mako/npm/win32-ia32-msvc/package.json @@ -1,6 +1,6 @@ { "name": "@umijs/mako-win32-ia32-msvc", - "version": "0.8.14", + "version": "0.8.15", "os": [ "win32" ], diff --git a/packages/mako/npm/win32-x64-msvc/package.json b/packages/mako/npm/win32-x64-msvc/package.json index 86f72537e..7136d84fc 100644 --- a/packages/mako/npm/win32-x64-msvc/package.json +++ b/packages/mako/npm/win32-x64-msvc/package.json @@ -1,6 +1,6 @@ { "name": "@umijs/mako-win32-x64-msvc", - "version": "0.8.14", + "version": "0.8.15", "os": [ "win32" ], diff --git a/packages/mako/package.json b/packages/mako/package.json index f82e45c5b..40e8f50a6 100644 --- a/packages/mako/package.json +++ b/packages/mako/package.json @@ -1,6 +1,6 @@ { "name": "@umijs/mako", - "version": "0.8.14", + "version": "0.8.15", "main": "dist/index.js", "types": "dist/index.d.ts", "bin": { @@ -77,14 +77,14 @@ "src:build": "father build" }, "optionalDependencies": { - "@umijs/mako-darwin-arm64": "0.8.14", - "@umijs/mako-linux-arm64-gnu": "0.8.14", - "@umijs/mako-linux-arm64-musl": "0.8.14", - "@umijs/mako-win32-ia32-msvc": "0.8.14", - "@umijs/mako-darwin-x64": "0.8.14", - "@umijs/mako-win32-x64-msvc": "0.8.14", - "@umijs/mako-linux-x64-gnu": "0.8.14", - "@umijs/mako-linux-x64-musl": "0.8.14" + "@umijs/mako-darwin-arm64": "0.8.15", + "@umijs/mako-linux-arm64-gnu": "0.8.15", + "@umijs/mako-linux-arm64-musl": "0.8.15", + "@umijs/mako-win32-ia32-msvc": "0.8.15", + "@umijs/mako-darwin-x64": "0.8.15", + "@umijs/mako-win32-x64-msvc": "0.8.15", + "@umijs/mako-linux-x64-gnu": "0.8.15", + "@umijs/mako-linux-x64-musl": "0.8.15" }, "repository": "git@github.com:umijs/mako.git" } \ No newline at end of file From 5f317cd4b2a40782f7398a2b55b8fcbe74de1257 Mon Sep 17 00:00:00 2001 From: sorrycc Date: Thu, 10 Oct 2024 14:54:42 +0800 Subject: [PATCH 15/21] chore: bundler-mako@0.8.15 --- packages/bundler-mako/package.json | 2 +- pnpm-lock.yaml | 67 +++++++++++++++--------------- 2 files changed, 35 insertions(+), 34 deletions(-) diff --git a/packages/bundler-mako/package.json b/packages/bundler-mako/package.json index f549112fb..5bbed2d87 100644 --- a/packages/bundler-mako/package.json +++ b/packages/bundler-mako/package.json @@ -1,6 +1,6 @@ { "name": "@umijs/bundler-mako", - "version": "0.8.14", + "version": "0.8.15", "dependencies": { "@umijs/bundler-utils": "^4.0.81", "@umijs/mako": "0.8.15", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9fb266c53..a770e96ce 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -436,7 +436,7 @@ importers: specifier: ^4.0.81 version: 4.1.6 '@umijs/mako': - specifier: 0.8.14 + specifier: 0.8.15 version: link:../mako chalk: specifier: ^4.1.2 @@ -537,29 +537,29 @@ importers: version: 21.1.1 optionalDependencies: '@umijs/mako-darwin-arm64': - specifier: 0.8.14 - version: 0.8.14 + specifier: 0.8.15 + version: 0.8.15 '@umijs/mako-darwin-x64': - specifier: 0.8.14 - version: 0.8.14 + specifier: 0.8.15 + version: 0.8.15 '@umijs/mako-linux-arm64-gnu': - specifier: 0.8.14 - version: 0.8.14 + specifier: 0.8.15 + version: 0.8.15 '@umijs/mako-linux-arm64-musl': - specifier: 0.8.14 - version: 0.8.14 + specifier: 0.8.15 + version: 0.8.15 '@umijs/mako-linux-x64-gnu': - specifier: 0.8.14 - version: 0.8.14 + specifier: 0.8.15 + version: 0.8.15 '@umijs/mako-linux-x64-musl': - specifier: 0.8.14 - version: 0.8.14 + specifier: 0.8.15 + version: 0.8.15 '@umijs/mako-win32-ia32-msvc': - specifier: 0.8.14 - version: 0.8.14 + specifier: 0.8.15 + version: 0.8.15 '@umijs/mako-win32-x64-msvc': - specifier: 0.8.14 - version: 0.8.14 + specifier: 0.8.15 + version: 0.8.15 devDependencies: '@napi-rs/cli': specifier: ^2.18.0 @@ -6512,8 +6512,8 @@ packages: dev: true optional: true - /@umijs/mako-darwin-arm64@0.8.14: - resolution: {integrity: sha512-V64q7DqM26+cMKDGyK/3uC/Dw4AR3ILiUieda7N6nthRbG4m6KHfRM8Tr/loDiSscHCkSS+gNCs1Ylp7VpcJ+g==} + /@umijs/mako-darwin-arm64@0.8.15: + resolution: {integrity: sha512-wuOB43kmCFDj5tK1xKI7vUDtPaU+qLxQcvxFCpgSuMlTLPzm5lvKr47nCZ1/46KWvt+ns5OMEYmwD7XwVy75mQ==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] @@ -6530,8 +6530,8 @@ packages: dev: true optional: true - /@umijs/mako-darwin-x64@0.8.14: - resolution: {integrity: sha512-FlamYs2kddKQoU92+NNQ69u8luI1lmqzsqIZkNh3auJ/WKrcrIJakKBjvpvCXzrzPdwg4FFdatbSMj+Y3NtOHA==} + /@umijs/mako-darwin-x64@0.8.15: + resolution: {integrity: sha512-L4bC7YG1t6MDO87Hmc6E8IOVWqKYT4Anneegc9QOVlBbvGWuJQcUBQaTrlceXbhSTkEEJVAJ7nl7qhBZDBM9qw==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] @@ -6539,8 +6539,8 @@ packages: dev: false optional: true - /@umijs/mako-linux-arm64-gnu@0.8.14: - resolution: {integrity: sha512-YoJTbQ9rIfWWrmK45diRVsa5y6g6zamydDLhnkjvxFRSl8BEtAqOzdOh7JAjOjxaQa7/x7kJZbg8QpDPYU793g==} + /@umijs/mako-linux-arm64-gnu@0.8.15: + resolution: {integrity: sha512-SWzw6lYd5JNmBbqEZfobfK5QFl3tanFm3KJm2sUmXDsruTCCWDd4sLNxcg7b+zh1ptsBT7aghc6fl4g+r0rXaw==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] @@ -6548,8 +6548,8 @@ packages: dev: false optional: true - /@umijs/mako-linux-arm64-musl@0.8.14: - resolution: {integrity: sha512-u/LZMIyMLFlLAtKZwrkqpSdF5jDFYeaQbx6zp6pGeeBHVYDnSKmPl0EVlsVZoDsN+TOPZfc47gJGuKdKJsXGpw==} + /@umijs/mako-linux-arm64-musl@0.8.15: + resolution: {integrity: sha512-uQxwLmxBijaIuge+uPNaGgaO7NhywiD9oOvJGcLjReKYZ24YigN9vDjrCQU9lbUF103d5oxpd5T8caViABwJuw==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] @@ -6566,8 +6566,8 @@ packages: dev: true optional: true - /@umijs/mako-linux-x64-gnu@0.8.14: - resolution: {integrity: sha512-5lAzXP842yD8IHvTQ6egTYu8ULwI4maEZBKO6wNS9IQgy586ijGFj/XsVc8Q9mx5xDmGnNs3BPpwbU/Rm1dgsw==} + /@umijs/mako-linux-x64-gnu@0.8.15: + resolution: {integrity: sha512-S0QCESwrmYeB8WQeUfe0oj7F83nsH3YHH6wS0wnIGcE3K6yHWQB73ygjReyz4RHsQZ6kay8bAEIpg24rlfJKyw==} engines: {node: '>= 10'} cpu: [x64] os: [linux] @@ -6584,8 +6584,8 @@ packages: dev: true optional: true - /@umijs/mako-linux-x64-musl@0.8.14: - resolution: {integrity: sha512-p4wuVRakorc192ucLz11hqFInsKmjTTsmGoLs7KQG2bP6KwZ2O2FNAmbPfLbHS0ORFsR/1HF38KW4o66nCTePA==} + /@umijs/mako-linux-x64-musl@0.8.15: + resolution: {integrity: sha512-E8bcYdCtVIky8FX5rIcwKn4Hvotqjd3+hFRZ27+RjuerxktB0Yb0kh1JGSu0UWc/xRk9dDjB20L8nfX3eKwjmw==} engines: {node: '>= 10'} cpu: [x64] os: [linux] @@ -6593,8 +6593,8 @@ packages: dev: false optional: true - /@umijs/mako-win32-ia32-msvc@0.8.14: - resolution: {integrity: sha512-dXMs4qVJ5cI+x07h4+hqtcIDYKJxA7xkIWOoZKXPr/PUUMBQdY5q6EspRKREUHKH1kxEOhsMqwlWxRoWzq3awA==} + /@umijs/mako-win32-ia32-msvc@0.8.15: + resolution: {integrity: sha512-aWXbaq6IxmtfgL+jn6UsiJFzaX1whN2+hzfS0eP31S1hRdeMjBvr6tLFiNcMfm9LmI/tlydjRR0n1WPgIlk5PA==} engines: {node: '>= 10'} cpu: [ia32] os: [win32] @@ -6602,8 +6602,8 @@ packages: dev: false optional: true - /@umijs/mako-win32-x64-msvc@0.8.14: - resolution: {integrity: sha512-lw5FZIlWJ/Mk4VQpOtSI0PIuInXSd+SJdxtn6pWOOEBZ2LomGRhEEsPhNbibyoqXKtJ9vgIHCfYZRVZVkicr7w==} + /@umijs/mako-win32-x64-msvc@0.8.15: + resolution: {integrity: sha512-SsrlUA/9TFRnmEWgripCyZMBrbqXXYdh/sJG2kUqk5Tp9KDVvpHbFhymNLaerpjaZwTw5qunI6+G5Ge+O/PA3g==} engines: {node: '>= 10'} cpu: [x64] os: [win32] @@ -9868,6 +9868,7 @@ packages: /eslint@8.41.0: resolution: {integrity: sha512-WQDQpzGBOP5IrXPo4Hc0814r4/v2rrIsB0rhT7jtunIalgg6gYXWhRMOejVO8yH21T/FGaxjmFjBMNqcIlmH1Q==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. hasBin: true dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@8.41.0) From d49565e44d6a65390d0781e527f84da6eb1d2c50 Mon Sep 17 00:00:00 2001 From: sorrycc Date: Thu, 10 Oct 2024 15:09:01 +0800 Subject: [PATCH 16/21] docs: changelog for 0.8.15 --- CHANGELOG.md | 64 ++++++++++++++++++++++++++++------------------ CHANGELOG_zh-CN.md | 54 +++++++++++++++++++++++--------------- 2 files changed, 73 insertions(+), 45 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bf4c74ca5..323693fa6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,17 @@ + +## 0.8.15 + +`2024-10-10` + +* feat: disable webp to base64 by [@Jinbao1001](https://github.com/Jinbao1001) in [#1602](https://github.com/umijs/mako/pull/1602) +* feat: add resolve_id plugin hook by [@sorrycc](https://github.com/sorrycc) in [#1625](https://github.com/umijs/mako/pull/1625) +* refactor: napi threadsafe function by [@xusd320](https://github.com/xusd320) in [#1608](https://github.com/umijs/mako/pull/1608) +* refactor: config codes organization by [@xusd320](https://github.com/xusd320) in [#1618](https://github.com/umijs/mako/pull/1618) +* fix(bundler-mako): experimental config should be merged deeply by [@sorrycc](https://github.com/sorrycc) in [#1617](https://github.com/umijs/mako/pull/1617) +* fix: clickToComponent don't work by [@sorrycc](https://github.com/sorrycc) in [#1620](https://github.com/umijs/mako/pull/1620) +* fix: duplicate_package_checker panic when no package.json is supplied by [@sorrycc](https://github.com/sorrycc) in [#1621](https://github.com/umijs/mako/pull/1621) +* fix: file_stem index out of bound by [@Jinbao1001](https://github.com/Jinbao1001) in [#1623](https://github.com/umijs/mako/pull/1623) + ## 0.8.14 `2024-09-25` @@ -8,25 +22,25 @@ `2024-09-23` -* fix: chunk_loading_global by @xusd320 in https://github.com/umijs/mako/pull/1590 -* fix: devServer put static serve proxy after umi proxy middleware by @whyer11 in https://github.com/umijs/mako/pull/1558 -* revert: import namespace optimize by @stormslowly in https://github.com/umijs/mako/pull/1606 +* fix: chunk_loading_global by [@xusd320](https://github.com/xusd320) in [#1590](https://github.com/umijs/mako/pull/1590) +* fix: devServer put static serve proxy after umi proxy middleware by [@whyer11](https://github.com/whyer11) in [#1558](https://github.com/umijs/mako/pull/1558) +* revert: import namespace optimize by [@stormslowly](https://github.com/stormslowly) in [#1606](https://github.com/umijs/mako/pull/1606) ## 0.8.12 `2024-09-13` -* fix(tree-shaking): detect export var side effects by @stormslowly in https://github.com/umijs/mako/pull/1579 -* fix: bad output when chunk_loading_global containing quotation mark by @xusd320 in https://github.com/umijs/mako/pull/1582 -* chore: ➕ add a subdot cli tool script for debug module/chunk graph by @stormslowly in https://github.com/umijs/mako/pull/1585 -* fix(win): copy don't work under windows by @sorrycc in https://github.com/umijs/mako/pull/1587 -* fix(win): module id should be win_pathed by @sorrycc in https://github.com/umijs/mako/pull/1588 -* feat(tree-shaking): optimize import namespace used all exports to partial used of source modules by @stormslowly in https://github.com/umijs/mako/pull/1584 -* fix: merge mako config by @hualigushi in https://github.com/umijs/mako/pull/1578 -* fix:clear deps should not panic when module not found by @Jinbao1001 in https://github.com/umijs/mako/pull/1581 -* Revert "fix: merge mako config" by @stormslowly in https://github.com/umijs/mako/pull/1589 -* fix: watch too many file error by @Jinbao1001 in https://github.com/umijs/mako/pull/1550 -* feat: support numeric module Id by @Jinbao1001 in https://github.com/umijs/mako/pull/1561 +* fix(tree-shaking): detect export var side effects by [@stormslowly](https://github.com/stormslowly) in [#1579](https://github.com/umijs/mako/pull/1579) +* fix: bad output when chunk_loading_global containing quotation mark by [@xusd320](https://github.com/xusd320) in [#1582](https://github.com/umijs/mako/pull/1582) +* chore: ➕ add a subdot cli tool script for debug module/chunk graph by [@stormslowly](https://github.com/stormslowly) in [#1585](https://github.com/umijs/mako/pull/1585) +* fix(win): copy don't work under windows by [@sorrycc](https://github.com/sorrycc) in [#1587](https://github.com/umijs/mako/pull/1587) +* fix(win): module id should be win_pathed by [@sorrycc](https://github.com/sorrycc) in [#1588](https://github.com/umijs/mako/pull/1588) +* feat(tree-shaking): optimize import namespace used all exports to partial used of source modules by [@stormslowly](https://github.com/stormslowly) in [#1584](https://github.com/umijs/mako/pull/1584) +* fix: merge mako config by [@hualigushi](https://github.com/hualigushi) in [#1578](https://github.com/umijs/mako/pull/1578) +* fix:clear deps should not panic when module not found by [@Jinbao1001](https://github.com/Jinbao1001) in [#1581](https://github.com/umijs/mako/pull/1581) +* Revert "fix: merge mako config" by [@stormslowly](https://github.com/stormslowly) in [#1589](https://github.com/umijs/mako/pull/1589) +* fix: watch too many file error by [@Jinbao1001](https://github.com/Jinbao1001) in [#1550](https://github.com/umijs/mako/pull/1550) +* feat: support numeric module Id by [@Jinbao1001](https://github.com/Jinbao1001) in [#1561](https://github.com/umijs/mako/pull/1561) ## 0.8.11 @@ -94,12 +108,12 @@ `2024-08-22` -- fix: wrong file extension for map file paths in stat.json by [@stormslowly](https://github.com/stormslowly) in https://github.com/umijs/mako/pull/1506 -- fix: resolve failed when package use `node` as key by [@sorrycc](https://github.com/sorrycc) in https://github.com/umijs/mako/pull/1516 -- perf: merge source map, speed up generation by 800% by [@xusd320](https://github.com/xusd320) in https://github.com/umijs/mako/pull/1509 -- perf: optimize group_chunks, speed up group_chunks by 500% by [@xusd320](https://github.com/xusd320) in https://github.com/umijs/mako/pull/1475 -- refactor: improve regex convention for px2rem config by [@xiaohuoni](https://github.com/xiaohuoni) in https://github.com/umijs/mako/pull/1469 -- refactor: improve behavior of define config by [@xusd320](https://github.com/xusd320) in https://github.com/umijs/mako/pull/1505 +- fix: wrong file extension for map file paths in stat.json by [@stormslowly](https://github.com/stormslowly) in [#1506](https://github.com/umijs/mako/pull/1506) +- fix: resolve failed when package use `node` as key by [@sorrycc](https://github.com/sorrycc) in [#1516](https://github.com/umijs/mako/pull/1516) +- perf: merge source map, speed up generation by 800% by [@xusd320](https://github.com/xusd320) in [#1509](https://github.com/umijs/mako/pull/1509) +- perf: optimize group_chunks, speed up group_chunks by 500% by [@xusd320](https://github.com/xusd320) in [#1475](https://github.com/umijs/mako/pull/1475) +- refactor: improve regex convention for px2rem config by [@xiaohuoni](https://github.com/xiaohuoni) in [#1469](https://github.com/umijs/mako/pull/1469) +- refactor: improve behavior of define config by [@xusd320](https://github.com/xusd320) in [#1505](https://github.com/umijs/mako/pull/1505) ## 0.8.2 @@ -124,10 +138,10 @@ `2024-08-08` -* [Breaking Change] refactor: not write stats.json anymore by [@xusd320](https://github.com/xusd320) in https://github.com/umijs/mako/pull/1485 -* feat: less support "globalVars" by [@gin-lsl](https://github.com/gin-lsl) in https://github.com/umijs/mako/pull/1465 -* feat(bundler-mako): generate dynamicImportToRequire from babel and webpack config by [@PeachScript](https://github.com/PeachScript) in https://github.com/umijs/mako/pull/1479 -* refactor: avoid underscore prefix for chunk file name by [@PeachScript](https://github.com/PeachScript) in https://github.com/umijs/mako/pull/1471 +* [Breaking Change] refactor: not write stats.json anymore by [@xusd320](https://github.com/xusd320) in [#1485](https://github.com/umijs/mako/pull/1485) +* feat: less support "globalVars" by [@gin-lsl](https://github.com/gin-lsl) in [#1465](https://github.com/umijs/mako/pull/1465) +* feat(bundler-mako): generate dynamicImportToRequire from babel and webpack config by [@PeachScript](https://github.com/PeachScript) in [#1479](https://github.com/umijs/mako/pull/1479) +* refactor: avoid underscore prefix for chunk file name by [@PeachScript](https://github.com/PeachScript) in [#1471](https://github.com/umijs/mako/pull/1471) ## 0.7.9 @@ -138,7 +152,7 @@ - feat: sass option support function by [@xiaohuoni](https://github.com/xiaohuoni) in [#1461](https://github.com/umijs/mako/pull/1461) - fix: double value lose by [@xiaohuoni](https://github.com/xiaohuoni) in [#1462](https://github.com/umijs/mako/pull/1462) - perf: use hashlink, speed up codeSplitting by 300% when building big project by [@xusd320](https://github.com/xusd320) in [#1460](https://github.com/umijs/mako/pull/1460) -- perf(tree-shaking): parallelize tree shaking module map init by [@stormslowly](https://github.com/stormslowly) in https://github.com/umijs/mako/pull/1452 +- perf(tree-shaking): parallelize tree shaking module map init by [@stormslowly](https://github.com/stormslowly) in [#1452](https://github.com/umijs/mako/pull/1452) ## 0.7.8 diff --git a/CHANGELOG_zh-CN.md b/CHANGELOG_zh-CN.md index c7c9649cb..d4f043735 100644 --- a/CHANGELOG_zh-CN.md +++ b/CHANGELOG_zh-CN.md @@ -1,3 +1,17 @@ + +## 0.8.15 + +`2024-10-10` + +* 功能:禁用 webp 转 base64 功能 by [@Jinbao1001](https://github.com/Jinbao1001) in [#1602](https://github.com/umijs/mako/pull/1602) +* 功能:添加 resolve_id 插件钩子 by [@sorrycc](https://github.com/sorrycc) in [#1625](https://github.com/umijs/mako/pull/1625) +* 重构:napi 线程安全函数 by [@xusd320](https://github.com/xusd320) in [#1608](https://github.com/umijs/mako/pull/1608) +* 重构:配置代码的组织方式 by [@xusd320](https://github.com/xusd320) in [#1618](https://github.com/umijs/mako/pull/1618) +* 修复(bundler-mako):实验性配置应进行深度合并 by [@sorrycc](https://github.com/sorrycc) in [#1617](https://github.com/umijs/mako/pull/1617) +* 修复:clickToComponent 功能失效 by [@sorrycc](https://github.com/sorrycc) in [#1620](https://github.com/umijs/mako/pull/1620) +* 修复:在没有 package.json 文件时 duplicate_package_checker 会崩溃 by [@sorrycc](https://github.com/sorrycc) in [#1621](https://github.com/umijs/mako/pull/1621) +* 修复:file_stem 索引超出范围问题 by [@Jinbao1001](https://github.com/Jinbao1001) in [#1623](https://github.com/umijs/mako/pull/1623) + ## 0.8.14 `2024-09-25` @@ -8,24 +22,24 @@ `2024-09-23` -* 修复: chunk_loading_global dev 内容未转义问题 by @xusd320 in https://github.com/umijs/mako/pull/1590 -* 修复: mako-bundler devServer 静态文件服务和 umi proxy 中间件执行顺序 by @whyer11 in https://github.com/umijs/mako/pull/1558 -* 回滚: `import * as` 的 tree shaking 优化 by @stormslowly in https://github.com/umijs/mako/pull/1606 +* 修复: chunk_loading_global dev 内容未转义问题 by [@xusd320](https://github.com/xusd320) in [#1590](https://github.com/umijs/mako/pull/1590) +* 修复: mako-bundler devServer 静态文件服务和 umi proxy 中间件执行顺序 by [@whyer11](https://github.com/whyer11) in [#1558](https://github.com/umijs/mako/pull/1558) +* 回滚: `import * as` 的 tree shaking 优化 by [@stormslowly](https://github.com/stormslowly) in [#1606](https://github.com/umijs/mako/pull/1606) ## 0.8.12 `2024-09-13` -* 修复: 检测导出变量的副作用以进行 tree-shaking 优化 (by @stormslowly in #1579) -* 修复: 修复 chunk_loading_global 包含引号时的输出错误 (by @xusd320 in #1582) -* 其他: 添加用于调试模块/块图的 subdot cli 工具脚本 (by @stormslowly in #1585) -* 修复: 修复 Windows 下复制功能失效的问题 (by @sorrycc in #1587) -* 修复: 修复 Windows 下模块 ID 的路径问题 (by @sorrycc in #1588) -* 优化: 优化按需引入命名空间,减少冗余代码 (by @stormslowly in #1584) -* 修复 (已回滚): 修复 Mako 配置合并问题 (by @hualigushi in #1578) -* 修复: 修复清除依赖项时找不到模块导致程序崩溃的问题 (by @Jinbao1001 in #1581) -* 修复: 修复监视过多文件导致的错误 (by @Jinbao1001 in #1550) -* 新增: 支持数字模块 ID (by @Jinbao1001 in #1561) +* 修复: 检测导出变量的副作用以进行 tree-shaking 优化 (by [@stormslowly](https://github.com/stormslowly) in [#1579](https://github.com/umijs/mako/pull/1579)) +* 修复: 修复 chunk_loading_global 包含引号时的输出错误 (by [@xusd320](https://github.com/xusd320) in [#1582](https://github.com/umijs/mako/pull/1582)) +* 其他: 添加用于调试模块/块图的 subdot cli 工具脚本 (by [@stormslowly](https://github.com/stormslowly) in [#1585](https://github.com/umijs/mako/pull/1585)) +* 修复: 修复 Windows 下复制功能失效的问题 (by [@sorrycc](https://github.com/sorrycc) in [#1587](https://github.com/umijs/mako/pull/1587)) +* 修复: 修复 Windows 下模块 ID 的路径问题 (by [@sorrycc](https://github.com/sorrycc) in [#1588](https://github.com/umijs/mako/pull/1588)) +* 优化: 优化按需引入命名空间,减少冗余代码 (by [@stormslowly](https://github.com/stormslowly) in [#1584](https://github.com/umijs/mako/pull/1584)) +* 修复 (已回滚): 修复 Mako 配置合并问题 (by [@hualigushi](https://github.com/hualigushi) in [#1578](https://github.com/umijs/mako/pull/1578)) +* 修复: 修复清除依赖项时找不到模块导致程序崩溃的问题 (by [@Jinbao1001](https://github.com/Jinbao1001) in [#1581](https://github.com/umijs/mako/pull/1581)) +* 修复: 修复监视过多文件导致的错误 (by [@Jinbao1001](https://github.com/Jinbao1001) in [#1550](https://github.com/umijs/mako/pull/1550)) +* 新增: 支持数字模块 ID (by [@Jinbao1001](https://github.com/Jinbao1001) in [#1561](https://github.com/umijs/mako/pull/1561)) ## 0.8.11 @@ -93,12 +107,12 @@ `2024-08-22` -- 修复:stat.json 中 map 文件路径中的后缀名错误 by [@stormslowly](https://github.com/stormslowly) in https://github.com/umijs/mako/pull/1506 -- 修复:无法解析使用 `node` 导出字段的依赖包 by [@sorrycc](https://github.com/sorrycc) in https://github.com/umijs/mako/pull/1516 -- 性能:合并 source map,最高为 generation 阶段提速 800% by [@xusd320](https://github.com/xusd320) in https://github.com/umijs/mako/pull/1509 -- 性能:优化 chunk 分组逻辑,最高为 group_chunks 阶段提速 500% by [@xusd320](https://github.com/xusd320) in https://github.com/umijs/mako/pull/1475 -- 改进:调整 px2rem 配置中正则值的约定方式 by [@xiaohuoni](https://github.com/xiaohuoni) in https://github.com/umijs/mako/pull/1469 -- 改进:调整 define 配置的替换行为,与社区共识保持一致 by [@xusd320](https://github.com/xusd320) in https://github.com/umijs/mako/pull/1505 +- 修复:stat.json 中 map 文件路径中的后缀名错误 by [@stormslowly](https://github.com/stormslowly) in [#1506](https://github.com/umijs/mako/pull/1506) +- 修复:无法解析使用 `node` 导出字段的依赖包 by [@sorrycc](https://github.com/sorrycc) in [#1516](https://github.com/umijs/mako/pull/1516) +- 性能:合并 source map,最高为 generation 阶段提速 800% by [@xusd320](https://github.com/xusd320) in [#1509](https://github.com/umijs/mako/pull/1509) +- 性能:优化 chunk 分组逻辑,最高为 group_chunks 阶段提速 500% by [@xusd320](https://github.com/xusd320) in [#1475](https://github.com/umijs/mako/pull/1475) +- 改进:调整 px2rem 配置中正则值的约定方式 by [@xiaohuoni](https://github.com/xiaohuoni) in [#1469](https://github.com/umijs/mako/pull/1469) +- 改进:调整 define 配置的替换行为,与社区共识保持一致 by [@xusd320](https://github.com/xusd320) in [#1505](https://github.com/umijs/mako/pull/1505) ## 0.8.2 @@ -138,7 +152,7 @@ - 新增: saas 配置支持 function by [@xiaohuoni](https://github.com/xiaohuoni) in [#1461](https://github.com/umijs/mako/pull/1461) - 修复: px2rem 没有正确复制 raw_value by [@xiaohuoni](https://github.com/xiaohuoni) in [#1462](https://github.com/umijs/mako/pull/1462) - 优化: 使用 hashlink 让大型项目 codeSplitting 提速 300% by [@xusd320](https://github.com/xusd320) in [#1460](https://github.com/umijs/mako/pull/1460) -- 优化: 并行处理树摇逻辑 by [@stormslowly](https://github.com/stormslowly) in https://github.com/umijs/mako/pull/1452 +- 优化: 并行处理树摇逻辑 by [@stormslowly](https://github.com/stormslowly) in [#1452](https://github.com/umijs/mako/pull/1452) ## 0.7.8 From 1d44b119b59f23191218fecaf70e8317e8262b88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?chencheng=20=28=E4=BA=91=E8=B0=A6=29?= Date: Fri, 11 Oct 2024 22:07:26 +0800 Subject: [PATCH 17/21] chore: update the release instruction (#1627) --- CONTRIBUTING.md | 25 ++++--- package.json | 2 +- packages/mako/package.json | 4 +- packages/mako/scripts/quick-release.ts | 58 ---------------- packages/mako/scripts/release.ts | 93 ++++---------------------- scripts/release.ts | 70 ------------------- 6 files changed, 30 insertions(+), 222 deletions(-) delete mode 100644 packages/mako/scripts/quick-release.ts delete mode 100644 scripts/release.ts diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0193fd714..6e4b4be5f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -166,21 +166,26 @@ $ XCODE_PROFILE=1 OKAM=/PATH/TO/umijs/marko/packages/bundler-mako/index.js bigfi ## Release -You can release mako with ci or locally. +Before release, please make sure everything is ok. -### Release with CI +```bash +$ just ready +``` -> NOTICE: _canary_ and _dev_ tags are now supported to be released with CI. +Open https://github.com/umijs/mako/actions?query=branch%3Amaster+event%3Apush to checkout the latest master push action with name "node-bind-build", and download the artifacts to packages/mako directory. If the artifacts has no commit hash in the name, you should add the commit hash manually. ```bash -# Make sure everything is ok -$ just ready -# Release with CI +$ git rev-parse HEAD +``` + +Then you can release the new version. + +``` +# Release @umijs/mako and @umijs/bundler-mako $ npm run release -# After released successful, you need to release bundler-mako manually. -$ npm run release:bundler-mako ``` -### Release Locally +After release, you must do 2 things: -Refer to https://yuque.antfin.com/mako/vz2gn4/vkp4qs8u4zcuxqoc for details. +- Release the new version on github +- Update the changelog in CHANGELOG.md and CHANGELOG_zh-CN.md diff --git a/package.json b/package.json index 24c29a888..8e5651539 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "test:e2e": "node scripts/test-e2e.mjs", "test:umi": "node scripts/test-e2e.mjs --fixtures e2e/fixtures.umi --umi", "test:hmr": "node scripts/test-hmr.mjs", - "release": "esno scripts/release.ts", + "release": "npm run release:mako && npm run release:bundler-mako", "release:mako": "pnpm --filter @umijs/mako release", "release:bundler-mako": "esno scripts/release-bundler-mako.ts", "release:rsc": "esno scripts/release-rsc.ts", diff --git a/packages/mako/package.json b/packages/mako/package.json index 40e8f50a6..84b2b589a 100644 --- a/packages/mako/package.json +++ b/packages/mako/package.json @@ -71,8 +71,6 @@ "universal": "napi universal", "version": "napi version", "release": "esno scripts/release.ts", - "release:quick": "esno scripts/quick-release.ts", - "release:build": "esno scripts/release.ts --build", "src:dev": "father dev", "src:build": "father build" }, @@ -87,4 +85,4 @@ "@umijs/mako-linux-x64-musl": "0.8.15" }, "repository": "git@github.com:umijs/mako.git" -} \ No newline at end of file +} diff --git a/packages/mako/scripts/quick-release.ts b/packages/mako/scripts/quick-release.ts deleted file mode 100644 index ccd12ffe0..000000000 --- a/packages/mako/scripts/quick-release.ts +++ /dev/null @@ -1,58 +0,0 @@ -import assert from 'assert'; -import 'zx/globals'; -import { - ensureGitStatus, - loadPkg, - pushToGit, - queryNewVersion, - rootPkgPath, - setNewVersionToBundlerMako, -} from './utils'; - -(async () => { - await run(); -})().catch((e) => { - console.error(e); - process.exit(1); -}); - -async function run() { - await ensureGitStatus(); - - const commitId = (await $`git rev-parse HEAD`).stdout.trim(); - const artifactsFile = `artifacts-${commitId}.zip`; - const hasArtifacts = fs.existsSync(path.join(process.cwd(), artifactsFile)); - assert(hasArtifacts, `${artifactsFile} not found in cwd`); - - const nodePkgPath = rootPkgPath(); - const nodePkg = loadPkg(nodePkgPath); - const { newVersion, tag, branch } = await queryNewVersion(nodePkg); - - nodePkg.version = newVersion; - fs.writeFileSync(nodePkgPath, JSON.stringify(nodePkg, null, 2) + '\n'); - - await build(); - await artifacts(artifactsFile); - - await $`npm publish --tag ${tag} --access public`; - - setNewVersionToBundlerMako(nodePkg.version); - - await pushToGit(nodePkg, branch); -} - -async function build() { - await $`rm -rf ./*.node`; - await $`find ./npm -name '*.node' | xargs rm -f`; - await $`rm -rf ./dist`; - - await $`pnpm run build`; - await $`pnpm run src:build`; - await $`pnpm run format`; -} - -async function artifacts(artifactsFile: string) { - await $`rm -rf *.node`; - await $`unzip ${artifactsFile}`; - await $`npm run artifacts:local`; -} diff --git a/packages/mako/scripts/release.ts b/packages/mako/scripts/release.ts index 12372f602..ccd12ffe0 100644 --- a/packages/mako/scripts/release.ts +++ b/packages/mako/scripts/release.ts @@ -1,3 +1,4 @@ +import assert from 'assert'; import 'zx/globals'; import { ensureGitStatus, @@ -9,11 +10,7 @@ import { } from './utils'; (async () => { - if (argv.build) { - await build(); - } else { - await run(); - } + await run(); })().catch((e) => { console.error(e); process.exit(1); @@ -22,17 +19,20 @@ import { async function run() { await ensureGitStatus(); - // check docker status - console.log('Check docker status'); - await $`docker ps`; + const commitId = (await $`git rev-parse HEAD`).stdout.trim(); + const artifactsFile = `artifacts-${commitId}.zip`; + const hasArtifacts = fs.existsSync(path.join(process.cwd(), artifactsFile)); + assert(hasArtifacts, `${artifactsFile} not found in cwd`); const nodePkgPath = rootPkgPath(); const nodePkg = loadPkg(nodePkgPath); const { newVersion, tag, branch } = await queryNewVersion(nodePkg); + nodePkg.version = newVersion; fs.writeFileSync(nodePkgPath, JSON.stringify(nodePkg, null, 2) + '\n'); await build(); + await artifacts(artifactsFile); await $`npm publish --tag ${tag} --access public`; @@ -42,84 +42,17 @@ async function run() { } async function build() { - // clean await $`rm -rf ./*.node`; await $`find ./npm -name '*.node' | xargs rm -f`; await $`rm -rf ./dist`; - // build linux *.node - console.log('linux building started...'); - const start = Date.now(); - const cargoRoot = path.join(__dirname, '../../..'); - // clean sailfish - // since its lock files may cause build error - await $`rm -rf ${cargoRoot}/target/release/build/sailfish*`; - await build_linux_binding('gnu'); - await build_linux_binding('musl'); - await $`pnpm run format`; - const duration = (Date.now() - start) / 1000; - console.log(`linux building done ${duration}s`); - - // build macos *.node - await $`cargo build --lib -r --target x86_64-apple-darwin`; - await $`pnpm run build:mac:x86`; - await $`cargo build --lib -r --target aarch64-apple-darwin`; - await $`pnpm run build:mac:aarch`; - await $`strip -x ./mako.darwin-*.node`; - - // build src + await $`pnpm run build`; await $`pnpm run src:build`; await $`pnpm run format`; - - // move artifacts to npm - await $`pnpm run artifacts:local`; } -async function build_linux_binding(cLib: 'musl' | 'gnu') { - const isArm = process.arch === 'arm64'; - const cargoBase = path.join( - process.env['CARGO_HOME'] || process.env['HOME']!, - '.cargo', - ); - const cargoMapOption = (p: string) => [ - '-v', - `${path.join(cargoBase, p)}:${path.join('/usr/local/cargo', p)}`, - ]; - const rustupRoot = path.join(os.homedir(), '.rustup'); - const makoRoot = path.join(__dirname, '../../..'); - const volumeOptions = [ - ...cargoMapOption('config'), - ...cargoMapOption('git/db'), - ...cargoMapOption('registry/cache'), - ...cargoMapOption('registry/index'), - ...[`-v`, `${makoRoot}:/build`], - ...[`-v`, `${rustupRoot}:/usr/local/rustup`], - ...[`-w`, `/build`], - ]; - const containerCMD = [ - `cargo build -r --lib --target x86_64-unknown-linux-${cLib}`, - 'cd packages/mako', - `npm run build:linux:${cLib}`, - 'strip mako.linux*.node', - ].join('&&'); - const envOptions: string[] = []; - if (process.env['RUSTUP_DIST_SERVER']) { - envOptions.push( - ...['-e', `RUSTUP_DIST_SERVER=${process.env['RUSTUP_DIST_SERVER']}`], - ); - } - if (process.env[`RUSTUP_UPDATE_ROOT`]) { - envOptions.push( - ...['-e', `RUSTUP_UPDATE_ROOT=${process.env[`RUSTUP_UPDATE_ROOT`]}`], - ); - } - const options = ['--rm', ...volumeOptions, ...envOptions]; - if (isArm) { - options.push(...['--platform', 'linux/amd64']); - } - const image = - cLib === 'gnu' - ? 'ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-debian' - : 'ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-alpine'; - await $`docker run ${options} ${image} bash -c ${containerCMD}`; +async function artifacts(artifactsFile: string) { + await $`rm -rf *.node`; + await $`unzip ${artifactsFile}`; + await $`npm run artifacts:local`; } diff --git a/scripts/release.ts b/scripts/release.ts deleted file mode 100644 index 03d9f1d9c..000000000 --- a/scripts/release.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { parse } from 'semver'; -import 'zx/globals'; - -(async () => { - // check branch - console.log('Check branch'); - const branch = (await $`git branch --show-current`).stdout.trim(); - if (branch !== 'master') { - throw new Error('Please run this script in master branch'); - } - - // check git status - console.log('Check git status'); - const status = (await $`git status --porcelain`).stdout.trim(); - if (status) { - throw new Error('Please commit all changes before release'); - } - - // bump version - console.log('Bump version'); - const nodePkgDir = path.join(__dirname, '../crates/node'); - const nodePkgPath = path.join(nodePkgDir, 'package.json'); - const nodePkg = JSON.parse(fs.readFileSync(nodePkgPath, 'utf-8')); - const version = nodePkg.version; - const parsedVersion = parse(version); - if (!parsedVersion) { - throw new Error(`Invalid version: ${version}`); - } - parsedVersion.patch += 1; - let newVersion = parsedVersion.format(); - // remove prerelease tag - newVersion = newVersion.replace(/-.+/, ''); - nodePkg.version = newVersion; - fs.writeFileSync(nodePkgPath, JSON.stringify(nodePkg, null, 2) + '\n'); - - // set new version to bundler-okam - console.log('Set new version to bundler-okam'); - const bundlerOkamPkgPath = path.join( - __dirname, - '../packages/bundler-okam/package.json', - ); - const bundlerOkamPkg = JSON.parse( - fs.readFileSync(bundlerOkamPkgPath, 'utf-8'), - ); - bundlerOkamPkg.dependencies['@okamjs/okam'] = `${newVersion}`; - fs.writeFileSync( - bundlerOkamPkgPath, - JSON.stringify(bundlerOkamPkg, null, 2) + '\n', - ); - - // pnpm install to update lockfile - console.log('pnpm install'); - await $`pnpm install`; - - // commit - console.log('Commit'); - await $`git add ./`; - await $`git commit -m "Release ${newVersion}"`; - - // tag - console.log('Tag'); - await $`git tag v${newVersion}`; - - // push - console.log('Push'); - await $`git push origin ${branch} --tags`; -})().catch((e) => { - console.error(e); - process.exit(1); -}); From 55dbf48cf57de1d96b5e2ab33db3d68f928870c0 Mon Sep 17 00:00:00 2001 From: xusd320 Date: Sat, 12 Oct 2024 10:56:28 +0800 Subject: [PATCH 18/21] refactor: code-splitting config (#1629) --- crates/mako/src/build/transform.rs | 4 +- crates/mako/src/config/code_splitting.rs | 61 ++++------------- crates/mako/src/generate/optimize_chunk.rs | 78 ++++++++++------------ crates/mako/src/plugins/ssu.rs | 13 ++-- crates/mako/src/utils.rs | 1 + 5 files changed, 60 insertions(+), 97 deletions(-) diff --git a/crates/mako/src/build/transform.rs b/crates/mako/src/build/transform.rs index b76481998..4f57cf79d 100644 --- a/crates/mako/src/build/transform.rs +++ b/crates/mako/src/build/transform.rs @@ -14,7 +14,7 @@ use swc_core::ecma::transforms::base::helpers::{Helpers, HELPERS}; use swc_core::ecma::transforms::base::{resolver, Assumptions}; use swc_core::ecma::transforms::compat::reserved_words; use swc_core::ecma::transforms::optimization::simplifier; -use swc_core::ecma::transforms::optimization::simplify::{dce, Config as SimpilifyConfig}; +use swc_core::ecma::transforms::optimization::simplify::{dce, Config as SimplifyConfig}; use swc_core::ecma::transforms::proposal::decorators; use swc_core::ecma::visit::{Fold, VisitMut}; @@ -236,7 +236,7 @@ impl Transform { // this must be kept for tree shaking to work Box::new(simplifier( unresolved_mark, - SimpilifyConfig { + SimplifyConfig { dce: dce::Config { top_level: false, ..Default::default() diff --git a/crates/mako/src/config/code_splitting.rs b/crates/mako/src/config/code_splitting.rs index 73e973f98..e517ce539 100644 --- a/crates/mako/src/config/code_splitting.rs +++ b/crates/mako/src/config/code_splitting.rs @@ -1,11 +1,10 @@ -use regex::Regex; use serde::{Deserialize, Serialize}; use super::generic_usize::GenericUsizeDefault; use crate::create_deserialize_fn; -#[derive(Deserialize, Serialize, Clone, Debug, Default)] -pub enum OptimizeAllowChunks { +#[derive(Deserialize, Serialize, Clone, Debug, Default, Eq, PartialEq)] +pub enum AllowChunks { #[serde(rename = "all")] All, #[serde(rename = "entry")] @@ -51,7 +50,7 @@ pub struct CodeSplittingGranularOptions { pub struct CodeSplittingAdvancedOptions { #[serde(default = "GenericUsizeDefault::<20000>::value")] pub min_size: usize, - pub groups: Vec, + pub groups: Vec, } impl Default for CodeSplittingAdvancedOptions { @@ -63,22 +62,22 @@ impl Default for CodeSplittingAdvancedOptions { } } -#[derive(Deserialize, Serialize, Clone, Debug)] -pub enum OptimizeChunkNameSuffixStrategy { +#[derive(Deserialize, Serialize, Clone, Debug, Eq, PartialEq)] +pub enum ChunkNameSuffixStrategy { #[serde(rename = "packageName")] PackageName, #[serde(rename = "dependentsHash")] DependentsHash, } -#[derive(Deserialize, Serialize, Clone, Debug)] +#[derive(Deserialize, Serialize, Clone, Debug, Eq, PartialEq)] #[serde(rename_all = "camelCase")] -pub struct OptimizeChunkGroup { +pub struct ChunkGroup { pub name: String, #[serde(default)] - pub name_suffix: Option, + pub name_suffix: Option, #[serde(default)] - pub allow_chunks: OptimizeAllowChunks, + pub allow_chunks: AllowChunks, #[serde(default = "GenericUsizeDefault::<1>::value")] pub min_chunks: usize, #[serde(default = "GenericUsizeDefault::<20000>::value")] @@ -89,14 +88,15 @@ pub struct OptimizeChunkGroup { pub min_module_size: Option, #[serde(default)] pub priority: i8, - #[serde(default, with = "optimize_test_format")] - pub test: Option, + #[serde(default)] + // A string raw of regex + pub test: Option, } -impl Default for OptimizeChunkGroup { +impl Default for ChunkGroup { fn default() -> Self { Self { - allow_chunks: OptimizeAllowChunks::default(), + allow_chunks: AllowChunks::default(), min_chunks: GenericUsizeDefault::<1>::value(), min_size: GenericUsizeDefault::<20000>::value(), max_size: GenericUsizeDefault::<5000000>::value(), @@ -109,37 +109,4 @@ impl Default for OptimizeChunkGroup { } } -/** - * custom formatter for convert string to regex - * @see https://serde.rs/custom-date-format.html - */ -mod optimize_test_format { - use regex::Regex; - use serde::{self, Deserialize, Deserializer, Serializer}; - - pub fn serialize(v: &Option, serializer: S) -> Result - where - S: Serializer, - { - if let Some(v) = v { - serializer.serialize_str(&v.to_string()) - } else { - serializer.serialize_none() - } - } - - pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> - where - D: Deserializer<'de>, - { - let v = String::deserialize(deserializer)?; - - if v.is_empty() { - Ok(None) - } else { - Ok(Regex::new(v.as_str()).ok()) - } - } -} - create_deserialize_fn!(deserialize_code_splitting, CodeSplitting); diff --git a/crates/mako/src/generate/optimize_chunk.rs b/crates/mako/src/generate/optimize_chunk.rs index 72d6ff928..c5d0b2db9 100644 --- a/crates/mako/src/generate/optimize_chunk.rs +++ b/crates/mako/src/generate/optimize_chunk.rs @@ -3,23 +3,22 @@ use std::string::String; use hashlink::LinkedHashSet; use indexmap::{IndexMap, IndexSet}; -use regex::Regex; use tracing::debug; use crate::compiler::Compiler; use crate::config::{ - CodeSplitting, CodeSplittingAdvancedOptions, CodeSplittingGranularOptions, - CodeSplittingStrategy, CodeSplittingStrategyOptions, GenericUsizeDefault, OptimizeAllowChunks, - OptimizeChunkGroup, OptimizeChunkNameSuffixStrategy, + AllowChunks, ChunkGroup, ChunkNameSuffixStrategy, CodeSplitting, CodeSplittingAdvancedOptions, + CodeSplittingGranularOptions, CodeSplittingStrategy, CodeSplittingStrategyOptions, + GenericUsizeDefault, }; use crate::generate::chunk::{Chunk, ChunkId, ChunkType}; use crate::generate::group_chunk::GroupUpdateResult; use crate::module::{Module, ModuleId, ModuleInfo}; use crate::resolve::{ResolvedResource, ResolverResource}; -use crate::utils::url_safe_base64_encode; +use crate::utils::{create_cached_regex, url_safe_base64_encode}; pub struct OptimizeChunksInfo { - pub group_options: OptimizeChunkGroup, + pub group_options: ChunkGroup, pub module_to_chunks: IndexMap>, } @@ -171,7 +170,7 @@ impl Compiler { // check test regex if let Some(test) = &optimize_info.group_options.test { - if !test.is_match(&module_id.id) { + if !create_cached_regex(test).is_match(&module_id.id) { continue; } } @@ -330,7 +329,7 @@ impl Compiler { for info in &mut *optimize_chunks_infos { if let Some(name_suffix) = &info.group_options.name_suffix { match name_suffix { - OptimizeChunkNameSuffixStrategy::PackageName => { + ChunkNameSuffixStrategy::PackageName => { let mut module_to_package_map: HashMap> = HashMap::new(); info.module_to_chunks.keys().for_each(|module_id| { @@ -367,7 +366,7 @@ impl Compiler { }) }); } - OptimizeChunkNameSuffixStrategy::DependentsHash => { + ChunkNameSuffixStrategy::DependentsHash => { let mut module_to_dependents_md5_map: HashMap> = HashMap::new(); info.module_to_chunks @@ -426,12 +425,11 @@ impl Compiler { let info_chunk_id = ChunkId { id: info.group_options.name.clone(), }; - let info_chunk_type = - if matches!(info.group_options.allow_chunks, OptimizeAllowChunks::Async) { - ChunkType::Sync - } else { - ChunkType::Entry(info_chunk_id.clone(), info.group_options.name.clone(), true) - }; + let info_chunk_type = if matches!(info.group_options.allow_chunks, AllowChunks::Async) { + ChunkType::Sync + } else { + ChunkType::Entry(info_chunk_id.clone(), info.group_options.name.clone(), true) + }; let info_chunk = Chunk { modules: info .module_to_chunks @@ -513,18 +511,14 @@ impl Compiler { /* the following is util methods */ - fn check_chunk_type_allow( - &self, - allow_chunks: &OptimizeAllowChunks, - chunk_type: &ChunkType, - ) -> bool { + fn check_chunk_type_allow(&self, allow_chunks: &AllowChunks, chunk_type: &ChunkType) -> bool { match allow_chunks { - OptimizeAllowChunks::All => matches!( + AllowChunks::All => matches!( chunk_type, &ChunkType::Entry(_, _, false) | &ChunkType::Async ), - OptimizeAllowChunks::Entry => matches!(chunk_type, &ChunkType::Entry(_, _, false)), - OptimizeAllowChunks::Async => chunk_type == &ChunkType::Async, + AllowChunks::Entry => matches!(chunk_type, &ChunkType::Entry(_, _, false)), + AllowChunks::Async => chunk_type == &ChunkType::Async, } } @@ -594,13 +588,13 @@ impl Compiler { fn code_splitting_strategy_auto() -> CodeSplittingAdvancedOptions { CodeSplittingAdvancedOptions { groups: vec![ - OptimizeChunkGroup { + ChunkGroup { name: "vendors".to_string(), - test: Regex::new(r"[/\\]node_modules[/\\]").ok(), + test: Some(r"[/\\]node_modules[/\\]".to_string()), priority: -10, ..Default::default() }, - OptimizeChunkGroup { + ChunkGroup { name: "common".to_string(), min_chunks: 2, // always split, to avoid multi-instance risk @@ -619,34 +613,36 @@ fn code_splitting_strategy_granular( ) -> CodeSplittingAdvancedOptions { CodeSplittingAdvancedOptions { groups: vec![ - OptimizeChunkGroup { + ChunkGroup { name: "framework".to_string(), - allow_chunks: OptimizeAllowChunks::All, + allow_chunks: AllowChunks::All, test: if framework_packages.is_empty() { - Regex::new("^$").ok() + Some("^$".to_string()) } else { - Regex::new(&format!( - r#"[/\\]node_modules[/\\].*({})[/\\]"#, - framework_packages.join("|") - )) - .ok() + Some( + format!( + r#"[/\\]node_modules[/\\].*({})[/\\]"#, + framework_packages.join("|") + ) + .to_string(), + ) }, priority: -10, ..Default::default() }, - OptimizeChunkGroup { + ChunkGroup { name: "lib".to_string(), - name_suffix: Some(OptimizeChunkNameSuffixStrategy::PackageName), - allow_chunks: OptimizeAllowChunks::Async, - test: Regex::new(r"[/\\]node_modules[/\\]").ok(), + name_suffix: Some(ChunkNameSuffixStrategy::PackageName), + allow_chunks: AllowChunks::Async, + test: Some(r"[/\\]node_modules[/\\]".to_string()), min_module_size: Some(lib_min_size), priority: -20, ..Default::default() }, - OptimizeChunkGroup { + ChunkGroup { name: "shared".to_string(), - name_suffix: Some(OptimizeChunkNameSuffixStrategy::DependentsHash), - allow_chunks: OptimizeAllowChunks::Async, + name_suffix: Some(ChunkNameSuffixStrategy::DependentsHash), + allow_chunks: AllowChunks::Async, priority: -30, min_chunks: 2, ..Default::default() diff --git a/crates/mako/src/plugins/ssu.rs b/crates/mako/src/plugins/ssu.rs index 843e3d152..9060a4794 100644 --- a/crates/mako/src/plugins/ssu.rs +++ b/crates/mako/src/plugins/ssu.rs @@ -8,15 +8,14 @@ use std::sync::{Arc, Mutex}; use anyhow::Result; use dashmap::DashSet; use rayon::prelude::*; -use regex::Regex; use serde::{Deserialize, Serialize}; use tracing::debug; use crate::ast::file::{Content, File, JsContent}; use crate::compiler::{Args, Compiler, Context}; use crate::config::{ - CodeSplitting, CodeSplittingAdvancedOptions, CodeSplittingStrategy, - CodeSplittingStrategyOptions, Config, OptimizeAllowChunks, OptimizeChunkGroup, + AllowChunks, ChunkGroup, CodeSplitting, CodeSplittingAdvancedOptions, CodeSplittingStrategy, + CodeSplittingStrategyOptions, Config, }; use crate::generate::chunk::ChunkType; use crate::generate::chunk_pot::util::{hash_hashmap, hash_vec}; @@ -164,18 +163,18 @@ impl Plugin for SUPlus { CodeSplittingAdvancedOptions { min_size: 0, groups: vec![ - OptimizeChunkGroup { + ChunkGroup { name: "node_modules".to_string(), name_suffix: None, - allow_chunks: OptimizeAllowChunks::All, + allow_chunks: AllowChunks::All, min_chunks: 0, min_size: 0, max_size: usize::MAX, min_module_size: None, priority: 10, - test: Regex::new(r"[/\\]node_modules[/\\]").ok(), + test: Some(r"[/\\]node_modules[/\\]".to_string()), }, - OptimizeChunkGroup { + ChunkGroup { name: "common".to_string(), min_chunks: 0, // always split, to avoid multi-instance risk diff --git a/crates/mako/src/utils.rs b/crates/mako/src/utils.rs index afde8941a..a469dd3a8 100644 --- a/crates/mako/src/utils.rs +++ b/crates/mako/src/utils.rs @@ -72,6 +72,7 @@ pub(crate) fn get_pkg_name(root: &Path) -> Option { pub fn create_cached_regex(re: &str) -> Regex { Regex::new(re).unwrap() } + #[cfg(test)] mod tests { use super::*; From bcdb3c4ad45b18fcbc3e64119e1d493cec8afaed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?chencheng=20=28=E4=BA=91=E8=B0=A6=29?= Date: Sat, 12 Oct 2024 11:18:35 +0800 Subject: [PATCH 19/21] feat: add loadInclude plugin hook (#1630) --- crates/binding/src/js_hook.rs | 6 ++++++ crates/binding/src/js_plugin.rs | 11 +++++++++++ docs/config.md | 1 + docs/config.zh-CN.md | 1 + e2e/fixtures/plugins/plugins.config.js | 15 ++++++++------- packages/mako/binding.d.ts | 1 + 6 files changed, 28 insertions(+), 7 deletions(-) diff --git a/crates/binding/src/js_hook.rs b/crates/binding/src/js_hook.rs index 444b47681..ba59d51cd 100644 --- a/crates/binding/src/js_hook.rs +++ b/crates/binding/src/js_hook.rs @@ -12,6 +12,8 @@ pub struct JsHooks { ts_type = "(filePath: string) => Promise<{ content: string, type: 'css'|'js' } | void> | void;" )] pub load: Option, + #[napi(ts_type = "(filePath: string) => Promise | bool;")] + pub load_include: Option, #[napi(ts_type = r#"(data: { isFirstCompile: boolean; time: number; @@ -66,6 +68,7 @@ pub struct TsFnHooks { pub build_start: Option>, pub generate_end: Option>, pub load: Option>>, + pub load_include: Option>>, pub resolve_id: Option>>, pub _on_generate_file: Option>, } @@ -82,6 +85,9 @@ impl TsFnHooks { load: hooks.load.as_ref().map(|hook| unsafe { ThreadsafeFunction::from_napi_value(env.raw(), hook.raw()).unwrap() }), + load_include: hooks.load_include.as_ref().map(|hook| unsafe { + ThreadsafeFunction::from_napi_value(env.raw(), hook.raw()).unwrap() + }), resolve_id: hooks.resolve_id.as_ref().map(|hook| unsafe { ThreadsafeFunction::from_napi_value(env.raw(), hook.raw()).unwrap() }), diff --git a/crates/binding/src/js_plugin.rs b/crates/binding/src/js_plugin.rs index 6d6b47ee5..4739e3fe9 100644 --- a/crates/binding/src/js_plugin.rs +++ b/crates/binding/src/js_plugin.rs @@ -26,6 +26,17 @@ impl Plugin for JsPlugin { fn load(&self, param: &PluginLoadParam, _context: &Arc) -> Result> { if let Some(hook) = &self.hooks.load { + if self.hooks.load_include.is_some() + && self + .hooks + .load_include + .as_ref() + .unwrap() + .call(param.file.path.to_string_lossy().to_string())? + == Some(false) + { + return Ok(None); + } let x: Option = hook.call(param.file.path.to_string_lossy().to_string())?; if let Some(x) = x { match x.content_type.as_str() { diff --git a/docs/config.md b/docs/config.md index 869cc77d6..c1f64314b 100644 --- a/docs/config.md +++ b/docs/config.md @@ -544,6 +544,7 @@ Specify the plugins to use. }; }) => void; load?: (filePath: string) => Promise<{ content: string, type: 'css'|'js'|'jsx'|'ts'|'tsx' }>; + loadInclude?: (filePath: string) => boolean; resolveId?: (id: string, importer: string) => Promise<{ id: string, external: bool }>; } ``` diff --git a/docs/config.zh-CN.md b/docs/config.zh-CN.md index 4e497031c..378e0324e 100644 --- a/docs/config.zh-CN.md +++ b/docs/config.zh-CN.md @@ -544,6 +544,7 @@ e.g. }; }) => void; load?: (filePath: string) => Promise<{ content: string, type: 'css'|'js'|'jsx'|'ts'|'tsx' }>; + loadInclude?: (filePath: string) => boolean; resolveId?: (id: string, importer: string) => Promise<{ id: string, external: bool }>; } ``` diff --git a/e2e/fixtures/plugins/plugins.config.js b/e2e/fixtures/plugins/plugins.config.js index 81e88e0bb..69cede8dc 100644 --- a/e2e/fixtures/plugins/plugins.config.js +++ b/e2e/fixtures/plugins/plugins.config.js @@ -11,13 +11,14 @@ module.exports = [ } }, { - async load(path) { - if (path.endsWith('.bar')) { - return { - content: `export default () => .bar;`, - type: 'jsx', - }; - } + async loadInclude(path) { + return path.endsWith('.bar'); + }, + async load() { + return { + content: `export default () => .bar;`, + type: 'jsx', + }; } }, { diff --git a/packages/mako/binding.d.ts b/packages/mako/binding.d.ts index 138b79371..0d9d02643 100644 --- a/packages/mako/binding.d.ts +++ b/packages/mako/binding.d.ts @@ -8,6 +8,7 @@ export interface JsHooks { load?: ( filePath: string, ) => Promise<{ content: string; type: 'css' | 'js' } | void> | void; + loadInclude?: (filePath: string) => Promise | bool; generateEnd?: (data: { isFirstCompile: boolean; time: number; From 7a21451d69a0768cdedcaab7b2a6840be4ec42f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?chencheng=20=28=E4=BA=91=E8=B0=A6=29?= Date: Sat, 12 Oct 2024 13:59:36 +0800 Subject: [PATCH 20/21] feat: add { isEntry } for resolve_id plugin hook (#1631) --- crates/binding/src/js_hook.rs | 12 ++++++++++-- crates/binding/src/js_plugin.rs | 14 ++++++++++---- crates/mako/src/build/analyze_deps.rs | 1 - crates/mako/src/plugin.rs | 9 ++++++++- crates/mako/src/resolve.rs | 14 ++++++++++---- docs/config.md | 2 +- docs/config.zh-CN.md | 2 +- e2e/fixtures/plugins/plugins.config.js | 4 ++-- packages/mako/binding.d.ts | 9 ++++++++- 9 files changed, 50 insertions(+), 17 deletions(-) diff --git a/crates/binding/src/js_hook.rs b/crates/binding/src/js_hook.rs index ba59d51cd..fcf0615ea 100644 --- a/crates/binding/src/js_hook.rs +++ b/crates/binding/src/js_hook.rs @@ -60,7 +60,9 @@ pub struct JsHooks { pub _on_generate_file: Option, #[napi(ts_type = "() => Promise;")] pub build_start: Option, - #[napi(ts_type = "(source: string, importer: string) => Promise<{ id: string }>;")] + #[napi( + ts_type = "(source: string, importer: string, { isEntry: bool }) => Promise<{ id: string }>;" + )] pub resolve_id: Option, } @@ -69,7 +71,8 @@ pub struct TsFnHooks { pub generate_end: Option>, pub load: Option>>, pub load_include: Option>>, - pub resolve_id: Option>>, + pub resolve_id: + Option>>, pub _on_generate_file: Option>, } @@ -117,3 +120,8 @@ pub struct ResolveIdResult { pub id: String, pub external: Option, } + +#[napi(object)] +pub struct ResolveIdParams { + pub is_entry: bool, +} diff --git a/crates/binding/src/js_plugin.rs b/crates/binding/src/js_plugin.rs index 4739e3fe9..e42b76762 100644 --- a/crates/binding/src/js_plugin.rs +++ b/crates/binding/src/js_plugin.rs @@ -1,7 +1,7 @@ use std::path::PathBuf; use std::sync::Arc; -use crate::js_hook::{LoadResult, ResolveIdResult, TsFnHooks, WriteFile}; +use crate::js_hook::{LoadResult, ResolveIdParams, ResolveIdResult, TsFnHooks, WriteFile}; pub struct JsPlugin { pub hooks: TsFnHooks, @@ -9,7 +9,7 @@ pub struct JsPlugin { use anyhow::{anyhow, Result}; use mako::ast::file::{Content, JsContent}; use mako::compiler::Context; -use mako::plugin::{Plugin, PluginGenerateEndParams, PluginLoadParam}; +use mako::plugin::{Plugin, PluginGenerateEndParams, PluginLoadParam, PluginResolveIdParams}; use mako::resolve::{ExternalResource, Resolution, ResolvedResource, ResolverResource}; impl Plugin for JsPlugin { @@ -64,11 +64,17 @@ impl Plugin for JsPlugin { &self, source: &str, importer: &str, + params: &PluginResolveIdParams, _context: &Arc, ) -> Result> { if let Some(hook) = &self.hooks.resolve_id { - let x: Option = - hook.call((source.to_string(), importer.to_string()))?; + let x: Option = hook.call(( + source.to_string(), + importer.to_string(), + ResolveIdParams { + is_entry: params.is_entry, + }, + ))?; if let Some(x) = x { if let Some(true) = x.external { return Ok(Some(ResolverResource::External(ExternalResource { diff --git a/crates/mako/src/build/analyze_deps.rs b/crates/mako/src/build/analyze_deps.rs index 5286717e0..1bb374aa5 100644 --- a/crates/mako/src/build/analyze_deps.rs +++ b/crates/mako/src/build/analyze_deps.rs @@ -52,7 +52,6 @@ impl AnalyzeDeps { for dep in deps { let result = resolve( - // . &file.resolve_from(&context), &dep, &context.resolvers, diff --git a/crates/mako/src/plugin.rs b/crates/mako/src/plugin.rs index 1b4d27883..5d1d54225 100644 --- a/crates/mako/src/plugin.rs +++ b/crates/mako/src/plugin.rs @@ -23,6 +23,11 @@ pub struct PluginLoadParam<'a> { pub file: &'a File, } +#[derive(Debug)] +pub struct PluginResolveIdParams { + pub is_entry: bool, +} + pub struct PluginParseParam<'a> { pub file: &'a File, } @@ -57,6 +62,7 @@ pub trait Plugin: Any + Send + Sync { &self, _source: &str, _importer: &str, + _params: &PluginResolveIdParams, _context: &Arc, ) -> Result> { Ok(None) @@ -256,10 +262,11 @@ impl PluginDriver { &self, source: &str, importer: &str, + params: &PluginResolveIdParams, context: &Arc, ) -> Result> { for plugin in &self.plugins { - let ret = plugin.resolve_id(source, importer, context)?; + let ret = plugin.resolve_id(source, importer, params, context)?; if ret.is_some() { return Ok(ret); } diff --git a/crates/mako/src/resolve.rs b/crates/mako/src/resolve.rs index 4a74f4462..f283eba13 100644 --- a/crates/mako/src/resolve.rs +++ b/crates/mako/src/resolve.rs @@ -23,6 +23,7 @@ use crate::config::{ }; use crate::features::rsc::Rsc; use crate::module::{Dependency, ResolveType}; +use crate::plugin::PluginResolveIdParams; use crate::utils::create_cached_regex; #[derive(Debug, Error)] @@ -52,10 +53,15 @@ pub fn resolve( crate::mako_profile_scope!("resolve", &dep.source); // plugin first - if let Some(resolved) = context - .plugin_driver - .resolve_id(&dep.source, path, context)? - { + if let Some(resolved) = context.plugin_driver.resolve_id( + &dep.source, + path, + // it's a compatibility feature for unplugin hooks + // is_entry is always false for dependencies + // since entry file does not need be be resolved + &PluginResolveIdParams { is_entry: false }, + context, + )? { return Ok(resolved); } diff --git a/docs/config.md b/docs/config.md index c1f64314b..2f6ed7799 100644 --- a/docs/config.md +++ b/docs/config.md @@ -545,7 +545,7 @@ Specify the plugins to use. }) => void; load?: (filePath: string) => Promise<{ content: string, type: 'css'|'js'|'jsx'|'ts'|'tsx' }>; loadInclude?: (filePath: string) => boolean; - resolveId?: (id: string, importer: string) => Promise<{ id: string, external: bool }>; + resolveId?: (id: string, importer: string, { isEntry: bool }) => Promise<{ id: string, external: bool }>; } ``` diff --git a/docs/config.zh-CN.md b/docs/config.zh-CN.md index 378e0324e..0e9845571 100644 --- a/docs/config.zh-CN.md +++ b/docs/config.zh-CN.md @@ -545,7 +545,7 @@ e.g. }) => void; load?: (filePath: string) => Promise<{ content: string, type: 'css'|'js'|'jsx'|'ts'|'tsx' }>; loadInclude?: (filePath: string) => boolean; - resolveId?: (id: string, importer: string) => Promise<{ id: string, external: bool }>; + resolveId?: (id: string, importer: string, { isEntry: bool }) => Promise<{ id: string, external: bool }>; } ``` diff --git a/e2e/fixtures/plugins/plugins.config.js b/e2e/fixtures/plugins/plugins.config.js index 69cede8dc..2dbeafc23 100644 --- a/e2e/fixtures/plugins/plugins.config.js +++ b/e2e/fixtures/plugins/plugins.config.js @@ -22,8 +22,8 @@ module.exports = [ } }, { - async resolveId(source, importer) { - console.log('resolveId', source, importer); + async resolveId(source, importer, options) { + console.log('resolveId', source, importer, options); if (source === 'resolve_id') { return { id: require('path').join(__dirname, 'resolve_id_mock.js'), external: false }; } diff --git a/packages/mako/binding.d.ts b/packages/mako/binding.d.ts index 0d9d02643..b99643f94 100644 --- a/packages/mako/binding.d.ts +++ b/packages/mako/binding.d.ts @@ -52,7 +52,11 @@ export interface JsHooks { }) => void; onGenerateFile?: (path: string, content: Buffer) => Promise; buildStart?: () => Promise; - resolveId?: (source: string, importer: string) => Promise<{ id: string }>; + resolveId?: ( + source: string, + importer: string, + { isEntry: bool }, + ) => Promise<{ id: string }>; } export interface WriteFile { path: string; @@ -66,6 +70,9 @@ export interface ResolveIdResult { id: string; external: boolean | null; } +export interface ResolveIdParams { + isEntry: boolean; +} export interface BuildParams { root: string; config: { From 428cdfabff83cba2e7575458fc1bd4cd0b64b8c7 Mon Sep 17 00:00:00 2001 From: pshu Date: Sat, 12 Oct 2024 15:38:13 +0800 Subject: [PATCH 21/21] feat/upgrade swc (#1444) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 🚧 * 🚧 a basic working version * chore: 🚨 lint happy * refactor: 🎨 adjust to new swc * refactor: 🎨 remove deprecated methods * chore: 🚨 lint happy * feat: ✨ update swc emotion * chore: 🔧 remove useless profile in sub crate * chore: 🔧 add back emotion plugin * refactor: 🎨 add back merge source map * test: ✅ hot update js file served by hyper static, it use text/javascript * chore: 🔧 lock update * chore: 🔧 clean up swc core feature * refactor: 🎨 fix breaking change of ctxt of span * fix: 🐛 ctxt apply mark * refactor: 🎨 use DUMMY CTXT instead of SyntaxContext::empty() * chore: ⬆️ temperal use mdxjs from kdy branch * feat: ✨ re-enable mdxjs * feat: ✨ swc_core 0.100.1 * chore: 🙈 ignore fmt in fixtures * chore: 🚨 lint happy * chore: ⬆️ swc_common * chore: ✏️ typo * release: @umijs/mako@0.8.1-canary.20240812.1 * chore: bundler-mako@0.8.1-canary.20240812.1 * chore: ⬆️ swc_core 0.100.6 * release: @umijs/mako@0.8.1-canary.20240814.2 * chore: bundler-mako@0.8.1-canary.20240814.2 * chore: 🚨 lint happy * chore: 🔧 CI build bindings * chore: 🔧 fix build docker * refactor: 🔥 remove aarch64-unknown-linux-gnu * chore: 🔧 create tar * chore: 🙈 * release: @umijs/mako@0.8.3-canary.20240820.1 * chore: bundler-mako@0.8.3-canary.20240820.1 * chore: 🔧 wrong donwload param * chore: 🔧 upload download actions should be same version * chore: 🔧 try codecov in ci * refactor: 🔥 remove unnecessary target * refactor: 🎨 use swc comments * fix: 🐛 after upgrade to swc_core it should remove paren before minifiy * refactor: 🎨 move dummy ctxt defintion to ast mod * chore: 🚨 lint happy * release: @umijs/mako@0.8.8-canary.20240902.1 * chore: bundler-mako@0.8.8-canary.20240902.1 * release: @umijs/mako@0.8.8-canary.20240903.3 * chore: bundler-mako@0.8.8-canary.20240903.3 * refactor: 🎨 use VisitMut + Fold code style * chore: ⬆️ update pnpm-lock * chore: 🙈 * revert: ⏪ delete musl bindin * release: @umijs/mako@0.8.9-canary.20240909.1 * chore: bundler-mako@0.8.9-canary.20240909.1 * release: @umijs/mako@0.8.11-canary.20240910.1 * chore: bundler-mako@0.8.11-canary.20240910.1 * fix: 🐛 use chars() instead of bytes() * fix: 🐛 unescape html entity by html escape crate * release: @umijs/mako@0.8.14-canary.20240924.1 * chore: bundler-mako@0.8.14-canary.20240924.1 * release: @umijs/mako@0.8.15-canary.20240927.1 * chore: bundler-mako@0.8.15-canary.20240927.1 --- Cargo.lock | 3810 +++++++++-------- Cargo.toml | 6 +- biome.json | 3 +- crates/mako/Cargo.toml | 25 +- crates/mako/src/ast.rs | 4 + crates/mako/src/ast/comments.rs | 40 +- crates/mako/src/ast/css_ast.rs | 7 +- crates/mako/src/ast/js_ast.rs | 8 +- crates/mako/src/ast/sourcemap.rs | 22 +- crates/mako/src/ast/utils.rs | 15 +- crates/mako/src/build/load.rs | 2 +- crates/mako/src/build/transform.rs | 4 +- crates/mako/src/compiler.rs | 4 + crates/mako/src/features/node.rs | 6 +- crates/mako/src/generate.rs | 8 - crates/mako/src/generate/chunk_pot.rs | 4 +- .../mako/src/generate/chunk_pot/ast_impl.rs | 2 + .../mako/src/generate/chunk_pot/str_impl.rs | 6 +- crates/mako/src/generate/chunk_pot/util.rs | 18 +- crates/mako/src/generate/minify.rs | 27 +- crates/mako/src/generate/swc_helpers.rs | 1 + crates/mako/src/generate/transform.rs | 3 +- crates/mako/src/lib.rs | 1 - crates/mako/src/main.rs | 1 - crates/mako/src/module.rs | 4 + crates/mako/src/plugins/bundless_compiler.rs | 1 - crates/mako/src/plugins/context_module.rs | 7 +- .../src/plugins/invalid_webpack_syntax.rs | 10 +- crates/mako/src/plugins/minifish/inject.rs | 28 +- .../mako/src/plugins/minifish/unsimplify.rs | 3 + crates/mako/src/plugins/progress.rs | 2 +- .../src/plugins/require_context/visitor.rs | 2 +- crates/mako/src/plugins/tree_shaking.rs | 3 +- .../mako/src/plugins/tree_shaking/module.rs | 10 +- .../tree_shaking/shake/module_concatenate.rs | 19 +- .../module_concatenate/concatenate_context.rs | 15 +- .../concatenated_transformer.rs | 35 +- .../concatenated_transformer/tests.rs | 14 +- .../module_concatenate/exports_transform.rs | 204 - .../external_transformer.rs | 2 +- .../module_concatenate/module_ref_rewriter.rs | 19 +- .../shake/module_concatenate/ref_link.rs | 18 +- .../plugins/tree_shaking/shake/skip_module.rs | 7 +- .../plugins/tree_shaking/statement_graph.rs | 3 + crates/mako/src/stats.rs | 7 +- crates/mako/src/visitors/async_module.rs | 39 +- crates/mako/src/visitors/common_js.rs | 22 +- crates/mako/src/visitors/css_px2rem.rs | 4 +- .../mako/src/visitors/default_export_namer.rs | 3 + crates/mako/src/visitors/dep_replacer.rs | 25 +- crates/mako/src/visitors/dynamic_import.rs | 20 +- .../src/visitors/dynamic_import_to_require.rs | 26 +- crates/mako/src/visitors/env_replacer.rs | 17 +- .../mako/src/visitors/fix_symbol_conflict.rs | 6 +- .../src/visitors/import_meta_env_replacer.rs | 14 +- crates/mako/src/visitors/mako_require.rs | 2 +- crates/mako/src/visitors/meta_url_replacer.rs | 7 +- crates/mako/src/visitors/new_url_assets.rs | 13 +- .../src/visitors/optimize_define_utils.rs | 39 +- crates/mako/src/visitors/provide.rs | 10 +- .../src/visitors/public_path_assignment.rs | 28 +- crates/mako/src/visitors/ts_strip.rs | 10 +- crates/mako/src/visitors/tsx_strip.rs | 4 + crates/svgr-rs/Cargo.toml | 41 + crates/svgr-rs/__fixture__/basic/input.svg | 13 + crates/svgr-rs/__fixture__/basic/output.jsx | 1 + .../should-handle-spaces-and-tab/input.svg | 11 + .../should-handle-spaces-and-tab/output.jsx | 1 + crates/svgr-rs/src/add_jsx_attribute.rs | 368 ++ crates/svgr-rs/src/core/config.rs | 186 + crates/svgr-rs/src/core/mod.rs | 2 + crates/svgr-rs/src/core/state.rs | 225 + crates/svgr-rs/src/error.rs | 11 + .../svgr-rs/src/hast_to_swc_ast/decode_xml.rs | 33 + .../svgr-rs/src/hast_to_swc_ast/mappings.rs | 492 +++ crates/svgr-rs/src/hast_to_swc_ast/mod.rs | 357 ++ .../hast_to_swc_ast/string_to_object_style.rs | 99 + crates/svgr-rs/src/hast_to_swc_ast/util.rs | 6 + crates/svgr-rs/src/lib.rs | 134 + crates/svgr-rs/src/remove_jsx_attribute.rs | 132 + crates/svgr-rs/src/replace_jsx_attribute.rs | 133 + crates/svgr-rs/src/svg_dynamic_title.rs | 384 ++ crates/svgr-rs/src/svg_em_dimensions.rs | 235 + .../svgr-rs/src/transform_react_native_svg.rs | 305 ++ .../src/transform_svg_component/mod.rs | 856 ++++ .../src/transform_svg_component/variables.rs | 607 +++ rust-toolchain.toml | 2 +- scripts/test-hmr.mjs | 2 +- 88 files changed, 6935 insertions(+), 2430 deletions(-) delete mode 100644 crates/mako/src/plugins/tree_shaking/shake/module_concatenate/exports_transform.rs create mode 100644 crates/svgr-rs/Cargo.toml create mode 100644 crates/svgr-rs/__fixture__/basic/input.svg create mode 100644 crates/svgr-rs/__fixture__/basic/output.jsx create mode 100644 crates/svgr-rs/__fixture__/should-handle-spaces-and-tab/input.svg create mode 100644 crates/svgr-rs/__fixture__/should-handle-spaces-and-tab/output.jsx create mode 100644 crates/svgr-rs/src/add_jsx_attribute.rs create mode 100644 crates/svgr-rs/src/core/config.rs create mode 100644 crates/svgr-rs/src/core/mod.rs create mode 100644 crates/svgr-rs/src/core/state.rs create mode 100644 crates/svgr-rs/src/error.rs create mode 100644 crates/svgr-rs/src/hast_to_swc_ast/decode_xml.rs create mode 100644 crates/svgr-rs/src/hast_to_swc_ast/mappings.rs create mode 100644 crates/svgr-rs/src/hast_to_swc_ast/mod.rs create mode 100644 crates/svgr-rs/src/hast_to_swc_ast/string_to_object_style.rs create mode 100644 crates/svgr-rs/src/hast_to_swc_ast/util.rs create mode 100644 crates/svgr-rs/src/lib.rs create mode 100644 crates/svgr-rs/src/remove_jsx_attribute.rs create mode 100644 crates/svgr-rs/src/replace_jsx_attribute.rs create mode 100644 crates/svgr-rs/src/svg_dynamic_title.rs create mode 100644 crates/svgr-rs/src/svg_em_dimensions.rs create mode 100644 crates/svgr-rs/src/transform_react_native_svg.rs create mode 100644 crates/svgr-rs/src/transform_svg_component/mod.rs create mode 100644 crates/svgr-rs/src/transform_svg_component/variables.rs diff --git a/Cargo.lock b/Cargo.lock index ddcbfa933..e8130886d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14,9 +14,9 @@ dependencies = [ [[package]] name = "ab_glyph" -version = "0.2.22" +version = "0.2.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1061f3ff92c2f65800df1f12fc7b4ff44ee14783104187dd04dfee6f11b0fd2" +checksum = "79faae4620f45232f599d9bc7b290f88247a0834162c4495ab2f02d60004adfb" dependencies = [ "ab_glyph_rasterizer", "owned_ttf_parser", @@ -51,7 +51,7 @@ checksum = "134d0acf6acb667c89d3332999b1a5df4edbc8d6113910f392ebb73f2b03bb56" dependencies = [ "accesskit", "accesskit_consumer", - "objc2", + "objc2 0.3.0-beta.3.patch-leaks.3", "once_cell", ] @@ -63,9 +63,9 @@ checksum = "e084cb5168790c0c112626175412dc5ad127083441a8248ae49ddf6725519e83" dependencies = [ "accesskit", "accesskit_consumer", - "async-channel", + "async-channel 1.9.0", "atspi", - "futures-lite", + "futures-lite 1.13.0", "serde", "zbus", ] @@ -99,9 +99,9 @@ dependencies = [ [[package]] name = "addr2line" -version = "0.19.0" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97" +checksum = "f5fb1d8e4442bd405fdfd1dacb42792696b0cf9cb15882e5d097b742a676d375" dependencies = [ "gimli", ] @@ -112,11 +112,17 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + [[package]] name = "ahash" -version = "0.7.6" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" dependencies = [ "getrandom", "once_cell", @@ -125,9 +131,9 @@ dependencies = [ [[package]] name = "ahash" -version = "0.8.6" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", "getrandom", @@ -139,18 +145,18 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.0.1" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67fc08ce920c31afb70f013dcce1bfc3a3195de6a228474e45e1f145b36f8d04" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] [[package]] name = "allocator-api2" -version = "0.2.16" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" +checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" [[package]] name = "android-activity" @@ -202,99 +208,96 @@ dependencies = [ [[package]] name = "anstream" -version = "0.3.2" +version = "0.6.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163" +checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", - "is-terminal", + "is_terminal_polyfill", "utf8parse", ] [[package]] name = "anstyle" -version = "1.0.0" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41ed9a86bf92ae6580e0a31281f65a1b1d867c0cc68d5346e2ae128dddfa6a7d" +checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" [[package]] name = "anstyle-parse" -version = "0.2.0" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e765fd216e48e067936442276d1d57399e37bce53c264d6fefbe298080cb57ee" +checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.0.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" +checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "anstyle-wincon" -version = "1.0.1" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188" +checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" dependencies = [ "anstyle", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "anyhow" -version = "1.0.71" +version = "1.0.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" +checksum = "4e1496f8fb1fbf272686b8d37f523dab3e4a7443300055e74cdaa449f3114356" [[package]] name = "arboard" -version = "3.2.1" +version = "3.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac57f2b058a76363e357c056e4f74f1945bf734d37b8b3ef49066c4787dde0fc" +checksum = "df099ccb16cd014ff054ac1bf392c67feeef57164b05c42f037cd40f5d4357f4" dependencies = [ "clipboard-win", "log", - "objc", - "objc-foundation", - "objc_id", + "objc2 0.5.2", + "objc2-app-kit", + "objc2-foundation", "parking_lot", - "thiserror", - "winapi 0.3.9", "x11rb", ] [[package]] name = "arrayref" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" +checksum = "9d151e35f61089500b617991b791fc8bfd237ae50cd5950803758a179b41e67a" [[package]] name = "arrayvec" -version = "0.7.2" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] name = "ast_node" -version = "0.9.5" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c09c69dffe06d222d072c878c3afe86eee2179806f20503faec97250268b4c24" +checksum = "f9184f2b369b3e8625712493c89b785881f27eedc6cde480a81883cef78868b2" dependencies = [ - "pmutil 0.6.1", "proc-macro2", "quote", "swc_macros_common", - "syn 2.0.50", + "syn 2.0.77", ] [[package]] @@ -303,7 +306,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c48ccdbf6ca6b121e0f586cbc0e73ae440e56c67c30fa0873b4e110d9c26d2b" dependencies = [ - "event-listener", + "event-listener 2.5.3", "futures-core", ] @@ -314,21 +317,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" dependencies = [ "concurrent-queue", - "event-listener", + "event-listener 2.5.3", + "futures-core", +] + +[[package]] +name = "async-channel" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" +dependencies = [ + "concurrent-queue", + "event-listener-strategy", "futures-core", + "pin-project-lite", ] [[package]] name = "async-executor" -version = "1.5.4" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c1da3ae8dabd9c00f453a329dfe1fb28da3c0a72e2478cdcd93171740c20499" +checksum = "30ca9a001c1e8ba5149f91a74362376cc6bc5b919d92d988668657bd570bdcec" dependencies = [ - "async-lock", "async-task", "concurrent-queue", - "fastrand 2.0.1", - "futures-lite", + "fastrand 2.1.1", + "futures-lite 2.3.0", "slab", ] @@ -338,10 +352,10 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "279cf904654eeebfa37ac9bb1598880884924aab82e290aa65c9e77a0e142e06" dependencies = [ - "async-lock", + "async-lock 2.8.0", "autocfg", "blocking", - "futures-lite", + "futures-lite 1.13.0", ] [[package]] @@ -350,73 +364,120 @@ version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" dependencies = [ - "async-lock", + "async-lock 2.8.0", "autocfg", "cfg-if", "concurrent-queue", - "futures-lite", + "futures-lite 1.13.0", "log", "parking", - "polling", - "rustix 0.37.19", + "polling 2.8.0", + "rustix 0.37.27", "slab", - "socket2", + "socket2 0.4.10", "waker-fn", ] +[[package]] +name = "async-io" +version = "2.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "444b0228950ee6501b3568d3c93bf1176a1fdbc3b758dcd9475046d30f4dc7e8" +dependencies = [ + "async-lock 3.4.0", + "cfg-if", + "concurrent-queue", + "futures-io", + "futures-lite 2.3.0", + "parking", + "polling 3.7.3", + "rustix 0.38.37", + "slab", + "tracing", + "windows-sys 0.59.0", +] + [[package]] name = "async-lock" version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" dependencies = [ - "event-listener", + "event-listener 2.5.3", +] + +[[package]] +name = "async-lock" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" +dependencies = [ + "event-listener 5.3.1", + "event-listener-strategy", + "pin-project-lite", ] [[package]] name = "async-process" -version = "1.7.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a9d28b1d97e08915212e2e45310d47854eafa69600756fc735fb788f75199c9" +checksum = "ea6438ba0a08d81529c69b36700fa2f95837bfe3e776ab39cde9c14d9149da88" dependencies = [ - "async-io", - "async-lock", - "autocfg", + "async-io 1.13.0", + "async-lock 2.8.0", + "async-signal", "blocking", "cfg-if", - "event-listener", - "futures-lite", - "rustix 0.37.19", - "signal-hook", + "event-listener 3.1.0", + "futures-lite 1.13.0", + "rustix 0.38.37", "windows-sys 0.48.0", ] [[package]] name = "async-recursion" -version = "1.0.5" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fd55a5ba1179988837d24ab4c7cc8ed6efdeff578ede0416b4225a5fca35bd0" +checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.77", +] + +[[package]] +name = "async-signal" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "637e00349800c0bdf8bfc21ebbc0b6524abea702b0da4168ac00d070d0c0b9f3" +dependencies = [ + "async-io 2.3.4", + "async-lock 3.4.0", + "atomic-waker", + "cfg-if", + "futures-core", + "futures-io", + "rustix 0.38.37", + "signal-hook-registry", + "slab", + "windows-sys 0.59.0", ] [[package]] name = "async-task" -version = "4.4.1" +version = "4.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9441c6b2fe128a7c2bf680a44c34d0df31ce09e5b7e401fcca3faa483dbc921" +checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" [[package]] name = "async-trait" -version = "0.1.68" +version = "0.1.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" +checksum = "a27b8a3a6e1a44fa4c8baf1f653e4172e81486d4941f2237e20dc2d0cf4ddff1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.77", ] [[package]] @@ -427,9 +488,9 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "atomic_refcell" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76f2bfe491d41d45507b8431da8274f7feeca64a49e86d980eed2937ec2ff020" +checksum = "41e67cd8309bbd06cd603a9e693a784ac2e5d1e955f11286e355089fcab3047c" [[package]] name = "atspi" @@ -441,7 +502,7 @@ dependencies = [ "async-trait", "atspi-macros", "enumflags2", - "futures-lite", + "futures-lite 1.13.0", "serde", "tracing", "zbus", @@ -458,60 +519,36 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi 0.1.19", - "libc", - "winapi 0.3.9", -] - -[[package]] -name = "auto_impl" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7862e21c893d65a1650125d157eaeec691439379a1cee17ee49031b79236ada4" -dependencies = [ - "proc-macro-error", - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "auto_impl" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fee3da8ef1276b0bee5dd1c7258010d8fffd31801447323115a25560e1327b89" +checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" dependencies = [ - "proc-macro-error", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.77", ] [[package]] name = "autocfg" -version = "1.1.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "backtrace" -version = "0.3.67" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ "addr2line", - "cc", "cfg-if", "libc", - "miniz_oxide 0.6.2", + "miniz_oxide 0.8.0", "object", "rustc-demangle", + "windows-targets 0.52.6", ] [[package]] @@ -529,12 +566,27 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + [[package]] name = "base64" version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "base64-simd" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "781dd20c3aff0bd194fe7d2a977dd92f21c173891f3a03b677359e5fa457e5d5" +dependencies = [ + "simd-abstraction", +] + [[package]] name = "better_scoped_tls" version = "0.1.1" @@ -561,9 +613,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.2" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" dependencies = [ "serde", ] @@ -601,7 +653,7 @@ version = "0.1.0-beta.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fa55741ee90902547802152aaf3f8e5248aab7e21468089560d4c8840561146" dependencies = [ - "objc-sys", + "objc-sys 0.2.0-beta.2", ] [[package]] @@ -611,105 +663,89 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8dd9e63c1744f755c2f60332b88de39d341e5e86239014ad839bd71c106dec42" dependencies = [ "block-sys", - "objc2-encode", + "objc2-encode 2.0.0-pre.2", +] + +[[package]] +name = "block2" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f" +dependencies = [ + "objc2 0.5.2", ] [[package]] name = "blocking" -version = "1.4.1" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c36a4d0d48574b3dd360b4b7d95cc651d2b6557b6402848a27d4b228a473e2a" +checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" dependencies = [ - "async-channel", - "async-lock", + "async-channel 2.3.1", "async-task", - "fastrand 2.0.1", "futures-io", - "futures-lite", + "futures-lite 2.3.0", "piper", - "tracing", ] [[package]] name = "browserslist-rs" -version = "0.13.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e33066f72a558361eeb1077b0aff0f1dce1ac75bdc20b38a642f155f767b2824" +checksum = "fdf0ca73de70c3da94e4194e4a01fe732378f55d47cf4c0588caab22a0dbfa14" dependencies = [ - "ahash 0.8.6", - "anyhow", + "ahash 0.8.11", "chrono", "either", + "indexmap 2.5.0", "itertools", "nom", "once_cell", - "quote", "serde", "serde_json", - "string_cache", - "string_cache_codegen", "thiserror", ] [[package]] name = "bumpalo" -version = "3.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" - -[[package]] -name = "bytecheck" -version = "0.6.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b6372023ac861f6e6dc89c8344a8f398fb42aaba2b5dbc649ca0c0e9dbcb627" -dependencies = [ - "bytecheck_derive", - "ptr_meta", - "simdutf8", -] - -[[package]] -name = "bytecheck_derive" -version = "0.6.11" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7ec4c6f261935ad534c0c22dbef2201b45918860eb1c574b972bd213a76af61" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", + "allocator-api2", ] [[package]] name = "bytemuck" -version = "1.14.0" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6" +checksum = "94bbb0ad554ad961ddc5da507a12a29b14e4ae5bda06b19f575a3e6079d2e2ae" dependencies = [ "bytemuck_derive", ] [[package]] name = "bytemuck_derive" -version = "1.5.0" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "965ab7eb5f8f97d2a083c799f3a1b994fc397b2fe2da5d1da1626ce15a39f2b1" +checksum = "0cc8b54b395f2fcfbb3d90c47b01c7f444d94d05bdeb775811dec868ac3bbc26" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.77", ] [[package]] name = "byteorder" -version = "1.4.3" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.4.0" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" [[package]] name = "c_linked_list" @@ -723,10 +759,10 @@ version = "0.46.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7c8c50262271cdf5abc979a5f76515c234e764fa025d1ba4862c0f0bcda0e95" dependencies = [ - "ahash 0.8.6", + "ahash 0.8.11", "cached_proc_macro", "cached_proc_macro_types", - "hashbrown 0.14.3", + "hashbrown 0.14.5", "instant", "once_cell", "thiserror", @@ -738,7 +774,7 @@ version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c878c71c2821aa2058722038a59a67583a4240524687c6028571c9b395ded61f" dependencies = [ - "darling", + "darling 0.14.4", "proc-macro2", "quote", "syn 1.0.109", @@ -746,9 +782,9 @@ dependencies = [ [[package]] name = "cached_proc_macro_types" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a4f925191b4367301851c6d99b09890311d74b0d43f274c0b34c86d308a3663" +checksum = "ade8366b8bd5ba243f0a58f036cc0ca8a2f069cff1a2351ef1cac6b083e16fc0" [[package]] name = "calloop" @@ -766,27 +802,27 @@ dependencies = [ [[package]] name = "camino" -version = "1.1.6" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" +checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" dependencies = [ "serde", ] [[package]] name = "cargo-platform" -version = "0.1.4" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12024c4645c97566567129c204f65d5815a8c9aecf30fcbe682b2fe034996d36" +checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc" dependencies = [ "serde", ] [[package]] name = "cargo_metadata" -version = "0.15.4" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eee4243f1f26fc7a42710e7439c149e2b10b05472f88090acce52632f231a73a" +checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037" dependencies = [ "camino", "cargo-platform", @@ -798,11 +834,13 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.79" +version = "1.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +checksum = "b62ac837cdb5cb22e10a256099b4fc502b1dfe560cb282963a974d7abd80e476" dependencies = [ "jobserver", + "libc", + "shlex", ] [[package]] @@ -848,44 +886,43 @@ dependencies = [ [[package]] name = "clap" -version = "4.3.11" +version = "4.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1640e5cc7fb47dbb8338fd471b105e7ed6c3cb2aeb00c2e067127ffd3764a05d" +checksum = "3e5a21b8495e732f1b3c364c9949b201ca7bae518c502c80256c96ad79eaf6ac" dependencies = [ "clap_builder", "clap_derive", - "once_cell", ] [[package]] name = "clap_builder" -version = "4.3.11" +version = "4.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98c59138d527eeaf9b53f35a77fcc1fad9d883116070c63d5de1c7dc7b00c72b" +checksum = "8cf2dd12af7a047ad9d6da2b6b249759a22a7abc0f474c1dae1777afa4b21a73" dependencies = [ "anstream", "anstyle", "clap_lex", - "strsim", + "strsim 0.11.1", ] [[package]] name = "clap_derive" -version = "4.3.2" +version = "4.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8cd2b2a819ad6eec39e8f1d6b53001af1e5469f8c177579cdaeb313115b825f" +checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0" dependencies = [ - "heck", + "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.77", ] [[package]] name = "clap_lex" -version = "0.5.0" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" +checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" [[package]] name = "clean-path" @@ -895,13 +932,11 @@ checksum = "aaa6b4b263a5d737e9bf6b7c09b72c41a5480aec4d7219af827f6564e950b6a5" [[package]] name = "clipboard-win" -version = "4.5.0" +version = "5.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7191c27c2357d9b7ef96baac1773290d4ca63b24205b82a3fd8a0637afcf0362" +checksum = "15efe7a882b08f34e38556b14f2fb3daa98769d06c7f0c1b076dfd0d983bc892" dependencies = [ "error-code", - "str-buf", - "winapi 0.3.9", ] [[package]] @@ -942,26 +977,25 @@ checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" [[package]] name = "colorchoice" -version = "1.0.0" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" [[package]] name = "colored" -version = "2.0.4" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2674ec482fbc38012cf31e6c42ba0177b431a0cb6f15fe40efa5aab1bda516f6" +checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8" dependencies = [ - "is-terminal", "lazy_static", "windows-sys 0.48.0", ] [[package]] name = "combine" -version = "4.6.6" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" dependencies = [ "bytes", "memchr", @@ -969,18 +1003,18 @@ dependencies = [ [[package]] name = "concurrent-queue" -version = "2.3.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f057a694a54f12365049b0958a1685bb52d567f5593b355fbf685838e873d400" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" dependencies = [ "crossbeam-utils", ] [[package]] name = "config" -version = "0.13.3" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d379af7f68bfc21714c6c7dea883544201741d2ce8274bb12fa54f89507f52a7" +checksum = "23738e11972c7643e4ec947840fc463b6a571afcd3e735bdfce7d03c7a784aca" dependencies = [ "async-trait", "json5", @@ -997,15 +1031,15 @@ dependencies = [ [[package]] name = "console" -version = "0.15.7" +version = "0.15.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c926e00cc70edefdc64d3a5ff31cc65bb97a3460097762bd23afb4d8145fccf8" +checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" dependencies = [ "encode_unicode", "lazy_static", "libc", "unicode-width", - "windows-sys 0.45.0", + "windows-sys 0.52.0", ] [[package]] @@ -1019,9 +1053,9 @@ dependencies = [ [[package]] name = "core-foundation" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" dependencies = [ "core-foundation-sys", "libc", @@ -1029,9 +1063,9 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.4" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "core-graphics" @@ -1048,9 +1082,9 @@ dependencies = [ [[package]] name = "core-graphics-types" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bb142d41022986c1d8ff29103a1411c8a3dfad3552f87a4f8dc50d61d4f4e33" +checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" dependencies = [ "bitflags 1.3.2", "core-foundation", @@ -1059,9 +1093,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.7" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e4c1eaa2012c47becbbad2ab175484c2a84d1185b566fb2cc5b8707343dfe58" +checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" dependencies = [ "libc", ] @@ -1083,55 +1117,46 @@ checksum = "ccaeedb56da03b09f598226e25e80088cb4cd25f316e6e4df7d695f0feeb1403" [[package]] name = "crc32fast" -version = "1.3.2" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" dependencies = [ "cfg-if", ] [[package]] name = "crossbeam-channel" -version = "0.5.8" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" +checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" dependencies = [ - "cfg-if", "crossbeam-utils", ] [[package]] name = "crossbeam-deque" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" dependencies = [ - "cfg-if", "crossbeam-epoch", "crossbeam-utils", ] [[package]] name = "crossbeam-epoch" -version = "0.9.14" +version = "0.9.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" dependencies = [ - "autocfg", - "cfg-if", "crossbeam-utils", - "memoffset 0.8.0", - "scopeguard", ] [[package]] name = "crossbeam-utils" -version = "0.8.15" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" -dependencies = [ - "cfg-if", -] +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "crypto-common" @@ -1145,12 +1170,12 @@ dependencies = [ [[package]] name = "ctor" -version = "0.2.2" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1586fa608b1dab41f667475b4a41faec5ba680aee428bfa5de4ea520fdc6e901" +checksum = "edb49164822f3ee45b17acd4a208cfc1251410cf0cad9a833234c9890774dd9f" dependencies = [ "quote", - "syn 2.0.50", + "syn 2.0.77", ] [[package]] @@ -1165,8 +1190,18 @@ version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" dependencies = [ - "darling_core", - "darling_macro", + "darling_core 0.14.4", + "darling_macro 0.14.4", +] + +[[package]] +name = "darling" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" +dependencies = [ + "darling_core 0.20.10", + "darling_macro 0.20.10", ] [[package]] @@ -1179,21 +1214,46 @@ dependencies = [ "ident_case", "proc-macro2", "quote", - "strsim", + "strsim 0.10.0", "syn 1.0.109", ] +[[package]] +name = "darling_core" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim 0.11.1", + "syn 2.0.77", +] + [[package]] name = "darling_macro" version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" dependencies = [ - "darling_core", + "darling_core 0.14.4", "quote", "syn 1.0.109", ] +[[package]] +name = "darling_macro" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" +dependencies = [ + "darling_core 0.20.10", + "quote", + "syn 2.0.77", +] + [[package]] name = "dashmap" version = "4.0.2" @@ -1211,7 +1271,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" dependencies = [ "cfg-if", - "hashbrown 0.14.3", + "hashbrown 0.14.5", "lock_api", "once_cell", "parking_lot_core", @@ -1219,19 +1279,27 @@ dependencies = [ [[package]] name = "data-encoding" -version = "2.4.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" [[package]] -name = "delegate" -version = "0.12.0" +name = "debugid" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e018fccbeeb50ff26562ece792ed06659b9c2dae79ece77c4456bb10d9bf79b" +checksum = "bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.50", + "serde", + "uuid", +] + +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", ] [[package]] @@ -1245,6 +1313,37 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "derive_builder" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd33f37ee6a119146a1781d3356a7c26028f83d779b2e04ecd45fdc75c76877b" +dependencies = [ + "derive_builder_macro", +] + +[[package]] +name = "derive_builder_core" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7431fa049613920234f22c47fdc33e6cf3ee83067091ea4277a3f8c4587aae38" +dependencies = [ + "darling 0.20.10", + "proc-macro2", + "quote", + "syn 2.0.77", +] + +[[package]] +name = "derive_builder_macro" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4abae7035bf79b9877b779505d8cf3749285b80c43941eda66604841889451dc" +dependencies = [ + "derive_builder_core", + "syn 2.0.77", +] + [[package]] name = "diff" version = "0.1.13" @@ -1279,7 +1378,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" dependencies = [ - "libloading 0.8.1", + "libloading 0.8.5", ] [[package]] @@ -1290,15 +1389,15 @@ checksum = "0688c2a7f92e427f44895cd63841bff7b29f8d7a1648b9e7e07a4a365b2e1257" [[package]] name = "downcast-rs" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" +checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" [[package]] name = "dunce" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" [[package]] name = "ecolor" @@ -1344,7 +1443,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3aef8ec3ae1b772f340170c65bf27d5b8c28f543a0116c844d2ac08d01123e7" dependencies = [ "accesskit", - "ahash 0.8.6", + "ahash 0.8.11", "epaint", "log", "nohash-hasher", @@ -1384,9 +1483,9 @@ dependencies = [ [[package]] name = "either" -version = "1.8.1" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "emath" @@ -1404,54 +1503,34 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" [[package]] -name = "enum-iterator" -version = "1.4.1" +name = "enumflags2" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7add3873b5dd076766ee79c8e406ad1a472c385476b9e38849f8eec24f1be689" +checksum = "d232db7f5956f3f14313dc2f87985c58bd2c695ce124c8cdd984e08e15ac133d" dependencies = [ - "enum-iterator-derive", + "enumflags2_derive", + "serde", ] [[package]] -name = "enum-iterator-derive" -version = "1.2.1" +name = "enumflags2_derive" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eecf8589574ce9b895052fa12d69af7a233f99e6107f5cb8dd1044f2a17bfdcb" +checksum = "de0d48a183585823424a4ce1aa132d174a6a81bd540895822eb4c8373a8e49e8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.77", ] [[package]] -name = "enumflags2" -version = "0.7.8" +name = "epaint" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5998b4f30320c9d93aed72f63af821bfdac50465b75428fce77b48ec482c3939" -dependencies = [ - "enumflags2_derive", - "serde", -] - -[[package]] -name = "enumflags2_derive" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f95e2801cd355d4a1a3e3953ce6ee5ae9603a5c833455343a8bfe3f44d418246" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.50", -] - -[[package]] -name = "epaint" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09333964d4d57f40a85338ba3ca5ed4716070ab184dcfed966b35491c5c64f3b" +checksum = "09333964d4d57f40a85338ba3ca5ed4716070ab184dcfed966b35491c5c64f3b" dependencies = [ "ab_glyph", - "ahash 0.8.6", + "ahash 0.8.11", "atomic_refcell", "bytemuck", "ecolor", @@ -1463,46 +1542,63 @@ dependencies = [ [[package]] name = "equivalent" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88bffebc5d80432c9b140ee17875ff173a8ab62faad5b257da912bd2f6c1c0a1" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.1" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" dependencies = [ - "errno-dragonfly", "libc", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] -name = "errno-dragonfly" -version = "0.1.2" +name = "error-code" +version = "3.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5d9305ccc6942a704f4335694ecd3de2ea531b114ac2d51f5f843750787a92f" + +[[package]] +name = "event-listener" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + +[[package]] +name = "event-listener" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +checksum = "d93877bcde0eb80ca09131a08d23f0a5c18a620b01db137dba666d18cd9b30c2" dependencies = [ - "cc", - "libc", + "concurrent-queue", + "parking", + "pin-project-lite", ] [[package]] -name = "error-code" -version = "2.3.1" +name = "event-listener" +version = "5.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64f18991e7bf11e7ffee451b5318b5c1a73c52d0d0ada6e5a3017c8c1ced6a21" +checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" dependencies = [ - "libc", - "str-buf", + "concurrent-queue", + "parking", + "pin-project-lite", ] [[package]] -name = "event-listener" -version = "2.5.3" +name = "event-listener-strategy" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" +checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" +dependencies = [ + "event-listener 5.3.1", + "pin-project-lite", +] [[package]] name = "fastrand" @@ -1515,15 +1611,15 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.0.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" +checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" [[package]] name = "fdeflate" -version = "0.3.0" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d329bdeac514ee06249dabc27877490f17f5d371ec693360768b838e19f3ae10" +checksum = "4f9bfee30e4dedf0ab8b422f03af778d9612b63f502710fc500a334ebe2de645" dependencies = [ "simd-adler32", ] @@ -1539,14 +1635,14 @@ dependencies = [ [[package]] name = "filetime" -version = "0.2.22" +version = "0.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4029edd3e734da6fe05b6cd7bd2960760a616bd2ddd0d59a0124746d6272af0" +checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.3.5", - "windows-sys 0.48.0", + "libredox 0.1.3", + "windows-sys 0.59.0", ] [[package]] @@ -1557,12 +1653,12 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[package]] name = "flate2" -version = "1.0.27" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6c98ee8095e9d1dcbf2fcc6d95acccb90d1c81db1e44725c6a984b1dbdfb010" +checksum = "324a1be68054ef05ad64b861cc9eaf1d623d2d8cb25b4bf2cb9cdd902b4bf253" dependencies = [ "crc32fast", - "miniz_oxide 0.7.1", + "miniz_oxide 0.8.0", ] [[package]] @@ -1597,14 +1693,13 @@ dependencies = [ [[package]] name = "from_variant" -version = "0.1.6" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03ec5dc38ee19078d84a692b1c41181ff9f94331c76cee66ff0208c770b5e54f" +checksum = "32016f1242eb82af5474752d00fd8ebcd9004bd69b462b1c91de833972d08ed4" dependencies = [ - "pmutil 0.6.1", "proc-macro2", "swc_macros_common", - "syn 2.0.50", + "syn 2.0.77", ] [[package]] @@ -1630,9 +1725,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" dependencies = [ "futures-channel", "futures-core", @@ -1645,9 +1740,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" dependencies = [ "futures-core", "futures-sink", @@ -1655,15 +1750,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" [[package]] name = "futures-executor" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" dependencies = [ "futures-core", "futures-task", @@ -1672,9 +1767,9 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" [[package]] name = "futures-lite" @@ -1691,34 +1786,47 @@ dependencies = [ "waker-fn", ] +[[package]] +name = "futures-lite" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" +dependencies = [ + "fastrand 2.1.1", + "futures-core", + "futures-io", + "parking", + "pin-project-lite", +] + [[package]] name = "futures-macro" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.77", ] [[package]] name = "futures-sink" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" [[package]] name = "futures-task" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" [[package]] name = "futures-util" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" dependencies = [ "futures-channel", "futures-core", @@ -1781,19 +1889,19 @@ dependencies = [ [[package]] name = "gethostname" -version = "0.2.3" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1ebd34e35c46e00bb73e81363248d627782724609fe1b6396f553f68fe3862e" +checksum = "0176e0459c2e4a1fe232f984bca6890e681076abb9934f6cea7c326f3fc47818" dependencies = [ "libc", - "winapi 0.3.9", + "windows-targets 0.48.5", ] [[package]] name = "getrandom" -version = "0.2.10" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", @@ -1802,21 +1910,21 @@ dependencies = [ [[package]] name = "getset" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e45727250e75cc04ff2846a66397da8ef2b3db8e40e0cef4df67950a07621eb9" +checksum = "f636605b743120a8d32ed92fc27b6cde1a769f8f936c065151eb66f88ded513c" dependencies = [ - "proc-macro-error", + "proc-macro-error2", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.77", ] [[package]] name = "gimli" -version = "0.27.2" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4" +checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64" [[package]] name = "gl_generator" @@ -1868,7 +1976,7 @@ dependencies = [ "glutin_glx_sys", "glutin_wgl_sys", "libloading 0.7.4", - "objc2", + "objc2 0.3.0-beta.3.patch-leaks.3", "once_cell", "raw-window-handle", "wayland-sys 0.30.1", @@ -1919,9 +2027,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.19" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d357c7ae988e7d2182f7d7871d0b963962420b0678b0997ce7de72001aeab782" +checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" dependencies = [ "bytes", "fnv", @@ -1929,7 +2037,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap 1.9.3", + "indexmap 2.5.0", "slab", "tokio", "tokio-util", @@ -1942,7 +2050,7 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" dependencies = [ - "ahash 0.7.6", + "ahash 0.7.8", ] [[package]] @@ -1951,16 +2059,16 @@ version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" dependencies = [ - "ahash 0.8.6", + "ahash 0.8.11", ] [[package]] name = "hashbrown" -version = "0.14.3" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ - "ahash 0.8.6", + "ahash 0.8.11", "allocator-api2", ] @@ -1970,7 +2078,7 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af" dependencies = [ - "hashbrown 0.14.3", + "hashbrown 0.14.5", ] [[package]] @@ -1980,28 +2088,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] -name = "hermit-abi" -version = "0.1.19" +name = "heck" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" -version = "0.2.6" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" -dependencies = [ - "libc", -] +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" [[package]] name = "hermit-abi" -version = "0.3.2" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" [[package]] name = "hex" @@ -2011,18 +2113,41 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "home" -version = "0.5.5" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.52.0", +] + +[[package]] +name = "hstr" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dae404c0c5d4e95d4858876ab02eecd6a196bb8caa42050dfa809938833fc412" +dependencies = [ + "hashbrown 0.14.5", + "new_debug_unreachable", + "once_cell", + "phf", + "rustc-hash", + "triomphe", +] + +[[package]] +name = "html-escape" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d1ad449764d627e22bfd7cd5e8868264fc9236e07c752972b4080cd351cb476" +dependencies = [ + "utf8-width", ] [[package]] name = "http" -version = "0.2.9" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" dependencies = [ "bytes", "fnv", @@ -2031,9 +2156,9 @@ dependencies = [ [[package]] name = "http-body" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", "http", @@ -2048,21 +2173,21 @@ checksum = "21dec9db110f5f872ed9699c3ecf50cf16f423502706ba5c72462e28d3157573" [[package]] name = "httparse" -version = "1.8.0" +version = "1.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" +checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" [[package]] name = "httpdate" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" -version = "0.14.27" +version = "0.14.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" +checksum = "a152ddd61dfaec7273fe8419ab357f33aee0d914c5f4efbf0d96fa749eea5ec9" dependencies = [ "bytes", "futures-channel", @@ -2075,7 +2200,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2", + "socket2 0.5.7", "tokio", "tower-service", "tracing", @@ -2116,9 +2241,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.58" +version = "0.1.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -2161,14 +2286,13 @@ checksum = "cb56e1aa765b4b4f3aadfab769793b7087bb03a4ea4920644a6d238e2df5b9ed" [[package]] name = "image" -version = "0.24.7" +version = "0.24.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f3dfdbdd72063086ff443e297b61695500514b1e41095b6fb9a5ab48a70a711" +checksum = "5690139d2f55868e080017335e4b94cb7414274c74f1669c84fb5feba2c9f69d" dependencies = [ "bytemuck", "byteorder", "color_quant", - "num-rational", "num-traits", "png", ] @@ -2181,18 +2305,18 @@ checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", "hashbrown 0.12.3", - "rayon", "serde", ] [[package]] name = "indexmap" -version = "2.2.6" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" dependencies = [ "equivalent", - "hashbrown 0.14.3", + "hashbrown 0.14.5", + "rayon", "serde", ] @@ -2231,23 +2355,22 @@ dependencies = [ [[package]] name = "insta" -version = "1.30.0" +version = "1.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28491f7753051e5704d4d0ae7860d45fae3238d7d235bc4289dcd45c48d3cec3" +checksum = "6593a41c7a73841868772495db7dc1e8ecab43bb5c0b6da2059246c4b506ab60" dependencies = [ "console", "lazy_static", "linked-hash-map", "serde", "similar", - "yaml-rust", ] [[package]] name = "instant" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" dependencies = [ "cfg-if", "js-sys", @@ -2261,7 +2384,7 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ - "hermit-abi 0.3.2", + "hermit-abi 0.3.9", "libc", "windows-sys 0.48.0", ] @@ -2277,40 +2400,25 @@ dependencies = [ [[package]] name = "is-macro" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a7d079e129b77477a49c5c4f1cfe9ce6c2c909ef52520693e8e811a714c7b20" -dependencies = [ - "Inflector", - "pmutil 0.5.3", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "is-macro" -version = "0.3.0" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4467ed1321b310c2625c5aa6c1b1ffc5de4d9e42668cf697a08fb033ee8265e" +checksum = "2069faacbe981460232f880d26bf3c7634e322d49053aa48c27e3ae642f728f1" dependencies = [ "Inflector", - "pmutil 0.6.1", "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.77", ] [[package]] name = "is-terminal" -version = "0.4.7" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" +checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" dependencies = [ - "hermit-abi 0.3.2", - "io-lifetimes", - "rustix 0.37.19", - "windows-sys 0.48.0", + "hermit-abi 0.4.0", + "libc", + "windows-sys 0.52.0", ] [[package]] @@ -2325,24 +2433,30 @@ dependencies = [ [[package]] name = "is_ci" -version = "1.1.1" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7655c9839580ee829dfacba1d1278c2b7883e50a277ff7541299489d6bdfdc45" + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "616cde7c720bb2bb5824a224687d8f77bfd38922027f01d825cd7453be5099fb" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "itertools" -version = "0.10.5" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" dependencies = [ "either", ] [[package]] name = "itoa" -version = "1.0.6" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "itoap" @@ -2374,27 +2488,30 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "jobserver" -version = "0.1.26" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" dependencies = [ "libc", ] [[package]] name = "js-sys" -version = "0.3.63" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f37a4a5928311ac501dee68b3c7613a1037d0edb30c8e5427bd832d55d1b790" +checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" dependencies = [ "wasm-bindgen", ] [[package]] name = "json-strip-comments" -version = "1.0.2" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d129799327c8f80861e467c59b825ba24c277dba6ad0d71a141dc98f9e04ee" +checksum = "b271732a960335e715b6b2ae66a086f115c74eb97360e996d2bd809bfc063bba" +dependencies = [ + "memchr", +] [[package]] name = "json5" @@ -2424,9 +2541,9 @@ checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" [[package]] name = "kqueue" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c8fc60ba15bf51257aa9807a48a61013db043fcf3a78cb0d916e8e396dcad98" +checksum = "7447f1ca1b7b563588a205fe93dea8df60fd981423a768bc1c0ded35ed147d0c" dependencies = [ "kqueue-sys", "libc", @@ -2434,9 +2551,9 @@ dependencies = [ [[package]] name = "kqueue-sys" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8367585489f01bc55dd27404dcf56b95e6da061a256a666ab23be9ba96a2e587" +checksum = "ed9625ffda8729b85e45cf04090035ac368927b8cebc34898e7c120f52e4838b" dependencies = [ "bitflags 1.3.2", "libc", @@ -2444,9 +2561,9 @@ dependencies = [ [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "lexical" @@ -2523,9 +2640,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.146" +version = "0.2.158" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b" +checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" [[package]] name = "libloading" @@ -2539,12 +2656,34 @@ dependencies = [ [[package]] name = "libloading" -version = "0.8.1" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c571b676ddfc9a8c12f1f3d3085a7b163966a8fd8098a90640953ce5f6170161" +checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" dependencies = [ "cfg-if", - "windows-sys 0.48.0", + "windows-targets 0.52.6", +] + +[[package]] +name = "libredox" +version = "0.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3af92c55d7d839293953fcd0fda5ecfe93297cfde6ffbdec13b41d99c0ba6607" +dependencies = [ + "bitflags 2.6.0", + "libc", + "redox_syscall 0.4.1", +] + +[[package]] +name = "libredox" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +dependencies = [ + "bitflags 2.6.0", + "libc", + "redox_syscall 0.5.4", ] [[package]] @@ -2567,21 +2706,21 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ece97ea872ece730aed82664c424eb4c8291e1ff2480247ccf7409044bc6479f" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" [[package]] name = "linux-raw-sys" -version = "0.4.10" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "lock_api" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ "autocfg", "scopeguard", @@ -2589,9 +2728,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.18" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "518ef76f2f87365916b142844c16d8fefd85039bc5699050210a7778ee1cd1de" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "lru" @@ -2614,7 +2753,7 @@ version = "0.1.0" dependencies = [ "anyhow", "base64 0.22.1", - "bitflags 2.4.2", + "bitflags 2.6.0", "cached", "chrono", "clap", @@ -2622,7 +2761,6 @@ dependencies = [ "config", "convert_case", "dashmap 4.0.2", - "delegate", "eframe", "fixedbitset", "fs_extra", @@ -2631,11 +2769,11 @@ dependencies = [ "glob", "glob-match", "hashlink", - "heck", + "heck 0.4.1", "hyper", "hyper-staticfile", "hyper-tungstenite", - "indexmap 2.2.6", + "indexmap 2.5.0", "indicatif", "insta", "maplit", @@ -2665,15 +2803,15 @@ dependencies = [ "serde_json", "serde_yaml", "svgr-rs", - "swc_core 0.83.22", + "swc_core 0.101.7", "swc_emotion", - "swc_error_reporters", + "swc_error_reporters 0.21.0", "swc_node_comments", "thiserror", "tikv-jemallocator", "tokio", "tokio-tungstenite", - "toml 0.7.6", + "toml 0.7.8", "tracing", "tracing-subscriber", "tungstenite", @@ -2715,9 +2853,9 @@ checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" [[package]] name = "markdown" -version = "1.0.0-alpha.11" +version = "1.0.0-alpha.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f557389e7cdb1e3574c43d82965f0d933fff789c6ea2779cb0e9e72ec4b1224e" +checksum = "911a8325e6fb87b89890cd4529a2ab34c2669c026279e61c26b7140a3d821ccb" dependencies = [ "unicode-id", ] @@ -2739,19 +2877,19 @@ checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" [[package]] name = "mdxjs" -version = "0.1.14" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "334329b79f2a86b4e432a4f9911df72e4b7dff1164dfa3027bc7f91d60391d8f" +checksum = "ec5cf50756dfb3eaf8f72979c94a3c2e281f3ba6e35280fa4b73eaac2cd23b6f" dependencies = [ "markdown", - "swc_core 0.79.71", + "swc_core 0.103.2", ] [[package]] name = "memchr" -version = "2.6.3" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memmap2" @@ -2782,74 +2920,68 @@ dependencies = [ [[package]] name = "memoffset" -version = "0.8.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" dependencies = [ "autocfg", ] [[package]] name = "miette" -version = "4.7.1" +version = "5.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c90329e44f9208b55f45711f9558cec15d7ef8295cc65ecd6d4188ae8edc58c" +checksum = "59bb584eaeeab6bd0226ccf3509a69d7936d148cf3d036ad350abe35e8c6856e" dependencies = [ - "atty", "backtrace", - "miette-derive 4.7.1", + "backtrace-ext", + "is-terminal", + "miette-derive 5.10.0", "once_cell", - "owo-colors", - "supports-color 1.3.1", - "supports-hyperlinks 1.2.0", - "supports-unicode 1.0.2", + "owo-colors 3.5.0", + "supports-color", + "supports-hyperlinks", + "supports-unicode", "terminal_size", - "textwrap", + "textwrap 0.15.2", "thiserror", "unicode-width", ] [[package]] name = "miette" -version = "5.10.0" +version = "7.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59bb584eaeeab6bd0226ccf3509a69d7936d148cf3d036ad350abe35e8c6856e" +checksum = "4edc8853320c2a0dab800fbda86253c8938f6ea88510dc92c5f1ed20e794afc1" dependencies = [ - "backtrace", - "backtrace-ext", - "is-terminal", - "miette-derive 5.10.0", - "once_cell", - "owo-colors", - "supports-color 2.1.0", - "supports-hyperlinks 2.1.0", - "supports-unicode 2.0.0", - "terminal_size", - "textwrap", + "cfg-if", + "miette-derive 7.2.0", + "owo-colors 4.1.0", + "textwrap 0.16.1", "thiserror", "unicode-width", ] [[package]] name = "miette-derive" -version = "4.7.1" +version = "5.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b5bc45b761bcf1b5e6e6c4128cd93b84c218721a8d9b894aa0aff4ed180174c" +checksum = "49e7bc1560b95a3c4a25d03de42fe76ca718ab92d1a22a55b9b4cf67b3ae635c" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.77", ] [[package]] name = "miette-derive" -version = "5.10.0" +version = "7.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49e7bc1560b95a3c4a25d03de42fe76ca718ab92d1a22a55b9b4cf67b3ae635c" +checksum = "dcf09caffaac8068c346b6df2a7fc27a177fd20b39421a39ce0a211bde679a6c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.77", ] [[package]] @@ -2880,9 +3012,9 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "mime_guess" -version = "2.0.4" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" dependencies = [ "mime", "unicase", @@ -2896,28 +3028,28 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.6.2" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" dependencies = [ "adler", + "simd-adler32", ] [[package]] name = "miniz_oxide" -version = "0.7.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" dependencies = [ - "adler", - "simd-adler32", + "adler2", ] [[package]] name = "mio" -version = "0.8.8" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", "log", @@ -2925,6 +3057,18 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "mio" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" +dependencies = [ + "hermit-abi 0.3.9", + "libc", + "wasi", + "windows-sys 0.52.0", +] + [[package]] name = "nanoid" version = "0.4.0" @@ -2940,7 +3084,7 @@ version = "2.16.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53575dfa17f208dd1ce3a2da2da4659aae393b256a472f2738a8586a6c4107fd" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.6.0", "ctor", "napi-derive", "napi-sys", @@ -2952,9 +3096,9 @@ dependencies = [ [[package]] name = "napi-build" -version = "2.0.1" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "882a73d9ef23e8dc2ebbffb6a6ae2ef467c0f18ac10711e4cc59c5485d41df0e" +checksum = "e1c0f5d67ee408a4685b61f5ab7e58605c8ae3f2b4189f0127d804ff13d5560a" [[package]] name = "napi-derive" @@ -2967,7 +3111,7 @@ dependencies = [ "napi-derive-backend", "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.77", ] [[package]] @@ -2982,7 +3126,7 @@ dependencies = [ "quote", "regex", "semver 1.0.23", - "syn 2.0.50", + "syn 2.0.77", ] [[package]] @@ -2991,7 +3135,7 @@ version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "427802e8ec3a734331fec1035594a210ce1ff4dc5bc1950530920ab717964ea3" dependencies = [ - "libloading 0.8.1", + "libloading 0.8.5", ] [[package]] @@ -3031,9 +3175,9 @@ dependencies = [ [[package]] name = "new_debug_unreachable" -version = "1.0.4" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" [[package]] name = "nix" @@ -3103,7 +3247,7 @@ version = "6.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6205bd8bb1e454ad2e27422015fb5e4f2bcc7e08fa8f27058670d208324a4d2d" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.6.0", "crossbeam-channel", "filetime", "fsevent-sys", @@ -3111,7 +3255,7 @@ dependencies = [ "kqueue", "libc", "log", - "mio", + "mio 0.8.11", "walkdir", "windows-sys 0.48.0", ] @@ -3141,53 +3285,46 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.4.3" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ - "autocfg", "num-integer", "num-traits", "serde", ] [[package]] -name = "num-integer" -version = "0.1.45" +name = "num-conv" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" -dependencies = [ - "autocfg", - "num-traits", -] +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" [[package]] -name = "num-rational" -version = "0.4.1" +name = "num-integer" +version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" dependencies = [ - "autocfg", - "num-integer", "num-traits", ] [[package]] name = "num-traits" -version = "0.2.15" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] [[package]] name = "num_cpus" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.2.6", + "hermit-abi 0.3.9", "libc", ] @@ -3230,7 +3367,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.77", ] [[package]] @@ -3249,21 +3386,16 @@ dependencies = [ ] [[package]] -name = "objc-foundation" -version = "0.1.1" +name = "objc-sys" +version = "0.2.0-beta.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9" -dependencies = [ - "block", - "objc", - "objc_id", -] +checksum = "df3b9834c1e95694a05a828b59f55fa2afec6288359cda67146126b3f90a55d7" [[package]] name = "objc-sys" -version = "0.2.0-beta.2" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b9834c1e95694a05a828b59f55fa2afec6288359cda67146126b3f90a55d7" +checksum = "cdb91bdd390c7ce1a8607f35f3ca7151b65afc0ff5ff3b34fa350f7d7c7e4310" [[package]] name = "objc2" @@ -3271,43 +3403,127 @@ version = "0.3.0-beta.3.patch-leaks.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e01640f9f2cb1220bbe80325e179e532cb3379ebcd1bf2279d703c19fe3a468" dependencies = [ - "block2", - "objc-sys", - "objc2-encode", + "block2 0.2.0-alpha.6", + "objc-sys 0.2.0-beta.2", + "objc2-encode 2.0.0-pre.2", ] [[package]] -name = "objc2-encode" -version = "2.0.0-pre.2" +name = "objc2" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abfcac41015b00a120608fdaa6938c44cb983fee294351cc4bac7638b4e50512" +checksum = "46a785d4eeff09c14c487497c162e92766fbb3e4059a71840cecc03d9a50b804" dependencies = [ - "objc-sys", + "objc-sys 0.3.5", + "objc2-encode 4.0.3", ] [[package]] -name = "objc_id" -version = "0.1.1" +name = "objc2-app-kit" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b" +checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" dependencies = [ - "objc", + "bitflags 2.6.0", + "block2 0.5.1", + "libc", + "objc2 0.5.2", + "objc2-core-data", + "objc2-core-image", + "objc2-foundation", + "objc2-quartz-core", +] + +[[package]] +name = "objc2-core-data" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" +dependencies = [ + "bitflags 2.6.0", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-image" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55260963a527c99f1819c4f8e3b47fe04f9650694ef348ffd2227e8196d34c80" +dependencies = [ + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation", + "objc2-metal", +] + +[[package]] +name = "objc2-encode" +version = "2.0.0-pre.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abfcac41015b00a120608fdaa6938c44cb983fee294351cc4bac7638b4e50512" +dependencies = [ + "objc-sys 0.2.0-beta.2", +] + +[[package]] +name = "objc2-encode" +version = "4.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7891e71393cd1f227313c9379a26a584ff3d7e6e7159e988851f0934c993f0f8" + +[[package]] +name = "objc2-foundation" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" +dependencies = [ + "bitflags 2.6.0", + "block2 0.5.1", + "libc", + "objc2 0.5.2", +] + +[[package]] +name = "objc2-metal" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" +dependencies = [ + "bitflags 2.6.0", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation", +] + +[[package]] +name = "objc2-quartz-core" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" +dependencies = [ + "bitflags 2.6.0", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation", + "objc2-metal", ] [[package]] name = "object" -version = "0.30.4" +version = "0.36.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03b4680b86d9cfafba8fc491dc9b6df26b68cf40e9e6cd73909194759a63c385" +checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.19.0" +version = "1.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "33ea5043e58958ee56f3e15a90aee535795cd7dfd319846288d93c5b57d85cbe" [[package]] name = "oneshot" @@ -3317,9 +3533,9 @@ checksum = "e296cf87e61c9cfc1a61c3c63a0f7f286ed4554e0e22be84e8a38e1d264a2a29" [[package]] name = "open" -version = "5.1.4" +version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5ca541f22b1c46d4bb9801014f234758ab4297e7870b904b6a8415b980a7388" +checksum = "61a877bf6abd716642a53ef1b89fb498923a4afca5c754f9050b4d081c05c4b3" dependencies = [ "is-wsl", "libc", @@ -3328,11 +3544,11 @@ dependencies = [ [[package]] name = "orbclient" -version = "0.3.46" +version = "0.3.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8378ac0dfbd4e7895f2d2c1f1345cab3836910baf3a300b000d04250f0c8428f" +checksum = "52f0d54bde9774d3a51dcf281a5def240c71996bc6ca05d2c847ec8b2b216166" dependencies = [ - "redox_syscall 0.3.5", + "libredox 0.0.2", ] [[package]] @@ -3355,6 +3571,12 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "outref" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f222829ae9293e33a9f5e9f440c6760a3d450a64affe1846486b140db81c1f4" + [[package]] name = "overload" version = "0.1.1" @@ -3363,9 +3585,9 @@ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] name = "owned_ttf_parser" -version = "0.19.0" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "706de7e2214113d63a8238d1910463cfce781129a6f263d13fdb09ff64355ba4" +checksum = "490d3a563d3122bf7c911a59b0add9389e5ec0f5f0c3ac6b91ff235a0e6a7f90" dependencies = [ "ttf-parser", ] @@ -3376,6 +3598,12 @@ version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" +[[package]] +name = "owo-colors" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb37767f6569cd834a413442455e0f066d0d522de8630436e2a1761d9726ba56" + [[package]] name = "oxc_resolver" version = "1.7.0" @@ -3396,15 +3624,15 @@ dependencies = [ [[package]] name = "parking" -version = "2.1.1" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e52c774a4c39359c1d1c52e43f73dd91a75a614652c825408eec30c95a9b2067" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "parking_lot" -version = "0.12.1" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", "parking_lot_core", @@ -3412,22 +3640,22 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.9" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.4.1", + "redox_syscall 0.5.4", "smallvec", - "windows-targets 0.48.0", + "windows-targets 0.52.6", ] [[package]] name = "paste" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "path-clean" @@ -3455,9 +3683,9 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" -version = "2.7.4" +version = "2.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c022f1e7b65d6a24c0dbbd5fb344c66881bc01f3e5ae74a1c8100f2f985d98a4" +checksum = "9c73c26c01b8c87956cea613c907c9d6ecffd8d18a2a5908e5de0adfaa185cea" dependencies = [ "memchr", "thiserror", @@ -3466,9 +3694,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.7.4" +version = "2.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35513f630d46400a977c4cb58f78e1bfbe01434316e60c37d27b9ad6139c66d8" +checksum = "664d22978e2815783adbdd2c588b455b1bd625299ce36b2a99881ac9627e6d8d" dependencies = [ "pest", "pest_generator", @@ -3476,22 +3704,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.4" +version = "2.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc9fc1b9e7057baba189b5c626e2d6f40681ae5b6eb064dc7c7834101ec8123a" +checksum = "a2d5487022d5d33f4c30d91c22afa240ce2a644e87fe08caad974d4eab6badbe" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.77", ] [[package]] name = "pest_meta" -version = "2.7.4" +version = "2.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1df74e9e7ec4053ceb980e7c0c8bd3594e977fde1af91daba9c928e8e8c6708d" +checksum = "0091754bbd0ea592c4deb3a122ce8ecbb0753b738aa82bc055fcc2eccc8d8174" dependencies = [ "once_cell", "pest", @@ -3500,30 +3728,29 @@ dependencies = [ [[package]] name = "petgraph" -version = "0.6.3" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dd7d28ee937e54fe3080c91faa1c3a46c06de6252988a7f4592ba2310ef22a4" +checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset", - "indexmap 1.9.3", + "indexmap 2.5.0", ] [[package]] name = "phf" -version = "0.10.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" +checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" dependencies = [ "phf_macros", "phf_shared", - "proc-macro-hack", ] [[package]] name = "phf_generator" -version = "0.10.0" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" +checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" dependencies = [ "phf_shared", "rand", @@ -3531,52 +3758,51 @@ dependencies = [ [[package]] name = "phf_macros" -version = "0.10.0" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58fdf3184dd560f160dd73922bea2d5cd6e8f064bf4b13110abd81b03697b4e0" +checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" dependencies = [ "phf_generator", "phf_shared", - "proc-macro-hack", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.77", ] [[package]] name = "phf_shared" -version = "0.10.0" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" +checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" dependencies = [ "siphasher", ] [[package]] name = "pin-project" -version = "1.1.0" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c95a7476719eab1e366eaf73d0260af3021184f18177925b07f54b30089ceead" +checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.0" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39407670928234ebc5e6e580247dd567ad73a3578460c5990f9503df207e8f07" +checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.77", ] [[package]] name = "pin-project-lite" -version = "0.2.9" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" [[package]] name = "pin-utils" @@ -3586,54 +3812,32 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "piper" -version = "0.2.1" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "668d31b1c4eba19242f2088b2bf3316b82ca31082a8335764db4e083db7485d4" +checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" dependencies = [ "atomic-waker", - "fastrand 2.0.1", + "fastrand 2.1.1", "futures-io", ] [[package]] name = "pkg-config" -version = "0.3.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" - -[[package]] -name = "pmutil" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3894e5d549cccbe44afecf72922f277f603cd4bb0219c8342631ef18fffbe004" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "pmutil" -version = "0.6.1" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52a40bc70c2c58040d2d8b167ba9a5ff59fc9dab7ad44771cfde3dcfde7a09c6" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.50", -] +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" [[package]] name = "png" -version = "0.17.10" +version = "0.17.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd75bf2d8dd3702b9707cdbc56a5b9ef42cec752eb8b3bafc01234558442aa64" +checksum = "06e4b0d3d1312775e782c86c91a111aa1f910cbb65e1337f9975b5f9a554b5e1" dependencies = [ "bitflags 1.3.2", "crc32fast", "fdeflate", "flate2", - "miniz_oxide 0.7.1", + "miniz_oxide 0.7.4", ] [[package]] @@ -3652,6 +3856,21 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "polling" +version = "3.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc2790cd301dec6cd3b7a025e4815cf825724a51c98dccfe6a3e55f05ffb6511" +dependencies = [ + "cfg-if", + "concurrent-queue", + "hermit-abi 0.4.0", + "pin-project-lite", + "rustix 0.38.37", + "tracing", + "windows-sys 0.59.0", +] + [[package]] name = "portable-atomic" version = "1.7.0" @@ -3659,24 +3878,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da544ee218f0d287a911e9c99a39a8c9bc8fcad3cb8db5959940044ecfc67265" [[package]] -name = "ppv-lite86" -version = "0.2.17" +name = "powerfmt" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] -name = "precomputed-hash" -version = "0.1.1" +name = "ppv-lite86" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] [[package]] name = "preset_env_base" -version = "0.4.8" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "008ae5e91d877e168b73c17bed2e4dc7553cd7cc237a776d9479eab6642352c5" +checksum = "1b30eab18be480c194938e433e269d5298a279f6410f02fbc73f3576a325c110" dependencies = [ - "ahash 0.8.6", + "ahash 0.8.11", "anyhow", "browserslist-rs", "dashmap 5.5.3", @@ -3705,53 +3927,45 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" dependencies = [ "once_cell", - "toml_edit 0.19.12", + "toml_edit 0.19.15", ] [[package]] -name = "proc-macro-error" -version = "1.0.4" +name = "proc-macro-error-attr2" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" dependencies = [ - "proc-macro-error-attr", "proc-macro2", "quote", - "syn 1.0.109", - "version_check", ] [[package]] -name = "proc-macro-error-attr" -version = "1.0.4" +name = "proc-macro-error2" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" dependencies = [ + "proc-macro-error-attr2", "proc-macro2", "quote", - "version_check", + "syn 2.0.77", ] -[[package]] -name = "proc-macro-hack" -version = "0.5.20+deprecated" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" - [[package]] name = "proc-macro2" -version = "1.0.78" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] [[package]] name = "psm" -version = "0.1.21" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5787f7cda34e3033a72192c018bc5883100330f362ef279a8cbccfce8bb4e874" +checksum = "aa37f80ca58604976033fae9515a8a2989fc13797d953f7c04fb8fa36a11f205" dependencies = [ "cc", ] @@ -3811,9 +4025,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.35" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] @@ -3904,16 +4118,25 @@ dependencies = [ "bitflags 1.3.2", ] +[[package]] +name = "redox_syscall" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0884ad60e090bf1345b93da0a5de8923c93884cd03f40dfcfddd3b4bee661853" +dependencies = [ + "bitflags 2.6.0", +] + [[package]] name = "regex" -version = "1.9.3" +version = "1.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81bc1d4caf89fac26a70747fe603c130093b53c773888797a6329091246d651a" +checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.3.6", - "regex-syntax 0.7.4", + "regex-automata 0.4.7", + "regex-syntax 0.8.4", ] [[package]] @@ -3927,13 +4150,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed1ceff11a1dddaee50c9dc8e4938bd106e9d89ae372f192311e7da498e3b69" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.7.4", + "regex-syntax 0.8.4", ] [[package]] @@ -3944,52 +4167,15 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.7.4" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "relative-path" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bf2521270932c3c7bed1a59151222bd7643c79310f2916f01925e1e16255698" - -[[package]] -name = "rend" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2571463863a6bd50c32f94402933f03457a3fbaf697a707c5be741e459f08fd" -dependencies = [ - "bytecheck", -] - -[[package]] -name = "rkyv" -version = "0.7.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0200c8230b013893c0b2d6213d6ec64ed2b9be2e0e016682b7224ff82cff5c58" -dependencies = [ - "bitvec", - "bytecheck", - "hashbrown 0.12.3", - "ptr_meta", - "rend", - "rkyv_derive", - "seahash", - "tinyvec", - "uuid", -] - -[[package]] -name = "rkyv_derive" -version = "0.7.42" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2e06b915b5c230a17d7a736d1e2e63ee753c256a8614ef3f5147b13a4f5541d" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] +checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2" [[package]] name = "ron" @@ -4014,9 +4200,9 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustc-hash" @@ -4035,48 +4221,48 @@ dependencies = [ [[package]] name = "rustix" -version = "0.37.19" +version = "0.37.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d" +checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2" dependencies = [ "bitflags 1.3.2", "errno", "io-lifetimes", "libc", - "linux-raw-sys 0.3.7", + "linux-raw-sys 0.3.8", "windows-sys 0.48.0", ] [[package]] name = "rustix" -version = "0.38.3" +version = "0.38.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac5ffa1efe7548069688cd7028f32591853cd7b5b756d41bcffd2353e4fc75b4" +checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.6.0", "errno", "libc", - "linux-raw-sys 0.4.10", - "windows-sys 0.48.0", + "linux-raw-sys 0.4.14", + "windows-sys 0.52.0", ] [[package]] name = "rustversion" -version = "1.0.12" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" [[package]] name = "ryu" -version = "1.0.13" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "ryu-js" -version = "0.2.2" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6518fc26bced4d53678a22d6e423e9d8716377def84545fe328236e3af070e7f" +checksum = "ad97d4ce1560a5e27cec89519dc8300d1aa6035b099821261c651486a19e44d5" [[package]] name = "sailfish" @@ -4102,8 +4288,8 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.50", - "toml 0.8.2", + "syn 2.0.77", + "toml 0.8.19", ] [[package]] @@ -4133,9 +4319,9 @@ checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" [[package]] name = "scopeguard" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "sctk-adwaita" @@ -4150,12 +4336,6 @@ dependencies = [ "tiny-skia", ] -[[package]] -name = "seahash" -version = "4.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" - [[package]] name = "semver" version = "0.9.0" @@ -4182,9 +4362,9 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.203" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" dependencies = [ "serde_derive", ] @@ -4203,76 +4383,66 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.203" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.77", ] [[package]] name = "serde_json" -version = "1.0.117" +version = "1.0.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" +checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" dependencies = [ - "indexmap 2.2.6", + "indexmap 2.5.0", "itoa", + "memchr", "ryu", "serde", ] [[package]] name = "serde_repr" -version = "0.1.16" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8725e1dfadb3a50f7e5ce0b1a540466f6ed3fe7a0fca2ac2b8b831d31316bd00" +checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.77", ] [[package]] name = "serde_spanned" -version = "0.6.3" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186" +checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" dependencies = [ "serde", ] [[package]] name = "serde_yaml" -version = "0.9.22" +version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "452e67b9c20c37fa79df53201dc03839651086ed9bbe92b3ca585ca9fdaa7d85" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ - "indexmap 2.2.6", + "indexmap 2.5.0", "itoa", "ryu", "serde", "unsafe-libyaml", ] -[[package]] -name = "sha-1" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - [[package]] name = "sha1" -version = "0.10.5" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", "cpufeatures", @@ -4292,30 +4462,35 @@ dependencies = [ [[package]] name = "sharded-slab" -version = "0.1.4" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" dependencies = [ "lazy_static", ] [[package]] -name = "signal-hook" -version = "0.3.17" +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook-registry" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" dependencies = [ "libc", - "signal-hook-registry", ] [[package]] -name = "signal-hook-registry" -version = "1.4.1" +name = "simd-abstraction" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +checksum = "9cadb29c57caadc51ff8346233b5cec1d240b68ce55cf1afc764818791876987" dependencies = [ - "libc", + "outref", ] [[package]] @@ -4324,47 +4499,41 @@ version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" -[[package]] -name = "simdutf8" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a" - [[package]] name = "similar" -version = "2.2.1" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "420acb44afdae038210c99e69aae24109f32f15500aa708e81d46c9f29d55fcf" +checksum = "1de1d4f81173b03af4c0cbed3c898f6bff5b870e4a7f5d6f4057d62a7a4b686e" [[package]] name = "siphasher" -version = "0.3.10" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" [[package]] name = "slab" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ "autocfg", ] [[package]] name = "slotmap" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1e08e261d0e8f5c43123b7adf3e4ca1690d655377ac93a03b2c9d3e98de1342" +checksum = "dbff4acf519f630b3a3ddcfaea6c06b42174d9a44bc70c620e9ed1649d58b82a" dependencies = [ "version_check", ] [[package]] name = "smallvec" -version = "1.11.1" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "smartstring" @@ -4379,9 +4548,9 @@ dependencies = [ [[package]] name = "smawk" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f67ad224767faa3c7d8b6d91985b78e70a1324408abcb1cfcc2be4c06bc06043" +checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" [[package]] name = "smithay-client-toolkit" @@ -4414,34 +4583,48 @@ dependencies = [ [[package]] name = "socket2" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" +checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" dependencies = [ "libc", "winapi 0.3.9", ] +[[package]] +name = "socket2" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + [[package]] name = "sourcemap" -version = "6.2.3" +version = "9.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eed16231c92d0a6f0388f56e0ab2be24ecff1173f8e22f0ea5e074d0525631cb" +checksum = "dab08a862c70980b8e23698b507e272317ae52a608a164a844111f5372374f1f" dependencies = [ + "base64-simd", + "bitvec", "data-encoding", + "debugid", "if_chain", + "rustc-hash", "rustc_version", "serde", "serde_json", - "unicode-id", + "unicode-id-start", "url", ] [[package]] name = "st-map" -version = "0.2.0" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f352d5d14be5a1f956d76ae0c8060c3487aaa2a080f10a4b4ff023c7c05a9047" +checksum = "8257dd592de7614be71a2342d36ba2d527ddad3f9a0c8d09d6ceed4c371531e4" dependencies = [ "arrayvec", "static-map-macro", @@ -4455,27 +4638,26 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "stacker" -version = "0.1.15" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c886bd4480155fd3ef527d45e9ac8dd7118a898a46530b7b94c3e21866259fce" +checksum = "799c883d55abdb5e98af1a7b3f23b9b6de8ecada0ecac058672d7635eb48ca7b" dependencies = [ "cc", "cfg-if", "libc", "psm", - "winapi 0.3.9", + "windows-sys 0.59.0", ] [[package]] name = "static-map-macro" -version = "0.3.0" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7628ae0bd92555d3de4303da41a5c8b1c5363e892001325f34e4be9ed024d0d7" +checksum = "710e9696ef338691287aeb937ee6ffe60022f579d3c8d2fd9d58973a9a10a466" dependencies = [ - "pmutil 0.6.1", "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.77", ] [[package]] @@ -4484,12 +4666,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" -[[package]] -name = "str-buf" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e08d8363704e6c71fc928674353e6b7c23dcea9d82d7012c8faf2a3a025f8d0" - [[package]] name = "strict-num" version = "0.1.1" @@ -4497,42 +4673,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" [[package]] -name = "string_cache" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" -dependencies = [ - "new_debug_unreachable", - "once_cell", - "parking_lot", - "phf_shared", - "precomputed-hash", - "serde", -] - -[[package]] -name = "string_cache_codegen" -version = "0.5.2" +name = "string_enum" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bb30289b722be4ff74a408c3cc27edeaad656e06cb1fe8fa9231fa59c728988" +checksum = "05e383308aebc257e7d7920224fa055c632478d92744eca77f99be8fa1545b90" dependencies = [ - "phf_generator", - "phf_shared", "proc-macro2", "quote", -] - -[[package]] -name = "string_enum" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fa4d4f81d7c05b9161f8de839975d3326328b8ba2831164b465524cc2f55252" -dependencies = [ - "pmutil 0.6.1", - "proc-macro2", - "quote", - "swc_macros_common", - "syn 2.0.50", + "swc_macros_common", + "syn 2.0.77", ] [[package]] @@ -4542,14 +4691,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] -name = "supports-color" -version = "1.3.1" +name = "strsim" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ba6faf2ca7ee42fdd458f4347ae0a9bd6bcc445ad7cb57ad82b383f18870d6f" -dependencies = [ - "atty", - "is_ci", -] +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "supports-color" @@ -4561,15 +4706,6 @@ dependencies = [ "is_ci", ] -[[package]] -name = "supports-hyperlinks" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "590b34f7c5f01ecc9d78dba4b3f445f31df750a67621cf31626f3b7441ce6406" -dependencies = [ - "atty", -] - [[package]] name = "supports-hyperlinks" version = "2.1.0" @@ -4581,18 +4717,9 @@ dependencies = [ [[package]] name = "supports-unicode" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8b945e45b417b125a8ec51f1b7df2f8df7920367700d1f98aedd21e5735f8b2" -dependencies = [ - "atty", -] - -[[package]] -name = "supports-unicode" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b6c2cb240ab5dd21ed4906895ee23fe5a48acdbd15a3ce388e7b62a9b66baf7" +checksum = "f850c19edd184a205e883199a261ed44471c81e39bd95b1357f5febbef00e77a" dependencies = [ "is-terminal", ] @@ -4600,29 +4727,32 @@ dependencies = [ [[package]] name = "svgr-rs" version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a959be330ea7bc8f5722868a53e625962ae70842ade80427bda9a0810ff50a80" dependencies = [ "clap", + "html-escape", "linked-hash-map", "linked_hash_set", + "napi", + "napi-derive", "regex", "serde", - "swc_core 0.74.6", + "swc_core 0.101.7", "swc_xml", + "testing", + "thiserror", ] [[package]] name = "swc" -version = "0.266.28" +version = "0.284.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49be68a31f62828304f0325a324bbf47cf128c954a49f4e3730eba29b01b6376" +checksum = "833bb7f4073f08aec7144619a2cf682413b7a0cc8f21b7e76abd2fd02373685d" dependencies = [ "anyhow", - "base64 0.13.1", + "base64 0.21.7", "dashmap 5.5.3", "either", - "indexmap 1.9.3", + "indexmap 2.5.0", "jsonc-parser", "lru", "once_cell", @@ -4633,100 +4763,97 @@ dependencies = [ "serde", "serde_json", "sourcemap", - "swc_atoms 0.5.9", + "swc_atoms", "swc_cached", - "swc_common 0.32.1", + "swc_common 0.37.5", + "swc_compiler_base", "swc_config", - "swc_ecma_ast 0.109.1", - "swc_ecma_codegen 0.145.5", + "swc_ecma_ast", + "swc_ecma_codegen", "swc_ecma_ext_transforms", "swc_ecma_lints", - "swc_ecma_loader 0.44.4", + "swc_ecma_loader", "swc_ecma_minifier", - "swc_ecma_parser 0.140.0", + "swc_ecma_parser", "swc_ecma_preset_env", "swc_ecma_transforms", - "swc_ecma_transforms_base 0.133.5", + "swc_ecma_transforms_base 0.144.0", "swc_ecma_transforms_compat", - "swc_ecma_transforms_optimization 0.193.23", - "swc_ecma_utils 0.123.0", - "swc_ecma_visit 0.95.1", - "swc_error_reporters", + "swc_ecma_transforms_optimization", + "swc_ecma_utils", + "swc_ecma_visit", + "swc_error_reporters 0.21.0", "swc_node_comments", "swc_timer", + "swc_transform_common", + "swc_typescript", "swc_visit", "tracing", "url", ] [[package]] -name = "swc_atoms" -version = "0.4.43" +name = "swc_allocator" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64593af3e0fbacd1b7147a0188f1fd77a2fc8ae3c2425bdb9528de255b9f452b" +checksum = "adc8bd3075d1c6964010333fae9ddcd91ad422a4f8eb8b3206a9b2b6afb4209e" dependencies = [ - "once_cell", + "bumpalo", + "hashbrown 0.14.5", + "ptr_meta", "rustc-hash", - "serde", - "string_cache", - "string_cache_codegen", "triomphe", ] [[package]] name = "swc_atoms" -version = "0.5.9" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f54563d7dcba626d4acfe14ed12def7ecc28e004debe3ecd2c3ee07cc47e449" +checksum = "bb6567e4e67485b3e7662b486f1565bdae54bd5b9d6b16b2ba1a9babb1e42125" dependencies = [ - "bytecheck", + "hstr", "once_cell", - "rkyv", "rustc-hash", "serde", - "string_cache", - "string_cache_codegen", - "triomphe", ] [[package]] name = "swc_bundler" -version = "0.212.5" +version = "0.236.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23c39d6d7fef9ee2a951423593764bea1666a4be0cbc89030d0da8f985124870" +checksum = "bf56bdfc5af60d362bfe63c002af34b9ffba711dd1630fc9d58c3b0a2f5ce54b" dependencies = [ - "ahash 0.7.6", "anyhow", "crc", - "indexmap 1.9.3", - "is-macro 0.2.2", + "indexmap 2.5.0", + "is-macro", "once_cell", "parking_lot", "petgraph", "radix_fmt", "relative-path", - "swc_atoms 0.4.43", - "swc_common 0.30.5", - "swc_ecma_ast 0.102.5", - "swc_ecma_codegen 0.137.6", - "swc_ecma_loader 0.42.5", - "swc_ecma_parser 0.132.6", - "swc_ecma_transforms_base 0.125.1", - "swc_ecma_transforms_optimization 0.185.4", - "swc_ecma_utils 0.115.8", - "swc_ecma_visit 0.88.5", - "swc_fast_graph 0.18.5", + "swc_atoms", + "swc_common 0.37.5", + "swc_ecma_ast", + "swc_ecma_codegen", + "swc_ecma_loader", + "swc_ecma_parser", + "swc_ecma_transforms_base 0.144.0", + "swc_ecma_transforms_optimization", + "swc_ecma_utils", + "swc_ecma_visit", + "swc_fast_graph", "swc_graph_analyzer", "tracing", ] [[package]] name = "swc_cached" -version = "0.3.17" +version = "0.3.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b8051bbf1c23817f9f2912fce18d9a6efcaaf8f8e1a4c69dbaf72bcaf71136" +checksum = "83406221c501860fce9c27444f44125eafe9e598b8b81be7563d7036784cd05c" dependencies = [ - "ahash 0.8.6", + "ahash 0.8.11", "anyhow", "dashmap 5.5.3", "once_cell", @@ -4736,11 +4863,10 @@ dependencies = [ [[package]] name = "swc_common" -version = "0.30.5" +version = "0.36.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53e95bf36e3e217431c50eab784c5601bf5f0ed3657aac6bda57748fa4d6103b" +checksum = "457fb92efa9f0c849d6bc4e86561982d464176bc3df96bb22baed5e98309e090" dependencies = [ - "ahash 0.7.6", "ast_node", "better_scoped_tls", "cfg-if", @@ -4753,10 +4879,11 @@ dependencies = [ "rustc-hash", "serde", "siphasher", - "string_cache", - "swc_atoms 0.4.43", + "swc_allocator", + "swc_atoms", "swc_eq_ignore_macros", "swc_visit", + "termcolor", "tracing", "unicode-width", "url", @@ -4764,10 +4891,11 @@ dependencies = [ [[package]] name = "swc_common" -version = "0.31.22" +version = "0.37.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88d00f960c667c59c133f30492f4d07f26242fcf988a066d3871e6d3d838d528" +checksum = "12d0a8eaaf1606c9207077d75828008cb2dfb51b095a766bd2b72ef893576e31" dependencies = [ + "ahash 0.8.11", "ast_node", "better_scoped_tls", "cfg-if", @@ -4776,121 +4904,85 @@ dependencies = [ "new_debug_unreachable", "num-bigint", "once_cell", + "parking_lot", "rustc-hash", "serde", "siphasher", - "string_cache", - "swc_atoms 0.5.9", + "sourcemap", + "swc_allocator", + "swc_atoms", "swc_eq_ignore_macros", "swc_visit", + "termcolor", "tracing", "unicode-width", "url", ] [[package]] -name = "swc_common" -version = "0.32.1" +name = "swc_compiler_base" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c84742fc22df1c293da5354c1cc8a5b45a045e9dc941005c1fd9cb4e9bdabc1" +checksum = "9859d605bfa3ba8323f37bc4f51839c0e21ea59b657f65865388b0adfeb0a413" dependencies = [ - "ahash 0.8.6", "anyhow", - "ast_node", - "atty", - "better_scoped_tls", - "bytecheck", - "cfg-if", - "either", - "from_variant", - "new_debug_unreachable", - "num-bigint", + "base64 0.21.7", "once_cell", - "parking_lot", - "rkyv", + "pathdiff", "rustc-hash", "serde", - "siphasher", + "serde_json", "sourcemap", - "string_cache", - "swc_atoms 0.5.9", - "swc_eq_ignore_macros", - "swc_visit", - "termcolor", - "tracing", - "unicode-width", - "url", + "swc_allocator", + "swc_atoms", + "swc_common 0.37.5", + "swc_config", + "swc_ecma_ast", + "swc_ecma_codegen", + "swc_ecma_minifier", + "swc_ecma_parser", + "swc_ecma_visit", + "swc_timer", ] [[package]] name = "swc_config" -version = "0.1.7" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ba1c7a40d38f9dd4e9a046975d3faf95af42937b34b2b963be4d8f01239584b" +checksum = "4740e53eaf68b101203c1df0937d5161a29f3c13bceed0836ddfe245b72dd000" dependencies = [ - "indexmap 1.9.3", + "anyhow", + "indexmap 2.5.0", "serde", "serde_json", + "sourcemap", + "swc_cached", "swc_config_macro", ] [[package]] name = "swc_config_macro" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5b5aaca9a0082be4515f0fbbecc191bf5829cd25b5b9c0a2810f6a2bb0d6829" +checksum = "7c5f56139042c1a95b54f5ca48baa0e0172d369bcc9d3d473dad1de36bae8399" dependencies = [ - "pmutil 0.6.1", "proc-macro2", "quote", "swc_macros_common", - "syn 2.0.50", + "syn 2.0.77", ] [[package]] name = "swc_core" -version = "0.74.6" +version = "0.101.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e18b78930ecae9f6415393c0c396af455e2a3cda540620f01b28a3e99ce4cc77" +checksum = "24fd64b47f1da39ff3c229b7a3f4fb4d9542e21b245ac77220a4b2ad1f455065" dependencies = [ - "swc_atoms 0.4.43", - "swc_bundler", - "swc_common 0.30.5", - "swc_ecma_ast 0.102.5", - "swc_ecma_codegen 0.137.6", - "swc_ecma_loader 0.42.5", - "swc_ecma_parser 0.132.6", - "swc_ecma_transforms_base 0.125.1", - "swc_ecma_visit 0.88.5", - "vergen", -] - -[[package]] -name = "swc_core" -version = "0.79.71" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83cc00b001e77b2c9019cbd5034fddbb627bb23010864a0e57d4943efa70644b" -dependencies = [ - "swc_atoms 0.5.9", - "swc_common 0.31.22", - "swc_ecma_ast 0.107.8", - "swc_ecma_codegen 0.142.18", - "swc_ecma_parser 0.137.16", - "swc_ecma_transforms_base 0.130.25", - "swc_ecma_visit 0.93.8", - "vergen", -] - -[[package]] -name = "swc_core" -version = "0.83.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f42b020b98b1d844dd831c089581ca259b4fb8a0af60c7e6aae8aeadcce57e93" -dependencies = [ - "once_cell", "swc", - "swc_atoms 0.5.9", - "swc_common 0.32.1", + "swc_allocator", + "swc_atoms", + "swc_bundler", + "swc_common 0.37.5", "swc_css_ast", "swc_css_codegen", "swc_css_compat", @@ -4900,52 +4992,66 @@ dependencies = [ "swc_css_prefixer", "swc_css_utils", "swc_css_visit", - "swc_ecma_ast 0.109.1", - "swc_ecma_codegen 0.145.5", + "swc_ecma_ast", + "swc_ecma_codegen", + "swc_ecma_loader", "swc_ecma_minifier", - "swc_ecma_parser 0.140.0", + "swc_ecma_parser", "swc_ecma_preset_env", "swc_ecma_quote_macros", - "swc_ecma_transforms_base 0.133.5", + "swc_ecma_transforms_base 0.144.0", "swc_ecma_transforms_compat", "swc_ecma_transforms_module", - "swc_ecma_transforms_optimization 0.193.23", + "swc_ecma_transforms_optimization", "swc_ecma_transforms_proposal", "swc_ecma_transforms_react", - "swc_ecma_transforms_testing", "swc_ecma_transforms_typescript", - "swc_ecma_utils 0.123.0", - "swc_ecma_visit 0.95.1", - "swc_plugin", - "swc_plugin_macro", - "swc_plugin_proxy", - "vergen", + "swc_ecma_utils", + "swc_ecma_visit", + "vergen 8.3.2", +] + +[[package]] +name = "swc_core" +version = "0.103.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1297a233d0681b82e8706df416c697331c37e777d3c873d9554243525c3407f1" +dependencies = [ + "swc_allocator", + "swc_atoms", + "swc_common 0.37.5", + "swc_ecma_ast", + "swc_ecma_codegen", + "swc_ecma_parser", + "swc_ecma_transforms_base 0.146.0", + "swc_ecma_visit", + "vergen 9.0.0", ] [[package]] name = "swc_css_ast" -version = "0.139.1" +version = "0.144.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fab824eff88884673de1d6b84cdb5d3d71c0b903fcef62a3ec1f44f40477433f" +checksum = "931a3c25a6bae42537783eab131b34d8fd2913d14f975106ceb3287716072ee0" dependencies = [ - "is-macro 0.3.0", + "is-macro", "string_enum", - "swc_atoms 0.5.9", - "swc_common 0.32.1", + "swc_atoms", + "swc_common 0.37.5", ] [[package]] name = "swc_css_codegen" -version = "0.149.1" +version = "0.155.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aef989abd4b9ccf3caf6a4ab0ceb9f9e7d6a27c08585a20a7fc7b9db6c73a341" +checksum = "09080a69fd9c07d76141f02c9d2826e46f08ffab5fdb8942cd8a95f38712f038" dependencies = [ - "auto_impl 1.1.0", - "bitflags 2.4.2", + "auto_impl", + "bitflags 2.6.0", "rustc-hash", "serde", - "swc_atoms 0.5.9", - "swc_common 0.32.1", + "swc_atoms", + "swc_common 0.37.5", "swc_css_ast", "swc_css_codegen_macros", "swc_css_utils", @@ -4953,29 +5059,28 @@ dependencies = [ [[package]] name = "swc_css_codegen_macros" -version = "0.2.2" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7da287376d8e9ab2e2c5a17fffd0c4701140433a8640ea52fa0c368e69dec565" +checksum = "de2ece8c7dbdde85aa1bcc9764c5f41f7450d8bf1312eac2375b8dc0ecbc13d7" dependencies = [ - "pmutil 0.6.1", "proc-macro2", "quote", "swc_macros_common", - "syn 2.0.50", + "syn 2.0.77", ] [[package]] name = "swc_css_compat" -version = "0.25.1" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1ee1b2b77e7daaf389237ca2656df01cf8c1a6f2d9b158459921b202a661f8a" +checksum = "a46554269c0dcf34f3a414b3b43ed7dcd5e777e6cfa270a476101e522650ec58" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.6.0", "once_cell", "serde", "serde_json", - "swc_atoms 0.5.9", - "swc_common 0.32.1", + "swc_atoms", + "swc_common 0.37.5", "swc_css_ast", "swc_css_utils", "swc_css_visit", @@ -4983,13 +5088,13 @@ dependencies = [ [[package]] name = "swc_css_minifier" -version = "0.114.1" +version = "0.120.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21db6b6ef607d47d09a7e2fd0b8fd5ec29d05d1182f8d3d5eebef0f1b94c3f4d" +checksum = "3db2730dce248bf3ebab2d39885e7494b14a74279f93afcef4054c19aca61d17" dependencies = [ "serde", - "swc_atoms 0.5.9", - "swc_common 0.32.1", + "swc_atoms", + "swc_common 0.37.5", "swc_css_ast", "swc_css_utils", "swc_css_visit", @@ -4997,14 +5102,14 @@ dependencies = [ [[package]] name = "swc_css_modules" -version = "0.27.3" +version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac80e62e3221cb2abc0edd33886c74c7d2a64ca3756adce0047527026dff71ca" +checksum = "754fa55c23bcfaca640182d7812bc2104f8b20a488e7d29975e890618b6dc71c" dependencies = [ "rustc-hash", "serde", - "swc_atoms 0.5.9", - "swc_common 0.32.1", + "swc_atoms", + "swc_common 0.37.5", "swc_css_ast", "swc_css_codegen", "swc_css_parser", @@ -5013,29 +5118,29 @@ dependencies = [ [[package]] name = "swc_css_parser" -version = "0.148.1" +version = "0.154.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b02a3c11508487249aa571a908e673c540191de97d5139bb78ab03188dd57e26" +checksum = "02babeae8d3a1dad9858e6ade577b27cc463f8eb60139df0d05d58605e6c0554" dependencies = [ "lexical", "serde", - "swc_atoms 0.5.9", - "swc_common 0.32.1", + "swc_atoms", + "swc_common 0.37.5", "swc_css_ast", ] [[package]] name = "swc_css_prefixer" -version = "0.151.1" +version = "0.158.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "274da87a8f0117ef86382b132812aa6a1b700b31c37ef95ce3bbde7e05f8c098" +checksum = "b883a7be6ae276f2085b72585a790394939f89b65dbb562ed53df7e97af93884" dependencies = [ "once_cell", "preset_env_base", "serde", "serde_json", - "swc_atoms 0.5.9", - "swc_common 0.32.1", + "swc_atoms", + "swc_common 0.37.5", "swc_css_ast", "swc_css_utils", "swc_css_visit", @@ -5043,207 +5148,314 @@ dependencies = [ [[package]] name = "swc_css_utils" -version = "0.136.1" +version = "0.141.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3eead47672e3c832e2e3fc3e523490c4822d80a7fc8c50e87a66f9ab7003b517" +checksum = "28e930b27b85b95329f29b1fa36be032fb9bd04f20b0a7180c9c0fc19a368979" dependencies = [ "once_cell", "serde", "serde_json", - "swc_atoms 0.5.9", - "swc_common 0.32.1", + "swc_atoms", + "swc_common 0.37.5", "swc_css_ast", "swc_css_visit", ] [[package]] name = "swc_css_visit" -version = "0.138.1" +version = "0.143.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83f01449a09b8a87ab4bd2ea6cbaaf74e39f9bfba3842a2918e998c5f9b428a4" +checksum = "c603fa9af0a4adc536a901ab728384c7da4fa0187b64d6aa25eb75ea61f1482b" dependencies = [ "serde", - "swc_atoms 0.5.9", - "swc_common 0.32.1", + "swc_atoms", + "swc_common 0.37.5", "swc_css_ast", "swc_visit", ] [[package]] name = "swc_ecma_ast" -version = "0.102.5" +version = "0.118.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bc96ac4740ddd7e09baaa153b6cf74e62ed7436d674606c060ea01fd7c20cd0" +checksum = "a6f866d12e4d519052b92a0a86d1ac7ff17570da1272ca0c89b3d6f802cd79df" dependencies = [ - "bitflags 1.3.2", - "is-macro 0.2.2", + "bitflags 2.6.0", + "is-macro", "num-bigint", + "phf", "scoped-tls", "serde", "string_enum", - "swc_atoms 0.4.43", - "swc_common 0.30.5", - "unicode-id", + "swc_atoms", + "swc_common 0.37.5", + "unicode-id-start", ] [[package]] -name = "swc_ecma_ast" -version = "0.107.8" +name = "swc_ecma_codegen" +version = "0.155.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6528f3dd33e11eae9d7fe9fee4a79d5bbd211c74426ab2eec64dc82bd2eb74d" +checksum = "cc7641608ef117cfbef9581a99d02059b522fcca75e5244fa0cbbd8606689c6f" dependencies = [ - "bitflags 2.4.2", - "is-macro 0.3.0", + "memchr", "num-bigint", - "scoped-tls", - "string_enum", - "swc_atoms 0.5.9", - "swc_common 0.31.22", - "unicode-id", + "once_cell", + "serde", + "sourcemap", + "swc_allocator", + "swc_atoms", + "swc_common 0.37.5", + "swc_ecma_ast", + "swc_ecma_codegen_macros", + "tracing", ] [[package]] -name = "swc_ecma_ast" -version = "0.109.1" +name = "swc_ecma_codegen_macros" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e063a1614daed3ea8be56e5dd8edb17003409088d2fc9ce4aca3378879812607" +checksum = "859fabde36db38634f3fad548dd5e3410c1aebba1b67a3c63e67018fa57a0bca" dependencies = [ - "bitflags 2.4.2", - "bytecheck", - "is-macro 0.3.0", - "num-bigint", - "rkyv", - "scoped-tls", + "proc-macro2", + "quote", + "swc_macros_common", + "syn 2.0.77", +] + +[[package]] +name = "swc_ecma_compat_bugfixes" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9f9cac39f19d6509db921f4b75934aaa64fc84b599416e5c1fcaed1c313132f" +dependencies = [ + "swc_atoms", + "swc_common 0.37.5", + "swc_ecma_ast", + "swc_ecma_compat_es2015", + "swc_ecma_transforms_base 0.144.0", + "swc_ecma_utils", + "swc_ecma_visit", + "swc_trace_macro", + "tracing", +] + +[[package]] +name = "swc_ecma_compat_common" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9acdf402b36f8e83084b10e119d7ba9d07e5229ef39e1343f147db816c7b73e" +dependencies = [ + "swc_common 0.37.5", + "swc_ecma_ast", + "swc_ecma_utils", + "swc_ecma_visit", + "swc_trace_macro", +] + +[[package]] +name = "swc_ecma_compat_es2015" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dade6e0c6e8ddb61281fee2331c3775a920c31535b91e8cace2e0c4eed6158d3" +dependencies = [ + "arrayvec", + "indexmap 2.5.0", + "is-macro", "serde", - "string_enum", - "swc_atoms 0.5.9", - "swc_common 0.32.1", - "unicode-id", + "serde_derive", + "smallvec", + "swc_atoms", + "swc_common 0.37.5", + "swc_config", + "swc_ecma_ast", + "swc_ecma_compat_common", + "swc_ecma_transforms_base 0.144.0", + "swc_ecma_transforms_classes", + "swc_ecma_transforms_macros", + "swc_ecma_utils", + "swc_ecma_visit", + "swc_trace_macro", + "tracing", ] [[package]] -name = "swc_ecma_codegen" -version = "0.137.6" +name = "swc_ecma_compat_es2016" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75b1fc2f9d9a83e15ea27df387279c9f79c12eedeb58af29da663fda952600b1" +checksum = "209e347cdc3fb56632a1d882f981f3448f5f529c16d8da9d770207fffda4a8f6" +dependencies = [ + "swc_atoms", + "swc_common 0.37.5", + "swc_ecma_ast", + "swc_ecma_transforms_base 0.144.0", + "swc_ecma_transforms_macros", + "swc_ecma_utils", + "swc_ecma_visit", + "swc_trace_macro", + "tracing", +] + +[[package]] +name = "swc_ecma_compat_es2017" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4aa87a6861b2adc8b0178fb450165101c4396409481c8726ec90ad28398cae5d" dependencies = [ - "memchr", - "num-bigint", - "once_cell", - "rustc-hash", "serde", - "sourcemap", - "swc_atoms 0.4.43", - "swc_common 0.30.5", - "swc_ecma_ast 0.102.5", - "swc_ecma_codegen_macros", + "swc_atoms", + "swc_common 0.37.5", + "swc_ecma_ast", + "swc_ecma_transforms_base 0.144.0", + "swc_ecma_transforms_macros", + "swc_ecma_utils", + "swc_ecma_visit", + "swc_trace_macro", "tracing", ] [[package]] -name = "swc_ecma_codegen" -version = "0.142.18" +name = "swc_ecma_compat_es2018" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "933643517578f6c383fead24be0ba707c8548d43a9f80c46cc6972c5d7a0ab3a" +checksum = "f577f098e7c3738ade709caadb17c9f3bd911ea2ee6cfacca561d12addcc5761" dependencies = [ - "memchr", - "num-bigint", - "once_cell", - "rustc-hash", "serde", - "sourcemap", - "swc_atoms 0.5.9", - "swc_common 0.31.22", - "swc_ecma_ast 0.107.8", - "swc_ecma_codegen_macros", + "swc_atoms", + "swc_common 0.37.5", + "swc_ecma_ast", + "swc_ecma_compat_common", + "swc_ecma_transforms_base 0.144.0", + "swc_ecma_transforms_macros", + "swc_ecma_utils", + "swc_ecma_visit", + "swc_trace_macro", "tracing", ] [[package]] -name = "swc_ecma_codegen" -version = "0.145.5" +name = "swc_ecma_compat_es2019" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "547ed57b827ea4df3e2c27cea153482f8b2ce2d271ae30c456fbb2d5a5ecc19d" +checksum = "f9d52253dc2f83a3fca526c387c33e4ff9a8423b68c271414c9f870e1ced3231" +dependencies = [ + "swc_atoms", + "swc_common 0.37.5", + "swc_ecma_ast", + "swc_ecma_transforms_base 0.144.0", + "swc_ecma_utils", + "swc_ecma_visit", + "swc_trace_macro", + "tracing", +] + +[[package]] +name = "swc_ecma_compat_es2020" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed343932876fad34b1d4a13e30c55b94531e89916f45e7c04203bc49a29565b9" dependencies = [ - "memchr", - "num-bigint", - "once_cell", - "rustc-hash", "serde", - "sourcemap", - "swc_atoms 0.5.9", - "swc_common 0.32.1", - "swc_ecma_ast 0.109.1", - "swc_ecma_codegen_macros", + "swc_atoms", + "swc_common 0.37.5", + "swc_ecma_ast", + "swc_ecma_compat_es2022", + "swc_ecma_transforms_base 0.144.0", + "swc_ecma_utils", + "swc_ecma_visit", + "swc_trace_macro", "tracing", ] [[package]] -name = "swc_ecma_codegen_macros" -version = "0.7.3" +name = "swc_ecma_compat_es2021" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcdff076dccca6cc6a0e0b2a2c8acfb066014382bc6df98ec99e755484814384" +checksum = "0b6b28a2c109466eaa809d9b9a5b81dcbb4e269ba293a9c5c34aabc67b6427bc" dependencies = [ - "pmutil 0.6.1", - "proc-macro2", - "quote", - "swc_macros_common", - "syn 2.0.50", + "swc_atoms", + "swc_common 0.37.5", + "swc_ecma_ast", + "swc_ecma_transforms_base 0.144.0", + "swc_ecma_utils", + "swc_ecma_visit", + "swc_trace_macro", + "tracing", +] + +[[package]] +name = "swc_ecma_compat_es2022" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab3a644e271ea2a9df88e3e456c5c204c4916ef5136b7d946f9cd25607f47ec6" +dependencies = [ + "swc_atoms", + "swc_common 0.37.5", + "swc_ecma_ast", + "swc_ecma_compat_common", + "swc_ecma_transforms_base 0.144.0", + "swc_ecma_transforms_classes", + "swc_ecma_transforms_macros", + "swc_ecma_utils", + "swc_ecma_visit", + "swc_trace_macro", + "tracing", +] + +[[package]] +name = "swc_ecma_compat_es3" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e55ffadc12067b21524bf7b5d6938021ee918f65f18937ed27245c23544bc910" +dependencies = [ + "swc_common 0.37.5", + "swc_ecma_ast", + "swc_ecma_transforms_base 0.144.0", + "swc_ecma_utils", + "swc_ecma_visit", + "swc_trace_macro", + "tracing", ] [[package]] name = "swc_ecma_ext_transforms" -version = "0.109.0" +version = "0.120.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d995f94740b4cde4919e6e03d982230f755f49dac9dac52f0218254a1fd69f2b" +checksum = "ad03ee53c734eb74757d03c07ec71b1a982261830c9253ef3e2e4a089f9af25d" dependencies = [ "phf", - "swc_atoms 0.5.9", - "swc_common 0.32.1", - "swc_ecma_ast 0.109.1", - "swc_ecma_utils 0.123.0", - "swc_ecma_visit 0.95.1", + "swc_atoms", + "swc_common 0.37.5", + "swc_ecma_ast", + "swc_ecma_utils", + "swc_ecma_visit", ] [[package]] name = "swc_ecma_lints" -version = "0.88.6" +version = "0.99.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "300ae29c0fc98ed0364aa2fd4aa7702d6dc67d411dd4894e7e60d40e99c4ef19" +checksum = "20c11bcc9e3dc49929500c07c8b0c84a88064847d31e9ee16204b257e6bd315c" dependencies = [ - "auto_impl 1.1.0", + "auto_impl", "dashmap 5.5.3", "parking_lot", "rayon", "regex", "serde", - "swc_atoms 0.5.9", - "swc_common 0.32.1", + "swc_atoms", + "swc_common 0.37.5", "swc_config", - "swc_ecma_ast 0.109.1", - "swc_ecma_utils 0.123.0", - "swc_ecma_visit 0.95.1", -] - -[[package]] -name = "swc_ecma_loader" -version = "0.42.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f07db9ffa757d71893e265c716307c3c9568ab85645c126e80e0d0ba7528aef5" -dependencies = [ - "ahash 0.7.6", - "anyhow", - "pathdiff", - "serde", - "swc_common 0.30.5", - "tracing", + "swc_ecma_ast", + "swc_ecma_utils", + "swc_ecma_visit", ] [[package]] name = "swc_ecma_loader" -version = "0.44.4" +version = "0.49.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b2b3a3ec38fc9c691b787d32ac2aa5eb6871d1fe74ac4a10638fbd9b9bc407b" +checksum = "55fa3d55045b97894bfb04d38aff6d6302ac8a6a38e3bb3dfb0d20475c4974a9" dependencies = [ "anyhow", "dashmap 5.5.3", @@ -5255,23 +5467,25 @@ dependencies = [ "pathdiff", "serde", "serde_json", + "swc_atoms", "swc_cached", - "swc_common 0.32.1", + "swc_common 0.37.5", "tracing", ] [[package]] name = "swc_ecma_minifier" -version = "0.187.26" +version = "0.203.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80a2eb3007ceb2ff8096f56ee67fe1cff2f94e21ea015f0f9d99dfe53fc680a9" +checksum = "c9bc16bd0a3c295588939fe8d02f795d3463a2e1613600f9c860c7a9aadebe7c" dependencies = [ "arrayvec", - "indexmap 1.9.3", + "indexmap 2.5.0", "num-bigint", "num_cpus", "once_cell", "parking_lot", + "phf", "radix_fmt", "rayon", "regex", @@ -5279,91 +5493,53 @@ dependencies = [ "ryu-js", "serde", "serde_json", - "swc_atoms 0.5.9", - "swc_cached", - "swc_common 0.32.1", + "swc_allocator", + "swc_atoms", + "swc_common 0.37.5", "swc_config", - "swc_ecma_ast 0.109.1", - "swc_ecma_codegen 0.145.5", - "swc_ecma_parser 0.140.0", - "swc_ecma_transforms_base 0.133.5", - "swc_ecma_transforms_optimization 0.193.23", + "swc_ecma_ast", + "swc_ecma_codegen", + "swc_ecma_parser", + "swc_ecma_transforms_base 0.144.0", + "swc_ecma_transforms_optimization", "swc_ecma_usage_analyzer", - "swc_ecma_utils 0.123.0", - "swc_ecma_visit 0.95.1", + "swc_ecma_utils", + "swc_ecma_visit", "swc_timer", "tracing", ] [[package]] name = "swc_ecma_parser" -version = "0.132.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9b8409efcb3c70fe31fb3203406ab73b3c3cd279aa2005887d1918049b2a38e" -dependencies = [ - "either", - "lexical", - "num-bigint", - "serde", - "smallvec", - "smartstring", - "stacker", - "swc_atoms 0.4.43", - "swc_common 0.30.5", - "swc_ecma_ast 0.102.5", - "tracing", - "typed-arena", -] - -[[package]] -name = "swc_ecma_parser" -version = "0.137.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f95601ae9654b664a44154bd5186af106df8e7de2dfecad211b29dc90b84185" -dependencies = [ - "either", - "num-bigint", - "num-traits", - "serde", - "smallvec", - "smartstring", - "stacker", - "swc_atoms 0.5.9", - "swc_common 0.31.22", - "swc_ecma_ast 0.107.8", - "tracing", - "typed-arena", -] - -[[package]] -name = "swc_ecma_parser" -version = "0.140.0" +version = "0.149.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c968599841fcecfdc2e490188ad93251897a1bb912882547e6889e14a368399" +checksum = "683dada14722714588b56481399c699378b35b2ba4deb5c4db2fb627a97fb54b" dependencies = [ "either", + "new_debug_unreachable", "num-bigint", "num-traits", + "phf", "serde", "smallvec", "smartstring", "stacker", - "swc_atoms 0.5.9", - "swc_common 0.32.1", - "swc_ecma_ast 0.109.1", + "swc_atoms", + "swc_common 0.37.5", + "swc_ecma_ast", "tracing", "typed-arena", ] [[package]] name = "swc_ecma_preset_env" -version = "0.201.25" +version = "0.216.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "641be911f548518ab41f22dd377420a9b5d9de857a2f77ffdf51cf2aff0069bd" +checksum = "e5c01c4097d54b6992d926474546472f10f1f94799a6eb9b70176fc33e778573" dependencies = [ "anyhow", "dashmap 5.5.3", - "indexmap 1.9.3", + "indexmap 2.5.0", "once_cell", "preset_env_base", "rustc-hash", @@ -5372,472 +5548,334 @@ dependencies = [ "serde_json", "st-map", "string_enum", - "swc_atoms 0.5.9", - "swc_common 0.32.1", - "swc_ecma_ast 0.109.1", + "swc_atoms", + "swc_common 0.37.5", + "swc_ecma_ast", "swc_ecma_transforms", - "swc_ecma_utils 0.123.0", - "swc_ecma_visit 0.95.1", + "swc_ecma_utils", + "swc_ecma_visit", ] [[package]] name = "swc_ecma_quote_macros" -version = "0.51.0" +version = "0.60.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b028b0675ad45b79b163c70e192f25b59d72366a2864c5d369dce707a38a1597" +checksum = "9781802c95d3bb1b248ae2641fab85012782bb5236e32600e6e4a00adf90a2dc" dependencies = [ "anyhow", - "pmutil 0.6.1", "proc-macro2", "quote", - "swc_atoms 0.5.9", - "swc_common 0.32.1", - "swc_ecma_ast 0.109.1", - "swc_ecma_parser 0.140.0", + "swc_atoms", + "swc_common 0.37.5", + "swc_ecma_ast", + "swc_ecma_parser", "swc_macros_common", - "syn 2.0.50", -] - -[[package]] -name = "swc_ecma_testing" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b776795afd44c8df3977391e239a8dedbe2139c5eeb1ea053c1e29314b6d8a7" -dependencies = [ - "anyhow", - "hex", - "sha-1", - "testing", - "tracing", + "syn 2.0.77", ] [[package]] name = "swc_ecma_transforms" -version = "0.224.23" +version = "0.238.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f2dd0d135dbbadad6698bb42df89b90b03605f1625ae0906c39b3749b5afc40" +checksum = "d6a33679b1611630ee41f8ee8b41b9587de4171819698d313f7f8ae2c699f41a" dependencies = [ - "swc_atoms 0.5.9", - "swc_common 0.32.1", - "swc_ecma_ast 0.109.1", - "swc_ecma_transforms_base 0.133.5", + "swc_atoms", + "swc_common 0.37.5", + "swc_ecma_ast", + "swc_ecma_transforms_base 0.144.0", "swc_ecma_transforms_compat", "swc_ecma_transforms_module", - "swc_ecma_transforms_optimization 0.193.23", + "swc_ecma_transforms_optimization", "swc_ecma_transforms_proposal", "swc_ecma_transforms_react", "swc_ecma_transforms_typescript", - "swc_ecma_utils 0.123.0", - "swc_ecma_visit 0.95.1", + "swc_ecma_utils", + "swc_ecma_visit", ] [[package]] name = "swc_ecma_transforms_base" -version = "0.125.1" +version = "0.144.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b87668640fe6d63ecabaae1805534d1445ff63382ab8961cd623ccdeb1bfbc" +checksum = "7c0a71579d030e12fd3cfbfc8712c4ce21afc526f2a759903c77d8df61950f5e" dependencies = [ "better_scoped_tls", - "bitflags 1.3.2", - "indexmap 1.9.3", - "once_cell", - "phf", - "rustc-hash", - "serde", - "smallvec", - "swc_atoms 0.4.43", - "swc_common 0.30.5", - "swc_ecma_ast 0.102.5", - "swc_ecma_parser 0.132.6", - "swc_ecma_utils 0.115.8", - "swc_ecma_visit 0.88.5", - "tracing", -] - -[[package]] -name = "swc_ecma_transforms_base" -version = "0.130.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42198e3909a6d852ebd88897267ee89323a8ebdbdb436ec60f48079f7c188018" -dependencies = [ - "better_scoped_tls", - "bitflags 2.4.2", - "indexmap 1.9.3", + "bitflags 2.6.0", + "indexmap 2.5.0", "once_cell", "phf", + "rayon", "rustc-hash", "serde", "smallvec", - "swc_atoms 0.5.9", - "swc_common 0.31.22", - "swc_ecma_ast 0.107.8", - "swc_ecma_parser 0.137.16", - "swc_ecma_utils 0.120.20", - "swc_ecma_visit 0.93.8", + "swc_atoms", + "swc_common 0.37.5", + "swc_ecma_ast", + "swc_ecma_parser", + "swc_ecma_utils", + "swc_ecma_visit", "tracing", ] [[package]] name = "swc_ecma_transforms_base" -version = "0.133.5" +version = "0.146.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "496e3957e19c22e61cd7ff020a87e1fe94c9334f4fa11267f08614fd5f85ba67" +checksum = "3b5a7c0a6c4cc7d0ba65549e7db52443bc0eb104563aeaae727ad87c176a1bbe" dependencies = [ "better_scoped_tls", - "bitflags 2.4.2", - "indexmap 1.9.3", + "bitflags 2.6.0", + "indexmap 2.5.0", "once_cell", "phf", - "rayon", "rustc-hash", "serde", "smallvec", - "swc_atoms 0.5.9", - "swc_common 0.32.1", - "swc_ecma_ast 0.109.1", - "swc_ecma_parser 0.140.0", - "swc_ecma_utils 0.123.0", - "swc_ecma_visit 0.95.1", + "swc_atoms", + "swc_common 0.37.5", + "swc_ecma_ast", + "swc_ecma_parser", + "swc_ecma_utils", + "swc_ecma_visit", "tracing", ] [[package]] name = "swc_ecma_transforms_classes" -version = "0.122.5" +version = "0.133.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "519ffccc874b8bb39db0fceec06c172b1d7a6e812ac6f4b0a000e5d3c295e495" +checksum = "0f37ec04525798a09ce02e52dc15433acee2d86664da0b8ede55bb5cefd95384" dependencies = [ - "swc_atoms 0.5.9", - "swc_common 0.32.1", - "swc_ecma_ast 0.109.1", - "swc_ecma_transforms_base 0.133.5", - "swc_ecma_utils 0.123.0", - "swc_ecma_visit 0.95.1", + "swc_atoms", + "swc_common 0.37.5", + "swc_ecma_ast", + "swc_ecma_transforms_base 0.144.0", + "swc_ecma_utils", + "swc_ecma_visit", ] [[package]] name = "swc_ecma_transforms_compat" -version = "0.159.12" +version = "0.170.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bfdc348f8e402b311cf25661086ea3bcdd8305688b582750d7934e2ba46f79e" +checksum = "4bb500b65423646da940e289ad37e7c88332d7194248c33fc63a9e768e104fe5" dependencies = [ "arrayvec", - "indexmap 1.9.3", - "is-macro 0.3.0", + "indexmap 2.5.0", + "is-macro", "num-bigint", "serde", "smallvec", - "swc_atoms 0.5.9", - "swc_common 0.32.1", + "swc_atoms", + "swc_common 0.37.5", "swc_config", - "swc_ecma_ast 0.109.1", - "swc_ecma_transforms_base 0.133.5", + "swc_ecma_ast", + "swc_ecma_compat_bugfixes", + "swc_ecma_compat_common", + "swc_ecma_compat_es2015", + "swc_ecma_compat_es2016", + "swc_ecma_compat_es2017", + "swc_ecma_compat_es2018", + "swc_ecma_compat_es2019", + "swc_ecma_compat_es2020", + "swc_ecma_compat_es2021", + "swc_ecma_compat_es2022", + "swc_ecma_compat_es3", + "swc_ecma_transforms_base 0.144.0", "swc_ecma_transforms_classes", "swc_ecma_transforms_macros", - "swc_ecma_utils 0.123.0", - "swc_ecma_visit 0.95.1", + "swc_ecma_utils", + "swc_ecma_visit", "swc_trace_macro", "tracing", ] [[package]] name = "swc_ecma_transforms_macros" -version = "0.5.3" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8188eab297da773836ef5cf2af03ee5cca7a563e1be4b146f8141452c28cc690" +checksum = "500a1dadad1e0e41e417d633b3d6d5de677c9e0d3159b94ba3348436cdb15aab" dependencies = [ - "pmutil 0.6.1", "proc-macro2", "quote", "swc_macros_common", - "syn 2.0.50", + "syn 2.0.77", ] [[package]] name = "swc_ecma_transforms_module" -version = "0.176.16" +version = "0.189.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aee1c35e2dde705a7c899247302c306c4e1d4f6c2374f6c075ae6c4964aa1c8c" +checksum = "2b5bddea322502ce309f77b76dcd7994ff700fbba7caf9d12eb6fb7ef98ecd1b" dependencies = [ "Inflector", "anyhow", - "bitflags 2.4.2", - "indexmap 1.9.3", - "is-macro 0.3.0", - "path-clean 0.1.0", + "bitflags 2.6.0", + "indexmap 2.5.0", + "is-macro", + "path-clean 1.0.1", "pathdiff", "regex", "serde", - "swc_atoms 0.5.9", + "swc_atoms", "swc_cached", - "swc_common 0.32.1", - "swc_ecma_ast 0.109.1", - "swc_ecma_loader 0.44.4", - "swc_ecma_parser 0.140.0", - "swc_ecma_transforms_base 0.133.5", - "swc_ecma_utils 0.123.0", - "swc_ecma_visit 0.95.1", + "swc_common 0.37.5", + "swc_ecma_ast", + "swc_ecma_loader", + "swc_ecma_parser", + "swc_ecma_transforms_base 0.144.0", + "swc_ecma_utils", + "swc_ecma_visit", "tracing", ] [[package]] name = "swc_ecma_transforms_optimization" -version = "0.185.4" +version = "0.207.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "544681f98bd62c45e8fc091cfbf8425fb02fd458a4ad81b9557be8bb41e5db37" +checksum = "fc9b6dcb79ac6f396988c13ce2f782116aeb92e8ee77656072d1146697f66022" dependencies = [ - "ahash 0.7.6", "dashmap 5.5.3", - "indexmap 1.9.3", - "once_cell", - "petgraph", - "rustc-hash", - "serde_json", - "swc_atoms 0.4.43", - "swc_common 0.30.5", - "swc_ecma_ast 0.102.5", - "swc_ecma_parser 0.132.6", - "swc_ecma_transforms_base 0.125.1", - "swc_ecma_transforms_macros", - "swc_ecma_utils 0.115.8", - "swc_ecma_visit 0.88.5", - "swc_fast_graph 0.18.5", - "tracing", -] - -[[package]] -name = "swc_ecma_transforms_optimization" -version = "0.193.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "321b41c92ea012e9514f694a6073ea7d5a5a081d4a78e381b0ee3c2a96a07b57" -dependencies = [ - "dashmap 5.5.3", - "indexmap 1.9.3", + "indexmap 2.5.0", "once_cell", "petgraph", "rayon", "rustc-hash", "serde_json", - "swc_atoms 0.5.9", - "swc_common 0.32.1", - "swc_ecma_ast 0.109.1", - "swc_ecma_parser 0.140.0", - "swc_ecma_transforms_base 0.133.5", + "swc_atoms", + "swc_common 0.37.5", + "swc_ecma_ast", + "swc_ecma_parser", + "swc_ecma_transforms_base 0.144.0", "swc_ecma_transforms_macros", - "swc_ecma_utils 0.123.0", - "swc_ecma_visit 0.95.1", - "swc_fast_graph 0.20.1", + "swc_ecma_utils", + "swc_ecma_visit", + "swc_fast_graph", "tracing", ] [[package]] name = "swc_ecma_transforms_proposal" -version = "0.167.15" +version = "0.178.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9303611271cf1d8884920e6056acd3dbbd9f4dfda8ba7295dd6c76a02d20401" +checksum = "b252ea08cfd11e434f4c625ec95493e06c8b000b50eb8e908d76f3325dd5dfa8" dependencies = [ "either", "rustc-hash", "serde", "smallvec", - "swc_atoms 0.5.9", - "swc_common 0.32.1", - "swc_ecma_ast 0.109.1", - "swc_ecma_transforms_base 0.133.5", + "swc_atoms", + "swc_common 0.37.5", + "swc_ecma_ast", + "swc_ecma_transforms_base 0.144.0", "swc_ecma_transforms_classes", "swc_ecma_transforms_macros", - "swc_ecma_utils 0.123.0", - "swc_ecma_visit 0.95.1", + "swc_ecma_utils", + "swc_ecma_visit", ] [[package]] name = "swc_ecma_transforms_react" -version = "0.179.16" +version = "0.190.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3066e5671862ec921d39a210bb94e2fd82c1d4a8b2ccf44feb9017ab8afadd61" +checksum = "c3e54a8c87d90812bf69b0f07931bb629111a3f24efe83b9190c3a40a5ebc25e" dependencies = [ - "base64 0.13.1", + "base64 0.21.7", "dashmap 5.5.3", - "indexmap 1.9.3", + "indexmap 2.5.0", "once_cell", "serde", - "sha-1", + "sha1", "string_enum", - "swc_atoms 0.5.9", - "swc_common 0.32.1", + "swc_allocator", + "swc_atoms", + "swc_common 0.37.5", "swc_config", - "swc_ecma_ast 0.109.1", - "swc_ecma_parser 0.140.0", - "swc_ecma_transforms_base 0.133.5", + "swc_ecma_ast", + "swc_ecma_parser", + "swc_ecma_transforms_base 0.144.0", "swc_ecma_transforms_macros", - "swc_ecma_utils 0.123.0", - "swc_ecma_visit 0.95.1", -] - -[[package]] -name = "swc_ecma_transforms_testing" -version = "0.136.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef0636ec69f3de36ed0155a05e338b6ee294b115fafa15e13996f1ca7f2af6c3" -dependencies = [ - "ansi_term", - "anyhow", - "base64 0.13.1", - "hex", - "serde", - "serde_json", - "sha-1", - "sourcemap", - "swc_common 0.32.1", - "swc_ecma_ast 0.109.1", - "swc_ecma_codegen 0.145.5", - "swc_ecma_parser 0.140.0", - "swc_ecma_testing", - "swc_ecma_transforms_base 0.133.5", - "swc_ecma_utils 0.123.0", - "swc_ecma_visit 0.95.1", - "tempfile", - "testing", + "swc_ecma_utils", + "swc_ecma_visit", ] [[package]] name = "swc_ecma_transforms_typescript" -version = "0.183.22" +version = "0.197.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "280a4ee5542e785db7c68a6b88de99916304fc47c47863f9c511db374c7e3835" +checksum = "0c7e8646e32ec76ed1bda9c111583f65ed8daa46586bbfd892788536c78a6d4c" dependencies = [ "ryu-js", "serde", - "swc_atoms 0.5.9", - "swc_common 0.32.1", - "swc_ecma_ast 0.109.1", - "swc_ecma_transforms_base 0.133.5", + "swc_atoms", + "swc_common 0.37.5", + "swc_ecma_ast", + "swc_ecma_transforms_base 0.144.0", "swc_ecma_transforms_react", - "swc_ecma_utils 0.123.0", - "swc_ecma_visit 0.95.1", + "swc_ecma_utils", + "swc_ecma_visit", ] [[package]] name = "swc_ecma_usage_analyzer" -version = "0.19.0" +version = "0.30.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71dc9b35f1f137c72badbadb705a2325d161ff603224ab0e07e6834774ea281" +checksum = "0c7689421c6a892642c5907fd608c56d982fdef0d6456f9dba3cc418c6ea7e07" dependencies = [ - "indexmap 1.9.3", + "indexmap 2.5.0", "rustc-hash", - "swc_atoms 0.5.9", - "swc_common 0.32.1", - "swc_ecma_ast 0.109.1", - "swc_ecma_utils 0.123.0", - "swc_ecma_visit 0.95.1", + "swc_atoms", + "swc_common 0.37.5", + "swc_ecma_ast", + "swc_ecma_utils", + "swc_ecma_visit", "swc_timer", "tracing", ] [[package]] name = "swc_ecma_utils" -version = "0.115.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "077231ec8a3423b1b5dea4e6e220f7681315acca80494624b71717cf39d3ae64" -dependencies = [ - "indexmap 1.9.3", - "num_cpus", - "once_cell", - "rustc-hash", - "swc_atoms 0.4.43", - "swc_common 0.30.5", - "swc_ecma_ast 0.102.5", - "swc_ecma_visit 0.88.5", - "tracing", - "unicode-id", -] - -[[package]] -name = "swc_ecma_utils" -version = "0.120.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "058e23023eab86b548b0488b84a4d490f8d2f5e1de6483d82e352218fd59ae31" -dependencies = [ - "indexmap 1.9.3", - "num_cpus", - "once_cell", - "rustc-hash", - "swc_atoms 0.5.9", - "swc_common 0.31.22", - "swc_ecma_ast 0.107.8", - "swc_ecma_visit 0.93.8", - "tracing", - "unicode-id", -] - -[[package]] -name = "swc_ecma_utils" -version = "0.123.0" +version = "0.134.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b6d6b59ebd31b25fe2692ff705c806961e7856de8b7e91fd0942328886cd315" +checksum = "54f4e07d0d4987f8f27933549498acce5f89451ebe09b7d65f4d4ed4fc731200" dependencies = [ - "indexmap 1.9.3", + "indexmap 2.5.0", "num_cpus", "once_cell", "rayon", "rustc-hash", - "swc_atoms 0.5.9", - "swc_common 0.32.1", - "swc_ecma_ast 0.109.1", - "swc_ecma_visit 0.95.1", + "ryu-js", + "swc_atoms", + "swc_common 0.37.5", + "swc_ecma_ast", + "swc_ecma_visit", "tracing", "unicode-id", ] [[package]] name = "swc_ecma_visit" -version = "0.88.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67210c9d3bc4cdf6a1b2c69cb4ec77660a37e55e883c5ed9f8bc0e801758334b" -dependencies = [ - "num-bigint", - "swc_atoms 0.4.43", - "swc_common 0.30.5", - "swc_ecma_ast 0.102.5", - "swc_visit", - "tracing", -] - -[[package]] -name = "swc_ecma_visit" -version = "0.93.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9abcc6c3255eea772716872d9c958abfe97b1f4658c7a9d1d9dc55eb7e6da254" -dependencies = [ - "num-bigint", - "swc_atoms 0.5.9", - "swc_common 0.31.22", - "swc_ecma_ast 0.107.8", - "swc_visit", - "tracing", -] - -[[package]] -name = "swc_ecma_visit" -version = "0.95.1" +version = "0.104.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2774848b306e17fa280c598ecb192cc2c72a1163942b02d48606514336e9e7c5" +checksum = "5b1c6802e68e51f336e8bc9644e9ff9da75d7da9c1a6247d532f2e908aa33e81" dependencies = [ + "new_debug_unreachable", "num-bigint", - "swc_atoms 0.5.9", - "swc_common 0.32.1", - "swc_ecma_ast 0.109.1", + "serde", + "swc_atoms", + "swc_common 0.37.5", + "swc_ecma_ast", "swc_visit", "tracing", ] [[package]] name = "swc_emotion" -version = "0.51.0" +version = "0.72.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d1a13c3241b2812f15e751687924b0458b55ca7c3576a752b939e954cb4b0ba" +checksum = "b4f4ea59296e236f2e66efb2a004fb2aecb1894dc7affd2747f83fe77939dadc" dependencies = [ - "base64 0.13.1", + "base64 0.22.1", "byteorder", "fxhash", "once_cell", @@ -5845,184 +5883,160 @@ dependencies = [ "regex", "serde", "sourcemap", - "swc_atoms 0.5.9", - "swc_common 0.32.1", - "swc_ecma_ast 0.109.1", - "swc_ecma_codegen 0.145.5", - "swc_ecma_utils 0.123.0", - "swc_ecma_visit 0.95.1", + "swc_atoms", + "swc_common 0.37.5", + "swc_ecma_ast", + "swc_ecma_codegen", + "swc_ecma_utils", + "swc_ecma_visit", "swc_trace_macro", "tracing", ] [[package]] name = "swc_eq_ignore_macros" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05a95d367e228d52484c53336991fdcf47b6b553ef835d9159db4ba40efb0ee8" +checksum = "63db0adcff29d220c3d151c5b25c0eabe7e32dd936212b84cdaa1392e3130497" dependencies = [ - "pmutil 0.6.1", "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.77", ] [[package]] name = "swc_error_reporters" -version = "0.16.1" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c76b479ad1a69bec65b261354b8e2dec8ed0f9ed43c7b54ab053dc4923e1c90e" +checksum = "e02c81943772dc4fb0a6228360552d353fedc1a368ee6d80a5172ecb376b1796" dependencies = [ "anyhow", - "miette 4.7.1", + "miette 7.2.0", "once_cell", "parking_lot", - "swc_common 0.32.1", + "swc_common 0.36.3", ] [[package]] -name = "swc_fast_graph" -version = "0.18.5" +name = "swc_error_reporters" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c9081b942cd9760525ef23f4c932cb2b314c5f06f3d8b25f7bb8a1449ff7ec" +checksum = "0d049e9256abf29d9fc66d3db3ea44b6815a64ad565ce31e117a74ee96478bb3" dependencies = [ - "indexmap 1.9.3", - "petgraph", - "rustc-hash", - "swc_common 0.30.5", + "anyhow", + "miette 7.2.0", + "once_cell", + "parking_lot", + "swc_common 0.37.5", ] [[package]] name = "swc_fast_graph" -version = "0.20.1" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2f7297cdefdb54d8d09e0294c1aec3826825b1feefd0c25978365aa7f447a1c" +checksum = "357e2c97bb51431d65080f25b436bc4e2fc1a7f64a643bc21a8353e478dc799f" dependencies = [ - "indexmap 1.9.3", + "indexmap 2.5.0", "petgraph", "rustc-hash", - "swc_common 0.32.1", + "swc_common 0.37.5", ] [[package]] name = "swc_graph_analyzer" -version = "0.19.5" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23f7b0fd7b458e07d47e4a401a452cd60090e9eff93eadf06880e1787e19f293" +checksum = "f84e1d24a0d6e4066b42cfc00ab9b3109e314465aa199dd3e16849ed9566dce7" dependencies = [ - "ahash 0.7.6", - "auto_impl 0.5.0", + "auto_impl", "petgraph", - "swc_fast_graph 0.18.5", + "swc_common 0.37.5", + "swc_fast_graph", "tracing", ] [[package]] name = "swc_macros_common" -version = "0.3.8" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a273205ccb09b51fabe88c49f3b34c5a4631c4c00a16ae20e03111d6a42e832" +checksum = "f486687bfb7b5c560868f69ed2d458b880cebc9babebcb67e49f31b55c5bf847" dependencies = [ - "pmutil 0.6.1", "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.77", ] [[package]] name = "swc_node_comments" -version = "0.19.1" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2b9597573f1ab8bae72329eef550d214ced0955c7a4f1b6b4ae5e216219e710" +checksum = "d016ab18b432523b2a3c104ce3aaf7d869db46c0a41477dbfb6201ddc86c1eb0" dependencies = [ "dashmap 5.5.3", - "swc_atoms 0.5.9", - "swc_common 0.32.1", + "swc_atoms", + "swc_common 0.37.5", ] [[package]] -name = "swc_plugin" -version = "0.90.0" +name = "swc_timer" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca5df720531bfbd7ceb1139319c39c20c446abfb8f7e0eb47b104205a71152b4" +checksum = "6b5fb6f8b8b85512aacbb3d7140a828666e0e0b1bcc69bf84000a0cd36306bab" dependencies = [ - "once_cell", + "tracing", ] [[package]] -name = "swc_plugin_macro" -version = "0.9.15" +name = "swc_trace_macro" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "785309d342a69df4c929ee59e14e36889ca832f1d2a3c1d03c47c93126c72dbc" +checksum = "ff9719b6085dd2824fd61938a881937be14b08f95e2d27c64c825a9f65e052ba" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.77", ] [[package]] -name = "swc_plugin_proxy" -version = "0.38.1" +name = "swc_transform_common" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a76ccadcc63a459e096f332730b2d4e09548fc10e0be63df9f3bacecdf5332fe" +checksum = "eda3e80e1ad638d3575bc07745a914af13dcb02215098659f864731078271f2c" dependencies = [ "better_scoped_tls", - "rkyv", - "swc_common 0.32.1", - "swc_ecma_ast 0.109.1", - "swc_trace_macro", - "tracing", -] - -[[package]] -name = "swc_timer" -version = "0.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1841a4bd92674f684a3e27b8e162d4eac912af87b34ecd4b6dc126fe4fd230fe" -dependencies = [ - "tracing", + "once_cell", + "rustc-hash", + "serde", + "serde_json", ] [[package]] -name = "swc_trace_macro" -version = "0.1.3" +name = "swc_typescript" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff9719b6085dd2824fd61938a881937be14b08f95e2d27c64c825a9f65e052ba" +checksum = "d5d043347b109a8aebfe01aaeada4af322304ea0f54ae8e5721df9afcb9305ca" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.50", + "swc_atoms", + "swc_common 0.37.5", + "swc_ecma_ast", + "thiserror", ] [[package]] name = "swc_visit" -version = "0.5.7" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e87c337fbb2d191bf371173dea6a957f01899adb8f189c6c31b122a6cfc98fc3" +checksum = "1ceb044142ba2719ef9eb3b6b454fce61ab849eb696c34d190f04651955c613d" dependencies = [ "either", - "swc_visit_macros", -] - -[[package]] -name = "swc_visit_macros" -version = "0.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f322730fb82f3930a450ac24de8c98523af7d34ab8cb2f46bcb405839891a99" -dependencies = [ - "Inflector", - "pmutil 0.6.1", - "proc-macro2", - "quote", - "swc_macros_common", - "syn 2.0.50", + "new_debug_unreachable", ] [[package]] name = "swc_xml" -version = "0.10.5" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b1b517334dc2fa4fa724f165f6c718d3cff27b1b668bfb6664261d2af1f00f9" +checksum = "0a00df52c70e48a1a46289447e32b646a69b8f01c8ff37d72a38e071820a2734" dependencies = [ "swc_xml_ast", "swc_xml_codegen", @@ -6032,64 +6046,63 @@ dependencies = [ [[package]] name = "swc_xml_ast" -version = "0.9.5" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d95821a0f2962faf3ff0fea16cdcf401c7cd90d67a09effb6b638bfe82df38d" +checksum = "657b5392f0b28a096b80dd7e07338f1a6da2d9f1ec18d8b4b7041b7c12ab7a7b" dependencies = [ - "is-macro 0.2.2", + "is-macro", "string_enum", - "swc_atoms 0.4.43", - "swc_common 0.30.5", + "swc_atoms", + "swc_common 0.37.5", ] [[package]] name = "swc_xml_codegen" -version = "0.10.5" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48738c170db37b0c3dd762d0d0348875aa59c4835f2b16fd6ea5e5204b7acd27" +checksum = "6c408c3aa4c32e1f9c6f0df39fb852a24c48a1ace1c70e8b3f0e2155f83705f2" dependencies = [ - "auto_impl 0.5.0", - "bitflags 1.3.2", + "auto_impl", + "bitflags 2.6.0", "rustc-hash", - "swc_atoms 0.4.43", - "swc_common 0.30.5", + "swc_atoms", + "swc_common 0.37.5", "swc_xml_ast", "swc_xml_codegen_macros", ] [[package]] name = "swc_xml_codegen_macros" -version = "0.1.1" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d5569cdfb93c97285c877c98eaa9c4897840666480fa2b8e35409c427d80086" +checksum = "aa129a0ce5386899ba969efe81b0e5e2f534c052d42682592f4beb95379ba977" dependencies = [ - "pmutil 0.5.3", "proc-macro2", "quote", "swc_macros_common", - "syn 1.0.109", + "syn 2.0.77", ] [[package]] name = "swc_xml_parser" -version = "0.10.5" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d69b0d1c906a89e68e4d205aebd680492f2998be2dd53405051651e785b7e656" +checksum = "b8f79116b03882e60045e0b0f6ddeb68a832eb06876430230a8c891485385cbd" dependencies = [ - "swc_atoms 0.4.43", - "swc_common 0.30.5", + "swc_atoms", + "swc_common 0.37.5", "swc_xml_ast", ] [[package]] name = "swc_xml_visit" -version = "0.9.5" +version = "0.16.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c68a07347d9446a2f9b9f57c5e3e5fbd8ee5471f811a3ed307209402c5ec7375" +checksum = "560b3e810d9b5bbdfc7fdb5bd6879c3ee1a980d352e42b5961512cb0a79c55b6" dependencies = [ "serde", - "swc_atoms 0.4.43", - "swc_common 0.30.5", + "swc_atoms", + "swc_common 0.37.5", "swc_visit", "swc_xml_ast", ] @@ -6107,9 +6120,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.50" +version = "2.0.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74f1bdc9872430ce9b75da68329d1c1746faf50ffac5f19e02b71e37ff881ffb" +checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" dependencies = [ "proc-macro2", "quote", @@ -6124,22 +6137,22 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" -version = "3.8.0" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" +checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" dependencies = [ "cfg-if", - "fastrand 2.0.1", - "redox_syscall 0.3.5", - "rustix 0.38.3", - "windows-sys 0.48.0", + "fastrand 2.1.1", + "once_cell", + "rustix 0.38.37", + "windows-sys 0.59.0", ] [[package]] name = "termcolor" -version = "1.3.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6093bad37da69aab9d123a8091e4be0aa4a03e4d601ec641c327398315f62b64" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" dependencies = [ "winapi-util", ] @@ -6156,9 +6169,9 @@ dependencies = [ [[package]] name = "testing" -version = "0.34.1" +version = "0.38.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc31f7f4a7baef94495386462c2a55caa0f0885b61b28c120f783132d14938ed" +checksum = "9dda7450d6e429db582ca8a2cf698f3bc63bc04dae8d857936e810180e510c86" dependencies = [ "ansi_term", "cargo_metadata", @@ -6166,9 +6179,10 @@ dependencies = [ "once_cell", "pretty_assertions", "regex", + "serde", "serde_json", - "swc_common 0.32.1", - "swc_error_reporters", + "swc_common 0.36.3", + "swc_error_reporters 0.20.0", "testing_macros", "tracing", "tracing-subscriber", @@ -6176,19 +6190,18 @@ dependencies = [ [[package]] name = "testing_macros" -version = "0.2.11" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1c15b796025051a07f1ac695ee0cac0883f05a0d510c9d171ef8d31a992e6a5" +checksum = "a39660370116afe46d5ff8bcb01b7afe2140dda3137ef5cb1914681e37a4ee06" dependencies = [ "anyhow", "glob", "once_cell", - "pmutil 0.6.1", "proc-macro2", "quote", "regex", "relative-path", - "syn 2.0.50", + "syn 2.0.77", ] [[package]] @@ -6202,31 +6215,42 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "textwrap" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" +dependencies = [ + "smawk", + "unicode-linebreak", + "unicode-width", +] + [[package]] name = "thiserror" -version = "1.0.61" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" +checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.61" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" +checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.77", ] [[package]] name = "thread_local" -version = "1.1.7" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" dependencies = [ "cfg-if", "once_cell", @@ -6254,11 +6278,14 @@ dependencies = [ [[package]] name = "time" -version = "0.3.22" +version = "0.3.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea9e1b3cf1243ae005d9e74085d4d542f3125458f3a81af210d901dcd7411efd" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" dependencies = [ + "deranged", "itoa", + "num-conv", + "powerfmt", "serde", "time-core", "time-macros", @@ -6266,16 +6293,17 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.9" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "372950940a5f07bf38dbe211d7283c9e6d7327df53794992d293e534c733d09b" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" dependencies = [ + "num-conv", "time-core", ] @@ -6306,9 +6334,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.6.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" dependencies = [ "tinyvec_macros", ] @@ -6321,18 +6349,17 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.28.2" +version = "1.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94d7b1cfd2aa4011f2de74c2c4c63665e27a71006b0a192dcd2710272e73dfa2" +checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" dependencies = [ - "autocfg", + "backtrace", "bytes", "libc", - "mio", - "num_cpus", + "mio 1.0.2", "pin-project-lite", - "socket2", - "windows-sys 0.48.0", + "socket2 0.5.7", + "windows-sys 0.52.0", ] [[package]] @@ -6349,16 +6376,15 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.8" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" +checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" dependencies = [ "bytes", "futures-core", "futures-sink", "pin-project-lite", "tokio", - "tracing", ] [[package]] @@ -6372,76 +6398,75 @@ dependencies = [ [[package]] name = "toml" -version = "0.7.6" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c17e963a819c331dcacd7ab957d80bc2b9a9c1e71c804826d2f283dd65306542" +checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257" dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.19.12", + "toml_edit 0.19.15", ] [[package]] name = "toml" -version = "0.8.2" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "185d8ab0dfbb35cf1399a6344d8484209c088f75f8f68230da55d48d95d43e3d" +checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.20.2", + "toml_edit 0.22.20", ] [[package]] name = "toml_datetime" -version = "0.6.3" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.19.12" +version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c500344a19072298cd05a7224b3c0c629348b78692bf48466c5238656e315a78" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.2.6", + "indexmap 2.5.0", "serde", "serde_spanned", "toml_datetime", - "winnow 0.4.7", + "winnow 0.5.40", ] [[package]] name = "toml_edit" -version = "0.20.2" +version = "0.22.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" +checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" dependencies = [ - "indexmap 2.2.6", + "indexmap 2.5.0", "serde", "serde_spanned", "toml_datetime", - "winnow 0.5.26", + "winnow 0.6.18", ] [[package]] name = "tower-service" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.37" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "cfg-if", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -6449,20 +6474,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.24" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f57e3ca2a01450b1a921183a9c9cbfda207fd822cef4ccb00a65402cbba7a74" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.77", ] [[package]] name = "tracing-core" -version = "0.1.31" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", "valuable", @@ -6470,20 +6495,20 @@ dependencies = [ [[package]] name = "tracing-log" -version = "0.1.3" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" dependencies = [ - "lazy_static", "log", + "once_cell", "tracing-core", ] [[package]] name = "tracing-subscriber" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" dependencies = [ "matchers", "nu-ansi-term", @@ -6499,9 +6524,9 @@ dependencies = [ [[package]] name = "triomphe" -version = "0.1.8" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1ee9bd9239c339d714d657fac840c6d2a4f9c45f4f9ec7b0975113458be78db" +checksum = "e6631e42e10b40c0690bf92f404ebcfe6e1fdb480391d15f17cc8e96eeed5369" dependencies = [ "serde", "stable_deref_trait", @@ -6509,15 +6534,15 @@ dependencies = [ [[package]] name = "try-lock" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "ttf-parser" -version = "0.19.2" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49d64318d8311fc2668e48b63969f4343e0a85c4a109aa8460d6672e364b8bd1" +checksum = "5be21190ff5d38e8b4a2d3b6a3ae57f612cc39c96e83cedeaf7abc338a8bac4a" [[package]] name = "tungstenite" @@ -6557,9 +6582,9 @@ checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" [[package]] name = "typenum" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "typescript_tsconfig_json" @@ -6568,7 +6593,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7cc416eaf05297012ead9d192226fe9a92e9a20f64f8780efb9085aaae9b590" dependencies = [ "clean-path", - "indexmap 2.2.6", + "indexmap 2.5.0", "rustc-hash", "serde", "serde_json", @@ -6582,83 +6607,86 @@ checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" [[package]] name = "uds_windows" -version = "1.0.2" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce65604324d3cce9b966701489fbd0cf318cb1f7bd9dd07ac9a4ee6fb791930d" +checksum = "89daebc3e6fd160ac4aa9fc8b3bf71e1f74fbf92367ae71fb83a037e8bf164b9" dependencies = [ + "memoffset 0.9.1", "tempfile", "winapi 0.3.9", ] [[package]] name = "unicase" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" +checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" dependencies = [ "version_check", ] [[package]] name = "unicode-bidi" -version = "0.3.13" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" [[package]] name = "unicode-id" -version = "0.3.3" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1b6def86329695390197b82c1e244a54a131ceb66c996f2088a3876e2ae083f" + +[[package]] +name = "unicode-id-start" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d70b6494226b36008c8366c288d77190b3fad2eb4c10533139c1c1f461127f1a" +checksum = "bc3882f69607a2ac8cc4de3ee7993d8f68bb06f2974271195065b3bd07f2edea" [[package]] name = "unicode-ident" -version = "1.0.9" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] name = "unicode-linebreak" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5faade31a542b8b35855fff6e8def199853b2da8da256da52f52f1316ee3137" -dependencies = [ - "hashbrown 0.12.3", - "regex", -] +checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" [[package]] name = "unicode-normalization" -version = "0.1.22" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" dependencies = [ "tinyvec", ] [[package]] name = "unicode-segmentation" -version = "1.10.1" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "unicode-width" -version = "0.1.10" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" +checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" [[package]] name = "unsafe-libyaml" -version = "0.2.8" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1865806a559042e51ab5414598446a5871b561d21b6764f2eabb0dd481d880a6" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" [[package]] name = "url" -version = "2.5.0" +version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" dependencies = [ "form_urlencoded", "idna", @@ -6671,17 +6699,23 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" +[[package]] +name = "utf8-width" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86bd8d4e895da8537e5315b8254664e6b769c4ff3db18321b297a1e7004392e3" + [[package]] name = "utf8parse" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.6.1" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e395fcf16a7a3d8127ec99782007af141946b4795001f876d54fb0d55978560" +checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" [[package]] name = "valuable" @@ -6691,9 +6725,9 @@ checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" [[package]] name = "vec1" -version = "1.10.1" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bda7c41ca331fe9a1c278a9e7ee055f4be7f5eb1c2b72f079b4ff8b5fce9d5c" +checksum = "eab68b56840f69efb0fefbe3ab6661499217ffdc58e2eef7c3f6f69835386322" [[package]] name = "vec_map" @@ -6703,30 +6737,54 @@ checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" [[package]] name = "vergen" -version = "7.5.1" +version = "8.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f21b881cd6636ece9735721cf03c1fe1e774fe258683d084bb2812ab67435749" +checksum = "2990d9ea5967266ea0ccf413a4aa5c42a93dbcfda9cb49a97de6931726b12566" dependencies = [ "anyhow", - "cfg-if", - "enum-iterator", + "cargo_metadata", + "regex", + "rustversion", +] + +[[package]] +name = "vergen" +version = "9.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c32e7318e93a9ac53693b6caccfb05ff22e04a44c7cf8a279051f24c09da286f" +dependencies = [ + "anyhow", + "cargo_metadata", + "derive_builder", + "getset", + "regex", + "rustversion", + "vergen-lib", +] + +[[package]] +name = "vergen-lib" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e06bee42361e43b60f363bad49d63798d0f42fb1768091812270eca00c784720" +dependencies = [ + "anyhow", + "derive_builder", "getset", "rustversion", - "thiserror", - "time", ] [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "waker-fn" -version = "1.1.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3c4517f54858c779bbcbf228f4fca63d121bf85fbecb2dc578cdf4a39395690" +checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7" [[package]] name = "walkdir" @@ -6740,11 +6798,10 @@ dependencies = [ [[package]] name = "want" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" dependencies = [ - "log", "try-lock", ] @@ -6756,34 +6813,35 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.86" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bba0e8cb82ba49ff4e229459ff22a191bbe9a1cb3a341610c9c33efc27ddf73" +checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" dependencies = [ "cfg-if", + "once_cell", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.86" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b04bc93f9d6bdee709f6bd2118f57dd6679cf1176a1af464fca3ab0d66d8fb" +checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.77", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.36" +version = "0.4.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d1985d03709c53167ce907ff394f5316aa22cb4e12761295c5dc57dacb6297e" +checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed" dependencies = [ "cfg-if", "js-sys", @@ -6793,9 +6851,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.86" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14d6b024f1a526bb0234f52840389927257beb670610081360e5a03c5df9c258" +checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -6803,22 +6861,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.86" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e128beba882dd1eb6200e1dc92ae6c5dbaa4311aa7bb211ca035779e5efc39f8" +checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.77", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.86" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed9d5b4305409d1fc9482fee2d7f9bcbf24b3972bf59817ef757e23982242a93" +checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" [[package]] name = "wayland-client" @@ -6907,9 +6965,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.63" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bdd9ef4e984da1187bf8110c5cf5b845fbc87a23602cdf912386a76fcd3a7c2" +checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" dependencies = [ "js-sys", "wasm-bindgen", @@ -6917,9 +6975,9 @@ dependencies = [ [[package]] name = "webbrowser" -version = "0.8.11" +version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2c79b77f525a2d670cb40619d7d9c673d09e0666f72c591ebd7861f84a87e57" +checksum = "db67ae75a9405634f5882791678772c94ff5f16a66535aae186e26aa0841fc8b" dependencies = [ "core-foundation", "home", @@ -6956,20 +7014,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi 0.3.9", -] - -[[package]] -name = "winapi-wsapoll" -version = "0.1.1" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c17110f57155602a80dca10be03852116403c9ff3cd25b079d666f2aa3df6e" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "winapi 0.3.9", + "windows-sys 0.59.0", ] [[package]] @@ -6986,16 +7035,16 @@ checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" dependencies = [ "windows-implement", "windows-interface", - "windows-targets 0.48.0", + "windows-targets 0.48.5", ] [[package]] name = "windows-core" -version = "0.50.0" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af6041b3f84485c21b57acdc0fee4f4f0c93f426053dc05fa5d6fc262537bbff" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.48.0", + "windows-targets 0.52.6", ] [[package]] @@ -7035,7 +7084,25 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets 0.48.0", + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", ] [[package]] @@ -7055,17 +7122,17 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm 0.48.0", - "windows_aarch64_msvc 0.48.0", - "windows_i686_gnu 0.48.0", - "windows_i686_msvc 0.48.0", - "windows_x86_64_gnu 0.48.0", - "windows_x86_64_gnullvm 0.48.0", - "windows_x86_64_msvc 0.48.0", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", ] [[package]] @@ -7092,9 +7159,9 @@ checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" @@ -7110,9 +7177,9 @@ checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" [[package]] name = "windows_aarch64_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" @@ -7128,9 +7195,9 @@ checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" [[package]] name = "windows_i686_gnu" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" @@ -7152,9 +7219,9 @@ checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" [[package]] name = "windows_i686_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" @@ -7170,9 +7237,9 @@ checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" [[package]] name = "windows_x86_64_gnu" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" @@ -7188,9 +7255,9 @@ checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" @@ -7206,9 +7273,9 @@ checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" [[package]] name = "windows_x86_64_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" @@ -7231,9 +7298,9 @@ dependencies = [ "instant", "libc", "log", - "mio", + "mio 0.8.11", "ndk", - "objc2", + "objc2 0.3.0-beta.3.patch-leaks.3", "once_cell", "orbclient", "percent-encoding", @@ -7253,18 +7320,18 @@ dependencies = [ [[package]] name = "winnow" -version = "0.4.7" +version = "0.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca0ace3845f0d96209f0375e6d367e3eb87eb65d27d445bdc9f1843a26f39448" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" dependencies = [ "memchr", ] [[package]] name = "winnow" -version = "0.5.26" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b67b5f0a4e7a27a64c651977932b9dc5667ca7fc31ac44b03ed37a0cf42fdfff" +checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" dependencies = [ "memchr", ] @@ -7291,50 +7358,42 @@ dependencies = [ [[package]] name = "x11rb" -version = "0.10.1" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "592b4883219f345e712b3209c62654ebda0bb50887f330cbd018d0f654bfd507" +checksum = "5d91ffca73ee7f68ce055750bf9f6eca0780b8c85eff9bc046a3b0da41755e12" dependencies = [ "gethostname", - "nix 0.24.3", - "winapi 0.3.9", - "winapi-wsapoll", + "rustix 0.38.37", "x11rb-protocol", ] [[package]] name = "x11rb-protocol" -version = "0.10.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56b245751c0ac9db0e006dc812031482784e434630205a93c73cfefcaabeac67" -dependencies = [ - "nix 0.24.3", -] +checksum = "ec107c4503ea0b4a98ef47356329af139c0a4f7750e621cf2973cd3385ebcb3d" [[package]] name = "xcursor" -version = "0.3.4" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "463705a63313cd4301184381c5e8042f0a7e9b4bb63653f216311d4ae74690b7" -dependencies = [ - "nom", -] +checksum = "0ef33da6b1660b4ddbfb3aef0ade110c8b8a781a3b6382fa5f2b5b040fd55f61" [[package]] name = "xdg-home" -version = "1.0.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2769203cd13a0c6015d515be729c526d041e9cf2c0cc478d57faee85f40c6dcd" +checksum = "ec1cdab258fb55c0da61328dc52c8764709b249011b2cad0454c72f0bf10a1f6" dependencies = [ - "nix 0.26.4", - "winapi 0.3.9", + "libc", + "windows-sys 0.59.0", ] [[package]] name = "xml-rs" -version = "0.8.14" +version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52839dc911083a8ef63efa4d039d1f58b5e409f923e44c80828f206f66e5541c" +checksum = "af4e2e2f7cba5a093896c1e150fbfe177d1883e7448200efb81d40b9d339ef26" [[package]] name = "yaml-rust" @@ -7353,15 +7412,15 @@ checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" [[package]] name = "zbus" -version = "3.14.1" +version = "3.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31de390a2d872e4cd04edd71b425e29853f786dc99317ed72d73d6fcf5ebb948" +checksum = "675d170b632a6ad49804c8cf2105d7c31eddd3312555cffd4b740e08e97c25e6" dependencies = [ "async-broadcast", "async-executor", "async-fs", - "async-io", - "async-lock", + "async-io 1.13.0", + "async-lock 2.8.0", "async-process", "async-recursion", "async-task", @@ -7370,7 +7429,7 @@ dependencies = [ "byteorder", "derivative", "enumflags2", - "event-listener", + "event-listener 2.5.3", "futures-core", "futures-sink", "futures-util", @@ -7394,9 +7453,9 @@ dependencies = [ [[package]] name = "zbus_macros" -version = "3.14.1" +version = "3.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d1794a946878c0e807f55a397187c11fc7a038ba5d868e7db4f3bd7760bc9d" +checksum = "7131497b0f887e8061b430c530240063d33bf9455fa34438f388a245da69e0a5" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -7408,9 +7467,9 @@ dependencies = [ [[package]] name = "zbus_names" -version = "2.6.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb80bb776dbda6e23d705cf0123c3b95df99c4ebeaec6c2599d4a5419902b4a9" +checksum = "437d738d3750bed6ca9b8d423ccc7a8eb284f6b1d6d4e225a0e4e6258d864c8d" dependencies = [ "serde", "static_assertions", @@ -7419,29 +7478,30 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.7.26" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e97e415490559a91254a2979b4829267a57d2fcd741a98eee8b722fb57289aa0" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ + "byteorder", "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.26" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd7e48ccf166952882ca8bd778a43502c64f33bf94c12ebe2a7f08e5a0f6689f" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.77", ] [[package]] name = "zvariant" -version = "3.15.0" +version = "3.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44b291bee0d960c53170780af148dca5fa260a63cdd24f1962fa82e03e53338c" +checksum = "4eef2be88ba09b358d3b58aca6e41cd853631d44787f319a1383ca83424fb2db" dependencies = [ "byteorder", "enumflags2", @@ -7453,9 +7513,9 @@ dependencies = [ [[package]] name = "zvariant_derive" -version = "3.15.0" +version = "3.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "934d7a7dfc310d6ee06c87ffe88ef4eca7d3e37bb251dece2ef93da8f17d8ecd" +checksum = "37c24dc0bed72f5f90d1f8bb5b07228cbf63b3c6e9f82d82559d4bae666e7ed9" dependencies = [ "proc-macro-crate", "proc-macro2", diff --git a/Cargo.toml b/Cargo.toml index 4438e1242..7f4044b07 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,11 +5,13 @@ resolver = "2" [workspace.dependencies] anyhow = "1.0.71" cached = "0.46.1" +clap = "4.3.11" mimalloc-rust = { version = "=0.2.1" } oneshot = "0.1.8" -serde = { version = "1.0.171", features = ["derive"] } +regex = "1.9.3" +serde = "1.0.171" serde_json = "1.0.100" -swc_core = { version = "=0.83.22", default-features = false } +swc_core = { version = "0.101.4", default-features = false } tikv-jemallocator = { version = "=0.5.4", features = ["disable_initial_exec_tls"] } [profile.release] diff --git a/biome.json b/biome.json index 6763f765f..381930e4b 100644 --- a/biome.json +++ b/biome.json @@ -20,7 +20,8 @@ "./tmp/**", "./.pnpm-store/**", "./packages/*/dist/**", - "**/package.json" + "**/package.json", + "./crates/svgr-rs/__fixture__/**" ] }, "formatter": { diff --git a/crates/mako/Cargo.toml b/crates/mako/Cargo.toml index e2608a694..4c0cc4cc2 100644 --- a/crates/mako/Cargo.toml +++ b/crates/mako/Cargo.toml @@ -14,7 +14,6 @@ test = false bitflags = { version = "2.4.2", features = ["serde"] } cached = { workspace = true } dashmap = "4.0.1" -delegate = "0.12.0" fixedbitset = "0.4.2" get_if_addrs = "0.5.3" glob-match = "0.2.1" @@ -30,13 +29,6 @@ serde_json = { workspace = true } url = { version = "2.5.0" } swc_core = { workspace = true, features = [ - "__ecma", - "__ecma_plugin_transform", - "__ecma_transforms", - "__parser", - "__testing_transform", - "__utils", - "__visit", "base", "common_concurrent", "common_sourcemap", @@ -50,11 +42,11 @@ swc_core = { workspace = true, features = [ "css_prefixer", "css_utils", "css_visit", - "css_visit_path", "ecma_ast", "ecma_codegen", "ecma_minifier", "ecma_minifier_concurrent", + "ecma_parser", "ecma_preset_env", "ecma_quote", "ecma_transforms_compat", @@ -63,18 +55,19 @@ swc_core = { workspace = true, features = [ "ecma_transforms_proposal", "ecma_transforms_react", "ecma_transforms_typescript", + "ecma_utils", "ecma_visit_path", "swc_ecma_quote_macros", ] } -swc_emotion = "0.51.0" -swc_error_reporters = "0.16.1" -swc_node_comments = "0.19.1" +swc_emotion = "0.72.19" +swc_error_reporters = "0.21.0" +swc_node_comments = "0.24.0" anyhow = { workspace = true } base64 = "0.22.1" chrono = "0.4.38" -clap = { version = "4.3.11", features = ["derive"] } +clap = { workspace = true, features = ["derive"] } colored = "2" config = "0.13.3" convert_case = "0.6.0" @@ -89,7 +82,7 @@ hyper-tungstenite = "0.10.0" indexmap = "2.0.0" indicatif = "0.17.8" md5 = "0.7.0" -mdxjs = "0.1.14" +mdxjs = "0.2.6" mime_guess = "2.0.4" notify = { version = "6.1.1", default-features = false, features = ["macos_kqueue"] } notify-debouncer-full = { version = "0.3.1", default-features = false } @@ -100,12 +93,12 @@ petgraph = "0.6.3" puffin = { version = "0.16.0", optional = true } puffin_egui = { version = "0.22.0", optional = true } rayon = "1.7.0" -regex = "1.9.3" +regex = { workspace = true } sailfish = "0.8.3" semver = "1.0.23" serde-xml-rs = "0.6.0" serde_yaml = "0.9.22" -svgr-rs = "0.1.3" +svgr-rs = { path = "../svgr-rs" } thiserror = "1.0.43" tokio = { version = "1", features = ["rt-multi-thread", "sync"] } tokio-tungstenite = "0.19.0" diff --git a/crates/mako/src/ast.rs b/crates/mako/src/ast.rs index 6995a5303..e131721a9 100644 --- a/crates/mako/src/ast.rs +++ b/crates/mako/src/ast.rs @@ -1,3 +1,5 @@ +use swc_core::common::SyntaxContext; + pub(crate) mod comments; pub(crate) mod css_ast; pub(crate) mod error; @@ -7,3 +9,5 @@ pub(crate) mod sourcemap; #[cfg(test)] pub mod tests; pub(crate) mod utils; + +pub const DUMMY_CTXT: SyntaxContext = SyntaxContext::empty(); diff --git a/crates/mako/src/ast/comments.rs b/crates/mako/src/ast/comments.rs index afc76e75f..078a81fe2 100644 --- a/crates/mako/src/ast/comments.rs +++ b/crates/mako/src/ast/comments.rs @@ -1,14 +1,13 @@ -use delegate::delegate; use swc_core::common; use swc_core::common::comments::{Comment, Comments as CommentsTrait}; use swc_core::common::{BytePos, Span}; use swc_node_comments::SwcComments; #[derive(Default)] -pub struct Comments(MakoComments); +pub struct Comments(SwcComments); impl Comments { - pub fn get_swc_comments(&self) -> &MakoComments { + pub fn get_swc_comments(&self) -> &SwcComments { &self.0 } @@ -85,38 +84,3 @@ impl Comments { found } } - -#[derive(Clone, Default)] -pub struct MakoComments(SwcComments); - -impl CommentsTrait for MakoComments { - fn add_pure_comment(&self, pos: BytePos) { - //ref: https://github.com/swc-project/swc/pull/8172 - if pos.is_dummy() { - #[cfg(debug_assertions)] - { - use tracing::warn; - warn!("still got pure comments at dummy pos! UPGRADE SWC!!!"); - } - return; - } - self.0.add_pure_comment(pos); - } - - delegate! { - to self.0 { - fn add_leading(&self, pos: BytePos, cmt: Comment); - fn add_leading_comments(&self, pos: BytePos, comments: Vec); - fn has_leading(&self, pos: BytePos) -> bool; - fn move_leading(&self, from: BytePos, to: BytePos); - fn take_leading(&self, pos: BytePos) -> Option>; - fn get_leading(&self, pos: BytePos) -> Option>; - fn add_trailing(&self, pos: BytePos, cmt: Comment); - fn add_trailing_comments(&self, pos: BytePos, comments: Vec); - fn has_trailing(&self, pos: BytePos) -> bool; - fn move_trailing(&self, from: BytePos, to: BytePos); - fn take_trailing(&self, pos: BytePos) -> Option>; - fn get_trailing(&self, pos: BytePos) -> Option>; - } - } -} diff --git a/crates/mako/src/ast/css_ast.rs b/crates/mako/src/ast/css_ast.rs index 12d55e841..931ae6b99 100644 --- a/crates/mako/src/ast/css_ast.rs +++ b/crates/mako/src/ast/css_ast.rs @@ -37,7 +37,7 @@ impl fmt::Debug for CssAst { impl CssAst { pub fn new(file: &File, context: Arc, css_modules: bool) -> Result { let fm = context.meta.css.cm.new_source_file( - FileName::Real(file.relative_path.clone()), + FileName::Real(file.relative_path.clone()).into(), file.get_content_raw(), ); let config = parser::parser::ParserConfig { @@ -45,7 +45,10 @@ impl CssAst { legacy_ie: true, ..Default::default() }; - let lexer = parser::lexer::Lexer::new(StringInput::from(&*fm), config); + + let comments = context.meta.css.comments.clone(); + + let lexer = parser::lexer::Lexer::new(StringInput::from(&*fm), Some(&comments), config); let mut parser = parser::parser::Parser::new(lexer, config); let parse_result = parser.parse_all(); let mut ast_errors = parser.take_errors(); diff --git a/crates/mako/src/ast/js_ast.rs b/crates/mako/src/ast/js_ast.rs index d08e37360..b6a3c9edd 100644 --- a/crates/mako/src/ast/js_ast.rs +++ b/crates/mako/src/ast/js_ast.rs @@ -9,7 +9,7 @@ use swc_core::ecma::codegen::text_writer::JsWriter; use swc_core::ecma::codegen::{Config as JsCodegenConfig, Emitter}; use swc_core::ecma::parser::error::SyntaxError; use swc_core::ecma::parser::lexer::Lexer; -use swc_core::ecma::parser::{EsConfig, Parser, StringInput, Syntax, TsConfig}; +use swc_core::ecma::parser::{EsSyntax, Parser, StringInput, Syntax, TsSyntax}; use swc_core::ecma::transforms::base::helpers::inject_helpers; use swc_core::ecma::utils::contains_top_level_await; use swc_core::ecma::visit; @@ -42,13 +42,13 @@ impl fmt::Debug for JsAst { impl JsAst { pub fn new(file: &File, context: Arc) -> Result { let fm = context.meta.script.cm.new_source_file( - FileName::Real(file.path.to_path_buf()), + FileName::Real(file.relative_path.to_path_buf()).into(), file.get_content_raw(), ); let comments = context.meta.script.origin_comments.read().unwrap(); let extname = &file.extname; let syntax = if extname == "ts" || extname == "tsx" { - Syntax::Typescript(TsConfig { + Syntax::Typescript(TsSyntax { tsx: extname == "tsx", decorators: true, ..Default::default() @@ -57,7 +57,7 @@ impl JsAst { let jsx = file.is_content_jsx() || extname == "jsx" || (extname == "js" && !file.is_under_node_modules); - Syntax::Es(EsConfig { + Syntax::Es(EsSyntax { jsx, decorators: true, decorators_before_export: true, diff --git a/crates/mako/src/ast/sourcemap.rs b/crates/mako/src/ast/sourcemap.rs index 392729f8c..1caf96cc0 100644 --- a/crates/mako/src/ast/sourcemap.rs +++ b/crates/mako/src/ast/sourcemap.rs @@ -68,11 +68,22 @@ impl From for RawSourceMap { impl From for swc_sourcemap::SourceMap { fn from(rsm: RawSourceMap) -> Self { Self::new( - rsm.file, + rsm.file.map(|f| f.into_boxed_str().into()), rsm.tokens, - rsm.names, - rsm.sources, - Some(rsm.sources_content), + rsm.names + .into_iter() + .map(|n| n.into_boxed_str().into()) + .collect(), + rsm.sources + .into_iter() + .map(|n| n.into_boxed_str().into()) + .collect(), + Some( + rsm.sources_content + .into_iter() + .map(|op_string| op_string.map(|s| s.into_boxed_str().into())) + .collect(), + ), ) } } @@ -126,9 +137,10 @@ pub fn merge_source_map( final_token.get_src_col(), replaced_source.as_deref(), final_token.get_name(), + false, ); - // add source centent + // add source content if !builder.has_source_contents(added_token.src_id) { let source_content = final_token.get_source_view().map(|view| view.source()); diff --git a/crates/mako/src/ast/utils.rs b/crates/mako/src/ast/utils.rs index 7c0626001..2ef8ba3be 100644 --- a/crates/mako/src/ast/utils.rs +++ b/crates/mako/src/ast/utils.rs @@ -1,7 +1,7 @@ use swc_core::common::{Mark, DUMMY_SP}; use swc_core::ecma::ast::{ - CallExpr, Callee, Expr, ExprOrSpread, Ident, Import, Lit, MemberExpr, MemberProp, MetaPropExpr, - MetaPropKind, Module, ModuleItem, + CallExpr, Callee, Expr, ExprOrSpread, Ident, IdentName, Import, Lit, MemberExpr, MemberProp, + MetaPropExpr, MetaPropKind, Module, ModuleItem, }; pub fn is_remote_or_data(url: &str) -> bool { @@ -66,7 +66,7 @@ pub fn get_call_expr_ident(call_expr: &CallExpr) -> Option<&Ident> { } pub fn is_ident_undefined(ident: &Ident, sym: &str, unresolved_mark: &Mark) -> bool { - ident.sym == *sym && ident.span.ctxt.outer() == *unresolved_mark + ident.sym == *sym && ident.ctxt.outer() == *unresolved_mark } pub fn get_first_str_arg(call_expr: &CallExpr) -> Option { @@ -92,7 +92,7 @@ pub fn is_import_meta_url(expr: &Expr) -> bool { .. }), prop: - MemberProp::Ident(Ident { + MemberProp::Ident(IdentName { sym, .. }), @@ -103,16 +103,16 @@ pub fn is_import_meta_url(expr: &Expr) -> bool { pub fn id(s: &str) -> Ident { Ident { + ctxt: Default::default(), span: DUMMY_SP, sym: s.into(), optional: false, } } pub fn member_prop(s: &str) -> MemberProp { - MemberProp::Ident(Ident { + MemberProp::Ident(IdentName { span: DUMMY_SP, sym: s.into(), - optional: false, }) } @@ -127,6 +127,7 @@ pub fn promise_all(promises: ExprOrSpread) -> Expr { pub fn member_call(obj: Expr, member_prop: MemberProp, args: Vec) -> Expr { Expr::Call(CallExpr { span: DUMMY_SP, + ctxt: Default::default(), callee: Callee::Expr(Box::new(Expr::Member(MemberExpr { span: DUMMY_SP, obj: Box::new(obj), @@ -140,7 +141,7 @@ pub fn member_call(obj: Expr, member_prop: MemberProp, args: Vec) pub fn require_ensure(source: String) -> Expr { member_call( Expr::Ident(id("__mako_require__")), - MemberProp::Ident(id("ensure")), + MemberProp::Ident(id("ensure").into()), vec![ExprOrSpread { spread: None, expr: Box::new(Expr::Lit(Lit::Str(source.into()))), diff --git a/crates/mako/src/build/load.rs b/crates/mako/src/build/load.rs index dfa2b95a9..401fd9e52 100644 --- a/crates/mako/src/build/load.rs +++ b/crates/mako/src/build/load.rs @@ -135,7 +135,7 @@ export function moduleToDom(css) { Err(reason) => { return Err(anyhow!(LoadError::CompileMdError { path: file.path.to_string_lossy().to_string(), - reason, + reason: reason.to_string(), })); } }; diff --git a/crates/mako/src/build/transform.rs b/crates/mako/src/build/transform.rs index 4f57cf79d..b02ce7469 100644 --- a/crates/mako/src/build/transform.rs +++ b/crates/mako/src/build/transform.rs @@ -98,13 +98,15 @@ impl Transform { cm.clone(), context.clone(), top_level_mark, + unresolved_mark, ))) } // strip should be ts only // since when use this in js, it will remove all unused imports // which is not expected as what webpack does if is_ts { - visitors.push(Box::new(ts_strip(top_level_mark))) + visitors + .push(Box::new(ts_strip(unresolved_mark, top_level_mark))); } // named default export if context.args.watch && !file.is_under_node_modules && is_jsx { diff --git a/crates/mako/src/compiler.rs b/crates/mako/src/compiler.rs index 0418a1f89..2f2a5703c 100644 --- a/crates/mako/src/compiler.rs +++ b/crates/mako/src/compiler.rs @@ -10,6 +10,7 @@ use regex::Regex; use swc_core::common::sync::Lrc; use swc_core::common::{Globals, SourceMap, DUMMY_SP}; use swc_core::ecma::ast::Ident; +use swc_node_comments::SwcComments; use tracing::debug; use crate::ast::comments::Comments; @@ -182,6 +183,7 @@ impl ScriptMeta { fn build_ident(ident: &str) -> Ident { Ident { + ctxt: Default::default(), span: DUMMY_SP, sym: ident.into(), optional: false, @@ -191,6 +193,7 @@ fn build_ident(ident: &str) -> Ident { pub struct CssMeta { pub cm: Lrc, pub globals: Globals, + pub comments: SwcComments, } impl CssMeta { @@ -198,6 +201,7 @@ impl CssMeta { Self { cm: Default::default(), globals: Globals::default(), + comments: Default::default(), } } } diff --git a/crates/mako/src/features/node.rs b/crates/mako/src/features/node.rs index 3a6cd09a7..50356e822 100644 --- a/crates/mako/src/features/node.rs +++ b/crates/mako/src/features/node.rs @@ -139,10 +139,10 @@ pub struct MockFilenameAndDirname { impl VisitMut for MockFilenameAndDirname { fn visit_mut_expr(&mut self, expr: &mut Expr) { if let Expr::Ident(ident) = expr - && ident.span.ctxt.outer() == self.unresolved_mark + && ident.ctxt.outer() == self.unresolved_mark { - let is_filename = ident.sym.to_string() == "__filename"; - let is_dirname = ident.sym.to_string() == "__dirname"; + let is_filename = ident.sym == "__filename"; + let is_dirname = ident.sym == "__dirname"; if is_filename || is_dirname { let path = diff_paths(&self.current_path, &self.context.root).unwrap_or("".into()); let value = if is_filename { diff --git a/crates/mako/src/generate.rs b/crates/mako/src/generate.rs index c8a2ddc57..d3c454892 100644 --- a/crates/mako/src/generate.rs +++ b/crates/mako/src/generate.rs @@ -34,14 +34,6 @@ use crate::stats::StatsJsonMap; use crate::utils::base64_encode; use crate::visitors::async_module::mark_async; -#[derive(Clone)] -pub struct EmitFile { - pub filename: String, - pub content: String, - pub chunk_id: String, - pub hashname: String, -} - #[derive(Serialize)] struct ChunksUrlMap { js: HashMap, diff --git a/crates/mako/src/generate/chunk_pot.rs b/crates/mako/src/generate/chunk_pot.rs index c66602ef0..be774290c 100644 --- a/crates/mako/src/generate/chunk_pot.rs +++ b/crates/mako/src/generate/chunk_pot.rs @@ -12,7 +12,7 @@ use swc_core::css::ast::Stylesheet; use crate::compiler::Context; use crate::config::Mode; -use crate::generate::chunk::{Chunk, ChunkType}; +use crate::generate::chunk::Chunk; pub use crate::generate::chunk_pot::util::CHUNK_FILE_NAME_HASH_LENGTH; use crate::generate::chunk_pot::util::{hash_hashmap, hash_vec}; use crate::generate::generate_chunks::ChunkFile; @@ -22,7 +22,6 @@ use crate::ternary; pub struct ChunkPot<'a> { pub chunk_id: String, - pub chunk_type: ChunkType, pub js_name: String, pub module_map: HashMap, pub js_hash: u64, @@ -39,7 +38,6 @@ impl<'cp> ChunkPot<'cp> { ChunkPot { js_name: chunk.filename(), - chunk_type: chunk.chunk_type.clone(), chunk_id: chunk.id.id.clone(), module_map: js_modules.module_map, js_hash: js_modules.raw_hash, diff --git a/crates/mako/src/generate/chunk_pot/ast_impl.rs b/crates/mako/src/generate/chunk_pot/ast_impl.rs index 44372edce..390261905 100644 --- a/crates/mako/src/generate/chunk_pot/ast_impl.rs +++ b/crates/mako/src/generate/chunk_pot/ast_impl.rs @@ -395,7 +395,9 @@ fn wrap_in_iife(module: SwcModule) -> SwcModule { params: vec![], decorators: vec![], span: DUMMY_SP, + ctxt: Default::default(), body: Some(BlockStmt { + ctxt: Default::default(), span: DUMMY_SP, stmts, }), diff --git a/crates/mako/src/generate/chunk_pot/str_impl.rs b/crates/mako/src/generate/chunk_pot/str_impl.rs index c51a666cb..906759e62 100644 --- a/crates/mako/src/generate/chunk_pot/str_impl.rs +++ b/crates/mako/src/generate/chunk_pot/str_impl.rs @@ -221,11 +221,7 @@ fn pot_to_chunk_module_object_string( chunk_prefix_offset: u32, ) -> Result<(String, RawSourceMap)> { let sorted_kv = { - let mut sorted_kv = pot - .module_map - .iter() - .map(|(k, v)| (k, v)) - .collect::>(); + let mut sorted_kv = pot.module_map.iter().collect::>(); sorted_kv.sort_by_key(|(k, _)| *k); diff --git a/crates/mako/src/generate/chunk_pot/util.rs b/crates/mako/src/generate/chunk_pot/util.rs index 094c91d8f..b0c0966d2 100644 --- a/crates/mako/src/generate/chunk_pot/util.rs +++ b/crates/mako/src/generate/chunk_pot/util.rs @@ -10,7 +10,7 @@ use swc_core::common::comments::{Comment, CommentKind, Comments}; use swc_core::common::errors::HANDLER; use swc_core::common::{Span, DUMMY_SP, GLOBALS}; use swc_core::ecma::ast::{ - ArrayLit, AssignOp, BinaryOp, BlockStmt, CondExpr, Expr, ExprOrSpread, FnExpr, Function, Ident, + ArrayLit, AssignOp, BinaryOp, BlockStmt, CondExpr, Expr, ExprOrSpread, FnExpr, Function, KeyValueProp, Module as SwcModule, ObjectLit, Prop, PropOrSpread, UnaryExpr, UnaryOp, }; use swc_core::ecma::atoms::js_word; @@ -71,6 +71,7 @@ pub(crate) fn render_module_js( pub(crate) fn empty_module_fn_expr() -> FnExpr { let func = Function { span: DUMMY_SP, + ctxt: Default::default(), params: vec![ quote_ident!("module").into(), quote_ident!("exports").into(), @@ -78,6 +79,7 @@ pub(crate) fn empty_module_fn_expr() -> FnExpr { ], decorators: vec![], body: Some(BlockStmt { + ctxt: Default::default(), span: DUMMY_SP, stmts: vec![], }), @@ -132,7 +134,7 @@ where K: Hash + Eq + Ord, V: Hash, { - let mut sorted_kv = map.iter().map(|(k, v)| (k, v)).collect::>(); + let mut sorted_kv = map.iter().collect::>(); sorted_kv.sort_by_key(|(k, _)| *k); let mut hasher: XxHash64 = Default::default(); @@ -165,11 +167,7 @@ pub(super) fn to_array_lit(elems: Vec) -> ArrayLit { pub(crate) fn pot_to_module_object(pot: &ChunkPot, context: &Arc) -> Result { crate::mako_profile_function!(); - let mut sorted_kv = pot - .module_map - .iter() - .map(|(k, v)| (k, v)) - .collect::>(); + let mut sorted_kv = pot.module_map.iter().collect::>(); sorted_kv.sort_by_key(|(k, _)| *k); let mut props = Vec::new(); @@ -249,9 +247,9 @@ pub(crate) fn pot_to_chunk_module( } .into(), ) - .make_assign_to(AssignOp::Assign, chunk_global_expr.clone().as_pat_or_expr()) + .make_assign_to(AssignOp::Assign, chunk_global_expr.clone().into()) .wrap_with_paren() - .make_member::(quote_ident!("push")); + .make_member(quote_ident!("push")); let chunk_register_stmt = chunk_global_obj .as_call( DUMMY_SP, @@ -302,6 +300,7 @@ fn to_module_fn_expr(module: &Module) -> Result { let func = Function { span: DUMMY_SP, + ctxt: Default::default(), params: vec![ quote_ident!("module").into(), quote_ident!("exports").into(), @@ -310,6 +309,7 @@ fn to_module_fn_expr(module: &Module) -> Result { decorators: vec![], body: Some(BlockStmt { span: DUMMY_SP, + ctxt: Default::default(), stmts, }), is_generator: false, diff --git a/crates/mako/src/generate/minify.rs b/crates/mako/src/generate/minify.rs index 8b9feff36..7e155d32d 100644 --- a/crates/mako/src/generate/minify.rs +++ b/crates/mako/src/generate/minify.rs @@ -8,7 +8,7 @@ use swc_core::css::ast::Stylesheet; use swc_core::css::minifier; use swc_core::ecma::minifier::optimize; use swc_core::ecma::minifier::option::{ExtraOptions, MinifyOptions}; -use swc_core::ecma::transforms::base::fixer::fixer; +use swc_core::ecma::transforms::base::fixer::{fixer, paren_remover}; use swc_core::ecma::transforms::base::helpers::{Helpers, HELPERS}; use swc_core::ecma::transforms::base::resolver; use swc_core::ecma::visit::VisitMutWith; @@ -28,24 +28,21 @@ pub fn minify_js(ast: &mut JsAst, context: &Arc) -> Result<()> { let unresolved_mark = ast.unresolved_mark; let top_level_mark = ast.top_level_mark; + let comments_lock = context.meta.script.origin_comments.read().unwrap(); + + let comments = comments_lock.get_swc_comments(); + ast.ast.visit_mut_with(&mut resolver( unresolved_mark, top_level_mark, false, )); + ast.ast.visit_mut_with(&mut paren_remover(Some(comments))); let mut minified = optimize( ast.ast.clone().into(), context.meta.script.cm.clone(), - Some( - context - .meta - .script - .origin_comments - .read() - .unwrap() - .get_swc_comments(), - ), + Some(comments), None, &MinifyOptions { compress: Some(Default::default()), @@ -59,15 +56,7 @@ pub fn minify_js(ast: &mut JsAst, context: &Arc) -> Result<()> { ) .expect_module(); - minified.visit_mut_with(&mut fixer(Some( - context - .meta - .script - .origin_comments - .read() - .unwrap() - .get_swc_comments(), - ))); + minified.visit_mut_with(&mut fixer(Some(comments))); ast.ast = minified; Ok(()) diff --git a/crates/mako/src/generate/swc_helpers.rs b/crates/mako/src/generate/swc_helpers.rs index d5284fb5f..270ec7db1 100644 --- a/crates/mako/src/generate/swc_helpers.rs +++ b/crates/mako/src/generate/swc_helpers.rs @@ -3,6 +3,7 @@ use indexmap::IndexSet; use crate::share::helpers::SWC_HELPERS; pub struct SwcHelpers { + #[allow(dead_code)] pub helpers: IndexSet, } diff --git a/crates/mako/src/generate/transform.rs b/crates/mako/src/generate/transform.rs index fc8642131..fc8380cd2 100644 --- a/crates/mako/src/generate/transform.rs +++ b/crates/mako/src/generate/transform.rs @@ -213,7 +213,6 @@ pub fn transform_js_generate(transform_js_param: TransformJsParam) -> Result<()> to_replace: dep_map, context, unresolved_mark, - top_level_mark, }; ast.ast.visit_mut_with(&mut dep_replacer); @@ -323,7 +322,7 @@ mod tests { } fn transform_css_code(content: &str, path: Option<&str>) -> String { - let path = if let Some(p) = path { p } else { "test.css" }; + let path = path.unwrap_or("test.css"); let context: Arc = Arc::new(Default::default()); let mut ast = CssAst::build(path, content, context.clone(), false).unwrap(); transform_css_generate(&mut ast.ast, &context); diff --git a/crates/mako/src/lib.rs b/crates/mako/src/lib.rs index 2d3444c18..5bc0ede9a 100644 --- a/crates/mako/src/lib.rs +++ b/crates/mako/src/lib.rs @@ -1,7 +1,6 @@ #![feature(box_patterns)] #![feature(hasher_prefixfree_extras)] #![feature(let_chains)] -#![feature(result_option_inspect)] pub mod ast; mod build; diff --git a/crates/mako/src/main.rs b/crates/mako/src/main.rs index 45691164d..5663333e6 100644 --- a/crates/mako/src/main.rs +++ b/crates/mako/src/main.rs @@ -1,6 +1,5 @@ #![feature(box_patterns)] #![feature(let_chains)] -#![feature(result_option_inspect)] use std::sync::Arc; diff --git a/crates/mako/src/module.rs b/crates/mako/src/module.rs index ad8e43a95..bd814d952 100644 --- a/crates/mako/src/module.rs +++ b/crates/mako/src/module.rs @@ -453,6 +453,7 @@ impl Module { let func = Function { span: DUMMY_SP, + ctxt: Default::default(), params: vec![ quote_ident!("module").into(), quote_ident!("exports").into(), @@ -461,6 +462,7 @@ impl Module { decorators: vec![], body: Some(BlockStmt { span: DUMMY_SP, + ctxt: Default::default(), stmts, }), is_generator: false, @@ -488,6 +490,7 @@ impl Debug for Module { fn empty_module_fn_expr() -> FnExpr { let func = Function { + ctxt: Default::default(), span: DUMMY_SP, params: vec![ quote_ident!("module").into(), @@ -496,6 +499,7 @@ fn empty_module_fn_expr() -> FnExpr { ], decorators: vec![], body: Some(BlockStmt { + ctxt: Default::default(), span: DUMMY_SP, stmts: vec![], }), diff --git a/crates/mako/src/plugins/bundless_compiler.rs b/crates/mako/src/plugins/bundless_compiler.rs index 82f9f1024..68c10be36 100644 --- a/crates/mako/src/plugins/bundless_compiler.rs +++ b/crates/mako/src/plugins/bundless_compiler.rs @@ -235,7 +235,6 @@ fn transform_js_generate( to_replace: dep_map, context, unresolved_mark: ast.unresolved_mark, - top_level_mark: ast.top_level_mark, }; ast.ast.visit_mut_with(&mut dep_replacer); diff --git a/crates/mako/src/plugins/context_module.rs b/crates/mako/src/plugins/context_module.rs index e44b528a2..8acfa2870 100644 --- a/crates/mako/src/plugins/context_module.rs +++ b/crates/mako/src/plugins/context_module.rs @@ -13,6 +13,7 @@ use swc_core::ecma::visit::{VisitMut, VisitMutWith}; use crate::ast::file::{Content, JsContent}; use crate::ast::utils::{is_commonjs_require, is_dynamic_import}; +use crate::ast::DUMMY_CTXT; use crate::build::load::JS_EXTENSIONS; use crate::compiler::Context; use crate::plugin::{Plugin, PluginLoadParam}; @@ -151,6 +152,7 @@ impl VisitMut for ContextModuleVisitor { let args_literals = format!("{}?context&glob={}", from, glob); let mut ctxt_call_expr = CallExpr { + ctxt: Default::default(), callee: expr.callee.clone(), args: vec![quote_str!(args_literals.clone()).as_arg()], span: DUMMY_SP, @@ -175,7 +177,7 @@ impl VisitMut for ContextModuleVisitor { .as_callee(); // TODO: allow use await in args // eg: import(`./i18n${await xxx()}`) - expr.args = vec![member_expr!(DUMMY_SP, m.default) + expr.args = vec![member_expr!(DUMMY_CTXT, DUMMY_SP, m.default) .as_call(DUMMY_SP, expr.args.clone()) .as_expr() .to_owned() @@ -203,8 +205,7 @@ fn try_replace_context_arg( // handle `(...)` Expr::Paren(ParenExpr { expr: paren_expr, .. - }) => try_replace_context_arg(paren_expr, has_visit_top_bin) - .map(|(prefix, suffix)| (prefix, suffix)), + }) => try_replace_context_arg(paren_expr, has_visit_top_bin), // handle `'./foo/' + bar` Expr::Bin(BinExpr { diff --git a/crates/mako/src/plugins/invalid_webpack_syntax.rs b/crates/mako/src/plugins/invalid_webpack_syntax.rs index 85ce2708a..568888ab8 100644 --- a/crates/mako/src/plugins/invalid_webpack_syntax.rs +++ b/crates/mako/src/plugins/invalid_webpack_syntax.rs @@ -36,7 +36,6 @@ impl Plugin for InvalidWebpackSyntaxPlugin { ast.visit_with(&mut InvalidSyntaxVisitor { unresolved_mark: param.unresolved_mark, handler: param.handler, - path: param.path, }); Ok(()) } @@ -45,7 +44,6 @@ impl Plugin for InvalidWebpackSyntaxPlugin { pub struct InvalidSyntaxVisitor<'a> { unresolved_mark: Mark, pub handler: &'a Handler, - pub path: &'a str, } impl<'a> Visit for InvalidSyntaxVisitor<'a> { @@ -65,7 +63,7 @@ impl<'a> Visit for InvalidSyntaxVisitor<'a> { let is_webpack_prefix = n.sym.starts_with("__webpack_") && &n.sym != "__webpack_nonce__" && &n.sym != "__webpack_public_path__"; - let has_binding = n.span.ctxt.outer() != self.unresolved_mark; + let has_binding = n.ctxt.outer() != self.unresolved_mark; if is_webpack_prefix && !has_binding { self.handler .struct_span_err( @@ -92,9 +90,9 @@ fn is_member_prop( .. } = expr { - let is_obj_match = ident.sym.to_string() == obj; - let has_binding = ident.span.ctxt.outer() != unresolved_mark; - let is_prop_match = prop_ident.sym.to_string() == prop; + let is_obj_match = ident.sym == obj; + let has_binding = ident.ctxt.outer() != unresolved_mark; + let is_prop_match = prop_ident.sym == prop; is_obj_match && (check_obj_binding && !has_binding) && is_prop_match } else { false diff --git a/crates/mako/src/plugins/minifish/inject.rs b/crates/mako/src/plugins/minifish/inject.rs index c64d25311..fc30874e1 100644 --- a/crates/mako/src/plugins/minifish/inject.rs +++ b/crates/mako/src/plugins/minifish/inject.rs @@ -3,7 +3,7 @@ use std::hash::{Hash, Hasher}; use indexmap::IndexSet; use regex::Regex; -use swc_core::common::{Mark, Span, SyntaxContext, DUMMY_SP}; +use swc_core::common::{Mark, SyntaxContext, DUMMY_SP}; use swc_core::ecma::ast::{ ExportSpecifier, Ident, ImportDecl, ImportDefaultSpecifier, ImportNamedSpecifier, ImportSpecifier, ImportStarAsSpecifier, MemberExpr, ModuleDecl, ModuleItem, NamedExport, Stmt, @@ -12,6 +12,8 @@ use swc_core::ecma::ast::{ use swc_core::ecma::utils::{quote_ident, quote_str, ExprFactory}; use swc_core::ecma::visit::{VisitMut, VisitMutWith}; +use crate::ast::DUMMY_CTXT; + pub(super) struct MyInjector<'a> { unresolved_mark: Mark, injects: HashMap, @@ -36,11 +38,11 @@ impl VisitMut for MyInjector<'_> { return; } - if n.span.ctxt.outer() == self.unresolved_mark { + if n.ctxt.outer() == self.unresolved_mark { let name = n.sym.to_string(); if let Some(inject) = self.injects.remove(&name) { - self.will_inject.insert((inject, n.span.ctxt)); + self.will_inject.insert((inject, n.ctxt)); } } } @@ -116,9 +118,10 @@ impl Hash for Inject { impl Inject { fn into_require_with(self, ctxt: SyntaxContext, unresolved_mark: Mark) -> ModuleItem { - let name_span = Span { ctxt, ..DUMMY_SP }; + let name_span = DUMMY_SP; + let unresolved_ctxt = DUMMY_CTXT.apply_mark(unresolved_mark); - let require_source_expr = quote_ident!(DUMMY_SP.apply_mark(unresolved_mark), "require") + let require_source_expr = quote_ident!(unresolved_ctxt, DUMMY_SP, "require") .as_call(DUMMY_SP, vec![quote_str!(self.from).as_arg()]); let stmt: Stmt = match (&self.named, &self.namespace) { @@ -130,14 +133,14 @@ impl Inject { } .into_var_decl( VarDeclKind::Var, - quote_ident!(name_span, self.name.clone()).into(), + quote_ident!(ctxt, name_span, self.name.clone()).into(), ) .into(), // import * as x (None, Some(true)) => require_source_expr .into_var_decl( VarDeclKind::Var, - quote_ident!(name_span, self.name.clone()).into(), + quote_ident!(ctxt, name_span, self.name.clone()).into(), ) .into(), @@ -149,7 +152,7 @@ impl Inject { } .into_var_decl( VarDeclKind::Var, - quote_ident!(name_span, self.name.clone()).into(), + quote_ident!(ctxt, name_span, self.name.clone()).into(), ) .into(), (Some(_), Some(true)) => { @@ -161,12 +164,12 @@ impl Inject { } fn into_with(self, ctxt: SyntaxContext) -> ModuleItem { - let name_span = Span { ctxt, ..DUMMY_SP }; + let name_span = DUMMY_SP; let specifier: ImportSpecifier = match (&self.named, &self.namespace) { // import { named as x } (Some(named), None | Some(false)) => ImportNamedSpecifier { span: DUMMY_SP, - local: quote_ident!(name_span, self.name.clone()), + local: quote_ident!(ctxt, name_span, self.name.clone()), imported: if *named == self.name { None } else { @@ -179,14 +182,14 @@ impl Inject { // import * as x (None, Some(true)) => ImportStarAsSpecifier { span: DUMMY_SP, - local: quote_ident!(name_span, self.name), + local: quote_ident!(ctxt, name_span, self.name), } .into(), // import x (None, None | Some(false)) => ImportDefaultSpecifier { span: DUMMY_SP, - local: quote_ident!(name_span, self.name), + local: quote_ident!(ctxt, name_span, self.name), } .into(), @@ -196,6 +199,7 @@ impl Inject { }; let decl: ModuleDecl = ImportDecl { + phase: Default::default(), span: DUMMY_SP, specifiers: vec![specifier], type_only: false, diff --git a/crates/mako/src/plugins/minifish/unsimplify.rs b/crates/mako/src/plugins/minifish/unsimplify.rs index 587d76a32..b4b8bd987 100644 --- a/crates/mako/src/plugins/minifish/unsimplify.rs +++ b/crates/mako/src/plugins/minifish/unsimplify.rs @@ -3,6 +3,8 @@ use swc_core::common::DUMMY_SP; use swc_core::ecma::ast::{BlockStmt, IfStmt, Stmt}; use swc_core::ecma::visit::{VisitMut, VisitMutWith}; +use crate::ast::DUMMY_CTXT; + pub(super) struct UnSimplify {} impl VisitMut for UnSimplify { @@ -14,6 +16,7 @@ impl VisitMut for UnSimplify { if_stmt.cons = Box::new( BlockStmt { + ctxt: DUMMY_CTXT, span: DUMMY_SP, stmts: vec![*cons], } diff --git a/crates/mako/src/plugins/progress.rs b/crates/mako/src/plugins/progress.rs index 43c89e12d..b68d3b304 100644 --- a/crates/mako/src/plugins/progress.rs +++ b/crates/mako/src/plugins/progress.rs @@ -9,7 +9,7 @@ use crate::ast::file::Content; use crate::compiler::Context; use crate::plugin::{Plugin, PluginLoadParam}; -/** +/* * 插件执行顺序 3 ~ 7 会重复执行 * 1. modify_config * 2. build_start diff --git a/crates/mako/src/plugins/require_context/visitor.rs b/crates/mako/src/plugins/require_context/visitor.rs index ec83ae6ce..229fc0c7e 100644 --- a/crates/mako/src/plugins/require_context/visitor.rs +++ b/crates/mako/src/plugins/require_context/visitor.rs @@ -47,7 +47,7 @@ impl RequireContextVisitor { builder.build() } - fn is_valid_args(&self, args: &Vec) -> bool { + fn is_valid_args(&self, args: &[ExprOrSpread]) -> bool { if !args.is_empty() && args.len() <= 4 { args.iter().all(|arg| { if arg.spread.is_some() { diff --git a/crates/mako/src/plugins/tree_shaking.rs b/crates/mako/src/plugins/tree_shaking.rs index be12f6306..ef7a64b1a 100644 --- a/crates/mako/src/plugins/tree_shaking.rs +++ b/crates/mako/src/plugins/tree_shaking.rs @@ -55,13 +55,14 @@ impl VisitMut for TopLevelDeclSplitter { if let ModuleItem::Stmt(Stmt::Decl(Decl::Var(var_decl))) = module_item { if var_decl.decls.len() > 1 { let declarators = var_decl.decls.take(); - + let ctxt = var_decl.ctxt; let kind = var_decl.kind; let items = declarators .into_iter() .map(|decl| { let i: ModuleItem = VarDecl { + ctxt, span: decl.span, kind, declare: false, diff --git a/crates/mako/src/plugins/tree_shaking/module.rs b/crates/mako/src/plugins/tree_shaking/module.rs index 1876bc5c3..3ee2378a3 100644 --- a/crates/mako/src/plugins/tree_shaking/module.rs +++ b/crates/mako/src/plugins/tree_shaking/module.rs @@ -1,4 +1,5 @@ use std::collections::{BTreeMap, HashSet}; +use std::fmt::Display; use swc_core::common::SyntaxContext; use swc_core::ecma::ast::{Module as SwcModule, ModuleItem}; @@ -21,14 +22,15 @@ pub enum UsedIdent { ExportAll, } -impl ToString for UsedIdent { - fn to_string(&self) -> String { - match self { +impl Display for UsedIdent { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let str = match self { UsedIdent::SwcIdent(ident) => ident.to_string(), UsedIdent::Default => "default".to_string(), UsedIdent::InExportAll(ident) => ident.to_string(), UsedIdent::ExportAll => "*".to_string(), - } + }; + write!(f, "{}", str) } } diff --git a/crates/mako/src/plugins/tree_shaking/shake/module_concatenate.rs b/crates/mako/src/plugins/tree_shaking/shake/module_concatenate.rs index db4ab61be..c5b3ce9fe 100644 --- a/crates/mako/src/plugins/tree_shaking/shake/module_concatenate.rs +++ b/crates/mako/src/plugins/tree_shaking/shake/module_concatenate.rs @@ -1,6 +1,5 @@ mod concatenate_context; mod concatenated_transformer; -mod exports_transform; mod external_transformer; mod module_ref_rewriter; mod ref_link; @@ -13,10 +12,10 @@ use std::sync::Arc; use concatenated_transformer::ConcatenatedTransform; use external_transformer::ExternalTransformer; use swc_core::common::util::take::Take; -use swc_core::common::{Span, SyntaxContext, GLOBALS}; +use swc_core::common::{SyntaxContext, GLOBALS}; use swc_core::ecma::transforms::base::hygiene::hygiene; use swc_core::ecma::transforms::base::resolver; -use swc_core::ecma::visit::{VisitMut, VisitMutWith}; +use swc_core::ecma::visit::{as_folder, Fold, VisitMut, VisitMutWith}; use self::concatenate_context::EsmDependantFlags; use self::utils::uniq_module_prefix; @@ -356,7 +355,7 @@ pub fn optimize_module_graph( ccn_trans.imported(all_import_type); script_ast.ast.visit_mut_with(&mut ccn_trans); - script_ast.ast.visit_mut_with(&mut CleanSyntaxContext {}); + script_ast.ast.visit_mut_with(&mut clean_syntax_context()); if cfg!(debug_assertions) && inner_print { let code = script_ast.generate(context.clone()).unwrap().code; @@ -412,7 +411,7 @@ pub fn optimize_module_graph( println!("root after all:\n{}\n", code); } - root_module_ast.visit_mut_with(&mut CleanSyntaxContext {}); + root_module_ast.visit_mut_with(&mut clean_syntax_context()); let prefix_items = concatenate_context.root_exports_stmts(&config.root); module_items.splice(0..0, prefix_items); @@ -447,13 +446,15 @@ struct ConcatenateConfig { externals: HashMap, } -impl ConcatenateConfig {} +struct CleanSyntaxContext; -pub struct CleanSyntaxContext; +pub fn clean_syntax_context() -> impl VisitMut + Fold { + as_folder(CleanSyntaxContext {}) +} impl VisitMut for CleanSyntaxContext { - fn visit_mut_span(&mut self, n: &mut Span) { - n.ctxt = SyntaxContext::empty(); + fn visit_mut_syntax_context(&mut self, ctxt: &mut SyntaxContext) { + *ctxt = SyntaxContext::empty(); } } diff --git a/crates/mako/src/plugins/tree_shaking/shake/module_concatenate/concatenate_context.rs b/crates/mako/src/plugins/tree_shaking/shake/module_concatenate/concatenate_context.rs index 40a96c7cd..d20b6565a 100644 --- a/crates/mako/src/plugins/tree_shaking/shake/module_concatenate/concatenate_context.rs +++ b/crates/mako/src/plugins/tree_shaking/shake/module_concatenate/concatenate_context.rs @@ -15,6 +15,7 @@ use swc_core::ecma::utils::{ }; use swc_core::ecma::visit::{Visit, VisitWith}; +use crate::ast::DUMMY_CTXT; use crate::module::{ImportType, ModuleId, NamedExportType, ResolveType}; use crate::module_graph::ModuleGraph; use crate::plugins::tree_shaking::shake::module_concatenate::ConcatenateConfig; @@ -250,10 +251,10 @@ pub type ImportModuleRefMap = HashMap; pub fn module_ref_to_expr(module_ref: &ModuleRef) -> Expr { match module_ref { - (id, None) => quote_ident!(id.sym.clone()).into(), + (id, None) => quote_ident!(DUMMY_CTXT, id.sym.clone()).into(), (id, Some(field)) => MemberExpr { span: DUMMY_SP, - obj: quote_ident!(id.sym.clone()).into(), + obj: quote_ident!(DUMMY_CTXT, id.sym.clone()).into(), prop: quote_ident!(field.clone()).into(), } .into(), @@ -301,7 +302,7 @@ impl ConcatenateContext { pub fn top_level_vars(ast: &Module, top_level_mark: Mark) -> HashSet { let mut top_level_vars = HashSet::new(); top_level_vars.extend( - collect_decls_with_ctxt(ast, SyntaxContext::empty().apply_mark(top_level_mark)) + collect_decls_with_ctxt(ast, DUMMY_CTXT.apply_mark(top_level_mark)) .iter() .map(|id: &Id| id.0.to_string()), ); @@ -327,7 +328,7 @@ impl ConcatenateContext { pub fn global_vars(ast: &Module, unresolved_mark: Mark) -> HashSet { let mut globals = HashSet::new(); - let mut collector = GlobalCollect::new(SyntaxContext::empty().apply_mark(unresolved_mark)); + let mut collector = GlobalCollect::new(DUMMY_CTXT.apply_mark(unresolved_mark)); ast.visit_with(&mut collector); globals.extend( collector @@ -401,7 +402,7 @@ impl ConcatenateContext { .collect(); // __mako_require__.d(exports, __esModule, { value: true }); - let esm_compat = member_expr!(DUMMY_SP, __mako_require__.d) + let esm_compat = member_expr!(DUMMY_CTXT, DUMMY_SP, __mako_require__.d) .as_call( DUMMY_SP, vec![ @@ -426,7 +427,7 @@ impl ConcatenateContext { if !key_value_props.is_empty() { // __mako_require__.e(exports, { exported: function(){ return v}, ... }); - let export_stmt = member_expr!(DUMMY_SP, __mako_require__.e) + let export_stmt = member_expr!(DUMMY_CTXT, DUMMY_SP, __mako_require__.e) .as_call( DUMMY_SP, vec![ @@ -527,7 +528,7 @@ impl GlobalCollect { impl Visit for GlobalCollect { fn visit_ident(&mut self, n: &Ident) { - if n.span.ctxt == self.unresolved_ctxt { + if n.ctxt == self.unresolved_ctxt { self.refed_globals.insert(n.to_id()); } } diff --git a/crates/mako/src/plugins/tree_shaking/shake/module_concatenate/concatenated_transformer.rs b/crates/mako/src/plugins/tree_shaking/shake/module_concatenate/concatenated_transformer.rs index 8edbad057..e31ff61fd 100644 --- a/crates/mako/src/plugins/tree_shaking/shake/module_concatenate/concatenated_transformer.rs +++ b/crates/mako/src/plugins/tree_shaking/shake/module_concatenate/concatenated_transformer.rs @@ -4,7 +4,7 @@ use std::sync::Arc; use swc_core::common::collections::AHashSet; use swc_core::common::comments::{Comment, CommentKind}; use swc_core::common::util::take::Take; -use swc_core::common::{Mark, Spanned, SyntaxContext, DUMMY_SP}; +use swc_core::common::{Mark, Spanned, DUMMY_SP}; use swc_core::ecma::ast::{ ClassDecl, DefaultDecl, ExportAll, ExportDecl, ExportDefaultDecl, ExportDefaultExpr, FnDecl, Id, ImportDecl, KeyValueProp, Module, ModuleItem, NamedExport, ObjectLit, Prop, PropOrSpread, @@ -19,6 +19,7 @@ use super::concatenate_context::{ use super::module_ref_rewriter::ModuleRefRewriter; use super::ref_link::{ModuleDeclMapCollector, Symbol, VarLink}; use super::utils::{uniq_module_default_export_name, uniq_module_namespace_name}; +use crate::ast::DUMMY_CTXT; use crate::compiler::Context; use crate::module::{relative_to_root, ImportType, ModuleId}; @@ -119,7 +120,7 @@ impl<'a> ConcatenatedTransform<'a> { if let Some(mf) = map.get("default") { mf.clone() } else { - (quote_ident!("undefined"), None) + (quote_ident!(DUMMY_CTXT, "undefined"), None) } } Symbol::Namespace => map.get("*").unwrap().clone(), @@ -127,7 +128,7 @@ impl<'a> ConcatenatedTransform<'a> { if let Some(mf) = map.get(&ident.sym.to_string()) { mf.clone() } else { - (quote_ident!("undefined"), None) + (quote_ident!(DUMMY_CTXT, "undefined"), None) } } }; @@ -137,7 +138,10 @@ impl<'a> ConcatenatedTransform<'a> { InnerOrExternal::External(external_names) => { ref_map.insert( id.clone(), - (quote_ident!(external_names.1.clone()), symbol.to_field()), + ( + quote_ident!(DUMMY_CTXT, external_names.1.clone()), + symbol.to_field(), + ), ); } } @@ -171,7 +175,7 @@ impl<'a> ConcatenatedTransform<'a> { if let Some(mf) = map.get("default") { mf.clone() } else { - (quote_ident!("undefined"), None) + (quote_ident!(DUMMY_CTXT, "undefined"), None) } } Symbol::Namespace => map.get("*").unwrap().clone(), @@ -179,7 +183,7 @@ impl<'a> ConcatenatedTransform<'a> { if let Some(mf) = map.get(&ident.sym.to_string()) { mf.clone() } else { - (quote_ident!("undefined"), None) + (quote_ident!(DUMMY_CTXT, "undefined"), None) } } }; @@ -188,7 +192,10 @@ impl<'a> ConcatenatedTransform<'a> { InnerOrExternal::External(external_names) => { ref_map.insert( id.0.to_string(), - (quote_ident!(external_names.1.clone()), symbol.to_field()), + ( + quote_ident!(DUMMY_CTXT, external_names.1.clone()), + symbol.to_field(), + ), ); } } @@ -289,7 +296,7 @@ impl<'a> ConcatenatedTransform<'a> { } fn resolve_conflict(&mut self, import_module_ref: &ImportModuleRefMap) { - let top_ctxt = SyntaxContext::empty().apply_mark(self.top_level_mark); + let top_ctxt = DUMMY_CTXT.apply_mark(self.top_level_mark); let imported_reference = all_referenced_variables(import_module_ref); @@ -367,7 +374,7 @@ impl<'a> ConcatenatedTransform<'a> { .map(Into::into) .collect::>(); - let define_exports: Stmt = member_expr!(DUMMY_SP, __mako_require__.e) + let define_exports: Stmt = member_expr!(DUMMY_CTXT, DUMMY_SP, __mako_require__.e) .as_call( DUMMY_SP, vec![ @@ -381,7 +388,10 @@ impl<'a> ConcatenatedTransform<'a> { ) .into_stmt(); - export_ref_map.insert("*".to_string(), (quote_ident!(ns_name.clone()), None)); + export_ref_map.insert( + "*".to_string(), + (quote_ident!(DUMMY_CTXT, ns_name.clone()), None), + ); self.my_top_decls.insert(ns_name); n.body.push(init_stmt.into()); @@ -474,7 +484,8 @@ impl<'a> VisitMut for ConcatenatedTransform<'a> { } fn visit_mut_export_default_expr(&mut self, export_default_expr: &mut ExportDefaultExpr) { - let span = export_default_expr.span.apply_mark(self.top_level_mark); + let span = export_default_expr.span; + let ctxt = DUMMY_CTXT.apply_mark(self.top_level_mark); let default_binding_name = self.default_bind_name.clone(); @@ -486,7 +497,7 @@ impl<'a> VisitMut for ConcatenatedTransform<'a> { .take() .into_var_decl( VarDeclKind::Var, - quote_ident!(span, default_binding_name.clone()).into(), + quote_ident!(ctxt, span, default_binding_name.clone()).into(), ) .into(); self.my_top_decls.insert(default_binding_name.clone()); diff --git a/crates/mako/src/plugins/tree_shaking/shake/module_concatenate/concatenated_transformer/tests.rs b/crates/mako/src/plugins/tree_shaking/shake/module_concatenate/concatenated_transformer/tests.rs index ff98a8973..e439a86fb 100644 --- a/crates/mako/src/plugins/tree_shaking/shake/module_concatenate/concatenated_transformer/tests.rs +++ b/crates/mako/src/plugins/tree_shaking/shake/module_concatenate/concatenated_transformer/tests.rs @@ -10,6 +10,7 @@ use super::super::ConcatenateContext; use super::utils::describe_export_map; use super::ConcatenatedTransform; use crate::ast::js_ast::JsAst; +use crate::ast::DUMMY_CTXT; use crate::compiler::Context; use crate::config::{Config, Mode, OptimizationConfig}; use crate::module::{ImportType, ModuleId}; @@ -616,7 +617,8 @@ fn test_export_from_var() { let mut ccn_ctx = ConcatenateContext { modules_exports_map: hashmap! { ModuleId::from("src/index.js") => hashmap! { - "default".to_string() => (quote_ident!("src_index_default"), None) + "default".to_string() => (quote_ident!(DUMMY_CTXT,"src_index_default"), + None) } }, ..Default::default() @@ -698,10 +700,10 @@ fn concatenate_context_fixture_with_inner_module() -> ConcatenateContext { }, modules_exports_map: hashmap! { ModuleId::from("src/index.js") => hashmap!{ - "*".to_string() => (quote_ident!("inner_namespace"), None), - "default".to_string() => ( quote_ident!("inner_default_export"), None), - "foo".to_string() => (quote_ident!("bar") ,None), - "named".to_string() => (quote_ident!("named"), None) + "*".to_string() => (quote_ident!(DUMMY_CTXT,"inner_namespace"), None), + "default".to_string() => ( quote_ident!(DUMMY_CTXT,"inner_default_export"), None), + "foo".to_string() => (quote_ident!(DUMMY_CTXT,"bar") ,None), + "named".to_string() => (quote_ident!(DUMMY_CTXT,"named"), None) }, ModuleId::from("src/no_exports.js") => hashmap!{}, }, @@ -739,7 +741,7 @@ fn inner_trans_code_imported_as( let src_to_module = hashmap! { "./src".to_string() => ModuleId::from("src/index.js"), "./no_exports".to_string() => ModuleId::from("src/no_exports.js"), - "external".to_string() => ModuleId::from("external") + "external".to_string() => ModuleId::from("external") }; GLOBALS.set(&context.meta.script.globals, || { diff --git a/crates/mako/src/plugins/tree_shaking/shake/module_concatenate/exports_transform.rs b/crates/mako/src/plugins/tree_shaking/shake/module_concatenate/exports_transform.rs deleted file mode 100644 index d4cbb07d6..000000000 --- a/crates/mako/src/plugins/tree_shaking/shake/module_concatenate/exports_transform.rs +++ /dev/null @@ -1,204 +0,0 @@ -use std::collections::HashSet; - -use swc_core::ecma::ast::{ - Decl, ExportSpecifier, Ident, ModuleDecl, ModuleExportName, ObjectPatProp, Pat, -}; -use swc_core::ecma::visit::{Visit, VisitWith}; - -#[derive(Default)] -pub(super) struct PatDefineIdCollector { - defined_idents: HashSet, -} - -impl Visit for PatDefineIdCollector { - fn visit_pat(&mut self, pat: &Pat) { - match pat { - Pat::Ident(bi) => { - self.defined_idents.insert(bi.id.sym.to_string()); - } - Pat::Array(array_pat) => { - for elem in array_pat.elems.iter().flatten() { - self.visit_pat(elem); - } - } - Pat::Rest(rest_pat) => { - self.visit_pat(&rest_pat.arg); - } - Pat::Object(obj_pat) => { - for prop in &obj_pat.props { - match prop { - ObjectPatProp::KeyValue(kv_prop) => { - self.visit_pat(&kv_prop.value); - } - ObjectPatProp::Assign(assign_prop) => { - self.defined_idents.insert(assign_prop.key.sym.to_string()); - } - ObjectPatProp::Rest(rest_prop) => { - self.visit_pat(&rest_prop.arg); - } - } - } - } - Pat::Assign(assign_pat) => { - self.visit_pat(&assign_pat.left); - } - Pat::Invalid(_) => {} - Pat::Expr(_) => {} - } - } -} - -#[derive(Default)] -pub(super) struct ExportsCollector { - exports: HashSet, -} - -impl Visit for ExportsCollector { - fn visit_module_decl(&mut self, n: &ModuleDecl) { - match n { - ModuleDecl::Import(_) => {} - ModuleDecl::ExportDecl(export_decl) => match &export_decl.decl { - Decl::Class(class_decl) => { - self.exports.insert(class_decl.ident.sym.to_string()); - } - Decl::Fn(fn_decl) => { - self.exports.insert(fn_decl.ident.sym.to_string()); - } - Decl::Var(var_decl) => { - for x in var_decl.decls.iter() { - let names = collect_defined_ident_in_pat(&x.name); - self.exports.extend(names); - } - } - Decl::Using(_using_decl) => { - // TODO: when necessary - // for var_decl in using_decl.decls.iter() { - // let names = collect_defined_ident_in_pat(&var_decl.name); - // self.exports.extend(names); - // } - } - Decl::TsInterface(_) => {} - Decl::TsTypeAlias(_) => {} - Decl::TsEnum(_) => {} - Decl::TsModule(_) => {} - }, - ModuleDecl::ExportNamed(export_named) => export_named.specifiers.iter().for_each( - |export_specifier| match &export_specifier { - ExportSpecifier::Namespace(namespace) => { - if let Some(ident) = module_export_name_as_ident(&namespace.name) { - self.exports.insert(ident.sym.to_string()); - } - } - ExportSpecifier::Default(export_default) => { - self.exports.insert(export_default.exported.sym.to_string()); - } - ExportSpecifier::Named(named_export) => { - if let Some(exported) = &named_export.exported - && let Some(ident) = module_export_name_as_ident(exported) - { - self.exports.insert(ident.sym.to_string()); - } else if let Some(ident) = module_export_name_as_ident(&named_export.orig) - { - self.exports.insert(ident.sym.to_string()); - } - } - }, - ), - ModuleDecl::ExportDefaultDecl(_) | ModuleDecl::ExportDefaultExpr(_) => { - self.exports.insert("default".into()); - } - ModuleDecl::ExportAll(_) => { - // not allowed in inner module - } - ModuleDecl::TsImportEquals(_) => {} - ModuleDecl::TsExportAssignment(_) => {} - ModuleDecl::TsNamespaceExport(_) => {} - } - } -} - -fn collect_defined_ident_in_pat(pat: &Pat) -> HashSet { - let mut c: PatDefineIdCollector = Default::default(); - pat.visit_with(&mut c); - c.defined_idents -} - -fn module_export_name_as_ident(module_export_name: &ModuleExportName) -> Option<&Ident> { - match module_export_name { - ModuleExportName::Ident(ident) => Some(ident), - _ => None, - } -} - -#[cfg(test)] -mod tests { - use maplit::hashset; - use swc_core::ecma::visit::VisitWith; - - use super::*; - use crate::ast::tests::TestUtils; - - #[test] - fn collect_default_export() { - assert_eq!( - extract_export("export default 1"), - hashset! {"default".to_string()} - ); - } - - #[test] - fn export_named_fn() { - assert_eq!( - extract_export("export function fn(){}"), - hashset! {"fn".to_string()} - ); - } - - #[test] - fn export_named_class() { - assert_eq!( - extract_export("export class C{}"), - hashset! {"C".to_string()} - ); - } - - #[test] - fn export_names() { - assert_eq!( - extract_export("let a=1,b=2; export {a,b}"), - hashset! {"a".to_string(), "b".to_string()} - ); - } - - #[test] - fn export_object_deconstruct() { - assert_eq!( - extract_export("let A= {a:1,b:2, c:3}; export const {a,b:x, ...z} = A"), - hashset! {"a".to_string(), "x".to_string(), "z".to_string()} - ); - } - - #[test] - fn export_array_deconstruct() { - assert_eq!( - extract_export("let a= [1,2,3]; export const [x,y,...z] = a"), - hashset! {"x".to_string(), "y".to_string(), "z".to_string()} - ); - } - - #[test] - fn export_var_decl_export() { - assert_eq!( - extract_export("export const a =1"), - hashset! {"a".to_string()} - ); - } - - fn extract_export(code: &str) -> HashSet { - let mut ast = TestUtils::gen_js_ast(code); - let mut collectort = ExportsCollector::default(); - - ast.ast.js_mut().ast.visit_with(&mut collectort); - collectort.exports - } -} diff --git a/crates/mako/src/plugins/tree_shaking/shake/module_concatenate/external_transformer.rs b/crates/mako/src/plugins/tree_shaking/shake/module_concatenate/external_transformer.rs index c34db19a5..2d5dd24ef 100644 --- a/crates/mako/src/plugins/tree_shaking/shake/module_concatenate/external_transformer.rs +++ b/crates/mako/src/plugins/tree_shaking/shake/module_concatenate/external_transformer.rs @@ -26,7 +26,7 @@ impl<'a> ExternalTransformer<'_> { fn require_arg_to_module_namespace( &self, - args: &Vec, + args: &[ExprOrSpread], ) -> Option<((String, String), ModuleId)> { if args.len() == 1 && let Some(arg) = args.first() diff --git a/crates/mako/src/plugins/tree_shaking/shake/module_concatenate/module_ref_rewriter.rs b/crates/mako/src/plugins/tree_shaking/shake/module_concatenate/module_ref_rewriter.rs index e240c597d..ba3a06742 100644 --- a/crates/mako/src/plugins/tree_shaking/shake/module_concatenate/module_ref_rewriter.rs +++ b/crates/mako/src/plugins/tree_shaking/shake/module_concatenate/module_ref_rewriter.rs @@ -5,11 +5,12 @@ use swc_core::common::{Span, SyntaxContext, DUMMY_SP}; use swc_core::ecma::ast::*; use swc_core::ecma::transforms::base::helpers::HELPERS; use swc_core::ecma::utils::{ - is_valid_prop_ident, quote_ident, quote_str, undefined, ExprFactory, IntoIndirectCall, + is_valid_prop_ident, quote_ident, quote_str, ExprFactory, IntoIndirectCall, }; use swc_core::ecma::visit::{noop_visit_mut_type, VisitMut, VisitMutWith}; use super::concatenate_context::ImportModuleRefMap; +use crate::ast::DUMMY_CTXT; pub struct ModuleRefRewriter<'a> { /// ```javascript @@ -55,7 +56,7 @@ impl<'a> ModuleRefRewriter<'a> { HELPERS .is_set() .then(|| HELPERS.with(|helper| helper.mark())) - .map(|mark| SyntaxContext::empty().apply_mark(mark)) + .map(|mark| DUMMY_CTXT.apply_mark(mark)) }, } } @@ -91,7 +92,7 @@ impl VisitMut for ModuleRefRewriter<'_> { Expr::This(ThisExpr { span }) => { if !self.allow_top_level_this && self.is_global_this { - *n = *undefined(*span); + *n = *Expr::undefined(*span); } } @@ -104,7 +105,7 @@ impl VisitMut for ModuleRefRewriter<'_> { Callee::Expr(e) if e.is_ident() => { let is_indirect_callee = e .as_ident() - .filter(|ident| self.helper_ctxt.iter().all(|ctxt| ctxt != &ident.span.ctxt)) + .filter(|ident| self.helper_ctxt.iter().all(|ctxt| ctxt != &ident.ctxt)) .and_then(|ident| self.import_map.get(&ident.to_id())) .map(|(_, prop)| prop.is_some()) .unwrap_or_default(); @@ -124,7 +125,7 @@ impl VisitMut for ModuleRefRewriter<'_> { let is_indirect = n .tag .as_ident() - .filter(|ident| self.helper_ctxt.iter().all(|ctxt| ctxt != &ident.span.ctxt)) + .filter(|ident| self.helper_ctxt.iter().all(|ctxt| ctxt != &ident.ctxt)) .and_then(|ident| self.import_map.get(&ident.to_id())) .map(|(_, prop)| prop.is_some()) .unwrap_or_default(); @@ -190,7 +191,7 @@ impl ModuleRefRewriter<'_> { .get(&ref_ident.to_id()) .map(|(mod_ident, mod_prop)| -> Expr { let mut mod_ident = mod_ident.clone(); - let span = ref_ident.span.with_ctxt(mod_ident.span.ctxt); + let span = ref_ident.span; mod_ident.span = span; let mod_expr = if self.lazy_record.contains(&mod_ident.to_id()) { @@ -217,7 +218,7 @@ impl ModuleRefRewriter<'_> { fn prop_name(key: &str, span: Span) -> IdentOrStr { if is_valid_prop_ident(key) { - IdentOrStr::Ident(quote_ident!(span, key)) + IdentOrStr::Ident(quote_ident!(DUMMY_CTXT, span, key)) } else { IdentOrStr::Str(quote_str!(span, key)) } @@ -231,7 +232,7 @@ enum IdentOrStr { impl From for PropName { fn from(val: IdentOrStr) -> Self { match val { - IdentOrStr::Ident(i) => Self::Ident(i), + IdentOrStr::Ident(i) => Self::Ident(i.into()), IdentOrStr::Str(s) => Self::Str(s), } } @@ -240,7 +241,7 @@ impl From for PropName { impl From for MemberProp { fn from(val: IdentOrStr) -> Self { match val { - IdentOrStr::Ident(i) => Self::Ident(i), + IdentOrStr::Ident(i) => Self::Ident(i.into()), IdentOrStr::Str(s) => Self::Computed(ComputedPropName { span: DUMMY_SP, expr: s.into(), diff --git a/crates/mako/src/plugins/tree_shaking/shake/module_concatenate/ref_link.rs b/crates/mako/src/plugins/tree_shaking/shake/module_concatenate/ref_link.rs index f23512ad5..5f9de125f 100644 --- a/crates/mako/src/plugins/tree_shaking/shake/module_concatenate/ref_link.rs +++ b/crates/mako/src/plugins/tree_shaking/shake/module_concatenate/ref_link.rs @@ -47,6 +47,8 @@ use swc_core::ecma::ast::{ use swc_core::ecma::utils::quote_ident; use swc_core::ecma::visit::{Visit, VisitWith}; +use crate::ast::DUMMY_CTXT; + #[derive(Default)] pub(super) struct PatDefineIdCollector { defined_idents: HashSet, @@ -73,7 +75,7 @@ impl Visit for PatDefineIdCollector { self.visit_pat(&kv_prop.value); } ObjectPatProp::Assign(assign_prop) => { - self.defined_idents.insert(assign_prop.key.clone()); + self.defined_idents.insert(assign_prop.key.clone().into()); } ObjectPatProp::Rest(rest_prop) => { self.visit_pat(&rest_prop.arg); @@ -284,8 +286,10 @@ impl Visit for ModuleDeclMapCollector { } }; - self.export_map - .insert(quote_ident!("default").to_id(), VarLink::Direct(default_id)); + self.export_map.insert( + quote_ident!(DUMMY_CTXT, "default").to_id(), + VarLink::Direct(default_id), + ); } ModuleDecl::ExportDefaultExpr(export_default_expr) => { let id = match export_default_expr.expr.as_ident() { @@ -296,12 +300,14 @@ impl Visit for ModuleDeclMapCollector { ), }; - self.export_map - .insert(quote_ident!("default").to_id(), VarLink::Direct(id)); + self.export_map.insert( + quote_ident!(DUMMY_CTXT, "default").to_id(), + VarLink::Direct(id), + ); } ModuleDecl::ExportAll(export_all) => { self.export_map.insert( - quote_ident!(format!("*:{}", self.current_stmt_id)).to_id(), + quote_ident!(DUMMY_CTXT, format!("*:{}", self.current_stmt_id)).to_id(), VarLink::All(export_all.src.value.to_string(), self.current_stmt_id), ); } diff --git a/crates/mako/src/plugins/tree_shaking/shake/skip_module.rs b/crates/mako/src/plugins/tree_shaking/shake/skip_module.rs index 6589cb092..9d73138a8 100644 --- a/crates/mako/src/plugins/tree_shaking/shake/skip_module.rs +++ b/crates/mako/src/plugins/tree_shaking/shake/skip_module.rs @@ -11,6 +11,7 @@ use swc_core::ecma::ast::{ use swc_core::ecma::utils::{quote_ident, quote_str}; use swc_core::quote; +use crate::ast::DUMMY_CTXT; use crate::compiler::Context; use crate::module::{Dependency, ImportType, ModuleId, NamedExportType, ResolveType}; use crate::module_graph::ModuleGraph; @@ -51,7 +52,7 @@ impl ReExportReplace { ) } else { quote!("export { $local as $ident } from \"$from\";" as ModuleItem, - local: Ident = quote_ident!(local.clone()), + local: Ident = quote_ident!(DUMMY_CTXT, local.clone()), ident: Ident = ident, from: Str = quote_str!(self.from_module_id.id.clone()) ) @@ -104,7 +105,7 @@ impl ReExportReplace { ) } else { quote!("import { $local as $ident } from \"$from\";" as ModuleItem, - local: Ident = quote_ident!(local.clone()), + local: Ident = quote_ident!(DUMMY_CTXT,local.clone()), ident: Ident = ident, from: Str = quote_str!(self.from_module_id.id.clone()) ) @@ -163,7 +164,7 @@ impl From<&ReExportType> for ImportType { pub(super) fn skip_module_optimize( module_graph: &mut ModuleGraph, - tree_shake_modules_ids: &Vec, + tree_shake_modules_ids: &[ModuleId], tree_shake_modules_map: &HashMap>, _context: &Arc, ) -> Result<()> { diff --git a/crates/mako/src/plugins/tree_shaking/statement_graph.rs b/crates/mako/src/plugins/tree_shaking/statement_graph.rs index cd77c008f..ad752b042 100644 --- a/crates/mako/src/plugins/tree_shaking/statement_graph.rs +++ b/crates/mako/src/plugins/tree_shaking/statement_graph.rs @@ -31,6 +31,7 @@ pub enum ImportSpecifierInfo { pub struct ImportInfo { pub source: String, pub specifiers: Vec, + #[allow(dead_code)] pub stmt_id: StatementId, } @@ -244,7 +245,9 @@ pub struct Statement { /// transform it to Ident.to_string() is exactly what we want pub defined_idents_map: HashMap>, pub is_self_executed: bool, + #[allow(dead_code)] pub has_side_effects: bool, + #[allow(dead_code)] pub span: Span, } diff --git a/crates/mako/src/stats.rs b/crates/mako/src/stats.rs index 380c48c4b..48da7b61f 100644 --- a/crates/mako/src/stats.rs +++ b/crates/mako/src/stats.rs @@ -9,7 +9,7 @@ use colored::*; use indexmap::IndexMap; use pathdiff::diff_paths; use serde::Serialize; -use swc_core::common::source_map::Pos; +use swc_core::common::source_map::SmallPos; use crate::compiler::{Compiler, Context}; use crate::features::rsc::{RscClientInfo, RscCssModules}; @@ -94,10 +94,7 @@ impl Compiler { let id = module.id.clone(); // 去拿 module 的文件 size 时,有可能 module 不存在,size 则设为 0 // 场景: xlsx 中引入了 fs 模块 - let size = match file_size(&id) { - Ok(size) => size, - Err(..) => 0, - }; + let size = file_size(&id).unwrap_or_default(); let module = StatsJsonChunkModuleItem { module_type: StatsJsonType::Module("module".to_string()), size, diff --git a/crates/mako/src/visitors/async_module.rs b/crates/mako/src/visitors/async_module.rs index 185e794e0..88b0baa3f 100644 --- a/crates/mako/src/visitors/async_module.rs +++ b/crates/mako/src/visitors/async_module.rs @@ -4,13 +4,14 @@ use std::sync::Arc; use swc_core::common::util::take::Take; use swc_core::common::{Mark, DUMMY_SP}; use swc_core::ecma::ast::{ - ArrayLit, AssignExpr, AssignOp, AwaitExpr, BlockStmt, BlockStmtOrExpr, CondExpr, Expr, Ident, - Lit, ModuleItem, ParenExpr, Stmt, VarDeclKind, + ArrayLit, ArrayPat, AssignExpr, AssignOp, AwaitExpr, BlockStmt, BlockStmtOrExpr, CondExpr, + Expr, Ident, Lit, ModuleItem, ParenExpr, Stmt, VarDeclKind, }; use swc_core::ecma::utils::{member_expr, quote_expr, quote_ident, ExprFactory}; use swc_core::ecma::visit::{VisitMut, VisitMutWith}; use crate::ast::utils::is_commonjs_require; +use crate::ast::DUMMY_CTXT; use crate::compiler::Context; use crate::module::{Dependency, ModuleId}; @@ -58,7 +59,8 @@ impl VisitMut for AsyncModule<'_> { && let Some(dep_span) = dep.span && dep_span.contains(str.span) { - let ident_name = quote_ident!(format!("{}{}__", ASYNC_IMPORTED_MODULE, idx)); + let ident_name = + quote_ident!(DUMMY_CTXT, format!("{}{}__", ASYNC_IMPORTED_MODULE, idx)); if !self.async_deps_idents.contains(&ident_name) { self.async_deps_idents.push(ident_name.clone()); @@ -124,17 +126,20 @@ impl VisitMut for AsyncModule<'_> { self.prepend_module_items.push(ModuleItem::Stmt( AssignExpr { op: AssignOp::Assign, - left: ArrayLit { + left: ArrayPat { span: DUMMY_SP, + optional: false, elems: self .async_deps_idents .iter() - .map(|ident| Some(ident.clone().as_arg())) + .map(|ident| Some(ident.clone().into())) .collect(), + type_ann: None, } - .as_pat_or_expr(), + .into(), right: CondExpr { - test: member_expr!(DUMMY_SP, __mako_async_dependencies__.then), + test: member_expr!(DUMMY_CTXT, DUMMY_SP, __mako_async_dependencies__.then) + .into(), cons: ParenExpr { expr: AwaitExpr { span: DUMMY_SP, @@ -170,7 +175,7 @@ impl VisitMut for AsyncModule<'_> { // module, async (handleAsyncDeps, asyncResult) => { }, bool // );` *module_items = vec![ModuleItem::Stmt( - member_expr!(DUMMY_SP, __mako_require__._async) + member_expr!(DUMMY_CTXT, DUMMY_SP, __mako_require__._async) .as_call( DUMMY_SP, vec![ @@ -183,6 +188,7 @@ impl VisitMut for AsyncModule<'_> { arrow_fn.is_async = true; arrow_fn.body = BlockStmtOrExpr::BlockStmt(BlockStmt { span: DUMMY_SP, + ctxt: DUMMY_CTXT, stmts: module_items .iter() .map(|stmt| stmt.as_stmt().unwrap().clone()) @@ -261,9 +267,7 @@ __mako_require__._async(module, async (handleAsyncDeps, asyncResult)=>{ var __mako_async_dependencies__ = handleAsyncDeps([ _async__mako_imported_module_0__ ]); - [ - _async__mako_imported_module_0__ - ] = __mako_async_dependencies__.then ? (await __mako_async_dependencies__)() : __mako_async_dependencies__; + [_async__mako_imported_module_0__] = __mako_async_dependencies__.then ? (await __mako_async_dependencies__)() : __mako_async_dependencies__; var _async = _interop_require_default._(_async__mako_imported_module_0__); 0, _async.default(1, 2); asyncResult(); @@ -296,10 +300,7 @@ __mako_require__._async(module, async (handleAsyncDeps, asyncResult)=>{ _async__mako_imported_module_0__, _async__mako_imported_module_1__ ]); - [ - _async__mako_imported_module_0__, - _async__mako_imported_module_1__ - ] = __mako_async_dependencies__.then ? (await __mako_async_dependencies__)() : __mako_async_dependencies__; + [_async__mako_imported_module_0__, _async__mako_imported_module_1__] = __mako_async_dependencies__.then ? (await __mako_async_dependencies__)() : __mako_async_dependencies__; var _async = _interop_require_default._(_async__mako_imported_module_0__); var _async_2 = _interop_require_default._(_async__mako_imported_module_1__); 0, _async.default(1, 2); @@ -333,9 +334,7 @@ __mako_require__._async(module, async (handleAsyncDeps, asyncResult)=>{ var __mako_async_dependencies__ = handleAsyncDeps([ _async__mako_imported_module_0__ ]); - [ - _async__mako_imported_module_0__ - ] = __mako_async_dependencies__.then ? (await __mako_async_dependencies__)() : __mako_async_dependencies__; + [_async__mako_imported_module_0__] = __mako_async_dependencies__.then ? (await __mako_async_dependencies__)() : __mako_async_dependencies__; var _async = _interop_require_default._(_export_star._(_async__mako_imported_module_0__, exports)); 0, _async.default(1, 2); asyncResult(); @@ -387,9 +386,7 @@ __mako_require__._async(module, async (handleAsyncDeps, asyncResult)=>{ var __mako_async_dependencies__ = handleAsyncDeps([ _async__mako_imported_module_0__ ]); - [ - _async__mako_imported_module_0__ - ] = __mako_async_dependencies__.then ? (await __mako_async_dependencies__)() : __mako_async_dependencies__; + [_async__mako_imported_module_0__] = __mako_async_dependencies__.then ? (await __mako_async_dependencies__)() : __mako_async_dependencies__; var _miexed_async = _interop_require_default._(_async__mako_imported_module_0__); async.add(1, 2); const async = require('./miexed_async'); diff --git a/crates/mako/src/visitors/common_js.rs b/crates/mako/src/visitors/common_js.rs index 9ef7cd5b0..f22fa771d 100644 --- a/crates/mako/src/visitors/common_js.rs +++ b/crates/mako/src/visitors/common_js.rs @@ -19,22 +19,14 @@ pub struct Commonjs { impl VisitMut for Commonjs { fn visit_mut_module(&mut self, n: &mut Module) { - let mut use_strict = false; - if utils::is_esm(n) { - use_strict = true + let use_strict = if utils::is_esm(n) { + true } else { - for item in n.body.iter() { - if let Some(stmt) = item.as_stmt() { - if stmt.is_directive() { - if stmt.is_use_strict() { - use_strict = true; - } - } else { - break; - } - } - } - } + n.body + .iter() + .take_while(|s| s.directive_continue()) + .any(|s| s.is_use_strict()) + }; n.visit_mut_with(&mut swc_common_js( self.unresolved_mark, diff --git a/crates/mako/src/visitors/css_px2rem.rs b/crates/mako/src/visitors/css_px2rem.rs index c125f2092..de7e4bb3a 100644 --- a/crates/mako/src/visitors/css_px2rem.rs +++ b/crates/mako/src/visitors/css_px2rem.rs @@ -99,7 +99,7 @@ impl VisitMut for Px2Rem { } fn visit_mut_length(&mut self, n: &mut Length) { - if n.unit.value.to_string() == "px" && self.should_transform(n.value.value) { + if n.unit.value == "px" && self.should_transform(n.value.value) { n.value.value /= self.config.root; if self.is_any_in_doublelist() { n.value.value *= 2.0; @@ -126,7 +126,7 @@ impl VisitMut for Px2Rem { // .a { --a-b: var(--c-d, 88px); } fn visit_mut_token(&mut self, t: &mut Token) { if let Token::Dimension(dimension) = t { - if dimension.unit.to_string() == "px" && self.should_transform(dimension.value) { + if dimension.unit == "px" && self.should_transform(dimension.value) { let mut rem_val = dimension.value / self.config.root; if self.is_any_in_doublelist() { rem_val *= 2.0; diff --git a/crates/mako/src/visitors/default_export_namer.rs b/crates/mako/src/visitors/default_export_namer.rs index 1c5449deb..25cc12141 100644 --- a/crates/mako/src/visitors/default_export_namer.rs +++ b/crates/mako/src/visitors/default_export_namer.rs @@ -35,6 +35,7 @@ impl VisitMut for DefaultExportNamer { return_type, type_params, span, + ctxt, .. } = arrow_expr.clone(); *item = ModuleDecl::ExportDefaultDecl(ExportDefaultDecl { @@ -50,6 +51,7 @@ impl VisitMut for DefaultExportNamer { BlockStmtOrExpr::BlockStmt(block_stmt) => block_stmt, BlockStmtOrExpr::Expr(expr) => BlockStmt { span, + ctxt, stmts: vec![Stmt::Return(ReturnStmt { span, arg: Some(expr), @@ -59,6 +61,7 @@ impl VisitMut for DefaultExportNamer { is_async, is_generator, span, + ctxt, return_type, type_params, decorators: vec![], diff --git a/crates/mako/src/visitors/dep_replacer.rs b/crates/mako/src/visitors/dep_replacer.rs index ab18f64e6..ee90a23f7 100644 --- a/crates/mako/src/visitors/dep_replacer.rs +++ b/crates/mako/src/visitors/dep_replacer.rs @@ -11,6 +11,7 @@ use swc_core::ecma::visit::{VisitMut, VisitMutWith}; use crate::ast::file::parse_path; use crate::ast::utils::{is_commonjs_require, is_dynamic_import, is_remote_or_data}; +use crate::ast::DUMMY_CTXT; use crate::compiler::Context; use crate::module::{Dependency, ModuleId}; use crate::visitors::virtual_css_modules::is_css_path; @@ -20,7 +21,6 @@ pub struct DepReplacer<'a> { pub to_replace: &'a DependenciesToReplace, pub context: &'a Arc, pub unresolved_mark: Mark, - pub top_level_mark: Mark, } type ResolvedModuleId = String; @@ -49,18 +49,23 @@ pub fn miss_throw_stmt>(source: T) -> Expr { // e.code = "MODULE_NOT_FOUND" let assign_error = quote_str!("MODULE_NOT_FOUND") - .make_assign_to(AssignOp::Assign, member_expr!(DUMMY_SP, e.code).into()) + .make_assign_to( + AssignOp::Assign, + member_expr!(DUMMY_CTXT, DUMMY_SP, e.code).into(), + ) .into_stmt(); // function() { ...; throw e } let fn_expr = Expr::Fn(FnExpr { - ident: Some(quote_ident!("makoMissingModule")), + ident: Some(quote_ident!(DUMMY_CTXT, "makoMissingModule")), function: Box::new(Function { is_async: false, params: vec![], decorators: vec![], span: DUMMY_SP, + ctxt: DUMMY_CTXT, body: Some(BlockStmt { + ctxt: Default::default(), span: DUMMY_SP, stmts: vec![ decl_error.into(), @@ -144,8 +149,9 @@ impl VisitMut for DepReplacer<'_> { if let Some(chunk) = chunk { let chunk_id = chunk.id.id.clone(); // `import('./xxx.css')` => `__mako_require__.ensure('./xxx.css')` - *expr = member_expr!(DUMMY_SP, __mako_require__.ensure) - .as_call(DUMMY_SP, vec![quote_str!(chunk_id).as_arg()]); + *expr = + member_expr!(DUMMY_CTXT, DUMMY_SP, __mako_require__.ensure) + .as_call(DUMMY_SP, vec![quote_str!(chunk_id).as_arg()]); return; } else { *expr = Expr::Lit(quote_str!("").into()); @@ -198,9 +204,9 @@ pub fn resolve_web_worker_mut(new_expr: &mut NewExpr, unresolved_mark: Mark) -> return None; } - if let box Expr::Ident(Ident { span, sym, .. }) = &mut new_expr.callee { + if let box Expr::Ident(Ident { sym, ctxt, .. }) = &mut new_expr.callee { // `Worker` must be unresolved - if sym == "Worker" && (span.ctxt.outer() == unresolved_mark) { + if sym == "Worker" && (ctxt.outer() == unresolved_mark) { let args = new_expr.args.as_mut().unwrap(); // new Worker(new URL(''), base); @@ -211,8 +217,8 @@ pub fn resolve_web_worker_mut(new_expr: &mut NewExpr, unresolved_mark: Mark) -> return None; } - if let box Expr::Ident(Ident { span, sym, .. }) = &new_expr.callee { - if sym == "URL" && (span.ctxt.outer() == unresolved_mark) { + if let box Expr::Ident(Ident { sym, ctxt, .. }) = &new_expr.callee { + if sym == "URL" && (ctxt.outer() == unresolved_mark) { // new URL(''); let args = new_expr.args.as_mut().unwrap(); if let box Expr::Lit(Lit::Str(ref mut str)) = &mut args[0].expr { @@ -380,7 +386,6 @@ try { to_replace: &DependenciesToReplace { resolved, missing }, context: &test_utils.context, unresolved_mark: ast.unresolved_mark, - top_level_mark: ast.top_level_mark, }; ast.ast.visit_mut_with(&mut visitor); }); diff --git a/crates/mako/src/visitors/dynamic_import.rs b/crates/mako/src/visitors/dynamic_import.rs index 9af78bc09..91014fde8 100644 --- a/crates/mako/src/visitors/dynamic_import.rs +++ b/crates/mako/src/visitors/dynamic_import.rs @@ -10,6 +10,7 @@ use swc_core::ecma::utils::{ use swc_core::ecma::visit::{VisitMut, VisitMutWith}; use crate::ast::utils::{is_dynamic_import, promise_all, require_ensure}; +use crate::ast::DUMMY_CTXT; use crate::compiler::Context; use crate::generate::chunk::ChunkId; use crate::visitors::dep_replacer::DependenciesToReplace; @@ -42,11 +43,7 @@ impl<'a> VisitMut for DynamicImport<'a> { let insert_at = n .body .iter() - .position(|module_item| { - !module_item - .as_stmt() - .map_or(false, |stmt| stmt.is_directive()) - }) + .position(|module_item| !module_item.directive_continue()) .unwrap(); let (id, _) = self @@ -138,18 +135,19 @@ impl<'a> VisitMut for DynamicImport<'a> { .into(), }); - let lazy_require_call = member_expr!(DUMMY_SP, __mako_require__.bind) - .as_call( + let lazy_require_call = + member_expr!(DUMMY_CTXT, DUMMY_SP, __mako_require__.bind).as_call( DUMMY_SP, vec![ quote_ident!("__mako_require__").as_arg(), quote_str!(resolved_source.clone()).as_arg(), ], ); - let dr_call = member_expr!(DUMMY_SP, __mako_require__.dr).as_call( - DUMMY_SP, - vec![self.interop.clone().as_arg(), lazy_require_call.as_arg()], - ); + let dr_call = member_expr!(DUMMY_CTXT, DUMMY_SP, __mako_require__.dr) + .as_call( + DUMMY_SP, + vec![self.interop.clone().as_arg(), lazy_require_call.as_arg()], + ); member_expr!(@EXT, DUMMY_SP, load_promise.into(), then) .as_call(call_expr.span, vec![dr_call.as_arg()]) diff --git a/crates/mako/src/visitors/dynamic_import_to_require.rs b/crates/mako/src/visitors/dynamic_import_to_require.rs index 2992006d0..2890b477d 100644 --- a/crates/mako/src/visitors/dynamic_import_to_require.rs +++ b/crates/mako/src/visitors/dynamic_import_to_require.rs @@ -6,6 +6,8 @@ use swc_core::ecma::utils::{ use swc_core::ecma::visit::{VisitMut, VisitMutWith}; use crate::ast::utils::is_dynamic_import; +use crate::ast::DUMMY_CTXT; + pub struct DynamicImportToRequire { pub unresolved_mark: Mark, changed: bool, @@ -31,11 +33,7 @@ impl VisitMut for DynamicImportToRequire { let insert_at = n .body .iter() - .position(|module_item| { - !module_item - .as_stmt() - .map_or(false, |stmt| stmt.is_directive()) - }) + .position(|module_item| !module_item.directive_continue()) .unwrap(); let require_interop = quote_ident!("__mako_require__").as_call( DUMMY_SP, @@ -62,17 +60,19 @@ impl VisitMut for DynamicImportToRequire { .. } = &mut call_expr.args[0] { - let source_lazy_require = - quote_ident!(DUMMY_SP.apply_mark(self.unresolved_mark), "require") - .as_call(DUMMY_SP, vec![quote_str!(source.value.clone()).as_arg()]) - .into_lazy_arrow(vec![]); + let ctxt = DUMMY_CTXT.apply_mark(self.unresolved_mark); + + let source_lazy_require = quote_ident!(ctxt, "require") + .as_call(DUMMY_SP, vec![quote_str!(source.value.clone()).as_arg()]) + .into_lazy_arrow(vec![]); // Promise.resolve() - let promise_resolve: Box = member_expr!(DUMMY_SP, Promise.resolve) - .as_call(DUMMY_SP, vec![]) - .into(); + let promise_resolve: Box = + member_expr!(DUMMY_CTXT, DUMMY_SP, Promise.resolve) + .as_call(DUMMY_SP, vec![]) + .into(); - let interop_call = quote_ident!(DUMMY_SP, self.interop.as_ref()); + let interop_call = quote_ident!(DUMMY_CTXT, self.interop.as_ref()); let promised_require: Expr = member_expr!(@EXT,DUMMY_SP, promise_resolve, then) .as_call(DUMMY_SP, vec![source_lazy_require.as_arg()]); let interop_require = diff --git a/crates/mako/src/visitors/env_replacer.rs b/crates/mako/src/visitors/env_replacer.rs index 37f691c32..87b873ae8 100644 --- a/crates/mako/src/visitors/env_replacer.rs +++ b/crates/mako/src/visitors/env_replacer.rs @@ -6,8 +6,8 @@ use anyhow::{anyhow, Result}; use serde_json::Value; use swc_core::common::{Mark, Span, DUMMY_SP}; use swc_core::ecma::ast::{ - ArrayLit, Bool, ComputedPropName, Expr, ExprOrSpread, Ident, KeyValueProp, Lit, MemberExpr, - MemberProp, ModuleItem, Null, Number, ObjectLit, Prop, PropOrSpread, Stmt, Str, + ArrayLit, Bool, ComputedPropName, Expr, ExprOrSpread, Ident, IdentName, KeyValueProp, Lit, + MemberExpr, MemberProp, ModuleItem, Null, Number, ObjectLit, Prop, PropOrSpread, Stmt, Str, }; use swc_core::ecma::utils::{quote_ident, ExprExt}; use swc_core::ecma::visit::{VisitMut, VisitMutWith}; @@ -36,9 +36,9 @@ impl EnvReplacer { } impl VisitMut for EnvReplacer { fn visit_mut_expr(&mut self, expr: &mut Expr) { - if let Expr::Ident(Ident { span, .. }) = expr { + if let Expr::Ident(Ident { ctxt, .. }) = expr { // 先判断 env 中的变量名称,是否是上下文中已经存在的变量名称 - if span.ctxt.outer() != self.unresolved_mark { + if ctxt.outer() != self.unresolved_mark { expr.visit_mut_children_with(self); return; } @@ -47,12 +47,11 @@ impl VisitMut for EnvReplacer { match expr { Expr::Member(MemberExpr { obj, prop, .. }) => { let mut member_visit_path = match prop { - MemberProp::Ident(Ident { sym, .. }) => sym.to_string(), + MemberProp::Ident(IdentName { sym, .. }) => sym.to_string(), MemberProp::Computed(ComputedPropName { expr: expr_compute, .. }) => match expr_compute.as_ref() { Expr::Lit(Lit::Str(Str { value, .. })) => value.to_string(), - Expr::Lit(Lit::Num(Number { value, .. })) => value.to_string(), _ => { obj.visit_mut_with(self); @@ -67,7 +66,7 @@ impl VisitMut for EnvReplacer { while let Expr::Member(MemberExpr { obj, prop, .. }) = current_member_obj { match prop { - MemberProp::Ident(Ident { sym, .. }) => { + MemberProp::Ident(IdentName { sym, .. }) => { member_visit_path.push('.'); member_visit_path.push_str(sym.as_ref()); } @@ -94,8 +93,8 @@ impl VisitMut for EnvReplacer { current_member_obj = obj.as_mut(); } - if let Expr::Ident(Ident { sym, span, .. }) = current_member_obj { - if span.ctxt.outer() != self.unresolved_mark { + if let Expr::Ident(Ident { sym, ctxt, .. }) = current_member_obj { + if ctxt.outer() != self.unresolved_mark { return; } member_visit_path.push('.'); diff --git a/crates/mako/src/visitors/fix_symbol_conflict.rs b/crates/mako/src/visitors/fix_symbol_conflict.rs index be5d5ff50..83c44d85f 100644 --- a/crates/mako/src/visitors/fix_symbol_conflict.rs +++ b/crates/mako/src/visitors/fix_symbol_conflict.rs @@ -8,6 +8,8 @@ use swc_core::ecma::ast::{Id, Ident, Module}; use swc_core::ecma::utils::IdentRenamer; use swc_core::ecma::visit::{VisitMut, VisitMutWith}; +use crate::ast::DUMMY_CTXT; + pub(crate) struct FixSymbolConflict { idents_named_symbol: HashSet, top_level_ctxt: SyntaxContext, @@ -17,14 +19,14 @@ impl FixSymbolConflict { pub fn new(top_level_mark: Mark) -> Self { Self { idents_named_symbol: Default::default(), - top_level_ctxt: SyntaxContext::empty().apply_mark(top_level_mark), + top_level_ctxt: DUMMY_CTXT.apply_mark(top_level_mark), } } } impl VisitMut for FixSymbolConflict { fn visit_mut_ident(&mut self, n: &mut Ident) { - if n.sym.eq("Symbol") && n.span.ctxt == self.top_level_ctxt { + if n.sym.eq("Symbol") && n.ctxt == self.top_level_ctxt { self.idents_named_symbol.insert(n.to_id()); } } diff --git a/crates/mako/src/visitors/import_meta_env_replacer.rs b/crates/mako/src/visitors/import_meta_env_replacer.rs index 366a4789e..b8e38931d 100644 --- a/crates/mako/src/visitors/import_meta_env_replacer.rs +++ b/crates/mako/src/visitors/import_meta_env_replacer.rs @@ -1,9 +1,8 @@ use swc_core::common::DUMMY_SP; use swc_core::ecma::ast::{ - Expr, Ident, KeyValueProp, MemberExpr, MemberProp, MetaPropExpr, MetaPropKind, ObjectLit, Prop, - PropOrSpread, + Expr, IdentName, KeyValueProp, MemberExpr, MemberProp, MetaPropExpr, MetaPropKind, ObjectLit, + Prop, PropOrSpread, }; -use swc_core::ecma::atoms::js_word; use swc_core::ecma::utils::{quote_ident, quote_str, ExprFactory}; use swc_core::ecma::visit::{VisitMut, VisitMutWith}; @@ -27,13 +26,9 @@ impl VisitMut for ImportMetaEnvReplacer { kind: MetaPropKind::ImportMeta, .. }), - prop: - MemberProp::Ident(Ident { - sym: js_word!("env"), - .. - }), + prop: MemberProp::Ident(IdentName { sym, .. }), .. - }) => { + }) if sym == "env" => { // replace import.meta.env with "({ MODE: 'production' })" *expr = ObjectLit { props: vec![PropOrSpread::Prop( @@ -54,7 +49,6 @@ impl VisitMut for ImportMetaEnvReplacer { #[cfg(test)] mod tests { - use swc_core::common::GLOBALS; use swc_core::ecma::visit::VisitMutWith; diff --git a/crates/mako/src/visitors/mako_require.rs b/crates/mako/src/visitors/mako_require.rs index dd060d766..02da722cf 100644 --- a/crates/mako/src/visitors/mako_require.rs +++ b/crates/mako/src/visitors/mako_require.rs @@ -16,7 +16,7 @@ impl MakoRequire { fn replace_require(&mut self, ident: &mut Ident) { // replace native require to __mako_require__ except ignored identities if is_ident_undefined(ident, "require", &self.unresolved_mark) { - *ident = Ident::new(MAKO_REQUIRE.into(), ident.span); + *ident = Ident::new(MAKO_REQUIRE.into(), ident.span, ident.ctxt); } } } diff --git a/crates/mako/src/visitors/meta_url_replacer.rs b/crates/mako/src/visitors/meta_url_replacer.rs index 7e822234d..3fd8f95be 100644 --- a/crates/mako/src/visitors/meta_url_replacer.rs +++ b/crates/mako/src/visitors/meta_url_replacer.rs @@ -4,6 +4,7 @@ use swc_core::ecma::utils::member_expr; use swc_core::ecma::visit::{VisitMut, VisitMutWith}; use crate::ast::utils::is_import_meta_url; +use crate::ast::DUMMY_CTXT; pub struct MetaUrlReplacer {} @@ -13,9 +14,9 @@ impl VisitMut for MetaUrlReplacer { // Compatible with workers: self.document ? self.document.baseURI : self.location.href *expr = Expr::Cond(CondExpr { span: DUMMY_SP, - test: member_expr!(DUMMY_SP, self.document), - cons: member_expr!(DUMMY_SP, self.document.baseURI), - alt: member_expr!(DUMMY_SP, self.location.href), + test: member_expr!(DUMMY_CTXT, DUMMY_SP, self.document).into(), + cons: member_expr!(DUMMY_CTXT, DUMMY_SP, self.document.baseURI).into(), + alt: member_expr!(DUMMY_CTXT, DUMMY_SP, self.location.href).into(), }); } diff --git a/crates/mako/src/visitors/new_url_assets.rs b/crates/mako/src/visitors/new_url_assets.rs index 4b672858c..665f6c7e5 100644 --- a/crates/mako/src/visitors/new_url_assets.rs +++ b/crates/mako/src/visitors/new_url_assets.rs @@ -8,7 +8,7 @@ use swc_core::ecma::utils::{member_expr, quote_str}; use swc_core::ecma::visit::VisitMut; use crate::ast::file::File; -use crate::ast::utils; +use crate::ast::{utils, DUMMY_CTXT}; use crate::build::load::Load; use crate::compiler::Context; use crate::config::Platform; @@ -51,8 +51,8 @@ impl NewUrlAssets { Expr::Bin(BinExpr { span: DUMMY_SP, op: BinaryOp::LogicalOr, - left: member_expr!(DUMMY_SP, document.baseURI), - right: member_expr!(DUMMY_SP, self.location.href), + left: member_expr!(DUMMY_CTXT, DUMMY_SP, document.baseURI).into(), + right: member_expr!(DUMMY_CTXT, DUMMY_SP, self.location.href).into(), }) } else { Expr::Lit( @@ -91,7 +91,12 @@ impl VisitMut for NewUrlAssets { Expr::Bin(BinExpr { span: DUMMY_SP, op: BinaryOp::Add, - left: member_expr!(DUMMY_SP, __mako_require__.publicPath), + left: member_expr!( + DUMMY_CTXT, + DUMMY_SP, + __mako_require__.publicPath + ) + .into(), right: Lit::Str(url.into()).into(), }) .into() diff --git a/crates/mako/src/visitors/optimize_define_utils.rs b/crates/mako/src/visitors/optimize_define_utils.rs index 47b836d5d..e0ac7c83a 100644 --- a/crates/mako/src/visitors/optimize_define_utils.rs +++ b/crates/mako/src/visitors/optimize_define_utils.rs @@ -1,8 +1,10 @@ use swc_core::common::{Mark, DUMMY_SP}; use swc_core::ecma::ast::{CallExpr, Expr, ExprOrSpread, ExprStmt, Lit, ModuleItem, Stmt, Str}; -use swc_core::ecma::utils::member_expr; +use swc_core::ecma::utils::{member_expr, ExprFactory}; use swc_core::ecma::visit::VisitMut; +use crate::ast::DUMMY_CTXT; + // TODO: add testcases pub struct OptimizeDefineUtils { pub top_level_mark: Mark, @@ -34,8 +36,12 @@ impl VisitMut for OptimizeDefineUtils { && is_string_lit_arg_with_value(call_expr.args.get(1), "__esModule") && is_obj_lit_arg(call_expr.args.get(2)) { - call_expr.callee = - member_expr!(DUMMY_SP.apply_mark(self.unresolved_mark), require.d).into(); + call_expr.callee = member_expr!( + DUMMY_CTXT.apply_mark(self.unresolved_mark), + DUMMY_SP, + require.d + ) + .as_callee(); } else { return; } @@ -55,8 +61,12 @@ impl VisitMut for OptimizeDefineUtils { && is_string_lit_arg(call_expr.args.get(1)) && is_obj_lit_arg(call_expr.args.get(2)) { - call_expr.callee = - member_expr!(DUMMY_SP.apply_mark(self.unresolved_mark), require.d).into(); + call_expr.callee = member_expr!( + DUMMY_CTXT.apply_mark(self.unresolved_mark), + DUMMY_SP, + require.d + ) + .as_callee(); return; } @@ -66,16 +76,19 @@ impl VisitMut for OptimizeDefineUtils { && call_expr.args.len() == 2 && is_export_arg(call_expr.args.first()) && is_obj_lit_arg(call_expr.args.get(1)) - && callee_ident.sym.to_string() == "_export" + && callee_ident.sym == "_export" // is private ident && !callee_ident - .span .ctxt .outer() .is_descendant_of(self.top_level_mark) { - call_expr.callee = - member_expr!(DUMMY_SP.apply_mark(self.unresolved_mark), require.e).into(); + call_expr.callee = member_expr!( + DUMMY_CTXT.apply_mark(self.unresolved_mark), + DUMMY_SP, + require.e + ) + .as_callee(); return; } } @@ -95,14 +108,14 @@ fn is_object_define(expr: &Expr) -> bool { let is_object = member .obj .as_ident() - .map(|ident| ident.sym.to_string() == "Object") + .map(|ident| ident.sym == "Object") .unwrap_or(false); is_object && member .prop .as_ident() - .map(|ident| ident.sym.to_string() == "defineProperty") + .map(|ident| ident.sym == "defineProperty") .unwrap_or(false) }) .unwrap_or(false) @@ -114,7 +127,7 @@ fn is_export_arg(arg: Option<&ExprOrSpread>) -> bool { && arg .expr .as_ident() - .map(|ident| ident.sym.to_string() == "exports") + .map(|ident| ident.sym == "exports") .unwrap_or(false) }) .unwrap_or(false) @@ -140,7 +153,7 @@ fn is_string_lit_arg_with_value(arg: Option<&ExprOrSpread>, value: &str) -> bool .as_lit() .map(|lit| { if let Lit::Str(str_lit) = lit { - str_lit.value.to_string() == value + str_lit.value == value } else { false } diff --git a/crates/mako/src/visitors/provide.rs b/crates/mako/src/visitors/provide.rs index bdba70854..5b62e70be 100644 --- a/crates/mako/src/visitors/provide.rs +++ b/crates/mako/src/visitors/provide.rs @@ -6,7 +6,9 @@ use swc_core::ecma::ast::{Expr, Ident, MemberExpr, Module, ModuleItem, VarDeclKi use swc_core::ecma::utils::{quote_ident, quote_str, ExprFactory}; use swc_core::ecma::visit::{VisitMut, VisitMutWith}; +use crate::ast::DUMMY_CTXT; use crate::config::Providers; + pub struct Provide { unresolved_mark: Mark, top_level_mark: Mark, @@ -38,7 +40,7 @@ impl VisitMut for Provide { )) } fn visit_mut_ident(&mut self, n: &mut Ident) { - let has_binding = n.span.ctxt.outer() != self.unresolved_mark; + let has_binding = n.ctxt.outer() != self.unresolved_mark; let name = &n.sym.to_string(); let provider = self.providers.get(name); @@ -87,7 +89,7 @@ impl ToTopLevelVars { let mut replaces: HashMap = Default::default(); vars.iter().for_each(|(k, _)| { - let ctxt = SyntaxContext::empty().apply_mark(top_level_mark); + let ctxt = DUMMY_CTXT.apply_mark(top_level_mark); replaces.insert(k.clone(), ctxt); }); @@ -100,9 +102,9 @@ impl ToTopLevelVars { impl VisitMut for ToTopLevelVars { fn visit_mut_ident(&mut self, i: &mut Ident) { - if i.span.ctxt.outer() == self.unresolved_mark { + if i.ctxt.outer() == self.unresolved_mark { if let Some(ctxt) = self.replaces_map.get(&i.sym.to_string()) { - i.span.ctxt = *ctxt; + i.ctxt = *ctxt; } } } diff --git a/crates/mako/src/visitors/public_path_assignment.rs b/crates/mako/src/visitors/public_path_assignment.rs index 97f054128..fc22ebad6 100644 --- a/crates/mako/src/visitors/public_path_assignment.rs +++ b/crates/mako/src/visitors/public_path_assignment.rs @@ -1,26 +1,28 @@ use swc_core::common::{Mark, DUMMY_SP}; -use swc_core::ecma::ast::{AssignExpr, AssignOp, Pat, PatOrExpr}; +use swc_core::ecma::ast::{AssignExpr, AssignOp, BindingIdent, Ident}; use swc_core::ecma::utils::member_expr; use swc_core::ecma::visit::{VisitMut, VisitMutWith}; +use crate::ast::DUMMY_CTXT; + pub struct PublicPathAssignment { pub unresolved_mark: Mark, } impl VisitMut for PublicPathAssignment { fn visit_mut_assign_expr(&mut self, n: &mut AssignExpr) { - if n.op == AssignOp::Assign { - if let PatOrExpr::Pat(box Pat::Ident(ident)) = &n.left { - let sym = ident.sym.as_ref(); - if ident.span.ctxt.outer() == self.unresolved_mark - && (sym == "__webpack_public_path__" || sym == "__mako_public_path__") - { - *n = AssignExpr { - left: PatOrExpr::Expr(member_expr!(DUMMY_SP, __mako_require__.publicPath)), - ..n.clone() - }; - } - } + if n.op == AssignOp::Assign + && let Some(BindingIdent { + id: Ident { sym, ctxt, .. }, + .. + }) = n.left.as_ident() + && (sym == "__webpack_public_path__" || sym == "__mako_public_path__") + && ctxt.outer() == self.unresolved_mark + { + *n = AssignExpr { + left: member_expr!(DUMMY_CTXT, DUMMY_SP, __mako_require__.publicPath).into(), + ..n.clone() + }; } n.visit_mut_children_with(self); } diff --git a/crates/mako/src/visitors/ts_strip.rs b/crates/mako/src/visitors/ts_strip.rs index b4066bfb0..dbcb81bb3 100644 --- a/crates/mako/src/visitors/ts_strip.rs +++ b/crates/mako/src/visitors/ts_strip.rs @@ -6,17 +6,21 @@ use swc_core::ecma::visit::{VisitMut, VisitMutWith}; pub struct TypescriptStrip { top_level_mark: Mark, + unresolved_mark: Mark, } impl VisitMut for TypescriptStrip { fn visit_mut_module(&mut self, n: &mut Module) { let mut p = Program::Module(n.take()); - p.visit_mut_with(&mut strip(self.top_level_mark)); + p.visit_mut_with(&mut strip(self.unresolved_mark, self.top_level_mark)); *n = p.module().unwrap(); } } -pub fn ts_strip(top_level_mark: Mark) -> impl VisitMut { - TypescriptStrip { top_level_mark } +pub fn ts_strip(unresolved_mark: Mark, top_level_mark: Mark) -> impl VisitMut { + TypescriptStrip { + top_level_mark, + unresolved_mark, + } } diff --git a/crates/mako/src/visitors/tsx_strip.rs b/crates/mako/src/visitors/tsx_strip.rs index 0d1d6e801..d8a170c85 100644 --- a/crates/mako/src/visitors/tsx_strip.rs +++ b/crates/mako/src/visitors/tsx_strip.rs @@ -14,6 +14,7 @@ pub struct TsxStrip { cm: Arc, context: Arc, top_level_mark: Mark, + unresolved_mark: Mark, } impl VisitMut for TsxStrip { @@ -29,6 +30,7 @@ impl VisitMut for TsxStrip { Default::default(), tsx_config, comments, + self.unresolved_mark, self.top_level_mark, )); *n = p.module().unwrap(); @@ -39,10 +41,12 @@ pub fn tsx_strip( cm: Arc, context: Arc, top_level_mark: Mark, + unresolved_mark: Mark, ) -> impl VisitMut { TsxStrip { cm, context, top_level_mark, + unresolved_mark, } } diff --git a/crates/svgr-rs/Cargo.toml b/crates/svgr-rs/Cargo.toml new file mode 100644 index 000000000..fecb95be5 --- /dev/null +++ b/crates/svgr-rs/Cargo.toml @@ -0,0 +1,41 @@ +[package] +authors = ["SyMind "] +description = "A tool to transform SVG into React components" +name = "svgr-rs" +edition = "2021" +license = "MIT" +repository = "https://github.com/svg-rust/svgr-rs.git" +version = "0.1.3" + +[features] +node = ["dep:napi", "dep:napi-derive"] + +[dependencies] +# Default enable napi4 feature, see https://nodejs.org/api/n-api.html#node-api-version-matrix +napi = { version = "2.12.0", default-features = false, features = ["async", "napi4"], optional = true } +napi-derive = { version = "2.12.2", optional = true } + +clap = { version = "4.2.0", features = ["derive"] } +html-escape = "0.2.13" +linked-hash-map = { version = "0.5.6", features = ["serde_impl"] } +linked_hash_set = "0.1.4" +regex = { workspace = true } +serde = { workspace = true, features = ["derive"] } +swc_core = { workspace = true, features = [ + "bundler", + "common_concurrent", + "ecma_ast", + "ecma_ast_serde", + "ecma_codegen", + "ecma_loader", + "ecma_parser", + "ecma_transforms", + "ecma_visit", +] } +swc_xml = "0.17.0" +thiserror = "1.0.56" + +testing = { version = "0.38.1" } + +[profile.release] +lto = true diff --git a/crates/svgr-rs/__fixture__/basic/input.svg b/crates/svgr-rs/__fixture__/basic/input.svg new file mode 100644 index 000000000..478f6e682 --- /dev/null +++ b/crates/svgr-rs/__fixture__/basic/input.svg @@ -0,0 +1,13 @@ + + + + Dismiss + Created with Sketch. + + + + + + + + diff --git a/crates/svgr-rs/__fixture__/basic/output.jsx b/crates/svgr-rs/__fixture__/basic/output.jsx new file mode 100644 index 000000000..302e28a67 --- /dev/null +++ b/crates/svgr-rs/__fixture__/basic/output.jsx @@ -0,0 +1 @@ +{"Dismiss"}{"Created with Sketch."}; diff --git a/crates/svgr-rs/__fixture__/should-handle-spaces-and-tab/input.svg b/crates/svgr-rs/__fixture__/should-handle-spaces-and-tab/input.svg new file mode 100644 index 000000000..1f3b04f46 --- /dev/null +++ b/crates/svgr-rs/__fixture__/should-handle-spaces-and-tab/input.svg @@ -0,0 +1,11 @@ + + + diff --git a/crates/svgr-rs/__fixture__/should-handle-spaces-and-tab/output.jsx b/crates/svgr-rs/__fixture__/should-handle-spaces-and-tab/output.jsx new file mode 100644 index 000000000..0cd3a2605 --- /dev/null +++ b/crates/svgr-rs/__fixture__/should-handle-spaces-and-tab/output.jsx @@ -0,0 +1 @@ +; diff --git a/crates/svgr-rs/src/add_jsx_attribute.rs b/crates/svgr-rs/src/add_jsx_attribute.rs new file mode 100644 index 000000000..5ca4016c2 --- /dev/null +++ b/crates/svgr-rs/src/add_jsx_attribute.rs @@ -0,0 +1,368 @@ +use swc_core::common::{SyntaxContext, DUMMY_SP}; +use swc_core::ecma::ast::*; +use swc_core::ecma::visit::VisitMut; + +use super::core; + +pub enum AttributePosition { + Start, + End, +} + +#[derive(Default)] +pub struct Attribute { + pub name: String, + pub value: Option, + pub spread: bool, + pub literal: bool, + pub position: Option, +} + +pub struct Visitor { + elements: Vec, + attributes: Vec, +} + +impl Visitor { + pub fn new(config: &core::config::Config) -> Self { + let mut attributes = Vec::new(); + + if let Some(svg_props) = &config.svg_props { + for (k, v) in svg_props { + let attr = svg_prop_to_attr(k, v); + attributes.push(attr); + } + } + + let _ref = config._ref.unwrap_or(false); + if _ref { + attributes.push(Attribute { + name: "ref".to_string(), + value: Some("ref".to_string()), + literal: true, + ..Default::default() + }); + } + + let title_prop = config.title_prop.unwrap_or(false); + if title_prop { + attributes.push(Attribute { + name: "aria-labelledby".to_string(), + value: Some("titleId".to_string()), + literal: true, + ..Default::default() + }); + } + + let desc_prop = config.desc_prop.unwrap_or(false); + if desc_prop { + attributes.push(Attribute { + name: "aria-describedby".to_string(), + value: Some("descId".to_string()), + literal: true, + ..Default::default() + }); + } + + let expand_props = match config.expand_props { + core::config::ExpandProps::Bool(b) => b, + _ => true, + }; + let position = match config.expand_props { + core::config::ExpandProps::Start => Some(AttributePosition::Start), + core::config::ExpandProps::End => Some(AttributePosition::End), + _ => None, + }; + if expand_props { + attributes.push(Attribute { + name: "props".to_string(), + spread: true, + position, + ..Default::default() + }); + } + + Self { + elements: vec!["svg".to_string(), "Svg".to_string()], + attributes, + } + } +} + +impl VisitMut for Visitor { + fn visit_mut_jsx_opening_element(&mut self, n: &mut JSXOpeningElement) { + if let JSXElementName::Ident(ident) = &n.name { + if !self.elements.contains(&ident.sym.to_string()) { + return; + } + } else { + return; + } + + for attribute in self.attributes.iter() { + let Attribute { + name, + value, + spread, + literal, + position, + } = attribute; + + let position = match position { + Some(position) => position, + None => &AttributePosition::End, + }; + + let new_attr = get_attr(*spread, name, value.as_ref(), *literal); + + let is_equal_attr = |attr: &JSXAttrOrSpread| -> bool { + if *spread { + if let JSXAttrOrSpread::SpreadElement(spread) = attr { + if let Expr::Ident(ident) = spread.expr.as_ref() { + return ident.sym == *name; + } + } + false + } else { + if let JSXAttrOrSpread::JSXAttr(attr) = attr { + if let JSXAttrName::Ident(ident) = &attr.name { + return ident.sym == *name; + } + } + false + } + }; + + let replaced = n.attrs.clone().iter().enumerate().any(|(index, attr)| { + if !is_equal_attr(attr) { + return false; + } + n.attrs[index] = new_attr.clone(); + true + }); + + if !replaced { + match position { + AttributePosition::Start => { + n.attrs.insert(0, new_attr); + } + AttributePosition::End => { + n.attrs.push(new_attr); + } + } + } + } + } +} + +fn get_attr(spread: bool, name: &str, value: Option<&String>, literal: bool) -> JSXAttrOrSpread { + if spread { + JSXAttrOrSpread::SpreadElement(SpreadElement { + dot3_token: DUMMY_SP, + expr: Box::new(Expr::Ident(Ident { + sym: name.to_string().into(), + span: DUMMY_SP, + ctxt: SyntaxContext::empty(), + optional: false, + })), + }) + } else { + JSXAttrOrSpread::JSXAttr(JSXAttr { + span: DUMMY_SP, + name: JSXAttrName::Ident(IdentName { + sym: name.to_string().into(), + span: DUMMY_SP, + }), + value: get_attr_value(literal, value), + }) + } +} + +fn get_attr_value(literal: bool, attr_value: Option<&String>) -> Option { + match attr_value { + Some(value) => { + if literal { + Some(JSXAttrValue::JSXExprContainer(JSXExprContainer { + span: DUMMY_SP, + expr: JSXExpr::Expr(Box::new(Expr::Ident(Ident { + sym: value.to_string().into(), + span: DUMMY_SP, + ctxt: SyntaxContext::empty(), + optional: false, + }))), + })) + } else { + Some(JSXAttrValue::Lit(Lit::Str(Str { + span: DUMMY_SP, + value: value.to_string().into(), + raw: None, + }))) + } + } + None => None, + } +} + +fn svg_prop_to_attr(key: &str, value: &str) -> Attribute { + let literal = value.starts_with('{') && value.ends_with('}'); + let str = if literal { + &value[1..value.len() - 1] + } else { + value + }; + Attribute { + name: key.to_string(), + value: Some(str.to_string()), + literal, + ..Default::default() + } +} + +#[cfg(test)] +mod tests { + use std::sync::Arc; + + use swc_core::common::{FileName, SourceMap}; + use swc_core::ecma::ast::*; + use swc_core::ecma::codegen::text_writer::JsWriter; + use swc_core::ecma::codegen::Emitter; + use swc_core::ecma::parser::lexer::Lexer; + use swc_core::ecma::parser::{EsSyntax, Parser, StringInput, Syntax}; + use swc_core::ecma::visit::{as_folder, FoldWith}; + + use super::*; + + pub struct Options { + elements: Vec, + attributes: Vec, + } + + fn code_test(input: &str, opts: Options, expected: &str) { + let cm = Arc::::default(); + let fm = cm.new_source_file(FileName::Anon.into(), input.to_string()); + + let lexer = Lexer::new( + Syntax::Es(EsSyntax { + decorators: true, + jsx: true, + ..Default::default() + }), + EsVersion::EsNext, + StringInput::from(&*fm), + None, + ); + + let mut parser = Parser::new_from(lexer); + let module = parser.parse_module().unwrap(); + + let module = module.fold_with(&mut as_folder(Visitor { + elements: opts.elements, + attributes: opts.attributes, + })); + + let mut buf = vec![]; + let mut emitter = Emitter { + cfg: Default::default(), + cm: cm.clone(), + comments: None, + wr: JsWriter::new(cm, "", &mut buf, None), + }; + emitter.emit_module(&module).unwrap(); + let result = String::from_utf8_lossy(&buf).to_string(); + + assert_eq!(result, expected); + } + + #[test] + fn should_add_simple_attribute() { + code_test( + r#"
;"#, + Options { + elements: vec!["div".to_string()], + attributes: vec![Attribute { + name: "disabled".to_string(), + ..Default::default() + }], + }, + r#"
;"#, + ); + } + + #[test] + fn should_add_attribute_with_value() { + code_test( + r#"
;"#, + Options { + elements: vec!["div".to_string()], + attributes: vec![Attribute { + name: "disabled".to_string(), + value: Some("true".to_string()), + ..Default::default() + }], + }, + r#"
;"#, + ); + } + + #[test] + fn should_add_literal_attribute() { + code_test( + r#"
;"#, + Options { + elements: vec!["div".to_string()], + attributes: vec![Attribute { + name: "ref".to_string(), + value: Some("ref".to_string()), + literal: true, + ..Default::default() + }], + }, + r#"
;"#, + ); + + code_test( + r#"
;"#, + Options { + elements: vec!["div".to_string()], + attributes: vec![Attribute { + name: "ref".to_string(), + value: Some("ref ? ref : null".to_string()), + literal: true, + ..Default::default() + }], + }, + r#"
;"#, + ); + } + + #[test] + fn should_add_spread_attribute() { + code_test( + r#"
;"#, + Options { + elements: vec!["div".to_string()], + attributes: vec![Attribute { + name: "props".to_string(), + position: Some(AttributePosition::Start), + spread: true, + ..Default::default() + }], + }, + r#"
;"#, + ); + + code_test( + r#"
;"#, + Options { + elements: vec!["span".to_string()], + attributes: vec![Attribute { + name: "props".to_string(), + position: Some(AttributePosition::End), + spread: true, + ..Default::default() + }], + }, + r#"
;"#, + ); + } +} diff --git a/crates/svgr-rs/src/core/config.rs b/crates/svgr-rs/src/core/config.rs new file mode 100644 index 000000000..d8f297e02 --- /dev/null +++ b/crates/svgr-rs/src/core/config.rs @@ -0,0 +1,186 @@ +use linked_hash_map::LinkedHashMap; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum Icon { + Bool(bool), + Str(String), + Num(f64), +} + +impl Default for Icon { + fn default() -> Self { + Icon::Bool(false) + } +} + +// Untagged enums with empty variants (de)serialize in unintuitive ways +// here: https://github.com/serde-rs/serde/issues/1560 +macro_rules! named_unit_variant { + ($variant:ident) => { + pub mod $variant { + pub fn serialize(serializer: S) -> Result + where + S: serde::Serializer, + { + let s = stringify!($variant).replace("_", "-"); + serializer.serialize_str(&s) + } + + pub fn deserialize<'de, D>(deserializer: D) -> Result<(), D::Error> + where + D: serde::Deserializer<'de>, + { + struct V; + impl<'de> serde::de::Visitor<'de> for V { + type Value = (); + fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + let mut s = String::new(); + s.push_str("\""); + s.push_str(stringify!($variant).replace("_", "-").as_str()); + s.push_str("\""); + f.write_str(&s) + } + fn visit_str(self, value: &str) -> Result { + let s = stringify!($variant).replace("_", "-"); + if value == s { + Ok(()) + } else { + Err(E::invalid_value(serde::de::Unexpected::Str(value), &self)) + } + } + } + deserializer.deserialize_str(V) + } + } + }; +} + +mod strings { + named_unit_variant!(start); + named_unit_variant!(end); + named_unit_variant!(classic); + named_unit_variant!(classic_preact); + named_unit_variant!(automatic); +} + +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +#[serde(untagged)] +pub enum ExpandProps { + Bool(bool), + #[serde(with = "strings::start")] + Start, + #[serde(with = "strings::end")] + #[default] + End, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum JSXRuntime { + #[serde(with = "strings::classic")] + Classic, + #[serde(with = "strings::classic_preact")] + ClassicPreact, + #[serde(with = "strings::automatic")] + Automatic, +} + +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +#[serde(rename_all = "camelCase")] +pub struct JSXRuntimeImport { + pub source: String, + pub namespace: Option, + pub default_specifier: Option, + pub specifiers: Option>, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum ExportType { + Named, + Default, +} + +/// The options used to transform the SVG. +#[derive(Debug, Clone, Default, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct Config { + /// Setting this to `true` will forward ref to the root SVG tag. + #[serde(default)] + #[serde(rename(serialize = "ref"))] + pub _ref: Option, + + /// Add title tag via title property. + /// If title_prop is set to true and no title is provided at render time, this will fallback to an existing title element in the svg if exists. + #[serde(default)] + pub title_prop: Option, + + /// Add desc tag via desc property. + /// If desc_prop is set to true and no description is provided at render time, this will fallback to an existing desc element in the svg if exists. + #[serde(default)] + pub desc_prop: Option, + + /// All properties given to component will be forwarded on SVG tag. + /// Possible values: "start", "end" or false. + #[serde(default)] + pub expand_props: ExpandProps, + + /// Keep `width` and `height` attributes from the root SVG tag. + /// Removal is guaranteed if `dimensions: false`, unlike the `remove_dimensions: true` SVGO plugin option which also generates a `viewBox` from the dimensions if no `viewBox` is present. + #[serde(default)] + pub dimensions: Option, + + /// Replace SVG `width` and `height` by a custom value. + /// If value is omitted, it uses `1em` in order to make SVG size inherits from text size. + #[serde(default)] + pub icon: Option, + + /// Modify all SVG nodes with uppercase and use a specific template with `react-native-svg` imports. + /// All unsupported nodes will be removed. + #[serde(default)] + pub native: Option, + + /// Add props to the root SVG tag. + #[serde(default)] + // Deserialize object/map while maintaining order + // here: https://github.com/serde-rs/serde/issues/269 + pub svg_props: Option>, + + /// Generates `.tsx` files with TypeScript typings. + #[serde(default)] + pub typescript: Option, + + /// Setting this to `true` will wrap the exported component in `React.memo`. + #[serde(default)] + pub memo: Option, + + /// Replace an attribute value by an other. + /// The main usage of this option is to change an icon color to "currentColor" in order to inherit from text color. + #[serde(default)] + pub replace_attr_values: Option>, + + /// Specify a JSX runtime to use. + /// * "classic": adds `import * as React from 'react'` on the top of file + /// * "automatic": do not add anything + /// * "classic-preact": adds `import { h } from 'preact'` on the top of file + #[serde(default)] + pub jsx_runtime: Option, + + /// Specify a custom JSX runtime source to use. Allows to customize the import added at the top of generated file. + #[serde(default)] + pub jsx_runtime_import: Option, + + /// The named export defaults to `ReactComponent`, can be customized with the `named_export` option. + #[serde(default = "default_named_export")] + pub named_export: String, + + /// If you prefer named export in any case, you may set the `export_type` option to `named`. + #[serde(default)] + pub export_type: Option, +} + +fn default_named_export() -> String { + "ReactComponent".to_string() +} diff --git a/crates/svgr-rs/src/core/mod.rs b/crates/svgr-rs/src/core/mod.rs new file mode 100644 index 000000000..0b0fd7ebb --- /dev/null +++ b/crates/svgr-rs/src/core/mod.rs @@ -0,0 +1,2 @@ +pub mod config; +pub mod state; diff --git a/crates/svgr-rs/src/core/state.rs b/crates/svgr-rs/src/core/state.rs new file mode 100644 index 000000000..7d9633d3d --- /dev/null +++ b/crates/svgr-rs/src/core/state.rs @@ -0,0 +1,225 @@ +use std::path::Path; + +use regex::Regex; + +#[cfg(feature = "node")] +#[napi(object)] +#[derive(Debug, Clone, Default)] +pub struct Caller { + pub name: Option, + pub previous_export: Option, +} + +#[cfg(not(feature = "node"))] +#[derive(Debug, Clone, Default)] +pub struct Caller { + pub name: Option, + pub previous_export: Option, +} + +/// The state linked to the transformation. +#[cfg(feature = "node")] +#[napi(object, js_name = "State")] +pub struct Config { + /// The name of the file that is generated, mainly used to find runtime config file to apply. + pub file_path: Option, + + /// The name of the component that will be used in the generated component. + pub component_name: Option, + + /// If you create a tool based on SVGR, it is always better to specify `state.caller`. + /// It permits the inter-operability betweens plugins. + /// If someone create a SVGR plugin it could adapt it specifically to your tool. + pub caller: Option, +} + +impl Default for Config { + fn default() -> Self { + Config { + file_path: None, + component_name: Some("SvgComponent".to_string()), + caller: None, + } + } +} + +#[cfg(not(feature = "node"))] +pub struct Config { + pub file_path: Option, + pub component_name: Option, + pub caller: Option, +} + +#[derive(Debug)] +pub struct InternalConfig { + #[allow(dead_code)] + pub file_path: Option, + pub component_name: String, + pub caller: Option, +} + +impl Default for InternalConfig { + fn default() -> Self { + InternalConfig { + file_path: None, + component_name: "SvgComponent".to_string(), + caller: None, + } + } +} + +fn uppercase_first_letter(s: &str) -> String { + let mut cs = s.chars(); + match cs.next() { + None => String::new(), + Some(f) => f.to_uppercase().chain(cs).collect(), + } +} + +const IDENTIFIER: &str = r"([\p{Alpha}\p{N}_]|$)"; +const SEPARATORS: &str = r"[_.\- ]+"; + +fn pascal_case(input: &str) -> String { + let separators_and_identifier = + Regex::new(format!("{}{}", SEPARATORS, IDENTIFIER).as_str()).unwrap(); + let numbers_and_identifier = Regex::new(format!("(\\d+){}", IDENTIFIER).as_str()).unwrap(); + let result = separators_and_identifier + .replace_all(input, |caps: ®ex::Captures| { + let identifier = caps.get(1).unwrap().as_str(); + identifier.to_uppercase() + }) + .to_string(); + let result = numbers_and_identifier + .replace_all(&result, |caps: ®ex::Captures| { + let num = caps.get(1).unwrap().as_str(); + let identifier = caps.get(2).unwrap().as_str(); + format!("{}{}", num, identifier.to_uppercase()) + }) + .to_string(); + uppercase_first_letter(&result) +} + +fn get_component_name(file_path: &str) -> String { + let valid_char_regex = Regex::new(r"[^a-zA-Z0-9 _-]").unwrap(); + let file_name = valid_char_regex + .replace_all( + Path::new(file_path) + .file_prefix() + .unwrap() + .to_str() + .unwrap(), + "", + ) + .to_string(); + let pascal_case_file_name = pascal_case(&file_name); + format!("Svg{}", pascal_case_file_name) +} + +pub fn expand_state(state: &Config) -> InternalConfig { + InternalConfig { + file_path: state.file_path.clone(), + component_name: match state.component_name.clone() { + Some(component_name) => component_name, + None => match state.file_path.clone() { + None => "SvgComponent".to_string(), + Some(path) => get_component_name(&path), + }, + }, + caller: state.caller.clone(), + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_1() { + let internal_config = expand_state(&Default::default()); + assert_eq!(internal_config.component_name, "SvgComponent"); + } + + #[test] + fn test_2() { + let input = Config { + file_path: Some("hello.svg".to_string()), + component_name: None, + caller: None, + }; + let internal_config = expand_state(&input); + assert_eq!(internal_config.file_path.unwrap(), "hello.svg"); + assert_eq!(internal_config.component_name, "SvgHello"); + } + + #[test] + fn test_3() { + let input = Config { + file_path: Some("hello-you.svg".to_string()), + component_name: None, + caller: None, + }; + let internal_config = expand_state(&input); + assert_eq!(internal_config.file_path.unwrap(), "hello-you.svg"); + assert_eq!(internal_config.component_name, "SvgHelloYou"); + } + + #[test] + fn test_4() { + let input = Config { + file_path: Some("hello_you.svg".to_string()), + component_name: None, + caller: None, + }; + let internal_config = expand_state(&input); + assert_eq!(internal_config.file_path.unwrap(), "hello_you.svg"); + assert_eq!(internal_config.component_name, "SvgHelloYou"); + } + + #[test] + fn test_5() { + let input = Config { + file_path: Some("1_big_svg.svg".to_string()), + component_name: None, + caller: None, + }; + let internal_config = expand_state(&input); + assert_eq!(internal_config.file_path.unwrap(), "1_big_svg.svg"); + assert_eq!(internal_config.component_name, "Svg1BigSvg"); + } + + #[test] + fn test_6() { + let input = Config { + file_path: Some("a&b~c-d_e.svg".to_string()), + component_name: None, + caller: None, + }; + let internal_config = expand_state(&input); + assert_eq!(internal_config.file_path.unwrap(), "a&b~c-d_e.svg"); + assert_eq!(internal_config.component_name, "SvgAbcDE"); + } + + #[test] + fn test_7() { + let input = Config { + file_path: Some("Arrow up.svg".to_string()), + component_name: None, + caller: None, + }; + let internal_config = expand_state(&input); + assert_eq!(internal_config.file_path.unwrap(), "Arrow up.svg"); + assert_eq!(internal_config.component_name, "SvgArrowUp"); + } + + #[test] + fn test_8() { + let input = Config { + file_path: Some("Arrow up.svg".to_string()), + component_name: Some("MyComponent".to_string()), + caller: None, + }; + let internal_config = expand_state(&input); + assert_eq!(internal_config.file_path.unwrap(), "Arrow up.svg"); + assert_eq!(internal_config.component_name, "MyComponent"); + } +} diff --git a/crates/svgr-rs/src/error.rs b/crates/svgr-rs/src/error.rs new file mode 100644 index 000000000..c9bb99d3e --- /dev/null +++ b/crates/svgr-rs/src/error.rs @@ -0,0 +1,11 @@ +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum SvgrError { + #[error("failed to parse SVG: {0}")] + Parse(String), + #[error("this is invalid SVG")] + InvalidSvg, + #[error("invalid configuration option: {0}")] + Configuration(String), +} diff --git a/crates/svgr-rs/src/hast_to_swc_ast/decode_xml.rs b/crates/svgr-rs/src/hast_to_swc_ast/decode_xml.rs new file mode 100644 index 000000000..cf14af172 --- /dev/null +++ b/crates/svgr-rs/src/hast_to_swc_ast/decode_xml.rs @@ -0,0 +1,33 @@ +pub fn decode_xml(s: &str) -> String { + let mut decoded = String::new(); + html_escape::decode_html_entities_to_string(s, &mut decoded); + decoded +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn escape_xml_text() { + let test_cases = vec![ + ("&", "&"), + ("'", "'"), + (""", "\""), + (">", ">"), + ("<", "<"), + ("&中文", "&中文"), + ("&amp;", "&"), + ("&#38;", "&"), + ("&#x26;", "&"), + ("&#38;", "&"), + ("&#38;", "&"), + (":", ":"), + ("&>", "&>"), + ("id=770&#anchor", "id=770&#anchor"), + ]; + test_cases.into_iter().for_each(|(input, expected)| { + assert_eq!(decode_xml(input), expected); + }); + } +} diff --git a/crates/svgr-rs/src/hast_to_swc_ast/mappings.rs b/crates/svgr-rs/src/hast_to_swc_ast/mappings.rs new file mode 100644 index 000000000..91c4d72b7 --- /dev/null +++ b/crates/svgr-rs/src/hast_to_swc_ast/mappings.rs @@ -0,0 +1,492 @@ +use std::collections::HashMap; + +// From https://raw.githubusercontent.com/facebook/react/master/packages/react-dom/src/shared/possibleStandardNames.js +pub fn create_attr_mappings() -> HashMap<&'static str, &'static str> { + HashMap::from([ + // HTML + ("accept", "accept"), + ("acceptcharset", "acceptCharset"), + ("accept-charset", "acceptCharset"), + ("accesskey", "accessKey"), + ("action", "action"), + ("allowfullscreen", "allowFullScreen"), + ("alt", "alt"), + ("as", "as"), + ("async", "async"), + ("autocapitalize", "autoCapitalize"), + ("autocomplete", "autoComplete"), + ("autocorrect", "autoCorrect"), + ("autofocus", "autoFocus"), + ("autoplay", "autoPlay"), + ("autosave", "autoSave"), + ("capture", "capture"), + ("cellpadding", "cellPadding"), + ("cellspacing", "cellSpacing"), + ("challenge", "challenge"), + ("charset", "charSet"), + ("checked", "checked"), + ("children", "children"), + ("cite", "cite"), + ("class", "className"), + ("classid", "classID"), + ("classname", "className"), + ("cols", "cols"), + ("colspan", "colSpan"), + ("content", "content"), + ("contenteditable", "contentEditable"), + ("contextmenu", "contextMenu"), + ("controls", "controls"), + ("controlslist", "controlsList"), + ("coords", "coords"), + ("crossorigin", "crossOrigin"), + ("dangerouslysetinnerhtml", "dangerouslySetInnerHTML"), + ("data", "data"), + ("datetime", "dateTime"), + ("default", "default"), + ("defaultchecked", "defaultChecked"), + ("defaultvalue", "defaultValue"), + ("defer", "defer"), + ("dir", "dir"), + ("disabled", "disabled"), + ("download", "download"), + ("draggable", "draggable"), + ("enctype", "encType"), + ("for", "htmlFor"), + ("form", "form"), + ("formmethod", "formMethod"), + ("formaction", "formAction"), + ("formenctype", "formEncType"), + ("formnovalidate", "formNoValidate"), + ("formtarget", "formTarget"), + ("frameborder", "frameBorder"), + ("headers", "headers"), + ("height", "height"), + ("hidden", "hidden"), + ("high", "high"), + ("href", "href"), + ("hreflang", "hrefLang"), + ("htmlfor", "htmlFor"), + ("httpequiv", "httpEquiv"), + ("http-equiv'", "httpEquiv"), + ("icon", "icon"), + ("id", "id"), + ("innerhtml", "innerHTML"), + ("inputmode", "inputMode"), + ("integrity", "integrity"), + ("is", "is"), + ("itemid", "itemID"), + ("itemprop", "itemProp"), + ("itemref", "itemRef"), + ("itemscope", "itemScope"), + ("itemtype", "itemType"), + ("keyparams", "keyParams"), + ("keytype", "keyType"), + ("kind", "kind"), + ("label", "label"), + ("lang", "lang"), + ("list", "list"), + ("loop", "loop"), + ("low", "low"), + ("manifest", "manifest"), + ("marginwidth", "marginWidth"), + ("marginheight", "marginHeight"), + ("max", "max"), + ("maxlength", "maxLength"), + ("media", "media"), + ("mediagroup", "mediaGroup"), + ("method", "method"), + ("min", "min"), + ("minlength", "minLength"), + ("multiple", "multiple"), + ("muted", "muted"), + ("name", "name"), + ("nomodule", "noModule"), + ("nonce", "nonce"), + ("novalidate", "noValidate"), + ("open", "open"), + ("optimum", "optimum"), + ("pattern", "pattern"), + ("placeholder", "placeholder"), + ("playsinline", "playsInline"), + ("poster", "poster"), + ("preload", "preload"), + ("profile", "profile"), + ("radiogroup", "radioGroup"), + ("readonly", "readOnly"), + ("referrerpolicy", "referrerPolicy"), + ("rel", "rel"), + ("required", "required"), + ("reversed", "reversed"), + ("role", "role"), + ("rows", "rows"), + ("rowspan", "rowSpan"), + ("sandbox", "sandbox"), + ("scope", "scope"), + ("scoped", "scoped"), + ("scrolling", "scrolling"), + ("seamless", "seamless"), + ("selected", "selected"), + ("shape", "shape"), + ("size", "size"), + ("sizes", "sizes"), + ("span", "span"), + ("spellcheck", "spellCheck"), + ("src", "src"), + ("srcdoc", "srcDoc"), + ("srclang", "srcLang"), + ("srcset", "srcSet"), + ("start", "start"), + ("step", "step"), + ("style", "style"), + ("summary", "summary"), + ("tabindex", "tabIndex"), + ("target", "target"), + ("title", "title"), + ("type", "type"), + ("usemap", "useMap"), + ("value", "value"), + ("width", "width"), + ("wmode", "wmode"), + ("wrap", "wrap"), + // SVG + ("about", "about"), + ("accentheight", "accentHeight"), + ("accent-height", "accentHeight"), + ("accumulate", "accumulate"), + ("additive", "additive"), + ("alignmentbaseline", "alignmentBaseline"), + ("alignment-baseline", "alignmentBaseline"), + ("allowreorder", "allowReorder"), + ("alphabetic", "alphabetic"), + ("amplitude", "amplitude"), + ("arabicform", "arabicForm"), + ("arabic-form", "arabicForm"), + ("ascent", "ascent"), + ("attributename", "attributeName"), + ("attributetype", "attributeType"), + ("autoreverse", "autoReverse"), + ("azimuth", "azimuth"), + ("basefrequency", "baseFrequency"), + ("baselineshift", "baselineShift"), + ("baseline-shift", "baselineShift"), + ("baseprofile", "baseProfile"), + ("bbox", "bbox"), + ("begin", "begin"), + ("bias", "bias"), + ("by", "by"), + ("calcmode", "calcMode"), + ("capheight", "capHeight"), + ("cap-height", "capHeight"), + ("clip", "clip"), + ("clippath", "clipPath"), + ("clip-path", "clipPath"), + ("clippathunits", "clipPathUnits"), + ("cliprule", "clipRule"), + ("clip-rule", "clipRule"), + ("color", "color"), + ("colorinterpolation", "colorInterpolation"), + ("color-interpolation", "colorInterpolation"), + ("colorinterpolationfilters", "colorInterpolationFilters"), + ("color-interpolation-filters", "colorInterpolationFilters"), + ("colorprofile", "colorProfile"), + ("color-profile", "colorProfile"), + ("colorrendering", "colorRendering"), + ("color-rendering", "colorRendering"), + ("contentscripttype", "contentScriptType"), + ("contentstyletype", "contentStyleType"), + ("cursor", "cursor"), + ("cx", "cx"), + ("cy", "cy"), + ("d", "d"), + ("datatype", "datatype"), + ("decelerate", "decelerate"), + ("descent", "descent"), + ("diffuseconstant", "diffuseConstant"), + ("direction", "direction"), + ("display", "display"), + ("divisor", "divisor"), + ("dominantbaseline", "dominantBaseline"), + ("dominant-baseline", "dominantBaseline"), + ("dur", "dur"), + ("dx", "dx"), + ("dy", "dy"), + ("edgemode", "edgeMode"), + ("elevation", "elevation"), + ("enablebackground", "enableBackground"), + ("enable-background", "enableBackground"), + ("end", "end"), + ("exponent", "exponent"), + ("externalresourcesrequired", "externalResourcesRequired"), + ("fill", "fill"), + ("fillopacity", "fillOpacity"), + ("fill-opacity", "fillOpacity"), + ("fillrule", "fillRule"), + ("fill-rule", "fillRule"), + ("filter", "filter"), + ("filterres", "filterRes"), + ("filterunits", "filterUnits"), + ("floodopacity", "floodOpacity"), + ("flood-opacity", "floodOpacity"), + ("floodcolor", "floodColor"), + ("flood-color", "floodColor"), + ("focusable", "focusable"), + ("fontfamily", "fontFamily"), + ("font-family", "fontFamily"), + ("fontsize", "fontSize"), + ("font-size", "fontSize"), + ("fontsizeadjust", "fontSizeAdjust"), + ("font-size-adjust", "fontSizeAdjust"), + ("fontstretch", "fontStretch"), + ("font-stretch", "fontStretch"), + ("fontstyle", "fontStyle"), + ("font-style", "fontStyle"), + ("fontvariant", "fontVariant"), + ("font-variant", "fontVariant"), + ("fontweight", "fontWeight"), + ("font-weight", "fontWeight"), + ("format", "format"), + ("from", "from"), + ("fx", "fx"), + ("fy", "fy"), + ("g1", "g1"), + ("g2", "g2"), + ("glyphname", "glyphName"), + ("glyph-name", "glyphName"), + ("glyphorientationhorizontal", "glyphOrientationHorizontal"), + ("glyph-orientation-horizontal", "glyphOrientationHorizontal"), + ("glyphorientationvertical", "glyphOrientationVertical"), + ("glyph-orientation-vertical", "glyphOrientationVertical"), + ("glyphref", "glyphRef"), + ("gradienttransform", "gradientTransform"), + ("gradientunits", "gradientUnits"), + ("hanging", "hanging"), + ("horizadvx", "horizAdvX"), + ("horiz-adv-x", "horizAdvX"), + ("horizoriginx", "horizOriginX"), + ("horiz-origin-x", "horizOriginX"), + ("ideographic", "ideographic"), + ("imagerendering", "imageRendering"), + ("image-rendering", "imageRendering"), + ("in2", "in2"), + ("in", "in"), + ("inlist", "inlist"), + ("intercept", "intercept"), + ("k1", "k1"), + ("k2", "k2"), + ("k3", "k3"), + ("k4", "k4"), + ("k", "k"), + ("kernelmatrix", "kernelMatrix"), + ("kernelunitlength", "kernelUnitLength"), + ("kerning", "kerning"), + ("keypoints", "keyPoints"), + ("keysplines", "keySplines"), + ("keytimes", "keyTimes"), + ("lengthadjust", "lengthAdjust"), + ("letterspacing", "letterSpacing"), + ("letter-spacing", "letterSpacing"), + ("lightingcolor", "lightingColor"), + ("lighting-color", "lightingColor"), + ("limitingconeangle", "limitingConeAngle"), + ("local", "local"), + ("markerend", "markerEnd"), + ("marker-end", "markerEnd"), + ("markerheight", "markerHeight"), + ("markermid", "markerMid"), + ("marker-mid", "markerMid"), + ("markerstart", "markerStart"), + ("marker-start", "markerStart"), + ("markerunits", "markerUnits"), + ("markerwidth", "markerWidth"), + ("mask", "mask"), + ("maskcontentunits", "maskContentUnits"), + ("maskunits", "maskUnits"), + ("mathematical", "mathematical"), + ("mode", "mode"), + ("numoctaves", "numOctaves"), + ("offset", "offset"), + ("opacity", "opacity"), + ("operator", "operator"), + ("order", "order"), + ("orient", "orient"), + ("orientation", "orientation"), + ("origin", "origin"), + ("overflow", "overflow"), + ("overlineposition", "overlinePosition"), + ("overline-position", "overlinePosition"), + ("overlinethickness", "overlineThickness"), + ("overline-thickness", "overlineThickness"), + ("paintorder", "paintOrder"), + ("paint-order", "paintOrder"), + ("panose1", "panose1"), + ("panose-1", "panose1"), + ("pathlength", "pathLength"), + ("patterncontentunits", "patternContentUnits"), + ("patterntransform", "patternTransform"), + ("patternunits", "patternUnits"), + ("pointerevents", "pointerEvents"), + ("pointer-events", "pointerEvents"), + ("points", "points"), + ("pointsatx", "pointsAtX"), + ("pointsaty", "pointsAtY"), + ("pointsatz", "pointsAtZ"), + ("prefix", "prefix"), + ("preservealpha", "preserveAlpha"), + ("preserveaspectratio", "preserveAspectRatio"), + ("primitiveunits", "primitiveUnits"), + ("property", "property"), + ("r", "r"), + ("radius", "radius"), + ("refx", "refX"), + ("refy", "refY"), + ("renderingintent", "renderingIntent"), + ("rendering-intent", "renderingIntent"), + ("repeatcount", "repeatCount"), + ("repeatdur", "repeatDur"), + ("requiredextensions", "requiredExtensions"), + ("requiredfeatures", "requiredFeatures"), + ("resource", "resource"), + ("restart", "restart"), + ("result", "result"), + ("results", "results"), + ("rotate", "rotate"), + ("rx", "rx"), + ("ry", "ry"), + ("scale", "scale"), + ("security", "security"), + ("seed", "seed"), + ("shaperendering", "shapeRendering"), + ("shape-rendering", "shapeRendering"), + ("slope", "slope"), + ("spacing", "spacing"), + ("specularconstant", "specularConstant"), + ("specularexponent", "specularExponent"), + ("speed", "speed"), + ("spreadmethod", "spreadMethod"), + ("startoffset", "startOffset"), + ("stddeviation", "stdDeviation"), + ("stemh", "stemh"), + ("stemv", "stemv"), + ("stitchtiles", "stitchTiles"), + ("stopcolor", "stopColor"), + ("stop-color", "stopColor"), + ("stopopacity", "stopOpacity"), + ("stop-opacity", "stopOpacity"), + ("strikethroughposition", "strikethroughPosition"), + ("strikethrough-position", "strikethroughPosition"), + ("strikethroughthickness", "strikethroughThickness"), + ("strikethrough-thickness", "strikethroughThickness"), + ("string", "string"), + ("stroke", "stroke"), + ("strokedasharray", "strokeDasharray"), + ("stroke-dasharray", "strokeDasharray"), + ("strokedashoffset", "strokeDashoffset"), + ("stroke-dashoffset", "strokeDashoffset"), + ("strokelinecap", "strokeLinecap"), + ("stroke-linecap", "strokeLinecap"), + ("strokelinejoin", "strokeLinejoin"), + ("stroke-linejoin", "strokeLinejoin"), + ("strokemiterlimit", "strokeMiterlimit"), + ("stroke-miterlimit", "strokeMiterlimit"), + ("strokewidth", "strokeWidth"), + ("stroke-width", "strokeWidth"), + ("strokeopacity", "strokeOpacity"), + ("stroke-opacity", "strokeOpacity"), + ( + "suppresscontenteditablewarning", + "suppressContentEditableWarning", + ), + ("suppresshydrationwarning", "suppressHydrationWarning"), + ("surfacescale", "surfaceScale"), + ("systemlanguage", "systemLanguage"), + ("tablevalues", "tableValues"), + ("targetx", "targetX"), + ("targety", "targetY"), + ("textanchor", "textAnchor"), + ("text-anchor", "textAnchor"), + ("textdecoration", "textDecoration"), + ("text-decoration", "textDecoration"), + ("textlength", "textLength"), + ("textrendering", "textRendering"), + ("text-rendering", "textRendering"), + ("to", "to"), + ("transform", "transform"), + ("typeof", "typeof"), + ("u1", "u1"), + ("u2", "u2"), + ("underlineposition", "underlinePosition"), + ("underline-position", "underlinePosition"), + ("underlinethickness", "underlineThickness"), + ("underline-thickness", "underlineThickness"), + ("unicode", "unicode"), + ("unicodebidi", "unicodeBidi"), + ("unicode-bidi", "unicodeBidi"), + ("unicoderange", "unicodeRange"), + ("unicode-range", "unicodeRange"), + ("unitsperem", "unitsPerEm"), + ("units-per-em", "unitsPerEm"), + ("unselectable", "unselectable"), + ("valphabetic", "vAlphabetic"), + ("v-alphabetic", "vAlphabetic"), + ("values", "values"), + ("vectoreffect", "vectorEffect"), + ("vector-effect", "vectorEffect"), + ("version", "version"), + ("vertadvy", "vertAdvY"), + ("vert-adv-y", "vertAdvY"), + ("vertoriginx", "vertOriginX"), + ("vert-origin-x", "vertOriginX"), + ("vertoriginy", "vertOriginY"), + ("vert-origin-y", "vertOriginY"), + ("vhanging", "vHanging"), + ("v-hanging", "vHanging"), + ("videographic", "vIdeographic"), + ("v-ideographic", "vIdeographic"), + ("viewbox", "viewBox"), + ("viewtarget", "viewTarget"), + ("visibility", "visibility"), + ("vmathematical", "vMathematical"), + ("v-mathematical", "vMathematical"), + ("vocab", "vocab"), + ("widths", "widths"), + ("wordspacing", "wordSpacing"), + ("word-spacing", "wordSpacing"), + ("writingmode", "writingMode"), + ("writing-mode", "writingMode"), + ("x1", "x1"), + ("x2", "x2"), + ("x", "x"), + ("xchannelselector", "xChannelSelector"), + ("xheight", "xHeight"), + ("x-height", "xHeight"), + ("xlinkactuate", "xlinkActuate"), + ("xlink:actuate", "xlinkActuate"), + ("xlinkarcrole", "xlinkArcrole"), + ("xlink:arcrole", "xlinkArcrole"), + ("xlinkhref", "xlinkHref"), + ("xlink:href", "xlinkHref"), + ("xlinkrole", "xlinkRole"), + ("xlink:role", "xlinkRole"), + ("xlinkshow", "xlinkShow"), + ("xlink:show", "xlinkShow"), + ("xlinktitle", "xlinkTitle"), + ("xlink:title", "xlinkTitle"), + ("xlinktype", "xlinkType"), + ("xlink:type", "xlinkType"), + ("xmlbase", "xmlBase"), + ("xml:base", "xmlBase"), + ("xmllang", "xmlLang"), + ("xml:lang", "xmlLang"), + ("xmlns", "xmlns"), + ("xml:space", "xmlSpace"), + ("xmlnsxlink", "xmlnsXlink"), + ("xmlns:xlink", "xmlnsXlink"), + ("xmlspace", "xmlSpace"), + ("y1", "y1"), + ("y2", "y2"), + ("y", "y"), + ("ychannelselector", "yChannelSelector"), + ("z", "z"), + ("zoomandpan", "zoomAndPan"), + ]) +} diff --git a/crates/svgr-rs/src/hast_to_swc_ast/mod.rs b/crates/svgr-rs/src/hast_to_swc_ast/mod.rs new file mode 100644 index 000000000..b3b49aec9 --- /dev/null +++ b/crates/svgr-rs/src/hast_to_swc_ast/mod.rs @@ -0,0 +1,357 @@ +use std::collections::HashMap; + +use regex::{Captures, Regex}; +use swc_core::common::{SyntaxContext, DUMMY_SP}; +use swc_core::ecma::ast::*; +use swc_core::ecma::atoms::JsWord; +use swc_xml::visit::{Visit, VisitWith}; + +mod decode_xml; +mod mappings; +mod string_to_object_style; +mod util; + +use self::decode_xml::*; +use self::mappings::*; +use self::string_to_object_style::*; +use self::util::*; + +fn kebab_case(str: &str) -> String { + let kebab_regex = Regex::new(r"[A-Z\u00C0-\u00D6\u00D8-\u00DE]").unwrap(); + kebab_regex + .replace_all(str, |caps: &Captures| { + format!("-{}", &caps[0].to_lowercase()) + }) + .to_string() +} + +fn convert_aria_attribute(kebab_key: &str) -> String { + let parts: Vec<&str> = kebab_key.split('-').collect(); + let aria = parts[0]; + let lowercase_parts: String = parts[1..].join("").to_lowercase(); + format!("{}-{}", aria, lowercase_parts) +} + +fn replace_spaces(s: &str) -> String { + let spaces_regex = Regex::new(r"[\t\r\n\u0085\u2028\u2029]+").unwrap(); + spaces_regex.replace_all(s, |_: &Captures| " ").to_string() +} + +fn get_value(attr_name: &str, value: &JsWord) -> JSXAttrValue { + if attr_name == "style" { + let style = string_to_object_style(value); + + return JSXAttrValue::JSXExprContainer(JSXExprContainer { + span: DUMMY_SP, + expr: JSXExpr::Expr(Box::new(style)), + }); + } + + if is_numeric(value) { + return JSXAttrValue::JSXExprContainer(JSXExprContainer { + span: DUMMY_SP, + expr: JSXExpr::Expr(Box::new(Expr::Lit(Lit::Num(Number { + span: DUMMY_SP, + value: value.parse().unwrap(), + raw: None, + })))), + }); + } + + JSXAttrValue::Lit(Lit::Str(Str { + span: DUMMY_SP, + value: replace_spaces(value).into(), + raw: None, + })) +} + +fn text(n: &swc_xml::ast::Text) -> Option { + let value = n.data.to_string(); + + let space_regex = Regex::new(r"^\s+$").unwrap(); + if space_regex.is_match(&value) { + return None; + } + + Some(JSXElementChild::JSXExprContainer(JSXExprContainer { + span: DUMMY_SP, + expr: JSXExpr::Expr(Box::new(Expr::Lit(Lit::Str(Str { + span: DUMMY_SP, + value: decode_xml(&value).into(), + raw: None, + })))), + })) +} + +pub struct HastVisitor { + jsx: Option, + attr_mappings: HashMap<&'static str, &'static str>, +} + +impl HastVisitor { + fn new() -> Self { + Self { + jsx: None, + attr_mappings: create_attr_mappings(), + } + } + + pub fn get_jsx(&self) -> Option { + self.jsx.clone() + } + + fn element(&self, n: &swc_xml::ast::Element) -> JSXElement { + let attrs = n + .attributes + .iter() + .map(|attr| { + let value = attr.value.clone().map(|v| get_value(&attr.name, &v)); + JSXAttrOrSpread::JSXAttr(JSXAttr { + span: DUMMY_SP, + name: JSXAttrName::Ident(self.get_key(&attr.name, &n.tag_name).into()), + value, + }) + }) + .collect::>(); + + let name = JSXElementName::Ident(Ident::new( + n.tag_name.clone(), + DUMMY_SP, + SyntaxContext::empty(), + )); + let children = self.all(&n.children); + + let opening = JSXOpeningElement { + span: DUMMY_SP, + name: name.clone(), + attrs, + self_closing: children.is_empty(), + type_args: None, + }; + + let closing = if !children.is_empty() { + Some(JSXClosingElement { + span: DUMMY_SP, + name, + }) + } else { + None + }; + + JSXElement { + span: DUMMY_SP, + opening, + children, + closing, + } + } + + fn all(&self, children: &[swc_xml::ast::Child]) -> Vec { + children + .iter() + .filter_map(|n| match n { + swc_xml::ast::Child::Element(e) => { + Some(JSXElementChild::JSXElement(Box::new(self.element(e)))) + } + swc_xml::ast::Child::Text(t) => text(t), + _ => None, + }) + .collect() + } + + fn get_key(&self, attr_name: &str, tag_name: &str) -> Ident { + let lower_case_name = attr_name.to_lowercase(); + let rc_key = { + match tag_name { + "input" => match lower_case_name.as_str() { + "checked" => Some("defaultChecked"), + "value" => Some("defaultValue"), + "maxlength" => Some("maxLength"), + _ => None, + }, + "form" => match lower_case_name.as_str() { + "enctype" => Some("encType"), + _ => None, + }, + _ => None, + } + }; + + if let Some(k) = rc_key { + return Ident { + span: DUMMY_SP, + ctxt: SyntaxContext::empty(), + sym: k.into(), + optional: false, + }; + } + + let mapped_attr = self.attr_mappings.get(lower_case_name.as_str()); + if let Some(k) = mapped_attr { + return Ident { + span: DUMMY_SP, + ctxt: SyntaxContext::empty(), + sym: JsWord::from(*k), + optional: false, + }; + } + + let kebab_key = kebab_case(attr_name); + + if kebab_key.starts_with("aria-") { + return Ident { + span: DUMMY_SP, + ctxt: SyntaxContext::empty(), + sym: convert_aria_attribute(attr_name).into(), + optional: false, + }; + } + + if kebab_key.starts_with("data-") { + return Ident { + span: DUMMY_SP, + ctxt: SyntaxContext::empty(), + sym: attr_name.into(), + optional: false, + }; + } + + Ident { + span: DUMMY_SP, + ctxt: SyntaxContext::empty(), + sym: attr_name.into(), + optional: false, + } + } +} + +impl Visit for HastVisitor { + fn visit_element(&mut self, n: &swc_xml::ast::Element) { + self.jsx = Some(self.element(n)); + } +} + +pub fn to_swc_ast(hast: swc_xml::ast::Document) -> Option { + let mut v = HastVisitor::new(); + hast.visit_with(&mut v); + v.get_jsx() +} + +#[cfg(test)] +mod tests { + use std::borrow::Borrow; + use std::path::PathBuf; + use std::sync::Arc; + + use swc_core::common::{FileName, SourceFile, SourceMap}; + use swc_core::ecma::codegen::text_writer::JsWriter; + use swc_core::ecma::codegen::{Config, Emitter}; + use swc_xml::parser::parse_file_as_document; + use testing::NormalizedOutput; + + use super::*; + + fn transform(cm: Arc, fm: Arc, minify: bool) -> String { + let mut errors = vec![]; + let doc = parse_file_as_document(fm.borrow(), Default::default(), &mut errors).unwrap(); + + let jsx = to_swc_ast(doc).unwrap(); + + let mut buf = vec![]; + + let new_line = match minify { + true => "", + false => "\n", + }; + let mut emitter = Emitter { + cfg: Config::default().with_minify(minify), + cm: cm.clone(), + comments: None, + wr: JsWriter::new(cm, new_line, &mut buf, None), + }; + + emitter + .emit_module_item(&ModuleItem::Stmt(Stmt::Expr(ExprStmt { + span: DUMMY_SP, + expr: Box::new(Expr::JSXElement(Box::new(jsx))), + }))) + .unwrap(); + + String::from_utf8_lossy(&buf).to_string() + } + + fn document_test(input: PathBuf) { + let jsx_path = input.parent().unwrap().join("output.jsx"); + + let cm = Arc::::default(); + let fm = cm.load_file(&input).expect("failed to load fixture file"); + + let res = transform(cm, fm, false); + + NormalizedOutput::from(res) + .compare_to_file(jsx_path) + .unwrap(); + } + + fn code_test(input: &str, expected: &str) { + let cm = Arc::::default(); + let fm = cm.new_source_file(FileName::Anon.into(), input.to_string()); + + let res = transform(cm, fm, true); + + assert_eq!(res, expected) + } + + #[testing::fixture("__fixture__/*/*.svg")] + fn pass(input: PathBuf) { + document_test(input); + } + + #[test] + fn transforms_data_x() { + code_test( + r#""#, + r#";"#, + ); + } + + #[test] + fn preserves_mask_type() { + code_test( + r#""#, + r#";"#, + ); + } + + #[test] + fn string_literals_children_of_text_nodes_should_have_decoded_xml_entities() { + code_test( + r#"<"#, + r#"{"<"};"#, + ); + } + + #[test] + fn string_literals_children_of_tspan_nodes_should_have_decoded_xml_entities() { + code_test( + r#"<"#, + r#"{"<"};"#, + ); + } + + #[test] + fn transforms_style() { + code_test( + r#""#, + r#";"#, + ); + } + + #[test] + fn transforms_class() { + code_test( + r#""#, + r#";"#, + ); + } +} diff --git a/crates/svgr-rs/src/hast_to_swc_ast/string_to_object_style.rs b/crates/svgr-rs/src/hast_to_swc_ast/string_to_object_style.rs new file mode 100644 index 000000000..67c3c5793 --- /dev/null +++ b/crates/svgr-rs/src/hast_to_swc_ast/string_to_object_style.rs @@ -0,0 +1,99 @@ +use regex::{Captures, Regex}; +use swc_core::common::DUMMY_SP; +use swc_core::ecma::ast::*; + +use super::util::*; + +const PX_REGEX: &str = r#"^\d+px$"#; +const MS_REGEX: &str = r#"^-ms-"#; +const VAR_REGEX: &str = r#"^--"#; + +pub fn hyphen_to_camel_case(s: &str) -> String { + let regex = Regex::new(r#"-(.)"#).unwrap(); + regex + .replace_all(s, |caps: &Captures| caps[1].to_uppercase()) + .into() +} + +// Format style key into JSX style object key. +pub fn format_key(key: &str) -> PropName { + let var_regex = Regex::new(VAR_REGEX).unwrap(); + if var_regex.is_match(key) { + return PropName::Str(Str { + span: DUMMY_SP, + value: key.into(), + raw: None, + }); + } + + let mut key = key.to_lowercase(); + let ms_regex = Regex::new(MS_REGEX).unwrap(); + if ms_regex.is_match(&key) { + key = key[1..].into(); + } + + PropName::Ident(IdentName::new(hyphen_to_camel_case(&key).into(), DUMMY_SP)) +} + +fn is_convertible_pixel_value(s: &str) -> bool { + let px_regex = Regex::new(PX_REGEX).unwrap(); + px_regex.is_match(s) +} + +// Format style value into JSX style object value. +pub fn format_value(value: &str) -> Expr { + if is_numeric(value) { + return Expr::Lit(Lit::Num(Number { + span: DUMMY_SP, + value: value.parse().unwrap(), + raw: None, + })); + } + + if is_convertible_pixel_value(value) { + return Expr::Lit(Lit::Num(Number { + span: DUMMY_SP, + value: value[..value.len() - 2].parse().unwrap(), + raw: None, + })); + } + + Expr::Lit(Lit::Str(Str { + span: DUMMY_SP, + value: value.into(), + raw: None, + })) +} + +pub fn string_to_object_style(raw_style: &str) -> Expr { + let entries = raw_style.split(';'); + + let properties = entries + .into_iter() + .filter_map(|entry| { + let style = entry.trim(); + if style.is_empty() { + return None; + } + + let first_colon = style.find(':'); + match first_colon { + Some(i) => { + let value = format_value(style[(i + 1)..].trim()); + let key = format_key(style[..i].trim()); + + Some(PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp { + key, + value: Box::new(value), + })))) + } + None => None, + } + }) + .collect::>(); + + Expr::Object(ObjectLit { + span: DUMMY_SP, + props: properties, + }) +} diff --git a/crates/svgr-rs/src/hast_to_swc_ast/util.rs b/crates/svgr-rs/src/hast_to_swc_ast/util.rs new file mode 100644 index 000000000..c7ed0d437 --- /dev/null +++ b/crates/svgr-rs/src/hast_to_swc_ast/util.rs @@ -0,0 +1,6 @@ +use regex::Regex; + +pub fn is_numeric(s: &str) -> bool { + let regex = Regex::new(r#"^(\-|\+)?\d+(\.\d+)?$"#).unwrap(); + regex.is_match(s) +} diff --git a/crates/svgr-rs/src/lib.rs b/crates/svgr-rs/src/lib.rs new file mode 100644 index 000000000..d7bd668ce --- /dev/null +++ b/crates/svgr-rs/src/lib.rs @@ -0,0 +1,134 @@ +#![feature(path_file_prefix)] +#![deny(clippy::all)] + +#[cfg(feature = "node")] +#[macro_use] +extern crate napi_derive; + +use std::borrow::Borrow; +use std::sync::Arc; + +use swc_core::common::comments::SingleThreadedComments; +use swc_core::common::{FileName, SourceMap}; +use swc_core::ecma::codegen::text_writer::JsWriter; +use swc_core::ecma::codegen::Emitter; +use swc_core::ecma::visit::{as_folder, FoldWith}; +use swc_xml::parser::parse_file_as_document; + +mod add_jsx_attribute; +mod core; +mod error; +mod hast_to_swc_ast; +mod remove_jsx_attribute; +mod replace_jsx_attribute; +mod svg_dynamic_title; +mod svg_em_dimensions; +mod transform_react_native_svg; +mod transform_svg_component; + +pub use error::SvgrError; + +pub use self::core::config::{Config, ExpandProps, ExportType, Icon, JSXRuntime, JSXRuntimeImport}; +pub use self::core::state::{Caller, Config as State}; + +/// Transform SVG into React components. +/// +/// It takes three arguments: +/// +/// * source: the SVG source code to transform +/// * options: the options used to transform the SVG +/// * state: a state linked to the transformation +/// +/// # Examples +/// +/// Basic usage: +/// +/// ```rust +/// use svgr_rs::transform; +/// +/// let result = transform( +/// r#""#.to_string(), +/// Default::default(), +/// Default::default(), +/// ); +/// ``` +pub fn transform(code: String, config: Config, state: State) -> Result { + let state = core::state::expand_state(&state); + + let cm = Arc::::default(); + let fm = cm.new_source_file(FileName::Anon.into(), code); + + let mut errors = vec![]; + let document = parse_file_as_document(fm.borrow(), Default::default(), &mut errors) + .map_err(|e| SvgrError::Parse(e.message().to_string()))?; + + let jsx_element = hast_to_swc_ast::to_swc_ast(document); + if jsx_element.is_none() { + return Err(SvgrError::InvalidSvg); + } + let jsx_element = jsx_element.unwrap(); + + let m = transform_svg_component::transform(jsx_element, &config, &state)?; + + let m = m.fold_with(&mut as_folder(remove_jsx_attribute::Visitor::new(&config))); + let m = m.fold_with(&mut as_folder(add_jsx_attribute::Visitor::new(&config))); + + let icon = match config.icon { + Some(core::config::Icon::Bool(b)) => b, + None => false, + _ => true, + }; + let dimensions = config.dimensions.unwrap_or(true); + let m = if icon && dimensions { + m.fold_with(&mut as_folder(svg_em_dimensions::Visitor::new(&config))) + } else { + m + }; + + let replace_attr_values = config.replace_attr_values.is_some(); + let m = if replace_attr_values { + m.fold_with(&mut as_folder(replace_jsx_attribute::Visitor::new(&config))) + } else { + m + }; + + let title_prop = config.title_prop.unwrap_or(false); + let m = if title_prop { + m.fold_with(&mut as_folder(svg_dynamic_title::Visitor::new( + "title".to_string(), + ))) + } else { + m + }; + + let desc_prop = config.desc_prop.unwrap_or(false); + let m = if desc_prop { + m.fold_with(&mut as_folder(svg_dynamic_title::Visitor::new( + "desc".to_string(), + ))) + } else { + m + }; + + let native = config.native.unwrap_or(false); + let m = if native { + let comments = SingleThreadedComments::default(); + m.fold_with(&mut as_folder(transform_react_native_svg::Visitor::new( + &comments, + ))) + } else { + m + }; + + let mut buf = vec![]; + + let mut emitter = Emitter { + cfg: Default::default(), + cm: cm.clone(), + comments: None, + wr: JsWriter::new(cm, "\n", &mut buf, None), + }; + emitter.emit_module(&m).unwrap(); + + Ok(String::from_utf8_lossy(&buf).to_string()) +} diff --git a/crates/svgr-rs/src/remove_jsx_attribute.rs b/crates/svgr-rs/src/remove_jsx_attribute.rs new file mode 100644 index 000000000..31962e223 --- /dev/null +++ b/crates/svgr-rs/src/remove_jsx_attribute.rs @@ -0,0 +1,132 @@ +use swc_core::ecma::ast::*; +use swc_core::ecma::visit::VisitMut; + +use super::core; + +pub struct Visitor { + elements: Vec, + attributes: Vec, +} + +impl Visitor { + pub fn new(config: &core::config::Config) -> Self { + let mut attributes = vec!["version".to_string()]; + + let dimensions = config.dimensions.unwrap_or(true); + if !dimensions { + attributes.push("width".to_string()); + attributes.push("height".to_string()); + } + + Self { + elements: vec!["svg".to_string(), "Svg".to_string()], + attributes, + } + } +} + +impl VisitMut for Visitor { + fn visit_mut_jsx_opening_element(&mut self, n: &mut JSXOpeningElement) { + if let JSXElementName::Ident(ident) = &n.name { + if !self.elements.contains(&ident.sym.to_string()) { + return; + } + } else { + return; + } + + let len = n.attrs.len(); + let mut attrs = n.attrs.clone(); + attrs.reverse(); + attrs.iter().enumerate().for_each(|(index, attr)| { + if let JSXAttrOrSpread::JSXAttr(jsx_attr) = attr { + if let JSXAttrName::Ident(ident) = &jsx_attr.name { + if self.attributes.contains(&ident.sym.to_string()) { + n.attrs.remove(len - index - 1); + } + } + } + }); + } +} + +#[cfg(test)] +mod tests { + use std::default::Default; + use std::sync::Arc; + + use swc_core::common::{FileName, SourceMap}; + use swc_core::ecma::ast::*; + use swc_core::ecma::codegen::text_writer::JsWriter; + use swc_core::ecma::codegen::Emitter; + use swc_core::ecma::parser::lexer::Lexer; + use swc_core::ecma::parser::{EsSyntax, Parser, StringInput, Syntax}; + use swc_core::ecma::visit::{as_folder, FoldWith}; + + use super::*; + + pub struct Options { + elements: Vec, + attributes: Vec, + } + + fn code_test(input: &str, opts: Options, expected: &str) { + let cm = Arc::new(SourceMap::default()); + let fm = cm.new_source_file(FileName::Anon.into(), input.to_string()); + + let lexer = Lexer::new( + Syntax::Es(EsSyntax { + decorators: true, + jsx: true, + ..Default::default() + }), + EsVersion::EsNext, + StringInput::from(&*fm), + None, + ); + + let mut parser = Parser::new_from(lexer); + let module = parser.parse_module().unwrap(); + + let module = module.fold_with(&mut as_folder(Visitor { + elements: opts.elements, + attributes: opts.attributes, + })); + + let mut buf = vec![]; + let mut emitter = Emitter { + cfg: Default::default(), + cm: cm.clone(), + comments: None, + wr: JsWriter::new(cm, "", &mut buf, None), + }; + emitter.emit_module(&module).unwrap(); + let result = String::from_utf8_lossy(&buf).to_string(); + + assert_eq!(result, expected); + } + + #[test] + fn should_remove_attributes_from_an_element() { + code_test( + r#"
;"#, + Options { + elements: vec!["span".to_string()], + attributes: vec!["foo".to_string()], + }, + r#"
;"#, + ); + } + + #[test] + fn should_not_throw_error_when_spread_operator_is_used() { + code_test( + r#"
;"#, + Options { + elements: vec!["span".to_string()], + attributes: vec!["foo".to_string()], + }, + r#"
;"#, + ); + } +} diff --git a/crates/svgr-rs/src/replace_jsx_attribute.rs b/crates/svgr-rs/src/replace_jsx_attribute.rs new file mode 100644 index 000000000..00c12e48a --- /dev/null +++ b/crates/svgr-rs/src/replace_jsx_attribute.rs @@ -0,0 +1,133 @@ +use linked_hash_map::LinkedHashMap; +use swc_core::common::{SyntaxContext, DUMMY_SP}; +use swc_core::ecma::ast::*; +use swc_core::ecma::visit::VisitMut; + +use super::core; + +pub struct Visitor { + values: LinkedHashMap, +} + +impl Visitor { + pub fn new(config: &core::config::Config) -> Self { + let replace_attr_values = config.replace_attr_values.as_ref().unwrap(); + + Self { + values: replace_attr_values.clone(), + } + } +} + +impl VisitMut for Visitor { + fn visit_mut_jsx_opening_element(&mut self, n: &mut JSXOpeningElement) { + n.attrs.iter_mut().for_each(|attr| { + if let JSXAttrOrSpread::JSXAttr(jsx_attr) = attr { + if let Some(JSXAttrValue::Lit(Lit::Str(str))) = &jsx_attr.value { + let old_value = str.value.to_string(); + + if self.values.contains_key(&old_value) { + let attr_value = get_attr_value(self.values.get(&old_value).unwrap()); + jsx_attr.value = Some(attr_value); + } + } + } + }); + } +} + +fn get_attr_value(new: &str) -> JSXAttrValue { + let literal = new.starts_with('{') && new.ends_with('}'); + let s = if literal { &new[1..new.len() - 1] } else { new }; + + if literal { + JSXAttrValue::JSXExprContainer(JSXExprContainer { + span: DUMMY_SP, + expr: JSXExpr::Expr(Box::new(Expr::Ident(Ident { + sym: s.to_string().into(), + span: DUMMY_SP, + ctxt: SyntaxContext::empty(), + optional: false, + }))), + }) + } else { + JSXAttrValue::Lit(Lit::Str(Str { + span: DUMMY_SP, + value: s.to_string().into(), + raw: None, + })) + } +} + +#[cfg(test)] +mod tests { + use std::sync::Arc; + + use swc_core::common::{FileName, SourceMap}; + use swc_core::ecma::ast::*; + use swc_core::ecma::codegen::text_writer::JsWriter; + use swc_core::ecma::codegen::Emitter; + use swc_core::ecma::parser::lexer::Lexer; + use swc_core::ecma::parser::{EsSyntax, Parser, StringInput, Syntax}; + use swc_core::ecma::visit::{as_folder, FoldWith}; + + use super::*; + + fn code_test(input: &str, replace_attr_values: LinkedHashMap, expected: &str) { + let cm = Arc::::default(); + let fm = cm.new_source_file(FileName::Anon.into(), input.to_string()); + + let lexer = Lexer::new( + Syntax::Es(EsSyntax { + decorators: true, + jsx: true, + ..Default::default() + }), + EsVersion::EsNext, + StringInput::from(&*fm), + None, + ); + + let mut parser = Parser::new_from(lexer); + let module = parser.parse_module().unwrap(); + + let module = module.fold_with(&mut as_folder(Visitor::new(&core::config::Config { + replace_attr_values: Some(replace_attr_values), + ..Default::default() + }))); + + let mut buf = vec![]; + let mut emitter = Emitter { + cfg: Default::default(), + cm: cm.clone(), + comments: None, + wr: JsWriter::new(cm, "", &mut buf, None), + }; + emitter.emit_module(&module).unwrap(); + let result = String::from_utf8_lossy(&buf).to_string(); + + assert_eq!(result, expected); + } + + #[test] + fn should_replace_attribute_values_1() { + let mut replace_attr_values = LinkedHashMap::new(); + replace_attr_values.insert("cool".to_string(), "not cool".to_string()); + code_test( + r#"
;"#, + replace_attr_values, + r#"
;"#, + ); + } + + #[test] + fn should_replace_attribute_values_2() { + let mut replace_attr_values = LinkedHashMap::new(); + replace_attr_values.insert("cool".to_string(), "{props.color}".to_string()); + code_test( + r#"
;"#, + replace_attr_values, + r#"
;"#, + ); + } +} diff --git a/crates/svgr-rs/src/svg_dynamic_title.rs b/crates/svgr-rs/src/svg_dynamic_title.rs new file mode 100644 index 000000000..26bad4e5b --- /dev/null +++ b/crates/svgr-rs/src/svg_dynamic_title.rs @@ -0,0 +1,384 @@ +use swc_core::common::{SyntaxContext, DUMMY_SP}; +use swc_core::ecma::ast::*; +use swc_core::ecma::visit::VisitMut; + +const ELEMENTS: [&str; 2] = ["svg", "Svg"]; + +pub struct Visitor { + tag: String, + tag_id: String, +} + +impl Visitor { + pub fn new(tag: String) -> Self { + let tag_id = format!("{}Id", tag); + + Self { tag, tag_id } + } + + fn get_tag_expr(&self, value: JSXAttrValue) -> Expr { + let cons = Box::new(Expr::JSXElement(Box::new(JSXElement { + span: DUMMY_SP, + opening: JSXOpeningElement { + span: DUMMY_SP, + name: JSXElementName::Ident(Ident::new( + self.tag.clone().into(), + DUMMY_SP, + SyntaxContext::empty(), + )), + attrs: vec![JSXAttrOrSpread::JSXAttr(JSXAttr { + span: DUMMY_SP, + name: JSXAttrName::Ident(IdentName::new("id".to_string().into(), DUMMY_SP)), + value: Some(value), + })], + self_closing: false, + type_args: None, + }, + children: vec![JSXElementChild::JSXExprContainer(JSXExprContainer { + span: DUMMY_SP, + expr: JSXExpr::Expr(Box::new(Expr::Ident(Ident::new( + self.tag.clone().into(), + DUMMY_SP, + SyntaxContext::empty(), + )))), + })], + closing: Some(JSXClosingElement { + span: DUMMY_SP, + name: JSXElementName::Ident(Ident::new( + self.tag.clone().into(), + DUMMY_SP, + SyntaxContext::empty(), + )), + }), + }))); + + Expr::Cond(CondExpr { + span: DUMMY_SP, + test: Box::new(Expr::Ident(Ident::new( + self.tag.clone().into(), + DUMMY_SP, + SyntaxContext::empty(), + ))), + cons, + alt: Box::new(Expr::Lit(Lit::Null(Null { span: DUMMY_SP }))), + }) + } + + fn get_tag_element(&self) -> JSXElementChild { + let value = JSXAttrValue::JSXExprContainer(JSXExprContainer { + span: DUMMY_SP, + expr: JSXExpr::Expr(Box::new(Expr::Ident(Ident::new( + self.tag_id.clone().into(), + DUMMY_SP, + SyntaxContext::empty(), + )))), + }); + + let expr = self.get_tag_expr(value); + + JSXElementChild::JSXExprContainer(JSXExprContainer { + span: DUMMY_SP, + expr: JSXExpr::Expr(Box::new(expr)), + }) + } + + fn get_tag_element_with_existing_title( + &self, + existing_title: &mut JSXElement, + ) -> JSXElementChild { + let test = Expr::Bin(BinExpr { + span: DUMMY_SP, + left: Box::new(Expr::Ident(Ident::new( + self.tag.clone().into(), + DUMMY_SP, + SyntaxContext::empty(), + ))), + op: op!("==="), + right: Box::new(Expr::Ident(Ident::new( + "undefined".into(), + DUMMY_SP, + SyntaxContext::empty(), + ))), + }); + + let existing_id = existing_title.opening.attrs.iter_mut().find(|attr| { + if let JSXAttrOrSpread::JSXAttr(JSXAttr { + name: JSXAttrName::Ident(ident), + .. + }) = attr + { + if ident.sym == "id" { + return true; + } + } + false + }); + + let id_attr_value = if let Some(JSXAttrOrSpread::JSXAttr(attr)) = existing_id { + let jsx_attr_value = match &attr.value { + Some(JSXAttrValue::Lit(Lit::Str(Str { value, .. }))) => { + JSXAttrValue::JSXExprContainer(JSXExprContainer { + span: DUMMY_SP, + expr: JSXExpr::Expr(Box::new(Expr::Bin(BinExpr { + span: DUMMY_SP, + left: Box::new(Expr::Ident(Ident::new( + self.tag_id.clone().into(), + DUMMY_SP, + SyntaxContext::empty(), + ))), + op: op!("||"), + right: Box::new(Expr::Lit(Lit::Str(Str { + span: DUMMY_SP, + value: value.clone(), + raw: None, + }))), + }))), + }) + } + _ => JSXAttrValue::JSXExprContainer(JSXExprContainer { + span: DUMMY_SP, + expr: JSXExpr::Expr(Box::new(Expr::Ident(Ident::new( + self.tag_id.clone().into(), + DUMMY_SP, + SyntaxContext::empty(), + )))), + }), + }; + + attr.value = Some(jsx_attr_value.clone()); + + jsx_attr_value + } else { + let jsx_attr_value = JSXAttrValue::JSXExprContainer(JSXExprContainer { + span: DUMMY_SP, + expr: JSXExpr::Expr(Box::new(Expr::Ident(Ident::new( + self.tag_id.clone().into(), + DUMMY_SP, + SyntaxContext::empty(), + )))), + }); + + let id_attr = JSXAttrOrSpread::JSXAttr(JSXAttr { + span: DUMMY_SP, + name: JSXAttrName::Ident(IdentName::new("id".into(), DUMMY_SP)), + value: Some(jsx_attr_value.clone()), + }); + existing_title.opening.attrs.push(id_attr); + + jsx_attr_value + }; + + if existing_title.children.is_empty() { + return JSXElementChild::JSXExprContainer(JSXExprContainer { + span: DUMMY_SP, + expr: JSXExpr::Expr(Box::new(self.get_tag_expr(id_attr_value))), + }); + } + + JSXElementChild::JSXExprContainer(JSXExprContainer { + span: DUMMY_SP, + expr: JSXExpr::Expr(Box::new(Expr::Cond(CondExpr { + span: DUMMY_SP, + test: Box::new(test), + cons: Box::new(Expr::JSXElement(Box::new(existing_title.clone()))), + alt: Box::new(self.get_tag_expr(id_attr_value)), + }))), + }) + } +} + +impl VisitMut for Visitor { + fn visit_mut_jsx_element(&mut self, n: &mut JSXElement) { + if let JSXElementName::Ident(ident) = &n.opening.name { + let name = ident.sym.to_string(); + if !ELEMENTS.iter().any(|e| *e == name) { + return; + } + + let has_tag = n.children.clone().iter_mut().enumerate().any(|(i, c)| { + if let JSXElementChild::JSXElement(e) = c { + if let JSXElementName::Ident(ident) = &e.opening.name { + if ident.sym == self.tag { + let tag_element = self.get_tag_element_with_existing_title(e); + n.children[i] = tag_element; + return true; + } + } + } + false + }); + + if !has_tag { + n.children.insert(0, self.get_tag_element()); + } + } + } +} + +#[cfg(test)] +mod tests { + use std::sync::Arc; + + use swc_core::common::{FileName, SourceMap}; + use swc_core::ecma::ast::*; + use swc_core::ecma::codegen::text_writer::JsWriter; + use swc_core::ecma::codegen::Emitter; + use swc_core::ecma::parser::lexer::Lexer; + use swc_core::ecma::parser::{EsSyntax, Parser, StringInput, Syntax}; + use swc_core::ecma::visit::{as_folder, FoldWith}; + + use super::*; + + fn code_test(input: &str, tag: String, expected: &str) { + let cm = Arc::::default(); + let fm = cm.new_source_file(FileName::Anon.into(), input.to_string()); + + let lexer = Lexer::new( + Syntax::Es(EsSyntax { + decorators: true, + jsx: true, + ..Default::default() + }), + EsVersion::EsNext, + StringInput::from(&*fm), + None, + ); + + let mut parser = Parser::new_from(lexer); + let module = parser.parse_module().unwrap(); + + let module = module.fold_with(&mut as_folder(Visitor::new(tag))); + + let mut buf = vec![]; + let mut emitter = Emitter { + cfg: Default::default(), + cm: cm.clone(), + comments: None, + wr: JsWriter::new(cm, "", &mut buf, None), + }; + emitter.emit_module(&module).unwrap(); + let result = String::from_utf8_lossy(&buf).to_string(); + + assert_eq!(result, expected); + } + + #[test] + fn title_plugin_should_add_title_attribute_if_not_present() { + code_test( + r#";"#, + "title".to_string(), + r#"{title ? {title} : null};"#, + ); + } + + #[test] + fn title_plugin_should_add_title_element_and_fallback_to_existing_title() { + code_test( + r#"Hello;"#, + "title".to_string(), + r#"{title === undefined ? Hello : title ? {title} : null};"#, + ); + + code_test( + r#"{"Hello"};"#, + "title".to_string(), + r#"{title === undefined ? {"Hello"} : title ? {title} : null};"#, + ); + } + + #[test] + fn title_plugin_should_preserve_any_existing_title_attributes() { + code_test( + r#"Hello;"#, + "title".to_string(), + r#"{title === undefined ? Hello : title ? {title} : null};"#, + ); + } + + #[test] + fn title_plugin_should_support_empty_title() { + code_test( + r#";"#, + "title".to_string(), + r#"{title ? {title} : null};"#, + ); + } + + #[test] + fn title_plugin_should_support_self_closing_title() { + code_test( + r#";"#, + "title".to_string(), + r#"{title ? {title} : null};"#, + ); + } + + #[test] + fn title_plugin_should_work_if_an_attribute_is_already_present() { + code_test( + r#";"#, + "title".to_string(), + r#"{title ? {title} : null};"#, + ); + } + + #[test] + fn desc_plugin_should_add_desc_attribute_if_not_present() { + code_test( + r#";"#, + "desc".to_string(), + r#"{desc ? {desc} : null};"#, + ); + } + + #[test] + fn desc_plugin_should_add_desc_element_and_fallback_to_existing_desc() { + code_test( + r#"Hello;"#, + "desc".to_string(), + r#"{desc === undefined ? Hello : desc ? {desc} : null};"#, + ); + + code_test( + r#"{"Hello"};"#, + "desc".to_string(), + r#"{desc === undefined ? {"Hello"} : desc ? {desc} : null};"#, + ); + } + + #[test] + fn desc_plugin_should_preserve_any_existing_desc_attributes() { + code_test( + r#"Hello;"#, + "desc".to_string(), + r#"{desc === undefined ? Hello : desc ? {desc} : null};"#, + ); + } + + #[test] + fn desc_plugin_should_support_empty_desc() { + code_test( + r#";"#, + "desc".to_string(), + r#"{desc ? {desc} : null};"#, + ); + } + + #[test] + fn desc_plugin_should_support_self_closing_desc() { + code_test( + r#";"#, + "desc".to_string(), + r#"{desc ? {desc} : null};"#, + ); + } + + #[test] + fn desc_plugin_should_work_if_an_attribute_is_already_present() { + code_test( + r#";"#, + "desc".to_string(), + r#"{desc ? {desc} : null};"#, + ); + } +} diff --git a/crates/svgr-rs/src/svg_em_dimensions.rs b/crates/svgr-rs/src/svg_em_dimensions.rs new file mode 100644 index 000000000..e99283b9b --- /dev/null +++ b/crates/svgr-rs/src/svg_em_dimensions.rs @@ -0,0 +1,235 @@ +use swc_core::common::DUMMY_SP; +use swc_core::ecma::ast::*; +use swc_core::ecma::visit::VisitMut; + +use super::core; + +const ELEMENTS: [&str; 2] = ["svg", "Svg"]; + +enum Size { + Str(String), + Num(f64), +} + +pub struct Visitor { + height: Option, + width: Option, +} + +impl Visitor { + pub fn new(config: &core::config::Config) -> Self { + let height: Option; + let width: Option; + + let icon = config + .icon + .clone() + .unwrap_or(core::config::Icon::Bool(false)); + match icon { + core::config::Icon::Str(s) => { + height = Some(Size::Str(s.clone())); + width = Some(Size::Str(s)); + } + core::config::Icon::Num(n) => { + height = Some(Size::Num(n)); + width = Some(Size::Num(n)); + } + core::config::Icon::Bool(_) => { + let native = config.native.unwrap_or(false); + if native { + height = Some(Size::Num(24.0)); + width = Some(Size::Num(24.0)); + } else { + height = None; + width = None; + } + } + } + + Self { height, width } + } +} + +impl VisitMut for Visitor { + fn visit_mut_jsx_opening_element(&mut self, n: &mut JSXOpeningElement) { + let is_svg = ELEMENTS.iter().any(|element| { + if let JSXElementName::Ident(ident) = n.name.clone() { + return ident.sym == *element; + } + false + }); + + if !is_svg { + return; + } + + let mut required_attrs = vec!["width", "height"]; + + n.attrs.iter_mut().for_each(|attr| { + if let JSXAttrOrSpread::JSXAttr(jsx_attr) = attr { + if let JSXAttrName::Ident(ident) = &jsx_attr.name { + required_attrs + .clone() + .iter() + .enumerate() + .for_each(|(index, attr)| { + if ident.sym == *attr { + match *attr { + "height" => { + jsx_attr.value.replace(get_value(self.height.as_ref())); + } + "width" => { + jsx_attr.value.replace(get_value(self.width.as_ref())); + } + _ => {} + } + required_attrs.remove(index); + } + }); + } + } + }); + + required_attrs.iter().for_each(|attr| { + n.attrs.push(JSXAttrOrSpread::JSXAttr(JSXAttr { + span: DUMMY_SP, + name: JSXAttrName::Ident(IdentName::new((*attr).into(), DUMMY_SP)), + value: Some(get_value(match *attr { + "height" => self.height.as_ref(), + "width" => self.width.as_ref(), + _ => None, + })), + })); + }); + } +} + +fn get_value(raw: Option<&Size>) -> JSXAttrValue { + match raw { + None => JSXAttrValue::Lit(Lit::Str(Str { + span: DUMMY_SP, + value: "1em".into(), + raw: None, + })), + Some(str_or_num) => match str_or_num { + Size::Str(str) => JSXAttrValue::Lit(Lit::Str(Str { + span: DUMMY_SP, + value: str.clone().into(), + raw: None, + })), + Size::Num(num) => JSXAttrValue::JSXExprContainer(JSXExprContainer { + expr: JSXExpr::Expr(Box::new(Expr::Lit(Lit::Num(Number { + span: DUMMY_SP, + value: *num, + raw: None, + })))), + span: DUMMY_SP, + }), + }, + } +} + +#[cfg(test)] +mod tests { + use std::default::Default; + use std::sync::Arc; + + use swc_core::common::{FileName, SourceMap}; + use swc_core::ecma::ast::*; + use swc_core::ecma::codegen::text_writer::JsWriter; + use swc_core::ecma::codegen::Emitter; + use swc_core::ecma::parser::lexer::Lexer; + use swc_core::ecma::parser::{EsSyntax, Parser, StringInput, Syntax}; + use swc_core::ecma::visit::{as_folder, FoldWith}; + + use super::*; + + struct Options { + height: Option, + width: Option, + } + + fn code_test(input: &str, opts: Options, expected: &str) { + let cm = Arc::new(SourceMap::default()); + let fm = cm.new_source_file(FileName::Anon.into(), input.to_string()); + + let lexer = Lexer::new( + Syntax::Es(EsSyntax { + decorators: true, + jsx: true, + ..Default::default() + }), + EsVersion::EsNext, + StringInput::from(&*fm), + None, + ); + + let mut parser = Parser::new_from(lexer); + let module = parser.parse_module().unwrap(); + + let module = module.fold_with(&mut as_folder(Visitor { + height: opts.height, + width: opts.width, + })); + + let mut buf = vec![]; + let mut emitter = Emitter { + cfg: Default::default(), + cm: cm.clone(), + comments: None, + wr: JsWriter::new(cm, "", &mut buf, None), + }; + emitter.emit_module(&module).unwrap(); + let result = String::from_utf8_lossy(&buf).to_string(); + + assert_eq!(result, expected); + } + + #[test] + fn replaces_width_or_height_attributes() { + code_test( + r#";"#, + Options { + height: None, + width: None, + }, + r#";"#, + ); + } + + #[test] + fn adds_em_if_they_are_not_present() { + code_test( + r#";"#, + Options { + height: None, + width: None, + }, + r#";"#, + ); + } + + #[test] + fn accepts_numeric_values() { + code_test( + r#";"#, + Options { + height: Some(Size::Num(24.0)), + width: Some(Size::Num(24.0)), + }, + r#";"#, + ); + } + + #[test] + fn accepts_string_values() { + code_test( + r#";"#, + Options { + height: Some(Size::Str("2em".to_string())), + width: Some(Size::Str("2em".to_string())), + }, + r#";"#, + ); + } +} diff --git a/crates/svgr-rs/src/transform_react_native_svg.rs b/crates/svgr-rs/src/transform_react_native_svg.rs new file mode 100644 index 000000000..64c8a1a95 --- /dev/null +++ b/crates/svgr-rs/src/transform_react_native_svg.rs @@ -0,0 +1,305 @@ +use std::cell::RefCell; +use std::collections::HashMap; +use std::rc::Rc; + +use linked_hash_set::LinkedHashSet; +use swc_core::common::comments::{Comment, CommentKind, Comments}; +use swc_core::common::{Span, SyntaxContext, DUMMY_SP}; +use swc_core::ecma::ast::*; +use swc_core::ecma::atoms::JsWord; +use swc_core::ecma::visit::{VisitMut, VisitMutWith}; + +pub struct Visitor<'a> { + replaced_components: Rc>>, + unsupported_components: Rc>>, + comments: &'a dyn Comments, +} + +impl<'a> Visitor<'a> { + pub fn new(comments: &'a dyn Comments) -> Self { + Visitor { + replaced_components: Rc::new(RefCell::new(LinkedHashSet::new())), + unsupported_components: Rc::new(RefCell::new(LinkedHashSet::new())), + comments, + } + } +} + +impl VisitMut for Visitor<'_> { + fn visit_mut_module(&mut self, n: &mut Module) { + let mut svg_element_visitor = SvgElementVisitor::new( + self.replaced_components.clone(), + self.unsupported_components.clone(), + ); + n.visit_mut_with(&mut svg_element_visitor); + + let mut import_decl_visitor = ImportDeclVisitor::new(self.replaced_components.clone()); + n.visit_mut_with(&mut import_decl_visitor); + + if let Some(span) = import_decl_visitor.import_decl_span { + let component_list = self + .unsupported_components + .borrow() + .clone() + .into_iter() + .collect::>() + .join(", "); + self.comments.add_trailing_comments( + span.hi, + vec![Comment { + kind: CommentKind::Block, + span: DUMMY_SP, + text: format!( + " SVGR has dropped some elements not supported by react-native-svg: {} ", + component_list + ) + .into(), + }], + ); + } + } +} + +struct SvgElementVisitor { + replaced_components: Rc>>, + unsupported_components: Rc>>, +} + +impl SvgElementVisitor { + fn new( + replaced_components: Rc>>, + unsupported_components: Rc>>, + ) -> Self { + SvgElementVisitor { + replaced_components, + unsupported_components, + } + } +} + +impl VisitMut for SvgElementVisitor { + fn visit_mut_jsx_element(&mut self, n: &mut JSXElement) { + if let JSXElementName::Ident(ident) = &mut n.opening.name { + if ident.sym == "svg" { + let mut jsx_element_visitor = JSXElementVisitor::new( + self.replaced_components.clone(), + self.unsupported_components.clone(), + ); + ident.sym = "Svg".into(); + if let Some(closing) = &mut n.closing { + if let JSXElementName::Ident(ident) = &mut closing.name { + ident.sym = "Svg".into(); + } + } + n.visit_mut_with(&mut jsx_element_visitor); + } + } + } +} + +struct JSXElementVisitor { + element_to_component: HashMap<&'static str, &'static str>, + + replaced_components: Rc>>, + unsupported_components: Rc>>, +} + +impl JSXElementVisitor { + fn new( + replaced_components: Rc>>, + unsupported_components: Rc>>, + ) -> Self { + JSXElementVisitor { + element_to_component: get_element_to_component(), + replaced_components, + unsupported_components, + } + } + + fn replace_element(&self, n: &mut JSXElement) -> bool { + if let JSXElementName::Ident(ident) = &mut n.opening.name { + let element = ident.sym.to_string(); + if let Some(component) = self.element_to_component.get(&element.as_str()) { + self.replaced_components + .borrow_mut() + .insert(component.to_string()); + ident.sym = JsWord::from(*component); + if let Some(closing) = &mut n.closing { + if let JSXElementName::Ident(ident) = &mut closing.name { + ident.sym = JsWord::from(*component); + } + } + } else { + // Remove element if not supported + self.unsupported_components.borrow_mut().insert(element); + return true; + } + } + false + } +} + +impl VisitMut for JSXElementVisitor { + fn visit_mut_jsx_element(&mut self, n: &mut JSXElement) { + n.visit_mut_children_with(self); + + let mut i = n.children.len(); + while i > 0 { + i -= 1; + if let JSXElementChild::JSXElement(jsx_element) = &mut n.children[i] { + let unsupported = self.replace_element(jsx_element); + if unsupported { + n.children.remove(i); + } + } + } + } +} + +fn get_element_to_component() -> HashMap<&'static str, &'static str> { + HashMap::from([ + ("svg", "Svg"), + ("circle", "Circle"), + ("clipPath", "ClipPath"), + ("ellipse", "Ellipse"), + ("g", "G"), + ("linearGradient", "LinearGradient"), + ("radialGradient", "RadialGradient"), + ("line", "Line"), + ("path", "Path"), + ("pattern", "Pattern"), + ("polygon", "Polygon"), + ("polyline", "Polyline"), + ("rect", "Rect"), + ("symbol", "Symbol"), + ("text", "Text"), + ("textPath", "TextPath"), + ("tspan", "TSpan"), + ("use", "Use"), + ("defs", "Defs"), + ("stop", "Stop"), + ("mask", "Mask"), + ("image", "Image"), + ("foreignObject", "ForeignObject"), + ]) +} + +struct ImportDeclVisitor { + replaced_components: Rc>>, + import_decl_span: Option, +} + +impl ImportDeclVisitor { + fn new(replaced_components: Rc>>) -> Self { + ImportDeclVisitor { + replaced_components, + import_decl_span: None, + } + } +} + +impl VisitMut for ImportDeclVisitor { + fn visit_mut_import_decl(&mut self, n: &mut ImportDecl) { + if n.src.value == "react-native-svg" { + for component in self.replaced_components.borrow().iter() { + if n.specifiers.iter().any(|specifier| { + if let ImportSpecifier::Named(named) = specifier { + if named.local.sym == *component { + return true; + } + } + false + }) { + break; + } + + n.specifiers + .push(ImportSpecifier::Named(ImportNamedSpecifier { + local: Ident::new( + JsWord::from(component.as_str()), + DUMMY_SP, + SyntaxContext::empty(), + ), + imported: None, + span: DUMMY_SP, + is_type_only: false, + })); + } + + self.import_decl_span = Some(n.span); + } else if n.src.value == "expo" { + n.specifiers + .push(ImportSpecifier::Named(ImportNamedSpecifier { + local: Ident::new("Svg".into(), DUMMY_SP, SyntaxContext::empty()), + imported: None, + span: DUMMY_SP, + is_type_only: false, + })); + + self.import_decl_span = Some(n.span); + } + } +} + +#[cfg(test)] +mod tests { + use std::sync::Arc; + + use swc_core::common::comments::SingleThreadedComments; + use swc_core::common::{FileName, SourceMap}; + use swc_core::ecma::ast::*; + use swc_core::ecma::codegen::text_writer::JsWriter; + use swc_core::ecma::codegen::Emitter; + use swc_core::ecma::parser::lexer::Lexer; + use swc_core::ecma::parser::{EsSyntax, Parser, StringInput, Syntax}; + use swc_core::ecma::visit::{as_folder, FoldWith}; + + use super::*; + + fn code_test(input: &str, expected: &str) { + let cm = Arc::::default(); + let fm = cm.new_source_file(FileName::Anon.into(), input.to_string()); + + let lexer = Lexer::new( + Syntax::Es(EsSyntax { + decorators: true, + jsx: true, + ..Default::default() + }), + EsVersion::EsNext, + StringInput::from(&*fm), + None, + ); + + let mut parser = Parser::new_from(lexer); + let module = parser.parse_module().unwrap(); + + let comments = SingleThreadedComments::default(); + let module = module.fold_with(&mut as_folder(Visitor::new(&comments))); + + let mut buf = vec![]; + let mut emitter = Emitter { + cfg: Default::default(), + cm: cm.clone(), + comments: Some(&comments), + wr: JsWriter::new(cm, "", &mut buf, None), + }; + emitter.emit_module(&module).unwrap(); + let result = String::from_utf8_lossy(&buf).to_string(); + + assert_eq!(result, expected); + } + + #[test] + fn should_transform_elements() { + code_test(r#"
;"#, r#";"#); + } + + #[test] + fn should_add_import() { + code_test( + r#"import Svg from 'react-native-svg';
;"#, + r#"import Svg, { G } from 'react-native-svg'; /* SVGR has dropped some elements not supported by react-native-svg: div */ ;"#, + ); + } +} diff --git a/crates/svgr-rs/src/transform_svg_component/mod.rs b/crates/svgr-rs/src/transform_svg_component/mod.rs new file mode 100644 index 000000000..0a3783d6a --- /dev/null +++ b/crates/svgr-rs/src/transform_svg_component/mod.rs @@ -0,0 +1,856 @@ +use swc_core::common::{SyntaxContext, DUMMY_SP}; +use swc_core::ecma::ast::*; + +use crate::{core, SvgrError}; + +mod variables; + +fn get_variables_options(config: &core::config::Config) -> variables::Options { + let expand_props = match config.expand_props { + core::config::ExpandProps::Bool(b) => Some(variables::ExpandProps::Bool(b)), + core::config::ExpandProps::Start => Some(variables::ExpandProps::Start), + core::config::ExpandProps::End => Some(variables::ExpandProps::End), + }; + + let export_type = match config.export_type { + Some(core::config::ExportType::Named) => variables::ExportType::Named, + _ => variables::ExportType::Default, + }; + + let mut opts = variables::Options { + typescript: config.typescript.unwrap_or(false), + title_prop: config.title_prop.unwrap_or(false), + desc_prop: config.desc_prop.unwrap_or(false), + expand_props, + _ref: config._ref.unwrap_or(false), + native: config.native.unwrap_or(false), + memo: config.memo.unwrap_or(false), + named_export: Some(config.named_export.clone()), + export_type, + ..Default::default() + }; + + if let Some(jsx_runtime_import) = &config.jsx_runtime_import { + opts.import_source = Some(jsx_runtime_import.source.clone()); + opts.jsx_runtime_import = Some(jsx_runtime_import.clone()); + return opts; + } + + let jsx_runtime = config + .jsx_runtime + .clone() + .unwrap_or(core::config::JSXRuntime::Classic); + + match jsx_runtime { + core::config::JSXRuntime::Classic => { + opts.jsx_runtime = variables::JSXRuntime::Classic; + opts.import_source = Some("react".to_string()); + opts.jsx_runtime_import = Some(core::config::JSXRuntimeImport { + source: "react".to_string(), + namespace: Some("React".to_string()), + ..Default::default() + }); + } + core::config::JSXRuntime::ClassicPreact => { + opts.jsx_runtime = variables::JSXRuntime::Classic; + opts.import_source = Some("preact".to_string()); + opts.jsx_runtime_import = Some(core::config::JSXRuntimeImport { + source: "preact".to_string(), + specifiers: Some(vec!["h".to_string()]), + ..Default::default() + }); + } + core::config::JSXRuntime::Automatic => { + opts.jsx_runtime = variables::JSXRuntime::Automatic; + } + } + + opts +} + +pub fn transform( + jsx_element: JSXElement, + config: &core::config::Config, + state: &core::state::InternalConfig, +) -> Result { + let variables_options = get_variables_options(config); + + let variables = variables::get_variables(variables_options, state, jsx_element)?; + + let mut body = vec![]; + + for import in variables.imports { + body.push(import); + } + + for interface in variables.interfaces { + body.push(interface); + } + + body.push(ModuleItem::Stmt(Stmt::Decl(Decl::Var(Box::new(VarDecl { + span: DUMMY_SP, + ctxt: SyntaxContext::empty(), + kind: VarDeclKind::Const, + declare: false, + decls: vec![VarDeclarator { + span: DUMMY_SP, + name: Pat::Ident(BindingIdent::from(Ident::new( + state.component_name.clone().into(), + DUMMY_SP, + SyntaxContext::empty(), + ))), + definite: false, + init: Some(Box::new(Expr::Arrow(ArrowExpr { + span: DUMMY_SP, + ctxt: SyntaxContext::empty(), + params: variables.props, + body: Box::new(BlockStmtOrExpr::Expr(Box::new(Expr::JSXElement(Box::new( + variables.jsx, + ))))), + is_async: false, + is_generator: false, + type_params: None, + return_type: None, + }))), + }], + }))))); + + for export in variables.exports { + body.push(export); + } + + Ok(Module { + span: DUMMY_SP, + body, + shebang: None, + }) +} + +#[cfg(test)] +mod tests { + use std::borrow::Borrow; + use std::sync::Arc; + + use swc_core::common::{FileName, SourceMap}; + use swc_core::ecma::codegen::text_writer::JsWriter; + use swc_core::ecma::codegen::Emitter; + use swc_core::ecma::parser; + + use super::*; + use crate::core; + + fn test_code( + input: &str, + config: &core::config::Config, + state: &core::state::InternalConfig, + expected: &str, + ) { + let cm = Arc::::default(); + let fm = cm.new_source_file(FileName::Anon.into(), input.to_string()); + + let mut recovered_errors = vec![]; + let expr = parser::parse_file_as_expr( + fm.borrow(), + parser::Syntax::Es(parser::EsSyntax { + jsx: true, + ..Default::default() + }), + EsVersion::Es2020, + None, + &mut recovered_errors, + ) + .unwrap(); + + let jsx_element = expr.as_jsx_element().unwrap(); + + let m = transform(*jsx_element.clone(), config, state).unwrap(); + + let mut buf = vec![]; + let mut emitter = Emitter { + cfg: Default::default(), + cm: cm.clone(), + comments: None, + wr: JsWriter::new(cm, "\n", &mut buf, None), + }; + emitter.emit_module(&m).unwrap(); + let result = String::from_utf8_lossy(&buf).to_string(); + + assert_eq!(result, expected); + } + + fn test_js_n_ts( + input: &str, + config: &core::config::Config, + state: &core::state::InternalConfig, + js: &str, + ts: &str, + ) { + test_code(input, config, state, js); + + let mut config = config.clone(); + config.typescript = Some(true); + test_code(input, &config, state, ts); + } + + #[test] + fn transforms_whole_program() { + test_js_n_ts( + r#""#, + &core::config::Config { + expand_props: core::config::ExpandProps::Bool(false), + ..Default::default() + }, + &core::state::InternalConfig { + ..Default::default() + }, + r#"import * as React from "react"; +const SvgComponent = ()=>; +export default SvgComponent; +"#, + r#"import * as React from "react"; +const SvgComponent = ()=>; +export default SvgComponent; +"#, + ); + } + + #[test] + fn with_native_option_adds_import_from_react_native_svg() { + test_js_n_ts( + r#""#, + &core::config::Config { + native: Some(true), + expand_props: core::config::ExpandProps::Bool(false), + ..Default::default() + }, + &core::state::InternalConfig { + ..Default::default() + }, + r#"import * as React from "react"; +import Svg from "react-native-svg"; +const SvgComponent = ()=>; +export default SvgComponent; +"#, + r#"import * as React from "react"; +import Svg from "react-native-svg"; +const SvgComponent = ()=>; +export default SvgComponent; +"#, + ); + } + + #[test] + fn with_ref_option_adds_forward_ref_component() { + test_js_n_ts( + r#""#, + &core::config::Config { + _ref: Some(true), + expand_props: core::config::ExpandProps::Bool(false), + ..Default::default() + }, + &core::state::InternalConfig { + component_name: "SvgComponent".to_string(), + ..Default::default() + }, + r#"import * as React from "react"; +import { forwardRef } from "react"; +const SvgComponent = (_, ref)=>; +const ForwardRef = forwardRef(SvgComponent); +export default ForwardRef; +"#, + r#"import * as React from "react"; +import { Ref, forwardRef } from "react"; +const SvgComponent = (_, ref: Ref)=>; +const ForwardRef = forwardRef(SvgComponent); +export default ForwardRef; +"#, + ); + } + + #[test] + fn with_title_prop_adds_title_and_title_id_prop() { + test_js_n_ts( + r#""#, + &core::config::Config { + title_prop: Some(true), + expand_props: core::config::ExpandProps::Bool(false), + ..Default::default() + }, + &core::state::InternalConfig { + ..Default::default() + }, + r#"import * as React from "react"; +const SvgComponent = ({ title, titleId })=>; +export default SvgComponent; +"#, + r#"import * as React from "react"; +interface SVGRProps { + title?: string; + titleId?: string; +} +const SvgComponent = ({ title, titleId }: SVGRProps)=>; +export default SvgComponent; +"#, + ); + } + + #[test] + fn with_title_prop_and_expand_props_adds_title_title_id_props_and_expands_props() { + test_js_n_ts( + r#""#, + &core::config::Config { + title_prop: Some(true), + expand_props: core::config::ExpandProps::Bool(true), + ..Default::default() + }, + &core::state::InternalConfig { + ..Default::default() + }, + r#"import * as React from "react"; +const SvgComponent = ({ title, titleId, ...props })=>; +export default SvgComponent; +"#, + r#"import * as React from "react"; +import { SVGProps } from "react"; +interface SVGRProps { + title?: string; + titleId?: string; +} +const SvgComponent = ({ title, titleId, ...props }: SVGProps & SVGRProps)=>; +export default SvgComponent; +"#, + ); + } + + #[test] + fn with_desc_prop_adds_desc_and_desc_id_prop() { + test_js_n_ts( + r#""#, + &core::config::Config { + desc_prop: Some(true), + expand_props: core::config::ExpandProps::Bool(false), + ..Default::default() + }, + &core::state::InternalConfig { + ..Default::default() + }, + r#"import * as React from "react"; +const SvgComponent = ({ desc, descId })=>; +export default SvgComponent; +"#, + r#"import * as React from "react"; +interface SVGRProps { + desc?: string; + descId?: string; +} +const SvgComponent = ({ desc, descId }: SVGRProps)=>; +export default SvgComponent; +"#, + ); + } + + #[test] + fn with_desc_prop_and_expand_props_adds_desc_desc_id_props_and_expands_prop() { + test_js_n_ts( + r#""#, + &core::config::Config { + expand_props: core::config::ExpandProps::Bool(true), + desc_prop: Some(true), + ..Default::default() + }, + &core::state::InternalConfig { + ..Default::default() + }, + r#"import * as React from "react"; +const SvgComponent = ({ desc, descId, ...props })=>; +export default SvgComponent; +"#, + r#"import * as React from "react"; +import { SVGProps } from "react"; +interface SVGRProps { + desc?: string; + descId?: string; +} +const SvgComponent = ({ desc, descId, ...props }: SVGProps & SVGRProps)=>; +export default SvgComponent; +"#, + ); + } + + #[test] + fn with_title_prop_and_desc_prop_adds_title_title_id_desc_and_desc_id_prop() { + test_js_n_ts( + r#""#, + &core::config::Config { + title_prop: Some(true), + desc_prop: Some(true), + expand_props: core::config::ExpandProps::Bool(false), + ..Default::default() + }, + &core::state::InternalConfig { + ..Default::default() + }, + r#"import * as React from "react"; +const SvgComponent = ({ title, titleId, desc, descId })=>; +export default SvgComponent; +"#, + r#"import * as React from "react"; +interface SVGRProps { + title?: string; + titleId?: string; + desc?: string; + descId?: string; +} +const SvgComponent = ({ title, titleId, desc, descId }: SVGRProps)=>; +export default SvgComponent; +"#, + ); + } + + #[test] + fn with_title_prop_desc_prop_and_expand_props_adds_title_title_id_desc_desc_id_props_and_expands_props( + ) { + test_js_n_ts( + r#""#, + &core::config::Config { + expand_props: core::config::ExpandProps::Bool(true), + title_prop: Some(true), + desc_prop: Some(true), + ..Default::default() + }, + &core::state::InternalConfig { + ..Default::default() + }, + r#"import * as React from "react"; +const SvgComponent = ({ title, titleId, desc, descId, ...props })=>; +export default SvgComponent; +"#, + r#"import * as React from "react"; +import { SVGProps } from "react"; +interface SVGRProps { + title?: string; + titleId?: string; + desc?: string; + descId?: string; +} +const SvgComponent = ({ title, titleId, desc, descId, ...props }: SVGProps & SVGRProps)=>; +export default SvgComponent; +"#, + ); + } + + #[test] + fn with_expand_props_add_props() { + test_js_n_ts( + r#""#, + &core::config::Config { + expand_props: core::config::ExpandProps::Bool(true), + ..Default::default() + }, + &core::state::InternalConfig { + component_name: "SvgComponent".to_string(), + ..Default::default() + }, + r#"import * as React from "react"; +const SvgComponent = (props)=>; +export default SvgComponent; +"#, + r#"import * as React from "react"; +import { SVGProps } from "react"; +const SvgComponent = (props: SVGProps)=>; +export default SvgComponent; +"#, + ); + } + + #[test] + fn with_ref_and_expand_props_option_expands_props() { + test_js_n_ts( + r#""#, + &core::config::Config { + expand_props: core::config::ExpandProps::Bool(true), + _ref: Some(true), + ..Default::default() + }, + &core::state::InternalConfig { + component_name: "SvgComponent".to_string(), + ..Default::default() + }, + r#"import * as React from "react"; +import { forwardRef } from "react"; +const SvgComponent = (props, ref)=>; +const ForwardRef = forwardRef(SvgComponent); +export default ForwardRef; +"#, + r#"import * as React from "react"; +import { SVGProps, Ref, forwardRef } from "react"; +const SvgComponent = (props: SVGProps, ref: Ref)=>; +const ForwardRef = forwardRef(SvgComponent); +export default ForwardRef; +"#, + ); + } + + #[test] + fn with_native_ref_option_adds_import_from_react_native_svg_and_adds_forward_ref_component() { + test_js_n_ts( + r#""#, + &core::config::Config { + native: Some(true), + _ref: Some(true), + expand_props: core::config::ExpandProps::Bool(false), + ..Default::default() + }, + &core::state::InternalConfig { + component_name: "SvgComponent".to_string(), + ..Default::default() + }, + r#"import * as React from "react"; +import Svg from "react-native-svg"; +import { forwardRef } from "react"; +const SvgComponent = (_, ref)=>; +const ForwardRef = forwardRef(SvgComponent); +export default ForwardRef; +"#, + r#"import * as React from "react"; +import Svg from "react-native-svg"; +import { Ref, forwardRef } from "react"; +const SvgComponent = (_, ref: Ref)=>; +const ForwardRef = forwardRef(SvgComponent); +export default ForwardRef; +"#, + ); + } + + #[test] + fn with_native_and_expand_props_option() { + test_js_n_ts( + r#""#, + &core::config::Config { + native: Some(true), + expand_props: core::config::ExpandProps::Bool(true), + ..Default::default() + }, + &core::state::InternalConfig { + component_name: "SvgComponent".to_string(), + ..Default::default() + }, + r#"import * as React from "react"; +import Svg from "react-native-svg"; +const SvgComponent = (props)=>; +export default SvgComponent; +"#, + r#"import * as React from "react"; +import Svg, { SvgProps } from "react-native-svg"; +const SvgComponent = (props: SvgProps)=>; +export default SvgComponent; +"#, + ); + } + + #[test] + fn with_native_ref_and_expand_props_option_adds_import_from_react_native_svg_and_adds_props_and_adds_forward_ref_component( + ) { + test_js_n_ts( + r#""#, + &core::config::Config { + native: Some(true), + expand_props: core::config::ExpandProps::Bool(true), + _ref: Some(true), + ..Default::default() + }, + &core::state::InternalConfig { + component_name: "SvgComponent".to_string(), + ..Default::default() + }, + r#"import * as React from "react"; +import Svg from "react-native-svg"; +import { forwardRef } from "react"; +const SvgComponent = (props, ref)=>; +const ForwardRef = forwardRef(SvgComponent); +export default ForwardRef; +"#, + r#"import * as React from "react"; +import Svg, { SvgProps } from "react-native-svg"; +import { Ref, forwardRef } from "react"; +const SvgComponent = (props: SvgProps, ref: Ref)=>; +const ForwardRef = forwardRef(SvgComponent); +export default ForwardRef; +"#, + ); + } + + #[test] + fn with_memo_option_wrap_component_in_react_memo() { + test_js_n_ts( + r#""#, + &core::config::Config { + memo: Some(true), + expand_props: core::config::ExpandProps::Bool(false), + ..Default::default() + }, + &core::state::InternalConfig { + component_name: "SvgComponent".to_string(), + ..Default::default() + }, + r#"import * as React from "react"; +import { memo } from "react"; +const SvgComponent = ()=>; +const Memo = memo(SvgComponent); +export default Memo; +"#, + r#"import * as React from "react"; +import { memo } from "react"; +const SvgComponent = ()=>; +const Memo = memo(SvgComponent); +export default Memo; +"#, + ); + } + + #[test] + fn with_both_memo_and_ref_option_wrap_component_in_react_memo_and_react_forward_ref() { + test_js_n_ts( + r#""#, + &core::config::Config { + memo: Some(true), + _ref: Some(true), + expand_props: core::config::ExpandProps::Bool(false), + ..Default::default() + }, + &core::state::InternalConfig { + component_name: "SvgComponent".to_string(), + ..Default::default() + }, + r#"import * as React from "react"; +import { forwardRef, memo } from "react"; +const SvgComponent = (_, ref)=>; +const ForwardRef = forwardRef(SvgComponent); +const Memo = memo(ForwardRef); +export default Memo; +"#, + r#"import * as React from "react"; +import { Ref, forwardRef, memo } from "react"; +const SvgComponent = (_, ref: Ref)=>; +const ForwardRef = forwardRef(SvgComponent); +const Memo = memo(ForwardRef); +export default Memo; +"#, + ); + } + + #[test] + fn with_named_export_option_and_previous_export_state_has_custom_named_export() { + test_js_n_ts( + r#""#, + &core::config::Config { + named_export: "Component".to_string(), + expand_props: core::config::ExpandProps::Bool(false), + ..Default::default() + }, + &core::state::InternalConfig { + component_name: "SvgComponent".to_string(), + caller: Some(core::state::Caller { + previous_export: Some( + "var img = new Image(); img.src = '...'; export default img;".to_string(), + ), + ..Default::default() + }), + ..Default::default() + }, + r#"import * as React from "react"; +const SvgComponent = ()=>; +export { SvgComponent as Component }; +var img = new Image(); +img.src = '...'; +export default img; +"#, + r#"import * as React from "react"; +const SvgComponent = ()=>; +export { SvgComponent as Component }; +var img = new Image(); +img.src = '...'; +export default img; +"#, + ); + } + + #[test] + fn with_named_export_and_export_type_option_and_without_previous_export_state_exports_via_named_export( + ) { + test_js_n_ts( + r#""#, + &core::config::Config { + named_export: "ReactComponent".to_string(), + export_type: Some(core::config::ExportType::Named), + expand_props: core::config::ExpandProps::Bool(false), + ..Default::default() + }, + &core::state::InternalConfig { + component_name: "SvgComponent".to_string(), + ..Default::default() + }, + r#"import * as React from "react"; +const SvgComponent = ()=>; +export { SvgComponent as ReactComponent }; +"#, + r#"import * as React from "react"; +const SvgComponent = ()=>; +export { SvgComponent as ReactComponent }; +"#, + ); + } + + // TODO: custom templates + + #[test] + fn jsx_runtime_supports_automatic_jsx_runtime() { + test_js_n_ts( + r#""#, + &core::config::Config { + jsx_runtime: Some(core::config::JSXRuntime::Automatic), + expand_props: core::config::ExpandProps::Bool(false), + ..Default::default() + }, + &core::state::InternalConfig { + ..Default::default() + }, + r#"const SvgComponent = ()=>; +export default SvgComponent; +"#, + r#"const SvgComponent = ()=>; +export default SvgComponent; +"#, + ); + } + + #[test] + fn jsx_runtime_supports_classic_jsx_runtime() { + test_js_n_ts( + r#""#, + &core::config::Config { + jsx_runtime: Some(core::config::JSXRuntime::Classic), + expand_props: core::config::ExpandProps::Bool(false), + ..Default::default() + }, + &core::state::InternalConfig { + ..Default::default() + }, + r#"import * as React from "react"; +const SvgComponent = ()=>; +export default SvgComponent; +"#, + r#"import * as React from "react"; +const SvgComponent = ()=>; +export default SvgComponent; +"#, + ); + } + + #[test] + fn allows_to_specify_a_custom_classic_jsx_runtime_using_specifiers() { + test_js_n_ts( + r#""#, + &core::config::Config { + jsx_runtime: Some(core::config::JSXRuntime::Classic), + jsx_runtime_import: Some(core::config::JSXRuntimeImport { + specifiers: Some(vec!["h".to_string()]), + source: "preact".to_string(), + ..Default::default() + }), + expand_props: core::config::ExpandProps::Bool(false), + ..Default::default() + }, + &core::state::InternalConfig { + ..Default::default() + }, + r#"import { h } from "preact"; +const SvgComponent = ()=>; +export default SvgComponent; +"#, + r#"import { h } from "preact"; +const SvgComponent = ()=>; +export default SvgComponent; +"#, + ); + } + + #[test] + fn allows_to_specify_a_custom_classic_jsx_runtime_using_namespace() { + test_js_n_ts( + r#""#, + &core::config::Config { + jsx_runtime: Some(core::config::JSXRuntime::Classic), + jsx_runtime_import: Some(core::config::JSXRuntimeImport { + namespace: Some("Preact".to_string()), + source: "preact".to_string(), + ..Default::default() + }), + expand_props: core::config::ExpandProps::Bool(false), + ..Default::default() + }, + &core::state::InternalConfig { + ..Default::default() + }, + r#"import * as Preact from "preact"; +const SvgComponent = ()=>; +export default SvgComponent; +"#, + r#"import * as Preact from "preact"; +const SvgComponent = ()=>; +export default SvgComponent; +"#, + ); + } + + #[test] + fn allows_to_specify_a_custom_classic_jsx_runtime_using_default_specifier() { + test_js_n_ts( + r#""#, + &core::config::Config { + jsx_runtime: Some(core::config::JSXRuntime::Classic), + jsx_runtime_import: Some(core::config::JSXRuntimeImport { + default_specifier: Some("h".to_string()), + source: "hyperapp-jsx-pragma".to_string(), + ..Default::default() + }), + expand_props: core::config::ExpandProps::Bool(false), + ..Default::default() + }, + &core::state::InternalConfig { + ..Default::default() + }, + r#"import h from "hyperapp-jsx-pragma"; +const SvgComponent = ()=>; +export default SvgComponent; +"#, + r#"import h from "hyperapp-jsx-pragma"; +const SvgComponent = ()=>; +export default SvgComponent; +"#, + ); + } + + #[test] + #[should_panic( + expected = r#"called `Result::unwrap()` on an `Err` value: Configuration("Specify \"namespace\", \"defaultSpecifier\", or \"specifiers\" in \"jsxRuntimeImport\" option")"# + )] + fn throws_with_invalid_configuration() { + test_code( + r#""#, + &core::config::Config { + jsx_runtime: Some(core::config::JSXRuntime::Classic), + jsx_runtime_import: Some(core::config::JSXRuntimeImport { + source: "preact".to_string(), + ..Default::default() + }), + expand_props: core::config::ExpandProps::Bool(false), + ..Default::default() + }, + &core::state::InternalConfig { + ..Default::default() + }, + r#""#, + ); + } +} diff --git a/crates/svgr-rs/src/transform_svg_component/variables.rs b/crates/svgr-rs/src/transform_svg_component/variables.rs new file mode 100644 index 000000000..f3842817c --- /dev/null +++ b/crates/svgr-rs/src/transform_svg_component/variables.rs @@ -0,0 +1,607 @@ +use std::borrow::Borrow; +use std::sync::Arc; + +use swc_core::common::{FileName, SourceMap, SyntaxContext, DUMMY_SP}; +use swc_core::ecma::ast::*; +use swc_core::ecma::parser; + +use super::core; +use crate::SvgrError; + +pub struct TemplateVariables { + #[allow(dead_code)] + pub component_name: String, + pub interfaces: Vec, + pub props: Vec, + pub imports: Vec, + pub exports: Vec, + pub jsx: JSXElement, +} + +#[derive(Default)] +pub enum JSXRuntime { + Automatic, + #[default] + Classic, +} + +pub enum ExpandProps { + Bool(bool), + Start, + End, +} + +#[derive(Default)] +pub enum ExportType { + #[default] + Default, + Named, +} + +#[derive(Default)] +pub struct Options { + pub typescript: bool, + pub title_prop: bool, + pub desc_prop: bool, + pub expand_props: Option, + pub _ref: bool, + // pub template: Option>, + pub native: bool, + pub memo: bool, + pub export_type: ExportType, + pub named_export: Option, + pub jsx_runtime: JSXRuntime, + pub jsx_runtime_import: Option, + pub import_source: Option, +} + +pub fn get_variables( + opts: Options, + state: &core::state::InternalConfig, + jsx: JSXElement, +) -> Result { + let mut interfaces = vec![]; + let mut props = vec![]; + let mut imports = vec![]; + let mut exports = vec![]; + + let import_source = opts.import_source.unwrap_or("react".to_string()); + + let mut export_identifier = state.component_name.clone(); + + let is_automatic = matches!(opts.jsx_runtime, JSXRuntime::Automatic); + if !is_automatic { + match opts.jsx_runtime_import { + Some(jsx_runtime_import) => { + let jsx_runtime_import = get_jsx_runtime_import(&jsx_runtime_import)?; + imports.push(jsx_runtime_import); + } + None => { + let default_jsx_runtime_import = core::config::JSXRuntimeImport { + source: "react".to_string(), + namespace: Some("React".to_string()), + ..Default::default() + }; + let jsx_runtime_import = get_jsx_runtime_import(&default_jsx_runtime_import)?; + imports.push(jsx_runtime_import); + } + } + } + + if opts.native { + let specifier = ImportSpecifier::Default(ImportDefaultSpecifier { + span: DUMMY_SP, + local: Ident { + span: DUMMY_SP, + ctxt: SyntaxContext::empty(), + sym: "Svg".into(), + optional: false, + }, + }); + get_or_create_import(&mut imports, "react-native-svg", specifier); + } + + if opts.title_prop || opts.desc_prop { + let mut properties = vec![]; + let mut property_signatures = vec![]; + + if opts.title_prop { + properties.push(create_property("title")); + properties.push(create_property("titleId")); + + if opts.typescript { + property_signatures.push(create_signature("title")); + property_signatures.push(create_signature("titleId")); + } + } + + if opts.desc_prop { + properties.push(create_property("desc")); + properties.push(create_property("descId")); + + if opts.typescript { + property_signatures.push(create_signature("desc")); + property_signatures.push(create_signature("descId")); + } + } + + let mut prop = ObjectPat { + span: DUMMY_SP, + props: properties, + optional: false, + type_ann: None, + }; + + if opts.typescript { + let interface = + ModuleItem::Stmt(Stmt::Decl(Decl::TsInterface(Box::new(TsInterfaceDecl { + id: Ident::new("SVGRProps".into(), DUMMY_SP, SyntaxContext::empty()), + span: DUMMY_SP, + declare: false, + type_params: None, + extends: vec![], + body: TsInterfaceBody { + span: DUMMY_SP, + body: property_signatures, + }, + })))); + interfaces.push(interface); + + prop.type_ann = Some(Box::new(TsTypeAnn { + span: DUMMY_SP, + type_ann: Box::new(TsType::TsTypeRef(TsTypeRef { + span: DUMMY_SP, + type_name: TsEntityName::Ident(Ident::new( + "SVGRProps".into(), + DUMMY_SP, + SyntaxContext::empty(), + )), + type_params: None, + })), + })); + } + + props.push(Pat::Object(prop)); + } + + let need_expand_props = match opts.expand_props { + None => false, + Some(ExpandProps::Bool(expand_props)) => expand_props, + _ => true, + }; + if need_expand_props { + let existing = if !props.is_empty() { + if let Pat::Object(ref mut object_pat) = props[0] { + let identifier = Pat::Ident(BindingIdent::from(Ident::new( + "props".into(), + DUMMY_SP, + SyntaxContext::empty(), + ))); + object_pat.props.push(ObjectPatProp::Rest(RestPat { + span: DUMMY_SP, + dot3_token: DUMMY_SP, + arg: Box::new(identifier), + type_ann: None, + })); + + if opts.typescript { + let svg_props_type = + ts_type_reference_svg_props(&mut imports, opts.native, &import_source); + let type_ann = Box::new(TsType::TsUnionOrIntersectionType( + TsUnionOrIntersectionType::TsIntersectionType(TsIntersectionType { + span: DUMMY_SP, + types: vec![ + svg_props_type, + Box::new(TsType::TsTypeRef(TsTypeRef { + span: DUMMY_SP, + type_name: TsEntityName::Ident(Ident::new( + "SVGRProps".into(), + DUMMY_SP, + SyntaxContext::empty(), + )), + type_params: None, + })), + ], + }), + )); + object_pat.type_ann = Some(Box::new(TsTypeAnn { + span: DUMMY_SP, + type_ann, + })); + } + + true + } else { + false + } + } else { + false + }; + + if !existing { + let mut prop = + BindingIdent::from(Ident::new("props".into(), DUMMY_SP, SyntaxContext::empty())); + + if opts.typescript { + let type_ann = + ts_type_reference_svg_props(&mut imports, opts.native, &import_source); + prop.type_ann = Some(Box::new(TsTypeAnn { + span: DUMMY_SP, + type_ann, + })); + } + + props.push(Pat::Ident(prop)); + } + } + + if opts._ref { + if props.is_empty() { + props.push(Pat::Ident(BindingIdent::from(Ident::new( + "_".into(), + DUMMY_SP, + SyntaxContext::empty(), + )))); + } + let mut prop = + BindingIdent::from(Ident::new("ref".into(), DUMMY_SP, SyntaxContext::empty())); + + if opts.typescript { + get_or_create_named_import(&mut imports, "react", "Ref"); + + prop.type_ann = Some(Box::new(TsTypeAnn { + span: DUMMY_SP, + type_ann: Box::new(TsType::TsTypeRef(TsTypeRef { + span: DUMMY_SP, + type_name: TsEntityName::Ident(Ident::new( + "Ref".into(), + DUMMY_SP, + SyntaxContext::empty(), + )), + type_params: Some(Box::new(TsTypeParamInstantiation { + span: DUMMY_SP, + params: vec![Box::new(TsType::TsTypeRef(TsTypeRef { + span: DUMMY_SP, + type_name: TsEntityName::Ident(Ident::new( + "SVGSVGElement".into(), + DUMMY_SP, + SyntaxContext::empty(), + )), + type_params: None, + }))], + })), + })), + })); + } + + props.push(Pat::Ident(prop)); + + get_or_create_named_import(&mut imports, &import_source, "forwardRef"); + let hoc = create_var_decl_init_hoc("ForwardRef", "forwardRef", &export_identifier); + exports.push(hoc); + export_identifier = "ForwardRef".to_string(); + } + + if opts.memo { + get_or_create_named_import(&mut imports, &import_source, "memo"); + let hoc = create_var_decl_init_hoc("Memo", "memo", &export_identifier); + exports.push(hoc); + export_identifier = "Memo".to_string(); + } + + let need_named_export = if state.caller.is_some() { + true + } else { + matches!(opts.export_type, ExportType::Named) + }; + if need_named_export { + if let Some(named_export) = opts.named_export { + let specifier = ExportSpecifier::Named(ExportNamedSpecifier { + span: DUMMY_SP, + orig: ModuleExportName::Ident(Ident::new( + export_identifier.clone().into(), + DUMMY_SP, + SyntaxContext::empty(), + )), + exported: Some(ModuleExportName::Ident(Ident { + span: DUMMY_SP, + ctxt: SyntaxContext::empty(), + sym: named_export.into(), + optional: false, + })), + is_type_only: false, + }); + + exports.push(ModuleItem::ModuleDecl(ModuleDecl::ExportNamed( + NamedExport { + span: DUMMY_SP, + specifiers: vec![specifier], + src: None, + type_only: false, + with: None, + }, + ))); + + if let Some(caller) = &state.caller { + if let Some(previous_export) = caller.previous_export.clone() { + let cm = Arc::::default(); + let fm = cm.new_source_file(FileName::Anon.into(), previous_export); + + let mut recovered_errors = vec![]; + let module = parser::parse_file_as_module( + fm.borrow(), + parser::Syntax::Es(parser::EsSyntax { + jsx: true, + ..Default::default() + }), + EsVersion::Es2020, + None, + &mut recovered_errors, + ) + .unwrap(); + for module_item in module.body { + exports.push(module_item) + } + } + } + } else { + return Err(SvgrError::Configuration( + r#""namedExport" not specified"#.to_string(), + )); + } + } + + if !need_named_export { + exports.push(ModuleItem::ModuleDecl(ModuleDecl::ExportDefaultExpr( + ExportDefaultExpr { + span: DUMMY_SP, + expr: Box::new(Expr::Ident(Ident::new( + export_identifier.into(), + DUMMY_SP, + SyntaxContext::empty(), + ))), + }, + ))); + } + + Ok(TemplateVariables { + component_name: state.component_name.clone(), + interfaces, + props, + imports, + exports, + jsx, + }) +} + +fn get_jsx_runtime_import(cfg: &core::config::JSXRuntimeImport) -> Result { + let specifiers = get_jsx_runtime_import_specifiers(cfg)?; + + Ok(ModuleItem::ModuleDecl(ModuleDecl::Import(ImportDecl { + span: DUMMY_SP, + specifiers, + src: Box::new(Str { + span: DUMMY_SP, + value: cfg.source.clone().into(), + raw: None, + }), + type_only: false, + with: None, + phase: Default::default(), + }))) +} + +fn get_jsx_runtime_import_specifiers( + cfg: &core::config::JSXRuntimeImport, +) -> Result, SvgrError> { + if let Some(namespace) = cfg.namespace.clone() { + let specifier = ImportSpecifier::Namespace(ImportStarAsSpecifier { + span: DUMMY_SP, + local: Ident { + span: DUMMY_SP, + ctxt: SyntaxContext::empty(), + sym: namespace.into(), + optional: false, + }, + }); + return Ok(vec![specifier]); + } + + if let Some(default_specifier) = cfg.default_specifier.clone() { + let specifier = ImportSpecifier::Default(ImportDefaultSpecifier { + span: DUMMY_SP, + local: Ident { + span: DUMMY_SP, + ctxt: SyntaxContext::empty(), + sym: default_specifier.into(), + optional: false, + }, + }); + return Ok(vec![specifier]); + } + + if let Some(specifiers) = cfg.specifiers.clone() { + let mut import_specifiers = vec![]; + for specifier in specifiers { + import_specifiers.push(ImportSpecifier::Named(ImportNamedSpecifier { + span: DUMMY_SP, + local: Ident { + span: DUMMY_SP, + ctxt: SyntaxContext::empty(), + sym: specifier.into(), + optional: false, + }, + imported: None, + is_type_only: false, + })); + } + return Ok(import_specifiers); + } + + Err(SvgrError::Configuration( + r#"Specify "namespace", "defaultSpecifier", or "specifiers" in "jsxRuntimeImport" option"# + .to_string(), + )) +} + +fn get_or_create_import( + imports: &mut Vec, + source_value: &str, + specifier: ImportSpecifier, +) { + let mut existing = None; + for import in imports.iter_mut() { + if let ModuleItem::ModuleDecl(ModuleDecl::Import(import_decl)) = import { + let is_namespace_import = import_decl + .specifiers + .iter() + .any(|specifier| matches!(specifier, ImportSpecifier::Namespace(_))); + if !is_namespace_import && import_decl.src.value == source_value { + existing = Some(import_decl); + break; + } + } + } + + if let Some(import_decl) = existing { + import_decl.specifiers.push(specifier); + return; + } + + let module_item = ModuleItem::ModuleDecl(ModuleDecl::Import(ImportDecl { + span: DUMMY_SP, + specifiers: vec![specifier], + src: Box::new(Str { + span: DUMMY_SP, + value: source_value.into(), + raw: None, + }), + type_only: false, + with: None, + phase: Default::default(), + })); + imports.push(module_item); +} + +fn get_or_create_named_import(imports: &mut Vec, source_value: &str, name: &str) { + let specifier = ImportSpecifier::Named(ImportNamedSpecifier { + span: DUMMY_SP, + local: Ident { + span: DUMMY_SP, + ctxt: SyntaxContext::empty(), + sym: name.into(), + optional: false, + }, + imported: None, + is_type_only: false, + }); + get_or_create_import(imports, source_value, specifier) +} + +fn create_var_decl_init_hoc(var_name: &str, callee: &str, component_name: &str) -> ModuleItem { + ModuleItem::Stmt(Stmt::Decl(Decl::Var(Box::new(VarDecl { + span: DUMMY_SP, + ctxt: SyntaxContext::empty(), + kind: VarDeclKind::Const, + declare: false, + decls: vec![VarDeclarator { + span: DUMMY_SP, + name: Pat::Ident(BindingIdent::from(Ident::new( + var_name.into(), + DUMMY_SP, + SyntaxContext::empty(), + ))), + definite: false, + init: Some(Box::new(Expr::Call(CallExpr { + span: DUMMY_SP, + ctxt: SyntaxContext::empty(), + callee: Callee::Expr(Box::new(Expr::Ident(Ident::new( + callee.into(), + DUMMY_SP, + SyntaxContext::empty(), + )))), + args: vec![ExprOrSpread { + spread: None, + expr: Box::new(Expr::Ident(Ident::new( + component_name.into(), + DUMMY_SP, + SyntaxContext::empty(), + ))), + }], + type_args: None, + }))), + }], + })))) +} + +fn create_property(key: &str) -> ObjectPatProp { + ObjectPatProp::Assign(AssignPatProp { + span: DUMMY_SP, + key: Ident::new(key.into(), DUMMY_SP, SyntaxContext::empty()).into(), + value: None, + }) +} + +fn create_signature(key: &str) -> TsTypeElement { + TsTypeElement::TsPropertySignature(TsPropertySignature { + span: DUMMY_SP, + readonly: false, + key: Box::new(Expr::Ident(Ident::new( + key.into(), + DUMMY_SP, + SyntaxContext::empty(), + ))), + computed: false, + optional: true, + type_ann: Some(Box::new(TsTypeAnn { + span: DUMMY_SP, + type_ann: Box::new(TsType::TsKeywordType(TsKeywordType { + span: DUMMY_SP, + kind: TsKeywordTypeKind::TsStringKeyword, + })), + })), + }) +} + +fn ts_type_reference_svg_props( + imports: &mut Vec, + native: bool, + import_source: &str, +) -> Box { + if native { + get_or_create_named_import(imports, "react-native-svg", "SvgProps"); + + return Box::new(TsType::TsTypeRef(TsTypeRef { + span: DUMMY_SP, + type_name: TsEntityName::Ident(Ident::new( + "SvgProps".into(), + DUMMY_SP, + SyntaxContext::empty(), + )), + type_params: None, + })); + } + + get_or_create_named_import(imports, import_source, "SVGProps"); + + Box::new(TsType::TsTypeRef(TsTypeRef { + span: DUMMY_SP, + type_name: TsEntityName::Ident(Ident::new( + "SVGProps".into(), + DUMMY_SP, + SyntaxContext::empty(), + )), + type_params: Some(Box::new(TsTypeParamInstantiation { + span: DUMMY_SP, + params: vec![Box::new(TsType::TsTypeRef(TsTypeRef { + span: DUMMY_SP, + type_name: TsEntityName::Ident(Ident::new( + "SVGSVGElement".into(), + DUMMY_SP, + SyntaxContext::empty(), + )), + type_params: None, + }))], + })), + })) +} diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 36e64a7ab..15a2e5e84 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] profile = "default" -channel = "nightly-2023-10-24" +channel = "nightly-2024-07-21" diff --git a/scripts/test-hmr.mjs b/scripts/test-hmr.mjs index 8d12ecc24..b61ec59e9 100644 --- a/scripts/test-hmr.mjs +++ b/scripts/test-hmr.mjs @@ -1807,7 +1807,7 @@ runTest('js: response correct content-type', async () => { const headers = response.headers(); assert.equal( headers['content-type'], - 'application/javascript; charset=utf-8', + 'text/javascript; charset=utf-8', 'hot-update content-type', ); cleanup({ process, browser });