mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 04:08:41 +00:00
feat(linter): handle top-level require for import plugin (#2491)
This commit is contained in:
parent
04f4621ed8
commit
d0a9c465f7
5 changed files with 69 additions and 111 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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) {})",
|
||||
|
|
|
|||
|
|
@ -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`
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue