• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16import fs from 'fs';
17import path from 'path';
18import {
19  DECLARES,
20  IGNORE_REFERENCES,
21  importDeclarationFiles,
22  KeyValueTypes,
23  mockBufferMap,
24  MockedFileMap,
25  TSTypes,
26  specialOverloadedFunctionArr,
27  callbackError, ClassNotInEts,
28  undefinedTypes
29} from '../common/constants';
30import {
31  Declare,
32  KeyValue,
33  ReferenceFindResult,
34  Members,
35  MockBuffer,
36  OverloadedFunctionType,
37  CallbackParamMockData
38} from '../types';
39import { generateKeyValue } from '../common/commonUtils';
40
41/**
42 * 生成文件内容
43 * @param mockBuffer mock信息
44 * @param members 文件根节点的成员
45 * @returns
46 */
47export function generateContent(mockBuffer: MockBuffer, members: Members): string {
48  const membersContent: string[] = [];
49  Object.keys(members).forEach(memberKey => {
50    if (memberKey === 'default') {
51      return;
52    }
53    const keyValue = members[memberKey];
54    if (!keyValue.isNeedMock) {
55      return;
56    }
57    if (keyValue.type === KeyValueTypes.IMPORT) {
58      return;
59    }
60    if (keyValue.isGlobalDeclare) {
61      membersContent.push(`export const ${memberKey}=global.${memberKey};`);
62    } else {
63      const memberBody = handleKeyValue(memberKey, keyValue, mockBuffer, [], keyValue, keyValue.property);
64      membersContent.push(`export const ${memberKey} = ${memberBody};`);
65    }
66    if (keyValue.isDefault) {
67      const exportDefaultStr = `export default ${keyValue.key}`;
68      membersContent.push(exportDefaultStr);
69    }
70  });
71  return membersContent.join('\n');
72}
73
74/**
75 * 处理KV节点
76 * @param key KV节点key值
77 * @param keyValue KV节点
78 * @param mockBuffer KV节点所在文件的mock信息
79 * @param kvPath KV节点路径
80 * @param rootKeyValue 仅次于FILE节点的根节点
81 * @param property KV节点的调用属性节点,如A.b, b节点为property
82 * @returns
83 */
84function handleKeyValue(
85  key: string,
86  keyValue: KeyValue,
87  mockBuffer: MockBuffer,
88  kvPath: KeyValue[],
89  rootKeyValue: KeyValue,
90  property: KeyValue
91): string {
92  if (keyValue.value !== undefined) {
93    return keyValue.value;
94  }
95  if (new Set<KeyValueTypes>([
96    KeyValueTypes.CLASS,
97    KeyValueTypes.MODULE,
98    KeyValueTypes.INTERFACE
99  ]).has(keyValue.type) && kvPath.includes(keyValue)) {
100    if (keyValue.isGlobalDeclare) {
101      return `global.${keyValue.key}`;
102    }
103    if (keyValue.parent.isGlobalDeclare) {
104      return `global.${keyValue.parent.key}_temp.${keyValue.key}`;
105    }
106    return 'this';
107  } else {
108    kvPath = kvPath.concat([keyValue]);
109  }
110
111  return mockKeyValue(key, keyValue, mockBuffer, kvPath, rootKeyValue, property);
112}
113
114/**
115 * 根据KV节点生成文件内容
116 * @param key KV节点key值
117 * @param keyValue KV节点
118 * @param mockBuffer KV节点所在文件的mock信息
119 * @param kvPath KV节点路径
120 * @param rootKeyValue 仅次于FILE节点的根节点
121 * @param property KV节点的调用属性节点,如A.b, b节点为property
122 * @returns
123 */
124function mockKeyValue(
125  key: string,
126  keyValue: KeyValue,
127  mockBuffer: MockBuffer,
128  kvPath: KeyValue[],
129  rootKeyValue: KeyValue,
130  property: KeyValue
131): string {
132  let value: string;
133  switch (keyValue.type) {
134    case KeyValueTypes.CLASS: {
135      value = handleClassKeyValue(keyValue, mockBuffer, kvPath, rootKeyValue);
136      break;
137    }
138    case KeyValueTypes.EXPORT: {
139      value = handleExportKeyValue(keyValue, mockBuffer);
140      break;
141    }
142    case KeyValueTypes.FILE: {
143      value = handleFileKeyValue(key, keyValue, mockBuffer, kvPath, rootKeyValue, property);
144      break;
145    }
146    case KeyValueTypes.FUNCTION: {
147      value = handleFunctionKeyValue(key, keyValue, mockBuffer, kvPath, rootKeyValue);
148      break;
149    }
150    case KeyValueTypes.IMPORT: {
151      value = handleImportKeyValue(keyValue, kvPath, rootKeyValue, property);
152      break;
153    }
154    case KeyValueTypes.INTERSECTION: {
155      value = handleIntersectionKeyValue(key, keyValue, mockBuffer, kvPath, rootKeyValue);
156      break;
157    }
158    case KeyValueTypes.MODULE: {
159      value = handleModuleKeyValue(key, keyValue, mockBuffer, kvPath, rootKeyValue, property);
160      break;
161    }
162    case KeyValueTypes.INTERFACE: {
163      value = handleInterfaceKeyValue(keyValue, mockBuffer, kvPath, rootKeyValue);
164      break;
165    }
166    case KeyValueTypes.VALUE: {
167      value = handleValueKeyValue(keyValue);
168      break;
169    }
170    case KeyValueTypes.VARIABLE: {
171      value = handleVariableKeyValue(keyValue, mockBuffer, kvPath, rootKeyValue);
172      break;
173    }
174    case KeyValueTypes.PROPERTY: {
175      value = handlePropertyKeyValue(keyValue, mockBuffer, kvPath, rootKeyValue);
176      break;
177    }
178    case KeyValueTypes.REFERENCE: {
179      value = handleReferenceKeyValue(key, keyValue, mockBuffer, kvPath, rootKeyValue, property);
180      break;
181    }
182    case KeyValueTypes.ENUM: {
183      value = handleEnumKeyValue(keyValue, mockBuffer, kvPath, rootKeyValue);
184      break;
185    }
186    case KeyValueTypes.EXPRESSION: {
187      value = handleExpressionKeyValue(keyValue, mockBuffer, kvPath, rootKeyValue);
188      break;
189    }
190  }
191  keyValue.value = value;
192  return value;
193}
194
195/**
196 * 处理class KV节点
197 * @param keyValue KV节点
198 * @param mockBuffer KV节点所在文件的mock信息
199 * @param kvPath KV节点路径
200 * @param rootKeyValue 仅次于FILE节点的根节点
201 * @returns
202 */
203function handleClassKeyValue(
204  keyValue: KeyValue,
205  mockBuffer: MockBuffer,
206  kvPath: KeyValue[],
207  rootKeyValue: KeyValue
208): string {
209  const memberLines: string[] = [];
210  const dynamicProperties: string[] = ['this.isAutoMock=true'];
211
212  if (keyValue.heritage) {
213    handleHeritage(keyValue, mockBuffer, kvPath.concat([keyValue.heritage]), rootKeyValue);
214  }
215
216  Object.keys(keyValue.members).forEach(memberKey => {
217    const memberKeyValue = keyValue.members[memberKey];
218    let elementName = memberKey;
219
220    if (memberKeyValue.type === KeyValueTypes.EXPRESSION) {
221      memberKeyValue.key = handleKeyValue(memberKey, memberKeyValue, mockBuffer, kvPath, rootKeyValue, memberKeyValue.property);
222      memberKeyValue.type = KeyValueTypes.FUNCTION;
223      memberKeyValue.value = undefined;
224      elementName = memberKeyValue.key;
225    }
226    const value = handleKeyValue(memberKey, memberKeyValue, mockBuffer, kvPath, rootKeyValue, memberKeyValue.property)
227      .replace(/^function\*?/, '');
228
229    if (memberKeyValue.type === KeyValueTypes.FUNCTION) {
230      if (memberKeyValue.members.IterableIterator) {
231        memberLines.push(`*${elementName}${value}`);
232      } else {
233        memberLines.push(`${memberKeyValue.isStatic ? 'static ' : ''}${elementName}${value}`);
234      }
235    } else {
236      if (memberKeyValue.isStatic) {
237        memberLines.push(`static get ${elementName}(){return ${value}}`);
238      } else {
239        dynamicProperties.push(`this.${elementName} = ${value}`);
240      }
241    }
242  });
243
244  return `class {constructor() {\n${dynamicProperties.join(';\n')}\n}\n${memberLines.join(';\n')}\n}`;
245}
246
247/**
248 * 处理继承
249 * @param keyValue KV节点
250 * @param mockBuffer KV节点所在文件的mock信息
251 * @param kvPath KV节点路径
252 * @param rootKeyValue 仅次于FILE节点的根节点
253 * @returns
254 */
255function handleHeritage(
256  keyValue: KeyValue,
257  mockBuffer: MockBuffer,
258  kvPath: KeyValue[],
259  rootKeyValue: KeyValue
260): void {
261  const keyValueInfo = findKeyValueDefined(keyValue.heritage.key, keyValue.heritage, mockBuffer, kvPath, rootKeyValue, keyValue.heritage.property);
262  const defKeyValue = keyValueInfo.keyValue;
263  const defMockBuffer = keyValueInfo.mockBuffer;
264  handleKeyValue(defKeyValue.key, defKeyValue, defMockBuffer, kvPath, rootKeyValue, defKeyValue.property);
265
266  Object.keys(defKeyValue.members).forEach(memberKey => {
267    const memberKeyValue = Object.assign({}, defKeyValue.members[memberKey]);
268    memberKeyValue.isMocked = false;
269    if (memberKeyValue.type === KeyValueTypes.EXPRESSION) {
270      memberKeyValue.key = handleKeyValue(memberKey, memberKeyValue, mockBuffer, kvPath, rootKeyValue, memberKeyValue.property);
271      memberKeyValue.type = KeyValueTypes.PROPERTY;
272    }
273    if (keyValue.members[memberKeyValue.key]) {
274      return;
275    }
276    keyValue.members[memberKeyValue.key] = memberKeyValue;
277  });
278}
279
280/**
281 * 处理export KV节点
282 * @param keyValue KV节点
283 * @param mockBuffer KV节点所在文件的mock信息
284 * @returns
285 */
286function handleExportKeyValue(
287  keyValue: KeyValue,
288  mockBuffer: MockBuffer
289): string {
290  return `export * from './${path.relative(path.dirname(mockBuffer.mockedFilePath), keyValue.key)}';`;
291}
292
293/**
294 * 处理file KV节点
295 * @param key KV节点key值
296 * @param keyValue KV节点
297 * @param mockBuffer KV节点所在文件的mock信息
298 * @param kvPath KV节点路径
299 * @param rootKeyValue 仅次于FILE节点的根节点
300 * @param property KV节点的调用属性节点,如A.b, b节点为property
301 * @returns
302 */
303function handleFileKeyValue(
304  key: string,
305  keyValue: KeyValue,
306  mockBuffer: MockBuffer,
307  kvPath: KeyValue[],
308  rootKeyValue: KeyValue,
309  property: KeyValue
310): string {
311  if (property) {
312    const propertyKeyValue = keyValue.members[property.key];
313    if (propertyKeyValue) {
314      return handleKeyValue(property.key, propertyKeyValue, mockBuffer, kvPath, rootKeyValue, property);
315    } else {
316      console.warn(`Not found ${property.key} from ${key} in file ${mockBuffer.rawFilePath}`);
317    }
318  }
319  return '\'\'';
320}
321
322/**
323 * 处理function KV节点
324 * @param key
325 * @param keyValue KV节点
326 * @param mockBuffer KV节点所在文件的mock信息
327 * @param kvPath KV节点路径
328 * @param rootKeyValue 仅次于FILE节点的根节点
329 * @returns
330 */
331function handleFunctionKeyValue(
332  key: string,
333  keyValue: KeyValue,
334  mockBuffer: MockBuffer,
335  kvPath: KeyValue[],
336  rootKeyValue: KeyValue
337): string {
338  const memberKey = 'IterableIterator';
339  const memberKeyValue = keyValue.members[memberKey];
340  if (memberKeyValue) {
341    return handleKeyValue(memberKey, memberKeyValue, mockBuffer, kvPath, rootKeyValue, memberKeyValue.property);
342  }
343
344  const sameFuncList: KeyValue[] = [];
345  sameFuncList.push(keyValue);
346
347  keyValue.sameName.forEach(sameFunction => {
348    sameFuncList.push(sameFunction);
349  });
350  return handleSameFunctions(key, sameFuncList, mockBuffer, kvPath, rootKeyValue);
351}
352
353/**
354 * 处理import KV节点
355 * @param keyValue KV节点
356 * @param kvPath KV节点路径
357 * @param rootKeyValue 仅次于FILE节点的根节点
358 * @param property KV节点的调用属性节点,如A.b, b节点为property
359 * @returns
360 */
361function handleImportKeyValue(
362  keyValue: KeyValue,
363  kvPath: KeyValue[],
364  rootKeyValue: KeyValue,
365  property: KeyValue
366): string {
367  const importedMockBuffer = mockBufferMap.get(MockedFileMap.get(keyValue.importedModulePath));
368  const importedRootKeyValue = importedMockBuffer.contents;
369  if (keyValue.isImportDefault) {
370    const defaultKeyValue = importedRootKeyValue.members.default;
371    if (!defaultKeyValue) {
372      console.warn(`The file: ${importedMockBuffer.rawFilePath} does not contain the default export.`);
373      return `'The file: ${importedMockBuffer.rawFilePath} does not contain the default export.'`;
374    }
375    return handleKeyValue(defaultKeyValue.key, defaultKeyValue, importedMockBuffer, kvPath, rootKeyValue, property);
376  }
377
378  const targetKeyValue = importedRootKeyValue.members[keyValue.rawName ?? keyValue.key];
379  if (!targetKeyValue) {
380    console.warn(`The ${keyValue.rawName ?? keyValue.key} does not export from ${MockedFileMap.get(keyValue.importedModulePath)}.`);
381    return '"Unknown type"';
382  }
383  return handleKeyValue(targetKeyValue.key, targetKeyValue, importedMockBuffer, kvPath, rootKeyValue, property);
384}
385
386/**
387 * 处理intersection KV节点
388 * @param key KV节点key值
389 * @param keyValue KV节点
390 * @param mockBuffer KV节点所在文件的mock信息
391 * @param kvPath KV节点路径
392 * @param rootKeyValue 仅次于FILE节点的根节点
393 * @returns
394 */
395function handleIntersectionKeyValue(
396  key: string,
397  keyValue: KeyValue,
398  mockBuffer: MockBuffer,
399  kvPath: KeyValue[],
400  rootKeyValue: KeyValue
401): string {
402  const params: string[] = [];
403  Object.keys(keyValue.methodParams).forEach(param => {
404    const paramKeyValue = keyValue.methodParams[param];
405    const value = handleKeyValue(param, paramKeyValue, mockBuffer, kvPath, rootKeyValue, paramKeyValue.property);
406    // 因为rollup在编译时,会将this编译成undefined,导致有运行时报错,因此需要打个补丁
407    params.push(`(${value}) || {}`);
408  });
409  return `${key}(${params.join(', ')})`;
410}
411
412/**
413 * 处理module KV节点
414 * @param key KV节点key值
415 * @param keyValue KV节点
416 * @param mockBuffer KV节点所在文件的mock信息
417 * @param kvPath KV节点路径
418 * @param rootKeyValue 仅次于FILE节点的根节点
419 * @param property KV节点的调用属性节点,如A.b, b节点为property
420 * @returns
421 */
422function handleModuleKeyValue(
423  key: string,
424  keyValue: KeyValue,
425  mockBuffer: MockBuffer,
426  kvPath: KeyValue[],
427  rootKeyValue: KeyValue,
428  property?: KeyValue
429): string {
430  const memberLines: string[] = [];
431  if (property) {
432    const propertyKeyValue = keyValue.members[property.key];
433    if (propertyKeyValue) {
434      return handleKeyValue(property.key, propertyKeyValue, mockBuffer, kvPath, rootKeyValue, propertyKeyValue.property);
435    } else {
436      console.warn(`Not found ${property.key} from ${key} in file ${mockBuffer.rawFilePath}`);
437    }
438  }
439  Object.keys(keyValue.members).forEach(memberKey => {
440    const memberKeyValue = keyValue.members[memberKey];
441    if (!keyValue.isGlobalDeclare && !memberKeyValue.isNeedMock) {
442      return;
443    }
444    const value = `${memberKeyValue.key}: ${handleKeyValue(memberKey, memberKeyValue, mockBuffer, kvPath, rootKeyValue, memberKeyValue.property)}`;
445    memberLines.push(value);
446  });
447  return `{\n${memberLines.join(',\n')}\n}`;
448}
449
450/**
451 * 处理interface KV节点
452 * @param keyValue KV节点
453 * @param mockBuffer KV节点所在文件的mock信息
454 * @param kvPath KV节点路径
455 * @param rootKeyValue 仅次于FILE节点的根节点
456 * @returns
457 */
458function handleInterfaceKeyValue(
459  keyValue: KeyValue,
460  mockBuffer: MockBuffer,
461  kvPath: KeyValue[],
462  rootKeyValue: KeyValue
463): string {
464  const memberLines: string[] = ['isAutoMock: true'];
465
466  if (keyValue.heritage) {
467    handleHeritage(keyValue, mockBuffer, kvPath.concat([keyValue.heritage]), rootKeyValue);
468  }
469  Object.keys(keyValue.members).forEach(memberKey => {
470    const memberKeyValue = keyValue.members[memberKey];
471    const value = `${memberKeyValue.key}: ${handleKeyValue(memberKey, memberKeyValue, mockBuffer, kvPath, rootKeyValue, memberKeyValue.property)}`;
472    memberLines.push(value);
473  });
474  return `{\n${memberLines.join(',\n')}\n}`;
475}
476
477/**
478 * 处理value KV节点
479 * @param keyValue KV节点
480 * @returns
481 */
482function handleValueKeyValue(
483  keyValue: KeyValue
484): string {
485  return keyValue.key;
486}
487
488/**
489 * 处理variable KV节点
490 * @param keyValue KV节点
491 * @param mockBuffer KV节点所在文件的mock信息
492 * @param kvPath KV节点路径
493 * @param rootKeyValue 仅次于FILE节点的根节点
494 * @returns
495 */
496function handleVariableKeyValue(
497  keyValue: KeyValue,
498  mockBuffer: MockBuffer,
499  kvPath: KeyValue[],
500  rootKeyValue: KeyValue
501): string {
502  const memberLines: string[] = [];
503  Object.keys(keyValue.members).forEach(memberKey => {
504    const memberKeyValue = keyValue.members[memberKey];
505    const value = handleKeyValue(memberKey, memberKeyValue, mockBuffer, kvPath, rootKeyValue, memberKeyValue.property);
506    memberLines.push(value);
507  });
508  return memberLines.join(',\n');
509}
510
511/**
512 * 查找reference KV节点定义位置
513 * @param key KV节点key值
514 * @param targetKeyValue 需要查找的reference KV节点
515 * @param mockBuffer KV节点所在文件的mock信息
516 * @param kvPath KV节点路径
517 * @param rootKeyValue 仅次于FILE节点的根节点
518 * @param property KV节点的调用属性节点,如A.b, b节点为property
519 * @returns
520 */
521function findKeyValueDefined(
522  key: string,
523  targetKeyValue: KeyValue,
524  mockBuffer: MockBuffer,
525  kvPath: KeyValue[],
526  rootKeyValue: KeyValue,
527  property: KeyValue
528): ReferenceFindResult {
529  let keyValueInfo: ReferenceFindResult;
530
531  // 在js库中找
532  keyValueInfo = findInLibs(key, targetKeyValue, mockBuffer, kvPath, rootKeyValue);
533  if (keyValueInfo) {
534    return keyValueInfo;
535  }
536
537  // 在当前文件中找
538  keyValueInfo = findInCurrentFile(key, targetKeyValue, targetKeyValue.parent, mockBuffer, kvPath, rootKeyValue, property);
539  if (keyValueInfo) {
540    return keyValueInfo;
541  }
542
543  // 在全局定义中找
544  keyValueInfo = findInDeclares(key);
545  if (keyValueInfo) {
546    return keyValueInfo;
547  }
548
549  // 在TS内置类型中找
550  keyValueInfo = findTSTypes(key, targetKeyValue, mockBuffer, kvPath, rootKeyValue);
551  if (keyValueInfo) {
552    return keyValueInfo;
553  }
554
555  // 在所有文件中找
556  keyValueInfo = findInAllFiles(key, property);
557  if (keyValueInfo) {
558    return keyValueInfo;
559  }
560
561  // 全局都未找到定义的类型,做特殊处理
562  if (Object.keys(undefinedTypes).includes(key)) {
563    const keyValue: KeyValue = generateKeyValue(key, KeyValueTypes.VALUE);
564    keyValue.value = undefinedTypes[key];
565    return { keyValue, mockBuffer };
566  }
567
568  const keyValuePath: string[] = getKeyValuePath(targetKeyValue);
569  const fromFilePath = MockedFileMap.get(keyValuePath[0]).replace(/\\/, '/');
570  const value: string = `'Cannot find type definition for ${keyValuePath.slice(1).join('->')} from file ${fromFilePath}'`;
571  console.warn(value);
572  const keyValue: KeyValue = generateKeyValue(key, KeyValueTypes.VALUE);
573  keyValue.value = value;
574  return { keyValue, mockBuffer };
575}
576
577/**
578 * 在 typescript 内置类型库中查找类型定义
579 * @param key KV节点key值
580 * @param targetKeyValue 需要查找的reference KV节点
581 * @param mockBuffer KV节点所在文件的mock信息
582 * @param kvPath KV节点路径
583 * @param rootKeyValue 仅次于FILE节点的根节点
584 * @returns
585 */
586function findTSTypes(
587  key: string,
588  targetKeyValue: KeyValue,
589  mockBuffer: MockBuffer,
590  kvPath: KeyValue[],
591  rootKeyValue: KeyValue
592): ReferenceFindResult {
593  const paramsContent: string[] = [];
594  Object.keys(targetKeyValue.typeParameters).forEach(typeParameter => {
595    const typeParameterKeyValue: KeyValue = targetKeyValue.typeParameters[typeParameter];
596    const paramContent: string = handleKeyValue(typeParameter, typeParameterKeyValue, mockBuffer, kvPath, rootKeyValue, typeParameterKeyValue.property);
597    paramsContent.push(paramContent);
598  });
599  if (!TSTypes[key]) {
600    return undefined;
601  }
602  const keyValue: KeyValue = generateKeyValue(key, KeyValueTypes.VALUE);
603  keyValue.value = TSTypes[key](paramsContent.join(', '));
604  return { keyValue, mockBuffer };
605}
606
607/**
608 * 处理函数参数
609 * @param params 参数成员
610 * @param mockBuffer 当前文件mock信息
611 * @param kvPath KV节点路径
612 * @param rootKeyValue 仅次于FILE节点的根节点
613 * @returns
614 */
615function handleParams(
616  params: Members,
617  mockBuffer: MockBuffer,
618  kvPath: KeyValue[],
619  rootKeyValue: KeyValue
620): string {
621  const contents: string[] = [];
622  Object.keys(params).forEach(key => {
623    const paramKeyValue = params[key];
624    contents.push(handleKeyValue(paramKeyValue.key, paramKeyValue, mockBuffer, kvPath, rootKeyValue, paramKeyValue.property));
625  });
626  return contents.join(', ');
627}
628
629/**
630 * 在 typescript 内置类型库中查找类型定义
631 * @param key KV节点key值
632 * @param targetKeyValue 需要查找的reference KV节点
633 * @param mockBuffer KV节点所在文件的mock信息
634 * @param kvPath KV节点路径
635 * @param rootKeyValue 仅次于FILE节点的根节点
636 * @returns
637 */
638function findInLibs(
639  key: string,
640  targetKeyValue: KeyValue,
641  mockBuffer: MockBuffer,
642  kvPath: KeyValue[],
643  rootKeyValue: KeyValue
644): ReferenceFindResult {
645  if (key === 'globalThis') {
646    const globalThisKeyValue = generateKeyValue(key, KeyValueTypes.VALUE);
647    return { keyValue: globalThisKeyValue, mockBuffer };
648  }
649  if (ClassNotInEts.has(key) || !global[key]) {
650    return undefined;
651  }
652  if (key === 'Symbol') {
653    return {
654      keyValue: generateKeyValue('[Symbol.iterator]', KeyValueTypes.VALUE),
655      mockBuffer
656    };
657  }
658  switch (typeof global[key]) {
659    case 'bigint': {
660      break;
661    }
662    case 'boolean': {
663      break;
664    }
665    case 'function': {
666      return findInLibFunction(key, targetKeyValue, mockBuffer, kvPath, rootKeyValue);
667    }
668    case 'number': {
669      break;
670    }
671    case 'object': {
672      break;
673    }
674    case 'string': {
675      break;
676    }
677    case 'symbol': {
678      break;
679    }
680    case 'undefined': {
681      break;
682    }
683  }
684  return undefined;
685}
686
687/**
688 * 在库函数中查找类型定义
689 * @param key KV节点key值
690 * @param targetKeyValue 需要查找的reference KV节点
691 * @param mockBuffer KV节点所在文件的mock信息
692 * @param kvPath KV节点路径
693 * @param rootKeyValue 仅次于FILE节点的根节点
694 * @returns
695 */
696function findInLibFunction(
697  key: string,
698  targetKeyValue: KeyValue,
699  mockBuffer: MockBuffer,
700  kvPath: KeyValue[],
701  rootKeyValue: KeyValue
702): ReferenceFindResult {
703  const params = handleParams(targetKeyValue.methodParams, mockBuffer, kvPath, rootKeyValue);
704  let value: string;
705  // 判断是否是函数
706  if (typeof global[key].constructor === 'function') {
707    value = `new ${key}(${params})`;
708  } else {
709    value = `${key}(${params})`;
710  }
711  return {
712    keyValue: generateKeyValue(value, KeyValueTypes.VALUE),
713    mockBuffer
714  };
715}
716
717/**
718 * 在当前文件中查找类型定义
719 * @param key KV节点key值
720 * @param targetKeyValue 需要查找的reference KV节点
721 * @param parent 父节点
722 * @param mockBuffer KV节点所在文件的mock信息
723 * @param kvPath KV节点路径
724 * @param rootKeyValue 仅次于FILE节点的根节点
725 * @param property KV节点的调用属性节点,如A.b, b节点为property
726 * @returns
727 */
728function findInCurrentFile(
729  key: string,
730  targetKeyValue: KeyValue,
731  parent: KeyValue,
732  mockBuffer: MockBuffer,
733  kvPath: KeyValue[],
734  rootKeyValue: KeyValue,
735  property: KeyValue
736): ReferenceFindResult {
737  if (!parent) {
738    return undefined as ReferenceFindResult;
739  }
740  if (parent.typeParameters[key] && parent.typeParameters[key] !== targetKeyValue) {
741    return { keyValue: parent.typeParameters[key], mockBuffer } as ReferenceFindResult;
742  }
743  const foundKeyValue = parent.members[key];
744  if (
745    foundKeyValue &&
746    foundKeyValue !== targetKeyValue &&
747    (
748      parent.type === KeyValueTypes.ENUM || foundKeyValue.type !== KeyValueTypes.PROPERTY
749    )
750  ) {
751    if (foundKeyValue.type === KeyValueTypes.IMPORT) {
752      return findDefFromImport(foundKeyValue, mockBuffer, rootKeyValue, property) as ReferenceFindResult;
753    }
754    const defKeyValue = findProperty(foundKeyValue, property);
755    if (defKeyValue) {
756      return {keyValue: defKeyValue, mockBuffer} as ReferenceFindResult;
757    }
758  }
759  return findInCurrentFile(key, targetKeyValue, parent.parent, mockBuffer, kvPath, rootKeyValue, property) as ReferenceFindResult;
760}
761
762/**
763 * 在全局声明中查找类型定义
764 * @param key KV节点key值
765 * @returns
766 */
767function findInDeclares(
768  key: string
769): ReferenceFindResult {
770  if (DECLARES[key]) {
771    const mockBuffer = mockBufferMap.get(MockedFileMap.get(DECLARES[key].from));
772    return {
773      keyValue: DECLARES[key].keyValue,
774      mockBuffer,
775      isGlobalDeclaration: path.basename(mockBuffer.rawFilePath).startsWith('@')
776    } as ReferenceFindResult;
777  } else {
778    return undefined as ReferenceFindResult;
779  }
780}
781
782/**
783 * 在所有文件中查找类型定义
784 * @param key KV节点key值
785 * @param property KV节点的调用属性节点,如A.b, b节点为property
786 * @returns
787 */
788function findInAllFiles(
789  key: string,
790  property?: KeyValue
791): ReferenceFindResult {
792  for (const definedMockBuffer of mockBufferMap.values()) {
793    const members = definedMockBuffer.contents.members;
794    if (members[key]) {
795      const defKeyValue = findProperty(members[key], property);
796      return { keyValue: defKeyValue, mockBuffer: definedMockBuffer } as ReferenceFindResult;
797    }
798  }
799  return undefined as ReferenceFindResult;
800}
801
802/**
803 * 获取节点在当前文件的路径
804 * 以递归的方式逐级向上获取所有祖先节点的key
805 * @param keyValue KV节点
806 * @param paths 节点路径
807 * @returns
808 */
809function getKeyValuePath(keyValue: KeyValue, paths = []): string[] {
810  if (!keyValue) {
811    return paths;
812  }
813  paths.unshift(keyValue.key);
814  return getKeyValuePath(keyValue.parent, paths);
815}
816
817/**
818 * 处理同名函数
819 * @param key
820 * @param sameFuncList 同名函数列表
821 * @param mockBuffer 当前文件的mock信息
822 * @param kvPath KV节点路径
823 * @param rootKeyValue 仅次于FILE节点的根节点
824 * @returns
825 */
826function handleSameFunctions(
827  key: string,
828  sameFuncList: KeyValue[],
829  mockBuffer: MockBuffer,
830  kvPath: KeyValue[],
831  rootKeyValue: KeyValue
832): string {
833  const functionName = sameFuncList[0].key;
834  if (sameFuncList.length >= 2) {
835    return handleOverloadedFunction(key, sameFuncList, mockBuffer, kvPath, rootKeyValue, functionName);
836  } else {
837    return handleSingleFunction(key, sameFuncList, mockBuffer, kvPath, rootKeyValue, functionName);
838  }
839}
840
841/**
842 * 处理重载函数
843 * @param key
844 * @param sameFuncList 同名函数列表
845 * @param mockBuffer 当前文件的mock信息
846 * @param kvPath KV节点路径
847 * @param rootKeyValue 仅次于FILE节点的根节点
848 * @param functionName
849 * @returns
850 */
851function handleOverloadedFunction(
852  key: string,
853  sameFuncList: KeyValue[],
854  mockBuffer: MockBuffer,
855  kvPath: KeyValue[],
856  rootKeyValue: KeyValue,
857  functionName: string
858): string {
859  const func = sameFuncList.find(func => func.members.Promise);
860  if (!func) {
861    return handleSingleFunction(key, sameFuncList, mockBuffer, kvPath, rootKeyValue, functionName);
862  }
863  const promiseTypes = func.members.Promise;
864  const memberLines: string[] = [];
865  const returnData: string[] = [];
866  const paramIndex: number = 1;
867  Object.keys(promiseTypes.typeParameters).forEach(memberKey => {
868    const memberKeyValue = promiseTypes.typeParameters[memberKey];
869    const value = handleKeyValue(memberKey, memberKeyValue, mockBuffer, kvPath, rootKeyValue, memberKeyValue.property);
870    memberLines.push(`const p${paramIndex} = ${value}`);
871    returnData.push(`p${paramIndex}`);
872  });
873  const isSpecial = specialOverloadedFunctionArr.includes(functionName);
874  const paramMockData = handleFunParamMockData(sameFuncList, mockBuffer, kvPath, rootKeyValue, isSpecial, 'multiple', returnData);
875  const isGetAccessor = key.startsWith('get ' + functionName);
876  const isSetAccessor = key.startsWith('set ' + functionName);
877  return `function (${isGetAccessor ? '' : `${isSetAccessor ? 'args' : '...args'}`}) {
878    ${isGetAccessor || isSetAccessor ? '' : `console.warn(ts.replace('{{}}', '${func.key}'));`}
879    ${memberLines.join(';\n')}${paramMockData ? '\n' + paramMockData : ''}
880    return new Promise(function (resolve, reject) {
881      resolve(${returnData.join(', ')});
882    });
883  }`;
884}
885
886function handleFunParamMockData(
887  funcList: KeyValue[],
888  mockBuffer: MockBuffer,
889  kvPath: KeyValue[],
890  rootKeyValue: KeyValue,
891  isSpecial: boolean,
892  funType: OverloadedFunctionType,
893  returnData?: string[]
894): string {
895  let paramMockData = '';
896  for (let i = 0; i < funcList.length; i++) {
897    const funInfo = funcList[i];
898    const { paramName, callBackParams, isAsyncCallback } = getCallbackMockData(funInfo, mockBuffer, kvPath, rootKeyValue, isSpecial);
899    if (!callBackParams.length) {
900      continue;
901    }
902    const returnInfo = isSpecial
903      ? callBackParams.join(', ')
904      : funType === 'single'
905        ? callBackParams.join(', ')
906        : returnData?.join(', ');
907    const data = `if (args && typeof args[args.length - 1] === 'function') {
908      args[args.length - 1].call(this, ${isAsyncCallback ? callbackError : ''}${returnInfo});
909    }`;
910    const info = (paramName ? `if(args && ['${paramName}'].includes(args[0])){\n` : '') + data + (paramName ? '}\n' : '');
911    if (funType === 'single' || isSpecial || !isSpecial && !paramMockData) {
912      paramMockData += info;
913    }
914  }
915  return paramMockData;
916}
917
918function getCallbackMockData(
919  funInfo: KeyValue,
920  mockBuffer: MockBuffer,
921  kvPath: KeyValue[],
922  rootKeyValue: KeyValue,
923  isSpecial: boolean
924): CallbackParamMockData {
925  let paramName = '';
926  let isAsyncCallback = true;
927  let callBackParams: string[] = [];
928  Object.keys(funInfo.methodParams).forEach(key => {
929    const paramInfo = funInfo.methodParams[key];
930    const callbackData = handleCallbackParamMockData(key, paramInfo, callBackParams, paramName, isAsyncCallback, mockBuffer, kvPath, rootKeyValue, isSpecial);
931    paramName = callbackData.paramName;
932    isAsyncCallback = callbackData.isAsyncCallback;
933    callBackParams = callbackData.callBackParams;
934  });
935  return {
936    paramName,
937    isAsyncCallback,
938    callBackParams
939  };
940}
941
942function handleCallbackParamMockData(
943  key: string,
944  paramInfo: KeyValue,
945  callBackParams: string[],
946  paramName: string,
947  isAsyncCallback: boolean,
948  mockBuffer: MockBuffer,
949  kvPath: KeyValue[],
950  rootKeyValue: KeyValue,
951  isSpecial: boolean
952): CallbackParamMockData {
953  if (key === 'callback') {
954    let callbackInfo: KeyValue;
955    if (paramInfo.members.Callback) {
956      isAsyncCallback = false;
957      callbackInfo = paramInfo.members.Callback;
958    }
959    if (paramInfo.members.AsyncCallback) {
960      isAsyncCallback = true;
961      callbackInfo = paramInfo.members.AsyncCallback;
962    }
963    callbackInfo && Object.keys(callbackInfo.typeParameters).forEach(memberKey => {
964      const memberKeyValue = callbackInfo.typeParameters[memberKey];
965      const value = handleKeyValue(memberKey, memberKeyValue, mockBuffer, kvPath, rootKeyValue, memberKeyValue.property);
966      callBackParams.push(value);
967    });
968  }
969  if (key === 'type' && isSpecial) {
970    Object.keys(paramInfo.members).forEach(memberKey => {
971      if (!paramName) {
972        paramName = memberKey;
973      }
974    });
975  }
976
977  return {
978    isAsyncCallback,
979    callBackParams,
980    paramName
981  };
982}
983
984/**
985 * 拼接property
986 * 通过递归方式,逐层将调用的属性拼接起来
987 * 如:将{A:{key:A, property: {key:b, property: {key: c}}}}
988 * 拼接成:A.b.c
989 * @param property 调用的属性
990 * @returns
991 */
992function concatProperty(property?: KeyValue): string {
993  if (!property) {
994    return '';
995  }
996  return `.${property.key}${concatProperty(property.property)}`;
997}
998
999/**
1000 * 获取获取定义KV节点的最后一个property
1001 *
1002 * @param keyValue 定义的KV节点
1003 * @param property 调用KV节点的属性
1004 * @returns
1005 */
1006function findProperty(keyValue: KeyValue, property?: KeyValue): KeyValue {
1007  const keyValueKey = keyValue.key;
1008  while (property && keyValue) {
1009    keyValue = keyValue.members[property.key];
1010    property = property.property;
1011  }
1012  if (!keyValue && property) {
1013    throw new Error(`未能在${keyValueKey}下找到${property.key}子孙属性`);
1014  }
1015  return keyValue;
1016}
1017
1018/**
1019 * 处理property KV节点
1020 * @param keyValue KV节点
1021 * @param mockBuffer KV节点所在文件的mock信息
1022 * @param kvPath KV节点路径
1023 * @param rootKeyValue 仅次于FILE节点的根节点
1024 * @returns
1025 */
1026function handlePropertyKeyValue(
1027  keyValue: KeyValue,
1028  mockBuffer: MockBuffer,
1029  kvPath: KeyValue[],
1030  rootKeyValue: KeyValue
1031): string {
1032  const memberLines: string[] = [];
1033  Object.keys(keyValue.members).forEach(memberKey => {
1034    const memberKeyValue = keyValue.members[memberKey];
1035    const value = handleKeyValue(memberKey, memberKeyValue, mockBuffer, kvPath, rootKeyValue, memberKeyValue.property);
1036    memberLines.push(value);
1037  });
1038  return memberLines.join(',');
1039}
1040
1041/**
1042 * 处理reference KV节点
1043 * @param key KV节点key值
1044 * @param keyValue KV节点
1045 * @param mockBuffer KV节点所在文件的mock信息
1046 * @param kvPath KV节点路径
1047 * @param rootKeyValue 仅次于FILE节点的根节点
1048 * @param property KV节点的调用属性节点,如A.b, b节点为property
1049 * @returns
1050 */
1051function handleReferenceKeyValue(
1052  key: string,
1053  keyValue: KeyValue,
1054  mockBuffer: MockBuffer,
1055  kvPath: KeyValue[],
1056  rootKeyValue: KeyValue,
1057  property: KeyValue
1058): string {
1059  if (IGNORE_REFERENCES.has(key)) {
1060    const memberLines: string[] = [];
1061    Object.keys(keyValue.typeParameters).forEach(memberKey => {
1062      const memberKeyValue = keyValue.typeParameters[memberKey];
1063      const value = handleKeyValue(memberKey, memberKeyValue, mockBuffer, kvPath, rootKeyValue, memberKeyValue.property);
1064      memberLines.push(value);
1065    });
1066    return memberLines.join(',\n');
1067  }
1068  const keyValueInfo = findKeyValueDefined(key, keyValue, mockBuffer, kvPath, rootKeyValue, keyValue.property);
1069  let value: string;
1070
1071  if (keyValueInfo.isGlobalDeclaration) {
1072    const properties = concatProperty(keyValue.property);
1073    value = `global.${keyValueInfo.keyValue.key}${properties}`;
1074    const dependKeyValue = property ? keyValueInfo.keyValue.members[property.key] : keyValueInfo.keyValue;
1075    !dependKeyValue.isMocked && rootKeyValue.dependOnGlobals.add(dependKeyValue);
1076  } else {
1077    value = handleKeyValue(keyValueInfo.keyValue.key, keyValueInfo.keyValue, keyValueInfo.mockBuffer, kvPath, rootKeyValue, property);
1078  }
1079
1080  if (value !== 'this') {
1081    switch (keyValueInfo.keyValue.type) {
1082      case KeyValueTypes.CLASS: {
1083        value = value.startsWith('global.') ? value : `new (${value})()`;
1084        break;
1085      }
1086      case KeyValueTypes.ENUM: {
1087        if (keyValue.parent.type !== KeyValueTypes.VARIABLE) {
1088          const firstMemberKey = Object.keys(keyValueInfo.keyValue.members)[0];
1089          const firstMemberKeyValue = keyValueInfo.keyValue.members[firstMemberKey];
1090          value = handleKeyValue(firstMemberKey, firstMemberKeyValue, keyValueInfo.mockBuffer, kvPath, rootKeyValue, firstMemberKeyValue.property);
1091        }
1092        break;
1093      }
1094    }
1095  }
1096
1097  return value;
1098}
1099
1100/**
1101 * 处理enum KV节点
1102 * @param keyValue KV节点
1103 * @param mockBuffer KV节点所在文件的mock信息
1104 * @param kvPath KV节点路径
1105 * @param rootKeyValue 仅次于FILE节点的根节点
1106 * @returns
1107 */
1108function handleEnumKeyValue(
1109  keyValue: KeyValue,
1110  mockBuffer: MockBuffer,
1111  kvPath: KeyValue[],
1112  rootKeyValue: KeyValue
1113): string {
1114  const memberLines: string[] = ['isAutoMock: 0'];
1115  Object.keys(keyValue.members).forEach(memberKey => {
1116    const memberKeyValue = keyValue.members[memberKey];
1117    const value = handleKeyValue(memberKey, memberKeyValue, mockBuffer, kvPath, rootKeyValue, memberKeyValue.property);
1118    memberLines.push(`${memberKey}: ${value}`);
1119  });
1120  return `{${memberLines.join(',\n')}}`;
1121}
1122
1123/**
1124 * 处理expression KV节点
1125 * @param keyValue KV节点
1126 * @param mockBuffer KV节点所在文件的mock信息
1127 * @param kvPath KV节点路径
1128 * @param rootKeyValue 仅次于FILE节点的根节点
1129 * @returns
1130 */
1131function handleExpressionKeyValue(
1132  keyValue: KeyValue,
1133  mockBuffer: MockBuffer,
1134  kvPath: KeyValue[],
1135  rootKeyValue: KeyValue
1136): string {
1137  const elements = keyValue.operateElements;
1138  return elements.map(element => {
1139    return handleKeyValue(element.key, element, mockBuffer, kvPath, rootKeyValue, element.property);
1140  }).join(' ');
1141}
1142
1143/**
1144 * 处理非重载函数
1145 * @param key
1146 * @param sameFuncList
1147 * @param mockBuffer KV节点所在文件的mock信息
1148 * @param kvPath KV节点路径
1149 * @param rootKeyValue 仅次于FILE节点的根节点
1150 * @param functionName
1151 * @returns
1152 */
1153function handleSingleFunction(
1154  key: string,
1155  sameFuncList: KeyValue[],
1156  mockBuffer: MockBuffer,
1157  kvPath: KeyValue[],
1158  rootKeyValue: KeyValue,
1159  functionName: string
1160): string {
1161  const funcKeyValue = sameFuncList[0];
1162  const memberLines: string[] = [];
1163  Object.keys(funcKeyValue.members).forEach(memberKey => {
1164    const memberKeyValue = funcKeyValue.members[memberKey];
1165    const value = handleKeyValue(memberKey, memberKeyValue, mockBuffer, kvPath, rootKeyValue, memberKeyValue.property);
1166    memberLines.push(value);
1167  });
1168  const isSpecial = specialOverloadedFunctionArr.includes(functionName);
1169  const funcList = isSpecial ? sameFuncList : [sameFuncList[0]];
1170  const paramMockData = handleFunParamMockData(funcList, mockBuffer, kvPath, rootKeyValue, isSpecial, 'single');
1171
1172  const isGetAccessor = key.startsWith('get ' + functionName);
1173  const isSetAccessor = key.startsWith('set ' + functionName);
1174  const returnStr = funcKeyValue.members.Promise && funcKeyValue.members.Promise.type === KeyValueTypes.REFERENCE ?
1175    `return new Promise(function (resolve, reject) {
1176          resolve(${memberLines.join(',')});
1177        })` :
1178    `return ${memberLines.join(',')}`;
1179
1180  return `function (${isGetAccessor ? '' : `${isSetAccessor ? 'args' : '...args'}`}) {
1181  ${isGetAccessor || isSetAccessor ? '' : `console.warn(ts.replace('{{}}', '${funcKeyValue.key}'));`}
1182  ${paramMockData ?? ''}${returnStr}
1183  }`;
1184}
1185
1186/**
1187 * 获取KV节点的最后一个property的类型
1188 * @param keyValue KV节点
1189 * @param property 调用的属性
1190 * @returns
1191 */
1192function getKeyValueType(keyValue: KeyValue, property?: KeyValue): KeyValueTypes {
1193  while (property) {
1194    keyValue = keyValue.members[property.key];
1195    property = property.property;
1196  }
1197  return keyValue.type;
1198}
1199
1200/**
1201 * 处理所有全局声明的KV节点
1202 * @param outMockJsFileDir mock文件输出路径
1203 */
1204export function handleDeclares(outMockJsFileDir: string): void {
1205  const declarations: string[] = [];
1206  const mockedDeclarations: Set<string> = new Set();
1207  Object.keys(DECLARES).forEach(key => {
1208    const keyValue = DECLARES[key].keyValue;
1209    switch (keyValue.type) {
1210      case KeyValueTypes.CLASS: {
1211        declarations.push(`global.${key}_temp = class {constructor(){this.isAutoMock=true}};\nglobal.${key} = global.${key} || global.${key}_temp;`);
1212        break;
1213      }
1214      case KeyValueTypes.INTERFACE:
1215      case KeyValueTypes.MODULE: {
1216        declarations.push(`global.${key}_temp = {isAutoMock: true};\nglobal.${key} = global.${key} || global.${key}_temp;`);
1217      }
1218    }
1219  });
1220
1221  Object.keys(DECLARES).forEach(key => {
1222    handleDeclare(DECLARES[key], declarations, mockedDeclarations);
1223  });
1224
1225  const INTERVAL = 100;
1226  for (let counter = 0; counter < declarations.length; counter += INTERVAL) {
1227    const index = Math.floor(counter / INTERVAL) + 1;
1228    const filePath = path.join(outMockJsFileDir, `globalDeclarations${index}.js`);
1229    importDeclarationFiles.push(`import * as globalDeclarations${index} from './globalDeclarations${index}';`);
1230    const content = declarations.slice(counter, counter + INTERVAL).join('\n');
1231    fs.writeFileSync(filePath, content);
1232  }
1233}
1234
1235/**
1236 * 处理全局声明的KV节点
1237 * @param declaration 全局声明的KV节点
1238 * @param declarations 所有全局声明的KV节点
1239 * @param mockedDeclarations 已mock的全局声明的KV节点的集合,避免重复mock
1240 * @param member 不为undefined时,只mock这个member节点
1241 * @returns
1242 */
1243function handleDeclare(
1244  declaration: Declare,
1245  declarations: string[],
1246  mockedDeclarations: Set<string>,
1247  member?: KeyValue
1248): void {
1249  if (member?.isMocked) {
1250    return;
1251  }
1252  const keyValue = declaration.keyValue;
1253  const key = keyValue.key;
1254  const mockBuffer = mockBufferMap.get(MockedFileMap.get(declaration.from));
1255
1256  const values: string[] = [];
1257  switch (keyValue.type) {
1258    case KeyValueTypes.FUNCTION: {
1259      if (!mockedDeclarations.has(key)) {
1260        const functionBody = handleKeyValue(key, keyValue, mockBuffer, [], keyValue, keyValue.property);
1261        const value = `global.${key} = global.${key} || (${functionBody});`;
1262        values.push(value);
1263        mockedDeclarations.add(key);
1264      }
1265      break;
1266    }
1267    case KeyValueTypes.CLASS: {
1268      handleGlobalClass(keyValue, mockBuffer, values, [keyValue], member);
1269      break;
1270    }
1271    case KeyValueTypes.MODULE: {
1272      handleGlobalModule(keyValue, mockBuffer, values, [keyValue], member);
1273      break;
1274    }
1275    case KeyValueTypes.INTERFACE: {
1276      handleGlobalInterface(keyValue, mockBuffer, values, [keyValue], member);
1277      break;
1278    }
1279    default: {
1280      if (!mockedDeclarations.has(key)) {
1281        const value = `global.${key} = global.${key} || (${handleKeyValue(key, keyValue, mockBuffer, [], keyValue, keyValue.property)});`;
1282        values.push(value);
1283        mockedDeclarations.add(key);
1284      }
1285      break;
1286    }
1287  }
1288  handleDependOnGlobals(keyValue, declarations, mockedDeclarations);
1289  Array.prototype.push.apply(declarations, values);
1290}
1291
1292/**
1293 * 处理KV节点用到的全局节点
1294 * @param keyValue KV节点
1295 * @param declarations 已mock的文本内容
1296 * @param mockedDeclarations 已mock的全局节点的集合
1297 * @returns
1298 */
1299function handleDependOnGlobals(
1300  keyValue: KeyValue,
1301  declarations: string[],
1302  mockedDeclarations: Set<string>
1303): void {
1304  if (keyValue.type === KeyValueTypes.FUNCTION) {
1305    return;
1306  }
1307  keyValue.dependOnGlobals.forEach(dependKeyValue => {
1308    if (dependKeyValue.isGlobalDeclare) {
1309      handleDeclare(DECLARES[dependKeyValue.key], declarations, mockedDeclarations);
1310    } else if (dependKeyValue.parent.isGlobalDeclare) {
1311      handleDeclare(DECLARES[dependKeyValue.parent.key], declarations, mockedDeclarations, dependKeyValue);
1312    } else {
1313      throw new Error(`${keyValue.key}非全局节点。`);
1314    }
1315  });
1316}
1317
1318/**
1319 * 处理全局class KV节点
1320 * @param keyValue class类型的KV节点
1321 * @param mockBuffer mock信息
1322 * @param declarations 已mock的文本内容
1323 * @param kvPath KV节点路径
1324 * @param member 不为undefined时,只mock这个member节点
1325 * @returns
1326 */
1327function handleGlobalClass(
1328  keyValue: KeyValue,
1329  mockBuffer: MockBuffer,
1330  declarations: string[],
1331  kvPath: KeyValue[],
1332  member?: KeyValue
1333): void {
1334  if (member) {
1335    if (!member.isMocked) {
1336      const memberValue = handleKeyValue(member.key, member, mockBuffer, kvPath, keyValue, member.property);
1337      const functionKeyword = member.type === KeyValueTypes.FUNCTION ? 'function' : '';
1338      const prototypeStr = member.isStatic ? '' : '.prototype';
1339      const value = `global.${keyValue.key}_temp${prototypeStr}.${member.key} = ${functionKeyword}${memberValue};`;
1340      member.isMocked = true;
1341      declarations.push(value);
1342    }
1343    return;
1344  }
1345  if (keyValue.heritage) {
1346    handleHeritage(keyValue, mockBuffer, kvPath.concat(keyValue), keyValue);
1347  }
1348
1349  Object.keys(keyValue.members).forEach(
1350    memberKey => handleClassMembers(memberKey, keyValue, mockBuffer, kvPath, declarations)
1351  );
1352  // 处理同名declare
1353  keyValue.sameDeclares.forEach(sameDeclare => {
1354    const sameKeyValue = sameDeclare.keyValue;
1355    const sameMockBuffer = mockBufferMap.get(MockedFileMap.get(sameDeclare.from));
1356    Object.keys(sameKeyValue.members).forEach(
1357      memberKey => handleClassMembers(memberKey, sameKeyValue, sameMockBuffer, kvPath, declarations)
1358    );
1359  });
1360}
1361
1362/**
1363 * 处理class KV节点的属性和方法
1364 * @param memberKey 属性或方法的名称
1365 * @param parent 父级class KV节点
1366 * @param mockBuffer 所属文件的mock信息
1367 * @param kvPath KV节点路径
1368 * @param declarations 已mock的文本内容
1369 * @returns
1370 */
1371function handleClassMembers(
1372  memberKey: string,
1373  parent: KeyValue,
1374  mockBuffer: MockBuffer,
1375  kvPath: KeyValue[],
1376  declarations: string[]
1377): void {
1378  const memberKeyValue = parent.members[memberKey];
1379  if (memberKeyValue.isMocked) {
1380    return;
1381  }
1382  let elementName = `.${memberKey}`;
1383  if (memberKeyValue.type === KeyValueTypes.EXPRESSION) {
1384    memberKeyValue.key = handleKeyValue(memberKey, memberKeyValue, mockBuffer, kvPath, parent, memberKeyValue.property);
1385    memberKeyValue.type = KeyValueTypes.FUNCTION;
1386    memberKeyValue.value = undefined;
1387    elementName = memberKeyValue.key;
1388  }
1389
1390  const memberValue = handleKeyValue(memberKey, memberKeyValue, mockBuffer, kvPath, parent, memberKeyValue.property);
1391  let value: string;
1392  if (memberKeyValue.type === KeyValueTypes.FUNCTION) {
1393    value = handleClassMethod(memberKey, memberKeyValue, parent, mockBuffer, kvPath, elementName, memberValue);
1394  } else {
1395    value = `global.${parent.key}_temp${memberKeyValue.isStatic ? '' : '.prototype'}${elementName} = ${memberValue};`;
1396  }
1397  if (!memberKeyValue.isStatic && memberKeyValue.sameName.some(sameKeyValue => sameKeyValue.isStatic)) {
1398    value += `\nglobal.${parent.key}_temp${elementName} = global.${parent.key}_temp.prototype${elementName}`;
1399  }
1400  memberKeyValue.isMocked = true;
1401  declarations.push(value);
1402}
1403
1404/**
1405 * 处理全局module KV节点
1406 * @param keyValue KV节点
1407 * @param mockBuffer 所属文件的mock信息
1408 * @param declarations 已mock的文本内容
1409 * @param kvPath KV节点路径
1410 * @param member 不为undefined时,只mock这个member节点
1411 * @returns
1412 */
1413function handleGlobalModule(
1414  keyValue: KeyValue,
1415  mockBuffer: MockBuffer,
1416  declarations: string[],
1417  kvPath: KeyValue[],
1418  member?: KeyValue
1419): void {
1420  return handleGlobalModuleOrInterface(keyValue, mockBuffer, declarations, kvPath, member);
1421}
1422
1423/**
1424 * 处理全局module或interface KV节点
1425 * @param keyValue KV节点
1426 * @param mockBuffer 所属文件的mock信息
1427 * @param declarations 已mock的文本内容
1428 * @param kvPath KV节点路径
1429 * @param member 不为undefined时,只mock这个member节点
1430 * @returns
1431 */
1432function handleGlobalModuleOrInterface(
1433  keyValue: KeyValue,
1434  mockBuffer: MockBuffer,
1435  declarations: string[],
1436  kvPath: KeyValue[],
1437  member?: KeyValue
1438): void {
1439  if (member) {
1440    if (!member.isMocked) {
1441      const memberKey = member.key;
1442      const memberValue = handleKeyValue(memberKey, member, mockBuffer, kvPath, keyValue, member.property);
1443      const value = `global.${keyValue.key}_temp.${memberKey} = ${memberValue};`;
1444      member.isMocked = true;
1445      declarations.push(value);
1446    }
1447    return;
1448  }
1449  Object.keys(keyValue.members).forEach(memberKey => handleModuleOrInterfaceMember(memberKey, keyValue, mockBuffer, kvPath, declarations, keyValue));
1450  // 处理同名declare
1451  keyValue.sameDeclares.forEach(sameDeclare => {
1452    const sameKeyValue = sameDeclare.keyValue;
1453    const sameMockBuffer = mockBufferMap.get(MockedFileMap.get(sameDeclare.from));
1454    const needHandleTypes = new Set([KeyValueTypes.CLASS, KeyValueTypes.INTERFACE, KeyValueTypes.MODULE]);
1455    if (!needHandleTypes.has(sameKeyValue.type) && path.basename(sameMockBuffer.rawFilePath).startsWith('@')) {
1456      return;
1457    }
1458    Object.keys(sameKeyValue.members).forEach(
1459      memberKey => handleModuleOrInterfaceMember(memberKey, sameKeyValue, sameMockBuffer, kvPath, declarations, keyValue)
1460    );
1461  });
1462}
1463
1464/**
1465 * 处理module和interface的成员
1466 * @param memberKey 成员名称
1467 * @param parent 成员父节点
1468 * @param mockBuffer 当前文件mock信息
1469 * @param kvPath KV节点路径
1470 * @param declarations 已mock的全局接口
1471 * @param rootKeyValue
1472 */
1473function handleModuleOrInterfaceMember(
1474  memberKey: string,
1475  parent: KeyValue,
1476  mockBuffer: MockBuffer,
1477  kvPath: KeyValue[],
1478  declarations: string[],
1479  rootKeyValue: KeyValue
1480): void {
1481  const memberKeyValue = parent.members[memberKey];
1482  if (memberKeyValue.isMocked) {
1483    return;
1484  }
1485  let elementName = `.${memberKey}`;
1486  if (memberKeyValue.type === KeyValueTypes.EXPRESSION) {
1487    memberKeyValue.key = handleKeyValue(memberKey, memberKeyValue, mockBuffer, kvPath, rootKeyValue, memberKeyValue.property);
1488    memberKeyValue.type = KeyValueTypes.PROPERTY;
1489    memberKeyValue.value = undefined;
1490    elementName = memberKeyValue.key;
1491  }
1492  const memberValue = handleKeyValue(memberKey, memberKeyValue, mockBuffer, kvPath, rootKeyValue, memberKeyValue.property);
1493  const value = `global.${parent.key}_temp${elementName} = ${memberValue};`;
1494  memberKeyValue.isMocked = true;
1495  declarations.push(value);
1496}
1497
1498/**
1499 * 处理全局interface KV节点
1500 * @param keyValue KV节点
1501 * @param mockBuffer 所属文件的mock信息
1502 * @param declarations 已mock的文本内容
1503 * @param kvPath KV节点路径
1504 * @param member 不为undefined时,只mock这个member节点
1505 * @returns
1506 */
1507function handleGlobalInterface(
1508  keyValue: KeyValue,
1509  mockBuffer: MockBuffer,
1510  declarations: string[],
1511  kvPath: KeyValue[],
1512  member?: KeyValue
1513): void {
1514  if (keyValue.heritage) {
1515    handleHeritage(keyValue, mockBuffer, kvPath.concat(keyValue), keyValue);
1516  }
1517  return handleGlobalModuleOrInterface(keyValue, mockBuffer, declarations, kvPath, member);
1518}
1519
1520/**
1521 * 从导入节点向上查找类型定义
1522 * @param importKeyValue 导入的KV节点
1523 * @param mockBuffer 当前文件的mock信息
1524 * @param rootKeyValue 仅次于FILE节点的根节点
1525 * @param property KV节点的调用属性节点,如A.b, b节点为property
1526 * @returns
1527 */
1528function findDefFromImport(
1529  importKeyValue: KeyValue,
1530  mockBuffer: MockBuffer,
1531  rootKeyValue: KeyValue,
1532  property?: KeyValue
1533): ReferenceFindResult {
1534  const importedMockBuffer = mockBufferMap.get(MockedFileMap.get(importKeyValue.importedModulePath));
1535  if (!importedMockBuffer) {
1536    throw new Error('未找到foundKeyValue.importedModulePath对应的mockBuffer');
1537  }
1538  let defKeyValue: KeyValue;
1539  if (importKeyValue.isImportDefault) {
1540    defKeyValue = importedMockBuffer.contents.members.default;
1541  } else if (importKeyValue.isNamespaceImport) {
1542    defKeyValue = importedMockBuffer.contents;
1543  } else {
1544    defKeyValue = importedMockBuffer.contents.members[importKeyValue.rawName ?? importKeyValue.key];
1545  }
1546  if (defKeyValue.isGlobalDeclare) {
1547    const dependKeyValue = property ? defKeyValue.members[property.key] : defKeyValue;
1548    if (dependKeyValue.type === KeyValueTypes.ENUM) {
1549      defKeyValue = dependKeyValue;
1550    } else {
1551      !dependKeyValue.isMocked && rootKeyValue.dependOnGlobals.add(dependKeyValue);
1552      const keyValueType = getKeyValueType(defKeyValue, property);
1553      const newKey = `global.${defKeyValue.key}${concatProperty(property)}`;
1554      defKeyValue = generateKeyValue(newKey, keyValueType);
1555      defKeyValue.value = newKey;
1556      !dependKeyValue.isMocked && defKeyValue.dependOnGlobals.add(dependKeyValue);
1557    }
1558  } else {
1559    defKeyValue = findProperty(defKeyValue, property);
1560  }
1561
1562  if (!defKeyValue) {
1563    const value = `Not exported ${importKeyValue.rawName ?? importKeyValue.key} from ${importedMockBuffer.rawFilePath} in ${mockBuffer.rawFilePath}`.replace(/\\/g, '/');
1564    console.error(value);
1565    defKeyValue = generateKeyValue(value, KeyValueTypes.VALUE, importedMockBuffer.contents);
1566    defKeyValue.value = `'${value}'`;
1567  }
1568  return { keyValue: defKeyValue, mockBuffer: importedMockBuffer };
1569}
1570
1571/**
1572 * mock类方法
1573 * @param memberKey 方法原名
1574 * @param memberKeyValue 方法KV节点
1575 * @param parent  负极节点
1576 * @param mockBuffer 当前文件的mock信息
1577 * @param kvPath KV检点路径
1578 * @param elementName 方法名转换后方法名
1579 * @param memberValue 类方法的mock内容
1580 */
1581function handleClassMethod(
1582  memberKey: string,
1583  memberKeyValue: KeyValue,
1584  parent: KeyValue,
1585  mockBuffer: MockBuffer,
1586  kvPath: KeyValue[],
1587  elementName: string,
1588  memberValue: string
1589): string {
1590  let value:string;
1591  if (memberKey.startsWith('get ') || memberKey.startsWith('set ')) {
1592    value = handleClassGetterOrSetterMethod(memberKeyValue, parent, mockBuffer, kvPath);
1593  } else {
1594    value = `global.${parent.key}_temp${memberKeyValue.isStatic ? '' : '.prototype'}${elementName} = ${memberValue};`;
1595  }
1596  return value;
1597}
1598
1599/**
1600 * mock 类中带get和set关键字的方法
1601 * @param memberKeyValue 类方法KV节点
1602 * @param parent 父级KV节点
1603 * @param mockBuffer 当前文件的mock信息
1604 * @param kvPath KV节点路径
1605 */
1606function handleClassGetterOrSetterMethod(
1607  memberKeyValue: KeyValue,
1608  parent: KeyValue,
1609  mockBuffer: MockBuffer,
1610  kvPath: KeyValue[]
1611): string {
1612  const getKey = `get ${memberKeyValue.key}`;
1613  let getMethodValue: string = '';
1614  if (parent.members[getKey]) {
1615    const getFunctionBody = handleKeyValue(getKey, parent.members[getKey], mockBuffer, kvPath, parent, memberKeyValue.property);
1616    getMethodValue = `get: ${getFunctionBody},`;
1617  }
1618
1619  let setMethodValue: string = '';
1620  const setKey = `set ${memberKeyValue.key}`;
1621  if (parent.members[setKey]) {
1622    const setFunctionBody = handleKeyValue(setKey, parent.members[setKey], mockBuffer, kvPath, parent, memberKeyValue.property);
1623    setMethodValue = `set: ${setFunctionBody},`;
1624  }
1625
1626  if (parent.members[getKey]) {
1627    parent.members[getKey].isMocked = true;
1628  }
1629  if (parent.members[setKey]) {
1630    parent.members[setKey].isMocked = true;
1631  }
1632
1633  return `Object.defineProperty(global.${parent.key}_temp, '${memberKeyValue.key}', {
1634  ${getMethodValue}
1635  ${setMethodValue}
1636});`;
1637}
1638