@@ -3,6 +3,11 @@ import { EditorSystem } from './editor.js';
3
3
import ts from 'typescript' ;
4
4
import { TypeProcessor } from './processor.js' ;
5
5
import { CodeShareManager } from './code-share.js' ;
6
+ import {
7
+ createSystem ,
8
+ createDefaultMapFromCDN ,
9
+ createVirtualCompilerHost
10
+ } from '@typescript/vfs' ;
6
11
7
12
/**
8
13
* @typedef {import('../../.build/plugins/PackageToJS/outputs/Package/bridge-js.js').PlayBridgeJS } PlayBridgeJS
@@ -38,6 +43,14 @@ export class BridgeJSPlayground {
38
43
this . copyButton = /** @type {HTMLButtonElement } */ ( document . getElementById ( 'copyButton' ) ) ;
39
44
/** @type {HTMLButtonElement } */
40
45
this . closeShareDialogButton = /** @type {HTMLButtonElement } */ ( document . getElementById ( 'closeShareDialog' ) ) ;
46
+
47
+ // Progress UI elements
48
+ /** @type {HTMLDivElement | null } */
49
+ this . progressBar = /** @type {HTMLDivElement } */ ( document . getElementById ( 'progressBar' ) ) ;
50
+ /** @type {HTMLDivElement | null } */
51
+ this . progressFill = /** @type {HTMLDivElement } */ ( document . getElementById ( 'progressFill' ) ) ;
52
+ /** @type {HTMLDivElement | null } */
53
+ this . progressLabel = /** @type {HTMLDivElement } */ ( document . getElementById ( 'progressLabel' ) ) ;
41
54
}
42
55
43
56
/**
@@ -50,44 +63,53 @@ export class BridgeJSPlayground {
50
63
}
51
64
52
65
try {
66
+ this . showProgress ( 'Starting…' , 5 ) ;
53
67
// Initialize editor system
54
68
await this . editorSystem . init ( ) ;
69
+ this . setProgress ( 'Editor ready' , 30 ) ;
55
70
56
71
// Initialize BridgeJS
57
72
await this . initializeBridgeJS ( ) ;
73
+ this . setProgress ( 'BridgeJS ready' , 70 ) ;
58
74
59
75
// Set up event listeners
60
76
this . setupEventListeners ( ) ;
61
77
62
78
// Check for shared code in URL
79
+ this . setProgress ( 'Checking shared code…' , 80 ) ;
63
80
const sharedCode = await CodeShareManager . extractCodeFromUrl ( ) ;
64
81
if ( sharedCode ) {
65
82
this . editorSystem . setInputs ( sharedCode ) ;
66
83
} else {
67
84
// Load sample code
68
85
this . editorSystem . setInputs ( sampleCode ) ;
69
86
}
70
-
87
+ this . setProgress ( 'Finalizing…' , 95 ) ;
71
88
this . isInitialized = true ;
72
89
console . log ( 'BridgeJS Playground initialized successfully' ) ;
90
+ this . setProgress ( 'Ready' , 100 ) ;
91
+ setTimeout ( ( ) => this . hideProgress ( ) , 400 ) ;
73
92
} catch ( error ) {
74
93
console . error ( 'Failed to initialize BridgeJS Playground:' , error ) ;
75
94
this . showError ( 'Failed to initialize application: ' + error . message ) ;
95
+ this . hideProgress ( ) ;
76
96
}
77
97
}
78
98
79
99
// Initialize BridgeJS
80
100
async initializeBridgeJS ( ) {
81
101
try {
82
102
// Import the BridgeJS module
103
+ this . setProgress ( 'Loading BridgeJS…' , 50 ) ;
83
104
const { init } = await import ( "../../.build/plugins/PackageToJS/outputs/Package/index.js" ) ;
105
+ const virtualHost = await this . createTS2SkeletonFactory ( ) ;
106
+ this . setProgress ( 'Preparing TypeScript host…' , 60 ) ;
84
107
const { exports } = await init ( {
85
- getImports : ( ) => {
86
- return {
87
- createTS2Skeleton : this . createTS2Skeleton
88
- } ;
89
- }
108
+ getImports : ( ) => ( {
109
+ createTS2Skeleton : ( ) => this . createTS2Skeleton ( virtualHost )
110
+ } )
90
111
} ) ;
112
+ this . setProgress ( 'Creating runtime…' , 65 ) ;
91
113
this . playBridgeJS = new exports . PlayBridgeJS ( ) ;
92
114
console . log ( 'BridgeJS initialized successfully' ) ;
93
115
} catch ( error ) {
@@ -171,32 +193,44 @@ export class BridgeJSPlayground {
171
193
} ) ;
172
194
}
173
195
174
- createTS2Skeleton ( ) {
196
+ async createTS2SkeletonFactory ( ) {
197
+ const createVirtualHost = async ( ) => {
198
+ const fsMap = await createDefaultMapFromCDN (
199
+ { target : ts . ScriptTarget . ES2015 } ,
200
+ ts . version ,
201
+ true ,
202
+ ts
203
+ ) ;
204
+
205
+ const system = createSystem ( fsMap ) ;
206
+
207
+ const compilerOptions = {
208
+ target : ts . ScriptTarget . ES2015 ,
209
+ lib : [ "es2015" , "dom" ] ,
210
+ } ;
211
+
212
+ return createVirtualCompilerHost ( system , compilerOptions , ts ) ;
213
+ }
214
+ return await createVirtualHost ( ) ;
215
+ }
216
+
217
+ /**
218
+ * @param {ReturnType<typeof createVirtualCompilerHost> } virtualHost
219
+ */
220
+ createTS2Skeleton ( virtualHost ) {
175
221
return {
222
+ /**
223
+ * @param {string } dtsCode
224
+ * @returns {string }
225
+ */
176
226
convert : ( dtsCode ) => {
177
- const virtualFilePath = "bridge-js.d.ts"
178
- const virtualHost = {
179
- fileExists : fileName => fileName === virtualFilePath ,
180
- readFile : fileName => dtsCode ,
181
- getSourceFile : ( fileName , languageVersion ) => {
182
- const sourceText = dtsCode ;
183
- if ( sourceText === undefined ) return undefined ;
184
- return ts . createSourceFile ( fileName , sourceText , languageVersion ) ;
185
- } ,
186
- getDefaultLibFileName : options => "lib.d.ts" ,
187
- writeFile : ( fileName , data ) => {
188
- console . log ( `[emit] ${ fileName } :\n${ data } ` ) ;
189
- } ,
190
- getCurrentDirectory : ( ) => "" ,
191
- getDirectories : ( ) => [ ] ,
192
- getCanonicalFileName : fileName => fileName ,
193
- getNewLine : ( ) => "\n" ,
194
- useCaseSensitiveFileNames : ( ) => true
195
- }
196
227
// Create TypeScript program from d.ts content
228
+ const virtualFilePath = "bridge-js.d.ts"
229
+ const sourceFile = ts . createSourceFile ( virtualFilePath , dtsCode , ts . ScriptTarget . ES2015 ) ;
230
+ virtualHost . updateFile ( sourceFile ) ;
197
231
const tsProgram = ts . createProgram ( {
198
232
rootNames : [ virtualFilePath ] ,
199
- host : virtualHost ,
233
+ host : virtualHost . compilerHost ,
200
234
options : {
201
235
noEmit : true ,
202
236
declaration : true ,
@@ -268,4 +302,42 @@ export class BridgeJSPlayground {
268
302
hideError ( ) {
269
303
this . errorDisplay . classList . remove ( 'show' ) ;
270
304
}
305
+
306
+ /**
307
+ * Shows progress bar.
308
+ * @param {string } label
309
+ * @param {number } percent
310
+ */
311
+ showProgress ( label , percent ) {
312
+ if ( this . progressBar ) {
313
+ this . progressBar . classList . add ( 'show' ) ;
314
+ this . progressBar . classList . remove ( 'hidden' ) ;
315
+ }
316
+ this . setProgress ( label , percent ) ;
317
+ }
318
+
319
+ /**
320
+ * Updates progress label and percentage.
321
+ * @param {string } label
322
+ * @param {number } percent
323
+ */
324
+ setProgress ( label , percent ) {
325
+ if ( this . progressLabel ) {
326
+ this . progressLabel . textContent = label ;
327
+ }
328
+ if ( this . progressFill ) {
329
+ const clamped = Math . max ( 0 , Math . min ( 100 , Number ( percent ) || 0 ) ) ;
330
+ this . progressFill . style . width = clamped + '%' ;
331
+ }
332
+ }
333
+
334
+ /**
335
+ * Hides progress bar.
336
+ */
337
+ hideProgress ( ) {
338
+ if ( this . progressBar ) {
339
+ this . progressBar . classList . remove ( 'show' ) ;
340
+ this . progressBar . classList . add ( 'hidden' ) ;
341
+ }
342
+ }
271
343
}
0 commit comments