UNPKG

12.6 kBJavaScriptView Raw
1"use strict";
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6exports.default = normalizeModuleAndLoadMetadata;
7exports.hasExports = hasExports;
8exports.isSideEffectImport = isSideEffectImport;
9exports.validateImportInteropOption = validateImportInteropOption;
10
11var _path = require("path");
12
13var _helperValidatorIdentifier = require("@babel/helper-validator-identifier");
14
15var _helperSplitExportDeclaration = require("@babel/helper-split-export-declaration");
16
17function hasExports(metadata) {
18 return metadata.hasExports;
19}
20
21function isSideEffectImport(source) {
22 return source.imports.size === 0 && source.importsNamespace.size === 0 && source.reexports.size === 0 && source.reexportNamespace.size === 0 && !source.reexportAll;
23}
24
25function validateImportInteropOption(importInterop) {
26 if (typeof importInterop !== "function" && importInterop !== "none" && importInterop !== "babel" && importInterop !== "node") {
27 throw new Error(`.importInterop must be one of "none", "babel", "node", or a function returning one of those values (received ${importInterop}).`);
28 }
29
30 return importInterop;
31}
32
33function resolveImportInterop(importInterop, source, filename) {
34 if (typeof importInterop === "function") {
35 return validateImportInteropOption(importInterop(source, filename));
36 }
37
38 return importInterop;
39}
40
41function normalizeModuleAndLoadMetadata(programPath, exportName, {
42 importInterop,
43 initializeReexports = false,
44 lazy = false,
45 esNamespaceOnly = false,
46 filename
47}) {
48 if (!exportName) {
49 exportName = programPath.scope.generateUidIdentifier("exports").name;
50 }
51
52 const stringSpecifiers = new Set();
53 nameAnonymousExports(programPath);
54 const {
55 local,
56 source,
57 hasExports
58 } = getModuleMetadata(programPath, {
59 initializeReexports,
60 lazy
61 }, stringSpecifiers);
62 removeModuleDeclarations(programPath);
63
64 for (const [, metadata] of source) {
65 if (metadata.importsNamespace.size > 0) {
66 metadata.name = metadata.importsNamespace.values().next().value;
67 }
68
69 const resolvedInterop = resolveImportInterop(importInterop, metadata.source, filename);
70
71 if (resolvedInterop === "none") {
72 metadata.interop = "none";
73 } else if (resolvedInterop === "node" && metadata.interop === "namespace") {
74 metadata.interop = "node-namespace";
75 } else if (resolvedInterop === "node" && metadata.interop === "default") {
76 metadata.interop = "node-default";
77 } else if (esNamespaceOnly && metadata.interop === "namespace") {
78 metadata.interop = "default";
79 }
80 }
81
82 return {
83 exportName,
84 exportNameListName: null,
85 hasExports,
86 local,
87 source,
88 stringSpecifiers
89 };
90}
91
92function getExportSpecifierName(path, stringSpecifiers) {
93 if (path.isIdentifier()) {
94 return path.node.name;
95 } else if (path.isStringLiteral()) {
96 const stringValue = path.node.value;
97
98 if (!(0, _helperValidatorIdentifier.isIdentifierName)(stringValue)) {
99 stringSpecifiers.add(stringValue);
100 }
101
102 return stringValue;
103 } else {
104 throw new Error(`Expected export specifier to be either Identifier or StringLiteral, got ${path.node.type}`);
105 }
106}
107
108function assertExportSpecifier(path) {
109 if (path.isExportSpecifier()) {
110 return;
111 } else if (path.isExportNamespaceSpecifier()) {
112 throw path.buildCodeFrameError("Export namespace should be first transformed by `@babel/plugin-proposal-export-namespace-from`.");
113 } else {
114 throw path.buildCodeFrameError("Unexpected export specifier type");
115 }
116}
117
118function getModuleMetadata(programPath, {
119 lazy,
120 initializeReexports
121}, stringSpecifiers) {
122 const localData = getLocalExportMetadata(programPath, initializeReexports, stringSpecifiers);
123 const sourceData = new Map();
124
125 const getData = sourceNode => {
126 const source = sourceNode.value;
127 let data = sourceData.get(source);
128
129 if (!data) {
130 data = {
131 name: programPath.scope.generateUidIdentifier((0, _path.basename)(source, (0, _path.extname)(source))).name,
132 interop: "none",
133 loc: null,
134 imports: new Map(),
135 importsNamespace: new Set(),
136 reexports: new Map(),
137 reexportNamespace: new Set(),
138 reexportAll: null,
139 lazy: false,
140 source
141 };
142 sourceData.set(source, data);
143 }
144
145 return data;
146 };
147
148 let hasExports = false;
149 programPath.get("body").forEach(child => {
150 if (child.isImportDeclaration()) {
151 const data = getData(child.node.source);
152 if (!data.loc) data.loc = child.node.loc;
153 child.get("specifiers").forEach(spec => {
154 if (spec.isImportDefaultSpecifier()) {
155 const localName = spec.get("local").node.name;
156 data.imports.set(localName, "default");
157 const reexport = localData.get(localName);
158
159 if (reexport) {
160 localData.delete(localName);
161 reexport.names.forEach(name => {
162 data.reexports.set(name, "default");
163 });
164 }
165 } else if (spec.isImportNamespaceSpecifier()) {
166 const localName = spec.get("local").node.name;
167 data.importsNamespace.add(localName);
168 const reexport = localData.get(localName);
169
170 if (reexport) {
171 localData.delete(localName);
172 reexport.names.forEach(name => {
173 data.reexportNamespace.add(name);
174 });
175 }
176 } else if (spec.isImportSpecifier()) {
177 const importName = getExportSpecifierName(spec.get("imported"), stringSpecifiers);
178 const localName = spec.get("local").node.name;
179 data.imports.set(localName, importName);
180 const reexport = localData.get(localName);
181
182 if (reexport) {
183 localData.delete(localName);
184 reexport.names.forEach(name => {
185 data.reexports.set(name, importName);
186 });
187 }
188 }
189 });
190 } else if (child.isExportAllDeclaration()) {
191 hasExports = true;
192 const data = getData(child.node.source);
193 if (!data.loc) data.loc = child.node.loc;
194 data.reexportAll = {
195 loc: child.node.loc
196 };
197 } else if (child.isExportNamedDeclaration() && child.node.source) {
198 hasExports = true;
199 const data = getData(child.node.source);
200 if (!data.loc) data.loc = child.node.loc;
201 child.get("specifiers").forEach(spec => {
202 assertExportSpecifier(spec);
203 const importName = getExportSpecifierName(spec.get("local"), stringSpecifiers);
204 const exportName = getExportSpecifierName(spec.get("exported"), stringSpecifiers);
205 data.reexports.set(exportName, importName);
206
207 if (exportName === "__esModule") {
208 throw spec.get("exported").buildCodeFrameError('Illegal export "__esModule".');
209 }
210 });
211 } else if (child.isExportNamedDeclaration() || child.isExportDefaultDeclaration()) {
212 hasExports = true;
213 }
214 });
215
216 for (const metadata of sourceData.values()) {
217 let needsDefault = false;
218 let needsNamed = false;
219
220 if (metadata.importsNamespace.size > 0) {
221 needsDefault = true;
222 needsNamed = true;
223 }
224
225 if (metadata.reexportAll) {
226 needsNamed = true;
227 }
228
229 for (const importName of metadata.imports.values()) {
230 if (importName === "default") needsDefault = true;else needsNamed = true;
231 }
232
233 for (const importName of metadata.reexports.values()) {
234 if (importName === "default") needsDefault = true;else needsNamed = true;
235 }
236
237 if (needsDefault && needsNamed) {
238 metadata.interop = "namespace";
239 } else if (needsDefault) {
240 metadata.interop = "default";
241 }
242 }
243
244 for (const [source, metadata] of sourceData) {
245 if (lazy !== false && !(isSideEffectImport(metadata) || metadata.reexportAll)) {
246 if (lazy === true) {
247 metadata.lazy = !/\./.test(source);
248 } else if (Array.isArray(lazy)) {
249 metadata.lazy = lazy.indexOf(source) !== -1;
250 } else if (typeof lazy === "function") {
251 metadata.lazy = lazy(source);
252 } else {
253 throw new Error(`.lazy must be a boolean, string array, or function`);
254 }
255 }
256 }
257
258 return {
259 hasExports,
260 local: localData,
261 source: sourceData
262 };
263}
264
265function getLocalExportMetadata(programPath, initializeReexports, stringSpecifiers) {
266 const bindingKindLookup = new Map();
267 programPath.get("body").forEach(child => {
268 let kind;
269
270 if (child.isImportDeclaration()) {
271 kind = "import";
272 } else {
273 if (child.isExportDefaultDeclaration()) {
274 child = child.get("declaration");
275 }
276
277 if (child.isExportNamedDeclaration()) {
278 if (child.node.declaration) {
279 child = child.get("declaration");
280 } else if (initializeReexports && child.node.source && child.get("source").isStringLiteral()) {
281 child.get("specifiers").forEach(spec => {
282 assertExportSpecifier(spec);
283 bindingKindLookup.set(spec.get("local").node.name, "block");
284 });
285 return;
286 }
287 }
288
289 if (child.isFunctionDeclaration()) {
290 kind = "hoisted";
291 } else if (child.isClassDeclaration()) {
292 kind = "block";
293 } else if (child.isVariableDeclaration({
294 kind: "var"
295 })) {
296 kind = "var";
297 } else if (child.isVariableDeclaration()) {
298 kind = "block";
299 } else {
300 return;
301 }
302 }
303
304 Object.keys(child.getOuterBindingIdentifiers()).forEach(name => {
305 bindingKindLookup.set(name, kind);
306 });
307 });
308 const localMetadata = new Map();
309
310 const getLocalMetadata = idPath => {
311 const localName = idPath.node.name;
312 let metadata = localMetadata.get(localName);
313
314 if (!metadata) {
315 const kind = bindingKindLookup.get(localName);
316
317 if (kind === undefined) {
318 throw idPath.buildCodeFrameError(`Exporting local "${localName}", which is not declared.`);
319 }
320
321 metadata = {
322 names: [],
323 kind
324 };
325 localMetadata.set(localName, metadata);
326 }
327
328 return metadata;
329 };
330
331 programPath.get("body").forEach(child => {
332 if (child.isExportNamedDeclaration() && (initializeReexports || !child.node.source)) {
333 if (child.node.declaration) {
334 const declaration = child.get("declaration");
335 const ids = declaration.getOuterBindingIdentifierPaths();
336 Object.keys(ids).forEach(name => {
337 if (name === "__esModule") {
338 throw declaration.buildCodeFrameError('Illegal export "__esModule".');
339 }
340
341 getLocalMetadata(ids[name]).names.push(name);
342 });
343 } else {
344 child.get("specifiers").forEach(spec => {
345 const local = spec.get("local");
346 const exported = spec.get("exported");
347 const localMetadata = getLocalMetadata(local);
348 const exportName = getExportSpecifierName(exported, stringSpecifiers);
349
350 if (exportName === "__esModule") {
351 throw exported.buildCodeFrameError('Illegal export "__esModule".');
352 }
353
354 localMetadata.names.push(exportName);
355 });
356 }
357 } else if (child.isExportDefaultDeclaration()) {
358 const declaration = child.get("declaration");
359
360 if (declaration.isFunctionDeclaration() || declaration.isClassDeclaration()) {
361 getLocalMetadata(declaration.get("id")).names.push("default");
362 } else {
363 throw declaration.buildCodeFrameError("Unexpected default expression export.");
364 }
365 }
366 });
367 return localMetadata;
368}
369
370function nameAnonymousExports(programPath) {
371 programPath.get("body").forEach(child => {
372 if (!child.isExportDefaultDeclaration()) return;
373 (0, _helperSplitExportDeclaration.default)(child);
374 });
375}
376
377function removeModuleDeclarations(programPath) {
378 programPath.get("body").forEach(child => {
379 if (child.isImportDeclaration()) {
380 child.remove();
381 } else if (child.isExportNamedDeclaration()) {
382 if (child.node.declaration) {
383 child.node.declaration._blockHoist = child.node._blockHoist;
384 child.replaceWith(child.node.declaration);
385 } else {
386 child.remove();
387 }
388 } else if (child.isExportDefaultDeclaration()) {
389 const declaration = child.get("declaration");
390
391 if (declaration.isFunctionDeclaration() || declaration.isClassDeclaration()) {
392 declaration._blockHoist = child.node._blockHoist;
393 child.replaceWith(declaration);
394 } else {
395 throw declaration.buildCodeFrameError("Unexpected default expression export.");
396 }
397 } else if (child.isExportAllDeclaration()) {
398 child.remove();
399 }
400 });
401}
402
403//# sourceMappingURL=normalize-and-load-metadata.js.map