phecda-server 7.0.0-alpha.0 → 7.0.0-alpha.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/assets/ps.json +24 -24
  2. package/assets/schema.json +55 -55
  3. package/bin/cli.mjs +31 -18
  4. package/dist/chunk-4LLLQOMF.js +152 -0
  5. package/dist/{chunk-BGXSMOLX.js → chunk-6OQ2SB5W.js} +138 -70
  6. package/dist/{chunk-SW5IKE5H.js → chunk-G7JFKM2M.js} +136 -89
  7. package/dist/{chunk-MBCHNDAY.js → chunk-KCPBITYZ.js} +24 -24
  8. package/dist/{chunk-HMVLXNV3.mjs → chunk-MUI6MTUO.mjs} +1 -1
  9. package/dist/chunk-NQ55PA2X.mjs +152 -0
  10. package/dist/{chunk-5622RBNB.mjs → chunk-YCES6ABN.mjs} +125 -57
  11. package/dist/{chunk-P75VKZJY.mjs → chunk-Z7NAAE4M.mjs} +94 -47
  12. package/dist/{core-BIcUwV18.d.mts → core-CUTbX_IS.d.ts} +5 -3
  13. package/dist/{core-CYwEPfN4.d.ts → core-DIfgUKIU.d.mts} +5 -3
  14. package/dist/helper.d.mts +8 -6
  15. package/dist/helper.d.ts +8 -6
  16. package/dist/helper.js +8 -3
  17. package/dist/helper.mjs +10 -5
  18. package/dist/http/elysia/index.d.mts +4 -4
  19. package/dist/http/elysia/index.d.ts +4 -4
  20. package/dist/http/elysia/index.js +43 -44
  21. package/dist/http/elysia/index.mjs +9 -10
  22. package/dist/http/express/index.d.mts +4 -4
  23. package/dist/http/express/index.d.ts +4 -4
  24. package/dist/http/express/index.js +40 -41
  25. package/dist/http/express/index.mjs +9 -10
  26. package/dist/http/fastify/index.d.mts +4 -4
  27. package/dist/http/fastify/index.d.ts +4 -4
  28. package/dist/http/fastify/index.js +41 -42
  29. package/dist/http/fastify/index.mjs +9 -10
  30. package/dist/http/h3/index.d.mts +4 -4
  31. package/dist/http/h3/index.d.ts +4 -4
  32. package/dist/http/h3/index.js +41 -42
  33. package/dist/http/h3/index.mjs +9 -10
  34. package/dist/http/hono/index.d.mts +4 -4
  35. package/dist/http/hono/index.d.ts +4 -4
  36. package/dist/http/hono/index.js +37 -39
  37. package/dist/http/hono/index.mjs +5 -7
  38. package/dist/http/hyper-express/index.d.mts +4 -4
  39. package/dist/http/hyper-express/index.d.ts +4 -4
  40. package/dist/http/hyper-express/index.js +38 -39
  41. package/dist/http/hyper-express/index.mjs +8 -9
  42. package/dist/http/koa/index.d.mts +4 -4
  43. package/dist/http/koa/index.d.ts +4 -4
  44. package/dist/http/koa/index.js +40 -41
  45. package/dist/http/koa/index.mjs +9 -10
  46. package/dist/index.d.mts +46 -40
  47. package/dist/index.d.ts +46 -40
  48. package/dist/index.js +48 -42
  49. package/dist/index.mjs +21 -15
  50. package/dist/{meta-BXKLFTgG.d.mts → meta-CR-D39hQ.d.mts} +7 -5
  51. package/dist/{meta-BXKLFTgG.d.ts → meta-CR-D39hQ.d.ts} +7 -5
  52. package/dist/rpc/bullmq/index.d.mts +5 -5
  53. package/dist/rpc/bullmq/index.d.ts +5 -5
  54. package/dist/rpc/bullmq/index.js +15 -14
  55. package/dist/rpc/bullmq/index.mjs +4 -3
  56. package/dist/rpc/kafka/index.d.mts +4 -4
  57. package/dist/rpc/kafka/index.d.ts +4 -4
  58. package/dist/rpc/kafka/index.js +15 -14
  59. package/dist/rpc/kafka/index.mjs +3 -2
  60. package/dist/rpc/nats/index.d.mts +4 -4
  61. package/dist/rpc/nats/index.d.ts +4 -4
  62. package/dist/rpc/nats/index.js +14 -13
  63. package/dist/rpc/nats/index.mjs +4 -3
  64. package/dist/rpc/rabbitmq/index.d.mts +4 -4
  65. package/dist/rpc/rabbitmq/index.d.ts +4 -4
  66. package/dist/rpc/rabbitmq/index.js +16 -15
  67. package/dist/rpc/rabbitmq/index.mjs +4 -3
  68. package/dist/rpc/redis/index.d.mts +4 -4
  69. package/dist/rpc/redis/index.d.ts +4 -4
  70. package/dist/rpc/redis/index.js +14 -13
  71. package/dist/rpc/redis/index.mjs +4 -3
  72. package/dist/test.d.mts +3 -3
  73. package/dist/test.d.ts +3 -3
  74. package/dist/test.js +6 -6
  75. package/dist/test.mjs +2 -2
  76. package/dist/{types-h40T3cRG.d.mts → types-BF1TDbFV.d.ts} +4 -3
  77. package/dist/{types-BtbL49Zs.d.mts → types-DYRu0vic.d.ts} +4 -3
  78. package/dist/{types-VFzEM7LL.d.ts → types-DYviSl5B.d.mts} +4 -3
  79. package/dist/{types-m3IEDKjP.d.ts → types-DqH1qA-q.d.mts} +4 -3
  80. package/package.json +8 -5
  81. package/register/export.mjs +30 -0
  82. package/register/index.mjs +50 -40
  83. package/register/loader.mjs +384 -367
  84. package/register/utils.mjs +60 -56
  85. package/dist/chunk-J5CFUN4V.js +0 -73
  86. package/dist/chunk-WHJ5FALK.mjs +0 -73
@@ -1,367 +1,384 @@
1
- import { fileURLToPath, pathToFileURL } from 'url'
2
- import { writeFile } from 'fs/promises'
3
- import {
4
- basename,
5
- extname,
6
- isAbsolute,
7
- relative,
8
- resolve as resolvePath,
9
- } from 'path'
10
- import { createRequire } from 'module'
11
- import ts from 'typescript'
12
- import chokidar from 'chokidar'
13
- import { log } from '../dist/index.mjs'
14
- import { compile, genUnImportRet, handleClassTypes, slash } from './utils.mjs'
15
-
16
- let port
17
-
18
- const isLowVersion = parseFloat(process.version.slice(1)) < 18.19
19
- // this part is important or not?
20
- const EXTENSIONS = [ts.Extension.Ts, ts.Extension.Tsx, ts.Extension.Mts]
21
- const tsconfig = {
22
- module: ts.ModuleKind.ESNext,
23
- moduleResolution: ts.ModuleResolutionKind.NodeNext,
24
- }
25
- const moduleResolutionCache = ts.createModuleResolutionCache(
26
- ts.sys.getCurrentDirectory(),
27
- x => x,
28
- tsconfig,
29
- )
30
- const host = {
31
- fileExists: ts.sys.fileExists,
32
- readFile: ts.sys.readFile,
33
- }
34
-
35
- let unimportRet
36
- const dtsPath = 'ps.d.ts'
37
-
38
- if (isLowVersion)
39
- await initialize()
40
-
41
- let config
42
-
43
- const workdir = process.env.PS_WORKDIR || process.cwd()
44
-
45
- const configPath = resolvePath(
46
- workdir,
47
- process.env.PS_CONFIG_FILE || 'ps.json',
48
- )
49
-
50
- const require = createRequire(import.meta.url)
51
- export async function initialize(data) {
52
- if (data)
53
- port = data.port
54
- log('read config...')
55
-
56
- config = require(configPath)
57
- if (!config.virtualFile)
58
- config.virtualFile = {}
59
-
60
- if (!process.env.PS_HMR_BAN) {
61
- chokidar.watch(configPath, { persistent: true }).on('change', () => {
62
- port.postMessage(
63
- JSON.stringify({
64
- type: 'relaunch',
65
- }),
66
- )
67
- })
68
- }
69
-
70
- if (!config.unimport)
71
- return
72
- unimportRet = await genUnImportRet(config.unimport)
73
- if (unimportRet) {
74
- log('auto import...')
75
- await unimportRet.init()
76
-
77
- writeFile(
78
- resolvePath(workdir, config.unimport.dtsPath || dtsPath),
79
- handleClassTypes(
80
- await unimportRet.generateTypeDeclarations({
81
- resolvePath: (i) => {
82
- if (i.from.startsWith('.') || isAbsolute(i.from)) {
83
- const related = slash(
84
- relative(workdir, i.from).replace(/\.ts(x)?$/, ''),
85
- )
86
-
87
- return !related.startsWith('.') ? `./${related}` : related
88
- }
89
- return i.from
90
- },
91
- }),
92
- ),
93
- )
94
- }
95
- }
96
-
97
- const watchFiles = new Set()
98
- const filesRecord = new Map()
99
- const moduleGraph = {}
100
-
101
- let entryUrl
102
-
103
- function addUrlToGraph(url, parent) {
104
- if (!(url in moduleGraph))
105
- moduleGraph[url] = new Set()
106
-
107
- moduleGraph[url].add(parent)
108
- return url + (filesRecord.has(url) ? `?t=${filesRecord.get(url)}` : '')
109
- }
110
-
111
- function getFileMid(file) {
112
- const filename = basename(file)
113
- const ret = filename.split('.')
114
- if (ret.length === 3)
115
- return ret[1]
116
- else return ''
117
- }
118
-
119
- export const resolve = async (specifier, context, nextResolve) => {
120
- // virtual file
121
- if (config.virtualFile[specifier]) {
122
- return {
123
- format: 'ts',
124
- url: specifier,
125
- shortCircuit: true,
126
- }
127
- }
128
- // entrypoint
129
- if (!context.parentURL) {
130
- entryUrl = specifier
131
- return {
132
- format: EXTENSIONS.some(ext => specifier.endsWith(ext))
133
- ? 'ts'
134
- : undefined,
135
- url: specifier,
136
- shortCircuit: true,
137
- }
138
- }
139
- // url import
140
- // it seems useless
141
- if (/^file:\/\/\//.test(specifier) && extname(specifier) === '.ts') {
142
- const url = addUrlToGraph(specifier, context.parentURL.split('?')[0])
143
- return {
144
- format: 'ts',
145
- url,
146
- shortCircuit: true,
147
- }
148
- }
149
-
150
- // hmr import
151
- if (
152
- context.parentURL.includes('/node_modules/phecda-server')
153
- && isAbsolute(specifier)
154
- ) {
155
- specifier = relative(fileURLToPath(entryUrl), specifier)
156
- .replace(/\.ts$/, '')
157
- .slice(1)
158
- context.parentURL = entryUrl
159
- }
160
-
161
- // import/require from external library
162
- if (context.parentURL.includes('/node_modules/'))
163
- return nextResolve(specifier)
164
- const { resolvedModule } = ts.resolveModuleName(
165
- specifier,
166
- fileURLToPath(context.parentURL),
167
- tsconfig,
168
- host,
169
- moduleResolutionCache,
170
- )
171
-
172
- // import between loacl projects
173
- if (
174
- resolvedModule
175
- && !resolvedModule.resolvedFileName.includes('/node_modules/')
176
- && EXTENSIONS.includes(resolvedModule.extension)
177
- ) {
178
- const url = addUrlToGraph(
179
- pathToFileURL(resolvedModule.resolvedFileName).href,
180
- context.parentURL.split('?')[0],
181
- )
182
-
183
- const importerMid = getFileMid(context.parentURL)
184
- const sourceMid = getFileMid(resolvedModule.resolvedFileName)
185
- if (config.resolve && importerMid && sourceMid) {
186
- const resolver = config.resolve.find(
187
- item => item.source === sourceMid && item.importer === importerMid,
188
- )
189
- if (resolver) {
190
- return {
191
- format: 'ts',
192
- url: pathToFileURL(resolvePath(workdir, resolver.path)).href,
193
- shortCircuit: true,
194
- }
195
- }
196
- }
197
-
198
- return {
199
- format: 'ts',
200
- url,
201
- shortCircuit: true,
202
- }
203
- }
204
-
205
- const resolveRet = await nextResolve(specifier)
206
-
207
- // ts resolve fail in some cases
208
- if (resolveRet.url && isAbsolute(resolveRet.url))
209
- resolveRet.url = pathToFileURL(resolveRet.url).href
210
-
211
- return resolveRet
212
- }
213
- // @todo the first params may be url or path, need to distinguish
214
-
215
- export const load = async (url, context, nextLoad) => {
216
- if (config.virtualFile[url]) {
217
- return {
218
- format: 'module',
219
- source: config.virtualFile[url],
220
- shortCircuit: true,
221
- }
222
- }
223
-
224
- url = url.split('?')[0]
225
- if (
226
- !url.includes('/node_modules/')
227
- && url.startsWith('file://')
228
- && !watchFiles.has(url)
229
- && !isLowVersion
230
- ) {
231
- watchFiles.add(url)
232
- // watch(
233
- // fileURLToPath(url),
234
- // debounce((type) => {
235
- // if (type === 'change') {
236
- // try {
237
- // const files = [...findTopScope(url, Date.now())].reverse()
238
-
239
- // port.postMessage(
240
- // JSON.stringify({
241
- // type: 'change',
242
- // files,
243
- // }),
244
- // )
245
- // }
246
- // catch (e) {
247
- // port.postMessage(
248
- // JSON.stringify({
249
- // type: 'relaunch',
250
- // }),
251
- // )
252
- // }
253
- // }
254
- // }),
255
- // )
256
-
257
- if (!process.env.PS_HMR_BAN) {
258
- chokidar.watch(fileURLToPath(url), { persistent: true }).on(
259
- 'change',
260
- debounce(() => {
261
- try {
262
- const files = [...findTopScope(url, Date.now())].reverse()
263
-
264
- port.postMessage(
265
- JSON.stringify({
266
- type: 'change',
267
- files,
268
- }),
269
- )
270
- }
271
- catch (e) {
272
- port.postMessage(
273
- JSON.stringify({
274
- type: 'relaunch',
275
- }),
276
- )
277
- }
278
- }),
279
- )
280
- }
281
- }
282
- // resolveModuleName failed
283
- // I don't know why it failed
284
- if (!context.format && url.endsWith('.ts'))
285
- context.format = 'ts'
286
-
287
- if (context.format === 'ts') {
288
- const { source } = await nextLoad(url, context)
289
-
290
- const code
291
- = typeof source === 'string' ? source : Buffer.from(source).toString()
292
- const compiled = await compile(code, url)
293
- if (unimportRet) {
294
- const { injectImports } = unimportRet
295
- return {
296
- format: 'module',
297
- source: (
298
- await injectImports(
299
- compiled,
300
- slash(url.startsWith('file://') ? fileURLToPath(url) : url),
301
- )
302
- ).code,
303
- shortCircuit: true,
304
- }
305
- }
306
- return {
307
- format: 'module',
308
- source: compiled,
309
- shortCircuit: true,
310
- }
311
- }
312
- else {
313
- return nextLoad(url, context)
314
- }
315
- }
316
-
317
- function findTopScope(url, time, modules = new Set()) {
318
- filesRecord.set(url, time)
319
- if (isModuleFileUrl(url)) {
320
- modules.add(fileURLToPath(url))
321
- }
322
- else {
323
- if (!moduleGraph[url])
324
- throw new Error('root file update')
325
- for (const i of [...moduleGraph[url]]) findTopScope(i, time, modules)
326
- }
327
-
328
- return modules
329
- }
330
-
331
- function debounce(cb, timeout = 500) {
332
- let timer
333
- return (...args) => {
334
- if (timer)
335
- return
336
-
337
- timer = setTimeout(() => {
338
- cb(...args)
339
- timer = undefined
340
- }, timeout)
341
- }
342
- }
343
-
344
- export function isModuleFileUrl(url) {
345
- const midName = getFileMid(url)
346
- if (!midName)
347
- return false
348
- if (
349
- [
350
- 'controller',
351
- 'rpc',
352
- 'service',
353
- 'module',
354
- 'extension',
355
- 'ext',
356
- 'guard',
357
- 'interceptor',
358
- 'plugin',
359
- 'filter',
360
- 'pipe',
361
- 'edge',
362
- ].includes(midName)
363
- )
364
- return true
365
-
366
- return config.moduleFile && config.moduleFile.includes(midName)
367
- }
1
+ import { fileURLToPath, pathToFileURL } from 'url'
2
+ import { writeFile } from 'fs/promises'
3
+ import {
4
+ basename,
5
+ dirname,
6
+ extname,
7
+ isAbsolute,
8
+ relative,
9
+ resolve as resolvePath,
10
+ } from 'path'
11
+ import { existsSync } from 'fs'
12
+ import ts from 'typescript'
13
+ import chokidar from 'chokidar'
14
+ import Debug from 'debug'
15
+ import { loadConfig } from 'unconfig'
16
+ import { compile, genUnImportRet, handleClassTypes, slash } from './utils.mjs'
17
+
18
+ const debug = Debug('phecda-server/loader')
19
+
20
+ const isLowVersion = parseFloat(process.version.slice(1)) < 18.19
21
+ const IS_DEV = process.env.NODE_ENV === 'development'
22
+ let port
23
+ let config
24
+ const workdir = process.cwd()
25
+ const configPath = resolvePath(
26
+ workdir,
27
+ process.env.PS_CONFIG_FILE || 'ps.json',
28
+ )
29
+
30
+ // unimport
31
+ let unimportRet
32
+ const dtsPath = process.env.PS_DTS_PATH || 'ps.d.ts'
33
+
34
+ // graph
35
+ let entryUrl
36
+ const watchFiles = new Set()
37
+ const filesRecord = new Map()
38
+ const moduleGraph = {}
39
+ // ts
40
+ let tsconfig = {
41
+ module: ts.ModuleKind.ESNext,
42
+ moduleResolution: ts.ModuleResolutionKind.NodeNext,
43
+ }
44
+ const EXTENSIONS = [ts.Extension.Ts, ts.Extension.Tsx, ts.Extension.Mts]
45
+ const tsconfigPath = resolvePath(process.cwd(), 'tsconfig.json')
46
+ const tsRet = ts.readConfigFile(tsconfigPath, ts.sys.readFile)
47
+ if (!tsRet.error) {
48
+ const { error, options } = ts.parseJsonConfigFileContent(
49
+ tsRet.config,
50
+ ts.sys,
51
+ dirname(tsconfigPath),
52
+ )
53
+ if (!error)
54
+ tsconfig = options
55
+ }
56
+ const moduleResolutionCache = ts.createModuleResolutionCache(
57
+ ts.sys.getCurrentDirectory(),
58
+ x => x,
59
+ tsconfig,
60
+ )
61
+ const host = {
62
+ fileExists: ts.sys.fileExists,
63
+ readFile: ts.sys.readFile,
64
+ }
65
+
66
+ if (isLowVersion)
67
+ await initialize()
68
+
69
+ export async function initialize(data) {
70
+ if (data)
71
+ port = data.port
72
+
73
+ debug('read config...')
74
+
75
+ const unconfigRet = await loadConfig({
76
+ sources: [
77
+ {
78
+ files: configPath,
79
+ extensions: ['ts', 'mts', 'cts', 'js', 'mjs', 'cjs', 'json', ''],
80
+ },
81
+ ],
82
+ merge: false,
83
+ })
84
+ config = unconfigRet.config
85
+ if (!config.virtualFile)
86
+ config.virtualFile = {}
87
+ if (!config.paths)
88
+ config.paths = {}
89
+
90
+ if (IS_DEV) {
91
+ chokidar.watch(configPath, { persistent: true }).on('change', () => {
92
+ port.postMessage(
93
+ JSON.stringify({
94
+ type: 'relaunch',
95
+ }),
96
+ )
97
+ })
98
+ }
99
+
100
+ if (!config.unimport)
101
+ return
102
+ unimportRet = await genUnImportRet(config.unimport)
103
+ if (unimportRet) {
104
+ debug('auto import...')
105
+ await unimportRet.init()
106
+
107
+ const unimportDtsPath = resolvePath(workdir, dtsPath)
108
+ writeFile(
109
+ unimportDtsPath,
110
+ handleClassTypes(
111
+ await unimportRet.generateTypeDeclarations({
112
+ resolvePath: (i) => {
113
+ if (i.from.startsWith('.') || isAbsolute(i.from)) {
114
+ const related = slash(
115
+ relative(dirname(unimportDtsPath), i.from).replace(/\.ts(x)?$/, ''),
116
+ )
117
+
118
+ return !related.startsWith('.') ? `./${related}` : related
119
+ }
120
+ return i.from
121
+ },
122
+ }),
123
+ ),
124
+ )
125
+ }
126
+ }
127
+
128
+ function addUrlToGraph(url, parent) {
129
+ if (!(url in moduleGraph))
130
+ moduleGraph[url] = new Set()
131
+
132
+ moduleGraph[url].add(parent)
133
+ return url + (filesRecord.has(url) ? `?t=${filesRecord.get(url)}` : '')
134
+ }
135
+
136
+ function getFileMid(file) {
137
+ const filename = basename(file)
138
+ const ret = filename.split('.')
139
+ if (ret.length === 3)
140
+ return ret[1]
141
+ else return ''
142
+ }
143
+
144
+ export const resolve = async (specifier, context, nextResolve) => {
145
+ // virtual file
146
+ if (config.virtualFile[specifier]) {
147
+ return {
148
+ format: 'ts',
149
+ url: specifier,
150
+ shortCircuit: true,
151
+ }
152
+ }
153
+ // entrypoint
154
+ if (!context.parentURL) {
155
+ if (/^file:\/\/\//.test(specifier) && existsSync(fileURLToPath(specifier))) {
156
+ entryUrl = specifier
157
+
158
+ return {
159
+ format: EXTENSIONS.some(ext => specifier.endsWith(ext))
160
+ ? 'ts'
161
+ : undefined,
162
+ url: specifier,
163
+ shortCircuit: true,
164
+ }
165
+ }
166
+ else {
167
+ // won't resolve virtual file as entry in vite
168
+ return nextResolve(specifier)
169
+ }
170
+ }
171
+ // url import
172
+ // it seems useless
173
+ if (/^file:\/\/\//.test(specifier) && extname(specifier) === '.ts') {
174
+ const url = addUrlToGraph(specifier, context.parentURL.split('?')[0])
175
+ return {
176
+ format: 'ts',
177
+ url,
178
+ shortCircuit: true,
179
+ }
180
+ }
181
+
182
+ // hmr import
183
+ if (
184
+ context.parentURL.includes('/node_modules/phecda-server')
185
+ && isAbsolute(specifier)
186
+ ) {
187
+ specifier = relative(fileURLToPath(entryUrl), specifier)
188
+ .replace(/\.ts$/, '')
189
+ .slice(1)
190
+ context.parentURL = entryUrl
191
+ }
192
+
193
+ // import/require from external library
194
+ if (context.parentURL.includes('/node_modules/'))
195
+ return nextResolve(specifier)
196
+ const { resolvedModule } = ts.resolveModuleName(
197
+ specifier,
198
+ fileURLToPath(context.parentURL),
199
+ tsconfig,
200
+ host,
201
+ moduleResolutionCache,
202
+ )
203
+
204
+ // import between loacl projects
205
+ if (
206
+ resolvedModule
207
+ && !resolvedModule.resolvedFileName.includes('/node_modules/')
208
+ && EXTENSIONS.includes(resolvedModule.extension)
209
+ ) {
210
+ const url = addUrlToGraph(
211
+ pathToFileURL(resolvedModule.resolvedFileName).href,
212
+ context.parentURL.split('?')[0],
213
+ )
214
+
215
+ const importerMid = getFileMid(context.parentURL)
216
+ const sourceMid = getFileMid(resolvedModule.resolvedFileName)
217
+ if (config.resolve && importerMid && sourceMid) {
218
+ const resolver = config.resolve.find(
219
+ item => item.source === sourceMid && item.importer === importerMid,
220
+ )
221
+ if (resolver) {
222
+ return {
223
+ format: 'ts',
224
+ url: pathToFileURL(resolvePath(workdir, resolver.path)).href,
225
+ shortCircuit: true,
226
+ }
227
+ }
228
+ }
229
+
230
+ return {
231
+ format: 'ts',
232
+ url,
233
+ shortCircuit: true,
234
+ }
235
+ }
236
+
237
+ const resolveRet = await nextResolve(specifier)
238
+
239
+ // ts resolve fail in some cases
240
+ if (resolveRet.url && isAbsolute(resolveRet.url))
241
+ resolveRet.url = pathToFileURL(resolveRet.url).href
242
+
243
+ return resolveRet
244
+ }
245
+ // @todo the first params may be url or path, need to distinguish
246
+
247
+ export const load = async (url, context, nextLoad) => {
248
+ if (config.virtualFile[url]) {
249
+ return {
250
+ format: 'module',
251
+ source: config.virtualFile[url],
252
+ shortCircuit: true,
253
+ }
254
+ }
255
+
256
+ url = url.split('?')[0]
257
+ if (
258
+ !url.includes('/node_modules/')
259
+ && url.startsWith('file://')
260
+ && !watchFiles.has(url)
261
+ && !isLowVersion
262
+ ) {
263
+ watchFiles.add(url)
264
+
265
+ if (IS_DEV) {
266
+ if (isModuleFileUrl(url)) {
267
+ port.postMessage(
268
+ JSON.stringify({
269
+ type: 'init',
270
+ files: [fileURLToPath(url)],
271
+ }),
272
+ )
273
+ }
274
+
275
+ chokidar.watch(fileURLToPath(url), { persistent: true }).on(
276
+ 'change',
277
+ debounce(() => {
278
+ try {
279
+ const files = [...findTopScope(url, Date.now())].reverse()
280
+
281
+ port.postMessage(
282
+ JSON.stringify({
283
+ type: 'change',
284
+ files,
285
+ }),
286
+ )
287
+ }
288
+ catch (e) {
289
+ port.postMessage(
290
+ JSON.stringify({
291
+ type: 'relaunch',
292
+ }),
293
+ )
294
+ }
295
+ }),
296
+ )
297
+ }
298
+ }
299
+ // resolveModuleName failed
300
+ // I don't know why it failed
301
+ if (!context.format && url.endsWith('.ts'))
302
+ context.format = 'ts'
303
+
304
+ if (context.format === 'ts') {
305
+ const { source } = await nextLoad(url, context)
306
+
307
+ const code
308
+ = typeof source === 'string' ? source : Buffer.from(source).toString()
309
+ const compiled = (await compile(code, url)).replace(/_ts_metadata\(\"design:paramtypes\"\,/g, '_ts_metadata("design:paramtypes",()=>')// handle cycle
310
+
311
+ if (unimportRet) {
312
+ const { injectImports } = unimportRet
313
+ return {
314
+ format: 'module',
315
+ source: (
316
+ await injectImports(
317
+ compiled,
318
+ slash(url.startsWith('file://') ? fileURLToPath(url) : url),
319
+ )
320
+ ).code,
321
+ shortCircuit: true,
322
+ }
323
+ }
324
+ return {
325
+ format: 'module',
326
+ source: compiled,
327
+ shortCircuit: true,
328
+ }
329
+ }
330
+ else {
331
+ return nextLoad(url, context)
332
+ }
333
+ }
334
+
335
+ function findTopScope(url, time, modules = new Set()) {
336
+ filesRecord.set(url, time)
337
+ if (isModuleFileUrl(url)) {
338
+ modules.add(fileURLToPath(url))
339
+ }
340
+ else {
341
+ if (!moduleGraph[url])
342
+ throw new Error('root file update')
343
+ for (const i of [...moduleGraph[url]]) findTopScope(i, time, modules)
344
+ }
345
+
346
+ return modules
347
+ }
348
+
349
+ function debounce(cb, timeout = 500) {
350
+ let timer
351
+ return (...args) => {
352
+ if (timer)
353
+ return
354
+
355
+ timer = setTimeout(() => {
356
+ cb(...args)
357
+ timer = undefined
358
+ }, timeout)
359
+ }
360
+ }
361
+
362
+ export function isModuleFileUrl(url) {
363
+ const midName = getFileMid(url)
364
+ if (!midName)
365
+ return false
366
+ if (
367
+ [
368
+ 'controller',
369
+ 'rpc',
370
+ 'service',
371
+ 'module',
372
+ 'extension',
373
+ 'ext',
374
+ 'guard',
375
+ 'addon',
376
+ 'filter',
377
+ 'pipe',
378
+ 'solo',
379
+ ].includes(midName)
380
+ )
381
+ return true
382
+
383
+ return config.moduleFile && config.moduleFile.includes(midName)
384
+ }