@zeropress/build-pages 0.5.5 → 0.6.1
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 +71 -12
- package/dist/action.js +2159 -289
- package/dist/prebuild.js +147 -24
- package/package.json +2 -2
- package/schemas/zeropress-build-pages.config.v0.1.schema.json +35 -14
- package/src/action.js +1 -1
- package/src/prebuild.js +161 -22
- package/themes/docs/layout.html +1 -1
- package/themes/docs/theme.json +4 -4
- package/schemas/zeropress-build-pages.config.schema.json +0 -5
package/dist/action.js
CHANGED
|
@@ -52242,15 +52242,25 @@ function invalidSlugValidationResult(value, code2) {
|
|
|
52242
52242
|
}
|
|
52243
52243
|
|
|
52244
52244
|
// node_modules/@zeropress/preview-data-validator/src/index.js
|
|
52245
|
-
var PREVIEW_DATA_VERSION = "0.
|
|
52245
|
+
var PREVIEW_DATA_VERSION = "0.6";
|
|
52246
52246
|
var PREVIEW_DOCUMENT_TYPES = ["plaintext", "markdown", "html"];
|
|
52247
52247
|
var PREVIEW_MENU_ITEM_TYPES = ["custom", "page", "post", "category"];
|
|
52248
52248
|
var PREVIEW_MENU_TARGETS = ["_self", "_blank"];
|
|
52249
52249
|
var PREVIEW_MENU_ID_PATTERN = /^[a-z][a-z0-9_-]{0,63}$/;
|
|
52250
52250
|
var PREVIEW_WIDGET_AREA_ID_PATTERN = /^[a-z][a-z0-9_-]{0,63}$/;
|
|
52251
|
+
var PREVIEW_COLLECTION_ID_PATTERN = /^[a-z][a-z0-9_-]{0,63}$/;
|
|
52252
|
+
var PREVIEW_COLLECTION_ITEM_TYPES = ["post", "page"];
|
|
52253
|
+
var PREVIEW_MEDIA_DELIVERY_MODES = ["none", "media_domain"];
|
|
52254
|
+
var PREVIEW_DATETIME_DISPLAY_MODES = ["static", "client"];
|
|
52255
|
+
var PREVIEW_DATETIME_STYLES = ["none", "short", "medium", "long", "full"];
|
|
52256
|
+
var PREVIEW_DISCOVERABILITY_VALUES = ["default", "noindex", "delist"];
|
|
52251
52257
|
var PREVIEW_PERMALINK_OUTPUT_STYLES = ["directory", "html-extension"];
|
|
52252
52258
|
var PREVIEW_PERMALINK_FIELDS = ["posts", "pages", "categories", "tags"];
|
|
52253
52259
|
var PREVIEW_FRONT_PAGE_TYPES = ["theme_index", "page", "standalone_html"];
|
|
52260
|
+
var PREVIEW_DATA_KEY_PATTERN = /^[a-zA-Z_][a-zA-Z0-9_]*(?:-[a-zA-Z0-9_]+)*$/;
|
|
52261
|
+
var PREVIEW_DATA_MAX_DEPTH = 4;
|
|
52262
|
+
var PREVIEW_DATA_MAX_KEYS = 64;
|
|
52263
|
+
var PREVIEW_DATA_MAX_ARRAY_LENGTH = 256;
|
|
52254
52264
|
var PREVIEW_PERMALINK_TOKENS = Object.freeze({
|
|
52255
52265
|
posts: /* @__PURE__ */ new Set(["slug", "public_id", "year", "month", "day"]),
|
|
52256
52266
|
pages: /* @__PURE__ */ new Set(["slug"]),
|
|
@@ -52259,7 +52269,7 @@ var PREVIEW_PERMALINK_TOKENS = Object.freeze({
|
|
|
52259
52269
|
});
|
|
52260
52270
|
function validatePreviewData(data) {
|
|
52261
52271
|
const errors = [];
|
|
52262
|
-
validateClosedObject(data, "", errors, ["$schema", "version", "generator", "generated_at", "site", "content", "menus", "widgets", "custom_css", "custom_html"]);
|
|
52272
|
+
validateClosedObject(data, "", errors, ["$schema", "version", "generator", "generated_at", "site", "content", "menus", "widgets", "collections", "custom_css", "custom_html"]);
|
|
52263
52273
|
if (isObject(data)) {
|
|
52264
52274
|
if (data.$schema !== void 0) {
|
|
52265
52275
|
validateString(data.$schema, "$schema", "INVALID_SCHEMA_HINT", errors);
|
|
@@ -52269,8 +52279,15 @@ function validatePreviewData(data) {
|
|
|
52269
52279
|
validateDateTimeString(data.generated_at, "generated_at", "INVALID_GENERATED_AT", errors);
|
|
52270
52280
|
validateSite(data.site, "site", errors);
|
|
52271
52281
|
validateContent(data.content, "content", errors);
|
|
52272
|
-
|
|
52273
|
-
|
|
52282
|
+
if (data.menus !== void 0) {
|
|
52283
|
+
validateMenus(data.menus, "menus", errors);
|
|
52284
|
+
}
|
|
52285
|
+
if (data.widgets !== void 0) {
|
|
52286
|
+
validateWidgets(data.widgets, "widgets", errors);
|
|
52287
|
+
}
|
|
52288
|
+
if (data.collections !== void 0) {
|
|
52289
|
+
validateCollections(data.collections, "collections", errors);
|
|
52290
|
+
}
|
|
52274
52291
|
if (data.custom_css !== void 0) {
|
|
52275
52292
|
validateCustomCss(data.custom_css, "custom_css", errors);
|
|
52276
52293
|
}
|
|
@@ -52293,23 +52310,58 @@ function assertPreviewData(data) {
|
|
|
52293
52310
|
return data;
|
|
52294
52311
|
}
|
|
52295
52312
|
function validateSite(site, path4, errors) {
|
|
52296
|
-
|
|
52313
|
+
validateClosedObject(site, path4, errors, [
|
|
52314
|
+
"title",
|
|
52315
|
+
"description",
|
|
52316
|
+
"url",
|
|
52317
|
+
"media_base_url",
|
|
52318
|
+
"media_delivery_mode",
|
|
52319
|
+
"favicon",
|
|
52320
|
+
"expose_generator",
|
|
52321
|
+
"locale",
|
|
52322
|
+
"posts_per_page",
|
|
52323
|
+
"datetime_display",
|
|
52324
|
+
"date_style",
|
|
52325
|
+
"time_style",
|
|
52326
|
+
"timezone",
|
|
52327
|
+
"disallow_comments",
|
|
52328
|
+
"indexing",
|
|
52329
|
+
"permalinks",
|
|
52330
|
+
"front_page",
|
|
52331
|
+
"post_index",
|
|
52332
|
+
"footer",
|
|
52333
|
+
"meta"
|
|
52334
|
+
]);
|
|
52297
52335
|
if (!isObject(site)) {
|
|
52298
52336
|
return;
|
|
52299
52337
|
}
|
|
52300
52338
|
validateNonEmptyString(site.title, `${path4}.title`, "INVALID_SITE_TITLE", errors);
|
|
52301
52339
|
validateString(site.description, `${path4}.description`, "INVALID_SITE_DESCRIPTION", errors);
|
|
52302
52340
|
validateSiteUri(site.url, `${path4}.url`, "INVALID_SITE_URL", errors);
|
|
52303
|
-
validateSiteUri(site.
|
|
52341
|
+
validateSiteUri(site.media_base_url, `${path4}.media_base_url`, "INVALID_SITE_MEDIA_BASE_URL", errors);
|
|
52342
|
+
if (site.media_delivery_mode !== void 0) {
|
|
52343
|
+
validateEnum(site.media_delivery_mode, `${path4}.media_delivery_mode`, "INVALID_SITE_MEDIA_DELIVERY_MODE", errors, PREVIEW_MEDIA_DELIVERY_MODES);
|
|
52344
|
+
}
|
|
52345
|
+
if (site.favicon !== void 0) {
|
|
52346
|
+
validateSiteFavicon(site.favicon, `${path4}.favicon`, errors);
|
|
52347
|
+
}
|
|
52348
|
+
if (site.expose_generator !== void 0) {
|
|
52349
|
+
validateBoolean(site.expose_generator, `${path4}.expose_generator`, "INVALID_SITE_EXPOSE_GENERATOR", errors);
|
|
52350
|
+
}
|
|
52304
52351
|
validateNonEmptyString(site.locale, `${path4}.locale`, "INVALID_SITE_LOCALE", errors);
|
|
52305
|
-
validateInteger(site.
|
|
52306
|
-
|
|
52307
|
-
|
|
52352
|
+
validateInteger(site.posts_per_page, `${path4}.posts_per_page`, "INVALID_SITE_POSTS_PER_PAGE", errors, { minimum: 1 });
|
|
52353
|
+
validateEnum(site.datetime_display, `${path4}.datetime_display`, "INVALID_SITE_DATETIME_DISPLAY", errors, PREVIEW_DATETIME_DISPLAY_MODES);
|
|
52354
|
+
validateEnum(site.date_style, `${path4}.date_style`, "INVALID_SITE_DATE_STYLE", errors, PREVIEW_DATETIME_STYLES);
|
|
52355
|
+
validateEnum(site.time_style, `${path4}.time_style`, "INVALID_SITE_TIME_STYLE", errors, PREVIEW_DATETIME_STYLES);
|
|
52308
52356
|
validateNonEmptyString(site.timezone, `${path4}.timezone`, "INVALID_SITE_TIMEZONE", errors);
|
|
52309
|
-
validateBoolean(site.
|
|
52357
|
+
validateBoolean(site.disallow_comments, `${path4}.disallow_comments`, "INVALID_SITE_DISALLOW_COMMENTS", errors);
|
|
52358
|
+
if (site.indexing !== void 0) {
|
|
52359
|
+
validateBoolean(site.indexing, `${path4}.indexing`, "INVALID_SITE_INDEXING", errors);
|
|
52360
|
+
}
|
|
52310
52361
|
validatePermalinks(site.permalinks, `${path4}.permalinks`, errors);
|
|
52311
52362
|
validateFrontPage(site.front_page, `${path4}.front_page`, errors);
|
|
52312
52363
|
validatePostIndex(site.post_index, `${path4}.post_index`, errors);
|
|
52364
|
+
validatePreviewMeta(site.meta, `${path4}.meta`, errors);
|
|
52313
52365
|
if (site.footer !== void 0) {
|
|
52314
52366
|
validateSiteFooter(site.footer, `${path4}.footer`, errors);
|
|
52315
52367
|
}
|
|
@@ -52318,7 +52370,6 @@ function validateSite(site, path4, errors) {
|
|
|
52318
52370
|
"site_description",
|
|
52319
52371
|
"site_url",
|
|
52320
52372
|
"metadata",
|
|
52321
|
-
"media_delivery_mode",
|
|
52322
52373
|
"media_delivery_base_url",
|
|
52323
52374
|
"language",
|
|
52324
52375
|
"siteLocale",
|
|
@@ -52328,7 +52379,7 @@ function validateSite(site, path4, errors) {
|
|
|
52328
52379
|
], "INVALID_LEGACY_SITE_FIELD");
|
|
52329
52380
|
}
|
|
52330
52381
|
function validateContent(content, path4, errors) {
|
|
52331
|
-
validateClosedObject(content, path4, errors, ["authors", "posts", "pages", "categories", "tags"]);
|
|
52382
|
+
validateClosedObject(content, path4, errors, ["authors", "posts", "pages", "categories", "tags", "media"]);
|
|
52332
52383
|
if (!isObject(content)) {
|
|
52333
52384
|
return;
|
|
52334
52385
|
}
|
|
@@ -52343,6 +52394,9 @@ function validateContent(content, path4, errors) {
|
|
|
52343
52394
|
validateArray(content.tags, `${path4}.tags`, "INVALID_TAGS", errors, (entry, index) => {
|
|
52344
52395
|
validatePreviewTag(entry, `${path4}.tags[${index}]`, errors);
|
|
52345
52396
|
});
|
|
52397
|
+
if (content.media !== void 0) {
|
|
52398
|
+
validateMediaArray(content.media, `${path4}.media`, errors);
|
|
52399
|
+
}
|
|
52346
52400
|
}
|
|
52347
52401
|
function validateSiteFooter(footer, path4, errors) {
|
|
52348
52402
|
validateClosedObject(footer, path4, errors, ["copyright_text", "attribution"]);
|
|
@@ -52353,10 +52407,7 @@ function validateSiteFooter(footer, path4, errors) {
|
|
|
52353
52407
|
validateNonEmptyString(footer.copyright_text, `${path4}.copyright_text`, "INVALID_SITE_FOOTER_COPYRIGHT_TEXT", errors);
|
|
52354
52408
|
}
|
|
52355
52409
|
if (footer.attribution !== void 0) {
|
|
52356
|
-
|
|
52357
|
-
if (isObject(footer.attribution) && footer.attribution.enabled !== void 0) {
|
|
52358
|
-
validateBoolean(footer.attribution.enabled, `${path4}.attribution.enabled`, "INVALID_SITE_FOOTER_ATTRIBUTION_ENABLED", errors);
|
|
52359
|
-
}
|
|
52410
|
+
validateBoolean(footer.attribution, `${path4}.attribution`, "INVALID_SITE_FOOTER_ATTRIBUTION", errors);
|
|
52360
52411
|
}
|
|
52361
52412
|
}
|
|
52362
52413
|
function validateMenus(menus, path4, errors) {
|
|
@@ -52382,7 +52433,7 @@ function validatePreviewMenu(menu, path4, errors) {
|
|
|
52382
52433
|
});
|
|
52383
52434
|
}
|
|
52384
52435
|
function validatePreviewMenuItem(item, path4, errors) {
|
|
52385
|
-
validateClosedObject(item, path4, errors, ["title", "url", "type", "target", "children"]);
|
|
52436
|
+
validateClosedObject(item, path4, errors, ["title", "url", "type", "target", "meta", "children"]);
|
|
52386
52437
|
if (!isObject(item)) {
|
|
52387
52438
|
return;
|
|
52388
52439
|
}
|
|
@@ -52390,6 +52441,7 @@ function validatePreviewMenuItem(item, path4, errors) {
|
|
|
52390
52441
|
validateUrlLike(item.url, `${path4}.url`, "INVALID_MENU_ITEM_URL", errors);
|
|
52391
52442
|
validateEnum(item.type, `${path4}.type`, "INVALID_MENU_ITEM_TYPE", errors, PREVIEW_MENU_ITEM_TYPES);
|
|
52392
52443
|
validateEnum(item.target, `${path4}.target`, "INVALID_MENU_ITEM_TARGET", errors, PREVIEW_MENU_TARGETS);
|
|
52444
|
+
validatePreviewMeta(item.meta, `${path4}.meta`, errors);
|
|
52393
52445
|
validateArray(item.children, `${path4}.children`, "INVALID_MENU_ITEM_CHILDREN", errors, (entry, index) => {
|
|
52394
52446
|
validatePreviewMenuItem(entry, `${path4}.children[${index}]`, errors);
|
|
52395
52447
|
});
|
|
@@ -52407,6 +52459,49 @@ function validateWidgets(widgets, path4, errors) {
|
|
|
52407
52459
|
validatePreviewWidgetArea(widgetArea, `${path4}.${widgetAreaId}`, errors);
|
|
52408
52460
|
}
|
|
52409
52461
|
}
|
|
52462
|
+
function validateCollections(collections, path4, errors) {
|
|
52463
|
+
validateObject(collections, path4, "INVALID_COLLECTIONS", errors);
|
|
52464
|
+
if (!isObject(collections)) {
|
|
52465
|
+
return;
|
|
52466
|
+
}
|
|
52467
|
+
for (const [collectionId, collection] of Object.entries(collections)) {
|
|
52468
|
+
if (!PREVIEW_COLLECTION_ID_PATTERN.test(collectionId)) {
|
|
52469
|
+
errors.push(issue("INVALID_COLLECTION_ID", `${path4}.${collectionId}`, "Collection ids must match ^[a-z][a-z0-9_-]{0,63}$"));
|
|
52470
|
+
}
|
|
52471
|
+
validatePreviewCollection(collection, `${path4}.${collectionId}`, errors);
|
|
52472
|
+
}
|
|
52473
|
+
}
|
|
52474
|
+
function validatePreviewCollection(collection, path4, errors) {
|
|
52475
|
+
validateClosedObject(collection, path4, errors, ["title", "description", "items"]);
|
|
52476
|
+
if (!isObject(collection)) {
|
|
52477
|
+
return;
|
|
52478
|
+
}
|
|
52479
|
+
if (collection.title !== void 0) {
|
|
52480
|
+
validateNonEmptyString(collection.title, `${path4}.title`, "INVALID_COLLECTION_TITLE", errors);
|
|
52481
|
+
}
|
|
52482
|
+
if (collection.description !== void 0) {
|
|
52483
|
+
validateString(collection.description, `${path4}.description`, "INVALID_COLLECTION_DESCRIPTION", errors);
|
|
52484
|
+
}
|
|
52485
|
+
const seenItems = /* @__PURE__ */ new Set();
|
|
52486
|
+
validateArray(collection.items, `${path4}.items`, "INVALID_COLLECTION_ITEMS", errors, (entry, index) => {
|
|
52487
|
+
validatePreviewCollectionItem(entry, `${path4}.items[${index}]`, errors, seenItems);
|
|
52488
|
+
});
|
|
52489
|
+
}
|
|
52490
|
+
function validatePreviewCollectionItem(item, path4, errors, seenItems) {
|
|
52491
|
+
validateClosedObject(item, path4, errors, ["type", "slug"]);
|
|
52492
|
+
if (!isObject(item)) {
|
|
52493
|
+
return;
|
|
52494
|
+
}
|
|
52495
|
+
validateEnum(item.type, `${path4}.type`, "INVALID_COLLECTION_ITEM_TYPE", errors, PREVIEW_COLLECTION_ITEM_TYPES);
|
|
52496
|
+
validateSlugSegment2(item.slug, `${path4}.slug`, "INVALID_COLLECTION_ITEM_SLUG", errors);
|
|
52497
|
+
if (typeof item.type === "string" && PREVIEW_COLLECTION_ITEM_TYPES.includes(item.type) && typeof item.slug === "string") {
|
|
52498
|
+
const key = `${item.type}:${item.slug}`;
|
|
52499
|
+
if (seenItems.has(key)) {
|
|
52500
|
+
errors.push(issue("DUPLICATE_COLLECTION_ITEM", `${path4}.slug`, "Duplicate collection item in the same collection"));
|
|
52501
|
+
}
|
|
52502
|
+
seenItems.add(key);
|
|
52503
|
+
}
|
|
52504
|
+
}
|
|
52410
52505
|
function validatePreviewWidgetArea(widgetArea, path4, errors) {
|
|
52411
52506
|
validateClosedObject(widgetArea, path4, errors, ["name", "items"]);
|
|
52412
52507
|
if (!isObject(widgetArea)) {
|
|
@@ -52498,6 +52593,46 @@ function validatePreviewAuthor(author, path4, errors) {
|
|
|
52498
52593
|
validateUrlLike(author.avatar, `${path4}.avatar`, "INVALID_AUTHOR_AVATAR", errors);
|
|
52499
52594
|
}
|
|
52500
52595
|
}
|
|
52596
|
+
function validateMediaArray(value, path4, errors) {
|
|
52597
|
+
const sources = /* @__PURE__ */ new Set();
|
|
52598
|
+
validateArray(value, path4, "INVALID_MEDIA", errors, (entry, index) => {
|
|
52599
|
+
validatePreviewMedia(entry, `${path4}[${index}]`, errors);
|
|
52600
|
+
if (!isObject(entry) || typeof entry.src !== "string") {
|
|
52601
|
+
return;
|
|
52602
|
+
}
|
|
52603
|
+
if (sources.has(entry.src)) {
|
|
52604
|
+
errors.push(issue("DUPLICATE_MEDIA_SRC", `${path4}[${index}].src`, "Media src values must be unique"));
|
|
52605
|
+
return;
|
|
52606
|
+
}
|
|
52607
|
+
sources.add(entry.src);
|
|
52608
|
+
});
|
|
52609
|
+
}
|
|
52610
|
+
function validateSiteFavicon(favicon, path4, errors) {
|
|
52611
|
+
validateClosedObject(favicon, path4, errors, ["icon", "svg", "png", "apple_touch_icon"]);
|
|
52612
|
+
if (!isObject(favicon)) {
|
|
52613
|
+
return;
|
|
52614
|
+
}
|
|
52615
|
+
if (favicon.icon === void 0 && favicon.svg === void 0 && favicon.png === void 0 && favicon.apple_touch_icon === void 0) {
|
|
52616
|
+
errors.push(issue("INVALID_SITE_FAVICON", path4, "site.favicon must include at least one favicon URL"));
|
|
52617
|
+
}
|
|
52618
|
+
for (const key of ["icon", "svg", "png", "apple_touch_icon"]) {
|
|
52619
|
+
if (favicon[key] !== void 0) {
|
|
52620
|
+
validateUrlLike(favicon[key], `${path4}.${key}`, "INVALID_SITE_FAVICON_URL", errors);
|
|
52621
|
+
}
|
|
52622
|
+
}
|
|
52623
|
+
}
|
|
52624
|
+
function validatePreviewMedia(media, path4, errors) {
|
|
52625
|
+
validateClosedObject(media, path4, errors, ["src", "width", "height", "alt"]);
|
|
52626
|
+
if (!isObject(media)) {
|
|
52627
|
+
return;
|
|
52628
|
+
}
|
|
52629
|
+
validateUrlLike(media.src, `${path4}.src`, "INVALID_MEDIA_SRC", errors);
|
|
52630
|
+
validateInteger(media.width, `${path4}.width`, "INVALID_MEDIA_WIDTH", errors, { minimum: 1 });
|
|
52631
|
+
validateInteger(media.height, `${path4}.height`, "INVALID_MEDIA_HEIGHT", errors, { minimum: 1 });
|
|
52632
|
+
if (media.alt !== void 0) {
|
|
52633
|
+
validateString(media.alt, `${path4}.alt`, "INVALID_MEDIA_ALT", errors);
|
|
52634
|
+
}
|
|
52635
|
+
}
|
|
52501
52636
|
function validatePreviewPost(post, path4, errors, authorIds) {
|
|
52502
52637
|
validateClosedObject(post, path4, errors, [
|
|
52503
52638
|
"id",
|
|
@@ -52512,7 +52647,9 @@ function validatePreviewPost(post, path4, errors, authorIds) {
|
|
|
52512
52647
|
"author_id",
|
|
52513
52648
|
"featured_image",
|
|
52514
52649
|
"meta",
|
|
52650
|
+
"data",
|
|
52515
52651
|
"status",
|
|
52652
|
+
"discoverability",
|
|
52516
52653
|
"allow_comments",
|
|
52517
52654
|
"category_slugs",
|
|
52518
52655
|
"tag_slugs"
|
|
@@ -52530,6 +52667,9 @@ function validatePreviewPost(post, path4, errors, authorIds) {
|
|
|
52530
52667
|
validateDateTimeString(post.updated_at_iso, `${path4}.updated_at_iso`, "INVALID_POST_UPDATED_AT_ISO", errors);
|
|
52531
52668
|
validateNonEmptyString(post.author_id, `${path4}.author_id`, "INVALID_POST_AUTHOR_ID", errors);
|
|
52532
52669
|
validateEnum(post.status, `${path4}.status`, "INVALID_POST_STATUS", errors, ["published", "draft"]);
|
|
52670
|
+
if (post.discoverability !== void 0) {
|
|
52671
|
+
validateEnum(post.discoverability, `${path4}.discoverability`, "INVALID_POST_DISCOVERABILITY", errors, PREVIEW_DISCOVERABILITY_VALUES);
|
|
52672
|
+
}
|
|
52533
52673
|
validateBoolean(post.allow_comments, `${path4}.allow_comments`, "INVALID_POST_ALLOW_COMMENTS", errors);
|
|
52534
52674
|
validateSlugArray(post.category_slugs, `${path4}.category_slugs`, "INVALID_POST_CATEGORY_SLUGS", errors);
|
|
52535
52675
|
validateSlugArray(post.tag_slugs, `${path4}.tag_slugs`, "INVALID_POST_TAG_SLUGS", errors);
|
|
@@ -52537,12 +52677,13 @@ function validatePreviewPost(post, path4, errors, authorIds) {
|
|
|
52537
52677
|
validateUrlLike(post.featured_image, `${path4}.featured_image`, "INVALID_POST_FEATURED_IMAGE", errors);
|
|
52538
52678
|
}
|
|
52539
52679
|
validatePreviewMeta(post.meta, `${path4}.meta`, errors);
|
|
52680
|
+
validatePreviewStructuredData(post.data, `${path4}.data`, errors);
|
|
52540
52681
|
if (typeof post.author_id === "string" && post.author_id.trim() !== "" && !authorIds.has(post.author_id)) {
|
|
52541
52682
|
errors.push(issue("INVALID_POST_AUTHOR_REFERENCE", `${path4}.author_id`, "Referenced author_id does not exist"));
|
|
52542
52683
|
}
|
|
52543
52684
|
}
|
|
52544
52685
|
function validatePreviewPage(page, path4, errors) {
|
|
52545
|
-
validateClosedObject(page, path4, errors, ["title", "slug", "path", "content", "document_type", "excerpt", "featured_image", "meta", "status"]);
|
|
52686
|
+
validateClosedObject(page, path4, errors, ["title", "slug", "path", "content", "document_type", "excerpt", "featured_image", "meta", "data", "status", "discoverability"]);
|
|
52546
52687
|
if (!isObject(page)) {
|
|
52547
52688
|
return;
|
|
52548
52689
|
}
|
|
@@ -52558,7 +52699,11 @@ function validatePreviewPage(page, path4, errors) {
|
|
|
52558
52699
|
validateUrlLike(page.featured_image, `${path4}.featured_image`, "INVALID_PAGE_FEATURED_IMAGE", errors);
|
|
52559
52700
|
}
|
|
52560
52701
|
validatePreviewMeta(page.meta, `${path4}.meta`, errors);
|
|
52702
|
+
validatePreviewStructuredData(page.data, `${path4}.data`, errors);
|
|
52561
52703
|
validateEnum(page.status, `${path4}.status`, "INVALID_PAGE_STATUS", errors, ["published", "draft"]);
|
|
52704
|
+
if (page.discoverability !== void 0) {
|
|
52705
|
+
validateEnum(page.discoverability, `${path4}.discoverability`, "INVALID_PAGE_DISCOVERABILITY", errors, PREVIEW_DISCOVERABILITY_VALUES);
|
|
52706
|
+
}
|
|
52562
52707
|
}
|
|
52563
52708
|
function validatePreviewMeta(meta, path4, errors) {
|
|
52564
52709
|
if (meta === void 0) {
|
|
@@ -52575,6 +52720,66 @@ function validatePreviewMeta(meta, path4, errors) {
|
|
|
52575
52720
|
errors.push(issue("INVALID_META_VALUE", `${path4}.${key}`, "meta values must be strings, numbers, booleans, or null"));
|
|
52576
52721
|
}
|
|
52577
52722
|
}
|
|
52723
|
+
function validatePreviewStructuredData(data, path4, errors) {
|
|
52724
|
+
if (data === void 0) {
|
|
52725
|
+
return;
|
|
52726
|
+
}
|
|
52727
|
+
if (!isObject(data)) {
|
|
52728
|
+
errors.push(issue("INVALID_DATA", path4, "data must be an object"));
|
|
52729
|
+
return;
|
|
52730
|
+
}
|
|
52731
|
+
validatePreviewDataObject(data, path4, errors, 0);
|
|
52732
|
+
}
|
|
52733
|
+
function validatePreviewDataValue(value, path4, errors, depth) {
|
|
52734
|
+
if (value === null || typeof value === "string" || typeof value === "boolean") {
|
|
52735
|
+
return;
|
|
52736
|
+
}
|
|
52737
|
+
if (typeof value === "number") {
|
|
52738
|
+
if (!Number.isFinite(value)) {
|
|
52739
|
+
errors.push(issue("INVALID_DATA_VALUE", path4, "data numbers must be finite"));
|
|
52740
|
+
}
|
|
52741
|
+
return;
|
|
52742
|
+
}
|
|
52743
|
+
if (Array.isArray(value)) {
|
|
52744
|
+
validatePreviewDataArray(value, path4, errors, depth);
|
|
52745
|
+
return;
|
|
52746
|
+
}
|
|
52747
|
+
if (isObject(value)) {
|
|
52748
|
+
validatePreviewDataObject(value, path4, errors, depth);
|
|
52749
|
+
return;
|
|
52750
|
+
}
|
|
52751
|
+
errors.push(issue("INVALID_DATA_VALUE", path4, "data values must be JSON-safe strings, numbers, booleans, null, arrays, or objects"));
|
|
52752
|
+
}
|
|
52753
|
+
function validatePreviewDataObject(object, path4, errors, depth) {
|
|
52754
|
+
if (depth > PREVIEW_DATA_MAX_DEPTH) {
|
|
52755
|
+
errors.push(issue("INVALID_DATA_DEPTH", path4, `data nesting must not exceed ${PREVIEW_DATA_MAX_DEPTH} container levels`));
|
|
52756
|
+
return;
|
|
52757
|
+
}
|
|
52758
|
+
const entries = Object.entries(object);
|
|
52759
|
+
if (entries.length > PREVIEW_DATA_MAX_KEYS) {
|
|
52760
|
+
errors.push(issue("INVALID_DATA_OBJECT_SIZE", path4, `data objects must not contain more than ${PREVIEW_DATA_MAX_KEYS} keys`));
|
|
52761
|
+
}
|
|
52762
|
+
for (const [key, value] of entries) {
|
|
52763
|
+
const childPath = `${path4}.${key}`;
|
|
52764
|
+
if (!PREVIEW_DATA_KEY_PATTERN.test(key)) {
|
|
52765
|
+
errors.push(issue("INVALID_DATA_KEY", childPath, "data keys must be valid template path segments"));
|
|
52766
|
+
continue;
|
|
52767
|
+
}
|
|
52768
|
+
validatePreviewDataValue(value, childPath, errors, depth + 1);
|
|
52769
|
+
}
|
|
52770
|
+
}
|
|
52771
|
+
function validatePreviewDataArray(array, path4, errors, depth) {
|
|
52772
|
+
if (depth > PREVIEW_DATA_MAX_DEPTH) {
|
|
52773
|
+
errors.push(issue("INVALID_DATA_DEPTH", path4, `data nesting must not exceed ${PREVIEW_DATA_MAX_DEPTH} container levels`));
|
|
52774
|
+
return;
|
|
52775
|
+
}
|
|
52776
|
+
if (array.length > PREVIEW_DATA_MAX_ARRAY_LENGTH) {
|
|
52777
|
+
errors.push(issue("INVALID_DATA_ARRAY_SIZE", path4, `data arrays must not contain more than ${PREVIEW_DATA_MAX_ARRAY_LENGTH} items`));
|
|
52778
|
+
}
|
|
52779
|
+
array.forEach((value, index) => {
|
|
52780
|
+
validatePreviewDataValue(value, `${path4}[${index}]`, errors, depth + 1);
|
|
52781
|
+
});
|
|
52782
|
+
}
|
|
52578
52783
|
function validatePermalinks(permalinks, path4, errors) {
|
|
52579
52784
|
if (permalinks === void 0) {
|
|
52580
52785
|
return;
|
|
@@ -52787,7 +52992,7 @@ function validateClosedObject(value, path4, errors, allowedKeys) {
|
|
|
52787
52992
|
return;
|
|
52788
52993
|
}
|
|
52789
52994
|
for (const key of Object.keys(value)) {
|
|
52790
|
-
if (!allowedKeys.includes(key)
|
|
52995
|
+
if (!allowedKeys.includes(key)) {
|
|
52791
52996
|
errors.push(issue("UNKNOWN_PROPERTY", path4 ? `${path4}.${key}` : key, "Unexpected property"));
|
|
52792
52997
|
}
|
|
52793
52998
|
}
|
|
@@ -52799,20 +53004,20 @@ function validateClosedObject(value, path4, errors, allowedKeys) {
|
|
|
52799
53004
|
}
|
|
52800
53005
|
function isOptionalKey(path4, key) {
|
|
52801
53006
|
if (path4 === "") {
|
|
52802
|
-
return key === "$schema" || key === "custom_css" || key === "custom_html";
|
|
53007
|
+
return key === "$schema" || key === "menus" || key === "widgets" || key === "collections" || key === "custom_css" || key === "custom_html";
|
|
52803
53008
|
}
|
|
52804
53009
|
if (path4 === "custom_html") {
|
|
52805
53010
|
return key === "head_end" || key === "body_end";
|
|
52806
53011
|
}
|
|
52807
53012
|
if (path4 === "site") {
|
|
52808
|
-
return key === "permalinks" || key === "front_page" || key === "post_index" || key === "footer";
|
|
53013
|
+
return key === "media_delivery_mode" || key === "favicon" || key === "expose_generator" || key === "indexing" || key === "permalinks" || key === "front_page" || key === "post_index" || key === "footer" || key === "meta";
|
|
53014
|
+
}
|
|
53015
|
+
if (path4 === "site.favicon") {
|
|
53016
|
+
return key === "icon" || key === "svg" || key === "png" || key === "apple_touch_icon";
|
|
52809
53017
|
}
|
|
52810
53018
|
if (path4 === "site.footer") {
|
|
52811
53019
|
return key === "copyright_text" || key === "attribution";
|
|
52812
53020
|
}
|
|
52813
|
-
if (path4 === "site.footer.attribution") {
|
|
52814
|
-
return key === "enabled";
|
|
52815
|
-
}
|
|
52816
53021
|
if (path4 === "site.front_page") {
|
|
52817
53022
|
return key === "page_slug" || key === "html";
|
|
52818
53023
|
}
|
|
@@ -52822,38 +53027,35 @@ function isOptionalKey(path4, key) {
|
|
|
52822
53027
|
if (path4 === "site.permalinks") {
|
|
52823
53028
|
return key === "output_style" || PREVIEW_PERMALINK_FIELDS.includes(key);
|
|
52824
53029
|
}
|
|
53030
|
+
if (path4 === "content") {
|
|
53031
|
+
return key === "media";
|
|
53032
|
+
}
|
|
52825
53033
|
if (path4.startsWith("content.authors[")) {
|
|
52826
53034
|
return key === "avatar";
|
|
52827
53035
|
}
|
|
53036
|
+
if (path4.startsWith("content.media[")) {
|
|
53037
|
+
return key === "alt";
|
|
53038
|
+
}
|
|
53039
|
+
if (path4.startsWith("menus.") && (path4.includes(".items[") || path4.includes(".children["))) {
|
|
53040
|
+
return key === "meta";
|
|
53041
|
+
}
|
|
52828
53042
|
if (path4.startsWith("widgets.") && path4.includes(".items[")) {
|
|
52829
53043
|
return key === "settings";
|
|
52830
53044
|
}
|
|
53045
|
+
if (path4.startsWith("collections.") && !path4.includes(".items[")) {
|
|
53046
|
+
return key === "title" || key === "description";
|
|
53047
|
+
}
|
|
52831
53048
|
if (path4.startsWith("content.posts[")) {
|
|
52832
|
-
return key === "id" || key === "featured_image" || key === "meta";
|
|
53049
|
+
return key === "id" || key === "featured_image" || key === "meta" || key === "data" || key === "discoverability";
|
|
52833
53050
|
}
|
|
52834
53051
|
if (path4.startsWith("content.pages[")) {
|
|
52835
|
-
return key === "path" || key === "excerpt" || key === "featured_image" || key === "meta";
|
|
53052
|
+
return key === "path" || key === "excerpt" || key === "featured_image" || key === "meta" || key === "data" || key === "discoverability";
|
|
52836
53053
|
}
|
|
52837
53054
|
if (path4.startsWith("content.categories[") || path4.startsWith("content.tags[")) {
|
|
52838
53055
|
return key === "description";
|
|
52839
53056
|
}
|
|
52840
53057
|
return false;
|
|
52841
53058
|
}
|
|
52842
|
-
function isSiteExtensionKey(path4, key) {
|
|
52843
|
-
if (path4 !== "site") {
|
|
52844
|
-
return false;
|
|
52845
|
-
}
|
|
52846
|
-
return ![
|
|
52847
|
-
"site_name",
|
|
52848
|
-
"site_description",
|
|
52849
|
-
"site_url",
|
|
52850
|
-
"metadata",
|
|
52851
|
-
"media_delivery_mode",
|
|
52852
|
-
"media_delivery_base_url",
|
|
52853
|
-
"site_timezone",
|
|
52854
|
-
"site_locale"
|
|
52855
|
-
].includes(key);
|
|
52856
|
-
}
|
|
52857
53059
|
function validateSlugArray(value, path4, code2, errors) {
|
|
52858
53060
|
if (!Array.isArray(value)) {
|
|
52859
53061
|
errors.push(issue(code2, path4, "Expected an array"));
|
|
@@ -52892,7 +53094,7 @@ function mapSlugValidationMessage(issueCode) {
|
|
|
52892
53094
|
function rejectLegacyKeys(value, path4, errors, keys, code2) {
|
|
52893
53095
|
for (const key of keys) {
|
|
52894
53096
|
if (key in value) {
|
|
52895
|
-
errors.push(issue(code2, `${path4}.${key}`, "Legacy field is not allowed in preview-data v0.
|
|
53097
|
+
errors.push(issue(code2, `${path4}.${key}`, "Legacy field is not allowed in preview-data v0.6"));
|
|
52896
53098
|
}
|
|
52897
53099
|
}
|
|
52898
53100
|
}
|
|
@@ -53002,9 +53204,46 @@ var PARTIAL_TAG_REGEX = /\{\{(partial:[^}]+)\}\}/g;
|
|
|
53002
53204
|
var TEMPLATE_PATH_SEGMENT_SOURCE = "[a-zA-Z_][a-zA-Z0-9_]*(?:-[a-zA-Z0-9_]+)*";
|
|
53003
53205
|
var TEMPLATE_PATH_REGEX = new RegExp(`^${TEMPLATE_PATH_SEGMENT_SOURCE}(?:\\.${TEMPLATE_PATH_SEGMENT_SOURCE})*$`);
|
|
53004
53206
|
var FOR_TAG_REGEX = new RegExp(`^#for ([a-zA-Z_][a-zA-Z0-9_]*) in (${TEMPLATE_PATH_SEGMENT_SOURCE}(?:\\.${TEMPLATE_PATH_SEGMENT_SOURCE})*)$`);
|
|
53005
|
-
var
|
|
53207
|
+
var NUMBER_LITERAL_REGEX = /^-?(?:0|[1-9]\d*)(?:\.\d+)?$/;
|
|
53208
|
+
var COMPARISON_BLOCK_TAGS = /* @__PURE__ */ new Set(["if_eq", "if_neq", "if_in", "if_starts_with"]);
|
|
53209
|
+
var COMPARISON_ELSE_IF_TAGS = /* @__PURE__ */ new Set(["else_if_eq", "else_if_neq", "else_if_in", "else_if_starts_with"]);
|
|
53210
|
+
var COMPARISON_TAG_OPERATORS = {
|
|
53211
|
+
if_eq: "eq",
|
|
53212
|
+
else_if_eq: "eq",
|
|
53213
|
+
if_neq: "neq",
|
|
53214
|
+
else_if_neq: "neq",
|
|
53215
|
+
if_in: "in",
|
|
53216
|
+
else_if_in: "in",
|
|
53217
|
+
if_starts_with: "starts_with",
|
|
53218
|
+
else_if_starts_with: "starts_with"
|
|
53219
|
+
};
|
|
53220
|
+
var PARTIAL_ARG_ROOT_PATHS = /* @__PURE__ */ new Set([
|
|
53221
|
+
"archive",
|
|
53222
|
+
"author",
|
|
53223
|
+
"category",
|
|
53224
|
+
"collection",
|
|
53225
|
+
"collections",
|
|
53226
|
+
"currentUrl",
|
|
53227
|
+
"language",
|
|
53228
|
+
"menu",
|
|
53229
|
+
"menus",
|
|
53230
|
+
"meta",
|
|
53231
|
+
"page",
|
|
53232
|
+
"pagination",
|
|
53233
|
+
"partial",
|
|
53234
|
+
"post",
|
|
53235
|
+
"posts",
|
|
53236
|
+
"route",
|
|
53237
|
+
"site",
|
|
53238
|
+
"tag",
|
|
53239
|
+
"taxonomies",
|
|
53240
|
+
"taxonomy",
|
|
53241
|
+
"widget",
|
|
53242
|
+
"widgets"
|
|
53243
|
+
]);
|
|
53006
53244
|
var PARTIAL_ARG_KEY_REGEX = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
|
|
53007
53245
|
var SEMVER_REGEX = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/;
|
|
53246
|
+
var LICENSE_REF_REGEX = /^LicenseRef-[A-Za-z0-9][A-Za-z0-9.-]*$/;
|
|
53008
53247
|
var NAMESPACE_REGEX = /^[a-z0-9]+(-[a-z0-9]+)*$/;
|
|
53009
53248
|
var SLUG_REGEX = /^[a-z0-9]+(-[a-z0-9]+)*$/;
|
|
53010
53249
|
var ALLOWED_LICENSES = [
|
|
@@ -53015,7 +53254,10 @@ var ALLOWED_LICENSES = [
|
|
|
53015
53254
|
"GPL-3.0-or-later"
|
|
53016
53255
|
];
|
|
53017
53256
|
var LICENSES = new Set(ALLOWED_LICENSES);
|
|
53018
|
-
var
|
|
53257
|
+
var THEME_LINK_KEYS = /* @__PURE__ */ new Set(["homepage", "repository", "documentation", "support", "marketplace", "license"]);
|
|
53258
|
+
var THEME_LINK_PROTOCOLS = /* @__PURE__ */ new Set(["http:", "https:", "mailto:"]);
|
|
53259
|
+
var DEFAULT_RUNTIME = "0.6";
|
|
53260
|
+
var THEME_RUNTIME_V0_6 = DEFAULT_RUNTIME;
|
|
53019
53261
|
var SUPPORTED_RUNTIMES = [DEFAULT_RUNTIME];
|
|
53020
53262
|
var SUPPORTED_RUNTIME_SET = new Set(SUPPORTED_RUNTIMES);
|
|
53021
53263
|
var NAMESPACE_MIN_LENGTH = 3;
|
|
@@ -53030,7 +53272,29 @@ var MENU_SLOT_ID_MAX_LENGTH = 32;
|
|
|
53030
53272
|
var MENU_SLOT_COUNT_MAX = 12;
|
|
53031
53273
|
var MENU_SLOT_TITLE_MAX_LENGTH = 80;
|
|
53032
53274
|
var MENU_SLOT_DESCRIPTION_MAX_LENGTH = 160;
|
|
53033
|
-
var SUPPORTED_THEME_FEATURES = /* @__PURE__ */ new Set(["comments", "newsletter", "
|
|
53275
|
+
var SUPPORTED_THEME_FEATURES = /* @__PURE__ */ new Set(["comments", "newsletter", "post_index"]);
|
|
53276
|
+
var THEME_MANIFEST_KEYS = /* @__PURE__ */ new Set([
|
|
53277
|
+
"$schema",
|
|
53278
|
+
"name",
|
|
53279
|
+
"namespace",
|
|
53280
|
+
"slug",
|
|
53281
|
+
"version",
|
|
53282
|
+
"license",
|
|
53283
|
+
"runtime",
|
|
53284
|
+
"author",
|
|
53285
|
+
"description",
|
|
53286
|
+
"thumbnail",
|
|
53287
|
+
"links",
|
|
53288
|
+
"features",
|
|
53289
|
+
"menu_slots",
|
|
53290
|
+
"widget_areas",
|
|
53291
|
+
"site_meta",
|
|
53292
|
+
"collection_slots"
|
|
53293
|
+
]);
|
|
53294
|
+
var SITE_META_KEY_REGEX = /^[a-z][a-z0-9_]*(?:-[a-z0-9_]+)*$/;
|
|
53295
|
+
var SITE_META_KEY_MAX_LENGTH = 64;
|
|
53296
|
+
var SITE_META_COUNT_MAX = 32;
|
|
53297
|
+
var SITE_META_TYPES = /* @__PURE__ */ new Set(["string", "number", "boolean"]);
|
|
53034
53298
|
function validateFeatureFlags(rawValue, errors) {
|
|
53035
53299
|
if (rawValue === void 0) {
|
|
53036
53300
|
return void 0;
|
|
@@ -53051,7 +53315,11 @@ function validateFeatureFlags(rawValue, errors) {
|
|
|
53051
53315
|
"INVALID_THEME_FEATURE",
|
|
53052
53316
|
`theme.json.features.${featureName}`,
|
|
53053
53317
|
`Unknown theme feature '${featureName}'`,
|
|
53054
|
-
"error"
|
|
53318
|
+
"error",
|
|
53319
|
+
{
|
|
53320
|
+
category: "theme_manifest",
|
|
53321
|
+
hint: themeFeatureHint(featureName)
|
|
53322
|
+
}
|
|
53055
53323
|
));
|
|
53056
53324
|
continue;
|
|
53057
53325
|
}
|
|
@@ -53068,6 +53336,80 @@ function validateFeatureFlags(rawValue, errors) {
|
|
|
53068
53336
|
}
|
|
53069
53337
|
return Object.keys(normalizedFeatures).length > 0 ? normalizedFeatures : void 0;
|
|
53070
53338
|
}
|
|
53339
|
+
function themeFeatureHint(featureName) {
|
|
53340
|
+
const hints = {
|
|
53341
|
+
postIndex: "ZeroPress runtime v0.6 uses snake_case keys. Use 'post_index' instead of 'postIndex'."
|
|
53342
|
+
};
|
|
53343
|
+
return hints[featureName] || "";
|
|
53344
|
+
}
|
|
53345
|
+
function themeManifestFieldHint(fieldName) {
|
|
53346
|
+
const hints = {
|
|
53347
|
+
menuSlots: "ZeroPress runtime v0.6 uses snake_case keys. Use 'menu_slots' instead of 'menuSlots'.",
|
|
53348
|
+
widgetAreas: "ZeroPress runtime v0.6 uses snake_case keys. Use 'widget_areas' instead of 'widgetAreas'.",
|
|
53349
|
+
siteMeta: "ZeroPress runtime v0.6 uses snake_case keys. Use 'site_meta' instead of 'siteMeta'.",
|
|
53350
|
+
collectionSlots: "ZeroPress runtime v0.6 uses snake_case keys. Use 'collection_slots' instead of 'collectionSlots'.",
|
|
53351
|
+
settings: "theme.json.settings was removed in runtime v0.6. Use preview-data site.meta and theme.json site_meta hints for site-level values."
|
|
53352
|
+
};
|
|
53353
|
+
return hints[fieldName] || "";
|
|
53354
|
+
}
|
|
53355
|
+
function isAllowedLicense(value) {
|
|
53356
|
+
return LICENSES.has(value) || LICENSE_REF_REGEX.test(value);
|
|
53357
|
+
}
|
|
53358
|
+
function isValidThemeLinkUrl(value) {
|
|
53359
|
+
try {
|
|
53360
|
+
const parsed = new URL(value);
|
|
53361
|
+
return THEME_LINK_PROTOCOLS.has(parsed.protocol);
|
|
53362
|
+
} catch {
|
|
53363
|
+
return false;
|
|
53364
|
+
}
|
|
53365
|
+
}
|
|
53366
|
+
function validateThemeLinks(rawValue, errors) {
|
|
53367
|
+
if (rawValue === void 0) {
|
|
53368
|
+
return void 0;
|
|
53369
|
+
}
|
|
53370
|
+
if (!rawValue || typeof rawValue !== "object" || Array.isArray(rawValue)) {
|
|
53371
|
+
errors.push(issue2(
|
|
53372
|
+
"INVALID_LINKS",
|
|
53373
|
+
"theme.json.links",
|
|
53374
|
+
"theme.json field 'links' must be an object when present",
|
|
53375
|
+
"error"
|
|
53376
|
+
));
|
|
53377
|
+
return void 0;
|
|
53378
|
+
}
|
|
53379
|
+
const normalizedLinks = {};
|
|
53380
|
+
for (const [linkKey, value] of Object.entries(rawValue)) {
|
|
53381
|
+
if (!THEME_LINK_KEYS.has(linkKey)) {
|
|
53382
|
+
errors.push(issue2(
|
|
53383
|
+
"INVALID_THEME_LINK",
|
|
53384
|
+
`theme.json.links.${linkKey}`,
|
|
53385
|
+
`Unknown theme link '${linkKey}'`,
|
|
53386
|
+
"error"
|
|
53387
|
+
));
|
|
53388
|
+
continue;
|
|
53389
|
+
}
|
|
53390
|
+
if (typeof value !== "string" || value.trim() === "") {
|
|
53391
|
+
errors.push(issue2(
|
|
53392
|
+
"INVALID_THEME_LINK_VALUE",
|
|
53393
|
+
`theme.json.links.${linkKey}`,
|
|
53394
|
+
`theme link '${linkKey}' must be a non-empty URL string`,
|
|
53395
|
+
"error"
|
|
53396
|
+
));
|
|
53397
|
+
continue;
|
|
53398
|
+
}
|
|
53399
|
+
const normalizedValue = value.trim();
|
|
53400
|
+
if (!isValidThemeLinkUrl(normalizedValue)) {
|
|
53401
|
+
errors.push(issue2(
|
|
53402
|
+
"INVALID_THEME_LINK_VALUE",
|
|
53403
|
+
`theme.json.links.${linkKey}`,
|
|
53404
|
+
`theme link '${linkKey}' must be an absolute http, https, or mailto URL`,
|
|
53405
|
+
"error"
|
|
53406
|
+
));
|
|
53407
|
+
continue;
|
|
53408
|
+
}
|
|
53409
|
+
normalizedLinks[linkKey] = normalizedValue;
|
|
53410
|
+
}
|
|
53411
|
+
return Object.keys(normalizedLinks).length > 0 ? normalizedLinks : void 0;
|
|
53412
|
+
}
|
|
53071
53413
|
function validateHelperMetadataMap(rawValue, fieldName, issueCodes, errors) {
|
|
53072
53414
|
if (rawValue === void 0) {
|
|
53073
53415
|
return void 0;
|
|
@@ -53161,6 +53503,127 @@ function validateHelperMetadataMap(rawValue, fieldName, issueCodes, errors) {
|
|
|
53161
53503
|
}
|
|
53162
53504
|
return Object.keys(normalizedItems).length > 0 ? normalizedItems : void 0;
|
|
53163
53505
|
}
|
|
53506
|
+
function validateSiteMetaMap(rawValue, errors) {
|
|
53507
|
+
if (rawValue === void 0) {
|
|
53508
|
+
return void 0;
|
|
53509
|
+
}
|
|
53510
|
+
if (!rawValue || typeof rawValue !== "object" || Array.isArray(rawValue)) {
|
|
53511
|
+
errors.push(issue2(
|
|
53512
|
+
"INVALID_SITE_META",
|
|
53513
|
+
"theme.json",
|
|
53514
|
+
"theme.json field 'site_meta' must be an object when present",
|
|
53515
|
+
"error"
|
|
53516
|
+
));
|
|
53517
|
+
return void 0;
|
|
53518
|
+
}
|
|
53519
|
+
const entries = Object.entries(rawValue);
|
|
53520
|
+
if (entries.length === 0) {
|
|
53521
|
+
errors.push(issue2(
|
|
53522
|
+
"INVALID_SITE_META",
|
|
53523
|
+
"theme.json",
|
|
53524
|
+
"theme.json field 'site_meta' must not be empty",
|
|
53525
|
+
"error"
|
|
53526
|
+
));
|
|
53527
|
+
}
|
|
53528
|
+
if (entries.length > SITE_META_COUNT_MAX) {
|
|
53529
|
+
errors.push(issue2(
|
|
53530
|
+
"INVALID_SITE_META",
|
|
53531
|
+
"theme.json",
|
|
53532
|
+
`theme.json field 'site_meta' must contain at most ${SITE_META_COUNT_MAX} keys`,
|
|
53533
|
+
"error"
|
|
53534
|
+
));
|
|
53535
|
+
}
|
|
53536
|
+
const normalizedItems = {};
|
|
53537
|
+
for (const [metaKey, value] of entries) {
|
|
53538
|
+
if (!SITE_META_KEY_REGEX.test(metaKey) || metaKey.length > SITE_META_KEY_MAX_LENGTH) {
|
|
53539
|
+
errors.push(issue2(
|
|
53540
|
+
"INVALID_SITE_META_KEY",
|
|
53541
|
+
`theme.json.site_meta.${metaKey}`,
|
|
53542
|
+
`site_meta key '${metaKey}' must start with a lowercase letter and use lowercase letters, digits, underscores, or internal hyphens only`,
|
|
53543
|
+
"error"
|
|
53544
|
+
));
|
|
53545
|
+
continue;
|
|
53546
|
+
}
|
|
53547
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
53548
|
+
errors.push(issue2(
|
|
53549
|
+
"INVALID_SITE_META_FIELD",
|
|
53550
|
+
`theme.json.site_meta.${metaKey}`,
|
|
53551
|
+
`site_meta key '${metaKey}' must be an object`,
|
|
53552
|
+
"error"
|
|
53553
|
+
));
|
|
53554
|
+
continue;
|
|
53555
|
+
}
|
|
53556
|
+
const allowedKeys = /* @__PURE__ */ new Set(["title", "description", "type", "default"]);
|
|
53557
|
+
for (const key of Object.keys(value)) {
|
|
53558
|
+
if (!allowedKeys.has(key)) {
|
|
53559
|
+
errors.push(issue2(
|
|
53560
|
+
"INVALID_SITE_META_PROPERTY",
|
|
53561
|
+
`theme.json.site_meta.${metaKey}.${key}`,
|
|
53562
|
+
`Unknown site_meta property '${key}' in key '${metaKey}'`,
|
|
53563
|
+
"error"
|
|
53564
|
+
));
|
|
53565
|
+
}
|
|
53566
|
+
}
|
|
53567
|
+
if (typeof value.title !== "string" || value.title.trim() === "") {
|
|
53568
|
+
errors.push(issue2(
|
|
53569
|
+
"INVALID_SITE_META_TITLE",
|
|
53570
|
+
`theme.json.site_meta.${metaKey}.title`,
|
|
53571
|
+
`site_meta key '${metaKey}' must define a non-empty 'title'`,
|
|
53572
|
+
"error"
|
|
53573
|
+
));
|
|
53574
|
+
} else if (value.title.trim().length > MENU_SLOT_TITLE_MAX_LENGTH) {
|
|
53575
|
+
errors.push(issue2(
|
|
53576
|
+
"INVALID_SITE_META_TITLE",
|
|
53577
|
+
`theme.json.site_meta.${metaKey}.title`,
|
|
53578
|
+
`site_meta key '${metaKey}' title must be at most ${MENU_SLOT_TITLE_MAX_LENGTH} characters`,
|
|
53579
|
+
"error"
|
|
53580
|
+
));
|
|
53581
|
+
}
|
|
53582
|
+
if (value.description !== void 0 && (typeof value.description !== "string" || value.description.trim().length > MENU_SLOT_DESCRIPTION_MAX_LENGTH)) {
|
|
53583
|
+
errors.push(issue2(
|
|
53584
|
+
"INVALID_SITE_META_DESCRIPTION",
|
|
53585
|
+
`theme.json.site_meta.${metaKey}.description`,
|
|
53586
|
+
`site_meta key '${metaKey}' description must be a string at most ${MENU_SLOT_DESCRIPTION_MAX_LENGTH} characters`,
|
|
53587
|
+
"error"
|
|
53588
|
+
));
|
|
53589
|
+
}
|
|
53590
|
+
if (value.type !== void 0 && !SITE_META_TYPES.has(value.type)) {
|
|
53591
|
+
errors.push(issue2(
|
|
53592
|
+
"INVALID_SITE_META_TYPE",
|
|
53593
|
+
`theme.json.site_meta.${metaKey}.type`,
|
|
53594
|
+
`site_meta key '${metaKey}' type must be one of: string, number, boolean`,
|
|
53595
|
+
"error"
|
|
53596
|
+
));
|
|
53597
|
+
}
|
|
53598
|
+
if (value.default !== void 0) {
|
|
53599
|
+
const defaultType = typeof value.default;
|
|
53600
|
+
if (value.default !== null && defaultType !== "string" && defaultType !== "number" && defaultType !== "boolean") {
|
|
53601
|
+
errors.push(issue2(
|
|
53602
|
+
"INVALID_SITE_META_DEFAULT",
|
|
53603
|
+
`theme.json.site_meta.${metaKey}.default`,
|
|
53604
|
+
`site_meta key '${metaKey}' default must be a string, number, boolean, or null`,
|
|
53605
|
+
"error"
|
|
53606
|
+
));
|
|
53607
|
+
} else if (typeof value.type === "string" && SITE_META_TYPES.has(value.type) && value.default !== null && defaultType !== value.type) {
|
|
53608
|
+
errors.push(issue2(
|
|
53609
|
+
"INVALID_SITE_META_DEFAULT",
|
|
53610
|
+
`theme.json.site_meta.${metaKey}.default`,
|
|
53611
|
+
`site_meta key '${metaKey}' default must match its declared type`,
|
|
53612
|
+
"error"
|
|
53613
|
+
));
|
|
53614
|
+
}
|
|
53615
|
+
}
|
|
53616
|
+
if (typeof value.title === "string" && value.title.trim() !== "" && value.title.trim().length <= MENU_SLOT_TITLE_MAX_LENGTH && (value.description === void 0 || typeof value.description === "string" && value.description.trim().length <= MENU_SLOT_DESCRIPTION_MAX_LENGTH) && (value.type === void 0 || SITE_META_TYPES.has(value.type)) && (value.default === void 0 || value.default === null || typeof value.default === "string" || typeof value.default === "number" || typeof value.default === "boolean")) {
|
|
53617
|
+
normalizedItems[metaKey] = {
|
|
53618
|
+
title: value.title.trim(),
|
|
53619
|
+
...typeof value.description === "string" && value.description.trim() !== "" ? { description: value.description.trim() } : {},
|
|
53620
|
+
...typeof value.type === "string" && SITE_META_TYPES.has(value.type) ? { type: value.type } : {},
|
|
53621
|
+
...value.default !== void 0 ? { default: value.default } : {}
|
|
53622
|
+
};
|
|
53623
|
+
}
|
|
53624
|
+
}
|
|
53625
|
+
return Object.keys(normalizedItems).length > 0 ? normalizedItems : void 0;
|
|
53626
|
+
}
|
|
53164
53627
|
async function validateThemeFiles(fileMap, options2 = {}) {
|
|
53165
53628
|
const files = normalizeFileMap(fileMap);
|
|
53166
53629
|
const errors = [];
|
|
@@ -53190,11 +53653,16 @@ async function validateThemeFiles(fileMap, options2 = {}) {
|
|
|
53190
53653
|
manifest = manifestResult.manifest;
|
|
53191
53654
|
errors.push(...manifestResult.errors);
|
|
53192
53655
|
} catch (error) {
|
|
53656
|
+
const rawThemeJson = getText(files.get("theme.json"));
|
|
53193
53657
|
errors.push(issue2(
|
|
53194
53658
|
"INVALID_THEME_JSON",
|
|
53195
53659
|
"theme.json",
|
|
53196
53660
|
`Invalid theme.json: ${error instanceof Error ? error.message : String(error)}`,
|
|
53197
|
-
"error"
|
|
53661
|
+
"error",
|
|
53662
|
+
{
|
|
53663
|
+
...locationForJsonParseError(error, rawThemeJson),
|
|
53664
|
+
category: "json_syntax"
|
|
53665
|
+
}
|
|
53198
53666
|
));
|
|
53199
53667
|
}
|
|
53200
53668
|
}
|
|
@@ -53254,6 +53722,20 @@ function validateManifest(themeJson) {
|
|
|
53254
53722
|
license: "",
|
|
53255
53723
|
runtime: ""
|
|
53256
53724
|
};
|
|
53725
|
+
for (const key of Object.keys(themeJson)) {
|
|
53726
|
+
if (!THEME_MANIFEST_KEYS.has(key)) {
|
|
53727
|
+
errors.push(issue2(
|
|
53728
|
+
"UNKNOWN_THEME_MANIFEST_FIELD",
|
|
53729
|
+
`theme.json.${key}`,
|
|
53730
|
+
`Unknown theme.json field '${key}'`,
|
|
53731
|
+
"error",
|
|
53732
|
+
{
|
|
53733
|
+
category: "theme_manifest",
|
|
53734
|
+
hint: themeManifestFieldHint(key)
|
|
53735
|
+
}
|
|
53736
|
+
));
|
|
53737
|
+
}
|
|
53738
|
+
}
|
|
53257
53739
|
if (themeJson.$schema !== void 0 && typeof themeJson.$schema !== "string") {
|
|
53258
53740
|
errors.push(issue2(
|
|
53259
53741
|
"INVALID_SCHEMA_HINT",
|
|
@@ -53281,13 +53763,24 @@ function validateManifest(themeJson) {
|
|
|
53281
53763
|
errors.push(issue2("INVALID_SEMVER", "theme.json", "Theme version must follow semantic versioning (e.g. 1.0.0)", "error"));
|
|
53282
53764
|
}
|
|
53283
53765
|
if (typeof themeJson.runtime === "string" && !SUPPORTED_RUNTIME_SET.has(themeJson.runtime.trim())) {
|
|
53284
|
-
errors.push(issue2(
|
|
53766
|
+
errors.push(issue2(
|
|
53767
|
+
"INVALID_RUNTIME_VERSION",
|
|
53768
|
+
"theme.json",
|
|
53769
|
+
`theme.json field 'runtime' must be one of: ${SUPPORTED_RUNTIMES.join(", ")}`,
|
|
53770
|
+
"error",
|
|
53771
|
+
{
|
|
53772
|
+
category: "theme_manifest",
|
|
53773
|
+
hint: `Update theme.json:
|
|
53774
|
+
|
|
53775
|
+
"runtime": "${THEME_RUNTIME_V0_6}"`
|
|
53776
|
+
}
|
|
53777
|
+
));
|
|
53285
53778
|
}
|
|
53286
|
-
if (typeof themeJson.license === "string" && !
|
|
53779
|
+
if (typeof themeJson.license === "string" && !isAllowedLicense(themeJson.license.trim())) {
|
|
53287
53780
|
errors.push(issue2(
|
|
53288
53781
|
"INVALID_LICENSE",
|
|
53289
53782
|
"theme.json",
|
|
53290
|
-
"theme.json field 'license' must be one of: MIT, Apache-2.0, BSD-3-Clause, GPL-3.0-only, GPL-3.0-or-later",
|
|
53783
|
+
"theme.json field 'license' must be one of: MIT, Apache-2.0, BSD-3-Clause, GPL-3.0-only, GPL-3.0-or-later, or a LicenseRef-* identifier",
|
|
53291
53784
|
"error"
|
|
53292
53785
|
));
|
|
53293
53786
|
}
|
|
@@ -53339,11 +53832,27 @@ function validateManifest(themeJson) {
|
|
|
53339
53832
|
manifest.description = description;
|
|
53340
53833
|
}
|
|
53341
53834
|
}
|
|
53835
|
+
if (themeJson.thumbnail !== void 0) {
|
|
53836
|
+
if (typeof themeJson.thumbnail !== "string") {
|
|
53837
|
+
errors.push(issue2(
|
|
53838
|
+
"INVALID_THUMBNAIL",
|
|
53839
|
+
"theme.json.thumbnail",
|
|
53840
|
+
"theme.json field 'thumbnail' must be a string when present",
|
|
53841
|
+
"error"
|
|
53842
|
+
));
|
|
53843
|
+
} else {
|
|
53844
|
+
manifest.thumbnail = themeJson.thumbnail;
|
|
53845
|
+
}
|
|
53846
|
+
}
|
|
53847
|
+
const links = validateThemeLinks(themeJson.links, errors);
|
|
53848
|
+
if (links) {
|
|
53849
|
+
manifest.links = links;
|
|
53850
|
+
}
|
|
53342
53851
|
const features = validateFeatureFlags(themeJson.features, errors);
|
|
53343
53852
|
if (features) {
|
|
53344
53853
|
manifest.features = features;
|
|
53345
53854
|
}
|
|
53346
|
-
const
|
|
53855
|
+
const menu_slots = validateHelperMetadataMap(themeJson.menu_slots, "menu_slots", {
|
|
53347
53856
|
itemLabel: "Menu slot",
|
|
53348
53857
|
propertyLabel: "menu slot property",
|
|
53349
53858
|
collectionLabel: "slots",
|
|
@@ -53354,10 +53863,10 @@ function validateManifest(themeJson) {
|
|
|
53354
53863
|
invalidTitleCode: "INVALID_MENU_SLOT_TITLE",
|
|
53355
53864
|
invalidDescriptionCode: "INVALID_MENU_SLOT_DESCRIPTION"
|
|
53356
53865
|
}, errors);
|
|
53357
|
-
if (
|
|
53358
|
-
manifest.
|
|
53866
|
+
if (menu_slots) {
|
|
53867
|
+
manifest.menu_slots = menu_slots;
|
|
53359
53868
|
}
|
|
53360
|
-
const
|
|
53869
|
+
const widget_areas = validateHelperMetadataMap(themeJson.widget_areas, "widget_areas", {
|
|
53361
53870
|
itemLabel: "Widget area",
|
|
53362
53871
|
propertyLabel: "widget area property",
|
|
53363
53872
|
collectionLabel: "areas",
|
|
@@ -53368,8 +53877,26 @@ function validateManifest(themeJson) {
|
|
|
53368
53877
|
invalidTitleCode: "INVALID_WIDGET_AREA_TITLE",
|
|
53369
53878
|
invalidDescriptionCode: "INVALID_WIDGET_AREA_DESCRIPTION"
|
|
53370
53879
|
}, errors);
|
|
53371
|
-
if (
|
|
53372
|
-
manifest.
|
|
53880
|
+
if (widget_areas) {
|
|
53881
|
+
manifest.widget_areas = widget_areas;
|
|
53882
|
+
}
|
|
53883
|
+
const site_meta = validateSiteMetaMap(themeJson.site_meta, errors);
|
|
53884
|
+
if (site_meta) {
|
|
53885
|
+
manifest.site_meta = site_meta;
|
|
53886
|
+
}
|
|
53887
|
+
const collection_slots = validateHelperMetadataMap(themeJson.collection_slots, "collection_slots", {
|
|
53888
|
+
itemLabel: "Collection slot",
|
|
53889
|
+
propertyLabel: "collection slot property",
|
|
53890
|
+
collectionLabel: "slots",
|
|
53891
|
+
invalidCollectionCode: "INVALID_COLLECTION_SLOTS",
|
|
53892
|
+
invalidIdCode: "INVALID_COLLECTION_SLOT_ID",
|
|
53893
|
+
invalidItemCode: "INVALID_COLLECTION_SLOT",
|
|
53894
|
+
invalidPropertyCode: "INVALID_COLLECTION_SLOT_PROPERTY",
|
|
53895
|
+
invalidTitleCode: "INVALID_COLLECTION_SLOT_TITLE",
|
|
53896
|
+
invalidDescriptionCode: "INVALID_COLLECTION_SLOT_DESCRIPTION"
|
|
53897
|
+
}, errors);
|
|
53898
|
+
if (collection_slots) {
|
|
53899
|
+
manifest.collection_slots = collection_slots;
|
|
53373
53900
|
}
|
|
53374
53901
|
return { errors, manifest: errors.length > 0 ? void 0 : manifest };
|
|
53375
53902
|
}
|
|
@@ -53381,8 +53908,20 @@ function validateTemplateSyntax(templatePath, content, context) {
|
|
|
53381
53908
|
if (contentSlotMatches.length !== 1) {
|
|
53382
53909
|
errors.push(issue2("INVALID_LAYOUT_SLOT", "layout.html", "layout.html must contain exactly one {{slot:content}}", "error"));
|
|
53383
53910
|
}
|
|
53384
|
-
|
|
53385
|
-
|
|
53911
|
+
const scriptMatch = /<script\b/i.exec(content);
|
|
53912
|
+
if (scriptMatch) {
|
|
53913
|
+
errors.push(issue2(
|
|
53914
|
+
"LAYOUT_SCRIPT_NOT_ALLOWED",
|
|
53915
|
+
"layout.html",
|
|
53916
|
+
"layout.html must not contain <script> tags",
|
|
53917
|
+
"error",
|
|
53918
|
+
{
|
|
53919
|
+
...locationForIndex(content, scriptMatch.index),
|
|
53920
|
+
category: "theme_validation",
|
|
53921
|
+
hint: "Move shared scripts into a partial such as {{partial:content-enhancements}}, then include that partial from layout.html.",
|
|
53922
|
+
snippet: snippetForIndex(content, scriptMatch.index)
|
|
53923
|
+
}
|
|
53924
|
+
));
|
|
53386
53925
|
}
|
|
53387
53926
|
}
|
|
53388
53927
|
let match2;
|
|
@@ -53433,7 +53972,9 @@ function validateRuntimeV05TemplateSyntax(templatePath, content, errors) {
|
|
|
53433
53972
|
index = end + 2;
|
|
53434
53973
|
if (token.startsWith("partial:")) {
|
|
53435
53974
|
try {
|
|
53436
|
-
parsePartialReferenceToken(token
|
|
53975
|
+
parsePartialReferenceToken(token, {
|
|
53976
|
+
allowedSingleSegmentPaths: getPartialArgScope(stack)
|
|
53977
|
+
});
|
|
53437
53978
|
} catch (error) {
|
|
53438
53979
|
errors.push(issue2(
|
|
53439
53980
|
"INVALID_PARTIAL_REFERENCE",
|
|
@@ -53458,7 +53999,7 @@ function validateRuntimeV05TemplateSyntax(templatePath, content, errors) {
|
|
|
53458
53999
|
}
|
|
53459
54000
|
if (token === "#else") {
|
|
53460
54001
|
const current = stack[stack.length - 1];
|
|
53461
|
-
if (!current || current.tag !== "if" && current.tag
|
|
54002
|
+
if (!current || current.tag !== "if" && !COMPARISON_BLOCK_TAGS.has(current.tag)) {
|
|
53462
54003
|
errors.push(issue2("UNEXPECTED_TEMPLATE_ELSE", templatePath, `Unexpected {{#else}} in ${templatePath}`, "error"));
|
|
53463
54004
|
return;
|
|
53464
54005
|
}
|
|
@@ -53469,9 +54010,11 @@ function validateRuntimeV05TemplateSyntax(templatePath, content, errors) {
|
|
|
53469
54010
|
current.hasElse = true;
|
|
53470
54011
|
continue;
|
|
53471
54012
|
}
|
|
53472
|
-
|
|
54013
|
+
const comparisonElseIfTag = getComparisonElseIfTag(token);
|
|
54014
|
+
if (comparisonElseIfTag) {
|
|
53473
54015
|
const current = stack[stack.length - 1];
|
|
53474
|
-
|
|
54016
|
+
const expectedBlockTag = comparisonElseIfTag.replace(/^else_/, "");
|
|
54017
|
+
if (!current || current.tag !== expectedBlockTag) {
|
|
53475
54018
|
errors.push(issue2("UNEXPECTED_TEMPLATE_ELSE_IF", templatePath, `Unexpected {{${token}}} in ${templatePath}`, "error"));
|
|
53476
54019
|
return;
|
|
53477
54020
|
}
|
|
@@ -53479,13 +54022,13 @@ function validateRuntimeV05TemplateSyntax(templatePath, content, errors) {
|
|
|
53479
54022
|
errors.push(issue2("INVALID_TEMPLATE_BRANCH_ORDER", templatePath, `{{${token}}} cannot appear after {{#else}} in ${templatePath}`, "error"));
|
|
53480
54023
|
return;
|
|
53481
54024
|
}
|
|
53482
|
-
const expression = token.slice(
|
|
53483
|
-
const parsed =
|
|
54025
|
+
const expression = token.slice(`#${comparisonElseIfTag} `.length).trim();
|
|
54026
|
+
const parsed = parseComparisonExpression(expression, comparisonElseIfTag);
|
|
53484
54027
|
if (!parsed) {
|
|
53485
54028
|
errors.push(issue2("UNSUPPORTED_TEMPLATE_TAG", templatePath, `Unsupported template tag '{{${token}}}' in ${templatePath}`, "error"));
|
|
53486
54029
|
return;
|
|
53487
54030
|
}
|
|
53488
|
-
|
|
54031
|
+
validateComparisonPathUsage(parsed, templatePath, errors, stack, { isPartialFile });
|
|
53489
54032
|
continue;
|
|
53490
54033
|
}
|
|
53491
54034
|
if (token.startsWith("#else_if ")) {
|
|
@@ -53508,7 +54051,7 @@ function validateRuntimeV05TemplateSyntax(templatePath, content, errors) {
|
|
|
53508
54051
|
}
|
|
53509
54052
|
if (token.startsWith("/")) {
|
|
53510
54053
|
const closingTag = token.slice(1).trim();
|
|
53511
|
-
if (!["if", "
|
|
54054
|
+
if (!["if", "for", ...COMPARISON_BLOCK_TAGS].includes(closingTag)) {
|
|
53512
54055
|
errors.push(issue2("UNSUPPORTED_TEMPLATE_TAG", templatePath, `Unsupported template closing tag '{{${token}}}' in ${templatePath}`, "error"));
|
|
53513
54056
|
return;
|
|
53514
54057
|
}
|
|
@@ -53529,22 +54072,23 @@ function validateRuntimeV05TemplateSyntax(templatePath, content, errors) {
|
|
|
53529
54072
|
stack.push({ tag: "if", hasElse: false });
|
|
53530
54073
|
continue;
|
|
53531
54074
|
}
|
|
53532
|
-
|
|
53533
|
-
|
|
53534
|
-
const
|
|
54075
|
+
const comparisonBlockTag = getComparisonBlockTag(token);
|
|
54076
|
+
if (comparisonBlockTag) {
|
|
54077
|
+
const expression = token.slice(`#${comparisonBlockTag} `.length).trim();
|
|
54078
|
+
const parsed = parseComparisonExpression(expression, comparisonBlockTag);
|
|
53535
54079
|
if (!parsed) {
|
|
53536
54080
|
errors.push(issue2("UNSUPPORTED_TEMPLATE_TAG", templatePath, `Unsupported template tag '{{${token}}}' in ${templatePath}`, "error"));
|
|
53537
54081
|
return;
|
|
53538
54082
|
}
|
|
53539
|
-
|
|
53540
|
-
stack.push({ tag:
|
|
54083
|
+
validateComparisonPathUsage(parsed, templatePath, errors, stack, { isPartialFile });
|
|
54084
|
+
stack.push({ tag: comparisonBlockTag, hasElse: false });
|
|
53541
54085
|
continue;
|
|
53542
54086
|
}
|
|
53543
54087
|
const forMatch = FOR_TAG_REGEX.exec(token);
|
|
53544
54088
|
if (forMatch) {
|
|
53545
54089
|
const path4 = forMatch[2];
|
|
53546
54090
|
validateReservedPathUsage(path4, templatePath, errors, stack, { isPartialFile });
|
|
53547
|
-
stack.push({ tag: "for", hasElse: false });
|
|
54091
|
+
stack.push({ tag: "for", itemName: forMatch[1], hasElse: false });
|
|
53548
54092
|
continue;
|
|
53549
54093
|
}
|
|
53550
54094
|
errors.push(issue2("UNSUPPORTED_TEMPLATE_TAG", templatePath, `Unsupported template tag '{{${token}}}' in ${templatePath}`, "error"));
|
|
@@ -53577,16 +54121,124 @@ function validateReservedPathUsage(path4, templatePath, errors, stack, options2
|
|
|
53577
54121
|
));
|
|
53578
54122
|
}
|
|
53579
54123
|
}
|
|
53580
|
-
function
|
|
53581
|
-
const
|
|
53582
|
-
|
|
54124
|
+
function validateComparisonPathUsage(parsed, templatePath, errors, stack, options2) {
|
|
54125
|
+
for (const operand of [parsed.left, ...parsed.operands]) {
|
|
54126
|
+
if (operand.kind === "path") {
|
|
54127
|
+
validateReservedPathUsage(operand.path, templatePath, errors, stack, options2);
|
|
54128
|
+
}
|
|
54129
|
+
}
|
|
54130
|
+
}
|
|
54131
|
+
function getComparisonBlockTag(token) {
|
|
54132
|
+
for (const tagName of COMPARISON_BLOCK_TAGS) {
|
|
54133
|
+
if (token.startsWith(`#${tagName} `)) {
|
|
54134
|
+
return tagName;
|
|
54135
|
+
}
|
|
54136
|
+
}
|
|
54137
|
+
return "";
|
|
54138
|
+
}
|
|
54139
|
+
function getComparisonElseIfTag(token) {
|
|
54140
|
+
for (const tagName of COMPARISON_ELSE_IF_TAGS) {
|
|
54141
|
+
if (token.startsWith(`#${tagName} `)) {
|
|
54142
|
+
return tagName;
|
|
54143
|
+
}
|
|
54144
|
+
}
|
|
54145
|
+
return "";
|
|
54146
|
+
}
|
|
54147
|
+
function parseComparisonExpression(expression, tagName) {
|
|
54148
|
+
const operator = COMPARISON_TAG_OPERATORS[tagName];
|
|
54149
|
+
let tokens;
|
|
54150
|
+
try {
|
|
54151
|
+
tokens = tokenizeExpression(expression);
|
|
54152
|
+
} catch {
|
|
54153
|
+
return null;
|
|
54154
|
+
}
|
|
54155
|
+
if (!operator || operator === "in" && tokens.length < 2 || operator !== "in" && tokens.length !== 2) {
|
|
53583
54156
|
return null;
|
|
53584
54157
|
}
|
|
54158
|
+
const left = parsePathOperand(tokens[0]);
|
|
54159
|
+
if (!left) {
|
|
54160
|
+
return null;
|
|
54161
|
+
}
|
|
54162
|
+
const operands = [];
|
|
54163
|
+
for (const token of tokens.slice(1)) {
|
|
54164
|
+
const operand = parseComparisonOperand(token);
|
|
54165
|
+
if (!operand) {
|
|
54166
|
+
return null;
|
|
54167
|
+
}
|
|
54168
|
+
operands.push(operand);
|
|
54169
|
+
}
|
|
53585
54170
|
return {
|
|
53586
|
-
|
|
53587
|
-
|
|
54171
|
+
operator,
|
|
54172
|
+
left,
|
|
54173
|
+
operands
|
|
53588
54174
|
};
|
|
53589
54175
|
}
|
|
54176
|
+
function tokenizeExpression(expression) {
|
|
54177
|
+
const tokens = [];
|
|
54178
|
+
let index = 0;
|
|
54179
|
+
while (index < expression.length) {
|
|
54180
|
+
while (/\s/.test(expression[index] || "")) {
|
|
54181
|
+
index += 1;
|
|
54182
|
+
}
|
|
54183
|
+
if (index >= expression.length) {
|
|
54184
|
+
break;
|
|
54185
|
+
}
|
|
54186
|
+
if (expression[index] === '"') {
|
|
54187
|
+
const start2 = index;
|
|
54188
|
+
index += 1;
|
|
54189
|
+
let escaped = false;
|
|
54190
|
+
while (index < expression.length) {
|
|
54191
|
+
const char = expression[index];
|
|
54192
|
+
if (escaped) {
|
|
54193
|
+
escaped = false;
|
|
54194
|
+
} else if (char === "\\") {
|
|
54195
|
+
escaped = true;
|
|
54196
|
+
} else if (char === '"') {
|
|
54197
|
+
index += 1;
|
|
54198
|
+
tokens.push(expression.slice(start2, index));
|
|
54199
|
+
break;
|
|
54200
|
+
}
|
|
54201
|
+
index += 1;
|
|
54202
|
+
}
|
|
54203
|
+
if (tokens[tokens.length - 1] !== expression.slice(start2, index)) {
|
|
54204
|
+
throw new Error(`Unclosed string literal in expression: ${expression}`);
|
|
54205
|
+
}
|
|
54206
|
+
continue;
|
|
54207
|
+
}
|
|
54208
|
+
const start = index;
|
|
54209
|
+
while (index < expression.length && !/\s/.test(expression[index])) {
|
|
54210
|
+
index += 1;
|
|
54211
|
+
}
|
|
54212
|
+
tokens.push(expression.slice(start, index));
|
|
54213
|
+
}
|
|
54214
|
+
return tokens;
|
|
54215
|
+
}
|
|
54216
|
+
function parsePathOperand(token) {
|
|
54217
|
+
return TEMPLATE_PATH_REGEX.test(token) ? { kind: "path", path: token } : null;
|
|
54218
|
+
}
|
|
54219
|
+
function parseComparisonOperand(token) {
|
|
54220
|
+
if (token.startsWith('"')) {
|
|
54221
|
+
try {
|
|
54222
|
+
const value = JSON.parse(token);
|
|
54223
|
+
return typeof value === "string" ? { kind: "literal", value } : null;
|
|
54224
|
+
} catch {
|
|
54225
|
+
return null;
|
|
54226
|
+
}
|
|
54227
|
+
}
|
|
54228
|
+
if (token === "true") {
|
|
54229
|
+
return { kind: "literal", value: true };
|
|
54230
|
+
}
|
|
54231
|
+
if (token === "false") {
|
|
54232
|
+
return { kind: "literal", value: false };
|
|
54233
|
+
}
|
|
54234
|
+
if (token === "null") {
|
|
54235
|
+
return { kind: "literal", value: null };
|
|
54236
|
+
}
|
|
54237
|
+
if (NUMBER_LITERAL_REGEX.test(token)) {
|
|
54238
|
+
return { kind: "literal", value: Number(token) };
|
|
54239
|
+
}
|
|
54240
|
+
return parsePathOperand(token);
|
|
54241
|
+
}
|
|
53590
54242
|
function validatePartialReferences(templateContents, partialContents, context) {
|
|
53591
54243
|
const { errors } = context;
|
|
53592
54244
|
for (const [templatePath, content] of templateContents.entries()) {
|
|
@@ -53652,7 +54304,7 @@ function getReferencedPartialNames(content) {
|
|
|
53652
54304
|
let match2;
|
|
53653
54305
|
while ((match2 = PARTIAL_TAG_REGEX.exec(content)) !== null) {
|
|
53654
54306
|
try {
|
|
53655
|
-
const { name } = parsePartialReferenceToken(match2[1]);
|
|
54307
|
+
const { name } = parsePartialReferenceToken(match2[1], { validateArgs: false });
|
|
53656
54308
|
matches.add(name);
|
|
53657
54309
|
} catch {
|
|
53658
54310
|
}
|
|
@@ -53660,7 +54312,7 @@ function getReferencedPartialNames(content) {
|
|
|
53660
54312
|
PARTIAL_TAG_REGEX.lastIndex = 0;
|
|
53661
54313
|
return matches;
|
|
53662
54314
|
}
|
|
53663
|
-
function parsePartialReferenceToken(token) {
|
|
54315
|
+
function parsePartialReferenceToken(token, options2 = {}) {
|
|
53664
54316
|
const source = String(token || "").trim();
|
|
53665
54317
|
if (!source.startsWith("partial:")) {
|
|
53666
54318
|
throw new Error("Partial token must start with partial:");
|
|
@@ -53675,10 +54327,12 @@ function parsePartialReferenceToken(token) {
|
|
|
53675
54327
|
throw new Error(`Invalid partial name '${name}'`);
|
|
53676
54328
|
}
|
|
53677
54329
|
const argsSource = expression.slice(name.length).trim();
|
|
53678
|
-
|
|
54330
|
+
if (options2.validateArgs !== false) {
|
|
54331
|
+
parsePartialArgs(argsSource, options2);
|
|
54332
|
+
}
|
|
53679
54333
|
return { name };
|
|
53680
54334
|
}
|
|
53681
|
-
function parsePartialArgs(source) {
|
|
54335
|
+
function parsePartialArgs(source, options2 = {}) {
|
|
53682
54336
|
if (!source) {
|
|
53683
54337
|
return {};
|
|
53684
54338
|
}
|
|
@@ -53730,7 +54384,8 @@ function parsePartialArgs(source) {
|
|
|
53730
54384
|
if (cursor >= source.length || source[cursor] !== '"') {
|
|
53731
54385
|
throw new Error(`Unclosed string literal for partial argument '${key}'`);
|
|
53732
54386
|
}
|
|
53733
|
-
|
|
54387
|
+
JSON.parse(source.slice(index, cursor + 1));
|
|
54388
|
+
args[key] = true;
|
|
53734
54389
|
index = cursor + 1;
|
|
53735
54390
|
continue;
|
|
53736
54391
|
}
|
|
@@ -53740,10 +54395,25 @@ function parsePartialArgs(source) {
|
|
|
53740
54395
|
continue;
|
|
53741
54396
|
}
|
|
53742
54397
|
if (source.startsWith("false", index) && isValueBoundary(source, index + 5)) {
|
|
53743
|
-
args[key] =
|
|
54398
|
+
args[key] = true;
|
|
53744
54399
|
index += 5;
|
|
53745
54400
|
continue;
|
|
53746
54401
|
}
|
|
54402
|
+
if (source.startsWith("null", index) && isValueBoundary(source, index + 4)) {
|
|
54403
|
+
args[key] = true;
|
|
54404
|
+
index += 4;
|
|
54405
|
+
continue;
|
|
54406
|
+
}
|
|
54407
|
+
const valueMatch = /^\S+/.exec(source.slice(index));
|
|
54408
|
+
if (!valueMatch) {
|
|
54409
|
+
throw new Error(`Missing partial argument value for '${key}'`);
|
|
54410
|
+
}
|
|
54411
|
+
const valueToken = valueMatch[0];
|
|
54412
|
+
if (NUMBER_LITERAL_REGEX.test(valueToken) || TEMPLATE_PATH_REGEX.test(valueToken) && isAllowedPartialArgPath(valueToken, options2)) {
|
|
54413
|
+
args[key] = true;
|
|
54414
|
+
index += valueToken.length;
|
|
54415
|
+
continue;
|
|
54416
|
+
}
|
|
53747
54417
|
throw new Error(`Unsupported partial argument value for '${key}'`);
|
|
53748
54418
|
}
|
|
53749
54419
|
return args;
|
|
@@ -53751,6 +54421,23 @@ function parsePartialArgs(source) {
|
|
|
53751
54421
|
function isValueBoundary(source, index) {
|
|
53752
54422
|
return index >= source.length || /\s/.test(source[index]);
|
|
53753
54423
|
}
|
|
54424
|
+
function isAllowedPartialArgPath(valueToken, options2) {
|
|
54425
|
+
if (valueToken.includes(".")) {
|
|
54426
|
+
return true;
|
|
54427
|
+
}
|
|
54428
|
+
const allowedSingleSegmentPaths = options2?.allowedSingleSegmentPaths;
|
|
54429
|
+
return allowedSingleSegmentPaths instanceof Set && allowedSingleSegmentPaths.has(valueToken);
|
|
54430
|
+
}
|
|
54431
|
+
function getPartialArgScope(stack) {
|
|
54432
|
+
const scope = new Set(PARTIAL_ARG_ROOT_PATHS);
|
|
54433
|
+
for (const entry of stack) {
|
|
54434
|
+
if (entry.tag === "for" && typeof entry.itemName === "string") {
|
|
54435
|
+
scope.add(entry.itemName);
|
|
54436
|
+
scope.add("loop");
|
|
54437
|
+
}
|
|
54438
|
+
}
|
|
54439
|
+
return scope;
|
|
54440
|
+
}
|
|
53754
54441
|
function validatePathSafety(pathEntries, errors) {
|
|
53755
54442
|
for (const entry of pathEntries) {
|
|
53756
54443
|
const entryPath = normalizePath(String(entry.path || ""));
|
|
@@ -53798,13 +54485,71 @@ function normalizeAbsolutePath(value) {
|
|
|
53798
54485
|
function isPathInsideRoot(candidate, root) {
|
|
53799
54486
|
return candidate === root || candidate.startsWith(`${root}/`);
|
|
53800
54487
|
}
|
|
53801
|
-
function issue2(code2, filePath, message, severity) {
|
|
53802
|
-
|
|
54488
|
+
function issue2(code2, filePath, message, severity, details = {}) {
|
|
54489
|
+
const nextIssue = {
|
|
53803
54490
|
code: code2,
|
|
53804
54491
|
path: filePath,
|
|
53805
54492
|
message,
|
|
53806
54493
|
severity
|
|
53807
54494
|
};
|
|
54495
|
+
if (Number.isInteger(details.line) && details.line > 0) {
|
|
54496
|
+
nextIssue.line = details.line;
|
|
54497
|
+
}
|
|
54498
|
+
if (Number.isInteger(details.column) && details.column > 0) {
|
|
54499
|
+
nextIssue.column = details.column;
|
|
54500
|
+
}
|
|
54501
|
+
if (typeof details.hint === "string" && details.hint.trim()) {
|
|
54502
|
+
nextIssue.hint = details.hint;
|
|
54503
|
+
}
|
|
54504
|
+
if (typeof details.category === "string" && details.category.trim()) {
|
|
54505
|
+
nextIssue.category = details.category;
|
|
54506
|
+
}
|
|
54507
|
+
if (details.snippet && typeof details.snippet === "object" && typeof details.snippet.line === "string" && typeof details.snippet.pointer === "string") {
|
|
54508
|
+
nextIssue.snippet = {
|
|
54509
|
+
line: details.snippet.line,
|
|
54510
|
+
pointer: details.snippet.pointer
|
|
54511
|
+
};
|
|
54512
|
+
}
|
|
54513
|
+
return nextIssue;
|
|
54514
|
+
}
|
|
54515
|
+
function locationForJsonParseError(error, source) {
|
|
54516
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
54517
|
+
const lineColumnMatch = /\bline\s+(\d+)\s+column\s+(\d+)/i.exec(message);
|
|
54518
|
+
if (lineColumnMatch) {
|
|
54519
|
+
return {
|
|
54520
|
+
line: Number(lineColumnMatch[1]),
|
|
54521
|
+
column: Number(lineColumnMatch[2])
|
|
54522
|
+
};
|
|
54523
|
+
}
|
|
54524
|
+
const positionMatch = /\bposition\s+(\d+)/i.exec(message);
|
|
54525
|
+
if (positionMatch) {
|
|
54526
|
+
return locationForIndex(source, Number(positionMatch[1]));
|
|
54527
|
+
}
|
|
54528
|
+
if (/Unexpected end of JSON input/i.test(message)) {
|
|
54529
|
+
return locationForIndex(source, source.length);
|
|
54530
|
+
}
|
|
54531
|
+
return {};
|
|
54532
|
+
}
|
|
54533
|
+
function locationForIndex(source, index) {
|
|
54534
|
+
const boundedIndex = Math.max(0, Math.min(Number.isInteger(index) ? index : 0, source.length));
|
|
54535
|
+
let line = 1;
|
|
54536
|
+
let column = 1;
|
|
54537
|
+
for (let cursor = 0; cursor < boundedIndex; cursor += 1) {
|
|
54538
|
+
if (source[cursor] === "\n") {
|
|
54539
|
+
line += 1;
|
|
54540
|
+
column = 1;
|
|
54541
|
+
} else {
|
|
54542
|
+
column += 1;
|
|
54543
|
+
}
|
|
54544
|
+
}
|
|
54545
|
+
return { line, column };
|
|
54546
|
+
}
|
|
54547
|
+
function snippetForIndex(source, index) {
|
|
54548
|
+
const location = locationForIndex(source, index);
|
|
54549
|
+
const lines = String(source).split(/\r?\n/);
|
|
54550
|
+
const line = lines[location.line - 1] || "";
|
|
54551
|
+
const pointer = `${" ".repeat(Math.max(location.column - 1, 0))}^`;
|
|
54552
|
+
return { line, pointer };
|
|
53808
54553
|
}
|
|
53809
54554
|
|
|
53810
54555
|
// node_modules/@zeropress/build-core/src/assets/asset-processor.js
|
|
@@ -53814,7 +54559,7 @@ var AssetProcessor = class {
|
|
|
53814
54559
|
return css.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\s+/g, " ").replace(/\s*([{}:;,>+~])\s*/g, "$1").replace(/;}/g, "}").trim();
|
|
53815
54560
|
}
|
|
53816
54561
|
async processJavaScript(js) {
|
|
53817
|
-
return js
|
|
54562
|
+
return js;
|
|
53818
54563
|
}
|
|
53819
54564
|
generateAssetHash(content) {
|
|
53820
54565
|
const hash = createHash("sha256");
|
|
@@ -59270,6 +60015,10 @@ function sanitizeHtml(html) {
|
|
|
59270
60015
|
"li",
|
|
59271
60016
|
"blockquote",
|
|
59272
60017
|
"aside",
|
|
60018
|
+
"figure",
|
|
60019
|
+
"figcaption",
|
|
60020
|
+
"picture",
|
|
60021
|
+
"source",
|
|
59273
60022
|
"table",
|
|
59274
60023
|
"thead",
|
|
59275
60024
|
"tbody",
|
|
@@ -59285,9 +60034,10 @@ function sanitizeHtml(html) {
|
|
|
59285
60034
|
const allowedAttributes = {
|
|
59286
60035
|
a: /* @__PURE__ */ new Set(["href", "title", "class", "id"]),
|
|
59287
60036
|
aside: /* @__PURE__ */ new Set(["role", "class", "id"]),
|
|
59288
|
-
img: /* @__PURE__ */ new Set(["src", "alt", "title", "class", "id", "width", "height"]),
|
|
60037
|
+
img: /* @__PURE__ */ new Set(["src", "srcset", "sizes", "alt", "title", "class", "id", "width", "height", "loading", "decoding"]),
|
|
59289
60038
|
iframe: /* @__PURE__ */ new Set(["src", "width", "height", "frameborder", "allowfullscreen", "class"]),
|
|
59290
60039
|
input: /* @__PURE__ */ new Set(["type", "checked", "disabled", "class", "id"]),
|
|
60040
|
+
source: /* @__PURE__ */ new Set(["src", "srcset", "sizes", "type", "media", "width", "height", "class", "id"]),
|
|
59291
60041
|
"*": /* @__PURE__ */ new Set(["class", "id"])
|
|
59292
60042
|
};
|
|
59293
60043
|
const safeUriPattern = /^(?:(?:https?|mailto|tel):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i;
|
|
@@ -59315,13 +60065,16 @@ function sanitizeHtml(html) {
|
|
|
59315
60065
|
if ((attributeName === "href" || attributeName === "src") && !safeUriPattern.test(attributeValue)) {
|
|
59316
60066
|
continue;
|
|
59317
60067
|
}
|
|
60068
|
+
if (attributeName === "srcset" && !isSafeSrcset(attributeValue, safeUriPattern)) {
|
|
60069
|
+
continue;
|
|
60070
|
+
}
|
|
59318
60071
|
if (normalizedTag === "input" && attributeName === "type" && attributeValue !== "checkbox") {
|
|
59319
60072
|
continue;
|
|
59320
60073
|
}
|
|
59321
60074
|
filteredAttributes.push(`${attributeName}="${attributeValue}"`);
|
|
59322
60075
|
}
|
|
59323
60076
|
}
|
|
59324
|
-
const isSelfClosing = match2.endsWith("/>") || normalizedTag === "br" || normalizedTag === "hr" || normalizedTag === "img" || normalizedTag === "input";
|
|
60077
|
+
const isSelfClosing = match2.endsWith("/>") || normalizedTag === "br" || normalizedTag === "hr" || normalizedTag === "img" || normalizedTag === "input" || normalizedTag === "source";
|
|
59325
60078
|
const attributeSuffix = filteredAttributes.length > 0 ? ` ${filteredAttributes.join(" ")}` : "";
|
|
59326
60079
|
return isSelfClosing ? `<${normalizedTag}${attributeSuffix} />` : `<${normalizedTag}${attributeSuffix}>`;
|
|
59327
60080
|
});
|
|
@@ -59332,6 +60085,13 @@ function sanitizeHtml(html) {
|
|
|
59332
60085
|
return part.replace(/&(?!(?:[a-zA-Z]+|#\d+|#x[0-9a-fA-F]+);)/g, "&");
|
|
59333
60086
|
}).join("");
|
|
59334
60087
|
}
|
|
60088
|
+
function isSafeSrcset(value, safeUriPattern) {
|
|
60089
|
+
const candidates = String(value).split(",").map((candidate) => candidate.trim()).filter(Boolean);
|
|
60090
|
+
return candidates.length > 0 && candidates.every((candidate) => {
|
|
60091
|
+
const [url] = candidate.split(/\s+/);
|
|
60092
|
+
return Boolean(url) && safeUriPattern.test(url);
|
|
60093
|
+
});
|
|
60094
|
+
}
|
|
59335
60095
|
function slugify(value) {
|
|
59336
60096
|
return String(value || "").toLowerCase().trim().replace(/[^\w\s-]/g, "").replace(/[\s_-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
59337
60097
|
}
|
|
@@ -59424,6 +60184,9 @@ var VariableResolver = class _VariableResolver {
|
|
|
59424
60184
|
}
|
|
59425
60185
|
}
|
|
59426
60186
|
}
|
|
60187
|
+
if (variablePath === "data" || variablePath.startsWith("data.") || variablePath.includes(".data.")) {
|
|
60188
|
+
return false;
|
|
60189
|
+
}
|
|
59427
60190
|
const lastSegment = variablePath.split(".").pop();
|
|
59428
60191
|
if (lastSegment === "html" || lastSegment?.endsWith("_html")) {
|
|
59429
60192
|
return true;
|
|
@@ -59441,7 +60204,10 @@ var VariableResolver = class _VariableResolver {
|
|
|
59441
60204
|
// node_modules/@zeropress/build-core/src/render/partial-resolver.js
|
|
59442
60205
|
var PARTIAL_NAME_REGEX2 = /^[a-zA-Z_][a-zA-Z0-9_-]*(?:\/[a-zA-Z_][a-zA-Z0-9_-]*)*$/;
|
|
59443
60206
|
var IDENTIFIER_REGEX = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
|
|
59444
|
-
|
|
60207
|
+
var PATH_SEGMENT_SOURCE = "[a-zA-Z_][a-zA-Z0-9_]*(?:-[a-zA-Z0-9_]+)*";
|
|
60208
|
+
var PATH_REGEX = new RegExp(`^${PATH_SEGMENT_SOURCE}(?:\\.${PATH_SEGMENT_SOURCE})*$`);
|
|
60209
|
+
var NUMBER_LITERAL_REGEX2 = /^-?(?:0|[1-9]\d*)(?:\.\d+)?$/;
|
|
60210
|
+
function parsePartialToken(token, options2 = {}) {
|
|
59445
60211
|
const source = String(token || "").trim();
|
|
59446
60212
|
if (!source.startsWith("partial:")) {
|
|
59447
60213
|
throw new Error(`Invalid partial token: ${source}`);
|
|
@@ -59456,10 +60222,10 @@ function parsePartialToken(token) {
|
|
|
59456
60222
|
throw new Error(`Invalid partial name: ${name}`);
|
|
59457
60223
|
}
|
|
59458
60224
|
const argsSource = expression.slice(name.length).trim();
|
|
59459
|
-
const args = parsePartialArgs2(argsSource);
|
|
60225
|
+
const args = parsePartialArgs2(argsSource, options2);
|
|
59460
60226
|
return { name, args };
|
|
59461
60227
|
}
|
|
59462
|
-
function parsePartialArgs2(source) {
|
|
60228
|
+
function parsePartialArgs2(source, options2 = {}) {
|
|
59463
60229
|
if (!source) {
|
|
59464
60230
|
return {};
|
|
59465
60231
|
}
|
|
@@ -59511,20 +60277,40 @@ function parsePartialArgs2(source) {
|
|
|
59511
60277
|
if (cursor >= source.length || source[cursor] !== '"') {
|
|
59512
60278
|
throw new Error(`Unclosed string literal for partial argument "${key}"`);
|
|
59513
60279
|
}
|
|
59514
|
-
args[key] = JSON.parse(source.slice(index, cursor + 1));
|
|
60280
|
+
args[key] = { kind: "literal", value: JSON.parse(source.slice(index, cursor + 1)) };
|
|
59515
60281
|
index = cursor + 1;
|
|
59516
60282
|
continue;
|
|
59517
60283
|
}
|
|
59518
60284
|
if (source.startsWith("true", index) && isValueBoundary2(source, index + 4)) {
|
|
59519
|
-
args[key] = true;
|
|
60285
|
+
args[key] = { kind: "literal", value: true };
|
|
59520
60286
|
index += 4;
|
|
59521
60287
|
continue;
|
|
59522
60288
|
}
|
|
59523
60289
|
if (source.startsWith("false", index) && isValueBoundary2(source, index + 5)) {
|
|
59524
|
-
args[key] = false;
|
|
60290
|
+
args[key] = { kind: "literal", value: false };
|
|
59525
60291
|
index += 5;
|
|
59526
60292
|
continue;
|
|
59527
60293
|
}
|
|
60294
|
+
if (source.startsWith("null", index) && isValueBoundary2(source, index + 4)) {
|
|
60295
|
+
args[key] = { kind: "literal", value: null };
|
|
60296
|
+
index += 4;
|
|
60297
|
+
continue;
|
|
60298
|
+
}
|
|
60299
|
+
const valueMatch = /^\S+/.exec(source.slice(index));
|
|
60300
|
+
if (!valueMatch) {
|
|
60301
|
+
throw new Error(`Missing partial argument value for "${key}"`);
|
|
60302
|
+
}
|
|
60303
|
+
const valueToken = valueMatch[0];
|
|
60304
|
+
if (NUMBER_LITERAL_REGEX2.test(valueToken)) {
|
|
60305
|
+
args[key] = { kind: "literal", value: Number(valueToken) };
|
|
60306
|
+
index += valueToken.length;
|
|
60307
|
+
continue;
|
|
60308
|
+
}
|
|
60309
|
+
if (PATH_REGEX.test(valueToken) && isAllowedPathArgument(valueToken, options2)) {
|
|
60310
|
+
args[key] = { kind: "path", path: valueToken };
|
|
60311
|
+
index += valueToken.length;
|
|
60312
|
+
continue;
|
|
60313
|
+
}
|
|
59528
60314
|
throw new Error(`Unsupported partial argument value for "${key}"`);
|
|
59529
60315
|
}
|
|
59530
60316
|
return args;
|
|
@@ -59532,12 +60318,146 @@ function parsePartialArgs2(source) {
|
|
|
59532
60318
|
function isValueBoundary2(source, index) {
|
|
59533
60319
|
return index >= source.length || /\s/.test(source[index]);
|
|
59534
60320
|
}
|
|
60321
|
+
function isAllowedPathArgument(valueToken, options2) {
|
|
60322
|
+
if (valueToken.includes(".")) {
|
|
60323
|
+
return true;
|
|
60324
|
+
}
|
|
60325
|
+
const allowedSingleSegmentPaths = options2?.allowedSingleSegmentPaths;
|
|
60326
|
+
return allowedSingleSegmentPaths instanceof Set && allowedSingleSegmentPaths.has(valueToken);
|
|
60327
|
+
}
|
|
59535
60328
|
|
|
59536
60329
|
// node_modules/@zeropress/build-core/src/render/control-flow-renderer.js
|
|
59537
|
-
var
|
|
59538
|
-
var
|
|
59539
|
-
var FOR_EXPRESSION_REGEX = new RegExp(`^([a-zA-Z_][a-zA-Z0-9_]*)\\s+in\\s+(${
|
|
59540
|
-
var
|
|
60330
|
+
var PATH_SEGMENT_SOURCE2 = "[a-zA-Z_][a-zA-Z0-9_]*(?:-[a-zA-Z0-9_]+)*";
|
|
60331
|
+
var PATH_REGEX2 = new RegExp(`^${PATH_SEGMENT_SOURCE2}(?:\\.${PATH_SEGMENT_SOURCE2})*$`);
|
|
60332
|
+
var FOR_EXPRESSION_REGEX = new RegExp(`^([a-zA-Z_][a-zA-Z0-9_]*)\\s+in\\s+(${PATH_SEGMENT_SOURCE2}(?:\\.${PATH_SEGMENT_SOURCE2})*)$`);
|
|
60333
|
+
var NUMBER_LITERAL_REGEX3 = /^-?(?:0|[1-9]\d*)(?:\.\d+)?$/;
|
|
60334
|
+
var COMPARISON_BLOCK_TAGS2 = /* @__PURE__ */ new Set(["if_eq", "if_neq", "if_in", "if_starts_with"]);
|
|
60335
|
+
var COMPARISON_ELSE_IF_TAGS2 = /* @__PURE__ */ new Set(["else_if_eq", "else_if_neq", "else_if_in", "else_if_starts_with"]);
|
|
60336
|
+
var COMPARISON_TAG_OPERATORS2 = {
|
|
60337
|
+
if_eq: "eq",
|
|
60338
|
+
else_if_eq: "eq",
|
|
60339
|
+
if_neq: "neq",
|
|
60340
|
+
else_if_neq: "neq",
|
|
60341
|
+
if_in: "in",
|
|
60342
|
+
else_if_in: "in",
|
|
60343
|
+
if_starts_with: "starts_with",
|
|
60344
|
+
else_if_starts_with: "starts_with"
|
|
60345
|
+
};
|
|
60346
|
+
var PARTIAL_ARG_ROOT_PATHS2 = /* @__PURE__ */ new Set([
|
|
60347
|
+
"archive",
|
|
60348
|
+
"author",
|
|
60349
|
+
"category",
|
|
60350
|
+
"collection",
|
|
60351
|
+
"collections",
|
|
60352
|
+
"currentUrl",
|
|
60353
|
+
"language",
|
|
60354
|
+
"menu",
|
|
60355
|
+
"menus",
|
|
60356
|
+
"meta",
|
|
60357
|
+
"page",
|
|
60358
|
+
"pagination",
|
|
60359
|
+
"partial",
|
|
60360
|
+
"post",
|
|
60361
|
+
"posts",
|
|
60362
|
+
"route",
|
|
60363
|
+
"site",
|
|
60364
|
+
"tag",
|
|
60365
|
+
"taxonomies",
|
|
60366
|
+
"taxonomy",
|
|
60367
|
+
"widget",
|
|
60368
|
+
"widgets"
|
|
60369
|
+
]);
|
|
60370
|
+
function getComparisonBlockTag2(token) {
|
|
60371
|
+
for (const tagName of COMPARISON_BLOCK_TAGS2) {
|
|
60372
|
+
if (token.startsWith(`#${tagName} `)) {
|
|
60373
|
+
return tagName;
|
|
60374
|
+
}
|
|
60375
|
+
}
|
|
60376
|
+
return "";
|
|
60377
|
+
}
|
|
60378
|
+
function getComparisonElseIfTag2(token) {
|
|
60379
|
+
for (const tagName of COMPARISON_ELSE_IF_TAGS2) {
|
|
60380
|
+
if (token.startsWith(`#${tagName} `)) {
|
|
60381
|
+
return tagName;
|
|
60382
|
+
}
|
|
60383
|
+
}
|
|
60384
|
+
return "";
|
|
60385
|
+
}
|
|
60386
|
+
function tokenizeExpression2(expression) {
|
|
60387
|
+
const tokens = [];
|
|
60388
|
+
let index = 0;
|
|
60389
|
+
while (index < expression.length) {
|
|
60390
|
+
while (/\s/.test(expression[index] || "")) {
|
|
60391
|
+
index += 1;
|
|
60392
|
+
}
|
|
60393
|
+
if (index >= expression.length) {
|
|
60394
|
+
break;
|
|
60395
|
+
}
|
|
60396
|
+
if (expression[index] === '"') {
|
|
60397
|
+
const start2 = index;
|
|
60398
|
+
index += 1;
|
|
60399
|
+
let escaped = false;
|
|
60400
|
+
while (index < expression.length) {
|
|
60401
|
+
const char = expression[index];
|
|
60402
|
+
if (escaped) {
|
|
60403
|
+
escaped = false;
|
|
60404
|
+
} else if (char === "\\") {
|
|
60405
|
+
escaped = true;
|
|
60406
|
+
} else if (char === '"') {
|
|
60407
|
+
index += 1;
|
|
60408
|
+
tokens.push(expression.slice(start2, index));
|
|
60409
|
+
break;
|
|
60410
|
+
}
|
|
60411
|
+
index += 1;
|
|
60412
|
+
}
|
|
60413
|
+
if (tokens[tokens.length - 1] !== expression.slice(start2, index)) {
|
|
60414
|
+
throw new Error(`Unclosed string literal in expression: ${expression}`);
|
|
60415
|
+
}
|
|
60416
|
+
continue;
|
|
60417
|
+
}
|
|
60418
|
+
const start = index;
|
|
60419
|
+
while (index < expression.length && !/\s/.test(expression[index])) {
|
|
60420
|
+
index += 1;
|
|
60421
|
+
}
|
|
60422
|
+
tokens.push(expression.slice(start, index));
|
|
60423
|
+
}
|
|
60424
|
+
return tokens;
|
|
60425
|
+
}
|
|
60426
|
+
function parsePathOperand2(token, tagName, expression) {
|
|
60427
|
+
if (!PATH_REGEX2.test(token)) {
|
|
60428
|
+
throw new Error(`Invalid ${tagName} expression: ${expression}`);
|
|
60429
|
+
}
|
|
60430
|
+
return { kind: "path", path: token };
|
|
60431
|
+
}
|
|
60432
|
+
function parseComparisonOperand2(token, tagName, expression) {
|
|
60433
|
+
if (token.startsWith('"')) {
|
|
60434
|
+
try {
|
|
60435
|
+
const value = JSON.parse(token);
|
|
60436
|
+
if (typeof value !== "string") {
|
|
60437
|
+
throw new Error("Expected string literal");
|
|
60438
|
+
}
|
|
60439
|
+
return { kind: "literal", value };
|
|
60440
|
+
} catch {
|
|
60441
|
+
throw new Error(`Invalid ${tagName} expression: ${expression}`);
|
|
60442
|
+
}
|
|
60443
|
+
}
|
|
60444
|
+
if (token === "true") {
|
|
60445
|
+
return { kind: "literal", value: true };
|
|
60446
|
+
}
|
|
60447
|
+
if (token === "false") {
|
|
60448
|
+
return { kind: "literal", value: false };
|
|
60449
|
+
}
|
|
60450
|
+
if (token === "null") {
|
|
60451
|
+
return { kind: "literal", value: null };
|
|
60452
|
+
}
|
|
60453
|
+
if (NUMBER_LITERAL_REGEX3.test(token)) {
|
|
60454
|
+
return { kind: "literal", value: Number(token) };
|
|
60455
|
+
}
|
|
60456
|
+
if (PATH_REGEX2.test(token)) {
|
|
60457
|
+
return { kind: "path", path: token };
|
|
60458
|
+
}
|
|
60459
|
+
throw new Error(`Invalid ${tagName} expression: ${expression}`);
|
|
60460
|
+
}
|
|
59541
60461
|
var ControlFlowRenderer = class {
|
|
59542
60462
|
constructor(options2 = {}) {
|
|
59543
60463
|
this.resolvePath = typeof options2.resolvePath === "function" ? options2.resolvePath : ((data, path4) => path4.split(".").reduce((current, segment) => {
|
|
@@ -59560,7 +60480,7 @@ var ControlFlowRenderer = class {
|
|
|
59560
60480
|
}
|
|
59561
60481
|
parse(template) {
|
|
59562
60482
|
const source = String(template || "");
|
|
59563
|
-
const { nodes, nextIndex, stopTag } = this.parseNodes(source, 0, /* @__PURE__ */ new Set());
|
|
60483
|
+
const { nodes, nextIndex, stopTag } = this.parseNodes(source, 0, /* @__PURE__ */ new Set(), PARTIAL_ARG_ROOT_PATHS2);
|
|
59564
60484
|
if (stopTag) {
|
|
59565
60485
|
throw new Error(`Unexpected closing tag ${stopTag}`);
|
|
59566
60486
|
}
|
|
@@ -59569,7 +60489,7 @@ var ControlFlowRenderer = class {
|
|
|
59569
60489
|
}
|
|
59570
60490
|
return nodes;
|
|
59571
60491
|
}
|
|
59572
|
-
parseNodes(source, startIndex, stopTags) {
|
|
60492
|
+
parseNodes(source, startIndex, stopTags, partialArgScope) {
|
|
59573
60493
|
const nodes = [];
|
|
59574
60494
|
let index = startIndex;
|
|
59575
60495
|
while (index < source.length) {
|
|
@@ -59620,9 +60540,10 @@ var ControlFlowRenderer = class {
|
|
|
59620
60540
|
}
|
|
59621
60541
|
return { nodes, nextIndex: tokenEnd + 2, stopTag: "else" };
|
|
59622
60542
|
}
|
|
59623
|
-
|
|
59624
|
-
|
|
59625
|
-
|
|
60543
|
+
const comparisonElseIfTag = getComparisonElseIfTag2(token);
|
|
60544
|
+
if (comparisonElseIfTag) {
|
|
60545
|
+
if (!stopTags.has(comparisonElseIfTag)) {
|
|
60546
|
+
throw new Error(`Unexpected ${comparisonElseIfTag} tag`);
|
|
59626
60547
|
}
|
|
59627
60548
|
return { nodes, nextIndex: tokenEnd + 2, stopTag: token };
|
|
59628
60549
|
}
|
|
@@ -59633,21 +60554,22 @@ var ControlFlowRenderer = class {
|
|
|
59633
60554
|
return { nodes, nextIndex: tokenEnd + 2, stopTag: token };
|
|
59634
60555
|
}
|
|
59635
60556
|
if (token.startsWith("partial:")) {
|
|
59636
|
-
const { name, args } = parsePartialToken(token);
|
|
60557
|
+
const { name, args } = parsePartialToken(token, { allowedSingleSegmentPaths: partialArgScope });
|
|
59637
60558
|
nodes.push({ type: "partial", name, args });
|
|
59638
60559
|
index = tokenEnd + 2;
|
|
59639
60560
|
continue;
|
|
59640
60561
|
}
|
|
59641
|
-
|
|
59642
|
-
|
|
59643
|
-
const
|
|
60562
|
+
const comparisonBlockTag = getComparisonBlockTag2(token);
|
|
60563
|
+
if (comparisonBlockTag) {
|
|
60564
|
+
const expression = token.slice(`#${comparisonBlockTag} `.length).trim();
|
|
60565
|
+
const block2 = this.parseComparisonBlock(source, tokenEnd + 2, comparisonBlockTag, expression, partialArgScope);
|
|
59644
60566
|
nodes.push(block2.node);
|
|
59645
60567
|
index = block2.nextIndex;
|
|
59646
60568
|
continue;
|
|
59647
60569
|
}
|
|
59648
60570
|
if (token.startsWith("#if ")) {
|
|
59649
60571
|
const expression = token.slice("#if ".length).trim();
|
|
59650
|
-
const block2 = this.parseIfBlock(source, tokenEnd + 2, expression);
|
|
60572
|
+
const block2 = this.parseIfBlock(source, tokenEnd + 2, expression, partialArgScope);
|
|
59651
60573
|
nodes.push(block2.node);
|
|
59652
60574
|
index = block2.nextIndex;
|
|
59653
60575
|
continue;
|
|
@@ -59659,7 +60581,8 @@ var ControlFlowRenderer = class {
|
|
|
59659
60581
|
throw new Error(`Invalid for expression: ${expression}`);
|
|
59660
60582
|
}
|
|
59661
60583
|
const [, itemName, path4] = match2;
|
|
59662
|
-
const
|
|
60584
|
+
const forScope = /* @__PURE__ */ new Set([...partialArgScope, itemName, "loop"]);
|
|
60585
|
+
const forResult = this.parseNodes(source, tokenEnd + 2, /* @__PURE__ */ new Set(["for"]), forScope);
|
|
59663
60586
|
if (forResult.stopTag !== "for") {
|
|
59664
60587
|
throw new Error("Unclosed for block");
|
|
59665
60588
|
}
|
|
@@ -59676,8 +60599,8 @@ var ControlFlowRenderer = class {
|
|
|
59676
60599
|
}
|
|
59677
60600
|
return { nodes, nextIndex: source.length, stopTag: null };
|
|
59678
60601
|
}
|
|
59679
|
-
parseIfBlock(source, startIndex, initialPath) {
|
|
59680
|
-
if (!
|
|
60602
|
+
parseIfBlock(source, startIndex, initialPath, partialArgScope) {
|
|
60603
|
+
if (!PATH_REGEX2.test(initialPath)) {
|
|
59681
60604
|
throw new Error(`Invalid if expression: ${initialPath}`);
|
|
59682
60605
|
}
|
|
59683
60606
|
const branches = [];
|
|
@@ -59685,13 +60608,13 @@ var ControlFlowRenderer = class {
|
|
|
59685
60608
|
let nextIndex = startIndex;
|
|
59686
60609
|
let currentPath = initialPath;
|
|
59687
60610
|
while (true) {
|
|
59688
|
-
const branchResult = this.parseNodes(source, nextIndex, /* @__PURE__ */ new Set(["else", "else_if", "if"]));
|
|
60611
|
+
const branchResult = this.parseNodes(source, nextIndex, /* @__PURE__ */ new Set(["else", "else_if", "if"]), partialArgScope);
|
|
59689
60612
|
branches.push({
|
|
59690
60613
|
path: currentPath,
|
|
59691
60614
|
consequent: branchResult.nodes
|
|
59692
60615
|
});
|
|
59693
60616
|
if (branchResult.stopTag === "else") {
|
|
59694
|
-
const elseResult = this.parseNodes(source, branchResult.nextIndex, /* @__PURE__ */ new Set(["if"]));
|
|
60617
|
+
const elseResult = this.parseNodes(source, branchResult.nextIndex, /* @__PURE__ */ new Set(["if"]), partialArgScope);
|
|
59695
60618
|
if (elseResult.stopTag !== "if") {
|
|
59696
60619
|
throw new Error("Unclosed if block after else");
|
|
59697
60620
|
}
|
|
@@ -59701,7 +60624,7 @@ var ControlFlowRenderer = class {
|
|
|
59701
60624
|
}
|
|
59702
60625
|
if (typeof branchResult.stopTag === "string" && branchResult.stopTag.startsWith("#else_if ")) {
|
|
59703
60626
|
currentPath = branchResult.stopTag.slice("#else_if ".length).trim();
|
|
59704
|
-
if (!
|
|
60627
|
+
if (!PATH_REGEX2.test(currentPath)) {
|
|
59705
60628
|
throw new Error(`Invalid else_if expression: ${currentPath}`);
|
|
59706
60629
|
}
|
|
59707
60630
|
nextIndex = branchResult.nextIndex;
|
|
@@ -59722,60 +60645,65 @@ var ControlFlowRenderer = class {
|
|
|
59722
60645
|
nextIndex
|
|
59723
60646
|
};
|
|
59724
60647
|
}
|
|
59725
|
-
|
|
59726
|
-
const initialBranch = this.
|
|
60648
|
+
parseComparisonBlock(source, startIndex, tagName, expression, partialArgScope) {
|
|
60649
|
+
const initialBranch = this.parseComparisonBranchExpression(expression, tagName);
|
|
59727
60650
|
const branches = [];
|
|
59728
60651
|
let alternate = [];
|
|
59729
60652
|
let nextIndex = startIndex;
|
|
59730
60653
|
let currentBranch = initialBranch;
|
|
60654
|
+
const elseIfTag = `else_${tagName}`;
|
|
59731
60655
|
while (true) {
|
|
59732
|
-
const branchResult = this.parseNodes(source, nextIndex, /* @__PURE__ */ new Set(["else",
|
|
60656
|
+
const branchResult = this.parseNodes(source, nextIndex, /* @__PURE__ */ new Set(["else", elseIfTag, tagName]), partialArgScope);
|
|
59733
60657
|
branches.push({
|
|
59734
|
-
|
|
59735
|
-
|
|
60658
|
+
operator: currentBranch.operator,
|
|
60659
|
+
left: currentBranch.left,
|
|
60660
|
+
operands: currentBranch.operands,
|
|
59736
60661
|
consequent: branchResult.nodes
|
|
59737
60662
|
});
|
|
59738
60663
|
if (branchResult.stopTag === "else") {
|
|
59739
|
-
const elseResult = this.parseNodes(source, branchResult.nextIndex, /* @__PURE__ */ new Set([
|
|
59740
|
-
if (elseResult.stopTag !==
|
|
59741
|
-
throw new Error(
|
|
60664
|
+
const elseResult = this.parseNodes(source, branchResult.nextIndex, /* @__PURE__ */ new Set([tagName]), partialArgScope);
|
|
60665
|
+
if (elseResult.stopTag !== tagName) {
|
|
60666
|
+
throw new Error(`Unclosed ${tagName} block after else`);
|
|
59742
60667
|
}
|
|
59743
60668
|
alternate = elseResult.nodes;
|
|
59744
60669
|
nextIndex = elseResult.nextIndex;
|
|
59745
60670
|
break;
|
|
59746
60671
|
}
|
|
59747
|
-
if (typeof branchResult.stopTag === "string" && branchResult.stopTag.startsWith(
|
|
59748
|
-
currentBranch = this.
|
|
59749
|
-
branchResult.stopTag.slice(
|
|
59750
|
-
|
|
60672
|
+
if (typeof branchResult.stopTag === "string" && branchResult.stopTag.startsWith(`#${elseIfTag} `)) {
|
|
60673
|
+
currentBranch = this.parseComparisonBranchExpression(
|
|
60674
|
+
branchResult.stopTag.slice(`#${elseIfTag} `.length).trim(),
|
|
60675
|
+
elseIfTag
|
|
59751
60676
|
);
|
|
59752
60677
|
nextIndex = branchResult.nextIndex;
|
|
59753
60678
|
continue;
|
|
59754
60679
|
}
|
|
59755
|
-
if (branchResult.stopTag ===
|
|
60680
|
+
if (branchResult.stopTag === tagName) {
|
|
59756
60681
|
nextIndex = branchResult.nextIndex;
|
|
59757
60682
|
break;
|
|
59758
60683
|
}
|
|
59759
|
-
throw new Error(
|
|
60684
|
+
throw new Error(`Unclosed ${tagName} block`);
|
|
59760
60685
|
}
|
|
59761
60686
|
return {
|
|
59762
60687
|
node: {
|
|
59763
|
-
type: "
|
|
60688
|
+
type: "comparison",
|
|
59764
60689
|
branches,
|
|
59765
60690
|
alternate
|
|
59766
60691
|
},
|
|
59767
60692
|
nextIndex
|
|
59768
60693
|
};
|
|
59769
60694
|
}
|
|
59770
|
-
|
|
59771
|
-
const
|
|
59772
|
-
|
|
60695
|
+
parseComparisonBranchExpression(expression, tagName) {
|
|
60696
|
+
const operator = COMPARISON_TAG_OPERATORS2[tagName];
|
|
60697
|
+
const tokens = tokenizeExpression2(expression);
|
|
60698
|
+
if (!operator || operator === "in" && tokens.length < 2 || operator !== "in" && tokens.length !== 2) {
|
|
59773
60699
|
throw new Error(`Invalid ${tagName} expression: ${expression}`);
|
|
59774
60700
|
}
|
|
59775
|
-
const [,
|
|
60701
|
+
const left = parsePathOperand2(tokens[0], tagName, expression);
|
|
60702
|
+
const operands = tokens.slice(1).map((token) => parseComparisonOperand2(token, tagName, expression));
|
|
59776
60703
|
return {
|
|
59777
|
-
|
|
59778
|
-
|
|
60704
|
+
operator,
|
|
60705
|
+
left,
|
|
60706
|
+
operands
|
|
59779
60707
|
};
|
|
59780
60708
|
}
|
|
59781
60709
|
renderNodes(nodes, data, renderOptions) {
|
|
@@ -59789,8 +60717,8 @@ var ControlFlowRenderer = class {
|
|
|
59789
60717
|
const branch = node.branches.find((entry) => this.isTruthy(this.resolvePath(data, entry.path)));
|
|
59790
60718
|
return branch ? this.renderNodes(branch.consequent, data, renderOptions) : this.renderNodes(node.alternate, data, renderOptions);
|
|
59791
60719
|
}
|
|
59792
|
-
case "
|
|
59793
|
-
const branch = node.branches.find((entry) => this.
|
|
60720
|
+
case "comparison": {
|
|
60721
|
+
const branch = node.branches.find((entry) => this.evaluateComparison(entry, data));
|
|
59794
60722
|
return branch ? this.renderNodes(branch.consequent, data, renderOptions) : this.renderNodes(node.alternate, data, renderOptions);
|
|
59795
60723
|
}
|
|
59796
60724
|
case "for": {
|
|
@@ -59825,15 +60753,62 @@ var ControlFlowRenderer = class {
|
|
|
59825
60753
|
throw new Error(`Circular partial reference detected: ${cycle}`);
|
|
59826
60754
|
}
|
|
59827
60755
|
const partialTemplate = String(partials.get(node.name) || "");
|
|
60756
|
+
const partialArgs = this.resolvePartialArgs(node.args, data);
|
|
59828
60757
|
const partialData = {
|
|
59829
60758
|
...data,
|
|
59830
|
-
partial: {
|
|
60759
|
+
partial: {
|
|
60760
|
+
...data?.partial && typeof data.partial === "object" ? data.partial : {},
|
|
60761
|
+
...partialArgs
|
|
60762
|
+
}
|
|
59831
60763
|
};
|
|
59832
60764
|
return this.renderTemplate(partialTemplate, partialData, {
|
|
59833
60765
|
...renderOptions,
|
|
59834
60766
|
partialStack: [...activeStack, node.name]
|
|
59835
60767
|
});
|
|
59836
60768
|
}
|
|
60769
|
+
resolvePartialArgs(args, data) {
|
|
60770
|
+
const resolved = {};
|
|
60771
|
+
for (const [key, operand] of Object.entries(args || {})) {
|
|
60772
|
+
if (operand?.kind === "literal") {
|
|
60773
|
+
resolved[key] = operand.value;
|
|
60774
|
+
continue;
|
|
60775
|
+
}
|
|
60776
|
+
if (operand?.kind === "path") {
|
|
60777
|
+
resolved[key] = this.resolvePath(data, operand.path);
|
|
60778
|
+
}
|
|
60779
|
+
}
|
|
60780
|
+
return resolved;
|
|
60781
|
+
}
|
|
60782
|
+
evaluateComparison(entry, data) {
|
|
60783
|
+
const left = this.evaluateOperand(entry.left, data);
|
|
60784
|
+
const operands = entry.operands.map((operand) => this.evaluateOperand(operand, data));
|
|
60785
|
+
if (entry.operator === "eq") {
|
|
60786
|
+
const right = operands[0];
|
|
60787
|
+
return !left.missing && !right.missing && left.value === right.value;
|
|
60788
|
+
}
|
|
60789
|
+
if (entry.operator === "neq") {
|
|
60790
|
+
const right = operands[0];
|
|
60791
|
+
return left.missing || right.missing || left.value !== right.value;
|
|
60792
|
+
}
|
|
60793
|
+
if (entry.operator === "in") {
|
|
60794
|
+
if (left.missing) {
|
|
60795
|
+
return false;
|
|
60796
|
+
}
|
|
60797
|
+
return operands.some((operand) => !operand.missing && left.value === operand.value);
|
|
60798
|
+
}
|
|
60799
|
+
if (entry.operator === "starts_with") {
|
|
60800
|
+
const right = operands[0];
|
|
60801
|
+
return !left.missing && !right.missing && typeof left.value === "string" && typeof right.value === "string" && left.value.startsWith(right.value);
|
|
60802
|
+
}
|
|
60803
|
+
return false;
|
|
60804
|
+
}
|
|
60805
|
+
evaluateOperand(operand, data) {
|
|
60806
|
+
if (operand.kind === "literal") {
|
|
60807
|
+
return { value: operand.value, missing: false };
|
|
60808
|
+
}
|
|
60809
|
+
const value = this.resolvePath(data, operand.path);
|
|
60810
|
+
return { value, missing: value === void 0 };
|
|
60811
|
+
}
|
|
59837
60812
|
isTruthy(value) {
|
|
59838
60813
|
if (Array.isArray(value)) {
|
|
59839
60814
|
return value.length > 0;
|
|
@@ -59875,7 +60850,7 @@ var ZeroPressEngine = class {
|
|
|
59875
60850
|
const renderData = this.combineRenderData(data, context);
|
|
59876
60851
|
const renderedContent = this.renderTemplate(template, renderData);
|
|
59877
60852
|
const layoutWithSlots = this.slotResolver.resolve(layout, this.themePackage.partials, CONTENT_SLOT_PLACEHOLDER);
|
|
59878
|
-
return this.renderTemplate(layoutWithSlots, renderData).replaceAll(CONTENT_SLOT_PLACEHOLDER, renderedContent);
|
|
60853
|
+
return this.renderTemplate(layoutWithSlots, renderData).replaceAll(CONTENT_SLOT_PLACEHOLDER, () => renderedContent);
|
|
59879
60854
|
}
|
|
59880
60855
|
combineRenderData(data, context) {
|
|
59881
60856
|
return {
|
|
@@ -59886,7 +60861,7 @@ var ZeroPressEngine = class {
|
|
|
59886
60861
|
};
|
|
59887
60862
|
}
|
|
59888
60863
|
renderTemplate(template, data) {
|
|
59889
|
-
if (this.themePackage?.metadata?.runtime !== "0.
|
|
60864
|
+
if (this.themePackage?.metadata?.runtime !== "0.6") {
|
|
59890
60865
|
throw new Error(`Unsupported theme runtime: ${this.themePackage?.metadata?.runtime || "unknown"}`);
|
|
59891
60866
|
}
|
|
59892
60867
|
return this.controlFlowRenderer.render(template, data, {
|
|
@@ -59902,13 +60877,17 @@ var ZeroPressEngine = class {
|
|
|
59902
60877
|
var DEFAULT_OPTIONS = {
|
|
59903
60878
|
assetHashing: true,
|
|
59904
60879
|
generateSpecialFiles: true,
|
|
60880
|
+
generateRobotsTxt: true,
|
|
59905
60881
|
writeManifest: false
|
|
59906
60882
|
};
|
|
59907
60883
|
var DEFAULT_POSTS_PER_PAGE = 10;
|
|
59908
|
-
var
|
|
59909
|
-
var
|
|
60884
|
+
var DEFAULT_DATETIME_DISPLAY = "static";
|
|
60885
|
+
var DEFAULT_DATE_STYLE = "medium";
|
|
60886
|
+
var DEFAULT_TIME_STYLE = "none";
|
|
59910
60887
|
var DEFAULT_TIMEZONE = "UTC";
|
|
59911
60888
|
var DEFAULT_LOCALE = "en-US";
|
|
60889
|
+
var DATETIME_DISPLAY_MODES = /* @__PURE__ */ new Set(["static", "client"]);
|
|
60890
|
+
var DATETIME_STYLES = /* @__PURE__ */ new Set(["none", "short", "medium", "long", "full"]);
|
|
59912
60891
|
var DEFAULT_PERMALINKS = Object.freeze({
|
|
59913
60892
|
output_style: "directory",
|
|
59914
60893
|
posts: "/posts/:slug/",
|
|
@@ -59926,9 +60905,24 @@ var DEFAULT_POST_INDEX = Object.freeze({
|
|
|
59926
60905
|
});
|
|
59927
60906
|
var PERMALINK_OUTPUT_STYLES = /* @__PURE__ */ new Set(["directory", "html-extension"]);
|
|
59928
60907
|
var COMMENT_POLICY_OUTPUT_PATH = "_zeropress/comment-policy.json";
|
|
60908
|
+
var SEARCH_INDEX_OUTPUT_PATH = "_zeropress/search.json";
|
|
60909
|
+
var SEARCH_ADAPTER_OUTPUT_PATH = "_zeropress/search.js";
|
|
59929
60910
|
var OUTPUT_PATH_CONTROL_CHAR_PATTERN = /[\u0000-\u001F\u007F]/;
|
|
59930
60911
|
var SAFE_MEDIA_PROTOCOLS = /* @__PURE__ */ new Set(["http:", "https:"]);
|
|
59931
60912
|
var SAFE_LINK_PROTOCOLS = /* @__PURE__ */ new Set(["http:", "https:", "mailto:", "tel:"]);
|
|
60913
|
+
var MEDIA_DELIVERY_MODES = /* @__PURE__ */ new Set(["none", "media_domain"]);
|
|
60914
|
+
var DISCOVERABILITY_VALUES = /* @__PURE__ */ new Set(["default", "noindex", "delist"]);
|
|
60915
|
+
var RESPONSIVE_IMAGE_WIDTHS = [320, 480, 768, 1024, 1280, 1600, 1920];
|
|
60916
|
+
var RESPONSIVE_IMAGE_EXTENSIONS = /* @__PURE__ */ new Set(["jpg", "jpeg", "png", "webp", "avif"]);
|
|
60917
|
+
var SEARCH_FIELD_WEIGHTS = Object.freeze({
|
|
60918
|
+
title: 5,
|
|
60919
|
+
headings: 3,
|
|
60920
|
+
tags: 2.5,
|
|
60921
|
+
categories: 2,
|
|
60922
|
+
excerpt: 1.5,
|
|
60923
|
+
content_text: 1
|
|
60924
|
+
});
|
|
60925
|
+
var SEARCH_RECENCY_BOOST_MAX = 0.15;
|
|
59932
60926
|
async function buildSite(input2) {
|
|
59933
60927
|
const options2 = { ...DEFAULT_OPTIONS, ...input2.options || {} };
|
|
59934
60928
|
const state = await createBuildState(input2, options2);
|
|
@@ -59971,12 +60965,22 @@ async function buildSite(input2) {
|
|
|
59971
60965
|
"application/json"
|
|
59972
60966
|
);
|
|
59973
60967
|
if (options2.generateSpecialFiles) {
|
|
60968
|
+
await writeOutput(state.writer, state.summaries, SEARCH_INDEX_OUTPUT_PATH, buildSearchIndexJson(state), "application/json");
|
|
60969
|
+
await writeOutput(state.writer, state.summaries, SEARCH_ADAPTER_OUTPUT_PATH, buildSearchAdapterJs(), "application/javascript");
|
|
59974
60970
|
await maybeRenderNotFoundPage(state);
|
|
59975
60971
|
if (hasCanonicalSiteUrl(state.previewData.site.url)) {
|
|
59976
|
-
await writeOutput(
|
|
60972
|
+
await writeOutput(
|
|
60973
|
+
state.writer,
|
|
60974
|
+
state.summaries,
|
|
60975
|
+
"sitemap.xml",
|
|
60976
|
+
buildSitemapXml(state.previewData.site, state.emitted, state.generatedAt, options2.sitemapStylesheetHref),
|
|
60977
|
+
"application/xml"
|
|
60978
|
+
);
|
|
59977
60979
|
await writeOutput(state.writer, state.summaries, "feed.xml", buildFeedXml(state.previewData.site, state.emitted, state.generatedAt), "application/rss+xml");
|
|
59978
60980
|
}
|
|
59979
|
-
|
|
60981
|
+
if (shouldGenerateRobotsTxt(options2)) {
|
|
60982
|
+
await writeOutput(state.writer, state.summaries, "robots.txt", buildRobotsTxt(state.previewData.site), "text/plain");
|
|
60983
|
+
}
|
|
59980
60984
|
}
|
|
59981
60985
|
return finalizeBuildResult(state.writer, state.summaries, options2);
|
|
59982
60986
|
}
|
|
@@ -59989,7 +60993,7 @@ async function createBuildState(input2, options2) {
|
|
|
59989
60993
|
const engine = new ZeroPressEngine();
|
|
59990
60994
|
const assetProcessor = new AssetProcessor();
|
|
59991
60995
|
const summaries = [];
|
|
59992
|
-
const previewData = normalizePreviewData(input2.previewData);
|
|
60996
|
+
const previewData = normalizePreviewData(input2.previewData, options2);
|
|
59993
60997
|
const renderData = createRenderData(previewData, themePackage.metadata);
|
|
59994
60998
|
engine.initialize(themePackage);
|
|
59995
60999
|
const assetOutputs = await buildAssetOutputs(themePackage.assets, assetProcessor, options2);
|
|
@@ -60012,6 +61016,8 @@ async function createBuildState(input2, options2) {
|
|
|
60012
61016
|
assetMap,
|
|
60013
61017
|
customCssHref: customCssAsset ? `/${customCssAsset.path}` : "",
|
|
60014
61018
|
customHtml: previewData.custom_html,
|
|
61019
|
+
favicon: previewData.site.favicon,
|
|
61020
|
+
exposeGenerator: previewData.site.expose_generator !== false,
|
|
60015
61021
|
commentPolicyContent: buildCommentPolicyManifest(renderData.posts),
|
|
60016
61022
|
options: options2,
|
|
60017
61023
|
generatedAt: /* @__PURE__ */ new Date(),
|
|
@@ -60068,6 +61074,7 @@ async function renderRoute(state, templateName, route) {
|
|
|
60068
61074
|
{
|
|
60069
61075
|
menus: state.previewData.menus,
|
|
60070
61076
|
widgets: state.widgets,
|
|
61077
|
+
collections: state.renderData.collections,
|
|
60071
61078
|
taxonomies: state.renderData.taxonomies,
|
|
60072
61079
|
...route,
|
|
60073
61080
|
route: routeContext,
|
|
@@ -60111,6 +61118,7 @@ async function renderFrontPage(state, route) {
|
|
|
60111
61118
|
{
|
|
60112
61119
|
menus: state.previewData.menus,
|
|
60113
61120
|
widgets: state.widgets,
|
|
61121
|
+
collections: state.renderData.collections,
|
|
60114
61122
|
taxonomies: state.renderData.taxonomies,
|
|
60115
61123
|
page,
|
|
60116
61124
|
route: routeContext,
|
|
@@ -60119,7 +61127,8 @@ async function renderFrontPage(state, route) {
|
|
|
60119
61127
|
title: buildDocumentTitle(page.title, state.previewData.site.title),
|
|
60120
61128
|
description: page.excerpt,
|
|
60121
61129
|
ogType: "website",
|
|
60122
|
-
image: page.featured_image
|
|
61130
|
+
image: page.featured_image,
|
|
61131
|
+
robotsNoindex: shouldNoindexDocument(page)
|
|
60123
61132
|
})
|
|
60124
61133
|
},
|
|
60125
61134
|
createRenderContext(state.previewData.site, currentUrl)
|
|
@@ -60131,7 +61140,8 @@ async function renderFrontPage(state, route) {
|
|
|
60131
61140
|
url: currentUrl,
|
|
60132
61141
|
title: page.title,
|
|
60133
61142
|
description: page.excerpt,
|
|
60134
|
-
includeInFeed: false
|
|
61143
|
+
includeInFeed: false,
|
|
61144
|
+
includeInSitemap: !isDelistedDocument(page)
|
|
60135
61145
|
};
|
|
60136
61146
|
return;
|
|
60137
61147
|
}
|
|
@@ -60140,6 +61150,7 @@ async function renderFrontPage(state, route) {
|
|
|
60140
61150
|
{
|
|
60141
61151
|
menus: state.previewData.menus,
|
|
60142
61152
|
widgets: state.widgets,
|
|
61153
|
+
collections: state.renderData.collections,
|
|
60143
61154
|
taxonomies: state.renderData.taxonomies,
|
|
60144
61155
|
...route,
|
|
60145
61156
|
route: routeContext,
|
|
@@ -60169,6 +61180,7 @@ async function renderPost(state, post) {
|
|
|
60169
61180
|
{
|
|
60170
61181
|
menus: state.previewData.menus,
|
|
60171
61182
|
widgets: state.widgets,
|
|
61183
|
+
collections: state.renderData.collections,
|
|
60172
61184
|
taxonomies: state.renderData.taxonomies,
|
|
60173
61185
|
post,
|
|
60174
61186
|
route: buildRouteContext("post", currentUrl),
|
|
@@ -60179,7 +61191,8 @@ async function renderPost(state, post) {
|
|
|
60179
61191
|
ogType: "article",
|
|
60180
61192
|
image: post.featured_image,
|
|
60181
61193
|
publishedTime: post.published_at_iso,
|
|
60182
|
-
modifiedTime: post.updated_at_iso
|
|
61194
|
+
modifiedTime: post.updated_at_iso,
|
|
61195
|
+
robotsNoindex: shouldNoindexDocument(post)
|
|
60183
61196
|
})
|
|
60184
61197
|
},
|
|
60185
61198
|
createRenderContext(state.previewData.site, currentUrl)
|
|
@@ -60187,14 +61200,16 @@ async function renderPost(state, post) {
|
|
|
60187
61200
|
html = state.assetProcessor.updateAssetReferences(html, state.assetMap);
|
|
60188
61201
|
html = injectSiteCustomizations(html, state);
|
|
60189
61202
|
await writeOutput(state.writer, state.summaries, routePathToOutputPath(post.url, state.previewData.site.permalinks.output_style), html, "text/html");
|
|
60190
|
-
|
|
60191
|
-
|
|
60192
|
-
|
|
60193
|
-
|
|
60194
|
-
|
|
60195
|
-
|
|
60196
|
-
|
|
60197
|
-
|
|
61203
|
+
if (!isDelistedDocument(post)) {
|
|
61204
|
+
state.emitted.posts.push({
|
|
61205
|
+
url: currentUrl,
|
|
61206
|
+
title: post.title,
|
|
61207
|
+
description: post.excerpt,
|
|
61208
|
+
publishedAt: post.published_at_iso,
|
|
61209
|
+
updatedAt: post.updated_at_iso,
|
|
61210
|
+
status: post.status
|
|
61211
|
+
});
|
|
61212
|
+
}
|
|
60198
61213
|
}
|
|
60199
61214
|
async function renderPage(state, page) {
|
|
60200
61215
|
const currentUrl = page.url;
|
|
@@ -60205,6 +61220,7 @@ async function renderPage(state, page) {
|
|
|
60205
61220
|
{
|
|
60206
61221
|
menus: state.previewData.menus,
|
|
60207
61222
|
widgets: state.widgets,
|
|
61223
|
+
collections: state.renderData.collections,
|
|
60208
61224
|
taxonomies: state.renderData.taxonomies,
|
|
60209
61225
|
page,
|
|
60210
61226
|
route: buildRouteContext("page", currentUrl),
|
|
@@ -60214,7 +61230,8 @@ async function renderPage(state, page) {
|
|
|
60214
61230
|
title: buildDocumentTitle(page.title, state.previewData.site.title),
|
|
60215
61231
|
description: page.excerpt,
|
|
60216
61232
|
ogType: "website",
|
|
60217
|
-
image: page.featured_image
|
|
61233
|
+
image: page.featured_image,
|
|
61234
|
+
robotsNoindex: shouldNoindexDocument(page)
|
|
60218
61235
|
})
|
|
60219
61236
|
},
|
|
60220
61237
|
createRenderContext(state.previewData.site, currentUrl)
|
|
@@ -60227,7 +61244,7 @@ async function renderPage(state, page) {
|
|
|
60227
61244
|
title: page.title,
|
|
60228
61245
|
description: page.excerpt,
|
|
60229
61246
|
status: page.status,
|
|
60230
|
-
includeInSitemap: page.omit_from_sitemap !== true
|
|
61247
|
+
includeInSitemap: page.omit_from_sitemap !== true && !isDelistedDocument(page)
|
|
60231
61248
|
});
|
|
60232
61249
|
}
|
|
60233
61250
|
async function maybeRenderNotFoundPage(state) {
|
|
@@ -60239,6 +61256,7 @@ async function maybeRenderNotFoundPage(state) {
|
|
|
60239
61256
|
{
|
|
60240
61257
|
menus: state.previewData.menus,
|
|
60241
61258
|
widgets: state.widgets,
|
|
61259
|
+
collections: state.renderData.collections,
|
|
60242
61260
|
taxonomies: state.renderData.taxonomies,
|
|
60243
61261
|
route: buildRouteContext("not_found", "/404.html"),
|
|
60244
61262
|
meta: buildPageMeta(state.previewData.site, {
|
|
@@ -60254,76 +61272,220 @@ async function maybeRenderNotFoundPage(state) {
|
|
|
60254
61272
|
html = injectSiteCustomizations(html, state);
|
|
60255
61273
|
await writeOutput(state.writer, state.summaries, "404.html", html, "text/html");
|
|
60256
61274
|
}
|
|
60257
|
-
function normalizePreviewData(previewData) {
|
|
61275
|
+
function normalizePreviewData(previewData, options2 = {}) {
|
|
60258
61276
|
const normalizedSite = {
|
|
60259
61277
|
...previewData.site,
|
|
60260
|
-
|
|
60261
|
-
|
|
60262
|
-
|
|
60263
|
-
|
|
61278
|
+
media_base_url: normalizeOptionalString(previewData.site.media_base_url),
|
|
61279
|
+
media_delivery_mode: MEDIA_DELIVERY_MODES.has(previewData.site.media_delivery_mode) ? previewData.site.media_delivery_mode : "none",
|
|
61280
|
+
favicon: normalizeSiteFavicon(previewData.site.favicon || options2.favicon),
|
|
61281
|
+
posts_per_page: Number.isInteger(previewData.site.posts_per_page) && previewData.site.posts_per_page > 0 ? previewData.site.posts_per_page : DEFAULT_POSTS_PER_PAGE,
|
|
61282
|
+
datetime_display: DATETIME_DISPLAY_MODES.has(previewData.site.datetime_display) ? previewData.site.datetime_display : DEFAULT_DATETIME_DISPLAY,
|
|
61283
|
+
date_style: DATETIME_STYLES.has(previewData.site.date_style) ? previewData.site.date_style : DEFAULT_DATE_STYLE,
|
|
61284
|
+
time_style: DATETIME_STYLES.has(previewData.site.time_style) ? previewData.site.time_style : DEFAULT_TIME_STYLE,
|
|
60264
61285
|
timezone: normalizeNonEmptyString(previewData.site.timezone, DEFAULT_TIMEZONE),
|
|
60265
61286
|
locale: normalizeLocale(previewData.site.locale || DEFAULT_LOCALE),
|
|
60266
|
-
|
|
61287
|
+
disallow_comments: previewData.site.disallow_comments === true,
|
|
61288
|
+
expose_generator: previewData.site.expose_generator !== false,
|
|
61289
|
+
indexing: previewData.site.indexing !== false,
|
|
60267
61290
|
permalinks: normalizePermalinks(previewData.site.permalinks),
|
|
60268
61291
|
front_page: normalizeFrontPage(previewData.site.front_page),
|
|
60269
61292
|
post_index: normalizePostIndex(previewData.site.post_index),
|
|
60270
61293
|
footer: normalizeSiteFooter(previewData.site.footer)
|
|
60271
61294
|
};
|
|
61295
|
+
const media = normalizeContentMedia(previewData.content.media, normalizedSite);
|
|
61296
|
+
const mediaRegistry = buildMediaRegistry(media);
|
|
60272
61297
|
return {
|
|
60273
61298
|
...previewData,
|
|
60274
61299
|
site: normalizedSite,
|
|
60275
|
-
|
|
61300
|
+
menus: normalizeRecordMap(previewData.menus),
|
|
61301
|
+
collections: normalizeCollections(previewData.collections),
|
|
61302
|
+
widgets: normalizeWidgetAreas(previewData.widgets, normalizedSite.media_base_url),
|
|
60276
61303
|
custom_css: normalizeCustomCss(previewData.custom_css),
|
|
60277
61304
|
custom_html: normalizeCustomHtml(previewData.custom_html),
|
|
60278
61305
|
content: {
|
|
60279
61306
|
...previewData.content,
|
|
60280
|
-
authors: previewData.content.authors.map((author) =>
|
|
60281
|
-
|
|
60282
|
-
|
|
60283
|
-
|
|
60284
|
-
|
|
60285
|
-
|
|
60286
|
-
|
|
60287
|
-
|
|
60288
|
-
|
|
60289
|
-
|
|
60290
|
-
|
|
60291
|
-
|
|
60292
|
-
|
|
60293
|
-
|
|
61307
|
+
authors: previewData.content.authors.map((author) => {
|
|
61308
|
+
const avatar = normalizeMediaField(author.avatar, normalizedSite.media_base_url);
|
|
61309
|
+
const avatarMedia = deriveManagedMedia(avatar, mediaRegistry, normalizedSite);
|
|
61310
|
+
return {
|
|
61311
|
+
...author,
|
|
61312
|
+
avatar,
|
|
61313
|
+
...avatarMedia ? { avatar_media: avatarMedia } : {}
|
|
61314
|
+
};
|
|
61315
|
+
}),
|
|
61316
|
+
posts: previewData.content.posts.map((post) => {
|
|
61317
|
+
const featuredImage = normalizeMediaField(post.featured_image, normalizedSite.media_base_url);
|
|
61318
|
+
const featuredMedia = deriveManagedMedia(featuredImage, mediaRegistry, normalizedSite);
|
|
61319
|
+
return {
|
|
61320
|
+
...post,
|
|
61321
|
+
published_at_iso: normalizeIsoTimestamp(post.published_at_iso),
|
|
61322
|
+
updated_at_iso: normalizeIsoTimestamp(post.updated_at_iso),
|
|
61323
|
+
discoverability: normalizeDiscoverability(post.discoverability),
|
|
61324
|
+
featured_image: featuredImage,
|
|
61325
|
+
...featuredMedia ? { featured_media: featuredMedia } : {}
|
|
61326
|
+
};
|
|
61327
|
+
}).sort((left, right) => toDate(right.published_at_iso).getTime() - toDate(left.published_at_iso).getTime()),
|
|
61328
|
+
pages: previewData.content.pages.map((page) => {
|
|
61329
|
+
const featuredImage = normalizeMediaField(page.featured_image, normalizedSite.media_base_url);
|
|
61330
|
+
const featuredMedia = deriveManagedMedia(featuredImage, mediaRegistry, normalizedSite);
|
|
61331
|
+
return {
|
|
61332
|
+
...page,
|
|
61333
|
+
discoverability: normalizeDiscoverability(page.discoverability),
|
|
61334
|
+
featured_image: featuredImage,
|
|
61335
|
+
...featuredMedia ? { featured_media: featuredMedia } : {}
|
|
61336
|
+
};
|
|
61337
|
+
}),
|
|
60294
61338
|
categories: [...previewData.content.categories],
|
|
60295
|
-
tags: [...previewData.content.tags]
|
|
61339
|
+
tags: [...previewData.content.tags],
|
|
61340
|
+
media
|
|
60296
61341
|
}
|
|
60297
61342
|
};
|
|
60298
61343
|
}
|
|
60299
|
-
function
|
|
60300
|
-
if (!
|
|
61344
|
+
function normalizeRecordMap(value) {
|
|
61345
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
61346
|
+
return {};
|
|
61347
|
+
}
|
|
61348
|
+
return { ...value };
|
|
61349
|
+
}
|
|
61350
|
+
function normalizeDiscoverability(value) {
|
|
61351
|
+
return DISCOVERABILITY_VALUES.has(value) ? value : "default";
|
|
61352
|
+
}
|
|
61353
|
+
function isDelistedDocument(document2) {
|
|
61354
|
+
return document2?.discoverability === "delist";
|
|
61355
|
+
}
|
|
61356
|
+
function shouldNoindexDocument(document2) {
|
|
61357
|
+
return document2?.discoverability === "noindex" || document2?.discoverability === "delist";
|
|
61358
|
+
}
|
|
61359
|
+
function normalizeContentMedia(mediaItems, site) {
|
|
61360
|
+
if (!Array.isArray(mediaItems)) {
|
|
61361
|
+
return [];
|
|
61362
|
+
}
|
|
61363
|
+
return mediaItems.map((item) => {
|
|
61364
|
+
if (!item || typeof item !== "object") {
|
|
61365
|
+
return null;
|
|
61366
|
+
}
|
|
61367
|
+
const src = normalizeMediaField(item.src, site.media_base_url);
|
|
61368
|
+
const width = Number.isInteger(item.width) && item.width > 0 ? item.width : 0;
|
|
61369
|
+
const height = Number.isInteger(item.height) && item.height > 0 ? item.height : 0;
|
|
61370
|
+
if (!src || !width || !height) {
|
|
61371
|
+
return null;
|
|
61372
|
+
}
|
|
61373
|
+
return {
|
|
61374
|
+
src,
|
|
61375
|
+
width,
|
|
61376
|
+
height,
|
|
61377
|
+
alt: typeof item.alt === "string" ? item.alt : ""
|
|
61378
|
+
};
|
|
61379
|
+
}).filter(Boolean);
|
|
61380
|
+
}
|
|
61381
|
+
function buildMediaRegistry(mediaItems) {
|
|
61382
|
+
const registry = /* @__PURE__ */ new Map();
|
|
61383
|
+
for (const item of mediaItems) {
|
|
61384
|
+
if (!registry.has(item.src)) {
|
|
61385
|
+
registry.set(item.src, item);
|
|
61386
|
+
}
|
|
61387
|
+
}
|
|
61388
|
+
return registry;
|
|
61389
|
+
}
|
|
61390
|
+
function deriveManagedMedia(src, mediaRegistry, site) {
|
|
61391
|
+
const normalizedSrc = normalizeOptionalString(src);
|
|
61392
|
+
if (!normalizedSrc) {
|
|
61393
|
+
return null;
|
|
61394
|
+
}
|
|
61395
|
+
const media = mediaRegistry.get(normalizedSrc);
|
|
61396
|
+
if (!media) {
|
|
61397
|
+
return null;
|
|
61398
|
+
}
|
|
61399
|
+
return {
|
|
61400
|
+
...media,
|
|
61401
|
+
srcset: buildResponsiveImageSrcset(media, site)
|
|
61402
|
+
};
|
|
61403
|
+
}
|
|
61404
|
+
function buildResponsiveImageSrcset(media, site) {
|
|
61405
|
+
if (site.media_delivery_mode !== "media_domain") {
|
|
61406
|
+
return "";
|
|
61407
|
+
}
|
|
61408
|
+
const media_base_url = normalizeOptionalString(site.media_base_url);
|
|
61409
|
+
if (!media_base_url || !isUrlUnderMediaBase(media.src, media_base_url) || !isResponsiveRasterImage(media.src)) {
|
|
61410
|
+
return "";
|
|
61411
|
+
}
|
|
61412
|
+
const widths = RESPONSIVE_IMAGE_WIDTHS.filter((width) => width <= media.width);
|
|
61413
|
+
if (!widths.includes(media.width)) {
|
|
61414
|
+
widths.push(media.width);
|
|
61415
|
+
}
|
|
61416
|
+
return widths.filter((width, index, values) => width > 0 && values.indexOf(width) === index).map((width) => `${buildResponsiveImageVariantUrl(media.src, width)} ${width}w`).join(", ");
|
|
61417
|
+
}
|
|
61418
|
+
function buildResponsiveImageVariantUrl(src, width) {
|
|
61419
|
+
try {
|
|
61420
|
+
const url = new URL(src);
|
|
61421
|
+
url.searchParams.set("w", String(width));
|
|
61422
|
+
url.searchParams.set("fit", "scale-down");
|
|
61423
|
+
url.searchParams.set("format", "auto");
|
|
61424
|
+
return decodeURI(url.toString());
|
|
61425
|
+
} catch {
|
|
61426
|
+
return src;
|
|
61427
|
+
}
|
|
61428
|
+
}
|
|
61429
|
+
function isUrlUnderMediaBase(src, media_base_url) {
|
|
61430
|
+
try {
|
|
61431
|
+
const sourceUrl = new URL(src);
|
|
61432
|
+
const baseUrl = new URL(media_base_url);
|
|
61433
|
+
const basePath = baseUrl.pathname.endsWith("/") ? baseUrl.pathname : `${baseUrl.pathname}/`;
|
|
61434
|
+
return sourceUrl.origin === baseUrl.origin && sourceUrl.pathname.startsWith(basePath);
|
|
61435
|
+
} catch {
|
|
61436
|
+
return false;
|
|
61437
|
+
}
|
|
61438
|
+
}
|
|
61439
|
+
function isResponsiveRasterImage(src) {
|
|
61440
|
+
try {
|
|
61441
|
+
const url = new URL(src);
|
|
61442
|
+
const lastSegment = url.pathname.split("/").pop() || "";
|
|
61443
|
+
const extension = lastSegment.includes(".") ? lastSegment.split(".").pop().toLowerCase() : "";
|
|
61444
|
+
return RESPONSIVE_IMAGE_EXTENSIONS.has(extension);
|
|
61445
|
+
} catch {
|
|
61446
|
+
return false;
|
|
61447
|
+
}
|
|
61448
|
+
}
|
|
61449
|
+
function normalizeCollections(collections) {
|
|
61450
|
+
if (!collections || typeof collections !== "object" || Array.isArray(collections)) {
|
|
60301
61451
|
return {};
|
|
60302
61452
|
}
|
|
60303
61453
|
return Object.fromEntries(
|
|
60304
|
-
Object.entries(
|
|
61454
|
+
Object.entries(collections).map(([collectionId, collection]) => [
|
|
61455
|
+
collectionId,
|
|
61456
|
+
{
|
|
61457
|
+
...collection,
|
|
61458
|
+
title: normalizeOptionalString(collection?.title),
|
|
61459
|
+
description: normalizeOptionalString(collection?.description),
|
|
61460
|
+
items: Array.isArray(collection?.items) ? collection.items.map((item) => ({ ...item })) : []
|
|
61461
|
+
}
|
|
61462
|
+
])
|
|
61463
|
+
);
|
|
61464
|
+
}
|
|
61465
|
+
function normalizeWidgetAreas(widget_areas, media_base_url) {
|
|
61466
|
+
if (!widget_areas || typeof widget_areas !== "object") {
|
|
61467
|
+
return {};
|
|
61468
|
+
}
|
|
61469
|
+
return Object.fromEntries(
|
|
61470
|
+
Object.entries(widget_areas).map(([widgetAreaId, widgetArea]) => [
|
|
60305
61471
|
widgetAreaId,
|
|
60306
61472
|
{
|
|
60307
61473
|
...widgetArea,
|
|
60308
61474
|
name: normalizeNonEmptyString(widgetArea?.name, widgetAreaId),
|
|
60309
|
-
items: Array.isArray(widgetArea?.items) ? widgetArea.items.map((item) => normalizeWidgetItem(item,
|
|
61475
|
+
items: Array.isArray(widgetArea?.items) ? widgetArea.items.map((item) => normalizeWidgetItem(item, media_base_url)) : []
|
|
60310
61476
|
}
|
|
60311
61477
|
])
|
|
60312
61478
|
);
|
|
60313
61479
|
}
|
|
60314
61480
|
function normalizeSiteFooter(footer) {
|
|
60315
61481
|
const source = footer && typeof footer === "object" && !Array.isArray(footer) ? footer : {};
|
|
60316
|
-
const attribution = source.attribution && typeof source.attribution === "object" && !Array.isArray(source.attribution) ? source.attribution : {};
|
|
60317
61482
|
return {
|
|
60318
61483
|
...source,
|
|
60319
61484
|
copyright_text: normalizeOptionalString(source.copyright_text),
|
|
60320
|
-
attribution:
|
|
60321
|
-
...attribution,
|
|
60322
|
-
enabled: attribution.enabled !== false
|
|
60323
|
-
}
|
|
61485
|
+
attribution: source.attribution !== false
|
|
60324
61486
|
};
|
|
60325
61487
|
}
|
|
60326
|
-
function normalizeWidgetItem(item,
|
|
61488
|
+
function normalizeWidgetItem(item, media_base_url) {
|
|
60327
61489
|
const normalizedItem = {
|
|
60328
61490
|
...item,
|
|
60329
61491
|
title: typeof item?.title === "string" ? item.title.trim() : ""
|
|
@@ -60333,7 +61495,7 @@ function normalizeWidgetItem(item, mediaBaseUrl) {
|
|
|
60333
61495
|
...normalizedItem,
|
|
60334
61496
|
settings: {
|
|
60335
61497
|
...item.settings,
|
|
60336
|
-
avatar: normalizeMediaField(item.settings.avatar,
|
|
61498
|
+
avatar: normalizeMediaField(item.settings.avatar, media_base_url)
|
|
60337
61499
|
}
|
|
60338
61500
|
};
|
|
60339
61501
|
}
|
|
@@ -60357,6 +61519,19 @@ function normalizeCustomHtml(customHtml) {
|
|
|
60357
61519
|
...bodyEnd ? { body_end: { content: bodyEnd } } : {}
|
|
60358
61520
|
};
|
|
60359
61521
|
}
|
|
61522
|
+
function normalizeSiteFavicon(favicon) {
|
|
61523
|
+
if (!favicon || typeof favicon !== "object") {
|
|
61524
|
+
return void 0;
|
|
61525
|
+
}
|
|
61526
|
+
const normalized = {};
|
|
61527
|
+
for (const key of ["icon", "svg", "png", "apple_touch_icon"]) {
|
|
61528
|
+
const value = normalizeOptionalString(favicon[key]);
|
|
61529
|
+
if (value) {
|
|
61530
|
+
normalized[key] = value;
|
|
61531
|
+
}
|
|
61532
|
+
}
|
|
61533
|
+
return Object.keys(normalized).length ? normalized : void 0;
|
|
61534
|
+
}
|
|
60360
61535
|
function normalizePermalinks(permalinks) {
|
|
60361
61536
|
const source = permalinks && typeof permalinks === "object" ? permalinks : {};
|
|
60362
61537
|
const outputStyle = typeof source.output_style === "string" && PERMALINK_OUTPUT_STYLES.has(source.output_style) ? source.output_style : DEFAULT_PERMALINKS.output_style;
|
|
@@ -60379,19 +61554,19 @@ function normalizeFrontPage(frontPage) {
|
|
|
60379
61554
|
...type === "standalone_html" ? { html: normalizeOptionalRawString(frontPage.html) } : {}
|
|
60380
61555
|
};
|
|
60381
61556
|
}
|
|
60382
|
-
function normalizePostIndex(
|
|
60383
|
-
if (!
|
|
61557
|
+
function normalizePostIndex(post_index) {
|
|
61558
|
+
if (!post_index || typeof post_index !== "object") {
|
|
60384
61559
|
return { ...DEFAULT_POST_INDEX };
|
|
60385
61560
|
}
|
|
60386
61561
|
return {
|
|
60387
|
-
enabled:
|
|
60388
|
-
path: normalizeNonEmptyString(
|
|
60389
|
-
paginate:
|
|
61562
|
+
enabled: post_index.enabled !== false,
|
|
61563
|
+
path: normalizeNonEmptyString(post_index.path, DEFAULT_POST_INDEX.path),
|
|
61564
|
+
paginate: post_index.paginate !== false
|
|
60390
61565
|
};
|
|
60391
61566
|
}
|
|
60392
61567
|
function createRenderData(previewData, themeMetadata = {}) {
|
|
60393
61568
|
const themeSupportsComments = themeMetadata?.features?.comments === true;
|
|
60394
|
-
const themeSupportsPostIndex = themeMetadata?.features?.
|
|
61569
|
+
const themeSupportsPostIndex = themeMetadata?.features?.post_index !== false;
|
|
60395
61570
|
const authorsById = new Map(previewData.content.authors.map((author) => [author.id, author]));
|
|
60396
61571
|
const categoriesBySlug = new Map(previewData.content.categories.map((category) => [category.slug, category]));
|
|
60397
61572
|
const tagsBySlug = new Map(previewData.content.tags.map((tag) => [tag.slug, tag]));
|
|
@@ -60399,7 +61574,8 @@ function createRenderData(previewData, themeMetadata = {}) {
|
|
|
60399
61574
|
const tagPostsBySlug = /* @__PURE__ */ new Map();
|
|
60400
61575
|
const categoryCountBySlug = /* @__PURE__ */ new Map();
|
|
60401
61576
|
const tagCountBySlug = /* @__PURE__ */ new Map();
|
|
60402
|
-
|
|
61577
|
+
const discoverableSourcePosts = previewData.content.posts.filter((post) => !isDelistedDocument(post));
|
|
61578
|
+
for (const post of discoverableSourcePosts) {
|
|
60403
61579
|
for (const slug of post.category_slugs) {
|
|
60404
61580
|
pushToSlugMap(categoryPostsBySlug, slug, post);
|
|
60405
61581
|
categoryCountBySlug.set(slug, (categoryCountBySlug.get(slug) || 0) + 1);
|
|
@@ -60410,43 +61586,54 @@ function createRenderData(previewData, themeMetadata = {}) {
|
|
|
60410
61586
|
}
|
|
60411
61587
|
}
|
|
60412
61588
|
const preparedPosts = previewData.content.posts.map((post) => preparePost(post, previewData.site, authorsById, categoriesBySlug, tagsBySlug, themeSupportsComments));
|
|
60413
|
-
const
|
|
61589
|
+
const discoverablePreparedPosts = preparedPosts.filter((post) => !isDelistedDocument(post));
|
|
61590
|
+
const adjacentPostsBySlug = new Map(
|
|
61591
|
+
discoverablePreparedPosts.map((post, index) => [post.slug, {
|
|
61592
|
+
prev: index > 0 ? buildAdjacentPostSummary(discoverablePreparedPosts[index - 1]) : null,
|
|
61593
|
+
next: index < discoverablePreparedPosts.length - 1 ? buildAdjacentPostSummary(discoverablePreparedPosts[index + 1]) : null
|
|
61594
|
+
}])
|
|
61595
|
+
);
|
|
61596
|
+
const posts = preparedPosts.map((post) => ({
|
|
60414
61597
|
...post,
|
|
60415
|
-
prev:
|
|
60416
|
-
next:
|
|
61598
|
+
prev: adjacentPostsBySlug.get(post.slug)?.prev || null,
|
|
61599
|
+
next: adjacentPostsBySlug.get(post.slug)?.next || null
|
|
60417
61600
|
}));
|
|
60418
61601
|
const pages = previewData.content.pages.map((page) => preparePage(page, previewData.site));
|
|
60419
61602
|
const postBySlug = new Map(posts.map((post) => [post.slug, post]));
|
|
61603
|
+
const pageBySlug = new Map(pages.map((page) => [page.slug, page]));
|
|
60420
61604
|
const frontPage = previewData.site.front_page;
|
|
60421
|
-
const
|
|
60422
|
-
|
|
60423
|
-
const
|
|
60424
|
-
const
|
|
60425
|
-
|
|
61605
|
+
const collections = resolveCollections(previewData.collections, postBySlug, pageBySlug, frontPage);
|
|
61606
|
+
attachCollectionCursors(posts, pages, collections);
|
|
61607
|
+
const post_index = previewData.site.post_index;
|
|
61608
|
+
const effectivePostIndexEnabled = post_index.enabled !== false && themeSupportsPostIndex;
|
|
61609
|
+
const effectivePostIndexPaginate = effectivePostIndexEnabled && post_index.paginate !== false;
|
|
61610
|
+
const post_indexBasePath = normalizeRoutePath(post_index.path || DEFAULT_POST_INDEX.path);
|
|
61611
|
+
if (frontPage.type !== "theme_index" && effectivePostIndexEnabled && post_indexBasePath === "/") {
|
|
60426
61612
|
throw new Error('Invalid front page configuration: site.front_page occupies "/" so site.post_index.path must not be "/". Set site.post_index.path to a non-root path or disable site.post_index.');
|
|
60427
61613
|
}
|
|
60428
|
-
const frontPageRoute = buildFrontPageRoute(frontPage, pages, effectivePostIndexEnabled,
|
|
61614
|
+
const frontPageRoute = buildFrontPageRoute(frontPage, pages, effectivePostIndexEnabled, post_indexBasePath);
|
|
60429
61615
|
const pageFrontPageSlug = frontPage.type === "page" ? frontPage.page_slug : "";
|
|
60430
61616
|
const preparedPages = pageFrontPageSlug ? pages.filter((page) => page.slug !== pageFrontPageSlug) : pages;
|
|
60431
61617
|
return {
|
|
60432
61618
|
posts,
|
|
60433
61619
|
pages: preparedPages,
|
|
60434
61620
|
postBySlug,
|
|
61621
|
+
collections,
|
|
60435
61622
|
taxonomies: buildGlobalTaxonomies(previewData, categoryCountBySlug, tagCountBySlug),
|
|
60436
61623
|
frontPageRoute,
|
|
60437
61624
|
indexRoutes: buildPostIndexRoutes({
|
|
60438
61625
|
enabled: effectivePostIndexEnabled,
|
|
60439
61626
|
paginate: effectivePostIndexPaginate,
|
|
60440
|
-
items:
|
|
60441
|
-
|
|
60442
|
-
basePath:
|
|
61627
|
+
items: discoverableSourcePosts,
|
|
61628
|
+
posts_per_page: previewData.site.posts_per_page,
|
|
61629
|
+
basePath: post_indexBasePath,
|
|
60443
61630
|
outputStyle: previewData.site.permalinks.output_style,
|
|
60444
61631
|
postBySlug,
|
|
60445
61632
|
frontPage
|
|
60446
61633
|
}),
|
|
60447
61634
|
archiveRoutes: buildPaginatedCollection({
|
|
60448
|
-
items:
|
|
60449
|
-
|
|
61635
|
+
items: discoverableSourcePosts,
|
|
61636
|
+
posts_per_page: previewData.site.posts_per_page,
|
|
60450
61637
|
basePath: "/archive/",
|
|
60451
61638
|
outputStyle: previewData.site.permalinks.output_style
|
|
60452
61639
|
}).map((entry) => ({
|
|
@@ -60462,7 +61649,7 @@ function createRenderData(previewData, themeMetadata = {}) {
|
|
|
60462
61649
|
items: previewData.content.categories,
|
|
60463
61650
|
postsBySlug: categoryPostsBySlug,
|
|
60464
61651
|
postBySlug,
|
|
60465
|
-
|
|
61652
|
+
posts_per_page: previewData.site.posts_per_page,
|
|
60466
61653
|
outputStyle: previewData.site.permalinks.output_style,
|
|
60467
61654
|
buildBasePath: (category) => resolvePermalink(previewData.site, "categories", category).path,
|
|
60468
61655
|
renderExtras: (category) => ({
|
|
@@ -60473,7 +61660,7 @@ function createRenderData(previewData, themeMetadata = {}) {
|
|
|
60473
61660
|
items: previewData.content.tags,
|
|
60474
61661
|
postsBySlug: tagPostsBySlug,
|
|
60475
61662
|
postBySlug,
|
|
60476
|
-
|
|
61663
|
+
posts_per_page: previewData.site.posts_per_page,
|
|
60477
61664
|
outputStyle: previewData.site.permalinks.output_style,
|
|
60478
61665
|
buildBasePath: (tag) => resolvePermalink(previewData.site, "tags", tag).path,
|
|
60479
61666
|
renderExtras: (tag) => ({
|
|
@@ -60488,9 +61675,113 @@ function buildGlobalTaxonomies(previewData, categoryCountBySlug, tagCountBySlug)
|
|
|
60488
61675
|
tags: buildGlobalTaxonomyItems(previewData.site, "tags", previewData.content.tags, tagCountBySlug)
|
|
60489
61676
|
};
|
|
60490
61677
|
}
|
|
60491
|
-
function
|
|
61678
|
+
function resolveCollections(collections, postBySlug, pageBySlug, frontPage) {
|
|
61679
|
+
if (!collections || typeof collections !== "object") {
|
|
61680
|
+
return {};
|
|
61681
|
+
}
|
|
61682
|
+
return Object.fromEntries(
|
|
61683
|
+
Object.entries(collections).map(([collectionId, collection]) => {
|
|
61684
|
+
const items = resolveCollectionItems(collectionId, collection?.items, postBySlug, pageBySlug, frontPage);
|
|
61685
|
+
return [
|
|
61686
|
+
collectionId,
|
|
61687
|
+
{
|
|
61688
|
+
id: collectionId,
|
|
61689
|
+
title: normalizeOptionalString(collection?.title),
|
|
61690
|
+
description: normalizeOptionalString(collection?.description),
|
|
61691
|
+
count: items.length,
|
|
61692
|
+
items
|
|
61693
|
+
}
|
|
61694
|
+
];
|
|
61695
|
+
})
|
|
61696
|
+
);
|
|
61697
|
+
}
|
|
61698
|
+
function resolveCollectionItems(collectionId, items, postBySlug, pageBySlug, frontPage) {
|
|
61699
|
+
if (!Array.isArray(items)) {
|
|
61700
|
+
return [];
|
|
61701
|
+
}
|
|
61702
|
+
return items.map((item, index) => resolveCollectionItem(collectionId, item, index, postBySlug, pageBySlug, frontPage));
|
|
61703
|
+
}
|
|
61704
|
+
function resolveCollectionItem(collectionId, item, index, postBySlug, pageBySlug, frontPage) {
|
|
61705
|
+
if (item?.type === "post") {
|
|
61706
|
+
const post = postBySlug.get(item.slug);
|
|
61707
|
+
if (!post) {
|
|
61708
|
+
throw new Error(`Invalid collection "${collectionId}": item ${index + 1} references missing post slug "${item.slug}".`);
|
|
61709
|
+
}
|
|
61710
|
+
return {
|
|
61711
|
+
type: "post",
|
|
61712
|
+
meta: post.meta,
|
|
61713
|
+
...buildStructuredPostSummary(post)
|
|
61714
|
+
};
|
|
61715
|
+
}
|
|
61716
|
+
if (item?.type === "page") {
|
|
61717
|
+
const page = pageBySlug.get(item.slug);
|
|
61718
|
+
if (!page) {
|
|
61719
|
+
throw new Error(`Invalid collection "${collectionId}": item ${index + 1} references missing page slug "${item.slug}".`);
|
|
61720
|
+
}
|
|
61721
|
+
return buildCollectionPageSummary(page, frontPage);
|
|
61722
|
+
}
|
|
61723
|
+
throw new Error(`Invalid collection "${collectionId}": item ${index + 1} has unsupported type "${item?.type}".`);
|
|
61724
|
+
}
|
|
61725
|
+
function buildCollectionPageSummary(page, frontPage) {
|
|
61726
|
+
return {
|
|
61727
|
+
type: "page",
|
|
61728
|
+
title: page.title,
|
|
61729
|
+
slug: page.slug,
|
|
61730
|
+
url: frontPage?.type === "page" && frontPage.page_slug === page.slug ? "/" : page.url,
|
|
61731
|
+
excerpt: page.excerpt || "",
|
|
61732
|
+
featured_image: page.featured_image || "",
|
|
61733
|
+
...page.featured_media ? { featured_media: { ...page.featured_media } } : {},
|
|
61734
|
+
meta: page.meta,
|
|
61735
|
+
data: page.data
|
|
61736
|
+
};
|
|
61737
|
+
}
|
|
61738
|
+
function attachCollectionCursors(posts, pages, collections) {
|
|
61739
|
+
const postTargets = new Map(posts.map((post) => [post.slug, post]));
|
|
61740
|
+
const pageTargets = new Map(pages.map((page) => [page.slug, page]));
|
|
61741
|
+
for (const [collectionId, collection] of Object.entries(collections || {})) {
|
|
61742
|
+
const items = Array.isArray(collection.items) ? collection.items : [];
|
|
61743
|
+
items.forEach((item, index) => {
|
|
61744
|
+
const target = item.type === "post" ? postTargets.get(item.slug) : item.type === "page" ? pageTargets.get(item.slug) : null;
|
|
61745
|
+
if (!target) {
|
|
61746
|
+
return;
|
|
61747
|
+
}
|
|
61748
|
+
target.collection_cursors = target.collection_cursors || {};
|
|
61749
|
+
target.collection_cursors[collectionId] = buildCollectionCursor(collectionId, collection, items, index);
|
|
61750
|
+
});
|
|
61751
|
+
}
|
|
61752
|
+
}
|
|
61753
|
+
function buildCollectionCursor(collectionId, collection, items, index) {
|
|
61754
|
+
const count = items.length;
|
|
61755
|
+
return {
|
|
61756
|
+
collection_id: collectionId,
|
|
61757
|
+
collection_title: collection.title || "",
|
|
61758
|
+
index,
|
|
61759
|
+
position: index + 1,
|
|
61760
|
+
count,
|
|
61761
|
+
first: index === 0,
|
|
61762
|
+
last: index === count - 1,
|
|
61763
|
+
prev: index > 0 ? buildCollectionCursorItemSummary(items[index - 1]) : null,
|
|
61764
|
+
next: index < count - 1 ? buildCollectionCursorItemSummary(items[index + 1]) : null
|
|
61765
|
+
};
|
|
61766
|
+
}
|
|
61767
|
+
function buildCollectionCursorItemSummary(item) {
|
|
61768
|
+
if (!item) {
|
|
61769
|
+
return null;
|
|
61770
|
+
}
|
|
61771
|
+
return {
|
|
61772
|
+
type: item.type,
|
|
61773
|
+
title: item.title,
|
|
61774
|
+
slug: item.slug,
|
|
61775
|
+
url: item.url,
|
|
61776
|
+
excerpt: item.excerpt || "",
|
|
61777
|
+
featured_image: item.featured_image || "",
|
|
61778
|
+
meta: item.meta,
|
|
61779
|
+
data: item.data
|
|
61780
|
+
};
|
|
61781
|
+
}
|
|
61782
|
+
function buildFrontPageRoute(frontPage, pages, effectivePostIndexEnabled, post_indexBasePath) {
|
|
60492
61783
|
if (frontPage.type === "theme_index") {
|
|
60493
|
-
if (effectivePostIndexEnabled &&
|
|
61784
|
+
if (effectivePostIndexEnabled && post_indexBasePath === "/") {
|
|
60494
61785
|
return null;
|
|
60495
61786
|
}
|
|
60496
61787
|
return {
|
|
@@ -60528,7 +61819,7 @@ function buildPostIndexRoutes(options2) {
|
|
|
60528
61819
|
return [];
|
|
60529
61820
|
}
|
|
60530
61821
|
if (!options2.paginate) {
|
|
60531
|
-
const items = options2.items.slice(0, options2.
|
|
61822
|
+
const items = options2.items.slice(0, options2.posts_per_page);
|
|
60532
61823
|
return [{
|
|
60533
61824
|
path: options2.basePath,
|
|
60534
61825
|
route_type: "post_index",
|
|
@@ -60542,7 +61833,7 @@ function buildPostIndexRoutes(options2) {
|
|
|
60542
61833
|
}
|
|
60543
61834
|
return buildPaginatedCollection({
|
|
60544
61835
|
items: options2.items,
|
|
60545
|
-
|
|
61836
|
+
posts_per_page: options2.posts_per_page,
|
|
60546
61837
|
basePath: options2.basePath,
|
|
60547
61838
|
outputStyle: options2.outputStyle
|
|
60548
61839
|
}).map((entry) => ({
|
|
@@ -60621,7 +61912,7 @@ function resolveWidgetItem(item, previewData, renderData, widgetAreaId, index) {
|
|
|
60621
61912
|
}
|
|
60622
61913
|
function resolveRecentPostsWidget(baseWidget, settings, renderData) {
|
|
60623
61914
|
const limit = clampInteger(settings?.limit, 5, 1, 20);
|
|
60624
|
-
const items = renderData.posts.slice(0, limit).map((post) => ({
|
|
61915
|
+
const items = renderData.posts.filter((post) => !isDelistedDocument(post)).slice(0, limit).map((post) => ({
|
|
60625
61916
|
title: post.title,
|
|
60626
61917
|
url: `/posts/${encodeSlugSegment(post.slug)}/`,
|
|
60627
61918
|
published_at: post.published_at,
|
|
@@ -60788,15 +62079,19 @@ function preparePost(post, site, authorsById, categoriesBySlug, tagsBySlug, them
|
|
|
60788
62079
|
updated_at_iso: post.updated_at_iso,
|
|
60789
62080
|
author_id: post.author_id,
|
|
60790
62081
|
featured_image: post.featured_image,
|
|
62082
|
+
...post.featured_media ? { featured_media: { ...post.featured_media } } : {},
|
|
60791
62083
|
meta: post.meta,
|
|
62084
|
+
data: post.data,
|
|
60792
62085
|
status: post.status,
|
|
62086
|
+
discoverability: post.discoverability,
|
|
60793
62087
|
allow_comments: post.allow_comments,
|
|
60794
62088
|
category_slugs: post.category_slugs,
|
|
60795
62089
|
tag_slugs: post.tag_slugs,
|
|
60796
62090
|
author: {
|
|
60797
62091
|
id: post.author_id,
|
|
60798
62092
|
display_name: normalizeNonEmptyString(author?.display_name, post.author_id),
|
|
60799
|
-
avatar: author?.avatar || ""
|
|
62093
|
+
avatar: author?.avatar || "",
|
|
62094
|
+
...author?.avatar_media ? { avatar_media: { ...author.avatar_media } } : {}
|
|
60800
62095
|
},
|
|
60801
62096
|
categories,
|
|
60802
62097
|
tags,
|
|
@@ -60805,7 +62100,7 @@ function preparePost(post, site, authorsById, categoriesBySlug, tagsBySlug, them
|
|
|
60805
62100
|
published_at: formatTimestamp(post.published_at_iso, site),
|
|
60806
62101
|
updated_at: formatTimestamp(post.updated_at_iso, site),
|
|
60807
62102
|
reading_time: calculateReadingTime(renderedDocument.html),
|
|
60808
|
-
comments_enabled: themeSupportsComments && site.
|
|
62103
|
+
comments_enabled: themeSupportsComments && site.disallow_comments !== true && post.allow_comments === true
|
|
60809
62104
|
};
|
|
60810
62105
|
}
|
|
60811
62106
|
function buildCommentPolicyManifest(posts) {
|
|
@@ -60824,7 +62119,7 @@ function buildTaxonomyRoutes(options2) {
|
|
|
60824
62119
|
}
|
|
60825
62120
|
const paginated = buildPaginatedCollection({
|
|
60826
62121
|
items: matchedPosts,
|
|
60827
|
-
|
|
62122
|
+
posts_per_page: options2.posts_per_page,
|
|
60828
62123
|
basePath: options2.buildBasePath(item),
|
|
60829
62124
|
outputStyle: options2.outputStyle
|
|
60830
62125
|
});
|
|
@@ -60845,13 +62140,13 @@ function buildTaxonomyRoutes(options2) {
|
|
|
60845
62140
|
function buildPaginatedCollection(options2) {
|
|
60846
62141
|
const basePath = normalizePaginationBasePath(options2.basePath);
|
|
60847
62142
|
const outputStyle = PERMALINK_OUTPUT_STYLES.has(options2.outputStyle) ? options2.outputStyle : DEFAULT_PERMALINKS.output_style;
|
|
60848
|
-
const
|
|
62143
|
+
const posts_per_page = Number.isInteger(options2.posts_per_page) && options2.posts_per_page > 0 ? options2.posts_per_page : DEFAULT_POSTS_PER_PAGE;
|
|
60849
62144
|
const totalPosts = options2.items.length;
|
|
60850
|
-
const totalPages = Math.max(1, Math.ceil(totalPosts /
|
|
62145
|
+
const totalPages = Math.max(1, Math.ceil(totalPosts / posts_per_page));
|
|
60851
62146
|
const pages = [];
|
|
60852
62147
|
for (let page = 1; page <= totalPages; page += 1) {
|
|
60853
|
-
const start = (page - 1) *
|
|
60854
|
-
const end = start +
|
|
62148
|
+
const start = (page - 1) * posts_per_page;
|
|
62149
|
+
const end = start + posts_per_page;
|
|
60855
62150
|
pages.push({
|
|
60856
62151
|
path: buildPaginatedPath(basePath, page),
|
|
60857
62152
|
page,
|
|
@@ -60998,9 +62293,13 @@ function buildStructuredPostSummary(post) {
|
|
|
60998
62293
|
published_at_iso: post.published_at_iso,
|
|
60999
62294
|
reading_time: post.reading_time,
|
|
61000
62295
|
featured_image: post.featured_image,
|
|
62296
|
+
...post.featured_media ? { featured_media: { ...post.featured_media } } : {},
|
|
62297
|
+
meta: post.meta,
|
|
62298
|
+
data: post.data,
|
|
61001
62299
|
author: {
|
|
61002
62300
|
display_name: post.author?.display_name || "",
|
|
61003
|
-
avatar: post.author?.avatar || ""
|
|
62301
|
+
avatar: post.author?.avatar || "",
|
|
62302
|
+
...post.author?.avatar_media ? { avatar_media: { ...post.author.avatar_media } } : {}
|
|
61004
62303
|
},
|
|
61005
62304
|
categories: Array.isArray(post.categories) ? post.categories.map((category) => ({ ...category })) : [],
|
|
61006
62305
|
tags: Array.isArray(post.tags) ? post.tags.map((tag) => ({ ...tag })) : []
|
|
@@ -61016,7 +62315,8 @@ function buildAdjacentPostSummary(post) {
|
|
|
61016
62315
|
url: post.url,
|
|
61017
62316
|
excerpt: post.excerpt,
|
|
61018
62317
|
published_at: post.published_at,
|
|
61019
|
-
published_at_iso: post.published_at_iso
|
|
62318
|
+
published_at_iso: post.published_at_iso,
|
|
62319
|
+
data: post.data
|
|
61020
62320
|
};
|
|
61021
62321
|
}
|
|
61022
62322
|
function buildArchiveGroups(posts, postBySlug) {
|
|
@@ -61089,40 +62389,22 @@ function formatArchiveLabel(date, site) {
|
|
|
61089
62389
|
function formatTimestamp(value, site) {
|
|
61090
62390
|
const date = toDate(value);
|
|
61091
62391
|
const locale = normalizeLocale(site.locale || DEFAULT_LOCALE);
|
|
61092
|
-
const
|
|
61093
|
-
const
|
|
62392
|
+
const dateStyle = DATETIME_STYLES.has(site.date_style) ? site.date_style : DEFAULT_DATE_STYLE;
|
|
62393
|
+
const timeStyle = DATETIME_STYLES.has(site.time_style) ? site.time_style : DEFAULT_TIME_STYLE;
|
|
61094
62394
|
const siteTimezone = normalizeNonEmptyString(site.timezone, DEFAULT_TIMEZONE);
|
|
61095
|
-
|
|
61096
|
-
|
|
61097
|
-
|
|
61098
|
-
|
|
61099
|
-
|
|
61100
|
-
}
|
|
61101
|
-
|
|
61102
|
-
|
|
61103
|
-
|
|
61104
|
-
|
|
61105
|
-
|
|
61106
|
-
|
|
61107
|
-
|
|
61108
|
-
formattedDate = `${month}/${day}/${year}`;
|
|
61109
|
-
} else if (dateFormat === "MMMM D, YYYY") {
|
|
61110
|
-
formattedDate = `${month} ${String(Number(day))}, ${year}`;
|
|
61111
|
-
}
|
|
61112
|
-
if (!timeFormat) {
|
|
61113
|
-
return formattedDate;
|
|
61114
|
-
}
|
|
61115
|
-
const timeParts = new Intl.DateTimeFormat(locale, {
|
|
61116
|
-
timeZone: siteTimezone,
|
|
61117
|
-
hour: "2-digit",
|
|
61118
|
-
minute: "2-digit",
|
|
61119
|
-
hour12: timeFormat === "hh:mm A"
|
|
61120
|
-
}).formatToParts(date);
|
|
61121
|
-
const hour = timeParts.find((part) => part.type === "hour")?.value || "";
|
|
61122
|
-
const minute = timeParts.find((part) => part.type === "minute")?.value || "";
|
|
61123
|
-
const dayPeriod = (timeParts.find((part) => part.type === "dayPeriod")?.value || "").toUpperCase();
|
|
61124
|
-
const formattedTime = timeFormat === "hh:mm A" ? `${hour}:${minute}${dayPeriod ? ` ${dayPeriod}` : ""}` : `${hour}:${minute}`;
|
|
61125
|
-
return `${formattedDate} ${formattedTime}`.trim();
|
|
62395
|
+
if (dateStyle === "none" && timeStyle === "none") {
|
|
62396
|
+
return "";
|
|
62397
|
+
}
|
|
62398
|
+
const options2 = {
|
|
62399
|
+
timeZone: siteTimezone
|
|
62400
|
+
};
|
|
62401
|
+
if (dateStyle !== "none") {
|
|
62402
|
+
options2.dateStyle = dateStyle;
|
|
62403
|
+
}
|
|
62404
|
+
if (timeStyle !== "none") {
|
|
62405
|
+
options2.timeStyle = timeStyle;
|
|
62406
|
+
}
|
|
62407
|
+
return new Intl.DateTimeFormat(locale, options2).format(date);
|
|
61126
62408
|
}
|
|
61127
62409
|
function calculateReadingTime(html) {
|
|
61128
62410
|
const plainText = String(html || "").replace(/<[^>]*>/g, " ");
|
|
@@ -61203,10 +62485,12 @@ async function normalizeAndValidateThemePackage(themePackage) {
|
|
|
61203
62485
|
...themePackage.metadata.author ? { author: themePackage.metadata.author } : {},
|
|
61204
62486
|
...themePackage.metadata.description ? { description: themePackage.metadata.description } : {},
|
|
61205
62487
|
...themePackage.metadata.thumbnail ? { thumbnail: themePackage.metadata.thumbnail } : {},
|
|
62488
|
+
...themePackage.metadata.links ? { links: themePackage.metadata.links } : {},
|
|
61206
62489
|
...themePackage.metadata.features ? { features: themePackage.metadata.features } : {},
|
|
61207
|
-
...themePackage.metadata.
|
|
61208
|
-
...themePackage.metadata.
|
|
61209
|
-
|
|
62490
|
+
...themePackage.metadata.menu_slots ? { menu_slots: themePackage.metadata.menu_slots } : {},
|
|
62491
|
+
...themePackage.metadata.widget_areas ? { widget_areas: themePackage.metadata.widget_areas } : {},
|
|
62492
|
+
...themePackage.metadata.site_meta ? { site_meta: themePackage.metadata.site_meta } : {},
|
|
62493
|
+
...themePackage.metadata.collection_slots ? { collection_slots: themePackage.metadata.collection_slots } : {}
|
|
61210
62494
|
}));
|
|
61211
62495
|
for (const [templateName, templateContent] of themePackage.templates.entries()) {
|
|
61212
62496
|
fileMap.set(`${templateName}.html`, templateContent);
|
|
@@ -61219,7 +62503,7 @@ async function normalizeAndValidateThemePackage(themePackage) {
|
|
|
61219
62503
|
}
|
|
61220
62504
|
const validation = await validateThemeFiles(fileMap);
|
|
61221
62505
|
if (!validation.ok) {
|
|
61222
|
-
throw new Error(
|
|
62506
|
+
throw new Error(formatThemeValidationFailure(validation));
|
|
61223
62507
|
}
|
|
61224
62508
|
if (!validation.manifest) {
|
|
61225
62509
|
throw new Error("Theme validation failed: normalized manifest not available");
|
|
@@ -61231,11 +62515,59 @@ async function normalizeAndValidateThemePackage(themePackage) {
|
|
|
61231
62515
|
assets: themePackage.assets
|
|
61232
62516
|
};
|
|
61233
62517
|
}
|
|
62518
|
+
function formatThemeValidationFailure(validation) {
|
|
62519
|
+
const blocks = [
|
|
62520
|
+
[
|
|
62521
|
+
"Theme validation failed",
|
|
62522
|
+
`Errors: ${validation.errors.length}`,
|
|
62523
|
+
`Checked files: ${validation.checkedFiles}`
|
|
62524
|
+
].join("\n"),
|
|
62525
|
+
...validation.errors.map((issue3) => formatThemeValidationIssue(issue3))
|
|
62526
|
+
];
|
|
62527
|
+
return blocks.join("\n\n");
|
|
62528
|
+
}
|
|
62529
|
+
function formatThemeValidationIssue(issue3) {
|
|
62530
|
+
if (!issue3) {
|
|
62531
|
+
return "Reason: Unknown error";
|
|
62532
|
+
}
|
|
62533
|
+
const lines = [`ERROR ${issue3.code || "THEME_VALIDATION_ERROR"}`];
|
|
62534
|
+
const location = splitIssuePath(issue3.path);
|
|
62535
|
+
if (location.file) {
|
|
62536
|
+
lines.push(`File: ${location.file}`);
|
|
62537
|
+
}
|
|
62538
|
+
if (location.path) {
|
|
62539
|
+
lines.push(`Path: ${location.path}`);
|
|
62540
|
+
}
|
|
62541
|
+
if (Number.isInteger(issue3.line) && Number.isInteger(issue3.column)) {
|
|
62542
|
+
lines.push(`Line: ${issue3.line}, Column: ${issue3.column}`);
|
|
62543
|
+
}
|
|
62544
|
+
if (issue3.category) {
|
|
62545
|
+
lines.push(`Category: ${issue3.category}`);
|
|
62546
|
+
}
|
|
62547
|
+
lines.push(`Reason: ${issue3.message || "Unknown error"}`);
|
|
62548
|
+
if (issue3.snippet) {
|
|
62549
|
+
const lineLabel = Number.isInteger(issue3.line) ? String(issue3.line) : "";
|
|
62550
|
+
lines.push("", `${lineLabel} | ${issue3.snippet.line}`, `${" ".repeat(lineLabel.length)} | ${issue3.snippet.pointer}`);
|
|
62551
|
+
}
|
|
62552
|
+
if (issue3.hint) {
|
|
62553
|
+
lines.push("", "Hint:", issue3.hint);
|
|
62554
|
+
}
|
|
62555
|
+
return lines.join("\n");
|
|
62556
|
+
}
|
|
62557
|
+
function splitIssuePath(issuePath) {
|
|
62558
|
+
const normalizedPath = String(issuePath || "");
|
|
62559
|
+
if (normalizedPath.startsWith("theme.json.")) {
|
|
62560
|
+
return {
|
|
62561
|
+
file: "theme.json",
|
|
62562
|
+
path: normalizedPath.slice("theme.json.".length)
|
|
62563
|
+
};
|
|
62564
|
+
}
|
|
62565
|
+
return { file: normalizedPath, path: "" };
|
|
62566
|
+
}
|
|
61234
62567
|
function normalizeThemePackageMetadata(sourceMetadata, manifest) {
|
|
61235
62568
|
return {
|
|
61236
62569
|
...manifest,
|
|
61237
|
-
...sourceMetadata?.thumbnail ? { thumbnail: sourceMetadata.thumbnail } : {}
|
|
61238
|
-
settings: sourceMetadata?.settings || {}
|
|
62570
|
+
...sourceMetadata?.thumbnail ? { thumbnail: sourceMetadata.thumbnail } : {}
|
|
61239
62571
|
};
|
|
61240
62572
|
}
|
|
61241
62573
|
async function buildAssetOutputs(assets, assetProcessor, options2) {
|
|
@@ -61301,6 +62633,7 @@ function buildPageMeta(site, options2 = {}) {
|
|
|
61301
62633
|
const ogType = normalizeNonEmptyString(options2.ogType, "website");
|
|
61302
62634
|
const publishedTime = normalizeOptionalString(options2.publishedTime);
|
|
61303
62635
|
const modifiedTime = normalizeOptionalString(options2.modifiedTime);
|
|
62636
|
+
const robotsNoindex = options2.robotsNoindex === true;
|
|
61304
62637
|
const meta = {
|
|
61305
62638
|
title: escapeHtml2(resolvedTitle),
|
|
61306
62639
|
description: resolvedDescription ? escapeHtml2(resolvedDescription) : "",
|
|
@@ -61312,7 +62645,8 @@ function buildPageMeta(site, options2 = {}) {
|
|
|
61312
62645
|
og_site_name: escapeHtml2(site.title),
|
|
61313
62646
|
og_image: ogImage ? escapeHtml2(ogImage) : "",
|
|
61314
62647
|
article_published_time: publishedTime ? escapeHtml2(publishedTime) : "",
|
|
61315
|
-
article_modified_time: modifiedTime ? escapeHtml2(modifiedTime) : ""
|
|
62648
|
+
article_modified_time: modifiedTime ? escapeHtml2(modifiedTime) : "",
|
|
62649
|
+
robots_noindex: robotsNoindex
|
|
61316
62650
|
};
|
|
61317
62651
|
return {
|
|
61318
62652
|
...meta,
|
|
@@ -61329,6 +62663,9 @@ function buildMetaHeadTags(meta) {
|
|
|
61329
62663
|
if (meta.description) {
|
|
61330
62664
|
tags.push(`<meta name="description" content="${meta.description}">`);
|
|
61331
62665
|
}
|
|
62666
|
+
if (meta.robots_noindex) {
|
|
62667
|
+
tags.push('<meta name="robots" content="noindex">');
|
|
62668
|
+
}
|
|
61332
62669
|
if (meta.canonical_url) {
|
|
61333
62670
|
tags.push(`<link rel="canonical" href="${meta.canonical_url}">`);
|
|
61334
62671
|
}
|
|
@@ -61369,7 +62706,7 @@ function resolveMetaImageUrl(image2) {
|
|
|
61369
62706
|
}
|
|
61370
62707
|
return "";
|
|
61371
62708
|
}
|
|
61372
|
-
function normalizeMediaField(value,
|
|
62709
|
+
function normalizeMediaField(value, media_base_url) {
|
|
61373
62710
|
if (value === void 0) {
|
|
61374
62711
|
return void 0;
|
|
61375
62712
|
}
|
|
@@ -61380,9 +62717,9 @@ function normalizeMediaField(value, mediaBaseUrl) {
|
|
|
61380
62717
|
if (isAbsoluteUrl(normalizedValue)) {
|
|
61381
62718
|
return normalizeAbsoluteUrl(normalizedValue, SAFE_MEDIA_PROTOCOLS);
|
|
61382
62719
|
}
|
|
61383
|
-
const normalizedBaseUrl = normalizeOptionalString(
|
|
62720
|
+
const normalizedBaseUrl = normalizeOptionalString(media_base_url);
|
|
61384
62721
|
if (!normalizedBaseUrl) {
|
|
61385
|
-
return
|
|
62722
|
+
return normalizedValue;
|
|
61386
62723
|
}
|
|
61387
62724
|
try {
|
|
61388
62725
|
return decodeURI(new URL(normalizedValue, normalizedBaseUrl).toString());
|
|
@@ -61586,7 +62923,11 @@ function assertPlannedOutputPathsSafe(state) {
|
|
|
61586
62923
|
COMMENT_POLICY_OUTPUT_PATH
|
|
61587
62924
|
];
|
|
61588
62925
|
if (state.options.generateSpecialFiles) {
|
|
61589
|
-
plannedPaths.push(
|
|
62926
|
+
plannedPaths.push(SEARCH_INDEX_OUTPUT_PATH, SEARCH_ADAPTER_OUTPUT_PATH);
|
|
62927
|
+
plannedPaths.push("404.html");
|
|
62928
|
+
if (shouldGenerateRobotsTxt(state.options)) {
|
|
62929
|
+
plannedPaths.push("robots.txt");
|
|
62930
|
+
}
|
|
61590
62931
|
if (hasCanonicalSiteUrl(state.previewData.site.url)) {
|
|
61591
62932
|
plannedPaths.push("sitemap.xml", "feed.xml");
|
|
61592
62933
|
}
|
|
@@ -61661,10 +63002,45 @@ function sha256(content) {
|
|
|
61661
63002
|
return hash.digest("hex");
|
|
61662
63003
|
}
|
|
61663
63004
|
function injectSiteCustomizations(html, state) {
|
|
61664
|
-
let next =
|
|
63005
|
+
let next = injectFaviconLinks(html, state.favicon);
|
|
63006
|
+
next = injectGeneratorMeta(next, state.exposeGenerator);
|
|
63007
|
+
next = injectCustomCssAssetLink(next, state.customCssHref);
|
|
61665
63008
|
next = injectCustomHtml(next, state.customHtml);
|
|
61666
63009
|
return next;
|
|
61667
63010
|
}
|
|
63011
|
+
function injectFaviconLinks(html, favicon) {
|
|
63012
|
+
const links = buildFaviconLinks(favicon);
|
|
63013
|
+
if (!links) {
|
|
63014
|
+
return html;
|
|
63015
|
+
}
|
|
63016
|
+
return html.replace("</head>", `${links}
|
|
63017
|
+
</head>`);
|
|
63018
|
+
}
|
|
63019
|
+
function buildFaviconLinks(favicon) {
|
|
63020
|
+
if (!favicon || typeof favicon !== "object") {
|
|
63021
|
+
return "";
|
|
63022
|
+
}
|
|
63023
|
+
const lines = [];
|
|
63024
|
+
if (normalizeOptionalString(favicon.icon)) {
|
|
63025
|
+
lines.push(` <link rel="icon" href="${escapeHtml2(favicon.icon)}" sizes="any">`);
|
|
63026
|
+
}
|
|
63027
|
+
if (normalizeOptionalString(favicon.svg)) {
|
|
63028
|
+
lines.push(` <link rel="icon" href="${escapeHtml2(favicon.svg)}" type="image/svg+xml">`);
|
|
63029
|
+
}
|
|
63030
|
+
if (normalizeOptionalString(favicon.png)) {
|
|
63031
|
+
lines.push(` <link rel="icon" href="${escapeHtml2(favicon.png)}" type="image/png">`);
|
|
63032
|
+
}
|
|
63033
|
+
if (normalizeOptionalString(favicon.apple_touch_icon)) {
|
|
63034
|
+
lines.push(` <link rel="apple-touch-icon" href="${escapeHtml2(favicon.apple_touch_icon)}">`);
|
|
63035
|
+
}
|
|
63036
|
+
return lines.join("\n");
|
|
63037
|
+
}
|
|
63038
|
+
function injectGeneratorMeta(html, exposeGenerator) {
|
|
63039
|
+
if (exposeGenerator === false) {
|
|
63040
|
+
return html;
|
|
63041
|
+
}
|
|
63042
|
+
return html.replace("</head>", ' <meta name="generator" content="ZeroPress">\n</head>');
|
|
63043
|
+
}
|
|
61668
63044
|
function injectCustomCssAssetLink(html, href) {
|
|
61669
63045
|
if (!normalizeOptionalString(href)) {
|
|
61670
63046
|
return html;
|
|
@@ -61686,9 +63062,383 @@ function injectCustomHtml(html, customHtml) {
|
|
|
61686
63062
|
}
|
|
61687
63063
|
return next;
|
|
61688
63064
|
}
|
|
61689
|
-
function
|
|
63065
|
+
function buildSearchIndexJson(state) {
|
|
63066
|
+
return `${JSON.stringify(buildSearchIndexItems(state), null, 2)}
|
|
63067
|
+
`;
|
|
63068
|
+
}
|
|
63069
|
+
function buildSearchIndexItems(state) {
|
|
63070
|
+
const posts = state.renderData.posts.filter((post) => post.status === "published" && !isDelistedDocument(post)).map((post) => ({
|
|
63071
|
+
id: `post:${post.slug}`,
|
|
63072
|
+
type: "post",
|
|
63073
|
+
title: post.title,
|
|
63074
|
+
url: post.url,
|
|
63075
|
+
excerpt: normalizeSearchText(post.excerpt),
|
|
63076
|
+
headings: buildSearchHeadings(post.toc),
|
|
63077
|
+
categories: Array.isArray(post.categories) ? post.categories.map((category) => category.name).filter(Boolean) : [],
|
|
63078
|
+
tags: Array.isArray(post.tags) ? post.tags.map((tag) => tag.name).filter(Boolean) : [],
|
|
63079
|
+
published_at_iso: normalizeIsoTimestamp(post.published_at_iso),
|
|
63080
|
+
updated_at_iso: normalizeIsoTimestamp(post.updated_at_iso),
|
|
63081
|
+
content_text: htmlToSearchText(post.html)
|
|
63082
|
+
}));
|
|
63083
|
+
const frontPagePage = state.renderData.frontPageRoute?.front_page_type === "page" ? state.renderData.frontPageRoute.page : null;
|
|
63084
|
+
const frontPageItems = frontPagePage && frontPagePage.status === "published" && !isDelistedDocument(frontPagePage) ? [buildSearchPageItem(frontPagePage, "/")] : [];
|
|
63085
|
+
const pageItems = state.renderData.pages.filter((page) => page.status === "published" && !isDelistedDocument(page)).map((page) => buildSearchPageItem(page, page.url));
|
|
63086
|
+
return [...posts, ...frontPageItems, ...pageItems];
|
|
63087
|
+
}
|
|
63088
|
+
function buildSearchPageItem(page, url) {
|
|
63089
|
+
return {
|
|
63090
|
+
id: `page:${page.slug}`,
|
|
63091
|
+
type: "page",
|
|
63092
|
+
title: page.title,
|
|
63093
|
+
url,
|
|
63094
|
+
excerpt: normalizeSearchText(page.excerpt),
|
|
63095
|
+
headings: buildSearchHeadings(page.toc),
|
|
63096
|
+
categories: [],
|
|
63097
|
+
tags: [],
|
|
63098
|
+
published_at_iso: "",
|
|
63099
|
+
updated_at_iso: "",
|
|
63100
|
+
content_text: htmlToSearchText(page.html)
|
|
63101
|
+
};
|
|
63102
|
+
}
|
|
63103
|
+
function buildSearchHeadings(toc) {
|
|
63104
|
+
return Array.isArray(toc) ? toc.map((item) => normalizeSearchText(item?.title)).filter(Boolean) : [];
|
|
63105
|
+
}
|
|
63106
|
+
function htmlToSearchText(html) {
|
|
63107
|
+
return normalizeSearchText(decodeHtmlEntities(
|
|
63108
|
+
String(html || "").replace(/<script\b[^>]*>[\s\S]*?<\/script>/gi, " ").replace(/<style\b[^>]*>[\s\S]*?<\/style>/gi, " ").replace(/<!--[\s\S]*?-->/g, " ").replace(/<[^>]+>/g, " ")
|
|
63109
|
+
));
|
|
63110
|
+
}
|
|
63111
|
+
function decodeHtmlEntities(value) {
|
|
63112
|
+
const namedEntities = {
|
|
63113
|
+
amp: "&",
|
|
63114
|
+
lt: "<",
|
|
63115
|
+
gt: ">",
|
|
63116
|
+
quot: '"',
|
|
63117
|
+
apos: "'",
|
|
63118
|
+
nbsp: " "
|
|
63119
|
+
};
|
|
63120
|
+
return String(value || "").replace(/&(#x[0-9a-fA-F]+|#\d+|[a-zA-Z][a-zA-Z0-9]+);/g, (match2, entity2) => {
|
|
63121
|
+
if (entity2.startsWith("#x")) {
|
|
63122
|
+
const codePoint = Number.parseInt(entity2.slice(2), 16);
|
|
63123
|
+
return Number.isFinite(codePoint) ? String.fromCodePoint(codePoint) : match2;
|
|
63124
|
+
}
|
|
63125
|
+
if (entity2.startsWith("#")) {
|
|
63126
|
+
const codePoint = Number.parseInt(entity2.slice(1), 10);
|
|
63127
|
+
return Number.isFinite(codePoint) ? String.fromCodePoint(codePoint) : match2;
|
|
63128
|
+
}
|
|
63129
|
+
return Object.prototype.hasOwnProperty.call(namedEntities, entity2) ? namedEntities[entity2] : match2;
|
|
63130
|
+
});
|
|
63131
|
+
}
|
|
63132
|
+
function normalizeSearchText(value) {
|
|
63133
|
+
return String(value || "").replace(/\s+/g, " ").trim();
|
|
63134
|
+
}
|
|
63135
|
+
function buildSearchAdapterJs() {
|
|
63136
|
+
const fieldWeightsJson = JSON.stringify(SEARCH_FIELD_WEIGHTS, null, 2);
|
|
63137
|
+
return `const FIELD_WEIGHTS = ${fieldWeightsJson};
|
|
63138
|
+
const FIELD_NAMES = Object.keys(FIELD_WEIGHTS);
|
|
63139
|
+
const RECENCY_BOOST_MAX = ${SEARCH_RECENCY_BOOST_MAX};
|
|
63140
|
+
const DEFAULT_LIMIT = 20;
|
|
63141
|
+
const BM25_K1 = 1.2;
|
|
63142
|
+
const BM25_B = 0.75;
|
|
63143
|
+
|
|
63144
|
+
let preparedIndexPromise;
|
|
63145
|
+
|
|
63146
|
+
export async function preload() {
|
|
63147
|
+
await loadPreparedIndex();
|
|
63148
|
+
}
|
|
63149
|
+
|
|
63150
|
+
export async function search(query, options = {}) {
|
|
63151
|
+
const prepared = await loadPreparedIndex();
|
|
63152
|
+
const terms = tokenize(query);
|
|
63153
|
+
const phrase = normalizeText(query);
|
|
63154
|
+
if (terms.length === 0 && !phrase) {
|
|
63155
|
+
return { results: [] };
|
|
63156
|
+
}
|
|
63157
|
+
|
|
63158
|
+
const hits = [];
|
|
63159
|
+
for (const document of prepared.documents) {
|
|
63160
|
+
const score = scoreDocument(document, terms, phrase, prepared);
|
|
63161
|
+
if (score > 0) {
|
|
63162
|
+
hits.push({ document, score });
|
|
63163
|
+
}
|
|
63164
|
+
}
|
|
63165
|
+
|
|
63166
|
+
const limit = normalizeLimit(options.limit);
|
|
63167
|
+
hits.sort((left, right) => right.score - left.score || left.document.raw.title.localeCompare(right.document.raw.title));
|
|
63168
|
+
|
|
63169
|
+
return {
|
|
63170
|
+
results: hits.slice(0, limit).map((hit) => ({
|
|
63171
|
+
id: hit.document.raw.id,
|
|
63172
|
+
score: Number(hit.score.toFixed(6)),
|
|
63173
|
+
data: async () => buildResultData(hit.document.raw, query),
|
|
63174
|
+
})),
|
|
63175
|
+
};
|
|
63176
|
+
}
|
|
63177
|
+
|
|
63178
|
+
async function loadPreparedIndex() {
|
|
63179
|
+
if (!preparedIndexPromise) {
|
|
63180
|
+
preparedIndexPromise = fetch(new URL('./search.json', import.meta.url))
|
|
63181
|
+
.then((response) => {
|
|
63182
|
+
if (!response.ok) {
|
|
63183
|
+
throw new Error('ZeroPress search index not found');
|
|
63184
|
+
}
|
|
63185
|
+
return response.json();
|
|
63186
|
+
})
|
|
63187
|
+
.then((items) => prepareIndex(Array.isArray(items) ? items : []));
|
|
63188
|
+
}
|
|
63189
|
+
|
|
63190
|
+
return preparedIndexPromise;
|
|
63191
|
+
}
|
|
63192
|
+
|
|
63193
|
+
function prepareIndex(items) {
|
|
63194
|
+
const documents = items.map((item) => prepareDocument(item));
|
|
63195
|
+
const documentFrequencies = new Map();
|
|
63196
|
+
const averageLengths = Object.fromEntries(FIELD_NAMES.map((fieldName) => [fieldName, 1]));
|
|
63197
|
+
const newestPostTime = documents.reduce((newest, document) => {
|
|
63198
|
+
if (document.raw.type !== 'post') {
|
|
63199
|
+
return newest;
|
|
63200
|
+
}
|
|
63201
|
+
return Math.max(newest, document.publishedTime || 0);
|
|
63202
|
+
}, 0);
|
|
63203
|
+
|
|
63204
|
+
for (const document of documents) {
|
|
63205
|
+
const seenTerms = new Set();
|
|
63206
|
+
for (const fieldName of FIELD_NAMES) {
|
|
63207
|
+
for (const term of document.fieldTokens[fieldName]) {
|
|
63208
|
+
seenTerms.add(term);
|
|
63209
|
+
}
|
|
63210
|
+
}
|
|
63211
|
+
for (const term of seenTerms) {
|
|
63212
|
+
documentFrequencies.set(term, (documentFrequencies.get(term) || 0) + 1);
|
|
63213
|
+
}
|
|
63214
|
+
}
|
|
63215
|
+
|
|
63216
|
+
for (const fieldName of FIELD_NAMES) {
|
|
63217
|
+
const total = documents.reduce((sum, document) => sum + document.fieldLengths[fieldName], 0);
|
|
63218
|
+
averageLengths[fieldName] = documents.length > 0 ? Math.max(1, total / documents.length) : 1;
|
|
63219
|
+
}
|
|
63220
|
+
|
|
63221
|
+
return {
|
|
63222
|
+
documents,
|
|
63223
|
+
documentFrequencies,
|
|
63224
|
+
averageLengths,
|
|
63225
|
+
documentCount: documents.length,
|
|
63226
|
+
newestPostTime,
|
|
63227
|
+
};
|
|
63228
|
+
}
|
|
63229
|
+
|
|
63230
|
+
function prepareDocument(item) {
|
|
63231
|
+
const raw = normalizeItem(item);
|
|
63232
|
+
const fields = {
|
|
63233
|
+
title: raw.title,
|
|
63234
|
+
headings: raw.headings.join(' '),
|
|
63235
|
+
tags: raw.tags.join(' '),
|
|
63236
|
+
categories: raw.categories.join(' '),
|
|
63237
|
+
excerpt: raw.excerpt,
|
|
63238
|
+
content_text: raw.content_text,
|
|
63239
|
+
};
|
|
63240
|
+
const fieldTexts = {};
|
|
63241
|
+
const fieldTokens = {};
|
|
63242
|
+
const fieldTermCounts = {};
|
|
63243
|
+
const fieldLengths = {};
|
|
63244
|
+
|
|
63245
|
+
for (const [fieldName, value] of Object.entries(fields)) {
|
|
63246
|
+
const normalizedText = normalizeText(value);
|
|
63247
|
+
const tokens = tokenize(normalizedText);
|
|
63248
|
+
fieldTexts[fieldName] = normalizedText;
|
|
63249
|
+
fieldTokens[fieldName] = tokens;
|
|
63250
|
+
fieldTermCounts[fieldName] = countTerms(tokens);
|
|
63251
|
+
fieldLengths[fieldName] = Math.max(1, tokens.length);
|
|
63252
|
+
}
|
|
63253
|
+
|
|
63254
|
+
return {
|
|
63255
|
+
raw,
|
|
63256
|
+
fieldTexts,
|
|
63257
|
+
fieldTokens,
|
|
63258
|
+
fieldTermCounts,
|
|
63259
|
+
fieldLengths,
|
|
63260
|
+
publishedTime: Date.parse(raw.published_at_iso) || 0,
|
|
63261
|
+
};
|
|
63262
|
+
}
|
|
63263
|
+
|
|
63264
|
+
function normalizeItem(item) {
|
|
63265
|
+
return {
|
|
63266
|
+
id: String(item && item.id || ''),
|
|
63267
|
+
type: item && item.type === 'page' ? 'page' : 'post',
|
|
63268
|
+
title: String(item && item.title || ''),
|
|
63269
|
+
url: String(item && item.url || ''),
|
|
63270
|
+
excerpt: String(item && item.excerpt || ''),
|
|
63271
|
+
headings: Array.isArray(item && item.headings) ? item.headings.map(String) : [],
|
|
63272
|
+
categories: Array.isArray(item && item.categories) ? item.categories.map(String) : [],
|
|
63273
|
+
tags: Array.isArray(item && item.tags) ? item.tags.map(String) : [],
|
|
63274
|
+
published_at_iso: String(item && item.published_at_iso || ''),
|
|
63275
|
+
updated_at_iso: String(item && item.updated_at_iso || ''),
|
|
63276
|
+
content_text: String(item && item.content_text || ''),
|
|
63277
|
+
};
|
|
63278
|
+
}
|
|
63279
|
+
|
|
63280
|
+
function scoreDocument(document, terms, phrase, prepared) {
|
|
63281
|
+
let score = 0;
|
|
63282
|
+
const uniqueTerms = Array.from(new Set(terms));
|
|
63283
|
+
|
|
63284
|
+
for (const term of uniqueTerms) {
|
|
63285
|
+
const documentFrequency = prepared.documentFrequencies.get(term) || 0;
|
|
63286
|
+
const idf = Math.log(1 + (prepared.documentCount - documentFrequency + 0.5) / (documentFrequency + 0.5));
|
|
63287
|
+
|
|
63288
|
+
for (const fieldName of FIELD_NAMES) {
|
|
63289
|
+
const termFrequency = document.fieldTermCounts[fieldName].get(term) || 0;
|
|
63290
|
+
if (termFrequency === 0) {
|
|
63291
|
+
continue;
|
|
63292
|
+
}
|
|
63293
|
+
|
|
63294
|
+
const fieldLength = document.fieldLengths[fieldName];
|
|
63295
|
+
const averageLength = prepared.averageLengths[fieldName];
|
|
63296
|
+
const denominator = termFrequency + BM25_K1 * (1 - BM25_B + BM25_B * (fieldLength / averageLength));
|
|
63297
|
+
score += FIELD_WEIGHTS[fieldName] * idf * ((termFrequency * (BM25_K1 + 1)) / denominator);
|
|
63298
|
+
}
|
|
63299
|
+
}
|
|
63300
|
+
|
|
63301
|
+
if (phrase && phrase.length > 1) {
|
|
63302
|
+
for (const fieldName of FIELD_NAMES) {
|
|
63303
|
+
if (document.fieldTexts[fieldName].includes(phrase)) {
|
|
63304
|
+
score += FIELD_WEIGHTS[fieldName] * 0.6;
|
|
63305
|
+
}
|
|
63306
|
+
}
|
|
63307
|
+
}
|
|
63308
|
+
|
|
63309
|
+
if (score <= 0) {
|
|
63310
|
+
return 0;
|
|
63311
|
+
}
|
|
63312
|
+
|
|
63313
|
+
return score * (1 + recencyBoost(document, prepared.newestPostTime));
|
|
63314
|
+
}
|
|
63315
|
+
|
|
63316
|
+
function recencyBoost(document, newestPostTime) {
|
|
63317
|
+
if (document.raw.type !== 'post' || !document.publishedTime || !newestPostTime) {
|
|
63318
|
+
return 0;
|
|
63319
|
+
}
|
|
63320
|
+
const ageMs = Math.max(0, newestPostTime - document.publishedTime);
|
|
63321
|
+
const halfLifeMs = 180 * 24 * 60 * 60 * 1000;
|
|
63322
|
+
return RECENCY_BOOST_MAX * Math.exp(-ageMs / halfLifeMs);
|
|
63323
|
+
}
|
|
63324
|
+
|
|
63325
|
+
function buildResultData(item, query) {
|
|
63326
|
+
const excerpt = buildExcerpt(item, query);
|
|
63327
|
+
return {
|
|
63328
|
+
url: item.url,
|
|
63329
|
+
excerpt,
|
|
63330
|
+
plain_excerpt: excerpt,
|
|
63331
|
+
meta: {
|
|
63332
|
+
title: item.title,
|
|
63333
|
+
type: item.type,
|
|
63334
|
+
published_at_iso: item.published_at_iso,
|
|
63335
|
+
updated_at_iso: item.updated_at_iso,
|
|
63336
|
+
categories: item.categories,
|
|
63337
|
+
tags: item.tags,
|
|
63338
|
+
},
|
|
63339
|
+
sub_results: [],
|
|
63340
|
+
};
|
|
63341
|
+
}
|
|
63342
|
+
|
|
63343
|
+
function buildExcerpt(item, query) {
|
|
63344
|
+
const explicitExcerpt = String(item.excerpt || '').trim();
|
|
63345
|
+
if (explicitExcerpt) {
|
|
63346
|
+
return explicitExcerpt;
|
|
63347
|
+
}
|
|
63348
|
+
|
|
63349
|
+
const text = String(item.content_text || '').replace(/\\s+/g, ' ').trim();
|
|
63350
|
+
if (!text) {
|
|
63351
|
+
return '';
|
|
63352
|
+
}
|
|
63353
|
+
|
|
63354
|
+
const normalizedText = normalizeText(text);
|
|
63355
|
+
const terms = tokenize(query);
|
|
63356
|
+
const firstMatch = terms.map((term) => normalizedText.indexOf(term)).filter((index) => index >= 0).sort((a, b) => a - b)[0];
|
|
63357
|
+
const start = Math.max(0, (firstMatch || 0) - 80);
|
|
63358
|
+
const end = Math.min(text.length, start + 180);
|
|
63359
|
+
const prefix = start > 0 ? '...' : '';
|
|
63360
|
+
const suffix = end < text.length ? '...' : '';
|
|
63361
|
+
return prefix + text.slice(start, end).trim() + suffix;
|
|
63362
|
+
}
|
|
63363
|
+
|
|
63364
|
+
function countTerms(tokens) {
|
|
63365
|
+
const counts = new Map();
|
|
63366
|
+
for (const token of tokens) {
|
|
63367
|
+
counts.set(token, (counts.get(token) || 0) + 1);
|
|
63368
|
+
}
|
|
63369
|
+
return counts;
|
|
63370
|
+
}
|
|
63371
|
+
|
|
63372
|
+
function tokenize(value) {
|
|
63373
|
+
const text = normalizeText(value);
|
|
63374
|
+
if (!text) {
|
|
63375
|
+
return [];
|
|
63376
|
+
}
|
|
63377
|
+
|
|
63378
|
+
const tokens = [];
|
|
63379
|
+
if (typeof Intl !== 'undefined' && typeof Intl.Segmenter === 'function') {
|
|
63380
|
+
try {
|
|
63381
|
+
const segmenter = new Intl.Segmenter(undefined, { granularity: 'word' });
|
|
63382
|
+
for (const part of segmenter.segment(text)) {
|
|
63383
|
+
if (part.isWordLike && isUsefulToken(part.segment)) {
|
|
63384
|
+
tokens.push(part.segment);
|
|
63385
|
+
}
|
|
63386
|
+
}
|
|
63387
|
+
} catch {
|
|
63388
|
+
// Fall through to regex tokenization.
|
|
63389
|
+
}
|
|
63390
|
+
}
|
|
63391
|
+
|
|
63392
|
+
for (const match of text.matchAll(/[\\p{Letter}\\p{Number}]+/gu)) {
|
|
63393
|
+
if (isUsefulToken(match[0])) {
|
|
63394
|
+
tokens.push(match[0]);
|
|
63395
|
+
}
|
|
63396
|
+
}
|
|
63397
|
+
|
|
63398
|
+
for (const match of text.matchAll(/[\\p{Script=Han}\\p{Script=Hiragana}\\p{Script=Katakana}\\p{Script=Hangul}]+/gu)) {
|
|
63399
|
+
tokens.push(...buildNgrams(match[0], 2));
|
|
63400
|
+
}
|
|
63401
|
+
|
|
63402
|
+
return tokens;
|
|
63403
|
+
}
|
|
63404
|
+
|
|
63405
|
+
function buildNgrams(value, size) {
|
|
63406
|
+
const normalized = Array.from(value);
|
|
63407
|
+
if (normalized.length <= size) {
|
|
63408
|
+
return isUsefulToken(value) ? [value] : [];
|
|
63409
|
+
}
|
|
63410
|
+
|
|
63411
|
+
const tokens = [];
|
|
63412
|
+
for (let index = 0; index <= normalized.length - size; index += 1) {
|
|
63413
|
+
tokens.push(normalized.slice(index, index + size).join(''));
|
|
63414
|
+
}
|
|
63415
|
+
tokens.push(value);
|
|
63416
|
+
return tokens;
|
|
63417
|
+
}
|
|
63418
|
+
|
|
63419
|
+
function isUsefulToken(value) {
|
|
63420
|
+
const token = String(value || '').trim();
|
|
63421
|
+
return token.length > 1 || /^\\d$/.test(token);
|
|
63422
|
+
}
|
|
63423
|
+
|
|
63424
|
+
function normalizeText(value) {
|
|
63425
|
+
return String(value || '')
|
|
63426
|
+
.normalize('NFKC')
|
|
63427
|
+
.toLowerCase()
|
|
63428
|
+
.replace(/[\\u2018\\u2019]/g, "'")
|
|
63429
|
+
.replace(/[_-]+/g, ' ')
|
|
63430
|
+
.replace(/\\s+/g, ' ')
|
|
63431
|
+
.trim();
|
|
63432
|
+
}
|
|
63433
|
+
|
|
63434
|
+
function normalizeLimit(value) {
|
|
63435
|
+
return Number.isInteger(value) && value > 0 ? Math.min(value, 100) : DEFAULT_LIMIT;
|
|
63436
|
+
}
|
|
63437
|
+
`;
|
|
63438
|
+
}
|
|
63439
|
+
function buildSitemapXml(site, emitted, generatedAt, stylesheetHref = "") {
|
|
61690
63440
|
const entries = [
|
|
61691
|
-
...emitted.frontPage ? [{
|
|
63441
|
+
...emitted.frontPage && emitted.frontPage.includeInSitemap !== false ? [{
|
|
61692
63442
|
url: emitted.frontPage.url,
|
|
61693
63443
|
changefreq: "daily",
|
|
61694
63444
|
priority: 1
|
|
@@ -61720,7 +63470,10 @@ function buildSitemapXml(site, emitted, generatedAt) {
|
|
|
61720
63470
|
<priority>${entry.priority.toFixed(1)}</priority>
|
|
61721
63471
|
</url>`;
|
|
61722
63472
|
}).join("\n");
|
|
61723
|
-
|
|
63473
|
+
const normalizedStylesheetHref = normalizeOptionalString(stylesheetHref);
|
|
63474
|
+
const stylesheet = normalizedStylesheetHref ? `
|
|
63475
|
+
<?xml-stylesheet type="text/xsl" href="${escapeXml(normalizedStylesheetHref)}"?>` : "";
|
|
63476
|
+
return `<?xml version="1.0" encoding="UTF-8"?>${stylesheet}
|
|
61724
63477
|
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
|
61725
63478
|
${body}
|
|
61726
63479
|
</urlset>`;
|
|
@@ -61752,13 +63505,22 @@ ${items}
|
|
|
61752
63505
|
</rss>`;
|
|
61753
63506
|
}
|
|
61754
63507
|
function buildRobotsTxt(site) {
|
|
61755
|
-
const lines = ["User-agent: *"
|
|
63508
|
+
const lines = ["User-agent: *"];
|
|
63509
|
+
if (site.indexing === false) {
|
|
63510
|
+
lines.push("Disallow: /");
|
|
63511
|
+
return `${lines.join("\n")}
|
|
63512
|
+
`;
|
|
63513
|
+
}
|
|
63514
|
+
lines.push("Allow: /");
|
|
61756
63515
|
if (site.url) {
|
|
61757
63516
|
lines.push("", `Sitemap: ${resolveSiteUrl(site.url, "/sitemap.xml")}`);
|
|
61758
63517
|
}
|
|
61759
63518
|
return `${lines.join("\n")}
|
|
61760
63519
|
`;
|
|
61761
63520
|
}
|
|
63521
|
+
function shouldGenerateRobotsTxt(options2) {
|
|
63522
|
+
return options2.generateSpecialFiles && options2.generateRobotsTxt !== false;
|
|
63523
|
+
}
|
|
61762
63524
|
function getContentType(assetPath) {
|
|
61763
63525
|
const ext = assetPath.split(".").pop()?.toLowerCase();
|
|
61764
63526
|
const contentTypes = {
|
|
@@ -61834,7 +63596,7 @@ async function loadThemePackageFromDir(themeDir) {
|
|
|
61834
63596
|
await readThemeDir(fs4, path4, themeDir, themeDir, fileMap);
|
|
61835
63597
|
const validation = await validateThemeFiles(fileMap);
|
|
61836
63598
|
if (!validation.ok) {
|
|
61837
|
-
throw new Error(
|
|
63599
|
+
throw new Error(formatThemeValidationFailure2(validation));
|
|
61838
63600
|
}
|
|
61839
63601
|
const rawThemeJson = String(fileMap.get("theme.json"));
|
|
61840
63602
|
const themeJson = JSON.parse(rawThemeJson);
|
|
@@ -61867,14 +63629,62 @@ async function loadThemePackageFromDir(themeDir) {
|
|
|
61867
63629
|
return {
|
|
61868
63630
|
metadata: {
|
|
61869
63631
|
...manifest,
|
|
61870
|
-
thumbnail: themeJson.thumbnail
|
|
61871
|
-
settings: themeJson.settings || {}
|
|
63632
|
+
thumbnail: themeJson.thumbnail
|
|
61872
63633
|
},
|
|
61873
63634
|
templates,
|
|
61874
63635
|
partials,
|
|
61875
63636
|
assets
|
|
61876
63637
|
};
|
|
61877
63638
|
}
|
|
63639
|
+
function formatThemeValidationFailure2(validation) {
|
|
63640
|
+
const blocks = [
|
|
63641
|
+
[
|
|
63642
|
+
"Theme validation failed",
|
|
63643
|
+
`Errors: ${validation.errors.length}`,
|
|
63644
|
+
`Checked files: ${validation.checkedFiles}`
|
|
63645
|
+
].join("\n"),
|
|
63646
|
+
...validation.errors.map((issue3) => formatThemeValidationIssue2(issue3))
|
|
63647
|
+
];
|
|
63648
|
+
return blocks.join("\n\n");
|
|
63649
|
+
}
|
|
63650
|
+
function formatThemeValidationIssue2(issue3) {
|
|
63651
|
+
if (!issue3) {
|
|
63652
|
+
return "Reason: Unknown error";
|
|
63653
|
+
}
|
|
63654
|
+
const lines = [`ERROR ${issue3.code || "THEME_VALIDATION_ERROR"}`];
|
|
63655
|
+
const location = splitIssuePath2(issue3.path);
|
|
63656
|
+
if (location.file) {
|
|
63657
|
+
lines.push(`File: ${location.file}`);
|
|
63658
|
+
}
|
|
63659
|
+
if (location.path) {
|
|
63660
|
+
lines.push(`Path: ${location.path}`);
|
|
63661
|
+
}
|
|
63662
|
+
if (Number.isInteger(issue3.line) && Number.isInteger(issue3.column)) {
|
|
63663
|
+
lines.push(`Line: ${issue3.line}, Column: ${issue3.column}`);
|
|
63664
|
+
}
|
|
63665
|
+
if (issue3.category) {
|
|
63666
|
+
lines.push(`Category: ${issue3.category}`);
|
|
63667
|
+
}
|
|
63668
|
+
lines.push(`Reason: ${issue3.message || "Unknown error"}`);
|
|
63669
|
+
if (issue3.snippet) {
|
|
63670
|
+
const lineLabel = Number.isInteger(issue3.line) ? String(issue3.line) : "";
|
|
63671
|
+
lines.push("", `${lineLabel} | ${issue3.snippet.line}`, `${" ".repeat(lineLabel.length)} | ${issue3.snippet.pointer}`);
|
|
63672
|
+
}
|
|
63673
|
+
if (issue3.hint) {
|
|
63674
|
+
lines.push("", "Hint:", issue3.hint);
|
|
63675
|
+
}
|
|
63676
|
+
return lines.join("\n");
|
|
63677
|
+
}
|
|
63678
|
+
function splitIssuePath2(issuePath) {
|
|
63679
|
+
const normalizedPath = String(issuePath || "");
|
|
63680
|
+
if (normalizedPath.startsWith("theme.json.")) {
|
|
63681
|
+
return {
|
|
63682
|
+
file: "theme.json",
|
|
63683
|
+
path: normalizedPath.slice("theme.json.".length)
|
|
63684
|
+
};
|
|
63685
|
+
}
|
|
63686
|
+
return { file: normalizedPath, path: "" };
|
|
63687
|
+
}
|
|
61878
63688
|
async function readThemeDir(fs4, path4, rootDir, currentDir, fileMap) {
|
|
61879
63689
|
const entries = await fs4.readdir(currentDir, { withFileTypes: true });
|
|
61880
63690
|
for (const entry of entries) {
|
|
@@ -61915,6 +63725,13 @@ var require2 = createRequire(import.meta.url);
|
|
|
61915
63725
|
var { version: PACKAGE_VERSION } = require2("../package.json");
|
|
61916
63726
|
var DEFAULT_PUBLIC_DIR_NAME = "public";
|
|
61917
63727
|
var PUBLIC_DIR_ENV_NAME = "ZEROPRESS_PUBLIC_DIR";
|
|
63728
|
+
var PUBLIC_FAVICON_FILES = Object.freeze({
|
|
63729
|
+
icon: "favicon.ico",
|
|
63730
|
+
svg: "favicon.svg",
|
|
63731
|
+
png: "favicon.png",
|
|
63732
|
+
apple_touch_icon: "apple-touch-icon.png"
|
|
63733
|
+
});
|
|
63734
|
+
var PUBLIC_SITEMAP_STYLESHEET_FILE = "sitemap.xsl";
|
|
61918
63735
|
async function assertThemeDirectory(themeDir) {
|
|
61919
63736
|
let stat;
|
|
61920
63737
|
try {
|
|
@@ -61929,17 +63746,26 @@ async function assertThemeDirectory(themeDir) {
|
|
|
61929
63746
|
throw new Error(`Theme path is not a directory: ${themeDir}`);
|
|
61930
63747
|
}
|
|
61931
63748
|
}
|
|
61932
|
-
async function runBuild(themeDir, previewData, outDir) {
|
|
61933
|
-
|
|
61934
|
-
assertPublicPathDoesNotOverlap("
|
|
63749
|
+
async function runBuild(themeDir, previewData, outDir, options2 = {}) {
|
|
63750
|
+
const publicDir = resolvePublicDir(process.cwd(), options2.publicDir);
|
|
63751
|
+
assertPublicPathDoesNotOverlap("Theme directory", themeDir, process.cwd(), publicDir);
|
|
63752
|
+
assertPublicPathDoesNotOverlap("Output directory", outDir, process.cwd(), publicDir);
|
|
61935
63753
|
await assertThemeDirectory(themeDir);
|
|
61936
63754
|
await assertEmptyOutputDirectory(outDir);
|
|
61937
|
-
await
|
|
63755
|
+
const hasPublicRobotsTxt = await publicRobotsTxtExists(publicDir);
|
|
63756
|
+
const publicFavicon = await discoverPublicFavicon(publicDir);
|
|
63757
|
+
const sitemapStylesheetHref = await discoverPublicSitemapStylesheet(publicDir);
|
|
63758
|
+
await copyPublicDirectory(publicDir, outDir);
|
|
61938
63759
|
const writer = new GeneratedOutputWriter({ outDir });
|
|
61939
63760
|
return buildSiteFromThemeDir({
|
|
61940
63761
|
previewData,
|
|
61941
63762
|
themeDir,
|
|
61942
|
-
writer
|
|
63763
|
+
writer,
|
|
63764
|
+
options: {
|
|
63765
|
+
favicon: publicFavicon,
|
|
63766
|
+
sitemapStylesheetHref,
|
|
63767
|
+
generateRobotsTxt: !hasPublicRobotsTxt
|
|
63768
|
+
}
|
|
61943
63769
|
});
|
|
61944
63770
|
}
|
|
61945
63771
|
var GeneratedOutputWriter = class {
|
|
@@ -61977,7 +63803,10 @@ async function assertEmptyOutputDirectory(outDir) {
|
|
|
61977
63803
|
throw error;
|
|
61978
63804
|
}
|
|
61979
63805
|
}
|
|
61980
|
-
function resolvePublicDir(cwd = process.cwd()) {
|
|
63806
|
+
function resolvePublicDir(cwd = process.cwd(), publicDir) {
|
|
63807
|
+
if (publicDir) {
|
|
63808
|
+
return path.resolve(cwd, publicDir);
|
|
63809
|
+
}
|
|
61981
63810
|
const envValue = process.env[PUBLIC_DIR_ENV_NAME]?.trim();
|
|
61982
63811
|
return path.resolve(cwd, envValue || DEFAULT_PUBLIC_DIR_NAME);
|
|
61983
63812
|
}
|
|
@@ -61996,6 +63825,48 @@ async function copyPublicDirectory(publicDir, outDir) {
|
|
|
61996
63825
|
}
|
|
61997
63826
|
await copyPublicEntries(publicDir, outDir);
|
|
61998
63827
|
}
|
|
63828
|
+
async function publicRobotsTxtExists(publicDir) {
|
|
63829
|
+
let stat;
|
|
63830
|
+
try {
|
|
63831
|
+
stat = await fs.lstat(path.join(publicDir, "robots.txt"));
|
|
63832
|
+
} catch (error) {
|
|
63833
|
+
if (error && (error.code === "ENOENT" || error.code === "ENOTDIR")) {
|
|
63834
|
+
return false;
|
|
63835
|
+
}
|
|
63836
|
+
throw error;
|
|
63837
|
+
}
|
|
63838
|
+
return stat.isFile();
|
|
63839
|
+
}
|
|
63840
|
+
async function discoverPublicFavicon(publicDir) {
|
|
63841
|
+
const favicon = {};
|
|
63842
|
+
for (const [key, filename] of Object.entries(PUBLIC_FAVICON_FILES)) {
|
|
63843
|
+
let stat;
|
|
63844
|
+
try {
|
|
63845
|
+
stat = await fs.lstat(path.join(publicDir, filename));
|
|
63846
|
+
} catch (error) {
|
|
63847
|
+
if (error && (error.code === "ENOENT" || error.code === "ENOTDIR")) {
|
|
63848
|
+
continue;
|
|
63849
|
+
}
|
|
63850
|
+
throw error;
|
|
63851
|
+
}
|
|
63852
|
+
if (stat.isFile()) {
|
|
63853
|
+
favicon[key] = `/${filename}`;
|
|
63854
|
+
}
|
|
63855
|
+
}
|
|
63856
|
+
return Object.keys(favicon).length ? favicon : void 0;
|
|
63857
|
+
}
|
|
63858
|
+
async function discoverPublicSitemapStylesheet(publicDir) {
|
|
63859
|
+
let stat;
|
|
63860
|
+
try {
|
|
63861
|
+
stat = await fs.lstat(path.join(publicDir, PUBLIC_SITEMAP_STYLESHEET_FILE));
|
|
63862
|
+
} catch (error) {
|
|
63863
|
+
if (error && (error.code === "ENOENT" || error.code === "ENOTDIR")) {
|
|
63864
|
+
return void 0;
|
|
63865
|
+
}
|
|
63866
|
+
throw error;
|
|
63867
|
+
}
|
|
63868
|
+
return stat.isFile() ? `/${PUBLIC_SITEMAP_STYLESHEET_FILE}` : void 0;
|
|
63869
|
+
}
|
|
61999
63870
|
async function copyPublicEntries(sourceDir, targetDir) {
|
|
62000
63871
|
const entries = await fs.readdir(sourceDir, { withFileTypes: true });
|
|
62001
63872
|
for (const entry of entries) {
|
|
@@ -62020,8 +63891,7 @@ function shouldIgnorePublicEntry(name) {
|
|
|
62020
63891
|
const lowerName = basename.toLowerCase();
|
|
62021
63892
|
return basename.startsWith(".") || lowerName === "node_modules" || lowerName === "thumbs.db" || lowerName.endsWith(".key") || lowerName.endsWith(".pem");
|
|
62022
63893
|
}
|
|
62023
|
-
function assertPublicPathDoesNotOverlap(label, candidatePath, cwd = process.cwd()) {
|
|
62024
|
-
const publicDir = resolvePublicDir(cwd);
|
|
63894
|
+
function assertPublicPathDoesNotOverlap(label, candidatePath, cwd = process.cwd(), publicDir = resolvePublicDir(cwd)) {
|
|
62025
63895
|
const resolvedCandidate = path.resolve(cwd, candidatePath);
|
|
62026
63896
|
if (!pathsOverlap(publicDir, resolvedCandidate)) {
|
|
62027
63897
|
return;
|
|
@@ -62332,7 +64202,7 @@ try {
|
|
|
62332
64202
|
process.exitCode = 1;
|
|
62333
64203
|
}
|
|
62334
64204
|
function input(name) {
|
|
62335
|
-
return process.env[`INPUT_${name.toUpperCase()
|
|
64205
|
+
return process.env[`INPUT_${name.toUpperCase()}`]?.trim() || "";
|
|
62336
64206
|
}
|
|
62337
64207
|
function booleanInput(name, fallback) {
|
|
62338
64208
|
const value = input(name);
|