@c9up/ream 0.2.28 → 0.2.30
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.
- package/README.md +5 -6
- package/dist/Codemods.d.ts +24 -0
- package/dist/Codemods.d.ts.map +1 -1
- package/dist/Codemods.js +211 -1
- package/dist/Codemods.js.map +1 -1
- package/dist/HttpKernel.d.ts.map +1 -1
- package/dist/HttpKernel.js +17 -5
- package/dist/HttpKernel.js.map +1 -1
- package/dist/Ignitor.d.ts +15 -2
- package/dist/Ignitor.d.ts.map +1 -1
- package/dist/Ignitor.js +33 -23
- package/dist/Ignitor.js.map +1 -1
- package/dist/bodyparser/BodyParserMiddleware.d.ts +4 -4
- package/dist/bodyparser/BodyParserMiddleware.d.ts.map +1 -1
- package/dist/bodyparser/BodyParserMiddleware.js +41 -11
- package/dist/bodyparser/BodyParserMiddleware.js.map +1 -1
- package/dist/bodyparser/MultipartFile.d.ts +21 -15
- package/dist/bodyparser/MultipartFile.d.ts.map +1 -1
- package/dist/bodyparser/MultipartFile.js +40 -58
- package/dist/bodyparser/MultipartFile.js.map +1 -1
- package/dist/bodyparser/parseSize.d.ts +7 -4
- package/dist/bodyparser/parseSize.d.ts.map +1 -1
- package/dist/bodyparser/parseSize.js +12 -17
- package/dist/bodyparser/parseSize.js.map +1 -1
- package/dist/bodyparser/qsParse.d.ts +20 -1
- package/dist/bodyparser/qsParse.d.ts.map +1 -1
- package/dist/bodyparser/qsParse.js +78 -25
- package/dist/bodyparser/qsParse.js.map +1 -1
- package/dist/codemods/source.d.ts +57 -0
- package/dist/codemods/source.d.ts.map +1 -0
- package/dist/codemods/source.js +282 -0
- package/dist/codemods/source.js.map +1 -0
- package/dist/console/prompts.d.ts.map +1 -1
- package/dist/console/prompts.js +3 -1
- package/dist/console/prompts.js.map +1 -1
- package/dist/container/Container.d.ts.map +1 -1
- package/dist/container/Container.js +61 -71
- package/dist/container/Container.js.map +1 -1
- package/dist/events/Emitter.d.ts +12 -0
- package/dist/events/Emitter.d.ts.map +1 -1
- package/dist/events/Emitter.js +36 -9
- package/dist/events/Emitter.js.map +1 -1
- package/dist/events/helix/helpers.d.ts.map +1 -1
- package/dist/events/helix/helpers.js +19 -9
- package/dist/events/helix/helpers.js.map +1 -1
- package/dist/graphql/GraphQLEngine.d.ts +8 -0
- package/dist/graphql/GraphQLEngine.d.ts.map +1 -1
- package/dist/graphql/GraphQLEngine.js +79 -12
- package/dist/graphql/GraphQLEngine.js.map +1 -1
- package/dist/helpers/MessageBuilder.d.ts +4 -2
- package/dist/helpers/MessageBuilder.d.ts.map +1 -1
- package/dist/helpers/MessageBuilder.js +4 -2
- package/dist/helpers/MessageBuilder.js.map +1 -1
- package/dist/helpers/errors.d.ts +11 -0
- package/dist/helpers/errors.d.ts.map +1 -0
- package/dist/helpers/errors.js +17 -0
- package/dist/helpers/errors.js.map +1 -0
- package/dist/helpers/napi-loader.d.ts.map +1 -1
- package/dist/helpers/napi-loader.js +3 -2
- package/dist/helpers/napi-loader.js.map +1 -1
- package/dist/http/Exception.d.ts +14 -1
- package/dist/http/Exception.d.ts.map +1 -1
- package/dist/http/Exception.js +10 -2
- package/dist/http/Exception.js.map +1 -1
- package/dist/http/HttpContext.d.ts +31 -2
- package/dist/http/HttpContext.d.ts.map +1 -1
- package/dist/http/HttpContext.js +12 -5
- package/dist/http/HttpContext.js.map +1 -1
- package/dist/http/RedirectBuilder.d.ts +9 -3
- package/dist/http/RedirectBuilder.d.ts.map +1 -1
- package/dist/http/RedirectBuilder.js +43 -37
- package/dist/http/RedirectBuilder.js.map +1 -1
- package/dist/http/Request.d.ts +42 -17
- package/dist/http/Request.d.ts.map +1 -1
- package/dist/http/Request.js +80 -58
- package/dist/http/Request.js.map +1 -1
- package/dist/http/Response.d.ts +7 -4
- package/dist/http/Response.d.ts.map +1 -1
- package/dist/http/Response.js +14 -6
- package/dist/http/Response.js.map +1 -1
- package/dist/http/SseStream.js +6 -7
- package/dist/http/SseStream.js.map +1 -1
- package/dist/http/permissions.d.ts +25 -0
- package/dist/http/permissions.d.ts.map +1 -0
- package/dist/http/permissions.js +38 -0
- package/dist/http/permissions.js.map +1 -0
- package/dist/http-client/HttpClient.d.ts +111 -0
- package/dist/http-client/HttpClient.d.ts.map +1 -0
- package/dist/http-client/HttpClient.js +386 -0
- package/dist/http-client/HttpClient.js.map +1 -0
- package/dist/http-client/addresses.d.ts +14 -0
- package/dist/http-client/addresses.d.ts.map +1 -0
- package/dist/http-client/addresses.js +57 -0
- package/dist/http-client/addresses.js.map +1 -0
- package/dist/http-client/fake.d.ts +50 -0
- package/dist/http-client/fake.d.ts.map +1 -0
- package/dist/http-client/fake.js +95 -0
- package/dist/http-client/fake.js.map +1 -0
- package/dist/http-client/index.d.ts +7 -0
- package/dist/http-client/index.d.ts.map +1 -0
- package/dist/http-client/index.js +7 -0
- package/dist/http-client/index.js.map +1 -0
- package/dist/index.d.ts +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/middleware/Pipeline.d.ts.map +1 -1
- package/dist/middleware/Pipeline.js +6 -3
- package/dist/middleware/Pipeline.js.map +1 -1
- package/dist/native/generated.d.ts +93 -36
- package/dist/native/generated.d.ts.map +1 -1
- package/dist/profiler/Profiler.d.ts.map +1 -1
- package/dist/profiler/Profiler.js +4 -1
- package/dist/profiler/Profiler.js.map +1 -1
- package/dist/profiler/client.generated.d.ts +5 -0
- package/dist/profiler/client.generated.d.ts.map +1 -0
- package/dist/profiler/client.generated.js +6 -0
- package/dist/profiler/client.generated.js.map +1 -0
- package/dist/profiler/collectors.d.ts +92 -13
- package/dist/profiler/collectors.d.ts.map +1 -1
- package/dist/profiler/collectors.js +106 -19
- package/dist/profiler/collectors.js.map +1 -1
- package/dist/profiler/endpoint.d.ts +2 -1
- package/dist/profiler/endpoint.d.ts.map +1 -1
- package/dist/profiler/endpoint.js +25 -1
- package/dist/profiler/endpoint.js.map +1 -1
- package/dist/profiler/index.d.ts +8 -4
- package/dist/profiler/index.d.ts.map +1 -1
- package/dist/profiler/index.js +11 -4
- package/dist/profiler/index.js.map +1 -1
- package/dist/profiler/middleware.d.ts.map +1 -1
- package/dist/profiler/middleware.js +76 -10
- package/dist/profiler/middleware.js.map +1 -1
- package/dist/profiler/preview.d.ts +17 -0
- package/dist/profiler/preview.d.ts.map +1 -0
- package/dist/profiler/preview.js +100 -0
- package/dist/profiler/preview.js.map +1 -0
- package/dist/profiler/toolbar.d.ts +15 -23
- package/dist/profiler/toolbar.d.ts.map +1 -1
- package/dist/profiler/toolbar.js +25 -91
- package/dist/profiler/toolbar.js.map +1 -1
- package/dist/profiler/types.d.ts +6 -1
- package/dist/profiler/types.d.ts.map +1 -1
- package/dist/router/Router.d.ts +6 -0
- package/dist/router/Router.d.ts.map +1 -1
- package/dist/router/Router.js +115 -12
- package/dist/router/Router.js.map +1 -1
- package/dist/rpc/RpcProvider.d.ts +6 -0
- package/dist/rpc/RpcProvider.d.ts.map +1 -1
- package/dist/rpc/RpcProvider.js +4 -1
- package/dist/rpc/RpcProvider.js.map +1 -1
- package/dist/rpc/RpcRouter.d.ts +27 -14
- package/dist/rpc/RpcRouter.d.ts.map +1 -1
- package/dist/rpc/RpcRouter.js +97 -40
- package/dist/rpc/RpcRouter.js.map +1 -1
- package/dist/scheduler/Scheduler.js +1 -1
- package/dist/scheduler/Scheduler.js.map +1 -1
- package/dist/scheduler/locks/RedisLockBackend.d.ts.map +1 -1
- package/dist/scheduler/locks/RedisLockBackend.js +13 -2
- package/dist/scheduler/locks/RedisLockBackend.js.map +1 -1
- package/dist/security/CookieSigner.d.ts.map +1 -1
- package/dist/security/CookieSigner.js +32 -8
- package/dist/security/CookieSigner.js.map +1 -1
- package/dist/security/SignedUrl.d.ts.map +1 -1
- package/dist/security/SignedUrl.js +16 -19
- package/dist/security/SignedUrl.js.map +1 -1
- package/dist/server/Server.d.ts +44 -12
- package/dist/server/Server.d.ts.map +1 -1
- package/dist/server/Server.js +31 -10
- package/dist/server/Server.js.map +1 -1
- package/dist/server/nativeGrpc.d.ts +27 -0
- package/dist/server/nativeGrpc.d.ts.map +1 -0
- package/dist/server/nativeGrpc.js +47 -0
- package/dist/server/nativeGrpc.js.map +1 -0
- package/dist/server/nativeLimits.d.ts +57 -0
- package/dist/server/nativeLimits.d.ts.map +1 -0
- package/dist/server/nativeLimits.js +75 -0
- package/dist/server/nativeLimits.js.map +1 -0
- package/dist/session/Session.d.ts +12 -0
- package/dist/session/Session.d.ts.map +1 -1
- package/dist/session/Session.js +13 -4
- package/dist/session/Session.js.map +1 -1
- package/dist/session/SessionMiddleware.d.ts.map +1 -1
- package/dist/session/SessionMiddleware.js +28 -9
- package/dist/session/SessionMiddleware.js.map +1 -1
- package/dist/session/config.d.ts +5 -0
- package/dist/session/config.d.ts.map +1 -1
- package/dist/session/config.js +8 -0
- package/dist/session/config.js.map +1 -1
- package/dist/session/drivers/MemoryDriver.d.ts.map +1 -1
- package/dist/session/drivers/MemoryDriver.js +26 -7
- package/dist/session/drivers/MemoryDriver.js.map +1 -1
- package/dist/session/errors.d.ts +17 -0
- package/dist/session/errors.d.ts.map +1 -1
- package/dist/session/errors.js +21 -0
- package/dist/session/errors.js.map +1 -1
- package/dist/session/templateTags.d.ts +14 -0
- package/dist/session/templateTags.d.ts.map +1 -1
- package/dist/session/templateTags.js +45 -17
- package/dist/session/templateTags.js.map +1 -1
- package/dist/storage/StaticMiddleware.d.ts.map +1 -1
- package/dist/storage/StaticMiddleware.js +49 -27
- package/dist/storage/StaticMiddleware.js.map +1 -1
- package/dist/testing/ApiResponse.d.ts.map +1 -1
- package/dist/testing/ApiResponse.js +7 -1
- package/dist/testing/ApiResponse.js.map +1 -1
- package/dist/testing/TestClient.d.ts.map +1 -1
- package/dist/testing/TestClient.js +16 -4
- package/dist/testing/TestClient.js.map +1 -1
- package/dist/utils/Macroable.d.ts +1 -1
- package/dist/utils/Macroable.js +2 -2
- package/dist/utils/Macroable.js.map +1 -1
- package/events.darwin-arm64.node +0 -0
- package/events.darwin-x64.node +0 -0
- package/events.linux-arm64-gnu.node +0 -0
- package/events.linux-x64-gnu.node +0 -0
- package/events.win32-x64-msvc.node +0 -0
- package/index.darwin-arm64.node +0 -0
- package/index.darwin-x64.node +0 -0
- package/index.linux-arm64-gnu.node +0 -0
- package/index.linux-x64-gnu.node +0 -0
- package/index.win32-x64-msvc.node +0 -0
- package/package.json +11 -3
- package/scheduler.darwin-arm64.node +0 -0
- package/scheduler.darwin-x64.node +0 -0
- package/scheduler.linux-arm64-gnu.node +0 -0
- package/scheduler.linux-x64-gnu.node +0 -0
- package/scheduler.win32-x64-msvc.node +0 -0
- package/src/Codemods.ts +314 -3
- package/src/HttpKernel.ts +18 -7
- package/src/Ignitor.ts +58 -26
- package/src/bodyparser/BodyParserMiddleware.ts +45 -16
- package/src/bodyparser/MultipartFile.ts +46 -67
- package/src/bodyparser/parseSize.ts +17 -17
- package/src/bodyparser/qsParse.ts +96 -26
- package/src/codemods/source.ts +303 -0
- package/src/console/prompts.ts +3 -1
- package/src/container/Container.ts +97 -81
- package/src/events/Emitter.ts +37 -10
- package/src/events/helix/helpers.ts +24 -19
- package/src/graphql/GraphQLEngine.ts +91 -14
- package/src/helpers/MessageBuilder.ts +4 -2
- package/src/helpers/errors.ts +16 -0
- package/src/helpers/napi-loader.ts +3 -2
- package/src/http/Exception.ts +17 -2
- package/src/http/HttpContext.ts +34 -5
- package/src/http/RedirectBuilder.ts +51 -37
- package/src/http/Request.ts +102 -58
- package/src/http/Response.ts +15 -7
- package/src/http/SseStream.ts +6 -7
- package/src/http/permissions.ts +47 -0
- package/src/http-client/HttpClient.ts +505 -0
- package/src/http-client/addresses.ts +58 -0
- package/src/http-client/fake.ts +141 -0
- package/src/http-client/index.ts +21 -0
- package/src/index.ts +6 -1
- package/src/middleware/Pipeline.ts +7 -3
- package/src/native/generated.ts +106 -48
- package/src/profiler/Profiler.ts +4 -1
- package/src/profiler/client/toolbar.css +595 -0
- package/src/profiler/client/toolbar.js +1299 -0
- package/src/profiler/client.generated.ts +7 -0
- package/src/profiler/collectors.ts +156 -19
- package/src/profiler/endpoint.ts +27 -1
- package/src/profiler/index.ts +17 -3
- package/src/profiler/middleware.ts +74 -9
- package/src/profiler/preview.ts +104 -0
- package/src/profiler/toolbar.ts +28 -91
- package/src/profiler/types.ts +6 -1
- package/src/router/Router.ts +136 -13
- package/src/rpc/RpcProvider.ts +10 -1
- package/src/rpc/RpcRouter.ts +129 -45
- package/src/scheduler/Scheduler.ts +1 -1
- package/src/scheduler/locks/RedisLockBackend.ts +12 -4
- package/src/security/CookieSigner.ts +30 -8
- package/src/security/SignedUrl.ts +18 -17
- package/src/server/Server.ts +60 -12
- package/src/server/nativeGrpc.ts +59 -0
- package/src/server/nativeLimits.ts +111 -0
- package/src/session/Session.ts +29 -4
- package/src/session/SessionMiddleware.ts +30 -10
- package/src/session/config.ts +7 -0
- package/src/session/drivers/MemoryDriver.ts +26 -7
- package/src/session/errors.ts +31 -0
- package/src/session/templateTags.ts +57 -0
- package/src/storage/StaticMiddleware.ts +46 -27
- package/src/testing/ApiResponse.ts +7 -1
- package/src/testing/TestClient.ts +14 -5
- package/src/utils/Macroable.ts +2 -2
- package/scripts/build-napi-types.mjs +0 -69
- package/scripts/copy-napi.mjs +0 -121
- package/scripts/generate-mime.mjs +0 -119
- package/scripts/generate-napi-types.mjs +0 -187
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Just enough of a TypeScript scanner for the configure codemods: find a
|
|
3
|
+
* call or an object/array literal in CODE (never inside a string, a template
|
|
4
|
+
* or a comment), split a literal into its top-level entries, and append to
|
|
5
|
+
* one. Upstream does this with a full AST; ream ships no compiler, and the
|
|
6
|
+
* files these codemods edit (`start/env.ts`, `reamrc.ts`) are object and
|
|
7
|
+
* array literals.
|
|
8
|
+
*
|
|
9
|
+
* Not handled: regular-expression literals (a quote inside one reads as the
|
|
10
|
+
* start of a string). Neither file has a reason to contain one.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const CLOSERS: Record<string, string> = { '{': '}', '[': ']', '(': ')' }
|
|
14
|
+
|
|
15
|
+
function isIdentifierChar(char: string | undefined): boolean {
|
|
16
|
+
return char !== undefined && /[A-Za-z0-9_$]/.test(char)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* The index just past the string, template or comment starting at `i`, or
|
|
21
|
+
* `i` itself when none starts there. An unterminated one runs to the end.
|
|
22
|
+
*/
|
|
23
|
+
function skipNonCode(src: string, i: number): number {
|
|
24
|
+
const char = src[i]
|
|
25
|
+
const next = src[i + 1]
|
|
26
|
+
if (char === '/' && next === '/') {
|
|
27
|
+
const end = src.indexOf('\n', i)
|
|
28
|
+
return end === -1 ? src.length : end
|
|
29
|
+
}
|
|
30
|
+
if (char === '/' && next === '*') {
|
|
31
|
+
const end = src.indexOf('*/', i + 2)
|
|
32
|
+
return end === -1 ? src.length : end + 2
|
|
33
|
+
}
|
|
34
|
+
if (char === "'" || char === '"') {
|
|
35
|
+
let j = i + 1
|
|
36
|
+
while (j < src.length && src[j] !== char && src[j] !== '\n') {
|
|
37
|
+
j += src[j] === '\\' ? 2 : 1
|
|
38
|
+
}
|
|
39
|
+
return j + 1
|
|
40
|
+
}
|
|
41
|
+
if (char === '`') {
|
|
42
|
+
let j = i + 1
|
|
43
|
+
while (j < src.length && src[j] !== '`') {
|
|
44
|
+
if (src[j] === '\\') {
|
|
45
|
+
j += 2
|
|
46
|
+
} else if (src[j] === '$' && src[j + 1] === '{') {
|
|
47
|
+
const close = matchClose(src, j + 1)
|
|
48
|
+
j = close === -1 ? src.length : close + 1
|
|
49
|
+
} else {
|
|
50
|
+
j += 1
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return j + 1
|
|
54
|
+
}
|
|
55
|
+
return i
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** Whether the string, template or block comment starting at `i` is closed. */
|
|
59
|
+
function isTerminated(src: string, i: number): boolean {
|
|
60
|
+
const char = src[i]
|
|
61
|
+
if (char === '/') return src.indexOf('*/', i + 2) !== -1
|
|
62
|
+
const end = skipNonCode(src, i)
|
|
63
|
+
return end <= src.length && end - 1 > i && src[end - 1] === char
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** Index of the bracket closing the one at `open`, or -1. */
|
|
67
|
+
export function matchClose(src: string, open: number): number {
|
|
68
|
+
const first = CLOSERS[src[open] ?? '']
|
|
69
|
+
if (first === undefined) return -1
|
|
70
|
+
const stack = [first]
|
|
71
|
+
let i = open + 1
|
|
72
|
+
while (i < src.length) {
|
|
73
|
+
const skipped = skipNonCode(src, i)
|
|
74
|
+
if (skipped !== i) {
|
|
75
|
+
i = skipped
|
|
76
|
+
continue
|
|
77
|
+
}
|
|
78
|
+
const char = src[i] ?? ''
|
|
79
|
+
const closer = CLOSERS[char]
|
|
80
|
+
if (closer !== undefined) {
|
|
81
|
+
stack.push(closer)
|
|
82
|
+
} else if (char === stack[stack.length - 1]) {
|
|
83
|
+
stack.pop()
|
|
84
|
+
if (stack.length === 0) return i
|
|
85
|
+
} else if (char === '}' || char === ']' || char === ')') {
|
|
86
|
+
return -1
|
|
87
|
+
}
|
|
88
|
+
i += 1
|
|
89
|
+
}
|
|
90
|
+
return -1
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** First code character at or after `i` (before `end`), skipping whitespace and comments. */
|
|
94
|
+
function firstCode(src: string, i: number, end: number): number {
|
|
95
|
+
let j = i
|
|
96
|
+
while (j < end) {
|
|
97
|
+
const char = src[j] ?? ''
|
|
98
|
+
if (/\s/.test(char)) {
|
|
99
|
+
j += 1
|
|
100
|
+
continue
|
|
101
|
+
}
|
|
102
|
+
if (char === '/' && (src[j + 1] === '/' || src[j + 1] === '*')) {
|
|
103
|
+
j = skipNonCode(src, j)
|
|
104
|
+
continue
|
|
105
|
+
}
|
|
106
|
+
return j
|
|
107
|
+
}
|
|
108
|
+
return end
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** One top-level entry of a literal: the text between two commas. */
|
|
112
|
+
export interface Segment {
|
|
113
|
+
start: number
|
|
114
|
+
end: number
|
|
115
|
+
/** First code character, or `end` when the entry is only trivia. */
|
|
116
|
+
codeStart: number
|
|
117
|
+
/** Just past the last code character (comments and whitespace excluded). */
|
|
118
|
+
codeEnd: number
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** Split `src[start, end)` on its top-level commas. */
|
|
122
|
+
export function segments(src: string, start: number, end: number): Segment[] {
|
|
123
|
+
const out: Segment[] = []
|
|
124
|
+
let segmentStart = start
|
|
125
|
+
let codeEnd = start
|
|
126
|
+
let depth = 0
|
|
127
|
+
let i = start
|
|
128
|
+
const close = (at: number) => {
|
|
129
|
+
const codeStart = firstCode(src, segmentStart, at)
|
|
130
|
+
out.push({ start: segmentStart, end: at, codeStart, codeEnd: Math.max(codeEnd, codeStart) })
|
|
131
|
+
}
|
|
132
|
+
while (i < end) {
|
|
133
|
+
const char = src[i] ?? ''
|
|
134
|
+
if (char === '/' && (src[i + 1] === '/' || src[i + 1] === '*')) {
|
|
135
|
+
i = skipNonCode(src, i)
|
|
136
|
+
continue
|
|
137
|
+
}
|
|
138
|
+
const skipped = skipNonCode(src, i)
|
|
139
|
+
if (skipped !== i) {
|
|
140
|
+
i = skipped
|
|
141
|
+
codeEnd = i
|
|
142
|
+
continue
|
|
143
|
+
}
|
|
144
|
+
if (char === ',' && depth === 0) {
|
|
145
|
+
close(i)
|
|
146
|
+
segmentStart = i + 1
|
|
147
|
+
codeEnd = i + 1
|
|
148
|
+
i += 1
|
|
149
|
+
continue
|
|
150
|
+
}
|
|
151
|
+
if (CLOSERS[char] !== undefined) depth += 1
|
|
152
|
+
else if (char === '}' || char === ']' || char === ')') depth -= 1
|
|
153
|
+
if (!/\s/.test(char)) codeEnd = i + 1
|
|
154
|
+
i += 1
|
|
155
|
+
}
|
|
156
|
+
close(end)
|
|
157
|
+
return out
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Whether `code` is one complete expression that cannot reach outside the
|
|
162
|
+
* slot it is written into: brackets balanced and never closing past where
|
|
163
|
+
* they opened, strings and comments terminated, no top-level comma.
|
|
164
|
+
*/
|
|
165
|
+
export function isSingleExpression(code: string): boolean {
|
|
166
|
+
if (code.trim() === '') return false
|
|
167
|
+
let depth = 0
|
|
168
|
+
let i = 0
|
|
169
|
+
while (i < code.length) {
|
|
170
|
+
const skipped = skipNonCode(code, i)
|
|
171
|
+
if (skipped !== i) {
|
|
172
|
+
// A line comment would swallow the comma written after the value.
|
|
173
|
+
const lineComment = code[i] === '/' && code[i + 1] === '/'
|
|
174
|
+
if (lineComment || !isTerminated(code, i)) return false
|
|
175
|
+
i = skipped
|
|
176
|
+
continue
|
|
177
|
+
}
|
|
178
|
+
const char = code[i] ?? ''
|
|
179
|
+
if (CLOSERS[char] !== undefined) depth += 1
|
|
180
|
+
else if (char === '}' || char === ']' || char === ')') {
|
|
181
|
+
depth -= 1
|
|
182
|
+
if (depth < 0) return false
|
|
183
|
+
} else if (char === ',' && depth === 0) return false
|
|
184
|
+
i += 1
|
|
185
|
+
}
|
|
186
|
+
return depth === 0
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Index of the `(` of the first call to `callee` in code, or -1. A mention
|
|
191
|
+
* inside a string or a comment, or as the tail of a longer name
|
|
192
|
+
* (`MyEnv.create`), does not count.
|
|
193
|
+
*/
|
|
194
|
+
export function findCall(src: string, callee: string): number {
|
|
195
|
+
let i = 0
|
|
196
|
+
while (i < src.length) {
|
|
197
|
+
const skipped = skipNonCode(src, i)
|
|
198
|
+
if (skipped !== i) {
|
|
199
|
+
i = skipped
|
|
200
|
+
continue
|
|
201
|
+
}
|
|
202
|
+
const before = src[i - 1]
|
|
203
|
+
if (src.startsWith(callee, i) && !isIdentifierChar(before) && before !== '.') {
|
|
204
|
+
const paren = firstCode(src, i + callee.length, src.length)
|
|
205
|
+
if (src[paren] === '(') return paren
|
|
206
|
+
}
|
|
207
|
+
i += 1
|
|
208
|
+
}
|
|
209
|
+
return -1
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/** Index of the `{` after the first `export default` in code, or -1. */
|
|
213
|
+
export function findExportDefaultObject(src: string): number {
|
|
214
|
+
let i = 0
|
|
215
|
+
while (i < src.length) {
|
|
216
|
+
const skipped = skipNonCode(src, i)
|
|
217
|
+
if (skipped !== i) {
|
|
218
|
+
i = skipped
|
|
219
|
+
continue
|
|
220
|
+
}
|
|
221
|
+
if (src.startsWith('export', i) && !isIdentifierChar(src[i - 1])) {
|
|
222
|
+
const word = firstCode(src, i + 'export'.length, src.length)
|
|
223
|
+
if (src.startsWith('default', word) && !isIdentifierChar(src[word + 'default'.length])) {
|
|
224
|
+
const brace = firstCode(src, word + 'default'.length, src.length)
|
|
225
|
+
return src[brace] === '{' ? brace : -1
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
i += 1
|
|
229
|
+
}
|
|
230
|
+
return -1
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/** A `key: value` entry of an object literal. */
|
|
234
|
+
export interface Property {
|
|
235
|
+
key: string
|
|
236
|
+
valueStart: number
|
|
237
|
+
valueEnd: number
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/** The `key: value` entries of the object literal opening at `open`. */
|
|
241
|
+
export function properties(src: string, open: number, close: number): Property[] {
|
|
242
|
+
const out: Property[] = []
|
|
243
|
+
for (const segment of segments(src, open + 1, close)) {
|
|
244
|
+
if (segment.codeStart >= segment.end) continue
|
|
245
|
+
const text = src.slice(segment.codeStart, segment.end)
|
|
246
|
+
const match = /^(?:([A-Za-z_$][\w$]*)|'([^'\\\n]*)'|"([^"\\\n]*)")\s*:/.exec(text)
|
|
247
|
+
if (match === null) continue
|
|
248
|
+
const key = match[1] ?? match[2] ?? match[3] ?? ''
|
|
249
|
+
const valueStart = firstCode(src, segment.codeStart + match[0].length, segment.end)
|
|
250
|
+
out.push({ key, valueStart, valueEnd: segment.codeEnd })
|
|
251
|
+
}
|
|
252
|
+
return out
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/** Leading whitespace of the line holding `index`. */
|
|
256
|
+
function lineIndent(src: string, index: number): string {
|
|
257
|
+
const lineStart = src.lastIndexOf('\n', index - 1) + 1
|
|
258
|
+
return /^[ \t]*/.exec(src.slice(lineStart))?.[0] ?? ''
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Append entries to the literal `src[open..close]` and return the new text.
|
|
263
|
+
*
|
|
264
|
+
* `build` receives the indentation of the existing entries (or one level
|
|
265
|
+
* deeper than the closing bracket when there are none) and returns the lines
|
|
266
|
+
* to add, each already ending with its comma. `blankLine` separates the new
|
|
267
|
+
* entries from existing ones. A missing comma after the last existing entry
|
|
268
|
+
* is added.
|
|
269
|
+
*/
|
|
270
|
+
export function appendToLiteral(
|
|
271
|
+
src: string,
|
|
272
|
+
open: number,
|
|
273
|
+
close: number,
|
|
274
|
+
eol: string,
|
|
275
|
+
build: (indent: string) => string[],
|
|
276
|
+
blankLine = false,
|
|
277
|
+
): string {
|
|
278
|
+
const all = segments(src, open + 1, close)
|
|
279
|
+
const entries = all.filter((s) => s.codeStart < s.end)
|
|
280
|
+
const first = entries[0]
|
|
281
|
+
const closeIndent = lineIndent(src, close)
|
|
282
|
+
const firstOnOwnLine =
|
|
283
|
+
first !== undefined &&
|
|
284
|
+
/^[ \t]*$/.test(src.slice(src.lastIndexOf('\n', first.codeStart - 1) + 1, first.codeStart))
|
|
285
|
+
const indent =
|
|
286
|
+
first !== undefined && firstOnOwnLine ? lineIndent(src, first.codeStart) : `${closeIndent} `
|
|
287
|
+
const lines = build(indent)
|
|
288
|
+
const separator = blankLine && entries.length > 0 ? eol : ''
|
|
289
|
+
|
|
290
|
+
const closeLineStart = src.lastIndexOf('\n', close - 1) + 1
|
|
291
|
+
const closeOnOwnLine = /^[ \t]*$/.test(src.slice(closeLineStart, close))
|
|
292
|
+
let out = closeOnOwnLine
|
|
293
|
+
? `${src.slice(0, closeLineStart)}${separator}${lines.join(eol)}${eol}${src.slice(closeLineStart)}`
|
|
294
|
+
: `${src.slice(0, close)}${eol}${separator}${lines.join(eol)}${eol}${closeIndent}${src.slice(close)}`
|
|
295
|
+
|
|
296
|
+
// The comma goes in last, as it sits before every insertion point above.
|
|
297
|
+
// No comma after the last entry when it is also the last segment.
|
|
298
|
+
const last = entries[entries.length - 1]
|
|
299
|
+
if (last !== undefined && all[all.length - 1] === last) {
|
|
300
|
+
out = `${out.slice(0, last.codeEnd)},${out.slice(last.codeEnd)}`
|
|
301
|
+
}
|
|
302
|
+
return out
|
|
303
|
+
}
|
package/src/console/prompts.ts
CHANGED
|
@@ -513,7 +513,9 @@ export class Prompt {
|
|
|
513
513
|
rl.question(query, (answer) => {
|
|
514
514
|
if (masked) stdout.write('\n')
|
|
515
515
|
rl.close()
|
|
516
|
-
|
|
516
|
+
// A secret is returned as typed: a password may begin or end with a
|
|
517
|
+
// space, and trimming it would store or compare a different one.
|
|
518
|
+
resolve(masked ? answer : answer.trim())
|
|
517
519
|
})
|
|
518
520
|
})
|
|
519
521
|
}
|
|
@@ -30,10 +30,23 @@ import type { Binding, ServiceFactory, ServiceToken } from './types.js'
|
|
|
30
30
|
*/
|
|
31
31
|
const RESERVED_TOKEN_NAMES = new Set(['__proto__', 'constructor', 'prototype'])
|
|
32
32
|
|
|
33
|
-
/**
|
|
33
|
+
/**
|
|
34
|
+
* Where one resolution stands: the tokens above it (a list for the message, a
|
|
35
|
+
* set for O(1) membership), and what it carries down.
|
|
36
|
+
*
|
|
37
|
+
* **Never mutated once in the async context.** Every resolution, and every
|
|
38
|
+
* construction that changes the parent, runs on its OWN copy
|
|
39
|
+
* (`#chain.run({ ...chain, ... })`). The chain used to be one object pushed to
|
|
40
|
+
* and popped from in place, and a chain opened around a whole body
|
|
41
|
+
* (`container.call()` around a command's `run()`, `resolveFor`,
|
|
42
|
+
* `runWithScopedValues`) was then shared by every concurrent task inside it:
|
|
43
|
+
* two tasks asking for the same singleton at once read as `catalog → catalog`,
|
|
44
|
+
* and one task's class could stand as another's parent for a contextual
|
|
45
|
+
* binding. A copy per step costs an array and a set the depth of the chain.
|
|
46
|
+
*/
|
|
34
47
|
interface ResolutionChain {
|
|
35
|
-
stack: ServiceToken[]
|
|
36
|
-
set:
|
|
48
|
+
readonly stack: readonly ServiceToken[]
|
|
49
|
+
readonly set: ReadonlySet<ServiceToken>
|
|
37
50
|
/**
|
|
38
51
|
* Values bound on the {@link ContainerResolver} that opened this chain.
|
|
39
52
|
*
|
|
@@ -51,8 +64,13 @@ interface ResolutionChain {
|
|
|
51
64
|
* `HttpContext`. Comparing this counter before and after a build says whether
|
|
52
65
|
* it actually read one, so a singleton that touched no request state still
|
|
53
66
|
* caches exactly as before.
|
|
67
|
+
*
|
|
68
|
+
* A box, the one mutable part, so the copies a chain is walked on all count
|
|
69
|
+
* into it: a read three dependencies down is a read by the singleton being
|
|
70
|
+
* built at the top. Concurrent siblings count into it too, which can only
|
|
71
|
+
* keep a singleton out of the cache, never put a request's into it.
|
|
54
72
|
*/
|
|
55
|
-
scopedReads
|
|
73
|
+
readonly scopedReads: { count: number }
|
|
56
74
|
/**
|
|
57
75
|
* The class whose dependencies are being resolved right now.
|
|
58
76
|
*
|
|
@@ -60,14 +78,19 @@ interface ResolutionChain {
|
|
|
60
78
|
* this", so the lookup needs the direct dependent. Carried on the chain for
|
|
61
79
|
* the same reason the scoped values are: `#autoConstruct` knows it, and
|
|
62
80
|
* every method between there and the lookup would otherwise have to pass it
|
|
63
|
-
* down.
|
|
81
|
+
* down. Each construction runs on a copy that names it, so a dependency's own
|
|
64
82
|
* dependencies see IT as their parent, not its parent.
|
|
65
83
|
*/
|
|
66
|
-
parent?: abstract new (
|
|
84
|
+
readonly parent?: abstract new (
|
|
67
85
|
...args: never[]
|
|
68
86
|
) => unknown
|
|
69
87
|
}
|
|
70
88
|
|
|
89
|
+
/** A chain with nothing in it yet. */
|
|
90
|
+
function openChain(extra: Partial<ResolutionChain> = {}): ResolutionChain {
|
|
91
|
+
return { stack: [], set: new Set(), scopedReads: { count: 0 }, ...extra }
|
|
92
|
+
}
|
|
93
|
+
|
|
71
94
|
export class Container {
|
|
72
95
|
#bindings: Map<ServiceToken, Binding> = new Map()
|
|
73
96
|
#singletons: Map<ServiceToken, unknown> = new Map()
|
|
@@ -320,9 +343,7 @@ export class Container {
|
|
|
320
343
|
// it and nothing outside it does.
|
|
321
344
|
const chain = this.#chain.getStore()
|
|
322
345
|
if (chain === undefined) {
|
|
323
|
-
return this.#chain.run(
|
|
324
|
-
this.resolve<T>(token, runtimeValues),
|
|
325
|
-
)
|
|
346
|
+
return this.#chain.run(openChain(), () => this.resolve<T>(token, runtimeValues))
|
|
326
347
|
}
|
|
327
348
|
|
|
328
349
|
if (chain.set.has(key)) {
|
|
@@ -332,15 +353,14 @@ export class Container {
|
|
|
332
353
|
context: { chain: cycle },
|
|
333
354
|
})
|
|
334
355
|
}
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
chain.stack.pop()
|
|
342
|
-
chain.set.delete(key)
|
|
356
|
+
// On a copy: see `ResolutionChain`. What this resolution triggers sees the
|
|
357
|
+
// key above it; a sibling running at the same time does not.
|
|
358
|
+
const own: ResolutionChain = {
|
|
359
|
+
...chain,
|
|
360
|
+
stack: [...chain.stack, key],
|
|
361
|
+
set: new Set(chain.set).add(key),
|
|
343
362
|
}
|
|
363
|
+
return this.#chain.run(own, () => this.#resolveInner<T>(key, token, runtimeValues))
|
|
344
364
|
}
|
|
345
365
|
|
|
346
366
|
/**
|
|
@@ -364,52 +384,17 @@ export class Container {
|
|
|
364
384
|
// its own with nobody in it.
|
|
365
385
|
const chain = this.#chain.getStore()
|
|
366
386
|
if (chain === undefined) {
|
|
367
|
-
return this.#chain.run({
|
|
387
|
+
return this.#chain.run(openChain({ parent: target }), () =>
|
|
368
388
|
this.call(instance, method, runtimeValues),
|
|
369
389
|
)
|
|
370
390
|
}
|
|
371
|
-
|
|
372
|
-
//
|
|
373
|
-
//
|
|
374
|
-
//
|
|
375
|
-
const args:
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
const paramTypes: unknown[] =
|
|
379
|
-
Reflect.getMetadata('design:paramtypes', target.prototype, method) ?? []
|
|
380
|
-
// `@Inject('token')` on a method parameter — a named binding the reflected
|
|
381
|
-
// type cannot express (an interface, or a class registered under a name).
|
|
382
|
-
const injectTokens = getMethodInjectTokens(target.prototype, method)
|
|
383
|
-
|
|
384
|
-
// `@Inject` counts towards the parameter span too: a method may carry named
|
|
385
|
-
// tokens without `design:paramtypes` being emitted for it, and computing the
|
|
386
|
-
// span from the reflected types alone left the loop at zero iterations —
|
|
387
|
-
// the tokens were read and then never used.
|
|
388
|
-
const injectSpan = injectTokens.size === 0 ? 0 : Math.max(...injectTokens.keys()) + 1
|
|
389
|
-
const len = Math.max(paramTypes.length, runtimeValues?.length ?? 0, injectSpan)
|
|
390
|
-
// Sequential resolution keeps the shared cycle-detection stack consistent.
|
|
391
|
-
for (let index = 0; index < len; index += 1) {
|
|
392
|
-
// Runtime values take precedence (and fill slots beyond paramTypes).
|
|
393
|
-
if (runtimeValues && index < runtimeValues.length) {
|
|
394
|
-
args.push(runtimeValues[index])
|
|
395
|
-
continue
|
|
396
|
-
}
|
|
397
|
-
const named = injectTokens.get(index)
|
|
398
|
-
if (named !== undefined) {
|
|
399
|
-
args.push(await this.resolve(named))
|
|
400
|
-
continue
|
|
401
|
-
}
|
|
402
|
-
const type = paramTypes[index]
|
|
403
|
-
args.push(isInjectableClass(type) ? await this.resolve(type) : undefined)
|
|
404
|
-
}
|
|
405
|
-
} finally {
|
|
406
|
-
// RESTORED whatever happened. Without the `finally`, a parameter that
|
|
407
|
-
// failed to resolve left the called class installed as the parent, so a
|
|
408
|
-
// caller that caught the error saw its contextual bindings applied to
|
|
409
|
-
// every later resolution — a binding meant for one handler leaking into
|
|
410
|
-
// the whole application.
|
|
411
|
-
chain.parent = outerParent
|
|
412
|
-
}
|
|
391
|
+
// The parameters are resolved with `target` as the parent, on a copy of
|
|
392
|
+
// the chain (see `ResolutionChain`), so nothing outside them sees it: not
|
|
393
|
+
// the caller once they are resolved, whatever happened, and not a task
|
|
394
|
+
// running beside them. The method itself runs on the caller's chain.
|
|
395
|
+
const args = await this.#chain.run({ ...chain, parent: target }, () =>
|
|
396
|
+
this.#methodArgs(target, method, runtimeValues),
|
|
397
|
+
)
|
|
413
398
|
|
|
414
399
|
const member: unknown = instance[method]
|
|
415
400
|
if (!isCallable(member)) {
|
|
@@ -418,6 +403,44 @@ export class Container {
|
|
|
418
403
|
return member.apply(instance, args)
|
|
419
404
|
}
|
|
420
405
|
|
|
406
|
+
/** The arguments `call()` passes to `target.prototype[method]`. */
|
|
407
|
+
async #methodArgs(
|
|
408
|
+
target: new (...args: never[]) => unknown,
|
|
409
|
+
method: string,
|
|
410
|
+
runtimeValues?: unknown[],
|
|
411
|
+
): Promise<unknown[]> {
|
|
412
|
+
const args: unknown[] = []
|
|
413
|
+
const paramTypes: unknown[] =
|
|
414
|
+
Reflect.getMetadata('design:paramtypes', target.prototype, method) ?? []
|
|
415
|
+
// `@Inject('token')` on a method parameter — a named binding the reflected
|
|
416
|
+
// type cannot express (an interface, or a class registered under a name).
|
|
417
|
+
const injectTokens = getMethodInjectTokens(target.prototype, method)
|
|
418
|
+
|
|
419
|
+
// `@Inject` counts towards the parameter span too: a method may carry named
|
|
420
|
+
// tokens without `design:paramtypes` being emitted for it, and computing the
|
|
421
|
+
// span from the reflected types alone left the loop at zero iterations —
|
|
422
|
+
// the tokens were read and then never used.
|
|
423
|
+
const injectSpan = injectTokens.size === 0 ? 0 : Math.max(...injectTokens.keys()) + 1
|
|
424
|
+
const len = Math.max(paramTypes.length, runtimeValues?.length ?? 0, injectSpan)
|
|
425
|
+
// One at a time, in parameter order: a factory with side effects runs
|
|
426
|
+
// in the order the signature reads.
|
|
427
|
+
for (let index = 0; index < len; index += 1) {
|
|
428
|
+
// Runtime values take precedence (and fill slots beyond paramTypes).
|
|
429
|
+
if (runtimeValues && index < runtimeValues.length) {
|
|
430
|
+
args.push(runtimeValues[index])
|
|
431
|
+
continue
|
|
432
|
+
}
|
|
433
|
+
const named = injectTokens.get(index)
|
|
434
|
+
if (named !== undefined) {
|
|
435
|
+
args.push(await this.resolve(named))
|
|
436
|
+
continue
|
|
437
|
+
}
|
|
438
|
+
const type = paramTypes[index]
|
|
439
|
+
args.push(isInjectableClass(type) ? await this.resolve(type) : undefined)
|
|
440
|
+
}
|
|
441
|
+
return args
|
|
442
|
+
}
|
|
443
|
+
|
|
421
444
|
/**
|
|
422
445
|
* A resolver whose {@link ContainerResolver.bindValue} values are isolated
|
|
423
446
|
* from this container (AdonisJS `container.createResolver()`).
|
|
@@ -441,10 +464,7 @@ export class Container {
|
|
|
441
464
|
fn: () => Promise<T>,
|
|
442
465
|
): Promise<T> {
|
|
443
466
|
const chain = this.#chain.getStore()
|
|
444
|
-
return this.#chain.run(
|
|
445
|
-
chain === undefined ? { stack: [], set: new Set(), values } : { ...chain, values },
|
|
446
|
-
fn,
|
|
447
|
-
)
|
|
467
|
+
return this.#chain.run(chain === undefined ? openChain({ values }) : { ...chain, values }, fn)
|
|
448
468
|
}
|
|
449
469
|
|
|
450
470
|
/** @internal Validate a token and hand back the value the container keys on. */
|
|
@@ -464,9 +484,8 @@ export class Container {
|
|
|
464
484
|
): Promise<T> {
|
|
465
485
|
if (parent === null) return this.make<T>(token, runtimeValues)
|
|
466
486
|
const chain = this.#chain.getStore()
|
|
467
|
-
return this.#chain.run(
|
|
468
|
-
|
|
469
|
-
() => this.make<T>(token, runtimeValues),
|
|
487
|
+
return this.#chain.run(chain === undefined ? openChain({ parent }) : { ...chain, parent }, () =>
|
|
488
|
+
this.make<T>(token, runtimeValues),
|
|
470
489
|
)
|
|
471
490
|
}
|
|
472
491
|
|
|
@@ -588,7 +607,7 @@ export class Container {
|
|
|
588
607
|
// resolves in (`resolveFor`: swaps, resolver values, container values).
|
|
589
608
|
// No `resolving` hooks: the value was not constructed here.
|
|
590
609
|
if (store?.values?.has(key)) {
|
|
591
|
-
store.scopedReads
|
|
610
|
+
store.scopedReads.count += 1
|
|
592
611
|
return store.values.get(key) as T
|
|
593
612
|
}
|
|
594
613
|
|
|
@@ -619,7 +638,7 @@ export class Container {
|
|
|
619
638
|
if (this.#wasPublished(key, shared)) return shared as T
|
|
620
639
|
}
|
|
621
640
|
|
|
622
|
-
const readsBefore = store?.scopedReads ?? 0
|
|
641
|
+
const readsBefore = store?.scopedReads.count ?? 0
|
|
623
642
|
const building = (async (): Promise<unknown> => {
|
|
624
643
|
const instance = binding.factory ? await binding.factory(this) : undefined
|
|
625
644
|
// Only cache while this is still the binding that started the build.
|
|
@@ -731,7 +750,7 @@ export class Container {
|
|
|
731
750
|
|
|
732
751
|
// Same rule as the explicit bindings: see `ResolutionChain.scopedReads`.
|
|
733
752
|
const store = this.#chain.getStore()
|
|
734
|
-
const readsBefore = store?.scopedReads ?? 0
|
|
753
|
+
const readsBefore = store?.scopedReads.count ?? 0
|
|
735
754
|
const building = (async (): Promise<unknown> => {
|
|
736
755
|
const instance = await this.#autoConstruct(target, runtimeValues)
|
|
737
756
|
await this.#runResolvingHooks(key, instance)
|
|
@@ -754,16 +773,13 @@ export class Container {
|
|
|
754
773
|
runtimeValues?: unknown[],
|
|
755
774
|
): Promise<unknown> {
|
|
756
775
|
// Everything resolved inside is a dependency OF `target`, which is what a
|
|
757
|
-
// contextual binding keys on.
|
|
758
|
-
//
|
|
759
|
-
|
|
760
|
-
const
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
} finally {
|
|
765
|
-
if (store !== undefined) store.parent = outerParent
|
|
766
|
-
}
|
|
776
|
+
// contextual binding keys on. On a copy of the chain (see
|
|
777
|
+
// `ResolutionChain`): nothing to restore on any of the construction's
|
|
778
|
+
// exits, and a construction running beside this one keeps its own parent.
|
|
779
|
+
const store = this.#chain.getStore() ?? openChain()
|
|
780
|
+
return this.#chain.run({ ...store, parent: target }, () =>
|
|
781
|
+
this.#constructWithDeps(target, runtimeValues),
|
|
782
|
+
)
|
|
767
783
|
}
|
|
768
784
|
|
|
769
785
|
async #constructWithDeps(
|
|
@@ -902,7 +918,7 @@ export class Container {
|
|
|
902
918
|
readsBefore: number,
|
|
903
919
|
): void {
|
|
904
920
|
if (scope !== 'singleton') return
|
|
905
|
-
if ((store?.scopedReads ?? 0) !== readsBefore) return
|
|
921
|
+
if ((store?.scopedReads.count ?? 0) !== readsBefore) return
|
|
906
922
|
this.#singletons.set(key, instance)
|
|
907
923
|
}
|
|
908
924
|
|