1 | import {isElement} from './ast';
|
2 | import generate from './generation';
|
3 |
|
4 |
|
5 | const add = (set, key) => set[key] = true;
|
6 | const del = (set, key) => delete set[key];
|
7 |
|
8 | export default function freeVariablesInMessage(node) {
|
9 | if (!isElement(node)) {
|
10 | return [];
|
11 | }
|
12 | const variables = {};
|
13 | freeVariablesInChildren(node.children, variables);
|
14 | del(variables, 'this');
|
15 | return Object.keys(variables);
|
16 | }
|
17 |
|
18 | function freeVariablesInChildren(children, variables) {
|
19 | children.forEach(child => {
|
20 | switch(child.type) {
|
21 | case 'JSXElement':
|
22 | freeVariablesInElement(child, variables);
|
23 | break;
|
24 |
|
25 | case 'JSXExpressionContainer':
|
26 | freeVariablesInExpression(child.expression, variables);
|
27 | break;
|
28 | }
|
29 | });
|
30 | }
|
31 |
|
32 | function freeVariablesInElement(element, variables) {
|
33 | freeVariablesInElementName(element.openingElement.name, variables);
|
34 | freeVariablesInAttributes(element.openingElement.attributes, variables);
|
35 | freeVariablesInChildren(element.children, variables);
|
36 | }
|
37 |
|
38 | function freeVariablesInElementName(name, variables) {
|
39 | if (name.type === 'JSXIdentifier') {
|
40 | if (name.name.toLowerCase() !== name.name) {
|
41 | add(variables, name.name);
|
42 | }
|
43 | } else if (name.type === 'JSXMemberExpression') {
|
44 |
|
45 | add(variables, generate(name).split('.')[0]);
|
46 | } else if (name.type === 'JSXNamespacedName') {
|
47 | if (name.namespace.name.toLowerCase() !== name.namespace.name) {
|
48 | add(variables, name.namespace.name);
|
49 | }
|
50 | }
|
51 | }
|
52 |
|
53 | function freeVariablesInAttributes(attributes, variables) {
|
54 | attributes.forEach(a => freeVariablesInAttribute(a, variables));
|
55 | }
|
56 |
|
57 | function freeVariablesInAttribute(attribute, variables) {
|
58 | if (
|
59 | attribute.value &&
|
60 | attribute.value.type === 'JSXExpressionContainer'
|
61 | ) {
|
62 | freeVariablesInExpression(attribute.value.expression, variables);
|
63 | }
|
64 | if (
|
65 | attribute.type === 'JSXSpreadAttribute'
|
66 | ) {
|
67 | freeVariablesInExpression(attribute.argument, variables);
|
68 | }
|
69 | }
|
70 |
|
71 | function freeVariablesInObjectExpression(expression, variables) {
|
72 | expression.properties.forEach(property => {
|
73 | if (property.type === 'SpreadProperty') {
|
74 | freeVariablesInExpression(property.argument, variables);
|
75 | } else {
|
76 | freeVariablesInExpression(property.value, variables);
|
77 | if (property.computed) {
|
78 | freeVariablesInExpression(property.key, variables);
|
79 | }
|
80 | }
|
81 | });
|
82 | }
|
83 |
|
84 | function freeVariablesInExpression(expression, variables) {
|
85 | switch(expression.type) {
|
86 | case 'Identifier':
|
87 | add(variables, expression.name);
|
88 | break;
|
89 |
|
90 | case 'MemberExpression':
|
91 | add(variables, generate(expression).split('.')[0]);
|
92 | break;
|
93 |
|
94 | case 'CallExpression':
|
95 | freeVariablesInExpression(expression.callee, variables);
|
96 | break;
|
97 |
|
98 | case 'BinaryExpression':
|
99 | freeVariablesInExpression(expression.left, variables);
|
100 | freeVariablesInExpression(expression.right, variables);
|
101 | break;
|
102 |
|
103 | case 'ObjectExpression':
|
104 | freeVariablesInObjectExpression(expression, variables);
|
105 | break;
|
106 |
|
107 | case 'Literal':
|
108 | case 'StringLiteral':
|
109 | case 'NumericLiteral':
|
110 | case 'BooleanLiteral':
|
111 | case 'JSXEmptyExpression':
|
112 |
|
113 | break;
|
114 |
|
115 | default:
|
116 | console.log(expression);
|
117 | }
|
118 | }
|