1717/* jslint evil: true */
1818
1919'use strict' ;
20- var runScripts ;
21- var loadScripts ;
22- var headEl ;
23- var dummyAnchor ;
2420
2521var buffer = require ( 'buffer' ) ;
22+ var docblock = require ( 'jstransform/src/docblock' ) ;
2623var transform = require ( 'jstransform' ) . transform ;
2724var 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.
3436var 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+ */
3645function 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.
235312if ( 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