@rse/nunjucks-cli 2.0.1 → 2.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.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,13 @@
2
2
  ChangeLog
3
3
  =========
4
4
 
5
+ 2.1.0 (2025-12-26)
6
+ ------------------
7
+
8
+ - REFACTOR: change option -e/--extension to option -p/--plugin
9
+ - IMPROVEMENT: add new option -e for loading custom .env files
10
+ - IMPROVEMENT: add new option -E for loading standard .env files
11
+
5
12
  2.0.0 (2025-12-21)
6
13
  ------------------
7
14
 
package/Dockerfile CHANGED
@@ -5,8 +5,8 @@
5
5
  # build arguments (early)
6
6
  ARG IMAGE_PREFIX=docker.io/engelschall/
7
7
  ARG IMAGE_NAME=nunjucks-cli
8
- ARG IMAGE_VERSION=2.0.0
9
- ARG IMAGE_RELEASE=20251221
8
+ ARG IMAGE_VERSION=2.1.0
9
+ ARG IMAGE_RELEASE=20251226
10
10
  ARG IMAGE_ALIAS=latest
11
11
 
12
12
  # derive image from a certain base image
package/README.md CHANGED
@@ -61,7 +61,7 @@ $ nunjucks
61
61
  [-C|--option <key>=<value>]
62
62
  [-d|--defines <context-file>]
63
63
  [-D|--define <key>=<value>]
64
- [-e|--extension <module-name>]
64
+ [-p|--plugin <module-name>]
65
65
  [-o|--output <output-file>|-]
66
66
  <input-file>|-
67
67
  ```
@@ -80,8 +80,8 @@ $ nunjucks
80
80
  - `-D`|`--define` `<key>=<value>`:<br/>
81
81
  Set context definition key/value.
82
82
  Can occur multiple times.
83
- - `-e`|`--extension` `<module-name>`:<br/>
84
- Load Nunjucks JavaScript extension module (installed via NPM).
83
+ - `-p`|`--plugin` `<module-name>`:<br/>
84
+ Load Nunjucks JavaScript plugin module (installed via NPM).
85
85
  - `-o`|`--output` `<output-file>`|`-`:<br/>
86
86
  Save output file (or stdout).
87
87
  - `<input-file>`|`-`:<br/>
package/nunjucks.1 CHANGED
@@ -1,9 +1,9 @@
1
- .TH "NUNJUCKS" "1" "June 2025" "" ""
1
+ .TH "NUNJUCKS" "1" "December 2025" "" ""
2
2
  .SH "NAME"
3
3
  \fBnunjucks\fR - Template Rendering Engine
4
4
  .SH "SYNOPSIS"
5
5
  .P
6
- \fBnunjucks\fR \[lB]\fB-h\fR|\fB--help\fR\[rB] \[lB]\fB-V\fR|\fB--version\fR\[rB] \[lB]\fB-c\fR|\fB--config\fR \fIconfig-file\fR\[rB] \[lB]\fB-C\fR|\fB--option\fR \fIkey\fR=\fIvalue\fR\[rB] \[lB]\fB-d\fR|\fB--defines\fR \fIcontext-file\fR\[rB] \[lB]\fB-D\fR|\fB--define\fR \fIkey\fR=\fIvalue\fR\[rB] \[lB]\fB-e\fR|\fB--extension\fR \fImodule-name\fR\[rB] \[lB]\fB-o\fR|\fB--output\fR \fIoutput-file\fR|\fB-\fR\[rB] \[lB]\fIinput-file\fR|\fB-\fR\[rB]
6
+ \fBnunjucks\fR \[lB]\fB-h\fR|\fB--help\fR\[rB] \[lB]\fB-V\fR|\fB--version\fR\[rB] \[lB]\fB-e\fR|\fB--env\fR \fIenv-file\fR\[rB] \[lB]\fB-E\fR|\fB--envs\fR\[rB] \[lB]\fB-c\fR|\fB--config\fR \fIconfig-file\fR\[rB] \[lB]\fB-C\fR|\fB--option\fR \fIkey\fR=\fIvalue\fR\[rB] \[lB]\fB-d\fR|\fB--defines\fR \fIcontext-file\fR\[rB] \[lB]\fB-D\fR|\fB--define\fR \fIkey\fR=\fIvalue\fR\[rB] \[lB]\fB-p\fR|\fB--plugin\fR \fImodule-name\fR\[rB] \[lB]\fB-o\fR|\fB--output\fR \fIoutput-file\fR|\fB-\fR\[rB] \[lB]\fIinput-file\fR|\fB-\fR\[rB]
7
7
  .SH "DESCRIPTION"
8
8
  .P
9
9
  \fBnunjucks\fR(1) is a small command-line utility to render templates with the rich and powerful templating language \fBMozilla Nunjucks\fR \fI\(lahttps://mozilla.github.io/nunjucks/\(ra\fR. This allows you to define your configuration in a YAML file and then render an output file based on a template input file where your configuration can be expanded. It optionally can load Nunjucks addons like the ones from the companion \fBNunjucks Addons\fR \fI\(lahttps://github.com/rse/nunjucks-addons\(ra\fR package.
@@ -12,23 +12,27 @@
12
12
  The following top-level options and arguments exist:
13
13
  .RS 0
14
14
  .IP \(bu 4
15
- \[lB]\fB-h\fR|\fB--help\fR\[rB] Show usage help.
15
+ \[lB]\fB-h\fR|\fB--help\fR\[rB]: Show usage help.
16
16
  .IP \(bu 4
17
- \[lB]\fB-V\fR|\fB--version\fR\[rB] Show program version information.
17
+ \[lB]\fB-V\fR|\fB--version\fR\[rB]: Show program version information.
18
18
  .IP \(bu 4
19
- \[lB]\fB-c\fR|\fB--config\fR \fIconfig-file\fR\[rB] Load Nunjucks configuration YAML file.
19
+ \[lB]\fB-e\fR|\fB--env\fR \fIenv-file\fR\[rB]: Load environment file with key/value definitions. These can later be accessed with the global \fBenv\fR variable.
20
20
  .IP \(bu 4
21
- \[lB]\fB-C\fR|\fB--option\fR \fIkey\fR=\fIvalue\fR\[rB] Set Nunjucks configuration option.
21
+ \[lB]\fB-E\fR|\fB--envs\fR\[rB]: Automatically load environment files with key/value definitions from all \fB.env\fR files in current and all parent directories.
22
22
  .IP \(bu 4
23
- \[lB]\fB-d\fR|\fB--defines\fR \fIcontext-file\fR\[rB] Load context definition YAML file. Can occur multiple times.
23
+ \[lB]\fB-c\fR|\fB--config\fR \fIconfig-file\fR\[rB]: Load Nunjucks configuration YAML file.
24
24
  .IP \(bu 4
25
- \[lB]\fB-D\fR|\fB--define\fR \fIkey\fR=\fIvalue\fR\[rB] Set context definition key/value. Can occur multiple times.
25
+ \[lB]\fB-C\fR|\fB--option\fR \fIkey\fR=\fIvalue\fR\[rB]: Set Nunjucks configuration option.
26
26
  .IP \(bu 4
27
- \[lB]\fB-e\fR|\fB--extension\fR \fImodule-name\fR\[rB] Load Nunjucks JavaScript extension module (installed via NPM).
27
+ \[lB]\fB-d\fR|\fB--defines\fR \fIcontext-file\fR\[rB]: Load context definition YAML file. Can occur multiple times.
28
28
  .IP \(bu 4
29
- \[lB]\fB-o\fR|\fB--output\fR \fIoutput-file\fR|\fB-\fR\[rB] Save output file (or stdout).
29
+ \[lB]\fB-D\fR|\fB--define\fR \fIkey\fR=\fIvalue\fR\[rB]: Set context definition key/value. Can occur multiple times.
30
30
  .IP \(bu 4
31
- \[lB]\fB<input-file>\fR|\fB-\fR\[rB] Load input file (or stdin).
31
+ \[lB]\fB-p\fR|\fB--plugin\fR \fImodule-name\fR\[rB]: Load Nunjucks JavaScript plugin module (installed via NPM).
32
+ .IP \(bu 4
33
+ \[lB]\fB-o\fR|\fB--output\fR \fIoutput-file\fR|\fB-\fR\[rB]: Save output file (or stdout).
34
+ .IP \(bu 4
35
+ \[lB]\fB<input-file>\fR|\fB-\fR\[rB]: Load input file (or stdin).
32
36
  .RE 0
33
37
 
34
38
  .SH "EXAMPLE"
package/nunjucks.js CHANGED
@@ -14,6 +14,8 @@ import chalk from "chalk";
14
14
  import jsYAML from "js-yaml";
15
15
  import nunjucks from "nunjucks";
16
16
  import deepmerge from "deepmerge";
17
+ import dotenvx from "@dotenvx/dotenvx";
18
+ import * as findup from "find-up";
17
19
  /* load my own information */
18
20
  const my = JSON.parse(await fs.promises.readFile(new URL("./package.json", import.meta.url), "utf-8"));
19
21
  /* parse command-line arguments */
@@ -24,11 +26,13 @@ program.name("nunjucks")
24
26
  .showHelpAfterError("hint: use option --help for usage information")
25
27
  .option("-h, --help", "show usage help", false)
26
28
  .option("-V, --version", "show program version information", false)
29
+ .option("-e, --env <env-file>", "load environment key/value file", reduceArray, [])
30
+ .option("-E, --envs", "load all environment key/value files", false)
27
31
  .option("-c, --config <config-file>", "load Nunjucks configuration YAML file", "")
28
32
  .option("-C, --option <key>=<value>", "set Nunjucks configuration option", reduceArray, [])
29
33
  .option("-d, --defines <context-file>", "load context definition YAML file", reduceArray, [])
30
34
  .option("-D, --define <key>=<value>", "set context definition key/value", reduceArray, [])
31
- .option("-e, --extension <module-name>", "load Nunjucks JavaScript extension module", reduceArray, [])
35
+ .option("-p, --plugin <module-name>", "load Nunjucks JavaScript plugin module", reduceArray, [])
32
36
  .option("-o, --output <output-file>", "save output file", "-")
33
37
  .argument("[<input-file>]", "input file");
34
38
  program.parse(process.argv);
@@ -82,7 +86,7 @@ if (inputFile === "-") {
82
86
  }
83
87
  else {
84
88
  if (!fs.existsSync(inputFile)) {
85
- console.error(chalk.red(`nunjucks: ERROR: failed to find input file: ${inputFile}`));
89
+ console.error(chalk.red(`nunjucks: ERROR: failed to find input file: "${inputFile}"`));
86
90
  process.exit(1);
87
91
  }
88
92
  input = fs.readFileSync(inputFile, { encoding: "utf8" });
@@ -98,6 +102,22 @@ for (const define of argv.defines) {
98
102
  process.exit(1);
99
103
  }
100
104
  }
105
+ /* load environment variables from all default files */
106
+ if (argv.envs) {
107
+ const files = findup.findUpMultipleSync(".env");
108
+ if (files.length > 0)
109
+ dotenvx.config({ path: files, quiet: true });
110
+ }
111
+ /* load environment variables from environment files */
112
+ if (argv.env.length > 0) {
113
+ for (const env of argv.env) {
114
+ if (!fs.existsSync(env)) {
115
+ console.error(chalk.red(`nunjucks: ERROR: environment file not found: "${env}"`));
116
+ process.exit(1);
117
+ }
118
+ }
119
+ dotenvx.config({ path: argv.env, quiet: true });
120
+ }
101
121
  /* expose environment variables to template */
102
122
  context.env = process.env;
103
123
  /* add context defines */
@@ -136,20 +156,20 @@ options = {
136
156
  };
137
157
  /* configure environment */
138
158
  const env = nunjucks.configure(inputFile, options);
139
- /* load external extension files */
140
- for (const extension of argv.extension) {
141
- let modpath = path.resolve(extension);
159
+ /* load external plugin modules */
160
+ for (const plugin of argv.plugin) {
161
+ let modpath = path.resolve(plugin);
142
162
  if (!fs.existsSync(modpath)) {
143
163
  try {
144
164
  const require = createRequire(import.meta.url);
145
- modpath = require.resolve(extension);
165
+ modpath = require.resolve(plugin);
146
166
  }
147
167
  catch (_ex) {
148
168
  modpath = null;
149
169
  }
150
170
  }
151
171
  if (modpath === null) {
152
- console.error(chalk.red(`nunjucks: ERROR: failed to find extension module: ${extension}`));
172
+ console.error(chalk.red(`nunjucks: ERROR: failed to find plugin module: ${plugin}`));
153
173
  process.exit(1);
154
174
  }
155
175
  /* dynamically import the module */
@@ -160,11 +180,11 @@ for (const extension of argv.extension) {
160
180
  mod = mod.default ?? mod;
161
181
  }
162
182
  catch (ex) {
163
- console.error(chalk.red(`nunjucks: ERROR: failed to load extension module: ${ex.toString()}`));
183
+ console.error(chalk.red(`nunjucks: ERROR: failed to load plugin module: ${ex.toString()}`));
164
184
  process.exit(1);
165
185
  }
166
186
  if (!(mod !== null && typeof mod === "function")) {
167
- console.error(chalk.red(`nunjucks: ERROR: failed to call extension file: ${modpath}`));
187
+ console.error(chalk.red(`nunjucks: ERROR: failed to call plugin file: "${modpath}"`));
168
188
  process.exit(1);
169
189
  }
170
190
  mod(env);
package/nunjucks.md CHANGED
@@ -6,11 +6,13 @@
6
6
  `nunjucks`
7
7
  \[`-h`|`--help`\]
8
8
  \[`-V`|`--version`\]
9
+ \[`-e`|`--env` *env-file*\]
10
+ \[`-E`|`--envs`\]
9
11
  \[`-c`|`--config` *config-file*\]
10
12
  \[`-C`|`--option` *key*=*value*\]
11
13
  \[`-d`|`--defines` *context-file*\]
12
14
  \[`-D`|`--define` *key*=*value*\]
13
- \[`-e`|`--extension` *module-name*\]
15
+ \[`-p`|`--plugin` *module-name*\]
14
16
  \[`-o`|`--output` *output-file*|`-`\]
15
17
  \[*input-file*|`-`\]
16
18
 
@@ -27,33 +29,41 @@ It optionally can load Nunjucks addons like the ones from the companion
27
29
 
28
30
  The following top-level options and arguments exist:
29
31
 
30
- - \[`-h`|`--help`\]
32
+ - \[`-h`|`--help`\]:
31
33
  Show usage help.
32
34
 
33
- - \[`-V`|`--version`\]
35
+ - \[`-V`|`--version`\]:
34
36
  Show program version information.
35
37
 
36
- - \[`-c`|`--config` *config-file*\]
38
+ - \[`-e`|`--env` *env-file*\]:
39
+ Load environment file with key/value definitions.
40
+ These can later be accessed with the global `env` variable.
41
+
42
+ - \[`-E`|`--envs`\]:
43
+ Automatically load environment files with key/value definitions
44
+ from all `.env` files in current and all parent directories.
45
+
46
+ - \[`-c`|`--config` *config-file*\]:
37
47
  Load Nunjucks configuration YAML file.
38
48
 
39
- - \[`-C`|`--option` *key*=*value*\]
49
+ - \[`-C`|`--option` *key*=*value*\]:
40
50
  Set Nunjucks configuration option.
41
51
 
42
- - \[`-d`|`--defines` *context-file*\]
52
+ - \[`-d`|`--defines` *context-file*\]:
43
53
  Load context definition YAML file.
44
54
  Can occur multiple times.
45
55
 
46
- - \[`-D`|`--define` *key*=*value*\]
56
+ - \[`-D`|`--define` *key*=*value*\]:
47
57
  Set context definition key/value.
48
58
  Can occur multiple times.
49
59
 
50
- - \[`-e`|`--extension` *module-name*\]
51
- Load Nunjucks JavaScript extension module (installed via NPM).
60
+ - \[`-p`|`--plugin` *module-name*\]:
61
+ Load Nunjucks JavaScript plugin module (installed via NPM).
52
62
 
53
- - \[`-o`|`--output` *output-file*|`-`\]
63
+ - \[`-o`|`--output` *output-file*|`-`\]:
54
64
  Save output file (or stdout).
55
65
 
56
- - \[`<input-file>`|`-`\]
66
+ - \[`<input-file>`|`-`\]:
57
67
  Load input file (or stdin).
58
68
 
59
69
  ## EXAMPLE
package/nunjucks.ts CHANGED
@@ -16,6 +16,8 @@ import chalk from "chalk"
16
16
  import jsYAML from "js-yaml"
17
17
  import nunjucks from "nunjucks"
18
18
  import deepmerge from "deepmerge"
19
+ import dotenvx from "@dotenvx/dotenvx"
20
+ import * as findup from "find-up"
19
21
 
20
22
  /* type definitions */
21
23
  type PackageInfo = {
@@ -38,11 +40,13 @@ type OptionsType = {
38
40
  type CLIOptions = {
39
41
  help: boolean
40
42
  version: boolean
43
+ env: string[]
44
+ envs: boolean
41
45
  config: string
42
46
  option: string[]
43
47
  defines: string[]
44
48
  define: string[]
45
- extension: string[]
49
+ plugin: string[]
46
50
  output: string
47
51
  _: string[]
48
52
  }
@@ -58,11 +62,13 @@ program.name("nunjucks")
58
62
  .showHelpAfterError("hint: use option --help for usage information")
59
63
  .option("-h, --help", "show usage help", false)
60
64
  .option("-V, --version", "show program version information", false)
65
+ .option("-e, --env <env-file>", "load environment key/value file", reduceArray, [])
66
+ .option("-E, --envs", "load all environment key/value files", false)
61
67
  .option("-c, --config <config-file>", "load Nunjucks configuration YAML file", "")
62
68
  .option("-C, --option <key>=<value>", "set Nunjucks configuration option", reduceArray, [])
63
69
  .option("-d, --defines <context-file>", "load context definition YAML file", reduceArray, [])
64
70
  .option("-D, --define <key>=<value>", "set context definition key/value", reduceArray, [])
65
- .option("-e, --extension <module-name>", "load Nunjucks JavaScript extension module", reduceArray, [])
71
+ .option("-p, --plugin <module-name>", "load Nunjucks JavaScript plugin module", reduceArray, [])
66
72
  .option("-o, --output <output-file>", "save output file", "-")
67
73
  .argument("[<input-file>]", "input file")
68
74
  program.parse(process.argv)
@@ -116,7 +122,7 @@ if (inputFile === "-") {
116
122
  }
117
123
  else {
118
124
  if (!fs.existsSync(inputFile)) {
119
- console.error(chalk.red(`nunjucks: ERROR: failed to find input file: ${inputFile}`))
125
+ console.error(chalk.red(`nunjucks: ERROR: failed to find input file: "${inputFile}"`))
120
126
  process.exit(1)
121
127
  }
122
128
  input = fs.readFileSync(inputFile, { encoding: "utf8" })
@@ -134,6 +140,24 @@ for (const define of argv.defines) {
134
140
  }
135
141
  }
136
142
 
143
+ /* load environment variables from all default files */
144
+ if (argv.envs) {
145
+ const files = findup.findUpMultipleSync(".env")
146
+ if (files.length > 0)
147
+ dotenvx.config({ path: files, quiet: true })
148
+ }
149
+
150
+ /* load environment variables from environment files */
151
+ if (argv.env.length > 0) {
152
+ for (const env of argv.env) {
153
+ if (!fs.existsSync(env)) {
154
+ console.error(chalk.red(`nunjucks: ERROR: environment file not found: "${env}"`))
155
+ process.exit(1)
156
+ }
157
+ }
158
+ dotenvx.config({ path: argv.env, quiet: true })
159
+ }
160
+
137
161
  /* expose environment variables to template */
138
162
  context.env = process.env
139
163
 
@@ -176,20 +200,20 @@ options = {
176
200
  /* configure environment */
177
201
  const env = nunjucks.configure(inputFile, options)
178
202
 
179
- /* load external extension files */
180
- for (const extension of argv.extension) {
181
- let modpath: string | null = path.resolve(extension)
203
+ /* load external plugin modules */
204
+ for (const plugin of argv.plugin) {
205
+ let modpath: string | null = path.resolve(plugin)
182
206
  if (!fs.existsSync(modpath)) {
183
207
  try {
184
208
  const require = createRequire(import.meta.url)
185
- modpath = require.resolve(extension)
209
+ modpath = require.resolve(plugin)
186
210
  }
187
211
  catch (_ex) {
188
212
  modpath = null
189
213
  }
190
214
  }
191
215
  if (modpath === null) {
192
- console.error(chalk.red(`nunjucks: ERROR: failed to find extension module: ${extension}`))
216
+ console.error(chalk.red(`nunjucks: ERROR: failed to find plugin module: ${plugin}`))
193
217
  process.exit(1)
194
218
  }
195
219
 
@@ -202,11 +226,11 @@ for (const extension of argv.extension) {
202
226
  mod = mod.default ?? mod
203
227
  }
204
228
  catch (ex: any) {
205
- console.error(chalk.red(`nunjucks: ERROR: failed to load extension module: ${ex.toString()}`))
229
+ console.error(chalk.red(`nunjucks: ERROR: failed to load plugin module: ${ex.toString()}`))
206
230
  process.exit(1)
207
231
  }
208
232
  if (!(mod !== null && typeof mod === "function")) {
209
- console.error(chalk.red(`nunjucks: ERROR: failed to call extension file: ${modpath}`))
233
+ console.error(chalk.red(`nunjucks: ERROR: failed to call plugin file: "${modpath}"`))
210
234
  process.exit(1)
211
235
  }
212
236
  mod(env)
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@rse/nunjucks-cli",
3
3
  "publishConfig": { "access": "public" },
4
- "version": "2.0.1",
5
- "stdver": "2.0.0-GA",
4
+ "version": "2.1.0",
5
+ "stdver": "2.1.0-GA",
6
6
  "description": "Nunjucks Template Rendering Command-Line Interface",
7
7
  "author": {
8
8
  "name": "Dr. Ralf S. Engelschall",
@@ -30,7 +30,9 @@
30
30
  "chalk": "5.6.2",
31
31
  "commander": "14.0.2",
32
32
  "js-yaml": "4.1.1",
33
- "deepmerge": "4.3.1"
33
+ "deepmerge": "4.3.1",
34
+ "@dotenvx/dotenvx": "1.51.2",
35
+ "find-up": "8.0.0"
34
36
  },
35
37
  "devDependencies": {
36
38
  "eslint": "9.39.2",
@@ -44,14 +46,15 @@
44
46
  "remark": "15.0.1",
45
47
  "remark-man": "9.0.0",
46
48
  "typescript": "5.9.3",
47
- "typescript-eslint": "8.50.0",
48
- "@rse/stx": "1.1.3",
49
+ "typescript-eslint": "8.50.1",
50
+ "@rse/stx": "1.1.4",
49
51
  "shx": "0.4.0",
50
52
  "@yao-pkg/pkg": "6.11.0",
51
53
 
52
54
  "@types/node": "25.0.3",
53
55
  "@types/js-yaml": "4.0.9",
54
- "@types/nunjucks": "3.2.6"
56
+ "@types/nunjucks": "3.2.6",
57
+ "@types/find-up": "4.0.2"
55
58
  },
56
59
  "scripts": {
57
60
  "start": "stx -v4 -c stx.conf",
package/stx.conf CHANGED
@@ -11,10 +11,7 @@ lint
11
11
 
12
12
  # build JavaScript from TypeScript
13
13
  build
14
- tsc --project tsconfig.json
15
-
16
- # build manual page
17
- man
14
+ tsc --project tsconfig.json && \
18
15
  remark --quiet --use remark-man --output nunjucks.1 nunjucks.md
19
16
 
20
17
  # execute simple smole test