Skip to content

Commit e1ea118

Browse files
committed
fix: revert pnpm patch, use inline JSON fix for scanSync upstream bug
Instead of patching @libpg-query/parser via pnpm patch (which caused CI issues with pnpm v9/v10 lockfile incompatibility), handle the upstream JSON serialization bug inline in scanner.ts. The approach: try scanSync normally, and if it throws due to unescaped control characters in the JSON output, retry with a temporarily monkey-patched JSON.parse that escapes control chars before parsing. This is synchronous so there are no concurrency concerns. All 28 tests pass. No changes to lockfile format or workspace config.
1 parent 7f34e49 commit e1ea118

4 files changed

Lines changed: 45 additions & 52 deletions

File tree

package.json

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,6 @@
2323
"bump-versions": "ts-node scripts/bump-versions.ts",
2424
"update-workspace": "makage update-workspace"
2525
},
26-
"pnpm": {
27-
"patchedDependencies": {
28-
"@libpg-query/parser@17.6.3": "patches/@libpg-query__parser@17.6.3.patch"
29-
}
30-
},
3126
"devDependencies": {
3227
"@types/jest": "^30.0.0",
3328
"@types/node": "^20.12.7",

packages/parse/src/scanner.ts

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,50 @@
99
*
1010
* Note: @libpg-query/parser has an upstream JSON serialization bug in
1111
* _wasm_scan where literal control characters in token text are not
12-
* escaped. This is fixed via a pnpm patch (see patches/ directory).
12+
* escaped. We work around this by retrying with a patched JSON.parse
13+
* that escapes control characters before parsing.
1314
*/
1415

1516
import { scanSync, type ScanToken } from '@libpg-query/parser';
1617

18+
/**
19+
* Escape unescaped control characters inside JSON string values.
20+
* The upstream _wasm_scan emits raw \n, \r, \t in token text fields,
21+
* which breaks JSON.parse. This replaces them with their escape sequences.
22+
*/
23+
function fixScanJson(raw: string): string {
24+
return raw.replace(
25+
/"(?:[^"\\]|\\.)*"/g,
26+
(match) =>
27+
match
28+
.replace(/\t/g, '\\t')
29+
.replace(/\n/g, '\\n')
30+
.replace(/\r/g, '\\r')
31+
);
32+
}
33+
34+
/**
35+
* Call scanSync with a workaround for the upstream JSON serialization bug.
36+
* First tries the normal path; if JSON.parse throws, retries with a
37+
* temporarily patched JSON.parse that escapes control characters.
38+
* This is synchronous so there are no concurrency concerns.
39+
*/
40+
function safeScanSync(sql: string): { tokens: ScanToken[] } {
41+
try {
42+
return scanSync(sql);
43+
} catch {
44+
// Retry with patched JSON.parse to handle unescaped control chars
45+
const origParse = JSON.parse;
46+
try {
47+
JSON.parse = ((text: string, reviver?: Parameters<typeof JSON.parse>[1]) =>
48+
origParse(fixScanJson(text), reviver)) as typeof JSON.parse;
49+
return scanSync(sql);
50+
} finally {
51+
JSON.parse = origParse;
52+
}
53+
}
54+
}
55+
1756
/** Token type for -- line comments from PostgreSQL's lexer */
1857
const SQL_COMMENT = 275;
1958

@@ -66,7 +105,7 @@ export function scanComments(sql: string): ScannedElement[] {
66105

67106
let tokens: ScanToken[];
68107
try {
69-
const scanResult = scanSync(sql);
108+
const scanResult = safeScanSync(sql);
70109
tokens = scanResult.tokens;
71110
} catch {
72111
return [];

patches/@libpg-query__parser@17.6.3.patch

Lines changed: 0 additions & 36 deletions
This file was deleted.

pnpm-lock.yaml

Lines changed: 4 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)