Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/hungry-coins-help.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"eslint-plugin-regexp": minor
---

Use Intl.Segmenter instead of grapheme-splitter
20 changes: 9 additions & 11 deletions lib/rules/no-misleading-unicode-character.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import type { RegExpVisitor } from "@eslint-community/regexpp/visitor"
import type { RegExpContext } from "../utils"
import { isEscapeSequence, createRule, defineRegexpVisitor } from "../utils"
import GraphemeSplitter from "grapheme-splitter"
import type { ReadonlyFlags } from "regexp-ast-analysis"
import { mention, mentionChar } from "../utils/mention"
import type {
Expand All @@ -12,7 +11,7 @@ import type {
import type { PatternRange } from "../utils/ast-utils/pattern-source"
import type { Rule } from "eslint"

const splitter = new GraphemeSplitter()
const segmenter = new Intl.Segmenter()

/** Returns whether the given string starts with a valid surrogate pair. */
function startsWithSurrogate(s: string): boolean {
Expand Down Expand Up @@ -66,10 +65,10 @@ function getGraphemeBeforeQuant(quant: Quantifier): string {
quant.element.end - alt.start,
)

const graphemes = splitter.splitGraphemes(before)
const grapheme = graphemes[graphemes.length - 1]
const segments = [...segmenter.segment(before)]
const segment = segments[segments.length - 1]

return grapheme
return segment.segment
}

interface GraphemeProblem {
Expand All @@ -95,14 +94,13 @@ function getGraphemeProblems(
element.type === "ClassStringDisjunction",
)

const graphemes = splitter.splitGraphemes(cc.raw.slice(offset, -1))
const problems: GraphemeProblem[] = []

for (const grapheme of graphemes) {
const problem = getProblem(grapheme, flags)
for (const { segment } of segmenter.segment(cc.raw.slice(offset, -1))) {
const problem = getProblem(segment, flags)
if (problem !== null) {
const start = offset + cc.start
const end = start + grapheme.length
const end = start + segment.length

if (
ignoreElements.some(
Expand All @@ -113,7 +111,7 @@ function getGraphemeProblems(
}

problems.push({
grapheme,
grapheme: segment,
problem,
start,
end,
Expand All @@ -122,7 +120,7 @@ function getGraphemeProblems(
),
})
}
offset += grapheme.length
offset += segment.length
}

return problems
Expand Down
7 changes: 7 additions & 0 deletions lib/utils/extract-capturing-group-references.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,13 @@ const WELL_KNOWN_ARRAY_METHODS: {
flat: {},
// ES2022
at: { result: "element" },
// ES2023
findLast: { elementParameters: [0], result: "element" },
findLastIndex: { elementParameters: [0] },
toReversed: { result: "array" },
toSorted: { elementParameters: [0, 1], result: "array" },
toSpliced: { result: "array" },
with: { result: "array" },
}

/**
Expand Down
7 changes: 7 additions & 0 deletions lib/utils/type-tracker/type-data/array.ts
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,13 @@ const getPrototypes = cache(() => {
flat: RETURN_UNKNOWN_ARRAY,
// ES2022
at: RETURN_ARRAY_ELEMENT, // element
// ES2023
findLast: RETURN_ARRAY_ELEMENT, // element
findLastIndex: RETURN_NUMBER,
toReversed: RETURN_SELF,
toSorted: RETURN_SELF,
toSpliced: RETURN_SELF,
with: RETURN_SELF,

length: NUMBER,
0: null, // element
Expand Down
2 changes: 2 additions & 0 deletions lib/utils/type-tracker/type-data/object.ts
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,8 @@ export function buildObjectConstructor(): TypeGlobalFunction {
getOwnPropertyDescriptors: null,
// ES2019
fromEntries: null,
// ES2022
hasOwn: RETURN_BOOLEAN,

prototype: null,
})
Expand Down
2 changes: 2 additions & 0 deletions lib/utils/type-tracker/type-data/regexp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ const getPrototypes: () => {
unicode: BOOLEAN, // prop
// ES2018
dotAll: BOOLEAN, // prop
// ES2022
hasIndices: BOOLEAN, // prop

[Symbol.match]: null,
[Symbol.replace]: null,
Expand Down
4 changes: 3 additions & 1 deletion lib/utils/type-tracker/type-data/string.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ const getPrototypes: () => {
trim: RETURN_STRING,
substr: RETURN_STRING,
valueOf: RETURN_STRING,
// ES2051
// ES2015
codePointAt: RETURN_NUMBER,
includes: RETURN_BOOLEAN,
endsWith: RETURN_BOOLEAN,
Expand Down Expand Up @@ -128,6 +128,8 @@ const getPrototypes: () => {
trimEnd: RETURN_STRING,
// ES2020
matchAll: null, // IterableIterator<RegExpMatchArray>
// ES2021
replaceAll: RETURN_STRING,
// ES2022
at: RETURN_STRING,

Expand Down
11 changes: 6 additions & 5 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,6 @@
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.9.1",
"comment-parser": "^1.4.0",
"grapheme-splitter": "^1.0.4",
"jsdoctypeparser": "^9.0.0",
"refa": "^0.12.1",
"regexp-ast-analysis": "^0.7.1",
Expand Down
2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"target": "es2015",
"module": "Node16",
"moduleResolution": "Node16",
"lib": ["es2020"],
"lib": ["es2023"],
"allowJs": true,
"checkJs": true,
"outDir": "./dist",
Expand Down