-
-
Notifications
You must be signed in to change notification settings - Fork 32
/
index.js
148 lines (137 loc) · 4.64 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
import Literal from '../Literal';
import JSXElement from '../JSXElement';
import Identifier from './Identifier';
import TaggedTemplateExpression from './TaggedTemplateExpression';
import TemplateLiteral from './TemplateLiteral';
import FunctionExpression from './FunctionExpression';
import LogicalExpression from './LogicalExpression';
import MemberExpression from './MemberExpression';
import OptionalMemberExpression from './OptionalMemberExpression';
import CallExpression from './CallExpression';
import UnaryExpression from './UnaryExpression';
import ThisExpression from './ThisExpression';
import ConditionalExpression from './ConditionalExpression';
import BinaryExpression from './BinaryExpression';
import ObjectExpression from './ObjectExpression';
import NewExpression from './NewExpression';
import UpdateExpression from './UpdateExpression';
import ArrayExpression from './ArrayExpression';
import BindExpression from './BindExpression';
import SpreadElement from './SpreadElement';
// Composition map of types to their extractor functions.
const TYPES = {
Identifier,
Literal,
JSXElement,
TaggedTemplateExpression,
TemplateLiteral,
ArrowFunctionExpression: FunctionExpression,
FunctionExpression,
LogicalExpression,
MemberExpression,
OptionalMemberExpression,
CallExpression,
UnaryExpression,
ThisExpression,
ConditionalExpression,
BinaryExpression,
ObjectExpression,
NewExpression,
UpdateExpression,
ArrayExpression,
BindExpression,
SpreadElement,
};
const noop = () => null;
const errorMessage = expression => `The prop value with an expression type of ${expression} could not be resolved. Please file issue to get this fixed immediately.`;
/**
* This function maps an AST value node
* to its correct extractor function for its
* given type.
*
* This will map correctly for *all* possible expression types.
*
* @param - value - AST Value object with type `JSXExpressionContainer`
* @returns The extracted value.
*/
export default function extract(value) {
// Value will not have the expression property when we recurse.
// The type for expression on ArrowFunctionExpression is a boolean.
let expression;
if (
typeof value.expression !== 'boolean'
&& value.expression
) {
expression = value.expression; // eslint-disable-line prefer-destructuring
} else {
expression = value;
}
let { type } = expression;
while (type === 'TSNonNullExpression' || type === 'TSAsExpression') {
expression = expression.expression;
type = expression.type;
}
if (TYPES[type] === undefined) {
throw new Error(errorMessage(type));
}
return TYPES[type](expression);
}
// Composition map of types to their extractor functions to handle literals.
const LITERAL_TYPES = Object.assign({}, TYPES, {
Literal: (value) => {
const extractedVal = TYPES.Literal.call(undefined, value);
const isNull = extractedVal === null;
// This will be convention for attributes that have null
// value explicitly defined (<div prop={null} /> maps to 'null').
return isNull ? 'null' : extractedVal;
},
Identifier: (value) => {
const isUndefined = TYPES.Identifier.call(undefined, value) === undefined;
return isUndefined ? undefined : null;
},
JSXElement: noop,
ArrowFunctionExpression: noop,
FunctionExpression: noop,
LogicalExpression: noop,
MemberExpression: noop,
OptionalMemberExpression: noop,
CallExpression: noop,
UnaryExpression: (value) => {
const extractedVal = TYPES.UnaryExpression.call(undefined, value);
return extractedVal === undefined ? null : extractedVal;
},
UpdateExpression: (value) => {
const extractedVal = TYPES.UpdateExpression.call(undefined, value);
return extractedVal === undefined ? null : extractedVal;
},
ThisExpression: noop,
ConditionalExpression: noop,
BinaryExpression: noop,
ObjectExpression: noop,
NewExpression: noop,
ArrayExpression: (value) => {
const extractedVal = TYPES.ArrayExpression.call(undefined, value);
return extractedVal.filter(val => val !== null);
},
BindExpression: noop,
SpreadElement: noop,
});
/**
* This function maps an AST value node
* to its correct extractor function for its
* given type.
*
* This will map correctly for *some* possible types that map to literals.
*
* @param - value - AST Value object with type `JSXExpressionContainer`
* @returns The extracted value.
*/
export function extractLiteral(value) {
// Value will not have the expression property when we recurse.
const expression = value.expression || value;
const { type } = expression;
if (LITERAL_TYPES[type] === undefined) {
throw new Error(errorMessage(type));
}
return LITERAL_TYPES[type](expression);
}