1const visited = 'visitedByInvariantWarningTransformer';
2
3const warningDevCheckTemplate = `
4 if (process.env.NODE_ENV !== 'production') {
5 NODE;
6 }
7`.trim();
8
9const plugin = ({ template, types: t }) => {
10 const wrapWithDevCheck = template(warningDevCheckTemplate, {
11 placeholderPattern: /^NODE$/,
12 });
13
14 return {
15 visitor: {
16 CallExpression(path) {
17 const { name } = path.node.callee;
18 if (
19 (name === 'warn' || name === 'deprecationWarning') &&
20 !path.node[visited]
21 ) {
22 path.node[visited] = true;
23
24 // The production-check may be hoisted if the parent
25 // is already an if-statement only containing the
26 // warn call
27 let p = path;
28 while (t.isExpressionStatement(p.parentPath.node)) {
29 if (
30 t.isBlockStatement(p.parentPath.parentPath.node) &&
31 p.parentPath.parentPath.node.body.length === 1 &&
32 p.parentPath.parentPath.node.body[0] === path.parentPath.node &&
33 t.isIfStatement(p.parentPath.parentPath.parentPath.node) &&
34 p.parentPath.parentPath.parentPath.node.consequent ===
35 p.parentPath.parentPath.node &&
36 !p.parentPath.parentPath.node.alternate
37 ) {
38 p = p.parentPath.parentPath.parentPath;
39 } else if (
40 t.isIfStatement(p.parentPath.parentPath.node) &&
41 p.parentPath.parentPath.node.consequent === p.parentPath.node &&
42 !p.parentPath.parentPath.node.alternate
43 ) {
44 p = path.parentPath.parentPath;
45 } else {
46 break;
47 }
48 }
49
50 p.replaceWith(wrapWithDevCheck({ NODE: p.node }));
51 } else if (name === 'invariant' && !path.node[visited]) {
52 path.node[visited] = true;
53 const formerNode = path.node.arguments[1];
54 path.node.arguments[1] = t.conditionalExpression(
55 t.binaryExpression(
56 '!==',
57 t.memberExpression(
58 t.memberExpression(
59 t.identifier('process'),
60 t.identifier('env')
61 ),
62 t.identifier('NODE_ENV')
63 ),
64 t.stringLiteral('production')
65 ),
66 formerNode,
67 t.stringLiteral('')
68 );
69 }
70 },
71 },
72 };
73};
74
75export default plugin;