@zeropress/build-core 0.6.1 → 0.6.2
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 +6 -2
- package/package.json +3 -3
- package/src/api/build-site.js +99 -2
package/README.md
CHANGED
|
@@ -57,8 +57,9 @@ import {
|
|
|
57
57
|
- `feed.xml`
|
|
58
58
|
- fallback `robots.txt`
|
|
59
59
|
- `/_zeropress/comment-policy.json`
|
|
60
|
-
- `/_zeropress/search.json`
|
|
61
|
-
- `/_zeropress/search.js`
|
|
60
|
+
- `/_zeropress/search.json` when native search is enabled
|
|
61
|
+
- `/_zeropress/search.js` when native search is enabled
|
|
62
|
+
- `/_zeropress/search_pagefind.js` when native search is enabled
|
|
62
63
|
- writing outputs through a pluggable writer
|
|
63
64
|
|
|
64
65
|
It does not:
|
|
@@ -212,6 +213,9 @@ The canonical `preview-data v0.6` site contract uses:
|
|
|
212
213
|
- `site.disallow_comments`
|
|
213
214
|
- `site.indexing`
|
|
214
215
|
- `site.expose_generator`
|
|
216
|
+
- `site.search`
|
|
217
|
+
|
|
218
|
+
Native search artifacts are emitted only when preview-data does not set `site.search: false` and the active theme declares `features.search: true`. `search_pagefind.js` is a Pagefind adapter that can replace `search.js` after a post-build Pagefind step.
|
|
215
219
|
|
|
216
220
|
Optional route templates behave as rendering capabilities, not guaranteed outputs:
|
|
217
221
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zeropress/build-core",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.2",
|
|
4
4
|
"description": "Shared ZeroPress build core",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -34,8 +34,8 @@
|
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"@zeropress/slug-policy": "0.1.0",
|
|
37
|
-
"@zeropress/preview-data-validator": "0.6.
|
|
38
|
-
"@zeropress/theme-validator": "0.6.
|
|
37
|
+
"@zeropress/preview-data-validator": "0.6.2",
|
|
38
|
+
"@zeropress/theme-validator": "0.6.2",
|
|
39
39
|
"highlight.js": "^11.11.1",
|
|
40
40
|
"markdown-it": "^14.1.0",
|
|
41
41
|
"markdown-it-anchor": "^9.2.0"
|
package/src/api/build-site.js
CHANGED
|
@@ -40,6 +40,7 @@ const PERMALINK_OUTPUT_STYLES = new Set(['directory', 'html-extension']);
|
|
|
40
40
|
const COMMENT_POLICY_OUTPUT_PATH = '_zeropress/comment-policy.json';
|
|
41
41
|
const SEARCH_INDEX_OUTPUT_PATH = '_zeropress/search.json';
|
|
42
42
|
const SEARCH_ADAPTER_OUTPUT_PATH = '_zeropress/search.js';
|
|
43
|
+
const SEARCH_PAGEFIND_ADAPTER_OUTPUT_PATH = '_zeropress/search_pagefind.js';
|
|
43
44
|
const OUTPUT_PATH_CONTROL_CHAR_PATTERN = /[\u0000-\u001F\u007F]/;
|
|
44
45
|
const SAFE_MEDIA_PROTOCOLS = new Set(['http:', 'https:']);
|
|
45
46
|
const SAFE_LINK_PROTOCOLS = new Set(['http:', 'https:', 'mailto:', 'tel:']);
|
|
@@ -107,9 +108,13 @@ export async function buildSite(input) {
|
|
|
107
108
|
'application/json',
|
|
108
109
|
);
|
|
109
110
|
|
|
110
|
-
if (options
|
|
111
|
+
if (shouldGenerateSearchArtifacts(state, options)) {
|
|
111
112
|
await writeOutput(state.writer, state.summaries, SEARCH_INDEX_OUTPUT_PATH, buildSearchIndexJson(state), 'application/json');
|
|
112
113
|
await writeOutput(state.writer, state.summaries, SEARCH_ADAPTER_OUTPUT_PATH, buildSearchAdapterJs(), 'application/javascript');
|
|
114
|
+
await writeOutput(state.writer, state.summaries, SEARCH_PAGEFIND_ADAPTER_OUTPUT_PATH, buildSearchPagefindAdapterJs(), 'application/javascript');
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (options.generateSpecialFiles) {
|
|
113
118
|
await maybeRenderNotFoundPage(state);
|
|
114
119
|
if (hasCanonicalSiteUrl(state.previewData.site.url)) {
|
|
115
120
|
await writeOutput(
|
|
@@ -459,6 +464,7 @@ function normalizePreviewData(previewData, options = {}) {
|
|
|
459
464
|
locale: normalizeLocale(previewData.site.locale || DEFAULT_LOCALE),
|
|
460
465
|
disallow_comments: previewData.site.disallow_comments === true,
|
|
461
466
|
expose_generator: previewData.site.expose_generator !== false,
|
|
467
|
+
search: previewData.site.search !== false,
|
|
462
468
|
indexing: previewData.site.indexing !== false,
|
|
463
469
|
permalinks: normalizePermalinks(previewData.site.permalinks),
|
|
464
470
|
front_page: normalizeFrontPage(previewData.site.front_page),
|
|
@@ -794,6 +800,8 @@ function normalizePostIndex(post_index) {
|
|
|
794
800
|
function createRenderData(previewData, themeMetadata = {}) {
|
|
795
801
|
const themeSupportsComments = themeMetadata?.features?.comments === true;
|
|
796
802
|
const themeSupportsPostIndex = themeMetadata?.features?.post_index !== false;
|
|
803
|
+
const themeSupportsSearch = themeMetadata?.features?.search === true;
|
|
804
|
+
previewData.site.search = previewData.site.search !== false && themeSupportsSearch;
|
|
797
805
|
const authorsById = new Map(previewData.content.authors.map((author) => [author.id, author]));
|
|
798
806
|
const categoriesBySlug = new Map(previewData.content.categories.map((category) => [category.slug, category]));
|
|
799
807
|
const tagsBySlug = new Map(previewData.content.tags.map((tag) => [tag.slug, tag]));
|
|
@@ -2393,8 +2401,11 @@ function assertPlannedOutputPathsSafe(state) {
|
|
|
2393
2401
|
COMMENT_POLICY_OUTPUT_PATH,
|
|
2394
2402
|
];
|
|
2395
2403
|
|
|
2404
|
+
if (shouldGenerateSearchArtifacts(state, state.options)) {
|
|
2405
|
+
plannedPaths.push(SEARCH_INDEX_OUTPUT_PATH, SEARCH_ADAPTER_OUTPUT_PATH, SEARCH_PAGEFIND_ADAPTER_OUTPUT_PATH);
|
|
2406
|
+
}
|
|
2407
|
+
|
|
2396
2408
|
if (state.options.generateSpecialFiles) {
|
|
2397
|
-
plannedPaths.push(SEARCH_INDEX_OUTPUT_PATH, SEARCH_ADAPTER_OUTPUT_PATH);
|
|
2398
2409
|
plannedPaths.push('404.html');
|
|
2399
2410
|
if (shouldGenerateRobotsTxt(state.options)) {
|
|
2400
2411
|
plannedPaths.push('robots.txt');
|
|
@@ -2965,6 +2976,88 @@ function normalizeLimit(value) {
|
|
|
2965
2976
|
`;
|
|
2966
2977
|
}
|
|
2967
2978
|
|
|
2979
|
+
function buildSearchPagefindAdapterJs() {
|
|
2980
|
+
return `let pagefindPromise;
|
|
2981
|
+
|
|
2982
|
+
export async function preload() {
|
|
2983
|
+
if (!pagefindPromise) {
|
|
2984
|
+
pagefindPromise = import(new URL('./pagefind/pagefind.js', import.meta.url).href).then(async (pagefind) => {
|
|
2985
|
+
if (typeof pagefind.options === 'function') {
|
|
2986
|
+
await pagefind.options({ baseUrl: '/' });
|
|
2987
|
+
}
|
|
2988
|
+
return pagefind;
|
|
2989
|
+
});
|
|
2990
|
+
}
|
|
2991
|
+
|
|
2992
|
+
return pagefindPromise;
|
|
2993
|
+
}
|
|
2994
|
+
|
|
2995
|
+
export async function search(query, options = {}) {
|
|
2996
|
+
const pagefind = await preload();
|
|
2997
|
+
const result = await pagefind.search(query, options);
|
|
2998
|
+
const limit = normalizeLimit(options.limit);
|
|
2999
|
+
if (!Array.isArray(result?.results)) {
|
|
3000
|
+
return result;
|
|
3001
|
+
}
|
|
3002
|
+
|
|
3003
|
+
const results = result.results.map(normalizeResult);
|
|
3004
|
+
return {
|
|
3005
|
+
...result,
|
|
3006
|
+
results: limit ? results.slice(0, limit) : results,
|
|
3007
|
+
};
|
|
3008
|
+
}
|
|
3009
|
+
|
|
3010
|
+
function normalizeResult(result) {
|
|
3011
|
+
if (!result || typeof result.data !== 'function') {
|
|
3012
|
+
return result;
|
|
3013
|
+
}
|
|
3014
|
+
|
|
3015
|
+
return {
|
|
3016
|
+
...result,
|
|
3017
|
+
data: async () => normalizeResultData(await result.data()),
|
|
3018
|
+
};
|
|
3019
|
+
}
|
|
3020
|
+
|
|
3021
|
+
function normalizeResultData(data) {
|
|
3022
|
+
if (!data || typeof data !== 'object') {
|
|
3023
|
+
return data;
|
|
3024
|
+
}
|
|
3025
|
+
|
|
3026
|
+
return {
|
|
3027
|
+
...data,
|
|
3028
|
+
url: normalizeUrl(data.url),
|
|
3029
|
+
sub_results: Array.isArray(data.sub_results)
|
|
3030
|
+
? data.sub_results.map((item) => ({ ...item, url: normalizeUrl(item.url) }))
|
|
3031
|
+
: data.sub_results,
|
|
3032
|
+
};
|
|
3033
|
+
}
|
|
3034
|
+
|
|
3035
|
+
function normalizeUrl(value) {
|
|
3036
|
+
const url = String(value || '');
|
|
3037
|
+
if (url.startsWith('/_zeropress/') && !url.startsWith('/_zeropress/pagefind/')) {
|
|
3038
|
+
return url.replace(/^\\/_zeropress/, '') || '/';
|
|
3039
|
+
}
|
|
3040
|
+
if (url.startsWith('_zeropress/') && !url.startsWith('_zeropress/pagefind/')) {
|
|
3041
|
+
return url.replace(/^_zeropress/, '') || '/';
|
|
3042
|
+
}
|
|
3043
|
+
return url;
|
|
3044
|
+
}
|
|
3045
|
+
|
|
3046
|
+
function normalizeLimit(value) {
|
|
3047
|
+
if (value === undefined || value === null) {
|
|
3048
|
+
return null;
|
|
3049
|
+
}
|
|
3050
|
+
|
|
3051
|
+
const limit = Number(value);
|
|
3052
|
+
if (!Number.isFinite(limit) || limit <= 0) {
|
|
3053
|
+
return null;
|
|
3054
|
+
}
|
|
3055
|
+
|
|
3056
|
+
return Math.floor(limit);
|
|
3057
|
+
}
|
|
3058
|
+
`;
|
|
3059
|
+
}
|
|
3060
|
+
|
|
2968
3061
|
function buildSitemapXml(site, emitted, generatedAt, stylesheetHref = '') {
|
|
2969
3062
|
const entries = [
|
|
2970
3063
|
...(emitted.frontPage && emitted.frontPage.includeInSitemap !== false
|
|
@@ -3045,6 +3138,10 @@ function shouldGenerateRobotsTxt(options) {
|
|
|
3045
3138
|
return options.generateSpecialFiles && options.generateRobotsTxt !== false;
|
|
3046
3139
|
}
|
|
3047
3140
|
|
|
3141
|
+
function shouldGenerateSearchArtifacts(state, options) {
|
|
3142
|
+
return options.generateSpecialFiles && state.previewData.site.search === true;
|
|
3143
|
+
}
|
|
3144
|
+
|
|
3048
3145
|
function getContentType(assetPath) {
|
|
3049
3146
|
const ext = assetPath.split('.').pop()?.toLowerCase();
|
|
3050
3147
|
const contentTypes = {
|