Tighten component/state update semantics and Storybook attribute sanitization#66
Tighten component/state update semantics and Storybook attribute sanitization#66JosunLP merged 5 commits intodevelopmentfrom
Conversation
Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR refines two core areas in bQuery: component update semantics (so state-driven renders aren’t gated by beforeUpdate) and Storybook template sanitization (so inferred allowlists don’t accidentally preserve unsafe attributes like inline style). It also improves Storybook boolean-attribute shorthand so callback values are evaluated before deciding attribute presence.
Changes:
- Component: make
setState()follow the state/signal rerender path by bypassingbeforeUpdate. - Storybook: narrow inferred sanitizer allowlists (custom elements only) and exclude inline
stylefrom auto-allowed attributes. - Tests: add regressions for state-update semantics, Storybook
stylestripping, and boolean shorthand with callback values.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
src/component/component.ts |
Updates setState() to skip beforeUpdate by calling render(..., runBeforeUpdate=false). |
src/storybook/index.ts |
Tightens inferred attribute allowlisting (no style, only for custom elements) and resolves boolean shorthand via callback-aware boolean evaluation. |
tests/component.test.ts |
Adds regression test ensuring beforeUpdate cannot block state-driven renders. |
tests/storybook.test.ts |
Adds coverage for style exclusion and boolean shorthand when values are callbacks. |
|
@copilot apply changes based on the comments in this thread |
Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com>
Applied in f4fb7c1. The Storybook scanner now consumes full quoted and unquoted literal attribute values after |
There was a problem hiding this comment.
Pull request overview
This PR refines bQuery’s component update lifecycle and hardens Storybook’s storyHtml sanitization inference so state-driven renders aren’t blocked by beforeUpdate, and Storybook templates don’t implicitly broaden sanitizer allowlists (notably for inline styles).
Changes:
- Adjust component
setState()to re-render without runningbeforeUpdate(matching signal-driven update semantics). - Narrow Storybook’s inferred
allowAttributesto custom elements only and exclude unsafe attribute classes (e.g.,style,on*). - Add regression tests covering the new component update behavior, Storybook allowlist narrowing, and boolean shorthand resolution for callback values.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
src/component/component.ts |
Routes setState() through a render path that bypasses beforeUpdate to prevent state-driven updates from being suppressed. |
src/storybook/index.ts |
Tightens inferred sanitizer allowlists (custom elements only; excludes style/on*) and resolves boolean shorthand from callback/derived values. |
tests/component.test.ts |
Adds regression coverage ensuring beforeUpdate doesn’t block state-driven renders. |
tests/storybook.test.ts |
Adds regression coverage for excluding style, avoiding attribute-name leakage from literal values, and callback-based boolean shorthand. |
|
@copilot apply changes based on the comments in this thread |
Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com>
Applied in 21febcf. The Storybook sanitizer scanner now preserves interpolation boundaries while still consuming whitespace-padded literal values after |
There was a problem hiding this comment.
Pull request overview
This PR refines component update behavior and Storybook template sanitization in bQuery by ensuring state-driven updates can’t be suppressed by beforeUpdate, while tightening Storybook’s inferred sanitizer allowlist to avoid preserving unsafe authored attributes like inline style.
Changes:
- Adjust component
setState()to bypassbeforeUpdate(matching signal-driven update semantics) while preservingbeforeUpdate(newProps, oldProps)for prop-driven updates. - Tighten Storybook
storyHtmlsanitizer inference: only auto-allow authored attributes on custom elements, excludingstyleandon*, and harden parsing to avoid allowlisting attributes found inside literal values. - Add regression tests covering the updated component/state semantics and Storybook sanitization/boolean-shorthand behavior.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
src/component/component.ts |
Makes setState() trigger update renders without running beforeUpdate, aligning state and signal update paths. |
src/storybook/index.ts |
Narrows inferred allowlists to custom-element-authored attributes (excluding style/on*) and resolves boolean shorthand from callback values before deciding attribute presence. |
tests/component.test.ts |
Adds coverage ensuring beforeUpdate does not block state-driven renders when props are unchanged. |
tests/storybook.test.ts |
Adds coverage for excluding inline style from inferred allowlists and for callback-resolved boolean shorthand semantics. |
|
@copilot apply changes based on the comments in this thread |
Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com>
Applied in e23e417. I aligned the |
There was a problem hiding this comment.
Pull request overview
This PR refines bQuery’s component update pipeline and Storybook template sanitization to ensure state/signal-driven renders cannot be suppressed by beforeUpdate, while tightening Storybook’s inferred sanitizer allowlist (notably excluding inline style) and fixing boolean shorthand resolution for callback values.
Changes:
- Update
setState()to bypassbeforeUpdate(matching signal-driven rerender semantics) while keepingbeforeUpdate(newProps, oldProps)for prop-driven updates. - Tighten Storybook’s inferred sanitizer allowlist by only auto-allowlisting authored attributes on custom elements and excluding
style/on*. - Add regression tests for state update semantics, Storybook allowlist inference edge cases, and boolean shorthand callback resolution.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
src/component/component.ts |
Routes setState() updates through render(..., runBeforeUpdate=false) so beforeUpdate only gates prop-driven renders. |
src/storybook/index.ts |
Improves template scanning using an interpolation boundary marker; restricts inferred allowlisted attributes to custom elements and filters out style/on*; resolves boolean shorthand from callbacks before presence checks. |
tests/component.test.ts |
Adds regression coverage ensuring beforeUpdate does not block state-driven renders while still applying to prop-driven updates. |
tests/storybook.test.ts |
Adds coverage for excluding inline style, preventing value-text from polluting inferred allowlists, and boolean shorthand callback semantics. |
* Add `bool()` support for boolean attributes in component templates (#55) Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Jonas Pfalzgraf <info@josunlp.de> * Add typed state generics to component definitions (#56) Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Jonas Pfalzgraf <info@josunlp.de> * Pass attribute change metadata to component `updated()` hooks (#58) Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Jonas Pfalzgraf <info@josunlp.de> * Add per-component sanitizer overrides for component render output (#57) * Initial plan * feat: add per-component sanitizer options Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * docs: clarify component sanitizer baseline Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * docs: warn about sensitive component sanitizer opts Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * test: cover sanitizer allowTags overrides Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * perf: precompute component sanitizer allowlists Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> --------- Signed-off-by: Jonas Pfalzgraf <info@josunlp.de> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> Co-authored-by: Jonas Pfalzgraf <info@josunlp.de> * Pass previous props into component `beforeUpdate` (#59) * Initial plan * Add previous props to beforeUpdate hook Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * Refine beforeUpdate old props implementation Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * Fix beforeUpdate typing regressions Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> --------- Signed-off-by: Jonas Pfalzgraf <info@josunlp.de> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> Co-authored-by: Jonas Pfalzgraf <info@josunlp.de> * Add explicit signal subscriptions to `component()` renders (#60) * Initial plan * feat: add component signal subscriptions Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * chore: document signal subscription tracking Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * fix: address signal integration review feedback Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * fix: tighten component signal typing Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * fix: resolve eslint failure in component signal test Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * fix: handle reconnect lifecycle and signal effect errors Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * fix: preserve reconnect signal wiring after hook errors Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * fix: skip beforeUpdate for signal rerenders Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> --------- Signed-off-by: Jonas Pfalzgraf <info@josunlp.de> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> Co-authored-by: Jonas Pfalzgraf <info@josunlp.de> * Add trusted sanitized fragments for `safeHtml` composition (#61) * Initial plan * feat: add trusted safeHtml fragment support Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * chore: finalize trusted safeHtml support Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * docs: address trusted safeHtml review feedback Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * docs: fix second trusted safeHtml review follow-up Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * refactor: split trusted html helpers from sanitizer Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * refactor: tighten trusted html branding Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * docs: tighten trusted html internals Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> --------- Signed-off-by: Jonas Pfalzgraf <info@josunlp.de> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> Co-authored-by: Jonas Pfalzgraf <info@josunlp.de> * Reuse component shadow-root style nodes across re-renders (#62) * Initial plan * fix: reuse component style element on rerender Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * chore: finalize component style reuse fix Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * test: tighten style reuse regression assertions Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * Add `@bquery/bquery/storybook` template helpers for Storybook stories (#63) * Initial plan * feat: add storybook template helper Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * docs: clarify storybook when fallback behavior Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * fix: keep storybook helpers out of full bundle Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * fix: sanitize storybook helper output Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * test: tighten storybook helper security coverage Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * feat: enhance storyHtml with improved boolean attribute handling and sanitization tests * fix: update storyHtml example to reflect correct boolean attribute output * fix: defensive tag delimiter and parser comments per code review Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * chore: release version 1.6.0 - Update CHANGELOG.md for version 1.6.0 release notes including added features, changes, fixes, and security improvements. - Enhance README.md to document new boolean attribute helpers and Storybook integration. - Update bun.lock to reflect dependency upgrades for Storybook and happy-dom. - Modify definition.md to include new Storybook helpers and component state management features. - Revise components.md to demonstrate new boolean attribute handling and typed state in components. - Update getting-started.md with Storybook authoring examples and improved module descriptions. - Enhance security.md to clarify sanitization practices and introduce trusted fragment handling. - Revise index.md to highlight new Storybook helpers in the feature list. - Update llms.txt to reflect the new version 1.6.0. - Bump version in package.json to 1.6.0 and update devDependencies for Storybook. * Address review feedback for test setup, test type coverage, and component state keys (#65) * Initial plan * Address review feedback for test typing and setup Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * Finalize review feedback fixes Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * Export component state key type Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * Default component state key generic Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * Tighten component/state update semantics and Storybook attribute sanitization (#66) * Initial plan * fix review follow-up for state updates and storybook sanitization Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * fix storybook attribute value scanning Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * fix storybook interpolation boundary parsing Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * docs align storybook attribute scan jsdoc Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> --------- Signed-off-by: Jonas Pfalzgraf <info@josunlp.de> Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
…tization (#66) * Initial plan * fix review follow-up for state updates and storybook sanitization Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * fix storybook attribute value scanning Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * fix storybook interpolation boundary parsing Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> * docs align storybook attribute scan jsdoc Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: JosunLP <20913954+JosunLP@users.noreply.github.com>
This follow-up addresses review feedback on the v1.6.0 changes in two areas: component rerender semantics and Storybook template sanitization. It prevents
beforeUpdateguards from suppressing state-driven renders and narrows Storybook’s inferred sanitizer allowlist so authored templates do not preserve unsafe inline attributes by default.Component update flow
setState()follow the same rerender path as signal-driven updates by skippingbeforeUpdate.beforeUpdate(newProps, oldProps)contract for prop-driven updates only.Storybook sanitization
allowAttributesto authored attributes on custom elements only.stylefrom the auto-allowlist so Storybook stories do not weaken the default sanitization boundary.variant,data-*, andaria-*working as expected.Boolean shorthand handling
?attr=${...}shorthand.Regression coverage
beforeUpdate.stylefrom Storybook’s inferred allowlist.✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.