@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/README.md +328 -69
- package/dist/cli/commands/assert.d.ts +4 -2
- package/dist/cli/commands/assert.d.ts.map +1 -1
- package/dist/cli/commands/assert.js +7 -9
- package/dist/cli/commands/explain.d.ts +6 -1
- package/dist/cli/commands/explain.d.ts.map +1 -1
- package/dist/cli/commands/explain.js +9 -16
- package/dist/cli/commands/export.d.ts +34 -0
- package/dist/cli/commands/export.d.ts.map +1 -0
- package/dist/cli/commands/export.js +263 -0
- package/dist/cli/commands/generate.d.ts +7 -2
- package/dist/cli/commands/generate.d.ts.map +1 -1
- package/dist/cli/commands/generate.js +9 -7
- package/dist/cli/commands/reverseEnv.d.ts +8 -2
- package/dist/cli/commands/reverseEnv.d.ts.map +1 -1
- package/dist/cli/commands/reverseEnv.js +14 -7
- package/dist/cli/index.js +265 -78
- package/dist/cli/utils/exitCodes.d.ts +8 -0
- package/dist/cli/utils/exitCodes.d.ts.map +1 -0
- package/dist/cli/utils/exitCodes.js +8 -0
- package/dist/cli/utils/load-schema.d.ts.map +1 -1
- package/dist/cli/utils/load-schema.js +19 -12
- package/dist/cli/utils/resolve-schema.d.ts.map +1 -1
- package/dist/cli/utils/resolve-schema.js +7 -3
- package/dist/cli/utils/toFile.d.ts +2 -0
- package/dist/cli/utils/toFile.d.ts.map +1 -0
- package/dist/cli/utils/toFile.js +8 -0
- package/dist/core.js +2 -2
- package/dist/errors.d.ts +29 -2
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +33 -4
- package/dist/romaintaillandier1978-dotenv-never-lies-0.3.0.tgz +0 -0
- package/package.json +9 -9
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
|
-
|
|
10
|
-
.
|
|
11
|
-
|
|
12
|
-
|
|
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
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
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
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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(
|
|
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
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
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(
|
|
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
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
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
|
-
|
|
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
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
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
|
-
|
|
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 @@
|
|
|
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;
|
|
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
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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":"
|
|
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
|
-
|
|
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
|
|
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 @@
|
|
|
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 {
|
|
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
|
|
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
|
|
2
|
-
|
|
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
|
package/dist/errors.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,
|
|
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
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
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
|
}
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@romaintaillandier1978/dotenv-never-lies",
|
|
3
|
-
"version": "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
|
},
|