From 5f299577f14ee9730528523c5b6f562f224f3e9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Castiel?= Date: Thu, 9 Nov 2017 20:10:44 -0500 Subject: [PATCH] refactoring and comments --- babylon-to-espree/convertTemplateType.js | 100 +++++++++++++++-------- 1 file changed, 67 insertions(+), 33 deletions(-) diff --git a/babylon-to-espree/convertTemplateType.js b/babylon-to-espree/convertTemplateType.js index 2fe45cda..d0ba10b1 100644 --- a/babylon-to-espree/convertTemplateType.js +++ b/babylon-to-espree/convertTemplateType.js @@ -1,55 +1,89 @@ "use strict"; module.exports = function(tokens, tt) { - const contextStack = [{ inTemplate: false, numBraces: 0 }]; - let contextIndex = 0; - const getContext = () => contextStack[contextIndex]; + // As long as we will iterate through the tokens array, we'll maintain a stack of + // contexts. This stack will alternate with: + // * template context (for strings): they have `isTemplate` set to `true`, and + // keep in `index` property the index of the token (in the array) that started + // the template; + // * non-template contexts (for JavaScript code): they have `isTemplate` set to + // `false`, and keep a number of opened braces ('{', i.e. the ones that were + // not closed with '}'). + // The top (i.e. last) context in the stack is the current one. + const contextStack = []; + + // At the beginning, we are not in a template. + pushNewNonTemplateContext(); for (let index = 0; index < tokens.length; index++) { const token = tokens[index]; - const context = getContext(); - if (context.inTemplate) { + if (currentContext().inTemplate) { // We are in a template… - const isTemplateEnder = - token.type === tt.dollarBraceL || token.type === tt.backQuote; - if (isTemplateEnder) { - if (token.type === tt.dollarBraceL) { - contextIndex++; - if (!contextStack[contextIndex]) { - contextStack[contextIndex] = { numBraces: 0, inTemplate: false }; - } - } else { - contextIndex--; - } - // We have a complete template token :) - const { index: startIndex } = context; - replaceWithTemplateType(startIndex, index); - index = startIndex; + // If we encounter a '${' or a '`', we go out of template (string) mode and create + // a template token. But the behavior differs depending on '${' or '`'… + if (token.type === tt.dollarBraceL) { + // If '${', then we begin a new expression with its own context. This means that + // we add a new context to the stack, and define it as the current context. + index = createTemplateTokenAndReturnNewIndex(index, token); + pushNewNonTemplateContext(); + } else if (token.type === tt.backQuote) { + // If '`', then we go back to the previous expression (the one before the template + // string began). We restore the previous context, with its numOfBraces. + index = createTemplateTokenAndReturnNewIndex(index, token); + popContext(); } + + // If not a '${' or a '`', we just keep going. } else { // We are out of a template… - const isTemplateStarter = - token.type === tt.backQuote || - (context.numBraces === 0 && token.type === tt.braceR); - if (isTemplateStarter) { - if (token.type === tt.backQuote) { - contextIndex++; - contextStack[contextIndex] = { index, inTemplate: true }; - } else { - contextIndex--; - } - contextStack[contextIndex].index = index; + // If we encounter a '`' or a '}' (and there is no not-closed '{'), we go in template + // (string) mode. Again two cases to handle: + if (token.type === tt.backQuote) { + // If '`', we begin a new template string, so we add a new context to the stack, and + // set it as the current context. + pushNewTemplateContext(index); + } else if (currentContext().numBraces === 0 && token.type === tt.braceR) { + // If '}', then we go back to the previous template string (that was "interrupted" by + // an embedded expression '${...}'), so we go back to the previous context. + popContext(); + currentContext().startIndex = index; + // Note that `contextStack[contextIndex].isTemplate` is already `true`. } else if (token.type === tt.braceL) { - context.numBraces++; + // In the case we encounter a '{', we increment the current number of openened braces. + currentContext().numBraces++; } else if (token.type === tt.braceR) { - context.numBraces--; + // And if '}' (and it's not been identified as the end of an embedded expression), we + // decrement the current number of opened braces. + currentContext().numBraces--; } } } + function createTemplateTokenAndReturnNewIndex(index, token) { + const { startIndex } = currentContext(); + replaceWithTemplateType(startIndex, index); + return startIndex; + } + + function currentContext() { + return contextStack[contextStack.length - 1]; + } + + function pushNewTemplateContext(startIndex) { + contextStack.push({ startIndex, inTemplate: true }); + } + + function pushNewNonTemplateContext() { + contextStack.push({ numBraces: 0, inTemplate: false }); + } + + function popContext() { + contextStack.pop(); + } + // append the values between start and end function createTemplateValue(start, end) { var value = "";