Plugin.js 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. "use strict";Object.defineProperty(exports, "__esModule", {value: true});var _path = require('path');
  2. var _helpermoduleimports = require('@babel/helper-module-imports');
  3. function transCamel(_str, symbol) {
  4. const str = _str[0].toLowerCase() + _str.substr(1);
  5. return str.replace(/([A-Z])/g, ($1) => `${symbol}${$1.toLowerCase()}`);
  6. }
  7. function winPath(path2) {
  8. return path2.replace(/\\/g, "/");
  9. }
  10. function normalizeCustomName(originCustomName) {
  11. if (typeof originCustomName === "string") {
  12. const customNameExports = require(originCustomName);
  13. return typeof customNameExports === "function" ? customNameExports : customNameExports.default;
  14. }
  15. return originCustomName;
  16. }
  17. class Plugin {
  18. constructor(libraryName, libraryDirectory, style, styleLibraryDirectory, customStyleName, camel2DashComponentName, camel2UnderlineComponentName, fileName, customName, transformToDefaultImport, types, index = 0) {
  19. this.libraryName = libraryName;
  20. this.libraryDirectory = typeof libraryDirectory === "undefined" ? "lib" : libraryDirectory;
  21. this.camel2DashComponentName = typeof camel2DashComponentName === "undefined" ? true : camel2DashComponentName;
  22. this.camel2UnderlineComponentName = camel2UnderlineComponentName;
  23. this.style = style || false;
  24. this.styleLibraryDirectory = styleLibraryDirectory;
  25. this.customStyleName = normalizeCustomName(customStyleName);
  26. this.fileName = fileName || "";
  27. this.customName = normalizeCustomName(customName);
  28. this.transformToDefaultImport = typeof transformToDefaultImport === "undefined" ? true : transformToDefaultImport;
  29. this.types = types;
  30. this.pluginStateKey = `importPluginState${index}`;
  31. }
  32. getPluginState(state) {
  33. if (!state[this.pluginStateKey]) {
  34. state[this.pluginStateKey] = {};
  35. }
  36. return state[this.pluginStateKey];
  37. }
  38. importMethod(methodName, file, pluginState) {
  39. if (!pluginState.selectedMethods[methodName]) {
  40. const {style, libraryDirectory} = this;
  41. const transformedMethodName = this.camel2UnderlineComponentName ? transCamel(methodName, "_") : this.camel2DashComponentName ? transCamel(methodName, "-") : methodName;
  42. const path2 = winPath(this.customName ? this.customName(transformedMethodName, file) : _path.join.call(void 0, this.libraryName, libraryDirectory, transformedMethodName, this.fileName));
  43. pluginState.selectedMethods[methodName] = this.transformToDefaultImport ? _helpermoduleimports.addDefault.call(void 0, file.path, path2, {nameHint: methodName}) : _helpermoduleimports.addNamed.call(void 0, file.path, methodName, path2);
  44. if (this.customStyleName) {
  45. const stylePath = winPath(this.customStyleName(transformedMethodName));
  46. _helpermoduleimports.addSideEffect.call(void 0, file.path, `${stylePath}`);
  47. } else if (this.styleLibraryDirectory) {
  48. const stylePath = winPath(_path.join.call(void 0, this.libraryName, this.styleLibraryDirectory, transformedMethodName, this.fileName));
  49. _helpermoduleimports.addSideEffect.call(void 0, file.path, `${stylePath}`);
  50. } else if (style === true) {
  51. _helpermoduleimports.addSideEffect.call(void 0, file.path, `${path2}/style`);
  52. } else if (style === "css") {
  53. _helpermoduleimports.addSideEffect.call(void 0, file.path, `${path2}/style/css`);
  54. } else if (typeof style === "function") {
  55. const stylePath = style(path2, file);
  56. if (stylePath) {
  57. _helpermoduleimports.addSideEffect.call(void 0, file.path, stylePath);
  58. }
  59. }
  60. }
  61. return {...pluginState.selectedMethods[methodName]};
  62. }
  63. buildExpressionHandler(node, props, path2, state) {
  64. const file = path2 && path2.hub && path2.hub.file || state && state.file;
  65. const {types} = this;
  66. const pluginState = this.getPluginState(state);
  67. props.forEach((prop) => {
  68. if (!types.isIdentifier(node[prop]))
  69. return;
  70. if (pluginState.specified[node[prop].name] && types.isImportSpecifier(path2.scope.getBinding(node[prop].name).path)) {
  71. node[prop] = this.importMethod(pluginState.specified[node[prop].name], file, pluginState);
  72. }
  73. });
  74. }
  75. buildDeclaratorHandler(node, prop, path2, state) {
  76. const file = path2 && path2.hub && path2.hub.file || state && state.file;
  77. const {types} = this;
  78. const pluginState = this.getPluginState(state);
  79. const checkScope = (targetNode) => pluginState.specified[targetNode.name] && path2.scope.hasBinding(targetNode.name) && path2.scope.getBinding(targetNode.name).path.type === "ImportSpecifier";
  80. if (types.isIdentifier(node[prop]) && checkScope(node[prop])) {
  81. node[prop] = this.importMethod(pluginState.specified[node[prop].name], file, pluginState);
  82. } else if (types.isSequenceExpression(node[prop])) {
  83. node[prop].expressions.forEach((expressionNode, index) => {
  84. if (types.isIdentifier(expressionNode) && checkScope(expressionNode)) {
  85. node[prop].expressions[index] = this.importMethod(pluginState.specified[expressionNode.name], file, pluginState);
  86. }
  87. });
  88. }
  89. }
  90. ProgramEnter(path2, state) {
  91. const pluginState = this.getPluginState(state);
  92. pluginState.specified = Object.create(null);
  93. pluginState.libraryObjs = Object.create(null);
  94. pluginState.selectedMethods = Object.create(null);
  95. pluginState.pathsToRemove = [];
  96. }
  97. ProgramExit(path2, state) {
  98. this.getPluginState(state).pathsToRemove.forEach((p) => !p.removed && p.remove());
  99. }
  100. ImportDeclaration(path2, state) {
  101. const {node} = path2;
  102. if (!node)
  103. return;
  104. const {value} = node.source;
  105. const {libraryName} = this;
  106. const {types} = this;
  107. const pluginState = this.getPluginState(state);
  108. if (value === libraryName) {
  109. node.specifiers.forEach((spec) => {
  110. if (types.isImportSpecifier(spec)) {
  111. pluginState.specified[spec.local.name] = spec.imported.name;
  112. } else {
  113. pluginState.libraryObjs[spec.local.name] = true;
  114. }
  115. });
  116. pluginState.pathsToRemove.push(path2);
  117. }
  118. }
  119. CallExpression(path2, state) {
  120. const {node} = path2;
  121. const file = path2 && path2.hub && path2.hub.file || state && state.file;
  122. const {name} = node.callee;
  123. const {types} = this;
  124. const pluginState = this.getPluginState(state);
  125. if (types.isIdentifier(node.callee)) {
  126. if (pluginState.specified[name]) {
  127. node.callee = this.importMethod(pluginState.specified[name], file, pluginState);
  128. }
  129. }
  130. node.arguments = node.arguments.map((arg) => {
  131. const {name: argName} = arg;
  132. if (pluginState.specified[argName] && path2.scope.hasBinding(argName) && path2.scope.getBinding(argName).path.type === "ImportSpecifier") {
  133. return this.importMethod(pluginState.specified[argName], file, pluginState);
  134. }
  135. return arg;
  136. });
  137. }
  138. MemberExpression(path2, state) {
  139. const {node} = path2;
  140. const file = path2 && path2.hub && path2.hub.file || state && state.file;
  141. const pluginState = this.getPluginState(state);
  142. if (!node.object || !node.object.name)
  143. return;
  144. if (pluginState.libraryObjs[node.object.name]) {
  145. path2.replaceWith(this.importMethod(node.property.name, file, pluginState));
  146. } else if (pluginState.specified[node.object.name] && path2.scope.hasBinding(node.object.name)) {
  147. const {scope} = path2.scope.getBinding(node.object.name);
  148. if (scope.path.parent.type === "File") {
  149. node.object = this.importMethod(pluginState.specified[node.object.name], file, pluginState);
  150. }
  151. }
  152. }
  153. Property(path2, state) {
  154. const {node} = path2;
  155. this.buildDeclaratorHandler(node, "value", path2, state);
  156. }
  157. VariableDeclarator(path2, state) {
  158. const {node} = path2;
  159. this.buildDeclaratorHandler(node, "init", path2, state);
  160. }
  161. ArrayExpression(path2, state) {
  162. const {node} = path2;
  163. const props = node.elements.map((_, index) => index);
  164. this.buildExpressionHandler(node.elements, props, path2, state);
  165. }
  166. LogicalExpression(path2, state) {
  167. const {node} = path2;
  168. this.buildExpressionHandler(node, ["left", "right"], path2, state);
  169. }
  170. ConditionalExpression(path2, state) {
  171. const {node} = path2;
  172. this.buildExpressionHandler(node, ["test", "consequent", "alternate"], path2, state);
  173. }
  174. IfStatement(path2, state) {
  175. const {node} = path2;
  176. this.buildExpressionHandler(node, ["test"], path2, state);
  177. this.buildExpressionHandler(node.test, ["left", "right"], path2, state);
  178. }
  179. ExpressionStatement(path2, state) {
  180. const {node} = path2;
  181. const {types} = this;
  182. if (types.isAssignmentExpression(node.expression)) {
  183. this.buildExpressionHandler(node.expression, ["right"], path2, state);
  184. }
  185. }
  186. ReturnStatement(path2, state) {
  187. const {node} = path2;
  188. this.buildExpressionHandler(node, ["argument"], path2, state);
  189. }
  190. ExportDefaultDeclaration(path2, state) {
  191. const {node} = path2;
  192. this.buildExpressionHandler(node, ["declaration"], path2, state);
  193. }
  194. BinaryExpression(path2, state) {
  195. const {node} = path2;
  196. this.buildExpressionHandler(node, ["left", "right"], path2, state);
  197. }
  198. NewExpression(path2, state) {
  199. const {node} = path2;
  200. this.buildExpressionHandler(node, ["callee", "arguments"], path2, state);
  201. }
  202. SwitchStatement(path2, state) {
  203. const {node} = path2;
  204. this.buildExpressionHandler(node, ["discriminant"], path2, state);
  205. }
  206. SwitchCase(path2, state) {
  207. const {node} = path2;
  208. this.buildExpressionHandler(node, ["test"], path2, state);
  209. }
  210. ClassDeclaration(path2, state) {
  211. const {node} = path2;
  212. this.buildExpressionHandler(node, ["superClass"], path2, state);
  213. }
  214. } exports.default = Plugin;