版博士V2.0程序
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.
 
 
 
 

488 lines
17 KiB

  1. // src/core/helper/emit-helper.ts?raw
  2. var emit_helper_default = "export default(emitFn,key,value,...args)=>{emitFn(key,value);return args.length>0?args[0]:value};\n";
  3. // src/core/helper/use-vmodel.ts?raw
  4. var use_vmodel_default = 'import{getCurrentInstance}from"vue";import{useVModel}from"@vueuse/core";export default(...keys)=>{const props=getCurrentInstance().proxy.$props;const ret={};for(const _k of keys){if(typeof _k==="string"){ret[_k]=useVModel(props,_k,void 0,{eventName:`update:${_k}`,passive:true})}else{const[key,prop=key,eventName=`update:${key}`,options={}]=_k;ret[key]=useVModel(props,prop,void 0,{eventName,passive:true,...options})}}return ret};\n';
  5. // src/core/helper/index.ts
  6. var helperPrefix = "/vue-macros/define-model";
  7. var emitHelperId = `${helperPrefix}/emit-helper`;
  8. var useVmodelHelperId = `${helperPrefix}/use-vmodel`;
  9. // src/core/index.ts
  10. import { extractIdentifiers, walkAST } from "ast-walker-scope";
  11. import {
  12. DEFINE_EMITS,
  13. DEFINE_MODEL,
  14. DEFINE_MODEL_DOLLAR,
  15. DEFINE_OPTIONS,
  16. DEFINE_PROPS,
  17. HELPER_PREFIX,
  18. MagicString,
  19. REPO_ISSUE_URL,
  20. WITH_DEFAULTS,
  21. getTransformResult,
  22. isCallOf,
  23. parseSFC,
  24. resolveObjectKey
  25. } from "@vue-macros/common";
  26. function transformDefineModel(code, id, version, unified) {
  27. let hasDefineProps = false;
  28. let hasDefineEmits = false;
  29. let hasDefineModel = false;
  30. let propsTypeDecl;
  31. let propsDestructureDecl;
  32. let emitsTypeDecl;
  33. let emitsIdentifier;
  34. let runtimeDefineFn;
  35. let modelDecl;
  36. let modelDeclKind;
  37. let modelTypeDecl;
  38. let modelIdentifier;
  39. let modelDestructureDecl;
  40. const modelIdentifiers = /* @__PURE__ */ new Set();
  41. const modelVue2 = { prop: "", event: "" };
  42. let mode;
  43. function processDefinePropsOrEmits(node, declId) {
  44. var _a, _b;
  45. if (isCallOf(node, WITH_DEFAULTS)) {
  46. node = node.arguments[0];
  47. }
  48. let type;
  49. if (isCallOf(node, DEFINE_PROPS)) {
  50. type = "props";
  51. } else if (isCallOf(node, DEFINE_EMITS)) {
  52. type = "emits";
  53. } else {
  54. return false;
  55. }
  56. const fnName = type === "props" ? DEFINE_PROPS : DEFINE_EMITS;
  57. if (node.arguments[0]) {
  58. runtimeDefineFn = fnName;
  59. return false;
  60. }
  61. if (type === "props")
  62. hasDefineProps = true;
  63. else
  64. hasDefineEmits = true;
  65. const typeDeclRaw = (_b = (_a = node.typeParameters) == null ? void 0 : _a.params) == null ? void 0 : _b[0];
  66. if (!typeDeclRaw)
  67. throw new SyntaxError(
  68. `${fnName}() expected a type parameter when used with ${DEFINE_MODEL}.`
  69. );
  70. const typeDecl = resolveQualifiedType(
  71. typeDeclRaw,
  72. (node2) => node2.type === "TSTypeLiteral"
  73. );
  74. if (!typeDecl) {
  75. throw new SyntaxError(
  76. `type argument passed to ${fnName}() must be a literal type, or a reference to an interface or literal type.`
  77. );
  78. }
  79. if (type === "props")
  80. propsTypeDecl = typeDecl;
  81. else
  82. emitsTypeDecl = typeDecl;
  83. if (declId) {
  84. if (type === "props" && declId.type === "ObjectPattern") {
  85. propsDestructureDecl = declId;
  86. } else if (type === "emits" && declId.type === "Identifier") {
  87. emitsIdentifier = declId.name;
  88. }
  89. } else if (type === "emits") {
  90. emitsIdentifier = `_${DEFINE_MODEL}_emit`;
  91. s.prependRight(setupOffset + node.start, `const ${emitsIdentifier} = `);
  92. }
  93. return true;
  94. }
  95. function processDefineModel(node, declId, kind) {
  96. var _a;
  97. if (isCallOf(node, DEFINE_MODEL))
  98. mode = "runtime";
  99. else if (isCallOf(node, DEFINE_MODEL_DOLLAR))
  100. mode = "reactivity-transform";
  101. else
  102. return false;
  103. if (hasDefineModel) {
  104. throw new SyntaxError(`duplicate ${DEFINE_MODEL}() call`);
  105. }
  106. hasDefineModel = true;
  107. modelDecl = node;
  108. const propsTypeDeclRaw = (_a = node.typeParameters) == null ? void 0 : _a.params[0];
  109. if (!propsTypeDeclRaw) {
  110. throw new SyntaxError(`expected a type parameter for ${DEFINE_MODEL}.`);
  111. }
  112. modelTypeDecl = resolveQualifiedType(
  113. propsTypeDeclRaw,
  114. (node2) => node2.type === "TSTypeLiteral"
  115. );
  116. if (!modelTypeDecl) {
  117. throw new SyntaxError(
  118. `type argument passed to ${DEFINE_MODEL}() must be a literal type, or a reference to an interface or literal type.`
  119. );
  120. }
  121. if (mode === "reactivity-transform" && declId) {
  122. const ids = extractIdentifiers(declId);
  123. ids.forEach((id2) => modelIdentifiers.add(id2));
  124. if (declId.type === "ObjectPattern") {
  125. modelDestructureDecl = declId;
  126. for (const property of declId.properties) {
  127. if (property.type === "RestElement") {
  128. throw new SyntaxError("rest element is not supported");
  129. }
  130. }
  131. } else {
  132. modelIdentifier = scriptSetup.loc.source.slice(
  133. declId.start,
  134. declId.end
  135. );
  136. }
  137. }
  138. if (kind)
  139. modelDeclKind = kind;
  140. return true;
  141. }
  142. function processDefineOptions(node) {
  143. if (!isCallOf(node, DEFINE_OPTIONS))
  144. return false;
  145. const [arg] = node.arguments;
  146. if (arg)
  147. processVue2Model(arg);
  148. return true;
  149. }
  150. function processVue2Script() {
  151. if (!script)
  152. return;
  153. const scriptAst = getScriptAst().body;
  154. if (scriptAst.length === 0)
  155. return;
  156. for (const node of scriptAst) {
  157. if (node.type === "ExportDefaultDeclaration") {
  158. const { declaration } = node;
  159. if (declaration.type === "ObjectExpression") {
  160. processVue2Model(declaration);
  161. } else if (declaration.type === "CallExpression" && declaration.callee.type === "Identifier" && ["defineComponent", "DO_defineComponent"].includes(
  162. declaration.callee.name
  163. )) {
  164. declaration.arguments.forEach((arg) => {
  165. if (arg.type === "ObjectExpression") {
  166. processVue2Model(arg);
  167. }
  168. });
  169. }
  170. }
  171. }
  172. }
  173. function processVue2Model(node) {
  174. if (node.type !== "ObjectExpression")
  175. return false;
  176. const model = node.properties.find(
  177. (prop) => prop.type === "ObjectProperty" && prop.key.type === "Identifier" && prop.key.name === "model" && prop.value.type === "ObjectExpression" && prop.value.properties.length === 2
  178. );
  179. if (!model)
  180. return false;
  181. model.value.properties.forEach((propertyItem) => {
  182. if (propertyItem.type === "ObjectProperty" && propertyItem.key.type === "Identifier" && propertyItem.value.type === "StringLiteral" && ["prop", "event"].includes(propertyItem.key.name)) {
  183. const key = propertyItem.key.name;
  184. modelVue2[key] = propertyItem.value.value;
  185. }
  186. });
  187. return true;
  188. }
  189. function resolveQualifiedType(node, qualifier) {
  190. if (qualifier(node)) {
  191. return node;
  192. }
  193. if (node.type === "TSTypeReference" && node.typeName.type === "Identifier") {
  194. const refName = node.typeName.name;
  195. const isQualifiedType = (node2) => {
  196. if (node2.type === "TSInterfaceDeclaration" && node2.id.name === refName) {
  197. return node2.body;
  198. } else if (node2.type === "TSTypeAliasDeclaration" && node2.id.name === refName && qualifier(node2.typeAnnotation)) {
  199. return node2.typeAnnotation;
  200. } else if (node2.type === "ExportNamedDeclaration" && node2.declaration) {
  201. return isQualifiedType(node2.declaration);
  202. }
  203. };
  204. for (const node2 of setupAst) {
  205. const qualified = isQualifiedType(node2);
  206. if (qualified) {
  207. return qualified;
  208. }
  209. }
  210. }
  211. }
  212. function extractPropsDefinitions(node) {
  213. var _a, _b, _c, _d;
  214. const members = node.type === "TSTypeLiteral" ? node.members : node.body;
  215. const map2 = {};
  216. for (const m of members) {
  217. if ((m.type === "TSPropertySignature" || m.type === "TSMethodSignature") && m.key.type === "Identifier") {
  218. const type = (_a = m.typeAnnotation) == null ? void 0 : _a.typeAnnotation;
  219. let typeAnnotation = "";
  220. let options;
  221. if (type) {
  222. typeAnnotation += `${m.optional ? "?" : ""}: `;
  223. if (type.type === "TSTypeReference" && type.typeName.type === "Identifier" && type.typeName.name === "ModelOptions" && ((_b = type.typeParameters) == null ? void 0 : _b.type) === "TSTypeParameterInstantiation" && type.typeParameters.params[0]) {
  224. typeAnnotation += setupContent.slice(
  225. type.typeParameters.params[0].start,
  226. type.typeParameters.params[0].end
  227. );
  228. if (((_c = type.typeParameters.params[1]) == null ? void 0 : _c.type) === "TSTypeLiteral") {
  229. options = {};
  230. for (const m2 of type.typeParameters.params[1].members) {
  231. if ((m2.type === "TSPropertySignature" || m2.type === "TSMethodSignature") && m2.key.type === "Identifier") {
  232. const type2 = (_d = m2.typeAnnotation) == null ? void 0 : _d.typeAnnotation;
  233. if (type2)
  234. options[setupContent.slice(m2.key.start, m2.key.end)] = setupContent.slice(type2.start, type2.end);
  235. }
  236. }
  237. }
  238. } else
  239. typeAnnotation += `${setupContent.slice(type.start, type.end)}`;
  240. }
  241. map2[m.key.name] = { typeAnnotation, options };
  242. }
  243. }
  244. return map2;
  245. }
  246. function getPropKey(key, omitDefault = false) {
  247. if (unified && version === 2 && key === "modelValue") {
  248. return "value";
  249. }
  250. return !omitDefault ? key : void 0;
  251. }
  252. function getEventKey(key, omitDefault = false) {
  253. if (version === 2) {
  254. if (modelVue2.prop === key) {
  255. return modelVue2.event;
  256. } else if (key === "value" || unified && key === "modelValue") {
  257. return "input";
  258. }
  259. }
  260. return !omitDefault ? `update:${key}` : void 0;
  261. }
  262. function rewriteMacros() {
  263. rewriteDefines();
  264. if (mode === "runtime") {
  265. rewriteRuntime();
  266. }
  267. function rewriteDefines() {
  268. const propsText = Object.entries(map).map(
  269. ([key, { typeAnnotation }]) => `${getPropKey(key)}${typeAnnotation}`
  270. ).join("\n");
  271. const emitsText = Object.entries(map).map(
  272. ([key, { typeAnnotation }]) => `(evt: '${getEventKey(key)}', value${typeAnnotation}): void`
  273. ).join("\n");
  274. if (hasDefineProps) {
  275. s.appendLeft(setupOffset + propsTypeDecl.start + 1, `${propsText}
  276. `);
  277. if (mode === "reactivity-transform" && propsDestructureDecl && modelDestructureDecl)
  278. for (const property of modelDestructureDecl.properties) {
  279. const text = code.slice(
  280. setupOffset + property.start,
  281. setupOffset + property.end
  282. );
  283. s.appendLeft(
  284. setupOffset + propsDestructureDecl.start + 1,
  285. `${text}, `
  286. );
  287. }
  288. } else {
  289. let text = "";
  290. const kind = modelDeclKind || "let";
  291. if (mode === "reactivity-transform") {
  292. if (modelIdentifier) {
  293. text = modelIdentifier;
  294. } else if (modelDestructureDecl) {
  295. text = code.slice(
  296. setupOffset + modelDestructureDecl.start,
  297. setupOffset + modelDestructureDecl.end
  298. );
  299. }
  300. }
  301. s.appendLeft(
  302. setupOffset,
  303. `
  304. ${text ? `${kind} ${text} = ` : ""}defineProps<{
  305. ${propsText}
  306. }>();`
  307. );
  308. }
  309. if (hasDefineEmits) {
  310. s.appendLeft(setupOffset + emitsTypeDecl.start + 1, `${emitsText}
  311. `);
  312. } else {
  313. emitsIdentifier = `${HELPER_PREFIX}emit`;
  314. s.appendLeft(
  315. setupOffset,
  316. `
  317. ${mode === "reactivity-transform" ? `const ${emitsIdentifier} = ` : ""}defineEmits<{
  318. ${emitsText}
  319. }>();`
  320. );
  321. }
  322. }
  323. function rewriteRuntime() {
  324. s.prependLeft(
  325. setupOffset,
  326. `
  327. import ${HELPER_PREFIX}useVModel from '${useVmodelHelperId}';`
  328. );
  329. const text = `${HELPER_PREFIX}useVModel(${Object.entries(map).map(([name, { options }]) => {
  330. const prop = getPropKey(name, true);
  331. const evt = getEventKey(name, true);
  332. if (!prop && !evt && !options)
  333. return stringifyValue(name);
  334. const args = [name, prop, evt].map((arg) => stringifyValue(arg));
  335. if (options) {
  336. const str = Object.entries(options).map(([k, v]) => ` ${stringifyValue(k)}: ${v}`).join(",\n");
  337. args.push(`{
  338. ${str}
  339. }`);
  340. }
  341. return `[${args.join(", ")}]`;
  342. }).join(", ")})`;
  343. s.overwriteNode(modelDecl, text, { offset: setupOffset });
  344. }
  345. }
  346. function processAssignModelVariable() {
  347. if (!emitsIdentifier)
  348. throw new Error(
  349. `Identifier of returning value of ${DEFINE_EMITS} is not found, please report this issue.
  350. ${REPO_ISSUE_URL}`
  351. );
  352. let hasTransformed = false;
  353. function overwrite(node, id2, value, original = false) {
  354. hasTransformed = true;
  355. const eventName = aliasMap[id2.name];
  356. const content = `${HELPER_PREFIX}emitHelper(${emitsIdentifier}, '${getEventKey(
  357. String(eventName)
  358. )}', ${value}${original ? `, ${id2.name}` : ""})`;
  359. s.overwriteNode(node, content, { offset: setupOffset });
  360. }
  361. walkAST(setupAst, {
  362. leave(node) {
  363. if (node.type === "AssignmentExpression") {
  364. if (node.left.type !== "Identifier")
  365. return;
  366. const id2 = this.scope[node.left.name];
  367. if (!modelIdentifiers.has(id2))
  368. return;
  369. const left = s.sliceNode(node.left, { offset: setupOffset });
  370. let right = s.sliceNode(node.right, { offset: setupOffset });
  371. if (node.operator !== "=") {
  372. right = `${left} ${node.operator.replace(/=$/, "")} ${right}`;
  373. }
  374. overwrite(node, id2, right);
  375. } else if (node.type === "UpdateExpression") {
  376. if (node.argument.type !== "Identifier")
  377. return;
  378. const id2 = this.scope[node.argument.name];
  379. if (!modelIdentifiers.has(id2))
  380. return;
  381. let value = node.argument.name;
  382. if (node.operator === "++")
  383. value += " + 1";
  384. else
  385. value += " - 1";
  386. overwrite(node, id2, value, !node.prefix);
  387. }
  388. }
  389. });
  390. if (hasTransformed) {
  391. s.prependLeft(
  392. setupOffset,
  393. `
  394. import ${HELPER_PREFIX}emitHelper from '${emitHelperId}';`
  395. );
  396. }
  397. }
  398. if (!code.includes(DEFINE_MODEL))
  399. return;
  400. const { script, scriptSetup, getSetupAst, getScriptAst } = parseSFC(code, id);
  401. if (!scriptSetup)
  402. return;
  403. const setupOffset = scriptSetup.loc.start.offset;
  404. const setupContent = scriptSetup.content;
  405. const setupAst = getSetupAst().body;
  406. const s = new MagicString(code);
  407. if (version === 2)
  408. processVue2Script();
  409. for (const node of setupAst) {
  410. if (node.type === "ExpressionStatement") {
  411. processDefinePropsOrEmits(node.expression);
  412. if (version === 2) {
  413. processDefineOptions(node.expression);
  414. }
  415. if (processDefineModel(node.expression) && mode === "reactivity-transform")
  416. s.remove(node.start + setupOffset, node.end + setupOffset);
  417. } else if (node.type === "VariableDeclaration" && !node.declare) {
  418. const total = node.declarations.length;
  419. let left = total;
  420. for (let i = 0; i < total; i++) {
  421. const decl = node.declarations[i];
  422. if (decl.init) {
  423. processDefinePropsOrEmits(decl.init, decl.id);
  424. if (processDefineModel(decl.init, decl.id, node.kind) && mode === "reactivity-transform") {
  425. if (left === 1) {
  426. s.remove(node.start + setupOffset, node.end + setupOffset);
  427. } else {
  428. let start = decl.start + setupOffset;
  429. let end = decl.end + setupOffset;
  430. if (i < total - 1) {
  431. end = node.declarations[i + 1].start + setupOffset;
  432. } else {
  433. start = node.declarations[i - 1].end + setupOffset;
  434. }
  435. s.remove(start, end);
  436. left--;
  437. }
  438. }
  439. }
  440. }
  441. }
  442. }
  443. if (!modelTypeDecl)
  444. return;
  445. if (runtimeDefineFn)
  446. throw new SyntaxError(
  447. `${runtimeDefineFn}() cannot accept non-type arguments when used with ${DEFINE_MODEL}()`
  448. );
  449. if (modelTypeDecl.type !== "TSTypeLiteral") {
  450. throw new SyntaxError(
  451. `type argument passed to ${DEFINE_MODEL}() must be a literal type, or a reference to an interface or literal type.`
  452. );
  453. }
  454. const map = extractPropsDefinitions(modelTypeDecl);
  455. const aliasMap = {};
  456. if (modelDestructureDecl)
  457. for (const p of modelDestructureDecl.properties) {
  458. if (p.type !== "ObjectProperty")
  459. continue;
  460. try {
  461. const key = resolveObjectKey(p.key, p.computed, false);
  462. if (p.value.type !== "Identifier")
  463. continue;
  464. aliasMap[p.value.name] = key;
  465. } catch {
  466. }
  467. }
  468. rewriteMacros();
  469. if (mode === "reactivity-transform" && hasDefineModel)
  470. processAssignModelVariable();
  471. return getTransformResult(s, id);
  472. }
  473. function stringifyValue(value) {
  474. return value !== void 0 ? JSON.stringify(value) : "undefined";
  475. }
  476. export {
  477. emit_helper_default,
  478. use_vmodel_default,
  479. helperPrefix,
  480. emitHelperId,
  481. useVmodelHelperId,
  482. transformDefineModel
  483. };