Skip to content

Commit f5b6ab7

Browse files
Merge pull request #7 from trueberryless-org/tests
Write tests
2 parents e39cb3f + 034a0bd commit f5b6ab7

File tree

268 files changed

+5946
-388
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

268 files changed

+5946
-388
lines changed

packages/starlight-spell-checker/index.ts

+11-9
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,12 @@ import {
55
type StarlightSpellCheckerConfig,
66
type StarlightSpellCheckerUserConfig,
77
} from "./libs/config";
8-
import { logErrors, logWarnings, validateTexts } from "./libs/validation";
8+
import {
9+
logErrors,
10+
logUnsupportedLanguages,
11+
logWarnings,
12+
validateTexts,
13+
} from "./libs/validation";
914
import { clearContentLayerCache } from "./libs/astro";
1015
import { remarkStarlightSpellChecker } from "./libs/remark";
1116
import { green } from "kleur/colors";
@@ -43,20 +48,17 @@ export default function starlightSpellChecker(
4348
},
4449
],
4550
],
51+
smartypants: false,
4652
},
4753
});
4854
},
49-
"astro:build:done": async ({ dir, pages }) => {
50-
const { warnings, errors } = await validateTexts(
51-
pages,
52-
dir,
53-
astroConfig,
54-
starlightConfig,
55-
config
56-
);
55+
"astro:build:done": async () => {
56+
const { warnings, errors, unsupportedLanguages } =
57+
await validateTexts(config);
5758

5859
logWarnings(logger, warnings);
5960
logErrors(logger, errors);
61+
logUnsupportedLanguages(logger, unsupportedLanguages);
6062

6163
if (warnings.size <= 0 && errors.size <= 0) {
6264
logger.info(green("✓ All words spelled correctly.\n"));

packages/starlight-spell-checker/libs/config.ts

+170
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,15 @@ const configSchema = z
8080
* @default false
8181
*/
8282
throwError: z.boolean().default(false),
83+
84+
/**
85+
* Defines a list of words that should be ignored by the case police checker.
86+
*
87+
* The words in this list will be ignored by the case police checker and will not be considered as misspelled.
88+
*
89+
* @default []
90+
*/
91+
ignore: z.array(z.string()).default([]),
8392
})
8493
.default({}),
8594

@@ -104,6 +113,23 @@ const configSchema = z
104113
* @default false
105114
*/
106115
throwError: z.boolean().default(false),
116+
117+
/**
118+
* Whether to ignore [literal words](https://github.com/syntax-tree/nlcst-is-literal).
119+
*
120+
* @default true
121+
*/
122+
ignoreLiterals: z.boolean().default(true),
123+
124+
/**
125+
* Whether to suggest straight (') or smart (’) apostrophes.
126+
*
127+
* @default "smart"
128+
*/
129+
mode: z
130+
.enum(["smart", "straight"])
131+
.default("smart")
132+
.transform((value) => value === "straight"),
107133
})
108134
.default({}),
109135

@@ -152,6 +178,22 @@ const configSchema = z
152178
* @default false
153179
*/
154180
throwError: z.boolean().default(false),
181+
182+
/**
183+
* Defines a list of words that should be ignored by the equality checker.
184+
*
185+
* The words in this list will be ignored by the equality checker and will not be considered as inconsiderate.
186+
*
187+
* @default []
188+
*/
189+
ignore: z.array(z.string()).default([]),
190+
191+
/**
192+
* Whether to allow "he or she", "garbagemen and garbagewomen", etc.
193+
*
194+
* @default false
195+
*/
196+
binary: z.boolean().default(false),
155197
})
156198
.default({}),
157199

@@ -200,6 +242,15 @@ const configSchema = z
200242
* @default false
201243
*/
202244
throwError: z.boolean().default(false),
245+
246+
/**
247+
* Defines a list of words that should be ignored by the intensify checker.
248+
*
249+
* The words in this list will be ignored by the intensify checker and will not be considered as weak.
250+
*
251+
* @default []
252+
*/
253+
ignore: z.array(z.string()).default([]),
203254
})
204255
.default({}),
205256

@@ -248,6 +299,15 @@ const configSchema = z
248299
* @default false
249300
*/
250301
throwError: z.boolean().default(false),
302+
303+
/**
304+
* Defines a list of words that should be ignored by the passive checker.
305+
*
306+
* The words in this list will be ignored by the passive checker and will not be considered as passive.
307+
*
308+
* @default []
309+
*/
310+
ignore: z.array(z.string()).default([]),
251311
})
252312
.default({}),
253313

@@ -272,11 +332,36 @@ const configSchema = z
272332
* @default false
273333
*/
274334
throwError: z.boolean().default(false),
335+
336+
/**
337+
* Defines a list of words that should be ignored by the profanity checker.
338+
*
339+
* The words in this list will be ignored by the profanity checker and will not be considered as vulgar.
340+
*
341+
* @default []
342+
*/
343+
ignore: z.array(z.string()).default([]),
344+
345+
/**
346+
* Minimum sureness to warn about, see [cuss](https://github.com/words/cuss)
347+
*
348+
* @default 0
349+
*/
350+
sureness: z
351+
.number()
352+
.refine((val) => [0, 1, 2].includes(val), {
353+
message: "Number must be 0, 1, or 2",
354+
})
355+
.default(0),
275356
})
276357
.default({}),
277358

278359
/**
279360
* Configuration for the readability plugin.
361+
*
362+
* It applies [Dale—Chall](https://github.com/words/dale-chall-formula),
363+
[Automated Readability](https://github.com/words/automated-readability), [Coleman-Liau](https://github.com/words/coleman-liau), [Flesch](https://github.com/words/flesch),
364+
[Gunning-Fog](https://github.com/words/gunning-fog), [SMOG](https://github.com/words/smog-formula), and [Spache](https://github.com/words/spache-formula).
280365
*/
281366
readability: z
282367
.object({
@@ -296,6 +381,33 @@ const configSchema = z
296381
* @default false
297382
*/
298383
throwError: z.boolean().default(false),
384+
385+
/**
386+
* Defines the target age group.
387+
*
388+
* @default 22
389+
*/
390+
age: z.number().default(22),
391+
392+
/**
393+
* Defines the minimum number of words.
394+
*
395+
* Evaluate sentences containing at least this number of words. While most algorithms assess the reading level of an entire text, this plugin analyzes each sentence individually. Short sentences, however, can be disproportionately influenced by a single long or complex word.
396+
*
397+
* @default 5
398+
*/
399+
minWords: z.number().default(5),
400+
401+
/**
402+
* Defines how many algorithms (out of 7) need to agree that something is hard to read.
403+
*
404+
* The algorithms are: [Dale—Chall](https://github.com/words/dale-chall-formula),
405+
[Automated Readability](https://github.com/words/automated-readability), [Coleman-Liau](https://github.com/words/coleman-liau), [Flesch](https://github.com/words/flesch),
406+
[Gunning-Fog](https://github.com/words/gunning-fog), [SMOG](https://github.com/words/smog-formula), and [Spache](https://github.com/words/spache-formula)
407+
*
408+
* @default 4/7
409+
*/
410+
threshold: z.number().default(4 / 7),
299411
})
300412
.default({}),
301413

@@ -368,6 +480,15 @@ const configSchema = z
368480
* @default false
369481
*/
370482
throwError: z.boolean().default(false),
483+
484+
/**
485+
* Defines a list of words that should be ignored by the simplify checker.
486+
*
487+
* The words in this list will be ignored by the simplify checker and will not be considered as simplifiable.
488+
*
489+
* @default []
490+
*/
491+
ignore: z.array(z.string()).default([]),
371492
})
372493
.default({}),
373494

@@ -416,6 +537,55 @@ const configSchema = z
416537
* @default false
417538
*/
418539
throwError: z.boolean().default(false),
540+
541+
/**
542+
* Whether to suggest straight (') or smart (’) apostrophes.
543+
*
544+
* @default "smart"
545+
*/
546+
mode: z.enum(["smart", "straight"]).default("smart"),
547+
548+
smart: z
549+
.union([
550+
z.array(
551+
z.string().refine((str) => str.length === 1 || str.length === 2, {
552+
message:
553+
"Each quote must be either one or two characters long.",
554+
})
555+
),
556+
z.record(
557+
z.array(
558+
z
559+
.string()
560+
.refine((str) => str.length === 1 || str.length === 2, {
561+
message:
562+
"Each quote must be either one or two characters long.",
563+
})
564+
)
565+
),
566+
])
567+
.default(["“”", "‘’"]),
568+
569+
straight: z
570+
.union([
571+
z.array(
572+
z.string().refine((str) => str.length === 1 || str.length === 2, {
573+
message:
574+
"Each quote must be either one or two characters long.",
575+
})
576+
),
577+
z.record(
578+
z.array(
579+
z
580+
.string()
581+
.refine((str) => str.length === 1 || str.length === 2, {
582+
message:
583+
"Each quote must be either one or two characters long.",
584+
})
585+
)
586+
),
587+
])
588+
.default(['"', "'"]),
419589
})
420590
.default({}),
421591

packages/starlight-spell-checker/libs/i18n.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { ensureLeadingSlash, ensureTrailingSlash } from "./path";
22
import type { StarlightUserConfig } from "./validation";
33

4+
import dictionaryDa from "dictionary-da";
45
import dictionaryDe from "dictionary-de";
56
import dictionaryEn, { type Dictionary } from "dictionary-en";
67
import dictionaryEs from "dictionary-es";
@@ -38,8 +39,9 @@ export function getLocaleConfig(config: StarlightUserConfig): LocaleConfig {
3839
};
3940
}
4041

41-
const dictionaryMapper: Record<string, any> = {
42+
const dictionaryMapper: Record<string, Dictionary | undefined> = {
4243
ar: undefined,
44+
da: dictionaryDa,
4345
de: dictionaryDe,
4446
en: dictionaryEn,
4547
es: dictionaryEs,
@@ -55,7 +57,7 @@ const dictionaryMapper: Record<string, any> = {
5557
"zh-tw": undefined,
5658
};
5759

58-
export function getLocaleDictionary(path: string): Dictionary {
60+
export function getLocaleDictionary(path: string): Dictionary | undefined {
5961
return dictionaryMapper[path];
6062
}
6163

packages/starlight-spell-checker/libs/remark.ts

+29-4
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,19 @@ import "mdast-util-mdx-jsx";
33
import nodePath from "node:path";
44
import { fileURLToPath } from "node:url";
55

6-
import { hasProperty } from "hast-util-has-property";
7-
import type { Nodes } from "hast";
8-
import { fromHtml } from "hast-util-from-html";
96
import { slug } from "github-slugger";
107
import type { Root } from "mdast";
11-
import { unified, type Plugin } from "unified";
8+
import { type Plugin } from "unified";
129
import { visit } from "unist-util-visit";
1310

1411
import { ensureTrailingSlash, stripLeadingSlash } from "./path";
1512
import { getLocaleConfig, getLocale } from "./i18n";
1613
import type { StarlightUserConfig } from "./validation";
1714

15+
import { unified } from "unified";
16+
import rehypeParse from "rehype-parse";
17+
import { toText } from "hast-util-to-text";
18+
1819
// All the text content keyed by locale, then keyed by file path.
1920
const contents: Contents = new Map();
2021

@@ -33,6 +34,30 @@ export const remarkStarlightSpellChecker: Plugin<
3334

3435
let fileContent: string = "";
3536

37+
// Extract all string values from frontmatter (recursively, with HTML parsing)
38+
const frontmatter = file.data.astro?.frontmatter;
39+
if (frontmatter) {
40+
const extractStrings = (obj: any): string[] => {
41+
const strings: string[] = [];
42+
for (const value of Object.values(obj)) {
43+
if (typeof value === "string") {
44+
// Parse HTML and extract text content
45+
const htmlTree = unified()
46+
.use(rehypeParse, { fragment: true })
47+
.parse(value);
48+
const textContent = toText(htmlTree);
49+
strings.push(textContent);
50+
} else if (typeof value === "object" && value !== null) {
51+
strings.push(...extractStrings(value));
52+
}
53+
}
54+
return strings;
55+
};
56+
57+
fileContent += extractStrings(frontmatter).join("\n");
58+
fileContent += "\n"; // Separate frontmatter from the Markdown content
59+
}
60+
3661
// https://github.com/syntax-tree/mdast#nodes
3762
// https://github.com/syntax-tree/mdast-util-mdx-jsx#nodes
3863
visit(

0 commit comments

Comments
 (0)