asyar-sdk 1.8.1 → 1.9.1
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/ExtensionBridge.test.d.ts +2 -0
- package/dist/ExtensionBridge.test.d.ts.map +1 -0
- package/dist/ExtensionBridge.test.js +229 -0
- package/dist/ExtensionBridge.test.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/search/SearchEngine.d.ts +20 -0
- package/dist/search/SearchEngine.d.ts.map +1 -0
- package/dist/search/SearchEngine.js +91 -0
- package/dist/search/SearchEngine.js.map +1 -0
- package/dist/search/SearchEngine.test.d.ts +2 -0
- package/dist/search/SearchEngine.test.d.ts.map +1 -0
- package/dist/search/SearchEngine.test.js +137 -0
- package/dist/search/SearchEngine.test.js.map +1 -0
- package/dist/search/index.d.ts +4 -0
- package/dist/search/index.d.ts.map +1 -0
- package/dist/search/index.js +9 -0
- package/dist/search/index.js.map +1 -0
- package/dist/search/textUtils.d.ts +10 -0
- package/dist/search/textUtils.d.ts.map +1 -0
- package/dist/search/textUtils.js +38 -0
- package/dist/search/textUtils.js.map +1 -0
- package/dist/search/textUtils.test.d.ts +2 -0
- package/dist/search/textUtils.test.d.ts.map +1 -0
- package/dist/search/textUtils.test.js +61 -0
- package/dist/search/textUtils.test.js.map +1 -0
- package/dist/search/types.d.ts +14 -0
- package/dist/search/types.d.ts.map +1 -0
- package/dist/search/types.js +3 -0
- package/dist/search/types.js.map +1 -0
- package/package.json +2 -1
- package/src/styles/tokens.css +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExtensionBridge.test.d.ts","sourceRoot":"","sources":["../src/ExtensionBridge.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
26
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
27
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
28
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
29
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
30
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
31
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
35
|
+
const vitest_1 = require("vitest");
|
|
36
|
+
// We need to reset the singleton between tests, so we import the module dynamically
|
|
37
|
+
// after mocking dependencies.
|
|
38
|
+
// Mock the MessageBroker
|
|
39
|
+
vitest_1.vi.mock('./ipc/MessageBroker', () => {
|
|
40
|
+
const handlers = new Map();
|
|
41
|
+
return {
|
|
42
|
+
MessageBroker: {
|
|
43
|
+
getInstance: () => ({
|
|
44
|
+
on: (type, handler) => handlers.set(type, handler),
|
|
45
|
+
send: vitest_1.vi.fn(),
|
|
46
|
+
}),
|
|
47
|
+
},
|
|
48
|
+
// Expose for test assertions
|
|
49
|
+
__handlers: handlers,
|
|
50
|
+
};
|
|
51
|
+
});
|
|
52
|
+
// Mock LogServiceProxy as a proper class
|
|
53
|
+
vitest_1.vi.mock('./services/LogServiceProxy', () => ({
|
|
54
|
+
LogServiceProxy: class {
|
|
55
|
+
constructor() {
|
|
56
|
+
this.debug = vitest_1.vi.fn();
|
|
57
|
+
this.info = vitest_1.vi.fn();
|
|
58
|
+
this.warn = vitest_1.vi.fn();
|
|
59
|
+
this.error = vitest_1.vi.fn();
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
}));
|
|
63
|
+
(0, vitest_1.describe)('ExtensionBridge search IPC', () => {
|
|
64
|
+
let postMessageSpy;
|
|
65
|
+
let messageHandler;
|
|
66
|
+
(0, vitest_1.beforeEach)(() => {
|
|
67
|
+
// Reset the singleton by clearing the module cache
|
|
68
|
+
vitest_1.vi.resetModules();
|
|
69
|
+
postMessageSpy = vitest_1.vi.fn();
|
|
70
|
+
// Capture the message event listener that ExtensionBridge installs
|
|
71
|
+
vitest_1.vi.spyOn(window, 'addEventListener').mockImplementation((type, handler) => {
|
|
72
|
+
if (type === 'message') {
|
|
73
|
+
messageHandler = handler;
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
// Mock window.parent.postMessage
|
|
77
|
+
Object.defineProperty(window, 'parent', {
|
|
78
|
+
value: { postMessage: postMessageSpy },
|
|
79
|
+
writable: true,
|
|
80
|
+
configurable: true,
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
(0, vitest_1.afterEach)(() => {
|
|
84
|
+
vitest_1.vi.restoreAllMocks();
|
|
85
|
+
messageHandler = undefined;
|
|
86
|
+
});
|
|
87
|
+
(0, vitest_1.it)('responds to asyar:search:request with results from registered extension', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
88
|
+
// Import fresh to trigger singleton creation
|
|
89
|
+
const { ExtensionBridge } = yield Promise.resolve().then(() => __importStar(require('./ExtensionBridge')));
|
|
90
|
+
const bridge = ExtensionBridge.getInstance();
|
|
91
|
+
// Register a manifest and extension with a search method
|
|
92
|
+
bridge.registerManifest({
|
|
93
|
+
id: 'test-ext',
|
|
94
|
+
name: 'Test Extension',
|
|
95
|
+
version: '1.0.0',
|
|
96
|
+
description: 'Test',
|
|
97
|
+
type: 'view',
|
|
98
|
+
searchable: true,
|
|
99
|
+
commands: [],
|
|
100
|
+
});
|
|
101
|
+
bridge.registerExtensionImplementation('test-ext', {
|
|
102
|
+
initialize: vitest_1.vi.fn(),
|
|
103
|
+
activate: vitest_1.vi.fn(),
|
|
104
|
+
deactivate: vitest_1.vi.fn(),
|
|
105
|
+
onUnload: vitest_1.vi.fn(),
|
|
106
|
+
executeCommand: vitest_1.vi.fn(),
|
|
107
|
+
search: vitest_1.vi.fn().mockResolvedValue([
|
|
108
|
+
{
|
|
109
|
+
title: 'Test Result',
|
|
110
|
+
subtitle: 'A test doc',
|
|
111
|
+
score: 0.9,
|
|
112
|
+
type: 'view',
|
|
113
|
+
icon: '📖',
|
|
114
|
+
viewPath: 'test-ext/TestView',
|
|
115
|
+
action: () => { },
|
|
116
|
+
},
|
|
117
|
+
]),
|
|
118
|
+
});
|
|
119
|
+
(0, vitest_1.expect)(messageHandler).toBeDefined();
|
|
120
|
+
// Simulate host sending asyar:search:request
|
|
121
|
+
const event = new MessageEvent('message', {
|
|
122
|
+
data: {
|
|
123
|
+
type: 'asyar:search:request',
|
|
124
|
+
messageId: 'search_123',
|
|
125
|
+
payload: { query: 'test' },
|
|
126
|
+
},
|
|
127
|
+
source: window.parent,
|
|
128
|
+
});
|
|
129
|
+
messageHandler(event);
|
|
130
|
+
// Wait for async search to complete
|
|
131
|
+
yield vitest_1.vi.waitFor(() => {
|
|
132
|
+
(0, vitest_1.expect)(postMessageSpy).toHaveBeenCalledWith(vitest_1.expect.objectContaining({
|
|
133
|
+
type: 'asyar:search:response',
|
|
134
|
+
messageId: 'search_123',
|
|
135
|
+
result: vitest_1.expect.arrayContaining([
|
|
136
|
+
vitest_1.expect.objectContaining({
|
|
137
|
+
title: 'Test Result',
|
|
138
|
+
subtitle: 'A test doc',
|
|
139
|
+
score: 0.9,
|
|
140
|
+
}),
|
|
141
|
+
]),
|
|
142
|
+
}), '*');
|
|
143
|
+
});
|
|
144
|
+
}));
|
|
145
|
+
(0, vitest_1.it)('responds with empty results when no extension implements search', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
146
|
+
const { ExtensionBridge } = yield Promise.resolve().then(() => __importStar(require('./ExtensionBridge')));
|
|
147
|
+
const bridge = ExtensionBridge.getInstance();
|
|
148
|
+
// Register extension WITHOUT search method
|
|
149
|
+
bridge.registerManifest({
|
|
150
|
+
id: 'no-search-ext',
|
|
151
|
+
name: 'No Search',
|
|
152
|
+
version: '1.0.0',
|
|
153
|
+
description: 'Test',
|
|
154
|
+
type: 'view',
|
|
155
|
+
commands: [],
|
|
156
|
+
});
|
|
157
|
+
bridge.registerExtensionImplementation('no-search-ext', {
|
|
158
|
+
initialize: vitest_1.vi.fn(),
|
|
159
|
+
activate: vitest_1.vi.fn(),
|
|
160
|
+
deactivate: vitest_1.vi.fn(),
|
|
161
|
+
onUnload: vitest_1.vi.fn(),
|
|
162
|
+
executeCommand: vitest_1.vi.fn(),
|
|
163
|
+
});
|
|
164
|
+
(0, vitest_1.expect)(messageHandler).toBeDefined();
|
|
165
|
+
const event = new MessageEvent('message', {
|
|
166
|
+
data: {
|
|
167
|
+
type: 'asyar:search:request',
|
|
168
|
+
messageId: 'search_456',
|
|
169
|
+
payload: { query: 'test' },
|
|
170
|
+
},
|
|
171
|
+
source: window.parent,
|
|
172
|
+
});
|
|
173
|
+
messageHandler(event);
|
|
174
|
+
yield vitest_1.vi.waitFor(() => {
|
|
175
|
+
(0, vitest_1.expect)(postMessageSpy).toHaveBeenCalledWith(vitest_1.expect.objectContaining({
|
|
176
|
+
type: 'asyar:search:response',
|
|
177
|
+
messageId: 'search_456',
|
|
178
|
+
result: [],
|
|
179
|
+
}), '*');
|
|
180
|
+
});
|
|
181
|
+
}));
|
|
182
|
+
(0, vitest_1.it)('strips action functions from search results (not serializable via postMessage)', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
183
|
+
const { ExtensionBridge } = yield Promise.resolve().then(() => __importStar(require('./ExtensionBridge')));
|
|
184
|
+
const bridge = ExtensionBridge.getInstance();
|
|
185
|
+
bridge.registerManifest({
|
|
186
|
+
id: 'strip-ext',
|
|
187
|
+
name: 'Strip Test',
|
|
188
|
+
version: '1.0.0',
|
|
189
|
+
description: 'Test',
|
|
190
|
+
type: 'view',
|
|
191
|
+
commands: [],
|
|
192
|
+
});
|
|
193
|
+
bridge.registerExtensionImplementation('strip-ext', {
|
|
194
|
+
initialize: vitest_1.vi.fn(),
|
|
195
|
+
activate: vitest_1.vi.fn(),
|
|
196
|
+
deactivate: vitest_1.vi.fn(),
|
|
197
|
+
onUnload: vitest_1.vi.fn(),
|
|
198
|
+
executeCommand: vitest_1.vi.fn(),
|
|
199
|
+
search: vitest_1.vi.fn().mockResolvedValue([
|
|
200
|
+
{
|
|
201
|
+
title: 'Doc',
|
|
202
|
+
score: 0.5,
|
|
203
|
+
type: 'view',
|
|
204
|
+
action: () => console.log('should be stripped'),
|
|
205
|
+
viewPath: 'strip-ext/View',
|
|
206
|
+
},
|
|
207
|
+
]),
|
|
208
|
+
});
|
|
209
|
+
(0, vitest_1.expect)(messageHandler).toBeDefined();
|
|
210
|
+
const event = new MessageEvent('message', {
|
|
211
|
+
data: {
|
|
212
|
+
type: 'asyar:search:request',
|
|
213
|
+
messageId: 'search_789',
|
|
214
|
+
payload: { query: 'doc' },
|
|
215
|
+
},
|
|
216
|
+
source: window.parent,
|
|
217
|
+
});
|
|
218
|
+
messageHandler(event);
|
|
219
|
+
yield vitest_1.vi.waitFor(() => {
|
|
220
|
+
(0, vitest_1.expect)(postMessageSpy).toHaveBeenCalled();
|
|
221
|
+
const call = postMessageSpy.mock.calls[0];
|
|
222
|
+
const result = call[0].result[0];
|
|
223
|
+
(0, vitest_1.expect)(result.title).toBe('Doc');
|
|
224
|
+
// action should NOT be present in the serialized result
|
|
225
|
+
(0, vitest_1.expect)(result).not.toHaveProperty('action');
|
|
226
|
+
});
|
|
227
|
+
}));
|
|
228
|
+
});
|
|
229
|
+
//# sourceMappingURL=ExtensionBridge.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExtensionBridge.test.js","sourceRoot":"","sources":["../src/ExtensionBridge.test.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAItD,YAAY,EACV,iBAAiB,EACjB,WAAW,EACX,oBAAoB,EACpB,wBAAwB,EACxB,eAAe,EACf,iBAAiB,EACjB,cAAc,EACd,gBAAgB,EACjB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAGL,qBAAqB,EACrB,qBAAqB,GACtB,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACnE,YAAY,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAG9D,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAItD,YAAY,EACV,iBAAiB,EACjB,WAAW,EACX,oBAAoB,EACpB,wBAAwB,EACxB,eAAe,EACf,iBAAiB,EACjB,cAAc,EACd,gBAAgB,EACjB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAGL,qBAAqB,EACrB,qBAAqB,GACtB,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACnE,YAAY,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAG9D,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC;AACxB,cAAc,UAAU,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -31,4 +31,5 @@ Object.defineProperty(exports, "ActionCategory", { enumerable: true, get: functi
|
|
|
31
31
|
// Re-export all types for easier consumption
|
|
32
32
|
__exportStar(require("./types"), exports);
|
|
33
33
|
__exportStar(require("./icons"), exports);
|
|
34
|
+
__exportStar(require("./search"), exports);
|
|
34
35
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,qDAAoD;AAA3C,kHAAA,eAAe,OAAA;AACxB,uDAAsD;AAA7C,oHAAA,gBAAgB,OAAA;AAezB,uCAKoB;AAJlB,4FAA4F;AAC5F,iFAAiF;AACjF,iHAAA,qBAAqB,OAAA;AACrB,iHAAA,qBAAqB,OAAA;AAGvB,qDAAqD;AACrD,iDAAmE;AAA1D,2GAAA,aAAa,OAAA;AAAE,4GAAA,cAAc,OAAA;AAGtC,6CAA6C;AAC7C,0CAAwB;AACxB,0CAAwB"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,qDAAoD;AAA3C,kHAAA,eAAe,OAAA;AACxB,uDAAsD;AAA7C,oHAAA,gBAAgB,OAAA;AAezB,uCAKoB;AAJlB,4FAA4F;AAC5F,iFAAiF;AACjF,iHAAA,qBAAqB,OAAA;AACrB,iHAAA,qBAAqB,OAAA;AAGvB,qDAAqD;AACrD,iDAAmE;AAA1D,2GAAA,aAAa,OAAA;AAAE,4GAAA,cAAc,OAAA;AAGtC,6CAA6C;AAC7C,0CAAwB;AACxB,0CAAwB;AACxB,2CAAyB"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { SearchEngineOptions } from './types';
|
|
2
|
+
export declare class SearchEngine<T> {
|
|
3
|
+
private _items;
|
|
4
|
+
private _haystack;
|
|
5
|
+
private readonly getText;
|
|
6
|
+
private readonly mode;
|
|
7
|
+
private readonly uf;
|
|
8
|
+
constructor(options: SearchEngineOptions<T>);
|
|
9
|
+
/**
|
|
10
|
+
* Set the item list. Rebuilds the searchable text haystack.
|
|
11
|
+
* Skips rebuild if the same array reference is passed (items unchanged).
|
|
12
|
+
*/
|
|
13
|
+
setItems(items: T[]): void;
|
|
14
|
+
/**
|
|
15
|
+
* Search items. Returns matching items in relevance order.
|
|
16
|
+
* Empty/whitespace query returns all items.
|
|
17
|
+
*/
|
|
18
|
+
search(query: string): T[];
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=SearchEngine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SearchEngine.d.ts","sourceRoot":"","sources":["../../src/search/SearchEngine.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAUnD,qBAAa,YAAY,CAAC,CAAC;IACzB,OAAO,CAAC,MAAM,CAAW;IACzB,OAAO,CAAC,SAAS,CAAgB;IACjC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAsB;IAC9C,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAoB;IACzC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAS;gBAEhB,OAAO,EAAE,mBAAmB,CAAC,CAAC,CAAC;IAY3C;;;OAGG;IACH,QAAQ,CAAC,KAAK,EAAE,CAAC,EAAE,GAAG,IAAI;IAM1B;;;OAGG;IACH,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,CAAC,EAAE;CAoD3B"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.SearchEngine = void 0;
|
|
7
|
+
const ufuzzy_1 = __importDefault(require("@leeoniya/ufuzzy"));
|
|
8
|
+
function isSubsequence(search, text) {
|
|
9
|
+
let si = 0;
|
|
10
|
+
for (let ti = 0; ti < text.length && si < search.length; ti++) {
|
|
11
|
+
if (search[si] === text[ti])
|
|
12
|
+
si++;
|
|
13
|
+
}
|
|
14
|
+
return si === search.length;
|
|
15
|
+
}
|
|
16
|
+
class SearchEngine {
|
|
17
|
+
constructor(options) {
|
|
18
|
+
var _a;
|
|
19
|
+
this._items = [];
|
|
20
|
+
this._haystack = [];
|
|
21
|
+
this.getText = options.getText;
|
|
22
|
+
this.mode = (_a = options.mode) !== null && _a !== void 0 ? _a : 'fuzzy';
|
|
23
|
+
this.uf = new ufuzzy_1.default({
|
|
24
|
+
intraMode: 1,
|
|
25
|
+
intraIns: 12,
|
|
26
|
+
intraSub: 1,
|
|
27
|
+
intraTrn: 1,
|
|
28
|
+
intraDel: 1,
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Set the item list. Rebuilds the searchable text haystack.
|
|
33
|
+
* Skips rebuild if the same array reference is passed (items unchanged).
|
|
34
|
+
*/
|
|
35
|
+
setItems(items) {
|
|
36
|
+
if (items === this._items)
|
|
37
|
+
return;
|
|
38
|
+
this._items = items;
|
|
39
|
+
this._haystack = items.map(this.getText);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Search items. Returns matching items in relevance order.
|
|
43
|
+
* Empty/whitespace query returns all items.
|
|
44
|
+
*/
|
|
45
|
+
search(query) {
|
|
46
|
+
const q = query.trim();
|
|
47
|
+
if (!q)
|
|
48
|
+
return [...this._items];
|
|
49
|
+
const qLower = q.toLowerCase();
|
|
50
|
+
const terms = qLower.split(/\s+/).filter(Boolean);
|
|
51
|
+
// Tier 1: Exact substring match (all terms must appear)
|
|
52
|
+
const exactIndices = [];
|
|
53
|
+
for (let i = 0; i < this._haystack.length; i++) {
|
|
54
|
+
const h = this._haystack[i].toLowerCase();
|
|
55
|
+
if (terms.every(t => h.includes(t))) {
|
|
56
|
+
exactIndices.push(i);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
if (this.mode === 'exact') {
|
|
60
|
+
return exactIndices.map(i => this._items[i]);
|
|
61
|
+
}
|
|
62
|
+
// Tier 2: Subsequence match (all terms appear as ordered subsequences)
|
|
63
|
+
const subseqIndices = [];
|
|
64
|
+
for (let i = 0; i < this._haystack.length; i++) {
|
|
65
|
+
const h = this._haystack[i].toLowerCase();
|
|
66
|
+
if (terms.every(t => isSubsequence(t, h))) {
|
|
67
|
+
subseqIndices.push(i);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
// Tier 3: uFuzzy (typo tolerance)
|
|
71
|
+
const idxs = this.uf.filter(this._haystack, q);
|
|
72
|
+
let fuzzyRankedIndices = [];
|
|
73
|
+
if (idxs && idxs.length > 0) {
|
|
74
|
+
const info = this.uf.info(idxs, this._haystack, q);
|
|
75
|
+
const order = this.uf.sort(info, this._haystack, q);
|
|
76
|
+
fuzzyRankedIndices = order.map(i => idxs[i]);
|
|
77
|
+
}
|
|
78
|
+
// Merge: exact first, then subsequence, then fuzzy (de-duplicated)
|
|
79
|
+
const exactItems = exactIndices.map(i => this._items[i]);
|
|
80
|
+
const seen = new Set(exactIndices);
|
|
81
|
+
const subseqOnlyItems = subseqIndices
|
|
82
|
+
.filter(i => !seen.has(i))
|
|
83
|
+
.map(i => { seen.add(i); return this._items[i]; });
|
|
84
|
+
const fuzzyOnlyItems = fuzzyRankedIndices
|
|
85
|
+
.filter(i => !seen.has(i))
|
|
86
|
+
.map(i => this._items[i]);
|
|
87
|
+
return [...exactItems, ...subseqOnlyItems, ...fuzzyOnlyItems];
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
exports.SearchEngine = SearchEngine;
|
|
91
|
+
//# sourceMappingURL=SearchEngine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SearchEngine.js","sourceRoot":"","sources":["../../src/search/SearchEngine.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SearchEngine.test.d.ts","sourceRoot":"","sources":["../../src/search/SearchEngine.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const vitest_1 = require("vitest");
|
|
4
|
+
const SearchEngine_1 = require("./SearchEngine");
|
|
5
|
+
function makeEngine(items, mode = 'fuzzy') {
|
|
6
|
+
const engine = new SearchEngine_1.SearchEngine({
|
|
7
|
+
getText: (item) => item.text,
|
|
8
|
+
mode,
|
|
9
|
+
});
|
|
10
|
+
engine.setItems(items);
|
|
11
|
+
return engine;
|
|
12
|
+
}
|
|
13
|
+
const sampleItems = [
|
|
14
|
+
{ id: '1', text: 'quarterly report summary for Q3' },
|
|
15
|
+
{ id: '2', text: 'banana smoothie recipe' },
|
|
16
|
+
{ id: '3', text: 'record of transactions' },
|
|
17
|
+
{ id: '4', text: 'apple pie recipe' },
|
|
18
|
+
{ id: '5', text: 'unrelated text document' },
|
|
19
|
+
];
|
|
20
|
+
(0, vitest_1.describe)('SearchEngine', () => {
|
|
21
|
+
(0, vitest_1.describe)('basic behavior', () => {
|
|
22
|
+
(0, vitest_1.it)('returns all items when query is empty', () => {
|
|
23
|
+
const engine = makeEngine(sampleItems);
|
|
24
|
+
(0, vitest_1.expect)(engine.search('')).toHaveLength(5);
|
|
25
|
+
});
|
|
26
|
+
(0, vitest_1.it)('returns all items when query is whitespace', () => {
|
|
27
|
+
const engine = makeEngine(sampleItems);
|
|
28
|
+
(0, vitest_1.expect)(engine.search(' ')).toHaveLength(5);
|
|
29
|
+
});
|
|
30
|
+
(0, vitest_1.it)('returns empty array when nothing matches', () => {
|
|
31
|
+
const engine = makeEngine(sampleItems);
|
|
32
|
+
(0, vitest_1.expect)(engine.search('zzzznothing')).toHaveLength(0);
|
|
33
|
+
});
|
|
34
|
+
(0, vitest_1.it)('finds exact substring matches', () => {
|
|
35
|
+
const engine = makeEngine(sampleItems);
|
|
36
|
+
const results = engine.search('banana');
|
|
37
|
+
(0, vitest_1.expect)(results.some(r => r.id === '2')).toBe(true);
|
|
38
|
+
(0, vitest_1.expect)(results.some(r => r.id === '1')).toBe(false);
|
|
39
|
+
});
|
|
40
|
+
(0, vitest_1.it)('is case-insensitive', () => {
|
|
41
|
+
const engine = makeEngine(sampleItems);
|
|
42
|
+
const results = engine.search('BANANA');
|
|
43
|
+
(0, vitest_1.expect)(results.some(r => r.id === '2')).toBe(true);
|
|
44
|
+
});
|
|
45
|
+
(0, vitest_1.it)('handles multi-word queries with AND logic for exact tier', () => {
|
|
46
|
+
const engine = makeEngine(sampleItems);
|
|
47
|
+
const results = engine.search('apple recipe');
|
|
48
|
+
(0, vitest_1.expect)(results.some(r => r.id === '4')).toBe(true);
|
|
49
|
+
(0, vitest_1.expect)(results.some(r => r.id === '2')).toBe(false); // has "recipe" but not "apple"
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
(0, vitest_1.describe)('fuzzy mode — subsequence matching', () => {
|
|
53
|
+
(0, vitest_1.it)('matches subsequences: "qrtly" finds "quarterly"', () => {
|
|
54
|
+
const engine = makeEngine(sampleItems);
|
|
55
|
+
const results = engine.search('qrtly');
|
|
56
|
+
(0, vitest_1.expect)(results.some(r => r.id === '1')).toBe(true);
|
|
57
|
+
});
|
|
58
|
+
(0, vitest_1.it)('matches across word boundaries: "qr" finds "quarterly report"', () => {
|
|
59
|
+
const engine = makeEngine(sampleItems);
|
|
60
|
+
const results = engine.search('qr');
|
|
61
|
+
(0, vitest_1.expect)(results.some(r => r.id === '1')).toBe(true);
|
|
62
|
+
});
|
|
63
|
+
(0, vitest_1.it)('multi-term fuzzy: "qrtly rep" finds "quarterly report summary"', () => {
|
|
64
|
+
const engine = makeEngine(sampleItems);
|
|
65
|
+
const results = engine.search('qrtly rep');
|
|
66
|
+
(0, vitest_1.expect)(results.some(r => r.id === '1')).toBe(true);
|
|
67
|
+
(0, vitest_1.expect)(results.some(r => r.id === '5')).toBe(false);
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
(0, vitest_1.describe)('fuzzy mode — typo tolerance', () => {
|
|
71
|
+
(0, vitest_1.it)('tolerates single substitution: "recort" finds "record"', () => {
|
|
72
|
+
const engine = makeEngine(sampleItems);
|
|
73
|
+
const results = engine.search('recort');
|
|
74
|
+
(0, vitest_1.expect)(results.some(r => r.id === '3')).toBe(true);
|
|
75
|
+
});
|
|
76
|
+
(0, vitest_1.it)('tolerates single transposition: "reocrd" finds "record"', () => {
|
|
77
|
+
const engine = makeEngine(sampleItems);
|
|
78
|
+
const results = engine.search('reocrd');
|
|
79
|
+
(0, vitest_1.expect)(results.some(r => r.id === '3')).toBe(true);
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
(0, vitest_1.describe)('ranking', () => {
|
|
83
|
+
(0, vitest_1.it)('ranks exact matches higher than fuzzy-only matches', () => {
|
|
84
|
+
const items = [
|
|
85
|
+
{ id: 'fuzzy', text: 'approximate appple thing' },
|
|
86
|
+
{ id: 'exact', text: 'apple pie recipe' },
|
|
87
|
+
];
|
|
88
|
+
const engine = makeEngine(items);
|
|
89
|
+
const results = engine.search('apple');
|
|
90
|
+
(0, vitest_1.expect)(results[0].id).toBe('exact');
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
(0, vitest_1.describe)('exact mode', () => {
|
|
94
|
+
(0, vitest_1.it)('does NOT match subsequences in exact mode', () => {
|
|
95
|
+
const engine = makeEngine(sampleItems, 'exact');
|
|
96
|
+
const results = engine.search('qrtly');
|
|
97
|
+
(0, vitest_1.expect)(results).toHaveLength(0);
|
|
98
|
+
});
|
|
99
|
+
(0, vitest_1.it)('still finds exact substrings in exact mode', () => {
|
|
100
|
+
const engine = makeEngine(sampleItems, 'exact');
|
|
101
|
+
const results = engine.search('banana');
|
|
102
|
+
(0, vitest_1.expect)(results.some(r => r.id === '2')).toBe(true);
|
|
103
|
+
});
|
|
104
|
+
(0, vitest_1.it)('multi-term AND logic in exact mode', () => {
|
|
105
|
+
const engine = makeEngine(sampleItems, 'exact');
|
|
106
|
+
const results = engine.search('apple recipe');
|
|
107
|
+
(0, vitest_1.expect)(results.some(r => r.id === '4')).toBe(true);
|
|
108
|
+
(0, vitest_1.expect)(results.some(r => r.id === '2')).toBe(false);
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
(0, vitest_1.describe)('setItems', () => {
|
|
112
|
+
(0, vitest_1.it)('rebuilds haystack when items change', () => {
|
|
113
|
+
const engine = new SearchEngine_1.SearchEngine({
|
|
114
|
+
getText: (item) => item.text,
|
|
115
|
+
});
|
|
116
|
+
engine.setItems([{ id: '1', text: 'first batch' }]);
|
|
117
|
+
(0, vitest_1.expect)(engine.search('first')).toHaveLength(1);
|
|
118
|
+
engine.setItems([{ id: '2', text: 'second batch' }]);
|
|
119
|
+
(0, vitest_1.expect)(engine.search('first')).toHaveLength(0);
|
|
120
|
+
(0, vitest_1.expect)(engine.search('second')).toHaveLength(1);
|
|
121
|
+
});
|
|
122
|
+
(0, vitest_1.it)('skips rebuild if same array reference is passed', () => {
|
|
123
|
+
const items = [{ id: '1', text: 'hello' }];
|
|
124
|
+
const engine = new SearchEngine_1.SearchEngine({
|
|
125
|
+
getText: (item) => item.text,
|
|
126
|
+
});
|
|
127
|
+
engine.setItems(items);
|
|
128
|
+
// Mutate the item (bad practice, but tests the reference check)
|
|
129
|
+
items[0].text = 'changed';
|
|
130
|
+
engine.setItems(items); // same reference — should NOT rebuild
|
|
131
|
+
// Haystack should still contain old value
|
|
132
|
+
(0, vitest_1.expect)(engine.search('hello')).toHaveLength(1);
|
|
133
|
+
(0, vitest_1.expect)(engine.search('changed')).toHaveLength(0);
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
//# sourceMappingURL=SearchEngine.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SearchEngine.test.js","sourceRoot":"","sources":["../../src/search/SearchEngine.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/search/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAClD,YAAY,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.stripRtf = exports.stripHtml = exports.SearchEngine = void 0;
|
|
4
|
+
var SearchEngine_1 = require("./SearchEngine");
|
|
5
|
+
Object.defineProperty(exports, "SearchEngine", { enumerable: true, get: function () { return SearchEngine_1.SearchEngine; } });
|
|
6
|
+
var textUtils_1 = require("./textUtils");
|
|
7
|
+
Object.defineProperty(exports, "stripHtml", { enumerable: true, get: function () { return textUtils_1.stripHtml; } });
|
|
8
|
+
Object.defineProperty(exports, "stripRtf", { enumerable: true, get: function () { return textUtils_1.stripRtf; } });
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/search/index.ts"],"names":[],"mappings":";;;AAAA,+CAA8C;AAArC,4GAAA,YAAY,OAAA;AACrB,yCAAkD;AAAzC,sGAAA,SAAS,OAAA;AAAE,qGAAA,QAAQ,OAAA"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Strip HTML tags, script/style blocks, and decode common entities.
|
|
3
|
+
* Uses regex — no DOM dependency, works in all environments.
|
|
4
|
+
*/
|
|
5
|
+
export declare function stripHtml(html: string): string;
|
|
6
|
+
/**
|
|
7
|
+
* Strip RTF control words, unicode escapes, braces, and backslashes.
|
|
8
|
+
*/
|
|
9
|
+
export declare function stripRtf(rtf: string): string;
|
|
10
|
+
//# sourceMappingURL=textUtils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"textUtils.d.ts","sourceRoot":"","sources":["../../src/search/textUtils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAc9C;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAQ5C"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.stripHtml = stripHtml;
|
|
4
|
+
exports.stripRtf = stripRtf;
|
|
5
|
+
/**
|
|
6
|
+
* Strip HTML tags, script/style blocks, and decode common entities.
|
|
7
|
+
* Uses regex — no DOM dependency, works in all environments.
|
|
8
|
+
*/
|
|
9
|
+
function stripHtml(html) {
|
|
10
|
+
if (!html)
|
|
11
|
+
return '';
|
|
12
|
+
return html
|
|
13
|
+
.replace(/<style[^>]*>[\s\S]*?<\/style>/gi, '')
|
|
14
|
+
.replace(/<script[^>]*>[\s\S]*?<\/script>/gi, '')
|
|
15
|
+
.replace(/<[^>]+>/g, ' ')
|
|
16
|
+
.replace(/ /gi, ' ')
|
|
17
|
+
.replace(/&/gi, '&')
|
|
18
|
+
.replace(/</gi, '<')
|
|
19
|
+
.replace(/>/gi, '>')
|
|
20
|
+
.replace(/"/gi, '"')
|
|
21
|
+
.replace(/&#\d+;/gi, ' ')
|
|
22
|
+
.replace(/\s+/g, ' ')
|
|
23
|
+
.trim();
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Strip RTF control words, unicode escapes, braces, and backslashes.
|
|
27
|
+
*/
|
|
28
|
+
function stripRtf(rtf) {
|
|
29
|
+
if (!rtf)
|
|
30
|
+
return '';
|
|
31
|
+
return rtf
|
|
32
|
+
.replace(/\\u-?\d+\??/g, '')
|
|
33
|
+
.replace(/\\[a-z]+-?\d*\s?/gi, '')
|
|
34
|
+
.replace(/[{}\\]/g, '')
|
|
35
|
+
.replace(/\s+/g, ' ')
|
|
36
|
+
.trim();
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=textUtils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"textUtils.js","sourceRoot":"","sources":["../../src/search/textUtils.ts"],"names":[],"mappings":";;AAIA,8BAcC;AAKD,4BAQC;AA/BD;;;GAGG;AACH,SAAgB,SAAS,CAAC,IAAY;IACpC,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,CAAC;IACrB,OAAO,IAAI;SACR,OAAO,CAAC,iCAAiC,EAAE,EAAE,CAAC;SAC9C,OAAO,CAAC,mCAAmC,EAAE,EAAE,CAAC;SAChD,OAAO,CAAC,UAAU,EAAE,GAAG,CAAC;SACxB,OAAO,CAAC,UAAU,EAAE,GAAG,CAAC;SACxB,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC;SACvB,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC;SACtB,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC;SACtB,OAAO,CAAC,UAAU,EAAE,GAAG,CAAC;SACxB,OAAO,CAAC,UAAU,EAAE,GAAG,CAAC;SACxB,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC;SACpB,IAAI,EAAE,CAAC;AACZ,CAAC;AAED;;GAEG;AACH,SAAgB,QAAQ,CAAC,GAAW;IAClC,IAAI,CAAC,GAAG;QAAE,OAAO,EAAE,CAAC;IACpB,OAAO,GAAG;SACP,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC;SAC3B,OAAO,CAAC,oBAAoB,EAAE,EAAE,CAAC;SACjC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC;SACtB,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC;SACpB,IAAI,EAAE,CAAC;AACZ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"textUtils.test.d.ts","sourceRoot":"","sources":["../../src/search/textUtils.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const vitest_1 = require("vitest");
|
|
4
|
+
const textUtils_1 = require("./textUtils");
|
|
5
|
+
(0, vitest_1.describe)('stripHtml', () => {
|
|
6
|
+
(0, vitest_1.it)('strips simple tags', () => {
|
|
7
|
+
(0, vitest_1.expect)((0, textUtils_1.stripHtml)('<p>hello</p>')).toBe('hello');
|
|
8
|
+
});
|
|
9
|
+
(0, vitest_1.it)('strips nested tags', () => {
|
|
10
|
+
(0, vitest_1.expect)((0, textUtils_1.stripHtml)('<div><p>hello <b>world</b></p></div>')).toBe('hello world');
|
|
11
|
+
});
|
|
12
|
+
(0, vitest_1.it)('strips full HTML documents', () => {
|
|
13
|
+
const html = '<html><head><meta charset="UTF-8"><style>body{color:red}</style></head><body><p>quarterly report</p></body></html>';
|
|
14
|
+
(0, vitest_1.expect)((0, textUtils_1.stripHtml)(html)).toContain('quarterly report');
|
|
15
|
+
(0, vitest_1.expect)((0, textUtils_1.stripHtml)(html)).not.toContain('<');
|
|
16
|
+
(0, vitest_1.expect)((0, textUtils_1.stripHtml)(html)).not.toContain('color:red');
|
|
17
|
+
});
|
|
18
|
+
(0, vitest_1.it)('strips script tags and their content', () => {
|
|
19
|
+
(0, vitest_1.expect)((0, textUtils_1.stripHtml)('<p>safe</p><script>alert("xss")</script>')).toBe('safe');
|
|
20
|
+
});
|
|
21
|
+
(0, vitest_1.it)('strips style tags and their content', () => {
|
|
22
|
+
(0, vitest_1.expect)((0, textUtils_1.stripHtml)('<style>.a{color:red}</style><p>text</p>')).toBe('text');
|
|
23
|
+
});
|
|
24
|
+
(0, vitest_1.it)('decodes common HTML entities', () => {
|
|
25
|
+
(0, vitest_1.expect)((0, textUtils_1.stripHtml)('a & b < c > d "e"')).toBe('a & b < c > d "e"');
|
|
26
|
+
});
|
|
27
|
+
(0, vitest_1.it)('collapses whitespace', () => {
|
|
28
|
+
(0, vitest_1.expect)((0, textUtils_1.stripHtml)('<p> hello </p> <p> world </p>')).toBe('hello world');
|
|
29
|
+
});
|
|
30
|
+
(0, vitest_1.it)('returns empty string for empty input', () => {
|
|
31
|
+
(0, vitest_1.expect)((0, textUtils_1.stripHtml)('')).toBe('');
|
|
32
|
+
});
|
|
33
|
+
(0, vitest_1.it)('returns plain text unchanged', () => {
|
|
34
|
+
(0, vitest_1.expect)((0, textUtils_1.stripHtml)('no tags here')).toBe('no tags here');
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
(0, vitest_1.describe)('stripRtf', () => {
|
|
38
|
+
(0, vitest_1.it)('strips RTF control words', () => {
|
|
39
|
+
const result = (0, textUtils_1.stripRtf)('{\\rtf1\\b hello\\b0 world}');
|
|
40
|
+
(0, vitest_1.expect)(result).toContain('hello');
|
|
41
|
+
(0, vitest_1.expect)(result).toContain('world');
|
|
42
|
+
(0, vitest_1.expect)(result).not.toContain('\\rtf');
|
|
43
|
+
(0, vitest_1.expect)(result).not.toContain('\\b');
|
|
44
|
+
});
|
|
45
|
+
(0, vitest_1.it)('strips unicode escape sequences', () => {
|
|
46
|
+
(0, vitest_1.expect)((0, textUtils_1.stripRtf)('\\u8230?')).not.toContain('\\u8230');
|
|
47
|
+
});
|
|
48
|
+
(0, vitest_1.it)('strips braces and backslashes', () => {
|
|
49
|
+
const result = (0, textUtils_1.stripRtf)('{\\rtf1 {\\b bold} text}');
|
|
50
|
+
(0, vitest_1.expect)(result).not.toContain('{');
|
|
51
|
+
(0, vitest_1.expect)(result).not.toContain('}');
|
|
52
|
+
});
|
|
53
|
+
(0, vitest_1.it)('collapses whitespace', () => {
|
|
54
|
+
const result = (0, textUtils_1.stripRtf)('{\\rtf1 hello world }');
|
|
55
|
+
(0, vitest_1.expect)(result).toBe('hello world');
|
|
56
|
+
});
|
|
57
|
+
(0, vitest_1.it)('returns empty string for empty input', () => {
|
|
58
|
+
(0, vitest_1.expect)((0, textUtils_1.stripRtf)('')).toBe('');
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
//# sourceMappingURL=textUtils.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"textUtils.test.js","sourceRoot":"","sources":["../../src/search/textUtils.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface SearchEngineOptions<T> {
|
|
2
|
+
/**
|
|
3
|
+
* Extract searchable text from an item.
|
|
4
|
+
* Called once per item when setItems() is called — not on every search.
|
|
5
|
+
*/
|
|
6
|
+
getText: (item: T) => string;
|
|
7
|
+
/**
|
|
8
|
+
* 'exact' — substring match only (fast, no typo tolerance)
|
|
9
|
+
* 'fuzzy' — two-tier: exact substring first, then uFuzzy subsequence + 1 typo per term
|
|
10
|
+
* Default: 'fuzzy'
|
|
11
|
+
*/
|
|
12
|
+
mode?: 'exact' | 'fuzzy';
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/search/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,mBAAmB,CAAC,CAAC;IACpC;;;OAGG;IACH,OAAO,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,MAAM,CAAC;IAE7B;;;;OAIG;IACH,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC;CAC1B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/search/types.ts"],"names":[],"mappings":""}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "asyar-sdk",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.9.1",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"bin": {
|
|
6
6
|
"asyar": "./dist/cli/index.js"
|
|
@@ -47,6 +47,7 @@
|
|
|
47
47
|
"src/styles"
|
|
48
48
|
],
|
|
49
49
|
"dependencies": {
|
|
50
|
+
"@leeoniya/ufuzzy": "^1.0.19",
|
|
50
51
|
"adm-zip": "^0.5.16",
|
|
51
52
|
"chalk": "^5.6.2",
|
|
52
53
|
"chokidar": "^3.6.0",
|