| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141 | /** * @fileoverview Rule to enforce spacing around embedded expressions of template strings * @author Toru Nagashima */"use strict";//------------------------------------------------------------------------------// Requirements//------------------------------------------------------------------------------const astUtils = require("./utils/ast-utils");//------------------------------------------------------------------------------// Rule Definition//------------------------------------------------------------------------------/** @type {import('../shared/types').Rule} */module.exports = {    meta: {        type: "layout",        docs: {            description: "Require or disallow spacing around embedded expressions of template strings",            recommended: false,            url: "https://eslint.org/docs/rules/template-curly-spacing"        },        fixable: "whitespace",        schema: [            { enum: ["always", "never"] }        ],        messages: {            expectedBefore: "Expected space(s) before '}'.",            expectedAfter: "Expected space(s) after '${'.",            unexpectedBefore: "Unexpected space(s) before '}'.",            unexpectedAfter: "Unexpected space(s) after '${'."        }    },    create(context) {        const sourceCode = context.getSourceCode();        const always = context.options[0] === "always";        /**         * Checks spacing before `}` of a given token.         * @param {Token} token A token to check. This is a Template token.         * @returns {void}         */        function checkSpacingBefore(token) {            if (!token.value.startsWith("}")) {                return; // starts with a backtick, this is the first template element in the template literal            }            const prevToken = sourceCode.getTokenBefore(token, { includeComments: true }),                hasSpace = sourceCode.isSpaceBetween(prevToken, token);            if (!astUtils.isTokenOnSameLine(prevToken, token)) {                return;            }            if (always && !hasSpace) {                context.report({                    loc: {                        start: token.loc.start,                        end: {                            line: token.loc.start.line,                            column: token.loc.start.column + 1                        }                    },                    messageId: "expectedBefore",                    fix: fixer => fixer.insertTextBefore(token, " ")                });            }            if (!always && hasSpace) {                context.report({                    loc: {                        start: prevToken.loc.end,                        end: token.loc.start                    },                    messageId: "unexpectedBefore",                    fix: fixer => fixer.removeRange([prevToken.range[1], token.range[0]])                });            }        }        /**         * Checks spacing after `${` of a given token.         * @param {Token} token A token to check. This is a Template token.         * @returns {void}         */        function checkSpacingAfter(token) {            if (!token.value.endsWith("${")) {                return; // ends with a backtick, this is the last template element in the template literal            }            const nextToken = sourceCode.getTokenAfter(token, { includeComments: true }),                hasSpace = sourceCode.isSpaceBetween(token, nextToken);            if (!astUtils.isTokenOnSameLine(token, nextToken)) {                return;            }            if (always && !hasSpace) {                context.report({                    loc: {                        start: {                            line: token.loc.end.line,                            column: token.loc.end.column - 2                        },                        end: token.loc.end                    },                    messageId: "expectedAfter",                    fix: fixer => fixer.insertTextAfter(token, " ")                });            }            if (!always && hasSpace) {                context.report({                    loc: {                        start: token.loc.end,                        end: nextToken.loc.start                    },                    messageId: "unexpectedAfter",                    fix: fixer => fixer.removeRange([token.range[1], nextToken.range[0]])                });            }        }        return {            TemplateElement(node) {                const token = sourceCode.getFirstToken(node);                checkSpacingBefore(token);                checkSpacingAfter(token);            }        };    }};
 |