дзеркало
https://github.com/l0ng-ai/openidea.git
синхронізовано 2026-11-09 11:15:40 +02:00
fix: avoid lookbehind in application regexes for older WebKit
Application regex lookbehind prevented older WebKit from loading the startup module graph. Replace lookbehind with boundary checks across run/terminal links, SQL aliases, debugger targets and refactoring; preserve Unicode boundaries, UTF-16 offsets and empty-match progress. Add compatibility and regression tests. Fixes #224 Refs #208
Цей коміт міститься в:
1 джерело
364bb5ef50
коміт
d37b96002b
10 files changed
+87
-10
No files matched your search
@@ -56,6 +56,16 @@ describe("locating Smart Step Into targets", () => {
|
||||
expect(locateStepTargets(line, 3, [target(1, "missing()")])).toBeNull();
|
||||
});
|
||||
|
||||
it("rejects identifier suffixes, preserving UTF-16 offsets and nested calls", () => {
|
||||
const line = "𐐀foo() αfoo() $foo() _foo() foo(foo())";
|
||||
const from = line.indexOf("foo(foo");
|
||||
expect(locateStepTargets(line, 0, [target(1, "foo()"), target(2, "foo()")])).toEqual([
|
||||
{ id: 1, from, to: from + 3 },
|
||||
{ id: 2, from: from + 4, to: from + 7 },
|
||||
]);
|
||||
expect(targetsOnLine("𐐀foo() bar()", 0, [target(1, "foo()"), target(2, "bar()")]).map((t) => t.id)).toEqual([2]);
|
||||
});
|
||||
|
||||
it("keeps only the paused line's calls when the adapter lists the whole function", () => {
|
||||
const line = " total = add(total, square(i))";
|
||||
const all = [target(0, "square(i)"), target(1, "add(total, square(i))"), target(2, 'print("total", total)')];
|
||||
|
||||
@@ -25,7 +25,11 @@ export function calleeName(label: string): string | null {
|
||||
|
||||
/** A call of `name`: `name(` not preceded by an identifier character. */
|
||||
function callPattern(name: string, flags: string): RegExp {
|
||||
return new RegExp(`(?<![\\p{L}\\p{N}_$])${name.replace(/\$/g, "\\$")}\\s*\\(`, flags);
|
||||
return new RegExp(`${name.replace(/\$/g, "\\$")}\\s*\\(`, flags);
|
||||
}
|
||||
|
||||
function isCallBoundary(text: string, from: number): boolean {
|
||||
return !/[\p{L}\p{N}_$]$/u.test(text.slice(Math.max(0, from - 2), from));
|
||||
}
|
||||
|
||||
function identifierEnd(text: string, from: number): number {
|
||||
@@ -55,7 +59,7 @@ export function locateStepTargets(lineText: string, line: number, targets: StepI
|
||||
const name = calleeName(t.label);
|
||||
if (!name) return null;
|
||||
for (const m of lineText.matchAll(callPattern(name, "gu"))) {
|
||||
if (used.has(m.index!)) continue;
|
||||
if (used.has(m.index!) || !isCallBoundary(lineText, m.index!)) continue;
|
||||
from = m.index!;
|
||||
to = from + name.length;
|
||||
break;
|
||||
@@ -78,7 +82,7 @@ export function targetsOnLine(lineText: string, line: number, targets: StepInTar
|
||||
if (t.line != null) return t.line === line;
|
||||
if (t.column != null) return true;
|
||||
const name = calleeName(t.label);
|
||||
return !name || callPattern(name, "u").test(lineText);
|
||||
return !name || [...lineText.matchAll(callPattern(name, "gu"))].some((m) => isCallBoundary(lineText, m.index));
|
||||
});
|
||||
return kept.length ? kept : targets;
|
||||
}
|
||||
|
||||
Reference in new issue
Заблокувати користувача