From 989ab88bc66a4a1f150f35421f8b09a888f3ae8b Mon Sep 17 00:00:00 2001 From: underfin <2218301630@qq.com> Date: Thu, 25 Jan 2024 15:24:05 +0800 Subject: [PATCH] fix(codegen): print `Directive` original string (#2157) > A Use Strict Directive may not contain an EscapeSequence or LineContinuation. It is `Use Strict Directive` spec, but the `expression` of `Directive` isn't original string value, it has error if using it to codegen, so here using `directive` of `Directive` to codegen and not to escape it. Here is crashed test cases. ``` js 'use str\ ict'; ``` The babel will print the original string, I follow it and avoid using `print_str` because it will escape string. I also changed some code using the `expression` of `Directive` to check `Use Strict Directive` . --- crates/oxc_codegen/src/gen.rs | 9 +++++++-- .../src/rules/nextjs/no_async_client_component.rs | 6 +----- crates/oxc_prettier/src/format/mod.rs | 2 +- crates/oxc_semantic/src/checker/javascript.rs | 2 +- tasks/coverage/codegen_runtime_test262.snap | 10 ++-------- tasks/transform_conformance/babel.snap.md | 7 +++++-- 6 files changed, 17 insertions(+), 19 deletions(-) diff --git a/crates/oxc_codegen/src/gen.rs b/crates/oxc_codegen/src/gen.rs index 89bc9d72ddd7c..88652f205780d 100644 --- a/crates/oxc_codegen/src/gen.rs +++ b/crates/oxc_codegen/src/gen.rs @@ -92,8 +92,13 @@ impl Gen for Hashbang { impl Gen for Directive { fn gen(&self, p: &mut Codegen<{ MINIFY }>, _ctx: Context) { - // Use the string value instead of the raw self.directive because it can cannot escaped values. - print_str(self.expression.value.as_str(), p); + // A Use Strict Directive may not contain an EscapeSequence or LineContinuation. + // So here should print original `directive` value, the `expression` value is escaped str. + // See https://github.com/babel/babel/blob/main/packages/babel-generator/src/generators/base.ts#L64 + let quote = choose_quote(self.directive.as_str()); + p.print(quote as u8); + p.print_str(self.directive.as_bytes()); + p.print(quote as u8); p.print_semicolon(); } } diff --git a/crates/oxc_linter/src/rules/nextjs/no_async_client_component.rs b/crates/oxc_linter/src/rules/nextjs/no_async_client_component.rs index 126cb43fa5954..c328a3133d9e9 100644 --- a/crates/oxc_linter/src/rules/nextjs/no_async_client_component.rs +++ b/crates/oxc_linter/src/rules/nextjs/no_async_client_component.rs @@ -43,11 +43,7 @@ impl Rule for NoAsyncClientComponent { let Some(root) = ctx.nodes().iter().next() else { return }; let AstKind::Program(program) = root.kind() else { return }; - if program - .directives - .iter() - .any(|directive| directive.expression.value.as_str() == "use client") - { + if program.directives.iter().any(|directive| directive.directive.as_str() == "use client") { for node in &program.body { let Statement::ModuleDeclaration(mod_decl) = &node else { continue; diff --git a/crates/oxc_prettier/src/format/mod.rs b/crates/oxc_prettier/src/format/mod.rs index 43fcb5295ce3c..3863d4430ce43 100644 --- a/crates/oxc_prettier/src/format/mod.rs +++ b/crates/oxc_prettier/src/format/mod.rs @@ -87,7 +87,7 @@ impl<'a> Format<'a> for Directive { let mut parts = p.vec(); parts.push(Doc::Str(string::print_string( p, - self.expression.value.as_str(), + self.directive.as_str(), p.options.single_quote, ))); if let Some(semi) = p.semi() { diff --git a/crates/oxc_semantic/src/checker/javascript.rs b/crates/oxc_semantic/src/checker/javascript.rs index 723e9a7c40df1..af6d4e7dd38ba 100644 --- a/crates/oxc_semantic/src/checker/javascript.rs +++ b/crates/oxc_semantic/src/checker/javascript.rs @@ -393,7 +393,7 @@ fn check_directive<'a>(directive: &Directive, node: &AstNode<'a>, ctx: &Semantic #[diagnostic()] struct IllegalUseStrict(#[label] Span); - if directive.expression.value != "use strict" { + if directive.directive != "use strict" { return; } diff --git a/tasks/coverage/codegen_runtime_test262.snap b/tasks/coverage/codegen_runtime_test262.snap index 20fcc82de5375..8ffc6e735f1f9 100644 --- a/tasks/coverage/codegen_runtime_test262.snap +++ b/tasks/coverage/codegen_runtime_test262.snap @@ -1,6 +1,6 @@ codegen_runtime_test262 Summary: -AST Parsed : 19663/19663 (100.00%) -Positive Passed: 19219/19663 (97.74%) +AST Parsed : 19665/19665 (100.00%) +Positive Passed: 19220/19665 (97.74%) Expect to run correctly: "annexB/built-ins/String/prototype/substr/surrogate-pairs.js" But got a runtime error: Test262Error: start: 1 Expected SameValue(«�», «\udf06») to be true @@ -131,12 +131,6 @@ But got a runtime error: Test262Error: descriptor should be enumerable Expect to run correctly: "annexB/language/global-code/switch-dflt-global-init.js" But got a runtime error: Test262Error: descriptor should be enumerable -Expect to run correctly: "language/directive-prologue/14.1-4-s.js" -But got a runtime error: Test262Error: Expected true but got false - -Expect to run correctly: "language/directive-prologue/14.1-5-s.js" -But got a runtime error: Test262Error: Expected true but got false - Expect to run correctly: "language/eval-code/direct/async-gen-func-decl-fn-body-cntns-arguments-func-decl-declare-arguments-and-assign.js" But got a runtime error: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all diff --git a/tasks/transform_conformance/babel.snap.md b/tasks/transform_conformance/babel.snap.md index c787b2bb8f781..ee7a6cd46a3c1 100644 --- a/tasks/transform_conformance/babel.snap.md +++ b/tasks/transform_conformance/babel.snap.md @@ -1,9 +1,8 @@ -Passed: 329/1369 +Passed: 327/1369 # All Passed: * babel-plugin-transform-numeric-separator * babel-plugin-transform-optional-catch-binding -* babel-plugin-transform-json-strings * babel-plugin-transform-shorthand-properties * babel-plugin-transform-sticky-regex * babel-plugin-transform-instanceof @@ -608,6 +607,10 @@ Passed: 329/1369 * transparent-expr-wrappers/ts-as-member-expression/input.ts * transparent-expr-wrappers/ts-parenthesized-expression-member-call/input.ts +# babel-plugin-transform-json-strings (2/4) +* json-strings/directive-line-separator/input.js +* json-strings/directive-paragraph-separator/input.js + # babel-plugin-transform-async-generator-functions (0/22) * async-generators/class-method/input.js * async-generators/class-private-method/input.js