@slimlib/smart-mock 0.1.2 → 0.1.4

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/dist/index.mjs CHANGED
@@ -1,327 +1,322 @@
1
- const mock = Symbol();
2
- const unwrap = Symbol();
3
- const unwrapValue = (value) => (value != null && value[unwrap]) || value;
4
- const getMockData = (value) => (value != null && value[mock]) || undefined;
5
- function createRecordingMockFactory() {
6
- const mockDatas = [];
7
- let counter = 0;
8
- return {
9
- createMock,
10
- generateGlobals,
11
- generate
12
- };
13
- function createMock(object, name) {
14
- return createInternalMock(object, {
15
- name,
16
- source: 0 /* MockDataSource.root */,
17
- useCount: 0,
18
- generated: false
19
- });
20
- }
21
- function generateGlobals() {
22
- const strings = [];
23
- for (const mockData of mockDatas) {
24
- if (mockData.generated)
25
- continue;
26
- if (!mockData.instanceName && mockData.source !== 0 /* MockDataSource.root */) {
27
- mockData.instanceName = getNextInstanceName();
28
- }
29
- const identifier = (mockData?.instanceName ?? mockData?.name);
30
- if (mockData.source !== 0 /* MockDataSource.root */) {
31
- strings.push('const ' + identifier + ' = ' + getAccessor(mockData, mockData.parent));
32
- }
33
- for (const effect of (mockData.sideEffects || [])) {
34
- switch (effect.source) {
35
- case 3 /* MockDataSource.set */:
36
- strings.push(identifier + '.' + effect.name + ' = ' + stringify(effect.options, replacer));
37
- break;
38
- // case MockDataSource.defineProperty:
39
- // strings.push('Object.defineProperty(' + identifier + ', "' + (effect.name as string) + '", ' + stringify(effect.options, replacer as ReplacerFunction) + ')');
40
- // break;
41
- case 5 /* MockDataSource.deleteProperty */:
42
- strings.push('delete ' + identifier + '["' + effect.name + '"]');
43
- break;
44
- case 6 /* MockDataSource.setPrototypeOf */:
45
- strings.push('Object.setPrototypeOf(' + identifier + ', ' + stringify(effect.options, replacer) + ')');
46
- break;
47
- case 7 /* MockDataSource.preventExtensions */:
48
- strings.push('Object.preventExtensions(' + identifier + ')');
49
- break;
50
- case 2 /* MockDataSource.call */:
51
- strings.push(identifier + getParameters(effect.options, replacer));
52
- break;
53
- }
54
- }
55
- }
56
- return strings.join('\n');
57
- function getAccessor(mockData, parent) {
58
- const parentName = (parent?.instanceName ?? parent?.name);
59
- switch (mockData.source) {
60
- case 2 /* MockDataSource.call */:
61
- return parentName + getParameters(mockData.options, replacer);
62
- case 1 /* MockDataSource.get */:
63
- return parentName + '.' + mockData.name;
64
- case 8 /* MockDataSource.construct */:
65
- {
66
- const newTarget = stringify(mockData.target, replacer);
67
- return parentName !== newTarget
68
- ? 'Reflect.construct(' + parentName + ',' + stringify(mockData.options, replacer) + ',' + newTarget + ')'
69
- : 'new ' + parentName + getParameters(mockData.options, replacer);
70
- }
71
- }
72
- }
73
- }
74
- function generate(object) {
75
- stringify(object, bumpReplacer);
76
- return stringify(object, replacer);
77
- }
78
- function bumpReplacer(value) {
79
- const mockData = getMockData(value);
80
- if (mockData) {
81
- ++mockData.useCount;
82
- return getCode(mockData, bumpReplacer, true);
83
- }
84
- return value;
85
- }
86
- function replacer(value) {
87
- const mockData = getMockData(value);
88
- if (mockData) {
89
- return getCode(mockData, replacer, true);
90
- }
91
- return value;
92
- }
93
- function getCode(value, replacer, bumpCount) {
94
- if (bumpCount && value.useCount > 1) {
95
- if (value.source === 0 /* MockDataSource.root */) {
96
- return value.name;
97
- }
98
- if (!value.instanceName) {
99
- value.instanceName = getNextInstanceName();
100
- }
101
- return value.instanceName;
102
- }
103
- value.generated = true;
104
- switch (value.source) {
105
- case 2 /* MockDataSource.call */:
106
- return getCallCode(value.parent, value);
107
- case 1 /* MockDataSource.get */:
108
- return getPrevCode(value) + '.' + value.name;
109
- case 0 /* MockDataSource.root */:
110
- return value.name;
111
- case 8 /* MockDataSource.construct */:
112
- {
113
- const prevCode = getPrevCode(value);
114
- const newTarget = stringify(value.target, replacer);
115
- return prevCode !== newTarget
116
- ? 'Reflect.construct(' + prevCode + ',' + stringify(value.options, replacer) + ',' + newTarget + ')'
117
- : 'new ' + prevCode + getParameters(value.options, replacer);
118
- }
119
- }
120
- function getCallCode(parent, value) {
121
- parent.generated = true;
122
- const prevCode = getPrevCode(parent);
123
- return prevCode + (prevCode ? '.' : '') + parent.name + getParameters(value.options, replacer);
124
- }
125
- function getPrevCode(mockData) {
126
- return mockData.parent ? getCode(mockData.parent, replacer, bumpCount) : '';
127
- }
128
- }
129
- function createInternalMock(target, mockData) {
130
- mockDatas.push(mockData);
131
- target[mock] = mockData;
132
- return new Proxy(target, {
133
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
134
- set(target, p, value, receiver) {
135
- const realValue = unwrapValue(value);
136
- if (!mockData.sideEffects) {
137
- mockData.sideEffects = [];
138
- }
139
- mockData.sideEffects.push({
140
- useCount: 0,
141
- name: p,
142
- options: realValue,
143
- parent: mockData,
144
- source: 3 /* MockDataSource.set */,
145
- generated: false
146
- });
147
- ++mockData.useCount;
148
- Reflect.set(target, p, realValue, receiver);
149
- return true;
150
- },
151
- get(target, p) {
152
- if (p === unwrap)
153
- return target;
154
- if (p === mock)
155
- return mockData;
156
- const value = Reflect.get(target, p);
157
- if (value === null || (typeof value !== 'object' && typeof value !== 'function')) {
158
- return value;
159
- }
160
- if (!mockData.mocks) {
161
- mockData.mocks = Object.create(null);
162
- }
163
- if (!mockData.mocks[p]) {
164
- mockData.mocks[p] = createInternalMock(value, {
165
- useCount: 0,
166
- name: p,
167
- parent: mockData,
168
- source: 1 /* MockDataSource.get */,
169
- generated: false
170
- });
171
- }
172
- const result = mockData.mocks[p];
173
- ++mockData.useCount;
174
- return result;
175
- },
176
- // eslint-disable-next-line @typescript-eslint/ban-types
177
- construct(target, argArray, newTarget) {
178
- const realTarget = unwrapValue(newTarget);
179
- const realArguments = unwrapValue(argArray);
180
- ++mockData.useCount;
181
- const result = Reflect.construct(target, realArguments, realTarget);
182
- return createInternalMock(result, {
183
- useCount: 0,
184
- name: '',
185
- options: realArguments,
186
- target: realTarget,
187
- parent: mockData,
188
- source: 8 /* MockDataSource.construct */,
189
- generated: false
190
- });
191
- },
192
- defineProperty(target, property, attributes) {
193
- const realValue = unwrapValue(attributes);
194
- // if (!mockData.sideEffects) {
195
- // mockData.sideEffects = [];
196
- // }
197
- // mockData.sideEffects.push({
198
- // useCount: 0,
199
- // name: property,
200
- // options: realValue,
201
- // parent: mockData,
202
- // source: MockDataSource.defineProperty,
203
- // generated: false
204
- // });
205
- // ++mockData.useCount;
206
- return Reflect.defineProperty(target, property, realValue);
207
- },
208
- deleteProperty(target, p) {
209
- if (!mockData.sideEffects) {
210
- mockData.sideEffects = [];
211
- }
212
- mockData.sideEffects.push({
213
- useCount: 0,
214
- name: p,
215
- options: undefined,
216
- parent: mockData,
217
- source: 5 /* MockDataSource.deleteProperty */,
218
- generated: false
219
- });
220
- ++mockData.useCount;
221
- const result = Reflect.deleteProperty(target, p);
222
- return result;
223
- },
224
- setPrototypeOf(target, v) {
225
- const realValue = unwrapValue(v);
226
- if (!mockData.sideEffects) {
227
- mockData.sideEffects = [];
228
- }
229
- mockData.sideEffects.push({
230
- useCount: 0,
231
- name: '',
232
- options: realValue,
233
- parent: mockData,
234
- source: 6 /* MockDataSource.setPrototypeOf */,
235
- generated: false
236
- });
237
- ++mockData.useCount;
238
- return Reflect.setPrototypeOf(target, realValue);
239
- },
240
- preventExtensions(target) {
241
- if (!mockData.sideEffects) {
242
- mockData.sideEffects = [];
243
- }
244
- mockData.sideEffects.push({
245
- useCount: 0,
246
- name: '',
247
- options: undefined,
248
- parent: mockData,
249
- source: 7 /* MockDataSource.preventExtensions */,
250
- generated: false
251
- });
252
- ++mockData.useCount;
253
- return Reflect.preventExtensions(target);
254
- },
255
- apply(target, thisArg, argumentsList) {
256
- const realThis = unwrapValue(thisArg);
257
- const realArguments = unwrapValue(argumentsList);
258
- ++mockData.useCount;
259
- const result = Reflect.apply(target, realThis, realArguments);
260
- if (result === null || (typeof result !== 'object' && typeof result !== 'function')) {
261
- if (!mockData.sideEffects) {
262
- mockData.sideEffects = [];
263
- }
264
- mockData.sideEffects.push({
265
- useCount: 0,
266
- name: '',
267
- parent: mockData,
268
- source: 2 /* MockDataSource.call */,
269
- options: realArguments,
270
- generated: false
271
- });
272
- ++mockData.useCount;
273
- return result;
274
- }
275
- return createInternalMock(result, {
276
- useCount: 0,
277
- name: '',
278
- parent: mockData,
279
- source: 2 /* MockDataSource.call */,
280
- options: realArguments,
281
- generated: false
282
- });
283
- }
284
- });
285
- }
286
- function getNextInstanceName() {
287
- return `tmp_${counter++}`;
288
- }
289
- }
290
- function getParameters(options, replacer) {
291
- return `(${options.length ? options.map(value => stringify(value, replacer)).join(',') : ''})`;
292
- }
293
- // stringify like functionality, recursively walks through objects and converts them to strings but leaved some basic values intact
294
- function stringify(value, replacer) {
295
- const original = value;
296
- value = replacer(value);
297
- if (original !== value && typeof value === 'string') {
298
- return value;
299
- }
300
- if (value === null) {
301
- return null;
302
- }
303
- if (value === undefined) {
304
- return undefined;
305
- }
306
- if (typeof value === 'number') {
307
- return `${value}`;
308
- }
309
- if (Array.isArray(value)) {
310
- return `[${value.map((v) => stringify(v, replacer)).join(',')}]`;
311
- }
312
- if (typeof value === 'boolean') {
313
- return value;
314
- }
315
- if (typeof value === 'function') {
316
- return value.toString();
317
- }
318
- if (value instanceof RegExp) {
319
- return value;
320
- }
321
- if (typeof value === 'object') {
322
- return `{${Object.entries(value).map(([k, v]) => k + ':' + stringify(v, replacer)).join(',')}}`;
323
- }
324
- return '"' + String(value) + '"';
1
+ const mock = Symbol();
2
+ const unwrap = Symbol();
3
+ const unwrapValue = (value) => (value != null && value[unwrap]) || value;
4
+ const getMockData = (value) => (value != null && value[mock]) || undefined;
5
+ function createRecordingMockFactory() {
6
+ const mockDatas = [];
7
+ let counter = 0;
8
+ return {
9
+ createMock,
10
+ generateGlobals,
11
+ generate
12
+ };
13
+ function createMock(object, name) {
14
+ return createInternalMock(object, {
15
+ name,
16
+ source: 0 /* MockDataSource.root */,
17
+ useCount: 0,
18
+ generated: false
19
+ });
20
+ }
21
+ function generateGlobals() {
22
+ const strings = [];
23
+ for (const mockData of mockDatas) {
24
+ if (mockData.generated)
25
+ continue;
26
+ if (!mockData.instanceName && mockData.source !== 0 /* MockDataSource.root */) {
27
+ mockData.instanceName = getNextInstanceName();
28
+ }
29
+ const identifier = (mockData?.instanceName ?? mockData?.name);
30
+ if (mockData.source !== 0 /* MockDataSource.root */) {
31
+ strings.push('const ' + identifier + ' = ' + getAccessor(mockData, mockData.parent));
32
+ }
33
+ for (const effect of (mockData.sideEffects || [])) {
34
+ switch (effect.source) {
35
+ case 3 /* MockDataSource.set */:
36
+ strings.push(identifier + '.' + effect.name + ' = ' + stringify(effect.options, replacer));
37
+ break;
38
+ // case MockDataSource.defineProperty:
39
+ // strings.push('Object.defineProperty(' + identifier + ', "' + (effect.name as string) + '", ' + stringify(effect.options, replacer as ReplacerFunction) + ')');
40
+ // break;
41
+ case 5 /* MockDataSource.deleteProperty */:
42
+ strings.push('delete ' + identifier + '["' + effect.name + '"]');
43
+ break;
44
+ case 6 /* MockDataSource.setPrototypeOf */:
45
+ strings.push('Object.setPrototypeOf(' + identifier + ', ' + stringify(effect.options, replacer) + ')');
46
+ break;
47
+ case 7 /* MockDataSource.preventExtensions */:
48
+ strings.push('Object.preventExtensions(' + identifier + ')');
49
+ break;
50
+ case 2 /* MockDataSource.call */:
51
+ strings.push(identifier + getParameters(effect.options, replacer));
52
+ break;
53
+ }
54
+ }
55
+ }
56
+ return strings.join('\n');
57
+ function getAccessor(mockData, parent) {
58
+ const parentName = (parent?.instanceName ?? parent?.name);
59
+ switch (mockData.source) {
60
+ case 2 /* MockDataSource.call */:
61
+ return parentName + getParameters(mockData.options, replacer);
62
+ case 1 /* MockDataSource.get */:
63
+ return parentName + '.' + mockData.name;
64
+ case 8 /* MockDataSource.construct */:
65
+ {
66
+ const newTarget = stringify(mockData.target, replacer);
67
+ return parentName !== newTarget
68
+ ? 'Reflect.construct(' + parentName + ',' + stringify(mockData.options, replacer) + ',' + newTarget + ')'
69
+ : 'new ' + parentName + getParameters(mockData.options, replacer);
70
+ }
71
+ }
72
+ }
73
+ }
74
+ function generate(object) {
75
+ stringify(object, bumpReplacer);
76
+ return stringify(object, replacer);
77
+ }
78
+ function bumpReplacer(value) {
79
+ const mockData = getMockData(value);
80
+ if (mockData) {
81
+ ++mockData.useCount;
82
+ return getCode(mockData, bumpReplacer, true);
83
+ }
84
+ return value;
85
+ }
86
+ function replacer(value) {
87
+ const mockData = getMockData(value);
88
+ if (mockData) {
89
+ return getCode(mockData, replacer, true);
90
+ }
91
+ return value;
92
+ }
93
+ function getCode(value, replacer, bumpCount) {
94
+ if (bumpCount && value.useCount > 1) {
95
+ if (value.source === 0 /* MockDataSource.root */) {
96
+ return value.name;
97
+ }
98
+ if (!value.instanceName) {
99
+ value.instanceName = getNextInstanceName();
100
+ }
101
+ return value.instanceName;
102
+ }
103
+ value.generated = true;
104
+ switch (value.source) {
105
+ case 2 /* MockDataSource.call */:
106
+ return getPrevCode(value) + getParameters(value.options, replacer);
107
+ case 1 /* MockDataSource.get */:
108
+ return getPrevCode(value) + '.' + value.name;
109
+ case 0 /* MockDataSource.root */:
110
+ return value.name;
111
+ case 8 /* MockDataSource.construct */:
112
+ {
113
+ const prevCode = getPrevCode(value);
114
+ const newTarget = stringify(value.target, replacer);
115
+ return prevCode !== newTarget
116
+ ? 'Reflect.construct(' + prevCode + ',' + stringify(value.options, replacer) + ',' + newTarget + ')'
117
+ : 'new ' + prevCode + getParameters(value.options, replacer);
118
+ }
119
+ }
120
+ function getPrevCode(mockData) {
121
+ return mockData.parent ? getCode(mockData.parent, replacer, bumpCount) : '';
122
+ }
123
+ }
124
+ function createInternalMock(target, mockData) {
125
+ mockDatas.push(mockData);
126
+ target[mock] = mockData;
127
+ return new Proxy(target, {
128
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
129
+ set(target, p, value, receiver) {
130
+ const realValue = unwrapValue(value);
131
+ if (!mockData.sideEffects) {
132
+ mockData.sideEffects = [];
133
+ }
134
+ mockData.sideEffects.push({
135
+ useCount: 0,
136
+ name: p,
137
+ options: realValue,
138
+ parent: mockData,
139
+ source: 3 /* MockDataSource.set */,
140
+ generated: false
141
+ });
142
+ ++mockData.useCount;
143
+ Reflect.set(target, p, realValue, receiver);
144
+ return true;
145
+ },
146
+ get(target, p) {
147
+ if (p === unwrap)
148
+ return target;
149
+ if (p === mock)
150
+ return mockData;
151
+ const value = Reflect.get(target, p);
152
+ if (value === null || (typeof value !== 'object' && typeof value !== 'function')) {
153
+ return value;
154
+ }
155
+ if (!mockData.mocks) {
156
+ mockData.mocks = Object.create(null);
157
+ }
158
+ if (!mockData.mocks[p]) {
159
+ mockData.mocks[p] = createInternalMock(value, {
160
+ useCount: 0,
161
+ name: p,
162
+ parent: mockData,
163
+ source: 1 /* MockDataSource.get */,
164
+ generated: false
165
+ });
166
+ }
167
+ const result = mockData.mocks[p];
168
+ ++mockData.useCount;
169
+ return result;
170
+ },
171
+ // eslint-disable-next-line @typescript-eslint/ban-types
172
+ construct(target, argArray, newTarget) {
173
+ const realTarget = unwrapValue(newTarget);
174
+ const realArguments = unwrapValue(argArray);
175
+ ++mockData.useCount;
176
+ const result = Reflect.construct(target, realArguments, realTarget);
177
+ return createInternalMock(result, {
178
+ useCount: 0,
179
+ name: '',
180
+ options: realArguments,
181
+ target: realTarget,
182
+ parent: mockData,
183
+ source: 8 /* MockDataSource.construct */,
184
+ generated: false
185
+ });
186
+ },
187
+ defineProperty(target, property, attributes) {
188
+ const realValue = unwrapValue(attributes);
189
+ // if (!mockData.sideEffects) {
190
+ // mockData.sideEffects = [];
191
+ // }
192
+ // mockData.sideEffects.push({
193
+ // useCount: 0,
194
+ // name: property,
195
+ // options: realValue,
196
+ // parent: mockData,
197
+ // source: MockDataSource.defineProperty,
198
+ // generated: false
199
+ // });
200
+ // ++mockData.useCount;
201
+ return Reflect.defineProperty(target, property, realValue);
202
+ },
203
+ deleteProperty(target, p) {
204
+ if (!mockData.sideEffects) {
205
+ mockData.sideEffects = [];
206
+ }
207
+ mockData.sideEffects.push({
208
+ useCount: 0,
209
+ name: p,
210
+ options: undefined,
211
+ parent: mockData,
212
+ source: 5 /* MockDataSource.deleteProperty */,
213
+ generated: false
214
+ });
215
+ ++mockData.useCount;
216
+ const result = Reflect.deleteProperty(target, p);
217
+ return result;
218
+ },
219
+ setPrototypeOf(target, v) {
220
+ const realValue = unwrapValue(v);
221
+ if (!mockData.sideEffects) {
222
+ mockData.sideEffects = [];
223
+ }
224
+ mockData.sideEffects.push({
225
+ useCount: 0,
226
+ name: '',
227
+ options: realValue,
228
+ parent: mockData,
229
+ source: 6 /* MockDataSource.setPrototypeOf */,
230
+ generated: false
231
+ });
232
+ ++mockData.useCount;
233
+ return Reflect.setPrototypeOf(target, realValue);
234
+ },
235
+ preventExtensions(target) {
236
+ if (!mockData.sideEffects) {
237
+ mockData.sideEffects = [];
238
+ }
239
+ mockData.sideEffects.push({
240
+ useCount: 0,
241
+ name: '',
242
+ options: undefined,
243
+ parent: mockData,
244
+ source: 7 /* MockDataSource.preventExtensions */,
245
+ generated: false
246
+ });
247
+ ++mockData.useCount;
248
+ return Reflect.preventExtensions(target);
249
+ },
250
+ apply(target, thisArg, argumentsList) {
251
+ const realThis = unwrapValue(thisArg);
252
+ const realArguments = unwrapValue(argumentsList);
253
+ ++mockData.useCount;
254
+ const result = Reflect.apply(target, realThis, realArguments);
255
+ if (result === null || (typeof result !== 'object' && typeof result !== 'function')) {
256
+ if (!mockData.sideEffects) {
257
+ mockData.sideEffects = [];
258
+ }
259
+ mockData.sideEffects.push({
260
+ useCount: 0,
261
+ name: '',
262
+ parent: mockData,
263
+ source: 2 /* MockDataSource.call */,
264
+ options: realArguments,
265
+ generated: false
266
+ });
267
+ ++mockData.useCount;
268
+ return result;
269
+ }
270
+ return createInternalMock(result, {
271
+ useCount: 0,
272
+ name: '',
273
+ parent: mockData,
274
+ source: 2 /* MockDataSource.call */,
275
+ options: realArguments,
276
+ generated: false
277
+ });
278
+ }
279
+ });
280
+ }
281
+ function getNextInstanceName() {
282
+ return `tmp_${counter++}`;
283
+ }
284
+ }
285
+ function getParameters(options, replacer) {
286
+ return `(${options.length ? options.map(value => stringify(value, replacer)).join(',') : ''})`;
287
+ }
288
+ // stringify like functionality, recursively walks through objects and converts them to strings but leaved some basic values intact
289
+ function stringify(value, replacer) {
290
+ const original = value;
291
+ value = replacer(value);
292
+ if (original !== value && typeof value === 'string') {
293
+ return value;
294
+ }
295
+ if (value === null) {
296
+ return null;
297
+ }
298
+ if (value === undefined) {
299
+ return undefined;
300
+ }
301
+ if (typeof value === 'number') {
302
+ return `${value}`;
303
+ }
304
+ if (Array.isArray(value)) {
305
+ return `[${value.map((v) => stringify(v, replacer)).join(',')}]`;
306
+ }
307
+ if (typeof value === 'boolean') {
308
+ return value;
309
+ }
310
+ if (typeof value === 'function') {
311
+ return value.toString();
312
+ }
313
+ if (value instanceof RegExp) {
314
+ return value;
315
+ }
316
+ if (typeof value === 'object') {
317
+ return `{${Object.entries(value).map(([k, v]) => k + ':' + stringify(v, replacer)).join(',')}}`;
318
+ }
319
+ return '"' + String(value) + '"';
325
320
  }
326
321
 
327
322
  export { createRecordingMockFactory as default };