configenvy 0.1.7 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -91,7 +91,7 @@ var presetConfigs = {
91
91
  }
92
92
  };
93
93
  var availablePresetNames = Object.keys(presetConfigs).sort();
94
- var availablePresetList = availablePresetNames.join(", ");
94
+ var availablePresetList = ["auto", ...availablePresetNames].join(", ");
95
95
  var require2 = createRequire(import.meta.url);
96
96
  var cliPackage = require2("../package.json");
97
97
  var cliVersion = cliPackage.version;
@@ -124,10 +124,11 @@ async function runDoctor(projectPath, options, dependencies = defaultDependencie
124
124
  async function runInit(projectPath, options = {}, dependencies = defaultDependencies) {
125
125
  const rootDir = dependencies.resolvePath(projectPath);
126
126
  const result = await dependencies.scanProject({ rootDir });
127
- const preset = resolvePreset(options.preset, dependencies);
128
- if (options.preset && !preset) return;
127
+ const preset = await resolvePreset(rootDir, options.preset, dependencies);
128
+ if (options.preset && !preset.config && options.preset !== "auto") return;
129
+ if (preset.message) dependencies.log(preset.message);
129
130
  const existingEnvExample = options.envExample && options.force ? await readOptionalText(dependencies.resolvePath(rootDir, ".env.example"), dependencies) : void 0;
130
- const files = buildInitFiles(rootDir, result, Boolean(options.envExample), dependencies.resolvePath, existingEnvExample, preset);
131
+ const files = buildInitFiles(rootDir, result, Boolean(options.envExample), dependencies.resolvePath, existingEnvExample, preset.config);
131
132
  if (options.dryRun) {
132
133
  for (const file of files) {
133
134
  dependencies.log(`Would write ${file.path}`);
@@ -177,14 +178,67 @@ function buildInitFiles(rootDir, result, includeEnvExample, resolvePath = resolv
177
178
  }
178
179
  return files;
179
180
  }
180
- function resolvePreset(name, dependencies) {
181
- if (!name) return void 0;
181
+ async function resolvePreset(rootDir, name, dependencies) {
182
+ if (!name) return {};
183
+ if (name === "auto") {
184
+ return detectPreset(rootDir, dependencies);
185
+ }
182
186
  if (name in presetConfigs) {
183
- return presetConfigs[name];
187
+ return { config: presetConfigs[name] };
184
188
  }
185
189
  dependencies.error(`Unknown preset "${name}". Available presets: ${availablePresetList}.`);
186
190
  dependencies.exit(1);
187
- return void 0;
191
+ return {};
192
+ }
193
+ async function detectPreset(rootDir, dependencies) {
194
+ const packageJson = await readPackageJson(rootDir, dependencies);
195
+ const packages = new Set(Object.keys({
196
+ ...packageJson?.dependencies,
197
+ ...packageJson?.devDependencies
198
+ }));
199
+ const packageDetections = [
200
+ ["nextjs", "next", 'dependency "next"'],
201
+ ["astro", "astro", 'dependency "astro"'],
202
+ ["nuxt", "nuxt", 'dependency "nuxt"'],
203
+ ["sveltekit", "@sveltejs/kit", 'dependency "@sveltejs/kit"'],
204
+ ["vite", "vite", 'dependency "vite"']
205
+ ];
206
+ for (const [presetName, packageName, reason] of packageDetections) {
207
+ if (packages.has(packageName)) {
208
+ return detectedPreset(presetName, reason);
209
+ }
210
+ }
211
+ const configDetections = [
212
+ ["nextjs", ["next.config.js", "next.config.mjs", "next.config.ts"]],
213
+ ["astro", ["astro.config.js", "astro.config.mjs", "astro.config.ts"]],
214
+ ["nuxt", ["nuxt.config.js", "nuxt.config.mjs", "nuxt.config.ts"]],
215
+ ["sveltekit", ["svelte.config.js", "svelte.config.ts"]],
216
+ ["vite", ["vite.config.js", "vite.config.mjs", "vite.config.ts"]]
217
+ ];
218
+ for (const [presetName, files] of configDetections) {
219
+ for (const file of files) {
220
+ if (await readOptionalText(dependencies.resolvePath(rootDir, file), dependencies) !== void 0) {
221
+ return detectedPreset(presetName, `found ${file}`);
222
+ }
223
+ }
224
+ }
225
+ return { message: "No framework preset detected. Using the base config." };
226
+ }
227
+ function detectedPreset(name, reason) {
228
+ return {
229
+ config: presetConfigs[name],
230
+ message: `Detected preset: ${name}
231
+ Reason: ${reason}`
232
+ };
233
+ }
234
+ async function readPackageJson(rootDir, dependencies) {
235
+ const content = await readOptionalText(dependencies.resolvePath(rootDir, "package.json"), dependencies);
236
+ if (content === void 0) return void 0;
237
+ try {
238
+ return JSON.parse(content);
239
+ } catch {
240
+ return void 0;
241
+ }
188
242
  }
189
243
  function mergeUnique(base, extra) {
190
244
  return [.../* @__PURE__ */ new Set([...base, ...extra])].sort();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "configenvy",
3
- "version": "0.1.7",
3
+ "version": "0.2.0",
4
4
  "description": "Find missing, unused, undocumented, and risky environment variables before setup breaks.",
5
5
  "type": "module",
6
6
  "engines": {
@@ -35,7 +35,7 @@
35
35
  "build": "tsup src/index.ts --format esm --dts --clean"
36
36
  },
37
37
  "dependencies": {
38
- "@configenvy/core": "0.1.7",
38
+ "@configenvy/core": "0.2.0",
39
39
  "commander": "^12.1.0"
40
40
  },
41
41
  "keywords": [
package/src/index.ts CHANGED
@@ -171,13 +171,18 @@ const presetConfigs = {
171
171
  } satisfies Record<string, Partial<StarterConfig>>;
172
172
 
173
173
  const availablePresetNames = Object.keys(presetConfigs).sort();
174
- const availablePresetList = availablePresetNames.join(", ");
174
+ const availablePresetList = ["auto", ...availablePresetNames].join(", ");
175
175
 
176
176
  type InitFile = {
177
177
  content: string;
178
178
  path: string;
179
179
  };
180
180
 
181
+ type PresetResolution = {
182
+ config?: Partial<StarterConfig>;
183
+ message?: string;
184
+ };
185
+
181
186
  const require = createRequire(import.meta.url);
182
187
  const cliPackage = require("../package.json") as { version: string };
183
188
  export const cliVersion = cliPackage.version;
@@ -224,12 +229,13 @@ export async function runInit(
224
229
  ): Promise<void> {
225
230
  const rootDir = dependencies.resolvePath(projectPath);
226
231
  const result = await dependencies.scanProject({ rootDir });
227
- const preset = resolvePreset(options.preset, dependencies);
228
- if (options.preset && !preset) return;
232
+ const preset = await resolvePreset(rootDir, options.preset, dependencies);
233
+ if (options.preset && !preset.config && options.preset !== "auto") return;
234
+ if (preset.message) dependencies.log(preset.message);
229
235
  const existingEnvExample = options.envExample && options.force
230
236
  ? await readOptionalText(dependencies.resolvePath(rootDir, ".env.example"), dependencies)
231
237
  : undefined;
232
- const files = buildInitFiles(rootDir, result, Boolean(options.envExample), dependencies.resolvePath, existingEnvExample, preset);
238
+ const files = buildInitFiles(rootDir, result, Boolean(options.envExample), dependencies.resolvePath, existingEnvExample, preset.config);
233
239
 
234
240
  if (options.dryRun) {
235
241
  for (const file of files) {
@@ -293,14 +299,78 @@ export function buildInitFiles(
293
299
  return files;
294
300
  }
295
301
 
296
- function resolvePreset(name: string | undefined, dependencies: CliDependencies): Partial<StarterConfig> | undefined {
297
- if (!name) return undefined;
302
+ async function resolvePreset(rootDir: string, name: string | undefined, dependencies: CliDependencies): Promise<PresetResolution> {
303
+ if (!name) return {};
304
+ if (name === "auto") {
305
+ return detectPreset(rootDir, dependencies);
306
+ }
298
307
  if (name in presetConfigs) {
299
- return presetConfigs[name as PresetName];
308
+ return { config: presetConfigs[name as PresetName] };
300
309
  }
301
310
  dependencies.error(`Unknown preset "${name}". Available presets: ${availablePresetList}.`);
302
311
  dependencies.exit(1);
303
- return undefined;
312
+ return {};
313
+ }
314
+
315
+ async function detectPreset(rootDir: string, dependencies: CliDependencies): Promise<PresetResolution> {
316
+ const packageJson = await readPackageJson(rootDir, dependencies);
317
+ const packages = new Set(Object.keys({
318
+ ...packageJson?.dependencies,
319
+ ...packageJson?.devDependencies
320
+ }));
321
+
322
+ const packageDetections: Array<[PresetName, string, string]> = [
323
+ ["nextjs", "next", "dependency \"next\""],
324
+ ["astro", "astro", "dependency \"astro\""],
325
+ ["nuxt", "nuxt", "dependency \"nuxt\""],
326
+ ["sveltekit", "@sveltejs/kit", "dependency \"@sveltejs/kit\""],
327
+ ["vite", "vite", "dependency \"vite\""]
328
+ ];
329
+ for (const [presetName, packageName, reason] of packageDetections) {
330
+ if (packages.has(packageName)) {
331
+ return detectedPreset(presetName, reason);
332
+ }
333
+ }
334
+
335
+ const configDetections: Array<[PresetName, string[]]> = [
336
+ ["nextjs", ["next.config.js", "next.config.mjs", "next.config.ts"]],
337
+ ["astro", ["astro.config.js", "astro.config.mjs", "astro.config.ts"]],
338
+ ["nuxt", ["nuxt.config.js", "nuxt.config.mjs", "nuxt.config.ts"]],
339
+ ["sveltekit", ["svelte.config.js", "svelte.config.ts"]],
340
+ ["vite", ["vite.config.js", "vite.config.mjs", "vite.config.ts"]]
341
+ ];
342
+ for (const [presetName, files] of configDetections) {
343
+ for (const file of files) {
344
+ if (await readOptionalText(dependencies.resolvePath(rootDir, file), dependencies) !== undefined) {
345
+ return detectedPreset(presetName, `found ${file}`);
346
+ }
347
+ }
348
+ }
349
+
350
+ return { message: "No framework preset detected. Using the base config." };
351
+ }
352
+
353
+ function detectedPreset(name: PresetName, reason: string): PresetResolution {
354
+ return {
355
+ config: presetConfigs[name],
356
+ message: `Detected preset: ${name}\nReason: ${reason}`
357
+ };
358
+ }
359
+
360
+ async function readPackageJson(rootDir: string, dependencies: CliDependencies): Promise<{
361
+ dependencies?: Record<string, string>;
362
+ devDependencies?: Record<string, string>;
363
+ } | undefined> {
364
+ const content = await readOptionalText(dependencies.resolvePath(rootDir, "package.json"), dependencies);
365
+ if (content === undefined) return undefined;
366
+ try {
367
+ return JSON.parse(content) as {
368
+ dependencies?: Record<string, string>;
369
+ devDependencies?: Record<string, string>;
370
+ };
371
+ } catch {
372
+ return undefined;
373
+ }
304
374
  }
305
375
 
306
376
  function mergeUnique(base: string[], extra: readonly string[]): string[] {