binja 0.3.4 → 0.4.1
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 +70 -8
- package/dist/cli.js +417 -0
- package/dist/debug/index.js +678 -0
- package/dist/index.js +419 -2
- package/dist/lexer/hybrid.d.ts +13 -0
- package/dist/lexer/hybrid.d.ts.map +1 -0
- package/dist/lexer/index.d.ts +4 -0
- package/dist/lexer/index.d.ts.map +1 -1
- package/dist/native/index.d.ts +72 -0
- package/dist/native/index.d.ts.map +1 -0
- package/dist/native/index.js +252 -0
- package/native/darwin-arm64/libbinja.dylib +0 -0
- package/native/darwin-x64/libbinja.dylib +0 -0
- package/native/linux-arm64/libbinja.so +0 -0
- package/native/linux-x64/libbinja.so +0 -0
- package/package.json +19 -7
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// src/native/index.ts
|
|
3
|
+
import { dlopen, FFIType, ptr, CString } from "bun:ffi";
|
|
4
|
+
import { join } from "path";
|
|
5
|
+
import { existsSync } from "fs";
|
|
6
|
+
var TokenType = {
|
|
7
|
+
TEXT: 0,
|
|
8
|
+
VAR_START: 1,
|
|
9
|
+
VAR_END: 2,
|
|
10
|
+
BLOCK_START: 3,
|
|
11
|
+
BLOCK_END: 4,
|
|
12
|
+
COMMENT_START: 5,
|
|
13
|
+
COMMENT_END: 6,
|
|
14
|
+
IDENTIFIER: 7,
|
|
15
|
+
STRING: 8,
|
|
16
|
+
NUMBER: 9,
|
|
17
|
+
OPERATOR: 10,
|
|
18
|
+
DOT: 11,
|
|
19
|
+
COMMA: 12,
|
|
20
|
+
PIPE: 13,
|
|
21
|
+
COLON: 14,
|
|
22
|
+
LPAREN: 15,
|
|
23
|
+
RPAREN: 16,
|
|
24
|
+
LBRACKET: 17,
|
|
25
|
+
RBRACKET: 18,
|
|
26
|
+
LBRACE: 19,
|
|
27
|
+
RBRACE: 20,
|
|
28
|
+
ASSIGN: 21,
|
|
29
|
+
EOF: 22
|
|
30
|
+
};
|
|
31
|
+
var symbols = {
|
|
32
|
+
binja_lexer_new: {
|
|
33
|
+
args: [FFIType.ptr, FFIType.u64],
|
|
34
|
+
returns: FFIType.ptr
|
|
35
|
+
},
|
|
36
|
+
binja_lexer_free: {
|
|
37
|
+
args: [FFIType.ptr],
|
|
38
|
+
returns: FFIType.void
|
|
39
|
+
},
|
|
40
|
+
binja_lexer_token_count: {
|
|
41
|
+
args: [FFIType.ptr],
|
|
42
|
+
returns: FFIType.u64
|
|
43
|
+
},
|
|
44
|
+
binja_lexer_token_type: {
|
|
45
|
+
args: [FFIType.ptr, FFIType.u64],
|
|
46
|
+
returns: FFIType.u8
|
|
47
|
+
},
|
|
48
|
+
binja_lexer_token_start: {
|
|
49
|
+
args: [FFIType.ptr, FFIType.u64],
|
|
50
|
+
returns: FFIType.u32
|
|
51
|
+
},
|
|
52
|
+
binja_lexer_token_end: {
|
|
53
|
+
args: [FFIType.ptr, FFIType.u64],
|
|
54
|
+
returns: FFIType.u32
|
|
55
|
+
},
|
|
56
|
+
binja_lexer_has_error: {
|
|
57
|
+
args: [FFIType.ptr],
|
|
58
|
+
returns: FFIType.bool
|
|
59
|
+
},
|
|
60
|
+
binja_lexer_error_code: {
|
|
61
|
+
args: [FFIType.ptr],
|
|
62
|
+
returns: FFIType.u8
|
|
63
|
+
},
|
|
64
|
+
binja_lexer_error_line: {
|
|
65
|
+
args: [FFIType.ptr],
|
|
66
|
+
returns: FFIType.u32
|
|
67
|
+
},
|
|
68
|
+
binja_tokenize_count: {
|
|
69
|
+
args: [FFIType.ptr, FFIType.u64],
|
|
70
|
+
returns: FFIType.u64
|
|
71
|
+
},
|
|
72
|
+
binja_version: {
|
|
73
|
+
args: [],
|
|
74
|
+
returns: FFIType.ptr
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
var _lib = null;
|
|
78
|
+
var _loadAttempted = false;
|
|
79
|
+
var _nativeAvailable = false;
|
|
80
|
+
function getLibraryPath() {
|
|
81
|
+
const platform = process.platform;
|
|
82
|
+
const arch = process.arch;
|
|
83
|
+
const libExt = platform === "darwin" ? "dylib" : platform === "win32" ? "dll" : "so";
|
|
84
|
+
const libName = `libbinja.${libExt}`;
|
|
85
|
+
const projectRoot = join(import.meta.dir, "..", "..");
|
|
86
|
+
const searchPaths = [
|
|
87
|
+
join(projectRoot, "native", `${platform}-${arch}`, libName),
|
|
88
|
+
join(projectRoot, "native", libName),
|
|
89
|
+
join(projectRoot, "zig-native", "zig-out", "lib", libName),
|
|
90
|
+
join(projectRoot, "zig-native", libName),
|
|
91
|
+
join(import.meta.dir, libName)
|
|
92
|
+
];
|
|
93
|
+
for (const p of searchPaths) {
|
|
94
|
+
if (existsSync(p)) {
|
|
95
|
+
return p;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
function loadLibrary() {
|
|
101
|
+
if (_loadAttempted) {
|
|
102
|
+
return _lib;
|
|
103
|
+
}
|
|
104
|
+
_loadAttempted = true;
|
|
105
|
+
const libPath = getLibraryPath();
|
|
106
|
+
if (!libPath) {
|
|
107
|
+
console.warn("[binja] Native library not found, using pure JS fallback");
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
try {
|
|
111
|
+
_lib = dlopen(libPath, symbols);
|
|
112
|
+
_nativeAvailable = true;
|
|
113
|
+
return _lib;
|
|
114
|
+
} catch (e) {
|
|
115
|
+
console.warn(`[binja] Failed to load native library: ${e}`);
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
function isNativeAvailable() {
|
|
120
|
+
loadLibrary();
|
|
121
|
+
return _nativeAvailable;
|
|
122
|
+
}
|
|
123
|
+
function nativeVersion() {
|
|
124
|
+
const lib = loadLibrary();
|
|
125
|
+
if (!lib)
|
|
126
|
+
return null;
|
|
127
|
+
const versionPtr = lib.symbols.binja_version();
|
|
128
|
+
if (!versionPtr)
|
|
129
|
+
return null;
|
|
130
|
+
return new CString(versionPtr).toString();
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
class NativeLexer {
|
|
134
|
+
lexerPtr = 0;
|
|
135
|
+
source;
|
|
136
|
+
sourceBuffer;
|
|
137
|
+
lib;
|
|
138
|
+
_tokenCount = 0;
|
|
139
|
+
_isEmpty = false;
|
|
140
|
+
constructor(source) {
|
|
141
|
+
const lib = loadLibrary();
|
|
142
|
+
if (!lib) {
|
|
143
|
+
throw new Error("Native library not available. Use isNativeAvailable() to check first.");
|
|
144
|
+
}
|
|
145
|
+
this.lib = lib;
|
|
146
|
+
this.source = source;
|
|
147
|
+
if (source.length === 0) {
|
|
148
|
+
this._isEmpty = true;
|
|
149
|
+
this._tokenCount = 1;
|
|
150
|
+
this.sourceBuffer = new Uint8Array(0);
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
this.sourceBuffer = new TextEncoder().encode(source);
|
|
154
|
+
const result = this.lib.symbols.binja_lexer_new(ptr(this.sourceBuffer), this.sourceBuffer.length);
|
|
155
|
+
if (!result) {
|
|
156
|
+
throw new Error("Failed to create native lexer");
|
|
157
|
+
}
|
|
158
|
+
this.lexerPtr = result;
|
|
159
|
+
this._tokenCount = Number(this.lib.symbols.binja_lexer_token_count(this.lexerPtr));
|
|
160
|
+
}
|
|
161
|
+
get tokenCount() {
|
|
162
|
+
return this._tokenCount;
|
|
163
|
+
}
|
|
164
|
+
getTokenType(index) {
|
|
165
|
+
if (this._isEmpty)
|
|
166
|
+
return TokenType.EOF;
|
|
167
|
+
return Number(this.lib.symbols.binja_lexer_token_type(this.lexerPtr, index));
|
|
168
|
+
}
|
|
169
|
+
getTokenStart(index) {
|
|
170
|
+
if (this._isEmpty)
|
|
171
|
+
return 0;
|
|
172
|
+
return Number(this.lib.symbols.binja_lexer_token_start(this.lexerPtr, index));
|
|
173
|
+
}
|
|
174
|
+
getTokenEnd(index) {
|
|
175
|
+
if (this._isEmpty)
|
|
176
|
+
return 0;
|
|
177
|
+
return Number(this.lib.symbols.binja_lexer_token_end(this.lexerPtr, index));
|
|
178
|
+
}
|
|
179
|
+
hasError() {
|
|
180
|
+
if (this._isEmpty)
|
|
181
|
+
return false;
|
|
182
|
+
return Boolean(this.lib.symbols.binja_lexer_has_error(this.lexerPtr));
|
|
183
|
+
}
|
|
184
|
+
getErrorCode() {
|
|
185
|
+
if (this._isEmpty)
|
|
186
|
+
return 0;
|
|
187
|
+
return Number(this.lib.symbols.binja_lexer_error_code(this.lexerPtr));
|
|
188
|
+
}
|
|
189
|
+
getErrorLine() {
|
|
190
|
+
if (this._isEmpty)
|
|
191
|
+
return 1;
|
|
192
|
+
return Number(this.lib.symbols.binja_lexer_error_line(this.lexerPtr));
|
|
193
|
+
}
|
|
194
|
+
getTokenValue(index) {
|
|
195
|
+
if (this._isEmpty)
|
|
196
|
+
return "";
|
|
197
|
+
const start = this.getTokenStart(index);
|
|
198
|
+
const end = this.getTokenEnd(index);
|
|
199
|
+
return new TextDecoder().decode(this.sourceBuffer.slice(start, end));
|
|
200
|
+
}
|
|
201
|
+
getToken(index) {
|
|
202
|
+
return {
|
|
203
|
+
type: this.getTokenType(index),
|
|
204
|
+
start: this.getTokenStart(index),
|
|
205
|
+
end: this.getTokenEnd(index),
|
|
206
|
+
value: this.getTokenValue(index)
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
getAllTokens() {
|
|
210
|
+
const tokens = [];
|
|
211
|
+
for (let i = 0;i < this._tokenCount; i++) {
|
|
212
|
+
tokens.push(this.getToken(i));
|
|
213
|
+
}
|
|
214
|
+
return tokens;
|
|
215
|
+
}
|
|
216
|
+
free() {
|
|
217
|
+
if (this.lexerPtr) {
|
|
218
|
+
this.lib.symbols.binja_lexer_free(this.lexerPtr);
|
|
219
|
+
this.lexerPtr = null;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
[Symbol.dispose]() {
|
|
223
|
+
this.free();
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
function tokenizeCount(source) {
|
|
227
|
+
if (source.length === 0) {
|
|
228
|
+
return 1;
|
|
229
|
+
}
|
|
230
|
+
const lib = loadLibrary();
|
|
231
|
+
if (!lib) {
|
|
232
|
+
throw new Error("Native library not available");
|
|
233
|
+
}
|
|
234
|
+
const bytes = new TextEncoder().encode(source);
|
|
235
|
+
return Number(lib.symbols.binja_tokenize_count(ptr(bytes), bytes.length));
|
|
236
|
+
}
|
|
237
|
+
function tokenize(source) {
|
|
238
|
+
const lexer = new NativeLexer(source);
|
|
239
|
+
try {
|
|
240
|
+
return lexer.getAllTokens();
|
|
241
|
+
} finally {
|
|
242
|
+
lexer.free();
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
export {
|
|
246
|
+
tokenizeCount,
|
|
247
|
+
tokenize,
|
|
248
|
+
nativeVersion,
|
|
249
|
+
isNativeAvailable,
|
|
250
|
+
TokenType,
|
|
251
|
+
NativeLexer
|
|
252
|
+
};
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "binja",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "High-performance Jinja2/Django template engine for Bun",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.js",
|
|
@@ -15,6 +15,12 @@
|
|
|
15
15
|
"types": "./dist/index.d.ts",
|
|
16
16
|
"bun": "./dist/index.js"
|
|
17
17
|
},
|
|
18
|
+
"./native": {
|
|
19
|
+
"import": "./dist/native/index.js",
|
|
20
|
+
"require": "./dist/native/index.js",
|
|
21
|
+
"types": "./dist/native/index.d.ts",
|
|
22
|
+
"bun": "./dist/native/index.js"
|
|
23
|
+
},
|
|
18
24
|
"./debug": {
|
|
19
25
|
"import": "./dist/debug/index.js",
|
|
20
26
|
"require": "./dist/debug/index.js",
|
|
@@ -24,22 +30,25 @@
|
|
|
24
30
|
},
|
|
25
31
|
"files": [
|
|
26
32
|
"dist",
|
|
33
|
+
"native",
|
|
27
34
|
"README.md",
|
|
28
35
|
"LICENSE"
|
|
29
36
|
],
|
|
30
37
|
"scripts": {
|
|
31
|
-
"build": "bun build ./src/index.ts --outdir ./dist --target bun && bun build ./src/cli.ts --outdir ./dist --target bun && bun run build:types",
|
|
38
|
+
"build": "bun build ./src/index.ts --outdir ./dist --target bun && bun build ./src/cli.ts --outdir ./dist --target bun && bun build ./src/native/index.ts --outdir ./dist/native --target bun && bun build ./src/debug/index.ts --outdir ./dist/debug --target bun && bun run build:types",
|
|
32
39
|
"build:types": "tsc --declaration --emitDeclarationOnly --outDir ./dist",
|
|
40
|
+
"build:native": "./scripts/build-native.sh",
|
|
41
|
+
"build:all": "bun run build:native && bun run build",
|
|
33
42
|
"test": "bun test",
|
|
34
43
|
"dev": "bun --watch src/index.ts",
|
|
35
44
|
"typecheck": "tsc --noEmit",
|
|
36
|
-
"prepublishOnly": "bun run build",
|
|
45
|
+
"prepublishOnly": "bun run build:all",
|
|
37
46
|
"version:patch": "npm version patch --no-git-tag-version",
|
|
38
47
|
"version:minor": "npm version minor --no-git-tag-version",
|
|
39
48
|
"version:major": "npm version major --no-git-tag-version",
|
|
40
|
-
"release:patch": "bun run version:patch && bun run build",
|
|
41
|
-
"release:minor": "bun run version:minor && bun run build",
|
|
42
|
-
"release:major": "bun run version:major && bun run build"
|
|
49
|
+
"release:patch": "bun run version:patch && bun run build:all",
|
|
50
|
+
"release:minor": "bun run version:minor && bun run build:all",
|
|
51
|
+
"release:major": "bun run version:major && bun run build:all"
|
|
43
52
|
},
|
|
44
53
|
"repository": {
|
|
45
54
|
"type": "git",
|
|
@@ -58,7 +67,10 @@
|
|
|
58
67
|
"ssr",
|
|
59
68
|
"template-engine",
|
|
60
69
|
"django-templates",
|
|
61
|
-
"typescript"
|
|
70
|
+
"typescript",
|
|
71
|
+
"zig",
|
|
72
|
+
"native",
|
|
73
|
+
"ffi"
|
|
62
74
|
],
|
|
63
75
|
"author": "egeominotti",
|
|
64
76
|
"license": "BSD-3-Clause",
|