mirror of
https://github.com/aphrody-labs/oxc.git
synced 2026-10-15 06:39:17 +00:00
feat(parser): distinguish unapplied no-side-effects comments (#26120)
## Summary Fixes #26088 `NO_SIDE_EFFECTS` can either be applied to a function: ```rs /* #__NO_SIDE_EFFECTS__ */ function foo() {} ``` Or be meaningless for its position, since it only works on function declaration: ```rs /* #__NO_SIDE_EFFECTS__ */ value; ``` But oxc could not distinguish these two cases. This PR adds `CommentContent::NoSideEffectsNotApplied`, mirroring the existing `PureNotApplied`. --------- Co-authored-by: Cameron <cameron.clark@hey.com>
This commit is contained in:
1 parent
5f9cffc753
commit
bfb4c57a5d
8 files changed
+161
-61
No files matched your search
@@ -78,37 +78,40 @@ pub enum CommentContent {
|
||||
/// `/* #__NO_SIDE_EFFECTS__ */`
|
||||
NoSideEffects = 6,
|
||||
|
||||
/// `/* #__NO_SIDE_EFFECTS__ */` that could not be applied to a function
|
||||
NoSideEffectsNotApplied = 7,
|
||||
|
||||
/// Webpack magic comment
|
||||
/// e.g. `/* webpackChunkName */`
|
||||
/// <https://webpack.js.org/api/module-methods/#magic-comments>
|
||||
Webpack = 7,
|
||||
Webpack = 8,
|
||||
|
||||
/// Vite comment
|
||||
/// e.g. `/* @vite-ignore */`
|
||||
/// <https://github.com/search?q=repo%3Avitejs%2Fvite%20vite-ignore&type=code>
|
||||
Vite = 8,
|
||||
Vite = 9,
|
||||
|
||||
/// Code Coverage Ignore
|
||||
/// `v8 ignore`, `c8 ignore`, `node:coverage`, `istanbul ignore`
|
||||
/// <https://github.com/oxc-project/oxc/issues/10091>
|
||||
CoverageIgnore = 9,
|
||||
CoverageIgnore = 10,
|
||||
|
||||
/// Turbopack magic comment
|
||||
/// e.g. `/* turbopackOptional: true */`
|
||||
/// <https://nextjs.org/docs/app/guides/lazy-loading#turbopackoptional-turbopack-only>
|
||||
Turbopack = 10,
|
||||
Turbopack = 11,
|
||||
|
||||
/// File-level code coverage ignore.
|
||||
///
|
||||
/// `v8 ignore file`, `istanbul ignore file`.
|
||||
/// Classified separately because its meaning remains valid if the next AST
|
||||
/// node is removed, unlike position-sensitive coverage annotations.
|
||||
CoverageIgnoreFile = 11,
|
||||
CoverageIgnoreFile = 12,
|
||||
|
||||
/// Marks the following string or no-substitution template as a property name.
|
||||
/// `/* @__KEY__ */` or `/* #__KEY__ */`
|
||||
/// <https://esbuild.github.io/api/#mangle-key>
|
||||
PropertyKey = 12,
|
||||
PropertyKey = 13,
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
|
||||
@@ -508,13 +508,12 @@ fn pure_comment() {
|
||||
test_same(
|
||||
"/* #__PURE__ -- @preserve */ pureOperation();\n", // rolldown#9408
|
||||
);
|
||||
// A `@__NO_SIDE_EFFECTS__` comment sharing the call site's `attached_to`
|
||||
// must not be emitted in place of the pure-call annotation. Without the
|
||||
// kind filter, `FxHashMap` last-write-wins would print the wrong
|
||||
// annotation kind in front of a CallExpression.
|
||||
// A misplaced `@__NO_SIDE_EFFECTS__` comment sharing the call site's `attached_to`
|
||||
// must be preserved for downstream consumers to warn about, without replacing the
|
||||
// valid pure-call annotation.
|
||||
test(
|
||||
"/* @__PURE__ */ /* @__NO_SIDE_EFFECTS__ */ pureOperation();\n",
|
||||
"/* @__PURE__ */ pureOperation();\n",
|
||||
"/* @__NO_SIDE_EFFECTS__ */ /* @__PURE__ */ pureOperation();\n",
|
||||
);
|
||||
test("const foo /* #__PURE__ */ = pureOperation();", "const foo = pureOperation();\n"); // INVALID: "=" not allowed after annotation
|
||||
|
||||
|
||||
@@ -155,11 +155,11 @@ export default function() {}
|
||||
/* #__NO_SIDE_EFFECTS__ */ export const c2 = () => {}, c3 = () => {}
|
||||
|
||||
----------
|
||||
export var v0 = function() {}, v1 = function() {};
|
||||
export let l0 = function() {}, l1 = function() {};
|
||||
/* #__NO_SIDE_EFFECTS__ */ export var v0 = function() {}, v1 = function() {};
|
||||
/* #__NO_SIDE_EFFECTS__ */ export let l0 = function() {}, l1 = function() {};
|
||||
export const c0 = /* @__NO_SIDE_EFFECTS__ */ function() {}, c1 = function() {};
|
||||
export var v2 = () => {}, v3 = () => {};
|
||||
export let l2 = () => {}, l3 = () => {};
|
||||
/* #__NO_SIDE_EFFECTS__ */ export var v2 = () => {}, v3 = () => {};
|
||||
/* #__NO_SIDE_EFFECTS__ */ export let l2 = () => {}, l3 = () => {};
|
||||
export const c2 = /* @__NO_SIDE_EFFECTS__ */ () => {}, c3 = () => {};
|
||||
|
||||
########## 8
|
||||
@@ -172,11 +172,11 @@ export const c2 = /* @__NO_SIDE_EFFECTS__ */ () => {}, c3 = () => {};
|
||||
/* #__NO_SIDE_EFFECTS__ */ const c2 = () => {}, c3 = () => {}
|
||||
|
||||
----------
|
||||
var v0 = function() {}, v1 = function() {};
|
||||
let l0 = function() {}, l1 = function() {};
|
||||
/* #__NO_SIDE_EFFECTS__ */ var v0 = function() {}, v1 = function() {};
|
||||
/* #__NO_SIDE_EFFECTS__ */ let l0 = function() {}, l1 = function() {};
|
||||
const c0 = /* @__NO_SIDE_EFFECTS__ */ function() {}, c1 = function() {};
|
||||
var v2 = () => {}, v3 = () => {};
|
||||
let l2 = () => {}, l3 = () => {};
|
||||
/* #__NO_SIDE_EFFECTS__ */ var v2 = () => {}, v3 = () => {};
|
||||
/* #__NO_SIDE_EFFECTS__ */ let l2 = () => {}, l3 = () => {};
|
||||
const c2 = /* @__NO_SIDE_EFFECTS__ */ () => {}, c3 = () => {};
|
||||
|
||||
########## 9
|
||||
|
||||
@@ -272,8 +272,8 @@ impl<'a, C: Config> ParserImpl<'a, C> {
|
||||
let start = self.cur_start();
|
||||
let opening_span = self.cur_token().span();
|
||||
// Capture annotation flags before bumping `(` since bump resets them
|
||||
let has_no_side_effects_comment =
|
||||
self.lexer.trivia_builder.previous_token_has_no_side_effects_comment();
|
||||
let no_side_effects_comments =
|
||||
self.lexer.trivia_builder.previous_token_no_side_effects_comments();
|
||||
self.bump_any(); // `bump` `(`
|
||||
let expr_start = self.cur_start();
|
||||
let (mut expressions, comma_start) = self.context(Context::In, Context::Decorator, |p| {
|
||||
@@ -312,14 +312,16 @@ impl<'a, C: Config> ParserImpl<'a, C> {
|
||||
match &mut expression {
|
||||
Expression::ArrowFunctionExpression(arrow_expr) => {
|
||||
arrow_expr.pife = true;
|
||||
if has_no_side_effects_comment {
|
||||
if let Some(comments) = no_side_effects_comments {
|
||||
arrow_expr.pure = true;
|
||||
self.lexer.trivia_builder.mark_no_side_effects_comments_applied(comments);
|
||||
}
|
||||
}
|
||||
Expression::FunctionExpression(func_expr) => {
|
||||
func_expr.pife = true;
|
||||
if has_no_side_effects_comment {
|
||||
if let Some(comments) = no_side_effects_comments {
|
||||
func_expr.pure = true;
|
||||
self.lexer.trivia_builder.mark_no_side_effects_comments_applied(comments);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
@@ -1489,8 +1491,8 @@ impl<'a, C: Config> ParserImpl<'a, C> {
|
||||
&mut self,
|
||||
allow_return_type_in_arrow_function: bool,
|
||||
) -> Expression<'a> {
|
||||
let has_no_side_effects_comment =
|
||||
self.lexer.trivia_builder.previous_token_has_no_side_effects_comment();
|
||||
let no_side_effects_comments =
|
||||
self.lexer.trivia_builder.previous_token_no_side_effects_comments();
|
||||
// [+Yield] YieldExpression
|
||||
if self.is_yield_expression() {
|
||||
return self.parse_yield_expression();
|
||||
@@ -1499,10 +1501,11 @@ impl<'a, C: Config> ParserImpl<'a, C> {
|
||||
if let Some(mut arrow_expr) = self
|
||||
.try_parse_parenthesized_arrow_function_expression(allow_return_type_in_arrow_function)
|
||||
{
|
||||
if has_no_side_effects_comment
|
||||
if let Some(comments) = no_side_effects_comments
|
||||
&& let Expression::ArrowFunctionExpression(func) = &mut arrow_expr
|
||||
{
|
||||
func.pure = true;
|
||||
self.lexer.trivia_builder.mark_no_side_effects_comments_applied(comments);
|
||||
}
|
||||
return arrow_expr;
|
||||
}
|
||||
@@ -1510,10 +1513,11 @@ impl<'a, C: Config> ParserImpl<'a, C> {
|
||||
if let Some(mut arrow_expr) = self
|
||||
.try_parse_async_simple_arrow_function_expression(allow_return_type_in_arrow_function)
|
||||
{
|
||||
if has_no_side_effects_comment
|
||||
if let Some(comments) = no_side_effects_comments
|
||||
&& let Expression::ArrowFunctionExpression(func) = &mut arrow_expr
|
||||
{
|
||||
func.pure = true;
|
||||
self.lexer.trivia_builder.mark_no_side_effects_comments_applied(comments);
|
||||
}
|
||||
return arrow_expr;
|
||||
}
|
||||
@@ -1534,10 +1538,11 @@ impl<'a, C: Config> ParserImpl<'a, C> {
|
||||
/* async */ false,
|
||||
allow_return_type_in_arrow_function,
|
||||
);
|
||||
if has_no_side_effects_comment
|
||||
if let Some(comments) = no_side_effects_comments
|
||||
&& let Expression::ArrowFunctionExpression(func) = &mut arrow_expr
|
||||
{
|
||||
func.pure = true;
|
||||
self.lexer.trivia_builder.mark_no_side_effects_comments_applied(comments);
|
||||
}
|
||||
return arrow_expr;
|
||||
}
|
||||
@@ -1554,8 +1559,10 @@ impl<'a, C: Config> ParserImpl<'a, C> {
|
||||
let mut expr =
|
||||
self.parse_conditional_expression_rest(start, lhs, allow_return_type_in_arrow_function);
|
||||
|
||||
if has_no_side_effects_comment {
|
||||
Self::set_pure_on_function_expr(&mut expr);
|
||||
if let Some(comments) = no_side_effects_comments
|
||||
&& Self::set_pure_on_function_expr(&mut expr)
|
||||
{
|
||||
self.lexer.trivia_builder.mark_no_side_effects_comments_applied(comments);
|
||||
}
|
||||
|
||||
expr
|
||||
@@ -1592,15 +1599,17 @@ impl<'a, C: Config> ParserImpl<'a, C> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn set_pure_on_function_expr(expr: &mut Expression<'a>) {
|
||||
pub(crate) fn set_pure_on_function_expr(expr: &mut Expression<'a>) -> bool {
|
||||
match expr {
|
||||
Expression::FunctionExpression(func) => {
|
||||
func.pure = true;
|
||||
true
|
||||
}
|
||||
Expression::ArrowFunctionExpression(func) => {
|
||||
func.pure = true;
|
||||
true
|
||||
}
|
||||
_ => {}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -677,8 +677,8 @@ impl<'a, C: Config> ParserImpl<'a, C> {
|
||||
let decl_start = self.cur_start();
|
||||
|
||||
// export default /* @__NO_SIDE_EFFECTS__ */ ...
|
||||
let has_no_side_effects_comment =
|
||||
self.lexer.trivia_builder.previous_token_has_no_side_effects_comment();
|
||||
let no_side_effects_comments =
|
||||
self.lexer.trivia_builder.previous_token_no_side_effects_comments();
|
||||
|
||||
// export default @decorator ...
|
||||
if self.at(Kind::At) {
|
||||
@@ -729,8 +729,9 @@ impl<'a, C: Config> ParserImpl<'a, C> {
|
||||
/* r#async */ true,
|
||||
FunctionKind::DefaultExport,
|
||||
);
|
||||
if has_no_side_effects_comment {
|
||||
if let Some(comments) = no_side_effects_comments {
|
||||
func.pure = true;
|
||||
self.lexer.trivia_builder.mark_no_side_effects_comments_applied(comments);
|
||||
}
|
||||
return ExportDefaultDeclarationKind::FunctionDeclaration(func);
|
||||
}
|
||||
@@ -771,8 +772,9 @@ impl<'a, C: Config> ParserImpl<'a, C> {
|
||||
/* r#async */ false,
|
||||
FunctionKind::DefaultExport,
|
||||
);
|
||||
if has_no_side_effects_comment {
|
||||
if let Some(comments) = no_side_effects_comments {
|
||||
func.pure = true;
|
||||
self.lexer.trivia_builder.mark_no_side_effects_comments_applied(comments);
|
||||
}
|
||||
return ExportDefaultDeclarationKind::FunctionDeclaration(func);
|
||||
}
|
||||
|
||||
@@ -132,8 +132,8 @@ impl<'a, C: Config> ParserImpl<'a, C> {
|
||||
&mut self,
|
||||
stmt_ctx: StatementContext,
|
||||
) -> Statement<'a> {
|
||||
let has_no_side_effects_comment =
|
||||
self.lexer.trivia_builder.previous_token_has_no_side_effects_comment();
|
||||
let no_side_effects_comments =
|
||||
self.lexer.trivia_builder.previous_token_no_side_effects_comments();
|
||||
|
||||
let mut stmt = match self.cur_kind() {
|
||||
Kind::LCurly => self.parse_block_statement(),
|
||||
@@ -195,46 +195,56 @@ impl<'a, C: Config> ParserImpl<'a, C> {
|
||||
_ => self.parse_expression_or_labeled_statement(),
|
||||
};
|
||||
|
||||
if has_no_side_effects_comment {
|
||||
Self::set_pure_on_function_stmt(&mut stmt);
|
||||
if let Some(comments) = no_side_effects_comments
|
||||
&& Self::set_pure_on_function_stmt(&mut stmt)
|
||||
{
|
||||
self.lexer.trivia_builder.mark_no_side_effects_comments_applied(comments);
|
||||
}
|
||||
|
||||
stmt
|
||||
}
|
||||
|
||||
fn set_pure_on_function_stmt(stmt: &mut Statement<'a>) {
|
||||
fn set_pure_on_function_stmt(stmt: &mut Statement<'a>) -> bool {
|
||||
match stmt {
|
||||
Statement::FunctionDeclaration(func) => {
|
||||
func.pure = true;
|
||||
true
|
||||
}
|
||||
Statement::ExportDefaultDeclaration(decl) => match &mut decl.declaration {
|
||||
ExportDefaultDeclarationKind::FunctionExpression(func)
|
||||
| ExportDefaultDeclarationKind::FunctionDeclaration(func) => {
|
||||
func.pure = true;
|
||||
true
|
||||
}
|
||||
ExportDefaultDeclarationKind::ArrowFunctionExpression(func) => {
|
||||
func.pure = true;
|
||||
true
|
||||
}
|
||||
_ => {}
|
||||
_ => false,
|
||||
},
|
||||
Statement::ExportDeclaration(decl) => match &mut decl.declaration {
|
||||
Declaration::FunctionDeclaration(func) => {
|
||||
func.pure = true;
|
||||
true
|
||||
}
|
||||
Declaration::VariableDeclaration(var_decl) if var_decl.kind.is_const() => {
|
||||
if let Some(Some(expr)) = var_decl.declarations.first_mut().map(|d| &mut d.init)
|
||||
{
|
||||
Self::set_pure_on_function_expr(expr);
|
||||
Self::set_pure_on_function_expr(expr)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => false,
|
||||
},
|
||||
Statement::VariableDeclaration(var_decl) if var_decl.kind.is_const() => {
|
||||
if let Some(Some(expr)) = var_decl.declarations.first_mut().map(|d| &mut d.init) {
|
||||
Self::set_pure_on_function_expr(expr);
|
||||
Self::set_pure_on_function_expr(expr)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ pub struct LexerCheckpoint<'a> {
|
||||
errors_snapshot: ErrorSnapshot<'a>,
|
||||
tokens_len: usize,
|
||||
pure_comments: Option<(usize, usize)>,
|
||||
has_no_side_effects_comment: bool,
|
||||
no_side_effects_comments: Option<(usize, usize)>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -199,7 +199,7 @@ impl<'a, C: Config> Lexer<'a, C> {
|
||||
errors_snapshot,
|
||||
tokens_len: self.tokens.len(),
|
||||
pure_comments: self.trivia_builder.previous_token_pure_comments(),
|
||||
has_no_side_effects_comment: self.trivia_builder.has_no_side_effects_comment,
|
||||
no_side_effects_comments: self.trivia_builder.previous_token_no_side_effects_comments(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -217,7 +217,7 @@ impl<'a, C: Config> Lexer<'a, C> {
|
||||
errors_snapshot,
|
||||
tokens_len: self.tokens.len(),
|
||||
pure_comments: self.trivia_builder.previous_token_pure_comments(),
|
||||
has_no_side_effects_comment: self.trivia_builder.has_no_side_effects_comment,
|
||||
no_side_effects_comments: self.trivia_builder.previous_token_no_side_effects_comments(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -232,7 +232,7 @@ impl<'a, C: Config> Lexer<'a, C> {
|
||||
self.source.set_position(checkpoint.source_position);
|
||||
self.token = checkpoint.token;
|
||||
self.trivia_builder.set_pure_comments(checkpoint.pure_comments);
|
||||
self.trivia_builder.has_no_side_effects_comment = checkpoint.has_no_side_effects_comment;
|
||||
self.trivia_builder.set_no_side_effects_comments(checkpoint.no_side_effects_comments);
|
||||
}
|
||||
|
||||
pub fn peek_token(&mut self) -> Token {
|
||||
@@ -483,7 +483,7 @@ impl<'a, C: Config> Lexer<'a, C> {
|
||||
#[inline] // Make sure is inlined into `next_token`
|
||||
fn read_next_token(&mut self) -> Kind {
|
||||
self.trivia_builder.clear_pure_comments();
|
||||
self.trivia_builder.has_no_side_effects_comment = false;
|
||||
self.trivia_builder.clear_no_side_effects_comments();
|
||||
|
||||
let end_pos = self.source.end();
|
||||
loop {
|
||||
@@ -551,7 +551,7 @@ impl<'a, C: Config> Lexer<'a, C> {
|
||||
#[inline]
|
||||
fn read_next_jsx_attribute_value(&mut self) -> Kind {
|
||||
self.trivia_builder.clear_pure_comments();
|
||||
self.trivia_builder.has_no_side_effects_comment = false;
|
||||
self.trivia_builder.clear_no_side_effects_comments();
|
||||
|
||||
let end_pos = self.source.end();
|
||||
loop {
|
||||
|
||||
@@ -32,7 +32,8 @@ pub struct TriviaBuilder<'a> {
|
||||
/// Range of comments preceding the current token that contains pure comments.
|
||||
pure_comments: Option<(usize, usize)>,
|
||||
|
||||
pub(super) has_no_side_effects_comment: bool,
|
||||
/// Range of comments preceding the current token that contains no-side-effects comments.
|
||||
no_side_effects_comments: Option<(usize, usize)>,
|
||||
}
|
||||
|
||||
impl<'a> TriviaBuilder<'a> {
|
||||
@@ -47,7 +48,7 @@ impl<'a> TriviaBuilder<'a> {
|
||||
saw_newline_for_comment: true,
|
||||
previous_token,
|
||||
pure_comments: None,
|
||||
has_no_side_effects_comment: false,
|
||||
no_side_effects_comments: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,8 +56,8 @@ impl<'a> TriviaBuilder<'a> {
|
||||
self.pure_comments
|
||||
}
|
||||
|
||||
pub fn previous_token_has_no_side_effects_comment(&self) -> bool {
|
||||
self.has_no_side_effects_comment
|
||||
pub fn previous_token_no_side_effects_comments(&self) -> Option<(usize, usize)> {
|
||||
self.no_side_effects_comments
|
||||
}
|
||||
|
||||
pub(super) fn set_pure_comments(&mut self, pure_comments: Option<(usize, usize)>) {
|
||||
@@ -67,6 +68,14 @@ impl<'a> TriviaBuilder<'a> {
|
||||
self.pure_comments = None;
|
||||
}
|
||||
|
||||
pub(super) fn set_no_side_effects_comments(&mut self, comments: Option<(usize, usize)>) {
|
||||
self.no_side_effects_comments = comments;
|
||||
}
|
||||
|
||||
pub(super) fn clear_no_side_effects_comments(&mut self) {
|
||||
self.no_side_effects_comments = None;
|
||||
}
|
||||
|
||||
pub fn mark_pure_comments_applied(&mut self, (start, end): (usize, usize)) {
|
||||
for comment in &mut self.comments[start..end] {
|
||||
if comment.content == CommentContent::PureNotApplied {
|
||||
@@ -75,6 +84,14 @@ impl<'a> TriviaBuilder<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mark_no_side_effects_comments_applied(&mut self, (start, end): (usize, usize)) {
|
||||
for comment in &mut self.comments[start..end] {
|
||||
if comment.content == CommentContent::NoSideEffectsNotApplied {
|
||||
comment.content = CommentContent::NoSideEffects;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_irregular_whitespace(&mut self, start: u32, end: u32) {
|
||||
// The irregular whitespaces array is ordered; only add if not added before, to avoid
|
||||
// duplicates when the parser looks ahead (e.g. `peek_token`) and rewinds, then re-lexes the
|
||||
@@ -249,6 +266,7 @@ impl<'a> TriviaBuilder<'a> {
|
||||
| CommentContent::Pure
|
||||
| CommentContent::PureNotApplied
|
||||
| CommentContent::NoSideEffects
|
||||
| CommentContent::NoSideEffectsNotApplied
|
||||
| CommentContent::PropertyKey
|
||||
)
|
||||
}
|
||||
@@ -261,8 +279,12 @@ impl<'a> TriviaBuilder<'a> {
|
||||
} else {
|
||||
self.pure_comments = Some((index, index + 1));
|
||||
}
|
||||
} else if comment.is_no_side_effects() {
|
||||
self.has_no_side_effects_comment = true;
|
||||
} else if comment.content == CommentContent::NoSideEffectsNotApplied {
|
||||
if let Some((_, end)) = &mut self.no_side_effects_comments {
|
||||
*end = index + 1;
|
||||
} else {
|
||||
self.no_side_effects_comments = Some((index, index + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,7 +467,7 @@ impl<'a> TriviaBuilder<'a> {
|
||||
comment.content = CommentContent::PureNotApplied;
|
||||
return;
|
||||
} else if rest.starts_with(b"NO_SIDE_EFFECTS__") {
|
||||
comment.content = CommentContent::NoSideEffects;
|
||||
comment.content = CommentContent::NoSideEffectsNotApplied;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1017,6 +1039,61 @@ function bar() {}";
|
||||
assert_eq!(comments[1].content, CommentContent::Pure, "second comment should remain Pure");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_side_effects_comment_not_applied() {
|
||||
let cases = [
|
||||
"/* #__NO_SIDE_EFFECTS__ */",
|
||||
"/* @__NO_SIDE_EFFECTS__ */ assert.ok(true);",
|
||||
"/* #__NO_SIDE_EFFECTS__ */ const foo = 1, bar = () => {};",
|
||||
"/* #__NO_SIDE_EFFECTS__ */ class Foo {}",
|
||||
"/* #__NO_SIDE_EFFECTS__ */ let foo = () => {};",
|
||||
"/* #__NO_SIDE_EFFECTS__ */ var foo = function() {};",
|
||||
"const foo /* #__NO_SIDE_EFFECTS__ */ = () => {};",
|
||||
];
|
||||
for source_text in cases {
|
||||
let comments = get_comments(source_text);
|
||||
assert_eq!(
|
||||
comments[0].content,
|
||||
CommentContent::NoSideEffectsNotApplied,
|
||||
"{source_text}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_side_effects_comment_applied() {
|
||||
let cases = [
|
||||
"/* #__NO_SIDE_EFFECTS__ */ function foo() {}",
|
||||
"/* #__NO_SIDE_EFFECTS__ */ async function foo() {}",
|
||||
"/* #__NO_SIDE_EFFECTS__ */ export function foo() {}",
|
||||
"export default /* #__NO_SIDE_EFFECTS__ */ function foo() {}",
|
||||
"const foo = /* #__NO_SIDE_EFFECTS__ */ function() {};",
|
||||
"const foo = /* #__NO_SIDE_EFFECTS__ */ () => {};",
|
||||
"/* #__NO_SIDE_EFFECTS__ */ const foo = () => {};",
|
||||
"/* #__NO_SIDE_EFFECTS__ */ export const foo = () => {};",
|
||||
"[/* #__NO_SIDE_EFFECTS__ */ function() {}];",
|
||||
];
|
||||
for source_text in cases {
|
||||
let comments = get_comments(source_text);
|
||||
assert_eq!(comments[0].content, CommentContent::NoSideEffects, "{source_text}");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_side_effects_comments_are_applied_independently() {
|
||||
let source_text = concat!(
|
||||
"/*#__NO_SIDE_EFFECTS__*/ value;",
|
||||
"/*#__NO_SIDE_EFFECTS__*/ /* comment */ /*@__NO_SIDE_EFFECTS__*/ function foo() {}",
|
||||
);
|
||||
let comments = get_comments(source_text);
|
||||
|
||||
assert_eq!(comments.len(), 4);
|
||||
assert_eq!(comments[0].content, CommentContent::NoSideEffectsNotApplied);
|
||||
assert_eq!(comments[1].content, CommentContent::NoSideEffects);
|
||||
assert_eq!(comments[2].content, CommentContent::None);
|
||||
assert_eq!(comments[3].content, CommentContent::NoSideEffects);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn comment_parsing() {
|
||||
let data = [
|
||||
@@ -1052,9 +1129,9 @@ function bar() {}";
|
||||
("/* webpackChunkName: 'my-chunk-name' */", CommentContent::Webpack),
|
||||
("/* webpack */", CommentContent::None),
|
||||
("/* @__PURE__ */", CommentContent::PureNotApplied),
|
||||
("/* @__NO_SIDE_EFFECTS__ */", CommentContent::NoSideEffects),
|
||||
("/* @__NO_SIDE_EFFECTS__ */", CommentContent::NoSideEffectsNotApplied),
|
||||
("/* #__PURE__ */", CommentContent::PureNotApplied),
|
||||
("/* #__NO_SIDE_EFFECTS__ */", CommentContent::NoSideEffects),
|
||||
("/* #__NO_SIDE_EFFECTS__ */", CommentContent::NoSideEffectsNotApplied),
|
||||
("/* @__KEY__ */", CommentContent::PropertyKey),
|
||||
("/* #__KEY__ */", CommentContent::PropertyKey),
|
||||
("/*\u{a0}@__KEY__\u{a0}*/", CommentContent::PropertyKey),
|
||||
|
||||
Reference in new issue
Block a user