151 lines
4.3 KiB
JavaScript
151 lines
4.3 KiB
JavaScript
import { declare } from "@babel/helper-plugin-utils";
|
|
import syntaxFlow from "@babel/plugin-syntax-flow";
|
|
import { types as t } from "@babel/core";
|
|
|
|
export default declare(api => {
|
|
api.assertVersion(7);
|
|
|
|
function wrapInFlowComment(path, parent) {
|
|
let attach = path.getPrevSibling();
|
|
let where = "trailing";
|
|
if (!attach.node) {
|
|
attach = path.parentPath;
|
|
where = "inner";
|
|
}
|
|
attach.addComment(where, generateComment(path, parent));
|
|
path.remove();
|
|
}
|
|
|
|
function generateComment(path, parent) {
|
|
let comment = path
|
|
.getSource()
|
|
.replace(/\*-\//g, "*-ESCAPED/")
|
|
.replace(/\*\//g, "*-/");
|
|
if (parent && parent.optional) comment = "?" + comment;
|
|
if (comment[0] !== ":") comment = ":: " + comment;
|
|
return comment;
|
|
}
|
|
|
|
return {
|
|
name: "transform-flow-comments",
|
|
inherits: syntaxFlow,
|
|
|
|
visitor: {
|
|
TypeCastExpression(path) {
|
|
const { node } = path;
|
|
path
|
|
.get("expression")
|
|
.addComment("trailing", generateComment(path.get("typeAnnotation")));
|
|
path.replaceWith(t.parenthesizedExpression(node.expression));
|
|
},
|
|
|
|
// support function a(b?) {}
|
|
Identifier(path) {
|
|
if (path.parentPath.isFlow()) {
|
|
return;
|
|
}
|
|
|
|
const { node } = path;
|
|
if (node.typeAnnotation) {
|
|
const typeAnnotation = path.get("typeAnnotation");
|
|
path.addComment("trailing", generateComment(typeAnnotation, node));
|
|
typeAnnotation.remove();
|
|
if (node.optional) {
|
|
node.optional = false;
|
|
}
|
|
} else if (node.optional) {
|
|
path.addComment("trailing", ":: ?");
|
|
node.optional = false;
|
|
}
|
|
},
|
|
|
|
AssignmentPattern: {
|
|
exit({ node }) {
|
|
const { left } = node;
|
|
if (left.optional) {
|
|
left.optional = false;
|
|
}
|
|
},
|
|
},
|
|
|
|
// strip optional property from function params - facebook/fbjs#17
|
|
Function(path) {
|
|
if (path.isDeclareFunction()) return;
|
|
const { node } = path;
|
|
if (node.returnType) {
|
|
const returnType = path.get("returnType");
|
|
const typeAnnotation = returnType.get("typeAnnotation");
|
|
const block = path.get("body");
|
|
block.addComment(
|
|
"leading",
|
|
generateComment(returnType, typeAnnotation.node),
|
|
);
|
|
returnType.remove();
|
|
}
|
|
if (node.typeParameters) {
|
|
const typeParameters = path.get("typeParameters");
|
|
const id = path.get("id");
|
|
id.addComment(
|
|
"trailing",
|
|
generateComment(typeParameters, typeParameters.node),
|
|
);
|
|
typeParameters.remove();
|
|
}
|
|
},
|
|
|
|
// support for `class X { foo: string }` - #4622
|
|
ClassProperty(path) {
|
|
const { node, parent } = path;
|
|
if (!node.value) {
|
|
wrapInFlowComment(path, parent);
|
|
} else if (node.typeAnnotation) {
|
|
const typeAnnotation = path.get("typeAnnotation");
|
|
path
|
|
.get("key")
|
|
.addComment(
|
|
"trailing",
|
|
generateComment(typeAnnotation, typeAnnotation.node),
|
|
);
|
|
typeAnnotation.remove();
|
|
}
|
|
},
|
|
|
|
// support `export type a = {}` - #8 Error: You passed path.replaceWith() a falsy node
|
|
ExportNamedDeclaration(path) {
|
|
const { node, parent } = path;
|
|
if (node.exportKind !== "type" && !t.isFlow(node.declaration)) {
|
|
return;
|
|
}
|
|
wrapInFlowComment(path, parent);
|
|
},
|
|
|
|
// support `import type A` and `import typeof A` #10
|
|
ImportDeclaration(path) {
|
|
const { node, parent } = path;
|
|
if (node.importKind !== "type" && node.importKind !== "typeof") {
|
|
return;
|
|
}
|
|
wrapInFlowComment(path, parent);
|
|
},
|
|
|
|
Flow(path) {
|
|
const { parent } = path;
|
|
wrapInFlowComment(path, parent);
|
|
},
|
|
|
|
Class(path) {
|
|
const { node } = path;
|
|
if (node.typeParameters) {
|
|
const typeParameters = path.get("typeParameters");
|
|
const block = path.get("body");
|
|
block.addComment(
|
|
"leading",
|
|
generateComment(typeParameters, typeParameters.node),
|
|
);
|
|
typeParameters.remove();
|
|
}
|
|
},
|
|
},
|
|
};
|
|
});
|