@samitouri / QOS-React / commits / bfd1531eca

Add a gulp script for extracting error codes (#6882)

Keyan Zhang committed Jun 1, 2016 at 11:21 UTC bfd1531eca38e4e25a9517a00d5be1283bda6696
10 files changed +437 -1
.travis.yml
+1
@@ -81,6 +81,7 @@ script:
81 >> src/renderers/dom/shared/ReactDOMFeatureFlags.js
82 ./node_modules/.bin/grunt jest:normal
83 git checkout -- src/renderers/dom/shared/ReactDOMFeatureFlags.js
84 + ./node_modules/.bin/gulp react:extract-errors
85 else
86 ./node_modules/.bin/grunt $TEST_TYPE
87 fi
gulpfile.js
+12 -1
@@ -15,6 +15,7 @@ var flatten = require('gulp-flatten');
15 var del = require('del');
16
17 var babelPluginModules = require('fbjs-scripts/babel-6/rewrite-modules');
18 +var extractErrors = require('./scripts/error-codes/gulp-extract-errors');
19
20 var paths = {
21 react: {
@@ -46,9 +47,13 @@ var moduleMap = Object.assign(
47 }
48 );
49
50 +var errorCodeOpts = {
51 + errorMapFilePath: 'scripts/error-codes/codes.json',
52 +};
53 +
54 var babelOpts = {
55 plugins: [
51 - [babelPluginModules, { map: moduleMap }],
56 + [babelPluginModules, {map: moduleMap}],
57 ],
58 };
59
@@ -64,4 +69,10 @@ gulp.task('react:modules', function() {
69 .pipe(gulp.dest(paths.react.lib));
70 });
71
72 +gulp.task('react:extract-errors', function() {
73 + return gulp
74 + .src(paths.react.src)
75 + .pipe(extractErrors(errorCodeOpts));
76 +});
77 +
78 gulp.task('default', ['react:modules']);
package.json
+4
@@ -29,6 +29,8 @@
29 "babel-plugin-transform-object-rest-spread": "^6.6.5",
30 "babel-plugin-transform-react-jsx-source": "^6.8.0",
31 "babel-preset-react": "^6.5.0",
32 + "babel-traverse": "^6.9.0",
33 + "babylon": "^6.8.0",
34 "browserify": "^13.0.0",
35 "bundle-collapser": "^1.1.1",
36 "coffee-script": "^1.8.0",
@@ -51,6 +53,7 @@
53 "gulp": "^3.9.0",
54 "gulp-babel": "^6.0.0",
55 "gulp-flatten": "^0.2.0",
56 + "gulp-util": "^3.0.7",
57 "gzip-js": "~0.3.2",
58 "jest": "^12.1.1",
59 "loose-envify": "^1.1.0",
@@ -95,6 +98,7 @@
98 "testPathDirs": [
99 "<rootDir>/eslint-rules",
100 "<rootDir>/mocks",
101 + "<rootDir>/scripts",
102 "<rootDir>/src",
103 "node_modules/fbjs"
104 ],
scripts/error-codes/Types.js new
+13
@@ -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; }; */
scripts/error-codes/__tests__/evalToString-test.js new
+36
@@ -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 +});
scripts/error-codes/__tests__/invertObject-test.js new
+54
@@ -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 new
+138
@@ -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 +}
scripts/error-codes/evalToString.js new
+27
@@ -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;
scripts/error-codes/gulp-extract-errors.js new
+117
@@ -0,0 +1,117 @@
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 babylon = require('babylon');
12 +var fs = require('fs');
13 +var gutil = require('gulp-util');
14 +var path = require('path');
15 +var through = require('through2');
16 +var traverse = require('babel-traverse').default;
17 +
18 +var evalToString = require('./evalToString');
19 +var invertObject = require('./invertObject');
20 +
21 +var PLUGIN_NAME = 'extract-errors';
22 +
23 +var babylonOptions = {
24 + sourceType: 'module',
25 + // As a parser, babylon has its own options and we can't directly
26 + // import/require a babel preset. It should be kept **the same** as
27 + // the `babel-plugin-syntax-*` ones specified in
28 + // https://github.com/facebook/fbjs/blob/master/babel-preset/configure.js
29 + plugins: [
30 + 'classProperties',
31 + 'flow',
32 + 'jsx',
33 + 'trailingFunctionCommas',
34 + 'objectRestSpread',
35 + ],
36 +};
37 +
38 +module.exports = function(opts) {
39 + if (!opts || !('errorMapFilePath' in opts)) {
40 + throw new gutil.PluginError(
41 + PLUGIN_NAME,
42 + 'Missing options. Ensure you pass an object with `errorMapFilePath`.'
43 + );
44 + }
45 +
46 + var errorMapFilePath = opts.errorMapFilePath;
47 + var existingErrorMap;
48 + try {
49 + existingErrorMap = require(
50 + path.join(__dirname, path.basename(errorMapFilePath))
51 + );
52 + } catch (e) {
53 + existingErrorMap = {};
54 + }
55 +
56 + var allErrorIDs = Object.keys(existingErrorMap);
57 + var currentID;
58 +
59 + if (allErrorIDs.length === 0) { // Map is empty
60 + currentID = 0;
61 + } else {
62 + currentID = Math.max.apply(null, allErrorIDs) + 1;
63 + }
64 +
65 + // Here we invert the map object in memory for faster error code lookup
66 + existingErrorMap = invertObject(existingErrorMap);
67 +
68 + function transform(file, enc, cb) {
69 + if (file.isNull()) {
70 + cb(null, file);
71 + return;
72 + }
73 +
74 + if (file.isStream()) {
75 + cb(new gutil.PluginError(PLUGIN_NAME, 'Streaming not supported'));
76 + return;
77 + }
78 +
79 + var source = file.contents.toString();
80 + var ast = babylon.parse(source, babylonOptions);
81 +
82 + traverse(ast, {
83 + CallExpression: {
84 + exit: function(astPath) {
85 + if (astPath.get('callee').isIdentifier({name: 'invariant'})) {
86 + var node = astPath.node;
87 +
88 + // error messages can be concatenated (`+`) at runtime, so here's a
89 + // trivial partial evaluator that interprets the literal value
90 + var errorMsgLiteral = evalToString(node.arguments[1]);
91 + if (existingErrorMap.hasOwnProperty(errorMsgLiteral)) {
92 + return;
93 + }
94 +
95 + existingErrorMap[errorMsgLiteral] = '' + (currentID++);
96 + }
97 + },
98 + },
99 + });
100 +
101 + cb();
102 + }
103 +
104 + function flush(cb) {
105 + fs.writeFile(
106 + errorMapFilePath,
107 + JSON.stringify(invertObject(existingErrorMap), null, 2) + '\n',
108 + 'utf-8',
109 + function() {
110 + // avoid calling cb with fs.write callback data
111 + cb();
112 + }
113 + );
114 + }
115 +
116 + return through.obj(transform, flush);
117 +};
scripts/error-codes/invertObject.js new
+35
@@ -0,0 +1,35 @@
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 +/*:: import type { ErrorMap } from './Types' */
14 +
15 +/**
16 + * turns
17 + * { 'MUCH ERROR': '0', 'SUCH WRONG': '1' }
18 + * into
19 + * { 0: 'MUCH ERROR', 1: 'SUCH WRONG' }
20 + */
21 +function invertObject(targetObj/* : ErrorMap */)/* : ErrorMap */ {
22 + var result = {};
23 + var mapKeys = Object.keys(targetObj);
24 +
25 + for (let i = 0; i < mapKeys.length; i++) {
26 + var originalKey = mapKeys[i];
27 + var originalVal = targetObj[originalKey];
28 +
29 + result[originalVal] = originalKey;
30 + }
31 +
32 + return result;
33 +}
34 +
35 +module.exports = invertObject;