1use std::{borrow::Cow, path::Path};
2
3use anyhow::{Result, bail};
4use async_trait::async_trait;
5use dap::{DapLocator, DebugRequest, adapters::DebugAdapterName};
6use gpui::SharedString;
7
8use task::{DebugScenario, SpawnInTerminal, TaskTemplate, VariableName};
9
10pub(crate) struct NodeLocator;
11
12const TYPESCRIPT_RUNNER_VARIABLE: VariableName =
13 VariableName::Custom(Cow::Borrowed("TYPESCRIPT_RUNNER"));
14
15#[async_trait]
16impl DapLocator for NodeLocator {
17 fn name(&self) -> SharedString {
18 SharedString::new_static("Node")
19 }
20
21 /// Determines whether this locator can generate debug target for given task.
22 fn create_scenario(
23 &self,
24 build_config: &TaskTemplate,
25 resolved_label: &str,
26 adapter: DebugAdapterName,
27 ) -> Option<DebugScenario> {
28 // TODO(debugger) fix issues with `await` breakpoint step
29 if cfg!(not(debug_assertions)) {
30 return None;
31 }
32
33 if adapter.as_ref() != "JavaScript" {
34 return None;
35 }
36 if build_config.command != TYPESCRIPT_RUNNER_VARIABLE.template_value() {
37 return None;
38 }
39 let test_library = build_config.args.first()?;
40 let program_path = Path::new("$ZED_WORKTREE_ROOT")
41 .join("node_modules")
42 .join(".bin")
43 .join(test_library);
44 let args = build_config.args[1..].to_vec();
45
46 let config = serde_json::json!({
47 "request": "launch",
48 "type": "pwa-node",
49 "program": program_path,
50 "args": args,
51 "cwd": build_config.cwd.clone(),
52 "runtimeArgs": ["--inspect-brk"],
53 "console": "integratedTerminal",
54 });
55
56 Some(DebugScenario {
57 adapter: adapter.0,
58 label: resolved_label.to_string().into(),
59 build: None,
60 config,
61 tcp_connection: None,
62 })
63 }
64
65 async fn run(&self, _: SpawnInTerminal) -> Result<DebugRequest> {
66 bail!("Python locator should not require DapLocator::run to be ran");
67 }
68}