ivue 1.6.1 → 2.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 +171 -33
- package/bin/ivue.mjs +152 -0
- package/dist/Reactive.d.ts +131 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.es.js +88 -206
- package/dist/index.umd.js +1 -1
- package/lib/Reactive.ts +285 -114
- package/lib/__tests__/Reactive.vitest.spec.ts +1056 -0
- package/lib/__tests__/ReactiveAdversarial.vitest.spec.ts +182 -0
- package/lib/__tests__/coverage-completion.vitest.spec.ts +24 -0
- package/lib/__tests__/ivue.vitest.spec.ts +76 -19
- package/lib/index.ts +1 -2
- package/package.json +39 -10
- package/skills/ivue/SKILL.md +726 -0
- package/dist/ivue.d.ts +0 -310
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { reactive, ref } from 'vue';
|
|
2
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
3
|
+
import { Reactive } from '../Reactive';
|
|
4
|
+
import { Kernel } from '../kernel';
|
|
5
|
+
|
|
6
|
+
describe('Reactive adversarial boundaries', () => {
|
|
7
|
+
it('richer cleanup composes as an ordinary method calling $stopEffects', () => {
|
|
8
|
+
const observed: number[] = [];
|
|
9
|
+
let closed = 0;
|
|
10
|
+
|
|
11
|
+
class $Store {
|
|
12
|
+
get count() {
|
|
13
|
+
return ref(0);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// the composition pattern: no reserved names, no auto-calls —
|
|
17
|
+
// the class's own dispose() does its work, then resets the engine
|
|
18
|
+
dispose() {
|
|
19
|
+
this.closeSocket();
|
|
20
|
+
(this as any).$stopEffects();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
closeSocket() {
|
|
24
|
+
closed++;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const Store = Reactive($Store);
|
|
29
|
+
const store: any = new Store();
|
|
30
|
+
const originalCount = store.count;
|
|
31
|
+
store.$watch(
|
|
32
|
+
() => store.count.value,
|
|
33
|
+
(count: number) => observed.push(count),
|
|
34
|
+
{ flush: 'sync' },
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
originalCount.value = 1;
|
|
38
|
+
expect(observed).toEqual([1]);
|
|
39
|
+
|
|
40
|
+
store.dispose();
|
|
41
|
+
|
|
42
|
+
expect(closed).toBe(1);
|
|
43
|
+
originalCount.value = 2;
|
|
44
|
+
expect(observed).toEqual([1]); // watcher dead
|
|
45
|
+
expect(store.count).not.toBe(originalCount); // cells reset
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('teardown clears only engine cache keys — consumer symbols survive', () => {
|
|
49
|
+
const consumerSymbol = Symbol('consumer-metadata');
|
|
50
|
+
|
|
51
|
+
class $Parent {
|
|
52
|
+
get inherited() {
|
|
53
|
+
return ref('parent');
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
class $Child extends $Parent {
|
|
58
|
+
get own() {
|
|
59
|
+
return ref('child');
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
grow() {
|
|
63
|
+
return this.own.value;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const Child = Reactive($Child);
|
|
68
|
+
const child: any = new Child();
|
|
69
|
+
|
|
70
|
+
// materialize cells on BOTH prototype layers + a bound method
|
|
71
|
+
const inheritedCell = child.inherited;
|
|
72
|
+
const ownCell = child.own;
|
|
73
|
+
const boundGrow = child.grow;
|
|
74
|
+
// a symbol the engine did NOT create — foreign metadata on the instance
|
|
75
|
+
child[consumerSymbol] = 'must survive';
|
|
76
|
+
|
|
77
|
+
child.$stopEffects();
|
|
78
|
+
|
|
79
|
+
// engine cells across the whole chain are gone: fresh identities
|
|
80
|
+
expect(child.inherited).not.toBe(inheritedCell);
|
|
81
|
+
expect(child.own).not.toBe(ownCell);
|
|
82
|
+
expect(child.grow).not.toBe(boundGrow);
|
|
83
|
+
// the consumer's symbol is untouched
|
|
84
|
+
expect(child[consumerSymbol]).toBe('must survive');
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('can allocate a fresh watcher scope after teardown', () => {
|
|
88
|
+
class $Store {
|
|
89
|
+
get count() {
|
|
90
|
+
return ref(0);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const Store = Reactive($Store);
|
|
95
|
+
const store: any = new Store();
|
|
96
|
+
const firstObserved = vi.fn();
|
|
97
|
+
store.$watch(() => store.count.value, firstObserved, { flush: 'sync' });
|
|
98
|
+
store.count.value = 1;
|
|
99
|
+
store.$stopEffects();
|
|
100
|
+
|
|
101
|
+
const secondObserved = vi.fn();
|
|
102
|
+
store.$watch(() => store.count.value, secondObserved, { flush: 'sync' });
|
|
103
|
+
store.count.value = 2;
|
|
104
|
+
|
|
105
|
+
expect(firstObserved).toHaveBeenCalledTimes(1);
|
|
106
|
+
expect(secondObserved).toHaveBeenCalledTimes(1);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it('does not poison a lazy ref cache when its factory throws once', () => {
|
|
110
|
+
let attempts = 0;
|
|
111
|
+
|
|
112
|
+
class $Store {
|
|
113
|
+
get state() {
|
|
114
|
+
attempts++;
|
|
115
|
+
if (attempts === 1) throw new Error('dependency is not ready');
|
|
116
|
+
return ref(7);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const Store = Reactive($Store);
|
|
121
|
+
const store = new Store();
|
|
122
|
+
|
|
123
|
+
expect(() => store.state).toThrow('dependency is not ready');
|
|
124
|
+
const recovered = store.state;
|
|
125
|
+
expect(recovered.value).toBe(7);
|
|
126
|
+
expect(store.state).toBe(recovered);
|
|
127
|
+
expect(attempts).toBe(2);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it('caches an undefined $-singleton result instead of rerunning it', () => {
|
|
131
|
+
const factory = vi.fn(() => undefined);
|
|
132
|
+
|
|
133
|
+
class $Store {
|
|
134
|
+
get $optionalService() {
|
|
135
|
+
return factory();
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const Store = Reactive($Store);
|
|
140
|
+
const store = new Store();
|
|
141
|
+
|
|
142
|
+
expect(store.$optionalService).toBeUndefined();
|
|
143
|
+
expect(store.$optionalService).toBeUndefined();
|
|
144
|
+
expect(factory).toHaveBeenCalledTimes(1);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it('tears down the raw instance when invoked through a Vue proxy', () => {
|
|
148
|
+
const observed = vi.fn();
|
|
149
|
+
|
|
150
|
+
class $Store {
|
|
151
|
+
get count() {
|
|
152
|
+
return ref(0);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const Store = Reactive($Store);
|
|
157
|
+
const rawStore: any = new Store();
|
|
158
|
+
const proxiedStore: any = reactive(rawStore);
|
|
159
|
+
const originalCount = rawStore.count;
|
|
160
|
+
proxiedStore.$watch(() => rawStore.count.value, observed, { flush: 'sync' });
|
|
161
|
+
|
|
162
|
+
originalCount.value = 1;
|
|
163
|
+
proxiedStore.$stopEffects();
|
|
164
|
+
originalCount.value = 2;
|
|
165
|
+
|
|
166
|
+
expect(observed).toHaveBeenCalledTimes(1);
|
|
167
|
+
expect(rawStore.count).not.toBe(originalCount);
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
describe('Kernel adversarial values', () => {
|
|
172
|
+
it('preserves stored falsy values instead of taking the fallback', () => {
|
|
173
|
+
const kernel = new Kernel();
|
|
174
|
+
kernel.set('zero', 0);
|
|
175
|
+
kernel.set('false', false);
|
|
176
|
+
kernel.set('empty', '');
|
|
177
|
+
|
|
178
|
+
expect(kernel.get('zero', 1)).toBe(0);
|
|
179
|
+
expect(kernel.get('false', true)).toBe(false);
|
|
180
|
+
expect(kernel.get('empty', 'fallback')).toBe('');
|
|
181
|
+
});
|
|
182
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Coverage completion for the package entry and Kernel container.
|
|
3
|
+
*/
|
|
4
|
+
import { describe, expect, it } from 'vitest';
|
|
5
|
+
import * as packageEntry from '../index';
|
|
6
|
+
import { Kernel, kernel } from '../kernel';
|
|
7
|
+
|
|
8
|
+
describe('package entry (index.ts)', () => {
|
|
9
|
+
it('re-exports the engine surface', () => {
|
|
10
|
+
expect(typeof packageEntry.Reactive).toBe('function');
|
|
11
|
+
});
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
describe('Kernel', () => {
|
|
15
|
+
it('sets, gets, falls back, clears', () => {
|
|
16
|
+
const container = new Kernel();
|
|
17
|
+
container.set('answer', 42);
|
|
18
|
+
expect(container.get('answer', 0)).toBe(42);
|
|
19
|
+
expect(container.get('missing', 'fallback')).toBe('fallback');
|
|
20
|
+
container.clear();
|
|
21
|
+
expect(container.get('answer', 0)).toBe(0);
|
|
22
|
+
expect(kernel).toBeInstanceOf(Kernel);
|
|
23
|
+
});
|
|
24
|
+
});
|
|
@@ -955,36 +955,36 @@ describe('ivue', () => {
|
|
|
955
955
|
});
|
|
956
956
|
|
|
957
957
|
it('mirrors default flags for class accessors: enumerable=false, configurable=true', () => {
|
|
958
|
-
const
|
|
959
|
-
const d = Object.getOwnPropertyDescriptor(
|
|
958
|
+
const instance = ivue(Flags);
|
|
959
|
+
const d = Object.getOwnPropertyDescriptor(instance, 'hidden');
|
|
960
960
|
|
|
961
961
|
expect(d?.enumerable).toBe(false);
|
|
962
962
|
expect(d?.configurable).toBe(true);
|
|
963
|
-
expect(isEnumerable(
|
|
963
|
+
expect(isEnumerable(instance, 'hidden')).toBe(false);
|
|
964
964
|
});
|
|
965
965
|
|
|
966
966
|
it('preserves enumerable=true from prototype on the reactive instance', () => {
|
|
967
|
-
const
|
|
968
|
-
const d = Object.getOwnPropertyDescriptor(
|
|
967
|
+
const instance = ivue(Flags);
|
|
968
|
+
const d = Object.getOwnPropertyDescriptor(instance, 'visible');
|
|
969
969
|
|
|
970
970
|
expect(d?.enumerable).toBe(true);
|
|
971
|
-
expect(isEnumerable(
|
|
971
|
+
expect(isEnumerable(instance, 'visible')).toBe(true);
|
|
972
972
|
|
|
973
973
|
// sanity check: hidden is not in keys; visible is
|
|
974
|
-
const keys = Object.keys(
|
|
974
|
+
const keys = Object.keys(instance);
|
|
975
975
|
expect(keys.includes('visible')).toBe(true);
|
|
976
976
|
expect(keys.includes('hidden')).toBe(false);
|
|
977
977
|
});
|
|
978
978
|
|
|
979
979
|
it('preserves configurable=false from prototype (cannot redefine)', () => {
|
|
980
|
-
const
|
|
981
|
-
const d = Object.getOwnPropertyDescriptor(
|
|
980
|
+
const instance = ivue(Flags);
|
|
981
|
+
const d = Object.getOwnPropertyDescriptor(instance, 'locked');
|
|
982
982
|
|
|
983
983
|
expect(d?.configurable).toBe(false);
|
|
984
984
|
|
|
985
985
|
// Attempting to redefine should throw a TypeError
|
|
986
986
|
expect(() =>
|
|
987
|
-
Object.defineProperty(
|
|
987
|
+
Object.defineProperty(instance, 'locked', {
|
|
988
988
|
get() {
|
|
989
989
|
return 99;
|
|
990
990
|
},
|
|
@@ -993,14 +993,14 @@ describe('ivue', () => {
|
|
|
993
993
|
});
|
|
994
994
|
|
|
995
995
|
it('configurable=true allows redefining accessor on the reactive instance', () => {
|
|
996
|
-
const
|
|
996
|
+
const instance = ivue(Flags);
|
|
997
997
|
|
|
998
998
|
// Before redefine
|
|
999
999
|
// @ts-expect-error anyway
|
|
1000
|
-
expect(
|
|
1000
|
+
expect(instance.visible).toBe(2);
|
|
1001
1001
|
|
|
1002
1002
|
// Redefine should succeed (configurable=true)
|
|
1003
|
-
Object.defineProperty(
|
|
1003
|
+
Object.defineProperty(instance, 'visible', {
|
|
1004
1004
|
get() {
|
|
1005
1005
|
return 42;
|
|
1006
1006
|
},
|
|
@@ -1009,10 +1009,10 @@ describe('ivue', () => {
|
|
|
1009
1009
|
});
|
|
1010
1010
|
|
|
1011
1011
|
// @ts-expect-error anyway
|
|
1012
|
-
expect(
|
|
1012
|
+
expect(instance.visible).toBe(42);
|
|
1013
1013
|
|
|
1014
1014
|
// And flags remain as set on redefinition
|
|
1015
|
-
const d = Object.getOwnPropertyDescriptor(
|
|
1015
|
+
const d = Object.getOwnPropertyDescriptor(instance, 'visible');
|
|
1016
1016
|
expect(d?.enumerable).toBe(true);
|
|
1017
1017
|
expect(d?.configurable).toBe(true);
|
|
1018
1018
|
});
|
|
@@ -1033,13 +1033,13 @@ describe('ivue', () => {
|
|
|
1033
1033
|
x = iref(7); // normal data
|
|
1034
1034
|
}
|
|
1035
1035
|
|
|
1036
|
-
const
|
|
1036
|
+
const instance = ivue(WithSymbol);
|
|
1037
1037
|
|
|
1038
1038
|
// sanity: Vue proxy still has the symbol (we won’t surface it)
|
|
1039
|
-
expect(
|
|
1039
|
+
expect(instance[S]).toBe(123);
|
|
1040
1040
|
|
|
1041
1041
|
// our property collector should not list symbols
|
|
1042
|
-
const { allProps } = getClassPropertiesAccessorsMap(
|
|
1042
|
+
const { allProps } = getClassPropertiesAccessorsMap(instance);
|
|
1043
1043
|
// only string keys
|
|
1044
1044
|
for (const k of allProps.keys()) {
|
|
1045
1045
|
expect(typeof k).toBe('string');
|
|
@@ -1048,7 +1048,7 @@ describe('ivue', () => {
|
|
|
1048
1048
|
expect(allProps.has('method')).toBe(false);
|
|
1049
1049
|
|
|
1050
1050
|
// toRefs() should not expose symbol-backed fields
|
|
1051
|
-
const r =
|
|
1051
|
+
const r = instance.toRefs();
|
|
1052
1052
|
expect('x' in r).toBe(true);
|
|
1053
1053
|
expect('method' in r).toBe(false);
|
|
1054
1054
|
expect(Object.getOwnPropertySymbols(r).length).toBe(0);
|
|
@@ -1828,3 +1828,60 @@ describe('ivue', () => {
|
|
|
1828
1828
|
});
|
|
1829
1829
|
});
|
|
1830
1830
|
});
|
|
1831
|
+
|
|
1832
|
+
describe('ivue coverage edge cases', () => {
|
|
1833
|
+
it('propsWithDefaults skips a required prop even when a default exists', () => {
|
|
1834
|
+
const typed = {
|
|
1835
|
+
a: { type: String, required: true },
|
|
1836
|
+
b: { type: Number },
|
|
1837
|
+
};
|
|
1838
|
+
const out = propsWithDefaults({ a: 'ignored', b: 2 }, { ...typed }) as Record<
|
|
1839
|
+
string,
|
|
1840
|
+
any
|
|
1841
|
+
>;
|
|
1842
|
+
// required → the `if (typed.required) continue` branch is taken
|
|
1843
|
+
expect('default' in out.a).toBe(false);
|
|
1844
|
+
expect(out.b.default).toBe(2);
|
|
1845
|
+
});
|
|
1846
|
+
|
|
1847
|
+
it('ivueDisableReactivity preserves BOTH getter and setter for an accessor', () => {
|
|
1848
|
+
class WithRW {
|
|
1849
|
+
static ivueDisableReactivity = new Set<keyof WithRW>(['rw']);
|
|
1850
|
+
_v = 1;
|
|
1851
|
+
get rw() {
|
|
1852
|
+
return this._v;
|
|
1853
|
+
}
|
|
1854
|
+
set rw(value: number) {
|
|
1855
|
+
this._v = value;
|
|
1856
|
+
}
|
|
1857
|
+
}
|
|
1858
|
+
|
|
1859
|
+
// ivue() path: descriptor has get AND set → both `?.bind(vue)` branches run
|
|
1860
|
+
const a = ivue(WithRW);
|
|
1861
|
+
expect(a.rw).toBe(1);
|
|
1862
|
+
a.rw = 5;
|
|
1863
|
+
expect(a.rw).toBe(5);
|
|
1864
|
+
|
|
1865
|
+
// clone() path exercises the same branch in ivueClone()
|
|
1866
|
+
const b = a.clone();
|
|
1867
|
+
expect(b.rw).toBe(5);
|
|
1868
|
+
b.rw = 9;
|
|
1869
|
+
expect(b.rw).toBe(9);
|
|
1870
|
+
expect(a.rw).toBe(5); // isolation
|
|
1871
|
+
});
|
|
1872
|
+
|
|
1873
|
+
it('deepClone tolerates a deepCloneArgs entry mapped to undefined (uses [])', () => {
|
|
1874
|
+
class Svc {
|
|
1875
|
+
value = 1;
|
|
1876
|
+
init(_isClone?: boolean, v = 7) {
|
|
1877
|
+
this.value = v;
|
|
1878
|
+
}
|
|
1879
|
+
}
|
|
1880
|
+
const svc = ivue(Svc);
|
|
1881
|
+
// has(Svc) === true but get(Svc) === undefined → the `?? []` fallback runs
|
|
1882
|
+
const deepCloneArgs = new Map<any, any[]>([[Svc, undefined as any]]);
|
|
1883
|
+
const cloned = deepClone(svc, deepCloneArgs);
|
|
1884
|
+
// clone() called with no args → init(true) default → value = 7
|
|
1885
|
+
expect(cloned.value).toBe(7);
|
|
1886
|
+
});
|
|
1887
|
+
});
|
package/lib/index.ts
CHANGED
|
@@ -1,2 +1 @@
|
|
|
1
|
-
export * from './
|
|
2
|
-
// export * from './Reactive';
|
|
1
|
+
export * from './Reactive';
|
package/package.json
CHANGED
|
@@ -1,32 +1,52 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ivue",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "Infinite Vue – Class Based Architecture for Vue 3",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
7
7
|
".": {
|
|
8
|
-
"
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
9
|
"import": "./dist/index.es.js",
|
|
10
|
-
"
|
|
11
|
-
}
|
|
10
|
+
"require": "./dist/index.umd.js"
|
|
11
|
+
},
|
|
12
|
+
"./package.json": "./package.json"
|
|
12
13
|
},
|
|
13
14
|
"main": "./dist/index.umd.js",
|
|
14
15
|
"module": "./dist/index.es.js",
|
|
15
16
|
"types": "./dist/index.d.ts",
|
|
16
17
|
"scripts": {
|
|
17
|
-
"dev": "vite
|
|
18
|
+
"dev": "vite demo --host",
|
|
19
|
+
"dev:demo": "vite demo --host",
|
|
20
|
+
"dev:flyweight": "vite examples/playground --port 5181 --host",
|
|
21
|
+
"build:flyweight": "vite build examples/playground",
|
|
22
|
+
"preview:flyweight": "vite preview examples/playground --port 5181 --host",
|
|
23
|
+
"measure:flyweight": "node examples/playground/src/examples/flyweight-grid/measure.mjs",
|
|
24
|
+
"measure:formula": "node demo/formula/measure.mjs",
|
|
25
|
+
"measure:grid": "node demo/grid/measure.mjs",
|
|
26
|
+
"dev:docs": "npm --prefix docs_v2 run dev -- --port 5174",
|
|
18
27
|
"test": "vitest --coverage.enabled=true --reporter=verbose --ui",
|
|
19
28
|
"coverage": "vitest run --coverage",
|
|
29
|
+
"bench": "vitest bench --run",
|
|
30
|
+
"bench:node-namespace": "vite-node experiments/node-namespace/benchmark.ts",
|
|
20
31
|
"cypress": "cypress run --component",
|
|
21
32
|
"cypress:headed": "cypress run --component --browser chrome --headed --no-exit",
|
|
22
33
|
"build": "tsc --version;tsc --p ./tsconfig.json && vite build",
|
|
23
34
|
"build:demo": "tsc --p ./tsconfig.json && vite build demo",
|
|
24
|
-
"
|
|
35
|
+
"build:docs": "npm run sync:examples && npm --prefix docs_v2 run build",
|
|
36
|
+
"render:og": "node docs_v2/scripts/brand-image-generator.mjs og",
|
|
37
|
+
"render:form-header": "node docs_v2/scripts/brand-image-generator.mjs form-header",
|
|
25
38
|
"preview:demo": "npm run build:demo && vite preview demo --host",
|
|
26
|
-
"
|
|
39
|
+
"preview:docs": "npm --prefix docs_v2 run preview",
|
|
40
|
+
"release": "npm run build && npm publish",
|
|
41
|
+
"sync:skill": "node -e \"const fs=require('fs');fs.mkdirSync('skills/ivue',{recursive:true});fs.copyFileSync('.claude/skills/ivue/SKILL.md','skills/ivue/SKILL.md')\"",
|
|
42
|
+
"prepack": "npm run sync:skill",
|
|
43
|
+
"sync:examples": "node -e \"require('fs').copyFileSync('lib/Reactive.ts','examples/playground/src/ivue.ts')\"",
|
|
44
|
+
"dev:playground": "vite examples/playground --host",
|
|
45
|
+
"build:playground": "vite build examples/playground",
|
|
46
|
+
"preview:playground": "vite preview examples/playground --host"
|
|
27
47
|
},
|
|
28
48
|
"peerDependencies": {
|
|
29
|
-
"vue": "^3.
|
|
49
|
+
"vue": "^3.2.0",
|
|
30
50
|
"vue-demi": "*"
|
|
31
51
|
},
|
|
32
52
|
"peerDependenciesMeta": {
|
|
@@ -37,6 +57,7 @@
|
|
|
37
57
|
"devDependencies": {
|
|
38
58
|
"@cypress/vite-dev-server": "^5.0.2",
|
|
39
59
|
"@cypress/vue": "^5.0.3",
|
|
60
|
+
"@quasar/extras": "^2.0.2",
|
|
40
61
|
"@types/lodash": "^4.17.20",
|
|
41
62
|
"@typescript-eslint/eslint-plugin": "^5.10.0",
|
|
42
63
|
"@typescript-eslint/parser": "^5.10.0",
|
|
@@ -55,9 +76,12 @@
|
|
|
55
76
|
"eslint-plugin-import": "^2.29.1",
|
|
56
77
|
"eslint-plugin-storybook": "^0.6.12",
|
|
57
78
|
"eslint-plugin-vue": "^9.14.1",
|
|
79
|
+
"fast-formula-parser": "^1.0.19",
|
|
58
80
|
"i": "^0.3.7",
|
|
59
81
|
"jsdom": "^21.0.0",
|
|
60
82
|
"npm": "^11.6.2",
|
|
83
|
+
"playwright": "^1.61.1",
|
|
84
|
+
"quasar": "^2.21.3",
|
|
61
85
|
"rollup-plugin-terser": "^7.0.2",
|
|
62
86
|
"typescript": "^5.9.3",
|
|
63
87
|
"vite": "^4.0.4",
|
|
@@ -97,7 +121,12 @@
|
|
|
97
121
|
},
|
|
98
122
|
"files": [
|
|
99
123
|
"lib",
|
|
100
|
-
"dist"
|
|
124
|
+
"dist",
|
|
125
|
+
"bin",
|
|
126
|
+
"skills"
|
|
101
127
|
],
|
|
102
|
-
"license": "MIT"
|
|
128
|
+
"license": "MIT",
|
|
129
|
+
"bin": {
|
|
130
|
+
"ivue": "bin/ivue.mjs"
|
|
131
|
+
}
|
|
103
132
|
}
|