UNPKG

7.35 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, '__esModule', { value: true });
4
5// the same as before
6var PREFIX = '__reactstandin__';
7var REGENERATE_METHOD = PREFIX + 'regenerateByEval';
8
9var templateOptions = {
10 placeholderPattern: /^([A-Z0-9]+)([A-Z0-9_]+)$/
11};
12
13/* eslint-disable */
14var shouldIgnoreFile = function shouldIgnoreFile(file) {
15 return !!file.split('\\').join('/').match(/node_modules\/(react|react-hot-loader)([\/]|$)/);
16};
17/* eslint-enable */
18
19module.exports = function plugin(args) {
20 var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
21
22 // This is a Babel plugin, but the user put it in the Webpack config.
23 if (this && this.callback) {
24 throw new Error('React Hot Loader: You are erroneously trying to use a Babel plugin ' + 'as a Webpack loader. We recommend that you use Babel, ' + 'remove "react-hot-loader/babel" from the "loaders" section ' + 'of your Webpack configuration, and instead add ' + '"react-hot-loader/babel" to the "plugins" section of your .babelrc file. ' + 'If you prefer not to use Babel, replace "react-hot-loader/babel" with ' + '"react-hot-loader/webpack" in the "loaders" section of your Webpack configuration. ');
25 }
26 var t = args.types,
27 template = args.template;
28 var _options$safetyNet = options.safetyNet,
29 safetyNet = _options$safetyNet === undefined ? true : _options$safetyNet;
30
31
32 var buildRegistration = template('reactHotLoader.register(ID, NAME, FILENAME);', templateOptions);
33 var headerTemplate = template('(function () {\n var enterModule = (typeof reactHotLoaderGlobal !== \'undefined\' ? reactHotLoaderGlobal : require(\'react-hot-loader\')).enterModule;\n enterModule && enterModule(module);\n }())', templateOptions);
34 var footerTemplate = template('(function () {\n var leaveModule = (typeof reactHotLoaderGlobal !== \'undefined\' ? reactHotLoaderGlobal : require(\'react-hot-loader\')).leaveModule;\n leaveModule && leaveModule(module);\n }())', templateOptions);
35 var evalTemplate = template('this[key]=eval(code);', templateOptions);
36
37 // We're making the IIFE we insert at the end of the file an unused variable
38 // because it otherwise breaks the output of the babel-node REPL (#359).
39
40 var buildTagger = template(' \n(function () { \n \n var reactHotLoader = (typeof reactHotLoaderGlobal !== \'undefined\' ?reactHotLoaderGlobal : require(\'react-hot-loader\')).default;\n \n if (!reactHotLoader) {\n return;\n }\n\n REGISTRATIONS \n}());\n ', templateOptions);
41
42 // Gather top-level variables, functions, and classes.
43 // Try our best to avoid variables from require().
44 // Ideally we only want to find components defined by the user.
45 function shouldRegisterBinding(binding) {
46 var _binding$path = binding.path,
47 type = _binding$path.type,
48 node = _binding$path.node;
49
50 switch (type) {
51 case 'FunctionDeclaration':
52 case 'ClassDeclaration':
53 case 'VariableDeclaration':
54 return true;
55 case 'VariableDeclarator':
56 {
57 var init = node.init;
58
59 if (t.isCallExpression(init) && init.callee.name === 'require') {
60 return false;
61 }
62 return true;
63 }
64 default:
65 return false;
66 }
67 }
68
69 var REGISTRATIONS = Symbol('registrations');
70 return {
71 visitor: {
72 ExportDefaultDeclaration: function ExportDefaultDeclaration(path, state) {
73 var file = state.file;
74 // Default exports with names are going
75 // to be in scope anyway so no need to bother.
76
77 if (path.node.declaration.id) {
78 return;
79 }
80
81 // Move export default right hand side to a variable
82 // so we can later refer to it and tag it with __source.
83 var id = path.scope.generateUidIdentifier('default');
84 var expression = t.isExpression(path.node.declaration) ? path.node.declaration : t.toExpression(path.node.declaration);
85 path.insertBefore(t.variableDeclaration('const', [t.variableDeclarator(id, expression)]));
86 path.node.declaration = id; // eslint-disable-line no-param-reassign
87
88 // It won't appear in scope.bindings
89 // so we'll manually remember it exists.
90 state[REGISTRATIONS].push(buildRegistration({
91 ID: id,
92 NAME: t.stringLiteral('default'),
93 FILENAME: t.stringLiteral(file.opts.filename)
94 }));
95 },
96
97
98 Program: {
99 enter: function enter(_ref, state) {
100 var scope = _ref.scope;
101 var file = state.file;
102
103 state[REGISTRATIONS] = []; // eslint-disable-line no-param-reassign
104
105 // Everything in the top level scope, when reasonable,
106 // is going to get tagged with __source.
107 /* eslint-disable guard-for-in,no-restricted-syntax */
108 for (var id in scope.bindings) {
109 var binding = scope.bindings[id];
110 if (shouldRegisterBinding(binding)) {
111 state[REGISTRATIONS].push(buildRegistration({
112 ID: binding.identifier,
113 NAME: t.stringLiteral(id),
114 FILENAME: t.stringLiteral(file.opts.filename)
115 }));
116 }
117 }
118 /* eslint-enable */
119 },
120 exit: function exit(_ref2, state) {
121 var node = _ref2.node;
122 var file = state.file;
123
124 var registrations = state[REGISTRATIONS];
125 state[REGISTRATIONS] = [];
126
127 // inject the code only if applicable
128 if (registrations && registrations.length && !shouldIgnoreFile(file.opts.filename)) {
129 if (safetyNet) {
130 node.body.unshift(headerTemplate());
131 }
132 // Inject the generated tagging code at the very end
133 // so that it is as minimally intrusive as possible.
134 node.body.push(t.emptyStatement());
135 node.body.push(buildTagger({ REGISTRATIONS: registrations }));
136 node.body.push(t.emptyStatement());
137
138 if (safetyNet) {
139 node.body.push(footerTemplate());
140 }
141 }
142 }
143 },
144 Class: function Class(classPath) {
145 var classBody = classPath.get('body');
146 var hasRegenerateMethod = false;
147 var hasMethods = false;
148
149 classBody.get('body').forEach(function (path) {
150 var node = path.node;
151
152 // don't apply transform to static class properties
153
154 if (node.static) {
155 return;
156 }
157
158 if (node.key.name !== REGENERATE_METHOD) {
159 hasMethods = true;
160 } else {
161 hasRegenerateMethod = true;
162 }
163 });
164
165 if (hasMethods && !hasRegenerateMethod) {
166 var regenerateMethod = t.classMethod('method', t.identifier(REGENERATE_METHOD), [t.identifier('key'), t.identifier('code')], t.blockStatement([evalTemplate()]));
167
168 classBody.pushContainer('body', regenerateMethod);
169
170 classBody.get('body').forEach(function (path) {
171 var node = path.node;
172
173
174 if (node.key.name === REGENERATE_METHOD) {
175 path.addComment('leading', ' @ts-ignore', true);
176 path.get('body').get('body')[0].addComment('leading', ' @ts-ignore', true);
177 }
178 });
179 }
180 }
181 }
182 };
183};
184
185module.exports.shouldIgnoreFile = shouldIgnoreFile;