Skip to content

Commit e3cf909

Browse files
committed
fix(doc): allow mapped type trailing semicolon omission
1 parent a10a7e2 commit e3cf909

4 files changed

Lines changed: 59 additions & 5 deletions

File tree

crates/emmylua_code_analysis/src/db_index/type/humanize_type.rs

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ use itertools::Itertools;
55

66
use crate::{
77
AsyncState, DbIndex, LuaAliasCallType, LuaConditionalType, LuaFunctionType, LuaGenericType,
8-
LuaIntersectionType, LuaMemberKey, LuaMemberOwner, LuaObjectType, LuaSignatureId,
9-
LuaStringTplType, LuaTupleType, LuaType, LuaTypeDeclId, LuaUnionType, TypeSubstitutor,
10-
VariadicType,
8+
LuaIntersectionType, LuaMappedType, LuaMemberKey, LuaMemberOwner, LuaObjectType,
9+
LuaSignatureId, LuaStringTplType, LuaTupleType, LuaType, LuaTypeDeclId, LuaUnionType,
10+
TypeSubstitutor, VariadicType,
1111
};
1212

1313
use super::{LuaAliasCallKind, LuaMultiLineUnion};
@@ -217,9 +217,9 @@ impl<'a> TypeHumanizer<'a> {
217217
}
218218
LuaType::Language(s) => w.write_str(s),
219219
LuaType::Conditional(c) => self.write_conditional_type(c, w),
220+
LuaType::Mapped(mapped) => self.write_mapped_type(mapped, w),
220221
LuaType::Never => w.write_str("never"),
221222
LuaType::ModuleRef(file_id) => self.write_module_ref(*file_id, w),
222-
_ => w.write_str("unknown"),
223223
}
224224
}
225225

@@ -1082,6 +1082,36 @@ impl<'a> TypeHumanizer<'a> {
10821082
Ok(())
10831083
}
10841084

1085+
// ─── Mapped ─────────────────────────────────────────────────────
1086+
1087+
fn write_mapped_type<W: Write>(&mut self, mapped: &LuaMappedType, w: &mut W) -> fmt::Result {
1088+
w.write_str("{ ")?;
1089+
if mapped.is_readonly {
1090+
w.write_str("readonly ")?;
1091+
}
1092+
1093+
w.write_char('[')?;
1094+
w.write_str(mapped.param.1.name.as_str())?;
1095+
w.write_str(" in ")?;
1096+
1097+
let saved = self.level;
1098+
self.level = self.child_level();
1099+
if let Some(constraint) = &mapped.param.1.constraint {
1100+
self.write_type(constraint, w)?;
1101+
} else {
1102+
w.write_str("unknown")?;
1103+
}
1104+
w.write_char(']')?;
1105+
if mapped.is_optional {
1106+
w.write_char('?')?;
1107+
}
1108+
w.write_str(": ")?;
1109+
self.write_type(&mapped.value, w)?;
1110+
self.level = saved;
1111+
1112+
w.write_str("; }")
1113+
}
1114+
10851115
// ─── ModuleRef ──────────────────────────────────────────────────
10861116

10871117
fn write_module_ref<W: Write>(&mut self, file_id: crate::FileId, w: &mut W) -> fmt::Result {

crates/emmylua_ls/src/handlers/test/hover_test.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,18 @@ mod tests {
361361
},
362362
));
363363

364+
check!(
365+
ws.check_hover(
366+
r#"
367+
---@alias Co<??>py<T> { readonly [K in keyof T]?: T[K] }
368+
"#,
369+
VirtualHoverResult {
370+
value: "```lua\n(alias) Copy<T> = { readonly [K in keyof T]?: T[K]; }\n```"
371+
.to_string(),
372+
},
373+
)
374+
);
375+
364376
check!(
365377
ws.check_hover(
366378
r#"

crates/emmylua_parser/src/grammar/doc/test.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3268,6 +3268,14 @@ Syntax(Chunk)@0..110
32683268
assert_ast_eq!(code, result);
32693269
}
32703270

3271+
#[test]
3272+
fn test_mapped_type_omits_trailing_semicolon_before_close_brace() {
3273+
let code = r#"---@alias Copy<T> { [K in keyof T]: T[K] }"#;
3274+
let tree = LuaParser::parse(code, ParserConfig::default());
3275+
3276+
assert_eq!(tree.get_errors(), &[]);
3277+
}
3278+
32713279
#[test]
32723280
fn test_alias_conditional_infer_dots() {
32733281
let code = r#"

crates/emmylua_parser/src/grammar/doc/types.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,11 @@ fn parse_mapped_type(p: &mut LuaDocParser, m: Marker) -> DocParseResult {
248248

249249
parse_type(p)?;
250250

251-
expect_token(p, LuaTokenKind::TkSemicolon)?;
251+
if p.current_token() == LuaTokenKind::TkSemicolon {
252+
p.bump();
253+
} else if p.current_token() != LuaTokenKind::TkRightBrace {
254+
expect_token(p, LuaTokenKind::TkSemicolon)?;
255+
}
252256
expect_token(p, LuaTokenKind::TkRightBrace)?;
253257

254258
p.set_parser_state(LuaDocParserState::Normal);

0 commit comments

Comments
 (0)