fix(core,studio): escape user values in querySelector attribute selectors

Extract cssAttrSelector to packages/core/src/utils/cssSelector.ts and
use it (or CSS.escape for browser-side code) at all 12 sites that
previously interpolated raw user-authored values into querySelector
attribute selectors. A " in a composition ID, script src, or
data-start value would produce a malformed selector that throws.

Node-side (core compiler/parser): uses the shared cssAttrSelector.
Browser-side (runtime, studio): uses native CSS.escape().

Supersedes #1568 which fixed only the 3 bundler sites.
This commit is contained in:
Miguel Ángel
2026-06-19 15:47:28 -04:00
committed by GitHub
parent 758eda995c
commit c0ffdc0fb0
15 changed files with 126 additions and 21 deletions
+3 -3
View File
@@ -97,11 +97,11 @@ export function createPickerModule(deps: PickerModuleDeps): PickerModule {
const htmlEl = el as HTMLElement;
if (htmlEl.id) return `#${htmlEl.id}`;
const compositionId = el.getAttribute("data-composition-id");
if (compositionId) return `[data-composition-id="${compositionId}"]`;
if (compositionId) return `[data-composition-id="${CSS.escape(compositionId)}"]`;
const compositionSrc = el.getAttribute("data-composition-src");
if (compositionSrc) return `[data-composition-src="${compositionSrc}"]`;
if (compositionSrc) return `[data-composition-src="${CSS.escape(compositionSrc)}"]`;
const track = el.getAttribute("data-track-index");
if (track) return `[data-track-index="${track}"]`;
if (track) return `[data-track-index="${CSS.escape(track)}"]`;
const tag = el.tagName.toLowerCase();
const parent = el.parentElement;
if (!parent) return tag;