1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 | "use strict";
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 | const astUtils = require("./utils/ast-utils");
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 | module.exports = {
|
19 | meta: {
|
20 | type: "layout",
|
21 |
|
22 | docs: {
|
23 | description: "require or disallow spacing around embedded expressions of template strings",
|
24 | category: "ECMAScript 6",
|
25 | recommended: false,
|
26 | url: "https://eslint.org/docs/rules/template-curly-spacing"
|
27 | },
|
28 |
|
29 | fixable: "whitespace",
|
30 |
|
31 | schema: [
|
32 | { enum: ["always", "never"] }
|
33 | ],
|
34 | messages: {
|
35 | expectedBefore: "Expected space(s) before '}'.",
|
36 | expectedAfter: "Expected space(s) after '${'.",
|
37 | unexpectedBefore: "Unexpected space(s) before '}'.",
|
38 | unexpectedAfter: "Unexpected space(s) after '${'."
|
39 | }
|
40 | },
|
41 |
|
42 | create(context) {
|
43 | const sourceCode = context.getSourceCode();
|
44 | const always = context.options[0] === "always";
|
45 |
|
46 | |
47 |
|
48 |
|
49 |
|
50 |
|
51 | function checkSpacingBefore(token) {
|
52 | if (!token.value.startsWith("}")) {
|
53 | return;
|
54 | }
|
55 |
|
56 | const prevToken = sourceCode.getTokenBefore(token, { includeComments: true }),
|
57 | hasSpace = sourceCode.isSpaceBetween(prevToken, token);
|
58 |
|
59 | if (!astUtils.isTokenOnSameLine(prevToken, token)) {
|
60 | return;
|
61 | }
|
62 |
|
63 | if (always && !hasSpace) {
|
64 | context.report({
|
65 | loc: {
|
66 | start: token.loc.start,
|
67 | end: {
|
68 | line: token.loc.start.line,
|
69 | column: token.loc.start.column + 1
|
70 | }
|
71 | },
|
72 | messageId: "expectedBefore",
|
73 | fix: fixer => fixer.insertTextBefore(token, " ")
|
74 | });
|
75 | }
|
76 |
|
77 | if (!always && hasSpace) {
|
78 | context.report({
|
79 | loc: {
|
80 | start: prevToken.loc.end,
|
81 | end: token.loc.start
|
82 | },
|
83 | messageId: "unexpectedBefore",
|
84 | fix: fixer => fixer.removeRange([prevToken.range[1], token.range[0]])
|
85 | });
|
86 | }
|
87 | }
|
88 |
|
89 | |
90 |
|
91 |
|
92 |
|
93 |
|
94 | function checkSpacingAfter(token) {
|
95 | if (!token.value.endsWith("${")) {
|
96 | return;
|
97 | }
|
98 |
|
99 | const nextToken = sourceCode.getTokenAfter(token, { includeComments: true }),
|
100 | hasSpace = sourceCode.isSpaceBetween(token, nextToken);
|
101 |
|
102 | if (!astUtils.isTokenOnSameLine(token, nextToken)) {
|
103 | return;
|
104 | }
|
105 |
|
106 | if (always && !hasSpace) {
|
107 | context.report({
|
108 | loc: {
|
109 | start: {
|
110 | line: token.loc.end.line,
|
111 | column: token.loc.end.column - 2
|
112 | },
|
113 | end: token.loc.end
|
114 | },
|
115 | messageId: "expectedAfter",
|
116 | fix: fixer => fixer.insertTextAfter(token, " ")
|
117 | });
|
118 | }
|
119 |
|
120 | if (!always && hasSpace) {
|
121 | context.report({
|
122 | loc: {
|
123 | start: token.loc.end,
|
124 | end: nextToken.loc.start
|
125 | },
|
126 | messageId: "unexpectedAfter",
|
127 | fix: fixer => fixer.removeRange([token.range[1], nextToken.range[0]])
|
128 | });
|
129 | }
|
130 | }
|
131 |
|
132 | return {
|
133 | TemplateElement(node) {
|
134 | const token = sourceCode.getFirstToken(node);
|
135 |
|
136 | checkSpacingBefore(token);
|
137 | checkSpacingAfter(token);
|
138 | }
|
139 | };
|
140 | }
|
141 | };
|