Skip to content

feat(noImpliedEval): flag new Function(...)#9811

Merged
dyc3 merged 1 commit intomainfrom
dyc3/noImpliedEval-rule-sources
Apr 7, 2026
Merged

feat(noImpliedEval): flag new Function(...)#9811
dyc3 merged 1 commit intomainfrom
dyc3/noImpliedEval-rule-sources

Conversation

@dyc3
Copy link
Copy Markdown
Contributor

@dyc3 dyc3 commented Apr 5, 2026

Summary

This extends noImpliedEval to cover the functionality of https://eslint.org/docs/latest/rules/no-new-func

The functionality of no-new-func is a subset of no-implied-eval (at least for the typescript-eslint version of the rule), so it makes sense to add it as a rule source.

I also took the chance to make the rule recommended. This has no effect on end users because nursery rules can't be activated when using recommended rules.

Test Plan

CI should be green

Docs

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Apr 5, 2026

🦋 Changeset detected

Latest commit: 1e5108c

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 13 packages
Name Type
@biomejs/biome Patch
@biomejs/cli-win32-x64 Patch
@biomejs/cli-win32-arm64 Patch
@biomejs/cli-darwin-x64 Patch
@biomejs/cli-darwin-arm64 Patch
@biomejs/cli-linux-x64 Patch
@biomejs/cli-linux-arm64 Patch
@biomejs/cli-linux-x64-musl Patch
@biomejs/cli-linux-arm64-musl Patch
@biomejs/wasm-web Patch
@biomejs/wasm-bundler Patch
@biomejs/wasm-nodejs Patch
@biomejs/backend-jsonrpc Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions github-actions Bot added A-CLI Area: CLI A-Linter Area: linter L-JavaScript Language: JavaScript and super languages labels Apr 5, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 5, 2026

Walkthrough

A Changeset is added to publish a patch for @biomejs/biome. The NoImpliedEval lint now analyses both call and new expressions, detects Function constructor usages in direct and indirect invocation patterns, records typed internal state for diagnostics (NoImpliedEvalState), and its metadata includes an additional ESLint mapping for no-new-func; the rule’s recommended flag was changed to true.

Possibly related PRs

  • feat(linter): add noImpliedEval rule #8838: Direct modification of the same no_implied_eval lint implementation adding Function-constructor handling, no-new-func source mapping and changing recommendation status.

Suggested labels

A-Diagnostic

Suggested reviewers

  • ematipico
  • Netail
🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The PR title accurately describes the main change: extending noImpliedEval to flag new Function(...) usages, which is the primary objective.
Description check ✅ Passed The description clearly relates to the changeset, explaining the motivation (covering ESLint's no-new-func), implementation rationale, and expected testing approach.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch dyc3/noImpliedEval-rule-sources

Warning

Review ran into problems

🔥 Problems

Git: Failed to clone repository. Please run the @coderabbitai full review command to re-trigger a full review. If the issue persists, set path_filters to include or exclude specific files.


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
.changeset/tidy-shirts-cut.md (1)

5-5: Changeset text is a bit maintainer-facing

Line 5 reads like internal metadata. Please rephrase it in user-impact terms and include the recommended: true change so release notes are clearer.

Possible wording
-Updated the metadata for `noImpliedEval` to include `no-new-func` as a rule source.
+Updated `noImpliedEval` to recognise ESLint's `no-new-func` during migration, and marked the rule as recommended (applies when using unstable nursery rules).

As per coding guidelines, ".changeset/*.md: Write changeset descriptions for end users, not developers."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.changeset/tidy-shirts-cut.md at line 5, Update the changeset description so
it speaks to end users: replace the maintainer-facing metadata mention of
"noImpliedEval" and "no-new-func as a rule source" with a user-facing sentence
explaining the change (e.g., "Add no-new-func as a source for noImpliedEval rule
to improve detection of new Function() and eval-like usage") and add the
recommended: true flag to the changeset metadata so the release notes clearly
state this rule is recommended.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@crates/biome_js_analyze/src/lint/nursery/no_implied_eval.rs`:
- Around line 80-83: The mapping claims coverage of ESLint's "no-new-func" but
this rule (in no_implied_eval.rs) only inspects
setTimeout/setInterval/setImmediate calls, so either remove
RuleSource::Eslint("no-new-func").inspired() from the list or extend the lint to
detect Function constructor usage; to fix, either delete the
RuleSource::Eslint("no-new-func").inspired() entry in the rule's sources array,
or add AST checks in the no_implied_eval lint for NewExpression and
CallExpression nodes whose callee is an Identifier named "Function" (and also
handle possible MemberExpression cases if needed) and emit the same diagnostic
so the rule truly covers Function(...) / new Function(...).

---

Nitpick comments:
In @.changeset/tidy-shirts-cut.md:
- Line 5: Update the changeset description so it speaks to end users: replace
the maintainer-facing metadata mention of "noImpliedEval" and "no-new-func as a
rule source" with a user-facing sentence explaining the change (e.g., "Add
no-new-func as a source for noImpliedEval rule to improve detection of new
Function() and eval-like usage") and add the recommended: true flag to the
changeset metadata so the release notes clearly state this rule is recommended.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 4a449b4e-bdcf-4ba9-8b6d-61317bdb253f

📥 Commits

Reviewing files that changed from the base of the PR and between 1d09f0f and 627d0b1.

⛔ Files ignored due to path filters (1)
  • crates/biome_cli/src/execute/migrate/eslint_any_rule_to_biome.rs is excluded by !**/migrate/eslint_any_rule_to_biome.rs and included by **
📒 Files selected for processing (2)
  • .changeset/tidy-shirts-cut.md
  • crates/biome_js_analyze/src/lint/nursery/no_implied_eval.rs

Comment thread crates/biome_js_analyze/src/lint/nursery/no_implied_eval.rs
@codspeed-hq
Copy link
Copy Markdown

codspeed-hq Bot commented Apr 5, 2026

Merging this PR will not alter performance

✅ 58 untouched benchmarks
⏩ 196 skipped benchmarks1


Comparing dyc3/noImpliedEval-rule-sources (1e5108c) with main (1d09f0f)

Open in CodSpeed

Footnotes

  1. 196 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@dyc3 dyc3 marked this pull request as draft April 5, 2026 17:30
@dyc3 dyc3 changed the title fix(migrate): add no-new-func as a rule source for noImpliedEval wip: feat(noImpliedEval): flag new Function(...) Apr 5, 2026
@dyc3 dyc3 force-pushed the dyc3/noImpliedEval-rule-sources branch 2 times, most recently from b2c221d to ef02635 Compare April 5, 2026 18:18
@dyc3 dyc3 changed the title wip: feat(noImpliedEval): flag new Function(...) feat(noImpliedEval): flag new Function(...) Apr 5, 2026
@dyc3 dyc3 marked this pull request as ready for review April 5, 2026 18:28
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@crates/biome_js_analyze/src/lint/nursery/no_implied_eval.rs`:
- Around line 107-130: The string-argument branch currently runs for both
JsNewExpression and JsCallExpression (because Query is JsNewOrCallExpression)
causing false positives for constructs like new setTimeout("..."); restrict that
branch to call expressions only: after resolving node (in run) verify the node
is a call expression (e.g., via node.as_call_expression() /
node.is_call_expression() or pattern-match the JsNewOrCallExpression into a
JsCallExpression) before checking args and calling is_string_argument, and only
return Some(NoImpliedEvalState::StringArgument) when the node is a call
expression.

In `@crates/biome_js_analyze/tests/specs/nursery/noImpliedEval/valid.js`:
- Around line 68-79: The file has two top-level declarations named Function (a
class at the top and a later function), causing a syntax error; split them into
separate scopes so both shadowing cases are valid—e.g., wrap one of the
top-level cases in its own block or IIFE (or move the later function into the
existing nestedClass or another function scope) so the class declaration `class
Function {}` and the function declaration `function Function() {}` are not in
the same top-level scope; ensure the `new Function()` calls remain in scope that
sees the intended shadowed binding so the rule tests still exercise both
shadowing scenarios.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 5cdf02e4-33a5-47d2-82d8-7d6a8527595b

📥 Commits

Reviewing files that changed from the base of the PR and between 627d0b1 and ef02635.

⛔ Files ignored due to path filters (3)
  • crates/biome_cli/src/execute/migrate/eslint_any_rule_to_biome.rs is excluded by !**/migrate/eslint_any_rule_to_biome.rs and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noImpliedEval/invalid.js.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noImpliedEval/valid.js.snap is excluded by !**/*.snap and included by **
📒 Files selected for processing (4)
  • .changeset/tidy-shirts-cut.md
  • crates/biome_js_analyze/src/lint/nursery/no_implied_eval.rs
  • crates/biome_js_analyze/tests/specs/nursery/noImpliedEval/invalid.js
  • crates/biome_js_analyze/tests/specs/nursery/noImpliedEval/valid.js
✅ Files skipped from review due to trivial changes (1)
  • .changeset/tidy-shirts-cut.md

Comment thread crates/biome_js_analyze/src/lint/nursery/no_implied_eval.rs
Comment thread crates/biome_js_analyze/tests/specs/nursery/noImpliedEval/valid.js
Copy link
Copy Markdown
Member

@ematipico ematipico left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changeset needs more love

expression: &AnyJsExpression,
model: &biome_js_semantic::SemanticModel,
) -> bool {
let Some((reference, name)) = global_identifier(&expression.clone().omit_parentheses()) else {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function already removes the parentheses, no need to do it here

Comment thread .changeset/tidy-shirts-cut.md Outdated
Comment thread crates/biome_js_analyze/src/lint/nursery/no_implied_eval.rs
@dyc3 dyc3 force-pushed the dyc3/noImpliedEval-rule-sources branch from ef02635 to 1e5108c Compare April 7, 2026 12:10
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
crates/biome_js_analyze/src/lint/nursery/no_implied_eval.rs (1)

218-227: Remove unnecessary .clone() call.

expression is already &AnyJsExpression, so the clone is redundant here.

♻️ Proposed fix
 fn is_global_function_constructor(
     expression: &AnyJsExpression,
     model: &biome_js_semantic::SemanticModel,
 ) -> bool {
-    let Some((reference, name)) = global_identifier(&expression.clone()) else {
+    let Some((reference, name)) = global_identifier(expression) else {
         return false;
     };
 
     name.text() == "Function" && model.binding(&reference).is_none()
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/biome_js_analyze/src/lint/nursery/no_implied_eval.rs` around lines 218
- 227, The .clone() on expression is unnecessary; in
is_global_function_constructor call global_identifier with the existing
reference rather than cloning—replace global_identifier(&expression.clone())
with global_identifier(expression) (referencing the function
is_global_function_constructor, the parameter expression, and the
global_identifier call).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@crates/biome_js_analyze/src/lint/nursery/no_implied_eval.rs`:
- Around line 218-227: The .clone() on expression is unnecessary; in
is_global_function_constructor call global_identifier with the existing
reference rather than cloning—replace global_identifier(&expression.clone())
with global_identifier(expression) (referencing the function
is_global_function_constructor, the parameter expression, and the
global_identifier call).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 869f746f-4c5e-40c5-b330-16b3d1142f5f

📥 Commits

Reviewing files that changed from the base of the PR and between ef02635 and 1e5108c.

⛔ Files ignored due to path filters (3)
  • crates/biome_cli/src/execute/migrate/eslint_any_rule_to_biome.rs is excluded by !**/migrate/eslint_any_rule_to_biome.rs and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noImpliedEval/invalid.js.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noImpliedEval/valid.js.snap is excluded by !**/*.snap and included by **
📒 Files selected for processing (4)
  • .changeset/tidy-shirts-cut.md
  • crates/biome_js_analyze/src/lint/nursery/no_implied_eval.rs
  • crates/biome_js_analyze/tests/specs/nursery/noImpliedEval/invalid.js
  • crates/biome_js_analyze/tests/specs/nursery/noImpliedEval/valid.js
✅ Files skipped from review due to trivial changes (1)
  • .changeset/tidy-shirts-cut.md
🚧 Files skipped from review as they are similar to previous changes (2)
  • crates/biome_js_analyze/tests/specs/nursery/noImpliedEval/invalid.js
  • crates/biome_js_analyze/tests/specs/nursery/noImpliedEval/valid.js

@dyc3 dyc3 merged commit 2dddca3 into main Apr 7, 2026
19 checks passed
@dyc3 dyc3 deleted the dyc3/noImpliedEval-rule-sources branch April 7, 2026 12:40
@github-actions github-actions Bot mentioned this pull request Apr 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-CLI Area: CLI A-Linter Area: linter L-JavaScript Language: JavaScript and super languages

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants