@@ -6,16 +6,16 @@ use serde::Serialize;
6
6
7
7
lazy_static ! {
8
8
static ref JS_DOC_TAG_MAYBE_DOC_RE : Regex = Regex :: new( r"(?s)^\s*@(deprecated)(?:\s+(.+))?" ) . unwrap( ) ;
9
- static ref JS_DOC_TAG_DOC_RE : Regex = Regex :: new( r"(?s)^\s*@(category|see|example|tags)(?:\s+(.+))" ) . unwrap( ) ;
9
+ static ref JS_DOC_TAG_DOC_RE : Regex = Regex :: new( r"(?s)^\s*@(category|see|example|tags|since )(?:\s+(.+))" ) . unwrap( ) ;
10
10
static ref JS_DOC_TAG_NAMED_RE : Regex = Regex :: new( r"(?s)^\s*@(callback|template|typeparam|typeParam)\s+([a-zA-Z_$]\S*)(?:\s+(.+))?" ) . unwrap( ) ;
11
11
static ref JS_DOC_TAG_NAMED_TYPED_RE : Regex = Regex :: new( r"(?s)^\s*@(prop(?:erty)?|typedef)\s+\{([^}]+)\}\s+([a-zA-Z_$]\S*)(?:\s+(.+))?" ) . unwrap( ) ;
12
- static ref JS_DOC_TAG_ONLY_RE : Regex = Regex :: new( r"^\s*@(constructor|class|ignore|module|public|private|protected|readonly)" ) . unwrap( ) ;
12
+ static ref JS_DOC_TAG_ONLY_RE : Regex = Regex :: new( r"^\s*@(constructor|class|ignore|internal| module|public|private|protected|readonly|experimental )" ) . unwrap( ) ;
13
13
static ref JS_DOC_TAG_PARAM_RE : Regex = Regex :: new(
14
14
r"(?s)^\s*@(?:param|arg(?:ument)?)(?:\s+\{(?P<type>[^}]+)\})?\s+(?:(?:\[(?P<nameWithDefault>[a-zA-Z_$]\S*?)(?:\s*=\s*(?P<default>[^]]+))?\])|(?P<name>[a-zA-Z_$]\S*))(?:\s+(?P<doc>.+))?"
15
15
)
16
16
. unwrap( ) ;
17
17
static ref JS_DOC_TAG_RE : Regex = Regex :: new( r"(?s)^\s*@(\S+)" ) . unwrap( ) ;
18
- static ref JS_DOC_TAG_RETURN_RE : Regex = Regex :: new( r"(?s)^\s*@returns?(?:\s+\{([^}]+)\})?(?:\s+(.+))?" ) . unwrap( ) ;
18
+ static ref JS_DOC_TAG_OPTIONAL_TYPE_AND_DOC_RE : Regex = Regex :: new( r"(?s)^\s*@( returns?|throws|exception) (?:\s+\{([^}]+)\})?(?:\s+(.+))?" ) . unwrap( ) ;
19
19
static ref JS_DOC_TAG_TYPED_RE : Regex = Regex :: new( r"(?s)^\s*@(enum|extends|augments|this|type|default)\s+\{([^}]+)\}(?:\s+(.+))?" ) . unwrap( ) ;
20
20
}
21
21
@@ -115,6 +115,8 @@ pub enum JsDocTag {
115
115
#[ serde( default ) ]
116
116
doc : String ,
117
117
} ,
118
+ /// `@experimental`
119
+ Experimental ,
118
120
/// `@extends {type} comment`
119
121
Extends {
120
122
#[ serde( rename = "type" ) ]
@@ -124,6 +126,8 @@ pub enum JsDocTag {
124
126
} ,
125
127
/// `@ignore`
126
128
Ignore ,
129
+ /// `@internal`
130
+ Internal ,
127
131
/// `@module`
128
132
Module ,
129
133
/// `@param`, `@arg` or `argument`, in format of `@param {type} name comment`
@@ -182,6 +186,13 @@ pub enum JsDocTag {
182
186
#[ serde( skip_serializing_if = "Option::is_none" , default ) ]
183
187
doc : Option < String > ,
184
188
} ,
189
+ /// `@throws {type} comment` or `@exception {type} comment`
190
+ Throws {
191
+ #[ serde( rename = "type" ) ]
192
+ type_ref : Option < String > ,
193
+ #[ serde( skip_serializing_if = "Option::is_none" , default ) ]
194
+ doc : Option < String > ,
195
+ } ,
185
196
/// `@typedef {type} name comment`
186
197
TypeDef {
187
198
name : String ,
@@ -202,6 +213,10 @@ pub enum JsDocTag {
202
213
See {
203
214
doc : String ,
204
215
} ,
216
+ /// `@since version`
217
+ Since {
218
+ doc : String ,
219
+ } ,
205
220
Unsupported {
206
221
value : String ,
207
222
} ,
@@ -213,7 +228,9 @@ impl From<String> for JsDocTag {
213
228
let kind = caps. get ( 1 ) . unwrap ( ) . as_str ( ) ;
214
229
match kind {
215
230
"constructor" | "class" => Self :: Constructor ,
231
+ "experimental" => Self :: Experimental ,
216
232
"ignore" => Self :: Ignore ,
233
+ "internal" => Self :: Internal ,
217
234
"module" => Self :: Module ,
218
235
"public" => Self :: Public ,
219
236
"private" => Self :: Private ,
@@ -280,6 +297,7 @@ impl From<String> for JsDocTag {
280
297
tags : doc. split ( ',' ) . map ( |i| i. trim ( ) . to_string ( ) ) . collect ( ) ,
281
298
} ,
282
299
"see" => Self :: See { doc } ,
300
+ "since" => Self :: Since { doc } ,
283
301
_ => unreachable ! ( "kind unexpected: {}" , kind) ,
284
302
}
285
303
} else if let Some ( caps) = JS_DOC_TAG_PARAM_RE . captures ( & value) {
@@ -300,10 +318,17 @@ impl From<String> for JsDocTag {
300
318
default,
301
319
doc,
302
320
}
303
- } else if let Some ( caps) = JS_DOC_TAG_RETURN_RE . captures ( & value) {
304
- let type_ref = caps. get ( 1 ) . map ( |m| m. as_str ( ) . to_string ( ) ) ;
305
- let doc = caps. get ( 2 ) . map ( |m| m. as_str ( ) . to_string ( ) ) ;
306
- Self :: Return { type_ref, doc }
321
+ } else if let Some ( caps) =
322
+ JS_DOC_TAG_OPTIONAL_TYPE_AND_DOC_RE . captures ( & value)
323
+ {
324
+ let kind = caps. get ( 1 ) . unwrap ( ) . as_str ( ) ;
325
+ let type_ref = caps. get ( 2 ) . map ( |m| m. as_str ( ) . to_string ( ) ) ;
326
+ let doc = caps. get ( 3 ) . map ( |m| m. as_str ( ) . to_string ( ) ) ;
327
+ match kind {
328
+ "return" | "returns" => Self :: Return { type_ref, doc } ,
329
+ "throws" | "exception" => Self :: Throws { type_ref, doc } ,
330
+ _ => unreachable ! ( "kind unexpected: {}" , kind) ,
331
+ }
307
332
} else {
308
333
Self :: Unsupported { value }
309
334
}
@@ -325,6 +350,11 @@ mod tests {
325
350
serde_json:: to_value( JsDoc :: from( "@class more" . to_string( ) ) ) . unwrap( ) ,
326
351
json!( { "tags" : [ { "kind" : "constructor" } ] } ) ,
327
352
) ;
353
+ assert_eq ! (
354
+ serde_json:: to_value( JsDoc :: from( "@experimental more" . to_string( ) ) )
355
+ . unwrap( ) ,
356
+ json!( { "tags" : [ { "kind" : "experimental" } ] } ) ,
357
+ ) ;
328
358
assert_eq ! (
329
359
serde_json:: to_value( JsDoc :: from( "@ignore more" . to_string( ) ) ) . unwrap( ) ,
330
360
json!( { "tags" : [ { "kind" : "ignore" } ] } ) ,
@@ -629,6 +659,15 @@ if (true) {
629
659
} ]
630
660
} )
631
661
) ;
662
+ assert_eq ! (
663
+ serde_json:: to_value( JsDoc :: from( "@since 1.0.0" . to_string( ) ) ) . unwrap( ) ,
664
+ json!( {
665
+ "tags" : [ {
666
+ "kind" : "since" ,
667
+ "doc" : "1.0.0"
668
+ } ]
669
+ } )
670
+ ) ;
632
671
633
672
assert_eq ! (
634
673
serde_json:: to_value( JsDoc :: from(
@@ -637,6 +676,7 @@ if (true) {
637
676
const a = "a";
638
677
@category foo
639
678
@see bar
679
+ @since 1.0.0
640
680
"#
641
681
. to_string( )
642
682
) )
@@ -654,6 +694,9 @@ const a = "a";
654
694
} , {
655
695
"kind" : "see" ,
656
696
"doc" : "bar"
697
+ } , {
698
+ "kind" : "since" ,
699
+ "doc" : "1.0.0"
657
700
} ]
658
701
659
702
} )
@@ -798,6 +841,49 @@ const a = "a";
798
841
) ;
799
842
}
800
843
844
+ #[ test]
845
+ fn test_js_doc_tag_throws ( ) {
846
+ assert_eq ! (
847
+ serde_json:: to_value( JsDoc :: from(
848
+ "@throws {string} maybe doc\n \n new paragraph" . to_string( )
849
+ ) )
850
+ . unwrap( ) ,
851
+ json!( {
852
+ "tags" : [ {
853
+ "kind" : "throws" ,
854
+ "type" : "string" ,
855
+ "doc" : "maybe doc\n \n new paragraph" ,
856
+ } ]
857
+ } )
858
+ ) ;
859
+ assert_eq ! (
860
+ serde_json:: to_value( JsDoc :: from(
861
+ "@throws maybe doc\n \n new paragraph" . to_string( )
862
+ ) )
863
+ . unwrap( ) ,
864
+ json!( {
865
+ "tags" : [ {
866
+ "kind" : "throws" ,
867
+ "type" : null,
868
+ "doc" : "maybe doc\n \n new paragraph" ,
869
+ } ]
870
+ } )
871
+ ) ;
872
+ assert_eq ! (
873
+ serde_json:: to_value( JsDoc :: from(
874
+ "@throws {string} maybe doc\n \n new paragraph" . to_string( )
875
+ ) )
876
+ . unwrap( ) ,
877
+ json!( {
878
+ "tags" : [ {
879
+ "kind" : "throws" ,
880
+ "type" : "string" ,
881
+ "doc" : "maybe doc\n \n new paragraph" ,
882
+ } ]
883
+ } )
884
+ ) ;
885
+ }
886
+
801
887
#[ test]
802
888
fn test_js_doc_from_str ( ) {
803
889
assert_eq ! (
0 commit comments