UNPKG

chrome-devtools-frontend

Version:
90 lines (81 loc) 3.87 kB
// Copyright 2021 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. 'use strict'; const {isLitHtmlTemplateCall} = require('./utils.js'); function templateElementPartStartsWithDoubleQuote(templateElementPartNode) { return templateElementPartNode.value.raw.startsWith('"'); } function templateElementPartEndsWithEqualsDoubleQuote(templateElementPartNode) { return templateElementPartNode.value.raw.endsWith('="'); } function removeQuotesFromAttribute({fixer, firstPart, secondPart}) { const [, rangeOfOpeningTemplatePartEnd] = firstPart.range; // From the first part, we need to remove the last character, which is the double quote. // We can do this by fetching the range of the node (range = start and end position on the line) // However, for the template part with the opening quote, the range will also contain the ${ of the interpolation: // <p class="${ // ^^^^^^^^^^^^ this is the text covered by the [start, end] range. // So what we need to do is remove the quote, and leave the last two characters alone. // Therefore we remove the third character back from the end, and only remove a single character, leaving the ${ part alone. const startingQuoteRangeToRemove = [rangeOfOpeningTemplatePartEnd - 3, rangeOfOpeningTemplatePartEnd - 2]; const [rangeOfClosingTemplatePartStart] = secondPart.range; // It's a similar story for the second part where the range includes the }: // }">foo</p> // ^^^^^^^^^^ this is the range // So therefore we get the start of the range, and add one to it, to dodge the } character, and then remove only the quote. const endingQuoteRangeToRemove = [rangeOfClosingTemplatePartStart + 1, rangeOfClosingTemplatePartStart + 2]; return [fixer.removeRange(startingQuoteRangeToRemove), fixer.removeRange(endingQuoteRangeToRemove)]; } module.exports = { meta: { type: 'problem', docs: { description: 'ensure no extra quotes around attributes when the value is interpolated', category: 'Possible Errors', }, fixable: 'code', messages: { attributeQuotesNotRequired: 'When interpolating a value as an attribute in LitHtml you do not need double quotes around it.', }, schema: [] // no options }, create: function(context) { return { TaggedTemplateExpression(node) { if (!isLitHtmlTemplateCall(node)) { return; } // quasis here = the static parts of a template expression // expressions = the dynamic parts of a template expression // For example, given: <p class="${foo}"> we will have: // quasis: ['<p class="', '">'] // expressions: ['foo'] (it's actually an AST node representing ${foo}) // So what we do is walk through and look for quasi pairs where: // 1. the first ends with =" // 2. the second begins with " // We can then be confident that we have found an attribute with quotes around it. node.quasi.quasis.forEach((templateElement, index) => { if (templateElementPartEndsWithEqualsDoubleQuote(templateElement)) { const nextElement = node.quasi.quasis[index + 1]; if (nextElement && templateElementPartStartsWithDoubleQuote(nextElement)) { const expressionBetweenTheParts = node.quasi.expressions[index]; context.report({ node: expressionBetweenTheParts, messageId: 'attributeQuotesNotRequired', fix(fixer) { return removeQuotesFromAttribute({ fixer, firstPart: templateElement, secondPart: nextElement, }); } }); } } }); }, }; } };