Skip to content

Conversation

@Sherry-hue
Copy link
Collaborator

@Sherry-hue Sherry-hue commented Jul 29, 2025

Summary by CodeRabbit

  • New Features

    • Improved support for handling JavaScript strings in style transformation and parsing, enabling direct string processing without manual UTF-16 encoding.
  • Refactor

    • Streamlined internal APIs to use JavaScript string types (JsString/string) instead of raw UTF-16 slices and pointers.
    • Updated all related interfaces, constants, and transformation logic to operate on string slices, reducing unsafe operations and memory management.
    • Rewrote parser and tokenizer to use iterator-based UTF-8 string processing instead of UTF-16 slice indexing.
    • Converted constants and rules from UTF-16 slices to string slices for simpler usage.
    • Adjusted TypeScript type definitions to reflect the new string-based interfaces.
  • Chores

    • Updated package dependencies and configuration to align with the new implementation and release grouping.

Checklist

  • Tests updated (or not required).
  • Documentation updated (or not required).
  • Changeset added, and when a BREAKING CHANGE occurs, it needs to be clearly marked (or not required).

@changeset-bot
Copy link

changeset-bot bot commented Jul 29, 2025

🦋 Changeset detected

Latest commit: a4f176f

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

This PR includes changesets to release 7 packages
Name Type
@lynx-js/web-style-transformer Patch
@lynx-js/web-mainthread-apis Patch
@lynx-js/web-core-server Patch
@lynx-js/web-core Patch
@lynx-js/web-worker-runtime Patch
@lynx-js/web-constants Patch
@lynx-js/web-worker-rpc 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

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jul 29, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

📝 Walkthrough

Walkthrough

This change refactors the inline style parsing and transformation pipeline across Rust and TypeScript to use js_sys::JsString and string slices instead of raw UTF-16 slices and pointers. It updates APIs, data structures, constants, and test cases to support direct string handling, removes unsafe pointer logic, and aligns Rust and TypeScript interfaces.

Changes

Cohort / File(s) Change Summary
Changeset & Config
.changeset/cyan-comics-glow.md, .changeset/config.json
Adds @lynx-js/web-style-transformer to the fixed release group and documents the patch changes.
Cargo Dependency Updates
.../inline-style-parser/Cargo.toml, .../web-style-transformer/Cargo.toml
Adds or corrects dependencies: js-sys and web-sys with "console" feature.
String/Index Refactor: Core Parser
.../inline-style-parser/src/char_code_definitions.rs, .../inline-style-parser/src/lib.rs, .../inline-style-parser/src/parse_inline_style.rs, .../inline-style-parser/src/tokenize.rs, .../inline-style-parser/src/utils.rs
Converts all string handling from UTF-16 slices and usize to js_sys::JsString and u32 indices; updates constants, macros, function signatures, and tests.
WebAssembly Interface & Transformer Refactor
.../web-style-transformer/src/lib.rs, .../web-style-transformer/src/transformer/transform.rs
Removes unsafe pointer-based interfaces; all Rust and JS interop now use JsString and String, refactors transformer logic and test cases accordingly.
Constants and Rules Refactor
.../web-style-transformer/src/transformer/constants.rs, .../web-style-transformer/src/transformer/rules.rs
Changes all constants and rule maps from UTF-16 slices to &str, updates macros and disables most replacement rules and related tests.
TypeScript/WASM API Update
.../web-mainthread-apis/src/utils/tokenizer.ts, .../web-style-transformer/standard.d.ts
Removes manual UTF-16 encoding and pointer logic; updates TypeScript declarations and usage to pass strings directly to WASM.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • PupilTong

Poem

🐇✨
Refactored strings from bytes to charm,
No more pointers—just JsString's warm.
Unsafe code now hops away,
Rust and JS speak the same way.
Constants, rules, and tests align,
This bunny thinks the code looks fine!
🥕💻

Note

⚡️ Unit Test Generation is now available in beta!

Learn more here, or try it out under "Finishing Touches" below.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@PupilTong PupilTong requested a review from Copilot July 29, 2025 09:15
Copy link
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: 6

🔭 Outside diff range comments (6)
packages/web-platform/web-mainthread-apis/src/utils/tokenizer.ts (2)

59-102: Remove commented UTF-16 memory management code.

The function correctly uses direct string passing, but the commented UTF-16 code should be removed for cleaner maintainability.

 export function transformParsedStyles(
   styles: [string, string][],
 ): { childStyle: [string, string][]; transformedStyle: [string, string][] } {
   let childStyle: [string, string][] = [];
   let transformedStyle: [string, string][] = [];
   for (const [property, value] of styles) {
-    // const { ptr: propertyPtr, len: propertyLen } = stringToUTF16(property);
-    // const { ptr: valuePtr, len: valueLen } = stringToUTF16(value);
     try {
       const transformedResult = wasm
         .transform_raw_u16_inline_style_ptr_parsed(
-          // propertyPtr,
-          // propertyLen,
           property,
           property.length,
-          // valuePtr,
-          // valueLen,
           value,
           value.length,
         );
-      // wasm.free(propertyPtr, propertyLen << 1);
-      // wasm.free(valuePtr, valueLen << 1);
       if (transformedResult) {
         const [transformedStyleForCurrent, childStyleForCurrent] =
           transformedResult;
         transformedStyle = transformedStyle.concat(transformedStyleForCurrent);
         if (childStyleForCurrent) {
           childStyle = childStyle.concat(childStyleForCurrent);
         }
       } else {
         // If the transformation fails, we keep the original style
         transformedStyle.push([property, value]);
       }
     } catch (e) {
-      // wasm.free(propertyPtr, propertyLen << 1);
-      // wasm.free(valuePtr, valueLen << 1);
       throw e;
     }
   }
   return {
     childStyle,
     transformedStyle,
   };
 }

4-4: Remove unused UTF-16 conversion utilities.

The HEAPU16 variable and stringToUTF16 function are no longer used and should be removed.

 let wasm: Awaited<ReturnType<typeof init>>;
-let HEAPU16: Uint16Array | undefined;
 var ENVIRONMENT_IS_NODE = typeof process == 'object'
   && typeof process.versions == 'object'
   && typeof process.versions.node == 'string';
-const stringToUTF16 = (str: string) => {
-  const len = str.length;
-  const ptr = wasm.malloc(len << 1);
-  if (!HEAPU16 || HEAPU16.byteLength == 0) {
-    HEAPU16 = new Uint16Array(wasm.memory.buffer);
-  }
-  for (let i = 0; i < len; i++) {
-    HEAPU16[(ptr >> 1) + i] = str.charCodeAt(i);
-  }
-  return { ptr, len };
-};

Also applies to: 30-40

packages/web-platform/web-style-transformer/src/transformer/transformer.rs (3)

36-47: Fix macro implementation for JsString

The is_digit_only! macro attempts to iterate over a JsString, but JsString doesn't implement Iterator. You need to iterate through the characters using index-based access.

 macro_rules! is_digit_only {
   ($source:expr, $start:expr, $end:expr) => {{
     let mut result = true;
-    for code in $source.slice($start, $end).iter() {
-      if code > b'9' as u16 || code < b'0' as u16 {
+    for i in $start..$end {
+      let code = $source.char_code_at(i) as u32;
+      if code > '9' as u32 || code < '0' as u32 {
         result = false;
         break;
       }
     }
     result
   }};
 }

172-172: Potential issue with is_digit_only! macro usage

This line uses the is_digit_only! macro which has the iteration issue mentioned above. This will cause a runtime error.


216-216: Another usage of broken is_digit_only! macro

This is another instance where the broken is_digit_only! macro is used.

packages/web-platform/web-style-transformer/src/transformer/constants.rs (1)

45-216: Apply consistent constant definitions

Some constants use direct string assignment while others still use the str_to_u16_slice! macro. After removing the macro, ensure all constants use direct string assignment for consistency.

🧹 Nitpick comments (12)
packages/web-platform/web-style-transformer/src/transformer/rules.rs (1)

264-290: Macros correctly handle UTF-16 to String conversion.

The macro implementations properly convert UTF-16 slices to String objects for hash map lookups. However, note that this approach involves string conversion overhead on each lookup.

Consider caching converted strings or optimizing the lookup mechanism if performance becomes a concern.

packages/web-platform/inline-style-parser/src/utils.rs (3)

70-70: Remove redundant cast to u32

The get_char_code! macro already returns a u32 value, so the additional cast is unnecessary.

-    let code = get_char_code!(source, source_length, offset) as u32;
+    let code = get_char_code!(source, source_length, offset);

114-115: Remove commented-out code

This commented code is not needed and should be removed to improve code cleanliness.

-    // let mut code: u16 = source[offset];
     let mut code = source.char_code_at(offset) as u32;

146-146: Use a named constant instead of magic number

Consider using a named constant for the character code 101 (lowercase 'e') for better readability.

-    if cmp_char!(source, source_length, offset, 101 /* e */) != 0 {
+    if cmp_char!(source, source_length, offset, 'e' as u32) != 0 {
packages/web-platform/web-style-transformer/src/lib.rs (3)

13-44: Remove large blocks of commented code

These commented code blocks should be removed as they're no longer needed after the refactoring to JsString. If this code is needed for reference, it should be preserved in version control history instead.


13-14: Use English comments for consistency

Please translate the Chinese comments to English for consistency across the codebase.

-// 将参数从 (ptr: *const u16, len: usize) 改为直接接收 JsString
+// Changed parameters from (ptr: *const u16, len: usize) to directly receive JsString

92-92: Remove unnecessary cast

The cast 0 as u32 is redundant since 0 is already inferred as u32 from the function signature.

-      &name_ptr, 0 as u32, name_len, &value_ptr, 0 as u32, value_len,
+      &name_ptr, 0, name_len, &value_ptr, 0, value_len,
packages/web-platform/inline-style-parser/src/tokenize.rs (1)

408-410: Simplify character code comparisons

The current casting pattern is unnecessarily complex. Since char_code_at returns f64, you can compare directly with numeric literals.

-            if source.char_code_at(ii) == ('*' as u16 as f64)
-              && source.char_code_at(ii + 1) == ('/' as u16 as f64)
+            if source.char_code_at(ii) == 42.0  // '*'
+              && source.char_code_at(ii + 1) == 47.0  // '/'
packages/web-platform/web-style-transformer/src/transformer/transformer.rs (3)

3-3: Remove unused import

The web_sys::console import is not used in this file and should be removed.

-use web_sys::console;

79-80: Remove commented code

Please remove this commented code to maintain code cleanliness.

-  // let value_str = &value.as_string().to_stri;
   if let Some(renamed_value) = get_rename_rule_value!(name, name_start, name_end) {

342-342: Remove large blocks of commented code

Please remove all the commented code blocks throughout this file. They clutter the codebase and make it harder to read.

Also applies to: 401-415

packages/web-platform/web-style-transformer/src/transformer/constants.rs (1)

24-102: Remove commented-out constant definitions

Please remove all the commented-out constant definitions. They're no longer needed and clutter the code.

For example:

-// pub const IMPORTANT_STR_U16: &str = str_to_u16_slice!(" !important");
 pub const IMPORTANT_STR_U16: &str = " !important";
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 143e481 and 7a1286d.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (15)
  • .changeset/cyan-comics-glow.md (1 hunks)
  • packages/web-platform/inline-style-parser/Cargo.toml (1 hunks)
  • packages/web-platform/inline-style-parser/src/char_code_definitions.rs (8 hunks)
  • packages/web-platform/inline-style-parser/src/lib.rs (33 hunks)
  • packages/web-platform/inline-style-parser/src/parse_inline_style.rs (4 hunks)
  • packages/web-platform/inline-style-parser/src/tokenize.rs (9 hunks)
  • packages/web-platform/inline-style-parser/src/types.rs (1 hunks)
  • packages/web-platform/inline-style-parser/src/utils.rs (9 hunks)
  • packages/web-platform/web-mainthread-apis/src/utils/tokenizer.ts (3 hunks)
  • packages/web-platform/web-style-transformer/Cargo.toml (1 hunks)
  • packages/web-platform/web-style-transformer/package.json (1 hunks)
  • packages/web-platform/web-style-transformer/src/lib.rs (3 hunks)
  • packages/web-platform/web-style-transformer/src/transformer/constants.rs (4 hunks)
  • packages/web-platform/web-style-transformer/src/transformer/rules.rs (1 hunks)
  • packages/web-platform/web-style-transformer/src/transformer/transformer.rs (19 hunks)
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: colinaaa
PR: lynx-family/lynx-stack#1330
File: .changeset/olive-animals-attend.md:1-3
Timestamp: 2025-07-22T09:23:07.797Z
Learning: In the lynx-family/lynx-stack repository, changesets are only required for meaningful changes to end-users such as bugfixes and features. Internal/development changes like chores, refactoring, or removing debug info do not need changeset entries.
Learnt from: PupilTong
PR: lynx-family/lynx-stack#1029
File: packages/web-platform/web-mainthread-apis/src/createMainThreadGlobalThis.ts:214-217
Timestamp: 2025-07-16T06:25:41.055Z
Learning: In the lynx-stack codebase, CSS strings produced by `genCssContent` are considered trusted developer input, so additional sanitization/escaping is not required.
Learnt from: colinaaa
PR: lynx-family/lynx-stack#1330
File: .changeset/olive-animals-attend.md:1-3
Timestamp: 2025-07-22T09:26:16.722Z
Learning: In the lynx-family/lynx-stack repository, CI checks require changesets when files matching the pattern "src/**" are modified (as configured in .changeset/config.json). For internal changes that don't need meaningful changesets, an empty changeset file is used to satisfy the CI requirement while not generating any release notes.
Learnt from: PupilTong
PR: lynx-family/lynx-stack#1029
File: packages/web-platform/web-core/src/uiThread/createRenderAllOnUI.ts:95-99
Timestamp: 2025-07-16T06:28:26.463Z
Learning: In the lynx-stack codebase, CSS selectors in SSR hydration are generated by their own packages, ensuring a predictable format that makes simple string manipulation safe and preferable over regex for performance reasons.
.changeset/cyan-comics-glow.md (5)

Learnt from: colinaaa
PR: #1330
File: .changeset/olive-animals-attend.md:1-3
Timestamp: 2025-07-22T09:23:07.797Z
Learning: In the lynx-family/lynx-stack repository, changesets are only required for meaningful changes to end-users such as bugfixes and features. Internal/development changes like chores, refactoring, or removing debug info do not need changeset entries.

Learnt from: colinaaa
PR: #1330
File: .changeset/olive-animals-attend.md:1-3
Timestamp: 2025-07-22T09:26:16.722Z
Learning: In the lynx-family/lynx-stack repository, CI checks require changesets when files matching the pattern "src/**" are modified (as configured in .changeset/config.json). For internal changes that don't need meaningful changesets, an empty changeset file is used to satisfy the CI requirement while not generating any release notes.

Learnt from: PupilTong
PR: #1029
File: packages/web-platform/web-core/src/uiThread/createRenderAllOnUI.ts:95-99
Timestamp: 2025-07-16T06:28:26.463Z
Learning: In the lynx-stack codebase, CSS selectors in SSR hydration are generated by their own packages, ensuring a predictable format that makes simple string manipulation safe and preferable over regex for performance reasons.

Learnt from: PupilTong
PR: #1029
File: packages/web-platform/web-mainthread-apis/src/createMainThreadGlobalThis.ts:214-217
Timestamp: 2025-07-16T06:25:41.055Z
Learning: In the lynx-stack codebase, CSS strings produced by genCssContent are considered trusted developer input, so additional sanitization/escaping is not required.

Learnt from: PupilTong
PR: #1029
File: packages/web-platform/web-core/src/uiThread/createRenderAllOnUI.ts:95-99
Timestamp: 2025-07-16T05:57:29.837Z
Learning: In the lynx-stack codebase, PupilTong prefers avoiding regex for parsing in performance-critical code paths like SSR hydration, preferring simple string manipulation operations even if they're less robust, when the input format is predictable and controlled.

packages/web-platform/web-style-transformer/src/lib.rs (1)

Learnt from: PupilTong
PR: #1029
File: packages/web-platform/web-mainthread-apis/src/createMainThreadGlobalThis.ts:214-217
Timestamp: 2025-07-16T06:25:41.055Z
Learning: In the lynx-stack codebase, CSS strings produced by genCssContent are considered trusted developer input, so additional sanitization/escaping is not required.

packages/web-platform/web-style-transformer/src/transformer/constants.rs (2)

Learnt from: PupilTong
PR: #1029
File: packages/web-platform/web-mainthread-apis/src/createMainThreadGlobalThis.ts:214-217
Timestamp: 2025-07-16T06:25:41.055Z
Learning: In the lynx-stack codebase, CSS strings produced by genCssContent are considered trusted developer input, so additional sanitization/escaping is not required.

Learnt from: PupilTong
PR: #1029
File: packages/web-platform/web-core/src/uiThread/createRenderAllOnUI.ts:95-99
Timestamp: 2025-07-16T06:28:26.463Z
Learning: In the lynx-stack codebase, CSS selectors in SSR hydration are generated by their own packages, ensuring a predictable format that makes simple string manipulation safe and preferable over regex for performance reasons.

🔇 Additional comments (18)
packages/web-platform/inline-style-parser/src/types.rs (1)

4-5: LGTM! Appropriate import for string interop.

The addition of JsString import supports the package-wide refactoring from UTF-16 slices to JavaScript string interop types, which improves safety and idiomatic WebAssembly usage.

packages/web-platform/web-style-transformer/Cargo.toml (1)

14-14: LGTM! Console feature enables enhanced debugging.

The addition of web-sys dependency with the "console" feature aligns with the safer string handling refactor and enables better debugging capabilities in the WebAssembly environment.

.changeset/cyan-comics-glow.md (1)

1-7: Changeset appropriately documents the string handling refactor.

The changeset correctly identifies this as a feature change affecting both packages involved in the JsString adoption. Based on the retrieved learnings, this represents a meaningful improvement to the string handling architecture that warrants a changeset entry.

packages/web-platform/web-style-transformer/package.json (1)

25-25: Verify use of --debug in production build

I didn’t find any separate “release” or “prod” build task in packages/web-platform/web-style-transformer/package.json or in its turbo.json—you're only invoking:

• packages/web-platform/web-style-transformer/package.json, line 25
"build": "wasm-pack build --debug …"

Using --debug increases bundle size and may impact runtime performance. Please confirm whether this is intentional for your production pipeline, or consider switching to a release‐optimized build (e.g. wasm-pack build --release) if you’re targeting production environments.

packages/web-platform/inline-style-parser/src/parse_inline_style.rs (4)

8-11: LGTM!

The conversion of IMPORTANT_STR from [u16] to [u32] correctly maintains the same character codes while aligning with the new u32-based character handling.


13-23: LGTM!

The struct field updates correctly transition from UTF-16 slice to JsString and use u32 indices, which is appropriate for JavaScript string indexing.


82-86: LGTM - Correct JsString character access.

The change from array indexing to char_code_at method correctly adapts to the JsString API while maintaining the same whitespace trimming logic.


132-159: LGTM!

The trait and function signature updates correctly use u32 indices and JsString, with proper method calls like length() for string length queries.

packages/web-platform/web-style-transformer/src/transformer/rules.rs (2)

5-28: All RENAME_RULE entries have been migrated

The active RENAME_RULE in
packages/web-platform/web-style-transformer/src/transformer/rules.rs
now defines the same eight mappings that were present in the commented-out UTF-16 version (lines 19–26), so no entries are missing.


30-261: Missing CSS transformation rules in REPLACE_RULE
An audit of rules.rs shows 58 UTF-16 mappings still commented out versus 43 active string-based mappings—about 15 rule insertions appear not yet ported. Please confirm whether those omitted rules are intentionally dropped or need migrating, and ensure that REPLACE_RULE covers all required CSS transformations.

• File: packages/web-platform/web-style-transformer/src/transformer/rules.rs
• Location: lines 30–261

packages/web-platform/inline-style-parser/src/lib.rs (4)

12-65: LGTM - Comprehensive migration to JsString API.

The test infrastructure correctly migrates from UTF-16 to JsString:

  • Declaration fields appropriately use u32 indices
  • Helper methods properly use slice() and JsString::from()
  • Test setup function correctly creates JsString instances

The migration maintains all functionality while adopting the new API.


484-497: LGTM - Tests correctly adapted to JsString API.

The test updates properly migrate from UTF-16 vectors to JsString while maintaining identical test logic and expectations. This validates that the API migration preserves functionality.


610-632: LGTM - Utility function tests properly updated.

The utility function tests correctly migrate to u32 character codes and JsString usage while maintaining comprehensive validation of core parsing functionality including string comparison and character classification.


715-802: LGTM - Tokenizer tests comprehensively updated.

The tokenizer tests properly migrate to the new API:

  • TokenCollector correctly uses u32 indices
  • All test inputs properly converted to JsString
  • Test coverage maintained for various token types and edge cases

This ensures the core tokenization functionality works correctly with the new string representation.

packages/web-platform/inline-style-parser/src/char_code_definitions.rs (4)

2-34: LGTM - Character category constants correctly migrated to u32.

The migration from u16 to u32 for character categories is comprehensive and correct:

  • All constants properly updated to u32
  • The category_map_value_const function correctly handles u32 input
  • Array initialization and indexing properly handles the type conversion

This provides the foundation for consistent u32-based character handling throughout the parser.


40-197: LGTM - Character classification macros properly updated.

The migration of character classification macros from u16 to u32 is correctly implemented:

  • All numeric literals properly updated (removed u16 suffixes)
  • Macro logic preserved while working with u32 character codes
  • Comprehensive coverage of CSS character classification requirements

200-211: LGTM - Character category lookup correctly handles type conversion.

The char_code_category! macro properly casts the u32 character code to usize for array indexing while maintaining the same ASCII/non-ASCII classification logic.


213-251: LGTM - String access macros correctly adapted for JsString.

The string access macros properly migrate to the JsString API:

  • cmp_char! correctly uses char_code_at() method and handles case-insensitive comparison
  • get_char_code! properly retrieves character codes with bounds checking
  • get_new_line_length! maintains correct CRLF handling logic

These macros provide the essential foundation for character-level operations in the parser.

Comment on lines +6 to +7
[depedencies]
js-sys = "0.3.77"
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix the typo in the dependencies section header.

There's a typo in the section header that will cause the dependency to be ignored by Cargo.

-[depedencies]
-js-sys = "0.3.77"
+[dependencies]
+js-sys = "0.3.77"
🤖 Prompt for AI Agents
In packages/web-platform/inline-style-parser/Cargo.toml at lines 6 to 7, fix the
typo in the section header by changing "[depedencies]" to "[dependencies]" so
that Cargo correctly recognizes and processes the dependency.

Comment on lines +9 to +10
[dependencies]
js-sys = "0.3.77"
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Remove the duplicate dependencies section.

The correctly spelled [dependencies] section already includes the js-sys dependency, making the misspelled section redundant.

-[dependencies]
-js-sys = "0.3.77"

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In packages/web-platform/inline-style-parser/Cargo.toml at lines 9 to 10, there
is a duplicate dependencies section with a misspelled header. Remove the
duplicate or incorrectly spelled dependencies section so that only the correctly
spelled [dependencies] section remains, which already includes the js-sys
dependency.

Comment on lines 41 to 18
export function transformInlineStyleString(str: string): string {
const { ptr, len } = stringToUTF16(str);
console.log(0, str);
// const { ptr, len } = stringToUTF16(str);
try {
const transformedStyle = wasm.transform_raw_u16_inline_style_ptr(ptr, len)
?? str;
wasm.free(ptr, len << 1);
return transformedStyle;
console.log('start parse', str);
const res = wasm.transform_inline_style(str) ?? str;

// const transformedStyle = wasm.transform_raw_u16_inline_style_ptr(ptr, len)
// ?? str;
// wasm.free(ptr, len << 1);
console.log('return-value', res);
return res;
} catch (e) {
wasm.free(ptr, len << 1);
// wasm.free(ptr, len << 1);
throw e;
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Clean up commented code and debug logging.

The function correctly transitions to direct string passing, but needs cleanup:

  1. Remove commented UTF-16 memory management code (lines 43, 48-50, 54)
  2. Remove debug console.log statements (lines 42, 45, 51) - these should not be in production code
  3. Remove unused stringToUTF16 function (lines 30-40) since it's no longer used
 export function transformInlineStyleString(str: string): string {
-  console.log(0, str);
-  // const { ptr, len } = stringToUTF16(str);
   try {
-    console.log('start parse', str);
     const res = wasm.transform_inline_style(str) ?? str;
-
-    // const transformedStyle = wasm.transform_raw_u16_inline_style_ptr(ptr, len)
-    //   ?? str;
-    // wasm.free(ptr, len << 1);
-    console.log('return-value', res);
     return res;
   } catch (e) {
-    // wasm.free(ptr, len << 1);
     throw e;
   }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export function transformInlineStyleString(str: string): string {
const { ptr, len } = stringToUTF16(str);
console.log(0, str);
// const { ptr, len } = stringToUTF16(str);
try {
const transformedStyle = wasm.transform_raw_u16_inline_style_ptr(ptr, len)
?? str;
wasm.free(ptr, len << 1);
return transformedStyle;
console.log('start parse', str);
const res = wasm.transform_inline_style(str) ?? str;
// const transformedStyle = wasm.transform_raw_u16_inline_style_ptr(ptr, len)
// ?? str;
// wasm.free(ptr, len << 1);
console.log('return-value', res);
return res;
} catch (e) {
wasm.free(ptr, len << 1);
// wasm.free(ptr, len << 1);
throw e;
}
}
export function transformInlineStyleString(str: string): string {
try {
const res = wasm.transform_inline_style(str) ?? str;
return res;
} catch (e) {
throw e;
}
}
🤖 Prompt for AI Agents
In packages/web-platform/web-mainthread-apis/src/utils/tokenizer.ts from lines
30 to 57, remove the unused stringToUTF16 function (lines 30-40), delete all
commented-out UTF-16 memory management code (lines 43, 48-50, 54), and eliminate
all console.log debug statements (lines 42, 45, 51) to clean up the function for
production readiness.

Comment on lines 1 to 22
#[macro_export]
macro_rules! str_to_u16_slice {
($s:expr) => {{
const S: &str = $s;
const LEN: usize = S.len();
const fn make_array() -> [u16; LEN] {
let bytes = S.as_bytes();
let mut result = [0u16; LEN];
let mut i = 0;
while i < LEN {
result[i] = bytes[i] as u16;
i += 1;
}
result
}
const ARRAY: [u16; LEN] = make_array();
&ARRAY
}};
($s:expr) => {
// {
// const S: &str = $s;
// const LEN: usize = S.len();
// const fn make_array() -> [u16; LEN] {
// let bytes = S.as_bytes();
// let mut result = [0u16; LEN];
// let mut i = 0;
// while i < LEN {
// result[i] = bytes[i] as u16;
// i += 1;
// }
// result
// }
// const ARRAY: [u16; LEN] = make_array();
// &ARRAY
// }
$s
};
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Remove str_to_u16_slice! macro and its usage

Since the macro now just returns the input string unchanged, it serves no purpose. Remove the macro definition and its usage throughout the file for cleaner code.

-#[macro_export]
-macro_rules! str_to_u16_slice {
-  ($s:expr) => {
-    //   {
-    //   const S: &str = $s;
-    //   const LEN: usize = S.len();
-    //   const fn make_array() -> [u16; LEN] {
-    //     let bytes = S.as_bytes();
-    //     let mut result = [0u16; LEN];
-    //     let mut i = 0;
-    //     while i < LEN {
-    //       result[i] = bytes[i] as u16;
-    //       i += 1;
-    //     }
-    //     result
-    //   }
-    //   const ARRAY: [u16; LEN] = make_array();
-    //   &ARRAY
-    // }
-    $s
-  };
-}

Then update all usages like:

-pub const LIST_MAIN_AXIS_GAP_STR_U16: &str = str_to_u16_slice!("list-main-axis-gap");
+pub const LIST_MAIN_AXIS_GAP_STR_U16: &str = "list-main-axis-gap";
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
#[macro_export]
macro_rules! str_to_u16_slice {
($s:expr) => {{
const S: &str = $s;
const LEN: usize = S.len();
const fn make_array() -> [u16; LEN] {
let bytes = S.as_bytes();
let mut result = [0u16; LEN];
let mut i = 0;
while i < LEN {
result[i] = bytes[i] as u16;
i += 1;
}
result
}
const ARRAY: [u16; LEN] = make_array();
&ARRAY
}};
($s:expr) => {
// {
// const S: &str = $s;
// const LEN: usize = S.len();
// const fn make_array() -> [u16; LEN] {
// let bytes = S.as_bytes();
// let mut result = [0u16; LEN];
// let mut i = 0;
// while i < LEN {
// result[i] = bytes[i] as u16;
// i += 1;
// }
// result
// }
// const ARRAY: [u16; LEN] = make_array();
// &ARRAY
// }
$s
};
}
// (entire `str_to_u16_slice!` macro definition removed)
🤖 Prompt for AI Agents
In packages/web-platform/web-style-transformer/src/transformer/constants.rs
lines 1 to 22, the str_to_u16_slice! macro is redundant as it only returns the
input string unchanged. Remove the entire macro definition and replace all its
usages in the file with the original string literals directly to simplify and
clean up the code.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR migrates the inline style parser from low-level UTF-16 slice handling to JavaScript string APIs, improving safety and simplifying the codebase. The change replaces [u16] slice operations with js_sys::JsString methods throughout the parsing pipeline.

  • Replaces UTF-16 slice operations with JavaScript string APIs across the parser
  • Updates function signatures to use js_sys::JsString and u32 offsets instead of [u16] slices and usize
  • Simplifies memory management by eliminating unsafe pointer operations

Reviewed Changes

Copilot reviewed 15 out of 16 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
transformer.rs Updates core transformation logic to use JsString APIs instead of UTF-16 slices
rules.rs Converts rule matching from slice operations to string-based lookups
constants.rs Changes string constants from UTF-16 arrays to string literals
lib.rs Updates public API to accept JsString directly instead of raw pointers
tokenizer.ts Removes UTF-16 encoding/decoding and direct pointer management
utils.rs Converts utility functions to work with JsString instead of slices
parse_inline_style.rs Updates parser state to use JsString and u32 offsets
tokenize.rs Modifies tokenizer to work with JsString character access
char_code_definitions.rs Updates character category definitions for u32 character codes

// 2. If the next input code point is U+002B PLUS SIGN (+) or U+002D HYPHEN-MINUS (-),
// consume it and append it to repr.
if code == 0x002B || code == 0x002D {
if code == 0x002B4 || code == 0x002D {
Copy link

Copilot AI Jul 29, 2025

Choose a reason for hiding this comment

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

The constant 0x002B4 appears to be incorrect. It should likely be 0x002B (plus sign). The value 0x002B4 (692 decimal) doesn't correspond to a standard ASCII character.

Suggested change
if code == 0x002B4 || code == 0x002D {
if code == 0x002B || code == 0x002D {

Copilot uses AI. Check for mistakes.
// code.toLowerCase() for A..Z
if code == $reference_code || (is_uppercase_letter!(code) && ((code | 32) == $reference_code))
{
if code == $reference_code || (is_uppercase_letter!(code) && (code == $reference_code)) {
Copy link

Copilot AI Jul 29, 2025

Choose a reason for hiding this comment

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

The logic for case-insensitive comparison is incorrect. The second condition (code == $reference_code) will never be true if the first condition failed. It should be ((code | 32) == $reference_code) to convert uppercase to lowercase.

Suggested change
if code == $reference_code || (is_uppercase_letter!(code) && (code == $reference_code)) {
if (code == $reference_code) || ((code | 32) == $reference_code) {

Copilot uses AI. Check for mistakes.
Comment on lines +6 to +8
[depedencies]
js-sys = "0.3.77"

Copy link

Copilot AI Jul 29, 2025

Choose a reason for hiding this comment

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

Misspelled section header depedencies should be dependencies.

Suggested change
[depedencies]
js-sys = "0.3.77"
# Removed the misspelled `[depedencies]` section as it is redundant and incorrect.

Copilot uses AI. Check for mistakes.
["--lynx-display-toggle", "var(--lynx-display-linear)"],
["--lynx-display", "linear"],
["display", "flex"],
]);
Copy link

Copilot AI Jul 29, 2025

Choose a reason for hiding this comment

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

The REPLACE_RULE HashMap is being returned with only a partial display_map entry. The commented out code suggests there should be more entries (direction_map, linear_orientation_map, etc.), but they are not being added to the map, which will break rule replacement functionality.

Suggested change
]);
]);
map.insert("display", display_map);
// Direction rules
let mut direction_map = HashMap::new();
direction_map.insert("row", &[
["--lynx-direction", "row"],
["direction", "ltr"],
]);
direction_map.insert("column", &[
["--lynx-direction", "column"],
["direction", "ttb"],
]);
map.insert("direction", direction_map);
// Linear orientation rules
let mut linear_orientation_map = HashMap::new();
linear_orientation_map.insert("horizontal", &[
["--lynx-orientation", "horizontal"],
["orientation", "landscape"],
]);
linear_orientation_map.insert("vertical", &[
["--lynx-orientation", "vertical"],
["orientation", "portrait"],
]);
map.insert("linear-orientation", linear_orientation_map);

Copilot uses AI. Check for mistakes.
let mut result_children: Vec<(&'a [u16], usize, usize, &'a [u16], usize, usize)> = Vec::new();
let mut result: Vec<(String, u32, u32, String, u32, u32)> = Vec::new();
let mut result_children: Vec<(String, u32, u32, String, u32, u32)> = Vec::new();
// let value_str = &value.as_string().to_stri;
Copy link

Copilot AI Jul 29, 2025

Choose a reason for hiding this comment

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

Incomplete commented code should be removed as it adds no value and may confuse developers.

Suggested change
// let value_str = &value.as_string().to_stri;

Copilot uses AI. Check for mistakes.
value_ptr: js_sys::JsString,
value_len: u32,
) -> Option<js_sys::Array> {
unsafe {
Copy link

Copilot AI Jul 29, 2025

Choose a reason for hiding this comment

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

The function is marked as unsafe but no longer performs unsafe operations since it now uses JsString instead of raw pointers. The unsafe block should be removed.

Copilot uses AI. Check for mistakes.
@Sherry-hue Sherry-hue force-pushed the feat/style-parser-string branch from 7a1286d to b4a072f Compare July 29, 2025 09:39
Copy link
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

🔭 Outside diff range comments (3)
packages/web-platform/inline-style-parser/src/lib.rs (2)

507-528: Fix inconsistent type usage in character classification tests

The character classification macros are still being tested with u16 casts, but based on the PR objectives and changes in other files, these should be using u32 to align with the new char_code_at return type.

-    assert!(is_digit!('0' as u16));
-    assert!(is_digit!('9' as u16));
-    assert!(!is_digit!('a' as u16));
+    assert!(is_digit!('0' as u32));
+    assert!(is_digit!('9' as u32));
+    assert!(!is_digit!('a' as u32));

-    assert!(is_hex_digit!('0' as u16));
-    assert!(is_hex_digit!('A' as u16));
-    assert!(is_hex_digit!('f' as u16));
-    assert!(!is_hex_digit!('g' as u16));
+    assert!(is_hex_digit!('0' as u32));
+    assert!(is_hex_digit!('A' as u32));
+    assert!(is_hex_digit!('f' as u32));
+    assert!(!is_hex_digit!('g' as u32));

-    assert!(is_uppercase_letter!('A' as u16));
-    assert!(is_uppercase_letter!('Z' as u16));
-    assert!(!is_uppercase_letter!('a' as u16));
+    assert!(is_uppercase_letter!('A' as u32));
+    assert!(is_uppercase_letter!('Z' as u32));
+    assert!(!is_uppercase_letter!('a' as u32));

-    assert!(is_lowercase_letter!('a' as u16));
-    assert!(is_lowercase_letter!('z' as u16));
-    assert!(!is_lowercase_letter!('A' as u16));
+    assert!(is_lowercase_letter!('a' as u32));
+    assert!(is_lowercase_letter!('z' as u32));
+    assert!(!is_lowercase_letter!('A' as u32));

-    assert!(is_letter!('A' as u16));
-    assert!(is_letter!('z' as u16));
-    assert!(!is_letter!('1' as u16));
+    assert!(is_letter!('A' as u32));
+    assert!(is_letter!('z' as u32));
+    assert!(!is_letter!('1' as u32));

535-544: Fix inconsistent type usage in name classification tests

Continue updating character classification tests to use u32 instead of u16.

-    assert!(is_name_start!('a' as u16));
-    assert!(is_name_start!('_' as u16));
+    assert!(is_name_start!('a' as u32));
+    assert!(is_name_start!('_' as u32));
    assert!(is_name_start!(0x0080));
-    assert!(!is_name_start!('1' as u16));
+    assert!(!is_name_start!('1' as u32));

-    assert!(is_name!('a' as u16));
-    assert!(is_name!('1' as u16));
-    assert!(is_name!('-' as u16));
-    assert!(!is_name!(' ' as u16));
+    assert!(is_name!('a' as u32));
+    assert!(is_name!('1' as u32));
+    assert!(is_name!('-' as u32));
+    assert!(!is_name!(' ' as u32));
packages/web-platform/web-style-transformer/src/transformer/transform.rs (1)

36-47: Fix incorrect implementation of is_digit_only macro

The is_digit_only macro is incorrectly using .iter() on a JsString slice and comparing with u16 values. JsString doesn't have an .iter() method that returns character codes.

 macro_rules! is_digit_only {
   ($source:expr, $start:expr, $end:expr) => {{
     let mut result = true;
-    for code in $source.slice($start, $end).iter() {
-      if code > b'9' as u16 || code < b'0' as u16 {
+    for i in $start..$end {
+      let code = $source.char_code_at(i) as u32;
+      if code > b'9' as u32 || code < b'0' as u32 {
         result = false;
         break;
       }
     }
     result
   }};
 }
🧹 Nitpick comments (2)
packages/web-platform/web-style-transformer/src/transformer/transform.rs (2)

49-64: Rename macro to reflect current string types

The macro name push_u16_decl_pairs is misleading since it no longer works with u16 arrays but with string slices.

-macro_rules! push_u16_decl_pairs {
+macro_rules! push_str_decl_pairs {
   ($vec:expr, $pairs:expr) => {
     $vec.extend($pairs.iter().map(|replaced| {
       let decl_name = replaced[0];
       let decl_value = replaced[1];
       (
         String::from(decl_name),
         0 as u32,
         decl_name.len() as u32,
         String::from(decl_value),
         0 as u32,
         decl_value.len() as u32,
       )
     }));
   };
 }

Also update all usages of this macro throughout the file.


261-275: Avoid unnecessary String allocations in flex value transformation

The code creates temporary String objects from JsString slices only to immediately borrow them as &str. This causes unnecessary allocations.

Consider storing the slice bounds and creating strings only when needed:

         // flex: <flex-grow> <flex-shrink> <flex-basis>
-        // &value[val_fields[0]..val_fields[1]]
-        let transformed_flex_values = &[
-          &[
-            FLEX_GROW_CSS_VAR_NAME,
-            &String::from(value.slice(val_fields[0], val_fields[1])),
-          ],
-          &[
-            FLEX_SHRINK_CSS_VAR_NAME,
-            &String::from(value.slice(val_fields[2], val_fields[3])),
-          ],
-          &[
-            FLEX_BASIS_CSS_VAR_NAME,
-            &String::from(value.slice(val_fields[4], val_fields[5])),
-          ],
-        ];
-        push_u16_decl_pairs!(result, transformed_flex_values);
+        result.push((
+          String::from(FLEX_GROW_CSS_VAR_NAME),
+          0,
+          FLEX_GROW_CSS_VAR_NAME.len() as u32,
+          String::from(value),
+          val_fields[0],
+          val_fields[1],
+        ));
+        result.push((
+          String::from(FLEX_SHRINK_CSS_VAR_NAME),
+          0,
+          FLEX_SHRINK_CSS_VAR_NAME.len() as u32,
+          String::from(value),
+          val_fields[2],
+          val_fields[3],
+        ));
+        result.push((
+          String::from(FLEX_BASIS_CSS_VAR_NAME),
+          0,
+          FLEX_BASIS_CSS_VAR_NAME.len() as u32,
+          String::from(value),
+          val_fields[4],
+          val_fields[5],
+        ));
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7a1286d and b4a072f.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (15)
  • .changeset/config.json (1 hunks)
  • .changeset/cyan-comics-glow.md (1 hunks)
  • packages/web-platform/inline-style-parser/Cargo.toml (1 hunks)
  • packages/web-platform/inline-style-parser/src/char_code_definitions.rs (7 hunks)
  • packages/web-platform/inline-style-parser/src/lib.rs (33 hunks)
  • packages/web-platform/inline-style-parser/src/parse_inline_style.rs (4 hunks)
  • packages/web-platform/inline-style-parser/src/tokenize.rs (9 hunks)
  • packages/web-platform/inline-style-parser/src/types.rs (1 hunks)
  • packages/web-platform/inline-style-parser/src/utils.rs (9 hunks)
  • packages/web-platform/web-mainthread-apis/src/utils/tokenizer.ts (3 hunks)
  • packages/web-platform/web-style-transformer/Cargo.toml (1 hunks)
  • packages/web-platform/web-style-transformer/src/lib.rs (3 hunks)
  • packages/web-platform/web-style-transformer/src/transformer/constants.rs (2 hunks)
  • packages/web-platform/web-style-transformer/src/transformer/rules.rs (1 hunks)
  • packages/web-platform/web-style-transformer/src/transformer/transform.rs (19 hunks)
✅ Files skipped from review due to trivial changes (3)
  • packages/web-platform/inline-style-parser/src/types.rs
  • .changeset/config.json
  • packages/web-platform/inline-style-parser/Cargo.toml
🚧 Files skipped from review as they are similar to previous changes (10)
  • .changeset/cyan-comics-glow.md
  • packages/web-platform/web-style-transformer/Cargo.toml
  • packages/web-platform/web-mainthread-apis/src/utils/tokenizer.ts
  • packages/web-platform/inline-style-parser/src/utils.rs
  • packages/web-platform/inline-style-parser/src/parse_inline_style.rs
  • packages/web-platform/web-style-transformer/src/transformer/rules.rs
  • packages/web-platform/web-style-transformer/src/lib.rs
  • packages/web-platform/inline-style-parser/src/char_code_definitions.rs
  • packages/web-platform/inline-style-parser/src/tokenize.rs
  • packages/web-platform/web-style-transformer/src/transformer/constants.rs
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: colinaaa
PR: lynx-family/lynx-stack#1330
File: .changeset/olive-animals-attend.md:1-3
Timestamp: 2025-07-22T09:23:07.797Z
Learning: In the lynx-family/lynx-stack repository, changesets are only required for meaningful changes to end-users such as bugfixes and features. Internal/development changes like chores, refactoring, or removing debug info do not need changeset entries.
Learnt from: PupilTong
PR: lynx-family/lynx-stack#1029
File: packages/web-platform/web-mainthread-apis/src/createMainThreadGlobalThis.ts:214-217
Timestamp: 2025-07-16T06:25:41.055Z
Learning: In the lynx-stack codebase, CSS strings produced by `genCssContent` are considered trusted developer input, so additional sanitization/escaping is not required.
Learnt from: PupilTong
PR: lynx-family/lynx-stack#1029
File: packages/web-platform/web-core/src/uiThread/createRenderAllOnUI.ts:95-99
Timestamp: 2025-07-16T06:28:26.463Z
Learning: In the lynx-stack codebase, CSS selectors in SSR hydration are generated by their own packages, ensuring a predictable format that makes simple string manipulation safe and preferable over regex for performance reasons.
Learnt from: PupilTong
PR: lynx-family/lynx-stack#1029
File: packages/web-platform/web-core/src/uiThread/createRenderAllOnUI.ts:95-99
Timestamp: 2025-07-16T05:57:29.837Z
Learning: In the lynx-stack codebase, PupilTong prefers avoiding regex for parsing in performance-critical code paths like SSR hydration, preferring simple string manipulation operations even if they're less robust, when the input format is predictable and controlled.
🧬 Code Graph Analysis (1)
packages/web-platform/inline-style-parser/src/lib.rs (3)
packages/web-platform/inline-style-parser/src/utils.rs (7)
  • cmp_str (3-26)
  • find_white_space_end (28-38)
  • find_decimal_number_end (40-50)
  • consume_number (110-177)
  • consume_name (81-107)
  • consume_escaped (53-77)
  • consume_bad_url_remnants (182-204)
packages/web-platform/inline-style-parser/src/parse_inline_style.rs (1)
  • on_token (26-129)
packages/web-platform/inline-style-parser/src/tokenize.rs (2)
  • on_token (254-254)
  • tokenize (257-544)

@Sherry-hue Sherry-hue force-pushed the feat/style-parser-string branch from b4a072f to 3446aac Compare July 29, 2025 12:14
@relativeci
Copy link

relativeci bot commented Jul 29, 2025

Web Explorer

#3418 Bundle Size — 395.55KiB (+12.21%).

5f3a2c7(current) vs 54eb5bf main#3410(baseline)

Bundle metrics  Change 3 changes
                 Current
#3418
     Baseline
#3410
No change  Initial JS 142.12KiB 142.12KiB
No change  Initial CSS 31.83KiB 31.83KiB
Change  Cache Invalidation 9.51% 0%
No change  Chunks 7 7
No change  Assets 7 7
Change  Modules 215(+0.94%) 213
No change  Duplicate Modules 17 17
Change  Duplicate Code 3.71%(-5.84%) 3.94%
No change  Packages 4 4
No change  Duplicate Packages 0 0
Bundle size by type  Change 2 changes Regression 2 regressions
                 Current
#3418
     Baseline
#3410
Regression  JS 228.69KiB (+1.01%) 226.4KiB
Regression  Other 135.04KiB (+43.21%) 94.29KiB
No change  CSS 31.83KiB 31.83KiB

Bundle analysis reportBranch Sherry-hue:feat/style-parser-str...Project dashboard


Generated by RelativeCIDocumentationReport issue

@relativeci
Copy link

relativeci bot commented Jul 29, 2025

React Example

#3428 Bundle Size — 235.18KiB (0%).

5f3a2c7(current) vs 54eb5bf main#3420(baseline)

Bundle metrics  no changes
                 Current
#3428
     Baseline
#3420
No change  Initial JS 0B 0B
No change  Initial CSS 0B 0B
No change  Cache Invalidation 0% 0%
No change  Chunks 0 0
No change  Assets 4 4
No change  Modules 156 156
No change  Duplicate Modules 63 63
No change  Duplicate Code 45.94% 45.94%
No change  Packages 2 2
No change  Duplicate Packages 0 0
Bundle size by type  no changes
                 Current
#3428
     Baseline
#3420
No change  IMG 145.76KiB 145.76KiB
No change  Other 89.42KiB 89.42KiB

Bundle analysis reportBranch Sherry-hue:feat/style-parser-str...Project dashboard


Generated by RelativeCIDocumentationReport issue

@Sherry-hue Sherry-hue force-pushed the feat/style-parser-string branch from 3446aac to 5f3a2c7 Compare July 29, 2025 12:40
Copy link
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: 4

🔭 Outside diff range comments (2)
packages/web-platform/web-style-transformer/src/lib.rs (1)

121-139: Remove unused malloc/free APIs from web-style-transformer

The RG search shows no live uses of these functions (only commented-out frees in tokenizer.ts), so after the JsString migration we can drop both Rust and TS bits:

• In packages/web-platform/web-style-transformer/src/lib.rs
– Remove pub fn malloc(size: usize)…
– Remove #[wasm_bindgen] pub unsafe fn free(ptr: *mut u8, size: usize)…

• In packages/web-platform/web-style-transformer/standard.d.ts
– Delete the export function malloc(size: number): number; and export function free(ptr: number, size: number): void; declarations

This cleans up dead code and simplifies the public API.

packages/web-platform/web-style-transformer/src/transformer/transform.rs (1)

36-47: Fix potential type mismatch in digit checking macro.

The is_digit_only macro compares character codes with u16 byte values, but JsString::char_code_at() returns f64. This could cause incorrect comparisons.

 macro_rules! is_digit_only {
   ($source:expr, $start:expr, $end:expr) => {{
     let mut result = true;
-    for code in $source.slice($start, $end).iter() {
-      if code > b'9' as u16 || code < b'0' as u16 {
+    for i in $start..$end {
+      let code = $source.char_code_at(i) as u32;
+      if code > b'9' as u32 || code < b'0' as u32 {
         result = false;
         break;
       }
     }
     result
   }};
 }
♻️ Duplicate comments (5)
packages/web-platform/web-style-transformer/src/transformer/rules.rs (1)

31-42: Critical issue: REPLACE_RULE map is incomplete and will break functionality.

The REPLACE_RULE map only contains display rules, but all other transformation rules (direction, linear-orientation, linear-direction, linear-gravity, etc.) that were previously defined are now commented out. This will cause rule replacement functionality to fail for most CSS properties.

You need to either:

  1. Migrate the commented UTF-16 rules to string-based equivalents, or
  2. Ensure this is intentional and update dependent code to handle missing rules gracefully
    map.insert("display", display_map);
+    
+    // Add the missing rule maps that were commented out
+    // Direction rules, linear-orientation rules, etc. need to be restored
+    // as string-based equivalents
packages/web-platform/web-style-transformer/src/lib.rs (1)

97-118: Remove unnecessary unsafe block.

The unsafe block is no longer needed since the function now uses JsString parameters instead of raw pointers, and no unsafe operations are performed within the block.

-  unsafe {
-    // let name_slice = core::slice::from_raw_parts(name_ptr, name_len);
-    // let value_slice = core::slice::from_raw_parts(value_ptr, value_len);
     // Call the tokenize function with our data and callback
     let (result, children_result) = transformer::transform::query_transform_rules(
-      &name_ptr, 0 as u32, name_len, &value_ptr, 0 as u32, value_len,
+      &name_ptr, 0, name_len, &value_ptr, 0, value_len,
     );
     // ... rest of the function
     Some(ret)
-  }
packages/web-platform/web-style-transformer/src/transformer/transform.rs (3)

348-355: Fix incorrect string slicing in Transformer implementation.

The code attempts to slice String objects using array indexing, which doesn't work in Rust. Strings must be sliced using byte indices, and the current approach may cause panics.

         // Append the declaration name and colon
-        self.transformed_source.push(String::from(
-          &decl_name[*decl_name_start as usize..*decl_name_end as usize],
-        ));
+        self.transformed_source.push(
+          decl_name[*decl_name_start as usize..*decl_name_end as usize].to_string()
+        );
         self.transformed_source.push(String::from(":"));
         // Append the declaration value
-        self.transformed_source.push(String::from(
-          &decl_value[*decl_value_start as usize..*decl_value_end as usize],
-        ));
+        self.transformed_source.push(
+          decl_value[*decl_value_start as usize..*decl_value_end as usize].to_string()
+        );

370-377: Fix string slicing in children styles as well.

The same string slicing issue exists in the children styles processing code.

Apply the same fix as above:

         // Append the declaration name and colon
-        self.extra_children_styles.push(String::from(
-          &decl_name[*decl_name_start as usize..*decl_name_end as usize],
-        ));
+        self.extra_children_styles.push(
+          decl_name[*decl_name_start as usize..*decl_name_end as usize].to_string()
+        );
         self.extra_children_styles.push(String::from(":"));
         // Append the declaration value
-        self.extra_children_styles.push(String::from(
-          &decl_value[*decl_value_start as usize..*decl_value_end as usize],
-        ));
+        self.extra_children_styles.push(
+          decl_value[*decl_value_start as usize..*decl_value_end as usize].to_string()
+        );

406-411: Optimize string concatenation and handle remaining content.

The current implementation uses flat_map over characters which is inefficient for string concatenation, and doesn't handle remaining content after the last declaration.

 pub fn transform_inline_style_string<'a>(source: &'a js_sys::JsString) -> String {
   let mut transformer: TransformerData<'a> = TransformerData {
     source,
     transformed_source: Vec::new(),
     offset: 0,
     extra_children_styles: Vec::new(),
   };
   parse_inline_style::parse_inline_style(source, &mut transformer);
-  // if transformer.offset != 0 {
-  //   // append the remaining part of the source
-  //   transformer
-  //     .transformed_source
-  //     .extend_from_slice(&source[transformer.offset..]);
-  // }
-  // String::from_utf16(&transformer.transformed_source).unwrap()
-  // console::log_1(&transformer.transformed_source);
-  transformer
-    .transformed_source
-    .iter()
-    .flat_map(|s| s.chars())
-    .collect()
-  // transformer.transformed_source
+  
+  // Append any remaining content after the last declaration
+  if transformer.offset < source.length() {
+    transformer.transformed_source.push(
+      String::from(source.slice(transformer.offset, source.length()))
+    );
+  }
+  
+  // Efficiently join all strings
+  transformer.transformed_source.join("")
 }
🧹 Nitpick comments (2)
packages/web-platform/web-style-transformer/src/transformer/rules.rs (1)

268-291: Optimize macro string conversions for better performance.

The macros are converting JsString slices to String objects for every lookup, which creates unnecessary allocations. Consider caching the string conversion or using a more efficient lookup approach.

macro_rules! get_rename_rule_value {
  ($name_slice:expr, $start:expr, $end:expr) => {
    crate::transformer::rules::RENAME_RULE
-      .get(&*String::from(
-        $name_slice.slice($start as u32, $end as u32),
-      ))
+      .get($name_slice.slice($start as u32, $end as u32).as_string()?.as_str())
      .copied()
  };
}
packages/web-platform/web-style-transformer/src/lib.rs (1)

71-72: Optimize macro string slicing for better performance.

The macro creates string slices that could be optimized to avoid unnecessary allocations when creating JsString objects from string slices.

-      let k = js_sys::JsString::from(&name_source[name_start as usize..name_end as usize]);
-      let v = js_sys::JsString::from(&value_source[value_start as usize..value_end as usize]);
+      let k = js_sys::JsString::from(&name_source[name_start as usize..name_end as usize]);
+      let v = js_sys::JsString::from(&value_source[value_start as usize..value_end as usize]);
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3446aac and 5f3a2c7.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (15)
  • .changeset/config.json (1 hunks)
  • .changeset/cyan-comics-glow.md (1 hunks)
  • packages/web-platform/inline-style-parser/Cargo.toml (1 hunks)
  • packages/web-platform/inline-style-parser/src/char_code_definitions.rs (7 hunks)
  • packages/web-platform/inline-style-parser/src/lib.rs (33 hunks)
  • packages/web-platform/inline-style-parser/src/parse_inline_style.rs (4 hunks)
  • packages/web-platform/inline-style-parser/src/tokenize.rs (9 hunks)
  • packages/web-platform/inline-style-parser/src/utils.rs (9 hunks)
  • packages/web-platform/web-mainthread-apis/src/utils/tokenizer.ts (3 hunks)
  • packages/web-platform/web-style-transformer/Cargo.toml (1 hunks)
  • packages/web-platform/web-style-transformer/src/lib.rs (3 hunks)
  • packages/web-platform/web-style-transformer/src/transformer/constants.rs (2 hunks)
  • packages/web-platform/web-style-transformer/src/transformer/rules.rs (1 hunks)
  • packages/web-platform/web-style-transformer/src/transformer/transform.rs (19 hunks)
  • packages/web-platform/web-style-transformer/standard.d.ts (2 hunks)
✅ Files skipped from review due to trivial changes (1)
  • packages/web-platform/inline-style-parser/Cargo.toml
🚧 Files skipped from review as they are similar to previous changes (11)
  • .changeset/cyan-comics-glow.md
  • packages/web-platform/web-mainthread-apis/src/utils/tokenizer.ts
  • packages/web-platform/web-style-transformer/Cargo.toml
  • packages/web-platform/inline-style-parser/src/utils.rs
  • .changeset/config.json
  • packages/web-platform/web-style-transformer/standard.d.ts
  • packages/web-platform/inline-style-parser/src/parse_inline_style.rs
  • packages/web-platform/inline-style-parser/src/tokenize.rs
  • packages/web-platform/web-style-transformer/src/transformer/constants.rs
  • packages/web-platform/inline-style-parser/src/lib.rs
  • packages/web-platform/inline-style-parser/src/char_code_definitions.rs
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: colinaaa
PR: lynx-family/lynx-stack#1330
File: .changeset/olive-animals-attend.md:1-3
Timestamp: 2025-07-22T09:23:07.797Z
Learning: In the lynx-family/lynx-stack repository, changesets are only required for meaningful changes to end-users such as bugfixes and features. Internal/development changes like chores, refactoring, or removing debug info do not need changeset entries.
Learnt from: PupilTong
PR: lynx-family/lynx-stack#1029
File: packages/web-platform/web-mainthread-apis/src/createMainThreadGlobalThis.ts:214-217
Timestamp: 2025-07-16T06:25:41.055Z
Learning: In the lynx-stack codebase, CSS strings produced by `genCssContent` are considered trusted developer input, so additional sanitization/escaping is not required.
packages/web-platform/web-style-transformer/src/lib.rs (1)

Learnt from: PupilTong
PR: #1029
File: packages/web-platform/web-mainthread-apis/src/createMainThreadGlobalThis.ts:214-217
Timestamp: 2025-07-16T06:25:41.055Z
Learning: In the lynx-stack codebase, CSS strings produced by genCssContent are considered trusted developer input, so additional sanitization/escaping is not required.

packages/web-platform/web-style-transformer/src/transformer/transform.rs (1)

Learnt from: PupilTong
PR: #1029
File: packages/web-platform/web-mainthread-apis/src/createMainThreadGlobalThis.ts:214-217
Timestamp: 2025-07-16T06:25:41.055Z
Learning: In the lynx-stack codebase, CSS strings produced by genCssContent are considered trusted developer input, so additional sanitization/escaping is not required.

🔇 Additional comments (1)
packages/web-platform/web-style-transformer/src/transformer/transform.rs (1)

418-662: Excellent test coverage for the refactored functionality.

The comprehensive test suite has been successfully updated to work with js_sys::JsString inputs and covers various transformation scenarios including flex properties, color handling, and complex CSS rules. This maintains good test coverage during the migration.

Comment on lines +44 to +262
// pub static ref REPLACE_RULE: HashMap<&'static [u16], HashMap<&'static [u16], &'static [[&'static [u16]; 2]]>> = {
// let mut map = HashMap::new();

// Linear orientation rules
let mut linear_orientation_map = HashMap::new();
linear_orientation_map.insert(HORIZONTAL_STR_U16, &[
[LYNX_LINEAR_ORIENTATION_STR_U16, HORIZONTAL_STR_U16],
[LYNX_LINEAR_ORIENTATION_TOGGLE_STR_U16, LYNX_LINEAR_ORIENTATION_TOGGLE_HORIZONTAL_VALUE_STR_U16],
] as &[[&[u16]; 2]]);
linear_orientation_map.insert(HORIZONTAL_REVERSE_STR_U16, &[
[LYNX_LINEAR_ORIENTATION_STR_U16, HORIZONTAL_REVERSE_STR_U16],
[LYNX_LINEAR_ORIENTATION_TOGGLE_STR_U16, LYNX_LINEAR_ORIENTATION_TOGGLE_HORIZONTAL_REVERSE_VALUE_STR_U16],
] as &[[&[u16]; 2]]);
linear_orientation_map.insert(VERTICAL_STR_U16, &[
[LYNX_LINEAR_ORIENTATION_STR_U16, VERTICAL_STR_U16],
[LYNX_LINEAR_ORIENTATION_TOGGLE_STR_U16, LYNX_LINEAR_ORIENTATION_TOGGLE_VERTICAL_VALUE_STR_U16],
] as &[[&[u16]; 2]]);
linear_orientation_map.insert(VERTICAL_REVERSE_STR_U16, &[
[LYNX_LINEAR_ORIENTATION_STR_U16, VERTICAL_REVERSE_STR_U16],
[LYNX_LINEAR_ORIENTATION_TOGGLE_STR_U16, LYNX_LINEAR_ORIENTATION_TOGGLE_VERTICAL_REVERSE_VALUE_STR_U16],
] as &[[&[u16]; 2]]);
// // Display rules
// let mut display_map = HashMap::new();
// display_map.insert(LINEAR_STR_U16, &[
// [LYNX_DISPLAY_TOGGLE_STR_U16, LYNX_DISPLAY_LINEAR_VAR_STR_U16],
// [LYNX_DISPLAY_STR_U16, LINEAR_STR_U16],
// [DISPLAY_STR_U16, FLEX_STR_U16],
// ] as &[[&[u16]; 2]]);
// display_map.insert(FLEX_STR_U16, &[
// [LYNX_DISPLAY_TOGGLE_STR_U16, LYNX_DISPLAY_FLEX_VAR_STR_U16],
// [LYNX_DISPLAY_STR_U16, FLEX_STR_U16],
// [DISPLAY_STR_U16, FLEX_STR_U16],
// ] as &[[&[u16]; 2]]);

// Linear direction rules
let mut linear_direction_map = HashMap::new();
linear_direction_map.insert(ROW_STR_U16, &[
[LYNX_LINEAR_ORIENTATION_STR_U16, HORIZONTAL_STR_U16],
[LYNX_LINEAR_ORIENTATION_TOGGLE_STR_U16, LYNX_LINEAR_ORIENTATION_TOGGLE_HORIZONTAL_VALUE_STR_U16],
] as &[[&[u16]; 2]]);
linear_direction_map.insert(ROW_REVERSE_STR_U16, &[
[LYNX_LINEAR_ORIENTATION_STR_U16, HORIZONTAL_REVERSE_STR_U16],
[LYNX_LINEAR_ORIENTATION_TOGGLE_STR_U16, LYNX_LINEAR_ORIENTATION_TOGGLE_HORIZONTAL_REVERSE_VALUE_STR_U16],
] as &[[&[u16]; 2]]);
linear_direction_map.insert(COLUMN_STR_U16, &[
[LYNX_LINEAR_ORIENTATION_STR_U16, VERTICAL_STR_U16],
[LYNX_LINEAR_ORIENTATION_TOGGLE_STR_U16, LYNX_LINEAR_ORIENTATION_TOGGLE_VERTICAL_VALUE_STR_U16],
] as &[[&[u16]; 2]]);
linear_direction_map.insert(COLUMN_REVERSE_STR_U16, &[
[LYNX_LINEAR_ORIENTATION_STR_U16, VERTICAL_REVERSE_STR_U16],
[LYNX_LINEAR_ORIENTATION_TOGGLE_STR_U16, LYNX_LINEAR_ORIENTATION_TOGGLE_VERTICAL_REVERSE_VALUE_STR_U16],
] as &[[&[u16]; 2]]);
// // Direction rules
// let mut direction_map = HashMap::new();
// direction_map.insert(LYNX_RTL_STR_U16, &[
// [DIRECTION_STR_U16, RTL_STR_U16],
// ] as &[[&[u16]; 2]]);

// Linear gravity rules
let mut linear_gravity_map = HashMap::new();
linear_gravity_map.insert(TOP_STR_U16, &[
[JUSTIFY_CONTENT_COLUMN_STR_U16, FLEX_START_STR_U16],
[JUSTIFY_CONTENT_COLUMN_REVERSE_STR_U16, FLEX_END_STR_U16],
[JUSTIFY_CONTENT_ROW_STR_U16, FLEX_START_STR_U16],
[JUSTIFY_CONTENT_ROW_REVERSE_STR_U16, FLEX_START_STR_U16],
] as &[[&[u16]; 2]]);
linear_gravity_map.insert(BOTTOM_STR_U16, &[
[JUSTIFY_CONTENT_COLUMN_STR_U16, FLEX_END_STR_U16],
[JUSTIFY_CONTENT_COLUMN_REVERSE_STR_U16, FLEX_START_STR_U16],
[JUSTIFY_CONTENT_ROW_STR_U16, FLEX_START_STR_U16],
[JUSTIFY_CONTENT_ROW_REVERSE_STR_U16, FLEX_START_STR_U16],
] as &[[&[u16]; 2]]);
linear_gravity_map.insert(LEFT_STR_U16, &[
[JUSTIFY_CONTENT_COLUMN_STR_U16, FLEX_START_STR_U16],
[JUSTIFY_CONTENT_COLUMN_REVERSE_STR_U16, FLEX_START_STR_U16],
[JUSTIFY_CONTENT_ROW_STR_U16, FLEX_START_STR_U16],
[JUSTIFY_CONTENT_ROW_REVERSE_STR_U16, FLEX_END_STR_U16],
] as &[[&[u16]; 2]]);
linear_gravity_map.insert(RIGHT_STR_U16, &[
[JUSTIFY_CONTENT_COLUMN_STR_U16, FLEX_START_STR_U16],
[JUSTIFY_CONTENT_COLUMN_REVERSE_STR_U16, FLEX_START_STR_U16],
[JUSTIFY_CONTENT_ROW_STR_U16, FLEX_END_STR_U16],
[JUSTIFY_CONTENT_ROW_REVERSE_STR_U16, FLEX_START_STR_U16],
] as &[[&[u16]; 2]]);
linear_gravity_map.insert(CENTER_VERTICAL_STR_U16, &[
[JUSTIFY_CONTENT_COLUMN_STR_U16, CENTER_STR_U16],
[JUSTIFY_CONTENT_COLUMN_REVERSE_STR_U16, CENTER_STR_U16],
[JUSTIFY_CONTENT_ROW_STR_U16, FLEX_START_STR_U16],
[JUSTIFY_CONTENT_ROW_REVERSE_STR_U16, FLEX_START_STR_U16],
] as &[[&[u16]; 2]]);
linear_gravity_map.insert(CENTER_HORIZONTAL_STR_U16, &[
[JUSTIFY_CONTENT_COLUMN_STR_U16, FLEX_START_STR_U16],
[JUSTIFY_CONTENT_COLUMN_REVERSE_STR_U16, FLEX_START_STR_U16],
[JUSTIFY_CONTENT_ROW_STR_U16, CENTER_STR_U16],
[JUSTIFY_CONTENT_ROW_REVERSE_STR_U16, CENTER_STR_U16],
] as &[[&[u16]; 2]]);
linear_gravity_map.insert(START_STR_U16, &[
[JUSTIFY_CONTENT_COLUMN_STR_U16, FLEX_START_STR_U16],
[JUSTIFY_CONTENT_COLUMN_REVERSE_STR_U16, FLEX_START_STR_U16],
[JUSTIFY_CONTENT_ROW_STR_U16, FLEX_START_STR_U16],
[JUSTIFY_CONTENT_ROW_REVERSE_STR_U16, FLEX_START_STR_U16],
] as &[[&[u16]; 2]]);
linear_gravity_map.insert(END_STR_U16, &[
[JUSTIFY_CONTENT_COLUMN_STR_U16, FLEX_END_STR_U16],
[JUSTIFY_CONTENT_COLUMN_REVERSE_STR_U16, FLEX_END_STR_U16],
[JUSTIFY_CONTENT_ROW_STR_U16, FLEX_END_STR_U16],
[JUSTIFY_CONTENT_ROW_REVERSE_STR_U16, FLEX_END_STR_U16],
] as &[[&[u16]; 2]]);
linear_gravity_map.insert(CENTER_STR_U16, &[
[JUSTIFY_CONTENT_COLUMN_STR_U16, CENTER_STR_U16],
[JUSTIFY_CONTENT_COLUMN_REVERSE_STR_U16, CENTER_STR_U16],
[JUSTIFY_CONTENT_ROW_STR_U16, CENTER_STR_U16],
[JUSTIFY_CONTENT_ROW_REVERSE_STR_U16, CENTER_STR_U16],
] as &[[&[u16]; 2]]);
linear_gravity_map.insert(SPACE_BETWEEN_STR_U16, &[
[JUSTIFY_CONTENT_COLUMN_STR_U16, SPACE_BETWEEN_STR_U16],
[JUSTIFY_CONTENT_COLUMN_REVERSE_STR_U16, SPACE_BETWEEN_STR_U16],
[JUSTIFY_CONTENT_ROW_STR_U16, SPACE_BETWEEN_STR_U16],
[JUSTIFY_CONTENT_ROW_REVERSE_STR_U16, SPACE_BETWEEN_STR_U16],
] as &[[&[u16]; 2]]);
// // Linear orientation rules
// let mut linear_orientation_map = HashMap::new();
// linear_orientation_map.insert(HORIZONTAL_STR_U16, &[
// [LYNX_LINEAR_ORIENTATION_STR_U16, HORIZONTAL_STR_U16],
// [LYNX_LINEAR_ORIENTATION_TOGGLE_STR_U16, LYNX_LINEAR_ORIENTATION_TOGGLE_HORIZONTAL_VALUE_STR_U16],
// ] as &[[&[u16]; 2]]);
// linear_orientation_map.insert(HORIZONTAL_REVERSE_STR_U16, &[
// [LYNX_LINEAR_ORIENTATION_STR_U16, HORIZONTAL_REVERSE_STR_U16],
// [LYNX_LINEAR_ORIENTATION_TOGGLE_STR_U16, LYNX_LINEAR_ORIENTATION_TOGGLE_HORIZONTAL_REVERSE_VALUE_STR_U16],
// ] as &[[&[u16]; 2]]);
// linear_orientation_map.insert(VERTICAL_STR_U16, &[
// [LYNX_LINEAR_ORIENTATION_STR_U16, VERTICAL_STR_U16],
// [LYNX_LINEAR_ORIENTATION_TOGGLE_STR_U16, LYNX_LINEAR_ORIENTATION_TOGGLE_VERTICAL_VALUE_STR_U16],
// ] as &[[&[u16]; 2]]);
// linear_orientation_map.insert(VERTICAL_REVERSE_STR_U16, &[
// [LYNX_LINEAR_ORIENTATION_STR_U16, VERTICAL_REVERSE_STR_U16],
// [LYNX_LINEAR_ORIENTATION_TOGGLE_STR_U16, LYNX_LINEAR_ORIENTATION_TOGGLE_VERTICAL_REVERSE_VALUE_STR_U16],
// ] as &[[&[u16]; 2]]);

// Linear cross gravity rules
let mut linear_cross_gravity_map = HashMap::new();
linear_cross_gravity_map.insert(START_STR_U16, &[
[ALIGN_ITEMS_STR_U16, START_STR_U16],
] as &[[&[u16]; 2]]);
linear_cross_gravity_map.insert(END_STR_U16, &[
[ALIGN_ITEMS_STR_U16, END_STR_U16],
] as &[[&[u16]; 2]]);
linear_cross_gravity_map.insert(CENTER_STR_U16, &[
[ALIGN_ITEMS_STR_U16, CENTER_STR_U16],
] as &[[&[u16]; 2]]);
linear_cross_gravity_map.insert(STRETCH_STR_U16, &[
[ALIGN_ITEMS_STR_U16, STRETCH_STR_U16],
] as &[[&[u16]; 2]]);
// // Linear direction rules
// let mut linear_direction_map = HashMap::new();
// linear_direction_map.insert(ROW_STR_U16, &[
// [LYNX_LINEAR_ORIENTATION_STR_U16, HORIZONTAL_STR_U16],
// [LYNX_LINEAR_ORIENTATION_TOGGLE_STR_U16, LYNX_LINEAR_ORIENTATION_TOGGLE_HORIZONTAL_VALUE_STR_U16],
// ] as &[[&[u16]; 2]]);
// linear_direction_map.insert(ROW_REVERSE_STR_U16, &[
// [LYNX_LINEAR_ORIENTATION_STR_U16, HORIZONTAL_REVERSE_STR_U16],
// [LYNX_LINEAR_ORIENTATION_TOGGLE_STR_U16, LYNX_LINEAR_ORIENTATION_TOGGLE_HORIZONTAL_REVERSE_VALUE_STR_U16],
// ] as &[[&[u16]; 2]]);
// linear_direction_map.insert(COLUMN_STR_U16, &[
// [LYNX_LINEAR_ORIENTATION_STR_U16, VERTICAL_STR_U16],
// [LYNX_LINEAR_ORIENTATION_TOGGLE_STR_U16, LYNX_LINEAR_ORIENTATION_TOGGLE_VERTICAL_VALUE_STR_U16],
// ] as &[[&[u16]; 2]]);
// linear_direction_map.insert(COLUMN_REVERSE_STR_U16, &[
// [LYNX_LINEAR_ORIENTATION_STR_U16, VERTICAL_REVERSE_STR_U16],
// [LYNX_LINEAR_ORIENTATION_TOGGLE_STR_U16, LYNX_LINEAR_ORIENTATION_TOGGLE_VERTICAL_REVERSE_VALUE_STR_U16],
// ] as &[[&[u16]; 2]]);

// Linear layout gravity rules
let mut linear_layout_gravity_map = HashMap::new();
linear_layout_gravity_map.insert(NONE_STR_U16, &[
[ALIGN_SELF_ROW_STR_U16, AUTO_STR_U16],
[ALIGN_SELF_COLUMN_STR_U16, AUTO_STR_U16],
] as &[[&[u16]; 2]]);
linear_layout_gravity_map.insert(STRETCH_STR_U16, &[
[ALIGN_SELF_ROW_STR_U16, STRETCH_STR_U16],
[ALIGN_SELF_COLUMN_STR_U16, STRETCH_STR_U16],
] as &[[&[u16]; 2]]);
linear_layout_gravity_map.insert(TOP_STR_U16, &[
[ALIGN_SELF_ROW_STR_U16, START_STR_U16],
[ALIGN_SELF_COLUMN_STR_U16, AUTO_STR_U16],
] as &[[&[u16]; 2]]);
linear_layout_gravity_map.insert(BOTTOM_STR_U16, &[
[ALIGN_SELF_ROW_STR_U16, END_STR_U16],
[ALIGN_SELF_COLUMN_STR_U16, AUTO_STR_U16],
] as &[[&[u16]; 2]]);
linear_layout_gravity_map.insert(LEFT_STR_U16, &[
[ALIGN_SELF_ROW_STR_U16, AUTO_STR_U16],
[ALIGN_SELF_COLUMN_STR_U16, START_STR_U16],
] as &[[&[u16]; 2]]);
linear_layout_gravity_map.insert(RIGHT_STR_U16, &[
[ALIGN_SELF_ROW_STR_U16, AUTO_STR_U16],
[ALIGN_SELF_COLUMN_STR_U16, END_STR_U16],
] as &[[&[u16]; 2]]);
linear_layout_gravity_map.insert(START_STR_U16, &[
[ALIGN_SELF_ROW_STR_U16, START_STR_U16],
[ALIGN_SELF_COLUMN_STR_U16, START_STR_U16],
] as &[[&[u16]; 2]]);
linear_layout_gravity_map.insert(END_STR_U16, &[
[ALIGN_SELF_ROW_STR_U16, END_STR_U16],
[ALIGN_SELF_COLUMN_STR_U16, END_STR_U16],
] as &[[&[u16]; 2]]);
linear_layout_gravity_map.insert(CENTER_STR_U16, &[
[ALIGN_SELF_ROW_STR_U16, CENTER_STR_U16],
[ALIGN_SELF_COLUMN_STR_U16, CENTER_STR_U16],
] as &[[&[u16]; 2]]);
linear_layout_gravity_map.insert(CENTER_VERTICAL_STR_U16, &[
[ALIGN_SELF_ROW_STR_U16, CENTER_STR_U16],
[ALIGN_SELF_COLUMN_STR_U16, START_STR_U16],
] as &[[&[u16]; 2]]);
linear_layout_gravity_map.insert(CENTER_HORIZONTAL_STR_U16, &[
[ALIGN_SELF_ROW_STR_U16, START_STR_U16],
[ALIGN_SELF_COLUMN_STR_U16, CENTER_STR_U16],
] as &[[&[u16]; 2]]);
linear_layout_gravity_map.insert(FILL_VERTICAL_STR_U16, &[
[ALIGN_SELF_ROW_STR_U16, STRETCH_STR_U16],
[ALIGN_SELF_COLUMN_STR_U16, AUTO_STR_U16],
] as &[[&[u16]; 2]]);
linear_layout_gravity_map.insert(FILL_HORIZONTAL_STR_U16, &[
[ALIGN_SELF_ROW_STR_U16, AUTO_STR_U16],
[ALIGN_SELF_COLUMN_STR_U16, STRETCH_STR_U16],
] as &[[&[u16]; 2]]);
// // Linear gravity rules
// let mut linear_gravity_map = HashMap::new();
// linear_gravity_map.insert(TOP_STR_U16, &[
// [JUSTIFY_CONTENT_COLUMN_STR_U16, FLEX_START_STR_U16],
// [JUSTIFY_CONTENT_COLUMN_REVERSE_STR_U16, FLEX_END_STR_U16],
// [JUSTIFY_CONTENT_ROW_STR_U16, FLEX_START_STR_U16],
// [JUSTIFY_CONTENT_ROW_REVERSE_STR_U16, FLEX_START_STR_U16],
// ] as &[[&[u16]; 2]]);
// linear_gravity_map.insert(BOTTOM_STR_U16, &[
// [JUSTIFY_CONTENT_COLUMN_STR_U16, FLEX_END_STR_U16],
// [JUSTIFY_CONTENT_COLUMN_REVERSE_STR_U16, FLEX_START_STR_U16],
// [JUSTIFY_CONTENT_ROW_STR_U16, FLEX_START_STR_U16],
// [JUSTIFY_CONTENT_ROW_REVERSE_STR_U16, FLEX_START_STR_U16],
// ] as &[[&[u16]; 2]]);
// linear_gravity_map.insert(LEFT_STR_U16, &[
// [JUSTIFY_CONTENT_COLUMN_STR_U16, FLEX_START_STR_U16],
// [JUSTIFY_CONTENT_COLUMN_REVERSE_STR_U16, FLEX_START_STR_U16],
// [JUSTIFY_CONTENT_ROW_STR_U16, FLEX_START_STR_U16],
// [JUSTIFY_CONTENT_ROW_REVERSE_STR_U16, FLEX_END_STR_U16],
// ] as &[[&[u16]; 2]]);
// linear_gravity_map.insert(RIGHT_STR_U16, &[
// [JUSTIFY_CONTENT_COLUMN_STR_U16, FLEX_START_STR_U16],
// [JUSTIFY_CONTENT_COLUMN_REVERSE_STR_U16, FLEX_START_STR_U16],
// [JUSTIFY_CONTENT_ROW_STR_U16, FLEX_END_STR_U16],
// [JUSTIFY_CONTENT_ROW_REVERSE_STR_U16, FLEX_START_STR_U16],
// ] as &[[&[u16]; 2]]);
// linear_gravity_map.insert(CENTER_VERTICAL_STR_U16, &[
// [JUSTIFY_CONTENT_COLUMN_STR_U16, CENTER_STR_U16],
// [JUSTIFY_CONTENT_COLUMN_REVERSE_STR_U16, CENTER_STR_U16],
// [JUSTIFY_CONTENT_ROW_STR_U16, FLEX_START_STR_U16],
// [JUSTIFY_CONTENT_ROW_REVERSE_STR_U16, FLEX_START_STR_U16],
// ] as &[[&[u16]; 2]]);
// linear_gravity_map.insert(CENTER_HORIZONTAL_STR_U16, &[
// [JUSTIFY_CONTENT_COLUMN_STR_U16, FLEX_START_STR_U16],
// [JUSTIFY_CONTENT_COLUMN_REVERSE_STR_U16, FLEX_START_STR_U16],
// [JUSTIFY_CONTENT_ROW_STR_U16, CENTER_STR_U16],
// [JUSTIFY_CONTENT_ROW_REVERSE_STR_U16, CENTER_STR_U16],
// ] as &[[&[u16]; 2]]);
// linear_gravity_map.insert(START_STR_U16, &[
// [JUSTIFY_CONTENT_COLUMN_STR_U16, FLEX_START_STR_U16],
// [JUSTIFY_CONTENT_COLUMN_REVERSE_STR_U16, FLEX_START_STR_U16],
// [JUSTIFY_CONTENT_ROW_STR_U16, FLEX_START_STR_U16],
// [JUSTIFY_CONTENT_ROW_REVERSE_STR_U16, FLEX_START_STR_U16],
// ] as &[[&[u16]; 2]]);
// linear_gravity_map.insert(END_STR_U16, &[
// [JUSTIFY_CONTENT_COLUMN_STR_U16, FLEX_END_STR_U16],
// [JUSTIFY_CONTENT_COLUMN_REVERSE_STR_U16, FLEX_END_STR_U16],
// [JUSTIFY_CONTENT_ROW_STR_U16, FLEX_END_STR_U16],
// [JUSTIFY_CONTENT_ROW_REVERSE_STR_U16, FLEX_END_STR_U16],
// ] as &[[&[u16]; 2]]);
// linear_gravity_map.insert(CENTER_STR_U16, &[
// [JUSTIFY_CONTENT_COLUMN_STR_U16, CENTER_STR_U16],
// [JUSTIFY_CONTENT_COLUMN_REVERSE_STR_U16, CENTER_STR_U16],
// [JUSTIFY_CONTENT_ROW_STR_U16, CENTER_STR_U16],
// [JUSTIFY_CONTENT_ROW_REVERSE_STR_U16, CENTER_STR_U16],
// ] as &[[&[u16]; 2]]);
// linear_gravity_map.insert(SPACE_BETWEEN_STR_U16, &[
// [JUSTIFY_CONTENT_COLUMN_STR_U16, SPACE_BETWEEN_STR_U16],
// [JUSTIFY_CONTENT_COLUMN_REVERSE_STR_U16, SPACE_BETWEEN_STR_U16],
// [JUSTIFY_CONTENT_ROW_STR_U16, SPACE_BETWEEN_STR_U16],
// [JUSTIFY_CONTENT_ROW_REVERSE_STR_U16, SPACE_BETWEEN_STR_U16],
// ] as &[[&[u16]; 2]]);

// Justify content rules
let mut justify_content_map = HashMap::new();
justify_content_map.insert(START_STR_U16, &[
[JUSTIFY_CONTENT_STR_U16, FLEX_START_STR_U16],
] as &[[&[u16]; 2]]);
justify_content_map.insert(END_STR_U16, &[
[JUSTIFY_CONTENT_STR_U16, FLEX_END_STR_U16],
] as &[[&[u16]; 2]]);
justify_content_map.insert(LEFT_STR_U16, &[
[INVALID_STR_U16,INVALID_STR_U16],
] as &[[&[u16]; 2]]);
justify_content_map.insert(RIGHT_STR_U16, &[
[INVALID_STR_U16,INVALID_STR_U16],
] as &[[&[u16]; 2]]);
// // Linear cross gravity rules
// let mut linear_cross_gravity_map = HashMap::new();
// linear_cross_gravity_map.insert(START_STR_U16, &[
// [ALIGN_ITEMS_STR_U16, START_STR_U16],
// ] as &[[&[u16]; 2]]);
// linear_cross_gravity_map.insert(END_STR_U16, &[
// [ALIGN_ITEMS_STR_U16, END_STR_U16],
// ] as &[[&[u16]; 2]]);
// linear_cross_gravity_map.insert(CENTER_STR_U16, &[
// [ALIGN_ITEMS_STR_U16, CENTER_STR_U16],
// ] as &[[&[u16]; 2]]);
// linear_cross_gravity_map.insert(STRETCH_STR_U16, &[
// [ALIGN_ITEMS_STR_U16, STRETCH_STR_U16],
// ] as &[[&[u16]; 2]]);

map.insert(DISPLAY_STR_U16, display_map);
map.insert(DIRECTION_STR_U16, direction_map);
map.insert(LINEAR_ORIENTATION_STR_U16, linear_orientation_map);
map.insert(LINEAR_DIRECTION_STR_U16, linear_direction_map);
map.insert(LINEAR_GRAVITY_STR_U16, linear_gravity_map);
map.insert(LINEAR_CROSS_GRAVITY_STR_U16, linear_cross_gravity_map);
map.insert(LINEAR_LAYOUT_GRAVITY_STR_U16, linear_layout_gravity_map);
map.insert(JUSTIFY_CONTENT_STR_U16, justify_content_map);
// // Linear layout gravity rules
// let mut linear_layout_gravity_map = HashMap::new();
// linear_layout_gravity_map.insert(NONE_STR_U16, &[
// [ALIGN_SELF_ROW_STR_U16, AUTO_STR_U16],
// [ALIGN_SELF_COLUMN_STR_U16, AUTO_STR_U16],
// ] as &[[&[u16]; 2]]);
// linear_layout_gravity_map.insert(STRETCH_STR_U16, &[
// [ALIGN_SELF_ROW_STR_U16, STRETCH_STR_U16],
// [ALIGN_SELF_COLUMN_STR_U16, STRETCH_STR_U16],
// ] as &[[&[u16]; 2]]);
// linear_layout_gravity_map.insert(TOP_STR_U16, &[
// [ALIGN_SELF_ROW_STR_U16, START_STR_U16],
// [ALIGN_SELF_COLUMN_STR_U16, AUTO_STR_U16],
// ] as &[[&[u16]; 2]]);
// linear_layout_gravity_map.insert(BOTTOM_STR_U16, &[
// [ALIGN_SELF_ROW_STR_U16, END_STR_U16],
// [ALIGN_SELF_COLUMN_STR_U16, AUTO_STR_U16],
// ] as &[[&[u16]; 2]]);
// linear_layout_gravity_map.insert(LEFT_STR_U16, &[
// [ALIGN_SELF_ROW_STR_U16, AUTO_STR_U16],
// [ALIGN_SELF_COLUMN_STR_U16, START_STR_U16],
// ] as &[[&[u16]; 2]]);
// linear_layout_gravity_map.insert(RIGHT_STR_U16, &[
// [ALIGN_SELF_ROW_STR_U16, AUTO_STR_U16],
// [ALIGN_SELF_COLUMN_STR_U16, END_STR_U16],
// ] as &[[&[u16]; 2]]);
// linear_layout_gravity_map.insert(START_STR_U16, &[
// [ALIGN_SELF_ROW_STR_U16, START_STR_U16],
// [ALIGN_SELF_COLUMN_STR_U16, START_STR_U16],
// ] as &[[&[u16]; 2]]);
// linear_layout_gravity_map.insert(END_STR_U16, &[
// [ALIGN_SELF_ROW_STR_U16, END_STR_U16],
// [ALIGN_SELF_COLUMN_STR_U16, END_STR_U16],
// ] as &[[&[u16]; 2]]);
// linear_layout_gravity_map.insert(CENTER_STR_U16, &[
// [ALIGN_SELF_ROW_STR_U16, CENTER_STR_U16],
// [ALIGN_SELF_COLUMN_STR_U16, CENTER_STR_U16],
// ] as &[[&[u16]; 2]]);
// linear_layout_gravity_map.insert(CENTER_VERTICAL_STR_U16, &[
// [ALIGN_SELF_ROW_STR_U16, CENTER_STR_U16],
// [ALIGN_SELF_COLUMN_STR_U16, START_STR_U16],
// ] as &[[&[u16]; 2]]);
// linear_layout_gravity_map.insert(CENTER_HORIZONTAL_STR_U16, &[
// [ALIGN_SELF_ROW_STR_U16, START_STR_U16],
// [ALIGN_SELF_COLUMN_STR_U16, CENTER_STR_U16],
// ] as &[[&[u16]; 2]]);
// linear_layout_gravity_map.insert(FILL_VERTICAL_STR_U16, &[
// [ALIGN_SELF_ROW_STR_U16, STRETCH_STR_U16],
// [ALIGN_SELF_COLUMN_STR_U16, AUTO_STR_U16],
// ] as &[[&[u16]; 2]]);
// linear_layout_gravity_map.insert(FILL_HORIZONTAL_STR_U16, &[
// [ALIGN_SELF_ROW_STR_U16, AUTO_STR_U16],
// [ALIGN_SELF_COLUMN_STR_U16, STRETCH_STR_U16],
// ] as &[[&[u16]; 2]]);

map
};
// // Justify content rules
// let mut justify_content_map = HashMap::new();
// justify_content_map.insert(START_STR_U16, &[
// [JUSTIFY_CONTENT_STR_U16, FLEX_START_STR_U16],
// ] as &[[&[u16]; 2]]);
// justify_content_map.insert(END_STR_U16, &[
// [JUSTIFY_CONTENT_STR_U16, FLEX_END_STR_U16],
// ] as &[[&[u16]; 2]]);
// justify_content_map.insert(LEFT_STR_U16, &[
// [INVALID_STR_U16,INVALID_STR_U16],
// ] as &[[&[u16]; 2]]);
// justify_content_map.insert(RIGHT_STR_U16, &[
// [INVALID_STR_U16,INVALID_STR_U16],
// ] as &[[&[u16]; 2]]);

// map.insert(DISPLAY_STR_U16, display_map);
// map.insert(DIRECTION_STR_U16, direction_map);
// map.insert(LINEAR_ORIENTATION_STR_U16, linear_orientation_map);
// map.insert(LINEAR_DIRECTION_STR_U16, linear_direction_map);
// map.insert(LINEAR_GRAVITY_STR_U16, linear_gravity_map);
// map.insert(LINEAR_CROSS_GRAVITY_STR_U16, linear_cross_gravity_map);
// map.insert(LINEAR_LAYOUT_GRAVITY_STR_U16, linear_layout_gravity_map);
// map.insert(JUSTIFY_CONTENT_STR_U16, justify_content_map);

// map
// };
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Remove extensive commented code blocks.

The large blocks of commented UTF-16 code (200+ lines) should be removed if the migration to string-based approach is complete. Keeping this much commented code makes the file difficult to maintain and review.

Consider removing the commented blocks entirely since:

  1. The old implementation is preserved in version control
  2. The commented code makes the file unnecessarily long and hard to read
  3. It creates confusion about which implementation is active
🤖 Prompt for AI Agents
In packages/web-platform/web-style-transformer/src/transformer/rules.rs from
lines 44 to 262, remove the large blocks of commented-out UTF-16 code related to
the old implementation. Since the migration to the string-based approach is
complete, delete these commented sections entirely to improve code readability,
reduce file length, and avoid confusion about the active implementation. The old
code remains accessible in version control if needed.

Comment on lines +293 to +435
// #[cfg(test)]
// mod tests {
// use std::str::from_utf8;

use crate::str_to_u16_slice;
// use crate::str_to_u16_slice;

#[test]
fn test_rename_rule_flex_direction() {
let source = "flex-direction:row".as_bytes();
let source: Vec<u16> = source.iter().map(|&b| b as u16).collect();
let name_start = 0;
let name_end = source.len() - 4;
let result: &'static [u16] = get_rename_rule_value!(&source, name_start, name_end).unwrap();
assert_eq!(result, str_to_u16_slice!("--flex-direction"));
}
#[test]
fn test_rename_rule_flex_direction_at_mid() {
let source = "height:1px;flex-direction:row".as_bytes();
let offset = "height:1px;".len();
let source: Vec<u16> = source.iter().map(|&b| b as u16).collect();
let name_start = offset;
let name_end = source.len() - 4;
let result = get_rename_rule_value!(&source, name_start, name_end).unwrap();
assert_eq!(result, str_to_u16_slice!("--flex-direction"));
}
#[test]
fn test_replace_rule_display_linear() {
let source = "display:linear".as_bytes();
let source: Vec<u16> = source.iter().map(|&b| b as u16).collect();
let name_start = 0;
let name_end = 7;
let value_start = 8;
let value_end = source.len();
let result = get_replace_rule_value!(
&source,
name_start,
name_end,
&source,
value_start,
value_end
)
.unwrap()
.iter()
.map(|pair| {
let key = pair[0].iter().map(|&c| c as u8).collect::<Vec<u8>>();
let value = pair[1].iter().map(|&c| c as u8).collect::<Vec<u8>>();
format!(
"{}:{}",
from_utf8(&key).unwrap(),
from_utf8(&value).unwrap()
)
})
.collect::<Vec<_>>()
.join(";");
assert_eq!(
result,
"--lynx-display-toggle:var(--lynx-display-linear);--lynx-display:linear;display:flex"
);
}
#[test]
fn test_replace_rule_display_linear_at_mid() {
let source = "height:1px;display:linear".as_bytes();
let source: Vec<u16> = source.iter().map(|&b| b as u16).collect();
let offset = "height:1px;".len();
let name_start = offset;
let name_end = offset + 7;
let value_start = offset + 8;
let value_end = source.len();
let result = get_replace_rule_value!(
&source,
name_start,
name_end,
&source,
value_start,
value_end
)
.unwrap()
.iter()
.map(|pair| {
let key = pair[0].iter().map(|&c| c as u8).collect::<Vec<u8>>();
let value = pair[1].iter().map(|&c| c as u8).collect::<Vec<u8>>();
format!(
"{}:{}",
from_utf8(&key).unwrap(),
from_utf8(&value).unwrap()
)
})
.collect::<Vec<_>>()
.join(";");
assert_eq!(
result,
"--lynx-display-toggle:var(--lynx-display-linear);--lynx-display:linear;display:flex"
);
}
// #[test]
// fn test_rename_rule_flex_direction() {
// let source = "flex-direction:row".as_bytes();
// let source: Vec<u16> = source.iter().map(|&b| b as u16).collect();
// let name_start = 0;
// let name_end = source.len() - 4;
// let result: &'static [u16] = get_rename_rule_value!(&source, name_start, name_end).unwrap();
// assert_eq!(result, str_to_u16_slice!("--flex-direction"));
// }
// #[test]
// fn test_rename_rule_flex_direction_at_mid() {
// let source = "height:1px;flex-direction:row".as_bytes();
// let offset = "height:1px;".len();
// let source: Vec<u16> = source.iter().map(|&b| b as u16).collect();
// let name_start = offset;
// let name_end = source.len() - 4;
// let result = get_rename_rule_value!(&source, name_start, name_end).unwrap();
// assert_eq!(result, str_to_u16_slice!("--flex-direction"));
// }
// #[test]
// fn test_replace_rule_display_linear() {
// let source = "display:linear".as_bytes();
// let source: Vec<u16> = source.iter().map(|&b| b as u16).collect();
// let name_start = 0;
// let name_end = 7;
// let value_start = 8;
// let value_end = source.len();
// let result = get_replace_rule_value!(
// &source,
// name_start,
// name_end,
// &source,
// value_start,
// value_end
// )
// .unwrap()
// .iter()
// .map(|pair| {
// let key = pair[0].iter().map(|&c| c as u8).collect::<Vec<u8>>();
// let value = pair[1].iter().map(|&c| c as u8).collect::<Vec<u8>>();
// format!(
// "{}:{}",
// from_utf8(&key).unwrap(),
// from_utf8(&value).unwrap()
// )
// })
// .collect::<Vec<_>>()
// .join(";");
// assert_eq!(
// result,
// "--lynx-display-toggle:var(--lynx-display-linear);--lynx-display:linear;display:flex"
// );
// }
// #[test]
// fn test_replace_rule_display_linear_at_mid() {
// let source = "height:1px;display:linear".as_bytes();
// let source: Vec<u16> = source.iter().map(|&b| b as u16).collect();
// let offset = "height:1px;".len();
// let name_start = offset;
// let name_end = offset + 7;
// let value_start = offset + 8;
// let value_end = source.len();
// let result = get_replace_rule_value!(
// &source,
// name_start,
// name_end,
// &source,
// value_start,
// value_end
// )
// .unwrap()
// .iter()
// .map(|pair| {
// let key = pair[0].iter().map(|&c| c as u8).collect::<Vec<u8>>();
// let value = pair[1].iter().map(|&c| c as u8).collect::<Vec<u8>>();
// format!(
// "{}:{}",
// from_utf8(&key).unwrap(),
// from_utf8(&value).unwrap()
// )
// })
// .collect::<Vec<_>>()
// .join(";");
// assert_eq!(
// result,
// "--lynx-display-toggle:var(--lynx-display-linear);--lynx-display:linear;display:flex"
// );
// }

#[test]
fn test_rename_rule_not_exist() {
let source = "background-image:url(\"https://example.com\")".as_bytes();
let source: Vec<u16> = source.iter().map(|&b| b as u16).collect();
let name_start = 0;
let name_end = "background-image".len();
let result = get_rename_rule_value!(&source, name_start, name_end);
assert_eq!(result, None);
}
// #[test]
// fn test_rename_rule_not_exist() {
// let source = "background-image:url(\"https://example.com\")".as_bytes();
// let source: Vec<u16> = source.iter().map(|&b| b as u16).collect();
// let name_start = 0;
// let name_end = "background-image".len();
// let result = get_rename_rule_value!(&source, name_start, name_end);
// assert_eq!(result, None);
// }

#[test]
fn test_replace_rule_value_not_match() {
let source = "display:grid".as_bytes();
let source: Vec<u16> = source.iter().map(|&b| b as u16).collect();
let name_start = 0;
let name_end = 7;
let value_start = 8;
let value_end = source.len();
let result = get_replace_rule_value!(
&source,
name_start,
name_end,
&source,
value_start,
value_end
);
assert_eq!(result, None);
}
// #[test]
// fn test_replace_rule_value_not_match() {
// let source = "display:grid".as_bytes();
// let source: Vec<u16> = source.iter().map(|&b| b as u16).collect();
// let name_start = 0;
// let name_end = 7;
// let value_start = 8;
// let value_end = source.len();
// let result = get_replace_rule_value!(
// &source,
// name_start,
// name_end,
// &source,
// value_start,
// value_end
// );
// assert_eq!(result, None);
// }

#[test]
fn test_replace_rule_name_not_match() {
let source = "height:1px".as_bytes();
let source: Vec<u16> = source.iter().map(|&b| b as u16).collect();
let name_start = 0;
let name_end = 6;
let value_start = 7;
let value_end = source.len();
let result = get_replace_rule_value!(
&source,
name_start,
name_end,
&source,
value_start,
value_end
);
assert_eq!(result, None);
}
}
// #[test]
// fn test_replace_rule_name_not_match() {
// let source = "height:1px".as_bytes();
// let source: Vec<u16> = source.iter().map(|&b| b as u16).collect();
// let name_start = 0;
// let name_end = 6;
// let value_start = 7;
// let value_end = source.len();
// let result = get_replace_rule_value!(
// &source,
// name_start,
// name_end,
// &source,
// value_start,
// value_end
// );
// assert_eq!(result, None);
// }
// }
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Restore test coverage for the refactored functionality.

All tests have been commented out, which significantly reduces test coverage for the rule transformation logic. The tests should be updated to work with the new string-based API rather than being disabled.

The tests need to be adapted to use js_sys::JsString inputs and string-based assertions. Would you like me to help convert these tests to work with the new API?

🤖 Prompt for AI Agents
In packages/web-platform/web-style-transformer/src/transformer/rules.rs from
lines 293 to 435, the test functions are currently commented out and use a u16
slice-based API. The issue is that these tests need to be restored and updated
to work with the new string-based API using js_sys::JsString inputs and
string-based assertions. To fix this, uncomment the tests and refactor them to
create inputs as JsString instances, adjust the calls to the transformation
functions accordingly, and update the assertions to compare string outputs
instead of u16 slices.

@codecov
Copy link

codecov bot commented Jul 29, 2025

❌ 7 Tests Failed:

Tests completed Failed Passed Skipped
2750 7 2743 44
View the top 3 failed test(s) by shortest run time
packages/web-platform/web-tests/tests/server.vitest.spec.ts > server-tests > basic-performance-event-div-100
Stack Traces | 0.0348s run time
Error: Snapshot `server-tests > basic-performance-event-div-100 1` mismatched

- Expected
+ Received

@@ -3,6 +3,6 @@
      --lynx-display: flex;
      --lynx-display-toggle: var(--lynx-display-flex);
    }
  [lynx-default-overflow-visible="true"] x-view{
      overflow: visible;
-   }</style><style l-part=""></style><div lynx-tag="page" l-uid="1" l-p-comp-uid="0" part="page" l-css-id="0" l-comp-id="0" l-template lynx-default-overflow-visible="true" l-part="1"><div lynx-tag="div" l-uid="2" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-0" l-part="2"></div><div lynx-tag="div" l-uid="3" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-1" l-part="3"></div><div lynx-tag="div" l-uid="4" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-2" l-part="4"></div><div lynx-tag="div" l-uid="5" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-3" l-part="5"></div><div lynx-tag="div" l-uid="6" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-4" l-part="6"></div><div lynx-tag="div" l-uid="7" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-5" l-part="7"></div><div lynx-tag="div" l-uid="8" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-6" l-part="8"></div><div lynx-tag="div" l-uid="9" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-7" l-part="9"></div><div lynx-tag="div" l-uid="10" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-8" l-part="10"></div><div lynx-tag="div" l-uid="11" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-9" l-part="11"></div><div lynx-tag="div" l-uid="12" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-10" l-part="12"></div><div lynx-tag="div" l-uid="13" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-11" l-part="13"></div><div lynx-tag="div" l-uid="14" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-12" l-part="14"></div><div lynx-tag="div" l-uid="15" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-13" l-part="15"></div><div lynx-tag="div" l-uid="16" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-14" l-part="16"></div><div lynx-tag="div" l-uid="17" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-15" l-part="17"></div><div lynx-tag="div" l-uid="18" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-16" l-part="18"></div><div lynx-tag="div" l-uid="19" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-17" l-part="19"></div><div lynx-tag="div" l-uid="20" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-18" l-part="20"></div><div lynx-tag="div" l-uid="21" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-19" l-part="21"></div><div lynx-tag="div" l-uid="22" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-20" l-part="22"></div><div lynx-tag="div" l-uid="23" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-21" l-part="23"></div><div lynx-tag="div" l-uid="24" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-22" l-part="24"></div><div lynx-tag="div" l-uid="25" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-23" l-part="25"></div><div lynx-tag="div" l-uid="26" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-24" l-part="26"></div><div lynx-tag="div" l-uid="27" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-25" l-part="27"></div><div lynx-tag="div" l-uid="28" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-26" l-part="28"></div><div lynx-tag="div" l-uid="29" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-27" l-part="29"></div><div lynx-tag="div" l-uid="30" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-28" l-part="30"></div><div lynx-tag="div" l-uid="31" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-29" l-part="31"></div><div lynx-tag="div" l-uid="32" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-30" l-part="32"></div><div lynx-tag="div" l-uid="33" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-31" l-part="33"></div><div lynx-tag="div" l-uid="34" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-32" l-part="34"></div><div lynx-tag="div" l-uid="35" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-33" l-part="35"></div><div lynx-tag="div" l-uid="36" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-34" l-part="36"></div><div lynx-tag="div" l-uid="37" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-35" l-part="37"></div><div lynx-tag="div" l-uid="38" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-36" l-part="38"></div><div lynx-tag="div" l-uid="39" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-37" l-part="39"></div><div lynx-tag="div" l-uid="40" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-38" l-part="40"></div><div lynx-tag="div" l-uid="41" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-39" l-part="41"></div><div lynx-tag="div" l-uid="42" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-40" l-part="42"></div><div lynx-tag="div" l-uid="43" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-41" l-part="43"></div><div lynx-tag="div" l-uid="44" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-42" l-part="44"></div><div lynx-tag="div" l-uid="45" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-43" l-part="45"></div><div lynx-tag="div" l-uid="46" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-44" l-part="46"></div><div lynx-tag="div" l-uid="47" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-45" l-part="47"></div><div lynx-tag="div" l-uid="48" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-46" l-part="48"></div><div lynx-tag="div" l-uid="49" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-47" l-part="49"></div><div lynx-tag="div" l-uid="50" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-48" l-part="50"></div><div lynx-tag="div" l-uid="51" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-49" l-part="51"></div><div lynx-tag="div" l-uid="52" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-50" l-part="52"></div><div lynx-tag="div" l-uid="53" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-51" l-part="53"></div><div lynx-tag="div" l-uid="54" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-52" l-part="54"></div><div lynx-tag="div" l-uid="55" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-53" l-part="55"></div><div lynx-tag="div" l-uid="56" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-54" l-part="56"></div><div lynx-tag="div" l-uid="57" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-55" l-part="57"></div><div lynx-tag="div" l-uid="58" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-56" l-part="58"></div><div lynx-tag="div" l-uid="59" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-57" l-part="59"></div><div lynx-tag="div" l-uid="60" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-58" l-part="60"></div><div lynx-tag="div" l-uid="61" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-59" l-part="61"></div><div lynx-tag="div" l-uid="62" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-60" l-part="62"></div><div lynx-tag="div" l-uid="63" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-61" l-part="63"></div><div lynx-tag="div" l-uid="64" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-62" l-part="64"></div><div lynx-tag="div" l-uid="65" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-63" l-part="65"></div><div lynx-tag="div" l-uid="66" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-64" l-part="66"></div><div lynx-tag="div" l-uid="67" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-65" l-part="67"></div><div lynx-tag="div" l-uid="68" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-66" l-part="68"></div><div lynx-tag="div" l-uid="69" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-67" l-part="69"></div><div lynx-tag="div" l-uid="70" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-68" l-part="70"></div><div lynx-tag="div" l-uid="71" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-69" l-part="71"></div><div lynx-tag="div" l-uid="72" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-70" l-part="72"></div><div lynx-tag="div" l-uid="73" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-71" l-part="73"></div><div lynx-tag="div" l-uid="74" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-72" l-part="74"></div><div lynx-tag="div" l-uid="75" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-73" l-part="75"></div><div lynx-tag="div" l-uid="76" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-74" l-part="76"></div><div lynx-tag="div" l-uid="77" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-75" l-part="77"></div><div lynx-tag="div" l-uid="78" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-76" l-part="78"></div><div lynx-tag="div" l-uid="79" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-77" l-part="79"></div><div lynx-tag="div" l-uid="80" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-78" l-part="80"></div><div lynx-tag="div" l-uid="81" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-79" l-part="81"></div><div lynx-tag="div" l-uid="82" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-80" l-part="82"></div><div lynx-tag="div" l-uid="83" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-81" l-part="83"></div><div lynx-tag="div" l-uid="84" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-82" l-part="84"></div><div lynx-tag="div" l-uid="85" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-83" l-part="85"></div><div lynx-tag="div" l-uid="86" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-84" l-part="86"></div><div lynx-tag="div" l-uid="87" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-85" l-part="87"></div><div lynx-tag="div" l-uid="88" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-86" l-part="88"></div><div lynx-tag="div" l-uid="89" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-87" l-part="89"></div><div lynx-tag="div" l-uid="90" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-88" l-part="90"></div><div lynx-tag="div" l-uid="91" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-89" l-part="91"></div><div lynx-tag="div" l-uid="92" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-90" l-part="92"></div><div lynx-tag="div" l-uid="93" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-91" l-part="93"></div><div lynx-tag="div" l-uid="94" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-92" l-part="94"></div><div lynx-tag="div" l-uid="95" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-93" l-part="95"></div><div lynx-tag="div" l-uid="96" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-94" l-part="96"></div><div lynx-tag="div" l-uid="97" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-95" l-part="97"></div><div lynx-tag="div" l-uid="98" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-96" l-part="98"></div><div lynx-tag="div" l-uid="99" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-97" l-part="99"></div><div lynx-tag="div" l-uid="100" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-98" l-part="100"></div><div lynx-tag="div" l-uid="101" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-99" l-part="101"></div></div></template></lynx-view>"
+   }</style><style l-part=""></style><div lynx-tag="page" l-uid="1" l-p-comp-uid="0" part="page" l-css-id="0" l-comp-id="0" l-template lynx-default-overflow-visible="true" l-part="1"><div lynx-tag="div" l-uid="2" l-p-comp-uid="1" style id="target-0" l-part="2"></div><div lynx-tag="div" l-uid="3" l-p-comp-uid="1" style id="target-1" l-part="3"></div><div lynx-tag="div" l-uid="4" l-p-comp-uid="1" style id="target-2" l-part="4"></div><div lynx-tag="div" l-uid="5" l-p-comp-uid="1" style id="target-3" l-part="5"></div><div lynx-tag="div" l-uid="6" l-p-comp-uid="1" style id="target-4" l-part="6"></div><div lynx-tag="div" l-uid="7" l-p-comp-uid="1" style id="target-5" l-part="7"></div><div lynx-tag="div" l-uid="8" l-p-comp-uid="1" style id="target-6" l-part="8"></div><div lynx-tag="div" l-uid="9" l-p-comp-uid="1" style id="target-7" l-part="9"></div><div lynx-tag="div" l-uid="10" l-p-comp-uid="1" style id="target-8" l-part="10"></div><div lynx-tag="div" l-uid="11" l-p-comp-uid="1" style id="target-9" l-part="11"></div><div lynx-tag="div" l-uid="12" l-p-comp-uid="1" style id="target-10" l-part="12"></div><div lynx-tag="div" l-uid="13" l-p-comp-uid="1" style id="target-11" l-part="13"></div><div lynx-tag="div" l-uid="14" l-p-comp-uid="1" style id="target-12" l-part="14"></div><div lynx-tag="div" l-uid="15" l-p-comp-uid="1" style id="target-13" l-part="15"></div><div lynx-tag="div" l-uid="16" l-p-comp-uid="1" style id="target-14" l-part="16"></div><div lynx-tag="div" l-uid="17" l-p-comp-uid="1" style id="target-15" l-part="17"></div><div lynx-tag="div" l-uid="18" l-p-comp-uid="1" style id="target-16" l-part="18"></div><div lynx-tag="div" l-uid="19" l-p-comp-uid="1" style id="target-17" l-part="19"></div><div lynx-tag="div" l-uid="20" l-p-comp-uid="1" style id="target-18" l-part="20"></div><div lynx-tag="div" l-uid="21" l-p-comp-uid="1" style id="target-19" l-part="21"></div><div lynx-tag="div" l-uid="22" l-p-comp-uid="1" style id="target-20" l-part="22"></div><div lynx-tag="div" l-uid="23" l-p-comp-uid="1" style id="target-21" l-part="23"></div><div lynx-tag="div" l-uid="24" l-p-comp-uid="1" style id="target-22" l-part="24"></div><div lynx-tag="div" l-uid="25" l-p-comp-uid="1" style id="target-23" l-part="25"></div><div lynx-tag="div" l-uid="26" l-p-comp-uid="1" style id="target-24" l-part="26"></div><div lynx-tag="div" l-uid="27" l-p-comp-uid="1" style id="target-25" l-part="27"></div><div lynx-tag="div" l-uid="28" l-p-comp-uid="1" style id="target-26" l-part="28"></div><div lynx-tag="div" l-uid="29" l-p-comp-uid="1" style id="target-27" l-part="29"></div><div lynx-tag="div" l-uid="30" l-p-comp-uid="1" style id="target-28" l-part="30"></div><div lynx-tag="div" l-uid="31" l-p-comp-uid="1" style id="target-29" l-part="31"></div><div lynx-tag="div" l-uid="32" l-p-comp-uid="1" style id="target-30" l-part="32"></div><div lynx-tag="div" l-uid="33" l-p-comp-uid="1" style id="target-31" l-part="33"></div><div lynx-tag="div" l-uid="34" l-p-comp-uid="1" style id="target-32" l-part="34"></div><div lynx-tag="div" l-uid="35" l-p-comp-uid="1" style id="target-33" l-part="35"></div><div lynx-tag="div" l-uid="36" l-p-comp-uid="1" style id="target-34" l-part="36"></div><div lynx-tag="div" l-uid="37" l-p-comp-uid="1" style id="target-35" l-part="37"></div><div lynx-tag="div" l-uid="38" l-p-comp-uid="1" style id="target-36" l-part="38"></div><div lynx-tag="div" l-uid="39" l-p-comp-uid="1" style id="target-37" l-part="39"></div><div lynx-tag="div" l-uid="40" l-p-comp-uid="1" style id="target-38" l-part="40"></div><div lynx-tag="div" l-uid="41" l-p-comp-uid="1" style id="target-39" l-part="41"></div><div lynx-tag="div" l-uid="42" l-p-comp-uid="1" style id="target-40" l-part="42"></div><div lynx-tag="div" l-uid="43" l-p-comp-uid="1" style id="target-41" l-part="43"></div><div lynx-tag="div" l-uid="44" l-p-comp-uid="1" style id="target-42" l-part="44"></div><div lynx-tag="div" l-uid="45" l-p-comp-uid="1" style id="target-43" l-part="45"></div><div lynx-tag="div" l-uid="46" l-p-comp-uid="1" style id="target-44" l-part="46"></div><div lynx-tag="div" l-uid="47" l-p-comp-uid="1" style id="target-45" l-part="47"></div><div lynx-tag="div" l-uid="48" l-p-comp-uid="1" style id="target-46" l-part="48"></div><div lynx-tag="div" l-uid="49" l-p-comp-uid="1" style id="target-47" l-part="49"></div><div lynx-tag="div" l-uid="50" l-p-comp-uid="1" style id="target-48" l-part="50"></div><div lynx-tag="div" l-uid="51" l-p-comp-uid="1" style id="target-49" l-part="51"></div><div lynx-tag="div" l-uid="52" l-p-comp-uid="1" style id="target-50" l-part="52"></div><div lynx-tag="div" l-uid="53" l-p-comp-uid="1" style id="target-51" l-part="53"></div><div lynx-tag="div" l-uid="54" l-p-comp-uid="1" style id="target-52" l-part="54"></div><div lynx-tag="div" l-uid="55" l-p-comp-uid="1" style id="target-53" l-part="55"></div><div lynx-tag="div" l-uid="56" l-p-comp-uid="1" style id="target-54" l-part="56"></div><div lynx-tag="div" l-uid="57" l-p-comp-uid="1" style id="target-55" l-part="57"></div><div lynx-tag="div" l-uid="58" l-p-comp-uid="1" style id="target-56" l-part="58"></div><div lynx-tag="div" l-uid="59" l-p-comp-uid="1" style id="target-57" l-part="59"></div><div lynx-tag="div" l-uid="60" l-p-comp-uid="1" style id="target-58" l-part="60"></div><div lynx-tag="div" l-uid="61" l-p-comp-uid="1" style id="target-59" l-part="61"></div><div lynx-tag="div" l-uid="62" l-p-comp-uid="1" style id="target-60" l-part="62"></div><div lynx-tag="div" l-uid="63" l-p-comp-uid="1" style id="target-61" l-part="63"></div><div lynx-tag="div" l-uid="64" l-p-comp-uid="1" style id="target-62" l-part="64"></div><div lynx-tag="div" l-uid="65" l-p-comp-uid="1" style id="target-63" l-part="65"></div><div lynx-tag="div" l-uid="66" l-p-comp-uid="1" style id="target-64" l-part="66"></div><div lynx-tag="div" l-uid="67" l-p-comp-uid="1" style id="target-65" l-part="67"></div><div lynx-tag="div" l-uid="68" l-p-comp-uid="1" style id="target-66" l-part="68"></div><div lynx-tag="div" l-uid="69" l-p-comp-uid="1" style id="target-67" l-part="69"></div><div lynx-tag="div" l-uid="70" l-p-comp-uid="1" style id="target-68" l-part="70"></div><div lynx-tag="div" l-uid="71" l-p-comp-uid="1" style id="target-69" l-part="71"></div><div lynx-tag="div" l-uid="72" l-p-comp-uid="1" style id="target-70" l-part="72"></div><div lynx-tag="div" l-uid="73" l-p-comp-uid="1" style id="target-71" l-part="73"></div><div lynx-tag="div" l-uid="74" l-p-comp-uid="1" style id="target-72" l-part="74"></div><div lynx-tag="div" l-uid="75" l-p-comp-uid="1" style id="target-73" l-part="75"></div><div lynx-tag="div" l-uid="76" l-p-comp-uid="1" style id="target-74" l-part="76"></div><div lynx-tag="div" l-uid="77" l-p-comp-uid="1" style id="target-75" l-part="77"></div><div lynx-tag="div" l-uid="78" l-p-comp-uid="1" style id="target-76" l-part="78"></div><div lynx-tag="div" l-uid="79" l-p-comp-uid="1" style id="target-77" l-part="79"></div><div lynx-tag="div" l-uid="80" l-p-comp-uid="1" style id="target-78" l-part="80"></div><div lynx-tag="div" l-uid="81" l-p-comp-uid="1" style id="target-79" l-part="81"></div><div lynx-tag="div" l-uid="82" l-p-comp-uid="1" style id="target-80" l-part="82"></div><div lynx-tag="div" l-uid="83" l-p-comp-uid="1" style id="target-81" l-part="83"></div><div lynx-tag="div" l-uid="84" l-p-comp-uid="1" style id="target-82" l-part="84"></div><div lynx-tag="div" l-uid="85" l-p-comp-uid="1" style id="target-83" l-part="85"></div><div lynx-tag="div" l-uid="86" l-p-comp-uid="1" style id="target-84" l-part="86"></div><div lynx-tag="div" l-uid="87" l-p-comp-uid="1" style id="target-85" l-part="87"></div><div lynx-tag="div" l-uid="88" l-p-comp-uid="1" style id="target-86" l-part="88"></div><div lynx-tag="div" l-uid="89" l-p-comp-uid="1" style id="target-87" l-part="89"></div><div lynx-tag="div" l-uid="90" l-p-comp-uid="1" style id="target-88" l-part="90"></div><div lynx-tag="div" l-uid="91" l-p-comp-uid="1" style id="target-89" l-part="91"></div><div lynx-tag="div" l-uid="92" l-p-comp-uid="1" style id="target-90" l-part="92"></div><div lynx-tag="div" l-uid="93" l-p-comp-uid="1" style id="target-91" l-part="93"></div><div lynx-tag="div" l-uid="94" l-p-comp-uid="1" style id="target-92" l-part="94"></div><div lynx-tag="div" l-uid="95" l-p-comp-uid="1" style id="target-93" l-part="95"></div><div lynx-tag="div" l-uid="96" l-p-comp-uid="1" style id="target-94" l-part="96"></div><div lynx-tag="div" l-uid="97" l-p-comp-uid="1" style id="target-95" l-part="97"></div><div lynx-tag="div" l-uid="98" l-p-comp-uid="1" style id="target-96" l-part="98"></div><div lynx-tag="div" l-uid="99" l-p-comp-uid="1" style id="target-97" l-part="99"></div><div lynx-tag="div" l-uid="100" l-p-comp-uid="1" style id="target-98" l-part="100"></div><div lynx-tag="div" l-uid="101" l-p-comp-uid="1" style id="target-99" l-part="101"></div></div></template></lynx-view>"

 ❯ tests/server.vitest.spec.ts:15:20
packages/web-platform/web-tests/tests/server.vitest.spec.ts > server-tests > basic-performance-div-10
Stack Traces | 0.0507s run time
Error: Snapshot `server-tests > basic-performance-div-10 1` mismatched

- Expected
+ Received

@@ -3,6 +3,6 @@
      --lynx-display: flex;
      --lynx-display-toggle: var(--lynx-display-flex);
    }
  [lynx-default-overflow-visible="true"] x-view{
      overflow: visible;
-   }</style><style l-part=""></style><div lynx-tag="page" l-uid="1" l-p-comp-uid="0" part="page" l-css-id="0" l-comp-id="0" l-template lynx-default-overflow-visible="true" l-part="1"><div lynx-tag="div" l-uid="2" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-0" l-part="2"></div><div lynx-tag="div" l-uid="3" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-1" l-part="3"></div><div lynx-tag="div" l-uid="4" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-2" l-part="4"></div><div lynx-tag="div" l-uid="5" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-3" l-part="5"></div><div lynx-tag="div" l-uid="6" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-4" l-part="6"></div><div lynx-tag="div" l-uid="7" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-5" l-part="7"></div><div lynx-tag="div" l-uid="8" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-6" l-part="8"></div><div lynx-tag="div" l-uid="9" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-7" l-part="9"></div><div lynx-tag="div" l-uid="10" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-8" l-part="10"></div><div lynx-tag="div" l-uid="11" l-p-comp-uid="1" style="height:100px;width:100px;background:pink" id="target-9" l-part="11"></div></div></template></lynx-view>"
+   }</style><style l-part=""></style><div lynx-tag="page" l-uid="1" l-p-comp-uid="0" part="page" l-css-id="0" l-comp-id="0" l-template lynx-default-overflow-visible="true" l-part="1"><div lynx-tag="div" l-uid="2" l-p-comp-uid="1" style id="target-0" l-part="2"></div><div lynx-tag="div" l-uid="3" l-p-comp-uid="1" style id="target-1" l-part="3"></div><div lynx-tag="div" l-uid="4" l-p-comp-uid="1" style id="target-2" l-part="4"></div><div lynx-tag="div" l-uid="5" l-p-comp-uid="1" style id="target-3" l-part="5"></div><div lynx-tag="div" l-uid="6" l-p-comp-uid="1" style id="target-4" l-part="6"></div><div lynx-tag="div" l-uid="7" l-p-comp-uid="1" style id="target-5" l-part="7"></div><div lynx-tag="div" l-uid="8" l-p-comp-uid="1" style id="target-6" l-part="8"></div><div lynx-tag="div" l-uid="9" l-p-comp-uid="1" style id="target-7" l-part="9"></div><div lynx-tag="div" l-uid="10" l-p-comp-uid="1" style id="target-8" l-part="10"></div><div lynx-tag="div" l-uid="11" l-p-comp-uid="1" style id="target-9" l-part="11"></div></div></template></lynx-view>"

 ❯ tests/server.vitest.spec.ts:15:20
fp-only.spec.ts::SSR no Javascript tests › configs › config-css-default-overflow-visible-unset
Stack Traces | 3.31s run time
fp-only.spec.ts:234:5 config-css-default-overflow-visible-unset

To view more test analytics, go to the Test Analytics Dashboard
📋 Got 3 mins? Take this short survey to help us improve Test Analytics.

Copy link
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: 4

🔭 Outside diff range comments (3)
packages/web-platform/web-style-transformer/standard.d.ts (1)

6-20: Update outdated function documentation

The comments still reference "raw uint16 pointer" and pointer safety concerns, but the function signatures now accept string parameters. These comments should be updated to reflect the new string-based interface.

-/**
- * lifted from the `console_log` example
- * Accepts a raw uint16 pointer from JS and transforms the inline style string into a JS string.
- * Returns `Some(JsString)` if the transformation was successful, or `None` if the input was empty or invalid.
- *
- * # Safety
- * The caller must ensure that `ptr` is valid and points to a slice of `u16` of length `len`.
- * This is a contract with the JavaScript side. Passing an invalid pointer or incorrect length may cause undefined behavior.
- */
+/**
+ * Transforms an inline style string into a processed style string.
+ * Returns a transformed string if successful, or undefined if the input was empty or invalid.
+ */
 export function transform_inline_style(ptr: string): string | undefined;
 /**
- * Accepts raw uint16 pointers from JS and parses the inline style name and value into a JS array.
- * Returns `Some(Array)` if parsing was successful, or `None` if both results are empty.
- *
- * # Safety
- * The caller must ensure that `name_ptr` and `value_ptr` are valid and point to slices of `u16` of lengths `name_len` and `value_len` respectively.
- * Passing invalid pointers or incorrect lengths may cause undefined behavior.
+ * Parses inline style name and value strings into a JS array.
+ * Returns an array if parsing was successful, or undefined if both results are empty.
  */
packages/web-platform/inline-style-parser/src/tokenize.rs (1)

150-444: Complete the iterator-based tokenization implementation

The tokenize function has an incomplete migration - the first part (lines 156-236) uses the new iterator-based approach with chars.peekable(), but the second part (lines 238-444) still uses the old char_code_at approach. This inconsistency will cause the function to fail since the iterator won't be properly consumed throughout the entire source.

The entire tokenize function needs to use a consistent approach. Either:

  1. Complete the iterator-based implementation for the entire function
  2. Revert to using indices throughout

The current mixed approach will not work correctly as the iterator position and offset tracking are not synchronized.

packages/web-platform/web-style-transformer/src/transformer/transform.rs (1)

36-47: Fix string iteration in is_digit_only macro

The macro attempts to call .iter() on a string slice, which doesn't have this method. Use .chars() instead to iterate over characters.

 macro_rules! is_digit_only {
   ($source:expr, $start:expr, $end:expr) => {{
     let mut result = true;
-    for code in $source.slice($start, $end).iter() {
-      if code > b'9' as u16 || code < b'0' as u16 {
+    for ch in $source.slice($start, $end).chars() {
+      let code = ch as u32;
+      if code > '9' as u32 || code < '0' as u32 {
         result = false;
         break;
       }
     }
     result
   }};
 }
♻️ Duplicate comments (4)
packages/web-platform/web-style-transformer/src/lib.rs (1)

53-74: Remove unnecessary unsafe block

The unsafe block is no longer needed since you're not performing any unsafe operations.

-  unsafe {
-    // let name_slice = core::slice::from_raw_parts(name_ptr, name_len);
-    // let value_slice = core::slice::from_raw_parts(value_ptr, value_len);
-    // Call the tokenize function with our data and callback
-    let (result, children_result) = transformer::transform::query_transform_rules(
-      &name_ptr, 0 as u32, name_len, &value_ptr, 0 as u32, value_len,
-    );
-    if result.is_empty() && children_result.is_empty() {
-      // if there are no results, we return None
-      return None;
-    }
-    // now we need to convert the result into a JS array
-    let ret = js_sys::Array::new();
-    ret.push(&push_parsed_result_to_js_array!(result).into());
-    if !children_result.is_empty() {
-      // if there are no children, we don't need to push an empty array
-      // but if there are children, we need to push them as well
-      ret.push(&push_parsed_result_to_js_array!(children_result).into());
-    }
-    Some(ret)
+  // Call the tokenize function with our data and callback
+  let (result, children_result) = transformer::transform::query_transform_rules(
+    &name_ptr, 0, name_len, &value_ptr, 0, value_len,
+  );
+  if result.is_empty() && children_result.is_empty() {
+    // if there are no results, we return None
+    return None;
+  }
+  // now we need to convert the result into a JS array
+  let ret = js_sys::Array::new();
+  ret.push(&push_parsed_result_to_js_array!(result).into());
+  if !children_result.is_empty() {
+    // if there are no children, we don't need to push an empty array
+    // but if there are children, we need to push them as well
+    ret.push(&push_parsed_result_to_js_array!(children_result).into());
   }
+  Some(ret)
packages/web-platform/web-style-transformer/src/transformer/transform.rs (2)

347-354: Fix incorrect string slicing in Transformer implementation

The code attempts to slice String objects using array indexing, which doesn't work in Rust. Based on the rest of the code, it appears decl_name and decl_value are already the full strings to be used.

         // Append the declaration name and colon
-        self.transformed_source.push(String::from(
-          &decl_name[*decl_name_start as usize..*decl_name_end as usize],
-        ));
-        self.transformed_source.push(String::from(":"));
+        self.transformed_source.push(decl_name);
+        self.transformed_source.push(":");
         // Append the declaration value
-        self.transformed_source.push(String::from(
-          &decl_value[*decl_value_start as usize..*decl_value_end as usize],
-        ));
+        self.transformed_source.push(decl_value);

The same fix should be applied to lines 370-377.


403-407: Optimize string concatenation

Using flat_map over characters is inefficient for string concatenation. Use join("") instead.

-  transformer
-    .transformed_source
-    .iter()
-    .flat_map(|s| s.chars())
-    .collect()
+  transformer.transformed_source.join("")
packages/web-platform/inline-style-parser/src/char_code_definitions.rs (1)

251-251: Fix incorrect case-insensitive comparison logic

The logic for case-insensitive comparison is incorrect. The condition (code == $reference_code) will never be true if the first condition failed.

-      if code == $reference_code || (is_uppercase_letter!(code) && (code == $reference_code)) {
+      if code == $reference_code || (is_uppercase_letter!(code) && ((code | 32) == $reference_code)) {
🧹 Nitpick comments (3)
packages/web-platform/web-style-transformer/src/transformer/transform.rs (1)

3-3: Remove unused import

The web_sys::console import is not used in this file.

-use web_sys::console;
packages/web-platform/inline-style-parser/src/char_code_definitions.rs (2)

182-204: Remove commented-out code

Large blocks of commented code should be removed to keep the codebase clean.

Remove the entire commented is_identifier_start macro implementation (lines 182-204) as it's been replaced by the new iterator-based version.


273-282: Remove commented-out code

Remove the commented get_new_line_length macro to keep the codebase clean.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5f3a2c7 and a4f176f.

⛔ Files ignored due to path filters (1)
  • packages/web-platform/web-tests/tests/react.spec.ts-snapshots/scroll-view/basic-element-scroll-view-fixed/initial-chromium-darwin.png is excluded by !**/*.png
📒 Files selected for processing (7)
  • packages/web-platform/inline-style-parser/src/char_code_definitions.rs (7 hunks)
  • packages/web-platform/inline-style-parser/src/parse_inline_style.rs (3 hunks)
  • packages/web-platform/inline-style-parser/src/tokenize.rs (5 hunks)
  • packages/web-platform/inline-style-parser/src/utils.rs (4 hunks)
  • packages/web-platform/web-style-transformer/src/lib.rs (3 hunks)
  • packages/web-platform/web-style-transformer/src/transformer/transform.rs (20 hunks)
  • packages/web-platform/web-style-transformer/standard.d.ts (2 hunks)
✅ Files skipped from review due to trivial changes (1)
  • packages/web-platform/inline-style-parser/src/parse_inline_style.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/web-platform/inline-style-parser/src/utils.rs
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: colinaaa
PR: lynx-family/lynx-stack#1330
File: .changeset/olive-animals-attend.md:1-3
Timestamp: 2025-07-22T09:23:07.797Z
Learning: In the lynx-family/lynx-stack repository, changesets are only required for meaningful changes to end-users such as bugfixes and features. Internal/development changes like chores, refactoring, or removing debug info do not need changeset entries.
Learnt from: PupilTong
PR: lynx-family/lynx-stack#1029
File: packages/web-platform/web-mainthread-apis/src/createMainThreadGlobalThis.ts:214-217
Timestamp: 2025-07-16T06:25:41.055Z
Learning: In the lynx-stack codebase, CSS strings produced by `genCssContent` are considered trusted developer input, so additional sanitization/escaping is not required.
Learnt from: colinaaa
PR: lynx-family/lynx-stack#1330
File: .changeset/olive-animals-attend.md:1-3
Timestamp: 2025-07-22T09:26:16.722Z
Learning: In the lynx-family/lynx-stack repository, CI checks require changesets when files matching the pattern "src/**" are modified (as configured in .changeset/config.json). For internal changes that don't need meaningful changesets, an empty changeset file is used to satisfy the CI requirement while not generating any release notes.
📚 Learning: in the lynx-stack codebase, css strings produced by `gencsscontent` are considered trusted developer...
Learnt from: PupilTong
PR: lynx-family/lynx-stack#1029
File: packages/web-platform/web-mainthread-apis/src/createMainThreadGlobalThis.ts:214-217
Timestamp: 2025-07-16T06:25:41.055Z
Learning: In the lynx-stack codebase, CSS strings produced by `genCssContent` are considered trusted developer input, so additional sanitization/escaping is not required.

Applied to files:

  • packages/web-platform/web-style-transformer/src/lib.rs
  • packages/web-platform/web-style-transformer/src/transformer/transform.rs
🧬 Code Graph Analysis (1)
packages/web-platform/web-style-transformer/standard.d.ts (1)
packages/web-platform/web-style-transformer/src/lib.rs (1)
  • transform_inline_style (14-20)

Comment on lines +215 to +220
if next_c.is_some() && is_digit!(next_c as u32) {
true
} else {
($second == 0x002E) && is_digit!($third) // U+002E FULL STOP (.)
(next_c.is_some() && next_c as u32 == 0x002E)
&& next_next_c.is_some()
&& is_digit!(next_next_c as u32) // U+002E FULL STOP (.)
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix type conversion issues in is_number_start macro

The macro has incorrect type conversions - next_c as u32 attempts to cast an Option to u32 which won't compile.

-      if next_c.is_some() && is_digit!(next_c as u32) {
+      if let Some(c) = next_c {
+        if is_digit!(c as u32) {
         true
+        } else {
+          false
+        }
       } else {
-        (next_c.is_some() && next_c as u32 == 0x002E)
-          && next_next_c.is_some()
-          && is_digit!(next_next_c as u32) // U+002E FULL STOP (.)
+        if let (Some(c1), Some(c2)) = (next_c, next_next_c) {
+          (c1 as u32 == 0x002E) && is_digit!(c2 as u32)
+        } else {
+          false
+        }
       }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if next_c.is_some() && is_digit!(next_c as u32) {
true
} else {
($second == 0x002E) && is_digit!($third) // U+002E FULL STOP (.)
(next_c.is_some() && next_c as u32 == 0x002E)
&& next_next_c.is_some()
&& is_digit!(next_next_c as u32) // U+002E FULL STOP (.)
if let Some(c) = next_c {
if is_digit!(c as u32) {
true
} else {
false
}
} else {
if let (Some(c1), Some(c2)) = (next_c, next_next_c) {
(c1 as u32 == 0x002E) && is_digit!(c2 as u32)
} else {
false
}
}
🤖 Prompt for AI Agents
In packages/web-platform/inline-style-parser/src/char_code_definitions.rs around
lines 215 to 220, the macro incorrectly casts an Option<char> directly to u32,
which is invalid. To fix this, first unwrap or pattern match the Option<char> to
get the char value, then convert that char to u32 before passing it to is_digit!
or comparing it to 0x002E. Adjust the code to safely handle the Option and
perform the conversion on the inner char only.

Comment on lines +309 to +311
if source.char_code_at(ii) == ('*' as u16 as f64)
&& source.char_code_at(ii + 1) == ('/' as u16 as f64)
{
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix inconsistent character code comparison

The code uses u16 casting and f64 comparison which is inconsistent with the rest of the codebase that uses u32.

-            if source.char_code_at(ii) == ('*' as u16 as f64)
-              && source.char_code_at(ii + 1) == ('/' as u16 as f64)
+            if source.char_code_at(ii) as u32 == ('*' as u32)
+              && source.char_code_at(ii + 1) as u32 == ('/' as u32)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if source.char_code_at(ii) == ('*' as u16 as f64)
&& source.char_code_at(ii + 1) == ('/' as u16 as f64)
{
if source.char_code_at(ii) as u32 == ('*' as u32)
&& source.char_code_at(ii + 1) as u32 == ('/' as u32)
{
🤖 Prompt for AI Agents
In packages/web-platform/inline-style-parser/src/tokenize.rs around lines 309 to
311, the character code comparison uses inconsistent casting to u16 and f64,
while the rest of the codebase uses u32. Update the casts to use u32
consistently for both the character literals and the char_code_at method
comparisons to maintain uniformity and correctness.

Comment on lines 15 to 20
unsafe {
let slice = core::slice::from_raw_parts(ptr, len);
// Call the tokenize function with our data and callback
let (transformed_inline_style, _) =
transformer::transform::transform_inline_style_string(slice);
if !transformed_inline_style.is_empty() {
return Some(js_sys::JsString::from_char_code(
transformed_inline_style.as_slice(),
));
}
let transformed_inline_style = transformer::transform::transform_inline_style_string(&source);
return Some(js_sys::JsString::from(transformed_inline_style));
}
None
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Remove unnecessary unsafe block and unreachable code

The function no longer performs any unsafe operations, so the unsafe block should be removed. Additionally, line 19 contains unreachable code after the return statement.

 pub fn transform_inline_style(source: String) -> Option<JsString> {
-  unsafe {
-    let transformed_inline_style = transformer::transform::transform_inline_style_string(&source);
-    return Some(js_sys::JsString::from(transformed_inline_style));
-  }
-  None
+  let transformed_inline_style = transformer::transform::transform_inline_style_string(&source);
+  Some(js_sys::JsString::from(transformed_inline_style))
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
unsafe {
let slice = core::slice::from_raw_parts(ptr, len);
// Call the tokenize function with our data and callback
let (transformed_inline_style, _) =
transformer::transform::transform_inline_style_string(slice);
if !transformed_inline_style.is_empty() {
return Some(js_sys::JsString::from_char_code(
transformed_inline_style.as_slice(),
));
}
let transformed_inline_style = transformer::transform::transform_inline_style_string(&source);
return Some(js_sys::JsString::from(transformed_inline_style));
}
None
}
pub fn transform_inline_style(source: String) -> Option<JsString> {
let transformed_inline_style = transformer::transform::transform_inline_style_string(&source);
Some(js_sys::JsString::from(transformed_inline_style))
}
🤖 Prompt for AI Agents
In packages/web-platform/web-style-transformer/src/lib.rs around lines 15 to 20,
remove the unnecessary unsafe block since no unsafe operations are performed.
Also, delete the unreachable code after the return statement on line 19 to clean
up the function.

Comment on lines +27 to +28
let k = js_sys::JsString::from(&name_source[name_start as usize..name_end as usize]);
let v = js_sys::JsString::from(&value_source[value_start as usize..value_end as usize]);
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Optimize string slicing to avoid unnecessary conversions

Converting JsString to String just for slicing is inefficient. Use JsString's slice method directly.

-      let k = js_sys::JsString::from(&name_source[name_start as usize..name_end as usize]);
-      let v = js_sys::JsString::from(&value_source[value_start as usize..value_end as usize]);
+      let k = name_source.slice(name_start, name_end);
+      let v = value_source.slice(value_start, value_end);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
let k = js_sys::JsString::from(&name_source[name_start as usize..name_end as usize]);
let v = js_sys::JsString::from(&value_source[value_start as usize..value_end as usize]);
let k = name_source.slice(name_start, name_end);
let v = value_source.slice(value_start, value_end);
🤖 Prompt for AI Agents
In packages/web-platform/web-style-transformer/src/lib.rs at lines 27 to 28, the
code converts JsString to Rust String for slicing, which is inefficient.
Instead, use the slice method provided by JsString directly on name_source and
value_source to obtain the substrings without intermediate conversions. Replace
the current slicing approach with JsString's slice method calls using the
appropriate indices.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants