You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: parse.rs
    path of file: ./repos/oxc/crates/oxc_semantic/src/jsdoc/parser
    
    the code of the file until where you have to start completion: use super::jsdoc_tag::{JSDocTag, JSDocTagKind};
use super::jsdoc_tag::{Param, ParamType};
use super::utils;

#[derive(Debug)]
pub struct JSDocParser<'a> {
    source_text: &'a str,
    current: usize,
}

// Refs: `parseJSDocCommentWorker()` and `doJSDocScan()` from TypeScript
// https://github.com/microsoft/TypeScript/blob/df8d755c1d76eaf0a8f1c1046a46061b53315718/src/compiler/parser.ts#L8814
impl<'a> JSDocParser<'a> {
    /// source_text: Inside of /**HERE*/, NOT includes `/**` and `*/`
    pub fn new(source_text: &'a str) -> Self {
        // Outer spaces can be trimmed
        Self { source_text: source_text.trim(), current: 0 }
    }

    pub fn parse(mut self) -> (String, Vec<JSDocTag<'a>>) {
        let comment = self.parse_comment();
        let tags = self.parse_tags();

        (comment, tags)
    }

    // JSDoc comment starts with description comment until the first `@` appears
    fn parse_comment(&mut self) -> String {
        // TODO: Should ignore inside of inline tags like `{@link}`?
        let comment = self.take_until(|c| c == '@');
        utils::trim_multiline_comment(comment)
    }

    fn parse_tags(&mut self) -> Vec<JSDocTag<'a>> {
        let mut tags = vec![];

        // Let's start with the first `@`
        while let Some(c) = self.source_text.chars().nth(self.current) {
            match c {
                '@' => {
                    self.current += 1;
                    tags.push(self.parse_tag());
                }
                _ => {
                    self.current += 1;
                }
            }
        }

        tags
    }

    fn parse_tag(&mut self) -> JSDocTag<'a> {
        let tag_name = self.take_until(|c| c == ' ' || c == '\n' || c == '@');
        match tag_name {
            // TODO: Add more tags
            "arg" | "argument" | "param" => self.parse_parameter_tag(),
            "deprecated" => self.parse_simple_tag(JSDocTagKind::Deprecated),
            _ => self.parse_simple_tag(JSDocTagKind::Unknown(tag_name)),
        }
    }

    // @tag_name [<some text>]
    fn parse_simple_tag(&mut self, kind: JSDocTagKind<'a>) -> JSDocTag<'a> {
        let comment = self.take_until(|c| c == '@');
        let comment = utils::trim_multiline_comment(comment);
        JSDocTag { kind, comment }
    }

    // @param n
    
    fn parses_parameter_tag() {
        assert_eq!(
            parse_from_full_text("/** @param */").1,
            vec![JSDocTag {
                kind: JSDocTagKind::Parameter(Param { name: "", r#type: None }),
                comment: String::new(),
            },]
        );
        assert_eq!(
            parse_from_full_text("/** @param @noop */").1,
            vec![
                JSDocTag {
                    kind: JSDocTagKind::Parameter(Param { name: "", r#type: None }),
                    comment: String::new(),
                },
                JSDocTag { kind: JSDocTagKind::Unknown("noop"), comment: String::new() },
            ]
        );
        assert_eq!(
            parse_from_full_text("/** @param name */").1,
            vec![JSDocTag {
                kind: JSDocTagKind::Parameter(Param { name: "name", r#type: None }),
                comment: String::new(),
            },]
        );
        assert_eq!(
            parse_from_full_text("/** @param {str} name */").1,
            vec![JSDocTag {
                kind: JSDocTagKind::Parameter(Param {
                    name: "name",
                    r#type: Some(ParamType { value: "str" })
                }),
                comment: String::new(),
            },]
        );
        assert_eq!(
            parse_from_full_text("/** @param {str} name comment */").1,
            vec![JSDocTag {
                kind: JSDocTagKind::Parameter(Param {
                    name: "name",
                    r#type: Some(ParamType { value: "str" })
                }),
                comment: "comment".to_string(),
            },]
        );
        assert_eq!(
            parse_from_full_text("/** @param {str} name comment */"),
            parse_from_full_text("/** @param {str} name - comment */"),
        );
        assert_eq!(
            parse_from_full_text("/** @param {str} name comment */"),
            parse_from_full_text(
                "/** @param {str} name
comment */"
            ),
        );
        assert_eq!(
            parse_from_full_text(
                "/** @param {str} name
comment */"
            ),
            parse_from_full_text(
                "/** 
                  * @param {str} name
                  * comment
                  */"
            ),
        );

        assert_eq!(
            parse_from_full_text(
                "
                /**
                 * @param {boolean} a
                 * @param {string b
                 * @param {string} c comment
                 * @param {Num} d - comment2
                 */
        "
            )
            .1,
            vec![
                JSDocTag {
                    kind: JSDocTagKind::Parameter(Param {
                        name: "a",
                        r#type: Some(ParamType { value: "boolean" })
                    }),
                    comment: String::new(),
                },
                JSDocTag {
                    kind: JSDocTagKind::Parameter(Param {
                        name: "b",
                        r#type: Some(ParamType { value: "string" })
                    }),
                    comment: String::new(),
                },
                JSDocTag {
                    kind: JSDocTagKind::Parameter(Param {
                        name: "c",
                        r#type: Some(ParamType { value: "string" })
                    }),
                    comment: "comment".to_string(),
                },
                JSDocTag {
                    kind: JSDocTagKind::Parameter(Param {
                        name: "d",
                        r#type: Some(ParamType { value: "Num" })
                    }),
                    comment: "comment2".to_string(),
                },
            ]
        );
    }
}