Skip to content

Commit

Permalink
make ComponentInterpolator a pure functional component
Browse files Browse the repository at this point in the history
Because ComponentInterpolator has no persistent state, this breaks the
dependency on the deprecated createClass by making ComponentInterpolator
a pure functional component instead. To do this, props and keyCounter
have been made part of the method signatures of its recursive helper
methods.
  • Loading branch information
Jason Wodicka committed Jun 27, 2017
1 parent ff60265 commit b2adb45
Showing 1 changed file with 76 additions and 69 deletions.
145 changes: 76 additions & 69 deletions ComponentInterpolator.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,78 +47,85 @@ var getInjectIndex = function(children, containerName) {
return index;
};

var ComponentInterpolator = React.createClass({
propTypes: {
string: string.isRequired,
wrappers: object
},

inferChildren() {
var tokens = (this.props.string || '').split(WRAPPER_PATTERN);
this.keyCounter = 0;
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: this.keyCounter++ },
true
);
children.push(child);
}
else {
children.push.apply(children, this.interpolatePlaceholders(token));
}
var Counter = function() {
this.count = 0;
this.next = function() {
return this.count++;
};
};

var inferChildren = function(props) {
var tokens = (props.string || '').split(WRAPPER_PATTERN);
var inferredChildren = interpolateAllComponents(tokens, props);

var currentChildren = toArray(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;
};

var interpolateAllComponents = function(tokens, props, keyCounter, eof) {
var token, child;
var children = [];
var wrappers = props.wrappers || {};
if (!keyCounter) {
keyCounter = new Counter();
}
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,
interpolateAllComponents(tokens, props, keyCounter, token),
{ key: keyCounter.next() },
true
);
children.push(child);
}
return children;
},

interpolatePlaceholders(string) {
var token, child;
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(
this.props.hasOwnProperty(token),
`<ComponentInterpolator> expected '${token}' placeholder value, none found`
);
child = this.props[token];
child = child && child.type ? React.cloneElement(child, {key: this.keyCounter++}) : child;
children.push(child);
} else {
children.push(token);
}
else {
children.push.apply(children, interpolatePlaceholders(token, props, keyCounter));
}
return children;
},
}
return children;
};

render() {
return React.createElement('span', {}, this.inferChildren());
var interpolatePlaceholders = function(string, props, keyCounter) {
var token, child;
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(
props.hasOwnProperty(token),
`<ComponentInterpolator> expected '${token}' placeholder value, none found`
);
child = props[token];
child = child && child.type ? React.cloneElement(child, {key: keyCounter.next()}) : child;
children.push(child);
} else {
children.push(token);
}
}
});
return children;
};

var ComponentInterpolator = function(props) {
return React.createElement('span', {}, inferChildren(props));
};

ComponentInterpolator.propTypes = {
string: string.isRequired,
wrappers: object
};

module.exports = ComponentInterpolator;

0 comments on commit b2adb45

Please sign in to comment.