harper.js 0.25.0 → 0.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/harper.d.ts +141 -5
- package/dist/harper.js +1325 -1776
- package/dist/harper_wasm_bg.wasm +0 -0
- package/dist/tsdoc-metadata.json +1 -1
- package/package.json +13 -5
- package/api-extractor.json +0 -20
- package/docs.sh +0 -24
- package/examples/commonjs-simple/README.md +0 -11
- package/examples/commonjs-simple/index.js +0 -27
- package/examples/commonjs-simple/package.json +0 -11
- package/examples/commonjs-simple/yarn.lock +0 -8
- package/examples/raw-web/README.md +0 -4
- package/examples/raw-web/index.html +0 -55
- package/src/Linter.bench.ts +0 -31
- package/src/Linter.test.ts +0 -208
- package/src/Linter.ts +0 -73
- package/src/LocalLinter.ts +0 -139
- package/src/WorkerLinter/communication.test.ts +0 -63
- package/src/WorkerLinter/communication.ts +0 -111
- package/src/WorkerLinter/index.ts +0 -170
- package/src/WorkerLinter/worker.js +0 -24
- package/src/loadWasm.ts +0 -26
- package/src/main.ts +0 -18
- package/tsconfig.json +0 -25
- package/vite.config.js +0 -63
|
Binary file
|
package/dist/tsdoc-metadata.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "harper.js",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.26.0",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"author": "Elijah Potter",
|
|
6
6
|
"description": "The grammar checker for developers.",
|
|
@@ -17,20 +17,28 @@
|
|
|
17
17
|
"scripts": {
|
|
18
18
|
"dev": "vite",
|
|
19
19
|
"build": "tsc && vite build",
|
|
20
|
-
"test": "vitest run
|
|
20
|
+
"test": "vitest run",
|
|
21
|
+
"test:debug": "vitest run --browser.headless false --testTimeout 0",
|
|
22
|
+
"api:extractor": "api-extractor run",
|
|
23
|
+
"api:documenter": "api-documenter markdown -i temp"
|
|
21
24
|
},
|
|
22
25
|
"devDependencies": {
|
|
23
26
|
"@microsoft/api-documenter": "^7.26.10",
|
|
24
27
|
"@microsoft/api-extractor": "^7.50.1",
|
|
25
28
|
"@vitest/browser": "^3.0.6",
|
|
26
29
|
"playwright": "^1.49.1",
|
|
27
|
-
"typescript": "
|
|
30
|
+
"typescript": "catalog:",
|
|
28
31
|
"vite": "^6.1.0",
|
|
29
32
|
"vite-plugin-dts": "^4.5.0",
|
|
30
33
|
"vite-plugin-virtual": "^0.3.0",
|
|
31
34
|
"vitest": "^3.0.5",
|
|
32
|
-
"wasm": "
|
|
35
|
+
"harper-wasm": "workspace:*",
|
|
36
|
+
"type-fest": "^4.37.0",
|
|
37
|
+
"p-memoize": "^7.1.1",
|
|
38
|
+
"p-lazy": "^5.0.0"
|
|
33
39
|
},
|
|
34
40
|
"main": "dist/harper.js",
|
|
35
|
-
"types": "dist/harper.d.ts"
|
|
41
|
+
"types": "dist/harper.d.ts",
|
|
42
|
+
"sideEffects": false,
|
|
43
|
+
"files": ["dist"]
|
|
36
44
|
}
|
package/api-extractor.json
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"mainEntryPointFilePath": "./dist/harper.d.ts",
|
|
3
|
-
"apiReport": {
|
|
4
|
-
"enabled": false
|
|
5
|
-
},
|
|
6
|
-
"docModel": {
|
|
7
|
-
"enabled": true
|
|
8
|
-
},
|
|
9
|
-
"dtsRollup": {
|
|
10
|
-
"enabled": false
|
|
11
|
-
},
|
|
12
|
-
"bundledPackages": ["wasm"],
|
|
13
|
-
"messages": {
|
|
14
|
-
"extractorMessageReporting": {
|
|
15
|
-
"ae-missing-release-tag": {
|
|
16
|
-
"logLevel": "none"
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
}
|
package/docs.sh
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
#! /bin/bash
|
|
2
|
-
|
|
3
|
-
set -eo pipefail
|
|
4
|
-
|
|
5
|
-
yarn run api-extractor run
|
|
6
|
-
yarn run api-documenter markdown -i temp
|
|
7
|
-
|
|
8
|
-
rm -r html || true
|
|
9
|
-
mkdir html || true
|
|
10
|
-
|
|
11
|
-
echo Rendering HTML...
|
|
12
|
-
|
|
13
|
-
for file in ./markdown/*.md
|
|
14
|
-
do
|
|
15
|
-
BASE=$(basename $file .md)
|
|
16
|
-
pandoc $file -o html/$BASE.html
|
|
17
|
-
perl -pi -e 's/"\K([^"]+)\.md(?=")/\1.html/g' html/$BASE.html
|
|
18
|
-
|
|
19
|
-
echo '<link rel="stylesheet" href="https://unpkg.com/mvp.css">' >> html/$BASE.html
|
|
20
|
-
done
|
|
21
|
-
|
|
22
|
-
rm -r ../web/static/docs/harperjs || true
|
|
23
|
-
mkdir -p ../web/static/docs/harperjs || true
|
|
24
|
-
mv -f html ../web/static/docs/harperjs/ref
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
async function main() {
|
|
2
|
-
const harper = await import('harper.js');
|
|
3
|
-
// We cannot use `WorkerLinter` on Node.js since it relies on web-specific APIs.
|
|
4
|
-
let linter = new harper.LocalLinter();
|
|
5
|
-
|
|
6
|
-
let lints = await linter.lint('This is a example of how to use `harper.js`.');
|
|
7
|
-
|
|
8
|
-
console.log('Here are the results of linting the above text:');
|
|
9
|
-
|
|
10
|
-
for (let lint of lints) {
|
|
11
|
-
console.log(' - ', lint.span().start, ':', lint.span().end, lint.message());
|
|
12
|
-
|
|
13
|
-
if (lint.suggestion_count() != 0) {
|
|
14
|
-
console.log('Suggestions:');
|
|
15
|
-
|
|
16
|
-
for (let sug of lint.suggestions()) {
|
|
17
|
-
console.log(
|
|
18
|
-
'\t - ',
|
|
19
|
-
sug.kind() == 1 ? 'Remove' : 'Replace with',
|
|
20
|
-
sug.get_replacement_text()
|
|
21
|
-
);
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
main();
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
|
2
|
-
# yarn lockfile v1
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
harper.js@^0.14.0:
|
|
6
|
-
version "0.14.0"
|
|
7
|
-
resolved "https://registry.yarnpkg.com/harper.js/-/harper.js-0.14.0.tgz#16d511070d4474dca501d4de1c76f7849ec0accb"
|
|
8
|
-
integrity sha512-WRzop2PmFK2AZiqNMHHWDFIqFmS7DeoNVhyibyu7T6wuSe24E1Tunolz8ZzMPfcaKuBB2SY+yGbyTOyj+/QD8g==
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
<!doctype html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="utf-8" />
|
|
5
|
-
<script type="module">
|
|
6
|
-
// We can import `harper.js` using native ECMAScript syntax.
|
|
7
|
-
import { WorkerLinter } from 'https://unpkg.com/harper.js@0.13.0/dist/harper.js';
|
|
8
|
-
|
|
9
|
-
// Since we are working in the browser, we can use either `WorkerLinter`, which doesn't block the event loop, or `LocalLinter`, which does.
|
|
10
|
-
let linter = new WorkerLinter();
|
|
11
|
-
|
|
12
|
-
// Every time the `<textarea/>` received an input, we process it and update our list.
|
|
13
|
-
async function onInput(e) {
|
|
14
|
-
let lints = await linter.lint(e.target.value);
|
|
15
|
-
|
|
16
|
-
let list = document.getElementById('errorlist');
|
|
17
|
-
// Clear previous results
|
|
18
|
-
list.innerHTML = '';
|
|
19
|
-
|
|
20
|
-
for (let lint of lints) {
|
|
21
|
-
let item = document.createElement('LI');
|
|
22
|
-
var text = document.createTextNode(lint.message());
|
|
23
|
-
item.appendChild(text);
|
|
24
|
-
list.appendChild(item);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
let inputField = document.getElementById('maininput');
|
|
29
|
-
inputField.addEventListener('input', onInput);
|
|
30
|
-
onInput({ target: inputField });
|
|
31
|
-
</script>
|
|
32
|
-
|
|
33
|
-
<!--Make the page look good using SimpleCSS-->
|
|
34
|
-
<link rel="stylesheet" href="https://cdn.simplecss.org/simple.min.css" />
|
|
35
|
-
</head>
|
|
36
|
-
|
|
37
|
-
<body>
|
|
38
|
-
<h1>Demo</h1>
|
|
39
|
-
|
|
40
|
-
<p>
|
|
41
|
-
This page is a simple example of using <code>harper.js</code> on a plain HTML page with a CDN.
|
|
42
|
-
It isn't pretty, but it demonstrates the fundamentals of using Harper. Start typing in the
|
|
43
|
-
text box below to start getting suggestions right in your browser.
|
|
44
|
-
</p>
|
|
45
|
-
|
|
46
|
-
<!--This is an intentional mistake to highlight the technology.-->
|
|
47
|
-
<textarea id="maininput">This is an test</textarea>
|
|
48
|
-
|
|
49
|
-
<h2>Errors</h2>
|
|
50
|
-
|
|
51
|
-
<ul id="errorlist">
|
|
52
|
-
Loading...
|
|
53
|
-
</ul>
|
|
54
|
-
</body>
|
|
55
|
-
</html>
|
package/src/Linter.bench.ts
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { bench } from 'vitest';
|
|
2
|
-
import LocalLinter from './LocalLinter';
|
|
3
|
-
import WorkerLinter from './WorkerLinter';
|
|
4
|
-
|
|
5
|
-
const linters = {
|
|
6
|
-
WorkerLinter: WorkerLinter,
|
|
7
|
-
LocalLinter: LocalLinter
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
for (const [linterName, Linter] of Object.entries(linters)) {
|
|
11
|
-
const linter = new Linter();
|
|
12
|
-
|
|
13
|
-
// Prime caches
|
|
14
|
-
linter.setup();
|
|
15
|
-
|
|
16
|
-
const defaultConfig = await linter.getDefaultLintConfig();
|
|
17
|
-
const emptyIgnoreState = await linter.exportIgnoredLints();
|
|
18
|
-
|
|
19
|
-
bench(`${linterName} set lint configuration`, async () => {
|
|
20
|
-
await linter.setLintConfig(defaultConfig);
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
bench(`${linterName} get lint configuration`, async () => {
|
|
24
|
-
await linter.getLintConfig();
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
bench(`${linterName} reset ignore state`, async () => {
|
|
28
|
-
await linter.clearIgnoredLints();
|
|
29
|
-
await linter.importIgnoredLints(emptyIgnoreState);
|
|
30
|
-
});
|
|
31
|
-
}
|
package/src/Linter.test.ts
DELETED
|
@@ -1,208 +0,0 @@
|
|
|
1
|
-
import { expect, test } from 'vitest';
|
|
2
|
-
import WorkerLinter from './WorkerLinter';
|
|
3
|
-
import LocalLinter from './LocalLinter';
|
|
4
|
-
|
|
5
|
-
const linters = {
|
|
6
|
-
WorkerLinter: WorkerLinter,
|
|
7
|
-
LocalLinter: LocalLinter
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
for (const [linterName, Linter] of Object.entries(linters)) {
|
|
11
|
-
test(`${linterName} detects repeated words`, async () => {
|
|
12
|
-
const linter = new Linter();
|
|
13
|
-
|
|
14
|
-
const lints = await linter.lint('The the problem is...');
|
|
15
|
-
|
|
16
|
-
expect(lints.length).toBe(1);
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
test(`${linterName} detects repeated words with multiple synchronous requests`, async () => {
|
|
20
|
-
const linter = new Linter();
|
|
21
|
-
|
|
22
|
-
const promises = [
|
|
23
|
-
linter.lint('The problem is that that...'),
|
|
24
|
-
linter.lint('The problem is...'),
|
|
25
|
-
linter.lint('The the problem is...')
|
|
26
|
-
];
|
|
27
|
-
|
|
28
|
-
const results = [];
|
|
29
|
-
|
|
30
|
-
for (const promise of promises) {
|
|
31
|
-
results.push(await promise);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
expect(results[0].length).toBe(1);
|
|
35
|
-
expect(results[0][0].suggestions().length).toBe(1);
|
|
36
|
-
expect(results[1].length).toBe(0);
|
|
37
|
-
expect(results[2].length).toBe(1);
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
test(`${linterName} detects repeated words with concurrent requests`, async () => {
|
|
41
|
-
const linter = new Linter();
|
|
42
|
-
|
|
43
|
-
const promises = [
|
|
44
|
-
linter.lint('The problem is that that...'),
|
|
45
|
-
linter.lint('The problem is...'),
|
|
46
|
-
linter.lint('The the problem is...')
|
|
47
|
-
];
|
|
48
|
-
|
|
49
|
-
const results = await Promise.all(promises);
|
|
50
|
-
|
|
51
|
-
expect(results[0].length).toBe(1);
|
|
52
|
-
expect(results[0][0].suggestions().length).toBe(1);
|
|
53
|
-
expect(results[1].length).toBe(0);
|
|
54
|
-
expect(results[2].length).toBe(1);
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
test(`${linterName} detects lorem ipsum paragraph as not english`, async () => {
|
|
58
|
-
const linter = new Linter();
|
|
59
|
-
|
|
60
|
-
const result = await linter.isLikelyEnglish(
|
|
61
|
-
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.'
|
|
62
|
-
);
|
|
63
|
-
|
|
64
|
-
expect(result).toBeTypeOf('boolean');
|
|
65
|
-
expect(result).toBe(false);
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
test(`${linterName} can run setup without issues`, async () => {
|
|
69
|
-
const linter = new Linter();
|
|
70
|
-
|
|
71
|
-
await linter.setup();
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
test(`${linterName} contains configuration option for repetition`, async () => {
|
|
75
|
-
const linter = new Linter();
|
|
76
|
-
|
|
77
|
-
const lintConfig = await linter.getLintConfig();
|
|
78
|
-
expect(lintConfig).toHaveProperty('RepeatedWords');
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
test(`${linterName} can both get and set its configuration`, async () => {
|
|
82
|
-
const linter = new Linter();
|
|
83
|
-
|
|
84
|
-
let lintConfig = await linter.getLintConfig();
|
|
85
|
-
|
|
86
|
-
for (const key of Object.keys(lintConfig)) {
|
|
87
|
-
lintConfig[key] = true;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
await linter.setLintConfig(lintConfig);
|
|
91
|
-
lintConfig = await linter.getLintConfig();
|
|
92
|
-
|
|
93
|
-
for (const key of Object.keys(lintConfig)) {
|
|
94
|
-
expect(lintConfig[key]).toBe(true);
|
|
95
|
-
}
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
test(`${linterName} can make things title case`, async () => {
|
|
99
|
-
const linter = new Linter();
|
|
100
|
-
|
|
101
|
-
const titleCase = await linter.toTitleCase('THIS IS A TEST FOR MAKING TITLES');
|
|
102
|
-
|
|
103
|
-
expect(titleCase).toBe('This Is a Test for Making Titles');
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
test(`${linterName} can get rule descriptions`, async () => {
|
|
107
|
-
const linter = new Linter();
|
|
108
|
-
|
|
109
|
-
const descriptions = await linter.getLintDescriptions();
|
|
110
|
-
|
|
111
|
-
expect(descriptions).toBeTypeOf('object');
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
test(`${linterName} rule descriptions are not empty`, async () => {
|
|
115
|
-
const linter = new Linter();
|
|
116
|
-
|
|
117
|
-
const descriptions = await linter.getLintDescriptions();
|
|
118
|
-
|
|
119
|
-
for (const value of Object.values(descriptions)) {
|
|
120
|
-
expect(value).toBeTypeOf('string');
|
|
121
|
-
expect(value).not.toHaveLength(0);
|
|
122
|
-
}
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
test(`${linterName} default lint config has no null values`, async () => {
|
|
126
|
-
const linter = new Linter();
|
|
127
|
-
|
|
128
|
-
const lintConfig = await linter.getDefaultLintConfig();
|
|
129
|
-
|
|
130
|
-
for (const value of Object.values(lintConfig)) {
|
|
131
|
-
expect(value).not.toBeNull();
|
|
132
|
-
}
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
test(`${linterName} can ignore lints`, async () => {
|
|
136
|
-
const linter = new Linter();
|
|
137
|
-
const source = 'This is an test.';
|
|
138
|
-
|
|
139
|
-
const firstRound = await linter.lint(source);
|
|
140
|
-
|
|
141
|
-
expect(firstRound.length).toBeGreaterThanOrEqual(1);
|
|
142
|
-
|
|
143
|
-
await linter.ignoreLint(firstRound[0]);
|
|
144
|
-
|
|
145
|
-
const secondRound = await linter.lint(source);
|
|
146
|
-
|
|
147
|
-
expect(secondRound.length).toBeLessThan(firstRound.length);
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
test(`${linterName} can reimport ignored lints.`, async () => {
|
|
151
|
-
const source = 'This is an test of xporting lints.';
|
|
152
|
-
|
|
153
|
-
const firstLinter = new Linter();
|
|
154
|
-
|
|
155
|
-
const firstLints = await firstLinter.lint(source);
|
|
156
|
-
|
|
157
|
-
for (const lint of firstLints) {
|
|
158
|
-
await firstLinter.ignoreLint(lint);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
const exported = await firstLinter.exportIgnoredLints();
|
|
162
|
-
|
|
163
|
-
/// Create a new instance and reimport the lints.
|
|
164
|
-
const secondLinter = new Linter();
|
|
165
|
-
await secondLinter.importIgnoredLints(exported);
|
|
166
|
-
|
|
167
|
-
const secondLints = await secondLinter.lint(source);
|
|
168
|
-
|
|
169
|
-
expect(firstLints.length).toBeGreaterThan(secondLints.length);
|
|
170
|
-
expect(secondLints.length).toBe(0);
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
test(`${linterName} can add words to the dictionary`, async () => {
|
|
174
|
-
const source = 'asdf is not a word';
|
|
175
|
-
|
|
176
|
-
const linter = new Linter();
|
|
177
|
-
let lints = await linter.lint(source);
|
|
178
|
-
|
|
179
|
-
expect(lints).toHaveLength(1);
|
|
180
|
-
|
|
181
|
-
await linter.importWords(['asdf']);
|
|
182
|
-
lints = await linter.lint(source);
|
|
183
|
-
|
|
184
|
-
expect(lints).toHaveLength(0);
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
test(`${linterName} allows correct capitalization of "United States"`, async () => {
|
|
188
|
-
const linter = new Linter();
|
|
189
|
-
const lints = await linter.lint('The United States is a big country.');
|
|
190
|
-
|
|
191
|
-
expect(lints).toHaveLength(0);
|
|
192
|
-
});
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
test('Linters have the same config format', async () => {
|
|
196
|
-
const configs = [];
|
|
197
|
-
|
|
198
|
-
for (const Linter of Object.values(linters)) {
|
|
199
|
-
const linter = new Linter();
|
|
200
|
-
|
|
201
|
-
configs.push(await linter.getLintConfig());
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
for (const config of configs) {
|
|
205
|
-
expect(config).toEqual(configs[0]);
|
|
206
|
-
expect(config).toBeTypeOf('object');
|
|
207
|
-
}
|
|
208
|
-
});
|
package/src/Linter.ts
DELETED
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import type { Lint, Span, Suggestion } from 'wasm';
|
|
2
|
-
import { LintConfig, LintOptions } from './main';
|
|
3
|
-
|
|
4
|
-
/** An interface for an object that can perform linting actions. */
|
|
5
|
-
export default interface Linter {
|
|
6
|
-
/** Complete any setup that is necessary before linting. This may include downloading and compiling the WebAssembly binary.
|
|
7
|
-
* This setup will complete when needed regardless of whether you call this function.
|
|
8
|
-
* This function exists to allow you to do this work when it is of least impact to the user experiences (i.e. while you're loading something else). */
|
|
9
|
-
setup(): Promise<void>;
|
|
10
|
-
|
|
11
|
-
/** Lint the provided text. */
|
|
12
|
-
lint(text: string, options?: LintOptions): Promise<Lint[]>;
|
|
13
|
-
|
|
14
|
-
/** Apply a suggestion to the given text, returning the transformed result. */
|
|
15
|
-
applySuggestion(text: string, suggestion: Suggestion, span: Span): Promise<string>;
|
|
16
|
-
|
|
17
|
-
/** Determine if the provided text is likely to be intended to be English.
|
|
18
|
-
* The algorithm can be described as "proof of concept" and as such does not work terribly well.*/
|
|
19
|
-
isLikelyEnglish(text: string): Promise<boolean>;
|
|
20
|
-
|
|
21
|
-
/** Determine which parts of a given string are intended to be English, returning those bits.
|
|
22
|
-
* The algorithm can be described as "proof of concept" and as such does not work terribly well.*/
|
|
23
|
-
isolateEnglish(text: string): Promise<string>;
|
|
24
|
-
|
|
25
|
-
/** Get the linter's current configuration. */
|
|
26
|
-
getLintConfig(): Promise<LintConfig>;
|
|
27
|
-
|
|
28
|
-
/** Get the default (unset) linter configuration as JSON.
|
|
29
|
-
* This method does not effect the caller's lint configuration, nor does it return the current one. */
|
|
30
|
-
getDefaultLintConfigAsJSON(): Promise<string>;
|
|
31
|
-
|
|
32
|
-
/** Get the default (unset) linter configuration.
|
|
33
|
-
* This method does not effect the caller's lint configuration, nor does it return the current one. */
|
|
34
|
-
getDefaultLintConfig(): Promise<LintConfig>;
|
|
35
|
-
|
|
36
|
-
/** Set the linter's current configuration. */
|
|
37
|
-
setLintConfig(config: LintConfig): Promise<void>;
|
|
38
|
-
|
|
39
|
-
/** Get the linter's current configuration as JSON. */
|
|
40
|
-
getLintConfigAsJSON(): Promise<string>;
|
|
41
|
-
|
|
42
|
-
/** Set the linter's current configuration from JSON. */
|
|
43
|
-
setLintConfigWithJSON(config: string): Promise<void>;
|
|
44
|
-
|
|
45
|
-
/** Get the linting rule descriptions as a JSON map. */
|
|
46
|
-
getLintDescriptionsAsJSON(): Promise<string>;
|
|
47
|
-
|
|
48
|
-
/** Get the linting rule descriptions as an object */
|
|
49
|
-
getLintDescriptions(): Promise<Record<string, string>>;
|
|
50
|
-
|
|
51
|
-
/** Convert a string to Chicago-style title case. */
|
|
52
|
-
toTitleCase(text: string): Promise<string>;
|
|
53
|
-
|
|
54
|
-
/** Ignore future instances of a lint from a previous linting run in future invocations. */
|
|
55
|
-
ignoreLint(lint: Lint): Promise<void>;
|
|
56
|
-
|
|
57
|
-
/** Export the ignored lints to a JSON list of privacy-respecting hashes. */
|
|
58
|
-
exportIgnoredLints(): Promise<string>;
|
|
59
|
-
|
|
60
|
-
/** Import ignored lints from a JSON list to the linter.
|
|
61
|
-
* This function appends to the existing lints, if any. */
|
|
62
|
-
importIgnoredLints(json: string): Promise<void>;
|
|
63
|
-
|
|
64
|
-
/** Clear records of all previously ignored lints. */
|
|
65
|
-
clearIgnoredLints(): Promise<void>;
|
|
66
|
-
|
|
67
|
-
/** Import words into the dictionary. This is a significant operation, so try to batch words. */
|
|
68
|
-
importWords(words: string[]): Promise<void>;
|
|
69
|
-
|
|
70
|
-
/** Export all added words from the dictionary. Note that this will NOT export anything from the curated dictionary,
|
|
71
|
-
* only words from previous calls to `this.importWords`. */
|
|
72
|
-
exportWords(): Promise<string[]>;
|
|
73
|
-
}
|
package/src/LocalLinter.ts
DELETED
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
import type { Lint, Span, Suggestion, Linter as WasmLinter } from 'wasm';
|
|
2
|
-
import { Language } from 'wasm';
|
|
3
|
-
import Linter from './Linter';
|
|
4
|
-
import loadWasm from './loadWasm';
|
|
5
|
-
import { LintConfig, LintOptions } from './main';
|
|
6
|
-
|
|
7
|
-
/** A Linter that runs in the current JavaScript context (meaning it is allowed to block the event loop). */
|
|
8
|
-
export default class LocalLinter implements Linter {
|
|
9
|
-
private inner: WasmLinter | undefined;
|
|
10
|
-
|
|
11
|
-
/** Initialize the WebAssembly and construct the inner Linter. */
|
|
12
|
-
private async initialize(): Promise<void> {
|
|
13
|
-
if (!this.inner) {
|
|
14
|
-
const wasm = await loadWasm();
|
|
15
|
-
wasm.setup();
|
|
16
|
-
this.inner = wasm.Linter.new();
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
async setup(): Promise<void> {
|
|
21
|
-
await this.initialize();
|
|
22
|
-
this.inner!.lint('', Language.Plain);
|
|
23
|
-
|
|
24
|
-
const exported = await this.exportIgnoredLints();
|
|
25
|
-
await this.importIgnoredLints(exported);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
async lint(text: string, options?: LintOptions): Promise<Lint[]> {
|
|
29
|
-
await this.initialize();
|
|
30
|
-
const lints = this.inner!.lint(
|
|
31
|
-
text,
|
|
32
|
-
options?.language === 'plaintext' ? Language.Plain : Language.Markdown
|
|
33
|
-
);
|
|
34
|
-
|
|
35
|
-
return lints;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
async applySuggestion(text: string, suggestion: Suggestion, span: Span): Promise<string> {
|
|
39
|
-
const wasm = await loadWasm();
|
|
40
|
-
return wasm.apply_suggestion(text, span, suggestion);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
async isLikelyEnglish(text: string): Promise<boolean> {
|
|
44
|
-
await this.initialize();
|
|
45
|
-
return this.inner!.is_likely_english(text);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
async isolateEnglish(text: string): Promise<string> {
|
|
49
|
-
await this.initialize();
|
|
50
|
-
return this.inner!.isolate_english(text);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
async getLintConfig(): Promise<LintConfig> {
|
|
54
|
-
await this.initialize();
|
|
55
|
-
|
|
56
|
-
return this.inner!.get_lint_config_as_object();
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
async getDefaultLintConfigAsJSON(): Promise<string> {
|
|
60
|
-
const wasm = await loadWasm();
|
|
61
|
-
|
|
62
|
-
return wasm.get_default_lint_config_as_json();
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
async getDefaultLintConfig(): Promise<LintConfig> {
|
|
66
|
-
const wasm = await loadWasm();
|
|
67
|
-
|
|
68
|
-
return wasm.get_default_lint_config();
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
async setLintConfig(config: LintConfig): Promise<void> {
|
|
72
|
-
await this.initialize();
|
|
73
|
-
|
|
74
|
-
this.inner!.set_lint_config_from_object(config);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
async getLintConfigAsJSON(): Promise<string> {
|
|
78
|
-
await this.initialize();
|
|
79
|
-
|
|
80
|
-
return this.inner!.get_lint_config_as_json();
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
async setLintConfigWithJSON(config: string): Promise<void> {
|
|
84
|
-
await this.initialize();
|
|
85
|
-
|
|
86
|
-
this.inner!.set_lint_config_from_json(config);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
async toTitleCase(text: string): Promise<string> {
|
|
90
|
-
const wasm = await loadWasm();
|
|
91
|
-
return wasm.to_title_case(text);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
async getLintDescriptions(): Promise<Record<string, string>> {
|
|
95
|
-
await this.initialize();
|
|
96
|
-
return this.inner!.get_lint_descriptions_as_object();
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
async getLintDescriptionsAsJSON(): Promise<string> {
|
|
100
|
-
await this.initialize();
|
|
101
|
-
return this.inner!.get_lint_descriptions_as_json();
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
async ignoreLint(lint: Lint): Promise<void> {
|
|
105
|
-
await this.initialize();
|
|
106
|
-
|
|
107
|
-
this.inner!.ignore_lint(lint);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
async exportIgnoredLints(): Promise<string> {
|
|
111
|
-
await this.initialize();
|
|
112
|
-
|
|
113
|
-
return this.inner!.export_ignored_lints();
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
async importIgnoredLints(json: string): Promise<void> {
|
|
117
|
-
await this.initialize();
|
|
118
|
-
|
|
119
|
-
return this.inner!.import_ignored_lints(json);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
async clearIgnoredLints(): Promise<void> {
|
|
123
|
-
await this.initialize();
|
|
124
|
-
|
|
125
|
-
return this.inner!.clear_ignored_lints();
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
async importWords(words: string[]): Promise<void> {
|
|
129
|
-
await this.initialize();
|
|
130
|
-
|
|
131
|
-
return this.inner!.import_words(words);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
async exportWords(): Promise<string[]> {
|
|
135
|
-
await this.initialize();
|
|
136
|
-
|
|
137
|
-
return this.inner!.export_words();
|
|
138
|
-
}
|
|
139
|
-
}
|