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 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}