forked from jenseng/react-i18nliner
-
Notifications
You must be signed in to change notification settings - Fork 2
/
ComponentInterpolator.js
124 lines (107 loc) · 3.69 KB
/
ComponentInterpolator.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
var React = require('react');
var cloneWithProps = require('react/lib/cloneWithProps');
var invariant = require('react/lib/invariant');
var { string, object } = React.PropTypes;
var WRAPPER_PATTERN = /(\*+)/;
var PLACEHOLDER_PATTERN = /(%\{.*?\})/;
var toArray = function(children) {
if (children instanceof Array) return children.slice();
if (!children) return [];
return [children];
};
// Replace a "$1" text descendant in this tree with the newDescendants
var injectNewDescendants = function(element, newDescendants, props, ensureInjected) {
newDescendants.injectedCount = newDescendants.injectedCount || 0;
props = props || {};
var children = toArray(element.props.children);
for (var i = 0; i < children.length; i++) {
var child = children[i];
children[i] = child.type ? injectNewDescendants(child, newDescendants) : child;
}
var injectIndex = getInjectIndex(children);
if (injectIndex >= 0) {
children.splice.apply(children, [injectIndex, 1].concat(newDescendants));
newDescendants.injectedCount++;
}
props.children = children;
if (ensureInjected) {
invariant(newDescendants.injectedCount === 1, 'wrappers must have a single "$1" text descendant');
}
return cloneWithProps(element, props);
};
var getInjectIndex = function(children, containerName) {
var child, index = -1;
for (var i = 0; i < children.length; i++) {
child = children[i];
if (typeof child !== "string") continue;
invariant(child === "$1", containerName + ' may not have any non-"$1" text children"');
invariant(index === -1, containerName + ' may not have multiple "$1" text children"');
index = i;
}
return index;
};
var ComponentInterpolator = React.createClass({
propTypes: {
string: string.isRequired,
wrappers: object
},
inferChildren() {
var tokens = (this.props.string || '').split(WRAPPER_PATTERN);
var inferredChildren = this.interpolateAllComponents(tokens);
var currentChildren = toArray(this.props.children);
var index = getInjectIndex(currentChildren, '<ComponentInterpolator>');
invariant(index >= 0, '<ComponentInterpolator> must have a "$1" text child"');
currentChildren.splice.apply(currentChildren, [index, 1].concat(inferredChildren));
return currentChildren;
},
interpolateAllComponents(tokens, eof) {
var token, child;
var children = [];
var wrappers = this.props.wrappers || {};
while (tokens.length) {
token = tokens.shift();
if (token === eof) break;
if (token.match(WRAPPER_PATTERN)) {
invariant(
child = wrappers[token],
`<ComponentInterpolator> expected '${token}' wrapper, none found`
);
child = injectNewDescendants(
child,
this.interpolateAllComponents(tokens, token),
{ key: tokens.length },
true
);
children.push(child);
}
else {
children.push.apply(children, this.interpolatePlaceholders(token));
}
}
return children;
},
interpolatePlaceholders(string) {
var token;
var tokens = string.split(PLACEHOLDER_PATTERN);
var children = [];
while (tokens.length) {
token = tokens.shift();
if (token.match(PLACEHOLDER_PATTERN)) {
token = token.slice(2, -1);
invariant(
child = this.props[token],
`<ComponentInterpolator> expected '${token}' placeholder value, none found`
);
child = child.type ? cloneWithProps(child, {key: tokens.length}) : child;
children.push(child);
} else {
children.push(token);
}
}
return children;
},
render() {
return React.createElement('span', {}, this.inferChildren());
}
});
module.exports = ComponentInterpolator;