@stati/core 1.16.3 → 1.18.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/dist/core/build.d.ts +41 -12
- package/dist/core/build.d.ts.map +1 -1
- package/dist/core/build.js +95 -13
- package/dist/core/index.d.ts +1 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/markdown.d.ts +19 -2
- package/dist/core/markdown.d.ts.map +1 -1
- package/dist/core/markdown.js +81 -2
- package/dist/core/templates.d.ts +11 -2
- package/dist/core/templates.d.ts.map +1 -1
- package/dist/core/templates.js +28 -11
- package/dist/core/utils/index.d.ts +1 -0
- package/dist/core/utils/index.d.ts.map +1 -1
- package/dist/core/utils/index.js +2 -0
- package/dist/core/utils/slugify.utils.d.ts +22 -0
- package/dist/core/utils/slugify.utils.d.ts.map +1 -0
- package/dist/core/utils/slugify.utils.js +108 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/metrics/index.d.ts +38 -0
- package/dist/metrics/index.d.ts.map +1 -0
- package/dist/metrics/index.js +42 -0
- package/dist/metrics/noop.d.ts +12 -0
- package/dist/metrics/noop.d.ts.map +1 -0
- package/dist/metrics/noop.js +88 -0
- package/dist/metrics/recorder.d.ts +31 -0
- package/dist/metrics/recorder.d.ts.map +1 -0
- package/dist/metrics/recorder.js +176 -0
- package/dist/metrics/types.d.ts +236 -0
- package/dist/metrics/types.d.ts.map +1 -0
- package/dist/metrics/types.js +7 -0
- package/dist/metrics/utils/index.d.ts +9 -0
- package/dist/metrics/utils/index.d.ts.map +1 -0
- package/dist/metrics/utils/index.js +9 -0
- package/dist/metrics/utils/system.utils.d.ts +44 -0
- package/dist/metrics/utils/system.utils.d.ts.map +1 -0
- package/dist/metrics/utils/system.utils.js +95 -0
- package/dist/metrics/utils/writer.utils.d.ts +64 -0
- package/dist/metrics/utils/writer.utils.d.ts.map +1 -0
- package/dist/metrics/utils/writer.utils.js +145 -0
- package/dist/types/config.d.ts +2 -0
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/content.d.ts +23 -4
- package/dist/types/content.d.ts.map +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/core/build.d.ts
CHANGED
|
@@ -1,7 +1,22 @@
|
|
|
1
1
|
import type { BuildStats, Logger } from '../types/index.js';
|
|
2
|
+
import type { BuildMetrics } from '../metrics/index.js';
|
|
3
|
+
/**
|
|
4
|
+
* Options for metrics collection during builds.
|
|
5
|
+
*/
|
|
6
|
+
export interface MetricsOptions {
|
|
7
|
+
/** Enable metrics collection */
|
|
8
|
+
enabled?: boolean;
|
|
9
|
+
/** Include per-page timing details */
|
|
10
|
+
detailed?: boolean;
|
|
11
|
+
}
|
|
2
12
|
/**
|
|
3
13
|
* Options for customizing the build process.
|
|
4
14
|
*
|
|
15
|
+
* @remarks
|
|
16
|
+
* The `| undefined` on optional properties is intentional due to
|
|
17
|
+
* `exactOptionalPropertyTypes: true` in tsconfig.json, allowing callers
|
|
18
|
+
* to explicitly pass `undefined` values.
|
|
19
|
+
*
|
|
5
20
|
* @example
|
|
6
21
|
* ```typescript
|
|
7
22
|
* const options: BuildOptions = {
|
|
@@ -9,23 +24,33 @@ import type { BuildStats, Logger } from '../types/index.js';
|
|
|
9
24
|
* clean: true, // Clean output directory before build
|
|
10
25
|
* configPath: './custom.config.js', // Custom config file path
|
|
11
26
|
* includeDrafts: true, // Include draft pages in build
|
|
12
|
-
* version: '1.0.0'
|
|
27
|
+
* version: '1.0.0', // Version to display in build messages
|
|
28
|
+
* metrics: { enabled: true, detailed: true } // Enable metrics collection
|
|
13
29
|
* };
|
|
14
30
|
* ```
|
|
15
31
|
*/
|
|
16
32
|
export interface BuildOptions {
|
|
17
33
|
/** Force rebuild of all pages, ignoring cache */
|
|
18
|
-
force?: boolean;
|
|
34
|
+
force?: boolean | undefined;
|
|
19
35
|
/** Clean the output directory before building */
|
|
20
|
-
clean?: boolean;
|
|
36
|
+
clean?: boolean | undefined;
|
|
21
37
|
/** Path to a custom configuration file */
|
|
22
|
-
configPath?: string;
|
|
38
|
+
configPath?: string | undefined;
|
|
23
39
|
/** Include draft pages in the build */
|
|
24
|
-
includeDrafts?: boolean;
|
|
40
|
+
includeDrafts?: boolean | undefined;
|
|
25
41
|
/** Custom logger for build output */
|
|
26
|
-
logger?: Logger;
|
|
42
|
+
logger?: Logger | undefined;
|
|
27
43
|
/** Version information to display in build messages */
|
|
28
|
-
version?: string;
|
|
44
|
+
version?: string | undefined;
|
|
45
|
+
/** Metrics collection options */
|
|
46
|
+
metrics?: MetricsOptions | undefined;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Extended build result including optional metrics.
|
|
50
|
+
*/
|
|
51
|
+
export interface BuildResult extends BuildStats {
|
|
52
|
+
/** Build metrics (only present when metrics enabled) */
|
|
53
|
+
buildMetrics?: BuildMetrics;
|
|
29
54
|
}
|
|
30
55
|
/**
|
|
31
56
|
* Builds the Stati site with ISG support.
|
|
@@ -43,20 +68,24 @@ export interface BuildOptions {
|
|
|
43
68
|
* 5. Update cache manifest
|
|
44
69
|
*
|
|
45
70
|
* @param options - Build configuration options
|
|
46
|
-
* @returns Promise resolving to build statistics
|
|
71
|
+
* @returns Promise resolving to build result with statistics and optional metrics
|
|
47
72
|
* @throws {Error} When configuration is invalid
|
|
48
73
|
* @throws {Error} When template rendering fails
|
|
49
74
|
* @throws {Error} When build lock cannot be acquired
|
|
50
75
|
*
|
|
51
76
|
* @example
|
|
52
77
|
* ```typescript
|
|
53
|
-
* const
|
|
78
|
+
* const result = await build({
|
|
54
79
|
* force: true,
|
|
55
80
|
* clean: true,
|
|
56
|
-
* includeDrafts: false
|
|
81
|
+
* includeDrafts: false,
|
|
82
|
+
* metrics: { enabled: true }
|
|
57
83
|
* });
|
|
58
|
-
* console.log(`Built ${
|
|
84
|
+
* console.log(`Built ${result.totalPages} pages in ${result.buildTimeMs}ms`);
|
|
85
|
+
* if (result.buildMetrics) {
|
|
86
|
+
* console.log(`Cache hit rate: ${result.buildMetrics.isg.cacheHitRate}`);
|
|
87
|
+
* }
|
|
59
88
|
* ```
|
|
60
89
|
*/
|
|
61
|
-
export declare function build(options?: BuildOptions): Promise<
|
|
90
|
+
export declare function build(options?: BuildOptions): Promise<BuildResult>;
|
|
62
91
|
//# sourceMappingURL=build.d.ts.map
|
package/dist/core/build.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/core/build.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/core/build.ts"],"names":[],"mappings":"AAgDA,OAAO,KAAK,EAEV,UAAU,EACV,MAAM,EAMP,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAkB,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGxE;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,gCAAgC;IAChC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,sCAAsC;IACtC,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,WAAW,YAAY;IAC3B,iDAAiD;IACjD,KAAK,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC5B,iDAAiD;IACjD,KAAK,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC5B,0CAA0C;IAC1C,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,uCAAuC;IACvC,aAAa,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACpC,qCAAqC;IACrC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,uDAAuD;IACvD,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,iCAAiC;IACjC,OAAO,CAAC,EAAE,cAAc,GAAG,SAAS,CAAC;CACtC;AAED;;GAEG;AACH,MAAM,WAAW,WAAY,SAAQ,UAAU;IAC7C,wDAAwD;IACxD,YAAY,CAAC,EAAE,YAAY,CAAC;CAC7B;AA4FD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAsB,KAAK,CAAC,OAAO,GAAE,YAAiB,GAAG,OAAO,CAAC,WAAW,CAAC,CAW5E"}
|
package/dist/core/build.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ensureDir, writeFile, remove, pathExists, stat, readdir, copyFile, resolveOutDir, resolveStaticDir, resolveCacheDir, enableInventoryTracking, disableInventoryTracking, clearInventory, writeTailwindClassInventory, getInventorySize, isTailwindUsed, loadPreviousInventory, compileTypeScript, autoInjectBundles, getBundlePathsForPage, } from './utils/index.js';
|
|
2
2
|
import { join, dirname, relative, posix } from 'node:path';
|
|
3
|
+
import { performance } from 'node:perf_hooks';
|
|
3
4
|
import { loadConfig } from '../config/loader.js';
|
|
4
5
|
import { loadContent } from './content.js';
|
|
5
6
|
import { createMarkdownProcessor, renderMarkdown } from './markdown.js';
|
|
@@ -10,6 +11,7 @@ import { generateSitemap, generateRobotsTxtFromConfig, autoInjectSEO, } from '..
|
|
|
10
11
|
import { generateRSSFeeds, validateRSSConfig } from '../rss/index.js';
|
|
11
12
|
import { getEnv } from '../env.js';
|
|
12
13
|
import { DEFAULT_OUT_DIR } from '../constants.js';
|
|
14
|
+
import { createMetricRecorder, noopMetricRecorder } from '../metrics/index.js';
|
|
13
15
|
/**
|
|
14
16
|
* Recursively calculates the total size of a directory in bytes.
|
|
15
17
|
* Used for build statistics.
|
|
@@ -103,19 +105,23 @@ const defaultLogger = {
|
|
|
103
105
|
* 5. Update cache manifest
|
|
104
106
|
*
|
|
105
107
|
* @param options - Build configuration options
|
|
106
|
-
* @returns Promise resolving to build statistics
|
|
108
|
+
* @returns Promise resolving to build result with statistics and optional metrics
|
|
107
109
|
* @throws {Error} When configuration is invalid
|
|
108
110
|
* @throws {Error} When template rendering fails
|
|
109
111
|
* @throws {Error} When build lock cannot be acquired
|
|
110
112
|
*
|
|
111
113
|
* @example
|
|
112
114
|
* ```typescript
|
|
113
|
-
* const
|
|
115
|
+
* const result = await build({
|
|
114
116
|
* force: true,
|
|
115
117
|
* clean: true,
|
|
116
|
-
* includeDrafts: false
|
|
118
|
+
* includeDrafts: false,
|
|
119
|
+
* metrics: { enabled: true }
|
|
117
120
|
* });
|
|
118
|
-
* console.log(`Built ${
|
|
121
|
+
* console.log(`Built ${result.totalPages} pages in ${result.buildTimeMs}ms`);
|
|
122
|
+
* if (result.buildMetrics) {
|
|
123
|
+
* console.log(`Cache hit rate: ${result.buildMetrics.isg.cacheHitRate}`);
|
|
124
|
+
* }
|
|
119
125
|
* ```
|
|
120
126
|
*/
|
|
121
127
|
export async function build(options = {}) {
|
|
@@ -184,14 +190,16 @@ async function loadContentAndBuildNavigation(config, options, logger) {
|
|
|
184
190
|
/**
|
|
185
191
|
* Processes pages with ISG caching logic.
|
|
186
192
|
*/
|
|
187
|
-
async function processPagesWithCache(pages, manifest, config, outDir, md, eta, navigation, buildTime, options, logger, compiledBundles) {
|
|
193
|
+
async function processPagesWithCache(pages, manifest, config, outDir, md, eta, navigation, buildTime, options, logger, compiledBundles, recorder = noopMetricRecorder) {
|
|
188
194
|
let cacheHits = 0;
|
|
189
195
|
let cacheMisses = 0;
|
|
190
196
|
// Build context
|
|
191
197
|
const buildContext = { config, pages };
|
|
192
198
|
// Run beforeAll hook
|
|
193
199
|
if (config.hooks?.beforeAll) {
|
|
200
|
+
const endHookBeforeAll = recorder.startSpan('hookBeforeAllMs');
|
|
194
201
|
await config.hooks.beforeAll(buildContext);
|
|
202
|
+
endHookBeforeAll();
|
|
195
203
|
}
|
|
196
204
|
// Render each page with tree-based progress tracking and ISG
|
|
197
205
|
if (logger.step) {
|
|
@@ -239,22 +247,30 @@ async function processPagesWithCache(pages, manifest, config, outDir, md, eta, n
|
|
|
239
247
|
else {
|
|
240
248
|
logger.processing(`📋 Cached ${page.url}`);
|
|
241
249
|
}
|
|
250
|
+
// Record page timing for cached pages (0ms render time)
|
|
251
|
+
recorder.recordPageTiming(page.url, 0, true);
|
|
242
252
|
continue;
|
|
243
253
|
}
|
|
244
254
|
// Cache miss - need to rebuild
|
|
245
255
|
cacheMisses++;
|
|
246
|
-
const startTime =
|
|
256
|
+
const startTime = performance.now();
|
|
247
257
|
// Run beforeRender hook
|
|
248
258
|
if (config.hooks?.beforeRender) {
|
|
259
|
+
const hookStart = performance.now();
|
|
249
260
|
await config.hooks.beforeRender({ page, config });
|
|
261
|
+
recorder.addToPhase('hookBeforeRenderTotalMs', performance.now() - hookStart);
|
|
250
262
|
}
|
|
251
|
-
// Render markdown to HTML
|
|
252
|
-
const
|
|
263
|
+
// Render markdown to HTML with TOC extraction
|
|
264
|
+
const tocEnabled = config.markdown?.toc !== false;
|
|
265
|
+
const { html: htmlContent, toc } = renderMarkdown(page.content, md, tocEnabled);
|
|
253
266
|
// Compute matched bundle paths for this page
|
|
254
267
|
const bundlePaths = getBundlePathsForPage(page.url, compiledBundles);
|
|
255
268
|
const assets = bundlePaths.length > 0 ? { bundlePaths } : undefined;
|
|
256
269
|
// Render with template
|
|
257
|
-
|
|
270
|
+
const renderResult = await renderPage(page, htmlContent, config, eta, navigation, pages, assets, toc, logger);
|
|
271
|
+
let finalHtml = renderResult.html;
|
|
272
|
+
// Record templates loaded for this page
|
|
273
|
+
recorder.increment('templatesLoaded', renderResult.templatesLoaded);
|
|
258
274
|
// Auto-inject SEO tags if enabled
|
|
259
275
|
if (config.seo?.autoInject !== false) {
|
|
260
276
|
const injectOptions = {
|
|
@@ -273,7 +289,9 @@ async function processPagesWithCache(pages, manifest, config, outDir, md, eta, n
|
|
|
273
289
|
if (shouldAutoInject && assets && assets.bundlePaths.length > 0) {
|
|
274
290
|
finalHtml = autoInjectBundles(finalHtml, assets.bundlePaths);
|
|
275
291
|
}
|
|
276
|
-
const renderTime =
|
|
292
|
+
const renderTime = Math.round(performance.now() - startTime);
|
|
293
|
+
// Record page timing for rendered pages (includes template count)
|
|
294
|
+
recorder.recordPageTiming(page.url, renderTime, false, renderResult.templatesLoaded);
|
|
277
295
|
if (logger.updateTreeNode) {
|
|
278
296
|
logger.updateTreeNode(pageId, 'completed', {
|
|
279
297
|
timing: renderTime,
|
|
@@ -292,7 +310,9 @@ async function processPagesWithCache(pages, manifest, config, outDir, md, eta, n
|
|
|
292
310
|
}
|
|
293
311
|
// Run afterRender hook
|
|
294
312
|
if (config.hooks?.afterRender) {
|
|
313
|
+
const hookStart = performance.now();
|
|
295
314
|
await config.hooks.afterRender({ page, config });
|
|
315
|
+
recorder.addToPhase('hookAfterRenderTotalMs', performance.now() - hookStart);
|
|
296
316
|
}
|
|
297
317
|
}
|
|
298
318
|
// Display final rendering tree and clear it
|
|
@@ -347,11 +367,29 @@ async function generateBuildStats(pages, assetsCount, buildStartTime, outDir, ca
|
|
|
347
367
|
* Separated for cleaner error handling and testing.
|
|
348
368
|
*/
|
|
349
369
|
async function buildInternal(options = {}) {
|
|
370
|
+
// Date.now() is used for user-facing build duration display (wall-clock time, in milliseconds).
|
|
371
|
+
// Note: Date.now() can be affected by system clock changes and is not monotonic.
|
|
372
|
+
// Internal metrics use performance.now() via the MetricRecorder for higher precision and monotonic timing,
|
|
373
|
+
// which is not affected by system clock adjustments.
|
|
350
374
|
const buildStartTime = Date.now();
|
|
351
375
|
const logger = options.logger || defaultLogger;
|
|
376
|
+
// Create metric recorder (noop if disabled)
|
|
377
|
+
const recorder = createMetricRecorder({
|
|
378
|
+
enabled: options.metrics?.enabled,
|
|
379
|
+
detailed: options.metrics?.detailed,
|
|
380
|
+
command: 'build',
|
|
381
|
+
flags: {
|
|
382
|
+
force: options.force,
|
|
383
|
+
clean: options.clean,
|
|
384
|
+
includeDrafts: options.includeDrafts,
|
|
385
|
+
},
|
|
386
|
+
statiVersion: options.version,
|
|
387
|
+
});
|
|
352
388
|
logger.building('Building your site...');
|
|
353
|
-
// Load configuration
|
|
389
|
+
// Load configuration (instrumented)
|
|
390
|
+
const endConfigSpan = recorder.startSpan('configLoadMs');
|
|
354
391
|
const { config, outDir, cacheDir } = await loadAndValidateConfig(options);
|
|
392
|
+
endConfigSpan();
|
|
355
393
|
// Initialize cache stats
|
|
356
394
|
let cacheHits = 0;
|
|
357
395
|
let cacheMisses = 0;
|
|
@@ -384,17 +422,27 @@ async function buildInternal(options = {}) {
|
|
|
384
422
|
}
|
|
385
423
|
}
|
|
386
424
|
// Load cache manifest for ISG (after potential clean operation)
|
|
425
|
+
const endManifestLoadSpan = recorder.startSpan('cacheManifestLoadMs');
|
|
387
426
|
const { manifest } = await setupCacheAndManifest(cacheDir);
|
|
427
|
+
endManifestLoadSpan();
|
|
388
428
|
// Load content and build navigation
|
|
389
429
|
if (logger.step) {
|
|
390
430
|
console.log(); // Add spacing before content loading
|
|
391
431
|
}
|
|
432
|
+
const endContentSpan = recorder.startSpan('contentDiscoveryMs');
|
|
392
433
|
const { pages, navigation, md, eta, navigationHash } = await loadContentAndBuildNavigation(config, options, logger);
|
|
434
|
+
endContentSpan();
|
|
435
|
+
// Record content discovery counts.
|
|
436
|
+
// Both totalPages and markdownFilesProcessed are incremented by pages.length
|
|
437
|
+
// because loadContent() only processes *.md files, so all pages are markdown files.
|
|
438
|
+
recorder.increment('totalPages', pages.length);
|
|
439
|
+
recorder.increment('markdownFilesProcessed', pages.length);
|
|
393
440
|
// Store navigation hash in manifest for change detection in dev server
|
|
394
441
|
manifest.navigationHash = navigationHash;
|
|
395
442
|
// Compile TypeScript if enabled
|
|
396
443
|
let compiledBundles = [];
|
|
397
444
|
if (config.typescript?.enabled) {
|
|
445
|
+
const endTsSpan = recorder.startSpan('typescriptCompileMs');
|
|
398
446
|
compiledBundles = await compileTypeScript({
|
|
399
447
|
projectRoot: process.cwd(),
|
|
400
448
|
config: config.typescript,
|
|
@@ -402,15 +450,21 @@ async function buildInternal(options = {}) {
|
|
|
402
450
|
mode: getEnv() === 'production' ? 'production' : 'development',
|
|
403
451
|
logger,
|
|
404
452
|
});
|
|
453
|
+
endTsSpan();
|
|
405
454
|
}
|
|
406
455
|
// Process pages with ISG caching logic
|
|
407
456
|
if (logger.step) {
|
|
408
457
|
console.log(); // Add spacing before page processing
|
|
409
458
|
}
|
|
459
|
+
const endPageRenderSpan = recorder.startSpan('pageRenderingMs');
|
|
410
460
|
const buildTime = new Date();
|
|
411
|
-
const pageProcessingResult = await processPagesWithCache(pages, manifest, config, outDir, md, eta, navigation, buildTime, options, logger, compiledBundles);
|
|
461
|
+
const pageProcessingResult = await processPagesWithCache(pages, manifest, config, outDir, md, eta, navigation, buildTime, options, logger, compiledBundles, recorder);
|
|
462
|
+
endPageRenderSpan();
|
|
412
463
|
cacheHits = pageProcessingResult.cacheHits;
|
|
413
464
|
cacheMisses = pageProcessingResult.cacheMisses;
|
|
465
|
+
// Record page rendering counts
|
|
466
|
+
recorder.increment('renderedPages', cacheMisses);
|
|
467
|
+
recorder.increment('cachedPages', cacheHits);
|
|
414
468
|
// Write Tailwind class inventory after all templates have been rendered (if Tailwind is used)
|
|
415
469
|
if (hasTailwind) {
|
|
416
470
|
const inventorySize = getInventorySize();
|
|
@@ -423,10 +477,15 @@ async function buildInternal(options = {}) {
|
|
|
423
477
|
disableInventoryTracking();
|
|
424
478
|
}
|
|
425
479
|
// Save updated cache manifest
|
|
480
|
+
const endManifestSaveSpan = recorder.startSpan('cacheManifestSaveMs');
|
|
426
481
|
await saveCacheManifest(cacheDir, manifest);
|
|
482
|
+
endManifestSaveSpan();
|
|
427
483
|
// Copy static assets and count them
|
|
484
|
+
const endAssetSpan = recorder.startSpan('assetCopyMs');
|
|
428
485
|
let assetsCount = 0;
|
|
429
486
|
assetsCount = await copyStaticAssets(config, outDir, logger);
|
|
487
|
+
endAssetSpan();
|
|
488
|
+
recorder.increment('assetsCopied', assetsCount);
|
|
430
489
|
// Get current environment
|
|
431
490
|
const currentEnv = getEnv();
|
|
432
491
|
// Generate sitemap if enabled (only in production mode)
|
|
@@ -435,8 +494,10 @@ async function buildInternal(options = {}) {
|
|
|
435
494
|
console.log(); // Add spacing before sitemap generation
|
|
436
495
|
}
|
|
437
496
|
logger.info('Generating sitemap...');
|
|
497
|
+
const endSitemapSpan = recorder.startSpan('sitemapGenerationMs');
|
|
438
498
|
const sitemapResult = generateSitemap(pages, config, config.sitemap);
|
|
439
499
|
await writeFile(join(outDir, 'sitemap.xml'), sitemapResult.xml);
|
|
500
|
+
endSitemapSpan();
|
|
440
501
|
// Write additional sitemap files if split
|
|
441
502
|
if (sitemapResult.sitemaps) {
|
|
442
503
|
for (const { filename, xml } of sitemapResult.sitemaps) {
|
|
@@ -506,9 +567,30 @@ async function buildInternal(options = {}) {
|
|
|
506
567
|
}
|
|
507
568
|
// Run afterAll hook
|
|
508
569
|
if (config.hooks?.afterAll) {
|
|
570
|
+
const endHookAfterAll = recorder.startSpan('hookAfterAllMs');
|
|
509
571
|
await config.hooks.afterAll({ config, pages });
|
|
572
|
+
endHookAfterAll();
|
|
510
573
|
}
|
|
511
574
|
// Calculate build statistics
|
|
512
575
|
const buildStats = await generateBuildStats(pages, assetsCount, buildStartTime, outDir, cacheHits, cacheMisses, logger);
|
|
513
|
-
|
|
576
|
+
// Set ISG metrics
|
|
577
|
+
const totalPages = pages.length;
|
|
578
|
+
const cacheHitRate = totalPages > 0 ? cacheHits / totalPages : 0;
|
|
579
|
+
recorder.setISGMetrics({
|
|
580
|
+
enabled: config.isg?.enabled !== false,
|
|
581
|
+
cacheHitRate,
|
|
582
|
+
manifestEntries: Object.keys(manifest.entries).length,
|
|
583
|
+
invalidatedEntries: cacheMisses,
|
|
584
|
+
});
|
|
585
|
+
// Take final memory snapshot
|
|
586
|
+
recorder.snapshotMemory();
|
|
587
|
+
// Build result with optional metrics
|
|
588
|
+
const result = {
|
|
589
|
+
...buildStats,
|
|
590
|
+
};
|
|
591
|
+
// Add metrics if enabled
|
|
592
|
+
if (recorder.enabled) {
|
|
593
|
+
result.buildMetrics = recorder.finalize();
|
|
594
|
+
}
|
|
595
|
+
return result;
|
|
514
596
|
}
|
package/dist/core/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Barrel file for all core Stati functionality including build, dev server, preview, and invalidation.
|
|
4
4
|
*/
|
|
5
5
|
export { build } from './build.js';
|
|
6
|
-
export type { BuildOptions } from './build.js';
|
|
6
|
+
export type { BuildOptions, MetricsOptions, BuildResult } from './build.js';
|
|
7
7
|
export { createDevServer } from './dev.js';
|
|
8
8
|
export type { DevServerOptions } from './dev.js';
|
|
9
9
|
export { createPreviewServer } from './preview.js';
|
package/dist/core/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAG5E,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAC3C,YAAY,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAGjD,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACnD,YAAY,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAGzD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,YAAY,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC"}
|
package/dist/core/markdown.d.ts
CHANGED
|
@@ -1,9 +1,26 @@
|
|
|
1
1
|
import MarkdownIt from 'markdown-it';
|
|
2
|
-
import type { StatiConfig } from '../types/index.js';
|
|
2
|
+
import type { StatiConfig, TocEntry } from '../types/index.js';
|
|
3
|
+
/**
|
|
4
|
+
* Result of rendering markdown content.
|
|
5
|
+
*/
|
|
6
|
+
export interface MarkdownResult {
|
|
7
|
+
/** The rendered HTML content */
|
|
8
|
+
html: string;
|
|
9
|
+
/** Table of contents entries extracted from headings */
|
|
10
|
+
toc: TocEntry[];
|
|
11
|
+
}
|
|
3
12
|
/**
|
|
4
13
|
* Creates and configures a MarkdownIt processor based on the provided configuration.
|
|
5
14
|
* Supports both plugin array format and configure function format.
|
|
6
15
|
*/
|
|
7
16
|
export declare function createMarkdownProcessor(config: StatiConfig): Promise<MarkdownIt>;
|
|
8
|
-
|
|
17
|
+
/**
|
|
18
|
+
* Renders markdown content to HTML with optional TOC extraction.
|
|
19
|
+
*
|
|
20
|
+
* @param content - The markdown content to render
|
|
21
|
+
* @param md - The configured MarkdownIt instance
|
|
22
|
+
* @param tocEnabled - Whether to extract TOC and inject heading anchors (default: true)
|
|
23
|
+
* @returns Object containing rendered HTML and TOC entries
|
|
24
|
+
*/
|
|
25
|
+
export declare function renderMarkdown(content: string, md: MarkdownIt, tocEnabled?: boolean): MarkdownResult;
|
|
9
26
|
//# sourceMappingURL=markdown.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../src/core/markdown.ts"],"names":[],"mappings":"AAAA,OAAO,UAAU,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../src/core/markdown.ts"],"names":[],"mappings":"AAAA,OAAO,UAAU,MAAM,aAAa,CAAC;AAKrC,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAG/D;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,gCAAgC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,wDAAwD;IACxD,GAAG,EAAE,QAAQ,EAAE,CAAC;CACjB;AAmBD;;;GAGG;AACH,wBAAsB,uBAAuB,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CAuCtF;AA6ED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,MAAM,EACf,EAAE,EAAE,UAAU,EACd,UAAU,GAAE,OAAc,GACzB,cAAc,CAWhB"}
|
package/dist/core/markdown.js
CHANGED
|
@@ -2,6 +2,7 @@ import MarkdownIt from 'markdown-it';
|
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
3
|
import { pathToFileURL } from 'node:url';
|
|
4
4
|
import path from 'node:path';
|
|
5
|
+
import { slugify } from './utils/index.js';
|
|
5
6
|
/**
|
|
6
7
|
* Load a markdown plugin, trying different resolution strategies
|
|
7
8
|
*/
|
|
@@ -62,6 +63,84 @@ export async function createMarkdownProcessor(config) {
|
|
|
62
63
|
}
|
|
63
64
|
return md;
|
|
64
65
|
}
|
|
65
|
-
|
|
66
|
-
|
|
66
|
+
/**
|
|
67
|
+
* Extracts text content from an inline token, handling nested children.
|
|
68
|
+
* Recursively processes all token types to capture text from links, images,
|
|
69
|
+
* code, and other inline elements.
|
|
70
|
+
*
|
|
71
|
+
* @param token - The inline token to extract text from
|
|
72
|
+
* @returns Plain text content
|
|
73
|
+
*/
|
|
74
|
+
function extractTextFromToken(token) {
|
|
75
|
+
// Handle tokens with children by recursively extracting from all children
|
|
76
|
+
if (token.children && token.children.length > 0) {
|
|
77
|
+
return token.children.map((child) => extractTextFromToken(child)).join('');
|
|
78
|
+
}
|
|
79
|
+
// For leaf tokens, return their content
|
|
80
|
+
// This handles 'text', 'code_inline', and other inline token types
|
|
81
|
+
return token.content || '';
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Extracts TOC entries from tokens and injects anchor IDs into heading tokens.
|
|
85
|
+
*
|
|
86
|
+
* @param tokens - The parsed markdown tokens
|
|
87
|
+
* @param tocEnabled - Whether TOC extraction is enabled
|
|
88
|
+
* @returns Array of TOC entries
|
|
89
|
+
*/
|
|
90
|
+
function extractAndInjectAnchors(tokens, tocEnabled) {
|
|
91
|
+
if (!tocEnabled) {
|
|
92
|
+
return [];
|
|
93
|
+
}
|
|
94
|
+
const toc = [];
|
|
95
|
+
const usedIds = new Map();
|
|
96
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
97
|
+
const token = tokens[i];
|
|
98
|
+
if (!token)
|
|
99
|
+
continue;
|
|
100
|
+
if (token.type === 'heading_open') {
|
|
101
|
+
// Extract level from tag (h1, h2, etc.)
|
|
102
|
+
const level = parseInt(token.tag.slice(1), 10);
|
|
103
|
+
// Only include levels 2-6 in TOC (skip h1)
|
|
104
|
+
if (level >= 2 && level <= 6) {
|
|
105
|
+
// Get the inline token that follows (contains heading text)
|
|
106
|
+
const inlineToken = tokens[i + 1];
|
|
107
|
+
if (inlineToken && inlineToken.type === 'inline') {
|
|
108
|
+
const text = extractTextFromToken(inlineToken);
|
|
109
|
+
let baseId = slugify(text);
|
|
110
|
+
// Fallback for empty slugs (e.g., headings with only emojis or special characters)
|
|
111
|
+
if (!baseId) {
|
|
112
|
+
baseId = 'heading';
|
|
113
|
+
}
|
|
114
|
+
// Handle duplicate IDs
|
|
115
|
+
let id = baseId;
|
|
116
|
+
const count = usedIds.get(baseId) || 0;
|
|
117
|
+
if (count > 0) {
|
|
118
|
+
id = `${baseId}-${count}`;
|
|
119
|
+
}
|
|
120
|
+
usedIds.set(baseId, count + 1);
|
|
121
|
+
// Inject the id attribute into the heading_open token
|
|
122
|
+
token.attrSet('id', id);
|
|
123
|
+
toc.push({ id, text, level });
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return toc;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Renders markdown content to HTML with optional TOC extraction.
|
|
132
|
+
*
|
|
133
|
+
* @param content - The markdown content to render
|
|
134
|
+
* @param md - The configured MarkdownIt instance
|
|
135
|
+
* @param tocEnabled - Whether to extract TOC and inject heading anchors (default: true)
|
|
136
|
+
* @returns Object containing rendered HTML and TOC entries
|
|
137
|
+
*/
|
|
138
|
+
export function renderMarkdown(content, md, tocEnabled = true) {
|
|
139
|
+
// Parse content into tokens
|
|
140
|
+
const tokens = md.parse(content, {});
|
|
141
|
+
// Extract TOC and inject anchor IDs
|
|
142
|
+
const toc = extractAndInjectAnchors(tokens, tocEnabled);
|
|
143
|
+
// Render tokens to HTML
|
|
144
|
+
const html = md.renderer.render(tokens, md.options, {});
|
|
145
|
+
return { html, toc };
|
|
67
146
|
}
|
package/dist/core/templates.d.ts
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
import { Eta } from 'eta';
|
|
2
|
-
import type { StatiConfig, PageModel, NavNode } from '../types/index.js';
|
|
2
|
+
import type { StatiConfig, PageModel, NavNode, TocEntry, Logger } from '../types/index.js';
|
|
3
|
+
/**
|
|
4
|
+
* Result of rendering a page template.
|
|
5
|
+
*/
|
|
6
|
+
export interface RenderResult {
|
|
7
|
+
/** The rendered HTML content */
|
|
8
|
+
html: string;
|
|
9
|
+
/** Number of templates loaded (layout + partials) */
|
|
10
|
+
templatesLoaded: number;
|
|
11
|
+
}
|
|
3
12
|
export declare function createTemplateEngine(config: StatiConfig): Eta;
|
|
4
|
-
export declare function renderPage(page: PageModel, body: string, config: StatiConfig, eta: Eta, navigation?: NavNode[], allPages?: PageModel[], assets?: import('../types/index.js').StatiAssets): Promise<
|
|
13
|
+
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>;
|
|
5
14
|
//# 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,
|
|
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;AAkB3B;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,gCAAgC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,qDAAqD;IACrD,eAAe,EAAE,MAAM,CAAC;CACzB;AAoMD,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,WAAW,GAAG,GAAG,CAW7D;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,GACd,OAAO,CAAC,YAAY,CAAC,CAuMvB"}
|
package/dist/core/templates.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Eta } from 'eta';
|
|
2
2
|
import { join, dirname, relative, basename, posix } from 'node:path';
|
|
3
3
|
import glob from 'fast-glob';
|
|
4
|
+
import { createFallbackLogger } from './utils/index.js';
|
|
4
5
|
import { TEMPLATE_EXTENSION } from '../constants.js';
|
|
5
6
|
import { getStatiVersion, isCollectionIndexPage, discoverLayout, getCollectionPathForPage, resolveSrcDir, createTemplateError, createValidatingPartialsProxy, propValue, wrapPartialsAsCallable, createNavigationHelpers, } from './utils/index.js';
|
|
6
7
|
import { getEnv } from '../env.js';
|
|
@@ -182,11 +183,14 @@ export function createTemplateEngine(config) {
|
|
|
182
183
|
});
|
|
183
184
|
return eta;
|
|
184
185
|
}
|
|
185
|
-
export async function renderPage(page, body, config, eta, navigation, allPages, assets) {
|
|
186
|
+
export async function renderPage(page, body, config, eta, navigation, allPages, assets, toc, logger) {
|
|
187
|
+
const log = logger || createFallbackLogger();
|
|
186
188
|
// Discover partials for this page's directory hierarchy
|
|
187
189
|
const srcDir = resolveSrcDir(config);
|
|
188
190
|
const relativePath = relative(srcDir, page.sourcePath);
|
|
189
191
|
const partialPaths = await discoverPartials(relativePath, config);
|
|
192
|
+
// Count templates: partials + layout (if found)
|
|
193
|
+
const partialsCount = Object.keys(partialPaths).length;
|
|
190
194
|
// Build collection data based on page type
|
|
191
195
|
let collectionData;
|
|
192
196
|
const isIndexPage = allPages && isCollectionIndexPage(page, allPages);
|
|
@@ -203,19 +207,31 @@ export async function renderPage(page, body, config, eta, navigation, allPages,
|
|
|
203
207
|
// Discover the appropriate layout using hierarchical layout.eta convention
|
|
204
208
|
// Pass isIndexPage flag to enable index.eta lookup for aggregation pages
|
|
205
209
|
const layoutPath = await discoverLayout(relativePath, config, page.frontMatter.layout, isIndexPage);
|
|
210
|
+
// Calculate total templates loaded (partials + layout if present)
|
|
211
|
+
const templatesLoaded = partialsCount + (layoutPath ? 1 : 0);
|
|
206
212
|
// Create navigation helpers
|
|
207
213
|
const navTree = navigation || [];
|
|
208
214
|
const navHelpers = createNavigationHelpers(navTree, page);
|
|
209
215
|
const currentNavNode = navHelpers.getCurrentNode();
|
|
216
|
+
// Define page-specific properties that override frontmatter
|
|
217
|
+
const pageOverrides = {
|
|
218
|
+
path: page.url,
|
|
219
|
+
url: page.url, // Add url property for compatibility
|
|
220
|
+
content: body,
|
|
221
|
+
navNode: currentNavNode, // Add current page's navigation node
|
|
222
|
+
toc: toc || [], // Table of contents entries extracted from markdown headings
|
|
223
|
+
};
|
|
224
|
+
// Check for frontmatter keys that conflict with reserved page properties
|
|
225
|
+
const conflictingKeys = Object.keys(pageOverrides).filter((key) => key in page.frontMatter);
|
|
226
|
+
if (conflictingKeys.length > 0) {
|
|
227
|
+
log.warning(`Frontmatter in "${page.sourcePath}" contains reserved keys that will be overwritten: ${conflictingKeys.join(', ')}`);
|
|
228
|
+
}
|
|
210
229
|
// Create base context for partial rendering
|
|
211
230
|
const baseContext = {
|
|
212
231
|
site: config.site,
|
|
213
232
|
page: {
|
|
214
233
|
...page.frontMatter,
|
|
215
|
-
|
|
216
|
-
url: page.url, // Add url property for compatibility
|
|
217
|
-
content: body,
|
|
218
|
-
navNode: currentNavNode, // Add current page's navigation node
|
|
234
|
+
...pageOverrides,
|
|
219
235
|
},
|
|
220
236
|
content: body,
|
|
221
237
|
nav: navHelpers, // Replace navigation with nav helpers
|
|
@@ -260,7 +276,7 @@ export async function renderPage(page, body, config, eta, navigation, allPages,
|
|
|
260
276
|
catch (error) {
|
|
261
277
|
// If this is the last pass, log the error and create placeholder
|
|
262
278
|
if (pass === maxPasses - 1) {
|
|
263
|
-
|
|
279
|
+
log.warning(`Failed to render partial ${partialName} at ${partialPath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
264
280
|
// In development mode, throw enhanced template error for partials too
|
|
265
281
|
if (getEnv() === 'development') {
|
|
266
282
|
const templateError = createTemplateError(error instanceof Error ? error : new Error(String(error)), partialPath);
|
|
@@ -302,19 +318,20 @@ export async function renderPage(page, body, config, eta, navigation, allPages,
|
|
|
302
318
|
};
|
|
303
319
|
try {
|
|
304
320
|
if (!layoutPath) {
|
|
305
|
-
|
|
306
|
-
return createFallbackHtml(page, body);
|
|
321
|
+
log.warning('No layout template found, using fallback');
|
|
322
|
+
return { html: createFallbackHtml(page, body), templatesLoaded };
|
|
307
323
|
}
|
|
308
|
-
|
|
324
|
+
const html = await eta.renderAsync(layoutPath, context);
|
|
325
|
+
return { html, templatesLoaded };
|
|
309
326
|
}
|
|
310
327
|
catch (error) {
|
|
311
|
-
|
|
328
|
+
log.error(`Error rendering layout ${layoutPath || 'unknown'}: ${error instanceof Error ? error.message : String(error)}`);
|
|
312
329
|
// In development mode, throw enhanced template error for better debugging
|
|
313
330
|
if (getEnv() === 'development') {
|
|
314
331
|
const templateError = createTemplateError(error instanceof Error ? error : new Error(String(error)), layoutPath || undefined);
|
|
315
332
|
throw templateError;
|
|
316
333
|
}
|
|
317
|
-
return createFallbackHtml(page, body);
|
|
334
|
+
return { html: createFallbackHtml(page, body), templatesLoaded };
|
|
318
335
|
}
|
|
319
336
|
}
|
|
320
337
|
function createFallbackHtml(page, body) {
|
|
@@ -6,6 +6,7 @@ export { readFile, writeFile, pathExists, ensureDir, remove, copyFile, readdir,
|
|
|
6
6
|
export { resolveSrcDir, resolveOutDir, resolveStaticDir, resolveCacheDir, resolveDevPaths, normalizeTemplatePath, resolveSrcPath, resolveOutPath, resolveStaticPath, } from './paths.utils.js';
|
|
7
7
|
export { discoverLayout, isCollectionIndexPage, getCollectionPathForPage, } from './template-discovery.utils.js';
|
|
8
8
|
export { propValue } from './template.utils.js';
|
|
9
|
+
export { slugify } from './slugify.utils.js';
|
|
9
10
|
export { trackTailwindClass, enableInventoryTracking, disableInventoryTracking, clearInventory, getInventory, getInventorySize, isTrackingEnabled, writeTailwindClassInventory, isTailwindUsed, resetTailwindDetection, loadPreviousInventory, } from './tailwind-inventory.utils.js';
|
|
10
11
|
export { createValidatingPartialsProxy } from './partial-validation.utils.js';
|
|
11
12
|
export { makeCallablePartial, wrapPartialsAsCallable } from './callable-partials.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,GACL,MAAM,eAAe,CAAC;AAGvB,OAAO,EACL,aAAa,EACb,aAAa,EACb,gBAAgB,EAChB,eAAe,EACf,eAAe,EACf,qBAAqB,EACrB,cAAc,EACd,cAAc,EACd,iBAAiB,GAClB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EACL,cAAc,EACd,qBAAqB,EACrB,wBAAwB,GACzB,MAAM,+BAA+B,CAAC;AAGvC,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAGhD,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,6BAA6B,EAAE,MAAM,+BAA+B,CAAC;AAG9E,OAAO,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AAC3F,YAAY,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAGpE,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAG/F,OAAO,EAAE,uBAAuB,EAAE,MAAM,+BAA+B,CAAC;AAGxE,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACzE,YAAY,EACV,eAAe,EACf,mBAAmB,EACnB,wBAAwB,GACzB,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,GAClB,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC"}
|
|
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,GACL,MAAM,eAAe,CAAC;AAGvB,OAAO,EACL,aAAa,EACb,aAAa,EACb,gBAAgB,EAChB,eAAe,EACf,eAAe,EACf,qBAAqB,EACrB,cAAc,EACd,cAAc,EACd,iBAAiB,GAClB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EACL,cAAc,EACd,qBAAqB,EACrB,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,6BAA6B,EAAE,MAAM,+BAA+B,CAAC;AAG9E,OAAO,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AAC3F,YAAY,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAGpE,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAG/F,OAAO,EAAE,uBAAuB,EAAE,MAAM,+BAA+B,CAAC;AAGxE,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACzE,YAAY,EACV,eAAe,EACf,mBAAmB,EACnB,wBAAwB,GACzB,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,GAClB,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC"}
|
package/dist/core/utils/index.js
CHANGED
|
@@ -10,6 +10,8 @@ export { resolveSrcDir, resolveOutDir, resolveStaticDir, resolveCacheDir, resolv
|
|
|
10
10
|
export { discoverLayout, isCollectionIndexPage, getCollectionPathForPage, } from './template-discovery.utils.js';
|
|
11
11
|
// Template utilities
|
|
12
12
|
export { propValue } from './template.utils.js';
|
|
13
|
+
// Slugify utilities
|
|
14
|
+
export { slugify } from './slugify.utils.js';
|
|
13
15
|
// Tailwind inventory utilities
|
|
14
16
|
export { trackTailwindClass, enableInventoryTracking, disableInventoryTracking, clearInventory, getInventory, getInventorySize, isTrackingEnabled, writeTailwindClassInventory, isTailwindUsed, resetTailwindDetection, loadPreviousInventory, } from './tailwind-inventory.utils.js';
|
|
15
17
|
// Partial validation utilities
|