@stati/core 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,205 @@
1
+ # @stati/core
2
+
3
+ The core engine for Stati, a lightweight TypeScript static site generator built with Vite-inspired architecture.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @stati/core
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ### Basic Setup
14
+
15
+ ```typescript
16
+ import { build, createDevServer, defineConfig } from '@stati/core';
17
+
18
+ // Define configuration
19
+ const config = defineConfig({
20
+ site: './site',
21
+ output: './dist',
22
+ public: './public',
23
+ });
24
+
25
+ // Build site
26
+ await build(config);
27
+
28
+ // Or start development server
29
+ const server = await createDevServer(config, {
30
+ port: 3000,
31
+ open: true,
32
+ });
33
+ ```
34
+
35
+ ### Configuration
36
+
37
+ ```typescript
38
+ import { defineConfig } from '@stati/core/config';
39
+
40
+ export default defineConfig({
41
+ // Site source directory
42
+ site: './site',
43
+
44
+ // Output directory for built site
45
+ output: './dist',
46
+
47
+ // Static assets directory
48
+ public: './public',
49
+
50
+ // Site metadata
51
+ meta: {
52
+ title: 'My Site',
53
+ description: 'A great static site',
54
+ url: 'https://example.com',
55
+ },
56
+
57
+ // Markdown configuration
58
+ markdown: {
59
+ plugins: ['markdown-it-anchor'],
60
+ options: {
61
+ html: true,
62
+ linkify: true,
63
+ typographer: true,
64
+ },
65
+ },
66
+
67
+ // Template configuration
68
+ templates: {
69
+ engine: 'eta',
70
+ options: {
71
+ views: './site',
72
+ cache: true,
73
+ },
74
+ },
75
+ });
76
+ ```
77
+
78
+ ## API
79
+
80
+ ### Core Functions
81
+
82
+ #### `build(options: BuildOptions): Promise<void>`
83
+
84
+ Build a static site.
85
+
86
+ ```typescript
87
+ import { build } from '@stati/core';
88
+
89
+ await build({
90
+ config: './stati.config.js',
91
+ force: false,
92
+ clean: false,
93
+ includeDrafts: false,
94
+ });
95
+ ```
96
+
97
+ #### `createDevServer(config: StatiConfig, options: DevServerOptions): Promise<DevServer>`
98
+
99
+ Create a development server with live reload.
100
+
101
+ ```typescript
102
+ import { createDevServer } from '@stati/core';
103
+
104
+ const server = await createDevServer(config, {
105
+ port: 3000,
106
+ open: true,
107
+ });
108
+ ```
109
+
110
+ #### `invalidate(options: InvalidateOptions): Promise<void>`
111
+
112
+ Invalidate cache by tags or paths.
113
+
114
+ ```typescript
115
+ import { invalidate } from '@stati/core';
116
+
117
+ await invalidate({
118
+ tags: ['blog', 'posts'],
119
+ paths: ['/blog', '/about'],
120
+ config: './stati.config.js',
121
+ });
122
+ ```
123
+
124
+ ### Configuration
125
+
126
+ #### `defineConfig(config: StatiConfig): StatiConfig`
127
+
128
+ Define a type-safe configuration with full TypeScript support.
129
+
130
+ ```typescript
131
+ import { defineConfig } from '@stati/core/config';
132
+
133
+ export default defineConfig({
134
+ // Your configuration here
135
+ });
136
+ ```
137
+
138
+ ## Types
139
+
140
+ The package exports comprehensive TypeScript types:
141
+
142
+ ```typescript
143
+ import type {
144
+ StatiConfig,
145
+ BuildOptions,
146
+ DevServerOptions,
147
+ InvalidateOptions,
148
+ Page,
149
+ Navigation,
150
+ MarkdownOptions,
151
+ TemplateOptions,
152
+ } from '@stati/core/types';
153
+ ```
154
+
155
+ ## Features
156
+
157
+ ### Markdown Processing
158
+
159
+ - **Front-matter support** with YAML, TOML, or JSON
160
+ - **Plugin system** using markdown-it ecosystem
161
+ - **Custom rendering** with configurable options
162
+ - **Draft pages** with `draft: true` in front-matter
163
+
164
+ ### Template Engine
165
+
166
+ - **Eta templates** with layouts and partials
167
+ - **Template inheritance** with `layout` front-matter property
168
+ - **Custom helpers** and filters
169
+ - **Hot reload** during development
170
+
171
+ ### Navigation System
172
+
173
+ - **Automatic hierarchy** based on filesystem structure
174
+ - **Breadcrumbs** and navigation trees
175
+ - **Custom sorting** with `order` front-matter property
176
+ - **Index pages** with special handling
177
+
178
+ ### Development Server
179
+
180
+ - **Live reload** with WebSocket integration
181
+ - **Hot rebuilding** on file changes
182
+ - **Static asset serving** from public directory
183
+ - **Error overlay** for development debugging
184
+
185
+ ### Caching & Performance
186
+
187
+ - **Smart caching** based on file modification times
188
+ - **Incremental builds** for faster rebuilds
189
+ - **Tag-based invalidation** for selective cache clearing
190
+ - **Memory optimization** for large sites
191
+
192
+ ## Architecture
193
+
194
+ Stati Core is built with a modular architecture:
195
+
196
+ - **Content processing** - Markdown parsing and front-matter extraction
197
+ - **Template rendering** - Eta engine with layouts and partials
198
+ - **Navigation building** - Automatic hierarchy generation
199
+ - **Asset handling** - Static file copying and optimization
200
+ - **Development server** - Live reload and hot rebuilding
201
+ - **Build system** - Production optimization and output generation
202
+
203
+ ## License
204
+
205
+ MIT
@@ -1,4 +1,4 @@
1
- import type { BuildStats } from '../types.js';
1
+ import type { BuildStats, Logger } from '../types.js';
2
2
  /**
3
3
  * Options for customizing the build process.
4
4
  *
@@ -8,7 +8,8 @@ import type { BuildStats } from '../types.js';
8
8
  * force: true, // Force rebuild of all pages
9
9
  * clean: true, // Clean output directory before build
10
10
  * configPath: './custom.config.js', // Custom config file path
11
- * includeDrafts: true // Include draft pages in build
11
+ * includeDrafts: true, // Include draft pages in build
12
+ * version: '1.0.0' // Version to display in build messages
12
13
  * };
13
14
  * ```
14
15
  */
@@ -21,6 +22,10 @@ export interface BuildOptions {
21
22
  configPath?: string;
22
23
  /** Include draft pages in the build */
23
24
  includeDrafts?: boolean;
25
+ /** Custom logger for build output */
26
+ logger?: Logger;
27
+ /** Version information to display in build messages */
28
+ version?: string;
24
29
  }
25
30
  /**
26
31
  * Builds the static site by processing content files and generating HTML pages.
@@ -1 +1 @@
1
- {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/core/build.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAgB,UAAU,EAAE,MAAM,aAAa,CAAC;AAE5D;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,YAAY;IAC3B,iDAAiD;IACjD,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,iDAAiD;IACjD,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,0CAA0C;IAC1C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,uCAAuC;IACvC,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAoFD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAsB,KAAK,CAAC,OAAO,GAAE,YAAiB,GAAG,OAAO,CAAC,UAAU,CAAC,CAyG3E"}
1
+ {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/core/build.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAgB,UAAU,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAEpE;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,YAAY;IAC3B,iDAAiD;IACjD,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,iDAAiD;IACjD,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,0CAA0C;IAC1C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,uCAAuC;IACvC,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,qCAAqC;IACrC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,uDAAuD;IACvD,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AA2HD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAsB,KAAK,CAAC,OAAO,GAAE,YAAiB,GAAG,OAAO,CAAC,UAAU,CAAC,CAwI3E"}
@@ -1,5 +1,5 @@
1
1
  import fse from 'fs-extra';
2
- const { ensureDir, writeFile, copy, remove, pathExists, stat, readdir } = fse;
2
+ const { ensureDir, writeFile, remove, pathExists, stat, readdir, copyFile } = fse;
3
3
  import { join, dirname } from 'path';
4
4
  import { loadConfig } from '../config/loader.js';
5
5
  import { loadContent } from './content.js';
@@ -32,31 +32,59 @@ async function getDirectorySize(dirPath) {
32
32
  return totalSize;
33
33
  }
34
34
  /**
35
- * Counts the number of files in a directory recursively.
36
- * Used for build statistics.
35
+ * Recursively copies static assets from source to destination directory
36
+ * while logging each file being copied.
37
37
  *
38
- * @param dirPath - Path to the directory
39
- * @returns Total number of files
38
+ * @param sourceDir - Source directory containing static assets
39
+ * @param destDir - Destination directory to copy assets to
40
+ * @param logger - Logger instance for output
41
+ * @param basePath - Base path for relative path calculation (for recursion)
42
+ * @returns Total number of files copied
40
43
  */
41
- async function countFilesInDirectory(dirPath) {
42
- if (!(await pathExists(dirPath))) {
44
+ async function copyStaticAssetsWithLogging(sourceDir, destDir, logger, basePath = '') {
45
+ let filesCopied = 0;
46
+ if (!(await pathExists(sourceDir))) {
43
47
  return 0;
44
48
  }
45
- let fileCount = 0;
46
- const items = await readdir(dirPath, { withFileTypes: true });
49
+ const items = await readdir(sourceDir, { withFileTypes: true });
47
50
  for (const item of items) {
48
- const itemPath = join(dirPath, item.name);
51
+ const sourcePath = join(sourceDir, item.name);
52
+ const destPath = join(destDir, basePath, item.name);
53
+ const relativePath = join(basePath, item.name).replace(/\\/g, '/');
49
54
  if (item.isDirectory()) {
50
- fileCount += await countFilesInDirectory(itemPath);
55
+ // Recursively copy directories
56
+ await ensureDir(destPath);
57
+ filesCopied += await copyStaticAssetsWithLogging(sourcePath, destPath, logger, relativePath);
51
58
  }
52
59
  else {
53
- fileCount++;
60
+ // Copy individual files
61
+ await ensureDir(dirname(destPath));
62
+ await copyFile(sourcePath, destPath);
63
+ if (logger.file) {
64
+ logger.file('copy', relativePath);
65
+ }
66
+ else {
67
+ logger.processing(`📄 ${relativePath}`);
68
+ }
69
+ filesCopied++;
54
70
  }
55
71
  }
56
- return fileCount;
72
+ return filesCopied;
57
73
  }
58
74
  /**
59
- * Formats build statistics for display.
75
+ * Default console logger implementation.
76
+ */
77
+ const defaultLogger = {
78
+ info: (message) => console.log(message),
79
+ success: (message) => console.log(message),
80
+ warning: (message) => console.warn(message),
81
+ error: (message) => console.error(message),
82
+ building: (message) => console.log(message),
83
+ processing: (message) => console.log(message),
84
+ stats: (message) => console.log(message),
85
+ };
86
+ /**
87
+ * Formats build statistics for display with prettier output.
60
88
  *
61
89
  * @param stats - Build statistics to format
62
90
  * @returns Formatted statistics string
@@ -65,16 +93,18 @@ function formatBuildStats(stats) {
65
93
  const sizeKB = (stats.outputSizeBytes / 1024).toFixed(1);
66
94
  const timeSeconds = (stats.buildTimeMs / 1000).toFixed(2);
67
95
  let output = `📊 Build Statistics:
68
- ⏱️ Build time: ${timeSeconds}s
69
- 📄 Pages built: ${stats.totalPages}
70
- 📦 Assets copied: ${stats.assetsCount}
71
- 💾 Output size: ${sizeKB} KB`;
96
+ ┌─────────────────────────────────────────┐
97
+ ⏱️ Build time: ${timeSeconds}s`.padEnd(41) + '│';
98
+ output += `\n│ 📄 Pages built: ${stats.totalPages}`.padEnd(42) + '│';
99
+ output += `\n│ 📦 Assets copied: ${stats.assetsCount}`.padEnd(42) + '│';
100
+ output += `\n│ 💾 Output size: ${sizeKB} KB`.padEnd(42) + '│';
72
101
  if (stats.cacheHits !== undefined && stats.cacheMisses !== undefined) {
73
102
  const totalCacheRequests = stats.cacheHits + stats.cacheMisses;
74
103
  const hitRate = totalCacheRequests > 0 ? ((stats.cacheHits / totalCacheRequests) * 100).toFixed(1) : '0';
75
- output += `
76
- 🎯 Cache hits: ${stats.cacheHits}/${totalCacheRequests} (${hitRate}%)`;
104
+ output +=
105
+ `\n│ 🎯 Cache hits: ${stats.cacheHits}/${totalCacheRequests} (${hitRate}%)`.padEnd(42) + '│';
77
106
  }
107
+ output += '\n└─────────────────────────────────────────┘';
78
108
  return output;
79
109
  }
80
110
  /**
@@ -104,7 +134,9 @@ function formatBuildStats(stats) {
104
134
  */
105
135
  export async function build(options = {}) {
106
136
  const buildStartTime = Date.now();
107
- console.log('🏗️ Building site...');
137
+ const logger = options.logger || defaultLogger;
138
+ logger.building('Building your site...');
139
+ console.log(); // Add spacing after build start
108
140
  // Load configuration
109
141
  const config = await loadConfig(options.configPath ? dirname(options.configPath) : process.cwd());
110
142
  const outDir = join(process.cwd(), config.outDir);
@@ -113,17 +145,24 @@ export async function build(options = {}) {
113
145
  await ensureDir(cacheDir);
114
146
  // Clean output directory if requested
115
147
  if (options.clean) {
116
- console.log('🧹 Cleaning output directory...');
148
+ logger.info('🧹 Cleaning output directory...');
117
149
  await remove(outDir);
118
150
  }
119
151
  await ensureDir(outDir);
120
152
  // Load all content
121
153
  const pages = await loadContent(config, options.includeDrafts);
122
- console.log(`📄 Found ${pages.length} pages`);
154
+ logger.info(`📄 Found ${pages.length} pages`);
123
155
  // Build navigation from pages
156
+ console.log(); // Add spacing before navigation step
157
+ if (logger.step) {
158
+ logger.step(1, 3, 'Building navigation');
159
+ }
124
160
  const navigation = buildNavigation(pages);
125
- console.log(`🧭 Built navigation with ${navigation.length} top-level items`);
126
- // Create processors
161
+ logger.info(`🧭 Built navigation with ${navigation.length} top-level items`);
162
+ // Display navigation tree if the logger supports it
163
+ if (logger.navigationTree) {
164
+ logger.navigationTree(navigation);
165
+ } // Create processors
127
166
  const md = await createMarkdownProcessor(config);
128
167
  const eta = createTemplateEngine(config);
129
168
  // Build context
@@ -132,9 +171,21 @@ export async function build(options = {}) {
132
171
  if (config.hooks?.beforeAll) {
133
172
  await config.hooks.beforeAll(buildContext);
134
173
  }
135
- // Render each page
136
- for (const page of pages) {
137
- console.log(` Building ${page.url}`);
174
+ // Render each page with progress tracking
175
+ if (logger.step) {
176
+ logger.step(2, 3, 'Rendering pages');
177
+ }
178
+ for (let i = 0; i < pages.length; i++) {
179
+ const page = pages[i];
180
+ if (!page)
181
+ continue; // Safety check
182
+ // Show progress for page rendering
183
+ if (logger.progress) {
184
+ logger.progress(i + 1, pages.length, `Rendering ${page.url}`);
185
+ }
186
+ else {
187
+ logger.processing(`Building ${page.url}`);
188
+ }
138
189
  // Run beforeRender hook
139
190
  if (config.hooks?.beforeRender) {
140
191
  await config.hooks.beforeRender({ page, config });
@@ -166,9 +217,13 @@ export async function build(options = {}) {
166
217
  let assetsCount = 0;
167
218
  const staticDir = join(process.cwd(), config.staticDir);
168
219
  if (await pathExists(staticDir)) {
169
- await copy(staticDir, outDir, { overwrite: true });
170
- assetsCount = await countFilesInDirectory(staticDir);
171
- console.log(`📦 Copied ${assetsCount} static assets`);
220
+ console.log(); // Add spacing before asset copying
221
+ if (logger.step) {
222
+ logger.step(3, 3, 'Copying static assets');
223
+ }
224
+ logger.info(`📦 Copying static assets from ${config.staticDir}`);
225
+ assetsCount = await copyStaticAssetsWithLogging(staticDir, outDir, logger);
226
+ logger.info(`📦 Copied ${assetsCount} static assets`);
172
227
  }
173
228
  // Run afterAll hook
174
229
  if (config.hooks?.afterAll) {
@@ -185,7 +240,13 @@ export async function build(options = {}) {
185
240
  cacheHits: 0,
186
241
  cacheMisses: 0,
187
242
  };
188
- console.log('✅ Build complete!');
189
- console.log(formatBuildStats(buildStats));
243
+ console.log(); // Add spacing before statistics
244
+ // Use table format if available, otherwise fall back to formatted string
245
+ if (logger.statsTable) {
246
+ logger.statsTable(buildStats);
247
+ }
248
+ else {
249
+ logger.stats(formatBuildStats(buildStats));
250
+ }
190
251
  return buildStats;
191
252
  }
@@ -0,0 +1,21 @@
1
+ import type { Logger } from '../types.js';
2
+ export interface DevServerOptions {
3
+ port?: number;
4
+ host?: string;
5
+ open?: boolean;
6
+ configPath?: string;
7
+ logger?: Logger;
8
+ }
9
+ export interface DevServer {
10
+ start(): Promise<void>;
11
+ stop(): Promise<void>;
12
+ url: string;
13
+ }
14
+ /**
15
+ * Creates and configures a development server with live reload functionality.
16
+ *
17
+ * @param options - Development server configuration options
18
+ * @returns Promise resolving to a DevServer instance
19
+ */
20
+ export declare function createDevServer(options?: DevServerOptions): Promise<DevServer>;
21
+ //# sourceMappingURL=dev.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dev.d.ts","sourceRoot":"","sources":["../../src/core/dev.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAe,MAAM,EAAE,MAAM,aAAa,CAAC;AAKvD,MAAM,WAAW,gBAAgB;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,SAAS;IACxB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACtB,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CAAC,OAAO,GAAE,gBAAqB,GAAG,OAAO,CAAC,SAAS,CAAC,CAgVxF"}
@@ -0,0 +1,305 @@
1
+ import { createServer } from 'http';
2
+ import { join, extname } from 'path';
3
+ import { readFile, stat } from 'fs/promises';
4
+ import { WebSocketServer } from 'ws';
5
+ import chokidar from 'chokidar';
6
+ import { build } from './build.js';
7
+ import { loadConfig } from '../config/loader.js';
8
+ /**
9
+ * Creates and configures a development server with live reload functionality.
10
+ *
11
+ * @param options - Development server configuration options
12
+ * @returns Promise resolving to a DevServer instance
13
+ */
14
+ export async function createDevServer(options = {}) {
15
+ const { port = 3000, host = 'localhost', open = false, configPath, logger = {
16
+ info: (msg) => console.log(msg),
17
+ success: (msg) => console.log(msg),
18
+ error: (msg) => console.error(msg),
19
+ warning: (msg) => console.warn(msg),
20
+ building: (msg) => console.log(msg),
21
+ processing: (msg) => console.log(msg),
22
+ stats: (msg) => console.log(msg),
23
+ }, } = options;
24
+ const url = `http://${host}:${port}`;
25
+ let httpServer = null;
26
+ let wsServer = null;
27
+ let watcher = null;
28
+ let config;
29
+ let isBuilding = false;
30
+ // Load configuration
31
+ try {
32
+ if (configPath) {
33
+ // For custom config path, we need to change to that directory temporarily
34
+ // This is a limitation of the current loadConfig implementation
35
+ logger.info?.(`Loading config from: ${configPath}`);
36
+ }
37
+ config = await loadConfig(process.cwd());
38
+ }
39
+ catch (error) {
40
+ logger.error?.(`Failed to load config: ${error instanceof Error ? error.message : String(error)}`);
41
+ throw error;
42
+ }
43
+ const outDir = join(process.cwd(), config.outDir || 'dist');
44
+ const srcDir = join(process.cwd(), config.srcDir || 'site');
45
+ const staticDir = join(process.cwd(), config.staticDir || 'public');
46
+ /**
47
+ * Performs an initial build to ensure dist/ exists
48
+ */
49
+ async function initialBuild() {
50
+ logger.info?.('🏗️ Performing initial build...');
51
+ try {
52
+ await build({
53
+ logger,
54
+ force: false,
55
+ clean: false,
56
+ ...(configPath && { configPath }),
57
+ });
58
+ logger.success?.('✅ Initial build complete');
59
+ }
60
+ catch (error) {
61
+ logger.error?.(`Initial build failed: ${error instanceof Error ? error.message : String(error)}`);
62
+ throw error;
63
+ }
64
+ }
65
+ /**
66
+ * Performs incremental rebuild when files change
67
+ */
68
+ async function incrementalRebuild(changedPath) {
69
+ if (isBuilding) {
70
+ logger.info?.('⏳ Build in progress, skipping...');
71
+ return;
72
+ }
73
+ isBuilding = true;
74
+ logger.info?.(`🔄 Rebuilding due to change: ${changedPath}`);
75
+ try {
76
+ await build({
77
+ logger,
78
+ force: false,
79
+ clean: false,
80
+ ...(configPath && { configPath }),
81
+ });
82
+ // Notify all connected clients to reload
83
+ if (wsServer) {
84
+ wsServer.clients.forEach((client) => {
85
+ const ws = client;
86
+ if (ws.readyState === 1) {
87
+ // WebSocket.OPEN
88
+ ws.send(JSON.stringify({ type: 'reload' }));
89
+ }
90
+ });
91
+ }
92
+ logger.success?.('✅ Rebuild complete');
93
+ }
94
+ catch (error) {
95
+ logger.error?.(`Rebuild failed: ${error instanceof Error ? error.message : String(error)}`);
96
+ }
97
+ finally {
98
+ isBuilding = false;
99
+ }
100
+ }
101
+ /**
102
+ * Gets MIME type for a file based on its extension
103
+ */
104
+ function getMimeType(filePath) {
105
+ const ext = extname(filePath).toLowerCase();
106
+ const mimeTypes = {
107
+ '.html': 'text/html',
108
+ '.js': 'application/javascript',
109
+ '.css': 'text/css',
110
+ '.json': 'application/json',
111
+ '.png': 'image/png',
112
+ '.jpg': 'image/jpeg',
113
+ '.jpeg': 'image/jpeg',
114
+ '.gif': 'image/gif',
115
+ '.svg': 'image/svg+xml',
116
+ '.ico': 'image/x-icon',
117
+ '.webp': 'image/webp',
118
+ '.woff': 'font/woff',
119
+ '.woff2': 'font/woff2',
120
+ '.ttf': 'font/ttf',
121
+ '.eot': 'application/vnd.ms-fontobject',
122
+ };
123
+ return mimeTypes[ext] || 'application/octet-stream';
124
+ }
125
+ /**
126
+ * Injects live reload script into HTML responses
127
+ */
128
+ function injectLiveReloadScript(html) {
129
+ const script = `
130
+ <script>
131
+ (function() {
132
+ const ws = new WebSocket('ws://${host}:${port}/__ws');
133
+ ws.onmessage = function(event) {
134
+ const data = JSON.parse(event.data);
135
+ if (data.type === 'reload') {
136
+ console.log('🔄 Reloading page due to file changes...');
137
+ window.location.reload();
138
+ }
139
+ };
140
+ ws.onopen = function() {
141
+ console.log('🔗 Connected to Stati dev server');
142
+ };
143
+ ws.onclose = function() {
144
+ console.log('❌ Lost connection to Stati dev server');
145
+ // Try to reconnect after a delay
146
+ setTimeout(() => window.location.reload(), 1000);
147
+ };
148
+ })();
149
+ </script>`;
150
+ // Insert before closing </body> tag, or at the end if no </body>
151
+ if (html.includes('</body>')) {
152
+ return html.replace('</body>', `${script}\n</body>`);
153
+ }
154
+ else {
155
+ return html + script;
156
+ }
157
+ }
158
+ /**
159
+ * Serves files from the dist directory
160
+ */
161
+ async function serveFile(requestPath) {
162
+ let filePath = join(outDir, requestPath === '/' ? 'index.html' : requestPath);
163
+ try {
164
+ const stats = await stat(filePath);
165
+ if (stats.isDirectory()) {
166
+ // Try to serve index.html from directory
167
+ const indexPath = join(filePath, 'index.html');
168
+ try {
169
+ await stat(indexPath);
170
+ filePath = indexPath;
171
+ }
172
+ catch {
173
+ return {
174
+ content: '404 - Directory listing not available',
175
+ mimeType: 'text/plain',
176
+ statusCode: 404,
177
+ };
178
+ }
179
+ }
180
+ const mimeType = getMimeType(filePath);
181
+ const content = await readFile(filePath);
182
+ // Inject live reload script into HTML files
183
+ if (mimeType === 'text/html') {
184
+ const html = content.toString('utf-8');
185
+ const injectedHtml = injectLiveReloadScript(html);
186
+ return {
187
+ content: injectedHtml,
188
+ mimeType,
189
+ statusCode: 200,
190
+ };
191
+ }
192
+ return {
193
+ content,
194
+ mimeType,
195
+ statusCode: 200,
196
+ };
197
+ }
198
+ catch {
199
+ // File not found
200
+ return {
201
+ content: '404 - File not found',
202
+ mimeType: 'text/plain',
203
+ statusCode: 404,
204
+ };
205
+ }
206
+ }
207
+ const devServer = {
208
+ url,
209
+ async start() {
210
+ // Perform initial build
211
+ await initialBuild();
212
+ // Create HTTP server
213
+ httpServer = createServer(async (req, res) => {
214
+ const requestPath = req.url || '/';
215
+ // Handle WebSocket upgrade path
216
+ if (requestPath === '/__ws') {
217
+ return; // Let WebSocket server handle this
218
+ }
219
+ logger.processing?.(`${req.method} ${requestPath}`);
220
+ try {
221
+ const { content, mimeType, statusCode } = await serveFile(requestPath);
222
+ res.writeHead(statusCode, {
223
+ 'Content-Type': mimeType,
224
+ 'Access-Control-Allow-Origin': '*',
225
+ 'Cache-Control': 'no-cache, no-store, must-revalidate',
226
+ });
227
+ res.end(content);
228
+ }
229
+ catch (error) {
230
+ logger.error?.(`Server error: ${error instanceof Error ? error.message : String(error)}`);
231
+ res.writeHead(500, { 'Content-Type': 'text/plain' });
232
+ res.end('500 - Internal Server Error');
233
+ }
234
+ });
235
+ // Create WebSocket server for live reload
236
+ wsServer = new WebSocketServer({
237
+ server: httpServer,
238
+ path: '/__ws',
239
+ });
240
+ wsServer.on('connection', (ws) => {
241
+ logger.info?.('🔗 Browser connected for live reload');
242
+ const websocket = ws;
243
+ websocket.on('close', () => {
244
+ logger.info?.('❌ Browser disconnected from live reload');
245
+ });
246
+ });
247
+ // Start HTTP server
248
+ await new Promise((resolve, reject) => {
249
+ httpServer.listen(port, host, () => {
250
+ resolve();
251
+ });
252
+ httpServer.on('error', (error) => {
253
+ reject(error);
254
+ });
255
+ });
256
+ // Set up file watching
257
+ const watchPaths = [srcDir, staticDir].filter(Boolean);
258
+ watcher = chokidar.watch(watchPaths, {
259
+ ignored: /(^|[/\\])\../, // ignore dotfiles
260
+ persistent: true,
261
+ ignoreInitial: true,
262
+ });
263
+ watcher.on('change', (path) => {
264
+ void incrementalRebuild(path);
265
+ });
266
+ watcher.on('add', (path) => {
267
+ void incrementalRebuild(path);
268
+ });
269
+ watcher.on('unlink', (path) => {
270
+ void incrementalRebuild(path);
271
+ });
272
+ logger.success?.(`🚀 Dev server running at ${url}`);
273
+ logger.info?.(`📁 Serving from: ${outDir}`);
274
+ logger.info?.(`👀 Watching: ${watchPaths.join(', ')}`);
275
+ // Open browser if requested
276
+ if (open) {
277
+ try {
278
+ const { default: openBrowser } = await import('open');
279
+ await openBrowser(url);
280
+ }
281
+ catch {
282
+ logger.info?.('Could not open browser automatically');
283
+ }
284
+ }
285
+ },
286
+ async stop() {
287
+ if (watcher) {
288
+ await watcher.close();
289
+ watcher = null;
290
+ }
291
+ if (wsServer) {
292
+ wsServer.close();
293
+ wsServer = null;
294
+ }
295
+ if (httpServer) {
296
+ await new Promise((resolve) => {
297
+ httpServer.close(() => resolve());
298
+ });
299
+ httpServer = null;
300
+ }
301
+ logger.info?.('🛑 Dev server stopped');
302
+ },
303
+ };
304
+ return devServer;
305
+ }
@@ -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;AAK1B,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,OAAO,EAAkB,MAAM,aAAa,CAAC;AAgRnF,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,WAAW,GAAG,GAAG,CAS7D;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,GACrB,OAAO,CAAC,MAAM,CAAC,CAgDjB"}
1
+ {"version":3,"file":"templates.d.ts","sourceRoot":"","sources":["../../src/core/templates.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAK1B,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,OAAO,EAAkB,MAAM,aAAa,CAAC;AAgRnF,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,WAAW,GAAG,GAAG,CAS7D;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,GACrB,OAAO,CAAC,MAAM,CAAC,CAkEjB"}
@@ -241,7 +241,7 @@ export async function renderPage(page, body, config, eta, navigation, allPages)
241
241
  // Discover partials for this page's directory hierarchy
242
242
  const srcDir = join(process.cwd(), config.srcDir);
243
243
  const relativePath = relative(srcDir, page.sourcePath);
244
- const partials = await discoverPartials(relativePath, config);
244
+ const partialPaths = await discoverPartials(relativePath, config);
245
245
  // Build collection data if this is an index page and all pages are provided
246
246
  let collectionData;
247
247
  const isIndexPage = allPages && isCollectionIndexPage(page, allPages);
@@ -251,20 +251,37 @@ export async function renderPage(page, body, config, eta, navigation, allPages)
251
251
  // Discover the appropriate layout using hierarchical layout.eta convention
252
252
  // Pass isIndexPage flag to enable index.eta lookup for aggregation pages
253
253
  const layoutPath = await discoverLayout(relativePath, config, page.frontMatter.layout, isIndexPage);
254
- const context = {
254
+ // Create base context for partial rendering
255
+ const baseContext = {
255
256
  site: config.site,
256
257
  page: {
257
258
  ...page.frontMatter,
258
259
  path: page.url,
260
+ url: page.url, // Add url property for compatibility
259
261
  content: body,
260
262
  },
261
263
  content: body,
262
264
  navigation: navigation || [],
263
- partials, // Add discovered partials to template context
264
265
  collection: collectionData, // Add collection data for index pages
265
266
  // Add custom filters to context
266
267
  ...(config.eta?.filters || {}),
267
268
  };
269
+ // Render partials and store their content
270
+ const renderedPartials = {};
271
+ for (const [partialName, partialPath] of Object.entries(partialPaths)) {
272
+ try {
273
+ const renderedContent = await eta.renderAsync(partialPath, baseContext);
274
+ renderedPartials[partialName] = renderedContent;
275
+ }
276
+ catch (error) {
277
+ console.warn(`Warning: Failed to render partial ${partialName} at ${partialPath}:`, error);
278
+ renderedPartials[partialName] = `<!-- Error rendering partial: ${partialName} -->`;
279
+ }
280
+ }
281
+ const context = {
282
+ ...baseContext,
283
+ partials: renderedPartials, // Add rendered partials to template context
284
+ };
268
285
  try {
269
286
  if (!layoutPath) {
270
287
  console.warn('No layout template found, using fallback');
package/dist/index.d.ts CHANGED
@@ -21,7 +21,9 @@
21
21
  */
22
22
  export type { StatiConfig, PageModel, FrontMatter, BuildContext, PageContext, BuildHooks, NavNode, ISGConfig, AgingRule, BuildStats, } from './types.js';
23
23
  export type { BuildOptions } from './core/build.js';
24
+ export type { DevServerOptions } from './core/dev.js';
24
25
  export { build } from './core/build.js';
26
+ export { createDevServer } from './core/dev.js';
25
27
  export { loadConfig } from './config/loader.js';
26
28
  export { invalidate } from './core/invalidate.js';
27
29
  import type { StatiConfig } from './types.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,YAAY,EACV,WAAW,EACX,SAAS,EACT,WAAW,EACX,YAAY,EACZ,WAAW,EACX,UAAU,EACV,OAAO,EACP,SAAS,EACT,SAAS,EACT,UAAU,GACX,MAAM,YAAY,CAAC;AAEpB,YAAY,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAEpD,OAAO,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAGlD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,WAAW,GAAG,WAAW,CAE7D"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,YAAY,EACV,WAAW,EACX,SAAS,EACT,WAAW,EACX,YAAY,EACZ,WAAW,EACX,UAAU,EACV,OAAO,EACP,SAAS,EACT,SAAS,EACT,UAAU,GACX,MAAM,YAAY,CAAC;AAEpB,YAAY,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACpD,YAAY,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEtD,OAAO,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AACxC,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAGlD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,WAAW,GAAG,WAAW,CAE7D"}
package/dist/index.js CHANGED
@@ -20,6 +20,7 @@
20
20
  * ```
21
21
  */
22
22
  export { build } from './core/build.js';
23
+ export { createDevServer } from './core/dev.js';
23
24
  export { loadConfig } from './config/loader.js';
24
25
  export { invalidate } from './core/invalidate.js';
25
26
  /**
package/dist/types.d.ts CHANGED
@@ -108,6 +108,15 @@ export interface StatiConfig {
108
108
  };
109
109
  /** Incremental Static Generation configuration */
110
110
  isg?: ISGConfig;
111
+ /** Development server configuration */
112
+ dev?: {
113
+ /** Port for development server (default: 3000) */
114
+ port?: number;
115
+ /** Host for development server (default: 'localhost') */
116
+ host?: string;
117
+ /** Whether to open browser automatically (default: false) */
118
+ open?: boolean;
119
+ };
111
120
  /** Build lifecycle hooks */
112
121
  hooks?: BuildHooks;
113
122
  }
@@ -259,6 +268,79 @@ export interface PageModel {
259
268
  /** Publication date (parsed from front matter or file stats) */
260
269
  publishedAt?: Date;
261
270
  }
271
+ /**
272
+ * Logger interface for customizing build output.
273
+ * Provides different log levels and formatting options for prettier CLI output.
274
+ *
275
+ * @example
276
+ * ```typescript
277
+ * const customLogger: Logger = {
278
+ * info: (msg) => console.log(chalk.blue('ℹ️ ' + msg)),
279
+ * success: (msg) => console.log(chalk.green('✅ ' + msg)),
280
+ * warning: (msg) => console.warn(chalk.yellow('⚠️ ' + msg)),
281
+ * error: (msg) => console.error(chalk.red('❌ ' + msg)),
282
+ * building: (msg) => console.log(chalk.cyan('🏗️ ' + msg)),
283
+ * processing: (msg) => console.log(chalk.gray(' ' + msg)),
284
+ * stats: (msg) => console.log(chalk.cyan('📊 ' + msg)),
285
+ * header: (msg) => console.log(boxedMessage(msg)),
286
+ * step: (step, total, msg) => console.log(`[${step}/${total}] ${msg}`),
287
+ * progress: (current, total, msg) => console.log(progressBar(current, total) + ' ' + msg),
288
+ * file: (op, path) => console.log(` 📄 ${op} ${path}`),
289
+ * url: (label, url) => console.log(` 🔗 ${label}: ${url}`),
290
+ * timing: (op, duration) => console.log(` ⏱️ ${op} completed in ${duration}ms`),
291
+ * divider: (title) => console.log('─'.repeat(50) + ' ' + title)
292
+ * };
293
+ * ```
294
+ */
295
+ export interface Logger {
296
+ /** Log informational messages */
297
+ info: (message: string) => void;
298
+ /** Log success messages */
299
+ success: (message: string) => void;
300
+ /** Log warning messages */
301
+ warning: (message: string) => void;
302
+ /** Log error messages */
303
+ error: (message: string) => void;
304
+ /** Log build progress messages */
305
+ building: (message: string) => void;
306
+ /** Log file processing messages */
307
+ processing: (message: string) => void;
308
+ /** Log statistics and metrics */
309
+ stats: (message: string) => void;
310
+ /** Display a header message in a box (optional) */
311
+ header?: (message: string) => void;
312
+ /** Display a step indicator (optional) */
313
+ step?: (step: number, total: number, message: string) => void;
314
+ /** Display progress with a bar (optional) */
315
+ progress?: (current: number, total: number, message: string) => void;
316
+ /** Log file operations (optional) */
317
+ file?: (operation: string, path: string) => void;
318
+ /** Log URLs with proper styling (optional) */
319
+ url?: (label: string, url: string) => void;
320
+ /** Log timing information (optional) */
321
+ timing?: (operation: string, duration: number) => void;
322
+ /** Display a section divider (optional) */
323
+ divider?: (title?: string) => void;
324
+ /** Start a spinner for long operations (optional) */
325
+ startSpinner?: (text: string, type?: 'building' | 'processing' | 'copying') => unknown;
326
+ /** Stop a spinner with success (optional) */
327
+ succeedSpinner?: (spinner: unknown, text?: string) => void;
328
+ /** Stop a spinner with failure (optional) */
329
+ failSpinner?: (spinner: unknown, text?: string) => void;
330
+ /** Update spinner text (optional) */
331
+ updateSpinner?: (spinner: unknown, text: string) => void;
332
+ /** Display build statistics as a table (optional) */
333
+ statsTable?: (stats: {
334
+ totalPages: number;
335
+ assetsCount: number;
336
+ buildTimeMs: number;
337
+ outputSizeBytes: number;
338
+ cacheHits?: number;
339
+ cacheMisses?: number;
340
+ }) => void;
341
+ /** Display navigation tree structure (optional) */
342
+ navigationTree?: (navigation: NavNode[]) => void;
343
+ }
262
344
  /**
263
345
  * Statistics collected during the build process.
264
346
  * Provides useful metrics about the site generation.
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stati/core",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -27,14 +27,18 @@
27
27
  "test": "vitest run"
28
28
  },
29
29
  "dependencies": {
30
+ "chokidar": "^3.6.0",
30
31
  "eta": "^3.5.0",
31
32
  "fast-glob": "^3.3.3",
32
33
  "fs-extra": "^11.2.0",
33
34
  "gray-matter": "^4.0.3",
34
- "markdown-it": "^14.1.0"
35
+ "markdown-it": "^14.1.0",
36
+ "open": "^10.1.0",
37
+ "ws": "^8.18.0"
35
38
  },
36
39
  "devDependencies": {
37
40
  "@types/fs-extra": "^11.0.4",
38
- "@types/markdown-it": "^14.1.2"
41
+ "@types/markdown-it": "^14.1.2",
42
+ "@types/ws": "^8.5.12"
39
43
  }
40
44
  }