fix(semantic/jsdoc): Support multibyte chars (#2694)

Co-authored-by: Boshen <boshenc@gmail.com>
This commit is contained in:
Yuji Sugiura 2024-03-13 20:00:01 +09:00 committed by GitHub
parent c820a5b661
commit b00d4b8110
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -35,14 +35,14 @@ impl<'a> JSDocParser<'a> {
let mut tags = vec![]; let mut tags = vec![];
// Let's start with the first `@` // Let's start with the first `@`
while let Some(c) = self.source_text.chars().nth(self.current) { while let Some(c) = self.source_text[self.current..].chars().next() {
match c { match c {
'@' => { '@' => {
self.current += 1; self.current += c.len_utf8();
tags.push(self.parse_tag()); tags.push(self.parse_tag());
} }
_ => { _ => {
self.current += 1; self.current += c.len_utf8();
} }
} }
} }
@ -91,7 +91,8 @@ impl<'a> JSDocParser<'a> {
self.skip_whitespace(); self.skip_whitespace();
// JSDoc.app ignores `-` char between name and comment, but TS doesn't // JSDoc.app ignores `-` char between name and comment, but TS doesn't
if self.at('-') { // Some people use `:` as separator
if self.at('-') || self.at(':') {
self.skip_whitespace(); self.skip_whitespace();
} }
@ -103,27 +104,29 @@ impl<'a> JSDocParser<'a> {
// //
// Parser utils // Parser utils
// //
fn skip_whitespace(&mut self) { fn skip_whitespace(&mut self) {
while let Some(c) = self.source_text.chars().nth(self.current) { while let Some(c) = self.source_text[self.current..].chars().next() {
if c != ' ' { if c != ' ' {
break; break;
} }
self.current += 1; self.current += c.len_utf8();
} }
} }
fn advance(&mut self) { fn advance(&mut self) {
if self.current < self.source_text.len() { if let Some(c) = self.source_text[self.current..].chars().next() {
self.current += 1; self.current += c.len_utf8();
} }
} }
fn at(&mut self, c: char) -> bool { fn at(&mut self, c: char) -> bool {
let Some(ch) = self.source_text.chars().nth(self.current) else { return false }; if let Some(ch) = self.source_text[self.current..].chars().next() {
if ch == c { if ch == c {
self.advance(); self.advance();
true true
} else {
false
}
} else { } else {
false false
} }
@ -131,11 +134,11 @@ impl<'a> JSDocParser<'a> {
fn take_until(&mut self, predicate: fn(char) -> bool) -> &'a str { fn take_until(&mut self, predicate: fn(char) -> bool) -> &'a str {
let start = self.current; let start = self.current;
while let Some(c) = self.source_text.chars().nth(self.current) { while let Some(c) = self.source_text[self.current..].chars().next() {
if predicate(c) { if predicate(c) {
break; break;
} }
self.current += 1; self.current += c.len_utf8();
} }
&self.source_text[start..self.current] &self.source_text[start..self.current]
} }
@ -173,13 +176,24 @@ mod test {
assert_eq!( assert_eq!(
parse_from_full_text( parse_from_full_text(
"/** "/**
this is comment this is
comment
@x @x
*/" */"
) )
.0, .0,
"this is comment" "this is\ncomment"
);
assert_eq!(
parse_from_full_text(
"/**
         *
         * multibyte文字はどう
*/"
)
.0,
"日本語とか\nmultibyte文字はどう"
); );
} }
@ -394,7 +408,7 @@ comment */"
comment */" comment */"
), ),
parse_from_full_text( parse_from_full_text(
"/** "/**
* @param {str} name * @param {str} name
* comment * comment
*/" */"
@ -445,4 +459,61 @@ comment */"
] ]
); );
} }
#[test]
fn parses_practical_with_multibyte() {
let jsdoc = parse_from_full_text(
"/**
* flat tree data on expanded state
*
* @export
* @template T
* @param {*} data : table data
* @param {string} childrenColumnName :
* @param {Set<Key>} expandedKeys : keys
* @param {GetRowKey<T>} getRowKey : rowKey的方法
* @returns flattened data
*/",
);
assert_eq!(jsdoc.0, "flat tree data on expanded state");
assert_eq!(
jsdoc.1,
vec![
JSDocTag { kind: JSDocTagKind::Unknown("export"), comment: String::new() },
JSDocTag { kind: JSDocTagKind::Unknown("template"), comment: "T".to_string() },
JSDocTag {
kind: JSDocTagKind::Parameter(Param {
name: "data",
r#type: Some(ParamType { value: "*" })
}),
comment: "table data".to_string(),
},
JSDocTag {
kind: JSDocTagKind::Parameter(Param {
name: "childrenColumnName",
r#type: Some(ParamType { value: "string" })
}),
comment: "指定树形结构的列名".to_string(),
},
JSDocTag {
kind: JSDocTagKind::Parameter(Param {
name: "expandedKeys",
r#type: Some(ParamType { value: "Set<Key>" })
}),
comment: "展开的行对应的keys".to_string(),
},
JSDocTag {
kind: JSDocTagKind::Parameter(Param {
name: "getRowKey",
r#type: Some(ParamType { value: "GetRowKey<T>" })
}),
comment: "获取当前rowKey的方法".to_string(),
},
JSDocTag {
kind: JSDocTagKind::Unknown("returns"),
comment: "flattened data".to_string(),
},
]
);
}
} }