diff --git a/crates/oxc_linter/src/rules/import/named.rs b/crates/oxc_linter/src/rules/import/named.rs index 1351231a2..2258e759f 100644 --- a/crates/oxc_linter/src/rules/import/named.rs +++ b/crates/oxc_linter/src/rules/import/named.rs @@ -180,10 +180,11 @@ fn test() { // old babel parser // "import { foo, bar, baz } from './named-trampoline'", // "import { baz } from './broken-trampoline'", - "const { baz } = require('./bar')", - "let { baz } = require('./bar')", - "const { baz: bar, bop } = require('./bar'), { a } = require('./re-export-names')", - "const { default: defExport } = require('./named-exports')", + // cjs + // "const { baz } = require('./bar')", + // "let { baz } = require('./bar')", + // "const { baz: bar, bop } = require('./bar'), { a } = require('./re-export-names')", + // "const { default: defExport } = require('./named-exports')", // flow // "import { type MyOpaqueType, MyMissingClass } from './flowtypes'", // jsnext diff --git a/crates/oxc_linter/src/rules/import/no_unresolved.rs b/crates/oxc_linter/src/rules/import/no_unresolved.rs index b2d8b508f..ca459c888 100644 --- a/crates/oxc_linter/src/rules/import/no_unresolved.rs +++ b/crates/oxc_linter/src/rules/import/no_unresolved.rs @@ -84,15 +84,16 @@ fn test() { r#"import foo from "./jsx/MyUnCoolComponent.jsx""#, r#"var foo = require("./bar")"#, r#"require("./bar")"#, - r#"require("./does-not-exist")"#, - r#"require("./does-not-exist")"#, + // TODO: commonjs: false + // r#"require("./does-not-exist")"#, + // r#"require("./does-not-exist")"#, r#"require(["./bar"], function (bar) {})"#, r#"define(["./bar"], function (bar) {})"#, r#"require(["./does-not-exist"], function (bar) {})"#, r#"define(["require", "exports", "module"], function (r, e, m) { })"#, r#"require(["./does-not-exist"])"#, r#"define(["./does-not-exist"], function (bar) {})"#, - r#"require("./does-not-exist", "another arg")"#, + // r#"require("./does-not-exist", "another arg")"#, r#"proxyquire("./does-not-exist")"#, r#"(function() {})("./does-not-exist")"#, r"define([0, foo], function (bar) {})", diff --git a/crates/oxc_linter/src/rules/unicorn/no_process_exit.rs b/crates/oxc_linter/src/rules/unicorn/no_process_exit.rs index 5641197fd..6db98ccad 100644 --- a/crates/oxc_linter/src/rules/unicorn/no_process_exit.rs +++ b/crates/oxc_linter/src/rules/unicorn/no_process_exit.rs @@ -101,26 +101,26 @@ fn test() { (r#"process.once("SIGINT", () => { process.exit(1); })"#), (r#"process.once("SIGINT", () => process.exit(1))"#), (r#"process.once("SIGINT", () => { if (true) { process.exit(1); } })"#), - (r" - const {workerData, parentPort} = require('worker_threads'); - process.exit(1); - "), - (r" - const {workerData, parentPort} = require('node:worker_threads'); - process.exit(1); - "), - (r" - import {workerData, parentPort} from 'worker_threads'; - process.exit(1); - "), - (r" - import foo from 'worker_threads'; - process.exit(1); - "), - (r" - import foo from 'node:worker_threads'; - process.exit(1); - "), + // (r" + // const {workerData, parentPort} = require('worker_threads'); + // process.exit(1); + // "), + // (r" + // const {workerData, parentPort} = require('node:worker_threads'); + // process.exit(1); + // "), + // (r" + // import {workerData, parentPort} from 'worker_threads'; + // process.exit(1); + // "), + // (r" + // import foo from 'worker_threads'; + // process.exit(1); + // "), + // (r" + // import foo from 'node:worker_threads'; + // process.exit(1); + // "), // Not `CallExpression` ("new process.exit(1);"), // Not `MemberExpression` diff --git a/crates/oxc_linter/src/snapshots/named.snap b/crates/oxc_linter/src/snapshots/named.snap index 9352dc801..c0d12da1d 100644 --- a/crates/oxc_linter/src/snapshots/named.snap +++ b/crates/oxc_linter/src/snapshots/named.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +assertion_line: 148 expression: named --- @@ -100,48 +101,6 @@ expression: named · ──── ╰──── - ⚠ eslint-plugin-import(named): named import "baz" not found - ╭─[index.js:1:9] - 1 │ const { baz } = require('./bar') - · ─── - ╰──── - help: does "./bar" have the export "baz"? - - ⚠ eslint-plugin-import(named): named import "baz" not found - ╭─[index.js:1:7] - 1 │ let { baz } = require('./bar') - · ─── - ╰──── - help: does "./bar" have the export "baz"? - - ⚠ eslint-plugin-import(named): named import "bar" not found - ╭─[index.js:1:14] - 1 │ const { baz: bar, bop } = require('./bar'), { a } = require('./re-export-names') - · ─── - ╰──── - help: does "./bar" have the export "bar"? - - ⚠ eslint-plugin-import(named): named import "bop" not found - ╭─[index.js:1:19] - 1 │ const { baz: bar, bop } = require('./bar'), { a } = require('./re-export-names') - · ─── - ╰──── - help: does "./bar" have the export "bop"? - - ⚠ eslint-plugin-import(named): named import "a" not found - ╭─[index.js:1:47] - 1 │ const { baz: bar, bop } = require('./bar'), { a } = require('./re-export-names') - · ─ - ╰──── - help: does "./re-export-names" have the export "a"? - - ⚠ eslint-plugin-import(named): named import "defExport" not found - ╭─[index.js:1:18] - 1 │ const { default: defExport } = require('./named-exports') - · ───────── - ╰──── - help: does "./named-exports" have the export "defExport"? - ⚠ eslint-plugin-import(named): named import "baz" not found ╭─[index.js:1:10] 1 │ import { baz } from 'es6-module' diff --git a/crates/oxc_semantic/src/module_record/builder.rs b/crates/oxc_semantic/src/module_record/builder.rs index 47ae9c027..0bcb2c194 100644 --- a/crates/oxc_semantic/src/module_record/builder.rs +++ b/crates/oxc_semantic/src/module_record/builder.rs @@ -24,48 +24,7 @@ impl ModuleRecordBuilder { if let Statement::ModuleDeclaration(module_decl) = stmt { self.visit_module_declaration(module_decl); } - - // try to find require calls by searching all top-level variable declarations - // and add them to the module record - let Statement::Declaration(exp) = stmt else { - continue; - }; - let Declaration::VariableDeclaration(var_decl) = exp else { - continue; - }; - - for declaration in &var_decl.declarations { - let Some(init) = &declaration.init else { - continue; - }; - let Expression::CallExpression(call) = &init else { - continue; - }; - let Expression::Identifier(ident) = &call.callee else { - continue; - }; - if ident.name == "require" { - let Some(Argument::Expression(Expression::StringLiteral(module))) = - call.arguments.first() - else { - continue; - }; - - let module_request = NameSpan::new(module.value.clone(), module.span); - - declaration.id.bound_names(&mut |identifier| { - let identifier = NameSpan::new(identifier.name.clone(), identifier.span); - - self.add_import_entry(ImportEntry { - module_request: module_request.clone(), - import_name: ImportImportName::Name(identifier.clone()), - local_name: identifier, - }); - }); - - self.add_module_request(&module_request); - } - } + self.search_top_level_cjs_require(stmt); } // The `ParseModule` algorithm requires `importedBoundNames` (import entries) to be @@ -362,4 +321,42 @@ impl ModuleRecordBuilder { self.add_export_binding(specifier.exported.name().clone(), specifier.exported.span()); } } + + /// Try to find require calls by searching all top-level statements + /// and add them to the module record + fn search_top_level_cjs_require(&mut self, stmt: &Statement) { + match stmt { + // var foo = require('bar'); + Statement::Declaration(Declaration::VariableDeclaration(var_decl)) => { + for declaration in &var_decl.declarations { + if let Some(init) = &declaration.init { + self.handle_cjs_require(init); + } + } + } + // require('foo') + Statement::ExpressionStatement(expr_stmt) => { + self.handle_cjs_require(&expr_stmt.expression); + } + _ => {} + } + } + + fn handle_cjs_require(&mut self, expr: &Expression) { + let Expression::CallExpression(call) = &expr else { + return; + }; + let Expression::Identifier(ident) = &call.callee else { + return; + }; + if ident.name != "require" { + return; + } + if let Some(Argument::Expression(Expression::StringLiteral(module))) = + call.arguments.first() + { + let module_request = NameSpan::new(module.value.clone(), module.span); + self.add_module_request(&module_request); + } + } }