1
1
'use strict' ;
2
2
3
- const { URL } = require ( 'url' ) ;
4
3
const { getURLFromFilePath } = require ( 'internal/url' ) ;
5
4
6
5
const {
7
- getNamespaceOfModuleWrap
6
+ getNamespaceOfModuleWrap,
7
+ createDynamicModule
8
8
} = require ( 'internal/loader/ModuleWrap' ) ;
9
9
10
10
const ModuleMap = require ( 'internal/loader/ModuleMap' ) ;
11
11
const ModuleJob = require ( 'internal/loader/ModuleJob' ) ;
12
- const resolveRequestUrl = require ( 'internal/loader/resolveRequestUrl ' ) ;
12
+ const ModuleRequest = require ( 'internal/loader/ModuleRequest ' ) ;
13
13
const errors = require ( 'internal/errors' ) ;
14
+ const debug = require ( 'util' ) . debuglog ( 'esm' ) ;
14
15
15
16
function getBase ( ) {
16
17
try {
17
- return getURLFromFilePath ( `${ process . cwd ( ) } /` ) ;
18
+ return getURLFromFilePath ( `${ process . cwd ( ) } /` ) . href ;
18
19
} catch ( e ) {
19
20
e . stack ;
20
21
// If the current working directory no longer exists.
@@ -28,45 +29,75 @@ function getBase() {
28
29
class Loader {
29
30
constructor ( base = getBase ( ) ) {
30
31
this . moduleMap = new ModuleMap ( ) ;
31
- if ( typeof base !== 'undefined' && base instanceof URL !== true ) {
32
- throw new errors . TypeError ( 'ERR_INVALID_ARG_TYPE' , 'base' , 'URL ' ) ;
32
+ if ( typeof base !== 'string' ) {
33
+ throw new errors . TypeError ( 'ERR_INVALID_ARG_TYPE' , 'base' , 'string ' ) ;
33
34
}
34
35
this . base = base ;
36
+ this . resolver = ModuleRequest . resolve . bind ( null ) ;
37
+ this . dynamicInstantiate = undefined ;
35
38
}
36
39
37
- async resolve ( specifier ) {
38
- const request = resolveRequestUrl ( this . base , specifier ) ;
39
- if ( request . url . protocol !== 'file:' ) {
40
- throw new errors . Error ( 'ERR_INVALID_PROTOCOL' ,
41
- request . url . protocol , 'file:' ) ;
42
- }
43
- return request . url ;
40
+ hook ( { resolve = ModuleRequest . resolve , dynamicInstantiate } ) {
41
+ this . resolver = resolve . bind ( null ) ;
42
+ this . dynamicInstantiate = dynamicInstantiate ;
44
43
}
45
44
46
- async getModuleJob ( dependentJob , specifier ) {
47
- if ( ! this . moduleMap . has ( dependentJob . url ) ) {
48
- throw new errors . Error ( 'ERR_MISSING_MODULE' , dependentJob . url ) ;
45
+ async resolve ( specifier , parentURL = this . base ) {
46
+ if ( typeof parentURL !== 'string' ) {
47
+ throw new errors . TypeError ( 'ERR_INVALID_ARG_TYPE' ,
48
+ 'parentURL' , 'string' ) ;
49
+ }
50
+ const { url, format } = await this . resolver ( specifier , parentURL ,
51
+ ModuleRequest . resolve ) ;
52
+
53
+ if ( typeof format !== 'string' ) {
54
+ throw new errors . TypeError ( 'ERR_INVALID_ARG_TYPE' , 'format' ,
55
+ [ 'esm' , 'cjs' , 'builtin' , 'addon' , 'json' ] ) ;
56
+ }
57
+ if ( typeof url !== 'string' ) {
58
+ throw new errors . TypeError ( 'ERR_INVALID_ARG_TYPE' , 'url' , 'string' ) ;
59
+ }
60
+
61
+ if ( format === 'builtin' ) {
62
+ return { url : `node:${ url } ` , format } ;
49
63
}
50
- const request = await resolveRequestUrl ( dependentJob . url , specifier ) ;
51
- const url = `${ request . url } ` ;
52
- if ( this . moduleMap . has ( url ) ) {
53
- return this . moduleMap . get ( url ) ;
64
+
65
+ if ( format !== 'dynamic' ) {
66
+ if ( ! ModuleRequest . loaders . has ( format ) ) {
67
+ throw new errors . Error ( 'ERR_UNKNOWN_MODULE_FORMAT' , format ) ;
68
+ }
69
+ if ( ! url . startsWith ( 'file:' ) ) {
70
+ throw new errors . Error ( 'ERR_INVALID_PROTOCOL' , url , 'file:' ) ;
71
+ }
54
72
}
55
- const dependencyJob = new ModuleJob ( this , request ) ;
56
- this . moduleMap . set ( url , dependencyJob ) ;
57
- return dependencyJob ;
73
+
74
+ return { url, format } ;
58
75
}
59
76
60
- async import ( specifier ) {
61
- const request = await resolveRequestUrl ( this . base , specifier ) ;
62
- const url = `${ request . url } ` ;
63
- let job ;
64
- if ( this . moduleMap . has ( url ) ) {
65
- job = this . moduleMap . get ( url ) ;
66
- } else {
67
- job = new ModuleJob ( this , request ) ;
77
+ async getModuleJob ( specifier , parentURL = this . base ) {
78
+ const { url, format } = await this . resolve ( specifier , parentURL ) ;
79
+ let job = this . moduleMap . get ( url ) ;
80
+ if ( job === undefined ) {
81
+ let loaderInstance ;
82
+ if ( format === 'dynamic' ) {
83
+ loaderInstance = async ( url ) => {
84
+ const { exports, execute } = await this . dynamicInstantiate ( url ) ;
85
+ return createDynamicModule ( exports , url , ( reflect ) => {
86
+ debug ( `Loading custom loader ${ url } ` ) ;
87
+ execute ( reflect . exports ) ;
88
+ } ) ;
89
+ } ;
90
+ } else {
91
+ loaderInstance = ModuleRequest . loaders . get ( format ) ;
92
+ }
93
+ job = new ModuleJob ( this , url , loaderInstance ) ;
68
94
this . moduleMap . set ( url , job ) ;
69
95
}
96
+ return job ;
97
+ }
98
+
99
+ async import ( specifier , parentURL = this . base ) {
100
+ const job = await this . getModuleJob ( specifier , parentURL ) ;
70
101
const module = await job . run ( ) ;
71
102
return getNamespaceOfModuleWrap ( module ) ;
72
103
}
0 commit comments