Skip to content

Commit 9ce7b62

Browse files
committed
feat: write an ESLint plugin to check code point names
1 parent 164c3ad commit 9ce7b62

File tree

12 files changed

+102
-17
lines changed

12 files changed

+102
-17
lines changed

eslint.config.js

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/* eslint-disable n/no-extraneous-import */
22

33
import js from "@eslint/js";
4+
import keybr from "@keybr/scripts/lib/eslint-plugin-keybr.js";
45
import confusingBrowserGlobals from "confusing-browser-globals";
56
import ava from "eslint-plugin-ava";
67
import formatjs from "eslint-plugin-formatjs";
@@ -32,6 +33,7 @@ export default [
3233
react.configs.flat["jsx-runtime"],
3334
node.configs["flat/recommended-module"],
3435
ava.configs["flat/recommended"],
36+
keybr.configs["recommended"],
3537
{
3638
ignores: ["packages/server/**", "packages/server-cli/**"],
3739
plugins: { "react-hooks": reactHooks },
@@ -87,10 +89,7 @@ export default [
8789
// configure node
8890
"n/file-extension-in-import": ["error", "always"],
8991
"n/hashbang": "off",
90-
"n/no-path-concat": "off",
9192
"n/no-process-exit": "off",
92-
"n/no-unsupported-features/es-builtins": "off",
93-
"n/no-unsupported-features/es-syntax": "off",
9493
"n/no-unsupported-features/node-builtins": "off",
9594
"n/prefer-global/buffer": ["error", "always"],
9695
"n/prefer-global/console": ["error", "always"],

packages/keybr-generators/lib/layout/diacritics.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ export const makeDeadCharacter = (
4646
if (dead != null) {
4747
return dead;
4848
}
49-
if (codePoint === /* * */ 0x002a) {
49+
if (codePoint === /* "*" */ 0x002a) {
5050
return { dead: codePoint };
5151
}
5252
console.error(

packages/keybr-generators/lib/layout/import-json.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ function parseCharacterList(
7070
}
7171

7272
if (a.length === 2) {
73-
if (a[0] === /* * */ 0x002a) {
73+
if (a[0] === /* "*" */ 0x002a) {
7474
characters.push(makeDeadCharacter(keyId, a[1]));
7575
continue;
7676
}

packages/keybr-keyboard-ui/lib/Key.test.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,8 @@ test.serial("dead labels", (t) => {
6363
[
6464
{ dead: /* COMBINING GRAVE ACCENT */ 0x0300 },
6565
{ dead: /* COMBINING ACUTE ACCENT */ 0x0301 },
66-
{ dead: /* * */ 0x002a },
67-
{ dead: /* * */ 0x002a },
66+
{ dead: /* "*" */ 0x002a },
67+
{ dead: /* "*" */ 0x002a },
6868
],
6969
);
7070

packages/keybr-keyboard/lib/keyboard.test.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ test("data", (t) => {
2424
Equal: [
2525
{ dead: /* COMBINING ACUTE ACCENT */ 0x0301 },
2626
{ dead: /* COMBINING GRAVE ACCENT */ 0x0300 },
27-
{ dead: /* * */ 0x002a },
28-
{ dead: /* * */ 0x002a },
27+
{ dead: /* "*" */ 0x002a },
28+
{ dead: /* "*" */ 0x002a },
2929
],
3030
};
3131
const geometryDict: GeometryDict = {
@@ -124,8 +124,8 @@ test("data", (t) => {
124124
"Equal",
125125
{ dead: /* COMBINING ACUTE ACCENT */ 0x0301 },
126126
{ dead: /* COMBINING GRAVE ACCENT */ 0x0300 },
127-
{ dead: /* * */ 0x002a },
128-
{ dead: /* * */ 0x002a },
127+
{ dead: /* "*" */ 0x002a },
128+
{ dead: /* "*" */ 0x002a },
129129
),
130130
);
131131

packages/keybr-keyboard/lib/keycharacters.test.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ test("codepoint characters", (t) => {
1919
test("dead characters", (t) => {
2020
const characters = new KeyCharacters(
2121
"KeyA",
22-
{ dead: /* * */ 0x002a },
23-
{ dead: /* * */ 0x002a },
22+
{ dead: /* "*" */ 0x002a },
23+
{ dead: /* "*" */ 0x002a },
2424
null,
2525
null,
2626
);

packages/keybr-unicode/lib/whitespace.ts

-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ export const isLinebreak = (codePoint: CodePoint): boolean =>
77
codePoint === /* LINE TABULATION */ 0x000b ||
88
codePoint === /* FORM FEED */ 0x000c ||
99
codePoint === /* CARRIAGE RETURN */ 0x000d ||
10-
codePoint === /* NEXT LINE */ 0x0085 ||
1110
codePoint === /* LINE SEPARATOR */ 0x2028 ||
1211
codePoint === /* PARAGRAPH SEPARATOR */ 0x2029;
1312

@@ -18,7 +17,6 @@ export const isWhitespace = (codePoint: CodePoint): boolean =>
1817
codePoint === /* FORM FEED */ 0x000c ||
1918
codePoint === /* CARRIAGE RETURN */ 0x000d ||
2019
codePoint === /* SPACE */ 0x0020 ||
21-
codePoint === /* NEXT LINE */ 0x0085 ||
2220
codePoint === /* NO-BREAK SPACE */ 0x00a0 ||
2321
codePoint === /* EN QUAD */ 0x2000 ||
2422
codePoint === /* EM QUAD */ 0x2001 ||

scripts/config-lint.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { existsSync } from "node:fs";
22
import { join } from "node:path";
33
import { globSync } from "glob";
4-
import { readJsonSync, writeJsonSync } from "./lib/fs.js";
4+
import { readJsonSync, writeJsonSync } from "./lib/fs-json.js";
55
import { packageJsonKeys, tsconfigJsonKeys } from "./lib/key-order.js";
66
import { findDeps, printUnusedDeps } from "./lib/lang.js";
77
import { sortJson } from "./lib/sort-json.js";

scripts/lib/codepoints.js

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import unicodeNames from "@unicode/unicode-16.0.0/Names/index.js";
2+
3+
const controlNames = new Map([
4+
[0x0000, "NULL"],
5+
[0x0008, "BACKSPACE"],
6+
[0x0009, "CHARACTER TABULATION"],
7+
[0x000a, "LINE FEED"],
8+
[0x000b, "LINE TABULATION"],
9+
[0x000c, "FORM FEED"],
10+
[0x000d, "CARRIAGE RETURN"],
11+
[0x001b, "ESCAPE"],
12+
]);
13+
14+
export function getCodePointName(codePoint) {
15+
return controlNames.get(codePoint) ?? unicodeNames.get(codePoint) ?? "?";
16+
}

scripts/lib/eslint-plugin-keybr.js

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import { getCodePointName } from "./codepoints.js";
2+
3+
const rule = {
4+
meta: {
5+
type: "problem",
6+
docs: {
7+
description: "Checks code point name comments.",
8+
},
9+
fixable: "code",
10+
schema: [],
11+
},
12+
create(context) {
13+
return {
14+
Literal(node) {
15+
if (
16+
node.type === "Literal" &&
17+
typeof node.value === "number" &&
18+
/0x[0-9a-fA-F]{4}/.test(node.raw)
19+
) {
20+
const [comment] = context.sourceCode.getCommentsBefore(node);
21+
if (comment?.type === "Block") {
22+
const name1 =
23+
node.value === /* QUOTATION MARK */ 0x0022
24+
? ` '"' `
25+
: ` "${String.fromCodePoint(node.value)}" `;
26+
const name2 = ` ${getCodePointName(node.value)} `;
27+
if (comment.value !== name1 && comment.value !== name2) {
28+
const expected = comment.value.includes('"')
29+
? `/*${name1}*/`
30+
: `/*${name2}*/`;
31+
context.report({
32+
node,
33+
message:
34+
"Invalid code point name comment, expected: {{ expected }}",
35+
data: {
36+
expected,
37+
},
38+
fix(fixer) {
39+
return fixer.replaceText(comment, expected);
40+
},
41+
});
42+
}
43+
}
44+
}
45+
},
46+
};
47+
},
48+
};
49+
50+
const plugin = {
51+
meta: {
52+
name: "eslint-plugin-keybr",
53+
version: "0.0.0",
54+
},
55+
configs: {},
56+
rules: {
57+
"codepoint-names": rule,
58+
},
59+
};
60+
61+
Object.assign(plugin.configs, {
62+
recommended: {
63+
plugins: {
64+
keybr: plugin,
65+
},
66+
rules: {
67+
"keybr/codepoint-names": "error",
68+
},
69+
},
70+
});
71+
72+
export default plugin;
File renamed without changes.

scripts/translate.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { writeFileSync } from "node:fs";
22
import { join } from "node:path";
33
import { compile, extract } from "@formatjs/cli-lib";
44
import { globSync } from "glob";
5-
import { readJsonSync, writeJsonSync } from "./lib/fs.js";
5+
import { readJsonSync, writeJsonSync } from "./lib/fs-json.js";
66
import { getHashDigest } from "./lib/intl.js";
77
import { findPackages, rootDir } from "./root.js";
88

0 commit comments

Comments
 (0)