/** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /*jslint node:true*/ /** * @typechecks */ 'use strict'; var Syntax = require('esprima-fb').Syntax; var utils = require('../src/utils'); /** * http://people.mozilla.org/~jorendorff/es6-draft.html#sec-12.1.9 */ function visitTemplateLiteral(traverse, node, path, state) { var templateElements = node.quasis; utils.append('(', state); for (var ii = 0; ii < templateElements.length; ii++) { var templateElement = templateElements[ii]; if (templateElement.value.raw !== '') { utils.append(getCookedValue(templateElement), state); if (!templateElement.tail) { // + between element and substitution utils.append(' + ', state); } // maintain line numbers utils.move(templateElement.range[0], state); utils.catchupNewlines(templateElement.range[1], state); } else { // templateElement.value.raw === '' // Concatenat adjacent substitutions, e.g. `${x}${y}`. Empty templates // appear before the first and after the last element - nothing to add in // those cases. if (ii > 0 && !templateElement.tail) { // + between substitution and substitution utils.append(' + ', state); } } utils.move(templateElement.range[1], state); if (!templateElement.tail) { var substitution = node.expressions[ii]; if (substitution.type === Syntax.Identifier || substitution.type === Syntax.MemberExpression || substitution.type === Syntax.CallExpression) { utils.catchup(substitution.range[1], state); } else { utils.append('(', state); traverse(substitution, path, state); utils.catchup(substitution.range[1], state); utils.append(')', state); } // if next templateElement isn't empty... if (templateElements[ii + 1].value.cooked !== '') { utils.append(' + ', state); } } } utils.move(node.range[1], state); utils.append(')', state); return false; } visitTemplateLiteral.test = function(node, path, state) { return node.type === Syntax.TemplateLiteral; }; /** * http://people.mozilla.org/~jorendorff/es6-draft.html#sec-12.2.6 */ function visitTaggedTemplateExpression(traverse, node, path, state) { var template = node.quasi; var numQuasis = template.quasis.length; // print the tag utils.move(node.tag.range[0], state); traverse(node.tag, path, state); utils.catchup(node.tag.range[1], state); // print array of template elements utils.append('(function() { var siteObj = [', state); for (var ii = 0; ii < numQuasis; ii++) { utils.append(getCookedValue(template.quasis[ii]), state); if (ii !== numQuasis - 1) { utils.append(', ', state); } } utils.append(']; siteObj.raw = [', state); for (ii = 0; ii < numQuasis; ii++) { utils.append(getRawValue(template.quasis[ii]), state); if (ii !== numQuasis - 1) { utils.append(', ', state); } } utils.append( ']; Object.freeze(siteObj.raw); Object.freeze(siteObj); return siteObj; }()', state ); // print substitutions if (numQuasis > 1) { for (ii = 0; ii < template.expressions.length; ii++) { var expression = template.expressions[ii]; utils.append(', ', state); // maintain line numbers by calling catchupWhiteSpace over the whole // previous TemplateElement utils.move(template.quasis[ii].range[0], state); utils.catchupNewlines(template.quasis[ii].range[1], state); utils.move(expression.range[0], state); traverse(expression, path, state); utils.catchup(expression.range[1], state); } } // print blank lines to push the closing ) down to account for the final // TemplateElement. utils.catchupNewlines(node.range[1], state); utils.append(')', state); return false; } visitTaggedTemplateExpression.test = function(node, path, state) { return node.type === Syntax.TaggedTemplateExpression; }; function getCookedValue(templateElement) { return JSON.stringify(templateElement.value.cooked); } function getRawValue(templateElement) { return JSON.stringify(templateElement.value.raw); } exports.visitorList = [ visitTemplateLiteral, visitTaggedTemplateExpression ];