@romaintaillandier1978/dotenv-never-lies 0.3.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/README.md +437 -160
  2. package/dist/cli/commands/assert.d.ts +4 -2
  3. package/dist/cli/commands/assert.d.ts.map +1 -1
  4. package/dist/cli/commands/assert.js +7 -9
  5. package/dist/cli/commands/explain.d.ts +6 -1
  6. package/dist/cli/commands/explain.d.ts.map +1 -1
  7. package/dist/cli/commands/explain.js +9 -16
  8. package/dist/cli/commands/export.d.ts +35 -0
  9. package/dist/cli/commands/export.d.ts.map +1 -0
  10. package/dist/cli/commands/export.js +268 -0
  11. package/dist/cli/commands/generate.d.ts +10 -2
  12. package/dist/cli/commands/generate.d.ts.map +1 -1
  13. package/dist/cli/commands/generate.js +9 -7
  14. package/dist/cli/commands/reverseEnv.d.ts +8 -2
  15. package/dist/cli/commands/reverseEnv.d.ts.map +1 -1
  16. package/dist/cli/commands/reverseEnv.js +21 -8
  17. package/dist/cli/index.js +323 -99
  18. package/dist/cli/utils/exitCodes.d.ts +8 -0
  19. package/dist/cli/utils/exitCodes.d.ts.map +1 -0
  20. package/dist/cli/utils/exitCodes.js +8 -0
  21. package/dist/cli/utils/infer-schema.d.ts.map +1 -1
  22. package/dist/cli/utils/infer-schema.js +4 -3
  23. package/dist/cli/utils/load-schema.d.ts.map +1 -1
  24. package/dist/cli/utils/load-schema.js +20 -12
  25. package/dist/cli/utils/printer.d.ts.map +1 -1
  26. package/dist/cli/utils/printer.js +5 -4
  27. package/dist/cli/utils/resolve-schema.d.ts.map +1 -1
  28. package/dist/cli/utils/resolve-schema.js +7 -3
  29. package/dist/cli/utils/toFile.d.ts +2 -0
  30. package/dist/cli/utils/toFile.d.ts.map +1 -0
  31. package/dist/cli/utils/toFile.js +8 -0
  32. package/dist/core.d.ts +33 -33
  33. package/dist/core.js +10 -10
  34. package/dist/errors.d.ts +29 -2
  35. package/dist/errors.d.ts.map +1 -1
  36. package/dist/errors.js +33 -4
  37. package/dist/romaintaillandier1978-dotenv-never-lies-0.3.0.tgz +0 -0
  38. package/package.json +9 -9
package/dist/cli/index.js CHANGED
@@ -1,127 +1,351 @@
1
1
  #!/usr/bin/env node
2
- import { program } from "commander";
2
+ import { program, CommanderError } from "commander";
3
3
  import { assertCommand } from "./commands/assert.js";
4
4
  import { generateCommand } from "./commands/generate.js";
5
5
  import { reverseEnvCommand } from "./commands/reverseEnv.js";
6
- import { explainCommand } from "./commands/explain.js";
6
+ import { explainCommand, printHuman } from "./commands/explain.js";
7
+ import { exportCommand } from "./commands/export.js";
8
+ import { toFile } from "./utils/toFile.js";
9
+ import { DnlError, ExitCodes, ValidationError } from "../errors.js";
10
+ import { createRequire } from "node:module";
11
+ const require = createRequire(import.meta.url);
12
+ const packageJson = require("../../package.json");
13
+ const exitCodeHelp = {
14
+ [ExitCodes.success]: "Success (everything is valid, exit OK)",
15
+ [ExitCodes.usageError]: "Usage error or internal error",
16
+ [ExitCodes.schemaNotFound]: "DNL schema not found or not resolved",
17
+ [ExitCodes.validationError]: "Validation failed (invalid environment)",
18
+ [ExitCodes.exportError]: "Export error (format, file writing, secret, etc.)",
19
+ };
20
+ // #region Program
7
21
  program
8
22
  .name("dnl")
9
- .version("0.1.0")
10
- .addHelpText("before", `
11
- CLI pour dotenv-never-lies.
12
- Valide, charge et génère des variables d’environnement typées à partir d’un schéma TypeScript/Zod.
23
+ //.version("0.3.0")
24
+ .version(packageJson.version)
25
+ // allows passing positional arguments, before/after options
26
+ .enablePositionalOptions()
27
+ .exitOverride()
28
+ .addHelpText("before", `Summary:
29
+ CLI for dotenv-never-lies.
30
+ Validates typed environment variables from a TypeScript/Zod schema.
13
31
  `)
14
- .addHelpText("after", `\nExemples :
32
+ .option("--schema <file>", "DNL schema file (e.g., path/to/my-dnl.ts). See the Environment schema section for details.")
33
+ .addHelpText("after", `\nExit codes:\n${Object.entries(exitCodeHelp)
34
+ .map(([key, value]) => ` - ${key}: ${value}`)
35
+ .join("\n")}
36
+ `)
37
+ .addHelpText("after", `\nEnvironment schema:
38
+ The dotenv-never-lies schema is resolved in the following order:
39
+ 1. --schema option if provided
40
+ 2. "dotenv-never-lies.schema" key in package.json
41
+ 3. Convention files:
42
+ - env.dnl.ts
43
+ - env.dnl.js
44
+ - dnl.config.ts
45
+ - dnl.config.js
46
+ If no schema is found, the command fails.
47
+ `)
48
+ .addHelpText("after", `\nExamples:
15
49
 
16
- # Vérifier l’environnement à l’exécution et arrêter le process si le schéma n’est pas respecté
17
- dnl assert
18
- dnl assert --schema env.dnl.ts
19
-
20
- # Générer un fichier .env documenté à partir du schéma
21
- dnl generate
22
- dnl generate --schema env.dnl.ts --out .env
23
-
24
- # Créer un schéma env.dnl.ts depuis un .env existant
25
- dnl reverse-env --source .env
26
-
27
- # Afficher les variables connues et leur description
28
- dnl explain
29
- `);
50
+ # Check the environment at runtime and exit the process if the schema is not satisfied
51
+ dnl assert
52
+ dnl assert --schema my-dnl.ts
53
+
54
+ # Generate a documented .env file from the schema
55
+ dnl generate
56
+ dnl generate --schema my-dnl.ts --out .env
57
+
58
+ # Create an env.dnl.ts schema from an existing .env
59
+ dnl reverse-env --source .env
60
+
61
+ # Display known variables and their description
62
+ dnl explain
63
+
64
+ # Export variables in docker-args format
65
+ dnl export docker-args --source .env
66
+
67
+ `);
68
+ // #endregion Program
69
+ // #region assert
30
70
  program
31
71
  .command("assert")
32
- .description("Vérifie l’environnement runtime et termine le process si le schéma n’est pas respecté.")
33
- .option("--schema <file>", "Fichier de schéma dnl (ex: my-dnl.ts)", "env.dnl.ts")
34
- .option("-s, --source <source>", "Source des variables (défaut : process.env)")
72
+ .description("Verifies the runtime environment and exits the process if the schema is not satisfied.")
73
+ .option("-s, --source <source>", "Variables source (default: process.env)")
35
74
  .action(assertCommand)
36
- .addHelpText("after", `\nExemples :
75
+ .addHelpText("after", `\nExamples:
37
76
 
38
- # Valider les variables d’environnement de process.env
39
- # Recommandé en CI pour empêcher un démarrage avec une configuration invalide
40
- dnl assert
41
- dnl assert --schema my-dnl.ts
42
-
43
- # Valider les variables d’environnement depuis un fichier .env
44
- # Recommandé en local (préparation du schéma, onboarding)
45
- dnl assert --source .env
46
- dnl assert --schema my-dnl.ts --source .env
47
-
48
- # valider les variables d'environnement du fichier fourni par la CI
49
- dnl assert --source $ENV_FILE
50
- dnl assert --schema my-dnl.ts --source $ENV_FILE
77
+ # Validate environment variables from process.env
78
+ # Recommended in CI to prevent starting with an invalid configuration
79
+ dnl assert
80
+ dnl assert --schema my-dnl.ts
81
+
82
+ # Validate environment variables from a .env file
83
+ # Recommended locally (schema preparation, onboarding)
84
+ dnl assert --source .env
85
+ dnl assert --schema my-dnl.ts --source .env
86
+
87
+ # validate environment variables from the file provided by the CI
88
+ dnl assert --source $ENV_FILE
89
+ dnl assert --schema my-dnl.ts --source $ENV_FILE
51
90
  `);
91
+ // #endregion assert
92
+ // #region export
93
+ const exportHelp = {
94
+ "docker-args": "Arguments `--env KEY=VALUE` for `docker run`",
95
+ "docker-env": "File compatible with Docker `--env-file`",
96
+ "github-env": "Inject into a GitHub Actions job environment",
97
+ "github-secret": "GitHub Secrets via gh CLI (repo or organization)",
98
+ "gitlab-env": "GitLab CI environment variables",
99
+ "k8s-configmap": "Kubernetes ConfigMap (NON-sensitive variables)",
100
+ "k8s-secret": "Kubernetes Secret (sensitive variables only)",
101
+ env: ".env file cleaned (without unnecessary comments)",
102
+ json: "Key/value JSON object",
103
+ ts: "Typed TypeScript object",
104
+ js: "JavaScript object",
105
+ };
52
106
  program
53
- .command("generate")
54
- .description("Génère un fichier .env à partir d’un schéma dnl.\n" +
55
- "Utile pour initialiser un projet ou faciliter l’onboarding d’un nouveau développeur.\n" +
56
- "Seules les valeurs définies par défaut dans le schéma sont écrites.")
57
- .option("--schema <file>", "Fichier de schéma env (ex: env.dnl.ts)")
58
- .option("-o, --out <file>", "Fichier de sortie (défaut : .env)")
59
- .option("-f, --force", "Écraser le fichier existant")
60
- .action(generateCommand)
61
- .addHelpText("after", `\nExemples :
62
-
63
- # Générer un fichier .env à partir du schéma par défaut (env.dnl.ts)
64
- dnl generate
107
+ .command("export")
108
+ .description("Exports environment variables to a specified format. Variables are exported after being validated against the schema.")
109
+ .argument("<format>", "Export format. See list and examples at the end")
110
+ .option("-s, --source <source>", "Variables source (default: process.env if none provided)")
111
+ .option("--hide-secret", 'Mask sensitive variables (replace with "********")')
112
+ .option("--exclude-secret", "Exclude sensitive variables (do not show them at all)")
113
+ .option("--include-comments", "Include comments in the export (does not work with the json format)")
114
+ .option("--serialize-typed", "Serialize validated runtime values (js/ts/json only). See below for more details.")
115
+ .option("-o, --out <file>", "Output file")
116
+ .option("-f, --force", "Overwrite the existing file, in conjunction with -o or --out")
117
+ .option("--k8s-name <name>", "Name for the k8s resource. Default: env-secret for k8s-secret, env-config for k8s-configmap")
118
+ .option("--github-org <org>", "GitHub organization name")
119
+ .action(async (format, opts) => {
120
+ const { content, warnings, out } = await exportCommand({ ...opts, format });
121
+ if (out) {
122
+ await toFile(content, out, opts.force ?? false);
123
+ }
124
+ else {
125
+ console.log(content);
126
+ }
127
+ for (const warning of warnings) {
128
+ console.error(`${warning}`);
129
+ }
130
+ })
131
+ .addHelpText("after", `\nExport formats:\n${Object.entries(exportHelp)
132
+ .map(([key, value]) => ` - ${key}: ${value}`)
133
+ .join("\n")}
134
+ `)
135
+ .addHelpText("after", `\nSerialize validated runtime values (js/ts/json only):
136
+ When the --serialize-typed option is used, runtime values (after Zod transformations and validation)
137
+ are serialized instead of the raw (but still validated) values from the source (.env or process.env).
65
138
 
66
- # Générer un fichier .env à partir d'un schéma spécifié
67
- dnl generate --schema my-dnl.ts
139
+ Example:
68
140
 
69
- # Générer un fichier .env.local à partir du schéma
70
- dnl generate --out .env.local
141
+ .env file:
142
+ NODE_CORS_ORIGIN=https://a.site.com;https://b.site.com;https://c.site.com
71
143
 
72
- # Générer un fichier .env à partir d'un schéma et écraser le fichier existant
73
- dnl generate --out .env --force
144
+ env.dnl.ts file:
145
+ NODE_CORS_ORIGIN: {
146
+ description: "Allowed frontend URLs separated by semicolons",
147
+ schema: z.string().transform((v) =>
148
+ v
149
+ .split(";")
150
+ .map((s) => s.trim())
151
+ .filter(Boolean)
152
+ ),
153
+ },
154
+
155
+ dnl export json --source .env
156
+ {
157
+ "NODE_CORS_ORIGIN": "https://a.site.com;https://b.site.com;https://c.site.com"
158
+ }
159
+
160
+ dnl export json --source .env --serialize-typed
161
+ {
162
+ "NODE_CORS_ORIGIN": [
163
+ "https://a.site.com",
164
+ "https://b.site.com",
165
+ "https://c.site.com"
166
+ ]
167
+ }
168
+
169
+ `)
170
+ .addHelpText("after", `\nExamples:
171
+
172
+ # --- Simple cases ----------------------------------------------------
173
+
174
+ # Export environment variables as JSON from a .env file
175
+ dnl export json --source .env
176
+
177
+ # Clean a .env file (remove comments and extraneous lines)
178
+ dnl export env --source .env --out .env.clean
179
+ dnl export env --source .env -fo .env
180
+
181
+
182
+ # --- Docker / CI ----------------------------------------------------
183
+
184
+ # Export variables as docker-args
185
+ dnl export docker-args --source .env
186
+
187
+ # Concrete CI example to run a Docker container
188
+ # (variables are injected dynamically)
189
+ docker run \\
190
+ $(dnl export docker-args --source $DOTENV_FILE) \\
191
+ --restart always \\
192
+ -d my-image:latest
193
+
194
+
195
+ # --- GitHub Actions -------------------------------------------------
196
+
197
+ # Export variables as GitHub secrets (current repo)
198
+ # Requires gh CLI configured (gh auth login)
199
+ dnl export github-secret
200
+
201
+ # Export variables as GitHub organization secrets
202
+ dnl export github-secret --github-org my-org
203
+
204
+ # Example usage in a GitHub Actions job:
205
+ # (variables are injected into the job environment)
206
+ dnl export github-env >> $GITHUB_ENV
207
+
208
+
209
+ # --- Kubernetes -----------------------------------------------------
210
+
211
+ # Generate a Kubernetes ConfigMap (NON-sensitive variables), from process.env
212
+ dnl export k8s-configmap --out k8s-configmap.yaml
213
+
214
+ # Generate a Kubernetes Secret from a .env file
215
+ dnl export k8s-secret --source .env --k8s-name my-secret --out k8s-secret.yaml
216
+
217
+ # Apply the generated files
218
+ kubectl apply -f k8s-configmap.yaml
219
+ kubectl apply -f k8s-secret.yaml
220
+
221
+ # note: if no secret is present in the dnl config, for k8s-secret the output will be empty
222
+
223
+ # --- TypeScript / JavaScript ---------------------------------------
224
+
225
+ # Export variables as a typed TypeScript object, or js
226
+ dnl export ts --out env.generated.ts --serialize-typed
227
+ dnl export js --out env.generated.js --serialize-typed
228
+ `);
229
+ // #endregion export
230
+ // #region generate
231
+ program
232
+ .command("generate")
233
+ .description("Generates a .env file from a DNL schema.\n" +
234
+ "Useful to bootstrap a project or facilitate onboarding of a new developer.\n" +
235
+ "Only default values defined in the schema are written.")
236
+ .option("-o, --out <file>", "Output file (default: .env)")
237
+ .option("-f, --force", "Overwrite existing file")
238
+ .action(async (opts) => {
239
+ const { content, out } = await generateCommand(opts);
240
+ await toFile(content, out, opts.force ?? false);
241
+ })
242
+ .addHelpText("after", `\nExamples:
243
+
244
+ # Generate a .env file from the default schema (env.dnl.ts)
245
+ dnl generate
246
+
247
+ # Generate a .env file from a specified schema
248
+ dnl generate --schema my-dnl.ts
249
+
250
+ # Generate a .env.local file from the schema
251
+ dnl generate --out .env.local
252
+
253
+ # Generate a .env file from a schema and overwrite the existing file
254
+ dnl generate --out .env --force
74
255
  `);
256
+ // #endregion generate
257
+ // #region reverse-env
75
258
  program
76
259
  .command("reverse-env")
77
- .description("Génère un schéma dotenv-never-lies à partir d’un fichier .env.\n" +
78
- "Utile pour migrer un projet existant vers dotenv-never-lies.\n" +
79
- "Le schéma généré est un point de départ et doit être affiné manuellement.")
80
- .option("-s, --source <source>", "Fichier .env source", ".env")
81
- .option("-o, --out <file>", "Fichier dnl de sortie", "env.dnl.ts")
82
- .option("-f, --force", "Écraser le fichier existant")
83
- .option("--guess-secret", "Tenter de deviner les variables sensibles (heuristique)")
84
- .action(reverseEnvCommand)
85
- .addHelpText("after", `\nExemples :
86
-
87
- # Générer un schéma env.dnl.ts à partir d'un fichier .env
88
- dnl reverse-env
89
-
90
- # Générer un schéma env.dnl.ts à partir d'un fichier .env.local
91
- dnl reverse-env --source .env.local
260
+ .description("Generates a dotenv-never-lies schema from a .env file.\n" +
261
+ "Useful to migrate an existing project to dotenv-never-lies.\n" +
262
+ "The generated schema is a starting point and must be refined manually.\n" +
263
+ "Keys in the .env file that are not valid identifiers are escaped to JSON strings. (e.g. MY-KEY -> 'MY-KEY')")
264
+ .option("-s, --source <source>", "Source .env file", ".env")
265
+ .option("-o, --out <file>", "Output DNL file", "env.dnl.ts")
266
+ .option("-f, --force", "Overwrite existing file")
267
+ .option("--guess-secret", "Try to guess sensitive variables (heuristic)")
268
+ .action(async (opts) => {
269
+ const { content, out, warnings } = await reverseEnvCommand(opts);
270
+ await toFile(content, out, opts.force ?? false);
271
+ for (const warning of warnings) {
272
+ console.error(`${warning}`);
273
+ }
274
+ })
275
+ .addHelpText("after", `\nExamples:
92
276
 
93
- # Générer un schéma my-dnl.ts à partir d'un fichier .env
94
- dnl reverse-env --out my-dnl.ts
95
-
96
- # Générer un schéma env.dnl.ts à partir d'un fichier .env et écraser le fichier existant
97
- dnl reverse-env --force
98
- `);
277
+ # Generate an env.dnl.ts schema from a .env file, try to guess sensitive variables
278
+ dnl reverse-env --guess-secret
279
+
280
+ # Generate an env.dnl.ts schema from a .env.local file
281
+ dnl reverse-env --source .env.local
282
+
283
+ # Generate a my-dnl.ts schema from a .env file
284
+ dnl reverse-env --out my-dnl.ts
285
+
286
+ # Generate an env.dnl.ts schema from a .env file and overwrite the existing file
287
+ dnl reverse-env --force
288
+ `);
289
+ // #endregion reverse-env
290
+ // #region explain
99
291
  program
100
292
  .command("explain")
101
- .description("Affiche la liste des variables d’environnement connues et leur description.")
102
- .argument("[keys...]", "Clés à expliquer (0..N). Sans argument, toutes les clés.")
103
- .option("--schema <file>", "Fichier de schéma env (ex: env.dnl.ts)")
104
- .option("-f, --format <format>", 'Format d\'affichage ("human" | "json")', "human")
293
+ .description("Displays the list of known environment variables and their description.")
294
+ .argument("[keys...]", "Keys to explain (0..N). Without argument, all keys.")
295
+ .option("-f, --format <format>", 'Output format ("human" | "json")', "human")
105
296
  .action(async (keys, opts) => {
106
- const result = await explainCommand({ keys: keys ?? [], schema: opts.schema, format: opts.format });
107
- process.exit(result);
297
+ const { format, result } = await explainCommand({ keys: keys ?? [], schema: opts.schema, format: opts.format });
298
+ if (format === "human") {
299
+ printHuman(result);
300
+ }
301
+ else {
302
+ console.log(JSON.stringify(result, null, 2));
303
+ }
108
304
  })
109
- .addHelpText("after", `\nExemples :
305
+ .addHelpText("after", `\nExamples:
110
306
 
111
- # expliquer toutes les variables connues et leur description
112
- dnl explain
113
-
114
- # expliquer une variable en détail
115
- dnl explain NODE_ENV
116
-
117
- # sortie machine
118
- dnl explain --format json
119
-
120
- # expliquer toutes les variables connues et leur description à partir d'un schéma
121
- dnl explain --schema another-env.ts
122
-
123
- # expliquer une partie des variables connues et leur description
124
- dnl explain NODE_ENV NODE_PORT
307
+ # explain all known variables and their description
308
+ dnl explain
309
+
310
+ # explain a variable in detail
311
+ dnl explain NODE_ENV
312
+
313
+ # machine-readable output
314
+ dnl explain --format json
315
+
316
+ # explain all known variables and their description from a schema
317
+ dnl explain --schema my-dnl.ts
318
+
319
+ # explain a subset of known variables and their description
320
+ dnl explain NODE_ENV NODE_PORT
125
321
 
126
322
  `);
127
- program.parse(process.argv);
323
+ // #endregion explain
324
+ try {
325
+ await program.parseAsync(process.argv);
326
+ process.exit(ExitCodes.success);
327
+ }
328
+ catch (err) {
329
+ // Commander throws a controlled error when help or version is displayed
330
+ if (err instanceof CommanderError) {
331
+ if (err.code === "commander.helpDisplayed" || err.code === "commander.version") {
332
+ process.exit(ExitCodes.success);
333
+ }
334
+ process.exit(typeof err.exitCode === "number" ? err.exitCode : ExitCodes.usageError);
335
+ }
336
+ if (err instanceof ValidationError) {
337
+ console.error("❌ Invalid environment variables:\n");
338
+ for (const issue of err.issues ?? []) {
339
+ console.error(`- ${issue.key}`);
340
+ console.error(` → ${issue.message}`);
341
+ }
342
+ process.exit(err.exitCode);
343
+ }
344
+ if (err instanceof DnlError) {
345
+ console.error(err.message);
346
+ process.exit(err.exitCode);
347
+ }
348
+ console.error("Unexpected error");
349
+ console.error(err);
350
+ process.exit(ExitCodes.usageError);
351
+ }
@@ -0,0 +1,8 @@
1
+ export declare enum ExitCodes {
2
+ success = 0,
3
+ usageError = 1,
4
+ schemaNotFound = 2,
5
+ validationError = 3,
6
+ exportError = 4
7
+ }
8
+ //# sourceMappingURL=exitCodes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exitCodes.d.ts","sourceRoot":"","sources":["../../../src/cli/utils/exitCodes.ts"],"names":[],"mappings":"AAAA,oBAAY,SAAS;IACjB,OAAO,IAAI;IACX,UAAU,IAAI;IACd,cAAc,IAAI;IAClB,eAAe,IAAI;IACnB,WAAW,IAAI;CAClB"}
@@ -0,0 +1,8 @@
1
+ export var ExitCodes;
2
+ (function (ExitCodes) {
3
+ ExitCodes[ExitCodes["success"] = 0] = "success";
4
+ ExitCodes[ExitCodes["usageError"] = 1] = "usageError";
5
+ ExitCodes[ExitCodes["schemaNotFound"] = 2] = "schemaNotFound";
6
+ ExitCodes[ExitCodes["validationError"] = 3] = "validationError";
7
+ ExitCodes[ExitCodes["exportError"] = 4] = "exportError";
8
+ })(ExitCodes || (ExitCodes = {}));
@@ -1 +1 @@
1
- {"version":3,"file":"infer-schema.d.ts","sourceRoot":"","sources":["../../../src/cli/utils/infer-schema.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,WAAW,GAAI,OAAO,MAAM,GAAG,SAAS,oIAuBpD,CAAC;AAIF,eAAO,MAAM,WAAW,GAAI,OAAO,MAAM,YAExC,CAAC"}
1
+ {"version":3,"file":"infer-schema.d.ts","sourceRoot":"","sources":["../../../src/cli/utils/infer-schema.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,WAAW,GAAI,OAAO,MAAM,GAAG,SAAS,oIAuBpD,CAAC;AAIF,eAAO,MAAM,WAAW,GAAI,OAAO,MAAM,YAGxC,CAAC"}
@@ -1,5 +1,5 @@
1
1
  export const inferSchema = (value) => {
2
- if (!value) {
2
+ if (value === undefined) {
3
3
  return "z.string().optional()";
4
4
  }
5
5
  if (/^(true|false)$/i.test(value)) {
@@ -18,7 +18,8 @@ export const inferSchema = (value) => {
18
18
  }
19
19
  return "z.string()";
20
20
  };
21
- const secretSuffixes = ["_SECRET", "_KEY", "_TOKEN", "_PASSWORD", "_AUTH"];
21
+ const secretMarkers = ["SECRET", "KEY", "TOKEN", "PASSWORD", "PASS", "AUTH"];
22
22
  export const guessSecret = (value) => {
23
- return secretSuffixes.some((suffix) => value.endsWith(suffix));
23
+ const parts = value.toUpperCase().split(/[_\-]/);
24
+ return secretMarkers.some((marker) => parts.includes(marker));
24
25
  };
@@ -1 +1 @@
1
- {"version":3,"file":"load-schema.d.ts","sourceRoot":"","sources":["../../../src/cli/utils/load-schema.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAEpD,eAAO,MAAM,OAAO,GAAU,YAAY,MAAM,KAAG,OAAO,CAAC,mBAAmB,CAAC,GAAG,CAAC,CAsBlF,CAAC"}
1
+ {"version":3,"file":"load-schema.d.ts","sourceRoot":"","sources":["../../../src/cli/utils/load-schema.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAGpD,eAAO,MAAM,OAAO,GAAU,YAAY,MAAM,KAAG,OAAO,CAAC,mBAAmB,CAAC,GAAG,CAAC,CA2BlF,CAAC"}
@@ -2,21 +2,29 @@ import { build } from "esbuild";
2
2
  import path from "node:path";
3
3
  import fs from "node:fs/promises";
4
4
  import { pathToFileURL } from "node:url";
5
+ import { SchemaNotFoundError } from "../../errors.js";
5
6
  export const loadDef = async (schemaPath) => {
6
7
  const outDir = path.join(process.cwd(), ".dnl");
7
8
  await fs.mkdir(outDir, { recursive: true });
9
+ // We always overwrite the file here; this could be an issue.
8
10
  const outFile = path.join(outDir, "env.dnl.mjs");
9
- await build({
10
- entryPoints: [schemaPath],
11
- outfile: outFile,
12
- format: "esm",
13
- platform: "node",
14
- target: "node18",
15
- bundle: false,
16
- });
17
- const mod = await import(pathToFileURL(outFile).href);
18
- if (!mod.default) {
19
- throw new Error("Le fichier env.dnl.ts doit exporter un schéma par défaut (export default).");
11
+ try {
12
+ await build({
13
+ entryPoints: [schemaPath],
14
+ outfile: outFile,
15
+ format: "esm",
16
+ platform: "node",
17
+ target: "node18",
18
+ bundle: true,
19
+ packages: "external",
20
+ });
21
+ const mod = await import(pathToFileURL(outFile).href);
22
+ if (!mod.default) {
23
+ throw new SchemaNotFoundError(`The file ${schemaPath} must export a default schema (export default).`);
24
+ }
25
+ return mod.default;
26
+ }
27
+ catch (error) {
28
+ throw new SchemaNotFoundError(`Unable to load DNL schema (${schemaPath}): ${error}`);
20
29
  }
21
- return mod.default;
22
30
  };
@@ -1 +1 @@
1
- {"version":3,"file":"printer.d.ts","sourceRoot":"","sources":["../../../src/cli/utils/printer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEjD,MAAM,MAAM,WAAW,GAAG;IACtB,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB,CAAC;AACF,eAAO,MAAM,aAAa,GAAI,KAAK,MAAM,EAAE,OAAO,gBAAgB,CAAC,GAAG,CAAC,KAAG,WAWzE,CAAC;AAEF,wBAAgB,YAAY,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,WAAW,GAAG,MAAM,CAoE5D;AAuBD,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,WAAW,GAAG,MAAM,GAAG,SAAS,CAwB9E;AAED,wBAAgB,UAAU,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,WAAW,GAAG,OAAO,CAyB3D"}
1
+ {"version":3,"file":"printer.d.ts","sourceRoot":"","sources":["../../../src/cli/utils/printer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEjD,MAAM,MAAM,WAAW,GAAG;IACtB,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB,CAAC;AACF,eAAO,MAAM,aAAa,GAAI,KAAK,MAAM,EAAE,OAAO,gBAAgB,CAAC,GAAG,CAAC,KAAG,WAWzE,CAAC;AAEF,wBAAgB,YAAY,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,WAAW,GAAG,MAAM,CAqE5D;AAuBD,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,WAAW,GAAG,MAAM,GAAG,SAAS,CAwB9E;AAED,wBAAgB,UAAU,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,WAAW,GAAG,OAAO,CAyB3D"}
@@ -45,11 +45,12 @@ export function printZodType(def) {
45
45
  }
46
46
  return "unknown | null";
47
47
  case "default":
48
+ //TODO : ignore les valeurs par défaut falsy (0, false, "") dans printZodType, donc dnl explain omet des defaults valides.
48
49
  if ("innerType" in def) {
49
50
  const result = printZodType(def.innerType);
50
51
  const defaultValue = typeof def.defaultValue === "function" ? def.defaultValue() : (def.defaultValue ?? undefined);
51
52
  // const defaultValue = (def as any).defaultValue;
52
- if (defaultValue) {
53
+ if (defaultValue !== undefined) {
53
54
  return result + " (default: " + defaultValue.toString() + ")";
54
55
  }
55
56
  return result;
@@ -97,7 +98,7 @@ export function getDefaultEnvValue(def) {
97
98
  const raw = typeof def.defaultValue === "function" ? def.defaultValue() : (def.defaultValue ?? undefined);
98
99
  return stringifyEnvValue(raw);
99
100
  }
100
- // wrappers transparents
101
+ // transparent wrappers
101
102
  case "optional":
102
103
  case "nullable":
103
104
  if ("innerType" in def) {
@@ -119,13 +120,13 @@ export function isRequired(def) {
119
120
  return false;
120
121
  case "default":
121
122
  return false;
122
- // nullable n’enlève PAS le required
123
+ // nullable DOES NOT remove the required
123
124
  case "nullable":
124
125
  if ("innerType" in def) {
125
126
  return isRequired(def.innerType);
126
127
  }
127
128
  return false;
128
- // pipe / transform → transparent côté required
129
+ // pipe / transform → transparent regarding required
129
130
  case "pipe":
130
131
  if ("in" in def) {
131
132
  return isRequired(def.in);
@@ -1 +1 @@
1
- {"version":3,"file":"resolve-schema.d.ts","sourceRoot":"","sources":["../../../src/cli/utils/resolve-schema.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,iBAAiB,GAAI,UAAU,MAAM,KAAG,MA0BpD,CAAC"}
1
+ {"version":3,"file":"resolve-schema.d.ts","sourceRoot":"","sources":["../../../src/cli/utils/resolve-schema.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,iBAAiB,GAAI,UAAU,MAAM,KAAG,MA6BpD,CAAC"}
@@ -1,10 +1,15 @@
1
1
  import fs from "node:fs";
2
2
  import path from "node:path";
3
+ import { SchemaNotFoundError } from "../../errors.js";
3
4
  const CANDIDATES = ["env.dnl.ts", "env.dnl.js", "dnl.config.ts", "dnl.config.js"];
4
5
  export const resolveSchemaPath = (cliPath) => {
5
6
  // 1. --schema
6
7
  if (cliPath) {
7
- return path.resolve(process.cwd(), cliPath);
8
+ const full = path.resolve(process.cwd(), cliPath);
9
+ if (!fs.existsSync(full)) {
10
+ throw new SchemaNotFoundError(`Schema file not found: ${cliPath}`);
11
+ }
12
+ return full;
8
13
  }
9
14
  // 2. package.json
10
15
  const pkgPath = path.resolve(process.cwd(), "package.json");
@@ -18,10 +23,9 @@ export const resolveSchemaPath = (cliPath) => {
18
23
  // 3. convention
19
24
  for (const file of CANDIDATES) {
20
25
  const full = path.resolve(process.cwd(), file);
21
- console.log("full", full);
22
26
  if (fs.existsSync(full)) {
23
27
  return full;
24
28
  }
25
29
  }
26
- throw new Error("No env schema found. Use --schema or define one in package.json.");
30
+ throw new SchemaNotFoundError("No env schema found. Use --schema, define dotenv-never-lies.schema in package.json, or add env.dnl.ts");
27
31
  };
@@ -0,0 +1,2 @@
1
+ export declare const toFile: (content: string, path: string, force?: boolean) => Promise<void>;
2
+ //# sourceMappingURL=toFile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toFile.d.ts","sourceRoot":"","sources":["../../../src/cli/utils/toFile.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,MAAM,GAAU,SAAS,MAAM,EAAE,MAAM,MAAM,EAAE,QAAO,OAAe,KAAG,OAAO,CAAC,IAAI,CAKhG,CAAC"}