Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,6 @@ src/api

# copied into the repo by `mdbook-mermaid` install:
/mermaid*.js

.agents
.kiro
156 changes: 150 additions & 6 deletions crates/mdbook-goals/src/goal_preprocessor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,15 @@ impl<'c> GoalPreprocessorWithContext<'c> {
// Handle filtered lists of goals with needs
self.replace_goals_with_needs_lists_filtered(chapter)?;

// Handle funding summary table
self.replace_funding_table(chapter)?;

// Handle roadmap-filtered funding table
self.replace_funding_table_filtered(chapter)?;

// Handle grouped funding table
self.replace_funding_table_grouped(chapter)?;

Ok(())
}

Expand Down Expand Up @@ -336,12 +345,147 @@ impl<'c> GoalPreprocessorWithContext<'c> {
&mut self,
chapter: &mut Chapter,
) -> anyhow::Result<()> {
self.replace_themed_goal_list(
chapter,
&re::GOALS_WITH_NEEDS_LIST_FILTERED,
"(((GOALS WITH NEEDS: ...)))",
|g| &g.metadata.needs,
)
loop {
let Some(m) = re::GOALS_WITH_NEEDS_LIST_FILTERED.find(&chapter.content) else {
return Ok(());
};
let range = m.range();

let chapter_path = chapter_path(chapter, "(((GOALS WITH NEEDS: ...)))")?;

let capture_value = re::GOALS_WITH_NEEDS_LIST_FILTERED
.captures(&chapter.content[range.clone()])
.and_then(|caps| caps.get(1))
.map(|m| m.as_str().trim())
.unwrap();

let goals = self.goal_documents(chapter_path)?;

let mut filtered_goals: Vec<&GoalDocument> = if capture_value == "Funding" {
goals
.iter()
.filter(|g| {
g.metadata.status.content.is_not_not_accepted() && g.needs_funding()
})
.collect()
} else if capture_value == "Contributor" {
goals
.iter()
.filter(|g| {
g.metadata.status.content.is_not_not_accepted()
&& (g.needs_contributor() || g.metadata.is_help_wanted())
})
.collect()
} else {
goals
.iter()
.filter(|g| {
g.metadata.status.content.is_not_not_accepted()
&& g.metadata.needs.contains(capture_value)
})
.collect()
};

filtered_goals.sort_by_key(|g| &g.metadata.title);

let heading_re = Regex::new(r"(?m)^(#+)\s").unwrap();
let preceding = &chapter.content[..range.start];
let context_level = heading_re
.find_iter(preceding)
.last()
.map(|m| m.as_str().trim().len())
.unwrap_or(1);

let output = if capture_value == "Funding" {
goal::format_funding_goal_sections(&filtered_goals, context_level + 1)
.into_anyhow()?
} else if capture_value == "Contributor" {
goal::format_help_wanted_goal_sections(&filtered_goals, context_level + 1)
.into_anyhow()?
} else {
goal::format_highlight_goal_sections(&filtered_goals, context_level + 1)
.into_anyhow()?
};

chapter.content.replace_range(range, &output);
}
}

fn replace_funding_table(&mut self, chapter: &mut Chapter) -> anyhow::Result<()> {
let Some(m) = re::FUNDING_TABLE.find(&chapter.content) else {
return Ok(());
};
let range = m.range();

let chapter_path = chapter_path(chapter, "(((FUNDING TABLE)))")?;
let goals = self.goal_documents(chapter_path)?;

let mut filtered_goals: Vec<&GoalDocument> = goals
.iter()
.filter(|g| g.metadata.status.content.is_not_not_accepted() && g.needs_funding())
.collect();

filtered_goals.sort_by_key(|g| &g.metadata.title);

let output = goal::format_funding_table(&filtered_goals);
chapter.content.replace_range(range, &output);
Ok(())
}

fn replace_funding_table_filtered(&mut self, chapter: &mut Chapter) -> anyhow::Result<()> {
let Some(m) = re::FUNDING_TABLE_FILTERED.find(&chapter.content) else {
return Ok(());
};
let range = m.range();

let chapter_path = chapter_path(chapter, "(((FUNDING TABLE: ...)))")?;

let filter_value = re::FUNDING_TABLE_FILTERED
.captures(&chapter.content[range.clone()])
.and_then(|caps| caps.get(1))
.map(|m| m.as_str().trim())
.unwrap();
let filter_value = filter_value.to_string();

let goals = self.goal_documents(chapter_path)?;

let mut filtered_goals: Vec<&GoalDocument> = goals
.iter()
.filter(|g| {
g.metadata.status.content.is_not_not_accepted()
&& g.needs_funding()
&& g.matches_roadmap_theme(&filter_value)
})
.collect();

filtered_goals.sort_by_key(|g| &g.metadata.title);

let output = goal::format_funding_table(&filtered_goals);
chapter.content.replace_range(range, &output);
Ok(())
}

fn replace_funding_table_grouped(&mut self, chapter: &mut Chapter) -> anyhow::Result<()> {
let Some(m) = re::FUNDING_TABLE_GROUPED.find(&chapter.content) else {
return Ok(());
};
let range = m.range();

let chapter_path = chapter_path(chapter, "(((FUNDING TABLE GROUPED)))")?;
let goals = self.goal_documents(chapter_path)?;
let roadmaps = self.roadmap_documents(chapter_path)?;

let mut filtered_goals: Vec<&GoalDocument> = goals
.iter()
.filter(|g| g.metadata.status.content.is_not_not_accepted() && g.needs_funding())
.collect();

filtered_goals.sort_by_key(|g| &g.metadata.title);

let roadmap_refs: Vec<&goal::RoadmapDocument> = roadmaps.iter().collect();
let output = goal::format_funding_table_grouped(&filtered_goals, &roadmap_refs);
chapter.content.replace_range(range, &output);
Ok(())
}

/// Shared helper for replacing themed goal list directives (HIGHLIGHT GOALS, GOALS WITH NEEDS).
Expand Down
2 changes: 1 addition & 1 deletion crates/rust-project-goals-cli/src/review.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ fn format_review(

for goal in sorted_goals {
// Help wanted marker
let help_wanted = if goal.metadata.is_help_wanted() {
let help_wanted = if goal.needs_contributor() || goal.metadata.is_help_wanted() {
" ![Help Wanted][]"
} else {
""
Expand Down
Loading
Loading