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 types = package_json
92 .contributes
93 .debuggers
94 .iter()
95 .map(|debugger| debugger.r#type.clone())
96 .collect::<Vec<_>>();
97 let mut conjuncts = package_json
98 .contributes
99 .debuggers
100 .into_iter()
101 .flat_map(|debugger| {
102 let r#type = debugger.r#type;
103 let configuration_attributes = debugger.configuration_attributes;
104 configuration_attributes
105 .launch
106 .map(|schema| ("launch", schema))
107 .into_iter()
108 .chain(
109 configuration_attributes
110 .attach
111 .map(|schema| ("attach", schema)),
112 )
113 .map(|(request, schema)| {
114 json_schema!({
115 "if": {
116 "properties": {
117 "type": {
118 "const": r#type
119 },
120 "request": {
121 "const": request
122 }
123 },
124 "required": ["type", "request"]
125 },
126 "then": schema
127 })
128 })
129 .collect::<Vec<_>>()
130 })
131 .collect::<Vec<_>>();
132 conjuncts.push(json_schema!({
133 "properties": {
134 "type": {
135 "enum": types
136 }
137 },
138 "required": ["type"]
139 }));
140 let schema = json_schema!({
141 "allOf": conjuncts
142 });
143
144 let mut schema = serde_json::to_string_pretty(&schema.to_value()).unwrap();
145 schema.push('\n');
146 std::fs::write(
147 format!(
148 "crates/dap_adapters/schemas/{}.json",
149 JsDebugAdapter::ADAPTER_NAME
150 ),
151 schema,
152 )
153 .unwrap();
154}