phecda-server 5.0.2 → 5.1.0

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 (167) hide show
  1. package/README.md +10 -108
  2. package/bin/cli.mjs +189 -186
  3. package/bin/schema.json +55 -55
  4. package/dist/{chunk-F5YWXY5W.js → chunk-423JPSEB.js} +18 -17
  5. package/dist/chunk-423JPSEB.js.map +1 -0
  6. package/dist/chunk-4R55T3HG.js +253 -0
  7. package/dist/chunk-4R55T3HG.js.map +1 -0
  8. package/dist/chunk-4YVAW3L4.mjs +76 -0
  9. package/dist/chunk-4YVAW3L4.mjs.map +1 -0
  10. package/dist/{chunk-W5EOVGQD.mjs → chunk-5DOVDDO7.mjs} +3 -2
  11. package/dist/chunk-5DOVDDO7.mjs.map +1 -0
  12. package/dist/{chunk-BXLBWRHS.js → chunk-5WQ2SMIK.js} +39 -38
  13. package/dist/chunk-5WQ2SMIK.js.map +1 -0
  14. package/dist/chunk-6MQP6OHU.mjs +295 -0
  15. package/dist/chunk-6MQP6OHU.mjs.map +1 -0
  16. package/dist/chunk-6Q2PCC3A.mjs +295 -0
  17. package/dist/chunk-6Q2PCC3A.mjs.map +1 -0
  18. package/dist/chunk-6UQYEBAN.js +253 -0
  19. package/dist/chunk-6UQYEBAN.js.map +1 -0
  20. package/dist/chunk-6W7CGOZC.mjs +565 -0
  21. package/dist/chunk-6W7CGOZC.mjs.map +1 -0
  22. package/dist/{chunk-YR5Q5F2K.js → chunk-7Y37NSBM.js} +1 -0
  23. package/dist/chunk-7Y37NSBM.js.map +1 -0
  24. package/dist/{chunk-RCTOVYZY.mjs → chunk-BQBSVGMG.mjs} +2 -1
  25. package/dist/chunk-BQBSVGMG.mjs.map +1 -0
  26. package/dist/chunk-BZP6GKM6.mjs +565 -0
  27. package/dist/chunk-BZP6GKM6.mjs.map +1 -0
  28. package/dist/{chunk-ITTD2GBR.mjs → chunk-C5JAHCS2.mjs} +1 -0
  29. package/dist/chunk-C5JAHCS2.mjs.map +1 -0
  30. package/dist/chunk-DTBKDALR.mjs +295 -0
  31. package/dist/chunk-DTBKDALR.mjs.map +1 -0
  32. package/dist/chunk-GHOKWS5V.js +295 -0
  33. package/dist/chunk-GHOKWS5V.js.map +1 -0
  34. package/dist/chunk-H4N6SHNG.mjs +76 -0
  35. package/dist/chunk-H4N6SHNG.mjs.map +1 -0
  36. package/dist/chunk-ICYHM4UM.js +565 -0
  37. package/dist/chunk-ICYHM4UM.js.map +1 -0
  38. package/dist/chunk-LOLXPM4J.mjs +529 -0
  39. package/dist/chunk-LOLXPM4J.mjs.map +1 -0
  40. package/dist/chunk-MSS6A2TU.js +585 -0
  41. package/dist/chunk-MSS6A2TU.js.map +1 -0
  42. package/dist/{chunk-AB4OX3WV.mjs → chunk-NEM3FY7C.mjs} +2 -1
  43. package/dist/chunk-NEM3FY7C.mjs.map +1 -0
  44. package/dist/chunk-OTHER3YM.mjs +253 -0
  45. package/dist/chunk-OTHER3YM.mjs.map +1 -0
  46. package/dist/chunk-Q2FYFIEY.js +295 -0
  47. package/dist/chunk-Q2FYFIEY.js.map +1 -0
  48. package/dist/chunk-QG4X6H5Y.js +565 -0
  49. package/dist/chunk-QG4X6H5Y.js.map +1 -0
  50. package/dist/chunk-QIEZ6YTG.mjs +295 -0
  51. package/dist/chunk-QIEZ6YTG.mjs.map +1 -0
  52. package/dist/chunk-QOAKHCM7.js +295 -0
  53. package/dist/chunk-QOAKHCM7.js.map +1 -0
  54. package/dist/chunk-QVUD6L5X.js +565 -0
  55. package/dist/chunk-QVUD6L5X.js.map +1 -0
  56. package/dist/{chunk-YERBWZCS.js → chunk-RGLTGKAU.js} +64 -63
  57. package/dist/chunk-RGLTGKAU.js.map +1 -0
  58. package/dist/chunk-SHRK3TVB.js +295 -0
  59. package/dist/chunk-SHRK3TVB.js.map +1 -0
  60. package/dist/chunk-TCH6S42Z.js +529 -0
  61. package/dist/chunk-TCH6S42Z.js.map +1 -0
  62. package/dist/chunk-UCGRFVHC.mjs +253 -0
  63. package/dist/chunk-UCGRFVHC.mjs.map +1 -0
  64. package/dist/chunk-VOISXWVF.mjs +295 -0
  65. package/dist/chunk-VOISXWVF.mjs.map +1 -0
  66. package/dist/chunk-W6BC5INO.mjs +295 -0
  67. package/dist/chunk-W6BC5INO.mjs.map +1 -0
  68. package/dist/chunk-X5WQRO4R.js +295 -0
  69. package/dist/chunk-X5WQRO4R.js.map +1 -0
  70. package/dist/chunk-XDMCVVD3.mjs +585 -0
  71. package/dist/chunk-XDMCVVD3.mjs.map +1 -0
  72. package/dist/chunk-XNTMYLK6.js +76 -0
  73. package/dist/chunk-XNTMYLK6.js.map +1 -0
  74. package/dist/chunk-Y6LI4FDO.js +537 -0
  75. package/dist/chunk-Y6LI4FDO.js.map +1 -0
  76. package/dist/chunk-YZ2AQ6IL.mjs +537 -0
  77. package/dist/chunk-YZ2AQ6IL.mjs.map +1 -0
  78. package/dist/chunk-Z4YJHEXT.js +76 -0
  79. package/dist/chunk-Z4YJHEXT.js.map +1 -0
  80. package/dist/chunk-ZE336SKZ.js +295 -0
  81. package/dist/chunk-ZE336SKZ.js.map +1 -0
  82. package/dist/chunk-ZJD235TO.mjs +565 -0
  83. package/dist/chunk-ZJD235TO.mjs.map +1 -0
  84. package/dist/core-39f27fe8.d.ts +131 -0
  85. package/dist/core-930ea883.d.ts +131 -0
  86. package/dist/core-eb646fe5.d.ts +139 -0
  87. package/dist/helper-06d25b37.d.ts +19 -0
  88. package/dist/helper-48454c0b.d.ts +20 -0
  89. package/dist/helper-6133f78f.d.ts +18 -0
  90. package/dist/helper-867a598d.d.ts +18 -0
  91. package/dist/helper-88b19c66.d.ts +12 -0
  92. package/dist/helper-9e206c66.d.ts +12 -0
  93. package/dist/helper-fcbf6aa8.d.ts +20 -0
  94. package/dist/index.d.ts +27 -32
  95. package/dist/index.js +45 -40
  96. package/dist/index.js.map +1 -0
  97. package/dist/index.mjs +15 -10
  98. package/dist/index.mjs.map +1 -0
  99. package/dist/rpc/bullmq/index.d.ts +10 -6
  100. package/dist/rpc/bullmq/index.js +33 -53
  101. package/dist/rpc/bullmq/index.js.map +1 -0
  102. package/dist/rpc/bullmq/index.mjs +27 -47
  103. package/dist/rpc/bullmq/index.mjs.map +1 -0
  104. package/dist/rpc/kafka/index.d.ts +10 -4
  105. package/dist/rpc/kafka/index.js +21 -37
  106. package/dist/rpc/kafka/index.js.map +1 -0
  107. package/dist/rpc/kafka/index.mjs +16 -32
  108. package/dist/rpc/kafka/index.mjs.map +1 -0
  109. package/dist/rpc/nats/index.d.ts +2 -2
  110. package/dist/rpc/nats/index.js +21 -34
  111. package/dist/rpc/nats/index.js.map +1 -0
  112. package/dist/rpc/nats/index.mjs +14 -27
  113. package/dist/rpc/nats/index.mjs.map +1 -0
  114. package/dist/rpc/rabbitmq/index.d.ts +2 -2
  115. package/dist/rpc/rabbitmq/index.js +24 -37
  116. package/dist/rpc/rabbitmq/index.js.map +1 -0
  117. package/dist/rpc/rabbitmq/index.mjs +15 -28
  118. package/dist/rpc/rabbitmq/index.mjs.map +1 -0
  119. package/dist/rpc/redis/index.d.ts +10 -4
  120. package/dist/rpc/redis/index.js +24 -37
  121. package/dist/rpc/redis/index.js.map +1 -0
  122. package/dist/rpc/redis/index.mjs +17 -30
  123. package/dist/rpc/redis/index.mjs.map +1 -0
  124. package/dist/server/elysia/index.d.ts +4 -3
  125. package/dist/server/elysia/index.js +78 -94
  126. package/dist/server/elysia/index.js.map +1 -0
  127. package/dist/server/elysia/index.mjs +75 -91
  128. package/dist/server/elysia/index.mjs.map +1 -0
  129. package/dist/server/express/index.d.ts +5 -4
  130. package/dist/server/express/index.js +80 -93
  131. package/dist/server/express/index.js.map +1 -0
  132. package/dist/server/express/index.mjs +78 -91
  133. package/dist/server/express/index.mjs.map +1 -0
  134. package/dist/server/fastify/index.d.ts +8 -5
  135. package/dist/server/fastify/index.js +84 -102
  136. package/dist/server/fastify/index.js.map +1 -0
  137. package/dist/server/fastify/index.mjs +80 -98
  138. package/dist/server/fastify/index.mjs.map +1 -0
  139. package/dist/server/h3/index.d.ts +5 -4
  140. package/dist/server/h3/index.js +82 -97
  141. package/dist/server/h3/index.js.map +1 -0
  142. package/dist/server/h3/index.mjs +81 -96
  143. package/dist/server/h3/index.mjs.map +1 -0
  144. package/dist/server/hono/index.d.ts +5 -4
  145. package/dist/server/hono/index.js +74 -90
  146. package/dist/server/hono/index.js.map +1 -0
  147. package/dist/server/hono/index.mjs +73 -89
  148. package/dist/server/hono/index.mjs.map +1 -0
  149. package/dist/server/hyper-express/index.d.ts +6 -5
  150. package/dist/server/hyper-express/index.js +79 -96
  151. package/dist/server/hyper-express/index.js.map +1 -0
  152. package/dist/server/hyper-express/index.mjs +78 -95
  153. package/dist/server/hyper-express/index.mjs.map +1 -0
  154. package/dist/server/koa/index.d.ts +5 -4
  155. package/dist/server/koa/index.js +80 -92
  156. package/dist/server/koa/index.js.map +1 -0
  157. package/dist/server/koa/index.mjs +77 -89
  158. package/dist/server/koa/index.mjs.map +1 -0
  159. package/dist/test.d.ts +1 -1
  160. package/dist/test.js +7 -6
  161. package/dist/test.js.map +1 -0
  162. package/dist/test.mjs +3 -2
  163. package/dist/test.mjs.map +1 -0
  164. package/package.json +8 -7
  165. package/register/index.mjs +40 -40
  166. package/register/loader.mjs +341 -340
  167. package/register/utils.mjs +81 -81
@@ -1,340 +1,341 @@
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 } 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
- const require = createRequire(import.meta.url)
43
- export async function initialize(data) {
44
- if (data)
45
- port = data.port
46
- log('read config...')
47
-
48
- const configPath = resolvePath(
49
- process.cwd(),
50
- process.env.PS_CONFIG_FILE || 'ps.json',
51
- )
52
-
53
- config = require(configPath)
54
- if (!config.virtualFile)
55
- config.virtualFile = {}
56
-
57
- if (!process.env.PS_HMR_BAN) {
58
- chokidar.watch(configPath, { persistent: true }).on('change', () => {
59
- port.postMessage(
60
- JSON.stringify({
61
- type: 'relaunch',
62
- }),
63
- )
64
- })
65
- }
66
-
67
- if (!config.unimport)
68
- return
69
- unimportRet = await genUnImportRet(config.unimport)
70
- await unimportRet.init()
71
- if (unimportRet) {
72
- log('auto import...')
73
- writeFile(
74
- config.unimport.dtsPath || dtsPath,
75
- handleClassTypes(await unimportRet.generateTypeDeclarations()),
76
- )
77
- }
78
- }
79
-
80
- const watchFiles = new Set()
81
- const filesRecord = new Map()
82
- const moduleGraph = {}
83
-
84
- let entryUrl
85
-
86
- function addUrlToGraph(url, parent) {
87
- if (!(url in moduleGraph))
88
- moduleGraph[url] = new Set()
89
-
90
- moduleGraph[url].add(parent)
91
- return url + (filesRecord.has(url) ? `?t=${filesRecord.get(url)}` : '')
92
- }
93
-
94
- function getFileMid(file) {
95
- const filename = basename(file)
96
- const ret = filename.split('.')
97
- if (ret.length === 3)
98
- return ret[1]
99
- else return ''
100
- }
101
-
102
- export const resolve = async (specifier, context, nextResolve) => {
103
- // virtual file
104
- if (config.virtualFile[specifier]) {
105
- return {
106
- format: 'ts',
107
- url: specifier,
108
- shortCircuit: true,
109
- }
110
- }
111
- // entrypoint
112
- if (!context.parentURL) {
113
- entryUrl = specifier
114
- return {
115
- format: EXTENSIONS.some(ext => specifier.endsWith(ext))
116
- ? 'ts'
117
- : undefined,
118
- url: specifier,
119
- shortCircuit: true,
120
- }
121
- }
122
- // url import
123
- if (/^file:\/\/\//.test(specifier) && extname(specifier) === '.ts') {
124
- const url = addUrlToGraph(specifier, context.parentURL.split('?')[0])
125
-
126
- return {
127
- format: 'ts',
128
- url,
129
- shortCircuit: true,
130
- }
131
- }
132
-
133
- // hmr import
134
- if (
135
- context.parentURL.includes('/node_modules/phecda-server')
136
- && isAbsolute(specifier)
137
- ) {
138
- specifier = relative(fileURLToPath(entryUrl), specifier)
139
- .replace(/\.ts$/, '')
140
- .slice(1)
141
- context.parentURL = entryUrl
142
- }
143
-
144
- // import/require from external library
145
- if (context.parentURL.includes('/node_modules/'))
146
- return nextResolve(specifier)
147
- const { resolvedModule } = ts.resolveModuleName(
148
- specifier,
149
- fileURLToPath(context.parentURL),
150
- tsconfig,
151
- host,
152
- moduleResolutionCache,
153
- )
154
- // import from local project to local project TS file
155
- if (
156
- resolvedModule
157
- && !resolvedModule.resolvedFileName.includes('/node_modules/')
158
- && EXTENSIONS.includes(resolvedModule.extension)
159
- ) {
160
- const url = addUrlToGraph(
161
- pathToFileURL(resolvedModule.resolvedFileName).href,
162
- context.parentURL.split('?')[0],
163
- )
164
-
165
- const importerMid = getFileMid(context.parentURL)
166
- const sourceMid = getFileMid(resolvedModule.resolvedFileName)
167
- if (config.resolve && importerMid && sourceMid) {
168
- const resolver = config.resolve.find(
169
- item => item.source === sourceMid && item.importer === importerMid,
170
- )
171
- if (resolver) {
172
- return {
173
- format: 'ts',
174
- url: pathToFileURL(resolvePath(process.cwd(), resolver.path)).href,
175
- shortCircuit: true,
176
- }
177
- }
178
- }
179
-
180
- return {
181
- format: 'ts',
182
- url,
183
- shortCircuit: true,
184
- }
185
- }
186
-
187
- return nextResolve(specifier)
188
- }
189
- // @todo the first params may be url or path, need to distinguish
190
-
191
- export const load = async (url, context, nextLoad) => {
192
- if (config.virtualFile[url]) {
193
- return {
194
- format: 'module',
195
- source: config.virtualFile[url],
196
- shortCircuit: true,
197
- }
198
- }
199
-
200
- url = url.split('?')[0]
201
- if (
202
- !url.includes('/node_modules/')
203
- && url.startsWith('file://')
204
- && !watchFiles.has(url)
205
- && !isLowVersion
206
- ) {
207
- watchFiles.add(url)
208
- // watch(
209
- // fileURLToPath(url),
210
- // debounce((type) => {
211
- // if (type === 'change') {
212
- // try {
213
- // const files = [...findTopScope(url, Date.now())].reverse()
214
-
215
- // port.postMessage(
216
- // JSON.stringify({
217
- // type: 'change',
218
- // files,
219
- // }),
220
- // )
221
- // }
222
- // catch (e) {
223
- // port.postMessage(
224
- // JSON.stringify({
225
- // type: 'relaunch',
226
- // }),
227
- // )
228
- // }
229
- // }
230
- // }),
231
- // )
232
-
233
- if (!process.env.PS_HMR_BAN) {
234
- chokidar.watch(fileURLToPath(url), { persistent: true }).on(
235
- 'change',
236
- debounce(() => {
237
- try {
238
- const files = [...findTopScope(url, Date.now())].reverse()
239
-
240
- port.postMessage(
241
- JSON.stringify({
242
- type: 'change',
243
- files,
244
- }),
245
- )
246
- }
247
- catch (e) {
248
- port.postMessage(
249
- JSON.stringify({
250
- type: 'relaunch',
251
- }),
252
- )
253
- }
254
- }),
255
- )
256
- }
257
- }
258
- // resolveModuleName failed
259
- // I don't know why it failed
260
- if (!context.format && url.endsWith('.ts'))
261
- context.format = 'ts'
262
-
263
- if (context.format === 'ts') {
264
- const { source } = await nextLoad(url, context)
265
-
266
- const code
267
- = typeof source === 'string' ? source : Buffer.from(source).toString()
268
- const compiled = await compile(code, url)
269
- if (unimportRet) {
270
- const { injectImports } = unimportRet
271
- return {
272
- format: 'module',
273
- source: (
274
- await injectImports(compiled, (url.startsWith('file://') ? fileURLToPath(url) : url).replace(/\\/g, '/'))
275
- ).code,
276
- shortCircuit: true,
277
- }
278
- }
279
- return {
280
- format: 'module',
281
- source: compiled,
282
- shortCircuit: true,
283
- }
284
- }
285
- else {
286
- return nextLoad(url, context)
287
- }
288
- }
289
-
290
- function findTopScope(url, time, modules = new Set()) {
291
- filesRecord.set(url, time)
292
- if (isModuleFileUrl(url)) {
293
- modules.add(fileURLToPath(url))
294
- }
295
- else {
296
- if (!moduleGraph[url])
297
- throw new Error('root file update')
298
- for (const i of [...moduleGraph[url]]) findTopScope(i, time, modules)
299
- }
300
-
301
- return modules
302
- }
303
-
304
- function debounce(cb, timeout = 500) {
305
- let timer
306
- return (...args) => {
307
- if (timer)
308
- return
309
-
310
- timer = setTimeout(() => {
311
- cb(...args)
312
- timer = undefined
313
- }, timeout)
314
- }
315
- }
316
-
317
- export function isModuleFileUrl(url) {
318
- const midName = getFileMid(url)
319
- if (!midName)
320
- return false
321
- if (
322
- [
323
- 'controller',
324
- 'rpc',
325
- 'service',
326
- 'module',
327
- 'extension',
328
- 'ext',
329
- 'guard',
330
- 'interceptor',
331
- 'plugin',
332
- 'filter',
333
- 'pipe',
334
- 'edge',
335
- ].includes(midName)
336
- )
337
- return true
338
-
339
- return config.moduleFile && config.moduleFile.includes(midName)
340
- }
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 } 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
+ const require = createRequire(import.meta.url)
43
+ export async function initialize(data) {
44
+ if (data)
45
+ port = data.port
46
+ log('read config...')
47
+
48
+ const configPath = resolvePath(
49
+ process.cwd(),
50
+ process.env.PS_CONFIG_FILE || 'ps.json',
51
+ )
52
+
53
+ config = require(configPath)
54
+ if (!config.virtualFile)
55
+ config.virtualFile = {}
56
+
57
+ if (!process.env.PS_HMR_BAN) {
58
+ chokidar.watch(configPath, { persistent: true }).on('change', () => {
59
+ port.postMessage(
60
+ JSON.stringify({
61
+ type: 'relaunch',
62
+ }),
63
+ )
64
+ })
65
+ }
66
+
67
+ if (!config.unimport)
68
+ return
69
+ unimportRet = await genUnImportRet(config.unimport)
70
+ if (unimportRet) {
71
+ log('auto import...')
72
+ await unimportRet.init()
73
+
74
+ writeFile(
75
+ config.unimport.dtsPath || dtsPath,
76
+ handleClassTypes(await unimportRet.generateTypeDeclarations()),
77
+ )
78
+ }
79
+ }
80
+
81
+ const watchFiles = new Set()
82
+ const filesRecord = new Map()
83
+ const moduleGraph = {}
84
+
85
+ let entryUrl
86
+
87
+ function addUrlToGraph(url, parent) {
88
+ if (!(url in moduleGraph))
89
+ moduleGraph[url] = new Set()
90
+
91
+ moduleGraph[url].add(parent)
92
+ return url + (filesRecord.has(url) ? `?t=${filesRecord.get(url)}` : '')
93
+ }
94
+
95
+ function getFileMid(file) {
96
+ const filename = basename(file)
97
+ const ret = filename.split('.')
98
+ if (ret.length === 3)
99
+ return ret[1]
100
+ else return ''
101
+ }
102
+
103
+ export const resolve = async (specifier, context, nextResolve) => {
104
+ // virtual file
105
+ if (config.virtualFile[specifier]) {
106
+ return {
107
+ format: 'ts',
108
+ url: specifier,
109
+ shortCircuit: true,
110
+ }
111
+ }
112
+ // entrypoint
113
+ if (!context.parentURL) {
114
+ entryUrl = specifier
115
+ return {
116
+ format: EXTENSIONS.some(ext => specifier.endsWith(ext))
117
+ ? 'ts'
118
+ : undefined,
119
+ url: specifier,
120
+ shortCircuit: true,
121
+ }
122
+ }
123
+ // url import
124
+ // it seems useless
125
+ if (/^file:\/\/\//.test(specifier) && extname(specifier) === '.ts') {
126
+ const url = addUrlToGraph(specifier, context.parentURL.split('?')[0])
127
+ return {
128
+ format: 'ts',
129
+ url,
130
+ shortCircuit: true,
131
+ }
132
+ }
133
+
134
+ // hmr import
135
+ if (
136
+ context.parentURL.includes('/node_modules/phecda-server')
137
+ && isAbsolute(specifier)
138
+ ) {
139
+ specifier = relative(fileURLToPath(entryUrl), specifier)
140
+ .replace(/\.ts$/, '')
141
+ .slice(1)
142
+ context.parentURL = entryUrl
143
+ }
144
+
145
+ // import/require from external library
146
+ if (context.parentURL.includes('/node_modules/'))
147
+ return nextResolve(specifier)
148
+ const { resolvedModule } = ts.resolveModuleName(
149
+ specifier,
150
+ fileURLToPath(context.parentURL),
151
+ tsconfig,
152
+ host,
153
+ moduleResolutionCache,
154
+ )
155
+ // import between loacl projects
156
+ if (
157
+ resolvedModule
158
+ && !resolvedModule.resolvedFileName.includes('/node_modules/')
159
+ && EXTENSIONS.includes(resolvedModule.extension)
160
+ ) {
161
+ const url = addUrlToGraph(
162
+ pathToFileURL(resolvedModule.resolvedFileName).href,
163
+ context.parentURL.split('?')[0],
164
+ )
165
+
166
+ const importerMid = getFileMid(context.parentURL)
167
+ const sourceMid = getFileMid(resolvedModule.resolvedFileName)
168
+ if (config.resolve && importerMid && sourceMid) {
169
+ const resolver = config.resolve.find(
170
+ item => item.source === sourceMid && item.importer === importerMid,
171
+ )
172
+ if (resolver) {
173
+ return {
174
+ format: 'ts',
175
+ url: pathToFileURL(resolvePath(process.cwd(), resolver.path)).href,
176
+ shortCircuit: true,
177
+ }
178
+ }
179
+ }
180
+
181
+ return {
182
+ format: 'ts',
183
+ url,
184
+ shortCircuit: true,
185
+ }
186
+ }
187
+
188
+ return nextResolve(specifier)
189
+ }
190
+ // @todo the first params may be url or path, need to distinguish
191
+
192
+ export const load = async (url, context, nextLoad) => {
193
+ if (config.virtualFile[url]) {
194
+ return {
195
+ format: 'module',
196
+ source: config.virtualFile[url],
197
+ shortCircuit: true,
198
+ }
199
+ }
200
+
201
+ url = url.split('?')[0]
202
+ if (
203
+ !url.includes('/node_modules/')
204
+ && url.startsWith('file://')
205
+ && !watchFiles.has(url)
206
+ && !isLowVersion
207
+ ) {
208
+ watchFiles.add(url)
209
+ // watch(
210
+ // fileURLToPath(url),
211
+ // debounce((type) => {
212
+ // if (type === 'change') {
213
+ // try {
214
+ // const files = [...findTopScope(url, Date.now())].reverse()
215
+
216
+ // port.postMessage(
217
+ // JSON.stringify({
218
+ // type: 'change',
219
+ // files,
220
+ // }),
221
+ // )
222
+ // }
223
+ // catch (e) {
224
+ // port.postMessage(
225
+ // JSON.stringify({
226
+ // type: 'relaunch',
227
+ // }),
228
+ // )
229
+ // }
230
+ // }
231
+ // }),
232
+ // )
233
+
234
+ if (!process.env.PS_HMR_BAN) {
235
+ chokidar.watch(fileURLToPath(url), { persistent: true }).on(
236
+ 'change',
237
+ debounce(() => {
238
+ try {
239
+ const files = [...findTopScope(url, Date.now())].reverse()
240
+
241
+ port.postMessage(
242
+ JSON.stringify({
243
+ type: 'change',
244
+ files,
245
+ }),
246
+ )
247
+ }
248
+ catch (e) {
249
+ port.postMessage(
250
+ JSON.stringify({
251
+ type: 'relaunch',
252
+ }),
253
+ )
254
+ }
255
+ }),
256
+ )
257
+ }
258
+ }
259
+ // resolveModuleName failed
260
+ // I don't know why it failed
261
+ if (!context.format && url.endsWith('.ts'))
262
+ context.format = 'ts'
263
+
264
+ if (context.format === 'ts') {
265
+ const { source } = await nextLoad(url, context)
266
+
267
+ const code
268
+ = typeof source === 'string' ? source : Buffer.from(source).toString()
269
+ const compiled = await compile(code, url)
270
+ if (unimportRet) {
271
+ const { injectImports } = unimportRet
272
+ return {
273
+ format: 'module',
274
+ source: (
275
+ await injectImports(compiled, (url.startsWith('file://') ? fileURLToPath(url) : url).replace(/\\/g, '/'))
276
+ ).code,
277
+ shortCircuit: true,
278
+ }
279
+ }
280
+ return {
281
+ format: 'module',
282
+ source: compiled,
283
+ shortCircuit: true,
284
+ }
285
+ }
286
+ else {
287
+ return nextLoad(url, context)
288
+ }
289
+ }
290
+
291
+ function findTopScope(url, time, modules = new Set()) {
292
+ filesRecord.set(url, time)
293
+ if (isModuleFileUrl(url)) {
294
+ modules.add(fileURLToPath(url))
295
+ }
296
+ else {
297
+ if (!moduleGraph[url])
298
+ throw new Error('root file update')
299
+ for (const i of [...moduleGraph[url]]) findTopScope(i, time, modules)
300
+ }
301
+
302
+ return modules
303
+ }
304
+
305
+ function debounce(cb, timeout = 500) {
306
+ let timer
307
+ return (...args) => {
308
+ if (timer)
309
+ return
310
+
311
+ timer = setTimeout(() => {
312
+ cb(...args)
313
+ timer = undefined
314
+ }, timeout)
315
+ }
316
+ }
317
+
318
+ export function isModuleFileUrl(url) {
319
+ const midName = getFileMid(url)
320
+ if (!midName)
321
+ return false
322
+ if (
323
+ [
324
+ 'controller',
325
+ 'rpc',
326
+ 'service',
327
+ 'module',
328
+ 'extension',
329
+ 'ext',
330
+ 'guard',
331
+ 'interceptor',
332
+ 'plugin',
333
+ 'filter',
334
+ 'pipe',
335
+ 'edge',
336
+ ].includes(midName)
337
+ )
338
+ return true
339
+
340
+ return config.moduleFile && config.moduleFile.includes(midName)
341
+ }