@rettangoli/sites 1.0.3 → 1.1.0
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 +22 -1
- package/package.json +1 -1
- package/src/createSiteBuilder.js +231 -126
package/README.md
CHANGED
|
@@ -32,7 +32,7 @@ my-site/
|
|
|
32
32
|
|
|
33
33
|
- YAML pages rendered through `jempl` + `yahtml`
|
|
34
34
|
- Markdown pages rendered through `markdown-it` + Shiki (default `rtglMarkdown`)
|
|
35
|
-
- Frontmatter (`template`, `tags`, arbitrary page metadata)
|
|
35
|
+
- Frontmatter (`template`, `url`, `tags`, arbitrary page metadata)
|
|
36
36
|
- Global data from `data/*.yaml` and optional inline `sites.config.yaml data`
|
|
37
37
|
- Collections built from page tags
|
|
38
38
|
- `$if`, `$for`, `$partial`, template functions
|
|
@@ -96,6 +96,27 @@ Example mappings:
|
|
|
96
96
|
- `pages/index.md` -> `_site/index.html` and `_site/index.md`
|
|
97
97
|
- `pages/docs/intro.md` -> `_site/docs/intro/index.html` and `_site/docs/intro.md`
|
|
98
98
|
|
|
99
|
+
For Markdown pages with a custom `url`, the copied `.md` file follows the custom URL path.
|
|
100
|
+
For example, `url: /guides/start/` writes `_site/guides/start/index.html` and `_site/guides/start.md`.
|
|
101
|
+
|
|
102
|
+
Pages use their file path as the URL by default:
|
|
103
|
+
- `pages/index.*` -> `/`
|
|
104
|
+
- `pages/about.*` -> `/about/`
|
|
105
|
+
- `pages/docs/intro.*` -> `/docs/intro/`
|
|
106
|
+
|
|
107
|
+
Set `url` in page frontmatter to override that path:
|
|
108
|
+
|
|
109
|
+
```md
|
|
110
|
+
---
|
|
111
|
+
title: Company
|
|
112
|
+
url: /company/
|
|
113
|
+
---
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
`url` is normalized to a site-relative clean URL with a leading and trailing slash, so `company` becomes `/company/`.
|
|
117
|
+
External URLs, query strings, fragments, whitespace, and `.` / `..` path segments are rejected.
|
|
118
|
+
Duplicate page URLs are rejected after normalization.
|
|
119
|
+
|
|
99
120
|
`imports` lets you map aliases to remote YAML files (HTTP/HTTPS only). Use aliases in pages/templates:
|
|
100
121
|
- page frontmatter: `template: base` or `template: docs`
|
|
101
122
|
- template/page content: `$partial: docs/nav`
|
package/package.json
CHANGED
package/src/createSiteBuilder.js
CHANGED
|
@@ -228,6 +228,123 @@ function isSchemaSidecarFile(fileName) {
|
|
|
228
228
|
return fileName.endsWith('.schema.yaml') || fileName.endsWith('.schema.yml');
|
|
229
229
|
}
|
|
230
230
|
|
|
231
|
+
function hasPageExtension(fileName) {
|
|
232
|
+
return fileName.endsWith('.yaml') || fileName.endsWith('.yml') || fileName.endsWith('.md');
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
function hasOwn(object, key) {
|
|
236
|
+
return Object.prototype.hasOwnProperty.call(object, key);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
function normalizeRelativeUrlPath(relativePath) {
|
|
240
|
+
return relativePath.replace(/\\/g, '/');
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function derivePageUrlFromRelativePath(relativePath) {
|
|
244
|
+
const normalizedPath = normalizeRelativeUrlPath(relativePath);
|
|
245
|
+
const pathWithoutExtension = normalizedPath.replace(/\.(yaml|yml|md)$/, '');
|
|
246
|
+
const pageName = path.posix.basename(pathWithoutExtension);
|
|
247
|
+
|
|
248
|
+
if (pageName === 'index') {
|
|
249
|
+
const dirName = path.posix.dirname(pathWithoutExtension);
|
|
250
|
+
return dirName === '.' ? '/' : `/${dirName}/`;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
return `/${pathWithoutExtension}/`;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function normalizePageUrlOverride(rawUrl, pagePath) {
|
|
257
|
+
if (typeof rawUrl !== 'string') {
|
|
258
|
+
throw new Error(`Invalid url in ${pagePath}: expected a string.`);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
if (rawUrl === '') {
|
|
262
|
+
throw new Error(`Invalid url in ${pagePath}: expected a non-empty string.`);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
if (/[\u0000-\u001F\u007F]/u.test(rawUrl)) {
|
|
266
|
+
throw new Error(`Invalid url in ${pagePath}: must not contain control characters.`);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
if (/\s/u.test(rawUrl)) {
|
|
270
|
+
throw new Error(`Invalid url in ${pagePath}: must not contain whitespace.`);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
if (/^[A-Za-z][A-Za-z0-9+.-]*:/u.test(rawUrl) || rawUrl.startsWith('//')) {
|
|
274
|
+
throw new Error(`Invalid url in ${pagePath}: expected a site-relative URL path.`);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
if (rawUrl.includes('\\')) {
|
|
278
|
+
throw new Error(`Invalid url in ${pagePath}: must use forward slashes.`);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
if (rawUrl.includes('?') || rawUrl.includes('#')) {
|
|
282
|
+
throw new Error(`Invalid url in ${pagePath}: must not include query strings or fragments.`);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
const withLeadingSlash = rawUrl.startsWith('/') ? rawUrl : `/${rawUrl}`;
|
|
286
|
+
const collapsedUrl = withLeadingSlash.replace(/\/+/g, '/');
|
|
287
|
+
const pathWithoutSlashes = collapsedUrl.replace(/^\/+|\/+$/g, '');
|
|
288
|
+
|
|
289
|
+
if (pathWithoutSlashes === '') {
|
|
290
|
+
return '/';
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
const segments = pathWithoutSlashes.split('/');
|
|
294
|
+
for (const segment of segments) {
|
|
295
|
+
let decodedSegment;
|
|
296
|
+
try {
|
|
297
|
+
decodedSegment = decodeURIComponent(segment);
|
|
298
|
+
} catch (error) {
|
|
299
|
+
throw new Error(`Invalid url in ${pagePath}: contains invalid URL encoding.`);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
if (decodedSegment === '.' || decodedSegment === '..') {
|
|
303
|
+
throw new Error(`Invalid url in ${pagePath}: must not contain "." or ".." segments.`);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
if (decodedSegment.includes('/') || decodedSegment.includes('\\')) {
|
|
307
|
+
throw new Error(`Invalid url in ${pagePath}: must not include encoded slashes or backslashes.`);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
if (/[\u0000-\u001F\u007F]/u.test(decodedSegment)) {
|
|
311
|
+
throw new Error(`Invalid url in ${pagePath}: must not contain control characters.`);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
if (/\s/u.test(decodedSegment)) {
|
|
315
|
+
throw new Error(`Invalid url in ${pagePath}: must not contain whitespace.`);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
return `/${segments.join('/')}/`;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
function resolvePageUrl(publicFrontmatter, relativePath, pagePath) {
|
|
323
|
+
if (hasOwn(publicFrontmatter, 'url')) {
|
|
324
|
+
return normalizePageUrlOverride(publicFrontmatter.url, pagePath);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
return derivePageUrlFromRelativePath(relativePath);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
function htmlOutputRelativePathFromUrl(url) {
|
|
331
|
+
if (url === '/') {
|
|
332
|
+
return 'index.html';
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
return `${url.slice(1, -1)}/index.html`;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
function markdownOutputRelativePathFromUrl(url) {
|
|
339
|
+
if (url === '/') {
|
|
340
|
+
return 'index.md';
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
const segments = url.slice(1, -1).split('/');
|
|
344
|
+
const fileName = `${segments.pop()}.md`;
|
|
345
|
+
return [...segments, fileName].join('/');
|
|
346
|
+
}
|
|
347
|
+
|
|
231
348
|
async function fetchRemoteYaml(url, fetchImpl, aliasLabel) {
|
|
232
349
|
const effectiveFetch = fetchImpl || globalThis.fetch;
|
|
233
350
|
if (typeof effectiveFetch !== 'function') {
|
|
@@ -485,12 +602,11 @@ export function createSiteBuilder({
|
|
|
485
602
|
};
|
|
486
603
|
}
|
|
487
604
|
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
const collections = {};
|
|
605
|
+
function collectPageEntries() {
|
|
606
|
+
const pageEntries = [];
|
|
491
607
|
const pagesDir = path.join(rootDir, 'pages');
|
|
492
608
|
|
|
493
|
-
function scanPages(
|
|
609
|
+
function scanPages(basePath = '') {
|
|
494
610
|
const fullDir = path.join(pagesDir, basePath);
|
|
495
611
|
if (!fs.existsSync(fullDir)) return;
|
|
496
612
|
|
|
@@ -502,82 +618,122 @@ export function createSiteBuilder({
|
|
|
502
618
|
const itemKind = resolveDirentKind(fs, itemPath, item);
|
|
503
619
|
|
|
504
620
|
if (itemKind === 'directory') {
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
} else if (itemKind === 'file' && (item.name.endsWith('.yaml') || item.name.endsWith('.yml') || item.name.endsWith('.md'))) {
|
|
508
|
-
// Extract frontmatter and content
|
|
621
|
+
scanPages(relativePath);
|
|
622
|
+
} else if (itemKind === 'file' && hasPageExtension(item.name)) {
|
|
509
623
|
const { frontmatter, content } = extractFrontmatterAndContent(itemPath);
|
|
510
|
-
const { frontmatter: publicFrontmatter } = splitSystemFrontmatter(frontmatter, globalData, itemPath);
|
|
624
|
+
const { frontmatter: publicFrontmatter, bindings } = splitSystemFrontmatter(frontmatter, globalData, itemPath);
|
|
625
|
+
const hasCustomUrl = hasOwn(publicFrontmatter, 'url');
|
|
626
|
+
const url = resolvePageUrl(publicFrontmatter, relativePath, itemPath);
|
|
627
|
+
const exposedFrontmatter = hasCustomUrl
|
|
628
|
+
? { ...publicFrontmatter, url }
|
|
629
|
+
: publicFrontmatter;
|
|
630
|
+
|
|
631
|
+
pageEntries.push({
|
|
632
|
+
pagePath: itemPath,
|
|
633
|
+
relativePath: normalizeRelativeUrlPath(relativePath),
|
|
634
|
+
isMarkdown: item.name.endsWith('.md'),
|
|
635
|
+
content,
|
|
636
|
+
frontmatter: exposedFrontmatter,
|
|
637
|
+
bindings,
|
|
638
|
+
url,
|
|
639
|
+
hasCustomUrl
|
|
640
|
+
});
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
}
|
|
511
644
|
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
645
|
+
scanPages();
|
|
646
|
+
return pageEntries;
|
|
647
|
+
}
|
|
515
648
|
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
649
|
+
function assertUniquePageUrls(pageEntries) {
|
|
650
|
+
const seen = new Map();
|
|
651
|
+
|
|
652
|
+
for (const entry of pageEntries) {
|
|
653
|
+
const existingEntry = seen.get(entry.url);
|
|
654
|
+
if (existingEntry) {
|
|
655
|
+
throw new Error(`Duplicate page URL "${entry.url}" in ${entry.pagePath}; already used by ${existingEntry.pagePath}.`);
|
|
656
|
+
}
|
|
657
|
+
seen.set(entry.url, entry);
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
function assertUniqueMarkdownOutputPaths(pageEntries) {
|
|
662
|
+
if (!keepMarkdownFiles) {
|
|
663
|
+
return;
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
const seen = new Map();
|
|
667
|
+
for (const entry of pageEntries) {
|
|
668
|
+
if (!entry.isMarkdown) {
|
|
669
|
+
continue;
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
const markdownOutputRelativePath = entry.hasCustomUrl
|
|
673
|
+
? markdownOutputRelativePathFromUrl(entry.url)
|
|
674
|
+
: entry.relativePath;
|
|
675
|
+
const existingEntry = seen.get(markdownOutputRelativePath);
|
|
676
|
+
if (existingEntry) {
|
|
677
|
+
throw new Error(`Duplicate markdown output path "${markdownOutputRelativePath}" in ${entry.pagePath}; already used by ${existingEntry.pagePath}.`);
|
|
678
|
+
}
|
|
679
|
+
seen.set(markdownOutputRelativePath, entry);
|
|
680
|
+
}
|
|
681
|
+
}
|
|
526
682
|
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
683
|
+
// Function to scan all pages and build collections
|
|
684
|
+
function buildCollections(pageEntries) {
|
|
685
|
+
const collections = {};
|
|
686
|
+
|
|
687
|
+
for (const entry of pageEntries) {
|
|
688
|
+
const publicFrontmatter = entry.frontmatter;
|
|
689
|
+
|
|
690
|
+
// Process tags
|
|
691
|
+
if (publicFrontmatter.tags) {
|
|
692
|
+
// Normalize tags to array
|
|
693
|
+
const tags = Array.isArray(publicFrontmatter.tags) ? publicFrontmatter.tags : [publicFrontmatter.tags];
|
|
694
|
+
|
|
695
|
+
// Add to collections
|
|
696
|
+
tags.forEach(tag => {
|
|
697
|
+
if (typeof tag === 'string' && tag.trim()) {
|
|
698
|
+
const trimmedTag = tag.trim();
|
|
699
|
+
if (!collections[trimmedTag]) {
|
|
700
|
+
collections[trimmedTag] = [];
|
|
701
|
+
}
|
|
702
|
+
collections[trimmedTag].push({
|
|
703
|
+
data: publicFrontmatter,
|
|
704
|
+
url: entry.url,
|
|
705
|
+
content: entry.content
|
|
545
706
|
});
|
|
546
707
|
}
|
|
547
|
-
}
|
|
708
|
+
});
|
|
548
709
|
}
|
|
549
710
|
}
|
|
550
711
|
|
|
551
|
-
scanPages('');
|
|
552
712
|
return collections;
|
|
553
713
|
}
|
|
554
714
|
|
|
715
|
+
const pageEntries = collectPageEntries();
|
|
716
|
+
assertUniquePageUrls(pageEntries);
|
|
717
|
+
assertUniqueMarkdownOutputPaths(pageEntries);
|
|
718
|
+
|
|
555
719
|
// Build collections in first pass
|
|
556
720
|
if (!quiet) console.log('Building collections...');
|
|
557
|
-
const collections = buildCollections();
|
|
721
|
+
const collections = buildCollections(pageEntries);
|
|
558
722
|
|
|
559
723
|
// Function to process a single page file
|
|
560
|
-
async function processPage(
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
724
|
+
async function processPage(pageEntry) {
|
|
725
|
+
const {
|
|
726
|
+
pagePath,
|
|
727
|
+
content: rawContent,
|
|
728
|
+
frontmatter: publicFrontmatter,
|
|
729
|
+
bindings: boundData,
|
|
730
|
+
isMarkdown,
|
|
731
|
+
url,
|
|
732
|
+
hasCustomUrl,
|
|
733
|
+
relativePath
|
|
734
|
+
} = pageEntry;
|
|
570
735
|
|
|
571
|
-
|
|
572
|
-
if (fileName === 'index') {
|
|
573
|
-
url = basePath && basePath !== '.' ? '/' + basePath.replace(/\\/g, '/') : '/';
|
|
574
|
-
if (url !== '/') {
|
|
575
|
-
url = url + '/';
|
|
576
|
-
}
|
|
577
|
-
} else {
|
|
578
|
-
const pagePath = basePath && basePath !== '.' ? path.join(basePath, fileName) : fileName;
|
|
579
|
-
url = '/' + pagePath.replace(/\\/g, '/') + '/';
|
|
580
|
-
}
|
|
736
|
+
if (!quiet) console.log(`Processing ${pagePath}...`);
|
|
581
737
|
|
|
582
738
|
// Deep merge global data with frontmatter and collections for the page context
|
|
583
739
|
const pageData = deepMerge(globalData, publicFrontmatter);
|
|
@@ -648,35 +804,9 @@ export function createSiteBuilder({
|
|
|
648
804
|
htmlString = convertToHtml(resultArray);
|
|
649
805
|
}
|
|
650
806
|
|
|
651
|
-
|
|
652
|
-
const
|
|
653
|
-
const
|
|
654
|
-
|
|
655
|
-
let outputPath, outputDir;
|
|
656
|
-
|
|
657
|
-
// Special case: index files remain as index.html, others become directory/index.html
|
|
658
|
-
if (pageFileName === 'index') {
|
|
659
|
-
if (dirPath && dirPath !== '.') {
|
|
660
|
-
// Nested index file: pages/blog/index.yaml -> _site/blog/index.html
|
|
661
|
-
outputPath = path.join(outputRootDir, dirPath, 'index.html');
|
|
662
|
-
outputDir = path.join(outputRootDir, dirPath);
|
|
663
|
-
} else {
|
|
664
|
-
// Root index file: pages/index.yaml -> _site/index.html
|
|
665
|
-
outputPath = path.join(outputRootDir, 'index.html');
|
|
666
|
-
outputDir = path.join(outputRootDir);
|
|
667
|
-
}
|
|
668
|
-
} else {
|
|
669
|
-
// Regular file: pages/test.yaml -> _site/test/index.html
|
|
670
|
-
if (dirPath && dirPath !== '.') {
|
|
671
|
-
// Nested regular file: pages/blog/post.yaml -> _site/blog/post/index.html
|
|
672
|
-
outputPath = path.join(outputRootDir, dirPath, pageFileName, 'index.html');
|
|
673
|
-
outputDir = path.join(outputRootDir, dirPath, pageFileName);
|
|
674
|
-
} else {
|
|
675
|
-
// Root level regular file: pages/test.yaml -> _site/test/index.html
|
|
676
|
-
outputPath = path.join(outputRootDir, pageFileName, 'index.html');
|
|
677
|
-
outputDir = path.join(outputRootDir, pageFileName);
|
|
678
|
-
}
|
|
679
|
-
}
|
|
807
|
+
const outputRelativePath = htmlOutputRelativePathFromUrl(url);
|
|
808
|
+
const outputPath = path.join(outputRootDir, ...outputRelativePath.split('/'));
|
|
809
|
+
const outputDir = path.dirname(outputPath);
|
|
680
810
|
|
|
681
811
|
if (!fs.existsSync(outputDir)) {
|
|
682
812
|
fs.mkdirSync(outputDir, { recursive: true });
|
|
@@ -686,8 +816,11 @@ export function createSiteBuilder({
|
|
|
686
816
|
fs.writeFileSync(outputPath, htmlString);
|
|
687
817
|
if (!quiet) console.log(` -> Written to ${outputPath}`);
|
|
688
818
|
|
|
689
|
-
if (isMarkdown && keepMarkdownFiles
|
|
690
|
-
const
|
|
819
|
+
if (isMarkdown && keepMarkdownFiles) {
|
|
820
|
+
const markdownOutputRelativePath = hasCustomUrl
|
|
821
|
+
? markdownOutputRelativePathFromUrl(url)
|
|
822
|
+
: relativePath;
|
|
823
|
+
const markdownOutputPath = path.join(outputRootDir, ...markdownOutputRelativePath.split('/'));
|
|
691
824
|
const markdownOutputDir = path.dirname(markdownOutputPath);
|
|
692
825
|
if (!fs.existsSync(markdownOutputDir)) {
|
|
693
826
|
fs.mkdirSync(markdownOutputDir, { recursive: true });
|
|
@@ -697,37 +830,9 @@ export function createSiteBuilder({
|
|
|
697
830
|
}
|
|
698
831
|
}
|
|
699
832
|
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
const fullDir = path.join(pagesDir, basePath);
|
|
704
|
-
|
|
705
|
-
if (!fs.existsSync(fullDir)) return;
|
|
706
|
-
|
|
707
|
-
const items = fs.readdirSync(fullDir, { withFileTypes: true });
|
|
708
|
-
|
|
709
|
-
for (const item of items) {
|
|
710
|
-
const itemPath = path.join(fullDir, item.name);
|
|
711
|
-
const relativePath = basePath ? path.join(basePath, item.name) : item.name;
|
|
712
|
-
const itemKind = resolveDirentKind(fs, itemPath, item);
|
|
713
|
-
|
|
714
|
-
if (itemKind === 'directory') {
|
|
715
|
-
// Recursively process subdirectories
|
|
716
|
-
await processAllPages(dir, relativePath);
|
|
717
|
-
} else if (itemKind === 'file') {
|
|
718
|
-
if (item.name.endsWith('.yaml') || item.name.endsWith('.yml')) {
|
|
719
|
-
// Process YAML file
|
|
720
|
-
const outputFileName = item.name.replace(/\.(yaml|yml)$/, '.html');
|
|
721
|
-
const outputRelativePath = basePath ? path.join(basePath, outputFileName) : outputFileName;
|
|
722
|
-
await processPage(itemPath, outputRelativePath, false);
|
|
723
|
-
} else if (item.name.endsWith('.md')) {
|
|
724
|
-
// Process Markdown file
|
|
725
|
-
const outputFileName = item.name.replace('.md', '.html');
|
|
726
|
-
const outputRelativePath = basePath ? path.join(basePath, outputFileName) : outputFileName;
|
|
727
|
-
await processPage(itemPath, outputRelativePath, true, relativePath);
|
|
728
|
-
}
|
|
729
|
-
// Ignore other file types
|
|
730
|
-
}
|
|
833
|
+
async function processAllPages() {
|
|
834
|
+
for (const pageEntry of pageEntries) {
|
|
835
|
+
await processPage(pageEntry);
|
|
731
836
|
}
|
|
732
837
|
}
|
|
733
838
|
|
|
@@ -784,7 +889,7 @@ export function createSiteBuilder({
|
|
|
784
889
|
copyStaticFiles();
|
|
785
890
|
|
|
786
891
|
// Process all pages (can overwrite static files)
|
|
787
|
-
await processAllPages(
|
|
892
|
+
await processAllPages();
|
|
788
893
|
|
|
789
894
|
if (!quiet) console.log('Build complete!');
|
|
790
895
|
};
|