@kimesh/layers 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,3 @@
1
+ # @kimesh/layers
2
+
3
+ Part of the [Kimesh](https://github.com/kimesh/kimesh) framework.
@@ -0,0 +1,357 @@
1
+ //#region src/types.d.ts
2
+ /**
3
+ * @kimesh/layers - Type definitions
4
+ *
5
+ * This module defines the core types for the Kimesh layer system.
6
+ */
7
+ /**
8
+ * Configuration for a single layer in kimesh.config.ts
9
+ */
10
+ interface KimeshLayerConfig {
11
+ /** Layer name (e.g., '@kimesh-layers/cms' or 'cms') */
12
+ name: string;
13
+ /** Path to the layer root directory */
14
+ path: string;
15
+ /** Routes configuration for this layer */
16
+ routes?: LayerRouteConfig;
17
+ /** Component configuration for this layer */
18
+ components?: LayerComponentConfig;
19
+ /** Composable configuration for this layer */
20
+ composables?: LayerComposableConfig;
21
+ /** Utils configuration for this layer */
22
+ utils?: LayerUtilsConfig;
23
+ /** Stores configuration for this layer */
24
+ stores?: LayerStoresConfig;
25
+ /** Auto-import configuration for this layer */
26
+ autoImport?: LayerAutoImportConfig;
27
+ /** CSS files to include from this layer */
28
+ css?: string[];
29
+ /** Dependencies required by this layer */
30
+ dependencies?: string[];
31
+ }
32
+ /**
33
+ * Extended layer configuration (from `extends` array)
34
+ * Can be a string path or full config object
35
+ */
36
+ type ExtendedLayerConfig = string | KimeshLayerConfig;
37
+ /**
38
+ * Route configuration for a layer
39
+ */
40
+ interface LayerRouteConfig {
41
+ /** Routes directory within the layer (default: 'routes') */
42
+ folder?: string;
43
+ /** Base path prefix for this layer's routes (e.g., '/blog') */
44
+ basePath?: string;
45
+ /** Include patterns for route files */
46
+ include?: string[];
47
+ /** Exclude patterns for route files */
48
+ exclude?: string[];
49
+ }
50
+ /**
51
+ * Component configuration for a layer
52
+ */
53
+ interface LayerComponentConfig {
54
+ /** Component directories to scan */
55
+ dirs?: string[];
56
+ /** Prefix for component names (e.g., 'Cms' → CmsButton) */
57
+ prefix?: string | false;
58
+ /** Register components globally */
59
+ global?: boolean;
60
+ /** File extensions to scan */
61
+ extensions?: string[];
62
+ }
63
+ /**
64
+ * Composable configuration for a layer
65
+ */
66
+ interface LayerComposableConfig {
67
+ /** Composable directories to scan */
68
+ dirs?: string[];
69
+ /** File extensions to scan */
70
+ extensions?: string[];
71
+ }
72
+ /**
73
+ * Utils configuration for a layer
74
+ */
75
+ interface LayerUtilsConfig {
76
+ /** Utils directories to scan */
77
+ dirs?: string[];
78
+ /** File extensions to scan */
79
+ extensions?: string[];
80
+ }
81
+ /**
82
+ * Stores configuration for a layer
83
+ */
84
+ interface LayerStoresConfig {
85
+ /** Stores directories to scan */
86
+ dirs?: string[];
87
+ }
88
+ /**
89
+ * Auto-import configuration for a layer
90
+ */
91
+ interface LayerAutoImportConfig {
92
+ /** Additional imports specific to this layer */
93
+ imports?: Array<string | {
94
+ from: string;
95
+ imports: string[];
96
+ }>;
97
+ }
98
+ /**
99
+ * Resolved layer with all metadata
100
+ */
101
+ interface ResolvedLayer {
102
+ /** Layer name */
103
+ name: string;
104
+ /** Absolute path to layer root */
105
+ path: string;
106
+ /** Priority (0 = app level, highest priority) */
107
+ priority: number;
108
+ /** Original configuration */
109
+ config: KimeshLayerConfig;
110
+ /** Layers this layer extends */
111
+ extends: string[];
112
+ /** Whether this is the app layer (priority 0) */
113
+ isApp: boolean;
114
+ /** Source type: 'local', 'npm', or 'workspace' */
115
+ source: "local" | "npm" | "workspace";
116
+ /** Alias mappings for this layer */
117
+ aliases: Record<string, string>;
118
+ /** Runtime config from this layer's kimesh.config.ts */
119
+ runtimeConfig?: Record<string, unknown>;
120
+ }
121
+ /**
122
+ * Layer stack - ordered list of resolved layers
123
+ */
124
+ interface LayerStack {
125
+ /** All layers ordered by priority (0 = highest) */
126
+ layers: ResolvedLayer[];
127
+ /** App layer (priority 0) */
128
+ app: ResolvedLayer;
129
+ /** Layer lookup by name */
130
+ byName: Map<string, ResolvedLayer>;
131
+ /** Total layer count */
132
+ count: number;
133
+ }
134
+ /**
135
+ * Layer resolution options
136
+ */
137
+ interface LayerResolveOptions {
138
+ /** Root directory of the application */
139
+ root: string;
140
+ /** Extended layers from config */
141
+ extends?: ExtendedLayerConfig[];
142
+ /** Auto-scan layers directory */
143
+ autoScan?: boolean;
144
+ /** Layers directory name (default: 'layers') */
145
+ layersDir?: string;
146
+ }
147
+ /**
148
+ * Layer merge result
149
+ */
150
+ interface MergedLayerConfig {
151
+ /** All resolved layers */
152
+ layers: ResolvedLayer[];
153
+ /** Merged routes configuration */
154
+ routes: {
155
+ /** All route directories to scan */dirs: Array<{
156
+ path: string;
157
+ layer: string;
158
+ }>;
159
+ };
160
+ /** Merged component configuration */
161
+ components: {
162
+ /** All component directories to scan */dirs: Array<{
163
+ path: string;
164
+ layer: string;
165
+ prefix?: string;
166
+ }>;
167
+ };
168
+ /** Merged composable configuration */
169
+ composables: {
170
+ /** All composable directories to scan */dirs: Array<{
171
+ path: string;
172
+ layer: string;
173
+ }>;
174
+ };
175
+ /** All CSS files from layers */
176
+ css: string[];
177
+ /** Vite aliases for all layers */
178
+ aliases: Record<string, string>;
179
+ /** Vite fs.allow paths */
180
+ fsAllow: string[];
181
+ /** Merged runtime config from all layers (app layer has highest priority) */
182
+ runtimeConfig: Record<string, unknown>;
183
+ }
184
+ /**
185
+ * Layer conflict information
186
+ */
187
+ interface LayerConflict {
188
+ /** Type of conflict */
189
+ type: "route" | "component" | "composable";
190
+ /** Name of the conflicting item */
191
+ name: string;
192
+ /** Winning layer */
193
+ winner: {
194
+ layer: string;
195
+ path: string;
196
+ };
197
+ /** Losing layers */
198
+ losers: Array<{
199
+ layer: string;
200
+ path: string;
201
+ }>;
202
+ }
203
+ //#endregion
204
+ //#region src/resolve.d.ts
205
+ /**
206
+ * Resolve all layers from configuration and auto-scanning
207
+ *
208
+ * Priority order (0 = highest):
209
+ * - 0: App (application src/)
210
+ * - 1+: Layers from extends[] array (order preserved)
211
+ * - N+: Auto-scanned layers/ directory (alphabetical)
212
+ */
213
+ declare function resolveLayers(options: LayerResolveOptions): Promise<LayerStack>;
214
+ /**
215
+ * Filter layers by enabled list
216
+ */
217
+ declare function filterLayersByEnabled(stack: LayerStack, enabled: string[] | 'all' | 'none'): LayerStack;
218
+ /**
219
+ * Get layer by name
220
+ */
221
+ declare function getLayer(stack: LayerStack, name: string): ResolvedLayer | undefined;
222
+ /**
223
+ * Check if a layer exists in the stack
224
+ */
225
+ declare function hasLayer(stack: LayerStack, name: string): boolean;
226
+ //#endregion
227
+ //#region src/merge.d.ts
228
+ /**
229
+ * Merge all layer configurations into a single unified config
230
+ *
231
+ * Merge strategy:
232
+ * - Routes: Collect from all layers (routes must be in correct directory structure)
233
+ * - Components: Collect from all layers, apply prefixes
234
+ * - Composables: Collect from all layers
235
+ * - CSS: Concatenate all CSS files
236
+ * - Aliases: Build complete alias map
237
+ */
238
+ declare function mergeLayerConfigs(stack: LayerStack): MergedLayerConfig;
239
+ /**
240
+ * Merge two configs with priority (using defu)
241
+ * Higher priority config values take precedence
242
+ */
243
+ declare function mergeConfigs<T extends object>(highPriority: T, lowPriority: T): T;
244
+ /**
245
+ * Detect conflicts between layers
246
+ */
247
+ declare function detectConflicts(merged: MergedLayerConfig): LayerConflict[];
248
+ //#endregion
249
+ //#region src/aliases.d.ts
250
+ /**
251
+ * Standard alias patterns for layers
252
+ */
253
+ declare const ALIAS_PATTERNS: {
254
+ /** Layer root: #layer-name -> /path/to/layer */readonly LAYER_ROOT: "#"; /** Layer root with tilde: ~layer-name -> /path/to/layer */
255
+ readonly LAYER_TILDE: "~"; /** Layer source: @layer-name -> /path/to/layer/src (or layer root) */
256
+ readonly LAYER_AT: "@";
257
+ };
258
+ /**
259
+ * Create aliases for a single layer
260
+ *
261
+ * Generated aliases:
262
+ * - #layer-name -> layer root
263
+ * - ~layer-name -> layer root
264
+ * - @layer-name -> layer src/ or root
265
+ * - #layer-name/routes -> layer routes/
266
+ * - #layer-name/components -> layer components/
267
+ * - #layer-name/composables -> layer composables/
268
+ */
269
+ declare function createLayerAliases(layerName: string, layerPath: string): Record<string, string>;
270
+ /**
271
+ * Build all aliases from merged layer config
272
+ */
273
+ declare function buildViteAliases(merged: MergedLayerConfig): Record<string, string>;
274
+ /**
275
+ * Generate aliases from a ResolvedLayer array
276
+ * This is a convenience function for kit integration
277
+ */
278
+ declare function generateLayerAliasesFromLayers(layers: ResolvedLayer[]): Record<string, string>;
279
+ /**
280
+ * Build Vite fs.allow array from layer paths
281
+ */
282
+ declare function buildFsAllow(merged: MergedLayerConfig): string[];
283
+ /**
284
+ * Generate Vite resolve.alias configuration
285
+ */
286
+ declare function generateViteAliasConfig(merged: MergedLayerConfig): Array<{
287
+ find: string | RegExp;
288
+ replacement: string;
289
+ }>;
290
+ /**
291
+ * Generate TypeScript paths configuration for tsconfig.json
292
+ */
293
+ declare function generateTsConfigPaths(merged: MergedLayerConfig, baseUrl?: string): Record<string, string[]>;
294
+ /**
295
+ * Generate virtual module resolving layer information
296
+ */
297
+ declare function generateLayerInfoModule(stack: LayerStack): string;
298
+ //#endregion
299
+ //#region src/index.d.ts
300
+ /**
301
+ * Options for prepareLayers when using (root, options) signature
302
+ */
303
+ interface PrepareLayersOptions {
304
+ enabled?: string[] | "all" | "none";
305
+ excluded?: string[];
306
+ }
307
+ /**
308
+ * Result type for prepareLayers with options object signature
309
+ */
310
+ interface PrepareLayersResult {
311
+ merged: MergedLayerConfig;
312
+ aliases: Record<string, string>;
313
+ fsAllow: string[];
314
+ }
315
+ /**
316
+ * Prepare layers from a root directory with filtering options.
317
+ * Returns an array of resolved layers.
318
+ *
319
+ * @example
320
+ * ```ts
321
+ * const layers = await prepareLayersFromRoot(process.cwd(), {
322
+ * enabled: ['blog', 'auth'],
323
+ * excluded: [],
324
+ * });
325
+ * ```
326
+ */
327
+ declare function prepareLayersFromRoot(root: string, options?: PrepareLayersOptions): Promise<ResolvedLayer[]>;
328
+ /**
329
+ * Prepare layers with full configuration options.
330
+ * Returns merged config, aliases, and fsAllow paths.
331
+ *
332
+ * @example
333
+ * ```ts
334
+ * const { merged, aliases, fsAllow } = await prepareLayersWithConfig({
335
+ * root: process.cwd(),
336
+ * extends: ['./layers/cms'],
337
+ * });
338
+ * ```
339
+ */
340
+ declare function prepareLayersWithConfig(options: LayerResolveOptions & {
341
+ enabled?: string[] | "all" | "none";
342
+ }): Promise<PrepareLayersResult>;
343
+ /**
344
+ * High-level utility to resolve and filter layers.
345
+ *
346
+ * Supports two call signatures:
347
+ * - `prepareLayers(root, options)` - Returns ResolvedLayer[]
348
+ * - `prepareLayers(options)` - Returns { merged, aliases, fsAllow }
349
+ *
350
+ * @deprecated Use prepareLayersFromRoot or prepareLayersWithConfig for clearer intent
351
+ */
352
+ declare function prepareLayers(rootOrOptions: string | (LayerResolveOptions & {
353
+ enabled?: string[] | "all" | "none";
354
+ }), options?: PrepareLayersOptions): Promise<ResolvedLayer[] | PrepareLayersResult>;
355
+ //#endregion
356
+ export { ALIAS_PATTERNS, type ExtendedLayerConfig, type KimeshLayerConfig, type LayerAutoImportConfig, type LayerComponentConfig, type LayerComposableConfig, type LayerConflict, type LayerResolveOptions, type LayerRouteConfig, type LayerStack, type LayerStoresConfig, type LayerUtilsConfig, type MergedLayerConfig, PrepareLayersOptions, PrepareLayersResult, type ResolvedLayer, buildFsAllow, buildViteAliases, createLayerAliases, detectConflicts, filterLayersByEnabled, generateLayerAliasesFromLayers as generateLayerAliases, generateLayerInfoModule, generateTsConfigPaths, generateViteAliasConfig, getLayer, hasLayer, mergeConfigs, mergeLayerConfigs, prepareLayers, prepareLayersFromRoot, prepareLayersWithConfig, resolveLayers };
357
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/resolve.ts","../src/merge.ts","../src/aliases.ts","../src/index.ts"],"mappings":"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"}
package/dist/index.mjs ADDED
@@ -0,0 +1,750 @@
1
+ import { createRequire } from "node:module";
2
+ import * as fs from "node:fs";
3
+ import * as path from "pathe";
4
+ import { loadConfig } from "c12";
5
+ import { consola } from "consola";
6
+ import { defu } from "defu";
7
+
8
+ //#region rolldown:runtime
9
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
10
+
11
+ //#endregion
12
+ //#region src/aliases.ts
13
+ /**
14
+ * @kimesh/layers - Path Aliasing
15
+ *
16
+ * This module generates per-layer path aliases for Vite configuration.
17
+ */
18
+ /**
19
+ * Standard alias patterns for layers
20
+ */
21
+ const ALIAS_PATTERNS = {
22
+ LAYER_ROOT: "#",
23
+ LAYER_TILDE: "~",
24
+ LAYER_AT: "@"
25
+ };
26
+ const SUB_DIRS = [
27
+ "routes",
28
+ "components",
29
+ "composables",
30
+ "utils",
31
+ "types",
32
+ "stores"
33
+ ];
34
+ /**
35
+ * Create aliases for a single layer
36
+ *
37
+ * Generated aliases:
38
+ * - #layer-name -> layer root
39
+ * - ~layer-name -> layer root
40
+ * - @layer-name -> layer src/ or root
41
+ * - #layer-name/routes -> layer routes/
42
+ * - #layer-name/components -> layer components/
43
+ * - #layer-name/composables -> layer composables/
44
+ */
45
+ function createLayerAliases(layerName, layerPath) {
46
+ const aliases = {};
47
+ const aliasName = sanitizeLayerName(layerName);
48
+ const srcPath = path.join(layerPath, "src");
49
+ aliases[`#${aliasName}`] = layerPath;
50
+ aliases[`~${aliasName}`] = layerPath;
51
+ aliases[`@${aliasName}`] = getLayerSourcePath(layerPath);
52
+ for (const subDir of SUB_DIRS) {
53
+ const rootSubDir = path.join(layerPath, subDir);
54
+ const srcSubDir = path.join(srcPath, subDir);
55
+ if (fs.existsSync(rootSubDir)) aliases[`#${aliasName}/${subDir}`] = rootSubDir;
56
+ if (fs.existsSync(srcSubDir)) aliases[`@${aliasName}/${subDir}`] = srcSubDir;
57
+ }
58
+ return aliases;
59
+ }
60
+ /**
61
+ * Sanitize layer name for use in aliases
62
+ *
63
+ * @example
64
+ * '@kimesh-layers/cms' -> 'kimesh-layers-cms'
65
+ * '@company/layer-auth' -> 'company-layer-auth'
66
+ * 'my-layer' -> 'my-layer'
67
+ */
68
+ function sanitizeLayerName(layerName) {
69
+ return layerName.replace(/^@/, "").replace(/\//g, "-");
70
+ }
71
+ /**
72
+ * Get source path for a layer (src/ if exists, otherwise root)
73
+ */
74
+ function getLayerSourcePath(layerPath) {
75
+ const srcPath = path.join(layerPath, "src");
76
+ return fs.existsSync(srcPath) ? srcPath : layerPath;
77
+ }
78
+ /**
79
+ * Add global app aliases (@ and ~) for the app layer
80
+ */
81
+ function addAppAliases(aliases, appLayer) {
82
+ aliases["@"] = getLayerSourcePath(appLayer.path);
83
+ aliases["~"] = appLayer.path;
84
+ }
85
+ /**
86
+ * Build all aliases from merged layer config
87
+ */
88
+ function buildViteAliases(merged) {
89
+ const aliases = { ...merged.aliases };
90
+ const appLayer = merged.layers.find((l) => l.isApp);
91
+ if (appLayer) addAppAliases(aliases, appLayer);
92
+ return aliases;
93
+ }
94
+ /**
95
+ * Generate aliases from a ResolvedLayer array
96
+ * This is a convenience function for kit integration
97
+ */
98
+ function generateLayerAliasesFromLayers(layers) {
99
+ const aliases = {};
100
+ for (const layer of layers) Object.assign(aliases, createLayerAliases(layer.name, layer.path));
101
+ const appLayer = layers.find((l) => l.isApp);
102
+ if (appLayer) addAppAliases(aliases, appLayer);
103
+ return aliases;
104
+ }
105
+ /**
106
+ * Build Vite fs.allow array from layer paths
107
+ */
108
+ function buildFsAllow(merged) {
109
+ const allow = new Set(merged.fsAllow);
110
+ for (const layer of merged.layers) if (layer.source === "npm" || layer.source === "workspace") {
111
+ const nodeModulesPath = findNodeModulesParent(layer.path);
112
+ if (nodeModulesPath) allow.add(nodeModulesPath);
113
+ }
114
+ return Array.from(allow);
115
+ }
116
+ /**
117
+ * Find the nearest node_modules parent directory
118
+ */
119
+ function findNodeModulesParent(filePath) {
120
+ let current = filePath;
121
+ while (current !== path.dirname(current)) {
122
+ if (path.basename(current) === "node_modules") return current;
123
+ current = path.dirname(current);
124
+ }
125
+ return null;
126
+ }
127
+ /**
128
+ * Generate Vite resolve.alias configuration
129
+ */
130
+ function generateViteAliasConfig(merged) {
131
+ const aliases = buildViteAliases(merged);
132
+ return Object.keys(aliases).sort((a, b) => b.length - a.length).map((key) => ({
133
+ find: key,
134
+ replacement: aliases[key]
135
+ }));
136
+ }
137
+ /**
138
+ * Generate TypeScript paths configuration for tsconfig.json
139
+ */
140
+ function generateTsConfigPaths(merged, baseUrl = ".") {
141
+ const paths = {};
142
+ const aliases = buildViteAliases(merged);
143
+ for (const [alias, target] of Object.entries(aliases)) {
144
+ const relativePath = path.relative(baseUrl, target);
145
+ paths[alias] = [relativePath];
146
+ paths[`${alias}/*`] = [`${relativePath}/*`];
147
+ }
148
+ return paths;
149
+ }
150
+ /**
151
+ * Generate virtual module resolving layer information
152
+ */
153
+ function generateLayerInfoModule(stack) {
154
+ const layersInfo = stack.layers.map((layer) => ({
155
+ name: layer.name,
156
+ path: layer.path,
157
+ priority: layer.priority,
158
+ source: layer.source,
159
+ isApp: layer.isApp
160
+ }));
161
+ return `
162
+ // Auto-generated by @kimesh/layers
163
+ // DO NOT EDIT
164
+
165
+ export const layers = ${JSON.stringify(layersInfo, null, 2)} as const;
166
+
167
+ export type LayerName = typeof layers[number]['name'];
168
+
169
+ export function getLayer(name: LayerName) {
170
+ return layers.find(l => l.name === name);
171
+ }
172
+
173
+ export const appLayer = ${JSON.stringify(layersInfo.find((l) => l.isApp))} as const;
174
+ `.trim();
175
+ }
176
+
177
+ //#endregion
178
+ //#region src/resolve.ts
179
+ /**
180
+ * @kimesh/layers - Layer Resolution
181
+ *
182
+ * This module handles layer discovery, resolution, and priority ordering.
183
+ */
184
+ const logger$1 = consola.withTag("kimesh:layers");
185
+ /**
186
+ * Resolve all layers from configuration and auto-scanning
187
+ *
188
+ * Priority order (0 = highest):
189
+ * - 0: App (application src/)
190
+ * - 1+: Layers from extends[] array (order preserved)
191
+ * - N+: Auto-scanned layers/ directory (alphabetical)
192
+ */
193
+ async function resolveLayers(options) {
194
+ const { root, extends: extendedLayers = [], autoScan = true, layersDir = "layers" } = options;
195
+ const startTime = performance.now();
196
+ const layers = [];
197
+ const visited = /* @__PURE__ */ new Set();
198
+ const resolving = /* @__PURE__ */ new Set();
199
+ const appLayer = createAppLayer(root);
200
+ layers.push(appLayer);
201
+ visited.add("app");
202
+ let priority = 1;
203
+ for (const extendedConfig of extendedLayers) {
204
+ const resolved = await resolveExtendedLayer(extendedConfig, root, priority, visited, resolving);
205
+ if (resolved) {
206
+ layers.push(resolved);
207
+ visited.add(resolved.name);
208
+ priority++;
209
+ }
210
+ }
211
+ if (autoScan) {
212
+ const autoScanned = await scanLayersDirectory(path.join(root, layersDir), priority, visited);
213
+ layers.push(...autoScanned);
214
+ }
215
+ const byName = /* @__PURE__ */ new Map();
216
+ for (const layer of layers) byName.set(layer.name, layer);
217
+ const elapsed = performance.now() - startTime;
218
+ logger$1.debug(`Resolved ${layers.length} layers in ${elapsed.toFixed(1)}ms`);
219
+ return {
220
+ layers,
221
+ app: appLayer,
222
+ byName,
223
+ count: layers.length
224
+ };
225
+ }
226
+ /**
227
+ * Create the app layer (priority 0)
228
+ */
229
+ function createAppLayer(root) {
230
+ const srcPath = path.join(root, "src");
231
+ return {
232
+ name: "app",
233
+ path: fs.existsSync(srcPath) ? srcPath : root,
234
+ priority: 0,
235
+ config: {
236
+ name: "app",
237
+ path: root
238
+ },
239
+ extends: [],
240
+ isApp: true,
241
+ source: "local",
242
+ aliases: createLayerAliases("app", root)
243
+ };
244
+ }
245
+ /**
246
+ * Resolve a single extended layer configuration
247
+ */
248
+ async function resolveExtendedLayer(config, root, priority, visited, resolving) {
249
+ const layerConfig = normalizeLayerConfig(config, root);
250
+ if (!layerConfig) {
251
+ logger$1.warn(`Could not normalize layer config: ${JSON.stringify(config)}`);
252
+ return null;
253
+ }
254
+ if (visited.has(layerConfig.name)) {
255
+ logger$1.debug(`Layer '${layerConfig.name}' already resolved, skipping`);
256
+ return null;
257
+ }
258
+ if (resolving.has(layerConfig.name)) throw new Error(`Circular dependency detected: ${[...resolving, layerConfig.name].join(" -> ")}`);
259
+ if (!fs.existsSync(layerConfig.path)) {
260
+ logger$1.warn(`Layer path does not exist: ${layerConfig.path}`);
261
+ return null;
262
+ }
263
+ const loaded = await loadLayerConfig(layerConfig.path);
264
+ const mergedConfig = {
265
+ ...layerConfig,
266
+ ...loaded?.config || {},
267
+ path: layerConfig.path,
268
+ name: loaded?.config?.name || layerConfig.name
269
+ };
270
+ const source = determineLayerSource(layerConfig.path, root);
271
+ return {
272
+ name: mergedConfig.name,
273
+ path: mergedConfig.path,
274
+ priority,
275
+ config: mergedConfig,
276
+ extends: [],
277
+ isApp: false,
278
+ source,
279
+ aliases: createLayerAliases(mergedConfig.name, mergedConfig.path),
280
+ runtimeConfig: loaded?.runtimeConfig
281
+ };
282
+ }
283
+ /**
284
+ * Normalize layer config from string path
285
+ */
286
+ function normalizeStringConfig(configPath, root) {
287
+ if (configPath.startsWith(".") || configPath.startsWith("/")) {
288
+ const absolutePath = path.isAbsolute(configPath) ? configPath : path.resolve(root, configPath);
289
+ return {
290
+ name: path.basename(absolutePath),
291
+ path: absolutePath
292
+ };
293
+ }
294
+ const packagePath = resolvePackagePath(configPath, root);
295
+ if (!packagePath) {
296
+ logger$1.warn(`Could not resolve package: ${configPath}`);
297
+ return null;
298
+ }
299
+ return {
300
+ name: configPath,
301
+ path: packagePath
302
+ };
303
+ }
304
+ /**
305
+ * Normalize layer config from object
306
+ */
307
+ function normalizeObjectConfig(config, root) {
308
+ if (!config.path) {
309
+ logger$1.warn(`Layer config missing path: ${JSON.stringify(config)}`);
310
+ return null;
311
+ }
312
+ const absolutePath = path.isAbsolute(config.path) ? config.path : path.resolve(root, config.path);
313
+ return {
314
+ ...config,
315
+ path: absolutePath
316
+ };
317
+ }
318
+ /**
319
+ * Normalize layer config from string or object
320
+ */
321
+ function normalizeLayerConfig(config, root) {
322
+ if (typeof config === "string") return normalizeStringConfig(config, root);
323
+ return normalizeObjectConfig(config, root);
324
+ }
325
+ /**
326
+ * Resolve NPM package path
327
+ */
328
+ function resolvePackagePath(packageName, root) {
329
+ const possiblePaths = [path.join(root, "node_modules", packageName), path.join(root, "..", "node_modules", packageName)];
330
+ for (const p of possiblePaths) if (fs.existsSync(p)) return p;
331
+ try {
332
+ const resolved = __require.resolve(`${packageName}/package.json`, { paths: [root] });
333
+ return path.dirname(resolved);
334
+ } catch {
335
+ return null;
336
+ }
337
+ }
338
+ /**
339
+ * Check if a path is a symlink
340
+ */
341
+ function isSymlink(filePath) {
342
+ try {
343
+ return fs.lstatSync(filePath).isSymbolicLink();
344
+ } catch {
345
+ return false;
346
+ }
347
+ }
348
+ /**
349
+ * Determine layer source type
350
+ */
351
+ function determineLayerSource(layerPath, _root) {
352
+ if (!layerPath.includes("node_modules")) return "local";
353
+ return isSymlink(layerPath) ? "workspace" : "npm";
354
+ }
355
+ const LAYER_STRUCTURE_MARKERS = [
356
+ "kimesh.config.ts",
357
+ "routes",
358
+ "components",
359
+ "composables"
360
+ ];
361
+ /**
362
+ * Check if a directory has valid layer structure
363
+ */
364
+ function hasLayerStructure(layerPath) {
365
+ return LAYER_STRUCTURE_MARKERS.some((marker) => fs.existsSync(path.join(layerPath, marker)));
366
+ }
367
+ /**
368
+ * Scan layers/ directory for auto-discovered layers
369
+ */
370
+ async function scanLayersDirectory(layersDir, startPriority, visited) {
371
+ if (!fs.existsSync(layersDir)) return [];
372
+ const directories = fs.readdirSync(layersDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).sort((a, b) => a.name.localeCompare(b.name));
373
+ const layers = [];
374
+ let priority = startPriority;
375
+ for (const entry of directories) {
376
+ const layerName = entry.name;
377
+ const layerPath = path.join(layersDir, layerName);
378
+ if (visited.has(layerName)) continue;
379
+ if (!hasLayerStructure(layerPath)) {
380
+ logger$1.debug(`Skipping '${layerName}' - no layer structure detected`);
381
+ continue;
382
+ }
383
+ const loaded = await loadLayerConfig(layerPath);
384
+ const resolved = {
385
+ name: loaded?.config?.name ?? layerName,
386
+ path: layerPath,
387
+ priority,
388
+ config: loaded?.config ?? {
389
+ name: layerName,
390
+ path: layerPath
391
+ },
392
+ extends: [],
393
+ isApp: false,
394
+ source: "local",
395
+ aliases: createLayerAliases(layerName, layerPath),
396
+ runtimeConfig: loaded?.runtimeConfig
397
+ };
398
+ layers.push(resolved);
399
+ visited.add(resolved.name);
400
+ priority++;
401
+ logger$1.debug(`Auto-discovered layer: ${layerName} (priority: ${resolved.priority})`);
402
+ }
403
+ return layers;
404
+ }
405
+ /**
406
+ * Load kimesh.config.ts from a layer directory using c12
407
+ */
408
+ async function loadLayerConfig(layerPath) {
409
+ const configPath = path.join(layerPath, "kimesh.config.ts");
410
+ if (!fs.existsSync(configPath)) return null;
411
+ try {
412
+ const { loadConfig: loadConfig$1 } = await import("c12");
413
+ const { config } = await loadConfig$1({
414
+ name: "kimesh",
415
+ cwd: layerPath,
416
+ extend: false
417
+ });
418
+ if (config) {
419
+ logger$1.debug(`Loaded config from ${configPath}`);
420
+ const { runtimeConfig, ...layerConfig } = config;
421
+ return {
422
+ config: {
423
+ ...layerConfig,
424
+ path: layerPath
425
+ },
426
+ runtimeConfig
427
+ };
428
+ }
429
+ } catch (error) {
430
+ logger$1.warn(`Failed to load config from ${configPath}: ${error}`);
431
+ }
432
+ return null;
433
+ }
434
+ /**
435
+ * Filter layers by enabled list
436
+ */
437
+ function filterLayersByEnabled(stack, enabled) {
438
+ if (enabled === "all") return stack;
439
+ if (enabled === "none") return {
440
+ layers: [stack.app],
441
+ app: stack.app,
442
+ byName: new Map([["app", stack.app]]),
443
+ count: 1
444
+ };
445
+ const enabledSet = new Set(["app", ...enabled]);
446
+ const filtered = stack.layers.filter((layer) => enabledSet.has(layer.name));
447
+ const byName = /* @__PURE__ */ new Map();
448
+ for (const layer of filtered) byName.set(layer.name, layer);
449
+ return {
450
+ layers: filtered,
451
+ app: stack.app,
452
+ byName,
453
+ count: filtered.length
454
+ };
455
+ }
456
+ /**
457
+ * Get layer by name
458
+ */
459
+ function getLayer(stack, name) {
460
+ return stack.byName.get(name);
461
+ }
462
+ /**
463
+ * Check if a layer exists in the stack
464
+ */
465
+ function hasLayer(stack, name) {
466
+ return stack.byName.has(name);
467
+ }
468
+
469
+ //#endregion
470
+ //#region src/merge.ts
471
+ /**
472
+ * @kimesh/layers - Configuration Merging
473
+ *
474
+ * This module handles merging layer configurations with priority-based resolution.
475
+ * Uses defu for deep merging with array concatenation.
476
+ */
477
+ const logger = consola.withTag("kimesh:layers:merge");
478
+ /**
479
+ * Find an existing directory from a list of candidate paths
480
+ */
481
+ function findExistingDir(paths) {
482
+ return paths.find((p) => fs.existsSync(p));
483
+ }
484
+ /**
485
+ * Collect directories from a layer for a given directory name.
486
+ * Checks both root and src/ locations.
487
+ */
488
+ function collectDirsForLayer(layer, dirName, customDirs = [], prefix) {
489
+ const dirs = [];
490
+ const layerPath = layer.path;
491
+ const srcPath = path.join(layerPath, "src");
492
+ const rootDir = path.join(layerPath, dirName);
493
+ const srcDir = path.join(srcPath, dirName);
494
+ if (fs.existsSync(rootDir)) dirs.push({
495
+ path: rootDir,
496
+ layer: layer.name,
497
+ prefix
498
+ });
499
+ if (fs.existsSync(srcDir) && srcDir !== rootDir) dirs.push({
500
+ path: srcDir,
501
+ layer: layer.name,
502
+ prefix
503
+ });
504
+ for (const customDir of customDirs) {
505
+ if (customDir === dirName) continue;
506
+ const customPath = findExistingDir([path.join(layerPath, customDir), path.join(srcPath, customDir)]);
507
+ if (customPath) dirs.push({
508
+ path: customPath,
509
+ layer: layer.name,
510
+ prefix
511
+ });
512
+ }
513
+ return dirs;
514
+ }
515
+ /**
516
+ * Merge all layer configurations into a single unified config
517
+ *
518
+ * Merge strategy:
519
+ * - Routes: Collect from all layers (routes must be in correct directory structure)
520
+ * - Components: Collect from all layers, apply prefixes
521
+ * - Composables: Collect from all layers
522
+ * - CSS: Concatenate all CSS files
523
+ * - Aliases: Build complete alias map
524
+ */
525
+ function mergeLayerConfigs(stack) {
526
+ const startTime = performance.now();
527
+ const routes = { dirs: [] };
528
+ const components = { dirs: [] };
529
+ const composables = { dirs: [] };
530
+ const css = [];
531
+ const aliases = {};
532
+ const fsAllow = [];
533
+ const sortedLayers = [...stack.layers].sort((a, b) => b.priority - a.priority);
534
+ let runtimeConfig = {};
535
+ for (const layer of sortedLayers) if (layer.runtimeConfig) runtimeConfig = defu(runtimeConfig, layer.runtimeConfig);
536
+ for (const layer of sortedLayers) {
537
+ const routeDirs = collectRouteDirs(layer);
538
+ routes.dirs.push(...routeDirs);
539
+ const componentDirs = collectComponentDirs(layer);
540
+ components.dirs.push(...componentDirs);
541
+ const composableDirs = collectComposableDirs(layer);
542
+ composables.dirs.push(...composableDirs);
543
+ const cssFiles = collectCssFiles(layer);
544
+ css.push(...cssFiles);
545
+ Object.assign(aliases, layer.aliases);
546
+ fsAllow.push(layer.path);
547
+ }
548
+ const sortByPriority = (a, b) => {
549
+ return (stack.byName.get(a.layer)?.priority ?? 999) - (stack.byName.get(b.layer)?.priority ?? 999);
550
+ };
551
+ routes.dirs.sort(sortByPriority);
552
+ components.dirs.sort(sortByPriority);
553
+ composables.dirs.sort(sortByPriority);
554
+ const elapsed = performance.now() - startTime;
555
+ logger.debug(`Merged ${stack.count} layers in ${elapsed.toFixed(1)}ms`);
556
+ logger.debug(` Routes dirs: ${routes.dirs.length}`);
557
+ logger.debug(` Component dirs: ${components.dirs.length}`);
558
+ logger.debug(` Composable dirs: ${composables.dirs.length}`);
559
+ logger.debug(` CSS files: ${css.length}`);
560
+ logger.debug(` RuntimeConfig keys: ${Object.keys(runtimeConfig).length}`);
561
+ return {
562
+ layers: stack.layers,
563
+ routes,
564
+ components,
565
+ composables,
566
+ css,
567
+ aliases,
568
+ fsAllow,
569
+ runtimeConfig
570
+ };
571
+ }
572
+ /**
573
+ * Collect route directories from a layer
574
+ */
575
+ function collectRouteDirs(layer) {
576
+ const customFolder = layer.config.routes?.folder;
577
+ return collectDirsForLayer(layer, "routes", customFolder ? [customFolder] : []);
578
+ }
579
+ /**
580
+ * Collect component directories from a layer
581
+ */
582
+ function collectComponentDirs(layer) {
583
+ const prefix = resolveComponentPrefix(layer);
584
+ return collectDirsForLayer(layer, "components", layer.config.components?.dirs ?? [], prefix);
585
+ }
586
+ /**
587
+ * Collect composable directories from a layer
588
+ */
589
+ function collectComposableDirs(layer) {
590
+ const composableDirs = collectDirsForLayer(layer, "composables", layer.config.composables?.dirs ?? []);
591
+ const hooksDirs = collectDirsForLayer(layer, "hooks");
592
+ return [...composableDirs, ...hooksDirs];
593
+ }
594
+ /**
595
+ * Collect CSS files from a layer
596
+ */
597
+ function collectCssFiles(layer) {
598
+ const files = [];
599
+ const configCss = layer.config.css || [];
600
+ for (const cssFile of configCss) {
601
+ const absolutePath = path.isAbsolute(cssFile) ? cssFile : path.join(layer.path, cssFile);
602
+ if (fs.existsSync(absolutePath)) files.push(absolutePath);
603
+ else logger.warn(`CSS file not found: ${absolutePath} (layer: ${layer.name})`);
604
+ }
605
+ return files;
606
+ }
607
+ /**
608
+ * Resolve component prefix for a layer
609
+ *
610
+ * Priority:
611
+ * 1. Explicit prefix in config.components.prefix
612
+ * 2. Derived from layer name: '@kimesh-layers/cms' -> 'Cms'
613
+ * 3. App layer: no prefix
614
+ */
615
+ function resolveComponentPrefix(layer) {
616
+ if (layer.isApp) return;
617
+ const configPrefix = layer.config.components?.prefix;
618
+ if (configPrefix === false) return;
619
+ if (typeof configPrefix === "string") return configPrefix;
620
+ return derivePrefix(layer.name);
621
+ }
622
+ /**
623
+ * Derive a component prefix from layer name
624
+ *
625
+ * Examples:
626
+ * - '@kimesh-layers/cms' -> 'Cms'
627
+ * - '@company/layer-auth' -> 'Auth'
628
+ * - 'cms' -> 'Cms'
629
+ * - 'my-layer' -> 'MyLayer'
630
+ */
631
+ function derivePrefix(layerName) {
632
+ const patterns = [/^@[\w-]+\/(?:layer-)?(.+)$/, /^(?:layer-)?(.+)$/];
633
+ let baseName = layerName;
634
+ for (const pattern of patterns) {
635
+ const match = layerName.match(pattern);
636
+ if (match) {
637
+ baseName = match[1];
638
+ break;
639
+ }
640
+ }
641
+ return toPascalCase(baseName);
642
+ }
643
+ /**
644
+ * Convert string to PascalCase
645
+ */
646
+ function toPascalCase(str) {
647
+ return str.split(/[-_]/).map((part) => part.charAt(0).toUpperCase() + part.slice(1).toLowerCase()).join("");
648
+ }
649
+ /**
650
+ * Merge two configs with priority (using defu)
651
+ * Higher priority config values take precedence
652
+ */
653
+ function mergeConfigs(highPriority, lowPriority) {
654
+ return defu(highPriority, lowPriority);
655
+ }
656
+ /**
657
+ * Detect conflicts between layers
658
+ */
659
+ function detectConflicts(merged) {
660
+ return [];
661
+ }
662
+
663
+ //#endregion
664
+ //#region src/index.ts
665
+ /**
666
+ * @kimesh/layers - Layer System for Kimesh Framework
667
+ *
668
+ * This package provides layer discovery, resolution, and configuration merging
669
+ * for the Kimesh framework's Nuxt-inspired layer architecture.
670
+ *
671
+ * @packageDocumentation
672
+ */
673
+ /**
674
+ * Extract extends array from config file without c12 merging
675
+ */
676
+ async function extractExtendsFromConfig(root) {
677
+ const configPath = path.join(root, "kimesh.config.ts");
678
+ if (!fs.existsSync(configPath)) return [];
679
+ const { config } = await loadConfig({
680
+ name: "kimesh",
681
+ cwd: root,
682
+ extend: false
683
+ });
684
+ return config?.extends ?? [];
685
+ }
686
+ /**
687
+ * Prepare layers from a root directory with filtering options.
688
+ * Returns an array of resolved layers.
689
+ *
690
+ * @example
691
+ * ```ts
692
+ * const layers = await prepareLayersFromRoot(process.cwd(), {
693
+ * enabled: ['blog', 'auth'],
694
+ * excluded: [],
695
+ * });
696
+ * ```
697
+ */
698
+ async function prepareLayersFromRoot(root, options = {}) {
699
+ let stack = await resolveLayers({
700
+ root,
701
+ extends: await extractExtendsFromConfig(root),
702
+ layersDir: "layers"
703
+ });
704
+ if (options.enabled && options.enabled !== "all") stack = filterLayersByEnabled(stack, options.enabled);
705
+ const merged = mergeLayerConfigs(stack);
706
+ if (options.excluded && options.excluded.length > 0) {
707
+ const excludeSet = new Set(options.excluded);
708
+ return merged.layers.filter((layer) => !excludeSet.has(layer.name));
709
+ }
710
+ return merged.layers;
711
+ }
712
+ /**
713
+ * Prepare layers with full configuration options.
714
+ * Returns merged config, aliases, and fsAllow paths.
715
+ *
716
+ * @example
717
+ * ```ts
718
+ * const { merged, aliases, fsAllow } = await prepareLayersWithConfig({
719
+ * root: process.cwd(),
720
+ * extends: ['./layers/cms'],
721
+ * });
722
+ * ```
723
+ */
724
+ async function prepareLayersWithConfig(options) {
725
+ let stack = await resolveLayers(options);
726
+ if (options.enabled) stack = filterLayersByEnabled(stack, options.enabled);
727
+ const merged = mergeLayerConfigs(stack);
728
+ return {
729
+ merged,
730
+ aliases: buildViteAliases(merged),
731
+ fsAllow: buildFsAllow(merged)
732
+ };
733
+ }
734
+ /**
735
+ * High-level utility to resolve and filter layers.
736
+ *
737
+ * Supports two call signatures:
738
+ * - `prepareLayers(root, options)` - Returns ResolvedLayer[]
739
+ * - `prepareLayers(options)` - Returns { merged, aliases, fsAllow }
740
+ *
741
+ * @deprecated Use prepareLayersFromRoot or prepareLayersWithConfig for clearer intent
742
+ */
743
+ async function prepareLayers(rootOrOptions, options) {
744
+ if (typeof rootOrOptions === "string") return prepareLayersFromRoot(rootOrOptions, options);
745
+ return prepareLayersWithConfig(rootOrOptions);
746
+ }
747
+
748
+ //#endregion
749
+ export { ALIAS_PATTERNS, buildFsAllow, buildViteAliases, createLayerAliases, detectConflicts, filterLayersByEnabled, generateLayerAliasesFromLayers as generateLayerAliases, generateLayerInfoModule, generateTsConfigPaths, generateViteAliasConfig, getLayer, hasLayer, mergeConfigs, mergeLayerConfigs, prepareLayers, prepareLayersFromRoot, prepareLayersWithConfig, resolveLayers };
750
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":["logger","loadConfig","loadC12Config"],"sources":["../src/aliases.ts","../src/resolve.ts","../src/merge.ts","../src/index.ts"],"sourcesContent":["/**\n * @kimesh/layers - Path Aliasing\n *\n * This module generates per-layer path aliases for Vite configuration.\n */\n\nimport * as fs from 'node:fs';\nimport * as path from 'pathe';\n\nimport type { LayerStack, MergedLayerConfig, ResolvedLayer } from './types.js';\n\n/**\n * Standard alias patterns for layers\n */\nexport const ALIAS_PATTERNS = {\n /** Layer root: #layer-name -> /path/to/layer */\n LAYER_ROOT: '#',\n\n /** Layer root with tilde: ~layer-name -> /path/to/layer */\n LAYER_TILDE: '~',\n\n /** Layer source: @layer-name -> /path/to/layer/src (or layer root) */\n LAYER_AT: '@',\n} as const;\n\nconst SUB_DIRS = ['routes', 'components', 'composables', 'utils', 'types', 'stores'] as const;\n\n/**\n * Create aliases for a single layer\n *\n * Generated aliases:\n * - #layer-name -> layer root\n * - ~layer-name -> layer root\n * - @layer-name -> layer src/ or root\n * - #layer-name/routes -> layer routes/\n * - #layer-name/components -> layer components/\n * - #layer-name/composables -> layer composables/\n */\nexport function createLayerAliases(\n layerName: string,\n layerPath: string\n): Record<string, string> {\n const aliases: Record<string, string> = {};\n const aliasName = sanitizeLayerName(layerName);\n const srcPath = path.join(layerPath, 'src');\n\n aliases[`#${aliasName}`] = layerPath;\n aliases[`~${aliasName}`] = layerPath;\n aliases[`@${aliasName}`] = getLayerSourcePath(layerPath);\n\n for (const subDir of SUB_DIRS) {\n const rootSubDir = path.join(layerPath, subDir);\n const srcSubDir = path.join(srcPath, subDir);\n\n if (fs.existsSync(rootSubDir)) {\n aliases[`#${aliasName}/${subDir}`] = rootSubDir;\n }\n if (fs.existsSync(srcSubDir)) {\n aliases[`@${aliasName}/${subDir}`] = srcSubDir;\n }\n }\n\n return aliases;\n}\n\n/**\n * Sanitize layer name for use in aliases\n *\n * @example\n * '@kimesh-layers/cms' -> 'kimesh-layers-cms'\n * '@company/layer-auth' -> 'company-layer-auth'\n * 'my-layer' -> 'my-layer'\n */\nfunction sanitizeLayerName(layerName: string): string {\n return layerName\n .replace(/^@/, '')\n .replace(/\\//g, '-');\n}\n\n/**\n * Get source path for a layer (src/ if exists, otherwise root)\n */\nfunction getLayerSourcePath(layerPath: string): string {\n const srcPath = path.join(layerPath, 'src');\n return fs.existsSync(srcPath) ? srcPath : layerPath;\n}\n\n/**\n * Add global app aliases (@ and ~) for the app layer\n */\nfunction addAppAliases(\n aliases: Record<string, string>,\n appLayer: ResolvedLayer\n): void {\n aliases['@'] = getLayerSourcePath(appLayer.path);\n aliases['~'] = appLayer.path;\n}\n\n/**\n * Build all aliases from merged layer config\n */\nexport function buildViteAliases(merged: MergedLayerConfig): Record<string, string> {\n const aliases: Record<string, string> = { ...merged.aliases };\n\n const appLayer = merged.layers.find((l) => l.isApp);\n if (appLayer) {\n addAppAliases(aliases, appLayer);\n }\n\n return aliases;\n}\n\n/**\n * Generate aliases from a ResolvedLayer array\n * This is a convenience function for kit integration\n */\nexport function generateLayerAliasesFromLayers(layers: ResolvedLayer[]): Record<string, string> {\n const aliases: Record<string, string> = {};\n\n for (const layer of layers) {\n Object.assign(aliases, createLayerAliases(layer.name, layer.path));\n }\n\n const appLayer = layers.find((l) => l.isApp);\n if (appLayer) {\n addAppAliases(aliases, appLayer);\n }\n\n return aliases;\n}\n\n/**\n * Build Vite fs.allow array from layer paths\n */\nexport function buildFsAllow(merged: MergedLayerConfig): string[] {\n const allow = new Set<string>(merged.fsAllow);\n\n // Add node_modules for npm layers\n for (const layer of merged.layers) {\n if (layer.source === 'npm' || layer.source === 'workspace') {\n // Add the layer's parent node_modules\n const nodeModulesPath = findNodeModulesParent(layer.path);\n if (nodeModulesPath) {\n allow.add(nodeModulesPath);\n }\n }\n }\n\n return Array.from(allow);\n}\n\n/**\n * Find the nearest node_modules parent directory\n */\nfunction findNodeModulesParent(filePath: string): string | null {\n let current = filePath;\n\n while (current !== path.dirname(current)) {\n if (path.basename(current) === 'node_modules') {\n return current;\n }\n current = path.dirname(current);\n }\n\n return null;\n}\n\n/**\n * Generate Vite resolve.alias configuration\n */\nexport function generateViteAliasConfig(\n merged: MergedLayerConfig\n): Array<{ find: string | RegExp; replacement: string }> {\n const aliases = buildViteAliases(merged);\n\n // Convert to Vite alias format\n // Sort by key length descending to match longer paths first\n const sortedKeys = Object.keys(aliases).sort((a, b) => b.length - a.length);\n\n return sortedKeys.map((key) => ({\n find: key,\n replacement: aliases[key],\n }));\n}\n\n/**\n * Generate TypeScript paths configuration for tsconfig.json\n */\nexport function generateTsConfigPaths(\n merged: MergedLayerConfig,\n baseUrl: string = '.'\n): Record<string, string[]> {\n const paths: Record<string, string[]> = {};\n const aliases = buildViteAliases(merged);\n\n for (const [alias, target] of Object.entries(aliases)) {\n // TypeScript paths need relative paths\n const relativePath = path.relative(baseUrl, target);\n\n paths[alias] = [relativePath];\n paths[`${alias}/*`] = [`${relativePath}/*`];\n }\n\n return paths;\n}\n\n/**\n * Generate virtual module resolving layer information\n */\nexport function generateLayerInfoModule(stack: LayerStack): string {\n const layersInfo = stack.layers.map((layer) => ({\n name: layer.name,\n path: layer.path,\n priority: layer.priority,\n source: layer.source,\n isApp: layer.isApp,\n }));\n\n return `\n// Auto-generated by @kimesh/layers\n// DO NOT EDIT\n\nexport const layers = ${JSON.stringify(layersInfo, null, 2)} as const;\n\nexport type LayerName = typeof layers[number]['name'];\n\nexport function getLayer(name: LayerName) {\n return layers.find(l => l.name === name);\n}\n\nexport const appLayer = ${JSON.stringify(layersInfo.find((l) => l.isApp))} as const;\n`.trim();\n}\n","/**\n * @kimesh/layers - Layer Resolution\n *\n * This module handles layer discovery, resolution, and priority ordering.\n */\n\nimport * as fs from 'node:fs';\nimport * as path from 'pathe';\nimport { consola } from 'consola';\n\nimport type {\n ExtendedLayerConfig,\n KimeshLayerConfig,\n LayerResolveOptions,\n LayerStack,\n ResolvedLayer,\n} from './types.js';\nimport { createLayerAliases } from './aliases.js';\n\nconst logger = consola.withTag('kimesh:layers');\n\n/**\n * Resolve all layers from configuration and auto-scanning\n *\n * Priority order (0 = highest):\n * - 0: App (application src/)\n * - 1+: Layers from extends[] array (order preserved)\n * - N+: Auto-scanned layers/ directory (alphabetical)\n */\nexport async function resolveLayers(\n options: LayerResolveOptions\n): Promise<LayerStack> {\n const { root, extends: extendedLayers = [], autoScan = true, layersDir = 'layers' } = options;\n const startTime = performance.now();\n\n const layers: ResolvedLayer[] = [];\n const visited = new Set<string>();\n const resolving = new Set<string>(); // For circular dependency detection\n\n // Priority 0: App layer\n const appLayer = createAppLayer(root);\n layers.push(appLayer);\n visited.add('app');\n\n // Priority 1+: Extended layers from config\n let priority = 1;\n for (const extendedConfig of extendedLayers) {\n const resolved = await resolveExtendedLayer(\n extendedConfig,\n root,\n priority,\n visited,\n resolving\n );\n if (resolved) {\n layers.push(resolved);\n visited.add(resolved.name);\n priority++;\n }\n }\n\n // Auto-scan layers/ directory\n if (autoScan) {\n const layersDirPath = path.join(root, layersDir);\n const autoScanned = await scanLayersDirectory(layersDirPath, priority, visited);\n layers.push(...autoScanned);\n }\n\n // Build lookup map\n const byName = new Map<string, ResolvedLayer>();\n for (const layer of layers) {\n byName.set(layer.name, layer);\n }\n\n const elapsed = performance.now() - startTime;\n logger.debug(`Resolved ${layers.length} layers in ${elapsed.toFixed(1)}ms`);\n\n return {\n layers,\n app: appLayer,\n byName,\n count: layers.length,\n };\n}\n\n/**\n * Create the app layer (priority 0)\n */\nfunction createAppLayer(root: string): ResolvedLayer {\n const srcPath = path.join(root, 'src');\n\n return {\n name: 'app',\n path: fs.existsSync(srcPath) ? srcPath : root,\n priority: 0,\n config: {\n name: 'app',\n path: root,\n },\n extends: [],\n isApp: true,\n source: 'local',\n aliases: createLayerAliases('app', root),\n };\n}\n\n/**\n * Resolve a single extended layer configuration\n */\nasync function resolveExtendedLayer(\n config: ExtendedLayerConfig,\n root: string,\n priority: number,\n visited: Set<string>,\n resolving: Set<string>\n): Promise<ResolvedLayer | null> {\n // Normalize config\n const layerConfig = normalizeLayerConfig(config, root);\n\n if (!layerConfig) {\n logger.warn(`Could not normalize layer config: ${JSON.stringify(config)}`);\n return null;\n }\n\n // Skip if already visited\n if (visited.has(layerConfig.name)) {\n logger.debug(`Layer '${layerConfig.name}' already resolved, skipping`);\n return null;\n }\n\n // Check for circular dependencies\n if (resolving.has(layerConfig.name)) {\n throw new Error(\n `Circular dependency detected: ${[...resolving, layerConfig.name].join(' -> ')}`\n );\n }\n\n // Validate layer path exists\n if (!fs.existsSync(layerConfig.path)) {\n logger.warn(`Layer path does not exist: ${layerConfig.path}`);\n return null;\n }\n\n // Load the layer's actual config if it has one\n const loaded = await loadLayerConfig(layerConfig.path);\n\n // Merge loaded config with the basic config (loaded config takes precedence)\n const mergedConfig: KimeshLayerConfig = {\n ...layerConfig,\n ...(loaded?.config || {}),\n // Ensure path is set\n path: layerConfig.path,\n // Use loaded name if available, otherwise keep original\n name: loaded?.config?.name || layerConfig.name,\n };\n\n // Determine source type\n const source = determineLayerSource(layerConfig.path, root);\n\n // Create resolved layer\n const resolved: ResolvedLayer = {\n name: mergedConfig.name,\n path: mergedConfig.path,\n priority,\n config: mergedConfig,\n extends: [], // TODO: Recursively resolve layer's extends\n isApp: false,\n source,\n aliases: createLayerAliases(mergedConfig.name, mergedConfig.path),\n runtimeConfig: loaded?.runtimeConfig,\n };\n\n return resolved;\n}\n\n/**\n * Normalize layer config from string path\n */\nfunction normalizeStringConfig(\n configPath: string,\n root: string\n): KimeshLayerConfig | null {\n const isLocalPath = configPath.startsWith('.') || configPath.startsWith('/');\n\n if (isLocalPath) {\n const absolutePath = path.isAbsolute(configPath)\n ? configPath\n : path.resolve(root, configPath);\n\n return {\n name: path.basename(absolutePath),\n path: absolutePath,\n };\n }\n\n const packagePath = resolvePackagePath(configPath, root);\n if (!packagePath) {\n logger.warn(`Could not resolve package: ${configPath}`);\n return null;\n }\n\n return {\n name: configPath,\n path: packagePath,\n };\n}\n\n/**\n * Normalize layer config from object\n */\nfunction normalizeObjectConfig(\n config: KimeshLayerConfig,\n root: string\n): KimeshLayerConfig | null {\n if (!config.path) {\n logger.warn(`Layer config missing path: ${JSON.stringify(config)}`);\n return null;\n }\n\n const absolutePath = path.isAbsolute(config.path)\n ? config.path\n : path.resolve(root, config.path);\n\n return {\n ...config,\n path: absolutePath,\n };\n}\n\n/**\n * Normalize layer config from string or object\n */\nfunction normalizeLayerConfig(\n config: ExtendedLayerConfig,\n root: string\n): KimeshLayerConfig | null {\n if (typeof config === 'string') {\n return normalizeStringConfig(config, root);\n }\n return normalizeObjectConfig(config, root);\n}\n\n/**\n * Resolve NPM package path\n */\nfunction resolvePackagePath(packageName: string, root: string): string | null {\n // Try node_modules resolution\n const possiblePaths = [\n path.join(root, 'node_modules', packageName),\n path.join(root, '..', 'node_modules', packageName), // Monorepo root\n ];\n\n for (const p of possiblePaths) {\n if (fs.existsSync(p)) {\n return p;\n }\n }\n\n // Try require.resolve (handles symlinks in monorepos)\n try {\n const resolved = require.resolve(`${packageName}/package.json`, {\n paths: [root],\n });\n return path.dirname(resolved);\n } catch {\n return null;\n }\n}\n\n/**\n * Check if a path is a symlink\n */\nfunction isSymlink(filePath: string): boolean {\n try {\n return fs.lstatSync(filePath).isSymbolicLink();\n } catch {\n return false;\n }\n}\n\n/**\n * Determine layer source type\n */\nfunction determineLayerSource(\n layerPath: string,\n _root: string\n): 'local' | 'npm' | 'workspace' {\n if (!layerPath.includes('node_modules')) {\n return 'local';\n }\n\n return isSymlink(layerPath) ? 'workspace' : 'npm';\n}\n\nconst LAYER_STRUCTURE_MARKERS = ['kimesh.config.ts', 'routes', 'components', 'composables'] as const;\n\n/**\n * Check if a directory has valid layer structure\n */\nfunction hasLayerStructure(layerPath: string): boolean {\n return LAYER_STRUCTURE_MARKERS.some((marker) =>\n fs.existsSync(path.join(layerPath, marker))\n );\n}\n\n/**\n * Scan layers/ directory for auto-discovered layers\n */\nasync function scanLayersDirectory(\n layersDir: string,\n startPriority: number,\n visited: Set<string>\n): Promise<ResolvedLayer[]> {\n if (!fs.existsSync(layersDir)) {\n return [];\n }\n\n const entries = fs.readdirSync(layersDir, { withFileTypes: true });\n const directories = entries\n .filter((entry) => entry.isDirectory())\n .sort((a, b) => a.name.localeCompare(b.name));\n\n const layers: ResolvedLayer[] = [];\n let priority = startPriority;\n\n for (const entry of directories) {\n const layerName = entry.name;\n const layerPath = path.join(layersDir, layerName);\n\n if (visited.has(layerName)) {\n continue;\n }\n\n if (!hasLayerStructure(layerPath)) {\n logger.debug(`Skipping '${layerName}' - no layer structure detected`);\n continue;\n }\n\n const loaded = await loadLayerConfig(layerPath);\n\n const resolved: ResolvedLayer = {\n name: loaded?.config?.name ?? layerName,\n path: layerPath,\n priority,\n config: loaded?.config ?? { name: layerName, path: layerPath },\n extends: [],\n isApp: false,\n source: 'local',\n aliases: createLayerAliases(layerName, layerPath),\n runtimeConfig: loaded?.runtimeConfig,\n };\n\n layers.push(resolved);\n visited.add(resolved.name);\n priority++;\n\n logger.debug(`Auto-discovered layer: ${layerName} (priority: ${resolved.priority})`);\n }\n\n return layers;\n}\n\n/**\n * Full config type (includes runtimeConfig from KimeshConfig)\n */\ninterface FullLayerConfig extends KimeshLayerConfig {\n runtimeConfig?: Record<string, unknown>;\n}\n\n/**\n * Loaded layer config result\n */\ninterface LoadedLayerConfig {\n config: KimeshLayerConfig;\n runtimeConfig?: Record<string, unknown>;\n}\n\n/**\n * Load kimesh.config.ts from a layer directory using c12\n */\nasync function loadLayerConfig(layerPath: string): Promise<LoadedLayerConfig | null> {\n const configPath = path.join(layerPath, 'kimesh.config.ts');\n\n if (!fs.existsSync(configPath)) {\n return null;\n }\n\n try {\n const { loadConfig } = await import('c12');\n const { config } = await loadConfig<FullLayerConfig>({\n name: 'kimesh',\n cwd: layerPath,\n extend: false, // Don't auto-extend nested configs\n });\n\n if (config) {\n logger.debug(`Loaded config from ${configPath}`);\n const { runtimeConfig, ...layerConfig } = config;\n return {\n config: {\n ...layerConfig,\n path: layerPath,\n },\n runtimeConfig,\n };\n }\n } catch (error) {\n logger.warn(`Failed to load config from ${configPath}: ${error}`);\n }\n\n return null;\n}\n\n/**\n * Filter layers by enabled list\n */\nexport function filterLayersByEnabled(\n stack: LayerStack,\n enabled: string[] | 'all' | 'none'\n): LayerStack {\n if (enabled === 'all') {\n return stack;\n }\n\n if (enabled === 'none') {\n // Only keep app layer\n return {\n layers: [stack.app],\n app: stack.app,\n byName: new Map([['app', stack.app]]),\n count: 1,\n };\n }\n\n // Filter to enabled layers + always include app\n const enabledSet = new Set(['app', ...enabled]);\n const filtered = stack.layers.filter((layer) => enabledSet.has(layer.name));\n\n const byName = new Map<string, ResolvedLayer>();\n for (const layer of filtered) {\n byName.set(layer.name, layer);\n }\n\n return {\n layers: filtered,\n app: stack.app,\n byName,\n count: filtered.length,\n };\n}\n\n/**\n * Get layer by name\n */\nexport function getLayer(stack: LayerStack, name: string): ResolvedLayer | undefined {\n return stack.byName.get(name);\n}\n\n/**\n * Check if a layer exists in the stack\n */\nexport function hasLayer(stack: LayerStack, name: string): boolean {\n return stack.byName.has(name);\n}\n","/**\n * @kimesh/layers - Configuration Merging\n *\n * This module handles merging layer configurations with priority-based resolution.\n * Uses defu for deep merging with array concatenation.\n */\n\nimport * as fs from 'node:fs';\nimport * as path from 'pathe';\nimport { defu } from 'defu';\nimport { consola } from 'consola';\n\nimport type {\n LayerStack,\n MergedLayerConfig,\n ResolvedLayer,\n LayerConflict,\n} from './types.js';\n\nconst logger = consola.withTag('kimesh:layers:merge');\n\n/**\n * Directory entry with layer information\n */\ninterface LayerDirEntry {\n path: string;\n layer: string;\n prefix?: string;\n}\n\n/**\n * Find an existing directory from a list of candidate paths\n */\nfunction findExistingDir(paths: string[]): string | undefined {\n return paths.find((p) => fs.existsSync(p));\n}\n\n/**\n * Collect directories from a layer for a given directory name.\n * Checks both root and src/ locations.\n */\nfunction collectDirsForLayer(\n layer: ResolvedLayer,\n dirName: string,\n customDirs: string[] = [],\n prefix?: string\n): LayerDirEntry[] {\n const dirs: LayerDirEntry[] = [];\n const layerPath = layer.path;\n const srcPath = path.join(layerPath, 'src');\n\n const rootDir = path.join(layerPath, dirName);\n const srcDir = path.join(srcPath, dirName);\n\n if (fs.existsSync(rootDir)) {\n dirs.push({ path: rootDir, layer: layer.name, prefix });\n }\n\n if (fs.existsSync(srcDir) && srcDir !== rootDir) {\n dirs.push({ path: srcDir, layer: layer.name, prefix });\n }\n\n for (const customDir of customDirs) {\n if (customDir === dirName) continue;\n\n const customPath = findExistingDir([\n path.join(layerPath, customDir),\n path.join(srcPath, customDir),\n ]);\n\n if (customPath) {\n dirs.push({ path: customPath, layer: layer.name, prefix });\n }\n }\n\n return dirs;\n}\n\n/**\n * Merge all layer configurations into a single unified config\n *\n * Merge strategy:\n * - Routes: Collect from all layers (routes must be in correct directory structure)\n * - Components: Collect from all layers, apply prefixes\n * - Composables: Collect from all layers\n * - CSS: Concatenate all CSS files\n * - Aliases: Build complete alias map\n */\nexport function mergeLayerConfigs(stack: LayerStack): MergedLayerConfig {\n const startTime = performance.now();\n\n const routes: MergedLayerConfig['routes'] = { dirs: [] };\n const components: MergedLayerConfig['components'] = { dirs: [] };\n const composables: MergedLayerConfig['composables'] = { dirs: [] };\n const css: string[] = [];\n const aliases: Record<string, string> = {};\n const fsAllow: string[] = [];\n\n // Process layers in reverse priority order (lowest priority first)\n // This ensures higher priority layers override lower priority ones\n const sortedLayers = [...stack.layers].sort((a, b) => b.priority - a.priority);\n\n // Merge runtimeConfig from all layers (lowest priority first, so higher priority wins)\n // Using defu for deep merge\n let runtimeConfig: Record<string, unknown> = {};\n for (const layer of sortedLayers) {\n if (layer.runtimeConfig) {\n runtimeConfig = defu(runtimeConfig, layer.runtimeConfig) as Record<string, unknown>;\n }\n }\n\n for (const layer of sortedLayers) {\n // Collect routes directories\n const routeDirs = collectRouteDirs(layer);\n routes.dirs.push(...routeDirs);\n\n // Collect component directories\n const componentDirs = collectComponentDirs(layer);\n components.dirs.push(...componentDirs);\n\n // Collect composable directories\n const composableDirs = collectComposableDirs(layer);\n composables.dirs.push(...composableDirs);\n\n // Collect CSS files\n const cssFiles = collectCssFiles(layer);\n css.push(...cssFiles);\n\n // Merge aliases\n Object.assign(aliases, layer.aliases);\n\n // Add layer path to fs.allow\n fsAllow.push(layer.path);\n }\n\n // Sort all dirs by priority (highest first) for conflict resolution\n const sortByPriority = (a: LayerDirEntry, b: LayerDirEntry): number => {\n const priorityA = stack.byName.get(a.layer)?.priority ?? 999;\n const priorityB = stack.byName.get(b.layer)?.priority ?? 999;\n return priorityA - priorityB;\n };\n\n routes.dirs.sort(sortByPriority);\n components.dirs.sort(sortByPriority);\n composables.dirs.sort(sortByPriority);\n\n const elapsed = performance.now() - startTime;\n logger.debug(`Merged ${stack.count} layers in ${elapsed.toFixed(1)}ms`);\n logger.debug(` Routes dirs: ${routes.dirs.length}`);\n logger.debug(` Component dirs: ${components.dirs.length}`);\n logger.debug(` Composable dirs: ${composables.dirs.length}`);\n logger.debug(` CSS files: ${css.length}`);\n logger.debug(` RuntimeConfig keys: ${Object.keys(runtimeConfig).length}`);\n\n return {\n layers: stack.layers,\n routes,\n components,\n composables,\n css,\n aliases,\n fsAllow,\n runtimeConfig,\n };\n}\n\n/**\n * Collect route directories from a layer\n */\nfunction collectRouteDirs(layer: ResolvedLayer): LayerDirEntry[] {\n const customFolder = layer.config.routes?.folder;\n const customDirs = customFolder ? [customFolder] : [];\n return collectDirsForLayer(layer, 'routes', customDirs);\n}\n\n/**\n * Collect component directories from a layer\n */\nfunction collectComponentDirs(layer: ResolvedLayer): LayerDirEntry[] {\n const prefix = resolveComponentPrefix(layer);\n const customDirs = layer.config.components?.dirs ?? [];\n return collectDirsForLayer(layer, 'components', customDirs, prefix);\n}\n\n/**\n * Collect composable directories from a layer\n */\nfunction collectComposableDirs(layer: ResolvedLayer): LayerDirEntry[] {\n const customDirs = layer.config.composables?.dirs ?? [];\n const composableDirs = collectDirsForLayer(layer, 'composables', customDirs);\n const hooksDirs = collectDirsForLayer(layer, 'hooks');\n return [...composableDirs, ...hooksDirs];\n}\n\n/**\n * Collect CSS files from a layer\n */\nfunction collectCssFiles(layer: ResolvedLayer): string[] {\n const files: string[] = [];\n\n // CSS files from config\n const configCss = layer.config.css || [];\n for (const cssFile of configCss) {\n const absolutePath = path.isAbsolute(cssFile)\n ? cssFile\n : path.join(layer.path, cssFile);\n\n if (fs.existsSync(absolutePath)) {\n files.push(absolutePath);\n } else {\n logger.warn(`CSS file not found: ${absolutePath} (layer: ${layer.name})`);\n }\n }\n\n return files;\n}\n\n/**\n * Resolve component prefix for a layer\n *\n * Priority:\n * 1. Explicit prefix in config.components.prefix\n * 2. Derived from layer name: '@kimesh-layers/cms' -> 'Cms'\n * 3. App layer: no prefix\n */\nfunction resolveComponentPrefix(layer: ResolvedLayer): string | undefined {\n // App layer never has a prefix\n if (layer.isApp) {\n return undefined;\n }\n\n // Explicit config\n const configPrefix = layer.config.components?.prefix;\n if (configPrefix === false) {\n return undefined;\n }\n if (typeof configPrefix === 'string') {\n return configPrefix;\n }\n\n // Derive from layer name\n return derivePrefix(layer.name);\n}\n\n/**\n * Derive a component prefix from layer name\n *\n * Examples:\n * - '@kimesh-layers/cms' -> 'Cms'\n * - '@company/layer-auth' -> 'Auth'\n * - 'cms' -> 'Cms'\n * - 'my-layer' -> 'MyLayer'\n */\nfunction derivePrefix(layerName: string): string {\n // Extract the meaningful part from scoped packages\n const patterns = [\n /^@[\\w-]+\\/(?:layer-)?(.+)$/, // @scope/layer-name or @scope/name\n /^(?:layer-)?(.+)$/, // layer-name or name\n ];\n\n let baseName = layerName;\n for (const pattern of patterns) {\n const match = layerName.match(pattern);\n if (match) {\n baseName = match[1];\n break;\n }\n }\n\n // Convert to PascalCase\n return toPascalCase(baseName);\n}\n\n/**\n * Convert string to PascalCase\n */\nfunction toPascalCase(str: string): string {\n return str\n .split(/[-_]/)\n .map((part) => part.charAt(0).toUpperCase() + part.slice(1).toLowerCase())\n .join('');\n}\n\n/**\n * Merge two configs with priority (using defu)\n * Higher priority config values take precedence\n */\nexport function mergeConfigs<T extends object>(\n highPriority: T,\n lowPriority: T\n): T {\n return defu(highPriority, lowPriority) as T;\n}\n\n/**\n * Detect conflicts between layers\n */\nexport function detectConflicts(merged: MergedLayerConfig): LayerConflict[] {\n const conflicts: LayerConflict[] = [];\n\n // Route conflicts would be detected at route generation time\n // Component conflicts would be detected at auto-import time\n // This is a placeholder for future conflict detection\n\n return conflicts;\n}\n","/**\n * @kimesh/layers - Layer System for Kimesh Framework\n *\n * This package provides layer discovery, resolution, and configuration merging\n * for the Kimesh framework's Nuxt-inspired layer architecture.\n *\n * @packageDocumentation\n */\n\nimport * as fs from \"node:fs\";\nimport * as path from \"pathe\";\nimport { loadConfig as loadC12Config } from \"c12\";\n\nimport type {\n ExtendedLayerConfig,\n LayerResolveOptions,\n MergedLayerConfig,\n ResolvedLayer,\n} from \"./types.js\";\nimport { resolveLayers, filterLayersByEnabled } from \"./resolve.js\";\nimport { mergeLayerConfigs } from \"./merge.js\";\nimport { buildViteAliases, buildFsAllow } from \"./aliases.js\";\n\n// Type exports\nexport type {\n KimeshLayerConfig,\n ExtendedLayerConfig,\n ResolvedLayer,\n LayerStack,\n LayerRouteConfig,\n LayerComponentConfig,\n LayerComposableConfig,\n LayerUtilsConfig,\n LayerStoresConfig,\n LayerAutoImportConfig,\n MergedLayerConfig,\n LayerConflict,\n LayerResolveOptions,\n} from \"./types.js\";\n\n// Layer resolution\nexport {\n resolveLayers,\n filterLayersByEnabled,\n getLayer,\n hasLayer,\n} from \"./resolve.js\";\n\n// Configuration merging\nexport { mergeLayerConfigs, mergeConfigs, detectConflicts } from \"./merge.js\";\n\n// Path aliasing\nexport {\n ALIAS_PATTERNS,\n createLayerAliases,\n buildViteAliases,\n generateLayerAliasesFromLayers as generateLayerAliases,\n buildFsAllow,\n generateViteAliasConfig,\n generateTsConfigPaths,\n generateLayerInfoModule,\n} from \"./aliases.js\";\n\n/**\n * Options for prepareLayers when using (root, options) signature\n */\nexport interface PrepareLayersOptions {\n enabled?: string[] | \"all\" | \"none\";\n excluded?: string[];\n}\n\n/**\n * Result type for prepareLayers with options object signature\n */\nexport interface PrepareLayersResult {\n merged: MergedLayerConfig;\n aliases: Record<string, string>;\n fsAllow: string[];\n}\n\n/**\n * Extract extends array from config file without c12 merging\n */\nasync function extractExtendsFromConfig(\n root: string\n): Promise<ExtendedLayerConfig[]> {\n const configPath = path.join(root, \"kimesh.config.ts\");\n\n if (!fs.existsSync(configPath)) {\n return [];\n }\n\n const { config } = await loadC12Config<{ extends?: ExtendedLayerConfig[] }>({\n name: \"kimesh\",\n cwd: root,\n extend: false,\n });\n\n return config?.extends ?? [];\n}\n\n/**\n * Prepare layers from a root directory with filtering options.\n * Returns an array of resolved layers.\n *\n * @example\n * ```ts\n * const layers = await prepareLayersFromRoot(process.cwd(), {\n * enabled: ['blog', 'auth'],\n * excluded: [],\n * });\n * ```\n */\nexport async function prepareLayersFromRoot(\n root: string,\n options: PrepareLayersOptions = {}\n): Promise<ResolvedLayer[]> {\n const extendsLayers = await extractExtendsFromConfig(root);\n\n const resolveOpts: LayerResolveOptions = {\n root,\n extends: extendsLayers,\n layersDir: \"layers\",\n };\n\n let stack = await resolveLayers(resolveOpts);\n\n if (options.enabled && options.enabled !== \"all\") {\n stack = filterLayersByEnabled(stack, options.enabled);\n }\n\n const merged = mergeLayerConfigs(stack);\n\n if (options.excluded && options.excluded.length > 0) {\n const excludeSet = new Set(options.excluded);\n return merged.layers.filter((layer) => !excludeSet.has(layer.name));\n }\n\n return merged.layers;\n}\n\n/**\n * Prepare layers with full configuration options.\n * Returns merged config, aliases, and fsAllow paths.\n *\n * @example\n * ```ts\n * const { merged, aliases, fsAllow } = await prepareLayersWithConfig({\n * root: process.cwd(),\n * extends: ['./layers/cms'],\n * });\n * ```\n */\nexport async function prepareLayersWithConfig(\n options: LayerResolveOptions & { enabled?: string[] | \"all\" | \"none\" }\n): Promise<PrepareLayersResult> {\n let stack = await resolveLayers(options);\n\n if (options.enabled) {\n stack = filterLayersByEnabled(stack, options.enabled);\n }\n\n const merged = mergeLayerConfigs(stack);\n const aliases = buildViteAliases(merged);\n const fsAllow = buildFsAllow(merged);\n\n return { merged, aliases, fsAllow };\n}\n\n/**\n * High-level utility to resolve and filter layers.\n *\n * Supports two call signatures:\n * - `prepareLayers(root, options)` - Returns ResolvedLayer[]\n * - `prepareLayers(options)` - Returns { merged, aliases, fsAllow }\n *\n * @deprecated Use prepareLayersFromRoot or prepareLayersWithConfig for clearer intent\n */\nexport async function prepareLayers(\n rootOrOptions:\n | string\n | (LayerResolveOptions & { enabled?: string[] | \"all\" | \"none\" }),\n options?: PrepareLayersOptions\n): Promise<ResolvedLayer[] | PrepareLayersResult> {\n if (typeof rootOrOptions === \"string\") {\n return prepareLayersFromRoot(rootOrOptions, options);\n }\n return prepareLayersWithConfig(rootOrOptions);\n}\n"],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "@kimesh/layers",
3
+ "version": "0.0.1",
4
+ "description": "Layer system for Kimesh framework - layer discovery, resolution, and configuration merging",
5
+ "type": "module",
6
+ "exports": {
7
+ ".": {
8
+ "types": "./dist/index.d.mts",
9
+ "import": "./dist/index.mjs"
10
+ }
11
+ },
12
+ "main": "./dist/index.mjs",
13
+ "types": "./dist/index.d.mts",
14
+ "files": [
15
+ "dist"
16
+ ],
17
+ "scripts": {
18
+ "build": "tsdown",
19
+ "dev": "tsdown --watch",
20
+ "typecheck": "tsc --noEmit",
21
+ "test": "vitest"
22
+ },
23
+ "dependencies": {
24
+ "c12": "^3.3.3",
25
+ "defu": "^6.1.4",
26
+ "pathe": "^2.0.3",
27
+ "consola": "^3.4.2"
28
+ },
29
+ "devDependencies": {
30
+ "@types/node": "^25.0.8",
31
+ "typescript": "^5.9.3",
32
+ "tsdown": "^0.20.0-beta.3",
33
+ "vitest": "^4.0.17"
34
+ }
35
+ }