Skip to content

Commit bfd1531

Browse files
committed
Add a gulp script for extracting error codes (#6882)
1 parent 50982ce commit bfd1531

File tree

10 files changed

+437
-1
lines changed

10 files changed

+437
-1
lines changed

.travis.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ script:
8181
>> src/renderers/dom/shared/ReactDOMFeatureFlags.js
8282
./node_modules/.bin/grunt jest:normal
8383
git checkout -- src/renderers/dom/shared/ReactDOMFeatureFlags.js
84+
./node_modules/.bin/gulp react:extract-errors
8485
else
8586
./node_modules/.bin/grunt $TEST_TYPE
8687
fi

gulpfile.js

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ var flatten = require('gulp-flatten');
1515
var del = require('del');
1616

1717
var babelPluginModules = require('fbjs-scripts/babel-6/rewrite-modules');
18+
var extractErrors = require('./scripts/error-codes/gulp-extract-errors');
1819

1920
var paths = {
2021
react: {
@@ -46,9 +47,13 @@ var moduleMap = Object.assign(
4647
}
4748
);
4849

50+
var errorCodeOpts = {
51+
errorMapFilePath: 'scripts/error-codes/codes.json',
52+
};
53+
4954
var babelOpts = {
5055
plugins: [
51-
[babelPluginModules, { map: moduleMap }],
56+
[babelPluginModules, {map: moduleMap}],
5257
],
5358
};
5459

@@ -64,4 +69,10 @@ gulp.task('react:modules', function() {
6469
.pipe(gulp.dest(paths.react.lib));
6570
});
6671

72+
gulp.task('react:extract-errors', function() {
73+
return gulp
74+
.src(paths.react.src)
75+
.pipe(extractErrors(errorCodeOpts));
76+
});
77+
6778
gulp.task('default', ['react:modules']);

package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
"babel-plugin-transform-object-rest-spread": "^6.6.5",
3030
"babel-plugin-transform-react-jsx-source": "^6.8.0",
3131
"babel-preset-react": "^6.5.0",
32+
"babel-traverse": "^6.9.0",
33+
"babylon": "^6.8.0",
3234
"browserify": "^13.0.0",
3335
"bundle-collapser": "^1.1.1",
3436
"coffee-script": "^1.8.0",
@@ -51,6 +53,7 @@
5153
"gulp": "^3.9.0",
5254
"gulp-babel": "^6.0.0",
5355
"gulp-flatten": "^0.2.0",
56+
"gulp-util": "^3.0.7",
5457
"gzip-js": "~0.3.2",
5558
"jest": "^12.1.1",
5659
"loose-envify": "^1.1.0",
@@ -95,6 +98,7 @@
9598
"testPathDirs": [
9699
"<rootDir>/eslint-rules",
97100
"<rootDir>/mocks",
101+
"<rootDir>/scripts",
98102
"<rootDir>/src",
99103
"node_modules/fbjs"
100104
],

scripts/error-codes/Types.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/**
2+
* Copyright (c) 2013-present, Facebook, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*
9+
* @flow
10+
*/
11+
'use strict';
12+
13+
/*:: export type ErrorMap = { [id: string]: string; }; */
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/**
2+
* Copyright (c) 2013-present, Facebook, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*/
9+
'use strict';
10+
11+
var evalToString = require('../evalToString');
12+
var babylon = require('babylon');
13+
14+
var parse = (source) => babylon.parse(
15+
`(${source});`
16+
).program.body[0].expression; // quick way to get an exp node
17+
18+
var parseAndEval = (source) => evalToString(parse(source));
19+
20+
describe('evalToString', () => {
21+
it('should support StringLiteral', () => {
22+
expect(parseAndEval(`'foobar'`)).toBe('foobar');
23+
expect(parseAndEval(`'yowassup'`)).toBe('yowassup');
24+
});
25+
26+
it('should support string concat (`+`)', () => {
27+
expect(parseAndEval(`'foo ' + 'bar'`)).toBe('foo bar');
28+
});
29+
30+
it('should throw when it finds other types', () => {
31+
expect(() => parseAndEval(`'foo ' + true`)).toThrowError(/Unsupported type/);
32+
expect(() => parseAndEval(`'foo ' + 3`)).toThrowError(/Unsupported type/);
33+
expect(() => parseAndEval(`'foo ' + null`)).toThrowError(/Unsupported type/);
34+
expect(() => parseAndEval(`'foo ' + undefined`)).toThrowError(/Unsupported type/);
35+
});
36+
});
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/**
2+
* Copyright (c) 2013-present, Facebook, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*/
9+
'use strict';
10+
11+
var invertObject = require('../invertObject');
12+
13+
var objectValues = (target) => Object.keys(target).map((key) => target[key]);
14+
15+
describe('invertObject', () => {
16+
it('should return an empty object for an empty input', () => {
17+
expect(invertObject({})).toEqual({});
18+
});
19+
20+
it('should invert key-values', () => {
21+
expect(invertObject({
22+
a: '3',
23+
b: '4',
24+
})).toEqual({
25+
3: 'a',
26+
4: 'b',
27+
});
28+
});
29+
30+
it('should take the last value when there\'re duplications in vals', () => {
31+
expect(invertObject({
32+
a: '3',
33+
b: '4',
34+
c: '3',
35+
})).toEqual({
36+
4: 'b',
37+
3: 'c',
38+
});
39+
});
40+
41+
it('should perserve the original order', () => {
42+
expect(Object.keys(invertObject({
43+
a: '3',
44+
b: '4',
45+
c: '3',
46+
}))).toEqual(['3', '4']);
47+
48+
expect(objectValues(invertObject({
49+
a: '3',
50+
b: '4',
51+
c: '3',
52+
}))).toEqual(['c', 'b']);
53+
});
54+
});

scripts/error-codes/codes.json

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
{
2+
"0": "React.addons.createFragment(...): Encountered an invalid child; DOM elements are not valid children of React components.",
3+
"1": "update(): expected target of %s to be an array; got %s.",
4+
"2": "update(): expected spec of %s to be an array; got %s. Did you forget to wrap your parameter in an array?",
5+
"3": "update(): You provided a key path to update() that did not contain one of %s. Did you forget to include {%s: ...}?",
6+
"4": "Cannot have more than one key in an object with %s",
7+
"5": "update(): %s expects a spec of type 'object'; got %s",
8+
"6": "update(): %s expects a target of type 'object'; got %s",
9+
"7": "Expected %s target to be an array; got %s",
10+
"8": "update(): expected spec of %s to be an array of arrays; got %s. Did you forget to wrap your parameters in an array?",
11+
"9": "update(): expected spec of %s to be a function; got %s.",
12+
"10": "findAllInRenderedTree(...): instance must be a composite component",
13+
"11": "TestUtils.scryRenderedDOMComponentsWithClass expects a className as a second argument.",
14+
"12": "ReactShallowRenderer render(): Invalid component element.%s",
15+
"13": "ReactShallowRenderer render(): Shallow rendering works only with custom components, not primitives (%s). Instead of calling `.render(el)` and inspecting the rendered output, look at `el.props` directly instead.",
16+
"14": "TestUtils.Simulate expects a component instance and not a ReactElement.TestUtils.Simulate will not work if you are using shallow rendering.",
17+
"15": "reactComponentExpect(...): instance must be a composite component",
18+
"16": "Do not override existing functions.",
19+
"17": "All native instances should have a tag.",
20+
"18": "Expected a component class, got %s.%s",
21+
"19": "Expect a native root tag, instead got %s",
22+
"20": "RawText \"%s\" must be wrapped in an explicit <Text> component.",
23+
"21": "findNodeHandle(...): Argument is not a component (type: %s, keys: %s)",
24+
"22": "findNodeHandle(...): Unable to find node handle for unmounted component.",
25+
"23": "onlyChild must be passed a children with exactly one child.",
26+
"24": "Mismatched list of contexts in callback queue",
27+
"25": "Trying to release an instance into a pool of a different type.",
28+
"26": "Unexpected node: %s",
29+
"27": "Transaction.perform(...): Cannot initialize a transaction when there is already an outstanding transaction.",
30+
"28": "Transaction.closeAll(): Cannot close transaction when none are open.",
31+
"29": "accumulate(...): Accumulated items must be not be null or undefined.",
32+
"30": "accumulateInto(...): Accumulated items must not be null or undefined.",
33+
"31": "Objects are not valid as a React child (found: %s).%s",
34+
"32": "Unable to find element with ID %s.",
35+
"33": "getNodeFromInstance: Invalid argument.",
36+
"34": "React DOM tree root should always have a node reference.",
37+
"35": "isAncestor: Invalid argument.",
38+
"36": "getParentInstance: Invalid argument.",
39+
"37": "_registerComponent(...): Target container is not a DOM element.",
40+
"38": "parentComponent must be a valid React Component",
41+
"39": "ReactDOM.render(): Invalid component element.%s",
42+
"40": "unmountComponentAtNode(...): Target container is not a DOM element.",
43+
"41": "mountComponentIntoNode(...): Target container is not valid.",
44+
"42": "You're trying to render a component to the document using server rendering but the checksum was invalid. This usually means you rendered a different component type or props on the client from the one on the server, or your render() methods are impure. React cannot handle this case due to cross-browser quirks by rendering at the document root. You should look for environment dependent code in your components and ensure the props are the same client and server side:\n%s",
45+
"43": "You're trying to render a component to the document but you didn't use server rendering. We can't do this without using server rendering due to cross-browser quirks. See ReactDOMServer.renderToString() for server rendering.",
46+
"44": "findDOMNode was called on an unmounted component.",
47+
"45": "Element appears to be neither ReactComponent nor DOMNode (keys: %s)",
48+
"46": "renderToString(): You must pass a valid ReactElement.",
49+
"47": "renderToStaticMarkup(): You must pass a valid ReactElement.",
50+
"48": "injectDOMPropertyConfig(...): You're trying to inject DOM property '%s' which has already been injected. You may be accidentally injecting the same DOM property config twice, or you may be injecting two configs that have conflicting property names.",
51+
"49": "DOMProperty: Properties that have side effects must use property: %s",
52+
"50": "DOMProperty: Value can be one of boolean, overloaded boolean, or numeric value, but not a combination: %s",
53+
"51": "dangerouslyRenderMarkup(...): Cannot render markup in a worker thread. Make sure `window` and `document` are available globally before requiring React when unit testing or use ReactDOMServer.renderToString for server rendering.",
54+
"52": "dangerouslyRenderMarkup(...): Missing markup.",
55+
"53": "Danger: Assigning to an already-occupied result index.",
56+
"54": "Danger: Did not assign to every index of resultList.",
57+
"55": "Danger: Expected markup to render %s nodes, but rendered %s.",
58+
"56": "dangerouslyReplaceNodeWithMarkup(...): Cannot render markup in a worker thread. Make sure `window` and `document` are available globally before requiring React when unit testing or use ReactDOMServer.renderToString() for server rendering.",
59+
"57": "dangerouslyReplaceNodeWithMarkup(...): Missing markup.",
60+
"58": "dangerouslyReplaceNodeWithMarkup(...): Cannot replace markup of the <html> node. This is because browser quirks make this unreliable and/or slow. If you want to render to the root you must use server rendering. See ReactDOMServer.renderToString().",
61+
"59": "%s is a void element tag and must not have `children` or use `props.dangerouslySetInnerHTML`.%s",
62+
"60": "Can only set one of `children` or `props.dangerouslySetInnerHTML`.",
63+
"61": "`props.dangerouslySetInnerHTML` must be in the form `{__html: ...}`. Please visit https://fb.me/react-invariant-dangerously-set-inner-html for more information.",
64+
"62": "The `style` prop expects a mapping from style properties to values, not a string. For example, style={{marginRight: spacing + 'em'}} when using JSX.%s",
65+
"63": "Must be mounted to trap events",
66+
"64": "trapBubbledEvent(...): Requires node to be rendered.",
67+
"65": "Invalid tag: %s",
68+
"66": "<%s> tried to unmount. Because of cross-browser quirks it is impossible to unmount some top-level components (eg <html>, <head>, and <body>) reliably and efficiently. To fix this, have a single top-level component that never unmounts render these elements.",
69+
"67": "Missing closing comment for text component %s",
70+
"68": "Expected devtool events to fire for the child before its parent includes it in onSetChildren().",
71+
"69": "Expected onSetDisplayName() to fire for the child before its parent includes it in onSetChildren().",
72+
"70": "Expected onSetChildren() or onSetText() to fire for the child before its parent includes it in onSetChildren().",
73+
"71": "Expected onMountComponent() to fire for the child before its parent includes it in onSetChildren().",
74+
"72": "Expected onSetParent() and onSetChildren() to be consistent (%s has parents %s and %s).",
75+
"73": "ReactClassInterface: You are attempting to override `%s` from your class specification. Ensure that your method names do not overlap with React methods.",
76+
"74": "ReactClassInterface: You are attempting to define `%s` on your component more than once. This conflict may be due to a mixin.",
77+
"75": "ReactClass: You're attempting to use a component class or function as a mixin. Instead, just use a regular object.",
78+
"76": "ReactClass: You're attempting to use a component as a mixin. Instead, just use a regular object.",
79+
"77": "ReactClass: Unexpected spec policy %s for key %s when mixing in component specs.",
80+
"78": "ReactClass: You are attempting to define a reserved property, `%s`, that shouldn't be on the \"statics\" key. Define it as an instance property instead; it will still be accessible on the constructor.",
81+
"79": "ReactClass: You are attempting to define `%s` on your component more than once. This conflict may be due to a mixin.",
82+
"80": "mergeIntoWithNoDuplicateKeys(): Cannot merge non-objects.",
83+
"81": "mergeIntoWithNoDuplicateKeys(): Tried to merge two objects with the same key: `%s`. This conflict may be due to a mixin; in particular, this may be caused by two getInitialState() or getDefaultProps() methods returning objects with clashing keys.",
84+
"82": "%s.getInitialState(): must return an object or null",
85+
"83": "createClass(...): Class specification must implement a `render` method.",
86+
"84": "%s: %s type `%s` is invalid; it must be a function, usually from React.PropTypes.",
87+
"85": "setState(...): takes an object of state variables to update or a function which returns an object of state variables.",
88+
"86": "SimpleEventPlugin: Unhandled event type, `%s`.",
89+
"87": "Cannot provide a checkedLink and a valueLink. If you want to use checkedLink, you probably don't want to use valueLink and vice versa.",
90+
"88": "Cannot provide a valueLink and a value or onChange event. If you want to use value or onChange, you probably don't want to use valueLink.",
91+
"89": "Cannot provide a checkedLink and a checked property or onChange event. If you want to use checked or onChange, you probably don't want to use checkedLink",
92+
"90": "ReactDOMInput: Mixing React and non-React radio inputs with the same `name` is not supported.",
93+
"91": "`dangerouslySetInnerHTML` does not make sense on <textarea>.",
94+
"92": "If you supply `defaultValue` on a <textarea>, do not pass children.",
95+
"93": "<textarea> can only have at most one child.",
96+
"94": "Expected %s listener to be a function, instead got type %s",
97+
"95": "processEventQueue(): Additional events were enqueued while processing an event queue. Support for this has not yet been implemented.",
98+
"96": "EventPluginRegistry: Cannot inject event plugins that do not exist in the plugin ordering, `%s`.",
99+
"97": "EventPluginRegistry: Event plugins must implement an `extractEvents` method, but `%s` does not.",
100+
"98": "EventPluginRegistry: Failed to publish event `%s` for plugin `%s`.",
101+
"99": "EventPluginHub: More than one plugin attempted to publish the same event name, `%s`.",
102+
"100": "EventPluginHub: More than one plugin attempted to publish the same registration name, `%s`.",
103+
"101": "EventPluginRegistry: Cannot inject event plugin ordering more than once. You are likely trying to load more than one copy of React.",
104+
"102": "EventPluginRegistry: Cannot inject two different event plugins using the same name, `%s`.",
105+
"103": "executeDirectDispatch(...): Invalid `event`.",
106+
"104": "ReactCompositeComponent: injectEnvironment() can only be called once.",
107+
"105": "%s(...): A valid React element (or null) must be returned. You may have returned undefined, an array or some other invalid object.",
108+
"106": "%s.state: must be set to an object or null",
109+
"107": "%s.getChildContext(): childContextTypes must be defined in order to use getChildContext().",
110+
"108": "%s.getChildContext(): key \"%s\" is not defined in childContextTypes.",
111+
"109": "%s.render(): A valid React element (or null) must be returned. You may have returned undefined, an array or some other invalid object.",
112+
"110": "Stateless function components cannot have refs.",
113+
"111": "There is no registered component for the tag %s",
114+
"112": "getNextDescendantID(%s, %s): Received an invalid React DOM ID.",
115+
"113": "getNextDescendantID(...): React has made an invalid assumption about the DOM hierarchy. Expected `%s` to be an ancestor of `%s`.",
116+
"114": "getFirstCommonAncestorID(%s, %s): Expected a valid React DOM ID: %s",
117+
"115": "traverseParentPath(...): Cannot traverse from and to the same ID, `%s`.",
118+
"116": "traverseParentPath(%s, %s, ...): Cannot traverse from two IDs that do not have a parent path.",
119+
"117": "traverseParentPath(%s, %s, ...): Detected an infinite loop while traversing the React DOM ID tree. This may be due to malformed IDs: %s",
120+
"118": "updateTextContent called on non-empty component.",
121+
"119": "addComponentAsRefTo(...): Only a ReactOwner can have refs. You might be adding a ref to a component that was not created inside a component's `render` method, or you have multiple copies of React loaded (details: https://fb.me/react-refs-must-have-owner).",
122+
"120": "removeComponentAsRefFrom(...): Only a ReactOwner can have refs. You might be removing a ref to a component that was not created inside a component's `render` method, or you have multiple copies of React loaded (details: https://fb.me/react-refs-must-have-owner).",
123+
"121": "performUpdateIfNecessary: Unexpected batch number (current %s, pending %s)",
124+
"122": "%s(...): Expected the last optional `callback` argument to be a function. Instead received: %s.",
125+
"123": "ReactUpdates: must inject a reconcile transaction class and batching strategy",
126+
"124": "Expected flush transaction's stored dirty-components length (%s) to match dirty-components array length (%s).",
127+
"125": "ReactUpdates.asap: Can't enqueue an asap callback in a context whereupdates are not being batched.",
128+
"126": "ReactUpdates: must provide a reconcile transaction class",
129+
"127": "ReactUpdates: must provide a batching strategy",
130+
"128": "ReactUpdates: must provide a batchedUpdates() function",
131+
"129": "ReactUpdates: must provide an isBatchingUpdates boolean attribute",
132+
"130": "Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: %s.%s",
133+
"131": "Encountered invalid React node of type %s",
134+
"132": "Ended a touch event which was not counted in trackedTouchCount.",
135+
"133": "Touch object is missing identifier",
136+
"134": "Touch data should have been recorded on start",
137+
"135": "Cannot find single active touch"
138+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/**
2+
* Copyright (c) 2013-present, Facebook, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*
9+
* @flow
10+
*/
11+
'use strict';
12+
13+
function evalToString(ast/* : Object */)/* : string */ {
14+
switch (ast.type) {
15+
case 'StringLiteral':
16+
return ast.value;
17+
case 'BinaryExpression': // `+`
18+
if (ast.operator !== '+') {
19+
throw new Error('Unsupported binary operator ' + ast.operator);
20+
}
21+
return evalToString(ast.left) + evalToString(ast.right);
22+
default:
23+
throw new Error('Unsupported type ' + ast.type);
24+
}
25+
}
26+
27+
module.exports = evalToString;

0 commit comments

Comments
 (0)