@hyperframes/parsers 0.8.156 → 0.8.158
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/hfIds.d.ts +4 -1
- package/dist/hfIds.js +133 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +133 -1
- package/package.json +2 -2
package/dist/hfIds.d.ts
CHANGED
|
@@ -23,5 +23,8 @@ declare function isCompositionTemplate(el: Element): boolean;
|
|
|
23
23
|
declare function walkCompositionDescendants(root: Document | Element, visit: (el: Element) => void): void;
|
|
24
24
|
|
|
25
25
|
declare function ensureHfIds(html: string): string;
|
|
26
|
+
/** ensureHfIds for a file someone edits: the same ids, inserted into the source text so nothing else in it changes.
|
|
27
|
+
* Markup whose tags the parser did not keep one-to-one falls back to ensureHfIds. */
|
|
28
|
+
declare function stampHfIdsInPlace(html: string): string;
|
|
26
29
|
|
|
27
|
-
export { EXCLUDED_TAGS, ensureHfIds, isCompositionTemplate, mintHfId, walkCompositionDescendants };
|
|
30
|
+
export { EXCLUDED_TAGS, ensureHfIds, isCompositionTemplate, mintHfId, stampHfIdsInPlace, walkCompositionDescendants };
|
package/dist/hfIds.js
CHANGED
|
@@ -96,18 +96,150 @@ function assignHfIds(body) {
|
|
|
96
96
|
|
|
97
97
|
// src/hfIds.ts
|
|
98
98
|
function ensureHfIds(html) {
|
|
99
|
+
const { document, wrapped } = parseFragmentOrDocument(html);
|
|
100
|
+
if (!document.body) return html;
|
|
101
|
+
assignHfIds(document.body);
|
|
102
|
+
return wrapped ? document.body.innerHTML || "" : document.toString();
|
|
103
|
+
}
|
|
104
|
+
function parseFragmentOrDocument(html) {
|
|
99
105
|
const wrapped = !/^(?:<!doctype|<html[\s>/])/i.test(
|
|
100
106
|
html.replace(/^(?:\s|<!--(?:>|->|[\s\S]*?-->))*/, "")
|
|
101
107
|
);
|
|
102
108
|
const { document } = wrapped ? parseHTML(`<!DOCTYPE html><html><head></head><body>${html}</body></html>`) : parseHTML(html);
|
|
109
|
+
return { document, wrapped };
|
|
110
|
+
}
|
|
111
|
+
function stampHfIdsInPlace(html) {
|
|
112
|
+
const { document, wrapped } = parseFragmentOrDocument(html);
|
|
103
113
|
if (!document.body) return html;
|
|
114
|
+
const elements = wrapped ? getChildElements(document.body).flatMap(inDocumentOrder) : inDocumentOrder(document.documentElement);
|
|
115
|
+
const existing = elements.map((el) => el.getAttribute("data-hf-id"));
|
|
116
|
+
const pinned = existing.map((id) => id !== null && id.length > 0);
|
|
104
117
|
assignHfIds(document.body);
|
|
105
|
-
|
|
118
|
+
const minted = elements.map((el, n) => pinned[n] ? null : el.getAttribute("data-hf-id"));
|
|
119
|
+
const tags = startTags(html);
|
|
120
|
+
const inserts = tags && alignInserts(html, tags, elements, minted, existing);
|
|
121
|
+
return inserts ? spliceIds(html, inserts) : ensureHfIds(html);
|
|
122
|
+
}
|
|
123
|
+
function inDocumentOrder(el) {
|
|
124
|
+
return [el, ...getChildElements(el).flatMap(inDocumentOrder)];
|
|
125
|
+
}
|
|
126
|
+
var RAW_TEXT = /* @__PURE__ */ new Set(["script", "style", "textarea", "title", "xmp", "noembed", "noframes"]);
|
|
127
|
+
var IMPLIED = /* @__PURE__ */ new Set(["html", "head", "body", "tbody"]);
|
|
128
|
+
function startTags(html) {
|
|
129
|
+
const lower = html.toLowerCase();
|
|
130
|
+
const tags = [];
|
|
131
|
+
let i = html.indexOf("<");
|
|
132
|
+
while (i >= 0) {
|
|
133
|
+
const name = html.startsWith("<!--", i) ? null : /^<([a-zA-Z][^\s/>]*)/.exec(html.slice(i, i + 128));
|
|
134
|
+
if (!name) {
|
|
135
|
+
i = nextTagAfter(html, i);
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
const end = closingBracket(html, i + name[0].length);
|
|
139
|
+
if (end < 0) return null;
|
|
140
|
+
const tag = name[1].toLowerCase();
|
|
141
|
+
tags.push({ name: tag, nameEnd: i + name[0].length, bracket: end });
|
|
142
|
+
const after = RAW_TEXT.has(tag) ? rawTextEnd(lower, tag, end) : end;
|
|
143
|
+
i = after < 0 ? -1 : html.indexOf("<", after + 1);
|
|
144
|
+
}
|
|
145
|
+
return tags;
|
|
146
|
+
}
|
|
147
|
+
function rawTextEnd(lower, tag, from) {
|
|
148
|
+
const marker = `</${tag}`;
|
|
149
|
+
for (let at = lower.indexOf(marker, from); at >= 0; at = lower.indexOf(marker, at + marker.length)) {
|
|
150
|
+
const next = lower[at + marker.length];
|
|
151
|
+
if (next !== void 0 && /[\s/>]/.test(next)) return at;
|
|
152
|
+
}
|
|
153
|
+
return -1;
|
|
154
|
+
}
|
|
155
|
+
function nextTagAfter(html, lt) {
|
|
156
|
+
const comment = html.startsWith("<!--", lt);
|
|
157
|
+
const end = comment ? html.indexOf("-->", lt + 4) : html.indexOf(">", lt);
|
|
158
|
+
return end < 0 ? -1 : html.indexOf("<", end + 1);
|
|
159
|
+
}
|
|
160
|
+
function closingBracket(html, from) {
|
|
161
|
+
let quote = "";
|
|
162
|
+
for (let i = from; i < html.length; i++) {
|
|
163
|
+
const c = html[i];
|
|
164
|
+
if (quote) quote = c === quote ? "" : quote;
|
|
165
|
+
else if (c === '"' || c === "'") quote = c;
|
|
166
|
+
else if (c === ">") return i;
|
|
167
|
+
}
|
|
168
|
+
return -1;
|
|
169
|
+
}
|
|
170
|
+
function alignInserts(html, tags, elements, minted, existing) {
|
|
171
|
+
const walked = walkAlign(html, tags, elements, minted, existing);
|
|
172
|
+
if (!walked) return null;
|
|
173
|
+
return walked.next === tags.length ? walked.inserts : null;
|
|
174
|
+
}
|
|
175
|
+
function walkAlign(html, tags, elements, minted, existing) {
|
|
176
|
+
const state = { inserts: [], next: 0 };
|
|
177
|
+
for (const [n, el] of elements.entries()) {
|
|
178
|
+
if (!take(state, html, tags, el, minted[n] ?? null, existing[n] === "")) return null;
|
|
179
|
+
}
|
|
180
|
+
return state;
|
|
181
|
+
}
|
|
182
|
+
function take(state, html, tags, el, id, fillEmpty) {
|
|
183
|
+
const step = alignOne(html, tags[state.next], el, id, fillEmpty);
|
|
184
|
+
if (!step) return false;
|
|
185
|
+
if (step.insert) state.inserts.push(step.insert);
|
|
186
|
+
if (step.next) state.next += 1;
|
|
187
|
+
return true;
|
|
188
|
+
}
|
|
189
|
+
function alignOne(html, tag, el, id, fillEmpty) {
|
|
190
|
+
if (tag?.name === el.tagName.toLowerCase()) return matched(html, tag, id, fillEmpty);
|
|
191
|
+
if (IMPLIED.has(el.tagName.toLowerCase()) && !id) return { insert: null, next: false };
|
|
192
|
+
return null;
|
|
193
|
+
}
|
|
194
|
+
function matched(html, tag, id, fillEmpty) {
|
|
195
|
+
if (!id) return { insert: null, next: true };
|
|
196
|
+
const placed = placeId(html, tag, id, fillEmpty);
|
|
197
|
+
if (!placed) return null;
|
|
198
|
+
return { insert: placed, next: true };
|
|
199
|
+
}
|
|
200
|
+
function placeId(html, tag, id, fillEmpty) {
|
|
201
|
+
if (!fillEmpty) return { at: tag.nameEnd, text: ` data-hf-id="${id}"` };
|
|
202
|
+
const emptyAt = emptyHfIdValue(html, tag);
|
|
203
|
+
if (emptyAt === null) return null;
|
|
204
|
+
return { at: emptyAt, text: id };
|
|
205
|
+
}
|
|
206
|
+
function emptyHfIdValue(html, tag) {
|
|
207
|
+
const open = outsideQuotes(html.slice(tag.nameEnd, tag.bracket));
|
|
208
|
+
const match = /\sdata-hf-id\s*=\s*(["'])\1/i.exec(open);
|
|
209
|
+
if (!match) return null;
|
|
210
|
+
return tag.nameEnd + match.index + match[0].length - 1;
|
|
211
|
+
}
|
|
212
|
+
function outsideQuotes(open) {
|
|
213
|
+
let quote = "";
|
|
214
|
+
let out = "";
|
|
215
|
+
for (const c of open) {
|
|
216
|
+
out += quotedChar(quote, c);
|
|
217
|
+
quote = quoteOf(quote, c);
|
|
218
|
+
}
|
|
219
|
+
return out;
|
|
220
|
+
}
|
|
221
|
+
function quoteOf(quote, c) {
|
|
222
|
+
if (quote) return c === quote ? "" : quote;
|
|
223
|
+
return c === '"' || c === "'" ? c : "";
|
|
224
|
+
}
|
|
225
|
+
function quotedChar(quote, c) {
|
|
226
|
+
if (!quote || c === quote) return c;
|
|
227
|
+
return " ".repeat(c.length);
|
|
228
|
+
}
|
|
229
|
+
function spliceIds(html, inserts) {
|
|
230
|
+
let out = "";
|
|
231
|
+
let from = 0;
|
|
232
|
+
for (const { at, text } of inserts) {
|
|
233
|
+
out += html.slice(from, at) + text;
|
|
234
|
+
from = at;
|
|
235
|
+
}
|
|
236
|
+
return out + html.slice(from);
|
|
106
237
|
}
|
|
107
238
|
export {
|
|
108
239
|
EXCLUDED_TAGS,
|
|
109
240
|
ensureHfIds,
|
|
110
241
|
isCompositionTemplate,
|
|
111
242
|
mintHfId,
|
|
243
|
+
stampHfIdsInPlace,
|
|
112
244
|
walkCompositionDescendants
|
|
113
245
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export { isStudioHoldSet } from './gsapParser.js';
|
|
|
5
5
|
export { getObjectArrayKeyframeTiming } from './gsapParserExports.js';
|
|
6
6
|
export { SPRING_PRESETS, SpringPreset, generateSpringEaseData } from './springEase.js';
|
|
7
7
|
export { parseGsapScriptAcorn as parseGsapScript } from './gsapParserAcorn.js';
|
|
8
|
-
export { EXCLUDED_TAGS, ensureHfIds, isCompositionTemplate, mintHfId, walkCompositionDescendants } from './hfIds.js';
|
|
8
|
+
export { EXCLUDED_TAGS, ensureHfIds, isCompositionTemplate, mintHfId, stampHfIdsInPlace, walkCompositionDescendants } from './hfIds.js';
|
|
9
9
|
export { ParsableDocumentLike, SubCompositionValidity, SubCompositionValidityReason, checkSubCompositionUsability, resolveSubCompositionContent } from './subCompositionValidity.js';
|
|
10
10
|
export { CANONICAL_AUTHORED_TIMING_ATTRIBUTES, COMPOSITION_ATTRIBUTES, COMPOSITION_CONTRACT_VERSION, ClipAttributeReader, ClipAttributeWriter, ClipTiming, ClipTimingDiagnostic, ClipTimingDiagnosticCode, ClipTimingUpdate, ClipTimingWriteError, DERIVED_TIMING_ATTRIBUTES, LEGACY_TIMING_ATTRIBUTES, ReadClipTimingOptions, ReferenceExpression, parseNumeric, parseStartExpression, readClipTiming, writeClipTiming } from './compositionContract.js';
|
|
11
11
|
export { CANONICAL_FONT_DISPLAY_NAMES, FONT_ALIAS_KEYS, FONT_ALIAS_MAP, HTML_BODY_CSS_HEIGHT_FIRST_RE, HTML_BODY_CSS_WIDTH_FIRST_RE, MediaSrcMutation, VIEWPORT_META_SIZE_RE, VariableUsageScan, extractMediaSrcMutations, parseCompositionVariables, resolveAliasDisplayName, scanVariableUsage } from './composition.js';
|
package/dist/index.js
CHANGED
|
@@ -2471,13 +2471,144 @@ function assignHfIds(body) {
|
|
|
2471
2471
|
|
|
2472
2472
|
// src/hfIds.ts
|
|
2473
2473
|
function ensureHfIds(html) {
|
|
2474
|
+
const { document, wrapped } = parseFragmentOrDocument(html);
|
|
2475
|
+
if (!document.body) return html;
|
|
2476
|
+
assignHfIds(document.body);
|
|
2477
|
+
return wrapped ? document.body.innerHTML || "" : document.toString();
|
|
2478
|
+
}
|
|
2479
|
+
function parseFragmentOrDocument(html) {
|
|
2474
2480
|
const wrapped = !/^(?:<!doctype|<html[\s>/])/i.test(
|
|
2475
2481
|
html.replace(/^(?:\s|<!--(?:>|->|[\s\S]*?-->))*/, "")
|
|
2476
2482
|
);
|
|
2477
2483
|
const { document } = wrapped ? parseHTML(`<!DOCTYPE html><html><head></head><body>${html}</body></html>`) : parseHTML(html);
|
|
2484
|
+
return { document, wrapped };
|
|
2485
|
+
}
|
|
2486
|
+
function stampHfIdsInPlace(html) {
|
|
2487
|
+
const { document, wrapped } = parseFragmentOrDocument(html);
|
|
2478
2488
|
if (!document.body) return html;
|
|
2489
|
+
const elements = wrapped ? getChildElements(document.body).flatMap(inDocumentOrder) : inDocumentOrder(document.documentElement);
|
|
2490
|
+
const existing = elements.map((el) => el.getAttribute("data-hf-id"));
|
|
2491
|
+
const pinned = existing.map((id) => id !== null && id.length > 0);
|
|
2479
2492
|
assignHfIds(document.body);
|
|
2480
|
-
|
|
2493
|
+
const minted = elements.map((el, n) => pinned[n] ? null : el.getAttribute("data-hf-id"));
|
|
2494
|
+
const tags = startTags(html);
|
|
2495
|
+
const inserts = tags && alignInserts(html, tags, elements, minted, existing);
|
|
2496
|
+
return inserts ? spliceIds(html, inserts) : ensureHfIds(html);
|
|
2497
|
+
}
|
|
2498
|
+
function inDocumentOrder(el) {
|
|
2499
|
+
return [el, ...getChildElements(el).flatMap(inDocumentOrder)];
|
|
2500
|
+
}
|
|
2501
|
+
var RAW_TEXT = /* @__PURE__ */ new Set(["script", "style", "textarea", "title", "xmp", "noembed", "noframes"]);
|
|
2502
|
+
var IMPLIED = /* @__PURE__ */ new Set(["html", "head", "body", "tbody"]);
|
|
2503
|
+
function startTags(html) {
|
|
2504
|
+
const lower = html.toLowerCase();
|
|
2505
|
+
const tags = [];
|
|
2506
|
+
let i = html.indexOf("<");
|
|
2507
|
+
while (i >= 0) {
|
|
2508
|
+
const name = html.startsWith("<!--", i) ? null : /^<([a-zA-Z][^\s/>]*)/.exec(html.slice(i, i + 128));
|
|
2509
|
+
if (!name) {
|
|
2510
|
+
i = nextTagAfter(html, i);
|
|
2511
|
+
continue;
|
|
2512
|
+
}
|
|
2513
|
+
const end = closingBracket(html, i + name[0].length);
|
|
2514
|
+
if (end < 0) return null;
|
|
2515
|
+
const tag = name[1].toLowerCase();
|
|
2516
|
+
tags.push({ name: tag, nameEnd: i + name[0].length, bracket: end });
|
|
2517
|
+
const after = RAW_TEXT.has(tag) ? rawTextEnd(lower, tag, end) : end;
|
|
2518
|
+
i = after < 0 ? -1 : html.indexOf("<", after + 1);
|
|
2519
|
+
}
|
|
2520
|
+
return tags;
|
|
2521
|
+
}
|
|
2522
|
+
function rawTextEnd(lower, tag, from) {
|
|
2523
|
+
const marker = `</${tag}`;
|
|
2524
|
+
for (let at = lower.indexOf(marker, from); at >= 0; at = lower.indexOf(marker, at + marker.length)) {
|
|
2525
|
+
const next = lower[at + marker.length];
|
|
2526
|
+
if (next !== void 0 && /[\s/>]/.test(next)) return at;
|
|
2527
|
+
}
|
|
2528
|
+
return -1;
|
|
2529
|
+
}
|
|
2530
|
+
function nextTagAfter(html, lt) {
|
|
2531
|
+
const comment = html.startsWith("<!--", lt);
|
|
2532
|
+
const end = comment ? html.indexOf("-->", lt + 4) : html.indexOf(">", lt);
|
|
2533
|
+
return end < 0 ? -1 : html.indexOf("<", end + 1);
|
|
2534
|
+
}
|
|
2535
|
+
function closingBracket(html, from) {
|
|
2536
|
+
let quote = "";
|
|
2537
|
+
for (let i = from; i < html.length; i++) {
|
|
2538
|
+
const c = html[i];
|
|
2539
|
+
if (quote) quote = c === quote ? "" : quote;
|
|
2540
|
+
else if (c === '"' || c === "'") quote = c;
|
|
2541
|
+
else if (c === ">") return i;
|
|
2542
|
+
}
|
|
2543
|
+
return -1;
|
|
2544
|
+
}
|
|
2545
|
+
function alignInserts(html, tags, elements, minted, existing) {
|
|
2546
|
+
const walked = walkAlign(html, tags, elements, minted, existing);
|
|
2547
|
+
if (!walked) return null;
|
|
2548
|
+
return walked.next === tags.length ? walked.inserts : null;
|
|
2549
|
+
}
|
|
2550
|
+
function walkAlign(html, tags, elements, minted, existing) {
|
|
2551
|
+
const state = { inserts: [], next: 0 };
|
|
2552
|
+
for (const [n, el] of elements.entries()) {
|
|
2553
|
+
if (!take(state, html, tags, el, minted[n] ?? null, existing[n] === "")) return null;
|
|
2554
|
+
}
|
|
2555
|
+
return state;
|
|
2556
|
+
}
|
|
2557
|
+
function take(state, html, tags, el, id, fillEmpty) {
|
|
2558
|
+
const step = alignOne(html, tags[state.next], el, id, fillEmpty);
|
|
2559
|
+
if (!step) return false;
|
|
2560
|
+
if (step.insert) state.inserts.push(step.insert);
|
|
2561
|
+
if (step.next) state.next += 1;
|
|
2562
|
+
return true;
|
|
2563
|
+
}
|
|
2564
|
+
function alignOne(html, tag, el, id, fillEmpty) {
|
|
2565
|
+
if (tag?.name === el.tagName.toLowerCase()) return matched(html, tag, id, fillEmpty);
|
|
2566
|
+
if (IMPLIED.has(el.tagName.toLowerCase()) && !id) return { insert: null, next: false };
|
|
2567
|
+
return null;
|
|
2568
|
+
}
|
|
2569
|
+
function matched(html, tag, id, fillEmpty) {
|
|
2570
|
+
if (!id) return { insert: null, next: true };
|
|
2571
|
+
const placed = placeId(html, tag, id, fillEmpty);
|
|
2572
|
+
if (!placed) return null;
|
|
2573
|
+
return { insert: placed, next: true };
|
|
2574
|
+
}
|
|
2575
|
+
function placeId(html, tag, id, fillEmpty) {
|
|
2576
|
+
if (!fillEmpty) return { at: tag.nameEnd, text: ` data-hf-id="${id}"` };
|
|
2577
|
+
const emptyAt = emptyHfIdValue(html, tag);
|
|
2578
|
+
if (emptyAt === null) return null;
|
|
2579
|
+
return { at: emptyAt, text: id };
|
|
2580
|
+
}
|
|
2581
|
+
function emptyHfIdValue(html, tag) {
|
|
2582
|
+
const open = outsideQuotes(html.slice(tag.nameEnd, tag.bracket));
|
|
2583
|
+
const match = /\sdata-hf-id\s*=\s*(["'])\1/i.exec(open);
|
|
2584
|
+
if (!match) return null;
|
|
2585
|
+
return tag.nameEnd + match.index + match[0].length - 1;
|
|
2586
|
+
}
|
|
2587
|
+
function outsideQuotes(open) {
|
|
2588
|
+
let quote = "";
|
|
2589
|
+
let out = "";
|
|
2590
|
+
for (const c of open) {
|
|
2591
|
+
out += quotedChar(quote, c);
|
|
2592
|
+
quote = quoteOf(quote, c);
|
|
2593
|
+
}
|
|
2594
|
+
return out;
|
|
2595
|
+
}
|
|
2596
|
+
function quoteOf(quote, c) {
|
|
2597
|
+
if (quote) return c === quote ? "" : quote;
|
|
2598
|
+
return c === '"' || c === "'" ? c : "";
|
|
2599
|
+
}
|
|
2600
|
+
function quotedChar(quote, c) {
|
|
2601
|
+
if (!quote || c === quote) return c;
|
|
2602
|
+
return " ".repeat(c.length);
|
|
2603
|
+
}
|
|
2604
|
+
function spliceIds(html, inserts) {
|
|
2605
|
+
let out = "";
|
|
2606
|
+
let from = 0;
|
|
2607
|
+
for (const { at, text } of inserts) {
|
|
2608
|
+
out += html.slice(from, at) + text;
|
|
2609
|
+
from = at;
|
|
2610
|
+
}
|
|
2611
|
+
return out + html.slice(from);
|
|
2481
2612
|
}
|
|
2482
2613
|
|
|
2483
2614
|
// src/utils/cssSelector.ts
|
|
@@ -4501,6 +4632,7 @@ export {
|
|
|
4501
4632
|
scanHtmlOpeningTags,
|
|
4502
4633
|
scanVariableUsage,
|
|
4503
4634
|
serializeGsapAnimations,
|
|
4635
|
+
stampHfIdsInPlace,
|
|
4504
4636
|
suggestMatchingPreset,
|
|
4505
4637
|
timingMismatches,
|
|
4506
4638
|
topLevelElements,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyperframes/parsers",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.158",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/heygen-com/hyperframes",
|
|
@@ -119,7 +119,7 @@
|
|
|
119
119
|
"tsx": "^4.21.0",
|
|
120
120
|
"typescript": "^5.0.0",
|
|
121
121
|
"vitest": "^4.1.11",
|
|
122
|
-
"@hyperframes/core": "0.8.
|
|
122
|
+
"@hyperframes/core": "0.8.158"
|
|
123
123
|
},
|
|
124
124
|
"scripts": {
|
|
125
125
|
"build": "tsup",
|