Skip to content

Commit d8a4f13

Browse files
Adds a mechanism to preload the effect's debugger instrumentation bef… (#75)
1 parent bcafdcd commit d8a4f13

File tree

4 files changed

+79
-1
lines changed

4 files changed

+79
-1
lines changed

.changeset/whole-parents-help.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"effect-vscode": patch
3+
---
4+
5+
Adds a mechanism to preload the effect's debugger instrumentation before node begins executing userlands scripts.

package.json

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,24 @@
5050
},
5151
"default": [],
5252
"description": "A list of span patterns to ignore when showing the span stack"
53+
},
54+
"effect.instrumentation.injectNodeOptions": {
55+
"type": "boolean",
56+
"default": false,
57+
"description": "If enabled, the effect instrumentation code will be injected into node debug configurations by appending a NODE_OPTIONS environment variable"
58+
},
59+
"effect.instrumentation.injectDebugConfigurations": {
60+
"type": "array",
61+
"items": {
62+
"type": "string",
63+
"default": ""
64+
},
65+
"default": [
66+
"node",
67+
"node-terminal",
68+
"pwa-node"
69+
],
70+
"description": "A list of debug configuration types to inject the instrumentation into when injectNodeOptions is enabled"
5371
}
5472
}
5573
},
@@ -256,6 +274,7 @@
256274
"test": "node ./out/test/runTest.js"
257275
},
258276
"devDependencies": {
277+
"@vscode/js-debug": "*",
259278
"@changesets/changelog-github": "^0.5.1",
260279
"@changesets/cli": "^2.29.5",
261280
"@effect/eslint-plugin": "^0.3.2",
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import * as Effect from "effect/Effect"
2+
import * as Layer from "effect/Layer"
3+
import * as Runtime from "effect/Runtime"
4+
import * as vscode from "vscode"
5+
import { configWithDefault, VsCodeContext } from "./VsCode"
6+
7+
export const InjectNodeOptionsInstrumentationLive = Effect.gen(function*() {
8+
const extension = yield* VsCodeContext
9+
10+
// gets the config if it shuold be injected or not
11+
const injectNodeOptions = yield* configWithDefault("effect.instrumentation", "injectNodeOptions", false)
12+
const injectDebugConfigurations = yield* configWithDefault("effect.instrumentation", "injectDebugConfigurations", [
13+
"node",
14+
"node-terminal",
15+
"pwa-node"
16+
])
17+
const runtime = yield* Effect.runtime<never>()
18+
19+
yield* Effect.acquireRelease(
20+
Effect.sync(() =>
21+
vscode.debug.registerDebugConfigurationProvider("*", {
22+
resolveDebugConfiguration(_folder, config, _token) {
23+
// if disabled (default) then do nothing
24+
const shouldInjectBool = Runtime.runSync(runtime, injectNodeOptions.get)
25+
if (!shouldInjectBool) return config
26+
27+
// abort immediately if the token is cancelled
28+
if (_token?.isCancellationRequested) return config
29+
30+
// if not supported, then do nothing
31+
const debugConfigurations = Runtime.runSync(runtime, injectDebugConfigurations.get)
32+
if (
33+
debugConfigurations.map((_) => String(_).toLowerCase()).indexOf(config.type.toLowerCase()) === -1
34+
) return config
35+
36+
// if enabled, then inject the instrumentation in NODE_OPTIONS
37+
const configEnv = config.env || {}
38+
const previousNodeOptions = configEnv.NODE_OPTIONS || "${env:NODE_OPTIONS}"
39+
const instrumentationPath = JSON.stringify(extension.extensionPath + "/out/instrumentation.global.js")
40+
return {
41+
...config,
42+
env: {
43+
...configEnv,
44+
"NODE_OPTIONS": `--require ${instrumentationPath} ${previousNodeOptions}`
45+
}
46+
}
47+
}
48+
})
49+
),
50+
(disposer) => Effect.sync(() => disposer.dispose())
51+
)
52+
}).pipe(Layer.scopedDiscard)

src/extension.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { DebugBreakpointsProviderLive } from "./DebugBreakpointsProvider"
88
import { DebugEnv } from "./DebugEnv"
99
import { DebugFibersProviderLive } from "./DebugFibersProvider"
1010
import { DebugSpanStackProviderLive } from "./DebugSpanStackProvider"
11+
import { InjectNodeOptionsInstrumentationLive } from "./InjectNodeOptionsInstrumentationProvider"
1112
import { LayerHoverProviderLive } from "./LayerHoverProvider"
1213
import { MetricsProviderLive } from "./MetricsProvider"
1314
import { SpanProviderLive } from "./SpanProvider"
@@ -25,7 +26,8 @@ const MainLive = ClientsProviderLive.pipe(
2526
DebugFibersProviderLive,
2627
TracerExtendedLive,
2728
LayerHoverProviderLive,
28-
DebugBreakpointsProviderLive
29+
DebugBreakpointsProviderLive,
30+
InjectNodeOptionsInstrumentationLive
2931
)),
3032
Layer.provide(Clients.Default),
3133
Layer.provide(DebugEnv.Live),

0 commit comments

Comments
 (0)