mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-11 14:50:02 +00:00
fix(lint): decode JSON attribute entities
This commit is contained in:
@@ -1049,6 +1049,24 @@ describe("composition rules", () => {
|
|||||||
expect(finding).toBeUndefined();
|
expect(finding).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("does not warn for an HTML-entity-encoded declarations array", async () => {
|
||||||
|
const declarations = JSON.stringify([
|
||||||
|
{
|
||||||
|
id: "title",
|
||||||
|
type: "string",
|
||||||
|
label: "Title",
|
||||||
|
description: 'A "quoted" title',
|
||||||
|
default: "Hello",
|
||||||
|
},
|
||||||
|
]).replaceAll('"', """);
|
||||||
|
const html = `<html data-composition-variables='${declarations}'><body><div data-composition-id="x"></div></body></html>`;
|
||||||
|
const result = await lintHyperframeHtml(html);
|
||||||
|
const finding = result.findings.find(
|
||||||
|
(f) => f.code === "invalid_composition_variables_declaration",
|
||||||
|
);
|
||||||
|
expect(finding).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
it("does not warn when data-composition-variables is absent", async () => {
|
it("does not warn when data-composition-variables is absent", async () => {
|
||||||
const html = `<html><body><div data-composition-id="x"></div></body></html>`;
|
const html = `<html><body><div data-composition-id="x"></div></body></html>`;
|
||||||
const result = await lintHyperframeHtml(html);
|
const result = await lintHyperframeHtml(html);
|
||||||
|
|||||||
@@ -194,27 +194,13 @@ export function readDecodedAttr(tagSource: string, attr: string): string | null
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read an attribute that may legitimately contain the opposite quote
|
* Read a JSON-bearing attribute with browser-equivalent character-reference
|
||||||
* character. `readAttr` truncates `data-variable-values='{"title":"Hello"}'`
|
* decoding. Imported or formatter-serialized HTML commonly stores JSON quotes
|
||||||
* at the first internal `"` because its `[^"']+` class excludes both quote
|
* as `"`; lint must inspect the same decoded value that `getAttribute()`
|
||||||
* types. This variant alternates: a double-quoted value never contains an
|
* exposes at runtime.
|
||||||
* unescaped `"`, and a single-quoted value never contains an unescaped `'`,
|
|
||||||
* so each branch can use a quote-specific class.
|
|
||||||
*
|
|
||||||
* Use for attributes whose values are JSON or otherwise carry the opposite
|
|
||||||
* quote character. Existing single-token attributes (`id`, `class`, etc.)
|
|
||||||
* stick with `readAttr` for consistency with the rest of the lint code.
|
|
||||||
*/
|
*/
|
||||||
export function readJsonAttr(tagSource: string, attr: string): string | null {
|
export function readJsonAttr(tagSource: string, attr: string): string | null {
|
||||||
if (!tagSource) return null;
|
return readDecodedAttr(tagSource, attr);
|
||||||
const escaped = attr.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
||||||
// See readAttr: `(?<![\w-])` prevents a short name from matching the tail of a
|
|
||||||
// longer hyphenated attribute (e.g. "id" inside `data-hf-id`).
|
|
||||||
const match = tagSource.match(
|
|
||||||
new RegExp(`(?<![\\w-])${escaped}\\s*=\\s*(?:"([^"]*)"|'([^']*)')`, "i"),
|
|
||||||
);
|
|
||||||
if (!match) return null;
|
|
||||||
return match[1] ?? match[2] ?? null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function collectCompositionIds(tags: OpenTag[]): Set<string> {
|
export function collectCompositionIds(tags: OpenTag[]): Set<string> {
|
||||||
|
|||||||
Reference in New Issue
Block a user