Skip to content

Commit b4f33ba

Browse files
authored
refactor: replace startsWith with strict equality (#883)
1 parent 8958b41 commit b4f33ba

14 files changed

+51
-19
lines changed

eslint.config.mjs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { fixupConfigRules } from "@eslint/compat"
44
import { FlatCompat } from "@eslint/eslintrc"
55
import js from "@eslint/js"
66
import myPlugin from "@ota-meshi/eslint-plugin"
7+
import pere from "eslint-plugin-pere"
78
import regexp from "eslint-plugin-regexp"
89
import unicorn from "eslint-plugin-unicorn"
910
import tseslint from "typescript-eslint"
@@ -169,6 +170,12 @@ export default [
169170
"no-implicit-globals": "off",
170171
"@typescript-eslint/naming-convention": "off",
171172
"@typescript-eslint/no-shadow": "error",
173+
"@typescript-eslint/prefer-string-starts-ends-with": [
174+
"error",
175+
{
176+
allowSingleElementEquality: "always",
177+
},
178+
],
172179
},
173180
},
174181
{
@@ -253,4 +260,11 @@ export default [
253260
"unicorn/prefer-string-raw": "error",
254261
},
255262
},
263+
{
264+
files: ["**/*.{ts,mts}"],
265+
plugins: { pere },
266+
rules: {
267+
"pere/no-startswith-one-char": "error",
268+
},
269+
},
256270
]

lib/rules/match-any.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ export default createRule("match-any", {
112112

113113
if (
114114
regexpNode.type === "CharacterClass" &&
115-
preference.startsWith("[") &&
115+
preference[0] === "[" &&
116116
preference.endsWith("]")
117117
) {
118118
// We know that the first and last character are the same,

lib/rules/no-control-character.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ export default createRule("no-control-character", {
5353
function isAllowedEscapeRaw(raw: string): boolean {
5454
return (
5555
ALLOWED_CONTROL_CHARS.test(raw) ||
56-
(raw.startsWith("\\") &&
56+
(raw[0] === "\\" &&
5757
ALLOWED_CONTROL_CHARS.test(raw.slice(1)))
5858
)
5959
}
@@ -78,7 +78,7 @@ export default createRule("no-control-character", {
7878

7979
return (
8080
isBadEscapeRaw(char.raw, char.value) ||
81-
(char.raw.startsWith("\\") &&
81+
(char.raw[0] === "\\" &&
8282
isBadEscapeRaw(char.raw.slice(1), char.value))
8383
)
8484
}

lib/rules/no-useless-escape.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ export default createRule("no-useless-escape", {
121121
onExpressionCharacterClassLeave: () =>
122122
characterClassStack.shift(),
123123
onCharacterEnter(cNode) {
124-
if (cNode.raw.startsWith("\\")) {
124+
if (cNode.raw[0] === "\\") {
125125
// escapes
126126
const char = cNode.raw.slice(1)
127127
const escapedChar = String.fromCodePoint(cNode.value)

lib/rules/no-useless-range.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ export default createRule("no-useless-range", {
6767
}
6868
}
6969

70-
if (rawAfter.startsWith("-")) {
70+
if (rawAfter[0] === "-") {
7171
// the next "-" might be interpreted as a range
7272
// operator now, so we have to escape it
7373
// e.g. /[a-a-z]/ -> /[a\-z]/

lib/rules/prefer-character-class.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ function elementsToCharacterClass(elements: CharElementArray): string {
122122
}
123123
})
124124

125-
if (parts.length > 0 && parts[0].startsWith("^")) {
125+
if (parts.length > 0 && parts[0][0] === "^") {
126126
parts[0] = `\\${parts[0]}`
127127
}
128128

lib/rules/sort-character-class-elements.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,7 @@ export default createRule("sort-character-class-elements", {
283283
*/
284284
function escapeRaw(node: CharacterClassElement, target: CharacterClassElement) {
285285
let raw = node.raw
286-
if (raw.startsWith("-")) {
286+
if (raw[0] === "-") {
287287
const parent = target.parent as CharacterClass
288288
const elements: (
289289
| UnicodeSetsCharacterClassElement
@@ -296,7 +296,7 @@ function escapeRaw(node: CharacterClassElement, target: CharacterClassElement) {
296296
) {
297297
raw = `\\${raw}`
298298
}
299-
} else if (raw.startsWith("^")) {
299+
} else if (raw[0] === "^") {
300300
const parent = target.parent as CharacterClass
301301
const elements: (
302302
| UnicodeSetsCharacterClassElement
@@ -306,7 +306,7 @@ function escapeRaw(node: CharacterClassElement, target: CharacterClassElement) {
306306
raw = `\\${raw}`
307307
}
308308
}
309-
if (target.raw.startsWith("-")) {
309+
if (target.raw[0] === "-") {
310310
if (node.type === "Character" || node.type === "CharacterSet") {
311311
raw = `${raw}\\`
312312
}

lib/rules/strict.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ export default createRule("strict", {
185185
return
186186
}
187187

188-
if (cNode.raw.startsWith("\\")) {
188+
if (cNode.raw[0] === "\\") {
189189
const identity = cNode.raw.slice(1)
190190
const syntaxChars = insideCharClass
191191
? CHARACTER_CLASS_SYNTAX_CHARACTERS

lib/utils/index.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -935,7 +935,7 @@ export function mightCreateNewElement(before: string, after: string): boolean {
935935
if (
936936
(/(?:^|[^\\])(?:\\{2})*\\[1-9]\d*$/u.test(before) &&
937937
/^\d/u.test(after)) ||
938-
(/(?:^|[^\\])(?:\\{2})*\\k$/u.test(before) && after.startsWith("<")) ||
938+
(/(?:^|[^\\])(?:\\{2})*\\k$/u.test(before) && after[0] === "<") ||
939939
/(?:^|[^\\])(?:\\{2})*\\k<[^<>]*$/u.test(before)
940940
) {
941941
return true
@@ -959,8 +959,7 @@ export function mightCreateNewElement(before: string, after: string): boolean {
959959
/^[\d,}]/u.test(after)) ||
960960
(/(?:^|[^\\])(?:\\{2})*\{\d+,$/u.test(before) &&
961961
/^(?:\d+(?:\}|$)|\})/u.test(after)) ||
962-
(/(?:^|[^\\])(?:\\{2})*\{\d+,\d*$/u.test(before) &&
963-
after.startsWith("}"))
962+
(/(?:^|[^\\])(?:\\{2})*\{\d+,\d*$/u.test(before) && after[0] === "}")
964963
) {
965964
return true
966965
}
@@ -1014,13 +1013,13 @@ export function fixRemoveCharacterClassElement(
10141013
if (
10151014
// ... the text character is a dash
10161015
// e.g. [a\w-b] -> [a\-b], [\w-b] -> [-b], [\s\w-b] -> [\s-b]
1017-
(textAfter.startsWith("-") &&
1016+
(textAfter[0] === "-" &&
10181017
elementBefore &&
10191018
elementBefore.type === "Character") ||
10201019
// ... the next character is a caret and the caret will then be the
10211020
// first character in the character class
10221021
// e.g. [a^b] -> [\^b], [ba^] -> [b^]
1023-
(textAfter.startsWith("^") && !cc.negate && !elementBefore)
1022+
(textAfter[0] === "^" && !cc.negate && !elementBefore)
10241023
) {
10251024
return "\\"
10261025
}

lib/utils/regex-syntax.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ export enum EscapeSequenceKind {
6868
* Returns which escape sequence kind was used for the given raw of a character literal.
6969
*/
7070
export function getEscapeSequenceKind(raw: string): EscapeSequenceKind | null {
71-
if (!raw.startsWith("\\")) {
71+
if (raw[0] !== "\\") {
7272
return null
7373
}
7474
if (isOctalEscape(raw)) {

0 commit comments

Comments
 (0)