@@ -57,7 +57,7 @@ export function setup(): void {
57
57
const mod = FileModule . load ( filename ) ;
58
58
if ( ! mod ) {
59
59
util . log ( "getGeneratedContents cannot find" , filename ) ;
60
- return null ;
60
+ return "" ;
61
61
}
62
62
return mod . outputCode ;
63
63
}
@@ -71,7 +71,7 @@ export function setup(): void {
71
71
// FileModule.load(). FileModules are NOT executed upon first load, only when
72
72
// compileAndRun is called.
73
73
export class FileModule {
74
- scriptVersion : string ;
74
+ scriptVersion = "" ;
75
75
readonly exports = { } ;
76
76
77
77
private static readonly map = new Map < string , FileModule > ( ) ;
@@ -105,15 +105,15 @@ export class FileModule {
105
105
execute ( this . fileName , this . outputCode ) ;
106
106
}
107
107
108
- static load ( fileName : string ) : FileModule {
108
+ static load ( fileName : string ) : FileModule | undefined {
109
109
return this . map . get ( fileName ) ;
110
110
}
111
111
112
112
static getScriptsWithSourceCode ( ) : string [ ] {
113
113
const out = [ ] ;
114
114
for ( const fn of this . map . keys ( ) ) {
115
115
const m = this . map . get ( fn ) ;
116
- if ( m . sourceCode ) {
116
+ if ( m && m . sourceCode ) {
117
117
out . push ( fn ) ;
118
118
}
119
119
}
@@ -127,9 +127,10 @@ export function makeDefine(fileName: string): AmdDefine {
127
127
log ( "localRequire" , x ) ;
128
128
} ;
129
129
const currentModule = FileModule . load ( fileName ) ;
130
- const localExports = currentModule . exports ;
130
+ util . assert ( currentModule != null ) ;
131
+ const localExports = currentModule ! . exports ;
131
132
log ( "localDefine" , fileName , deps , localExports ) ;
132
- const args = deps . map ( dep => {
133
+ const args = deps . map ( ( dep ) => {
133
134
if ( dep === "require" ) {
134
135
return localRequire ;
135
136
} else if ( dep === "exports" ) {
@@ -140,9 +141,13 @@ export function makeDefine(fileName: string): AmdDefine {
140
141
return deno ;
141
142
} else {
142
143
const resolved = resolveModuleName ( dep , fileName ) ;
143
- const depModule = FileModule . load ( resolved ) ;
144
- depModule . compileAndRun ( ) ;
145
- return depModule . exports ;
144
+ util . assert ( resolved != null ) ;
145
+ const depModule = FileModule . load ( resolved ! ) ;
146
+ if ( depModule ) {
147
+ depModule . compileAndRun ( ) ;
148
+ return depModule . exports ;
149
+ }
150
+ return undefined ;
146
151
}
147
152
} ) ;
148
153
factory ( ...args ) ;
@@ -156,10 +161,14 @@ export function resolveModule(
156
161
) : null | FileModule {
157
162
util . log ( "resolveModule" , { moduleSpecifier, containingFile } ) ;
158
163
util . assert ( moduleSpecifier != null && moduleSpecifier . length > 0 ) ;
159
- let filename : string , sourceCode : string , outputCode : string ;
164
+ let filename : string | null ;
165
+ let sourceCode : string | null ;
166
+ let outputCode : string | null ;
160
167
if ( moduleSpecifier . startsWith ( ASSETS ) || containingFile . startsWith ( ASSETS ) ) {
161
168
// Assets are compiled into the runtime javascript bundle.
162
- const moduleId = moduleSpecifier . split ( "/" ) . pop ( ) ;
169
+ // we _know_ `.pop()` will return a string, but TypeScript doesn't so
170
+ // not null assertion
171
+ const moduleId = moduleSpecifier . split ( "/" ) . pop ( ) ! ;
163
172
const assetName = moduleId . includes ( "." ) ? moduleId : `${ moduleId } .d.ts` ;
164
173
util . assert ( assetName in assetSourceCode , `No such asset "${ assetName } "` ) ;
165
174
sourceCode = assetSourceCode [ assetName ] ;
@@ -179,15 +188,17 @@ export function resolveModule(
179
188
sourceCode = fetchResponse . sourceCode ;
180
189
outputCode = fetchResponse . outputCode ;
181
190
}
182
- if ( sourceCode == null || sourceCode . length === 0 ) {
191
+ if ( sourceCode == null || sourceCode . length === 0 || filename == null ) {
183
192
return null ;
184
193
}
185
194
util . log ( "resolveModule sourceCode length " , sourceCode . length ) ;
186
195
const m = FileModule . load ( filename ) ;
187
196
if ( m != null ) {
188
197
return m ;
189
198
} else {
190
- return new FileModule ( filename , sourceCode , outputCode ) ;
199
+ // null and undefined are incompatible in strict mode, but outputCode being
200
+ // null here has no runtime behavior impact, therefore not null assertion
201
+ return new FileModule ( filename , sourceCode , outputCode ! ) ;
191
202
}
192
203
}
193
204
@@ -204,7 +215,7 @@ function resolveModuleName(
204
215
}
205
216
206
217
function execute ( fileName : string , outputCode : string ) : void {
207
- util . assert ( outputCode && outputCode . length > 0 ) ;
218
+ util . assert ( outputCode != null && outputCode . length > 0 ) ;
208
219
window [ "define" ] = makeDefine ( fileName ) ;
209
220
outputCode += `\n//# sourceURL=${ fileName } ` ;
210
221
globalEval ( outputCode ) ;
@@ -278,7 +289,7 @@ class TypeScriptHost implements ts.LanguageServiceHost {
278
289
getScriptVersion ( fileName : string ) : string {
279
290
util . log ( "getScriptVersion" , fileName ) ;
280
291
const m = FileModule . load ( fileName ) ;
281
- return m . scriptVersion ;
292
+ return m && m . scriptVersion || "" ;
282
293
}
283
294
284
295
getScriptSnapshot ( fileName : string ) : ts . IScriptSnapshot | undefined {
@@ -323,32 +334,33 @@ class TypeScriptHost implements ts.LanguageServiceHost {
323
334
const fn = "lib.globals.d.ts" ; // ts.getDefaultLibFileName(options);
324
335
util . log ( "getDefaultLibFileName" , fn ) ;
325
336
const m = resolveModule ( fn , ASSETS ) ;
326
- return m . fileName ;
337
+ util . assert ( m != null ) ;
338
+ // TypeScript cannot track assertions, therefore not null assertion
339
+ return m ! . fileName ;
327
340
}
328
341
329
342
resolveModuleNames (
330
343
moduleNames : string [ ] ,
331
- containingFile : string ,
332
- reusedNames ?: string [ ]
333
- ) : Array < ts . ResolvedModule | undefined > {
344
+ containingFile : string
345
+ ) : ts . ResolvedModule [ ] {
334
346
//util.log("resolveModuleNames", { moduleNames, reusedNames });
335
- return moduleNames . map ( ( name : string ) => {
347
+ return moduleNames . map ( ( name ) => {
336
348
let resolvedFileName ;
337
349
if ( name === "deno" ) {
338
350
resolvedFileName = resolveModuleName ( "deno.d.ts" , ASSETS ) ;
339
351
} else if ( name === "typescript" ) {
340
352
resolvedFileName = resolveModuleName ( "typescript.d.ts" , ASSETS ) ;
341
353
} else {
342
354
resolvedFileName = resolveModuleName ( name , containingFile ) ;
343
- if ( resolvedFileName == null ) {
344
- return undefined ;
345
- }
355
+ }
356
+ if ( resolvedFileName == null ) {
357
+ return undefined ;
346
358
}
347
359
// This flags to the compiler to not go looking to transpile functional
348
360
// code, anything that is in `/$asset$/` is just library code
349
361
const isExternalLibraryImport = resolvedFileName . startsWith ( ASSETS ) ;
350
362
return { resolvedFileName, isExternalLibraryImport } ;
351
- } ) ;
363
+ } ) . filter ( ( mod ) => mod != null ) as ts . ResolvedModule [ ] ;
352
364
}
353
365
}
354
366
0 commit comments