@artinstack/migrator 0.1.10 → 0.1.13
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/README.md +2 -1
- package/dist/{bundle-Do-9ikQv.d.ts → bundle-BgoXkWMy.d.ts} +1 -1
- package/dist/{chunk-3YJFSTYR.js → chunk-373TTCG7.js} +12 -1
- package/dist/chunk-373TTCG7.js.map +1 -0
- package/dist/chunk-4XZK55RW.js +837 -0
- package/dist/chunk-4XZK55RW.js.map +1 -0
- package/dist/{chunk-YLVPZ4M3.js → chunk-53VXTXGM.js} +97 -524
- package/dist/chunk-53VXTXGM.js.map +1 -0
- package/dist/{chunk-3A2PA4P3.js → chunk-5TRCJONX.js} +4 -232
- package/dist/chunk-5TRCJONX.js.map +1 -0
- package/dist/chunk-HUSXCKPI.js +357 -0
- package/dist/chunk-HUSXCKPI.js.map +1 -0
- package/dist/{chunk-LC7CGWDN.js → chunk-PD5AZX3B.js} +1 -1
- package/dist/chunk-PD5AZX3B.js.map +1 -0
- package/dist/{chunk-S4SUJT2D.js → chunk-VQ5HKNYP.js} +109 -4
- package/dist/chunk-VQ5HKNYP.js.map +1 -0
- package/dist/cli/index.js +5 -4
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +7 -6
- package/dist/normalizer/index.d.ts +106 -4
- package/dist/normalizer/index.js +2 -2
- package/dist/sinks/index.d.ts +2 -2
- package/dist/sinks/index.js +3 -3
- package/dist/transformers/index.d.ts +1 -1
- package/dist/transformers/index.js +3 -2
- package/dist/{types-TCHy3Oko.d.ts → types-Bicgdp4Z.d.ts} +15 -1
- package/package.json +1 -1
- package/dist/chunk-3A2PA4P3.js.map +0 -1
- package/dist/chunk-3YJFSTYR.js.map +0 -1
- package/dist/chunk-BONZ3U3I.js +0 -124
- package/dist/chunk-BONZ3U3I.js.map +0 -1
- package/dist/chunk-LC7CGWDN.js.map +0 -1
- package/dist/chunk-S4SUJT2D.js.map +0 -1
- package/dist/chunk-YLVPZ4M3.js.map +0 -1
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createMigrationMediaRefReplaceWith,
|
|
3
|
+
isMigrationMediaRef,
|
|
4
|
+
normalizeAssetUrl,
|
|
5
|
+
resolveMigrationMediaSourceId
|
|
6
|
+
} from "./chunk-S4GMDRGX.js";
|
|
7
|
+
|
|
8
|
+
// src/transformers/rewrite-inline-images.ts
|
|
9
|
+
import * as cheerio from "cheerio";
|
|
10
|
+
var BACKGROUND_IMAGE_URL_PATTERN = /background(?:-image)?\s*:[^;]*?url\s*\(\s*(['"]?)([^'")]+)\1\s*\)/gi;
|
|
11
|
+
function resolveRewriteOptions(options) {
|
|
12
|
+
const replaceWith = options.replaceWith ?? createMigrationMediaRefReplaceWith();
|
|
13
|
+
const requireUploaded = options.requireUploaded ?? Boolean(options.replaceWith);
|
|
14
|
+
return { replaceWith, requireUploaded };
|
|
15
|
+
}
|
|
16
|
+
function tryRewriteUrl(src, options, uploadedBySourceId, referencedSources, unresolved) {
|
|
17
|
+
const normalized = normalizeAssetUrl(src);
|
|
18
|
+
if (!normalized) return void 0;
|
|
19
|
+
if (isMigrationMediaRef(normalized)) {
|
|
20
|
+
referencedSources.add(normalized);
|
|
21
|
+
return normalized;
|
|
22
|
+
}
|
|
23
|
+
referencedSources.add(normalized);
|
|
24
|
+
const ref = options.resolveAsset(normalized);
|
|
25
|
+
if (!ref?.sourceAssetId) {
|
|
26
|
+
unresolved.add(normalized);
|
|
27
|
+
return void 0;
|
|
28
|
+
}
|
|
29
|
+
const { replaceWith, requireUploaded } = resolveRewriteOptions(options);
|
|
30
|
+
const uploaded = uploadedBySourceId.get(ref.sourceAssetId);
|
|
31
|
+
if (requireUploaded && !uploaded) {
|
|
32
|
+
unresolved.add(normalized);
|
|
33
|
+
return void 0;
|
|
34
|
+
}
|
|
35
|
+
return replaceWith(ref, uploaded);
|
|
36
|
+
}
|
|
37
|
+
function rewriteBackgroundUrlsInStyle(style, options, uploadedBySourceId, referencedSources, unresolved) {
|
|
38
|
+
return style.replace(BACKGROUND_IMAGE_URL_PATTERN, (full, quote, rawUrl) => {
|
|
39
|
+
const replaced = tryRewriteUrl(rawUrl.trim(), options, uploadedBySourceId, referencedSources, unresolved);
|
|
40
|
+
if (!replaced) return full;
|
|
41
|
+
const urlCall = quote ? `url(${quote}${replaced}${quote})` : `url(${replaced})`;
|
|
42
|
+
return full.replace(/url\s*\(\s*(['"]?)([^'")]+)\1\s*\)/i, urlCall);
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
function rewriteSrcset(srcset, options, uploadedBySourceId, referencedSources, unresolved) {
|
|
46
|
+
return srcset.split(",").map((entry) => {
|
|
47
|
+
const trimmed = entry.trim();
|
|
48
|
+
if (!trimmed) return entry;
|
|
49
|
+
const [urlPart, descriptor] = trimmed.split(/\s+/, 2);
|
|
50
|
+
const replaced = tryRewriteUrl(urlPart ?? "", options, uploadedBySourceId, referencedSources, unresolved);
|
|
51
|
+
if (!replaced) return entry;
|
|
52
|
+
return descriptor ? `${replaced} ${descriptor}` : replaced;
|
|
53
|
+
}).join(", ");
|
|
54
|
+
}
|
|
55
|
+
function rewriteInlineImages(html, options, uploadedBySourceId) {
|
|
56
|
+
if (!html.trim()) {
|
|
57
|
+
return { html, referencedSources: [], unresolved: [] };
|
|
58
|
+
}
|
|
59
|
+
const $ = cheerio.load(html, { xml: false });
|
|
60
|
+
const referencedSources = /* @__PURE__ */ new Set();
|
|
61
|
+
const unresolved = /* @__PURE__ */ new Set();
|
|
62
|
+
$("img").each((_, element) => {
|
|
63
|
+
const img = $(element);
|
|
64
|
+
const src = img.attr("src")?.trim();
|
|
65
|
+
if (src && !src.startsWith("data:")) {
|
|
66
|
+
const replaced = tryRewriteUrl(src, options, uploadedBySourceId, referencedSources, unresolved);
|
|
67
|
+
if (replaced) img.attr("src", replaced);
|
|
68
|
+
}
|
|
69
|
+
const srcset = img.attr("srcset")?.trim();
|
|
70
|
+
if (srcset) {
|
|
71
|
+
img.attr("srcset", rewriteSrcset(srcset, options, uploadedBySourceId, referencedSources, unresolved));
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
$("[data-bg-image]").each((_, element) => {
|
|
75
|
+
const node = $(element);
|
|
76
|
+
const bgImage = node.attr("data-bg-image")?.trim();
|
|
77
|
+
if (!bgImage || bgImage.startsWith("data:")) return;
|
|
78
|
+
const replaced = tryRewriteUrl(bgImage, options, uploadedBySourceId, referencedSources, unresolved);
|
|
79
|
+
if (replaced) node.attr("data-bg-image", replaced);
|
|
80
|
+
});
|
|
81
|
+
$("[style]").each((_, element) => {
|
|
82
|
+
const node = $(element);
|
|
83
|
+
const style = node.attr("style");
|
|
84
|
+
if (!style?.includes("background")) return;
|
|
85
|
+
const rewritten = rewriteBackgroundUrlsInStyle(
|
|
86
|
+
style,
|
|
87
|
+
options,
|
|
88
|
+
uploadedBySourceId,
|
|
89
|
+
referencedSources,
|
|
90
|
+
unresolved
|
|
91
|
+
);
|
|
92
|
+
if (rewritten !== style) node.attr("style", rewritten);
|
|
93
|
+
});
|
|
94
|
+
return {
|
|
95
|
+
html: $.root().html() ?? html,
|
|
96
|
+
referencedSources: [...referencedSources],
|
|
97
|
+
unresolved: [...unresolved]
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
function stampMigrationMediaRefs(html, options) {
|
|
101
|
+
return rewriteInlineImages(
|
|
102
|
+
html,
|
|
103
|
+
{
|
|
104
|
+
resolveAsset: (src) => {
|
|
105
|
+
const sourceAssetId = resolveMigrationMediaSourceId(
|
|
106
|
+
src,
|
|
107
|
+
options.urlToSourceId,
|
|
108
|
+
options.originUrlRewrite
|
|
109
|
+
);
|
|
110
|
+
if (!sourceAssetId) return void 0;
|
|
111
|
+
return { originalSrc: src, sourceAssetId };
|
|
112
|
+
},
|
|
113
|
+
replaceWith: options.replaceWith,
|
|
114
|
+
requireUploaded: options.requireUploaded ?? false
|
|
115
|
+
},
|
|
116
|
+
/* @__PURE__ */ new Map()
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// src/parsers/wordpress/builders/registry.ts
|
|
121
|
+
function layoutEscapeRegExp(value) {
|
|
122
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
123
|
+
}
|
|
124
|
+
function shortcodeOpenRegex(token) {
|
|
125
|
+
return new RegExp(`\\[${layoutEscapeRegExp(token)}\\b([^\\]]*)\\]`, "gi");
|
|
126
|
+
}
|
|
127
|
+
function shortcodeCloseRegex(token) {
|
|
128
|
+
return new RegExp(`\\[\\/${layoutEscapeRegExp(token)}\\b[^\\]]*\\]`, "gi");
|
|
129
|
+
}
|
|
130
|
+
var FRACTIONAL_COLUMN_WIDTHS = {
|
|
131
|
+
one_col: "100%",
|
|
132
|
+
one_half: "50%",
|
|
133
|
+
one_third: "33.33%",
|
|
134
|
+
two_third: "66.67%",
|
|
135
|
+
two_thirds: "66.67%",
|
|
136
|
+
one_fourth: "25%",
|
|
137
|
+
three_fourth: "75%",
|
|
138
|
+
three_fourths: "75%"
|
|
139
|
+
};
|
|
140
|
+
function parseFractionalColumnWidth(token) {
|
|
141
|
+
return FRACTIONAL_COLUMN_WIDTHS[token];
|
|
142
|
+
}
|
|
143
|
+
function prefixedLayoutMap(config) {
|
|
144
|
+
return {
|
|
145
|
+
kind: "prefixed",
|
|
146
|
+
sectionRegex: shortcodeOpenRegex(config.section),
|
|
147
|
+
sectionCloseRegex: shortcodeCloseRegex(config.section),
|
|
148
|
+
rowRegex: shortcodeOpenRegex(config.row),
|
|
149
|
+
rowCloseRegex: shortcodeCloseRegex(config.row),
|
|
150
|
+
columnRegex: shortcodeOpenRegex(config.column),
|
|
151
|
+
columnCloseRegex: shortcodeCloseRegex(config.column),
|
|
152
|
+
bgParamName: config.bgParamName,
|
|
153
|
+
colsParamName: config.colsParamName
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
function extendedPrefixedLayoutMap(levels) {
|
|
157
|
+
return { kind: "extended-prefixed", levels };
|
|
158
|
+
}
|
|
159
|
+
function fractionalLayoutMap(config) {
|
|
160
|
+
const columnWidths = {};
|
|
161
|
+
for (const token of config.columns) {
|
|
162
|
+
const width = parseFractionalColumnWidth(token);
|
|
163
|
+
if (width) columnWidths[token] = width;
|
|
164
|
+
}
|
|
165
|
+
return {
|
|
166
|
+
kind: "fractional",
|
|
167
|
+
sectionRegex: shortcodeOpenRegex(config.section),
|
|
168
|
+
sectionCloseRegex: shortcodeCloseRegex(config.section),
|
|
169
|
+
rowRegex: shortcodeOpenRegex(config.row),
|
|
170
|
+
rowCloseRegex: shortcodeCloseRegex(config.row),
|
|
171
|
+
columnTokens: config.columns,
|
|
172
|
+
columnOpenRegexes: config.columns.map(shortcodeOpenRegex),
|
|
173
|
+
columnCloseRegexes: config.columns.map(shortcodeCloseRegex),
|
|
174
|
+
columnWidths,
|
|
175
|
+
bgParamName: config.bgParamName
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
var WP_WIDGET_PLACEHOLDER = "\u200B";
|
|
179
|
+
var WORDPRESS_WIDGET_REGISTRY = {
|
|
180
|
+
mapShortcodePrefixes: [
|
|
181
|
+
"blox_gmap",
|
|
182
|
+
"tatsu_gmap",
|
|
183
|
+
"tatsu_map",
|
|
184
|
+
"et_pb_map",
|
|
185
|
+
"vc_gmaps",
|
|
186
|
+
"vc_map"
|
|
187
|
+
],
|
|
188
|
+
contactFormRules: [
|
|
189
|
+
{ tag: "contact-form-7", source: "contact-form-7", idParam: "id" },
|
|
190
|
+
{ tag: "contact_form", source: "contact-form-7", idParam: "id" },
|
|
191
|
+
{ tag: "gravityform", source: "gravityforms", idParam: "id" },
|
|
192
|
+
{ tag: "ninja_form", source: "ninja-forms", idParam: "id" },
|
|
193
|
+
{ tag: "wpforms", source: "wpforms", idParam: "id" }
|
|
194
|
+
],
|
|
195
|
+
videoShortcodePrefixes: [
|
|
196
|
+
"youtube",
|
|
197
|
+
"vimeo",
|
|
198
|
+
"embed",
|
|
199
|
+
"tatsu_video",
|
|
200
|
+
"et_pb_video",
|
|
201
|
+
"vc_video"
|
|
202
|
+
],
|
|
203
|
+
portfolioShortcode: "portfolio",
|
|
204
|
+
blogShortcodeTags: ["blog", "recent_posts"],
|
|
205
|
+
testimonialsWrapperTags: ["testimonials"],
|
|
206
|
+
testimonialItemTag: "testimonial",
|
|
207
|
+
sliderShortcodeTags: ["rev_slider", "masterslider"],
|
|
208
|
+
galleryShortcode: "gallery",
|
|
209
|
+
idGalleryShortcodes: ["oshine_gallery", "vc_gallery", "nggallery"]
|
|
210
|
+
};
|
|
211
|
+
var UNRESOLVABLE_SHORTCODE_PREFIXES = [
|
|
212
|
+
"woocommerce_cart",
|
|
213
|
+
"woocommerce_checkout",
|
|
214
|
+
"woocommerce_my_account"
|
|
215
|
+
];
|
|
216
|
+
var WORDPRESS_BUILDER_REGISTRY = [
|
|
217
|
+
{
|
|
218
|
+
id: "tatsu",
|
|
219
|
+
detect: /\[(?:\/)?tatsu_/i,
|
|
220
|
+
layoutMap: prefixedLayoutMap({
|
|
221
|
+
section: "tatsu_section",
|
|
222
|
+
row: "tatsu_row",
|
|
223
|
+
column: "tatsu_column",
|
|
224
|
+
bgParamName: "bg_image",
|
|
225
|
+
colsParamName: "layout"
|
|
226
|
+
}),
|
|
227
|
+
wrapperRules: [
|
|
228
|
+
{ shortcodePrefix: "tatsu_text" },
|
|
229
|
+
{ shortcodePrefix: "tatsu_inline_text" },
|
|
230
|
+
{ shortcodePrefix: "tatsu_text_with_shortcodes" },
|
|
231
|
+
{ shortcodePrefix: "tatsu_icon_group" }
|
|
232
|
+
],
|
|
233
|
+
urlRules: [
|
|
234
|
+
{ shortcodePrefix: "tatsu_image", urlParams: ["image", "url", "src"], tag: "img" },
|
|
235
|
+
{ shortcodePrefix: "tatsu_single_image", urlParams: ["image", "url", "src"], tag: "img" }
|
|
236
|
+
],
|
|
237
|
+
iconImageRules: [
|
|
238
|
+
{ shortcodePrefix: "tatsu_icon", imageParam: "icon_image", hrefParam: "href" }
|
|
239
|
+
],
|
|
240
|
+
scaffoldingPrefixes: ["tatsu_"]
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
id: "divi",
|
|
244
|
+
detect: /\[(?:\/)?et_pb_/i,
|
|
245
|
+
layoutMap: prefixedLayoutMap({
|
|
246
|
+
section: "et_pb_section",
|
|
247
|
+
row: "et_pb_row",
|
|
248
|
+
column: "et_pb_column",
|
|
249
|
+
bgParamName: "background_image"
|
|
250
|
+
}),
|
|
251
|
+
urlRules: [{ shortcodePrefix: "et_pb_image", urlParams: ["src", "url"], tag: "img" }],
|
|
252
|
+
scaffoldingPrefixes: ["et_pb_"]
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
id: "wpbakery",
|
|
256
|
+
detect: /\[(?:\/)?vc_/i,
|
|
257
|
+
layoutMap: extendedPrefixedLayoutMap([
|
|
258
|
+
{ role: "section", tokens: ["vc_section"], bgParamName: "bg_image" },
|
|
259
|
+
{ role: "row", tokens: ["vc_row"], colsParamName: "layout" },
|
|
260
|
+
{ role: "column", tokens: ["vc_column_inner", "vc_column"], widthParamName: "width" }
|
|
261
|
+
]),
|
|
262
|
+
urlRules: [
|
|
263
|
+
{ shortcodePrefix: "vc_single_image", urlParams: ["image", "src", "url"], tag: "img" }
|
|
264
|
+
],
|
|
265
|
+
scaffoldingPrefixes: ["vc_"]
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
id: "fusion",
|
|
269
|
+
detect: /\[(?:\/)?fusion_/i,
|
|
270
|
+
layoutMap: prefixedLayoutMap({
|
|
271
|
+
section: "fusion_builder_container",
|
|
272
|
+
row: "fusion_builder_row",
|
|
273
|
+
column: "fusion_builder_column",
|
|
274
|
+
bgParamName: "background_image"
|
|
275
|
+
}),
|
|
276
|
+
scaffoldingPrefixes: ["fusion_"]
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
id: "beaver",
|
|
280
|
+
detect: /\[(?:\/)?fl_(?:row|col|builder)/i,
|
|
281
|
+
layoutMap: extendedPrefixedLayoutMap([
|
|
282
|
+
{ role: "row", tokens: ["fl_row"] },
|
|
283
|
+
{ role: "column", tokens: ["fl_col"] }
|
|
284
|
+
]),
|
|
285
|
+
scaffoldingPrefixes: ["fl_"]
|
|
286
|
+
},
|
|
287
|
+
{
|
|
288
|
+
id: "elementor",
|
|
289
|
+
detect: /\[(?:\/)?elementor[-_]/i,
|
|
290
|
+
urlRules: [
|
|
291
|
+
{ shortcodePrefix: "elementor-widget", urlParams: ["url", "src", "image"], tag: "img" }
|
|
292
|
+
],
|
|
293
|
+
scaffoldingPrefixes: ["elementor_"]
|
|
294
|
+
},
|
|
295
|
+
{
|
|
296
|
+
id: "oshine",
|
|
297
|
+
detect: /\[(?:special_sub_title|special_heading5|blox_\w+|grid_content|grids|testimonial\b|portfolio\b|recent_posts\b|animate_icon\w*|section\b|row\b|one_col|one_third|one_half|one_fourth|two_third|three_fourth|text\b)/i,
|
|
298
|
+
layoutMap: fractionalLayoutMap({
|
|
299
|
+
section: "section",
|
|
300
|
+
row: "row",
|
|
301
|
+
columns: [
|
|
302
|
+
"one_col",
|
|
303
|
+
"one_third",
|
|
304
|
+
"two_third",
|
|
305
|
+
"two_thirds",
|
|
306
|
+
"one_half",
|
|
307
|
+
"one_fourth",
|
|
308
|
+
"three_fourth",
|
|
309
|
+
"three_fourths"
|
|
310
|
+
],
|
|
311
|
+
bgParamName: "bg_image"
|
|
312
|
+
}),
|
|
313
|
+
layoutMaps: [
|
|
314
|
+
extendedPrefixedLayoutMap([
|
|
315
|
+
{ role: "section", tokens: ["blox_row"], bgParamName: "bg_image" },
|
|
316
|
+
{ role: "row", tokens: ["blox_row_inner"], colsParamName: "columns" },
|
|
317
|
+
{
|
|
318
|
+
role: "column",
|
|
319
|
+
tokens: ["blox_column_inner", "blox_column"],
|
|
320
|
+
widthParamName: "width"
|
|
321
|
+
}
|
|
322
|
+
])
|
|
323
|
+
],
|
|
324
|
+
textRules: [
|
|
325
|
+
{
|
|
326
|
+
shortcodePrefix: "special_sub_title",
|
|
327
|
+
fields: [{ param: "title_content", tag: "p" }]
|
|
328
|
+
},
|
|
329
|
+
{
|
|
330
|
+
shortcodePrefix: "special_heading5",
|
|
331
|
+
fields: [
|
|
332
|
+
{ param: "title_content", tag: "h2" },
|
|
333
|
+
{ param: "caption_content", tag: "h4" }
|
|
334
|
+
]
|
|
335
|
+
}
|
|
336
|
+
],
|
|
337
|
+
wrapperRules: [
|
|
338
|
+
{ shortcodePrefix: "grid_content" },
|
|
339
|
+
{ shortcodePrefix: "blox_text" }
|
|
340
|
+
],
|
|
341
|
+
urlRules: [
|
|
342
|
+
{ shortcodePrefix: "blox_image", urlParams: ["image", "img", "src", "url"], tag: "img" }
|
|
343
|
+
],
|
|
344
|
+
scaffoldingPrefixes: ["blox_", "animate_icon"],
|
|
345
|
+
legacyScaffoldingTokens: ["text", "icon", "linebreak", "grids", "testimonials"]
|
|
346
|
+
}
|
|
347
|
+
];
|
|
348
|
+
|
|
349
|
+
export {
|
|
350
|
+
rewriteInlineImages,
|
|
351
|
+
stampMigrationMediaRefs,
|
|
352
|
+
WP_WIDGET_PLACEHOLDER,
|
|
353
|
+
WORDPRESS_WIDGET_REGISTRY,
|
|
354
|
+
UNRESOLVABLE_SHORTCODE_PREFIXES,
|
|
355
|
+
WORDPRESS_BUILDER_REGISTRY
|
|
356
|
+
};
|
|
357
|
+
//# sourceMappingURL=chunk-HUSXCKPI.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/transformers/rewrite-inline-images.ts","../src/parsers/wordpress/builders/registry.ts"],"sourcesContent":["import * as cheerio from \"cheerio\";\n\nimport {\n buildMigrationMediaUrlIndex,\n createMigrationMediaRefReplaceWith,\n isMigrationMediaRef,\n normalizeAssetUrl,\n resolveMigrationMediaSourceId,\n type OriginUrlRewriteConfig,\n} from \"../lib/media-urls.js\";\n\nexport interface RewriteInlineImageRef {\n originalSrc: string;\n sourceAssetId?: string;\n}\n\nexport interface UploadedAssetRef {\n targetId: string;\n publicUrl?: string;\n}\n\nexport interface RewriteInlineImagesOptions {\n resolveAsset: (src: string) => RewriteInlineImageRef | undefined;\n /**\n * Replace a resolved source id with a migration ref or CDN URL.\n * When omitted, defaults to OSS-14 `artinstack-migration://asset/…` refs.\n */\n replaceWith?: (ref: RewriteInlineImageRef, uploaded?: UploadedAssetRef) => string;\n /**\n * When true, skip URLs that cannot be matched to an uploaded vault target.\n * Default: false when using migration refs; true when a custom `replaceWith` is supplied.\n */\n requireUploaded?: boolean;\n}\n\nexport interface RewriteInlineImagesResult {\n html: string;\n referencedSources: string[];\n unresolved: string[];\n}\n\n/** Inline CSS `background` / `background-image: url(…)` (quoted or bare). */\nconst BACKGROUND_IMAGE_URL_PATTERN =\n /background(?:-image)?\\s*:[^;]*?url\\s*\\(\\s*(['\"]?)([^'\")]+)\\1\\s*\\)/gi;\n\nfunction resolveRewriteOptions(\n options: RewriteInlineImagesOptions,\n): Required<Pick<RewriteInlineImagesOptions, \"replaceWith\" | \"requireUploaded\">> {\n const replaceWith = options.replaceWith ?? createMigrationMediaRefReplaceWith();\n const requireUploaded = options.requireUploaded ?? Boolean(options.replaceWith);\n return { replaceWith, requireUploaded };\n}\n\nfunction tryRewriteUrl(\n src: string,\n options: RewriteInlineImagesOptions,\n uploadedBySourceId: Map<string, UploadedAssetRef>,\n referencedSources: Set<string>,\n unresolved: Set<string>,\n): string | undefined {\n const normalized = normalizeAssetUrl(src);\n if (!normalized) return undefined;\n\n if (isMigrationMediaRef(normalized)) {\n referencedSources.add(normalized);\n return normalized;\n }\n\n referencedSources.add(normalized);\n const ref = options.resolveAsset(normalized);\n if (!ref?.sourceAssetId) {\n unresolved.add(normalized);\n return undefined;\n }\n\n const { replaceWith, requireUploaded } = resolveRewriteOptions(options);\n const uploaded = uploadedBySourceId.get(ref.sourceAssetId);\n if (requireUploaded && !uploaded) {\n unresolved.add(normalized);\n return undefined;\n }\n\n return replaceWith(ref, uploaded);\n}\n\nfunction rewriteBackgroundUrlsInStyle(\n style: string,\n options: RewriteInlineImagesOptions,\n uploadedBySourceId: Map<string, UploadedAssetRef>,\n referencedSources: Set<string>,\n unresolved: Set<string>,\n): string {\n return style.replace(BACKGROUND_IMAGE_URL_PATTERN, (full, quote: string, rawUrl: string) => {\n const replaced = tryRewriteUrl(rawUrl.trim(), options, uploadedBySourceId, referencedSources, unresolved);\n if (!replaced) return full;\n\n const urlCall = quote\n ? `url(${quote}${replaced}${quote})`\n : `url(${replaced})`;\n return full.replace(/url\\s*\\(\\s*(['\"]?)([^'\")]+)\\1\\s*\\)/i, urlCall);\n });\n}\n\nfunction rewriteSrcset(\n srcset: string,\n options: RewriteInlineImagesOptions,\n uploadedBySourceId: Map<string, UploadedAssetRef>,\n referencedSources: Set<string>,\n unresolved: Set<string>,\n): string {\n return srcset\n .split(\",\")\n .map((entry) => {\n const trimmed = entry.trim();\n if (!trimmed) return entry;\n const [urlPart, descriptor] = trimmed.split(/\\s+/, 2);\n const replaced = tryRewriteUrl(urlPart ?? \"\", options, uploadedBySourceId, referencedSources, unresolved);\n if (!replaced) return entry;\n return descriptor ? `${replaced} ${descriptor}` : replaced;\n })\n .join(\", \");\n}\n\n/** Rewrite `<img src>` / `srcset`, `data-bg-image`, and inline CSS backgrounds using uploaded asset targets. */\nexport function rewriteInlineImages(\n html: string,\n options: RewriteInlineImagesOptions,\n uploadedBySourceId: Map<string, UploadedAssetRef>,\n): RewriteInlineImagesResult {\n if (!html.trim()) {\n return { html, referencedSources: [], unresolved: [] };\n }\n\n const $ = cheerio.load(html, { xml: false });\n const referencedSources = new Set<string>();\n const unresolved = new Set<string>();\n\n $(\"img\").each((_, element) => {\n const img = $(element);\n const src = img.attr(\"src\")?.trim();\n if (src && !src.startsWith(\"data:\")) {\n const replaced = tryRewriteUrl(src, options, uploadedBySourceId, referencedSources, unresolved);\n if (replaced) img.attr(\"src\", replaced);\n }\n\n const srcset = img.attr(\"srcset\")?.trim();\n if (srcset) {\n img.attr(\"srcset\", rewriteSrcset(srcset, options, uploadedBySourceId, referencedSources, unresolved));\n }\n });\n\n $(\"[data-bg-image]\").each((_, element) => {\n const node = $(element);\n const bgImage = node.attr(\"data-bg-image\")?.trim();\n if (!bgImage || bgImage.startsWith(\"data:\")) return;\n const replaced = tryRewriteUrl(bgImage, options, uploadedBySourceId, referencedSources, unresolved);\n if (replaced) node.attr(\"data-bg-image\", replaced);\n });\n\n $(\"[style]\").each((_, element) => {\n const node = $(element);\n const style = node.attr(\"style\");\n if (!style?.includes(\"background\")) return;\n const rewritten = rewriteBackgroundUrlsInStyle(\n style,\n options,\n uploadedBySourceId,\n referencedSources,\n unresolved,\n );\n if (rewritten !== style) node.attr(\"style\", rewritten);\n });\n\n return {\n html: $.root().html() ?? html,\n referencedSources: [...referencedSources],\n unresolved: [...unresolved],\n };\n}\n\nexport interface StampMigrationMediaRefsOptions {\n /** Pre-built url/pathname → sourceId map (from attachments + inline assets). */\n urlToSourceId: Map<string, string>;\n /** Canonicalize lookup keys during stamp (OSS-15). */\n originUrlRewrite?: OriginUrlRewriteConfig;\n replaceWith?: RewriteInlineImagesOptions[\"replaceWith\"];\n requireUploaded?: boolean;\n}\n\n/**\n * OSS-14 — replace resolved `wp-content/uploads` URLs with `artinstack-migration://asset/…`\n * refs. Does not invent refs for unknown URLs (left unchanged + listed in `unresolved`).\n */\nexport function stampMigrationMediaRefs(\n html: string,\n options: StampMigrationMediaRefsOptions,\n): RewriteInlineImagesResult {\n return rewriteInlineImages(\n html,\n {\n resolveAsset: (src) => {\n const sourceAssetId = resolveMigrationMediaSourceId(\n src,\n options.urlToSourceId,\n options.originUrlRewrite,\n );\n if (!sourceAssetId) return undefined;\n return { originalSrc: src, sourceAssetId };\n },\n replaceWith: options.replaceWith,\n requireUploaded: options.requireUploaded ?? false,\n },\n new Map(),\n );\n}\n\n/** Build a url index from attachment rows and/or normalized assets. */\nexport { buildMigrationMediaUrlIndex };\n","export type BuilderHtmlTag = \"img\" | \"video\" | \"iframe\";\nexport type TextHtmlTag = \"p\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\";\n\n/** Bucket 1 — shortcodes with asset URL params → standard HTML. */\nexport interface BuilderUrlRule {\n shortcodePrefix: string;\n urlParams: string[];\n tag: BuilderHtmlTag;\n}\n\n/** Bucket 1 — shortcodes with text params → semantic HTML. */\nexport interface BuilderTextRule {\n shortcodePrefix: string;\n fields: { param: string; tag: TextHtmlTag }[];\n}\n\n/** Bucket 1 — shortcodes with inner HTML (+ optional image param). */\nexport interface BuilderWrapperRule {\n shortcodePrefix: string;\n urlParams?: string[];\n}\n\n/** Bucket 1 — image-based icon modules (`icon_image` param) → linked `<img>`. */\nexport interface BuilderIconImageRule {\n shortcodePrefix: string;\n imageParam: string;\n hrefParam?: string;\n}\n\n/** Bucket 1 — dynamic embeds replaced with a static migration placeholder. */\nexport interface BuilderPlaceholderRule {\n shortcodePrefix: string;\n html: string;\n}\n\n/** Profile A — prefixed namespace tokens (Tatsu, Divi, WPBakery, …). */\nexport interface PrefixedLayoutMap {\n kind: \"prefixed\";\n sectionRegex: RegExp;\n sectionCloseRegex: RegExp;\n rowRegex: RegExp;\n rowCloseRegex: RegExp;\n columnRegex: RegExp;\n columnCloseRegex: RegExp;\n bgParamName?: string;\n colsParamName?: string;\n}\n\n/** Profile B — legacy Blox fractional column tokens (`one_third`, `one_half`, …). */\nexport interface FractionalLayoutMap {\n kind: \"fractional\";\n sectionRegex: RegExp;\n sectionCloseRegex: RegExp;\n rowRegex: RegExp;\n rowCloseRegex: RegExp;\n columnTokens: string[];\n columnOpenRegexes: RegExp[];\n columnCloseRegexes: RegExp[];\n columnWidths: Record<string, string>;\n bgParamName?: string;\n}\n\n/** Profile C — multiple tokens per layout role (Blox prefixed, WPBakery inner columns, …). */\nexport interface ExtendedPrefixedLayoutLevel {\n role: \"section\" | \"row\" | \"column\";\n tokens: string[];\n bgParamName?: string;\n colsParamName?: string;\n widthParamName?: string;\n}\n\nexport interface ExtendedPrefixedLayoutMap {\n kind: \"extended-prefixed\";\n levels: ExtendedPrefixedLayoutLevel[];\n}\n\nexport type StructuralLayoutMap =\n | PrefixedLayoutMap\n | FractionalLayoutMap\n | ExtendedPrefixedLayoutMap;\n\nfunction layoutEscapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\nfunction shortcodeOpenRegex(token: string): RegExp {\n return new RegExp(`\\\\[${layoutEscapeRegExp(token)}\\\\b([^\\\\]]*)\\\\]`, \"gi\");\n}\n\nfunction shortcodeCloseRegex(token: string): RegExp {\n return new RegExp(`\\\\[\\\\/${layoutEscapeRegExp(token)}\\\\b[^\\\\]]*\\\\]`, \"gi\");\n}\n\nconst FRACTIONAL_COLUMN_WIDTHS: Record<string, string> = {\n one_col: \"100%\",\n one_half: \"50%\",\n one_third: \"33.33%\",\n two_third: \"66.67%\",\n two_thirds: \"66.67%\",\n one_fourth: \"25%\",\n three_fourth: \"75%\",\n three_fourths: \"75%\",\n};\n\nexport function parseFractionalColumnWidth(token: string): string | undefined {\n return FRACTIONAL_COLUMN_WIDTHS[token];\n}\n\n/** Profile A — section/row/column share a static namespace prefix. */\nexport function prefixedLayoutMap(config: {\n section: string;\n row: string;\n column: string;\n bgParamName?: string;\n colsParamName?: string;\n}): PrefixedLayoutMap {\n return {\n kind: \"prefixed\",\n sectionRegex: shortcodeOpenRegex(config.section),\n sectionCloseRegex: shortcodeCloseRegex(config.section),\n rowRegex: shortcodeOpenRegex(config.row),\n rowCloseRegex: shortcodeCloseRegex(config.row),\n columnRegex: shortcodeOpenRegex(config.column),\n columnCloseRegex: shortcodeCloseRegex(config.column),\n bgParamName: config.bgParamName,\n colsParamName: config.colsParamName,\n };\n}\n\n/** Profile B — legacy Blox/Oshine mathematical column shortcodes. */\n/** Profile C — map several shortcode names per section/row/column role (longest token first). */\nexport function extendedPrefixedLayoutMap(\n levels: ExtendedPrefixedLayoutLevel[],\n): ExtendedPrefixedLayoutMap {\n return { kind: \"extended-prefixed\", levels };\n}\n\nexport function fractionalLayoutMap(config: {\n section: string;\n row: string;\n columns: string[];\n bgParamName?: string;\n}): FractionalLayoutMap {\n const columnWidths: Record<string, string> = {};\n for (const token of config.columns) {\n const width = parseFractionalColumnWidth(token);\n if (width) columnWidths[token] = width;\n }\n\n return {\n kind: \"fractional\",\n sectionRegex: shortcodeOpenRegex(config.section),\n sectionCloseRegex: shortcodeCloseRegex(config.section),\n rowRegex: shortcodeOpenRegex(config.row),\n rowCloseRegex: shortcodeCloseRegex(config.row),\n columnTokens: config.columns,\n columnOpenRegexes: config.columns.map(shortcodeOpenRegex),\n columnCloseRegexes: config.columns.map(shortcodeCloseRegex),\n columnWidths,\n bgParamName: config.bgParamName,\n };\n}\n\n/** Per builder-family registry entry — declarative map executed by the flatten engine. */\nexport interface BuilderThemeConfig {\n id: string;\n detect: RegExp;\n layoutMap?: StructuralLayoutMap;\n /** Additional layout maps applied after `layoutMap` (e.g. Blox prefixed + legacy fractional). */\n layoutMaps?: StructuralLayoutMap[];\n urlRules?: BuilderUrlRule[];\n textRules?: BuilderTextRule[];\n wrapperRules?: BuilderWrapperRule[];\n iconImageRules?: BuilderIconImageRule[];\n placeholderRules?: BuilderPlaceholderRule[];\n scaffoldingPrefixes?: string[];\n legacyScaffoldingTokens?: string[];\n}\n\n/** @deprecated Alias — families not themes. */\nexport type BuilderFamilyConfig = BuilderThemeConfig;\n\n// ---------------------------------------------------------------------------\n// Widget registry (OSS-12 / OSS-16) — cross-builder; not BuilderThemeConfig\n// ---------------------------------------------------------------------------\n\n/** Keeps empty widget stubs from collapsing during cheerio text sweeps. */\nexport const WP_WIDGET_PLACEHOLDER = \"\\u200B\";\n\nexport interface WordPressContactFormWidgetRule {\n /** Shortcode tag name (e.g. `contact-form-7`). */\n tag: string;\n /** Value for `data-wp-form-source`. */\n source: string;\n /** Attribute holding the form id (e.g. `id`). */\n idParam: string;\n}\n\n/** Declarative widget tables consumed by `flattenWordPressWidgets()` in flatten.ts. */\nexport interface WordPressWidgetRegistry {\n mapShortcodePrefixes: readonly string[];\n contactFormRules: readonly WordPressContactFormWidgetRule[];\n videoShortcodePrefixes: readonly string[];\n /** Core / plugin portfolio dynamic shortcode tag. */\n portfolioShortcode: string;\n /** Builder blog roll modules (Tatsu/Oshine `[blog]`, etc.). */\n blogShortcodeTags: readonly string[];\n /** Testimonials carousel/list wrapper shortcodes (Oshine `[testimonials]`, etc.). */\n testimonialsWrapperTags: readonly string[];\n /** Inner testimonial item shortcode tag. */\n testimonialItemTag: string;\n /** In-body RevSlider / MasterSlider shortcodes → slider widget stub (alias only). */\n sliderShortcodeTags: readonly string[];\n /** WordPress core gallery shortcode tag (`ids=` split handled in engine). */\n galleryShortcode: string;\n /** Builder/plugin gallery shortcodes with explicit `ids=` attachment lists (OSS-12). */\n idGalleryShortcodes: readonly string[];\n}\n\nexport const WORDPRESS_WIDGET_REGISTRY: WordPressWidgetRegistry = {\n mapShortcodePrefixes: [\n \"blox_gmap\",\n \"tatsu_gmap\",\n \"tatsu_map\",\n \"et_pb_map\",\n \"vc_gmaps\",\n \"vc_map\",\n ],\n contactFormRules: [\n { tag: \"contact-form-7\", source: \"contact-form-7\", idParam: \"id\" },\n { tag: \"contact_form\", source: \"contact-form-7\", idParam: \"id\" },\n { tag: \"gravityform\", source: \"gravityforms\", idParam: \"id\" },\n { tag: \"ninja_form\", source: \"ninja-forms\", idParam: \"id\" },\n { tag: \"wpforms\", source: \"wpforms\", idParam: \"id\" },\n ],\n videoShortcodePrefixes: [\n \"youtube\",\n \"vimeo\",\n \"embed\",\n \"tatsu_video\",\n \"et_pb_video\",\n \"vc_video\",\n ],\n portfolioShortcode: \"portfolio\",\n blogShortcodeTags: [\"blog\", \"recent_posts\"],\n testimonialsWrapperTags: [\"testimonials\"],\n testimonialItemTag: \"testimonial\",\n sliderShortcodeTags: [\"rev_slider\", \"masterslider\"],\n galleryShortcode: \"gallery\",\n idGalleryShortcodes: [\"oshine_gallery\", \"vc_gallery\", \"nggallery\"],\n};\n\n/** Shortcodes that cannot become static HTML — reported in conflicts, never stripped. */\nexport const UNRESOLVABLE_SHORTCODE_PREFIXES = [\n \"woocommerce_cart\",\n \"woocommerce_checkout\",\n \"woocommerce_my_account\",\n] as const;\n\nexport const WORDPRESS_BUILDER_REGISTRY: BuilderThemeConfig[] = [\n {\n id: \"tatsu\",\n detect: /\\[(?:\\/)?tatsu_/i,\n layoutMap: prefixedLayoutMap({\n section: \"tatsu_section\",\n row: \"tatsu_row\",\n column: \"tatsu_column\",\n bgParamName: \"bg_image\",\n colsParamName: \"layout\",\n }),\n wrapperRules: [\n { shortcodePrefix: \"tatsu_text\" },\n { shortcodePrefix: \"tatsu_inline_text\" },\n { shortcodePrefix: \"tatsu_text_with_shortcodes\" },\n { shortcodePrefix: \"tatsu_icon_group\" },\n ],\n urlRules: [\n { shortcodePrefix: \"tatsu_image\", urlParams: [\"image\", \"url\", \"src\"], tag: \"img\" },\n { shortcodePrefix: \"tatsu_single_image\", urlParams: [\"image\", \"url\", \"src\"], tag: \"img\" },\n ],\n iconImageRules: [\n { shortcodePrefix: \"tatsu_icon\", imageParam: \"icon_image\", hrefParam: \"href\" },\n ],\n scaffoldingPrefixes: [\"tatsu_\"],\n },\n {\n id: \"divi\",\n detect: /\\[(?:\\/)?et_pb_/i,\n layoutMap: prefixedLayoutMap({\n section: \"et_pb_section\",\n row: \"et_pb_row\",\n column: \"et_pb_column\",\n bgParamName: \"background_image\",\n }),\n urlRules: [{ shortcodePrefix: \"et_pb_image\", urlParams: [\"src\", \"url\"], tag: \"img\" }],\n scaffoldingPrefixes: [\"et_pb_\"],\n },\n {\n id: \"wpbakery\",\n detect: /\\[(?:\\/)?vc_/i,\n layoutMap: extendedPrefixedLayoutMap([\n { role: \"section\", tokens: [\"vc_section\"], bgParamName: \"bg_image\" },\n { role: \"row\", tokens: [\"vc_row\"], colsParamName: \"layout\" },\n { role: \"column\", tokens: [\"vc_column_inner\", \"vc_column\"], widthParamName: \"width\" },\n ]),\n urlRules: [\n { shortcodePrefix: \"vc_single_image\", urlParams: [\"image\", \"src\", \"url\"], tag: \"img\" },\n ],\n scaffoldingPrefixes: [\"vc_\"],\n },\n {\n id: \"fusion\",\n detect: /\\[(?:\\/)?fusion_/i,\n layoutMap: prefixedLayoutMap({\n section: \"fusion_builder_container\",\n row: \"fusion_builder_row\",\n column: \"fusion_builder_column\",\n bgParamName: \"background_image\",\n }),\n scaffoldingPrefixes: [\"fusion_\"],\n },\n {\n id: \"beaver\",\n detect: /\\[(?:\\/)?fl_(?:row|col|builder)/i,\n layoutMap: extendedPrefixedLayoutMap([\n { role: \"row\", tokens: [\"fl_row\"] },\n { role: \"column\", tokens: [\"fl_col\"] },\n ]),\n scaffoldingPrefixes: [\"fl_\"],\n },\n {\n id: \"elementor\",\n detect: /\\[(?:\\/)?elementor[-_]/i,\n urlRules: [\n { shortcodePrefix: \"elementor-widget\", urlParams: [\"url\", \"src\", \"image\"], tag: \"img\" },\n ],\n scaffoldingPrefixes: [\"elementor_\"],\n },\n {\n id: \"oshine\",\n detect:\n /\\[(?:special_sub_title|special_heading5|blox_\\w+|grid_content|grids|testimonial\\b|portfolio\\b|recent_posts\\b|animate_icon\\w*|section\\b|row\\b|one_col|one_third|one_half|one_fourth|two_third|three_fourth|text\\b)/i,\n layoutMap: fractionalLayoutMap({\n section: \"section\",\n row: \"row\",\n columns: [\n \"one_col\",\n \"one_third\",\n \"two_third\",\n \"two_thirds\",\n \"one_half\",\n \"one_fourth\",\n \"three_fourth\",\n \"three_fourths\",\n ],\n bgParamName: \"bg_image\",\n }),\n layoutMaps: [\n extendedPrefixedLayoutMap([\n { role: \"section\", tokens: [\"blox_row\"], bgParamName: \"bg_image\" },\n { role: \"row\", tokens: [\"blox_row_inner\"], colsParamName: \"columns\" },\n {\n role: \"column\",\n tokens: [\"blox_column_inner\", \"blox_column\"],\n widthParamName: \"width\",\n },\n ]),\n ],\n textRules: [\n {\n shortcodePrefix: \"special_sub_title\",\n fields: [{ param: \"title_content\", tag: \"p\" }],\n },\n {\n shortcodePrefix: \"special_heading5\",\n fields: [\n { param: \"title_content\", tag: \"h2\" },\n { param: \"caption_content\", tag: \"h4\" },\n ],\n },\n ],\n wrapperRules: [\n { shortcodePrefix: \"grid_content\" },\n { shortcodePrefix: \"blox_text\" },\n ],\n urlRules: [\n { shortcodePrefix: \"blox_image\", urlParams: [\"image\", \"img\", \"src\", \"url\"], tag: \"img\" },\n ],\n scaffoldingPrefixes: [\"blox_\", \"animate_icon\"],\n legacyScaffoldingTokens: [\"text\", \"icon\", \"linebreak\", \"grids\", \"testimonials\"],\n },\n];\n\n/** @deprecated Use urlRules on BuilderThemeConfig — kept for type migration clarity. */\nexport type BuilderContentRule = BuilderUrlRule;\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/normalizer/types.ts","../src/normalizer/idempotency.ts","../src/normalizer/bundle.ts","../src/normalizer/portfolio-media.ts"],"sourcesContent":["export type MigrationPlatform = \"wordpress\" | \"smugmug\" | \"squarespace\" | \"wix\";\n\nexport type EntityType = \"post\" | \"page\" | \"asset\" | \"portfolio\" | \"category\" | \"tag\";\n\nexport type PublishStatus = \"draft\" | \"published\" | \"archived\";\n\nexport interface SourceMetadata {\n platform: MigrationPlatform;\n id: string;\n url?: string;\n path?: string;\n exportedAt?: string;\n /** WordPress `post_type` when the DTO shape differs (e.g. portfolio CPT emitted as `page`). */\n postType?: string;\n}\n\n/** Canonical post DTO — raw HTML; sanitize at host sink. */\nexport interface NormalizedPost {\n type: \"post\";\n source: SourceMetadata;\n sourceId: string;\n title: string;\n slug: string;\n excerpt?: string;\n contentHtml: string;\n publishedAt?: string;\n status: PublishStatus;\n categorySlugs?: string[];\n tagSlugs?: string[];\n /** WordPress attachment id before two-pass resolution. */\n sourceFeaturedMediaId?: string;\n featuredAssetSourceId?: string;\n seoTitle?: string;\n seoDescription?: string;\n}\n\n/** RevSlider / MasterSlider reference from theme hero meta (OSS-27) — alias only, no slide payloads in WXR. */\nexport interface PageHeroSliderHint {\n plugin: \"revslider\" | \"masterslider\";\n alias: string;\n slidertitle?: string;\n source?: \"meta-shortcode\" | \"meta-slider-field\" | \"tatsu-json\";\n}\n\n/** Non-body layout signals for host promotion (theme chrome, hero slots, …). */\nexport interface PageLayoutHints {\n heroSlider?: PageHeroSliderHint;\n}\n\n/** Canonical page DTO — raw HTML snapshot. */\nexport interface NormalizedPage {\n type: \"page\";\n source: SourceMetadata;\n sourceId: string;\n title: string;\n slug: string;\n contentHtml: string;\n contentCss?: string;\n isHomePage?: boolean;\n /** Site portfolio listing shell (distinct from portfolio CPT singles). */\n isPortfolioPage?: boolean;\n layoutHints?: PageLayoutHints;\n status: PublishStatus;\n seoTitle?: string;\n seoDescription?: string;\n}\n\n/** EXIF fields preserved from SmugMug / camera metadata when present. */\nexport interface NormalizedAssetExif {\n iso?: number;\n aperture?: number;\n shutter?: string;\n focalLength?: number;\n}\n\n/** Remote asset to stream into the host sink. */\nexport interface NormalizedAsset {\n type: \"asset\";\n source: SourceMetadata;\n sourceId: string;\n sourceUrl: string;\n filename: string;\n mimeType?: string;\n caption?: string;\n altText?: string;\n keywords?: string[];\n exif?: NormalizedAssetExif;\n portfolioSourceId?: string;\n sort?: number;\n}\n\n/** M2M index: portfolio ↔ asset membership and sort order. */\nexport interface PortfolioMediaLink {\n portfolioSourceId: string;\n assetSourceId: string;\n sort: number;\n}\n\nexport interface NormalizedPortfolio {\n type: \"portfolio\";\n source: SourceMetadata;\n sourceId: string;\n title: string;\n slug: string;\n description?: string;\n parentSourceId?: string;\n}\n\nexport interface NormalizedCategory {\n type: \"category\";\n source: SourceMetadata;\n sourceId: string;\n name: string;\n slug: string;\n}\n\nexport interface NormalizedTag {\n type: \"tag\";\n source: SourceMetadata;\n sourceId: string;\n name: string;\n slug: string;\n}\n\nexport type NormalizedEntity =\n | NormalizedPost\n | NormalizedPage\n | NormalizedAsset\n | NormalizedPortfolio\n | NormalizedCategory\n | NormalizedTag;\n\nexport interface ValidationIssue {\n code: string;\n message: string;\n path?: string;\n}\n\nexport interface ValidationResult {\n ok: boolean;\n issues: ValidationIssue[];\n summary?: {\n posts?: number;\n pages?: number;\n assets?: number;\n portfolios?: number;\n /** WordPress `post_type=portfolio` (and configured CPT slugs) in raw WXR. */\n portfolioCpt?: number;\n categories?: number;\n tags?: number;\n /** WXR rows the parser would emit (OSS-19). */\n importableItemCount?: number;\n unsupportedOnly?: boolean;\n skippedPostTypes?: Record<string, number>;\n };\n}\n\nexport interface WxrImportSummary {\n importableItemCount: number;\n unsupportedOnly: boolean;\n skippedPostTypes: Record<string, number>;\n skippedWooCommerceStubPages?: number;\n}\n\nexport interface AdapterContext {\n input: unknown;\n cursor?: MigrationCursor;\n}\n\nexport interface MigrationAdapter {\n platform: MigrationPlatform;\n validateInput(input: unknown): ValidationResult | Promise<ValidationResult>;\n enumerateEntities(ctx: AdapterContext): AsyncIterable<NormalizedEntity>;\n /** Platform-specific import accounting (e.g. WordPress skipped `post_type`s). */\n getImportSummary?(input: unknown): Promise<WxrImportSummary | undefined>;\n}\n\nexport interface MigrationCursor {\n lastEntityKey?: EntityKey;\n state?: Record<string, unknown>;\n}\n\nexport interface EntityKey {\n platform: MigrationPlatform;\n entityType: EntityType;\n sourceId: string;\n}\n\nexport function entityKey(entity: NormalizedEntity, platform: MigrationPlatform): EntityKey {\n return {\n platform,\n entityType: entity.type,\n sourceId: entity.sourceId,\n };\n}\n","import type { EntityKey, MigrationCursor } from \"./types.js\";\n\n/** Portable entity state for resume / idempotency (not Directus field names). */\nexport type EntityState = \"pending\" | \"done\" | \"failed\" | \"skipped\";\n\nexport interface TrackedEntity extends EntityKey {\n state: EntityState;\n targetId?: string;\n errorMessage?: string;\n}\n\nexport interface MigrationCheckpoint {\n jobId: string;\n cursor: MigrationCursor;\n entities: TrackedEntity[];\n updatedAt: string;\n}\n\nexport function isTerminalState(state: EntityState): boolean {\n return state === \"done\" || state === \"skipped\";\n}\n\nexport function shouldProcessEntity(\n key: EntityKey,\n entities: TrackedEntity[],\n): boolean {\n const existing = entities.find(\n (e) =>\n e.platform === key.platform &&\n e.entityType === key.entityType &&\n e.sourceId === key.sourceId,\n );\n return !existing || !isTerminalState(existing.state);\n}\n","import type {\n NormalizedAsset,\n NormalizedCategory,\n NormalizedEntity,\n NormalizedPage,\n NormalizedPortfolio,\n NormalizedPost,\n NormalizedTag,\n} from \"./types.js\";\n\nexport interface EntityBundle {\n posts: NormalizedPost[];\n pages: NormalizedPage[];\n media: NormalizedAsset[];\n portfolios: NormalizedPortfolio[];\n categories: NormalizedCategory[];\n tags: NormalizedTag[];\n}\n\nexport function emptyBundle(): EntityBundle {\n return {\n posts: [],\n pages: [],\n media: [],\n portfolios: [],\n categories: [],\n tags: [],\n };\n}\n\nexport async function collectEntities(\n entities: AsyncIterable<NormalizedEntity>,\n): Promise<EntityBundle> {\n const bundle = emptyBundle();\n\n for await (const entity of entities) {\n switch (entity.type) {\n case \"post\":\n bundle.posts.push(entity);\n break;\n case \"page\":\n bundle.pages.push(entity);\n break;\n case \"asset\":\n bundle.media.push(entity);\n break;\n case \"portfolio\":\n bundle.portfolios.push(entity);\n break;\n case \"category\":\n bundle.categories.push(entity);\n break;\n case \"tag\":\n bundle.tags.push(entity);\n break;\n default: {\n const _exhaustive: never = entity;\n throw new Error(`Unknown entity type: ${(_exhaustive as NormalizedEntity).type}`);\n }\n }\n }\n\n return bundle;\n}\n\nexport interface BundleCounts {\n posts: number;\n pages: number;\n assets: number;\n portfolios: number;\n categories: number;\n tags: number;\n}\n\nexport function bundleCounts(bundle: EntityBundle): BundleCounts {\n return {\n posts: bundle.posts.length,\n pages: bundle.pages.length,\n assets: bundle.media.length,\n portfolios: bundle.portfolios.length,\n categories: bundle.categories.length,\n tags: bundle.tags.length,\n };\n}\n","import type { EntityBundle } from \"./bundle.js\";\nimport type { PortfolioMediaLink } from \"./types.js\";\n\n/** Derive portfolio↔asset M2M rows from assets carrying `portfolioSourceId`. */\nexport function buildPortfolioMediaLinks(bundle: EntityBundle): PortfolioMediaLink[] {\n const links: PortfolioMediaLink[] = [];\n\n for (const asset of bundle.media) {\n if (!asset.portfolioSourceId) continue;\n links.push({\n portfolioSourceId: asset.portfolioSourceId,\n assetSourceId: asset.sourceId,\n sort: asset.sort ?? 0,\n });\n }\n\n links.sort((a, b) => {\n if (a.portfolioSourceId !== b.portfolioSourceId) {\n return a.portfolioSourceId.localeCompare(b.portfolioSourceId);\n }\n return a.sort - b.sort || a.assetSourceId.localeCompare(b.assetSourceId);\n });\n\n return links;\n}\n"],"mappings":";AA4LO,SAAS,UAAU,QAA0B,UAAwC;AAC1F,SAAO;AAAA,IACL;AAAA,IACA,YAAY,OAAO;AAAA,IACnB,UAAU,OAAO;AAAA,EACnB;AACF;;;AChLO,SAAS,gBAAgB,OAA6B;AAC3D,SAAO,UAAU,UAAU,UAAU;AACvC;AAEO,SAAS,oBACd,KACA,UACS;AACT,QAAM,WAAW,SAAS;AAAA,IACxB,CAAC,MACC,EAAE,aAAa,IAAI,YACnB,EAAE,eAAe,IAAI,cACrB,EAAE,aAAa,IAAI;AAAA,EACvB;AACA,SAAO,CAAC,YAAY,CAAC,gBAAgB,SAAS,KAAK;AACrD;;;ACdO,SAAS,cAA4B;AAC1C,SAAO;AAAA,IACL,OAAO,CAAC;AAAA,IACR,OAAO,CAAC;AAAA,IACR,OAAO,CAAC;AAAA,IACR,YAAY,CAAC;AAAA,IACb,YAAY,CAAC;AAAA,IACb,MAAM,CAAC;AAAA,EACT;AACF;AAEA,eAAsB,gBACpB,UACuB;AACvB,QAAM,SAAS,YAAY;AAE3B,mBAAiB,UAAU,UAAU;AACnC,YAAQ,OAAO,MAAM;AAAA,MACnB,KAAK;AACH,eAAO,MAAM,KAAK,MAAM;AACxB;AAAA,MACF,KAAK;AACH,eAAO,MAAM,KAAK,MAAM;AACxB;AAAA,MACF,KAAK;AACH,eAAO,MAAM,KAAK,MAAM;AACxB;AAAA,MACF,KAAK;AACH,eAAO,WAAW,KAAK,MAAM;AAC7B;AAAA,MACF,KAAK;AACH,eAAO,WAAW,KAAK,MAAM;AAC7B;AAAA,MACF,KAAK;AACH,eAAO,KAAK,KAAK,MAAM;AACvB;AAAA,MACF,SAAS;AACP,cAAM,cAAqB;AAC3B,cAAM,IAAI,MAAM,wBAAyB,YAAiC,IAAI,EAAE;AAAA,MAClF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAWO,SAAS,aAAa,QAAoC;AAC/D,SAAO;AAAA,IACL,OAAO,OAAO,MAAM;AAAA,IACpB,OAAO,OAAO,MAAM;AAAA,IACpB,QAAQ,OAAO,MAAM;AAAA,IACrB,YAAY,OAAO,WAAW;AAAA,IAC9B,YAAY,OAAO,WAAW;AAAA,IAC9B,MAAM,OAAO,KAAK;AAAA,EACpB;AACF;;;AC/EO,SAAS,yBAAyB,QAA4C;AACnF,QAAM,QAA8B,CAAC;AAErC,aAAW,SAAS,OAAO,OAAO;AAChC,QAAI,CAAC,MAAM,kBAAmB;AAC9B,UAAM,KAAK;AAAA,MACT,mBAAmB,MAAM;AAAA,MACzB,eAAe,MAAM;AAAA,MACrB,MAAM,MAAM,QAAQ;AAAA,IACtB,CAAC;AAAA,EACH;AAEA,QAAM,KAAK,CAAC,GAAG,MAAM;AACnB,QAAI,EAAE,sBAAsB,EAAE,mBAAmB;AAC/C,aAAO,EAAE,kBAAkB,cAAc,EAAE,iBAAiB;AAAA,IAC9D;AACA,WAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,cAAc,cAAc,EAAE,aAAa;AAAA,EACzE,CAAC;AAED,SAAO;AACT;","names":[]}
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import {
|
|
2
|
+
normalizeVideoEmbedUrl
|
|
3
|
+
} from "./chunk-4XZK55RW.js";
|
|
1
4
|
import {
|
|
2
5
|
isMigrationMediaRef,
|
|
3
6
|
parseMigrationMediaRef
|
|
@@ -131,6 +134,42 @@ function isPreservedEmbedIframe(tagName, attributes) {
|
|
|
131
134
|
const src = attributes?.src ?? "";
|
|
132
135
|
return EMBED_IFRAME_SRC.test(src);
|
|
133
136
|
}
|
|
137
|
+
function isBlockLinkedImageAnchor($, $el) {
|
|
138
|
+
if (tagNameOf($el) !== "a") return false;
|
|
139
|
+
const href = $el.attr("href")?.trim();
|
|
140
|
+
if (!href || href === "#") return false;
|
|
141
|
+
let tagChildCount = 0;
|
|
142
|
+
let onlyImg = false;
|
|
143
|
+
$el.contents().each((_, node) => {
|
|
144
|
+
if (node.type === "text") {
|
|
145
|
+
if (String("data" in node ? node.data : "").trim()) {
|
|
146
|
+
tagChildCount = -1;
|
|
147
|
+
}
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
if (node.type !== "tag") return;
|
|
151
|
+
tagChildCount += 1;
|
|
152
|
+
onlyImg = tagNameOf($(node)) === "img";
|
|
153
|
+
});
|
|
154
|
+
return tagChildCount === 1 && onlyImg;
|
|
155
|
+
}
|
|
156
|
+
function walkLinkedImageAnchor($, $el, options) {
|
|
157
|
+
const href = $el.attr("href").trim();
|
|
158
|
+
const $img = $el.children().first();
|
|
159
|
+
const meta = pickElementMeta($img);
|
|
160
|
+
const attributes = { ...meta.attributes ?? {}, href };
|
|
161
|
+
return applyElementMeta(
|
|
162
|
+
{
|
|
163
|
+
type: resolveComponentType("img", meta.classes, options),
|
|
164
|
+
tagName: "img",
|
|
165
|
+
void: true
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
attributes,
|
|
169
|
+
classes: meta.classes
|
|
170
|
+
}
|
|
171
|
+
);
|
|
172
|
+
}
|
|
134
173
|
function layoutAttributesForComponent(attributes) {
|
|
135
174
|
if (!attributes) return void 0;
|
|
136
175
|
const { [LAYOUT_DATA_ATTR]: _layout, ...rest } = attributes;
|
|
@@ -234,13 +273,23 @@ function walkNode($, $el, options) {
|
|
|
234
273
|
return component2;
|
|
235
274
|
}
|
|
236
275
|
if (isWpWidgetMarker(meta.attributes)) {
|
|
237
|
-
|
|
276
|
+
const component2 = applyElementMeta(
|
|
238
277
|
{
|
|
239
278
|
type: resolveWidgetComponentType(options),
|
|
240
279
|
tagName
|
|
241
280
|
},
|
|
242
281
|
meta
|
|
243
282
|
);
|
|
283
|
+
if (meta.attributes?.[WP_WIDGET_ATTR]?.trim() === "testimonials") {
|
|
284
|
+
const children = walkChildren($, $el, options).filter((child) => {
|
|
285
|
+
if (child.type !== "textnode") return true;
|
|
286
|
+
return Boolean(child.content?.trim());
|
|
287
|
+
});
|
|
288
|
+
if (children.length > 0) {
|
|
289
|
+
component2.components = children;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
return component2;
|
|
244
293
|
}
|
|
245
294
|
if (isPreservedEmbedIframe(tagName, meta.attributes)) {
|
|
246
295
|
return applyElementMeta(
|
|
@@ -252,6 +301,9 @@ function walkNode($, $el, options) {
|
|
|
252
301
|
meta
|
|
253
302
|
);
|
|
254
303
|
}
|
|
304
|
+
if (tagName === "a" && isBlockLinkedImageAnchor($, $el)) {
|
|
305
|
+
return walkLinkedImageAnchor($, $el, options);
|
|
306
|
+
}
|
|
255
307
|
if (VOID_TAGS.has(tagName)) {
|
|
256
308
|
return applyElementMeta(
|
|
257
309
|
{
|
|
@@ -359,6 +411,45 @@ function serializeContentHtml($) {
|
|
|
359
411
|
// src/transformers/html-to-tiptap/index.ts
|
|
360
412
|
import * as cheerio2 from "cheerio";
|
|
361
413
|
|
|
414
|
+
// src/transformers/html-to-tiptap/video-embed.ts
|
|
415
|
+
var VIDEO_WIDGET = "video";
|
|
416
|
+
var VIDEO_IFRAME_SRC = /youtube\.com\/embed|youtube-nocookie\.com\/embed|youtu\.be|player\.vimeo\.com\/video/i;
|
|
417
|
+
function isVideoWidgetElement($el) {
|
|
418
|
+
return $el.attr("data-wp-widget")?.toLowerCase() === VIDEO_WIDGET;
|
|
419
|
+
}
|
|
420
|
+
function buildVideoEmbedNode(input) {
|
|
421
|
+
return {
|
|
422
|
+
type: "embed",
|
|
423
|
+
attrs: {
|
|
424
|
+
src: input.embedUrl,
|
|
425
|
+
provider: input.provider,
|
|
426
|
+
dataWpWidget: VIDEO_WIDGET,
|
|
427
|
+
dataEmbedUrl: input.embedUrl,
|
|
428
|
+
dataVideoProvider: input.provider
|
|
429
|
+
}
|
|
430
|
+
};
|
|
431
|
+
}
|
|
432
|
+
function videoEmbedNodeFromWidget($el) {
|
|
433
|
+
const embedUrl = $el.attr("data-embed-url")?.trim();
|
|
434
|
+
if (!embedUrl) return null;
|
|
435
|
+
const provider = $el.attr("data-video-provider")?.trim() || "external";
|
|
436
|
+
return buildVideoEmbedNode({ embedUrl, provider });
|
|
437
|
+
}
|
|
438
|
+
function videoEmbedNodeFromIframe($el) {
|
|
439
|
+
const src = $el.attr("src")?.trim();
|
|
440
|
+
if (!src || !VIDEO_IFRAME_SRC.test(src)) return null;
|
|
441
|
+
const normalized = normalizeVideoEmbedUrl(src);
|
|
442
|
+
return buildVideoEmbedNode({
|
|
443
|
+
embedUrl: normalized?.embedUrl ?? src,
|
|
444
|
+
provider: normalized?.provider ?? "external"
|
|
445
|
+
});
|
|
446
|
+
}
|
|
447
|
+
function isPreservedVideoIframe($el, tagName) {
|
|
448
|
+
if (tagName !== "iframe") return false;
|
|
449
|
+
const src = $el.attr("src")?.trim() ?? "";
|
|
450
|
+
return VIDEO_IFRAME_SRC.test(src);
|
|
451
|
+
}
|
|
452
|
+
|
|
362
453
|
// src/transformers/html-to-tiptap/walk.ts
|
|
363
454
|
var SKIP_TAGS2 = /* @__PURE__ */ new Set(["script", "style", "noscript", "template"]);
|
|
364
455
|
var HEADING_TAGS = /* @__PURE__ */ new Set(["h1", "h2", "h3", "h4", "h5", "h6"]);
|
|
@@ -434,7 +525,7 @@ function hasBlockChild($, $el) {
|
|
|
434
525
|
if ($child.get(0)?.type === "text") return;
|
|
435
526
|
const childTag = tagNameOf2($child);
|
|
436
527
|
if (!childTag) return;
|
|
437
|
-
if (HEADING_TAGS.has(childTag) || childTag === "p" || childTag === "ul" || childTag === "ol" || childTag === "blockquote" || childTag === "pre" || childTag === "hr" || childTag === "img" || childTag === "table" || isLayoutMarker($child, { unwrapLayoutMarkers: true }) || UNWRAP_TAGS.has(childTag) && hasBlockChild($, $child)) {
|
|
528
|
+
if (HEADING_TAGS.has(childTag) || childTag === "p" || childTag === "ul" || childTag === "ol" || childTag === "blockquote" || childTag === "pre" || childTag === "hr" || childTag === "img" || childTag === "iframe" || childTag === "table" || isLayoutMarker($child, { unwrapLayoutMarkers: true }) || UNWRAP_TAGS.has(childTag) && hasBlockChild($, $child)) {
|
|
438
529
|
hasBlock = true;
|
|
439
530
|
}
|
|
440
531
|
});
|
|
@@ -549,6 +640,12 @@ function parseMixedBlockContent($, $el, options) {
|
|
|
549
640
|
if (image) blocks.push(image);
|
|
550
641
|
return;
|
|
551
642
|
}
|
|
643
|
+
if (tagName === "iframe" && isPreservedVideoIframe($child, tagName)) {
|
|
644
|
+
flushInline();
|
|
645
|
+
const embed = videoEmbedNodeFromIframe($child);
|
|
646
|
+
if (embed) blocks.push(embed);
|
|
647
|
+
return;
|
|
648
|
+
}
|
|
552
649
|
if (INLINE_TAGS2.has(tagName)) {
|
|
553
650
|
inlineBuffer.push(...parseInlineContent($, $child));
|
|
554
651
|
return;
|
|
@@ -566,7 +663,7 @@ function walkListItem($, $el, options) {
|
|
|
566
663
|
}
|
|
567
664
|
const normalized = [];
|
|
568
665
|
for (const block of blocks) {
|
|
569
|
-
if (block.type === "paragraph" || block.type === "image" || block.type === "blockquote" || block.type === "bulletList" || block.type === "orderedList") {
|
|
666
|
+
if (block.type === "paragraph" || block.type === "image" || block.type === "embed" || block.type === "blockquote" || block.type === "bulletList" || block.type === "orderedList") {
|
|
570
667
|
normalized.push(block);
|
|
571
668
|
continue;
|
|
572
669
|
}
|
|
@@ -587,6 +684,14 @@ function walkBlockNode($, $el, options) {
|
|
|
587
684
|
if (isLayoutMarker($el, options)) {
|
|
588
685
|
return walkBlockNodes($, $el, options);
|
|
589
686
|
}
|
|
687
|
+
if (isVideoWidgetElement($el)) {
|
|
688
|
+
const embed = videoEmbedNodeFromWidget($el);
|
|
689
|
+
return embed ? [embed] : [];
|
|
690
|
+
}
|
|
691
|
+
if (isPreservedVideoIframe($el, tagName)) {
|
|
692
|
+
const embed = videoEmbedNodeFromIframe($el);
|
|
693
|
+
return embed ? [embed] : [];
|
|
694
|
+
}
|
|
590
695
|
if (UNWRAP_TAGS.has(tagName)) {
|
|
591
696
|
if (hasBlockChild($, $el)) {
|
|
592
697
|
return walkBlockNodes($, $el, options);
|
|
@@ -961,4 +1066,4 @@ export {
|
|
|
961
1066
|
validateTiptapDoc,
|
|
962
1067
|
expandMigrationMediaRefs
|
|
963
1068
|
};
|
|
964
|
-
//# sourceMappingURL=chunk-
|
|
1069
|
+
//# sourceMappingURL=chunk-VQ5HKNYP.js.map
|