Skip to content

Commit

Permalink
Merge branch 'main' into feat/eslint-no-new-func
Browse files Browse the repository at this point in the history
  • Loading branch information
DonIsaac authored Aug 31, 2024
2 parents a55d24a + 35f03db commit fa1917d
Show file tree
Hide file tree
Showing 45 changed files with 3,061 additions and 2,200 deletions.
1 change: 1 addition & 0 deletions .github/FUNDING.yml
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
github: [Boshen]
open_collective: oxc
6 changes: 3 additions & 3 deletions .github/actions/clone-submodules/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,19 @@ runs:
with:
repository: tc39/test262
path: tasks/coverage/test262
ref: a15874163e6a4f19ee7cd3e47592af382af0f5fd
ref: d62fa93c8f9ce5e687c0bbaa5d2b59670ab2ff60

- uses: actions/checkout@v4
with:
repository: babel/babel
path: tasks/coverage/babel
ref: 12619ffe5b0777edb0223304da1fdf8770d93e7c
ref: 3bcfee232506a4cebe410f02042fb0f0adeeb0b1

- uses: actions/checkout@v4
with:
repository: microsoft/TypeScript
path: tasks/coverage/typescript
ref: d8086f14b6b97c0df34a0cc2f56d4b5926a0c299
ref: a709f9899c2a544b6de65a0f2623ecbbe1394eab

- uses: actions/checkout@v4
with:
Expand Down
14 changes: 0 additions & 14 deletions .github/workflows/auto-labeler.yml

This file was deleted.

24 changes: 24 additions & 0 deletions .github/workflows/pr.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: Check PR

on:
pull_request_target:
types:
- opened
- edited
- synchronize

jobs:
pr:
if: github.repository == 'oxc-project/oxc'
name: Label and Check PR Title
permissions:
contents: read
pull-requests: write
runs-on: ubuntu-latest
steps:
- uses: taiki-e/checkout-action@v1
- uses: actions/labeler@v5
- name: Validate PR title
uses: amannn/action-semantic-pull-request@v5
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
3 changes: 2 additions & 1 deletion crates/oxc_ast/src/ast_builder_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,8 @@ impl<'a> AstBuilder<'a> {

#[inline]
pub fn move_assignment_target(self, target: &mut AssignmentTarget<'a>) -> AssignmentTarget<'a> {
let dummy = self.simple_assignment_target_identifier_reference(Span::default(), "");
let dummy =
self.simple_assignment_target_identifier_reference(Span::default(), Atom::from(""));
mem::replace(target, dummy.into())
}

Expand Down
6 changes: 6 additions & 0 deletions crates/oxc_ast/src/ast_impl/js.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1050,6 +1050,12 @@ impl<'a> Function<'a> {
}
}

/// Returns this [`Function`]'s name, if it has one.
#[inline]
pub fn name(&self) -> Option<Atom<'a>> {
self.id.as_ref().map(|id| id.name.clone())
}

pub fn is_typescript_syntax(&self) -> bool {
matches!(
self.r#type,
Expand Down
14 changes: 7 additions & 7 deletions crates/oxc_isolated_declarations/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -426,11 +426,11 @@ impl<'a> IsolatedDeclarations<'a> {
}
}
Some(Declaration::FunctionDeclaration(func)) => {
if let Some(id) = func.id.as_ref() {
if let Some(name) = func.name() {
assignable_properties_for_namespace
.entry(&ident.name)
.or_default()
.insert(id.name.clone());
.insert(name);
}
}
Some(Declaration::ClassDeclaration(cls)) => {
Expand Down Expand Up @@ -487,17 +487,17 @@ impl<'a> IsolatedDeclarations<'a> {
&decl.declaration
{
if func.body.is_some() {
if let Some(id) = func.id.as_ref() {
can_expando_function_names.insert(id.name.clone());
if let Some(name) = func.name() {
can_expando_function_names.insert(name);
}
}
}
}
Statement::FunctionDeclaration(func) => {
if func.body.is_some() {
if let Some(id) = func.id.as_ref() {
if self.scope.has_reference(&id.name) {
can_expando_function_names.insert(id.name.clone());
if let Some(name) = func.name() {
if self.scope.has_reference(&name) {
can_expando_function_names.insert(name);
}
}
}
Expand Down
28 changes: 9 additions & 19 deletions crates/oxc_linter/src/rules/eslint/func_names.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ enum FuncNamesConfig {

impl FuncNamesConfig {
fn is_invalid_function(self, func: &Function, parent_node: &AstNode<'_>) -> bool {
let func_name = get_function_name(func);
let func_name = func.name();

match self {
Self::Never => func_name.is_some() && func.r#type != FunctionType::FunctionDeclaration,
Expand Down Expand Up @@ -230,13 +230,6 @@ fn get_function_identifier<'a>(func: &'a Function<'a>) -> Option<&'a Span> {
func.id.as_ref().map(|id| &id.span)
}

/**
* Gets the identifier name of the function
*/
fn get_function_name<'f, 'a>(func: &'f Function<'a>) -> Option<&'f Atom<'a>> {
func.id.as_ref().map(|id| &id.name)
}

fn get_property_key_name<'a>(key: &PropertyKey<'a>) -> Option<Cow<'a, str>> {
if matches!(key, PropertyKey::NullLiteral(_)) {
return Some("null".into());
Expand Down Expand Up @@ -342,14 +335,14 @@ fn get_function_name_with_kind<'a>(func: &Function<'a>, parent_node: &AstNode<'a
}
} else if let Some(static_name) = get_static_property_name(parent_node) {
tokens.push(static_name);
} else if let Some(name) = get_function_name(func) {
} else if let Some(name) = func.name() {
tokens.push(Cow::Borrowed(name.as_str()));
}
}
_ => {
if let Some(static_name) = get_static_property_name(parent_node) {
tokens.push(static_name);
} else if let Some(name) = get_function_name(func) {
} else if let Some(name) = func.name() {
tokens.push(Cow::Borrowed(name.as_str()));
}
}
Expand Down Expand Up @@ -399,8 +392,8 @@ impl Rule for FuncNames {
// check at first if the callee calls an invalid function
if !invalid_funcs
.iter()
.filter_map(|(func, _)| get_function_name(func))
.any(|func_name| func_name == &identifier.name)
.filter_map(|(func, _)| func.name())
.any(|func_name| func_name == identifier.name)
{
continue;
}
Expand All @@ -409,11 +402,9 @@ impl Rule for FuncNames {
let ast_span = ctx.nodes().iter_parents(node.id()).skip(1).find_map(|p| {
match p.kind() {
AstKind::Function(func) => {
let func_name = get_function_name(func);

func_name?;
let func_name = func.name()?;

if *func_name.unwrap() == identifier.name {
if func_name == identifier.name {
return Some(func.span);
}

Expand All @@ -434,7 +425,6 @@ impl Rule for FuncNames {
}

for (func, parent_node) in &invalid_funcs {
let func_name = get_function_name(func);
let func_name_complete = get_function_name_with_kind(func, parent_node);

let report_span = Span::new(func.span.start, func.params.span.start);
Expand All @@ -444,10 +434,10 @@ impl Rule for FuncNames {
.as_ref()
.map_or_else(|| func.params.span.start, |tp| tp.span.start),
);
if func_name.is_some() {
if let Some(id) = func.id.as_ref() {
ctx.diagnostic_with_suggestion(
named_diagnostic(&func_name_complete, report_span),
|fixer| func.id.as_ref().map_or(fixer.noop(), |id| fixer.delete(id)),
|fixer| fixer.delete(id),
);
} else {
ctx.diagnostic_with_fix(
Expand Down
4 changes: 1 addition & 3 deletions crates/oxc_linter/src/rules/react/rules_of_hooks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -353,9 +353,7 @@ fn is_somewhere_inside_component_or_hook(nodes: &AstNodes, node_id: AstNodeId) -
(
node.id(),
match node.kind() {
AstKind::Function(func) => {
func.id.as_ref().map(|it| Cow::Borrowed(it.name.as_str()))
}
AstKind::Function(func) => func.name().map(Cow::from),
AstKind::ArrowFunctionExpression(_) => {
get_declaration_identifier(nodes, node.id())
}
Expand Down
60 changes: 57 additions & 3 deletions crates/oxc_linter/src/rules/unicorn/prefer_type_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ declare_oxc_lint!(
/// ```
PreferTypeError,
pedantic,
pending
fix
);

impl Rule for PreferTypeError {
Expand Down Expand Up @@ -82,7 +82,10 @@ impl Rule for PreferTypeError {
};

if is_type_checking_expr(&if_stmt.test) {
ctx.diagnostic(prefer_type_error_diagnostic(new_expr.callee.span()));
ctx.diagnostic_with_fix(
prefer_type_error_diagnostic(new_expr.callee.span()),
|fixer| fixer.replace(new_expr.callee.span(), "TypeError"),
);
}
}
}
Expand Down Expand Up @@ -468,5 +471,56 @@ fn test() {
",
];

Tester::new(PreferTypeError::NAME, pass, fail).test_and_snapshot();
let fix = vec![
(
r"if (!isFinite(foo)) { throw new Error(); }",
r"if (!isFinite(foo)) { throw new TypeError(); }",
),
(
r"if (isNaN(foo) === false) { throw new Error(); }",
r"if (isNaN(foo) === false) { throw new TypeError(); }",
),
(
r"if (Array.isArray(foo)) { throw new Error('foo is an Array'); }",
r"if (Array.isArray(foo)) { throw new TypeError('foo is an Array'); }",
),
(
r"if (foo instanceof bar) { throw new Error(foobar); }",
r"if (foo instanceof bar) { throw new TypeError(foobar); }",
),
(
r"if (_.isElement(foo)) { throw new Error(); }",
r"if (_.isElement(foo)) { throw new TypeError(); }",
),
(
r"if (_.isElement(foo)) { throw new Error; }",
r"if (_.isElement(foo)) { throw new TypeError; }",
),
(
r"if (wrapper._.isElement(foo)) { throw new Error; }",
r"if (wrapper._.isElement(foo)) { throw new TypeError; }",
),
(
r"if (typeof foo == 'Foo' || 'Foo' === typeof foo) { throw new Error(); }",
r"if (typeof foo == 'Foo' || 'Foo' === typeof foo) { throw new TypeError(); }",
),
(
r"if (Number.isFinite(foo) && Number.isSafeInteger(foo) && Number.isInteger(foo)) { throw new Error(); }",
r"if (Number.isFinite(foo) && Number.isSafeInteger(foo) && Number.isInteger(foo)) { throw new TypeError(); }",
),
(
r"if (wrapper.n.isFinite(foo) && wrapper.n.isSafeInteger(foo) && wrapper.n.isInteger(foo)) { throw new Error(); }",
r"if (wrapper.n.isFinite(foo) && wrapper.n.isSafeInteger(foo) && wrapper.n.isInteger(foo)) { throw new TypeError(); }",
),
(
r"if (wrapper.f.g.n.isFinite(foo) && wrapper.g.n.isSafeInteger(foo) && wrapper.n.isInteger(foo)) { throw new Error(); }",
r"if (wrapper.f.g.n.isFinite(foo) && wrapper.g.n.isSafeInteger(foo) && wrapper.n.isInteger(foo)) { throw new TypeError(); }",
),
(
r"if (_.isElement(foo)) { throw (new Error()); }",
r"if (_.isElement(foo)) { throw (new TypeError()); }",
),
];

Tester::new(PreferTypeError::NAME, pass, fail).expect_fix(fix).test_and_snapshot();
}
21 changes: 6 additions & 15 deletions crates/oxc_transformer/examples/transformer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,7 @@ use oxc_codegen::CodeGenerator;
use oxc_parser::Parser;
use oxc_semantic::SemanticBuilder;
use oxc_span::SourceType;
use oxc_transformer::{
ArrowFunctionsOptions, ES2015Options, ReactOptions, TransformOptions, Transformer,
TypeScriptOptions,
};
use oxc_transformer::{EnvOptions, Targets, TransformOptions, Transformer};

// Instruction:
// create a `test.tsx`,
Expand Down Expand Up @@ -37,17 +34,11 @@ fn main() {
println!("{source_text}\n");

let mut program = ret.program;
let transform_options = TransformOptions {
typescript: TypeScriptOptions::default(),
es2015: ES2015Options { arrow_function: Some(ArrowFunctionsOptions::default()) },
react: ReactOptions {
jsx_plugin: true,
jsx_self_plugin: true,
jsx_source_plugin: true,
..Default::default()
},
..Default::default()
};
let transform_options = TransformOptions::from_preset_env(&EnvOptions {
targets: Targets::from_query("chrome 51"),
..EnvOptions::default()
})
.unwrap();

let (symbols, scopes) = SemanticBuilder::new(&source_text, source_type)
.build(&program)
Expand Down
24 changes: 23 additions & 1 deletion crates/oxc_transformer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ use oxc_allocator::{Allocator, Vec};
use oxc_ast::{ast::*, Trivias};
use oxc_diagnostics::OxcDiagnostic;
use oxc_semantic::{ScopeTree, SymbolTable};
use oxc_span::SourceType;
use oxc_span::{SourceType, SPAN};
use oxc_traverse::{traverse_mut, Traverse, TraverseCtx};

pub use crate::{
Expand Down Expand Up @@ -284,6 +284,28 @@ impl<'a> Traverse<'a> for Transformer<'a> {
self.x2_es2016.enter_statements(stmts, ctx);
}

fn exit_arrow_function_expression(
&mut self,
arrow: &mut ArrowFunctionExpression<'a>,
ctx: &mut TraverseCtx<'a>,
) {
// Some plugins may add new statements to the ArrowFunctionExpression's body,
// which can cause issues with the `() => x;` case, as it only allows a single statement.
// To address this, we wrap the last statement in a return statement and set the expression to false.
// This transforms the arrow function into the form `() => { return x; };`.
if arrow.expression && arrow.body.statements.len() > 1 {
let Statement::ExpressionStatement(statement) = arrow.body.statements.pop().unwrap()
else {
unreachable!("The last statement in an ArrowFunctionExpression should always be an ExpressionStatement.")
};
arrow
.body
.statements
.push(ctx.ast.statement_return(SPAN, Some(statement.unbox().expression)));
arrow.expression = false;
}
}

fn exit_statements(&mut self, stmts: &mut Vec<'a, Statement<'a>>, ctx: &mut TraverseCtx<'a>) {
self.x0_typescript.transform_statements_on_exit(stmts, ctx);
self.x1_react.transform_statements_on_exit(stmts, ctx);
Expand Down
6 changes: 3 additions & 3 deletions justfile
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ ready:

# Clone or update submodules
submodules:
just clone-submodule tasks/coverage/test262 [email protected]:tc39/test262.git a15874163e6a4f19ee7cd3e47592af382af0f5fd
just clone-submodule tasks/coverage/babel [email protected]:babel/babel.git 12619ffe5b0777edb0223304da1fdf8770d93e7c
just clone-submodule tasks/coverage/typescript [email protected]:microsoft/TypeScript.git d8086f14b6b97c0df34a0cc2f56d4b5926a0c299
just clone-submodule tasks/coverage/test262 [email protected]:tc39/test262.git d62fa93c8f9ce5e687c0bbaa5d2b59670ab2ff60
just clone-submodule tasks/coverage/babel [email protected]:babel/babel.git 3bcfee232506a4cebe410f02042fb0f0adeeb0b1
just clone-submodule tasks/coverage/typescript [email protected]:microsoft/TypeScript.git a709f9899c2a544b6de65a0f2623ecbbe1394eab
just clone-submodule tasks/prettier_conformance/prettier [email protected]:prettier/prettier.git 7142cf354cce2558f41574f44b967baf11d5b603

# Install git pre-commit to format files
Expand Down
6 changes: 3 additions & 3 deletions tasks/coverage/codegen_babel.snap
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
commit: 12619ffe
commit: 3bcfee23

codegen_babel Summary:
AST Parsed : 2100/2100 (100.00%)
Positive Passed: 2100/2100 (100.00%)
AST Parsed : 2101/2101 (100.00%)
Positive Passed: 2101/2101 (100.00%)
Loading

0 comments on commit fa1917d

Please sign in to comment.