issy 0.5.2 → 0.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/main.js ADDED
@@ -0,0 +1,2220 @@
1
+ import { createRequire } from "node:module";
2
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
3
+
4
+ // src/main.ts
5
+ import {
6
+ cpSync,
7
+ existsSync as existsSync2,
8
+ mkdirSync,
9
+ readdirSync,
10
+ readFileSync,
11
+ rmSync,
12
+ writeFileSync
13
+ } from "node:fs";
14
+ import { dirname as dirname2, join as join2, resolve as resolve2 } from "node:path";
15
+ import { fileURLToPath } from "node:url";
16
+ // ../core/src/lib/issues.ts
17
+ import { existsSync } from "node:fs";
18
+ import { mkdir, readdir, readFile, writeFile } from "node:fs/promises";
19
+ import { dirname, join, resolve } from "node:path";
20
+
21
+ // ../../node_modules/.bun/fractional-indexing@3.2.0/node_modules/fractional-indexing/src/index.js
22
+ var BASE_62_DIGITS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
23
+ function midpoint(a, b, digits) {
24
+ const zero = digits[0];
25
+ if (b != null && a >= b) {
26
+ throw new Error(a + " >= " + b);
27
+ }
28
+ if (a.slice(-1) === zero || b && b.slice(-1) === zero) {
29
+ throw new Error("trailing zero");
30
+ }
31
+ if (b) {
32
+ let n = 0;
33
+ while ((a[n] || zero) === b[n]) {
34
+ n++;
35
+ }
36
+ if (n > 0) {
37
+ return b.slice(0, n) + midpoint(a.slice(n), b.slice(n), digits);
38
+ }
39
+ }
40
+ const digitA = a ? digits.indexOf(a[0]) : 0;
41
+ const digitB = b != null ? digits.indexOf(b[0]) : digits.length;
42
+ if (digitB - digitA > 1) {
43
+ const midDigit = Math.round(0.5 * (digitA + digitB));
44
+ return digits[midDigit];
45
+ } else {
46
+ if (b && b.length > 1) {
47
+ return b.slice(0, 1);
48
+ } else {
49
+ return digits[digitA] + midpoint(a.slice(1), null, digits);
50
+ }
51
+ }
52
+ }
53
+ function validateInteger(int) {
54
+ if (int.length !== getIntegerLength(int[0])) {
55
+ throw new Error("invalid integer part of order key: " + int);
56
+ }
57
+ }
58
+ function getIntegerLength(head) {
59
+ if (head >= "a" && head <= "z") {
60
+ return head.charCodeAt(0) - 97 + 2;
61
+ } else if (head >= "A" && head <= "Z") {
62
+ return 90 - head.charCodeAt(0) + 2;
63
+ } else {
64
+ throw new Error("invalid order key head: " + head);
65
+ }
66
+ }
67
+ function getIntegerPart(key) {
68
+ const integerPartLength = getIntegerLength(key[0]);
69
+ if (integerPartLength > key.length) {
70
+ throw new Error("invalid order key: " + key);
71
+ }
72
+ return key.slice(0, integerPartLength);
73
+ }
74
+ function validateOrderKey(key, digits) {
75
+ if (key === "A" + digits[0].repeat(26)) {
76
+ throw new Error("invalid order key: " + key);
77
+ }
78
+ const i = getIntegerPart(key);
79
+ const f = key.slice(i.length);
80
+ if (f.slice(-1) === digits[0]) {
81
+ throw new Error("invalid order key: " + key);
82
+ }
83
+ }
84
+ function incrementInteger(x, digits) {
85
+ validateInteger(x);
86
+ const [head, ...digs] = x.split("");
87
+ let carry = true;
88
+ for (let i = digs.length - 1;carry && i >= 0; i--) {
89
+ const d = digits.indexOf(digs[i]) + 1;
90
+ if (d === digits.length) {
91
+ digs[i] = digits[0];
92
+ } else {
93
+ digs[i] = digits[d];
94
+ carry = false;
95
+ }
96
+ }
97
+ if (carry) {
98
+ if (head === "Z") {
99
+ return "a" + digits[0];
100
+ }
101
+ if (head === "z") {
102
+ return null;
103
+ }
104
+ const h = String.fromCharCode(head.charCodeAt(0) + 1);
105
+ if (h > "a") {
106
+ digs.push(digits[0]);
107
+ } else {
108
+ digs.pop();
109
+ }
110
+ return h + digs.join("");
111
+ } else {
112
+ return head + digs.join("");
113
+ }
114
+ }
115
+ function decrementInteger(x, digits) {
116
+ validateInteger(x);
117
+ const [head, ...digs] = x.split("");
118
+ let borrow = true;
119
+ for (let i = digs.length - 1;borrow && i >= 0; i--) {
120
+ const d = digits.indexOf(digs[i]) - 1;
121
+ if (d === -1) {
122
+ digs[i] = digits.slice(-1);
123
+ } else {
124
+ digs[i] = digits[d];
125
+ borrow = false;
126
+ }
127
+ }
128
+ if (borrow) {
129
+ if (head === "a") {
130
+ return "Z" + digits.slice(-1);
131
+ }
132
+ if (head === "A") {
133
+ return null;
134
+ }
135
+ const h = String.fromCharCode(head.charCodeAt(0) - 1);
136
+ if (h < "Z") {
137
+ digs.push(digits.slice(-1));
138
+ } else {
139
+ digs.pop();
140
+ }
141
+ return h + digs.join("");
142
+ } else {
143
+ return head + digs.join("");
144
+ }
145
+ }
146
+ function generateKeyBetween(a, b, digits = BASE_62_DIGITS) {
147
+ if (a != null) {
148
+ validateOrderKey(a, digits);
149
+ }
150
+ if (b != null) {
151
+ validateOrderKey(b, digits);
152
+ }
153
+ if (a != null && b != null && a >= b) {
154
+ throw new Error(a + " >= " + b);
155
+ }
156
+ if (a == null) {
157
+ if (b == null) {
158
+ return "a" + digits[0];
159
+ }
160
+ const ib2 = getIntegerPart(b);
161
+ const fb2 = b.slice(ib2.length);
162
+ if (ib2 === "A" + digits[0].repeat(26)) {
163
+ return ib2 + midpoint("", fb2, digits);
164
+ }
165
+ if (ib2 < b) {
166
+ return ib2;
167
+ }
168
+ const res = decrementInteger(ib2, digits);
169
+ if (res == null) {
170
+ throw new Error("cannot decrement any more");
171
+ }
172
+ return res;
173
+ }
174
+ if (b == null) {
175
+ const ia2 = getIntegerPart(a);
176
+ const fa2 = a.slice(ia2.length);
177
+ const i2 = incrementInteger(ia2, digits);
178
+ return i2 == null ? ia2 + midpoint(fa2, null, digits) : i2;
179
+ }
180
+ const ia = getIntegerPart(a);
181
+ const fa = a.slice(ia.length);
182
+ const ib = getIntegerPart(b);
183
+ const fb = b.slice(ib.length);
184
+ if (ia === ib) {
185
+ return ia + midpoint(fa, fb, digits);
186
+ }
187
+ const i = incrementInteger(ia, digits);
188
+ if (i == null) {
189
+ throw new Error("cannot increment any more");
190
+ }
191
+ if (i < b) {
192
+ return i;
193
+ }
194
+ return ia + midpoint(fa, null, digits);
195
+ }
196
+ function generateNKeysBetween(a, b, n, digits = BASE_62_DIGITS) {
197
+ if (n === 0) {
198
+ return [];
199
+ }
200
+ if (n === 1) {
201
+ return [generateKeyBetween(a, b, digits)];
202
+ }
203
+ if (b == null) {
204
+ let c2 = generateKeyBetween(a, b, digits);
205
+ const result = [c2];
206
+ for (let i = 0;i < n - 1; i++) {
207
+ c2 = generateKeyBetween(c2, b, digits);
208
+ result.push(c2);
209
+ }
210
+ return result;
211
+ }
212
+ if (a == null) {
213
+ let c2 = generateKeyBetween(a, b, digits);
214
+ const result = [c2];
215
+ for (let i = 0;i < n - 1; i++) {
216
+ c2 = generateKeyBetween(a, c2, digits);
217
+ result.push(c2);
218
+ }
219
+ result.reverse();
220
+ return result;
221
+ }
222
+ const mid = Math.floor(n / 2);
223
+ const c = generateKeyBetween(a, b, digits);
224
+ return [
225
+ ...generateNKeysBetween(a, c, mid, digits),
226
+ c,
227
+ ...generateNKeysBetween(c, b, n - mid - 1, digits)
228
+ ];
229
+ }
230
+
231
+ // ../core/src/lib/issues.ts
232
+ var issyDir = null;
233
+ var issuesDir = null;
234
+ function setIssyDir(dir) {
235
+ issyDir = dir;
236
+ issuesDir = join(dir, "issues");
237
+ }
238
+ function getIssyDir() {
239
+ if (!issyDir) {
240
+ throw new Error("Issy directory not initialized. Call resolveIssyDir() first.");
241
+ }
242
+ return issyDir;
243
+ }
244
+ function getIssuesDir() {
245
+ if (!issuesDir) {
246
+ throw new Error("Issues directory not initialized. Call resolveIssyDir() first.");
247
+ }
248
+ return issuesDir;
249
+ }
250
+ async function ensureIssuesDir() {
251
+ await mkdir(getIssuesDir(), { recursive: true });
252
+ }
253
+ function findIssyDirUpward(fromPath) {
254
+ let current = resolve(fromPath);
255
+ for (let i = 0;i < 20; i++) {
256
+ const candidate = join(current, ".issy");
257
+ if (existsSync(candidate)) {
258
+ return candidate;
259
+ }
260
+ const parent = dirname(current);
261
+ if (parent === current)
262
+ break;
263
+ current = parent;
264
+ }
265
+ return null;
266
+ }
267
+ function findLegacyIssuesDirUpward(fromPath) {
268
+ let current = resolve(fromPath);
269
+ for (let i = 0;i < 20; i++) {
270
+ const candidate = join(current, ".issues");
271
+ if (existsSync(candidate)) {
272
+ return candidate;
273
+ }
274
+ const parent = dirname(current);
275
+ if (parent === current)
276
+ break;
277
+ current = parent;
278
+ }
279
+ return null;
280
+ }
281
+ function findGitRoot(fromPath) {
282
+ let current = resolve(fromPath);
283
+ for (let i = 0;i < 20; i++) {
284
+ const gitDir = join(current, ".git");
285
+ if (existsSync(gitDir)) {
286
+ return current;
287
+ }
288
+ const parent = dirname(current);
289
+ if (parent === current)
290
+ break;
291
+ current = parent;
292
+ }
293
+ return null;
294
+ }
295
+ function resolveIssyDir() {
296
+ if (process.env.ISSY_DIR) {
297
+ const dir = resolve(process.env.ISSY_DIR);
298
+ setIssyDir(dir);
299
+ return dir;
300
+ }
301
+ const startDir = process.env.ISSY_ROOT || process.cwd();
302
+ const found = findIssyDirUpward(startDir);
303
+ if (found) {
304
+ setIssyDir(found);
305
+ return found;
306
+ }
307
+ const gitRoot = findGitRoot(startDir);
308
+ if (gitRoot) {
309
+ const gitIssyDir = join(gitRoot, ".issy");
310
+ setIssyDir(gitIssyDir);
311
+ return gitIssyDir;
312
+ }
313
+ const fallback = join(resolve(startDir), ".issy");
314
+ setIssyDir(fallback);
315
+ return fallback;
316
+ }
317
+ function parseFrontmatter(content) {
318
+ const match = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
319
+ if (!match) {
320
+ return { frontmatter: {}, body: content };
321
+ }
322
+ const [, frontmatterStr, body] = match;
323
+ const frontmatter = {};
324
+ for (const line of frontmatterStr.split(`
325
+ `)) {
326
+ const colonIdx = line.indexOf(":");
327
+ if (colonIdx > 0) {
328
+ const key = line.slice(0, colonIdx).trim();
329
+ const value = line.slice(colonIdx + 1).trim();
330
+ frontmatter[key] = value;
331
+ }
332
+ }
333
+ return { frontmatter, body };
334
+ }
335
+ function generateFrontmatter(data) {
336
+ const lines = ["---"];
337
+ lines.push(`title: ${data.title}`);
338
+ lines.push(`description: ${data.description}`);
339
+ lines.push(`priority: ${data.priority}`);
340
+ if (data.scope) {
341
+ lines.push(`scope: ${data.scope}`);
342
+ }
343
+ lines.push(`type: ${data.type}`);
344
+ if (data.labels) {
345
+ lines.push(`labels: ${data.labels}`);
346
+ }
347
+ lines.push(`status: ${data.status}`);
348
+ if (data.order) {
349
+ lines.push(`order: ${data.order}`);
350
+ }
351
+ lines.push(`created: ${data.created}`);
352
+ if (data.updated) {
353
+ lines.push(`updated: ${data.updated}`);
354
+ }
355
+ lines.push("---");
356
+ return lines.join(`
357
+ `);
358
+ }
359
+ function getIssueIdFromFilename(filename) {
360
+ const match = filename.match(/^(\d+)-/);
361
+ return match ? match[1] : filename.replace(".md", "");
362
+ }
363
+ function createSlug(title) {
364
+ return title.toLowerCase().replace(/[^a-z0-9\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-").slice(0, 50);
365
+ }
366
+ function formatDate(date = new Date) {
367
+ return date.toISOString().slice(0, 19);
368
+ }
369
+ async function getIssueFiles() {
370
+ try {
371
+ const files = await readdir(getIssuesDir());
372
+ return files.filter((f) => f.endsWith(".md") && /^\d{4}-/.test(f));
373
+ } catch {
374
+ return [];
375
+ }
376
+ }
377
+ async function getNextIssueNumber() {
378
+ const files = await getIssueFiles();
379
+ if (files.length === 0)
380
+ return "0001";
381
+ const numbers = files.map((f) => parseInt(getIssueIdFromFilename(f), 10)).filter((n) => !Number.isNaN(n));
382
+ const max = Math.max(...numbers, 0);
383
+ return String(max + 1).padStart(4, "0");
384
+ }
385
+ async function getIssue(id) {
386
+ const files = await getIssueFiles();
387
+ const paddedId = id.padStart(4, "0");
388
+ const file = files.find((f) => f.startsWith(paddedId) || getIssueIdFromFilename(f) === paddedId);
389
+ if (!file)
390
+ return null;
391
+ const filepath = join(getIssuesDir(), file);
392
+ const content = await readFile(filepath, "utf-8");
393
+ const { frontmatter, body } = parseFrontmatter(content);
394
+ return {
395
+ id: getIssueIdFromFilename(file),
396
+ filename: file,
397
+ frontmatter,
398
+ content: body
399
+ };
400
+ }
401
+ async function getAllIssues() {
402
+ const files = await getIssueFiles();
403
+ const issues = [];
404
+ for (const file of files) {
405
+ const filepath = join(getIssuesDir(), file);
406
+ const content = await readFile(filepath, "utf-8");
407
+ const { frontmatter, body } = parseFrontmatter(content);
408
+ issues.push({
409
+ id: getIssueIdFromFilename(file),
410
+ filename: file,
411
+ frontmatter,
412
+ content: body
413
+ });
414
+ }
415
+ return issues.sort((a, b) => {
416
+ const orderA = a.frontmatter.order;
417
+ const orderB = b.frontmatter.order;
418
+ if (orderA && orderB)
419
+ return orderA < orderB ? -1 : orderA > orderB ? 1 : 0;
420
+ if (orderA && !orderB)
421
+ return -1;
422
+ if (!orderA && orderB)
423
+ return 1;
424
+ return a.id < b.id ? -1 : a.id > b.id ? 1 : 0;
425
+ });
426
+ }
427
+ async function getOpenIssuesByOrder() {
428
+ const allIssues = await getAllIssues();
429
+ return allIssues.filter((i) => i.frontmatter.status === "open");
430
+ }
431
+ function computeOrderKey(openIssues, options, excludeId) {
432
+ const issues = excludeId ? openIssues.filter((i) => i.id !== excludeId.padStart(4, "0")) : openIssues;
433
+ if (options.first) {
434
+ if (issues.length === 0)
435
+ return generateKeyBetween(null, null);
436
+ const firstOrder = issues[0].frontmatter.order || null;
437
+ return generateKeyBetween(null, firstOrder);
438
+ }
439
+ if (options.last) {
440
+ if (issues.length === 0)
441
+ return generateKeyBetween(null, null);
442
+ const lastOrder2 = issues[issues.length - 1].frontmatter.order || null;
443
+ return generateKeyBetween(lastOrder2, null);
444
+ }
445
+ if (options.after) {
446
+ const targetId = options.after.padStart(4, "0");
447
+ const idx = issues.findIndex((i) => i.id === targetId);
448
+ if (idx === -1)
449
+ throw new Error(`Issue #${options.after} not found among open issues. The --after target must be an open issue.`);
450
+ const afterOrder = issues[idx].frontmatter.order || null;
451
+ const nextOrder = idx + 1 < issues.length ? issues[idx + 1].frontmatter.order || null : null;
452
+ return generateKeyBetween(afterOrder, nextOrder);
453
+ }
454
+ if (options.before) {
455
+ const targetId = options.before.padStart(4, "0");
456
+ const idx = issues.findIndex((i) => i.id === targetId);
457
+ if (idx === -1)
458
+ throw new Error(`Issue #${options.before} not found among open issues. The --before target must be an open issue.`);
459
+ const beforeOrder = issues[idx].frontmatter.order || null;
460
+ const prevOrder = idx > 0 ? issues[idx - 1].frontmatter.order || null : null;
461
+ return generateKeyBetween(prevOrder, beforeOrder);
462
+ }
463
+ if (issues.length === 0) {
464
+ return generateKeyBetween(null, null);
465
+ }
466
+ const lastOrder = issues[issues.length - 1].frontmatter.order || null;
467
+ return generateKeyBetween(lastOrder, null);
468
+ }
469
+ function generateBatchOrderKeys(count) {
470
+ return generateNKeysBetween(null, null, count);
471
+ }
472
+ async function createIssue(input) {
473
+ await ensureIssuesDir();
474
+ if (!input.title) {
475
+ throw new Error("Title is required");
476
+ }
477
+ const priority = input.priority || "medium";
478
+ const scope = input.scope;
479
+ const type = input.type || "improvement";
480
+ if (!["high", "medium", "low"].includes(priority)) {
481
+ throw new Error("Priority must be: high, medium, or low");
482
+ }
483
+ if (scope && !["small", "medium", "large"].includes(scope)) {
484
+ throw new Error("Scope must be: small, medium, or large");
485
+ }
486
+ if (!["bug", "improvement"].includes(type)) {
487
+ throw new Error("Type must be: bug or improvement");
488
+ }
489
+ const issueNumber = await getNextIssueNumber();
490
+ const slug = createSlug(input.title);
491
+ const filename = `${issueNumber}-${slug}.md`;
492
+ const frontmatter = {
493
+ title: input.title,
494
+ description: input.description || input.title,
495
+ priority,
496
+ scope: scope || undefined,
497
+ type,
498
+ labels: input.labels || undefined,
499
+ status: "open",
500
+ order: input.order || undefined,
501
+ created: formatDate()
502
+ };
503
+ const content = `${generateFrontmatter(frontmatter)}
504
+
505
+ ## Details
506
+
507
+ <!-- Add detailed description here -->
508
+
509
+ `;
510
+ await writeFile(join(getIssuesDir(), filename), content);
511
+ return {
512
+ id: issueNumber,
513
+ filename,
514
+ frontmatter,
515
+ content: `
516
+ ## Details
517
+
518
+ <!-- Add detailed description here -->
519
+
520
+ `
521
+ };
522
+ }
523
+ async function updateIssue(id, input) {
524
+ const issue = await getIssue(id);
525
+ if (!issue) {
526
+ throw new Error(`Issue not found: ${id}`);
527
+ }
528
+ const updatedFrontmatter = {
529
+ ...issue.frontmatter,
530
+ ...input.title && { title: input.title },
531
+ ...input.description && { description: input.description },
532
+ ...input.priority && { priority: input.priority },
533
+ ...input.scope && { scope: input.scope },
534
+ ...input.type && { type: input.type },
535
+ ...input.labels !== undefined && {
536
+ labels: input.labels || undefined
537
+ },
538
+ ...input.status && { status: input.status },
539
+ ...input.order && { order: input.order },
540
+ updated: formatDate()
541
+ };
542
+ const content = `${generateFrontmatter(updatedFrontmatter)}
543
+ ${issue.content}`;
544
+ await writeFile(join(getIssuesDir(), issue.filename), content);
545
+ return {
546
+ ...issue,
547
+ frontmatter: updatedFrontmatter
548
+ };
549
+ }
550
+ async function closeIssue(id) {
551
+ return updateIssue(id, { status: "closed" });
552
+ }
553
+ async function reopenIssue(id, order) {
554
+ return updateIssue(id, { status: "open", order });
555
+ }
556
+ async function getOnCloseContent() {
557
+ try {
558
+ const onClosePath = join(getIssyDir(), "on_close.md");
559
+ return await readFile(onClosePath, "utf-8");
560
+ } catch {
561
+ return null;
562
+ }
563
+ }
564
+ async function getNextIssue() {
565
+ const openIssues = await getOpenIssuesByOrder();
566
+ return openIssues.length > 0 ? openIssues[0] : null;
567
+ }
568
+ // ../core/src/lib/query-parser.ts
569
+ var SUPPORTED_QUALIFIERS = new Set([
570
+ "is",
571
+ "priority",
572
+ "scope",
573
+ "type",
574
+ "label",
575
+ "sort"
576
+ ]);
577
+ function parseQuery(query) {
578
+ const qualifiers = {};
579
+ const searchTextParts = [];
580
+ if (!query || !query.trim()) {
581
+ return { qualifiers, searchText: "" };
582
+ }
583
+ const tokens = tokenizeQuery(query);
584
+ for (const token of tokens) {
585
+ const colonIndex = token.indexOf(":");
586
+ if (colonIndex > 0 && colonIndex < token.length - 1) {
587
+ const key = token.substring(0, colonIndex);
588
+ const value = token.substring(colonIndex + 1);
589
+ if (SUPPORTED_QUALIFIERS.has(key)) {
590
+ qualifiers[key] = value;
591
+ } else {
592
+ searchTextParts.push(token);
593
+ }
594
+ } else {
595
+ searchTextParts.push(token);
596
+ }
597
+ }
598
+ return {
599
+ qualifiers,
600
+ searchText: searchTextParts.join(" ").trim()
601
+ };
602
+ }
603
+ function tokenizeQuery(query) {
604
+ const tokens = [];
605
+ let currentToken = "";
606
+ let inQuotes = false;
607
+ let quoteChar = "";
608
+ for (let i = 0;i < query.length; i++) {
609
+ const char = query[i];
610
+ if ((char === '"' || char === "'") && !inQuotes) {
611
+ inQuotes = true;
612
+ quoteChar = char;
613
+ } else if (char === quoteChar && inQuotes) {
614
+ inQuotes = false;
615
+ quoteChar = "";
616
+ } else if (char === " " && !inQuotes) {
617
+ if (currentToken) {
618
+ tokens.push(currentToken);
619
+ currentToken = "";
620
+ }
621
+ } else {
622
+ currentToken += char;
623
+ }
624
+ }
625
+ if (currentToken) {
626
+ tokens.push(currentToken);
627
+ }
628
+ return tokens;
629
+ }
630
+ // ../../node_modules/.bun/fuse.js@7.1.0/node_modules/fuse.js/dist/fuse.mjs
631
+ function isArray(value) {
632
+ return !Array.isArray ? getTag(value) === "[object Array]" : Array.isArray(value);
633
+ }
634
+ var INFINITY = 1 / 0;
635
+ function baseToString(value) {
636
+ if (typeof value == "string") {
637
+ return value;
638
+ }
639
+ let result = value + "";
640
+ return result == "0" && 1 / value == -INFINITY ? "-0" : result;
641
+ }
642
+ function toString(value) {
643
+ return value == null ? "" : baseToString(value);
644
+ }
645
+ function isString(value) {
646
+ return typeof value === "string";
647
+ }
648
+ function isNumber(value) {
649
+ return typeof value === "number";
650
+ }
651
+ function isBoolean(value) {
652
+ return value === true || value === false || isObjectLike(value) && getTag(value) == "[object Boolean]";
653
+ }
654
+ function isObject(value) {
655
+ return typeof value === "object";
656
+ }
657
+ function isObjectLike(value) {
658
+ return isObject(value) && value !== null;
659
+ }
660
+ function isDefined(value) {
661
+ return value !== undefined && value !== null;
662
+ }
663
+ function isBlank(value) {
664
+ return !value.trim().length;
665
+ }
666
+ function getTag(value) {
667
+ return value == null ? value === undefined ? "[object Undefined]" : "[object Null]" : Object.prototype.toString.call(value);
668
+ }
669
+ var INCORRECT_INDEX_TYPE = "Incorrect 'index' type";
670
+ var LOGICAL_SEARCH_INVALID_QUERY_FOR_KEY = (key) => `Invalid value for key ${key}`;
671
+ var PATTERN_LENGTH_TOO_LARGE = (max) => `Pattern length exceeds max of ${max}.`;
672
+ var MISSING_KEY_PROPERTY = (name) => `Missing ${name} property in key`;
673
+ var INVALID_KEY_WEIGHT_VALUE = (key) => `Property 'weight' in key '${key}' must be a positive integer`;
674
+ var hasOwn = Object.prototype.hasOwnProperty;
675
+
676
+ class KeyStore {
677
+ constructor(keys) {
678
+ this._keys = [];
679
+ this._keyMap = {};
680
+ let totalWeight = 0;
681
+ keys.forEach((key) => {
682
+ let obj = createKey(key);
683
+ this._keys.push(obj);
684
+ this._keyMap[obj.id] = obj;
685
+ totalWeight += obj.weight;
686
+ });
687
+ this._keys.forEach((key) => {
688
+ key.weight /= totalWeight;
689
+ });
690
+ }
691
+ get(keyId) {
692
+ return this._keyMap[keyId];
693
+ }
694
+ keys() {
695
+ return this._keys;
696
+ }
697
+ toJSON() {
698
+ return JSON.stringify(this._keys);
699
+ }
700
+ }
701
+ function createKey(key) {
702
+ let path = null;
703
+ let id = null;
704
+ let src = null;
705
+ let weight = 1;
706
+ let getFn = null;
707
+ if (isString(key) || isArray(key)) {
708
+ src = key;
709
+ path = createKeyPath(key);
710
+ id = createKeyId(key);
711
+ } else {
712
+ if (!hasOwn.call(key, "name")) {
713
+ throw new Error(MISSING_KEY_PROPERTY("name"));
714
+ }
715
+ const name = key.name;
716
+ src = name;
717
+ if (hasOwn.call(key, "weight")) {
718
+ weight = key.weight;
719
+ if (weight <= 0) {
720
+ throw new Error(INVALID_KEY_WEIGHT_VALUE(name));
721
+ }
722
+ }
723
+ path = createKeyPath(name);
724
+ id = createKeyId(name);
725
+ getFn = key.getFn;
726
+ }
727
+ return { path, id, weight, src, getFn };
728
+ }
729
+ function createKeyPath(key) {
730
+ return isArray(key) ? key : key.split(".");
731
+ }
732
+ function createKeyId(key) {
733
+ return isArray(key) ? key.join(".") : key;
734
+ }
735
+ function get(obj, path) {
736
+ let list = [];
737
+ let arr = false;
738
+ const deepGet = (obj2, path2, index) => {
739
+ if (!isDefined(obj2)) {
740
+ return;
741
+ }
742
+ if (!path2[index]) {
743
+ list.push(obj2);
744
+ } else {
745
+ let key = path2[index];
746
+ const value = obj2[key];
747
+ if (!isDefined(value)) {
748
+ return;
749
+ }
750
+ if (index === path2.length - 1 && (isString(value) || isNumber(value) || isBoolean(value))) {
751
+ list.push(toString(value));
752
+ } else if (isArray(value)) {
753
+ arr = true;
754
+ for (let i = 0, len = value.length;i < len; i += 1) {
755
+ deepGet(value[i], path2, index + 1);
756
+ }
757
+ } else if (path2.length) {
758
+ deepGet(value, path2, index + 1);
759
+ }
760
+ }
761
+ };
762
+ deepGet(obj, isString(path) ? path.split(".") : path, 0);
763
+ return arr ? list : list[0];
764
+ }
765
+ var MatchOptions = {
766
+ includeMatches: false,
767
+ findAllMatches: false,
768
+ minMatchCharLength: 1
769
+ };
770
+ var BasicOptions = {
771
+ isCaseSensitive: false,
772
+ ignoreDiacritics: false,
773
+ includeScore: false,
774
+ keys: [],
775
+ shouldSort: true,
776
+ sortFn: (a, b) => a.score === b.score ? a.idx < b.idx ? -1 : 1 : a.score < b.score ? -1 : 1
777
+ };
778
+ var FuzzyOptions = {
779
+ location: 0,
780
+ threshold: 0.6,
781
+ distance: 100
782
+ };
783
+ var AdvancedOptions = {
784
+ useExtendedSearch: false,
785
+ getFn: get,
786
+ ignoreLocation: false,
787
+ ignoreFieldNorm: false,
788
+ fieldNormWeight: 1
789
+ };
790
+ var Config = {
791
+ ...BasicOptions,
792
+ ...MatchOptions,
793
+ ...FuzzyOptions,
794
+ ...AdvancedOptions
795
+ };
796
+ var SPACE = /[^ ]+/g;
797
+ function norm(weight = 1, mantissa = 3) {
798
+ const cache = new Map;
799
+ const m = Math.pow(10, mantissa);
800
+ return {
801
+ get(value) {
802
+ const numTokens = value.match(SPACE).length;
803
+ if (cache.has(numTokens)) {
804
+ return cache.get(numTokens);
805
+ }
806
+ const norm2 = 1 / Math.pow(numTokens, 0.5 * weight);
807
+ const n = parseFloat(Math.round(norm2 * m) / m);
808
+ cache.set(numTokens, n);
809
+ return n;
810
+ },
811
+ clear() {
812
+ cache.clear();
813
+ }
814
+ };
815
+ }
816
+
817
+ class FuseIndex {
818
+ constructor({
819
+ getFn = Config.getFn,
820
+ fieldNormWeight = Config.fieldNormWeight
821
+ } = {}) {
822
+ this.norm = norm(fieldNormWeight, 3);
823
+ this.getFn = getFn;
824
+ this.isCreated = false;
825
+ this.setIndexRecords();
826
+ }
827
+ setSources(docs = []) {
828
+ this.docs = docs;
829
+ }
830
+ setIndexRecords(records = []) {
831
+ this.records = records;
832
+ }
833
+ setKeys(keys = []) {
834
+ this.keys = keys;
835
+ this._keysMap = {};
836
+ keys.forEach((key, idx) => {
837
+ this._keysMap[key.id] = idx;
838
+ });
839
+ }
840
+ create() {
841
+ if (this.isCreated || !this.docs.length) {
842
+ return;
843
+ }
844
+ this.isCreated = true;
845
+ if (isString(this.docs[0])) {
846
+ this.docs.forEach((doc, docIndex) => {
847
+ this._addString(doc, docIndex);
848
+ });
849
+ } else {
850
+ this.docs.forEach((doc, docIndex) => {
851
+ this._addObject(doc, docIndex);
852
+ });
853
+ }
854
+ this.norm.clear();
855
+ }
856
+ add(doc) {
857
+ const idx = this.size();
858
+ if (isString(doc)) {
859
+ this._addString(doc, idx);
860
+ } else {
861
+ this._addObject(doc, idx);
862
+ }
863
+ }
864
+ removeAt(idx) {
865
+ this.records.splice(idx, 1);
866
+ for (let i = idx, len = this.size();i < len; i += 1) {
867
+ this.records[i].i -= 1;
868
+ }
869
+ }
870
+ getValueForItemAtKeyId(item, keyId) {
871
+ return item[this._keysMap[keyId]];
872
+ }
873
+ size() {
874
+ return this.records.length;
875
+ }
876
+ _addString(doc, docIndex) {
877
+ if (!isDefined(doc) || isBlank(doc)) {
878
+ return;
879
+ }
880
+ let record = {
881
+ v: doc,
882
+ i: docIndex,
883
+ n: this.norm.get(doc)
884
+ };
885
+ this.records.push(record);
886
+ }
887
+ _addObject(doc, docIndex) {
888
+ let record = { i: docIndex, $: {} };
889
+ this.keys.forEach((key, keyIndex) => {
890
+ let value = key.getFn ? key.getFn(doc) : this.getFn(doc, key.path);
891
+ if (!isDefined(value)) {
892
+ return;
893
+ }
894
+ if (isArray(value)) {
895
+ let subRecords = [];
896
+ const stack = [{ nestedArrIndex: -1, value }];
897
+ while (stack.length) {
898
+ const { nestedArrIndex, value: value2 } = stack.pop();
899
+ if (!isDefined(value2)) {
900
+ continue;
901
+ }
902
+ if (isString(value2) && !isBlank(value2)) {
903
+ let subRecord = {
904
+ v: value2,
905
+ i: nestedArrIndex,
906
+ n: this.norm.get(value2)
907
+ };
908
+ subRecords.push(subRecord);
909
+ } else if (isArray(value2)) {
910
+ value2.forEach((item, k) => {
911
+ stack.push({
912
+ nestedArrIndex: k,
913
+ value: item
914
+ });
915
+ });
916
+ } else
917
+ ;
918
+ }
919
+ record.$[keyIndex] = subRecords;
920
+ } else if (isString(value) && !isBlank(value)) {
921
+ let subRecord = {
922
+ v: value,
923
+ n: this.norm.get(value)
924
+ };
925
+ record.$[keyIndex] = subRecord;
926
+ }
927
+ });
928
+ this.records.push(record);
929
+ }
930
+ toJSON() {
931
+ return {
932
+ keys: this.keys,
933
+ records: this.records
934
+ };
935
+ }
936
+ }
937
+ function createIndex(keys, docs, { getFn = Config.getFn, fieldNormWeight = Config.fieldNormWeight } = {}) {
938
+ const myIndex = new FuseIndex({ getFn, fieldNormWeight });
939
+ myIndex.setKeys(keys.map(createKey));
940
+ myIndex.setSources(docs);
941
+ myIndex.create();
942
+ return myIndex;
943
+ }
944
+ function parseIndex(data, { getFn = Config.getFn, fieldNormWeight = Config.fieldNormWeight } = {}) {
945
+ const { keys, records } = data;
946
+ const myIndex = new FuseIndex({ getFn, fieldNormWeight });
947
+ myIndex.setKeys(keys);
948
+ myIndex.setIndexRecords(records);
949
+ return myIndex;
950
+ }
951
+ function computeScore$1(pattern, {
952
+ errors = 0,
953
+ currentLocation = 0,
954
+ expectedLocation = 0,
955
+ distance = Config.distance,
956
+ ignoreLocation = Config.ignoreLocation
957
+ } = {}) {
958
+ const accuracy = errors / pattern.length;
959
+ if (ignoreLocation) {
960
+ return accuracy;
961
+ }
962
+ const proximity = Math.abs(expectedLocation - currentLocation);
963
+ if (!distance) {
964
+ return proximity ? 1 : accuracy;
965
+ }
966
+ return accuracy + proximity / distance;
967
+ }
968
+ function convertMaskToIndices(matchmask = [], minMatchCharLength = Config.minMatchCharLength) {
969
+ let indices = [];
970
+ let start = -1;
971
+ let end = -1;
972
+ let i = 0;
973
+ for (let len = matchmask.length;i < len; i += 1) {
974
+ let match = matchmask[i];
975
+ if (match && start === -1) {
976
+ start = i;
977
+ } else if (!match && start !== -1) {
978
+ end = i - 1;
979
+ if (end - start + 1 >= minMatchCharLength) {
980
+ indices.push([start, end]);
981
+ }
982
+ start = -1;
983
+ }
984
+ }
985
+ if (matchmask[i - 1] && i - start >= minMatchCharLength) {
986
+ indices.push([start, i - 1]);
987
+ }
988
+ return indices;
989
+ }
990
+ var MAX_BITS = 32;
991
+ function search(text, pattern, patternAlphabet, {
992
+ location = Config.location,
993
+ distance = Config.distance,
994
+ threshold = Config.threshold,
995
+ findAllMatches = Config.findAllMatches,
996
+ minMatchCharLength = Config.minMatchCharLength,
997
+ includeMatches = Config.includeMatches,
998
+ ignoreLocation = Config.ignoreLocation
999
+ } = {}) {
1000
+ if (pattern.length > MAX_BITS) {
1001
+ throw new Error(PATTERN_LENGTH_TOO_LARGE(MAX_BITS));
1002
+ }
1003
+ const patternLen = pattern.length;
1004
+ const textLen = text.length;
1005
+ const expectedLocation = Math.max(0, Math.min(location, textLen));
1006
+ let currentThreshold = threshold;
1007
+ let bestLocation = expectedLocation;
1008
+ const computeMatches = minMatchCharLength > 1 || includeMatches;
1009
+ const matchMask = computeMatches ? Array(textLen) : [];
1010
+ let index;
1011
+ while ((index = text.indexOf(pattern, bestLocation)) > -1) {
1012
+ let score = computeScore$1(pattern, {
1013
+ currentLocation: index,
1014
+ expectedLocation,
1015
+ distance,
1016
+ ignoreLocation
1017
+ });
1018
+ currentThreshold = Math.min(score, currentThreshold);
1019
+ bestLocation = index + patternLen;
1020
+ if (computeMatches) {
1021
+ let i = 0;
1022
+ while (i < patternLen) {
1023
+ matchMask[index + i] = 1;
1024
+ i += 1;
1025
+ }
1026
+ }
1027
+ }
1028
+ bestLocation = -1;
1029
+ let lastBitArr = [];
1030
+ let finalScore = 1;
1031
+ let binMax = patternLen + textLen;
1032
+ const mask = 1 << patternLen - 1;
1033
+ for (let i = 0;i < patternLen; i += 1) {
1034
+ let binMin = 0;
1035
+ let binMid = binMax;
1036
+ while (binMin < binMid) {
1037
+ const score2 = computeScore$1(pattern, {
1038
+ errors: i,
1039
+ currentLocation: expectedLocation + binMid,
1040
+ expectedLocation,
1041
+ distance,
1042
+ ignoreLocation
1043
+ });
1044
+ if (score2 <= currentThreshold) {
1045
+ binMin = binMid;
1046
+ } else {
1047
+ binMax = binMid;
1048
+ }
1049
+ binMid = Math.floor((binMax - binMin) / 2 + binMin);
1050
+ }
1051
+ binMax = binMid;
1052
+ let start = Math.max(1, expectedLocation - binMid + 1);
1053
+ let finish = findAllMatches ? textLen : Math.min(expectedLocation + binMid, textLen) + patternLen;
1054
+ let bitArr = Array(finish + 2);
1055
+ bitArr[finish + 1] = (1 << i) - 1;
1056
+ for (let j = finish;j >= start; j -= 1) {
1057
+ let currentLocation = j - 1;
1058
+ let charMatch = patternAlphabet[text.charAt(currentLocation)];
1059
+ if (computeMatches) {
1060
+ matchMask[currentLocation] = +!!charMatch;
1061
+ }
1062
+ bitArr[j] = (bitArr[j + 1] << 1 | 1) & charMatch;
1063
+ if (i) {
1064
+ bitArr[j] |= (lastBitArr[j + 1] | lastBitArr[j]) << 1 | 1 | lastBitArr[j + 1];
1065
+ }
1066
+ if (bitArr[j] & mask) {
1067
+ finalScore = computeScore$1(pattern, {
1068
+ errors: i,
1069
+ currentLocation,
1070
+ expectedLocation,
1071
+ distance,
1072
+ ignoreLocation
1073
+ });
1074
+ if (finalScore <= currentThreshold) {
1075
+ currentThreshold = finalScore;
1076
+ bestLocation = currentLocation;
1077
+ if (bestLocation <= expectedLocation) {
1078
+ break;
1079
+ }
1080
+ start = Math.max(1, 2 * expectedLocation - bestLocation);
1081
+ }
1082
+ }
1083
+ }
1084
+ const score = computeScore$1(pattern, {
1085
+ errors: i + 1,
1086
+ currentLocation: expectedLocation,
1087
+ expectedLocation,
1088
+ distance,
1089
+ ignoreLocation
1090
+ });
1091
+ if (score > currentThreshold) {
1092
+ break;
1093
+ }
1094
+ lastBitArr = bitArr;
1095
+ }
1096
+ const result = {
1097
+ isMatch: bestLocation >= 0,
1098
+ score: Math.max(0.001, finalScore)
1099
+ };
1100
+ if (computeMatches) {
1101
+ const indices = convertMaskToIndices(matchMask, minMatchCharLength);
1102
+ if (!indices.length) {
1103
+ result.isMatch = false;
1104
+ } else if (includeMatches) {
1105
+ result.indices = indices;
1106
+ }
1107
+ }
1108
+ return result;
1109
+ }
1110
+ function createPatternAlphabet(pattern) {
1111
+ let mask = {};
1112
+ for (let i = 0, len = pattern.length;i < len; i += 1) {
1113
+ const char = pattern.charAt(i);
1114
+ mask[char] = (mask[char] || 0) | 1 << len - i - 1;
1115
+ }
1116
+ return mask;
1117
+ }
1118
+ var stripDiacritics = String.prototype.normalize ? (str) => str.normalize("NFD").replace(/[\u0300-\u036F\u0483-\u0489\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u0610-\u061A\u064B-\u065F\u0670\u06D6-\u06DC\u06DF-\u06E4\u06E7\u06E8\u06EA-\u06ED\u0711\u0730-\u074A\u07A6-\u07B0\u07EB-\u07F3\u07FD\u0816-\u0819\u081B-\u0823\u0825-\u0827\u0829-\u082D\u0859-\u085B\u08D3-\u08E1\u08E3-\u0903\u093A-\u093C\u093E-\u094F\u0951-\u0957\u0962\u0963\u0981-\u0983\u09BC\u09BE-\u09C4\u09C7\u09C8\u09CB-\u09CD\u09D7\u09E2\u09E3\u09FE\u0A01-\u0A03\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A70\u0A71\u0A75\u0A81-\u0A83\u0ABC\u0ABE-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AE2\u0AE3\u0AFA-\u0AFF\u0B01-\u0B03\u0B3C\u0B3E-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B62\u0B63\u0B82\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD7\u0C00-\u0C04\u0C3E-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C62\u0C63\u0C81-\u0C83\u0CBC\u0CBE-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CE2\u0CE3\u0D00-\u0D03\u0D3B\u0D3C\u0D3E-\u0D44\u0D46-\u0D48\u0D4A-\u0D4D\u0D57\u0D62\u0D63\u0D82\u0D83\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DF2\u0DF3\u0E31\u0E34-\u0E3A\u0E47-\u0E4E\u0EB1\u0EB4-\u0EB9\u0EBB\u0EBC\u0EC8-\u0ECD\u0F18\u0F19\u0F35\u0F37\u0F39\u0F3E\u0F3F\u0F71-\u0F84\u0F86\u0F87\u0F8D-\u0F97\u0F99-\u0FBC\u0FC6\u102B-\u103E\u1056-\u1059\u105E-\u1060\u1062-\u1064\u1067-\u106D\u1071-\u1074\u1082-\u108D\u108F\u109A-\u109D\u135D-\u135F\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17B4-\u17D3\u17DD\u180B-\u180D\u1885\u1886\u18A9\u1920-\u192B\u1930-\u193B\u1A17-\u1A1B\u1A55-\u1A5E\u1A60-\u1A7C\u1A7F\u1AB0-\u1ABE\u1B00-\u1B04\u1B34-\u1B44\u1B6B-\u1B73\u1B80-\u1B82\u1BA1-\u1BAD\u1BE6-\u1BF3\u1C24-\u1C37\u1CD0-\u1CD2\u1CD4-\u1CE8\u1CED\u1CF2-\u1CF4\u1CF7-\u1CF9\u1DC0-\u1DF9\u1DFB-\u1DFF\u20D0-\u20F0\u2CEF-\u2CF1\u2D7F\u2DE0-\u2DFF\u302A-\u302F\u3099\u309A\uA66F-\uA672\uA674-\uA67D\uA69E\uA69F\uA6F0\uA6F1\uA802\uA806\uA80B\uA823-\uA827\uA880\uA881\uA8B4-\uA8C5\uA8E0-\uA8F1\uA8FF\uA926-\uA92D\uA947-\uA953\uA980-\uA983\uA9B3-\uA9C0\uA9E5\uAA29-\uAA36\uAA43\uAA4C\uAA4D\uAA7B-\uAA7D\uAAB0\uAAB2-\uAAB4\uAAB7\uAAB8\uAABE\uAABF\uAAC1\uAAEB-\uAAEF\uAAF5\uAAF6\uABE3-\uABEA\uABEC\uABED\uFB1E\uFE00-\uFE0F\uFE20-\uFE2F]/g, "") : (str) => str;
1119
+
1120
+ class BitapSearch {
1121
+ constructor(pattern, {
1122
+ location = Config.location,
1123
+ threshold = Config.threshold,
1124
+ distance = Config.distance,
1125
+ includeMatches = Config.includeMatches,
1126
+ findAllMatches = Config.findAllMatches,
1127
+ minMatchCharLength = Config.minMatchCharLength,
1128
+ isCaseSensitive = Config.isCaseSensitive,
1129
+ ignoreDiacritics = Config.ignoreDiacritics,
1130
+ ignoreLocation = Config.ignoreLocation
1131
+ } = {}) {
1132
+ this.options = {
1133
+ location,
1134
+ threshold,
1135
+ distance,
1136
+ includeMatches,
1137
+ findAllMatches,
1138
+ minMatchCharLength,
1139
+ isCaseSensitive,
1140
+ ignoreDiacritics,
1141
+ ignoreLocation
1142
+ };
1143
+ pattern = isCaseSensitive ? pattern : pattern.toLowerCase();
1144
+ pattern = ignoreDiacritics ? stripDiacritics(pattern) : pattern;
1145
+ this.pattern = pattern;
1146
+ this.chunks = [];
1147
+ if (!this.pattern.length) {
1148
+ return;
1149
+ }
1150
+ const addChunk = (pattern2, startIndex) => {
1151
+ this.chunks.push({
1152
+ pattern: pattern2,
1153
+ alphabet: createPatternAlphabet(pattern2),
1154
+ startIndex
1155
+ });
1156
+ };
1157
+ const len = this.pattern.length;
1158
+ if (len > MAX_BITS) {
1159
+ let i = 0;
1160
+ const remainder = len % MAX_BITS;
1161
+ const end = len - remainder;
1162
+ while (i < end) {
1163
+ addChunk(this.pattern.substr(i, MAX_BITS), i);
1164
+ i += MAX_BITS;
1165
+ }
1166
+ if (remainder) {
1167
+ const startIndex = len - MAX_BITS;
1168
+ addChunk(this.pattern.substr(startIndex), startIndex);
1169
+ }
1170
+ } else {
1171
+ addChunk(this.pattern, 0);
1172
+ }
1173
+ }
1174
+ searchIn(text) {
1175
+ const { isCaseSensitive, ignoreDiacritics, includeMatches } = this.options;
1176
+ text = isCaseSensitive ? text : text.toLowerCase();
1177
+ text = ignoreDiacritics ? stripDiacritics(text) : text;
1178
+ if (this.pattern === text) {
1179
+ let result2 = {
1180
+ isMatch: true,
1181
+ score: 0
1182
+ };
1183
+ if (includeMatches) {
1184
+ result2.indices = [[0, text.length - 1]];
1185
+ }
1186
+ return result2;
1187
+ }
1188
+ const {
1189
+ location,
1190
+ distance,
1191
+ threshold,
1192
+ findAllMatches,
1193
+ minMatchCharLength,
1194
+ ignoreLocation
1195
+ } = this.options;
1196
+ let allIndices = [];
1197
+ let totalScore = 0;
1198
+ let hasMatches = false;
1199
+ this.chunks.forEach(({ pattern, alphabet, startIndex }) => {
1200
+ const { isMatch, score, indices } = search(text, pattern, alphabet, {
1201
+ location: location + startIndex,
1202
+ distance,
1203
+ threshold,
1204
+ findAllMatches,
1205
+ minMatchCharLength,
1206
+ includeMatches,
1207
+ ignoreLocation
1208
+ });
1209
+ if (isMatch) {
1210
+ hasMatches = true;
1211
+ }
1212
+ totalScore += score;
1213
+ if (isMatch && indices) {
1214
+ allIndices = [...allIndices, ...indices];
1215
+ }
1216
+ });
1217
+ let result = {
1218
+ isMatch: hasMatches,
1219
+ score: hasMatches ? totalScore / this.chunks.length : 1
1220
+ };
1221
+ if (hasMatches && includeMatches) {
1222
+ result.indices = allIndices;
1223
+ }
1224
+ return result;
1225
+ }
1226
+ }
1227
+
1228
+ class BaseMatch {
1229
+ constructor(pattern) {
1230
+ this.pattern = pattern;
1231
+ }
1232
+ static isMultiMatch(pattern) {
1233
+ return getMatch(pattern, this.multiRegex);
1234
+ }
1235
+ static isSingleMatch(pattern) {
1236
+ return getMatch(pattern, this.singleRegex);
1237
+ }
1238
+ search() {}
1239
+ }
1240
+ function getMatch(pattern, exp) {
1241
+ const matches = pattern.match(exp);
1242
+ return matches ? matches[1] : null;
1243
+ }
1244
+
1245
+ class ExactMatch extends BaseMatch {
1246
+ constructor(pattern) {
1247
+ super(pattern);
1248
+ }
1249
+ static get type() {
1250
+ return "exact";
1251
+ }
1252
+ static get multiRegex() {
1253
+ return /^="(.*)"$/;
1254
+ }
1255
+ static get singleRegex() {
1256
+ return /^=(.*)$/;
1257
+ }
1258
+ search(text) {
1259
+ const isMatch = text === this.pattern;
1260
+ return {
1261
+ isMatch,
1262
+ score: isMatch ? 0 : 1,
1263
+ indices: [0, this.pattern.length - 1]
1264
+ };
1265
+ }
1266
+ }
1267
+
1268
+ class InverseExactMatch extends BaseMatch {
1269
+ constructor(pattern) {
1270
+ super(pattern);
1271
+ }
1272
+ static get type() {
1273
+ return "inverse-exact";
1274
+ }
1275
+ static get multiRegex() {
1276
+ return /^!"(.*)"$/;
1277
+ }
1278
+ static get singleRegex() {
1279
+ return /^!(.*)$/;
1280
+ }
1281
+ search(text) {
1282
+ const index = text.indexOf(this.pattern);
1283
+ const isMatch = index === -1;
1284
+ return {
1285
+ isMatch,
1286
+ score: isMatch ? 0 : 1,
1287
+ indices: [0, text.length - 1]
1288
+ };
1289
+ }
1290
+ }
1291
+
1292
+ class PrefixExactMatch extends BaseMatch {
1293
+ constructor(pattern) {
1294
+ super(pattern);
1295
+ }
1296
+ static get type() {
1297
+ return "prefix-exact";
1298
+ }
1299
+ static get multiRegex() {
1300
+ return /^\^"(.*)"$/;
1301
+ }
1302
+ static get singleRegex() {
1303
+ return /^\^(.*)$/;
1304
+ }
1305
+ search(text) {
1306
+ const isMatch = text.startsWith(this.pattern);
1307
+ return {
1308
+ isMatch,
1309
+ score: isMatch ? 0 : 1,
1310
+ indices: [0, this.pattern.length - 1]
1311
+ };
1312
+ }
1313
+ }
1314
+
1315
+ class InversePrefixExactMatch extends BaseMatch {
1316
+ constructor(pattern) {
1317
+ super(pattern);
1318
+ }
1319
+ static get type() {
1320
+ return "inverse-prefix-exact";
1321
+ }
1322
+ static get multiRegex() {
1323
+ return /^!\^"(.*)"$/;
1324
+ }
1325
+ static get singleRegex() {
1326
+ return /^!\^(.*)$/;
1327
+ }
1328
+ search(text) {
1329
+ const isMatch = !text.startsWith(this.pattern);
1330
+ return {
1331
+ isMatch,
1332
+ score: isMatch ? 0 : 1,
1333
+ indices: [0, text.length - 1]
1334
+ };
1335
+ }
1336
+ }
1337
+
1338
+ class SuffixExactMatch extends BaseMatch {
1339
+ constructor(pattern) {
1340
+ super(pattern);
1341
+ }
1342
+ static get type() {
1343
+ return "suffix-exact";
1344
+ }
1345
+ static get multiRegex() {
1346
+ return /^"(.*)"\$$/;
1347
+ }
1348
+ static get singleRegex() {
1349
+ return /^(.*)\$$/;
1350
+ }
1351
+ search(text) {
1352
+ const isMatch = text.endsWith(this.pattern);
1353
+ return {
1354
+ isMatch,
1355
+ score: isMatch ? 0 : 1,
1356
+ indices: [text.length - this.pattern.length, text.length - 1]
1357
+ };
1358
+ }
1359
+ }
1360
+
1361
+ class InverseSuffixExactMatch extends BaseMatch {
1362
+ constructor(pattern) {
1363
+ super(pattern);
1364
+ }
1365
+ static get type() {
1366
+ return "inverse-suffix-exact";
1367
+ }
1368
+ static get multiRegex() {
1369
+ return /^!"(.*)"\$$/;
1370
+ }
1371
+ static get singleRegex() {
1372
+ return /^!(.*)\$$/;
1373
+ }
1374
+ search(text) {
1375
+ const isMatch = !text.endsWith(this.pattern);
1376
+ return {
1377
+ isMatch,
1378
+ score: isMatch ? 0 : 1,
1379
+ indices: [0, text.length - 1]
1380
+ };
1381
+ }
1382
+ }
1383
+
1384
+ class FuzzyMatch extends BaseMatch {
1385
+ constructor(pattern, {
1386
+ location = Config.location,
1387
+ threshold = Config.threshold,
1388
+ distance = Config.distance,
1389
+ includeMatches = Config.includeMatches,
1390
+ findAllMatches = Config.findAllMatches,
1391
+ minMatchCharLength = Config.minMatchCharLength,
1392
+ isCaseSensitive = Config.isCaseSensitive,
1393
+ ignoreDiacritics = Config.ignoreDiacritics,
1394
+ ignoreLocation = Config.ignoreLocation
1395
+ } = {}) {
1396
+ super(pattern);
1397
+ this._bitapSearch = new BitapSearch(pattern, {
1398
+ location,
1399
+ threshold,
1400
+ distance,
1401
+ includeMatches,
1402
+ findAllMatches,
1403
+ minMatchCharLength,
1404
+ isCaseSensitive,
1405
+ ignoreDiacritics,
1406
+ ignoreLocation
1407
+ });
1408
+ }
1409
+ static get type() {
1410
+ return "fuzzy";
1411
+ }
1412
+ static get multiRegex() {
1413
+ return /^"(.*)"$/;
1414
+ }
1415
+ static get singleRegex() {
1416
+ return /^(.*)$/;
1417
+ }
1418
+ search(text) {
1419
+ return this._bitapSearch.searchIn(text);
1420
+ }
1421
+ }
1422
+
1423
+ class IncludeMatch extends BaseMatch {
1424
+ constructor(pattern) {
1425
+ super(pattern);
1426
+ }
1427
+ static get type() {
1428
+ return "include";
1429
+ }
1430
+ static get multiRegex() {
1431
+ return /^'"(.*)"$/;
1432
+ }
1433
+ static get singleRegex() {
1434
+ return /^'(.*)$/;
1435
+ }
1436
+ search(text) {
1437
+ let location = 0;
1438
+ let index;
1439
+ const indices = [];
1440
+ const patternLen = this.pattern.length;
1441
+ while ((index = text.indexOf(this.pattern, location)) > -1) {
1442
+ location = index + patternLen;
1443
+ indices.push([index, location - 1]);
1444
+ }
1445
+ const isMatch = !!indices.length;
1446
+ return {
1447
+ isMatch,
1448
+ score: isMatch ? 0 : 1,
1449
+ indices
1450
+ };
1451
+ }
1452
+ }
1453
+ var searchers = [
1454
+ ExactMatch,
1455
+ IncludeMatch,
1456
+ PrefixExactMatch,
1457
+ InversePrefixExactMatch,
1458
+ InverseSuffixExactMatch,
1459
+ SuffixExactMatch,
1460
+ InverseExactMatch,
1461
+ FuzzyMatch
1462
+ ];
1463
+ var searchersLen = searchers.length;
1464
+ var SPACE_RE = / +(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)/;
1465
+ var OR_TOKEN = "|";
1466
+ function parseQuery2(pattern, options = {}) {
1467
+ return pattern.split(OR_TOKEN).map((item) => {
1468
+ let query = item.trim().split(SPACE_RE).filter((item2) => item2 && !!item2.trim());
1469
+ let results = [];
1470
+ for (let i = 0, len = query.length;i < len; i += 1) {
1471
+ const queryItem = query[i];
1472
+ let found = false;
1473
+ let idx = -1;
1474
+ while (!found && ++idx < searchersLen) {
1475
+ const searcher = searchers[idx];
1476
+ let token = searcher.isMultiMatch(queryItem);
1477
+ if (token) {
1478
+ results.push(new searcher(token, options));
1479
+ found = true;
1480
+ }
1481
+ }
1482
+ if (found) {
1483
+ continue;
1484
+ }
1485
+ idx = -1;
1486
+ while (++idx < searchersLen) {
1487
+ const searcher = searchers[idx];
1488
+ let token = searcher.isSingleMatch(queryItem);
1489
+ if (token) {
1490
+ results.push(new searcher(token, options));
1491
+ break;
1492
+ }
1493
+ }
1494
+ }
1495
+ return results;
1496
+ });
1497
+ }
1498
+ var MultiMatchSet = new Set([FuzzyMatch.type, IncludeMatch.type]);
1499
+
1500
+ class ExtendedSearch {
1501
+ constructor(pattern, {
1502
+ isCaseSensitive = Config.isCaseSensitive,
1503
+ ignoreDiacritics = Config.ignoreDiacritics,
1504
+ includeMatches = Config.includeMatches,
1505
+ minMatchCharLength = Config.minMatchCharLength,
1506
+ ignoreLocation = Config.ignoreLocation,
1507
+ findAllMatches = Config.findAllMatches,
1508
+ location = Config.location,
1509
+ threshold = Config.threshold,
1510
+ distance = Config.distance
1511
+ } = {}) {
1512
+ this.query = null;
1513
+ this.options = {
1514
+ isCaseSensitive,
1515
+ ignoreDiacritics,
1516
+ includeMatches,
1517
+ minMatchCharLength,
1518
+ findAllMatches,
1519
+ ignoreLocation,
1520
+ location,
1521
+ threshold,
1522
+ distance
1523
+ };
1524
+ pattern = isCaseSensitive ? pattern : pattern.toLowerCase();
1525
+ pattern = ignoreDiacritics ? stripDiacritics(pattern) : pattern;
1526
+ this.pattern = pattern;
1527
+ this.query = parseQuery2(this.pattern, this.options);
1528
+ }
1529
+ static condition(_, options) {
1530
+ return options.useExtendedSearch;
1531
+ }
1532
+ searchIn(text) {
1533
+ const query = this.query;
1534
+ if (!query) {
1535
+ return {
1536
+ isMatch: false,
1537
+ score: 1
1538
+ };
1539
+ }
1540
+ const { includeMatches, isCaseSensitive, ignoreDiacritics } = this.options;
1541
+ text = isCaseSensitive ? text : text.toLowerCase();
1542
+ text = ignoreDiacritics ? stripDiacritics(text) : text;
1543
+ let numMatches = 0;
1544
+ let allIndices = [];
1545
+ let totalScore = 0;
1546
+ for (let i = 0, qLen = query.length;i < qLen; i += 1) {
1547
+ const searchers2 = query[i];
1548
+ allIndices.length = 0;
1549
+ numMatches = 0;
1550
+ for (let j = 0, pLen = searchers2.length;j < pLen; j += 1) {
1551
+ const searcher = searchers2[j];
1552
+ const { isMatch, indices, score } = searcher.search(text);
1553
+ if (isMatch) {
1554
+ numMatches += 1;
1555
+ totalScore += score;
1556
+ if (includeMatches) {
1557
+ const type = searcher.constructor.type;
1558
+ if (MultiMatchSet.has(type)) {
1559
+ allIndices = [...allIndices, ...indices];
1560
+ } else {
1561
+ allIndices.push(indices);
1562
+ }
1563
+ }
1564
+ } else {
1565
+ totalScore = 0;
1566
+ numMatches = 0;
1567
+ allIndices.length = 0;
1568
+ break;
1569
+ }
1570
+ }
1571
+ if (numMatches) {
1572
+ let result = {
1573
+ isMatch: true,
1574
+ score: totalScore / numMatches
1575
+ };
1576
+ if (includeMatches) {
1577
+ result.indices = allIndices;
1578
+ }
1579
+ return result;
1580
+ }
1581
+ }
1582
+ return {
1583
+ isMatch: false,
1584
+ score: 1
1585
+ };
1586
+ }
1587
+ }
1588
+ var registeredSearchers = [];
1589
+ function register(...args) {
1590
+ registeredSearchers.push(...args);
1591
+ }
1592
+ function createSearcher(pattern, options) {
1593
+ for (let i = 0, len = registeredSearchers.length;i < len; i += 1) {
1594
+ let searcherClass = registeredSearchers[i];
1595
+ if (searcherClass.condition(pattern, options)) {
1596
+ return new searcherClass(pattern, options);
1597
+ }
1598
+ }
1599
+ return new BitapSearch(pattern, options);
1600
+ }
1601
+ var LogicalOperator = {
1602
+ AND: "$and",
1603
+ OR: "$or"
1604
+ };
1605
+ var KeyType = {
1606
+ PATH: "$path",
1607
+ PATTERN: "$val"
1608
+ };
1609
+ var isExpression = (query) => !!(query[LogicalOperator.AND] || query[LogicalOperator.OR]);
1610
+ var isPath = (query) => !!query[KeyType.PATH];
1611
+ var isLeaf = (query) => !isArray(query) && isObject(query) && !isExpression(query);
1612
+ var convertToExplicit = (query) => ({
1613
+ [LogicalOperator.AND]: Object.keys(query).map((key) => ({
1614
+ [key]: query[key]
1615
+ }))
1616
+ });
1617
+ function parse(query, options, { auto = true } = {}) {
1618
+ const next = (query2) => {
1619
+ let keys = Object.keys(query2);
1620
+ const isQueryPath = isPath(query2);
1621
+ if (!isQueryPath && keys.length > 1 && !isExpression(query2)) {
1622
+ return next(convertToExplicit(query2));
1623
+ }
1624
+ if (isLeaf(query2)) {
1625
+ const key = isQueryPath ? query2[KeyType.PATH] : keys[0];
1626
+ const pattern = isQueryPath ? query2[KeyType.PATTERN] : query2[key];
1627
+ if (!isString(pattern)) {
1628
+ throw new Error(LOGICAL_SEARCH_INVALID_QUERY_FOR_KEY(key));
1629
+ }
1630
+ const obj = {
1631
+ keyId: createKeyId(key),
1632
+ pattern
1633
+ };
1634
+ if (auto) {
1635
+ obj.searcher = createSearcher(pattern, options);
1636
+ }
1637
+ return obj;
1638
+ }
1639
+ let node = {
1640
+ children: [],
1641
+ operator: keys[0]
1642
+ };
1643
+ keys.forEach((key) => {
1644
+ const value = query2[key];
1645
+ if (isArray(value)) {
1646
+ value.forEach((item) => {
1647
+ node.children.push(next(item));
1648
+ });
1649
+ }
1650
+ });
1651
+ return node;
1652
+ };
1653
+ if (!isExpression(query)) {
1654
+ query = convertToExplicit(query);
1655
+ }
1656
+ return next(query);
1657
+ }
1658
+ function computeScore(results, { ignoreFieldNorm = Config.ignoreFieldNorm }) {
1659
+ results.forEach((result) => {
1660
+ let totalScore = 1;
1661
+ result.matches.forEach(({ key, norm: norm2, score }) => {
1662
+ const weight = key ? key.weight : null;
1663
+ totalScore *= Math.pow(score === 0 && weight ? Number.EPSILON : score, (weight || 1) * (ignoreFieldNorm ? 1 : norm2));
1664
+ });
1665
+ result.score = totalScore;
1666
+ });
1667
+ }
1668
+ function transformMatches(result, data) {
1669
+ const matches = result.matches;
1670
+ data.matches = [];
1671
+ if (!isDefined(matches)) {
1672
+ return;
1673
+ }
1674
+ matches.forEach((match) => {
1675
+ if (!isDefined(match.indices) || !match.indices.length) {
1676
+ return;
1677
+ }
1678
+ const { indices, value } = match;
1679
+ let obj = {
1680
+ indices,
1681
+ value
1682
+ };
1683
+ if (match.key) {
1684
+ obj.key = match.key.src;
1685
+ }
1686
+ if (match.idx > -1) {
1687
+ obj.refIndex = match.idx;
1688
+ }
1689
+ data.matches.push(obj);
1690
+ });
1691
+ }
1692
+ function transformScore(result, data) {
1693
+ data.score = result.score;
1694
+ }
1695
+ function format(results, docs, {
1696
+ includeMatches = Config.includeMatches,
1697
+ includeScore = Config.includeScore
1698
+ } = {}) {
1699
+ const transformers = [];
1700
+ if (includeMatches)
1701
+ transformers.push(transformMatches);
1702
+ if (includeScore)
1703
+ transformers.push(transformScore);
1704
+ return results.map((result) => {
1705
+ const { idx } = result;
1706
+ const data = {
1707
+ item: docs[idx],
1708
+ refIndex: idx
1709
+ };
1710
+ if (transformers.length) {
1711
+ transformers.forEach((transformer) => {
1712
+ transformer(result, data);
1713
+ });
1714
+ }
1715
+ return data;
1716
+ });
1717
+ }
1718
+
1719
+ class Fuse {
1720
+ constructor(docs, options = {}, index) {
1721
+ this.options = { ...Config, ...options };
1722
+ if (this.options.useExtendedSearch && false) {}
1723
+ this._keyStore = new KeyStore(this.options.keys);
1724
+ this.setCollection(docs, index);
1725
+ }
1726
+ setCollection(docs, index) {
1727
+ this._docs = docs;
1728
+ if (index && !(index instanceof FuseIndex)) {
1729
+ throw new Error(INCORRECT_INDEX_TYPE);
1730
+ }
1731
+ this._myIndex = index || createIndex(this.options.keys, this._docs, {
1732
+ getFn: this.options.getFn,
1733
+ fieldNormWeight: this.options.fieldNormWeight
1734
+ });
1735
+ }
1736
+ add(doc) {
1737
+ if (!isDefined(doc)) {
1738
+ return;
1739
+ }
1740
+ this._docs.push(doc);
1741
+ this._myIndex.add(doc);
1742
+ }
1743
+ remove(predicate = () => false) {
1744
+ const results = [];
1745
+ for (let i = 0, len = this._docs.length;i < len; i += 1) {
1746
+ const doc = this._docs[i];
1747
+ if (predicate(doc, i)) {
1748
+ this.removeAt(i);
1749
+ i -= 1;
1750
+ len -= 1;
1751
+ results.push(doc);
1752
+ }
1753
+ }
1754
+ return results;
1755
+ }
1756
+ removeAt(idx) {
1757
+ this._docs.splice(idx, 1);
1758
+ this._myIndex.removeAt(idx);
1759
+ }
1760
+ getIndex() {
1761
+ return this._myIndex;
1762
+ }
1763
+ search(query, { limit = -1 } = {}) {
1764
+ const {
1765
+ includeMatches,
1766
+ includeScore,
1767
+ shouldSort,
1768
+ sortFn,
1769
+ ignoreFieldNorm
1770
+ } = this.options;
1771
+ let results = isString(query) ? isString(this._docs[0]) ? this._searchStringList(query) : this._searchObjectList(query) : this._searchLogical(query);
1772
+ computeScore(results, { ignoreFieldNorm });
1773
+ if (shouldSort) {
1774
+ results.sort(sortFn);
1775
+ }
1776
+ if (isNumber(limit) && limit > -1) {
1777
+ results = results.slice(0, limit);
1778
+ }
1779
+ return format(results, this._docs, {
1780
+ includeMatches,
1781
+ includeScore
1782
+ });
1783
+ }
1784
+ _searchStringList(query) {
1785
+ const searcher = createSearcher(query, this.options);
1786
+ const { records } = this._myIndex;
1787
+ const results = [];
1788
+ records.forEach(({ v: text, i: idx, n: norm2 }) => {
1789
+ if (!isDefined(text)) {
1790
+ return;
1791
+ }
1792
+ const { isMatch, score, indices } = searcher.searchIn(text);
1793
+ if (isMatch) {
1794
+ results.push({
1795
+ item: text,
1796
+ idx,
1797
+ matches: [{ score, value: text, norm: norm2, indices }]
1798
+ });
1799
+ }
1800
+ });
1801
+ return results;
1802
+ }
1803
+ _searchLogical(query) {
1804
+ const expression = parse(query, this.options);
1805
+ const evaluate = (node, item, idx) => {
1806
+ if (!node.children) {
1807
+ const { keyId, searcher } = node;
1808
+ const matches = this._findMatches({
1809
+ key: this._keyStore.get(keyId),
1810
+ value: this._myIndex.getValueForItemAtKeyId(item, keyId),
1811
+ searcher
1812
+ });
1813
+ if (matches && matches.length) {
1814
+ return [
1815
+ {
1816
+ idx,
1817
+ item,
1818
+ matches
1819
+ }
1820
+ ];
1821
+ }
1822
+ return [];
1823
+ }
1824
+ const res = [];
1825
+ for (let i = 0, len = node.children.length;i < len; i += 1) {
1826
+ const child = node.children[i];
1827
+ const result = evaluate(child, item, idx);
1828
+ if (result.length) {
1829
+ res.push(...result);
1830
+ } else if (node.operator === LogicalOperator.AND) {
1831
+ return [];
1832
+ }
1833
+ }
1834
+ return res;
1835
+ };
1836
+ const records = this._myIndex.records;
1837
+ const resultMap = {};
1838
+ const results = [];
1839
+ records.forEach(({ $: item, i: idx }) => {
1840
+ if (isDefined(item)) {
1841
+ let expResults = evaluate(expression, item, idx);
1842
+ if (expResults.length) {
1843
+ if (!resultMap[idx]) {
1844
+ resultMap[idx] = { idx, item, matches: [] };
1845
+ results.push(resultMap[idx]);
1846
+ }
1847
+ expResults.forEach(({ matches }) => {
1848
+ resultMap[idx].matches.push(...matches);
1849
+ });
1850
+ }
1851
+ }
1852
+ });
1853
+ return results;
1854
+ }
1855
+ _searchObjectList(query) {
1856
+ const searcher = createSearcher(query, this.options);
1857
+ const { keys, records } = this._myIndex;
1858
+ const results = [];
1859
+ records.forEach(({ $: item, i: idx }) => {
1860
+ if (!isDefined(item)) {
1861
+ return;
1862
+ }
1863
+ let matches = [];
1864
+ keys.forEach((key, keyIndex) => {
1865
+ matches.push(...this._findMatches({
1866
+ key,
1867
+ value: item[keyIndex],
1868
+ searcher
1869
+ }));
1870
+ });
1871
+ if (matches.length) {
1872
+ results.push({
1873
+ idx,
1874
+ item,
1875
+ matches
1876
+ });
1877
+ }
1878
+ });
1879
+ return results;
1880
+ }
1881
+ _findMatches({ key, value, searcher }) {
1882
+ if (!isDefined(value)) {
1883
+ return [];
1884
+ }
1885
+ let matches = [];
1886
+ if (isArray(value)) {
1887
+ value.forEach(({ v: text, i: idx, n: norm2 }) => {
1888
+ if (!isDefined(text)) {
1889
+ return;
1890
+ }
1891
+ const { isMatch, score, indices } = searcher.searchIn(text);
1892
+ if (isMatch) {
1893
+ matches.push({
1894
+ score,
1895
+ key,
1896
+ value: text,
1897
+ idx,
1898
+ norm: norm2,
1899
+ indices
1900
+ });
1901
+ }
1902
+ });
1903
+ } else {
1904
+ const { v: text, n: norm2 } = value;
1905
+ const { isMatch, score, indices } = searcher.searchIn(text);
1906
+ if (isMatch) {
1907
+ matches.push({ score, key, value: text, norm: norm2, indices });
1908
+ }
1909
+ }
1910
+ return matches;
1911
+ }
1912
+ }
1913
+ Fuse.version = "7.1.0";
1914
+ Fuse.createIndex = createIndex;
1915
+ Fuse.parseIndex = parseIndex;
1916
+ Fuse.config = Config;
1917
+ {
1918
+ Fuse.parseQuery = parse;
1919
+ }
1920
+ {
1921
+ register(ExtendedSearch);
1922
+ }
1923
+
1924
+ // ../core/src/lib/search.ts
1925
+ var FUSE_OPTIONS = {
1926
+ keys: [
1927
+ { name: "frontmatter.title", weight: 1 },
1928
+ { name: "frontmatter.description", weight: 0.7 },
1929
+ { name: "frontmatter.labels", weight: 0.5 },
1930
+ { name: "content", weight: 0.3 }
1931
+ ],
1932
+ threshold: 0.4,
1933
+ ignoreLocation: true,
1934
+ includeScore: true
1935
+ };
1936
+ function createSearchIndex(issues) {
1937
+ return new Fuse(issues, FUSE_OPTIONS);
1938
+ }
1939
+ function sortIssues(issues, sortBy) {
1940
+ const sortOption = sortBy.toLowerCase();
1941
+ if (sortOption === "roadmap") {
1942
+ issues.sort((a, b) => {
1943
+ const orderA = a.frontmatter.order;
1944
+ const orderB = b.frontmatter.order;
1945
+ if (orderA && orderB)
1946
+ return orderA < orderB ? -1 : orderA > orderB ? 1 : 0;
1947
+ if (orderA && !orderB)
1948
+ return -1;
1949
+ if (!orderA && orderB)
1950
+ return 1;
1951
+ return a.id < b.id ? -1 : a.id > b.id ? 1 : 0;
1952
+ });
1953
+ } else if (sortOption === "priority") {
1954
+ const priorityOrder = {
1955
+ high: 0,
1956
+ medium: 1,
1957
+ low: 2
1958
+ };
1959
+ issues.sort((a, b) => {
1960
+ const priorityA = priorityOrder[a.frontmatter.priority] ?? 999;
1961
+ const priorityB = priorityOrder[b.frontmatter.priority] ?? 999;
1962
+ if (priorityA !== priorityB)
1963
+ return priorityA - priorityB;
1964
+ return b.id.localeCompare(a.id);
1965
+ });
1966
+ } else if (sortOption === "scope") {
1967
+ const scopeOrder = {
1968
+ small: 0,
1969
+ medium: 1,
1970
+ large: 2
1971
+ };
1972
+ issues.sort((a, b) => {
1973
+ const scopeA = a.frontmatter.scope ? scopeOrder[a.frontmatter.scope] ?? 99 : 99;
1974
+ const scopeB = b.frontmatter.scope ? scopeOrder[b.frontmatter.scope] ?? 99 : 99;
1975
+ if (scopeA !== scopeB)
1976
+ return scopeA - scopeB;
1977
+ return b.id.localeCompare(a.id);
1978
+ });
1979
+ } else if (sortOption === "created") {
1980
+ issues.sort((a, b) => {
1981
+ const dateA = a.frontmatter.created || "";
1982
+ const dateB = b.frontmatter.created || "";
1983
+ if (dateA !== dateB)
1984
+ return dateB.localeCompare(dateA);
1985
+ return b.id.localeCompare(a.id);
1986
+ });
1987
+ } else if (sortOption === "created-asc") {
1988
+ issues.sort((a, b) => {
1989
+ const dateA = a.frontmatter.created || "";
1990
+ const dateB = b.frontmatter.created || "";
1991
+ if (dateA !== dateB)
1992
+ return dateA.localeCompare(dateB);
1993
+ return a.id.localeCompare(b.id);
1994
+ });
1995
+ } else if (sortOption === "updated") {
1996
+ issues.sort((a, b) => {
1997
+ const dateA = a.frontmatter.updated || a.frontmatter.created || "";
1998
+ const dateB = b.frontmatter.updated || b.frontmatter.created || "";
1999
+ if (dateA !== dateB)
2000
+ return dateB.localeCompare(dateA);
2001
+ return b.id.localeCompare(a.id);
2002
+ });
2003
+ } else if (sortOption === "id") {
2004
+ issues.sort((a, b) => b.id.localeCompare(a.id));
2005
+ } else {
2006
+ issues.sort((a, b) => {
2007
+ const orderA = a.frontmatter.order;
2008
+ const orderB = b.frontmatter.order;
2009
+ if (orderA && orderB)
2010
+ return orderA < orderB ? -1 : orderA > orderB ? 1 : 0;
2011
+ if (orderA && !orderB)
2012
+ return -1;
2013
+ if (!orderA && orderB)
2014
+ return 1;
2015
+ return a.id < b.id ? -1 : a.id > b.id ? 1 : 0;
2016
+ });
2017
+ }
2018
+ }
2019
+ function filterByQuery(issues, query) {
2020
+ const parsed = parseQuery(query);
2021
+ let result = issues.filter((issue) => {
2022
+ if (parsed.qualifiers.is) {
2023
+ const statusValue = parsed.qualifiers.is.toLowerCase();
2024
+ if (statusValue === "open" || statusValue === "closed") {
2025
+ if (issue.frontmatter.status !== statusValue) {
2026
+ return false;
2027
+ }
2028
+ }
2029
+ }
2030
+ if (parsed.qualifiers.priority) {
2031
+ const priorityValue = parsed.qualifiers.priority.toLowerCase();
2032
+ if (priorityValue === "high" || priorityValue === "medium" || priorityValue === "low") {
2033
+ if (issue.frontmatter.priority !== priorityValue) {
2034
+ return false;
2035
+ }
2036
+ }
2037
+ }
2038
+ if (parsed.qualifiers.scope) {
2039
+ const scopeValue = parsed.qualifiers.scope.toLowerCase();
2040
+ if (scopeValue === "small" || scopeValue === "medium" || scopeValue === "large") {
2041
+ if (issue.frontmatter.scope !== scopeValue) {
2042
+ return false;
2043
+ }
2044
+ }
2045
+ }
2046
+ if (parsed.qualifiers.type) {
2047
+ const typeValue = parsed.qualifiers.type.toLowerCase();
2048
+ if (typeValue === "bug" || typeValue === "improvement") {
2049
+ if (issue.frontmatter.type !== typeValue) {
2050
+ return false;
2051
+ }
2052
+ }
2053
+ }
2054
+ if (parsed.qualifiers.label) {
2055
+ const labelQuery = parsed.qualifiers.label.toLowerCase();
2056
+ const issueLabels = (issue.frontmatter.labels || "").toLowerCase();
2057
+ if (!issueLabels.includes(labelQuery)) {
2058
+ return false;
2059
+ }
2060
+ }
2061
+ return true;
2062
+ });
2063
+ if (!parsed.searchText.trim()) {
2064
+ const sortBy = parsed.qualifiers.sort?.toLowerCase() || "roadmap";
2065
+ sortIssues(result, sortBy);
2066
+ }
2067
+ if (parsed.searchText.trim()) {
2068
+ const searchQuery = parsed.searchText.trim();
2069
+ const idMatches = [];
2070
+ const nonIdMatches = [];
2071
+ const normalizedQuery = searchQuery.replace(/^0+/, "");
2072
+ for (const issue of result) {
2073
+ const normalizedId = issue.id.replace(/^0+/, "");
2074
+ if (normalizedId.startsWith(normalizedQuery) || issue.id.startsWith(searchQuery)) {
2075
+ idMatches.push(issue);
2076
+ }
2077
+ }
2078
+ const fuse = createSearchIndex(result);
2079
+ const searchResults = fuse.search(searchQuery);
2080
+ const matchedIds = new Set(searchResults.map((r) => r.item.id));
2081
+ const idMatchSet = new Set(idMatches.map((i) => i.id));
2082
+ for (const issue of result) {
2083
+ if (!idMatchSet.has(issue.id) && matchedIds.has(issue.id)) {
2084
+ nonIdMatches.push(issue);
2085
+ }
2086
+ }
2087
+ nonIdMatches.sort((a, b) => {
2088
+ const aScore = searchResults.find((r) => r.item.id === a.id)?.score ?? 1;
2089
+ const bScore = searchResults.find((r) => r.item.id === b.id)?.score ?? 1;
2090
+ return aScore - bScore;
2091
+ });
2092
+ result = [...idMatches, ...nonIdMatches];
2093
+ }
2094
+ return result;
2095
+ }
2096
+ // src/main.ts
2097
+ var args = process.argv.slice(2);
2098
+ if (args[0] === "--version" || args[0] === "-v") {
2099
+ console.log(`issy v${process.env.ISSY_PKG_VERSION || "unknown"}`);
2100
+ process.exit(0);
2101
+ }
2102
+ var issyDir2 = resolveIssyDir();
2103
+ var issuesDir2 = join2(issyDir2, "issues");
2104
+ process.env.ISSY_DIR = issyDir2;
2105
+ process.env.ISSY_ROOT = dirname2(issyDir2);
2106
+ var legacyDir = findLegacyIssuesDirUpward(process.env.ISSY_ROOT || process.cwd());
2107
+ if (legacyDir && args[0] !== "migrate" && args[0] !== "init") {
2108
+ if (!existsSync2(issyDir2)) {
2109
+ console.warn(`⚠️ Legacy .issues/ directory detected at ${legacyDir}`);
2110
+ console.warn(` Run "issy migrate" to upgrade to the new .issy/ structure.
2111
+ `);
2112
+ }
2113
+ }
2114
+ var CLI_COMMANDS = new Set([
2115
+ "list",
2116
+ "search",
2117
+ "read",
2118
+ "create",
2119
+ "update",
2120
+ "close",
2121
+ "reopen",
2122
+ "next",
2123
+ "help",
2124
+ "--help",
2125
+ "-h"
2126
+ ]);
2127
+ if (args[0] === "migrate") {
2128
+ migrate();
2129
+ } else if (args[0] === "init") {
2130
+ init();
2131
+ } else if (CLI_COMMANDS.has(args[0] || "")) {
2132
+ const dir = dirname2(fileURLToPath(import.meta.url));
2133
+ const cli = await import(resolve2(dir, "cli.js"));
2134
+ await cli.ready;
2135
+ process.exit(0);
2136
+ } else {
2137
+ const portIdx = args.findIndex((arg) => arg === "--port" || arg === "-p");
2138
+ if (portIdx >= 0 && args[portIdx + 1]) {
2139
+ process.env.ISSUES_PORT = args[portIdx + 1];
2140
+ }
2141
+ await import("@miketromba/issy-app");
2142
+ }
2143
+ function migrate() {
2144
+ const startDir = process.env.ISSY_ROOT || process.cwd();
2145
+ const legacy = findLegacyIssuesDirUpward(startDir);
2146
+ if (!legacy) {
2147
+ console.log("No legacy .issues/ directory found. Nothing to migrate.");
2148
+ process.exit(0);
2149
+ }
2150
+ if (existsSync2(issyDir2) && existsSync2(issuesDir2)) {
2151
+ console.log(".issy/issues/ already exists. Migration may have already been completed.");
2152
+ process.exit(1);
2153
+ }
2154
+ console.log(`Migrating ${legacy} → ${issuesDir2}`);
2155
+ mkdirSync(issuesDir2, { recursive: true });
2156
+ const files = readdirSync(legacy).filter((f) => f.endsWith(".md") && /^\d{4}-/.test(f));
2157
+ const issueData = files.map((f) => {
2158
+ const content = readFileSync(join2(legacy, f), "utf-8");
2159
+ const { frontmatter } = parseFrontmatter(content);
2160
+ return { filename: f, content, frontmatter };
2161
+ }).sort((a, b) => a.filename.localeCompare(b.filename));
2162
+ const openIssues = issueData.filter((i) => i.frontmatter.status === "open");
2163
+ const orderKeys = generateBatchOrderKeys(openIssues.length);
2164
+ const orderMap = new Map;
2165
+ openIssues.forEach((issue, idx) => {
2166
+ orderMap.set(issue.filename, orderKeys[idx]);
2167
+ });
2168
+ for (const issue of issueData) {
2169
+ let content = issue.content;
2170
+ const orderKey = orderMap.get(issue.filename);
2171
+ if (orderKey) {
2172
+ content = content.replace(/^(---\n[\s\S]*?)(status: \w+)/m, `$1$2
2173
+ order: ${orderKey}`);
2174
+ }
2175
+ writeFileSync(join2(issuesDir2, issue.filename), content);
2176
+ }
2177
+ const otherFiles = readdirSync(legacy).filter((f) => !files.includes(f));
2178
+ for (const f of otherFiles) {
2179
+ try {
2180
+ cpSync(join2(legacy, f), join2(issuesDir2, f), { recursive: true });
2181
+ } catch {}
2182
+ }
2183
+ rmSync(legacy, { recursive: true });
2184
+ console.log(`✅ Migrated ${files.length} issue(s) to ${issuesDir2}`);
2185
+ if (openIssues.length > 0) {
2186
+ console.log(` Assigned roadmap order to ${openIssues.length} open issue(s).`);
2187
+ }
2188
+ console.log(` Removed ${legacy}`);
2189
+ process.exit(0);
2190
+ }
2191
+ function init() {
2192
+ const shouldSeed = args.includes("--seed");
2193
+ if (!existsSync2(issuesDir2)) {
2194
+ mkdirSync(issuesDir2, { recursive: true });
2195
+ }
2196
+ if (shouldSeed) {
2197
+ const hasIssues = existsSync2(issuesDir2) && readdirSync(issuesDir2).some((f) => f.endsWith(".md"));
2198
+ if (!hasIssues) {
2199
+ const firstOrderKey = computeOrderKey([], {});
2200
+ const welcome = `---
2201
+ title: Welcome to issy
2202
+ description: Your first issue in this repo
2203
+ priority: medium
2204
+ type: improvement
2205
+ status: open
2206
+ order: ${firstOrderKey}
2207
+ created: ${new Date().toISOString().slice(0, 19)}
2208
+ ---
2209
+
2210
+ ## Details
2211
+
2212
+ - This issue was created automatically on first run.
2213
+ - Edit it, close it, or delete it to get started.
2214
+ `;
2215
+ writeFileSync(join2(issuesDir2, "0001-welcome-to-issy.md"), welcome);
2216
+ }
2217
+ }
2218
+ console.log(`Initialized ${issyDir2}`);
2219
+ process.exit(0);
2220
+ }