Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5fd0d7cd2b | |||
| 3105ca73c1 | |||
| 0e1d35582a |
+1
-1
@@ -116,7 +116,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": ["tests/bench/**/*.mjs"],
|
||||
"files": ["tests/bench/**/*.js"],
|
||||
"rules": {
|
||||
"no-console": "off"
|
||||
}
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"$schema": "https://swc.rs/schema.json",
|
||||
"module": {
|
||||
"type": "commonjs",
|
||||
"importInterop": "swc"
|
||||
},
|
||||
"sourceMaps": "inline"
|
||||
}
|
||||
@@ -1,11 +1,8 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import { createRequire } from 'node:module';
|
||||
import { loadTemplates, cli } from '../lib/precompiler.js';
|
||||
import yargs from 'yargs';
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
const Precompiler = require('../dist/cjs/precompiler');
|
||||
|
||||
const parser = yargs(process.argv.slice(2))
|
||||
.usage('Precompile handlebar templates.\nUsage: $0 [template|directory]...')
|
||||
.help(false)
|
||||
@@ -19,23 +16,6 @@ const parser = yargs(process.argv.slice(2))
|
||||
type: 'string',
|
||||
description: 'Source Map File',
|
||||
})
|
||||
.option('a', {
|
||||
type: 'boolean',
|
||||
description: 'Exports amd style (require.js)',
|
||||
alias: 'amd',
|
||||
})
|
||||
.option('c', {
|
||||
type: 'string',
|
||||
description: 'Exports CommonJS style, path to Handlebars module',
|
||||
alias: 'commonjs',
|
||||
default: null,
|
||||
})
|
||||
.option('h', {
|
||||
type: 'string',
|
||||
description: 'Path to handlebar.js (only valid for amd-style)',
|
||||
alias: 'handlebarPath',
|
||||
default: '',
|
||||
})
|
||||
.option('k', {
|
||||
type: 'string',
|
||||
description: 'Known helpers',
|
||||
@@ -117,7 +97,7 @@ const argv = parser.parseSync();
|
||||
argv.files = argv._;
|
||||
delete argv._;
|
||||
|
||||
Precompiler.loadTemplates(argv, function (err, opts) {
|
||||
loadTemplates(argv, function (err, opts) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
@@ -127,7 +107,7 @@ Precompiler.loadTemplates(argv, function (err, opts) {
|
||||
} else {
|
||||
// cli() is async (returns a Promise), so errors would become unhandled
|
||||
// rejections. Re-throw via nextTick to surface them as uncaught exceptions.
|
||||
Promise.resolve(Precompiler.cli(opts)).catch((error) => {
|
||||
Promise.resolve(cli(opts)).catch((error) => {
|
||||
process.nextTick(() => {
|
||||
throw error;
|
||||
});
|
||||
@@ -0,0 +1,127 @@
|
||||
import Handlebars from './lib/index.js';
|
||||
import fs from 'fs';
|
||||
|
||||
// Read the basic.js test file and extract test cases
|
||||
// For now, manually define a set of representative test cases
|
||||
const tests = [];
|
||||
|
||||
function T(template, input, expected, opts) {
|
||||
tests.push({
|
||||
template,
|
||||
input: input ?? {},
|
||||
expected,
|
||||
compileOpts: opts?.compile ?? {},
|
||||
runtimeOpts: opts?.runtime ?? {},
|
||||
});
|
||||
}
|
||||
|
||||
// ============ basic.js equivalents ============
|
||||
const g = (t, i, e, co, ro) => T(t, i, e, { compile: co, runtime: ro });
|
||||
|
||||
g('{{foo}}', { foo: 'foo' }, 'foo');
|
||||
g('\\{{foo}}', { foo: 'food' }, '{{foo}}');
|
||||
g('content \\{{foo}}', { foo: 'food' }, 'content {{foo}}');
|
||||
g('\\\\{{foo}}', { foo: 'food' }, '\\food');
|
||||
g('\\\\ {{foo}}', { foo: 'food' }, '\\\\ food');
|
||||
g(
|
||||
'Goodbye\n{{cruel}}\n{{world}}!',
|
||||
{ cruel: 'cruel', world: 'world' },
|
||||
'Goodbye\ncruel\nworld!'
|
||||
);
|
||||
g('{{.}}{{length}}', 'bye', 'bye3');
|
||||
g('Goodbye\n{{cruel}}\n{{world.bar}}!', undefined, 'Goodbye\n\n!');
|
||||
g(
|
||||
'{{! Goodbye}}Goodbye\n{{cruel}}\n{{world}}!',
|
||||
{ cruel: 'cruel', world: 'world' },
|
||||
'Goodbye\ncruel\nworld!'
|
||||
);
|
||||
g(' {{~! comment ~}} blah', {}, 'blah');
|
||||
g(' {{~!-- long-comment --~}} blah', {}, 'blah');
|
||||
g(' {{! comment ~}} blah', {}, ' blah');
|
||||
g(' {{~! comment}} blah', {}, ' blah');
|
||||
g('{{#if foo}}foo{{/if}}', { foo: true }, 'foo');
|
||||
g('{{#if foo}}foo{{else}}bar{{/if}}', { foo: false }, 'bar');
|
||||
g('{{#unless foo}}bar{{/unless}}', { foo: false }, 'bar');
|
||||
g('{{#with foo}}{{bar}}{{/with}}', { foo: { bar: 'baz' } }, 'baz');
|
||||
g('{{#each items}}{{this}}{{/each}}', { items: ['a', 'b', 'c'] }, 'abc');
|
||||
g('{{#each items}}{{@index}}{{/each}}', { items: ['a', 'b'] }, '01');
|
||||
g('<b>{{foo}}</b>', { foo: '&' }, '<b>&</b>');
|
||||
g('{{{foo}}}', { foo: '<b>' }, '<b>');
|
||||
g('{{foo.bar}}', { foo: { bar: 'baz' } }, 'baz');
|
||||
g('{{foo/bar}}', { foo: { bar: 'baz' } }, 'baz');
|
||||
g('{{../foo}}', {}, ''); // depth at root = empty
|
||||
g('{{{foo}}}', { foo: '&' }, '&');
|
||||
|
||||
// ============ blocks.js equivalents ============
|
||||
g(
|
||||
'{{#list people}}{{firstName}} {{lastName}}\n{{/list}}',
|
||||
{
|
||||
people: [
|
||||
{ firstName: 'Yehuda', lastName: 'Katz' },
|
||||
{ firstName: 'Carl', lastName: 'Lerche' },
|
||||
],
|
||||
},
|
||||
'Yehuda Katz\nCarl Lerche\n'
|
||||
);
|
||||
g(
|
||||
'{{#list people}}{{../prefix}} {{firstName}}\n{{/list}}',
|
||||
{ people: [{ firstName: 'Yehuda' }, { firstName: 'Carl' }], prefix: 'Mr' },
|
||||
'Mr Yehuda\nMr Carl\n'
|
||||
);
|
||||
g(
|
||||
'{{#each people as |person|}}{{person}}\n{{/each}}',
|
||||
{ people: ['Yehuda', 'Carl'] },
|
||||
'Yehuda\nCarl\n'
|
||||
);
|
||||
|
||||
// ============ builtins.js equivalents ============
|
||||
g(
|
||||
'{{#if goodbye}}GOODBYE {{/if}}cruel {{world}}!',
|
||||
{ goodbye: true, world: 'world' },
|
||||
'GOODBYE cruel world!'
|
||||
);
|
||||
g(
|
||||
'{{#if goodbye}}GOODBYE {{/if}}cruel {{world}}!',
|
||||
{ goodbye: false, world: 'world' },
|
||||
'cruel world!'
|
||||
);
|
||||
g('{{lookup foo "bar"}}', { foo: { bar: 'val' } }, 'val');
|
||||
g(
|
||||
'{{#each items as |value key|}}{{key}}:{{value}},{{/each}}',
|
||||
{ items: { a: 1, b: 2 } },
|
||||
'a:1,b:2,'
|
||||
);
|
||||
|
||||
// Write output
|
||||
const results = tests.map((t, i) => {
|
||||
let result,
|
||||
error = null;
|
||||
try {
|
||||
const env = Handlebars.create();
|
||||
const compiled = env.compile(t.template, t.compileOpts);
|
||||
result = compiled(t.input, t.runtimeOpts);
|
||||
} catch (e) {
|
||||
error = e.message;
|
||||
result = null;
|
||||
}
|
||||
return {
|
||||
i,
|
||||
template: t.template,
|
||||
input: JSON.stringify(t.input),
|
||||
expected: t.expected,
|
||||
result,
|
||||
error,
|
||||
};
|
||||
});
|
||||
|
||||
fs.writeFileSync('/tmp/golden_results.json', JSON.stringify(results, null, 2));
|
||||
console.log(`Generated ${results.length} golden results`);
|
||||
const failures = results.filter((r) => r.result !== r.expected);
|
||||
if (failures.length) {
|
||||
console.log(`\nFAILURES (${failures.length}):`);
|
||||
failures.forEach((f) =>
|
||||
console.log(
|
||||
` [${f.i}] "${f.template}" expected="${f.expected}" got="${f.result}" error="${f.error}"`
|
||||
)
|
||||
);
|
||||
}
|
||||
+9
-5
@@ -5,14 +5,18 @@ import {
|
||||
Visitor,
|
||||
} from '@handlebars/parser';
|
||||
|
||||
import runtime from './handlebars.runtime';
|
||||
import runtime from './handlebars.runtime.js';
|
||||
|
||||
// Compiler imports
|
||||
import AST from './handlebars/compiler/ast';
|
||||
import { Compiler, compile, precompile } from './handlebars/compiler/compiler';
|
||||
import JavaScriptCompiler from './handlebars/compiler/javascript-compiler';
|
||||
import AST from './handlebars/compiler/ast.js';
|
||||
import {
|
||||
Compiler,
|
||||
compile,
|
||||
precompile,
|
||||
} from './handlebars/compiler/compiler.js';
|
||||
import JavaScriptCompiler from './handlebars/compiler/javascript-compiler.js';
|
||||
|
||||
import noConflict from './handlebars/no-conflict';
|
||||
import noConflict from './handlebars/no-conflict.js';
|
||||
|
||||
let _create = runtime.create;
|
||||
function create() {
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { Exception } from '@handlebars/parser';
|
||||
import * as base from './handlebars/base';
|
||||
import * as base from './handlebars/base.js';
|
||||
|
||||
// Each of these augment the Handlebars object. No need to setup here.
|
||||
// (This is done to easily share code between commonjs and browse envs)
|
||||
import SafeString from './handlebars/safe-string';
|
||||
import * as Utils from './handlebars/utils';
|
||||
import * as runtime from './handlebars/runtime';
|
||||
// (This is done to easily share code between module systems and browser envs)
|
||||
import SafeString from './handlebars/safe-string.js';
|
||||
import * as Utils from './handlebars/utils.js';
|
||||
import * as runtime from './handlebars/runtime.js';
|
||||
|
||||
import noConflict from './handlebars/no-conflict';
|
||||
import noConflict from './handlebars/no-conflict.js';
|
||||
|
||||
// For compatibility and usage outside of module systems, make the Handlebars object a namespace
|
||||
function create() {
|
||||
@@ -37,4 +37,15 @@ noConflict(inst);
|
||||
|
||||
inst['default'] = inst;
|
||||
|
||||
// Named re-exports for CJS interop.
|
||||
// See the comment in lib/index.js for the full explanation. In short:
|
||||
// require('handlebars/runtime').COMPILER_REVISION must be directly accessible
|
||||
// for tools like handlebars-loader that compare compiler and runtime revisions.
|
||||
export {
|
||||
VERSION,
|
||||
COMPILER_REVISION,
|
||||
LAST_COMPATIBLE_COMPILER_REVISION,
|
||||
REVISION_CHANGES,
|
||||
} from './handlebars/base.js';
|
||||
|
||||
export default inst;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { Exception } from '@handlebars/parser';
|
||||
import { createFrame, extend, toString } from './utils';
|
||||
import { registerDefaultHelpers } from './helpers';
|
||||
import { registerDefaultDecorators } from './decorators';
|
||||
import logger from './logger';
|
||||
import { resetLoggedProperties } from './internal/proto-access';
|
||||
import { createFrame, extend, toString } from './utils.js';
|
||||
import { registerDefaultHelpers } from './helpers.js';
|
||||
import { registerDefaultDecorators } from './decorators.js';
|
||||
import logger from './logger.js';
|
||||
import { resetLoggedProperties } from './internal/proto-access.js';
|
||||
|
||||
export const VERSION = '4.7.7';
|
||||
export const COMPILER_REVISION = 8;
|
||||
|
||||
@@ -1,56 +1,5 @@
|
||||
/* global define */
|
||||
import { isArray } from '../utils';
|
||||
|
||||
let SourceNode;
|
||||
|
||||
try {
|
||||
/* v8 ignore next */
|
||||
if (typeof define !== 'function' || !define.amd) {
|
||||
// We don't support this in AMD environments. For these environments, we assume that
|
||||
// they are running on the browser and thus have no need for the source-map library.
|
||||
// The variable indirection prevents bundlers from statically resolving and bundling
|
||||
// source-map (which requires Node-built-ins). The stub SourceNode below handles
|
||||
// browser/bundled usage. Bundlers may emit a "Critical dependency" warning — this
|
||||
// is expected and harmless.
|
||||
let mod = 'source-map';
|
||||
let SourceMap = require(mod);
|
||||
SourceNode = SourceMap.SourceNode;
|
||||
}
|
||||
// oxlint-disable-next-line no-unused-vars -- Babel 5 requires named catch param
|
||||
} catch (err) {
|
||||
/* NOP */
|
||||
}
|
||||
|
||||
/* v8 ignore next -- tested but not covered due to dist build */
|
||||
if (!SourceNode) {
|
||||
SourceNode = function (line, column, srcFile, chunks) {
|
||||
this.src = '';
|
||||
if (chunks) {
|
||||
this.add(chunks);
|
||||
}
|
||||
};
|
||||
/* v8 ignore next */
|
||||
SourceNode.prototype = {
|
||||
add: function (chunks) {
|
||||
if (isArray(chunks)) {
|
||||
chunks = chunks.join('');
|
||||
}
|
||||
this.src += chunks;
|
||||
},
|
||||
prepend: function (chunks) {
|
||||
if (isArray(chunks)) {
|
||||
chunks = chunks.join('');
|
||||
}
|
||||
this.src = chunks + this.src;
|
||||
},
|
||||
toStringWithSourceMap: function () {
|
||||
return { code: this.toString() };
|
||||
},
|
||||
toString: function () {
|
||||
return this.src;
|
||||
},
|
||||
};
|
||||
}
|
||||
import { isArray } from '../utils.js';
|
||||
import { SourceNode } from '#source-node';
|
||||
|
||||
function castChunk(chunk, codeGen, loc) {
|
||||
if (isArray(chunk)) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Exception } from '@handlebars/parser';
|
||||
import { isArray, indexOf, extend } from '../utils';
|
||||
import AST from './ast';
|
||||
import { isArray, indexOf, extend } from '../utils.js';
|
||||
import AST from './ast.js';
|
||||
|
||||
const slice = [].slice;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Exception } from '@handlebars/parser';
|
||||
import { COMPILER_REVISION, REVISION_CHANGES } from '../base';
|
||||
import { isArray } from '../utils';
|
||||
import CodeGen from './code-gen';
|
||||
import { COMPILER_REVISION, REVISION_CHANGES } from '../base.js';
|
||||
import { isArray } from '../utils.js';
|
||||
import CodeGen from './code-gen.js';
|
||||
|
||||
function Literal(value) {
|
||||
this.value = value;
|
||||
@@ -164,10 +164,12 @@ JavaScriptCompiler.prototype = {
|
||||
|
||||
let { programs, decorators } = this.context;
|
||||
for (i = 0, l = programs.length; i < l; i++) {
|
||||
ret[i] = programs[i];
|
||||
if (decorators[i]) {
|
||||
ret[i + '_d'] = decorators[i];
|
||||
ret.useDecorators = true;
|
||||
if (programs[i]) {
|
||||
ret[i] = programs[i];
|
||||
if (decorators[i]) {
|
||||
ret[i + '_d'] = decorators[i];
|
||||
ret.useDecorators = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -834,8 +836,8 @@ JavaScriptCompiler.prototype = {
|
||||
let existing = this.matchExistingProgram(child);
|
||||
|
||||
if (existing == null) {
|
||||
// Placeholder to prevent name conflicts for nested children
|
||||
let index = this.context.programs.push('') - 1;
|
||||
this.context.programs.push(''); // Placeholder to prevent name conflicts for nested children
|
||||
let index = this.context.programs.length;
|
||||
child.index = index;
|
||||
child.name = 'program' + index;
|
||||
this.context.programs[index] = compiler.compile(
|
||||
@@ -1173,20 +1175,34 @@ function strictLookup(requireTerminal, compiler, parts, startPartIndex, type) {
|
||||
stack = compiler.nameLookup(stack, parts[i], type);
|
||||
}
|
||||
|
||||
if (requireTerminal) {
|
||||
if (!requireTerminal) {
|
||||
return stack;
|
||||
}
|
||||
|
||||
if (startPartIndex > len) {
|
||||
// Compat mode already consumed all parts via depthedLookup; the stack
|
||||
// holds the resolved value, not an object to look the property up on.
|
||||
// Use container.strictLookup to traverse depths with a strict error on miss.
|
||||
return [
|
||||
compiler.aliasable('container.strict'),
|
||||
'(',
|
||||
stack,
|
||||
', ',
|
||||
compiler.aliasable('container.strictLookup'),
|
||||
'(depths, ',
|
||||
compiler.quotedString(parts[len]),
|
||||
', ',
|
||||
JSON.stringify(compiler.source.currentLocation),
|
||||
' )',
|
||||
];
|
||||
} else {
|
||||
return stack;
|
||||
}
|
||||
|
||||
return [
|
||||
compiler.aliasable('container.strict'),
|
||||
'(',
|
||||
stack,
|
||||
', ',
|
||||
compiler.quotedString(parts[len]),
|
||||
', ',
|
||||
JSON.stringify(compiler.source.currentLocation),
|
||||
' )',
|
||||
];
|
||||
}
|
||||
|
||||
export default JavaScriptCompiler;
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
import { isArray } from '../utils.js';
|
||||
|
||||
// Lightweight stub for browser environments where the source-map package
|
||||
// (which depends on Node.js built-ins) is not available.
|
||||
export function SourceNode(line, column, srcFile, chunks) {
|
||||
this.src = '';
|
||||
if (chunks) {
|
||||
this.add(chunks);
|
||||
}
|
||||
}
|
||||
|
||||
SourceNode.prototype = {
|
||||
add(chunks) {
|
||||
if (isArray(chunks)) {
|
||||
chunks = chunks.join('');
|
||||
}
|
||||
this.src += chunks;
|
||||
},
|
||||
prepend(chunks) {
|
||||
if (isArray(chunks)) {
|
||||
chunks = chunks.join('');
|
||||
}
|
||||
this.src = chunks + this.src;
|
||||
},
|
||||
toStringWithSourceMap() {
|
||||
return { code: this.toString() };
|
||||
},
|
||||
toString() {
|
||||
return this.src;
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
export { SourceNode } from 'source-map';
|
||||
@@ -1,4 +1,4 @@
|
||||
import registerInline from './decorators/inline';
|
||||
import registerInline from './decorators/inline.js';
|
||||
|
||||
export function registerDefaultDecorators(instance) {
|
||||
registerInline(instance);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { extend } from '../utils';
|
||||
import { extend } from '../utils.js';
|
||||
|
||||
export default function (instance) {
|
||||
instance.registerDecorator(
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import registerBlockHelperMissing from './helpers/block-helper-missing';
|
||||
import registerEach from './helpers/each';
|
||||
import registerHelperMissing from './helpers/helper-missing';
|
||||
import registerIf from './helpers/if';
|
||||
import registerLog from './helpers/log';
|
||||
import registerLookup from './helpers/lookup';
|
||||
import registerWith from './helpers/with';
|
||||
import registerBlockHelperMissing from './helpers/block-helper-missing.js';
|
||||
import registerEach from './helpers/each.js';
|
||||
import registerHelperMissing from './helpers/helper-missing.js';
|
||||
import registerIf from './helpers/if.js';
|
||||
import registerLog from './helpers/log.js';
|
||||
import registerLookup from './helpers/lookup.js';
|
||||
import registerWith from './helpers/with.js';
|
||||
|
||||
export function registerDefaultHelpers(instance) {
|
||||
registerBlockHelperMissing(instance);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { isArray } from '../utils';
|
||||
import { isArray } from '../utils.js';
|
||||
|
||||
export default function (instance) {
|
||||
instance.registerHelper('blockHelperMissing', function (context, options) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Exception } from '@handlebars/parser';
|
||||
import { createFrame, isArray, isFunction, isMap, isSet } from '../utils';
|
||||
import { createFrame, isArray, isFunction, isMap, isSet } from '../utils.js';
|
||||
|
||||
export default function (instance) {
|
||||
instance.registerHelper('each', function (context, options) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Exception } from '@handlebars/parser';
|
||||
import { isEmpty, isFunction } from '../utils';
|
||||
import { isEmpty, isFunction } from '../utils.js';
|
||||
|
||||
export default function (instance) {
|
||||
instance.registerHelper('if', function (conditional, options) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Exception } from '@handlebars/parser';
|
||||
import { isEmpty, isFunction } from '../utils';
|
||||
import { isEmpty, isFunction } from '../utils.js';
|
||||
|
||||
export default function (instance) {
|
||||
instance.registerHelper('with', function (context, options) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { extend } from '../utils';
|
||||
import logger from '../logger';
|
||||
import { extend } from '../utils.js';
|
||||
import logger from '../logger.js';
|
||||
|
||||
const loggedProperties = Object.create(null);
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { indexOf } from './utils';
|
||||
import { indexOf } from './utils.js';
|
||||
|
||||
let logger = {
|
||||
methodMap: ['debug', 'info', 'warn', 'error'],
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
import { Exception } from '@handlebars/parser';
|
||||
import * as Utils from './utils';
|
||||
import * as Utils from './utils.js';
|
||||
import {
|
||||
COMPILER_REVISION,
|
||||
createFrame,
|
||||
LAST_COMPATIBLE_COMPILER_REVISION,
|
||||
REVISION_CHANGES,
|
||||
} from './base';
|
||||
import { moveHelperToHooks } from './helpers';
|
||||
import { wrapHelper } from './internal/wrapHelper';
|
||||
} from './base.js';
|
||||
import { moveHelperToHooks } from './helpers.js';
|
||||
import { wrapHelper } from './internal/wrapHelper.js';
|
||||
import {
|
||||
createProtoAccessControl,
|
||||
resultIsAllowed,
|
||||
} from './internal/proto-access';
|
||||
} from './internal/proto-access.js';
|
||||
|
||||
export function checkRevision(compilerInfo) {
|
||||
const compilerRevision = (compilerInfo && compilerInfo[0]) || 1,
|
||||
@@ -116,6 +116,22 @@ export function template(templateSpec, env) {
|
||||
}
|
||||
return container.lookupProperty(obj, name);
|
||||
},
|
||||
strictLookup: function (depths, name, loc) {
|
||||
const len = depths.length;
|
||||
let depth;
|
||||
for (let i = 0; i < len; i++) {
|
||||
const d = depths[i];
|
||||
if (
|
||||
d &&
|
||||
(typeof d === 'object' || typeof d === 'function') &&
|
||||
name in d
|
||||
) {
|
||||
depth = d;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return container.strict(depth, name, loc);
|
||||
},
|
||||
lookupProperty: function (parent, propertyName) {
|
||||
if (Utils.isMap(parent)) {
|
||||
return parent.get(propertyName);
|
||||
|
||||
+44
-23
@@ -1,25 +1,46 @@
|
||||
// USAGE:
|
||||
// var handlebars = require('handlebars');
|
||||
/* eslint-disable no-var */
|
||||
import handlebars from './handlebars.js';
|
||||
import { PrintVisitor, print } from '@handlebars/parser';
|
||||
|
||||
// var local = handlebars.create();
|
||||
handlebars.PrintVisitor = PrintVisitor;
|
||||
handlebars.print = print;
|
||||
|
||||
var handlebars = require('../dist/cjs/handlebars')['default'];
|
||||
|
||||
var parser = require('@handlebars/parser');
|
||||
handlebars.PrintVisitor = parser.PrintVisitor;
|
||||
handlebars.print = parser.print;
|
||||
|
||||
module.exports = handlebars;
|
||||
|
||||
// Publish a Node.js require() handler for .handlebars and .hbs files
|
||||
function extension(module, filename) {
|
||||
var fs = require('fs');
|
||||
var templateString = fs.readFileSync(filename, 'utf8');
|
||||
module.exports = handlebars.compile(templateString);
|
||||
}
|
||||
/* v8 ignore next 4 */
|
||||
if (typeof require !== 'undefined' && require.extensions) {
|
||||
require.extensions['.handlebars'] = extension;
|
||||
require.extensions['.hbs'] = extension;
|
||||
}
|
||||
// Named exports for CJS interop.
|
||||
//
|
||||
// When Node.js (v22+) runs require() on an ESM module, it returns the module
|
||||
// namespace object — only named exports become direct properties. Without these,
|
||||
// require('handlebars') would return { default: inst } and calls like
|
||||
// Handlebars.precompile() or Handlebars.COMPILER_REVISION would be undefined.
|
||||
//
|
||||
// Tools like handlebars-loader rely on these being directly accessible via
|
||||
// require('handlebars').create(), require('handlebars').COMPILER_REVISION, etc.
|
||||
export const {
|
||||
create,
|
||||
compile,
|
||||
precompile,
|
||||
parse,
|
||||
parseWithoutProcessing,
|
||||
COMPILER_REVISION,
|
||||
LAST_COMPATIBLE_COMPILER_REVISION,
|
||||
REVISION_CHANGES,
|
||||
VERSION,
|
||||
AST,
|
||||
Compiler,
|
||||
JavaScriptCompiler,
|
||||
Parser,
|
||||
Visitor,
|
||||
SafeString,
|
||||
Exception,
|
||||
Utils,
|
||||
escapeExpression,
|
||||
VM,
|
||||
template,
|
||||
log,
|
||||
registerHelper,
|
||||
unregisterHelper,
|
||||
registerPartial,
|
||||
unregisterPartial,
|
||||
registerDecorator,
|
||||
unregisterDecorator,
|
||||
} = handlebars;
|
||||
export { PrintVisitor, print };
|
||||
export default handlebars;
|
||||
|
||||
+16
-45
@@ -1,11 +1,11 @@
|
||||
/* eslint-disable no-console */
|
||||
import Async from 'neo-async';
|
||||
import fs from 'fs';
|
||||
import Handlebars from './handlebars';
|
||||
import Handlebars from './handlebars.js';
|
||||
import { basename } from 'path';
|
||||
import { SourceMapConsumer, SourceNode } from 'source-map';
|
||||
|
||||
module.exports.loadTemplates = function (opts, callback) {
|
||||
export function loadTemplates(opts, callback) {
|
||||
loadStrings(opts, function (err, strings) {
|
||||
if (err) {
|
||||
callback(err);
|
||||
@@ -20,7 +20,7 @@ module.exports.loadTemplates = function (opts, callback) {
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
function loadStrings(opts, callback) {
|
||||
let strings = arrayCast(opts.string),
|
||||
@@ -152,7 +152,7 @@ function loadFiles(opts, callback) {
|
||||
);
|
||||
}
|
||||
|
||||
module.exports.cli = async function (opts) {
|
||||
export async function cli(opts) {
|
||||
if (opts.version) {
|
||||
console.log(Handlebars.VERSION);
|
||||
return;
|
||||
@@ -176,12 +176,7 @@ module.exports.cli = async function (opts) {
|
||||
}
|
||||
|
||||
// Force simple mode if we have only one template and it's unnamed.
|
||||
if (
|
||||
!opts.amd &&
|
||||
!opts.commonjs &&
|
||||
opts.templates.length === 1 &&
|
||||
!opts.templates[0].name
|
||||
) {
|
||||
if (opts.templates.length === 1 && !opts.templates[0].name) {
|
||||
opts.simple = true;
|
||||
}
|
||||
|
||||
@@ -200,17 +195,7 @@ module.exports.cli = async function (opts) {
|
||||
|
||||
let output = new SourceNode();
|
||||
if (!opts.simple) {
|
||||
if (opts.amd) {
|
||||
output.add(
|
||||
"define(['" +
|
||||
opts.handlebarPath +
|
||||
'handlebars.runtime\'], function(Handlebars) {\n Handlebars = Handlebars["default"];'
|
||||
);
|
||||
} else if (opts.commonjs) {
|
||||
output.add('var Handlebars = require("' + opts.commonjs + '");');
|
||||
} else {
|
||||
output.add('(function() {\n');
|
||||
}
|
||||
output.add('(function() {\n');
|
||||
output.add(' var template = Handlebars.template, templates = ');
|
||||
if (opts.namespace) {
|
||||
output.add(opts.namespace);
|
||||
@@ -253,9 +238,6 @@ module.exports.cli = async function (opts) {
|
||||
throw new Handlebars.Exception('Name missing for template');
|
||||
}
|
||||
|
||||
if (opts.amd && !multiple) {
|
||||
output.add('return ');
|
||||
}
|
||||
output.add([
|
||||
objectName,
|
||||
"['",
|
||||
@@ -269,14 +251,7 @@ module.exports.cli = async function (opts) {
|
||||
|
||||
// Output the content
|
||||
if (!opts.simple) {
|
||||
if (opts.amd) {
|
||||
if (multiple) {
|
||||
output.add(['return ', objectName, ';\n']);
|
||||
}
|
||||
output.add('});');
|
||||
} else if (!opts.commonjs) {
|
||||
output.add('})();');
|
||||
}
|
||||
output.add('})();');
|
||||
}
|
||||
|
||||
if (opts.map) {
|
||||
@@ -287,7 +262,7 @@ module.exports.cli = async function (opts) {
|
||||
output.map = output.map + '';
|
||||
|
||||
if (opts.min) {
|
||||
output = minify(output, opts.map);
|
||||
output = await minify(output, opts.map);
|
||||
}
|
||||
|
||||
if (opts.map) {
|
||||
@@ -300,7 +275,7 @@ module.exports.cli = async function (opts) {
|
||||
} else {
|
||||
console.log(output);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function arrayCast(value) {
|
||||
value = value != null ? value : [];
|
||||
@@ -313,29 +288,25 @@ function arrayCast(value) {
|
||||
/**
|
||||
* Run uglify to minify the compiled template, if uglify exists in the dependencies.
|
||||
*
|
||||
* We are using `require` instead of `import` here, because es6-modules do not allow
|
||||
* dynamic imports and uglify-js is an optional dependency. Since we are inside NodeJS here, this
|
||||
* should not be a problem.
|
||||
*
|
||||
* @param {string} output the compiled template
|
||||
* @param {string} sourceMapFile the file to write the source map to.
|
||||
*/
|
||||
function minify(output, sourceMapFile) {
|
||||
async function minify(output, sourceMapFile) {
|
||||
let uglify;
|
||||
try {
|
||||
// Try to resolve uglify-js in order to see if it does exist
|
||||
require.resolve('uglify-js');
|
||||
uglify = await import('uglify-js');
|
||||
// Handle both default and named exports
|
||||
uglify = uglify.default || uglify;
|
||||
} catch (e) {
|
||||
if (e.code !== 'MODULE_NOT_FOUND') {
|
||||
// Something else seems to be wrong
|
||||
if (e.code !== 'ERR_MODULE_NOT_FOUND' && e.code !== 'MODULE_NOT_FOUND') {
|
||||
throw e;
|
||||
}
|
||||
// it does not exist!
|
||||
console.error(
|
||||
'Code minimization is disabled due to missing uglify-js dependency'
|
||||
);
|
||||
return output;
|
||||
}
|
||||
return require('uglify-js').minify(output.code, {
|
||||
return uglify.minify(output.code, {
|
||||
sourceMap: {
|
||||
content: output.map,
|
||||
url: sourceMapFile,
|
||||
|
||||
Generated
+18
-3648
File diff suppressed because it is too large
Load Diff
+25
-22
@@ -16,26 +16,40 @@
|
||||
"url": "https://github.com/handlebars-lang/handlebars.js.git"
|
||||
},
|
||||
"bin": {
|
||||
"handlebars": "bin/handlebars.mjs"
|
||||
"handlebars": "bin/handlebars.js"
|
||||
},
|
||||
"files": [
|
||||
"bin",
|
||||
"dist/*.js",
|
||||
"dist/cjs/**/*.js",
|
||||
"lib",
|
||||
"release-notes.md",
|
||||
"runtime.js",
|
||||
"types/*.d.ts",
|
||||
"runtime.d.ts"
|
||||
],
|
||||
"type": "module",
|
||||
"main": "lib/index.js",
|
||||
"browser": "./dist/cjs/handlebars.js",
|
||||
"types": "types/index.d.ts",
|
||||
"imports": {
|
||||
"#source-node": {
|
||||
"node": "./lib/handlebars/compiler/source-node.node.js",
|
||||
"default": "./lib/handlebars/compiler/source-node.browser.js"
|
||||
}
|
||||
},
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./types/index.d.ts",
|
||||
"default": "./lib/index.js"
|
||||
},
|
||||
"./runtime": {
|
||||
"types": "./runtime.d.ts",
|
||||
"default": "./lib/handlebars.runtime.js"
|
||||
},
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"scripts": {
|
||||
"clean": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true});require('fs').rmSync('tmp',{recursive:true,force:true})\"",
|
||||
"build:cjs": "swc lib --out-dir dist/cjs --strip-leading-paths --ignore \"**/index.js\"",
|
||||
"build:bundles": "rspack build",
|
||||
"build": "npm run clean && npm run build:cjs && npm run build:bundles",
|
||||
"clean": "node --input-type=module -e \"import fs from 'fs';fs.rmSync('dist',{recursive:true,force:true});fs.rmSync('tmp',{recursive:true,force:true})\"",
|
||||
"build": "npm run clean && rspack build",
|
||||
"release": "npm run build",
|
||||
"publish:aws": "npm run build && npm run test:tasks && node tasks/publish-to-aws.js",
|
||||
"format": "oxfmt --write . && oxlint --fix .",
|
||||
@@ -52,14 +66,14 @@
|
||||
"test:browser-smoke": "playwright test --config tests/browser/playwright.config.js",
|
||||
"test:serve": "npx serve -l 9999 .",
|
||||
"test:integration": "npm run build && ./tests/integration/run-integration-tests.sh",
|
||||
"bench": "node tests/bench/perf.mjs",
|
||||
"bench:compare": "node tests/bench/compare.mjs",
|
||||
"bench:size": "node tests/bench/size.mjs",
|
||||
"bench": "node tests/bench/perf.js",
|
||||
"bench:compare": "node tests/bench/compare.js",
|
||||
"bench:size": "node tests/bench/size.js",
|
||||
"--- combined tasks ---": "",
|
||||
"check-before-pull-request": "concurrently --kill-others-on-fail npm:lint npm:test"
|
||||
},
|
||||
"dependencies": {
|
||||
"@handlebars/parser": "^2.1.0",
|
||||
"@handlebars/parser": "^2.2.2",
|
||||
"neo-async": "^2.6.2",
|
||||
"source-map": "^0.7.6",
|
||||
"yargs": "^18.0.0"
|
||||
@@ -69,8 +83,6 @@
|
||||
"@playwright/test": "^1.58.2",
|
||||
"@rspack/cli": "^1.7.8",
|
||||
"@rspack/core": "^1.7.8",
|
||||
"@swc/cli": "^0.8.0",
|
||||
"@swc/core": "^1.15.18",
|
||||
"@vitest/browser": "^4.0.18",
|
||||
"@vitest/browser-playwright": "^4.0.18",
|
||||
"@vitest/coverage-v8": "^4.0.18",
|
||||
@@ -116,14 +128,5 @@
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
},
|
||||
"jspm": {
|
||||
"main": "handlebars",
|
||||
"directories": {
|
||||
"lib": "dist/cjs"
|
||||
},
|
||||
"buildConfig": {
|
||||
"minify": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+38
-23
@@ -1,8 +1,14 @@
|
||||
const { rspack } = require('@rspack/core');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
import { rspack } from '@rspack/core';
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
const pkg = require('./package.json');
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
|
||||
const pkg = JSON.parse(
|
||||
fs.readFileSync(path.resolve(__dirname, 'package.json'), 'utf8')
|
||||
);
|
||||
const license = fs.readFileSync(path.resolve(__dirname, 'LICENSE'), 'utf8');
|
||||
const banner = `/*!
|
||||
|
||||
@@ -29,28 +35,11 @@ function createConfig(entry, filename, minimize) {
|
||||
filename,
|
||||
library: {
|
||||
name: 'Handlebars',
|
||||
type: 'umd',
|
||||
type: 'self',
|
||||
export: 'default',
|
||||
},
|
||||
globalObject: 'this',
|
||||
clean: false,
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.js$/,
|
||||
exclude: /node_modules/,
|
||||
use: {
|
||||
loader: 'builtin:swc-loader',
|
||||
options: {
|
||||
jsc: {
|
||||
parser: { syntax: 'ecmascript' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
optimization: {
|
||||
minimize,
|
||||
minimizer: minimize
|
||||
@@ -71,12 +60,38 @@ function createConfig(entry, filename, minimize) {
|
||||
: [],
|
||||
},
|
||||
plugins,
|
||||
resolve: {
|
||||
extensions: ['.js', '.json'],
|
||||
mainFields: ['main'],
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.js$/,
|
||||
resolve: {
|
||||
fullySpecified: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
test: /\.js$/,
|
||||
exclude: /node_modules/,
|
||||
use: {
|
||||
loader: 'builtin:swc-loader',
|
||||
options: {
|
||||
jsc: {
|
||||
parser: { syntax: 'ecmascript' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
target: ['web', 'browserslist'],
|
||||
devtool: false,
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = [
|
||||
export default [
|
||||
createConfig('./lib/handlebars.js', 'handlebars.js', false),
|
||||
createConfig('./lib/handlebars.runtime.js', 'handlebars.runtime.js', false),
|
||||
createConfig('./lib/handlebars.js', 'handlebars.min.js', true),
|
||||
|
||||
Vendored
+3
-2
@@ -1,3 +1,4 @@
|
||||
import Handlebars = require('handlebars');
|
||||
import Handlebars from 'handlebars';
|
||||
|
||||
declare module 'handlebars/runtime' {}
|
||||
declare const runtime: typeof Handlebars;
|
||||
export default runtime;
|
||||
|
||||
+3
-3
@@ -1,3 +1,3 @@
|
||||
// Create a simple path alias to allow browserify to resolve
|
||||
// the runtime on a supported path.
|
||||
module.exports = require('./dist/cjs/handlebars.runtime')['default'];
|
||||
import runtime from './lib/handlebars.runtime.js';
|
||||
|
||||
export default runtime;
|
||||
|
||||
Vendored
+6
-3
@@ -1,7 +1,10 @@
|
||||
require('./common');
|
||||
import './common.js';
|
||||
|
||||
var fs = require('fs'),
|
||||
vm = require('vm');
|
||||
import fs from 'fs';
|
||||
import vm from 'vm';
|
||||
import { createRequire } from 'module';
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
|
||||
global.Handlebars = 'no-conflict';
|
||||
|
||||
|
||||
Vendored
+3
-2
@@ -1,6 +1,7 @@
|
||||
require('./common');
|
||||
import './common.js';
|
||||
import Handlebars from '../../lib/index.js';
|
||||
|
||||
global.Handlebars = require('../../lib');
|
||||
global.Handlebars = Handlebars;
|
||||
|
||||
global.CompilerContext = {
|
||||
compile: function (template, options) {
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
define(['handlebars.runtime'], function(Handlebars) {
|
||||
Handlebars = Handlebars["default"]; var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {};
|
||||
return templates['bom'] = template({"compiler":[8,">= 4.3.0"],"main":function(container,depth0,helpers,partials,data) {
|
||||
return "a";
|
||||
},"useData":true});
|
||||
});
|
||||
@@ -1,6 +0,0 @@
|
||||
define(['handlebars.runtime'], function(Handlebars) {
|
||||
Handlebars = Handlebars["default"]; var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {};
|
||||
return templates['empty'] = template({"compiler":[8,">= 4.3.0"],"main":function(container,depth0,helpers,partials,data) {
|
||||
return "";
|
||||
},"useData":true});
|
||||
});
|
||||
Vendored
-1
@@ -1 +0,0 @@
|
||||
define(["handlebars.runtime"],function(e){var t=(e=e.default).template;return(e.templates=e.templates||{}).empty=t({compiler:[8,">= 4.3.0"],main:function(e,t,a,n,r){return""},useData:!0})});
|
||||
@@ -1,6 +0,0 @@
|
||||
define(['handlebars.runtime'], function(Handlebars) {
|
||||
Handlebars = Handlebars["default"]; var template = Handlebars.template, templates = CustomNamespace.templates = CustomNamespace.templates || {};
|
||||
return templates['empty'] = template({"compiler":[8,">= 4.3.0"],"main":function(container,depth0,helpers,partials,data) {
|
||||
return "";
|
||||
},"useData":true});
|
||||
});
|
||||
@@ -1,3 +0,0 @@
|
||||
{"compiler":[8,">= 4.3.0"],"main":function(container,depth0,helpers,partials,data) {
|
||||
return "";
|
||||
},"useData":true}
|
||||
@@ -1,10 +0,0 @@
|
||||
define(['handlebars.runtime'], function(Handlebars) {
|
||||
Handlebars = Handlebars["default"]; var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {};
|
||||
templates['firstTemplate'] = template({"compiler":[8,">= 4.3.0"],"main":function(container,depth0,helpers,partials,data) {
|
||||
return "<div>1</div>";
|
||||
},"useData":true});
|
||||
templates['secondTemplate'] = template({"compiler":[8,">= 4.3.0"],"main":function(container,depth0,helpers,partials,data) {
|
||||
return "<div>2</div>";
|
||||
},"useData":true});
|
||||
return templates;
|
||||
});
|
||||
@@ -1,5 +1,5 @@
|
||||
(function() {
|
||||
var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {};
|
||||
var template = Handlebars.template, templates = CustomNamespace.templates = CustomNamespace.templates || {};
|
||||
templates['empty'] = template({"compiler":[8,">= 4.3.0"],"main":function(container,depth0,helpers,partials,data) {
|
||||
return "";
|
||||
},"useData":true});
|
||||
@@ -1,6 +0,0 @@
|
||||
define(['handlebars.runtime'], function(Handlebars) {
|
||||
Handlebars = Handlebars["default"]; var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {};
|
||||
return templates['artifacts/partial.template'] = template({"compiler":[8,">= 4.3.0"],"main":function(container,depth0,helpers,partials,data) {
|
||||
return "<div>Test Partial</div>";
|
||||
},"useData":true});
|
||||
});
|
||||
@@ -1,6 +0,0 @@
|
||||
define(['some-path/handlebars.runtime'], function(Handlebars) {
|
||||
Handlebars = Handlebars["default"]; var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {};
|
||||
return templates['empty'] = template({"compiler":[8,">= 4.3.0"],"main":function(container,depth0,helpers,partials,data) {
|
||||
return "";
|
||||
},"useData":true});
|
||||
});
|
||||
+19
-22
@@ -1,25 +1,22 @@
|
||||
Precompile handlebar templates.
|
||||
Usage: handlebars.mjs [template|directory]...
|
||||
Usage: handlebars.js [template|directory]...
|
||||
|
||||
Options:
|
||||
-f, --output Output File [string]
|
||||
--map Source Map File [string]
|
||||
-a, --amd Exports amd style (require.js) [boolean]
|
||||
-c, --commonjs Exports CommonJS style, path to Handlebars module [string] [default: null]
|
||||
-h, --handlebarPath Path to handlebar.js (only valid for amd-style) [string] [default: ""]
|
||||
-k, --known Known helpers [string]
|
||||
-o, --knownOnly Known helpers only [boolean]
|
||||
-m, --min Minimize output [boolean]
|
||||
-n, --namespace Template namespace [string] [default: "Handlebars.templates"]
|
||||
-s, --simple Output template function only. [boolean]
|
||||
-N, --name Name of passed string templates. Optional if running in a simple mode. Required when operating on
|
||||
multiple templates. [string]
|
||||
-i, --string Generates a template from the passed CLI argument.
|
||||
"-" is treated as a special value and causes stdin to be read for the template value. [string]
|
||||
-r, --root Template root. Base value that will be stripped from template names. [string]
|
||||
-p, --partial Compiling a partial template [boolean]
|
||||
-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 Prints the current compiler version [boolean]
|
||||
--help Outputs this message [boolean]
|
||||
-f, --output Output File [string]
|
||||
--map Source Map File [string]
|
||||
-k, --known Known helpers [string]
|
||||
-o, --knownOnly Known helpers only [boolean]
|
||||
-m, --min Minimize output [boolean]
|
||||
-n, --namespace Template namespace [string] [default: "Handlebars.templates"]
|
||||
-s, --simple Output template function only. [boolean]
|
||||
-N, --name Name of passed string templates. Optional if running in a simple mode. Required when operating on
|
||||
multiple templates. [string]
|
||||
-i, --string Generates a template from the passed CLI argument.
|
||||
"-" is treated as a special value and causes stdin to be read for the template value. [string]
|
||||
-r, --root Template root. Base value that will be stripped from template names. [string]
|
||||
-p, --partial Compiling a partial template [boolean]
|
||||
-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 Prints the current compiler version [boolean]
|
||||
--help Outputs this message [boolean]
|
||||
@@ -1,10 +0,0 @@
|
||||
define(['handlebars.runtime'], function(Handlebars) {
|
||||
Handlebars = Handlebars["default"]; var template = Handlebars.template, templates = someNameSpace = someNameSpace || {};
|
||||
templates['empty'] = template({"compiler":[8,">= 4.3.0"],"main":function(container,depth0,helpers,partials,data) {
|
||||
return "";
|
||||
},"useData":true});
|
||||
templates['empty'] = template({"compiler":[8,">= 4.3.0"],"main":function(container,depth0,helpers,partials,data) {
|
||||
return "";
|
||||
},"useData":true});
|
||||
return templates;
|
||||
});
|
||||
@@ -1,6 +0,0 @@
|
||||
define(['handlebars.runtime'], function(Handlebars) {
|
||||
Handlebars = Handlebars["default"]; var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {};
|
||||
return templates['non.default.extension'] = template({"compiler":[8,">= 4.3.0"],"main":function(container,depth0,helpers,partials,data) {
|
||||
return "<div>This is a test</div>";
|
||||
},"useData":true});
|
||||
});
|
||||
@@ -1,24 +0,0 @@
|
||||
define(['handlebars.runtime'], function(Handlebars) {
|
||||
Handlebars = Handlebars["default"]; var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {};
|
||||
return templates['known.helpers'] = template({"0":function(container,depth0,helpers,partials,data) {
|
||||
var stack1, lookupProperty = container.lookupProperty || function(parent, propertyName) {
|
||||
if (Object.prototype.hasOwnProperty.call(parent, propertyName)) {
|
||||
return parent[propertyName];
|
||||
}
|
||||
return undefined
|
||||
};
|
||||
return " <div>Some known helper</div>\n"
|
||||
+ ((stack1 = lookupProperty(helpers,"anotherHelper").call(depth0 != null ? depth0 : (container.nullContext || {}),true,{"name":"anotherHelper","hash":{},"fn":container.program(1, data, 0),"inverse":container.noop,"data":data,"loc":{"start":{"line":3,"column":4},"end":{"line":5,"column":22}}})) != null ? stack1 : "");
|
||||
},"1":function(container,depth0,helpers,partials,data) {
|
||||
return " <div>Another known helper</div>\n";
|
||||
},"compiler":[8,">= 4.3.0"],"main":function(container,depth0,helpers,partials,data) {
|
||||
var stack1, lookupProperty = container.lookupProperty || function(parent, propertyName) {
|
||||
if (Object.prototype.hasOwnProperty.call(parent, propertyName)) {
|
||||
return parent[propertyName];
|
||||
}
|
||||
return undefined
|
||||
};
|
||||
return ((stack1 = lookupProperty(helpers,"someHelper").call(depth0 != null ? depth0 : (container.nullContext || {}),true,{"name":"someHelper","hash":{},"fn":container.program(0, data, 0),"inverse":container.noop,"data":data,"loc":{"start":{"line":1,"column":0},"end":{"line":6,"column":15}}})) != null ? stack1 : "");
|
||||
},"useData":true});
|
||||
});
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
define(['handlebars.runtime'], function(Handlebars) {
|
||||
Handlebars = Handlebars["default"]; var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {};
|
||||
return Handlebars.partials['partial.template'] = template({"compiler":[8,">= 4.3.0"],"main":function(container,depth0,helpers,partials,data) {
|
||||
return "<div>Test Partial</div>";
|
||||
},"useData":true});
|
||||
});
|
||||
@@ -1,2 +0,0 @@
|
||||
define(["handlebars.runtime"],function(e){var t=(e=e.default).template;return(e.templates=e.templates||{}).test=t({compiler:[8,">= 4.3.0"],main:function(e,t,a,n,i){return"<div>1</div>"},useData:!0})});
|
||||
//# sourceMappingURL=./spec/tmp/source.map.amd.txt
|
||||
+25
-114
@@ -1,15 +1,19 @@
|
||||
/* eslint-disable no-console */
|
||||
import Handlebars from '../lib/index.js';
|
||||
import * as Precompiler from '../lib/precompiler.js';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import uglify from 'uglify-js';
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
describe('precompiler', function () {
|
||||
// NOP Under non-node environments
|
||||
if (typeof process === 'undefined') {
|
||||
return;
|
||||
}
|
||||
|
||||
var Handlebars = require('../lib'),
|
||||
Precompiler = require('../dist/cjs/precompiler'),
|
||||
fs = require('fs'),
|
||||
uglify = require('uglify-js');
|
||||
|
||||
var log,
|
||||
logFunction,
|
||||
errorLog,
|
||||
@@ -25,34 +29,6 @@ describe('precompiler', function () {
|
||||
content,
|
||||
writeFileSync;
|
||||
|
||||
/**
|
||||
* Mock the Module.prototype.require-function such that an error is thrown, when "uglify-js" is loaded.
|
||||
*
|
||||
* The function cleans up its mess when "callback" is finished
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
async function mockRequireUglify(loadError, callback) {
|
||||
var Module = require('module');
|
||||
var _resolveFilename = Module._resolveFilename;
|
||||
delete require.cache[require.resolve('uglify-js')];
|
||||
delete require.cache[require.resolve('../dist/cjs/precompiler')];
|
||||
Module._resolveFilename = function (request, mod) {
|
||||
if (request === 'uglify-js') {
|
||||
throw loadError;
|
||||
}
|
||||
return _resolveFilename.call(this, request, mod);
|
||||
};
|
||||
try {
|
||||
await callback();
|
||||
} finally {
|
||||
Module._resolveFilename = _resolveFilename;
|
||||
delete require.cache[require.resolve('uglify-js')];
|
||||
delete require.cache[require.resolve('../dist/cjs/precompiler')];
|
||||
}
|
||||
}
|
||||
|
||||
beforeEach(function () {
|
||||
precompile = Handlebars.precompile;
|
||||
minify = uglify.minify;
|
||||
@@ -117,7 +93,10 @@ describe('precompiler', function () {
|
||||
});
|
||||
it('should throw when missing name', async function () {
|
||||
await expect(
|
||||
Precompiler.cli({ templates: [{ source: '' }], amd: true })
|
||||
Precompiler.cli({
|
||||
templates: [{ source: '' }, { source: '' }],
|
||||
hasDirectory: true,
|
||||
})
|
||||
).rejects.toThrow('Name missing for template');
|
||||
});
|
||||
it('should throw when combining simple and directories', async function () {
|
||||
@@ -140,56 +119,14 @@ describe('precompiler', function () {
|
||||
await Precompiler.cli({ templates: [{ source: '' }] });
|
||||
expect(log).toBe('simple\n');
|
||||
});
|
||||
it('should output amd templates', async function () {
|
||||
|
||||
it('should output wrapped templates', async function () {
|
||||
Handlebars.precompile = function () {
|
||||
return 'amd';
|
||||
return 'wrapped';
|
||||
};
|
||||
await Precompiler.cli({ templates: [emptyTemplate], amd: true });
|
||||
expect(log).toMatch(/template\(amd\)/);
|
||||
});
|
||||
it('should output multiple amd', async function () {
|
||||
Handlebars.precompile = function () {
|
||||
return 'amd';
|
||||
};
|
||||
await Precompiler.cli({
|
||||
templates: [emptyTemplate, emptyTemplate],
|
||||
amd: true,
|
||||
namespace: 'foo',
|
||||
});
|
||||
expect(log).toMatch(/templates = foo = foo \|\|/);
|
||||
expect(log).toMatch(/return templates/);
|
||||
expect(log).toMatch(/template\(amd\)/);
|
||||
});
|
||||
it('should output amd partials', async function () {
|
||||
Handlebars.precompile = function () {
|
||||
return 'amd';
|
||||
};
|
||||
await Precompiler.cli({
|
||||
templates: [emptyTemplate],
|
||||
amd: true,
|
||||
partial: true,
|
||||
});
|
||||
expect(log).toMatch(/return Handlebars\.partials\['empty'\]/);
|
||||
expect(log).toMatch(/template\(amd\)/);
|
||||
});
|
||||
it('should output multiple amd partials', async function () {
|
||||
Handlebars.precompile = function () {
|
||||
return 'amd';
|
||||
};
|
||||
await Precompiler.cli({
|
||||
templates: [emptyTemplate, emptyTemplate],
|
||||
amd: true,
|
||||
partial: true,
|
||||
});
|
||||
expect(log).not.toMatch(/return Handlebars\.partials\[/);
|
||||
expect(log).toMatch(/template\(amd\)/);
|
||||
});
|
||||
it('should output commonjs templates', async function () {
|
||||
Handlebars.precompile = function () {
|
||||
return 'commonjs';
|
||||
};
|
||||
await Precompiler.cli({ templates: [emptyTemplate], commonjs: true });
|
||||
expect(log).toMatch(/template\(commonjs\)/);
|
||||
await Precompiler.cli({ templates: [emptyTemplate] });
|
||||
expect(log).toMatch(/template\(wrapped\)/);
|
||||
expect(log).toMatch(/\(function\(\)/);
|
||||
});
|
||||
|
||||
it('should set data flag', async function () {
|
||||
@@ -233,7 +170,7 @@ describe('precompiler', function () {
|
||||
|
||||
it('should output minimized templates', async function () {
|
||||
Handlebars.precompile = function () {
|
||||
return 'amd';
|
||||
return 'iife';
|
||||
};
|
||||
uglify.minify = function () {
|
||||
return { code: 'min' };
|
||||
@@ -242,33 +179,6 @@ describe('precompiler', function () {
|
||||
expect(log).toBe('min');
|
||||
});
|
||||
|
||||
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';
|
||||
await mockRequireUglify(error, async function () {
|
||||
var Precompiler = require('../dist/cjs/precompiler');
|
||||
Handlebars.precompile = function () {
|
||||
return 'amd';
|
||||
};
|
||||
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', async function () {
|
||||
await mockRequireUglify(new Error('Mock Error'), async function () {
|
||||
var Precompiler = require('../dist/cjs/precompiler');
|
||||
Handlebars.precompile = function () {
|
||||
return 'amd';
|
||||
};
|
||||
await expect(
|
||||
Precompiler.cli({ templates: [emptyTemplate], min: true })
|
||||
).rejects.toThrow('Mock Error');
|
||||
});
|
||||
});
|
||||
|
||||
it('should output map', async function () {
|
||||
await Precompiler.cli({ templates: [emptyTemplate], map: 'foo.js.map' });
|
||||
|
||||
@@ -367,11 +277,12 @@ describe('precompiler', function () {
|
||||
expect(opts.templates[1].source).toBe('bar');
|
||||
});
|
||||
it('should accept stdin input', async function () {
|
||||
var stdin = require('mock-stdin').stdin();
|
||||
var { stdin } = await import('mock-stdin');
|
||||
var stdinMock = stdin();
|
||||
var promise = loadTemplatesAsync({ string: '-' });
|
||||
stdin.send('fo');
|
||||
stdin.send('o');
|
||||
stdin.end();
|
||||
stdinMock.send('fo');
|
||||
stdinMock.send('o');
|
||||
stdinMock.end();
|
||||
var opts = await promise;
|
||||
expect(opts.templates[0].source).toBe('foo');
|
||||
});
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
if (typeof require !== 'undefined' && require.extensions['.handlebars']) {
|
||||
describe('Require', function () {
|
||||
it('Load .handlebars files with require()', function () {
|
||||
var template = require('./artifacts/example_1');
|
||||
expect(template).toBe(require('./artifacts/example_1.handlebars'));
|
||||
|
||||
var expected = 'foo\n';
|
||||
var result = template({ foo: 'foo' });
|
||||
|
||||
expect(result).toBe(expected);
|
||||
});
|
||||
|
||||
it('Load .hbs files with require()', function () {
|
||||
var template = require('./artifacts/example_2');
|
||||
expect(template).toBe(require('./artifacts/example_2.hbs'));
|
||||
|
||||
var expected = 'Hello, World!\n';
|
||||
var result = template({ name: 'World' });
|
||||
|
||||
expect(result).toBe(expected);
|
||||
});
|
||||
});
|
||||
}
|
||||
+5
-4
@@ -1,8 +1,9 @@
|
||||
import { createRequire } from 'module';
|
||||
|
||||
var SourceMap, SourceMapConsumer;
|
||||
try {
|
||||
if (typeof define !== 'function' || !define.amd) {
|
||||
var SourceMap = require('source-map'),
|
||||
SourceMapConsumer = SourceMap.SourceMapConsumer;
|
||||
}
|
||||
SourceMap = createRequire(import.meta.url)('source-map');
|
||||
SourceMapConsumer = SourceMap.SourceMapConsumer;
|
||||
} catch {
|
||||
/* NOP for in browser */
|
||||
}
|
||||
|
||||
+7
-3
@@ -1,16 +1,20 @@
|
||||
import fs from 'fs';
|
||||
import { fileURLToPath } from 'url';
|
||||
import path from 'path';
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
describe('spec', function () {
|
||||
// NOP Under non-node environments
|
||||
if (typeof process === 'undefined') {
|
||||
return;
|
||||
}
|
||||
|
||||
var fs = require('fs');
|
||||
|
||||
var specDir = __dirname + '/mustache/specs/';
|
||||
var specs = fs.readdirSync(specDir).filter((name) => /.*\.json$/.test(name));
|
||||
|
||||
specs.forEach(function (name) {
|
||||
var spec = require(specDir + name);
|
||||
var spec = JSON.parse(fs.readFileSync(specDir + name, 'utf8'));
|
||||
spec.tests.forEach(function (test) {
|
||||
// Our lambda implementation knowingly deviates from the optional Mustache lambda spec
|
||||
// We also do not support alternative delimiters
|
||||
|
||||
@@ -121,6 +121,63 @@ describe('strict', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('strict and compat mode', function () {
|
||||
it('GH-1741: should render a simple variable', function () {
|
||||
expectTemplate('{{v}}')
|
||||
.withCompileOptions({ strict: true, compat: true })
|
||||
.withInput({ v: 'a' })
|
||||
.toCompileTo('a');
|
||||
});
|
||||
|
||||
it('should throw for a missing variable', function () {
|
||||
expectTemplate('{{v}}')
|
||||
.withCompileOptions({ strict: true, compat: true })
|
||||
.toThrow(Exception, /"v" not defined in/);
|
||||
});
|
||||
|
||||
it('GH-2149: should render correctly when block context is a boolean', function () {
|
||||
expectTemplate('{{#foo}}Hello {{bar}}{{/foo}}')
|
||||
.withCompileOptions({ strict: true, compat: true })
|
||||
.withInput({ foo: true, bar: 'World' })
|
||||
.toCompileTo('Hello World');
|
||||
});
|
||||
|
||||
it('GH-2149: should render correctly when looking up a property on each item', function () {
|
||||
expectTemplate('{{#each items}}{{name}}{{/each}}')
|
||||
.withCompileOptions({ strict: true, compat: true })
|
||||
.withInput({ items: [{ name: 'Hello' }] })
|
||||
.toCompileTo('Hello');
|
||||
});
|
||||
|
||||
it('should still throw when a property is missing at all depths', function () {
|
||||
expectTemplate('{{#each items}}{{name}}{{/each}}')
|
||||
.withCompileOptions({ strict: true, compat: true })
|
||||
.withInput({ items: [1, 2] })
|
||||
.toThrow(Exception, /"name" not defined in/);
|
||||
});
|
||||
|
||||
it('should still perform recursive lookup when a property is not in the current context', function () {
|
||||
expectTemplate('{{#each items}}{{name}}{{/each}}')
|
||||
.withCompileOptions({ strict: true, compat: true })
|
||||
.withInput({ name: 'root', items: [{}] })
|
||||
.toCompileTo('root');
|
||||
});
|
||||
|
||||
it('should still perform recursive lookup with a multi-part path not in context', function () {
|
||||
expectTemplate('{{#with child}}{{name.first}}{{/with}}')
|
||||
.withCompileOptions({ strict: true, compat: true })
|
||||
.withInput({ name: { first: 'root' }, child: { name: null } })
|
||||
.toCompileTo('root');
|
||||
});
|
||||
|
||||
it('should directly return an explicitly null property', function () {
|
||||
expectTemplate('{{#each items}}{{name}}{{/each}}')
|
||||
.withCompileOptions({ strict: true, compat: true })
|
||||
.withInput({ name: 'root', items: [{ name: null }] })
|
||||
.toCompileTo('');
|
||||
});
|
||||
});
|
||||
|
||||
describe('assume objects', function () {
|
||||
it('should ignore missing property', function () {
|
||||
expectTemplate('{{hello}}')
|
||||
|
||||
@@ -1,796 +0,0 @@
|
||||
function shouldMatchTokens(result, tokens) {
|
||||
for (var index = 0; index < result.length; index++) {
|
||||
expect(result[index].name).toBe(tokens[index]);
|
||||
}
|
||||
}
|
||||
function shouldBeToken(result, name, text) {
|
||||
expect(result.name).toBe(name);
|
||||
expect(result.text).toBe(text);
|
||||
}
|
||||
|
||||
describe('Tokenizer', function () {
|
||||
if (!Handlebars.Parser) {
|
||||
return;
|
||||
}
|
||||
|
||||
function tokenize(template) {
|
||||
var parser = Handlebars.Parser,
|
||||
lexer = parser.lexer;
|
||||
|
||||
lexer.setInput(template);
|
||||
var out = [],
|
||||
token;
|
||||
|
||||
while ((token = lexer.lex())) {
|
||||
var result = parser.terminals_[token] || token;
|
||||
if (!result || result === 'EOF' || result === 'INVALID') {
|
||||
break;
|
||||
}
|
||||
out.push({ name: result, text: lexer.yytext });
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
it('tokenizes a simple mustache as "OPEN ID CLOSE"', function () {
|
||||
var result = tokenize('{{foo}}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'CLOSE']);
|
||||
shouldBeToken(result[1], 'ID', 'foo');
|
||||
});
|
||||
|
||||
it('supports unescaping with &', function () {
|
||||
var result = tokenize('{{&bar}}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'CLOSE']);
|
||||
|
||||
shouldBeToken(result[0], 'OPEN', '{{&');
|
||||
shouldBeToken(result[1], 'ID', 'bar');
|
||||
});
|
||||
|
||||
it('supports unescaping with {{{', function () {
|
||||
var result = tokenize('{{{bar}}}');
|
||||
shouldMatchTokens(result, ['OPEN_UNESCAPED', 'ID', 'CLOSE_UNESCAPED']);
|
||||
|
||||
shouldBeToken(result[1], 'ID', 'bar');
|
||||
});
|
||||
|
||||
it('supports escaping delimiters', function () {
|
||||
var result = tokenize('{{foo}} \\{{bar}} {{baz}}');
|
||||
shouldMatchTokens(result, [
|
||||
'OPEN',
|
||||
'ID',
|
||||
'CLOSE',
|
||||
'CONTENT',
|
||||
'CONTENT',
|
||||
'OPEN',
|
||||
'ID',
|
||||
'CLOSE',
|
||||
]);
|
||||
|
||||
shouldBeToken(result[3], 'CONTENT', ' ');
|
||||
shouldBeToken(result[4], 'CONTENT', '{{bar}} ');
|
||||
});
|
||||
|
||||
it('supports escaping multiple delimiters', function () {
|
||||
var result = tokenize('{{foo}} \\{{bar}} \\{{baz}}');
|
||||
shouldMatchTokens(result, [
|
||||
'OPEN',
|
||||
'ID',
|
||||
'CLOSE',
|
||||
'CONTENT',
|
||||
'CONTENT',
|
||||
'CONTENT',
|
||||
]);
|
||||
|
||||
shouldBeToken(result[3], 'CONTENT', ' ');
|
||||
shouldBeToken(result[4], 'CONTENT', '{{bar}} ');
|
||||
shouldBeToken(result[5], 'CONTENT', '{{baz}}');
|
||||
});
|
||||
|
||||
it('supports escaping a triple stash', function () {
|
||||
var result = tokenize('{{foo}} \\{{{bar}}} {{baz}}');
|
||||
shouldMatchTokens(result, [
|
||||
'OPEN',
|
||||
'ID',
|
||||
'CLOSE',
|
||||
'CONTENT',
|
||||
'CONTENT',
|
||||
'OPEN',
|
||||
'ID',
|
||||
'CLOSE',
|
||||
]);
|
||||
|
||||
shouldBeToken(result[4], 'CONTENT', '{{{bar}}} ');
|
||||
});
|
||||
|
||||
it('supports escaping escape character', function () {
|
||||
var result = tokenize('{{foo}} \\\\{{bar}} {{baz}}');
|
||||
shouldMatchTokens(result, [
|
||||
'OPEN',
|
||||
'ID',
|
||||
'CLOSE',
|
||||
'CONTENT',
|
||||
'OPEN',
|
||||
'ID',
|
||||
'CLOSE',
|
||||
'CONTENT',
|
||||
'OPEN',
|
||||
'ID',
|
||||
'CLOSE',
|
||||
]);
|
||||
|
||||
shouldBeToken(result[3], 'CONTENT', ' \\');
|
||||
shouldBeToken(result[5], 'ID', 'bar');
|
||||
});
|
||||
|
||||
it('supports escaping multiple escape characters', function () {
|
||||
var result = tokenize('{{foo}} \\\\{{bar}} \\\\{{baz}}');
|
||||
shouldMatchTokens(result, [
|
||||
'OPEN',
|
||||
'ID',
|
||||
'CLOSE',
|
||||
'CONTENT',
|
||||
'OPEN',
|
||||
'ID',
|
||||
'CLOSE',
|
||||
'CONTENT',
|
||||
'OPEN',
|
||||
'ID',
|
||||
'CLOSE',
|
||||
]);
|
||||
|
||||
shouldBeToken(result[3], 'CONTENT', ' \\');
|
||||
shouldBeToken(result[5], 'ID', 'bar');
|
||||
shouldBeToken(result[7], 'CONTENT', ' \\');
|
||||
shouldBeToken(result[9], 'ID', 'baz');
|
||||
});
|
||||
|
||||
it('supports escaped mustaches after escaped escape characters', function () {
|
||||
var result = tokenize('{{foo}} \\\\{{bar}} \\{{baz}}');
|
||||
shouldMatchTokens(result, [
|
||||
'OPEN',
|
||||
'ID',
|
||||
'CLOSE',
|
||||
'CONTENT',
|
||||
'OPEN',
|
||||
'ID',
|
||||
'CLOSE',
|
||||
'CONTENT',
|
||||
'CONTENT',
|
||||
'CONTENT',
|
||||
]);
|
||||
|
||||
shouldBeToken(result[3], 'CONTENT', ' \\');
|
||||
shouldBeToken(result[4], 'OPEN', '{{');
|
||||
shouldBeToken(result[5], 'ID', 'bar');
|
||||
shouldBeToken(result[7], 'CONTENT', ' ');
|
||||
shouldBeToken(result[8], 'CONTENT', '{{baz}}');
|
||||
});
|
||||
|
||||
it('supports escaped escape characters after escaped mustaches', function () {
|
||||
var result = tokenize('{{foo}} \\{{bar}} \\\\{{baz}}');
|
||||
shouldMatchTokens(result, [
|
||||
'OPEN',
|
||||
'ID',
|
||||
'CLOSE',
|
||||
'CONTENT',
|
||||
'CONTENT',
|
||||
'CONTENT',
|
||||
'OPEN',
|
||||
'ID',
|
||||
'CLOSE',
|
||||
]);
|
||||
|
||||
shouldBeToken(result[4], 'CONTENT', '{{bar}} ');
|
||||
shouldBeToken(result[5], 'CONTENT', '\\');
|
||||
shouldBeToken(result[6], 'OPEN', '{{');
|
||||
shouldBeToken(result[7], 'ID', 'baz');
|
||||
});
|
||||
|
||||
it('supports escaped escape character on a triple stash', function () {
|
||||
var result = tokenize('{{foo}} \\\\{{{bar}}} {{baz}}');
|
||||
shouldMatchTokens(result, [
|
||||
'OPEN',
|
||||
'ID',
|
||||
'CLOSE',
|
||||
'CONTENT',
|
||||
'OPEN_UNESCAPED',
|
||||
'ID',
|
||||
'CLOSE_UNESCAPED',
|
||||
'CONTENT',
|
||||
'OPEN',
|
||||
'ID',
|
||||
'CLOSE',
|
||||
]);
|
||||
|
||||
shouldBeToken(result[3], 'CONTENT', ' \\');
|
||||
shouldBeToken(result[5], 'ID', 'bar');
|
||||
});
|
||||
|
||||
it('tokenizes a simple path', function () {
|
||||
var result = tokenize('{{foo/bar}}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'SEP', 'ID', 'CLOSE']);
|
||||
});
|
||||
|
||||
it('allows dot notation', function () {
|
||||
var result = tokenize('{{foo.bar}}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'SEP', 'ID', 'CLOSE']);
|
||||
|
||||
shouldMatchTokens(tokenize('{{foo.bar.baz}}'), [
|
||||
'OPEN',
|
||||
'ID',
|
||||
'SEP',
|
||||
'ID',
|
||||
'SEP',
|
||||
'ID',
|
||||
'CLOSE',
|
||||
]);
|
||||
});
|
||||
|
||||
it('allows path literals with []', function () {
|
||||
var result = tokenize('{{foo.[bar]}}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'SEP', 'ID', 'CLOSE']);
|
||||
});
|
||||
|
||||
it('allows multiple path literals on a line with []', function () {
|
||||
var result = tokenize('{{foo.[bar]}}{{foo.[baz]}}');
|
||||
shouldMatchTokens(result, [
|
||||
'OPEN',
|
||||
'ID',
|
||||
'SEP',
|
||||
'ID',
|
||||
'CLOSE',
|
||||
'OPEN',
|
||||
'ID',
|
||||
'SEP',
|
||||
'ID',
|
||||
'CLOSE',
|
||||
]);
|
||||
});
|
||||
|
||||
it('allows escaped literals in []', function () {
|
||||
var result = tokenize('{{foo.[bar\\]]}}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'SEP', 'ID', 'CLOSE']);
|
||||
});
|
||||
|
||||
it('tokenizes {{.}} as OPEN ID CLOSE', function () {
|
||||
var result = tokenize('{{.}}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'CLOSE']);
|
||||
});
|
||||
|
||||
it('tokenizes a path as "OPEN (ID SEP)* ID CLOSE"', function () {
|
||||
var result = tokenize('{{../foo/bar}}');
|
||||
shouldMatchTokens(result, [
|
||||
'OPEN',
|
||||
'ID',
|
||||
'SEP',
|
||||
'ID',
|
||||
'SEP',
|
||||
'ID',
|
||||
'CLOSE',
|
||||
]);
|
||||
shouldBeToken(result[1], 'ID', '..');
|
||||
});
|
||||
|
||||
it('tokenizes a path with .. as a parent path', function () {
|
||||
var result = tokenize('{{../foo.bar}}');
|
||||
shouldMatchTokens(result, [
|
||||
'OPEN',
|
||||
'ID',
|
||||
'SEP',
|
||||
'ID',
|
||||
'SEP',
|
||||
'ID',
|
||||
'CLOSE',
|
||||
]);
|
||||
shouldBeToken(result[1], 'ID', '..');
|
||||
});
|
||||
|
||||
it('tokenizes a path with this/foo as OPEN ID SEP ID CLOSE', function () {
|
||||
var result = tokenize('{{this/foo}}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'SEP', 'ID', 'CLOSE']);
|
||||
shouldBeToken(result[1], 'ID', 'this');
|
||||
shouldBeToken(result[3], 'ID', 'foo');
|
||||
});
|
||||
|
||||
it('tokenizes a simple mustache with spaces as "OPEN ID CLOSE"', function () {
|
||||
var result = tokenize('{{ foo }}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'CLOSE']);
|
||||
shouldBeToken(result[1], 'ID', 'foo');
|
||||
});
|
||||
|
||||
it('tokenizes a simple mustache with line breaks as "OPEN ID ID CLOSE"', function () {
|
||||
var result = tokenize('{{ foo \n bar }}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'CLOSE']);
|
||||
shouldBeToken(result[1], 'ID', 'foo');
|
||||
});
|
||||
|
||||
it('tokenizes raw content as "CONTENT"', function () {
|
||||
var result = tokenize('foo {{ bar }} baz');
|
||||
shouldMatchTokens(result, ['CONTENT', 'OPEN', 'ID', 'CLOSE', 'CONTENT']);
|
||||
shouldBeToken(result[0], 'CONTENT', 'foo ');
|
||||
shouldBeToken(result[4], 'CONTENT', ' baz');
|
||||
});
|
||||
|
||||
it('tokenizes a partial as "OPEN_PARTIAL ID CLOSE"', function () {
|
||||
var result = tokenize('{{> foo}}');
|
||||
shouldMatchTokens(result, ['OPEN_PARTIAL', 'ID', 'CLOSE']);
|
||||
});
|
||||
|
||||
it('tokenizes a partial with context as "OPEN_PARTIAL ID ID CLOSE"', function () {
|
||||
var result = tokenize('{{> foo bar }}');
|
||||
shouldMatchTokens(result, ['OPEN_PARTIAL', 'ID', 'ID', 'CLOSE']);
|
||||
});
|
||||
|
||||
it('tokenizes a partial without spaces as "OPEN_PARTIAL ID CLOSE"', function () {
|
||||
var result = tokenize('{{>foo}}');
|
||||
shouldMatchTokens(result, ['OPEN_PARTIAL', 'ID', 'CLOSE']);
|
||||
});
|
||||
|
||||
it('tokenizes a partial space at the }); as "OPEN_PARTIAL ID CLOSE"', function () {
|
||||
var result = tokenize('{{>foo }}');
|
||||
shouldMatchTokens(result, ['OPEN_PARTIAL', 'ID', 'CLOSE']);
|
||||
});
|
||||
|
||||
it('tokenizes a partial space at the }); as "OPEN_PARTIAL ID CLOSE"', function () {
|
||||
var result = tokenize('{{>foo/bar.baz }}');
|
||||
shouldMatchTokens(result, [
|
||||
'OPEN_PARTIAL',
|
||||
'ID',
|
||||
'SEP',
|
||||
'ID',
|
||||
'SEP',
|
||||
'ID',
|
||||
'CLOSE',
|
||||
]);
|
||||
});
|
||||
|
||||
it('tokenizes partial block declarations', function () {
|
||||
var result = tokenize('{{#> foo}}');
|
||||
shouldMatchTokens(result, ['OPEN_PARTIAL_BLOCK', 'ID', 'CLOSE']);
|
||||
});
|
||||
it('tokenizes a comment as "COMMENT"', function () {
|
||||
var result = tokenize('foo {{! this is a comment }} bar {{ baz }}');
|
||||
shouldMatchTokens(result, [
|
||||
'CONTENT',
|
||||
'COMMENT',
|
||||
'CONTENT',
|
||||
'OPEN',
|
||||
'ID',
|
||||
'CLOSE',
|
||||
]);
|
||||
shouldBeToken(result[1], 'COMMENT', '{{! this is a comment }}');
|
||||
});
|
||||
|
||||
it('tokenizes a block comment as "COMMENT"', function () {
|
||||
var result = tokenize('foo {{!-- this is a {{comment}} --}} bar {{ baz }}');
|
||||
shouldMatchTokens(result, [
|
||||
'CONTENT',
|
||||
'COMMENT',
|
||||
'CONTENT',
|
||||
'OPEN',
|
||||
'ID',
|
||||
'CLOSE',
|
||||
]);
|
||||
shouldBeToken(result[1], 'COMMENT', '{{!-- this is a {{comment}} --}}');
|
||||
});
|
||||
|
||||
it('tokenizes a block comment with whitespace as "COMMENT"', function () {
|
||||
var result = tokenize(
|
||||
'foo {{!-- this is a\n{{comment}}\n--}} bar {{ baz }}'
|
||||
);
|
||||
shouldMatchTokens(result, [
|
||||
'CONTENT',
|
||||
'COMMENT',
|
||||
'CONTENT',
|
||||
'OPEN',
|
||||
'ID',
|
||||
'CLOSE',
|
||||
]);
|
||||
shouldBeToken(result[1], 'COMMENT', '{{!-- this is a\n{{comment}}\n--}}');
|
||||
});
|
||||
|
||||
it('tokenizes open and closing blocks as OPEN_BLOCK, ID, CLOSE ..., OPEN_ENDBLOCK ID CLOSE', function () {
|
||||
var result = tokenize('{{#foo}}content{{/foo}}');
|
||||
shouldMatchTokens(result, [
|
||||
'OPEN_BLOCK',
|
||||
'ID',
|
||||
'CLOSE',
|
||||
'CONTENT',
|
||||
'OPEN_ENDBLOCK',
|
||||
'ID',
|
||||
'CLOSE',
|
||||
]);
|
||||
});
|
||||
|
||||
it('tokenizes directives', function () {
|
||||
shouldMatchTokens(tokenize('{{#*foo}}content{{/foo}}'), [
|
||||
'OPEN_BLOCK',
|
||||
'ID',
|
||||
'CLOSE',
|
||||
'CONTENT',
|
||||
'OPEN_ENDBLOCK',
|
||||
'ID',
|
||||
'CLOSE',
|
||||
]);
|
||||
shouldMatchTokens(tokenize('{{*foo}}'), ['OPEN', 'ID', 'CLOSE']);
|
||||
});
|
||||
|
||||
it('tokenizes inverse sections as "INVERSE"', function () {
|
||||
shouldMatchTokens(tokenize('{{^}}'), ['INVERSE']);
|
||||
shouldMatchTokens(tokenize('{{else}}'), ['INVERSE']);
|
||||
shouldMatchTokens(tokenize('{{ else }}'), ['INVERSE']);
|
||||
});
|
||||
|
||||
it('tokenizes inverse sections with ID as "OPEN_INVERSE ID CLOSE"', function () {
|
||||
var result = tokenize('{{^foo}}');
|
||||
shouldMatchTokens(result, ['OPEN_INVERSE', 'ID', 'CLOSE']);
|
||||
shouldBeToken(result[1], 'ID', 'foo');
|
||||
});
|
||||
|
||||
it('tokenizes inverse sections with ID and spaces as "OPEN_INVERSE ID CLOSE"', function () {
|
||||
var result = tokenize('{{^ foo }}');
|
||||
shouldMatchTokens(result, ['OPEN_INVERSE', 'ID', 'CLOSE']);
|
||||
shouldBeToken(result[1], 'ID', 'foo');
|
||||
});
|
||||
|
||||
it('tokenizes mustaches with params as "OPEN ID ID ID CLOSE"', function () {
|
||||
var result = tokenize('{{ foo bar baz }}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'ID', 'CLOSE']);
|
||||
shouldBeToken(result[1], 'ID', 'foo');
|
||||
shouldBeToken(result[2], 'ID', 'bar');
|
||||
shouldBeToken(result[3], 'ID', 'baz');
|
||||
});
|
||||
|
||||
it('tokenizes mustaches with String params as "OPEN ID ID STRING CLOSE"', function () {
|
||||
var result = tokenize('{{ foo bar "baz" }}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'STRING', 'CLOSE']);
|
||||
shouldBeToken(result[3], 'STRING', 'baz');
|
||||
});
|
||||
|
||||
it('tokenizes mustaches with String params using single quotes as "OPEN ID ID STRING CLOSE"', function () {
|
||||
var result = tokenize("{{ foo bar 'baz' }}");
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'STRING', 'CLOSE']);
|
||||
shouldBeToken(result[3], 'STRING', 'baz');
|
||||
});
|
||||
|
||||
it('tokenizes String params with spaces inside as "STRING"', function () {
|
||||
var result = tokenize('{{ foo bar "baz bat" }}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'STRING', 'CLOSE']);
|
||||
shouldBeToken(result[3], 'STRING', 'baz bat');
|
||||
});
|
||||
|
||||
it('tokenizes String params with escapes quotes as STRING', function () {
|
||||
var result = tokenize('{{ foo "bar\\"baz" }}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'STRING', 'CLOSE']);
|
||||
shouldBeToken(result[2], 'STRING', 'bar"baz');
|
||||
});
|
||||
|
||||
it('tokenizes String params using single quotes with escapes quotes as STRING', function () {
|
||||
var result = tokenize("{{ foo 'bar\\'baz' }}");
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'STRING', 'CLOSE']);
|
||||
shouldBeToken(result[2], 'STRING', "bar'baz");
|
||||
});
|
||||
|
||||
it('tokenizes numbers', function () {
|
||||
var result = tokenize('{{ foo 1 }}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'NUMBER', 'CLOSE']);
|
||||
shouldBeToken(result[2], 'NUMBER', '1');
|
||||
|
||||
result = tokenize('{{ foo 1.1 }}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'NUMBER', 'CLOSE']);
|
||||
shouldBeToken(result[2], 'NUMBER', '1.1');
|
||||
|
||||
result = tokenize('{{ foo -1 }}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'NUMBER', 'CLOSE']);
|
||||
shouldBeToken(result[2], 'NUMBER', '-1');
|
||||
|
||||
result = tokenize('{{ foo -1.1 }}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'NUMBER', 'CLOSE']);
|
||||
shouldBeToken(result[2], 'NUMBER', '-1.1');
|
||||
});
|
||||
|
||||
it('tokenizes booleans', function () {
|
||||
var result = tokenize('{{ foo true }}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'BOOLEAN', 'CLOSE']);
|
||||
shouldBeToken(result[2], 'BOOLEAN', 'true');
|
||||
|
||||
result = tokenize('{{ foo false }}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'BOOLEAN', 'CLOSE']);
|
||||
shouldBeToken(result[2], 'BOOLEAN', 'false');
|
||||
});
|
||||
|
||||
it('tokenizes undefined and null', function () {
|
||||
var result = tokenize('{{ foo undefined null }}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'UNDEFINED', 'NULL', 'CLOSE']);
|
||||
shouldBeToken(result[2], 'UNDEFINED', 'undefined');
|
||||
shouldBeToken(result[3], 'NULL', 'null');
|
||||
});
|
||||
|
||||
it('tokenizes hash arguments', function () {
|
||||
var result = tokenize('{{ foo bar=baz }}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'EQUALS', 'ID', 'CLOSE']);
|
||||
|
||||
result = tokenize('{{ foo bar baz=bat }}');
|
||||
shouldMatchTokens(result, [
|
||||
'OPEN',
|
||||
'ID',
|
||||
'ID',
|
||||
'ID',
|
||||
'EQUALS',
|
||||
'ID',
|
||||
'CLOSE',
|
||||
]);
|
||||
|
||||
result = tokenize('{{ foo bar baz=1 }}');
|
||||
shouldMatchTokens(result, [
|
||||
'OPEN',
|
||||
'ID',
|
||||
'ID',
|
||||
'ID',
|
||||
'EQUALS',
|
||||
'NUMBER',
|
||||
'CLOSE',
|
||||
]);
|
||||
|
||||
result = tokenize('{{ foo bar baz=true }}');
|
||||
shouldMatchTokens(result, [
|
||||
'OPEN',
|
||||
'ID',
|
||||
'ID',
|
||||
'ID',
|
||||
'EQUALS',
|
||||
'BOOLEAN',
|
||||
'CLOSE',
|
||||
]);
|
||||
|
||||
result = tokenize('{{ foo bar baz=false }}');
|
||||
shouldMatchTokens(result, [
|
||||
'OPEN',
|
||||
'ID',
|
||||
'ID',
|
||||
'ID',
|
||||
'EQUALS',
|
||||
'BOOLEAN',
|
||||
'CLOSE',
|
||||
]);
|
||||
|
||||
result = tokenize('{{ foo bar\n baz=bat }}');
|
||||
shouldMatchTokens(result, [
|
||||
'OPEN',
|
||||
'ID',
|
||||
'ID',
|
||||
'ID',
|
||||
'EQUALS',
|
||||
'ID',
|
||||
'CLOSE',
|
||||
]);
|
||||
|
||||
result = tokenize('{{ foo bar baz="bat" }}');
|
||||
shouldMatchTokens(result, [
|
||||
'OPEN',
|
||||
'ID',
|
||||
'ID',
|
||||
'ID',
|
||||
'EQUALS',
|
||||
'STRING',
|
||||
'CLOSE',
|
||||
]);
|
||||
|
||||
result = tokenize('{{ foo bar baz="bat" bam=wot }}');
|
||||
shouldMatchTokens(result, [
|
||||
'OPEN',
|
||||
'ID',
|
||||
'ID',
|
||||
'ID',
|
||||
'EQUALS',
|
||||
'STRING',
|
||||
'ID',
|
||||
'EQUALS',
|
||||
'ID',
|
||||
'CLOSE',
|
||||
]);
|
||||
|
||||
result = tokenize('{{foo omg bar=baz bat="bam"}}');
|
||||
shouldMatchTokens(result, [
|
||||
'OPEN',
|
||||
'ID',
|
||||
'ID',
|
||||
'ID',
|
||||
'EQUALS',
|
||||
'ID',
|
||||
'ID',
|
||||
'EQUALS',
|
||||
'STRING',
|
||||
'CLOSE',
|
||||
]);
|
||||
shouldBeToken(result[2], 'ID', 'omg');
|
||||
});
|
||||
|
||||
it('tokenizes special @ identifiers', function () {
|
||||
var result = tokenize('{{ @foo }}');
|
||||
shouldMatchTokens(result, ['OPEN', 'DATA', 'ID', 'CLOSE']);
|
||||
shouldBeToken(result[2], 'ID', 'foo');
|
||||
|
||||
result = tokenize('{{ foo @bar }}');
|
||||
shouldMatchTokens(result, ['OPEN', 'ID', 'DATA', 'ID', 'CLOSE']);
|
||||
shouldBeToken(result[3], 'ID', 'bar');
|
||||
|
||||
result = tokenize('{{ foo bar=@baz }}');
|
||||
shouldMatchTokens(result, [
|
||||
'OPEN',
|
||||
'ID',
|
||||
'ID',
|
||||
'EQUALS',
|
||||
'DATA',
|
||||
'ID',
|
||||
'CLOSE',
|
||||
]);
|
||||
shouldBeToken(result[5], 'ID', 'baz');
|
||||
});
|
||||
|
||||
it('does not time out in a mustache with a single } followed by EOF', function () {
|
||||
shouldMatchTokens(tokenize('{{foo}'), ['OPEN', 'ID']);
|
||||
});
|
||||
|
||||
it('does not time out in a mustache when invalid ID characters are used', function () {
|
||||
shouldMatchTokens(tokenize('{{foo & }}'), ['OPEN', 'ID']);
|
||||
});
|
||||
|
||||
it('tokenizes subexpressions', function () {
|
||||
var result = tokenize('{{foo (bar)}}');
|
||||
shouldMatchTokens(result, [
|
||||
'OPEN',
|
||||
'ID',
|
||||
'OPEN_SEXPR',
|
||||
'ID',
|
||||
'CLOSE_SEXPR',
|
||||
'CLOSE',
|
||||
]);
|
||||
shouldBeToken(result[1], 'ID', 'foo');
|
||||
shouldBeToken(result[3], 'ID', 'bar');
|
||||
|
||||
result = tokenize('{{foo (a-x b-y)}}');
|
||||
shouldMatchTokens(result, [
|
||||
'OPEN',
|
||||
'ID',
|
||||
'OPEN_SEXPR',
|
||||
'ID',
|
||||
'ID',
|
||||
'CLOSE_SEXPR',
|
||||
'CLOSE',
|
||||
]);
|
||||
shouldBeToken(result[1], 'ID', 'foo');
|
||||
shouldBeToken(result[3], 'ID', 'a-x');
|
||||
shouldBeToken(result[4], 'ID', 'b-y');
|
||||
});
|
||||
|
||||
it('tokenizes nested subexpressions', function () {
|
||||
var result = tokenize('{{foo (bar (lol rofl)) (baz)}}');
|
||||
shouldMatchTokens(result, [
|
||||
'OPEN',
|
||||
'ID',
|
||||
'OPEN_SEXPR',
|
||||
'ID',
|
||||
'OPEN_SEXPR',
|
||||
'ID',
|
||||
'ID',
|
||||
'CLOSE_SEXPR',
|
||||
'CLOSE_SEXPR',
|
||||
'OPEN_SEXPR',
|
||||
'ID',
|
||||
'CLOSE_SEXPR',
|
||||
'CLOSE',
|
||||
]);
|
||||
shouldBeToken(result[3], 'ID', 'bar');
|
||||
shouldBeToken(result[5], 'ID', 'lol');
|
||||
shouldBeToken(result[6], 'ID', 'rofl');
|
||||
shouldBeToken(result[10], 'ID', 'baz');
|
||||
});
|
||||
|
||||
it('tokenizes nested subexpressions: literals', function () {
|
||||
var result = tokenize(
|
||||
'{{foo (bar (lol true) false) (baz 1) (blah \'b\') (blorg "c")}}'
|
||||
);
|
||||
shouldMatchTokens(result, [
|
||||
'OPEN',
|
||||
'ID',
|
||||
'OPEN_SEXPR',
|
||||
'ID',
|
||||
'OPEN_SEXPR',
|
||||
'ID',
|
||||
'BOOLEAN',
|
||||
'CLOSE_SEXPR',
|
||||
'BOOLEAN',
|
||||
'CLOSE_SEXPR',
|
||||
'OPEN_SEXPR',
|
||||
'ID',
|
||||
'NUMBER',
|
||||
'CLOSE_SEXPR',
|
||||
'OPEN_SEXPR',
|
||||
'ID',
|
||||
'STRING',
|
||||
'CLOSE_SEXPR',
|
||||
'OPEN_SEXPR',
|
||||
'ID',
|
||||
'STRING',
|
||||
'CLOSE_SEXPR',
|
||||
'CLOSE',
|
||||
]);
|
||||
});
|
||||
|
||||
it('tokenizes block params', function () {
|
||||
var result = tokenize('{{#foo as |bar|}}');
|
||||
shouldMatchTokens(result, [
|
||||
'OPEN_BLOCK',
|
||||
'ID',
|
||||
'OPEN_BLOCK_PARAMS',
|
||||
'ID',
|
||||
'CLOSE_BLOCK_PARAMS',
|
||||
'CLOSE',
|
||||
]);
|
||||
|
||||
result = tokenize('{{#foo as |bar baz|}}');
|
||||
shouldMatchTokens(result, [
|
||||
'OPEN_BLOCK',
|
||||
'ID',
|
||||
'OPEN_BLOCK_PARAMS',
|
||||
'ID',
|
||||
'ID',
|
||||
'CLOSE_BLOCK_PARAMS',
|
||||
'CLOSE',
|
||||
]);
|
||||
|
||||
result = tokenize('{{#foo as | bar baz |}}');
|
||||
shouldMatchTokens(result, [
|
||||
'OPEN_BLOCK',
|
||||
'ID',
|
||||
'OPEN_BLOCK_PARAMS',
|
||||
'ID',
|
||||
'ID',
|
||||
'CLOSE_BLOCK_PARAMS',
|
||||
'CLOSE',
|
||||
]);
|
||||
|
||||
result = tokenize('{{#foo as as | bar baz |}}');
|
||||
shouldMatchTokens(result, [
|
||||
'OPEN_BLOCK',
|
||||
'ID',
|
||||
'ID',
|
||||
'OPEN_BLOCK_PARAMS',
|
||||
'ID',
|
||||
'ID',
|
||||
'CLOSE_BLOCK_PARAMS',
|
||||
'CLOSE',
|
||||
]);
|
||||
|
||||
result = tokenize('{{else foo as |bar baz|}}');
|
||||
shouldMatchTokens(result, [
|
||||
'OPEN_INVERSE_CHAIN',
|
||||
'ID',
|
||||
'OPEN_BLOCK_PARAMS',
|
||||
'ID',
|
||||
'ID',
|
||||
'CLOSE_BLOCK_PARAMS',
|
||||
'CLOSE',
|
||||
]);
|
||||
});
|
||||
|
||||
it('tokenizes raw blocks', function () {
|
||||
var result = tokenize(
|
||||
'{{{{a}}}} abc {{{{/a}}}} aaa {{{{a}}}} abc {{{{/a}}}}'
|
||||
);
|
||||
shouldMatchTokens(result, [
|
||||
'OPEN_RAW_BLOCK',
|
||||
'ID',
|
||||
'CLOSE_RAW_BLOCK',
|
||||
'CONTENT',
|
||||
'END_RAW_BLOCK',
|
||||
'CONTENT',
|
||||
'OPEN_RAW_BLOCK',
|
||||
'ID',
|
||||
'CLOSE_RAW_BLOCK',
|
||||
'CONTENT',
|
||||
'END_RAW_BLOCK',
|
||||
]);
|
||||
});
|
||||
});
|
||||
@@ -1,58 +0,0 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Handlebars Runtime UMD Smoke Test</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
</head>
|
||||
<body>
|
||||
<h1>Handlebars Runtime UMD Smoke Test</h1>
|
||||
<pre id="results"></pre>
|
||||
<script src="/spec/vendor/require.js"></script>
|
||||
<script>
|
||||
var results = document.getElementById('results');
|
||||
var failures = 0;
|
||||
var tests = 0;
|
||||
|
||||
function assert(condition, message) {
|
||||
tests++;
|
||||
if (!condition) {
|
||||
failures++;
|
||||
results.textContent += 'FAIL: ' + message + '\n';
|
||||
} else {
|
||||
results.textContent += 'PASS: ' + message + '\n';
|
||||
}
|
||||
}
|
||||
|
||||
requirejs.config({
|
||||
paths: {
|
||||
'handlebars.runtime': '/dist/handlebars.runtime',
|
||||
},
|
||||
});
|
||||
|
||||
require(['handlebars.runtime'], function (Handlebars) {
|
||||
try {
|
||||
assert(
|
||||
typeof Handlebars !== 'undefined',
|
||||
'Handlebars runtime loaded via RequireJS'
|
||||
);
|
||||
assert(
|
||||
typeof Handlebars.template === 'function',
|
||||
'Handlebars.template exists'
|
||||
);
|
||||
assert(
|
||||
typeof Handlebars.VERSION === 'string',
|
||||
'Handlebars.VERSION exists'
|
||||
);
|
||||
} catch (e) {
|
||||
failures++;
|
||||
results.textContent += 'ERROR: ' + e.message + '\n';
|
||||
}
|
||||
|
||||
results.textContent +=
|
||||
'\n' + tests + ' tests, ' + failures + ' failures\n';
|
||||
window.mochaResults = { passes: tests - failures, failures: failures };
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,66 +0,0 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Handlebars UMD Module Smoke Test</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
</head>
|
||||
<body>
|
||||
<h1>Handlebars UMD Module Smoke Test</h1>
|
||||
<pre id="results"></pre>
|
||||
<script src="/spec/vendor/require.js"></script>
|
||||
<script>
|
||||
var results = document.getElementById('results');
|
||||
var failures = 0;
|
||||
var tests = 0;
|
||||
|
||||
function assert(condition, message) {
|
||||
tests++;
|
||||
if (!condition) {
|
||||
failures++;
|
||||
results.textContent += 'FAIL: ' + message + '\n';
|
||||
} else {
|
||||
results.textContent += 'PASS: ' + message + '\n';
|
||||
}
|
||||
}
|
||||
|
||||
requirejs.config({
|
||||
paths: {
|
||||
handlebars: '/dist/handlebars',
|
||||
},
|
||||
});
|
||||
|
||||
require(['handlebars'], function (Handlebars) {
|
||||
try {
|
||||
assert(
|
||||
typeof Handlebars !== 'undefined',
|
||||
'Handlebars loaded via RequireJS'
|
||||
);
|
||||
assert(
|
||||
typeof Handlebars.compile === 'function',
|
||||
'Handlebars.compile exists'
|
||||
);
|
||||
assert(
|
||||
typeof Handlebars.template === 'function',
|
||||
'Handlebars.template exists'
|
||||
);
|
||||
assert(
|
||||
typeof Handlebars.VERSION === 'string',
|
||||
'Handlebars.VERSION exists'
|
||||
);
|
||||
|
||||
var template = Handlebars.compile('Hello {{name}}!');
|
||||
var output = template({ name: 'UMD' });
|
||||
assert(output === 'Hello UMD!', 'Basic compilation works: ' + output);
|
||||
} catch (e) {
|
||||
failures++;
|
||||
results.textContent += 'ERROR: ' + e.message + '\n';
|
||||
}
|
||||
|
||||
results.textContent +=
|
||||
'\n' + tests + ' tests, ' + failures + ' failures\n';
|
||||
window.mochaResults = { passes: tests - failures, failures: failures };
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Vendored
-2054
File diff suppressed because it is too large
Load Diff
+12
-19
@@ -1,10 +1,10 @@
|
||||
/* eslint-disable no-console */
|
||||
const fs = require('fs');
|
||||
const { S3, PutObjectCommand } = require('@aws-sdk/client-s3');
|
||||
const git = require('./util/git');
|
||||
const semver = require('semver');
|
||||
import fs from 'fs';
|
||||
import { S3, PutObjectCommand } from '@aws-sdk/client-s3';
|
||||
import * as git from './util/git.js';
|
||||
import semver from 'semver';
|
||||
|
||||
const PUBLISHED_FILES = [
|
||||
export const PUBLISHED_FILES = [
|
||||
'handlebars.js',
|
||||
'handlebars.min.js',
|
||||
'handlebars.runtime.js',
|
||||
@@ -29,7 +29,7 @@ async function main() {
|
||||
}
|
||||
}
|
||||
|
||||
function buildSuffixes(commitInfo) {
|
||||
export function buildSuffixes(commitInfo) {
|
||||
const suffixes = [];
|
||||
|
||||
if (commitInfo.isMaster) {
|
||||
@@ -44,7 +44,7 @@ function buildSuffixes(commitInfo) {
|
||||
return suffixes;
|
||||
}
|
||||
|
||||
function validateS3Env() {
|
||||
export function validateS3Env() {
|
||||
const bucket = process.env.S3_BUCKET_NAME,
|
||||
region = process.env.S3_REGION,
|
||||
key = process.env.S3_ACCESS_KEY_ID,
|
||||
@@ -55,7 +55,7 @@ function validateS3Env() {
|
||||
}
|
||||
}
|
||||
|
||||
async function publish(suffixes, overrides) {
|
||||
export async function publish(suffixes, overrides) {
|
||||
const publishPromises = suffixes.map((suffix) =>
|
||||
publishSuffix(suffix, overrides)
|
||||
);
|
||||
@@ -98,24 +98,17 @@ function getS3Client() {
|
||||
return s3Client;
|
||||
}
|
||||
|
||||
function getNameInBucket(filename, suffix) {
|
||||
export function getNameInBucket(filename, suffix) {
|
||||
return filename.replace(/\.js$/, suffix + '.js');
|
||||
}
|
||||
|
||||
function getLocalFile(filename) {
|
||||
export function getLocalFile(filename) {
|
||||
return 'dist/' + filename;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
PUBLISHED_FILES,
|
||||
buildSuffixes,
|
||||
validateS3Env,
|
||||
publish,
|
||||
getNameInBucket,
|
||||
getLocalFile,
|
||||
};
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
if (require.main === module) {
|
||||
if (process.argv[1] === fileURLToPath(import.meta.url)) {
|
||||
main().catch((err) => {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
|
||||
+28
-113
@@ -1,9 +1,9 @@
|
||||
const fs = require('fs');
|
||||
const { exec } = require('child_process');
|
||||
const { execCommand, FileTestHelper } = require('cli-testlab');
|
||||
const Handlebars = require('../../lib');
|
||||
import fs from 'fs';
|
||||
import { exec } from 'child_process';
|
||||
import { execCommand, FileTestHelper } from 'cli-testlab';
|
||||
import Handlebars from '../../lib/index.js';
|
||||
|
||||
const cli = 'node ./bin/handlebars.mjs';
|
||||
const cli = 'node ./bin/handlebars.js';
|
||||
|
||||
expect.extend({
|
||||
toEqualWithRelaxedSpace(received, expected) {
|
||||
@@ -58,71 +58,22 @@ describe('bin/handlebars', 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).toEqualWithRelaxedSpace(
|
||||
expectedFile('./spec/expected/empty.amd.js')
|
||||
);
|
||||
});
|
||||
|
||||
it('-a -s produces simple AMD output', async function () {
|
||||
const result = await execCommand(
|
||||
`${cli} -a -s spec/artifacts/empty.handlebars`
|
||||
);
|
||||
expect(result.stdout).toEqualWithRelaxedSpace(
|
||||
expectedFile('./spec/expected/empty.amd.simple.js')
|
||||
);
|
||||
});
|
||||
|
||||
it('-a -m produces minified AMD output', async function () {
|
||||
const result = await execCommand(
|
||||
`${cli} -a -m spec/artifacts/empty.handlebars`
|
||||
);
|
||||
expect(result.stdout).toEqualWithRelaxedSpace(
|
||||
expectedFile('./spec/expected/empty.amd.min.js')
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
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`
|
||||
`${cli} -n CustomNamespace.templates spec/artifacts/empty.handlebars`
|
||||
);
|
||||
expect(result.stdout).toEqualWithRelaxedSpace(
|
||||
expectedFile('./spec/expected/empty.amd.namespace.js')
|
||||
expectedFile('./spec/expected/empty.namespace.js')
|
||||
);
|
||||
});
|
||||
|
||||
it('--namespace sets custom namespace', async function () {
|
||||
const result = await execCommand(
|
||||
`${cli} -a --namespace CustomNamespace.templates spec/artifacts/empty.handlebars`
|
||||
`${cli} --namespace CustomNamespace.templates spec/artifacts/empty.handlebars`
|
||||
);
|
||||
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')
|
||||
expectedFile('./spec/expected/empty.namespace.js')
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -144,14 +95,12 @@ describe('bin/handlebars', function () {
|
||||
files.registerForCleanup(outputFile);
|
||||
|
||||
await execCommand(
|
||||
`${cli} -a -f ${outputFile} spec/artifacts/empty.handlebars`
|
||||
`${cli} -f ${outputFile} spec/artifacts/empty.handlebars`
|
||||
);
|
||||
|
||||
expect(files.fileExists(outputFile)).toBe(true);
|
||||
const content = files.getFileTextContent(outputFile);
|
||||
expect(content).toEqualWithRelaxedSpace(
|
||||
expectedFile('./spec/expected/empty.amd.js')
|
||||
);
|
||||
expect(content).toMatch(/template\(/);
|
||||
});
|
||||
|
||||
it('--map writes source map and appends sourceMappingURL', async function () {
|
||||
@@ -159,7 +108,7 @@ describe('bin/handlebars', function () {
|
||||
files.registerForCleanup(mapFile);
|
||||
|
||||
const result = await execCommand(
|
||||
`${cli} -i "<div>1</div>" -a -m -N test --map ${mapFile}`
|
||||
`${cli} -i "<div>1</div>" -m -N test --map ${mapFile}`
|
||||
);
|
||||
|
||||
expect(result.stdout).toContain('sourceMappingURL=');
|
||||
@@ -174,75 +123,52 @@ describe('bin/handlebars', function () {
|
||||
describe('template options', 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).toEqualWithRelaxedSpace(
|
||||
expectedFile('./spec/expected/non.default.extension.amd.js')
|
||||
`${cli} -e hbs ./spec/artifacts/non.default.extension.hbs`
|
||||
);
|
||||
expect(result.stdout).toMatch(/template\(/);
|
||||
});
|
||||
|
||||
it('-p compiles as partial', async function () {
|
||||
const result = await execCommand(
|
||||
`${cli} -a -p ./spec/artifacts/partial.template.handlebars`
|
||||
);
|
||||
expect(result.stdout).toEqualWithRelaxedSpace(
|
||||
expectedFile('./spec/expected/partial.template.js')
|
||||
`${cli} -p ./spec/artifacts/partial.template.handlebars`
|
||||
);
|
||||
expect(result.stdout).toMatch(/Handlebars\.partials/);
|
||||
});
|
||||
|
||||
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).toEqualWithRelaxedSpace(
|
||||
expectedFile('./spec/expected/empty.root.amd.js')
|
||||
`${cli} spec/artifacts/partial.template.handlebars -r spec`
|
||||
);
|
||||
expect(result.stdout).toMatch(/template\(/);
|
||||
});
|
||||
|
||||
it('-b strips BOM', async function () {
|
||||
const result = await execCommand(
|
||||
`${cli} ./spec/artifacts/bom.handlebars -b -a`
|
||||
);
|
||||
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')
|
||||
`${cli} ./spec/artifacts/bom.handlebars -b`
|
||||
);
|
||||
expect(result.stdout).toMatch(/template\(/);
|
||||
});
|
||||
|
||||
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')
|
||||
`${cli} spec/artifacts/known.helpers.handlebars -k someHelper -k anotherHelper -o`
|
||||
);
|
||||
expect(result.stdout).toMatch(/template\(/);
|
||||
});
|
||||
});
|
||||
|
||||
describe('inline templates', function () {
|
||||
it('-i compiles inline template', async function () {
|
||||
const result = await execCommand(
|
||||
`${cli} -i "<div>hello</div>" -a -N myTemplate`
|
||||
`${cli} -i "<div>hello</div>" -N myTemplate`
|
||||
);
|
||||
expect(result.stdout).toContain("define(['handlebars.runtime']");
|
||||
expect(result.stdout).toContain("templates['myTemplate']");
|
||||
});
|
||||
|
||||
it('-i compiles multiple inline templates with -N', async function () {
|
||||
const result = await execCommand(
|
||||
`${cli} -i "<div>1</div>" -i "<div>2</div>" -N firstTemplate -N secondTemplate -a`
|
||||
);
|
||||
expect(result.stdout).toEqualWithRelaxedSpace(
|
||||
expectedFile('./spec/expected/empty.name.amd.js')
|
||||
);
|
||||
it('-i compiles simple unnamed inline template', async function () {
|
||||
const result = await execCommand(`${cli} -i "<div>hello</div>"`);
|
||||
// Unnamed single template defaults to simple mode
|
||||
expect(result.stdout).toMatch(/function/);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -250,7 +176,7 @@ describe('bin/handlebars', function () {
|
||||
it('should not produce unhandled promise rejections on async errors', async function () {
|
||||
const { stderr } = await new Promise((resolve) => {
|
||||
exec(
|
||||
`node --unhandled-rejections=warn ./bin/handlebars.mjs -i "<div>test</div>" -N test --map /nonexistent/dir/test.map`,
|
||||
`node --unhandled-rejections=warn ./bin/handlebars.js -i "<div>test</div>" -N test --map /nonexistent/dir/test.map`,
|
||||
(error, stdout, stderr) => {
|
||||
resolve({ exitCode: error ? error.code : 0, stderr });
|
||||
}
|
||||
@@ -260,15 +186,4 @@ describe('bin/handlebars', function () {
|
||||
expect(stderr).not.toMatch(/unhandled/i);
|
||||
});
|
||||
});
|
||||
|
||||
describe('negated boolean flags', 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).toEqualWithRelaxedSpace(
|
||||
expectedFile('./spec/expected/empty.common.js')
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
const http = require('http');
|
||||
import http from 'http';
|
||||
|
||||
/**
|
||||
* Minimal in-memory S3-compatible server for testing.
|
||||
* Supports PutObject and GetObject via path-style requests.
|
||||
*/
|
||||
function createFakeS3() {
|
||||
export function createFakeS3() {
|
||||
const buckets = new Map();
|
||||
|
||||
const server = http.createServer((req, res) => {
|
||||
@@ -77,5 +77,3 @@ function parsePath(url) {
|
||||
key: parts.slice(1).join('/') || null,
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = { createFakeS3 };
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
const os = require('os');
|
||||
const path = require('path');
|
||||
const fs = require('fs-extra');
|
||||
const { spawnSync } = require('child_process');
|
||||
|
||||
const git = require('../util/git');
|
||||
import os from 'os';
|
||||
import path from 'path';
|
||||
import fs from 'fs-extra';
|
||||
import { spawnSync } from 'child_process';
|
||||
import * as git from '../util/git.js';
|
||||
|
||||
const tmpBaseDir = path.join(os.tmpdir(), 'handlebars-task-tests');
|
||||
const tmpDir = path.join(tmpBaseDir, Date.now().toString(36));
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
const fs = require('fs');
|
||||
const { S3, GetObjectCommand } = require('@aws-sdk/client-s3');
|
||||
const { createFakeS3 } = require('./fake-s3');
|
||||
import fs from 'fs';
|
||||
import { S3, GetObjectCommand } from '@aws-sdk/client-s3';
|
||||
import { createFakeS3 } from './fake-s3.js';
|
||||
|
||||
const BUCKET = 'test-bucket';
|
||||
|
||||
const {
|
||||
import {
|
||||
PUBLISHED_FILES,
|
||||
buildSuffixes,
|
||||
validateS3Env,
|
||||
publish,
|
||||
getNameInBucket,
|
||||
getLocalFile,
|
||||
} = require('../publish-to-aws');
|
||||
} from '../publish-to-aws.js';
|
||||
|
||||
let server;
|
||||
let s3Client;
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
const childProcess = require('child_process');
|
||||
|
||||
module.exports = {
|
||||
execNodeJsScriptWithInheritedOutput,
|
||||
};
|
||||
|
||||
async function execNodeJsScriptWithInheritedOutput(command, args) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const child = childProcess.fork(command, args, { stdio: 'inherit' });
|
||||
child.on('close', (code) => {
|
||||
if (code !== 0) {
|
||||
reject(new Error(`Child process failed with exit-code ${code}`));
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
+29
-26
@@ -1,30 +1,33 @@
|
||||
const childProcess = require('child_process');
|
||||
import childProcess from 'child_process';
|
||||
|
||||
module.exports = {
|
||||
async remotes() {
|
||||
return git('remote', '-v');
|
||||
},
|
||||
async branches() {
|
||||
return git('branch', '-a');
|
||||
},
|
||||
async commitInfo() {
|
||||
const headSha = await getHeadSha();
|
||||
const masterSha = await getMasterSha();
|
||||
return {
|
||||
headSha,
|
||||
masterSha,
|
||||
tagName: await getTagName(),
|
||||
isMaster: headSha === masterSha,
|
||||
};
|
||||
},
|
||||
async add(path) {
|
||||
return git('add', '-f', path);
|
||||
},
|
||||
async commit(message) {
|
||||
return git('commit', '--message', message);
|
||||
},
|
||||
git, // visible for testing
|
||||
};
|
||||
export async function remotes() {
|
||||
return git('remote', '-v');
|
||||
}
|
||||
|
||||
export async function branches() {
|
||||
return git('branch', '-a');
|
||||
}
|
||||
|
||||
export async function commitInfo() {
|
||||
const headSha = await getHeadSha();
|
||||
const masterSha = await getMasterSha();
|
||||
return {
|
||||
headSha,
|
||||
masterSha,
|
||||
tagName: await getTagName(),
|
||||
isMaster: headSha === masterSha,
|
||||
};
|
||||
}
|
||||
|
||||
export async function add(path) {
|
||||
return git('add', '-f', path);
|
||||
}
|
||||
|
||||
export async function commit(message) {
|
||||
return git('commit', '--message', message);
|
||||
}
|
||||
|
||||
export { git };
|
||||
|
||||
async function getHeadSha() {
|
||||
const stdout = await git('rev-parse', '--short', 'HEAD');
|
||||
|
||||
+7
-7
@@ -1,7 +1,7 @@
|
||||
const fs = require('fs');
|
||||
const { execSync } = require('child_process');
|
||||
const git = require('./util/git');
|
||||
const semver = require('semver');
|
||||
import fs from 'fs';
|
||||
import { execSync } from 'child_process';
|
||||
import * as git from './util/git.js';
|
||||
import semver from 'semver';
|
||||
|
||||
async function main() {
|
||||
const version = process.argv[2];
|
||||
@@ -50,16 +50,16 @@ async function main() {
|
||||
execSync('npm run build', { stdio: 'inherit' });
|
||||
}
|
||||
|
||||
async function replaceAndAdd(filePath, regex, value) {
|
||||
export async function replaceAndAdd(filePath, regex, value) {
|
||||
let content = fs.readFileSync(filePath, 'utf8');
|
||||
content = content.replace(regex, value);
|
||||
fs.writeFileSync(filePath, content);
|
||||
await git.add(filePath);
|
||||
}
|
||||
|
||||
module.exports = { replaceAndAdd };
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
if (require.main === module) {
|
||||
if (process.argv[1] === fileURLToPath(import.meta.url)) {
|
||||
main().catch((err) => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(err);
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"type": "Program",
|
||||
"body": [
|
||||
{
|
||||
"type": "ContentStatement",
|
||||
"original": "Hello ",
|
||||
"value": "Hello ",
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 0 },
|
||||
"end": { "line": 1, "column": 6 }
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "MustacheStatement",
|
||||
"path": {
|
||||
"type": "PathExpression",
|
||||
"this": false,
|
||||
"data": false,
|
||||
"depth": 0,
|
||||
"head": "name",
|
||||
"tail": [],
|
||||
"parts": ["name"],
|
||||
"original": "name",
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 8 },
|
||||
"end": { "line": 1, "column": 12 }
|
||||
}
|
||||
},
|
||||
"params": [],
|
||||
"escaped": true,
|
||||
"strip": { "open": false, "close": false },
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 6 },
|
||||
"end": { "line": 1, "column": 14 }
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "ContentStatement",
|
||||
"original": "!",
|
||||
"value": "!",
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 14 },
|
||||
"end": { "line": 1, "column": 15 }
|
||||
}
|
||||
}
|
||||
],
|
||||
"strip": {},
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 0 },
|
||||
"end": { "line": 1, "column": 15 }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
Hello {{name}}!
|
||||
@@ -0,0 +1,88 @@
|
||||
{
|
||||
"type": "Program",
|
||||
"body": [
|
||||
{
|
||||
"type": "BlockStatement",
|
||||
"path": {
|
||||
"type": "PathExpression",
|
||||
"this": false,
|
||||
"data": false,
|
||||
"depth": 0,
|
||||
"head": "if",
|
||||
"tail": [],
|
||||
"parts": ["if"],
|
||||
"original": "if",
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 3 },
|
||||
"end": { "line": 1, "column": 5 }
|
||||
}
|
||||
},
|
||||
"params": [
|
||||
{
|
||||
"type": "PathExpression",
|
||||
"this": false,
|
||||
"data": false,
|
||||
"depth": 0,
|
||||
"head": "active",
|
||||
"tail": [],
|
||||
"parts": ["active"],
|
||||
"original": "active",
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 6 },
|
||||
"end": { "line": 1, "column": 12 }
|
||||
}
|
||||
}
|
||||
],
|
||||
"program": {
|
||||
"type": "Program",
|
||||
"body": [
|
||||
{
|
||||
"type": "ContentStatement",
|
||||
"original": "yes",
|
||||
"value": "yes",
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 14 },
|
||||
"end": { "line": 1, "column": 17 }
|
||||
}
|
||||
}
|
||||
],
|
||||
"strip": {},
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 14 },
|
||||
"end": { "line": 1, "column": 17 }
|
||||
}
|
||||
},
|
||||
"inverse": {
|
||||
"type": "Program",
|
||||
"body": [
|
||||
{
|
||||
"type": "ContentStatement",
|
||||
"original": "no",
|
||||
"value": "no",
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 25 },
|
||||
"end": { "line": 1, "column": 27 }
|
||||
}
|
||||
}
|
||||
],
|
||||
"strip": {},
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 25 },
|
||||
"end": { "line": 1, "column": 27 }
|
||||
}
|
||||
},
|
||||
"openStrip": { "open": false, "close": false },
|
||||
"inverseStrip": { "open": false, "close": false },
|
||||
"closeStrip": { "open": false, "close": false },
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 0 },
|
||||
"end": { "line": 1, "column": 34 }
|
||||
}
|
||||
}
|
||||
],
|
||||
"strip": {},
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 0 },
|
||||
"end": { "line": 1, "column": 34 }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{{#if active}}yes{{else}}no{{/if}}
|
||||
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"type": "Program",
|
||||
"body": [
|
||||
{
|
||||
"type": "MustacheStatement",
|
||||
"path": {
|
||||
"type": "PathExpression",
|
||||
"this": false,
|
||||
"data": false,
|
||||
"depth": 0,
|
||||
"head": "helper",
|
||||
"tail": [],
|
||||
"parts": ["helper"],
|
||||
"original": "helper",
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 2 },
|
||||
"end": { "line": 1, "column": 8 }
|
||||
}
|
||||
},
|
||||
"params": [
|
||||
{
|
||||
"type": "NumberLiteral",
|
||||
"value": 42,
|
||||
"original": 42,
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 9 },
|
||||
"end": { "line": 1, "column": 11 }
|
||||
}
|
||||
}
|
||||
],
|
||||
"escaped": true,
|
||||
"strip": { "open": false, "close": false },
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 0 },
|
||||
"end": { "line": 1, "column": 13 }
|
||||
}
|
||||
}
|
||||
],
|
||||
"strip": {},
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 0 },
|
||||
"end": { "line": 1, "column": 13 }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{{helper 42}}
|
||||
@@ -0,0 +1,53 @@
|
||||
{
|
||||
"type": "Program",
|
||||
"body": [
|
||||
{
|
||||
"type": "MustacheStatement",
|
||||
"path": {
|
||||
"type": "PathExpression",
|
||||
"this": false,
|
||||
"data": false,
|
||||
"depth": 0,
|
||||
"head": "helper",
|
||||
"tail": [],
|
||||
"parts": ["helper"],
|
||||
"original": "helper",
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 2 },
|
||||
"end": { "line": 1, "column": 8 }
|
||||
}
|
||||
},
|
||||
"params": [
|
||||
{
|
||||
"type": "BooleanLiteral",
|
||||
"value": true,
|
||||
"original": true,
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 9 },
|
||||
"end": { "line": 1, "column": 13 }
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "BooleanLiteral",
|
||||
"value": false,
|
||||
"original": false,
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 14 },
|
||||
"end": { "line": 1, "column": 19 }
|
||||
}
|
||||
}
|
||||
],
|
||||
"escaped": true,
|
||||
"strip": { "open": false, "close": false },
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 0 },
|
||||
"end": { "line": 1, "column": 21 }
|
||||
}
|
||||
}
|
||||
],
|
||||
"strip": {},
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 0 },
|
||||
"end": { "line": 1, "column": 21 }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{{helper true false}}
|
||||
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"type": "Program",
|
||||
"body": [
|
||||
{
|
||||
"type": "MustacheStatement",
|
||||
"path": {
|
||||
"type": "PathExpression",
|
||||
"this": false,
|
||||
"data": false,
|
||||
"depth": 0,
|
||||
"head": "helper",
|
||||
"tail": [],
|
||||
"parts": ["helper"],
|
||||
"original": "helper",
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 2 },
|
||||
"end": { "line": 1, "column": 8 }
|
||||
}
|
||||
},
|
||||
"params": [
|
||||
{
|
||||
"type": "StringLiteral",
|
||||
"value": "str",
|
||||
"original": "str",
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 9 },
|
||||
"end": { "line": 1, "column": 14 }
|
||||
}
|
||||
}
|
||||
],
|
||||
"escaped": true,
|
||||
"strip": { "open": false, "close": false },
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 0 },
|
||||
"end": { "line": 1, "column": 16 }
|
||||
}
|
||||
}
|
||||
],
|
||||
"strip": {},
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 0 },
|
||||
"end": { "line": 1, "column": 16 }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{{helper "str"}}
|
||||
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"type": "Program",
|
||||
"body": [
|
||||
{
|
||||
"type": "MustacheStatement",
|
||||
"path": {
|
||||
"type": "PathExpression",
|
||||
"this": false,
|
||||
"data": false,
|
||||
"depth": 0,
|
||||
"head": "foo",
|
||||
"tail": ["bar", "baz"],
|
||||
"parts": ["foo", "bar", "baz"],
|
||||
"original": "foo.bar.baz",
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 2 },
|
||||
"end": { "line": 1, "column": 13 }
|
||||
}
|
||||
},
|
||||
"params": [],
|
||||
"escaped": true,
|
||||
"strip": { "open": false, "close": false },
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 0 },
|
||||
"end": { "line": 1, "column": 15 }
|
||||
}
|
||||
}
|
||||
],
|
||||
"strip": {},
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 0 },
|
||||
"end": { "line": 1, "column": 15 }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{{foo.bar.baz}}
|
||||
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"type": "Program",
|
||||
"body": [
|
||||
{
|
||||
"type": "MustacheStatement",
|
||||
"path": {
|
||||
"type": "PathExpression",
|
||||
"this": false,
|
||||
"data": false,
|
||||
"depth": 2,
|
||||
"head": "parent",
|
||||
"tail": [],
|
||||
"parts": ["parent"],
|
||||
"original": "../../parent",
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 2 },
|
||||
"end": { "line": 1, "column": 14 }
|
||||
}
|
||||
},
|
||||
"params": [],
|
||||
"escaped": true,
|
||||
"strip": { "open": false, "close": false },
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 0 },
|
||||
"end": { "line": 1, "column": 16 }
|
||||
}
|
||||
}
|
||||
],
|
||||
"strip": {},
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 0 },
|
||||
"end": { "line": 1, "column": 16 }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{{../../parent}}
|
||||
@@ -0,0 +1,69 @@
|
||||
{
|
||||
"type": "Program",
|
||||
"body": [
|
||||
{
|
||||
"type": "BlockStatement",
|
||||
"path": {
|
||||
"type": "PathExpression",
|
||||
"this": false,
|
||||
"data": false,
|
||||
"depth": 0,
|
||||
"head": "each",
|
||||
"tail": [],
|
||||
"parts": ["each"],
|
||||
"original": "each",
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 3 },
|
||||
"end": { "line": 1, "column": 7 }
|
||||
}
|
||||
},
|
||||
"params": [
|
||||
{
|
||||
"type": "PathExpression",
|
||||
"this": false,
|
||||
"data": false,
|
||||
"depth": 0,
|
||||
"head": "items",
|
||||
"tail": [],
|
||||
"parts": ["items"],
|
||||
"original": "items",
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 8 },
|
||||
"end": { "line": 1, "column": 13 }
|
||||
}
|
||||
}
|
||||
],
|
||||
"program": {
|
||||
"type": "Program",
|
||||
"body": [
|
||||
{
|
||||
"type": "ContentStatement",
|
||||
"original": "it",
|
||||
"value": "it",
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 29 },
|
||||
"end": { "line": 1, "column": 31 }
|
||||
}
|
||||
}
|
||||
],
|
||||
"strip": {},
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 29 },
|
||||
"end": { "line": 1, "column": 31 }
|
||||
},
|
||||
"blockParams": ["item", "idx"]
|
||||
},
|
||||
"openStrip": { "open": false, "close": false },
|
||||
"closeStrip": { "open": false, "close": false },
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 0 },
|
||||
"end": { "line": 1, "column": 40 }
|
||||
}
|
||||
}
|
||||
],
|
||||
"strip": {},
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 0 },
|
||||
"end": { "line": 1, "column": 40 }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{{#each items as |item idx|}}it{{/each}}
|
||||
@@ -0,0 +1,63 @@
|
||||
{
|
||||
"type": "Program",
|
||||
"body": [
|
||||
{
|
||||
"type": "DecoratorBlock",
|
||||
"path": {
|
||||
"type": "PathExpression",
|
||||
"this": false,
|
||||
"data": false,
|
||||
"depth": 0,
|
||||
"head": "inline",
|
||||
"tail": [],
|
||||
"parts": ["inline"],
|
||||
"original": "inline",
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 4 },
|
||||
"end": { "line": 1, "column": 10 }
|
||||
}
|
||||
},
|
||||
"params": [
|
||||
{
|
||||
"type": "StringLiteral",
|
||||
"value": "foo",
|
||||
"original": "foo",
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 11 },
|
||||
"end": { "line": 1, "column": 16 }
|
||||
}
|
||||
}
|
||||
],
|
||||
"program": {
|
||||
"type": "Program",
|
||||
"body": [
|
||||
{
|
||||
"type": "ContentStatement",
|
||||
"original": "bar",
|
||||
"value": "bar",
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 18 },
|
||||
"end": { "line": 1, "column": 21 }
|
||||
}
|
||||
}
|
||||
],
|
||||
"strip": {},
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 18 },
|
||||
"end": { "line": 1, "column": 21 }
|
||||
}
|
||||
},
|
||||
"openStrip": { "open": false, "close": false },
|
||||
"closeStrip": { "open": false, "close": false },
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 0 },
|
||||
"end": { "line": 1, "column": 32 }
|
||||
}
|
||||
}
|
||||
],
|
||||
"strip": {},
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 0 },
|
||||
"end": { "line": 1, "column": 32 }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{{#*inline "foo"}}bar{{/inline}}
|
||||
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"type": "Program",
|
||||
"body": [
|
||||
{
|
||||
"type": "ContentStatement",
|
||||
"original": "before ",
|
||||
"value": "before ",
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 0 },
|
||||
"end": { "line": 1, "column": 7 }
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "MustacheStatement",
|
||||
"path": {
|
||||
"type": "PathExpression",
|
||||
"this": false,
|
||||
"data": false,
|
||||
"depth": 0,
|
||||
"head": "name",
|
||||
"tail": [],
|
||||
"parts": ["name"],
|
||||
"original": "name",
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 9 },
|
||||
"end": { "line": 1, "column": 13 }
|
||||
}
|
||||
},
|
||||
"params": [],
|
||||
"escaped": true,
|
||||
"strip": { "open": false, "close": false },
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 7 },
|
||||
"end": { "line": 1, "column": 15 }
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "ContentStatement",
|
||||
"original": " after",
|
||||
"value": " after",
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 15 },
|
||||
"end": { "line": 1, "column": 21 }
|
||||
}
|
||||
}
|
||||
],
|
||||
"strip": {},
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 0 },
|
||||
"end": { "line": 1, "column": 21 }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
before {{name}} after
|
||||
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"type": "Program",
|
||||
"body": [
|
||||
{
|
||||
"type": "ContentStatement",
|
||||
"original": "before ",
|
||||
"value": "before ",
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 0 },
|
||||
"end": { "line": 1, "column": 7 }
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "MustacheStatement",
|
||||
"path": {
|
||||
"type": "PathExpression",
|
||||
"this": false,
|
||||
"data": false,
|
||||
"depth": 0,
|
||||
"head": "name",
|
||||
"tail": [],
|
||||
"parts": ["name"],
|
||||
"original": "name",
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 9 },
|
||||
"end": { "line": 1, "column": 13 }
|
||||
}
|
||||
},
|
||||
"params": [],
|
||||
"escaped": true,
|
||||
"strip": { "open": false, "close": false },
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 7 },
|
||||
"end": { "line": 1, "column": 15 }
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "ContentStatement",
|
||||
"original": " after",
|
||||
"value": " after",
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 15 },
|
||||
"end": { "line": 1, "column": 21 }
|
||||
}
|
||||
}
|
||||
],
|
||||
"strip": {},
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 0 },
|
||||
"end": { "line": 1, "column": 21 }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
before {{name}} after
|
||||
@@ -0,0 +1,68 @@
|
||||
{
|
||||
"type": "Program",
|
||||
"body": [
|
||||
{
|
||||
"type": "BlockStatement",
|
||||
"path": {
|
||||
"type": "PathExpression",
|
||||
"this": false,
|
||||
"data": false,
|
||||
"depth": 0,
|
||||
"head": "each",
|
||||
"tail": [],
|
||||
"parts": ["each"],
|
||||
"original": "each",
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 3 },
|
||||
"end": { "line": 1, "column": 7 }
|
||||
}
|
||||
},
|
||||
"params": [
|
||||
{
|
||||
"type": "PathExpression",
|
||||
"this": false,
|
||||
"data": false,
|
||||
"depth": 0,
|
||||
"head": "items",
|
||||
"tail": [],
|
||||
"parts": ["items"],
|
||||
"original": "items",
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 8 },
|
||||
"end": { "line": 1, "column": 13 }
|
||||
}
|
||||
}
|
||||
],
|
||||
"program": {
|
||||
"type": "Program",
|
||||
"body": [
|
||||
{
|
||||
"type": "ContentStatement",
|
||||
"original": "item",
|
||||
"value": "item",
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 15 },
|
||||
"end": { "line": 1, "column": 19 }
|
||||
}
|
||||
}
|
||||
],
|
||||
"strip": {},
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 15 },
|
||||
"end": { "line": 1, "column": 19 }
|
||||
}
|
||||
},
|
||||
"openStrip": { "open": false, "close": false },
|
||||
"closeStrip": { "open": false, "close": false },
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 0 },
|
||||
"end": { "line": 1, "column": 28 }
|
||||
}
|
||||
}
|
||||
],
|
||||
"strip": {},
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 0 },
|
||||
"end": { "line": 1, "column": 28 }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{{#each items}}item{{/each}}
|
||||
@@ -0,0 +1,68 @@
|
||||
{
|
||||
"type": "Program",
|
||||
"body": [
|
||||
{
|
||||
"type": "BlockStatement",
|
||||
"path": {
|
||||
"type": "PathExpression",
|
||||
"this": false,
|
||||
"data": false,
|
||||
"depth": 0,
|
||||
"head": "each",
|
||||
"tail": [],
|
||||
"parts": ["each"],
|
||||
"original": "each",
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 3 },
|
||||
"end": { "line": 1, "column": 7 }
|
||||
}
|
||||
},
|
||||
"params": [
|
||||
{
|
||||
"type": "PathExpression",
|
||||
"this": false,
|
||||
"data": false,
|
||||
"depth": 0,
|
||||
"head": "items",
|
||||
"tail": [],
|
||||
"parts": ["items"],
|
||||
"original": "items",
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 8 },
|
||||
"end": { "line": 1, "column": 13 }
|
||||
}
|
||||
}
|
||||
],
|
||||
"program": {
|
||||
"type": "Program",
|
||||
"body": [
|
||||
{
|
||||
"type": "ContentStatement",
|
||||
"original": "item",
|
||||
"value": "item",
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 15 },
|
||||
"end": { "line": 1, "column": 19 }
|
||||
}
|
||||
}
|
||||
],
|
||||
"strip": {},
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 15 },
|
||||
"end": { "line": 1, "column": 19 }
|
||||
}
|
||||
},
|
||||
"openStrip": { "open": false, "close": false },
|
||||
"closeStrip": { "open": false, "close": false },
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 0 },
|
||||
"end": { "line": 1, "column": 28 }
|
||||
}
|
||||
}
|
||||
],
|
||||
"strip": {},
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 0 },
|
||||
"end": { "line": 1, "column": 28 }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{{#each items}}item{{/each}}
|
||||
@@ -0,0 +1,53 @@
|
||||
{
|
||||
"type": "Program",
|
||||
"body": [
|
||||
{
|
||||
"type": "BlockStatement",
|
||||
"path": {
|
||||
"type": "PathExpression",
|
||||
"this": false,
|
||||
"data": false,
|
||||
"depth": 0,
|
||||
"head": "inverted",
|
||||
"tail": [],
|
||||
"parts": ["inverted"],
|
||||
"original": "inverted",
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 3 },
|
||||
"end": { "line": 1, "column": 11 }
|
||||
}
|
||||
},
|
||||
"params": [],
|
||||
"inverse": {
|
||||
"type": "Program",
|
||||
"body": [
|
||||
{
|
||||
"type": "ContentStatement",
|
||||
"original": "body",
|
||||
"value": "body",
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 13 },
|
||||
"end": { "line": 1, "column": 17 }
|
||||
}
|
||||
}
|
||||
],
|
||||
"strip": {},
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 13 },
|
||||
"end": { "line": 1, "column": 17 }
|
||||
}
|
||||
},
|
||||
"openStrip": { "open": false, "close": false },
|
||||
"closeStrip": { "open": false, "close": false },
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 0 },
|
||||
"end": { "line": 1, "column": 30 }
|
||||
}
|
||||
}
|
||||
],
|
||||
"strip": {},
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 0 },
|
||||
"end": { "line": 1, "column": 30 }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{{^inverted}}body{{/inverted}}
|
||||
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"type": "Program",
|
||||
"body": [
|
||||
{
|
||||
"type": "PartialStatement",
|
||||
"name": {
|
||||
"type": "PathExpression",
|
||||
"this": false,
|
||||
"data": false,
|
||||
"depth": 0,
|
||||
"head": "partial",
|
||||
"tail": [],
|
||||
"parts": ["partial"],
|
||||
"original": "partial",
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 4 },
|
||||
"end": { "line": 1, "column": 11 }
|
||||
}
|
||||
},
|
||||
"params": [],
|
||||
"indent": "",
|
||||
"strip": { "open": false, "close": false },
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 0 },
|
||||
"end": { "line": 1, "column": 13 }
|
||||
}
|
||||
}
|
||||
],
|
||||
"strip": {},
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 0 },
|
||||
"end": { "line": 1, "column": 13 }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{{> partial}}
|
||||
@@ -0,0 +1,53 @@
|
||||
{
|
||||
"type": "Program",
|
||||
"body": [
|
||||
{
|
||||
"type": "PartialBlockStatement",
|
||||
"name": {
|
||||
"type": "PathExpression",
|
||||
"this": false,
|
||||
"data": false,
|
||||
"depth": 0,
|
||||
"head": "layout",
|
||||
"tail": [],
|
||||
"parts": ["layout"],
|
||||
"original": "layout",
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 5 },
|
||||
"end": { "line": 1, "column": 11 }
|
||||
}
|
||||
},
|
||||
"params": [],
|
||||
"program": {
|
||||
"type": "Program",
|
||||
"body": [
|
||||
{
|
||||
"type": "ContentStatement",
|
||||
"original": "body",
|
||||
"value": "body",
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 13 },
|
||||
"end": { "line": 1, "column": 17 }
|
||||
}
|
||||
}
|
||||
],
|
||||
"strip": {},
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 13 },
|
||||
"end": { "line": 1, "column": 17 }
|
||||
}
|
||||
},
|
||||
"openStrip": { "open": false, "close": false },
|
||||
"closeStrip": { "open": false, "close": false },
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 0 },
|
||||
"end": { "line": 1, "column": 28 }
|
||||
}
|
||||
}
|
||||
],
|
||||
"strip": {},
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 0 },
|
||||
"end": { "line": 1, "column": 28 }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{{#> layout}}body{{/layout}}
|
||||
@@ -0,0 +1,80 @@
|
||||
{
|
||||
"type": "Program",
|
||||
"body": [
|
||||
{
|
||||
"type": "MustacheStatement",
|
||||
"path": {
|
||||
"type": "PathExpression",
|
||||
"this": false,
|
||||
"data": false,
|
||||
"depth": 0,
|
||||
"head": "helper",
|
||||
"tail": [],
|
||||
"parts": ["helper"],
|
||||
"original": "helper",
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 2 },
|
||||
"end": { "line": 1, "column": 8 }
|
||||
}
|
||||
},
|
||||
"params": [
|
||||
{
|
||||
"type": "PathExpression",
|
||||
"this": false,
|
||||
"data": false,
|
||||
"depth": 0,
|
||||
"head": "param1",
|
||||
"tail": [],
|
||||
"parts": ["param1"],
|
||||
"original": "param1",
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 9 },
|
||||
"end": { "line": 1, "column": 15 }
|
||||
}
|
||||
}
|
||||
],
|
||||
"hash": {
|
||||
"type": "Hash",
|
||||
"pairs": [
|
||||
{
|
||||
"type": "HashPair",
|
||||
"key": "key",
|
||||
"value": {
|
||||
"type": "PathExpression",
|
||||
"this": false,
|
||||
"data": false,
|
||||
"depth": 0,
|
||||
"head": "value",
|
||||
"tail": [],
|
||||
"parts": ["value"],
|
||||
"original": "value",
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 20 },
|
||||
"end": { "line": 1, "column": 25 }
|
||||
}
|
||||
},
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 16 },
|
||||
"end": { "line": 1, "column": 25 }
|
||||
}
|
||||
}
|
||||
],
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 16 },
|
||||
"end": { "line": 1, "column": 25 }
|
||||
}
|
||||
},
|
||||
"escaped": true,
|
||||
"strip": { "open": false, "close": false },
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 0 },
|
||||
"end": { "line": 1, "column": 27 }
|
||||
}
|
||||
}
|
||||
],
|
||||
"strip": {},
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 0 },
|
||||
"end": { "line": 1, "column": 27 }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{{helper param1 key=value}}
|
||||
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"type": "Program",
|
||||
"body": [
|
||||
{
|
||||
"type": "MustacheStatement",
|
||||
"path": {
|
||||
"type": "PathExpression",
|
||||
"this": false,
|
||||
"data": false,
|
||||
"depth": 0,
|
||||
"head": "helper",
|
||||
"tail": [],
|
||||
"parts": ["helper"],
|
||||
"original": "helper",
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 2 },
|
||||
"end": { "line": 1, "column": 8 }
|
||||
}
|
||||
},
|
||||
"params": [
|
||||
{
|
||||
"type": "NumberLiteral",
|
||||
"value": 42,
|
||||
"original": 42,
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 9 },
|
||||
"end": { "line": 1, "column": 11 }
|
||||
}
|
||||
}
|
||||
],
|
||||
"escaped": true,
|
||||
"strip": { "open": false, "close": false },
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 0 },
|
||||
"end": { "line": 1, "column": 13 }
|
||||
}
|
||||
}
|
||||
],
|
||||
"strip": {},
|
||||
"loc": {
|
||||
"start": { "line": 1, "column": 0 },
|
||||
"end": { "line": 1, "column": 13 }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{{helper 42}}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user