@cmtlyt/lingshu-toolkit 0.3.0 → 0.5.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/dist/247.js +66 -0
- package/dist/707.js +8 -2
- package/dist/react/index.js +2 -4
- package/dist/react/use-mount/index.js +1 -1
- package/dist/react/use-ref-state/index.js +1 -3
- package/dist/shared/allx/__test__/allsettled.test.d.ts +1 -0
- package/dist/shared/allx/__test__/basic.test.d.ts +1 -0
- package/dist/shared/allx/__test__/circular-dependency.test.d.ts +1 -0
- package/dist/shared/allx/__test__/dependency.test.d.ts +1 -0
- package/dist/shared/allx/__test__/edge-cases.test.d.ts +1 -0
- package/dist/shared/allx/__test__/error-handling.test.d.ts +1 -0
- package/dist/shared/allx/__test__/execution-order.test.d.ts +1 -0
- package/dist/shared/allx/__test__/falsy-values.test.d.ts +1 -0
- package/dist/shared/allx/__test__/performance.test.d.ts +1 -0
- package/dist/shared/allx/__test__/type-checking.test.d.ts +1 -0
- package/dist/shared/allx/__test__/use-cases.test.d.ts +1 -0
- package/dist/shared/allx/index.d.ts +13 -0
- package/dist/shared/allx/index.js +44 -0
- package/dist/shared/allx/types.d.ts +13 -0
- package/dist/shared/allx/types.js +0 -0
- package/dist/shared/allx/utils.d.ts +9 -0
- package/dist/shared/allx/utils.js +94 -0
- package/dist/shared/animation/index.d.ts +2 -2
- package/dist/shared/animation/index.js +19 -13
- package/dist/shared/animation/types.d.ts +6 -4
- package/dist/shared/animation/utils.d.ts +3 -5
- package/dist/shared/animation/utils.js +2 -6
- package/dist/shared/api-controller/__test__/index.browser.test.d.ts +1 -0
- package/dist/shared/api-controller/__test__/index.node.test.d.ts +1 -0
- package/dist/shared/api-controller/create-api.d.ts +26 -0
- package/dist/shared/api-controller/create-api.js +79 -0
- package/dist/shared/api-controller/index.d.ts +3 -0
- package/dist/shared/api-controller/index.js +3 -0
- package/dist/shared/api-controller/request.d.ts +7 -0
- package/dist/shared/api-controller/request.js +66 -0
- package/dist/shared/api-controller/types.d.ts +141 -0
- package/dist/shared/api-controller/types.js +0 -0
- package/dist/shared/api-controller/utils.d.ts +22 -0
- package/dist/shared/api-controller/utils.js +96 -0
- package/dist/shared/data-handler/tools.js +1 -3
- package/dist/shared/data-mixed-manager/__test__/basic.test.d.ts +1 -0
- package/dist/shared/data-mixed-manager/__test__/build-options.test.d.ts +1 -0
- package/dist/shared/data-mixed-manager/__test__/constructor-options.test.d.ts +1 -0
- package/dist/shared/data-mixed-manager/__test__/data-management.test.d.ts +1 -0
- package/dist/shared/data-mixed-manager/__test__/edge-cases.test.d.ts +1 -0
- package/dist/shared/data-mixed-manager/__test__/events.browser.test.d.ts +1 -0
- package/dist/shared/data-mixed-manager/__test__/events.test.d.ts +1 -0
- package/dist/shared/data-mixed-manager/__test__/fixed-slots.test.d.ts +1 -0
- package/dist/shared/data-mixed-manager/__test__/insert-mode.test.d.ts +1 -0
- package/dist/shared/data-mixed-manager/constants.d.ts +8 -0
- package/dist/shared/data-mixed-manager/constants.js +9 -0
- package/dist/shared/data-mixed-manager/index.d.ts +128 -0
- package/dist/shared/data-mixed-manager/index.js +226 -0
- package/dist/shared/data-mixed-manager/types.d.ts +90 -0
- package/dist/shared/data-mixed-manager/types.js +0 -0
- package/dist/shared/index.d.ts +5 -0
- package/dist/shared/index.js +957 -2
- package/dist/shared/logger/index.d.ts +5 -0
- package/dist/shared/logger/index.js +1 -0
- package/dist/shared/throw-error/index.d.ts +1 -0
- package/dist/shared/throw-error/index.js +5 -2
- package/dist/shared/try-call/index.d.ts +22 -0
- package/dist/shared/try-call/index.js +59 -0
- package/dist/shared/try-call/index.test.d.ts +1 -0
- package/dist/shared/types/base.d.ts +5 -0
- package/dist/shared/types/pack.d.ts +1 -1
- package/dist/shared/utils/__test__/base.test.d.ts +1 -0
- package/dist/shared/utils/__test__/verify.test.d.ts +1 -0
- package/dist/shared/utils/base.d.ts +3 -0
- package/dist/shared/utils/base.js +6 -0
- package/dist/shared/utils/index.d.ts +2 -0
- package/dist/shared/utils/index.js +2 -0
- package/dist/shared/utils/verify.d.ts +53 -0
- package/dist/shared/utils/verify.js +67 -0
- package/package.json +10 -7
- package/dist/607.js +0 -311
package/dist/shared/index.js
CHANGED
|
@@ -1,2 +1,957 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import { throwType, createError, logger, $dt, throwError, getType, identity, dataHandler, $t, noop } from "../707.js";
|
|
2
|
+
function isSymbol(_v) {
|
|
3
|
+
return 'symbol' == typeof _v;
|
|
4
|
+
}
|
|
5
|
+
function isUndef(_v) {
|
|
6
|
+
return void 0 === _v;
|
|
7
|
+
}
|
|
8
|
+
function isNull(_v) {
|
|
9
|
+
return null === _v;
|
|
10
|
+
}
|
|
11
|
+
function isNullOrUndef(_v) {
|
|
12
|
+
return isNull(_v) || isUndef(_v);
|
|
13
|
+
}
|
|
14
|
+
function verify_isNaN(_v) {
|
|
15
|
+
return Number.isNaN(_v);
|
|
16
|
+
}
|
|
17
|
+
function isPlainSymbol(_v) {
|
|
18
|
+
return isSymbol(_v) && isUndef(Symbol.keyFor(_v));
|
|
19
|
+
}
|
|
20
|
+
function isObject(_v) {
|
|
21
|
+
return 'object' == typeof _v && !isNull(_v);
|
|
22
|
+
}
|
|
23
|
+
function isPlainObject(_v) {
|
|
24
|
+
return isObject(_v) && !isArray(_v);
|
|
25
|
+
}
|
|
26
|
+
function isArray(_v) {
|
|
27
|
+
return Array.isArray(_v);
|
|
28
|
+
}
|
|
29
|
+
function isEmptyArray(_v) {
|
|
30
|
+
return isArray(_v) && 0 === _v.length;
|
|
31
|
+
}
|
|
32
|
+
function isString(_v) {
|
|
33
|
+
return 'string' == typeof _v;
|
|
34
|
+
}
|
|
35
|
+
function isEmptyString(_v) {
|
|
36
|
+
return isString(_v) && 0 === _v.length;
|
|
37
|
+
}
|
|
38
|
+
function isNumber(_v) {
|
|
39
|
+
return 'number' == typeof _v;
|
|
40
|
+
}
|
|
41
|
+
function isPlainNumber(_v) {
|
|
42
|
+
return isNumber(_v) && !verify_isNaN(_v);
|
|
43
|
+
}
|
|
44
|
+
function isPropertyKey(_v) {
|
|
45
|
+
return isString(_v) || isNumber(_v) || isSymbol(_v);
|
|
46
|
+
}
|
|
47
|
+
function isBoolean(_v) {
|
|
48
|
+
return 'boolean' == typeof _v;
|
|
49
|
+
}
|
|
50
|
+
function isTrue(_v) {
|
|
51
|
+
return true === _v || isString(_v) && 'true' === _v.toLowerCase();
|
|
52
|
+
}
|
|
53
|
+
function isFalse(_v) {
|
|
54
|
+
return false === _v || isString(_v) && 'false' === _v.toLowerCase();
|
|
55
|
+
}
|
|
56
|
+
function isTruthy(_v) {
|
|
57
|
+
return !!_v;
|
|
58
|
+
}
|
|
59
|
+
function isFalsy(_v) {
|
|
60
|
+
return !(verify_isNaN(_v) || _v);
|
|
61
|
+
}
|
|
62
|
+
function isFunction(_v) {
|
|
63
|
+
return 'function' == typeof _v;
|
|
64
|
+
}
|
|
65
|
+
function isPromiseLike(_v) {
|
|
66
|
+
return isObject(_v) && isFunction(_v.then);
|
|
67
|
+
}
|
|
68
|
+
function withResolvers() {
|
|
69
|
+
return 'function' == typeof Promise.withResolvers ? Promise.withResolvers() : (()=>{
|
|
70
|
+
const resolver = {
|
|
71
|
+
promise: null,
|
|
72
|
+
resolve: null,
|
|
73
|
+
reject: null
|
|
74
|
+
};
|
|
75
|
+
resolver.promise = new Promise((resolve, reject)=>{
|
|
76
|
+
resolver.resolve = resolve;
|
|
77
|
+
resolver.reject = reject;
|
|
78
|
+
});
|
|
79
|
+
return resolver;
|
|
80
|
+
})();
|
|
81
|
+
}
|
|
82
|
+
function detectCycle(from, to, waitingForGraph) {
|
|
83
|
+
const visited = new Set();
|
|
84
|
+
const queue = [
|
|
85
|
+
to
|
|
86
|
+
];
|
|
87
|
+
let head = 0;
|
|
88
|
+
while(head < queue.length){
|
|
89
|
+
const node = queue[head++];
|
|
90
|
+
if (node === from) return true;
|
|
91
|
+
if (visited.has(node)) continue;
|
|
92
|
+
visited.add(node);
|
|
93
|
+
const deps = waitingForGraph.get(node);
|
|
94
|
+
if (deps) {
|
|
95
|
+
const depsIter = deps.values();
|
|
96
|
+
for(let dep = depsIter.next(); !dep.done; dep = depsIter.next())queue.push(dep.value);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
function getCached(results, depName, allSettled) {
|
|
102
|
+
if (Reflect.getOwnPropertyDescriptor(results, depName)) {
|
|
103
|
+
const cached = results[depName];
|
|
104
|
+
if (allSettled) return 'rejected' === cached.status ? Promise.reject(cached.reason) : Promise.resolve(cached.value);
|
|
105
|
+
return Promise.resolve(cached);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
function createDepResolver(waitingFor, resolverMap, currentTask, depName) {
|
|
109
|
+
waitingFor.set(currentTask, (waitingFor.get(currentTask) || new Set()).add(depName));
|
|
110
|
+
const depResolvers = resolverMap.get(depName) || withResolvers();
|
|
111
|
+
resolverMap.set(depName, depResolvers);
|
|
112
|
+
return depResolvers.promise.then((value)=>{
|
|
113
|
+
waitingFor.get(currentTask)?.delete(depName);
|
|
114
|
+
return value;
|
|
115
|
+
}, (error)=>{
|
|
116
|
+
waitingFor.get(currentTask)?.delete(depName);
|
|
117
|
+
throw error;
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
function cleanWaitingForGraph(waitingForGraph, depName) {
|
|
121
|
+
waitingForGraph.forEach((deps, task)=>{
|
|
122
|
+
deps.delete(depName);
|
|
123
|
+
if (0 === deps.size) waitingForGraph.delete(task);
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
function createDepProxy(tasks, results, options) {
|
|
127
|
+
const resolverMap = new Map();
|
|
128
|
+
const taskNameSet = new Set(Reflect.ownKeys(tasks));
|
|
129
|
+
const waitingForGraph = new Map();
|
|
130
|
+
const resolveDepFor = (depName, value)=>{
|
|
131
|
+
const resolver = resolverMap.get(depName);
|
|
132
|
+
if (resolver) {
|
|
133
|
+
resolver.resolve(value);
|
|
134
|
+
resolverMap.delete(depName);
|
|
135
|
+
}
|
|
136
|
+
cleanWaitingForGraph(waitingForGraph, depName);
|
|
137
|
+
};
|
|
138
|
+
const rejectDepFor = (depName, error)=>{
|
|
139
|
+
const resolver = resolverMap.get(depName);
|
|
140
|
+
if (resolver) {
|
|
141
|
+
resolver.reject(error);
|
|
142
|
+
resolverMap.delete(depName);
|
|
143
|
+
}
|
|
144
|
+
cleanWaitingForGraph(waitingForGraph, depName);
|
|
145
|
+
};
|
|
146
|
+
const createContextFor = (currentTask)=>new Proxy({}, {
|
|
147
|
+
get (_, depName) {
|
|
148
|
+
if (!taskNameSet.has(depName)) return Promise.reject(createError('allx', `Unknown task "${String(depName)}"`));
|
|
149
|
+
const cached = getCached(results, depName, options.allSettled);
|
|
150
|
+
if (cached) return cached;
|
|
151
|
+
if (detectCycle(currentTask, depName, waitingForGraph)) return Promise.reject(createError('allx', `Circular dependency detected: "${String(currentTask)}" -> "${String(depName)}"`));
|
|
152
|
+
return createDepResolver(waitingForGraph, resolverMap, currentTask, depName);
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
return {
|
|
156
|
+
taskNameSet,
|
|
157
|
+
createContextFor,
|
|
158
|
+
resolveDepFor,
|
|
159
|
+
rejectDepFor
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
function getValueFormatFunc(options) {
|
|
163
|
+
if (!options) return (value, _type = 'fulfilled')=>value;
|
|
164
|
+
if (options.allSettled) return (value, status = 'fulfilled')=>'fulfilled' === status ? {
|
|
165
|
+
status,
|
|
166
|
+
value
|
|
167
|
+
} : {
|
|
168
|
+
status,
|
|
169
|
+
reason: value
|
|
170
|
+
};
|
|
171
|
+
return (value, _type = 'fulfilled')=>value;
|
|
172
|
+
}
|
|
173
|
+
const validInfo = $dt({
|
|
174
|
+
allSettled: $t.boolean(false)
|
|
175
|
+
});
|
|
176
|
+
async function allx(tasks, options) {
|
|
177
|
+
const validOptions = dataHandler(options || {}, validInfo, {
|
|
178
|
+
unwrap: true
|
|
179
|
+
});
|
|
180
|
+
const { allSettled } = validOptions;
|
|
181
|
+
const results = {};
|
|
182
|
+
const depCtrl = createDepProxy(tasks, results, validOptions);
|
|
183
|
+
const valueFormat = getValueFormatFunc(options);
|
|
184
|
+
const promises = [];
|
|
185
|
+
depCtrl.taskNameSet.forEach(async (taskName)=>{
|
|
186
|
+
const taskFn = tasks[taskName];
|
|
187
|
+
const context = {
|
|
188
|
+
$: depCtrl.createContextFor(taskName)
|
|
189
|
+
};
|
|
190
|
+
const taskResolvers = withResolvers();
|
|
191
|
+
taskResolvers.promise.then((value)=>{
|
|
192
|
+
results[taskName] = valueFormat(value, 'fulfilled');
|
|
193
|
+
depCtrl.resolveDepFor(taskName, value);
|
|
194
|
+
return value;
|
|
195
|
+
}, (error)=>{
|
|
196
|
+
if (allSettled) results[taskName] = valueFormat(error, 'rejected');
|
|
197
|
+
depCtrl.rejectDepFor(taskName, error);
|
|
198
|
+
});
|
|
199
|
+
promises.push(taskResolvers.promise);
|
|
200
|
+
if (isPromiseLike(taskFn)) return void await taskFn.then(taskResolvers.resolve, taskResolvers.reject);
|
|
201
|
+
if (!isFunction(taskFn)) return void taskResolvers.resolve(taskFn);
|
|
202
|
+
try {
|
|
203
|
+
const result = await taskFn.call(context);
|
|
204
|
+
taskResolvers.resolve(result);
|
|
205
|
+
} catch (error) {
|
|
206
|
+
taskResolvers.reject(error);
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
if (allSettled) return Promise.allSettled(promises).then(()=>results);
|
|
210
|
+
return Promise.all(promises).then(()=>results);
|
|
211
|
+
}
|
|
212
|
+
function getNextValueHandler(from, to, valueFormatter) {
|
|
213
|
+
const type = getType(from);
|
|
214
|
+
const context = {
|
|
215
|
+
progress: 0,
|
|
216
|
+
valueFormatter
|
|
217
|
+
};
|
|
218
|
+
const baseNextValue = (_from, _to)=>{
|
|
219
|
+
const { valueFormatter: formatter, progress } = context;
|
|
220
|
+
if ('number' !== getType(_from)) return _from;
|
|
221
|
+
return formatter(_from + (_to - _from) * progress);
|
|
222
|
+
};
|
|
223
|
+
const arrayHandler = (_from, _to)=>{
|
|
224
|
+
const result = Array.from(_from, (item, idx)=>{
|
|
225
|
+
if (Array.isArray(item)) return arrayHandler(item, _to[idx]);
|
|
226
|
+
if ('object' === getType(item)) return objectHandler(item, _to[idx]);
|
|
227
|
+
return baseNextValue(item, _to[idx]);
|
|
228
|
+
});
|
|
229
|
+
return result;
|
|
230
|
+
};
|
|
231
|
+
const objectHandler = (_from, _to)=>{
|
|
232
|
+
const result = {};
|
|
233
|
+
const keys = Reflect.ownKeys(_from);
|
|
234
|
+
for(let i = 0; i < keys.length; i++){
|
|
235
|
+
const key = keys[i];
|
|
236
|
+
const fromValue = _from[key];
|
|
237
|
+
const toValue = _to[key];
|
|
238
|
+
if (Array.isArray(_from[key])) result[key] = arrayHandler(fromValue, toValue);
|
|
239
|
+
else if ('object' === getType(fromValue)) result[key] = objectHandler(fromValue, toValue);
|
|
240
|
+
else result[key] = baseNextValue(fromValue, toValue);
|
|
241
|
+
}
|
|
242
|
+
return result;
|
|
243
|
+
};
|
|
244
|
+
let nextValueHandler = baseNextValue;
|
|
245
|
+
if ('array' === type) nextValueHandler = arrayHandler;
|
|
246
|
+
else if ('object' === type) nextValueHandler = objectHandler;
|
|
247
|
+
return (progress)=>{
|
|
248
|
+
context.progress = progress;
|
|
249
|
+
return nextValueHandler(from, to);
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
function matchValid(from, to, valueParser) {
|
|
253
|
+
const fromType = getType(from);
|
|
254
|
+
const toType = getType(to);
|
|
255
|
+
if (fromType !== toType) throwType('animation/stepAnimation', 'from and to must be the same type');
|
|
256
|
+
if ('array' === fromType) {
|
|
257
|
+
if (from.length !== to.length) throwType('animation/stepAnimation', 'from and to must be the same length');
|
|
258
|
+
const result = [
|
|
259
|
+
Array.from({
|
|
260
|
+
length: from.length
|
|
261
|
+
}),
|
|
262
|
+
Array.from({
|
|
263
|
+
length: to.length
|
|
264
|
+
})
|
|
265
|
+
];
|
|
266
|
+
for(let i = 0; i < from.length; i++){
|
|
267
|
+
const [fromItem, toItem] = matchValid(from[i], to[i], valueParser);
|
|
268
|
+
result[0][i] = fromItem;
|
|
269
|
+
result[1][i] = toItem;
|
|
270
|
+
}
|
|
271
|
+
return result;
|
|
272
|
+
}
|
|
273
|
+
if ('object' === fromType) {
|
|
274
|
+
const toKeys = Reflect.ownKeys(to);
|
|
275
|
+
const fromKeys = new Set(Reflect.ownKeys(from));
|
|
276
|
+
const result = [
|
|
277
|
+
{},
|
|
278
|
+
{}
|
|
279
|
+
];
|
|
280
|
+
for(let i = 0; i < toKeys.length; i++){
|
|
281
|
+
const key = toKeys[i];
|
|
282
|
+
if (!fromKeys.has(key)) throwType('animation/stepAnimation', `from does not have this key: ${String(key)}`);
|
|
283
|
+
const [fromItem, toItem] = matchValid(from[key], to[key], valueParser);
|
|
284
|
+
result[0][key] = fromItem;
|
|
285
|
+
result[1][key] = toItem;
|
|
286
|
+
}
|
|
287
|
+
return result;
|
|
288
|
+
}
|
|
289
|
+
if ('number' !== fromType) return [
|
|
290
|
+
valueParser(from),
|
|
291
|
+
valueParser(to)
|
|
292
|
+
];
|
|
293
|
+
return [
|
|
294
|
+
from,
|
|
295
|
+
to
|
|
296
|
+
];
|
|
297
|
+
}
|
|
298
|
+
function createNextTick(resolvers, rcSignal) {
|
|
299
|
+
const nextTick = (()=>{
|
|
300
|
+
if ('function' == typeof globalThis.requestAnimationFrame) return globalThis.requestAnimationFrame;
|
|
301
|
+
return (callback)=>setTimeout(callback, 16);
|
|
302
|
+
})();
|
|
303
|
+
return (callback)=>{
|
|
304
|
+
if (rcSignal.stopSignal) return true;
|
|
305
|
+
nextTick(()=>tryRun(callback, resolvers, (error)=>{
|
|
306
|
+
rcSignal.stop();
|
|
307
|
+
resolvers.reject(error);
|
|
308
|
+
}));
|
|
309
|
+
return false;
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
async function tryRun(callback, resolvers, customErrorHandler) {
|
|
313
|
+
return new Promise((resolve, reject)=>{
|
|
314
|
+
const result = callback();
|
|
315
|
+
if (result && 'function' == typeof result.then) return result.then(resolve, reject);
|
|
316
|
+
resolve();
|
|
317
|
+
}).catch(customErrorHandler || resolvers.reject);
|
|
318
|
+
}
|
|
319
|
+
function createRunningControllerSignal(startFn, options) {
|
|
320
|
+
const { onStart, onStop, onClear } = options;
|
|
321
|
+
const resolvers = withResolvers();
|
|
322
|
+
const ctrl = {
|
|
323
|
+
stopSignal: true,
|
|
324
|
+
resolvers,
|
|
325
|
+
stop: ()=>{
|
|
326
|
+
ctrl.stopSignal = true;
|
|
327
|
+
onStop();
|
|
328
|
+
},
|
|
329
|
+
start: ()=>{
|
|
330
|
+
ctrl.stopSignal = false;
|
|
331
|
+
onStart();
|
|
332
|
+
startFn();
|
|
333
|
+
},
|
|
334
|
+
clear: ()=>{
|
|
335
|
+
ctrl.stopSignal = true;
|
|
336
|
+
onClear();
|
|
337
|
+
resolvers.resolve(true);
|
|
338
|
+
}
|
|
339
|
+
};
|
|
340
|
+
return ctrl;
|
|
341
|
+
}
|
|
342
|
+
const animation_validInfo = $dt({
|
|
343
|
+
autoStart: $t.boolean(true),
|
|
344
|
+
easing: $t["function"](()=>identity),
|
|
345
|
+
onStart: $t["function"](()=>noop),
|
|
346
|
+
onStop: $t["function"](()=>noop),
|
|
347
|
+
onClear: $t["function"](()=>noop),
|
|
348
|
+
onUpdate: $t["function"](()=>noop),
|
|
349
|
+
onComplete: $t["function"](()=>noop),
|
|
350
|
+
formatterValue: $t["function"](()=>identity),
|
|
351
|
+
formatter: $t["function"](()=>identity),
|
|
352
|
+
parser: $t["function"](()=>identity)
|
|
353
|
+
});
|
|
354
|
+
function* stepAnimation(from, to, step, options = {}) {
|
|
355
|
+
if (!Number.isInteger(step) || step <= 0) throwError('stepAnimation', 'step must be a positive integer', RangeError);
|
|
356
|
+
const validOptions = dataHandler(options, animation_validInfo, {
|
|
357
|
+
unwrap: true
|
|
358
|
+
});
|
|
359
|
+
const { parser: valueParser = identity, formatterValue = identity, formatter } = validOptions;
|
|
360
|
+
const [validFrom, validTo] = matchValid(from, to, valueParser);
|
|
361
|
+
const getNextValue = getNextValueHandler(validFrom, validTo, formatterValue);
|
|
362
|
+
for(let i = 0; i <= step; i++){
|
|
363
|
+
const value = formatter(getNextValue(i / step));
|
|
364
|
+
yield value;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
function animation(from, to, duration, options = {}) {
|
|
368
|
+
if (duration <= 0 || !Number.isInteger(duration)) throwError('animation', 'duration must be a positive integer', RangeError);
|
|
369
|
+
const validOptions = dataHandler(options, animation_validInfo, {
|
|
370
|
+
unwrap: true
|
|
371
|
+
});
|
|
372
|
+
const [validFrom, validTo] = matchValid(from, to, validOptions.parser);
|
|
373
|
+
const { autoStart, easing, onComplete, onUpdate, formatterValue, formatter } = validOptions;
|
|
374
|
+
const _getNextValue = getNextValueHandler(validFrom, validTo, formatterValue);
|
|
375
|
+
const getNextValue = (...args)=>formatter(_getNextValue(...args));
|
|
376
|
+
let startTime = 0;
|
|
377
|
+
let hasStarted = false;
|
|
378
|
+
const rcSignal = createRunningControllerSignal(()=>{
|
|
379
|
+
const now = performance.now();
|
|
380
|
+
startTime += now;
|
|
381
|
+
const stopFlag = nextTick(tick);
|
|
382
|
+
if (stopFlag) {
|
|
383
|
+
startTime -= performance.now();
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
if (!hasStarted) {
|
|
387
|
+
onUpdate(getNextValue(0));
|
|
388
|
+
hasStarted = true;
|
|
389
|
+
}
|
|
390
|
+
}, validOptions);
|
|
391
|
+
const { resolvers } = rcSignal;
|
|
392
|
+
const nextTick = createNextTick(resolvers, rcSignal);
|
|
393
|
+
const tick = ()=>{
|
|
394
|
+
const elapsed = performance.now() - startTime;
|
|
395
|
+
const progress = easing(Math.min(elapsed / duration, 1));
|
|
396
|
+
const value = getNextValue(progress);
|
|
397
|
+
onUpdate(value);
|
|
398
|
+
if (elapsed < duration) {
|
|
399
|
+
const stopFlag = nextTick(tick);
|
|
400
|
+
if (stopFlag) startTime = -elapsed;
|
|
401
|
+
} else {
|
|
402
|
+
onComplete();
|
|
403
|
+
resolvers.resolve(false);
|
|
404
|
+
}
|
|
405
|
+
};
|
|
406
|
+
if (false !== autoStart) rcSignal.start();
|
|
407
|
+
return {
|
|
408
|
+
promise: resolvers.promise,
|
|
409
|
+
stop: rcSignal.stop,
|
|
410
|
+
start: rcSignal.start,
|
|
411
|
+
clear: rcSignal.clear
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
const EMPTY = Symbol('EMPTY');
|
|
415
|
+
function tryCallFunc(cb, onError, onFinal) {
|
|
416
|
+
if (!isFunction(cb)) throwType('tryCallFunc', 'callback is not a function');
|
|
417
|
+
const catchFn = (self, ctx, error)=>{
|
|
418
|
+
if (isFunction(onError)) try {
|
|
419
|
+
ctx.errorResult = Reflect.apply(onError, self, [
|
|
420
|
+
error
|
|
421
|
+
]);
|
|
422
|
+
} catch (err) {
|
|
423
|
+
ctx.error = err;
|
|
424
|
+
}
|
|
425
|
+
else ctx.error = error;
|
|
426
|
+
return ctx.errorResult;
|
|
427
|
+
};
|
|
428
|
+
const finallyFn = (self, ctx, result)=>{
|
|
429
|
+
try {
|
|
430
|
+
if (ctx.error !== EMPTY) throw ctx.error;
|
|
431
|
+
} finally{
|
|
432
|
+
if (isFunction(onFinal)) if (ctx.errorResult !== EMPTY) Reflect.apply(onFinal, self, [
|
|
433
|
+
ctx.errorResult
|
|
434
|
+
]);
|
|
435
|
+
else if (ctx.error !== EMPTY) Reflect.apply(onFinal, self, [
|
|
436
|
+
ctx.error
|
|
437
|
+
]);
|
|
438
|
+
else Reflect.apply(onFinal, self, [
|
|
439
|
+
result
|
|
440
|
+
]);
|
|
441
|
+
}
|
|
442
|
+
};
|
|
443
|
+
return function(...args) {
|
|
444
|
+
const ctx = {
|
|
445
|
+
oriResult: EMPTY,
|
|
446
|
+
errorResult: EMPTY,
|
|
447
|
+
error: EMPTY
|
|
448
|
+
};
|
|
449
|
+
const asyncFn = async ()=>{
|
|
450
|
+
try {
|
|
451
|
+
ctx.oriResult = Reflect.apply(cb, this, args);
|
|
452
|
+
return ctx.oriResult;
|
|
453
|
+
} catch (error) {
|
|
454
|
+
return catchFn(this, ctx, error);
|
|
455
|
+
}
|
|
456
|
+
};
|
|
457
|
+
const fnPromise = asyncFn().catch((error)=>catchFn(this, ctx, error));
|
|
458
|
+
if (isPromiseLike(ctx.oriResult)) return fnPromise.then((result)=>{
|
|
459
|
+
finallyFn(this, ctx, result);
|
|
460
|
+
return result;
|
|
461
|
+
});
|
|
462
|
+
finallyFn(this, ctx, ctx.oriResult);
|
|
463
|
+
return ctx.oriResult !== EMPTY ? ctx.oriResult : ctx.errorResult;
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
function tryCall(cb, onError, onFinal) {
|
|
467
|
+
if (!isFunction(cb)) throwType('tryCall', 'callback is not a function');
|
|
468
|
+
return tryCallFunc(cb, onError, onFinal).call(this);
|
|
469
|
+
}
|
|
470
|
+
const ABSOLUTE_URL_REG = /^[a-z][a-z\d+\-.]*:/im;
|
|
471
|
+
function isAbsUrl(url) {
|
|
472
|
+
if (!url) return false;
|
|
473
|
+
return ABSOLUTE_URL_REG.test(url);
|
|
474
|
+
}
|
|
475
|
+
function targetUrlParser(_url, _baseUrl) {
|
|
476
|
+
if (isAbsUrl(_url)) return new URL(_url);
|
|
477
|
+
if (!isAbsUrl(_baseUrl)) throwType('apiController.request', 'baseUrl 配置不合法, 必须是绝对路径');
|
|
478
|
+
const baseUrl = new URL(_baseUrl);
|
|
479
|
+
const basePath = '/' === baseUrl.pathname ? '' : baseUrl.pathname.replace(/\/$/, '');
|
|
480
|
+
const relativePath = _url.startsWith('/') ? _url : `/${_url}`;
|
|
481
|
+
const url = `${basePath}${relativePath}`;
|
|
482
|
+
return new URL(url, baseUrl);
|
|
483
|
+
}
|
|
484
|
+
function urlParamsParser(url, params) {
|
|
485
|
+
if (!url.includes('/:')) return url;
|
|
486
|
+
if (!params) throwType('apiController.parseParams', 'url 中存在 params 参数, params 配置不能为空, 请使用 custom 方法调用并传递 params 配置');
|
|
487
|
+
const urlSplit = url.split('/');
|
|
488
|
+
const emptyKeys = [];
|
|
489
|
+
for(let i = 1; i < urlSplit.length; ++i){
|
|
490
|
+
if (':' !== urlSplit[i][0]) continue;
|
|
491
|
+
const param = urlSplit[i].slice(1);
|
|
492
|
+
const originValue = params[param];
|
|
493
|
+
if (!(isPlainNumber(originValue) || originValue)) {
|
|
494
|
+
emptyKeys.push(param);
|
|
495
|
+
continue;
|
|
496
|
+
}
|
|
497
|
+
const paramValue = encodeURIComponent(String(originValue));
|
|
498
|
+
urlSplit[i] = paramValue;
|
|
499
|
+
}
|
|
500
|
+
if (emptyKeys.length) throwType('apiController.parseParams', `params 配置中缺少 [${emptyKeys.join(', ')}] 参数`);
|
|
501
|
+
return urlSplit.join('/');
|
|
502
|
+
}
|
|
503
|
+
function getBody(data, tdto) {
|
|
504
|
+
const _body = tdto ? tdto(data) : data;
|
|
505
|
+
const bodyType = getType(_body);
|
|
506
|
+
switch(bodyType){
|
|
507
|
+
case 'object':
|
|
508
|
+
case 'array':
|
|
509
|
+
case 'number':
|
|
510
|
+
case 'boolean':
|
|
511
|
+
case 'function':
|
|
512
|
+
return JSON.stringify(_body);
|
|
513
|
+
default:
|
|
514
|
+
return _body;
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
function instanceMemberGetter(prop, instanceObj) {
|
|
518
|
+
return instanceObj[prop];
|
|
519
|
+
}
|
|
520
|
+
function createInstance(apiMap, realDefaultConfig, defaultConfig) {
|
|
521
|
+
return {
|
|
522
|
+
$: apiMap,
|
|
523
|
+
$$: defaultConfig,
|
|
524
|
+
$$r: realDefaultConfig,
|
|
525
|
+
$updateBaseUrl (baseUrl) {
|
|
526
|
+
if (isAbsUrl(baseUrl)) realDefaultConfig.baseUrl = baseUrl;
|
|
527
|
+
else {
|
|
528
|
+
const { origin } = globalThis.location || {};
|
|
529
|
+
if (!origin) throwError('apiController.$updateBaseUrl', 'location.origin is undefined');
|
|
530
|
+
const normalizedPath = (baseUrl || '/').startsWith('/') ? baseUrl || '' : `/${baseUrl}`;
|
|
531
|
+
realDefaultConfig.baseUrl = `${origin}${normalizedPath}`;
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
};
|
|
535
|
+
}
|
|
536
|
+
function getInstanceMemberOrApi(target, prop, receiver, instanceObj) {
|
|
537
|
+
if (Reflect.getOwnPropertyDescriptor(instanceObj, prop)) return {
|
|
538
|
+
instanceMember: instanceMemberGetter(prop, instanceObj)
|
|
539
|
+
};
|
|
540
|
+
const hasExactProp = isString(prop) && Reflect.has(target, prop);
|
|
541
|
+
const isCustom = isString(prop) && prop.endsWith('Custom') && !hasExactProp;
|
|
542
|
+
const name = isCustom ? prop.slice(0, -6) : prop;
|
|
543
|
+
if (!Reflect.getOwnPropertyDescriptor(target, name)) return;
|
|
544
|
+
const api = Reflect.get(target, name, receiver);
|
|
545
|
+
if (isCustom && !isString(api.url)) return;
|
|
546
|
+
return {
|
|
547
|
+
api,
|
|
548
|
+
isCustom
|
|
549
|
+
};
|
|
550
|
+
}
|
|
551
|
+
function apiNamesCheck(_apiMap, isDeep = false) {
|
|
552
|
+
const apiNames = Reflect.ownKeys(_apiMap);
|
|
553
|
+
const warnNames = [];
|
|
554
|
+
for(let i = 0; i < apiNames.length; i++){
|
|
555
|
+
const name = apiNames[i];
|
|
556
|
+
if (name.endsWith('Custom')) warnNames.push(name);
|
|
557
|
+
if (!isString(_apiMap[name].url)) warnNames.push(...apiNamesCheck(_apiMap[name], true));
|
|
558
|
+
}
|
|
559
|
+
if (!isDeep && warnNames.length > 0) logger.warn('apiController.createApiWithMap', 'api 命名不应该使用 Custom 结尾, 因为这是一个内部实现的方法', warnNames);
|
|
560
|
+
return warnNames;
|
|
561
|
+
}
|
|
562
|
+
async function baseRequest(config, getResponse) {
|
|
563
|
+
const { baseUrl, url, method: _method, parser, data, tdto, tvo, onResponse, ...rest } = config;
|
|
564
|
+
const targetUrl = targetUrlParser(url, baseUrl);
|
|
565
|
+
const method = _method?.toUpperCase();
|
|
566
|
+
const requestInfo = tryCall(()=>{
|
|
567
|
+
if (isNullOrUndef(method) || 'GET' === method || 'HEAD' === method) {
|
|
568
|
+
const queryKeys = Object.keys(data || {});
|
|
569
|
+
for(let i = 0; i < queryKeys.length; ++i)targetUrl.searchParams.append(queryKeys[i], data[queryKeys[i]]);
|
|
570
|
+
return new Request(targetUrl, {
|
|
571
|
+
...rest,
|
|
572
|
+
method
|
|
573
|
+
});
|
|
574
|
+
}
|
|
575
|
+
const body = getBody(data, tdto);
|
|
576
|
+
return new Request(targetUrl, {
|
|
577
|
+
...rest,
|
|
578
|
+
method,
|
|
579
|
+
body
|
|
580
|
+
});
|
|
581
|
+
});
|
|
582
|
+
const responseInfo = await getResponse(requestInfo);
|
|
583
|
+
const resResult = await tryCall(()=>{
|
|
584
|
+
if (onResponse) return onResponse(responseInfo, config);
|
|
585
|
+
if (!parser) return responseInfo.json();
|
|
586
|
+
if ('stream' === parser) return responseInfo.body;
|
|
587
|
+
const responseHandler = responseInfo[parser];
|
|
588
|
+
if (isFunction(responseHandler)) return Reflect.apply(responseHandler, responseInfo, []);
|
|
589
|
+
throwType('apiController.responseParser', 'Invalid parser');
|
|
590
|
+
});
|
|
591
|
+
return tvo ? tvo(resResult) : resResult;
|
|
592
|
+
}
|
|
593
|
+
async function mockRequest(config) {
|
|
594
|
+
const { onRequest, ...rest } = config;
|
|
595
|
+
return baseRequest(config, async (requestInfo)=>{
|
|
596
|
+
const reqResult = await (onRequest && onRequest(requestInfo, config));
|
|
597
|
+
const responseBody = getBody(reqResult);
|
|
598
|
+
return new Response(responseBody, {
|
|
599
|
+
...rest
|
|
600
|
+
});
|
|
601
|
+
});
|
|
602
|
+
}
|
|
603
|
+
async function networkRequest(config) {
|
|
604
|
+
return baseRequest(config, fetch);
|
|
605
|
+
}
|
|
606
|
+
function request(config) {
|
|
607
|
+
const url = urlParamsParser(config.url, config.params);
|
|
608
|
+
const { requestMode, requestModeMap } = config;
|
|
609
|
+
const customRequest = (requestModeMap || {})[requestMode || ''];
|
|
610
|
+
if (customRequest) return customRequest({
|
|
611
|
+
...config,
|
|
612
|
+
url
|
|
613
|
+
});
|
|
614
|
+
if ('mock' === requestMode) return mockRequest({
|
|
615
|
+
...config,
|
|
616
|
+
url
|
|
617
|
+
});
|
|
618
|
+
return networkRequest({
|
|
619
|
+
...config,
|
|
620
|
+
url
|
|
621
|
+
});
|
|
622
|
+
}
|
|
623
|
+
const FROM_DEFINE = Symbol('fromDefine');
|
|
624
|
+
function createApiWithMap(apiMap, defaultConfig) {
|
|
625
|
+
const fromDefine = apiMap[FROM_DEFINE];
|
|
626
|
+
delete apiMap[FROM_DEFINE];
|
|
627
|
+
const proxyCache = Object.create(null);
|
|
628
|
+
const realDefaultConfig = defaultConfig || {};
|
|
629
|
+
if (!isTrue(fromDefine)) apiNamesCheck(apiMap);
|
|
630
|
+
const instanceObj = createInstance(apiMap, realDefaultConfig, defaultConfig);
|
|
631
|
+
const proxy = new Proxy(apiMap, {
|
|
632
|
+
get (target, prop, receiver) {
|
|
633
|
+
if (Reflect.getOwnPropertyDescriptor(proxyCache, prop)) return proxyCache[prop];
|
|
634
|
+
const { instanceMember, api, isCustom = false } = getInstanceMemberOrApi(target, prop, receiver, instanceObj) || {};
|
|
635
|
+
if (instanceMember) return instanceMember;
|
|
636
|
+
if (!api) return;
|
|
637
|
+
let result = null;
|
|
638
|
+
result = isString(api.url) ? createApi({
|
|
639
|
+
...api,
|
|
640
|
+
[FROM_DEFINE]: fromDefine
|
|
641
|
+
}, realDefaultConfig, isCustom) : createApiWithMap({
|
|
642
|
+
...api,
|
|
643
|
+
[FROM_DEFINE]: fromDefine
|
|
644
|
+
}, realDefaultConfig);
|
|
645
|
+
proxyCache[prop] = result;
|
|
646
|
+
return result;
|
|
647
|
+
}
|
|
648
|
+
});
|
|
649
|
+
return proxy;
|
|
650
|
+
}
|
|
651
|
+
function createApi(api, defaultConfig, custom) {
|
|
652
|
+
const fromDefine = api[FROM_DEFINE];
|
|
653
|
+
delete api[FROM_DEFINE];
|
|
654
|
+
const realDefaultConfig = defaultConfig || {};
|
|
655
|
+
if (!isString(api.url)) throwType('apiController.createApi', '入参应为 APIConfig 对象');
|
|
656
|
+
if (api.url.includes('/:')) {
|
|
657
|
+
if (!isTrue(fromDefine)) logger.warn('apiController.createApi', 'url 中存在 params 参数, 使用 defineApi 或 defineApiMap 定义 API 或 API map 来获取更好的类型提示');
|
|
658
|
+
if (!isTrue(custom)) throwType('apiController.createApi', 'url 中存在 params 参数, 不支持普通请求, 转为自定义请求');
|
|
659
|
+
}
|
|
660
|
+
let handler = null;
|
|
661
|
+
handler = isTrue(custom) ? (data, config)=>request({
|
|
662
|
+
...realDefaultConfig,
|
|
663
|
+
...api,
|
|
664
|
+
...config,
|
|
665
|
+
url: api.url,
|
|
666
|
+
data,
|
|
667
|
+
oriUrl: api.url
|
|
668
|
+
}) : (data)=>request({
|
|
669
|
+
...realDefaultConfig,
|
|
670
|
+
...api,
|
|
671
|
+
data,
|
|
672
|
+
oriUrl: api.url
|
|
673
|
+
});
|
|
674
|
+
const instanceObj = createInstance(api, realDefaultConfig, defaultConfig);
|
|
675
|
+
if (!isAbsUrl(api.url)) instanceObj.$updateBaseUrl(realDefaultConfig.baseUrl);
|
|
676
|
+
return new Proxy(handler, {
|
|
677
|
+
get (target, prop, receiver) {
|
|
678
|
+
if (Reflect.getOwnPropertyDescriptor(instanceObj, prop)) return instanceMemberGetter(prop, instanceObj);
|
|
679
|
+
return Reflect.get(target, prop, receiver);
|
|
680
|
+
}
|
|
681
|
+
});
|
|
682
|
+
}
|
|
683
|
+
function defineApi(_api) {
|
|
684
|
+
return {
|
|
685
|
+
..._api,
|
|
686
|
+
[FROM_DEFINE]: true
|
|
687
|
+
};
|
|
688
|
+
}
|
|
689
|
+
function defineApiMap(_apiMap) {
|
|
690
|
+
apiNamesCheck(_apiMap);
|
|
691
|
+
return {
|
|
692
|
+
..._apiMap,
|
|
693
|
+
[FROM_DEFINE]: true
|
|
694
|
+
};
|
|
695
|
+
}
|
|
696
|
+
function getEmpty(_v) {
|
|
697
|
+
return Array.isArray(_v) ? [] : {};
|
|
698
|
+
}
|
|
699
|
+
function valueCheck(_v) {
|
|
700
|
+
return Array.isArray(_v) || 'object' == typeof _v;
|
|
701
|
+
}
|
|
702
|
+
function conditionMerge(...input) {
|
|
703
|
+
const conditionItems = (input.length > 1 ? input : input[0]).map((item)=>{
|
|
704
|
+
let result = null;
|
|
705
|
+
if (Array.isArray(item)) {
|
|
706
|
+
const [condition, value, fullback] = item;
|
|
707
|
+
result = {
|
|
708
|
+
condition,
|
|
709
|
+
value,
|
|
710
|
+
fullback
|
|
711
|
+
};
|
|
712
|
+
} else if (Object.getOwnPropertyDescriptor(item, 'condition')) result = item;
|
|
713
|
+
else throwType('conditionMerge', 'input must be an ConditionItem');
|
|
714
|
+
const validValue = valueCheck(result.value);
|
|
715
|
+
const validFullback = void 0 === result.fullback || valueCheck(result.fullback);
|
|
716
|
+
if (!(validValue && validFullback)) throwType('conditionMerge', 'value and fullback must be an array or object');
|
|
717
|
+
return result;
|
|
718
|
+
});
|
|
719
|
+
const result = getEmpty(conditionItems[0].value);
|
|
720
|
+
const mergeFn = Array.isArray(result) ? (a1, a2)=>Reflect.apply(Array.prototype.splice.bind(a1, a1.length, 0), null, a2) : Object.assign;
|
|
721
|
+
for(let i = 0, item = conditionItems[i]; i < conditionItems.length; item = conditionItems[++i])mergeFn(result, item.condition ? item.value : item.fullback || getEmpty(item.value));
|
|
722
|
+
return result;
|
|
723
|
+
}
|
|
724
|
+
const SLOT_TYPE = {
|
|
725
|
+
fixed: {
|
|
726
|
+
fixedFlag: Symbol('fixed')
|
|
727
|
+
},
|
|
728
|
+
insert: {
|
|
729
|
+
insertFlag: Symbol('insert')
|
|
730
|
+
}
|
|
731
|
+
};
|
|
732
|
+
const data_mixed_manager_validInfo = $dt({
|
|
733
|
+
name: $t.string('default'),
|
|
734
|
+
fixedSlots: $t.array([]),
|
|
735
|
+
dataList: $t.array([]),
|
|
736
|
+
listener: $t.object({})
|
|
737
|
+
});
|
|
738
|
+
class DataMixedManager extends EventTarget {
|
|
739
|
+
addEventListener(...args) {
|
|
740
|
+
return super.addEventListener.apply(this, args);
|
|
741
|
+
}
|
|
742
|
+
removeEventListener(...args) {
|
|
743
|
+
return super.removeEventListener.apply(this, args);
|
|
744
|
+
}
|
|
745
|
+
options;
|
|
746
|
+
fixedSlots = new Map();
|
|
747
|
+
dataList = [];
|
|
748
|
+
mixedData = [];
|
|
749
|
+
lastMixedSlotIdx = -1;
|
|
750
|
+
prevDataLength = 0;
|
|
751
|
+
isBatching = false;
|
|
752
|
+
constructor(options){
|
|
753
|
+
super();
|
|
754
|
+
const validOptions = dataHandler(options || {}, data_mixed_manager_validInfo, {
|
|
755
|
+
unwrap: true
|
|
756
|
+
});
|
|
757
|
+
const { fixedSlots, dataList, listener } = validOptions;
|
|
758
|
+
this.options = validOptions;
|
|
759
|
+
this.addFixedSlots(fixedSlots, {
|
|
760
|
+
lazy: true
|
|
761
|
+
});
|
|
762
|
+
this.appendList(dataList);
|
|
763
|
+
try {
|
|
764
|
+
this.initListener(listener);
|
|
765
|
+
} catch (error) {
|
|
766
|
+
throwError('dataMixedManager', error.message, error.constructor);
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
initListener(listener) {
|
|
770
|
+
const listenerNames = Object.keys(listener);
|
|
771
|
+
for(let i = 0, name = listenerNames[i], handler = listener[name]; i < listenerNames.length; name = listenerNames[++i], handler = listener[name])this.addEventListener(name, handler);
|
|
772
|
+
}
|
|
773
|
+
getTypeText(_type) {
|
|
774
|
+
switch(_type){
|
|
775
|
+
case SLOT_TYPE.fixed:
|
|
776
|
+
return 'fixed';
|
|
777
|
+
case SLOT_TYPE.insert:
|
|
778
|
+
return 'insert';
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
buildSlotConfig(config, type) {
|
|
782
|
+
const typeText = this.getTypeText(config.type || type);
|
|
783
|
+
return {
|
|
784
|
+
...config,
|
|
785
|
+
type: typeText,
|
|
786
|
+
inputPosition: config.position,
|
|
787
|
+
insertMode: config.insertMode || 'cover'
|
|
788
|
+
};
|
|
789
|
+
}
|
|
790
|
+
addFixedSlot(config, buildOptions) {
|
|
791
|
+
const realConfig = this.reorderFixedSlots(this.buildSlotConfig(config, SLOT_TYPE.fixed));
|
|
792
|
+
this.fixedSlots.set(realConfig.position, realConfig);
|
|
793
|
+
this.buildMixedData(buildOptions);
|
|
794
|
+
return realConfig.position;
|
|
795
|
+
}
|
|
796
|
+
reorderFixedSlots(config) {
|
|
797
|
+
const { position: oldPosition, insertMode } = config;
|
|
798
|
+
if (null == insertMode || 'cover' === insertMode || !this.fixedSlots.has(oldPosition)) return {
|
|
799
|
+
...config,
|
|
800
|
+
inputPosition: oldPosition
|
|
801
|
+
};
|
|
802
|
+
const position = 'after' === insertMode ? oldPosition + 1 : oldPosition;
|
|
803
|
+
for(let i = position + 1, preItem = this.fixedSlots.get(i - 1), currItem = this.fixedSlots.get(i); preItem; ++i, preItem = currItem, currItem = this.fixedSlots.get(i)){
|
|
804
|
+
preItem.position = i;
|
|
805
|
+
this.fixedSlots.set(i, preItem);
|
|
806
|
+
}
|
|
807
|
+
return {
|
|
808
|
+
...config,
|
|
809
|
+
position,
|
|
810
|
+
inputPosition: oldPosition
|
|
811
|
+
};
|
|
812
|
+
}
|
|
813
|
+
addFixedSlots(configs, buildOptions) {
|
|
814
|
+
if (!configs.length) return [];
|
|
815
|
+
const positions = this.batchUpdate(()=>configs.map((config)=>this.addFixedSlot(config)));
|
|
816
|
+
this.buildMixedData(buildOptions);
|
|
817
|
+
return positions;
|
|
818
|
+
}
|
|
819
|
+
deleteFixedSlot(position, buildOptions) {
|
|
820
|
+
this.fixedSlots.delete(position);
|
|
821
|
+
this.buildMixedData(buildOptions);
|
|
822
|
+
}
|
|
823
|
+
deleteFixedSlots(positions, buildOptions) {
|
|
824
|
+
if (!positions.length) return;
|
|
825
|
+
this.batchUpdate(()=>positions.forEach((position)=>void this.deleteFixedSlot(position)));
|
|
826
|
+
this.buildMixedData(buildOptions);
|
|
827
|
+
}
|
|
828
|
+
batchUpdate(callback) {
|
|
829
|
+
try {
|
|
830
|
+
this.isBatching = true;
|
|
831
|
+
const result = callback();
|
|
832
|
+
return result;
|
|
833
|
+
} finally{
|
|
834
|
+
this.isBatching = false;
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
clearFixedSlots(buildOptions) {
|
|
838
|
+
this.fixedSlots.clear();
|
|
839
|
+
this.buildMixedData(buildOptions);
|
|
840
|
+
}
|
|
841
|
+
appendList(list, buildOptions) {
|
|
842
|
+
if (!list.length) return;
|
|
843
|
+
this.dataList.push(...list);
|
|
844
|
+
this.buildMixedData({
|
|
845
|
+
...buildOptions,
|
|
846
|
+
lazy: true === (buildOptions || {}).lazy
|
|
847
|
+
});
|
|
848
|
+
}
|
|
849
|
+
clearList() {
|
|
850
|
+
this.dataList.length = 0;
|
|
851
|
+
this.mixedData.length = 0;
|
|
852
|
+
this.dispatch('change', {
|
|
853
|
+
mode: 'clear',
|
|
854
|
+
mixedData: this.getMixedData({
|
|
855
|
+
mode: 'rebuild'
|
|
856
|
+
})
|
|
857
|
+
});
|
|
858
|
+
this.dispatch('clear');
|
|
859
|
+
}
|
|
860
|
+
getMixedData(buildOptions) {
|
|
861
|
+
this.buildMixedData({
|
|
862
|
+
...buildOptions,
|
|
863
|
+
lazy: false
|
|
864
|
+
});
|
|
865
|
+
return this.mixedData.slice();
|
|
866
|
+
}
|
|
867
|
+
dispatch(name, data) {
|
|
868
|
+
const detail = {
|
|
869
|
+
name: this.options.name,
|
|
870
|
+
...data
|
|
871
|
+
};
|
|
872
|
+
this.dispatchEvent(new CustomEvent(name, {
|
|
873
|
+
detail
|
|
874
|
+
}));
|
|
875
|
+
if ("u" > typeof window) window.dispatchEvent(new CustomEvent(`[DMM]:${name}`, {
|
|
876
|
+
detail
|
|
877
|
+
}));
|
|
878
|
+
}
|
|
879
|
+
buildMixedData(buildOptions) {
|
|
880
|
+
if (this.isBatching) return;
|
|
881
|
+
const { lazy, mode } = buildOptions || {};
|
|
882
|
+
if ('rebuild' === mode) {
|
|
883
|
+
this.prevDataLength = 0;
|
|
884
|
+
this.lastMixedSlotIdx = -1;
|
|
885
|
+
}
|
|
886
|
+
if (false !== lazy || this.dataList.length <= this.prevDataLength) return;
|
|
887
|
+
let dataStartIdx = this.prevDataLength;
|
|
888
|
+
const dataEndIdx = this.dataList.length;
|
|
889
|
+
const newItemCount = dataEndIdx - dataStartIdx;
|
|
890
|
+
this.prevDataLength = dataEndIdx;
|
|
891
|
+
const isPatchMode = dataStartIdx > 0;
|
|
892
|
+
const filteredSlots = this.sliceSlots(isPatchMode ? this.mixedData.length : this.lastMixedSlotIdx, this.mixedData.length + newItemCount);
|
|
893
|
+
this.lastMixedSlotIdx = filteredSlots.at(-1) ?? this.lastMixedSlotIdx;
|
|
894
|
+
let mixedStartIdx = isPatchMode ? this.mixedData.length : 0;
|
|
895
|
+
this.mixedData.length = (isPatchMode ? newItemCount + mixedStartIdx : dataEndIdx) + filteredSlots.length;
|
|
896
|
+
for(let fpIdx = 0, fpItem = filteredSlots[fpIdx]; dataStartIdx < dataEndIdx; ++mixedStartIdx)if (mixedStartIdx === fpItem) {
|
|
897
|
+
const fixedSlot = this.fixedSlots.get(fpItem);
|
|
898
|
+
this.mixedData[mixedStartIdx] = {
|
|
899
|
+
isFixed: true,
|
|
900
|
+
type: fixedSlot.type,
|
|
901
|
+
data: fixedSlot.data
|
|
902
|
+
};
|
|
903
|
+
fpItem = filteredSlots[++fpIdx];
|
|
904
|
+
} else {
|
|
905
|
+
this.mixedData[mixedStartIdx] = {
|
|
906
|
+
isFixed: false,
|
|
907
|
+
type: 'plain',
|
|
908
|
+
data: this.dataList[dataStartIdx]
|
|
909
|
+
};
|
|
910
|
+
++dataStartIdx;
|
|
911
|
+
}
|
|
912
|
+
this.dispatch('change', {
|
|
913
|
+
mode: isPatchMode ? 'patch' : 'rebuild',
|
|
914
|
+
mixedData: this.mixedData.slice()
|
|
915
|
+
});
|
|
916
|
+
}
|
|
917
|
+
sliceSlots(startIdx, endIdx = 1 / 0) {
|
|
918
|
+
let prevItem = -2;
|
|
919
|
+
let count = 0;
|
|
920
|
+
return Array.from(this.fixedSlots.keys()).sort((ai, bi)=>ai - bi).filter((item)=>{
|
|
921
|
+
if (item >= startIdx && item < endIdx + count || item - 1 === prevItem) {
|
|
922
|
+
++count;
|
|
923
|
+
prevItem = item;
|
|
924
|
+
return true;
|
|
925
|
+
}
|
|
926
|
+
return false;
|
|
927
|
+
});
|
|
928
|
+
}
|
|
929
|
+
insertSlot(config) {
|
|
930
|
+
const realPosition = this.addFixedSlot({
|
|
931
|
+
...config,
|
|
932
|
+
type: SLOT_TYPE.insert
|
|
933
|
+
});
|
|
934
|
+
if (realPosition > this.mixedData.length) return realPosition;
|
|
935
|
+
this.buildMixedData({
|
|
936
|
+
lazy: false,
|
|
937
|
+
mode: 'rebuild'
|
|
938
|
+
});
|
|
939
|
+
return realPosition;
|
|
940
|
+
}
|
|
941
|
+
insertSlots(configs) {
|
|
942
|
+
if (!configs.length) return [];
|
|
943
|
+
const positions = this.batchUpdate(()=>configs.map((config)=>this.insertSlot(config)));
|
|
944
|
+
this.buildMixedData({
|
|
945
|
+
lazy: false,
|
|
946
|
+
mode: 'rebuild'
|
|
947
|
+
});
|
|
948
|
+
return positions;
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
function dataMixedManager(options) {
|
|
952
|
+
return new DataMixedManager(options);
|
|
953
|
+
}
|
|
954
|
+
Symbol('__PACK__');
|
|
955
|
+
export { $dt, $t, createError, dataHandler, defineTransform, getType, identity, noop, throwError, throwType } from "../707.js";
|
|
956
|
+
export { createStorageHandler } from "../247.js";
|
|
957
|
+
export { allx, animation, conditionMerge, createApi, createApiWithMap, dataMixedManager, defineApi, defineApiMap, isArray, isBoolean, isEmptyArray, isEmptyString, isFalse, isFalsy, isFunction, isNull, isNullOrUndef, isNumber, isObject, isPlainNumber, isPlainObject, isPlainSymbol, isPromiseLike, isPropertyKey, isString, isSymbol, isTrue, isTruthy, isUndef, request, stepAnimation, tryCall, tryCallFunc, verify_isNaN as isNaN, withResolvers };
|