-
Notifications
You must be signed in to change notification settings - Fork 26
feat(iOS): attributed string to html serializer #324
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
feat(iOS): attributed string to html serializer #324
Conversation
|
@szydlovsky could you please review this one? |
|
Hey @IvanIhnatsiuk we're having quite a busy week. Will take a look when we're offloaded. |
|
We have to think about merging strategy. PR is quite big and it affects already working part of the app. Ideally we should have tests which verifies if there is no regression |
|
@exploIF , if I don't have enough time to write unit tests for this. If you could write them, it would be great. What I can suggest at the moment is to add a feature flag, for example: |
Summary
This PR has two main ideas
Current situation
The existing HTML serialization logic is quite difficult to follow and maintain.
During serialization we need to:
All of this makes the processing complex and error-prone.
Proposed approach
The main idea is to move style knowledge into style classes and build an intermediate HTML node tree, which is then serialized in a clean, deterministic way.
1. Style definitions
Each style class is responsible for describing how it maps to HTML.
Every style must implement:
tagNameattributeKeysubTagNameisSelfClosingisParagraphStyleStyles that require parameters (e.g. color, mention params, href, etc.) additionally conform to
ParameterizedStyleProtocol:This removes the need for:
Because styles now fully describe themselves, we can separate paragraph styles and inline styles upfront, which avoids unnecessary checks during traversal.
2. HTML element tree
Instead of writing HTML directly while walking the attributed string, we first build a tree of HTML nodes.
There are two node types:
HTMLElementNode{ tag: NSString, attributes: NSDictionary<NSString *, NSString *> | nil, children: NSArray<HTMLNode *>, selfClosing: BOOL }HTMLTextNode{ source: NSString, // text range: NSRange // substring range }This gives us a clear, inspectable intermediate representation before serialization.
3. Converting an attributed string into nodes
Step 1: Root node
<html>node with an emptychildrenarray.Step 2: Paragraph enumeration
We enumerate paragraphs of the attributed string:
Empty paragraph
→ add a
<br />node (self-closing)Non-empty paragraph
styleConditionChecking only the first character is sufficient because mixed paragraph types (e.g. H1 + UL in the same paragraph) are not supported.
Step 3: Inline attribute processing
For each paragraph, we enumerate attribute runs:
Create an
HTMLTextNodewith:Traverse all inline styles and wrap the text node when a style applies:
Example:
For the text Hello world, this results in:
"Hello"→<strong>TextNode</strong>"world"→<em>TextNode</em>Each attribute run produces its own small inline subtree.
4. Building HTML from the node tree
Once the tree is built, HTML generation is straightforward and isolated.
The serializer performs a depth-first recursive traversal:
Key properties
Summary
This approach:
Benchmarks
New style example
To add a new style, we just need to specify
Test Plan
Provide clear steps so another contributor can reproduce the behavior or verify the feature works.
For example:
Screenshots / Videos
Screen.Recording.2025-12-13.at.23.06.56.mov
Include any visual proof that helps reviewers understand the change — UI updates, bug reproduction or the result of the fix.
Compatibility