@artinstack/migrator 0.1.9 → 0.1.12
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-B3XS20r_.d.ts → bundle-CysqqLij.d.ts} +1 -1
- package/dist/chunk-J7EUSPEA.js +667 -0
- package/dist/chunk-J7EUSPEA.js.map +1 -0
- package/dist/{chunk-3YJFSTYR.js → chunk-MUFGDYGI.js} +2 -1
- package/dist/chunk-MUFGDYGI.js.map +1 -0
- package/dist/{chunk-KTQGOM45.js → chunk-PFUXPS7A.js} +1 -1
- package/dist/chunk-PFUXPS7A.js.map +1 -0
- package/dist/{chunk-FB3MMCHY.js → chunk-Q44KGFIH.js} +97 -531
- package/dist/chunk-Q44KGFIH.js.map +1 -0
- package/dist/chunk-QFJXNEXG.js +355 -0
- package/dist/chunk-QFJXNEXG.js.map +1 -0
- package/dist/{chunk-PPT5RIZ4.js → chunk-VRRYN6NS.js} +40 -236
- package/dist/chunk-VRRYN6NS.js.map +1 -0
- package/dist/{chunk-S4SUJT2D.js → chunk-WCAHVNWW.js} +98 -3
- package/dist/chunk-WCAHVNWW.js.map +1 -0
- package/dist/cli/index.js +12 -6
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.js +9 -6
- package/dist/normalizer/index.d.ts +10 -4
- package/dist/normalizer/index.js +2 -2
- package/dist/sinks/index.d.ts +13 -3
- package/dist/sinks/index.js +5 -3
- package/dist/transformers/index.d.ts +1 -1
- package/dist/transformers/index.js +3 -2
- package/dist/{types-Ce4r6zqt.d.ts → types-CLNmloya.d.ts} +15 -1
- package/package.json +1 -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-FB3MMCHY.js.map +0 -1
- package/dist/chunk-KTQGOM45.js.map +0 -1
- package/dist/chunk-PPT5RIZ4.js.map +0 -1
- package/dist/chunk-S4SUJT2D.js.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { N as NormalizedPost, a as NormalizedPage, b as NormalizedAsset, c as NormalizedPortfolio, d as NormalizedCategory, e as NormalizedTag, f as NormalizedEntity } from './types-
|
|
1
|
+
import { N as NormalizedPost, a as NormalizedPage, b as NormalizedAsset, c as NormalizedPortfolio, d as NormalizedCategory, e as NormalizedTag, f as NormalizedEntity } from './types-CLNmloya.js';
|
|
2
2
|
|
|
3
3
|
interface EntityBundle {
|
|
4
4
|
posts: NormalizedPost[];
|
|
@@ -0,0 +1,667 @@
|
|
|
1
|
+
import {
|
|
2
|
+
WORDPRESS_BUILDER_REGISTRY,
|
|
3
|
+
WORDPRESS_WIDGET_REGISTRY,
|
|
4
|
+
WP_WIDGET_PLACEHOLDER
|
|
5
|
+
} from "./chunk-QFJXNEXG.js";
|
|
6
|
+
import {
|
|
7
|
+
normalizeAssetUrl
|
|
8
|
+
} from "./chunk-S4GMDRGX.js";
|
|
9
|
+
|
|
10
|
+
// src/parsers/wordpress/builders/flatten.ts
|
|
11
|
+
function escapeRegExp(value) {
|
|
12
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
13
|
+
}
|
|
14
|
+
function extractQuotedParam(params, name) {
|
|
15
|
+
const pattern = new RegExp(`\\b${escapeRegExp(name)}\\s*=\\s*`, "i");
|
|
16
|
+
const match = pattern.exec(params);
|
|
17
|
+
if (!match) return void 0;
|
|
18
|
+
let index = match.index + match[0].length;
|
|
19
|
+
while (index < params.length && /\s/.test(params[index])) index += 1;
|
|
20
|
+
if (params.slice(index, index + 6) === """) {
|
|
21
|
+
index += 6;
|
|
22
|
+
let value2 = "";
|
|
23
|
+
while (index < params.length) {
|
|
24
|
+
if (params.slice(index, index + 6) === """) break;
|
|
25
|
+
value2 += params[index];
|
|
26
|
+
index += 1;
|
|
27
|
+
}
|
|
28
|
+
const trimmed2 = value2.trim();
|
|
29
|
+
return trimmed2 || void 0;
|
|
30
|
+
}
|
|
31
|
+
const quote = params[index];
|
|
32
|
+
if (quote !== '"' && quote !== "'") return void 0;
|
|
33
|
+
index += 1;
|
|
34
|
+
let value = "";
|
|
35
|
+
while (index < params.length) {
|
|
36
|
+
const char = params[index];
|
|
37
|
+
if (char === "\\" && index + 1 < params.length) {
|
|
38
|
+
value += params[index + 1];
|
|
39
|
+
index += 2;
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
if (char === quote) break;
|
|
43
|
+
value += char;
|
|
44
|
+
index += 1;
|
|
45
|
+
}
|
|
46
|
+
const trimmed = value.trim();
|
|
47
|
+
return trimmed || void 0;
|
|
48
|
+
}
|
|
49
|
+
function escapeLayoutAttr(value) {
|
|
50
|
+
return value.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<");
|
|
51
|
+
}
|
|
52
|
+
function parseFractionWidth(fraction) {
|
|
53
|
+
if (!fraction?.trim()) return void 0;
|
|
54
|
+
const trimmed = fraction.trim();
|
|
55
|
+
const match = trimmed.match(/^(\d+)\s*\/\s*(\d+)$/);
|
|
56
|
+
if (!match) return void 0;
|
|
57
|
+
const numerator = Number(match[1]);
|
|
58
|
+
const denominator = Number(match[2]);
|
|
59
|
+
if (!Number.isFinite(numerator) || !Number.isFinite(denominator) || denominator <= 0) {
|
|
60
|
+
return void 0;
|
|
61
|
+
}
|
|
62
|
+
const percent = numerator / denominator * 100;
|
|
63
|
+
const rounded = Math.round(percent * 100) / 100;
|
|
64
|
+
return `${rounded % 1 === 0 ? rounded.toFixed(0) : rounded}%`;
|
|
65
|
+
}
|
|
66
|
+
function parseRowLayoutCols(layout) {
|
|
67
|
+
if (!layout?.trim()) return void 0;
|
|
68
|
+
const parts = layout.split("+").map((part) => part.trim()).filter(Boolean);
|
|
69
|
+
return parts.length > 1 ? parts.length : void 0;
|
|
70
|
+
}
|
|
71
|
+
function openSectionDiv(params, bgParamName) {
|
|
72
|
+
const attrs = ['data-layout="section"'];
|
|
73
|
+
const bgImage = extractQuotedParam(params, bgParamName ?? "bg_image");
|
|
74
|
+
if (bgImage?.startsWith("http")) {
|
|
75
|
+
attrs.push(`data-bg-image="${escapeLayoutAttr(bgImage)}"`);
|
|
76
|
+
}
|
|
77
|
+
return `<div ${attrs.join(" ")}>`;
|
|
78
|
+
}
|
|
79
|
+
function openRowDiv(params, colsParamName) {
|
|
80
|
+
const attrs = ['data-layout="row"'];
|
|
81
|
+
const cols = parseRowLayoutCols(extractQuotedParam(params, colsParamName ?? "layout"));
|
|
82
|
+
if (cols) attrs.push(`data-cols="${cols}"`);
|
|
83
|
+
return `<div ${attrs.join(" ")}>`;
|
|
84
|
+
}
|
|
85
|
+
function openColumnDiv(params, widthParamName) {
|
|
86
|
+
const attrs = ['data-layout="column"'];
|
|
87
|
+
const width = parseFractionWidth(extractQuotedParam(params, widthParamName ?? "width"));
|
|
88
|
+
if (width) attrs.push(`data-col-width="${width}"`);
|
|
89
|
+
return `<div ${attrs.join(" ")}>`;
|
|
90
|
+
}
|
|
91
|
+
function applyPrefixedLayoutMap(content, map) {
|
|
92
|
+
let html = content;
|
|
93
|
+
html = html.replace(map.sectionRegex, (_, params) => openSectionDiv(params, map.bgParamName));
|
|
94
|
+
html = html.replace(map.sectionCloseRegex, "</div>");
|
|
95
|
+
html = html.replace(map.rowRegex, (_, params) => openRowDiv(params, map.colsParamName));
|
|
96
|
+
html = html.replace(map.rowCloseRegex, "</div>");
|
|
97
|
+
html = html.replace(map.columnRegex, '<div data-layout="column">');
|
|
98
|
+
html = html.replace(map.columnCloseRegex, "</div>");
|
|
99
|
+
return html;
|
|
100
|
+
}
|
|
101
|
+
function applyFractionalLayoutMap(content, map) {
|
|
102
|
+
let html = content;
|
|
103
|
+
html = html.replace(map.sectionRegex, (_, params) => openSectionDiv(params, map.bgParamName));
|
|
104
|
+
html = html.replace(map.sectionCloseRegex, "</div>");
|
|
105
|
+
html = html.replace(map.rowRegex, (_, params) => openRowDiv(params));
|
|
106
|
+
html = html.replace(map.rowCloseRegex, "</div>");
|
|
107
|
+
for (let index = 0; index < map.columnTokens.length; index += 1) {
|
|
108
|
+
const token = map.columnTokens[index];
|
|
109
|
+
const width = map.columnWidths[token];
|
|
110
|
+
const openRegex = map.columnOpenRegexes[index];
|
|
111
|
+
const closeRegex = map.columnCloseRegexes[index];
|
|
112
|
+
html = html.replace(openRegex, () => {
|
|
113
|
+
const attrs = ['data-layout="column"'];
|
|
114
|
+
if (width) attrs.push(`data-col-width="${width}"`);
|
|
115
|
+
return `<div ${attrs.join(" ")}>`;
|
|
116
|
+
});
|
|
117
|
+
html = html.replace(closeRegex, "</div>");
|
|
118
|
+
}
|
|
119
|
+
return html;
|
|
120
|
+
}
|
|
121
|
+
function applyExtendedPrefixedLayoutMap(content, map) {
|
|
122
|
+
let html = content;
|
|
123
|
+
const levels = [...map.levels].sort((left, right) => {
|
|
124
|
+
const leftMax = Math.max(...left.tokens.map((token) => token.length));
|
|
125
|
+
const rightMax = Math.max(...right.tokens.map((token) => token.length));
|
|
126
|
+
return rightMax - leftMax;
|
|
127
|
+
});
|
|
128
|
+
for (const level of levels) {
|
|
129
|
+
const tokens = [...level.tokens].sort((left, right) => right.length - left.length);
|
|
130
|
+
for (const token of tokens) {
|
|
131
|
+
const openRegex = new RegExp(`\\[${escapeRegExp(token)}\\b([^\\]]*)\\]`, "gi");
|
|
132
|
+
const closeRegex = new RegExp(`\\[\\/${escapeRegExp(token)}\\b[^\\]]*\\]`, "gi");
|
|
133
|
+
html = html.replace(openRegex, (_, params) => {
|
|
134
|
+
switch (level.role) {
|
|
135
|
+
case "section":
|
|
136
|
+
return openSectionDiv(params, level.bgParamName);
|
|
137
|
+
case "row":
|
|
138
|
+
return openRowDiv(params, level.colsParamName);
|
|
139
|
+
case "column":
|
|
140
|
+
return openColumnDiv(params, level.widthParamName);
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
html = html.replace(closeRegex, "</div>");
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return html;
|
|
147
|
+
}
|
|
148
|
+
function applyStructuralLayoutMap(content, map) {
|
|
149
|
+
switch (map.kind) {
|
|
150
|
+
case "prefixed":
|
|
151
|
+
return applyPrefixedLayoutMap(content, map);
|
|
152
|
+
case "fractional":
|
|
153
|
+
return applyFractionalLayoutMap(content, map);
|
|
154
|
+
case "extended-prefixed":
|
|
155
|
+
return applyExtendedPrefixedLayoutMap(content, map);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
function collectLayoutMaps(theme) {
|
|
159
|
+
const maps = [];
|
|
160
|
+
if (theme.layoutMap) maps.push(theme.layoutMap);
|
|
161
|
+
if (theme.layoutMaps?.length) maps.push(...theme.layoutMaps);
|
|
162
|
+
return maps;
|
|
163
|
+
}
|
|
164
|
+
function extractShortcodeParam(params, names) {
|
|
165
|
+
for (const name of names) {
|
|
166
|
+
const value = extractQuotedParam(params, name);
|
|
167
|
+
if (value) return value;
|
|
168
|
+
}
|
|
169
|
+
return void 0;
|
|
170
|
+
}
|
|
171
|
+
function escapeHtmlText(text) {
|
|
172
|
+
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
173
|
+
}
|
|
174
|
+
function textToHtml(text, tag) {
|
|
175
|
+
const paragraphs = text.split(/\n{2,}/).map((part) => part.trim()).filter(Boolean);
|
|
176
|
+
if (paragraphs.length === 0) return "";
|
|
177
|
+
return paragraphs.map((paragraph) => {
|
|
178
|
+
const inner = escapeHtmlText(paragraph).replace(/\n/g, "<br />");
|
|
179
|
+
return `<${tag}>${inner}</${tag}>`;
|
|
180
|
+
}).join("\n");
|
|
181
|
+
}
|
|
182
|
+
function emitHtmlTag(tag, url) {
|
|
183
|
+
const normalized = normalizeAssetUrl(url) ?? url;
|
|
184
|
+
const escaped = normalized.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<");
|
|
185
|
+
switch (tag) {
|
|
186
|
+
case "img":
|
|
187
|
+
return `<img src="${escaped}" alt="" />`;
|
|
188
|
+
case "video":
|
|
189
|
+
return `<video src="${escaped}" controls></video>`;
|
|
190
|
+
case "iframe":
|
|
191
|
+
return `<iframe src="${escaped}" loading="lazy"></iframe>`;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
function convertUrlRule(content, rule) {
|
|
195
|
+
const prefix = escapeRegExp(rule.shortcodePrefix);
|
|
196
|
+
const pattern = new RegExp(
|
|
197
|
+
`\\[${prefix}\\b([^\\]]*)\\]\\s*(?:\\[\\/${prefix}\\b[^\\]]*\\])?`,
|
|
198
|
+
"gi"
|
|
199
|
+
);
|
|
200
|
+
return content.replace(pattern, (block, params) => {
|
|
201
|
+
const url = extractShortcodeParam(params, rule.urlParams);
|
|
202
|
+
if (!url) return block;
|
|
203
|
+
return emitHtmlTag(rule.tag, url);
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
function convertTextRule(content, rule) {
|
|
207
|
+
const prefix = escapeRegExp(rule.shortcodePrefix);
|
|
208
|
+
const pattern = new RegExp(
|
|
209
|
+
`\\[${prefix}\\b([^\\]]*)\\]\\s*(?:\\[\\/${prefix}\\b[^\\]]*\\])?`,
|
|
210
|
+
"gis"
|
|
211
|
+
);
|
|
212
|
+
return content.replace(pattern, (block, params) => {
|
|
213
|
+
const parts = [];
|
|
214
|
+
for (const field of rule.fields) {
|
|
215
|
+
const text = extractQuotedParam(params, field.param);
|
|
216
|
+
if (!text) continue;
|
|
217
|
+
const html = textToHtml(text, field.tag);
|
|
218
|
+
if (html) parts.push(html);
|
|
219
|
+
}
|
|
220
|
+
return parts.length > 0 ? parts.join("\n") : block;
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
function convertWrapperRule(content, rule) {
|
|
224
|
+
const prefix = escapeRegExp(rule.shortcodePrefix);
|
|
225
|
+
const pattern = new RegExp(
|
|
226
|
+
`\\[${prefix}\\b([^\\]]*)\\]([\\s\\S]*?)\\[\\/${prefix}\\b[^\\]]*\\]`,
|
|
227
|
+
"gi"
|
|
228
|
+
);
|
|
229
|
+
return content.replace(pattern, (_, params, inner) => {
|
|
230
|
+
const parts = [];
|
|
231
|
+
if (rule.urlParams?.length) {
|
|
232
|
+
const url = extractShortcodeParam(params, rule.urlParams);
|
|
233
|
+
if (url) parts.push(emitHtmlTag("img", url));
|
|
234
|
+
}
|
|
235
|
+
parts.push(inner.trim());
|
|
236
|
+
return parts.filter(Boolean).join("\n");
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
function isPlaceholderImageUrl(url) {
|
|
240
|
+
return /placehold\.it|placeholder\.com|via\.placeholder/i.test(url);
|
|
241
|
+
}
|
|
242
|
+
function convertIconImageRule(content, rule) {
|
|
243
|
+
const prefix = escapeRegExp(rule.shortcodePrefix);
|
|
244
|
+
const pattern = new RegExp(
|
|
245
|
+
`\\[${prefix}\\b([^\\]]*)\\]\\s*(?:\\[\\/${prefix}\\b[^\\]]*\\])?`,
|
|
246
|
+
"gi"
|
|
247
|
+
);
|
|
248
|
+
return content.replace(pattern, (_, params) => {
|
|
249
|
+
const iconImage = extractQuotedParam(params, rule.imageParam) ?? extractQuotedParam(params, "image");
|
|
250
|
+
if (!iconImage?.startsWith("http") || isPlaceholderImageUrl(iconImage)) {
|
|
251
|
+
return "";
|
|
252
|
+
}
|
|
253
|
+
const img = emitHtmlTag("img", iconImage);
|
|
254
|
+
if (rule.hrefParam) {
|
|
255
|
+
const href = extractQuotedParam(params, rule.hrefParam);
|
|
256
|
+
if (href?.startsWith("http")) {
|
|
257
|
+
const escapedHref = href.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<");
|
|
258
|
+
return `<a href="${escapedHref}">${img}</a>`;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
return img;
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
function convertPlaceholderRule(content, rule) {
|
|
265
|
+
const prefix = escapeRegExp(rule.shortcodePrefix);
|
|
266
|
+
const pattern = new RegExp(
|
|
267
|
+
`\\[${prefix}\\b([^\\]]*)\\]\\s*(?:\\[\\/${prefix}\\b[^\\]]*\\])?`,
|
|
268
|
+
"gi"
|
|
269
|
+
);
|
|
270
|
+
return content.replace(pattern, rule.html);
|
|
271
|
+
}
|
|
272
|
+
function stripScaffoldingPrefix(content, prefix) {
|
|
273
|
+
const escaped = escapeRegExp(prefix);
|
|
274
|
+
const opener = new RegExp(`\\[${escaped}[a-z0-9_-]*[^\\]]*\\]`, "gi");
|
|
275
|
+
const closer = new RegExp(`\\[\\/${escaped}[a-z0-9_-]*[^\\]]*\\]`, "gi");
|
|
276
|
+
return content.replace(opener, "").replace(closer, "");
|
|
277
|
+
}
|
|
278
|
+
function stripLegacyTokens(content, tokens) {
|
|
279
|
+
let result = content;
|
|
280
|
+
for (const token of tokens) {
|
|
281
|
+
const escaped = escapeRegExp(token);
|
|
282
|
+
const opener = new RegExp(`\\[${escaped}\\b[^\\]]*\\]`, "gi");
|
|
283
|
+
const closer = new RegExp(`\\[\\/${escaped}\\b[^\\]]*\\]`, "gi");
|
|
284
|
+
result = result.replace(opener, "").replace(closer, "");
|
|
285
|
+
}
|
|
286
|
+
return result;
|
|
287
|
+
}
|
|
288
|
+
function detectThemes(content, registry) {
|
|
289
|
+
return registry.filter((theme) => theme.detect.test(content));
|
|
290
|
+
}
|
|
291
|
+
function extractBareOrQuotedParam(params, name) {
|
|
292
|
+
const quoted = extractQuotedParam(params, name);
|
|
293
|
+
if (quoted) return quoted;
|
|
294
|
+
const pattern = new RegExp(`\\b${escapeRegExp(name)}\\s*=\\s*([^\\s"'\\]]+)`, "i");
|
|
295
|
+
const match = pattern.exec(params);
|
|
296
|
+
return match?.[1]?.trim() || void 0;
|
|
297
|
+
}
|
|
298
|
+
function emitWidgetStub(widget, attrs, tag = "div") {
|
|
299
|
+
const parts = [`data-wp-widget="${escapeLayoutAttr(widget)}"`];
|
|
300
|
+
for (const [key, value] of Object.entries(attrs)) {
|
|
301
|
+
if (value) parts.push(`${key}="${escapeLayoutAttr(value)}"`);
|
|
302
|
+
}
|
|
303
|
+
return `<${tag} ${parts.join(" ")}>${WP_WIDGET_PLACEHOLDER}</${tag}>`;
|
|
304
|
+
}
|
|
305
|
+
function normalizeVideoEmbedUrl(raw) {
|
|
306
|
+
const trimmed = raw.trim();
|
|
307
|
+
if (!trimmed || trimmed.startsWith("data:")) return void 0;
|
|
308
|
+
try {
|
|
309
|
+
const url = new URL(trimmed.startsWith("//") ? `https:${trimmed}` : trimmed);
|
|
310
|
+
const host = url.hostname.replace(/^www\./, "").replace(/^m\./, "");
|
|
311
|
+
if (host === "youtu.be") {
|
|
312
|
+
const id = url.pathname.split("/").filter(Boolean)[0];
|
|
313
|
+
if (id) {
|
|
314
|
+
return { provider: "youtube", embedUrl: `https://www.youtube-nocookie.com/embed/${id}` };
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
if (host === "youtube.com" || host === "youtube-nocookie.com") {
|
|
318
|
+
const embedMatch = url.pathname.match(/\/embed\/([^/?#]+)/);
|
|
319
|
+
if (embedMatch?.[1]) {
|
|
320
|
+
const start = url.searchParams.get("start");
|
|
321
|
+
const suffix = start ? `?start=${start}` : "";
|
|
322
|
+
return {
|
|
323
|
+
provider: "youtube",
|
|
324
|
+
embedUrl: `https://www.youtube-nocookie.com/embed/${embedMatch[1]}${suffix}`
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
const videoId = url.searchParams.get("v");
|
|
328
|
+
if (videoId) {
|
|
329
|
+
const t = url.searchParams.get("t") ?? url.searchParams.get("start");
|
|
330
|
+
const startSeconds = t?.endsWith("s") ? t.slice(0, -1) : t;
|
|
331
|
+
const suffix = startSeconds ? `?start=${startSeconds}` : "";
|
|
332
|
+
return {
|
|
333
|
+
provider: "youtube",
|
|
334
|
+
embedUrl: `https://www.youtube-nocookie.com/embed/${videoId}${suffix}`
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
if (host === "vimeo.com") {
|
|
339
|
+
const segments = url.pathname.split("/").filter(Boolean);
|
|
340
|
+
const id = segments[segments.length - 1];
|
|
341
|
+
if (id && /^\d+$/.test(id)) {
|
|
342
|
+
return { provider: "vimeo", embedUrl: `https://player.vimeo.com/video/${id}` };
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
if (host === "player.vimeo.com") {
|
|
346
|
+
const match = url.pathname.match(/\/video\/(\d+)/);
|
|
347
|
+
if (match?.[1]) {
|
|
348
|
+
return { provider: "vimeo", embedUrl: `https://player.vimeo.com/video/${match[1]}` };
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
} catch {
|
|
352
|
+
return void 0;
|
|
353
|
+
}
|
|
354
|
+
return void 0;
|
|
355
|
+
}
|
|
356
|
+
function emitVideoWidgetFromParams(params, inner) {
|
|
357
|
+
const url = extractShortcodeParam(params, ["url", "src", "video", "link", "youtube_url", "vimeo_url"]) ?? inner.trim().match(/^https?:\/\/\S+/)?.[0];
|
|
358
|
+
if (!url) {
|
|
359
|
+
return emitWidgetStub("video", { "data-video-provider": "external" });
|
|
360
|
+
}
|
|
361
|
+
const normalized = normalizeVideoEmbedUrl(url);
|
|
362
|
+
if (normalized) {
|
|
363
|
+
return emitWidgetStub("video", {
|
|
364
|
+
"data-video-provider": normalized.provider,
|
|
365
|
+
"data-embed-url": normalized.embedUrl
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
if (/\.(mp4|webm|ogg)(\?|#|$)/i.test(url)) {
|
|
369
|
+
return emitHtmlTag("video", url);
|
|
370
|
+
}
|
|
371
|
+
return emitWidgetStub("video", {
|
|
372
|
+
"data-video-provider": "external",
|
|
373
|
+
"data-embed-url": url
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
function buildGoogleMapsEmbedUrlFromMapParams(params) {
|
|
377
|
+
const direct = extractShortcodeParam(params, [
|
|
378
|
+
"embed_url",
|
|
379
|
+
"url",
|
|
380
|
+
"src",
|
|
381
|
+
"map_url",
|
|
382
|
+
"iframe_url",
|
|
383
|
+
"embed"
|
|
384
|
+
]);
|
|
385
|
+
if (direct && /google\.com\/maps|maps\.google\.com/i.test(direct)) {
|
|
386
|
+
return { embedUrl: direct.trim() };
|
|
387
|
+
}
|
|
388
|
+
const lat = extractBareOrQuotedParam(params, "lat") ?? extractBareOrQuotedParam(params, "latitude") ?? extractBareOrQuotedParam(params, "map_lat");
|
|
389
|
+
const lng = extractBareOrQuotedParam(params, "lng") ?? extractBareOrQuotedParam(params, "longitude") ?? extractBareOrQuotedParam(params, "map_lng");
|
|
390
|
+
const address = extractBareOrQuotedParam(params, "address") ?? extractBareOrQuotedParam(params, "map_address") ?? extractBareOrQuotedParam(params, "location") ?? extractBareOrQuotedParam(params, "map_location") ?? extractBareOrQuotedParam(params, "q");
|
|
391
|
+
if (lat && lng) {
|
|
392
|
+
const zoom = extractBareOrQuotedParam(params, "zoom") ?? "14";
|
|
393
|
+
return {
|
|
394
|
+
embedUrl: `https://maps.google.com/maps?q=${encodeURIComponent(`${lat},${lng}`)}&z=${zoom}&output=embed`,
|
|
395
|
+
lat,
|
|
396
|
+
lng
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
if (address) {
|
|
400
|
+
return {
|
|
401
|
+
embedUrl: `https://maps.google.com/maps?q=${encodeURIComponent(address)}&output=embed`,
|
|
402
|
+
query: address
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
return {};
|
|
406
|
+
}
|
|
407
|
+
function flattenMapShortcodes(content, widgetRegistry) {
|
|
408
|
+
let html = content;
|
|
409
|
+
for (const prefix of widgetRegistry.mapShortcodePrefixes) {
|
|
410
|
+
const pattern = new RegExp(
|
|
411
|
+
`\\[${escapeRegExp(prefix)}\\b([^\\]]*)\\]\\s*(?:\\[\\/${escapeRegExp(prefix)}\\b[^\\]]*\\])?`,
|
|
412
|
+
"gi"
|
|
413
|
+
);
|
|
414
|
+
html = html.replace(pattern, (_, params) => {
|
|
415
|
+
const resolved = buildGoogleMapsEmbedUrlFromMapParams(params);
|
|
416
|
+
return emitWidgetStub("map", {
|
|
417
|
+
...resolved.embedUrl ? { "data-embed-url": resolved.embedUrl } : {},
|
|
418
|
+
...resolved.lat ? { "data-wp-map-lat": resolved.lat } : {},
|
|
419
|
+
...resolved.lng ? { "data-wp-map-lng": resolved.lng } : {},
|
|
420
|
+
...resolved.query ? { "data-wp-map-query": resolved.query } : {}
|
|
421
|
+
});
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
return html;
|
|
425
|
+
}
|
|
426
|
+
function flattenContactFormShortcodes(content, widgetRegistry) {
|
|
427
|
+
let html = content;
|
|
428
|
+
for (const rule of widgetRegistry.contactFormRules) {
|
|
429
|
+
const pattern = new RegExp(
|
|
430
|
+
`\\[${escapeRegExp(rule.tag)}\\b([^\\]]*)\\]\\s*(?:\\[\\/${escapeRegExp(rule.tag)}\\b[^\\]]*\\])?`,
|
|
431
|
+
"gi"
|
|
432
|
+
);
|
|
433
|
+
html = html.replace(pattern, (_, params) => {
|
|
434
|
+
const id = extractBareOrQuotedParam(params, rule.idParam);
|
|
435
|
+
return emitWidgetStub(
|
|
436
|
+
"contact-form",
|
|
437
|
+
{
|
|
438
|
+
"data-wp-form-source": rule.source,
|
|
439
|
+
...id ? { "data-wp-form-id": id } : {}
|
|
440
|
+
},
|
|
441
|
+
"section"
|
|
442
|
+
);
|
|
443
|
+
});
|
|
444
|
+
}
|
|
445
|
+
return html;
|
|
446
|
+
}
|
|
447
|
+
function emitInlineGalleryFromIds(idList) {
|
|
448
|
+
const images = idList.map((id) => `<img data-wp-attachment-id="${escapeLayoutAttr(id)}" alt="" />`).join("");
|
|
449
|
+
return `<figure data-wp-inline-gallery>${images}</figure>`;
|
|
450
|
+
}
|
|
451
|
+
function parseGalleryAttachmentIds(params) {
|
|
452
|
+
const ids = extractBareOrQuotedParam(params, "ids");
|
|
453
|
+
const idList = ids?.split(",").map((part) => part.trim()).filter((part) => /^\d+$/.test(part));
|
|
454
|
+
return idList?.length ? idList : void 0;
|
|
455
|
+
}
|
|
456
|
+
function flattenIdGalleryShortcode(content, tag) {
|
|
457
|
+
const escaped = escapeRegExp(tag);
|
|
458
|
+
const pattern = new RegExp(`\\[${escaped}\\b([^\\]]*)\\](?:\\s*\\[\\/${escaped}\\])?`, "gi");
|
|
459
|
+
return content.replace(pattern, (fullMatch, params) => {
|
|
460
|
+
const idList = parseGalleryAttachmentIds(params);
|
|
461
|
+
if (idList?.length) {
|
|
462
|
+
return emitInlineGalleryFromIds(idList);
|
|
463
|
+
}
|
|
464
|
+
return fullMatch;
|
|
465
|
+
});
|
|
466
|
+
}
|
|
467
|
+
function flattenGalleryShortcodes(content, widgetRegistry) {
|
|
468
|
+
const tag = escapeRegExp(widgetRegistry.galleryShortcode);
|
|
469
|
+
const pattern = new RegExp(`\\[${tag}\\b([^\\]]*)\\](?:\\s*\\[\\/${tag}\\])?`, "gi");
|
|
470
|
+
return content.replace(pattern, (_, params) => {
|
|
471
|
+
const idList = parseGalleryAttachmentIds(params);
|
|
472
|
+
if (idList?.length) {
|
|
473
|
+
return emitInlineGalleryFromIds(idList);
|
|
474
|
+
}
|
|
475
|
+
const category = extractBareOrQuotedParam(params, "category") ?? extractBareOrQuotedParam(params, "type");
|
|
476
|
+
return emitWidgetStub("portfolio", {
|
|
477
|
+
"data-wp-gallery-dynamic": "1",
|
|
478
|
+
...category ? { "data-wp-portfolio-category": category } : {}
|
|
479
|
+
});
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
function flattenIdBasedGalleryShortcodes(content, widgetRegistry) {
|
|
483
|
+
let html = content;
|
|
484
|
+
for (const tag of widgetRegistry.idGalleryShortcodes) {
|
|
485
|
+
html = flattenIdGalleryShortcode(html, tag);
|
|
486
|
+
}
|
|
487
|
+
return html;
|
|
488
|
+
}
|
|
489
|
+
var SHORTCODE_WORD_COUNTS = {
|
|
490
|
+
one: "1",
|
|
491
|
+
two: "2",
|
|
492
|
+
three: "3",
|
|
493
|
+
four: "4",
|
|
494
|
+
five: "5",
|
|
495
|
+
six: "6",
|
|
496
|
+
seven: "7",
|
|
497
|
+
eight: "8",
|
|
498
|
+
nine: "9",
|
|
499
|
+
ten: "10"
|
|
500
|
+
};
|
|
501
|
+
function normalizeShortcodeCount(raw) {
|
|
502
|
+
if (!raw?.trim()) return void 0;
|
|
503
|
+
const trimmed = raw.trim().toLowerCase();
|
|
504
|
+
if (/^\d+$/.test(trimmed)) return trimmed;
|
|
505
|
+
return SHORTCODE_WORD_COUNTS[trimmed];
|
|
506
|
+
}
|
|
507
|
+
function inferBlogListingLayout(params) {
|
|
508
|
+
const raw = extractBareOrQuotedParam(params, "builderLayout") ?? extractBareOrQuotedParam(params, "layout") ?? extractBareOrQuotedParam(params, "style");
|
|
509
|
+
if (!raw) return "grid";
|
|
510
|
+
const normalized = raw.trim().toLowerCase();
|
|
511
|
+
if (normalized === "list" || normalized === "grid" || normalized === "featured" || normalized === "sidebar") {
|
|
512
|
+
return normalized;
|
|
513
|
+
}
|
|
514
|
+
return "grid";
|
|
515
|
+
}
|
|
516
|
+
function flattenBlogListingShortcodes(content, widgetRegistry) {
|
|
517
|
+
let html = content;
|
|
518
|
+
for (const tag of widgetRegistry.blogShortcodeTags) {
|
|
519
|
+
const escaped = escapeRegExp(tag);
|
|
520
|
+
const pattern = new RegExp(`\\[${escaped}\\b([^\\]]*)\\](?:\\s*\\[\\/${escaped}\\])?`, "gi");
|
|
521
|
+
html = html.replace(pattern, (_, params) => {
|
|
522
|
+
const limit = normalizeShortcodeCount(extractBareOrQuotedParam(params, "number_of_posts")) ?? normalizeShortcodeCount(extractBareOrQuotedParam(params, "count")) ?? normalizeShortcodeCount(extractBareOrQuotedParam(params, "posts_per_page")) ?? normalizeShortcodeCount(extractBareOrQuotedParam(params, "number"));
|
|
523
|
+
const filterBy = extractBareOrQuotedParam(params, "filter_by")?.toLowerCase();
|
|
524
|
+
const categories = extractBareOrQuotedParam(params, "categories");
|
|
525
|
+
const tags = extractBareOrQuotedParam(params, "tags");
|
|
526
|
+
const col = extractBareOrQuotedParam(params, "col");
|
|
527
|
+
return emitWidgetStub(
|
|
528
|
+
"blog-listing",
|
|
529
|
+
{
|
|
530
|
+
"data-wp-blog-layout": inferBlogListingLayout(params),
|
|
531
|
+
...limit ? { "data-wp-blog-limit": limit } : {},
|
|
532
|
+
...col ? { "data-wp-blog-columns": col } : {},
|
|
533
|
+
...filterBy === "category" && categories ? { "data-wp-blog-category": categories } : {},
|
|
534
|
+
...filterBy === "tag" && tags ? { "data-wp-blog-tags": tags } : {}
|
|
535
|
+
},
|
|
536
|
+
"section"
|
|
537
|
+
);
|
|
538
|
+
});
|
|
539
|
+
}
|
|
540
|
+
return html;
|
|
541
|
+
}
|
|
542
|
+
function flattenPortfolioShortcodes(content, widgetRegistry) {
|
|
543
|
+
const tag = escapeRegExp(widgetRegistry.portfolioShortcode);
|
|
544
|
+
const pattern = new RegExp(`\\[${tag}\\b([^\\]]*)\\](?:\\s*\\[\\/${tag}\\])?`, "gi");
|
|
545
|
+
return content.replace(pattern, (_, params) => {
|
|
546
|
+
const category = extractBareOrQuotedParam(params, "category");
|
|
547
|
+
const slug = extractBareOrQuotedParam(params, "slug");
|
|
548
|
+
return emitWidgetStub("portfolio", {
|
|
549
|
+
...category ? { "data-wp-portfolio-category": category } : {},
|
|
550
|
+
...slug ? { "data-wp-portfolio-slug": slug } : {}
|
|
551
|
+
});
|
|
552
|
+
});
|
|
553
|
+
}
|
|
554
|
+
function flattenVideoShortcodes(content, widgetRegistry) {
|
|
555
|
+
let html = content;
|
|
556
|
+
for (const prefix of widgetRegistry.videoShortcodePrefixes) {
|
|
557
|
+
const wrapped = new RegExp(
|
|
558
|
+
`\\[${escapeRegExp(prefix)}\\b([^\\]]*)\\]([\\s\\S]*?)\\[\\/${escapeRegExp(prefix)}\\b[^\\]]*\\]`,
|
|
559
|
+
"gi"
|
|
560
|
+
);
|
|
561
|
+
html = html.replace(
|
|
562
|
+
wrapped,
|
|
563
|
+
(_, params, inner) => emitVideoWidgetFromParams(params, inner)
|
|
564
|
+
);
|
|
565
|
+
const selfClosing = new RegExp(
|
|
566
|
+
`\\[${escapeRegExp(prefix)}\\b([^\\]]*)\\]`,
|
|
567
|
+
"gi"
|
|
568
|
+
);
|
|
569
|
+
html = html.replace(selfClosing, (_, params) => emitVideoWidgetFromParams(params, ""));
|
|
570
|
+
}
|
|
571
|
+
return html;
|
|
572
|
+
}
|
|
573
|
+
function looksLikeContactFormHtml(formHtml) {
|
|
574
|
+
if (!/<form\b/i.test(formHtml)) return false;
|
|
575
|
+
const lower = formHtml.toLowerCase();
|
|
576
|
+
if (/searchform|wp-login-form|loginform|lostpasswordform/i.test(lower)) return false;
|
|
577
|
+
if (/type\s*=\s*["']search["']/i.test(formHtml)) return false;
|
|
578
|
+
if (/newsletter|subscribe/i.test(lower) && !/<textarea\b/i.test(formHtml)) return false;
|
|
579
|
+
const hasEmailField = /type\s*=\s*["']email["']/i.test(formHtml) || /name\s*=\s*["'][^"']*email/i.test(formHtml) || /class\s*=\s*["'][^"']*email/i.test(formHtml);
|
|
580
|
+
const hasMessageField = /<textarea\b/i.test(formHtml) || /name\s*=\s*["'][^"']*(message|comment|body|enquiry|inquiry)/i.test(formHtml);
|
|
581
|
+
const hasContactHint = /contact|serverless-contact|get-in-touch|request-quote|quote-request/i.test(lower);
|
|
582
|
+
if (hasEmailField && hasMessageField) return true;
|
|
583
|
+
if (hasContactHint && hasEmailField) return true;
|
|
584
|
+
if (hasContactHint && hasMessageField) return true;
|
|
585
|
+
return false;
|
|
586
|
+
}
|
|
587
|
+
function stripContactFormHelperScripts(html) {
|
|
588
|
+
return html.replace(
|
|
589
|
+
/<script\b[^>]*\bsrc\s*=\s*["'][^"']*(?:recaptcha|contact_form|contact-form)[^"']*["'][^>]*>\s*<\/script>\s*/gi,
|
|
590
|
+
""
|
|
591
|
+
);
|
|
592
|
+
}
|
|
593
|
+
function flattenCustomHtmlContactForms(content) {
|
|
594
|
+
let html = content.replace(/<form\b[^>]*>[\s\S]*?<\/form>/gi, (formHtml) => {
|
|
595
|
+
if (!looksLikeContactFormHtml(formHtml)) return formHtml;
|
|
596
|
+
const formId = formHtml.match(/\bid\s*=\s*["']([^"']+)["']/i)?.[1]?.trim() || formHtml.match(/\bname\s*=\s*["']([^"']+)["']/i)?.[1]?.trim();
|
|
597
|
+
return emitWidgetStub(
|
|
598
|
+
"contact-form",
|
|
599
|
+
{
|
|
600
|
+
"data-wp-form-source": "custom-html",
|
|
601
|
+
...formId ? { "data-wp-form-id": formId } : {}
|
|
602
|
+
},
|
|
603
|
+
"section"
|
|
604
|
+
);
|
|
605
|
+
});
|
|
606
|
+
html = stripContactFormHelperScripts(html);
|
|
607
|
+
return html;
|
|
608
|
+
}
|
|
609
|
+
function flattenWordPressWidgets(content, widgetRegistry = WORDPRESS_WIDGET_REGISTRY) {
|
|
610
|
+
let html = content;
|
|
611
|
+
html = flattenGalleryShortcodes(html, widgetRegistry);
|
|
612
|
+
html = flattenIdBasedGalleryShortcodes(html, widgetRegistry);
|
|
613
|
+
html = flattenPortfolioShortcodes(html, widgetRegistry);
|
|
614
|
+
html = flattenBlogListingShortcodes(html, widgetRegistry);
|
|
615
|
+
html = flattenMapShortcodes(html, widgetRegistry);
|
|
616
|
+
html = flattenContactFormShortcodes(html, widgetRegistry);
|
|
617
|
+
html = flattenVideoShortcodes(html, widgetRegistry);
|
|
618
|
+
html = flattenCustomHtmlContactForms(html);
|
|
619
|
+
return html;
|
|
620
|
+
}
|
|
621
|
+
function flattenWordPressBuilders(content, options = {}) {
|
|
622
|
+
if (!content.trim()) {
|
|
623
|
+
return { html: content, detectedThemes: [] };
|
|
624
|
+
}
|
|
625
|
+
const registry = options.registry ?? WORDPRESS_BUILDER_REGISTRY;
|
|
626
|
+
const themes = detectThemes(content, registry);
|
|
627
|
+
const widgetRegistry = options.widgetRegistry ?? WORDPRESS_WIDGET_REGISTRY;
|
|
628
|
+
let html = flattenWordPressWidgets(content, widgetRegistry);
|
|
629
|
+
for (const theme of themes) {
|
|
630
|
+
for (const rule of theme.wrapperRules ?? []) {
|
|
631
|
+
html = convertWrapperRule(html, rule);
|
|
632
|
+
}
|
|
633
|
+
for (const rule of theme.textRules ?? []) {
|
|
634
|
+
html = convertTextRule(html, rule);
|
|
635
|
+
}
|
|
636
|
+
for (const rule of theme.urlRules ?? []) {
|
|
637
|
+
html = convertUrlRule(html, rule);
|
|
638
|
+
}
|
|
639
|
+
for (const rule of theme.placeholderRules ?? []) {
|
|
640
|
+
html = convertPlaceholderRule(html, rule);
|
|
641
|
+
}
|
|
642
|
+
for (const rule of theme.iconImageRules ?? []) {
|
|
643
|
+
html = convertIconImageRule(html, rule);
|
|
644
|
+
}
|
|
645
|
+
for (const layoutMap of collectLayoutMaps(theme)) {
|
|
646
|
+
html = applyStructuralLayoutMap(html, layoutMap);
|
|
647
|
+
}
|
|
648
|
+
for (const prefix of theme.scaffoldingPrefixes ?? []) {
|
|
649
|
+
html = stripScaffoldingPrefix(html, prefix);
|
|
650
|
+
}
|
|
651
|
+
if (theme.legacyScaffoldingTokens?.length) {
|
|
652
|
+
html = stripLegacyTokens(html, theme.legacyScaffoldingTokens);
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
html = flattenWordPressWidgets(html, widgetRegistry);
|
|
656
|
+
html = html.replace(/\n{3,}/g, "\n\n").trim();
|
|
657
|
+
return {
|
|
658
|
+
html,
|
|
659
|
+
detectedThemes: themes.map((theme) => theme.id)
|
|
660
|
+
};
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
export {
|
|
664
|
+
normalizeVideoEmbedUrl,
|
|
665
|
+
flattenWordPressBuilders
|
|
666
|
+
};
|
|
667
|
+
//# sourceMappingURL=chunk-J7EUSPEA.js.map
|