UNPKG

5.33 kBJavaScriptView Raw
1"use strict";
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6exports.default = transpileNamespace;
7
8var _core = require("@babel/core");
9
10function transpileNamespace(path, t, allowNamespaces) {
11 if (path.node.declare || path.node.id.type === "StringLiteral") {
12 path.remove();
13 return;
14 }
15
16 if (!allowNamespaces) {
17 throw path.hub.file.buildCodeFrameError(path.node.id, "Namespace not marked type-only declare." + " Non-declarative namespaces are only supported experimentally in Babel." + " To enable and review caveats see:" + " https://babeljs.io/docs/en/babel-plugin-transform-typescript");
18 }
19
20 const name = path.node.id.name;
21 const value = handleNested(path, t, t.cloneDeep(path.node));
22 const bound = path.scope.hasOwnBinding(name);
23
24 if (path.parent.type === "ExportNamedDeclaration") {
25 if (!bound) {
26 path.parentPath.insertAfter(value);
27 path.replaceWith(getDeclaration(t, name));
28 path.scope.registerDeclaration(path.parentPath);
29 } else {
30 path.parentPath.replaceWith(value);
31 }
32 } else if (bound) {
33 path.replaceWith(value);
34 } else {
35 path.scope.registerDeclaration(path.replaceWithMultiple([getDeclaration(t, name), value])[0]);
36 }
37}
38
39function getDeclaration(t, name) {
40 return t.variableDeclaration("let", [t.variableDeclarator(t.identifier(name))]);
41}
42
43function getMemberExpression(t, name, itemName) {
44 return t.memberExpression(t.identifier(name), t.identifier(itemName));
45}
46
47function handleVariableDeclaration(node, name, hub) {
48 if (node.kind !== "const") {
49 throw hub.file.buildCodeFrameError(node, "Namespaces exporting non-const are not supported by Babel." + " Change to const or see:" + " https://babeljs.io/docs/en/babel-plugin-transform-typescript");
50 }
51
52 const {
53 declarations
54 } = node;
55
56 if (declarations.every(declarator => _core.types.isIdentifier(declarator.id))) {
57 for (const declarator of node.declarations) {
58 declarator.init = _core.types.assignmentExpression("=", getMemberExpression(_core.types, name, declarator.id.name), declarator.init);
59 }
60
61 return [node];
62 }
63
64 const bindingIdentifiers = _core.types.getBindingIdentifiers(node);
65
66 const assignments = [];
67
68 for (const idName in bindingIdentifiers) {
69 assignments.push(_core.types.assignmentExpression("=", getMemberExpression(_core.types, name, idName), _core.types.cloneNode(bindingIdentifiers[idName])));
70 }
71
72 return [node, _core.types.expressionStatement(_core.types.sequenceExpression(assignments))];
73}
74
75function handleNested(path, t, node, parentExport) {
76 const names = new Set();
77 const realName = node.id;
78 const name = path.scope.generateUid(realName.name);
79 const namespaceTopLevel = node.body.body;
80
81 for (let i = 0; i < namespaceTopLevel.length; i++) {
82 const subNode = namespaceTopLevel[i];
83
84 switch (subNode.type) {
85 case "TSModuleDeclaration":
86 {
87 const transformed = handleNested(path, t, subNode);
88 const moduleName = subNode.id.name;
89
90 if (names.has(moduleName)) {
91 namespaceTopLevel[i] = transformed;
92 } else {
93 names.add(moduleName);
94 namespaceTopLevel.splice(i++, 1, getDeclaration(t, moduleName), transformed);
95 }
96
97 continue;
98 }
99
100 case "TSEnumDeclaration":
101 case "FunctionDeclaration":
102 case "ClassDeclaration":
103 names.add(subNode.id.name);
104 continue;
105
106 case "VariableDeclaration":
107 {
108 for (const name in t.getBindingIdentifiers(subNode)) {
109 names.add(name);
110 }
111
112 continue;
113 }
114
115 default:
116 continue;
117
118 case "ExportNamedDeclaration":
119 }
120
121 switch (subNode.declaration.type) {
122 case "TSEnumDeclaration":
123 case "FunctionDeclaration":
124 case "ClassDeclaration":
125 {
126 const itemName = subNode.declaration.id.name;
127 names.add(itemName);
128 namespaceTopLevel.splice(i++, 1, subNode.declaration, t.expressionStatement(t.assignmentExpression("=", getMemberExpression(t, name, itemName), t.identifier(itemName))));
129 break;
130 }
131
132 case "VariableDeclaration":
133 {
134 const nodes = handleVariableDeclaration(subNode.declaration, name, path.hub);
135 namespaceTopLevel.splice(i, nodes.length, ...nodes);
136 i += nodes.length - 1;
137 break;
138 }
139
140 case "TSModuleDeclaration":
141 {
142 const transformed = handleNested(path, t, subNode.declaration, t.identifier(name));
143 const moduleName = subNode.declaration.id.name;
144
145 if (names.has(moduleName)) {
146 namespaceTopLevel[i] = transformed;
147 } else {
148 names.add(moduleName);
149 namespaceTopLevel.splice(i++, 1, getDeclaration(t, moduleName), transformed);
150 }
151 }
152 }
153 }
154
155 let fallthroughValue = t.objectExpression([]);
156
157 if (parentExport) {
158 const memberExpr = t.memberExpression(parentExport, realName);
159 fallthroughValue = _core.template.expression.ast`
160 ${t.cloneNode(memberExpr)} ||
161 (${t.cloneNode(memberExpr)} = ${fallthroughValue})
162 `;
163 }
164
165 return _core.template.statement.ast`
166 (function (${t.identifier(name)}) {
167 ${namespaceTopLevel}
168 })(${realName} || (${t.cloneNode(realName)} = ${fallthroughValue}));
169 `;
170}
\No newline at end of file