Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(harper.js): added ability to configure the markup language #379

Merged
merged 3 commits into from
Jan 15, 2025
Merged
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
23 changes: 15 additions & 8 deletions harper-wasm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::sync::Arc;

use harper_core::language_detection::is_doc_likely_english;
use harper_core::linting::{LintGroup, LintGroupConfig, Linter as _};
use harper_core::parsers::{IsolateEnglish, Markdown, PlainEnglish};
use harper_core::parsers::{IsolateEnglish, Markdown, Parser, PlainEnglish};
use harper_core::{remove_overlaps, Document, FstDictionary, FullDictionary, Lrc};
use serde::{Deserialize, Serialize};
use wasm_bindgen::prelude::wasm_bindgen;
Expand Down Expand Up @@ -42,6 +42,12 @@ make_serialize_fns_for!(Suggestion);
make_serialize_fns_for!(Lint);
make_serialize_fns_for!(Span);

#[wasm_bindgen]
pub enum Language {
Plain,
Markdown,
}

#[wasm_bindgen]
pub struct Linter {
lint_group: LintGroup<Arc<FstDictionary>>,
Expand Down Expand Up @@ -112,16 +118,17 @@ impl Linter {
}

/// Perform the configured linting on the provided text.
pub fn lint(&mut self, text: String) -> Vec<Lint> {
pub fn lint(&mut self, text: String, language: Language) -> Vec<Lint> {
let source: Vec<_> = text.chars().collect();
let source = Lrc::new(source);

// TODO: Have a way to configure the markdown parser
let document = Document::new_from_vec(
source.clone(),
&Markdown::default(),
&FullDictionary::curated(),
);
let parser: Box<dyn Parser> = match language {
Language::Plain => Box::new(PlainEnglish),
// TODO: Have a way to configure the Markdown parser
Language::Markdown => Box::new(Markdown::default()),
};

let document = Document::new_from_vec(source.clone(), &parser, &FullDictionary::curated());

let mut lints = self.lint_group.lint(&document);

Expand Down
4 changes: 2 additions & 2 deletions packages/harper.js/src/Linter.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { Lint, Span, Suggestion } from 'wasm';
import { LintConfig } from './main';
import { LintConfig, LintOptions } from './main';

/** An interface for an object that can perform linting actions. */
export default interface Linter {
Expand All @@ -9,7 +9,7 @@ export default interface Linter {
setup(): Promise<void>;

/** Lint the provided text. */
lint(text: string): Promise<Lint[]>;
lint(text: string, options?: LintOptions): Promise<Lint[]>;

/** Apply a suggestion to the given text, returning the transformed result. */
applySuggestion(text: string, suggestion: Suggestion, span: Span): Promise<string>;
Expand Down
12 changes: 8 additions & 4 deletions packages/harper.js/src/LocalLinter.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import type { Lint, Span, Suggestion, Linter as WasmLinter } from 'wasm';
import { Language } from 'wasm';
import Linter from './Linter';
import loadWasm from './loadWasm';
import { LintConfig } from './main';
import { LintConfig, LintOptions } from './main';

/** A Linter that runs in the current JavaScript context (meaning it is allowed to block the event loop). */
export default class LocalLinter implements Linter {
Expand All @@ -18,12 +19,15 @@ export default class LocalLinter implements Linter {

async setup(): Promise<void> {
await this.initialize();
this.inner!.lint('');
this.inner!.lint('', Language.Plain);
}

async lint(text: string): Promise<Lint[]> {
async lint(text: string, options?: LintOptions): Promise<Lint[]> {
await this.initialize();
const lints = this.inner!.lint(text);
const lints = this.inner!.lint(
text,
options?.language === 'plaintext' ? Language.Plain : Language.Markdown
);

return lints;
}
Expand Down
6 changes: 3 additions & 3 deletions packages/harper.js/src/WorkerLinter/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type { Lint, Suggestion, Span } from 'wasm';
import Linter from '../Linter';
import Worker from './worker.js?worker&inline';
import { getWasmUri } from '../loadWasm';
import { LintConfig } from '../main';
import { LintConfig, LintOptions } from '../main';

/** The data necessary to complete a request once the worker has responded. */
type RequestItem = {
Expand Down Expand Up @@ -61,8 +61,8 @@ export default class WorkerLinter implements Linter {
return this.rpc('setup', []);
}

lint(text: string): Promise<Lint[]> {
return this.rpc('lint', [text]);
lint(text: string, options?: LintOptions): Promise<Lint[]> {
return this.rpc('lint', [text, options]);
}

applySuggestion(text: string, suggestion: Suggestion, span: Span): Promise<string> {
Expand Down
6 changes: 6 additions & 0 deletions packages/harper.js/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,9 @@ export type { Linter, Lint, Span, Suggestion };
/** A linting rule configuration dependent on upstream Harper's available rules.
* This is a record, since you shouldn't hard-code the existence of any particular rules and should generalize based on this struct. */
export type LintConfig = Record<string, boolean | undefined>;

/** The option used to configure the parser for an individual linting operation. */
export type LintOptions = {
/** The markup language that is being passed. Defaults to `markdown`. */
language?: 'plaintext' | 'markdown';
};
Loading