Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
97f5303
fix: init
h-a-n-a Aug 7, 2025
5677ffa
chore: rename
h-a-n-a Aug 8, 2025
926f74a
feat: add `EscapedChar` to represent both char and lone surrogates
h-a-n-a Aug 8, 2025
5efc4d8
fix: fix size assertions
h-a-n-a Aug 8, 2025
b658457
fix: generate code
h-a-n-a Aug 8, 2025
0900cd8
fix: try to fix tests and stuff
h-a-n-a Aug 13, 2025
df556ff
fix(minifier): temporarily disable cocnat str for lone surrogates
h-a-n-a Aug 13, 2025
c317e41
chore: comment
h-a-n-a Aug 13, 2025
c2b23e3
test: fix
h-a-n-a Aug 14, 2025
2a28d73
test: pass more tests
h-a-n-a Aug 14, 2025
ffac6e1
test: fix typing
h-a-n-a Aug 14, 2025
c20d18e
fix: fix more cases
h-a-n-a Aug 14, 2025
cf22343
test: update parser test262 snapshots
h-a-n-a Aug 14, 2025
7d6d27c
chore: comments
h-a-n-a Aug 14, 2025
9e84f9d
test: create test for member expression evaluation
h-a-n-a Aug 15, 2025
a88b269
chore: leave expr_simplifier case for now
h-a-n-a Aug 15, 2025
18356b1
test: fix snapshot of ascii_only_true_identifier_es5
h-a-n-a Aug 18, 2025
cba4caa
test: fix snapshot of crate swc
h-a-n-a Aug 18, 2025
f5320d9
chore: add TODO for template literals
h-a-n-a Aug 18, 2025
4e849c5
feat: support concatenating strs
h-a-n-a Aug 18, 2025
a19e410
feat: support member expr optimization with lone surrogate and surrog…
h-a-n-a Aug 18, 2025
d0917d4
test: update codegen tests and snapshots
h-a-n-a Aug 18, 2025
9b13b31
feat: add back string concatenation in expr simplifier
h-a-n-a Aug 18, 2025
770086e
fix: remove lone surrogate from bindings as it's not upgraded
h-a-n-a Aug 19, 2025
2781365
perf: remove runtime assertion
h-a-n-a Aug 19, 2025
e16a544
feat: support template literal
h-a-n-a Aug 19, 2025
1a8492a
ci: fix
h-a-n-a Aug 19, 2025
f6a4da4
test: fix snapshot
h-a-n-a Aug 20, 2025
fdd8ca6
fix: hoist `pair_to_code_point` to avoid cyclic dep
h-a-n-a Sep 1, 2025
410a397
chore(ecma_minifier): update lib-size snapshot
h-a-n-a Sep 1, 2025
120c4fb
fix: try to fix `binding_core_node` bundle
h-a-n-a Sep 1, 2025
634c47b
Create metal-radios-swim.md
kdy1 Sep 4, 2025
bad060c
chore: restore `decorator-tests`
h-a-n-a Sep 5, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
5 changes: 5 additions & 0 deletions .changeset/metal-radios-swim.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
swc_ecma_ast: major
---

fix(es/ast): Fix unicode lone surrogates handling
1 change: 1 addition & 0 deletions bindings/binding_core_node/src/bundle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,7 @@ impl swc_core::bundler::Hook for Hook {
span,
raw: None,
value: file_name.into(),
lone_surrogates: false,
}))),
},
KeyValueProp {
Expand Down
2 changes: 1 addition & 1 deletion crates/swc/tests/fixture/issues-7xxx/7678/output/1.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
let str="\uD83D\uDC68\\u200D\uD83D\uDE80";let obj={"\uD83D\uDC68\\u200D\uD83D\uDE80":"wrong"};
let str="\\uD83D\\uDC68\\u200D\\uD83D\\uDE80";let obj={"\\uD83D\\uDC68\\u200D\\uD83D\\uDE80":"wrong"};
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
// 2. Let cu1 be floor((cp – 65536) / 1024) + 0xD800.
// Although we should just get back a single code point value of 0xD800,
// this is a useful edge-case test.
var x = "\u{D800}";
var x = "\ud800";
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
// 2. Let cu1 be floor((cp – 65536) / 1024) + 0xD800.
// Although we should just get back a single code point value of 0xD800,
// this is a useful edge-case test.
var x = "\u{D800}";
var x = "\ud800";
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
// 2. Let cu2 be ((cp – 65536) modulo 1024) + 0xDC00.
// Although we should just get back a single code point value of 0xDC00,
// this is a useful edge-case test.
var x = "\u{DC00}";
var x = "\udc00";
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
// 2. Let cu2 be ((cp – 65536) modulo 1024) + 0xDC00.
// Although we should just get back a single code point value of 0xDC00,
// this is a useful edge-case test.
var x = "\u{DC00}";
var x = "\udc00";
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
// 2. Let cu1 be floor((cp – 65536) / 1024) + 0xD800.
// Although we should just get back a single code point value of 0xD800,
// this is a useful edge-case test.
var x = "\u{D800}";
var x = "\ud800";
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
// 2. Let cu2 be ((cp – 65536) modulo 1024) + 0xDC00.
// Although we should just get back a single code point value of 0xDC00,
// this is a useful edge-case test.
var x = "\u{DC00}";
var x = "\udc00";
6 changes: 3 additions & 3 deletions crates/swc/tests/vercel/full/utf8-1/output/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import r from './on-demand-entries-client';
import { addMessageListener as n, connectHMR as c } from './error-overlay/websocket';
var o = JSON.parse(document.getElementById('__NEXT_DATA__').textContent);
window.__NEXT_DATA__ = o;
var s = o.assetPrefix, i = o.page, _ = null, u = __webpack_hash__, d = (s = s || '') + (s.endsWith('/') ? '' : '/') + '_next/static/webpack/';
var s = o.assetPrefix, i = o.page, _ = null, d = __webpack_hash__, u = (s = s || '') + (s.endsWith('/') ? '' : '/') + '_next/static/webpack/';
n(function(a) {
if ('\uD83D\uDC93' !== a.data) try {
var r = JSON.parse(a.data);
Expand All @@ -28,7 +28,7 @@ n(function(a) {
5
]), [
4,
fetch('undefined' != typeof __webpack_runtime_id__ ? "".concat(d).concat(u, ".").concat(__webpack_runtime_id__, ".hot-update.json") : "".concat(d).concat(u, ".hot-update.json"))
fetch('undefined' != typeof __webpack_runtime_id__ ? "".concat(u).concat(d, ".").concat(__webpack_runtime_id__, ".hot-update.json") : "".concat(u).concat(d, ".hot-update.json"))
];
case 2:
return [
Expand All @@ -38,7 +38,7 @@ n(function(a) {
case 3:
return e = t.sent(), a = '/' === i ? 'index' : i, (Array.isArray(e.c) ? e.c : Object.keys(e.c)).some(function(e) {
return -1 !== e.indexOf("pages".concat(a.startsWith('/') ? a : "/".concat(a))) || -1 !== e.indexOf("pages".concat(a.startsWith('/') ? a : "/".concat(a)).replace(/\//g, '\\'));
}) ? document.location.reload(!0) : u = _, [
}) ? document.location.reload(!0) : d = _, [
3,
5
];
Expand Down
1 change: 1 addition & 0 deletions crates/swc_bundler/examples/bundle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ impl swc_bundler::Hook for Hook {
span,
raw: None,
value: file_name.into(),
lone_surrogates: false,
}))),
},
KeyValueProp {
Expand Down
2 changes: 2 additions & 0 deletions crates/swc_bundler/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ pub(crate) trait VarDeclaratorExt: Into<VarDeclarator> {
span: DUMMY_SP,
raw: None,
value: name.into(),
lone_surrogates: false,
}
.assign_to(Ident::new_no_ctxt(atom!("INJECTED_FROM"), DUMMY_SP)),
]
Expand Down Expand Up @@ -193,6 +194,7 @@ fn metadata(key: &str, value: &str) -> PropOrSpread {
span: DUMMY_SP,
value: value.into(),
raw: None,
lone_surrogates: false,
})
.into(),
})))
Expand Down
1 change: 1 addition & 0 deletions crates/swc_bundler/tests/deno.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1120,6 +1120,7 @@ impl swc_bundler::Hook for Hook {
span,
raw: None,
value: file_name.into(),
lone_surrogates: false,
}))),
},
KeyValueProp {
Expand Down
1 change: 1 addition & 0 deletions crates/swc_bundler/tests/fixture.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ impl swc_bundler::Hook for Hook {
span,
raw: None,
value: file_name.into(),
lone_surrogates: false,
}))),
},
KeyValueProp {
Expand Down
12 changes: 12 additions & 0 deletions crates/swc_ecma_ast/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1199,6 +1199,15 @@ pub struct TplElement {
/// You may need to perform. `.replace("\r\n", "\n").replace('\r', "\n")` on
/// this value.
pub raw: Atom,

/// The string value contains lone surrogates.
///
/// `cooked` is encoded with `\u{FFFD}` to mark the lone surrogate as an
/// escaped value.
///
/// For example, a "\uD808" is a lone surrogate, and it's encoded as
/// `\u{FFFD}D808`.
pub lone_surrogates: bool,
}

impl Take for TplElement {
Expand All @@ -1208,6 +1217,7 @@ impl Take for TplElement {
tail: Default::default(),
cooked: None,
raw: Default::default(),
lone_surrogates: false,
}
}
}
Expand All @@ -1219,12 +1229,14 @@ impl<'a> arbitrary::Arbitrary<'a> for TplElement {
let span = u.arbitrary()?;
let cooked = Some(u.arbitrary::<String>()?.into());
let raw = u.arbitrary::<String>()?.into();
let lone_surrogates = u.arbitrary::<bool>()?.into();

Ok(Self {
span,
tail: false,
cooked,
raw,
lone_surrogates,
})
}
}
Expand Down
36 changes: 18 additions & 18 deletions crates/swc_ecma_ast/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -571,7 +571,7 @@ mod rkyv_layout_assert {
assert_size!(ArchivedTaggedTpl, 28);
assert_size!(ArchivedThisExpr, 8);
assert_size!(ArchivedTpl, 24);
assert_size!(ArchivedTplElement, 32);
assert_size!(ArchivedTplElement, 36);
assert_size!(ArchivedUnaryExpr, 16);
assert_size!(ArchivedUpdateExpr, 16);
assert_size!(ArchivedYieldExpr, 20);
Expand Down Expand Up @@ -616,7 +616,7 @@ mod rkyv_layout_assert {
assert_size!(ArchivedNull, 8);
assert_size!(ArchivedNumber, 32);
assert_size!(ArchivedRegex, 24);
assert_size!(ArchivedStr, 28);
assert_size!(ArchivedStr, 32);

// Module declaration types
assert_size!(ArchivedDefaultDecl, 36);
Expand All @@ -625,16 +625,16 @@ mod rkyv_layout_assert {
assert_size!(ArchivedExportDefaultDecl, 44);
assert_size!(ArchivedExportDefaultExpr, 12);
assert_size!(ArchivedExportDefaultSpecifier, 24);
assert_size!(ArchivedExportNamedSpecifier, 80);
assert_size!(ArchivedExportNamespaceSpecifier, 40);
assert_size!(ArchivedExportSpecifier, 84);
assert_size!(ArchivedExportNamedSpecifier, 88);
assert_size!(ArchivedExportNamespaceSpecifier, 44);
assert_size!(ArchivedExportSpecifier, 92);
assert_size!(ArchivedImportDecl, 36);
assert_size!(ArchivedImportDefaultSpecifier, 32);
assert_size!(ArchivedImportNamedSpecifier, 72);
assert_size!(ArchivedImportSpecifier, 76);
assert_size!(ArchivedImportNamedSpecifier, 76);
assert_size!(ArchivedImportSpecifier, 80);
assert_size!(ArchivedImportStarAsSpecifier, 32);
assert_size!(ArchivedModuleDecl, 48);
assert_size!(ArchivedModuleExportName, 32);
assert_size!(ArchivedModuleExportName, 36);
assert_size!(ArchivedNamedExport, 36);

// Operator types
Expand Down Expand Up @@ -700,17 +700,17 @@ mod rkyv_layout_assert {
assert_size!(ArchivedTsConstructorType, 32);
assert_size!(ArchivedTsEntityName, 28);
assert_size!(ArchivedTsEnumDecl, 44);
assert_size!(ArchivedTsEnumMember, 48);
assert_size!(ArchivedTsEnumMemberId, 32);
assert_size!(ArchivedTsEnumMember, 52);
assert_size!(ArchivedTsEnumMemberId, 36);
assert_size!(ArchivedTsExportAssignment, 12);
assert_size!(ArchivedTsExprWithTypeArgs, 20);
assert_size!(ArchivedTsExternalModuleRef, 36);
assert_size!(ArchivedTsExternalModuleRef, 40);
assert_size!(ArchivedTsFnOrConstructorType, 36);
assert_size!(ArchivedTsFnParam, 36);
assert_size!(ArchivedTsFnType, 28);
assert_size!(ArchivedTsGetterSignature, 24);
assert_size!(ArchivedTsImportEqualsDecl, 76);
assert_size!(ArchivedTsImportType, 92);
assert_size!(ArchivedTsImportEqualsDecl, 80);
assert_size!(ArchivedTsImportType, 96);
assert_size!(ArchivedTsIndexSignature, 28);
assert_size!(ArchivedTsIndexedAccessType, 20);
assert_size!(ArchivedTsInferType, 60);
Expand All @@ -725,9 +725,9 @@ mod rkyv_layout_assert {
assert_size!(ArchivedTsMappedType, 84);
assert_size!(ArchivedTsMethodSignature, 40);
assert_size!(ArchivedTsModuleBlock, 16);
assert_size!(ArchivedTsModuleDecl, 92);
assert_size!(ArchivedTsModuleName, 32);
assert_size!(ArchivedTsModuleRef, 40);
assert_size!(ArchivedTsModuleDecl, 96);
assert_size!(ArchivedTsModuleName, 36);
assert_size!(ArchivedTsModuleRef, 44);
assert_size!(ArchivedTsNamespaceBody, 44);
assert_size!(ArchivedTsNamespaceDecl, 40);
assert_size!(ArchivedTsNamespaceExportDecl, 32);
Expand Down Expand Up @@ -758,8 +758,8 @@ mod rkyv_layout_assert {
assert_size!(ArchivedTsTypeParamDecl, 16);
assert_size!(ArchivedTsTypeParamInstantiation, 16);
assert_size!(ArchivedTsTypePredicate, 48);
assert_size!(ArchivedTsTypeQuery, 112);
assert_size!(ArchivedTsTypeQueryExpr, 96);
assert_size!(ArchivedTsTypeQuery, 116);
assert_size!(ArchivedTsTypeQueryExpr, 100);
assert_size!(ArchivedTsTypeRef, 44);
assert_size!(ArchivedTsUnionOrIntersectionType, 20);
assert_size!(ArchivedTsUnionType, 16);
Expand Down
19 changes: 18 additions & 1 deletion crates/swc_ecma_ast/src/lit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,15 @@ pub struct Str {
/// Use `None` value only for transformations to avoid recalculate escaped
/// characters in strings
pub raw: Option<Atom>,

/// The string value contains lone surrogates.
///
/// `value` is encoded with `\u{FFFD}` to mark the lone surrogate as an
/// escaped value.
///
/// For example, a "\uD808" is a lone surrogate, and it's encoded as
/// `\u{FFFD}D808`.
pub lone_surrogates: bool,
}

impl Take for Str {
Expand All @@ -198,6 +207,7 @@ impl Take for Str {
span: DUMMY_SP,
value: atom!(""),
raw: None,
lone_surrogates: false,
}
}
}
Expand All @@ -209,8 +219,14 @@ impl<'a> arbitrary::Arbitrary<'a> for Str {
let span = u.arbitrary()?;
let value = u.arbitrary::<String>()?.into();
let raw = Some(u.arbitrary::<String>()?.into());
let lone_surrogates = u.arbitrary()?;

Ok(Self { span, value, raw })
Ok(Self {
span,
value,
raw,
lone_surrogates,
})
}
}

Expand Down Expand Up @@ -282,6 +298,7 @@ impl From<Atom> for Str {
span: DUMMY_SP,
value,
raw: None,
lone_surrogates: false,
}
}
}
Expand Down
Loading
Loading