@stati/core 1.29.2 → 2.0.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 +10 -13
- package/dist/config/loader.d.ts +9 -0
- package/dist/config/loader.d.ts.map +1 -1
- package/dist/config/loader.js +77 -1
- package/dist/core/build.d.ts.map +1 -1
- package/dist/core/build.js +39 -29
- package/dist/core/content.d.ts.map +1 -1
- package/dist/core/content.js +9 -7
- package/dist/core/dev.d.ts.map +1 -1
- package/dist/core/dev.js +156 -197
- package/dist/core/eta-plugin.d.ts +60 -0
- package/dist/core/eta-plugin.d.ts.map +1 -0
- package/dist/core/eta-plugin.js +143 -0
- package/dist/core/isg/builder.d.ts +37 -19
- package/dist/core/isg/builder.d.ts.map +1 -1
- package/dist/core/isg/builder.js +70 -153
- package/dist/core/isg/deps.d.ts +8 -70
- package/dist/core/isg/deps.d.ts.map +1 -1
- package/dist/core/isg/deps.js +10 -401
- package/dist/core/isg/hash.d.ts.map +1 -1
- package/dist/core/isg/hash.js +2 -1
- package/dist/core/isg/index.d.ts +2 -2
- package/dist/core/isg/index.d.ts.map +1 -1
- package/dist/core/isg/index.js +3 -3
- package/dist/core/isg/manifest.d.ts.map +1 -1
- package/dist/core/isg/manifest.js +6 -1
- package/dist/core/markdown.d.ts +1 -1
- package/dist/core/markdown.d.ts.map +1 -1
- package/dist/core/markdown.js +3 -2
- package/dist/core/template-index.d.ts +209 -0
- package/dist/core/template-index.d.ts.map +1 -0
- package/dist/core/template-index.js +484 -0
- package/dist/core/template-render.d.ts +137 -0
- package/dist/core/template-render.d.ts.map +1 -0
- package/dist/core/template-render.js +444 -0
- package/dist/core/templates.d.ts +29 -11
- package/dist/core/templates.d.ts.map +1 -1
- package/dist/core/templates.js +115 -196
- package/dist/core/utils/context-validation.utils.d.ts +10 -6
- package/dist/core/utils/context-validation.utils.d.ts.map +1 -1
- package/dist/core/utils/context-validation.utils.js +39 -16
- package/dist/core/utils/date.utils.d.ts +1 -1
- package/dist/core/utils/date.utils.js +1 -1
- package/dist/core/utils/dev-css-watcher.utils.d.ts.map +1 -1
- package/dist/core/utils/dev-css-watcher.utils.js +3 -2
- package/dist/core/utils/error-overlay.utils.d.ts.map +1 -1
- package/dist/core/utils/error-overlay.utils.js +7 -45
- package/dist/core/utils/front-matter.utils.d.ts +50 -0
- package/dist/core/utils/front-matter.utils.d.ts.map +1 -0
- package/dist/core/utils/front-matter.utils.js +157 -0
- package/dist/core/utils/index.d.ts +4 -5
- package/dist/core/utils/index.d.ts.map +1 -1
- package/dist/core/utils/index.js +5 -7
- package/dist/core/utils/paths.utils.d.ts +3 -3
- package/dist/core/utils/paths.utils.js +6 -6
- package/dist/core/utils/tailwind-inventory.utils.d.ts +2 -2
- package/dist/core/utils/tailwind-inventory.utils.d.ts.map +1 -1
- package/dist/core/utils/tailwind-inventory.utils.js +15 -6
- package/dist/core/utils/template-discovery.utils.d.ts +3 -14
- package/dist/core/utils/template-discovery.utils.d.ts.map +1 -1
- package/dist/core/utils/template-discovery.utils.js +2 -62
- package/dist/core/utils/template-errors.utils.d.ts +14 -1
- package/dist/core/utils/template-errors.utils.d.ts.map +1 -1
- package/dist/core/utils/template-errors.utils.js +45 -4
- package/dist/core/utils/theme.utils.d.ts +17 -0
- package/dist/core/utils/theme.utils.d.ts.map +1 -0
- package/dist/core/utils/theme.utils.js +59 -0
- package/dist/images/index.d.ts +1 -2
- package/dist/images/index.d.ts.map +1 -1
- package/dist/images/index.js +0 -1
- package/dist/images/markdown-rule.d.ts +1 -2
- package/dist/images/markdown-rule.d.ts.map +1 -1
- package/dist/images/og.d.ts +2 -15
- package/dist/images/og.d.ts.map +1 -1
- package/dist/images/og.js +4 -47
- package/dist/images/runtime.d.ts +24 -5
- package/dist/images/runtime.d.ts.map +1 -1
- package/dist/images/runtime.js +14 -12
- 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 +4 -1
- package/dist/metrics/recorder.d.ts.map +1 -1
- package/dist/metrics/recorder.js +11 -8
- package/dist/metrics/types.d.ts +31 -5
- package/dist/metrics/types.d.ts.map +1 -1
- package/dist/metrics/utils/html-report.utils.d.ts +2 -1
- package/dist/metrics/utils/html-report.utils.d.ts.map +1 -1
- package/dist/metrics/utils/html-report.utils.js +1115 -1136
- package/dist/types/config.d.ts +18 -6
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/content.d.ts +83 -16
- package/dist/types/content.d.ts.map +1 -1
- package/dist/types/index.d.ts +4 -3
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/isg.d.ts +48 -2
- package/dist/types/isg.d.ts.map +1 -1
- package/package.json +6 -6
- package/dist/core/utils/callable-partials.utils.d.ts +0 -60
- package/dist/core/utils/callable-partials.utils.d.ts.map +0 -1
- package/dist/core/utils/callable-partials.utils.js +0 -127
- package/dist/core/utils/partial-validation.utils.d.ts +0 -9
- package/dist/core/utils/partial-validation.utils.d.ts.map +0 -1
- package/dist/core/utils/partial-validation.utils.js +0 -107
|
@@ -2,54 +2,14 @@
|
|
|
2
2
|
* Error overlay utility for displaying pretty errors in development mode.
|
|
3
3
|
* Provides a user-friendly interface for template rendering and build errors.
|
|
4
4
|
*/
|
|
5
|
+
import { STATI_FAVICON_HREF, STATI_MARK_PATH, STATI_THEME_STYLES } from './theme.utils.js';
|
|
5
6
|
const ERROR_HEADLINES = {
|
|
6
7
|
template: 'Template rendering failed',
|
|
7
8
|
build: 'Build process failed',
|
|
8
9
|
markdown: 'Markdown processing failed',
|
|
9
10
|
config: 'Configuration error',
|
|
10
11
|
};
|
|
11
|
-
const
|
|
12
|
-
/** Inline favicon, so the overlay never requests the site's own favicon. */
|
|
13
|
-
const FAVICON_HREF = `data:image/svg+xml,${encodeURIComponent(`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="#2563eb" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="${BOLT_PATH}"/></svg>`)}`;
|
|
14
|
-
const OVERLAY_STYLES = `
|
|
15
|
-
:root {
|
|
16
|
-
--canvas: 255 255 255;
|
|
17
|
-
--raised: 248 250 252;
|
|
18
|
-
--sunken: 246 248 250;
|
|
19
|
-
--ink: 11 13 18;
|
|
20
|
-
--muted: 71 85 105;
|
|
21
|
-
--faint: 91 101 119;
|
|
22
|
-
--line: 226 232 240;
|
|
23
|
-
--line-strong: 203 213 225;
|
|
24
|
-
--accent: 37 99 235;
|
|
25
|
-
--accent-ink: 29 78 216;
|
|
26
|
-
--on-accent: 255 255 255;
|
|
27
|
-
--danger: 185 28 28;
|
|
28
|
-
--danger-wash: 254 242 242;
|
|
29
|
-
--font-display: 'Archivo', 'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
|
|
30
|
-
--font-sans: 'Inter', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
31
|
-
--font-mono: 'Fira Code', ui-monospace, 'Cascadia Code', Menlo, Monaco, Consolas, 'Liberation Mono', monospace;
|
|
32
|
-
color-scheme: light;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
@media (prefers-color-scheme: dark) {
|
|
36
|
-
:root {
|
|
37
|
-
--canvas: 2 6 23;
|
|
38
|
-
--raised: 15 23 42;
|
|
39
|
-
--sunken: 11 18 32;
|
|
40
|
-
--ink: 241 245 249;
|
|
41
|
-
--muted: 148 163 184;
|
|
42
|
-
--faint: 131 145 167;
|
|
43
|
-
--line: 30 41 59;
|
|
44
|
-
--line-strong: 51 65 85;
|
|
45
|
-
--accent: 96 165 250;
|
|
46
|
-
--accent-ink: 147 197 253;
|
|
47
|
-
--on-accent: 2 6 23;
|
|
48
|
-
--danger: 248 113 113;
|
|
49
|
-
--danger-wash: 38 12 20;
|
|
50
|
-
color-scheme: dark;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
12
|
+
const OVERLAY_STYLES = `${STATI_THEME_STYLES}
|
|
53
13
|
|
|
54
14
|
*,
|
|
55
15
|
*::before,
|
|
@@ -723,7 +683,7 @@ export function createErrorOverlay(error, requestPath) {
|
|
|
723
683
|
<meta charset="UTF-8">
|
|
724
684
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
725
685
|
<meta name="color-scheme" content="light dark">
|
|
726
|
-
<link rel="icon" href="${
|
|
686
|
+
<link rel="icon" href="${STATI_FAVICON_HREF}">
|
|
727
687
|
<title>Stati Development Error</title>
|
|
728
688
|
<style>${OVERLAY_STYLES}
|
|
729
689
|
</style>
|
|
@@ -732,7 +692,7 @@ export function createErrorOverlay(error, requestPath) {
|
|
|
732
692
|
<header class="bar">
|
|
733
693
|
<div class="shell">
|
|
734
694
|
<div class="brand">
|
|
735
|
-
<svg class="brand-mark" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="${
|
|
695
|
+
<svg class="brand-mark" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="${STATI_MARK_PATH}"/></svg>
|
|
736
696
|
<span class="brand-name">Stati</span>
|
|
737
697
|
<span class="brand-rule" aria-hidden="true"></span>
|
|
738
698
|
<span class="brand-context">Development error</span>
|
|
@@ -984,7 +944,9 @@ function getErrorSuggestions(error, type) {
|
|
|
984
944
|
}
|
|
985
945
|
}
|
|
986
946
|
else if (type === 'markdown') {
|
|
987
|
-
if (message.includes('front
|
|
947
|
+
if (message.includes('front matter') ||
|
|
948
|
+
message.includes('front-matter') ||
|
|
949
|
+
message.includes('yaml')) {
|
|
988
950
|
suggestions.push('Check the YAML front-matter syntax for errors');
|
|
989
951
|
suggestions.push('Ensure front-matter is properly enclosed in --- markers');
|
|
990
952
|
suggestions.push('Verify that all YAML values are properly quoted if they contain special characters');
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Front matter: the block between `---` lines at the start of a Markdown file, in YAML.
|
|
3
|
+
* @module core/utils/front-matter
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* A Markdown file split into its front matter and its body.
|
|
7
|
+
*/
|
|
8
|
+
export interface ParsedFrontMatter {
|
|
9
|
+
/** The front matter's keys and values; empty when the file has none */
|
|
10
|
+
data: Record<string, unknown>;
|
|
11
|
+
/** The Markdown after the front matter */
|
|
12
|
+
content: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Thrown for front matter that cannot be read: invalid YAML, YAML that is not a set of
|
|
16
|
+
* `key: value` lines, or a language other than YAML after the opening `---`.
|
|
17
|
+
*/
|
|
18
|
+
export declare class FrontMatterError extends Error {
|
|
19
|
+
readonly filePath: string;
|
|
20
|
+
readonly line?: number | undefined;
|
|
21
|
+
readonly column?: number | undefined;
|
|
22
|
+
/**
|
|
23
|
+
* @param message - What is wrong, with the file and the line
|
|
24
|
+
* @param filePath - The Markdown file
|
|
25
|
+
* @param line - The line of the problem in the file, 1-based
|
|
26
|
+
* @param column - The column of the problem, 1-based
|
|
27
|
+
*/
|
|
28
|
+
constructor(message: string, filePath: string, line?: number | undefined, column?: number | undefined);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Splits a Markdown file into its front matter and its body.
|
|
32
|
+
*
|
|
33
|
+
* Front matter starts with `---` as the file's first line, `---yaml` included, and ends at the
|
|
34
|
+
* next line that starts with `---`; without one, the whole file is front matter. A file that
|
|
35
|
+
* starts with `----` or any other text has none. A byte order mark is dropped.
|
|
36
|
+
*
|
|
37
|
+
* @param source - The file's text
|
|
38
|
+
* @param filePath - The file, for error messages
|
|
39
|
+
* @returns The front matter as an object, and the Markdown after it
|
|
40
|
+
* @throws {FrontMatterError} When the front matter is not valid YAML, is YAML of another shape
|
|
41
|
+
* than `key: value` lines, or names another language after `---`
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```typescript
|
|
45
|
+
* parseFrontMatter('---\ntitle: Home\n---\n# Welcome', 'site/index.md');
|
|
46
|
+
* // { data: { title: 'Home' }, content: '# Welcome' }
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
export declare function parseFrontMatter(source: string, filePath: string): ParsedFrontMatter;
|
|
50
|
+
//# sourceMappingURL=front-matter.utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"front-matter.utils.d.ts","sourceRoot":"","sources":["../../../src/core/utils/front-matter.utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,uEAAuE;IACvE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,0CAA0C;IAC1C,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;GAGG;AACH,qBAAa,gBAAiB,SAAQ,KAAK;aASvB,QAAQ,EAAE,MAAM;aAChB,IAAI,CAAC,EAAE,MAAM;aACb,MAAM,CAAC,EAAE,MAAM;IAVjC;;;;;OAKG;gBAED,OAAO,EAAE,MAAM,EACC,QAAQ,EAAE,MAAM,EAChB,IAAI,CAAC,EAAE,MAAM,YAAA,EACb,MAAM,CAAC,EAAE,MAAM,YAAA;CAKlC;AAUD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,iBAAiB,CAwCpF"}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Front matter: the block between `---` lines at the start of a Markdown file, in YAML.
|
|
3
|
+
* @module core/utils/front-matter
|
|
4
|
+
*/
|
|
5
|
+
import { relative } from 'node:path';
|
|
6
|
+
import { load, YAMLException } from 'js-yaml';
|
|
7
|
+
/**
|
|
8
|
+
* Thrown for front matter that cannot be read: invalid YAML, YAML that is not a set of
|
|
9
|
+
* `key: value` lines, or a language other than YAML after the opening `---`.
|
|
10
|
+
*/
|
|
11
|
+
export class FrontMatterError extends Error {
|
|
12
|
+
filePath;
|
|
13
|
+
line;
|
|
14
|
+
column;
|
|
15
|
+
/**
|
|
16
|
+
* @param message - What is wrong, with the file and the line
|
|
17
|
+
* @param filePath - The Markdown file
|
|
18
|
+
* @param line - The line of the problem in the file, 1-based
|
|
19
|
+
* @param column - The column of the problem, 1-based
|
|
20
|
+
*/
|
|
21
|
+
constructor(message, filePath, line, column) {
|
|
22
|
+
super(message);
|
|
23
|
+
this.filePath = filePath;
|
|
24
|
+
this.line = line;
|
|
25
|
+
this.column = column;
|
|
26
|
+
this.name = 'FrontMatterError';
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
const DELIMITER = '---';
|
|
30
|
+
/** The closing delimiter: the first line that starts with `---` */
|
|
31
|
+
const CLOSING_DELIMITER = `\n${DELIMITER}`;
|
|
32
|
+
/** Comment lines, which alone leave the front matter empty */
|
|
33
|
+
const COMMENT_LINES = /^\s*#[^\n]+/gm;
|
|
34
|
+
/** A `key: value` line whose unquoted value contains `: `, which YAML reads as a nested key */
|
|
35
|
+
const UNQUOTED_COLON_VALUE = /^\s*([^\s:#'"][^:]*):\s+([^\s'"[{|>&*!#].*?:(?:\s.*)?)$/;
|
|
36
|
+
/**
|
|
37
|
+
* Splits a Markdown file into its front matter and its body.
|
|
38
|
+
*
|
|
39
|
+
* Front matter starts with `---` as the file's first line, `---yaml` included, and ends at the
|
|
40
|
+
* next line that starts with `---`; without one, the whole file is front matter. A file that
|
|
41
|
+
* starts with `----` or any other text has none. A byte order mark is dropped.
|
|
42
|
+
*
|
|
43
|
+
* @param source - The file's text
|
|
44
|
+
* @param filePath - The file, for error messages
|
|
45
|
+
* @returns The front matter as an object, and the Markdown after it
|
|
46
|
+
* @throws {FrontMatterError} When the front matter is not valid YAML, is YAML of another shape
|
|
47
|
+
* than `key: value` lines, or names another language after `---`
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```typescript
|
|
51
|
+
* parseFrontMatter('---\ntitle: Home\n---\n# Welcome', 'site/index.md');
|
|
52
|
+
* // { data: { title: 'Home' }, content: '# Welcome' }
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
export function parseFrontMatter(source, filePath) {
|
|
56
|
+
const text = source.charCodeAt(0) === 0xfeff ? source.slice(1) : source;
|
|
57
|
+
if (!text.startsWith(DELIMITER) || text.charAt(DELIMITER.length) === '-') {
|
|
58
|
+
return { data: {}, content: text };
|
|
59
|
+
}
|
|
60
|
+
// The rest of the opening line can name the language, as in ---yaml
|
|
61
|
+
let rest = text.slice(DELIMITER.length);
|
|
62
|
+
const openingLineEnd = rest.search(/\r?\n/);
|
|
63
|
+
const language = (openingLineEnd === -1 ? rest : rest.slice(0, openingLineEnd)).trim();
|
|
64
|
+
if (language !== '') {
|
|
65
|
+
rest = rest.slice(openingLineEnd === -1 ? rest.length : openingLineEnd);
|
|
66
|
+
}
|
|
67
|
+
const closeIndex = rest.indexOf(CLOSING_DELIMITER);
|
|
68
|
+
const block = closeIndex === -1 ? rest : rest.slice(0, closeIndex);
|
|
69
|
+
let content = '';
|
|
70
|
+
if (closeIndex !== -1) {
|
|
71
|
+
content = rest.slice(closeIndex + CLOSING_DELIMITER.length);
|
|
72
|
+
if (content.startsWith('\r'))
|
|
73
|
+
content = content.slice(1);
|
|
74
|
+
if (content.startsWith('\n'))
|
|
75
|
+
content = content.slice(1);
|
|
76
|
+
}
|
|
77
|
+
if (block.replace(COMMENT_LINES, '').trim() === '') {
|
|
78
|
+
return { data: {}, content };
|
|
79
|
+
}
|
|
80
|
+
try {
|
|
81
|
+
return { data: parseBlock(block, language.toLowerCase(), filePath), content };
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
// Without a closing line the whole file is front matter: most likely the --- is a
|
|
85
|
+
// horizontal rule, or the closing line is missing
|
|
86
|
+
if (closeIndex === -1 && error instanceof FrontMatterError) {
|
|
87
|
+
throw new FrontMatterError(`Invalid front matter in ${displayPath(filePath)}: the file starts with a --- line, which starts front matter, and no later --- line ends it. Add the closing --- line, or start the file with *** for a horizontal rule.`, filePath, 1);
|
|
88
|
+
}
|
|
89
|
+
throw error;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Parses the text between the delimiters. Its first line is the file's first line.
|
|
94
|
+
*/
|
|
95
|
+
function parseBlock(block, language, filePath) {
|
|
96
|
+
const where = `Invalid front matter in ${displayPath(filePath)}`;
|
|
97
|
+
let data;
|
|
98
|
+
if (language === '' || language === 'yaml' || language === 'yml') {
|
|
99
|
+
try {
|
|
100
|
+
data = load(block);
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
throw describeYamlError(error, block, filePath, where);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
else if (language === 'json') {
|
|
107
|
+
try {
|
|
108
|
+
data = JSON.parse(block);
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
112
|
+
throw new FrontMatterError(`${where}: ${reason}.`, filePath);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
throw new FrontMatterError(`${where} at line 1: Stati reads front matter in YAML, not ${language}. Remove "${language}" after the opening ---.`, filePath, 1);
|
|
117
|
+
}
|
|
118
|
+
if (!isMapping(data)) {
|
|
119
|
+
throw new FrontMatterError(`${where}: front matter must be "key: value" lines, such as "title: My page", not ${describeData(data)}.`, filePath);
|
|
120
|
+
}
|
|
121
|
+
return data;
|
|
122
|
+
}
|
|
123
|
+
function describeYamlError(error, block, filePath, where) {
|
|
124
|
+
if (!(error instanceof YAMLException)) {
|
|
125
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
126
|
+
return new FrontMatterError(`${where}: ${reason}.`, filePath);
|
|
127
|
+
}
|
|
128
|
+
// The block starts on the file's first line, so its line numbers are the file's
|
|
129
|
+
const line = error.mark.line + 1;
|
|
130
|
+
const column = error.mark.column + 1;
|
|
131
|
+
const offending = UNQUOTED_COLON_VALUE.exec(block.split(/\r?\n/)[error.mark.line] ?? '');
|
|
132
|
+
const hint = offending
|
|
133
|
+
? ` Quote a value that contains a colon, such as ${offending[1]}: ${JSON.stringify(offending[2].trim())}.`
|
|
134
|
+
: '';
|
|
135
|
+
return new FrontMatterError(`${where} at line ${line}, column ${column}: ${error.reason}.${hint}`, filePath, line, column);
|
|
136
|
+
}
|
|
137
|
+
/** Whether a parsed value is a YAML mapping, which js-yaml loads as a plain object */
|
|
138
|
+
function isMapping(value) {
|
|
139
|
+
return (typeof value === 'object' && value !== null && Object.getPrototypeOf(value) === Object.prototype);
|
|
140
|
+
}
|
|
141
|
+
function describeData(value) {
|
|
142
|
+
if (value === null || value === undefined)
|
|
143
|
+
return 'null';
|
|
144
|
+
if (Array.isArray(value))
|
|
145
|
+
return 'a list';
|
|
146
|
+
if (value instanceof Date)
|
|
147
|
+
return 'a date';
|
|
148
|
+
if (typeof value === 'string')
|
|
149
|
+
return `the text ${JSON.stringify(value)}`;
|
|
150
|
+
if (typeof value === 'object')
|
|
151
|
+
return 'binary data';
|
|
152
|
+
return `the ${typeof value} ${String(value)}`;
|
|
153
|
+
}
|
|
154
|
+
/** A file for messages: its path from the project directory */
|
|
155
|
+
function displayPath(filePath) {
|
|
156
|
+
return relative(process.cwd(), filePath).replace(/\\/g, '/') || filePath;
|
|
157
|
+
}
|
|
@@ -4,16 +4,15 @@
|
|
|
4
4
|
*/
|
|
5
5
|
export { readFile, writeFile, pathExists, ensureDir, remove, copyFile, readdir, stat, lstat, realpath, readFileBuffer, readFileBufferSync, statSyncOrNull, listFilesRecursiveSync, } from './fs.utils.js';
|
|
6
6
|
export { resolveSrcDir, resolveOutDir, resolveStaticDir, resolveCacheDir, resolveDevPaths, normalizeTemplatePath, resolveSrcPath, resolveOutPath, resolveStaticPath, normalizePathForComparison, isPathWithinDirectory, getPageOutputFile, } from './paths.utils.js';
|
|
7
|
-
export {
|
|
7
|
+
export { 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';
|
|
11
|
-
export {
|
|
11
|
+
export { parseFrontMatter, FrontMatterError } from './front-matter.utils.js';
|
|
12
|
+
export type { ParsedFrontMatter } from './front-matter.utils.js';
|
|
12
13
|
export { createValidatingContextProxy, isPassthroughProperty, parseUnknownPropertyMessage, UnknownTemplatePropertyError, } from './context-validation.utils.js';
|
|
13
14
|
export { editDistance, findSimilarNames } from './similarity.utils.js';
|
|
14
|
-
export {
|
|
15
|
-
export type { CallablePartial } from './callable-partials.utils.js';
|
|
16
|
-
export { TemplateError, parseEtaError, createTemplateError } from './template-errors.utils.js';
|
|
15
|
+
export { TemplateError, TemplateUsageError, parseEtaError, createTemplateError, } from './template-errors.utils.js';
|
|
17
16
|
export { createNavigationHelpers } from './navigation-helpers.utils.js';
|
|
18
17
|
export { getMimeType, parseRequestPath, resolveNotFoundPage, resolveRequestFile, resolvePrettyUrl, mergeServerOptions, assertPortAvailable, toPortUnavailableError, PortUnavailableError, } from './server.utils.js';
|
|
19
18
|
export type { PrettyUrlResult, MergedServerOptions, MergeServerOptionsParams, PortUnavailableCode, } from './server.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,EACJ,KAAK,EACL,QAAQ,EACR,cAAc,EACd,kBAAkB,EAClB,cAAc,EACd,sBAAsB,GACvB,MAAM,eAAe,CAAC;AAGvB,OAAO,EACL,aAAa,EACb,aAAa,EACb,gBAAgB,EAChB,eAAe,EACf,eAAe,EACf,qBAAqB,EACrB,cAAc,EACd,cAAc,EACd,iBAAiB,EACjB,0BAA0B,EAC1B,qBAAqB,EACrB,iBAAiB,GAClB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EACL,
|
|
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,EACJ,KAAK,EACL,QAAQ,EACR,cAAc,EACd,kBAAkB,EAClB,cAAc,EACd,sBAAsB,GACvB,MAAM,eAAe,CAAC;AAGvB,OAAO,EACL,aAAa,EACb,aAAa,EACb,gBAAgB,EAChB,eAAe,EACf,eAAe,EACf,qBAAqB,EACrB,cAAc,EACd,cAAc,EACd,iBAAiB,EACjB,0BAA0B,EAC1B,qBAAqB,EACrB,iBAAiB,GAClB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EACL,qBAAqB,EACrB,aAAa,EACb,sBAAsB,EACtB,wBAAwB,GACzB,MAAM,+BAA+B,CAAC;AAGvC,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAGhD,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAG7C,OAAO,EACL,kBAAkB,EAClB,uBAAuB,EACvB,wBAAwB,EACxB,cAAc,EACd,YAAY,EACZ,gBAAgB,EAChB,iBAAiB,EACjB,2BAA2B,EAC3B,cAAc,EACd,sBAAsB,EACtB,qBAAqB,GACtB,MAAM,+BAA+B,CAAC;AAGvC,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC7E,YAAY,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAGjE,OAAO,EACL,4BAA4B,EAC5B,qBAAqB,EACrB,2BAA2B,EAC3B,4BAA4B,GAC7B,MAAM,+BAA+B,CAAC;AAGvC,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAGvE,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,aAAa,EACb,mBAAmB,GACpB,MAAM,4BAA4B,CAAC;AAGpC,OAAO,EAAE,uBAAuB,EAAE,MAAM,+BAA+B,CAAC;AAGxE,OAAO,EACL,WAAW,EACX,gBAAgB,EAChB,mBAAmB,EACnB,kBAAkB,EAClB,gBAAgB,EAChB,kBAAkB,EAClB,mBAAmB,EACnB,sBAAsB,EACtB,oBAAoB,GACrB,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EACV,eAAe,EACf,mBAAmB,EACnB,wBAAwB,EACxB,mBAAmB,GACpB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AACjF,YAAY,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAG7D,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAGrD,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAGpE,OAAO,EACL,mBAAmB,EACnB,qBAAqB,EACrB,yBAAyB,EACzB,wBAAwB,GACzB,MAAM,4BAA4B,CAAC;AACpC,YAAY,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAGrE,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAGzD,OAAO,EACL,iBAAiB,EACjB,uBAAuB,EACvB,kBAAkB,EAClB,qBAAqB,EACrB,iBAAiB,EACjB,WAAW,EACX,qBAAqB,EACrB,sBAAsB,GACvB,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EACV,cAAc,EACd,YAAY,EACZ,yBAAyB,GAC1B,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAG/E,OAAO,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAG5E,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAGlD,OAAO,EAAE,sBAAsB,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAC;AAC7F,YAAY,EAAE,6BAA6B,EAAE,MAAM,4BAA4B,CAAC"}
|
package/dist/core/utils/index.js
CHANGED
|
@@ -6,24 +6,22 @@
|
|
|
6
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
8
|
export { resolveSrcDir, resolveOutDir, resolveStaticDir, resolveCacheDir, resolveDevPaths, normalizeTemplatePath, resolveSrcPath, resolveOutPath, resolveStaticPath, normalizePathForComparison, isPathWithinDirectory, getPageOutputFile, } from './paths.utils.js';
|
|
9
|
-
//
|
|
10
|
-
export {
|
|
9
|
+
// Page list utilities (collection index pages, virtual pages)
|
|
10
|
+
export { 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
|
|
14
14
|
export { slugify } from './slugify.utils.js';
|
|
15
15
|
// Tailwind inventory utilities
|
|
16
16
|
export { trackTailwindClass, enableInventoryTracking, disableInventoryTracking, clearInventory, getInventory, getInventorySize, isTrackingEnabled, writeTailwindClassInventory, isTailwindUsed, resetTailwindDetection, loadPreviousInventory, } from './tailwind-inventory.utils.js';
|
|
17
|
-
//
|
|
18
|
-
export {
|
|
17
|
+
// Front matter parsing
|
|
18
|
+
export { parseFrontMatter, FrontMatterError } from './front-matter.utils.js';
|
|
19
19
|
// Template context validation utilities
|
|
20
20
|
export { createValidatingContextProxy, isPassthroughProperty, parseUnknownPropertyMessage, UnknownTemplatePropertyError, } from './context-validation.utils.js';
|
|
21
21
|
// String similarity utilities
|
|
22
22
|
export { editDistance, findSimilarNames } from './similarity.utils.js';
|
|
23
|
-
// Callable partial utilities
|
|
24
|
-
export { makeCallablePartial, wrapPartialsAsCallable } from './callable-partials.utils.js';
|
|
25
23
|
// Template error utilities
|
|
26
|
-
export { TemplateError, parseEtaError, createTemplateError } from './template-errors.utils.js';
|
|
24
|
+
export { TemplateError, TemplateUsageError, parseEtaError, createTemplateError, } from './template-errors.utils.js';
|
|
27
25
|
// Navigation helper utilities
|
|
28
26
|
export { createNavigationHelpers } from './navigation-helpers.utils.js';
|
|
29
27
|
// Server utilities
|
|
@@ -5,19 +5,19 @@ import type { StatiConfig } from '../../types/index.js';
|
|
|
5
5
|
*/
|
|
6
6
|
/**
|
|
7
7
|
* Resolves the absolute source directory path from configuration.
|
|
8
|
-
* @param config - Stati configuration
|
|
8
|
+
* @param config - Stati configuration; `srcDir` defaults to `site`, as `loadConfig()` sets it
|
|
9
9
|
* @returns Absolute path to the source directory
|
|
10
10
|
*/
|
|
11
11
|
export declare function resolveSrcDir(config: StatiConfig): string;
|
|
12
12
|
/**
|
|
13
13
|
* Resolves the absolute output directory path from configuration.
|
|
14
|
-
* @param config - Stati configuration
|
|
14
|
+
* @param config - Stati configuration; `outDir` defaults to `dist`
|
|
15
15
|
* @returns Absolute path to the output directory
|
|
16
16
|
*/
|
|
17
17
|
export declare function resolveOutDir(config: StatiConfig): string;
|
|
18
18
|
/**
|
|
19
19
|
* Resolves the absolute static directory path from configuration.
|
|
20
|
-
* @param config - Stati configuration
|
|
20
|
+
* @param config - Stati configuration; `staticDir` defaults to `public`
|
|
21
21
|
* @returns Absolute path to the static directory
|
|
22
22
|
*/
|
|
23
23
|
export declare function resolveStaticDir(config: StatiConfig): string;
|
|
@@ -6,27 +6,27 @@ import { DEFAULT_SRC_DIR, DEFAULT_OUT_DIR, DEFAULT_STATIC_DIR, CACHE_DIR_NAME, }
|
|
|
6
6
|
*/
|
|
7
7
|
/**
|
|
8
8
|
* Resolves the absolute source directory path from configuration.
|
|
9
|
-
* @param config - Stati configuration
|
|
9
|
+
* @param config - Stati configuration; `srcDir` defaults to `site`, as `loadConfig()` sets it
|
|
10
10
|
* @returns Absolute path to the source directory
|
|
11
11
|
*/
|
|
12
12
|
export function resolveSrcDir(config) {
|
|
13
|
-
return join(process.cwd(), config.srcDir);
|
|
13
|
+
return join(process.cwd(), config.srcDir ?? DEFAULT_SRC_DIR);
|
|
14
14
|
}
|
|
15
15
|
/**
|
|
16
16
|
* Resolves the absolute output directory path from configuration.
|
|
17
|
-
* @param config - Stati configuration
|
|
17
|
+
* @param config - Stati configuration; `outDir` defaults to `dist`
|
|
18
18
|
* @returns Absolute path to the output directory
|
|
19
19
|
*/
|
|
20
20
|
export function resolveOutDir(config) {
|
|
21
|
-
return join(process.cwd(), config.outDir);
|
|
21
|
+
return join(process.cwd(), config.outDir ?? DEFAULT_OUT_DIR);
|
|
22
22
|
}
|
|
23
23
|
/**
|
|
24
24
|
* Resolves the absolute static directory path from configuration.
|
|
25
|
-
* @param config - Stati configuration
|
|
25
|
+
* @param config - Stati configuration; `staticDir` defaults to `public`
|
|
26
26
|
* @returns Absolute path to the static directory
|
|
27
27
|
*/
|
|
28
28
|
export function resolveStaticDir(config) {
|
|
29
|
-
return join(process.cwd(), config.staticDir);
|
|
29
|
+
return join(process.cwd(), config.staticDir ?? DEFAULT_STATIC_DIR);
|
|
30
30
|
}
|
|
31
31
|
/**
|
|
32
32
|
* Resolves the absolute cache directory path.
|
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
*/
|
|
9
9
|
/**
|
|
10
10
|
* Detects if Tailwind CSS is being used in the project by checking for:
|
|
11
|
-
* 1. tailwind.config.js or
|
|
12
|
-
* 2. tailwindcss in package.json dependencies
|
|
11
|
+
* 1. tailwind.config.js, .ts, .mjs or .cjs (Tailwind CSS 3)
|
|
12
|
+
* 2. tailwindcss, @tailwindcss/cli or @tailwindcss/postcss in package.json dependencies
|
|
13
13
|
*
|
|
14
14
|
* Results are cached to avoid repeated file system checks.
|
|
15
15
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tailwind-inventory.utils.d.ts","sourceRoot":"","sources":["../../../src/core/utils/tailwind-inventory.utils.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;
|
|
1
|
+
{"version":3,"file":"tailwind-inventory.utils.d.ts","sourceRoot":"","sources":["../../../src/core/utils/tailwind-inventory.utils.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AA6BH;;;;;;;;;GASG;AACH,wBAAsB,cAAc,CAAC,WAAW,GAAE,MAAsB,GAAG,OAAO,CAAC,OAAO,CAAC,CA4C1F;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,IAAI,CAE7C;AAED;;;;;;;GAOG;AACH,wBAAsB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAkC7E;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAI1D;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,IAAI,IAAI,CAE9C;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,IAAI,IAAI,CAE/C;AAED;;;GAGG;AACH,wBAAgB,cAAc,IAAI,IAAI,CAErC;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,IAAI,MAAM,EAAE,CAEvC;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,IAAI,OAAO,CAE3C;AAqCD,wBAAsB,2BAA2B,CAC/C,QAAQ,EAAE,MAAM,EAChB,eAAe,UAAQ,GACtB,OAAO,CAAC,MAAM,CAAC,CAiEjB"}
|
|
@@ -23,10 +23,15 @@ let inventoryTrackingEnabled = false;
|
|
|
23
23
|
* Cached result of Tailwind detection to avoid repeated file system checks.
|
|
24
24
|
*/
|
|
25
25
|
let tailwindDetected = null;
|
|
26
|
+
/**
|
|
27
|
+
* Packages that mean a project uses Tailwind CSS. Tailwind CSS 4 runs its CLI and
|
|
28
|
+
* PostCSS plugin from separate packages and needs no config file.
|
|
29
|
+
*/
|
|
30
|
+
const TAILWIND_PACKAGES = ['tailwindcss', '@tailwindcss/cli', '@tailwindcss/postcss'];
|
|
26
31
|
/**
|
|
27
32
|
* Detects if Tailwind CSS is being used in the project by checking for:
|
|
28
|
-
* 1. tailwind.config.js or
|
|
29
|
-
* 2. tailwindcss in package.json dependencies
|
|
33
|
+
* 1. tailwind.config.js, .ts, .mjs or .cjs (Tailwind CSS 3)
|
|
34
|
+
* 2. tailwindcss, @tailwindcss/cli or @tailwindcss/postcss in package.json dependencies
|
|
30
35
|
*
|
|
31
36
|
* Results are cached to avoid repeated file system checks.
|
|
32
37
|
*
|
|
@@ -60,7 +65,7 @@ export async function isTailwindUsed(projectRoot = process.cwd()) {
|
|
|
60
65
|
...packageJson.dependencies,
|
|
61
66
|
...packageJson.devDependencies,
|
|
62
67
|
};
|
|
63
|
-
if (
|
|
68
|
+
if (TAILWIND_PACKAGES.some((name) => deps[name])) {
|
|
64
69
|
tailwindDetected = true;
|
|
65
70
|
return true;
|
|
66
71
|
}
|
|
@@ -176,7 +181,8 @@ export function isTrackingEnabled() {
|
|
|
176
181
|
* Writes the Tailwind class inventory to an HTML file that Tailwind can scan.
|
|
177
182
|
*
|
|
178
183
|
* The generated file contains all tracked classes in a hidden div.
|
|
179
|
-
*
|
|
184
|
+
* Tailwind must scan it: an `@source` rule in the CSS file (Tailwind CSS 4) or an
|
|
185
|
+
* entry in the `content` array of tailwind.config.js (Tailwind CSS 3).
|
|
180
186
|
* Skips write if the inventory hasn't changed (dev mode optimization).
|
|
181
187
|
*
|
|
182
188
|
* @param cacheDir - Directory where the inventory file should be written (typically .stati/)
|
|
@@ -228,10 +234,13 @@ export async function writeTailwindClassInventory(cacheDir, skipIfUnchanged = fa
|
|
|
228
234
|
Auto-generated by Stati - DO NOT EDIT
|
|
229
235
|
|
|
230
236
|
This file contains dynamically-generated Tailwind classes extracted from your templates.
|
|
231
|
-
It ensures that Tailwind
|
|
237
|
+
It ensures that Tailwind generates CSS for classes built with template
|
|
232
238
|
variables (e.g., from-\${color}-50).
|
|
233
239
|
|
|
234
|
-
|
|
240
|
+
Tailwind CSS 4: add an @source rule for this file to your CSS file. From src/styles.css:
|
|
241
|
+
@source '../.stati/tailwind-classes.html';
|
|
242
|
+
|
|
243
|
+
Tailwind CSS 3: add this file to your tailwind.config.js content array:
|
|
235
244
|
content: [
|
|
236
245
|
'./site/**/*.{md,eta,html}',
|
|
237
246
|
'./.stati/tailwind-classes.html'
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { PageModel } from '../../types/index.js';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
3
|
+
* Page list utilities shared by rendering and the ISG cache: collection index pages, virtual
|
|
4
|
+
* pages and collection paths. Layout discovery uses the template index (core/template-index.ts).
|
|
5
5
|
*/
|
|
6
6
|
/**
|
|
7
7
|
* Whether a page was created by Stati rather than loaded from a Markdown file: a page expanded
|
|
@@ -38,17 +38,6 @@ export declare function getFirstPaginationPage(page: PageModel, allPages: PageMo
|
|
|
38
38
|
* @returns True if the page is a collection index page
|
|
39
39
|
*/
|
|
40
40
|
export declare function isCollectionIndexPage(page: PageModel, allPages: PageModel[]): boolean;
|
|
41
|
-
/**
|
|
42
|
-
* Discovers layout files by searching up the directory hierarchy.
|
|
43
|
-
* Supports both explicit layout specification and automatic discovery.
|
|
44
|
-
*
|
|
45
|
-
* @param pagePath - The path to the page (relative to srcDir)
|
|
46
|
-
* @param config - Stati configuration
|
|
47
|
-
* @param explicitLayout - Explicit layout name from front-matter
|
|
48
|
-
* @param isIndexPage - Whether this is an aggregation/index page (enables index.eta lookup)
|
|
49
|
-
* @returns The layout file path (relative to srcDir) or null if none found
|
|
50
|
-
*/
|
|
51
|
-
export declare function discoverLayout(pagePath: string, config: StatiConfig, explicitLayout?: string, isIndexPage?: boolean): Promise<string | null>;
|
|
52
41
|
/**
|
|
53
42
|
* Gets the collection path for a given page URL.
|
|
54
43
|
* For index pages, returns the page's URL. For child pages, returns the parent directory.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"template-discovery.utils.d.ts","sourceRoot":"","sources":["../../../src/core/utils/template-discovery.utils.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"template-discovery.utils.d.ts","sourceRoot":"","sources":["../../../src/core/utils/template-discovery.utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEtD;;;GAGG;AAEH;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,CAEtD;AAiED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,SAAS,EACf,QAAQ,EAAE,SAAS,EAAE,GACpB,SAAS,GAAG,SAAS,CAMvB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,OAAO,CAoBrF;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAkBhE"}
|
|
@@ -1,10 +1,6 @@
|
|
|
1
|
-
import { join, dirname, posix } from 'node:path';
|
|
2
|
-
import { pathExists } from './fs.utils.js';
|
|
3
|
-
import { LAYOUT_TEMPLATE } from '../../constants.js';
|
|
4
|
-
import { resolveSrcDir } from './paths.utils.js';
|
|
5
1
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
2
|
+
* Page list utilities shared by rendering and the ISG cache: collection index pages, virtual
|
|
3
|
+
* pages and collection paths. Layout discovery uses the template index (core/template-index.ts).
|
|
8
4
|
*/
|
|
9
5
|
/**
|
|
10
6
|
* Whether a page was created by Stati rather than loaded from a Markdown file: a page expanded
|
|
@@ -110,62 +106,6 @@ export function isCollectionIndexPage(page, allPages) {
|
|
|
110
106
|
const containingUrl = getPageListIndex(allPages).prefixes.get(pageUrlAsDir);
|
|
111
107
|
return containingUrl === null || (containingUrl !== undefined && containingUrl !== page.url);
|
|
112
108
|
}
|
|
113
|
-
/**
|
|
114
|
-
* Discovers layout files by searching up the directory hierarchy.
|
|
115
|
-
* Supports both explicit layout specification and automatic discovery.
|
|
116
|
-
*
|
|
117
|
-
* @param pagePath - The path to the page (relative to srcDir)
|
|
118
|
-
* @param config - Stati configuration
|
|
119
|
-
* @param explicitLayout - Explicit layout name from front-matter
|
|
120
|
-
* @param isIndexPage - Whether this is an aggregation/index page (enables index.eta lookup)
|
|
121
|
-
* @returns The layout file path (relative to srcDir) or null if none found
|
|
122
|
-
*/
|
|
123
|
-
export async function discoverLayout(pagePath, config, explicitLayout, isIndexPage) {
|
|
124
|
-
// Early return if required config values are missing
|
|
125
|
-
if (!config.srcDir) {
|
|
126
|
-
return null;
|
|
127
|
-
}
|
|
128
|
-
const srcDir = resolveSrcDir(config);
|
|
129
|
-
// If explicit layout is specified, use it
|
|
130
|
-
if (explicitLayout) {
|
|
131
|
-
const layoutPath = join(srcDir, `${explicitLayout}.eta`);
|
|
132
|
-
if (await pathExists(layoutPath)) {
|
|
133
|
-
return `${explicitLayout}.eta`;
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
// Get the directory of the current page
|
|
137
|
-
const pageDir = dirname(pagePath);
|
|
138
|
-
const pathSegments = pageDir === '.' ? [] : pageDir.split(/[/\\]/); // Handle both separators
|
|
139
|
-
// Search for layout.eta from current directory up to root
|
|
140
|
-
const dirsToSearch = [];
|
|
141
|
-
// Add current directory if not root
|
|
142
|
-
if (pathSegments.length > 0) {
|
|
143
|
-
for (let i = pathSegments.length; i > 0; i--) {
|
|
144
|
-
dirsToSearch.push(pathSegments.slice(0, i).join('/'));
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
// Add root directory
|
|
148
|
-
dirsToSearch.push('');
|
|
149
|
-
for (const dir of dirsToSearch) {
|
|
150
|
-
// For index pages, first check for index.eta in each directory
|
|
151
|
-
if (isIndexPage) {
|
|
152
|
-
const indexLayoutPath = dir ? join(srcDir, dir, 'index.eta') : join(srcDir, 'index.eta');
|
|
153
|
-
if (await pathExists(indexLayoutPath)) {
|
|
154
|
-
// Return relative path with forward slashes for Eta
|
|
155
|
-
const relativePath = dir ? `${dir}/index.eta` : 'index.eta';
|
|
156
|
-
return posix.normalize(relativePath);
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
// Then check for layout.eta as fallback
|
|
160
|
-
const layoutPath = dir ? join(srcDir, dir, LAYOUT_TEMPLATE) : join(srcDir, LAYOUT_TEMPLATE);
|
|
161
|
-
if (await pathExists(layoutPath)) {
|
|
162
|
-
// Return relative path with forward slashes for Eta
|
|
163
|
-
const relativePath = dir ? `${dir}/${LAYOUT_TEMPLATE}` : LAYOUT_TEMPLATE;
|
|
164
|
-
return posix.normalize(relativePath);
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
return null;
|
|
168
|
-
}
|
|
169
109
|
/**
|
|
170
110
|
* Gets the collection path for a given page URL.
|
|
171
111
|
* For index pages, returns the page's URL. For child pages, returns the parent directory.
|
|
@@ -19,12 +19,25 @@ export declare class TemplateError extends Error {
|
|
|
19
19
|
*/
|
|
20
20
|
toErrorDetails(): Promise<ErrorDetails>;
|
|
21
21
|
}
|
|
22
|
+
/**
|
|
23
|
+
* Thrown by Stati's template functions, such as `stati.include()` and `stati.layout()`, for a
|
|
24
|
+
* mistake at the call: an unknown template name, props that are not an object, Eta's own
|
|
25
|
+
* `include()`. Thrown inside a template, so Eta's debug mode adds the calling template and line
|
|
26
|
+
* to the message, and keeps this error as its `cause`.
|
|
27
|
+
*/
|
|
28
|
+
export declare class TemplateUsageError extends Error {
|
|
29
|
+
/** Fixes to show in the error overlay */
|
|
30
|
+
readonly suggestions: string[];
|
|
31
|
+
constructor(message: string, suggestions?: string[]);
|
|
32
|
+
}
|
|
22
33
|
/**
|
|
23
34
|
* Parses Eta template errors to extract file location information.
|
|
24
35
|
*/
|
|
25
36
|
export declare function parseEtaError(error: Error, templatePath?: string): TemplateError;
|
|
26
37
|
/**
|
|
27
|
-
* Enhances a generic error with template-specific context.
|
|
38
|
+
* Enhances a generic error with template-specific context. An error that wraps a
|
|
39
|
+
* {@link TemplateError}, as Eta's debug mode does for an error from a nested template, returns
|
|
40
|
+
* the innermost one, which points at the template that failed.
|
|
28
41
|
*/
|
|
29
42
|
export declare function createTemplateError(error: Error, templatePath?: string, _line?: number, _column?: number): TemplateError;
|
|
30
43
|
//# sourceMappingURL=template-errors.utils.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"template-errors.utils.d.ts","sourceRoot":"","sources":["../../../src/core/utils/template-errors.utils.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAG7D;;GAEG;AACH,qBAAa,aAAc,SAAQ,KAAK;IACtC,SAAgB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClC,SAAgB,IAAI,CAAC,EAAE,MAAM,CAAC;IAC9B,SAAgB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChC,SAAgB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClC,8EAA8E;IAC9E,SAAgB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvC,SAAgB,OAAO,CAAC,EAAE;QACxB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;QAClB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;KAClB,CAAC;gBAGA,OAAO,EAAE,MAAM,EACf,QAAQ,CAAC,EAAE,MAAM,EACjB,IAAI,CAAC,EAAE,MAAM,EACb,MAAM,CAAC,EAAE,MAAM,EACf,QAAQ,CAAC,EAAE,MAAM,EACjB,WAAW,CAAC,EAAE,MAAM,EAAE;IAWxB;;OAEG;IACG,cAAc,IAAI,OAAO,CAAC,YAAY,CAAC;CAoE9C;
|
|
1
|
+
{"version":3,"file":"template-errors.utils.d.ts","sourceRoot":"","sources":["../../../src/core/utils/template-errors.utils.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAG7D;;GAEG;AACH,qBAAa,aAAc,SAAQ,KAAK;IACtC,SAAgB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClC,SAAgB,IAAI,CAAC,EAAE,MAAM,CAAC;IAC9B,SAAgB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChC,SAAgB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClC,8EAA8E;IAC9E,SAAgB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvC,SAAgB,OAAO,CAAC,EAAE;QACxB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;QAClB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;KAClB,CAAC;gBAGA,OAAO,EAAE,MAAM,EACf,QAAQ,CAAC,EAAE,MAAM,EACjB,IAAI,CAAC,EAAE,MAAM,EACb,MAAM,CAAC,EAAE,MAAM,EACf,QAAQ,CAAC,EAAE,MAAM,EACjB,WAAW,CAAC,EAAE,MAAM,EAAE;IAWxB;;OAEG;IACG,cAAc,IAAI,OAAO,CAAC,YAAY,CAAC;CAoE9C;AAED;;;;;GAKG;AACH,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,yCAAyC;IACzC,SAAgB,WAAW,EAAE,MAAM,EAAE,CAAC;gBAE1B,OAAO,EAAE,MAAM,EAAE,WAAW,GAAE,MAAM,EAAO;CAKxD;AAyDD;;GAEG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,KAAK,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,aAAa,CAyDhF;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,KAAK,EACZ,YAAY,CAAC,EAAE,MAAM,EACrB,KAAK,CAAC,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,MAAM,GACf,aAAa,CAQf"}
|