Skip to content

Commit 0aeedd2

Browse files
committed
cleanup build, use tsc
1 parent 9712324 commit 0aeedd2

File tree

12 files changed

+1110
-811
lines changed

12 files changed

+1110
-811
lines changed

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,6 @@ npm-debug.log
55
libpg_query/**/*.proto
66
wasm/libpg-query.js
77
*.wasm
8-
.cache
8+
.cache
9+
esm/
10+
cjs/

package.json

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,9 @@
2121
}
2222
},
2323
"scripts": {
24-
"clean": "yarn wasm:clean",
25-
"build": "yarn wasm:clean && yarn wasm:build",
24+
"clean": "yarn wasm:clean && rimraf cjs esm",
25+
"build:js": "node scripts/build.js",
26+
"build": "yarn clean; yarn wasm:build; yarn build:js",
2627
"wasm:make": "docker run --rm -v $(pwd):/src -u $(id -u):$(id -g) emscripten/emsdk emmake make",
2728
"wasm:build": "yarn wasm:make build",
2829
"wasm:rebuild": "yarn wasm:make rebuild",
@@ -43,7 +44,8 @@
4344
"@yamlize/cli": "^0.8.0",
4445
"chai": "^3.5.0",
4546
"mocha": "^5.2.0",
46-
"rimraf": "5.0.0"
47+
"rimraf": "5.0.0",
48+
"typescript": "^5.3.3"
4749
},
4850
"dependencies": {
4951
"@pgsql/types": "^17.0.0",

scripts/build.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
const fs = require('fs');
2+
const path = require('path');
3+
const { execSync } = require('child_process');
4+
5+
// Run TypeScript compilation
6+
console.log('Compiling TypeScript...');
7+
execSync('tsc', { stdio: 'inherit' });
8+
execSync('tsc -p tsconfig.esm.json', { stdio: 'inherit' });
9+
10+
// Rename files to have correct extensions
11+
const wasmDir = path.join(__dirname, '../wasm');
12+
const cjsDir = path.join(__dirname, '../cjs');
13+
const esmDir = path.join(__dirname, '../esm');
14+
15+
// Rename CommonJS files
16+
fs.renameSync(
17+
path.join(cjsDir, 'index.js'),
18+
path.join(wasmDir, 'index.cjs')
19+
);
20+
21+
// Rename ESM files
22+
fs.renameSync(
23+
path.join(esmDir, 'index.js'),
24+
path.join(wasmDir, 'index.js')
25+
);
26+
27+
// Rename declaration files
28+
fs.renameSync(
29+
path.join(cjsDir, 'index.d.ts'),
30+
path.join(wasmDir, 'index.d.ts')
31+
);
32+
33+
console.log('Build completed successfully!');

src/index.ts

Lines changed: 299 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,299 @@
1+
import { ParseResult } from "@pgsql/types";
2+
export * from "@pgsql/types";
3+
4+
// @ts-ignore
5+
import PgQueryModule from './libpg-query.js';
6+
// @ts-ignore
7+
import { pg_query } from '../proto.js';
8+
9+
interface WasmModule {
10+
_malloc: (size: number) => number;
11+
_free: (ptr: number) => void;
12+
_wasm_free_string: (ptr: number) => void;
13+
_wasm_parse_query: (queryPtr: number) => number;
14+
_wasm_deparse_protobuf: (dataPtr: number, length: number) => number;
15+
_wasm_parse_plpgsql: (queryPtr: number) => number;
16+
_wasm_fingerprint: (queryPtr: number) => number;
17+
_wasm_normalize_query: (queryPtr: number) => number;
18+
lengthBytesUTF8: (str: string) => number;
19+
stringToUTF8: (str: string, ptr: number, len: number) => void;
20+
UTF8ToString: (ptr: number) => string;
21+
HEAPU8: Uint8Array;
22+
}
23+
24+
let wasmModule: WasmModule;
25+
26+
const initPromise = PgQueryModule().then((module: WasmModule) => {
27+
wasmModule = module;
28+
});
29+
30+
export async function loadModule(): Promise<void> {
31+
if (!wasmModule) {
32+
await initPromise;
33+
}
34+
}
35+
36+
function awaitInit<T extends (...args: any[]) => Promise<any>>(fn: T): T {
37+
return (async (...args: Parameters<T>) => {
38+
await initPromise;
39+
return fn(...args);
40+
}) as T;
41+
}
42+
43+
function stringToPtr(str: string): number {
44+
const len = wasmModule.lengthBytesUTF8(str) + 1;
45+
const ptr = wasmModule._malloc(len);
46+
try {
47+
wasmModule.stringToUTF8(str, ptr, len);
48+
return ptr;
49+
} catch (error) {
50+
wasmModule._free(ptr);
51+
throw error;
52+
}
53+
}
54+
55+
function ptrToString(ptr: number): string {
56+
return wasmModule.UTF8ToString(ptr);
57+
}
58+
59+
export const parseQuery = awaitInit(async (query: string): Promise<ParseResult> => {
60+
const queryPtr = stringToPtr(query);
61+
let resultPtr = 0;
62+
63+
try {
64+
resultPtr = wasmModule._wasm_parse_query(queryPtr);
65+
const resultStr = ptrToString(resultPtr);
66+
67+
if (resultStr.startsWith('syntax error') || resultStr.startsWith('deparse error') || resultStr.includes('ERROR')) {
68+
throw new Error(resultStr);
69+
}
70+
71+
return JSON.parse(resultStr);
72+
} finally {
73+
wasmModule._free(queryPtr);
74+
if (resultPtr) {
75+
wasmModule._wasm_free_string(resultPtr);
76+
}
77+
}
78+
});
79+
80+
export const deparse = awaitInit(async (parseTree: ParseResult): Promise<string> => {
81+
if (!parseTree || typeof parseTree !== 'object' || !Array.isArray(parseTree.stmts) || parseTree.stmts.length === 0) {
82+
throw new Error('No parseTree provided');
83+
}
84+
85+
const msg = pg_query.ParseResult.fromObject(parseTree);
86+
const data = pg_query.ParseResult.encode(msg).finish();
87+
88+
const dataPtr = wasmModule._malloc(data.length);
89+
let resultPtr = 0;
90+
91+
try {
92+
wasmModule.HEAPU8.set(data, dataPtr);
93+
resultPtr = wasmModule._wasm_deparse_protobuf(dataPtr, data.length);
94+
const resultStr = ptrToString(resultPtr);
95+
96+
if (resultStr.startsWith('syntax error') || resultStr.startsWith('deparse error') || resultStr.includes('ERROR')) {
97+
throw new Error(resultStr);
98+
}
99+
100+
return resultStr;
101+
} finally {
102+
wasmModule._free(dataPtr);
103+
if (resultPtr) {
104+
wasmModule._wasm_free_string(resultPtr);
105+
}
106+
}
107+
});
108+
109+
export const parsePlPgSQL = awaitInit(async (query: string): Promise<ParseResult> => {
110+
const queryPtr = stringToPtr(query);
111+
let resultPtr = 0;
112+
113+
try {
114+
resultPtr = wasmModule._wasm_parse_plpgsql(queryPtr);
115+
const resultStr = ptrToString(resultPtr);
116+
117+
if (resultStr.startsWith('syntax error') || resultStr.startsWith('deparse error') || resultStr.includes('ERROR')) {
118+
throw new Error(resultStr);
119+
}
120+
121+
return JSON.parse(resultStr);
122+
} finally {
123+
wasmModule._free(queryPtr);
124+
if (resultPtr) {
125+
wasmModule._wasm_free_string(resultPtr);
126+
}
127+
}
128+
});
129+
130+
export const fingerprint = awaitInit(async (query: string): Promise<string> => {
131+
const queryPtr = stringToPtr(query);
132+
let resultPtr = 0;
133+
134+
try {
135+
resultPtr = wasmModule._wasm_fingerprint(queryPtr);
136+
const resultStr = ptrToString(resultPtr);
137+
138+
if (resultStr.startsWith('syntax error') || resultStr.startsWith('deparse error') || resultStr.includes('ERROR')) {
139+
throw new Error(resultStr);
140+
}
141+
142+
return resultStr;
143+
} finally {
144+
wasmModule._free(queryPtr);
145+
if (resultPtr) {
146+
wasmModule._wasm_free_string(resultPtr);
147+
}
148+
}
149+
});
150+
151+
export const normalize = awaitInit(async (query: string): Promise<string> => {
152+
const queryPtr = stringToPtr(query);
153+
let resultPtr = 0;
154+
155+
try {
156+
resultPtr = wasmModule._wasm_normalize_query(queryPtr);
157+
const resultStr = ptrToString(resultPtr);
158+
159+
if (resultStr.startsWith('syntax error') || resultStr.startsWith('deparse error') || resultStr.includes('ERROR')) {
160+
throw new Error(resultStr);
161+
}
162+
163+
return resultStr;
164+
} finally {
165+
wasmModule._free(queryPtr);
166+
if (resultPtr) {
167+
wasmModule._wasm_free_string(resultPtr);
168+
}
169+
}
170+
});
171+
172+
// Sync versions
173+
export function parseQuerySync(query: string): ParseResult {
174+
if (!wasmModule) {
175+
throw new Error('WASM module not initialized. Call loadModule() first.');
176+
}
177+
const queryPtr = stringToPtr(query);
178+
let resultPtr = 0;
179+
180+
try {
181+
resultPtr = wasmModule._wasm_parse_query(queryPtr);
182+
const resultStr = ptrToString(resultPtr);
183+
184+
if (resultStr.startsWith('syntax error') || resultStr.startsWith('deparse error') || resultStr.includes('ERROR')) {
185+
throw new Error(resultStr);
186+
}
187+
188+
return JSON.parse(resultStr);
189+
} finally {
190+
wasmModule._free(queryPtr);
191+
if (resultPtr) {
192+
wasmModule._wasm_free_string(resultPtr);
193+
}
194+
}
195+
}
196+
197+
export function deparseSync(parseTree: ParseResult): string {
198+
if (!wasmModule) {
199+
throw new Error('WASM module not initialized. Call loadModule() first.');
200+
}
201+
if (!parseTree || typeof parseTree !== 'object' || !Array.isArray(parseTree.stmts) || parseTree.stmts.length === 0) {
202+
throw new Error('No parseTree provided');
203+
}
204+
205+
const msg = pg_query.ParseResult.fromObject(parseTree);
206+
const data = pg_query.ParseResult.encode(msg).finish();
207+
208+
const dataPtr = wasmModule._malloc(data.length);
209+
let resultPtr = 0;
210+
211+
try {
212+
wasmModule.HEAPU8.set(data, dataPtr);
213+
resultPtr = wasmModule._wasm_deparse_protobuf(dataPtr, data.length);
214+
const resultStr = ptrToString(resultPtr);
215+
216+
if (resultStr.startsWith('syntax error') || resultStr.startsWith('deparse error') || resultStr.includes('ERROR')) {
217+
throw new Error(resultStr);
218+
}
219+
220+
return resultStr;
221+
} finally {
222+
wasmModule._free(dataPtr);
223+
if (resultPtr) {
224+
wasmModule._wasm_free_string(resultPtr);
225+
}
226+
}
227+
}
228+
229+
export function parsePlPgSQLSync(query: string): ParseResult {
230+
if (!wasmModule) {
231+
throw new Error('WASM module not initialized. Call loadModule() first.');
232+
}
233+
const queryPtr = stringToPtr(query);
234+
let resultPtr = 0;
235+
236+
try {
237+
resultPtr = wasmModule._wasm_parse_plpgsql(queryPtr);
238+
const resultStr = ptrToString(resultPtr);
239+
240+
if (resultStr.startsWith('syntax error') || resultStr.startsWith('deparse error') || resultStr.includes('ERROR')) {
241+
throw new Error(resultStr);
242+
}
243+
244+
return JSON.parse(resultStr);
245+
} finally {
246+
wasmModule._free(queryPtr);
247+
if (resultPtr) {
248+
wasmModule._wasm_free_string(resultPtr);
249+
}
250+
}
251+
}
252+
253+
export function fingerprintSync(query: string): string {
254+
if (!wasmModule) {
255+
throw new Error('WASM module not initialized. Call loadModule() first.');
256+
}
257+
const queryPtr = stringToPtr(query);
258+
let resultPtr = 0;
259+
260+
try {
261+
resultPtr = wasmModule._wasm_fingerprint(queryPtr);
262+
const resultStr = ptrToString(resultPtr);
263+
264+
if (resultStr.startsWith('syntax error') || resultStr.startsWith('deparse error') || resultStr.includes('ERROR')) {
265+
throw new Error(resultStr);
266+
}
267+
268+
return resultStr;
269+
} finally {
270+
wasmModule._free(queryPtr);
271+
if (resultPtr) {
272+
wasmModule._wasm_free_string(resultPtr);
273+
}
274+
}
275+
}
276+
277+
export function normalizeSync(query: string): string {
278+
if (!wasmModule) {
279+
throw new Error('WASM module not initialized. Call loadModule() first.');
280+
}
281+
const queryPtr = stringToPtr(query);
282+
let resultPtr = 0;
283+
284+
try {
285+
resultPtr = wasmModule._wasm_normalize_query(queryPtr);
286+
const resultStr = ptrToString(resultPtr);
287+
288+
if (resultStr.startsWith('syntax error') || resultStr.startsWith('deparse error') || resultStr.includes('ERROR')) {
289+
throw new Error(resultStr);
290+
}
291+
292+
return resultStr;
293+
} finally {
294+
wasmModule._free(queryPtr);
295+
if (resultPtr) {
296+
wasmModule._wasm_free_string(resultPtr);
297+
}
298+
}
299+
}

src/libpg-query.d.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
declare module './libpg-query.js' {
2+
interface WasmModule {
3+
_malloc: (size: number) => number;
4+
_free: (ptr: number) => void;
5+
_wasm_free_string: (ptr: number) => void;
6+
_wasm_parse_query: (queryPtr: number) => number;
7+
_wasm_deparse_protobuf: (dataPtr: number, length: number) => number;
8+
_wasm_parse_plpgsql: (queryPtr: number) => number;
9+
_wasm_fingerprint: (queryPtr: number) => number;
10+
_wasm_normalize_query: (queryPtr: number) => number;
11+
lengthBytesUTF8: (str: string) => number;
12+
stringToUTF8: (str: string, ptr: number, len: number) => void;
13+
UTF8ToString: (ptr: number) => string;
14+
HEAPU8: Uint8Array;
15+
}
16+
17+
const PgQueryModule: () => Promise<WasmModule>;
18+
export default PgQueryModule;
19+
}

0 commit comments

Comments
 (0)