Skip to content

Commit 9160da5

Browse files
committed
Add note on case mapping
1 parent 3fe681b commit 9160da5

File tree

14 files changed

+950
-4
lines changed

14 files changed

+950
-4
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
"clsx": "^2.0.0",
5656
"color": "^4.2.3",
5757
"copy-text-to-clipboard": "^3.2.0",
58+
"core-js": "^3.33.2",
5859
"github-slugger": "^2.0.0",
5960
"hast-util-to-text": "^4.0.0",
6061
"prism-react-renderer": "^2.1.0",

project-words.txt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,32 @@
1+
casedness
12
cena
23
charis
4+
closedness
35
cmyk
6+
codomain
47
conlang
58
copiable
69
coursetable
10+
dialytika
11+
dotless
712
estree
13+
flattenable
814
huayu
915
infty
16+
injectivity
1017
joshcena
1118
katex
1219
kitchensink
1320
kwargs
21+
letterlike
22+
lext
1423
luo
24+
mathbb
1525
mathcal
26+
mathtt
1627
mdast
1728
mdxjs
29+
mediavalist
1830
metastring
1931
naclo
2032
noninteractive
@@ -23,15 +35,21 @@ numpy
2335
peaceiris
2436
pipeable
2537
posix
38+
prosgegrammeni
2639
randcolor
2740
rehype
2841
saturationl
2942
scrolly
3043
sida
3144
silw
45+
surjectivity
3246
svgr
47+
tonos
3348
triaging
3449
tseslint
50+
uext
3551
wfla
3652
wordcloud
53+
yiwn
54+
ypogegrammeni
3755
zhihu

server/pre-render.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ const render = (
1818
// Has leading slash; no trailing slash
1919
// e.g. ["/", "/about", "/404"]
2020
const routesToPrerender = (
21-
await glob(toAbsolute("../src/pages/**/*.{tsx,mdx}"))
21+
await glob(toAbsolute("../src/pages/**/[!_]*.{tsx,mdx}"))
2222
).map((file) => {
2323
const name = Path.relative(toAbsolute("../src/pages"), file)
2424
.replace(/(?:\/?index)?\.(?:tsx|mdx)$/, "")

src/App.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import "core-js/proposals/set-methods-v2";
2+
import "core-js/proposals/iterator-helpers";
3+
14
import React from "react";
25
import { routes } from "./routes";
36
import { Route, Routes } from "react-router-dom";

src/components/Heading/index.tsx

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useEffect, useMemo, useContext } from "react";
1+
import React, { useEffect, useMemo, useContext, type ReactNode } from "react";
22
import GithubSlugger, { slug } from "github-slugger";
33
import styles from "./index.module.css";
44

@@ -26,6 +26,14 @@ function useSlugger(): GithubSlugger {
2626
return slugger;
2727
}
2828

29+
function getText(children: ReactNode): string {
30+
if (typeof children === "string") return children;
31+
if (Array.isArray(children))
32+
return children.map(getText).filter(Boolean).join(" ");
33+
if (React.isValidElement(children)) return getText(children.props.children);
34+
return "";
35+
}
36+
2937
export default function Heading({
3038
level,
3139
children,
@@ -42,7 +50,7 @@ export default function Heading({
4250
// () => slugger.slug(children as string),
4351
// [slugger, children],
4452
// );
45-
const id = anchor ?? slug(children as string);
53+
const id = anchor ?? slug(getText(children));
4654
return (
4755
<HeadingTag id={id}>
4856
<a href={`#${id}`} className={styles.anchor}>

src/global.css

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,10 @@ td {
151151
border: 1px solid var(--color-text);
152152
}
153153

154+
summary {
155+
cursor: pointer;
156+
}
157+
154158
.tooltip {
155159
--rt-opacity: 1;
156160
background-color: var(--color-background);
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
.charSet {
2+
display: flex;
3+
flex-direction: row;
4+
flex-wrap: wrap;
5+
gap: 0.5em;
6+
}
7+
8+
.char {
9+
min-width: 7em;
10+
}
11+
12+
:global(.assertion-failed) {
13+
color: red;
14+
font-weight: bold;
15+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import clsx from "clsx";
2+
import styles from "./_DataTables.module.css";
3+
4+
export function charCode(char: string): string {
5+
return `${char} (${[...char]
6+
.map(
7+
(c) =>
8+
`U+${c.codePointAt(0)!.toString(16).toUpperCase().padStart(4, "0")}`,
9+
)
10+
.join(" ")})`;
11+
}
12+
13+
export function CharSet<T>({
14+
set,
15+
display,
16+
assertSize,
17+
}: {
18+
readonly set: Iterable<T>;
19+
readonly display?: (char: T) => string;
20+
readonly assertSize?: number;
21+
}): JSX.Element {
22+
const values = [...set];
23+
const assertionFailed =
24+
assertSize !== undefined && values.length !== assertSize;
25+
if (assertionFailed) {
26+
console.error(
27+
"Assertion failed: expected set of size",
28+
assertSize,
29+
"but got",
30+
values.length,
31+
);
32+
}
33+
if (values.length === 0) {
34+
return (
35+
<span className={clsx(assertionFailed && "assertion-failed")}></span>
36+
);
37+
}
38+
39+
return (
40+
<details>
41+
<summary>
42+
Character set (
43+
<span className={clsx(assertionFailed && "assertion-failed")}>
44+
{values.length}
45+
</span>
46+
)
47+
</summary>
48+
{display ? (
49+
<ul>
50+
{values.map((char, i) => (
51+
// eslint-disable-next-line react/no-array-index-key
52+
<li key={i}>{display(char)}</li>
53+
))}
54+
</ul>
55+
) : (
56+
<div className={styles.charSet}>
57+
{values.map((char) => (
58+
<span key={char as string} className={styles.char}>
59+
{charCode(char as string)}
60+
</span>
61+
))}
62+
</div>
63+
)}
64+
</details>
65+
);
66+
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
export function toLowerCase(char: string): string;
2+
export function toLowerCase(char: Iterable<string>): Set<string>;
3+
export function toLowerCase(
4+
char: string | Iterable<string>,
5+
): string | Set<string> {
6+
if (typeof char === "string") return char.toLowerCase().normalize("NFC");
7+
return new Set(Iterator.from(char).map(toLowerCase));
8+
}
9+
10+
export function toUpperCase(char: string): string;
11+
export function toUpperCase(char: Iterable<string>): Set<string>;
12+
export function toUpperCase(
13+
char: string | Iterable<string>,
14+
): string | Set<string> {
15+
if (typeof char === "string") return char.toUpperCase().normalize("NFC");
16+
return new Set(Iterator.from(char).map(toUpperCase));
17+
}
18+
19+
export function isChar(char: string): boolean {
20+
return [...char].length === 1;
21+
}
22+
23+
export function isUpperCase(char: string): boolean {
24+
return /\p{Uppercase_Letter}/u.test(char);
25+
}
26+
27+
export function isLowerCase(char: string): boolean {
28+
return /\p{Lowercase_Letter}/u.test(char);
29+
}
30+
31+
export const UC = new Set<string>();
32+
export const U = new Set<string>();
33+
export const L = new Set<string>();
34+
export const Uext = new Set<string>();
35+
export const Lext = new Set<string>();
36+
export const ML = new Set<string>();
37+
export const MU = new Set<string>();
38+
export const ML_ = new Set<string>();
39+
export const MU_ = new Set<string>();
40+
export const NL = new Set<string>();
41+
export const NU = new Set<string>();
42+
export const NL_ = new Set<string>();
43+
export const NU_ = new Set<string>();
44+
45+
export function isI(c: string): boolean {
46+
return toUpperCase(c) === c && toLowerCase(c) === c;
47+
}
48+
49+
for (let c = 0; c < 0x10ffff; c++) {
50+
const char = String.fromCodePoint(c).normalize("NFC");
51+
if (isUpperCase(char)) Uext.add(char);
52+
if (isLowerCase(char)) Lext.add(char);
53+
if (!isChar(char) || isI(char)) continue;
54+
UC.add(char);
55+
const upper = toUpperCase(char);
56+
const lower = toLowerCase(char);
57+
if (isI(upper))
58+
console.error(`Invariant broken: toUpperCase(${char}) = ${upper} ∈ I`);
59+
else if (isI(lower))
60+
console.error(`Invariant broken: toLowerCase(${char}) = ${lower} ∈ I`);
61+
if (!isChar(upper)) {
62+
if (isChar(toLowerCase(upper))) {
63+
ML.add(char);
64+
ML_.add(upper);
65+
} else {
66+
NL.add(char);
67+
NL_.add(upper);
68+
}
69+
}
70+
if (!isChar(lower)) {
71+
if (isChar(toUpperCase(lower))) {
72+
MU.add(char);
73+
MU_.add(lower);
74+
} else {
75+
NU.add(char);
76+
NU_.add(lower);
77+
}
78+
}
79+
if (isUpperCase(char)) U.add(char);
80+
if (isLowerCase(char)) L.add(char);
81+
}
82+
83+
export const GrU = new Set(NL.values().filter((c) => toLowerCase(c) !== c));
84+
85+
export const RU = toUpperCase(UC);
86+
export const RL = toLowerCase(UC);

0 commit comments

Comments
 (0)