1 | "use strict";
|
2 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
3 | if (k2 === undefined) k2 = k;
|
4 | Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
5 | }) : (function(o, m, k, k2) {
|
6 | if (k2 === undefined) k2 = k;
|
7 | o[k2] = m[k];
|
8 | }));
|
9 | var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
10 | Object.defineProperty(o, "default", { enumerable: true, value: v });
|
11 | }) : function(o, v) {
|
12 | o["default"] = v;
|
13 | });
|
14 | var __importStar = (this && this.__importStar) || function (mod) {
|
15 | if (mod && mod.__esModule) return mod;
|
16 | var result = {};
|
17 | if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
18 | __setModuleDefault(result, mod);
|
19 | return result;
|
20 | };
|
21 | Object.defineProperty(exports, "__esModule", { value: true });
|
22 | const util = __importStar(require("../util"));
|
23 | const util_1 = require("../util");
|
24 | const definition = {
|
25 | type: 'object',
|
26 | properties: {
|
27 | before: { type: 'boolean' },
|
28 | after: { type: 'boolean' },
|
29 | },
|
30 | additionalProperties: false,
|
31 | };
|
32 | function createRules(options) {
|
33 | var _a;
|
34 | const globals = Object.assign(Object.assign({}, ((options === null || options === void 0 ? void 0 : options.before) !== undefined ? { before: options.before } : {})), ((options === null || options === void 0 ? void 0 : options.after) !== undefined ? { after: options.after } : {}));
|
35 | const override = (_a = options === null || options === void 0 ? void 0 : options.overrides) !== null && _a !== void 0 ? _a : {};
|
36 | const colon = Object.assign(Object.assign({ before: false, after: true }, globals), override === null || override === void 0 ? void 0 : override.colon);
|
37 | const arrow = Object.assign(Object.assign({ before: true, after: true }, globals), override === null || override === void 0 ? void 0 : override.arrow);
|
38 | return {
|
39 | colon: colon,
|
40 | arrow: arrow,
|
41 | variable: Object.assign(Object.assign({}, colon), override === null || override === void 0 ? void 0 : override.variable),
|
42 | property: Object.assign(Object.assign({}, colon), override === null || override === void 0 ? void 0 : override.property),
|
43 | parameter: Object.assign(Object.assign({}, colon), override === null || override === void 0 ? void 0 : override.parameter),
|
44 | returnType: Object.assign(Object.assign({}, colon), override === null || override === void 0 ? void 0 : override.returnType),
|
45 | };
|
46 | }
|
47 | function getIdentifierRules(rules, node) {
|
48 | const scope = node === null || node === void 0 ? void 0 : node.parent;
|
49 | if ((0, util_1.isVariableDeclarator)(scope)) {
|
50 | return rules.variable;
|
51 | }
|
52 | else if ((0, util_1.isFunctionOrFunctionType)(scope)) {
|
53 | return rules.parameter;
|
54 | }
|
55 | else {
|
56 | return rules.colon;
|
57 | }
|
58 | }
|
59 | function getRules(rules, node) {
|
60 | var _a;
|
61 | const scope = (_a = node === null || node === void 0 ? void 0 : node.parent) === null || _a === void 0 ? void 0 : _a.parent;
|
62 | if ((0, util_1.isTSFunctionType)(scope) || (0, util_1.isTSConstructorType)(scope)) {
|
63 | return rules.arrow;
|
64 | }
|
65 | else if ((0, util_1.isIdentifier)(scope)) {
|
66 | return getIdentifierRules(rules, scope);
|
67 | }
|
68 | else if ((0, util_1.isClassOrTypeElement)(scope)) {
|
69 | return rules.property;
|
70 | }
|
71 | else if ((0, util_1.isFunction)(scope)) {
|
72 | return rules.returnType;
|
73 | }
|
74 | else {
|
75 | return rules.colon;
|
76 | }
|
77 | }
|
78 | exports.default = util.createRule({
|
79 | name: 'type-annotation-spacing',
|
80 | meta: {
|
81 | type: 'layout',
|
82 | docs: {
|
83 | description: 'Require consistent spacing around type annotations',
|
84 | recommended: false,
|
85 | },
|
86 | fixable: 'whitespace',
|
87 | messages: {
|
88 | expectedSpaceAfter: "Expected a space after the '{{type}}'.",
|
89 | expectedSpaceBefore: "Expected a space before the '{{type}}'.",
|
90 | unexpectedSpaceAfter: "Unexpected space after the '{{type}}'.",
|
91 | unexpectedSpaceBefore: "Unexpected space before the '{{type}}'.",
|
92 | unexpectedSpaceBetween: "Unexpected space between the '{{previousToken}}' and the '{{type}}'.",
|
93 | },
|
94 | schema: [
|
95 | {
|
96 | type: 'object',
|
97 | properties: {
|
98 | before: { type: 'boolean' },
|
99 | after: { type: 'boolean' },
|
100 | overrides: {
|
101 | type: 'object',
|
102 | properties: {
|
103 | colon: definition,
|
104 | arrow: definition,
|
105 | variable: definition,
|
106 | parameter: definition,
|
107 | property: definition,
|
108 | returnType: definition,
|
109 | },
|
110 | additionalProperties: false,
|
111 | },
|
112 | },
|
113 | additionalProperties: false,
|
114 | },
|
115 | ],
|
116 | },
|
117 | defaultOptions: [
|
118 |
|
119 |
|
120 | {},
|
121 | ],
|
122 | create(context, [options]) {
|
123 | const punctuators = [':', '=>'];
|
124 | const sourceCode = context.getSourceCode();
|
125 | const ruleSet = createRules(options);
|
126 | |
127 |
|
128 |
|
129 |
|
130 | function checkTypeAnnotationSpacing(typeAnnotation) {
|
131 | const nextToken = typeAnnotation;
|
132 | const punctuatorTokenEnd = sourceCode.getTokenBefore(nextToken);
|
133 | let punctuatorTokenStart = punctuatorTokenEnd;
|
134 | let previousToken = sourceCode.getTokenBefore(punctuatorTokenEnd);
|
135 | let type = punctuatorTokenEnd.value;
|
136 | if (!punctuators.includes(type)) {
|
137 | return;
|
138 | }
|
139 | const { before, after } = getRules(ruleSet, typeAnnotation);
|
140 | if (type === ':' && previousToken.value === '?') {
|
141 | if (sourceCode.isSpaceBetweenTokens(previousToken, punctuatorTokenStart)) {
|
142 | context.report({
|
143 | node: punctuatorTokenStart,
|
144 | messageId: 'unexpectedSpaceBetween',
|
145 | data: {
|
146 | type,
|
147 | previousToken: previousToken.value,
|
148 | },
|
149 | fix(fixer) {
|
150 | return fixer.removeRange([
|
151 | previousToken.range[1],
|
152 | punctuatorTokenStart.range[0],
|
153 | ]);
|
154 | },
|
155 | });
|
156 | }
|
157 |
|
158 | type = '?:';
|
159 | punctuatorTokenStart = previousToken;
|
160 | previousToken = sourceCode.getTokenBefore(previousToken);
|
161 |
|
162 | if (previousToken.value === '+' || previousToken.value === '-') {
|
163 | type = `${previousToken.value}?:`;
|
164 | punctuatorTokenStart = previousToken;
|
165 | previousToken = sourceCode.getTokenBefore(previousToken);
|
166 | }
|
167 | }
|
168 | const previousDelta = punctuatorTokenStart.range[0] - previousToken.range[1];
|
169 | const nextDelta = nextToken.range[0] - punctuatorTokenEnd.range[1];
|
170 | if (after && nextDelta === 0) {
|
171 | context.report({
|
172 | node: punctuatorTokenEnd,
|
173 | messageId: 'expectedSpaceAfter',
|
174 | data: {
|
175 | type,
|
176 | },
|
177 | fix(fixer) {
|
178 | return fixer.insertTextAfter(punctuatorTokenEnd, ' ');
|
179 | },
|
180 | });
|
181 | }
|
182 | else if (!after && nextDelta > 0) {
|
183 | context.report({
|
184 | node: punctuatorTokenEnd,
|
185 | messageId: 'unexpectedSpaceAfter',
|
186 | data: {
|
187 | type,
|
188 | },
|
189 | fix(fixer) {
|
190 | return fixer.removeRange([
|
191 | punctuatorTokenEnd.range[1],
|
192 | nextToken.range[0],
|
193 | ]);
|
194 | },
|
195 | });
|
196 | }
|
197 | if (before && previousDelta === 0) {
|
198 | context.report({
|
199 | node: punctuatorTokenStart,
|
200 | messageId: 'expectedSpaceBefore',
|
201 | data: {
|
202 | type,
|
203 | },
|
204 | fix(fixer) {
|
205 | return fixer.insertTextAfter(previousToken, ' ');
|
206 | },
|
207 | });
|
208 | }
|
209 | else if (!before && previousDelta > 0) {
|
210 | context.report({
|
211 | node: punctuatorTokenStart,
|
212 | messageId: 'unexpectedSpaceBefore',
|
213 | data: {
|
214 | type,
|
215 | },
|
216 | fix(fixer) {
|
217 | return fixer.removeRange([
|
218 | previousToken.range[1],
|
219 | punctuatorTokenStart.range[0],
|
220 | ]);
|
221 | },
|
222 | });
|
223 | }
|
224 | }
|
225 | return {
|
226 | TSMappedType(node) {
|
227 | if (node.typeAnnotation) {
|
228 | checkTypeAnnotationSpacing(node.typeAnnotation);
|
229 | }
|
230 | },
|
231 | TSTypeAnnotation(node) {
|
232 | checkTypeAnnotationSpacing(node.typeAnnotation);
|
233 | },
|
234 | };
|
235 | },
|
236 | });
|
237 |
|
\ | No newline at end of file |