Skip to content

Commit

Permalink
make invariant hygienic again
Browse files Browse the repository at this point in the history
  • Loading branch information
Keyan Zhang committed Jun 3, 2016
1 parent a6d4858 commit 0a2dacf
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 35 deletions.
35 changes: 29 additions & 6 deletions scripts/error-codes/__tests__/dev-expression-with-codes-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@

let babel = require('babel-core');
let devExpressionWithCodes = require('../dev-expression-with-codes');
let prodInvariantName = require('../constants').prodInvariantName;

function transform(input) {
return babel.transform(input, {
Expand Down Expand Up @@ -60,39 +59,63 @@ if (process.env.NODE_ENV !== 'production') {
compare(
"var invariant = require('invariant');",

`var invariant = require('invariant');
`var _prodInvariant = require('reactProdInvariant');
var ${prodInvariantName} = require('reactProdInvariant');`
var invariant = require('invariant');`
);
});

it('should replace simple invariant calls', () => {
compare(
"invariant(condition, 'Do not override existing functions.');",
"var _prodInvariant = require('reactProdInvariant');\n\n" +
"!condition ? " +
"process.env.NODE_ENV !== 'production' ? " +
"invariant(false, 'Do not override existing functions.') : " +
`_prodInvariant('16') : void 0;`
);
});

it("should only add `reactProdInvariant` once", () => {
var expectedInvariantTransformResult = (
"!condition ? " +
"process.env.NODE_ENV !== 'production' ? " +
"invariant(false, 'Do not override existing functions.') : " +
`${prodInvariantName}('16') : void 0;`
`_prodInvariant('16') : void 0;`
);

compare(
`var invariant = require('invariant');
invariant(condition, 'Do not override existing functions.');
invariant(condition, 'Do not override existing functions.');`,

`var _prodInvariant = require('reactProdInvariant');
var invariant = require('invariant');
${expectedInvariantTransformResult}
${expectedInvariantTransformResult}`
);
});

it('should support invariant calls with args', () => {
compare(
"invariant(condition, 'Expected %s target to be an array; got %s', 'foo', 'bar');",
"var _prodInvariant = require('reactProdInvariant');\n\n" +
"!condition ? " +
"process.env.NODE_ENV !== 'production' ? " +
"invariant(false, 'Expected %s target to be an array; got %s', 'foo', 'bar') : " +
`${prodInvariantName}('7', 'foo', 'bar') : void 0;`
`_prodInvariant('7', 'foo', 'bar') : void 0;`
);
});

it('should support invariant calls with a concatenated template string and args', () => {
compare(
"invariant(condition, 'Expected a component class, ' + 'got %s.' + '%s', 'Foo', 'Bar');",
"var _prodInvariant = require('reactProdInvariant');\n\n" +
"!condition ? " +
"process.env.NODE_ENV !== 'production' ? " +
"invariant(false, 'Expected a component class, got %s.%s', 'Foo', 'Bar') : " +
`${prodInvariantName}('18', 'Foo', 'Bar') : void 0;`
`_prodInvariant('18', 'Foo', 'Bar') : void 0;`
);
});

Expand Down
15 changes: 0 additions & 15 deletions scripts/error-codes/constants.js

This file was deleted.

37 changes: 23 additions & 14 deletions scripts/error-codes/dev-expression-with-codes.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,27 @@
var evalToString = require('./evalToString');
var existingErrorMap = require('./codes.json');
var invertObject = require('./invertObject');
var prodInvariantName = require('./constants').prodInvariantName;

var errorMap = invertObject(existingErrorMap);
var prodInvariantModuleName = 'reactProdInvariant';

module.exports = function(babel) {
var t = babel.types;

var SEEN_SYMBOL = Symbol();

var buildRequire = babel.template(`var IMPORT_NAME = require(SOURCE);`);

var REQUIRE_PROD_INVARIANT = buildRequire({
IMPORT_NAME: t.identifier(prodInvariantName),
SOURCE: t.stringLiteral(prodInvariantModuleName),
});
function getProdInvariantId(path, localState) {
if (!localState.id) {
localState.id = path.scope.generateUidIdentifier('prodInvariant');
path.scope.getProgramParent().push({
id: localState.id,
init: t.callExpression(
t.identifier('require'),
[t.stringLiteral('reactProdInvariant')]
),
});
}
return localState.id;
}

var DEV_EXPRESSION = t.binaryExpression(
'!==',
Expand All @@ -43,6 +48,10 @@ module.exports = function(babel) {
);

return {
pre: function() {
this.id = null;
},

visitor: {
Identifier: {
enter: function(path) {
Expand All @@ -63,17 +72,16 @@ module.exports = function(babel) {
if (node[SEEN_SYMBOL]) {
return;
}
// Insert require('reactProdInvariant') after all `require('invariant')`s.
// NOTE currently it only supports the format of
// `var invariant = require('invariant');` (VariableDeclaration)
// and NOT ES6 imports/assignments.
// Insert `var _hygienicVarName = require('reactProdInvariant');`
// before all `require('invariant')`s.
// NOTE it doesn't support ES6 imports yet.
if (
path.get('callee').isIdentifier({name: 'require'}) &&
path.get('arguments')[0] &&
path.get('arguments')[0].isStringLiteral({value: 'invariant'})
) {
node[SEEN_SYMBOL] = true;
path.parentPath.parentPath.insertAfter(REQUIRE_PROD_INVARIANT);
getProdInvariantId(path, this);
} else if (path.get('callee').isIdentifier({name: 'invariant'})) {
// Turns this code:
//
Expand Down Expand Up @@ -129,7 +137,8 @@ module.exports = function(babel) {

devInvariant[SEEN_SYMBOL] = true;

var prodInvariant = t.callExpression(t.identifier(prodInvariantName), [
var localInvariantId = getProdInvariantId(path, this);
var prodInvariant = t.callExpression(localInvariantId, [
t.stringLiteral(prodErrorId),
].concat(node.arguments.slice(2)));

Expand Down

0 comments on commit 0a2dacf

Please sign in to comment.