zero-query 0.9.8 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +55 -31
- package/cli/args.js +1 -1
- package/cli/commands/build.js +2 -2
- package/cli/commands/bundle.js +15 -15
- package/cli/commands/create.js +41 -7
- package/cli/commands/dev/devtools/index.js +1 -1
- package/cli/commands/dev/devtools/js/core.js +14 -14
- package/cli/commands/dev/devtools/js/elements.js +4 -4
- package/cli/commands/dev/devtools/js/stats.js +1 -1
- package/cli/commands/dev/devtools/styles.css +2 -2
- package/cli/commands/dev/index.js +2 -2
- package/cli/commands/dev/logger.js +1 -1
- package/cli/commands/dev/overlay.js +21 -14
- package/cli/commands/dev/server.js +5 -5
- package/cli/commands/dev/validator.js +7 -7
- package/cli/commands/dev/watcher.js +6 -6
- package/cli/help.js +4 -2
- package/cli/index.js +2 -2
- package/cli/scaffold/default/app/app.js +17 -18
- package/cli/scaffold/default/app/components/about.js +9 -9
- package/cli/scaffold/default/app/components/api-demo.js +6 -6
- package/cli/scaffold/default/app/components/contact-card.js +4 -4
- package/cli/scaffold/default/app/components/contacts/contacts.css +2 -2
- package/cli/scaffold/default/app/components/contacts/contacts.html +3 -3
- package/cli/scaffold/default/app/components/contacts/contacts.js +11 -11
- package/cli/scaffold/default/app/components/counter.js +8 -8
- package/cli/scaffold/default/app/components/home.js +13 -13
- package/cli/scaffold/default/app/components/not-found.js +1 -1
- package/cli/scaffold/default/app/components/playground/playground.css +1 -1
- package/cli/scaffold/default/app/components/playground/playground.html +11 -11
- package/cli/scaffold/default/app/components/playground/playground.js +11 -11
- package/cli/scaffold/default/app/components/todos.js +8 -8
- package/cli/scaffold/default/app/components/toolkit/toolkit.css +1 -1
- package/cli/scaffold/default/app/components/toolkit/toolkit.html +4 -4
- package/cli/scaffold/default/app/components/toolkit/toolkit.js +7 -7
- package/cli/scaffold/default/app/routes.js +1 -1
- package/cli/scaffold/default/app/store.js +1 -1
- package/cli/scaffold/default/global.css +2 -2
- package/cli/scaffold/default/index.html +2 -2
- package/cli/scaffold/minimal/app/app.js +6 -7
- package/cli/scaffold/minimal/app/components/about.js +5 -5
- package/cli/scaffold/minimal/app/components/counter.js +6 -6
- package/cli/scaffold/minimal/app/components/home.js +8 -8
- package/cli/scaffold/minimal/app/components/not-found.js +1 -1
- package/cli/scaffold/minimal/app/routes.js +1 -1
- package/cli/scaffold/minimal/app/store.js +1 -1
- package/cli/scaffold/minimal/global.css +2 -2
- package/cli/scaffold/minimal/index.html +1 -1
- package/cli/scaffold/ssr/app/app.js +29 -0
- package/cli/scaffold/ssr/app/components/about.js +28 -0
- package/cli/scaffold/ssr/app/components/home.js +37 -0
- package/cli/scaffold/ssr/app/components/not-found.js +15 -0
- package/cli/scaffold/ssr/app/routes.js +6 -0
- package/cli/scaffold/ssr/global.css +113 -0
- package/cli/scaffold/ssr/index.html +31 -0
- package/cli/scaffold/ssr/package.json +8 -0
- package/cli/scaffold/ssr/server/index.js +118 -0
- package/cli/utils.js +6 -6
- package/dist/zquery.dist.zip +0 -0
- package/dist/zquery.js +565 -228
- package/dist/zquery.min.js +2 -2
- package/index.d.ts +25 -12
- package/index.js +11 -7
- package/package.json +9 -3
- package/src/component.js +64 -63
- package/src/core.js +15 -15
- package/src/diff.js +38 -38
- package/src/errors.js +72 -18
- package/src/expression.js +15 -17
- package/src/http.js +4 -4
- package/src/package.json +1 -0
- package/src/reactive.js +75 -9
- package/src/router.js +104 -24
- package/src/ssr.js +133 -39
- package/src/store.js +103 -21
- package/src/utils.js +64 -12
- package/tests/audit.test.js +143 -15
- package/tests/cli.test.js +20 -20
- package/tests/component.test.js +121 -121
- package/tests/core.test.js +56 -56
- package/tests/diff.test.js +42 -42
- package/tests/errors.test.js +425 -147
- package/tests/expression.test.js +58 -53
- package/tests/http.test.js +20 -20
- package/tests/reactive.test.js +185 -24
- package/tests/router.test.js +501 -74
- package/tests/ssr.test.js +444 -10
- package/tests/store.test.js +264 -23
- package/tests/utils.test.js +163 -26
- package/types/collection.d.ts +2 -2
- package/types/component.d.ts +5 -5
- package/types/errors.d.ts +36 -4
- package/types/http.d.ts +3 -3
- package/types/misc.d.ts +9 -9
- package/types/reactive.d.ts +25 -3
- package/types/router.d.ts +10 -6
- package/types/ssr.d.ts +22 -2
- package/types/store.d.ts +40 -5
- package/types/utils.d.ts +1 -1
package/tests/audit.test.js
CHANGED
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
escapeHtml, html, trust, TrustedHTML, uuid, camelCase, kebabCase,
|
|
13
13
|
deepClone, deepMerge, isEqual, param, parseQuery,
|
|
14
14
|
storage, session, EventBus, bus,
|
|
15
|
+
setPath,
|
|
15
16
|
} from '../src/utils.js';
|
|
16
17
|
import { createRouter, getRouter } from '../src/router.js';
|
|
17
18
|
import { component, mount, mountAll, destroy, prefetch, getInstance } from '../src/component.js';
|
|
@@ -2861,7 +2862,7 @@ describe('Store', () => {
|
|
|
2861
2862
|
actions: { inc(state) { state.count++; } }
|
|
2862
2863
|
});
|
|
2863
2864
|
const received = [];
|
|
2864
|
-
store.subscribe('count', (val, old) => received.push({ val, old }));
|
|
2865
|
+
store.subscribe('count', (key, val, old) => received.push({ val, old }));
|
|
2865
2866
|
store.dispatch('inc');
|
|
2866
2867
|
store.dispatch('inc');
|
|
2867
2868
|
expect(received).toEqual([
|
|
@@ -2876,7 +2877,7 @@ describe('Store', () => {
|
|
|
2876
2877
|
actions: { bump(state) { state.x++; } }
|
|
2877
2878
|
});
|
|
2878
2879
|
const received = [];
|
|
2879
|
-
const unsub = store.subscribe('x', (val) => received.push(val));
|
|
2880
|
+
const unsub = store.subscribe('x', (key, val) => received.push(val));
|
|
2880
2881
|
store.dispatch('bump');
|
|
2881
2882
|
unsub();
|
|
2882
2883
|
store.dispatch('bump');
|
|
@@ -3062,7 +3063,7 @@ describe('Store', () => {
|
|
|
3062
3063
|
});
|
|
3063
3064
|
const received = [];
|
|
3064
3065
|
store.subscribe('x', () => { throw new Error('sub error'); });
|
|
3065
|
-
store.subscribe('x', (val) => received.push(val));
|
|
3066
|
+
store.subscribe('x', (key, val) => received.push(val));
|
|
3066
3067
|
store.dispatch('bump');
|
|
3067
3068
|
// The second subscriber still gets called because reportError is used (not re-throw)
|
|
3068
3069
|
expect(received).toEqual([1]);
|
|
@@ -3093,7 +3094,7 @@ describe('Store', () => {
|
|
|
3093
3094
|
state: { x: 0 }
|
|
3094
3095
|
});
|
|
3095
3096
|
const received = [];
|
|
3096
|
-
store.subscribe('x', (val) => received.push(val));
|
|
3097
|
+
store.subscribe('x', (key, val) => received.push(val));
|
|
3097
3098
|
store.state.x = 99;
|
|
3098
3099
|
expect(received).toEqual([99]);
|
|
3099
3100
|
});
|
|
@@ -3895,7 +3896,7 @@ describe('TrustedHTML and html template tag', () => {
|
|
|
3895
3896
|
|
|
3896
3897
|
|
|
3897
3898
|
// ===========================================================================
|
|
3898
|
-
// 24. Bug 9
|
|
3899
|
+
// 24. Bug 9 - `new` constructor globals reachable
|
|
3899
3900
|
// ===========================================================================
|
|
3900
3901
|
describe('new constructor globals (Bug 9)', () => {
|
|
3901
3902
|
const eval_ = (expr, ctx = {}) => safeEval(expr, [ctx]);
|
|
@@ -3912,10 +3913,9 @@ describe('new constructor globals (Bug 9)', () => {
|
|
|
3912
3913
|
expect(result.has(2)).toBe(true);
|
|
3913
3914
|
});
|
|
3914
3915
|
|
|
3915
|
-
it('new RegExp
|
|
3916
|
+
it('new RegExp is blocked (ReDoS prevention)', () => {
|
|
3916
3917
|
const result = eval_('new RegExp(pat, flags)', { pat: '^hello', flags: 'i' });
|
|
3917
|
-
expect(result).
|
|
3918
|
-
expect(result.test('Hello world')).toBe(true);
|
|
3918
|
+
expect(result).toBeUndefined();
|
|
3919
3919
|
});
|
|
3920
3920
|
|
|
3921
3921
|
it('new URL creates a URL', () => {
|
|
@@ -3931,10 +3931,9 @@ describe('new constructor globals (Bug 9)', () => {
|
|
|
3931
3931
|
expect(result.get('b')).toBe('2');
|
|
3932
3932
|
});
|
|
3933
3933
|
|
|
3934
|
-
it('new Error
|
|
3934
|
+
it('new Error is blocked (info disclosure prevention)', () => {
|
|
3935
3935
|
const result = eval_('new Error(msg)', { msg: 'test error' });
|
|
3936
|
-
expect(result).
|
|
3937
|
-
expect(result.message).toBe('test error');
|
|
3936
|
+
expect(result).toBeUndefined();
|
|
3938
3937
|
});
|
|
3939
3938
|
|
|
3940
3939
|
it('Map and Set are accessible as identifiers for instanceof', () => {
|
|
@@ -3945,7 +3944,7 @@ describe('new constructor globals (Bug 9)', () => {
|
|
|
3945
3944
|
|
|
3946
3945
|
|
|
3947
3946
|
// ===========================================================================
|
|
3948
|
-
// 25. Bug 10
|
|
3947
|
+
// 25. Bug 10 - optional_call preserves `this` binding
|
|
3949
3948
|
// ===========================================================================
|
|
3950
3949
|
describe('optional_call this binding (Bug 10)', () => {
|
|
3951
3950
|
const eval_ = (expr, ctx = {}) => safeEval(expr, [ctx]);
|
|
@@ -3974,7 +3973,7 @@ describe('optional_call this binding (Bug 10)', () => {
|
|
|
3974
3973
|
|
|
3975
3974
|
|
|
3976
3975
|
// ===========================================================================
|
|
3977
|
-
// 26. Bug 11
|
|
3976
|
+
// 26. Bug 11 - HTTP abort vs timeout distinction
|
|
3978
3977
|
// ===========================================================================
|
|
3979
3978
|
describe('HTTP abort vs timeout message (Bug 11)', () => {
|
|
3980
3979
|
it('user abort says "aborted" not "timeout"', async () => {
|
|
@@ -4000,7 +3999,7 @@ describe('HTTP abort vs timeout message (Bug 11)', () => {
|
|
|
4000
3999
|
|
|
4001
4000
|
|
|
4002
4001
|
// ===========================================================================
|
|
4003
|
-
// 27. Bug 12
|
|
4002
|
+
// 27. Bug 12 - isEqual circular reference protection
|
|
4004
4003
|
// ===========================================================================
|
|
4005
4004
|
describe('isEqual circular reference protection (Bug 12)', () => {
|
|
4006
4005
|
it('does not stack overflow on circular objects', () => {
|
|
@@ -4008,7 +4007,7 @@ describe('isEqual circular reference protection (Bug 12)', () => {
|
|
|
4008
4007
|
a.self = a;
|
|
4009
4008
|
const b = { x: 1 };
|
|
4010
4009
|
b.self = b;
|
|
4011
|
-
// Should not throw
|
|
4010
|
+
// Should not throw - just return true (both are circular in the same shape)
|
|
4012
4011
|
expect(() => isEqual(a, b)).not.toThrow();
|
|
4013
4012
|
expect(isEqual(a, b)).toBe(true);
|
|
4014
4013
|
});
|
|
@@ -4028,3 +4027,132 @@ describe('isEqual circular reference protection (Bug 12)', () => {
|
|
|
4028
4027
|
expect(isEqual([1, 2], [1, 3])).toBe(false);
|
|
4029
4028
|
});
|
|
4030
4029
|
});
|
|
4030
|
+
|
|
4031
|
+
|
|
4032
|
+
// ===========================================================================
|
|
4033
|
+
// SECURITY AUDIT v2 - Prototype Pollution, ReDoS, Expression Safety
|
|
4034
|
+
// ===========================================================================
|
|
4035
|
+
|
|
4036
|
+
describe('Security: deepMerge prototype pollution prevention', () => {
|
|
4037
|
+
it('blocks __proto__ key from being merged', () => {
|
|
4038
|
+
const target = {};
|
|
4039
|
+
const malicious = JSON.parse('{"__proto__": {"polluted": true}}');
|
|
4040
|
+
deepMerge(target, malicious);
|
|
4041
|
+
expect(target.polluted).toBeUndefined();
|
|
4042
|
+
expect(({}).polluted).toBeUndefined();
|
|
4043
|
+
});
|
|
4044
|
+
|
|
4045
|
+
it('blocks constructor key from being merged', () => {
|
|
4046
|
+
const target = {};
|
|
4047
|
+
deepMerge(target, { constructor: { prototype: { polluted: true } } });
|
|
4048
|
+
expect(({}).polluted).toBeUndefined();
|
|
4049
|
+
});
|
|
4050
|
+
|
|
4051
|
+
it('blocks prototype key from being merged', () => {
|
|
4052
|
+
const target = {};
|
|
4053
|
+
deepMerge(target, { prototype: { polluted: true } });
|
|
4054
|
+
expect(target.prototype).toBeUndefined();
|
|
4055
|
+
});
|
|
4056
|
+
|
|
4057
|
+
it('still merges safe keys normally', () => {
|
|
4058
|
+
const result = deepMerge({}, { a: 1, b: { c: 2 } });
|
|
4059
|
+
expect(result).toEqual({ a: 1, b: { c: 2 } });
|
|
4060
|
+
});
|
|
4061
|
+
|
|
4062
|
+
it('blocks nested __proto__ pollution attempt', () => {
|
|
4063
|
+
const target = { nested: {} };
|
|
4064
|
+
const malicious = JSON.parse('{"nested": {"__proto__": {"deep": true}}}');
|
|
4065
|
+
deepMerge(target, malicious);
|
|
4066
|
+
expect(({}).deep).toBeUndefined();
|
|
4067
|
+
expect(target.nested.deep).toBeUndefined();
|
|
4068
|
+
});
|
|
4069
|
+
});
|
|
4070
|
+
|
|
4071
|
+
describe('Security: setPath prototype pollution prevention', () => {
|
|
4072
|
+
it('blocks __proto__ in path segments', () => {
|
|
4073
|
+
const obj = {};
|
|
4074
|
+
setPath(obj, '__proto__.polluted', true);
|
|
4075
|
+
expect(({}).polluted).toBeUndefined();
|
|
4076
|
+
});
|
|
4077
|
+
|
|
4078
|
+
it('blocks constructor in path segments', () => {
|
|
4079
|
+
const obj = {};
|
|
4080
|
+
setPath(obj, 'constructor.prototype.polluted', true);
|
|
4081
|
+
expect(({}).polluted).toBeUndefined();
|
|
4082
|
+
});
|
|
4083
|
+
|
|
4084
|
+
it('blocks prototype as final key', () => {
|
|
4085
|
+
const obj = {};
|
|
4086
|
+
setPath(obj, 'prototype', { evil: true });
|
|
4087
|
+
expect(obj.prototype).toBeUndefined();
|
|
4088
|
+
});
|
|
4089
|
+
|
|
4090
|
+
it('still sets safe paths normally', () => {
|
|
4091
|
+
const obj = {};
|
|
4092
|
+
setPath(obj, 'a.b.c', 42);
|
|
4093
|
+
expect(obj.a.b.c).toBe(42);
|
|
4094
|
+
});
|
|
4095
|
+
});
|
|
4096
|
+
|
|
4097
|
+
describe('Security: expression evaluator - blocked constructors', () => {
|
|
4098
|
+
it('blocks RegExp constructor (ReDoS prevention)', () => {
|
|
4099
|
+
expect(eval_('new RegExp(".*")')).toBeUndefined();
|
|
4100
|
+
expect(eval_('RegExp')).toBeUndefined();
|
|
4101
|
+
});
|
|
4102
|
+
|
|
4103
|
+
it('blocks Error constructor (info leak prevention)', () => {
|
|
4104
|
+
expect(eval_('new Error("test")')).toBeUndefined();
|
|
4105
|
+
});
|
|
4106
|
+
|
|
4107
|
+
it('blocks Function constructor', () => {
|
|
4108
|
+
expect(eval_('new Function("return 1")')).toBeUndefined();
|
|
4109
|
+
});
|
|
4110
|
+
|
|
4111
|
+
it('still allows safe constructors', () => {
|
|
4112
|
+
expect(eval_('new Date(2024, 0, 1)')).toBeInstanceOf(Date);
|
|
4113
|
+
expect(eval_('new Map')).toBeInstanceOf(Map);
|
|
4114
|
+
expect(eval_('new Set')).toBeInstanceOf(Set);
|
|
4115
|
+
expect(eval_('new Array(3)')).toBeInstanceOf(Array);
|
|
4116
|
+
expect(eval_('new URL("https://example.com")')).toBeInstanceOf(URL);
|
|
4117
|
+
});
|
|
4118
|
+
});
|
|
4119
|
+
|
|
4120
|
+
describe('Security: expression evaluator - blocked property access', () => {
|
|
4121
|
+
it('blocks __proto__ access', () => {
|
|
4122
|
+
expect(eval_('obj.__proto__', { obj: {} })).toBeUndefined();
|
|
4123
|
+
});
|
|
4124
|
+
|
|
4125
|
+
it('blocks constructor access', () => {
|
|
4126
|
+
expect(eval_('obj.constructor', { obj: {} })).toBeUndefined();
|
|
4127
|
+
});
|
|
4128
|
+
|
|
4129
|
+
it('blocks prototype access', () => {
|
|
4130
|
+
expect(eval_('obj.prototype', { obj: function(){} })).toBeUndefined();
|
|
4131
|
+
});
|
|
4132
|
+
|
|
4133
|
+
it('blocks __defineGetter__ access', () => {
|
|
4134
|
+
expect(eval_('obj.__defineGetter__', { obj: {} })).toBeUndefined();
|
|
4135
|
+
});
|
|
4136
|
+
|
|
4137
|
+
it('blocks call/apply/bind', () => {
|
|
4138
|
+
expect(eval_('fn.call', { fn: () => {} })).toBeUndefined();
|
|
4139
|
+
expect(eval_('fn.apply', { fn: () => {} })).toBeUndefined();
|
|
4140
|
+
expect(eval_('fn.bind', { fn: () => {} })).toBeUndefined();
|
|
4141
|
+
});
|
|
4142
|
+
});
|
|
4143
|
+
|
|
4144
|
+
describe('Security: template expression HTML escaping', () => {
|
|
4145
|
+
it('escapeHtml escapes script tags', () => {
|
|
4146
|
+
expect(escapeHtml('<script>alert(1)</script>')).toBe('<script>alert(1)</script>');
|
|
4147
|
+
});
|
|
4148
|
+
|
|
4149
|
+
it('escapeHtml escapes quotes and ampersands', () => {
|
|
4150
|
+
expect(escapeHtml('"&\'')).toBe('"&'');
|
|
4151
|
+
});
|
|
4152
|
+
|
|
4153
|
+
it('escapeHtml handles non-string input', () => {
|
|
4154
|
+
expect(escapeHtml(42)).toBe('42');
|
|
4155
|
+
expect(escapeHtml(null)).toBe('null');
|
|
4156
|
+
expect(escapeHtml(undefined)).toBe('undefined');
|
|
4157
|
+
});
|
|
4158
|
+
});
|
package/tests/cli.test.js
CHANGED
|
@@ -2,10 +2,10 @@ import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
// ---------------------------------------------------------------------------
|
|
5
|
-
// CLI utils
|
|
5
|
+
// CLI utils - stripComments
|
|
6
6
|
// ---------------------------------------------------------------------------
|
|
7
7
|
|
|
8
|
-
describe('CLI
|
|
8
|
+
describe('CLI - stripComments', () => {
|
|
9
9
|
let stripComments;
|
|
10
10
|
|
|
11
11
|
beforeEach(async () => {
|
|
@@ -88,10 +88,10 @@ describe('CLI — stripComments', () => {
|
|
|
88
88
|
|
|
89
89
|
|
|
90
90
|
// ---------------------------------------------------------------------------
|
|
91
|
-
// CLI utils
|
|
91
|
+
// CLI utils - minify
|
|
92
92
|
// ---------------------------------------------------------------------------
|
|
93
93
|
|
|
94
|
-
describe('CLI
|
|
94
|
+
describe('CLI - minify', () => {
|
|
95
95
|
let minify;
|
|
96
96
|
|
|
97
97
|
beforeEach(async () => {
|
|
@@ -152,10 +152,10 @@ describe('CLI — minify', () => {
|
|
|
152
152
|
|
|
153
153
|
|
|
154
154
|
// ---------------------------------------------------------------------------
|
|
155
|
-
// CLI utils
|
|
155
|
+
// CLI utils - sizeKB
|
|
156
156
|
// ---------------------------------------------------------------------------
|
|
157
157
|
|
|
158
|
-
describe('CLI
|
|
158
|
+
describe('CLI - sizeKB', () => {
|
|
159
159
|
let sizeKB;
|
|
160
160
|
|
|
161
161
|
beforeEach(async () => {
|
|
@@ -186,10 +186,10 @@ describe('CLI — sizeKB', () => {
|
|
|
186
186
|
|
|
187
187
|
|
|
188
188
|
// ---------------------------------------------------------------------------
|
|
189
|
-
// CLI args
|
|
189
|
+
// CLI args - flag and option
|
|
190
190
|
// ---------------------------------------------------------------------------
|
|
191
191
|
|
|
192
|
-
describe('CLI
|
|
192
|
+
describe('CLI - args module', () => {
|
|
193
193
|
let originalArgv;
|
|
194
194
|
|
|
195
195
|
beforeEach(() => {
|
|
@@ -257,7 +257,7 @@ describe('CLI — args module', () => {
|
|
|
257
257
|
// showHelp
|
|
258
258
|
// ===========================================================================
|
|
259
259
|
|
|
260
|
-
describe('CLI
|
|
260
|
+
describe('CLI - showHelp', () => {
|
|
261
261
|
it('outputs help text to console', async () => {
|
|
262
262
|
const spy = vi.spyOn(console, 'log').mockImplementation(() => {});
|
|
263
263
|
const showHelp = (await import('../cli/help.js')).default;
|
|
@@ -283,10 +283,10 @@ describe('CLI — showHelp', () => {
|
|
|
283
283
|
|
|
284
284
|
|
|
285
285
|
// ===========================================================================
|
|
286
|
-
// stripComments
|
|
286
|
+
// stripComments - additional edge cases
|
|
287
287
|
// ===========================================================================
|
|
288
288
|
|
|
289
|
-
describe('CLI
|
|
289
|
+
describe('CLI - stripComments extra', () => {
|
|
290
290
|
let stripComments;
|
|
291
291
|
beforeEach(async () => {
|
|
292
292
|
const mod = await import('../cli/utils.js');
|
|
@@ -331,10 +331,10 @@ describe('CLI — stripComments extra', () => {
|
|
|
331
331
|
|
|
332
332
|
|
|
333
333
|
// ===========================================================================
|
|
334
|
-
// minify
|
|
334
|
+
// minify - additional edge cases
|
|
335
335
|
// ===========================================================================
|
|
336
336
|
|
|
337
|
-
describe('CLI
|
|
337
|
+
describe('CLI - minify extra', () => {
|
|
338
338
|
let minify;
|
|
339
339
|
beforeEach(async () => {
|
|
340
340
|
const mod = await import('../cli/utils.js');
|
|
@@ -365,10 +365,10 @@ describe('CLI — minify extra', () => {
|
|
|
365
365
|
|
|
366
366
|
|
|
367
367
|
// ===========================================================================
|
|
368
|
-
// sizeKB
|
|
368
|
+
// sizeKB - edge cases
|
|
369
369
|
// ===========================================================================
|
|
370
370
|
|
|
371
|
-
describe('CLI
|
|
371
|
+
describe('CLI - sizeKB extra', () => {
|
|
372
372
|
let sizeKB;
|
|
373
373
|
beforeEach(async () => {
|
|
374
374
|
const mod = await import('../cli/utils.js');
|
|
@@ -393,7 +393,7 @@ describe('CLI — sizeKB extra', () => {
|
|
|
393
393
|
// copyDirSync
|
|
394
394
|
// ===========================================================================
|
|
395
395
|
|
|
396
|
-
describe('CLI
|
|
396
|
+
describe('CLI - copyDirSync', () => {
|
|
397
397
|
let copyDirSync;
|
|
398
398
|
const fs = require('fs');
|
|
399
399
|
const path = require('path');
|
|
@@ -428,10 +428,10 @@ describe('CLI — copyDirSync', () => {
|
|
|
428
428
|
|
|
429
429
|
|
|
430
430
|
// ===========================================================================
|
|
431
|
-
// flag/option
|
|
431
|
+
// flag/option - additional cases
|
|
432
432
|
// ===========================================================================
|
|
433
433
|
|
|
434
|
-
describe('CLI
|
|
434
|
+
describe('CLI - flag/option extra', () => {
|
|
435
435
|
it('flag returns false when absent', async () => {
|
|
436
436
|
process.argv = ['node', 'script'];
|
|
437
437
|
vi.resetModules();
|
|
@@ -457,10 +457,10 @@ describe('CLI — flag/option extra', () => {
|
|
|
457
457
|
|
|
458
458
|
|
|
459
459
|
// ===========================================================================
|
|
460
|
-
// createProject
|
|
460
|
+
// createProject - scaffold command
|
|
461
461
|
// ===========================================================================
|
|
462
462
|
|
|
463
|
-
describe('CLI
|
|
463
|
+
describe('CLI - createProject', () => {
|
|
464
464
|
const fs = require('fs');
|
|
465
465
|
const path = require('path');
|
|
466
466
|
const os = require('os');
|