naider 1.17.2 → 1.18.0
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 +101 -2
- package/SPEC.naide +66 -0
- package/assets/naide.ico +0 -0
- package/assets/naide_check.png +0 -0
- package/assets/nx.ico +0 -0
- package/assets/nx_check.png +0 -0
- package/bin/generate-icons.js +169 -140
- package/bin/postinstall.js +4 -4
- package/lsp/server.js +26 -4
- package/package.json +1 -1
- package/src/generator-c.js +65 -0
- package/src/generator-cpp.js +78 -0
- package/src/generator-csharp.js +68 -0
- package/src/generator-dart.js +74 -0
- package/src/generator-go.js +62 -0
- package/src/generator-java.js +75 -0
- package/src/generator-kotlin.js +63 -0
- package/src/generator-php.js +61 -0
- package/src/generator-python.js +86 -0
- package/src/generator-ruby.js +54 -0
- package/src/generator-rust.js +74 -0
- package/src/generator-swift.js +67 -0
- package/src/generator.js +54 -0
- package/src/parser.js +63 -1
- package/src/tokens.js +7 -0
- package/vscode-naide/syntaxes/naide.tmLanguage.json +3 -3
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
**Node AI Development Environment** — A programming language simpler than Python, designed for AI-speed code generation, that transpiles to **15 languages**.
|
|
4
4
|
|
|
5
|
-
NAIDE is built on four principles: simpler than Python (built-in functions, syntax sugar, zero boilerplate), one way to write everything (zero ambiguity), keyword-driven intent (the first token decides meaning), and minimal token count (fewer tokens = faster AI generation). Write once, compile to any target.
|
|
5
|
+
NAIDE is built on four principles: simpler than Python (built-in functions, syntax sugar, zero boilerplate), one way to write everything (zero ambiguity), keyword-driven intent (the first token decides meaning), and minimal token count (fewer tokens = faster AI generation). Write once, compile to any target. 40+ built-in functions, syntax sugar (`unless`, `until`, `repeat`, `swap`, `is`/`isnt`, one-line functions, `auto` type inference, destructuring, pipe operator), and 55+ built-in features including servers, databases, authentication, bots, GraphQL, gRPC, WebRTC, blockchain, and more.
|
|
6
6
|
|
|
7
7
|
### Compilation Targets
|
|
8
8
|
|
|
@@ -136,9 +136,29 @@ any data = null
|
|
|
136
136
|
|
|
137
137
|
mut int counter = 0 # mutable (let)
|
|
138
138
|
mut str label = "init"
|
|
139
|
+
|
|
140
|
+
auto x = 42 # type inferred (const)
|
|
141
|
+
auto msg = "hello" # compiler infers str
|
|
142
|
+
mut auto counter2 = 0 # type inferred (let)
|
|
139
143
|
```
|
|
140
144
|
|
|
141
|
-
Types: `str`, `int`, `num`, `bool`, `list`, `map`, `any`, `json`, `void`
|
|
145
|
+
Types: `str`, `int`, `num`, `bool`, `list`, `map`, `any`, `json`, `void`, `auto` (inferred)
|
|
146
|
+
|
|
147
|
+
### Destructuring
|
|
148
|
+
|
|
149
|
+
```python
|
|
150
|
+
# Object destructuring
|
|
151
|
+
auto {name, age} = user
|
|
152
|
+
auto {name, age = 0} = user # with defaults
|
|
153
|
+
auto {name, ...rest} = user # with rest
|
|
154
|
+
mut {score, level} = gameState # mutable
|
|
155
|
+
|
|
156
|
+
# Array destructuring
|
|
157
|
+
auto [first, second] = items
|
|
158
|
+
auto [head, ...tail] = items # with rest
|
|
159
|
+
auto [x, y = 0] = coords # with defaults
|
|
160
|
+
mut [a, b] = pair # mutable
|
|
161
|
+
```
|
|
142
162
|
|
|
143
163
|
### String Interpolation
|
|
144
164
|
|
|
@@ -257,6 +277,28 @@ model Admin extends User:
|
|
|
257
277
|
ret ["read", "write", "delete"]
|
|
258
278
|
```
|
|
259
279
|
|
|
280
|
+
Schema inheritance with constructors and methods:
|
|
281
|
+
|
|
282
|
+
```python
|
|
283
|
+
schema Animal:
|
|
284
|
+
id auto
|
|
285
|
+
name str required
|
|
286
|
+
species str required
|
|
287
|
+
|
|
288
|
+
schema Dog extends Animal:
|
|
289
|
+
breed str optional
|
|
290
|
+
trained bool default(false)
|
|
291
|
+
|
|
292
|
+
init(str name, str breed):
|
|
293
|
+
self.name = name
|
|
294
|
+
self.breed = breed
|
|
295
|
+
|
|
296
|
+
fn bark() -> str:
|
|
297
|
+
ret "Woof! I'm {self.name}"
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
`init(params):` defines a constructor. `fn method():` defines methods. `extends` inherits all fields and methods from the parent.
|
|
301
|
+
|
|
260
302
|
### Pipe Operator
|
|
261
303
|
|
|
262
304
|
```python
|
|
@@ -264,8 +306,37 @@ list result = data
|
|
|
264
306
|
|> filter((x) => x.active)
|
|
265
307
|
|> map((x) => x.name)
|
|
266
308
|
|> sort()
|
|
309
|
+
|
|
310
|
+
int total = items
|
|
311
|
+
|> filter((x) => x > 0)
|
|
312
|
+
|> map((x) => x * 2)
|
|
313
|
+
|> reduce((a, b) => a + b, 0)
|
|
267
314
|
```
|
|
268
315
|
|
|
316
|
+
Chain operations left to right for readable data transformations.
|
|
317
|
+
|
|
318
|
+
### Optional Chaining & Null Coalescing
|
|
319
|
+
|
|
320
|
+
```python
|
|
321
|
+
str name = user?.name # safe property access
|
|
322
|
+
any val = data?.nested?.value # deep safe access
|
|
323
|
+
str display = user?.name ?? "Anonymous" # fallback on null/undefined
|
|
324
|
+
int port = config?.port ?? 3000
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
`?.` safely accesses properties (returns `undefined` if the left side is `null`/`undefined`). `??` provides a fallback value when the left side is `null` or `undefined`.
|
|
328
|
+
|
|
329
|
+
### Spread Operator
|
|
330
|
+
|
|
331
|
+
```python
|
|
332
|
+
list combined = [...listA, ...listB]
|
|
333
|
+
map merged = {...defaults, ...overrides}
|
|
334
|
+
list withExtra = [...items, 4, 5, 6]
|
|
335
|
+
map withDebug = {...config, debug: true}
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
Spread arrays and objects with `...`. Works in list literals, map literals, and function arguments.
|
|
339
|
+
|
|
269
340
|
### Imports / Exports
|
|
270
341
|
|
|
271
342
|
```python
|
|
@@ -888,6 +959,15 @@ Variables become constants. Missing `required` vars exit with an error.
|
|
|
888
959
|
## Syntax Sugar (Simpler than Python)
|
|
889
960
|
|
|
890
961
|
```python
|
|
962
|
+
# auto — type inference
|
|
963
|
+
auto x = 42
|
|
964
|
+
auto msg = "hello"
|
|
965
|
+
mut auto counter = 0
|
|
966
|
+
|
|
967
|
+
# destructuring
|
|
968
|
+
auto {name, age} = user
|
|
969
|
+
auto [first, ...rest] = items
|
|
970
|
+
|
|
891
971
|
# unless — negated if
|
|
892
972
|
unless x > 10:
|
|
893
973
|
log "small"
|
|
@@ -918,6 +998,16 @@ if y isnt null: log "exists"
|
|
|
918
998
|
# one-line functions
|
|
919
999
|
fn double(int x) -> int = x * 2
|
|
920
1000
|
|
|
1001
|
+
# pipe operator
|
|
1002
|
+
list result = items |> filter((x) => x > 0) |> map((x) => x * 2)
|
|
1003
|
+
|
|
1004
|
+
# optional chaining + null coalescing
|
|
1005
|
+
str name = user?.name ?? "Anonymous"
|
|
1006
|
+
|
|
1007
|
+
# spread
|
|
1008
|
+
list all = [...a, ...b]
|
|
1009
|
+
map merged = {...defaults, ...overrides}
|
|
1010
|
+
|
|
921
1011
|
# print alias
|
|
922
1012
|
print "hello world"
|
|
923
1013
|
```
|
|
@@ -955,6 +1045,15 @@ list flat_list = flat(nested)
|
|
|
955
1045
|
list zipped = zip(a, b)
|
|
956
1046
|
list chunks = chunk(items, 3)
|
|
957
1047
|
|
|
1048
|
+
# Functional ops (map/filter/reduce)
|
|
1049
|
+
list doubled = map(items, (x) => x * 2)
|
|
1050
|
+
list big = filter(items, (x) => x > 5)
|
|
1051
|
+
int total = reduce(items, (a, b) => a + b, 0)
|
|
1052
|
+
any found = find(items, (x) => x > 3)
|
|
1053
|
+
bool allPos = every(items, (x) => x > 0)
|
|
1054
|
+
bool hasNeg = some(items, (x) => x < 0)
|
|
1055
|
+
foreach(items, (x) => log x)
|
|
1056
|
+
|
|
958
1057
|
# Math
|
|
959
1058
|
num a = abs(-5)
|
|
960
1059
|
num r = round(3.7)
|
package/SPEC.naide
CHANGED
|
@@ -27,6 +27,26 @@ any data = null
|
|
|
27
27
|
mut int counter = 0
|
|
28
28
|
mut str label = "initial"
|
|
29
29
|
|
|
30
|
+
# auto 型推論 (コンパイラが型を推論)
|
|
31
|
+
auto x = 42 # const x = 42
|
|
32
|
+
auto msg = "hello" # const msg = "hello"
|
|
33
|
+
auto items = [1, 2, 3] # const items = [1, 2, 3]
|
|
34
|
+
mut auto counter2 = 0 # let counter2 = 0
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
# ---- 分割代入 (Destructuring) ----
|
|
38
|
+
# オブジェクト分割代入
|
|
39
|
+
auto {name2, age} = user
|
|
40
|
+
auto {name3, age2 = 0} = user # デフォルト値
|
|
41
|
+
auto {name4, ...rest} = user # レスト
|
|
42
|
+
mut {score, level} = gameState # 可変
|
|
43
|
+
|
|
44
|
+
# 配列分割代入
|
|
45
|
+
auto [first, second] = items
|
|
46
|
+
auto [head, ...tail] = items # レスト
|
|
47
|
+
auto [x2, y = 0] = coords # デフォルト値
|
|
48
|
+
mut [a3, b3] = pair # 可変
|
|
49
|
+
|
|
30
50
|
|
|
31
51
|
# ---- 文字列補間 ----
|
|
32
52
|
# ダブルクォートで {式} が自動展開
|
|
@@ -132,12 +152,29 @@ if err instanceof TypeError:
|
|
|
132
152
|
log "type error occurred"
|
|
133
153
|
|
|
134
154
|
|
|
155
|
+
# ---- map/filter/reduce ビルトイン ----
|
|
156
|
+
# コレクション操作の組み込み関数
|
|
157
|
+
list doubled = map(items, (x) => x * 2)
|
|
158
|
+
list big = filter(items, (x) => x > 5)
|
|
159
|
+
int total2 = reduce(items, (a, b) => a + b, 0)
|
|
160
|
+
any found = find(items, (x) => x > 3)
|
|
161
|
+
bool allBig = every(items, (x) => x > 0)
|
|
162
|
+
bool hasBig = some(items, (x) => x > 10)
|
|
163
|
+
foreach(items, (x) => log x)
|
|
164
|
+
|
|
165
|
+
|
|
135
166
|
# ---- パイプ演算子 ----
|
|
136
167
|
# データ変換チェーンが読みやすい
|
|
137
168
|
list result = [1, 2, 3, 4, 5]
|
|
138
169
|
|> filter((x) => x > 2)
|
|
139
170
|
|> map((x) => x * 10)
|
|
140
171
|
|
|
172
|
+
# パイプ + map/filter/reduce の組み合わせ
|
|
173
|
+
list names = users
|
|
174
|
+
|> filter((u) => u.active)
|
|
175
|
+
|> map((u) => u.name)
|
|
176
|
+
|> sort()
|
|
177
|
+
|
|
141
178
|
|
|
142
179
|
# ---- クラス (model) ----
|
|
143
180
|
model User:
|
|
@@ -159,6 +196,25 @@ model Admin extends User:
|
|
|
159
196
|
ret ["read", "write", "delete"]
|
|
160
197
|
|
|
161
198
|
|
|
199
|
+
# ---- スキーマ継承 (schema extends) ----
|
|
200
|
+
# schema も extends で継承可能
|
|
201
|
+
schema Animal:
|
|
202
|
+
id auto
|
|
203
|
+
name str required
|
|
204
|
+
species str required
|
|
205
|
+
|
|
206
|
+
schema Dog extends Animal:
|
|
207
|
+
breed str optional
|
|
208
|
+
trained bool default(false)
|
|
209
|
+
|
|
210
|
+
init(str name, str breed):
|
|
211
|
+
self.name = name
|
|
212
|
+
self.breed = breed
|
|
213
|
+
|
|
214
|
+
fn bark() -> str:
|
|
215
|
+
ret "Woof! I'm {self.name}"
|
|
216
|
+
|
|
217
|
+
|
|
162
218
|
# ---- データベース永続化 ----
|
|
163
219
|
# db ディレクトリパス → スキーマストアがJSONファイルに自動保存
|
|
164
220
|
db "data/"
|
|
@@ -436,7 +492,15 @@ pub str VERSION = "1.0.0"
|
|
|
436
492
|
|
|
437
493
|
|
|
438
494
|
# ---- null安全 ----
|
|
495
|
+
# オプショナルチェーニング (?.)
|
|
439
496
|
any val = data?.nested?.value ?? "default"
|
|
497
|
+
str userName = user?.name
|
|
498
|
+
any first = items?.[0]
|
|
499
|
+
any result2 = obj?.method?.()
|
|
500
|
+
|
|
501
|
+
# Null合体演算子 (??)
|
|
502
|
+
str displayName = user?.name ?? "Anonymous"
|
|
503
|
+
int port = config?.port ?? 3000
|
|
440
504
|
|
|
441
505
|
|
|
442
506
|
# ---- await.all (Promise.all) ----
|
|
@@ -446,6 +510,8 @@ any val = data?.nested?.value ?? "default"
|
|
|
446
510
|
# ---- スプレッド ----
|
|
447
511
|
list combined = [...items, 4, 5, 6]
|
|
448
512
|
map merged = {...config, debug: true}
|
|
513
|
+
list all = [...listA, ...listB]
|
|
514
|
+
map full = {...defaults, ...overrides}
|
|
449
515
|
|
|
450
516
|
|
|
451
517
|
# ---- ページ生成 (HTML) ----
|
package/assets/naide.ico
CHANGED
|
Binary file
|
|
Binary file
|
package/assets/nx.ico
CHANGED
|
Binary file
|
|
Binary file
|
package/bin/generate-icons.js
CHANGED
|
@@ -1,13 +1,62 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import { writeFileSync } from 'fs';
|
|
3
|
+
import { writeFileSync, mkdirSync } from 'fs';
|
|
4
4
|
import { resolve, dirname } from 'path';
|
|
5
5
|
import { fileURLToPath } from 'url';
|
|
6
|
+
import zlib from 'zlib';
|
|
6
7
|
|
|
7
8
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
8
9
|
|
|
10
|
+
function createPNG(width, height, pixels) {
|
|
11
|
+
const signature = Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]);
|
|
12
|
+
|
|
13
|
+
function makeChunk(type, data) {
|
|
14
|
+
const buf = Buffer.alloc(4 + type.length + data.length + 4);
|
|
15
|
+
buf.writeUInt32BE(data.length, 0);
|
|
16
|
+
buf.write(type, 4);
|
|
17
|
+
data.copy(buf, 4 + type.length);
|
|
18
|
+
const crc = crc32(buf.slice(4, 4 + type.length + data.length));
|
|
19
|
+
buf.writeUInt32BE(crc, buf.length - 4);
|
|
20
|
+
return buf;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const ihdr = Buffer.alloc(13);
|
|
24
|
+
ihdr.writeUInt32BE(width, 0);
|
|
25
|
+
ihdr.writeUInt32BE(height, 4);
|
|
26
|
+
ihdr[8] = 8;
|
|
27
|
+
ihdr[9] = 6;
|
|
28
|
+
ihdr[10] = 0;
|
|
29
|
+
ihdr[11] = 0;
|
|
30
|
+
ihdr[12] = 0;
|
|
31
|
+
|
|
32
|
+
const rawData = Buffer.alloc(height * (1 + width * 4));
|
|
33
|
+
for (let y = 0; y < height; y++) {
|
|
34
|
+
rawData[y * (1 + width * 4)] = 0;
|
|
35
|
+
for (let x = 0; x < width; x++) {
|
|
36
|
+
const si = (y * width + x) * 4;
|
|
37
|
+
const di = y * (1 + width * 4) + 1 + x * 4;
|
|
38
|
+
rawData[di + 0] = pixels[si + 0];
|
|
39
|
+
rawData[di + 1] = pixels[si + 1];
|
|
40
|
+
rawData[di + 2] = pixels[si + 2];
|
|
41
|
+
rawData[di + 3] = pixels[si + 3];
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
const compressed = zlib.deflateSync(rawData);
|
|
45
|
+
|
|
46
|
+
const ihdrChunk = makeChunk('IHDR', ihdr);
|
|
47
|
+
const idatChunk = makeChunk('IDAT', compressed);
|
|
48
|
+
const iendChunk = makeChunk('IEND', Buffer.alloc(0));
|
|
49
|
+
|
|
50
|
+
return Buffer.concat([signature, ihdrChunk, idatChunk, iendChunk]);
|
|
51
|
+
}
|
|
52
|
+
|
|
9
53
|
function createICO(sizes, renderFn) {
|
|
10
|
-
const images = sizes.map(s =>
|
|
54
|
+
const images = sizes.map(s => {
|
|
55
|
+
const pixels = new Uint8Array(s * s * 4);
|
|
56
|
+
renderFn(pixels, s);
|
|
57
|
+
return { size: s, data: createPNG(s, s, pixels) };
|
|
58
|
+
});
|
|
59
|
+
|
|
11
60
|
const headerSize = 6 + images.length * 16;
|
|
12
61
|
let offset = headerSize;
|
|
13
62
|
|
|
@@ -34,175 +83,155 @@ function createICO(sizes, renderFn) {
|
|
|
34
83
|
return Buffer.concat([header, ...entries, ...images.map(i => i.data)]);
|
|
35
84
|
}
|
|
36
85
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
const buf = Buffer.alloc(totalSize);
|
|
49
|
-
|
|
50
|
-
buf.writeUInt32LE(40, 0);
|
|
51
|
-
buf.writeInt32LE(size, 4);
|
|
52
|
-
buf.writeInt32LE(size * 2, 8);
|
|
53
|
-
buf.writeUInt16LE(1, 12);
|
|
54
|
-
buf.writeUInt16LE(32, 14);
|
|
55
|
-
buf.writeUInt32LE(0, 16);
|
|
56
|
-
buf.writeUInt32LE(pixelDataSize + andMaskSize, 20);
|
|
57
|
-
buf.writeInt32LE(0, 24);
|
|
58
|
-
buf.writeInt32LE(0, 28);
|
|
59
|
-
buf.writeUInt32LE(0, 32);
|
|
60
|
-
buf.writeUInt32LE(0, 36);
|
|
61
|
-
|
|
62
|
-
for (let y = 0; y < size; y++) {
|
|
63
|
-
const srcRow = (size - 1 - y) * size * 4;
|
|
64
|
-
const dstRow = bmpInfoSize + y * rowSize;
|
|
65
|
-
for (let x = 0; x < size; x++) {
|
|
66
|
-
const si = srcRow + x * 4;
|
|
67
|
-
const di = dstRow + x * 4;
|
|
68
|
-
buf[di + 0] = pixels[si + 2];
|
|
69
|
-
buf[di + 1] = pixels[si + 1];
|
|
70
|
-
buf[di + 2] = pixels[si + 0];
|
|
71
|
-
buf[di + 3] = pixels[si + 3];
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
const andOffset = bmpInfoSize + pixelDataSize;
|
|
76
|
-
for (let y = 0; y < size; y++) {
|
|
77
|
-
const srcRow = (size - 1 - y) * size * 4;
|
|
78
|
-
for (let x = 0; x < size; x++) {
|
|
79
|
-
const alpha = pixels[srcRow + x * 4 + 3];
|
|
80
|
-
if (alpha < 128) {
|
|
81
|
-
const byteIdx = andOffset + y * andRowSize + Math.floor(x / 8);
|
|
82
|
-
buf[byteIdx] |= (0x80 >> (x % 8));
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
return { size, data: buf };
|
|
86
|
+
const crcTable = new Uint32Array(256);
|
|
87
|
+
for (let n = 0; n < 256; n++) {
|
|
88
|
+
let c = n;
|
|
89
|
+
for (let k = 0; k < 8; k++) c = (c & 1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1);
|
|
90
|
+
crcTable[n] = c;
|
|
91
|
+
}
|
|
92
|
+
function crc32(buf) {
|
|
93
|
+
let crc = 0xFFFFFFFF;
|
|
94
|
+
for (let i = 0; i < buf.length; i++) crc = crcTable[(crc ^ buf[i]) & 0xFF] ^ (crc >>> 8);
|
|
95
|
+
return (crc ^ 0xFFFFFFFF) >>> 0;
|
|
88
96
|
}
|
|
89
97
|
|
|
90
98
|
function setPixel(pixels, size, x, y, r, g, b, a = 255) {
|
|
91
99
|
if (x < 0 || x >= size || y < 0 || y >= size) return;
|
|
92
100
|
const i = (y * size + x) * 4;
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
pixels[i +
|
|
98
|
-
pixels[i +
|
|
99
|
-
pixels[i +
|
|
100
|
-
|
|
101
|
-
pixels[i + 0] = r;
|
|
102
|
-
pixels[i + 1] = g;
|
|
103
|
-
pixels[i + 2] = b;
|
|
104
|
-
pixels[i + 3] = a;
|
|
101
|
+
const sa = a / 255;
|
|
102
|
+
const da = (pixels[i + 3] / 255) * (1 - sa);
|
|
103
|
+
const oa = sa + da;
|
|
104
|
+
if (oa > 0) {
|
|
105
|
+
pixels[i + 0] = Math.round((r * sa + pixels[i + 0] * da) / oa);
|
|
106
|
+
pixels[i + 1] = Math.round((g * sa + pixels[i + 1] * da) / oa);
|
|
107
|
+
pixels[i + 2] = Math.round((b * sa + pixels[i + 2] * da) / oa);
|
|
108
|
+
pixels[i + 3] = Math.round(oa * 255);
|
|
105
109
|
}
|
|
106
110
|
}
|
|
107
111
|
|
|
108
|
-
function fillRect(
|
|
109
|
-
for (let y = y0; y < y0 + h; y++)
|
|
110
|
-
for (let x = x0; x < x0 + w; x++)
|
|
111
|
-
setPixel(
|
|
112
|
+
function fillRect(p, s, x0, y0, w, h, r, g, b, a = 255) {
|
|
113
|
+
for (let y = y0; y < y0 + h && y < s; y++)
|
|
114
|
+
for (let x = x0; x < x0 + w && x < s; x++)
|
|
115
|
+
setPixel(p, s, x, y, r, g, b, a);
|
|
112
116
|
}
|
|
113
117
|
|
|
114
|
-
function
|
|
118
|
+
function fillCircle(p, s, cx, cy, radius, r, g, b, a = 255) {
|
|
119
|
+
const r2 = radius * radius;
|
|
120
|
+
for (let y = Math.floor(cy - radius); y <= Math.ceil(cy + radius); y++) {
|
|
121
|
+
for (let x = Math.floor(cx - radius); x <= Math.ceil(cx + radius); x++) {
|
|
122
|
+
const dx = x - cx + 0.5, dy = y - cy + 0.5;
|
|
123
|
+
const d2 = dx * dx + dy * dy;
|
|
124
|
+
if (d2 <= r2) {
|
|
125
|
+
const edge = Math.max(0, Math.min(1, (radius - Math.sqrt(d2)) * 1.5));
|
|
126
|
+
setPixel(p, s, x, y, r, g, b, Math.round(a * edge));
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function fillRoundRect(p, s, x0, y0, w, h, rad, r, g, b, a = 255) {
|
|
115
133
|
for (let y = y0; y < y0 + h; y++) {
|
|
116
134
|
for (let x = x0; x < x0 + w; x++) {
|
|
117
|
-
let
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
const
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
if (dx * dx + dy * dy > radius * radius) {
|
|
131
|
-
inside = false;
|
|
132
|
-
break;
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
+
let draw = true;
|
|
136
|
+
if (x < x0 + rad && y < y0 + rad) {
|
|
137
|
+
const dx = x - (x0 + rad), dy = y - (y0 + rad);
|
|
138
|
+
if (dx * dx + dy * dy > rad * rad) draw = false;
|
|
139
|
+
} else if (x >= x0 + w - rad && y < y0 + rad) {
|
|
140
|
+
const dx = x - (x0 + w - rad - 1), dy = y - (y0 + rad);
|
|
141
|
+
if (dx * dx + dy * dy > rad * rad) draw = false;
|
|
142
|
+
} else if (x < x0 + rad && y >= y0 + h - rad) {
|
|
143
|
+
const dx = x - (x0 + rad), dy = y - (y0 + h - rad - 1);
|
|
144
|
+
if (dx * dx + dy * dy > rad * rad) draw = false;
|
|
145
|
+
} else if (x >= x0 + w - rad && y >= y0 + h - rad) {
|
|
146
|
+
const dx = x - (x0 + w - rad - 1), dy = y - (y0 + h - rad - 1);
|
|
147
|
+
if (dx * dx + dy * dy > rad * rad) draw = false;
|
|
135
148
|
}
|
|
136
|
-
if (
|
|
149
|
+
if (draw) setPixel(p, s, x, y, r, g, b, a);
|
|
137
150
|
}
|
|
138
151
|
}
|
|
139
152
|
}
|
|
140
153
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
154
|
+
function distToSegment(px, py, ax, ay, bx, by) {
|
|
155
|
+
const dx = bx - ax, dy = by - ay;
|
|
156
|
+
const len2 = dx * dx + dy * dy;
|
|
157
|
+
if (len2 === 0) return Math.hypot(px - ax, py - ay);
|
|
158
|
+
const t = Math.max(0, Math.min(1, ((px - ax) * dx + (py - ay) * dy) / len2));
|
|
159
|
+
return Math.hypot(px - (ax + t * dx), py - (ay + t * dy));
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function drawSmooth(p, s, segments, ox, oy, scale, r, g, b) {
|
|
163
|
+
const thick = scale * 0.22;
|
|
164
|
+
const x0 = Math.floor(ox - thick - 1), y0 = Math.floor(oy - thick - 1);
|
|
165
|
+
const x1 = Math.ceil(ox + scale + thick + 1), y1 = Math.ceil(oy + scale + thick + 1);
|
|
166
|
+
for (let y = Math.max(0, y0); y < Math.min(s, y1); y++) {
|
|
167
|
+
for (let x = Math.max(0, x0); x < Math.min(s, x1); x++) {
|
|
168
|
+
let minD = Infinity;
|
|
169
|
+
for (const seg of segments) {
|
|
170
|
+
const d = distToSegment(x + 0.5, y + 0.5,
|
|
171
|
+
ox + seg[0] * scale, oy + seg[1] * scale,
|
|
172
|
+
ox + seg[2] * scale, oy + seg[3] * scale);
|
|
173
|
+
if (d < minD) minD = d;
|
|
174
|
+
}
|
|
175
|
+
if (minD < thick + 1) {
|
|
176
|
+
const alpha = Math.max(0, Math.min(1, (thick + 0.8 - minD) / 1.2));
|
|
177
|
+
setPixel(p, s, x, y, r, g, b, Math.round(255 * alpha));
|
|
162
178
|
}
|
|
163
179
|
}
|
|
164
180
|
}
|
|
165
181
|
}
|
|
166
182
|
|
|
183
|
+
function drawLetterN(p, s, cx, cy, h, r, g, b) {
|
|
184
|
+
const w = h * 0.7;
|
|
185
|
+
const x0 = cx - w / 2, y0 = cy - h / 2;
|
|
186
|
+
const segments = [
|
|
187
|
+
[0, 0, 0, 1],
|
|
188
|
+
[1, 0, 1, 1],
|
|
189
|
+
[0, 0, 1, 1],
|
|
190
|
+
];
|
|
191
|
+
drawSmooth(p, s, segments, x0, y0, h, r, g, b);
|
|
192
|
+
const extra = h * 0.22;
|
|
193
|
+
drawSmooth(p, s, [[0, 0, 0, 1], [1, 0, 1, 1], [0, 0, 1, 1]], x0, y0, h, r, g, b);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function drawLetterX(p, s, cx, cy, h, r, g, b) {
|
|
197
|
+
const segments = [
|
|
198
|
+
[0, 0, 1, 1],
|
|
199
|
+
[1, 0, 0, 1],
|
|
200
|
+
];
|
|
201
|
+
const x0 = cx - h * 0.35, y0 = cy - h / 2;
|
|
202
|
+
drawSmooth(p, s, segments, x0, y0, h, r, g, b);
|
|
203
|
+
}
|
|
204
|
+
|
|
167
205
|
function renderNaideIcon(pixels, size) {
|
|
168
206
|
const s = size;
|
|
169
|
-
const
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
const
|
|
176
|
-
|
|
177
|
-
const oy = Math.round((s - gh) / 2);
|
|
178
|
-
drawGlyph(pixels, s, GLYPH_N, ox, oy, glyphScale, 255, 255, 255);
|
|
207
|
+
const pad = Math.max(1, Math.round(s * 0.08));
|
|
208
|
+
const rad = Math.max(3, Math.round(s * 0.22));
|
|
209
|
+
|
|
210
|
+
fillRoundRect(pixels, s, 0, 0, s, s, rad, 35, 70, 150);
|
|
211
|
+
fillRoundRect(pixels, s, pad, pad, s - pad * 2, s - pad * 2, Math.max(2, rad - 2), 55, 110, 210);
|
|
212
|
+
|
|
213
|
+
const letterH = Math.round(s * 0.5);
|
|
214
|
+
drawLetterN(pixels, s, Math.round(s / 2), Math.round(s * 0.46), letterH, 255, 255, 255);
|
|
179
215
|
}
|
|
180
216
|
|
|
181
217
|
function renderNxIcon(pixels, size) {
|
|
182
218
|
const s = size;
|
|
183
|
-
const
|
|
184
|
-
|
|
185
|
-
fillRoundRect(pixels, s, 1, 1, s - 2, s - 2, r, 30, 200, 100);
|
|
186
|
-
|
|
187
|
-
const glyphScale = Math.max(1, Math.round(s / 10));
|
|
188
|
-
const gw = 5 * glyphScale;
|
|
189
|
-
const gh = 5 * glyphScale;
|
|
190
|
-
const ox = Math.round((s - gw) / 2);
|
|
191
|
-
const oy = Math.round((s - gh) / 2);
|
|
192
|
-
drawGlyph(pixels, s, GLYPH_X, ox, oy, glyphScale, 255, 255, 255);
|
|
193
|
-
}
|
|
219
|
+
const pad = Math.max(1, Math.round(s * 0.08));
|
|
220
|
+
const rad = Math.max(3, Math.round(s * 0.22));
|
|
194
221
|
|
|
195
|
-
|
|
196
|
-
|
|
222
|
+
fillRoundRect(pixels, s, 0, 0, s, s, rad, 25, 110, 60);
|
|
223
|
+
fillRoundRect(pixels, s, pad, pad, s - pad * 2, s - pad * 2, Math.max(2, rad - 2), 45, 160, 90);
|
|
197
224
|
|
|
198
|
-
const
|
|
199
|
-
|
|
225
|
+
const letterH = Math.round(s * 0.5);
|
|
226
|
+
drawLetterX(pixels, s, Math.round(s / 2), Math.round(s * 0.46), letterH, 255, 255, 255);
|
|
227
|
+
}
|
|
200
228
|
|
|
201
|
-
import { mkdirSync } from 'fs';
|
|
202
229
|
mkdirSync(resolve(__dirname, '..', 'assets'), { recursive: true });
|
|
203
230
|
|
|
204
|
-
|
|
205
|
-
|
|
231
|
+
const naideIco = createICO([16, 32, 48, 256], renderNaideIcon);
|
|
232
|
+
const nxIco = createICO([16, 32, 48, 256], renderNxIcon);
|
|
233
|
+
|
|
234
|
+
writeFileSync(resolve(__dirname, '..', 'assets', 'naide.ico'), naideIco);
|
|
235
|
+
writeFileSync(resolve(__dirname, '..', 'assets', 'nx.ico'), nxIco);
|
|
206
236
|
|
|
207
|
-
console.log(
|
|
208
|
-
console.log(`Generated: ${nxOut}`);
|
|
237
|
+
console.log('Icons generated successfully.');
|
package/bin/postinstall.js
CHANGED
|
@@ -39,10 +39,10 @@ function registerWindows() {
|
|
|
39
39
|
regAdd('HKCU\\Software\\Classes\\NAIDEXFile\\shell\\open\\command', cmd);
|
|
40
40
|
|
|
41
41
|
const assetsDir = resolve(__dirname, '..', 'assets');
|
|
42
|
-
const naideIco = resolve(assetsDir, 'naide.ico')
|
|
43
|
-
const nxIco = resolve(assetsDir, 'nx.ico')
|
|
44
|
-
|
|
45
|
-
|
|
42
|
+
const naideIco = resolve(assetsDir, 'naide.ico');
|
|
43
|
+
const nxIco = resolve(assetsDir, 'nx.ico');
|
|
44
|
+
regAdd('HKCU\\Software\\Classes\\NAIDEFile\\DefaultIcon', naideIco);
|
|
45
|
+
regAdd('HKCU\\Software\\Classes\\NAIDEXFile\\DefaultIcon', nxIco);
|
|
46
46
|
|
|
47
47
|
console.log(' .naide and .nx file associations registered (Windows)');
|
|
48
48
|
}
|