@geekmidas/cli 0.23.0 → 0.24.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.
@@ -0,0 +1,189 @@
1
+ import { getAppGkmConfig, isWorkspaceConfig, processConfig } from "./workspace-CPLEZDZf.mjs";
2
+ import { existsSync, readFileSync } from "node:fs";
3
+ import { dirname, join, parse } from "node:path";
4
+
5
+ //#region src/config.ts
6
+ /**
7
+ * Define GKM configuration with full TypeScript support.
8
+ * This is an identity function that provides type safety and autocomplete.
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * // gkm.config.ts
13
+ * import { defineConfig } from '@geekmidas/cli/config';
14
+ *
15
+ * export default defineConfig({
16
+ * routes: './src/endpoints/**\/*.ts',
17
+ * envParser: './src/config/env',
18
+ * logger: './src/config/logger',
19
+ * telescope: true,
20
+ * });
21
+ * ```
22
+ */
23
+ function defineConfig(config) {
24
+ return config;
25
+ }
26
+ /**
27
+ * Parse a module config string into path and import pattern.
28
+ *
29
+ * @param configString - Config string in format "./path/to/module" or "./path/to/module#exportName"
30
+ * @param defaultAlias - The default alias name to use if no export name specified
31
+ * @returns Object with path and import pattern
32
+ *
33
+ * @example
34
+ * parseModuleConfig('./src/config/env', 'envParser')
35
+ * // { path: './src/config/env', importPattern: 'envParser' }
36
+ *
37
+ * parseModuleConfig('./src/config/env#envParser', 'envParser')
38
+ * // { path: './src/config/env', importPattern: '{ envParser }' }
39
+ *
40
+ * parseModuleConfig('./src/config/env#myEnv', 'envParser')
41
+ * // { path: './src/config/env', importPattern: '{ myEnv as envParser }' }
42
+ */
43
+ function parseModuleConfig(configString, defaultAlias) {
44
+ const parts = configString.split("#");
45
+ const path = parts[0] ?? configString;
46
+ const exportName = parts[1];
47
+ const importPattern = !exportName ? defaultAlias : exportName === defaultAlias ? `{ ${defaultAlias} }` : `{ ${exportName} as ${defaultAlias} }`;
48
+ return {
49
+ path,
50
+ importPattern
51
+ };
52
+ }
53
+ /**
54
+ * Find and return the path to the config file.
55
+ *
56
+ * Resolution order:
57
+ * 1. GKM_CONFIG_PATH env var (set by workspace dev command)
58
+ * 2. Walk up directory tree from cwd
59
+ */
60
+ function findConfigPath(cwd) {
61
+ const files = [
62
+ "gkm.config.json",
63
+ "gkm.config.ts",
64
+ "gkm.config.js"
65
+ ];
66
+ const envConfigPath = process.env.GKM_CONFIG_PATH;
67
+ if (envConfigPath && existsSync(envConfigPath)) return {
68
+ configPath: envConfigPath,
69
+ workspaceRoot: dirname(envConfigPath)
70
+ };
71
+ let currentDir = cwd;
72
+ const { root } = parse(currentDir);
73
+ while (currentDir !== root) {
74
+ for (const file of files) {
75
+ const configPath = join(currentDir, file);
76
+ if (existsSync(configPath)) return {
77
+ configPath,
78
+ workspaceRoot: currentDir
79
+ };
80
+ }
81
+ currentDir = dirname(currentDir);
82
+ }
83
+ throw new Error("Configuration file not found. Please create gkm.config.json, gkm.config.ts, or gkm.config.js in the project root.");
84
+ }
85
+ /**
86
+ * Get app name from package.json in the given directory.
87
+ * Handles scoped packages by extracting the name after the scope.
88
+ *
89
+ * @example
90
+ * getAppNameFromCwd('/path/to/apps/api')
91
+ * // package.json: { "name": "@myorg/api" }
92
+ * // Returns: 'api'
93
+ */
94
+ function getAppNameFromCwd(cwd = process.cwd()) {
95
+ const packageJsonPath = join(cwd, "package.json");
96
+ if (!existsSync(packageJsonPath)) return null;
97
+ try {
98
+ const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
99
+ const name = packageJson.name;
100
+ if (!name) return null;
101
+ if (name.startsWith("@") && name.includes("/")) return name.split("/")[1] ?? null;
102
+ return name;
103
+ } catch {
104
+ return null;
105
+ }
106
+ }
107
+ /**
108
+ * Load raw configuration from file.
109
+ */
110
+ async function loadRawConfig(cwd) {
111
+ const { configPath, workspaceRoot } = findConfigPath(cwd);
112
+ try {
113
+ const config = await import(configPath);
114
+ return {
115
+ config: config.default,
116
+ workspaceRoot
117
+ };
118
+ } catch (error) {
119
+ throw new Error(`Failed to load config: ${error.message}`);
120
+ }
121
+ }
122
+ /**
123
+ * Load configuration file (single-app format).
124
+ * For backwards compatibility with existing code.
125
+ *
126
+ * @deprecated Use loadWorkspaceConfig for new code
127
+ */
128
+ async function loadConfig(cwd = process.cwd()) {
129
+ const { config } = await loadRawConfig(cwd);
130
+ if (isWorkspaceConfig(config)) throw new Error("Workspace configuration detected. Use loadWorkspaceConfig() instead.");
131
+ return config;
132
+ }
133
+ /**
134
+ * Load configuration file and process it as a workspace.
135
+ * Works with both single-app and workspace configurations.
136
+ *
137
+ * Single-app configs are automatically wrapped as a workspace with one app.
138
+ *
139
+ * @example
140
+ * ```ts
141
+ * const { type, workspace } = await loadWorkspaceConfig();
142
+ *
143
+ * if (type === 'workspace') {
144
+ * console.log('Multi-app workspace:', workspace.apps);
145
+ * } else {
146
+ * console.log('Single app wrapped as workspace');
147
+ * }
148
+ * ```
149
+ */
150
+ async function loadWorkspaceConfig(cwd = process.cwd()) {
151
+ const { config, workspaceRoot } = await loadRawConfig(cwd);
152
+ return processConfig(config, workspaceRoot);
153
+ }
154
+ /**
155
+ * Load app-specific configuration from workspace.
156
+ * Uses the app name from package.json to find the correct app config.
157
+ *
158
+ * @example
159
+ * ```ts
160
+ * // From apps/api directory with package.json: { "name": "@myorg/api" }
161
+ * const { app, workspace, workspaceRoot } = await loadAppConfig();
162
+ * console.log(app.routes); // './src/endpoints/**\/*.ts'
163
+ * ```
164
+ */
165
+ async function loadAppConfig(cwd = process.cwd()) {
166
+ const appName = getAppNameFromCwd(cwd);
167
+ if (!appName) throw new Error("Could not determine app name. Ensure package.json exists with a \"name\" field.");
168
+ const { config, workspaceRoot } = await loadRawConfig(cwd);
169
+ const loadedConfig = processConfig(config, workspaceRoot);
170
+ const app = loadedConfig.workspace.apps[appName];
171
+ if (!app) {
172
+ const availableApps = Object.keys(loadedConfig.workspace.apps).join(", ");
173
+ throw new Error(`App "${appName}" not found in workspace config. Available apps: ${availableApps}. Ensure the package.json name matches the app key in gkm.config.ts.`);
174
+ }
175
+ const gkmConfig = getAppGkmConfig(loadedConfig.workspace, appName);
176
+ if (!gkmConfig) throw new Error(`App "${appName}" is not a backend app and cannot be run with gkm dev.`);
177
+ return {
178
+ appName,
179
+ app,
180
+ gkmConfig,
181
+ workspace: loadedConfig.workspace,
182
+ workspaceRoot,
183
+ appRoot: join(workspaceRoot, app.path)
184
+ };
185
+ }
186
+
187
+ //#endregion
188
+ export { defineConfig, getAppNameFromCwd, loadAppConfig, loadConfig, loadWorkspaceConfig, parseModuleConfig };
189
+ //# sourceMappingURL=config-BogU0_oQ.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-BogU0_oQ.mjs","names":["config: GkmConfig","configString: string","defaultAlias: string","cwd: string"],"sources":["../src/config.ts"],"sourcesContent":["import { existsSync, readFileSync } from 'node:fs';\nimport { dirname, join, parse } from 'node:path';\nimport type { GkmConfig } from './types.js';\nimport {\n\tgetAppGkmConfig,\n\tisWorkspaceConfig,\n\ttype LoadedConfig,\n\ttype NormalizedAppConfig,\n\ttype NormalizedWorkspace,\n\tprocessConfig,\n\ttype WorkspaceConfig,\n} from './workspace/index.js';\n\nexport type { GkmConfig } from './types.js';\nexport type { LoadedConfig, WorkspaceConfig } from './workspace/index.js';\nexport { defineWorkspace } from './workspace/index.js';\n/**\n * Define GKM configuration with full TypeScript support.\n * This is an identity function that provides type safety and autocomplete.\n *\n * @example\n * ```ts\n * // gkm.config.ts\n * import { defineConfig } from '@geekmidas/cli/config';\n *\n * export default defineConfig({\n * routes: './src/endpoints/**\\/*.ts',\n * envParser: './src/config/env',\n * logger: './src/config/logger',\n * telescope: true,\n * });\n * ```\n */\nexport function defineConfig(config: GkmConfig): GkmConfig {\n\treturn config;\n}\n\nexport interface ParsedModuleConfig {\n\tpath: string;\n\timportPattern: string;\n}\n\n/**\n * Parse a module config string into path and import pattern.\n *\n * @param configString - Config string in format \"./path/to/module\" or \"./path/to/module#exportName\"\n * @param defaultAlias - The default alias name to use if no export name specified\n * @returns Object with path and import pattern\n *\n * @example\n * parseModuleConfig('./src/config/env', 'envParser')\n * // { path: './src/config/env', importPattern: 'envParser' }\n *\n * parseModuleConfig('./src/config/env#envParser', 'envParser')\n * // { path: './src/config/env', importPattern: '{ envParser }' }\n *\n * parseModuleConfig('./src/config/env#myEnv', 'envParser')\n * // { path: './src/config/env', importPattern: '{ myEnv as envParser }' }\n */\nexport function parseModuleConfig(\n\tconfigString: string,\n\tdefaultAlias: string,\n): ParsedModuleConfig {\n\tconst parts = configString.split('#');\n\tconst path = parts[0] ?? configString;\n\tconst exportName = parts[1];\n\tconst importPattern = !exportName\n\t\t? defaultAlias\n\t\t: exportName === defaultAlias\n\t\t\t? `{ ${defaultAlias} }`\n\t\t\t: `{ ${exportName} as ${defaultAlias} }`;\n\n\treturn { path, importPattern };\n}\n\nexport interface ConfigDiscoveryResult {\n\tconfigPath: string;\n\tworkspaceRoot: string;\n}\n\n/**\n * Find and return the path to the config file.\n *\n * Resolution order:\n * 1. GKM_CONFIG_PATH env var (set by workspace dev command)\n * 2. Walk up directory tree from cwd\n */\nfunction findConfigPath(cwd: string): ConfigDiscoveryResult {\n\tconst files = ['gkm.config.json', 'gkm.config.ts', 'gkm.config.js'];\n\n\t// Check GKM_CONFIG_PATH env var first (set by workspace dev command)\n\tconst envConfigPath = process.env.GKM_CONFIG_PATH;\n\tif (envConfigPath && existsSync(envConfigPath)) {\n\t\treturn {\n\t\t\tconfigPath: envConfigPath,\n\t\t\tworkspaceRoot: dirname(envConfigPath),\n\t\t};\n\t}\n\n\t// Walk up directory tree to find config\n\tlet currentDir = cwd;\n\tconst { root } = parse(currentDir);\n\n\twhile (currentDir !== root) {\n\t\tfor (const file of files) {\n\t\t\tconst configPath = join(currentDir, file);\n\t\t\tif (existsSync(configPath)) {\n\t\t\t\treturn {\n\t\t\t\t\tconfigPath,\n\t\t\t\t\tworkspaceRoot: currentDir,\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t\tcurrentDir = dirname(currentDir);\n\t}\n\n\tthrow new Error(\n\t\t'Configuration file not found. Please create gkm.config.json, gkm.config.ts, or gkm.config.js in the project root.',\n\t);\n}\n\n/**\n * Get app name from package.json in the given directory.\n * Handles scoped packages by extracting the name after the scope.\n *\n * @example\n * getAppNameFromCwd('/path/to/apps/api')\n * // package.json: { \"name\": \"@myorg/api\" }\n * // Returns: 'api'\n */\nexport function getAppNameFromCwd(cwd: string = process.cwd()): string | null {\n\tconst packageJsonPath = join(cwd, 'package.json');\n\n\tif (!existsSync(packageJsonPath)) {\n\t\treturn null;\n\t}\n\n\ttry {\n\t\tconst packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));\n\t\tconst name = packageJson.name as string | undefined;\n\n\t\tif (!name) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// Handle scoped packages: @scope/name -> name\n\t\tif (name.startsWith('@') && name.includes('/')) {\n\t\t\treturn name.split('/')[1] ?? null;\n\t\t}\n\n\t\treturn name;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\ninterface RawConfigResult {\n\tconfig: GkmConfig | WorkspaceConfig;\n\tworkspaceRoot: string;\n}\n\n/**\n * Load raw configuration from file.\n */\nasync function loadRawConfig(cwd: string): Promise<RawConfigResult> {\n\tconst { configPath, workspaceRoot } = findConfigPath(cwd);\n\n\ttry {\n\t\tconst config = await import(configPath);\n\t\treturn {\n\t\t\tconfig: config.default,\n\t\t\tworkspaceRoot,\n\t\t};\n\t} catch (error) {\n\t\tthrow new Error(`Failed to load config: ${(error as Error).message}`);\n\t}\n}\n\n/**\n * Load configuration file (single-app format).\n * For backwards compatibility with existing code.\n *\n * @deprecated Use loadWorkspaceConfig for new code\n */\nexport async function loadConfig(\n\tcwd: string = process.cwd(),\n): Promise<GkmConfig> {\n\tconst { config } = await loadRawConfig(cwd);\n\n\t// If it's a workspace config, throw an error\n\tif (isWorkspaceConfig(config)) {\n\t\tthrow new Error(\n\t\t\t'Workspace configuration detected. Use loadWorkspaceConfig() instead.',\n\t\t);\n\t}\n\n\treturn config;\n}\n\n/**\n * Load configuration file and process it as a workspace.\n * Works with both single-app and workspace configurations.\n *\n * Single-app configs are automatically wrapped as a workspace with one app.\n *\n * @example\n * ```ts\n * const { type, workspace } = await loadWorkspaceConfig();\n *\n * if (type === 'workspace') {\n * console.log('Multi-app workspace:', workspace.apps);\n * } else {\n * console.log('Single app wrapped as workspace');\n * }\n * ```\n */\nexport async function loadWorkspaceConfig(\n\tcwd: string = process.cwd(),\n): Promise<LoadedConfig> {\n\tconst { config, workspaceRoot } = await loadRawConfig(cwd);\n\treturn processConfig(config, workspaceRoot);\n}\n\nexport interface AppConfigResult {\n\tappName: string;\n\tapp: NormalizedAppConfig;\n\tgkmConfig: GkmConfig;\n\tworkspace: NormalizedWorkspace;\n\tworkspaceRoot: string;\n\tappRoot: string;\n}\n\n/**\n * Load app-specific configuration from workspace.\n * Uses the app name from package.json to find the correct app config.\n *\n * @example\n * ```ts\n * // From apps/api directory with package.json: { \"name\": \"@myorg/api\" }\n * const { app, workspace, workspaceRoot } = await loadAppConfig();\n * console.log(app.routes); // './src/endpoints/**\\/*.ts'\n * ```\n */\nexport async function loadAppConfig(\n\tcwd: string = process.cwd(),\n): Promise<AppConfigResult> {\n\tconst appName = getAppNameFromCwd(cwd);\n\n\tif (!appName) {\n\t\tthrow new Error(\n\t\t\t'Could not determine app name. Ensure package.json exists with a \"name\" field.',\n\t\t);\n\t}\n\n\tconst { config, workspaceRoot } = await loadRawConfig(cwd);\n\tconst loadedConfig = processConfig(config, workspaceRoot);\n\n\t// Find the app in workspace (apps is a Record<string, NormalizedAppConfig>)\n\tconst app = loadedConfig.workspace.apps[appName];\n\n\tif (!app) {\n\t\tconst availableApps = Object.keys(loadedConfig.workspace.apps).join(', ');\n\t\tthrow new Error(\n\t\t\t`App \"${appName}\" not found in workspace config. Available apps: ${availableApps}. ` +\n\t\t\t\t`Ensure the package.json name matches the app key in gkm.config.ts.`,\n\t\t);\n\t}\n\n\t// Get the app's GKM config using the helper\n\tconst gkmConfig = getAppGkmConfig(loadedConfig.workspace, appName);\n\n\tif (!gkmConfig) {\n\t\tthrow new Error(\n\t\t\t`App \"${appName}\" is not a backend app and cannot be run with gkm dev.`,\n\t\t);\n\t}\n\n\treturn {\n\t\tappName,\n\t\tapp,\n\t\tgkmConfig,\n\t\tworkspace: loadedConfig.workspace,\n\t\tworkspaceRoot,\n\t\tappRoot: join(workspaceRoot, app.path),\n\t};\n}\n"],"mappings":"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"}
@@ -53,6 +53,10 @@ function parseModuleConfig(configString, defaultAlias) {
53
53
  }
54
54
  /**
55
55
  * Find and return the path to the config file.
56
+ *
57
+ * Resolution order:
58
+ * 1. GKM_CONFIG_PATH env var (set by workspace dev command)
59
+ * 2. Walk up directory tree from cwd
56
60
  */
57
61
  function findConfigPath(cwd) {
58
62
  const files = [
@@ -60,20 +64,58 @@ function findConfigPath(cwd) {
60
64
  "gkm.config.ts",
61
65
  "gkm.config.js"
62
66
  ];
63
- for (const file of files) {
64
- const path = (0, node_path.join)(cwd, file);
65
- if ((0, node_fs.existsSync)(path)) return path;
67
+ const envConfigPath = process.env.GKM_CONFIG_PATH;
68
+ if (envConfigPath && (0, node_fs.existsSync)(envConfigPath)) return {
69
+ configPath: envConfigPath,
70
+ workspaceRoot: (0, node_path.dirname)(envConfigPath)
71
+ };
72
+ let currentDir = cwd;
73
+ const { root } = (0, node_path.parse)(currentDir);
74
+ while (currentDir !== root) {
75
+ for (const file of files) {
76
+ const configPath = (0, node_path.join)(currentDir, file);
77
+ if ((0, node_fs.existsSync)(configPath)) return {
78
+ configPath,
79
+ workspaceRoot: currentDir
80
+ };
81
+ }
82
+ currentDir = (0, node_path.dirname)(currentDir);
66
83
  }
67
84
  throw new Error("Configuration file not found. Please create gkm.config.json, gkm.config.ts, or gkm.config.js in the project root.");
68
85
  }
69
86
  /**
87
+ * Get app name from package.json in the given directory.
88
+ * Handles scoped packages by extracting the name after the scope.
89
+ *
90
+ * @example
91
+ * getAppNameFromCwd('/path/to/apps/api')
92
+ * // package.json: { "name": "@myorg/api" }
93
+ * // Returns: 'api'
94
+ */
95
+ function getAppNameFromCwd(cwd = process.cwd()) {
96
+ const packageJsonPath = (0, node_path.join)(cwd, "package.json");
97
+ if (!(0, node_fs.existsSync)(packageJsonPath)) return null;
98
+ try {
99
+ const packageJson = JSON.parse((0, node_fs.readFileSync)(packageJsonPath, "utf-8"));
100
+ const name = packageJson.name;
101
+ if (!name) return null;
102
+ if (name.startsWith("@") && name.includes("/")) return name.split("/")[1] ?? null;
103
+ return name;
104
+ } catch {
105
+ return null;
106
+ }
107
+ }
108
+ /**
70
109
  * Load raw configuration from file.
71
110
  */
72
111
  async function loadRawConfig(cwd) {
73
- const configPath = findConfigPath(cwd);
112
+ const { configPath, workspaceRoot } = findConfigPath(cwd);
74
113
  try {
75
114
  const config = await import(configPath);
76
- return config.default;
115
+ return {
116
+ config: config.default,
117
+ workspaceRoot
118
+ };
77
119
  } catch (error) {
78
120
  throw new Error(`Failed to load config: ${error.message}`);
79
121
  }
@@ -85,7 +127,7 @@ async function loadRawConfig(cwd) {
85
127
  * @deprecated Use loadWorkspaceConfig for new code
86
128
  */
87
129
  async function loadConfig(cwd = process.cwd()) {
88
- const config = await loadRawConfig(cwd);
130
+ const { config } = await loadRawConfig(cwd);
89
131
  if (require_workspace.isWorkspaceConfig(config)) throw new Error("Workspace configuration detected. Use loadWorkspaceConfig() instead.");
90
132
  return config;
91
133
  }
@@ -107,8 +149,40 @@ async function loadConfig(cwd = process.cwd()) {
107
149
  * ```
108
150
  */
109
151
  async function loadWorkspaceConfig(cwd = process.cwd()) {
110
- const config = await loadRawConfig(cwd);
111
- return require_workspace.processConfig(config, cwd);
152
+ const { config, workspaceRoot } = await loadRawConfig(cwd);
153
+ return require_workspace.processConfig(config, workspaceRoot);
154
+ }
155
+ /**
156
+ * Load app-specific configuration from workspace.
157
+ * Uses the app name from package.json to find the correct app config.
158
+ *
159
+ * @example
160
+ * ```ts
161
+ * // From apps/api directory with package.json: { "name": "@myorg/api" }
162
+ * const { app, workspace, workspaceRoot } = await loadAppConfig();
163
+ * console.log(app.routes); // './src/endpoints/**\/*.ts'
164
+ * ```
165
+ */
166
+ async function loadAppConfig(cwd = process.cwd()) {
167
+ const appName = getAppNameFromCwd(cwd);
168
+ if (!appName) throw new Error("Could not determine app name. Ensure package.json exists with a \"name\" field.");
169
+ const { config, workspaceRoot } = await loadRawConfig(cwd);
170
+ const loadedConfig = require_workspace.processConfig(config, workspaceRoot);
171
+ const app = loadedConfig.workspace.apps[appName];
172
+ if (!app) {
173
+ const availableApps = Object.keys(loadedConfig.workspace.apps).join(", ");
174
+ throw new Error(`App "${appName}" not found in workspace config. Available apps: ${availableApps}. Ensure the package.json name matches the app key in gkm.config.ts.`);
175
+ }
176
+ const gkmConfig = require_workspace.getAppGkmConfig(loadedConfig.workspace, appName);
177
+ if (!gkmConfig) throw new Error(`App "${appName}" is not a backend app and cannot be run with gkm dev.`);
178
+ return {
179
+ appName,
180
+ app,
181
+ gkmConfig,
182
+ workspace: loadedConfig.workspace,
183
+ workspaceRoot,
184
+ appRoot: (0, node_path.join)(workspaceRoot, app.path)
185
+ };
112
186
  }
113
187
 
114
188
  //#endregion
@@ -118,6 +192,18 @@ Object.defineProperty(exports, 'defineConfig', {
118
192
  return defineConfig;
119
193
  }
120
194
  });
195
+ Object.defineProperty(exports, 'getAppNameFromCwd', {
196
+ enumerable: true,
197
+ get: function () {
198
+ return getAppNameFromCwd;
199
+ }
200
+ });
201
+ Object.defineProperty(exports, 'loadAppConfig', {
202
+ enumerable: true,
203
+ get: function () {
204
+ return loadAppConfig;
205
+ }
206
+ });
121
207
  Object.defineProperty(exports, 'loadConfig', {
122
208
  enumerable: true,
123
209
  get: function () {
@@ -136,4 +222,4 @@ Object.defineProperty(exports, 'parseModuleConfig', {
136
222
  return parseModuleConfig;
137
223
  }
138
224
  });
139
- //# sourceMappingURL=config-CxrLu8ia.cjs.map
225
+ //# sourceMappingURL=config-CTftATBX.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-CTftATBX.cjs","names":["config: GkmConfig","configString: string","defaultAlias: string","cwd: string"],"sources":["../src/config.ts"],"sourcesContent":["import { existsSync, readFileSync } from 'node:fs';\nimport { dirname, join, parse } from 'node:path';\nimport type { GkmConfig } from './types.js';\nimport {\n\tgetAppGkmConfig,\n\tisWorkspaceConfig,\n\ttype LoadedConfig,\n\ttype NormalizedAppConfig,\n\ttype NormalizedWorkspace,\n\tprocessConfig,\n\ttype WorkspaceConfig,\n} from './workspace/index.js';\n\nexport type { GkmConfig } from './types.js';\nexport type { LoadedConfig, WorkspaceConfig } from './workspace/index.js';\nexport { defineWorkspace } from './workspace/index.js';\n/**\n * Define GKM configuration with full TypeScript support.\n * This is an identity function that provides type safety and autocomplete.\n *\n * @example\n * ```ts\n * // gkm.config.ts\n * import { defineConfig } from '@geekmidas/cli/config';\n *\n * export default defineConfig({\n * routes: './src/endpoints/**\\/*.ts',\n * envParser: './src/config/env',\n * logger: './src/config/logger',\n * telescope: true,\n * });\n * ```\n */\nexport function defineConfig(config: GkmConfig): GkmConfig {\n\treturn config;\n}\n\nexport interface ParsedModuleConfig {\n\tpath: string;\n\timportPattern: string;\n}\n\n/**\n * Parse a module config string into path and import pattern.\n *\n * @param configString - Config string in format \"./path/to/module\" or \"./path/to/module#exportName\"\n * @param defaultAlias - The default alias name to use if no export name specified\n * @returns Object with path and import pattern\n *\n * @example\n * parseModuleConfig('./src/config/env', 'envParser')\n * // { path: './src/config/env', importPattern: 'envParser' }\n *\n * parseModuleConfig('./src/config/env#envParser', 'envParser')\n * // { path: './src/config/env', importPattern: '{ envParser }' }\n *\n * parseModuleConfig('./src/config/env#myEnv', 'envParser')\n * // { path: './src/config/env', importPattern: '{ myEnv as envParser }' }\n */\nexport function parseModuleConfig(\n\tconfigString: string,\n\tdefaultAlias: string,\n): ParsedModuleConfig {\n\tconst parts = configString.split('#');\n\tconst path = parts[0] ?? configString;\n\tconst exportName = parts[1];\n\tconst importPattern = !exportName\n\t\t? defaultAlias\n\t\t: exportName === defaultAlias\n\t\t\t? `{ ${defaultAlias} }`\n\t\t\t: `{ ${exportName} as ${defaultAlias} }`;\n\n\treturn { path, importPattern };\n}\n\nexport interface ConfigDiscoveryResult {\n\tconfigPath: string;\n\tworkspaceRoot: string;\n}\n\n/**\n * Find and return the path to the config file.\n *\n * Resolution order:\n * 1. GKM_CONFIG_PATH env var (set by workspace dev command)\n * 2. Walk up directory tree from cwd\n */\nfunction findConfigPath(cwd: string): ConfigDiscoveryResult {\n\tconst files = ['gkm.config.json', 'gkm.config.ts', 'gkm.config.js'];\n\n\t// Check GKM_CONFIG_PATH env var first (set by workspace dev command)\n\tconst envConfigPath = process.env.GKM_CONFIG_PATH;\n\tif (envConfigPath && existsSync(envConfigPath)) {\n\t\treturn {\n\t\t\tconfigPath: envConfigPath,\n\t\t\tworkspaceRoot: dirname(envConfigPath),\n\t\t};\n\t}\n\n\t// Walk up directory tree to find config\n\tlet currentDir = cwd;\n\tconst { root } = parse(currentDir);\n\n\twhile (currentDir !== root) {\n\t\tfor (const file of files) {\n\t\t\tconst configPath = join(currentDir, file);\n\t\t\tif (existsSync(configPath)) {\n\t\t\t\treturn {\n\t\t\t\t\tconfigPath,\n\t\t\t\t\tworkspaceRoot: currentDir,\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t\tcurrentDir = dirname(currentDir);\n\t}\n\n\tthrow new Error(\n\t\t'Configuration file not found. Please create gkm.config.json, gkm.config.ts, or gkm.config.js in the project root.',\n\t);\n}\n\n/**\n * Get app name from package.json in the given directory.\n * Handles scoped packages by extracting the name after the scope.\n *\n * @example\n * getAppNameFromCwd('/path/to/apps/api')\n * // package.json: { \"name\": \"@myorg/api\" }\n * // Returns: 'api'\n */\nexport function getAppNameFromCwd(cwd: string = process.cwd()): string | null {\n\tconst packageJsonPath = join(cwd, 'package.json');\n\n\tif (!existsSync(packageJsonPath)) {\n\t\treturn null;\n\t}\n\n\ttry {\n\t\tconst packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));\n\t\tconst name = packageJson.name as string | undefined;\n\n\t\tif (!name) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// Handle scoped packages: @scope/name -> name\n\t\tif (name.startsWith('@') && name.includes('/')) {\n\t\t\treturn name.split('/')[1] ?? null;\n\t\t}\n\n\t\treturn name;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\ninterface RawConfigResult {\n\tconfig: GkmConfig | WorkspaceConfig;\n\tworkspaceRoot: string;\n}\n\n/**\n * Load raw configuration from file.\n */\nasync function loadRawConfig(cwd: string): Promise<RawConfigResult> {\n\tconst { configPath, workspaceRoot } = findConfigPath(cwd);\n\n\ttry {\n\t\tconst config = await import(configPath);\n\t\treturn {\n\t\t\tconfig: config.default,\n\t\t\tworkspaceRoot,\n\t\t};\n\t} catch (error) {\n\t\tthrow new Error(`Failed to load config: ${(error as Error).message}`);\n\t}\n}\n\n/**\n * Load configuration file (single-app format).\n * For backwards compatibility with existing code.\n *\n * @deprecated Use loadWorkspaceConfig for new code\n */\nexport async function loadConfig(\n\tcwd: string = process.cwd(),\n): Promise<GkmConfig> {\n\tconst { config } = await loadRawConfig(cwd);\n\n\t// If it's a workspace config, throw an error\n\tif (isWorkspaceConfig(config)) {\n\t\tthrow new Error(\n\t\t\t'Workspace configuration detected. Use loadWorkspaceConfig() instead.',\n\t\t);\n\t}\n\n\treturn config;\n}\n\n/**\n * Load configuration file and process it as a workspace.\n * Works with both single-app and workspace configurations.\n *\n * Single-app configs are automatically wrapped as a workspace with one app.\n *\n * @example\n * ```ts\n * const { type, workspace } = await loadWorkspaceConfig();\n *\n * if (type === 'workspace') {\n * console.log('Multi-app workspace:', workspace.apps);\n * } else {\n * console.log('Single app wrapped as workspace');\n * }\n * ```\n */\nexport async function loadWorkspaceConfig(\n\tcwd: string = process.cwd(),\n): Promise<LoadedConfig> {\n\tconst { config, workspaceRoot } = await loadRawConfig(cwd);\n\treturn processConfig(config, workspaceRoot);\n}\n\nexport interface AppConfigResult {\n\tappName: string;\n\tapp: NormalizedAppConfig;\n\tgkmConfig: GkmConfig;\n\tworkspace: NormalizedWorkspace;\n\tworkspaceRoot: string;\n\tappRoot: string;\n}\n\n/**\n * Load app-specific configuration from workspace.\n * Uses the app name from package.json to find the correct app config.\n *\n * @example\n * ```ts\n * // From apps/api directory with package.json: { \"name\": \"@myorg/api\" }\n * const { app, workspace, workspaceRoot } = await loadAppConfig();\n * console.log(app.routes); // './src/endpoints/**\\/*.ts'\n * ```\n */\nexport async function loadAppConfig(\n\tcwd: string = process.cwd(),\n): Promise<AppConfigResult> {\n\tconst appName = getAppNameFromCwd(cwd);\n\n\tif (!appName) {\n\t\tthrow new Error(\n\t\t\t'Could not determine app name. Ensure package.json exists with a \"name\" field.',\n\t\t);\n\t}\n\n\tconst { config, workspaceRoot } = await loadRawConfig(cwd);\n\tconst loadedConfig = processConfig(config, workspaceRoot);\n\n\t// Find the app in workspace (apps is a Record<string, NormalizedAppConfig>)\n\tconst app = loadedConfig.workspace.apps[appName];\n\n\tif (!app) {\n\t\tconst availableApps = Object.keys(loadedConfig.workspace.apps).join(', ');\n\t\tthrow new Error(\n\t\t\t`App \"${appName}\" not found in workspace config. Available apps: ${availableApps}. ` +\n\t\t\t\t`Ensure the package.json name matches the app key in gkm.config.ts.`,\n\t\t);\n\t}\n\n\t// Get the app's GKM config using the helper\n\tconst gkmConfig = getAppGkmConfig(loadedConfig.workspace, appName);\n\n\tif (!gkmConfig) {\n\t\tthrow new Error(\n\t\t\t`App \"${appName}\" is not a backend app and cannot be run with gkm dev.`,\n\t\t);\n\t}\n\n\treturn {\n\t\tappName,\n\t\tapp,\n\t\tgkmConfig,\n\t\tworkspace: loadedConfig.workspace,\n\t\tworkspaceRoot,\n\t\tappRoot: join(workspaceRoot, app.path),\n\t};\n}\n"],"mappings":"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"}
package/dist/config.cjs CHANGED
@@ -1,8 +1,10 @@
1
1
  const require_workspace = require('./workspace-iWgBlX6h.cjs');
2
- const require_config = require('./config-CxrLu8ia.cjs');
2
+ const require_config = require('./config-CTftATBX.cjs');
3
3
 
4
4
  exports.defineConfig = require_config.defineConfig;
5
5
  exports.defineWorkspace = require_workspace.defineWorkspace;
6
+ exports.getAppNameFromCwd = require_config.getAppNameFromCwd;
7
+ exports.loadAppConfig = require_config.loadAppConfig;
6
8
  exports.loadConfig = require_config.loadConfig;
7
9
  exports.loadWorkspaceConfig = require_config.loadWorkspaceConfig;
8
10
  exports.parseModuleConfig = require_config.parseModuleConfig;
package/dist/config.d.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { GkmConfig } from "./types-l53qUmGt.cjs";
2
- import { LoadedConfig, WorkspaceConfig, defineWorkspace } from "./index-DEWYvYvg.cjs";
2
+ import { LoadedConfig, NormalizedAppConfig, NormalizedWorkspace, WorkspaceConfig, defineWorkspace } from "./index-DEWYvYvg.cjs";
3
3
 
4
4
  //#region src/config.d.ts
5
5
 
@@ -43,6 +43,20 @@ interface ParsedModuleConfig {
43
43
  * // { path: './src/config/env', importPattern: '{ myEnv as envParser }' }
44
44
  */
45
45
  declare function parseModuleConfig(configString: string, defaultAlias: string): ParsedModuleConfig;
46
+ interface ConfigDiscoveryResult {
47
+ configPath: string;
48
+ workspaceRoot: string;
49
+ }
50
+ /**
51
+ * Get app name from package.json in the given directory.
52
+ * Handles scoped packages by extracting the name after the scope.
53
+ *
54
+ * @example
55
+ * getAppNameFromCwd('/path/to/apps/api')
56
+ * // package.json: { "name": "@myorg/api" }
57
+ * // Returns: 'api'
58
+ */
59
+ declare function getAppNameFromCwd(cwd?: string): string | null;
46
60
  /**
47
61
  * Load configuration file (single-app format).
48
62
  * For backwards compatibility with existing code.
@@ -68,7 +82,27 @@ declare function loadConfig(cwd?: string): Promise<GkmConfig>;
68
82
  * ```
69
83
  */
70
84
  declare function loadWorkspaceConfig(cwd?: string): Promise<LoadedConfig>;
85
+ interface AppConfigResult {
86
+ appName: string;
87
+ app: NormalizedAppConfig;
88
+ gkmConfig: GkmConfig;
89
+ workspace: NormalizedWorkspace;
90
+ workspaceRoot: string;
91
+ appRoot: string;
92
+ }
93
+ /**
94
+ * Load app-specific configuration from workspace.
95
+ * Uses the app name from package.json to find the correct app config.
96
+ *
97
+ * @example
98
+ * ```ts
99
+ * // From apps/api directory with package.json: { "name": "@myorg/api" }
100
+ * const { app, workspace, workspaceRoot } = await loadAppConfig();
101
+ * console.log(app.routes); // './src/endpoints/**\/*.ts'
102
+ * ```
103
+ */
104
+ declare function loadAppConfig(cwd?: string): Promise<AppConfigResult>;
71
105
  //# sourceMappingURL=config.d.ts.map
72
106
  //#endregion
73
- export { GkmConfig, LoadedConfig, ParsedModuleConfig, WorkspaceConfig, defineConfig, defineWorkspace, loadConfig, loadWorkspaceConfig, parseModuleConfig };
107
+ export { AppConfigResult, ConfigDiscoveryResult, GkmConfig, LoadedConfig, ParsedModuleConfig, WorkspaceConfig, defineConfig, defineWorkspace, getAppNameFromCwd, loadAppConfig, loadConfig, loadWorkspaceConfig, parseModuleConfig };
74
108
  //# sourceMappingURL=config.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.cts","names":[],"sources":["../src/config.ts"],"sourcesContent":[],"mappings":";;;;;;;;AA8B0D;AAI1D;AAsBA;AAwDA;;;;AAEU;AA8BV;;;;AAEU;;iBApHM,YAAA,SAAqB,YAAY;UAIhC,kBAAA;;;;;;;;;;;;;;;;;;;;;iBAsBD,iBAAA,8CAGb;;;;;;;iBAqDmB,UAAA,gBAEnB,QAAQ;;;;;;;;;;;;;;;;;;iBA8BW,mBAAA,gBAEnB,QAAQ"}
1
+ {"version":3,"file":"config.d.cts","names":[],"sources":["../src/config.ts"],"sourcesContent":[],"mappings":";;;;;;;;AAiC0D;AAI1D;AAsBA;AAgBA;AAuDA;AAsDA;;;;AAEU;AA8BV;;;;AAEU,iBAzLM,YAAA,CAyLN,MAAA,EAzL2B,SAyL3B,CAAA,EAzLuC,SAyLvC;AAKO,UA1LA,kBAAA,CA0Le;EAAA,IAAA,EAAA,MAAA;EAAA,aAE1B,EAAA,MAAA;;;AAEyB;AAgB/B;;;;AAEU;;;;;;;;;;;iBA1LM,iBAAA,8CAGb;UAac,qBAAA;;;;;;;;;;;;;iBAuDD,iBAAA;;;;;;;iBAsDM,UAAA,gBAEnB,QAAQ;;;;;;;;;;;;;;;;;;iBA8BW,mBAAA,gBAEnB,QAAQ;UAKM,eAAA;;OAEX;aACM;aACA;;;;;;;;;;;;;;;iBAgBU,aAAA,gBAEnB,QAAQ"}
package/dist/config.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { GkmConfig } from "./types-K2uQJ-FO.mjs";
2
- import { LoadedConfig, WorkspaceConfig, defineWorkspace } from "./index-CWN-bgrO.mjs";
2
+ import { LoadedConfig, NormalizedAppConfig, NormalizedWorkspace, WorkspaceConfig, defineWorkspace } from "./index-CWN-bgrO.mjs";
3
3
 
4
4
  //#region src/config.d.ts
5
5
 
@@ -43,6 +43,20 @@ interface ParsedModuleConfig {
43
43
  * // { path: './src/config/env', importPattern: '{ myEnv as envParser }' }
44
44
  */
45
45
  declare function parseModuleConfig(configString: string, defaultAlias: string): ParsedModuleConfig;
46
+ interface ConfigDiscoveryResult {
47
+ configPath: string;
48
+ workspaceRoot: string;
49
+ }
50
+ /**
51
+ * Get app name from package.json in the given directory.
52
+ * Handles scoped packages by extracting the name after the scope.
53
+ *
54
+ * @example
55
+ * getAppNameFromCwd('/path/to/apps/api')
56
+ * // package.json: { "name": "@myorg/api" }
57
+ * // Returns: 'api'
58
+ */
59
+ declare function getAppNameFromCwd(cwd?: string): string | null;
46
60
  /**
47
61
  * Load configuration file (single-app format).
48
62
  * For backwards compatibility with existing code.
@@ -68,7 +82,27 @@ declare function loadConfig(cwd?: string): Promise<GkmConfig>;
68
82
  * ```
69
83
  */
70
84
  declare function loadWorkspaceConfig(cwd?: string): Promise<LoadedConfig>;
85
+ interface AppConfigResult {
86
+ appName: string;
87
+ app: NormalizedAppConfig;
88
+ gkmConfig: GkmConfig;
89
+ workspace: NormalizedWorkspace;
90
+ workspaceRoot: string;
91
+ appRoot: string;
92
+ }
93
+ /**
94
+ * Load app-specific configuration from workspace.
95
+ * Uses the app name from package.json to find the correct app config.
96
+ *
97
+ * @example
98
+ * ```ts
99
+ * // From apps/api directory with package.json: { "name": "@myorg/api" }
100
+ * const { app, workspace, workspaceRoot } = await loadAppConfig();
101
+ * console.log(app.routes); // './src/endpoints/**\/*.ts'
102
+ * ```
103
+ */
104
+ declare function loadAppConfig(cwd?: string): Promise<AppConfigResult>;
71
105
  //# sourceMappingURL=config.d.ts.map
72
106
  //#endregion
73
- export { GkmConfig, LoadedConfig, ParsedModuleConfig, WorkspaceConfig, defineConfig, defineWorkspace, loadConfig, loadWorkspaceConfig, parseModuleConfig };
107
+ export { AppConfigResult, ConfigDiscoveryResult, GkmConfig, LoadedConfig, ParsedModuleConfig, WorkspaceConfig, defineConfig, defineWorkspace, getAppNameFromCwd, loadAppConfig, loadConfig, loadWorkspaceConfig, parseModuleConfig };
74
108
  //# sourceMappingURL=config.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.mts","names":[],"sources":["../src/config.ts"],"sourcesContent":[],"mappings":";;;;;;;;AA8B0D;AAI1D;AAsBA;AAwDA;;;;AAEU;AA8BV;;;;AAEU;;iBApHM,YAAA,SAAqB,YAAY;UAIhC,kBAAA;;;;;;;;;;;;;;;;;;;;;iBAsBD,iBAAA,8CAGb;;;;;;;iBAqDmB,UAAA,gBAEnB,QAAQ;;;;;;;;;;;;;;;;;;iBA8BW,mBAAA,gBAEnB,QAAQ"}
1
+ {"version":3,"file":"config.d.mts","names":[],"sources":["../src/config.ts"],"sourcesContent":[],"mappings":";;;;;;;;AAiC0D;AAI1D;AAsBA;AAgBA;AAuDA;AAsDA;;;;AAEU;AA8BV;;;;AAEU,iBAzLM,YAAA,CAyLN,MAAA,EAzL2B,SAyL3B,CAAA,EAzLuC,SAyLvC;AAKO,UA1LA,kBAAA,CA0Le;EAAA,IAAA,EAAA,MAAA;EAAA,aAE1B,EAAA,MAAA;;;AAEyB;AAgB/B;;;;AAEU;;;;;;;;;;;iBA1LM,iBAAA,8CAGb;UAac,qBAAA;;;;;;;;;;;;;iBAuDD,iBAAA;;;;;;;iBAsDM,UAAA,gBAEnB,QAAQ;;;;;;;;;;;;;;;;;;iBA8BW,mBAAA,gBAEnB,QAAQ;UAKM,eAAA;;OAEX;aACM;aACA;;;;;;;;;;;;;;;iBAgBU,aAAA,gBAEnB,QAAQ"}
package/dist/config.mjs CHANGED
@@ -1,4 +1,4 @@
1
1
  import { defineWorkspace } from "./workspace-CPLEZDZf.mjs";
2
- import { defineConfig, loadConfig, loadWorkspaceConfig, parseModuleConfig } from "./config-BaYqrF3n.mjs";
2
+ import { defineConfig, getAppNameFromCwd, loadAppConfig, loadConfig, loadWorkspaceConfig, parseModuleConfig } from "./config-BogU0_oQ.mjs";
3
3
 
4
- export { defineConfig, defineWorkspace, loadConfig, loadWorkspaceConfig, parseModuleConfig };
4
+ export { defineConfig, defineWorkspace, getAppNameFromCwd, loadAppConfig, loadConfig, loadWorkspaceConfig, parseModuleConfig };