版博士V2.0程序
Não pode escolher mais do que 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 
 

220 linhas
6.4 KiB

  1. // src/core/utils.ts
  2. function getChildrenLocation(node) {
  3. if (node.children.length > 0) {
  4. const lastChild = node.children[node.children.length - 1];
  5. return [node.children[0].loc.start.offset, lastChild.loc.end.offset];
  6. } else {
  7. return void 0;
  8. }
  9. }
  10. function parseVueRequest(id) {
  11. const [filename, rawQuery] = id.split(`?`, 2);
  12. const query = Object.fromEntries(new URLSearchParams(rawQuery));
  13. if (query.vue != null) {
  14. query.vue = true;
  15. }
  16. if (query.index != null) {
  17. query.index = Number(query.index);
  18. }
  19. if (query.raw != null) {
  20. query.raw = true;
  21. }
  22. if (query.url != null) {
  23. query.url = true;
  24. }
  25. if (query.scoped != null) {
  26. query.scoped = true;
  27. }
  28. return {
  29. filename,
  30. query
  31. };
  32. }
  33. // src/core/constants.ts
  34. var QUERY_NAMED_TEMPLATE = "?vue&type=named-template";
  35. var QUERY_TEMPLATE = "type=template&namedTemplate";
  36. var QUERY_TEMPLATE_MAIN = `${QUERY_TEMPLATE}&mainTemplate`;
  37. var MAIN_TEMPLATE = Symbol();
  38. // src/core/index.ts
  39. import {
  40. HELPER_PREFIX,
  41. MagicString,
  42. babelParse,
  43. getLang,
  44. getTransformResult,
  45. importHelperFn,
  46. isCallOf,
  47. walkAST
  48. } from "@vue-macros/common";
  49. import { createTransformContext, parse, traverseNode } from "@vue/compiler-dom";
  50. function transformTemplateIs(s) {
  51. return (node) => {
  52. if (!(node.type === 1 && node.tag === "template"))
  53. return;
  54. const propIs = node.props.find(
  55. (prop) => prop.type === 6 && prop.name === "is"
  56. );
  57. if (!(propIs == null ? void 0 : propIs.value))
  58. return;
  59. const refName = propIs.value.content;
  60. s.overwrite(
  61. node.loc.start.offset,
  62. node.loc.end.offset,
  63. `<component is="named-template-${refName}" />`
  64. );
  65. };
  66. }
  67. function preTransform(code, id, templateContent) {
  68. const root = parse(code);
  69. const templates = root.children.filter(
  70. (node) => node.type === 1 && node.tag === "template"
  71. );
  72. if (templates.length <= 1)
  73. return;
  74. const s = new MagicString(code);
  75. for (const node of templates) {
  76. const propName = node.props.find(
  77. (prop) => prop.type === 6 && prop.name === "name"
  78. );
  79. if (!propName) {
  80. preTransformMainTemplate({ s, root, node, id, templateContent });
  81. continue;
  82. } else if (!propName.value) {
  83. continue;
  84. }
  85. const name = propName.value.content;
  86. let template = "";
  87. const templateLoc = getChildrenLocation(node);
  88. if (templateLoc) {
  89. template = s.slice(...templateLoc);
  90. }
  91. if (!templateContent[id])
  92. templateContent[id] = {};
  93. templateContent[id][name] = template;
  94. s.appendLeft(node.loc.start.offset, `<named-template name="${name}">`);
  95. s.appendLeft(node.loc.end.offset, "</named-template>");
  96. }
  97. return getTransformResult(s, id);
  98. }
  99. function preTransformMainTemplate({
  100. s,
  101. root,
  102. node,
  103. id,
  104. templateContent
  105. }) {
  106. const ctx = createTransformContext(root, {
  107. filename: id,
  108. nodeTransforms: [transformTemplateIs(s)]
  109. });
  110. traverseNode(node, ctx);
  111. const loc = getChildrenLocation(node);
  112. if (!loc)
  113. return;
  114. if (!templateContent[id])
  115. templateContent[id] = {};
  116. templateContent[id][MAIN_TEMPLATE] = s.slice(...loc);
  117. s.remove(...loc);
  118. const offset = node.loc.start.offset + 1 + node.tag.length;
  119. s.appendLeft(offset, ` src="${`${id}?vue&${QUERY_TEMPLATE_MAIN}`}"`);
  120. }
  121. function postTransform(code, id, customBlocks) {
  122. var _a, _b, _c;
  123. const lang = getLang(id);
  124. const program = babelParse(code, lang);
  125. const { filename } = parseVueRequest(id);
  126. if (!id.includes(QUERY_TEMPLATE_MAIN)) {
  127. postTransformMainEntry(program, filename, customBlocks);
  128. return;
  129. }
  130. const s = new MagicString(code);
  131. const subTemplates = [];
  132. for (const node of program.body) {
  133. if (node.type === "ExportNamedDeclaration" && ((_a = node.declaration) == null ? void 0 : _a.type) === "FunctionDeclaration" && ((_b = node.declaration.id) == null ? void 0 : _b.name) === "render") {
  134. const params = node.declaration.params;
  135. if (params.length > 0) {
  136. const lastParams = params[node.declaration.params.length - 1];
  137. const loc = [params[0].start, lastParams.end];
  138. const paramsText = s.slice(...loc);
  139. s.overwrite(...loc, "...args");
  140. s.appendLeft(
  141. node.declaration.body.start + 1,
  142. `
  143. let [${paramsText}] = args`
  144. );
  145. }
  146. }
  147. }
  148. walkAST(program, {
  149. enter(node) {
  150. if (isCallOf(node, ["_createVNode", "_createBlock"]) && isCallOf(node.arguments[0], "_resolveDynamicComponent") && node.arguments[0].arguments[0].type === "StringLiteral" && node.arguments[0].arguments[0].value.startsWith("named-template-")) {
  151. subTemplates.push({
  152. vnode: node,
  153. component: node.arguments[0],
  154. name: node.arguments[0].arguments[0].value.replace(
  155. "named-template-",
  156. ""
  157. ),
  158. fnName: node.callee.name
  159. });
  160. }
  161. }
  162. });
  163. if (subTemplates.length === 0)
  164. return;
  165. for (const { vnode, component, name, fnName } of subTemplates) {
  166. const block = (_c = customBlocks[filename]) == null ? void 0 : _c[name];
  167. if (!block)
  168. throw new SyntaxError(`Unknown named template: ${name}`);
  169. const render = `${HELPER_PREFIX}block_${escapeTemplateName(
  170. name
  171. )}.render(...args)`;
  172. if (fnName === "_createVNode") {
  173. s.overwriteNode(vnode, render);
  174. } else if (fnName === "_createBlock") {
  175. importHelperFn(s, 0, "Fragment", "vue");
  176. s.overwriteNode(component, `${HELPER_PREFIX}Fragment`);
  177. const text = `${vnode.arguments[1] ? "" : ", null"}, [${render}]`;
  178. s.appendLeft((vnode.arguments[1] || vnode.arguments[0]).end, text);
  179. }
  180. }
  181. for (const [name, source] of Object.entries(customBlocks[filename])) {
  182. s.prepend(
  183. `import { default as ${HELPER_PREFIX}block_${escapeTemplateName(
  184. name
  185. )} } from ${JSON.stringify(source)}
  186. `
  187. );
  188. }
  189. return getTransformResult(s, id);
  190. }
  191. function postTransformMainEntry(program, id, customBlocks) {
  192. for (const node of program.body) {
  193. if (node.type === "ImportDeclaration" && node.source.value.includes(QUERY_NAMED_TEMPLATE)) {
  194. const { name } = parseVueRequest(node.source.value).query;
  195. if (!customBlocks[id])
  196. customBlocks[id] = {};
  197. customBlocks[id][name] = node.source.value;
  198. }
  199. }
  200. }
  201. function escapeTemplateName(name) {
  202. return name.replace(/-/g, "$DASH");
  203. }
  204. export {
  205. getChildrenLocation,
  206. parseVueRequest,
  207. QUERY_NAMED_TEMPLATE,
  208. QUERY_TEMPLATE,
  209. QUERY_TEMPLATE_MAIN,
  210. MAIN_TEMPLATE,
  211. transformTemplateIs,
  212. preTransform,
  213. preTransformMainTemplate,
  214. postTransform,
  215. postTransformMainEntry
  216. };