@stati/core 1.3.1 → 1.4.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.
Files changed (84) hide show
  1. package/dist/config/loader.d.ts +7 -1
  2. package/dist/config/loader.d.ts.map +1 -1
  3. package/dist/config/loader.js +17 -12
  4. package/dist/constants.d.ts +71 -0
  5. package/dist/constants.d.ts.map +1 -0
  6. package/dist/constants.js +78 -0
  7. package/dist/core/build.d.ts +1 -1
  8. package/dist/core/build.d.ts.map +1 -1
  9. package/dist/core/build.js +94 -69
  10. package/dist/core/content.d.ts +1 -1
  11. package/dist/core/content.d.ts.map +1 -1
  12. package/dist/core/content.js +10 -5
  13. package/dist/core/dev.d.ts +1 -7
  14. package/dist/core/dev.d.ts.map +1 -1
  15. package/dist/core/dev.js +202 -141
  16. package/dist/core/invalidate.d.ts +1 -1
  17. package/dist/core/invalidate.d.ts.map +1 -1
  18. package/dist/core/invalidate.js +3 -3
  19. package/dist/core/isg/build-lock.d.ts.map +1 -1
  20. package/dist/core/isg/build-lock.js +4 -2
  21. package/dist/core/isg/builder.d.ts +1 -1
  22. package/dist/core/isg/builder.d.ts.map +1 -1
  23. package/dist/core/isg/deps.d.ts +1 -1
  24. package/dist/core/isg/deps.d.ts.map +1 -1
  25. package/dist/core/isg/deps.js +59 -78
  26. package/dist/core/isg/hash.d.ts.map +1 -1
  27. package/dist/core/isg/hash.js +26 -17
  28. package/dist/core/isg/manifest.d.ts +1 -1
  29. package/dist/core/isg/manifest.d.ts.map +1 -1
  30. package/dist/core/isg/manifest.js +21 -8
  31. package/dist/core/isg/ttl.d.ts +1 -1
  32. package/dist/core/isg/ttl.d.ts.map +1 -1
  33. package/dist/core/isg/ttl.js +6 -9
  34. package/dist/core/isg/validation.d.ts +1 -1
  35. package/dist/core/isg/validation.d.ts.map +1 -1
  36. package/dist/core/markdown.d.ts +1 -1
  37. package/dist/core/markdown.d.ts.map +1 -1
  38. package/dist/core/navigation.d.ts +1 -1
  39. package/dist/core/navigation.d.ts.map +1 -1
  40. package/dist/core/preview.d.ts +19 -0
  41. package/dist/core/preview.d.ts.map +1 -0
  42. package/dist/core/preview.js +163 -0
  43. package/dist/core/templates.d.ts +1 -1
  44. package/dist/core/templates.d.ts.map +1 -1
  45. package/dist/core/templates.js +28 -105
  46. package/dist/core/utils/fs.d.ts +37 -0
  47. package/dist/core/utils/fs.d.ts.map +1 -0
  48. package/dist/core/utils/fs.js +86 -0
  49. package/dist/core/utils/partials.d.ts +24 -0
  50. package/dist/core/utils/partials.d.ts.map +1 -0
  51. package/dist/core/utils/partials.js +85 -0
  52. package/dist/core/utils/paths.d.ts +67 -0
  53. package/dist/core/utils/paths.d.ts.map +1 -0
  54. package/dist/core/utils/paths.js +86 -0
  55. package/dist/core/utils/template-discovery.d.ts +34 -0
  56. package/dist/core/utils/template-discovery.d.ts.map +1 -0
  57. package/dist/core/utils/template-discovery.js +111 -0
  58. package/dist/index.d.ts +4 -2
  59. package/dist/index.d.ts.map +1 -1
  60. package/dist/index.js +1 -0
  61. package/dist/tests/utils/test-mocks.d.ts +69 -0
  62. package/dist/tests/utils/test-mocks.d.ts.map +1 -0
  63. package/dist/tests/utils/test-mocks.js +125 -0
  64. package/dist/types/config.d.ts +178 -0
  65. package/dist/types/config.d.ts.map +1 -0
  66. package/dist/types/config.js +1 -0
  67. package/dist/types/content.d.ts +124 -0
  68. package/dist/types/content.d.ts.map +1 -0
  69. package/dist/types/content.js +4 -0
  70. package/dist/types/index.d.ts +10 -0
  71. package/dist/types/index.d.ts.map +1 -0
  72. package/dist/types/index.js +5 -0
  73. package/dist/types/isg.d.ts +103 -0
  74. package/dist/types/isg.d.ts.map +1 -0
  75. package/dist/types/isg.js +4 -0
  76. package/dist/types/logging.d.ts +113 -0
  77. package/dist/types/logging.d.ts.map +1 -0
  78. package/dist/types/logging.js +4 -0
  79. package/dist/types/navigation.d.ts +43 -0
  80. package/dist/types/navigation.d.ts.map +1 -0
  81. package/dist/types/navigation.js +4 -0
  82. package/dist/types.d.ts +10 -10
  83. package/dist/types.d.ts.map +1 -1
  84. package/package.json +1 -1
@@ -1,4 +1,10 @@
1
- import type { StatiConfig } from '../types.js';
1
+ import type { StatiConfig } from '../types/index.js';
2
+ /**
3
+ * Builds config file paths for a given directory.
4
+ * @param cwd - Directory to search for config files
5
+ * @returns Array of absolute paths to potential config files
6
+ */
7
+ export declare function getConfigFilePaths(cwd: string): string[];
2
8
  /**
3
9
  * Loads and validates Stati configuration from the project directory.
4
10
  * Searches for configuration files in order: stati.config.ts, stati.config.js, stati.config.mjs
@@ -1 +1 @@
1
- {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAsB/C;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,UAAU,CAAC,GAAG,GAAE,MAAsB,GAAG,OAAO,CAAC,WAAW,CAAC,CA2DlF"}
1
+ {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAgCrD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAExD;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,UAAU,CAAC,GAAG,GAAE,MAAsB,GAAG,OAAO,CAAC,WAAW,CAAC,CAuDlF"}
@@ -2,24 +2,33 @@ import { existsSync } from 'fs';
2
2
  import { join, resolve } from 'path';
3
3
  import { pathToFileURL } from 'url';
4
4
  import { validateISGConfig, ISGConfigurationError } from '../core/isg/validation.js';
5
+ import { DEFAULT_SRC_DIR, DEFAULT_OUT_DIR, DEFAULT_STATIC_DIR, DEFAULT_SITE_TITLE, DEFAULT_DEV_BASE_URL, DEFAULT_TTL_SECONDS, DEFAULT_MAX_AGE_CAP_DAYS, CONFIG_FILE_PATTERNS, } from '../constants.js';
5
6
  /**
6
7
  * Default configuration values for Stati.
7
8
  * Used as fallback when no configuration file is found.
8
9
  */
9
10
  const DEFAULT_CONFIG = {
10
- srcDir: 'site',
11
- outDir: 'dist',
12
- staticDir: 'public',
11
+ srcDir: DEFAULT_SRC_DIR,
12
+ outDir: DEFAULT_OUT_DIR,
13
+ staticDir: DEFAULT_STATIC_DIR,
13
14
  site: {
14
- title: 'My Site',
15
- baseUrl: 'http://localhost:3000',
15
+ title: DEFAULT_SITE_TITLE,
16
+ baseUrl: DEFAULT_DEV_BASE_URL,
16
17
  },
17
18
  isg: {
18
19
  enabled: true,
19
- ttlSeconds: 3600,
20
- maxAgeCapDays: 365,
20
+ ttlSeconds: DEFAULT_TTL_SECONDS,
21
+ maxAgeCapDays: DEFAULT_MAX_AGE_CAP_DAYS,
21
22
  },
22
23
  };
24
+ /**
25
+ * Builds config file paths for a given directory.
26
+ * @param cwd - Directory to search for config files
27
+ * @returns Array of absolute paths to potential config files
28
+ */
29
+ export function getConfigFilePaths(cwd) {
30
+ return CONFIG_FILE_PATTERNS.map((pattern) => join(cwd, pattern));
31
+ }
23
32
  /**
24
33
  * Loads and validates Stati configuration from the project directory.
25
34
  * Searches for configuration files in order: stati.config.ts, stati.config.js, stati.config.mjs
@@ -41,11 +50,7 @@ const DEFAULT_CONFIG = {
41
50
  * @throws {Error} When configuration file exists but contains invalid JavaScript/TypeScript
42
51
  */
43
52
  export async function loadConfig(cwd = process.cwd()) {
44
- const configPaths = [
45
- join(cwd, 'stati.config.ts'),
46
- join(cwd, 'stati.config.js'),
47
- join(cwd, 'stati.config.mjs'),
48
- ];
53
+ const configPaths = getConfigFilePaths(cwd);
49
54
  let configPath = null;
50
55
  for (const path of configPaths) {
51
56
  if (existsSync(path)) {
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Centralized constants for Stati static site generator.
3
+ * This module contains all magic constants used throughout the Stati core package.
4
+ */
5
+ /** Default source directory for content files */
6
+ export declare const DEFAULT_SRC_DIR = "site";
7
+ /** Default output directory for built files */
8
+ export declare const DEFAULT_OUT_DIR = "dist";
9
+ /** Default static assets directory */
10
+ export declare const DEFAULT_STATIC_DIR = "public";
11
+ /** Stati cache directory name */
12
+ export declare const CACHE_DIR_NAME = ".stati";
13
+ /** Cache subdirectory for ISG manifest and related files */
14
+ export declare const CACHE_SUBDIR = "cache";
15
+ /** ISG cache manifest filename */
16
+ export declare const MANIFEST_FILENAME = "manifest.json";
17
+ /** Supported configuration file extensions in order of preference */
18
+ export declare const CONFIG_FILE_EXTENSIONS: readonly [".ts", ".js", ".mjs"];
19
+ /** Configuration file base name */
20
+ export declare const CONFIG_FILE_BASE = "stati.config";
21
+ /** Complete configuration file patterns */
22
+ export declare const CONFIG_FILE_PATTERNS: string[];
23
+ /** Default development server port */
24
+ export declare const DEFAULT_DEV_PORT = 3000;
25
+ /** Default development server host */
26
+ export declare const DEFAULT_DEV_HOST = "localhost";
27
+ /** Default development server base URL */
28
+ export declare const DEFAULT_DEV_BASE_URL = "http://localhost:3000";
29
+ /** Default TTL for cached pages in seconds (6 hours) */
30
+ export declare const DEFAULT_TTL_SECONDS = 21600;
31
+ /** Default maximum age cap for aging rules in days (1 year) */
32
+ export declare const DEFAULT_MAX_AGE_CAP_DAYS = 365;
33
+ /** Clock drift tolerance in milliseconds to prevent rebuild loops */
34
+ export declare const CLOCK_DRIFT_TOLERANCE_MS = 30000;
35
+ /** Seconds in one minute */
36
+ export declare const SECONDS_PER_MINUTE = 60;
37
+ /** Seconds in one hour */
38
+ export declare const SECONDS_PER_HOUR: number;
39
+ /** Seconds in one day */
40
+ export declare const SECONDS_PER_DAY: number;
41
+ /** Seconds in one week */
42
+ export declare const SECONDS_PER_WEEK: number;
43
+ /** Milliseconds in one day */
44
+ export declare const MILLISECONDS_PER_DAY: number;
45
+ /** 5 minutes in seconds - for very fresh content */
46
+ export declare const TTL_5_MINUTES: number;
47
+ /** 30 minutes in seconds - for recent content */
48
+ export declare const TTL_30_MINUTES: number;
49
+ /** 1 hour in seconds - for hourly updates */
50
+ export declare const TTL_1_HOUR: number;
51
+ /** 2 hours in seconds - for bi-hourly updates */
52
+ export declare const TTL_2_HOURS: number;
53
+ /** 6 hours in seconds - default TTL */
54
+ export declare const TTL_6_HOURS = 21600;
55
+ /** 1 day in seconds - for daily content */
56
+ export declare const TTL_1_DAY: number;
57
+ /** 1 week in seconds - for weekly content */
58
+ export declare const TTL_1_WEEK: number;
59
+ /** Eta template file extension */
60
+ export declare const TEMPLATE_EXTENSION = ".eta";
61
+ /** Markdown file extension */
62
+ export declare const MARKDOWN_EXTENSION = ".md";
63
+ /** Layout template filename */
64
+ export declare const LAYOUT_TEMPLATE = "layout.eta";
65
+ /** Partials directory prefix (folders starting with underscore) */
66
+ export declare const PARTIALS_DIR_PREFIX = "_";
67
+ /** Default site title */
68
+ export declare const DEFAULT_SITE_TITLE = "My Stati Site";
69
+ /** Default locale for internationalization */
70
+ export declare const DEFAULT_LOCALE = "en-US";
71
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,iDAAiD;AACjD,eAAO,MAAM,eAAe,SAAS,CAAC;AAEtC,+CAA+C;AAC/C,eAAO,MAAM,eAAe,SAAS,CAAC;AAEtC,sCAAsC;AACtC,eAAO,MAAM,kBAAkB,WAAW,CAAC;AAE3C,iCAAiC;AACjC,eAAO,MAAM,cAAc,WAAW,CAAC;AAEvC,4DAA4D;AAC5D,eAAO,MAAM,YAAY,UAAU,CAAC;AAEpC,kCAAkC;AAClC,eAAO,MAAM,iBAAiB,kBAAkB,CAAC;AAIjD,qEAAqE;AACrE,eAAO,MAAM,sBAAsB,iCAAkC,CAAC;AAEtE,mCAAmC;AACnC,eAAO,MAAM,gBAAgB,iBAAiB,CAAC;AAE/C,2CAA2C;AAC3C,eAAO,MAAM,oBAAoB,UAEhC,CAAC;AAIF,sCAAsC;AACtC,eAAO,MAAM,gBAAgB,OAAO,CAAC;AAErC,sCAAsC;AACtC,eAAO,MAAM,gBAAgB,cAAc,CAAC;AAE5C,0CAA0C;AAC1C,eAAO,MAAM,oBAAoB,0BAAmD,CAAC;AAIrF,wDAAwD;AACxD,eAAO,MAAM,mBAAmB,QAAQ,CAAC;AAEzC,+DAA+D;AAC/D,eAAO,MAAM,wBAAwB,MAAM,CAAC;AAE5C,qEAAqE;AACrE,eAAO,MAAM,wBAAwB,QAAQ,CAAC;AAI9C,4BAA4B;AAC5B,eAAO,MAAM,kBAAkB,KAAK,CAAC;AAErC,0BAA0B;AAC1B,eAAO,MAAM,gBAAgB,QAA0B,CAAC;AAExD,yBAAyB;AACzB,eAAO,MAAM,eAAe,QAAwB,CAAC;AAErD,0BAA0B;AAC1B,eAAO,MAAM,gBAAgB,QAAsB,CAAC;AAEpD,8BAA8B;AAC9B,eAAO,MAAM,oBAAoB,QAAyB,CAAC;AAI3D,oDAAoD;AACpD,eAAO,MAAM,aAAa,QAAyB,CAAC;AAEpD,iDAAiD;AACjD,eAAO,MAAM,cAAc,QAA0B,CAAC;AAEtD,6CAA6C;AAC7C,eAAO,MAAM,UAAU,QAAmB,CAAC;AAE3C,iDAAiD;AACjD,eAAO,MAAM,WAAW,QAAuB,CAAC;AAEhD,uCAAuC;AACvC,eAAO,MAAM,WAAW,QAAsB,CAAC;AAE/C,2CAA2C;AAC3C,eAAO,MAAM,SAAS,QAAkB,CAAC;AAEzC,6CAA6C;AAC7C,eAAO,MAAM,UAAU,QAAmB,CAAC;AAI3C,kCAAkC;AAClC,eAAO,MAAM,kBAAkB,SAAS,CAAC;AAEzC,8BAA8B;AAC9B,eAAO,MAAM,kBAAkB,QAAQ,CAAC;AAExC,+BAA+B;AAC/B,eAAO,MAAM,eAAe,eAAgC,CAAC;AAE7D,mEAAmE;AACnE,eAAO,MAAM,mBAAmB,MAAM,CAAC;AAIvC,yBAAyB;AACzB,eAAO,MAAM,kBAAkB,kBAAkB,CAAC;AAElD,8CAA8C;AAC9C,eAAO,MAAM,cAAc,UAAU,CAAC"}
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Centralized constants for Stati static site generator.
3
+ * This module contains all magic constants used throughout the Stati core package.
4
+ */
5
+ // === Directory and File System Constants ===
6
+ /** Default source directory for content files */
7
+ export const DEFAULT_SRC_DIR = 'site';
8
+ /** Default output directory for built files */
9
+ export const DEFAULT_OUT_DIR = 'dist';
10
+ /** Default static assets directory */
11
+ export const DEFAULT_STATIC_DIR = 'public';
12
+ /** Stati cache directory name */
13
+ export const CACHE_DIR_NAME = '.stati';
14
+ /** Cache subdirectory for ISG manifest and related files */
15
+ export const CACHE_SUBDIR = 'cache';
16
+ /** ISG cache manifest filename */
17
+ export const MANIFEST_FILENAME = 'manifest.json';
18
+ // === Configuration File Constants ===
19
+ /** Supported configuration file extensions in order of preference */
20
+ export const CONFIG_FILE_EXTENSIONS = ['.ts', '.js', '.mjs'];
21
+ /** Configuration file base name */
22
+ export const CONFIG_FILE_BASE = 'stati.config';
23
+ /** Complete configuration file patterns */
24
+ export const CONFIG_FILE_PATTERNS = CONFIG_FILE_EXTENSIONS.map((ext) => `${CONFIG_FILE_BASE}${ext}`);
25
+ // === Development Server Constants ===
26
+ /** Default development server port */
27
+ export const DEFAULT_DEV_PORT = 3000;
28
+ /** Default development server host */
29
+ export const DEFAULT_DEV_HOST = 'localhost';
30
+ /** Default development server base URL */
31
+ export const DEFAULT_DEV_BASE_URL = `http://${DEFAULT_DEV_HOST}:${DEFAULT_DEV_PORT}`;
32
+ // === ISG (Incremental Static Generation) Constants ===
33
+ /** Default TTL for cached pages in seconds (6 hours) */
34
+ export const DEFAULT_TTL_SECONDS = 21600;
35
+ /** Default maximum age cap for aging rules in days (1 year) */
36
+ export const DEFAULT_MAX_AGE_CAP_DAYS = 365;
37
+ /** Clock drift tolerance in milliseconds to prevent rebuild loops */
38
+ export const CLOCK_DRIFT_TOLERANCE_MS = 30000; // 30 seconds
39
+ // === Time Constants (for convenience and clarity) ===
40
+ /** Seconds in one minute */
41
+ export const SECONDS_PER_MINUTE = 60;
42
+ /** Seconds in one hour */
43
+ export const SECONDS_PER_HOUR = 60 * SECONDS_PER_MINUTE;
44
+ /** Seconds in one day */
45
+ export const SECONDS_PER_DAY = 24 * SECONDS_PER_HOUR;
46
+ /** Seconds in one week */
47
+ export const SECONDS_PER_WEEK = 7 * SECONDS_PER_DAY;
48
+ /** Milliseconds in one day */
49
+ export const MILLISECONDS_PER_DAY = SECONDS_PER_DAY * 1000;
50
+ // === Common ISG TTL Values ===
51
+ /** 5 minutes in seconds - for very fresh content */
52
+ export const TTL_5_MINUTES = 5 * SECONDS_PER_MINUTE;
53
+ /** 30 minutes in seconds - for recent content */
54
+ export const TTL_30_MINUTES = 30 * SECONDS_PER_MINUTE;
55
+ /** 1 hour in seconds - for hourly updates */
56
+ export const TTL_1_HOUR = SECONDS_PER_HOUR;
57
+ /** 2 hours in seconds - for bi-hourly updates */
58
+ export const TTL_2_HOURS = 2 * SECONDS_PER_HOUR;
59
+ /** 6 hours in seconds - default TTL */
60
+ export const TTL_6_HOURS = DEFAULT_TTL_SECONDS;
61
+ /** 1 day in seconds - for daily content */
62
+ export const TTL_1_DAY = SECONDS_PER_DAY;
63
+ /** 1 week in seconds - for weekly content */
64
+ export const TTL_1_WEEK = SECONDS_PER_WEEK;
65
+ // === Template and File Extension Constants ===
66
+ /** Eta template file extension */
67
+ export const TEMPLATE_EXTENSION = '.eta';
68
+ /** Markdown file extension */
69
+ export const MARKDOWN_EXTENSION = '.md';
70
+ /** Layout template filename */
71
+ export const LAYOUT_TEMPLATE = `layout${TEMPLATE_EXTENSION}`;
72
+ /** Partials directory prefix (folders starting with underscore) */
73
+ export const PARTIALS_DIR_PREFIX = '_';
74
+ // === Site Configuration Defaults ===
75
+ /** Default site title */
76
+ export const DEFAULT_SITE_TITLE = 'My Stati Site';
77
+ /** Default locale for internationalization */
78
+ export const DEFAULT_LOCALE = 'en-US';
@@ -1,4 +1,4 @@
1
- import type { BuildStats, Logger } from '../types.js';
1
+ import type { BuildStats, Logger } from '../types/index.js';
2
2
  /**
3
3
  * Options for customizing the build process.
4
4
  *
@@ -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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAsB,KAAK,CAAC,OAAO,GAAE,YAAiB,GAAG,OAAO,CAAC,UAAU,CAAC,CAW3E"}
1
+ {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/core/build.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAEV,UAAU,EACV,MAAM,EAKP,MAAM,mBAAmB,CAAC;AAG3B;;;;;;;;;;;;;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;AA4FD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAsB,KAAK,CAAC,OAAO,GAAE,YAAiB,GAAG,OAAO,CAAC,UAAU,CAAC,CAW3E"}
@@ -1,5 +1,4 @@
1
- import fse from 'fs-extra';
2
- const { ensureDir, writeFile, remove, pathExists, stat, readdir, copyFile } = fse;
1
+ import { ensureDir, writeFile, remove, pathExists, stat, readdir, copyFile } from './utils/fs.js';
3
2
  import { join, dirname, relative } from 'path';
4
3
  import { posix } from 'path';
5
4
  import { loadConfig } from '../config/loader.js';
@@ -10,6 +9,7 @@ import { buildNavigation } from './navigation.js';
10
9
  import { loadCacheManifest, saveCacheManifest } from './isg/manifest.js';
11
10
  import { shouldRebuildPage, createCacheEntry, updateCacheEntry } from './isg/builder.js';
12
11
  import { withBuildLock } from './isg/build-lock.js';
12
+ import { resolveOutDir, resolveStaticDir, resolveCacheDir } from './utils/paths.js';
13
13
  /**
14
14
  * Recursively calculates the total size of a directory in bytes.
15
15
  * Used for build statistics.
@@ -87,30 +87,6 @@ const defaultLogger = {
87
87
  processing: (message) => console.log(message),
88
88
  stats: (message) => console.log(message),
89
89
  };
90
- /**
91
- * Formats build statistics for display with prettier output.
92
- *
93
- * @param stats - Build statistics to format
94
- * @returns Formatted statistics string
95
- */
96
- function formatBuildStats(stats) {
97
- const sizeKB = (stats.outputSizeBytes / 1024).toFixed(1);
98
- const timeSeconds = (stats.buildTimeMs / 1000).toFixed(2);
99
- let output = `Build Statistics:
100
- ┌─────────────────────────────────────────┐
101
- │ Build time: ${timeSeconds}s`.padEnd(41) + '│';
102
- output += `\n│ 📄 Pages built: ${stats.totalPages}`.padEnd(42) + '│';
103
- output += `\n│ 📦 Assets copied: ${stats.assetsCount}`.padEnd(42) + '│';
104
- output += `\n│ Output size: ${sizeKB} KB`.padEnd(42) + '│';
105
- if (stats.cacheHits !== undefined && stats.cacheMisses !== undefined) {
106
- const totalCacheRequests = stats.cacheHits + stats.cacheMisses;
107
- const hitRate = totalCacheRequests > 0 ? ((stats.cacheHits / totalCacheRequests) * 100).toFixed(1) : '0';
108
- output +=
109
- `\n│ Cache hits: ${stats.cacheHits}/${totalCacheRequests} (${hitRate}%)`.padEnd(42) + '│';
110
- }
111
- output += '\n└─────────────────────────────────────────┘';
112
- return output;
113
- }
114
90
  /**
115
91
  * Builds the Stati site with ISG support.
116
92
  * Processes all pages and assets, with smart caching for incremental builds.
@@ -143,7 +119,7 @@ function formatBuildStats(stats) {
143
119
  * ```
144
120
  */
145
121
  export async function build(options = {}) {
146
- const cacheDir = join(process.cwd(), '.stati');
122
+ const cacheDir = resolveCacheDir();
147
123
  // Ensure cache directory exists before acquiring build lock
148
124
  await ensureDir(cacheDir);
149
125
  // Use build lock to prevent concurrent builds, with force option to override
@@ -153,20 +129,21 @@ export async function build(options = {}) {
153
129
  });
154
130
  }
155
131
  /**
156
- * Internal build implementation without locking.
157
- * Separated for cleaner error handling and testing.
132
+ * Loads and validates configuration, returning config and output directory.
158
133
  */
159
- async function buildInternal(options = {}) {
160
- const buildStartTime = Date.now();
161
- const logger = options.logger || defaultLogger;
162
- logger.building('Building your site...');
163
- console.log(); // Add spacing after build start
134
+ async function loadAndValidateConfig(options) {
164
135
  // Load configuration
165
136
  const config = await loadConfig(options.configPath ? dirname(options.configPath) : process.cwd());
166
- const outDir = join(process.cwd(), config.outDir);
137
+ const outDir = resolveOutDir(config);
138
+ const cacheDir = resolveCacheDir();
167
139
  // Create .stati cache directory
168
- const cacheDir = join(process.cwd(), '.stati');
169
140
  await ensureDir(cacheDir);
141
+ return { config, outDir, cacheDir };
142
+ }
143
+ /**
144
+ * Sets up cache manifest and initializes cache statistics.
145
+ */
146
+ async function setupCacheAndManifest(cacheDir) {
170
147
  // Load cache manifest for ISG
171
148
  let cacheManifest = await loadCacheManifest(cacheDir);
172
149
  // If no cache manifest exists, create an empty one
@@ -177,15 +154,12 @@ async function buildInternal(options = {}) {
177
154
  }
178
155
  // At this point cacheManifest is guaranteed to be non-null
179
156
  const manifest = cacheManifest;
180
- // Initialize cache stats
181
- let cacheHits = 0;
182
- let cacheMisses = 0;
183
- // Clean output directory if requested
184
- if (options.clean) {
185
- logger.info('Cleaning output directory...');
186
- await remove(outDir);
187
- }
188
- await ensureDir(outDir);
157
+ return { manifest };
158
+ }
159
+ /**
160
+ * Loads content and builds navigation.
161
+ */
162
+ async function loadContentAndBuildNavigation(config, options, logger) {
189
163
  // Load all content
190
164
  const pages = await loadContent(config, options.includeDrafts);
191
165
  logger.info(`📄 Found ${pages.length} pages`);
@@ -199,9 +173,18 @@ async function buildInternal(options = {}) {
199
173
  // Display navigation tree if the logger supports it
200
174
  if (logger.navigationTree) {
201
175
  logger.navigationTree(navigation);
202
- } // Create processors
176
+ }
177
+ // Create processors
203
178
  const md = await createMarkdownProcessor(config);
204
179
  const eta = createTemplateEngine(config);
180
+ return { pages, navigation, md, eta };
181
+ }
182
+ /**
183
+ * Processes pages with ISG caching logic.
184
+ */
185
+ async function processPagesWithCache(pages, manifest, config, outDir, md, eta, navigation, buildTime, options, logger) {
186
+ let cacheHits = 0;
187
+ let cacheMisses = 0;
205
188
  // Build context
206
189
  const buildContext = { config, pages };
207
190
  // Run beforeAll hook
@@ -216,7 +199,6 @@ async function buildInternal(options = {}) {
216
199
  if (logger.startRenderingTree) {
217
200
  logger.startRenderingTree('Page Rendering Process');
218
201
  }
219
- const buildTime = new Date();
220
202
  for (let i = 0; i < pages.length; i++) {
221
203
  const page = pages[i];
222
204
  if (!page)
@@ -304,31 +286,34 @@ async function buildInternal(options = {}) {
304
286
  }
305
287
  // Display final rendering tree and clear it
306
288
  if (logger.showRenderingTree) {
307
- console.log(); // Add spacing
308
289
  logger.showRenderingTree();
309
290
  if (logger.clearRenderingTree) {
310
291
  logger.clearRenderingTree();
311
292
  }
312
293
  }
313
- // Save updated cache manifest
314
- await saveCacheManifest(cacheDir, manifest);
315
- // Copy static assets and count them
316
- let assetsCount = 0;
317
- const staticDir = join(process.cwd(), config.staticDir);
318
- if (await pathExists(staticDir)) {
319
- console.log(); // Add spacing before asset copying
320
- if (logger.step) {
321
- logger.step(3, 3, 'Copying static assets');
322
- }
323
- logger.info(`Copying static assets from ${config.staticDir}`);
324
- assetsCount = await copyStaticAssetsWithLogging(staticDir, outDir, logger);
325
- logger.info(`Copied ${assetsCount} static assets`);
294
+ return { cacheHits, cacheMisses };
295
+ }
296
+ /**
297
+ * Copies static assets and returns the count.
298
+ */
299
+ async function copyStaticAssets(config, outDir, logger) {
300
+ const staticDir = resolveStaticDir(config);
301
+ if (!(await pathExists(staticDir))) {
302
+ return 0;
326
303
  }
327
- // Run afterAll hook
328
- if (config.hooks?.afterAll) {
329
- await config.hooks.afterAll(buildContext);
304
+ console.log(); // Add spacing before asset copying
305
+ if (logger.step) {
306
+ logger.step(3, 3, 'Copying static assets');
330
307
  }
331
- // Calculate build statistics
308
+ logger.info(`Copying static assets from ${config.staticDir}`);
309
+ const assetsCount = await copyStaticAssetsWithLogging(staticDir, outDir, logger);
310
+ logger.info(`Copied ${assetsCount} static assets`);
311
+ return assetsCount;
312
+ }
313
+ /**
314
+ * Generates build statistics.
315
+ */
316
+ async function generateBuildStats(pages, assetsCount, buildStartTime, outDir, cacheHits, cacheMisses, logger) {
332
317
  const buildEndTime = Date.now();
333
318
  const buildStats = {
334
319
  totalPages: pages.length,
@@ -339,13 +324,53 @@ async function buildInternal(options = {}) {
339
324
  cacheHits,
340
325
  cacheMisses,
341
326
  };
342
- console.log(); // Add spacing before statistics
343
- // Use table format if available, otherwise fall back to formatted string
344
327
  if (logger.statsTable) {
328
+ console.log(); // Add spacing before statistics
345
329
  logger.statsTable(buildStats);
330
+ console.log(); // Add spacing after statistics
346
331
  }
347
- else {
348
- logger.stats(formatBuildStats(buildStats));
332
+ return buildStats;
333
+ }
334
+ /**
335
+ * Internal build implementation without locking.
336
+ * Separated for cleaner error handling and testing.
337
+ */
338
+ async function buildInternal(options = {}) {
339
+ const buildStartTime = Date.now();
340
+ const logger = options.logger || defaultLogger;
341
+ logger.building('Building your site...');
342
+ // Load configuration
343
+ const { config, outDir, cacheDir } = await loadAndValidateConfig(options);
344
+ // Load cache manifest for ISG
345
+ const { manifest } = await setupCacheAndManifest(cacheDir);
346
+ // Initialize cache stats
347
+ let cacheHits = 0;
348
+ let cacheMisses = 0;
349
+ // Clean output directory if requested
350
+ if (options.clean) {
351
+ logger.info('Cleaning output directory...');
352
+ await remove(outDir);
349
353
  }
354
+ await ensureDir(outDir);
355
+ // Load content and build navigation
356
+ console.log(); // Add spacing before content loading
357
+ const { pages, navigation, md, eta } = await loadContentAndBuildNavigation(config, options, logger);
358
+ // Process pages with ISG caching logic
359
+ console.log(); // Add spacing before page processing
360
+ const buildTime = new Date();
361
+ const pageProcessingResult = await processPagesWithCache(pages, manifest, config, outDir, md, eta, navigation, buildTime, options, logger);
362
+ cacheHits = pageProcessingResult.cacheHits;
363
+ cacheMisses = pageProcessingResult.cacheMisses;
364
+ // Save updated cache manifest
365
+ await saveCacheManifest(cacheDir, manifest);
366
+ // Copy static assets and count them
367
+ let assetsCount = 0;
368
+ assetsCount = await copyStaticAssets(config, outDir, logger);
369
+ // Run afterAll hook
370
+ if (config.hooks?.afterAll) {
371
+ await config.hooks.afterAll({ config, pages });
372
+ }
373
+ // Calculate build statistics
374
+ const buildStats = await generateBuildStats(pages, assetsCount, buildStartTime, outDir, cacheHits, cacheMisses, logger);
350
375
  return buildStats;
351
376
  }
@@ -1,4 +1,4 @@
1
- import type { PageModel, StatiConfig } from '../types.js';
1
+ import type { PageModel, StatiConfig } from '../types/index.js';
2
2
  /**
3
3
  * Loads and parses all content files from the configured source directory.
4
4
  *
@@ -1 +1 @@
1
- {"version":3,"file":"content.d.ts","sourceRoot":"","sources":["../../src/core/content.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1D;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,WAAW,CAC/B,MAAM,EAAE,WAAW,EACnB,aAAa,CAAC,EAAE,OAAO,GACtB,OAAO,CAAC,SAAS,EAAE,CAAC,CAyCtB"}
1
+ {"version":3,"file":"content.d.ts","sourceRoot":"","sources":["../../src/core/content.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAIhE;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,WAAW,CAC/B,MAAM,EAAE,WAAW,EACnB,aAAa,CAAC,EAAE,OAAO,GACtB,OAAO,CAAC,SAAS,EAAE,CAAC,CA6CtB"}
@@ -1,8 +1,9 @@
1
1
  import glob from 'fast-glob';
2
- import fse from 'fs-extra';
3
- const { readFile } = fse;
2
+ import { readFile } from './utils/fs.js';
4
3
  import matter from 'gray-matter';
5
- import { join, relative, dirname, basename } from 'path';
4
+ import { relative, dirname, basename } from 'path';
5
+ import { MARKDOWN_EXTENSION } from '../constants.js';
6
+ import { resolveSrcDir } from './utils/paths.js';
6
7
  /**
7
8
  * Loads and parses all content files from the configured source directory.
8
9
  *
@@ -20,7 +21,7 @@ import { join, relative, dirname, basename } from 'path';
20
21
  * ```
21
22
  */
22
23
  export async function loadContent(config, includeDrafts) {
23
- const contentDir = join(process.cwd(), config.srcDir);
24
+ const contentDir = resolveSrcDir(config);
24
25
  // Exclude folders starting with underscore from content discovery
25
26
  const files = await glob('**/*.md', {
26
27
  cwd: contentDir,
@@ -30,6 +31,10 @@ export async function loadContent(config, includeDrafts) {
30
31
  const pages = [];
31
32
  for (const file of files) {
32
33
  const content = await readFile(file, 'utf-8');
34
+ if (!content) {
35
+ console.warn(`Skipping file ${file}: could not read content`);
36
+ continue;
37
+ }
33
38
  const { data: frontMatter, content: markdown } = matter(content);
34
39
  // Skip drafts unless explicitly included
35
40
  if (frontMatter.draft && !includeDrafts) {
@@ -54,7 +59,7 @@ export async function loadContent(config, includeDrafts) {
54
59
  }
55
60
  function computeSlug(relativePath) {
56
61
  const dir = dirname(relativePath);
57
- const name = basename(relativePath, '.md');
62
+ const name = basename(relativePath, MARKDOWN_EXTENSION);
58
63
  if (name === 'index') {
59
64
  return dir === '.' ? '/' : `/${dir}`;
60
65
  }
@@ -1,4 +1,4 @@
1
- import type { Logger } from '../types.js';
1
+ import type { Logger } from '../types/index.js';
2
2
  export interface DevServerOptions {
3
3
  port?: number;
4
4
  host?: string;
@@ -11,11 +11,5 @@ export interface DevServer {
11
11
  stop(): Promise<void>;
12
12
  url: string;
13
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
14
  export declare function createDevServer(options?: DevServerOptions): Promise<DevServer>;
21
15
  //# sourceMappingURL=dev.d.ts.map
@@ -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,CAoaxF"}
1
+ {"version":3,"file":"dev.d.ts","sourceRoot":"","sources":["../../src/core/dev.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAe,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAS7D,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;AAyMD,wBAAsB,eAAe,CAAC,OAAO,GAAE,gBAAqB,GAAG,OAAO,CAAC,SAAS,CAAC,CAgTxF"}