novac 2.0.1 → 2.2.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.
Files changed (161) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +1574 -597
  3. package/bin/novac +468 -171
  4. package/bin/nvc +522 -0
  5. package/bin/nvml +78 -17
  6. package/demo.nv +0 -0
  7. package/demo_builtins.nv +0 -0
  8. package/demo_http.nv +0 -0
  9. package/examples/bf.nv +69 -0
  10. package/examples/math.nv +21 -0
  11. package/kits/birdAPI/kitdef.js +954 -0
  12. package/kits/kitRNG/kitdef.js +740 -0
  13. package/kits/kitSSH/kitdef.js +1272 -0
  14. package/kits/kitadb/kitdef.js +606 -0
  15. package/kits/kitai/kitdef.js +2185 -0
  16. package/kits/kitansi/kitdef.js +1402 -0
  17. package/kits/kitcanvas/kitdef.js +914 -0
  18. package/kits/kitclippy/kitdef.js +925 -0
  19. package/kits/kitformat/kitdef.js +1485 -0
  20. package/kits/kitgps/kitdef.js +1862 -0
  21. package/kits/kitlibproc/kitdef.js +3 -2
  22. package/kits/kitmatrix/ex.js +19 -0
  23. package/kits/kitmatrix/kitdef.js +960 -0
  24. package/kits/kitmorse/kitdef.js +229 -0
  25. package/kits/kitmpatch/kitdef.js +906 -0
  26. package/kits/kitnet/kitdef.js +1401 -0
  27. package/kits/kitnovacweb/README.md +1416 -143
  28. package/kits/kitnovacweb/kitdef.js +92 -2
  29. package/kits/kitnovacweb/nvml/executor.js +578 -176
  30. package/kits/kitnovacweb/nvml/index.js +2 -2
  31. package/kits/kitnovacweb/nvml/lexer.js +72 -69
  32. package/kits/kitnovacweb/nvml/parser.js +328 -159
  33. package/kits/kitnovacweb/nvml/renderer.js +770 -270
  34. package/kits/kitparse/kitdef.js +1688 -0
  35. package/kits/kitproto/kitdef.js +613 -0
  36. package/kits/kitqr/kitdef.js +637 -0
  37. package/kits/kitregex++/kitdef.js +1353 -0
  38. package/kits/kitrequire/kitdef.js +1599 -0
  39. package/kits/kitx11/kitdef.js +1 -0
  40. package/kits/kitx11/kitx11.js +2472 -0
  41. package/kits/kitx11/kitx11_conn.js +948 -0
  42. package/kits/kitx11/kitx11_worker.js +121 -0
  43. package/kits/libtea/kitdef.js +2691 -0
  44. package/kits/libterm/ex.js +285 -0
  45. package/kits/libterm/kitdef.js +1927 -0
  46. package/novac/LICENSE +21 -0
  47. package/novac/README.md +1823 -0
  48. package/novac/bin/novac +950 -0
  49. package/novac/bin/nvc +522 -0
  50. package/novac/bin/nvml +542 -0
  51. package/novac/demo.nv +245 -0
  52. package/novac/demo_builtins.nv +209 -0
  53. package/novac/demo_http.nv +62 -0
  54. package/novac/examples/bf.nv +69 -0
  55. package/novac/examples/math.nv +21 -0
  56. package/novac/kits/kitai/kitdef.js +2185 -0
  57. package/novac/kits/kitansi/kitdef.js +1402 -0
  58. package/novac/kits/kitformat/kitdef.js +1485 -0
  59. package/novac/kits/kitgps/kitdef.js +1862 -0
  60. package/novac/kits/kitlibfs/kitdef.js +231 -0
  61. package/{examples/example-project/nova_modules → novac/kits}/kitlibproc/kitdef.js +3 -2
  62. package/novac/kits/kitmatrix/ex.js +19 -0
  63. package/novac/kits/kitmatrix/kitdef.js +960 -0
  64. package/novac/kits/kitmpatch/kitdef.js +906 -0
  65. package/novac/kits/kitnovacweb/README.md +1572 -0
  66. package/novac/kits/kitnovacweb/demo.nv +12 -0
  67. package/novac/kits/kitnovacweb/demo.nvml +71 -0
  68. package/novac/kits/kitnovacweb/index.nova +12 -0
  69. package/novac/kits/kitnovacweb/kitdef.js +692 -0
  70. package/novac/kits/kitnovacweb/nova.kit.json +8 -0
  71. package/novac/kits/kitnovacweb/nvml/executor.js +739 -0
  72. package/novac/kits/kitnovacweb/nvml/index.js +67 -0
  73. package/novac/kits/kitnovacweb/nvml/lexer.js +263 -0
  74. package/novac/kits/kitnovacweb/nvml/parser.js +508 -0
  75. package/novac/kits/kitnovacweb/nvml/renderer.js +924 -0
  76. package/novac/kits/kitparse/kitdef.js +1688 -0
  77. package/novac/kits/kitregex++/kitdef.js +1353 -0
  78. package/novac/kits/kitrequire/kitdef.js +1599 -0
  79. package/novac/kits/kitx11/kitdef.js +1 -0
  80. package/novac/kits/kitx11/kitx11.js +2472 -0
  81. package/novac/kits/kitx11/kitx11_conn.js +948 -0
  82. package/novac/kits/kitx11/kitx11_worker.js +121 -0
  83. package/novac/kits/libtea/tf.js +2691 -0
  84. package/novac/kits/libterm/ex.js +285 -0
  85. package/novac/kits/libterm/kitdef.js +1927 -0
  86. package/novac/node_modules/chalk/license +9 -0
  87. package/novac/node_modules/chalk/package.json +83 -0
  88. package/novac/node_modules/chalk/readme.md +297 -0
  89. package/novac/node_modules/chalk/source/index.d.ts +325 -0
  90. package/novac/node_modules/chalk/source/index.js +225 -0
  91. package/novac/node_modules/chalk/source/utilities.js +33 -0
  92. package/novac/node_modules/chalk/source/vendor/ansi-styles/index.d.ts +236 -0
  93. package/novac/node_modules/chalk/source/vendor/ansi-styles/index.js +223 -0
  94. package/novac/node_modules/chalk/source/vendor/supports-color/browser.d.ts +1 -0
  95. package/novac/node_modules/chalk/source/vendor/supports-color/browser.js +34 -0
  96. package/novac/node_modules/chalk/source/vendor/supports-color/index.d.ts +55 -0
  97. package/novac/node_modules/chalk/source/vendor/supports-color/index.js +190 -0
  98. package/novac/node_modules/commander/LICENSE +22 -0
  99. package/novac/node_modules/commander/Readme.md +1176 -0
  100. package/novac/node_modules/commander/esm.mjs +16 -0
  101. package/novac/node_modules/commander/index.js +24 -0
  102. package/novac/node_modules/commander/lib/argument.js +150 -0
  103. package/novac/node_modules/commander/lib/command.js +2777 -0
  104. package/novac/node_modules/commander/lib/error.js +39 -0
  105. package/novac/node_modules/commander/lib/help.js +747 -0
  106. package/novac/node_modules/commander/lib/option.js +380 -0
  107. package/novac/node_modules/commander/lib/suggestSimilar.js +101 -0
  108. package/novac/node_modules/commander/package-support.json +19 -0
  109. package/novac/node_modules/commander/package.json +82 -0
  110. package/novac/node_modules/commander/typings/esm.d.mts +3 -0
  111. package/novac/node_modules/commander/typings/index.d.ts +1113 -0
  112. package/novac/node_modules/node-addon-api/LICENSE.md +9 -0
  113. package/novac/node_modules/node-addon-api/README.md +95 -0
  114. package/novac/node_modules/node-addon-api/common.gypi +21 -0
  115. package/novac/node_modules/node-addon-api/except.gypi +25 -0
  116. package/novac/node_modules/node-addon-api/index.js +14 -0
  117. package/novac/node_modules/node-addon-api/napi-inl.deprecated.h +186 -0
  118. package/novac/node_modules/node-addon-api/napi-inl.h +7165 -0
  119. package/novac/node_modules/node-addon-api/napi.h +3364 -0
  120. package/novac/node_modules/node-addon-api/node_addon_api.gyp +42 -0
  121. package/novac/node_modules/node-addon-api/node_api.gyp +9 -0
  122. package/novac/node_modules/node-addon-api/noexcept.gypi +26 -0
  123. package/novac/node_modules/node-addon-api/package-support.json +21 -0
  124. package/novac/node_modules/node-addon-api/package.json +480 -0
  125. package/novac/node_modules/node-addon-api/tools/README.md +73 -0
  126. package/novac/node_modules/node-addon-api/tools/check-napi.js +99 -0
  127. package/novac/node_modules/node-addon-api/tools/clang-format.js +71 -0
  128. package/novac/node_modules/node-addon-api/tools/conversion.js +301 -0
  129. package/novac/node_modules/serialize-javascript/LICENSE +27 -0
  130. package/novac/node_modules/serialize-javascript/README.md +149 -0
  131. package/novac/node_modules/serialize-javascript/index.js +297 -0
  132. package/novac/node_modules/serialize-javascript/package.json +33 -0
  133. package/novac/package.json +27 -0
  134. package/novac/scripts/update-bin.js +24 -0
  135. package/novac/src/core/bstd.js +1035 -0
  136. package/novac/src/core/config.js +155 -0
  137. package/novac/src/core/describe.js +187 -0
  138. package/novac/src/core/emitter.js +499 -0
  139. package/novac/src/core/error.js +86 -0
  140. package/novac/src/core/executor.js +5606 -0
  141. package/novac/src/core/formatter.js +686 -0
  142. package/novac/src/core/lexer.js +1026 -0
  143. package/novac/src/core/nova_builtins.js +717 -0
  144. package/novac/src/core/nova_thread_worker.js +166 -0
  145. package/novac/src/core/parser.js +2181 -0
  146. package/novac/src/core/types.js +112 -0
  147. package/novac/src/index.js +28 -0
  148. package/novac/src/runtime/stdlib.js +244 -0
  149. package/package.json +6 -3
  150. package/scripts/update-bin.js +0 -0
  151. package/src/core/bstd.js +838 -362
  152. package/src/core/executor.js +2578 -170
  153. package/src/core/lexer.js +502 -54
  154. package/src/core/nova_builtins.js +21 -3
  155. package/src/core/parser.js +413 -72
  156. package/src/core/types.js +30 -2
  157. package/src/index.js +0 -0
  158. package/examples/example-project/README.md +0 -3
  159. package/examples/example-project/src/main.nova +0 -3
  160. package/src/core/environment.js +0 -0
  161. /package/{examples/example-project/bin/example-project.nv → novac/node_modules/node-addon-api/nothing.c} +0 -0
@@ -0,0 +1,637 @@
1
+ // kitqr — novac QR code generation kit
2
+ // Pure JS, no native dependencies.
3
+ // Encodes text/URLs/data → QR matrix → ASCII / Unicode-art / SVG output.
4
+ //
5
+ // Supports QR versions 1-40, error correction L/M/Q/H, byte mode encoding.
6
+
7
+ 'use strict';
8
+
9
+ // ─── CONSTANTS ────────────────────────────────────────────────────────────────
10
+
11
+ const EC = { L: 0, M: 1, Q: 2, H: 3 };
12
+ const EC_NAME = ['L', 'M', 'Q', 'H'];
13
+
14
+ // Number of data codewords per version per EC level (versions 1-10 subset for brevity)
15
+ // Full table: ISO 18004:2015 Table 9
16
+ const DATA_CODEWORDS = [
17
+ // L M Q H
18
+ null,
19
+ [null, 19, 16, 13, 9 ], // v1
20
+ [null, 34, 28, 22, 16], // v2
21
+ [null, 55, 44, 34, 26], // v3
22
+ [null, 80, 64, 48, 36], // v4
23
+ [null, 108, 86, 62, 46], // v5
24
+ [null, 136, 108, 76, 60], // v6
25
+ [null, 156, 124, 88, 66], // v7
26
+ [null, 194, 154, 110, 86], // v8
27
+ [null, 232, 182, 132, 100], // v9
28
+ [null, 274, 216, 154, 122], // v10
29
+ [null, 324, 254, 180, 140], // v11
30
+ [null, 370, 290, 206, 158], // v12
31
+ [null, 428, 334, 244, 180], // v13
32
+ [null, 461, 365, 261, 197], // v14
33
+ [null, 523, 415, 295, 223], // v15
34
+ [null, 589, 453, 325, 253], // v16
35
+ [null, 647, 507, 367, 283], // v17
36
+ [null, 721, 563, 397, 313], // v18
37
+ [null, 795, 627, 445, 341], // v19
38
+ [null, 861, 669, 485, 385], // v20
39
+ [null, 932, 714, 512, 406], // v21
40
+ [null,1006, 782, 568, 442], // v22
41
+ [null,1094, 860, 614, 464], // v23
42
+ [null,1174, 914, 664, 514], // v24
43
+ [null,1276,1000, 718, 538], // v25
44
+ [null,1370,1062, 754, 596], // v26
45
+ [null,1468,1128, 808, 628], // v27
46
+ [null,1531,1193, 871, 661], // v28
47
+ [null,1631,1267, 911, 701], // v29
48
+ [null,1735,1373, 985, 745], // v30
49
+ [null,1843,1455,1033, 793], // v31
50
+ [null,1955,1541,1115, 845], // v32
51
+ [null,2071,1631,1171, 901], // v33
52
+ [null,2191,1725,1231, 961], // v34
53
+ [null,2306,1812,1286, 986], // v35
54
+ [null,2434,1914,1354,1054], // v36
55
+ [null,2566,1992,1426,1096], // v37
56
+ [null,2702,2102,1502,1142], // v38
57
+ [null,2812,2216,1582,1222], // v39
58
+ [null,2956,2334,1666,1276], // v40
59
+ ];
60
+
61
+ // EC codewords per block and block counts — ISO 18004 Table 9 (abbreviated)
62
+ // Format: [ecPerBlock, blocks1, dataPerBlock1, blocks2, dataPerBlock2]
63
+ const EC_BLOCKS = [
64
+ null,
65
+ // v1
66
+ [[7,1,19],[10,1,16],[13,1,13],[17,1,9]],
67
+ // v2
68
+ [[10,1,34],[16,1,28],[22,1,22],[28,1,16]],
69
+ // v3
70
+ [[15,1,55],[26,1,44],[18,2,17],[22,2,13]],
71
+ // v4
72
+ [[20,1,80],[18,2,32],[26,2,24],[16,4,9]],
73
+ // v5
74
+ [[26,1,108],[24,2,43],[18,2,15,2,16],[22,2,11,2,12]],
75
+ // v6
76
+ [[18,2,68],[16,4,27],[24,4,19],[28,4,15]],
77
+ // v7
78
+ [[20,2,78],[18,4,31],[18,2,14,4,15],[26,4,13,1,14]],
79
+ // v8
80
+ [[24,2,97],[22,2,38,2,39],[22,4,18,2,19],[26,4,14,2,15]],
81
+ // v9
82
+ [[30,2,116],[22,3,36,2,37],[20,4,16,4,17],[24,4,12,4,13]],
83
+ // v10
84
+ [[18,2,68,2,69],[26,4,43,1,44],[24,6,19,2,20],[28,6,15,2,16]],
85
+ ];
86
+
87
+ // Alignment pattern positions per version
88
+ const ALIGN_POS = [
89
+ null,
90
+ [], // v1
91
+ [6,18], // v2
92
+ [6,22], // v3
93
+ [6,26], // v4
94
+ [6,30], // v5
95
+ [6,34], // v6
96
+ [6,22,38], // v7
97
+ [6,24,42], // v8
98
+ [6,26,46], // v9
99
+ [6,28,50], // v10
100
+ [6,30,54], // v11
101
+ [6,32,58], // v12
102
+ [6,34,62], // v13
103
+ [6,26,46,66], // v14
104
+ [6,26,48,70], // v15
105
+ [6,26,50,74], // v16
106
+ [6,30,54,78], // v17
107
+ [6,30,56,82], // v18
108
+ [6,30,58,86], // v19
109
+ [6,34,62,90], // v20
110
+ [6,28,50,72,94], // v21
111
+ [6,26,50,74,98], // v22
112
+ [6,30,54,78,102], // v23
113
+ [6,28,54,80,106], // v24
114
+ [6,32,58,84,110], // v25
115
+ [6,30,58,86,114], // v26
116
+ [6,34,62,90,118], // v27
117
+ [6,26,50,74,98,122], // v28
118
+ [6,30,54,78,102,126], // v29
119
+ [6,26,52,78,104,130], // v30
120
+ [6,30,56,82,108,134], // v31
121
+ [6,34,60,86,112,138], // v32
122
+ [6,30,58,86,114,142], // v33
123
+ [6,34,62,90,118,146], // v34
124
+ [6,30,54,82,110,138,166], // v35
125
+ [6,24,50,76,102,128,154], // v36
126
+ [6,28,54,80,106,132,158], // v37
127
+ [6,32,58,84,110,136,162], // v38
128
+ [6,26,54,82,110,138,166], // v39
129
+ [6,30,58,86,114,142,170], // v40
130
+ ];
131
+
132
+ // Format information strings (15-bit, pre-computed) — ISO 18004 Table C.1
133
+ const FORMAT_INFO = [
134
+ // EC L (00)
135
+ [0x77C4, 0x72F3, 0x7DAA, 0x789D, 0x662F, 0x6318, 0x6C41, 0x6976],
136
+ // EC M (01)
137
+ [0x5412, 0x5125, 0x5E7C, 0x5B4B, 0x45F9, 0x40CE, 0x4F97, 0x4AA0],
138
+ // EC Q (10)
139
+ [0x355F, 0x3068, 0x3F31, 0x3A06, 0x24B4, 0x2183, 0x2EDA, 0x2BED],
140
+ // EC H (11)
141
+ [0x1689, 0x13BE, 0x1CE7, 0x19D0, 0x0762, 0x0255, 0x0D0C, 0x083B],
142
+ ];
143
+
144
+ // Version information strings for v7-v40 — ISO 18004 Table D.1
145
+ const VERSION_INFO = [
146
+ null,null,null,null,null,null,null,
147
+ 0x07C94, 0x085BC, 0x09A99, 0x0A4D3, 0x0BBF6, 0x0C762, 0x0D847,
148
+ 0x0E60D, 0x0F928, 0x10B78, 0x1145D, 0x12A17, 0x13532, 0x149A6,
149
+ 0x15683, 0x168C9, 0x177EC, 0x18EC4, 0x191E1, 0x1AFAB, 0x1B08E,
150
+ 0x1CC1A, 0x1D33F, 0x1ED75, 0x1F250, 0x209D5, 0x216F0, 0x228BA,
151
+ 0x2379F, 0x24B0B, 0x2542E, 0x26A64, 0x27541, 0x28C69,
152
+ ];
153
+
154
+ // GF(256) log/exp tables for Reed-Solomon
155
+ const GF_EXP = new Uint8Array(512);
156
+ const GF_LOG = new Uint8Array(256);
157
+ (function buildGF() {
158
+ let x = 1;
159
+ for (let i = 0; i < 255; i++) {
160
+ GF_EXP[i] = x;
161
+ GF_LOG[x] = i;
162
+ x = (x << 1) ^ (x & 0x80 ? 0x11D : 0);
163
+ }
164
+ for (let i = 255; i < 512; i++) GF_EXP[i] = GF_EXP[i - 255];
165
+ })();
166
+
167
+ function gfMul(a, b) {
168
+ if (a === 0 || b === 0) return 0;
169
+ return GF_EXP[GF_LOG[a] + GF_LOG[b]];
170
+ }
171
+
172
+ function rsGeneratorPoly(degree) {
173
+ let g = [1];
174
+ for (let i = 0; i < degree; i++) {
175
+ const ng = new Array(g.length + 1).fill(0);
176
+ for (let j = 0; j < g.length; j++) {
177
+ ng[j] ^= gfMul(g[j], GF_EXP[i]);
178
+ ng[j + 1] ^= g[j];
179
+ }
180
+ g = ng;
181
+ }
182
+ return g;
183
+ }
184
+
185
+ function rsEncode(data, ecLen) {
186
+ const gen = rsGeneratorPoly(ecLen);
187
+ const msg = [...data, ...new Array(ecLen).fill(0)];
188
+ for (let i = 0; i < data.length; i++) {
189
+ const coeff = msg[i];
190
+ if (coeff === 0) continue;
191
+ for (let j = 0; j < gen.length; j++) {
192
+ msg[i + j] ^= gfMul(gen[j], coeff);
193
+ }
194
+ }
195
+ return msg.slice(data.length);
196
+ }
197
+
198
+ // ─── ENCODING ─────────────────────────────────────────────────────────────────
199
+
200
+ function encodeData(text, version, ecLevel) {
201
+ const bytes = Array.from(Buffer.from(text, 'utf8'));
202
+ const charCount = bytes.length;
203
+ const totalBits = DATA_CODEWORDS[version][ecLevel] * 8;
204
+
205
+ const bits = [];
206
+ const push = (val, len) => {
207
+ for (let i = len - 1; i >= 0; i--) bits.push((val >> i) & 1);
208
+ };
209
+
210
+ // Mode indicator: byte mode = 0100
211
+ push(0b0100, 4);
212
+ // Character count: 8 bits for v1-9, 16 for v10-26, 16 for v27-40
213
+ const ccBits = version < 10 ? 8 : 16;
214
+ push(charCount, ccBits);
215
+ // Data
216
+ for (const b of bytes) push(b, 8);
217
+ // Terminator
218
+ const term = Math.min(4, totalBits - bits.length);
219
+ for (let i = 0; i < term; i++) bits.push(0);
220
+ // Byte-align
221
+ while (bits.length % 8 !== 0) bits.push(0);
222
+ // Pad codewords
223
+ const padWords = [0xEC, 0x11];
224
+ let pi = 0;
225
+ while (bits.length < totalBits) { push(padWords[pi++ % 2], 8); }
226
+
227
+ // Convert to bytes
228
+ const codewords = [];
229
+ for (let i = 0; i < bits.length; i += 8) {
230
+ let byte = 0;
231
+ for (let j = 0; j < 8; j++) byte = (byte << 1) | bits[i + j];
232
+ codewords.push(byte);
233
+ }
234
+ return codewords;
235
+ }
236
+
237
+ function interleaveBlocks(codewords, version, ecLevel) {
238
+ const spec = EC_BLOCKS[version]?.[ecLevel];
239
+ if (!spec) return codewords; // fallback
240
+
241
+ const [ecPerBlock, b1count, b1data, b2count = 0, b2data = 0] = spec;
242
+
243
+ const blocks = [];
244
+ let pos = 0;
245
+
246
+ const makeBlocks = (count, dataLen) => {
247
+ for (let i = 0; i < count; i++) {
248
+ const data = codewords.slice(pos, pos + dataLen);
249
+ pos += dataLen;
250
+ const ec = rsEncode(data, ecPerBlock);
251
+ blocks.push({ data, ec });
252
+ }
253
+ };
254
+
255
+ makeBlocks(b1count, b1data);
256
+ if (b2count) makeBlocks(b2count, b2data);
257
+
258
+ const result = [];
259
+ const maxData = Math.max(b1data, b2data || 0);
260
+ for (let i = 0; i < maxData; i++)
261
+ for (const b of blocks) if (i < b.data.length) result.push(b.data[i]);
262
+ for (let i = 0; i < ecPerBlock; i++)
263
+ for (const b of blocks) result.push(b.ec[i]);
264
+
265
+ return result;
266
+ }
267
+
268
+ // ─── MATRIX ───────────────────────────────────────────────────────────────────
269
+
270
+ const DARK = 1, LIGHT = 0, RESERVED = 2;
271
+
272
+ function makeMatrix(size) {
273
+ return Array.from({ length: size }, () => new Int8Array(size).fill(-1));
274
+ }
275
+
276
+ function setFinderPattern(matrix, row, col) {
277
+ for (let r = -1; r <= 7; r++) {
278
+ for (let c = -1; c <= 7; c++) {
279
+ const mr = row + r, mc = col + c;
280
+ if (mr < 0 || mr >= matrix.length || mc < 0 || mc >= matrix.length) continue;
281
+ const inModule = r >= 0 && r <= 6 && c >= 0 && c <= 6;
282
+ const onBorder = r === 0 || r === 6 || c === 0 || c === 6;
283
+ const inInner = r >= 2 && r <= 4 && c >= 2 && c <= 4;
284
+ matrix[mr][mc] = inModule && (onBorder || inInner) ? DARK : LIGHT;
285
+ }
286
+ }
287
+ }
288
+
289
+ function setTimingPattern(matrix, size) {
290
+ for (let i = 8; i < size - 8; i++) {
291
+ const v = i % 2 === 0 ? DARK : LIGHT;
292
+ matrix[6][i] = v;
293
+ matrix[i][6] = v;
294
+ }
295
+ }
296
+
297
+ function setAlignmentPatterns(matrix, version) {
298
+ const pos = ALIGN_POS[version] || [];
299
+ for (const r of pos) {
300
+ for (const c of pos) {
301
+ if (matrix[r][c] !== -1) continue;
302
+ for (let dr = -2; dr <= 2; dr++) {
303
+ for (let dc = -2; dc <= 2; dc++) {
304
+ const onEdge = Math.abs(dr) === 2 || Math.abs(dc) === 2;
305
+ const center = dr === 0 && dc === 0;
306
+ matrix[r + dr][c + dc] = onEdge || center ? DARK : LIGHT;
307
+ }
308
+ }
309
+ }
310
+ }
311
+ }
312
+
313
+ function reserveFormatArea(matrix, size) {
314
+ // Reserve format info areas
315
+ for (let i = 0; i <= 8; i++) {
316
+ if (matrix[8][i] === -1) matrix[8][i] = RESERVED;
317
+ if (matrix[i][8] === -1) matrix[i][8] = RESERVED;
318
+ }
319
+ for (let i = size - 8; i < size; i++) {
320
+ if (matrix[8][i] === -1) matrix[8][i] = RESERVED;
321
+ if (matrix[i][8] === -1) matrix[i][8] = RESERVED;
322
+ }
323
+ // Dark module
324
+ matrix[size - 8][8] = DARK;
325
+ }
326
+
327
+ function reserveVersionArea(matrix, size, version) {
328
+ if (version < 7) return;
329
+ for (let i = 0; i < 6; i++) {
330
+ for (let j = size - 11; j < size - 8; j++) {
331
+ matrix[i][j] = RESERVED;
332
+ matrix[j][i] = RESERVED;
333
+ }
334
+ }
335
+ }
336
+
337
+ function placeData(matrix, size, data) {
338
+ let bitIdx = 0;
339
+ const bits = [];
340
+ for (const byte of data) for (let i = 7; i >= 0; i--) bits.push((byte >> i) & 1);
341
+
342
+ let up = true;
343
+ for (let col = size - 1; col >= 1; col -= 2) {
344
+ if (col === 6) col--;
345
+ for (let rowOff = 0; rowOff < size; rowOff++) {
346
+ const row = up ? size - 1 - rowOff : rowOff;
347
+ for (let dc = 0; dc < 2; dc++) {
348
+ const c = col - dc;
349
+ if (matrix[row][c] !== -1) continue;
350
+ matrix[row][c] = bitIdx < bits.length ? bits[bitIdx++] : LIGHT;
351
+ }
352
+ }
353
+ up = !up;
354
+ }
355
+ }
356
+
357
+ // Mask patterns
358
+ const MASKS = [
359
+ (r, c) => (r + c) % 2 === 0,
360
+ (r, _) => r % 2 === 0,
361
+ (_, c) => c % 3 === 0,
362
+ (r, c) => (r + c) % 3 === 0,
363
+ (r, c) => (Math.floor(r / 2) + Math.floor(c / 3)) % 2 === 0,
364
+ (r, c) => (r * c) % 2 + (r * c) % 3 === 0,
365
+ (r, c) => ((r * c) % 2 + (r * c) % 3) % 2 === 0,
366
+ (r, c) => ((r + c) % 2 + (r * c) % 3) % 2 === 0,
367
+ ];
368
+
369
+ function applyMask(matrix, size, maskIdx) {
370
+ const fn = MASKS[maskIdx];
371
+ const m = matrix.map(r => Int8Array.from(r));
372
+ for (let r = 0; r < size; r++)
373
+ for (let c = 0; c < size; c++)
374
+ if (m[r][c] !== RESERVED && fn(r, c)) m[r][c] ^= 1;
375
+ return m;
376
+ }
377
+
378
+ function penaltyScore(matrix, size) {
379
+ let score = 0;
380
+ // Rule 1: 5+ in a row
381
+ for (let r = 0; r < size; r++) {
382
+ for (let c = 0; c < size; ) {
383
+ const v = matrix[r][c];
384
+ let run = 1;
385
+ while (c + run < size && matrix[r][c + run] === v) run++;
386
+ if (run >= 5) score += 3 + (run - 5);
387
+ c += run;
388
+ }
389
+ }
390
+ for (let c = 0; c < size; c++) {
391
+ for (let r = 0; r < size; ) {
392
+ const v = matrix[r][c];
393
+ let run = 1;
394
+ while (r + run < size && matrix[r + run][c] === v) run++;
395
+ if (run >= 5) score += 3 + (run - 5);
396
+ r += run;
397
+ }
398
+ }
399
+ // Rule 2: 2×2 blocks
400
+ for (let r = 0; r < size - 1; r++)
401
+ for (let c = 0; c < size - 1; c++)
402
+ if (matrix[r][c] === matrix[r+1][c] &&
403
+ matrix[r][c] === matrix[r][c+1] &&
404
+ matrix[r][c] === matrix[r+1][c+1]) score += 3;
405
+ // Rule 3: finder-like patterns
406
+ const pat1 = [1,0,1,1,1,0,1,0,0,0,0];
407
+ const pat2 = [0,0,0,0,1,0,1,1,1,0,1];
408
+ const check = (arr) => {
409
+ for (let i = 0; i <= arr.length - 11; i++) {
410
+ if (pat1.every((v,j) => arr[i+j] === v) || pat2.every((v,j) => arr[i+j] === v)) score += 40;
411
+ }
412
+ };
413
+ for (let r = 0; r < size; r++) check(Array.from(matrix[r]));
414
+ for (let c = 0; c < size; c++) check(Array.from({ length: size }, (_,r) => matrix[r][c]));
415
+ // Rule 4: dark module ratio
416
+ let dark = 0;
417
+ for (let r = 0; r < size; r++) for (let c = 0; c < size; c++) if (matrix[r][c] === DARK) dark++;
418
+ const pct = dark / (size * size) * 100;
419
+ score += Math.abs(Math.floor(pct / 5) * 5 - 50) / 5 * 10 +
420
+ Math.abs(Math.ceil(pct / 5) * 5 - 50) / 5 * 10;
421
+ return score;
422
+ }
423
+
424
+ function writeFormatInfo(matrix, size, ecLevel, maskIdx) {
425
+ const info = FORMAT_INFO[ecLevel][maskIdx];
426
+ const bits = [];
427
+ for (let i = 14; i >= 0; i--) bits.push((info >> i) & 1);
428
+
429
+ // Around top-left finder
430
+ let bi = 0;
431
+ for (let i = 0; i <= 5; i++) matrix[8][i] = bits[bi++];
432
+ matrix[8][7] = bits[bi++];
433
+ matrix[8][8] = bits[bi++];
434
+ matrix[7][8] = bits[bi++];
435
+ for (let i = 5; i >= 0; i--) matrix[i][8] = bits[bi++];
436
+
437
+ // Bottom-left and top-right
438
+ bi = 0;
439
+ for (let i = size - 1; i >= size - 8; i--) matrix[i][8] = bits[bi++];
440
+ for (let i = size - 8; i < size; i++) matrix[8][i] = bits[bi++];
441
+ }
442
+
443
+ function writeVersionInfo(matrix, size, version) {
444
+ if (version < 7) return;
445
+ const info = VERSION_INFO[version];
446
+ let bi = 17;
447
+ for (let i = 0; i < 6; i++) {
448
+ for (let j = 0; j < 3; j++) {
449
+ const bit = (info >> bi--) & 1;
450
+ matrix[i][size - 11 + j] = bit;
451
+ matrix[size - 11 + j][i] = bit;
452
+ }
453
+ }
454
+ }
455
+
456
+ // ─── MAIN ENCODE ──────────────────────────────────────────────────────────────
457
+
458
+ function encode(text, opts = {}) {
459
+ const ecLevel = typeof opts.ec === 'string' ? EC[opts.ec.toUpperCase()] ?? EC.M : (opts.ec ?? EC.M);
460
+ const quiet = opts.quiet ?? 4;
461
+
462
+ // Find minimum version
463
+ const bytes = Buffer.from(text, 'utf8');
464
+ let version = opts.version ?? 0;
465
+
466
+ if (!version) {
467
+ // byte mode char count overhead: mode(4) + cc(8 for v1-9, 16 for v10+) + data
468
+ for (let v = 1; v <= 40; v++) {
469
+ const ccBits = v < 10 ? 8 : 16;
470
+ const needed = Math.ceil((4 + ccBits + bytes.length * 8) / 8);
471
+ if (needed <= DATA_CODEWORDS[v][ecLevel]) { version = v; break; }
472
+ }
473
+ }
474
+ if (!version) throw new Error('Data too large for QR code (max version 40)');
475
+
476
+ const size = version * 4 + 17;
477
+
478
+ // Build codewords
479
+ const dataWords = encodeData(text, version, ecLevel);
480
+ const finalWords = interleaveBlocks(dataWords, version, ecLevel);
481
+
482
+ // Build matrix
483
+ const matrix = makeMatrix(size);
484
+ setFinderPattern(matrix, 0, 0);
485
+ setFinderPattern(matrix, 0, size - 7);
486
+ setFinderPattern(matrix, size - 7, 0);
487
+ setTimingPattern(matrix, size);
488
+ setAlignmentPatterns(matrix, version);
489
+ reserveFormatArea(matrix, size);
490
+ reserveVersionArea(matrix, size, version);
491
+ placeData(matrix, size, finalWords);
492
+ writeVersionInfo(matrix, size, version);
493
+
494
+ // Choose best mask
495
+ let bestMask = 0, bestScore = Infinity;
496
+ for (let m = 0; m < 8; m++) {
497
+ const masked = applyMask(matrix, size, m);
498
+ writeFormatInfo(masked, size, ecLevel, m);
499
+ const s = penaltyScore(masked, size);
500
+ if (s < bestScore) { bestScore = s; bestMask = m; }
501
+ }
502
+
503
+ const finalMatrix = applyMask(matrix, size, bestMask);
504
+ writeFormatInfo(finalMatrix, size, ecLevel, bestMask);
505
+
506
+ return {
507
+ matrix: finalMatrix,
508
+ size,
509
+ version,
510
+ ec: EC_NAME[ecLevel],
511
+ mask: bestMask,
512
+ quiet,
513
+ };
514
+ }
515
+
516
+ // ─── RENDERERS ────────────────────────────────────────────────────────────────
517
+
518
+ function toAscii(qr, opts = {}) {
519
+ const dark = opts.dark ?? '##';
520
+ const light = opts.light ?? ' ';
521
+ const q = qr.quiet;
522
+ const pad = light.repeat(qr.size + q * 2);
523
+ const lines = [pad.repeat ? pad : pad];
524
+
525
+ const emptyRow = light.repeat(qr.size + q * 2);
526
+ for (let i = 0; i < q; i++) lines.push(emptyRow);
527
+
528
+ for (let r = 0; r < qr.size; r++) {
529
+ let line = light.repeat(q);
530
+ for (let c = 0; c < qr.size; c++) {
531
+ line += qr.matrix[r][c] === DARK ? dark : light;
532
+ }
533
+ line += light.repeat(q);
534
+ lines.push(line);
535
+ }
536
+ for (let i = 0; i < q; i++) lines.push(emptyRow);
537
+ return lines.join('\n');
538
+ }
539
+
540
+ function toUnicode(qr) {
541
+ // Uses half-block characters: each char covers 2 rows
542
+ const q = qr.quiet;
543
+ const wide = qr.size + q * 2;
544
+ const lines = [];
545
+ const get = (r, c) => {
546
+ const mr = r - q, mc = c - q;
547
+ if (mr < 0 || mr >= qr.size || mc < 0 || mc >= qr.size) return false;
548
+ return qr.matrix[mr][mc] === DARK;
549
+ };
550
+ for (let r = 0; r < qr.size + q * 2; r += 2) {
551
+ let line = '';
552
+ for (let c = 0; c < wide; c++) {
553
+ const top = get(r, c), bot = get(r + 1, c);
554
+ if (top && bot) line += '█';
555
+ else if (top) line += '▀';
556
+ else if (bot) line += '▄';
557
+ else line += ' ';
558
+ }
559
+ lines.push(line);
560
+ }
561
+ return lines.join('\n');
562
+ }
563
+
564
+ function toSVG(qr, opts = {}) {
565
+ const moduleSize = opts.moduleSize ?? 4;
566
+ const dark = opts.dark ?? '#000000';
567
+ const light = opts.light ?? '#ffffff';
568
+ const q = qr.quiet;
569
+ const total = (qr.size + q * 2) * moduleSize;
570
+
571
+ const rects = [];
572
+ for (let r = 0; r < qr.size; r++) {
573
+ for (let c = 0; c < qr.size; c++) {
574
+ if (qr.matrix[r][c] === DARK) {
575
+ const x = (c + q) * moduleSize;
576
+ const y = (r + q) * moduleSize;
577
+ rects.push(`<rect x="${x}" y="${y}" width="${moduleSize}" height="${moduleSize}" fill="${dark}"/>`);
578
+ }
579
+ }
580
+ }
581
+
582
+ return `<?xml version="1.0" encoding="UTF-8"?>
583
+ <svg xmlns="http://www.w3.org/2000/svg" version="1.1"
584
+ viewBox="0 0 ${total} ${total}" width="${total}" height="${total}">
585
+ <rect width="${total}" height="${total}" fill="${light}"/>
586
+ ${rects.join('\n ')}
587
+ </svg>`;
588
+ }
589
+
590
+ function toMatrix(qr) {
591
+ // Returns a plain 2D array of booleans (true=dark)
592
+ return qr.matrix.map(row => Array.from(row).map(v => v === DARK));
593
+ }
594
+
595
+ function toDataURL(qr, opts = {}) {
596
+ // Returns a data URL with SVG content (base64)
597
+ const svg = toSVG(qr, opts);
598
+ return 'data:image/svg+xml;base64,' + Buffer.from(svg).toString('base64');
599
+ }
600
+
601
+ // ─── HIGH-LEVEL API ───────────────────────────────────────────────────────────
602
+
603
+ function qr(text, opts = {}) {
604
+ const encoded = encode(text, opts);
605
+ const format = opts.format ?? 'unicode';
606
+ switch (format) {
607
+ case 'ascii': return toAscii(encoded, opts);
608
+ case 'unicode': return toUnicode(encoded);
609
+ case 'svg': return toSVG(encoded, opts);
610
+ case 'matrix': return toMatrix(encoded);
611
+ case 'dataurl': return toDataURL(encoded, opts);
612
+ case 'raw': return encoded;
613
+ default: throw new Error(`Unknown format: ${format}. Use 'ascii', 'unicode', 'svg', 'matrix', 'dataurl', or 'raw'.`);
614
+ }
615
+ }
616
+
617
+ // ─── EXPORTS ─────────────────────────────────────────────────────────────────
618
+
619
+ module.exports = {
620
+ kitdef: {
621
+ // High-level: encode and render in one call
622
+ qr,
623
+
624
+ // Low-level: encode only → returns raw QR object { matrix, size, version, ec, mask }
625
+ encode,
626
+
627
+ // Renderers (accept raw QR object)
628
+ toAscii,
629
+ toUnicode,
630
+ toSVG,
631
+ toMatrix,
632
+ toDataURL,
633
+
634
+ // EC level constants
635
+ EC,
636
+ }
637
+ };