Skip to content

fix: warn on self-scoped composition selectors#562

Merged
miguel-heygen merged 1 commit intomainfrom
fix/lint-self-composition-selector
Apr 29, 2026
Merged

fix: warn on self-scoped composition selectors#562
miguel-heygen merged 1 commit intomainfrom
fix/lint-self-composition-selector

Conversation

@miguel-heygen
Copy link
Copy Markdown
Collaborator

Problem

Closes #557.

Authors can follow the documented [data-composition-id="<self>"] CSS pattern and accidentally create selectors that are unsafe when the same block is embedded more than once. The existing linter did not flag that authoring risk, including when the selector lived in a linked local stylesheet.

What this fixes

  • Adds composition_self_attribute_selector as a warning when CSS targets the current file's root composition id.
  • Keeps selectors for other composition ids silent so parent/cross-block targeting remains allowed.
  • Includes local linked stylesheet content in hyperframes lint for root and sub-composition files.
  • Adds core linter coverage for inline and external CSS plus CLI coverage for a linked sub-composition stylesheet.

Root cause

The linter only extracted composition ids from inline <style> blocks for wrapper existence checks. It did not parse selectors against the current root id, and the CLI did not pass linked local CSS into the core linter at all.

Verification

Local checks

  • bun run --filter @hyperframes/core test src/lint/rules/core.test.ts
  • bun test packages/cli/src/utils/lintProject.test.ts
  • bun run build:hyperframes-runtime before the CLI test in this cold worktree
  • bun run --filter @hyperframes/core typecheck
  • bun run --filter @hyperframes/cli typecheck
  • bunx oxlint packages/core/src/lint/types.ts packages/core/src/lint/context.ts packages/core/src/lint/rules/core.ts packages/core/src/lint/rules/core.test.ts packages/cli/src/utils/lintProject.ts packages/cli/src/utils/lintProject.test.ts
  • bunx oxfmt --check packages/core/src/lint/types.ts packages/core/src/lint/context.ts packages/core/src/lint/rules/core.ts packages/core/src/lint/rules/core.test.ts packages/cli/src/utils/lintProject.ts packages/cli/src/utils/lintProject.test.ts

Browser verification

  • Created /tmp/hf-self-selector-lint-qa with [data-composition-id="scene"] .title in inline CSS.
  • bun run --filter @hyperframes/cli dev -- lint /tmp/hf-self-selector-lint-qa reported composition_self_attribute_selector as a warning.
  • Opened Studio at http://localhost:5195 and verified the Lint panel shows the warning.
  • Screenshot: qa-artifacts/issue-557/self-selector-lint-panel.png
  • Recording: qa-artifacts/issue-557/self-selector-lint-panel.webm

Notes

The QA artifacts are local only and not included in the PR.

Copy link
Copy Markdown
Collaborator

@jrusso1020 jrusso1020 left a comment

Choose a reason for hiding this comment

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

LGTM — preventive lint rule paired with #561's runtime fix.

Rule: composition_self_attribute_selector walks each style block via postcss, fires on selectors targeting the file's own root composition id. Skips :root, html, body, *. Recommends #<root-id> in the fixHint when the root has an id, with #556 reference.

External CSS now in scope: lintProject.ts collects local <link rel="stylesheet"> files and feeds them through the lint context's externalStyles. Skips remote/data URLs. Resolves relative to the composition file. This is a solid expansion — previously the linter was inline-only.

Symmetric proof: reverted only core.ts + context.ts + types.ts while keeping the new tests → "warns when inline CSS targets the root composition id" + "warns when external CSS targets the root composition id" both fail red. The "does not warn when CSS targets a different composition id" test still passes (no rule = no findings, as expected). Restoring → 564/564 pass.

One nit, non-blocking: the fixHint message references #556 and says "until per-instance scoping is supported." With #561 landing alongside, per-instance scoping IS now supported in the bundled flow, so the message is slightly stale. The rule is still valuable as preventive guidance (the docs pattern depends on the bundler's rewrite — #<id> is more direct), but the fixHint copy could be updated post-merge to reflect "rely on #<id> for clearer authoring intent" rather than implying scoping doesn't exist.

— Review by Rames Jusso

@miguel-heygen miguel-heygen force-pushed the fix/lint-self-composition-selector branch from f918f82 to 1540efb Compare April 29, 2026 15:52
@miguel-heygen
Copy link
Copy Markdown
Collaborator Author

Addressed the copy nit: refreshed the fixHint so it recommends using the root id for clearer authoring intent / instance-isolated styling without implying per-instance scoping is unsupported, and added a regression assertion that the stale #556 wording is gone.

@miguel-heygen miguel-heygen merged commit 403c00e into main Apr 29, 2026
41 checks passed
@miguel-heygen miguel-heygen deleted the fix/lint-self-composition-selector branch April 29, 2026 16:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

hyperframes lint: warn on [data-composition-id="<self>"] selectors that do not isolate per-instance

2 participants