You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

345 lines
10 KiB

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