add tstyche tests

This commit is contained in:
Igor Savin
2026-03-18 23:44:08 +02:00
committed by Jay Linski
parent 92e842f82e
commit 1b321a8bef
8 changed files with 827 additions and 658 deletions
+35 -1
View File
@@ -39,6 +39,7 @@
"oxlint": "^1.51.0",
"semver": "^5.0.1",
"tinybench": "^6.0.0",
"tstyche": "^6.2.0",
"typescript": "^5.9.3",
"uglify-js": "^3.19.3",
"vitest": "^4.0.18"
@@ -13211,6 +13212,30 @@
"integrity": "sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA==",
"dev": true
},
"node_modules/tstyche": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/tstyche/-/tstyche-6.2.0.tgz",
"integrity": "sha512-WBiB6fGGsmQCFFRGwYaKq528pCLJ0CUUdrIdUm2rnVJ1Ineskbrv9uQADWsD3uHndEV/Hesdx1Gj8PdkBahxlQ==",
"dev": true,
"license": "MIT",
"bin": {
"tstyche": "dist/bin.js"
},
"engines": {
"node": ">=22.12"
},
"funding": {
"url": "https://github.com/tstyche/tstyche?sponsor=1"
},
"peerDependencies": {
"typescript": ">=5.4"
},
"peerDependenciesMeta": {
"typescript": {
"optional": true
}
}
},
"node_modules/type-check": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
@@ -13244,6 +13269,7 @@
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
"dev": true,
"license": "Apache-2.0",
"peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -22876,6 +22902,13 @@
"integrity": "sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA==",
"dev": true
},
"tstyche": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/tstyche/-/tstyche-6.2.0.tgz",
"integrity": "sha512-WBiB6fGGsmQCFFRGwYaKq528pCLJ0CUUdrIdUm2rnVJ1Ineskbrv9uQADWsD3uHndEV/Hesdx1Gj8PdkBahxlQ==",
"dev": true,
"requires": {}
},
"type-check": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
@@ -22899,7 +22932,8 @@
"version": "5.9.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
"dev": true
"dev": true,
"peer": true
},
"uglify-js": {
"version": "3.19.3",
+2 -1
View File
@@ -42,7 +42,7 @@
"lint": "npm run lint:oxlint && npm run lint:format && npm run lint:types && npm run lint:compat",
"lint:oxlint": "oxlint --max-warnings 0 .",
"lint:format": "oxfmt --check .",
"lint:types": "tsc --noEmit --project types",
"lint:types": "tsc --noEmit --project types && tstyche",
"lint:compat": "eslint",
"test": "npm run build && vitest run --project node --project tasks --project rspack --coverage",
"test:browser": "vitest run --project browser",
@@ -85,6 +85,7 @@
"oxlint": "^1.51.0",
"semver": "^5.0.1",
"tinybench": "^6.0.0",
"tstyche": "^6.2.0",
"typescript": "^5.9.3",
"uglify-js": "^3.19.3",
"vitest": "^4.0.18"
+3 -2
View File
@@ -25,7 +25,7 @@ describe('source-map', function () {
expect(template.map).toBeTruthy();
}
});
it('should map source properly', function () {
it('should map source properly', async function () {
var templateSource =
' b{{hello}} \n {{bar}}a {{#block arg hash=(subex 1 subval)}}{{/block}}',
template = Handlebars.precompile(templateSource, {
@@ -34,7 +34,7 @@ describe('source-map', function () {
});
if (template.map) {
var consumer = new SourceMapConsumer(template.map),
var consumer = await new SourceMapConsumer(template.map),
lines = template.code.split('\n'),
srcLines = templateSource.split('\n'),
generated = grepLine('" b"', lines),
@@ -43,6 +43,7 @@ describe('source-map', function () {
var mapped = consumer.originalPositionFor(generated);
expect(mapped.line).toBe(source.line);
expect(mapped.column).toBe(source.column);
consumer.destroy();
}
});
});
-256
View File
@@ -1,256 +0,0 @@
const childProcess = require('child_process');
const fs = require('fs');
const os = require('os');
const path = require('path');
const testCases = [
{
binInputParameters: ['-a', 'spec/artifacts/empty.handlebars'],
outputLocation: 'stdout',
expectedOutputSpec: './spec/expected/empty.amd.js',
},
{
binInputParameters: [
'-a',
'-f',
'TEST_OUTPUT',
'spec/artifacts/empty.handlebars',
],
outputLocation: 'TEST_OUTPUT',
expectedOutputSpec: './spec/expected/empty.amd.js',
},
{
binInputParameters: [
'-a',
'-n',
'CustomNamespace.templates',
'spec/artifacts/empty.handlebars',
],
outputLocation: 'stdout',
expectedOutputSpec: './spec/expected/empty.amd.namespace.js',
},
{
binInputParameters: [
'-a',
'--namespace',
'CustomNamespace.templates',
'spec/artifacts/empty.handlebars',
],
outputLocation: 'stdout',
expectedOutputSpec: './spec/expected/empty.amd.namespace.js',
},
{
binInputParameters: ['-a', '-s', 'spec/artifacts/empty.handlebars'],
outputLocation: 'stdout',
expectedOutputSpec: './spec/expected/empty.amd.simple.js',
},
{
binInputParameters: ['-a', '-m', 'spec/artifacts/empty.handlebars'],
outputLocation: 'stdout',
expectedOutputSpec: './spec/expected/empty.amd.min.js',
},
{
binInputParameters: [
'spec/artifacts/known.helpers.handlebars',
'-a',
'-k',
'someHelper',
'-k',
'anotherHelper',
'-o',
],
outputLocation: 'stdout',
expectedOutputSpec: './spec/expected/non.empty.amd.known.helper.js',
},
{
binInputParameters: ['--help'],
outputLocation: 'stdout',
expectedOutputSpec: './spec/expected/help.menu.txt',
},
{
binInputParameters: ['-v'],
outputLocation: 'stdout',
expectedOutput: require('../../lib').VERSION,
},
{
binInputParameters: [
'-a',
'-e',
'hbs',
'./spec/artifacts/non.default.extension.hbs',
],
outputLocation: 'stdout',
expectedOutputSpec: './spec/expected/non.default.extension.amd.js',
},
{
binInputParameters: [
'-a',
'-p',
'./spec/artifacts/partial.template.handlebars',
],
outputLocation: 'stdout',
expectedOutputSpec: './spec/expected/partial.template.js',
},
{
binInputParameters: ['spec/artifacts/empty.handlebars', '-c'],
outputLocation: 'stdout',
expectedOutputSpec: './spec/expected/empty.common.js',
},
{
binInputParameters: [
'spec/artifacts/empty.handlebars',
'spec/artifacts/empty.handlebars',
'-a',
'-n',
'someNameSpace',
],
outputLocation: 'stdout',
expectedOutputSpec: './spec/expected/namespace.amd.js',
},
{
binInputParameters: [
'spec/artifacts/empty.handlebars',
'-h',
'some-path/',
'-a',
],
outputLocation: 'stdout',
expectedOutputSpec: './spec/expected/handlebar.path.amd.js',
},
{
binInputParameters: [
'spec/artifacts/partial.template.handlebars',
'-r',
'spec',
'-a',
],
outputLocation: 'stdout',
expectedOutputSpec: './spec/expected/empty.root.amd.js',
},
{
binInputParameters: [
'-i',
'<div>1</div>',
'-i',
'<div>2</div>',
'-N',
'firstTemplate',
'-N',
'secondTemplate',
'-a',
],
outputLocation: 'stdout',
expectedOutputSpec: './spec/expected/empty.name.amd.js',
},
{
binInputParameters: [
'-i',
'<div>1</div>',
'-a',
'-m',
'-N',
'test',
'--map',
'./spec/tmp/source.map.amd.txt',
],
outputLocation: 'stdout',
expectedOutputSpec: './spec/expected/source.map.amd.js',
},
{
binInputParameters: ['./spec/artifacts/bom.handlebars', '-b', '-a'],
outputLocation: 'stdout',
expectedOutputSpec: './spec/expected/bom.amd.js',
},
// Issue #1673
{
binInputParameters: [
'--amd',
'--no-amd',
'spec/artifacts/empty.handlebars',
],
outputLocation: 'stdout',
expectedOutputSpec: './spec/expected/empty.common.js',
},
];
expect.extend({
toEqualWithRelaxedSpace(received, expected) {
const normalize = (str) =>
typeof str === 'string'
? str
.replace(/\r\n/g, '\n')
.split('\n')
.map((line) => line.replace(/\s+/g, ' ').trim())
.filter((line) => line.length > 0)
.join('\n')
.trim()
: str;
const normalizedReceived = normalize(received);
const normalizedExpected = normalize(expected);
const pass = normalizedReceived === normalizedExpected;
return {
pass,
message: () =>
`Expected output to match with relaxed whitespace.\n\n` +
`Expected:\n${normalizedExpected}\n\nReceived:\n${normalizedReceived}`,
};
},
});
describe('bin/handlebars', function () {
testCases.forEach(
(
{
binInputParameters,
outputLocation,
expectedOutputSpec,
expectedOutput,
},
index
) => {
it(`test case ${index}: handlebars ${binInputParameters.join(
' '
)}`, function () {
const stdout = executeBinHandlebars(...binInputParameters);
if (!expectedOutput && expectedOutputSpec) {
expectedOutput = fs.readFileSync(expectedOutputSpec, 'utf-8');
}
const useStdout = outputLocation === 'stdout';
const actualOutput = useStdout
? stdout
: fs.readFileSync(outputLocation, 'utf-8');
if (!useStdout) {
fs.unlinkSync(outputLocation);
}
expect(actualOutput).toEqualWithRelaxedSpace(expectedOutput);
});
}
);
});
// helper functions
function executeBinHandlebars(...args) {
if (os.platform() === 'win32') {
// On Windows, the executable handlebars.js file cannot be run directly
const nodeJs = process.argv[0];
return execFilesSyncUtf8(nodeJs, ['./bin/handlebars.js'].concat(args));
}
return execFilesSyncUtf8('./bin/handlebars.js', args);
}
function execFilesSyncUtf8(command, args) {
const env = process.env;
env.PATH = addPathToNodeJs(env.PATH);
return childProcess.execFileSync(command, args, { encoding: 'utf-8', env });
}
function addPathToNodeJs(pathEnvironment) {
return path.dirname(process.argv0) + path.delimiter + pathEnvironment;
}
+139 -101
View File
@@ -1,87 +1,128 @@
const fs = require('fs');
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',
],
});
expect.extend({
toEqualWithRelaxedSpace(received, expected) {
const normalize = (str) =>
typeof str === 'string'
? str
.replace(/\r\n/g, '\n')
.split('\n')
.map((line) => line.replace(/\s+/g, ' ').trim())
.filter((line) => line.length > 0)
.join('\n')
.trim()
: str;
const normalizedReceived = normalize(received);
const normalizedExpected = normalize(expected);
const pass = normalizedReceived === normalizedExpected;
return {
pass,
message: () =>
`Expected output to match with relaxed whitespace.\n\n` +
`Expected:\n${normalizedExpected}\n\nReceived:\n${normalizedReceived}`,
};
},
});
it('should display version with -v', async function () {
function expectedFile(specPath) {
return fs.readFileSync(specPath, 'utf-8');
}
describe('bin/handlebars', function () {
describe('help and version', function () {
it('--help displays help menu', async function () {
const result = await execCommand(`${cli} --help`);
expect(result.stdout).toEqualWithRelaxedSpace(
expectedFile('./spec/expected/help.menu.txt')
);
});
it('no arguments displays help menu', async function () {
const result = await execCommand(`${cli}`);
expect(result.stdout).toEqualWithRelaxedSpace(
expectedFile('./spec/expected/help.menu.txt')
);
});
it('-v prints the compiler version', 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 () {
describe('AMD output', function () {
it('-a produces AMD output', 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).toEqualWithRelaxedSpace(
expectedFile('./spec/expected/empty.amd.js')
);
expect(result.stdout).toContain('Handlebars.template');
expect(result.stdout).not.toContain("define(['handlebars.runtime']");
});
it('should precompile in simple mode', async function () {
it('-a -s produces simple AMD output', 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']");
expect(result.stdout).toEqualWithRelaxedSpace(
expectedFile('./spec/expected/empty.amd.simple.js')
);
});
it('should precompile with minification', async function () {
it('-a -m produces minified AMD output', async function () {
const result = await execCommand(
`${cli} -a -m spec/artifacts/empty.handlebars`
);
expect(result.stdout).toContain('define(');
expect(result.stdout).toContain('handlebars.runtime');
expect(result.stdout).toEqualWithRelaxedSpace(
expectedFile('./spec/expected/empty.amd.min.js')
);
});
});
describe('custom namespace', function () {
it('should use custom namespace with -n', async function () {
describe('CommonJS output', function () {
it('-c produces CommonJS output', async function () {
const result = await execCommand(
`${cli} spec/artifacts/empty.handlebars -c`
);
expect(result.stdout).toEqualWithRelaxedSpace(
expectedFile('./spec/expected/empty.common.js')
);
});
});
describe('namespace', function () {
it('-n sets custom namespace', 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');
expect(result.stdout).toEqualWithRelaxedSpace(
expectedFile('./spec/expected/empty.amd.namespace.js')
);
});
it('should use custom namespace with --namespace', async function () {
it('--namespace sets custom namespace', async function () {
const result = await execCommand(
`${cli} -a --namespace CustomNamespace.templates spec/artifacts/empty.handlebars`
);
expect(result.stdout).toContain('CustomNamespace.templates');
expect(result.stdout).toEqualWithRelaxedSpace(
expectedFile('./spec/expected/empty.amd.namespace.js')
);
});
it('multiple files share a namespace', async function () {
const result = await execCommand(
`${cli} spec/artifacts/empty.handlebars spec/artifacts/empty.handlebars -a -n someNameSpace`
);
expect(result.stdout).toEqualWithRelaxedSpace(
expectedFile('./spec/expected/namespace.amd.js')
);
});
});
@@ -97,8 +138,8 @@ describe('bin/handlebars (cli-testlab)', function () {
files.cleanup();
});
it('should write output to a file with -f', async function () {
const outputFile = 'tmp/cli-testlab-output.js';
it('-f writes output to a file', async function () {
const outputFile = 'tmp/cli-test-output.js';
files.registerForCleanup(outputFile);
await execCommand(
@@ -107,21 +148,22 @@ describe('bin/handlebars (cli-testlab)', function () {
expect(files.fileExists(outputFile)).toBe(true);
const content = files.getFileTextContent(outputFile);
expect(content).toContain("define(['handlebars.runtime']");
expect(content).toContain("templates['empty']");
expect(content).toEqualWithRelaxedSpace(
expectedFile('./spec/expected/empty.amd.js')
);
});
it('should generate source map file with --map', async function () {
const mapFile = 'tmp/cli-testlab-source.map';
it('--map writes source map and appends sourceMappingURL', async function () {
const mapFile = 'tmp/cli-test-source.map';
files.registerForCleanup(mapFile);
await execCommand(
const result = await execCommand(
`${cli} -i "<div>1</div>" -a -m -N test --map ${mapFile}`
);
expect(result.stdout).toContain('sourceMappingURL=');
expect(files.fileExists(mapFile)).toBe(true);
const mapContent = files.getFileTextContent(mapFile);
const parsed = JSON.parse(mapContent);
const parsed = JSON.parse(files.getFileTextContent(mapFile));
expect(parsed).toHaveProperty('version', 3);
expect(parsed).toHaveProperty('sources');
expect(parsed).toHaveProperty('mappings');
@@ -129,39 +171,63 @@ describe('bin/handlebars (cli-testlab)', function () {
});
describe('template options', function () {
it('should support custom extension with -e', async function () {
it('-e sets custom extension', 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']");
expect(result.stdout).toEqualWithRelaxedSpace(
expectedFile('./spec/expected/non.default.extension.amd.js')
);
});
it('should compile as partial with -p', async function () {
it('-p compiles as partial', async function () {
const result = await execCommand(
`${cli} -a -p ./spec/artifacts/partial.template.handlebars`
);
expect(result.stdout).toContain('Handlebars.partials');
expect(result.stdout).toEqualWithRelaxedSpace(
expectedFile('./spec/expected/partial.template.js')
);
});
it('should strip root from template names with -r', async function () {
it('-r strips root from template names', async function () {
const result = await execCommand(
`${cli} spec/artifacts/partial.template.handlebars -r spec -a`
);
expect(result.stdout).not.toContain("templates['spec/");
expect(result.stdout).toEqualWithRelaxedSpace(
expectedFile('./spec/expected/empty.root.amd.js')
);
});
it('should strip BOM with -b', async function () {
it('-b strips BOM', 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']");
expect(result.stdout).toEqualWithRelaxedSpace(
expectedFile('./spec/expected/bom.amd.js')
);
});
it('-h sets custom handlebar path', async function () {
const result = await execCommand(
`${cli} spec/artifacts/empty.handlebars -h some-path/ -a`
);
expect(result.stdout).toEqualWithRelaxedSpace(
expectedFile('./spec/expected/handlebar.path.amd.js')
);
});
it('-k -o sets known helpers only', async function () {
const result = await execCommand(
`${cli} spec/artifacts/known.helpers.handlebars -a -k someHelper -k anotherHelper -o`
);
expect(result.stdout).toEqualWithRelaxedSpace(
expectedFile('./spec/expected/non.empty.amd.known.helper.js')
);
});
});
describe('inline templates', function () {
it('should compile inline template with -i', async function () {
it('-i compiles inline template', async function () {
const result = await execCommand(
`${cli} -i "<div>hello</div>" -a -N myTemplate`
);
@@ -169,52 +235,24 @@ describe('bin/handlebars (cli-testlab)', function () {
expect(result.stdout).toContain("templates['myTemplate']");
});
it('should compile multiple inline templates', async function () {
it('-i compiles multiple inline templates with -N', async function () {
const result = await execCommand(
`${cli} -i "<div>1</div>" -i "<div>2</div>" -N first -N second -a`
`${cli} -i "<div>1</div>" -i "<div>2</div>" -N firstTemplate -N secondTemplate -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']"
expect(result.stdout).toEqualWithRelaxedSpace(
expectedFile('./spec/expected/empty.name.amd.js')
);
});
});
describe('negated boolean flags', function () {
it('should support --no-amd to negate --amd (issue #1673)', async function () {
it('--no-amd negates --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).toEqualWithRelaxedSpace(
expectedFile('./spec/expected/empty.common.js')
);
expect(result.stdout).toContain('someNameSpace');
expect(result.stdout).toContain("define(['handlebars.runtime']");
});
});
});
+4
View File
@@ -0,0 +1,4 @@
{
"testFileMatch": ["types/__typetests__/**/*.tst.ts"],
"tsconfig": "./types/tsconfig.json"
}
+645
View File
@@ -0,0 +1,645 @@
import { expect, test, describe } from 'tstyche';
import Handlebars from 'handlebars';
import {
HandlebarsTemplatable,
HandlebarsTemplateDelegate,
HandlebarsTemplates,
TemplateSpecification,
CompileOptions,
PrecompileOptions,
RuntimeOptions,
KnownHelpers,
BuiltinHelperName,
CustomHelperName,
Logger,
CompilerInfo,
hbs,
} from 'handlebars';
// ---------------------------------------------------------------------------
// Handlebars.compile
// ---------------------------------------------------------------------------
describe('Handlebars.compile', () => {
test('returns a HandlebarsTemplateDelegate', () => {
expect(Handlebars.compile('{{name}}')).type.toBe<
HandlebarsTemplateDelegate<any>
>();
});
test('returns a typed delegate when generic is specified', () => {
expect(Handlebars.compile<{ name: string }>('{{name}}')).type.toBe<
HandlebarsTemplateDelegate<{ name: string }>
>();
});
test('compiled template returns string', () => {
const template = Handlebars.compile('{{name}}');
expect(template({})).type.toBe<string>();
});
test('accepts CompileOptions', () => {
expect(
Handlebars.compile('test', { strict: true, noEscape: true })
).type.not.toRaiseError();
});
test('accepts knownHelpers with built-in and custom names', () => {
expect(
Handlebars.compile('test', {
knownHelpers: { each: true, customHelper: true },
})
).type.not.toRaiseError();
});
});
// ---------------------------------------------------------------------------
// Handlebars.precompile
// ---------------------------------------------------------------------------
describe('Handlebars.precompile', () => {
test('returns TemplateSpecification', () => {
expect(
Handlebars.precompile('{{name}}')
).type.toBe<TemplateSpecification>();
});
test('accepts PrecompileOptions', () => {
expect(
Handlebars.precompile('test', { srcName: 'a.hbs', destName: 'a.js' })
).type.not.toRaiseError();
});
});
// ---------------------------------------------------------------------------
// Handlebars.template
// ---------------------------------------------------------------------------
describe('Handlebars.template', () => {
test('returns HandlebarsTemplateDelegate', () => {
const spec = {} as TemplateSpecification;
expect(Handlebars.template(spec)).type.toBe<
HandlebarsTemplateDelegate<any>
>();
});
});
// ---------------------------------------------------------------------------
// Handlebars.registerHelper / unregisterHelper
// ---------------------------------------------------------------------------
describe('Handlebars.registerHelper', () => {
test('accepts name and function', () => {
expect(
Handlebars.registerHelper('myHelper', (ctx: any) => 'result')
).type.toBe<void>();
});
test('accepts a spec object', () => {
expect(
Handlebars.registerHelper({ myHelper: () => 'result' })
).type.toBe<void>();
});
});
describe('Handlebars.unregisterHelper', () => {
test('accepts a name', () => {
expect(Handlebars.unregisterHelper('myHelper')).type.toBe<void>();
});
});
// ---------------------------------------------------------------------------
// Handlebars.registerPartial / unregisterPartial
// ---------------------------------------------------------------------------
describe('Handlebars.registerPartial', () => {
test('accepts name and string', () => {
expect(
Handlebars.registerPartial('myPartial', '<div>{{name}}</div>')
).type.toBe<void>();
});
test('accepts spec object', () => {
expect(
Handlebars.registerPartial({ myPartial: '<div>{{name}}</div>' })
).type.toBe<void>();
});
});
describe('Handlebars.unregisterPartial', () => {
test('accepts a name', () => {
expect(Handlebars.unregisterPartial('myPartial')).type.toBe<void>();
});
});
// ---------------------------------------------------------------------------
// Handlebars.registerDecorator / unregisterDecorator
// ---------------------------------------------------------------------------
describe('Handlebars.registerDecorator', () => {
test('accepts name and function', () => {
expect(
Handlebars.registerDecorator('myDecorator', () => {})
).type.toBe<void>();
});
});
describe('Handlebars.unregisterDecorator', () => {
test('accepts a name', () => {
expect(Handlebars.unregisterDecorator('myDecorator')).type.toBe<void>();
});
});
// ---------------------------------------------------------------------------
// Handlebars utility functions
// ---------------------------------------------------------------------------
describe('Handlebars utility functions', () => {
test('K returns void', () => {
expect(Handlebars.K()).type.toBe<void>();
});
test('createFrame returns any', () => {
expect(Handlebars.createFrame({})).type.toBe<any>();
});
test('blockParams returns any[]', () => {
expect(Handlebars.blockParams([], [])).type.toBe<any[]>();
});
test('log returns void', () => {
expect(Handlebars.log(1, 'message')).type.toBe<void>();
});
test('noConflict returns typeof Handlebars', () => {
expect(Handlebars.noConflict()).type.toBe<typeof Handlebars>();
});
test('escapeExpression is exported at top level', () => {
expect(Handlebars.escapeExpression('test')).type.toBe<string>();
});
});
// ---------------------------------------------------------------------------
// Handlebars.HelperOptions
// ---------------------------------------------------------------------------
describe('Handlebars.HelperOptions', () => {
test('fn and inverse are callable TemplateDelegates', () => {
const options = {} as Handlebars.HelperOptions;
expect(options.fn({})).type.toBe<string>();
expect(options.inverse({})).type.toBe<string>();
});
test('hash is a Record', () => {
const options = {} as Handlebars.HelperOptions;
expect(options.hash).type.toBe<Record<string, any>>();
});
});
// ---------------------------------------------------------------------------
// Handlebars.SafeString
// ---------------------------------------------------------------------------
describe('Handlebars.SafeString', () => {
test('is constructable with string', () => {
expect(
new Handlebars.SafeString('<b>bold</b>')
).type.toBe<Handlebars.SafeString>();
});
test('toString returns string', () => {
const safe = new Handlebars.SafeString('test');
expect(safe.toString()).type.toBe<string>();
});
test('toHTML returns string', () => {
const safe = new Handlebars.SafeString('test');
expect(safe.toHTML()).type.toBe<string>();
});
});
// ---------------------------------------------------------------------------
// Handlebars.Exception
// ---------------------------------------------------------------------------
describe('Handlebars.Exception', () => {
test('is constructable with message only', () => {
expect(new Handlebars.Exception('error')).type.toBe<Handlebars.Exception>();
});
test('is constructable with message and node', () => {
expect(
new Handlebars.Exception('error', {
type: 'MustacheStatement',
loc: {
source: 'source',
start: { line: 1, column: 0 },
end: { line: 1, column: 10 },
},
})
).type.not.toRaiseError();
});
test('has all expected fields', () => {
const ex = new Handlebars.Exception('msg');
expect(ex.message).type.toBe<string>();
expect(ex.name).type.toBe<string>();
expect(ex.description).type.toBe<string>();
expect(ex.fileName).type.toBe<string>();
expect(ex.number).type.toBe<number>();
expect(ex.lineNumber).type.toBe<any>();
expect(ex.endLineNumber).type.toBe<any>();
expect(ex.column).type.toBe<any>();
expect(ex.endColumn).type.toBe<any>();
expect(ex.stack).type.toBe<string | undefined>();
});
});
// ---------------------------------------------------------------------------
// Handlebars.Utils
// ---------------------------------------------------------------------------
describe('Handlebars.Utils', () => {
test('escapeExpression returns string', () => {
expect(Handlebars.Utils.escapeExpression('<script>')).type.toBe<string>();
});
test('createFrame returns any', () => {
expect(Handlebars.Utils.createFrame({})).type.toBe<any>();
});
test('blockParams returns any[]', () => {
expect(Handlebars.Utils.blockParams([], [])).type.toBe<any[]>();
});
test('isEmpty returns boolean', () => {
expect(Handlebars.Utils.isEmpty(null)).type.toBe<boolean>();
});
test('extend returns any', () => {
expect(Handlebars.Utils.extend({}, {})).type.toBe<any>();
});
test('toString returns string', () => {
expect(Handlebars.Utils.toString(42)).type.toBe<string>();
});
test('isArray returns boolean', () => {
expect(Handlebars.Utils.isArray([])).type.toBe<boolean>();
});
test('isFunction returns boolean', () => {
expect(Handlebars.Utils.isFunction(() => {})).type.toBe<boolean>();
});
test('isMap returns boolean', () => {
expect(Handlebars.Utils.isMap(new Map())).type.toBe<boolean>();
});
test('isSet returns boolean', () => {
expect(Handlebars.Utils.isSet(new Set())).type.toBe<boolean>();
});
});
// ---------------------------------------------------------------------------
// Handlebars namespace constants
// ---------------------------------------------------------------------------
describe('Handlebars constants', () => {
test('VERSION is string', () => {
expect(Handlebars.VERSION).type.toBe<string>();
});
test('helpers is a record of HelperDelegate', () => {
expect(Handlebars.helpers).type.toBe<{
[name: string]: Handlebars.HelperDelegate;
}>();
});
test('templates is HandlebarsTemplates', () => {
expect(Handlebars.templates).type.toBe<HandlebarsTemplates>();
});
test('partials is a record', () => {
expect(Handlebars.partials).type.toBe<{ [name: string]: any }>();
});
test('decorators is a record', () => {
expect(Handlebars.decorators).type.toBe<{ [name: string]: Function }>();
});
test('logger is Logger', () => {
expect(Handlebars.logger).type.toBe<Logger>();
});
});
// ---------------------------------------------------------------------------
// Handlebars.create
// ---------------------------------------------------------------------------
describe('Handlebars.create', () => {
test('returns typeof Handlebars', () => {
expect(Handlebars.create()).type.toBe<typeof Handlebars>();
});
});
// ---------------------------------------------------------------------------
// Handlebars.parse / parseWithoutProcessing
// ---------------------------------------------------------------------------
describe('Handlebars.parse', () => {
test('works without options', () => {
expect(Handlebars.parse('{{name}}')).type.not.toRaiseError();
});
test('accepts ParseOptions', () => {
expect(
Handlebars.parse('{{name}}', { srcName: 'test.hbs' })
).type.not.toRaiseError();
});
});
describe('Handlebars.parseWithoutProcessing', () => {
test('returns AST.Program', () => {
expect(
Handlebars.parseWithoutProcessing('{{name}}')
).type.not.toRaiseError();
});
});
// ---------------------------------------------------------------------------
// RuntimeOptions
// ---------------------------------------------------------------------------
describe('RuntimeOptions', () => {
test('compiled template accepts all RuntimeOptions fields', () => {
const template = Handlebars.compile('test');
expect(
template(
{},
{
partial: true,
depths: [{}],
helpers: { myHelper: () => '' },
partials: { link: '<a>{{name}}</a>' },
decorators: { myDec: () => {} },
data: { root: {} },
blockParams: [[]],
allowCallsToHelperMissing: true,
allowedProtoMethods: { foo: true },
allowedProtoProperties: { bar: false },
allowProtoMethodsByDefault: true,
allowProtoPropertiesByDefault: false,
}
)
).type.toBe<string>();
});
test('empty options object is valid', () => {
const template = Handlebars.compile('test');
expect(template({}, {})).type.toBe<string>();
});
});
// ---------------------------------------------------------------------------
// CompileOptions
// ---------------------------------------------------------------------------
describe('CompileOptions', () => {
test('accepts all fields', () => {
expect(
Handlebars.compile('test', {
data: true,
compat: true,
knownHelpers: { each: true },
knownHelpersOnly: true,
noEscape: true,
strict: true,
assumeObjects: true,
preventIndent: true,
ignoreStandalone: true,
explicitPartialContext: true,
})
).type.not.toRaiseError();
});
});
// ---------------------------------------------------------------------------
// HandlebarsTemplateDelegate generic
// ---------------------------------------------------------------------------
describe('HandlebarsTemplateDelegate generic', () => {
test('enforces context type', () => {
const template: HandlebarsTemplateDelegate<{ name: string }> =
Handlebars.compile<{ name: string }>('{{name}}');
expect(template({ name: 'test' })).type.toBe<string>();
});
});
// ---------------------------------------------------------------------------
// Handlebars.VM.resolvePartial
// ---------------------------------------------------------------------------
describe('Handlebars.VM.resolvePartial', () => {
test('accepts expected parameters and returns HandlebarsTemplateDelegate', () => {
const partial = {} as HandlebarsTemplateDelegate | undefined;
const context = {};
const options = {} as Handlebars.ResolvePartialOptions;
expect(Handlebars.VM.resolvePartial(partial, context, options)).type.toBe<
HandlebarsTemplateDelegate<any>
>();
});
test('ResolvePartialOptions has expected fields', () => {
const options = {} as Handlebars.ResolvePartialOptions;
expect(options.name).type.toBe<string>();
expect(options.helpers).type.toBe<
{ [name: string]: Function } | undefined
>();
expect(options.partials).type.toBe<
{ [name: string]: HandlebarsTemplateDelegate } | undefined
>();
expect(options.decorators).type.toBe<
{ [name: string]: Function } | undefined
>();
expect(options.data).type.toBe<any>();
});
});
// ---------------------------------------------------------------------------
// ICompiler interface
// ---------------------------------------------------------------------------
describe('Handlebars.ICompiler', () => {
test('has all visitor methods', () => {
const compiler = {} as Handlebars.ICompiler;
expect(compiler.accept).type.not.toRaiseError();
expect(compiler.Program).type.not.toRaiseError();
expect(compiler.BlockStatement).type.not.toRaiseError();
expect(compiler.PartialStatement).type.not.toRaiseError();
expect(compiler.PartialBlockStatement).type.not.toRaiseError();
expect(compiler.DecoratorBlock).type.not.toRaiseError();
expect(compiler.Decorator).type.not.toRaiseError();
expect(compiler.MustacheStatement).type.not.toRaiseError();
expect(compiler.ContentStatement).type.not.toRaiseError();
expect(compiler.CommentStatement).type.not.toRaiseError();
expect(compiler.SubExpression).type.not.toRaiseError();
expect(compiler.PathExpression).type.not.toRaiseError();
expect(compiler.StringLiteral).type.not.toRaiseError();
expect(compiler.NumberLiteral).type.not.toRaiseError();
expect(compiler.BooleanLiteral).type.not.toRaiseError();
expect(compiler.UndefinedLiteral).type.not.toRaiseError();
expect(compiler.NullLiteral).type.not.toRaiseError();
expect(compiler.Hash).type.not.toRaiseError();
});
});
// ---------------------------------------------------------------------------
// Visitor class
// ---------------------------------------------------------------------------
describe('Handlebars.Visitor', () => {
test('implements ICompiler', () => {
expect<Handlebars.Visitor>().type.toBeAssignableTo<Handlebars.ICompiler>();
});
test('has acceptKey and acceptArray methods', () => {
const visitor = new Handlebars.Visitor();
expect(visitor.acceptKey).type.not.toRaiseError();
expect(visitor.acceptArray).type.not.toRaiseError();
});
});
// ---------------------------------------------------------------------------
// Logger interface
// ---------------------------------------------------------------------------
describe('Logger', () => {
test('has log level constants', () => {
const logger = {} as Logger;
expect(logger.DEBUG).type.toBe<number>();
expect(logger.INFO).type.toBe<number>();
expect(logger.WARN).type.toBe<number>();
expect(logger.ERROR).type.toBe<number>();
expect(logger.level).type.toBe<number>();
});
test('has methodMap and log', () => {
const logger = {} as Logger;
expect(logger.methodMap).type.toBe<{ [level: number]: string }>();
expect(logger.log(0, 'msg')).type.toBe<void>();
});
});
// ---------------------------------------------------------------------------
// Top-level exported types
// ---------------------------------------------------------------------------
describe('top-level exports', () => {
test('HandlebarsTemplatable has template field', () => {
const view = {} as HandlebarsTemplatable;
expect(view.template).type.toBe<HandlebarsTemplateDelegate>();
});
test('CompilerInfo is a tuple', () => {
expect<CompilerInfo>().type.toBe<[number, string]>();
});
test('BuiltinHelperName is a string union', () => {
expect<BuiltinHelperName>().type.toBe<
| 'helperMissing'
| 'blockHelperMissing'
| 'each'
| 'if'
| 'unless'
| 'with'
| 'log'
| 'lookup'
>();
});
test('CustomHelperName is string', () => {
expect<CustomHelperName>().type.toBe<string>();
});
test('KnownHelpers uses BuiltinHelperName and CustomHelperName', () => {
const helpers: KnownHelpers = { each: true, myCustom: true };
expect(helpers).type.not.toRaiseError();
});
});
// ---------------------------------------------------------------------------
// hbs namespace
// ---------------------------------------------------------------------------
describe('hbs namespace', () => {
test('hbs.SafeString aliases Handlebars.SafeString', () => {
expect<hbs.SafeString>().type.toBe<Handlebars.SafeString>();
});
test('hbs.Utils aliases typeof Handlebars.Utils', () => {
expect<hbs.Utils>().type.toBe<typeof Handlebars.Utils>();
});
test('AST types are accessible', () => {
const node = {} as hbs.AST.MustacheStatement;
expect(node.type).type.not.toRaiseError();
});
});
// ---------------------------------------------------------------------------
// Handlebars.AST
// ---------------------------------------------------------------------------
describe('Handlebars.AST', () => {
test('helpers is accessible', () => {
expect(Handlebars.AST.helpers).type.not.toRaiseError();
});
});
// ---------------------------------------------------------------------------
// AST discriminated union
// ---------------------------------------------------------------------------
describe('AST discriminated union', () => {
test('type field narrows AST node types', () => {
const node = {} as
| hbs.AST.MustacheStatement
| hbs.AST.BlockStatement
| hbs.AST.PartialStatement
| hbs.AST.PartialBlockStatement
| hbs.AST.ContentStatement
| hbs.AST.CommentStatement
| hbs.AST.SubExpression
| hbs.AST.PathExpression
| hbs.AST.StringLiteral
| hbs.AST.BooleanLiteral
| hbs.AST.NumberLiteral
| hbs.AST.UndefinedLiteral
| hbs.AST.NullLiteral
| hbs.AST.Hash
| hbs.AST.HashPair;
if (node.type === 'MustacheStatement') {
expect(node).type.toBe<hbs.AST.MustacheStatement>();
}
if (node.type === 'BlockStatement') {
expect(node).type.toBe<hbs.AST.BlockStatement>();
}
if (node.type === 'PartialStatement') {
expect(node).type.toBe<hbs.AST.PartialStatement>();
}
if (node.type === 'PartialBlockStatement') {
expect(node).type.toBe<hbs.AST.PartialBlockStatement>();
}
if (node.type === 'ContentStatement') {
expect(node).type.toBe<hbs.AST.ContentStatement>();
}
if (node.type === 'CommentStatement') {
expect(node).type.toBe<hbs.AST.CommentStatement>();
}
if (node.type === 'SubExpression') {
expect(node).type.toBe<hbs.AST.SubExpression>();
}
if (node.type === 'PathExpression') {
expect(node).type.toBe<hbs.AST.PathExpression>();
}
if (node.type === 'StringLiteral') {
expect(node).type.toBe<hbs.AST.StringLiteral>();
}
if (node.type === 'BooleanLiteral') {
expect(node).type.toBe<hbs.AST.BooleanLiteral>();
}
if (node.type === 'NumberLiteral') {
expect(node).type.toBe<hbs.AST.NumberLiteral>();
}
if (node.type === 'UndefinedLiteral') {
expect(node).type.toBe<hbs.AST.UndefinedLiteral>();
}
if (node.type === 'NullLiteral') {
expect(node).type.toBe<hbs.AST.NullLiteral>();
}
if (node.type === 'Hash') {
expect(node).type.toBe<hbs.AST.Hash>();
}
if (node.type === 'HashPair') {
expect(node).type.toBe<hbs.AST.HashPair>();
}
});
});
-298
View File
@@ -1,298 +0,0 @@
/* These test cases were imported from https://github.com/DefinitelyTyped/DefinitelyTyped
* and includes previous contributions from the DefinitelyTyped community.
* For full history prior to their migration to handlebars.js, please see:
* https://github.com/DefinitelyTyped/DefinitelyTyped/commits/1ce60bdc07f10e0b076778c6c953271c072bc894/types/handlebars/handlebars-tests.ts
*/
import Handlebars from 'handlebars';
import { HandlebarsTemplateDelegate, hbs } from 'handlebars';
const context = {
author: { firstName: 'Alan', lastName: 'Johnson' },
body: 'I Love Handlebars',
comments: [
{
author: { firstName: 'Yehuda', lastName: 'Katz' },
body: 'Me too!',
},
],
};
Handlebars.registerHelper('fullName', (person: typeof context.author) => {
return person.firstName + ' ' + person.lastName;
});
Handlebars.registerHelper('agree_button', function (this: any) {
return new Handlebars.SafeString(
'<button>I agree. I ' + this.emotion + ' ' + this.name + '</button>'
);
});
const source1 =
'<p>Hello, my name is {{name}}. I am from {{hometown}}. I have ' +
'{{kids.length}} kids:</p>' +
'<ul>{{#kids}}<li>{{name}} is {{age}}</li>{{/kids}}</ul>';
const template1 = Handlebars.compile(source1);
template1({
name: 'Alan',
hometown: 'Somewhere, TX',
kids: [
{ name: 'Jimmy', age: 12 },
{ name: 'Sally', age: 4 },
],
});
Handlebars.registerHelper('link_to', (context: typeof post) => {
return '<a href="' + context.url + '">' + context.body + '</a>';
});
const post = { url: '/hello-world', body: 'Hello World!' };
const context2 = { posts: [post] };
const source2 = '<ul>{{#posts}}<li>{{{link_to this}}}</li>{{/posts}}</ul>';
const template2: HandlebarsTemplateDelegate<{
posts: { url: string; body: string }[];
}> = Handlebars.compile(source2);
template2(context2);
Handlebars.registerHelper('link_to', (title: string, context: typeof post) => {
return '<a href="/posts' + context.url + '">' + title + '!</a>';
});
const context3 = { posts: [{ url: '/hello-world', body: 'Hello World!' }] };
const source3 =
'<ul>{{#posts}}<li>{{{link_to "Post" this}}}</li>{{/posts}}</ul>';
const template3 = Handlebars.compile<typeof context3>(source3);
template3(context3);
const source4 =
'<ul>{{#people}}<li>{{#link}}{{name}}{{/link}}</li>{{/people}}</ul>';
Handlebars.registerHelper('link', function (this: any, context: any) {
return '<a href="/people/' + this.id + '">' + context.fn(this) + '</a>';
});
const template4 = Handlebars.compile<{
people: { name: string; id: number }[];
}>(source4);
const data2 = {
people: [
{ name: 'Alan', id: 1 },
{ name: 'Yehuda', id: 2 },
],
};
template4(data2);
const source5 = '<ul>{{#people}}<li>{{> link}}</li>{{/people}}</ul>';
Handlebars.registerPartial('link', '<a href="/people/{{id}}">{{name}}</a>');
const template5 = Handlebars.compile(source5);
const data3 = {
people: [
{ name: 'Alan', id: 1 },
{ name: 'Yehuda', id: 2 },
],
};
template5(data3);
const source6 = '{{#list nav}}<a href="{{url}}">{{title}}</a>{{/list}}';
const template6 = Handlebars.compile(source6);
Handlebars.registerHelper(
'list',
(context, options: Handlebars.HelperOptions) => {
let ret = '<ul>';
for (let i = 0, j = context.length; i < j; i++) {
ret = ret + '<li>' + options.fn(context[i]) + '</li>';
}
return ret + '</ul>';
}
);
template6([{ url: '', title: '' }]);
const escapedExpression = Handlebars.Utils.escapeExpression(
"<script>alert('xss');</script>"
);
Handlebars.helpers !== undefined;
const parsedTmpl = Handlebars.parse('<p>Hello, my name is {{name}}.</p>', {
srcName: '/foo/bar/baz.hbs',
ignoreStandalone: true,
});
const parsedTmplWithoutOptions = Handlebars.parse(
'<p>Hello, my name is {{name}}.</p>'
);
// Custom partial resolution.
const originalResolvePartial = Handlebars.VM.resolvePartial;
Handlebars.VM.resolvePartial = <T>(
partial: HandlebarsTemplateDelegate<T> | undefined,
context: any,
options: Handlebars.ResolvePartialOptions
): HandlebarsTemplateDelegate<T> => {
const name = options.name.replace(/my/, 'your');
// transform name.
options.name = name;
return originalResolvePartial(partial, context, options);
};
// #1544, allow custom helpers in knownHelpers
Handlebars.compile('test', {
knownHelpers: {
each: true,
customHelper: true,
},
});
Handlebars.compile('test')({}, { allowCallsToHelperMissing: true });
Handlebars.compile('test')({}, {});
const allthings = {} as
| hbs.AST.MustacheStatement
| hbs.AST.BlockStatement
| hbs.AST.PartialStatement
| hbs.AST.PartialBlockStatement
| hbs.AST.ContentStatement
| hbs.AST.CommentStatement
| hbs.AST.SubExpression
| hbs.AST.PathExpression
| hbs.AST.StringLiteral
| hbs.AST.BooleanLiteral
| hbs.AST.NumberLiteral
| hbs.AST.UndefinedLiteral
| hbs.AST.NullLiteral
| hbs.AST.Hash
| hbs.AST.HashPair;
switch (allthings.type) {
case 'MustacheStatement':
let mustacheStatement: hbs.AST.MustacheStatement;
mustacheStatement = allthings;
break;
case 'BlockStatement':
let blockStatement: hbs.AST.BlockStatement;
blockStatement = allthings;
break;
case 'PartialStatement':
let partialStatement: hbs.AST.PartialStatement;
partialStatement = allthings;
break;
case 'PartialBlockStatement':
let partialBlockStatement: hbs.AST.PartialBlockStatement;
partialBlockStatement = allthings;
break;
case 'ContentStatement':
let ContentStatement: hbs.AST.ContentStatement;
ContentStatement = allthings;
break;
case 'CommentStatement':
let CommentStatement: hbs.AST.CommentStatement;
CommentStatement = allthings;
break;
case 'SubExpression':
let SubExpression: hbs.AST.SubExpression;
SubExpression = allthings;
break;
case 'PathExpression':
let PathExpression: hbs.AST.PathExpression;
PathExpression = allthings;
break;
case 'StringLiteral':
let StringLiteral: hbs.AST.StringLiteral;
StringLiteral = allthings;
break;
case 'BooleanLiteral':
let BooleanLiteral: hbs.AST.BooleanLiteral;
BooleanLiteral = allthings;
break;
case 'NumberLiteral':
let NumberLiteral: hbs.AST.NumberLiteral;
NumberLiteral = allthings;
break;
case 'UndefinedLiteral':
let UndefinedLiteral: hbs.AST.UndefinedLiteral;
UndefinedLiteral = allthings;
break;
case 'NullLiteral':
let NullLiteral: hbs.AST.NullLiteral;
NullLiteral = allthings;
break;
case 'Hash':
let Hash: hbs.AST.Hash;
Hash = allthings;
break;
case 'HashPair':
let HashPair: hbs.AST.HashPair;
HashPair = allthings;
break;
default:
break;
}
function testParseWithoutProcessing() {
const parsedTemplate: hbs.AST.Program = Handlebars.parseWithoutProcessing(
'<p>Hello, my name is {{name}}.</p>',
{
srcName: '/foo/bar/baz.hbs',
}
);
const parsedTemplateWithoutOptions: hbs.AST.Program =
Handlebars.parseWithoutProcessing('<p>Hello, my name is {{name}}.</p>');
}
function testExceptionTypings() {
// Test exception constructor with a single argument - message.
let exception: Handlebars.Exception = new Handlebars.Exception('message');
// Fields
let message: string = exception.message;
let lineNumber: number = exception.lineNumber;
let column: number = exception.column;
let endLineNumber: number = exception.endLineNumber;
let endColumn: number = exception.endColumn;
let description = exception.description;
let name: string = exception.name;
let fileName: string = exception.fileName;
let stack: string | undefined = exception.stack;
}
function testExceptionWithNodeTypings() {
// Test exception constructor with both arguments.
const exception: Handlebars.Exception = new Handlebars.Exception('message', {
type: 'MustacheStatement',
loc: {
source: 'source',
start: { line: 1, column: 5 },
end: { line: 10, column: 2 },
},
});
// Fields
let message: string = exception.message;
let lineNumber: number = exception.lineNumber;
let column: number = exception.column;
let endLineNumber: number = exception.endLineNumber;
let endColumn: number = exception.endColumn;
let description = exception.description;
let name: string = exception.name;
let fileName: string = exception.fileName;
let stack: string | undefined = exception.stack;
}
function testProtoAccessControlControlOptions() {
Handlebars.compile('test')(
{},
{
allowedProtoMethods: { allowedMethod: true, forbiddenMethod: false },
allowedProtoProperties: {
allowedProperty: true,
forbiddenProperty: false,
},
allowProtoMethodsByDefault: true,
allowProtoPropertiesByDefault: false,
partials: {
link: '<a href="/people/{{id}}">{{name}}</a>',
},
}
);
}
function testHandlebarsVersion() {
let version: string = Handlebars.VERSION;
}