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"));
14const TYPESCRIPT_JEST_TASK_VARIABLE: VariableName =
15 VariableName::Custom(Cow::Borrowed("TYPESCRIPT_JEST"));
16
17#[async_trait]
18impl DapLocator for NodeLocator {
19 fn name(&self) -> SharedString {
20 SharedString::new_static("Node")
21 }
22
23 /// Determines whether this locator can generate debug target for given task.
24 fn create_scenario(
25 &self,
26 build_config: &TaskTemplate,
27 resolved_label: &str,
28 adapter: DebugAdapterName,
29 ) -> Option<DebugScenario> {
30 if adapter.0.as_ref() != "JavaScript" {
31 return None;
32 }
33 if build_config.command != TYPESCRIPT_RUNNER_VARIABLE.template_value() {
34 return None;
35 }
36 let test_library = build_config.args.first()?;
37 let program_path = Path::new("$ZED_WORKTREE_ROOT")
38 .join("node_modules")
39 .join(".bin")
40 .join(test_library);
41
42 let mut args = if test_library == "jest"
43 || test_library == &TYPESCRIPT_JEST_TASK_VARIABLE.template_value()
44 {
45 vec!["--runInBand".to_owned()]
46 } else {
47 vec![]
48 };
49 args.extend(build_config.args[1..].iter().cloned());
50
51 let config = serde_json::json!({
52 "request": "launch",
53 "type": "pwa-node",
54 "runtimeExecutable": program_path,
55 "args": args,
56 "cwd": build_config.cwd.clone(),
57 "env": {
58 "VITEST_MIN_FORKS": "0",
59 "VITEST_MAX_FORKS": "1"
60 },
61 "runtimeArgs": ["--inspect-brk"],
62 "console": "integratedTerminal",
63 });
64
65 Some(DebugScenario {
66 adapter: adapter.0,
67 label: resolved_label.to_string().into(),
68 build: None,
69 config,
70 tcp_connection: None,
71 })
72 }
73
74 async fn run(&self, _: SpawnInTerminal) -> Result<DebugRequest> {
75 bail!("JavaScript locator should not require DapLocator::run to be ran");
76 }
77}