UNPKG

7.95 kBJavaScriptView Raw
1"use strict";
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6exports.default = void 0;
7
8var _helperPluginUtils = require("@babel/helper-plugin-utils");
9
10var _pluginSyntaxFlow = _interopRequireDefault(require("@babel/plugin-syntax-flow"));
11
12var _core = require("@babel/core");
13
14var _generator = _interopRequireDefault(require("@babel/generator"));
15
16function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
17
18var _default = (0, _helperPluginUtils.declare)(api => {
19 api.assertVersion(7);
20
21 function commentFromString(comment) {
22 return typeof comment === "string" ? {
23 type: "CommentBlock",
24 value: comment
25 } : comment;
26 }
27
28 function attachComment({
29 ofPath,
30 toPath,
31 where = "trailing",
32 optional = false,
33 comments = generateComment(ofPath, optional),
34 keepType = false
35 }) {
36 if (!toPath || !toPath.node) {
37 toPath = ofPath.getPrevSibling();
38 where = "trailing";
39 }
40
41 if (!toPath.node) {
42 toPath = ofPath.getNextSibling();
43 where = "leading";
44 }
45
46 if (!toPath.node) {
47 toPath = ofPath.parentPath;
48 where = "inner";
49 }
50
51 if (!Array.isArray(comments)) {
52 comments = [comments];
53 }
54
55 comments = comments.map(commentFromString);
56
57 if (!keepType && ofPath && ofPath.node) {
58 const node = ofPath.node;
59 const parent = ofPath.parentPath;
60 const prev = ofPath.getPrevSibling();
61 const next = ofPath.getNextSibling();
62 const isSingleChild = !(prev.node || next.node);
63 const leading = node.leadingComments;
64 const trailing = node.trailingComments;
65
66 if (isSingleChild && leading) {
67 parent.addComments("inner", leading);
68 }
69
70 toPath.addComments(where, comments);
71 ofPath.remove();
72
73 if (isSingleChild && trailing) {
74 parent.addComments("inner", trailing);
75 }
76 } else {
77 toPath.addComments(where, comments);
78 }
79 }
80
81 function wrapInFlowComment(path) {
82 attachComment({
83 ofPath: path,
84 comments: generateComment(path, path.parent.optional)
85 });
86 }
87
88 function generateComment(path, optional) {
89 let comment = path.getSource().replace(/\*-\//g, "*-ESCAPED/").replace(/\*\//g, "*-/");
90 if (optional) comment = "?" + comment;
91 if (comment[0] !== ":") comment = ":: " + comment;
92 return comment;
93 }
94
95 function isTypeImport(importKind) {
96 return importKind === "type" || importKind === "typeof";
97 }
98
99 return {
100 name: "transform-flow-comments",
101 inherits: _pluginSyntaxFlow.default,
102 visitor: {
103 TypeCastExpression(path) {
104 const {
105 node
106 } = path;
107 attachComment({
108 ofPath: path.get("typeAnnotation"),
109 toPath: path.get("expression"),
110 keepType: true
111 });
112 path.replaceWith(_core.types.parenthesizedExpression(node.expression));
113 },
114
115 Identifier(path) {
116 if (path.parentPath.isFlow()) return;
117 const {
118 node
119 } = path;
120
121 if (node.typeAnnotation) {
122 attachComment({
123 ofPath: path.get("typeAnnotation"),
124 toPath: path,
125 optional: node.optional || node.typeAnnotation.optional
126 });
127
128 if (node.optional) {
129 node.optional = false;
130 }
131 } else if (node.optional) {
132 attachComment({
133 toPath: path,
134 comments: ":: ?"
135 });
136 node.optional = false;
137 }
138 },
139
140 AssignmentPattern: {
141 exit({
142 node
143 }) {
144 const {
145 left
146 } = node;
147
148 if (left.optional) {
149 left.optional = false;
150 }
151 }
152
153 },
154
155 Function(path) {
156 if (path.isDeclareFunction()) return;
157 const {
158 node
159 } = path;
160
161 if (node.typeParameters) {
162 attachComment({
163 ofPath: path.get("typeParameters"),
164 toPath: path.get("id"),
165 optional: node.typeParameters.optional
166 });
167 }
168
169 if (node.returnType) {
170 attachComment({
171 ofPath: path.get("returnType"),
172 toPath: path.get("body"),
173 where: "leading",
174 optional: node.returnType.typeAnnotation.optional
175 });
176 }
177 },
178
179 ClassProperty(path) {
180 const {
181 node
182 } = path;
183
184 if (!node.value) {
185 wrapInFlowComment(path);
186 } else if (node.typeAnnotation) {
187 attachComment({
188 ofPath: path.get("typeAnnotation"),
189 toPath: path.get("key"),
190 optional: node.typeAnnotation.optional
191 });
192 }
193 },
194
195 ExportNamedDeclaration(path) {
196 const {
197 node
198 } = path;
199
200 if (node.exportKind !== "type" && !_core.types.isFlow(node.declaration)) {
201 return;
202 }
203
204 wrapInFlowComment(path);
205 },
206
207 ImportDeclaration(path) {
208 const {
209 node
210 } = path;
211
212 if (isTypeImport(node.importKind)) {
213 wrapInFlowComment(path);
214 return;
215 }
216
217 const typeSpecifiers = node.specifiers.filter(specifier => isTypeImport(specifier.importKind));
218 const nonTypeSpecifiers = node.specifiers.filter(specifier => !isTypeImport(specifier.importKind));
219 node.specifiers = nonTypeSpecifiers;
220
221 if (typeSpecifiers.length > 0) {
222 const typeImportNode = _core.types.cloneNode(node);
223
224 typeImportNode.specifiers = typeSpecifiers;
225 const comment = `:: ${(0, _generator.default)(typeImportNode).code}`;
226
227 if (nonTypeSpecifiers.length > 0) {
228 attachComment({
229 toPath: path,
230 comments: comment
231 });
232 } else {
233 attachComment({
234 ofPath: path,
235 comments: comment
236 });
237 }
238 }
239 },
240
241 ObjectPattern(path) {
242 const {
243 node
244 } = path;
245
246 if (node.typeAnnotation) {
247 attachComment({
248 ofPath: path.get("typeAnnotation"),
249 toPath: path,
250 optional: node.optional || node.typeAnnotation.optional
251 });
252 }
253 },
254
255 Flow(path) {
256 wrapInFlowComment(path);
257 },
258
259 Class(path) {
260 const {
261 node
262 } = path;
263 let comments = [];
264
265 if (node.typeParameters) {
266 const typeParameters = path.get("typeParameters");
267 comments.push(generateComment(typeParameters, node.typeParameters.optional));
268 const trailingComments = node.typeParameters.trailingComments;
269
270 if (trailingComments) {
271 comments.push(...trailingComments);
272 }
273
274 typeParameters.remove();
275 }
276
277 if (node.superClass) {
278 if (comments.length > 0) {
279 attachComment({
280 toPath: path.get("id"),
281 comments: comments
282 });
283 comments = [];
284 }
285
286 if (node.superTypeParameters) {
287 const superTypeParameters = path.get("superTypeParameters");
288 comments.push(generateComment(superTypeParameters, superTypeParameters.node.optional));
289 superTypeParameters.remove();
290 }
291 }
292
293 if (node.implements) {
294 const impls = path.get("implements");
295 const comment = "implements " + impls.map(impl => generateComment(impl).replace(/^:: /, "")).join(", ");
296 delete node["implements"];
297
298 if (comments.length === 1) {
299 comments[0] += ` ${comment}`;
300 } else {
301 comments.push(`:: ${comment}`);
302 }
303 }
304
305 if (comments.length > 0) {
306 attachComment({
307 toPath: path.get("body"),
308 where: "leading",
309 comments: comments
310 });
311 }
312 }
313
314 }
315 };
316});
317
318exports.default = _default;
\No newline at end of file