@@ -107,6 +107,7 @@ impl ParserStateMachine {
107
107
108
108
#[ derive( Debug , Clone ) ]
109
109
pub struct Article {
110
+ pub order : i16 ,
110
111
pub topic : String ,
111
112
pub content : String ,
112
113
pub path : String ,
@@ -150,6 +151,27 @@ enum Keyword {
150
151
* ```
151
152
*/
152
153
Article ,
154
+ /**
155
+ * @Article Syntax
156
+ * `@Order <Order of the Article>` is for controlling the order of the article sections.
157
+ *
158
+ * Example:
159
+ *
160
+ * ```rust
161
+ * /**
162
+ * * @Article Usage example
163
+ * * @Order 2
164
+ * * ## Header2
165
+ * */
166
+ *
167
+ * /**
168
+ * * @Article Usage example
169
+ * * @Order 1
170
+ * * # Header1
171
+ * */
172
+ * ```
173
+ */
174
+ Order ,
153
175
/**
154
176
* @Article Syntax
155
177
* `@FileArticle` allows you to mark a whole file is a source of documentation for a specified
@@ -229,6 +251,7 @@ enum Keyword {
229
251
impl Keyword {
230
252
fn as_str ( & self ) -> & ' static str {
231
253
match * self {
254
+ Keyword :: Order => "@Order" ,
232
255
Keyword :: Article => "@Article" ,
233
256
Keyword :: FileArticle => "@FileArticle" ,
234
257
Keyword :: Ignore => "@Ignore" ,
@@ -262,6 +285,7 @@ impl Parser {
262
285
263
286
let articles: Vec < Article > = vec ! [ ] ;
264
287
let current_article = Article {
288
+ order : 0 ,
265
289
topic : String :: from ( "" ) ,
266
290
content : String :: from ( "" ) ,
267
291
path : String :: from ( "" ) ,
@@ -327,6 +351,14 @@ impl Parser {
327
351
result
328
352
}
329
353
354
+ fn parse_article_order ( & self , order_block_line : String ) -> i16 {
355
+ order_block_line
356
+ . replace ( Keyword :: Order . as_str ( ) , "" )
357
+ . trim ( )
358
+ . parse ( )
359
+ . unwrap_or ( 0 )
360
+ }
361
+
330
362
fn trim_article_line ( & self , line : String ) -> String {
331
363
line. trim_start ( )
332
364
. trim_start_matches ( self . comment_symbol )
@@ -336,6 +368,7 @@ impl Parser {
336
368
337
369
fn new_article ( & self ) -> Article {
338
370
Article {
371
+ order : 0 ,
339
372
topic : String :: from ( "" ) ,
340
373
content : String :: from ( "" ) ,
341
374
path : String :: from ( "" ) ,
@@ -350,6 +383,7 @@ impl Parser {
350
383
let topic = name_chunks[ 2 ..] . join ( "." ) ;
351
384
352
385
vec ! [ Article {
386
+ order: 0 ,
353
387
topic,
354
388
content: String :: from( file_content) ,
355
389
path: String :: from( file_path) ,
@@ -429,6 +463,13 @@ impl Parser {
429
463
self . current_article . topic = self . trim_article_line ( topic) ;
430
464
self . current_article . start_line = line_number;
431
465
self . state_machine . to_article_mut ( ) ;
466
+ } else if trimmed_line. starts_with ( Keyword :: Order . as_str ( ) )
467
+ && self . state_machine . is_in ( ParserState :: ArticleParsing )
468
+ {
469
+ let parsed_order = self . parse_article_order ( trimmed_line) ;
470
+
471
+ self . current_article . order = parsed_order;
472
+ self . current_article . start_line = line_number;
432
473
} else if trimmed_line. starts_with ( Keyword :: Ignore . as_str ( ) ) {
433
474
self . state_machine . to_skippintg_mut ( ) ;
434
475
self . current_article = self . new_article ( ) ;
@@ -484,6 +525,7 @@ impl Parser {
484
525
line_number += 1 ;
485
526
}
486
527
528
+ self . articles . sort_by_key ( |a| a. order ) ;
487
529
self . articles . clone ( )
488
530
}
489
531
@@ -559,6 +601,7 @@ pub fn test () {}
559
601
560
602
let articles = parser. parse_file ( file_content, "" ) ;
561
603
let expected_result = vec ! [ Article {
604
+ order: 0 ,
562
605
topic: String :: from( "Test article" ) ,
563
606
content: String :: from( "some text" ) ,
564
607
path: "" . to_string( ) ,
@@ -569,6 +612,48 @@ pub fn test () {}
569
612
assert_eq ! ( articles, expected_result) ;
570
613
}
571
614
615
+ #[ test]
616
+ fn parse_articles_with_custom_order ( ) {
617
+ let mut parser = Parser :: new ( get_test_config ( ) ) ;
618
+ let file_content = "
619
+ /**
620
+ * @Article Test article3
621
+ * @Order 3
622
+ * some text3
623
+ */
624
+ pub fn test () {}
625
+
626
+ /**
627
+ * @Article Test article1
628
+ * @Order 1
629
+ * some text
630
+ */
631
+ pub fn test2 () {}
632
+ " ;
633
+
634
+ let articles = parser. parse_file ( file_content, "" ) ;
635
+ let expected_result = vec ! [
636
+ Article {
637
+ order: 1 ,
638
+ topic: String :: from( "Test article1" ) ,
639
+ content: String :: from( "some text" ) ,
640
+ path: "" . to_string( ) ,
641
+ start_line: 11 ,
642
+ end_line: 12 ,
643
+ } ,
644
+ Article {
645
+ order: 3 ,
646
+ topic: String :: from( "Test article3" ) ,
647
+ content: String :: from( "some text3" ) ,
648
+ path: "" . to_string( ) ,
649
+ start_line: 4 ,
650
+ end_line: 5 ,
651
+ } ,
652
+ ] ;
653
+
654
+ assert_eq ! ( articles, expected_result) ;
655
+ }
656
+
572
657
#[ test]
573
658
fn ignore_comments_with_ignore_mark ( ) {
574
659
let mut parser = Parser :: new ( get_test_config ( ) ) ;
@@ -604,6 +689,7 @@ pub fn test () {}
604
689
605
690
let articles = parser. parse_file ( file_content, "" ) ;
606
691
let expected_result = vec ! [ Article {
692
+ order: 0 ,
607
693
topic: String :: from( "Test article" ) ,
608
694
content: String :: from( "some multiline\n awesome text" ) ,
609
695
path: "" . to_string( ) ,
@@ -650,6 +736,7 @@ pub fn test () {}
650
736
651
737
let articles = parser. parse_file ( file_content, "" ) ;
652
738
let expected_result = vec ! [ Article {
739
+ order: 0 ,
653
740
topic: String :: from( "Test article" ) ,
654
741
content: String :: from( "```rust\n fn main() {\n println!(\" Hello world!\" );\n }\n ```\n \n ```rust\n fn test() {\n println!(\" Hello world!\" );\n }\n ```" ) ,
655
742
path: "" . to_string( ) ,
@@ -684,6 +771,7 @@ fn parse_documentation_with_indentation_before_comments() {
684
771
685
772
let articles = parser. parse_file ( file_content, "" ) ;
686
773
let expected_result = vec ! [ Article {
774
+ order: 0 ,
687
775
topic: String :: from( "Test article" ) ,
688
776
content: String :: from( "#### [no-implicit-coercion](https://eslint.org/docs/rules/no-implicit-coercion)\n All implicit coercions except `!!` are disallowed:\n ```js\n // Fail\n +foo\n 1 * foo\n \' \' + foo\n `${foo}`\n ~foo.indexOf(bar)\n \n // Pass\n !!foo\n ```" ) ,
689
777
path: "" . to_string( ) ,
@@ -714,6 +802,7 @@ pub fn test () {}
714
802
715
803
let articles = parser. parse_file ( file_content, "" ) ;
716
804
let expected_result = vec ! [ Article {
805
+ order: 0 ,
717
806
topic: String :: from( "Test article" ) ,
718
807
content: String :: from( "List:\n * Item 1\n * Item 2\n \n Item 2 subtext\n * Item 3" ) ,
719
808
path: "" . to_string( ) ,
@@ -738,6 +827,7 @@ use std::io::prelude::*;
738
827
739
828
let articles = parser. parse_file ( file_content, "" ) ;
740
829
let expected_result = vec ! [ Article {
830
+ order: 0 ,
741
831
topic: String :: from( "Test article" ) ,
742
832
content: String :: from( "" ) ,
743
833
path: "" . to_string( ) ,
760
850
761
851
let articles = parser. parse_file ( file_content, "" ) ;
762
852
let expected_result = vec ! [ Article {
853
+ order: 0 ,
763
854
topic: String :: from( "Test article" ) ,
764
855
content: String :: from( "test" ) ,
765
856
path: "" . to_string( ) ,
@@ -784,6 +875,7 @@ const b = 2
784
875
785
876
let articles = parser. parse_file ( file_content, "" ) ;
786
877
let expected_result = vec ! [ Article {
878
+ order: 0 ,
787
879
topic: String :: from( "Test article" ) ,
788
880
content: String :: from( "test" ) ,
789
881
path: "" . to_string( ) ,
@@ -816,13 +908,15 @@ fn use_global_article_attribute() {
816
908
let articles = parser. parse_file ( file_content, "" ) ;
817
909
let expected_result = vec ! [
818
910
Article {
911
+ order: 0 ,
819
912
topic: String :: from( "Test article" ) ,
820
913
content: String :: from( "test" ) ,
821
914
path: "" . to_string( ) ,
822
915
start_line: 6 ,
823
916
end_line: 7 ,
824
917
} ,
825
918
Article {
919
+ order: 0 ,
826
920
topic: String :: from( "Test article" ) ,
827
921
content: String :: from( "test" ) ,
828
922
path: "" . to_string( ) ,
@@ -856,6 +950,7 @@ fn ignore_sections_in_case_of_global_article() {
856
950
857
951
let articles = parser. parse_file ( file_content, "" ) ;
858
952
let expected_result = vec ! [ Article {
953
+ order: 0 ,
859
954
topic: String :: from( "Test article" ) ,
860
955
content: String :: from( "test" ) ,
861
956
path: "" . to_string( ) ,
@@ -881,6 +976,7 @@ const TIMEOUT = 3000
881
976
882
977
let articles = parser. parse_file ( file_content, "" ) ;
883
978
let expected_result = vec ! [ Article {
979
+ order: 0 ,
884
980
topic: String :: from( "Test article" ) ,
885
981
content: String :: from( "Request timeout:\n ```js/\n const TIMEOUT = 3000\n ```" ) ,
886
982
path: "" . to_string( ) ,
@@ -908,6 +1004,7 @@ const TIMEOUT = 3000
908
1004
909
1005
let articles = parser. parse_file ( file_content, "" ) ;
910
1006
let expected_result = vec ! [ Article {
1007
+ order: 0 ,
911
1008
topic: String :: from( "Test article" ) ,
912
1009
content: String :: from( "Request timeout:\n ```js/\n const TIMEOUT = 3000\n ```" ) ,
913
1010
path: "" . to_string( ) ,
@@ -933,6 +1030,7 @@ fn parse_code_block_attribute_from_ending_comment_only() {
933
1030
934
1031
let articles = parser. parse_file ( file_content, "" ) ;
935
1032
let expected_result = vec ! [ Article {
1033
+ order: 0 ,
936
1034
topic: String :: from( "Test article" ) ,
937
1035
content: String :: from( "Should ignore @CodeBlockEnd in a text block\n ```rust/\n ...\n ```" ) ,
938
1036
path: "" . to_string( ) ,
@@ -960,6 +1058,7 @@ fn parse_nested_commends() {
960
1058
961
1059
let articles = parser. parse_file ( file_content, "" ) ;
962
1060
let expected_result = vec ! [ Article {
1061
+ order: 0 ,
963
1062
topic: String :: from( "Test article" ) ,
964
1063
content: String :: from( "Example:\n /**\n * @Article Example article\n * Example\n */\n test" ) ,
965
1064
path: "" . to_string( ) ,
@@ -998,6 +1097,7 @@ fn parse_fdoc_file_check() {
998
1097
let parser = Parser :: new ( get_test_config ( ) ) ;
999
1098
let result = parser. parse_fdoc_file ( "test" , "/some/long/path/to/file.fdoc.md" ) ;
1000
1099
let expected_result = vec ! [ Article {
1100
+ order: 0 ,
1001
1101
topic: String :: from( "file" ) ,
1002
1102
content: String :: from( "test" ) ,
1003
1103
path: "/some/long/path/to/file.fdoc.md" . to_string( ) ,
0 commit comments