utils.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. "use strict";
  2. var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
  3. if (k2 === undefined) k2 = k;
  4. Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
  5. }) : (function(o, m, k, k2) {
  6. if (k2 === undefined) k2 = k;
  7. o[k2] = m[k];
  8. }));
  9. var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
  10. Object.defineProperty(o, "default", { enumerable: true, value: v });
  11. }) : function(o, v) {
  12. o["default"] = v;
  13. });
  14. var __importStar = (this && this.__importStar) || function (mod) {
  15. if (mod && mod.__esModule) return mod;
  16. var result = {};
  17. if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
  18. __setModuleDefault(result, mod);
  19. return result;
  20. };
  21. var __importDefault = (this && this.__importDefault) || function (mod) {
  22. return (mod && mod.__esModule) ? mod : { "default": mod };
  23. };
  24. Object.defineProperty(exports, "__esModule", { value: true });
  25. exports.transformJSXSpreadAttribute = exports.isConstant = exports.dedupeProperties = exports.isOn = exports.buildIIFE = exports.walksScope = exports.transformJSXSpreadChild = exports.transformJSXExpressionContainer = exports.transformJSXText = exports.getJSXAttributeName = exports.getTag = exports.transformJSXMemberExpression = exports.checkIsComponent = exports.shouldTransformedToSlots = exports.isDirective = exports.createIdentifier = exports.KEEP_ALIVE = exports.FRAGMENT = exports.JSX_HELPER_KEY = void 0;
  26. const t = __importStar(require("@babel/types"));
  27. const html_tags_1 = __importDefault(require("html-tags"));
  28. const svg_tags_1 = __importDefault(require("svg-tags"));
  29. exports.JSX_HELPER_KEY = 'JSX_HELPER_KEY';
  30. exports.FRAGMENT = 'Fragment';
  31. exports.KEEP_ALIVE = 'KeepAlive';
  32. /**
  33. * create Identifier
  34. * @param path NodePath
  35. * @param state
  36. * @param name string
  37. * @returns MemberExpression
  38. */
  39. const createIdentifier = (state, name) => state.get(name)();
  40. exports.createIdentifier = createIdentifier;
  41. /**
  42. * Checks if string is describing a directive
  43. * @param src string
  44. */
  45. const isDirective = (src) => src.startsWith('v-')
  46. || (src.startsWith('v') && src.length >= 2 && src[1] >= 'A' && src[1] <= 'Z');
  47. exports.isDirective = isDirective;
  48. /**
  49. * Should transformed to slots
  50. * @param tag string
  51. * @returns boolean
  52. */
  53. const shouldTransformedToSlots = (tag) => !(tag.endsWith(exports.FRAGMENT) || tag === exports.KEEP_ALIVE);
  54. exports.shouldTransformedToSlots = shouldTransformedToSlots;
  55. /**
  56. * Check if a Node is a component
  57. *
  58. * @param t
  59. * @param path JSXOpeningElement
  60. * @returns boolean
  61. */
  62. const checkIsComponent = (path, state) => {
  63. var _a, _b;
  64. const namePath = path.get('name');
  65. if (namePath.isJSXMemberExpression()) {
  66. return exports.shouldTransformedToSlots(namePath.node.property.name); // For withCtx
  67. }
  68. const tag = namePath.node.name;
  69. return !((_b = (_a = state.opts).isCustomElement) === null || _b === void 0 ? void 0 : _b.call(_a, tag)) && exports.shouldTransformedToSlots(tag) && !html_tags_1.default.includes(tag) && !svg_tags_1.default.includes(tag);
  70. };
  71. exports.checkIsComponent = checkIsComponent;
  72. /**
  73. * Transform JSXMemberExpression to MemberExpression
  74. * @param path JSXMemberExpression
  75. * @returns MemberExpression
  76. */
  77. const transformJSXMemberExpression = (path) => {
  78. const objectPath = path.node.object;
  79. const propertyPath = path.node.property;
  80. const transformedObject = t.isJSXMemberExpression(objectPath)
  81. ? exports.transformJSXMemberExpression(path.get('object'))
  82. : t.isJSXIdentifier(objectPath)
  83. ? t.identifier(objectPath.name)
  84. : t.nullLiteral();
  85. const transformedProperty = t.identifier(propertyPath.name);
  86. return t.memberExpression(transformedObject, transformedProperty);
  87. };
  88. exports.transformJSXMemberExpression = transformJSXMemberExpression;
  89. /**
  90. * Get tag (first attribute for h) from JSXOpeningElement
  91. * @param path JSXElement
  92. * @param state State
  93. * @returns Identifier | StringLiteral | MemberExpression | CallExpression
  94. */
  95. const getTag = (path, state) => {
  96. var _a, _b;
  97. const namePath = path.get('openingElement').get('name');
  98. if (namePath.isJSXIdentifier()) {
  99. const { name } = namePath.node;
  100. if (!html_tags_1.default.includes(name) && !svg_tags_1.default.includes(name)) {
  101. return (name === exports.FRAGMENT
  102. ? exports.createIdentifier(state, exports.FRAGMENT)
  103. : path.scope.hasBinding(name)
  104. ? t.identifier(name)
  105. : ((_b = (_a = state.opts).isCustomElement) === null || _b === void 0 ? void 0 : _b.call(_a, name))
  106. ? t.stringLiteral(name)
  107. : t.callExpression(exports.createIdentifier(state, 'resolveComponent'), [t.stringLiteral(name)]));
  108. }
  109. return t.stringLiteral(name);
  110. }
  111. if (namePath.isJSXMemberExpression()) {
  112. return exports.transformJSXMemberExpression(namePath);
  113. }
  114. throw new Error(`getTag: ${namePath.type} is not supported`);
  115. };
  116. exports.getTag = getTag;
  117. const getJSXAttributeName = (path) => {
  118. const nameNode = path.node.name;
  119. if (t.isJSXIdentifier(nameNode)) {
  120. return nameNode.name;
  121. }
  122. return `${nameNode.namespace.name}:${nameNode.name.name}`;
  123. };
  124. exports.getJSXAttributeName = getJSXAttributeName;
  125. /**
  126. * Transform JSXText to StringLiteral
  127. * @param path JSXText
  128. * @returns StringLiteral | null
  129. */
  130. const transformJSXText = (path) => {
  131. const { node } = path;
  132. const lines = node.value.split(/\r\n|\n|\r/);
  133. let lastNonEmptyLine = 0;
  134. for (let i = 0; i < lines.length; i++) {
  135. if (lines[i].match(/[^ \t]/)) {
  136. lastNonEmptyLine = i;
  137. }
  138. }
  139. let str = '';
  140. for (let i = 0; i < lines.length; i++) {
  141. const line = lines[i];
  142. const isFirstLine = i === 0;
  143. const isLastLine = i === lines.length - 1;
  144. const isLastNonEmptyLine = i === lastNonEmptyLine;
  145. // replace rendered whitespace tabs with spaces
  146. let trimmedLine = line.replace(/\t/g, ' ');
  147. // trim whitespace touching a newline
  148. if (!isFirstLine) {
  149. trimmedLine = trimmedLine.replace(/^[ ]+/, '');
  150. }
  151. // trim whitespace touching an endline
  152. if (!isLastLine) {
  153. trimmedLine = trimmedLine.replace(/[ ]+$/, '');
  154. }
  155. if (trimmedLine) {
  156. if (!isLastNonEmptyLine) {
  157. trimmedLine += ' ';
  158. }
  159. str += trimmedLine;
  160. }
  161. }
  162. return str !== '' ? t.stringLiteral(str) : null;
  163. };
  164. exports.transformJSXText = transformJSXText;
  165. /**
  166. * Transform JSXExpressionContainer to Expression
  167. * @param path JSXExpressionContainer
  168. * @returns Expression
  169. */
  170. const transformJSXExpressionContainer = (path) => path.get('expression').node;
  171. exports.transformJSXExpressionContainer = transformJSXExpressionContainer;
  172. /**
  173. * Transform JSXSpreadChild
  174. * @param path JSXSpreadChild
  175. * @returns SpreadElement
  176. */
  177. const transformJSXSpreadChild = (path) => t.spreadElement(path.get('expression').node);
  178. exports.transformJSXSpreadChild = transformJSXSpreadChild;
  179. const walksScope = (path, name, slotFlag) => {
  180. if (path.scope.hasBinding(name) && path.parentPath) {
  181. if (t.isJSXElement(path.parentPath.node)) {
  182. path.parentPath.setData('slotFlag', slotFlag);
  183. }
  184. exports.walksScope(path.parentPath, name, slotFlag);
  185. }
  186. };
  187. exports.walksScope = walksScope;
  188. const buildIIFE = (path, children) => {
  189. const { parentPath } = path;
  190. if (t.isAssignmentExpression(parentPath)) {
  191. const { left } = parentPath.node;
  192. if (t.isIdentifier(left)) {
  193. return children.map((child) => {
  194. if (t.isIdentifier(child) && child.name === left.name) {
  195. const insertName = path.scope.generateUidIdentifier(child.name);
  196. parentPath.insertBefore(t.variableDeclaration('const', [
  197. t.variableDeclarator(insertName, t.callExpression(t.functionExpression(null, [], t.blockStatement([t.returnStatement(child)])), [])),
  198. ]));
  199. return insertName;
  200. }
  201. return child;
  202. });
  203. }
  204. }
  205. return children;
  206. };
  207. exports.buildIIFE = buildIIFE;
  208. const onRE = /^on[^a-z]/;
  209. const isOn = (key) => onRE.test(key);
  210. exports.isOn = isOn;
  211. const mergeAsArray = (existing, incoming) => {
  212. if (t.isArrayExpression(existing.value)) {
  213. existing.value.elements.push(incoming.value);
  214. }
  215. else {
  216. existing.value = t.arrayExpression([
  217. existing.value,
  218. incoming.value,
  219. ]);
  220. }
  221. };
  222. const dedupeProperties = (properties = [], mergeProps) => {
  223. if (!mergeProps) {
  224. return properties;
  225. }
  226. const knownProps = new Map();
  227. const deduped = [];
  228. properties.forEach((prop) => {
  229. if (t.isStringLiteral(prop.key)) {
  230. const { value: name } = prop.key;
  231. const existing = knownProps.get(name);
  232. if (existing) {
  233. if (name === 'style' || name === 'class' || name.startsWith('on')) {
  234. mergeAsArray(existing, prop);
  235. }
  236. }
  237. else {
  238. knownProps.set(name, prop);
  239. deduped.push(prop);
  240. }
  241. }
  242. else {
  243. // v-model target with variable
  244. deduped.push(prop);
  245. }
  246. });
  247. return deduped;
  248. };
  249. exports.dedupeProperties = dedupeProperties;
  250. /**
  251. * Check if an attribute value is constant
  252. * @param node
  253. * @returns boolean
  254. */
  255. const isConstant = (node) => {
  256. if (t.isIdentifier(node)) {
  257. return node.name === 'undefined';
  258. }
  259. if (t.isArrayExpression(node)) {
  260. const { elements } = node;
  261. return elements.every((element) => element && exports.isConstant(element));
  262. }
  263. if (t.isObjectExpression(node)) {
  264. return node.properties.every((property) => exports.isConstant(property.value));
  265. }
  266. if (t.isLiteral(node)) {
  267. return true;
  268. }
  269. return false;
  270. };
  271. exports.isConstant = isConstant;
  272. const transformJSXSpreadAttribute = (nodePath, path, mergeProps, args) => {
  273. const argument = path.get('argument');
  274. const properties = t.isObjectExpression(argument.node) ? argument.node.properties : undefined;
  275. if (!properties) {
  276. if (argument.isIdentifier()) {
  277. exports.walksScope(nodePath, argument.node.name, 2 /* DYNAMIC */);
  278. }
  279. args.push(mergeProps ? argument.node : t.spreadElement(argument.node));
  280. }
  281. else if (mergeProps) {
  282. args.push(t.objectExpression(properties));
  283. }
  284. else {
  285. args.push(...properties);
  286. }
  287. };
  288. exports.transformJSXSpreadAttribute = transformJSXSpreadAttribute;