@romaintaillandier1978/dotenv-never-lies 0.4.0 → 1.1.1
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 +257 -239
- package/dist/cli/commands/export.d.ts +4 -3
- package/dist/cli/commands/export.d.ts.map +1 -1
- package/dist/cli/commands/export.js +105 -100
- package/dist/cli/commands/generate.d.ts +4 -1
- package/dist/cli/commands/generate.d.ts.map +1 -1
- package/dist/cli/commands/reverseEnv.d.ts.map +1 -1
- package/dist/cli/commands/reverseEnv.js +8 -2
- package/dist/cli/index.js +146 -109
- package/dist/cli/utils/infer-schema.d.ts.map +1 -1
- package/dist/cli/utils/infer-schema.js +4 -3
- package/dist/cli/utils/load-schema.d.ts.map +1 -1
- package/dist/cli/utils/load-schema.js +5 -4
- package/dist/cli/utils/printer.d.ts.map +1 -1
- package/dist/cli/utils/printer.js +5 -4
- package/dist/core.d.ts +33 -33
- package/dist/core.js +8 -8
- package/package.json +7 -6
package/dist/cli/index.js
CHANGED
|
@@ -11,57 +11,57 @@ import { createRequire } from "node:module";
|
|
|
11
11
|
const require = createRequire(import.meta.url);
|
|
12
12
|
const packageJson = require("../../package.json");
|
|
13
13
|
const exitCodeHelp = {
|
|
14
|
-
[ExitCodes.success]: "
|
|
15
|
-
[ExitCodes.usageError]: "
|
|
16
|
-
[ExitCodes.schemaNotFound]: "
|
|
17
|
-
[ExitCodes.validationError]: "Validation
|
|
18
|
-
[ExitCodes.exportError]: "
|
|
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
19
|
};
|
|
20
20
|
// #region Program
|
|
21
21
|
program
|
|
22
22
|
.name("dnl")
|
|
23
23
|
//.version("0.3.0")
|
|
24
24
|
.version(packageJson.version)
|
|
25
|
-
//
|
|
25
|
+
// allows passing positional arguments, before/after options
|
|
26
26
|
.enablePositionalOptions()
|
|
27
27
|
.exitOverride()
|
|
28
|
-
.addHelpText("before", `
|
|
29
|
-
CLI
|
|
30
|
-
|
|
28
|
+
.addHelpText("before", `Summary:
|
|
29
|
+
CLI for dotenv-never-lies.
|
|
30
|
+
Validates typed environment variables from a TypeScript/Zod schema.
|
|
31
31
|
`)
|
|
32
|
-
.option("--schema <file>", "
|
|
33
|
-
.addHelpText("after", `\nExit codes
|
|
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
34
|
.map(([key, value]) => ` - ${key}: ${value}`)
|
|
35
35
|
.join("\n")}
|
|
36
36
|
`)
|
|
37
|
-
.addHelpText("after", `\
|
|
38
|
-
|
|
39
|
-
1.
|
|
40
|
-
2.
|
|
41
|
-
3.
|
|
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
42
|
- env.dnl.ts
|
|
43
43
|
- env.dnl.js
|
|
44
44
|
- dnl.config.ts
|
|
45
45
|
- dnl.config.js
|
|
46
|
-
|
|
46
|
+
If no schema is found, the command fails.
|
|
47
47
|
`)
|
|
48
|
-
.addHelpText("after", `\
|
|
48
|
+
.addHelpText("after", `\nExamples:
|
|
49
49
|
|
|
50
|
-
#
|
|
50
|
+
# Check the environment at runtime and exit the process if the schema is not satisfied
|
|
51
51
|
dnl assert
|
|
52
52
|
dnl assert --schema my-dnl.ts
|
|
53
53
|
|
|
54
|
-
#
|
|
54
|
+
# Generate a documented .env file from the schema
|
|
55
55
|
dnl generate
|
|
56
56
|
dnl generate --schema my-dnl.ts --out .env
|
|
57
57
|
|
|
58
|
-
#
|
|
58
|
+
# Create an env.dnl.ts schema from an existing .env
|
|
59
59
|
dnl reverse-env --source .env
|
|
60
60
|
|
|
61
|
-
#
|
|
61
|
+
# Display known variables and their description
|
|
62
62
|
dnl explain
|
|
63
63
|
|
|
64
|
-
#
|
|
64
|
+
# Export variables in docker-args format
|
|
65
65
|
dnl export docker-args --source .env
|
|
66
66
|
|
|
67
67
|
`);
|
|
@@ -69,54 +69,55 @@ program
|
|
|
69
69
|
// #region assert
|
|
70
70
|
program
|
|
71
71
|
.command("assert")
|
|
72
|
-
.description("
|
|
73
|
-
.option("-s, --source <source>", "
|
|
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)")
|
|
74
74
|
.action(assertCommand)
|
|
75
|
-
.addHelpText("after", `\
|
|
75
|
+
.addHelpText("after", `\nExamples:
|
|
76
76
|
|
|
77
|
-
#
|
|
78
|
-
#
|
|
77
|
+
# Validate environment variables from process.env
|
|
78
|
+
# Recommended in CI to prevent starting with an invalid configuration
|
|
79
79
|
dnl assert
|
|
80
80
|
dnl assert --schema my-dnl.ts
|
|
81
81
|
|
|
82
|
-
#
|
|
83
|
-
#
|
|
82
|
+
# Validate environment variables from a .env file
|
|
83
|
+
# Recommended locally (schema preparation, onboarding)
|
|
84
84
|
dnl assert --source .env
|
|
85
85
|
dnl assert --schema my-dnl.ts --source .env
|
|
86
86
|
|
|
87
|
-
#
|
|
87
|
+
# validate environment variables from the file provided by the CI
|
|
88
88
|
dnl assert --source $ENV_FILE
|
|
89
89
|
dnl assert --schema my-dnl.ts --source $ENV_FILE
|
|
90
90
|
`);
|
|
91
91
|
// #endregion assert
|
|
92
92
|
// #region export
|
|
93
93
|
const exportHelp = {
|
|
94
|
-
"docker-args": "Arguments `--env KEY=VALUE`
|
|
95
|
-
"docker-env": "
|
|
96
|
-
"github-env": "
|
|
97
|
-
"github-secret": "Secrets
|
|
98
|
-
"gitlab-env": "
|
|
99
|
-
"k8s-configmap": "ConfigMap
|
|
100
|
-
"k8s-secret": "Secret
|
|
101
|
-
env: "
|
|
102
|
-
json: "
|
|
103
|
-
ts: "
|
|
104
|
-
js: "
|
|
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
105
|
};
|
|
106
106
|
program
|
|
107
107
|
.command("export")
|
|
108
|
-
.description("
|
|
109
|
-
.argument("<format>", "
|
|
110
|
-
.option("-s, --source <source>", "
|
|
111
|
-
.option("--hide-secret", '
|
|
112
|
-
.option("--exclude-secret", "
|
|
113
|
-
.option("--include-comments", "
|
|
114
|
-
.option("-
|
|
115
|
-
.option("-
|
|
116
|
-
.option("
|
|
117
|
-
.option("--
|
|
118
|
-
.
|
|
119
|
-
|
|
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 });
|
|
120
121
|
if (out) {
|
|
121
122
|
await toFile(content, out, opts.force ?? false);
|
|
122
123
|
}
|
|
@@ -127,29 +128,64 @@ program
|
|
|
127
128
|
console.error(`${warning}`);
|
|
128
129
|
}
|
|
129
130
|
})
|
|
130
|
-
.addHelpText("after", `\
|
|
131
|
+
.addHelpText("after", `\nExport formats:\n${Object.entries(exportHelp)
|
|
131
132
|
.map(([key, value]) => ` - ${key}: ${value}`)
|
|
132
133
|
.join("\n")}
|
|
133
134
|
`)
|
|
134
|
-
.addHelpText("after", `\
|
|
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).
|
|
138
|
+
|
|
139
|
+
Example:
|
|
140
|
+
|
|
141
|
+
.env file:
|
|
142
|
+
NODE_CORS_ORIGIN=https://a.site.com;https://b.site.com;https://c.site.com
|
|
143
|
+
|
|
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:
|
|
135
171
|
|
|
136
|
-
# ---
|
|
172
|
+
# --- Simple cases ----------------------------------------------------
|
|
137
173
|
|
|
138
|
-
#
|
|
174
|
+
# Export environment variables as JSON from a .env file
|
|
139
175
|
dnl export json --source .env
|
|
140
176
|
|
|
141
|
-
#
|
|
177
|
+
# Clean a .env file (remove comments and extraneous lines)
|
|
142
178
|
dnl export env --source .env --out .env.clean
|
|
143
179
|
dnl export env --source .env -fo .env
|
|
144
180
|
|
|
145
181
|
|
|
146
182
|
# --- Docker / CI ----------------------------------------------------
|
|
147
183
|
|
|
148
|
-
#
|
|
184
|
+
# Export variables as docker-args
|
|
149
185
|
dnl export docker-args --source .env
|
|
150
186
|
|
|
151
|
-
#
|
|
152
|
-
# (
|
|
187
|
+
# Concrete CI example to run a Docker container
|
|
188
|
+
# (variables are injected dynamically)
|
|
153
189
|
docker run \\
|
|
154
190
|
$(dnl export docker-args --source $DOTENV_FILE) \\
|
|
155
191
|
--restart always \\
|
|
@@ -158,76 +194,77 @@ program
|
|
|
158
194
|
|
|
159
195
|
# --- GitHub Actions -------------------------------------------------
|
|
160
196
|
|
|
161
|
-
#
|
|
162
|
-
#
|
|
197
|
+
# Export variables as GitHub secrets (current repo)
|
|
198
|
+
# Requires gh CLI configured (gh auth login)
|
|
163
199
|
dnl export github-secret
|
|
164
200
|
|
|
165
|
-
#
|
|
201
|
+
# Export variables as GitHub organization secrets
|
|
166
202
|
dnl export github-secret --github-org my-org
|
|
167
203
|
|
|
168
|
-
#
|
|
169
|
-
# (
|
|
204
|
+
# Example usage in a GitHub Actions job:
|
|
205
|
+
# (variables are injected into the job environment)
|
|
170
206
|
dnl export github-env >> $GITHUB_ENV
|
|
171
207
|
|
|
172
208
|
|
|
173
209
|
# --- Kubernetes -----------------------------------------------------
|
|
174
210
|
|
|
175
|
-
#
|
|
211
|
+
# Generate a Kubernetes ConfigMap (NON-sensitive variables), from process.env
|
|
176
212
|
dnl export k8s-configmap --out k8s-configmap.yaml
|
|
177
213
|
|
|
178
|
-
#
|
|
214
|
+
# Generate a Kubernetes Secret from a .env file
|
|
179
215
|
dnl export k8s-secret --source .env --k8s-name my-secret --out k8s-secret.yaml
|
|
180
216
|
|
|
181
|
-
#
|
|
217
|
+
# Apply the generated files
|
|
182
218
|
kubectl apply -f k8s-configmap.yaml
|
|
183
219
|
kubectl apply -f k8s-secret.yaml
|
|
184
220
|
|
|
185
|
-
#
|
|
221
|
+
# note: if no secret is present in the dnl config, for k8s-secret the output will be empty
|
|
186
222
|
|
|
187
223
|
# --- TypeScript / JavaScript ---------------------------------------
|
|
188
224
|
|
|
189
|
-
#
|
|
190
|
-
dnl export ts --out env.generated.ts
|
|
191
|
-
dnl export js --out env.generated.js
|
|
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
|
|
192
228
|
`);
|
|
193
229
|
// #endregion export
|
|
194
230
|
// #region generate
|
|
195
231
|
program
|
|
196
232
|
.command("generate")
|
|
197
|
-
.description("
|
|
198
|
-
"
|
|
199
|
-
"
|
|
200
|
-
.option("-o, --out <file>", "
|
|
201
|
-
.option("-f, --force", "
|
|
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")
|
|
202
238
|
.action(async (opts) => {
|
|
203
239
|
const { content, out } = await generateCommand(opts);
|
|
204
240
|
await toFile(content, out, opts.force ?? false);
|
|
205
241
|
})
|
|
206
|
-
.addHelpText("after", `\
|
|
242
|
+
.addHelpText("after", `\nExamples:
|
|
207
243
|
|
|
208
|
-
#
|
|
244
|
+
# Generate a .env file from the default schema (env.dnl.ts)
|
|
209
245
|
dnl generate
|
|
210
246
|
|
|
211
|
-
#
|
|
247
|
+
# Generate a .env file from a specified schema
|
|
212
248
|
dnl generate --schema my-dnl.ts
|
|
213
249
|
|
|
214
|
-
#
|
|
250
|
+
# Generate a .env.local file from the schema
|
|
215
251
|
dnl generate --out .env.local
|
|
216
252
|
|
|
217
|
-
#
|
|
253
|
+
# Generate a .env file from a schema and overwrite the existing file
|
|
218
254
|
dnl generate --out .env --force
|
|
219
255
|
`);
|
|
220
256
|
// #endregion generate
|
|
221
257
|
// #region reverse-env
|
|
222
258
|
program
|
|
223
259
|
.command("reverse-env")
|
|
224
|
-
.description("
|
|
225
|
-
"
|
|
226
|
-
"
|
|
227
|
-
|
|
228
|
-
.option("-
|
|
229
|
-
.option("-
|
|
230
|
-
.option("--
|
|
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)")
|
|
231
268
|
.action(async (opts) => {
|
|
232
269
|
const { content, out, warnings } = await reverseEnvCommand(opts);
|
|
233
270
|
await toFile(content, out, opts.force ?? false);
|
|
@@ -235,27 +272,27 @@ program
|
|
|
235
272
|
console.error(`${warning}`);
|
|
236
273
|
}
|
|
237
274
|
})
|
|
238
|
-
.addHelpText("after", `\
|
|
275
|
+
.addHelpText("after", `\nExamples:
|
|
239
276
|
|
|
240
|
-
#
|
|
241
|
-
dnl reverse-env
|
|
277
|
+
# Generate an env.dnl.ts schema from a .env file, try to guess sensitive variables
|
|
278
|
+
dnl reverse-env --guess-secret
|
|
242
279
|
|
|
243
|
-
#
|
|
280
|
+
# Generate an env.dnl.ts schema from a .env.local file
|
|
244
281
|
dnl reverse-env --source .env.local
|
|
245
282
|
|
|
246
|
-
#
|
|
283
|
+
# Generate a my-dnl.ts schema from a .env file
|
|
247
284
|
dnl reverse-env --out my-dnl.ts
|
|
248
285
|
|
|
249
|
-
#
|
|
250
|
-
dnl reverse-env --force
|
|
286
|
+
# Generate an env.dnl.ts schema from a .env file and overwrite the existing file
|
|
287
|
+
dnl reverse-env --force
|
|
251
288
|
`);
|
|
252
289
|
// #endregion reverse-env
|
|
253
290
|
// #region explain
|
|
254
291
|
program
|
|
255
292
|
.command("explain")
|
|
256
|
-
.description("
|
|
257
|
-
.argument("[keys...]", "
|
|
258
|
-
.option("-f, --format <format>", '
|
|
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")
|
|
259
296
|
.action(async (keys, opts) => {
|
|
260
297
|
const { format, result } = await explainCommand({ keys: keys ?? [], schema: opts.schema, format: opts.format });
|
|
261
298
|
if (format === "human") {
|
|
@@ -265,21 +302,21 @@ program
|
|
|
265
302
|
console.log(JSON.stringify(result, null, 2));
|
|
266
303
|
}
|
|
267
304
|
})
|
|
268
|
-
.addHelpText("after", `\
|
|
305
|
+
.addHelpText("after", `\nExamples:
|
|
269
306
|
|
|
270
|
-
#
|
|
307
|
+
# explain all known variables and their description
|
|
271
308
|
dnl explain
|
|
272
309
|
|
|
273
|
-
#
|
|
310
|
+
# explain a variable in detail
|
|
274
311
|
dnl explain NODE_ENV
|
|
275
312
|
|
|
276
|
-
#
|
|
313
|
+
# machine-readable output
|
|
277
314
|
dnl explain --format json
|
|
278
315
|
|
|
279
|
-
#
|
|
316
|
+
# explain all known variables and their description from a schema
|
|
280
317
|
dnl explain --schema my-dnl.ts
|
|
281
318
|
|
|
282
|
-
#
|
|
319
|
+
# explain a subset of known variables and their description
|
|
283
320
|
dnl explain NODE_ENV NODE_PORT
|
|
284
321
|
|
|
285
322
|
`);
|
|
@@ -289,7 +326,7 @@ try {
|
|
|
289
326
|
process.exit(ExitCodes.success);
|
|
290
327
|
}
|
|
291
328
|
catch (err) {
|
|
292
|
-
// Commander
|
|
329
|
+
// Commander throws a controlled error when help or version is displayed
|
|
293
330
|
if (err instanceof CommanderError) {
|
|
294
331
|
if (err.code === "commander.helpDisplayed" || err.code === "commander.version") {
|
|
295
332
|
process.exit(ExitCodes.success);
|
|
@@ -308,7 +345,7 @@ catch (err) {
|
|
|
308
345
|
console.error(err.message);
|
|
309
346
|
process.exit(err.exitCode);
|
|
310
347
|
}
|
|
311
|
-
console.error("
|
|
348
|
+
console.error("Unexpected error");
|
|
312
349
|
console.error(err);
|
|
313
350
|
process.exit(ExitCodes.usageError);
|
|
314
351
|
}
|
|
@@ -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,
|
|
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 (
|
|
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
|
|
21
|
+
const secretMarkers = ["SECRET", "KEY", "TOKEN", "PASSWORD", "PASS", "AUTH"];
|
|
22
22
|
export const guessSecret = (value) => {
|
|
23
|
-
|
|
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;AAGpD,eAAO,MAAM,OAAO,GAAU,YAAY,MAAM,KAAG,OAAO,CAAC,mBAAmB,CAAC,GAAG,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"}
|
|
@@ -6,7 +6,7 @@ import { SchemaNotFoundError } from "../../errors.js";
|
|
|
6
6
|
export const loadDef = async (schemaPath) => {
|
|
7
7
|
const outDir = path.join(process.cwd(), ".dnl");
|
|
8
8
|
await fs.mkdir(outDir, { recursive: true });
|
|
9
|
-
//
|
|
9
|
+
// We always overwrite the file here; this could be an issue.
|
|
10
10
|
const outFile = path.join(outDir, "env.dnl.mjs");
|
|
11
11
|
try {
|
|
12
12
|
await build({
|
|
@@ -15,15 +15,16 @@ export const loadDef = async (schemaPath) => {
|
|
|
15
15
|
format: "esm",
|
|
16
16
|
platform: "node",
|
|
17
17
|
target: "node18",
|
|
18
|
-
bundle:
|
|
18
|
+
bundle: true,
|
|
19
|
+
packages: "external",
|
|
19
20
|
});
|
|
20
21
|
const mod = await import(pathToFileURL(outFile).href);
|
|
21
22
|
if (!mod.default) {
|
|
22
|
-
throw new SchemaNotFoundError(`
|
|
23
|
+
throw new SchemaNotFoundError(`The file ${schemaPath} must export a default schema (export default).`);
|
|
23
24
|
}
|
|
24
25
|
return mod.default;
|
|
25
26
|
}
|
|
26
27
|
catch (error) {
|
|
27
|
-
throw new SchemaNotFoundError(`
|
|
28
|
+
throw new SchemaNotFoundError(`Unable to load DNL schema (${schemaPath}): ${error}`);
|
|
28
29
|
}
|
|
29
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,
|
|
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
|
|
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
|
|
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
|
|
129
|
+
// pipe / transform → transparent regarding required
|
|
129
130
|
case "pipe":
|
|
130
131
|
if ("in" in def) {
|
|
131
132
|
return isRequired(def.in);
|