Repository navigation
fix(directive): compile input and output names with lone surrogates - #593
Merged
Merged
Conversation
oxc 0.155 stores string values as `JSStr`, which has no `&str` form for a lone surrogate (`'x-\uD800'`). Such an input or output member was dropped from the definition, and such an alias was an error. ngtsc reads them like any string and prints each lone code unit as a `\uXXXX` escape. Names, aliases and evaluated metadata strings now keep each lone code unit as two characters: the noncharacter U+FDD0, then U+10F800 + offset. The JS, `.d.ts` and JIT string printers turn that pair back into `\uXXXX`; either character on its own is printed as itself. A property name holding one is written as a key (`ctx["q-\uD800"]`), and an `ngAcceptInputType_` member holding one is quoted, where ngtsc's output is not valid JS / TS. A selector holding a lone surrogate is still an error: the selector parser can't read it. Closes #505 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e5869b8826
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes #505.
Since oxc 0.155 (#589), string values are
JSStr, which has no&strform for a lone surrogate. So onmain:ngtsc compiles all of them. I checked this by running ngc 22.2.3 (full and partial) and the linker on these cases. It prints each lone code unit in a generated string as an uppercase
\uXXXX:This PR emits the same, in full, partial and JIT output, in
setClassMetadataand in the.d.ts.How
A Rust
&strcan't hold a lone surrogate, soutil/lone_surrogate.rsstores each lone code unit0xD800 + kas two characters: the noncharacter U+FDD0 (which Unicode reserves for a program's internal use), then U+10F800 + k. Only that pair is a lone surrogate. Either character on its own, as real text, is printed as itself.util/lone_surrogate.rsdirective/evaluator.rsDynamic). Transform types and thengAcceptInputType_clash check find such a member.directive/property_decorators.rs,class_metadata/builders.rs@Input/input()/model()/output()aliases andpropDecoratorskeys keep it. A string query predicate takes the same path as any string, solone_surrogate_selectorsgoes.directive/decorator.rsmain's error, because the selector parser can't read it.component/transform.rs__decoratemember name is now escaped.output/emitter.rs,dts.rs,directive/dts_type.rs\uXXXX.Where this differs from ngtsc
ngtsc writes invalid output in two places. This PR writes valid output there instead:
@ViewChild('r') 'q-\uD800': ngtsc writesctx.q-<U+FFFD> = .... This PR writesctx["q-\uD800"] = ....ngAcceptInputType_member with a lone surrogate: ngtsc writes it unquoted, as U+FFFD. This PR quotes it.Side effects of reading these strings
stylesand host attribute values holding a lone surrogate now compile like ngtsc. Onmainthey were errors.constlike any other (const _c0 = ["\uD800"]), as ngtsc does.Not in this PR (same on
main)@HostBinding/@HostListenerarguments, host keys,hostDirectivesmappings,exportAs,@Pipe({name})and@Attribute(...)holding a lone surrogate.templateholding a lone surrogate. The component is silently left uncompiled.selector: '[ké]'panics atpipeline/selector.rs:240).\uXXXX.Tests
tests/lone_surrogate_names_test.rshas 12 cases, with expected fragments taken from ngc's output. All 12 fail onmain, except the two that pinmainbehaviour (the selector error, and private-use characters printed as themselves). The cases:.d.ts;inputs:/outputs:arrays;ngAcceptInputType_;Three existing tests asserted the old behaviour (an error, or an inline predicate). They now assert ngtsc's output.
cargo fmt --all -- --check,cargo test --all-features(3340 passed) andcargo run -p oxc_angular_conformance(1264/1264, no snapshot diff) pass.🤖 Generated with Claude Code