@samitouri / QOS-React-2 / commits / 31a025a667

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 +};