1 | 'use strict';
|
2 |
|
3 | var core = require('@babel/core');
|
4 |
|
5 | const elementToComponent = {
|
6 | svg: "Svg",
|
7 | circle: "Circle",
|
8 | clipPath: "ClipPath",
|
9 | ellipse: "Ellipse",
|
10 | g: "G",
|
11 | linearGradient: "LinearGradient",
|
12 | radialGradient: "RadialGradient",
|
13 | line: "Line",
|
14 | path: "Path",
|
15 | pattern: "Pattern",
|
16 | polygon: "Polygon",
|
17 | polyline: "Polyline",
|
18 | rect: "Rect",
|
19 | symbol: "Symbol",
|
20 | text: "Text",
|
21 | textPath: "TextPath",
|
22 | tspan: "TSpan",
|
23 | use: "Use",
|
24 | defs: "Defs",
|
25 | stop: "Stop",
|
26 | mask: "Mask",
|
27 | image: "Image",
|
28 | foreignObject: "ForeignObject"
|
29 | };
|
30 | const plugin = () => {
|
31 | function replaceElement(path, state) {
|
32 | const namePath = path.get("openingElement").get("name");
|
33 | if (!namePath.isJSXIdentifier())
|
34 | return;
|
35 | const { name } = namePath.node;
|
36 | const component = elementToComponent[name];
|
37 | if (component) {
|
38 | namePath.replaceWith(core.types.jsxIdentifier(component));
|
39 | if (path.has("closingElement")) {
|
40 | const closingNamePath = path.get("closingElement").get("name");
|
41 | closingNamePath.replaceWith(core.types.jsxIdentifier(component));
|
42 | }
|
43 | state.replacedComponents.add(component);
|
44 | return;
|
45 | }
|
46 | state.unsupportedComponents.add(name);
|
47 | path.remove();
|
48 | }
|
49 | const svgElementVisitor = {
|
50 | JSXElement(path, state) {
|
51 | if (!path.get("openingElement").get("name").isJSXIdentifier({ name: "svg" })) {
|
52 | return;
|
53 | }
|
54 | replaceElement(path, state);
|
55 | path.traverse(jsxElementVisitor, state);
|
56 | }
|
57 | };
|
58 | const jsxElementVisitor = {
|
59 | JSXElement(path, state) {
|
60 | replaceElement(path, state);
|
61 | }
|
62 | };
|
63 | const importDeclarationVisitor = {
|
64 | ImportDeclaration(path, state) {
|
65 | if (path.get("source").isStringLiteral({ value: "react-native-svg" }) && !path.get("importKind").hasNode()) {
|
66 | state.replacedComponents.forEach((component) => {
|
67 | if (path.get("specifiers").some(
|
68 | (specifier) => specifier.get("local").isIdentifier({ name: component })
|
69 | )) {
|
70 | return;
|
71 | }
|
72 | path.pushContainer(
|
73 | "specifiers",
|
74 | core.types.importSpecifier(core.types.identifier(component), core.types.identifier(component))
|
75 | );
|
76 | });
|
77 | } else if (path.get("source").isStringLiteral({ value: "expo" })) {
|
78 | path.pushContainer(
|
79 | "specifiers",
|
80 | core.types.importSpecifier(core.types.identifier("Svg"), core.types.identifier("Svg"))
|
81 | );
|
82 | } else {
|
83 | return;
|
84 | }
|
85 | if (state.unsupportedComponents.size && !path.has("trailingComments")) {
|
86 | const componentList = [...state.unsupportedComponents].join(", ");
|
87 | path.addComment(
|
88 | "trailing",
|
89 | ` SVGR has dropped some elements not supported by react-native-svg: ${componentList} `
|
90 | );
|
91 | }
|
92 | }
|
93 | };
|
94 | return {
|
95 | visitor: {
|
96 | Program(path, state) {
|
97 | state.replacedComponents = new Set();
|
98 | state.unsupportedComponents = new Set();
|
99 | path.traverse(svgElementVisitor, state);
|
100 | path.traverse(importDeclarationVisitor, state);
|
101 | }
|
102 | }
|
103 | };
|
104 | };
|
105 |
|
106 | module.exports = plugin;
|
107 |
|