zero-query 1.0.9 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +2 -0
- package/cli/args.js +33 -33
- package/cli/commands/build-api.js +443 -0
- package/cli/commands/build.js +254 -216
- package/cli/commands/bundle.js +1228 -1183
- package/cli/commands/create.js +137 -121
- package/cli/commands/dev/devtools/index.js +56 -56
- package/cli/commands/dev/devtools/js/components.js +49 -49
- package/cli/commands/dev/devtools/js/core.js +423 -423
- package/cli/commands/dev/devtools/js/elements.js +421 -421
- package/cli/commands/dev/devtools/js/network.js +166 -166
- package/cli/commands/dev/devtools/js/performance.js +73 -73
- package/cli/commands/dev/devtools/js/router.js +105 -105
- package/cli/commands/dev/devtools/js/source.js +132 -132
- package/cli/commands/dev/devtools/js/stats.js +35 -35
- package/cli/commands/dev/devtools/js/tabs.js +79 -79
- package/cli/commands/dev/devtools/panel.html +95 -95
- package/cli/commands/dev/devtools/styles.css +244 -244
- package/cli/commands/dev/index.js +107 -107
- package/cli/commands/dev/logger.js +75 -75
- package/cli/commands/dev/overlay.js +858 -858
- package/cli/commands/dev/server.js +220 -167
- package/cli/commands/dev/validator.js +94 -94
- package/cli/commands/dev/watcher.js +172 -172
- package/cli/help.js +114 -112
- package/cli/index.js +52 -52
- package/cli/scaffold/default/LICENSE +21 -21
- package/cli/scaffold/default/app/app.js +207 -207
- package/cli/scaffold/default/app/components/about.js +201 -201
- package/cli/scaffold/default/app/components/api-demo.js +143 -143
- package/cli/scaffold/default/app/components/contact-card.js +231 -231
- package/cli/scaffold/default/app/components/contacts/contacts.css +706 -706
- package/cli/scaffold/default/app/components/contacts/contacts.html +200 -200
- package/cli/scaffold/default/app/components/contacts/contacts.js +196 -196
- package/cli/scaffold/default/app/components/counter.js +127 -127
- package/cli/scaffold/default/app/components/home.js +249 -249
- package/cli/scaffold/default/app/components/not-found.js +16 -16
- package/cli/scaffold/default/app/components/playground/playground.css +115 -115
- package/cli/scaffold/default/app/components/playground/playground.html +161 -161
- package/cli/scaffold/default/app/components/playground/playground.js +116 -116
- package/cli/scaffold/default/app/components/todos.js +225 -225
- package/cli/scaffold/default/app/components/toolkit/toolkit.css +97 -97
- package/cli/scaffold/default/app/components/toolkit/toolkit.html +146 -146
- package/cli/scaffold/default/app/components/toolkit/toolkit.js +280 -280
- package/cli/scaffold/default/app/routes.js +15 -15
- package/cli/scaffold/default/app/store.js +101 -101
- package/cli/scaffold/default/global.css +552 -552
- package/cli/scaffold/default/index.html +99 -99
- package/cli/scaffold/minimal/app/app.js +85 -85
- package/cli/scaffold/minimal/app/components/about.js +68 -68
- package/cli/scaffold/minimal/app/components/counter.js +122 -122
- package/cli/scaffold/minimal/app/components/home.js +68 -68
- package/cli/scaffold/minimal/app/components/not-found.js +16 -16
- package/cli/scaffold/minimal/app/routes.js +9 -9
- package/cli/scaffold/minimal/app/store.js +36 -36
- package/cli/scaffold/minimal/global.css +300 -300
- package/cli/scaffold/minimal/index.html +44 -44
- package/cli/scaffold/ssr/app/app.js +41 -41
- package/cli/scaffold/ssr/app/components/about.js +55 -55
- package/cli/scaffold/ssr/app/components/blog/index.js +65 -65
- package/cli/scaffold/ssr/app/components/blog/post.js +86 -86
- package/cli/scaffold/ssr/app/components/home.js +37 -37
- package/cli/scaffold/ssr/app/components/not-found.js +15 -15
- package/cli/scaffold/ssr/app/routes.js +8 -8
- package/cli/scaffold/ssr/global.css +228 -228
- package/cli/scaffold/ssr/index.html +37 -37
- package/cli/scaffold/ssr/package.json +8 -8
- package/cli/scaffold/ssr/server/data/posts.js +144 -144
- package/cli/scaffold/ssr/server/index.js +213 -213
- package/cli/scaffold/webrtc/app/app.js +11 -0
- package/cli/scaffold/webrtc/app/components/video-room.js +295 -0
- package/cli/scaffold/webrtc/app/lib/room.js +252 -0
- package/cli/scaffold/webrtc/assets/.gitkeep +0 -0
- package/cli/scaffold/webrtc/global.css +250 -0
- package/cli/scaffold/webrtc/index.html +21 -0
- package/cli/utils.js +305 -287
- package/dist/API.md +7264 -0
- package/dist/zquery.dist.zip +0 -0
- package/dist/zquery.js +10313 -6252
- package/dist/zquery.min.js +8 -601
- package/index.d.ts +570 -365
- package/index.js +311 -232
- package/package.json +76 -69
- package/src/component.js +1709 -1454
- package/src/core.js +921 -921
- package/src/diff.js +497 -497
- package/src/errors.js +209 -209
- package/src/expression.js +922 -922
- package/src/http.js +242 -242
- package/src/package.json +1 -1
- package/src/reactive.js +255 -254
- package/src/router.js +843 -773
- package/src/ssr.js +418 -418
- package/src/store.js +318 -272
- package/src/utils.js +515 -515
- package/src/webrtc/e2ee.js +351 -0
- package/src/webrtc/errors.js +116 -0
- package/src/webrtc/ice.js +301 -0
- package/src/webrtc/index.js +131 -0
- package/src/webrtc/joinToken.js +119 -0
- package/src/webrtc/observe.js +172 -0
- package/src/webrtc/peer.js +351 -0
- package/src/webrtc/reactive.js +268 -0
- package/src/webrtc/room.js +625 -0
- package/src/webrtc/sdp.js +302 -0
- package/src/webrtc/sfu/index.js +43 -0
- package/src/webrtc/sfu/livekit.js +131 -0
- package/src/webrtc/sfu/mediasoup.js +150 -0
- package/src/webrtc/signaling.js +373 -0
- package/src/webrtc/turn.js +237 -0
- package/tests/_helpers/webrtcFakes.js +289 -0
- package/tests/audit.test.js +4158 -4158
- package/tests/cli.test.js +1136 -1023
- package/tests/compare.test.js +497 -0
- package/tests/component.test.js +3969 -3938
- package/tests/core.test.js +1910 -1910
- package/tests/dev-server.test.js +489 -0
- package/tests/diff.test.js +1416 -1416
- package/tests/docs.test.js +1664 -0
- package/tests/electron-features.test.js +864 -0
- package/tests/errors.test.js +619 -619
- package/tests/expression.test.js +1056 -1056
- package/tests/http.test.js +648 -648
- package/tests/reactive.test.js +819 -819
- package/tests/router.test.js +2327 -2327
- package/tests/ssr.test.js +870 -870
- package/tests/store.test.js +830 -830
- package/tests/test-minifier.js +153 -153
- package/tests/test-ssr.js +27 -27
- package/tests/utils.test.js +1377 -1377
- package/tests/webrtc/e2ee.test.js +283 -0
- package/tests/webrtc/ice.test.js +202 -0
- package/tests/webrtc/joinToken.test.js +89 -0
- package/tests/webrtc/observe.test.js +111 -0
- package/tests/webrtc/peer.test.js +373 -0
- package/tests/webrtc/reactive.test.js +235 -0
- package/tests/webrtc/room.test.js +406 -0
- package/tests/webrtc/sdp.test.js +151 -0
- package/tests/webrtc/sfu-livekit.test.js +119 -0
- package/tests/webrtc/sfu.test.js +160 -0
- package/tests/webrtc/signaling.test.js +251 -0
- package/tests/webrtc/turn.test.js +256 -0
- package/types/collection.d.ts +383 -383
- package/types/component.d.ts +186 -186
- package/types/errors.d.ts +135 -135
- package/types/http.d.ts +92 -92
- package/types/misc.d.ts +201 -201
- package/types/reactive.d.ts +98 -98
- package/types/router.d.ts +190 -190
- package/types/ssr.d.ts +102 -102
- package/types/store.d.ts +146 -145
- package/types/utils.d.ts +245 -245
- package/types/webrtc.d.ts +653 -0
package/cli/utils.js
CHANGED
|
@@ -1,287 +1,305 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* cli/utils.js - shared utility functions
|
|
3
|
-
*
|
|
4
|
-
* Context-aware comment stripping, quick minification, size formatting,
|
|
5
|
-
* and recursive directory copying. These are consumed by both the
|
|
6
|
-
* build and bundle commands.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
'use strict';
|
|
10
|
-
|
|
11
|
-
const fs = require('fs');
|
|
12
|
-
const path = require('path');
|
|
13
|
-
|
|
14
|
-
// ---------------------------------------------------------------------------
|
|
15
|
-
// _copyTemplateLiteral - copy a template literal verbatim, tracking ${…}
|
|
16
|
-
// nesting so that `//` inside template text isn't mistaken for a comment.
|
|
17
|
-
// ---------------------------------------------------------------------------
|
|
18
|
-
|
|
19
|
-
function _copyTemplateLiteral(code, start) {
|
|
20
|
-
let out = '`';
|
|
21
|
-
let i = start + 1; // skip opening backtick
|
|
22
|
-
let depth = 0;
|
|
23
|
-
while (i < code.length) {
|
|
24
|
-
if (code[i] === '\\') { out += code[i] + (code[i + 1] || ''); i += 2; continue; }
|
|
25
|
-
if (code[i] === '$' && code[i + 1] === '{') { depth++; out += '${'; i += 2; continue; }
|
|
26
|
-
if (depth > 0) {
|
|
27
|
-
if (code[i] === '{') { depth++; out += code[i]; i++; continue; }
|
|
28
|
-
if (code[i] === '}') { depth--; out += code[i]; i++; continue; }
|
|
29
|
-
if (code[i] === '`') {
|
|
30
|
-
const nested = _copyTemplateLiteral(code, i);
|
|
31
|
-
out += nested.text; i = nested.end; continue;
|
|
32
|
-
}
|
|
33
|
-
if (code[i] === '"' || code[i] === "'") {
|
|
34
|
-
const q = code[i]; out += code[i]; i++;
|
|
35
|
-
while (i < code.length) {
|
|
36
|
-
if (code[i] === '\\') { out += code[i] + (code[i + 1] || ''); i += 2; continue; }
|
|
37
|
-
out += code[i];
|
|
38
|
-
if (code[i] === q) { i++; break; }
|
|
39
|
-
i++;
|
|
40
|
-
}
|
|
41
|
-
continue;
|
|
42
|
-
}
|
|
43
|
-
out += code[i]; i++; continue;
|
|
44
|
-
}
|
|
45
|
-
if (code[i] === '`') { out += '`'; i++; return { text: out, end: i }; }
|
|
46
|
-
out += code[i]; i++;
|
|
47
|
-
}
|
|
48
|
-
return { text: out, end: i };
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// ---------------------------------------------------------------------------
|
|
52
|
-
// stripComments - context-aware, skips strings / templates / regex
|
|
53
|
-
// ---------------------------------------------------------------------------
|
|
54
|
-
|
|
55
|
-
function stripComments(code) {
|
|
56
|
-
let out = '';
|
|
57
|
-
let i = 0;
|
|
58
|
-
while (i < code.length) {
|
|
59
|
-
const ch = code[i];
|
|
60
|
-
const next = code[i + 1];
|
|
61
|
-
|
|
62
|
-
// Regular string literals: copy verbatim
|
|
63
|
-
if (ch === '"' || ch === "'") {
|
|
64
|
-
const quote = ch;
|
|
65
|
-
out += ch; i++;
|
|
66
|
-
while (i < code.length) {
|
|
67
|
-
if (code[i] === '\\') { out += code[i] + (code[i + 1] || ''); i += 2; continue; }
|
|
68
|
-
out += code[i];
|
|
69
|
-
if (code[i] === quote) { i++; break; }
|
|
70
|
-
i++;
|
|
71
|
-
}
|
|
72
|
-
continue;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// Template literal: copy verbatim with ${…} nesting support
|
|
76
|
-
if (ch === '`') {
|
|
77
|
-
const tpl = _copyTemplateLiteral(code, i);
|
|
78
|
-
out += tpl.text; i = tpl.end;
|
|
79
|
-
continue;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// Block comment
|
|
83
|
-
if (ch === '/' && next === '*') {
|
|
84
|
-
i += 2;
|
|
85
|
-
while (i < code.length && !(code[i] === '*' && code[i + 1] === '/')) i++;
|
|
86
|
-
i += 2;
|
|
87
|
-
continue;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// Line comment
|
|
91
|
-
if (ch === '/' && next === '/') {
|
|
92
|
-
i += 2;
|
|
93
|
-
while (i < code.length && code[i] !== '\n') i++;
|
|
94
|
-
continue;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// Regex literal
|
|
98
|
-
if (ch === '/') {
|
|
99
|
-
const before = out.replace(/\s+$/, '');
|
|
100
|
-
const last = before[before.length - 1];
|
|
101
|
-
const isRegexCtx = !last || '=({[,;:!&|?~+-*/%^>'.includes(last)
|
|
102
|
-
|| before.endsWith('return') || before.endsWith('typeof')
|
|
103
|
-
|| before.endsWith('case') || before.endsWith('in')
|
|
104
|
-
|| before.endsWith('delete') || before.endsWith('void')
|
|
105
|
-
|| before.endsWith('throw') || before.endsWith('new');
|
|
106
|
-
if (isRegexCtx) {
|
|
107
|
-
out += ch; i++;
|
|
108
|
-
let inCharClass = false;
|
|
109
|
-
while (i < code.length) {
|
|
110
|
-
const rc = code[i];
|
|
111
|
-
if (rc === '\\') { out += rc + (code[i + 1] || ''); i += 2; continue; }
|
|
112
|
-
if (rc === '[') inCharClass = true;
|
|
113
|
-
if (rc === ']') inCharClass = false;
|
|
114
|
-
out += rc; i++;
|
|
115
|
-
if (rc === '/' && !inCharClass) {
|
|
116
|
-
while (i < code.length && /[gimsuy]/.test(code[i])) { out += code[i]; i++; }
|
|
117
|
-
break;
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
continue;
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
out += ch; i++;
|
|
125
|
-
}
|
|
126
|
-
return out;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// ---------------------------------------------------------------------------
|
|
130
|
-
// minify -
|
|
131
|
-
//
|
|
132
|
-
// and
|
|
133
|
-
//
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
i
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
return false;
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
1
|
+
/**
|
|
2
|
+
* cli/utils.js - shared utility functions
|
|
3
|
+
*
|
|
4
|
+
* Context-aware comment stripping, quick minification, size formatting,
|
|
5
|
+
* and recursive directory copying. These are consumed by both the
|
|
6
|
+
* build and bundle commands.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const fs = require('fs');
|
|
12
|
+
const path = require('path');
|
|
13
|
+
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
// _copyTemplateLiteral - copy a template literal verbatim, tracking ${…}
|
|
16
|
+
// nesting so that `//` inside template text isn't mistaken for a comment.
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
|
|
19
|
+
function _copyTemplateLiteral(code, start) {
|
|
20
|
+
let out = '`';
|
|
21
|
+
let i = start + 1; // skip opening backtick
|
|
22
|
+
let depth = 0;
|
|
23
|
+
while (i < code.length) {
|
|
24
|
+
if (code[i] === '\\') { out += code[i] + (code[i + 1] || ''); i += 2; continue; }
|
|
25
|
+
if (code[i] === '$' && code[i + 1] === '{') { depth++; out += '${'; i += 2; continue; }
|
|
26
|
+
if (depth > 0) {
|
|
27
|
+
if (code[i] === '{') { depth++; out += code[i]; i++; continue; }
|
|
28
|
+
if (code[i] === '}') { depth--; out += code[i]; i++; continue; }
|
|
29
|
+
if (code[i] === '`') {
|
|
30
|
+
const nested = _copyTemplateLiteral(code, i);
|
|
31
|
+
out += nested.text; i = nested.end; continue;
|
|
32
|
+
}
|
|
33
|
+
if (code[i] === '"' || code[i] === "'") {
|
|
34
|
+
const q = code[i]; out += code[i]; i++;
|
|
35
|
+
while (i < code.length) {
|
|
36
|
+
if (code[i] === '\\') { out += code[i] + (code[i + 1] || ''); i += 2; continue; }
|
|
37
|
+
out += code[i];
|
|
38
|
+
if (code[i] === q) { i++; break; }
|
|
39
|
+
i++;
|
|
40
|
+
}
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
out += code[i]; i++; continue;
|
|
44
|
+
}
|
|
45
|
+
if (code[i] === '`') { out += '`'; i++; return { text: out, end: i }; }
|
|
46
|
+
out += code[i]; i++;
|
|
47
|
+
}
|
|
48
|
+
return { text: out, end: i };
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// ---------------------------------------------------------------------------
|
|
52
|
+
// stripComments - context-aware, skips strings / templates / regex
|
|
53
|
+
// ---------------------------------------------------------------------------
|
|
54
|
+
|
|
55
|
+
function stripComments(code) {
|
|
56
|
+
let out = '';
|
|
57
|
+
let i = 0;
|
|
58
|
+
while (i < code.length) {
|
|
59
|
+
const ch = code[i];
|
|
60
|
+
const next = code[i + 1];
|
|
61
|
+
|
|
62
|
+
// Regular string literals: copy verbatim
|
|
63
|
+
if (ch === '"' || ch === "'") {
|
|
64
|
+
const quote = ch;
|
|
65
|
+
out += ch; i++;
|
|
66
|
+
while (i < code.length) {
|
|
67
|
+
if (code[i] === '\\') { out += code[i] + (code[i + 1] || ''); i += 2; continue; }
|
|
68
|
+
out += code[i];
|
|
69
|
+
if (code[i] === quote) { i++; break; }
|
|
70
|
+
i++;
|
|
71
|
+
}
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Template literal: copy verbatim with ${…} nesting support
|
|
76
|
+
if (ch === '`') {
|
|
77
|
+
const tpl = _copyTemplateLiteral(code, i);
|
|
78
|
+
out += tpl.text; i = tpl.end;
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Block comment
|
|
83
|
+
if (ch === '/' && next === '*') {
|
|
84
|
+
i += 2;
|
|
85
|
+
while (i < code.length && !(code[i] === '*' && code[i + 1] === '/')) i++;
|
|
86
|
+
i += 2;
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Line comment
|
|
91
|
+
if (ch === '/' && next === '/') {
|
|
92
|
+
i += 2;
|
|
93
|
+
while (i < code.length && code[i] !== '\n') i++;
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Regex literal
|
|
98
|
+
if (ch === '/') {
|
|
99
|
+
const before = out.replace(/\s+$/, '');
|
|
100
|
+
const last = before[before.length - 1];
|
|
101
|
+
const isRegexCtx = !last || '=({[,;:!&|?~+-*/%^>'.includes(last)
|
|
102
|
+
|| before.endsWith('return') || before.endsWith('typeof')
|
|
103
|
+
|| before.endsWith('case') || before.endsWith('in')
|
|
104
|
+
|| before.endsWith('delete') || before.endsWith('void')
|
|
105
|
+
|| before.endsWith('throw') || before.endsWith('new');
|
|
106
|
+
if (isRegexCtx) {
|
|
107
|
+
out += ch; i++;
|
|
108
|
+
let inCharClass = false;
|
|
109
|
+
while (i < code.length) {
|
|
110
|
+
const rc = code[i];
|
|
111
|
+
if (rc === '\\') { out += rc + (code[i + 1] || ''); i += 2; continue; }
|
|
112
|
+
if (rc === '[') inCharClass = true;
|
|
113
|
+
if (rc === ']') inCharClass = false;
|
|
114
|
+
out += rc; i++;
|
|
115
|
+
if (rc === '/' && !inCharClass) {
|
|
116
|
+
while (i < code.length && /[gimsuy]/.test(code[i])) { out += code[i]; i++; }
|
|
117
|
+
break;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
out += ch; i++;
|
|
125
|
+
}
|
|
126
|
+
return out;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// ---------------------------------------------------------------------------
|
|
130
|
+
// minify - production minification via esbuild
|
|
131
|
+
// Performs identifier mangling, dead-code elimination, whitespace removal,
|
|
132
|
+
// and boolean shortening. Falls back to the legacy in-house pass-through
|
|
133
|
+
// minifier if esbuild fails to load (e.g. on a clean clone before
|
|
134
|
+
// `npm install`).
|
|
135
|
+
// ---------------------------------------------------------------------------
|
|
136
|
+
|
|
137
|
+
function minify(code, banner) {
|
|
138
|
+
let esbuild;
|
|
139
|
+
try { esbuild = require('esbuild'); }
|
|
140
|
+
catch (_) { return banner + '\n' + _minifyBody(code.replace(banner, '')); }
|
|
141
|
+
|
|
142
|
+
const body = code.replace(banner, '');
|
|
143
|
+
const result = esbuild.transformSync(body, {
|
|
144
|
+
minify: true,
|
|
145
|
+
target: 'es2019',
|
|
146
|
+
legalComments: 'none',
|
|
147
|
+
treeShaking: true,
|
|
148
|
+
keepNames: false,
|
|
149
|
+
minifyIdentifiers: true,
|
|
150
|
+
minifyWhitespace: true,
|
|
151
|
+
minifySyntax: true,
|
|
152
|
+
charset: 'utf8',
|
|
153
|
+
});
|
|
154
|
+
return banner + '\n' + result.code.trimEnd() + '\n';
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Single-pass minifier: walks character-by-character, skips strings/regex,
|
|
159
|
+
* strips comments, and emits a space only when both neighbours are
|
|
160
|
+
* identifier-like characters (or when collapsing would create ++, --, // or /*).
|
|
161
|
+
*/
|
|
162
|
+
function _minifyBody(code) {
|
|
163
|
+
let out = '';
|
|
164
|
+
let i = 0;
|
|
165
|
+
|
|
166
|
+
while (i < code.length) {
|
|
167
|
+
const ch = code[i];
|
|
168
|
+
const nx = code[i + 1];
|
|
169
|
+
|
|
170
|
+
// -- Regular string literal: copy verbatim -----------------
|
|
171
|
+
if (ch === '"' || ch === "'") {
|
|
172
|
+
const q = ch;
|
|
173
|
+
out += ch; i++;
|
|
174
|
+
while (i < code.length) {
|
|
175
|
+
if (code[i] === '\\') { out += code[i] + (code[i + 1] || ''); i += 2; continue; }
|
|
176
|
+
out += code[i];
|
|
177
|
+
if (code[i] === q) { i++; break; }
|
|
178
|
+
i++;
|
|
179
|
+
}
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// -- Template literal: copy verbatim with ${…} nesting -------
|
|
184
|
+
if (ch === '`') {
|
|
185
|
+
const tpl = _copyTemplateLiteral(code, i);
|
|
186
|
+
out += tpl.text; i = tpl.end;
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// -- Block comment: skip -------------------------------------
|
|
191
|
+
if (ch === '/' && nx === '*') {
|
|
192
|
+
i += 2;
|
|
193
|
+
while (i < code.length && !(code[i] === '*' && code[i + 1] === '/')) i++;
|
|
194
|
+
i += 2;
|
|
195
|
+
continue;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// -- Line comment: skip --------------------------------------
|
|
199
|
+
if (ch === '/' && nx === '/') {
|
|
200
|
+
i += 2;
|
|
201
|
+
while (i < code.length && code[i] !== '\n') i++;
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// -- Regex literal: copy verbatim ----------------------------
|
|
206
|
+
if (ch === '/') {
|
|
207
|
+
if (_isRegexCtx(out)) {
|
|
208
|
+
out += ch; i++;
|
|
209
|
+
let inCC = false;
|
|
210
|
+
while (i < code.length) {
|
|
211
|
+
const rc = code[i];
|
|
212
|
+
if (rc === '\\') { out += rc + (code[i + 1] || ''); i += 2; continue; }
|
|
213
|
+
if (rc === '[') inCC = true;
|
|
214
|
+
if (rc === ']') inCC = false;
|
|
215
|
+
out += rc; i++;
|
|
216
|
+
if (rc === '/' && !inCC) {
|
|
217
|
+
while (i < code.length && /[gimsuy]/.test(code[i])) { out += code[i]; i++; }
|
|
218
|
+
break;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// -- Whitespace: collapse ------------------------------------
|
|
226
|
+
if (ch === ' ' || ch === '\t' || ch === '\n' || ch === '\r') {
|
|
227
|
+
let hasNewline = ch === '\n' || ch === '\r';
|
|
228
|
+
while (i < code.length && (code[i] === ' ' || code[i] === '\t' || code[i] === '\n' || code[i] === '\r')) {
|
|
229
|
+
if (code[i] === '\n' || code[i] === '\r') hasNewline = true;
|
|
230
|
+
i++;
|
|
231
|
+
}
|
|
232
|
+
const before = out[out.length - 1];
|
|
233
|
+
const after = code[i];
|
|
234
|
+
// After '}', a newline may be needed for ASI (e.g. var x=function(){}⏎var y).
|
|
235
|
+
// A space alone doesn't trigger ASI, so preserve ';\n' when '}' precedes
|
|
236
|
+
// an identifier-start character and the original whitespace had a newline.
|
|
237
|
+
const afterIsId = after && ((after >= 'a' && after <= 'z') || (after >= 'A' && after <= 'Z') || after === '_' || after === '$');
|
|
238
|
+
if (before === '}' && afterIsId && hasNewline) { out += '\n'; continue; }
|
|
239
|
+
if (_needsSpace(before, after)) out += ' ';
|
|
240
|
+
continue;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
out += ch;
|
|
244
|
+
i++;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
return out;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/** True when removing the space between a and b would change semantics. */
|
|
251
|
+
function _needsSpace(a, b) {
|
|
252
|
+
if (!a || !b) return false;
|
|
253
|
+
const idA = (a >= 'a' && a <= 'z') || (a >= 'A' && a <= 'Z') || (a >= '0' && a <= '9') || a === '_' || a === '$';
|
|
254
|
+
const idB = (b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z') || (b >= '0' && b <= '9') || b === '_' || b === '$';
|
|
255
|
+
if (idA && idB) return true; // e.g. const x, return value
|
|
256
|
+
if (a === '+' && b === '+') return true; // prevent ++
|
|
257
|
+
if (a === '-' && b === '-') return true; // prevent --
|
|
258
|
+
if (a === '/' && (b === '/' || b === '*')) return true; // prevent // or /*
|
|
259
|
+
return false;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/** Heuristic: is the next '/' a regex start (vs division)? */
|
|
263
|
+
function _isRegexCtx(out) {
|
|
264
|
+
let end = out.length - 1;
|
|
265
|
+
while (end >= 0 && out[end] === ' ') end--;
|
|
266
|
+
if (end < 0) return true;
|
|
267
|
+
const last = out[end];
|
|
268
|
+
if ('=({[,;:!&|?~+-*/%^>'.includes(last)) return true;
|
|
269
|
+
const tail = out.substring(Math.max(0, end - 7), end + 1);
|
|
270
|
+
const kws = ['return', 'typeof', 'case', 'in', 'delete', 'void', 'throw', 'new'];
|
|
271
|
+
for (const kw of kws) {
|
|
272
|
+
if (tail.endsWith(kw)) {
|
|
273
|
+
const pos = end - kw.length;
|
|
274
|
+
if (pos < 0 || !((out[pos] >= 'a' && out[pos] <= 'z') || (out[pos] >= 'A' && out[pos] <= 'Z') || (out[pos] >= '0' && out[pos] <= '9') || out[pos] === '_' || out[pos] === '$')) return true;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
return false;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// ---------------------------------------------------------------------------
|
|
281
|
+
// sizeKB - human-readable file size
|
|
282
|
+
// ---------------------------------------------------------------------------
|
|
283
|
+
|
|
284
|
+
function sizeKB(buf) {
|
|
285
|
+
return (buf.length / 1024).toFixed(1);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// ---------------------------------------------------------------------------
|
|
289
|
+
// copyDirSync - recursive directory copy
|
|
290
|
+
// ---------------------------------------------------------------------------
|
|
291
|
+
|
|
292
|
+
function copyDirSync(src, dest) {
|
|
293
|
+
if (!fs.existsSync(dest)) fs.mkdirSync(dest, { recursive: true });
|
|
294
|
+
for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
|
|
295
|
+
const srcPath = path.join(src, entry.name);
|
|
296
|
+
const destPath = path.join(dest, entry.name);
|
|
297
|
+
if (entry.isDirectory()) {
|
|
298
|
+
copyDirSync(srcPath, destPath);
|
|
299
|
+
} else {
|
|
300
|
+
fs.copyFileSync(srcPath, destPath);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
module.exports = { stripComments, minify, sizeKB, copyDirSync };
|