tracked-instance 1.0.0 → 1.0.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.
@@ -0,0 +1,17 @@
1
+ import { ShallowRef, ComputedRef, Ref } from 'vue';
2
+ import { TrackedInstance } from './tracked-instance';
3
+ export interface CollectionItem<Item extends Record<string, any>, Meta = Record<string, any>> {
4
+ instance: TrackedInstance<Item>;
5
+ meta: Meta;
6
+ isRemoved: Ref<boolean>;
7
+ isNew: Ref<boolean>;
8
+ }
9
+ export interface Collection<Item extends Record<string, any>, Meta = Record<string, any>> {
10
+ items: ShallowRef<CollectionItem<Item, Meta>[]>;
11
+ isDirty: ComputedRef<boolean>;
12
+ add: (item: Partial<Item>, afterIndex?: number) => CollectionItem<Item, Meta>;
13
+ remove: (index: number, isHardRemove?: boolean) => void;
14
+ loadData: (items: Item[]) => void;
15
+ reset: () => void;
16
+ }
17
+ export declare const useCollection: <Item extends Record<string, any>, Meta = Record<string, any>>(createItemMeta?: (instance: TrackedInstance<Item>) => Meta) => Collection<Item, Meta>;
@@ -0,0 +1,57 @@
1
+ import { computed, shallowRef, triggerRef, ref } from 'vue';
2
+ import { useTrackedInstance } from './tracked-instance';
3
+ export const useCollection = (createItemMeta = () => ({})) => {
4
+ const items = shallowRef([]);
5
+ const isDirty = computed(() => items.value.some(({ instance, isRemoved, isNew }) => instance.isDirty.value || isNew.value || isRemoved.value));
6
+ const add = (item, index = items.value.length) => {
7
+ const instance = useTrackedInstance(item);
8
+ const newItem = {
9
+ isRemoved: ref(false),
10
+ isNew: ref(true),
11
+ instance,
12
+ meta: createItemMeta(instance)
13
+ };
14
+ items.value.splice(index, 0, newItem);
15
+ triggerRef(items);
16
+ return newItem;
17
+ };
18
+ const remove = (index, isHardRemove = false) => {
19
+ const item = items.value[index];
20
+ if (item.isNew.value || isHardRemove) {
21
+ items.value.splice(index, 1);
22
+ triggerRef(items);
23
+ }
24
+ else {
25
+ items.value[index].isRemoved.value = true;
26
+ }
27
+ };
28
+ const loadData = (loadedItems) => {
29
+ items.value = loadedItems.map((item) => {
30
+ const instance = useTrackedInstance(item);
31
+ return {
32
+ isNew: ref(false),
33
+ isRemoved: ref(false),
34
+ instance,
35
+ meta: createItemMeta(instance)
36
+ };
37
+ });
38
+ triggerRef(items);
39
+ };
40
+ const reset = () => {
41
+ items.value = items.value.filter(({ isNew }) => !isNew.value);
42
+ for (const item of items.value) {
43
+ item.isRemoved.value = false;
44
+ item.instance.reset();
45
+ }
46
+ triggerRef(items);
47
+ };
48
+ return {
49
+ items,
50
+ isDirty,
51
+ add,
52
+ remove,
53
+ loadData,
54
+ reset
55
+ };
56
+ };
57
+ //# sourceMappingURL=collection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collection.js","sourceRoot":"","sources":["../src/collection.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export type { TrackedInstance } from './tracked-instance';
2
+ export type { Collection, CollectionItem } from './collection';
3
+ export { useTrackedInstance } from './tracked-instance';
4
+ export { useCollection } from './collection';
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export { useTrackedInstance } from './tracked-instance';
2
+ export { useCollection } from './collection';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAC,kBAAkB,EAAC,MAAM,oBAAoB,CAAA;AACrD,OAAO,EAAC,aAAa,EAAC,MAAM,cAAc,CAAA"}
@@ -0,0 +1,13 @@
1
+ import { Ref } from 'vue';
2
+ type DeepPartial<T> = T extends object ? {
3
+ [P in keyof T]?: DeepPartial<T[P]>;
4
+ } : T;
5
+ export interface TrackedInstance<Data extends Record<string, any>> {
6
+ data: Ref<Data>;
7
+ isDirty: Ref<boolean>;
8
+ changedData: Ref<DeepPartial<Data>>;
9
+ loadData: (newData: DeepPartial<Data>) => void;
10
+ reset: () => void;
11
+ }
12
+ export declare const useTrackedInstance: <Data extends Record<string, any>>(initialData: Partial<Data>) => TrackedInstance<Data>;
13
+ export {};
@@ -0,0 +1,266 @@
1
+ import { get, has, set, unset } from 'lodash-es';
2
+ import { computed, customRef } from 'vue';
3
+ const isObject = (value) => typeof value === 'object' &&
4
+ value !== null &&
5
+ !Array.isArray(value) &&
6
+ !(value instanceof Date) &&
7
+ !(value instanceof File) &&
8
+ !(value instanceof Map) &&
9
+ !(value instanceof Set);
10
+ const isEmpty = (value) => Object.keys(value).length === 0;
11
+ const iterateObject = function* (source, params = {}) {
12
+ const { goDeepCondition = (_, value) => isObject(value), includeParent = false } = params;
13
+ const iterateObjectDeep = function* (path, obj) {
14
+ for (const [key, value] of Object.entries(obj)) {
15
+ const currentPath = path.concat(key);
16
+ if (goDeepCondition(currentPath, value)) {
17
+ if (includeParent) {
18
+ yield [currentPath, value];
19
+ }
20
+ yield* iterateObjectDeep(currentPath, value);
21
+ }
22
+ else {
23
+ yield [currentPath, value];
24
+ }
25
+ }
26
+ };
27
+ yield* iterateObjectDeep([], source);
28
+ };
29
+ const createNestedRef = (source, handler) => customRef((track, trigger) => {
30
+ // make nested objects and arrays is reactive
31
+ const createProxy = (source, path = []) => {
32
+ const currentProxyHandler = handler(path);
33
+ return new Proxy(source, {
34
+ ...currentProxyHandler,
35
+ get(target, property, receiver) {
36
+ track();
37
+ const result = currentProxyHandler.get
38
+ ? currentProxyHandler.get(target, property, receiver)
39
+ : Reflect.get(target, property, receiver);
40
+ if (isObject(result) || Array.isArray(result)) {
41
+ return createProxy(result, path.concat({ target, property, receiver }));
42
+ }
43
+ return result;
44
+ },
45
+ set(target, property, value, receiver) {
46
+ const result = currentProxyHandler.set
47
+ ? currentProxyHandler.set(target, property, value, receiver)
48
+ : Reflect.set(target, property, value, receiver);
49
+ trigger();
50
+ return result;
51
+ },
52
+ deleteProperty(target, property) {
53
+ const result = currentProxyHandler.deleteProperty
54
+ ? currentProxyHandler.deleteProperty(target, property)
55
+ : Reflect.deleteProperty(target, property);
56
+ trigger();
57
+ return result;
58
+ }
59
+ });
60
+ };
61
+ let value = createProxy(source);
62
+ return {
63
+ get() {
64
+ track();
65
+ return value;
66
+ },
67
+ set(newValue) {
68
+ value = createProxy(newValue);
69
+ trigger();
70
+ }
71
+ };
72
+ });
73
+ // array values in originalData should store in default object to avoid removing items on change length
74
+ class ArrayInOriginalData {
75
+ length;
76
+ constructor(length) {
77
+ this.length = length;
78
+ // length should not include in iterations
79
+ Object.defineProperty(this, 'length', {
80
+ enumerable: false,
81
+ value: length
82
+ });
83
+ }
84
+ }
85
+ const setOriginalDataValue = (originalData, path) => {
86
+ let originalDataTarget = originalData;
87
+ for (const { target: oldValueParent, property } of path.slice(0, -1)) {
88
+ if (property in originalDataTarget) {
89
+ if (isObject(originalDataTarget[property]) || originalDataTarget[property] instanceof ArrayInOriginalData) {
90
+ originalDataTarget = originalDataTarget[property];
91
+ }
92
+ else {
93
+ // cancel set originalData value because in this case we try to replace primitive value by object or array value
94
+ return;
95
+ }
96
+ }
97
+ else {
98
+ if (Array.isArray(oldValueParent[property])) {
99
+ originalDataTarget = originalDataTarget[property] = new ArrayInOriginalData(oldValueParent[property].length);
100
+ }
101
+ else if (isObject(oldValueParent[property])) {
102
+ originalDataTarget = originalDataTarget[property] = {};
103
+ }
104
+ }
105
+ }
106
+ const lastItem = path.at(-1);
107
+ originalDataTarget[lastItem.property] = lastItem.target[lastItem.property];
108
+ };
109
+ const snapshotValueToOriginalData = (originalData, path, value) => {
110
+ const pathAsString = path.map((i) => i.property);
111
+ const valueInOriginalData = get(originalData, pathAsString);
112
+ const markRemovedFieldsAsUndefined = (valueInOriginalData, oldValue) => {
113
+ const keysSet = new Set();
114
+ if (valueInOriginalData) {
115
+ for (const key of Object.keys(valueInOriginalData)) {
116
+ keysSet.add(key);
117
+ }
118
+ }
119
+ if (oldValue) {
120
+ for (const key of Object.keys(oldValue)) {
121
+ keysSet.add(key);
122
+ }
123
+ }
124
+ const keys = Array.from(keysSet).filter((key) => !Object.keys(value).includes(key));
125
+ for (const key of keys) {
126
+ snapshotValueToOriginalData(originalData, path.concat({ target: oldValue || value, property: key }), undefined);
127
+ }
128
+ };
129
+ const lastPathItem = path.at(-1);
130
+ const oldValue = lastPathItem.target[lastPathItem.property];
131
+ if (isObject(value) && (isObject(valueInOriginalData) || isObject(oldValue))) {
132
+ // if value includes in oldValue or originalData need mark removed fields as undefined and recursively run nested objects
133
+ markRemovedFieldsAsUndefined(valueInOriginalData, oldValue);
134
+ for (const key of Object.keys(value)) {
135
+ snapshotValueToOriginalData(originalData, path.concat({ target: oldValue || value, property: key }), value[key]);
136
+ }
137
+ }
138
+ else if (Array.isArray(value) && (valueInOriginalData instanceof ArrayInOriginalData || Array.isArray(oldValue))) {
139
+ // do same for arrays
140
+ markRemovedFieldsAsUndefined(valueInOriginalData, oldValue);
141
+ for (const key of value.keys()) {
142
+ snapshotValueToOriginalData(originalData, path.concat({ target: oldValue || value, property: key.toString() }), value[key]);
143
+ }
144
+ }
145
+ else {
146
+ // in case value is plain then store it into originalData
147
+ if (!has(originalData, pathAsString)) {
148
+ if (oldValue !== value) {
149
+ setOriginalDataValue(originalData, path);
150
+ }
151
+ }
152
+ else if (valueInOriginalData === value) {
153
+ unset(originalData, pathAsString);
154
+ }
155
+ }
156
+ };
157
+ export const useTrackedInstance = (initialData) => {
158
+ const _originalData = createNestedRef({}, (path) => ({
159
+ deleteProperty(target, property) {
160
+ const result = Reflect.deleteProperty(target, property);
161
+ if (path.length) {
162
+ const parent = path.at(-1);
163
+ if (isEmpty(target)) {
164
+ delete parent.receiver[parent.property];
165
+ }
166
+ }
167
+ return result;
168
+ }
169
+ }));
170
+ const _data = createNestedRef({ root: initialData }, (parentThree) => ({
171
+ set(target, property, value, receiver) {
172
+ const path = parentThree.concat({ target, property, receiver });
173
+ const oldValue = target[property];
174
+ const triggerChangingArrayItems = () => {
175
+ // in case length in array has changed then emit changing of value by index
176
+ const originalDataValue = get(_originalData.value, path.map((i) => i.property));
177
+ const { length: originalDataLength } = originalDataValue || oldValue;
178
+ if (value < originalDataLength) {
179
+ // when removed new value
180
+ for (let i = value; i < originalDataLength; i++) {
181
+ delete receiver[i];
182
+ }
183
+ }
184
+ else if (originalDataLength < value) {
185
+ // store all removed values as "undefined" when this array values was in data before do some change
186
+ for (let i = originalDataLength; i < value; i++) {
187
+ receiver[i] = undefined;
188
+ }
189
+ }
190
+ };
191
+ if (Array.isArray(target) && property === 'length') {
192
+ if (value !== oldValue) {
193
+ triggerChangingArrayItems();
194
+ }
195
+ }
196
+ else {
197
+ snapshotValueToOriginalData(_originalData.value, path, value);
198
+ }
199
+ return Reflect.set(target, property, value, receiver);
200
+ },
201
+ deleteProperty(target, property) {
202
+ setOriginalDataValue(_originalData.value, parentThree.concat({ target, property }));
203
+ return Reflect.deleteProperty(target, property);
204
+ }
205
+ }));
206
+ const data = computed({
207
+ get: () => _data.value.root,
208
+ set: (value) => (_data.value.root = value)
209
+ });
210
+ const isDirty = computed(() => Object.keys(_originalData.value).length > 0);
211
+ const _changedData = computed(() => {
212
+ const changedData = {};
213
+ const originalDataIterator = iterateObject(_originalData.value, {
214
+ goDeepCondition: (path, value) => {
215
+ /*
216
+ * iterate over originalData
217
+ * but avoid going deep in case
218
+ * when value in data have different data type
219
+ * of same value in originalData
220
+ */
221
+ const valueInData = get(_data.value, path);
222
+ const isBothValuesAsArray = value instanceof ArrayInOriginalData && Array.isArray(valueInData);
223
+ const isBothValuesAsObject = isObject(value) && isObject(valueInData);
224
+ return isBothValuesAsObject || isBothValuesAsArray;
225
+ }
226
+ });
227
+ for (const [path] of originalDataIterator) {
228
+ const valueInData = get(_data.value, path);
229
+ set(changedData, path, valueInData);
230
+ }
231
+ return changedData;
232
+ });
233
+ const changedData = computed(() => _changedData.value.root);
234
+ const loadData = (newData) => {
235
+ _data.value = { root: newData };
236
+ _originalData.value = {};
237
+ };
238
+ const reset = () => {
239
+ const updatedData = JSON.parse(JSON.stringify(_data.value));
240
+ // iterate over originalData including objects to check array values
241
+ for (const [path, value] of iterateObject(_originalData.value, { includeParent: true })) {
242
+ if (value instanceof ArrayInOriginalData) {
243
+ // reset array length in data to remove new items
244
+ set(updatedData, path.concat('length'), value.length);
245
+ }
246
+ else if (!isObject(value)) {
247
+ if (value === undefined) {
248
+ unset(updatedData, path);
249
+ }
250
+ else {
251
+ set(updatedData, path, value);
252
+ }
253
+ }
254
+ }
255
+ _data.value = updatedData;
256
+ _originalData.value = {};
257
+ };
258
+ return {
259
+ data,
260
+ changedData,
261
+ isDirty,
262
+ loadData,
263
+ reset
264
+ };
265
+ };
266
+ //# sourceMappingURL=tracked-instance.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tracked-instance.js","sourceRoot":"","sources":["../src/tracked-instance.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.0.0",
2
+ "version": "1.0.1",
3
3
  "name": "tracked-instance",
4
4
  "description": "Build large forms and track all changes",
5
5
  "type": "module",
@@ -9,6 +9,10 @@
9
9
  },
10
10
  "main": "./dist/index.js",
11
11
  "types": "dist/index.d.ts",
12
+ "files": [
13
+ "dist",
14
+ "src"
15
+ ],
12
16
  "devDependencies": {
13
17
  "@types/lodash-es": "^4.17.12",
14
18
  "typescript": "^5.2.2",
@@ -1,22 +0,0 @@
1
- name: Run tests
2
-
3
- on:
4
- push:
5
- branches: [ master ]
6
-
7
- jobs:
8
- test:
9
- runs-on: ubuntu-latest
10
-
11
- strategy:
12
- matrix:
13
- node-version: [20.x]
14
-
15
- steps:
16
- - uses: actions/checkout@v2
17
- - name: Use Node.js ${{ matrix.node-version }}
18
- uses: actions/setup-node@v1
19
- with:
20
- node-version: ${{ matrix.node-version }}
21
- - run: npm install
22
- - run: npm run test
@@ -1,6 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <project version="4">
3
- <component name="TypeScriptCompiler">
4
- <option name="nodeInterpreterTextField" value="$USER_HOME$/.nvm/versions/node/v20.11.0/bin/node" />
5
- </component>
6
- </project>
package/.idea/modules.xml DELETED
@@ -1,8 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <project version="4">
3
- <component name="ProjectModuleManager">
4
- <modules>
5
- <module fileurl="file://$PROJECT_DIR$/.idea/tracked-instance.iml" filepath="$PROJECT_DIR$/.idea/tracked-instance.iml" />
6
- </modules>
7
- </component>
8
- </project>
@@ -1,12 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <module type="WEB_MODULE" version="4">
3
- <component name="NewModuleRootManager">
4
- <content url="file://$MODULE_DIR$">
5
- <excludeFolder url="file://$MODULE_DIR$/.tmp" />
6
- <excludeFolder url="file://$MODULE_DIR$/temp" />
7
- <excludeFolder url="file://$MODULE_DIR$/tmp" />
8
- </content>
9
- <orderEntry type="inheritedJdk" />
10
- <orderEntry type="sourceFolder" forTests="false" />
11
- </component>
12
- </module>
package/.idea/vcs.xml DELETED
@@ -1,6 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <project version="4">
3
- <component name="VcsDirectoryMappings">
4
- <mapping directory="$PROJECT_DIR$" vcs="Git" />
5
- </component>
6
- </project>
@@ -1,99 +0,0 @@
1
- import {useCollection} from '../src'
2
- import {describe, expect, it} from 'vitest'
3
-
4
- interface Person {
5
- name: string
6
- }
7
-
8
- describe('Collection', () => {
9
- describe('Create', () => {
10
- it('Should add new item at index in data', () => {
11
- const collection = useCollection<Person>()
12
- collection.loadData([{name: 'admin'}, {name: 'user'}])
13
- collection.add({name: 'new user'}, 1)
14
- expect(collection.items.value.map((item) => item.instance.data.value)).to.deep.equal([
15
- {name: 'admin'},
16
- {name: 'new user'},
17
- {name: 'user'}
18
- ])
19
- })
20
- })
21
-
22
- describe('isDirty', () => {
23
- it('Should make collection dirty when some item is "isDirty"', () => {
24
- const collection = useCollection<Person>()
25
- collection.loadData([{name: 'admin'}, {name: 'user'}])
26
- collection.items.value[0].instance.data.value.name = 'changed name'
27
- expect(collection.isDirty.value).equal(true)
28
- })
29
- it('Should make collection dirty when some item is removed', () => {
30
- const collection = useCollection<Person>()
31
- collection.loadData([{name: 'admin'}, {name: 'user'}])
32
- collection.remove(0)
33
- expect(collection.isDirty.value).equal(true)
34
- })
35
- it('Should make collection dirty when some item is "isNew"', () => {
36
- const collection = useCollection<Person>()
37
- collection.loadData([{name: 'admin'}, {name: 'user'}])
38
- collection.add({name: 'new user'})
39
- expect(collection.isDirty.value).equal(true)
40
- })
41
- })
42
-
43
- describe('reset', () => {
44
- const collection = useCollection<Person>()
45
- collection.loadData([{name: 'admin'}, {name: 'user'}])
46
- collection.items.value[0].instance.data.value.name = 'admin2'
47
- collection.add({name: 'new user'})
48
- collection.remove(0)
49
- collection.reset()
50
-
51
- it(`Collection shouldn't dirty`, () => {
52
- expect(collection.isDirty.value).equal(false)
53
- })
54
- it('Should clean deleted items', () => {
55
- expect(collection.items.value.some((item) => item.isRemoved.value)).equal(false)
56
- })
57
- it('Should reset each item in data', () => {
58
- expect(collection.items.value.some((item) => item.instance.isDirty.value)).equal(false)
59
- })
60
- it('should revert deleted items', async () => {
61
- expect(collection.items.value.map((item) => item.instance.data.value)).deep.eq([{name: 'admin'}, {name: 'user'}])
62
- })
63
- })
64
-
65
- describe('delete', () => {
66
- const collection = useCollection<Person>()
67
- collection.loadData([{name: 'admin'}, {name: 'user'}])
68
- collection.add({name: 'new user'})
69
- collection.remove(2)
70
- collection.remove(1)
71
-
72
- it('Should delete new items when removing it', () => {
73
- expect(collection.items.value[0].instance.data.value.name).equal('admin')
74
- expect(collection.items.value[1].instance.data.value.name).equal('user')
75
- expect(collection.items.value[1].isRemoved.value).equal(true)
76
- expect(collection.items.value[2]).undefined
77
- })
78
- })
79
-
80
- describe('loadData', () => {
81
- const collection = useCollection<Person>()
82
- collection.loadData([{name: 'admin'}, {name: 'user'}])
83
- it('Should load correct data', () => {
84
- expect(collection.items.value.map((item) => item.instance.data.value)).to.deep.equal([
85
- {name: 'admin'},
86
- {name: 'user'}
87
- ])
88
- })
89
- it(`Loaded items shouldn't equals "isNew"`, () => {
90
- expect(collection.items.value.some((item) => item.instance.isDirty.value)).equal(false)
91
- })
92
- it('Should clean revert removed items', () => {
93
- collection.remove(1)
94
- collection.remove(0)
95
- collection.loadData([{name: 'admin'}, {name: 'user'}])
96
- expect(collection.items.value.some((item) => item.isRemoved.value)).equal(false)
97
- })
98
- })
99
- })
@@ -1,313 +0,0 @@
1
- import {useTrackedInstance} from '../src'
2
- import {describe, expect, it} from 'vitest'
3
-
4
- describe('useTrackedInstance', async () => {
5
- it('should change data', async () => {
6
- const instance = useTrackedInstance({
7
- name: 'John',
8
- age: 22
9
- })
10
- expect(instance.isDirty.value).eq(false)
11
- expect(instance.changedData.value).undefined
12
-
13
- instance.data.value.name = 'test'
14
-
15
- expect(instance.isDirty.value).eq(true)
16
- expect(instance.changedData.value).deep.eq({
17
- name: 'test'
18
- })
19
-
20
- instance.data.value.name = 'John'
21
- expect(instance.isDirty.value).eq(false)
22
- })
23
-
24
- it('should accept primitive value as root', async () => {
25
- const instance = useTrackedInstance('John')
26
- instance.data.value = 'Jane'
27
-
28
- expect(instance.isDirty.value).eq(true)
29
-
30
- instance.reset()
31
-
32
- expect(instance.isDirty.value).eq(false)
33
- expect(instance.data.value).eq('John')
34
-
35
- instance.data.value = 'Tom'
36
- instance.loadData('Jack')
37
-
38
- expect(instance.isDirty.value).eq(false)
39
- expect(instance.data.value).eq('Jack')
40
- })
41
-
42
- it('should change array of string', async () => {
43
- const instance = useTrackedInstance({
44
- name: 'John',
45
- hobbies: ['drift']
46
- })
47
- instance.data.value.hobbies.push('films')
48
-
49
- expect(instance.isDirty.value).eq(true)
50
- expect(instance.changedData.value).deep.eq({
51
- hobbies: [undefined, 'films']
52
- })
53
- })
54
-
55
- it('should change nested value in object', async () => {
56
- const instance = useTrackedInstance({
57
- name: 'John',
58
- info: {
59
- contact: {
60
- phone: '1234567',
61
- address: 'Earth'
62
- }
63
- }
64
- })
65
-
66
- instance.data.value.info.contact.phone = 'none'
67
- expect(instance.changedData.value).deep.eq({
68
- info: {
69
- contact: {
70
- phone: 'none'
71
- }
72
- }
73
- })
74
- })
75
-
76
- it('should clean "changedData" after "loadData" ', async () => {
77
- const instance = useTrackedInstance({
78
- name: 'John',
79
- age: 22
80
- })
81
- instance.data.value.name = 'none'
82
- instance.data.value.age = 0
83
- instance.loadData({
84
- name: 'Test',
85
- age: 100
86
- })
87
-
88
- expect(instance.data.value).deep.eq({
89
- name: 'Test',
90
- age: 100
91
- })
92
- expect(instance.isDirty.value).eq(false)
93
- expect(instance.changedData.value).undefined
94
- })
95
-
96
- it('should reset data after do some change', async () => {
97
- const instance = useTrackedInstance({
98
- name: 'John',
99
- info: {
100
- contact: {
101
- phone: '1234567',
102
- address: 'Earth'
103
- }
104
- },
105
- hobbies: ['drift', 'films']
106
- })
107
- instance.data.value.name = 'changed'
108
- instance.data.value.info.contact.phone = 'none'
109
- instance.data.value.hobbies.splice(0, 1, 'test', 'test2')
110
- instance.reset()
111
-
112
- expect(instance.data.value).deep.eq({
113
- name: 'John',
114
- info: {
115
- contact: {
116
- phone: '1234567',
117
- address: 'Earth'
118
- }
119
- },
120
- hobbies: ['drift', 'films']
121
- })
122
- expect(instance.isDirty.value).eq(false)
123
- expect(instance.changedData.value).undefined
124
- })
125
-
126
- it('should display correct changedData after replace some value as object', async () => {
127
- const instance = useTrackedInstance<{
128
- contact: null | {
129
- phone: string
130
- galaxy: string
131
- address?: string
132
- }
133
- user: null | {
134
- name: string
135
- }
136
- }>({
137
- contact: {
138
- phone: '123',
139
- galaxy: 'Milky way',
140
- address: 'Earth'
141
- },
142
- user: null
143
- })
144
-
145
- instance.data.value.contact = null
146
-
147
- instance.data.value.contact = {
148
- phone: '1',
149
- galaxy: 'Milky way'
150
- }
151
- expect(instance.changedData.value).deep.eq({
152
- contact: {
153
- phone: '1',
154
- address: undefined
155
- }
156
- })
157
-
158
- instance.data.value.contact = {
159
- phone: '123',
160
- galaxy: 'Milky way',
161
- address: 'Earth'
162
- }
163
- expect(instance.isDirty.value).eq(false)
164
-
165
- instance.data.value.user = {
166
- name: 'Jack'
167
- }
168
- instance.data.value.user.name = 'John'
169
- expect(instance.changedData.value).deep.eq({
170
- user: {
171
- name: 'John'
172
- }
173
- })
174
- })
175
-
176
- it('should make whole object prop undefined', async () => {
177
- const instance = useTrackedInstance<{
178
- name?: string
179
- info?: Record<string, string>
180
- }>({
181
- name: 'John',
182
- info: {
183
- phone: '1234567',
184
- address: 'Earth'
185
- }
186
- })
187
- instance.data.value.name = undefined
188
- instance.data.value.info = undefined
189
-
190
- expect(instance.changedData.value).deep.eq({
191
- name: undefined,
192
- info: undefined
193
- })
194
- })
195
-
196
- it('should replace primitive value as new object', async () => {
197
- const instance = useTrackedInstance<{
198
- user: string | {name: string}
199
- }>({
200
- user: 'John'
201
- })
202
- instance.data.value.user = 'Jack'
203
-
204
- expect(instance.changedData.value).deep.eq({
205
- user: 'Jack'
206
- })
207
-
208
- instance.data.value.user = {
209
- name: 'Peter'
210
- }
211
-
212
- expect(instance.changedData.value).deep.eq({
213
- user: {name: 'Peter'}
214
- })
215
-
216
- instance.reset()
217
- expect(instance.data.value).deep.eq({
218
- user: 'John'
219
- })
220
- expect(instance.isDirty.value).eq(false)
221
- })
222
-
223
- it('should replace object value as new object', async () => {
224
- const instance = useTrackedInstance<{
225
- info: {
226
- address: string
227
- phone?: string
228
- passport: {
229
- id: number
230
- country?: string
231
- year?: number
232
- owner?: string
233
- }
234
- }
235
- }>({
236
- info: {
237
- address: 'Earth',
238
- phone: '1234567',
239
- passport: {
240
- id: 1,
241
- year: 2000
242
- }
243
- }
244
- })
245
- instance.data.value.info.address = 'Mars'
246
-
247
- expect(instance.changedData.value).deep.eq({
248
- info: {
249
- address: 'Mars'
250
- }
251
- })
252
-
253
- instance.data.value.info = {
254
- address: 'Earth',
255
- passport: {
256
- id: 2,
257
- country: 'Ukraine',
258
- owner: 'Jack'
259
- }
260
- }
261
-
262
- instance.data.value.info = {
263
- address: 'Earth',
264
- passport: {
265
- id: 2,
266
- country: 'Ukraine'
267
- }
268
- }
269
-
270
- expect(instance.changedData.value).deep.eq({
271
- info: {
272
- phone: undefined,
273
- passport: {
274
- id: 2,
275
- year: undefined,
276
- country: 'Ukraine'
277
- }
278
- }
279
- })
280
-
281
- instance.reset()
282
-
283
- expect(instance.changedData.value).undefined
284
- expect(instance.data.value).deep.eq({
285
- info: {
286
- address: 'Earth',
287
- phone: '1234567',
288
- passport: {
289
- id: 1,
290
- year: 2000
291
- }
292
- }
293
- })
294
- })
295
-
296
- it('should display correct changedData when change nested value in array of objects', async () => {
297
- const instance = useTrackedInstance<{id: number; name: string}[]>([
298
- {
299
- id: 1,
300
- name: 'John'
301
- },
302
- {
303
- id: 2,
304
- name: 'Jack'
305
- }
306
- ])
307
-
308
- instance.data.value[1].name = 'Joe'
309
- const expectedData = []
310
- expectedData[1] = {name: 'Joe'}
311
- expect(instance.changedData.value).deep.eq(expectedData)
312
- })
313
- })
package/tsconfig.json DELETED
@@ -1,24 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ESNext",
4
- "module": "ESNext",
5
- "moduleResolution": "bundler",
6
- "strict": true,
7
- "esModuleInterop": true,
8
- "allowSyntheticDefaultImports": true,
9
- "sourceMap": true,
10
- "declaration": true,
11
- "outDir": "./dist",
12
- "lib": ["ESNext", "DOM"],
13
- "useDefineForClassFields": true,
14
- "skipLibCheck": true,
15
- "resolveJsonModule": true,
16
- "isolatedModules": true,
17
-
18
- /* Linting */
19
- "noUnusedLocals": true,
20
- "noUnusedParameters": true,
21
- "noFallthroughCasesInSwitch": true
22
- },
23
- "include": ["src"],
24
- }
File without changes