1use collections::HashMap;
2use dap_adapters::JsDebugAdapter;
3use schemars::{Schema, json_schema};
4use serde::{Deserialize, Serialize};
5use task::{EnvVariableReplacer, VariableName};
6use tempfile::TempDir;
7
8fn main() {
9 #[derive(Serialize, Deserialize)]
10 struct PackageJsonConfigurationAttributes {
11 #[serde(default, skip_serializing_if = "Option::is_none")]
12 launch: Option<Schema>,
13 #[serde(default, skip_serializing_if = "Option::is_none")]
14 attach: Option<Schema>,
15 }
16
17 #[derive(Serialize, Deserialize)]
18 #[serde(rename_all = "camelCase")]
19 struct PackageJsonDebugger {
20 r#type: String,
21 configuration_attributes: PackageJsonConfigurationAttributes,
22 }
23
24 #[derive(Serialize, Deserialize)]
25 struct PackageJsonContributes {
26 debuggers: Vec<PackageJsonDebugger>,
27 }
28
29 #[derive(Serialize, Deserialize)]
30 struct PackageJson {
31 contributes: PackageJsonContributes,
32 }
33
34 let dir = TempDir::new().unwrap();
35 let path = std::fs::canonicalize(dir.path()).unwrap();
36 let (package_json, package_nls_json) =
37 dap_adapters::JsDebugAdapter::fetch_schema(&path).unwrap();
38 let package_nls_json =
39 serde_json::from_str::<HashMap<String, serde_json::Value>>(&package_nls_json)
40 .unwrap()
41 .into_iter()
42 .filter_map(|(k, v)| {
43 let v = v.as_str()?;
44 Some((k, v.to_owned()))
45 })
46 .collect::<HashMap<_, _>>();
47
48 let package_json: serde_json::Value = serde_json::from_str(&package_json).unwrap();
49
50 struct Replacer {
51 package_nls_json: HashMap<String, String>,
52 env: EnvVariableReplacer,
53 }
54
55 impl Replacer {
56 fn replace(&self, input: serde_json::Value) -> serde_json::Value {
57 match input {
58 serde_json::Value::String(s) => {
59 if s.starts_with("%") && s.ends_with("%") {
60 self.package_nls_json
61 .get(s.trim_matches('%'))
62 .map(|s| s.as_str().into())
63 .unwrap_or("(missing)".into())
64 } else {
65 self.env.replace(&s).into()
66 }
67 }
68 serde_json::Value::Array(arr) => {
69 serde_json::Value::Array(arr.into_iter().map(|v| self.replace(v)).collect())
70 }
71 serde_json::Value::Object(obj) => serde_json::Value::Object(
72 obj.into_iter().map(|(k, v)| (k, self.replace(v))).collect(),
73 ),
74 _ => input,
75 }
76 }
77 }
78
79 let env = EnvVariableReplacer::new(HashMap::from_iter([(
80 "workspaceFolder".to_owned(),
81 VariableName::WorktreeRoot.to_string(),
82 )]));
83 let replacer = Replacer {
84 env,
85 package_nls_json,
86 };
87 let package_json = replacer.replace(package_json);
88
89 let package_json: PackageJson = serde_json::from_value(package_json).unwrap();
90
91 let alternatives = package_json
92 .contributes
93 .debuggers
94 .into_iter()
95 .flat_map(|debugger| {
96 let r#type = debugger.r#type;
97 let configuration_attributes = debugger.configuration_attributes;
98 configuration_attributes
99 .launch
100 .map(|schema| ("launch", schema))
101 .into_iter()
102 .chain(
103 configuration_attributes
104 .attach
105 .map(|schema| ("attach", schema)),
106 )
107 .map(|(request, schema)| {
108 json_schema!({
109 "if": {
110 "properties": {
111 "type": {
112 "enum": [r#type]
113 },
114 "request": {
115 "enum": [request]
116 }
117 },
118 "required": ["type", "request"]
119 },
120 "then": schema
121 })
122 })
123 .collect::<Vec<_>>()
124 })
125 .collect::<Vec<_>>();
126 let schema = json_schema!({
127 "allOf": alternatives
128 });
129
130 let mut schema = serde_json::to_string_pretty(&schema.to_value()).unwrap();
131 schema.push('\n');
132 std::fs::write(
133 format!(
134 "crates/dap_adapters/schemas/{}.json",
135 JsDebugAdapter::ADAPTER_NAME
136 ),
137 schema,
138 )
139 .unwrap();
140}