1 4
import * as t from '@babel/types';
2
import { NodePath } from '@babel/traverse';
3 4
import * as helpers from './helpers';
4 4
import { STUB_BLOCK, TEMPLATE_ID, EXPRESSION_BLOCK, ENTRY } from './constants';
5

6 4
function isStubAttribute(attribute: t.JSXAttribute | t.JSXSpreadAttribute) {
7 4
  if (t.isJSXSpreadAttribute(attribute)) {
8 4
    return false;
9
  }
10

11 4
  const attrName = attribute.name.name;
12

13 4
  if (attrName === TEMPLATE_ID || attrName === ENTRY) {
14 4
    return false;
15
  }
16

17
  // case: Null
18 4
  if (attribute.value === null) {
19 4
    return true;
20
  }
21

22
  // case: Literal 属性
23 4
  if (t.isLiteral(attribute.value)) {
24 4
    return true;
25
  }
26

27
  // case: 表达式
28 4
  if (t.isJSXExpressionContainer(attribute.value)) {
29
    // 同 Literal
30 4
    if (t.isLiteral(attribute.value.expression)) {
31 4
      return true;
32
    }
33
  }
34
}
35

36
/**
37
 * 判断是否是一个可以 stub 的元素
38
 *
39
 * @param {t.JSXElement|t.JSXFragment} node
40
 * @returns
41
 */
42 4
function isStubElement(node: t.JSXElement | t.JSXFragment, path: NodePath<any>): boolean {
43 4
  let isSelfStub = false;
44

45 4
  if (t.isJSXFragment(node)) {
46 4
    isSelfStub = true;
47
  }
48

49 4
  if (t.isJSXElement(node)) {
50 4
    const name = (node.openingElement.name as any)?.name;
51

52 4
    if (name === STUB_BLOCK) {
53 0
      return true;
54
    }
55

56 4
    if (name === EXPRESSION_BLOCK) {
57 4
      return false;
58
    }
59

60 4
    if (!helpers.isHostComponentElement(node, path)) {
61 0
      return false;
62
    }
63

64 4
    const attributes = node.openingElement.attributes;
65 4
    isSelfStub = attributes.every(isStubAttribute);
66
  }
67

68 4
  const isChildrenVoid: boolean = node.children.every(c => {
69 4
    if (t.isJSXElement(c) || t.isJSXFragment(c)) {
70 4
      return isStubElement(c, path);
71
    }
72

73 4
    if (t.isJSXText(c)) {
74 4
      return true;
75
    }
76

77 4
    if (t.isJSXExpressionContainer(c)) {
78 4
      if (t.isLiteral(c.expression)) {
79 0
        return true;
80
      }
81
    }
82

83
    // case: JSXSpreadChild
84

85 4
    return false;
86
  });
87

88 4
  return isSelfStub && isChildrenVoid;
89
}
90

91
/**
92
 * 在生成模板后,对 jsx 再处理
93
 * 用于帮助简化 React 生成 虚拟 dom
94
 *
95
 * @export
96
 * @returns
97
 */
98 4
export default function postProcess() {
99 4
  return {
100
    visitor: {
101 4
      JSXElement: (path: NodePath<t.JSXElement>) => {
102 4
        const node = path.node;
103

104 4
        if ((node.openingElement.name as any)?.name === STUB_BLOCK) {
105 4
          return;
106
        }
107

108
        // 非 host component 不处理
109 4
        if (!helpers.isHostComponentElement(node, path)) {
110 4
          return false;
111
        }
112

113
        // 删除可以被 stub 的属性
114 4
        node.openingElement.attributes = node.openingElement.attributes.filter(attr => !isStubAttribute(attr));
115

116 4
        if (isStubElement(node, path)) {
117 4
          helpers.replacedWithStubBlock(path);
118
        }
119
      },
120
    },
121
  };
122
}

Read our documentation on viewing source code .

Loading