@stati/core 1.2.0 → 1.3.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.
@@ -28,31 +28,35 @@ export interface BuildOptions {
28
28
  version?: string;
29
29
  }
30
30
  /**
31
- * Builds the static site by processing content files and generating HTML pages.
32
- * This is the main entry point for Stati's build process.
31
+ * Builds the Stati site with ISG support.
32
+ * Processes all pages and assets, with smart caching for incremental builds.
33
+ *
33
34
  * Uses build locking to prevent concurrent builds from corrupting cache.
35
+ * The manifest tracks build dependencies and cache entries for efficient rebuilds.
36
+ * Pages are only rebuilt if their content, templates, or dependencies have changed.
37
+ *
38
+ * Build process:
39
+ * 1. Load configuration and content
40
+ * 2. Check cache manifest for existing entries
41
+ * 3. Process each page (rebuild only if needed)
42
+ * 4. Copy static assets
43
+ * 5. Update cache manifest
34
44
  *
35
45
  * @param options - Build configuration options
46
+ * @returns Promise resolving to build statistics
47
+ * @throws {Error} When configuration is invalid
48
+ * @throws {Error} When template rendering fails
49
+ * @throws {Error} When build lock cannot be acquired
36
50
  *
37
51
  * @example
38
52
  * ```typescript
39
- * import { build } from 'stati';
40
- *
41
- * // Basic build
42
- * await build();
43
- *
44
- * // Build with options
45
- * await build({
46
- * clean: true,
53
+ * const stats = await build({
47
54
  * force: true,
48
- * configPath: './custom.config.js'
55
+ * clean: true,
56
+ * includeDrafts: false
49
57
  * });
58
+ * console.log(`Built ${stats.pageCount} pages in ${stats.buildTime}ms`);
50
59
  * ```
51
- *
52
- * @throws {Error} When configuration loading fails
53
- * @throws {Error} When content processing fails
54
- * @throws {Error} When template rendering fails
55
- * @throws {Error} When build lock cannot be acquired
56
60
  */
57
61
  export declare function build(options?: BuildOptions): Promise<BuildStats>;
58
62
  //# sourceMappingURL=build.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/core/build.ts"],"names":[],"mappings":"AAYA,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;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAsB,KAAK,CAAC,OAAO,GAAE,YAAiB,GAAG,OAAO,CAAC,UAAU,CAAC,CAQ3E"}
1
+ {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/core/build.ts"],"names":[],"mappings":"AAYA,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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAsB,KAAK,CAAC,OAAO,GAAE,YAAiB,GAAG,OAAO,CAAC,UAAU,CAAC,CAW3E"}
@@ -112,34 +112,40 @@ function formatBuildStats(stats) {
112
112
  return output;
113
113
  }
114
114
  /**
115
- * Builds the static site by processing content files and generating HTML pages.
116
- * This is the main entry point for Stati's build process.
115
+ * Builds the Stati site with ISG support.
116
+ * Processes all pages and assets, with smart caching for incremental builds.
117
+ *
117
118
  * Uses build locking to prevent concurrent builds from corrupting cache.
119
+ * The manifest tracks build dependencies and cache entries for efficient rebuilds.
120
+ * Pages are only rebuilt if their content, templates, or dependencies have changed.
121
+ *
122
+ * Build process:
123
+ * 1. Load configuration and content
124
+ * 2. Check cache manifest for existing entries
125
+ * 3. Process each page (rebuild only if needed)
126
+ * 4. Copy static assets
127
+ * 5. Update cache manifest
118
128
  *
119
129
  * @param options - Build configuration options
130
+ * @returns Promise resolving to build statistics
131
+ * @throws {Error} When configuration is invalid
132
+ * @throws {Error} When template rendering fails
133
+ * @throws {Error} When build lock cannot be acquired
120
134
  *
121
135
  * @example
122
136
  * ```typescript
123
- * import { build } from 'stati';
124
- *
125
- * // Basic build
126
- * await build();
127
- *
128
- * // Build with options
129
- * await build({
130
- * clean: true,
137
+ * const stats = await build({
131
138
  * force: true,
132
- * configPath: './custom.config.js'
139
+ * clean: true,
140
+ * includeDrafts: false
133
141
  * });
142
+ * console.log(`Built ${stats.pageCount} pages in ${stats.buildTime}ms`);
134
143
  * ```
135
- *
136
- * @throws {Error} When configuration loading fails
137
- * @throws {Error} When content processing fails
138
- * @throws {Error} When template rendering fails
139
- * @throws {Error} When build lock cannot be acquired
140
144
  */
141
145
  export async function build(options = {}) {
142
146
  const cacheDir = join(process.cwd(), '.stati');
147
+ // Ensure cache directory exists before acquiring build lock
148
+ await ensureDir(cacheDir);
143
149
  // Use build lock to prevent concurrent builds, with force option to override
144
150
  return await withBuildLock(cacheDir, () => buildInternal(options), {
145
151
  force: Boolean(options.force || options.clean), // Allow force if user explicitly requests it
@@ -1 +1 @@
1
- {"version":3,"file":"dev.d.ts","sourceRoot":"","sources":["../../src/core/dev.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAe,MAAM,EAAE,MAAM,aAAa,CAAC;AAMvD,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,CA0ZxF"}
1
+ {"version":3,"file":"dev.d.ts","sourceRoot":"","sources":["../../src/core/dev.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAe,MAAM,EAAE,MAAM,aAAa,CAAC;AAMvD,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,CAoaxF"}
package/dist/core/dev.js CHANGED
@@ -71,17 +71,30 @@ export async function createDevServer(options = {}) {
71
71
  return;
72
72
  }
73
73
  isBuilding = true;
74
+ const startTime = Date.now();
75
+ // Create a quiet logger for dev builds that suppresses verbose output
76
+ const devLogger = {
77
+ info: () => { }, // Suppress info messages
78
+ success: () => { }, // Suppress success messages
79
+ error: logger.error || (() => { }),
80
+ warning: logger.warning || (() => { }),
81
+ building: () => { }, // Suppress building messages
82
+ processing: () => { }, // Suppress processing messages
83
+ stats: () => { }, // Suppress stats messages
84
+ };
74
85
  try {
86
+ const relativePath = changedPath
87
+ .replace(process.cwd(), '')
88
+ .replace(/\\/g, '/')
89
+ .replace(/^\//, '');
75
90
  // Check if the changed file is a template/partial
76
91
  if (changedPath.endsWith('.eta') || changedPath.includes('_partials')) {
77
- logger.info?.(`🎨 Template changed: ${changedPath}`);
78
- await handleTemplateChange(changedPath);
92
+ await handleTemplateChange(changedPath, devLogger);
79
93
  }
80
94
  else {
81
95
  // Content or static file changed - use normal rebuild
82
- logger.info?.(`📄 Content changed: ${changedPath}`);
83
96
  await build({
84
- logger,
97
+ logger: devLogger,
85
98
  force: false,
86
99
  clean: false,
87
100
  ...(configPath && { configPath }),
@@ -97,10 +110,12 @@ export async function createDevServer(options = {}) {
97
110
  }
98
111
  });
99
112
  }
100
- logger.success?.('Rebuild complete');
113
+ const duration = Date.now() - startTime;
114
+ logger.info?.(`⚡ ${relativePath} rebuilt in ${duration}ms`);
101
115
  }
102
116
  catch (error) {
103
- logger.error?.(`Rebuild failed: ${error instanceof Error ? error.message : String(error)}`);
117
+ const duration = Date.now() - startTime;
118
+ logger.error?.(`❌ Rebuild failed after ${duration}ms: ${error instanceof Error ? error.message : String(error)}`);
104
119
  }
105
120
  finally {
106
121
  isBuilding = false;
@@ -109,16 +124,16 @@ export async function createDevServer(options = {}) {
109
124
  /**
110
125
  * Handles template/partial file changes by invalidating affected pages
111
126
  */
112
- async function handleTemplateChange(templatePath) {
127
+ async function handleTemplateChange(templatePath, buildLogger) {
113
128
  const cacheDir = join(process.cwd(), '.stati');
129
+ const effectiveLogger = buildLogger || logger;
114
130
  try {
115
131
  // Load existing cache manifest
116
132
  let cacheManifest = await loadCacheManifest(cacheDir);
117
133
  if (!cacheManifest) {
118
134
  // No cache exists, perform full rebuild
119
- logger.info?.('No cache found, performing full rebuild...');
120
135
  await build({
121
- logger,
136
+ logger: effectiveLogger,
122
137
  force: false,
123
138
  clean: false,
124
139
  ...(configPath && { configPath }),
@@ -135,27 +150,21 @@ export async function createDevServer(options = {}) {
135
150
  }
136
151
  }
137
152
  if (affectedPages.length > 0) {
138
- logger.info?.(`đŸŽ¯ Invalidating ${affectedPages.length} affected pages:`);
139
- affectedPages.forEach((page) => logger.info?.(` 📄 ${page}`));
140
153
  // Save updated cache manifest
141
154
  await saveCacheManifest(cacheDir, cacheManifest);
142
155
  // Perform incremental rebuild (only affected pages will be rebuilt)
143
156
  await build({
144
- logger,
157
+ logger: effectiveLogger,
145
158
  force: false,
146
159
  clean: false,
147
160
  ...(configPath && { configPath }),
148
161
  });
149
162
  }
150
- else {
151
- logger.info?.('â„šī¸ No pages affected by template change');
152
- }
153
163
  }
154
- catch (error) {
155
- logger.warning?.(`Template dependency analysis failed, performing full rebuild: ${error instanceof Error ? error.message : String(error)}`);
164
+ catch {
156
165
  // Fallback to full rebuild
157
166
  await build({
158
- logger,
167
+ logger: effectiveLogger,
159
168
  force: false,
160
169
  clean: false,
161
170
  ...(configPath && { configPath }),
@@ -1 +1 @@
1
- {"version":3,"file":"build-lock.d.ts","sourceRoot":"","sources":["../../../src/core/isg/build-lock.ts"],"names":[],"mappings":"AAYA;;GAEG;AACH,UAAU,SAAS;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,QAAQ,CAAS;gBAEb,QAAQ,EAAE,MAAM;IAI5B;;;;;;;;;;;;;;;;;;;OAmBG;IACG,WAAW,CAAC,OAAO,GAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAoDrF;;;;;;;OAOG;IACG,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IAqBlC;;;;;;;;;;;OAWG;IACG,UAAU,IAAI,OAAO,CAAC,OAAO,CAAC;IAiBpC;;;;OAIG;IACG,WAAW,IAAI,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;IAY9C;;;OAGG;YACW,eAAe;IAQ7B;;OAEG;YACW,cAAc;IAW5B;;OAEG;YACW,YAAY;IAS1B;;OAEG;YACW,gBAAgB;IAY9B;;OAEG;IACH,OAAO,CAAC,WAAW;IAQnB;;OAEG;IACH,OAAO,CAAC,KAAK;CAGd;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,aAAa,CAAC,CAAC,EACnC,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACzB,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAO,GAClD,OAAO,CAAC,CAAC,CAAC,CASZ"}
1
+ {"version":3,"file":"build-lock.d.ts","sourceRoot":"","sources":["../../../src/core/isg/build-lock.ts"],"names":[],"mappings":"AAYA;;GAEG;AACH,UAAU,SAAS;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,QAAQ,CAAS;gBAEb,QAAQ,EAAE,MAAM;IAI5B;;;;;;;;;;;;;;;;;;;OAmBG;IACG,WAAW,CAAC,OAAO,GAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAoDrF;;;;;;;OAOG;IACG,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IAqBlC;;;;;;;;;;;OAWG;IACG,UAAU,IAAI,OAAO,CAAC,OAAO,CAAC;IAiBpC;;;;OAIG;IACG,WAAW,IAAI,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;IAY9C;;;OAGG;YACW,eAAe;IAQ7B;;OAEG;YACW,cAAc;IAc5B;;OAEG;YACW,YAAY;IAS1B;;OAEG;YACW,gBAAgB;IAY9B;;OAEG;IACH,OAAO,CAAC,WAAW;IAQnB;;OAEG;IACH,OAAO,CAAC,KAAK;CAGd;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,aAAa,CAAC,CAAC,EACnC,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACzB,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAO,GAClD,OAAO,CAAC,CAAC,CAAC,CASZ"}
@@ -1,6 +1,6 @@
1
1
  import fse from 'fs-extra';
2
- const { writeFile, readFile, pathExists, remove } = fse;
3
- import { join } from 'path';
2
+ const { writeFile, readFile, pathExists, remove, ensureDir } = fse;
3
+ import { join, dirname } from 'path';
4
4
  import { hostname } from 'os';
5
5
  /**
6
6
  * Manages build process locking to prevent concurrent Stati builds from corrupting cache.
@@ -167,6 +167,8 @@ export class BuildLockManager {
167
167
  timestamp: new Date().toISOString(),
168
168
  hostname: this.getHostname(),
169
169
  };
170
+ // Ensure the cache directory exists before creating the lock file
171
+ await ensureDir(dirname(this.lockPath));
170
172
  // Use 'wx' flag to create file exclusively (fails if exists)
171
173
  await writeFile(this.lockPath, JSON.stringify(lockInfo, null, 2), { flag: 'wx' });
172
174
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stati/core",
3
- "version": "1.2.0",
3
+ "version": "1.3.1",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",