@rse/nunjucks-cli 2.0.0 → 2.0.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/nunjucks.js +187 -0
- package/nunjucks.ts +0 -0
- package/package.json +2 -2
- package/stx.conf +10 -5
- package/tsconfig.json +2 -2
package/nunjucks.js
ADDED
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/*
|
|
3
|
+
** nunjucks -- Nunjucks Template Rendering Command-Line Interface
|
|
4
|
+
** Copyright (c) 2019-2025 Dr. Ralf S. Engelschall <http://engelschall.com>
|
|
5
|
+
** Licensed under MIT <http://spdx.org/licenses/MIT.html>
|
|
6
|
+
*/
|
|
7
|
+
/* built-in requirements */
|
|
8
|
+
import fs from "node:fs";
|
|
9
|
+
import path from "node:path";
|
|
10
|
+
import { createRequire } from "node:module";
|
|
11
|
+
/* external requirements */
|
|
12
|
+
import { Command } from "commander";
|
|
13
|
+
import chalk from "chalk";
|
|
14
|
+
import jsYAML from "js-yaml";
|
|
15
|
+
import nunjucks from "nunjucks";
|
|
16
|
+
import deepmerge from "deepmerge";
|
|
17
|
+
/* load my own information */
|
|
18
|
+
const my = JSON.parse(await fs.promises.readFile(new URL("./package.json", import.meta.url), "utf-8"));
|
|
19
|
+
/* parse command-line arguments */
|
|
20
|
+
const program = new Command();
|
|
21
|
+
const reduceArray = (v, l) => l.concat([v]);
|
|
22
|
+
program.name("nunjucks")
|
|
23
|
+
.description("Nunjucks Template Rendering Command-Line Interface")
|
|
24
|
+
.showHelpAfterError("hint: use option --help for usage information")
|
|
25
|
+
.option("-h, --help", "show usage help", false)
|
|
26
|
+
.option("-V, --version", "show program version information", false)
|
|
27
|
+
.option("-c, --config <config-file>", "load Nunjucks configuration YAML file", "")
|
|
28
|
+
.option("-C, --option <key>=<value>", "set Nunjucks configuration option", reduceArray, [])
|
|
29
|
+
.option("-d, --defines <context-file>", "load context definition YAML file", reduceArray, [])
|
|
30
|
+
.option("-D, --define <key>=<value>", "set context definition key/value", reduceArray, [])
|
|
31
|
+
.option("-e, --extension <module-name>", "load Nunjucks JavaScript extension module", reduceArray, [])
|
|
32
|
+
.option("-o, --output <output-file>", "save output file", "-")
|
|
33
|
+
.argument("[<input-file>]", "input file");
|
|
34
|
+
program.parse(process.argv);
|
|
35
|
+
const argv = {
|
|
36
|
+
...program.opts(),
|
|
37
|
+
_: program.args
|
|
38
|
+
};
|
|
39
|
+
/* handle special help request */
|
|
40
|
+
if (argv.help) {
|
|
41
|
+
console.log(program.helpInformation());
|
|
42
|
+
console.log("Example:\n $ echo \"Hello, {{ who }}!\" | nunjucks -Dwho=World -\n");
|
|
43
|
+
process.exit(0);
|
|
44
|
+
}
|
|
45
|
+
/* handle special version request */
|
|
46
|
+
if (argv.version) {
|
|
47
|
+
console.log(`${my.name} ${my.version} (Node.js ${process.versions.node}, Nunjucks: ${my.dependencies.nunjucks})`);
|
|
48
|
+
console.log(`${my.description}`);
|
|
49
|
+
console.log(`Copyright (c) 2019-2025 ${my.author.name} <${my.author.url}>`);
|
|
50
|
+
console.log(`Licensed under ${my.license} <http://spdx.org/licenses/${my.license}.html>`);
|
|
51
|
+
process.exit(0);
|
|
52
|
+
}
|
|
53
|
+
/* read input file */
|
|
54
|
+
let input = "";
|
|
55
|
+
if (argv._.length > 1) {
|
|
56
|
+
console.error(chalk.red("nunjucks: ERROR: invalid number of arguments (zero or one input file expected)"));
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
let inputFile = argv._[0] ?? "-";
|
|
60
|
+
if (inputFile === "-") {
|
|
61
|
+
inputFile = "<stdin>";
|
|
62
|
+
process.stdin.setEncoding("utf-8");
|
|
63
|
+
const BUFSIZE = 256;
|
|
64
|
+
const buf = Buffer.alloc(BUFSIZE);
|
|
65
|
+
while (true) {
|
|
66
|
+
let bytesRead = 0;
|
|
67
|
+
try {
|
|
68
|
+
bytesRead = fs.readSync(process.stdin.fd, buf, 0, BUFSIZE, null);
|
|
69
|
+
}
|
|
70
|
+
catch (ex) {
|
|
71
|
+
if (ex.code === "EAGAIN")
|
|
72
|
+
continue;
|
|
73
|
+
else if (ex.code === "EOF")
|
|
74
|
+
break;
|
|
75
|
+
else
|
|
76
|
+
throw ex;
|
|
77
|
+
}
|
|
78
|
+
if (bytesRead === 0)
|
|
79
|
+
break;
|
|
80
|
+
input += buf.toString("utf8", 0, bytesRead);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
if (!fs.existsSync(inputFile)) {
|
|
85
|
+
console.error(chalk.red(`nunjucks: ERROR: failed to find input file: ${inputFile}`));
|
|
86
|
+
process.exit(1);
|
|
87
|
+
}
|
|
88
|
+
input = fs.readFileSync(inputFile, { encoding: "utf8" });
|
|
89
|
+
}
|
|
90
|
+
/* provide context variables for template */
|
|
91
|
+
let context = {};
|
|
92
|
+
for (const define of argv.defines) {
|
|
93
|
+
try {
|
|
94
|
+
context = deepmerge(context, jsYAML.load(fs.readFileSync(define, { encoding: "utf8" })));
|
|
95
|
+
}
|
|
96
|
+
catch (ex) {
|
|
97
|
+
console.error(chalk.red(`nunjucks: ERROR: failed to load context YAML file: ${ex.toString()}`));
|
|
98
|
+
process.exit(1);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
/* expose environment variables to template */
|
|
102
|
+
context.env = process.env;
|
|
103
|
+
/* add context defines */
|
|
104
|
+
argv.define.forEach((define) => {
|
|
105
|
+
const match = define.match(/^([^=]+)(?:=(.*))?$/);
|
|
106
|
+
if (!match)
|
|
107
|
+
return;
|
|
108
|
+
let [, key, val] = match;
|
|
109
|
+
if (!key)
|
|
110
|
+
return;
|
|
111
|
+
if (val === undefined)
|
|
112
|
+
val = "true";
|
|
113
|
+
context[key] = val;
|
|
114
|
+
});
|
|
115
|
+
/* determine Nunjucks options */
|
|
116
|
+
let options = {};
|
|
117
|
+
if (argv.config) {
|
|
118
|
+
try {
|
|
119
|
+
options = jsYAML.load(fs.readFileSync(argv.config, { encoding: "utf8" }));
|
|
120
|
+
}
|
|
121
|
+
catch (ex) {
|
|
122
|
+
console.error(chalk.red(`nunjucks: ERROR: failed to load options YAML file: ${ex.toString()}`));
|
|
123
|
+
process.exit(1);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
if (argv.option.length > 0)
|
|
127
|
+
options = Object.assign(options, argv.option);
|
|
128
|
+
options = {
|
|
129
|
+
autoescape: false,
|
|
130
|
+
throwOnUndefined: false,
|
|
131
|
+
trimBlocks: true,
|
|
132
|
+
lstripBlocks: true,
|
|
133
|
+
watch: false,
|
|
134
|
+
noCache: true,
|
|
135
|
+
...options
|
|
136
|
+
};
|
|
137
|
+
/* configure environment */
|
|
138
|
+
const env = nunjucks.configure(inputFile, options);
|
|
139
|
+
/* load external extension files */
|
|
140
|
+
for (const extension of argv.extension) {
|
|
141
|
+
let modpath = path.resolve(extension);
|
|
142
|
+
if (!fs.existsSync(modpath)) {
|
|
143
|
+
try {
|
|
144
|
+
const require = createRequire(import.meta.url);
|
|
145
|
+
modpath = require.resolve(extension);
|
|
146
|
+
}
|
|
147
|
+
catch (_ex) {
|
|
148
|
+
modpath = null;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
if (modpath === null) {
|
|
152
|
+
console.error(chalk.red(`nunjucks: ERROR: failed to find extension module: ${extension}`));
|
|
153
|
+
process.exit(1);
|
|
154
|
+
}
|
|
155
|
+
/* dynamically import the module */
|
|
156
|
+
let mod;
|
|
157
|
+
try {
|
|
158
|
+
mod = await import(modpath);
|
|
159
|
+
/* handle both default and named exports */
|
|
160
|
+
mod = mod.default ?? mod;
|
|
161
|
+
}
|
|
162
|
+
catch (ex) {
|
|
163
|
+
console.error(chalk.red(`nunjucks: ERROR: failed to load extension module: ${ex.toString()}`));
|
|
164
|
+
process.exit(1);
|
|
165
|
+
}
|
|
166
|
+
if (!(mod !== null && typeof mod === "function")) {
|
|
167
|
+
console.error(chalk.red(`nunjucks: ERROR: failed to call extension file: ${modpath}`));
|
|
168
|
+
process.exit(1);
|
|
169
|
+
}
|
|
170
|
+
mod(env);
|
|
171
|
+
}
|
|
172
|
+
/* render Nunjucks template */
|
|
173
|
+
let output;
|
|
174
|
+
try {
|
|
175
|
+
output = env.renderString(input, context);
|
|
176
|
+
}
|
|
177
|
+
catch (ex) {
|
|
178
|
+
console.error(chalk.red(`nunjucks: ERROR: failed to render template: ${ex.toString()}`));
|
|
179
|
+
process.exit(1);
|
|
180
|
+
}
|
|
181
|
+
/* write output */
|
|
182
|
+
if (argv.output === "-")
|
|
183
|
+
process.stdout.write(output);
|
|
184
|
+
else
|
|
185
|
+
fs.writeFileSync(argv.output, output, { encoding: "utf8" });
|
|
186
|
+
/* die gracefully */
|
|
187
|
+
process.exit(0);
|
package/nunjucks.ts
CHANGED
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rse/nunjucks-cli",
|
|
3
3
|
"publishConfig": { "access": "public" },
|
|
4
|
-
"version": "2.0.
|
|
4
|
+
"version": "2.0.1",
|
|
5
5
|
"stdver": "2.0.0-GA",
|
|
6
6
|
"description": "Nunjucks Template Rendering Command-Line Interface",
|
|
7
7
|
"author": {
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"url": "http://github.com/rse/nunjucks-cli/issues"
|
|
19
19
|
},
|
|
20
20
|
"bin": {
|
|
21
|
-
"nunjucks": "nunjucks.
|
|
21
|
+
"nunjucks": "nunjucks.js"
|
|
22
22
|
},
|
|
23
23
|
"man": "nunjucks.1",
|
|
24
24
|
"type": "module",
|
package/stx.conf
CHANGED
|
@@ -7,6 +7,10 @@
|
|
|
7
7
|
# static code analysis
|
|
8
8
|
lint
|
|
9
9
|
eslint --config eslint.mjs nunjucks.ts && \
|
|
10
|
+
tsc --noEmit --project tsconfig.json
|
|
11
|
+
|
|
12
|
+
# build JavaScript from TypeScript
|
|
13
|
+
build
|
|
10
14
|
tsc --project tsconfig.json
|
|
11
15
|
|
|
12
16
|
# build manual page
|
|
@@ -14,20 +18,20 @@ man
|
|
|
14
18
|
remark --quiet --use remark-man --output nunjucks.1 nunjucks.md
|
|
15
19
|
|
|
16
20
|
# execute simple smole test
|
|
17
|
-
test
|
|
18
|
-
echo 'Hello, {{who}}!' | node nunjucks.
|
|
21
|
+
test : build
|
|
22
|
+
echo 'Hello, {{who}}!' | node nunjucks.js -D who=world -
|
|
19
23
|
|
|
20
24
|
# build all-in-one packages
|
|
21
25
|
build:pkg [hostname=en4.*]
|
|
22
26
|
|
|
23
27
|
# package distribution archives
|
|
24
|
-
package : build:pkg [hostname=en4.*]
|
|
28
|
+
package : build build:pkg [hostname=en4.*]
|
|
25
29
|
VERSION=`sed -n '/"version":/ s/.*: *"\(.*\)".*/\1/p' package.json` && \
|
|
26
30
|
targets="node24-linux-x64,node24-linux-arm64" && \
|
|
27
31
|
targets="$targets,node24-win-x64,node24-win-arm64" && \
|
|
28
32
|
targets="$targets,node24-macos-x64,node24-macos-arm64" && \
|
|
29
33
|
sed -e 's;@rse/nunjucks-cli;nunjucks;' <package.json >nunjucks.json && \
|
|
30
|
-
pkg --sea --public -c nunjucks.json -t "$targets" nunjucks.
|
|
34
|
+
pkg --sea --public -c nunjucks.json -t "$targets" nunjucks.js && \
|
|
31
35
|
rm -f nunjucks.json && \
|
|
32
36
|
shx mv nunjucks-linux-x64 nunjucks-lnx-x64 && \
|
|
33
37
|
shx mv nunjucks-linux-arm64 nunjucks-lnx-a64 && \
|
|
@@ -42,7 +46,7 @@ package : build:pkg [hostname=en4.*]
|
|
|
42
46
|
mkdir -p nunjucks-$VERSION-mac-a64/ && \
|
|
43
47
|
mkdir -p nunjucks-$VERSION-lnx-x64/ && \
|
|
44
48
|
mkdir -p nunjucks-$VERSION-lnx-a64/ && \
|
|
45
|
-
cp -p nunjucks.
|
|
49
|
+
cp -p nunjucks.js nunjucks-$VERSION/nunjucks.js && \
|
|
46
50
|
cp -p nunjucks-win-x64.exe nunjucks-$VERSION-win-x64/nunjucks.exe && \
|
|
47
51
|
cp -p nunjucks-win-a64.exe nunjucks-$VERSION-win-a64/nunjucks.exe && \
|
|
48
52
|
cp -p nunjucks-mac-x64 nunjucks-$VERSION-mac-x64/nunjucks && \
|
|
@@ -81,6 +85,7 @@ publish : package [hostname=en4.*]
|
|
|
81
85
|
|
|
82
86
|
# remove all generated artifacts
|
|
83
87
|
clean
|
|
88
|
+
shx rm -f nunjucks.js && \
|
|
84
89
|
shx rm -rf nunjucks-*.zip
|
|
85
90
|
|
|
86
91
|
# remove all generated artifacts
|
package/tsconfig.json
CHANGED
|
@@ -5,13 +5,13 @@
|
|
|
5
5
|
"lib": [ "ES2024" ],
|
|
6
6
|
"moduleResolution": "node16",
|
|
7
7
|
"resolveJsonModule": true,
|
|
8
|
-
"
|
|
8
|
+
"declaration": false,
|
|
9
9
|
"allowSyntheticDefaultImports": true,
|
|
10
10
|
"esModuleInterop": true,
|
|
11
11
|
"forceConsistentCasingInFileNames": true,
|
|
12
12
|
"strict": true,
|
|
13
13
|
"skipLibCheck": true,
|
|
14
|
-
"
|
|
14
|
+
"outDir": ".",
|
|
15
15
|
"types": [ "node" ]
|
|
16
16
|
},
|
|
17
17
|
"include": [
|