lecodes-cli 0.6.2 → 0.6.3
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 +16 -3
- package/dist/index.js +1937 -132
- package/package.json +4 -1
- package/runtime/sdk/gl/Scene.ts +22 -0
- package/runtime/sdk/gl/touch.ts +14 -2
- package/runtime/sdk/inject.ts +1 -1
- package/runtime/sdk-types.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,14 +1,1111 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from "node:module";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
|
+
var __defProp = Object.defineProperty;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
function __accessProp(key) {
|
|
9
|
+
return this[key];
|
|
10
|
+
}
|
|
11
|
+
var __toESMCache_node;
|
|
12
|
+
var __toESMCache_esm;
|
|
13
|
+
var __toESM = (mod, isNodeMode, target) => {
|
|
14
|
+
var canCache = mod != null && typeof mod === "object";
|
|
15
|
+
if (canCache) {
|
|
16
|
+
var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
|
|
17
|
+
var cached = cache.get(mod);
|
|
18
|
+
if (cached)
|
|
19
|
+
return cached;
|
|
20
|
+
}
|
|
21
|
+
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
22
|
+
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
23
|
+
for (let key of __getOwnPropNames(mod))
|
|
24
|
+
if (!__hasOwnProp.call(to, key))
|
|
25
|
+
__defProp(to, key, {
|
|
26
|
+
get: __accessProp.bind(mod, key),
|
|
27
|
+
enumerable: true
|
|
28
|
+
});
|
|
29
|
+
if (canCache)
|
|
30
|
+
cache.set(mod, to);
|
|
31
|
+
return to;
|
|
32
|
+
};
|
|
33
|
+
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
3
34
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
4
35
|
|
|
5
|
-
//
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
36
|
+
// ../../node_modules/.bun/qrcode-terminal@0.12.0/node_modules/qrcode-terminal/vendor/QRCode/QRMode.js
|
|
37
|
+
var require_QRMode = __commonJS((exports, module) => {
|
|
38
|
+
module.exports = {
|
|
39
|
+
MODE_NUMBER: 1 << 0,
|
|
40
|
+
MODE_ALPHA_NUM: 1 << 1,
|
|
41
|
+
MODE_8BIT_BYTE: 1 << 2,
|
|
42
|
+
MODE_KANJI: 1 << 3
|
|
43
|
+
};
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
// ../../node_modules/.bun/qrcode-terminal@0.12.0/node_modules/qrcode-terminal/vendor/QRCode/QR8bitByte.js
|
|
47
|
+
var require_QR8bitByte = __commonJS((exports, module) => {
|
|
48
|
+
var QRMode = require_QRMode();
|
|
49
|
+
function QR8bitByte(data) {
|
|
50
|
+
this.mode = QRMode.MODE_8BIT_BYTE;
|
|
51
|
+
this.data = data;
|
|
52
|
+
}
|
|
53
|
+
QR8bitByte.prototype = {
|
|
54
|
+
getLength: function() {
|
|
55
|
+
return this.data.length;
|
|
56
|
+
},
|
|
57
|
+
write: function(buffer) {
|
|
58
|
+
for (var i = 0;i < this.data.length; i++) {
|
|
59
|
+
buffer.put(this.data.charCodeAt(i), 8);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
module.exports = QR8bitByte;
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
// ../../node_modules/.bun/qrcode-terminal@0.12.0/node_modules/qrcode-terminal/vendor/QRCode/QRMath.js
|
|
67
|
+
var require_QRMath = __commonJS((exports, module) => {
|
|
68
|
+
var QRMath = {
|
|
69
|
+
glog: function(n) {
|
|
70
|
+
if (n < 1) {
|
|
71
|
+
throw new Error("glog(" + n + ")");
|
|
72
|
+
}
|
|
73
|
+
return QRMath.LOG_TABLE[n];
|
|
74
|
+
},
|
|
75
|
+
gexp: function(n) {
|
|
76
|
+
while (n < 0) {
|
|
77
|
+
n += 255;
|
|
78
|
+
}
|
|
79
|
+
while (n >= 256) {
|
|
80
|
+
n -= 255;
|
|
81
|
+
}
|
|
82
|
+
return QRMath.EXP_TABLE[n];
|
|
83
|
+
},
|
|
84
|
+
EXP_TABLE: new Array(256),
|
|
85
|
+
LOG_TABLE: new Array(256)
|
|
86
|
+
};
|
|
87
|
+
for (i = 0;i < 8; i++) {
|
|
88
|
+
QRMath.EXP_TABLE[i] = 1 << i;
|
|
89
|
+
}
|
|
90
|
+
var i;
|
|
91
|
+
for (i = 8;i < 256; i++) {
|
|
92
|
+
QRMath.EXP_TABLE[i] = QRMath.EXP_TABLE[i - 4] ^ QRMath.EXP_TABLE[i - 5] ^ QRMath.EXP_TABLE[i - 6] ^ QRMath.EXP_TABLE[i - 8];
|
|
93
|
+
}
|
|
94
|
+
var i;
|
|
95
|
+
for (i = 0;i < 255; i++) {
|
|
96
|
+
QRMath.LOG_TABLE[QRMath.EXP_TABLE[i]] = i;
|
|
97
|
+
}
|
|
98
|
+
var i;
|
|
99
|
+
module.exports = QRMath;
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
// ../../node_modules/.bun/qrcode-terminal@0.12.0/node_modules/qrcode-terminal/vendor/QRCode/QRPolynomial.js
|
|
103
|
+
var require_QRPolynomial = __commonJS((exports, module) => {
|
|
104
|
+
var QRMath = require_QRMath();
|
|
105
|
+
function QRPolynomial(num, shift) {
|
|
106
|
+
if (num.length === undefined) {
|
|
107
|
+
throw new Error(num.length + "/" + shift);
|
|
108
|
+
}
|
|
109
|
+
var offset = 0;
|
|
110
|
+
while (offset < num.length && num[offset] === 0) {
|
|
111
|
+
offset++;
|
|
112
|
+
}
|
|
113
|
+
this.num = new Array(num.length - offset + shift);
|
|
114
|
+
for (var i = 0;i < num.length - offset; i++) {
|
|
115
|
+
this.num[i] = num[i + offset];
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
QRPolynomial.prototype = {
|
|
119
|
+
get: function(index) {
|
|
120
|
+
return this.num[index];
|
|
121
|
+
},
|
|
122
|
+
getLength: function() {
|
|
123
|
+
return this.num.length;
|
|
124
|
+
},
|
|
125
|
+
multiply: function(e) {
|
|
126
|
+
var num = new Array(this.getLength() + e.getLength() - 1);
|
|
127
|
+
for (var i = 0;i < this.getLength(); i++) {
|
|
128
|
+
for (var j = 0;j < e.getLength(); j++) {
|
|
129
|
+
num[i + j] ^= QRMath.gexp(QRMath.glog(this.get(i)) + QRMath.glog(e.get(j)));
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return new QRPolynomial(num, 0);
|
|
133
|
+
},
|
|
134
|
+
mod: function(e) {
|
|
135
|
+
if (this.getLength() - e.getLength() < 0) {
|
|
136
|
+
return this;
|
|
137
|
+
}
|
|
138
|
+
var ratio = QRMath.glog(this.get(0)) - QRMath.glog(e.get(0));
|
|
139
|
+
var num = new Array(this.getLength());
|
|
140
|
+
for (var i = 0;i < this.getLength(); i++) {
|
|
141
|
+
num[i] = this.get(i);
|
|
142
|
+
}
|
|
143
|
+
for (var x = 0;x < e.getLength(); x++) {
|
|
144
|
+
num[x] ^= QRMath.gexp(QRMath.glog(e.get(x)) + ratio);
|
|
145
|
+
}
|
|
146
|
+
return new QRPolynomial(num, 0).mod(e);
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
module.exports = QRPolynomial;
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
// ../../node_modules/.bun/qrcode-terminal@0.12.0/node_modules/qrcode-terminal/vendor/QRCode/QRMaskPattern.js
|
|
153
|
+
var require_QRMaskPattern = __commonJS((exports, module) => {
|
|
154
|
+
module.exports = {
|
|
155
|
+
PATTERN000: 0,
|
|
156
|
+
PATTERN001: 1,
|
|
157
|
+
PATTERN010: 2,
|
|
158
|
+
PATTERN011: 3,
|
|
159
|
+
PATTERN100: 4,
|
|
160
|
+
PATTERN101: 5,
|
|
161
|
+
PATTERN110: 6,
|
|
162
|
+
PATTERN111: 7
|
|
163
|
+
};
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
// ../../node_modules/.bun/qrcode-terminal@0.12.0/node_modules/qrcode-terminal/vendor/QRCode/QRUtil.js
|
|
167
|
+
var require_QRUtil = __commonJS((exports, module) => {
|
|
168
|
+
var QRMode = require_QRMode();
|
|
169
|
+
var QRPolynomial = require_QRPolynomial();
|
|
170
|
+
var QRMath = require_QRMath();
|
|
171
|
+
var QRMaskPattern = require_QRMaskPattern();
|
|
172
|
+
var QRUtil = {
|
|
173
|
+
PATTERN_POSITION_TABLE: [
|
|
174
|
+
[],
|
|
175
|
+
[6, 18],
|
|
176
|
+
[6, 22],
|
|
177
|
+
[6, 26],
|
|
178
|
+
[6, 30],
|
|
179
|
+
[6, 34],
|
|
180
|
+
[6, 22, 38],
|
|
181
|
+
[6, 24, 42],
|
|
182
|
+
[6, 26, 46],
|
|
183
|
+
[6, 28, 50],
|
|
184
|
+
[6, 30, 54],
|
|
185
|
+
[6, 32, 58],
|
|
186
|
+
[6, 34, 62],
|
|
187
|
+
[6, 26, 46, 66],
|
|
188
|
+
[6, 26, 48, 70],
|
|
189
|
+
[6, 26, 50, 74],
|
|
190
|
+
[6, 30, 54, 78],
|
|
191
|
+
[6, 30, 56, 82],
|
|
192
|
+
[6, 30, 58, 86],
|
|
193
|
+
[6, 34, 62, 90],
|
|
194
|
+
[6, 28, 50, 72, 94],
|
|
195
|
+
[6, 26, 50, 74, 98],
|
|
196
|
+
[6, 30, 54, 78, 102],
|
|
197
|
+
[6, 28, 54, 80, 106],
|
|
198
|
+
[6, 32, 58, 84, 110],
|
|
199
|
+
[6, 30, 58, 86, 114],
|
|
200
|
+
[6, 34, 62, 90, 118],
|
|
201
|
+
[6, 26, 50, 74, 98, 122],
|
|
202
|
+
[6, 30, 54, 78, 102, 126],
|
|
203
|
+
[6, 26, 52, 78, 104, 130],
|
|
204
|
+
[6, 30, 56, 82, 108, 134],
|
|
205
|
+
[6, 34, 60, 86, 112, 138],
|
|
206
|
+
[6, 30, 58, 86, 114, 142],
|
|
207
|
+
[6, 34, 62, 90, 118, 146],
|
|
208
|
+
[6, 30, 54, 78, 102, 126, 150],
|
|
209
|
+
[6, 24, 50, 76, 102, 128, 154],
|
|
210
|
+
[6, 28, 54, 80, 106, 132, 158],
|
|
211
|
+
[6, 32, 58, 84, 110, 136, 162],
|
|
212
|
+
[6, 26, 54, 82, 110, 138, 166],
|
|
213
|
+
[6, 30, 58, 86, 114, 142, 170]
|
|
214
|
+
],
|
|
215
|
+
G15: 1 << 10 | 1 << 8 | 1 << 5 | 1 << 4 | 1 << 2 | 1 << 1 | 1 << 0,
|
|
216
|
+
G18: 1 << 12 | 1 << 11 | 1 << 10 | 1 << 9 | 1 << 8 | 1 << 5 | 1 << 2 | 1 << 0,
|
|
217
|
+
G15_MASK: 1 << 14 | 1 << 12 | 1 << 10 | 1 << 4 | 1 << 1,
|
|
218
|
+
getBCHTypeInfo: function(data) {
|
|
219
|
+
var d = data << 10;
|
|
220
|
+
while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15) >= 0) {
|
|
221
|
+
d ^= QRUtil.G15 << QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15);
|
|
222
|
+
}
|
|
223
|
+
return (data << 10 | d) ^ QRUtil.G15_MASK;
|
|
224
|
+
},
|
|
225
|
+
getBCHTypeNumber: function(data) {
|
|
226
|
+
var d = data << 12;
|
|
227
|
+
while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18) >= 0) {
|
|
228
|
+
d ^= QRUtil.G18 << QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18);
|
|
229
|
+
}
|
|
230
|
+
return data << 12 | d;
|
|
231
|
+
},
|
|
232
|
+
getBCHDigit: function(data) {
|
|
233
|
+
var digit = 0;
|
|
234
|
+
while (data !== 0) {
|
|
235
|
+
digit++;
|
|
236
|
+
data >>>= 1;
|
|
237
|
+
}
|
|
238
|
+
return digit;
|
|
239
|
+
},
|
|
240
|
+
getPatternPosition: function(typeNumber) {
|
|
241
|
+
return QRUtil.PATTERN_POSITION_TABLE[typeNumber - 1];
|
|
242
|
+
},
|
|
243
|
+
getMask: function(maskPattern, i, j) {
|
|
244
|
+
switch (maskPattern) {
|
|
245
|
+
case QRMaskPattern.PATTERN000:
|
|
246
|
+
return (i + j) % 2 === 0;
|
|
247
|
+
case QRMaskPattern.PATTERN001:
|
|
248
|
+
return i % 2 === 0;
|
|
249
|
+
case QRMaskPattern.PATTERN010:
|
|
250
|
+
return j % 3 === 0;
|
|
251
|
+
case QRMaskPattern.PATTERN011:
|
|
252
|
+
return (i + j) % 3 === 0;
|
|
253
|
+
case QRMaskPattern.PATTERN100:
|
|
254
|
+
return (Math.floor(i / 2) + Math.floor(j / 3)) % 2 === 0;
|
|
255
|
+
case QRMaskPattern.PATTERN101:
|
|
256
|
+
return i * j % 2 + i * j % 3 === 0;
|
|
257
|
+
case QRMaskPattern.PATTERN110:
|
|
258
|
+
return (i * j % 2 + i * j % 3) % 2 === 0;
|
|
259
|
+
case QRMaskPattern.PATTERN111:
|
|
260
|
+
return (i * j % 3 + (i + j) % 2) % 2 === 0;
|
|
261
|
+
default:
|
|
262
|
+
throw new Error("bad maskPattern:" + maskPattern);
|
|
263
|
+
}
|
|
264
|
+
},
|
|
265
|
+
getErrorCorrectPolynomial: function(errorCorrectLength) {
|
|
266
|
+
var a = new QRPolynomial([1], 0);
|
|
267
|
+
for (var i = 0;i < errorCorrectLength; i++) {
|
|
268
|
+
a = a.multiply(new QRPolynomial([1, QRMath.gexp(i)], 0));
|
|
269
|
+
}
|
|
270
|
+
return a;
|
|
271
|
+
},
|
|
272
|
+
getLengthInBits: function(mode, type) {
|
|
273
|
+
if (1 <= type && type < 10) {
|
|
274
|
+
switch (mode) {
|
|
275
|
+
case QRMode.MODE_NUMBER:
|
|
276
|
+
return 10;
|
|
277
|
+
case QRMode.MODE_ALPHA_NUM:
|
|
278
|
+
return 9;
|
|
279
|
+
case QRMode.MODE_8BIT_BYTE:
|
|
280
|
+
return 8;
|
|
281
|
+
case QRMode.MODE_KANJI:
|
|
282
|
+
return 8;
|
|
283
|
+
default:
|
|
284
|
+
throw new Error("mode:" + mode);
|
|
285
|
+
}
|
|
286
|
+
} else if (type < 27) {
|
|
287
|
+
switch (mode) {
|
|
288
|
+
case QRMode.MODE_NUMBER:
|
|
289
|
+
return 12;
|
|
290
|
+
case QRMode.MODE_ALPHA_NUM:
|
|
291
|
+
return 11;
|
|
292
|
+
case QRMode.MODE_8BIT_BYTE:
|
|
293
|
+
return 16;
|
|
294
|
+
case QRMode.MODE_KANJI:
|
|
295
|
+
return 10;
|
|
296
|
+
default:
|
|
297
|
+
throw new Error("mode:" + mode);
|
|
298
|
+
}
|
|
299
|
+
} else if (type < 41) {
|
|
300
|
+
switch (mode) {
|
|
301
|
+
case QRMode.MODE_NUMBER:
|
|
302
|
+
return 14;
|
|
303
|
+
case QRMode.MODE_ALPHA_NUM:
|
|
304
|
+
return 13;
|
|
305
|
+
case QRMode.MODE_8BIT_BYTE:
|
|
306
|
+
return 16;
|
|
307
|
+
case QRMode.MODE_KANJI:
|
|
308
|
+
return 12;
|
|
309
|
+
default:
|
|
310
|
+
throw new Error("mode:" + mode);
|
|
311
|
+
}
|
|
312
|
+
} else {
|
|
313
|
+
throw new Error("type:" + type);
|
|
314
|
+
}
|
|
315
|
+
},
|
|
316
|
+
getLostPoint: function(qrCode) {
|
|
317
|
+
var moduleCount = qrCode.getModuleCount();
|
|
318
|
+
var lostPoint = 0;
|
|
319
|
+
var row = 0;
|
|
320
|
+
var col = 0;
|
|
321
|
+
for (row = 0;row < moduleCount; row++) {
|
|
322
|
+
for (col = 0;col < moduleCount; col++) {
|
|
323
|
+
var sameCount = 0;
|
|
324
|
+
var dark = qrCode.isDark(row, col);
|
|
325
|
+
for (var r = -1;r <= 1; r++) {
|
|
326
|
+
if (row + r < 0 || moduleCount <= row + r) {
|
|
327
|
+
continue;
|
|
328
|
+
}
|
|
329
|
+
for (var c2 = -1;c2 <= 1; c2++) {
|
|
330
|
+
if (col + c2 < 0 || moduleCount <= col + c2) {
|
|
331
|
+
continue;
|
|
332
|
+
}
|
|
333
|
+
if (r === 0 && c2 === 0) {
|
|
334
|
+
continue;
|
|
335
|
+
}
|
|
336
|
+
if (dark === qrCode.isDark(row + r, col + c2)) {
|
|
337
|
+
sameCount++;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
if (sameCount > 5) {
|
|
342
|
+
lostPoint += 3 + sameCount - 5;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
for (row = 0;row < moduleCount - 1; row++) {
|
|
347
|
+
for (col = 0;col < moduleCount - 1; col++) {
|
|
348
|
+
var count = 0;
|
|
349
|
+
if (qrCode.isDark(row, col))
|
|
350
|
+
count++;
|
|
351
|
+
if (qrCode.isDark(row + 1, col))
|
|
352
|
+
count++;
|
|
353
|
+
if (qrCode.isDark(row, col + 1))
|
|
354
|
+
count++;
|
|
355
|
+
if (qrCode.isDark(row + 1, col + 1))
|
|
356
|
+
count++;
|
|
357
|
+
if (count === 0 || count === 4) {
|
|
358
|
+
lostPoint += 3;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
for (row = 0;row < moduleCount; row++) {
|
|
363
|
+
for (col = 0;col < moduleCount - 6; col++) {
|
|
364
|
+
if (qrCode.isDark(row, col) && !qrCode.isDark(row, col + 1) && qrCode.isDark(row, col + 2) && qrCode.isDark(row, col + 3) && qrCode.isDark(row, col + 4) && !qrCode.isDark(row, col + 5) && qrCode.isDark(row, col + 6)) {
|
|
365
|
+
lostPoint += 40;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
for (col = 0;col < moduleCount; col++) {
|
|
370
|
+
for (row = 0;row < moduleCount - 6; row++) {
|
|
371
|
+
if (qrCode.isDark(row, col) && !qrCode.isDark(row + 1, col) && qrCode.isDark(row + 2, col) && qrCode.isDark(row + 3, col) && qrCode.isDark(row + 4, col) && !qrCode.isDark(row + 5, col) && qrCode.isDark(row + 6, col)) {
|
|
372
|
+
lostPoint += 40;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
var darkCount = 0;
|
|
377
|
+
for (col = 0;col < moduleCount; col++) {
|
|
378
|
+
for (row = 0;row < moduleCount; row++) {
|
|
379
|
+
if (qrCode.isDark(row, col)) {
|
|
380
|
+
darkCount++;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
var ratio = Math.abs(100 * darkCount / moduleCount / moduleCount - 50) / 5;
|
|
385
|
+
lostPoint += ratio * 10;
|
|
386
|
+
return lostPoint;
|
|
387
|
+
}
|
|
388
|
+
};
|
|
389
|
+
module.exports = QRUtil;
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
// ../../node_modules/.bun/qrcode-terminal@0.12.0/node_modules/qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel.js
|
|
393
|
+
var require_QRErrorCorrectLevel = __commonJS((exports, module) => {
|
|
394
|
+
module.exports = {
|
|
395
|
+
L: 1,
|
|
396
|
+
M: 0,
|
|
397
|
+
Q: 3,
|
|
398
|
+
H: 2
|
|
399
|
+
};
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
// ../../node_modules/.bun/qrcode-terminal@0.12.0/node_modules/qrcode-terminal/vendor/QRCode/QRRSBlock.js
|
|
403
|
+
var require_QRRSBlock = __commonJS((exports, module) => {
|
|
404
|
+
var QRErrorCorrectLevel = require_QRErrorCorrectLevel();
|
|
405
|
+
function QRRSBlock(totalCount, dataCount) {
|
|
406
|
+
this.totalCount = totalCount;
|
|
407
|
+
this.dataCount = dataCount;
|
|
408
|
+
}
|
|
409
|
+
QRRSBlock.RS_BLOCK_TABLE = [
|
|
410
|
+
[1, 26, 19],
|
|
411
|
+
[1, 26, 16],
|
|
412
|
+
[1, 26, 13],
|
|
413
|
+
[1, 26, 9],
|
|
414
|
+
[1, 44, 34],
|
|
415
|
+
[1, 44, 28],
|
|
416
|
+
[1, 44, 22],
|
|
417
|
+
[1, 44, 16],
|
|
418
|
+
[1, 70, 55],
|
|
419
|
+
[1, 70, 44],
|
|
420
|
+
[2, 35, 17],
|
|
421
|
+
[2, 35, 13],
|
|
422
|
+
[1, 100, 80],
|
|
423
|
+
[2, 50, 32],
|
|
424
|
+
[2, 50, 24],
|
|
425
|
+
[4, 25, 9],
|
|
426
|
+
[1, 134, 108],
|
|
427
|
+
[2, 67, 43],
|
|
428
|
+
[2, 33, 15, 2, 34, 16],
|
|
429
|
+
[2, 33, 11, 2, 34, 12],
|
|
430
|
+
[2, 86, 68],
|
|
431
|
+
[4, 43, 27],
|
|
432
|
+
[4, 43, 19],
|
|
433
|
+
[4, 43, 15],
|
|
434
|
+
[2, 98, 78],
|
|
435
|
+
[4, 49, 31],
|
|
436
|
+
[2, 32, 14, 4, 33, 15],
|
|
437
|
+
[4, 39, 13, 1, 40, 14],
|
|
438
|
+
[2, 121, 97],
|
|
439
|
+
[2, 60, 38, 2, 61, 39],
|
|
440
|
+
[4, 40, 18, 2, 41, 19],
|
|
441
|
+
[4, 40, 14, 2, 41, 15],
|
|
442
|
+
[2, 146, 116],
|
|
443
|
+
[3, 58, 36, 2, 59, 37],
|
|
444
|
+
[4, 36, 16, 4, 37, 17],
|
|
445
|
+
[4, 36, 12, 4, 37, 13],
|
|
446
|
+
[2, 86, 68, 2, 87, 69],
|
|
447
|
+
[4, 69, 43, 1, 70, 44],
|
|
448
|
+
[6, 43, 19, 2, 44, 20],
|
|
449
|
+
[6, 43, 15, 2, 44, 16],
|
|
450
|
+
[4, 101, 81],
|
|
451
|
+
[1, 80, 50, 4, 81, 51],
|
|
452
|
+
[4, 50, 22, 4, 51, 23],
|
|
453
|
+
[3, 36, 12, 8, 37, 13],
|
|
454
|
+
[2, 116, 92, 2, 117, 93],
|
|
455
|
+
[6, 58, 36, 2, 59, 37],
|
|
456
|
+
[4, 46, 20, 6, 47, 21],
|
|
457
|
+
[7, 42, 14, 4, 43, 15],
|
|
458
|
+
[4, 133, 107],
|
|
459
|
+
[8, 59, 37, 1, 60, 38],
|
|
460
|
+
[8, 44, 20, 4, 45, 21],
|
|
461
|
+
[12, 33, 11, 4, 34, 12],
|
|
462
|
+
[3, 145, 115, 1, 146, 116],
|
|
463
|
+
[4, 64, 40, 5, 65, 41],
|
|
464
|
+
[11, 36, 16, 5, 37, 17],
|
|
465
|
+
[11, 36, 12, 5, 37, 13],
|
|
466
|
+
[5, 109, 87, 1, 110, 88],
|
|
467
|
+
[5, 65, 41, 5, 66, 42],
|
|
468
|
+
[5, 54, 24, 7, 55, 25],
|
|
469
|
+
[11, 36, 12],
|
|
470
|
+
[5, 122, 98, 1, 123, 99],
|
|
471
|
+
[7, 73, 45, 3, 74, 46],
|
|
472
|
+
[15, 43, 19, 2, 44, 20],
|
|
473
|
+
[3, 45, 15, 13, 46, 16],
|
|
474
|
+
[1, 135, 107, 5, 136, 108],
|
|
475
|
+
[10, 74, 46, 1, 75, 47],
|
|
476
|
+
[1, 50, 22, 15, 51, 23],
|
|
477
|
+
[2, 42, 14, 17, 43, 15],
|
|
478
|
+
[5, 150, 120, 1, 151, 121],
|
|
479
|
+
[9, 69, 43, 4, 70, 44],
|
|
480
|
+
[17, 50, 22, 1, 51, 23],
|
|
481
|
+
[2, 42, 14, 19, 43, 15],
|
|
482
|
+
[3, 141, 113, 4, 142, 114],
|
|
483
|
+
[3, 70, 44, 11, 71, 45],
|
|
484
|
+
[17, 47, 21, 4, 48, 22],
|
|
485
|
+
[9, 39, 13, 16, 40, 14],
|
|
486
|
+
[3, 135, 107, 5, 136, 108],
|
|
487
|
+
[3, 67, 41, 13, 68, 42],
|
|
488
|
+
[15, 54, 24, 5, 55, 25],
|
|
489
|
+
[15, 43, 15, 10, 44, 16],
|
|
490
|
+
[4, 144, 116, 4, 145, 117],
|
|
491
|
+
[17, 68, 42],
|
|
492
|
+
[17, 50, 22, 6, 51, 23],
|
|
493
|
+
[19, 46, 16, 6, 47, 17],
|
|
494
|
+
[2, 139, 111, 7, 140, 112],
|
|
495
|
+
[17, 74, 46],
|
|
496
|
+
[7, 54, 24, 16, 55, 25],
|
|
497
|
+
[34, 37, 13],
|
|
498
|
+
[4, 151, 121, 5, 152, 122],
|
|
499
|
+
[4, 75, 47, 14, 76, 48],
|
|
500
|
+
[11, 54, 24, 14, 55, 25],
|
|
501
|
+
[16, 45, 15, 14, 46, 16],
|
|
502
|
+
[6, 147, 117, 4, 148, 118],
|
|
503
|
+
[6, 73, 45, 14, 74, 46],
|
|
504
|
+
[11, 54, 24, 16, 55, 25],
|
|
505
|
+
[30, 46, 16, 2, 47, 17],
|
|
506
|
+
[8, 132, 106, 4, 133, 107],
|
|
507
|
+
[8, 75, 47, 13, 76, 48],
|
|
508
|
+
[7, 54, 24, 22, 55, 25],
|
|
509
|
+
[22, 45, 15, 13, 46, 16],
|
|
510
|
+
[10, 142, 114, 2, 143, 115],
|
|
511
|
+
[19, 74, 46, 4, 75, 47],
|
|
512
|
+
[28, 50, 22, 6, 51, 23],
|
|
513
|
+
[33, 46, 16, 4, 47, 17],
|
|
514
|
+
[8, 152, 122, 4, 153, 123],
|
|
515
|
+
[22, 73, 45, 3, 74, 46],
|
|
516
|
+
[8, 53, 23, 26, 54, 24],
|
|
517
|
+
[12, 45, 15, 28, 46, 16],
|
|
518
|
+
[3, 147, 117, 10, 148, 118],
|
|
519
|
+
[3, 73, 45, 23, 74, 46],
|
|
520
|
+
[4, 54, 24, 31, 55, 25],
|
|
521
|
+
[11, 45, 15, 31, 46, 16],
|
|
522
|
+
[7, 146, 116, 7, 147, 117],
|
|
523
|
+
[21, 73, 45, 7, 74, 46],
|
|
524
|
+
[1, 53, 23, 37, 54, 24],
|
|
525
|
+
[19, 45, 15, 26, 46, 16],
|
|
526
|
+
[5, 145, 115, 10, 146, 116],
|
|
527
|
+
[19, 75, 47, 10, 76, 48],
|
|
528
|
+
[15, 54, 24, 25, 55, 25],
|
|
529
|
+
[23, 45, 15, 25, 46, 16],
|
|
530
|
+
[13, 145, 115, 3, 146, 116],
|
|
531
|
+
[2, 74, 46, 29, 75, 47],
|
|
532
|
+
[42, 54, 24, 1, 55, 25],
|
|
533
|
+
[23, 45, 15, 28, 46, 16],
|
|
534
|
+
[17, 145, 115],
|
|
535
|
+
[10, 74, 46, 23, 75, 47],
|
|
536
|
+
[10, 54, 24, 35, 55, 25],
|
|
537
|
+
[19, 45, 15, 35, 46, 16],
|
|
538
|
+
[17, 145, 115, 1, 146, 116],
|
|
539
|
+
[14, 74, 46, 21, 75, 47],
|
|
540
|
+
[29, 54, 24, 19, 55, 25],
|
|
541
|
+
[11, 45, 15, 46, 46, 16],
|
|
542
|
+
[13, 145, 115, 6, 146, 116],
|
|
543
|
+
[14, 74, 46, 23, 75, 47],
|
|
544
|
+
[44, 54, 24, 7, 55, 25],
|
|
545
|
+
[59, 46, 16, 1, 47, 17],
|
|
546
|
+
[12, 151, 121, 7, 152, 122],
|
|
547
|
+
[12, 75, 47, 26, 76, 48],
|
|
548
|
+
[39, 54, 24, 14, 55, 25],
|
|
549
|
+
[22, 45, 15, 41, 46, 16],
|
|
550
|
+
[6, 151, 121, 14, 152, 122],
|
|
551
|
+
[6, 75, 47, 34, 76, 48],
|
|
552
|
+
[46, 54, 24, 10, 55, 25],
|
|
553
|
+
[2, 45, 15, 64, 46, 16],
|
|
554
|
+
[17, 152, 122, 4, 153, 123],
|
|
555
|
+
[29, 74, 46, 14, 75, 47],
|
|
556
|
+
[49, 54, 24, 10, 55, 25],
|
|
557
|
+
[24, 45, 15, 46, 46, 16],
|
|
558
|
+
[4, 152, 122, 18, 153, 123],
|
|
559
|
+
[13, 74, 46, 32, 75, 47],
|
|
560
|
+
[48, 54, 24, 14, 55, 25],
|
|
561
|
+
[42, 45, 15, 32, 46, 16],
|
|
562
|
+
[20, 147, 117, 4, 148, 118],
|
|
563
|
+
[40, 75, 47, 7, 76, 48],
|
|
564
|
+
[43, 54, 24, 22, 55, 25],
|
|
565
|
+
[10, 45, 15, 67, 46, 16],
|
|
566
|
+
[19, 148, 118, 6, 149, 119],
|
|
567
|
+
[18, 75, 47, 31, 76, 48],
|
|
568
|
+
[34, 54, 24, 34, 55, 25],
|
|
569
|
+
[20, 45, 15, 61, 46, 16]
|
|
570
|
+
];
|
|
571
|
+
QRRSBlock.getRSBlocks = function(typeNumber, errorCorrectLevel) {
|
|
572
|
+
var rsBlock = QRRSBlock.getRsBlockTable(typeNumber, errorCorrectLevel);
|
|
573
|
+
if (rsBlock === undefined) {
|
|
574
|
+
throw new Error("bad rs block @ typeNumber:" + typeNumber + "/errorCorrectLevel:" + errorCorrectLevel);
|
|
575
|
+
}
|
|
576
|
+
var length = rsBlock.length / 3;
|
|
577
|
+
var list = [];
|
|
578
|
+
for (var i = 0;i < length; i++) {
|
|
579
|
+
var count = rsBlock[i * 3 + 0];
|
|
580
|
+
var totalCount = rsBlock[i * 3 + 1];
|
|
581
|
+
var dataCount = rsBlock[i * 3 + 2];
|
|
582
|
+
for (var j = 0;j < count; j++) {
|
|
583
|
+
list.push(new QRRSBlock(totalCount, dataCount));
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
return list;
|
|
587
|
+
};
|
|
588
|
+
QRRSBlock.getRsBlockTable = function(typeNumber, errorCorrectLevel) {
|
|
589
|
+
switch (errorCorrectLevel) {
|
|
590
|
+
case QRErrorCorrectLevel.L:
|
|
591
|
+
return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 0];
|
|
592
|
+
case QRErrorCorrectLevel.M:
|
|
593
|
+
return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 1];
|
|
594
|
+
case QRErrorCorrectLevel.Q:
|
|
595
|
+
return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 2];
|
|
596
|
+
case QRErrorCorrectLevel.H:
|
|
597
|
+
return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 3];
|
|
598
|
+
default:
|
|
599
|
+
return;
|
|
600
|
+
}
|
|
601
|
+
};
|
|
602
|
+
module.exports = QRRSBlock;
|
|
603
|
+
});
|
|
604
|
+
|
|
605
|
+
// ../../node_modules/.bun/qrcode-terminal@0.12.0/node_modules/qrcode-terminal/vendor/QRCode/QRBitBuffer.js
|
|
606
|
+
var require_QRBitBuffer = __commonJS((exports, module) => {
|
|
607
|
+
function QRBitBuffer() {
|
|
608
|
+
this.buffer = [];
|
|
609
|
+
this.length = 0;
|
|
610
|
+
}
|
|
611
|
+
QRBitBuffer.prototype = {
|
|
612
|
+
get: function(index) {
|
|
613
|
+
var bufIndex = Math.floor(index / 8);
|
|
614
|
+
return (this.buffer[bufIndex] >>> 7 - index % 8 & 1) == 1;
|
|
615
|
+
},
|
|
616
|
+
put: function(num, length) {
|
|
617
|
+
for (var i = 0;i < length; i++) {
|
|
618
|
+
this.putBit((num >>> length - i - 1 & 1) == 1);
|
|
619
|
+
}
|
|
620
|
+
},
|
|
621
|
+
getLengthInBits: function() {
|
|
622
|
+
return this.length;
|
|
623
|
+
},
|
|
624
|
+
putBit: function(bit) {
|
|
625
|
+
var bufIndex = Math.floor(this.length / 8);
|
|
626
|
+
if (this.buffer.length <= bufIndex) {
|
|
627
|
+
this.buffer.push(0);
|
|
628
|
+
}
|
|
629
|
+
if (bit) {
|
|
630
|
+
this.buffer[bufIndex] |= 128 >>> this.length % 8;
|
|
631
|
+
}
|
|
632
|
+
this.length++;
|
|
633
|
+
}
|
|
634
|
+
};
|
|
635
|
+
module.exports = QRBitBuffer;
|
|
636
|
+
});
|
|
637
|
+
|
|
638
|
+
// ../../node_modules/.bun/qrcode-terminal@0.12.0/node_modules/qrcode-terminal/vendor/QRCode/index.js
|
|
639
|
+
var require_QRCode = __commonJS((exports, module) => {
|
|
640
|
+
var QR8bitByte = require_QR8bitByte();
|
|
641
|
+
var QRUtil = require_QRUtil();
|
|
642
|
+
var QRPolynomial = require_QRPolynomial();
|
|
643
|
+
var QRRSBlock = require_QRRSBlock();
|
|
644
|
+
var QRBitBuffer = require_QRBitBuffer();
|
|
645
|
+
function QRCode(typeNumber, errorCorrectLevel) {
|
|
646
|
+
this.typeNumber = typeNumber;
|
|
647
|
+
this.errorCorrectLevel = errorCorrectLevel;
|
|
648
|
+
this.modules = null;
|
|
649
|
+
this.moduleCount = 0;
|
|
650
|
+
this.dataCache = null;
|
|
651
|
+
this.dataList = [];
|
|
652
|
+
}
|
|
653
|
+
QRCode.prototype = {
|
|
654
|
+
addData: function(data) {
|
|
655
|
+
var newData = new QR8bitByte(data);
|
|
656
|
+
this.dataList.push(newData);
|
|
657
|
+
this.dataCache = null;
|
|
658
|
+
},
|
|
659
|
+
isDark: function(row, col) {
|
|
660
|
+
if (row < 0 || this.moduleCount <= row || col < 0 || this.moduleCount <= col) {
|
|
661
|
+
throw new Error(row + "," + col);
|
|
662
|
+
}
|
|
663
|
+
return this.modules[row][col];
|
|
664
|
+
},
|
|
665
|
+
getModuleCount: function() {
|
|
666
|
+
return this.moduleCount;
|
|
667
|
+
},
|
|
668
|
+
make: function() {
|
|
669
|
+
if (this.typeNumber < 1) {
|
|
670
|
+
var typeNumber = 1;
|
|
671
|
+
for (typeNumber = 1;typeNumber < 40; typeNumber++) {
|
|
672
|
+
var rsBlocks = QRRSBlock.getRSBlocks(typeNumber, this.errorCorrectLevel);
|
|
673
|
+
var buffer = new QRBitBuffer;
|
|
674
|
+
var totalDataCount = 0;
|
|
675
|
+
for (var i = 0;i < rsBlocks.length; i++) {
|
|
676
|
+
totalDataCount += rsBlocks[i].dataCount;
|
|
677
|
+
}
|
|
678
|
+
for (var x = 0;x < this.dataList.length; x++) {
|
|
679
|
+
var data = this.dataList[x];
|
|
680
|
+
buffer.put(data.mode, 4);
|
|
681
|
+
buffer.put(data.getLength(), QRUtil.getLengthInBits(data.mode, typeNumber));
|
|
682
|
+
data.write(buffer);
|
|
683
|
+
}
|
|
684
|
+
if (buffer.getLengthInBits() <= totalDataCount * 8)
|
|
685
|
+
break;
|
|
686
|
+
}
|
|
687
|
+
this.typeNumber = typeNumber;
|
|
688
|
+
}
|
|
689
|
+
this.makeImpl(false, this.getBestMaskPattern());
|
|
690
|
+
},
|
|
691
|
+
makeImpl: function(test, maskPattern) {
|
|
692
|
+
this.moduleCount = this.typeNumber * 4 + 17;
|
|
693
|
+
this.modules = new Array(this.moduleCount);
|
|
694
|
+
for (var row = 0;row < this.moduleCount; row++) {
|
|
695
|
+
this.modules[row] = new Array(this.moduleCount);
|
|
696
|
+
for (var col = 0;col < this.moduleCount; col++) {
|
|
697
|
+
this.modules[row][col] = null;
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
this.setupPositionProbePattern(0, 0);
|
|
701
|
+
this.setupPositionProbePattern(this.moduleCount - 7, 0);
|
|
702
|
+
this.setupPositionProbePattern(0, this.moduleCount - 7);
|
|
703
|
+
this.setupPositionAdjustPattern();
|
|
704
|
+
this.setupTimingPattern();
|
|
705
|
+
this.setupTypeInfo(test, maskPattern);
|
|
706
|
+
if (this.typeNumber >= 7) {
|
|
707
|
+
this.setupTypeNumber(test);
|
|
708
|
+
}
|
|
709
|
+
if (this.dataCache === null) {
|
|
710
|
+
this.dataCache = QRCode.createData(this.typeNumber, this.errorCorrectLevel, this.dataList);
|
|
711
|
+
}
|
|
712
|
+
this.mapData(this.dataCache, maskPattern);
|
|
713
|
+
},
|
|
714
|
+
setupPositionProbePattern: function(row, col) {
|
|
715
|
+
for (var r = -1;r <= 7; r++) {
|
|
716
|
+
if (row + r <= -1 || this.moduleCount <= row + r)
|
|
717
|
+
continue;
|
|
718
|
+
for (var c2 = -1;c2 <= 7; c2++) {
|
|
719
|
+
if (col + c2 <= -1 || this.moduleCount <= col + c2)
|
|
720
|
+
continue;
|
|
721
|
+
if (0 <= r && r <= 6 && (c2 === 0 || c2 === 6) || 0 <= c2 && c2 <= 6 && (r === 0 || r === 6) || 2 <= r && r <= 4 && 2 <= c2 && c2 <= 4) {
|
|
722
|
+
this.modules[row + r][col + c2] = true;
|
|
723
|
+
} else {
|
|
724
|
+
this.modules[row + r][col + c2] = false;
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
},
|
|
729
|
+
getBestMaskPattern: function() {
|
|
730
|
+
var minLostPoint = 0;
|
|
731
|
+
var pattern = 0;
|
|
732
|
+
for (var i = 0;i < 8; i++) {
|
|
733
|
+
this.makeImpl(true, i);
|
|
734
|
+
var lostPoint = QRUtil.getLostPoint(this);
|
|
735
|
+
if (i === 0 || minLostPoint > lostPoint) {
|
|
736
|
+
minLostPoint = lostPoint;
|
|
737
|
+
pattern = i;
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
return pattern;
|
|
741
|
+
},
|
|
742
|
+
createMovieClip: function(target_mc, instance_name, depth) {
|
|
743
|
+
var qr_mc = target_mc.createEmptyMovieClip(instance_name, depth);
|
|
744
|
+
var cs = 1;
|
|
745
|
+
this.make();
|
|
746
|
+
for (var row = 0;row < this.modules.length; row++) {
|
|
747
|
+
var y = row * cs;
|
|
748
|
+
for (var col = 0;col < this.modules[row].length; col++) {
|
|
749
|
+
var x = col * cs;
|
|
750
|
+
var dark = this.modules[row][col];
|
|
751
|
+
if (dark) {
|
|
752
|
+
qr_mc.beginFill(0, 100);
|
|
753
|
+
qr_mc.moveTo(x, y);
|
|
754
|
+
qr_mc.lineTo(x + cs, y);
|
|
755
|
+
qr_mc.lineTo(x + cs, y + cs);
|
|
756
|
+
qr_mc.lineTo(x, y + cs);
|
|
757
|
+
qr_mc.endFill();
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
return qr_mc;
|
|
762
|
+
},
|
|
763
|
+
setupTimingPattern: function() {
|
|
764
|
+
for (var r = 8;r < this.moduleCount - 8; r++) {
|
|
765
|
+
if (this.modules[r][6] !== null) {
|
|
766
|
+
continue;
|
|
767
|
+
}
|
|
768
|
+
this.modules[r][6] = r % 2 === 0;
|
|
769
|
+
}
|
|
770
|
+
for (var c2 = 8;c2 < this.moduleCount - 8; c2++) {
|
|
771
|
+
if (this.modules[6][c2] !== null) {
|
|
772
|
+
continue;
|
|
773
|
+
}
|
|
774
|
+
this.modules[6][c2] = c2 % 2 === 0;
|
|
775
|
+
}
|
|
776
|
+
},
|
|
777
|
+
setupPositionAdjustPattern: function() {
|
|
778
|
+
var pos = QRUtil.getPatternPosition(this.typeNumber);
|
|
779
|
+
for (var i = 0;i < pos.length; i++) {
|
|
780
|
+
for (var j = 0;j < pos.length; j++) {
|
|
781
|
+
var row = pos[i];
|
|
782
|
+
var col = pos[j];
|
|
783
|
+
if (this.modules[row][col] !== null) {
|
|
784
|
+
continue;
|
|
785
|
+
}
|
|
786
|
+
for (var r = -2;r <= 2; r++) {
|
|
787
|
+
for (var c2 = -2;c2 <= 2; c2++) {
|
|
788
|
+
if (Math.abs(r) === 2 || Math.abs(c2) === 2 || r === 0 && c2 === 0) {
|
|
789
|
+
this.modules[row + r][col + c2] = true;
|
|
790
|
+
} else {
|
|
791
|
+
this.modules[row + r][col + c2] = false;
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
},
|
|
798
|
+
setupTypeNumber: function(test) {
|
|
799
|
+
var bits = QRUtil.getBCHTypeNumber(this.typeNumber);
|
|
800
|
+
var mod;
|
|
801
|
+
for (var i = 0;i < 18; i++) {
|
|
802
|
+
mod = !test && (bits >> i & 1) === 1;
|
|
803
|
+
this.modules[Math.floor(i / 3)][i % 3 + this.moduleCount - 8 - 3] = mod;
|
|
804
|
+
}
|
|
805
|
+
for (var x = 0;x < 18; x++) {
|
|
806
|
+
mod = !test && (bits >> x & 1) === 1;
|
|
807
|
+
this.modules[x % 3 + this.moduleCount - 8 - 3][Math.floor(x / 3)] = mod;
|
|
808
|
+
}
|
|
809
|
+
},
|
|
810
|
+
setupTypeInfo: function(test, maskPattern) {
|
|
811
|
+
var data = this.errorCorrectLevel << 3 | maskPattern;
|
|
812
|
+
var bits = QRUtil.getBCHTypeInfo(data);
|
|
813
|
+
var mod;
|
|
814
|
+
for (var v = 0;v < 15; v++) {
|
|
815
|
+
mod = !test && (bits >> v & 1) === 1;
|
|
816
|
+
if (v < 6) {
|
|
817
|
+
this.modules[v][8] = mod;
|
|
818
|
+
} else if (v < 8) {
|
|
819
|
+
this.modules[v + 1][8] = mod;
|
|
820
|
+
} else {
|
|
821
|
+
this.modules[this.moduleCount - 15 + v][8] = mod;
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
for (var h = 0;h < 15; h++) {
|
|
825
|
+
mod = !test && (bits >> h & 1) === 1;
|
|
826
|
+
if (h < 8) {
|
|
827
|
+
this.modules[8][this.moduleCount - h - 1] = mod;
|
|
828
|
+
} else if (h < 9) {
|
|
829
|
+
this.modules[8][15 - h - 1 + 1] = mod;
|
|
830
|
+
} else {
|
|
831
|
+
this.modules[8][15 - h - 1] = mod;
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
this.modules[this.moduleCount - 8][8] = !test;
|
|
835
|
+
},
|
|
836
|
+
mapData: function(data, maskPattern) {
|
|
837
|
+
var inc = -1;
|
|
838
|
+
var row = this.moduleCount - 1;
|
|
839
|
+
var bitIndex = 7;
|
|
840
|
+
var byteIndex = 0;
|
|
841
|
+
for (var col = this.moduleCount - 1;col > 0; col -= 2) {
|
|
842
|
+
if (col === 6)
|
|
843
|
+
col--;
|
|
844
|
+
while (true) {
|
|
845
|
+
for (var c2 = 0;c2 < 2; c2++) {
|
|
846
|
+
if (this.modules[row][col - c2] === null) {
|
|
847
|
+
var dark = false;
|
|
848
|
+
if (byteIndex < data.length) {
|
|
849
|
+
dark = (data[byteIndex] >>> bitIndex & 1) === 1;
|
|
850
|
+
}
|
|
851
|
+
var mask = QRUtil.getMask(maskPattern, row, col - c2);
|
|
852
|
+
if (mask) {
|
|
853
|
+
dark = !dark;
|
|
854
|
+
}
|
|
855
|
+
this.modules[row][col - c2] = dark;
|
|
856
|
+
bitIndex--;
|
|
857
|
+
if (bitIndex === -1) {
|
|
858
|
+
byteIndex++;
|
|
859
|
+
bitIndex = 7;
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
row += inc;
|
|
864
|
+
if (row < 0 || this.moduleCount <= row) {
|
|
865
|
+
row -= inc;
|
|
866
|
+
inc = -inc;
|
|
867
|
+
break;
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
};
|
|
873
|
+
QRCode.PAD0 = 236;
|
|
874
|
+
QRCode.PAD1 = 17;
|
|
875
|
+
QRCode.createData = function(typeNumber, errorCorrectLevel, dataList) {
|
|
876
|
+
var rsBlocks = QRRSBlock.getRSBlocks(typeNumber, errorCorrectLevel);
|
|
877
|
+
var buffer = new QRBitBuffer;
|
|
878
|
+
for (var i = 0;i < dataList.length; i++) {
|
|
879
|
+
var data = dataList[i];
|
|
880
|
+
buffer.put(data.mode, 4);
|
|
881
|
+
buffer.put(data.getLength(), QRUtil.getLengthInBits(data.mode, typeNumber));
|
|
882
|
+
data.write(buffer);
|
|
883
|
+
}
|
|
884
|
+
var totalDataCount = 0;
|
|
885
|
+
for (var x = 0;x < rsBlocks.length; x++) {
|
|
886
|
+
totalDataCount += rsBlocks[x].dataCount;
|
|
887
|
+
}
|
|
888
|
+
if (buffer.getLengthInBits() > totalDataCount * 8) {
|
|
889
|
+
throw new Error("code length overflow. (" + buffer.getLengthInBits() + ">" + totalDataCount * 8 + ")");
|
|
890
|
+
}
|
|
891
|
+
if (buffer.getLengthInBits() + 4 <= totalDataCount * 8) {
|
|
892
|
+
buffer.put(0, 4);
|
|
893
|
+
}
|
|
894
|
+
while (buffer.getLengthInBits() % 8 !== 0) {
|
|
895
|
+
buffer.putBit(false);
|
|
896
|
+
}
|
|
897
|
+
while (true) {
|
|
898
|
+
if (buffer.getLengthInBits() >= totalDataCount * 8) {
|
|
899
|
+
break;
|
|
900
|
+
}
|
|
901
|
+
buffer.put(QRCode.PAD0, 8);
|
|
902
|
+
if (buffer.getLengthInBits() >= totalDataCount * 8) {
|
|
903
|
+
break;
|
|
904
|
+
}
|
|
905
|
+
buffer.put(QRCode.PAD1, 8);
|
|
906
|
+
}
|
|
907
|
+
return QRCode.createBytes(buffer, rsBlocks);
|
|
908
|
+
};
|
|
909
|
+
QRCode.createBytes = function(buffer, rsBlocks) {
|
|
910
|
+
var offset = 0;
|
|
911
|
+
var maxDcCount = 0;
|
|
912
|
+
var maxEcCount = 0;
|
|
913
|
+
var dcdata = new Array(rsBlocks.length);
|
|
914
|
+
var ecdata = new Array(rsBlocks.length);
|
|
915
|
+
for (var r = 0;r < rsBlocks.length; r++) {
|
|
916
|
+
var dcCount = rsBlocks[r].dataCount;
|
|
917
|
+
var ecCount = rsBlocks[r].totalCount - dcCount;
|
|
918
|
+
maxDcCount = Math.max(maxDcCount, dcCount);
|
|
919
|
+
maxEcCount = Math.max(maxEcCount, ecCount);
|
|
920
|
+
dcdata[r] = new Array(dcCount);
|
|
921
|
+
for (var i = 0;i < dcdata[r].length; i++) {
|
|
922
|
+
dcdata[r][i] = 255 & buffer.buffer[i + offset];
|
|
923
|
+
}
|
|
924
|
+
offset += dcCount;
|
|
925
|
+
var rsPoly = QRUtil.getErrorCorrectPolynomial(ecCount);
|
|
926
|
+
var rawPoly = new QRPolynomial(dcdata[r], rsPoly.getLength() - 1);
|
|
927
|
+
var modPoly = rawPoly.mod(rsPoly);
|
|
928
|
+
ecdata[r] = new Array(rsPoly.getLength() - 1);
|
|
929
|
+
for (var x = 0;x < ecdata[r].length; x++) {
|
|
930
|
+
var modIndex = x + modPoly.getLength() - ecdata[r].length;
|
|
931
|
+
ecdata[r][x] = modIndex >= 0 ? modPoly.get(modIndex) : 0;
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
var totalCodeCount = 0;
|
|
935
|
+
for (var y = 0;y < rsBlocks.length; y++) {
|
|
936
|
+
totalCodeCount += rsBlocks[y].totalCount;
|
|
937
|
+
}
|
|
938
|
+
var data = new Array(totalCodeCount);
|
|
939
|
+
var index = 0;
|
|
940
|
+
for (var z = 0;z < maxDcCount; z++) {
|
|
941
|
+
for (var s = 0;s < rsBlocks.length; s++) {
|
|
942
|
+
if (z < dcdata[s].length) {
|
|
943
|
+
data[index++] = dcdata[s][z];
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
for (var xx = 0;xx < maxEcCount; xx++) {
|
|
948
|
+
for (var t = 0;t < rsBlocks.length; t++) {
|
|
949
|
+
if (xx < ecdata[t].length) {
|
|
950
|
+
data[index++] = ecdata[t][xx];
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
return data;
|
|
955
|
+
};
|
|
956
|
+
module.exports = QRCode;
|
|
957
|
+
});
|
|
958
|
+
|
|
959
|
+
// ../../node_modules/.bun/qrcode-terminal@0.12.0/node_modules/qrcode-terminal/lib/main.js
|
|
960
|
+
var require_main = __commonJS((exports, module) => {
|
|
961
|
+
var QRCode = require_QRCode();
|
|
962
|
+
var QRErrorCorrectLevel = require_QRErrorCorrectLevel();
|
|
963
|
+
var black = "\x1B[40m \x1B[0m";
|
|
964
|
+
var white = "\x1B[47m \x1B[0m";
|
|
965
|
+
var toCell = function(isBlack) {
|
|
966
|
+
return isBlack ? black : white;
|
|
967
|
+
};
|
|
968
|
+
var repeat = function(color) {
|
|
969
|
+
return {
|
|
970
|
+
times: function(count) {
|
|
971
|
+
return new Array(count).join(color);
|
|
972
|
+
}
|
|
973
|
+
};
|
|
974
|
+
};
|
|
975
|
+
var fill = function(length, value) {
|
|
976
|
+
var arr = new Array(length);
|
|
977
|
+
for (var i = 0;i < length; i++) {
|
|
978
|
+
arr[i] = value;
|
|
979
|
+
}
|
|
980
|
+
return arr;
|
|
981
|
+
};
|
|
982
|
+
module.exports = {
|
|
983
|
+
error: QRErrorCorrectLevel.L,
|
|
984
|
+
generate: function(input, opts, cb) {
|
|
985
|
+
if (typeof opts === "function") {
|
|
986
|
+
cb = opts;
|
|
987
|
+
opts = {};
|
|
988
|
+
}
|
|
989
|
+
var qrcode = new QRCode(-1, this.error);
|
|
990
|
+
qrcode.addData(input);
|
|
991
|
+
qrcode.make();
|
|
992
|
+
var output = "";
|
|
993
|
+
if (opts && opts.small) {
|
|
994
|
+
var BLACK = true, WHITE = false;
|
|
995
|
+
var moduleCount = qrcode.getModuleCount();
|
|
996
|
+
var moduleData = qrcode.modules.slice();
|
|
997
|
+
var oddRow = moduleCount % 2 === 1;
|
|
998
|
+
if (oddRow) {
|
|
999
|
+
moduleData.push(fill(moduleCount, WHITE));
|
|
1000
|
+
}
|
|
1001
|
+
var platte = {
|
|
1002
|
+
WHITE_ALL: "█",
|
|
1003
|
+
WHITE_BLACK: "▀",
|
|
1004
|
+
BLACK_WHITE: "▄",
|
|
1005
|
+
BLACK_ALL: " "
|
|
1006
|
+
};
|
|
1007
|
+
var borderTop = repeat(platte.BLACK_WHITE).times(moduleCount + 3);
|
|
1008
|
+
var borderBottom = repeat(platte.WHITE_BLACK).times(moduleCount + 3);
|
|
1009
|
+
output += borderTop + `
|
|
1010
|
+
`;
|
|
1011
|
+
for (var row = 0;row < moduleCount; row += 2) {
|
|
1012
|
+
output += platte.WHITE_ALL;
|
|
1013
|
+
for (var col = 0;col < moduleCount; col++) {
|
|
1014
|
+
if (moduleData[row][col] === WHITE && moduleData[row + 1][col] === WHITE) {
|
|
1015
|
+
output += platte.WHITE_ALL;
|
|
1016
|
+
} else if (moduleData[row][col] === WHITE && moduleData[row + 1][col] === BLACK) {
|
|
1017
|
+
output += platte.WHITE_BLACK;
|
|
1018
|
+
} else if (moduleData[row][col] === BLACK && moduleData[row + 1][col] === WHITE) {
|
|
1019
|
+
output += platte.BLACK_WHITE;
|
|
1020
|
+
} else {
|
|
1021
|
+
output += platte.BLACK_ALL;
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
output += platte.WHITE_ALL + `
|
|
1025
|
+
`;
|
|
1026
|
+
}
|
|
1027
|
+
if (!oddRow) {
|
|
1028
|
+
output += borderBottom;
|
|
1029
|
+
}
|
|
1030
|
+
} else {
|
|
1031
|
+
var border = repeat(white).times(qrcode.getModuleCount() + 3);
|
|
1032
|
+
output += border + `
|
|
1033
|
+
`;
|
|
1034
|
+
qrcode.modules.forEach(function(row2) {
|
|
1035
|
+
output += white;
|
|
1036
|
+
output += row2.map(toCell).join("");
|
|
1037
|
+
output += white + `
|
|
1038
|
+
`;
|
|
1039
|
+
});
|
|
1040
|
+
output += border;
|
|
1041
|
+
}
|
|
1042
|
+
if (cb)
|
|
1043
|
+
cb(output);
|
|
1044
|
+
else
|
|
1045
|
+
console.log(output);
|
|
1046
|
+
},
|
|
1047
|
+
setErrorLevel: function(error) {
|
|
1048
|
+
this.error = QRErrorCorrectLevel[error] || this.error;
|
|
1049
|
+
}
|
|
1050
|
+
};
|
|
1051
|
+
});
|
|
1052
|
+
// package.json
|
|
1053
|
+
var package_default = {
|
|
1054
|
+
name: "lecodes-cli",
|
|
1055
|
+
version: "0.6.3",
|
|
1056
|
+
description: "Clone, edit and push LeCodes projects from your machine.",
|
|
1057
|
+
type: "module",
|
|
1058
|
+
license: "MIT",
|
|
1059
|
+
keywords: [
|
|
1060
|
+
"lecodes",
|
|
1061
|
+
"cli"
|
|
1062
|
+
],
|
|
1063
|
+
bin: {
|
|
1064
|
+
lecodes: "dist/index.js"
|
|
1065
|
+
},
|
|
1066
|
+
files: [
|
|
1067
|
+
"dist",
|
|
1068
|
+
"runtime",
|
|
1069
|
+
"README.md"
|
|
1070
|
+
],
|
|
1071
|
+
engines: {
|
|
1072
|
+
node: ">=18"
|
|
1073
|
+
},
|
|
1074
|
+
scripts: {
|
|
1075
|
+
icon: "bun scripts/make-icon.ts",
|
|
1076
|
+
"vendor-runtime": "bun scripts/vendor-runtime.ts",
|
|
1077
|
+
"sync-peers": "bun scripts/sync-peer-versions.ts",
|
|
1078
|
+
build: 'bun scripts/vendor-runtime.ts && bun build src/index.ts --target=node --outfile dist/index.js --external @letary/chisel --external lecodes-renderer --external lecodes-design --banner="#!/usr/bin/env node"',
|
|
1079
|
+
"build:bin": "bun scripts/build-bin.ts",
|
|
1080
|
+
typecheck: "tsc --noEmit",
|
|
1081
|
+
dev: "bun run src/index.ts",
|
|
1082
|
+
prepublishOnly: "bun run sync-peers && bun run build"
|
|
1083
|
+
},
|
|
1084
|
+
dependencies: {
|
|
1085
|
+
"@letary/chisel": "^0.2.0"
|
|
1086
|
+
},
|
|
1087
|
+
peerDependencies: {
|
|
1088
|
+
"lecodes-design": "^0.3.1",
|
|
1089
|
+
"lecodes-renderer": "^0.5.0"
|
|
1090
|
+
},
|
|
1091
|
+
peerDependenciesMeta: {
|
|
1092
|
+
"lecodes-design": {
|
|
1093
|
+
optional: true
|
|
1094
|
+
},
|
|
1095
|
+
"lecodes-renderer": {
|
|
1096
|
+
optional: true
|
|
1097
|
+
}
|
|
1098
|
+
},
|
|
1099
|
+
devDependencies: {
|
|
1100
|
+
"lecodes-design": "workspace:*",
|
|
1101
|
+
"lecodes-renderer": "^0.4.1",
|
|
1102
|
+
"qrcode-terminal": "^0.12.0",
|
|
1103
|
+
sdk: "workspace:*"
|
|
1104
|
+
}
|
|
1105
|
+
};
|
|
9
1106
|
|
|
10
1107
|
// src/commands/clone.ts
|
|
11
|
-
import { existsSync as
|
|
1108
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync5, readdirSync } from "node:fs";
|
|
12
1109
|
import { resolve } from "node:path";
|
|
13
1110
|
|
|
14
1111
|
// src/util.ts
|
|
@@ -285,9 +1382,25 @@ var materializeAssets = async (root, project, apiUrl, token, onProgress) => {
|
|
|
285
1382
|
};
|
|
286
1383
|
|
|
287
1384
|
// src/types.ts
|
|
1385
|
+
import { dirname as dirname4, join as join5 } from "node:path";
|
|
1386
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync4, readFileSync as readFileSync3, writeFileSync as writeFileSync4 } from "node:fs";
|
|
1387
|
+
|
|
1388
|
+
// src/distRoot.ts
|
|
1389
|
+
import { existsSync as existsSync2 } from "node:fs";
|
|
288
1390
|
import { dirname as dirname3, join as join4 } from "node:path";
|
|
289
1391
|
import { fileURLToPath } from "node:url";
|
|
290
|
-
|
|
1392
|
+
var distRoot = (() => {
|
|
1393
|
+
const candidates = [
|
|
1394
|
+
join4(dirname3(fileURLToPath(import.meta.url)), ".."),
|
|
1395
|
+
dirname3(process.execPath)
|
|
1396
|
+
];
|
|
1397
|
+
for (const c2 of candidates)
|
|
1398
|
+
if (existsSync2(join4(c2, "runtime")))
|
|
1399
|
+
return c2;
|
|
1400
|
+
return candidates[0];
|
|
1401
|
+
})();
|
|
1402
|
+
|
|
1403
|
+
// src/types.ts
|
|
291
1404
|
var TSCONFIG = {
|
|
292
1405
|
compilerOptions: {
|
|
293
1406
|
target: "ES2020",
|
|
@@ -305,10 +1418,10 @@ var TSCONFIG = {
|
|
|
305
1418
|
exclude: ["node_modules"]
|
|
306
1419
|
};
|
|
307
1420
|
var writeTypeBundle = (root, bundle) => {
|
|
308
|
-
const typesDir =
|
|
1421
|
+
const typesDir = join5(root, LECODES_DIR, "types");
|
|
309
1422
|
for (const [path, text] of Object.entries(bundle)) {
|
|
310
|
-
const dest =
|
|
311
|
-
mkdirSync4(
|
|
1423
|
+
const dest = join5(typesDir, path);
|
|
1424
|
+
mkdirSync4(dirname4(dest), { recursive: true });
|
|
312
1425
|
writeFileSync4(dest, text);
|
|
313
1426
|
}
|
|
314
1427
|
};
|
|
@@ -316,13 +1429,12 @@ var materializeTypes = async (root, apiUrl) => {
|
|
|
316
1429
|
writeTypeBundle(root, await getTypes(apiUrl));
|
|
317
1430
|
};
|
|
318
1431
|
var readLocalTypeBundle = () => {
|
|
319
|
-
const here = dirname3(fileURLToPath(import.meta.url));
|
|
320
1432
|
const candidates = [
|
|
321
|
-
|
|
322
|
-
|
|
1433
|
+
join5(distRoot, "runtime", "sdk-types.json"),
|
|
1434
|
+
join5(distRoot, "..", "sdk", "dist", "types.json")
|
|
323
1435
|
];
|
|
324
1436
|
for (const path of candidates) {
|
|
325
|
-
if (
|
|
1437
|
+
if (existsSync3(path)) {
|
|
326
1438
|
try {
|
|
327
1439
|
return JSON.parse(readFileSync3(path, "utf8"));
|
|
328
1440
|
} catch {}
|
|
@@ -338,12 +1450,12 @@ var materializeTypesLocal = (root) => {
|
|
|
338
1450
|
return true;
|
|
339
1451
|
};
|
|
340
1452
|
var writeTsconfig = (root) => {
|
|
341
|
-
writeFileSync4(
|
|
1453
|
+
writeFileSync4(join5(root, "tsconfig.json"), JSON.stringify(TSCONFIG, null, 2));
|
|
342
1454
|
};
|
|
343
1455
|
|
|
344
1456
|
// src/ignore.ts
|
|
345
|
-
import { existsSync as
|
|
346
|
-
import { join as
|
|
1457
|
+
import { existsSync as existsSync4, readFileSync as readFileSync4, writeFileSync as writeFileSync5 } from "node:fs";
|
|
1458
|
+
import { join as join6 } from "node:path";
|
|
347
1459
|
var BUILTIN_PATTERNS = ["node_modules/", ".git/", "_*", "*.log", ".DS_Store"];
|
|
348
1460
|
var DEFAULT_IGNORE_FILE = `# Files matched here are NOT pushed to LeCodes.
|
|
349
1461
|
# Only untracked files are affected — assets already in the project stay tracked
|
|
@@ -419,8 +1531,8 @@ var buildMatcher = (rules) => (key, isDir) => {
|
|
|
419
1531
|
};
|
|
420
1532
|
var loadIgnore = (root) => {
|
|
421
1533
|
const lines = [...BUILTIN_PATTERNS];
|
|
422
|
-
const file =
|
|
423
|
-
if (
|
|
1534
|
+
const file = join6(root, ".lecodesignore");
|
|
1535
|
+
if (existsSync4(file)) {
|
|
424
1536
|
try {
|
|
425
1537
|
lines.push(...readFileSync4(file, "utf8").split(/\r?\n/));
|
|
426
1538
|
} catch {}
|
|
@@ -429,8 +1541,8 @@ var loadIgnore = (root) => {
|
|
|
429
1541
|
return buildMatcher(rules);
|
|
430
1542
|
};
|
|
431
1543
|
var writeDefaultIgnore = (root) => {
|
|
432
|
-
const file =
|
|
433
|
-
if (!
|
|
1544
|
+
const file = join6(root, ".lecodesignore");
|
|
1545
|
+
if (!existsSync4(file))
|
|
434
1546
|
writeFileSync5(file, DEFAULT_IGNORE_FILE);
|
|
435
1547
|
};
|
|
436
1548
|
|
|
@@ -453,7 +1565,7 @@ var clone = async (args) => {
|
|
|
453
1565
|
const project = await getProject(apiUrl, token, uuid);
|
|
454
1566
|
const dir = args._[1] ?? slug(project.name);
|
|
455
1567
|
const root = resolve(dir);
|
|
456
|
-
if (
|
|
1568
|
+
if (existsSync5(root) && readdirSync(root).length > 0) {
|
|
457
1569
|
throw new CliError(`Directory "${dir}" already exists and is not empty.`);
|
|
458
1570
|
}
|
|
459
1571
|
mkdirSync5(root, { recursive: true });
|
|
@@ -473,8 +1585,8 @@ var clone = async (args) => {
|
|
|
473
1585
|
};
|
|
474
1586
|
|
|
475
1587
|
// src/commands/create.ts
|
|
476
|
-
import { existsSync as
|
|
477
|
-
import { join as
|
|
1588
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync6, readdirSync as readdirSync2, writeFileSync as writeFileSync6 } from "node:fs";
|
|
1589
|
+
import { join as join7, resolve as resolve2 } from "node:path";
|
|
478
1590
|
var slug2 = (name) => name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "project";
|
|
479
1591
|
var STARTER = `// Welcome to le.codes — no imports needed, the whole SDK is available as globals.
|
|
480
1592
|
const scene = new Scene2D({ background: '#10131a' })
|
|
@@ -493,7 +1605,7 @@ var create = async (args) => {
|
|
|
493
1605
|
throw new CliError("Usage: lecodes create <name> [directory]");
|
|
494
1606
|
const dir = args._[1] ?? slug2(name);
|
|
495
1607
|
const root = resolve2(dir);
|
|
496
|
-
if (
|
|
1608
|
+
if (existsSync6(root) && readdirSync2(root).length > 0) {
|
|
497
1609
|
throw new CliError(`Directory "${dir}" already exists and is not empty.`);
|
|
498
1610
|
}
|
|
499
1611
|
mkdirSync6(root, { recursive: true });
|
|
@@ -503,7 +1615,7 @@ var create = async (args) => {
|
|
|
503
1615
|
await materializeTypes(root, apiUrl);
|
|
504
1616
|
writeTsconfig(root);
|
|
505
1617
|
writeDefaultIgnore(root);
|
|
506
|
-
writeFileSync6(
|
|
1618
|
+
writeFileSync6(join7(root, "main.ts"), STARTER);
|
|
507
1619
|
const commits = await getCommits(apiUrl, token, uuid);
|
|
508
1620
|
writeManifest(root, { uuid, apiUrl, name, baseHeadId: commits.headId, files: {} });
|
|
509
1621
|
success(`Created ${c.bold(name)} in ${c.bold(dir)}/`);
|
|
@@ -511,8 +1623,8 @@ var create = async (args) => {
|
|
|
511
1623
|
};
|
|
512
1624
|
|
|
513
1625
|
// src/commands/design.ts
|
|
514
|
-
import { existsSync as
|
|
515
|
-
import { basename as basename2, join as
|
|
1626
|
+
import { existsSync as existsSync10, mkdirSync as mkdirSync8, readFileSync as readFileSync9, readdirSync as readdirSync5, writeFileSync as writeFileSync8, appendFileSync } from "node:fs";
|
|
1627
|
+
import { basename as basename2, join as join12 } from "node:path";
|
|
516
1628
|
|
|
517
1629
|
// src/compile/designCompile.ts
|
|
518
1630
|
import { readFileSync as readFileSync8 } from "node:fs";
|
|
@@ -520,7 +1632,7 @@ import { basename } from "node:path";
|
|
|
520
1632
|
|
|
521
1633
|
// src/localFiles.ts
|
|
522
1634
|
import { readdirSync as readdirSync3, readFileSync as readFileSync5 } from "node:fs";
|
|
523
|
-
import { join as
|
|
1635
|
+
import { join as join8, relative } from "node:path";
|
|
524
1636
|
var SKIP_DIRS = new Set([".lecodes", ".git", "node_modules"]);
|
|
525
1637
|
var SKIP_FILES = new Set(["tsconfig.json", "jsconfig.json", ".gitignore", ".lecodesignore", ".DS_Store"]);
|
|
526
1638
|
var TEXT_EXTS = new Set([
|
|
@@ -574,7 +1686,7 @@ var scanLocal = (root, opts = {}) => {
|
|
|
574
1686
|
};
|
|
575
1687
|
const walk = (dir, parentIgnored) => {
|
|
576
1688
|
for (const entry of readdirSync3(dir, { withFileTypes: true })) {
|
|
577
|
-
const abs =
|
|
1689
|
+
const abs = join8(dir, entry.name);
|
|
578
1690
|
const key = toKey(relative(root, abs));
|
|
579
1691
|
if (entry.isDirectory()) {
|
|
580
1692
|
if (SKIP_DIRS.has(entry.name))
|
|
@@ -628,15 +1740,14 @@ var diffLocal = (manifest, scan) => {
|
|
|
628
1740
|
var hasChanges = (diff) => diff.added.length + diff.modified.length + diff.deleted.length > 0;
|
|
629
1741
|
|
|
630
1742
|
// src/compile/projectCompile.ts
|
|
631
|
-
import { existsSync as
|
|
1743
|
+
import { existsSync as existsSync8 } from "node:fs";
|
|
632
1744
|
import { createRequire as createRequire3 } from "node:module";
|
|
633
|
-
import { dirname as
|
|
634
|
-
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
1745
|
+
import { dirname as dirname6, join as join10 } from "node:path";
|
|
635
1746
|
// ../sdk/src/compile/bundler.ts
|
|
636
|
-
import { existsSync as
|
|
1747
|
+
import { existsSync as existsSync7, readdirSync as readdirSync4, readFileSync as readFileSync6, statSync } from "node:fs";
|
|
637
1748
|
import { spawnSync } from "node:child_process";
|
|
638
1749
|
import { createRequire as createRequire2 } from "node:module";
|
|
639
|
-
import { dirname as
|
|
1750
|
+
import { dirname as dirname5, join as join9, relative as relative2 } from "node:path";
|
|
640
1751
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
641
1752
|
|
|
642
1753
|
// ../sdk/src/compile/assetMacro.ts
|
|
@@ -697,11 +1808,11 @@ var classBodyDeclaresAspect = (src, from) => {
|
|
|
697
1808
|
// ../sdk/src/compile/bundler.ts
|
|
698
1809
|
var resolveInject = () => {
|
|
699
1810
|
const override = process.env.LECODES_SDK_INJECT;
|
|
700
|
-
if (override &&
|
|
1811
|
+
if (override && existsSync7(override))
|
|
701
1812
|
return override;
|
|
702
|
-
const here =
|
|
703
|
-
const src =
|
|
704
|
-
if (
|
|
1813
|
+
const here = dirname5(fileURLToPath2(import.meta.url));
|
|
1814
|
+
const src = join9(here, "..", "inject.ts");
|
|
1815
|
+
if (existsSync7(src))
|
|
705
1816
|
return src;
|
|
706
1817
|
throw new Error("sdk: could not locate the inject source (LECODES_SDK_INJECT / src/inject.ts)");
|
|
707
1818
|
};
|
|
@@ -724,7 +1835,7 @@ var resolveSdkSrc = () => {
|
|
|
724
1835
|
if (!inject.endsWith("inject.ts")) {
|
|
725
1836
|
throw new Error(`chisel needs the SDK source tree (src/inject.ts); got ${inject}. Set LECODES_SDK_INJECT to the source.`);
|
|
726
1837
|
}
|
|
727
|
-
return
|
|
1838
|
+
return dirname5(inject);
|
|
728
1839
|
};
|
|
729
1840
|
var isSdkSource = (path) => /\.[tj]s$/.test(path) && !path.endsWith(".d.ts") && !path.includes("/compile/") && !path.includes("/tests/") && !path.includes("/__tests__/");
|
|
730
1841
|
var sdkFilesCache = new Map;
|
|
@@ -735,7 +1846,7 @@ var collectSdkFiles = (sdkSrc) => {
|
|
|
735
1846
|
const out = {};
|
|
736
1847
|
const walk = (dir) => {
|
|
737
1848
|
for (const name of readdirSync4(dir)) {
|
|
738
|
-
const p =
|
|
1849
|
+
const p = join9(dir, name);
|
|
739
1850
|
if (statSync(p).isDirectory())
|
|
740
1851
|
walk(p);
|
|
741
1852
|
else if (isSdkSource(p))
|
|
@@ -749,13 +1860,13 @@ var collectSdkFiles = (sdkSrc) => {
|
|
|
749
1860
|
var resolveChiselBin = () => {
|
|
750
1861
|
const override = process.env.LECODES_CHISEL_BIN;
|
|
751
1862
|
if (override) {
|
|
752
|
-
if (
|
|
1863
|
+
if (existsSync7(override))
|
|
753
1864
|
return override;
|
|
754
1865
|
throw new Error(`LECODES_CHISEL_BIN points at a missing file: ${override}`);
|
|
755
1866
|
}
|
|
756
1867
|
try {
|
|
757
1868
|
const bin = createRequire2(import.meta.url)("@letary/chisel").binaryPath();
|
|
758
|
-
if (bin &&
|
|
1869
|
+
if (bin && existsSync7(bin))
|
|
759
1870
|
return bin;
|
|
760
1871
|
} catch {}
|
|
761
1872
|
throw new Error("chisel binary not found. Install @letary/chisel, or set LECODES_CHISEL_BIN.");
|
|
@@ -915,18 +2026,19 @@ ${inlineSourceMapComment(map)}` : code;
|
|
|
915
2026
|
${inlineSourceMapComment(offsetSourceMap(map, headerLines))}`;
|
|
916
2027
|
};
|
|
917
2028
|
// src/compile/projectCompile.ts
|
|
918
|
-
var
|
|
919
|
-
|
|
920
|
-
if (existsSync7(vendoredInject))
|
|
2029
|
+
var vendoredInject = join10(distRoot, "runtime", "sdk", "inject.ts");
|
|
2030
|
+
if (existsSync8(vendoredInject))
|
|
921
2031
|
process.env.LECODES_SDK_INJECT = vendoredInject;
|
|
922
2032
|
var resolveChiselBin2 = () => {
|
|
923
2033
|
if (process.env.LECODES_CHISEL_BIN)
|
|
924
2034
|
return process.env.LECODES_CHISEL_BIN;
|
|
925
2035
|
try {
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
}
|
|
2036
|
+
const fromPkg = createRequire3(import.meta.url)("@letary/chisel").binaryPath();
|
|
2037
|
+
if (fromPkg)
|
|
2038
|
+
return fromPkg;
|
|
2039
|
+
} catch {}
|
|
2040
|
+
const local = join10(dirname6(process.execPath), process.platform === "win32" ? "chisel.exe" : "chisel");
|
|
2041
|
+
return existsSync8(local) ? local : null;
|
|
930
2042
|
};
|
|
931
2043
|
var chiselBin = resolveChiselBin2();
|
|
932
2044
|
if (chiselBin)
|
|
@@ -943,8 +2055,8 @@ var compileProject2 = (opts) => compileProject({
|
|
|
943
2055
|
|
|
944
2056
|
// src/compile/assetIcons.ts
|
|
945
2057
|
import { createHash as createHash2 } from "node:crypto";
|
|
946
|
-
import { existsSync as
|
|
947
|
-
import { dirname as
|
|
2058
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync7, readFileSync as readFileSync7, writeFileSync as writeFileSync7 } from "node:fs";
|
|
2059
|
+
import { dirname as dirname7, join as join11 } from "node:path";
|
|
948
2060
|
var DEFAULT_REGISTRY = process.env.LECODES_ICON_REGISTRY?.trim() || "https://icon-registry.jt3.ru/v1";
|
|
949
2061
|
var ICON_ID = /^([a-z0-9]+(?:-[a-z0-9]+)*):([a-z0-9]+(?:-[a-z0-9]+)*)$/;
|
|
950
2062
|
var isIdentStart = (c2) => c2 >= "A" && c2 <= "Z" || c2 >= "a" && c2 <= "z" || c2 === "_" || c2 === "$";
|
|
@@ -1196,7 +2308,7 @@ var readText = async (registry, rel) => {
|
|
|
1196
2308
|
return res.ok ? await res.text() : null;
|
|
1197
2309
|
}
|
|
1198
2310
|
try {
|
|
1199
|
-
return readFileSync7(
|
|
2311
|
+
return readFileSync7(join11(registry, rel), "utf8");
|
|
1200
2312
|
} catch {
|
|
1201
2313
|
return null;
|
|
1202
2314
|
}
|
|
@@ -1240,7 +2352,7 @@ var renderNotices = (lock) => {
|
|
|
1240
2352
|
`);
|
|
1241
2353
|
};
|
|
1242
2354
|
var writeIfChanged = (path, text) => {
|
|
1243
|
-
const current =
|
|
2355
|
+
const current = existsSync9(path) ? safeRead(path) : null;
|
|
1244
2356
|
if (current === text)
|
|
1245
2357
|
return false;
|
|
1246
2358
|
writeFileSync7(path, text);
|
|
@@ -1255,13 +2367,13 @@ var safeRead = (path) => {
|
|
|
1255
2367
|
};
|
|
1256
2368
|
var vendorIcons = async (designDir, ids, opts = {}) => {
|
|
1257
2369
|
const registry = (opts.registry ?? DEFAULT_REGISTRY).replace(/\/+$/, "");
|
|
1258
|
-
const lockPath =
|
|
2370
|
+
const lockPath = join11(designDir, "icons.lock.json");
|
|
1259
2371
|
const lock = readLock(lockPath) ?? { registry, icons: {}, packs: {} };
|
|
1260
2372
|
const svgById = new Map;
|
|
1261
2373
|
const missing = [];
|
|
1262
2374
|
for (const id of ids) {
|
|
1263
2375
|
const li = lock.icons[id];
|
|
1264
|
-
const cached = li && safeRead(
|
|
2376
|
+
const cached = li && safeRead(join11(designDir, li.path));
|
|
1265
2377
|
if (cached)
|
|
1266
2378
|
svgById.set(id, cached);
|
|
1267
2379
|
else
|
|
@@ -1282,8 +2394,8 @@ var vendorIcons = async (designDir, ids, opts = {}) => {
|
|
|
1282
2394
|
if (svg === null)
|
|
1283
2395
|
throw new Error(`assetIcon: icon "${id}" not found in the registry. Check the name at ${registryHome(registry)}.`);
|
|
1284
2396
|
const rel = `assets/icons/${pack}/${name}.svg`;
|
|
1285
|
-
const abs =
|
|
1286
|
-
mkdirSync7(
|
|
2397
|
+
const abs = join11(designDir, rel);
|
|
2398
|
+
mkdirSync7(dirname7(abs), { recursive: true });
|
|
1287
2399
|
writeFileSync7(abs, svg);
|
|
1288
2400
|
lock.icons[id] = { pack, name, hash: sha12(svg), spdx: lic.spdx, path: rel };
|
|
1289
2401
|
lock.packs[pack] = { spdx: lic.spdx, title: lic.title, url: lic.url, attribution: lic.attribution, modifiedNotice: lic.modifiedNotice };
|
|
@@ -1293,7 +2405,7 @@ var vendorIcons = async (designDir, ids, opts = {}) => {
|
|
|
1293
2405
|
writeIfChanged(lockPath, serializeLock(lock));
|
|
1294
2406
|
}
|
|
1295
2407
|
if (Object.keys(lock.icons).length)
|
|
1296
|
-
writeIfChanged(
|
|
2408
|
+
writeIfChanged(join11(designDir, "ICON-NOTICES.md"), renderNotices(lock));
|
|
1297
2409
|
return svgById;
|
|
1298
2410
|
};
|
|
1299
2411
|
var applyAssetIcons = async (entries, designDir, opts = {}) => {
|
|
@@ -1737,29 +2849,29 @@ var getContext = (args) => {
|
|
|
1737
2849
|
manifest,
|
|
1738
2850
|
name: manifest?.name ?? basename2(root),
|
|
1739
2851
|
dirName,
|
|
1740
|
-
designDir:
|
|
2852
|
+
designDir: join12(root, dirName),
|
|
1741
2853
|
designKey: "/" + dirName.replace(/\\/g, "/")
|
|
1742
2854
|
};
|
|
1743
2855
|
};
|
|
1744
2856
|
var listScreens = (designDir) => {
|
|
1745
|
-
const dir =
|
|
1746
|
-
if (!
|
|
2857
|
+
const dir = join12(designDir, "screens");
|
|
2858
|
+
if (!existsSync10(dir))
|
|
1747
2859
|
return [];
|
|
1748
2860
|
return readdirSync5(dir).filter((f) => f.endsWith(".ts") && !f.startsWith(".")).map((f) => f.slice(0, -3)).sort();
|
|
1749
2861
|
};
|
|
1750
2862
|
var readMetaSizes = (designDir) => {
|
|
1751
2863
|
try {
|
|
1752
|
-
const meta = JSON.parse(readFileSync9(
|
|
2864
|
+
const meta = JSON.parse(readFileSync9(join12(designDir, "meta.json"), "utf8"));
|
|
1753
2865
|
return meta?.screens ?? {};
|
|
1754
2866
|
} catch {
|
|
1755
2867
|
return {};
|
|
1756
2868
|
}
|
|
1757
2869
|
};
|
|
1758
2870
|
var writeMcpConfig = (ctx, port) => {
|
|
1759
|
-
const path =
|
|
2871
|
+
const path = join12(ctx.root, ".mcp.json");
|
|
1760
2872
|
const entry = { type: "http", url: `http://localhost:${port}/mcp` };
|
|
1761
2873
|
let config = {};
|
|
1762
|
-
if (
|
|
2874
|
+
if (existsSync10(path)) {
|
|
1763
2875
|
try {
|
|
1764
2876
|
config = JSON.parse(readFileSync9(path, "utf8"));
|
|
1765
2877
|
} catch {
|
|
@@ -1784,15 +2896,15 @@ var init = async (ctx, args) => {
|
|
|
1784
2896
|
["spec.md", SPEC_MD],
|
|
1785
2897
|
["README.md", README_HINT],
|
|
1786
2898
|
["CLAUDE.md", CLAUDE_MD],
|
|
1787
|
-
[
|
|
1788
|
-
[
|
|
2899
|
+
[join12("shared", "tokens.ts"), TOKENS_TS],
|
|
2900
|
+
[join12("screens", "home.ts"), HOME_SCREEN_TS]
|
|
1789
2901
|
];
|
|
1790
|
-
mkdirSync8(
|
|
1791
|
-
mkdirSync8(
|
|
2902
|
+
mkdirSync8(join12(ctx.designDir, "screens"), { recursive: true });
|
|
2903
|
+
mkdirSync8(join12(ctx.designDir, "shared"), { recursive: true });
|
|
1792
2904
|
let created = 0;
|
|
1793
2905
|
for (const [rel, content] of files) {
|
|
1794
|
-
const abs =
|
|
1795
|
-
if (
|
|
2906
|
+
const abs = join12(ctx.designDir, rel);
|
|
2907
|
+
if (existsSync10(abs)) {
|
|
1796
2908
|
note(`kept ${ctx.dirName}/${rel.replace(/\\/g, "/")}`);
|
|
1797
2909
|
continue;
|
|
1798
2910
|
}
|
|
@@ -1800,9 +2912,9 @@ var init = async (ctx, args) => {
|
|
|
1800
2912
|
log(`${c.green("created")} ${ctx.dirName}/${rel.replace(/\\/g, "/")}`);
|
|
1801
2913
|
created++;
|
|
1802
2914
|
}
|
|
1803
|
-
const ignorePath =
|
|
2915
|
+
const ignorePath = join12(ctx.root, ".lecodesignore");
|
|
1804
2916
|
const ignoreLine = `${ctx.dirName}/.snapshots/`;
|
|
1805
|
-
const current =
|
|
2917
|
+
const current = existsSync10(ignorePath) ? readFileSync9(ignorePath, "utf8") : "";
|
|
1806
2918
|
if (!current.split(/\r?\n/).includes(ignoreLine)) {
|
|
1807
2919
|
appendFileSync(ignorePath, (current && !current.endsWith(`
|
|
1808
2920
|
`) ? `
|
|
@@ -1813,8 +2925,8 @@ var init = async (ctx, args) => {
|
|
|
1813
2925
|
writeMcpConfig(ctx, Number(flagStr(args, "port")) || DEFAULT_PORT);
|
|
1814
2926
|
const wroteTypes = materializeTypesLocal(ctx.designDir);
|
|
1815
2927
|
writeTsconfig(ctx.designDir);
|
|
1816
|
-
mkdirSync8(
|
|
1817
|
-
writeFileSync8(
|
|
2928
|
+
mkdirSync8(join12(ctx.designDir, ".lecodes", "types"), { recursive: true });
|
|
2929
|
+
writeFileSync8(join12(ctx.designDir, ".lecodes", "types", "design-macros.d.ts"), DESIGN_MACROS_DTS);
|
|
1818
2930
|
log(`${c.green("created")} ${ctx.dirName}/tsconfig.json${wroteTypes ? ` + ${ctx.dirName}/.lecodes/types/` : ""} (IDE types)`);
|
|
1819
2931
|
if (!wroteTypes)
|
|
1820
2932
|
warnErr("Bundled SDK types not found — tsconfig written, but globals may show unresolved until the CLI is rebuilt with vendored types.");
|
|
@@ -1863,7 +2975,7 @@ var snapshot = async (ctx, args) => {
|
|
|
1863
2975
|
killer.unref?.();
|
|
1864
2976
|
const png = flagBool(args, "png") || flagStr(args, "png") !== undefined;
|
|
1865
2977
|
const sizes = readMetaSizes(ctx.designDir);
|
|
1866
|
-
const outDir = flagStr(args, "out-dir") ??
|
|
2978
|
+
const outDir = flagStr(args, "out-dir") ?? join12(ctx.designDir, ".snapshots");
|
|
1867
2979
|
const single = targets.length === 1 && requested.length === 1 && !png && !allStates && !flagStr(args, "out-dir");
|
|
1868
2980
|
const onConsole = flagBool(args, "logs") ? (level, text) => logErr(`${c.dim(`[${level}]`)} ${text}`) : undefined;
|
|
1869
2981
|
if (!single)
|
|
@@ -1872,7 +2984,7 @@ var snapshot = async (ctx, args) => {
|
|
|
1872
2984
|
const [width, height] = sizes[id]?.size ?? [390, 844];
|
|
1873
2985
|
let plan = [{ state: undefined, bases: [id] }];
|
|
1874
2986
|
if (discover) {
|
|
1875
|
-
const { states, canonical } = discover(readFileSync9(
|
|
2987
|
+
const { states, canonical } = discover(readFileSync9(join12(ctx.designDir, "screens", `${id}.ts`), "utf8"));
|
|
1876
2988
|
if (stateFlag !== undefined) {
|
|
1877
2989
|
if (!states.includes(stateFlag)) {
|
|
1878
2990
|
if (requested.length === 1)
|
|
@@ -1913,18 +3025,18 @@ var snapshot = async (ctx, args) => {
|
|
|
1913
3025
|
for (const w of pngResult.warnings)
|
|
1914
3026
|
warnErr(`${tag}: ${w}`);
|
|
1915
3027
|
for (const base of bases) {
|
|
1916
|
-
writeFileSync8(
|
|
1917
|
-
log(`${c.green("✓")} ${tag} → ${
|
|
3028
|
+
writeFileSync8(join12(outDir, `${base}.json`), result.text);
|
|
3029
|
+
log(`${c.green("✓")} ${tag} → ${join12(outDir, `${base}.json`)}`);
|
|
1918
3030
|
if (pngResult) {
|
|
1919
|
-
writeFileSync8(
|
|
1920
|
-
log(`${c.green("✓")} ${tag} → ${
|
|
3031
|
+
writeFileSync8(join12(outDir, `${base}.png`), pngResult.png);
|
|
3032
|
+
log(`${c.green("✓")} ${tag} → ${join12(outDir, `${base}.png`)}`);
|
|
1921
3033
|
}
|
|
1922
3034
|
}
|
|
1923
3035
|
}
|
|
1924
3036
|
}
|
|
1925
3037
|
};
|
|
1926
3038
|
var serve = async (ctx, args) => {
|
|
1927
|
-
if (!
|
|
3039
|
+
if (!existsSync10(ctx.designDir)) {
|
|
1928
3040
|
throw new CliError(`No ${ctx.dirName}/ folder here. Run "lecodes design init" to scaffold it.`);
|
|
1929
3041
|
}
|
|
1930
3042
|
let designServer;
|
|
@@ -1997,7 +3109,7 @@ var serve = async (ctx, args) => {
|
|
|
1997
3109
|
openBrowser(server.url);
|
|
1998
3110
|
};
|
|
1999
3111
|
var arrange = async (ctx, args) => {
|
|
2000
|
-
if (!
|
|
3112
|
+
if (!existsSync10(ctx.designDir)) {
|
|
2001
3113
|
throw new CliError(`No ${ctx.dirName}/ folder here. Run "lecodes design init" to scaffold it.`);
|
|
2002
3114
|
}
|
|
2003
3115
|
let designServer;
|
|
@@ -2033,7 +3145,7 @@ var share = async (ctx, args) => {
|
|
|
2033
3145
|
note("Turn it off with: lecodes design share --off");
|
|
2034
3146
|
};
|
|
2035
3147
|
var check = async (ctx, args) => {
|
|
2036
|
-
if (!
|
|
3148
|
+
if (!existsSync10(ctx.designDir)) {
|
|
2037
3149
|
throw new CliError(`No ${ctx.dirName}/ folder here. Run "lecodes design init" to scaffold it.`);
|
|
2038
3150
|
}
|
|
2039
3151
|
let designServer;
|
|
@@ -2097,9 +3209,605 @@ var design = async (args) => {
|
|
|
2097
3209
|
throw new CliError(`Unknown design subcommand "${sub}" (serve | init | snapshot | arrange | check | share).`);
|
|
2098
3210
|
};
|
|
2099
3211
|
|
|
2100
|
-
// src/
|
|
3212
|
+
// src/commands/dev.ts
|
|
3213
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync9, readFileSync as readFileSync11, watch, writeFileSync as writeFileSync9 } from "node:fs";
|
|
3214
|
+
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
3215
|
+
import { networkInterfaces } from "node:os";
|
|
3216
|
+
import { basename as basename4, join as join14 } from "node:path";
|
|
3217
|
+
|
|
3218
|
+
// src/dev/devServer.ts
|
|
3219
|
+
import { createServer as createServer2 } from "node:http";
|
|
3220
|
+
import { createReadStream, existsSync as existsSync11, statSync as statSync2 } from "node:fs";
|
|
3221
|
+
import { join as join13 } from "node:path";
|
|
3222
|
+
|
|
3223
|
+
// src/compile/collectLocal.ts
|
|
2101
3224
|
import { readFileSync as readFileSync10 } from "node:fs";
|
|
2102
3225
|
import { basename as basename3 } from "node:path";
|
|
3226
|
+
var collectLocalEntries = (root, manifest, assetBase) => {
|
|
3227
|
+
const entries = [];
|
|
3228
|
+
const warnings = [];
|
|
3229
|
+
const scan = scanLocal(root, { ignore: loadIgnore(root), tracked: new Set(Object.keys(manifest?.files ?? {})) });
|
|
3230
|
+
for (const file of scan.files) {
|
|
3231
|
+
const type = manifest?.files[file.path]?.type ?? classifyKind(basename3(file.path));
|
|
3232
|
+
if (type === "resource") {
|
|
3233
|
+
entries.push({ path: file.path, type, fileSrc: assetBase + encodeURI(file.path), absPath: file.absPath });
|
|
3234
|
+
} else if (type === "shader") {
|
|
3235
|
+
warnings.push(`${file.path}: shaders compile on the server — push the project once for shaders to work in dev mode.`);
|
|
3236
|
+
entries.push({ path: file.path, type, shaders: [] });
|
|
3237
|
+
} else {
|
|
3238
|
+
entries.push({ path: file.path, type, text: readFileSync10(file.absPath, "utf8") });
|
|
3239
|
+
}
|
|
3240
|
+
}
|
|
3241
|
+
return { entries, warnings };
|
|
3242
|
+
};
|
|
3243
|
+
|
|
3244
|
+
// src/dev/clientTemplates.ts
|
|
3245
|
+
var DEV_SCREEN_TS = `const title = "LeCodes Dev"
|
|
3246
|
+
const project = __DEV_NAME__
|
|
3247
|
+
|
|
3248
|
+
UIScreen([
|
|
3249
|
+
UIText(title).style({ fontSize: 30, fontWeight: 700, color: "#ffffff" }),
|
|
3250
|
+
UIText(project).style({ fontSize: 16, color: "#9fb0d0", mt: 8 }),
|
|
3251
|
+
UIText("Connected — loading the project…").style({ fontSize: 14, color: "#6b7a99", mt: 20 }),
|
|
3252
|
+
]).style({ bgColor: "#11131a", justifyContent: "center", alignItems: "center", p: 40 }).open()
|
|
3253
|
+
`;
|
|
3254
|
+
var DEV_PRELUDE_JS = `
|
|
3255
|
+
;(function () {
|
|
3256
|
+
var ORIGIN = "__DEV_ORIGIN__"
|
|
3257
|
+
var BASE = "__DEV_BASE__"
|
|
3258
|
+
var TRANSPORT = "__DEV_TRANSPORT__"
|
|
3259
|
+
var V = __DEV_V__
|
|
3260
|
+
var wsId = null
|
|
3261
|
+
var busy = false
|
|
3262
|
+
var queued = null
|
|
3263
|
+
|
|
3264
|
+
function post(obj) {
|
|
3265
|
+
var text = JSON.stringify(obj)
|
|
3266
|
+
if (TRANSPORT === "ws") {
|
|
3267
|
+
if (wsId !== null) { try { _creatorUtils.websocketSend(wsId, text) } catch (e) {} }
|
|
3268
|
+
return
|
|
3269
|
+
}
|
|
3270
|
+
try {
|
|
3271
|
+
_creatorUtils.fetch(ORIGIN + BASE + "/log", { method: "POST", body: text, headers: { "content-type": "application/json" } },
|
|
3272
|
+
function (id) { try { _creatorUtils.disposeFetch(id) } catch (e) {} }, function () {})
|
|
3273
|
+
} catch (e) {}
|
|
3274
|
+
}
|
|
3275
|
+
|
|
3276
|
+
// Mirror console output to the dev terminal ('silent' guards recursion through wrapped calls).
|
|
3277
|
+
var silent = false
|
|
3278
|
+
;["log", "warn", "error"].forEach(function (level) {
|
|
3279
|
+
var orig = console[level]
|
|
3280
|
+
console[level] = function () {
|
|
3281
|
+
var parts = []
|
|
3282
|
+
for (var i = 0; i < arguments.length; i++) {
|
|
3283
|
+
var a = arguments[i]
|
|
3284
|
+
if (typeof a === "string") { parts.push(a); continue }
|
|
3285
|
+
try { parts.push(JSON.stringify(a)) } catch (e) { parts.push(String(a)) }
|
|
3286
|
+
}
|
|
3287
|
+
try { orig.apply(console, arguments) } catch (e) {}
|
|
3288
|
+
if (!silent) { silent = true; try { post({ type: "log", level: level, text: parts.join(" ") }) } finally { silent = false } }
|
|
3289
|
+
}
|
|
3290
|
+
})
|
|
3291
|
+
|
|
3292
|
+
function report(err) { post({ type: "error", text: String(err) }) }
|
|
3293
|
+
|
|
3294
|
+
function load(v) {
|
|
3295
|
+
if (busy) { queued = v; return }
|
|
3296
|
+
busy = true
|
|
3297
|
+
_creatorUtils.fetch(ORIGIN + BASE + "/bundle.js?v=" + v + "&t=" + TRANSPORT, {}, function (id, status) {
|
|
3298
|
+
if (status >= 400) { busy = false; report("bundle fetch: HTTP " + status); return }
|
|
3299
|
+
// Same engine bringup the app launcher does for a fresh launch (see desktop initial.ts).
|
|
3300
|
+
var head = ""
|
|
3301
|
+
try { head = _creatorUtils.fetchSlice(id, 0, 300) } catch (e) {}
|
|
3302
|
+
var preloads = head.match(/\\/\\/ preload: (.+)/)
|
|
3303
|
+
if (head.indexOf("// gl:") < 0) {
|
|
3304
|
+
try { _creator.createEngine(preloads ? preloads[1].split(";") : []) } catch (e) { report("createEngine: " + String(e)) }
|
|
3305
|
+
}
|
|
3306
|
+
_creatorUtils.run(id, function (err) {
|
|
3307
|
+
// Eval failed → native rollback kept THIS world (and its connection) alive. Keep serving.
|
|
3308
|
+
busy = false
|
|
3309
|
+
report(err)
|
|
3310
|
+
if (queued !== null) { var q = queued; queued = null; load(q) }
|
|
3311
|
+
})
|
|
3312
|
+
// On success this world is torn down next tick — the new bundle carries its own prelude.
|
|
3313
|
+
}, function (err) { busy = false; report("bundle fetch failed: " + String(err)) })
|
|
3314
|
+
}
|
|
3315
|
+
|
|
3316
|
+
function onServer(data) {
|
|
3317
|
+
var m = null
|
|
3318
|
+
try { m = JSON.parse(data) } catch (e) { return }
|
|
3319
|
+
if (m && m.type === "reload" && typeof m.v === "number" && m.v !== V) load(m.v)
|
|
3320
|
+
}
|
|
3321
|
+
|
|
3322
|
+
if (TRANSPORT === "ws") {
|
|
3323
|
+
var url = ORIGIN.replace("http", "ws") + BASE + "/ws"
|
|
3324
|
+
var open = function () {
|
|
3325
|
+
try {
|
|
3326
|
+
wsId = _creatorUtils.websocketOpen(url, function (channel, data) {
|
|
3327
|
+
if (channel === "open") {
|
|
3328
|
+
try { _creatorUtils.websocketSend(wsId, JSON.stringify({ type: "hello", v: V })) } catch (e) {}
|
|
3329
|
+
} else if (channel === "message") {
|
|
3330
|
+
onServer(data)
|
|
3331
|
+
} else if (channel === "close" || channel === "error") {
|
|
3332
|
+
wsId = null
|
|
3333
|
+
setTimeout(open, 2000)
|
|
3334
|
+
}
|
|
3335
|
+
})
|
|
3336
|
+
} catch (e) { setTimeout(open, 2000) }
|
|
3337
|
+
}
|
|
3338
|
+
open()
|
|
3339
|
+
} else {
|
|
3340
|
+
var poll = function () {
|
|
3341
|
+
_creatorUtils.fetch(ORIGIN + BASE + "/version", {}, function (id, status) {
|
|
3342
|
+
var v = null
|
|
3343
|
+
try { v = _creatorUtils.fetchToJson(id).v } catch (e) {}
|
|
3344
|
+
try { _creatorUtils.disposeFetch(id) } catch (e) {}
|
|
3345
|
+
setTimeout(poll, 700)
|
|
3346
|
+
if (status < 400 && typeof v === "number" && v !== V && !busy) load(v)
|
|
3347
|
+
}, function () { setTimeout(poll, 1500) })
|
|
3348
|
+
}
|
|
3349
|
+
poll()
|
|
3350
|
+
}
|
|
3351
|
+
})();
|
|
3352
|
+
`;
|
|
3353
|
+
var renderPrelude = (p) => DEV_PRELUDE_JS.split("__DEV_ORIGIN__").join(p.origin).split("__DEV_BASE__").join(p.base).split("__DEV_TRANSPORT__").join(p.transport).split("__DEV_V__").join(String(p.v));
|
|
3354
|
+
var renderDevScreen = (name) => DEV_SCREEN_TS.split("__DEV_NAME__").join(JSON.stringify(name));
|
|
3355
|
+
|
|
3356
|
+
// src/dev/wsServer.ts
|
|
3357
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
3358
|
+
var WS_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
|
|
3359
|
+
var acceptKey = (key) => createHash3("sha1").update(key + WS_GUID).digest("base64");
|
|
3360
|
+
var encodeTextFrame = (text) => {
|
|
3361
|
+
const payload = Buffer.from(text, "utf8");
|
|
3362
|
+
const len = payload.length;
|
|
3363
|
+
let header;
|
|
3364
|
+
if (len < 126) {
|
|
3365
|
+
header = Buffer.from([129, len]);
|
|
3366
|
+
} else if (len < 65536) {
|
|
3367
|
+
header = Buffer.alloc(4);
|
|
3368
|
+
header[0] = 129;
|
|
3369
|
+
header[1] = 126;
|
|
3370
|
+
header.writeUInt16BE(len, 2);
|
|
3371
|
+
} else {
|
|
3372
|
+
header = Buffer.alloc(10);
|
|
3373
|
+
header[0] = 129;
|
|
3374
|
+
header[1] = 127;
|
|
3375
|
+
header.writeBigUInt64BE(BigInt(len), 2);
|
|
3376
|
+
}
|
|
3377
|
+
return Buffer.concat([header, payload]);
|
|
3378
|
+
};
|
|
3379
|
+
var encodeControlFrame = (opcode, payload = Buffer.alloc(0)) => Buffer.concat([Buffer.from([128 | opcode, Math.min(payload.length, 125)]), payload.subarray(0, 125)]);
|
|
3380
|
+
var OPCODE = { CONTINUATION: 0, TEXT: 1, BINARY: 2, CLOSE: 8, PING: 9, PONG: 10 };
|
|
3381
|
+
var createFrameDecoder = () => {
|
|
3382
|
+
let buf = Buffer.alloc(0);
|
|
3383
|
+
return (chunk) => {
|
|
3384
|
+
buf = buf.length === 0 ? chunk : Buffer.concat([buf, chunk]);
|
|
3385
|
+
const frames = [];
|
|
3386
|
+
while (buf.length >= 2) {
|
|
3387
|
+
const opcode = buf[0] & 15;
|
|
3388
|
+
const masked = (buf[1] & 128) !== 0;
|
|
3389
|
+
let len = buf[1] & 127;
|
|
3390
|
+
let off = 2;
|
|
3391
|
+
if (len === 126) {
|
|
3392
|
+
if (buf.length < 4)
|
|
3393
|
+
break;
|
|
3394
|
+
len = buf.readUInt16BE(2);
|
|
3395
|
+
off = 4;
|
|
3396
|
+
} else if (len === 127) {
|
|
3397
|
+
if (buf.length < 10)
|
|
3398
|
+
break;
|
|
3399
|
+
len = Number(buf.readBigUInt64BE(2));
|
|
3400
|
+
off = 10;
|
|
3401
|
+
}
|
|
3402
|
+
const maskLen = masked ? 4 : 0;
|
|
3403
|
+
if (buf.length < off + maskLen + len)
|
|
3404
|
+
break;
|
|
3405
|
+
let payload = buf.subarray(off + maskLen, off + maskLen + len);
|
|
3406
|
+
if (masked) {
|
|
3407
|
+
const mask = buf.subarray(off, off + 4);
|
|
3408
|
+
const unmasked = Buffer.alloc(len);
|
|
3409
|
+
for (let i = 0;i < len; i++)
|
|
3410
|
+
unmasked[i] = payload[i] ^ mask[i & 3];
|
|
3411
|
+
payload = unmasked;
|
|
3412
|
+
}
|
|
3413
|
+
buf = buf.subarray(off + maskLen + len);
|
|
3414
|
+
frames.push({ opcode, payload });
|
|
3415
|
+
}
|
|
3416
|
+
return frames;
|
|
3417
|
+
};
|
|
3418
|
+
};
|
|
3419
|
+
var upgradeWebSocket = (req, socket, handlers) => {
|
|
3420
|
+
const key = req.headers["sec-websocket-key"];
|
|
3421
|
+
if (typeof key !== "string" || (req.headers.upgrade ?? "").toLowerCase() !== "websocket") {
|
|
3422
|
+
socket.destroy();
|
|
3423
|
+
return null;
|
|
3424
|
+
}
|
|
3425
|
+
socket.write(`HTTP/1.1 101 Switching Protocols\r
|
|
3426
|
+
` + `Upgrade: websocket\r
|
|
3427
|
+
` + `Connection: Upgrade\r
|
|
3428
|
+
` + `Sec-WebSocket-Accept: ${acceptKey(key)}\r
|
|
3429
|
+
\r
|
|
3430
|
+
`);
|
|
3431
|
+
let open = true;
|
|
3432
|
+
const finish = () => {
|
|
3433
|
+
if (!open)
|
|
3434
|
+
return;
|
|
3435
|
+
open = false;
|
|
3436
|
+
handlers.onClose();
|
|
3437
|
+
};
|
|
3438
|
+
const decode = createFrameDecoder();
|
|
3439
|
+
socket.on("data", (chunk) => {
|
|
3440
|
+
for (const frame of decode(chunk)) {
|
|
3441
|
+
if (frame.opcode === OPCODE.TEXT) {
|
|
3442
|
+
handlers.onMessage(frame.payload.toString("utf8"));
|
|
3443
|
+
} else if (frame.opcode === OPCODE.PING) {
|
|
3444
|
+
if (open)
|
|
3445
|
+
socket.write(encodeControlFrame(OPCODE.PONG, frame.payload));
|
|
3446
|
+
} else if (frame.opcode === OPCODE.CLOSE) {
|
|
3447
|
+
if (open)
|
|
3448
|
+
socket.write(encodeControlFrame(OPCODE.CLOSE));
|
|
3449
|
+
socket.end();
|
|
3450
|
+
finish();
|
|
3451
|
+
}
|
|
3452
|
+
}
|
|
3453
|
+
});
|
|
3454
|
+
socket.on("close", finish);
|
|
3455
|
+
socket.on("error", () => socket.destroy());
|
|
3456
|
+
return {
|
|
3457
|
+
send: (text) => {
|
|
3458
|
+
if (open)
|
|
3459
|
+
socket.write(encodeTextFrame(text));
|
|
3460
|
+
},
|
|
3461
|
+
close: () => {
|
|
3462
|
+
if (!open)
|
|
3463
|
+
return;
|
|
3464
|
+
socket.write(encodeControlFrame(OPCODE.CLOSE));
|
|
3465
|
+
socket.end();
|
|
3466
|
+
finish();
|
|
3467
|
+
}
|
|
3468
|
+
};
|
|
3469
|
+
};
|
|
3470
|
+
|
|
3471
|
+
// src/dev/devServer.ts
|
|
3472
|
+
var MIME = {
|
|
3473
|
+
png: "image/png",
|
|
3474
|
+
jpg: "image/jpeg",
|
|
3475
|
+
jpeg: "image/jpeg",
|
|
3476
|
+
webp: "image/webp",
|
|
3477
|
+
gif: "image/gif",
|
|
3478
|
+
svg: "image/svg+xml",
|
|
3479
|
+
ktx: "application/octet-stream",
|
|
3480
|
+
ktx2: "application/octet-stream",
|
|
3481
|
+
glb: "model/gltf-binary",
|
|
3482
|
+
bin: "application/octet-stream",
|
|
3483
|
+
mp3: "audio/mpeg",
|
|
3484
|
+
wav: "audio/wav",
|
|
3485
|
+
ogg: "audio/ogg",
|
|
3486
|
+
m4a: "audio/mp4",
|
|
3487
|
+
mp4: "video/mp4",
|
|
3488
|
+
webm: "video/webm",
|
|
3489
|
+
ttf: "font/ttf",
|
|
3490
|
+
otf: "font/otf",
|
|
3491
|
+
woff: "font/woff",
|
|
3492
|
+
woff2: "font/woff2",
|
|
3493
|
+
json: "application/json",
|
|
3494
|
+
txt: "text/plain",
|
|
3495
|
+
js: "text/javascript"
|
|
3496
|
+
};
|
|
3497
|
+
var contentType = (path) => {
|
|
3498
|
+
const i = path.lastIndexOf(".");
|
|
3499
|
+
return i >= 0 && MIME[path.slice(i + 1).toLowerCase()] || "application/octet-stream";
|
|
3500
|
+
};
|
|
3501
|
+
var sendText = (res, status, type, body) => {
|
|
3502
|
+
res.writeHead(status, { "content-type": type, "cache-control": "no-store" });
|
|
3503
|
+
res.end(body);
|
|
3504
|
+
};
|
|
3505
|
+
var sendJson = (res, status, body) => sendText(res, status, "application/json", JSON.stringify(body));
|
|
3506
|
+
var readBody = (req) => new Promise((resolve3) => {
|
|
3507
|
+
let body = "";
|
|
3508
|
+
req.on("data", (c2) => {
|
|
3509
|
+
if (body.length < 256 * 1024)
|
|
3510
|
+
body += c2.toString("utf8");
|
|
3511
|
+
});
|
|
3512
|
+
req.on("end", () => resolve3(body));
|
|
3513
|
+
req.on("error", () => resolve3(body));
|
|
3514
|
+
});
|
|
3515
|
+
var startDevServer = async (options) => {
|
|
3516
|
+
const { root, manifest, name, origin, token, entryOverride } = options;
|
|
3517
|
+
const log2 = options.log ?? (() => {});
|
|
3518
|
+
const base = `/t/${token}`;
|
|
3519
|
+
let v = 0;
|
|
3520
|
+
let bundleJs = null;
|
|
3521
|
+
let compileChain = Promise.resolve();
|
|
3522
|
+
const stripVolatile = (js) => js.replace(/^\/\/ last-updated: .*$/m, "");
|
|
3523
|
+
const compileOnce = async () => {
|
|
3524
|
+
try {
|
|
3525
|
+
const { entries, warnings } = collectLocalEntries(root, manifest, `${base}/assets`);
|
|
3526
|
+
const js = await compileProject2({ entries, name, publicUrl: origin, entryOverride, header: true });
|
|
3527
|
+
const changed = bundleJs === null || stripVolatile(js) !== stripVolatile(bundleJs);
|
|
3528
|
+
if (changed) {
|
|
3529
|
+
bundleJs = js;
|
|
3530
|
+
v++;
|
|
3531
|
+
broadcast(JSON.stringify({ type: "reload", v }));
|
|
3532
|
+
}
|
|
3533
|
+
return { ok: true, changed, v, warnings };
|
|
3534
|
+
} catch (e) {
|
|
3535
|
+
return { ok: false, error: e instanceof Error ? e.message : String(e) };
|
|
3536
|
+
}
|
|
3537
|
+
};
|
|
3538
|
+
const recompile = () => {
|
|
3539
|
+
const run = compileChain.then(compileOnce);
|
|
3540
|
+
compileChain = run;
|
|
3541
|
+
return run;
|
|
3542
|
+
};
|
|
3543
|
+
const devJs = await compileProject2({
|
|
3544
|
+
entries: [{ path: "/.dev-entry.ts", type: "text", text: renderDevScreen(name) }],
|
|
3545
|
+
name: "LeCodes Dev",
|
|
3546
|
+
publicUrl: origin,
|
|
3547
|
+
entryOverride: "/.dev-entry.ts",
|
|
3548
|
+
header: true
|
|
3549
|
+
});
|
|
3550
|
+
const clients = new Set;
|
|
3551
|
+
const broadcast = (text) => {
|
|
3552
|
+
for (const client of clients)
|
|
3553
|
+
client.send(text);
|
|
3554
|
+
};
|
|
3555
|
+
const printDeviceMessage = (raw) => {
|
|
3556
|
+
let m = {};
|
|
3557
|
+
try {
|
|
3558
|
+
m = JSON.parse(raw);
|
|
3559
|
+
} catch {
|
|
3560
|
+
return;
|
|
3561
|
+
}
|
|
3562
|
+
if (m.type === "log")
|
|
3563
|
+
log2(`[device:${m.level ?? "log"}] ${m.text ?? ""}`);
|
|
3564
|
+
else if (m.type === "error")
|
|
3565
|
+
log2(`[device:error] ${m.text ?? ""}`);
|
|
3566
|
+
};
|
|
3567
|
+
const transportOf = (url) => url.searchParams.get("t") === "poll" ? "poll" : "ws";
|
|
3568
|
+
const handle = async (req, res) => {
|
|
3569
|
+
const url = new URL(req.url ?? "/", origin);
|
|
3570
|
+
const path = url.pathname;
|
|
3571
|
+
if (!path.startsWith(base + "/"))
|
|
3572
|
+
return sendText(res, 404, "text/plain", "Not found");
|
|
3573
|
+
const route = path.slice(base.length);
|
|
3574
|
+
if (route === "/dev.js") {
|
|
3575
|
+
return sendText(res, 200, "text/javascript", devJs + `
|
|
3576
|
+
` + renderPrelude({ origin, base, transport: transportOf(url), v: -1 }));
|
|
3577
|
+
}
|
|
3578
|
+
if (route === "/bundle.js") {
|
|
3579
|
+
if (bundleJs === null)
|
|
3580
|
+
return sendText(res, 503, "text/plain", "No successful compile yet — check the terminal.");
|
|
3581
|
+
return sendText(res, 200, "text/javascript", bundleJs + `
|
|
3582
|
+
` + renderPrelude({ origin, base, transport: transportOf(url), v }));
|
|
3583
|
+
}
|
|
3584
|
+
if (route === "/version") {
|
|
3585
|
+
return sendJson(res, 200, { v });
|
|
3586
|
+
}
|
|
3587
|
+
if (route === "/log" && req.method === "POST") {
|
|
3588
|
+
printDeviceMessage(await readBody(req));
|
|
3589
|
+
return sendJson(res, 200, { ok: true });
|
|
3590
|
+
}
|
|
3591
|
+
if (route.startsWith("/assets/")) {
|
|
3592
|
+
let key;
|
|
3593
|
+
try {
|
|
3594
|
+
key = toKey(decodeURIComponent(route.slice("/assets".length)));
|
|
3595
|
+
} catch {
|
|
3596
|
+
return sendText(res, 400, "text/plain", "Bad path");
|
|
3597
|
+
}
|
|
3598
|
+
const abs = join13(root, key.slice(1));
|
|
3599
|
+
if (!existsSync11(abs) || !statSync2(abs).isFile())
|
|
3600
|
+
return sendText(res, 404, "text/plain", "Not found");
|
|
3601
|
+
res.writeHead(200, { "content-type": contentType(key), "cache-control": "no-store" });
|
|
3602
|
+
createReadStream(abs).pipe(res);
|
|
3603
|
+
return;
|
|
3604
|
+
}
|
|
3605
|
+
return sendText(res, 404, "text/plain", "Not found");
|
|
3606
|
+
};
|
|
3607
|
+
const server = createServer2((req, res) => {
|
|
3608
|
+
handle(req, res).catch((e) => {
|
|
3609
|
+
log2(`request failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
3610
|
+
if (!res.headersSent)
|
|
3611
|
+
sendText(res, 500, "text/plain", "Internal error");
|
|
3612
|
+
});
|
|
3613
|
+
});
|
|
3614
|
+
server.on("upgrade", (req, socket) => {
|
|
3615
|
+
const url = new URL(req.url ?? "/", origin);
|
|
3616
|
+
if (url.pathname !== base + "/ws") {
|
|
3617
|
+
socket.destroy();
|
|
3618
|
+
return;
|
|
3619
|
+
}
|
|
3620
|
+
const conn = upgradeWebSocket(req, socket, {
|
|
3621
|
+
onMessage: (text) => {
|
|
3622
|
+
let m = {};
|
|
3623
|
+
try {
|
|
3624
|
+
m = JSON.parse(text);
|
|
3625
|
+
} catch {}
|
|
3626
|
+
if (m.type === "hello") {
|
|
3627
|
+
if (typeof m.v === "number" && m.v !== v && bundleJs !== null) {
|
|
3628
|
+
conn?.send(JSON.stringify({ type: "reload", v }));
|
|
3629
|
+
}
|
|
3630
|
+
} else {
|
|
3631
|
+
printDeviceMessage(text);
|
|
3632
|
+
}
|
|
3633
|
+
},
|
|
3634
|
+
onClose: () => {
|
|
3635
|
+
if (conn)
|
|
3636
|
+
clients.delete(conn);
|
|
3637
|
+
}
|
|
3638
|
+
});
|
|
3639
|
+
if (conn)
|
|
3640
|
+
clients.add(conn);
|
|
3641
|
+
});
|
|
3642
|
+
await new Promise((resolve3, reject) => {
|
|
3643
|
+
server.once("error", reject);
|
|
3644
|
+
server.listen(options.port, options.bind ?? "0.0.0.0", () => {
|
|
3645
|
+
server.removeListener("error", reject);
|
|
3646
|
+
resolve3();
|
|
3647
|
+
});
|
|
3648
|
+
});
|
|
3649
|
+
const address = server.address();
|
|
3650
|
+
const boundPort = typeof address === "object" && address !== null ? address.port : options.port;
|
|
3651
|
+
return {
|
|
3652
|
+
url: `${origin}${base}/dev.js`,
|
|
3653
|
+
base,
|
|
3654
|
+
port: boundPort,
|
|
3655
|
+
v: () => v,
|
|
3656
|
+
clientCount: () => clients.size,
|
|
3657
|
+
recompile,
|
|
3658
|
+
close: () => {
|
|
3659
|
+
for (const client of clients)
|
|
3660
|
+
client.close();
|
|
3661
|
+
server.close();
|
|
3662
|
+
}
|
|
3663
|
+
};
|
|
3664
|
+
};
|
|
3665
|
+
|
|
3666
|
+
// src/commands/dev.ts
|
|
3667
|
+
var DEFAULT_PORT2 = 4499;
|
|
3668
|
+
var DEBOUNCE_MS = 120;
|
|
3669
|
+
var WATCH_SKIP_DIRS = new Set([".lecodes", ".git", "node_modules"]);
|
|
3670
|
+
var WATCH_SKIP_FILES = new Set(["tsconfig.json", "jsconfig.json", ".gitignore", ".lecodesignore", ".DS_Store"]);
|
|
3671
|
+
var pickLanAddress = () => {
|
|
3672
|
+
const nets = networkInterfaces();
|
|
3673
|
+
for (const name of Object.keys(nets)) {
|
|
3674
|
+
for (const net of nets[name] ?? []) {
|
|
3675
|
+
if (net.family === "IPv4" && !net.internal)
|
|
3676
|
+
return net.address;
|
|
3677
|
+
}
|
|
3678
|
+
}
|
|
3679
|
+
return null;
|
|
3680
|
+
};
|
|
3681
|
+
var loadDevToken = (root) => {
|
|
3682
|
+
const path = join14(root, LECODES_DIR, "dev.json");
|
|
3683
|
+
try {
|
|
3684
|
+
const token2 = JSON.parse(readFileSync11(path, "utf8")).token;
|
|
3685
|
+
if (token2 && /^[a-z0-9]{8,}$/.test(token2))
|
|
3686
|
+
return token2;
|
|
3687
|
+
} catch {}
|
|
3688
|
+
const token = randomBytes2(6).toString("hex");
|
|
3689
|
+
mkdirSync9(join14(root, LECODES_DIR), { recursive: true });
|
|
3690
|
+
writeFileSync9(path, JSON.stringify({ token }, null, 2) + `
|
|
3691
|
+
`);
|
|
3692
|
+
return token;
|
|
3693
|
+
};
|
|
3694
|
+
var printQr = async (url) => {
|
|
3695
|
+
try {
|
|
3696
|
+
const qrcode = (await Promise.resolve().then(() => __toESM(require_main(), 1))).default;
|
|
3697
|
+
await new Promise((resolve3) => qrcode.generate(url, { small: true }, (out) => {
|
|
3698
|
+
log(out);
|
|
3699
|
+
resolve3();
|
|
3700
|
+
}));
|
|
3701
|
+
} catch {
|
|
3702
|
+
note("(couldn't render a QR code — open the URL below on the device)");
|
|
3703
|
+
}
|
|
3704
|
+
};
|
|
3705
|
+
var dev = async (args) => {
|
|
3706
|
+
let root;
|
|
3707
|
+
let manifest;
|
|
3708
|
+
try {
|
|
3709
|
+
root = findProjectRoot(process.cwd());
|
|
3710
|
+
manifest = readManifest(root);
|
|
3711
|
+
} catch {
|
|
3712
|
+
root = process.cwd();
|
|
3713
|
+
manifest = null;
|
|
3714
|
+
}
|
|
3715
|
+
const name = manifest?.name ?? basename4(root);
|
|
3716
|
+
if (typeof globalThis.Bun !== "undefined") {
|
|
3717
|
+
warnErr("Running under Bun: the websocket reload channel doesn't work here — run `lecodes dev` with Node (or use ?t=poll on the device URL).");
|
|
3718
|
+
}
|
|
3719
|
+
const port = Number(flagStr(args, "port")) || DEFAULT_PORT2;
|
|
3720
|
+
const host = flagStr(args, "host") ?? pickLanAddress();
|
|
3721
|
+
if (!host)
|
|
3722
|
+
throw new CliError("No LAN address found — pass one with --host <ip>.");
|
|
3723
|
+
const origin = `http://${host}:${port}`;
|
|
3724
|
+
const token = loadDevToken(root);
|
|
3725
|
+
const server = await startDevServer({
|
|
3726
|
+
root,
|
|
3727
|
+
manifest,
|
|
3728
|
+
name,
|
|
3729
|
+
origin,
|
|
3730
|
+
port,
|
|
3731
|
+
token,
|
|
3732
|
+
entryOverride: flagStr(args, "entry"),
|
|
3733
|
+
log: note
|
|
3734
|
+
}).catch((e) => {
|
|
3735
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
3736
|
+
throw new CliError(msg.includes("EADDRINUSE") ? `Port ${port} is already in use — pass --port <n>.` : msg);
|
|
3737
|
+
});
|
|
3738
|
+
note("Compiling…");
|
|
3739
|
+
const first = await server.recompile();
|
|
3740
|
+
if (first.ok) {
|
|
3741
|
+
for (const w of first.warnings)
|
|
3742
|
+
warnErr(w);
|
|
3743
|
+
} else {
|
|
3744
|
+
warnErr(`Compile failed — fix it and save; devices connect once it compiles:
|
|
3745
|
+
${first.error}`);
|
|
3746
|
+
}
|
|
3747
|
+
const ignore = loadIgnore(root);
|
|
3748
|
+
const shouldRecompile = (file) => {
|
|
3749
|
+
if (file === null)
|
|
3750
|
+
return true;
|
|
3751
|
+
const parts = file.replace(/\\/g, "/").split("/");
|
|
3752
|
+
if (parts.some((p) => WATCH_SKIP_DIRS.has(p)))
|
|
3753
|
+
return false;
|
|
3754
|
+
if (WATCH_SKIP_FILES.has(parts[parts.length - 1]))
|
|
3755
|
+
return false;
|
|
3756
|
+
try {
|
|
3757
|
+
const key = toKey(file);
|
|
3758
|
+
if (ignore(key, false))
|
|
3759
|
+
return false;
|
|
3760
|
+
} catch {
|
|
3761
|
+
return false;
|
|
3762
|
+
}
|
|
3763
|
+
return true;
|
|
3764
|
+
};
|
|
3765
|
+
const debug = process.env.LECODES_DEV_DEBUG === "1";
|
|
3766
|
+
let timer = null;
|
|
3767
|
+
const onChange = (file) => {
|
|
3768
|
+
if (debug)
|
|
3769
|
+
note(`[watch] event: ${file ?? "(null)"} → ${shouldRecompile(file) ? "recompile" : "skip"}`);
|
|
3770
|
+
if (!shouldRecompile(file))
|
|
3771
|
+
return;
|
|
3772
|
+
if (timer)
|
|
3773
|
+
clearTimeout(timer);
|
|
3774
|
+
timer = setTimeout(async () => {
|
|
3775
|
+
timer = null;
|
|
3776
|
+
const result = await server.recompile();
|
|
3777
|
+
if (!result.ok) {
|
|
3778
|
+
warnErr(`Compile failed (devices keep the last good version):
|
|
3779
|
+
${result.error}`);
|
|
3780
|
+
} else if (result.changed) {
|
|
3781
|
+
const devices = server.clientCount();
|
|
3782
|
+
note(`✓ v${result.v} → ${devices} device${devices === 1 ? "" : "s"}`);
|
|
3783
|
+
for (const w of result.warnings)
|
|
3784
|
+
warnErr(w);
|
|
3785
|
+
}
|
|
3786
|
+
}, DEBOUNCE_MS);
|
|
3787
|
+
};
|
|
3788
|
+
let watcher = null;
|
|
3789
|
+
try {
|
|
3790
|
+
watcher = watch(root, { recursive: true }, (_type, file) => onChange(file));
|
|
3791
|
+
} catch {
|
|
3792
|
+
warnErr("fs.watch(recursive) unavailable on this platform — hot reload disabled (restart to pick up changes).");
|
|
3793
|
+
}
|
|
3794
|
+
watcher?.on("error", (e) => warnErr(`Watcher error — hot reload may have stopped (restart lecodes dev): ${e.message}`));
|
|
3795
|
+
log("");
|
|
3796
|
+
log(`${c.bold("LeCodes Dev")} — ${name}`);
|
|
3797
|
+
log("");
|
|
3798
|
+
if (!flagBool(args, "no-qr"))
|
|
3799
|
+
await printQr(server.url);
|
|
3800
|
+
log(`Scan the QR with the LeCodes app, or open: ${c.bold(server.url)}`);
|
|
3801
|
+
note(`Older desktop builds (no websocket bridge): ${server.url}?t=poll`);
|
|
3802
|
+
if (existsSync12(join14(root, LECODES_DIR, "manifest.json")))
|
|
3803
|
+
note(`Token stored in ${LECODES_DIR}/dev.json (delete it to rotate the URL).`);
|
|
3804
|
+
log("");
|
|
3805
|
+
log(`Watching ${root} — save a file to hot-reload. Ctrl+C to stop.`);
|
|
3806
|
+
};
|
|
3807
|
+
|
|
3808
|
+
// src/serverDiff.ts
|
|
3809
|
+
import { readFileSync as readFileSync12 } from "node:fs";
|
|
3810
|
+
import { basename as basename5 } from "node:path";
|
|
2103
3811
|
var isTextAsset = (t) => t === "text" || t === "shader" || t === "scene";
|
|
2104
3812
|
var computeServerDiff = (project, scan) => {
|
|
2105
3813
|
const pathById = buildPaths(project.assets);
|
|
@@ -2116,8 +3824,8 @@ var computeServerDiff = (project, scan) => {
|
|
|
2116
3824
|
const server = serverByPath.get(path);
|
|
2117
3825
|
const local = localByPath.get(path);
|
|
2118
3826
|
if (local && !server) {
|
|
2119
|
-
const text = isTextKind(classifyKind(
|
|
2120
|
-
entries.push({ path, status: "added", binary: !text, serverText: "", localText: text ?
|
|
3827
|
+
const text = isTextKind(classifyKind(basename5(path)));
|
|
3828
|
+
entries.push({ path, status: "added", binary: !text, serverText: "", localText: text ? readFileSync12(local.absPath, "utf8") : undefined });
|
|
2121
3829
|
continue;
|
|
2122
3830
|
}
|
|
2123
3831
|
if (server && !local) {
|
|
@@ -2128,12 +3836,12 @@ var computeServerDiff = (project, scan) => {
|
|
|
2128
3836
|
if (server && local) {
|
|
2129
3837
|
if (isTextAsset(server.type)) {
|
|
2130
3838
|
const serverText = server.text ?? "";
|
|
2131
|
-
const localText =
|
|
3839
|
+
const localText = readFileSync12(local.absPath, "utf8");
|
|
2132
3840
|
if (serverText !== localText)
|
|
2133
3841
|
entries.push({ path, status: "modified", binary: false, serverText, localText });
|
|
2134
3842
|
} else {
|
|
2135
3843
|
const serverSize = server.file?.size;
|
|
2136
|
-
const localSize = Buffer.byteLength(
|
|
3844
|
+
const localSize = Buffer.byteLength(readFileSync12(local.absPath));
|
|
2137
3845
|
if (serverSize !== undefined && serverSize !== localSize) {
|
|
2138
3846
|
entries.push({ path, status: "modified", binary: true });
|
|
2139
3847
|
}
|
|
@@ -2285,6 +3993,76 @@ var diff = async (args) => {
|
|
|
2285
3993
|
};
|
|
2286
3994
|
var statusLabel = (e) => e.status === "added" ? c.green(" added ") : e.status === "removed" ? c.red(" removed ") : c.yellow(" modified ");
|
|
2287
3995
|
|
|
3996
|
+
// src/commands/init.ts
|
|
3997
|
+
import { existsSync as existsSync13, mkdirSync as mkdirSync10, writeFileSync as writeFileSync10 } from "node:fs";
|
|
3998
|
+
import { basename as basename6, dirname as dirname8, join as join15, resolve as resolve3 } from "node:path";
|
|
3999
|
+
var STARTER2 = `// Welcome to LeCodes — the whole SDK is available as globals, no imports needed.
|
|
4000
|
+
// Run it live on a device with \`lecodes dev\`, or bundle it with \`lecodes preview -o app.js\`.
|
|
4001
|
+
|
|
4002
|
+
let count = 0
|
|
4003
|
+
|
|
4004
|
+
const counter = UIText({ color: "#9fb0d0", fontSize: 22, marginTop: 18 }, "Taps: 0")
|
|
4005
|
+
|
|
4006
|
+
const button = UIButton(
|
|
4007
|
+
{
|
|
4008
|
+
backgroundColor: "#4f7cff",
|
|
4009
|
+
borderRadius: 14,
|
|
4010
|
+
paddingVertical: 16,
|
|
4011
|
+
paddingHorizontal: 40,
|
|
4012
|
+
marginTop: 24,
|
|
4013
|
+
alignItems: "center",
|
|
4014
|
+
justifyContent: "center",
|
|
4015
|
+
},
|
|
4016
|
+
[UIText({ color: "#ffffff", fontSize: 22 }, "Tap me")],
|
|
4017
|
+
).onClick(() => {
|
|
4018
|
+
count++
|
|
4019
|
+
counter.text = "Taps: " + count
|
|
4020
|
+
})
|
|
4021
|
+
|
|
4022
|
+
const screen = UIScreen(
|
|
4023
|
+
{ backgroundColor: "#1e2230", alignItems: "center", justifyContent: "center", padding: 40 },
|
|
4024
|
+
[
|
|
4025
|
+
UIColumn(
|
|
4026
|
+
{ backgroundColor: "#2b3550", borderRadius: 24, padding: 40, alignItems: "center" },
|
|
4027
|
+
[UIText({ color: "#ffffff", fontSize: 32 }, "Hello, LeCodes"), button, counter],
|
|
4028
|
+
),
|
|
4029
|
+
],
|
|
4030
|
+
)
|
|
4031
|
+
|
|
4032
|
+
screen.open()
|
|
4033
|
+
`;
|
|
4034
|
+
var init2 = async (args) => {
|
|
4035
|
+
const dirArg = (args._[0] ?? ".").replace(/[/\\]+$/, "") || ".";
|
|
4036
|
+
const root = resolve3(dirArg);
|
|
4037
|
+
const name = basename6(root);
|
|
4038
|
+
mkdirSync10(root, { recursive: true });
|
|
4039
|
+
let created = 0;
|
|
4040
|
+
const write = (rel, content) => {
|
|
4041
|
+
const abs = join15(root, rel);
|
|
4042
|
+
if (existsSync13(abs)) {
|
|
4043
|
+
note(`kept ${rel}`);
|
|
4044
|
+
return;
|
|
4045
|
+
}
|
|
4046
|
+
mkdirSync10(dirname8(abs), { recursive: true });
|
|
4047
|
+
writeFileSync10(abs, content);
|
|
4048
|
+
log(`${c.green("created")} ${rel}`);
|
|
4049
|
+
created++;
|
|
4050
|
+
};
|
|
4051
|
+
write("main.ts", STARTER2);
|
|
4052
|
+
write(".lecodesignore", DEFAULT_IGNORE_FILE);
|
|
4053
|
+
const wroteTypes = materializeTypesLocal(root);
|
|
4054
|
+
writeTsconfig(root);
|
|
4055
|
+
log(`${c.green("written")} tsconfig.json${wroteTypes ? ` + ${LECODES_DIR}/types/` : ""} (IDE types)`);
|
|
4056
|
+
if (!wroteTypes) {
|
|
4057
|
+
warnErr("Bundled SDK types not found — tsconfig written, but globals may show unresolved until the CLI is rebuilt with vendored types.");
|
|
4058
|
+
}
|
|
4059
|
+
log("");
|
|
4060
|
+
success(created ? `Local project ${c.bold(name)} ready${dirArg === "." ? "" : ` in ${c.bold(dirArg)}/`}.` : `Project ${c.bold(name)} already initialized.`);
|
|
4061
|
+
const cd = dirArg === "." ? "" : `cd ${dirArg} && `;
|
|
4062
|
+
log(` ${c.bold(cd + "lecodes dev")} run it on a device with hot reload`);
|
|
4063
|
+
log(` ${c.bold(cd + "lecodes preview -o app.js")} bundle it for LeCodes Desktop`);
|
|
4064
|
+
};
|
|
4065
|
+
|
|
2288
4066
|
// src/commands/login.ts
|
|
2289
4067
|
var login = async (args) => {
|
|
2290
4068
|
const config = loadConfig();
|
|
@@ -2297,12 +4075,12 @@ var login = async (args) => {
|
|
|
2297
4075
|
};
|
|
2298
4076
|
|
|
2299
4077
|
// src/commands/preview.ts
|
|
2300
|
-
import { writeFileSync as
|
|
2301
|
-
import { resolve as
|
|
4078
|
+
import { writeFileSync as writeFileSync11 } from "node:fs";
|
|
4079
|
+
import { basename as basename8, resolve as resolve4 } from "node:path";
|
|
2302
4080
|
|
|
2303
4081
|
// src/compile/collect.ts
|
|
2304
|
-
import { readFileSync as
|
|
2305
|
-
import { basename as
|
|
4082
|
+
import { readFileSync as readFileSync13 } from "node:fs";
|
|
4083
|
+
import { basename as basename7 } from "node:path";
|
|
2306
4084
|
var collectEntries = (root, manifest, project) => {
|
|
2307
4085
|
const pathById = buildPaths(project.assets);
|
|
2308
4086
|
const serverByPath = new Map;
|
|
@@ -2314,7 +4092,7 @@ var collectEntries = (root, manifest, project) => {
|
|
|
2314
4092
|
const entries = [];
|
|
2315
4093
|
const warnings = [];
|
|
2316
4094
|
for (const file of scanLocal(root).files) {
|
|
2317
|
-
const type = manifest.files[file.path]?.type ?? classifyKind(
|
|
4095
|
+
const type = manifest.files[file.path]?.type ?? classifyKind(basename7(file.path));
|
|
2318
4096
|
if (type === "resource") {
|
|
2319
4097
|
const src = serverByPath.get(file.path)?.fileSrc;
|
|
2320
4098
|
if (!src)
|
|
@@ -2326,7 +4104,7 @@ var collectEntries = (root, manifest, project) => {
|
|
|
2326
4104
|
warnings.push(`No compiled shader for ${file.path} — push it to compile the shader.`);
|
|
2327
4105
|
entries.push({ path: file.path, type, shaders });
|
|
2328
4106
|
} else {
|
|
2329
|
-
entries.push({ path: file.path, type, text:
|
|
4107
|
+
entries.push({ path: file.path, type, text: readFileSync13(file.absPath, "utf8") });
|
|
2330
4108
|
}
|
|
2331
4109
|
}
|
|
2332
4110
|
return { entries, warnings };
|
|
@@ -2334,21 +4112,44 @@ var collectEntries = (root, manifest, project) => {
|
|
|
2334
4112
|
|
|
2335
4113
|
// src/commands/preview.ts
|
|
2336
4114
|
var preview = async (args) => {
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
4115
|
+
let root;
|
|
4116
|
+
let manifest;
|
|
4117
|
+
try {
|
|
4118
|
+
root = findProjectRoot(process.cwd());
|
|
4119
|
+
manifest = readManifest(root);
|
|
4120
|
+
} catch {
|
|
4121
|
+
root = process.cwd();
|
|
4122
|
+
manifest = null;
|
|
4123
|
+
}
|
|
4124
|
+
let entries;
|
|
4125
|
+
let warnings;
|
|
4126
|
+
let name;
|
|
4127
|
+
let publicUrl;
|
|
4128
|
+
let localAssets = false;
|
|
4129
|
+
if (manifest) {
|
|
4130
|
+
const config = loadConfig();
|
|
4131
|
+
const apiUrl = requireApiUrl(config);
|
|
4132
|
+
const token = requireToken(config);
|
|
4133
|
+
note("Resolving project assets…");
|
|
4134
|
+
const project = await getProject(apiUrl, token, manifest.uuid);
|
|
4135
|
+
({ entries, warnings } = collectEntries(root, manifest, project));
|
|
4136
|
+
name = manifest.name;
|
|
4137
|
+
publicUrl = flagStr(args, "public-url") ?? apiUrl;
|
|
4138
|
+
} else {
|
|
4139
|
+
const publicUrlFlag = flagStr(args, "public-url");
|
|
4140
|
+
localAssets = publicUrlFlag === undefined;
|
|
4141
|
+
publicUrl = publicUrlFlag ?? "";
|
|
4142
|
+
({ entries, warnings } = collectLocalEntries(root, null, publicUrl));
|
|
4143
|
+
name = basename8(root);
|
|
4144
|
+
}
|
|
2345
4145
|
note("Compiling…");
|
|
2346
4146
|
const js = await compileProject2({
|
|
2347
4147
|
entries,
|
|
2348
|
-
name
|
|
2349
|
-
publicUrl
|
|
4148
|
+
name,
|
|
4149
|
+
publicUrl,
|
|
2350
4150
|
entryOverride: flagStr(args, "entry"),
|
|
2351
|
-
header: !flagBool(args, "no-header")
|
|
4151
|
+
header: !flagBool(args, "no-header"),
|
|
4152
|
+
localAssets
|
|
2352
4153
|
});
|
|
2353
4154
|
for (const w of warnings)
|
|
2354
4155
|
warnErr(w);
|
|
@@ -2356,7 +4157,7 @@ var preview = async (args) => {
|
|
|
2356
4157
|
if (out && isNullSink(out)) {
|
|
2357
4158
|
note(`Discarded output (${out})`);
|
|
2358
4159
|
} else if (out) {
|
|
2359
|
-
|
|
4160
|
+
writeFileSync11(resolve4(out), js);
|
|
2360
4161
|
note(`Wrote ${out} (${js.length} bytes)`);
|
|
2361
4162
|
} else {
|
|
2362
4163
|
process.stdout.write(js);
|
|
@@ -2368,8 +4169,8 @@ var preview = async (args) => {
|
|
|
2368
4169
|
};
|
|
2369
4170
|
|
|
2370
4171
|
// src/commands/render.ts
|
|
2371
|
-
import { writeFileSync as
|
|
2372
|
-
import { resolve as
|
|
4172
|
+
import { writeFileSync as writeFileSync12 } from "node:fs";
|
|
4173
|
+
import { resolve as resolve5 } from "node:path";
|
|
2373
4174
|
var LOCAL_ASSET_SCHEME2 = "lecodesfile://";
|
|
2374
4175
|
var DEVICE_SAFE_AREA = {
|
|
2375
4176
|
none: [0, 0, 0, 0],
|
|
@@ -2465,7 +4266,7 @@ var render = async (args) => {
|
|
|
2465
4266
|
if (isNullSink(pngFlag)) {
|
|
2466
4267
|
note(`Discarded PNG (${pngFlag})`);
|
|
2467
4268
|
} else {
|
|
2468
|
-
|
|
4269
|
+
writeFileSync12(resolve5(pngFlag), png);
|
|
2469
4270
|
note(`Wrote ${pngFlag} (${png.length} bytes, ${width}x${height})`);
|
|
2470
4271
|
}
|
|
2471
4272
|
return done((cb) => cb());
|
|
@@ -2480,7 +4281,7 @@ var render = async (args) => {
|
|
|
2480
4281
|
return done((cb) => cb());
|
|
2481
4282
|
}
|
|
2482
4283
|
if (out) {
|
|
2483
|
-
|
|
4284
|
+
writeFileSync12(resolve5(out), result.text);
|
|
2484
4285
|
note(`Wrote ${out} (${result.text.length} bytes)`);
|
|
2485
4286
|
return done((cb) => cb());
|
|
2486
4287
|
}
|
|
@@ -2491,8 +4292,8 @@ var render = async (args) => {
|
|
|
2491
4292
|
};
|
|
2492
4293
|
|
|
2493
4294
|
// src/commands/pull.ts
|
|
2494
|
-
import { existsSync as
|
|
2495
|
-
import { dirname as
|
|
4295
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync11, rmSync, writeFileSync as writeFileSync13 } from "node:fs";
|
|
4296
|
+
import { dirname as dirname9, join as join16 } from "node:path";
|
|
2496
4297
|
var pull = async (args) => {
|
|
2497
4298
|
const root = findProjectRoot(process.cwd());
|
|
2498
4299
|
const manifest = readManifest(root);
|
|
@@ -2512,8 +4313,8 @@ var pull = async (args) => {
|
|
|
2512
4313
|
const remotePaths = new Set([...buildPaths(project.assets).entries()].filter(([id]) => project.assets.find((a) => a.id === id)?.type !== "folder").map(([, path]) => path));
|
|
2513
4314
|
for (const path of Object.keys(manifest.files)) {
|
|
2514
4315
|
if (!remotePaths.has(path)) {
|
|
2515
|
-
const abs =
|
|
2516
|
-
if (
|
|
4316
|
+
const abs = join16(root, ...path.replace(/^\//, "").split("/"));
|
|
4317
|
+
if (existsSync14(abs))
|
|
2517
4318
|
rmSync(abs);
|
|
2518
4319
|
}
|
|
2519
4320
|
}
|
|
@@ -2551,18 +4352,18 @@ var pullPaths = async (root, manifest, project, paths, apiUrl, token) => {
|
|
|
2551
4352
|
const files = { ...manifest.files };
|
|
2552
4353
|
for (const asset of targets) {
|
|
2553
4354
|
const key = pathById.get(asset.id);
|
|
2554
|
-
const abs =
|
|
2555
|
-
|
|
4355
|
+
const abs = join16(root, ...key.replace(/^\//, "").split("/"));
|
|
4356
|
+
mkdirSync11(dirname9(abs), { recursive: true });
|
|
2556
4357
|
let sha;
|
|
2557
4358
|
if (asset.type === "file") {
|
|
2558
4359
|
if (!asset.file?.src)
|
|
2559
4360
|
continue;
|
|
2560
4361
|
const bytes = await downloadBlob(apiUrl, asset.file.src);
|
|
2561
|
-
|
|
4362
|
+
writeFileSync13(abs, bytes);
|
|
2562
4363
|
sha = sha256(bytes);
|
|
2563
4364
|
} else {
|
|
2564
4365
|
const text = asset.text ?? "";
|
|
2565
|
-
|
|
4366
|
+
writeFileSync13(abs, text);
|
|
2566
4367
|
sha = sha256(text);
|
|
2567
4368
|
}
|
|
2568
4369
|
files[key] = { id: asset.id, type: kindOf2(asset.type), sha };
|
|
@@ -2574,8 +4375,8 @@ var pullPaths = async (root, manifest, project, paths, apiUrl, token) => {
|
|
|
2574
4375
|
};
|
|
2575
4376
|
|
|
2576
4377
|
// src/commands/push.ts
|
|
2577
|
-
import { basename as
|
|
2578
|
-
import { readFileSync as
|
|
4378
|
+
import { basename as basename9 } from "node:path";
|
|
4379
|
+
import { readFileSync as readFileSync14 } from "node:fs";
|
|
2579
4380
|
var push = async (args) => {
|
|
2580
4381
|
const root = findProjectRoot(process.cwd());
|
|
2581
4382
|
const manifest = readManifest(root);
|
|
@@ -2629,14 +4430,14 @@ var push = async (args) => {
|
|
|
2629
4430
|
let uploaded = 0;
|
|
2630
4431
|
for (const file of scan.files) {
|
|
2631
4432
|
const source = sourceFor(file.path);
|
|
2632
|
-
const kind = source?.type ?? classifyKind(
|
|
4433
|
+
const kind = source?.type ?? classifyKind(basename9(file.path));
|
|
2633
4434
|
const entry = { path: file.path, type: kind };
|
|
2634
4435
|
if (source)
|
|
2635
4436
|
entry.assetId = source.id;
|
|
2636
4437
|
if (isTextKind(kind)) {
|
|
2637
|
-
entry.text =
|
|
4438
|
+
entry.text = readFileSync14(file.absPath, "utf8");
|
|
2638
4439
|
} else if (!source || source.sha !== file.sha) {
|
|
2639
|
-
const blob = await uploadBlob(apiUrl, token, manifest.uuid,
|
|
4440
|
+
const blob = await uploadBlob(apiUrl, token, manifest.uuid, basename9(file.path), readFileSync14(file.absPath));
|
|
2640
4441
|
entry.blobFileId = blob.id;
|
|
2641
4442
|
uploaded++;
|
|
2642
4443
|
}
|
|
@@ -2723,6 +4524,9 @@ var HELP = `${c.bold("lecodes")} — clone, edit and push LeCodes projects from
|
|
|
2723
4524
|
${c.bold("Usage:")} lecodes <command> [options]
|
|
2724
4525
|
|
|
2725
4526
|
${c.bold("Commands:")}
|
|
4527
|
+
init [dir] Scaffold a new LOCAL project (no login/server): a starter
|
|
4528
|
+
main.ts, IDE types + tsconfig, and a .lecodesignore.
|
|
4529
|
+
Run it with 'lecodes dev' or 'lecodes preview'.
|
|
2726
4530
|
login Authorize in the browser and store an access token
|
|
2727
4531
|
--token <pat> store a token from the web UI instead
|
|
2728
4532
|
--api <url> API origin (default https://le.codes)
|
|
@@ -2744,6 +4548,14 @@ ${c.bold("Commands:")}
|
|
|
2744
4548
|
--force push even if the server moved on (shows + confirms
|
|
2745
4549
|
which server files get overwritten)
|
|
2746
4550
|
-y, --yes skip the --force overwrite confirmation
|
|
4551
|
+
dev Run the project on a device from this machine, with hot reload:
|
|
4552
|
+
starts a LAN dev server + prints a QR code; scan it with the
|
|
4553
|
+
LeCodes app. Saves recompile + hot-swap the running app; device
|
|
4554
|
+
logs/errors stream back here. No login needed.
|
|
4555
|
+
--port <n> server port (default 4499)
|
|
4556
|
+
--host <ip> LAN address to advertise (default: auto-detect)
|
|
4557
|
+
--entry <path> override the entrypoint
|
|
4558
|
+
--no-qr don't render the QR code
|
|
2747
4559
|
preview Compile the local project to JS (prints to stdout)
|
|
2748
4560
|
-o, --out <file> write to a file instead of stdout
|
|
2749
4561
|
--entry <path> override the entrypoint
|
|
@@ -2774,15 +4586,8 @@ ${c.bold("Commands:")}
|
|
|
2774
4586
|
--logs forward the screens' console output (to stderr)
|
|
2775
4587
|
|
|
2776
4588
|
Config lives in ~/.lecodes/config.json (override with LECODES_API / LECODES_TOKEN).`;
|
|
2777
|
-
var commands = { login, create, clone, status, diff, pull, push, preview, render, design };
|
|
2778
|
-
var readVersion = () =>
|
|
2779
|
-
try {
|
|
2780
|
-
const here2 = dirname8(fileURLToPath4(import.meta.url));
|
|
2781
|
-
return JSON.parse(readFileSync13(join13(here2, "..", "package.json"), "utf8")).version ?? "unknown";
|
|
2782
|
-
} catch {
|
|
2783
|
-
return "unknown";
|
|
2784
|
-
}
|
|
2785
|
-
};
|
|
4589
|
+
var commands = { init: init2, login, create, clone, status, diff, pull, push, preview, render, design, dev };
|
|
4590
|
+
var readVersion = () => package_default.version ?? "unknown";
|
|
2786
4591
|
var main = async () => {
|
|
2787
4592
|
const argv = process.argv.slice(2);
|
|
2788
4593
|
const command = argv[0];
|