@romaintaillandier1978/dotenv-never-lies 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli/index.js CHANGED
@@ -1,77 +1,224 @@
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]: "Succès (tout est valide, sortie OK)",
15
+ [ExitCodes.usageError]: "Erreur d’usage ou erreur système",
16
+ [ExitCodes.schemaNotFound]: "Schéma DNL introuvable ou non résolu",
17
+ [ExitCodes.validationError]: "Validation échouée (env invalide)",
18
+ [ExitCodes.exportError]: "Erreur d’export (format, écriture fichier, 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
+ // permet de passer des arguments positionnels, avant / après les options
26
+ .enablePositionalOptions()
27
+ .exitOverride()
28
+ .addHelpText("before", `Résumé :
29
+ CLI pour dotenv-never-lies.
30
+ Valide les variables d’environnement typées à partir d’un schéma TypeScript/Zod.
13
31
  `)
32
+ .option("--schema <file>", "Fichier de schéma dnl (ex: path/to/my-dnl.ts). Voir la section Schéma d’environnement pour plus de détails.")
33
+ .addHelpText("after", `\nExit codes :\n${Object.entries(exitCodeHelp)
34
+ .map(([key, value]) => ` - ${key}: ${value}`)
35
+ .join("\n")}
36
+ `)
37
+ .addHelpText("after", `\nSchéma d’environnement :
38
+ Le schéma dotenv-never-lies est résolu dans l’ordre suivant :
39
+ 1. Option --schema si fournie
40
+ 2. Clé "dotenv-never-lies.schema" dans package.json
41
+ 3. Fichiers par convention :
42
+ - env.dnl.ts
43
+ - env.dnl.js
44
+ - dnl.config.ts
45
+ - dnl.config.js
46
+ Si aucun schéma n’est trouvé, la commande échoue.
47
+ `)
14
48
  .addHelpText("after", `\nExemples :
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
+ # Vérifier l’environnement à l’exécution et arrêter le process si le schéma n’est pas respecté
51
+ dnl assert
52
+ dnl assert --schema my-dnl.ts
53
+
54
+ # Générer un fichier .env documenté à partir du schéma
55
+ dnl generate
56
+ dnl generate --schema my-dnl.ts --out .env
57
+
58
+ # Créer un schéma env.dnl.ts depuis un .env existant
59
+ dnl reverse-env --source .env
60
+
61
+ # Afficher les variables connues et leur description
62
+ dnl explain
63
+
64
+ # Exporter les variables au format docker-args
65
+ dnl export docker-args --source .env
66
+
67
+ `);
68
+ // #endregion Program
69
+ // #region assert
30
70
  program
31
71
  .command("assert")
32
72
  .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
73
  .option("-s, --source <source>", "Source des variables (défaut : process.env)")
35
74
  .action(assertCommand)
36
75
  .addHelpText("after", `\nExemples :
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
+ # Valider les variables d’environnement de process.env
78
+ # Recommandé en CI pour empêcher un démarrage avec une configuration invalide
79
+ dnl assert
80
+ dnl assert --schema my-dnl.ts
81
+
82
+ # Valider les variables d’environnement depuis un fichier .env
83
+ # Recommandé en local (préparation du schéma, onboarding)
84
+ dnl assert --source .env
85
+ dnl assert --schema my-dnl.ts --source .env
86
+
87
+ # valider les variables d'environnement du fichier fourni par la 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` pour `docker run`",
95
+ "docker-env": "Fichier compatible `--env-file` Docker",
96
+ "github-env": "Injection dans l’environnement d’un job GitHub Actions",
97
+ "github-secret": "Secrets GitHub via gh CLI (repo ou organisation)",
98
+ "gitlab-env": "Variables d’environnement GitLab CI",
99
+ "k8s-configmap": "ConfigMap Kubernetes (variables NON sensibles)",
100
+ "k8s-secret": "Secret Kubernetes (variables sensibles uniquement)",
101
+ env: "Fichier .env nettoyé (sans commentaires inutiles)",
102
+ json: "Objet JSON clé/valeur",
103
+ ts: "Objet TypeScript typé",
104
+ js: "Objet JavaScript",
105
+ };
106
+ program
107
+ .command("export")
108
+ .description("Exporte les variables d'environnement dans un format spécifié")
109
+ .argument("<format>", "Format d'exportation. Voir liste et exemples à la fin")
110
+ .option("-s, --source <source>", "Source des variables (sans source process.env sera utilisé)")
111
+ .option("--hide-secret", 'Masquer les variables sensibles (rempalcer par "********")')
112
+ .option("--exclude-secret", "Exclure les variables sensibles (ne pas les montrer du tout)")
113
+ .option("--include-comments", "Inclure les commentaires dans l'exportation (ne fonctionne pas avec le format json)")
114
+ .option("-o, --out <file>", "Fichier de sortie")
115
+ .option("-f,--force", "Écraser le fichier existant, en conjonction avec l'option -o ou --out")
116
+ .option("--k8s-name <name>", "Nom du secret k8s default: env-secret pour le format k8s-secret, env-config pour le format k8s-configmap")
117
+ .option("--github-org <org>", "Nom de l'organisation github")
118
+ .action(async (opts) => {
119
+ const { content, warnings, out } = await exportCommand(opts);
120
+ if (out) {
121
+ await toFile(content, out, opts.force ?? false);
122
+ }
123
+ else {
124
+ console.log(content);
125
+ }
126
+ for (const warning of warnings) {
127
+ console.error(`${warning}`);
128
+ }
129
+ })
130
+ .addHelpText("after", `\nFormats d'exportation :\n${Object.entries(exportHelp)
131
+ .map(([key, value]) => ` - ${key}: ${value}`)
132
+ .join("\n")}
133
+ `)
134
+ .addHelpText("after", `\nExemples :
135
+
136
+ # --- Cas simples ----------------------------------------------------
137
+
138
+ # Exporter les variables d'environnement au format JSON depuis un fichier .env
139
+ dnl export json --source .env
140
+
141
+ # Nettoyer un fichier .env (retirer commentaires et lignes inutiles)
142
+ dnl export env --source .env --out .env.clean
143
+ dnl export env --source .env -fo .env
144
+
145
+
146
+ # --- Docker / CI ----------------------------------------------------
147
+
148
+ # Exporter les variables au format docker-args
149
+ dnl export docker-args --source .env
150
+
151
+ # Exemple concret en CI pour lancer un conteneur Docker
152
+ # (les variables sont injectées dynamiquement)
153
+ docker run \\
154
+ $(dnl export docker-args --source $DOTENV_FILE) \\
155
+ --restart always \\
156
+ -d my-image:latest
157
+
158
+
159
+ # --- GitHub Actions -------------------------------------------------
160
+
161
+ # Exporter les variables comme secrets GitHub (repo courant)
162
+ # Nécessite gh CLI configuré (gh auth login)
163
+ dnl export github-secret
164
+
165
+ # Exporter les variables comme secrets d'une organisation GitHub
166
+ dnl export github-secret --github-org my-org
167
+
168
+ # Exemple d'usage dans un job GitHub Actions :
169
+ # (les variables sont injectées dans l'environnement du job)
170
+ dnl export github-env >> $GITHUB_ENV
171
+
172
+
173
+ # --- Kubernetes -----------------------------------------------------
174
+
175
+ # Générer un ConfigMap Kubernetes (variables NON sensibles)
176
+ dnl export k8s-configmap --out k8s-configmap.yaml
177
+
178
+ # Générer un Secret Kubernetes à partir d'un fichier .env
179
+ dnl export k8s-secret --source .env --k8s-name my-secret --out k8s-secret.yaml
180
+
181
+ # Appliquer les fichiers générés
182
+ kubectl apply -f k8s-configmap.yaml
183
+ kubectl apply -f k8s-secret.yaml
184
+
185
+ # attention : si aucun secret n'est présent dans la config dnl, pour k8s-secret, la sortie sera vide
186
+
187
+ # --- TypeScript / JavaScript ---------------------------------------
188
+
189
+ # Exporter les variables sous forme d'objet TypeScript typé, ou js
190
+ dnl export ts --out env.generated.ts
191
+ dnl export js --out env.generated.js
192
+ `);
193
+ // #endregion export
194
+ // #region generate
52
195
  program
53
196
  .command("generate")
54
197
  .description("Génère un fichier .env à partir d’un schéma dnl.\n" +
55
198
  "Utile pour initialiser un projet ou faciliter l’onboarding d’un nouveau développeur.\n" +
56
199
  "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
200
  .option("-o, --out <file>", "Fichier de sortie (défaut : .env)")
59
201
  .option("-f, --force", "Écraser le fichier existant")
60
- .action(generateCommand)
202
+ .action(async (opts) => {
203
+ const { content, out } = await generateCommand(opts);
204
+ await toFile(content, out, opts.force ?? false);
205
+ })
61
206
  .addHelpText("after", `\nExemples :
62
207
 
63
- # Générer un fichier .env à partir du schéma par défaut (env.dnl.ts)
64
- dnl generate
65
-
66
- # Générer un fichier .env à partir d'un schéma spécifié
67
- dnl generate --schema my-dnl.ts
68
-
69
- # Générer un fichier .env.local à partir du schéma
70
- dnl generate --out .env.local
71
-
72
- # Générer un fichier .env à partir d'un schéma et écraser le fichier existant
73
- dnl generate --out .env --force
208
+ # Générer un fichier .env à partir du schéma par défaut (env.dnl.ts)
209
+ dnl generate
210
+
211
+ # Générer un fichier .env à partir d'un schéma spécifié
212
+ dnl generate --schema my-dnl.ts
213
+
214
+ # Générer un fichier .env.local à partir du schéma
215
+ dnl generate --out .env.local
216
+
217
+ # Générer un fichier .env à partir d'un schéma et écraser le fichier existant
218
+ dnl generate --out .env --force
74
219
  `);
220
+ // #endregion generate
221
+ // #region reverse-env
75
222
  program
76
223
  .command("reverse-env")
77
224
  .description("Génère un schéma dotenv-never-lies à partir d’un fichier .env.\n" +
@@ -81,47 +228,87 @@ program
81
228
  .option("-o, --out <file>", "Fichier dnl de sortie", "env.dnl.ts")
82
229
  .option("-f, --force", "Écraser le fichier existant")
83
230
  .option("--guess-secret", "Tenter de deviner les variables sensibles (heuristique)")
84
- .action(reverseEnvCommand)
231
+ .action(async (opts) => {
232
+ const { content, out, warnings } = await reverseEnvCommand(opts);
233
+ await toFile(content, out, opts.force ?? false);
234
+ for (const warning of warnings) {
235
+ console.error(`${warning}`);
236
+ }
237
+ })
85
238
  .addHelpText("after", `\nExemples :
86
239
 
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
92
-
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
- `);
240
+ # Générer un schéma env.dnl.ts à partir d'un fichier .env
241
+ dnl reverse-env
242
+
243
+ # Générer un schéma env.dnl.ts à partir d'un fichier .env.local
244
+ dnl reverse-env --source .env.local
245
+
246
+ # Générer un schéma my-dnl.ts à partir d'un fichier .env
247
+ dnl reverse-env --out my-dnl.ts
248
+
249
+ # Générer un schéma env.dnl.ts à partir d'un fichier .env et écraser le fichier existant
250
+ dnl reverse-env --force
251
+ `);
252
+ // #endregion reverse-env
253
+ // #region explain
99
254
  program
100
255
  .command("explain")
101
256
  .description("Affiche la liste des variables d’environnement connues et leur description.")
102
257
  .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
258
  .option("-f, --format <format>", 'Format d\'affichage ("human" | "json")', "human")
105
259
  .action(async (keys, opts) => {
106
- const result = await explainCommand({ keys: keys ?? [], schema: opts.schema, format: opts.format });
107
- process.exit(result);
260
+ const { format, result } = await explainCommand({ keys: keys ?? [], schema: opts.schema, format: opts.format });
261
+ if (format === "human") {
262
+ printHuman(result);
263
+ }
264
+ else {
265
+ console.log(JSON.stringify(result, null, 2));
266
+ }
108
267
  })
109
268
  .addHelpText("after", `\nExemples :
110
269
 
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
270
+ # expliquer toutes les variables connues et leur description
271
+ dnl explain
272
+
273
+ # expliquer une variable en détail
274
+ dnl explain NODE_ENV
275
+
276
+ # sortie machine
277
+ dnl explain --format json
278
+
279
+ # expliquer toutes les variables connues et leur description à partir d'un schéma
280
+ dnl explain --schema my-dnl.ts
281
+
282
+ # expliquer une partie des variables connues et leur description
283
+ dnl explain NODE_ENV NODE_PORT
125
284
 
126
285
  `);
127
- program.parse(process.argv);
286
+ // #endregion explain
287
+ try {
288
+ await program.parseAsync(process.argv);
289
+ process.exit(ExitCodes.success);
290
+ }
291
+ catch (err) {
292
+ // Commander lève une erreur contrôlée lorsque l'aide ou la version sont affichées
293
+ if (err instanceof CommanderError) {
294
+ if (err.code === "commander.helpDisplayed" || err.code === "commander.version") {
295
+ process.exit(ExitCodes.success);
296
+ }
297
+ process.exit(typeof err.exitCode === "number" ? err.exitCode : ExitCodes.usageError);
298
+ }
299
+ if (err instanceof ValidationError) {
300
+ console.error("❌ Invalid environment variables:\n");
301
+ for (const issue of err.issues ?? []) {
302
+ console.error(`- ${issue.key}`);
303
+ console.error(` → ${issue.message}`);
304
+ }
305
+ process.exit(err.exitCode);
306
+ }
307
+ if (err instanceof DnlError) {
308
+ console.error(err.message);
309
+ process.exit(err.exitCode);
310
+ }
311
+ console.error("Erreur inattendue");
312
+ console.error(err);
313
+ process.exit(ExitCodes.usageError);
314
+ }
@@ -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":"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,CA0BlF,CAAC"}
@@ -2,21 +2,28 @@ 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
+ // La on écrase toujours le fichier, mais ca pourrait être un problème.
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: false,
19
+ });
20
+ const mod = await import(pathToFileURL(outFile).href);
21
+ if (!mod.default) {
22
+ throw new SchemaNotFoundError(`Le fichier ${schemaPath} doit exporter un schéma par défaut (export default).`);
23
+ }
24
+ return mod.default;
25
+ }
26
+ catch (error) {
27
+ throw new SchemaNotFoundError(`Impossible de charger le schéma DNL (${schemaPath}): ${error}`);
20
28
  }
21
- return mod.default;
22
29
  };
@@ -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"}
@@ -0,0 +1,8 @@
1
+ import { ExportError } from "../../errors.js";
2
+ import fs from "node:fs";
3
+ export const toFile = async (content, path, force = false) => {
4
+ if (fs.existsSync(path) && !force) {
5
+ throw new ExportError(`${path} already exists. Use --force to overwrite.`);
6
+ }
7
+ fs.writeFileSync(path, content);
8
+ };
package/dist/core.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { z } from "zod";
2
2
  import dotenv from "dotenv";
3
3
  import dotenvExpand from "dotenv-expand";
4
- import { EnvFileNotFoundError } from "./errors.js";
4
+ import { DnlError, ExitCodes } from "./errors.js";
5
5
  import fs from "fs";
6
6
  /**
7
7
  * Définit un schéma d'environnement.
@@ -41,7 +41,7 @@ export const define = (def) => {
41
41
  */
42
42
  export const readEnvFile = (path) => {
43
43
  if (!fs.existsSync(path)) {
44
- throw new EnvFileNotFoundError(path);
44
+ throw new DnlError(`Env file not found: ${path}`, ExitCodes.usageError);
45
45
  }
46
46
  const content = fs.readFileSync(path);
47
47
  const parsed = dotenv.parse(content);
package/dist/errors.d.ts CHANGED
@@ -1,4 +1,31 @@
1
- export declare class EnvFileNotFoundError extends Error {
2
- constructor(path: string);
1
+ export declare enum ExitCodes {
2
+ success = 0,
3
+ usageError = 1,
4
+ schemaNotFound = 2,
5
+ validationError = 3,
6
+ exportError = 4
7
+ }
8
+ export declare class DnlError extends Error {
9
+ readonly exitCode: ExitCodes;
10
+ constructor(message: string, exitCode: ExitCodes);
11
+ }
12
+ export declare class UsageError extends DnlError {
13
+ constructor(message: string);
14
+ }
15
+ export declare class SchemaNotFoundError extends DnlError {
16
+ constructor(message: string);
17
+ }
18
+ export declare class ValidationError extends DnlError {
19
+ readonly issues?: {
20
+ key: string;
21
+ message: string;
22
+ }[] | undefined;
23
+ constructor(message: string, issues?: {
24
+ key: string;
25
+ message: string;
26
+ }[] | undefined);
27
+ }
28
+ export declare class ExportError extends DnlError {
29
+ constructor(message: string);
3
30
  }
4
31
  //# sourceMappingURL=errors.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,oBAAqB,SAAQ,KAAK;gBAC/B,IAAI,EAAE,MAAM;CAI3B"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,oBAAY,SAAS;IACjB,OAAO,IAAI;IACX,UAAU,IAAI;IACd,cAAc,IAAI;IAClB,eAAe,IAAI;IACnB,WAAW,IAAI;CAClB;AAED,qBAAa,QAAS,SAAQ,KAAK;aAGX,QAAQ,EAAE,SAAS;gBADnC,OAAO,EAAE,MAAM,EACC,QAAQ,EAAE,SAAS;CAI1C;AACD,qBAAa,UAAW,SAAQ,QAAQ;gBACxB,OAAO,EAAE,MAAM;CAG9B;AACD,qBAAa,mBAAoB,SAAQ,QAAQ;gBACjC,OAAO,EAAE,MAAM;CAG9B;AAED,qBAAa,eAAgB,SAAQ,QAAQ;aAGrB,MAAM,CAAC,EAAE;QACrB,GAAG,EAAE,MAAM,CAAC;QACZ,OAAO,EAAE,MAAM,CAAC;KACnB,EAAE;gBAJH,OAAO,EAAE,MAAM,EACC,MAAM,CAAC,EAAE;QACrB,GAAG,EAAE,MAAM,CAAC;QACZ,OAAO,EAAE,MAAM,CAAC;KACnB,EAAE,YAAA;CAIV;AAED,qBAAa,WAAY,SAAQ,QAAQ;gBACzB,OAAO,EAAE,MAAM;CAG9B"}
package/dist/errors.js CHANGED
@@ -1,6 +1,35 @@
1
- export class EnvFileNotFoundError extends Error {
2
- constructor(path) {
3
- super(`Env file not found: ${path}`);
4
- this.name = "EnvFileNotFoundError";
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 = {}));
9
+ export class DnlError extends Error {
10
+ constructor(message, exitCode) {
11
+ super(message);
12
+ this.exitCode = exitCode;
13
+ }
14
+ }
15
+ export class UsageError extends DnlError {
16
+ constructor(message) {
17
+ super(message, ExitCodes.usageError);
18
+ }
19
+ }
20
+ export class SchemaNotFoundError extends DnlError {
21
+ constructor(message) {
22
+ super(message, ExitCodes.schemaNotFound);
23
+ }
24
+ }
25
+ export class ValidationError extends DnlError {
26
+ constructor(message, issues) {
27
+ super(message, ExitCodes.validationError);
28
+ this.issues = issues;
29
+ }
30
+ }
31
+ export class ExportError extends DnlError {
32
+ constructor(message) {
33
+ super(message, ExitCodes.exportError);
5
34
  }
6
35
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@romaintaillandier1978/dotenv-never-lies",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Typed, validated, and explicit environment variables — powered by Zod.",
5
5
  "license": "MIT",
6
6
  "author": "Romain TAILLANDIER",
@@ -9,6 +9,14 @@
9
9
  "type": "git",
10
10
  "url": "https://github.com/romaintaillandier1978/dotenv-never-lies"
11
11
  },
12
+ "scripts": {
13
+ "build": "tsc",
14
+ "pack": "rm -rf dist && yarn build && npm pack --pack-destination ./dist",
15
+ "pack:check": "npm pack --dry-run",
16
+ "release:patch": "npm version patch",
17
+ "release:minor": "npm version minor",
18
+ "release:major": "npm version major"
19
+ },
12
20
  "keywords": [
13
21
  "env",
14
22
  "environment",
@@ -42,14 +50,6 @@
42
50
  "bin": {
43
51
  "dnl": "./dist/cli/index.js"
44
52
  },
45
- "scripts": {
46
- "build": "tsc",
47
- "prepublishOnly": "npm test && npm run build",
48
- "test": "yarn build && node dist/DnlTest.js",
49
- "dev": "tsx src/cli/index.ts",
50
- "devold": "yarn build && node dist/cli/index.js",
51
- "gen": "rm -rf dist; rm dotenv-never-lies-v*.tgz; yarn build && yarn pack"
52
- },
53
53
  "peerDependencies": {
54
54
  "zod": ">=4.2.1"
55
55
  },