Skip to content

Commit 9e58266

Browse files
committed
Merge pull request react#1802 from zpao/jsxtransformer-cleanup
Jsxtransformer cleanup
2 parents 61d4954 + 31a025a commit 9e58266

1 file changed

Lines changed: 128 additions & 46 deletions

File tree

vendor/browser-transforms.js

Lines changed: 128 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -17,23 +17,33 @@
1717
/* jslint evil: true */
1818

1919
'use strict';
20-
var runScripts;
21-
var loadScripts;
22-
var headEl;
23-
var dummyAnchor;
2420

2521
var buffer = require('buffer');
22+
var docblock = require('jstransform/src/docblock');
2623
var transform = require('jstransform').transform;
2724
var visitors = require('./fbtransform/visitors');
28-
var docblock = require('jstransform/src/docblock');
25+
26+
var runScripts;
27+
var loadScripts;
28+
var headEl;
29+
var dummyAnchor;
30+
var inlineScriptCount = 0;
2931

3032
// The source-map library relies on Object.defineProperty, but IE8 doesn't
3133
// support it fully even with es5-sham. Indeed, es5-sham's defineProperty
3234
// throws when Object.prototype.__defineGetter__ is missing, so we skip building
3335
// the source map in that case.
3436
var supportsAccessors = Object.prototype.hasOwnProperty('__defineGetter__');
3537

38+
/**
39+
* Run provided code through jstransform.
40+
*
41+
* @param {string} source Original source code
42+
* @param {object?} options Options to pass to jstransform
43+
* @return {object} object as returned from jstransform
44+
*/
3645
function transformReact(source, options) {
46+
// TODO: just use react-tools
3747
var visitorList;
3848
if (options && options.harmony) {
3949
visitorList = visitors.getAllVisitors();
@@ -46,23 +56,31 @@ function transformReact(source, options) {
4656
});
4757
}
4858

49-
exports.transform = transformReact;
50-
51-
exports.exec = function(code, options) {
52-
return eval(transformReact(code, options).code);
53-
};
54-
55-
var inlineScriptCount = 0;
59+
/**
60+
* Eval provided source after transforming it.
61+
*
62+
* @param {string} source Original source code
63+
* @param {object?} options Options to pass to jstransform
64+
*/
65+
function exec(source, options) {
66+
return eval(transformReact(source, options).code);
67+
}
5668

57-
// This method returns a nicely formated line of code pointing the
58-
// exactly location of the error `e`.
59-
// The line is limited in size so big lines of code are also shown
60-
// in a readable way.
61-
// Example:
62-
//
63-
// ... x', overflow:'scroll'}} id={} onScroll={this.scroll} class=" ...
64-
// ^
65-
var createSourceCodeErrorMessage = function(code, e) {
69+
/**
70+
* This method returns a nicely formated line of code pointing to the exact
71+
* location of the error `e`. The line is limited in size so big lines of code
72+
* are also shown in a readable way.
73+
*
74+
* Example:
75+
* ... x', overflow:'scroll'}} id={} onScroll={this.scroll} class=" ...
76+
* ^
77+
*
78+
* @param {string} code The full string of code
79+
* @param {Error} e The error being thrown
80+
* @return {string} formatted message
81+
* @internal
82+
*/
83+
function createSourceCodeErrorMessage(code, e) {
6684
var sourceLines = code.split('\n');
6785
var erroneousLine = sourceLines[e.lineNumber - 1];
6886

@@ -89,24 +107,33 @@ var createSourceCodeErrorMessage = function(code, e) {
89107
var message = '\n\n' + erroneousLine + '\n';
90108
message += new Array(errorColumn - 1).join(' ') + '^';
91109
return message;
92-
};
110+
}
93111

94-
var transformCode = function(code, source, options) {
112+
/**
113+
* Actually transform the code.
114+
*
115+
* @param {string} code
116+
* @param {string?} url
117+
* @param {object?} options
118+
* @return {string} The transformed code.
119+
* @internal
120+
*/
121+
function transformCode(code, url, options) {
95122
var jsx = docblock.parseAsObject(docblock.extract(code)).jsx;
96123

97124
if (jsx) {
98125
try {
99126
var transformed = transformReact(code, options);
100127
} catch(e) {
101128
e.message += '\n at ';
102-
if (source) {
129+
if (url) {
103130
if ('fileName' in e) {
104131
// We set `fileName` if it's supported by this error object and
105-
// a `source` was provided.
106-
// The error will correctly point to `source` in Firefox.
107-
e.fileName = source;
132+
// a `url` was provided.
133+
// The error will correctly point to `url` in Firefox.
134+
e.fileName = url;
108135
}
109-
e.message += source + ':' + e.lineNumber + ':' + e.column;
136+
e.message += url + ':' + e.lineNumber + ':' + e.column;
110137
} else {
111138
e.message += location.href;
112139
}
@@ -119,7 +146,8 @@ var transformCode = function(code, source, options) {
119146
}
120147

121148
var map = transformed.sourceMap.toJSON();
122-
if (source == null) {
149+
var source;
150+
if (url == null) {
123151
source = "Inline JSX script";
124152
inlineScriptCount++;
125153
if (inlineScriptCount > 1) {
@@ -130,7 +158,7 @@ var transformCode = function(code, source, options) {
130158
// protocol and hostname, so use the pathname. We could use just the
131159
// filename, but hopefully using the full path will prevent potential
132160
// issues where the same filename exists in multiple directories.
133-
dummyAnchor.href = source;
161+
dummyAnchor.href = url;
134162
source = dummyAnchor.pathname.substr(1);
135163
}
136164
map.sources = [source];
@@ -142,17 +170,37 @@ var transformCode = function(code, source, options) {
142170
buffer.Buffer(JSON.stringify(map)).toString('base64')
143171
);
144172
} else {
173+
// TODO: warn that we found a script tag missing the docblock?
174+
// or warn and proceed anyway?
175+
// or warn, add it ourselves, and proceed anyway?
145176
return code;
146177
}
147-
};
178+
}
179+
148180

149-
var run = exports.run = function(code, source, options) {
181+
/**
182+
* Appends a script element at the end of the <head> with the content of code,
183+
* after transforming it.
184+
*
185+
* @param {string} code The original source code
186+
* @param {string?} url Where the code came from. null if inline
187+
* @param {object?} options Options to pass to jstransform
188+
* @internal
189+
*/
190+
function run(code, url, options) {
150191
var scriptEl = document.createElement('script');
151-
scriptEl.text = transformCode(code, source, options);
192+
scriptEl.text = transformCode(code, url, options);
152193
headEl.appendChild(scriptEl);
153-
};
194+
}
154195

155-
var load = exports.load = function(url, callback) {
196+
/**
197+
* Load script from the provided url and pass the content to the callback.
198+
*
199+
* @param {string} url The location of the script src
200+
* @param {function} callback Function to call with the content of url
201+
* @internal
202+
*/
203+
function load(url, callback) {
156204
var xhr;
157205
xhr = window.ActiveXObject ? new window.ActiveXObject('Microsoft.XMLHTTP')
158206
: new XMLHttpRequest();
@@ -173,15 +221,23 @@ var load = exports.load = function(url, callback) {
173221
}
174222
};
175223
return xhr.send(null);
176-
};
224+
}
177225

178-
loadScripts = function(scripts) {
226+
/**
227+
* Loop over provided script tags and get the content, via innerHTML if an
228+
* inline script, or by using XHR. Transforms are applied if needed. The scripts
229+
* are executed in the order they are found on the page.
230+
*
231+
* @param {array} scripts The <script> elements to load and run.
232+
* @internal
233+
*/
234+
function loadScripts(scripts) {
179235
var result = scripts.map(function() {
180236
return false;
181237
});
182238
var count = result.length;
183239

184-
var check = function() {
240+
function check() {
185241
var script, i;
186242

187243
for (i = 0; i < count; i++) {
@@ -193,8 +249,8 @@ loadScripts = function(scripts) {
193249
} else if (!script) {
194250
break;
195251
}
196-
};
197-
};
252+
}
253+
}
198254

199255
scripts.forEach(function(script, i) {
200256
var options;
@@ -206,17 +262,32 @@ loadScripts = function(scripts) {
206262

207263
if (script.src) {
208264
load(script.src, function(content, url) {
209-
result[i] = { executed: false, content: content, url: url, options: options };
265+
result[i] = {
266+
executed: false,
267+
content: content,
268+
url: url,
269+
options: options
270+
};
210271
check();
211272
});
212273
} else {
213-
result[i] = { executed: false, content: script.innerHTML, url: null, options: options };
274+
result[i] = {
275+
executed: false,
276+
content: script.innerHTML,
277+
url: null,
278+
options: options
279+
};
214280
check();
215281
}
216282
});
217-
};
283+
}
218284

219-
runScripts = function() {
285+
/**
286+
* Find and run all script tags with type="text/jsx".
287+
*
288+
* @internal
289+
*/
290+
function runScripts() {
220291
var scripts = document.getElementsByTagName('script');
221292

222293
// Array.prototype.slice cannot be used on NodeList on IE8
@@ -227,11 +298,17 @@ runScripts = function() {
227298
}
228299
}
229300

230-
console.warn("You are using the in-browser JSX transformer. Be sure to precompile your JSX for production - http://facebook.github.io/react/docs/tooling-integration.html#jsx");
301+
console.warn(
302+
'You are using the in-browser JSX transformer. Be sure to precompile ' +
303+
'your JSX for production - ' +
304+
'http://facebook.github.io/react/docs/tooling-integration.html#jsx'
305+
);
231306

232307
loadScripts(jsxScripts);
233-
};
308+
}
234309

310+
// Listen for load event if we're in a browser and then kick off finding and
311+
// running of scripts.
235312
if (typeof window !== "undefined" && window !== null) {
236313
headEl = document.getElementsByTagName('head')[0];
237314
dummyAnchor = document.createElement('a');
@@ -242,3 +319,8 @@ if (typeof window !== "undefined" && window !== null) {
242319
window.attachEvent('onload', runScripts);
243320
}
244321
}
322+
323+
module.exports = {
324+
transform: transformReact,
325+
exec: exec
326+
};

0 commit comments

Comments
 (0)