Skip to content

Commit 1c05d4e

Browse files
authored
Add regexp/prefer-unicode-codepoint-escapes rule (#33)
1 parent 76f3ad8 commit 1c05d4e

File tree

6 files changed

+189
-0
lines changed

6 files changed

+189
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ The rules with the following star :star: are included in the `plugin:regexp/reco
100100
| [regexp/prefer-regexp-test](https://ota-meshi.github.io/eslint-plugin-regexp/rules/prefer-regexp-test.html) | enforce that `RegExp#test` is used instead of `String#match` and `RegExp#exec` | :wrench: |
101101
| [regexp/prefer-star-quantifier](https://ota-meshi.github.io/eslint-plugin-regexp/rules/prefer-star-quantifier.html) | enforce using `*` quantifier | :star::wrench: |
102102
| [regexp/prefer-t](https://ota-meshi.github.io/eslint-plugin-regexp/rules/prefer-t.html) | enforce using `\t` | :star::wrench: |
103+
| [regexp/prefer-unicode-codepoint-escapes](https://ota-meshi.github.io/eslint-plugin-regexp/rules/prefer-unicode-codepoint-escapes.html) | enforce use of unicode codepoint escapes | :wrench: |
103104
| [regexp/prefer-w](https://ota-meshi.github.io/eslint-plugin-regexp/rules/prefer-w.html) | enforce using `\w` | :star::wrench: |
104105

105106
<!--RULES_TABLE_END-->

docs/rules/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,5 @@ The rules with the following star :star: are included in the `plugin:regexp/reco
3232
| [regexp/prefer-regexp-test](./prefer-regexp-test.md) | enforce that `RegExp#test` is used instead of `String#match` and `RegExp#exec` | :wrench: |
3333
| [regexp/prefer-star-quantifier](./prefer-star-quantifier.md) | enforce using `*` quantifier | :star::wrench: |
3434
| [regexp/prefer-t](./prefer-t.md) | enforce using `\t` | :star::wrench: |
35+
| [regexp/prefer-unicode-codepoint-escapes](./prefer-unicode-codepoint-escapes.md) | enforce use of unicode codepoint escapes | :wrench: |
3536
| [regexp/prefer-w](./prefer-w.md) | enforce using `\w` | :star::wrench: |
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
---
2+
pageClass: "rule-details"
3+
sidebarDepth: 0
4+
title: "regexp/prefer-unicode-codepoint-escapes"
5+
description: "enforce use of unicode codepoint escapes"
6+
---
7+
# regexp/prefer-unicode-codepoint-escapes
8+
9+
> enforce use of unicode codepoint escapes
10+
11+
- :exclamation: <badge text="This rule has not been released yet." vertical="middle" type="error"> ***This rule has not been released yet.*** </badge>
12+
- :wrench: The `--fix` option on the [command line](https://eslint.org/docs/user-guide/command-line-interface#fixing-problems) can automatically fix some of the problems reported by this rule.
13+
14+
## :book: Rule Details
15+
16+
This rule enforces the use of Unicode codepoint escapes instead of Unicode escapes using surrogate pairs.
17+
18+
<eslint-code-block fix>
19+
20+
```js
21+
/* eslint regexp/prefer-unicode-codepoint-escapes: "error" */
22+
23+
/* ✓ GOOD */
24+
var foo = /\u{1f600}/u
25+
var foo = /😀/u
26+
27+
/* ✗ BAD */
28+
var foo = /\ud83d\ude00/u
29+
```
30+
31+
</eslint-code-block>
32+
33+
## :wrench: Options
34+
35+
Nothing.
36+
37+
## :mag: Implementation
38+
39+
- [Rule source](https://github.com/ota-meshi/eslint-plugin-regexp/blob/master/lib/rules/prefer-unicode-codepoint-escapes.ts)
40+
- [Test source](https://github.com/ota-meshi/eslint-plugin-regexp/blob/master/tests/lib/rules/prefer-unicode-codepoint-escapes.ts)
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import type { Expression } from "estree"
2+
import type { RegExpVisitor } from "regexpp/visitor"
3+
import {
4+
createRule,
5+
defineRegexpVisitor,
6+
getRegexpLocation,
7+
getRegexpRange,
8+
} from "../utils"
9+
10+
export default createRule("prefer-unicode-codepoint-escapes", {
11+
meta: {
12+
docs: {
13+
description: "enforce use of unicode codepoint escapes",
14+
// TODO In the major version, it will be changed to "recommended".
15+
recommended: false,
16+
},
17+
fixable: "code",
18+
schema: [],
19+
messages: {
20+
disallowSurrogatePair:
21+
"Use Unicode codepoint escapes instead of Unicode escapes using surrogate pairs.",
22+
},
23+
type: "suggestion", // "problem",
24+
},
25+
create(context) {
26+
const sourceCode = context.getSourceCode()
27+
28+
/**
29+
* Create visitor
30+
* @param node
31+
*/
32+
function createVisitor(
33+
node: Expression,
34+
_pattern: string,
35+
flags: string,
36+
): RegExpVisitor.Handlers {
37+
if (!flags.includes("u")) {
38+
return {}
39+
}
40+
return {
41+
onCharacterEnter(cNode) {
42+
if (cNode.value >= 0x10000) {
43+
if (/^(?:\\u[\da-fA-F]{4}){2}$/.test(cNode.raw)) {
44+
context.report({
45+
node,
46+
loc: getRegexpLocation(sourceCode, node, cNode),
47+
messageId: "disallowSurrogatePair",
48+
fix(fixer) {
49+
const range = getRegexpRange(
50+
sourceCode,
51+
node,
52+
cNode,
53+
)
54+
if (range == null) {
55+
return null
56+
}
57+
let text = String.fromCodePoint(cNode.value)
58+
.codePointAt(0)!
59+
.toString(16)
60+
if (/[A-F]/.test(cNode.raw)) {
61+
text = text.toUpperCase()
62+
}
63+
return fixer.replaceTextRange(
64+
range,
65+
`\\u{${text}}`,
66+
)
67+
},
68+
})
69+
}
70+
}
71+
},
72+
}
73+
}
74+
75+
return defineRegexpVisitor(context, {
76+
createVisitor,
77+
})
78+
},
79+
})

lib/utils/rules.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import preferRegexpExec from "../rules/prefer-regexp-exec"
2020
import preferRegexpTest from "../rules/prefer-regexp-test"
2121
import preferStarQuantifier from "../rules/prefer-star-quantifier"
2222
import preferT from "../rules/prefer-t"
23+
import preferUnicodeCodepointEscapes from "../rules/prefer-unicode-codepoint-escapes"
2324
import preferW from "../rules/prefer-w"
2425

2526
export const rules = [
@@ -44,5 +45,6 @@ export const rules = [
4445
preferRegexpTest,
4546
preferStarQuantifier,
4647
preferT,
48+
preferUnicodeCodepointEscapes,
4749
preferW,
4850
] as RuleModule[]
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import { RuleTester } from "eslint"
2+
import rule from "../../../lib/rules/prefer-unicode-codepoint-escapes"
3+
4+
const tester = new RuleTester({
5+
parserOptions: {
6+
ecmaVersion: 2020,
7+
sourceType: "module",
8+
},
9+
})
10+
11+
tester.run("prefer-unicode-codepoint-escapes", rule as any, {
12+
valid: [
13+
`/regexp/u`,
14+
String.raw`/\ud83d\ude00/`,
15+
String.raw`/[\ud83d\ude00]/`,
16+
String.raw`/\u{1f600}/u`,
17+
String.raw`/😀/u`,
18+
],
19+
invalid: [
20+
{
21+
code: String.raw`/\ud83d\ude00/u`,
22+
output: String.raw`/\u{1f600}/u`,
23+
errors: [
24+
{
25+
message:
26+
"Use Unicode codepoint escapes instead of Unicode escapes using surrogate pairs.",
27+
line: 1,
28+
column: 2,
29+
endLine: 1,
30+
endColumn: 14,
31+
},
32+
],
33+
},
34+
{
35+
code: String.raw`/[\ud83d\ude00]/u`,
36+
output: String.raw`/[\u{1f600}]/u`,
37+
errors: [
38+
{
39+
message:
40+
"Use Unicode codepoint escapes instead of Unicode escapes using surrogate pairs.",
41+
line: 1,
42+
column: 3,
43+
endLine: 1,
44+
endColumn: 15,
45+
},
46+
],
47+
},
48+
{
49+
code: String.raw`/\uD83D\uDE00/u`,
50+
output: String.raw`/\u{1F600}/u`,
51+
errors: [
52+
"Use Unicode codepoint escapes instead of Unicode escapes using surrogate pairs.",
53+
],
54+
},
55+
{
56+
code: String.raw`
57+
const s = "\\ud83d\\ude00"
58+
new RegExp(s, 'u')
59+
`,
60+
output: null,
61+
errors: [
62+
"Use Unicode codepoint escapes instead of Unicode escapes using surrogate pairs.",
63+
],
64+
},
65+
],
66+
})

0 commit comments

Comments
 (0)