From 9b7359512aaeb6f6da230f2daea8b4d714bd6e68 Mon Sep 17 00:00:00 2001 From: Liang Mi Date: Mon, 6 Jul 2026 10:24:47 +0800 Subject: [PATCH 1/9] wip --- crates/vite_static_config/src/lib.rs | 101 ++++++++++++++++++++++++++- 1 file changed, 100 insertions(+), 1 deletion(-) diff --git a/crates/vite_static_config/src/lib.rs b/crates/vite_static_config/src/lib.rs index 29d65539e0..630051a127 100644 --- a/crates/vite_static_config/src/lib.rs +++ b/crates/vite_static_config/src/lib.rs @@ -5,7 +5,10 @@ //! config like `run` without needing a Node.js runtime. use oxc_allocator::Allocator; -use oxc_ast::ast::{Expression, ObjectPropertyKind, Program, Statement}; +use oxc_ast::ast::{ + BindingPattern, Expression, ImportDeclarationSpecifier, ModuleExportName, ObjectPropertyKind, + Program, Statement, +}; use oxc_parser::Parser; use oxc_span::SourceType; use rustc_hash::FxHashMap; @@ -145,6 +148,11 @@ fn parse_js_ts_config(source: &str, extension: &str) -> FieldMap { /// 4. `module.exports = { ... }` fn extract_config_fields(program: &Program<'_>) -> FieldMap { for stmt in &program.body { + // Filter `defineConfig` import from other packages or defined by itself. + if find_custom_define_config(stmt) { + return FieldMap::unanalyzable(); + } + // ESM: export default ... if let Statement::ExportDefaultDeclaration(decl) = stmt { if let Some(expr) = decl.declaration.as_expression() { @@ -246,6 +254,97 @@ fn extract_config_from_function_body(body: &oxc_ast::ast::FunctionBody<'_>) -> F FieldMap::unanalyzable() } +fn find_custom_define_config(stmt: &Statement<'_>) -> bool { + if let Statement::VariableDeclaration(decl) = stmt { + // Reject `var/let/const defineConfig = .....`, except `const defineConfig = require('vite-plus').defineConfig` + for declarator in &decl.declarations { + if let BindingPattern::BindingIdentifier(id) = &declarator.id + && id.name == "defineConfig" + { + let allowed = declarator.init.as_ref().is_some_and(|init| { + init.without_parentheses().as_member_expression().is_some_and(|member| { + member.static_property_name() == Some("defineConfig") + && matches!( + member.object().without_parentheses(), + Expression::CallExpression(call) + if call.common_js_require().is_some_and(|source| source.value == "vite-plus") + ) + }) + }); + if !allowed { + return true; + } + } + } + + // Reject `var/let/const { defineConfig } = .....`, except `const { defineConfig } = require('vite-plus')` + for declarator in &decl.declarations { + let BindingPattern::ObjectPattern(pattern) = &declarator.id else { + continue; + }; + + for prop in &pattern.properties { + let binds_define_config = match &prop.value { + BindingPattern::BindingIdentifier(id) => id.name == "defineConfig", + BindingPattern::AssignmentPattern(assignment) => { + matches!(&assignment.left, BindingPattern::BindingIdentifier(id) if id.name == "defineConfig") + } + _ => false, + }; + if !binds_define_config { + continue; + } + + let is_direct_define_config = !prop.computed + && prop.key.static_name().is_some_and(|key| key == "defineConfig"); + let is_allowed = is_direct_define_config && declarator.init.as_ref().is_some_and(|init| { + matches!( + init.without_parentheses(), + Expression::CallExpression(call) + if call.common_js_require().is_some_and(|source| source.value == "vite-plus") + ) + }); + + if !is_allowed { + return true; + } + } + } + } + + if let Statement::ImportDeclaration(import_decl) = stmt { + let Some(specifiers) = &import_decl.specifiers else { + return false; + }; + + for specifier in specifiers { + // Reject `import defineConfig from .....` + if let ImportDeclarationSpecifier::ImportDefaultSpecifier(specifier) = specifier + && specifier.local.name == "defineConfig" + { + return true; + } + + // Reject `import { defineConfig } from ....` except `import { defineConfig } from 'vite-plus'` + if let ImportDeclarationSpecifier::ImportSpecifier(specifier) = specifier + && specifier.local.name == "defineConfig" + { + let imported_define_config = match &specifier.imported { + ModuleExportName::IdentifierName(id) => id.name == "defineConfig", + ModuleExportName::IdentifierReference(id) => id.name == "defineConfig", + ModuleExportName::StringLiteral(lit) => lit.value == "defineConfig", + }; + + if import_decl.source.value != "vite-plus" || !imported_define_config { + return true; + } + } + } + } + + false +} + /// Count `return` statements recursively in a slice of statements. /// Does not descend into nested function/arrow expressions (they have their own returns). fn count_returns_in_stmts(stmts: &[Statement<'_>]) -> usize { From d7916934e83235ac9de270eefcdedb1c6700d6b1 Mon Sep 17 00:00:00 2001 From: Liang Mi Date: Mon, 6 Jul 2026 10:37:12 +0800 Subject: [PATCH 2/9] snap-test --- .../run-config-custom-define-config/define-config.ts | 12 ++++++++++++ .../run-config-custom-define-config/package.json | 4 ++++ .../run-config-custom-define-config/runtime.js | 1 + .../run-config-custom-define-config/snap.txt | 4 ++++ .../run-config-custom-define-config/static.js | 1 + .../run-config-custom-define-config/steps.json | 5 +++++ .../run-config-custom-define-config/vite.config.ts | 12 ++++++++++++ 7 files changed, 39 insertions(+) create mode 100644 packages/cli/snap-tests/run-config-custom-define-config/define-config.ts create mode 100644 packages/cli/snap-tests/run-config-custom-define-config/package.json create mode 100644 packages/cli/snap-tests/run-config-custom-define-config/runtime.js create mode 100644 packages/cli/snap-tests/run-config-custom-define-config/snap.txt create mode 100644 packages/cli/snap-tests/run-config-custom-define-config/static.js create mode 100644 packages/cli/snap-tests/run-config-custom-define-config/steps.json create mode 100644 packages/cli/snap-tests/run-config-custom-define-config/vite.config.ts diff --git a/packages/cli/snap-tests/run-config-custom-define-config/define-config.ts b/packages/cli/snap-tests/run-config-custom-define-config/define-config.ts new file mode 100644 index 0000000000..cd81b1fe9b --- /dev/null +++ b/packages/cli/snap-tests/run-config-custom-define-config/define-config.ts @@ -0,0 +1,12 @@ +export function defineConfig(_config: unknown) { + return { + run: { + tasks: { + selected: { + command: 'node runtime.js', + dependsOn: [], + }, + }, + }, + }; +} diff --git a/packages/cli/snap-tests/run-config-custom-define-config/package.json b/packages/cli/snap-tests/run-config-custom-define-config/package.json new file mode 100644 index 0000000000..cb6912a458 --- /dev/null +++ b/packages/cli/snap-tests/run-config-custom-define-config/package.json @@ -0,0 +1,4 @@ +{ + "name": "run-config-custom-define-config", + "private": true +} diff --git a/packages/cli/snap-tests/run-config-custom-define-config/runtime.js b/packages/cli/snap-tests/run-config-custom-define-config/runtime.js new file mode 100644 index 0000000000..e684430508 --- /dev/null +++ b/packages/cli/snap-tests/run-config-custom-define-config/runtime.js @@ -0,0 +1 @@ +console.log('runtime defineConfig result'); diff --git a/packages/cli/snap-tests/run-config-custom-define-config/snap.txt b/packages/cli/snap-tests/run-config-custom-define-config/snap.txt new file mode 100644 index 0000000000..397862db9f --- /dev/null +++ b/packages/cli/snap-tests/run-config-custom-define-config/snap.txt @@ -0,0 +1,4 @@ +> vp run selected # defineConfig from a local module must use runtime config resolution +$ node runtime.js +runtime defineConfig result + diff --git a/packages/cli/snap-tests/run-config-custom-define-config/static.js b/packages/cli/snap-tests/run-config-custom-define-config/static.js new file mode 100644 index 0000000000..90f289f6bc --- /dev/null +++ b/packages/cli/snap-tests/run-config-custom-define-config/static.js @@ -0,0 +1 @@ +console.log('statically extracted config'); diff --git a/packages/cli/snap-tests/run-config-custom-define-config/steps.json b/packages/cli/snap-tests/run-config-custom-define-config/steps.json new file mode 100644 index 0000000000..5b0d9957c0 --- /dev/null +++ b/packages/cli/snap-tests/run-config-custom-define-config/steps.json @@ -0,0 +1,5 @@ +{ + "commands": [ + "vp run selected # defineConfig from a local module must use runtime config resolution" + ] +} diff --git a/packages/cli/snap-tests/run-config-custom-define-config/vite.config.ts b/packages/cli/snap-tests/run-config-custom-define-config/vite.config.ts new file mode 100644 index 0000000000..4725c9d0e7 --- /dev/null +++ b/packages/cli/snap-tests/run-config-custom-define-config/vite.config.ts @@ -0,0 +1,12 @@ +import { defineConfig } from './define-config'; + +export default defineConfig({ + run: { + tasks: { + selected: { + command: 'node static.js', + dependsOn: [], + }, + }, + }, +}); From bf702d8c87dad1a03a9e0b2ebfc94baa14c888ed Mon Sep 17 00:00:00 2001 From: Liang Mi Date: Mon, 6 Jul 2026 10:43:08 +0800 Subject: [PATCH 3/9] unit tests --- crates/vite_static_config/src/lib.rs | 37 ++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/crates/vite_static_config/src/lib.rs b/crates/vite_static_config/src/lib.rs index 630051a127..c88a7166de 100644 --- a/crates/vite_static_config/src/lib.rs +++ b/crates/vite_static_config/src/lib.rs @@ -651,6 +651,32 @@ mod tests { assert_json(&result, "lint", serde_json::json!({ "plugins": ["a"] })); } + #[test] + fn define_config_import_from_other_package_is_non_static() { + let result = parse( + r" + import { defineConfig } from 'vite'; + export default defineConfig({ + run: { cacheScripts: true }, + }); + ", + ); + assert_non_static(&result, "run"); + } + + #[test] + fn define_config_defined_as_variable() { + let result = parse( + r" + const { defineConfig } = {}; + export default defineConfig({ + run: { cacheScripts: true }, + }); + ", + ); + assert_non_static(&result, "run"); + } + // ── module.exports = { ... } ─────────────────────────────────────── #[test] @@ -683,6 +709,17 @@ mod tests { assert_non_static(&parse_js_ts_config("module.exports = otherFn({ a: 1 });", "cjs"), "run"); } + #[test] + fn module_exports_untrusted_define_config_import() { + assert_non_static( + &parse_js_ts_config( + "const defineConfig = require('config-preset'); module.exports = defineConfig({ run: {} });", + "cjs", + ), + "run", + ); + } + // ── Primitive values ──────────────────────────────────────────────── #[test] From 9292b3f0b78ceec3cb60467c6ec8e8b0e827cb0a Mon Sep 17 00:00:00 2001 From: Liang Mi Date: Mon, 6 Jul 2026 11:21:46 +0800 Subject: [PATCH 4/9] wip --- crates/vite_static_config/src/lib.rs | 86 +++++++++++++++++++++++++++- 1 file changed, 83 insertions(+), 3 deletions(-) diff --git a/crates/vite_static_config/src/lib.rs b/crates/vite_static_config/src/lib.rs index c88a7166de..3a9db71b97 100644 --- a/crates/vite_static_config/src/lib.rs +++ b/crates/vite_static_config/src/lib.rs @@ -147,9 +147,12 @@ fn parse_js_ts_config(source: &str, extension: &str) -> FieldMap { /// 3. `module.exports = defineConfig({ ... })` /// 4. `module.exports = { ... }` fn extract_config_fields(program: &Program<'_>) -> FieldMap { + if has_untrusted_hoisted_define_config_binding(program) { + return FieldMap::unanalyzable(); + } + for stmt in &program.body { - // Filter `defineConfig` import from other packages or defined by itself. - if find_custom_define_config(stmt) { + if has_untrusted_define_config_variable_binding(stmt) { return FieldMap::unanalyzable(); } @@ -254,7 +257,11 @@ fn extract_config_from_function_body(body: &oxc_ast::ast::FunctionBody<'_>) -> F FieldMap::unanalyzable() } -fn find_custom_define_config(stmt: &Statement<'_>) -> bool { +fn has_untrusted_hoisted_define_config_binding(program: &Program<'_>) -> bool { + program.body.iter().any(has_untrusted_hoisted_define_config_binding_in_stmt) +} + +fn has_untrusted_define_config_variable_binding(stmt: &Statement<'_>) -> bool { if let Statement::VariableDeclaration(decl) = stmt { // Reject `var/let/const defineConfig = .....`, except `const defineConfig = require('vite-plus').defineConfig` for declarator in &decl.declarations { @@ -312,6 +319,24 @@ fn find_custom_define_config(stmt: &Statement<'_>) -> bool { } } + false +} + +fn has_untrusted_hoisted_define_config_binding_in_stmt(stmt: &Statement<'_>) -> bool { + // Reject `function defineConfig(...){...}` + if let Statement::FunctionDeclaration(func) = stmt + && func.id.as_ref().is_some_and(|id| id.name == "defineConfig") + { + return true; + } + + // Reject `import defineConfig = require(...)` + if let Statement::TSImportEqualsDeclaration(import_decl) = stmt + && import_decl.id.name == "defineConfig" + { + return true; + } + if let Statement::ImportDeclaration(import_decl) = stmt { let Some(specifiers) = &import_decl.specifiers else { return false; @@ -664,6 +689,19 @@ mod tests { assert_non_static(&result, "run"); } + #[test] + fn define_config_import_after_default_export_is_non_static() { + let result = parse( + r" + export default defineConfig({ + run: { cacheScripts: true }, + }); + import { defineConfig } from './define-config'; + ", + ); + assert_non_static(&result, "run"); + } + #[test] fn define_config_defined_as_variable() { let result = parse( @@ -677,6 +715,48 @@ mod tests { assert_non_static(&result, "run"); } + #[test] + fn define_config_variable_after_default_export_does_not_block_static_extraction() { + let result = parse( + r" + export default defineConfig({ + run: { cacheScripts: true }, + }); + const defineConfig = () => ({ run: { cacheScripts: false } }); + ", + ); + assert_json(&result, "run", serde_json::json!({ "cacheScripts": true })); + } + + #[test] + fn define_config_defined_as_function_is_non_static() { + let result = parse( + r" + function defineConfig() { + return { run: { cacheScripts: false } }; + } + export default defineConfig({ + run: { cacheScripts: true }, + }); + ", + ); + assert_non_static(&result, "run"); + } + + #[test] + fn define_config_import_equals_is_non_static() { + let result = parse_js_ts_config( + r#" + import defineConfig = require("./define-config"); + export default defineConfig({ + run: { cacheScripts: true }, + }); + "#, + "cts", + ); + assert_non_static(&result, "run"); + } + // ── module.exports = { ... } ─────────────────────────────────────── #[test] From 4bded2ec89ebf7dba61684469163d4de31e360ce Mon Sep 17 00:00:00 2001 From: Liang Mi Date: Mon, 6 Jul 2026 11:40:11 +0800 Subject: [PATCH 5/9] wip --- crates/vite_static_config/src/lib.rs | 144 ++++++++++++++++++--------- 1 file changed, 96 insertions(+), 48 deletions(-) diff --git a/crates/vite_static_config/src/lib.rs b/crates/vite_static_config/src/lib.rs index 3a9db71b97..83d6ffc708 100644 --- a/crates/vite_static_config/src/lib.rs +++ b/crates/vite_static_config/src/lib.rs @@ -6,8 +6,8 @@ use oxc_allocator::Allocator; use oxc_ast::ast::{ - BindingPattern, Expression, ImportDeclarationSpecifier, ModuleExportName, ObjectPropertyKind, - Program, Statement, + BindingPattern, Declaration, Expression, ImportDeclarationSpecifier, ModuleExportName, + ObjectPropertyKind, Program, Statement, VariableDeclaration, }; use oxc_parser::Parser; use oxc_span::SourceType; @@ -262,59 +262,74 @@ fn has_untrusted_hoisted_define_config_binding(program: &Program<'_>) -> bool { } fn has_untrusted_define_config_variable_binding(stmt: &Statement<'_>) -> bool { - if let Statement::VariableDeclaration(decl) = stmt { - // Reject `var/let/const defineConfig = .....`, except `const defineConfig = require('vite-plus').defineConfig` - for declarator in &decl.declarations { - if let BindingPattern::BindingIdentifier(id) = &declarator.id - && id.name == "defineConfig" - { - let allowed = declarator.init.as_ref().is_some_and(|init| { - init.without_parentheses().as_member_expression().is_some_and(|member| { - member.static_property_name() == Some("defineConfig") - && matches!( - member.object().without_parentheses(), - Expression::CallExpression(call) - if call.common_js_require().is_some_and(|source| source.value == "vite-plus") - ) - }) - }); - if !allowed { - return true; + match stmt { + Statement::VariableDeclaration(decl) => { + has_untrusted_define_config_variable_declaration(decl) + } + Statement::ExportNamedDeclaration(export_decl) => { + export_decl.declaration.as_ref().is_some_and(|decl| match decl { + Declaration::VariableDeclaration(decl) => { + has_untrusted_define_config_variable_declaration(decl) } + _ => false, + }) + } + _ => false, + } +} + +fn has_untrusted_define_config_variable_declaration(decl: &VariableDeclaration<'_>) -> bool { + // Reject `var/let/const defineConfig = .....`, except `const defineConfig = require('vite-plus').defineConfig` + for declarator in &decl.declarations { + if let BindingPattern::BindingIdentifier(id) = &declarator.id + && id.name == "defineConfig" + { + let allowed = declarator.init.as_ref().is_some_and(|init| { + init.without_parentheses().as_member_expression().is_some_and(|member| { + member.static_property_name() == Some("defineConfig") + && matches!( + member.object().without_parentheses(), + Expression::CallExpression(call) + if call.common_js_require().is_some_and(|source| source.value == "vite-plus") + ) + }) + }); + if !allowed { + return true; } } + } - // Reject `var/let/const { defineConfig } = .....`, except `const { defineConfig } = require('vite-plus')` - for declarator in &decl.declarations { - let BindingPattern::ObjectPattern(pattern) = &declarator.id else { - continue; - }; + // Reject `var/let/const { defineConfig } = .....`, except `const { defineConfig } = require('vite-plus')` + for declarator in &decl.declarations { + let BindingPattern::ObjectPattern(pattern) = &declarator.id else { + continue; + }; - for prop in &pattern.properties { - let binds_define_config = match &prop.value { - BindingPattern::BindingIdentifier(id) => id.name == "defineConfig", - BindingPattern::AssignmentPattern(assignment) => { - matches!(&assignment.left, BindingPattern::BindingIdentifier(id) if id.name == "defineConfig") - } - _ => false, - }; - if !binds_define_config { - continue; + for prop in &pattern.properties { + let binds_define_config = match &prop.value { + BindingPattern::BindingIdentifier(id) => id.name == "defineConfig", + BindingPattern::AssignmentPattern(assignment) => { + matches!(&assignment.left, BindingPattern::BindingIdentifier(id) if id.name == "defineConfig") } + _ => false, + }; + if !binds_define_config { + continue; + } - let is_direct_define_config = !prop.computed - && prop.key.static_name().is_some_and(|key| key == "defineConfig"); - let is_allowed = is_direct_define_config && declarator.init.as_ref().is_some_and(|init| { - matches!( - init.without_parentheses(), - Expression::CallExpression(call) - if call.common_js_require().is_some_and(|source| source.value == "vite-plus") - ) - }); - - if !is_allowed { - return true; - } + let is_direct_define_config = + !prop.computed && prop.key.static_name().is_some_and(|key| key == "defineConfig"); + let is_allowed = is_direct_define_config && declarator.init.as_ref().is_some_and(|init| { + matches!( + init.without_parentheses(), + Expression::CallExpression(call) + if call.common_js_require().is_some_and(|source| source.value == "vite-plus") + ) + }); + + if !is_allowed { + return true; } } } @@ -350,6 +365,13 @@ fn has_untrusted_hoisted_define_config_binding_in_stmt(stmt: &Statement<'_>) -> return true; } + // Reject `import * as defineConfig from .....` + if let ImportDeclarationSpecifier::ImportNamespaceSpecifier(specifier) = specifier + && specifier.local.name == "defineConfig" + { + return true; + } + // Reject `import { defineConfig } from ....` except `import { defineConfig } from 'vite-plus'` if let ImportDeclarationSpecifier::ImportSpecifier(specifier) = specifier && specifier.local.name == "defineConfig" @@ -689,6 +711,19 @@ mod tests { assert_non_static(&result, "run"); } + #[test] + fn define_config_namespace_import_is_non_static() { + let result = parse( + r" + import * as defineConfig from './define-config'; + export default defineConfig({ + run: { cacheScripts: true }, + }); + ", + ); + assert_non_static(&result, "run"); + } + #[test] fn define_config_import_after_default_export_is_non_static() { let result = parse( @@ -715,6 +750,19 @@ mod tests { assert_non_static(&result, "run"); } + #[test] + fn define_config_defined_as_exported_variable_is_non_static() { + let result = parse( + r" + export const defineConfig = (config) => config; + export default defineConfig({ + run: { cacheScripts: true }, + }); + ", + ); + assert_non_static(&result, "run"); + } + #[test] fn define_config_variable_after_default_export_does_not_block_static_extraction() { let result = parse( From 1cae72a270863d6fd99d92f831c457b3b19ff091 Mon Sep 17 00:00:00 2001 From: Liang Mi Date: Mon, 6 Jul 2026 11:53:46 +0800 Subject: [PATCH 6/9] enhance --- crates/vite_static_config/src/lib.rs | 32 ++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/crates/vite_static_config/src/lib.rs b/crates/vite_static_config/src/lib.rs index 83d6ffc708..a2786b2a9e 100644 --- a/crates/vite_static_config/src/lib.rs +++ b/crates/vite_static_config/src/lib.rs @@ -147,19 +147,18 @@ fn parse_js_ts_config(source: &str, extension: &str) -> FieldMap { /// 3. `module.exports = defineConfig({ ... })` /// 4. `module.exports = { ... }` fn extract_config_fields(program: &Program<'_>) -> FieldMap { - if has_untrusted_hoisted_define_config_binding(program) { - return FieldMap::unanalyzable(); - } + let mut has_untrusted_define_config_binding = + has_untrusted_hoisted_define_config_binding(program); for stmt in &program.body { if has_untrusted_define_config_variable_binding(stmt) { - return FieldMap::unanalyzable(); + has_untrusted_define_config_binding = true; } // ESM: export default ... if let Statement::ExportDefaultDeclaration(decl) = stmt { if let Some(expr) = decl.declaration.as_expression() { - return extract_config_from_expr(expr); + return extract_config_from_expr(expr, has_untrusted_define_config_binding); } // export default class/function — not analyzable return FieldMap::unanalyzable(); @@ -172,7 +171,7 @@ fn extract_config_fields(program: &Program<'_>) -> FieldMap { m.object().is_specific_id("module") && m.static_property_name() == Some("exports") }) { - return extract_config_from_expr(&assign.right); + return extract_config_from_expr(&assign.right, has_untrusted_define_config_binding); } } @@ -186,13 +185,19 @@ fn extract_config_fields(program: &Program<'_>) -> FieldMap { /// - `defineConfig(function() { return { ... }; })` → extract from return statement /// - `{ ... }` → extract directly /// - anything else → not analyzable -fn extract_config_from_expr(expr: &Expression<'_>) -> FieldMap { +fn extract_config_from_expr( + expr: &Expression<'_>, + has_untrusted_define_config_binding: bool, +) -> FieldMap { let expr = expr.without_parentheses(); match expr { Expression::CallExpression(call) => { if !call.callee.is_specific_id("defineConfig") { return FieldMap::unanalyzable(); } + if has_untrusted_define_config_binding { + return FieldMap::unanalyzable(); + } let Some(first_arg) = call.arguments.first() else { return FieldMap::unanalyzable(); }; @@ -675,6 +680,19 @@ mod tests { assert_json(&result, "num", serde_json::json!(42)); } + #[test] + fn plain_export_default_object_ignores_unrelated_define_config_binding() { + let result = parse( + r" + import { defineConfig } from 'vite'; + export default { + run: { cacheScripts: true }, + }; + ", + ); + assert_json(&result, "run", serde_json::json!({ "cacheScripts": true })); + } + #[test] fn export_default_empty_object() { let result = parse("export default {}"); From 01a10353272950dedcf592e9d31bea17d2a875d4 Mon Sep 17 00:00:00 2001 From: Liang Mi Date: Mon, 6 Jul 2026 12:23:44 +0800 Subject: [PATCH 7/9] wip --- crates/vite_static_config/src/lib.rs | 283 +++++---------------------- 1 file changed, 44 insertions(+), 239 deletions(-) diff --git a/crates/vite_static_config/src/lib.rs b/crates/vite_static_config/src/lib.rs index a2786b2a9e..bc456f1e4b 100644 --- a/crates/vite_static_config/src/lib.rs +++ b/crates/vite_static_config/src/lib.rs @@ -6,8 +6,8 @@ use oxc_allocator::Allocator; use oxc_ast::ast::{ - BindingPattern, Declaration, Expression, ImportDeclarationSpecifier, ModuleExportName, - ObjectPropertyKind, Program, Statement, VariableDeclaration, + Expression, ImportDeclarationSpecifier, ImportOrExportKind, ModuleExportName, + ObjectPropertyKind, Program, Statement, }; use oxc_parser::Parser; use oxc_span::SourceType; @@ -142,23 +142,18 @@ fn parse_js_ts_config(source: &str, extension: &str) -> FieldMap { /// Find the config object in a parsed program and extract its fields. /// /// Searches for the config value in the following patterns (in order): -/// 1. `export default defineConfig({ ... })` +/// 1. `export default defineConfig({ ... })` with `defineConfig` imported from `vite-plus` /// 2. `export default { ... }` -/// 3. `module.exports = defineConfig({ ... })` +/// 3. `module.exports = defineConfig({ ... })` with `defineConfig` imported from `vite-plus` /// 4. `module.exports = { ... }` fn extract_config_fields(program: &Program<'_>) -> FieldMap { - let mut has_untrusted_define_config_binding = - has_untrusted_hoisted_define_config_binding(program); + let has_trusted_define_config_import = has_trusted_define_config_import(program); for stmt in &program.body { - if has_untrusted_define_config_variable_binding(stmt) { - has_untrusted_define_config_binding = true; - } - // ESM: export default ... if let Statement::ExportDefaultDeclaration(decl) = stmt { if let Some(expr) = decl.declaration.as_expression() { - return extract_config_from_expr(expr, has_untrusted_define_config_binding); + return extract_config_from_expr(expr, has_trusted_define_config_import); } // export default class/function — not analyzable return FieldMap::unanalyzable(); @@ -171,7 +166,7 @@ fn extract_config_fields(program: &Program<'_>) -> FieldMap { m.object().is_specific_id("module") && m.static_property_name() == Some("exports") }) { - return extract_config_from_expr(&assign.right, has_untrusted_define_config_binding); + return extract_config_from_expr(&assign.right, has_trusted_define_config_import); } } @@ -187,7 +182,7 @@ fn extract_config_fields(program: &Program<'_>) -> FieldMap { /// - anything else → not analyzable fn extract_config_from_expr( expr: &Expression<'_>, - has_untrusted_define_config_binding: bool, + has_trusted_define_config_import: bool, ) -> FieldMap { let expr = expr.without_parentheses(); match expr { @@ -195,7 +190,7 @@ fn extract_config_from_expr( if !call.callee.is_specific_id("defineConfig") { return FieldMap::unanalyzable(); } - if has_untrusted_define_config_binding { + if !has_trusted_define_config_import { return FieldMap::unanalyzable(); } let Some(first_arg) = call.arguments.first() else { @@ -262,139 +257,35 @@ fn extract_config_from_function_body(body: &oxc_ast::ast::FunctionBody<'_>) -> F FieldMap::unanalyzable() } -fn has_untrusted_hoisted_define_config_binding(program: &Program<'_>) -> bool { - program.body.iter().any(has_untrusted_hoisted_define_config_binding_in_stmt) -} - -fn has_untrusted_define_config_variable_binding(stmt: &Statement<'_>) -> bool { - match stmt { - Statement::VariableDeclaration(decl) => { - has_untrusted_define_config_variable_declaration(decl) - } - Statement::ExportNamedDeclaration(export_decl) => { - export_decl.declaration.as_ref().is_some_and(|decl| match decl { - Declaration::VariableDeclaration(decl) => { - has_untrusted_define_config_variable_declaration(decl) - } - _ => false, - }) - } - _ => false, - } -} - -fn has_untrusted_define_config_variable_declaration(decl: &VariableDeclaration<'_>) -> bool { - // Reject `var/let/const defineConfig = .....`, except `const defineConfig = require('vite-plus').defineConfig` - for declarator in &decl.declarations { - if let BindingPattern::BindingIdentifier(id) = &declarator.id - && id.name == "defineConfig" - { - let allowed = declarator.init.as_ref().is_some_and(|init| { - init.without_parentheses().as_member_expression().is_some_and(|member| { - member.static_property_name() == Some("defineConfig") - && matches!( - member.object().without_parentheses(), - Expression::CallExpression(call) - if call.common_js_require().is_some_and(|source| source.value == "vite-plus") - ) - }) - }); - if !allowed { - return true; - } - } - } - - // Reject `var/let/const { defineConfig } = .....`, except `const { defineConfig } = require('vite-plus')` - for declarator in &decl.declarations { - let BindingPattern::ObjectPattern(pattern) = &declarator.id else { - continue; - }; - - for prop in &pattern.properties { - let binds_define_config = match &prop.value { - BindingPattern::BindingIdentifier(id) => id.name == "defineConfig", - BindingPattern::AssignmentPattern(assignment) => { - matches!(&assignment.left, BindingPattern::BindingIdentifier(id) if id.name == "defineConfig") - } - _ => false, - }; - if !binds_define_config { - continue; - } - - let is_direct_define_config = - !prop.computed && prop.key.static_name().is_some_and(|key| key == "defineConfig"); - let is_allowed = is_direct_define_config && declarator.init.as_ref().is_some_and(|init| { - matches!( - init.without_parentheses(), - Expression::CallExpression(call) - if call.common_js_require().is_some_and(|source| source.value == "vite-plus") - ) - }); - - if !is_allowed { - return true; - } - } - } - - false -} - -fn has_untrusted_hoisted_define_config_binding_in_stmt(stmt: &Statement<'_>) -> bool { - // Reject `function defineConfig(...){...}` - if let Statement::FunctionDeclaration(func) = stmt - && func.id.as_ref().is_some_and(|id| id.name == "defineConfig") - { - return true; - } - - // Reject `import defineConfig = require(...)` - if let Statement::TSImportEqualsDeclaration(import_decl) = stmt - && import_decl.id.name == "defineConfig" - { - return true; - } - - if let Statement::ImportDeclaration(import_decl) = stmt { - let Some(specifiers) = &import_decl.specifiers else { +fn has_trusted_define_config_import(program: &Program<'_>) -> bool { + program.body.iter().any(|stmt| { + let Statement::ImportDeclaration(import_decl) = stmt else { return false; }; - - for specifier in specifiers { - // Reject `import defineConfig from .....` - if let ImportDeclarationSpecifier::ImportDefaultSpecifier(specifier) = specifier - && specifier.local.name == "defineConfig" - { - return true; - } - - // Reject `import * as defineConfig from .....` - if let ImportDeclarationSpecifier::ImportNamespaceSpecifier(specifier) = specifier - && specifier.local.name == "defineConfig" - { - return true; - } - - // Reject `import { defineConfig } from ....` except `import { defineConfig } from 'vite-plus'` - if let ImportDeclarationSpecifier::ImportSpecifier(specifier) = specifier - && specifier.local.name == "defineConfig" - { - let imported_define_config = match &specifier.imported { - ModuleExportName::IdentifierName(id) => id.name == "defineConfig", - ModuleExportName::IdentifierReference(id) => id.name == "defineConfig", - ModuleExportName::StringLiteral(lit) => lit.value == "defineConfig", + if import_decl.import_kind != ImportOrExportKind::Value + || import_decl.source.value != "vite-plus" + { + return false; + } + import_decl.specifiers.as_ref().is_some_and(|specifiers| { + specifiers.iter().any(|specifier| { + let ImportDeclarationSpecifier::ImportSpecifier(specifier) = specifier else { + return false; }; + specifier.import_kind == ImportOrExportKind::Value + && specifier.local.name == "defineConfig" + && module_export_name_is_define_config(&specifier.imported) + }) + }) + }) +} - if import_decl.source.value != "vite-plus" || !imported_define_config { - return true; - } - } - } +fn module_export_name_is_define_config(name: &ModuleExportName<'_>) -> bool { + match name { + ModuleExportName::IdentifierName(id) => id.name == "defineConfig", + ModuleExportName::IdentifierReference(id) => id.name == "defineConfig", + ModuleExportName::StringLiteral(lit) => lit.value == "defineConfig", } - - false } /// Count `return` statements recursively in a slice of statements. @@ -681,7 +572,7 @@ mod tests { } #[test] - fn plain_export_default_object_ignores_unrelated_define_config_binding() { + fn plain_export_default_object_ignores_unrelated_define_config_import() { let result = parse( r" import { defineConfig } from 'vite'; @@ -730,77 +621,10 @@ mod tests { } #[test] - fn define_config_namespace_import_is_non_static() { - let result = parse( - r" - import * as defineConfig from './define-config'; - export default defineConfig({ - run: { cacheScripts: true }, - }); - ", - ); - assert_non_static(&result, "run"); - } - - #[test] - fn define_config_import_after_default_export_is_non_static() { - let result = parse( - r" - export default defineConfig({ - run: { cacheScripts: true }, - }); - import { defineConfig } from './define-config'; - ", - ); - assert_non_static(&result, "run"); - } - - #[test] - fn define_config_defined_as_variable() { - let result = parse( - r" - const { defineConfig } = {}; - export default defineConfig({ - run: { cacheScripts: true }, - }); - ", - ); - assert_non_static(&result, "run"); - } - - #[test] - fn define_config_defined_as_exported_variable_is_non_static() { - let result = parse( - r" - export const defineConfig = (config) => config; - export default defineConfig({ - run: { cacheScripts: true }, - }); - ", - ); - assert_non_static(&result, "run"); - } - - #[test] - fn define_config_variable_after_default_export_does_not_block_static_extraction() { - let result = parse( - r" - export default defineConfig({ - run: { cacheScripts: true }, - }); - const defineConfig = () => ({ run: { cacheScripts: false } }); - ", - ); - assert_json(&result, "run", serde_json::json!({ "cacheScripts": true })); - } - - #[test] - fn define_config_defined_as_function_is_non_static() { + fn define_config_type_import_from_vite_plus_is_non_static() { let result = parse( r" - function defineConfig() { - return { run: { cacheScripts: false } }; - } + import type { defineConfig } from 'vite-plus'; export default defineConfig({ run: { cacheScripts: true }, }); @@ -809,20 +633,6 @@ mod tests { assert_non_static(&result, "run"); } - #[test] - fn define_config_import_equals_is_non_static() { - let result = parse_js_ts_config( - r#" - import defineConfig = require("./define-config"); - export default defineConfig({ - run: { cacheScripts: true }, - }); - "#, - "cts", - ); - assert_non_static(&result, "run"); - } - // ── module.exports = { ... } ─────────────────────────────────────── #[test] @@ -832,7 +642,7 @@ mod tests { } #[test] - fn module_exports_define_config() { + fn module_exports_define_config_without_import_is_non_static() { let result = parse_js_ts_config( r" const { defineConfig } = require('vite-plus'); @@ -842,7 +652,7 @@ mod tests { ", "cjs", ); - assert_json(&result, "run", serde_json::json!({ "cacheScripts": true })); + assert_non_static(&result, "run"); } #[test] @@ -855,17 +665,6 @@ mod tests { assert_non_static(&parse_js_ts_config("module.exports = otherFn({ a: 1 });", "cjs"), "run"); } - #[test] - fn module_exports_untrusted_define_config_import() { - assert_non_static( - &parse_js_ts_config( - "const defineConfig = require('config-preset'); module.exports = defineConfig({ run: {} });", - "cjs", - ), - "run", - ); - } - // ── Primitive values ──────────────────────────────────────────────── #[test] @@ -1226,6 +1025,8 @@ mod tests { fn define_config_arrow_block_body() { let result = parse( r" + import { defineConfig } from 'vite-plus'; + export default defineConfig(({ mode }) => { const env = loadEnv(mode, process.cwd(), ''); return { @@ -1243,6 +1044,8 @@ mod tests { fn define_config_arrow_expression_body() { let result = parse( r" + import { defineConfig } from 'vite-plus'; + export default defineConfig(() => ({ run: { cacheScripts: true }, build: { outDir: 'dist' }, @@ -1257,6 +1060,8 @@ mod tests { fn define_config_function_expression() { let result = parse( r" + import { defineConfig } from 'vite-plus'; + export default defineConfig(function() { return { run: { cacheScripts: true }, From 3d2fc136cc70dc212c39431885354d4f0ac00a97 Mon Sep 17 00:00:00 2001 From: Liang Mi Date: Mon, 6 Jul 2026 12:35:32 +0800 Subject: [PATCH 8/9] wip --- crates/vite_static_config/src/lib.rs | 87 ++++++++++++++++++++++++---- 1 file changed, 76 insertions(+), 11 deletions(-) diff --git a/crates/vite_static_config/src/lib.rs b/crates/vite_static_config/src/lib.rs index bc456f1e4b..a345e51925 100644 --- a/crates/vite_static_config/src/lib.rs +++ b/crates/vite_static_config/src/lib.rs @@ -6,8 +6,8 @@ use oxc_allocator::Allocator; use oxc_ast::ast::{ - Expression, ImportDeclarationSpecifier, ImportOrExportKind, ModuleExportName, - ObjectPropertyKind, Program, Statement, + BindingPattern, Expression, ImportDeclarationSpecifier, ImportOrExportKind, ModuleExportName, + ObjectPropertyKind, Program, Statement, VariableDeclarationKind, }; use oxc_parser::Parser; use oxc_span::SourceType; @@ -142,18 +142,22 @@ fn parse_js_ts_config(source: &str, extension: &str) -> FieldMap { /// Find the config object in a parsed program and extract its fields. /// /// Searches for the config value in the following patterns (in order): -/// 1. `export default defineConfig({ ... })` with `defineConfig` imported from `vite-plus` +/// 1. `export default defineConfig({ ... })` with `defineConfig` trusted from `vite-plus` /// 2. `export default { ... }` -/// 3. `module.exports = defineConfig({ ... })` with `defineConfig` imported from `vite-plus` +/// 3. `module.exports = defineConfig({ ... })` with `defineConfig` trusted from `vite-plus` /// 4. `module.exports = { ... }` fn extract_config_fields(program: &Program<'_>) -> FieldMap { - let has_trusted_define_config_import = has_trusted_define_config_import(program); + let mut has_trusted_define_config_binding = has_trusted_define_config_import(program); for stmt in &program.body { + if has_trusted_define_config_cjs_binding(stmt) { + has_trusted_define_config_binding = true; + } + // ESM: export default ... if let Statement::ExportDefaultDeclaration(decl) = stmt { if let Some(expr) = decl.declaration.as_expression() { - return extract_config_from_expr(expr, has_trusted_define_config_import); + return extract_config_from_expr(expr, has_trusted_define_config_binding); } // export default class/function — not analyzable return FieldMap::unanalyzable(); @@ -166,7 +170,7 @@ fn extract_config_fields(program: &Program<'_>) -> FieldMap { m.object().is_specific_id("module") && m.static_property_name() == Some("exports") }) { - return extract_config_from_expr(&assign.right, has_trusted_define_config_import); + return extract_config_from_expr(&assign.right, has_trusted_define_config_binding); } } @@ -182,7 +186,7 @@ fn extract_config_fields(program: &Program<'_>) -> FieldMap { /// - anything else → not analyzable fn extract_config_from_expr( expr: &Expression<'_>, - has_trusted_define_config_import: bool, + has_trusted_define_config_binding: bool, ) -> FieldMap { let expr = expr.without_parentheses(); match expr { @@ -190,7 +194,7 @@ fn extract_config_from_expr( if !call.callee.is_specific_id("defineConfig") { return FieldMap::unanalyzable(); } - if !has_trusted_define_config_import { + if !has_trusted_define_config_binding { return FieldMap::unanalyzable(); } let Some(first_arg) = call.arguments.first() else { @@ -288,6 +292,53 @@ fn module_export_name_is_define_config(name: &ModuleExportName<'_>) -> bool { } } +fn has_trusted_define_config_cjs_binding(stmt: &Statement<'_>) -> bool { + match stmt { + Statement::VariableDeclaration(decl) => { + decl.kind == VariableDeclarationKind::Const + && decl.declarations.iter().any(|declarator| { + declarator.init.as_ref().is_some_and(|init| match &declarator.id { + BindingPattern::BindingIdentifier(id) => { + id.name == "defineConfig" && is_require_vite_plus_define_config(init) + } + BindingPattern::ObjectPattern(pattern) => { + is_require_vite_plus(init) + && pattern.properties.iter().any(|prop| { + !prop.computed + && prop + .key + .static_name() + .is_some_and(|key| key == "defineConfig") + && matches!( + &prop.value, + BindingPattern::BindingIdentifier(id) + if id.name == "defineConfig" + ) + }) + } + _ => false, + }) + }) + } + _ => false, + } +} + +fn is_require_vite_plus_define_config(expr: &Expression<'_>) -> bool { + expr.without_parentheses().as_member_expression().is_some_and(|member| { + member.static_property_name() == Some("defineConfig") + && is_require_vite_plus(member.object()) + }) +} + +fn is_require_vite_plus(expr: &Expression<'_>) -> bool { + matches!( + expr.without_parentheses(), + Expression::CallExpression(call) + if call.common_js_require().is_some_and(|source| source.value == "vite-plus") + ) +} + /// Count `return` statements recursively in a slice of statements. /// Does not descend into nested function/arrow expressions (they have their own returns). fn count_returns_in_stmts(stmts: &[Statement<'_>]) -> usize { @@ -642,7 +693,7 @@ mod tests { } #[test] - fn module_exports_define_config_without_import_is_non_static() { + fn module_exports_define_config_destructured_require() { let result = parse_js_ts_config( r" const { defineConfig } = require('vite-plus'); @@ -652,7 +703,21 @@ mod tests { ", "cjs", ); - assert_non_static(&result, "run"); + assert_json(&result, "run", serde_json::json!({ "cacheScripts": true })); + } + + #[test] + fn module_exports_define_config_member_require() { + let result = parse_js_ts_config( + r" + const defineConfig = require('vite-plus').defineConfig; + module.exports = defineConfig({ + run: { cacheScripts: true }, + }); + ", + "cjs", + ); + assert_json(&result, "run", serde_json::json!({ "cacheScripts": true })); } #[test] From 4e5a3cbae9f299b9123eb22e7b94e223d6b22e62 Mon Sep 17 00:00:00 2001 From: MK Date: Mon, 6 Jul 2026 14:44:06 +0800 Subject: [PATCH 9/9] refactor(static_config): simplify trusted defineConfig detection - Reuse oxc's ModuleExportName::name() instead of the hand-rolled three-variant matcher. - Collapse the eager import scan plus interleaved mutable flag into a single immutable pass over the program body. - Extract the duplicated "vite-plus" / "defineConfig" literals into named constants. --- crates/vite_static_config/src/lib.rs | 71 +++++++++++++--------------- 1 file changed, 32 insertions(+), 39 deletions(-) diff --git a/crates/vite_static_config/src/lib.rs b/crates/vite_static_config/src/lib.rs index a345e51925..cb7cca623d 100644 --- a/crates/vite_static_config/src/lib.rs +++ b/crates/vite_static_config/src/lib.rs @@ -6,14 +6,19 @@ use oxc_allocator::Allocator; use oxc_ast::ast::{ - BindingPattern, Expression, ImportDeclarationSpecifier, ImportOrExportKind, ModuleExportName, - ObjectPropertyKind, Program, Statement, VariableDeclarationKind, + BindingPattern, Expression, ImportDeclarationSpecifier, ImportOrExportKind, ObjectPropertyKind, + Program, Statement, VariableDeclarationKind, }; use oxc_parser::Parser; use oxc_span::SourceType; use rustc_hash::FxHashMap; use vite_path::AbsolutePath; +/// The package that exports the `defineConfig` helper static extraction trusts. +const VITE_PLUS_PACKAGE: &str = "vite-plus"; +/// The name of the config helper static extraction trusts. +const DEFINE_CONFIG: &str = "defineConfig"; + /// The result of statically analyzing a single config field's value. #[derive(Debug, Clone, PartialEq, Eq)] pub enum FieldValue { @@ -147,13 +152,11 @@ fn parse_js_ts_config(source: &str, extension: &str) -> FieldMap { /// 3. `module.exports = defineConfig({ ... })` with `defineConfig` trusted from `vite-plus` /// 4. `module.exports = { ... }` fn extract_config_fields(program: &Program<'_>) -> FieldMap { - let mut has_trusted_define_config_binding = has_trusted_define_config_import(program); + let has_trusted_define_config_binding = program.body.iter().any(|stmt| { + is_trusted_define_config_import(stmt) || has_trusted_define_config_cjs_binding(stmt) + }); for stmt in &program.body { - if has_trusted_define_config_cjs_binding(stmt) { - has_trusted_define_config_binding = true; - } - // ESM: export default ... if let Statement::ExportDefaultDeclaration(decl) = stmt { if let Some(expr) = decl.declaration.as_expression() { @@ -261,37 +264,27 @@ fn extract_config_from_function_body(body: &oxc_ast::ast::FunctionBody<'_>) -> F FieldMap::unanalyzable() } -fn has_trusted_define_config_import(program: &Program<'_>) -> bool { - program.body.iter().any(|stmt| { - let Statement::ImportDeclaration(import_decl) = stmt else { - return false; - }; - if import_decl.import_kind != ImportOrExportKind::Value - || import_decl.source.value != "vite-plus" - { - return false; - } - import_decl.specifiers.as_ref().is_some_and(|specifiers| { - specifiers.iter().any(|specifier| { - let ImportDeclarationSpecifier::ImportSpecifier(specifier) = specifier else { - return false; - }; - specifier.import_kind == ImportOrExportKind::Value - && specifier.local.name == "defineConfig" - && module_export_name_is_define_config(&specifier.imported) - }) +fn is_trusted_define_config_import(stmt: &Statement<'_>) -> bool { + let Statement::ImportDeclaration(import_decl) = stmt else { + return false; + }; + if import_decl.import_kind != ImportOrExportKind::Value + || import_decl.source.value != VITE_PLUS_PACKAGE + { + return false; + } + import_decl.specifiers.as_ref().is_some_and(|specifiers| { + specifiers.iter().any(|specifier| { + let ImportDeclarationSpecifier::ImportSpecifier(specifier) = specifier else { + return false; + }; + specifier.import_kind == ImportOrExportKind::Value + && specifier.local.name == DEFINE_CONFIG + && specifier.imported.name() == DEFINE_CONFIG }) }) } -fn module_export_name_is_define_config(name: &ModuleExportName<'_>) -> bool { - match name { - ModuleExportName::IdentifierName(id) => id.name == "defineConfig", - ModuleExportName::IdentifierReference(id) => id.name == "defineConfig", - ModuleExportName::StringLiteral(lit) => lit.value == "defineConfig", - } -} - fn has_trusted_define_config_cjs_binding(stmt: &Statement<'_>) -> bool { match stmt { Statement::VariableDeclaration(decl) => { @@ -299,7 +292,7 @@ fn has_trusted_define_config_cjs_binding(stmt: &Statement<'_>) -> bool { && decl.declarations.iter().any(|declarator| { declarator.init.as_ref().is_some_and(|init| match &declarator.id { BindingPattern::BindingIdentifier(id) => { - id.name == "defineConfig" && is_require_vite_plus_define_config(init) + id.name == DEFINE_CONFIG && is_require_vite_plus_define_config(init) } BindingPattern::ObjectPattern(pattern) => { is_require_vite_plus(init) @@ -308,11 +301,11 @@ fn has_trusted_define_config_cjs_binding(stmt: &Statement<'_>) -> bool { && prop .key .static_name() - .is_some_and(|key| key == "defineConfig") + .is_some_and(|key| key == DEFINE_CONFIG) && matches!( &prop.value, BindingPattern::BindingIdentifier(id) - if id.name == "defineConfig" + if id.name == DEFINE_CONFIG ) }) } @@ -326,7 +319,7 @@ fn has_trusted_define_config_cjs_binding(stmt: &Statement<'_>) -> bool { fn is_require_vite_plus_define_config(expr: &Expression<'_>) -> bool { expr.without_parentheses().as_member_expression().is_some_and(|member| { - member.static_property_name() == Some("defineConfig") + member.static_property_name() == Some(DEFINE_CONFIG) && is_require_vite_plus(member.object()) }) } @@ -335,7 +328,7 @@ fn is_require_vite_plus(expr: &Expression<'_>) -> bool { matches!( expr.without_parentheses(), Expression::CallExpression(call) - if call.common_js_require().is_some_and(|source| source.value == "vite-plus") + if call.common_js_require().is_some_and(|source| source.value == VITE_PLUS_PACKAGE) ) }