@artinstack/migrator 0.1.4 → 0.1.6

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/index.js CHANGED
@@ -15,7 +15,7 @@ import {
15
15
  squarespaceAdapter,
16
16
  wixAdapter,
17
17
  wordpressAdapter
18
- } from "./chunk-Q6M5JEL3.js";
18
+ } from "./chunk-XQVKA54A.js";
19
19
  import {
20
20
  normalizedAssetExifSchema,
21
21
  normalizedAssetSchema,
@@ -53,13 +53,12 @@ import {
53
53
  hasWarnings,
54
54
  mapJsonPrettyWire,
55
55
  portfolioMediaMatchesBundle,
56
- rewriteInlineImages,
57
56
  runDryRun,
58
57
  runMigration,
59
58
  runMigrationFromBundle,
60
59
  staleUrlsFromEstimate,
61
60
  writeFilesystemExport
62
- } from "./chunk-XKWWXKP3.js";
61
+ } from "./chunk-IPYHS5R2.js";
63
62
  import {
64
63
  buildPortfolioMediaLinks,
65
64
  bundleCounts,
@@ -69,361 +68,31 @@ import {
69
68
  isTerminalState,
70
69
  shouldProcessEntity
71
70
  } from "./chunk-HI7JHWZU.js";
71
+ import {
72
+ cssToStyles,
73
+ grapesComponentSchema,
74
+ grapesProjectSnapshotSchema,
75
+ grapesStyleRuleSchema,
76
+ htmlToGrapes,
77
+ htmlToTiptap,
78
+ tiptapDocSchema,
79
+ tiptapMarkSchema,
80
+ tiptapNodeSchema,
81
+ validateGrapesProjectSnapshot,
82
+ validateTiptapDoc
83
+ } from "./chunk-CIOYDRY5.js";
84
+ import {
85
+ rewriteInlineImages
86
+ } from "./chunk-EXYXTAZM.js";
72
87
  import {
73
88
  discoverContentAssetUrls,
89
+ discoverFeaturedAssetCandidateUrls,
74
90
  discoverRawImgSrcs,
75
91
  extractInlineImageSrcs,
76
92
  isLikelyImageUrl,
77
- normalizeAssetUrl
78
- } from "./chunk-2PNSVE5Y.js";
79
-
80
- // src/transformers/html-to-grapes/index.ts
81
- import * as cheerio from "cheerio";
82
-
83
- // src/transformers/css-to-styles/index.ts
84
- function stripCssComments(css) {
85
- return css.replace(/\/\*[\s\S]*?\*\//g, "");
86
- }
87
- function parseDeclarations(block) {
88
- const style = {};
89
- for (const declaration of block.split(";")) {
90
- const trimmed = declaration.trim();
91
- if (!trimmed) continue;
92
- const separator = trimmed.indexOf(":");
93
- if (separator === -1) continue;
94
- const property = trimmed.slice(0, separator).trim();
95
- const value = trimmed.slice(separator + 1).trim();
96
- if (!property || !value) continue;
97
- style[property] = value;
98
- }
99
- return style;
100
- }
101
- function cssToStyles(css) {
102
- const cleaned = stripCssComments(css);
103
- const rules = [];
104
- const rulePattern = /([^{]+)\{([^}]*)\}/g;
105
- for (const match of cleaned.matchAll(rulePattern)) {
106
- const selectorText = match[1]?.trim() ?? "";
107
- const declarationBlock = match[2] ?? "";
108
- if (!selectorText || selectorText.startsWith("@")) continue;
109
- const style = parseDeclarations(declarationBlock);
110
- if (Object.keys(style).length === 0) continue;
111
- const selectors = selectorText.split(",").map((selector) => selector.trim()).filter(Boolean);
112
- if (selectors.length === 0) continue;
113
- rules.push({ selectors, style });
114
- }
115
- return rules;
116
- }
117
-
118
- // src/transformers/html-to-grapes/walk.ts
119
- var INLINE_TAGS = /* @__PURE__ */ new Set([
120
- "a",
121
- "abbr",
122
- "b",
123
- "br",
124
- "cite",
125
- "code",
126
- "del",
127
- "em",
128
- "i",
129
- "img",
130
- "ins",
131
- "mark",
132
- "q",
133
- "s",
134
- "small",
135
- "span",
136
- "strong",
137
- "sub",
138
- "sup",
139
- "u",
140
- "wbr"
141
- ]);
142
- var VOID_TAGS = /* @__PURE__ */ new Set([
143
- "area",
144
- "base",
145
- "br",
146
- "col",
147
- "embed",
148
- "hr",
149
- "img",
150
- "input",
151
- "link",
152
- "meta",
153
- "param",
154
- "source",
155
- "track",
156
- "wbr"
157
- ]);
158
- var TEXT_CONTAINER_TAGS = /* @__PURE__ */ new Set([
159
- "blockquote",
160
- "figcaption",
161
- "h1",
162
- "h2",
163
- "h3",
164
- "h4",
165
- "h5",
166
- "h6",
167
- "label",
168
- "li",
169
- "p",
170
- "pre",
171
- "td",
172
- "th"
173
- ]);
174
- var SKIP_TAGS = /* @__PURE__ */ new Set(["script", "style", "noscript", "template"]);
175
- var DEFAULT_TYPES = {
176
- a: "link",
177
- img: "image"
178
- };
179
- function tagNameOf($el) {
180
- const raw = $el.prop("tagName");
181
- return typeof raw === "string" ? raw.toLowerCase() : void 0;
182
- }
183
- function applyElementMeta(component, meta) {
184
- if (meta.attributes) component.attributes = meta.attributes;
185
- if (meta.classes) component.classes = meta.classes;
186
- return component;
187
- }
188
- function pickElementMeta($el) {
189
- const attributes = {};
190
- const classes = [];
191
- if (typeof $el.attr() === "object") {
192
- for (const [key, value] of Object.entries($el.attr() ?? {})) {
193
- if (key === "class") {
194
- classes.push(...value.split(/\s+/).filter(Boolean));
195
- continue;
196
- }
197
- attributes[key] = value;
198
- }
199
- }
200
- return {
201
- attributes: Object.keys(attributes).length > 0 ? attributes : void 0,
202
- classes: classes.length > 0 ? classes : void 0
203
- };
204
- }
205
- function resolveComponentType(tagName, classes, options) {
206
- if (options.componentMap && classes) {
207
- for (const className of classes) {
208
- const mapped = options.componentMap[className];
209
- if (mapped) return mapped;
210
- }
211
- }
212
- return DEFAULT_TYPES[tagName] ?? "default";
213
- }
214
- function hasOnlyInlineContent($, $el) {
215
- let inlineOnly = true;
216
- $el.contents().each((_, node) => {
217
- if (!inlineOnly) return;
218
- const $child = $(node);
219
- if ($child.get(0)?.type === "text") return;
220
- const childTag = tagNameOf($child);
221
- if (!childTag || !INLINE_TAGS.has(childTag)) {
222
- inlineOnly = false;
223
- return;
224
- }
225
- if (!hasOnlyInlineContent($, $child)) {
226
- inlineOnly = false;
227
- }
228
- });
229
- return inlineOnly;
230
- }
231
- function walkChildren($, $el, options) {
232
- const components = [];
233
- $el.contents().each((_, node) => {
234
- const walked = walkNode($, $(node), options);
235
- if (!walked) return;
236
- if (Array.isArray(walked)) {
237
- components.push(...walked);
238
- } else {
239
- components.push(walked);
240
- }
241
- });
242
- return components;
243
- }
244
- function walkNode($, $el, options) {
245
- const node = $el.get(0);
246
- if (!node) return null;
247
- if (node.type === "text") {
248
- const text = "data" in node ? String(node.data ?? "") : "";
249
- if (!text.trim()) return null;
250
- return { type: "textnode", content: text };
251
- }
252
- if (node.type !== "tag") return null;
253
- const tagName = tagNameOf($el);
254
- if (!tagName || SKIP_TAGS.has(tagName)) return null;
255
- const meta = pickElementMeta($el);
256
- if (VOID_TAGS.has(tagName)) {
257
- return applyElementMeta(
258
- {
259
- type: resolveComponentType(tagName, meta.classes, options),
260
- tagName,
261
- void: true
262
- },
263
- meta
264
- );
265
- }
266
- if (TEXT_CONTAINER_TAGS.has(tagName) && hasOnlyInlineContent($, $el)) {
267
- return applyElementMeta(
268
- {
269
- type: "text",
270
- tagName,
271
- content: $el.html() ?? ""
272
- },
273
- meta
274
- );
275
- }
276
- if (INLINE_TAGS.has(tagName)) {
277
- return applyElementMeta(
278
- {
279
- type: "text",
280
- content: $.html($el) ?? ""
281
- },
282
- meta
283
- );
284
- }
285
- const components = walkChildren($, $el, options);
286
- const component = applyElementMeta(
287
- {
288
- type: resolveComponentType(tagName, meta.classes, options),
289
- tagName
290
- },
291
- meta
292
- );
293
- if (components.length > 0) {
294
- component.components = components;
295
- }
296
- return component;
297
- }
298
- function appendWalked(content, walked) {
299
- if (!walked) return;
300
- if (Array.isArray(walked)) {
301
- content.push(...walked);
302
- return;
303
- }
304
- content.push(walked);
305
- }
306
- function walkNodes($, $nodes, content, options) {
307
- $nodes.each((_, node) => {
308
- appendWalked(content, walkNode($, $(node), options));
309
- });
310
- }
311
- function walkHtmlToComponents($, options = {}) {
312
- const content = [];
313
- const body = $("body");
314
- if (body.length) {
315
- walkNodes($, body.contents(), content, options);
316
- return content;
317
- }
318
- const children = $.root().children();
319
- if (children.length) {
320
- walkNodes($, children, content, options);
321
- } else {
322
- walkNodes($, $.root().contents(), content, options);
323
- }
324
- return content;
325
- }
326
-
327
- // src/transformers/html-to-grapes/index.ts
328
- function htmlToGrapes(html, options = {}) {
329
- const trimmed = html.trim();
330
- if (!trimmed) {
331
- return { content: [], styles: [] };
332
- }
333
- const $ = cheerio.load(trimmed, { xml: false });
334
- const styleBlocks = [];
335
- $("style").each((_, element) => {
336
- styleBlocks.push($(element).html() ?? "");
337
- $(element).remove();
338
- });
339
- const contentCss = styleBlocks.join("\n").trim();
340
- const styles = cssToStyles(contentCss);
341
- const content = walkHtmlToComponents($, options);
342
- const contentHtml = serializeContentHtml($);
343
- return {
344
- content,
345
- styles,
346
- ...contentHtml ? { contentHtml } : {},
347
- ...contentCss ? { contentCss } : {}
348
- };
349
- }
350
- function serializeContentHtml($) {
351
- const body = $("body");
352
- if (body.length) {
353
- const html = body.html()?.trim();
354
- return html || void 0;
355
- }
356
- const rootHtml = $.root().html()?.trim();
357
- return rootHtml || void 0;
358
- }
359
-
360
- // src/transformers/validate-snapshot.ts
361
- import { z } from "zod";
362
- var grapesStyleRuleSchema = z.object({
363
- selectors: z.array(z.string().min(1)).min(1),
364
- style: z.record(z.string(), z.string())
365
- });
366
- var grapesComponentSchema = z.lazy(
367
- () => z.object({
368
- type: z.string().min(1),
369
- tagName: z.string().optional(),
370
- attributes: z.record(z.string(), z.string()).optional(),
371
- classes: z.array(z.string()).optional(),
372
- components: z.array(grapesComponentSchema).optional(),
373
- content: z.string().optional(),
374
- void: z.boolean().optional()
375
- })
376
- );
377
- var grapesProjectSnapshotSchema = z.object({
378
- content: z.array(grapesComponentSchema),
379
- styles: z.array(grapesStyleRuleSchema),
380
- contentHtml: z.string().optional(),
381
- contentCss: z.string().optional()
382
- });
383
- function zodIssuesToValidationIssues(issues) {
384
- return issues.map((issue) => ({
385
- code: issue.code,
386
- message: issue.message,
387
- path: issue.path.length > 0 ? issue.path.join(".") : void 0
388
- }));
389
- }
390
- function collectComponentTypes(components) {
391
- const types = [];
392
- for (const component of components) {
393
- types.push(component.type);
394
- if (component.components?.length) {
395
- types.push(...collectComponentTypes(component.components));
396
- }
397
- }
398
- return types;
399
- }
400
- function validateAllowedComponentTypes(snapshot, allowedComponentTypes) {
401
- const allowlist = new Set(allowedComponentTypes);
402
- const issues = [];
403
- for (const componentType of collectComponentTypes(snapshot.content)) {
404
- if (!allowlist.has(componentType)) {
405
- issues.push({
406
- code: "invalid_component_type",
407
- message: `Component type "${componentType}" is not in allowedComponentTypes`,
408
- path: "content"
409
- });
410
- }
411
- }
412
- return issues;
413
- }
414
- function validateGrapesProjectSnapshot(snapshot, options = {}) {
415
- const result = grapesProjectSnapshotSchema.safeParse(snapshot);
416
- if (!result.success) {
417
- return { ok: false, issues: zodIssuesToValidationIssues(result.error.issues) };
418
- }
419
- if (options.allowedComponentTypes?.length) {
420
- const typeIssues = validateAllowedComponentTypes(result.data, options.allowedComponentTypes);
421
- if (typeIssues.length > 0) {
422
- return { ok: false, issues: typeIssues };
423
- }
424
- }
425
- return { ok: true, issues: [] };
426
- }
93
+ normalizeAssetUrl,
94
+ resolveFeaturedContentAssetUrl
95
+ } from "./chunk-XYP3VYDH.js";
427
96
  export {
428
97
  FALLBACK_ASSET_BYTES,
429
98
  FilesystemMigrationSink,
@@ -449,6 +118,7 @@ export {
449
118
  cssToStyles,
450
119
  detectRedirectLoops,
451
120
  discoverContentAssetUrls,
121
+ discoverFeaturedAssetCandidateUrls,
452
122
  discoverRawImgSrcs,
453
123
  emptyBundle,
454
124
  emptyConflictReport,
@@ -462,6 +132,7 @@ export {
462
132
  hasBlockingConflicts,
463
133
  hasWarnings,
464
134
  htmlToGrapes,
135
+ htmlToTiptap,
465
136
  isLikelyImageUrl,
466
137
  isTerminalState,
467
138
  mapJsonPrettyWire,
@@ -476,6 +147,7 @@ export {
476
147
  normalizedTagSchema,
477
148
  portfolioMediaMatchesBundle,
478
149
  readSmugMugCredentialsFromEnv,
150
+ resolveFeaturedContentAssetUrl,
479
151
  rewriteInlineImages,
480
152
  rewriteOriginUrlsInText,
481
153
  runDryRun,
@@ -488,6 +160,9 @@ export {
488
160
  sourceMetadataSchema,
489
161
  squarespaceAdapter,
490
162
  staleUrlsFromEstimate,
163
+ tiptapDocSchema,
164
+ tiptapMarkSchema,
165
+ tiptapNodeSchema,
491
166
  validateGrapesProjectSnapshot,
492
167
  validateNormalizedAsset,
493
168
  validateNormalizedCategory,
@@ -496,6 +171,7 @@ export {
496
171
  validateNormalizedPortfolio,
497
172
  validateNormalizedPost,
498
173
  validateNormalizedTag,
174
+ validateTiptapDoc,
499
175
  wixAdapter,
500
176
  wordpressAdapter,
501
177
  writeFilesystemExport
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/transformers/html-to-grapes/index.ts","../src/transformers/css-to-styles/index.ts","../src/transformers/html-to-grapes/walk.ts","../src/transformers/validate-snapshot.ts"],"sourcesContent":["import * as cheerio from \"cheerio\";\n\nimport { cssToStyles } from \"../css-to-styles/index.js\";\nimport type { GrapesProjectSnapshot, HtmlToGrapesOptions } from \"./types.js\";\nimport { walkHtmlToComponents } from \"./walk.js\";\n\nexport type {\n GrapesComponent,\n GrapesProjectSnapshot,\n GrapesStyleRule,\n HtmlToGrapesOptions,\n} from \"./types.js\";\n\n/** Cheerio HTML walk → Grapes `content` + root `styles`. */\nexport function htmlToGrapes(html: string, options: HtmlToGrapesOptions = {}): GrapesProjectSnapshot {\n const trimmed = html.trim();\n if (!trimmed) {\n return { content: [], styles: [] };\n }\n\n const $ = cheerio.load(trimmed, { xml: false });\n const styleBlocks: string[] = [];\n\n $(\"style\").each((_, element) => {\n styleBlocks.push($(element).html() ?? \"\");\n $(element).remove();\n });\n\n const contentCss = styleBlocks.join(\"\\n\").trim();\n const styles = cssToStyles(contentCss);\n const content = walkHtmlToComponents($, options);\n const contentHtml = serializeContentHtml($);\n\n return {\n content,\n styles,\n ...(contentHtml ? { contentHtml } : {}),\n ...(contentCss ? { contentCss } : {}),\n };\n}\n\nfunction serializeContentHtml($: cheerio.CheerioAPI): string | undefined {\n const body = $(\"body\");\n if (body.length) {\n const html = body.html()?.trim();\n return html || undefined;\n }\n\n const rootHtml = $.root().html()?.trim();\n return rootHtml || undefined;\n}\n","import type { GrapesStyleRule } from \"../html-to-grapes/types.js\";\n\nfunction stripCssComments(css: string): string {\n return css.replace(/\\/\\*[\\s\\S]*?\\*\\//g, \"\");\n}\n\nfunction parseDeclarations(block: string): Record<string, string> {\n const style: Record<string, string> = {};\n for (const declaration of block.split(\";\")) {\n const trimmed = declaration.trim();\n if (!trimmed) continue;\n const separator = trimmed.indexOf(\":\");\n if (separator === -1) continue;\n const property = trimmed.slice(0, separator).trim();\n const value = trimmed.slice(separator + 1).trim();\n if (!property || !value) continue;\n style[property] = value;\n }\n return style;\n}\n\n/** Parse `<style>` blocks and class rules into Grapes root `styles[]`. */\nexport function cssToStyles(css: string): GrapesStyleRule[] {\n const cleaned = stripCssComments(css);\n const rules: GrapesStyleRule[] = [];\n const rulePattern = /([^{]+)\\{([^}]*)\\}/g;\n\n for (const match of cleaned.matchAll(rulePattern)) {\n const selectorText = match[1]?.trim() ?? \"\";\n const declarationBlock = match[2] ?? \"\";\n if (!selectorText || selectorText.startsWith(\"@\")) continue;\n\n const style = parseDeclarations(declarationBlock);\n if (Object.keys(style).length === 0) continue;\n\n const selectors = selectorText\n .split(\",\")\n .map((selector) => selector.trim())\n .filter(Boolean);\n\n if (selectors.length === 0) continue;\n rules.push({ selectors, style });\n }\n\n return rules;\n}\n","import type { Cheerio, CheerioAPI } from \"cheerio\";\nimport type { AnyNode } from \"domhandler\";\n\nimport type { GrapesComponent, HtmlToGrapesOptions } from \"./types.js\";\n\ntype CheerioSelection = Cheerio<AnyNode>;\n\nconst INLINE_TAGS = new Set([\n \"a\",\n \"abbr\",\n \"b\",\n \"br\",\n \"cite\",\n \"code\",\n \"del\",\n \"em\",\n \"i\",\n \"img\",\n \"ins\",\n \"mark\",\n \"q\",\n \"s\",\n \"small\",\n \"span\",\n \"strong\",\n \"sub\",\n \"sup\",\n \"u\",\n \"wbr\",\n]);\n\nconst VOID_TAGS = new Set([\n \"area\",\n \"base\",\n \"br\",\n \"col\",\n \"embed\",\n \"hr\",\n \"img\",\n \"input\",\n \"link\",\n \"meta\",\n \"param\",\n \"source\",\n \"track\",\n \"wbr\",\n]);\n\nconst TEXT_CONTAINER_TAGS = new Set([\n \"blockquote\",\n \"figcaption\",\n \"h1\",\n \"h2\",\n \"h3\",\n \"h4\",\n \"h5\",\n \"h6\",\n \"label\",\n \"li\",\n \"p\",\n \"pre\",\n \"td\",\n \"th\",\n]);\n\nconst SKIP_TAGS = new Set([\"script\", \"style\", \"noscript\", \"template\"]);\n\nconst DEFAULT_TYPES: Record<string, string> = {\n a: \"link\",\n img: \"image\",\n};\n\nfunction tagNameOf($el: CheerioSelection): string | undefined {\n const raw = $el.prop(\"tagName\");\n return typeof raw === \"string\" ? raw.toLowerCase() : undefined;\n}\n\nfunction applyElementMeta(\n component: GrapesComponent,\n meta: Pick<GrapesComponent, \"attributes\" | \"classes\">,\n): GrapesComponent {\n if (meta.attributes) component.attributes = meta.attributes;\n if (meta.classes) component.classes = meta.classes;\n return component;\n}\n\nfunction pickElementMeta($el: CheerioSelection): Pick<GrapesComponent, \"attributes\" | \"classes\"> {\n const attributes: Record<string, string> = {};\n const classes: string[] = [];\n\n if (typeof $el.attr() === \"object\") {\n for (const [key, value] of Object.entries($el.attr() ?? {})) {\n if (key === \"class\") {\n classes.push(...value.split(/\\s+/).filter(Boolean));\n continue;\n }\n attributes[key] = value;\n }\n }\n\n return {\n attributes: Object.keys(attributes).length > 0 ? attributes : undefined,\n classes: classes.length > 0 ? classes : undefined,\n };\n}\n\nfunction resolveComponentType(\n tagName: string,\n classes: string[] | undefined,\n options: HtmlToGrapesOptions,\n): string {\n if (options.componentMap && classes) {\n for (const className of classes) {\n const mapped = options.componentMap[className];\n if (mapped) return mapped;\n }\n }\n return DEFAULT_TYPES[tagName] ?? \"default\";\n}\n\nfunction hasOnlyInlineContent($: CheerioAPI, $el: CheerioSelection): boolean {\n let inlineOnly = true;\n\n $el.contents().each((_, node) => {\n if (!inlineOnly) return;\n const $child = $(node);\n if ($child.get(0)?.type === \"text\") return;\n const childTag = tagNameOf($child);\n if (!childTag || !INLINE_TAGS.has(childTag)) {\n inlineOnly = false;\n return;\n }\n if (!hasOnlyInlineContent($, $child)) {\n inlineOnly = false;\n }\n });\n\n return inlineOnly;\n}\n\nfunction walkChildren(\n $: CheerioAPI,\n $el: CheerioSelection,\n options: HtmlToGrapesOptions,\n): GrapesComponent[] {\n const components: GrapesComponent[] = [];\n\n $el.contents().each((_, node) => {\n const walked = walkNode($, $(node), options);\n if (!walked) return;\n if (Array.isArray(walked)) {\n components.push(...walked);\n } else {\n components.push(walked);\n }\n });\n\n return components;\n}\n\nfunction walkNode(\n $: CheerioAPI,\n $el: CheerioSelection,\n options: HtmlToGrapesOptions,\n): GrapesComponent | GrapesComponent[] | null {\n const node = $el.get(0);\n if (!node) return null;\n\n if (node.type === \"text\") {\n const text = \"data\" in node ? String(node.data ?? \"\") : \"\";\n if (!text.trim()) return null;\n return { type: \"textnode\", content: text };\n }\n\n if (node.type !== \"tag\") return null;\n\n const tagName = tagNameOf($el);\n if (!tagName || SKIP_TAGS.has(tagName)) return null;\n\n const meta = pickElementMeta($el);\n\n if (VOID_TAGS.has(tagName)) {\n return applyElementMeta(\n {\n type: resolveComponentType(tagName, meta.classes, options),\n tagName,\n void: true,\n },\n meta,\n );\n }\n\n if (TEXT_CONTAINER_TAGS.has(tagName) && hasOnlyInlineContent($, $el)) {\n return applyElementMeta(\n {\n type: \"text\",\n tagName,\n content: $el.html() ?? \"\",\n },\n meta,\n );\n }\n\n if (INLINE_TAGS.has(tagName)) {\n return applyElementMeta(\n {\n type: \"text\",\n content: $.html($el) ?? \"\",\n },\n meta,\n );\n }\n\n const components = walkChildren($, $el, options);\n const component = applyElementMeta(\n {\n type: resolveComponentType(tagName, meta.classes, options),\n tagName,\n },\n meta,\n );\n\n if (components.length > 0) {\n component.components = components;\n }\n\n return component;\n}\n\nfunction appendWalked(\n content: GrapesComponent[],\n walked: GrapesComponent | GrapesComponent[] | null,\n): void {\n if (!walked) return;\n if (Array.isArray(walked)) {\n content.push(...walked);\n return;\n }\n content.push(walked);\n}\n\nfunction walkNodes(\n $: CheerioAPI,\n $nodes: CheerioSelection,\n content: GrapesComponent[],\n options: HtmlToGrapesOptions,\n): void {\n $nodes.each((_, node) => {\n appendWalked(content, walkNode($, $(node), options));\n });\n}\n\nexport function walkHtmlToComponents(\n $: CheerioAPI,\n options: HtmlToGrapesOptions = {},\n): GrapesComponent[] {\n const content: GrapesComponent[] = [];\n const body = $(\"body\");\n\n if (body.length) {\n walkNodes($, body.contents(), content, options);\n return content;\n }\n\n const children = $.root().children();\n if (children.length) {\n walkNodes($, children, content, options);\n } else {\n walkNodes($, $.root().contents(), content, options);\n }\n\n return content;\n}\n","import { z } from \"zod\";\n\nimport type { ValidationIssue, ValidationResult } from \"../normalizer/types.js\";\nimport type { GrapesComponent, GrapesProjectSnapshot } from \"./html-to-grapes/types.js\";\n\nexport const grapesStyleRuleSchema = z.object({\n selectors: z.array(z.string().min(1)).min(1),\n style: z.record(z.string(), z.string()),\n});\n\nexport const grapesComponentSchema: z.ZodType<GrapesComponent> = z.lazy(() =>\n z.object({\n type: z.string().min(1),\n tagName: z.string().optional(),\n attributes: z.record(z.string(), z.string()).optional(),\n classes: z.array(z.string()).optional(),\n components: z.array(grapesComponentSchema).optional(),\n content: z.string().optional(),\n void: z.boolean().optional(),\n }),\n);\n\nexport const grapesProjectSnapshotSchema = z.object({\n content: z.array(grapesComponentSchema),\n styles: z.array(grapesStyleRuleSchema),\n contentHtml: z.string().optional(),\n contentCss: z.string().optional(),\n});\n\nexport interface ValidateGrapesProjectSnapshotOptions {\n /** When set, every component `type` in the tree must be in this allowlist. */\n allowedComponentTypes?: string[];\n}\n\nfunction zodIssuesToValidationIssues(issues: z.ZodIssue[]): ValidationIssue[] {\n return issues.map((issue) => ({\n code: issue.code,\n message: issue.message,\n path: issue.path.length > 0 ? issue.path.join(\".\") : undefined,\n }));\n}\n\nfunction collectComponentTypes(components: GrapesComponent[]): string[] {\n const types: string[] = [];\n for (const component of components) {\n types.push(component.type);\n if (component.components?.length) {\n types.push(...collectComponentTypes(component.components));\n }\n }\n return types;\n}\n\nfunction validateAllowedComponentTypes(\n snapshot: GrapesProjectSnapshot,\n allowedComponentTypes: string[],\n): ValidationIssue[] {\n const allowlist = new Set(allowedComponentTypes);\n const issues: ValidationIssue[] = [];\n\n for (const componentType of collectComponentTypes(snapshot.content)) {\n if (!allowlist.has(componentType)) {\n issues.push({\n code: \"invalid_component_type\",\n message: `Component type \"${componentType}\" is not in allowedComponentTypes`,\n path: \"content\",\n });\n }\n }\n\n return issues;\n}\n\n/**\n * Opt-in structural check for a Grapes project snapshot (not a full Grapes editor project file).\n * Does not validate host-specific component registries unless `allowedComponentTypes` is passed.\n */\nexport function validateGrapesProjectSnapshot(\n snapshot: unknown,\n options: ValidateGrapesProjectSnapshotOptions = {},\n): ValidationResult {\n const result = grapesProjectSnapshotSchema.safeParse(snapshot);\n if (!result.success) {\n return { ok: false, issues: zodIssuesToValidationIssues(result.error.issues) };\n }\n\n if (options.allowedComponentTypes?.length) {\n const typeIssues = validateAllowedComponentTypes(result.data, options.allowedComponentTypes);\n if (typeIssues.length > 0) {\n return { ok: false, issues: typeIssues };\n }\n }\n\n return { ok: true, issues: [] };\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -5,12 +5,22 @@ declare function normalizeAssetUrl(raw: string): string | undefined;
5
5
  /** Heuristic: URL likely points at a raster/vector image asset, not a page link. */
6
6
  declare function isLikelyImageUrl(url: string): boolean;
7
7
  /**
8
- * Generic content-discovery pass: collect image URLs from HTML `<img>` tags and
9
- * common shortcode/builder attributes (`src=`, `image=`, `url=`) without parsing
10
- * builder-specific structure (Tatsu, Elementor, etc.).
8
+ * Ordered featured-image candidates when `_thumbnail_id` is missing heroes
9
+ * (`data-bg-image`, CSS backgrounds, `bg_image=`) before inline assets; within
10
+ * each tier, first in document order wins. Filename tokens (`_w`, `_2048`, )
11
+ * are not interpreted as quality signals.
12
+ */
13
+ declare function discoverFeaturedAssetCandidateUrls(content: string): string[];
14
+ /** Best featured-image URL from post/page HTML when attachment id is unavailable. */
15
+ declare function resolveFeaturedContentAssetUrl(content: string): string | undefined;
16
+ /**
17
+ * Generic content-discovery pass: collect image URLs from HTML `<img>` tags,
18
+ * section hero markers (`data-bg-image`), inline CSS backgrounds, and common
19
+ * shortcode/builder attributes (`src=`, `image=`, `bg_image=`, …) without
20
+ * parsing builder-specific structure (Tatsu, Elementor, etc.).
11
21
  */
12
22
  declare function discoverContentAssetUrls(content: string): string[];
13
23
  /** @deprecated Use discoverContentAssetUrls — kept for call-site clarity during transition. */
14
24
  declare function extractInlineImageSrcs(content: string): string[];
15
25
 
16
- export { discoverContentAssetUrls, discoverRawImgSrcs, extractInlineImageSrcs, isLikelyImageUrl, normalizeAssetUrl };
26
+ export { discoverContentAssetUrls, discoverFeaturedAssetCandidateUrls, discoverRawImgSrcs, extractInlineImageSrcs, isLikelyImageUrl, normalizeAssetUrl, resolveFeaturedContentAssetUrl };
package/dist/lib/index.js CHANGED
@@ -1,15 +1,19 @@
1
1
  import {
2
2
  discoverContentAssetUrls,
3
+ discoverFeaturedAssetCandidateUrls,
3
4
  discoverRawImgSrcs,
4
5
  extractInlineImageSrcs,
5
6
  isLikelyImageUrl,
6
- normalizeAssetUrl
7
- } from "../chunk-2PNSVE5Y.js";
7
+ normalizeAssetUrl,
8
+ resolveFeaturedContentAssetUrl
9
+ } from "../chunk-XYP3VYDH.js";
8
10
  export {
9
11
  discoverContentAssetUrls,
12
+ discoverFeaturedAssetCandidateUrls,
10
13
  discoverRawImgSrcs,
11
14
  extractInlineImageSrcs,
12
15
  isLikelyImageUrl,
13
- normalizeAssetUrl
16
+ normalizeAssetUrl,
17
+ resolveFeaturedContentAssetUrl
14
18
  };
15
19
  //# sourceMappingURL=index.js.map
@@ -1,5 +1,7 @@
1
- import { d as MigrationCursor, b as EntityKey, E as EntityBundle, P as PortfolioMediaLink, V as ValidationResult } from '../bundle-DfM_jKbq.js';
2
- export { A as AdapterContext, B as BundleCounts, c as EntityType, M as MigrationAdapter, a as MigrationPlatform, N as NormalizedAsset, e as NormalizedAssetExif, f as NormalizedCategory, g as NormalizedEntity, h as NormalizedPage, i as NormalizedPortfolio, j as NormalizedPost, k as NormalizedTag, l as PublishStatus, S as SourceMetadata, m as ValidationIssue, n as bundleCounts, o as collectEntities, p as emptyBundle, q as entityKey } from '../bundle-DfM_jKbq.js';
1
+ import { i as MigrationCursor, E as EntityKey, P as PortfolioMediaLink, l as ValidationResult } from '../types-DWOP8Dcy.js';
2
+ export { A as AdapterContext, h as EntityType, M as MigrationAdapter, g as MigrationPlatform, b as NormalizedAsset, j as NormalizedAssetExif, d as NormalizedCategory, f as NormalizedEntity, a as NormalizedPage, c as NormalizedPortfolio, N as NormalizedPost, e as NormalizedTag, k as PublishStatus, S as SourceMetadata, V as ValidationIssue, m as entityKey } from '../types-DWOP8Dcy.js';
3
+ import { E as EntityBundle } from '../bundle-uAAHehbv.js';
4
+ export { B as BundleCounts, b as bundleCounts, c as collectEntities, e as emptyBundle } from '../bundle-uAAHehbv.js';
3
5
  import { z } from 'zod';
4
6
 
5
7
  /** Portable entity state for resume / idempotency (not Directus field names). */
@@ -0,0 +1,21 @@
1
+ interface RewriteInlineImageRef {
2
+ originalSrc: string;
3
+ sourceAssetId?: string;
4
+ }
5
+ interface UploadedAssetRef {
6
+ targetId: string;
7
+ publicUrl?: string;
8
+ }
9
+ interface RewriteInlineImagesOptions {
10
+ resolveAsset: (src: string) => RewriteInlineImageRef | undefined;
11
+ replaceWith: (ref: RewriteInlineImageRef, uploaded: UploadedAssetRef) => string;
12
+ }
13
+ interface RewriteInlineImagesResult {
14
+ html: string;
15
+ referencedSources: string[];
16
+ unresolved: string[];
17
+ }
18
+ /** Rewrite `<img src>` / `srcset`, `data-bg-image`, and inline CSS backgrounds using uploaded asset targets. */
19
+ declare function rewriteInlineImages(html: string, options: RewriteInlineImagesOptions, uploadedBySourceId: Map<string, UploadedAssetRef>): RewriteInlineImagesResult;
20
+
21
+ export { type RewriteInlineImageRef as R, type UploadedAssetRef as U, type RewriteInlineImagesOptions as a, type RewriteInlineImagesResult as b, rewriteInlineImages as r };