zero-query 1.0.5 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/cli/commands/build-api.js +442 -0
- package/cli/commands/build.js +33 -2
- package/cli/commands/bundle.js +174 -8
- package/cli/commands/dev/server.js +57 -3
- package/cli/scaffold/default/app/components/contacts/contacts.css +9 -9
- package/cli/scaffold/default/app/components/playground/playground.css +1 -1
- package/cli/scaffold/default/app/components/playground/playground.html +5 -5
- package/cli/scaffold/default/app/components/playground/playground.js +1 -1
- package/cli/scaffold/default/app/components/toolkit/toolkit.css +1 -1
- package/cli/scaffold/default/app/components/toolkit/toolkit.html +3 -3
- package/cli/scaffold/default/app/components/toolkit/toolkit.js +4 -4
- package/cli/utils.js +16 -7
- package/dist/API.md +6603 -0
- package/dist/zquery.dist.zip +0 -0
- package/dist/zquery.js +387 -25
- package/dist/zquery.min.js +631 -2
- package/index.d.ts +9 -3
- package/index.js +10 -2
- package/package.json +3 -2
- package/src/component.js +243 -6
- package/src/reactive.js +4 -3
- package/src/router.js +79 -9
- package/src/store.js +49 -3
- package/tests/cli.test.js +343 -0
- package/tests/compare.test.js +486 -0
- package/tests/dev-server.test.js +489 -0
- package/tests/docs.test.js +1650 -0
- package/tests/electron-features.test.js +864 -0
- package/types/misc.d.ts +7 -7
- package/types/reactive.d.ts +1 -1
- package/types/store.d.ts +2 -1
package/tests/cli.test.js
CHANGED
|
@@ -1,6 +1,269 @@
|
|
|
1
1
|
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
2
|
|
|
3
3
|
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
// CLI bundle - stripModuleSyntax
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
|
|
8
|
+
describe('CLI - stripModuleSyntax', () => {
|
|
9
|
+
let stripModuleSyntax;
|
|
10
|
+
|
|
11
|
+
beforeEach(async () => {
|
|
12
|
+
vi.resetModules();
|
|
13
|
+
const mod = await import('../cli/commands/bundle.js');
|
|
14
|
+
stripModuleSyntax = mod.stripModuleSyntax;
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
// -- Import stripping ---------------------------------------------------
|
|
18
|
+
|
|
19
|
+
it('strips named import from module', () => {
|
|
20
|
+
const result = stripModuleSyntax("import { foo } from './mod.js';\nconst x = 1;");
|
|
21
|
+
expect(result.code.trim()).toBe('const x = 1;');
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('strips default import from module', () => {
|
|
25
|
+
const result = stripModuleSyntax("import foo from './mod.js';\nconst x = 1;");
|
|
26
|
+
expect(result.code.trim()).toBe('const x = 1;');
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('strips side-effect import', () => {
|
|
30
|
+
const result = stripModuleSyntax("import './mod.js';\nconst x = 1;");
|
|
31
|
+
expect(result.code.trim()).toBe('const x = 1;');
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('strips multi-line import', () => {
|
|
35
|
+
const input = "import {\n a,\n b,\n c\n} from './mod.js';\nconst x = 1;";
|
|
36
|
+
const result = stripModuleSyntax(input);
|
|
37
|
+
expect(result.code.trim()).toBe('const x = 1;');
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// -- export default -----------------------------------------------------
|
|
41
|
+
|
|
42
|
+
it('strips export default keyword', () => {
|
|
43
|
+
const result = stripModuleSyntax('export default function foo() {}');
|
|
44
|
+
expect(result.code.trim()).toBe('function foo() {}');
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// -- export const/let/var → var -----------------------------------------
|
|
48
|
+
|
|
49
|
+
it('converts export const to var', () => {
|
|
50
|
+
const result = stripModuleSyntax('export const x = 1;');
|
|
51
|
+
expect(result.code.trim()).toBe('var x = 1;');
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('converts export let to var', () => {
|
|
55
|
+
const result = stripModuleSyntax('export let y = 2;');
|
|
56
|
+
expect(result.code.trim()).toBe('var y = 2;');
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('converts export var (keeps var)', () => {
|
|
60
|
+
const result = stripModuleSyntax('export var z = 3;');
|
|
61
|
+
expect(result.code.trim()).toBe('var z = 3;');
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// -- export function → var assignment -----------------------------------
|
|
65
|
+
|
|
66
|
+
it('converts export function to var assignment', () => {
|
|
67
|
+
const result = stripModuleSyntax('export function greet(name) { return name; }');
|
|
68
|
+
expect(result.code.trim()).toBe('var greet = function greet(name) { return name; }');
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('converts export async function to var assignment', () => {
|
|
72
|
+
const result = stripModuleSyntax('export async function fetchData() {}');
|
|
73
|
+
expect(result.code.trim()).toBe('var fetchData = async function fetchData() {}');
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
// -- export class → var assignment --------------------------------------
|
|
77
|
+
|
|
78
|
+
it('converts export class to var assignment', () => {
|
|
79
|
+
const result = stripModuleSyntax('export class MyComponent {}');
|
|
80
|
+
expect(result.code.trim()).toBe('var MyComponent = class MyComponent {}');
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// -- bare export block: export { a, b } ---------------------------------
|
|
84
|
+
|
|
85
|
+
it('converts bare exported function declarations to var', () => {
|
|
86
|
+
const input = 'function buildIndex() {}\nexport { buildIndex };';
|
|
87
|
+
const result = stripModuleSyntax(input);
|
|
88
|
+
expect(result.code).toContain('var buildIndex = function buildIndex()');
|
|
89
|
+
expect(result.code).not.toContain('export');
|
|
90
|
+
expect(result.bareExportNames).toEqual([{ local: 'buildIndex', exported: 'buildIndex' }]);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('converts bare exported async function to var', () => {
|
|
94
|
+
const input = 'async function load() {}\nexport { load };';
|
|
95
|
+
const result = stripModuleSyntax(input);
|
|
96
|
+
expect(result.code).toContain('var load = async function load()');
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('converts bare exported const/let declarations to var', () => {
|
|
100
|
+
const input = 'const MAX = 10;\nlet count = 0;\nexport { MAX, count };';
|
|
101
|
+
const result = stripModuleSyntax(input);
|
|
102
|
+
expect(result.code).toContain('var MAX');
|
|
103
|
+
expect(result.code).toContain('var count');
|
|
104
|
+
expect(result.code).not.toContain('const MAX');
|
|
105
|
+
expect(result.code).not.toContain('let count');
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it('handles multi-line bare export block', () => {
|
|
109
|
+
const input = 'function a() {}\nfunction b() {}\nexport {\n a,\n b\n};';
|
|
110
|
+
const result = stripModuleSyntax(input);
|
|
111
|
+
expect(result.code).toContain('var a = function a()');
|
|
112
|
+
expect(result.code).toContain('var b = function b()');
|
|
113
|
+
expect(result.bareExportNames).toHaveLength(2);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
// -- export { local as exported } aliasing ------------------------------
|
|
117
|
+
|
|
118
|
+
it('creates alias for export { local as exported }', () => {
|
|
119
|
+
const input = 'function foo() {}\nexport { foo as bar };';
|
|
120
|
+
const result = stripModuleSyntax(input);
|
|
121
|
+
expect(result.code).toContain('var foo = function foo()');
|
|
122
|
+
expect(result.code).toContain('var bar = foo;');
|
|
123
|
+
expect(result.bareExportNames).toEqual([{ local: 'foo', exported: 'bar' }]);
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it('creates multiple aliases when needed', () => {
|
|
127
|
+
const input = 'function a() {}\nfunction b() {}\nexport { a as x, b as y };';
|
|
128
|
+
const result = stripModuleSyntax(input);
|
|
129
|
+
expect(result.code).toContain('var x = a;');
|
|
130
|
+
expect(result.code).toContain('var y = b;');
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it('does not create alias when local equals exported', () => {
|
|
134
|
+
const input = 'function foo() {}\nexport { foo };';
|
|
135
|
+
const result = stripModuleSyntax(input);
|
|
136
|
+
expect(result.code).not.toContain('var foo = foo;');
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it('handles mix of aliased and non-aliased exports', () => {
|
|
140
|
+
const input = 'function a() {}\nfunction b() {}\nexport { a, b as c };';
|
|
141
|
+
const result = stripModuleSyntax(input);
|
|
142
|
+
expect(result.code).toContain('var a = function a()');
|
|
143
|
+
expect(result.code).toContain('var b = function b()');
|
|
144
|
+
expect(result.code).not.toContain('var a = a;');
|
|
145
|
+
expect(result.code).toContain('var c = b;');
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
// -- Template literal preservation --------------------------------------
|
|
149
|
+
|
|
150
|
+
it('preserves export keyword inside template literal', () => {
|
|
151
|
+
const input = "const example = `export const x = 1;`;\nexport const y = 2;";
|
|
152
|
+
const result = stripModuleSyntax(input);
|
|
153
|
+
expect(result.code).toContain('`export const x = 1;`');
|
|
154
|
+
expect(result.code).toContain('var y = 2;');
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
it('preserves export class inside template literal', () => {
|
|
158
|
+
const input = "const code = `export class Counter {}`;\nexport class Real {}";
|
|
159
|
+
const result = stripModuleSyntax(input);
|
|
160
|
+
expect(result.code).toContain('`export class Counter {}`');
|
|
161
|
+
expect(result.code).toContain('var Real = class Real');
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it('preserves nested template literal content', () => {
|
|
165
|
+
const input = "const x = `outer ${`inner export const a = 1;`} end`;\nexport const b = 2;";
|
|
166
|
+
const result = stripModuleSyntax(input);
|
|
167
|
+
expect(result.code).toContain('inner export const a = 1;');
|
|
168
|
+
expect(result.code).toContain('var b = 2;');
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
it('handles deeply nested template literals', () => {
|
|
172
|
+
const input = "const x = `a ${y ? `b ${`c`}` : ''} d`;\nexport const z = 1;";
|
|
173
|
+
const result = stripModuleSyntax(input);
|
|
174
|
+
expect(result.code).toContain('var z = 1;');
|
|
175
|
+
// Nested templates should be preserved without corruption
|
|
176
|
+
expect(result.code).toContain('`a ${');
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
// -- Edge cases ---------------------------------------------------------
|
|
180
|
+
|
|
181
|
+
it('returns empty bareExportNames when no bare exports', () => {
|
|
182
|
+
const result = stripModuleSyntax('export const x = 1;');
|
|
183
|
+
expect(result.bareExportNames).toEqual([]);
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
it('handles code with no imports or exports', () => {
|
|
187
|
+
const input = 'const x = 1;\nfunction foo() {}';
|
|
188
|
+
const result = stripModuleSyntax(input);
|
|
189
|
+
expect(result.code.trim()).toBe(input);
|
|
190
|
+
expect(result.bareExportNames).toEqual([]);
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
it('preserves indentation', () => {
|
|
194
|
+
const result = stripModuleSyntax(' export const x = 1;');
|
|
195
|
+
expect(result.code).toContain(' var x = 1;');
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
it('handles export inside string (not template)', () => {
|
|
199
|
+
const input = 'const s = "export const x = 1;";\nexport const y = 2;';
|
|
200
|
+
const result = stripModuleSyntax(input);
|
|
201
|
+
expect(result.code).toContain('"export const x = 1;"');
|
|
202
|
+
expect(result.code).toContain('var y = 2;');
|
|
203
|
+
});
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
// ---------------------------------------------------------------------------
|
|
208
|
+
// CLI - minify ASI preservation
|
|
209
|
+
// ---------------------------------------------------------------------------
|
|
210
|
+
|
|
211
|
+
describe('CLI - minify ASI preservation', () => {
|
|
212
|
+
let minify;
|
|
213
|
+
|
|
214
|
+
beforeEach(async () => {
|
|
215
|
+
vi.resetModules();
|
|
216
|
+
const mod = await import('../cli/utils.js');
|
|
217
|
+
minify = mod.minify;
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
it('preserves newline between } and var', () => {
|
|
221
|
+
const input = 'var x = function() {}\nvar y = 1;';
|
|
222
|
+
const result = minify(input, '');
|
|
223
|
+
expect(result).toContain('}\nvar');
|
|
224
|
+
expect(result).not.toContain('}var');
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
it('preserves newline between } and identifier', () => {
|
|
228
|
+
const input = 'function a() {}\nfunction b() {}';
|
|
229
|
+
const result = minify(input, '');
|
|
230
|
+
expect(result).toContain('}\nfunction');
|
|
231
|
+
expect(result).not.toContain('}function');
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
it('preserves newline between } and const', () => {
|
|
235
|
+
const input = 'if (true) {}\nconst x = 1;';
|
|
236
|
+
const result = minify(input, '');
|
|
237
|
+
expect(result).toContain('}\nconst');
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
it('preserves newline between } and let', () => {
|
|
241
|
+
const input = 'if (true) {}\nlet x = 1;';
|
|
242
|
+
const result = minify(input, '');
|
|
243
|
+
expect(result).toContain('}\nlet');
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
it('does not add newline where none existed', () => {
|
|
247
|
+
const input = 'if(x){a()} else{b()}';
|
|
248
|
+
const result = minify(input, '');
|
|
249
|
+
// } followed by else on same line — no newline needed
|
|
250
|
+
expect(result).not.toContain('}\n');
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
it('handles }\\n followed by underscore-prefixed identifier', () => {
|
|
254
|
+
const input = 'var x = function() {}\n_init();';
|
|
255
|
+
const result = minify(input, '');
|
|
256
|
+
expect(result).toContain('}\n_init');
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
it('handles }\\n followed by $-prefixed identifier', () => {
|
|
260
|
+
const input = 'var x = function() {}\n$el.show();';
|
|
261
|
+
const result = minify(input, '');
|
|
262
|
+
expect(result).toContain('}\n$el');
|
|
263
|
+
});
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
|
|
4
267
|
// ---------------------------------------------------------------------------
|
|
5
268
|
// CLI utils - stripComments
|
|
6
269
|
// ---------------------------------------------------------------------------
|
|
@@ -758,3 +1021,83 @@ describe('CLI - createProject', () => {
|
|
|
758
1021
|
spy.mockRestore();
|
|
759
1022
|
});
|
|
760
1023
|
});
|
|
1024
|
+
|
|
1025
|
+
|
|
1026
|
+
// ===========================================================================
|
|
1027
|
+
// minifyTemplateLiterals - regex literal awareness
|
|
1028
|
+
// ===========================================================================
|
|
1029
|
+
|
|
1030
|
+
describe('CLI - minifyTemplateLiterals regex handling', () => {
|
|
1031
|
+
let minifyTemplateLiterals;
|
|
1032
|
+
|
|
1033
|
+
beforeEach(async () => {
|
|
1034
|
+
const mod = await import('../cli/commands/bundle.js');
|
|
1035
|
+
minifyTemplateLiterals = mod.minifyTemplateLiterals;
|
|
1036
|
+
});
|
|
1037
|
+
|
|
1038
|
+
it('preserves code after regex containing backtick characters', () => {
|
|
1039
|
+
// Simulates: h = h.replace(/`([^`]+)`/g, '<code>$1</code>');
|
|
1040
|
+
// The backtick inside the regex must not be mistaken for a template literal.
|
|
1041
|
+
const input = "h = h.replace(/\x60([^\x60]+)\x60/g, '<code>$1</code>');\nreturn h;";
|
|
1042
|
+
const result = minifyTemplateLiterals(input);
|
|
1043
|
+
expect(result).toContain('return h');
|
|
1044
|
+
expect(result).toContain('<code>$1</code>');
|
|
1045
|
+
});
|
|
1046
|
+
|
|
1047
|
+
it('does not eat closing braces after backtick-in-regex', () => {
|
|
1048
|
+
const input = [
|
|
1049
|
+
"var fmt = {",
|
|
1050
|
+
" md(raw) {",
|
|
1051
|
+
" let h = raw;",
|
|
1052
|
+
" h = h.replace(/\x60([^\x60]+)\x60/g, '<code>$1</code>');",
|
|
1053
|
+
" h = h.replace(/^[\\-\\*] (.+)$/gm, '<li>$1</li>');",
|
|
1054
|
+
" return h;",
|
|
1055
|
+
" }",
|
|
1056
|
+
"};",
|
|
1057
|
+
"var canvas = document.getElementById('bg-canvas');",
|
|
1058
|
+
].join('\n');
|
|
1059
|
+
const result = minifyTemplateLiterals(input);
|
|
1060
|
+
expect(result).toContain('return h;');
|
|
1061
|
+
expect(result).toContain('};');
|
|
1062
|
+
expect(result).toContain("getElementById('bg-canvas')");
|
|
1063
|
+
});
|
|
1064
|
+
|
|
1065
|
+
it('handles regex with single backtick', () => {
|
|
1066
|
+
const input = "x.replace(/\x60/g, \"'\");\nvar y = 1;";
|
|
1067
|
+
const result = minifyTemplateLiterals(input);
|
|
1068
|
+
expect(result).toContain('var y = 1');
|
|
1069
|
+
});
|
|
1070
|
+
|
|
1071
|
+
it('handles regex backtick in character class', () => {
|
|
1072
|
+
const input = "x.match(/[\x60'\"]/g);\nvar z = 2;";
|
|
1073
|
+
const result = minifyTemplateLiterals(input);
|
|
1074
|
+
expect(result).toContain('var z = 2');
|
|
1075
|
+
});
|
|
1076
|
+
|
|
1077
|
+
it('does not confuse division operator with regex', () => {
|
|
1078
|
+
// After a number or identifier, / is division, not regex start
|
|
1079
|
+
const input = "var x = a / b;\nvar t = \x60hello\x60;";
|
|
1080
|
+
const result = minifyTemplateLiterals(input);
|
|
1081
|
+
expect(result).toContain('a / b');
|
|
1082
|
+
expect(result).toContain('\x60hello\x60');
|
|
1083
|
+
});
|
|
1084
|
+
|
|
1085
|
+
it('still minifies real template literals correctly', () => {
|
|
1086
|
+
const input = "var html = \x60<div> <span> text </span> </div>\x60;";
|
|
1087
|
+
const result = minifyTemplateLiterals(input);
|
|
1088
|
+
// Template whitespace should be collapsed
|
|
1089
|
+
expect(result).not.toContain(' <span> ');
|
|
1090
|
+
});
|
|
1091
|
+
|
|
1092
|
+
it('handles regex after return keyword', () => {
|
|
1093
|
+
const input = "return /\x60test\x60/g;\nvar after = 1;";
|
|
1094
|
+
const result = minifyTemplateLiterals(input);
|
|
1095
|
+
expect(result).toContain('var after = 1');
|
|
1096
|
+
});
|
|
1097
|
+
|
|
1098
|
+
it('handles regex after assignment operator', () => {
|
|
1099
|
+
const input = "var re = /\x60([^\x60]+)\x60/gi;\nvar next = true;";
|
|
1100
|
+
const result = minifyTemplateLiterals(input);
|
|
1101
|
+
expect(result).toContain('var next = true');
|
|
1102
|
+
});
|
|
1103
|
+
});
|