Add docblocks and consistent styling to JSXTransformer
Paul O’Shannessy committed
Jul 9, 2014 at 11:49 UTC
31a025a667880da45b75e3ede37fcb5056c267ac
1 file changed
+128
-46
vendor/browser-transforms.js
+128
-46
@@ -17,15 +17,17 @@
17
/* jslint evil: true */
18
19
'use strict';
20
-var runScripts;
21
-var loadScripts;
22
-var headEl;
23
-var dummyAnchor;
20
21
var buffer = require('buffer');
22
+var docblock = require('jstransform/src/docblock');
23
var transform = require('jstransform').transform;
24
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;
31
32
// The source-map library relies on Object.defineProperty, but IE8 doesn't
33
// support it fully even with es5-sham. Indeed, es5-sham's defineProperty
@@ -33,7 +35,15 @@ var docblock = require('jstransform/src/docblock');
35
// the source map in that case.
36
var supportsAccessors = Object.prototype.hasOwnProperty('__defineGetter__');
37
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
+ */
45
function transformReact(source, options) {
46
+ // TODO: just use react-tools
47
var visitorList;
48
if (options && options.harmony) {
49
visitorList = visitors.getAllVisitors();
@@ -46,23 +56,31 @@ function transformReact(source, options) {
56
});
57
}
58
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
+}
68
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) {
84
var sourceLines = code.split('\n');
85
var erroneousLine = sourceLines[e.lineNumber - 1];
86
@@ -89,9 +107,18 @@ var createSourceCodeErrorMessage = function(code, e) {
107
var message = '\n\n' + erroneousLine + '\n';
108
message += new Array(errorColumn - 1).join(' ') + '^';
109
return message;
92
-};
110
+}
111
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) {
122
var jsx = docblock.parseAsObject(docblock.extract(code)).jsx;
123
124
if (jsx) {
@@ -99,14 +126,14 @@ var transformCode = function(code, source, options) {
126
var transformed = transformReact(code, options);
127
} catch(e) {
128
e.message += '\n at ';
102
- if (source) {
129
+ if (url) {
130
if ('fileName' in e) {
131
// 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;
135
}
109
- e.message += source + ':' + e.lineNumber + ':' + e.column;
136
+ e.message += url + ':' + e.lineNumber + ':' + e.column;
137
} else {
138
e.message += location.href;
139
}
@@ -119,7 +146,8 @@ var transformCode = function(code, source, options) {
146
}
147
148
var map = transformed.sourceMap.toJSON();
122
- if (source == null) {
149
+ var source;
150
+ if (url == null) {
151
source = "Inline JSX script";
152
inlineScriptCount++;
153
if (inlineScriptCount > 1) {
@@ -130,7 +158,7 @@ var transformCode = function(code, source, options) {
158
// protocol and hostname, so use the pathname. We could use just the
159
// filename, but hopefully using the full path will prevent potential
160
// issues where the same filename exists in multiple directories.
133
- dummyAnchor.href = source;
161
+ dummyAnchor.href = url;
162
source = dummyAnchor.pathname.substr(1);
163
}
164
map.sources = [source];
@@ -142,17 +170,37 @@ var transformCode = function(code, source, options) {
170
buffer.Buffer(JSON.stringify(map)).toString('base64')
171
);
172
} 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?
176
return code;
177
}
147
-};
178
+}
179
+
180
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) {
191
var scriptEl = document.createElement('script');
151
- scriptEl.text = transformCode(code, source, options);
192
+ scriptEl.text = transformCode(code, url, options);
193
headEl.appendChild(scriptEl);
153
-};
194
+}
195
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) {
204
var xhr;
205
xhr = window.ActiveXObject ? new window.ActiveXObject('Microsoft.XMLHTTP')
206
: new XMLHttpRequest();
@@ -173,15 +221,23 @@ var load = exports.load = function(url, callback) {
221
}
222
};
223
return xhr.send(null);
176
-};
224
+}
225
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) {
235
var result = scripts.map(function() {
236
return false;
237
});
238
var count = result.length;
239
184
- var check = function() {
240
+ function check() {
241
var script, i;
242
243
for (i = 0; i < count; i++) {
@@ -193,8 +249,8 @@ loadScripts = function(scripts) {
249
} else if (!script) {
250
break;
251
}
196
- };
197
- };
252
+ }
253
+ }
254
255
scripts.forEach(function(script, i) {
256
var options;
@@ -206,17 +262,32 @@ loadScripts = function(scripts) {
262
263
if (script.src) {
264
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
+ };
271
check();
272
});
273
} 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
+ };
280
check();
281
}
282
});
217
-};
283
+}
284
219
-runScripts = function() {
285
+/**
286
+ * Find and run all script tags with type="text/jsx".
287
+ *
288
+ * @internal
289
+ */
290
+function runScripts() {
291
var scripts = document.getElementsByTagName('script');
292
293
// Array.prototype.slice cannot be used on NodeList on IE8
@@ -227,11 +298,17 @@ runScripts = function() {
298
}
299
}
300
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
+ );
306
307
loadScripts(jsxScripts);
233
-};
308
+}
309
310
+// Listen for load event if we're in a browser and then kick off finding and
311
+// running of scripts.
312
if (typeof window !== "undefined" && window !== null) {
313
headEl = document.getElementsByTagName('head')[0];
314
dummyAnchor = document.createElement('a');
@@ -242,3 +319,8 @@ if (typeof window !== "undefined" && window !== null) {
319
window.attachEvent('onload', runScripts);
320
}
321
}
322
+
323
+module.exports = {
324
+ transform: transformReact,
325
+ exec: exec
326
+};