-
-
Notifications
You must be signed in to change notification settings - Fork 249
Implement <select> parsing changes
#1610
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: master
Are you sure you want to change the base?
Implement <select> parsing changes
#1610
Conversation
Bumps [test/data/html5lib-tests](https://github.com/html5lib/html5lib-tests) from `a9f4496` to `8f43b7e`. - [Commits](html5lib/html5lib-tests@a9f4496...8f43b7e) --- updated-dependencies: - dependency-name: test/data/html5lib-tests dependency-version: 8f43b7ec8c9d02179f5f38e0ea08cb5000fb9c9e dependency-type: direct:production ... Signed-off-by: dependabot[bot] <support@github.com>
a9f4496 to 8f43b7e<select> parsing changes
There was a problem hiding this 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 updates the HTML5 parser to implement relaxed <select> element parsing rules as specified in the HTML spec update (whatwg/html#10548). The changes remove the dedicated "in select" and "in select in table" insertion modes, integrate select-related parsing directly into the "in body" mode, and add support for the new <selectedcontent> element with automatic content cloning from selected options.
Key changes:
- Removes
IN_SELECTandIN_SELECT_IN_TABLEinsertion modes - Adds
<selectedcontent>element support with automatic cloning of selected option content - Updates
<select>to be a scoping element and modifies scope checking logic - Updates test suite reference to include new HTML5lib tests for relaxed select parsing
Reviewed changes
Copilot reviewed 7 out of 8 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| test/data/html5lib-tests | Updates submodule to version containing new select parsing tests |
| packages/parse5/lib/parser/open-element-stack.ts | Adds SELECT to scoping elements, removes hasInSelectScope method |
| packages/parse5/lib/parser/open-element-stack.test.ts | Removes tests for the deleted hasInSelectScope method |
| packages/parse5/lib/parser/index.ts | Removes select-specific insertion modes, adds selectedcontent cloning logic and integrates select parsing into body mode |
| packages/parse5/lib/parser/index.test.ts | Adds test exclusions for cases testing old select parsing behavior |
| packages/parse5/lib/common/html.ts | Adds SELECTEDCONTENT tag and SELECTED attribute constants |
| packages/parse5-parser-stream/test/parser-stream.test.ts | Adds same test exclusions as parser tests |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // Selectedcontent cloning helpers | ||
|
|
||
| /** @internal */ | ||
| /** @internal */ |
Copilot
AI
Nov 28, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove duplicate @internal JSDoc comment on line 331. The comment already appears on line 330.
| /** @internal */ |
| this.selectedOptionInSelect = null; | ||
| } | ||
| } | ||
|
|
Copilot
AI
Nov 28, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add JSDoc comment for _maybeCloneOptionIntoSelectedcontent method to document its purpose and the selectedcontent cloning logic.
| /** | |
| * Clones the children of the appropriate <option> element into the selectedcontent element. | |
| * | |
| * This is used when finalizing a <select> element with enabled selectedcontent. | |
| * The method determines which <option> to clone: | |
| * - If there is a selectedOptionInSelect (an <option> with the 'selected' attribute), its children are cloned. | |
| * - Otherwise, the children of the firstOptionInSelect (the first <option> in the <select>) are cloned. | |
| * The children are deeply cloned and appended to the selectedcontent element. | |
| * If no suitable <option> is found, no cloning occurs. | |
| */ |
| this._cloneChildrenInto(optionToClone, this.enabledSelectedcontent); | ||
| } | ||
|
|
||
| /** @internal */ |
Copilot
AI
Nov 28, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add JSDoc comment for _cloneChildrenInto method to document parameters and cloning behavior.
| /** @internal */ | |
| /** | |
| * Clones all child nodes from the `source` element into the `target` element. | |
| * First, removes all existing children from the `target`. | |
| * Then, deep-clones each child node from `source` and appends it to `target`. | |
| * | |
| * @param {T['element']} source - The element whose children will be cloned. | |
| * @param {T['element']} target - The element to receive the cloned children. | |
| * @internal | |
| */ |
| this.treeAdapter.appendChild(target, cloned); | ||
| } | ||
| } | ||
|
|
Copilot
AI
Nov 28, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add JSDoc comment for _deepCloneNode method to document the recursive cloning logic and return value.
| /** | |
| * Recursively creates a deep clone of the given node and all its descendants. | |
| * - For text nodes, returns a new text node with the same content. | |
| * - For comment nodes, returns a new comment node with the same content. | |
| * - For element nodes, creates a new element with the same tag name, namespace, and attributes, | |
| * then recursively clones and appends all child nodes. | |
| * - For other node types (e.g., document type), returns the node itself (no cloning). | |
| * | |
| * @param node The node to deep clone. | |
| * @returns A deep clone of the input node, including all child nodes. | |
| */ |
| // Track this as the enabled selectedcontent if: | ||
| // 1. We're inside a select (selectedcontentSelect is set) | ||
| // 2. We don't already have an enabled selectedcontent | ||
| // 3. The select doesn't have the 'multiple' attribute (checked via selectedcontentSelect being set) |
Copilot
AI
Nov 28, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment states that the 'multiple' attribute check is done via selectedcontentSelect being set, but there's no actual check for the 'multiple' attribute in this code. Either add the missing validation or update the comment to accurately reflect the implementation.
| // 3. The select doesn't have the 'multiple' attribute (checked via selectedcontentSelect being set) | |
| // (Note: This does not check for the 'multiple' attribute on the select element) |
Bumps test/data/html5lib-tests from
a9f4496to8f43b7e.Commits
8f43b7eTest multiple option elements against selectedcontentcfb6639Add select particular element in scope testf994590Update tests for relaxed <select> parserYou can trigger a rebase of this PR by commenting
@dependabot rebase.Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR:
@dependabot rebasewill rebase this PR@dependabot recreatewill recreate this PR, overwriting any edits that have been made to it@dependabot mergewill merge this PR after your CI passes on it@dependabot squash and mergewill squash and merge this PR after your CI passes on it@dependabot cancel mergewill cancel a previously requested merge and block automerging@dependabot reopenwill reopen this PR if it is closed@dependabot closewill close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually@dependabot show <dependency name> ignore conditionswill show all of the ignore conditions of the specified dependency@dependabot ignore this major versionwill close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)@dependabot ignore this minor versionwill close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)@dependabot ignore this dependencywill close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)