@yongdall/common 0.1.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/index.mjs ADDED
@@ -0,0 +1,1158 @@
1
+ //#region \0rolldown/runtime.js
2
+ var __defProp = Object.defineProperty;
3
+ var __exportAll = (all, no_symbols) => {
4
+ let target = {};
5
+ for (var name in all) {
6
+ __defProp(target, name, {
7
+ get: all[name],
8
+ enumerable: true
9
+ });
10
+ }
11
+ if (!no_symbols) {
12
+ __defProp(target, Symbol.toStringTag, { value: "Module" });
13
+ }
14
+ return target;
15
+ };
16
+
17
+ //#endregion
18
+ //#region packages/common/Search/util.mjs
19
+ /**
20
+ * @template T
21
+ * @template TReturn
22
+ * @template TNext
23
+ * @param {Generator<T, TReturn, TNext>} generator
24
+ * @param {(value: T) => TNext} run
25
+ * @param {TNext} def
26
+ */
27
+ function runGenerator(generator, run, def) {
28
+ /** @type {TNext} */
29
+ let value = def;
30
+ for (;;) {
31
+ const result = generator.next(value);
32
+ if (result.done) return result.value;
33
+ value = run(result.value);
34
+ }
35
+ }
36
+ /**
37
+ * @template T
38
+ * @template TReturn
39
+ * @template TNext
40
+ * @param {Generator<T, TReturn, TNext>} generator
41
+ * @param {(value: T) => PromiseLike<TNext> | TNext} run
42
+ * @param {TNext} def
43
+ */
44
+ async function asyncRunGenerator(generator, run, def) {
45
+ /** @type {TNext} */
46
+ let value = def;
47
+ for (;;) {
48
+ const result = generator.next(value);
49
+ if (result.done) return result.value;
50
+ value = await run(result.value);
51
+ }
52
+ }
53
+
54
+ //#endregion
55
+ //#region packages/common/Search/exec.mjs
56
+ /** @import { Children, Field, Match, Or } from './types.mjs' */
57
+ /**
58
+ *
59
+ * @param {Record<string, any>[]} data
60
+ * @param {Field[]} fields
61
+ * @returns {any[]}
62
+ */
63
+ function select(data, fields) {
64
+ let list = data;
65
+ for (let item of fields) {
66
+ const [field, ...sub] = typeof item === "string" ? [item] : item;
67
+ if (!list.length) continue;
68
+ /** @type {any[]} */
69
+ const subList = [];
70
+ it: for (const item of list) {
71
+ if (!item || typeof item !== "object") continue;
72
+ if (!Object.hasOwn(item, field)) continue;
73
+ let value = item[field];
74
+ for (const index of sub) {
75
+ if (!Array.isArray(value)) continue it;
76
+ value = value[index];
77
+ }
78
+ subList.push(value);
79
+ }
80
+ list = subList.flat(Infinity).filter((v) => v && typeof v === "object");
81
+ }
82
+ return list;
83
+ }
84
+ /**
85
+ *
86
+ * @param {Record<string, any>[]} list
87
+ * @param {string} field
88
+ * @returns {any[]}
89
+ */
90
+ function selectValue(list, field) {
91
+ /** @type {any[]} */
92
+ const subList = [];
93
+ for (const item of list) {
94
+ if (!item || typeof item !== "object") continue;
95
+ if (!Object.hasOwn(item, field)) continue;
96
+ subList.push(item[field]);
97
+ }
98
+ return subList;
99
+ }
100
+ /**
101
+ * @typedef {object} ExecParam
102
+ * @property {string[]} fields
103
+ * @property {string} operator
104
+ * @property {string?} [sign]
105
+ * @property {any} value
106
+ * @property {any[]} values
107
+ */
108
+ /**
109
+ *
110
+ * @param {Record<string, any>[]} data
111
+ * @param {string[]} parentFields
112
+ * @param {Match} match
113
+ * @returns {Generator<ExecParam, boolean?, boolean?>}
114
+ */
115
+ function* execMatch(data, parentFields, match) {
116
+ const fields = [...match[0]];
117
+ const currentFields = [...parentFields, ...fields.map((v) => typeof v === "string" ? v : v[0])];
118
+ const last = fields.pop();
119
+ if (!last) return null;
120
+ const lastField = typeof last === "string" ? last : last[0];
121
+ const records = select(data, fields);
122
+ if (!records.length) return false;
123
+ const [, value, operator, sign] = match;
124
+ if (operator === null) {
125
+ const values = selectValue(records, lastField);
126
+ return sign ? values.find((v) => v === null) : values.find((v) => v !== null);
127
+ }
128
+ if (typeof value !== "object" || !value || Array.isArray(value)) {
129
+ const values = selectValue(records, lastField);
130
+ if (!values.length) return false;
131
+ return yield {
132
+ fields: currentFields,
133
+ operator,
134
+ sign,
135
+ value,
136
+ values
137
+ };
138
+ }
139
+ if (value.filter || value.table || value.placeholder) return null;
140
+ const field = value.field;
141
+ if (!field) return null;
142
+ /** @type {boolean?} */
143
+ let defResult = false;
144
+ for (const item of records) {
145
+ if (!item || typeof item !== "object") continue;
146
+ if (!Object.hasOwn(item, field)) continue;
147
+ if (!Object.hasOwn(item, lastField)) continue;
148
+ defResult = null;
149
+ const result = yield {
150
+ fields: currentFields,
151
+ operator,
152
+ sign,
153
+ value: item[field],
154
+ values: [item[lastField]]
155
+ };
156
+ if (result === null) continue;
157
+ return result;
158
+ }
159
+ return defResult;
160
+ }
161
+ /**
162
+ *
163
+ * @param {Record<string, any>[]} data
164
+ * @param {string[]} parentFields
165
+ * @param {Match | Children | Or} match
166
+ * @returns {Generator<ExecParam, boolean?, boolean?>}
167
+ */
168
+ function* execItem(data, parentFields, match) {
169
+ if (!Array.isArray(match)) {
170
+ const { and, or } = match;
171
+ return yield* execOr(data, parentFields, and, or);
172
+ }
173
+ if (match.length !== 2) return yield* execMatch(data, parentFields, match);
174
+ /** @type {boolean?} */
175
+ let defResult = null;
176
+ const values = select(data, match[0]);
177
+ if (!values.length) return false;
178
+ const fields = [...parentFields, ...match[0].map((v) => typeof v === "string" ? v : v[0])];
179
+ for (const item of match[1]) {
180
+ const result = yield* execItem(values, fields, item);
181
+ if (result === null) continue;
182
+ if (!result) return false;
183
+ defResult = true;
184
+ }
185
+ return defResult;
186
+ }
187
+ /**
188
+ *
189
+ * @param {Record<string, any>[]} list
190
+ * @param {string[]} parentFields
191
+ * @param {(Match | Children)[]} [and]
192
+ * @param {(Match | Children | Or)[]} [or]
193
+ * @returns {Generator<ExecParam, boolean?, boolean?>}
194
+ */
195
+ function* execOr(list, parentFields, and, or) {
196
+ /** @type {boolean?} */
197
+ let defResult = null;
198
+ if (Array.isArray(and)) for (const item of and) {
199
+ const result = yield* execItem(list, parentFields, item);
200
+ if (result === null) continue;
201
+ if (!result) return false;
202
+ defResult = true;
203
+ }
204
+ if (Array.isArray(or)) for (const item of or) {
205
+ const result = yield* execItem(list, parentFields, item);
206
+ if (result === null) continue;
207
+ if (result) return true;
208
+ defResult = true;
209
+ }
210
+ return defResult;
211
+ }
212
+ /**
213
+ *
214
+ * @param {Record<string, any>} data
215
+ * @param {(value: ExecParam) => boolean?} exec
216
+ * @param {(Match | Children)[]} [and]
217
+ * @param {(Match | Children | Or)[]} [or]
218
+ */
219
+ function exec(data, exec, and, or) {
220
+ return runGenerator(execOr([data].flat(), [], and, or), exec, null);
221
+ }
222
+ /**
223
+ *
224
+ * @param {Record<string, any>} data
225
+ * @param {(value: ExecParam) => PromiseLike<boolean?> | boolean?} exec
226
+ * @param {(Match | Children)[]} [and]
227
+ * @param {(Match | Children | Or)[]} [or]
228
+ */
229
+ async function asyncExec(data, exec, and, or) {
230
+ return asyncRunGenerator(execOr([data].flat(), [], and, or), exec, null);
231
+ }
232
+
233
+ //#endregion
234
+ //#region packages/common/Search/fill.mjs
235
+ /** @import { Value } from './types.mjs' */
236
+ /** @import { Children, Field, FieldValue, Match, Or } from './types.mjs' */
237
+ /**
238
+ *
239
+ * @template {Match | Children | Or} T
240
+ * @param {T[]} match
241
+ * @returns {Generator<Value | (() => Value), T[]?, Value | (() => string | null) | null>}
242
+ */
243
+ function* fillList(match) {
244
+ /** @type {T[]} */
245
+ let list = [];
246
+ let has = false;
247
+ for (const child of match) {
248
+ const val = yield* fillMatch(child);
249
+ list.push(val || child);
250
+ if (val) has = true;
251
+ }
252
+ return has ? list : null;
253
+ }
254
+ /**
255
+ *
256
+ * @template {Match | Children | Or} T
257
+ * @param {T} match
258
+ * @returns {Generator<Value | (() => Value), T?, Value | (() => string | null) | null>}
259
+ */
260
+ function* fillMatch(match) {
261
+ if (!Array.isArray(match)) {
262
+ const and = match.and && (yield* fillMatches(match.and));
263
+ const or = match.or && (yield* fillMatches(match.or));
264
+ if (!and && !or) return null;
265
+ return {
266
+ and: and || match.and,
267
+ or: or || match.or
268
+ };
269
+ }
270
+ if (match.length === 2) {
271
+ if (!(yield* fillMatches(match[1]))) return null;
272
+ return [match[0], match[1]];
273
+ }
274
+ const value = yield match[1];
275
+ if (value === null) return null;
276
+ return [
277
+ match[0],
278
+ value,
279
+ match[2],
280
+ match[3]
281
+ ];
282
+ }
283
+ /**
284
+ *
285
+ * @template {Match | Children | Or} T
286
+ * @param {T[]} match
287
+ * @returns {Generator<Value | (() => Value), T[]?, Value | (() => string | null) | null>}
288
+ */
289
+ function* fillMatches(match) {
290
+ /** @type {T[]} */
291
+ const list = [];
292
+ let has = false;
293
+ for (const child of match) {
294
+ const val = yield* fillMatch(child);
295
+ list.push(val || child);
296
+ if (val) has = true;
297
+ }
298
+ return has ? list : null;
299
+ }
300
+ /**
301
+ *
302
+ * @template {Match | Children | Or} T
303
+ * @param {T[] | null | undefined} match
304
+ * @param {(placeholder: string) => string | (() => string | null) | null} getPlaceholder
305
+ * @returns {T[]}
306
+ */
307
+ function fill(match, getPlaceholder) {
308
+ if (!match) return [];
309
+ /**
310
+ *
311
+ * @template {Value | (() => Value)} T
312
+ * @param {T} match
313
+ * @returns {Value | (() => string | null) | null}
314
+ */
315
+ function fillValue(match) {
316
+ if (!match || typeof match !== "object") return null;
317
+ if (Array.isArray(match)) return null;
318
+ const placeholder = match.placeholder;
319
+ if (!placeholder || typeof placeholder !== "string") return null;
320
+ return getPlaceholder(placeholder);
321
+ }
322
+ return runGenerator(fillList(match), fillValue, null) || match;
323
+ }
324
+
325
+ //#endregion
326
+ //#region packages/common/Search/parse.mjs
327
+ /** @import { RecursiveArray } from '../types/types.mjs' */
328
+ /** @import { Children, Field, Match, Or, Param, Value } from './types.mjs' */
329
+ /**
330
+ * @typedef {object} Parse.Field
331
+ * @property {string} field
332
+ * @property {string?} [group]
333
+ * @property {number[]} sub
334
+ */
335
+ /**
336
+ * @typedef {object} Parse.Match
337
+ * @property {null} [children]
338
+ * @property {Parse.Field[]} fields
339
+ * @property {string?} operator
340
+ * @property {string} [sign]
341
+ * @property {Value} value
342
+ */
343
+ /**
344
+ * @typedef {object} Parse.Children
345
+ * @property {Parse.Field[]} fields
346
+ * @property {(Parse.Match | Parse.Children)[]} children
347
+ */
348
+ /**
349
+ *
350
+ * @param {Parse.Field[]} fields
351
+ * @returns {Field[]}
352
+ */
353
+ function compressFields(fields) {
354
+ return fields.map(({ field, sub }) => sub.length ? [field, ...sub] : field);
355
+ }
356
+ /**
357
+ *
358
+ * @param {Parse.Match | Parse.Children} v
359
+ * @returns {Match | Children}
360
+ */
361
+ function compressAndItem(v) {
362
+ if (v.children) return [compressFields(v.fields), v.children.map(compressAndItem)];
363
+ const { fields, operator, value, sign } = v;
364
+ return [
365
+ compressFields(fields),
366
+ value,
367
+ operator,
368
+ sign
369
+ ];
370
+ }
371
+ const fieldParserRegex = /^([-_\d\p{L}]+)((?:\[-?\d+\])*)$/u;
372
+ /**
373
+ *
374
+ * @param {string} l
375
+ */
376
+ function parseFields(l) {
377
+ /** @type {Parse.Field[]} */
378
+ const fields = [];
379
+ for (const v of l.split(".")) {
380
+ if (!v || v[0] === "?") return null;
381
+ const index = v.indexOf("?");
382
+ const r = fieldParserRegex.exec(index > 0 ? v.slice(0, index) : v);
383
+ if (!r) return null;
384
+ const sub = r[2]?.split(/\[|\]/).filter(Boolean).map((v) => parseInt(v) || 0) || [];
385
+ const group = index > 0 ? v.slice(index) : void 0;
386
+ fields.push({
387
+ field: r[1],
388
+ group,
389
+ sub
390
+ });
391
+ }
392
+ return fields;
393
+ }
394
+ /** @param {string} v */
395
+ const decodeValue = (v) => decodeURIComponent(v.replaceAll("+", " "));
396
+ /**
397
+ *
398
+ * @param {string} s
399
+ * @returns {string | RecursiveArray<string>?}
400
+ */
401
+ function parseArrayValue(s) {
402
+ /** @type {(string | RecursiveArray<string>)[]} */
403
+ const root = [];
404
+ /** @type {(string | RecursiveArray<string>)[][]} */
405
+ const stack = [];
406
+ let current = root;
407
+ /** @type {string[]} */
408
+ let strings = [];
409
+ let end = false;
410
+ let must = true;
411
+ function add() {
412
+ current.push(decodeValue(strings.join()));
413
+ strings = [];
414
+ }
415
+ for (const c of s) {
416
+ if (c === ",") {
417
+ if (end) end = false;
418
+ else add();
419
+ must = true;
420
+ continue;
421
+ }
422
+ if (c === ")") {
423
+ if (must || strings.length) {
424
+ add();
425
+ must = false;
426
+ }
427
+ const last = stack.pop();
428
+ if (!last) return null;
429
+ last.push(current);
430
+ current = last;
431
+ end = true;
432
+ continue;
433
+ }
434
+ if (end) return null;
435
+ must = false;
436
+ if (c !== "(") {
437
+ strings.push(c);
438
+ continue;
439
+ }
440
+ if (strings.length) return null;
441
+ stack.push(current);
442
+ current = [];
443
+ }
444
+ if (must || strings.length) add();
445
+ if (stack.length) return null;
446
+ return root.length === 1 ? root[0] : root;
447
+ }
448
+ const valueQRegex = /^([-_\d\p{L}]+)@([-_\d\p{L}]+)/u;
449
+ /**
450
+ *
451
+ * @param {string?} v
452
+ * @returns {Value | true}
453
+ */
454
+ function parseValue(v) {
455
+ if (v === null) return true;
456
+ if (v[0] === "?") return { placeholder: decodeValue(v.slice(1)) };
457
+ if (v[0] === ":") return { field: decodeValue(v.slice(1)) };
458
+ if (v[0] === "@") return null;
459
+ if (valueQRegex.test(v)) return null;
460
+ if (v.includes("(") || v.includes(")")) {
461
+ const list = parseArrayValue(v);
462
+ if (list) return list;
463
+ }
464
+ if (v.includes(",")) return v.split(",").map((v) => decodeValue(v.replaceAll("+", " ")));
465
+ return decodeValue(v);
466
+ }
467
+ /**
468
+ *
469
+ * @param {(Parse.Match | Parse.Children)[]} list
470
+ * @returns {Iterable<Match | Children>}
471
+ */
472
+ function* toAnd(list) {
473
+ /** @type {[(Parse.Match | Parse.Children), Parse.Field[], Parse.Field[]][]} */
474
+ const values = list.map((v) => {
475
+ const fields = v.fields;
476
+ const index = fields.findLastIndex((v) => v.group);
477
+ if (index < 0 || index >= fields.length - 1) return [
478
+ v,
479
+ [],
480
+ []
481
+ ];
482
+ const field = fields[index];
483
+ if (!field) return [
484
+ v,
485
+ [],
486
+ []
487
+ ];
488
+ return [
489
+ {
490
+ ...v,
491
+ fields: fields.slice(index + 1)
492
+ },
493
+ fields.slice(0, index + 1),
494
+ [...fields.slice(0, index), {
495
+ ...field,
496
+ group: void 0
497
+ }]
498
+ ];
499
+ });
500
+ const map = Object.groupBy(values, (v) => JSON.stringify(v[1]));
501
+ yield* map["[]"]?.map((v) => compressAndItem(v[0])) || [];
502
+ delete map["[]"];
503
+ /** @type {Parse.Children[]} */
504
+ const result = Object.values(map).filter(Boolean).map((list = []) => {
505
+ if (!list?.length) return {
506
+ fields: [],
507
+ children: []
508
+ };
509
+ return {
510
+ fields: list[0][2] || [],
511
+ children: list.map((v) => v[0])
512
+ };
513
+ }).filter((v) => v.fields.length);
514
+ if (!result.length) return;
515
+ yield* toAnd(result);
516
+ }
517
+ /**
518
+ *
519
+ * @param {(Parse.Match & {groups: string[]})[]} list
520
+ * @returns {Or}
521
+ */
522
+ function toOr(list) {
523
+ const map = Map.groupBy(list, (v) => v.groups.shift() ?? null);
524
+ const and = map.get(null) || [];
525
+ const baseOr = map.get("") || [];
526
+ map.delete(null);
527
+ map.delete("");
528
+ return {
529
+ or: [...baseOr.map((v) => compressAndItem(v)), ...[...map.values()].map((v) => toOr(v))],
530
+ and: [...toAnd(and)]
531
+ };
532
+ }
533
+ /**
534
+ *
535
+ * @param {string} search
536
+ * @returns {Param}
537
+ */
538
+ function parse(search, split = "&") {
539
+ /** @type {string[]} */
540
+ const values = [];
541
+ /** @type {string[]} */
542
+ const select = [];
543
+ /** @type {[field: string, desc?: boolean][]} */
544
+ const sorts = [];
545
+ let limit = 0;
546
+ let offset = 0;
547
+ let page = 0;
548
+ /** @type {Record<string, string>} */
549
+ const placeholders = {};
550
+ /** @type {(Parse.Match & {groups: string[]})[]} */
551
+ const allMatches = [];
552
+ for (const s of search.split(split)) {
553
+ if (s[0] === "=") {
554
+ values.push(s.slice(1));
555
+ continue;
556
+ }
557
+ const index = s.indexOf("=");
558
+ const key = index < 0 ? s : s.slice(0, index);
559
+ const val = index < 0 ? null : s.slice(index + 1);
560
+ if (index <= 0) continue;
561
+ if (`.!@^*<>{}[]()+|;,"'\`\\/`.includes(key[0])) continue;
562
+ if (key[0] === "?") {
563
+ placeholders[decodeValue(key.slice(1))] = decodeValue(val || "");
564
+ continue;
565
+ }
566
+ if (key[0] === ":") {
567
+ const name = key.slice(1);
568
+ if (!val) continue;
569
+ if (name === "sort") sorts.push(...val.split(",").filter(Boolean).map((v) => {
570
+ const desc = v[0] === "-";
571
+ return [decodeValue(desc ? v.slice(1) : v), desc];
572
+ }).filter(Boolean));
573
+ else if (name === "select") select.push(...val.split(",").map(decodeValue).filter(Boolean));
574
+ else if (name === "limit") {
575
+ if (val && /^\d+$/.test(val)) limit = parseInt(val);
576
+ } else if (name === "offset") {
577
+ if (val && /^\d+$/.test(val)) offset = parseInt(val);
578
+ } else if (name === "page") {
579
+ if (val && /^\d+$/.test(val)) page = parseInt(val);
580
+ }
581
+ continue;
582
+ }
583
+ const sg = key.split("~");
584
+ let field = sg.pop() || "";
585
+ let sign = "";
586
+ if ("!".includes(field[field.length - 1])) {
587
+ sign = "!";
588
+ field = field.slice(0, -1);
589
+ }
590
+ const l = field.split(":", 3);
591
+ if (l.length > 2) continue;
592
+ const fields = parseFields(l[0]);
593
+ if (!fields) continue;
594
+ const value = parseValue(val);
595
+ if (value === null) continue;
596
+ const operator = decodeValue(l[1] || "");
597
+ const groupIndex = sg.indexOf("");
598
+ const groups = groupIndex < 0 ? sg : sg.slice(0, groupIndex + 1);
599
+ allMatches.push({
600
+ groups,
601
+ fields,
602
+ operator: !operator && value === true ? null : operator,
603
+ sign,
604
+ value: value === true ? null : value
605
+ });
606
+ }
607
+ const { and, or } = toOr(allMatches);
608
+ /** @type {Param} */
609
+ const result = {};
610
+ if (values?.length) result.values = values;
611
+ if (limit && limit > 0) result.limit = limit;
612
+ if (page && page > 0) result.page = page;
613
+ if (offset && offset > 0) result.offset = offset;
614
+ if (select?.length) result.select = select;
615
+ if (sorts?.length) result.sort = sorts;
616
+ const where = and;
617
+ if (where?.length) result.where = where;
618
+ const orWhere = or;
619
+ if (orWhere?.length) result.orWhere = orWhere;
620
+ if (Array.isArray(placeholders) && placeholders.length) result.placeholders = placeholders;
621
+ return result;
622
+ }
623
+
624
+ //#endregion
625
+ //#region packages/common/Search/merge.mjs
626
+ /** @import { Param } from './types.mjs' */
627
+ /**
628
+ *
629
+ * @param {Partial<Param>} a
630
+ * @param {Partial<Param>} b
631
+ * @returns {Param}
632
+ */
633
+ function merge(a, b) {
634
+ const limit = b.limit || a.limit || 10;
635
+ const page = b.page ?? a.page;
636
+ const offset = b.offset ?? (b.limit && (b.page || b.page === 0) ? (Math.floor(Math.max(b.page || 0, 1)) - 1) * b.limit : null) ?? a.offset ?? (a.limit && (a.page || a.page === 0) ? (Math.floor(Math.max(a.page || 0, 1)) - 1) * a.limit : null) ?? (Math.floor(Math.max(page || 0, 1)) - 1) * limit;
637
+ const values = [...a.values || [], ...b.values || []];
638
+ const sort = [...a.sort || [], ...b.sort || []];
639
+ const select = [...a.select || [], ...b.select || []];
640
+ const where = [...a.where || [], ...b.where || []];
641
+ const orWhere = [...a.orWhere || [], ...b.orWhere || []];
642
+ const or = [...a.or || [], ...b.or || []];
643
+ /** @type {Param} */
644
+ const result = {};
645
+ if (values?.length) result.values = values;
646
+ if (limit && limit > 0) result.limit = limit;
647
+ if (page && page > 0) result.page = page;
648
+ if (offset && offset > 0) result.offset = offset;
649
+ if (select?.length) result.select = select;
650
+ if (sort?.length) result.sort = sort;
651
+ if (where?.length) result.where = where;
652
+ if (orWhere?.length) result.orWhere = orWhere;
653
+ if (or?.length) result.or = or;
654
+ return result;
655
+ }
656
+
657
+ //#endregion
658
+ //#region packages/common/Search/stringify.mjs
659
+ /** @import { RecursiveArray } from '../types/types.mjs' */
660
+ /** @import { Children, Field, FieldValue, Match, Or, Param } from './types.mjs' */
661
+ /** @param {string} v */
662
+ const encodeValue = (v) => encodeURIComponent(v).replaceAll("%20", "+");
663
+ /**
664
+ *
665
+ * @param {string | RecursiveArray<string> | FieldValue} value
666
+ */
667
+ function stringifyValue(value) {
668
+ if (Array.isArray(value)) {
669
+ /**
670
+ *
671
+ * @param {string | RecursiveArray<string>} v
672
+ * @returns {string}
673
+ */
674
+ function s(v) {
675
+ if (Array.isArray(v)) return `(${v.map(s).join(",")})`;
676
+ return encodeValue(v);
677
+ }
678
+ const val = value.map(s).join(",");
679
+ if (value.length > 1) return val;
680
+ return `(${val})`;
681
+ }
682
+ if (typeof value !== "object") return encodeValue(value);
683
+ const { field, placeholder } = value;
684
+ if (placeholder) return `?${encodeValue(placeholder)}`;
685
+ if (field) return `:${encodeValue(field)}`;
686
+ return "";
687
+ }
688
+ /**
689
+ *
690
+ * @param {Field[]} fields
691
+ */
692
+ function stringifyFields(fields) {
693
+ return fields.map((item) => {
694
+ const [field, ...sub] = typeof item === "string" ? [item] : item;
695
+ return `${encodeValue(field)}${sub.map(() => `[k]`).join("")}`;
696
+ }).join(".");
697
+ }
698
+ /**
699
+ *
700
+ * @param {Match} define
701
+ */
702
+ function stringifyDefine([fields, value, operator, sign]) {
703
+ const key = operator ? `${stringifyFields(fields)}:${encodeValue(operator)}${sign || ""}` : `${stringifyFields(fields)}${sign || ""}`;
704
+ if (operator === null) return key;
705
+ if (value === null) return "";
706
+ if (typeof value === "function") return "";
707
+ return `${key}=${stringifyValue(value)}`;
708
+ }
709
+ /**
710
+ *
711
+ * @param {(Match | Children)[]} list
712
+ * @returns {string[]}
713
+ */
714
+ function stringifyAnd(list) {
715
+ let index = 0;
716
+ return list.flatMap((v) => {
717
+ if (v.length !== 2) return stringifyDefine(v);
718
+ const list = stringifyAnd(v[1]);
719
+ if (!list.length) return [];
720
+ let key = stringifyFields(v[0]);
721
+ if (list.length > 1) key += `?${(index++).toString(36)}`;
722
+ return list.map((v) => `${key}.${v}`);
723
+ }).filter(Boolean);
724
+ }
725
+ /**
726
+ *
727
+ * @param {(Match | Children | Or)[]} list
728
+ * @returns {string[]}
729
+ */
730
+ function stringifyOr(list) {
731
+ let index = 0;
732
+ return list.map((v) => {
733
+ if (Array.isArray(v)) return stringifyAnd([v]);
734
+ return [...stringifyAnd(v.and || []), ...stringifyOr(v.or || [])];
735
+ }).flatMap((list) => {
736
+ if (!list) return [];
737
+ const key = list.length === 1 ? `~` : `${(index++).toString(36)}~`;
738
+ return list.map((v) => `${key}${v}`);
739
+ });
740
+ }
741
+ /**
742
+ *
743
+ * @param {Partial<Param>} query
744
+ * @param {boolean} [usePage]
745
+ */
746
+ function stringify({ values, where, orWhere, sort, select, limit, offset, page, placeholders }, usePage) {
747
+ /** @type {string[]} */
748
+ let queries = [];
749
+ for (const v of values || []) {
750
+ if (!v) continue;
751
+ queries.push(`=${encodeValue(v)}`);
752
+ }
753
+ if (limit && limit > 0) queries.push(`:limit=${limit}`);
754
+ if (usePage) {
755
+ if (page && page > 0) queries.push(`:page=${page}`);
756
+ } else if (offset && offset > 0) queries.push(`:offset=${offset}`);
757
+ if (select) {
758
+ const val = select.filter(Boolean).map(encodeValue).join(",");
759
+ if (val) queries.push(`.select=${val}`);
760
+ }
761
+ if (sort) {
762
+ const val = sort.filter(Boolean).map((v) => {
763
+ if (Array.isArray(v)) {
764
+ const [field, desc] = v;
765
+ if (field) return `${desc ? "-" : ""}${encodeValue(field)}`;
766
+ } else if (v) return encodeValue(v);
767
+ return "";
768
+ }).filter(Boolean).join(",");
769
+ if (val) queries.push(`.sort=${val}`);
770
+ }
771
+ if (placeholders && typeof placeholders === "object" && !Array.isArray(placeholders)) for (const [k, v] of Object.entries(placeholders)) queries.push(`?${encodeValue(k)}=${encodeValue(v)}`);
772
+ for (const v of stringifyAnd(where || [])) queries.push(v);
773
+ for (const v of stringifyOr(orWhere || [])) queries.push(v);
774
+ return queries.join("&");
775
+ }
776
+
777
+ //#endregion
778
+ //#region packages/common/Search/index.mjs
779
+ var Search_exports = /* @__PURE__ */ __exportAll({
780
+ asyncExec: () => asyncExec,
781
+ asyncRunGenerator: () => asyncRunGenerator,
782
+ exec: () => exec,
783
+ fill: () => fill,
784
+ fillMatches: () => fillMatches,
785
+ merge: () => merge,
786
+ parse: () => parse,
787
+ runGenerator: () => runGenerator,
788
+ stringify: () => stringify
789
+ });
790
+
791
+ //#endregion
792
+ //#region packages/common/Hook.mjs
793
+ /**
794
+ * @template T
795
+ * @typedef {T | readonly T[]} Hook.MaybeArray
796
+ */
797
+ /**
798
+ * @template T
799
+ * @typedef {T extends readonly any[] ? Readonly<T>
800
+ * : T extends Record<string, any> ? Hook.MaybeArray<Hook.Define<T> | T>
801
+ * : T extends object ? Hook.MaybeArray<Hook.Define<T> | T>
802
+ * : Hook.MaybeArray<T>
803
+ * } Hook.Item
804
+ */
805
+ /**
806
+ * @template T
807
+ * @typedef {T extends Record<string, any> ? { [k in keyof T]?: Hook.Item<T[k]> } : T} Hook.Define
808
+ */
809
+ /** @type {*} */
810
+ const noopFilter = () => true;
811
+ /**
812
+ *
813
+ * @param {Record<string, any>} plugin
814
+ * @param {string[]} name
815
+ * @returns {*[]}
816
+ */
817
+ function findHook(plugin, name) {
818
+ let list = [plugin].flat();
819
+ for (const k of name.filter(Boolean)) {
820
+ const values = [];
821
+ for (const it of list) {
822
+ if (!it || typeof it !== "object") continue;
823
+ if (!Object.hasOwn(it, k)) continue;
824
+ values.push(it[k]);
825
+ }
826
+ if (!values.length) return [];
827
+ list = values.flat();
828
+ }
829
+ return list;
830
+ }
831
+ /**
832
+ *
833
+ * @template T
834
+ * @param {any} plugin
835
+ * @param {string[]} names
836
+ * @returns {T | void}
837
+ */
838
+ function first(plugin, names) {
839
+ if (!names.length) return plugin;
840
+ if (!plugin || typeof plugin !== "object") return;
841
+ const [name, ...keys] = names;
842
+ for (const v of [plugin].flat()) {
843
+ const val = first(v[name], keys);
844
+ if (val !== void 0) return val;
845
+ }
846
+ }
847
+ /**
848
+ *
849
+ * @template T
850
+ * @param {Record<string, any>} hooks
851
+ * @param {string[]} name
852
+ * @returns {IterableIterator<T>}
853
+ */
854
+ function* values(hooks, name) {
855
+ for (const it of Object.values(hooks)) for (const value of findHook(it, name)) yield value;
856
+ }
857
+ /**
858
+ * @template T
859
+ */
860
+ var Hook = class Hook {
861
+ /**
862
+ * @template {object} T
863
+ * @param {Record<string, Hook.Define<T>> | (() => Record<string, Hook.Define<T>>)} [options]
864
+ * @return {Hook<T>}
865
+ */
866
+ static build(options) {
867
+ const hook = new Hook();
868
+ return Hook.update(hook, options);
869
+ }
870
+ /**
871
+ *
872
+ * @template T
873
+ * @param {Hook<T>} hook
874
+ * @param {Record<string, Hook.Define<T>> | (() => Record<string, Hook.Define<T>>)} [options]
875
+ */
876
+ static update(hook, options) {
877
+ let updated = false;
878
+ if (typeof options === "function") {
879
+ Object.defineProperty(hook.#config, "hooks", {
880
+ configurable: true,
881
+ get() {
882
+ const r = options();
883
+ return typeof r === "object" && r || {};
884
+ }
885
+ });
886
+ updated = true;
887
+ } else if (options && typeof options === "object") {
888
+ Object.defineProperty(hook.#config, "hooks", {
889
+ configurable: true,
890
+ value: options
891
+ });
892
+ updated = true;
893
+ }
894
+ if (updated) Hook.reset(hook);
895
+ return hook;
896
+ }
897
+ /**
898
+ *
899
+ * @template T
900
+ * @param {Hook<T>} hook
901
+ */
902
+ static reset(hook) {
903
+ const hooks = hook.#hooks;
904
+ const resetFn = hook.#config.resetFn;
905
+ resetFn.sort(([, a], [, b]) => a - b);
906
+ const before = resetFn.filter(([, p]) => p <= 0);
907
+ const after = resetFn.filter(([, p]) => p > 0);
908
+ for (const [fn] of before) fn();
909
+ for (const fn of values(hooks, ["reset"])) {
910
+ if (typeof fn !== "function") continue;
911
+ fn();
912
+ }
913
+ for (const [fn] of after) fn();
914
+ }
915
+ /** @type {{hooks: any; resetFn: [fn: () => void, hysteresis: number][]}} */
916
+ #config = {
917
+ hooks: Object.create(null),
918
+ resetFn: []
919
+ };
920
+ /** @type {string[]} */
921
+ #keys = [];
922
+ #stringTag = "Hook";
923
+ [Symbol.iterator]() {
924
+ return this.entries();
925
+ }
926
+ [Symbol.toStringTag]() {
927
+ return this.#stringTag;
928
+ }
929
+ /** @param {string} hint */
930
+ [Symbol.toPrimitive](hint) {
931
+ if (hint === "number") return NaN;
932
+ return `[${this[Symbol.toStringTag]()}]`;
933
+ }
934
+ get #hooks() {
935
+ return this.#config.hooks;
936
+ }
937
+ /**
938
+ * @template {T extends readonly any[] ? never : T extends object ? string & keyof T : never} K
939
+ * @param {K} key
940
+ * @returns {Hook<Exclude<T extends readonly any[] ? never : T extends object ? T[K] :never, void | undefined>>}
941
+ */
942
+ get(key) {
943
+ const keys = [...this.#keys, key];
944
+ const hook = new Hook();
945
+ hook.#config = this.#config;
946
+ hook.#keys = keys;
947
+ hook.#stringTag = `Hook(${keys.join(".")})`;
948
+ return hook;
949
+ }
950
+ /**
951
+ * @param {T extends (...args: infer A) => any ? A : []} args
952
+ * @returns
953
+ */
954
+ call(...args) {
955
+ for (const fn of this.values()) {
956
+ if (typeof fn !== "function") continue;
957
+ fn(...args);
958
+ }
959
+ }
960
+ /**
961
+ *
962
+ * @param {string} plugin
963
+ * @returns {T | void}
964
+ */
965
+ first(plugin) {
966
+ const hooks = this.#hooks;
967
+ if (!Object.hasOwn(hooks, plugin)) return;
968
+ return first(hooks[plugin], this.#keys.filter(Boolean));
969
+ }
970
+ /**
971
+ *
972
+ * @param {string} plugin
973
+ * @returns {IterableIterator<T extends readonly (infer V)[] ? V : T>}
974
+ */
975
+ *plugin(plugin) {
976
+ const hooks = this.#hooks;
977
+ if (!Object.hasOwn(hooks, plugin)) return;
978
+ yield* findHook(hooks[plugin], this.#keys.filter(Boolean));
979
+ }
980
+ /**
981
+ *
982
+ * @returns {IterableIterator<T extends readonly (infer V)[] ? V : T>}
983
+ */
984
+ values() {
985
+ return values(this.#hooks, this.#keys);
986
+ }
987
+ /**
988
+ *
989
+ * @returns {IterableIterator<[string, T extends readonly (infer V)[] ? V : T]>}
990
+ */
991
+ *entries() {
992
+ const hooks = this.#hooks;
993
+ const name = this.#keys;
994
+ for (const [plugin, it] of Object.entries(hooks)) for (const value of findHook(it, name)) yield [plugin, value];
995
+ }
996
+ /**
997
+ *
998
+ * @template [TX=(T extends Record<string, infer TT>? TT extends readonly (infer V)[] ? V : TT : never)]
999
+ * @param {(v: *)=>v is TX} filter
1000
+ * @returns {IterableIterator<[plugin: string, key: string, value: TX]>}
1001
+ */
1002
+ *entriesObject(filter = noopFilter) {
1003
+ for (const [plugin, hooksMap] of this.entries()) {
1004
+ if (!hooksMap || typeof hooksMap !== "object") continue;
1005
+ for (const [k, v] of Object.entries(hooksMap)) {
1006
+ if (!filter(v)) continue;
1007
+ yield [
1008
+ plugin,
1009
+ k,
1010
+ v
1011
+ ];
1012
+ }
1013
+ }
1014
+ }
1015
+ /**
1016
+ * @template [TT=(T extends Record<string, infer TT> ? TT : never)]
1017
+ * @param {(v: *)=>v is TT} [filter]
1018
+ * @returns {Record<string, TT>}
1019
+ */
1020
+ named(filter = noopFilter) {
1021
+ /** @type {Record<string, TT>} */
1022
+ const result = Object.create(null);
1023
+ for (const hooksMap of this.values()) {
1024
+ if (!hooksMap || typeof hooksMap !== "object") continue;
1025
+ for (const [k, v] of Object.entries(hooksMap)) {
1026
+ if (!filter(v)) continue;
1027
+ result[k] = v;
1028
+ }
1029
+ }
1030
+ return result;
1031
+ }
1032
+ /**
1033
+ *
1034
+ * @param {() => void} fn
1035
+ * @param {number} [hysteresis]
1036
+ * @returns
1037
+ */
1038
+ listen(fn, hysteresis) {
1039
+ if (typeof fn !== "function") return () => {};
1040
+ const resetFn = this.#config.resetFn;
1041
+ /** @type {[() => void, number]} */
1042
+ const it = [fn, Number.isFinite(hysteresis) && hysteresis || 0];
1043
+ resetFn.push(it);
1044
+ resetFn.sort(([, a], [, b]) => b - a);
1045
+ return () => {
1046
+ const index = resetFn.findIndex((v) => v === it);
1047
+ if (index >= 0) resetFn.splice(index, 1);
1048
+ };
1049
+ }
1050
+ };
1051
+
1052
+ //#endregion
1053
+ //#region packages/common/model.mjs
1054
+ const regex = /\{([^}{}]+)\}/g;
1055
+ /**
1056
+ *
1057
+ * @param {string?} [pattern]
1058
+ */
1059
+ function getPatternFields(pattern) {
1060
+ if (!pattern || typeof pattern !== "string") return [];
1061
+ /** @type {string[]} */
1062
+ const fields = [];
1063
+ for (let result = regex.exec(pattern); result; result = regex.exec(pattern)) fields.push(result[1]);
1064
+ return fields;
1065
+ }
1066
+ /**
1067
+ *
1068
+ * @param {string?} [pattern]
1069
+ * @param {Record<string, any>?} [document]
1070
+ * @returns
1071
+ */
1072
+ function runPattern(pattern, document) {
1073
+ if (!pattern || typeof pattern !== "string") return "";
1074
+ const doc = typeof document === "object" && document || {};
1075
+ return pattern.replace(regex, (_, v) => {
1076
+ if (Object.hasOwn(doc, v)) return doc[v] ?? "";
1077
+ return `{${v}}`;
1078
+ });
1079
+ }
1080
+
1081
+ //#endregion
1082
+ //#region packages/common/yieldPermissionConstraintFields.mjs
1083
+ /** @import { Permission } from '@yongdall/types' */
1084
+ /**
1085
+ *
1086
+ * @param {Permission} permission
1087
+ * @returns {Iterable<string>}
1088
+ */
1089
+ function* yieldPermissionConstraintFields({ constraints, organizationField }) {
1090
+ if (organizationField) yield organizationField;
1091
+ if (!constraints) return;
1092
+ for (const [field, constraint] of Object.entries(constraints)) {
1093
+ if (!constraint) continue;
1094
+ const { value, values, user } = constraint;
1095
+ if (value !== void 0) yield field;
1096
+ else if (Array.isArray(values) && values.length) yield field;
1097
+ else if (values instanceof Set && values.size) yield field;
1098
+ else if (user) yield field;
1099
+ }
1100
+ }
1101
+
1102
+ //#endregion
1103
+ //#region packages/common/index.mjs
1104
+ const pluginIdRegex = /^(?:(?<scope>@[a-zA-Z\d_.-]+)\/)?(?<name>[a-zA-Z\d_.-]+)$/;
1105
+ const findPluginIdRegex = /^(?<pluginId>(?:(?<scope>@[a-zA-Z\d_.-]+)\/)?(?<name>[a-zA-Z\d_.-]+))(?:\/(?<path>[^#]*))?(?:#(?<hash>.*))?$/;
1106
+ /**
1107
+ * @typedef {object} Plugin
1108
+ * @property {string} [version]
1109
+ * @property {Record<string, string>} [assets]
1110
+ * @property {string} [hooks]
1111
+ * @property {string[]} [styles]
1112
+ */
1113
+ /**
1114
+ * @typedef {object} BootConfiguration
1115
+ * @property {string} [route] 路由管理器
1116
+ * @property {string} [theme] 界面主题
1117
+ * @property {string} [authenticator] 登陆器
1118
+ * @property {boolean} [authRequired] 是否强制登陆
1119
+ * @property {string} [skin]
1120
+ * @property {boolean} [single]
1121
+ * @property {string} [application]
1122
+ * @property {string} [domain]
1123
+ * @property {string | number} [port]
1124
+ * @property {string} [path]
1125
+ * @property {Record<string, string>} [pages]
1126
+ * @property {Record<string, string>} [configurationPages]
1127
+ *
1128
+ *
1129
+ * @property {string} [logo]
1130
+ * @property {string} [title]
1131
+ * @property {string} [company]
1132
+ * @property {string} [type]
1133
+ * @property {string} [help] 帮助链接
1134
+ * @property {any[]} [userMenus]
1135
+ */
1136
+ /**
1137
+ * @typedef {object} Importmap
1138
+ * @property {Record<string, string>} imports
1139
+ * @property {Record<string, Record<string, string>>} scopes
1140
+ */
1141
+ /**
1142
+ * @typedef {object} Indicator
1143
+ * @property {string} color
1144
+ * @property {string} label
1145
+ * @property {unknown} [filters]
1146
+ */
1147
+ /**
1148
+ *
1149
+ * @param {*} v
1150
+ * @returns {v is (...p: any[]) => any}
1151
+ */
1152
+ function isFunction(v) {
1153
+ return typeof v === "function";
1154
+ }
1155
+
1156
+ //#endregion
1157
+ export { Hook, Search_exports as Search, findPluginIdRegex, getPatternFields, isFunction, pluginIdRegex, runPattern, yieldPermissionConstraintFields };
1158
+ //# sourceMappingURL=index.mjs.map