update_schemas.rs

  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}