react / wstein / node_modules / jest-cli / node_modules / istanbul / node_modules / handlebars / dist / cjs / handlebars / compiler / javascript-compiler.js
80728 views"use strict";1var COMPILER_REVISION = require("../base").COMPILER_REVISION;2var REVISION_CHANGES = require("../base").REVISION_CHANGES;3var Exception = require("../exception")["default"];4var isArray = require("../utils").isArray;5var CodeGen = require("./code-gen")["default"];67function Literal(value) {8this.value = value;9}1011function JavaScriptCompiler() {}1213JavaScriptCompiler.prototype = {14// PUBLIC API: You can override these methods in a subclass to provide15// alternative compiled forms for name lookup and buffering semantics16nameLookup: function(parent, name /* , type*/) {17if (JavaScriptCompiler.isValidJavaScriptVariableName(name)) {18return [parent, ".", name];19} else {20return [parent, "['", name, "']"];21}22},23depthedLookup: function(name) {24return [this.aliasable('this.lookup'), '(depths, "', name, '")'];25},2627compilerInfo: function() {28var revision = COMPILER_REVISION,29versions = REVISION_CHANGES[revision];30return [revision, versions];31},3233appendToBuffer: function(source, location, explicit) {34// Force a source as this simplifies the merge logic.35if (!isArray(source)) {36source = [source];37}38source = this.source.wrap(source, location);3940if (this.environment.isSimple) {41return ['return ', source, ';'];42} else if (explicit) {43// This is a case where the buffer operation occurs as a child of another44// construct, generally braces. We have to explicitly output these buffer45// operations to ensure that the emitted code goes in the correct location.46return ['buffer += ', source, ';'];47} else {48source.appendToBuffer = true;49return source;50}51},5253initializeBuffer: function() {54return this.quotedString("");55},56// END PUBLIC API5758compile: function(environment, options, context, asObject) {59this.environment = environment;60this.options = options;61this.stringParams = this.options.stringParams;62this.trackIds = this.options.trackIds;63this.precompile = !asObject;6465this.name = this.environment.name;66this.isChild = !!context;67this.context = context || {68programs: [],69environments: []70};7172this.preamble();7374this.stackSlot = 0;75this.stackVars = [];76this.aliases = {};77this.registers = { list: [] };78this.hashes = [];79this.compileStack = [];80this.inlineStack = [];81this.blockParams = [];8283this.compileChildren(environment, options);8485this.useDepths = this.useDepths || environment.useDepths || this.options.compat;86this.useBlockParams = this.useBlockParams || environment.useBlockParams;8788var opcodes = environment.opcodes,89opcode,90firstLoc,91i,92l;9394for (i = 0, l = opcodes.length; i < l; i++) {95opcode = opcodes[i];9697this.source.currentLocation = opcode.loc;98firstLoc = firstLoc || opcode.loc;99this[opcode.opcode].apply(this, opcode.args);100}101102// Flush any trailing content that might be pending.103this.source.currentLocation = firstLoc;104this.pushSource('');105106/* istanbul ignore next */107if (this.stackSlot || this.inlineStack.length || this.compileStack.length) {108throw new Exception('Compile completed with content left on stack');109}110111var fn = this.createFunctionContext(asObject);112if (!this.isChild) {113var ret = {114compiler: this.compilerInfo(),115main: fn116};117var programs = this.context.programs;118for (i = 0, l = programs.length; i < l; i++) {119if (programs[i]) {120ret[i] = programs[i];121}122}123124if (this.environment.usePartial) {125ret.usePartial = true;126}127if (this.options.data) {128ret.useData = true;129}130if (this.useDepths) {131ret.useDepths = true;132}133if (this.useBlockParams) {134ret.useBlockParams = true;135}136if (this.options.compat) {137ret.compat = true;138}139140if (!asObject) {141ret.compiler = JSON.stringify(ret.compiler);142143this.source.currentLocation = {start: {line: 1, column: 0}};144ret = this.objectLiteral(ret);145146if (options.srcName) {147ret = ret.toStringWithSourceMap({file: options.destName});148ret.map = ret.map && ret.map.toString();149} else {150ret = ret.toString();151}152} else {153ret.compilerOptions = this.options;154}155156return ret;157} else {158return fn;159}160},161162preamble: function() {163// track the last context pushed into place to allow skipping the164// getContext opcode when it would be a noop165this.lastContext = 0;166this.source = new CodeGen(this.options.srcName);167},168169createFunctionContext: function(asObject) {170var varDeclarations = '';171172var locals = this.stackVars.concat(this.registers.list);173if(locals.length > 0) {174varDeclarations += ", " + locals.join(", ");175}176177// Generate minimizer alias mappings178//179// When using true SourceNodes, this will update all references to the given alias180// as the source nodes are reused in situ. For the non-source node compilation mode,181// aliases will not be used, but this case is already being run on the client and182// we aren't concern about minimizing the template size.183var aliasCount = 0;184for (var alias in this.aliases) {185var node = this.aliases[alias];186187if (this.aliases.hasOwnProperty(alias) && node.children && node.referenceCount > 1) {188varDeclarations += ', alias' + (++aliasCount) + '=' + alias;189node.children[0] = 'alias' + aliasCount;190}191}192193var params = ["depth0", "helpers", "partials", "data"];194195if (this.useBlockParams || this.useDepths) {196params.push('blockParams');197}198if (this.useDepths) {199params.push('depths');200}201202// Perform a second pass over the output to merge content when possible203var source = this.mergeSource(varDeclarations);204205if (asObject) {206params.push(source);207208return Function.apply(this, params);209} else {210return this.source.wrap(['function(', params.join(','), ') {\n ', source, '}']);211}212},213mergeSource: function(varDeclarations) {214var isSimple = this.environment.isSimple,215appendOnly = !this.forceBuffer,216appendFirst,217218sourceSeen,219bufferStart,220bufferEnd;221this.source.each(function(line) {222if (line.appendToBuffer) {223if (bufferStart) {224line.prepend(' + ');225} else {226bufferStart = line;227}228bufferEnd = line;229} else {230if (bufferStart) {231if (!sourceSeen) {232appendFirst = true;233} else {234bufferStart.prepend('buffer += ');235}236bufferEnd.add(';');237bufferStart = bufferEnd = undefined;238}239240sourceSeen = true;241if (!isSimple) {242appendOnly = false;243}244}245});246247248if (appendOnly) {249if (bufferStart) {250bufferStart.prepend('return ');251bufferEnd.add(';');252} else if (!sourceSeen) {253this.source.push('return "";');254}255} else {256varDeclarations += ", buffer = " + (appendFirst ? '' : this.initializeBuffer());257258if (bufferStart) {259bufferStart.prepend('return buffer + ');260bufferEnd.add(';');261} else {262this.source.push('return buffer;');263}264}265266if (varDeclarations) {267this.source.prepend('var ' + varDeclarations.substring(2) + (appendFirst ? '' : ';\n'));268}269270return this.source.merge();271},272273// [blockValue]274//275// On stack, before: hash, inverse, program, value276// On stack, after: return value of blockHelperMissing277//278// The purpose of this opcode is to take a block of the form279// `{{#this.foo}}...{{/this.foo}}`, resolve the value of `foo`, and280// replace it on the stack with the result of properly281// invoking blockHelperMissing.282blockValue: function(name) {283var blockHelperMissing = this.aliasable('helpers.blockHelperMissing'),284params = [this.contextName(0)];285this.setupHelperArgs(name, 0, params);286287var blockName = this.popStack();288params.splice(1, 0, blockName);289290this.push(this.source.functionCall(blockHelperMissing, 'call', params));291},292293// [ambiguousBlockValue]294//295// On stack, before: hash, inverse, program, value296// Compiler value, before: lastHelper=value of last found helper, if any297// On stack, after, if no lastHelper: same as [blockValue]298// On stack, after, if lastHelper: value299ambiguousBlockValue: function() {300// We're being a bit cheeky and reusing the options value from the prior exec301var blockHelperMissing = this.aliasable('helpers.blockHelperMissing'),302params = [this.contextName(0)];303this.setupHelperArgs('', 0, params, true);304305this.flushInline();306307var current = this.topStack();308params.splice(1, 0, current);309310this.pushSource([311'if (!', this.lastHelper, ') { ',312current, ' = ', this.source.functionCall(blockHelperMissing, 'call', params),313'}']);314},315316// [appendContent]317//318// On stack, before: ...319// On stack, after: ...320//321// Appends the string value of `content` to the current buffer322appendContent: function(content) {323if (this.pendingContent) {324content = this.pendingContent + content;325} else {326this.pendingLocation = this.source.currentLocation;327}328329this.pendingContent = content;330},331332// [append]333//334// On stack, before: value, ...335// On stack, after: ...336//337// Coerces `value` to a String and appends it to the current buffer.338//339// If `value` is truthy, or 0, it is coerced into a string and appended340// Otherwise, the empty string is appended341append: function() {342if (this.isInline()) {343this.replaceStack(function(current) {344return [' != null ? ', current, ' : ""'];345});346347this.pushSource(this.appendToBuffer(this.popStack()));348} else {349var local = this.popStack();350this.pushSource(['if (', local, ' != null) { ', this.appendToBuffer(local, undefined, true), ' }']);351if (this.environment.isSimple) {352this.pushSource(['else { ', this.appendToBuffer("''", undefined, true), ' }']);353}354}355},356357// [appendEscaped]358//359// On stack, before: value, ...360// On stack, after: ...361//362// Escape `value` and append it to the buffer363appendEscaped: function() {364this.pushSource(this.appendToBuffer(365[this.aliasable('this.escapeExpression'), '(', this.popStack(), ')']));366},367368// [getContext]369//370// On stack, before: ...371// On stack, after: ...372// Compiler value, after: lastContext=depth373//374// Set the value of the `lastContext` compiler value to the depth375getContext: function(depth) {376this.lastContext = depth;377},378379// [pushContext]380//381// On stack, before: ...382// On stack, after: currentContext, ...383//384// Pushes the value of the current context onto the stack.385pushContext: function() {386this.pushStackLiteral(this.contextName(this.lastContext));387},388389// [lookupOnContext]390//391// On stack, before: ...392// On stack, after: currentContext[name], ...393//394// Looks up the value of `name` on the current context and pushes395// it onto the stack.396lookupOnContext: function(parts, falsy, scoped) {397var i = 0;398399if (!scoped && this.options.compat && !this.lastContext) {400// The depthed query is expected to handle the undefined logic for the root level that401// is implemented below, so we evaluate that directly in compat mode402this.push(this.depthedLookup(parts[i++]));403} else {404this.pushContext();405}406407this.resolvePath('context', parts, i, falsy);408},409410// [lookupBlockParam]411//412// On stack, before: ...413// On stack, after: blockParam[name], ...414//415// Looks up the value of `parts` on the given block param and pushes416// it onto the stack.417lookupBlockParam: function(blockParamId, parts) {418this.useBlockParams = true;419420this.push(['blockParams[', blockParamId[0], '][', blockParamId[1], ']']);421this.resolvePath('context', parts, 1);422},423424// [lookupData]425//426// On stack, before: ...427// On stack, after: data, ...428//429// Push the data lookup operator430lookupData: function(depth, parts) {431/*jshint -W083 */432if (!depth) {433this.pushStackLiteral('data');434} else {435this.pushStackLiteral('this.data(data, ' + depth + ')');436}437438this.resolvePath('data', parts, 0, true);439},440441resolvePath: function(type, parts, i, falsy) {442/*jshint -W083 */443if (this.options.strict || this.options.assumeObjects) {444this.push(strictLookup(this.options.strict, this, parts, type));445return;446}447448var len = parts.length;449for (; i < len; i++) {450this.replaceStack(function(current) {451var lookup = this.nameLookup(current, parts[i], type);452// We want to ensure that zero and false are handled properly if the context (falsy flag)453// needs to have the special handling for these values.454if (!falsy) {455return [' != null ? ', lookup, ' : ', current];456} else {457// Otherwise we can use generic falsy handling458return [' && ', lookup];459}460});461}462},463464// [resolvePossibleLambda]465//466// On stack, before: value, ...467// On stack, after: resolved value, ...468//469// If the `value` is a lambda, replace it on the stack by470// the return value of the lambda471resolvePossibleLambda: function() {472this.push([this.aliasable('this.lambda'), '(', this.popStack(), ', ', this.contextName(0), ')']);473},474475// [pushStringParam]476//477// On stack, before: ...478// On stack, after: string, currentContext, ...479//480// This opcode is designed for use in string mode, which481// provides the string value of a parameter along with its482// depth rather than resolving it immediately.483pushStringParam: function(string, type) {484this.pushContext();485this.pushString(type);486487// If it's a subexpression, the string result488// will be pushed after this opcode.489if (type !== 'SubExpression') {490if (typeof string === 'string') {491this.pushString(string);492} else {493this.pushStackLiteral(string);494}495}496},497498emptyHash: function(omitEmpty) {499if (this.trackIds) {500this.push('{}'); // hashIds501}502if (this.stringParams) {503this.push('{}'); // hashContexts504this.push('{}'); // hashTypes505}506this.pushStackLiteral(omitEmpty ? 'undefined' : '{}');507},508pushHash: function() {509if (this.hash) {510this.hashes.push(this.hash);511}512this.hash = {values: [], types: [], contexts: [], ids: []};513},514popHash: function() {515var hash = this.hash;516this.hash = this.hashes.pop();517518if (this.trackIds) {519this.push(this.objectLiteral(hash.ids));520}521if (this.stringParams) {522this.push(this.objectLiteral(hash.contexts));523this.push(this.objectLiteral(hash.types));524}525526this.push(this.objectLiteral(hash.values));527},528529// [pushString]530//531// On stack, before: ...532// On stack, after: quotedString(string), ...533//534// Push a quoted version of `string` onto the stack535pushString: function(string) {536this.pushStackLiteral(this.quotedString(string));537},538539// [pushLiteral]540//541// On stack, before: ...542// On stack, after: value, ...543//544// Pushes a value onto the stack. This operation prevents545// the compiler from creating a temporary variable to hold546// it.547pushLiteral: function(value) {548this.pushStackLiteral(value);549},550551// [pushProgram]552//553// On stack, before: ...554// On stack, after: program(guid), ...555//556// Push a program expression onto the stack. This takes557// a compile-time guid and converts it into a runtime-accessible558// expression.559pushProgram: function(guid) {560if (guid != null) {561this.pushStackLiteral(this.programExpression(guid));562} else {563this.pushStackLiteral(null);564}565},566567// [invokeHelper]568//569// On stack, before: hash, inverse, program, params..., ...570// On stack, after: result of helper invocation571//572// Pops off the helper's parameters, invokes the helper,573// and pushes the helper's return value onto the stack.574//575// If the helper is not found, `helperMissing` is called.576invokeHelper: function(paramSize, name, isSimple) {577var nonHelper = this.popStack();578var helper = this.setupHelper(paramSize, name);579var simple = isSimple ? [helper.name, ' || '] : '';580581var lookup = ['('].concat(simple, nonHelper);582if (!this.options.strict) {583lookup.push(' || ', this.aliasable('helpers.helperMissing'));584}585lookup.push(')');586587this.push(this.source.functionCall(lookup, 'call', helper.callParams));588},589590// [invokeKnownHelper]591//592// On stack, before: hash, inverse, program, params..., ...593// On stack, after: result of helper invocation594//595// This operation is used when the helper is known to exist,596// so a `helperMissing` fallback is not required.597invokeKnownHelper: function(paramSize, name) {598var helper = this.setupHelper(paramSize, name);599this.push(this.source.functionCall(helper.name, 'call', helper.callParams));600},601602// [invokeAmbiguous]603//604// On stack, before: hash, inverse, program, params..., ...605// On stack, after: result of disambiguation606//607// This operation is used when an expression like `{{foo}}`608// is provided, but we don't know at compile-time whether it609// is a helper or a path.610//611// This operation emits more code than the other options,612// and can be avoided by passing the `knownHelpers` and613// `knownHelpersOnly` flags at compile-time.614invokeAmbiguous: function(name, helperCall) {615this.useRegister('helper');616617var nonHelper = this.popStack();618619this.emptyHash();620var helper = this.setupHelper(0, name, helperCall);621622var helperName = this.lastHelper = this.nameLookup('helpers', name, 'helper');623624var lookup = ['(', '(helper = ', helperName, ' || ', nonHelper, ')'];625if (!this.options.strict) {626lookup[0] = '(helper = ';627lookup.push(628' != null ? helper : ',629this.aliasable('helpers.helperMissing')630);631}632633this.push([634'(', lookup,635(helper.paramsInit ? ['),(', helper.paramsInit] : []), '),',636'(typeof helper === ', this.aliasable('"function"'), ' ? ',637this.source.functionCall('helper','call', helper.callParams), ' : helper))'638]);639},640641// [invokePartial]642//643// On stack, before: context, ...644// On stack after: result of partial invocation645//646// This operation pops off a context, invokes a partial with that context,647// and pushes the result of the invocation back.648invokePartial: function(isDynamic, name, indent) {649var params = [],650options = this.setupParams(name, 1, params, false);651652if (isDynamic) {653name = this.popStack();654delete options.name;655}656657if (indent) {658options.indent = JSON.stringify(indent);659}660options.helpers = 'helpers';661options.partials = 'partials';662663if (!isDynamic) {664params.unshift(this.nameLookup('partials', name, 'partial'));665} else {666params.unshift(name);667}668669if (this.options.compat) {670options.depths = 'depths';671}672options = this.objectLiteral(options);673params.push(options);674675this.push(this.source.functionCall('this.invokePartial', '', params));676},677678// [assignToHash]679//680// On stack, before: value, ..., hash, ...681// On stack, after: ..., hash, ...682//683// Pops a value off the stack and assigns it to the current hash684assignToHash: function(key) {685var value = this.popStack(),686context,687type,688id;689690if (this.trackIds) {691id = this.popStack();692}693if (this.stringParams) {694type = this.popStack();695context = this.popStack();696}697698var hash = this.hash;699if (context) {700hash.contexts[key] = context;701}702if (type) {703hash.types[key] = type;704}705if (id) {706hash.ids[key] = id;707}708hash.values[key] = value;709},710711pushId: function(type, name, child) {712if (type === 'BlockParam') {713this.pushStackLiteral(714'blockParams[' + name[0] + '].path[' + name[1] + ']'715+ (child ? ' + ' + JSON.stringify('.' + child) : ''));716} else if (type === 'PathExpression') {717this.pushString(name);718} else if (type === 'SubExpression') {719this.pushStackLiteral('true');720} else {721this.pushStackLiteral('null');722}723},724725// HELPERS726727compiler: JavaScriptCompiler,728729compileChildren: function(environment, options) {730var children = environment.children, child, compiler;731732for(var i=0, l=children.length; i<l; i++) {733child = children[i];734compiler = new this.compiler();735736var index = this.matchExistingProgram(child);737738if (index == null) {739this.context.programs.push(''); // Placeholder to prevent name conflicts for nested children740index = this.context.programs.length;741child.index = index;742child.name = 'program' + index;743this.context.programs[index] = compiler.compile(child, options, this.context, !this.precompile);744this.context.environments[index] = child;745746this.useDepths = this.useDepths || compiler.useDepths;747this.useBlockParams = this.useBlockParams || compiler.useBlockParams;748} else {749child.index = index;750child.name = 'program' + index;751752this.useDepths = this.useDepths || child.useDepths;753this.useBlockParams = this.useBlockParams || child.useBlockParams;754}755}756},757matchExistingProgram: function(child) {758for (var i = 0, len = this.context.environments.length; i < len; i++) {759var environment = this.context.environments[i];760if (environment && environment.equals(child)) {761return i;762}763}764},765766programExpression: function(guid) {767var child = this.environment.children[guid],768programParams = [child.index, 'data', child.blockParams];769770if (this.useBlockParams || this.useDepths) {771programParams.push('blockParams');772}773if (this.useDepths) {774programParams.push('depths');775}776777return 'this.program(' + programParams.join(', ') + ')';778},779780useRegister: function(name) {781if(!this.registers[name]) {782this.registers[name] = true;783this.registers.list.push(name);784}785},786787push: function(expr) {788if (!(expr instanceof Literal)) {789expr = this.source.wrap(expr);790}791792this.inlineStack.push(expr);793return expr;794},795796pushStackLiteral: function(item) {797this.push(new Literal(item));798},799800pushSource: function(source) {801if (this.pendingContent) {802this.source.push(803this.appendToBuffer(this.source.quotedString(this.pendingContent), this.pendingLocation));804this.pendingContent = undefined;805}806807if (source) {808this.source.push(source);809}810},811812replaceStack: function(callback) {813var prefix = ['('],814stack,815createdStack,816usedLiteral;817818/* istanbul ignore next */819if (!this.isInline()) {820throw new Exception('replaceStack on non-inline');821}822823// We want to merge the inline statement into the replacement statement via ','824var top = this.popStack(true);825826if (top instanceof Literal) {827// Literals do not need to be inlined828stack = [top.value];829prefix = ['(', stack];830usedLiteral = true;831} else {832// Get or create the current stack name for use by the inline833createdStack = true;834var name = this.incrStack();835836prefix = ['((', this.push(name), ' = ', top, ')'];837stack = this.topStack();838}839840var item = callback.call(this, stack);841842if (!usedLiteral) {843this.popStack();844}845if (createdStack) {846this.stackSlot--;847}848this.push(prefix.concat(item, ')'));849},850851incrStack: function() {852this.stackSlot++;853if(this.stackSlot > this.stackVars.length) { this.stackVars.push("stack" + this.stackSlot); }854return this.topStackName();855},856topStackName: function() {857return "stack" + this.stackSlot;858},859flushInline: function() {860var inlineStack = this.inlineStack;861this.inlineStack = [];862for (var i = 0, len = inlineStack.length; i < len; i++) {863var entry = inlineStack[i];864/* istanbul ignore if */865if (entry instanceof Literal) {866this.compileStack.push(entry);867} else {868var stack = this.incrStack();869this.pushSource([stack, ' = ', entry, ';']);870this.compileStack.push(stack);871}872}873},874isInline: function() {875return this.inlineStack.length;876},877878popStack: function(wrapped) {879var inline = this.isInline(),880item = (inline ? this.inlineStack : this.compileStack).pop();881882if (!wrapped && (item instanceof Literal)) {883return item.value;884} else {885if (!inline) {886/* istanbul ignore next */887if (!this.stackSlot) {888throw new Exception('Invalid stack pop');889}890this.stackSlot--;891}892return item;893}894},895896topStack: function() {897var stack = (this.isInline() ? this.inlineStack : this.compileStack),898item = stack[stack.length - 1];899900/* istanbul ignore if */901if (item instanceof Literal) {902return item.value;903} else {904return item;905}906},907908contextName: function(context) {909if (this.useDepths && context) {910return 'depths[' + context + ']';911} else {912return 'depth' + context;913}914},915916quotedString: function(str) {917return this.source.quotedString(str);918},919920objectLiteral: function(obj) {921return this.source.objectLiteral(obj);922},923924aliasable: function(name) {925var ret = this.aliases[name];926if (ret) {927ret.referenceCount++;928return ret;929}930931ret = this.aliases[name] = this.source.wrap(name);932ret.aliasable = true;933ret.referenceCount = 1;934935return ret;936},937938setupHelper: function(paramSize, name, blockHelper) {939var params = [],940paramsInit = this.setupHelperArgs(name, paramSize, params, blockHelper);941var foundHelper = this.nameLookup('helpers', name, 'helper');942943return {944params: params,945paramsInit: paramsInit,946name: foundHelper,947callParams: [this.contextName(0)].concat(params)948};949},950951setupParams: function(helper, paramSize, params) {952var options = {}, contexts = [], types = [], ids = [], param;953954options.name = this.quotedString(helper);955options.hash = this.popStack();956957if (this.trackIds) {958options.hashIds = this.popStack();959}960if (this.stringParams) {961options.hashTypes = this.popStack();962options.hashContexts = this.popStack();963}964965var inverse = this.popStack(),966program = this.popStack();967968// Avoid setting fn and inverse if neither are set. This allows969// helpers to do a check for `if (options.fn)`970if (program || inverse) {971options.fn = program || 'this.noop';972options.inverse = inverse || 'this.noop';973}974975// The parameters go on to the stack in order (making sure that they are evaluated in order)976// so we need to pop them off the stack in reverse order977var i = paramSize;978while (i--) {979param = this.popStack();980params[i] = param;981982if (this.trackIds) {983ids[i] = this.popStack();984}985if (this.stringParams) {986types[i] = this.popStack();987contexts[i] = this.popStack();988}989}990991if (this.trackIds) {992options.ids = this.source.generateArray(ids);993}994if (this.stringParams) {995options.types = this.source.generateArray(types);996options.contexts = this.source.generateArray(contexts);997}998999if (this.options.data) {1000options.data = 'data';1001}1002if (this.useBlockParams) {1003options.blockParams = 'blockParams';1004}1005return options;1006},10071008setupHelperArgs: function(helper, paramSize, params, useRegister) {1009var options = this.setupParams(helper, paramSize, params, true);1010options = this.objectLiteral(options);1011if (useRegister) {1012this.useRegister('options');1013params.push('options');1014return ['options=', options];1015} else {1016params.push(options);1017return '';1018}1019}1020};102110221023var reservedWords = (1024"break else new var" +1025" case finally return void" +1026" catch for switch while" +1027" continue function this with" +1028" default if throw" +1029" delete in try" +1030" do instanceof typeof" +1031" abstract enum int short" +1032" boolean export interface static" +1033" byte extends long super" +1034" char final native synchronized" +1035" class float package throws" +1036" const goto private transient" +1037" debugger implements protected volatile" +1038" double import public let yield await" +1039" null true false"1040).split(" ");10411042var compilerWords = JavaScriptCompiler.RESERVED_WORDS = {};10431044for(var i=0, l=reservedWords.length; i<l; i++) {1045compilerWords[reservedWords[i]] = true;1046}10471048JavaScriptCompiler.isValidJavaScriptVariableName = function(name) {1049return !JavaScriptCompiler.RESERVED_WORDS[name] && /^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(name);1050};10511052function strictLookup(requireTerminal, compiler, parts, type) {1053var stack = compiler.popStack();10541055var i = 0,1056len = parts.length;1057if (requireTerminal) {1058len--;1059}10601061for (; i < len; i++) {1062stack = compiler.nameLookup(stack, parts[i], type);1063}10641065if (requireTerminal) {1066return [compiler.aliasable('this.strict'), '(', stack, ', ', compiler.quotedString(parts[i]), ')'];1067} else {1068return stack;1069}1070}10711072exports["default"] = JavaScriptCompiler;10731074