normalize-and-load-metadata.js 10 KB

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