@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
package/dist/core/isg/deps.d.ts
CHANGED
|
@@ -1,79 +1,17 @@
|
|
|
1
|
-
import type { PageModel
|
|
2
|
-
|
|
3
|
-
* Clears the template path and content caches.
|
|
4
|
-
* Should be called at the start of each build.
|
|
5
|
-
*/
|
|
6
|
-
export declare function clearTemplatePathCache(): void;
|
|
7
|
-
/**
|
|
8
|
-
* Error thrown when a circular dependency is detected in templates.
|
|
9
|
-
*/
|
|
10
|
-
export declare class CircularDependencyError extends Error {
|
|
11
|
-
readonly dependencyChain: string[];
|
|
12
|
-
constructor(dependencyChain: string[], message: string);
|
|
13
|
-
}
|
|
14
|
-
/**
|
|
15
|
-
* Tracks template dependencies for a given page by parsing template content.
|
|
16
|
-
* Only includes templates that are actually referenced (via include, layout, or stati.partials calls).
|
|
17
|
-
* This provides accurate dependency tracking for ISG cache invalidation.
|
|
18
|
-
*
|
|
19
|
-
* The function recursively parses the layout template and all its dependencies to build
|
|
20
|
-
* the complete dependency tree. This ensures that changes to unused partials don't
|
|
21
|
-
* trigger unnecessary page rebuilds.
|
|
22
|
-
*
|
|
23
|
-
* @param page - The page model to track dependencies for
|
|
24
|
-
* @param config - Stati configuration
|
|
25
|
-
* @param allPages - All pages in the site, used to detect collection index pages the same way rendering does
|
|
26
|
-
* @returns Array of absolute paths to actually-used template files (POSIX format)
|
|
27
|
-
* @throws {CircularDependencyError} When circular dependencies are detected in templates
|
|
28
|
-
*
|
|
29
|
-
* @example
|
|
30
|
-
* ```typescript
|
|
31
|
-
* try {
|
|
32
|
-
* const deps = await trackTemplateDependencies(page, config, allPages);
|
|
33
|
-
* console.log(`Page depends on ${deps.length} template files`);
|
|
34
|
-
* } catch (error) {
|
|
35
|
-
* if (error instanceof CircularDependencyError) {
|
|
36
|
-
* console.error(`Circular dependency: ${error.dependencyChain.join(' -> ')}`);
|
|
37
|
-
* }
|
|
38
|
-
* }
|
|
39
|
-
* ```
|
|
40
|
-
*/
|
|
41
|
-
export declare function trackTemplateDependencies(page: PageModel, config: StatiConfig, allPages: PageModel[]): Promise<string[]>;
|
|
1
|
+
import type { PageModel } from '../../types/index.js';
|
|
2
|
+
import type { TemplateIndex } from '../template-index.js';
|
|
42
3
|
/**
|
|
43
4
|
* Resolves the layout a page renders with, in the form stored as the first entry of its
|
|
44
5
|
* cache dependencies. Uses the same lookup as rendering, so callers can tell whether the
|
|
45
|
-
* page's layout has changed since
|
|
6
|
+
* page's layout has changed since it rendered, for example when a collection gains its first
|
|
7
|
+
* child page and switches to `index.eta`.
|
|
8
|
+
*
|
|
9
|
+
* The other templates a page uses are recorded while it renders.
|
|
46
10
|
*
|
|
47
11
|
* @param page - The page model to resolve the layout for
|
|
48
|
-
* @param config - Stati configuration
|
|
49
12
|
* @param allPages - All pages in the site, used to detect collection index pages the same way rendering does
|
|
13
|
+
* @param index - The build's template index
|
|
50
14
|
* @returns Absolute path to the layout file (POSIX format), or null if no layout applies
|
|
51
15
|
*/
|
|
52
|
-
export declare function resolveLayoutDependency(page: PageModel,
|
|
53
|
-
/**
|
|
54
|
-
* Resolves the Open Graph template a page renders with, when Open Graph images are on and the
|
|
55
|
-
* page does not opt out. Pages that use the built-in template have no file dependency.
|
|
56
|
-
*
|
|
57
|
-
* @param page - The page model
|
|
58
|
-
* @param config - Stati configuration
|
|
59
|
-
* @returns Absolute path to the template (POSIX format), or null
|
|
60
|
-
*/
|
|
61
|
-
export declare function resolveOgTemplateDependency(page: PageModel, config: StatiConfig): Promise<string | null>;
|
|
62
|
-
/**
|
|
63
|
-
* Resolves a template name to its file path.
|
|
64
|
-
* Used for explicit layout specifications in front matter.
|
|
65
|
-
*
|
|
66
|
-
* @param layout - Layout name (without .eta extension)
|
|
67
|
-
* @param config - Stati configuration
|
|
68
|
-
* @returns Absolute path to template file, or null if not found
|
|
69
|
-
*
|
|
70
|
-
* @example
|
|
71
|
-
* ```typescript
|
|
72
|
-
* const templatePath = await resolveTemplatePath('post', config);
|
|
73
|
-
* if (templatePath) {
|
|
74
|
-
* console.log(`Found template at: ${templatePath}`);
|
|
75
|
-
* }
|
|
76
|
-
* ```
|
|
77
|
-
*/
|
|
78
|
-
export declare function resolveTemplatePath(layout: string, config: StatiConfig): Promise<string | null>;
|
|
16
|
+
export declare function resolveLayoutDependency(page: PageModel, allPages: PageModel[], index: TemplateIndex): string | null;
|
|
79
17
|
//# sourceMappingURL=deps.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deps.d.ts","sourceRoot":"","sources":["../../../src/core/isg/deps.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"deps.d.ts","sourceRoot":"","sources":["../../../src/core/isg/deps.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAE1D;;;;;;;;;;;;GAYG;AACH,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,SAAS,EACf,QAAQ,EAAE,SAAS,EAAE,EACrB,KAAK,EAAE,aAAa,GACnB,MAAM,GAAG,IAAI,CASf"}
|
package/dist/core/isg/deps.js
CHANGED
|
@@ -1,411 +1,20 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import glob from 'fast-glob';
|
|
4
|
-
import { TEMPLATE_EXTENSION, DEFAULT_OG_TEMPLATE } from '../../constants.js';
|
|
5
|
-
import { clearOgTemplateCache, findOgTemplatePath, isOgImageExcluded } from '../../images/og.js';
|
|
6
|
-
/**
|
|
7
|
-
* Per-build cache for template path resolution (glob results).
|
|
8
|
-
* Cleared at the start of each build via clearTemplatePathCache().
|
|
9
|
-
*/
|
|
10
|
-
const templatePathCache = new Map();
|
|
11
|
-
/**
|
|
12
|
-
* Per-build cache for template content reads.
|
|
13
|
-
* Cleared at the start of each build via clearTemplatePathCache().
|
|
14
|
-
*/
|
|
15
|
-
const templateContentCache = new Map();
|
|
16
|
-
/**
|
|
17
|
-
* Clears the template path and content caches.
|
|
18
|
-
* Should be called at the start of each build.
|
|
19
|
-
*/
|
|
20
|
-
export function clearTemplatePathCache() {
|
|
21
|
-
templatePathCache.clear();
|
|
22
|
-
templateContentCache.clear();
|
|
23
|
-
clearOgTemplateCache();
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* Error thrown when a circular dependency is detected in templates.
|
|
27
|
-
*/
|
|
28
|
-
export class CircularDependencyError extends Error {
|
|
29
|
-
dependencyChain;
|
|
30
|
-
constructor(dependencyChain, message) {
|
|
31
|
-
super(message);
|
|
32
|
-
this.dependencyChain = dependencyChain;
|
|
33
|
-
this.name = 'CircularDependencyError';
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
|
-
* Tracks template dependencies for a given page by parsing template content.
|
|
38
|
-
* Only includes templates that are actually referenced (via include, layout, or stati.partials calls).
|
|
39
|
-
* This provides accurate dependency tracking for ISG cache invalidation.
|
|
40
|
-
*
|
|
41
|
-
* The function recursively parses the layout template and all its dependencies to build
|
|
42
|
-
* the complete dependency tree. This ensures that changes to unused partials don't
|
|
43
|
-
* trigger unnecessary page rebuilds.
|
|
44
|
-
*
|
|
45
|
-
* @param page - The page model to track dependencies for
|
|
46
|
-
* @param config - Stati configuration
|
|
47
|
-
* @param allPages - All pages in the site, used to detect collection index pages the same way rendering does
|
|
48
|
-
* @returns Array of absolute paths to actually-used template files (POSIX format)
|
|
49
|
-
* @throws {CircularDependencyError} When circular dependencies are detected in templates
|
|
50
|
-
*
|
|
51
|
-
* @example
|
|
52
|
-
* ```typescript
|
|
53
|
-
* try {
|
|
54
|
-
* const deps = await trackTemplateDependencies(page, config, allPages);
|
|
55
|
-
* console.log(`Page depends on ${deps.length} template files`);
|
|
56
|
-
* } catch (error) {
|
|
57
|
-
* if (error instanceof CircularDependencyError) {
|
|
58
|
-
* console.error(`Circular dependency: ${error.dependencyChain.join(' -> ')}`);
|
|
59
|
-
* }
|
|
60
|
-
* }
|
|
61
|
-
* ```
|
|
62
|
-
*/
|
|
63
|
-
export async function trackTemplateDependencies(page, config, allPages) {
|
|
64
|
-
// Early return if required config values are missing
|
|
65
|
-
if (!config.srcDir) {
|
|
66
|
-
console.warn('Config srcDir is missing, cannot track template dependencies');
|
|
67
|
-
return [];
|
|
68
|
-
}
|
|
69
|
-
const deps = [];
|
|
70
|
-
const srcDir = resolveSrcDir(config);
|
|
71
|
-
// Track dependencies with circular detection
|
|
72
|
-
// The visited set will contain all templates that are actually used (not just accessible)
|
|
73
|
-
const visited = new Set();
|
|
74
|
-
const currentPath = new Set();
|
|
75
|
-
// 1. Find the layout file that will be used for this page
|
|
76
|
-
const absoluteLayoutPath = await resolveLayoutDependency(page, config, allPages);
|
|
77
|
-
if (absoluteLayoutPath) {
|
|
78
|
-
deps.push(absoluteLayoutPath);
|
|
79
|
-
// Recursively traverse the template dependency tree
|
|
80
|
-
// This populates 'visited' with all actually-used templates (not just accessible ones)
|
|
81
|
-
await collectTemplateDependencies(absoluteLayoutPath, srcDir, visited, currentPath);
|
|
82
|
-
}
|
|
83
|
-
// The Open Graph template renders with the page, so it and its partials are dependencies too.
|
|
84
|
-
// It comes after the layout, which must stay first.
|
|
85
|
-
const ogTemplatePath = await resolveOgTemplateDependency(page, config);
|
|
86
|
-
if (ogTemplatePath) {
|
|
87
|
-
deps.push(ogTemplatePath);
|
|
88
|
-
await collectTemplateDependencies(ogTemplatePath, srcDir, visited, currentPath);
|
|
89
|
-
}
|
|
90
|
-
// 2. Add all actually-used templates from the visited set
|
|
91
|
-
// Filter to only include underscore directories (partials/components)
|
|
92
|
-
// and normalize paths to POSIX format
|
|
93
|
-
for (const templatePath of visited) {
|
|
94
|
-
const normalizedPath = templatePath.replace(/\\/g, '/');
|
|
95
|
-
// Only add partials (files in directories starting with underscore) - layout is already added
|
|
96
|
-
// Use strict pattern to match /_dirname/ where dirname starts with underscore
|
|
97
|
-
if (/\/_[^/]+\//.test(normalizedPath)) {
|
|
98
|
-
deps.push(normalizedPath);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
return deps;
|
|
102
|
-
}
|
|
1
|
+
import { posix, relative } from 'node:path';
|
|
2
|
+
import { isCollectionIndexPage } from '../utils/index.js';
|
|
103
3
|
/**
|
|
104
4
|
* Resolves the layout a page renders with, in the form stored as the first entry of its
|
|
105
5
|
* cache dependencies. Uses the same lookup as rendering, so callers can tell whether the
|
|
106
|
-
* page's layout has changed since
|
|
6
|
+
* page's layout has changed since it rendered, for example when a collection gains its first
|
|
7
|
+
* child page and switches to `index.eta`.
|
|
8
|
+
*
|
|
9
|
+
* The other templates a page uses are recorded while it renders.
|
|
107
10
|
*
|
|
108
11
|
* @param page - The page model to resolve the layout for
|
|
109
|
-
* @param config - Stati configuration
|
|
110
12
|
* @param allPages - All pages in the site, used to detect collection index pages the same way rendering does
|
|
13
|
+
* @param index - The build's template index
|
|
111
14
|
* @returns Absolute path to the layout file (POSIX format), or null if no layout applies
|
|
112
15
|
*/
|
|
113
|
-
export
|
|
114
|
-
|
|
115
|
-
return null;
|
|
116
|
-
}
|
|
117
|
-
const srcDir = resolveSrcDir(config);
|
|
118
|
-
const layoutPath = await discoverLayout(relative(srcDir, page.sourcePath), config, page.frontMatter.layout, isCollectionIndexPage(page, allPages));
|
|
16
|
+
export function resolveLayoutDependency(page, allPages, index) {
|
|
17
|
+
const { file } = index.resolvePageLayout(relative(index.srcDir, page.sourcePath).replace(/\\/g, '/'), page.frontMatter.layout, isCollectionIndexPage(page, allPages));
|
|
119
18
|
// Normalize to POSIX format for consistent manifest output across platforms
|
|
120
|
-
return
|
|
121
|
-
}
|
|
122
|
-
/**
|
|
123
|
-
* Resolves the Open Graph template a page renders with, when Open Graph images are on and the
|
|
124
|
-
* page does not opt out. Pages that use the built-in template have no file dependency.
|
|
125
|
-
*
|
|
126
|
-
* @param page - The page model
|
|
127
|
-
* @param config - Stati configuration
|
|
128
|
-
* @returns Absolute path to the template (POSIX format), or null
|
|
129
|
-
*/
|
|
130
|
-
export async function resolveOgTemplateDependency(page, config) {
|
|
131
|
-
const og = config.images ? config.images.og : undefined;
|
|
132
|
-
if (!og || !config.srcDir) {
|
|
133
|
-
return null;
|
|
134
|
-
}
|
|
135
|
-
const options = og === true ? {} : og;
|
|
136
|
-
if (isOgImageExcluded(page, options.exclude ?? [])) {
|
|
137
|
-
return null;
|
|
138
|
-
}
|
|
139
|
-
const templatePath = await findOgTemplatePath(page.sourcePath, resolveSrcDir(config), options.template ?? DEFAULT_OG_TEMPLATE);
|
|
140
|
-
return templatePath ? templatePath.replace(/\\/g, '/') : null;
|
|
141
|
-
}
|
|
142
|
-
/**
|
|
143
|
-
* Resolves a template name to its file path.
|
|
144
|
-
* Used for explicit layout specifications in front matter.
|
|
145
|
-
*
|
|
146
|
-
* @param layout - Layout name (without .eta extension)
|
|
147
|
-
* @param config - Stati configuration
|
|
148
|
-
* @returns Absolute path to template file, or null if not found
|
|
149
|
-
*
|
|
150
|
-
* @example
|
|
151
|
-
* ```typescript
|
|
152
|
-
* const templatePath = await resolveTemplatePath('post', config);
|
|
153
|
-
* if (templatePath) {
|
|
154
|
-
* console.log(`Found template at: ${templatePath}`);
|
|
155
|
-
* }
|
|
156
|
-
* ```
|
|
157
|
-
*/
|
|
158
|
-
export async function resolveTemplatePath(layout, config) {
|
|
159
|
-
const srcDir = resolveSrcDir(config);
|
|
160
|
-
const layoutPath = join(srcDir, `${layout}.eta`);
|
|
161
|
-
if (await pathExists(layoutPath)) {
|
|
162
|
-
return layoutPath;
|
|
163
|
-
}
|
|
164
|
-
return null;
|
|
165
|
-
}
|
|
166
|
-
/**
|
|
167
|
-
* Recursively collects all template dependencies by parsing template content.
|
|
168
|
-
* Only includes templates that are actually referenced (not just accessible).
|
|
169
|
-
* Uses DFS to traverse the dependency graph and detects circular references.
|
|
170
|
-
*
|
|
171
|
-
* @param templatePath - Absolute path to template file to analyze
|
|
172
|
-
* @param srcDir - Source directory for resolving relative template paths
|
|
173
|
-
* @param visited - Set to track all visited templates (accumulated dependencies)
|
|
174
|
-
* @param currentPath - Set of templates in current DFS path (for cycle detection)
|
|
175
|
-
* @throws {CircularDependencyError} When a circular dependency is detected
|
|
176
|
-
*/
|
|
177
|
-
async function collectTemplateDependencies(templatePath, srcDir, visited, currentPath) {
|
|
178
|
-
// Normalize path for consistent tracking
|
|
179
|
-
const normalizedPath = templatePath.replace(/\\/g, '/');
|
|
180
|
-
// Check for circular dependency FIRST (before visited check)
|
|
181
|
-
// A circular dependency means we're visiting a template that's already in our current DFS path
|
|
182
|
-
// This must be checked before the visited check because a path in currentPath is always in visited
|
|
183
|
-
if (currentPath.has(normalizedPath)) {
|
|
184
|
-
const chain = [...currentPath, normalizedPath];
|
|
185
|
-
throw new CircularDependencyError(chain, `Circular dependency detected in templates: ${chain.join(' -> ')}`);
|
|
186
|
-
}
|
|
187
|
-
// Skip if already processed (but not in current path - those are handled above)
|
|
188
|
-
if (visited.has(normalizedPath)) {
|
|
189
|
-
return;
|
|
190
|
-
}
|
|
191
|
-
// Check if template file exists
|
|
192
|
-
if (!(await pathExists(templatePath))) {
|
|
193
|
-
return;
|
|
194
|
-
}
|
|
195
|
-
// Add to tracking sets
|
|
196
|
-
currentPath.add(normalizedPath);
|
|
197
|
-
visited.add(normalizedPath);
|
|
198
|
-
try {
|
|
199
|
-
// Read template content to find includes/extends (use cache)
|
|
200
|
-
let content;
|
|
201
|
-
if (templateContentCache.has(normalizedPath)) {
|
|
202
|
-
content = templateContentCache.get(normalizedPath);
|
|
203
|
-
}
|
|
204
|
-
else {
|
|
205
|
-
content = await readFile(templatePath, 'utf-8');
|
|
206
|
-
templateContentCache.set(normalizedPath, content ?? null);
|
|
207
|
-
}
|
|
208
|
-
if (!content) {
|
|
209
|
-
return;
|
|
210
|
-
}
|
|
211
|
-
// Parse template to find referenced templates
|
|
212
|
-
const dependencies = await parseTemplateDependencies(content, templatePath, srcDir);
|
|
213
|
-
// Recursively collect dependencies
|
|
214
|
-
for (const depPath of dependencies) {
|
|
215
|
-
await collectTemplateDependencies(depPath, srcDir, visited, currentPath);
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
catch (error) {
|
|
219
|
-
// Re-throw circular dependency errors - these are fatal
|
|
220
|
-
if (error instanceof CircularDependencyError) {
|
|
221
|
-
throw error;
|
|
222
|
-
}
|
|
223
|
-
// Log warning but continue - don't fail the entire build for template parsing issues
|
|
224
|
-
if (error instanceof Error) {
|
|
225
|
-
console.warn(`Warning: Could not parse template ${templatePath}: ${error.message}`);
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
finally {
|
|
229
|
-
// Remove from current path when backtracking
|
|
230
|
-
currentPath.delete(normalizedPath);
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
/**
|
|
234
|
-
* Parses a template file to find included/extended templates.
|
|
235
|
-
* This is a basic implementation that looks for common Eta patterns.
|
|
236
|
-
*
|
|
237
|
-
* @param content - Template file content
|
|
238
|
-
* @param templatePath - Path to the template file (for error context)
|
|
239
|
-
* @param srcDir - Source directory for resolving relative paths
|
|
240
|
-
* @returns Array of absolute paths to dependent templates
|
|
241
|
-
*/
|
|
242
|
-
async function parseTemplateDependencies(content, templatePath, srcDir) {
|
|
243
|
-
const dependencies = [];
|
|
244
|
-
const templateDir = dirname(templatePath);
|
|
245
|
-
// Strip comments from template content to avoid false positives
|
|
246
|
-
// This removes:
|
|
247
|
-
// 1. Eta block comments: <% /* ... */ %> or <% /** ... */ %>
|
|
248
|
-
// 2. JavaScript single-line comments within Eta blocks: <% // ... %>
|
|
249
|
-
// 3. JavaScript block comments within Eta blocks (handles multi-line)
|
|
250
|
-
const contentWithoutComments = content
|
|
251
|
-
// Remove JS block comments (/* ... */) - handles multi-line
|
|
252
|
-
.replace(/\/\*[\s\S]*?\*\//g, '')
|
|
253
|
-
// Remove JS single-line comments (// ...) but only within Eta blocks
|
|
254
|
-
// This is tricky - we'll be conservative and just remove // comments to end of line
|
|
255
|
-
.replace(/\/\/[^\n]*/g, '');
|
|
256
|
-
// Look for Eta include patterns: <%~ include('template') %>
|
|
257
|
-
const includePatterns = [
|
|
258
|
-
/<%[~-]?\s*include\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g,
|
|
259
|
-
/<%[~-]?\s*include\s*\(\s*['"`]([^'"`]+)['"`]\s*,/g, // with parameters
|
|
260
|
-
];
|
|
261
|
-
for (const pattern of includePatterns) {
|
|
262
|
-
let match;
|
|
263
|
-
while ((match = pattern.exec(contentWithoutComments)) !== null) {
|
|
264
|
-
const includePath = match[1];
|
|
265
|
-
if (includePath) {
|
|
266
|
-
const resolvedPath = await resolveTemplatePathInternal(includePath, srcDir, templateDir);
|
|
267
|
-
if (resolvedPath) {
|
|
268
|
-
dependencies.push(resolvedPath);
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
// Look for Eta layout/extends patterns: <%~ layout('template') %>
|
|
274
|
-
const layoutPatterns = [
|
|
275
|
-
/<%[~-]?\s*layout\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g,
|
|
276
|
-
/<%[~-]?\s*extends?\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g,
|
|
277
|
-
];
|
|
278
|
-
for (const pattern of layoutPatterns) {
|
|
279
|
-
let match;
|
|
280
|
-
while ((match = pattern.exec(contentWithoutComments)) !== null) {
|
|
281
|
-
const layoutPath = match[1];
|
|
282
|
-
if (layoutPath) {
|
|
283
|
-
const resolvedPath = await resolveTemplatePathInternal(layoutPath, srcDir, templateDir);
|
|
284
|
-
if (resolvedPath) {
|
|
285
|
-
dependencies.push(resolvedPath);
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
// Look for Stati partial patterns - both callable and non-callable
|
|
291
|
-
// Callable: stati.partials.name() or stati.partials['name']()
|
|
292
|
-
// Non-callable: stati.partials.name or stati.partials['name'] (used with <%~ %>)
|
|
293
|
-
const partialPatterns = [
|
|
294
|
-
// Callable patterns (with parentheses)
|
|
295
|
-
/stati\.partials\.(\w+)\s*\(/g, // stati.partials.header(
|
|
296
|
-
/stati\.partials\[['"`]([^'"`]+)['"`]\]\s*\(/g, // stati.partials['header'](
|
|
297
|
-
// Non-callable patterns (without parentheses, used in <%~ stati.partials.name %>)
|
|
298
|
-
// These patterns use lookaheads to distinguish between:
|
|
299
|
-
// - stati.partials.name (partial reference, should match)
|
|
300
|
-
// - stati.partials.name() (function call, should NOT match here - handled above)
|
|
301
|
-
//
|
|
302
|
-
// Pattern breakdown for dot notation: /stati\.partials\.(\w+)(?=\s*[%}\s]|$)(?!\s*\()/g
|
|
303
|
-
// - stati\.partials\. : Literal "stati.partials."
|
|
304
|
-
// - (\w+) : Capture partial name (letters, digits, underscore)
|
|
305
|
-
// - (?=\s*[%}\s]|$) : Positive lookahead - must be followed by whitespace, %, }, or end of string
|
|
306
|
-
// - (?!\s*\() : Negative lookahead - must NOT be followed by "(" (excludes function calls)
|
|
307
|
-
/stati\.partials\.(\w+)(?=\s*[%}\s]|$)(?!\s*\()/g,
|
|
308
|
-
// Pattern breakdown for bracket notation: /stati\.partials\[['"`]([^'"`]+)['"`]\](?=\s*[%}\s]|$)(?!\s*\()/g
|
|
309
|
-
// - stati\.partials\[ : Literal "stati.partials["
|
|
310
|
-
// - ['"`] : Opening quote (single, double, or backtick)
|
|
311
|
-
// - ([^'"`]+) : Capture partial name (any chars except quotes)
|
|
312
|
-
// - ['"`]\] : Closing quote and bracket
|
|
313
|
-
// - (?=\s*[%}\s]|$) : Positive lookahead - must be followed by whitespace, %, }, or end of string
|
|
314
|
-
// - (?!\s*\() : Negative lookahead - must NOT be followed by "(" (excludes function calls)
|
|
315
|
-
/stati\.partials\[['"`]([^'"`]+)['"`]\](?=\s*[%}\s]|$)(?!\s*\()/g,
|
|
316
|
-
];
|
|
317
|
-
// Use a Set to avoid duplicate partial names
|
|
318
|
-
const foundPartials = new Set();
|
|
319
|
-
for (const pattern of partialPatterns) {
|
|
320
|
-
let match;
|
|
321
|
-
while ((match = pattern.exec(contentWithoutComments)) !== null) {
|
|
322
|
-
const partialName = match[1];
|
|
323
|
-
if (partialName) {
|
|
324
|
-
foundPartials.add(partialName);
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
// Resolve each unique partial name
|
|
329
|
-
for (const partialName of foundPartials) {
|
|
330
|
-
const partialFileName = `${partialName}${TEMPLATE_EXTENSION}`;
|
|
331
|
-
const resolvedPath = await resolveTemplatePathInternal(partialFileName, srcDir, templateDir);
|
|
332
|
-
if (resolvedPath) {
|
|
333
|
-
dependencies.push(resolvedPath);
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
return dependencies;
|
|
337
|
-
}
|
|
338
|
-
/**
|
|
339
|
-
* Internal helper to resolve template paths (renamed to avoid naming conflict).
|
|
340
|
-
* Handles relative paths and adds .eta extension if needed.
|
|
341
|
-
*
|
|
342
|
-
* @param templateRef - Template reference from include/layout statement
|
|
343
|
-
* @param srcDir - Source directory for resolving paths
|
|
344
|
-
* @param currentDir - Current directory for hierarchical search (optional)
|
|
345
|
-
* @returns Absolute path to template file, or null if not found
|
|
346
|
-
*/
|
|
347
|
-
async function resolveTemplatePathInternal(templateRef, srcDir, currentDir) {
|
|
348
|
-
// Create cache key from all inputs
|
|
349
|
-
const cacheKey = `${templateRef}|${srcDir}|${currentDir ?? ''}`;
|
|
350
|
-
// Check cache first
|
|
351
|
-
if (templatePathCache.has(cacheKey)) {
|
|
352
|
-
return templatePathCache.get(cacheKey) ?? null;
|
|
353
|
-
}
|
|
354
|
-
const templateName = templateRef.endsWith(TEMPLATE_EXTENSION)
|
|
355
|
-
? templateRef
|
|
356
|
-
: `${templateRef}${TEMPLATE_EXTENSION}`;
|
|
357
|
-
// Try absolute path from srcDir
|
|
358
|
-
const absolutePath = join(srcDir, templateName);
|
|
359
|
-
if (await pathExists(absolutePath)) {
|
|
360
|
-
templatePathCache.set(cacheKey, absolutePath);
|
|
361
|
-
return absolutePath;
|
|
362
|
-
}
|
|
363
|
-
// Determine the starting directory for hierarchical search (relative to srcDir)
|
|
364
|
-
const startDir = currentDir ? relative(srcDir, currentDir) : '';
|
|
365
|
-
// Build list of directories to search (current dir up to srcDir root only)
|
|
366
|
-
// This ensures we never search outside the source directory boundary
|
|
367
|
-
const dirsToSearch = [];
|
|
368
|
-
// Safety check: ensure currentDir is within srcDir (relative path shouldn't start with '..')
|
|
369
|
-
if (startDir.startsWith('..')) {
|
|
370
|
-
// If currentDir is outside srcDir, only search at srcDir root
|
|
371
|
-
dirsToSearch.push('');
|
|
372
|
-
}
|
|
373
|
-
else {
|
|
374
|
-
const pathSegments = startDir === '' ? [] : startDir.split(/[/\\]/);
|
|
375
|
-
// Add directories from current up to srcDir root (don't go beyond srcDir)
|
|
376
|
-
if (pathSegments.length > 0) {
|
|
377
|
-
for (let i = pathSegments.length; i >= 0; i--) {
|
|
378
|
-
if (i === 0) {
|
|
379
|
-
dirsToSearch.push(''); // srcDir root directory
|
|
380
|
-
}
|
|
381
|
-
else {
|
|
382
|
-
dirsToSearch.push(pathSegments.slice(0, i).join('/'));
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
else {
|
|
387
|
-
dirsToSearch.push(''); // srcDir root directory only
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
// Search each directory level for the template in underscore directories
|
|
391
|
-
for (const dir of dirsToSearch) {
|
|
392
|
-
const searchDir = dir ? join(srcDir, dir) : srcDir;
|
|
393
|
-
try {
|
|
394
|
-
// Search for template in underscore directories at this level only
|
|
395
|
-
const pattern = posix.join(searchDir.replace(/\\/g, '/'), '_*', templateName);
|
|
396
|
-
const matches = await glob(pattern, { absolute: true });
|
|
397
|
-
if (matches.length > 0) {
|
|
398
|
-
// Normalize to POSIX format for consistent cross-platform path handling
|
|
399
|
-
const result = matches[0].replace(/\\/g, '/');
|
|
400
|
-
templatePathCache.set(cacheKey, result);
|
|
401
|
-
return result;
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
catch {
|
|
405
|
-
// Continue if directory doesn't exist or can't be read
|
|
406
|
-
continue;
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
templatePathCache.set(cacheKey, null);
|
|
410
|
-
return null;
|
|
19
|
+
return file ? posix.join(index.srcDir.replace(/\\/g, '/'), file) : null;
|
|
411
20
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hash.d.ts","sourceRoot":"","sources":["../../../src/core/isg/hash.ts"],"names":[],"mappings":"AAgCA;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAmBhG;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"hash.d.ts","sourceRoot":"","sources":["../../../src/core/isg/hash.ts"],"names":[],"mappings":"AAgCA;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAmBhG;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA+B9E;AAED;;;;;;;;GAQG;AACH,wBAAsB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAG7E;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,iBAAiB,CAC/B,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,EAAE,EACpB,gBAAgB,CAAC,EAAE,MAAM,GACxB,MAAM,CASR;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,OAAO,EAAE,GAAG,MAAM,CA+CnE"}
|
package/dist/core/isg/hash.js
CHANGED
|
@@ -94,7 +94,8 @@ export async function computeFileHash(filePath) {
|
|
|
94
94
|
return null;
|
|
95
95
|
}
|
|
96
96
|
const content = await readFile(filePath, 'utf-8');
|
|
97
|
-
|
|
97
|
+
// An empty file has a hash too: a page that includes an empty template must stay cached
|
|
98
|
+
if (content === null) {
|
|
98
99
|
fileHashCache.set(normalizedPath, null);
|
|
99
100
|
return null;
|
|
100
101
|
}
|
package/dist/core/isg/index.d.ts
CHANGED
|
@@ -7,12 +7,12 @@
|
|
|
7
7
|
* @module isg
|
|
8
8
|
*/
|
|
9
9
|
export { loadCacheManifest, saveCacheManifest, createEmptyManifest } from './manifest.js';
|
|
10
|
-
export { shouldRebuildPage, createCacheEntry, updateCacheEntry, hasRecordedReads, } from './builder.js';
|
|
10
|
+
export { shouldRebuildPage, createCacheEntry, updateCacheEntry, hasRecordedReads, hasRecordedTemplates, } from './builder.js';
|
|
11
11
|
export type { RenderedAssets } from './builder.js';
|
|
12
12
|
export { pruneOrphanedPages } from './prune.js';
|
|
13
13
|
export { BuildLockManager, withBuildLock } from './build-lock.js';
|
|
14
14
|
export { DevServerLockManager } from './dev-server-lock.js';
|
|
15
|
-
export {
|
|
15
|
+
export { resolveLayoutDependency } from './deps.js';
|
|
16
16
|
export { computeContentHash, computeFileHash, computeBinaryFileHash, computeInputsHash, computeNavigationHash, clearFileHashCache, } from './hash.js';
|
|
17
17
|
export { getSafeCurrentTime, parseSafeDate, computeEffectiveTTL, computeNextRebuildAt, isPageFrozen, applyAgingRules, } from './ttl.js';
|
|
18
18
|
export { ISGConfigurationError, validateISGConfig, validatePageISGOverrides, extractNumericOverride, } from './validation.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/isg/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAG1F,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/isg/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAG1F,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,oBAAoB,GACrB,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAGnD,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAGhD,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAClE,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAG5D,OAAO,EAAE,uBAAuB,EAAE,MAAM,WAAW,CAAC;AAGpD,OAAO,EACL,kBAAkB,EAClB,eAAe,EACf,qBAAqB,EACrB,iBAAiB,EACjB,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,WAAW,CAAC;AAGnB,OAAO,EACL,kBAAkB,EAClB,aAAa,EACb,mBAAmB,EACnB,oBAAoB,EACpB,YAAY,EACZ,eAAe,GAChB,MAAM,UAAU,CAAC;AAGlB,OAAO,EACL,qBAAqB,EACrB,iBAAiB,EACjB,wBAAwB,EACxB,sBAAsB,GACvB,MAAM,iBAAiB,CAAC"}
|
package/dist/core/isg/index.js
CHANGED
|
@@ -9,14 +9,14 @@
|
|
|
9
9
|
// Manifest management
|
|
10
10
|
export { loadCacheManifest, saveCacheManifest, createEmptyManifest } from './manifest.js';
|
|
11
11
|
// Build decision logic
|
|
12
|
-
export { shouldRebuildPage, createCacheEntry, updateCacheEntry, hasRecordedReads, } from './builder.js';
|
|
12
|
+
export { shouldRebuildPage, createCacheEntry, updateCacheEntry, hasRecordedReads, hasRecordedTemplates, } from './builder.js';
|
|
13
13
|
// Removal of pages that no longer exist
|
|
14
14
|
export { pruneOrphanedPages } from './prune.js';
|
|
15
15
|
// Build locking
|
|
16
16
|
export { BuildLockManager, withBuildLock } from './build-lock.js';
|
|
17
17
|
export { DevServerLockManager } from './dev-server-lock.js';
|
|
18
|
-
//
|
|
19
|
-
export {
|
|
18
|
+
// The layout a page renders with; every other template is recorded while it renders
|
|
19
|
+
export { resolveLayoutDependency } from './deps.js';
|
|
20
20
|
// Hash computation
|
|
21
21
|
export { computeContentHash, computeFileHash, computeBinaryFileHash, computeInputsHash, computeNavigationHash, clearFileHashCache, } from './hash.js';
|
|
22
22
|
// TTL and aging
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../../src/core/isg/manifest.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAc,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../../src/core/isg/manifest.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAc,MAAM,sBAAsB,CAAC;AAWtE;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAsGvF;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAyEhG;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,IAAI,aAAa,CAInD"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { readFile, writeFile, pathExists, ensureDir } from '../utils/index.js';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
3
|
import { MANIFEST_FILENAME } from '../../constants.js';
|
|
4
|
+
import { isTemplateLookupList } from '../template-index.js';
|
|
4
5
|
/**
|
|
5
6
|
* Loads the ISG cache manifest from the cache directory.
|
|
6
7
|
* Returns null if no manifest exists or if it's corrupted.
|
|
@@ -237,12 +238,16 @@ function validateCacheEntry(entry, path) {
|
|
|
237
238
|
return false;
|
|
238
239
|
}
|
|
239
240
|
}
|
|
240
|
-
for (const field of ['readsCollection', 'readsNav']) {
|
|
241
|
+
for (const field of ['readsCollection', 'readsNav', 'templatesRecorded']) {
|
|
241
242
|
if (entryObj[field] !== undefined && typeof entryObj[field] !== 'boolean') {
|
|
242
243
|
console.warn(`Invalid cache entry for ${path}: "${field}" must be a boolean if present`);
|
|
243
244
|
return false;
|
|
244
245
|
}
|
|
245
246
|
}
|
|
247
|
+
if (entryObj.templateLookups !== undefined && !isTemplateLookupList(entryObj.templateLookups)) {
|
|
248
|
+
console.warn(`Invalid cache entry for ${path}: "templateLookups" must be a list of { name, from?, file } objects`);
|
|
249
|
+
return false;
|
|
250
|
+
}
|
|
246
251
|
// Validate that deps and tags arrays contain strings
|
|
247
252
|
if (!entryObj.deps.every((dep) => typeof dep === 'string')) {
|
|
248
253
|
console.warn(`Invalid cache entry for ${path}: all "deps" must be strings`);
|
package/dist/core/markdown.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../src/core/markdown.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../src/core/markdown.ts"],"names":[],"mappings":"AACA,OAA8B,EAAE,KAAK,UAAU,EAAc,MAAM,aAAa,CAAC;AAIjF,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAI/D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAEvD;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,gCAAgC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,wDAAwD;IACxD,GAAG,EAAE,QAAQ,EAAE,CAAC;CACjB;AAQD;;;GAGG;AACH,wBAAgB,2BAA2B,IAAI,IAAI,CAElD;AAmBD;;;;GAIG;AACH,wBAAsB,uBAAuB,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CAsDtF;AA6ED;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,GAAG,QAAQ,EAAE,CAGtE;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,qFAAqF;IACrF,MAAM,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC;CACjC;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,MAAM,EACf,EAAE,EAAE,UAAU,EACd,UAAU,GAAE,OAAc,EAC1B,OAAO,GAAE,qBAA0B,GAClC,cAAc,CAkBhB"}
|
package/dist/core/markdown.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
// markdown-it's default export is a value only; the instance type is its named `MarkdownIt` export
|
|
2
|
+
import MarkdownItConstructor from 'markdown-it';
|
|
2
3
|
import { createRequire } from 'node:module';
|
|
3
4
|
import { pathToFileURL } from 'node:url';
|
|
4
5
|
import path from 'node:path';
|
|
@@ -44,7 +45,7 @@ export async function createMarkdownProcessor(config) {
|
|
|
44
45
|
if (isDevelopment() && cachedMarkdownProcessor) {
|
|
45
46
|
return cachedMarkdownProcessor;
|
|
46
47
|
}
|
|
47
|
-
const md = new
|
|
48
|
+
const md = new MarkdownItConstructor({
|
|
48
49
|
html: true,
|
|
49
50
|
linkify: true,
|
|
50
51
|
typographer: true,
|