update dependencies

This commit is contained in:
Igor Savin
2026-03-18 23:27:46 +02:00
committed by Jay Linski
parent 6f1de2025e
commit 92e842f82e
8 changed files with 680 additions and 716 deletions
+5 -3
View File
@@ -1,7 +1,9 @@
#!/usr/bin/env node
const yargs = require('yargs')
const yargs = require('yargs')(process.argv.slice(2))
.usage('Precompile handlebar templates.\nUsage: $0 [template|directory]...')
.help(false)
.version(false)
.option('f', {
type: 'string',
description: 'Output File',
@@ -105,7 +107,7 @@ const yargs = require('yargs')
})
.wrap(120);
const argv = yargs.argv;
const argv = yargs.parseSync();
argv.files = argv._;
delete argv._;
@@ -116,7 +118,7 @@ Precompiler.loadTemplates(argv, function (err, opts) {
}
if (opts.help || (!opts.templates.length && !opts.version)) {
yargs.showHelp();
yargs.showHelp('log');
} else {
Precompiler.cli(opts);
}
+5 -4
View File
@@ -152,7 +152,7 @@ function loadFiles(opts, callback) {
);
}
module.exports.cli = function (opts) {
module.exports.cli = async function (opts) {
if (opts.version) {
console.log(Handlebars.VERSION);
return;
@@ -221,7 +221,7 @@ module.exports.cli = function (opts) {
output.add('{};\n');
}
opts.templates.forEach(function (template) {
for (const template of opts.templates) {
let options = {
knownHelpers: known,
knownHelpersOnly: opts.o,
@@ -238,11 +238,12 @@ module.exports.cli = function (opts) {
// If we are generating a source map, we have to reconstruct the SourceNode object
if (opts.map) {
let consumer = new SourceMapConsumer(precompiled.map);
let consumer = await new SourceMapConsumer(precompiled.map);
precompiled = SourceNode.fromStringWithSourceMap(
precompiled.code,
consumer
);
consumer.destroy();
}
if (opts.simple) {
@@ -264,7 +265,7 @@ module.exports.cli = function (opts) {
');\n',
]);
}
});
}
// Output the content
if (!opts.simple) {
+402 -662
View File
File diff suppressed because it is too large Load Diff
+4 -3
View File
@@ -60,8 +60,8 @@
"dependencies": {
"@handlebars/parser": "^2.1.0",
"neo-async": "^2.6.2",
"source-map": "^0.6.1",
"yargs": "^16.2.0"
"source-map": "^0.7.6",
"yargs": "^18.0.0"
},
"devDependencies": {
"@aws-sdk/client-s3": "^3.1011.0",
@@ -73,6 +73,7 @@
"@vitest/browser": "^4.0.18",
"@vitest/browser-playwright": "^4.0.18",
"@vitest/coverage-v8": "^4.0.18",
"cli-testlab": "^6.0.0",
"concurrently": "^5.0.0",
"eslint": "^10.0.3",
"eslint-plugin-compat": "^7.0.1",
@@ -84,7 +85,7 @@
"oxlint": "^1.51.0",
"semver": "^5.0.1",
"tinybench": "^6.0.0",
"typescript": "^3.4.3",
"typescript": "^5.9.3",
"uglify-js": "^3.19.3",
"vitest": "^4.0.18"
},
+2 -2
View File
@@ -2,7 +2,6 @@ Precompile handlebar templates.
Usage: handlebars.js [template|directory]...
Options:
--help Outputs this message [boolean]
-f, --output Output File [string]
--map Source Map File [string]
-a, --amd Exports amd style (require.js) [boolean]
@@ -22,4 +21,5 @@ Options:
-d, --data Include data when compiling [boolean]
-e, --extension Template extension. [string] [default: "handlebars"]
-b, --bom Removes the BOM (Byte Order Mark) from the beginning of the templates. [boolean]
-v, --version Show version number [boolean]
-v, --version Prints the current compiler version [boolean]
--help Outputs this message [boolean]
+36 -36
View File
@@ -33,7 +33,7 @@ describe('precompiler', function () {
* @param {Error} loadError the error that should be thrown if uglify is loaded
* @param {function} callback a callback-function to run when the mock is active.
*/
function mockRequireUglify(loadError, callback) {
async function mockRequireUglify(loadError, callback) {
var Module = require('module');
var _resolveFilename = Module._resolveFilename;
delete require.cache[require.resolve('uglify-js')];
@@ -45,7 +45,7 @@ describe('precompiler', function () {
return _resolveFilename.call(this, request, mod);
};
try {
callback();
await callback();
} finally {
Module._resolveFilename = _resolveFilename;
delete require.cache[require.resolve('uglify-js')];
@@ -87,40 +87,40 @@ describe('precompiler', function () {
Precompiler.cli({ templates: [], version: true });
expect(log).toBe(Handlebars.VERSION);
});
it('should throw if lacking templates', function () {
expect(function () {
Precompiler.cli({ templates: [] });
}).toThrow('Must define at least one template or directory.');
it('should throw if lacking templates', async function () {
await expect(Precompiler.cli({ templates: [] })).rejects.toThrow(
'Must define at least one template or directory.'
);
});
it('should handle empty/filtered directories', function () {
Precompiler.cli({ hasDirectory: true, templates: [] });
it('should handle empty/filtered directories', async function () {
await Precompiler.cli({ hasDirectory: true, templates: [] });
// Success is not throwing
});
it('should throw when combining simple and minimized', function () {
expect(function () {
Precompiler.cli({ templates: [__dirname], simple: true, min: true });
}).toThrow('Unable to minimize simple output');
it('should throw when combining simple and minimized', async function () {
await expect(
Precompiler.cli({ templates: [__dirname], simple: true, min: true })
).rejects.toThrow('Unable to minimize simple output');
});
it('should throw when combining simple and multiple templates', function () {
expect(function () {
it('should throw when combining simple and multiple templates', async function () {
await expect(
Precompiler.cli({
templates: [
__dirname + '/artifacts/empty.handlebars',
__dirname + '/artifacts/empty.handlebars',
],
simple: true,
})
).rejects.toThrow('Unable to output multiple templates in simple mode');
});
}).toThrow('Unable to output multiple templates in simple mode');
it('should throw when missing name', async function () {
await expect(
Precompiler.cli({ templates: [{ source: '' }], amd: true })
).rejects.toThrow('Name missing for template');
});
it('should throw when missing name', function () {
expect(function () {
Precompiler.cli({ templates: [{ source: '' }], amd: true });
}).toThrow('Name missing for template');
});
it('should throw when combining simple and directories', function () {
expect(function () {
Precompiler.cli({ hasDirectory: true, templates: [1], simple: true });
}).toThrow('Unable to output multiple templates in simple mode');
it('should throw when combining simple and directories', async function () {
await expect(
Precompiler.cli({ hasDirectory: true, templates: [1], simple: true })
).rejects.toThrow('Unable to output multiple templates in simple mode');
});
it('should output simple templates', function () {
@@ -227,42 +227,42 @@ describe('precompiler', function () {
expect(log).toBe('min');
});
it('should omit minimization gracefully, if uglify-js is missing', function () {
it('should omit minimization gracefully, if uglify-js is missing', async function () {
var error = new Error("Cannot find module 'uglify-js'");
error.code = 'MODULE_NOT_FOUND';
mockRequireUglify(error, function () {
await mockRequireUglify(error, async function () {
var Precompiler = require('../dist/cjs/precompiler');
Handlebars.precompile = function () {
return 'amd';
};
Precompiler.cli({ templates: [emptyTemplate], min: true });
await Precompiler.cli({ templates: [emptyTemplate], min: true });
expect(log).toMatch(/template\(amd\)/);
expect(log).toMatch(/\n/);
expect(errorLog).toMatch(/Code minimization is disabled/);
});
});
it('should fail on errors (other than missing module) while loading uglify-js', function () {
mockRequireUglify(new Error('Mock Error'), function () {
expect(function () {
it('should fail on errors (other than missing module) while loading uglify-js', async function () {
await mockRequireUglify(new Error('Mock Error'), async function () {
var Precompiler = require('../dist/cjs/precompiler');
Handlebars.precompile = function () {
return 'amd';
};
Precompiler.cli({ templates: [emptyTemplate], min: true });
}).toThrow('Mock Error');
await expect(
Precompiler.cli({ templates: [emptyTemplate], min: true })
).rejects.toThrow('Mock Error');
});
});
it('should output map', function () {
Precompiler.cli({ templates: [emptyTemplate], map: 'foo.js.map' });
it('should output map', async function () {
await Precompiler.cli({ templates: [emptyTemplate], map: 'foo.js.map' });
expect(file).toBe('foo.js.map');
expect(log.match(/sourceMappingURL=/g).length).toBe(1);
});
it('should output map', function () {
Precompiler.cli({
it('should output map with minification', async function () {
await Precompiler.cli({
templates: [emptyTemplate],
min: true,
map: 'foo.js.map',
+1 -1
View File
@@ -70,7 +70,7 @@ const testCases = [
{
binInputParameters: ['-v'],
outputLocation: 'stdout',
expectedOutput: require('../../package.json').version,
expectedOutput: require('../../lib').VERSION,
},
{
binInputParameters: [
+220
View File
@@ -0,0 +1,220 @@
const { execCommand, FileTestHelper } = require('cli-testlab');
const Handlebars = require('../../lib');
const cli = 'node ./bin/handlebars.js';
describe('bin/handlebars (cli-testlab)', function () {
describe('help and version', function () {
it('should display help menu with --help', async function () {
await execCommand(`${cli} --help`, {
expectedOutput: [
'Precompile handlebar templates.',
'Usage:',
'--output',
'--amd',
'--commonjs',
'--partial',
'--extension',
'--bom',
],
});
});
it('should display version with -v', async function () {
await execCommand(`${cli} -v`, {
expectedOutput: Handlebars.VERSION,
});
});
it('should display help when no arguments are provided', async function () {
await execCommand(`${cli}`, {
expectedOutput: 'Precompile handlebar templates.',
});
});
});
describe('precompilation output modes', function () {
it('should precompile a template in AMD mode', async function () {
const result = await execCommand(
`${cli} -a spec/artifacts/empty.handlebars`
);
expect(result.stdout).toContain("define(['handlebars.runtime']");
expect(result.stdout).toContain("templates['empty']");
});
it('should precompile a template in CommonJS mode', async function () {
const result = await execCommand(
`${cli} spec/artifacts/empty.handlebars -c`
);
expect(result.stdout).toContain('Handlebars.template');
expect(result.stdout).not.toContain("define(['handlebars.runtime']");
});
it('should precompile in simple mode', async function () {
const result = await execCommand(
`${cli} -a -s spec/artifacts/empty.handlebars`
);
expect(result.stdout).toContain('"compiler"');
expect(result.stdout).toContain('"main"');
expect(result.stdout).not.toContain("templates['empty']");
});
it('should precompile with minification', async function () {
const result = await execCommand(
`${cli} -a -m spec/artifacts/empty.handlebars`
);
expect(result.stdout).toContain('define(');
expect(result.stdout).toContain('handlebars.runtime');
});
});
describe('custom namespace', function () {
it('should use custom namespace with -n', async function () {
const result = await execCommand(
`${cli} -a -n CustomNamespace.templates spec/artifacts/empty.handlebars`
);
expect(result.stdout).toContain('CustomNamespace.templates');
expect(result.stdout).not.toContain('Handlebars.templates');
});
it('should use custom namespace with --namespace', async function () {
const result = await execCommand(
`${cli} -a --namespace CustomNamespace.templates spec/artifacts/empty.handlebars`
);
expect(result.stdout).toContain('CustomNamespace.templates');
});
});
describe('file output', function () {
let files;
beforeEach(function () {
files = new FileTestHelper({ basePath: '.' });
files.createDir('tmp');
});
afterEach(function () {
files.cleanup();
});
it('should write output to a file with -f', async function () {
const outputFile = 'tmp/cli-testlab-output.js';
files.registerForCleanup(outputFile);
await execCommand(
`${cli} -a -f ${outputFile} spec/artifacts/empty.handlebars`
);
expect(files.fileExists(outputFile)).toBe(true);
const content = files.getFileTextContent(outputFile);
expect(content).toContain("define(['handlebars.runtime']");
expect(content).toContain("templates['empty']");
});
it('should generate source map file with --map', async function () {
const mapFile = 'tmp/cli-testlab-source.map';
files.registerForCleanup(mapFile);
await execCommand(
`${cli} -i "<div>1</div>" -a -m -N test --map ${mapFile}`
);
expect(files.fileExists(mapFile)).toBe(true);
const mapContent = files.getFileTextContent(mapFile);
const parsed = JSON.parse(mapContent);
expect(parsed).toHaveProperty('version', 3);
expect(parsed).toHaveProperty('sources');
expect(parsed).toHaveProperty('mappings');
});
});
describe('template options', function () {
it('should support custom extension with -e', async function () {
const result = await execCommand(
`${cli} -a -e hbs ./spec/artifacts/non.default.extension.hbs`
);
expect(result.stdout).toContain("define(['handlebars.runtime']");
expect(result.stdout).toContain("templates['non.default.extension']");
});
it('should compile as partial with -p', async function () {
const result = await execCommand(
`${cli} -a -p ./spec/artifacts/partial.template.handlebars`
);
expect(result.stdout).toContain('Handlebars.partials');
});
it('should strip root from template names with -r', async function () {
const result = await execCommand(
`${cli} spec/artifacts/partial.template.handlebars -r spec -a`
);
expect(result.stdout).not.toContain("templates['spec/");
});
it('should strip BOM with -b', async function () {
const result = await execCommand(
`${cli} ./spec/artifacts/bom.handlebars -b -a`
);
expect(result.stdout).not.toContain('\uFEFF');
expect(result.stdout).toContain("define(['handlebars.runtime']");
});
});
describe('inline templates', function () {
it('should compile inline template with -i', async function () {
const result = await execCommand(
`${cli} -i "<div>hello</div>" -a -N myTemplate`
);
expect(result.stdout).toContain("define(['handlebars.runtime']");
expect(result.stdout).toContain("templates['myTemplate']");
});
it('should compile multiple inline templates', async function () {
const result = await execCommand(
`${cli} -i "<div>1</div>" -i "<div>2</div>" -N first -N second -a`
);
expect(result.stdout).toContain("templates['first']");
expect(result.stdout).toContain("templates['second']");
});
});
describe('known helpers', function () {
it('should accept known helpers with -k', async function () {
const result = await execCommand(
`${cli} spec/artifacts/known.helpers.handlebars -a -k someHelper -k anotherHelper -o`
);
expect(result.stdout).toContain("define(['handlebars.runtime']");
});
});
describe('handlebar path', function () {
it('should accept custom handlebar path with -h', async function () {
const result = await execCommand(
`${cli} spec/artifacts/empty.handlebars -h some-path/ -a`
);
expect(result.stdout).toContain(
"define(['some-path/handlebars.runtime']"
);
});
});
describe('negated boolean flags', function () {
it('should support --no-amd to negate --amd (issue #1673)', async function () {
const result = await execCommand(
`${cli} --amd --no-amd spec/artifacts/empty.handlebars`
);
expect(result.stdout).not.toContain("define(['handlebars.runtime']");
expect(result.stdout).toContain('Handlebars.template');
});
});
describe('multiple files', function () {
it('should precompile multiple files into a single output', async function () {
const result = await execCommand(
`${cli} spec/artifacts/empty.handlebars spec/artifacts/empty.handlebars -a -n someNameSpace`
);
expect(result.stdout).toContain('someNameSpace');
expect(result.stdout).toContain("define(['handlebars.runtime']");
});
});
});