1use std::{borrow::Cow, path::PathBuf};
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 async fn create_scenario(
23 &self,
24 build_config: &TaskTemplate,
25 resolved_label: &str,
26 adapter: &DebugAdapterName,
27 ) -> Option<DebugScenario> {
28 if adapter.0.as_ref() != "JavaScript" {
29 return None;
30 }
31 if build_config.command != TYPESCRIPT_RUNNER_VARIABLE.template_value() {
32 return None;
33 }
34 let test_library = build_config.args.first()?;
35 let program_path_base: PathBuf = match test_library.as_str() {
36 "jest" => "${ZED_CUSTOM_TYPESCRIPT_JEST_PACKAGE_PATH}".to_owned(),
37 "mocha" => "${ZED_CUSTOM_TYPESCRIPT_MOCHA_PACKAGE_PATH}".to_owned(),
38 "vitest" => "${ZED_CUSTOM_TYPESCRIPT_VITEST_PACKAGE_PATH}".to_owned(),
39 "jasmine" => "${ZED_CUSTOM_TYPESCRIPT_JASMINE_PACKAGE_PATH}".to_owned(),
40 _ => VariableName::WorktreeRoot.template_value(),
41 }
42 .into();
43
44 let program_path = program_path_base
45 .join("node_modules")
46 .join(".bin")
47 .join(test_library);
48
49 let mut args = if test_library == "jest" {
50 vec!["--runInBand".to_owned()]
51 } else {
52 vec![]
53 };
54 args.extend(build_config.args[1..].iter().cloned());
55
56 let config = serde_json::json!({
57 "request": "launch",
58 "type": "pwa-node",
59 "runtimeExecutable": program_path,
60 "args": args,
61 "cwd": build_config.cwd.clone(),
62 "env": {
63 "VITEST_MIN_FORKS": "0",
64 "VITEST_MAX_FORKS": "1"
65 },
66 "runtimeArgs": ["--inspect-brk"],
67 "console": "integratedTerminal",
68 });
69
70 Some(DebugScenario {
71 adapter: adapter.0.clone(),
72 label: resolved_label.to_string().into(),
73 build: None,
74 config,
75 tcp_connection: None,
76 })
77 }
78
79 async fn run(&self, _: SpawnInTerminal) -> Result<DebugRequest> {
80 bail!("JavaScript locator should not require DapLocator::run to be ran");
81 }
82}