You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
213 lines
4.6 KiB
213 lines
4.6 KiB
2 years ago
|
#!/usr/bin/env node
|
||
|
/*
|
||
|
* EJS Embedded JavaScript templates
|
||
|
* Copyright 2112 Matthew Eernisse (mde@fleegix.org)
|
||
|
*
|
||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
* you may not use this file except in compliance with the License.
|
||
|
* You may obtain a copy of the License at
|
||
|
*
|
||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
*
|
||
|
* Unless required by applicable law or agreed to in writing, software
|
||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
* See the License for the specific language governing permissions and
|
||
|
* limitations under the License.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
|
||
|
let program = require('jake').program;
|
||
|
delete global.jake; // NO NOT WANT
|
||
|
program.setTaskNames = function (n) { this.taskNames = n; };
|
||
|
|
||
|
let ejs = require('../lib/ejs');
|
||
|
let { hyphenToCamel } = require('../lib/utils');
|
||
|
let fs = require('fs');
|
||
|
let args = process.argv.slice(2);
|
||
|
let usage = fs.readFileSync(`${__dirname}/../usage.txt`).toString();
|
||
|
|
||
|
const CLI_OPTS = [
|
||
|
{ full: 'output-file',
|
||
|
abbr: 'o',
|
||
|
expectValue: true,
|
||
|
},
|
||
|
{ full: 'data-file',
|
||
|
abbr: 'f',
|
||
|
expectValue: true,
|
||
|
},
|
||
|
{ full: 'data-input',
|
||
|
abbr: 'i',
|
||
|
expectValue: true,
|
||
|
},
|
||
|
{ full: 'delimiter',
|
||
|
abbr: 'm',
|
||
|
expectValue: true,
|
||
|
passThrough: true,
|
||
|
},
|
||
|
{ full: 'open-delimiter',
|
||
|
abbr: 'p',
|
||
|
expectValue: true,
|
||
|
passThrough: true,
|
||
|
},
|
||
|
{ full: 'close-delimiter',
|
||
|
abbr: 'c',
|
||
|
expectValue: true,
|
||
|
passThrough: true,
|
||
|
},
|
||
|
{ full: 'strict',
|
||
|
abbr: 's',
|
||
|
expectValue: false,
|
||
|
allowValue: false,
|
||
|
passThrough: true,
|
||
|
},
|
||
|
{ full: 'no-with',
|
||
|
abbr: 'n',
|
||
|
expectValue: false,
|
||
|
allowValue: false,
|
||
|
},
|
||
|
{ full: 'locals-name',
|
||
|
abbr: 'l',
|
||
|
expectValue: true,
|
||
|
passThrough: true,
|
||
|
},
|
||
|
{ full: 'rm-whitespace',
|
||
|
abbr: 'w',
|
||
|
expectValue: false,
|
||
|
allowValue: false,
|
||
|
passThrough: true,
|
||
|
},
|
||
|
{ full: 'debug',
|
||
|
abbr: 'd',
|
||
|
expectValue: false,
|
||
|
allowValue: false,
|
||
|
passThrough: true,
|
||
|
},
|
||
|
{ full: 'help',
|
||
|
abbr: 'h',
|
||
|
passThrough: true,
|
||
|
},
|
||
|
{ full: 'version',
|
||
|
abbr: 'V',
|
||
|
passThrough: true,
|
||
|
},
|
||
|
// Alias lowercase v
|
||
|
{ full: 'version',
|
||
|
abbr: 'v',
|
||
|
passThrough: true,
|
||
|
},
|
||
|
];
|
||
|
|
||
|
let preempts = {
|
||
|
version: function () {
|
||
|
program.die(ejs.VERSION);
|
||
|
},
|
||
|
help: function () {
|
||
|
program.die(usage);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
let stdin = '';
|
||
|
process.stdin.setEncoding('utf8');
|
||
|
process.stdin.on('readable', () => {
|
||
|
let chunk;
|
||
|
while ((chunk = process.stdin.read()) !== null) {
|
||
|
stdin += chunk;
|
||
|
}
|
||
|
});
|
||
|
|
||
|
function run() {
|
||
|
|
||
|
program.availableOpts = CLI_OPTS;
|
||
|
program.parseArgs(args);
|
||
|
|
||
|
let templatePath = program.taskNames[0];
|
||
|
let pVals = program.envVars;
|
||
|
let pOpts = {};
|
||
|
|
||
|
for (let p in program.opts) {
|
||
|
let name = hyphenToCamel(p);
|
||
|
pOpts[name] = program.opts[p];
|
||
|
}
|
||
|
|
||
|
let opts = {};
|
||
|
let vals = {};
|
||
|
|
||
|
// Same-named 'passthrough' opts
|
||
|
CLI_OPTS.forEach((opt) => {
|
||
|
let optName = hyphenToCamel(opt.full);
|
||
|
if (opt.passThrough && typeof pOpts[optName] != 'undefined') {
|
||
|
opts[optName] = pOpts[optName];
|
||
|
}
|
||
|
});
|
||
|
|
||
|
// Bail out for help/version
|
||
|
for (let p in opts) {
|
||
|
if (preempts[p]) {
|
||
|
return preempts[p]();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Default to having views relative from the current working directory
|
||
|
opts.views = ['.'];
|
||
|
|
||
|
// Ensure there's a template to render
|
||
|
if (!templatePath) {
|
||
|
throw new Error('Please provide a template path. (Run ejs -h for help)');
|
||
|
}
|
||
|
|
||
|
if (opts.strict) {
|
||
|
pOpts.noWith = true;
|
||
|
}
|
||
|
if (pOpts.noWith) {
|
||
|
opts._with = false;
|
||
|
}
|
||
|
|
||
|
// Grab and parse any input data, in order of precedence:
|
||
|
// 1. Stdin
|
||
|
// 2. CLI arg via -i
|
||
|
// 3. Data file via -f
|
||
|
// Any individual vals passed at the end (e.g., foo=bar) will override
|
||
|
// any vals previously set
|
||
|
let input;
|
||
|
let err = new Error('Please do not pass data multiple ways. Pick one of stdin, -f, or -i.');
|
||
|
if (stdin) {
|
||
|
input = stdin;
|
||
|
}
|
||
|
else if (pOpts.dataInput) {
|
||
|
if (input) {
|
||
|
throw err;
|
||
|
}
|
||
|
input = decodeURIComponent(pOpts.dataInput);
|
||
|
}
|
||
|
else if (pOpts.dataFile) {
|
||
|
if (input) {
|
||
|
throw err;
|
||
|
}
|
||
|
input = fs.readFileSync(pOpts.dataFile).toString();
|
||
|
}
|
||
|
|
||
|
if (input) {
|
||
|
vals = JSON.parse(input);
|
||
|
}
|
||
|
|
||
|
// Override / set any individual values passed from the command line
|
||
|
for (let p in pVals) {
|
||
|
vals[p] = pVals[p];
|
||
|
}
|
||
|
|
||
|
let template = fs.readFileSync(templatePath).toString();
|
||
|
let output = ejs.render(template, vals, opts);
|
||
|
if (pOpts.outputFile) {
|
||
|
fs.writeFileSync(pOpts.outputFile, output);
|
||
|
}
|
||
|
else {
|
||
|
process.stdout.write(output);
|
||
|
}
|
||
|
process.exit();
|
||
|
}
|
||
|
|
||
|
// Defer execution so that stdin can be read if necessary
|
||
|
setImmediate(run);
|