Skip to content

Commit

Permalink
feat(Automattic#104): propagate markdown config options through project
Browse files Browse the repository at this point in the history
  • Loading branch information
grantlemons committed Dec 6, 2024
1 parent 183f07d commit 0a4121f
Show file tree
Hide file tree
Showing 17 changed files with 166 additions and 94 deletions.
16 changes: 9 additions & 7 deletions harper-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use ariadne::{Color, Label, Report, ReportKind, Source};
use clap::Parser;
use harper_comments::CommentParser;
use harper_core::linting::{LintGroup, LintGroupConfig, Linter};
use harper_core::parsers::Markdown;
use harper_core::parsers::{Markdown, MarkdownOptions};
use harper_core::{remove_overlaps, Dictionary, Document, FstDictionary};

#[derive(Debug, Parser)]
Expand All @@ -32,12 +32,14 @@ enum Args {

fn main() -> anyhow::Result<()> {
let args = Args::parse();
let markdown_options = MarkdownOptions::default();
let linting_options = LintGroupConfig::default();

match args {
Args::Lint { file, count } => {
let (doc, source) = load_file(&file)?;
let (doc, source) = load_file(&file, markdown_options)?;

let mut linter = LintGroup::new(LintGroupConfig::default(), FstDictionary::curated());
let mut linter = LintGroup::new(linting_options, FstDictionary::curated());
let mut lints = linter.lint(&doc);

if count {
Expand Down Expand Up @@ -75,7 +77,7 @@ fn main() -> anyhow::Result<()> {
std::process::exit(1);
}
Args::Parse { file } => {
let (doc, _) = load_file(&file)?;
let (doc, _) = load_file(&file, markdown_options)?;

for token in doc.tokens() {
let json = serde_json::to_string(&token)?;
Expand All @@ -101,15 +103,15 @@ fn main() -> anyhow::Result<()> {
}
}

fn load_file(file: &Path) -> anyhow::Result<(Document, String)> {
fn load_file(file: &Path, markdown_options: MarkdownOptions) -> anyhow::Result<(Document, String)> {
let source = std::fs::read_to_string(file)?;

let mut parser: Box<dyn harper_core::parsers::Parser> =
if let Some("md") = file.extension().map(|v| v.to_str().unwrap()) {
Box::new(Markdown)
Box::new(Markdown::new(markdown_options))
} else {
Box::new(
CommentParser::new_from_filename(file)
CommentParser::new_from_filename(file, Markdown::new(markdown_options))
.map(Box::new)
.ok_or(format_err!("Could not detect language ID."))?,
)
Expand Down
16 changes: 9 additions & 7 deletions harper-comments/src/comment_parser.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::path::Path;

use comment_parsers::{Go, JavaDoc, JsDoc, Unit};
use harper_core::parsers::{self, Parser};
use harper_core::parsers::{self, Markdown, Parser};
use harper_core::{FullDictionary, Token};
use harper_tree_sitter::TreeSitterMasker;
use tree_sitter::Node;
Expand All @@ -17,7 +17,7 @@ impl CommentParser {
self.inner.masker.create_ident_dict(source)
}

pub fn new_from_language_id(language_id: &str) -> Option<Self> {
pub fn new_from_language_id(language_id: &str, markdown_parser: Markdown) -> Option<Self> {
let language = match language_id {
"rust" => tree_sitter_rust::language(),
"typescriptreact" => tree_sitter_typescript::language_tsx(),
Expand All @@ -40,10 +40,12 @@ impl CommentParser {
};

let comment_parser: Box<dyn Parser> = match language_id {
"javascriptreact" | "typescript" | "typescriptreact" | "javascript" => Box::new(JsDoc),
"javascriptreact" | "typescript" | "typescriptreact" | "javascript" => {
Box::new(JsDoc::new(markdown_parser))
}
"java" => Box::new(JavaDoc::default()),
"go" => Box::new(Go),
_ => Box::new(Unit),
"go" => Box::new(Go::new(markdown_parser)),
_ => Box::new(Unit::new(markdown_parser)),
};

Some(Self {
Expand All @@ -55,8 +57,8 @@ impl CommentParser {
}

/// Infer the programming language from a provided filename.
pub fn new_from_filename(filename: &Path) -> Option<Self> {
Self::new_from_language_id(Self::filename_to_filetype(filename)?)
pub fn new_from_filename(filename: &Path, markdown_parser: Markdown) -> Option<Self> {
Self::new_from_language_id(Self::filename_to_filetype(filename)?, markdown_parser)
}

/// Convert a provided path to a corresponding Language Server Protocol file
Expand Down
16 changes: 11 additions & 5 deletions harper-comments/src/comment_parsers/go.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,16 @@ use harper_core::Token;

use super::without_initiators;

#[derive(Debug, Clone, Copy)]
pub struct Go;
#[derive(Clone)]
pub struct Go {
markdown_parser: Markdown,
}

impl Go {
pub fn new(markdown_parser: Markdown) -> Self {
Self { markdown_parser }
}
}

impl Parser for Go {
fn parse(&mut self, source: &[char]) -> Vec<Token> {
Expand All @@ -25,9 +33,7 @@ impl Parser for Go {
actual_source = new_source
}

let mut markdown_parser = Markdown;

let mut new_tokens = markdown_parser.parse(actual_source);
let mut new_tokens = self.markdown_parser.parse(actual_source);

new_tokens
.iter_mut()
Expand Down
28 changes: 20 additions & 8 deletions harper-comments/src/comment_parsers/jsdoc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,16 @@ use itertools::Itertools;

use super::without_initiators;

pub struct JsDoc;
#[derive(Clone)]
pub struct JsDoc {
markdown_parser: Markdown,
}

impl JsDoc {
pub fn new(markdown_parser: Markdown) -> Self {
Self { markdown_parser }
}
}

impl Parser for JsDoc {
fn parse(&mut self, source: &[char]) -> Vec<Token> {
Expand All @@ -13,7 +22,7 @@ impl Parser for JsDoc {
let mut chars_traversed = 0;

for line in source.split(|c| *c == '\n') {
let mut new_tokens = parse_line(line);
let mut new_tokens = parse_line(line, &mut self.markdown_parser);

if chars_traversed + line.len() < source.len() {
new_tokens.push(Token::new(
Expand All @@ -34,7 +43,7 @@ impl Parser for JsDoc {
}
}

fn parse_line(source: &[char]) -> Vec<Token> {
fn parse_line(source: &[char], markdown_parser: &mut Markdown) -> Vec<Token> {
let actual_line = without_initiators(source);

if actual_line.is_empty() {
Expand All @@ -43,7 +52,7 @@ fn parse_line(source: &[char]) -> Vec<Token> {

let source_line = actual_line.get_content(source);

let mut new_tokens = Markdown.parse(source_line);
let mut new_tokens = markdown_parser.parse(source_line);

// Handle inline tags
mark_inline_tags(&mut new_tokens);
Expand Down Expand Up @@ -148,21 +157,23 @@ fn parse_inline_tag(tokens: &[Token]) -> Option<usize> {

#[cfg(test)]
mod tests {
use harper_core::{Document, Punctuation, TokenKind};
use harper_core::{parsers::Markdown, Document, Punctuation, TokenKind};

use crate::CommentParser;

#[test]
fn escapes_loop() {
let source = "/** This should _not_cause an infinite loop: {@ */";
let mut parser = CommentParser::new_from_language_id("javascript").unwrap();
let mut parser =
CommentParser::new_from_language_id("javascript", Markdown::default()).unwrap();
Document::new_curated(source, &mut parser);
}

#[test]
fn handles_inline_link() {
let source = "/** See {@link MyClass} and [MyClass's foo property]{@link MyClass#foo}. */";
let mut parser = CommentParser::new_from_language_id("javascript").unwrap();
let mut parser =
CommentParser::new_from_language_id("javascript", Markdown::default()).unwrap();
let document = Document::new_curated(source, &mut parser);

assert!(matches!(
Expand Down Expand Up @@ -206,7 +217,8 @@ mod tests {
#[test]
fn handles_class() {
let source = "/** @class Circle representing a circle. */";
let mut parser = CommentParser::new_from_language_id("javascript").unwrap();
let mut parser =
CommentParser::new_from_language_id("javascript", Markdown::default()).unwrap();
let document = Document::new_curated(source, &mut parser);

assert!(document
Expand Down
17 changes: 12 additions & 5 deletions harper-comments/src/comment_parsers/unit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,16 @@ use super::without_initiators;
///
/// It assumes it is being provided a single line of comment at a time,
/// including the comment initiation characters.
pub struct Unit;
#[derive(Clone)]
pub struct Unit {
markdown_parser: Markdown,
}

impl Unit {
pub fn new(markdown_parser: Markdown) -> Self {
Self { markdown_parser }
}
}

impl Parser for Unit {
fn parse(&mut self, source: &[char]) -> Vec<Token> {
Expand All @@ -28,7 +37,7 @@ impl Parser for Unit {
continue;
}

let mut new_tokens = parse_line(line);
let mut new_tokens = parse_line(line, &mut self.markdown_parser);

if chars_traversed + line.len() < source.len() {
new_tokens.push(Token::new(
Expand All @@ -49,7 +58,7 @@ impl Parser for Unit {
}
}

fn parse_line(source: &[char]) -> Vec<Token> {
fn parse_line(source: &[char], markdown_parser: &mut Markdown) -> Vec<Token> {
let actual = without_initiators(source);

if actual.is_empty() {
Expand All @@ -58,8 +67,6 @@ fn parse_line(source: &[char]) -> Vec<Token> {

let source = actual.get_content(source);

let mut markdown_parser = Markdown;

let mut new_tokens = markdown_parser.parse(source);

new_tokens
Expand Down
3 changes: 2 additions & 1 deletion harper-comments/tests/language_support.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use std::path::Path;

use harper_comments::CommentParser;
use harper_core::linting::{LintGroup, LintGroupConfig, Linter};
use harper_core::parsers::Markdown;
use harper_core::{Document, FstDictionary};

/// Creates a unit test checking that the linting of a source file in
Expand All @@ -20,7 +21,7 @@ macro_rules! create_test {
)
);

let mut parser = CommentParser::new_from_filename(Path::new(filename)).unwrap();
let mut parser = CommentParser::new_from_filename(Path::new(filename), Markdown::default()).unwrap();
let dict = FstDictionary::curated();
let document = Document::new(&source, &mut parser, &dict);

Expand Down
8 changes: 5 additions & 3 deletions harper-core/benches/parse_demo.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
use criterion::{black_box, criterion_group, criterion_main, Criterion};
use harper_core::linting::{LintGroup, LintGroupConfig, Linter};
use harper_core::parsers::MarkdownOptions;
use harper_core::{Document, FstDictionary};

static DEMO: &str = include_str!("../../demo.md");

fn parse_demo(c: &mut Criterion) {
c.bench_function("parse_demo", |b| {
b.iter(|| Document::new_markdown_curated(black_box(DEMO)))
b.iter(|| Document::new_markdown_curated(black_box(DEMO), MarkdownOptions::default()))
});
}

fn lint_demo(c: &mut Criterion) {
let dictionary = FstDictionary::curated();
let mut lint_set = LintGroup::new(Default::default(), dictionary);
let document = Document::new_markdown_curated(black_box(DEMO));
let document = Document::new_markdown_curated(black_box(DEMO), MarkdownOptions::default());

c.bench_function("lint_demo", |b| {
b.iter(|| lint_set.lint(&document));
Expand All @@ -25,7 +26,8 @@ fn lint_demo_uncached(c: &mut Criterion) {
b.iter(|| {
let dictionary = FstDictionary::curated();
let mut lint_set = LintGroup::new(LintGroupConfig::default(), dictionary.clone());
let document = Document::new_markdown(black_box(DEMO), &dictionary);
let document =
Document::new_markdown(black_box(DEMO), MarkdownOptions::default(), &dictionary);
lint_set.lint(&document)
})
});
Expand Down
22 changes: 15 additions & 7 deletions harper-core/src/document.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::fmt::Display;

use paste::paste;

use crate::parsers::{Markdown, Parser, PlainEnglish};
use crate::parsers::{Markdown, MarkdownOptions, Parser, PlainEnglish};
use crate::patterns::{PatternExt, RepeatingPattern, SequencePattern};
use crate::punctuation::Punctuation;
use crate::token::NumberSuffix;
Expand Down Expand Up @@ -71,14 +71,22 @@ impl Document {

/// Parse text to produce a document using the built-in [`Markdown`] parser
/// and curated dictionary.
pub fn new_markdown_curated(text: &str) -> Self {
Self::new(text, &mut Markdown, &FstDictionary::curated())
pub fn new_markdown_curated(text: &str, markdown_options: MarkdownOptions) -> Self {
Self::new(
text,
&mut Markdown::new(markdown_options),
&FstDictionary::curated(),
)
}

/// Parse text to produce a document using the built-in [`PlainEnglish`]
/// parser and the curated dictionary.
pub fn new_markdown(text: &str, dictionary: &impl Dictionary) -> Self {
Self::new(text, &mut Markdown, dictionary)
pub fn new_markdown(
text: &str,
markdown_options: MarkdownOptions,
dictionary: &impl Dictionary,
) -> Self {
Self::new(text, &mut Markdown::new(markdown_options), dictionary)
}

/// Re-parse important language constructs.
Expand Down Expand Up @@ -553,14 +561,14 @@ mod tests {
use itertools::Itertools;

use super::Document;
use crate::Span;
use crate::{parsers::MarkdownOptions, Span};

fn assert_condensed_contractions(text: &str, final_tok_count: usize) {
let document = Document::new_plain_english_curated(text);

assert_eq!(document.tokens.len(), final_tok_count);

let document = Document::new_markdown_curated(text);
let document = Document::new_markdown_curated(text, MarkdownOptions::default());

assert_eq!(document.tokens.len(), final_tok_count);
}
Expand Down
6 changes: 3 additions & 3 deletions harper-core/src/linting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,10 @@ pub trait Linter: Send + Sync {
#[cfg(test)]
mod tests {
use super::Linter;
use crate::Document;
use crate::{parsers::MarkdownOptions, Document};

pub fn assert_lint_count(text: &str, mut linter: impl Linter, count: usize) {
let test = Document::new_markdown_curated(text);
let test = Document::new_markdown_curated(text, MarkdownOptions::default());
let lints = linter.lint(&test);
dbg!(&lints);
assert_eq!(lints.len(), count);
Expand All @@ -74,7 +74,7 @@ mod tests {
/// Runs a provided linter on text, applies the first suggestion from each
/// lint and asserts that the result is equal to a given value.
pub fn assert_suggestion_result(text: &str, mut linter: impl Linter, expected_result: &str) {
let test = Document::new_markdown_curated(text);
let test = Document::new_markdown_curated(text, MarkdownOptions::default());
let lints = linter.lint(&test);

let mut text: Vec<char> = text.chars().collect();
Expand Down
Loading

0 comments on commit 0a4121f

Please sign in to comment.