Skip to content

Commit aef05cc

Browse files
committed
feat: add the ability to order articles
1 parent d3c66c3 commit aef05cc

File tree

2 files changed

+98
-2
lines changed

2 files changed

+98
-2
lines changed

src/parser.rs

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ impl ParserStateMachine {
107107

108108
#[derive(Debug, Clone)]
109109
pub struct Article {
110+
pub order: i16,
110111
pub topic: String,
111112
pub content: String,
112113
pub path: String,
@@ -150,6 +151,27 @@ enum Keyword {
150151
* ```
151152
*/
152153
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,
153175
/**
154176
* @Article Syntax
155177
* `@FileArticle` allows you to mark a whole file is a source of documentation for a specified
@@ -229,6 +251,7 @@ enum Keyword {
229251
impl Keyword {
230252
fn as_str(&self) -> &'static str {
231253
match *self {
254+
Keyword::Order => "@Order",
232255
Keyword::Article => "@Article",
233256
Keyword::FileArticle => "@FileArticle",
234257
Keyword::Ignore => "@Ignore",
@@ -262,6 +285,7 @@ impl Parser {
262285

263286
let articles: Vec<Article> = vec![];
264287
let current_article = Article {
288+
order: 0,
265289
topic: String::from(""),
266290
content: String::from(""),
267291
path: String::from(""),
@@ -336,6 +360,7 @@ impl Parser {
336360

337361
fn new_article(&self) -> Article {
338362
Article {
363+
order: 0,
339364
topic: String::from(""),
340365
content: String::from(""),
341366
path: String::from(""),
@@ -350,6 +375,7 @@ impl Parser {
350375
let topic = name_chunks[2..].join(".");
351376

352377
vec![Article {
378+
order: 0,
353379
topic,
354380
content: String::from(file_content),
355381
path: String::from(file_path),
@@ -429,6 +455,17 @@ impl Parser {
429455
self.current_article.topic = self.trim_article_line(topic);
430456
self.current_article.start_line = line_number;
431457
self.state_machine.to_article_mut();
458+
} else if trimmed_line.starts_with(Keyword::Order.as_str())
459+
&& self.state_machine.is_in(ParserState::ArticleParsing)
460+
{
461+
let parsed_order = trimmed_line
462+
.replace(Keyword::Order.as_str(), "")
463+
.trim()
464+
.parse()
465+
.unwrap_or(0);
466+
467+
self.current_article.order = parsed_order;
468+
self.current_article.start_line = line_number;
432469
} else if trimmed_line.starts_with(Keyword::Ignore.as_str()) {
433470
self.state_machine.to_skippintg_mut();
434471
self.current_article = self.new_article();
@@ -484,6 +521,7 @@ impl Parser {
484521
line_number += 1;
485522
}
486523

524+
self.articles.sort_by_key(|a| a.order);
487525
self.articles.clone()
488526
}
489527

@@ -559,6 +597,7 @@ pub fn test () {}
559597

560598
let articles = parser.parse_file(file_content, "");
561599
let expected_result = vec![Article {
600+
order: 0,
562601
topic: String::from("Test article"),
563602
content: String::from("some text"),
564603
path: "".to_string(),
@@ -569,6 +608,48 @@ pub fn test () {}
569608
assert_eq!(articles, expected_result);
570609
}
571610

611+
#[test]
612+
fn parse_articles_with_custom_order() {
613+
let mut parser = Parser::new(get_test_config());
614+
let file_content = "
615+
/**
616+
* @Article Test article3
617+
* @Order 3
618+
* some text3
619+
*/
620+
pub fn test () {}
621+
622+
/**
623+
* @Article Test article1
624+
* @Order 1
625+
* some text
626+
*/
627+
pub fn test2 () {}
628+
";
629+
630+
let articles = parser.parse_file(file_content, "");
631+
let expected_result = vec![
632+
Article {
633+
order: 1,
634+
topic: String::from("Test article1"),
635+
content: String::from("some text"),
636+
path: "".to_string(),
637+
start_line: 11,
638+
end_line: 12,
639+
},
640+
Article {
641+
order: 3,
642+
topic: String::from("Test article3"),
643+
content: String::from("some text3"),
644+
path: "".to_string(),
645+
start_line: 4,
646+
end_line: 5,
647+
},
648+
];
649+
650+
assert_eq!(articles, expected_result);
651+
}
652+
572653
#[test]
573654
fn ignore_comments_with_ignore_mark() {
574655
let mut parser = Parser::new(get_test_config());
@@ -604,6 +685,7 @@ pub fn test () {}
604685

605686
let articles = parser.parse_file(file_content, "");
606687
let expected_result = vec![Article {
688+
order: 0,
607689
topic: String::from("Test article"),
608690
content: String::from("some multiline\nawesome text"),
609691
path: "".to_string(),
@@ -650,6 +732,7 @@ pub fn test () {}
650732

651733
let articles = parser.parse_file(file_content, "");
652734
let expected_result = vec![Article {
735+
order: 0,
653736
topic: String::from("Test article"),
654737
content: String::from("```rust\nfn main() {\n println!(\"Hello world!\");\n}\n```\n\n```rust\nfn test() {\n println!(\"Hello world!\");\n}\n```"),
655738
path: "".to_string(),
@@ -684,6 +767,7 @@ fn parse_documentation_with_indentation_before_comments() {
684767

685768
let articles = parser.parse_file(file_content, "");
686769
let expected_result = vec![Article {
770+
order: 0,
687771
topic: String::from("Test article"),
688772
content: String::from("#### [no-implicit-coercion](https://eslint.org/docs/rules/no-implicit-coercion)\nAll implicit coercions except `!!` are disallowed:\n```js\n// Fail\n+foo\n1 * foo\n\'\' + foo\n`${foo}`\n~foo.indexOf(bar)\n\n// Pass\n!!foo\n```"),
689773
path: "".to_string(),
@@ -714,6 +798,7 @@ pub fn test () {}
714798

715799
let articles = parser.parse_file(file_content, "");
716800
let expected_result = vec![Article {
801+
order: 0,
717802
topic: String::from("Test article"),
718803
content: String::from("List:\n* Item 1\n* Item 2\n\n Item 2 subtext\n* Item 3"),
719804
path: "".to_string(),
@@ -738,6 +823,7 @@ use std::io::prelude::*;
738823

739824
let articles = parser.parse_file(file_content, "");
740825
let expected_result = vec![Article {
826+
order: 0,
741827
topic: String::from("Test article"),
742828
content: String::from(""),
743829
path: "".to_string(),
@@ -760,6 +846,7 @@ test
760846

761847
let articles = parser.parse_file(file_content, "");
762848
let expected_result = vec![Article {
849+
order: 0,
763850
topic: String::from("Test article"),
764851
content: String::from("test"),
765852
path: "".to_string(),
@@ -784,6 +871,7 @@ const b = 2
784871

785872
let articles = parser.parse_file(file_content, "");
786873
let expected_result = vec![Article {
874+
order: 0,
787875
topic: String::from("Test article"),
788876
content: String::from("test"),
789877
path: "".to_string(),
@@ -816,13 +904,15 @@ fn use_global_article_attribute() {
816904
let articles = parser.parse_file(file_content, "");
817905
let expected_result = vec![
818906
Article {
907+
order: 0,
819908
topic: String::from("Test article"),
820909
content: String::from("test"),
821910
path: "".to_string(),
822911
start_line: 6,
823912
end_line: 7,
824913
},
825914
Article {
915+
order: 0,
826916
topic: String::from("Test article"),
827917
content: String::from("test"),
828918
path: "".to_string(),
@@ -856,6 +946,7 @@ fn ignore_sections_in_case_of_global_article() {
856946

857947
let articles = parser.parse_file(file_content, "");
858948
let expected_result = vec![Article {
949+
order: 0,
859950
topic: String::from("Test article"),
860951
content: String::from("test"),
861952
path: "".to_string(),
@@ -881,6 +972,7 @@ const TIMEOUT = 3000
881972

882973
let articles = parser.parse_file(file_content, "");
883974
let expected_result = vec![Article {
975+
order: 0,
884976
topic: String::from("Test article"),
885977
content: String::from("Request timeout:\n```js/\nconst TIMEOUT = 3000\n```"),
886978
path: "".to_string(),
@@ -908,6 +1000,7 @@ const TIMEOUT = 3000
9081000

9091001
let articles = parser.parse_file(file_content, "");
9101002
let expected_result = vec![Article {
1003+
order: 0,
9111004
topic: String::from("Test article"),
9121005
content: String::from("Request timeout:\n```js/\nconst TIMEOUT = 3000\n```"),
9131006
path: "".to_string(),
@@ -933,6 +1026,7 @@ fn parse_code_block_attribute_from_ending_comment_only() {
9331026

9341027
let articles = parser.parse_file(file_content, "");
9351028
let expected_result = vec![Article {
1029+
order: 0,
9361030
topic: String::from("Test article"),
9371031
content: String::from("Should ignore @CodeBlockEnd in a text block\n```rust/\n...\n```"),
9381032
path: "".to_string(),
@@ -960,6 +1054,7 @@ fn parse_nested_commends() {
9601054

9611055
let articles = parser.parse_file(file_content, "");
9621056
let expected_result = vec![Article {
1057+
order: 0,
9631058
topic: String::from("Test article"),
9641059
content: String::from("Example:\n/**\n* @Article Example article\n* Example\n*/\ntest"),
9651060
path: "".to_string(),
@@ -998,6 +1093,7 @@ fn parse_fdoc_file_check() {
9981093
let parser = Parser::new(get_test_config());
9991094
let result = parser.parse_fdoc_file("test", "/some/long/path/to/file.fdoc.md");
10001095
let expected_result = vec![Article {
1096+
order: 0,
10011097
topic: String::from("file"),
10021098
content: String::from("test"),
10031099
path: "/some/long/path/to/file.fdoc.md".to_string(),

src/plugins.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ pub struct Plugins {
2828
* {{ #your-plugin-name
2929
* any text here
3030
* }}
31-
*
31+
*
3232
* ```
3333
*
3434
* To create a plugin for parsing these blocks, you should add a file called `your-plugin-name.html.lua` into the plugins folder. By default, it's `./plugins`, but it's possible to change it in the config file.
@@ -44,7 +44,7 @@ pub struct Plugins {
4444
*
4545
* ```lua
4646
* function transform(text)
47-
* result = 'transformted text'
47+
* result = 'transformted text'
4848
* end
4949
* ```
5050
*

0 commit comments

Comments
 (0)