mirror of
https://github.com/danbulant/oxc
synced 2026-05-25 12:51:57 +00:00
fix(semantic/jsdoc): Skip parsing @ inside of backticks (#3017)
This PR aims to support these cases.
````js
/**
* This is normal comment, `@xxx` should not parsed as tag.
*
* @example ```ts
// @comment
@decoratorInComment
class Foo { }
```
*/
````
Only `@example` should be parsed as tag.
This commit is contained in:
parent
395ad76410
commit
2c325ef3d6
2 changed files with 44 additions and 2 deletions
|
|
@ -304,4 +304,30 @@ line2
|
||||||
let (type_part, comment_part) = tag.type_comment();
|
let (type_part, comment_part) = tag.type_comment();
|
||||||
assert_eq!((type_part, comment_part.parsed()), (None, "flattened data".to_string()));
|
assert_eq!((type_part, comment_part.parsed()), (None, "flattened data".to_string()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parses_with_backticks() {
|
||||||
|
let allocator = Allocator::default();
|
||||||
|
let semantic = build_semantic(
|
||||||
|
&allocator,
|
||||||
|
"
|
||||||
|
/**
|
||||||
|
* This is normal comment, `@xxx` should not parsed as tag.
|
||||||
|
*
|
||||||
|
* @example ```ts
|
||||||
|
// @comment
|
||||||
|
@decoratorInComment
|
||||||
|
class Foo { }
|
||||||
|
```
|
||||||
|
*/
|
||||||
|
",
|
||||||
|
);
|
||||||
|
let jsdoc = semantic.jsdoc().iter_all().next().unwrap();
|
||||||
|
|
||||||
|
let mut tags = jsdoc.tags().iter();
|
||||||
|
assert_eq!(tags.len(), 1);
|
||||||
|
|
||||||
|
let tag = tags.next().unwrap();
|
||||||
|
assert_eq!(tag.kind.parsed(), "example");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,14 +19,30 @@ pub fn parse_jsdoc(source_text: &str, jsdoc_span_start: u32) -> (JSDocCommentPar
|
||||||
// So, find `@` to split comment and each tag.
|
// So, find `@` to split comment and each tag.
|
||||||
// But `@` can be found inside of `{}` (e.g. `{@see link}`), it should be distinguished.
|
// But `@` can be found inside of `{}` (e.g. `{@see link}`), it should be distinguished.
|
||||||
let mut in_braces = false;
|
let mut in_braces = false;
|
||||||
|
// Also, `@` is often found inside of backtick(` or ```), like markdown.
|
||||||
|
let mut in_backticks = false;
|
||||||
let mut comment_found = false;
|
let mut comment_found = false;
|
||||||
// Parser local offsets, not for global span
|
// Parser local offsets, not for global span
|
||||||
let (mut start, mut end) = (0, 0);
|
let (mut start, mut end) = (0, 0);
|
||||||
for ch in source_text.chars() {
|
|
||||||
|
let mut chars = source_text.chars().peekable();
|
||||||
|
while let Some(ch) = chars.next() {
|
||||||
|
let can_parse = !(in_braces || in_backticks);
|
||||||
match ch {
|
match ch {
|
||||||
|
// NOTE: For now, only odd backtick(s) are handled.
|
||||||
|
// - 1 backtick: inline code
|
||||||
|
// - 3, 5, ... backticks: code fence
|
||||||
|
// Not so common but technically, major markdown parser can handle 3 or more backticks as code fence.
|
||||||
|
// (for nested code blocks)
|
||||||
|
// But for now, 4, 6, ... backticks are not handled here to keep things simple...
|
||||||
|
'`' => {
|
||||||
|
if chars.peek().is_some_and(|&c| c != '`') {
|
||||||
|
in_backticks = !in_backticks;
|
||||||
|
}
|
||||||
|
}
|
||||||
'{' => in_braces = true,
|
'{' => in_braces = true,
|
||||||
'}' => in_braces = false,
|
'}' => in_braces = false,
|
||||||
'@' if !in_braces => {
|
'@' if can_parse => {
|
||||||
let part = &source_text[start..end];
|
let part = &source_text[start..end];
|
||||||
let span = Span::new(
|
let span = Span::new(
|
||||||
jsdoc_span_start + u32::try_from(start).unwrap_or_default(),
|
jsdoc_span_start + u32::try_from(start).unwrap_or_default(),
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue