hanzi-chai 0.3.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.
Files changed (52) hide show
  1. package/dist/affine.d.ts +8 -0
  2. package/dist/affine.js +153 -0
  3. package/dist/assembly.d.ts +63 -0
  4. package/dist/assembly.js +286 -0
  5. package/dist/bezier.d.ts +74 -0
  6. package/dist/bezier.js +140 -0
  7. package/dist/classifier.d.ts +109 -0
  8. package/dist/classifier.js +108 -0
  9. package/dist/component.d.ts +115 -0
  10. package/dist/component.js +278 -0
  11. package/dist/compound.d.ts +64 -0
  12. package/dist/compound.js +652 -0
  13. package/dist/config.d.ts +236 -0
  14. package/dist/config.js +48 -0
  15. package/dist/data/cjk.txt +20902 -0
  16. package/dist/data/data/cjk.txt +20902 -0
  17. package/dist/data/data/dictionary.txt +69429 -0
  18. package/dist/data/data/frequency.txt +263137 -0
  19. package/dist/data/data/key_distribution.txt +46 -0
  20. package/dist/data/data/pair_equivalence.txt +2116 -0
  21. package/dist/data/data/repertoire.json.deflate +0 -0
  22. package/dist/data/data/tygf.txt +8105 -0
  23. package/dist/data/dictionary.txt +69429 -0
  24. package/dist/data/frequency.txt +263137 -0
  25. package/dist/data/key_distribution.txt +46 -0
  26. package/dist/data/pair_equivalence.txt +2116 -0
  27. package/dist/data/repertoire.json.deflate +0 -0
  28. package/dist/data/tygf.txt +8105 -0
  29. package/dist/data.d.ts +195 -0
  30. package/dist/data.js +18 -0
  31. package/dist/degenerator.d.ts +21 -0
  32. package/dist/degenerator.js +134 -0
  33. package/dist/element.d.ts +56 -0
  34. package/dist/element.js +225 -0
  35. package/dist/equivalence.d.ts +21 -0
  36. package/dist/equivalence.js +74 -0
  37. package/dist/index.d.ts +45 -0
  38. package/dist/index.js +126 -0
  39. package/dist/index.mjs +3553 -0
  40. package/dist/mathjs.d.ts +10 -0
  41. package/dist/mathjs.js +9 -0
  42. package/dist/repertoire.d.ts +75 -0
  43. package/dist/repertoire.js +406 -0
  44. package/dist/selector.d.ts +110 -0
  45. package/dist/selector.js +310 -0
  46. package/dist/topology.d.ts +41 -0
  47. package/dist/topology.js +209 -0
  48. package/dist/transformer.d.ts +18 -0
  49. package/dist/transformer.js +111 -0
  50. package/dist/utils.d.ts +107 -0
  51. package/dist/utils.js +546 -0
  52. package/package.json +34 -0
package/dist/index.mjs ADDED
@@ -0,0 +1,3553 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
+ var __publicField = (obj, key, value) => {
4
+ __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
5
+ return value;
6
+ };
7
+
8
+ // src/mathjs.ts
9
+ var add = (a, b) => [a[0] + b[0], a[1] + b[1]];
10
+ var subtract = (a, b) => [a[0] - b[0], a[1] - b[1]];
11
+ var multiply = (a, b) => [a * b[0], a * b[1]];
12
+ var divide = (a, b) => [a[0] / b, a[1] / b];
13
+ var dot = (a, b) => a[0] * b[0] + a[1] * b[1];
14
+ var mean = (a) => (a[0] + a[1]) / 2;
15
+ var distance = (a, b) => Math.sqrt((a[0] - b[0]) ** 2 + (a[1] - b[1]) ** 2);
16
+
17
+ // src/affine.ts
18
+ import { cloneDeep } from "lodash-es";
19
+ var Affine = class {
20
+ constructor(xscale, yscale, translate = [0, 0]) {
21
+ __publicField(this, "xscale");
22
+ __publicField(this, "yscale");
23
+ __publicField(this, "translate");
24
+ this.xscale = xscale;
25
+ this.yscale = yscale;
26
+ this.translate = translate;
27
+ }
28
+ transformDraw(draw) {
29
+ const next = cloneDeep(draw);
30
+ switch (next.command) {
31
+ case "h":
32
+ next.parameterList[0] *= this.xscale;
33
+ break;
34
+ case "v":
35
+ next.parameterList[0] *= this.yscale;
36
+ break;
37
+ case "c":
38
+ case "z":
39
+ for (const index of [0, 2, 4]) {
40
+ next.parameterList[index] *= this.xscale;
41
+ next.parameterList[index + 1] *= this.yscale;
42
+ }
43
+ break;
44
+ }
45
+ return next;
46
+ }
47
+ transformSVGStroke(stroke) {
48
+ const [x, y] = stroke.start;
49
+ const start = add(
50
+ [x * this.xscale, y * this.yscale],
51
+ this.translate
52
+ );
53
+ const next = {
54
+ ...stroke,
55
+ start,
56
+ curveList: stroke.curveList.map((c) => this.transformDraw(c))
57
+ };
58
+ return next;
59
+ }
60
+ transformSVGGlyph(glyph) {
61
+ return glyph.map((x) => this.transformSVGStroke(x));
62
+ }
63
+ };
64
+ var id = new Affine(1, 1);
65
+ var left = new Affine(0.5, 1);
66
+ var right = new Affine(0.5, 1, [50, 0]);
67
+ var top = new Affine(1, 0.5);
68
+ var bottom = new Affine(1, 0.5, [0, 50]);
69
+ var leftThird = new Affine(0.33, 1);
70
+ var centerThird = new Affine(0.33, 1, [33, 0]);
71
+ var rightThird = new Affine(0.33, 1, [66, 0]);
72
+ var topThird = new Affine(1, 0.33);
73
+ var middleThird = new Affine(1, 0.33, [0, 33]);
74
+ var bottomThird = new Affine(1, 0.33, [0, 66]);
75
+ var affineMap = {
76
+ "\u2FF0": [left, right],
77
+ "\u2FF1": [top, bottom],
78
+ "\u2FF2": [leftThird, centerThird, rightThird],
79
+ "\u2FF3": [topThird, middleThird, bottomThird],
80
+ "\u2FF4": [id, new Affine(0.5, 0.5, [25, 25])],
81
+ "\u2FF5": [id, new Affine(0.5, 0.5, [25, 40])],
82
+ "\u2FF6": [id, new Affine(0.5, 0.5, [25, 10])],
83
+ "\u2FF7": [id, new Affine(0.5, 0.5, [40, 25])],
84
+ "\u2FF8": [id, new Affine(0.5, 0.5, [40, 40])],
85
+ "\u2FF9": [id, new Affine(0.5, 0.5, [10, 40])],
86
+ "\u2FFA": [id, new Affine(0.5, 0.5, [40, 10])],
87
+ "\u2FFC": [id, new Affine(0.5, 0.5, [10, 25])],
88
+ "\u2FFD": [id, new Affine(0.5, 0.5, [10, 10])],
89
+ "\u2FFB": [id, id],
90
+ "\u2FFE": [id],
91
+ "\u2FFF": [id]
92
+ };
93
+ function affineMerge(compound, glyphList) {
94
+ const { operator, order: order3, parameters } = compound;
95
+ const transformedGlyphs = [];
96
+ const boundingBox = { x: [0, 100], y: [0, 100] };
97
+ if (["\u2FF0", "\u2FF2", "\u2FF1", "\u2FF3"].includes(operator)) {
98
+ let mainAxisOffset = 0;
99
+ const isLR = ["\u2FF0", "\u2FF2"].includes(operator);
100
+ for (const [index, { strokes, box }] of glyphList.entries()) {
101
+ const mainAxisLength = isLR ? box.x[1] - box.x[0] : box.y[1] - box.y[0];
102
+ if (index === 0) {
103
+ transformedGlyphs.push(structuredClone(strokes));
104
+ boundingBox.x = structuredClone(box.x);
105
+ boundingBox.y = structuredClone(box.y);
106
+ mainAxisOffset = isLR ? box.x[1] : box.y[1];
107
+ continue;
108
+ }
109
+ let gap = 20;
110
+ if (index === 1 && parameters?.gap2 !== void 0) {
111
+ gap = parameters.gap2;
112
+ } else if (index === 2 && parameters?.gap3 !== void 0) {
113
+ gap = parameters.gap3;
114
+ }
115
+ mainAxisOffset += gap;
116
+ const increase = gap + mainAxisLength;
117
+ let affine;
118
+ if (isLR) {
119
+ affine = new Affine(1, 1, [mainAxisOffset - box.x[0], 0]);
120
+ boundingBox.x[1] += increase;
121
+ boundingBox.y[0] = Math.min(boundingBox.y[0], box.y[0]);
122
+ boundingBox.y[1] = Math.max(boundingBox.y[1], box.y[1]);
123
+ } else {
124
+ affine = new Affine(1, 1, [0, mainAxisOffset - box.y[0]]);
125
+ boundingBox.y[1] += increase;
126
+ boundingBox.x[0] = Math.min(boundingBox.x[0], box.x[0]);
127
+ boundingBox.x[1] = Math.max(boundingBox.x[1], box.x[1]);
128
+ }
129
+ transformedGlyphs.push(affine.transformSVGGlyph(strokes));
130
+ mainAxisOffset += mainAxisLength;
131
+ }
132
+ } else {
133
+ for (const [index, affine] of affineMap[operator].entries()) {
134
+ const transformed = affine.transformSVGGlyph(glyphList[index].strokes);
135
+ transformedGlyphs.push(transformed);
136
+ }
137
+ }
138
+ const result = [];
139
+ if (order3 === void 0) {
140
+ result.push(...transformedGlyphs.flat());
141
+ } else {
142
+ for (const { index, strokes } of order3) {
143
+ const glyph = transformedGlyphs[index];
144
+ if (glyph === void 0)
145
+ continue;
146
+ if (strokes === 0) {
147
+ result.push(...glyph);
148
+ } else {
149
+ result.push(...glyph.slice(0, strokes));
150
+ transformedGlyphs[index] = glyph.slice(strokes);
151
+ }
152
+ }
153
+ }
154
+ const merged = {
155
+ strokes: result,
156
+ box: boundingBox
157
+ };
158
+ return merged;
159
+ }
160
+
161
+ // src/element.ts
162
+ var pronunciationElementTypes = [
163
+ "\u58F0\u6BCD",
164
+ "\u53CC\u62FC\u58F0\u6BCD",
165
+ "\u97F5\u6BCD",
166
+ "\u53CC\u62FC\u97F5\u6BCD",
167
+ "\u58F0\u8C03",
168
+ "\u9996\u5B57\u6BCD",
169
+ "\u672B\u5B57\u6BCD"
170
+ ];
171
+ var r = String.raw;
172
+ var defaultAlgebra = {
173
+ \u58F0\u6BCD: [
174
+ { type: "xform", from: "^([bpmfdtnlgkhjqxzcsr]h?|^).+$", to: "$1" },
175
+ { type: "xform", from: "^$", to: "0" }
176
+ ],
177
+ \u97F5\u6BCD: [
178
+ // 恢复 v
179
+ { type: "xform", from: "^([jqxy])u", to: "$1v" },
180
+ // 恢复合、齐、撮口的韵母形式
181
+ { type: "xform", from: "yv", to: "v" },
182
+ { type: "xform", from: "yi?", to: "i" },
183
+ { type: "xform", from: "wu?", to: "u" },
184
+ // 恢复 iou, uei, uen
185
+ { type: "xform", from: "iu", to: "iou" },
186
+ { type: "xform", from: "u([in])", to: "ue$1" },
187
+ { type: "xform", from: r`^.*?([aeêiouv].*|m|ng?)\d$`, to: "$1" }
188
+ ],
189
+ \u53CC\u62FC\u58F0\u6BCD: [
190
+ { type: "xform", from: "^([bpmfdtnlgkhjqxzcsryw]h?|^).+$", to: "$1" },
191
+ { type: "xform", from: "^$", to: "0" }
192
+ ],
193
+ \u53CC\u62FC\u97F5\u6BCD: [{ type: "xform", from: r`^.*?([aeêiouv].*|m|ng?)\d$`, to: "$1" }],
194
+ \u58F0\u8C03: [{ type: "xform", from: r`.+(\d)`, to: "$1" }],
195
+ \u9996\u5B57\u6BCD: [{ type: "xform", from: r`^(.).+`, to: "$1" }],
196
+ \u672B\u5B57\u6BCD: [{ type: "xform", from: r`.*(.)\d`, to: "$1" }]
197
+ };
198
+ var applyRules = (name, rules, syllable) => {
199
+ let result = syllable;
200
+ for (const { type, from, to } of rules) {
201
+ switch (type) {
202
+ case "xform":
203
+ result = result.replace(new RegExp(from), to);
204
+ break;
205
+ case "xlit":
206
+ result = result.replace(new RegExp(`[${from}]`), (s) => {
207
+ const index = from.indexOf(s);
208
+ return to[index] || "";
209
+ });
210
+ break;
211
+ }
212
+ }
213
+ return `${name}-${result}`;
214
+ };
215
+ var renderName = (object) => {
216
+ switch (object.type) {
217
+ case "\u6C49\u5B57":
218
+ case "\u7ED3\u6784":
219
+ return object.type;
220
+ case "\u56FA\u5B9A":
221
+ return object.key;
222
+ case "\u5B57\u97F3":
223
+ return object.subtype;
224
+ case "\u5B57\u6839":
225
+ return `\u6839 ${object.rootIndex}`;
226
+ case "\u7B14\u753B":
227
+ return `\u6839 ${object.rootIndex} \u7B14 ${object.strokeIndex}`;
228
+ case "\u4E8C\u7B14":
229
+ return `\u6839 ${object.rootIndex} \u7B14 (${object.strokeIndex * 2 - Math.sign(object.strokeIndex)}, ${object.strokeIndex * 2})`;
230
+ case "\u81EA\u5B9A\u4E49":
231
+ return `${object.subtype} ${object.rootIndex}`;
232
+ case "\u7279\u6B8A":
233
+ return object.subtype;
234
+ }
235
+ };
236
+ var renderList = (object) => {
237
+ const list = [object.type];
238
+ switch (object.type) {
239
+ case "\u56FA\u5B9A":
240
+ return [...list, object.key];
241
+ case "\u5B57\u97F3":
242
+ return [...list, object.subtype];
243
+ case "\u5B57\u6839":
244
+ return [...list, object.rootIndex];
245
+ case "\u7B14\u753B":
246
+ return [...list, object.rootIndex, object.strokeIndex];
247
+ case "\u4E8C\u7B14":
248
+ return [...list, object.rootIndex, object.strokeIndex];
249
+ case "\u81EA\u5B9A\u4E49":
250
+ return [...list, object.subtype, object.rootIndex];
251
+ case "\u7279\u6B8A":
252
+ return [...list, object.subtype];
253
+ }
254
+ return list;
255
+ };
256
+ var parseList = (value) => {
257
+ const type = value[0];
258
+ switch (type) {
259
+ case "\u56FA\u5B9A":
260
+ return { type, key: value[1] };
261
+ case "\u5B57\u97F3":
262
+ return { type, subtype: value[1] };
263
+ case "\u5B57\u6839":
264
+ return { type, rootIndex: value[1] };
265
+ case "\u7B14\u753B":
266
+ return {
267
+ type,
268
+ rootIndex: value[1],
269
+ strokeIndex: value[2]
270
+ };
271
+ case "\u4E8C\u7B14":
272
+ return {
273
+ type,
274
+ rootIndex: value[1],
275
+ strokeIndex: value[2]
276
+ };
277
+ case "\u81EA\u5B9A\u4E49":
278
+ return {
279
+ type,
280
+ subtype: value[1],
281
+ rootIndex: value[2]
282
+ };
283
+ case "\u7279\u6B8A":
284
+ return { type, subtype: value[1] };
285
+ }
286
+ return { type };
287
+ };
288
+ function signedIndex(a, i) {
289
+ return i >= 0 ? a[i - 1] : a[a.length + i];
290
+ }
291
+ var algebraCache = /* @__PURE__ */ new Map();
292
+ var zhangmaSupplement = (result, { rootSequence }) => {
293
+ const coalesce = (n) => {
294
+ if (n === 6)
295
+ return 2;
296
+ if (n === 7)
297
+ return 5;
298
+ return n;
299
+ };
300
+ const { sequence } = result;
301
+ const first2 = rootSequence.get(sequence[0]);
302
+ const last = rootSequence.get(sequence[sequence.length - 1]);
303
+ const firstfirst = coalesce(first2[0]);
304
+ const lastlast = coalesce(last.at(-1));
305
+ if (sequence.length === 1 && first2.length === 1) {
306
+ return "61";
307
+ }
308
+ return result.operator && /[⿰⿲⿺]/.test(result.operator) ? `${firstfirst}${lastlast}` : `${lastlast}${firstfirst}`;
309
+ };
310
+ var zhangmaPseudoRoot = (result) => {
311
+ if (!("best" in result))
312
+ return "0";
313
+ const { best } = result;
314
+ return best.scheme.length === 2 && best.evaluation.get("\u80FD\u8FDE\u4E0D\u4EA4") ? "1" : "0";
315
+ };
316
+ var specialElementHandlers = {
317
+ \u5F20\u7801\u8865\u7801: zhangmaSupplement,
318
+ \u5F20\u7801\u51C6\u7801\u5143: zhangmaPseudoRoot
319
+ };
320
+ var findElement = (object, result, algebra, extra) => {
321
+ const { pinyin, sequence } = result;
322
+ let root;
323
+ let strokes;
324
+ let name;
325
+ let hash;
326
+ let rules;
327
+ let transformed;
328
+ let stroke1;
329
+ let stroke2;
330
+ switch (object.type) {
331
+ case "\u6C49\u5B57":
332
+ return result.char;
333
+ case "\u56FA\u5B9A":
334
+ return object.key;
335
+ case "\u7ED3\u6784":
336
+ if ("operator" in result) {
337
+ return result.operator;
338
+ }
339
+ return void 0;
340
+ case "\u5B57\u97F3":
341
+ name = object.subtype;
342
+ hash = `${name}:${pinyin}`;
343
+ if (algebraCache.has(hash))
344
+ return algebraCache.get(hash);
345
+ rules = defaultAlgebra[name] || algebra?.[name];
346
+ transformed = applyRules(name, rules, pinyin);
347
+ algebraCache.set(hash, transformed);
348
+ return transformed;
349
+ case "\u5B57\u6839":
350
+ return signedIndex(sequence, object.rootIndex);
351
+ case "\u7B14\u753B":
352
+ case "\u4E8C\u7B14":
353
+ root = signedIndex(sequence, object.rootIndex);
354
+ if (root === void 0)
355
+ return void 0;
356
+ strokes = extra.rootSequence.get(root);
357
+ if (strokes === void 0) {
358
+ if (Math.abs(object.strokeIndex) === 1)
359
+ return root;
360
+ return void 0;
361
+ }
362
+ if (object.type === "\u7B14\u753B") {
363
+ const number = signedIndex(strokes, object.strokeIndex);
364
+ return number?.toString();
365
+ }
366
+ stroke1 = signedIndex(
367
+ strokes,
368
+ object.strokeIndex * 2 - Math.sign(object.strokeIndex)
369
+ );
370
+ if (stroke1 === void 0)
371
+ return void 0;
372
+ stroke2 = signedIndex(strokes, object.strokeIndex * 2);
373
+ return [stroke1, stroke2 ?? 0].join("");
374
+ case "\u81EA\u5B9A\u4E49":
375
+ return signedIndex(result.custom[object.subtype] ?? [], object.rootIndex);
376
+ case "\u7279\u6B8A":
377
+ return specialElementHandlers[object.subtype]?.(result, extra);
378
+ }
379
+ };
380
+
381
+ // src/bezier.ts
382
+ var sortTwoNumbers = (ar) => ar.sort((a, b) => a - b);
383
+ var getBoundingBox = (a) => [a.controls[0], a.controls[a.controls.length - 1]];
384
+ var getIntervalOnOrientation = (a) => {
385
+ const start = a.controls[0];
386
+ const end = a.controls.at(-1);
387
+ const i1 = sortTwoNumbers([start[0], end[0]]);
388
+ const i2 = sortTwoNumbers([start[1], end[1]]);
389
+ if (a.orientation === "horizontal") {
390
+ return [i1, i2];
391
+ }
392
+ return [i2, i1];
393
+ };
394
+ var evaluate = (a, t) => {
395
+ if (a.type === "linear") {
396
+ return add(
397
+ multiply(1 - t, a.controls[0]),
398
+ multiply(t, a.controls[1])
399
+ );
400
+ }
401
+ if (a.type === "arc") {
402
+ return [0, 0];
403
+ }
404
+ const v01 = add(
405
+ multiply((1 - t) ** 3, a.controls[0]),
406
+ multiply(3 * (1 - t) ** 2 * t, a.controls[1])
407
+ );
408
+ const v23 = add(
409
+ multiply(3 * (1 - t) * t ** 2, a.controls[2]),
410
+ multiply(t ** 3, a.controls[3])
411
+ );
412
+ return add(v01, v23);
413
+ };
414
+ var makeCurve = (start, { command, parameterList }) => {
415
+ if (command === "a") {
416
+ return {
417
+ type: "arc",
418
+ orientation: "horizontal",
419
+ controls: [start, start]
420
+ };
421
+ }
422
+ if (command === "c" || command === "z") {
423
+ const p12 = add(start, parameterList.slice(0, 2));
424
+ const p2 = add(start, parameterList.slice(2, 4));
425
+ const p3 = add(start, parameterList.slice(4));
426
+ return {
427
+ type: "cubic",
428
+ orientation: command === "c" ? "vertical" : "horizontal",
429
+ controls: [start, p12, p2, p3]
430
+ };
431
+ }
432
+ let p1;
433
+ switch (command) {
434
+ case "h":
435
+ p1 = add(start, [parameterList[0], 0]);
436
+ break;
437
+ case "v":
438
+ p1 = add(start, [0, parameterList[0]]);
439
+ break;
440
+ }
441
+ return {
442
+ type: "linear",
443
+ orientation: command === "v" ? "vertical" : "horizontal",
444
+ controls: [start, p1]
445
+ };
446
+ };
447
+ var render = ({ feature, start, curveList }) => {
448
+ const r2 = { feature, curveList: [] };
449
+ let previousPosition = start;
450
+ for (const draw of curveList) {
451
+ const curve = makeCurve(previousPosition, draw);
452
+ previousPosition = curve.type === "linear" ? curve.controls[1] : curve.type === "arc" ? curve.controls[1] : curve.controls[3];
453
+ r2.curveList.push(curve);
454
+ }
455
+ return r2;
456
+ };
457
+ var area = (p, q) => p[0] * q[1] - p[1] * q[0];
458
+ var getIntervalPosition = (i, j) => {
459
+ const [imin, imax] = i.sort((a, b) => a - b);
460
+ const [jmin, jmax] = j.sort((a, b) => a - b);
461
+ if (imax < jmin)
462
+ return -1;
463
+ if (imin > jmax)
464
+ return 1;
465
+ if (imin < jmin && imax < jmax)
466
+ return -0.5;
467
+ if (imin > jmin && imax > jmax)
468
+ return 0.5;
469
+ return 0;
470
+ };
471
+ var findCrossPoint = (a, at, b, bt) => {
472
+ const [astart, aend] = [evaluate(a, at[0]), evaluate(a, at[1])];
473
+ const [bstart, bend] = [evaluate(b, bt[0]), evaluate(b, bt[1])];
474
+ const xposition = getIntervalPosition(
475
+ [astart[0], aend[0]],
476
+ [bstart[0], bend[0]]
477
+ );
478
+ const yposition = getIntervalPosition(
479
+ [astart[1], aend[1]],
480
+ [bstart[1], bend[1]]
481
+ );
482
+ const totallyDisjoint = [-1, 1];
483
+ if (totallyDisjoint.includes(xposition) || totallyDisjoint.includes(yposition))
484
+ return void 0;
485
+ const [alength, blength] = [distance(astart, aend), distance(bstart, bend)];
486
+ const threshold = 1;
487
+ if (alength < threshold && blength < threshold)
488
+ return divide(add(add(astart, aend), add(bstart, bend)), 4);
489
+ const [atmid, btmid] = [mean(at), mean(bt)];
490
+ const a_firsthalf = [at[0], atmid];
491
+ const a_secondhalf = [atmid, at[1]];
492
+ const b_firsthalf = [bt[0], btmid];
493
+ const b_secondhalf = [btmid, bt[1]];
494
+ return findCrossPoint(a, a_firsthalf, b, b_firsthalf) || findCrossPoint(a, a_firsthalf, b, b_secondhalf) || findCrossPoint(a, a_secondhalf, b, b_firsthalf) || findCrossPoint(a, a_secondhalf, b, b_secondhalf);
495
+ };
496
+ var isCollinear = (from, to, point) => {
497
+ const [u, v] = [subtract(to, point), subtract(from, point)];
498
+ return area(u, v) === 0 && dot(u, v) < 0;
499
+ };
500
+ var curveLength = (curve) => {
501
+ const [start, end] = getBoundingBox(curve);
502
+ return distance(start, end);
503
+ };
504
+ var sort = (a) => a.sort((a2, b) => a2 - b);
505
+ var contains = (r1, r2) => {
506
+ return r1[0] <= r2[0] && r1[1] >= r2[1];
507
+ };
508
+ var _isBoundedBy = (curve, xrange, yrange) => {
509
+ const [start, end] = getBoundingBox(curve);
510
+ const thisXRange = sort([start[0], end[0]]);
511
+ const thisYRange = sort([start[1], end[1]]);
512
+ return contains(xrange, thisXRange) && contains(yrange, thisYRange);
513
+ };
514
+ var isBoundedBy = (stroke, xrange, yrange) => {
515
+ return stroke.curveList.every((x) => _isBoundedBy(x, xrange, yrange));
516
+ };
517
+
518
+ // src/topology.ts
519
+ import { isEqual, minBy } from "lodash-es";
520
+ var makeAttachRelation = (first2, second) => ({ type: "\u8FDE", first: first2, second });
521
+ var getParallelRelation = (a, b) => {
522
+ const [amain, across] = getIntervalOnOrientation(a);
523
+ const [bmain, bcross] = getIntervalOnOrientation(b);
524
+ const mainPosition = getIntervalPosition(amain, bmain);
525
+ const crossPosition = getIntervalPosition(across, bcross);
526
+ return { type: "\u5E73\u884C", mainAxis: mainPosition, crossAxis: crossPosition };
527
+ };
528
+ var getDisjointRelation = (a, b) => {
529
+ if (a.orientation === b.orientation)
530
+ return getParallelRelation(a, b);
531
+ const [astart, aend] = getBoundingBox(a);
532
+ const [bstart, bend] = getBoundingBox(b);
533
+ return {
534
+ type: "\u6563",
535
+ x: getIntervalPosition([astart[0], aend[0]], [bstart[0], bend[0]]),
536
+ y: getIntervalPosition([astart[1], aend[1]], [bstart[1], bend[1]])
537
+ };
538
+ };
539
+ var getAttachRelation = (a, b) => {
540
+ const [astart, aend] = getBoundingBox(a);
541
+ const [bstart, bend] = getBoundingBox(b);
542
+ if (isEqual(astart, bstart))
543
+ return makeAttachRelation("\u524D", "\u524D");
544
+ if (isEqual(astart, bend))
545
+ return makeAttachRelation("\u524D", "\u540E");
546
+ if (isEqual(aend, bstart))
547
+ return makeAttachRelation("\u540E", "\u524D");
548
+ if (isEqual(aend, bend))
549
+ return makeAttachRelation("\u540E", "\u540E");
550
+ if (a.type === "linear") {
551
+ if (isCollinear(astart, aend, bstart))
552
+ return makeAttachRelation("\u4E2D", "\u524D");
553
+ if (isCollinear(astart, aend, bend))
554
+ return makeAttachRelation("\u4E2D", "\u540E");
555
+ }
556
+ if (b.type === "linear") {
557
+ if (isCollinear(bstart, bend, astart))
558
+ return makeAttachRelation("\u524D", "\u4E2D");
559
+ if (isCollinear(bstart, bend, aend))
560
+ return makeAttachRelation("\u540E", "\u4E2D");
561
+ }
562
+ };
563
+ var linearRelation = (a, b) => {
564
+ const [astart, aend] = a.controls;
565
+ const [bstart, bend] = b.controls;
566
+ const [v, v1, v2] = [
567
+ subtract(aend, astart),
568
+ subtract(bstart, astart),
569
+ subtract(bend, astart)
570
+ ];
571
+ const vc = area(v, v1) * area(v, v2);
572
+ const [u, u1, u2] = [
573
+ subtract(bend, bstart),
574
+ subtract(astart, bstart),
575
+ subtract(aend, bstart)
576
+ ];
577
+ const uc = area(u, u1) * area(u, u2);
578
+ if (vc < 0 && uc < 0) {
579
+ return { type: "\u4EA4" };
580
+ }
581
+ return getDisjointRelation(a, b);
582
+ };
583
+ var genericRelation = (a, b) => {
584
+ const crossPoint = findCrossPoint(a, [0, 1], b, [0, 1]);
585
+ if (crossPoint === void 0)
586
+ return getDisjointRelation(a, b);
587
+ const [astart, aend] = getBoundingBox(a);
588
+ const [bstart, bend] = getBoundingBox(b);
589
+ const distanceThreshold = 3;
590
+ if (distance(crossPoint, astart) < distanceThreshold)
591
+ return makeAttachRelation("\u524D", "\u4E2D");
592
+ if (distance(crossPoint, aend) < distanceThreshold)
593
+ return makeAttachRelation("\u540E", "\u4E2D");
594
+ if (distance(crossPoint, bstart) < distanceThreshold)
595
+ return makeAttachRelation("\u4E2D", "\u524D");
596
+ if (distance(crossPoint, bend) < distanceThreshold)
597
+ return makeAttachRelation("\u4E2D", "\u540E");
598
+ return { type: "\u4EA4" };
599
+ };
600
+ var curveRelation = (c1, c2) => {
601
+ const relation = getAttachRelation(c1, c2);
602
+ if (relation !== void 0)
603
+ return relation;
604
+ if (c1.type === "linear" && c2.type === "linear") {
605
+ return linearRelation(c1, c2);
606
+ }
607
+ return genericRelation(c1, c2);
608
+ };
609
+ var strokeRelation = (stroke1, stroke2) => {
610
+ const strokeRelation2 = [];
611
+ for (const curve1 of stroke1.curveList) {
612
+ for (const curve2 of stroke2.curveList) {
613
+ strokeRelation2.push(curveRelation(curve1, curve2));
614
+ }
615
+ }
616
+ return strokeRelation2;
617
+ };
618
+ var renderSVGStroke = ({ feature, start, curveList }) => {
619
+ const r2 = { feature, curveList: [] };
620
+ let previousPosition = start;
621
+ for (const draw of curveList) {
622
+ const curve = makeCurve(previousPosition, draw);
623
+ previousPosition = curve.type === "linear" ? curve.controls[1] : curve.type === "arc" ? curve.controls[1] : curve.controls[3];
624
+ r2.curveList.push(curve);
625
+ }
626
+ return r2;
627
+ };
628
+ var renderSVGGlyph = (glyph) => glyph.map(renderSVGStroke);
629
+ var isConforming = (r1, r2) => {
630
+ switch (r1.type) {
631
+ case "\u5E73\u884C":
632
+ return r2.type === "\u5E73\u884C";
633
+ case "\u6563":
634
+ return true;
635
+ case "\u4EA4":
636
+ return r2.type === "\u4EA4" || r2.type === "\u8FDE" && r2.second === "\u4E2D" || r2.type === "\u6563";
637
+ case "\u8FDE":
638
+ if (r1.second === "\u4E2D") {
639
+ return r2.type === "\u4EA4" || r2.type === "\u6563" || r2.type === "\u8FDE" && r2.second === "\u4E2D";
640
+ }
641
+ return r2.type === "\u8FDE" && r2.second === r1.second || r2.type === "\u6563";
642
+ }
643
+ };
644
+ var hashPoint = (point) => `${point[0]}-${point[1]}`;
645
+ var findCorners = (renderedGlyph) => {
646
+ const extremes = [];
647
+ const pointToStroke = /* @__PURE__ */ new Map();
648
+ for (const [strokeIndex, { curveList }] of renderedGlyph.entries()) {
649
+ const subExtremes = [];
650
+ for (const [curveIndex, curve] of curveList.entries()) {
651
+ const [start, end] = getBoundingBox(curve);
652
+ if (curveIndex === 0)
653
+ subExtremes.push(start);
654
+ subExtremes.push(end);
655
+ }
656
+ for (const point of subExtremes) {
657
+ const hash = hashPoint(point);
658
+ if (!pointToStroke.has(hash))
659
+ pointToStroke.set(hash, strokeIndex);
660
+ }
661
+ extremes.push(...subExtremes);
662
+ }
663
+ const topLeft = minBy(extremes, (p) => distance(p, [0, 0]));
664
+ const topRight = minBy(extremes, (p) => distance(p, [100, 0]));
665
+ const bottomLeft = minBy(extremes, (p) => distance(p, [0, 100]));
666
+ const bottomRight = minBy(extremes, (p) => distance(p, [100, 100]));
667
+ return [topLeft, topRight, bottomLeft, bottomRight].map(
668
+ (point) => pointToStroke.get(hashPoint(point))
669
+ );
670
+ };
671
+ var findTopology = (renderedGlyph) => {
672
+ const topology = { matrix: [], orientedPairs: [] };
673
+ for (const [index1, stroke1] of renderedGlyph.entries()) {
674
+ const row = [];
675
+ for (const [index2, stroke2] of renderedGlyph.entries()) {
676
+ if (index1 === index2)
677
+ row.push([]);
678
+ else
679
+ row.push(strokeRelation(stroke1, stroke2));
680
+ }
681
+ topology.matrix.push(row);
682
+ }
683
+ for (const [index1] of renderedGlyph.entries()) {
684
+ for (const [index2] of renderedGlyph.entries()) {
685
+ if (index2 >= index1)
686
+ break;
687
+ const relations = topology.matrix[index1]?.[index2];
688
+ if (relations.some((v) => v.type === "\u4EA4" || v.type === "\u8FDE"))
689
+ continue;
690
+ const parallelIndex = relations.findIndex(
691
+ (v) => v.type === "\u5E73\u884C" && v.mainAxis === 0
692
+ );
693
+ if (parallelIndex !== -1) {
694
+ topology.orientedPairs.push([index1, index2]);
695
+ }
696
+ }
697
+ }
698
+ return topology;
699
+ };
700
+
701
+ // src/data.ts
702
+ var operators = [
703
+ "\u2FF0",
704
+ "\u2FF1",
705
+ "\u2FF2",
706
+ "\u2FF3",
707
+ "\u2FF4",
708
+ "\u2FF5",
709
+ "\u2FF6",
710
+ "\u2FF7",
711
+ "\u2FF8",
712
+ "\u2FF9",
713
+ "\u2FFA",
714
+ "\u2FFB",
715
+ "\u2FFC",
716
+ "\u2FFD",
717
+ "\u2FFE",
718
+ "\u2FFF"
719
+ ];
720
+
721
+ // src/config.ts
722
+ var characterSetSpecifiers = [
723
+ "minimal",
724
+ "gb2312",
725
+ "general",
726
+ "basic",
727
+ "extended",
728
+ "supplement",
729
+ "maximal",
730
+ "custom"
731
+ ];
732
+ function isVariableKey(key) {
733
+ return typeof key === "object" && key !== null && "variable" in key;
734
+ }
735
+ function isMerge(value) {
736
+ return typeof value === "object" && value !== null && "element" in value;
737
+ }
738
+ var binaryOps = [
739
+ "\u662F",
740
+ "\u4E0D\u662F",
741
+ "\u5339\u914D",
742
+ "\u4E0D\u5339\u914D",
743
+ "\u7F16\u7801\u5339\u914D",
744
+ "\u7F16\u7801\u4E0D\u5339\u914D"
745
+ ];
746
+ var unaryOps = ["\u5B58\u5728", "\u4E0D\u5B58\u5728"];
747
+ var ops = unaryOps.concat(...binaryOps);
748
+ var wordLengthArray = [...Array(9).keys()].map((x) => ({
749
+ label: x + 1,
750
+ value: x + 1
751
+ }));
752
+ var fingeringLabels = [
753
+ "\u540C\u624B",
754
+ "\u5927\u8DE8",
755
+ "\u5C0F\u8DE8",
756
+ "\u5E72\u6270",
757
+ "\u9519\u624B",
758
+ "\u4E09\u8FDE",
759
+ "\u5907\u7528",
760
+ "\u5907\u7528"
761
+ ];
762
+ var defaultOptimization = {
763
+ objective: {},
764
+ metaheuristic: {
765
+ algorithm: "SimulatedAnnealing"
766
+ }
767
+ };
768
+
769
+ // src/classifier.ts
770
+ var classifier = {
771
+ \u6A2A: 1,
772
+ \u63D0: 1,
773
+ \u7AD6: 2,
774
+ \u7AD6\u94A9: 2,
775
+ \u6487: 3,
776
+ \u5E73\u6487: 3,
777
+ \u70B9: 4,
778
+ \u5E73\u70B9: 4,
779
+ \u637A: 4,
780
+ \u5E73\u637A: 4,
781
+ \u6311\u637A: 4,
782
+ \u6A2A\u94A9: 5,
783
+ \u6A2A\u6487: 5,
784
+ \u6A2A\u6298: 5,
785
+ \u6A2A\u6298\u94A9: 5,
786
+ \u6A2A\u659C\u94A9: 5,
787
+ \u6A2A\u6298\u63D0: 5,
788
+ \u6A2A\u6298\u6298: 5,
789
+ \u6A2A\u6298\u5F2F: 5,
790
+ \u6A2A\u6487\u5F2F\u94A9: 5,
791
+ \u6A2A\u6298\u5F2F\u94A9: 5,
792
+ \u6A2A\u659C\u5F2F\u94A9: 5,
793
+ \u6A2A\u6298\u6298\u6487: 5,
794
+ \u6A2A\u6298\u6298\u6298: 5,
795
+ \u6A2A\u6298\u6298\u6298\u94A9: 5,
796
+ \u7AD6\u63D0: 5,
797
+ \u7AD6\u6298: 5,
798
+ \u7AD6\u5F2F: 5,
799
+ \u7AD6\u5F2F\u5DE6: 5,
800
+ \u7AD6\u5F2F\u94A9: 5,
801
+ \u7AD6\u6298\u6487: 5,
802
+ \u7AD6\u6298\u6298\u94A9: 5,
803
+ \u7AD6\u6298\u6298: 5,
804
+ \u6487\u70B9: 5,
805
+ \u6487\u6298: 5,
806
+ \u5F2F\u94A9: 5,
807
+ \u659C\u94A9: 5,
808
+ \u6487\u94A9: 5,
809
+ \u5367\u94A9: 5,
810
+ \u5708: 5,
811
+ \u7279\u6B8A\u7B14\u753B: 5
812
+ };
813
+ var mergeClassifier = (partialClassifier) => {
814
+ return { ...classifier, ...partialClassifier ?? {} };
815
+ };
816
+ var schema = {
817
+ \u6A2A: ["h"],
818
+ \u63D0: ["h"],
819
+ // 美化:提
820
+ \u7AD6: ["v"],
821
+ \u7AD6\u94A9: ["v"],
822
+ // 美化:钩
823
+ \u6487: ["c"],
824
+ \u5E73\u6487: ["z"],
825
+ \u70B9: ["c"],
826
+ \u5E73\u70B9: ["z"],
827
+ \u637A: ["c"],
828
+ \u5E73\u637A: ["z"],
829
+ \u6311\u637A: ["h", "c"],
830
+ \u6A2A\u94A9: ["h"],
831
+ // 美化:钩
832
+ \u6A2A\u6487: ["h", "c"],
833
+ \u6A2A\u6298: ["h", "v"],
834
+ \u6A2A\u6298\u94A9: ["h", "v"],
835
+ // 美化:钩
836
+ \u6A2A\u659C\u94A9: ["h", "c"],
837
+ // 美化:钩
838
+ \u6A2A\u6298\u63D0: ["h", "v", "h"],
839
+ // 美化:提
840
+ \u6A2A\u6298\u6298: ["h", "v", "h"],
841
+ \u6A2A\u6298\u5F2F: ["h", "v", "h"],
842
+ \u6A2A\u6487\u5F2F\u94A9: ["h", "c", "v"],
843
+ // 美化:钩
844
+ \u6A2A\u6298\u5F2F\u94A9: ["h", "v", "h"],
845
+ // 美化:钩
846
+ \u6A2A\u659C\u5F2F\u94A9: ["h", "c"],
847
+ // 美化:钩
848
+ \u6A2A\u6298\u6298\u6487: ["h", "v", "h", "c"],
849
+ \u6A2A\u6298\u6298\u6298: ["h", "v", "h", "v"],
850
+ \u6A2A\u6298\u6298\u6298\u94A9: ["h", "v", "h", "v"],
851
+ // 美化:钩
852
+ \u7AD6\u63D0: ["v", "h"],
853
+ // 美化:提
854
+ \u7AD6\u6298: ["v", "h"],
855
+ \u7AD6\u5F2F: ["v", "h"],
856
+ \u7AD6\u5F2F\u5DE6: ["v", "h"],
857
+ \u7AD6\u5F2F\u94A9: ["v", "h"],
858
+ // 美化:钩
859
+ \u7AD6\u6298\u6487: ["v", "h", "c"],
860
+ \u7AD6\u6298\u6298\u94A9: ["v", "h", "v"],
861
+ // 美化:钩
862
+ \u7AD6\u6298\u6298: ["v", "h", "v"],
863
+ \u6487\u70B9: ["c", "c"],
864
+ \u6487\u6298: ["c", "h"],
865
+ \u5F2F\u94A9: ["v"],
866
+ // 美化:钩
867
+ \u659C\u94A9: ["c"],
868
+ // 美化:钩
869
+ \u6487\u94A9: ["c"],
870
+ // 美化:钩
871
+ \u5367\u94A9: ["c"],
872
+ // 美化:钩
873
+ \u5708: ["a"],
874
+ \u7279\u6B8A\u7B14\u753B: ["c"]
875
+ };
876
+
877
+ // src/repertoire.ts
878
+ import { isEqual as isEqual4, sortBy as sortBy2 } from "lodash-es";
879
+
880
+ // src/degenerator.ts
881
+ import { isEqual as isEqual2 } from "lodash-es";
882
+ var indicesToBinary = (n) => (indices) => {
883
+ let binaryCode = 0;
884
+ for (const index of indices) {
885
+ binaryCode += 1 << n - index - 1;
886
+ }
887
+ return binaryCode;
888
+ };
889
+ var binaryToIndices = (n) => (binary) => {
890
+ const indices = [...Array(n).keys()];
891
+ return indices.filter((index) => binary & 1 << n - index - 1);
892
+ };
893
+ var defaultDegenerator = {
894
+ feature: {
895
+ \u63D0: "\u6A2A",
896
+ \u637A: "\u70B9"
897
+ },
898
+ no_cross: false
899
+ };
900
+ var strokeFeatureEqual = (degenerator, s1, s2) => {
901
+ const feature = degenerator.feature ?? {};
902
+ const d1 = feature[s1] ?? s1;
903
+ const d2 = feature[s2] ?? s2;
904
+ return d1 === d2;
905
+ };
906
+ var verifySpecialRoots = (component, root, indices) => {
907
+ if (["\u571F", "\u58EB"].includes(root.name)) {
908
+ const [i1, _, i3] = indices;
909
+ const upperHeng = component.glyph[i1]?.curveList[0];
910
+ const lowerHeng = component.glyph[i3]?.curveList[0];
911
+ const lowerIsLonger = curveLength(upperHeng) < curveLength(lowerHeng);
912
+ return root.name === "\u571F" ? lowerIsLonger : !lowerIsLonger;
913
+ }
914
+ if (["\u672A", "\u672B"].includes(root.name)) {
915
+ const [i1, i2] = indices;
916
+ const upperHeng = component.glyph[i1]?.curveList[0];
917
+ const lowerHeng = component.glyph[i2]?.curveList[0];
918
+ const lowerIsLonger = curveLength(upperHeng) < curveLength(lowerHeng);
919
+ return root.name === "\u672A" ? lowerIsLonger : !lowerIsLonger;
920
+ }
921
+ if (["\u53E3", "\u56D7"].includes(root.name)) {
922
+ if (["\u56D7", "\uE02D"].includes(component.name)) {
923
+ return root.name === "\u56D7";
924
+ }
925
+ const [i1, _, i3] = indices;
926
+ const upperLeft = component.glyph[i1]?.curveList[0]?.controls[0];
927
+ const lowerRight = component.glyph[i3]?.curveList[0]?.controls.at(-1);
928
+ const xrange = [upperLeft[0], lowerRight[0]];
929
+ const yrange = [upperLeft[1], lowerRight[1]];
930
+ const otherStrokes = component.glyph.filter(
931
+ (_2, index) => !indices.includes(index)
932
+ );
933
+ const containsStroke = otherStrokes.some(
934
+ (stroke) => isBoundedBy(stroke, xrange, yrange)
935
+ );
936
+ return root.name === "\u56D7" ? containsStroke : !containsStroke;
937
+ }
938
+ if ([
939
+ "\uE087",
940
+ "\uE43D"
941
+ /* 全字头 */
942
+ ].includes(root.name)) {
943
+ const [i1] = indices;
944
+ const attachPoint = component.glyph[i1]?.curveList[0]?.controls[0];
945
+ const otherStrokes = component.glyph.filter(
946
+ (_, index) => !indices.includes(index)
947
+ );
948
+ const otherCurves = otherStrokes.flatMap((s) => s.curveList);
949
+ const pieAndNaIsSeparated = otherCurves.some(
950
+ (x) => x.type === "linear" && isCollinear(x.controls[0], x.controls[1], attachPoint)
951
+ );
952
+ return root.name === "\uE087" ? pieAndNaIsSeparated : !pieAndNaIsSeparated;
953
+ }
954
+ return true;
955
+ };
956
+ var generateSliceBinaries = (degenerator, component, root) => {
957
+ const { glyph: cglyph, topology: ctopology } = component;
958
+ const { glyph: rglyph, topology: rtopology } = root;
959
+ if (cglyph.length < rglyph.length)
960
+ return [];
961
+ let queue = [[]];
962
+ for (const [rIndex, rStroke] of rglyph.entries()) {
963
+ const rStrokeTopology = rtopology.matrix[rIndex]?.slice(0, rIndex);
964
+ const end = cglyph.length - rglyph.length + rIndex + 1;
965
+ for (let _ = queue.length; _ !== 0; --_) {
966
+ const indexList = queue.shift();
967
+ const start = indexList.length ? indexList.at(-1) + 1 : 0;
968
+ for (const [cIndex, cStroke] of cglyph.slice(start, end).entries()) {
969
+ if (!strokeFeatureEqual(degenerator, cStroke.feature, rStroke.feature))
970
+ continue;
971
+ const realIndex = cIndex + start;
972
+ const cStrokeTopology = ctopology.matrix[realIndex]?.filter(
973
+ (_2, i) => indexList.includes(i)
974
+ );
975
+ if (!isEqual2(cStrokeTopology, rStrokeTopology))
976
+ continue;
977
+ queue.push(indexList.concat(realIndex));
978
+ }
979
+ }
980
+ if (!queue)
981
+ return [];
982
+ }
983
+ if (degenerator.no_cross) {
984
+ const allindices = [...Array(cglyph.length).keys()];
985
+ queue = queue.filter((indices) => {
986
+ const others = allindices.filter((x) => !indices.includes(x));
987
+ const allCombinations = indices.flatMap(
988
+ (x) => others.map((y) => sortTwoNumbers([x, y]))
989
+ );
990
+ return allCombinations.every(([x, y]) => {
991
+ const relation = ctopology.matrix[y]?.[x];
992
+ return relation.every((cr) => cr.type !== "\u4EA4");
993
+ });
994
+ });
995
+ }
996
+ return queue.filter((x) => verifySpecialRoots(component, root, x)).map(indicesToBinary(cglyph.length));
997
+ };
998
+ var degenerate = (degenerator, glyph) => {
999
+ const featureMap = degenerator.feature ?? {};
1000
+ return [
1001
+ glyph.map((x) => x.feature).map((x) => featureMap[x] || x),
1002
+ findTopology(glyph)
1003
+ ];
1004
+ };
1005
+
1006
+ // src/selector.ts
1007
+ import { isEqual as isEqual3 } from "lodash-es";
1008
+ var defaultSelector = [
1009
+ "\u7ED3\u6784\u5B8C\u6574",
1010
+ "\u6839\u5C11\u4F18\u5148",
1011
+ "\u80FD\u8FDE\u4E0D\u4EA4",
1012
+ "\u80FD\u6563\u4E0D\u8FDE",
1013
+ "\u5168\u7B26\u7B14\u987A",
1014
+ "\u53D6\u5927\u4F18\u5148"
1015
+ ];
1016
+ function isLess(a, b) {
1017
+ if (typeof a === "number" && typeof b === "number") {
1018
+ return a < b;
1019
+ }
1020
+ if (Array.isArray(a) && Array.isArray(b)) {
1021
+ for (const [i, v] of a.entries()) {
1022
+ const u = b[i];
1023
+ if (u === void 0)
1024
+ return false;
1025
+ if (v < u)
1026
+ return true;
1027
+ if (v > u)
1028
+ return false;
1029
+ }
1030
+ return false;
1031
+ }
1032
+ return false;
1033
+ }
1034
+ var length = {
1035
+ title: "\u6839\u5C11\u4F18\u5148",
1036
+ key: (scheme) => scheme.length
1037
+ };
1038
+ var countStrokes = (n) => n < 2 ? n : (n & 1) + countStrokes(n >>> 1);
1039
+ var bias = {
1040
+ title: "\u53D6\u5927\u4F18\u5148",
1041
+ key: (scheme) => scheme.map(countStrokes).map((x) => -x),
1042
+ display: (data) => `(${data.map((x) => -x).join(", ")})`
1043
+ };
1044
+ var unbias = {
1045
+ title: "\u53D6\u5C0F\u4F18\u5148",
1046
+ key: (scheme) => scheme.map(countStrokes),
1047
+ display: (data) => `(${data.join(", ")})`
1048
+ };
1049
+ var order = {
1050
+ title: "\u5168\u7B26\u7B14\u987A",
1051
+ key: (scheme, { component }) => {
1052
+ const indices = scheme.flatMap(
1053
+ (x) => binaryToIndices(component.glyph.length)(x)
1054
+ );
1055
+ const isSorted = indices.slice(1).every((v, i) => indices[i] < v);
1056
+ return Number(!isSorted);
1057
+ }
1058
+ };
1059
+ var order2 = {
1060
+ title: "\u8FDE\u7EED\u7B14\u987A",
1061
+ key: (scheme, { component }) => {
1062
+ const indices = scheme.map(binaryToIndices(component.glyph.length));
1063
+ const unSorted = indices.filter(
1064
+ (x) => x.length - 1 !== x.at(-1) - x[0]
1065
+ ).length;
1066
+ return unSorted;
1067
+ }
1068
+ };
1069
+ var similar = {
1070
+ title: "\u975E\u5F62\u8FD1\u6839",
1071
+ key: (scheme, { rootMap, secondaryRoots }) => {
1072
+ const roots = scheme.map((x) => rootMap.get(x));
1073
+ return roots.filter((x) => secondaryRoots.has(x)).length;
1074
+ }
1075
+ };
1076
+ var strong = {
1077
+ title: "\u591A\u5F3A\u5B57\u6839",
1078
+ key: (scheme, { rootMap, analysis: analysis2 }) => {
1079
+ const strong2 = analysis2?.strong || [];
1080
+ const roots = scheme.map((x) => rootMap.get(x));
1081
+ return -roots.filter((x) => strong2.includes(x)).length;
1082
+ }
1083
+ };
1084
+ var weak = {
1085
+ title: "\u5C11\u5F31\u5B57\u6839",
1086
+ key: (scheme, { rootMap, analysis: analysis2 }) => {
1087
+ const weak2 = analysis2?.weak || [];
1088
+ const roots = scheme.map((x) => rootMap.get(x));
1089
+ return roots.filter((x) => weak2.includes(x)).length;
1090
+ }
1091
+ };
1092
+ var makeTopologySieve = (relationType, avoidRelationType, title) => {
1093
+ const key = (scheme, { component }) => {
1094
+ const parsedScheme = scheme.map(
1095
+ (x) => binaryToIndices(component.glyph.length)(x)
1096
+ );
1097
+ let totalCrosses = 0;
1098
+ for (const [i, bi] of parsedScheme.entries()) {
1099
+ for (const [j, bj] of parsedScheme.entries()) {
1100
+ if (j >= i)
1101
+ continue;
1102
+ let r2 = false;
1103
+ let a = false;
1104
+ for (const k of bi) {
1105
+ for (const l of bj) {
1106
+ const [smaller, larger] = [Math.min(k, l), Math.max(k, l)];
1107
+ const relations = component.topology.matrix[larger]?.[smaller];
1108
+ r2 || (r2 = relations.some((v) => v.type === relationType));
1109
+ a || (a = relations.some((v) => avoidRelationType.includes(v.type)));
1110
+ }
1111
+ }
1112
+ if (!a)
1113
+ totalCrosses += Number(r2);
1114
+ }
1115
+ }
1116
+ return totalCrosses;
1117
+ };
1118
+ return { key, title };
1119
+ };
1120
+ var crossing = makeTopologySieve("\u4EA4", [], "\u80FD\u8FDE\u4E0D\u4EA4");
1121
+ var attaching = makeTopologySieve("\u8FDE", ["\u4EA4"], "\u80FD\u6563\u4E0D\u8FDE");
1122
+ var orientation = {
1123
+ title: "\u540C\u5411\u7B14\u753B",
1124
+ key: (scheme, { component }) => {
1125
+ const n = component.glyph.length;
1126
+ const parsedScheme = scheme.map(binaryToIndices(n));
1127
+ let totalCrosses = 0;
1128
+ for (const [i, bi] of parsedScheme.entries()) {
1129
+ for (const [j, bj] of parsedScheme.entries()) {
1130
+ if (j >= i)
1131
+ continue;
1132
+ let r2 = false;
1133
+ for (const k of bi) {
1134
+ for (const l of bj) {
1135
+ const [smaller, larger] = sortTwoNumbers([k, l]);
1136
+ const oriented = component.topology.orientedPairs.some(
1137
+ (x) => isEqual3(x, [larger, smaller])
1138
+ );
1139
+ r2 || (r2 = oriented);
1140
+ }
1141
+ }
1142
+ totalCrosses += Number(r2);
1143
+ }
1144
+ }
1145
+ return totalCrosses;
1146
+ }
1147
+ };
1148
+ var contains2 = (b1, b2) => (b1 | b2) === b1;
1149
+ var integrity = {
1150
+ title: "\u7ED3\u6784\u5B8C\u6574",
1151
+ key: (scheme, { rootMap }) => {
1152
+ const priorities = [
1153
+ "\u53E3",
1154
+ "\u56D7",
1155
+ "\u5182",
1156
+ "\uE439",
1157
+ "\u531A",
1158
+ "\u51F5",
1159
+ "\uE009",
1160
+ "\u52F9",
1161
+ "\u5C38",
1162
+ "\uE407"
1163
+ ];
1164
+ const shouldHave = [...rootMap].filter(([_, name]) => priorities.includes(name)).map(([binary]) => binary);
1165
+ const breaks = shouldHave.filter(
1166
+ (x) => !scheme.some((binary) => contains2(binary, x))
1167
+ ).length;
1168
+ return breaks;
1169
+ }
1170
+ };
1171
+ var sieveMap = new Map(
1172
+ [
1173
+ length,
1174
+ order,
1175
+ order2,
1176
+ bias,
1177
+ unbias,
1178
+ crossing,
1179
+ attaching,
1180
+ similar,
1181
+ orientation,
1182
+ integrity,
1183
+ strong,
1184
+ weak
1185
+ ].map((x) => [x.title, x])
1186
+ );
1187
+ var select = (config, component, schemeList, rootMap, requiredRoots) => {
1188
+ const environment = {
1189
+ component,
1190
+ rootMap,
1191
+ ...config
1192
+ };
1193
+ const sieveNames = config.analysis.selector ?? defaultSelector;
1194
+ const schemeData = schemeList.map((scheme) => {
1195
+ const evaluation = /* @__PURE__ */ new Map();
1196
+ for (const sieveName of sieveNames) {
1197
+ const sieve = sieveMap.get(sieveName);
1198
+ const value = sieve.key(scheme, environment);
1199
+ evaluation.set(sieve.title, value);
1200
+ }
1201
+ return {
1202
+ scheme,
1203
+ roots: scheme.map((x) => rootMap.get(x)),
1204
+ evaluation,
1205
+ optional: false
1206
+ };
1207
+ });
1208
+ schemeData.sort((a, b) => {
1209
+ for (const sieveName of sieveNames) {
1210
+ const aValue = a.evaluation.get(sieveName);
1211
+ const bValue = b.evaluation.get(sieveName);
1212
+ if (isLess(aValue, bValue))
1213
+ return -1;
1214
+ if (isLess(bValue, aValue))
1215
+ return 1;
1216
+ continue;
1217
+ }
1218
+ return 0;
1219
+ });
1220
+ const requiredRootsNames = Array.from(requiredRoots).map(
1221
+ (x) => rootMap.get(x)
1222
+ );
1223
+ const optionalRootsData = schemeData.map(
1224
+ (x) => x.roots.filter((y) => !requiredRootsNames.includes(y))
1225
+ );
1226
+ for (const [index, data] of schemeData.entries()) {
1227
+ data.optional = true;
1228
+ for (let prevIndex = 0; prevIndex != index; ++prevIndex) {
1229
+ const current = optionalRootsData[index];
1230
+ const previous = optionalRootsData[prevIndex];
1231
+ if (previous.every((x) => current.includes(x))) {
1232
+ data.optional = false;
1233
+ break;
1234
+ }
1235
+ }
1236
+ if (data.scheme.every((x) => requiredRoots.has(x) || (x & x - 1) === 0)) {
1237
+ break;
1238
+ }
1239
+ }
1240
+ if (schemeData.length === 0)
1241
+ return new NoSchemeError();
1242
+ return schemeData;
1243
+ };
1244
+
1245
+ // src/component.ts
1246
+ import { bisectLeft, bisectRight } from "d3-array";
1247
+
1248
+ // src/utils.ts
1249
+ import { range } from "lodash-es";
1250
+ import { dump } from "js-yaml";
1251
+ var printableAscii = range(33, 127).map(
1252
+ (x) => String.fromCodePoint(x)
1253
+ );
1254
+ var formatDate = (date) => {
1255
+ return `${date.getMonth() + 1}-${date.getDate()} ${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}`;
1256
+ };
1257
+ var unicodeBlocks = [
1258
+ // 统一汉字基本集与扩展
1259
+ {
1260
+ name: "cjk",
1261
+ label: "\u4E2D\u65E5\u97E9\u7EDF\u4E00\u8868\u610F\u6587\u5B57",
1262
+ begin: 19968,
1263
+ end: 40959,
1264
+ count: 20992
1265
+ },
1266
+ {
1267
+ name: "cjk-a",
1268
+ label: "\u4E2D\u65E5\u97E9\u7EDF\u4E00\u8868\u610F\u6587\u5B57\u6269\u5C55A",
1269
+ begin: 13312,
1270
+ end: 19903,
1271
+ count: 6592
1272
+ },
1273
+ {
1274
+ name: "cjk-b",
1275
+ label: "\u4E2D\u65E5\u97E9\u7EDF\u4E00\u8868\u610F\u6587\u5B57\u6269\u5C55B",
1276
+ begin: 131072,
1277
+ end: 173791,
1278
+ count: 42720
1279
+ },
1280
+ {
1281
+ name: "cjk-c",
1282
+ label: "\u4E2D\u65E5\u97E9\u7EDF\u4E00\u8868\u610F\u6587\u5B57\u6269\u5C55C",
1283
+ begin: 173824,
1284
+ end: 177983,
1285
+ count: 4160
1286
+ },
1287
+ {
1288
+ name: "cjk-d",
1289
+ label: "\u4E2D\u65E5\u97E9\u7EDF\u4E00\u8868\u610F\u6587\u5B57\u6269\u5C55D",
1290
+ begin: 177984,
1291
+ end: 178207,
1292
+ count: 222
1293
+ },
1294
+ {
1295
+ name: "cjk-e",
1296
+ label: "\u4E2D\u65E5\u97E9\u7EDF\u4E00\u8868\u610F\u6587\u5B57\u6269\u5C55E",
1297
+ begin: 178208,
1298
+ end: 183983,
1299
+ count: 5774
1300
+ },
1301
+ {
1302
+ name: "cjk-f",
1303
+ label: "\u4E2D\u65E5\u97E9\u7EDF\u4E00\u8868\u610F\u6587\u5B57\u6269\u5C55F",
1304
+ begin: 183984,
1305
+ end: 191471,
1306
+ count: 7473
1307
+ },
1308
+ {
1309
+ name: "cjk-g",
1310
+ label: "\u4E2D\u65E5\u97E9\u7EDF\u4E00\u8868\u610F\u6587\u5B57\u6269\u5C55G",
1311
+ begin: 196608,
1312
+ end: 201551,
1313
+ count: 4939
1314
+ },
1315
+ {
1316
+ name: "cjk-h",
1317
+ label: "\u4E2D\u65E5\u97E9\u7EDF\u4E00\u8868\u610F\u6587\u5B57\u6269\u5C55H",
1318
+ begin: 201552,
1319
+ end: 205743,
1320
+ count: 4192
1321
+ },
1322
+ {
1323
+ name: "cjk-i",
1324
+ label: "\u4E2D\u65E5\u97E9\u7EDF\u4E00\u8868\u610F\u6587\u5B57\u6269\u5C55I",
1325
+ begin: 191472,
1326
+ end: 192095,
1327
+ count: 622
1328
+ },
1329
+ {
1330
+ name: "cjk-j",
1331
+ label: "\u4E2D\u65E5\u97E9\u7EDF\u4E00\u8868\u610F\u6587\u5B57\u6269\u5C55J",
1332
+ begin: 205744,
1333
+ end: 210047,
1334
+ count: 4298
1335
+ },
1336
+ // 部件
1337
+ {
1338
+ name: "radicals-sup",
1339
+ label: "\u4E2D\u65E5\u97E9\u90E8\u9996\u8865\u5145",
1340
+ begin: 11904,
1341
+ end: 12031,
1342
+ count: 115
1343
+ },
1344
+ { name: "kangxi", label: "\u5EB7\u7199\u90E8\u9996", begin: 12032, end: 12255, count: 214 },
1345
+ {
1346
+ name: "strokes",
1347
+ label: "\u4E2D\u65E5\u97E9\u7B14\u753B",
1348
+ begin: 12736,
1349
+ end: 12783,
1350
+ count: 38
1351
+ },
1352
+ // 兼容汉字
1353
+ {
1354
+ name: "compat",
1355
+ label: "\u4E2D\u65E5\u97E9\u517C\u5BB9\u8868\u610F\u6587\u5B57",
1356
+ begin: 63744,
1357
+ end: 64255,
1358
+ count: 472
1359
+ },
1360
+ {
1361
+ name: "compat-sup",
1362
+ label: "\u4E2D\u65E5\u97E9\u517C\u5BB9\u8868\u610F\u6587\u5B57\u8865\u5145",
1363
+ begin: 194560,
1364
+ end: 195103,
1365
+ count: 542
1366
+ },
1367
+ // 古文字系统
1368
+ {
1369
+ name: "tangut",
1370
+ label: "\u897F\u590F\u6587",
1371
+ begin: 94208,
1372
+ end: 100351,
1373
+ count: 6144
1374
+ },
1375
+ {
1376
+ name: "tangut-comp",
1377
+ label: "\u897F\u590F\u6587\u5B57\u6784\u4EF6",
1378
+ begin: 100352,
1379
+ end: 101119,
1380
+ count: 768
1381
+ },
1382
+ {
1383
+ name: "tangut-sup",
1384
+ label: "\u897F\u590F\u6587\u8865\u5145",
1385
+ begin: 101632,
1386
+ end: 101759,
1387
+ count: 31
1388
+ },
1389
+ {
1390
+ name: "tangut-comp-sup",
1391
+ label: "\u897F\u590F\u6587\u5B57\u6784\u4EF6\u8865\u5145",
1392
+ begin: 101760,
1393
+ end: 101887,
1394
+ count: 115
1395
+ },
1396
+ {
1397
+ name: "khitan-small",
1398
+ label: "\u5951\u4E39\u5C0F\u5B57",
1399
+ begin: 101120,
1400
+ end: 101631,
1401
+ count: 470
1402
+ },
1403
+ // 标点符号与排版字符
1404
+ {
1405
+ name: "punct",
1406
+ label: "\u4E2D\u65E5\u97E9\u7B26\u53F7\u548C\u6807\u70B9",
1407
+ begin: 12288,
1408
+ end: 12351,
1409
+ count: 64
1410
+ },
1411
+ {
1412
+ name: "enclosed",
1413
+ label: "\u4E2D\u65E5\u97E9\u5E26\u5708\u5B57\u6BCD\u548C\u6708\u4EFD",
1414
+ begin: 12800,
1415
+ end: 13055,
1416
+ count: 255
1417
+ },
1418
+ {
1419
+ name: "enclosed-sup",
1420
+ label: "\u4E2D\u65E5\u97E9\u5E26\u5708\u6587\u5B57\u8865\u5145",
1421
+ begin: 127488,
1422
+ end: 127743,
1423
+ count: 64
1424
+ },
1425
+ {
1426
+ name: "ideo-symbols",
1427
+ label: "\u8868\u610F\u6587\u5B57\u7B26\u53F7\u4E0E\u6807\u70B9",
1428
+ begin: 94176,
1429
+ end: 94207,
1430
+ count: 7
1431
+ },
1432
+ // 私用区
1433
+ { name: "pua", label: "\u79C1\u7528\u533A (BMP)", begin: 57344, end: 63743, count: 0 },
1434
+ {
1435
+ name: "pua-plane15",
1436
+ label: "\u79C1\u7528\u533A (Plane 15)",
1437
+ begin: 983040,
1438
+ end: 1048573,
1439
+ count: 0
1440
+ }
1441
+ ];
1442
+ var unicodeBlock = (code) => {
1443
+ for (const block of unicodeBlocks) {
1444
+ if (code >= block.begin && code <= block.end) {
1445
+ return block.name;
1446
+ }
1447
+ }
1448
+ return "unknown";
1449
+ };
1450
+ var unicodeBlockRank = (code) => {
1451
+ for (const [rank, block] of unicodeBlocks.entries()) {
1452
+ if (code >= block.begin && code <= block.end) {
1453
+ return rank;
1454
+ }
1455
+ }
1456
+ return -1;
1457
+ };
1458
+ var isValidCJKBasicChar = (char) => {
1459
+ const code = char.codePointAt(0);
1460
+ const block = unicodeBlock(code);
1461
+ return block === "cjk";
1462
+ };
1463
+ var isValidCJKChar = (char) => {
1464
+ const code = char.codePointAt(0);
1465
+ const block = unicodeBlock(code);
1466
+ return block.startsWith("cjk");
1467
+ };
1468
+ var isValidCJKSupplement = (char) => {
1469
+ const code = char.codePointAt(0);
1470
+ const block = unicodeBlock(code);
1471
+ return block === "radicals-sup" || block === "kangxi" || block === "strokes" || block === "compat" || block === "compat-sup" || block === "punct";
1472
+ };
1473
+ var isPUA = (char) => {
1474
+ const code = char.codePointAt(0);
1475
+ const block = unicodeBlock(code);
1476
+ return block === "pua" || block === "pua-plane15";
1477
+ };
1478
+ var chars = (s) => {
1479
+ return Array.from(s).length;
1480
+ };
1481
+ var getDummyBasicComponent = () => ({
1482
+ type: "basic_component",
1483
+ strokes: [getDummySVGStroke("\u6A2A")]
1484
+ });
1485
+ var getDummyDerivedComponent = () => ({
1486
+ type: "derived_component",
1487
+ source: "\u4E00",
1488
+ strokes: [getDummyReferenceStroke()]
1489
+ });
1490
+ var getDummySplicedComponent = () => ({
1491
+ type: "spliced_component",
1492
+ operator: "\u2FF0",
1493
+ operandList: ["\u4E00", "\u4E28"]
1494
+ });
1495
+ var getDummyReferenceStroke = () => ({
1496
+ feature: "reference",
1497
+ index: 0
1498
+ });
1499
+ var getDummySVGStroke = (feature, start = [0, 0], oldCurveList = []) => {
1500
+ const typelist = schema[feature];
1501
+ return {
1502
+ feature,
1503
+ start,
1504
+ curveList: typelist.map((command, index) => {
1505
+ if (oldCurveList[index]?.command === command) {
1506
+ return oldCurveList[index];
1507
+ }
1508
+ switch (command) {
1509
+ case "a":
1510
+ return { command, parameterList: [20] };
1511
+ case "h":
1512
+ case "v":
1513
+ return { command, parameterList: [20] };
1514
+ default:
1515
+ return { command, parameterList: [10, 10, 20, 20, 30, 30] };
1516
+ }
1517
+ })
1518
+ };
1519
+ };
1520
+ var getDummyCompound = (operator) => ({
1521
+ type: "compound",
1522
+ operator,
1523
+ operandList: ["\u4E00", "\u4E00"]
1524
+ });
1525
+ var isComponent = (glyph) => glyph.type === "basic_component" || glyph.type === "derived_component" || glyph.type === "spliced_component" || glyph.type === "identity";
1526
+ var getSupplemental = (repertoire, list) => {
1527
+ const set = new Set(list);
1528
+ const reverseForm = Object.fromEntries(
1529
+ Object.entries(repertoire).map(([x]) => [x, []])
1530
+ );
1531
+ for (const [char, { glyph }] of Object.entries(repertoire)) {
1532
+ if (glyph?.type === "compound") {
1533
+ glyph.operandList.forEach((x) => reverseForm[x]?.push(char));
1534
+ }
1535
+ }
1536
+ const componentsNotChar = Object.entries(repertoire).filter(([, v]) => v.glyph?.type === "basic_component").map(([x]) => x).filter((x) => !set.has(x));
1537
+ const suppList = [];
1538
+ componentsNotChar.forEach((char) => {
1539
+ let trial = char;
1540
+ while (trial && !set.has(trial)) {
1541
+ trial = reverseForm[trial]?.[0];
1542
+ }
1543
+ if (trial)
1544
+ suppList.push(trial);
1545
+ });
1546
+ return Array.from(new Set(suppList));
1547
+ };
1548
+ var listToObject = (list) => Object.fromEntries(list.map((x) => [String.fromCodePoint(x.unicode), x]));
1549
+ function getRecordFromTSV(text) {
1550
+ const tsv = text.trim().split("\n").map((x) => x.trim().split(" "));
1551
+ const data = {};
1552
+ tsv.forEach(([char, freq]) => {
1553
+ if (char === void 0 || freq === void 0)
1554
+ return;
1555
+ const maybeNumber = Number(freq);
1556
+ if (Number.isNaN(maybeNumber))
1557
+ return;
1558
+ data[char] = maybeNumber;
1559
+ });
1560
+ return data;
1561
+ }
1562
+ function getDistributionFromTSV(text) {
1563
+ const tsv = text.trim().split("\n").map((x) => x.trim().split(" "));
1564
+ const data = {};
1565
+ tsv.forEach(([char, ideal_s, lt_penalty_s, gt_penalty_s]) => {
1566
+ if (char === void 0 || ideal_s === void 0 || lt_penalty_s === void 0 || gt_penalty_s === void 0)
1567
+ return;
1568
+ const [ideal, lt_penalty, gt_penalty] = [
1569
+ ideal_s,
1570
+ lt_penalty_s,
1571
+ gt_penalty_s
1572
+ ].map(Number);
1573
+ if (Number.isNaN(ideal) || Number.isNaN(lt_penalty) || Number.isNaN(gt_penalty))
1574
+ return;
1575
+ data[char] = { ideal, lt_penalty, gt_penalty };
1576
+ });
1577
+ return data;
1578
+ }
1579
+ function getDictFromTSV(text) {
1580
+ const result = [];
1581
+ for (const line of text.trim().split("\n")) {
1582
+ const [key, value] = line.trim().split(" ");
1583
+ if (key === void 0 || value === void 0)
1584
+ continue;
1585
+ result.push([key, value]);
1586
+ }
1587
+ return result;
1588
+ }
1589
+ var processExport = (content, filename) => {
1590
+ const blob = new Blob([content], { type: "text/plain" });
1591
+ const a = document.createElement("a");
1592
+ a.download = filename;
1593
+ const url = window.URL.createObjectURL(blob);
1594
+ a.href = url;
1595
+ a.click();
1596
+ window.URL.revokeObjectURL(url);
1597
+ };
1598
+ var exportYAML = (config, filename, flowLevel = 4, sanitize = true) => {
1599
+ const unsafeContent = dump(config, { flowLevel });
1600
+ if (!sanitize) {
1601
+ processExport(unsafeContent, `${filename}.yaml`);
1602
+ } else {
1603
+ const fileContent = unsafeContent.replace(/[\uE000-\uFFFF]/g, (c) => {
1604
+ return `"\\u${c.codePointAt(0)?.toString(16)}"`;
1605
+ });
1606
+ processExport(fileContent, `${filename}.yaml`);
1607
+ }
1608
+ };
1609
+ var exportJSON = (data, filename) => {
1610
+ const unsafeContent = JSON.stringify(data);
1611
+ const fileContent = unsafeContent.replace(/[\uE000-\uFFFF]/g, (c) => {
1612
+ return `\\u${c.codePointAt(0)?.toString(16)}`;
1613
+ });
1614
+ processExport(fileContent, filename);
1615
+ };
1616
+ var exportTSV = (data, filename) => {
1617
+ const fileContent = data.map((x) => x.join(" ")).join("\n");
1618
+ processExport(fileContent, filename);
1619
+ };
1620
+ var stringify = (element) => {
1621
+ if (element === void 0) {
1622
+ return "\u03B5";
1623
+ } else if (typeof element === "string") {
1624
+ return element;
1625
+ } else {
1626
+ return `${element.element}.${element.index}`;
1627
+ }
1628
+ };
1629
+ var parseKey = (key) => {
1630
+ if (key === "\u03B5") {
1631
+ return void 0;
1632
+ } else if (key.includes(".")) {
1633
+ const [element, index_s] = key.split(".");
1634
+ const index = Number(index_s);
1635
+ if (Number.isNaN(index)) {
1636
+ throw new Error(`\u65E0\u6CD5\u89E3\u6790\u7684\u952E\uFF1A${key}`);
1637
+ }
1638
+ return { element, index };
1639
+ } else {
1640
+ return key;
1641
+ }
1642
+ };
1643
+ var joinKeys = (keys) => {
1644
+ return keys.every((x) => typeof x === "string") ? keys.join("") : keys;
1645
+ };
1646
+ var match = (character, input) => {
1647
+ const { tag, operator, part } = input;
1648
+ if ("glyphs" in character) {
1649
+ const isTagMatched2 = tag === void 0 || character.glyphs.some((x) => x.tags?.includes(tag));
1650
+ const isOperatorMatched2 = operator === void 0 || character.glyphs.some(
1651
+ (x) => "operator" in x && x.operator.includes(operator)
1652
+ );
1653
+ const isPartMatched2 = part === void 0 || character.glyphs.some(
1654
+ (x) => "operandList" in x && x.operandList.includes(part)
1655
+ );
1656
+ return isTagMatched2 && isOperatorMatched2 && isPartMatched2;
1657
+ }
1658
+ const isTagMatched = tag === void 0 || character.glyph?.tags?.includes(tag);
1659
+ const isOperatorMatched = operator === void 0 || character.glyph?.type === "compound" && character.glyph.operator.includes(operator);
1660
+ const isPartMatched = part === void 0 || character.glyph?.type === "compound" && character.glyph.operandList.includes(part);
1661
+ return isTagMatched && isOperatorMatched && isPartMatched;
1662
+ };
1663
+ var makeCharacterFilter = (input, repertoire, sequenceMap) => {
1664
+ let sequenceRegex;
1665
+ try {
1666
+ if (input.sequence) {
1667
+ sequenceRegex = new RegExp(input.sequence);
1668
+ }
1669
+ } catch {
1670
+ }
1671
+ return (name) => {
1672
+ const character = repertoire[name];
1673
+ if (character === void 0)
1674
+ return false;
1675
+ const sequence = sequenceMap.get(name) ?? "";
1676
+ const isNameMatched = ((character.name ?? "") + name).includes(
1677
+ input.name ?? ""
1678
+ );
1679
+ const isSequenceMatched = sequenceRegex?.test(sequence) ?? true;
1680
+ const isUnicodeMatched = input.unicode === void 0 || input.unicode === name.codePointAt(0);
1681
+ const isMatched = match(character, input);
1682
+ return isNameMatched && isSequenceMatched && isUnicodeMatched && isMatched;
1683
+ };
1684
+ };
1685
+ var makeFilter = (input, form, sequence) => (char) => {
1686
+ if ((sequence.get(char)?.length ?? 0) <= 1)
1687
+ return false;
1688
+ const name = form[char]?.name ?? "";
1689
+ const seq = sequence.get(char) ?? "";
1690
+ return name.includes(input) || char.includes(input) || seq.startsWith(input);
1691
+ };
1692
+ var makeDefaultAnalyzer = (maxLength) => {
1693
+ const form = {
1694
+ type: "all",
1695
+ position: range(0, maxLength),
1696
+ top: 0
1697
+ };
1698
+ return form;
1699
+ };
1700
+ function \u6700\u5927\u9006\u5411\u5339\u914D\u5206\u8BCD(\u8BCD\u5178, \u6587\u672C) {
1701
+ const \u8BCD\u5217\u8868 = [];
1702
+ const \u5B57\u7B26\u5217\u8868 = [...\u6587\u672C];
1703
+ let \u7ED3\u675F\u4F4D\u7F6E = \u5B57\u7B26\u5217\u8868.length;
1704
+ while (\u7ED3\u675F\u4F4D\u7F6E > 0) {
1705
+ const \u672B\u5B57 = \u5B57\u7B26\u5217\u8868[\u7ED3\u675F\u4F4D\u7F6E - 1];
1706
+ if (!\u8BCD\u5178.has(\u672B\u5B57)) {
1707
+ \u8BCD\u5217\u8868.unshift(\u672B\u5B57);
1708
+ \u7ED3\u675F\u4F4D\u7F6E -= 1;
1709
+ continue;
1710
+ }
1711
+ for (let \u5F00\u59CB\u4F4D\u7F6E = 0; \u5F00\u59CB\u4F4D\u7F6E < \u7ED3\u675F\u4F4D\u7F6E; \u5F00\u59CB\u4F4D\u7F6E++) {
1712
+ const \u8BCD = \u5B57\u7B26\u5217\u8868.slice(\u5F00\u59CB\u4F4D\u7F6E, \u7ED3\u675F\u4F4D\u7F6E).join("");
1713
+ if (\u8BCD\u5178.has(\u8BCD)) {
1714
+ \u8BCD\u5217\u8868.unshift(\u8BCD);
1715
+ \u7ED3\u675F\u4F4D\u7F6E = \u5F00\u59CB\u4F4D\u7F6E;
1716
+ break;
1717
+ }
1718
+ }
1719
+ }
1720
+ return \u8BCD\u5217\u8868;
1721
+ }
1722
+ var adapt = (\u539F\u59CB\u8BCD\u9891\u6620\u5C04, \u8BCD\u5178) => {
1723
+ const \u65B0\u8BCD\u9891\u6620\u5C04 = /* @__PURE__ */ new Map();
1724
+ for (const [\u8BCD, \u8BCD\u9891] of Object.entries(\u539F\u59CB\u8BCD\u9891\u6620\u5C04)) {
1725
+ if (\u8BCD\u5178.has(\u8BCD)) {
1726
+ \u65B0\u8BCD\u9891\u6620\u5C04.set(\u8BCD, (\u65B0\u8BCD\u9891\u6620\u5C04.get(\u8BCD) ?? 0) + \u8BCD\u9891);
1727
+ } else {
1728
+ const \u5B50\u8BCD\u5217\u8868 = \u6700\u5927\u9006\u5411\u5339\u914D\u5206\u8BCD(\u8BCD\u5178, \u8BCD);
1729
+ for (const \u5B50\u8BCD of \u5B50\u8BCD\u5217\u8868) {
1730
+ \u65B0\u8BCD\u9891\u6620\u5C04.set(\u5B50\u8BCD, (\u65B0\u8BCD\u9891\u6620\u5C04.get(\u5B50\u8BCD) ?? 0) + \u8BCD\u9891);
1731
+ }
1732
+ }
1733
+ }
1734
+ return \u65B0\u8BCD\u9891\u6620\u5C04;
1735
+ };
1736
+ var getReversedMapping = (mapping, alphabet) => {
1737
+ const reversedMapping = new Map(
1738
+ Array.from(alphabet).map((key) => [key, []])
1739
+ );
1740
+ const recursivelyRenderKey = (key) => {
1741
+ if (typeof key === "string")
1742
+ return key;
1743
+ const mapped = mapping[key.element];
1744
+ if (typeof mapped === "object" && "element" in mapped) {
1745
+ return "";
1746
+ }
1747
+ return recursivelyRenderKey(mapped[key.index]);
1748
+ };
1749
+ for (const [name, code] of Object.entries(mapping)) {
1750
+ if (typeof code === "string" || Array.isArray(code)) {
1751
+ const first2 = recursivelyRenderKey(code[0]);
1752
+ reversedMapping.get(first2)?.push({ name, code });
1753
+ }
1754
+ }
1755
+ return reversedMapping;
1756
+ };
1757
+
1758
+ // src/compound.ts
1759
+ import { range as range2, sortBy } from "lodash-es";
1760
+ var getGlyphBoundingBox = (glyph) => {
1761
+ let [xmin, ymin, xmax, ymax] = [
1762
+ Number.POSITIVE_INFINITY,
1763
+ Number.POSITIVE_INFINITY,
1764
+ Number.NEGATIVE_INFINITY,
1765
+ Number.NEGATIVE_INFINITY
1766
+ ];
1767
+ for (const { start, curveList } of glyph) {
1768
+ let [x, y] = start;
1769
+ xmin = Math.min(xmin, x);
1770
+ ymin = Math.min(ymin, y);
1771
+ xmax = Math.max(xmax, x);
1772
+ ymax = Math.max(ymax, y);
1773
+ for (const { command, parameterList } of curveList) {
1774
+ switch (command) {
1775
+ case "h":
1776
+ x += parameterList[0];
1777
+ break;
1778
+ case "v":
1779
+ y += parameterList[0];
1780
+ break;
1781
+ case "a":
1782
+ xmin = Math.min(xmin, x - parameterList[0]);
1783
+ xmax = Math.max(xmax, x + parameterList[0]);
1784
+ ymax = Math.max(ymax, y + 2 * parameterList[0]);
1785
+ break;
1786
+ default: {
1787
+ const [_x1, _y1, _x2, _y2, x3, y3] = parameterList;
1788
+ x += x3;
1789
+ y += y3;
1790
+ break;
1791
+ }
1792
+ }
1793
+ xmin = Math.min(xmin, x);
1794
+ ymin = Math.min(ymin, y);
1795
+ xmax = Math.max(xmax, x);
1796
+ ymax = Math.max(ymax, y);
1797
+ }
1798
+ }
1799
+ const bb = { x: [xmin, xmax], y: [ymin, ymax] };
1800
+ return bb;
1801
+ };
1802
+ var recursiveRenderCompound = (compound, repertoire, glyphCache = /* @__PURE__ */ new Map()) => {
1803
+ const glyphs = [];
1804
+ for (const char of compound.operandList) {
1805
+ const glyph = repertoire[char]?.glyph;
1806
+ if (glyph === void 0)
1807
+ return new InvalidGlyphError();
1808
+ if (glyph.type === "basic_component") {
1809
+ let box = glyphCache.get(char)?.box;
1810
+ if (box === void 0) {
1811
+ box = getGlyphBoundingBox(glyph.strokes);
1812
+ glyphCache.set(char, { strokes: glyph.strokes, box });
1813
+ }
1814
+ glyphs.push({ strokes: glyph.strokes, box });
1815
+ } else {
1816
+ const cache = glyphCache.get(char);
1817
+ if (cache !== void 0) {
1818
+ glyphs.push(cache);
1819
+ continue;
1820
+ }
1821
+ const rendered = recursiveRenderCompound(glyph, repertoire, glyphCache);
1822
+ if (rendered instanceof Error)
1823
+ return rendered;
1824
+ glyphs.push(rendered);
1825
+ glyphCache.set(char, rendered);
1826
+ }
1827
+ }
1828
+ return affineMerge(compound, glyphs);
1829
+ };
1830
+ var recursiveRenderStrokeSequence = (compound, repertoire, sequenceCache = /* @__PURE__ */ new Map()) => {
1831
+ const sequences = [];
1832
+ for (const char of compound.operandList) {
1833
+ const glyph = repertoire[char]?.glyph;
1834
+ if (glyph === void 0)
1835
+ return new InvalidGlyphError();
1836
+ if (glyph.type === "basic_component") {
1837
+ sequences.push(glyph.strokes.map((x) => classifier[x.feature]).join(""));
1838
+ } else {
1839
+ const cache = sequenceCache.get(char);
1840
+ if (cache !== void 0) {
1841
+ sequences.push(cache);
1842
+ continue;
1843
+ }
1844
+ const rendered = recursiveRenderStrokeSequence(
1845
+ glyph,
1846
+ repertoire,
1847
+ sequenceCache
1848
+ );
1849
+ if (rendered instanceof Error)
1850
+ return rendered;
1851
+ sequences.push(rendered);
1852
+ sequenceCache.set(char, rendered);
1853
+ }
1854
+ }
1855
+ const { order: order3 } = compound;
1856
+ if (order3 === void 0) {
1857
+ return sequences.join("");
1858
+ } else {
1859
+ const merged = [];
1860
+ for (const { index, strokes } of order3) {
1861
+ const seq = sequences[index];
1862
+ if (seq === void 0)
1863
+ continue;
1864
+ if (strokes === 0) {
1865
+ merged.push(seq);
1866
+ } else {
1867
+ merged.push(seq.slice(0, strokes));
1868
+ sequences[index] = seq.slice(strokes);
1869
+ }
1870
+ }
1871
+ return merged.join("");
1872
+ }
1873
+ };
1874
+ var topologicalSort = (repertoire, required, config) => {
1875
+ let compounds = /* @__PURE__ */ new Map();
1876
+ for (let i = 0; i !== 10; ++i) {
1877
+ const thisLevelCompound = /* @__PURE__ */ new Map();
1878
+ for (const [name, character] of Object.entries(repertoire)) {
1879
+ if (!required.has(name) || compounds.get(name))
1880
+ continue;
1881
+ const { glyph } = character;
1882
+ if (glyph === void 0 || glyph.type !== "compound")
1883
+ continue;
1884
+ const wellKnown = glyph.operandList.every(
1885
+ (x) => repertoire[x]?.glyph?.type === "basic_component" || compounds.get(x) !== void 0
1886
+ );
1887
+ const isRoot = config.roots.has(name) && !config.optionalRoots.has(name);
1888
+ if (wellKnown || isRoot) {
1889
+ thisLevelCompound.set(name, character);
1890
+ }
1891
+ }
1892
+ compounds = new Map([...compounds, ...thisLevelCompound]);
1893
+ }
1894
+ return compounds;
1895
+ };
1896
+ var sequentialSerializer = (operandResults, glyph) => {
1897
+ const rest = {
1898
+ operator: glyph.operator,
1899
+ operandResults
1900
+ };
1901
+ if (glyph.order === void 0) {
1902
+ const full2 = operandResults.flatMap((x) => x.full);
1903
+ return { sequence: [...full2], full: full2, ...rest };
1904
+ }
1905
+ const full = [];
1906
+ const subsequences = operandResults.map((x) => ({
1907
+ rest: x.full,
1908
+ taken: 0
1909
+ }));
1910
+ for (const { index, strokes } of glyph.order) {
1911
+ const data = subsequences[index];
1912
+ if (data === void 0) {
1913
+ continue;
1914
+ }
1915
+ if (strokes === 0) {
1916
+ full.push(...data.rest);
1917
+ data.rest = [];
1918
+ } else {
1919
+ const partitionResult = operandResults[index];
1920
+ if ("schemes" in partitionResult) {
1921
+ const { best, strokes: totalStrokes } = partitionResult;
1922
+ const upperBound = 1 << totalStrokes - data.taken;
1923
+ const lowerBound = 1 << totalStrokes - data.taken - strokes;
1924
+ const toTake = best.scheme.filter(
1925
+ (binary) => binary >= lowerBound && binary < upperBound
1926
+ ).length;
1927
+ full.push(...data.rest.slice(0, toTake));
1928
+ data.rest = data.rest.slice(toTake);
1929
+ } else {
1930
+ full.push(...data.rest);
1931
+ data.rest = [];
1932
+ }
1933
+ }
1934
+ }
1935
+ return { sequence: [...full], full, ...rest };
1936
+ };
1937
+ var zhenmaSerializer = (operandResults, glyph) => {
1938
+ const sequence = [];
1939
+ if (glyph.operator === "\u2FF6") {
1940
+ sequence.push(...operandResults[1].sequence);
1941
+ sequence.push(...operandResults[0].sequence);
1942
+ } else {
1943
+ operandResults.map((x) => x.sequence).forEach((x) => sequence.push(...x));
1944
+ }
1945
+ return {
1946
+ sequence,
1947
+ full: [],
1948
+ operator: glyph.operator,
1949
+ operandResults
1950
+ };
1951
+ };
1952
+ var regularize = (x, direction) => {
1953
+ const result = [];
1954
+ const regex = direction === "\u2FF0" ? /[⿰⿲]/ : /[⿱⿳]/;
1955
+ for (const part of x) {
1956
+ if (result.length < 2 && "operandResults" in part && regex.test(part.operator)) {
1957
+ result.push(...part.operandResults);
1958
+ } else {
1959
+ result.push(part);
1960
+ }
1961
+ }
1962
+ return result;
1963
+ };
1964
+ var zhangmaSerializer = (operandResults, glyph) => {
1965
+ const sequence = [];
1966
+ const full = [];
1967
+ if (glyph.operator === "\u2FF6" || glyph.operator === "\u2FFA" && glyph.operandList[0] === "\uE09D") {
1968
+ for (const part of operandResults.reverse())
1969
+ full.push(...part.full);
1970
+ } else {
1971
+ for (const part of operandResults)
1972
+ full.push(...part.full);
1973
+ }
1974
+ const getShouMo = (x) => x.length === 1 ? x : [x[0], x.at(-1)];
1975
+ const regularizedResults = operandResults.length === 2 && /[⿰⿱]/.test(glyph.operator) ? regularize(operandResults, glyph.operator) : operandResults;
1976
+ if (/[⿱⿳]/.test(glyph.operator)) {
1977
+ const dieyanIndex = regularizedResults.findIndex(
1978
+ (x) => "operandResults" in x && /[⿰⿲]/.test(x.operator)
1979
+ );
1980
+ const dieyan = regularizedResults.at(
1981
+ dieyanIndex
1982
+ );
1983
+ const aboveDieyanSequence = [];
1984
+ switch (dieyanIndex) {
1985
+ case -1:
1986
+ for (const part of regularizedResults)
1987
+ sequence.push(...part.full);
1988
+ break;
1989
+ case 0:
1990
+ for (const part of dieyan.operandResults)
1991
+ sequence.push(...part.full[0]);
1992
+ if (regularizedResults.length > 2) {
1993
+ sequence.push(regularizedResults[1]?.full[0]);
1994
+ sequence.push(regularizedResults.at(-1)?.full.at(-1));
1995
+ } else {
1996
+ sequence.push(...getShouMo(regularizedResults[1].full));
1997
+ }
1998
+ break;
1999
+ default:
2000
+ for (let index = 0; index < dieyanIndex; ++index) {
2001
+ aboveDieyanSequence.push(...regularizedResults[index].full);
2002
+ }
2003
+ sequence.push(...aboveDieyanSequence.slice(0, 2));
2004
+ if (dieyanIndex + 1 < regularizedResults.length) {
2005
+ sequence.push(dieyan.operandResults[0]?.full[0]);
2006
+ if (sequence.length === 2) {
2007
+ sequence.push(dieyan.operandResults.at(-1)?.full[0]);
2008
+ }
2009
+ sequence.push(regularizedResults.at(-1)?.full.at(-1));
2010
+ } else {
2011
+ sequence.push(...dieyan.full);
2012
+ }
2013
+ }
2014
+ } else if (/[⿰⿲]/.test(glyph.operator)) {
2015
+ const left2 = regularizedResults[0];
2016
+ if ("operandResults" in left2 && /[⿱⿳]/.test(left2.operator)) {
2017
+ const dieyanIndex = left2.operandResults.findIndex(
2018
+ (x) => "operandResults" in x && /[⿰⿲]/.test(x.operator)
2019
+ );
2020
+ const dieyan = left2.operandResults.at(
2021
+ dieyanIndex
2022
+ );
2023
+ if (dieyanIndex !== -1) {
2024
+ sequence.push(left2.operandResults[0]?.full[0]);
2025
+ if (dieyanIndex === 0)
2026
+ sequence.push(dieyan.operandResults.at(-1)?.full[0]);
2027
+ else
2028
+ sequence.push(dieyan.operandResults[0]?.full[0]);
2029
+ sequence.push(left2.operandResults.at(-1)?.full.at(-1));
2030
+ }
2031
+ }
2032
+ if (sequence.length > 0) {
2033
+ sequence.push(regularizedResults.at(-1)?.full.at(-1));
2034
+ } else {
2035
+ sequence.push(...getShouMo(left2.full));
2036
+ if (regularizedResults.length > 2) {
2037
+ sequence.push(...getShouMo(regularizedResults[1].full));
2038
+ }
2039
+ if (sequence.length === 4)
2040
+ sequence.pop();
2041
+ for (let index = Math.min(2, regularizedResults.length - 1); index < regularizedResults.length; ++index) {
2042
+ sequence.push(...regularizedResults[index].full);
2043
+ }
2044
+ }
2045
+ } else {
2046
+ sequence.push(...full);
2047
+ }
2048
+ return {
2049
+ sequence,
2050
+ full,
2051
+ operator: glyph.operator,
2052
+ operandResults: regularizedResults
2053
+ };
2054
+ };
2055
+ var snow2Serializer = (operandResults, glyph) => {
2056
+ const order3 = glyph.order ?? glyph.operandList.map((_, i) => ({ index: i, strokes: 0 }));
2057
+ const sortedOperandResults = sortBy(
2058
+ range2(operandResults.length),
2059
+ (i) => order3.findIndex((b) => b.index === i)
2060
+ ).map((i) => operandResults[i]);
2061
+ const first2 = sortedOperandResults[0];
2062
+ const second = sortedOperandResults[1];
2063
+ const marker = first2.full.length == 1 ? second.full.length == 1 ? "q" : "e" : second.full.length == 1 ? "w" : "r";
2064
+ const full = [first2.sequence[0], second.sequence[0]];
2065
+ const sequence = [...full, marker];
2066
+ return {
2067
+ sequence,
2068
+ full,
2069
+ operator: glyph.operator,
2070
+ operandResults
2071
+ };
2072
+ };
2073
+ var limit = (sequence, maximum, config) => {
2074
+ let codes = 0;
2075
+ const { roots } = config;
2076
+ const final = [];
2077
+ for (const x of sequence) {
2078
+ if (x === "\xB7") {
2079
+ final.push(x);
2080
+ continue;
2081
+ }
2082
+ const length2 = 1;
2083
+ codes += length2;
2084
+ final.push(x);
2085
+ if (codes >= maximum)
2086
+ break;
2087
+ }
2088
+ return final;
2089
+ };
2090
+ var xkjdSerializer = (operandResults, glyph, config) => {
2091
+ const { roots: primaryRoots } = config;
2092
+ const order3 = glyph.order ?? glyph.operandList.map((_, i) => ({ index: i, strokes: 0 }));
2093
+ const sequence = [];
2094
+ const full = [];
2095
+ const sequential = sequentialSerializer(operandResults, glyph, config);
2096
+ full.push(...sequential.full);
2097
+ if (order3[0]?.strokes !== 1) {
2098
+ const sortedOperandResults = sortBy(
2099
+ range2(operandResults.length),
2100
+ (i) => order3.findIndex((b) => b.index === i)
2101
+ ).map((i) => operandResults[i]);
2102
+ for (const [index, part] of sortedOperandResults.entries()) {
2103
+ if (index === 0) {
2104
+ let codes = 0;
2105
+ for (const x of part.full) {
2106
+ const length2 = 1;
2107
+ if (codes === 1 && length2 > 1) {
2108
+ const equivalent = {
2109
+ \u571F: "1",
2110
+ \u8279: "2",
2111
+ \u91D1: "2",
2112
+ \u624B: "2",
2113
+ \u5341: "3",
2114
+ \u65E5: "4",
2115
+ \u8D1D: "5"
2116
+ };
2117
+ sequence.push(equivalent[x] ?? "1");
2118
+ } else {
2119
+ sequence.push(x);
2120
+ }
2121
+ codes += length2;
2122
+ if (codes >= 2)
2123
+ break;
2124
+ }
2125
+ } else {
2126
+ sequence.push(...part.full);
2127
+ }
2128
+ }
2129
+ } else {
2130
+ sequence.push(...sequential.sequence);
2131
+ }
2132
+ const finalSequence = limit(sequence, 4, config);
2133
+ return {
2134
+ sequence: finalSequence,
2135
+ full,
2136
+ operator: glyph.operator,
2137
+ operandResults
2138
+ };
2139
+ };
2140
+ var shouyouSerializer = (operandResults, glyph, config) => {
2141
+ const order3 = glyph.order ?? glyph.operandList.map((_, i) => ({ index: i, strokes: 0 }));
2142
+ const sortedOperandResults = sortBy(
2143
+ range2(operandResults.length),
2144
+ (i) => order3.findIndex((b) => b.index === i)
2145
+ ).map((i) => operandResults[i]);
2146
+ const first2 = sortedOperandResults[0];
2147
+ const second = sortedOperandResults[1];
2148
+ let sequence;
2149
+ const full = sequentialSerializer(operandResults, glyph, config).full;
2150
+ if (/[⿰⿲]/.test(glyph.operator) || glyph.operator === "\u2FFA" && order3[0].index === 0)
2151
+ sequence = [first2.full[0], second.full[0]];
2152
+ else {
2153
+ sequence = [...full];
2154
+ }
2155
+ return {
2156
+ sequence,
2157
+ full,
2158
+ operator: glyph.operator,
2159
+ operandResults
2160
+ };
2161
+ };
2162
+ var feihuaSerializer = (operandResults, glyph, config) => {
2163
+ const order3 = glyph.order ?? glyph.operandList.map((_, i) => ({ index: i, strokes: 0 }));
2164
+ const sortedOperandResults = sortBy(
2165
+ range2(operandResults.length),
2166
+ (i) => order3.findIndex((b) => b.index === i)
2167
+ ).map((i) => operandResults[i]);
2168
+ const sequence = [];
2169
+ const first2 = sortedOperandResults[0];
2170
+ const last = sortedOperandResults.at(-1);
2171
+ const handleResidual = (sequence2, parts) => {
2172
+ if (parts.length > 1) {
2173
+ for (const x of parts) {
2174
+ sequence2.push(...x.full2[0]);
2175
+ }
2176
+ } else {
2177
+ const part = parts[0];
2178
+ if ("operandResults" in part) {
2179
+ for (const x of part.operandResults) {
2180
+ sequence2.push(...x.full2[0]);
2181
+ }
2182
+ } else {
2183
+ sequence2.push(...part.full2);
2184
+ }
2185
+ }
2186
+ };
2187
+ if (/[⿴⿵⿶⿷⿸⿹⿺⿼⿽⿻]/.test(glyph.operator) && "strokes" in operandResults[0]) {
2188
+ sequence.push(operandResults[0].full[0]);
2189
+ handleResidual(sequence, operandResults.slice(1));
2190
+ } else if (first2.full.length === 1 && /[又]/.test(first2.full[0]) && last.full.length === 1) {
2191
+ sequence.push(last.full[0]);
2192
+ handleResidual(sequence, sortedOperandResults.slice(0, -1));
2193
+ } else if (first2.full.length !== 1 && last.full.length === 1) {
2194
+ sequence.push(last.full[0]);
2195
+ handleResidual(sequence, sortedOperandResults.slice(0, -1));
2196
+ } else {
2197
+ sequence.push(first2.full[0]);
2198
+ handleResidual(sequence, sortedOperandResults.slice(1));
2199
+ }
2200
+ const full = sequentialSerializer(operandResults, glyph, config).full;
2201
+ const backups = operandResults.map((x) => x.full);
2202
+ operandResults.forEach((part) => {
2203
+ part.full = [...part.full2];
2204
+ });
2205
+ const full2 = sequentialSerializer(operandResults, glyph, config).full;
2206
+ operandResults.forEach((part, i) => {
2207
+ part.full = backups[i];
2208
+ });
2209
+ return {
2210
+ sequence,
2211
+ full,
2212
+ full2,
2213
+ operator: glyph.operator,
2214
+ operandResults
2215
+ };
2216
+ };
2217
+ var erbiSerializer = (operandResults, glyph, config) => {
2218
+ const order3 = glyph.order ?? glyph.operandList.map((_, i) => ({ index: i, strokes: 0 }));
2219
+ const sortedOperandResults = sortBy(
2220
+ range2(operandResults.length),
2221
+ (i) => order3.findIndex((b) => b.index === i)
2222
+ ).map((i) => operandResults[i]);
2223
+ const sequence = [];
2224
+ for (const [index, part] of sortedOperandResults.entries()) {
2225
+ if (index === sortedOperandResults.length - 1)
2226
+ sequence.push(...part.sequence);
2227
+ else
2228
+ sequence.push(part.sequence[0]);
2229
+ }
2230
+ return {
2231
+ sequence,
2232
+ full: sequence,
2233
+ operator: glyph.operator,
2234
+ operandResults
2235
+ };
2236
+ };
2237
+ var serializerTypes = [
2238
+ "sequential",
2239
+ "zhangma",
2240
+ "zhenma",
2241
+ "snow2",
2242
+ "xkjd",
2243
+ "shouyou",
2244
+ "feihua",
2245
+ "erbi"
2246
+ ];
2247
+ var serializerMap = {
2248
+ sequential: sequentialSerializer,
2249
+ zhangma: zhangmaSerializer,
2250
+ zhenma: zhenmaSerializer,
2251
+ snow2: snow2Serializer,
2252
+ xkjd: xkjdSerializer,
2253
+ shouyou: shouyouSerializer,
2254
+ feihua: feihuaSerializer,
2255
+ erbi: erbiSerializer
2256
+ };
2257
+ var disassembleCompounds = (repertoire, config, componentResults, characters, requiredCompounds) => {
2258
+ const knownCharacters = new Set(characters);
2259
+ const compounds = topologicalSort(repertoire, requiredCompounds, config);
2260
+ const compoundResults = /* @__PURE__ */ new Map();
2261
+ const compoundError = [];
2262
+ const getResult = (s) => componentResults.get(s) || compoundResults.get(s);
2263
+ const serializerName = config.analysis.serializer ?? "sequential";
2264
+ const serializer = serializerMap[serializerName] ?? sequentialSerializer;
2265
+ if (serializerName === "xkjd") {
2266
+ for (const [_, result] of componentResults.entries()) {
2267
+ result.sequence = limit(result.sequence, 4, config);
2268
+ }
2269
+ } else if (serializerName === "snow2") {
2270
+ for (const [key, result] of componentResults.entries()) {
2271
+ result.sequence = result.sequence.slice(0, 1);
2272
+ if (result.sequence[0] !== key)
2273
+ result.sequence.push("");
2274
+ }
2275
+ } else if (serializerName === "feihua") {
2276
+ for (const [key, result] of componentResults.entries()) {
2277
+ if ("schemes" in result) {
2278
+ const dc = config.analysis?.dynamic_customize ?? {};
2279
+ const schemeList = dc[key] ?? result.schemes.filter((x) => x.optional).map((x) => x.roots);
2280
+ const scheme = schemeList.find(
2281
+ (x) => x.every((r2) => {
2282
+ let value = config.roots.get(r2);
2283
+ while (isMerge(value)) {
2284
+ value = config.roots.get(value.element);
2285
+ }
2286
+ return /[aoeiuv;/]/.test(value);
2287
+ })
2288
+ );
2289
+ result.full2 = scheme;
2290
+ result.sequence = scheme.slice(0, 3);
2291
+ } else {
2292
+ result.full2 = [...result.full];
2293
+ }
2294
+ }
2295
+ }
2296
+ for (const [char, { glyph }] of compounds.entries()) {
2297
+ if (config.roots.has(char)) {
2298
+ if (serializerName === "feihua") {
2299
+ const rawOperandResults2 = glyph.operandList.map(getResult);
2300
+ const operandResults = rawOperandResults2;
2301
+ const serialization = serializer(operandResults, glyph, config);
2302
+ serialization.full = [char];
2303
+ let value = config.roots.get(char);
2304
+ while (isMerge(value)) {
2305
+ value = config.roots.get(value.element);
2306
+ }
2307
+ if (/[aoeiuv;/]/.test(value)) {
2308
+ serialization.full2 = [char];
2309
+ }
2310
+ compoundResults.set(char, serialization);
2311
+ continue;
2312
+ }
2313
+ const sequence = [char];
2314
+ if (serializerName === "snow2") {
2315
+ sequence.push("q");
2316
+ }
2317
+ compoundResults.set(char, {
2318
+ sequence,
2319
+ full: [char],
2320
+ // @ts-ignore
2321
+ full2: [char],
2322
+ strokes: 0,
2323
+ operator: void 0
2324
+ });
2325
+ continue;
2326
+ }
2327
+ const rawOperandResults = glyph.operandList.map(getResult);
2328
+ if (rawOperandResults.every((x) => x !== void 0)) {
2329
+ const operandResults = rawOperandResults;
2330
+ const serialization = serializer(operandResults, glyph, config);
2331
+ compoundResults.set(char, serialization);
2332
+ } else {
2333
+ if (knownCharacters.has(char)) {
2334
+ compoundError.push(char);
2335
+ }
2336
+ }
2337
+ }
2338
+ return [compoundResults, compoundError];
2339
+ };
2340
+
2341
+ // src/component.ts
2342
+ var InvalidGlyphError = class extends Error {
2343
+ };
2344
+ var makeIntervalSum = (strokes, rootsSet) => {
2345
+ const array = [...Array(strokes).keys()].map((x) => 1 << x).reverse();
2346
+ const intervalSums = /* @__PURE__ */ new Set();
2347
+ for (let start = 0; start !== strokes - 1; ++start) {
2348
+ let sum = array[start];
2349
+ for (let end = start + 1; end !== strokes; ++end) {
2350
+ sum += array[end];
2351
+ if (rootsSet.has(sum)) {
2352
+ intervalSums.add(sum);
2353
+ }
2354
+ }
2355
+ }
2356
+ return intervalSums;
2357
+ };
2358
+ var generateSchemes = (strokes, roots, requiredRoots) => {
2359
+ const schemeList = [];
2360
+ const total = (1 << strokes) - 1;
2361
+ const intervalSums = makeIntervalSum(strokes, requiredRoots);
2362
+ const combineNext = (partialSum, scheme, revcumsum) => {
2363
+ const restBin = total - partialSum;
2364
+ const restBin1st = 1 << restBin.toString(2).length - 1;
2365
+ const start = bisectLeft(roots, restBin1st);
2366
+ const end = bisectRight(roots, restBin);
2367
+ for (const binary of roots.slice(start, end)) {
2368
+ if ((partialSum & binary) !== 0)
2369
+ continue;
2370
+ const newPartialSum = partialSum + binary;
2371
+ const newRevcumsum = revcumsum.map((x) => x + binary);
2372
+ const newScheme = scheme.concat(binary);
2373
+ if (newRevcumsum.some((x) => intervalSums.has(x))) {
2374
+ continue;
2375
+ }
2376
+ newRevcumsum.push(binary);
2377
+ if (newPartialSum === total) {
2378
+ schemeList.push(newScheme);
2379
+ } else {
2380
+ combineNext(newPartialSum, newScheme, newRevcumsum);
2381
+ }
2382
+ }
2383
+ };
2384
+ combineNext(0, [], []);
2385
+ return schemeList;
2386
+ };
2387
+ var NoSchemeError = class extends Error {
2388
+ };
2389
+ var MultipleSchemeError2 = class extends Error {
2390
+ };
2391
+ var getComponentScheme = (component, rootData, config, classifier2) => {
2392
+ const currentRoots = /* @__PURE__ */ new Set([...config.roots.keys()]);
2393
+ const optionalRoots = /* @__PURE__ */ new Set([...config.optionalRoots.keys()]);
2394
+ const requiredRoots = new Set(
2395
+ [...currentRoots].filter((x) => !optionalRoots.has(x))
2396
+ );
2397
+ if (requiredRoots.has(component.name))
2398
+ return {
2399
+ strokes: component.glyph.length,
2400
+ sequence: [component.name],
2401
+ full: [component.name],
2402
+ operator: void 0
2403
+ };
2404
+ if (config.analysis.serializer === "erbi") {
2405
+ const firstStroke = component.glyph[0];
2406
+ const secondStroke = component.glyph[1];
2407
+ const first2 = classifier2[firstStroke.feature].toString();
2408
+ const second = secondStroke ? classifier2[secondStroke.feature].toString() : "0";
2409
+ const sequence2 = [first2 + second];
2410
+ if (component.glyph.length > 2) {
2411
+ const lastStroke = component.glyph[component.glyph.length - 1];
2412
+ const last = classifier2[lastStroke.feature].toString();
2413
+ sequence2.push(last);
2414
+ }
2415
+ return {
2416
+ strokes: component.glyph.length,
2417
+ sequence: sequence2,
2418
+ full: sequence2,
2419
+ operator: void 0
2420
+ };
2421
+ }
2422
+ const rootMap = new Map(
2423
+ component.glyph.map((stroke, index) => {
2424
+ const binary = 1 << component.glyph.length - 1 - index;
2425
+ return [binary, classifier2[stroke.feature].toString()];
2426
+ })
2427
+ );
2428
+ for (const root of rootData) {
2429
+ const binaries = generateSliceBinaries(
2430
+ config.analysis?.degenerator ?? defaultDegenerator,
2431
+ component,
2432
+ root
2433
+ );
2434
+ binaries.forEach((binary) => rootMap.set(binary, root.name));
2435
+ }
2436
+ const roots = Array.from(rootMap.keys()).sort((a, b) => a - b);
2437
+ const requiredRootsBinary = new Set(
2438
+ [...rootMap].filter(([K, v]) => requiredRoots.has(v)).map(([K, v]) => K)
2439
+ );
2440
+ const schemeList = generateSchemes(
2441
+ component.glyph.length,
2442
+ roots,
2443
+ requiredRootsBinary
2444
+ );
2445
+ if (schemeList.length === 0) {
2446
+ return new NoSchemeError();
2447
+ }
2448
+ const selectResult = select(
2449
+ config,
2450
+ component,
2451
+ schemeList,
2452
+ rootMap,
2453
+ requiredRootsBinary
2454
+ );
2455
+ if (selectResult instanceof Error) {
2456
+ return selectResult;
2457
+ }
2458
+ const best = selectResult.find(
2459
+ (x) => x.scheme.every(
2460
+ (y) => currentRoots.has(rootMap.get(y)) || /\d/.test(rootMap.get(y))
2461
+ )
2462
+ );
2463
+ let sequence = best.scheme.map((n) => rootMap.get(n));
2464
+ return {
2465
+ sequence,
2466
+ full: [...sequence],
2467
+ strokes: component.glyph.length,
2468
+ map: rootMap,
2469
+ best,
2470
+ schemes: selectResult,
2471
+ operator: void 0
2472
+ };
2473
+ };
2474
+ var recursiveRenderComponent = (component, repertoire, glyphCache = /* @__PURE__ */ new Map(), depth = 0) => {
2475
+ if (depth > 100) {
2476
+ console.error("Recursion depth exceeded", component);
2477
+ return new InvalidGlyphError();
2478
+ }
2479
+ if (component.type === "basic_component")
2480
+ return component.strokes;
2481
+ if (component.type === "derived_component") {
2482
+ const sourceComponent = repertoire[component.source]?.glyphs?.find?.(isComponent);
2483
+ if (sourceComponent === void 0)
2484
+ return new InvalidGlyphError();
2485
+ const sourceGlyph = recursiveRenderComponent(
2486
+ sourceComponent,
2487
+ repertoire,
2488
+ glyphCache,
2489
+ depth + 1
2490
+ );
2491
+ if (sourceGlyph instanceof InvalidGlyphError)
2492
+ return sourceGlyph;
2493
+ const glyph = [];
2494
+ component.strokes.forEach((x) => {
2495
+ if (x.feature === "reference") {
2496
+ const sourceStroke = sourceGlyph[x.index];
2497
+ if (sourceStroke === void 0)
2498
+ return;
2499
+ glyph.push(sourceStroke);
2500
+ } else {
2501
+ glyph.push(x);
2502
+ }
2503
+ });
2504
+ return glyph;
2505
+ }
2506
+ if (component.type === "spliced_component") {
2507
+ const glyphs = [];
2508
+ for (const name of component.operandList) {
2509
+ const sourceComponent = repertoire[name]?.glyphs?.find?.(isComponent);
2510
+ if (sourceComponent === void 0)
2511
+ return new InvalidGlyphError();
2512
+ const sourceGlyph = recursiveRenderComponent(
2513
+ sourceComponent,
2514
+ repertoire,
2515
+ glyphCache,
2516
+ depth + 1
2517
+ );
2518
+ if (sourceGlyph instanceof InvalidGlyphError)
2519
+ return sourceGlyph;
2520
+ const box = getGlyphBoundingBox(sourceGlyph);
2521
+ glyphs.push({ strokes: sourceGlyph, box });
2522
+ }
2523
+ const asCompound = { ...component, type: "compound" };
2524
+ return affineMerge(asCompound, glyphs).strokes;
2525
+ }
2526
+ if (component.type === "identity") {
2527
+ const sourceComponent = repertoire[component.source]?.glyphs?.find?.(isComponent);
2528
+ if (sourceComponent === void 0)
2529
+ return new InvalidGlyphError();
2530
+ return recursiveRenderComponent(
2531
+ sourceComponent,
2532
+ repertoire,
2533
+ glyphCache,
2534
+ depth + 1
2535
+ );
2536
+ }
2537
+ return new InvalidGlyphError();
2538
+ };
2539
+ var computeComponent = (name, svgglyph) => {
2540
+ const glyph = renderSVGGlyph(svgglyph);
2541
+ const topology = findTopology(glyph);
2542
+ const cache = { glyph, topology, name };
2543
+ return cache;
2544
+ };
2545
+ var renderRootList = (repertoire, elements) => {
2546
+ const rootList = /* @__PURE__ */ new Map();
2547
+ for (const root of elements) {
2548
+ const glyph = repertoire[root]?.glyph;
2549
+ if (glyph === void 0)
2550
+ continue;
2551
+ if (glyph.type === "basic_component") {
2552
+ rootList.set(root, computeComponent(root, glyph.strokes));
2553
+ } else {
2554
+ const rendered = recursiveRenderCompound(glyph, repertoire);
2555
+ if (rendered instanceof Error)
2556
+ continue;
2557
+ rootList.set(root, computeComponent(root, rendered.strokes));
2558
+ }
2559
+ }
2560
+ return rootList;
2561
+ };
2562
+ var disassembleComponents = (repertoire, config, characters, components) => {
2563
+ const rootMap = renderRootList(repertoire, [
2564
+ ...config.roots.keys(),
2565
+ ...config.optionalRoots.keys()
2566
+ ]);
2567
+ const rootList = [...rootMap.values()];
2568
+ const classifier2 = mergeClassifier(config.analysis?.classifier);
2569
+ const result = [];
2570
+ const error = [];
2571
+ Object.entries(repertoire).forEach(([name, character]) => {
2572
+ if (character.glyph?.type !== "basic_component" || !components.has(name))
2573
+ return;
2574
+ const cache = rootMap.has(name) ? rootMap.get(name) : computeComponent(name, character.glyph.strokes);
2575
+ const scheme = getComponentScheme(cache, rootList, config, classifier2);
2576
+ if (scheme instanceof Error) {
2577
+ error.push(name);
2578
+ } else {
2579
+ result.push([name, scheme]);
2580
+ }
2581
+ });
2582
+ result.sort((a, b) => {
2583
+ return a[1].strokes - b[1].strokes;
2584
+ });
2585
+ return [new Map(result), error];
2586
+ };
2587
+
2588
+ // src/repertoire.ts
2589
+ import { range as range3 } from "d3-array";
2590
+ var findGlyphIndex = (glyphs, tags) => {
2591
+ for (const tag of tags) {
2592
+ const withTag = glyphs.findIndex((x) => (x.tags ?? []).includes(tag));
2593
+ if (withTag !== -1)
2594
+ return withTag;
2595
+ }
2596
+ return 0;
2597
+ };
2598
+ var determine = (repertoire, customGlyph = {}, customReadings = {}, tags = []) => {
2599
+ const determined = {};
2600
+ const glyphCache = /* @__PURE__ */ new Map();
2601
+ for (const [name, character] of Object.entries(repertoire)) {
2602
+ const { ambiguous: _, glyphs, readings, ...rest } = character;
2603
+ const selectedIndex = findGlyphIndex(glyphs, tags);
2604
+ const rawglyph = customGlyph[name] ?? glyphs[selectedIndex] ?? getDummyBasicComponent();
2605
+ const glyph = recursiveHandleRawGlyph(rawglyph, glyphCache, repertoire);
2606
+ const finalReadings = customReadings[name] ?? readings;
2607
+ const determined_character = {
2608
+ ...rest,
2609
+ glyph,
2610
+ readings: finalReadings
2611
+ };
2612
+ determined[name] = determined_character;
2613
+ }
2614
+ return determined;
2615
+ };
2616
+ function recursiveHandleRawGlyph(glyph, glyphCache, repertoire) {
2617
+ if (glyph.type === "derived_component" || glyph.type === "spliced_component") {
2618
+ const svgglyph = recursiveRenderComponent(glyph, repertoire, glyphCache);
2619
+ return {
2620
+ type: "basic_component",
2621
+ tags: glyph.tags,
2622
+ strokes: svgglyph instanceof Error ? [] : svgglyph
2623
+ };
2624
+ } else if (glyph.type === "identity") {
2625
+ return recursiveHandleRawGlyph(
2626
+ repertoire[glyph.source].glyphs[0],
2627
+ glyphCache,
2628
+ repertoire
2629
+ );
2630
+ } else {
2631
+ return glyph;
2632
+ }
2633
+ }
2634
+ var getRootSequence = (repertoire, config) => {
2635
+ const classifier2 = mergeClassifier(config.analysis?.classifier);
2636
+ const findSequence = (x) => {
2637
+ if (x.match(/[0-9]+/)) {
2638
+ return [...x].map(Number);
2639
+ }
2640
+ const glyph = repertoire[x]?.glyph;
2641
+ if (glyph === void 0) {
2642
+ return [];
2643
+ }
2644
+ if (glyph.type === "basic_component") {
2645
+ return glyph.strokes.map((s) => classifier2[s.feature]);
2646
+ }
2647
+ const sequence = recursiveRenderCompound(glyph, repertoire);
2648
+ if (sequence instanceof Error)
2649
+ return [];
2650
+ return sequence.strokes.map((s) => classifier2[s.feature]);
2651
+ };
2652
+ const rootSequence = /* @__PURE__ */ new Map();
2653
+ const roots = /* @__PURE__ */ new Set([
2654
+ ...config.roots.keys(),
2655
+ ...config.optionalRoots.keys()
2656
+ ]);
2657
+ for (const root of roots) {
2658
+ rootSequence.set(root, findSequence(root));
2659
+ }
2660
+ for (const num of Object.values(classifier2)) {
2661
+ rootSequence.set(num.toString(), [num]);
2662
+ }
2663
+ return rootSequence;
2664
+ };
2665
+ var getRequiredTargets = (repertoire, config, characters) => {
2666
+ const queue = [...characters];
2667
+ const components = /* @__PURE__ */ new Set();
2668
+ const compounds = /* @__PURE__ */ new Set();
2669
+ const knownSet = new Set(characters);
2670
+ while (queue.length) {
2671
+ const char = queue.shift();
2672
+ const glyph = repertoire[char].glyph;
2673
+ if (glyph.type === "compound") {
2674
+ compounds.add(char);
2675
+ const isCurrentRoot = config.roots.has(char);
2676
+ const isOptionalRoot = config.optionalRoots.has(char);
2677
+ if (isCurrentRoot && !isOptionalRoot)
2678
+ continue;
2679
+ glyph.operandList.forEach((x) => {
2680
+ if (!knownSet.has(x)) {
2681
+ knownSet.add(x);
2682
+ queue.push(x);
2683
+ }
2684
+ });
2685
+ } else {
2686
+ components.add(char);
2687
+ }
2688
+ }
2689
+ return { components, compounds };
2690
+ };
2691
+ var analysis = (repertoire, config, characters) => {
2692
+ const { components, compounds } = getRequiredTargets(
2693
+ repertoire,
2694
+ config,
2695
+ characters
2696
+ );
2697
+ const [componentResults, componentError] = disassembleComponents(
2698
+ repertoire,
2699
+ config,
2700
+ characters,
2701
+ components
2702
+ );
2703
+ const customizations = /* @__PURE__ */ new Map();
2704
+ const customConfig = config.analysis?.customize ?? {};
2705
+ for (const [component, sequence] of Object.entries(customConfig)) {
2706
+ const previousResult = componentResults.get(component);
2707
+ if (previousResult === void 0)
2708
+ continue;
2709
+ if (previousResult !== void 0 && "best" in previousResult) {
2710
+ const maybeBetter = previousResult.schemes.find((x) => {
2711
+ const list = x.scheme.map((y) => previousResult.map.get(y));
2712
+ return isEqual4(list, sequence);
2713
+ });
2714
+ if (maybeBetter !== void 0) {
2715
+ const genuineResult = {
2716
+ ...previousResult,
2717
+ best: maybeBetter,
2718
+ sequence,
2719
+ full: sequence
2720
+ };
2721
+ customizations.set(component, genuineResult);
2722
+ continue;
2723
+ }
2724
+ }
2725
+ const pseudoResult = {
2726
+ strokes: 0,
2727
+ sequence,
2728
+ full: sequence,
2729
+ operator: void 0
2730
+ };
2731
+ customizations.set(component, pseudoResult);
2732
+ }
2733
+ const all = /* @__PURE__ */ new Set([...config.roots.keys()]);
2734
+ for (const [component, sequenceList] of Object.entries(
2735
+ config.analysis?.dynamic_customize ?? {}
2736
+ )) {
2737
+ const previousResult = componentResults.get(
2738
+ component
2739
+ );
2740
+ for (const sequence of sequenceList) {
2741
+ if (!sequence.every((x) => /\d/.test(x) || all.has(x)))
2742
+ continue;
2743
+ const pseudoResult = {
2744
+ ...previousResult,
2745
+ sequence,
2746
+ full: sequence
2747
+ };
2748
+ customizations.set(component, pseudoResult);
2749
+ break;
2750
+ }
2751
+ }
2752
+ const customized = new Map([...componentResults, ...customizations]);
2753
+ const [compoundResults, compoundError] = disassembleCompounds(
2754
+ repertoire,
2755
+ config,
2756
+ customized,
2757
+ characters,
2758
+ compounds
2759
+ );
2760
+ const rootSequence = getRootSequence(repertoire, config);
2761
+ return {
2762
+ componentResults,
2763
+ componentError,
2764
+ customizations,
2765
+ customized,
2766
+ compoundResults,
2767
+ compoundError,
2768
+ rootSequence
2769
+ };
2770
+ };
2771
+ var dynamicAnalysis = (repertoire, config, characters, dictionary, adaptedFrequency, algebra) => {
2772
+ const { components, compounds } = getRequiredTargets(
2773
+ repertoire,
2774
+ config,
2775
+ characters
2776
+ );
2777
+ const [componentResults, componentError] = disassembleComponents(
2778
+ repertoire,
2779
+ config,
2780
+ characters,
2781
+ components
2782
+ );
2783
+ const segmentMap = /* @__PURE__ */ new Map();
2784
+ const segmentDynamicAnalysis = /* @__PURE__ */ new Map();
2785
+ const bushouMap = /* @__PURE__ */ new Map();
2786
+ for (const [name, analysis2] of componentResults) {
2787
+ const maybeCustomDynamicAnalysis = config.analysis.dynamic_customize?.[name];
2788
+ const dynamicAnalysis2 = "schemes" in analysis2 ? analysis2.schemes.filter((x) => x.optional).map((x) => x.roots) : [analysis2.sequence];
2789
+ segmentDynamicAnalysis.set(
2790
+ name,
2791
+ maybeCustomDynamicAnalysis ?? dynamicAnalysis2
2792
+ );
2793
+ segmentMap.set(name, [name]);
2794
+ }
2795
+ const sortedCompounds = topologicalSort(repertoire, compounds, config);
2796
+ const rootMap = renderRootList(repertoire, [
2797
+ ...config.roots.keys(),
2798
+ ...config.optionalRoots.keys()
2799
+ ]);
2800
+ const classifier2 = mergeClassifier(config.analysis?.classifier);
2801
+ const rootList = [...rootMap.values()];
2802
+ const cachedGetSegment = (part, start, end) => {
2803
+ const character = repertoire[part];
2804
+ const name = `${isPUA(part) ? character.name : part}.${start}-${end ?? 0}`;
2805
+ if (segmentDynamicAnalysis.has(name)) {
2806
+ return name;
2807
+ }
2808
+ if (character.glyph.type !== "basic_component") {
2809
+ console.log(`Cannot segment non-basic component: ${part}`);
2810
+ return name;
2811
+ }
2812
+ const glyph = character.glyph.strokes.slice(start, end);
2813
+ const cache = computeComponent(name, glyph);
2814
+ console.log(
2815
+ `Part: ${part} (${part.codePointAt(0)}) [${start}${end ? `-${end}` : ""}]`
2816
+ );
2817
+ const analysis2 = getComponentScheme(
2818
+ cache,
2819
+ rootList,
2820
+ config,
2821
+ classifier2
2822
+ );
2823
+ segmentDynamicAnalysis.set(
2824
+ name,
2825
+ analysis2.schemes.filter((x) => x.optional).map((x) => x.roots)
2826
+ );
2827
+ segmentMap.set(name, [name]);
2828
+ return name;
2829
+ };
2830
+ const fullSegmentMap = new Map(segmentMap.entries());
2831
+ for (const [name, compound] of sortedCompounds) {
2832
+ const isCurrentRoots = config.roots.has(name);
2833
+ const isOptionalRoots = config.optionalRoots.has(name);
2834
+ if (isCurrentRoots && !isOptionalRoots) {
2835
+ segmentDynamicAnalysis.set(name, [[name]]);
2836
+ segmentMap.set(name, [name]);
2837
+ fullSegmentMap.set(name, [name]);
2838
+ continue;
2839
+ }
2840
+ const glyph = compound.glyph;
2841
+ const componentList = [];
2842
+ const order3 = glyph.order ?? glyph.operandList.map((_, i) => ({ index: i, strokes: 0 }));
2843
+ if (config.analysis.serializer === "qingyun") {
2844
+ const seenIndex = /* @__PURE__ */ new Map();
2845
+ for (const { index, strokes } of order3) {
2846
+ const part = glyph.operandList[index];
2847
+ if (strokes === 0) {
2848
+ if (!seenIndex.has(index)) {
2849
+ componentList.push(...segmentMap.get(part));
2850
+ } else {
2851
+ const start = seenIndex.get(index);
2852
+ const name2 = cachedGetSegment(part, start);
2853
+ componentList.push(name2);
2854
+ }
2855
+ } else {
2856
+ const start = seenIndex.get(index) ?? 0;
2857
+ const end = start + strokes;
2858
+ const name2 = cachedGetSegment(part, start, end);
2859
+ componentList.push(name2);
2860
+ seenIndex.set(index, end);
2861
+ }
2862
+ }
2863
+ } else if (config.analysis.serializer === "feihua") {
2864
+ const sortedOperandList = sortBy2(
2865
+ range3(glyph.operandList.length),
2866
+ (i) => order3.findIndex((b) => b.index === i)
2867
+ ).map((i) => glyph.operandList[i]);
2868
+ const fullComponentList = [];
2869
+ for (const child of sortedOperandList) {
2870
+ fullComponentList.push(...fullSegmentMap.get(child));
2871
+ }
2872
+ fullSegmentMap.set(name, fullComponentList);
2873
+ const first2 = sortedOperandList[0];
2874
+ const last = sortedOperandList.at(-1);
2875
+ const firstDynamic = segmentDynamicAnalysis.get(first2);
2876
+ const lastDynamic = segmentDynamicAnalysis.get(last);
2877
+ const res = [];
2878
+ if (/[⿴⿵⿶⿷⿸⿹⿺⿼⿽⿻]/.test(glyph.operator) && componentResults.has(glyph.operandList[0])) {
2879
+ bushouMap.set(
2880
+ name,
2881
+ segmentDynamicAnalysis.get(glyph.operandList[0])[0][0]
2882
+ );
2883
+ res.push(...glyph.operandList.slice(1));
2884
+ } else if (firstDynamic?.[0]?.length === 1 && lastDynamic?.[0]?.length === 1 && /[又]/.test(firstDynamic[0][0])) {
2885
+ bushouMap.set(name, lastDynamic[0][0]);
2886
+ res.push(...sortedOperandList.slice(0, -1));
2887
+ } else if (firstDynamic?.[0]?.length === 1) {
2888
+ bushouMap.set(name, firstDynamic[0][0]);
2889
+ res.push(...sortedOperandList.slice(1));
2890
+ } else if (lastDynamic?.[0]?.length === 1) {
2891
+ bushouMap.set(name, lastDynamic[0][0]);
2892
+ res.push(...sortedOperandList.slice(0, -1));
2893
+ } else {
2894
+ const firstSegments = fullSegmentMap.get(first2);
2895
+ const segment = firstSegments[0];
2896
+ const bushou = segmentDynamicAnalysis.get(segment)[0][0];
2897
+ bushouMap.set(name, bushou);
2898
+ res.push(...sortedOperandList.slice(1));
2899
+ }
2900
+ if (res.length === 1) {
2901
+ const only = res[0];
2902
+ if (!sortedCompounds.has(only)) {
2903
+ componentList.push(...fullSegmentMap.get(only).slice(0, 2));
2904
+ } else {
2905
+ const subglyph = sortedCompounds.get(only).glyph;
2906
+ const order4 = subglyph.order ?? subglyph.operandList.map((_, i) => ({ index: i, strokes: 0 }));
2907
+ const sortedOperandList2 = sortBy2(
2908
+ range3(subglyph.operandList.length),
2909
+ (i) => order4.findIndex((b) => b.index === i)
2910
+ ).map((i) => subglyph.operandList[i]);
2911
+ for (const part of sortedOperandList2) {
2912
+ componentList.push(...fullSegmentMap.get(part)[0]);
2913
+ }
2914
+ }
2915
+ } else {
2916
+ for (const child of res) {
2917
+ componentList.push(fullSegmentMap.get(child)[0]);
2918
+ }
2919
+ }
2920
+ } else {
2921
+ const sortedOperandList = sortBy2(
2922
+ range3(glyph.operandList.length),
2923
+ (i) => order3.findIndex((b) => b.index === i)
2924
+ ).map((i) => glyph.operandList[i]);
2925
+ for (const child of sortedOperandList) {
2926
+ componentList.push(...segmentMap.get(child));
2927
+ }
2928
+ }
2929
+ if (isOptionalRoots) {
2930
+ let dynamic = [[]];
2931
+ for (const operand of componentList) {
2932
+ const dynamicAnalysis2 = segmentDynamicAnalysis.get(operand);
2933
+ dynamic = dynamic.map((x) => dynamicAnalysis2.map((y) => x.concat(y))).flat();
2934
+ }
2935
+ segmentDynamicAnalysis.set(name, [[name]].concat(dynamic));
2936
+ segmentMap.set(name, [name]);
2937
+ } else {
2938
+ segmentMap.set(name, componentList);
2939
+ }
2940
+ }
2941
+ const \u6C49\u5B57\u4FE1\u606F = characters.map((x) => {
2942
+ const readings = repertoire[x]?.readings ?? [];
2943
+ const frequency = adaptedFrequency.get(x) ?? 0;
2944
+ const frequencies = readings.map(({ pinyin, importance }) => {
2945
+ const entry = {
2946
+ \u62FC\u97F3: pinyin,
2947
+ \u9891\u7387: Math.round(frequency * importance / 100)
2948
+ };
2949
+ for (const [name, rules] of Object.entries(algebra)) {
2950
+ entry[name] = applyRules(name, rules, pinyin);
2951
+ }
2952
+ return entry;
2953
+ });
2954
+ return {
2955
+ \u6C49\u5B57: x,
2956
+ \u901A\u89C4: repertoire[x].tygf,
2957
+ gb2312: repertoire[x].gb2312,
2958
+ \u9891\u7387: frequency,
2959
+ \u8BFB\u97F3: frequencies,
2960
+ \u5B57\u5757: segmentMap.get(x) ?? [],
2961
+ \u90E8\u9996: bushouMap.get(x)
2962
+ };
2963
+ });
2964
+ const \u591A\u5B57\u8BCD\u4FE1\u606F = dictionary.map(([word, syllables]) => {
2965
+ const frequency = adaptedFrequency.get(word) ?? 0;
2966
+ const readings = syllables.split(" ").map((pinyin) => {
2967
+ const entry = {
2968
+ \u62FC\u97F3: pinyin
2969
+ };
2970
+ for (const [name, rules] of Object.entries(algebra)) {
2971
+ entry[name] = applyRules(name, rules, pinyin);
2972
+ }
2973
+ return entry;
2974
+ });
2975
+ return {
2976
+ \u8BCD: word,
2977
+ \u9891\u7387: frequency,
2978
+ \u8BFB\u97F3: readings
2979
+ };
2980
+ });
2981
+ const result = {
2982
+ \u6C49\u5B57\u4FE1\u606F,
2983
+ \u591A\u5B57\u8BCD\u4FE1\u606F,
2984
+ \u52A8\u6001\u62C6\u5206: Object.fromEntries(segmentDynamicAnalysis),
2985
+ \u5B57\u6839\u7B14\u753B: Object.fromEntries(getRootSequence(repertoire, config))
2986
+ };
2987
+ return result;
2988
+ };
2989
+
2990
+ // src/assembly.ts
2991
+ var getPriorityMap = (priorityShortCodes) => {
2992
+ return new Map(
2993
+ priorityShortCodes.map(([word, pinyin_list, level]) => {
2994
+ const hash = `${word}-${pinyin_list}`;
2995
+ return [hash, level];
2996
+ })
2997
+ );
2998
+ };
2999
+ var table = {
3000
+ \u662F: (t, v) => t === v,
3001
+ \u4E0D\u662F: (t, v) => t !== v,
3002
+ \u5339\u914D: (t, v) => t !== void 0 && new RegExp(v).test(t),
3003
+ \u4E0D\u5339\u914D: (t, v) => t !== void 0 && !new RegExp(v).test(t),
3004
+ \u7F16\u7801\u5339\u914D: (t, v, m) => t !== void 0 && new RegExp(v).test(m[t]),
3005
+ \u7F16\u7801\u4E0D\u5339\u914D: (t, v, m) => t !== void 0 && !new RegExp(v).test(m[t]),
3006
+ \u5B58\u5728: (t) => t !== void 0,
3007
+ \u4E0D\u5B58\u5728: (t) => t === void 0
3008
+ };
3009
+ var satisfy = (condition, result, config, extra, totalMapping) => {
3010
+ const { object, operator } = condition;
3011
+ const target = findElement(object, result, config, extra);
3012
+ const fn = table[operator];
3013
+ if ("value" in condition) {
3014
+ return fn(target, condition.value, totalMapping);
3015
+ }
3016
+ return fn(target, null, totalMapping);
3017
+ };
3018
+ var compile = (keyboard, encoder, algebra) => {
3019
+ const { mapping } = keyboard;
3020
+ const alphabet = keyboard.alphabet ?? "";
3021
+ const totalMapping = {};
3022
+ return (result, data, extra) => {
3023
+ let node = "s0";
3024
+ const codes = [];
3025
+ while (node) {
3026
+ if (node.startsWith("s")) {
3027
+ const source = encoder.sources[node];
3028
+ const { object, next, index } = source;
3029
+ if (node !== "s0") {
3030
+ const element = findElement(object, result, algebra, extra);
3031
+ if (element === void 0) {
3032
+ node = next;
3033
+ continue;
3034
+ }
3035
+ if (element.length === 1 && alphabet.includes(element)) {
3036
+ codes.push(element);
3037
+ node = next;
3038
+ continue;
3039
+ }
3040
+ let mapped = mapping[element];
3041
+ let groupedElement = element;
3042
+ if (mapped === void 0) {
3043
+ node = next;
3044
+ continue;
3045
+ }
3046
+ while (isMerge(mapped)) {
3047
+ groupedElement = mapped.element;
3048
+ mapped = mapping[mapped.element];
3049
+ }
3050
+ if (index === void 0) {
3051
+ for (const [index2, key] of Array.from(mapped).entries()) {
3052
+ codes.push(
3053
+ // typeof key === "string"
3054
+ // ? { element: groupedElement, index }
3055
+ // : key,
3056
+ { element: groupedElement, index: index2 }
3057
+ );
3058
+ }
3059
+ } else {
3060
+ const key = mapped[index];
3061
+ if (key !== void 0) {
3062
+ codes.push(
3063
+ // typeof key === "string"
3064
+ // ? { element: groupedElement, index }
3065
+ // : key,
3066
+ { element: groupedElement, index }
3067
+ );
3068
+ }
3069
+ }
3070
+ }
3071
+ node = next;
3072
+ } else {
3073
+ const condition = encoder.conditions[node];
3074
+ if (satisfy(condition, result, algebra, extra, totalMapping)) {
3075
+ node = condition.positive;
3076
+ } else {
3077
+ node = condition.negative;
3078
+ }
3079
+ }
3080
+ }
3081
+ return codes.slice(0, encoder.max_length ?? codes.length);
3082
+ };
3083
+ };
3084
+ var signedIndex2 = (elements, index) => {
3085
+ const order3 = index.codePointAt(0) - "a".codePointAt(0);
3086
+ const signedOrder = order3 < 13 ? order3 : order3 - 26;
3087
+ return elements.at(signedOrder);
3088
+ };
3089
+ var gather = (totalElements, rules) => {
3090
+ const result = [];
3091
+ let matched = false;
3092
+ for (const rule of rules) {
3093
+ if ("length_equal" in rule) {
3094
+ matched = totalElements.length === rule.length_equal;
3095
+ } else if ("length_in_range" in rule) {
3096
+ matched = totalElements.length >= rule.length_in_range[0] && totalElements.length <= rule.length_in_range[1];
3097
+ }
3098
+ if (matched) {
3099
+ const tokens = Array.from(rule.formula);
3100
+ for (let i = 0; i < tokens.length; i = i + 2) {
3101
+ const charIndex = tokens[i].toLowerCase();
3102
+ const elementIndex = tokens[i + 1];
3103
+ const elements = signedIndex2(totalElements, charIndex);
3104
+ if (elements === void 0)
3105
+ continue;
3106
+ const element = signedIndex2(elements, elementIndex);
3107
+ if (element === void 0)
3108
+ continue;
3109
+ result.push(element);
3110
+ }
3111
+ break;
3112
+ }
3113
+ }
3114
+ if (matched)
3115
+ return result;
3116
+ };
3117
+ var assemble = (repertoire, config, characters, dictionary, adaptedFrequency, analysisResult, customElements) => {
3118
+ const { customized, compoundResults } = analysisResult;
3119
+ const extra = { rootSequence: analysisResult.rootSequence };
3120
+ const func = compile(config.keyboard, config.encoder, config.algebra);
3121
+ const result = [];
3122
+ algebraCache.clear();
3123
+ const characterCache = /* @__PURE__ */ new Map();
3124
+ const customLookup = (character) => Object.fromEntries(
3125
+ Object.entries(customElements).map(([name, map]) => {
3126
+ return [name, (map[character] ?? []).map((x) => `${name}-${x}`)];
3127
+ })
3128
+ );
3129
+ for (const character of characters) {
3130
+ const frequency = adaptedFrequency.get(character) ?? 0;
3131
+ const shapeInfo = customized.get(character) || compoundResults.get(character);
3132
+ if (shapeInfo === void 0)
3133
+ continue;
3134
+ const final = [];
3135
+ if (character in repertoire === false)
3136
+ continue;
3137
+ const readings = [...repertoire[character].readings];
3138
+ if (readings.length === 0) {
3139
+ readings.push({ pinyin: "", importance: 100 });
3140
+ }
3141
+ for (const reading of readings) {
3142
+ const result2 = {
3143
+ char: character,
3144
+ pinyin: reading.pinyin,
3145
+ frequency: Math.round(frequency * (reading.importance / 100)),
3146
+ ...shapeInfo,
3147
+ custom: customLookup(character)
3148
+ };
3149
+ const elements = func(result2, repertoire, extra);
3150
+ characterCache.set(`${character}:${reading.pinyin}`, elements);
3151
+ const summary = summarize(elements);
3152
+ let isDuplicated = false;
3153
+ for (const previous of final) {
3154
+ if (summarize(previous.sequence) === summary) {
3155
+ previous.frequency += result2.frequency;
3156
+ previous.pinyin_list.push(reading.pinyin);
3157
+ isDuplicated = true;
3158
+ break;
3159
+ }
3160
+ }
3161
+ if (!isDuplicated) {
3162
+ final.push({
3163
+ name: character,
3164
+ sequence: elements,
3165
+ frequency: result2.frequency,
3166
+ pinyin_list: [reading.pinyin]
3167
+ });
3168
+ }
3169
+ }
3170
+ result.push(...final);
3171
+ }
3172
+ const rules = config.encoder.rules;
3173
+ if (!rules)
3174
+ return result;
3175
+ const knownWords = /* @__PURE__ */ new Set();
3176
+ for (const [word, pinyin] of dictionary) {
3177
+ const frequency = adaptedFrequency.get(word) ?? 0;
3178
+ const characters2 = Array.from(word);
3179
+ const syllables = pinyin.split(" ");
3180
+ let valid = true;
3181
+ const totalElements = [];
3182
+ for (const [i, character] of characters2.entries()) {
3183
+ const pinyin2 = syllables[i];
3184
+ const hash2 = `${character}:${pinyin2}`;
3185
+ let elements = characterCache.get(hash2);
3186
+ if (elements !== void 0) {
3187
+ totalElements.push(elements);
3188
+ continue;
3189
+ }
3190
+ const shapeInfo = customized.get(character) || compoundResults.get(character);
3191
+ if (shapeInfo === void 0) {
3192
+ valid = false;
3193
+ break;
3194
+ }
3195
+ const result2 = {
3196
+ char: character,
3197
+ pinyin: pinyin2,
3198
+ frequency,
3199
+ ...shapeInfo,
3200
+ custom: customLookup(character)
3201
+ };
3202
+ elements = func(result2, repertoire, extra);
3203
+ totalElements.push(elements);
3204
+ }
3205
+ if (!valid)
3206
+ continue;
3207
+ const wordElements = gather(totalElements, rules);
3208
+ if (wordElements === void 0)
3209
+ continue;
3210
+ const hash = `${word}:${summarize(wordElements)}`;
3211
+ if (knownWords.has(hash))
3212
+ continue;
3213
+ result.push({
3214
+ name: word,
3215
+ sequence: wordElements,
3216
+ frequency,
3217
+ pinyin_list: [pinyin]
3218
+ });
3219
+ knownWords.add(hash);
3220
+ }
3221
+ const priorityMap = getPriorityMap(config.priority);
3222
+ return result.map((x) => {
3223
+ const hash = `${x.name}-${x.pinyin_list.join(",")}`;
3224
+ const level = priorityMap.get(hash);
3225
+ return level !== void 0 ? { ...x, level } : x;
3226
+ });
3227
+ };
3228
+ var stringifySequence = (result) => {
3229
+ return result.map((x) => {
3230
+ return { ...x, sequence: summarize(x.sequence) };
3231
+ });
3232
+ };
3233
+ var summarize = (elements) => {
3234
+ return elements.map((x) => {
3235
+ if (x === void 0)
3236
+ return "\u03B5";
3237
+ if (typeof x === "string")
3238
+ return x;
3239
+ if (x.index === 0) {
3240
+ return x.element;
3241
+ }
3242
+ return `${x.element}.${x.index}`;
3243
+ }).join(" ");
3244
+ };
3245
+
3246
+ // src/templates.ts
3247
+ import * as path from "path";
3248
+ import { load } from "js-yaml";
3249
+ import { readFileSync } from "fs";
3250
+ function loadConfig(name) {
3251
+ const yamlPath = path.join(__dirname, `examples/${name}.yaml`);
3252
+ const content = readFileSync(yamlPath, "utf8");
3253
+ return load(content);
3254
+ }
3255
+ var snow4 = loadConfig("snow4");
3256
+ var bxm = loadConfig("bxm");
3257
+ var mswb = loadConfig("mswb");
3258
+ var ziyuan = loadConfig("ziyuan");
3259
+ var jdh = loadConfig("jdh");
3260
+ var cqkm = loadConfig("cqkm");
3261
+ var shouyou = loadConfig("shouyou");
3262
+ var xkjd = loadConfig("xkjd");
3263
+ var longma = loadConfig("longma");
3264
+ var easy = loadConfig("easy");
3265
+ var yustar = loadConfig("yustar");
3266
+ var yujoy = loadConfig("yujoy");
3267
+ var tianma = loadConfig("tianma");
3268
+ var zhengma = loadConfig("zhengma");
3269
+ var zhenma = loadConfig("zhenma");
3270
+ var zhangma = loadConfig("zhangma");
3271
+ var xuma = loadConfig("xuma");
3272
+ var huma = loadConfig("huma");
3273
+ var sapphire = loadConfig("sapphire");
3274
+ var examples = {
3275
+ snow4,
3276
+ longma,
3277
+ jdh,
3278
+ shouyou,
3279
+ xkjd,
3280
+ cqkm,
3281
+ bxm,
3282
+ mswb,
3283
+ ziyuan,
3284
+ easy,
3285
+ huma,
3286
+ tianma,
3287
+ sapphire,
3288
+ xuma,
3289
+ yustar,
3290
+ yujoy,
3291
+ zhangma,
3292
+ zhengma,
3293
+ zhenma
3294
+ };
3295
+ var classifierTypes = [
3296
+ "\u56FD\u6807\u4E94\u5206\u7C7B",
3297
+ "\u8868\u5F62\u7801\u516D\u5206\u7C7B",
3298
+ "\u90D1\u7801\u4E03\u5206\u7C7B"
3299
+ ];
3300
+ var classifierMap = {
3301
+ \u56FD\u6807\u4E94\u5206\u7C7B: {},
3302
+ \u8868\u5F62\u7801\u516D\u5206\u7C7B: examples.mswb.analysis.classifier,
3303
+ \u90D1\u7801\u4E03\u5206\u7C7B: examples.zhengma.analysis.classifier
3304
+ };
3305
+ var keyboardTypes = [
3306
+ "\u51B0\u96EA\u56DB\u62FC",
3307
+ "\u9F99\u7801",
3308
+ "\u7B80\u5355\u9E64",
3309
+ "\u9996\u53F3\u62FC\u97F3",
3310
+ "\u661F\u7A7A\u952E\u9053",
3311
+ "\u8D85\u5F3A\u5FEB\u7801",
3312
+ "\u8868\u5F62\u7801",
3313
+ "\u7C73\u5341\u4E94\u7B14",
3314
+ "\u5B57\u6E90",
3315
+ "\u5B87\u6D69\xB7\u661F\u9648",
3316
+ "\u537F\u4E91",
3317
+ "\u90D1\u7801",
3318
+ "\u771F\u7801",
3319
+ "\u5F20\u7801",
3320
+ "\u5F90\u7801",
3321
+ "\u864E\u7801",
3322
+ "\u5929\u7801",
3323
+ "\u84DD\u5B9D\u77F3",
3324
+ "\u65E0"
3325
+ ];
3326
+ var keyboardMap = {
3327
+ \u51B0\u96EA\u56DB\u62FC: examples.snow4.form,
3328
+ \u9F99\u7801: examples.longma.form,
3329
+ \u7B80\u5355\u9E64: examples.jdh.form,
3330
+ \u9996\u53F3\u62FC\u97F3: examples.shouyou.form,
3331
+ \u661F\u7A7A\u952E\u9053: examples.xkjd.form,
3332
+ \u8D85\u5F3A\u5FEB\u7801: examples.cqkm.form,
3333
+ \u8868\u5F62\u7801: examples.bxm.form,
3334
+ \u7C73\u5341\u4E94\u7B14: examples.mswb.form,
3335
+ \u5B57\u6E90: examples.ziyuan.form,
3336
+ "\u5B87\u6D69\xB7\u661F\u9648": examples.yustar.form,
3337
+ \u537F\u4E91: examples.yujoy.form,
3338
+ \u90D1\u7801: examples.zhengma.form,
3339
+ \u771F\u7801: examples.zhenma.form,
3340
+ \u5F20\u7801: examples.zhangma.form,
3341
+ \u5F90\u7801: examples.xuma.form,
3342
+ \u864E\u7801: examples.huma.form,
3343
+ \u5929\u7801: examples.tianma.form,
3344
+ \u84DD\u5B9D\u77F3: examples.sapphire.form,
3345
+ \u65E0: {
3346
+ alphabet: "qwertyuiopasdfghjklzxcvbnm",
3347
+ mapping: {}
3348
+ }
3349
+ };
3350
+ var encoderTypes = [
3351
+ "\u97F3\u7801\uFF08\u51B0\u96EA\u56DB\u62FC\uFF09",
3352
+ "\u97F3\u7801\uFF08\u9F99\u7801\uFF09",
3353
+ "\u97F3\u5F62\u7801\uFF08\u7B80\u5355\u9E64\uFF09",
3354
+ "\u97F3\u5F62\u7801\uFF08\u9996\u53F3\u62FC\u97F3\uFF09",
3355
+ "\u97F3\u5F62\u7801\uFF08\u661F\u7A7A\u952E\u9053\uFF09",
3356
+ "\u97F3\u5F62\u7801\uFF08\u8D85\u5F3A\u5FEB\u7801\uFF09",
3357
+ "\u5F62\u97F3\u7801\uFF08\u8868\u5F62\u7801\uFF09",
3358
+ "\u5F62\u97F3\u7801\uFF08\u7C73\u5341\u4E94\u7B14\uFF09",
3359
+ "\u5F62\u97F3\u7801\uFF08\u5B57\u6E90\uFF09",
3360
+ "\u5355\u7F16\u5F62\u7801\uFF08\u5F20\u7801\uFF09",
3361
+ "\u5355\u7F16\u5F62\u7801\uFF08\u84DD\u5B9D\u77F3\uFF09",
3362
+ "\u53CC\u7F16\u5F62\u7801\uFF08\u90D1\u7801\uFF09",
3363
+ "\u53CC\u7F16\u5F62\u7801\uFF08\u771F\u7801\uFF09",
3364
+ "\u53CC\u7F16\u5F62\u7801\uFF08\u5F90\u7801\uFF09",
3365
+ "\u53CC\u7F16\u5F62\u7801\uFF08\u6613\u7801\uFF09",
3366
+ "\u53CC\u7F16\u5F62\u7801\uFF08\u5B87\u6D69\xB7\u661F\u9648\uFF09",
3367
+ "\u53CC\u7F16\u5F62\u7801\uFF08\u537F\u4E91\uFF09",
3368
+ "\u53CC\u7F16\u5F62\u7801\uFF08\u864E\u7801\uFF09",
3369
+ "\u53CC\u7F16\u5F62\u7801\uFF08\u5929\u7801\uFF09"
3370
+ ];
3371
+ var encoderMap = {
3372
+ "\u97F3\u7801\uFF08\u51B0\u96EA\u56DB\u62FC\uFF09": examples.snow4.encoder,
3373
+ "\u97F3\u7801\uFF08\u9F99\u7801\uFF09": examples.longma.encoder,
3374
+ "\u97F3\u5F62\u7801\uFF08\u7B80\u5355\u9E64\uFF09": examples.jdh.encoder,
3375
+ "\u97F3\u5F62\u7801\uFF08\u9996\u53F3\u62FC\u97F3\uFF09": examples.shouyou.encoder,
3376
+ "\u97F3\u5F62\u7801\uFF08\u661F\u7A7A\u952E\u9053\uFF09": examples.xkjd.encoder,
3377
+ "\u97F3\u5F62\u7801\uFF08\u8D85\u5F3A\u5FEB\u7801\uFF09": examples.cqkm.encoder,
3378
+ "\u5F62\u97F3\u7801\uFF08\u8868\u5F62\u7801\uFF09": examples.bxm.encoder,
3379
+ "\u5F62\u97F3\u7801\uFF08\u7C73\u5341\u4E94\u7B14\uFF09": examples.mswb.encoder,
3380
+ "\u5F62\u97F3\u7801\uFF08\u5B57\u6E90\uFF09": examples.ziyuan.encoder,
3381
+ "\u5355\u7F16\u5F62\u7801\uFF08\u5F20\u7801\uFF09": examples.zhangma.encoder,
3382
+ "\u5355\u7F16\u5F62\u7801\uFF08\u84DD\u5B9D\u77F3\uFF09": examples.sapphire.encoder,
3383
+ "\u53CC\u7F16\u5F62\u7801\uFF08\u90D1\u7801\uFF09": examples.zhengma.encoder,
3384
+ "\u53CC\u7F16\u5F62\u7801\uFF08\u771F\u7801\uFF09": examples.zhenma.encoder,
3385
+ "\u53CC\u7F16\u5F62\u7801\uFF08\u5F90\u7801\uFF09": examples.xuma.encoder,
3386
+ "\u53CC\u7F16\u5F62\u7801\uFF08\u6613\u7801\uFF09": examples.easy.encoder,
3387
+ "\u53CC\u7F16\u5F62\u7801\uFF08\u5B87\u6D69\xB7\u661F\u9648\uFF09": examples.yustar.encoder,
3388
+ "\u53CC\u7F16\u5F62\u7801\uFF08\u537F\u4E91\uFF09": examples.yujoy.encoder,
3389
+ "\u53CC\u7F16\u5F62\u7801\uFF08\u864E\u7801\uFF09": examples.huma.encoder,
3390
+ "\u53CC\u7F16\u5F62\u7801\uFF08\u5929\u7801\uFF09": examples.tianma.encoder
3391
+ };
3392
+ var createConfig = (starter) => {
3393
+ const form = keyboardMap[starter.keyboard];
3394
+ const classifier2 = classifierMap[starter.data];
3395
+ for (const value of Object.values(mergeClassifier(classifier2))) {
3396
+ const element = value.toString();
3397
+ if (!form.mapping[element]) {
3398
+ form.mapping[element] = form.alphabet?.[0];
3399
+ }
3400
+ }
3401
+ return {
3402
+ version: "0.3",
3403
+ source: null,
3404
+ info: {
3405
+ name: starter.name,
3406
+ author: "\u65E0\u540D\u6C0F",
3407
+ version: "1.0.0",
3408
+ description: "\u4ECE\u6A21\u677F\u521B\u5EFA"
3409
+ },
3410
+ analysis: {
3411
+ classifier: classifier2,
3412
+ degenerator: defaultDegenerator,
3413
+ selector: defaultSelector
3414
+ },
3415
+ form,
3416
+ encoder: encoderMap[starter.encoder]
3417
+ };
3418
+ };
3419
+ var defaultConfig = createConfig({
3420
+ name: "",
3421
+ data: "\u56FD\u6807\u4E94\u5206\u7C7B",
3422
+ keyboard: "\u65E0",
3423
+ encoder: "\u5F62\u97F3\u7801\uFF08\u7C73\u5341\u4E94\u7B14\uFF09"
3424
+ });
3425
+ export {
3426
+ InvalidGlyphError,
3427
+ MultipleSchemeError2 as MultipleSchemeError,
3428
+ NoSchemeError,
3429
+ adapt,
3430
+ affineMerge,
3431
+ algebraCache,
3432
+ analysis,
3433
+ applyRules,
3434
+ area,
3435
+ assemble,
3436
+ attaching,
3437
+ bias,
3438
+ binaryOps,
3439
+ binaryToIndices,
3440
+ characterSetSpecifiers,
3441
+ chars,
3442
+ classifier,
3443
+ classifierTypes,
3444
+ computeComponent,
3445
+ createConfig,
3446
+ crossing,
3447
+ curveLength,
3448
+ curveRelation,
3449
+ defaultAlgebra,
3450
+ defaultConfig,
3451
+ defaultDegenerator,
3452
+ defaultOptimization,
3453
+ defaultSelector,
3454
+ degenerate,
3455
+ determine,
3456
+ disassembleComponents,
3457
+ disassembleCompounds,
3458
+ distance,
3459
+ dynamicAnalysis,
3460
+ encoderTypes,
3461
+ examples,
3462
+ exportJSON,
3463
+ exportTSV,
3464
+ exportYAML,
3465
+ findCorners,
3466
+ findCrossPoint,
3467
+ findElement,
3468
+ findGlyphIndex,
3469
+ findTopology,
3470
+ fingeringLabels,
3471
+ formatDate,
3472
+ generateSchemes,
3473
+ generateSliceBinaries,
3474
+ getBoundingBox,
3475
+ getComponentScheme,
3476
+ getDictFromTSV,
3477
+ getDistributionFromTSV,
3478
+ getDummyBasicComponent,
3479
+ getDummyCompound,
3480
+ getDummyDerivedComponent,
3481
+ getDummyReferenceStroke,
3482
+ getDummySVGStroke,
3483
+ getDummySplicedComponent,
3484
+ getGlyphBoundingBox,
3485
+ getIntervalOnOrientation,
3486
+ getIntervalPosition,
3487
+ getPriorityMap,
3488
+ getRecordFromTSV,
3489
+ getRequiredTargets,
3490
+ getReversedMapping,
3491
+ getSupplemental,
3492
+ indicesToBinary,
3493
+ integrity,
3494
+ isBoundedBy,
3495
+ isCollinear,
3496
+ isComponent,
3497
+ isConforming,
3498
+ isLess,
3499
+ isMerge,
3500
+ isPUA,
3501
+ isValidCJKBasicChar,
3502
+ isValidCJKChar,
3503
+ isValidCJKSupplement,
3504
+ isVariableKey,
3505
+ joinKeys,
3506
+ keyboardTypes,
3507
+ length,
3508
+ listToObject,
3509
+ makeCharacterFilter,
3510
+ makeCurve,
3511
+ makeDefaultAnalyzer,
3512
+ makeFilter,
3513
+ makeIntervalSum,
3514
+ mergeClassifier,
3515
+ operators,
3516
+ ops,
3517
+ order,
3518
+ order2,
3519
+ orientation,
3520
+ parseKey,
3521
+ parseList,
3522
+ printableAscii,
3523
+ pronunciationElementTypes,
3524
+ recursiveRenderComponent,
3525
+ recursiveRenderCompound,
3526
+ recursiveRenderStrokeSequence,
3527
+ render,
3528
+ renderList,
3529
+ renderName,
3530
+ renderRootList,
3531
+ renderSVGGlyph,
3532
+ renderSVGStroke,
3533
+ schema,
3534
+ select,
3535
+ serializerMap,
3536
+ serializerTypes,
3537
+ sieveMap,
3538
+ similar,
3539
+ sortTwoNumbers,
3540
+ stringify,
3541
+ stringifySequence,
3542
+ strokeRelation,
3543
+ strong,
3544
+ summarize,
3545
+ topologicalSort,
3546
+ unaryOps,
3547
+ unbias,
3548
+ unicodeBlock,
3549
+ unicodeBlockRank,
3550
+ unicodeBlocks,
3551
+ weak,
3552
+ wordLengthArray
3553
+ };