@@ -6,15 +6,16 @@ var fs = require("fs");
66var acorn = require ( "acorn" ) ;
77
88var file = process . argv [ 2 ] ;
9+ var chapNum = Number ( file . match ( / ^ \d * / ) [ 0 ] ) ;
910var input = fs . readFileSync ( file , "utf8" ) ;
1011
11- var code = "var alert = function() {}, prompt = function() { return 'x'; }, confirm = function() { return true; }; window = this;\n" ;
12+ var baseCode = "var alert = function() {}, prompt = function() { return 'x'; }, confirm = function() { return true; }; window = this; requestAnimationFrame = setTimeout = clearTimeout = setInterval = clearInterval = Math.min ;\n" ;
1213
1314var include = / \n : l o a d _ f i l e s : ( \[ [ ^ \] ] + \] ) / . exec ( input ) ;
1415if ( include ) JSON . parse ( include [ 1 ] ) . forEach ( function ( fileName ) {
1516 var text = fs . readFileSync ( "html/" + fileName ) ;
1617 if ( ! / \/ \/ t e s t : n o / . test ( text ) )
17- code += text ;
18+ baseCode += text ;
1819} ) ;
1920
2021function wrapTestOutput ( snippet , config ) {
@@ -36,12 +37,27 @@ function pos(index) {
3637 return "line " + ( input . slice ( 0 , index ) . split ( "\n" ) . length + 1 ) ;
3738}
3839
39- var re = / ( (?: \/ \/ .* \n | \s ) * ) (?: [ s a n d b o x = . * \n ) ? \[ s o u r c e , j a v a s c r i p t \] \n - - - - \n ( [ \s \S ] * ?\n ) - - - - / g, m ;
40+ var sandboxes = { } , anonId = 0 ;
41+
42+ var re = / ( (?: \/ \/ .* \n | \s ) * ) (?: \[ s a n d b o x = " ( [ ^ " ] * ) " \] \n ) ? \[ s o u r c e , ( [ ^ \] ] + ) \] \n - - - - \n ( [ \s \S ] * ?\n ) - - - - / g, m ;
4043while ( m = re . exec ( input ) ) {
41- var snippet = m [ 2 ] , hasConf = m [ 1 ] . match ( / \/ \/ t e s t : ( .* ) / ) , config = hasConf ? hasConf [ 1 ] : "" ;
44+ var snippet = m [ 4 ] , hasConf = m [ 1 ] . match ( / \/ \/ t e s t : ( .* ) / ) ;
45+ var sandbox = m [ 2 ] || "null" , type = m [ 3 ] , config = hasConf ? hasConf [ 1 ] : "" ;
4246 var where = pos ( m . index ) ;
47+
48+ if ( type != "javascript" && type != "text/html" ) continue ;
49+
50+ var boxId = m [ 2 ] || ( type == "javascript" ? "null" : "box" + ( ++ anonId ) ) ;
51+ var sandbox = sandboxes [ boxId ] ;
52+ if ( ! sandbox )
53+ sandbox = sandboxes [ boxId ] = { code : "" } ;
54+
55+ if ( type == "text/html" ) {
56+ var stripped = stripHTML ( snippet ) ;
57+ snippet = stripped . javascript ;
58+ }
4359 try {
44- acorn . parse ( snippet , { strictSemicolons : ! / 0 1 _ v a l u e / . test ( file ) } ) ;
60+ acorn . parse ( snippet , { strictSemicolons : chapNum != 1 } ) ;
4561 } catch ( e ) {
4662 console . log ( "parse error at " + where + ": " + e . toString ( ) ) ;
4763 }
@@ -50,8 +66,28 @@ while (m = re.exec(input)) {
5066 else if ( / \/ \/ → / . test ( snippet ) ) snippet = wrapTestOutput ( snippet , config ) ;
5167 if ( / \b w r a p \b / . test ( config ) ) snippet = "(function(){\n" + snippet + "}());\n" ;
5268
53- code += "console.pos = " + JSON . stringify ( where ) + ";\n" ;
54- code += snippet ;
69+ if ( type == "text/html" ) {
70+ if ( sandbox . html ) console . log ( "Double HTML for box " + boxId ) ;
71+ sandbox . html = stripped . html ;
72+ sandbox . code = stripped . included + "console.pos = " + JSON . stringify ( where ) + ";\n" + snippet + sandbox . code ;
73+ } else {
74+ sandbox . code += "console.pos = " + JSON . stringify ( where ) + ";\n" ;
75+ sandbox . code += snippet ;
76+ }
77+ }
78+
79+ function stripHTML ( code ) {
80+ var included = "" , script = "" ;
81+ code = code . replace ( / < s c r i p t \b [ ^ > ] * ?(?: \b s r c \s * = \s * ( ' [ ^ ' ] + ' | " [ ^ " ] + " | [ ^ \s > ] + ) [ ^ > ] * ) ? > ( [ \s \S ] * ?) < \/ s c r i p t > / , function ( m , src , content ) {
82+ if ( src ) {
83+ if ( / [ " ' ] / . test ( src . charAt ( 0 ) ) ) src = src . slice ( 1 , src . length - 1 ) ;
84+ included += fs . readFileSync ( "html/" + src , "utf8" ) ;
85+ } else {
86+ script += content ;
87+ }
88+ return "" ;
89+ } ) ;
90+ return { html : code , included : included , javascript : script } ;
5591}
5692
5793function represent ( val ) {
@@ -136,6 +172,7 @@ var accum = "", _console = {
136172 var clip = string . indexOf ( "…" ) , ok = false ;
137173 if ( / \b t r a i l i n g \b / . test ( config ) ) accum = accum . replace ( / \s + ( \n | $ ) / g, "$1" ) ;
138174 if ( / \b t r i m \b / . test ( config ) ) { accum = accum . trim ( ) ; string = string . trim ( ) ; }
175+ if ( / \b n o n u m b e r s \b / . test ( config ) ) { accum = accum . replace ( / \d / g, "" ) ; string = string . replace ( / \d / g, "" ) ; }
139176 if ( / \b c l i p \b / . test ( config ) ) ok = compareClipped ( string , accum ) ;
140177 else if ( / \b j o i n \b / . test ( config ) ) ok = compareJoined ( string , accum ) ;
141178 else if ( clip > - 1 ) ok = string . slice ( 0 , clip ) == accum . slice ( 0 , clip ) ;
@@ -145,7 +182,6 @@ var accum = "", _console = {
145182 } ,
146183 missingErr : function ( ) {
147184 console . log ( "expected error not raised at " + this . pos ) ;
148- console . log ( code ) ;
149185 } ,
150186 compareErr : function ( err , string ) {
151187 if ( err . toString ( ) != string )
@@ -154,8 +190,41 @@ var accum = "", _console = {
154190 pos : null
155191} ;
156192
157- try {
158- ( new Function ( "console" , code ) ) ( _console ) ;
159- } catch ( e ) {
160- console . log ( "error raised (" + _console . pos + "): " + e . toString ( ) ) ;
193+ function report ( err ) {
194+ var msg = err . toString ( ) ;
195+ if ( / ^ \[ o b j e c t / . test ( msg ) && err . message ) msg = err . message ;
196+ console . log ( "error raised (" + _console . pos + "): " + msg , err . stack ) ;
197+ }
198+
199+ var i = 0 , boxes = Object . keys ( sandboxes ) . map ( function ( k ) { return sandboxes [ k ] ; } ) ; ;
200+ function nextSandbox ( ) {
201+ if ( i == boxes . length ) return ;
202+ var sandbox = boxes [ i ] ;
203+ i ++ ;
204+ if ( chapNum < 12 ) { // Language-only
205+ try {
206+ ( new Function ( "console" , baseCode + sandbox . code ) ) ( _console ) ;
207+ nextSandbox ( ) ;
208+ } catch ( e ) {
209+ report ( e ) ;
210+ }
211+ } else {
212+ require ( "jsdom" ) . env ( {
213+ url : file + "/" + i ,
214+ html : sandbox . html || "<!doctype html><body></body>" ,
215+ src : [ baseCode ] ,
216+ done : function ( err , window ) {
217+ if ( err ) report ( err [ 0 ] ) ;
218+ window . console = _console ;
219+ window . Element . prototype . innerText = "abc" ;
220+ try {
221+ window . run ( sandbox . code , file + "/" + i ) ;
222+ } catch ( e ) {
223+ report ( e ) ;
224+ }
225+ nextSandbox ( ) ;
226+ }
227+ } ) ;
228+ }
161229}
230+ nextSandbox ( ) ;
0 commit comments