@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/bundle-uAAHehbv.d.ts +23 -0
- package/dist/chunk-CIOYDRY5.js +851 -0
- package/dist/chunk-CIOYDRY5.js.map +1 -0
- package/dist/chunk-EXYXTAZM.js +91 -0
- package/dist/chunk-EXYXTAZM.js.map +1 -0
- package/dist/{chunk-XKWWXKP3.js → chunk-IPYHS5R2.js} +157 -87
- package/dist/chunk-IPYHS5R2.js.map +1 -0
- package/dist/{chunk-Q6M5JEL3.js → chunk-XQVKA54A.js} +150 -6
- package/dist/chunk-XQVKA54A.js.map +1 -0
- package/dist/chunk-XYP3VYDH.js +159 -0
- package/dist/chunk-XYP3VYDH.js.map +1 -0
- package/dist/cli/index.js +4 -3
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +8 -87
- package/dist/index.js +29 -353
- package/dist/index.js.map +1 -1
- package/dist/lib/index.d.ts +14 -4
- package/dist/lib/index.js +7 -3
- package/dist/normalizer/index.d.ts +4 -2
- package/dist/rewrite-inline-images-DPoxyzVC.d.ts +21 -0
- package/dist/sinks/index.d.ts +262 -3
- package/dist/sinks/index.js +5 -3
- package/dist/transformers/index.d.ts +157 -0
- package/dist/transformers/index.js +32 -0
- package/dist/transformers/index.js.map +1 -0
- package/dist/{bundle-DfM_jKbq.d.ts → types-DWOP8Dcy.d.ts} +1 -21
- package/package.json +5 -1
- package/dist/chunk-2PNSVE5Y.js +0 -67
- package/dist/chunk-2PNSVE5Y.js.map +0 -1
- package/dist/chunk-Q6M5JEL3.js.map +0 -1
- package/dist/chunk-XKWWXKP3.js.map +0 -1
- package/dist/index-D88mjcF5.d.ts +0 -279
package/dist/index.js
CHANGED
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
squarespaceAdapter,
|
|
16
16
|
wixAdapter,
|
|
17
17
|
wordpressAdapter
|
|
18
|
-
} from "./chunk-
|
|
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-
|
|
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
|
-
|
|
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":[]}
|
package/dist/lib/index.d.ts
CHANGED
|
@@ -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
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
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
|
-
|
|
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 {
|
|
2
|
-
export { A as AdapterContext,
|
|
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 };
|