···11use miette::Diagnostic;
22use serde_json::Value;
33-use std::path::{Path, PathBuf};
33+use std::path::PathBuf;
44use thiserror::Error;
5566#[derive(Error, Debug, Diagnostic)]
77pub enum MlfGenerateError {
88 #[error("Failed to read file: {path}")]
99 #[diagnostic(code(mlf::generate::read_file))]
1010+ #[allow(dead_code)]
1011 ReadFile {
1112 path: String,
1213 #[source]
···15161617 #[error("Failed to parse JSON: {path}")]
1718 #[diagnostic(code(mlf::generate::parse_json))]
1919+ #[allow(dead_code)]
1820 ParseJson {
1921 path: String,
2022 #[source]
···161163pub fn generate_mlf_from_json(json: &Value) -> Result<String, MlfGenerateError> {
162164 let mut output = String::new();
163165166166+ // Extract NSID to get the last segment for "main" definitions
167167+ let nsid = json
168168+ .get("id")
169169+ .and_then(|v| v.as_str())
170170+ .ok_or_else(|| MlfGenerateError::InvalidLexicon {
171171+ message: "Missing 'id' field in lexicon".to_string(),
172172+ })?;
173173+174174+ let last_segment = nsid.split('.').last().unwrap_or("main");
175175+164176 let defs = json.get("defs").and_then(|v| v.as_object()).ok_or_else(|| {
165177 MlfGenerateError::InvalidLexicon {
166178 message: "Missing or invalid 'defs' field".to_string(),
···177189178190 match def_type {
179191 "record" => {
180180- let mlf = generate_record(name, def)?;
192192+ let mlf = generate_record(name, def, last_segment)?;
181193 output.push_str(&mlf);
182194 output.push('\n');
183195 }
184196 "query" => {
185185- let mlf = generate_query(name, def)?;
197197+ let mlf = generate_query(name, def, last_segment)?;
186198 output.push_str(&mlf);
187199 output.push('\n');
188200 }
189201 "procedure" => {
190190- let mlf = generate_procedure(name, def)?;
202202+ let mlf = generate_procedure(name, def, last_segment)?;
191203 output.push_str(&mlf);
192204 output.push('\n');
193205 }
194206 "subscription" => {
195195- let mlf = generate_subscription(name, def)?;
207207+ let mlf = generate_subscription(name, def, last_segment)?;
196208 output.push_str(&mlf);
197209 output.push('\n');
198210 }
···215227 Ok(output)
216228}
217229218218-fn generate_record(name: &str, def: &Value) -> Result<String, MlfGenerateError> {
230230+/// Reserved words in MLF that need to be escaped
231231+const RESERVED_WORDS: &[&str] = &[
232232+ "main", "record", "query", "procedure", "subscription", "token", "def", "type", "use",
233233+ "pub", "alias", "namespace", "constrained", "error", "unit", "null", "boolean",
234234+ "integer", "string", "bytes", "blob", "unknown", "array", "object", "union", "ref",
235235+];
236236+237237+/// Escape a name if it's a reserved word
238238+fn escape_name(name: &str) -> String {
239239+ if RESERVED_WORDS.contains(&name) {
240240+ format!("`{}`", name)
241241+ } else {
242242+ name.to_string()
243243+ }
244244+}
245245+246246+fn generate_record(name: &str, def: &Value, last_segment: &str) -> Result<String, MlfGenerateError> {
219247 let mut output = String::new();
220248221249 // Add doc comment if present
···227255 }
228256 }
229257230230- // Use "main" name if present, otherwise use the definition name
258258+ // Use last segment of NSID for "main" definitions
231259 let record_name = if name == "main" {
232232- // Try to extract the last segment from the namespace ID
233233- // This is a heuristic - we could make it better
234234- "main"
260260+ escape_name(last_segment)
235261 } else {
236236- name
262262+ escape_name(name)
237263 };
238264239265 output.push_str(&format!("record {} {{\n", record_name));
···286312 Ok(output)
287313}
288314289289-fn generate_query(name: &str, def: &Value) -> Result<String, MlfGenerateError> {
315315+fn generate_query(name: &str, def: &Value, last_segment: &str) -> Result<String, MlfGenerateError> {
290316 let mut output = String::new();
291317292318 // Add doc comment
···298324 }
299325 }
300326301301- let query_name = if name == "main" { "query" } else { name };
327327+ let query_name = if name == "main" {
328328+ escape_name(last_segment)
329329+ } else {
330330+ escape_name(name)
331331+ };
302332 output.push_str(&format!("query {}", query_name));
303333304334 // Parameters
···368398 Ok(output)
369399}
370400371371-fn generate_procedure(name: &str, def: &Value) -> Result<String, MlfGenerateError> {
401401+fn generate_procedure(name: &str, def: &Value, last_segment: &str) -> Result<String, MlfGenerateError> {
372402 let mut output = String::new();
373403374404 // Add doc comment
···380410 }
381411 }
382412383383- let procedure_name = if name == "main" { "procedure" } else { name };
413413+ let procedure_name = if name == "main" {
414414+ escape_name(last_segment)
415415+ } else {
416416+ escape_name(name)
417417+ };
384418 output.push_str(&format!("procedure {}", procedure_name));
385419386420 // Input parameters
···456490 Ok(output)
457491}
458492459459-fn generate_subscription(name: &str, def: &Value) -> Result<String, MlfGenerateError> {
493493+fn generate_subscription(name: &str, def: &Value, last_segment: &str) -> Result<String, MlfGenerateError> {
460494 let mut output = String::new();
461495462496 // Add doc comment
···469503 }
470504471505 let subscription_name = if name == "main" {
472472- "subscription"
506506+ escape_name(last_segment)
473507 } else {
474474- name
508508+ escape_name(name)
475509 };
476510 output.push_str(&format!("subscription {}", subscription_name));
477511
+1-1
mlf-cli/src/workspace_ext.rs
···109109}
110110111111impl WorkspaceExt for Workspace {
112112- fn has_module(&self, namespace: &str) -> bool {
112112+ fn has_module(&self, _namespace: &str) -> bool {
113113 // This requires exposing the modules field or adding a method to mlf-lang
114114 // For now, we'll just try to add and catch the error
115115 // TODO: Add a proper has_module method to Workspace