@@ -62,6 +62,14 @@ export interface CompileParameter {
6262 is_private ?: boolean ;
6363 "compiler-info" ?: CompilerInfo ;
6464}
65+ /**
66+ * Represents a single line in the ndjson response from /api/compile.ndjson
67+ */
68+ export interface CompileNdjsonResult {
69+ type : string ;
70+ data : string ;
71+ }
72+
6573export interface CompileResult {
6674 status : string ;
6775 signal : string ;
@@ -93,17 +101,15 @@ interface CompileProps {
93101 codes : Code [ ] ;
94102}
95103export interface CompileResultWithOutput extends CompileResult {
96- compilerOutput : ReplOutput [ ] ;
97- compilerError : ReplOutput [ ] ;
98- programOutput : ReplOutput [ ] ;
99- programError : ReplOutput [ ] ;
104+ output : ReplOutput [ ] ;
100105}
101106
102107export async function compileAndRun (
103108 options : CompileProps
104109) : Promise < CompileResultWithOutput > {
105- const result : CompileResult = await fetch (
106- new URL ( "/api/compile.json" , WANDBOX ) ,
110+ // Call the ndjson API instead of json API
111+ const response = await fetch (
112+ new URL ( "/api/compile.ndjson" , WANDBOX ) ,
107113 {
108114 method : "post" ,
109115 headers : {
@@ -121,32 +127,124 @@ export async function compileAndRun(
121127 is_private : true ,
122128 } satisfies CompileParameter ) ,
123129 }
124- ) . then ( ( res ) => res . json ( ) ) ;
130+ ) ;
131+
132+ if ( ! response . ok ) {
133+ throw new Error ( `HTTP error! status: ${ response . status } ` ) ;
134+ }
135+
136+ // Read the ndjson response as a stream
137+ const reader = response . body ?. getReader ( ) ;
138+ if ( ! reader ) {
139+ throw new Error ( "Response body is not readable" ) ;
140+ }
141+
142+ const decoder = new TextDecoder ( ) ;
143+ let buffer = "" ;
144+ const ndjsonResults : CompileNdjsonResult [ ] = [ ] ;
145+
146+ try {
147+ while ( true ) {
148+ const { done, value } = await reader . read ( ) ;
149+ if ( done ) break ;
150+
151+ buffer += decoder . decode ( value , { stream : true } ) ;
152+ const lines = buffer . split ( "\n" ) ;
153+
154+ // Keep the last incomplete line in the buffer
155+ buffer = lines . pop ( ) || "" ;
156+
157+ for ( const line of lines ) {
158+ if ( line . trim ( ) . length > 0 ) {
159+ ndjsonResults . push ( JSON . parse ( line ) as CompileNdjsonResult ) ;
160+ }
161+ }
162+ }
163+
164+ // Process any remaining data in the buffer
165+ if ( buffer . trim ( ) . length > 0 ) {
166+ ndjsonResults . push ( JSON . parse ( buffer ) as CompileNdjsonResult ) ;
167+ }
168+ } finally {
169+ reader . releaseLock ( ) ;
170+ }
171+
172+ // Merge ndjson results into a CompileResult (same logic as Rust merge_compile_result)
173+ const result : CompileResult = {
174+ status : "" ,
175+ signal : "" ,
176+ compiler_output : "" ,
177+ compiler_error : "" ,
178+ compiler_message : "" ,
179+ program_output : "" ,
180+ program_error : "" ,
181+ program_message : "" ,
182+ permlink : "" ,
183+ url : "" ,
184+ } ;
185+
186+ // Build output array in the order messages are received
187+ const output : ReplOutput [ ] = [ ] ;
188+
189+ for ( const r of ndjsonResults ) {
190+ switch ( r . type ) {
191+ case "Control" :
192+ // Ignore control messages
193+ break ;
194+ case "CompilerMessageS" :
195+ result . compiler_output += r . data ;
196+ result . compiler_message += r . data ;
197+ // Add to output in order
198+ if ( r . data . trim ( ) ) {
199+ for ( const line of r . data . trim ( ) . split ( "\n" ) ) {
200+ output . push ( { type : "stdout" , message : line } ) ;
201+ }
202+ }
203+ break ;
204+ case "CompilerMessageE" :
205+ result . compiler_error += r . data ;
206+ result . compiler_message += r . data ;
207+ // Add to output in order
208+ if ( r . data . trim ( ) ) {
209+ for ( const line of r . data . trim ( ) . split ( "\n" ) ) {
210+ output . push ( { type : "error" , message : line } ) ;
211+ }
212+ }
213+ break ;
214+ case "StdOut" :
215+ result . program_output += r . data ;
216+ result . program_message += r . data ;
217+ // Add to output in order
218+ if ( r . data . trim ( ) ) {
219+ for ( const line of r . data . trim ( ) . split ( "\n" ) ) {
220+ output . push ( { type : "stdout" , message : line } ) ;
221+ }
222+ }
223+ break ;
224+ case "StdErr" :
225+ result . program_error += r . data ;
226+ result . program_message += r . data ;
227+ // Add to output in order
228+ if ( r . data . trim ( ) ) {
229+ for ( const line of r . data . trim ( ) . split ( "\n" ) ) {
230+ output . push ( { type : "stderr" , message : line } ) ;
231+ }
232+ }
233+ break ;
234+ case "ExitCode" :
235+ result . status += r . data ;
236+ break ;
237+ case "Signal" :
238+ result . signal += r . data ;
239+ break ;
240+ default :
241+ // Ignore unknown types
242+ break ;
243+ }
244+ }
245+
125246 return {
126247 ...result ,
127- compilerOutput : result . compiler_output . trim ( )
128- ? result . compiler_output
129- . trim ( )
130- . split ( "\n" )
131- . map ( ( line ) => ( { type : "stdout" as const , message : line } ) )
132- : [ ] ,
133- compilerError : result . compiler_error . trim ( )
134- ? result . compiler_error
135- . trim ( )
136- . split ( "\n" )
137- . map ( ( line ) => ( { type : "error" as const , message : line } ) )
138- : [ ] ,
139- programOutput : result . program_output . trim ( )
140- ? result . program_output
141- . trim ( )
142- . split ( "\n" )
143- . map ( ( line ) => ( { type : "stdout" as const , message : line } ) )
144- : [ ] ,
145- programError : result . program_error . trim ( )
146- ? result . program_error
147- . trim ( )
148- . split ( "\n" )
149- . map ( ( line ) => ( { type : "error" as const , message : line } ) )
150- : [ ] ,
248+ output,
151249 } ;
152250}
0 commit comments