yuku 0.2.0 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<!-- markdownlint-disable first-line-h1 -->
|
|
2
|
+
|
|
3
|
+
<!-- markdownlint-start-capture -->
|
|
4
|
+
<!-- markdownlint-disable-file no-inline-html -->
|
|
5
|
+
<div align="center">
|
|
6
|
+
|
|
7
|
+
<!-- markdownlint-disable-next-line no-alt-text -->
|
|
8
|
+
<img src="/assets/logo.svg" alt="Logo" width="300" />
|
|
9
|
+
|
|
10
|
+
[](https://npmjs.com/package/yuku)
|
|
11
|
+
[](https://github.com/sponsors/arshad-yaseen)
|
|
12
|
+
|
|
13
|
+
A very fast JavaScript/TypeScript parser written in Zig to enable JavaScript tooling in Zig.
|
|
14
|
+
|
|
15
|
+
</div>
|
|
16
|
+
|
|
17
|
+
<br/>
|
|
18
|
+
|
|
19
|
+
- Full ECMAScript spec compliance
|
|
20
|
+
- Very fast, built with performance in mind from the start, competitive with established parsers like Oxc.
|
|
21
|
+
- Robust error recovery, partial ASTs on recoverable errors.
|
|
22
|
+
- Rich features, including JSX and TypeScript support.
|
|
23
|
+
- Can output 100% ESTree + TypeScript-ESTree compliant AST when needed.
|
|
24
|
+
|
|
25
|
+
<br/>
|
|
@@ -17,7 +17,11 @@ interface YukuNode {
|
|
|
17
17
|
type: string;
|
|
18
18
|
[key: string]: unknown;
|
|
19
19
|
}
|
|
20
|
-
type YukuAST =
|
|
20
|
+
type YukuAST = {
|
|
21
|
+
program: YukuNode[];
|
|
22
|
+
errors: Record<string, unknown>[];
|
|
23
|
+
comments: Record<string, unknown>[];
|
|
24
|
+
};
|
|
21
25
|
/**
|
|
22
26
|
* Parse JavaScript/TypeScript source code into a Yuku AST.
|
|
23
27
|
*
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
//
|
|
1
|
+
// npm/browser.ts
|
|
2
2
|
var SourceType;
|
|
3
3
|
((SourceType2) => {
|
|
4
4
|
SourceType2[SourceType2["Script"] = 0] = "Script";
|
|
@@ -16,31 +16,43 @@ var wasmInstance = null;
|
|
|
16
16
|
async function getWasmInstance() {
|
|
17
17
|
if (wasmInstance)
|
|
18
18
|
return wasmInstance;
|
|
19
|
-
const
|
|
20
|
-
const wasmBuffer = await fetch(wasmUrl).then((r) => r.arrayBuffer());
|
|
21
|
-
const wasmModule = await WebAssembly.instantiate(wasmBuffer);
|
|
19
|
+
const wasmModule = await WebAssembly.instantiateStreaming(fetch(new URL("./yuku.wasm", import.meta.url)));
|
|
22
20
|
wasmInstance = wasmModule.instance.exports;
|
|
23
21
|
return wasmInstance;
|
|
24
22
|
}
|
|
25
|
-
|
|
26
|
-
const
|
|
23
|
+
function readLengthPrefixedData(memory, ptr) {
|
|
24
|
+
const view = new DataView(memory.buffer);
|
|
25
|
+
const length = view.getUint32(ptr, true);
|
|
26
|
+
const dataPtr = ptr + 4;
|
|
27
|
+
return { length, dataPtr };
|
|
28
|
+
}
|
|
29
|
+
function parseInternal(wasm, source, options) {
|
|
27
30
|
const encoder = new TextEncoder;
|
|
28
31
|
const sourceBytes = encoder.encode(source);
|
|
29
32
|
const sourceLen = sourceBytes.length;
|
|
30
|
-
const sourcePtr = wasm.alloc(sourceLen);
|
|
31
|
-
if (!sourcePtr) {
|
|
33
|
+
const sourcePtr = sourceLen > 0 ? wasm.alloc(sourceLen) : 0;
|
|
34
|
+
if (sourceLen > 0 && !sourcePtr) {
|
|
32
35
|
throw new Error("Failed to allocate memory for source code");
|
|
33
36
|
}
|
|
34
37
|
try {
|
|
35
|
-
|
|
36
|
-
|
|
38
|
+
if (sourceLen > 0 && sourcePtr) {
|
|
39
|
+
const wasmMemory = new Uint8Array(wasm.memory.buffer, sourcePtr, sourceLen);
|
|
40
|
+
wasmMemory.set(sourceBytes);
|
|
41
|
+
}
|
|
37
42
|
const sourceType = normalizeSourceType(options.sourceType);
|
|
38
43
|
const lang = normalizeLang(options.lang);
|
|
39
44
|
const resultPtr = wasm.parse(sourcePtr, sourceLen, sourceType, lang);
|
|
40
45
|
if (resultPtr === 0) {
|
|
41
46
|
throw new Error("Failed to parse source code");
|
|
42
47
|
}
|
|
48
|
+
if (!Number.isInteger(resultPtr) || resultPtr < 0 || resultPtr >= wasm.memory.buffer.byteLength || resultPtr + 4 > wasm.memory.buffer.byteLength) {
|
|
49
|
+
throw new Error("Invalid result pointer from WASM parser");
|
|
50
|
+
}
|
|
43
51
|
const { length: jsonLen, dataPtr: jsonDataPtr } = readLengthPrefixedData(wasm.memory, resultPtr);
|
|
52
|
+
if (!Number.isInteger(jsonDataPtr) || jsonDataPtr < 0 || jsonDataPtr >= wasm.memory.buffer.byteLength || jsonDataPtr + jsonLen > wasm.memory.buffer.byteLength) {
|
|
53
|
+
wasm.free(resultPtr, jsonLen + 4);
|
|
54
|
+
throw new Error("Invalid result pointer from WASM parser");
|
|
55
|
+
}
|
|
44
56
|
try {
|
|
45
57
|
const decoder = new TextDecoder;
|
|
46
58
|
const jsonBytes = new Uint8Array(wasm.memory.buffer, jsonDataPtr, jsonLen);
|
|
@@ -50,42 +62,23 @@ async function parse(source, options = {}) {
|
|
|
50
62
|
wasm.free(resultPtr, jsonLen + 4);
|
|
51
63
|
}
|
|
52
64
|
} finally {
|
|
53
|
-
|
|
65
|
+
if (sourceLen > 0 && sourcePtr) {
|
|
66
|
+
wasm.free(sourcePtr, sourceLen);
|
|
67
|
+
}
|
|
54
68
|
}
|
|
55
69
|
}
|
|
70
|
+
async function parse(source, options = {}) {
|
|
71
|
+
const wasm = await getWasmInstance();
|
|
72
|
+
return parseInternal(wasm, source, options);
|
|
73
|
+
}
|
|
56
74
|
function parseSync(source, options = {}) {
|
|
57
75
|
if (!wasmInstance) {
|
|
58
76
|
throw new Error("WASM not loaded. Call parse() first or manually call preload()");
|
|
59
77
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
const sourcePtr = wasm.alloc(sourceLen);
|
|
65
|
-
if (!sourcePtr) {
|
|
66
|
-
throw new Error("Failed to allocate memory for source code");
|
|
67
|
-
}
|
|
68
|
-
try {
|
|
69
|
-
const wasmMemory = new Uint8Array(wasm.memory.buffer, sourcePtr, sourceLen);
|
|
70
|
-
wasmMemory.set(sourceBytes);
|
|
71
|
-
const sourceType = normalizeSourceType(options.sourceType);
|
|
72
|
-
const lang = normalizeLang(options.lang);
|
|
73
|
-
const resultPtr = wasm.parse(sourcePtr, sourceLen, sourceType, lang);
|
|
74
|
-
if (resultPtr === 0) {
|
|
75
|
-
throw new Error("Failed to parse source code");
|
|
76
|
-
}
|
|
77
|
-
const { length: jsonLen, dataPtr: jsonDataPtr } = readLengthPrefixedData(wasm.memory, resultPtr);
|
|
78
|
-
try {
|
|
79
|
-
const decoder = new TextDecoder;
|
|
80
|
-
const jsonBytes = new Uint8Array(wasm.memory.buffer, jsonDataPtr, jsonLen);
|
|
81
|
-
const jsonStr = decoder.decode(jsonBytes);
|
|
82
|
-
return JSON.parse(jsonStr);
|
|
83
|
-
} finally {
|
|
84
|
-
wasm.free(resultPtr, jsonLen + 4);
|
|
85
|
-
}
|
|
86
|
-
} finally {
|
|
87
|
-
wasm.free(sourcePtr, sourceLen);
|
|
88
|
-
}
|
|
78
|
+
return parseInternal(wasmInstance, source, options);
|
|
79
|
+
}
|
|
80
|
+
async function preload() {
|
|
81
|
+
await getWasmInstance();
|
|
89
82
|
}
|
|
90
83
|
function normalizeSourceType(sourceType) {
|
|
91
84
|
return sourceType === "script" ? 0 /* Script */ : 1 /* Module */;
|
|
@@ -104,15 +97,6 @@ function normalizeLang(lang) {
|
|
|
104
97
|
return 0 /* JS */;
|
|
105
98
|
}
|
|
106
99
|
}
|
|
107
|
-
function readLengthPrefixedData(memory, ptr) {
|
|
108
|
-
const view = new DataView(memory.buffer);
|
|
109
|
-
const length = view.getUint32(ptr, true);
|
|
110
|
-
const dataPtr = ptr + 4;
|
|
111
|
-
return { length, dataPtr };
|
|
112
|
-
}
|
|
113
|
-
async function preload() {
|
|
114
|
-
await getWasmInstance();
|
|
115
|
-
}
|
|
116
100
|
export {
|
|
117
101
|
preload,
|
|
118
102
|
parseSync,
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,37 +1,38 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "yuku",
|
|
3
3
|
"description": "A very fast JavaScript/TypeScript parser written in Zig",
|
|
4
|
-
"version": "0.2.
|
|
4
|
+
"version": "0.2.2",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
7
|
-
"dist"
|
|
7
|
+
"npm/dist"
|
|
8
8
|
],
|
|
9
9
|
"module": "./dist/index.js",
|
|
10
10
|
"types": "./dist/index.d.ts",
|
|
11
|
-
"browser": "./dist/browser.js",
|
|
12
11
|
"exports": {
|
|
13
12
|
".": {
|
|
14
|
-
"browser": {
|
|
15
|
-
"types": "./dist/browser.d.ts",
|
|
16
|
-
"import": "./dist/browser.js",
|
|
17
|
-
"default": "./dist/browser.js"
|
|
18
|
-
},
|
|
19
13
|
"import": {
|
|
20
14
|
"types": "./dist/index.d.ts",
|
|
21
15
|
"default": "./dist/index.js"
|
|
22
16
|
}
|
|
23
17
|
},
|
|
18
|
+
"./browser": {
|
|
19
|
+
"types": "./dist/browser.d.ts",
|
|
20
|
+
"default": "./dist/browser.js"
|
|
21
|
+
},
|
|
24
22
|
"./package.json": "./package.json"
|
|
25
23
|
},
|
|
26
24
|
"license": "MIT",
|
|
27
25
|
"scripts": {
|
|
28
26
|
"build": "bunup",
|
|
29
27
|
"dev": "bunup --watch",
|
|
30
|
-
"type-check": "tsc --noEmit"
|
|
28
|
+
"type-check": "tsc --noEmit",
|
|
29
|
+
"test": "zig build && bun run build && bun test/run.ts"
|
|
31
30
|
},
|
|
32
31
|
"devDependencies": {
|
|
33
32
|
"@types/bun": "^1.3.5",
|
|
34
33
|
"bunup": "^0.16.11",
|
|
34
|
+
"fast-deep-equal": "^3.1.3",
|
|
35
|
+
"jest-diff": "^30.2.0",
|
|
35
36
|
"typescript": "^5.9.3"
|
|
36
37
|
},
|
|
37
38
|
"peerDependencies": {
|
|
File without changes
|