normalize-and-load-metadata.js 13 KB

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