@stati/core 1.27.2 → 1.29.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 +6 -1
- package/dist/config/errors.d.ts +10 -0
- package/dist/config/errors.d.ts.map +1 -0
- package/dist/config/errors.js +10 -0
- package/dist/config/loader.d.ts.map +1 -1
- package/dist/config/loader.js +15 -2
- package/dist/constants.d.ts +26 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +23 -0
- package/dist/core/build.d.ts.map +1 -1
- package/dist/core/build.js +201 -41
- package/dist/core/collections.d.ts +139 -0
- package/dist/core/collections.d.ts.map +1 -0
- package/dist/core/collections.js +342 -0
- package/dist/core/content.d.ts.map +1 -1
- package/dist/core/content.js +2 -1
- package/dist/core/dev.d.ts.map +1 -1
- package/dist/core/dev.js +11 -62
- package/dist/core/expand.d.ts +86 -0
- package/dist/core/expand.d.ts.map +1 -0
- package/dist/core/expand.js +484 -0
- package/dist/core/isg/builder.d.ts +27 -2
- package/dist/core/isg/builder.d.ts.map +1 -1
- package/dist/core/isg/builder.js +83 -11
- package/dist/core/isg/deps.d.ts +9 -0
- package/dist/core/isg/deps.d.ts.map +1 -1
- package/dist/core/isg/deps.js +30 -1
- package/dist/core/isg/hash.d.ts +14 -2
- package/dist/core/isg/hash.d.ts.map +1 -1
- package/dist/core/isg/hash.js +30 -2
- package/dist/core/isg/index.d.ts +4 -2
- package/dist/core/isg/index.d.ts.map +1 -1
- package/dist/core/isg/index.js +4 -2
- package/dist/core/isg/manifest.js +14 -0
- package/dist/core/isg/prune.d.ts +32 -0
- package/dist/core/isg/prune.d.ts.map +1 -0
- package/dist/core/isg/prune.js +113 -0
- package/dist/core/markdown.d.ts +10 -1
- package/dist/core/markdown.d.ts.map +1 -1
- package/dist/core/markdown.js +13 -3
- package/dist/core/navigation.d.ts +4 -2
- package/dist/core/navigation.d.ts.map +1 -1
- package/dist/core/navigation.js +17 -2
- package/dist/core/templates.d.ts +15 -1
- package/dist/core/templates.d.ts.map +1 -1
- package/dist/core/templates.js +121 -126
- package/dist/core/utils/fs.utils.d.ts +29 -1
- package/dist/core/utils/fs.utils.d.ts.map +1 -1
- package/dist/core/utils/fs.utils.js +74 -1
- package/dist/core/utils/index.d.ts +3 -3
- package/dist/core/utils/index.d.ts.map +1 -1
- package/dist/core/utils/index.js +3 -3
- package/dist/core/utils/paths.utils.d.ts +15 -0
- package/dist/core/utils/paths.utils.d.ts.map +1 -1
- package/dist/core/utils/paths.utils.js +20 -0
- package/dist/core/utils/template-discovery.utils.d.ts +25 -1
- package/dist/core/utils/template-discovery.utils.d.ts.map +1 -1
- package/dist/core/utils/template-discovery.utils.js +61 -11
- package/dist/images/config.d.ts +52 -0
- package/dist/images/config.d.ts.map +1 -0
- package/dist/images/config.js +200 -0
- package/dist/images/index.d.ts +15 -0
- package/dist/images/index.d.ts.map +1 -0
- package/dist/images/index.js +11 -0
- package/dist/images/manifest.d.ts +36 -0
- package/dist/images/manifest.d.ts.map +1 -0
- package/dist/images/manifest.js +69 -0
- package/dist/images/markdown-rule.d.ts +26 -0
- package/dist/images/markdown-rule.d.ts.map +1 -0
- package/dist/images/markdown-rule.js +60 -0
- package/dist/images/markup.d.ts +39 -0
- package/dist/images/markup.d.ts.map +1 -0
- package/dist/images/markup.js +72 -0
- package/dist/images/og.d.ts +52 -0
- package/dist/images/og.d.ts.map +1 -0
- package/dist/images/og.js +165 -0
- package/dist/images/plan.d.ts +101 -0
- package/dist/images/plan.d.ts.map +1 -0
- package/dist/images/plan.js +128 -0
- package/dist/images/provider.d.ts +35 -0
- package/dist/images/provider.d.ts.map +1 -0
- package/dist/images/provider.js +70 -0
- package/dist/images/resolve.d.ts +45 -0
- package/dist/images/resolve.d.ts.map +1 -0
- package/dist/images/resolve.js +51 -0
- package/dist/images/runtime.d.ts +258 -0
- package/dist/images/runtime.d.ts.map +1 -0
- package/dist/images/runtime.js +659 -0
- package/dist/images/sources.d.ts +47 -0
- package/dist/images/sources.d.ts.map +1 -0
- package/dist/images/sources.js +97 -0
- package/dist/images/utils/image-probe.utils.d.ts +30 -0
- package/dist/images/utils/image-probe.utils.d.ts.map +1 -0
- package/dist/images/utils/image-probe.utils.js +307 -0
- package/dist/images/utils/index.d.ts +7 -0
- package/dist/images/utils/index.d.ts.map +1 -0
- package/dist/images/utils/index.js +5 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/metrics/noop.d.ts.map +1 -1
- package/dist/metrics/noop.js +3 -0
- package/dist/metrics/recorder.d.ts.map +1 -1
- package/dist/metrics/recorder.js +3 -0
- package/dist/metrics/types.d.ts +8 -0
- package/dist/metrics/types.d.ts.map +1 -1
- package/dist/rss/generator.d.ts.map +1 -1
- package/dist/rss/generator.js +5 -2
- package/dist/search/generator.d.ts +9 -0
- package/dist/search/generator.d.ts.map +1 -1
- package/dist/search/generator.js +20 -0
- package/dist/search/index.d.ts +1 -1
- package/dist/search/index.d.ts.map +1 -1
- package/dist/search/index.js +1 -1
- package/dist/seo/auto-inject.d.ts +3 -0
- package/dist/seo/auto-inject.d.ts.map +1 -1
- package/dist/seo/auto-inject.js +1 -0
- package/dist/seo/generator.d.ts +24 -0
- package/dist/seo/generator.d.ts.map +1 -1
- package/dist/seo/generator.js +65 -1
- package/dist/seo/index.d.ts +1 -1
- package/dist/seo/index.d.ts.map +1 -1
- package/dist/seo/index.js +1 -1
- package/dist/types/config.d.ts +60 -0
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/content.d.ts +150 -3
- package/dist/types/content.d.ts.map +1 -1
- package/dist/types/images.d.ts +185 -0
- package/dist/types/images.d.ts.map +1 -0
- package/dist/types/images.js +8 -0
- package/dist/types/index.d.ts +3 -2
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/isg.d.ts +19 -0
- package/dist/types/isg.d.ts.map +1 -1
- package/dist/types/seo.d.ts +9 -0
- package/dist/types/seo.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -2,8 +2,10 @@ import type { PageModel, NavNode } from '../types/index.js';
|
|
|
2
2
|
/**
|
|
3
3
|
* Builds a hierarchical navigation structure from pages.
|
|
4
4
|
* Groups pages by directory structure and sorts them appropriately.
|
|
5
|
+
* Generated pages are left out unless their template sets `nav: true`, and so are the
|
|
6
|
+
* later pages of paginated listings.
|
|
5
7
|
*
|
|
6
|
-
* @param
|
|
8
|
+
* @param allPages - Array of page models to build navigation from
|
|
7
9
|
* @returns Array of top-level navigation nodes
|
|
8
10
|
*
|
|
9
11
|
* @example
|
|
@@ -17,5 +19,5 @@ import type { PageModel, NavNode } from '../types/index.js';
|
|
|
17
19
|
* // Results in hierarchical structure with sorted blog posts
|
|
18
20
|
* ```
|
|
19
21
|
*/
|
|
20
|
-
export declare function buildNavigation(
|
|
22
|
+
export declare function buildNavigation(allPages: PageModel[]): NavNode[];
|
|
21
23
|
//# sourceMappingURL=navigation.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"navigation.d.ts","sourceRoot":"","sources":["../../src/core/navigation.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"navigation.d.ts","sourceRoot":"","sources":["../../src/core/navigation.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAe5D;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,SAAS,EAAE,GAAG,OAAO,EAAE,CA2ChE"}
|
package/dist/core/navigation.js
CHANGED
|
@@ -1,9 +1,23 @@
|
|
|
1
1
|
import { basename } from 'node:path';
|
|
2
|
+
import { isVirtualPage } from './utils/index.js';
|
|
3
|
+
/**
|
|
4
|
+
* Whether a page appears in navigation. Pages generated from a `[param].md` template appear
|
|
5
|
+
* only when the template sets `nav: true`; later pages of a paginated listing never do.
|
|
6
|
+
*/
|
|
7
|
+
function isInNavigation(page) {
|
|
8
|
+
if (!isVirtualPage(page)) {
|
|
9
|
+
return true;
|
|
10
|
+
}
|
|
11
|
+
const firstPage = (page.pagination?.pageNumber ?? 1) === 1;
|
|
12
|
+
return page.generated !== undefined && firstPage && page.frontMatter.nav === true;
|
|
13
|
+
}
|
|
2
14
|
/**
|
|
3
15
|
* Builds a hierarchical navigation structure from pages.
|
|
4
16
|
* Groups pages by directory structure and sorts them appropriately.
|
|
17
|
+
* Generated pages are left out unless their template sets `nav: true`, and so are the
|
|
18
|
+
* later pages of paginated listings.
|
|
5
19
|
*
|
|
6
|
-
* @param
|
|
20
|
+
* @param allPages - Array of page models to build navigation from
|
|
7
21
|
* @returns Array of top-level navigation nodes
|
|
8
22
|
*
|
|
9
23
|
* @example
|
|
@@ -17,7 +31,8 @@ import { basename } from 'node:path';
|
|
|
17
31
|
* // Results in hierarchical structure with sorted blog posts
|
|
18
32
|
* ```
|
|
19
33
|
*/
|
|
20
|
-
export function buildNavigation(
|
|
34
|
+
export function buildNavigation(allPages) {
|
|
35
|
+
const pages = allPages.filter(isInNavigation);
|
|
21
36
|
// Group pages by their collection (directory)
|
|
22
37
|
const collections = new Map();
|
|
23
38
|
for (const page of pages) {
|
package/dist/core/templates.d.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { Eta } from 'eta';
|
|
2
2
|
import type { StatiConfig, PageModel, NavNode, TocEntry, Logger } from '../types/index.js';
|
|
3
|
+
import type { PageReads } from './collections.js';
|
|
4
|
+
import type { PageImages } from '../images/runtime.js';
|
|
5
|
+
import type { GeneratedOgImage } from '../types/index.js';
|
|
3
6
|
/**
|
|
4
7
|
* Result of rendering a page template.
|
|
5
8
|
*/
|
|
@@ -8,6 +11,17 @@ export interface RenderResult {
|
|
|
8
11
|
html: string;
|
|
9
12
|
/** Number of templates loaded (layout + partials) */
|
|
10
13
|
templatesLoaded: number;
|
|
14
|
+
/** Open Graph image generated for the page, if any */
|
|
15
|
+
ogImage?: GeneratedOgImage | undefined;
|
|
16
|
+
/** Shared data the render read, which the cache entry records */
|
|
17
|
+
reads: PageReads;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Page-specific state for {@link renderPage}.
|
|
21
|
+
*/
|
|
22
|
+
export interface RenderPageExtras {
|
|
23
|
+
/** Image state of the page; without it `stati.image()` emits a plain `<img>` */
|
|
24
|
+
images?: PageImages | undefined;
|
|
11
25
|
}
|
|
12
26
|
/**
|
|
13
27
|
* Clear the cached template engine. Call this when templates change in dev mode
|
|
@@ -15,5 +29,5 @@ export interface RenderResult {
|
|
|
15
29
|
*/
|
|
16
30
|
export declare function clearTemplateEngineCache(): void;
|
|
17
31
|
export declare function createTemplateEngine(config: StatiConfig): Eta;
|
|
18
|
-
export declare function renderPage(page: PageModel, body: string, config: StatiConfig, eta: Eta, navigation?: NavNode[], allPages?: PageModel[], assets?: import('../types/index.js').StatiAssets, toc?: TocEntry[], logger?: Logger): Promise<RenderResult>;
|
|
32
|
+
export declare function renderPage(page: PageModel, body: string, config: StatiConfig, eta: Eta, navigation?: NavNode[], allPages?: PageModel[], assets?: import('../types/index.js').StatiAssets, toc?: TocEntry[], logger?: Logger, extras?: RenderPageExtras): Promise<RenderResult>;
|
|
19
33
|
//# sourceMappingURL=templates.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"templates.d.ts","sourceRoot":"","sources":["../../src/core/templates.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAG1B,OAAO,KAAK,EACV,WAAW,EACX,SAAS,EACT,OAAO,EAEP,QAAQ,EACR,MAAM,EACP,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"templates.d.ts","sourceRoot":"","sources":["../../src/core/templates.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAG1B,OAAO,KAAK,EACV,WAAW,EACX,SAAS,EACT,OAAO,EAEP,QAAQ,EACR,MAAM,EACP,MAAM,mBAAmB,CAAC;AAuB3B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAGlD,OAAO,KAAK,EAAE,UAAU,EAAqB,MAAM,sBAAsB,CAAC;AAC1E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAE1D;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,gCAAgC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,qDAAqD;IACrD,eAAe,EAAE,MAAM,CAAC;IACxB,sDAAsD;IACtD,OAAO,CAAC,EAAE,gBAAgB,GAAG,SAAS,CAAC;IACvC,iEAAiE;IACjE,KAAK,EAAE,SAAS,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,gFAAgF;IAChF,MAAM,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC;CACjC;AAuHD;;;GAGG;AACH,wBAAgB,wBAAwB,IAAI,IAAI,CAE/C;AAED,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,WAAW,GAAG,GAAG,CA2B7D;AAED,wBAAsB,UAAU,CAC9B,IAAI,EAAE,SAAS,EACf,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,WAAW,EACnB,GAAG,EAAE,GAAG,EACR,UAAU,CAAC,EAAE,OAAO,EAAE,EACtB,QAAQ,CAAC,EAAE,SAAS,EAAE,EACtB,MAAM,CAAC,EAAE,OAAO,mBAAmB,EAAE,WAAW,EAChD,GAAG,CAAC,EAAE,QAAQ,EAAE,EAChB,MAAM,CAAC,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,gBAAgB,GACxB,OAAO,CAAC,YAAY,CAAC,CA8RvB"}
|
package/dist/core/templates.js
CHANGED
|
@@ -3,122 +3,48 @@ import { join, dirname, relative, basename, posix } from 'node:path';
|
|
|
3
3
|
import glob from 'fast-glob';
|
|
4
4
|
import { createFallbackLogger } from './utils/index.js';
|
|
5
5
|
import { TEMPLATE_EXTENSION } from '../constants.js';
|
|
6
|
-
import { getStatiVersion, isCollectionIndexPage, discoverLayout,
|
|
6
|
+
import { getStatiVersion, isCollectionIndexPage, discoverLayout, resolveSrcDir, createTemplateError, createValidatingPartialsProxy, createValidatingContextProxy, propValue, slugify, wrapPartialsAsCallable, createNavigationHelpers, } from './utils/index.js';
|
|
7
|
+
import { getCollections, resolveCollectionPath, createCollectionView, copyPaginationData, copyGeneratedData, } from './collections.js';
|
|
7
8
|
import { isDevelopment, isProduction } from '../env.js';
|
|
8
|
-
import { generateSEO } from '../seo/index.js';
|
|
9
|
+
import { generateSEO, resolveGeneratedImagePlaceholders } from '../seo/index.js';
|
|
9
10
|
/**
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* @param pages - Pages to group
|
|
13
|
-
* @returns Object mapping tag names to arrays of pages
|
|
11
|
+
* `stati.image()` when images are turned off: a plain `<img>`, attributes escaped.
|
|
14
12
|
*/
|
|
15
|
-
function
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
const tags = page.frontMatter.tags;
|
|
19
|
-
if (Array.isArray(tags)) {
|
|
20
|
-
for (const tag of tags) {
|
|
21
|
-
if (typeof tag === 'string') {
|
|
22
|
-
if (!pagesByTag[tag]) {
|
|
23
|
-
pagesByTag[tag] = [];
|
|
24
|
-
}
|
|
25
|
-
pagesByTag[tag].push(page);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
}
|
|
13
|
+
function renderPlainImage(src, options = {}) {
|
|
14
|
+
if (typeof src !== 'string' || !src.trim()) {
|
|
15
|
+
return '';
|
|
29
16
|
}
|
|
30
|
-
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
*/
|
|
38
|
-
function sortPagesByDate(pages) {
|
|
39
|
-
return pages.sort((a, b) => {
|
|
40
|
-
// Sort by publishedAt (newest first)
|
|
41
|
-
if (a.publishedAt && b.publishedAt) {
|
|
42
|
-
return b.publishedAt.getTime() - a.publishedAt.getTime();
|
|
43
|
-
}
|
|
44
|
-
if (a.publishedAt && !b.publishedAt)
|
|
45
|
-
return -1;
|
|
46
|
-
if (!a.publishedAt && b.publishedAt)
|
|
47
|
-
return 1;
|
|
48
|
-
// Fallback to title
|
|
49
|
-
const titleA = a.frontMatter.title || basename(a.url) || 'Untitled';
|
|
50
|
-
const titleB = b.frontMatter.title || basename(b.url) || 'Untitled';
|
|
51
|
-
return titleA.localeCompare(titleB);
|
|
52
|
-
});
|
|
17
|
+
const attributes = [
|
|
18
|
+
`src="${escapeHtml(src)}"`,
|
|
19
|
+
`alt="${escapeHtml(options.alt ?? '')}"`,
|
|
20
|
+
...(options.title ? [`title="${escapeHtml(options.title)}"`] : []),
|
|
21
|
+
...(options.class ? [`class="${escapeHtml(options.class)}"`] : []),
|
|
22
|
+
];
|
|
23
|
+
return `<img ${attributes.join(' ')}>`;
|
|
53
24
|
}
|
|
54
25
|
/**
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
* @param currentPage - The current page being rendered (must be an index page)
|
|
59
|
-
* @param allPages - All pages in the site
|
|
60
|
-
* @returns Collection data for template rendering
|
|
26
|
+
* Wraps the navigation helpers for one render so that reading any of them sets `reads.nav`.
|
|
27
|
+
* Like the collection view, it uses accessors on a plain object, so spreading the template
|
|
28
|
+
* context does not count as a read. The helpers return the shared nodes unchanged.
|
|
61
29
|
*/
|
|
62
|
-
function
|
|
63
|
-
const
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
return page.url.startsWith(pageUrlAsDir);
|
|
79
|
-
}
|
|
80
|
-
});
|
|
81
|
-
// Find direct children (one level down)
|
|
82
|
-
const children = collectionPages.filter((page) => {
|
|
83
|
-
const relativePath = page.url.substring(collectionPath.length);
|
|
84
|
-
const cleanPath = relativePath.startsWith('/') ? relativePath.substring(1) : relativePath;
|
|
85
|
-
return !cleanPath.includes('/'); // No further slashes means direct child
|
|
86
|
-
});
|
|
87
|
-
// Sort pages by date for recent posts
|
|
88
|
-
const recentPages = sortPagesByDate([...collectionPages]);
|
|
89
|
-
// Group by tags
|
|
90
|
-
const pagesByTag = groupPagesByTags(collectionPages);
|
|
91
|
-
return {
|
|
92
|
-
pages: collectionPages,
|
|
93
|
-
children,
|
|
94
|
-
recentPages,
|
|
95
|
-
pagesByTag,
|
|
96
|
-
metadata: {
|
|
97
|
-
totalPages: collectionPages.length,
|
|
98
|
-
hasChildren: children.length > 0,
|
|
99
|
-
collectionPath,
|
|
100
|
-
collectionName,
|
|
101
|
-
},
|
|
102
|
-
};
|
|
103
|
-
}
|
|
104
|
-
/**
|
|
105
|
-
* Builds collection data for a child page (showing parent collection data).
|
|
106
|
-
* Finds the parent collection and returns its data.
|
|
107
|
-
*
|
|
108
|
-
* @param currentPage - The current page being rendered
|
|
109
|
-
* @param allPages - All pages in the site
|
|
110
|
-
* @returns Collection data for the parent collection or undefined
|
|
111
|
-
*/
|
|
112
|
-
function buildParentCollectionData(currentPage, allPages) {
|
|
113
|
-
// Get the parent collection path
|
|
114
|
-
const parentPath = getCollectionPathForPage(currentPage.url);
|
|
115
|
-
// Find the index page for the parent collection
|
|
116
|
-
const parentIndexPage = allPages.find((p) => p.url === parentPath);
|
|
117
|
-
if (parentIndexPage) {
|
|
118
|
-
// Build collection data for the parent
|
|
119
|
-
return buildCollectionData(parentIndexPage, allPages);
|
|
30
|
+
function createNavView(helpers, reads) {
|
|
31
|
+
const view = {};
|
|
32
|
+
for (const [key, initial] of Object.entries(helpers)) {
|
|
33
|
+
let value = initial;
|
|
34
|
+
Object.defineProperty(view, key, {
|
|
35
|
+
enumerable: true,
|
|
36
|
+
configurable: true,
|
|
37
|
+
get() {
|
|
38
|
+
reads.nav = true;
|
|
39
|
+
return value;
|
|
40
|
+
},
|
|
41
|
+
set(next) {
|
|
42
|
+
reads.nav = true;
|
|
43
|
+
value = next;
|
|
44
|
+
},
|
|
45
|
+
});
|
|
120
46
|
}
|
|
121
|
-
return
|
|
47
|
+
return view;
|
|
122
48
|
}
|
|
123
49
|
/**
|
|
124
50
|
* Discovers partials in the hierarchy for a given page path.
|
|
@@ -215,25 +141,34 @@ export function createTemplateEngine(config) {
|
|
|
215
141
|
}
|
|
216
142
|
return eta;
|
|
217
143
|
}
|
|
218
|
-
export async function renderPage(page, body, config, eta, navigation, allPages, assets, toc, logger) {
|
|
144
|
+
export async function renderPage(page, body, config, eta, navigation, allPages, assets, toc, logger, extras) {
|
|
219
145
|
const log = logger || createFallbackLogger();
|
|
146
|
+
const pageImages = extras?.images;
|
|
147
|
+
// The generated Open Graph image is known once the og template has rendered, after the
|
|
148
|
+
// partials. Until then stati.generateSEO() emits placeholders for its tags.
|
|
149
|
+
const ogState = {
|
|
150
|
+
image: undefined,
|
|
151
|
+
pending: pageImages?.wantsOg() ?? false,
|
|
152
|
+
};
|
|
220
153
|
// Discover partials for this page's directory hierarchy
|
|
221
154
|
const srcDir = resolveSrcDir(config);
|
|
222
155
|
const relativePath = relative(srcDir, page.sourcePath);
|
|
223
156
|
const partialPaths = await discoverPartials(relativePath, config);
|
|
224
157
|
// Count templates: partials + layout (if found)
|
|
225
158
|
const partialsCount = Object.keys(partialPaths).length;
|
|
226
|
-
//
|
|
159
|
+
// What this render reads from shared data, so the cache can rebuild the page when it changes
|
|
160
|
+
const reads = { collection: false, nav: false };
|
|
161
|
+
// The page's collection: its own on index pages, the one it belongs to on other pages, or
|
|
162
|
+
// the one its front matter names. Collections are computed once per page list.
|
|
227
163
|
let collectionData;
|
|
228
164
|
const isIndexPage = allPages && isCollectionIndexPage(page, allPages);
|
|
229
165
|
if (allPages) {
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
collectionData = buildParentCollectionData(page, allPages);
|
|
166
|
+
const collectionPath = resolveCollectionPath(page, allPages);
|
|
167
|
+
const data = collectionPath !== undefined
|
|
168
|
+
? getCollections(allPages).byPath.get(collectionPath)
|
|
169
|
+
: undefined;
|
|
170
|
+
if (data) {
|
|
171
|
+
collectionData = createCollectionView(data, reads);
|
|
237
172
|
}
|
|
238
173
|
}
|
|
239
174
|
// Discover the appropriate layout using hierarchical layout.eta convention
|
|
@@ -258,28 +193,52 @@ export async function renderPage(page, body, config, eta, navigation, allPages,
|
|
|
258
193
|
if (conflictingKeys.length > 0) {
|
|
259
194
|
log.warning(`Frontmatter in "${page.sourcePath}" contains reserved keys that will be overwritten: ${conflictingKeys.join(', ')}`);
|
|
260
195
|
}
|
|
196
|
+
// The current page's navigation node counts as a navigation read
|
|
197
|
+
const pageContext = { ...page.frontMatter, ...pageOverrides };
|
|
198
|
+
Object.defineProperty(pageContext, 'navNode', {
|
|
199
|
+
enumerable: true,
|
|
200
|
+
configurable: true,
|
|
201
|
+
get() {
|
|
202
|
+
reads.nav = true;
|
|
203
|
+
return currentNavNode;
|
|
204
|
+
},
|
|
205
|
+
});
|
|
261
206
|
// Create base context for partial rendering
|
|
262
207
|
const baseContext = {
|
|
263
208
|
site: config.site,
|
|
264
|
-
page:
|
|
265
|
-
...page.frontMatter,
|
|
266
|
-
...pageOverrides,
|
|
267
|
-
},
|
|
209
|
+
page: pageContext,
|
|
268
210
|
content: body,
|
|
269
|
-
nav: navHelpers, // Replace navigation with nav helpers
|
|
211
|
+
nav: createNavView(navHelpers, reads), // Replace navigation with nav helpers
|
|
270
212
|
collection: collectionData, // Add collection data
|
|
213
|
+
// Set on paginated listings and on pages generated from [param].md templates. Placed before
|
|
214
|
+
// the filters, like slugify, so that an existing filter with the same name keeps working.
|
|
215
|
+
pagination: page.pagination ? copyPaginationData(page.pagination) : undefined,
|
|
216
|
+
generated: page.generated ? copyGeneratedData(page.generated) : undefined,
|
|
217
|
+
slugify,
|
|
271
218
|
// Add custom filters to context
|
|
272
219
|
...(config.eta?.filters || {}),
|
|
273
220
|
generator: {
|
|
274
221
|
version: getStatiVersion(),
|
|
275
222
|
},
|
|
276
223
|
// Stati utilities object with helper functions
|
|
277
|
-
generateSEO: (tags) => generateSEO({
|
|
224
|
+
generateSEO: (tags) => generateSEO({
|
|
225
|
+
page,
|
|
226
|
+
config,
|
|
227
|
+
site: config.site,
|
|
228
|
+
generatedImage: ogState.image,
|
|
229
|
+
deferGeneratedImage: ogState.pending,
|
|
230
|
+
}, tags),
|
|
278
231
|
propValue,
|
|
232
|
+
// Image with dimensions, lazy loading and, with images.responsive, srcset variants
|
|
233
|
+
image: (src, options) => pageImages ? pageImages.renderHelperImage(src, options) : renderPlainImage(src, options),
|
|
279
234
|
assets, // TypeScript bundle assets (available when typescript.enabled is true)
|
|
280
235
|
// Set by callable partials invoked with props; always present so that
|
|
281
236
|
// stati.props?.x works under the dev-mode context validation
|
|
282
237
|
props: undefined,
|
|
238
|
+
// Set while the Open Graph template renders: { width, height }
|
|
239
|
+
og: undefined,
|
|
240
|
+
// The page's generated Open Graph image, once rendered: { url, path, width, height, alt }
|
|
241
|
+
ogImage: undefined,
|
|
283
242
|
};
|
|
284
243
|
// Render partials and store their content
|
|
285
244
|
// Use multiple passes to allow partials to reference other partials
|
|
@@ -345,6 +304,27 @@ export async function renderPage(page, body, config, eta, navigation, allPages,
|
|
|
345
304
|
break;
|
|
346
305
|
}
|
|
347
306
|
}
|
|
307
|
+
// Render the Open Graph template with the layout's context, minus the page body, so the
|
|
308
|
+
// generated image is known before the layout renders its SEO tags
|
|
309
|
+
if (pageImages && ogState.pending) {
|
|
310
|
+
// Copy the page's property descriptors so that navNode stays a getter: spreading would
|
|
311
|
+
// read it and count every page with a card as reading the navigation
|
|
312
|
+
const ogPage = Object.defineProperties({}, Object.getOwnPropertyDescriptors(baseContext.page));
|
|
313
|
+
ogPage.content = '';
|
|
314
|
+
const ogBaseContext = {
|
|
315
|
+
...baseContext,
|
|
316
|
+
content: '',
|
|
317
|
+
page: ogPage,
|
|
318
|
+
og: pageImages.ogSize(),
|
|
319
|
+
};
|
|
320
|
+
const ogContext = createValidatingContextProxy({
|
|
321
|
+
...ogBaseContext,
|
|
322
|
+
partials: createValidatingPartialsProxy(wrapPartialsAsCallable(eta, renderedPartials, partialPaths, ogBaseContext)),
|
|
323
|
+
});
|
|
324
|
+
ogState.image = (await pageImages.renderOg(ogContext, eta)) ?? undefined;
|
|
325
|
+
ogState.pending = false;
|
|
326
|
+
baseContext.ogImage = ogState.image;
|
|
327
|
+
}
|
|
348
328
|
// Wrap final rendered partials as callable before passing to layout context
|
|
349
329
|
const callablePartials = wrapPartialsAsCallable(eta, renderedPartials, partialPaths, baseContext);
|
|
350
330
|
const context = createValidatingContextProxy({
|
|
@@ -354,10 +334,20 @@ export async function renderPage(page, body, config, eta, navigation, allPages,
|
|
|
354
334
|
try {
|
|
355
335
|
if (!layoutPath) {
|
|
356
336
|
log.warning('No layout template found, using fallback');
|
|
357
|
-
return {
|
|
337
|
+
return {
|
|
338
|
+
html: createFallbackHtml(page, body),
|
|
339
|
+
templatesLoaded,
|
|
340
|
+
ogImage: ogState.image,
|
|
341
|
+
reads,
|
|
342
|
+
};
|
|
358
343
|
}
|
|
359
344
|
const html = await eta.renderAsync(layoutPath, context);
|
|
360
|
-
return {
|
|
345
|
+
return {
|
|
346
|
+
html: resolveGeneratedImagePlaceholders(html, ogState.image),
|
|
347
|
+
templatesLoaded,
|
|
348
|
+
ogImage: ogState.image,
|
|
349
|
+
reads,
|
|
350
|
+
};
|
|
361
351
|
}
|
|
362
352
|
catch (error) {
|
|
363
353
|
log.error(`Error rendering layout ${layoutPath || 'unknown'}: ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -366,7 +356,12 @@ export async function renderPage(page, body, config, eta, navigation, allPages,
|
|
|
366
356
|
const templateError = createTemplateError(error instanceof Error ? error : new Error(String(error)), layoutPath || undefined);
|
|
367
357
|
throw templateError;
|
|
368
358
|
}
|
|
369
|
-
return {
|
|
359
|
+
return {
|
|
360
|
+
html: createFallbackHtml(page, body),
|
|
361
|
+
templatesLoaded,
|
|
362
|
+
ogImage: ogState.image,
|
|
363
|
+
reads,
|
|
364
|
+
};
|
|
370
365
|
}
|
|
371
366
|
}
|
|
372
367
|
function createFallbackHtml(page, body) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import fse from 'fs-extra';
|
|
2
|
-
import type { WriteFileOptions } from 'node:fs';
|
|
2
|
+
import type { WriteFileOptions, Stats } from 'node:fs';
|
|
3
3
|
/**
|
|
4
4
|
* Safely reads a file with consistent error handling.
|
|
5
5
|
*/
|
|
@@ -24,6 +24,14 @@ export declare function remove(path: string): Promise<void>;
|
|
|
24
24
|
* Gets file stats with consistent error handling.
|
|
25
25
|
*/
|
|
26
26
|
export declare function stat(filePath: string): Promise<fse.Stats>;
|
|
27
|
+
/**
|
|
28
|
+
* Gets file stats without following a symbolic link at the path, with consistent error handling.
|
|
29
|
+
*/
|
|
30
|
+
export declare function lstat(filePath: string): Promise<fse.Stats>;
|
|
31
|
+
/**
|
|
32
|
+
* Resolves a path to its real location, following symbolic links, with consistent error handling.
|
|
33
|
+
*/
|
|
34
|
+
export declare function realpath(filePath: string): Promise<string>;
|
|
27
35
|
/**
|
|
28
36
|
* Reads directory contents with consistent error handling.
|
|
29
37
|
*/
|
|
@@ -34,4 +42,24 @@ export declare function readdir<T extends boolean = false>(dirPath: string, opti
|
|
|
34
42
|
* Copies a file with consistent error handling.
|
|
35
43
|
*/
|
|
36
44
|
export declare function copyFile(src: string, dest: string): Promise<void>;
|
|
45
|
+
/**
|
|
46
|
+
* Reads a file as raw bytes. Returns null if the file does not exist.
|
|
47
|
+
*/
|
|
48
|
+
export declare function readFileBuffer(filePath: string): Promise<Buffer | null>;
|
|
49
|
+
/**
|
|
50
|
+
* Reads a file as raw bytes synchronously. Returns null if the file does not exist.
|
|
51
|
+
* For code that must stay synchronous, such as template helpers.
|
|
52
|
+
*/
|
|
53
|
+
export declare function readFileBufferSync(filePath: string): Buffer | null;
|
|
54
|
+
/**
|
|
55
|
+
* Gets file stats synchronously. Returns null if the path does not exist.
|
|
56
|
+
*/
|
|
57
|
+
export declare function statSyncOrNull(filePath: string): Stats | null;
|
|
58
|
+
/**
|
|
59
|
+
* Lists every file under a directory, recursively.
|
|
60
|
+
*
|
|
61
|
+
* @param dirPath - Directory to list
|
|
62
|
+
* @returns Paths relative to `dirPath` with forward slashes; empty if the directory does not exist
|
|
63
|
+
*/
|
|
64
|
+
export declare function listFilesRecursiveSync(dirPath: string): string[];
|
|
37
65
|
//# sourceMappingURL=fs.utils.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fs.utils.d.ts","sourceRoot":"","sources":["../../../src/core/utils/fs.utils.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"fs.utils.d.ts","sourceRoot":"","sources":["../../../src/core/utils/fs.utils.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,UAAU,CAAC;AAE3B,OAAO,KAAK,EAAE,gBAAgB,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAqDvD;;GAEG;AACH,wBAAsB,QAAQ,CAC5B,QAAQ,EAAE,MAAM,EAChB,QAAQ,GAAE,OAAO,GAAG,MAAgB,GACnC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAExB;AAED;;GAEG;AACH,wBAAsB,SAAS,CAC7B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,gBAAgB,GACzB,OAAO,CAAC,IAAI,CAAC,CAEf;AAED;;GAEG;AACH,wBAAsB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAEnE;AAED;;GAEG;AACH,wBAAsB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE9D;AAED;;GAEG;AACH,wBAAsB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAExD;AAED;;GAEG;AACH,wBAAsB,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAE/D;AAED;;GAEG;AACH,wBAAsB,KAAK,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAEhE;AAED;;GAEG;AACH,wBAAsB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAEhE;AAED;;GAEG;AACH,wBAAsB,OAAO,CAAC,CAAC,SAAS,OAAO,GAAG,KAAK,EACrD,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE;IAAE,aAAa,CAAC,EAAE,CAAC,CAAA;CAAE,GAC9B,OAAO,CAAC,CAAC,SAAS,IAAI,GAAG,GAAG,CAAC,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC,CAcnD;AAED;;GAEG;AACH,wBAAsB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAEvE;AAED;;GAEG;AACH,wBAAsB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAE7E;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAUlE;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,KAAK,GAAG,IAAI,CAU7D;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAchE"}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import fse from 'fs-extra';
|
|
2
|
-
|
|
2
|
+
import { readFileSync, statSync, readdirSync } from 'node:fs';
|
|
3
|
+
import { join, relative } from 'node:path';
|
|
4
|
+
const { readFile: fseReadFile, writeFile: fseWriteFile, pathExists: fsePathExists, ensureDir: fseEnsureDir, remove: fseRemove, stat: fseStat, lstat: fseLstat, realpath: fseRealpath, readdir: fseReaddir, copyFile: fseCopyFile, } = fse;
|
|
3
5
|
/**
|
|
4
6
|
* Wraps fs-extra operations with consistent error handling.
|
|
5
7
|
*/
|
|
@@ -63,6 +65,18 @@ export async function remove(path) {
|
|
|
63
65
|
export async function stat(filePath) {
|
|
64
66
|
return wrapFsOperation('get stats for', fseStat(filePath), filePath);
|
|
65
67
|
}
|
|
68
|
+
/**
|
|
69
|
+
* Gets file stats without following a symbolic link at the path, with consistent error handling.
|
|
70
|
+
*/
|
|
71
|
+
export async function lstat(filePath) {
|
|
72
|
+
return wrapFsOperation('get stats for', fseLstat(filePath), filePath);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Resolves a path to its real location, following symbolic links, with consistent error handling.
|
|
76
|
+
*/
|
|
77
|
+
export async function realpath(filePath) {
|
|
78
|
+
return wrapFsOperation('resolve', fseRealpath(filePath), filePath);
|
|
79
|
+
}
|
|
66
80
|
/**
|
|
67
81
|
* Reads directory contents with consistent error handling.
|
|
68
82
|
*/
|
|
@@ -86,3 +100,62 @@ export async function readdir(dirPath, options) {
|
|
|
86
100
|
export async function copyFile(src, dest) {
|
|
87
101
|
return wrapFsOperation('copy', fseCopyFile(src, dest), `${src} to ${dest}`);
|
|
88
102
|
}
|
|
103
|
+
/**
|
|
104
|
+
* Reads a file as raw bytes. Returns null if the file does not exist.
|
|
105
|
+
*/
|
|
106
|
+
export async function readFileBuffer(filePath) {
|
|
107
|
+
return wrapFsOperationNullable('read file', fseReadFile(filePath), filePath);
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Reads a file as raw bytes synchronously. Returns null if the file does not exist.
|
|
111
|
+
* For code that must stay synchronous, such as template helpers.
|
|
112
|
+
*/
|
|
113
|
+
export function readFileBufferSync(filePath) {
|
|
114
|
+
try {
|
|
115
|
+
return readFileSync(filePath);
|
|
116
|
+
}
|
|
117
|
+
catch (error) {
|
|
118
|
+
const nodeError = error;
|
|
119
|
+
if (nodeError.code === 'ENOENT' || nodeError.code === 'ENOTDIR') {
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
throw new Error(`Failed to read file ${filePath}: ${nodeError.message}`, { cause: error });
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Gets file stats synchronously. Returns null if the path does not exist.
|
|
127
|
+
*/
|
|
128
|
+
export function statSyncOrNull(filePath) {
|
|
129
|
+
try {
|
|
130
|
+
return statSync(filePath);
|
|
131
|
+
}
|
|
132
|
+
catch (error) {
|
|
133
|
+
const nodeError = error;
|
|
134
|
+
if (nodeError.code === 'ENOENT' || nodeError.code === 'ENOTDIR') {
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
throw new Error(`Failed to get stats for ${filePath}: ${nodeError.message}`, { cause: error });
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Lists every file under a directory, recursively.
|
|
142
|
+
*
|
|
143
|
+
* @param dirPath - Directory to list
|
|
144
|
+
* @returns Paths relative to `dirPath` with forward slashes; empty if the directory does not exist
|
|
145
|
+
*/
|
|
146
|
+
export function listFilesRecursiveSync(dirPath) {
|
|
147
|
+
let entries;
|
|
148
|
+
try {
|
|
149
|
+
entries = readdirSync(dirPath, { withFileTypes: true, recursive: true });
|
|
150
|
+
}
|
|
151
|
+
catch (error) {
|
|
152
|
+
const nodeError = error;
|
|
153
|
+
if (nodeError.code === 'ENOENT' || nodeError.code === 'ENOTDIR') {
|
|
154
|
+
return [];
|
|
155
|
+
}
|
|
156
|
+
throw new Error(`Failed to read directory ${dirPath}: ${nodeError.message}`, { cause: error });
|
|
157
|
+
}
|
|
158
|
+
return entries
|
|
159
|
+
.filter((entry) => entry.isFile())
|
|
160
|
+
.map((entry) => relative(dirPath, join(entry.parentPath, entry.name)).replace(/\\/g, '/'));
|
|
161
|
+
}
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
* Core utilities index
|
|
3
3
|
* @module core/utils
|
|
4
4
|
*/
|
|
5
|
-
export { readFile, writeFile, pathExists, ensureDir, remove, copyFile, readdir, stat, } from './fs.utils.js';
|
|
6
|
-
export { resolveSrcDir, resolveOutDir, resolveStaticDir, resolveCacheDir, resolveDevPaths, normalizeTemplatePath, resolveSrcPath, resolveOutPath, resolveStaticPath, normalizePathForComparison, isPathWithinDirectory, } from './paths.utils.js';
|
|
7
|
-
export { discoverLayout, isCollectionIndexPage, getCollectionPathForPage, } from './template-discovery.utils.js';
|
|
5
|
+
export { readFile, writeFile, pathExists, ensureDir, remove, copyFile, readdir, stat, lstat, realpath, readFileBuffer, readFileBufferSync, statSyncOrNull, listFilesRecursiveSync, } from './fs.utils.js';
|
|
6
|
+
export { resolveSrcDir, resolveOutDir, resolveStaticDir, resolveCacheDir, resolveDevPaths, normalizeTemplatePath, resolveSrcPath, resolveOutPath, resolveStaticPath, normalizePathForComparison, isPathWithinDirectory, getPageOutputFile, } from './paths.utils.js';
|
|
7
|
+
export { discoverLayout, isCollectionIndexPage, isVirtualPage, getFirstPaginationPage, getCollectionPathForPage, } from './template-discovery.utils.js';
|
|
8
8
|
export { propValue } from './template.utils.js';
|
|
9
9
|
export { slugify } from './slugify.utils.js';
|
|
10
10
|
export { trackTailwindClass, enableInventoryTracking, disableInventoryTracking, clearInventory, getInventory, getInventorySize, isTrackingEnabled, writeTailwindClassInventory, isTailwindUsed, resetTailwindDetection, loadPreviousInventory, } from './tailwind-inventory.utils.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/utils/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EACL,QAAQ,EACR,SAAS,EACT,UAAU,EACV,SAAS,EACT,MAAM,EACN,QAAQ,EACR,OAAO,EACP,IAAI,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/utils/index.ts"],"names":[],"mappings":"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"}
|
package/dist/core/utils/index.js
CHANGED
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
* @module core/utils
|
|
4
4
|
*/
|
|
5
5
|
// File system utilities
|
|
6
|
-
export { readFile, writeFile, pathExists, ensureDir, remove, copyFile, readdir, stat, } from './fs.utils.js';
|
|
6
|
+
export { readFile, writeFile, pathExists, ensureDir, remove, copyFile, readdir, stat, lstat, realpath, readFileBuffer, readFileBufferSync, statSyncOrNull, listFilesRecursiveSync, } from './fs.utils.js';
|
|
7
7
|
// Path resolution utilities
|
|
8
|
-
export { resolveSrcDir, resolveOutDir, resolveStaticDir, resolveCacheDir, resolveDevPaths, normalizeTemplatePath, resolveSrcPath, resolveOutPath, resolveStaticPath, normalizePathForComparison, isPathWithinDirectory, } from './paths.utils.js';
|
|
8
|
+
export { resolveSrcDir, resolveOutDir, resolveStaticDir, resolveCacheDir, resolveDevPaths, normalizeTemplatePath, resolveSrcPath, resolveOutPath, resolveStaticPath, normalizePathForComparison, isPathWithinDirectory, getPageOutputFile, } from './paths.utils.js';
|
|
9
9
|
// Template discovery utilities
|
|
10
|
-
export { discoverLayout, isCollectionIndexPage, getCollectionPathForPage, } from './template-discovery.utils.js';
|
|
10
|
+
export { discoverLayout, isCollectionIndexPage, isVirtualPage, getFirstPaginationPage, getCollectionPathForPage, } from './template-discovery.utils.js';
|
|
11
11
|
// Template utilities
|
|
12
12
|
export { propValue } from './template.utils.js';
|
|
13
13
|
// Slugify utilities
|
|
@@ -131,4 +131,19 @@ export declare function normalizePathForComparison(filePath: string, basePath?:
|
|
|
131
131
|
* ```
|
|
132
132
|
*/
|
|
133
133
|
export declare function isPathWithinDirectory(baseDir: string, targetPath: string): boolean;
|
|
134
|
+
/**
|
|
135
|
+
* The file a page URL is written to, relative to the output directory. The build joins it to
|
|
136
|
+
* the output directory, which also normalizes separators and `.` segments.
|
|
137
|
+
*
|
|
138
|
+
* @param url - The page URL
|
|
139
|
+
* @returns The output file
|
|
140
|
+
*
|
|
141
|
+
* @example
|
|
142
|
+
* ```typescript
|
|
143
|
+
* getPageOutputFile('/'); // 'index.html'
|
|
144
|
+
* getPageOutputFile('/blog/'); // '/blog/index.html'
|
|
145
|
+
* getPageOutputFile('/blog/post'); // '/blog/post.html'
|
|
146
|
+
* ```
|
|
147
|
+
*/
|
|
148
|
+
export declare function getPageOutputFile(url: string): string;
|
|
134
149
|
//# sourceMappingURL=paths.utils.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"paths.utils.d.ts","sourceRoot":"","sources":["../../../src/core/utils/paths.utils.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAQxD;;;GAGG;AAEH;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAEzD;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAEzD;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAE5D;AAED;;;GAGG;AACH,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,WAAW;;;;EAMlD;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAElE;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAEhF;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAEhF;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAEnF;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AACH,wBAAgB,0BAA0B,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CA6BtF;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAYlF"}
|
|
1
|
+
{"version":3,"file":"paths.utils.d.ts","sourceRoot":"","sources":["../../../src/core/utils/paths.utils.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAQxD;;;GAGG;AAEH;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAEzD;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAEzD;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAE5D;AAED;;;GAGG;AACH,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,WAAW;;;;EAMlD;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAElE;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAEhF;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAEhF;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAEnF;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AACH,wBAAgB,0BAA0B,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CA6BtF;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAYlF;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAKrD"}
|