2 * @fileoverview Rule to enforce spacing around embedded expressions of template strings
3 * @author Toru Nagashima
8 //------------------------------------------------------------------------------
10 //------------------------------------------------------------------------------
12 const astUtils = require("./utils/ast-utils");
14 //------------------------------------------------------------------------------
16 //------------------------------------------------------------------------------
23 description: "require or disallow spacing around embedded expressions of template strings",
24 category: "ECMAScript 6",
26 url: "https://eslint.org/docs/rules/template-curly-spacing"
29 fixable: "whitespace",
32 { enum: ["always", "never"] }
35 expectedBefore: "Expected space(s) before '}'.",
36 expectedAfter: "Expected space(s) after '${'.",
37 unexpectedBefore: "Unexpected space(s) before '}'.",
38 unexpectedAfter: "Unexpected space(s) after '${'."
43 const sourceCode = context.getSourceCode();
44 const always = context.options[0] === "always";
47 * Checks spacing before `}` of a given token.
48 * @param {Token} token A token to check. This is a Template token.
51 function checkSpacingBefore(token) {
52 if (!token.value.startsWith("}")) {
53 return; // starts with a backtick, this is the first template element in the template literal
56 const prevToken = sourceCode.getTokenBefore(token, { includeComments: true }),
57 hasSpace = sourceCode.isSpaceBetween(prevToken, token);
59 if (!astUtils.isTokenOnSameLine(prevToken, token)) {
63 if (always && !hasSpace) {
66 start: token.loc.start,
68 line: token.loc.start.line,
69 column: token.loc.start.column + 1
72 messageId: "expectedBefore",
73 fix: fixer => fixer.insertTextBefore(token, " ")
77 if (!always && hasSpace) {
80 start: prevToken.loc.end,
83 messageId: "unexpectedBefore",
84 fix: fixer => fixer.removeRange([prevToken.range[1], token.range[0]])
90 * Checks spacing after `${` of a given token.
91 * @param {Token} token A token to check. This is a Template token.
94 function checkSpacingAfter(token) {
95 if (!token.value.endsWith("${")) {
96 return; // ends with a backtick, this is the last template element in the template literal
99 const nextToken = sourceCode.getTokenAfter(token, { includeComments: true }),
100 hasSpace = sourceCode.isSpaceBetween(token, nextToken);
102 if (!astUtils.isTokenOnSameLine(token, nextToken)) {
106 if (always && !hasSpace) {
110 line: token.loc.end.line,
111 column: token.loc.end.column - 2
115 messageId: "expectedAfter",
116 fix: fixer => fixer.insertTextAfter(token, " ")
120 if (!always && hasSpace) {
123 start: token.loc.end,
124 end: nextToken.loc.start
126 messageId: "unexpectedAfter",
127 fix: fixer => fixer.removeRange([token.range[1], nextToken.range[0]])
133 TemplateElement(node) {
134 const token = sourceCode.getFirstToken(node);
136 checkSpacingBefore(token);
137 checkSpacingAfter(token);