@backstage/plugin-search-backend-node 0.6.1-next.0 → 0.6.2-next.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +28 -0
- package/dist/index.cjs.js +45 -6
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/package.json +7 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,33 @@
|
|
|
1
1
|
# @backstage/plugin-search-backend-node
|
|
2
2
|
|
|
3
|
+
## 0.6.2-next.0
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- e7794a0aaa: propagate indexing errors so they don't appear successful to the task scheduler
|
|
8
|
+
- Updated dependencies
|
|
9
|
+
- @backstage/backend-tasks@0.3.2-next.0
|
|
10
|
+
|
|
11
|
+
## 0.6.1
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- 71d3432710: Search Engines will now index documents in batches of 1000 instead of 100 (under the hood). This may result in your Backstage backend consuming slightly more memory during index runs, but should dramatically improve indexing performance for large document sets.
|
|
16
|
+
- 3a74e203a8: Support generating highlighted matched terms in search result data
|
|
17
|
+
- Updated dependencies
|
|
18
|
+
- @backstage/backend-tasks@0.3.1
|
|
19
|
+
- @backstage/plugin-search-common@0.3.4
|
|
20
|
+
|
|
21
|
+
## 0.6.1-next.1
|
|
22
|
+
|
|
23
|
+
### Patch Changes
|
|
24
|
+
|
|
25
|
+
- 71d3432710: Search Engines will now index documents in batches of 1000 instead of 100 (under the hood). This may result in your Backstage backend consuming slightly more memory during index runs, but should dramatically improve indexing performance for large document sets.
|
|
26
|
+
- 3a74e203a8: Support generating highlighted matched terms in search result data
|
|
27
|
+
- Updated dependencies
|
|
28
|
+
- @backstage/backend-tasks@0.3.1-next.1
|
|
29
|
+
- @backstage/plugin-search-common@0.3.4-next.0
|
|
30
|
+
|
|
3
31
|
## 0.6.1-next.0
|
|
4
32
|
|
|
5
33
|
### Patch Changes
|
package/dist/index.cjs.js
CHANGED
|
@@ -5,6 +5,7 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
5
5
|
var stream = require('stream');
|
|
6
6
|
var nodeAbortController = require('node-abort-controller');
|
|
7
7
|
var lunr = require('lunr');
|
|
8
|
+
var uuid = require('uuid');
|
|
8
9
|
var errors = require('@backstage/errors');
|
|
9
10
|
|
|
10
11
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
@@ -98,14 +99,15 @@ class IndexBuilder {
|
|
|
98
99
|
return decorator;
|
|
99
100
|
}));
|
|
100
101
|
const indexer = await this.searchEngine.getIndexer(type);
|
|
101
|
-
return new Promise((
|
|
102
|
+
return new Promise((resolve, reject) => {
|
|
102
103
|
stream.pipeline([collator, ...decorators, indexer], (error) => {
|
|
103
104
|
if (error) {
|
|
104
105
|
this.logger.error(`Collating documents for ${type} failed: ${error}`);
|
|
106
|
+
reject(error);
|
|
105
107
|
} else {
|
|
106
108
|
this.logger.info(`Collating documents for ${type} succeeded`);
|
|
109
|
+
resolve();
|
|
107
110
|
}
|
|
108
|
-
done();
|
|
109
111
|
});
|
|
110
112
|
});
|
|
111
113
|
}
|
|
@@ -223,12 +225,13 @@ class DecoratorBase extends stream.Transform {
|
|
|
223
225
|
|
|
224
226
|
class LunrSearchEngineIndexer extends BatchSearchEngineIndexer {
|
|
225
227
|
constructor() {
|
|
226
|
-
super({ batchSize:
|
|
228
|
+
super({ batchSize: 1e3 });
|
|
227
229
|
this.schemaInitialized = false;
|
|
228
230
|
this.docStore = {};
|
|
229
231
|
this.builder = new lunr__default["default"].Builder();
|
|
230
232
|
this.builder.pipeline.add(lunr__default["default"].trimmer, lunr__default["default"].stopWordFilter, lunr__default["default"].stemmer);
|
|
231
233
|
this.builder.searchPipeline.add(lunr__default["default"].stemmer);
|
|
234
|
+
this.builder.metadataWhitelist = ["position"];
|
|
232
235
|
}
|
|
233
236
|
async initialize() {
|
|
234
237
|
}
|
|
@@ -310,6 +313,9 @@ class LunrSearchEngine {
|
|
|
310
313
|
};
|
|
311
314
|
this.logger = logger;
|
|
312
315
|
this.docStore = {};
|
|
316
|
+
const uuidTag = uuid.v4();
|
|
317
|
+
this.highlightPreTag = `<${uuidTag}>`;
|
|
318
|
+
this.highlightPostTag = `</${uuidTag}>`;
|
|
313
319
|
}
|
|
314
320
|
setTranslator(translator) {
|
|
315
321
|
this.translator = translator;
|
|
@@ -350,9 +356,20 @@ class LunrSearchEngine {
|
|
|
350
356
|
const nextPageCursor = hasNextPage ? encodePageCursor({ page: page + 1 }) : void 0;
|
|
351
357
|
const previousPageCursor = hasPreviousPage ? encodePageCursor({ page: page - 1 }) : void 0;
|
|
352
358
|
const realResultSet = {
|
|
353
|
-
results: results.slice(offset, offset + pageSize).map((d) => {
|
|
354
|
-
|
|
355
|
-
|
|
359
|
+
results: results.slice(offset, offset + pageSize).map((d) => ({
|
|
360
|
+
type: d.type,
|
|
361
|
+
document: this.docStore[d.result.ref],
|
|
362
|
+
highlight: {
|
|
363
|
+
preTag: this.highlightPreTag,
|
|
364
|
+
postTag: this.highlightPostTag,
|
|
365
|
+
fields: parseHighlightFields({
|
|
366
|
+
preTag: this.highlightPreTag,
|
|
367
|
+
postTag: this.highlightPostTag,
|
|
368
|
+
doc: this.docStore[d.result.ref],
|
|
369
|
+
positionMetadata: d.result.matchData.metadata
|
|
370
|
+
})
|
|
371
|
+
}
|
|
372
|
+
})),
|
|
356
373
|
nextPageCursor,
|
|
357
374
|
previousPageCursor
|
|
358
375
|
};
|
|
@@ -370,6 +387,28 @@ function decodePageCursor(pageCursor) {
|
|
|
370
387
|
function encodePageCursor({ page }) {
|
|
371
388
|
return Buffer.from(`${page}`, "utf-8").toString("base64");
|
|
372
389
|
}
|
|
390
|
+
function parseHighlightFields({
|
|
391
|
+
preTag,
|
|
392
|
+
postTag,
|
|
393
|
+
doc,
|
|
394
|
+
positionMetadata
|
|
395
|
+
}) {
|
|
396
|
+
const highlightFieldPositions = Object.values(positionMetadata).reduce((fieldPositions, metadata) => {
|
|
397
|
+
Object.keys(metadata).map((fieldKey) => {
|
|
398
|
+
var _a;
|
|
399
|
+
fieldPositions[fieldKey] = (_a = fieldPositions[fieldKey]) != null ? _a : [];
|
|
400
|
+
fieldPositions[fieldKey].push(...metadata[fieldKey].position);
|
|
401
|
+
});
|
|
402
|
+
return fieldPositions;
|
|
403
|
+
}, {});
|
|
404
|
+
return Object.fromEntries(Object.entries(highlightFieldPositions).map(([field, positions]) => {
|
|
405
|
+
positions.sort((a, b) => b[0] - a[0]);
|
|
406
|
+
const highlightedField = positions.reduce((content, pos) => {
|
|
407
|
+
return `${content.substring(0, pos[0])}${preTag}${content.substring(pos[0], pos[0] + pos[1])}${postTag}${content.substring(pos[0] + pos[1])}`;
|
|
408
|
+
}, doc[field]);
|
|
409
|
+
return [field, highlightedField];
|
|
410
|
+
}));
|
|
411
|
+
}
|
|
373
412
|
|
|
374
413
|
class TestPipeline {
|
|
375
414
|
constructor({
|
package/dist/index.cjs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs.js","sources":["../src/Scheduler.ts","../src/IndexBuilder.ts","../src/indexing/BatchSearchEngineIndexer.ts","../src/indexing/DecoratorBase.ts","../src/engines/LunrSearchEngineIndexer.ts","../src/engines/LunrSearchEngine.ts","../src/test-utils/TestPipeline.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { AbortController } from 'node-abort-controller';\nimport { Logger } from 'winston';\nimport { TaskFunction, TaskRunner } from '@backstage/backend-tasks';\n\ntype TaskEnvelope = {\n task: TaskFunction;\n scheduledRunner: TaskRunner;\n};\n\n/**\n * @public ScheduleTaskParameters\n */\nexport interface ScheduleTaskParameters {\n id: string;\n task: TaskFunction;\n scheduledRunner: TaskRunner;\n}\n\n/**\n * @beta\n */\nexport class Scheduler {\n private logger: Logger;\n private schedule: { [id: string]: TaskEnvelope };\n private abortController: AbortController;\n private isRunning: boolean;\n\n constructor({ logger }: { logger: Logger }) {\n this.logger = logger;\n this.schedule = {};\n this.abortController = new AbortController();\n this.isRunning = false;\n }\n\n /**\n * Adds each task and interval to the schedule.\n * When running the tasks, the scheduler waits at least for the time specified\n * in the interval once the task was completed, before running it again.\n */\n addToSchedule({ id, task, scheduledRunner }: ScheduleTaskParameters) {\n if (this.isRunning) {\n throw new Error(\n 'Cannot add task to schedule that has already been started.',\n );\n }\n\n if (this.schedule[id]) {\n throw new Error(`Task with id ${id} already exists.`);\n }\n\n this.schedule[id] = { task, scheduledRunner };\n }\n\n /**\n * Starts the scheduling process for each task\n */\n start() {\n this.logger.info('Starting all scheduled search tasks.');\n this.isRunning = true;\n Object.keys(this.schedule).forEach(id => {\n const { task, scheduledRunner } = this.schedule[id];\n scheduledRunner.run({\n id,\n fn: task,\n signal: this.abortController.signal,\n });\n });\n }\n\n /**\n * Stop all scheduled tasks.\n */\n stop() {\n this.logger.info('Stopping all scheduled search tasks.');\n this.abortController.abort();\n this.isRunning = false;\n }\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport {\n DocumentDecoratorFactory,\n DocumentTypeInfo,\n SearchEngine,\n} from '@backstage/plugin-search-common';\nimport { Transform, pipeline } from 'stream';\nimport { Logger } from 'winston';\nimport { Scheduler } from './Scheduler';\nimport {\n IndexBuilderOptions,\n RegisterCollatorParameters,\n RegisterDecoratorParameters,\n} from './types';\n\n/**\n * @beta\n */\nexport class IndexBuilder {\n private collators: Record<string, RegisterCollatorParameters>;\n private decorators: Record<string, DocumentDecoratorFactory[]>;\n private documentTypes: Record<string, DocumentTypeInfo>;\n private searchEngine: SearchEngine;\n private logger: Logger;\n\n constructor({ logger, searchEngine }: IndexBuilderOptions) {\n this.collators = {};\n this.decorators = {};\n this.documentTypes = {};\n this.logger = logger;\n this.searchEngine = searchEngine;\n }\n\n getSearchEngine(): SearchEngine {\n return this.searchEngine;\n }\n\n getDocumentTypes(): Record<string, DocumentTypeInfo> {\n return this.documentTypes;\n }\n\n /**\n * Makes the index builder aware of a collator that should be executed at the\n * given refresh interval.\n */\n addCollator({ factory, schedule }: RegisterCollatorParameters): void {\n this.logger.info(\n `Added ${factory.constructor.name} collator factory for type ${factory.type}`,\n );\n this.collators[factory.type] = {\n factory,\n schedule,\n };\n this.documentTypes[factory.type] = {\n visibilityPermission: factory.visibilityPermission,\n };\n }\n\n /**\n * Makes the index builder aware of a decorator. If no types are provided on\n * the decorator, it will be applied to documents from all known collators,\n * otherwise it will only be applied to documents of the given types.\n */\n addDecorator({ factory }: RegisterDecoratorParameters): void {\n const types = factory.types || ['*'];\n this.logger.info(\n `Added decorator ${factory.constructor.name} to types ${types.join(\n ', ',\n )}`,\n );\n types.forEach(type => {\n if (this.decorators.hasOwnProperty(type)) {\n this.decorators[type].push(factory);\n } else {\n this.decorators[type] = [factory];\n }\n });\n }\n\n /**\n * Compiles collators and decorators into tasks, which are added to a\n * scheduler returned to the caller.\n */\n async build(): Promise<{ scheduler: Scheduler }> {\n const scheduler = new Scheduler({\n logger: this.logger,\n });\n\n Object.keys(this.collators).forEach(type => {\n scheduler.addToSchedule({\n id: `search_index_${type.replace('-', '_').toLocaleLowerCase('en-US')}`,\n scheduledRunner: this.collators[type].schedule,\n task: async () => {\n // Instantiate the collator.\n const collator = await this.collators[type].factory.getCollator();\n this.logger.info(\n `Collating documents for ${type} via ${this.collators[type].factory.constructor.name}`,\n );\n\n // Instantiate all relevant decorators.\n const decorators: Transform[] = await Promise.all(\n (this.decorators['*'] || [])\n .concat(this.decorators[type] || [])\n .map(async factory => {\n const decorator = await factory.getDecorator();\n this.logger.info(\n `Attached decorator via ${factory.constructor.name} to ${type} index pipeline.`,\n );\n return decorator;\n }),\n );\n\n // Instantiate the indexer.\n const indexer = await this.searchEngine.getIndexer(type);\n\n // Compose collator/decorators/indexer into a pipeline\n return new Promise<void>(done => {\n pipeline(\n [collator, ...decorators, indexer],\n (error: NodeJS.ErrnoException | null) => {\n if (error) {\n this.logger.error(\n `Collating documents for ${type} failed: ${error}`,\n );\n } else {\n this.logger.info(`Collating documents for ${type} succeeded`);\n }\n\n // Signal index pipeline completion!\n done();\n },\n );\n });\n },\n });\n });\n\n return {\n scheduler,\n };\n }\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { assertError } from '@backstage/errors';\nimport { IndexableDocument } from '@backstage/plugin-search-common';\nimport { Writable } from 'stream';\n\n/**\n * @beta\n */\nexport type BatchSearchEngineOptions = {\n batchSize: number;\n};\n\n/**\n * Base class encapsulating batch-based stream processing. Useful as a base\n * class for search engine indexers.\n * @beta\n */\nexport abstract class BatchSearchEngineIndexer extends Writable {\n private batchSize: number;\n private currentBatch: IndexableDocument[] = [];\n private initialized: Promise<undefined | Error>;\n\n constructor(options: BatchSearchEngineOptions) {\n super({ objectMode: true });\n this.batchSize = options.batchSize;\n\n // @todo Once node v15 is minimum, convert to _construct implementation.\n this.initialized = new Promise(done => {\n // Necessary to allow concrete implementation classes to construct\n // themselves before calling their initialize() methods.\n setImmediate(async () => {\n try {\n await this.initialize();\n done(undefined);\n } catch (e) {\n assertError(e);\n done(e);\n }\n });\n });\n }\n\n /**\n * Receives an array of indexable documents (of size this.batchSize) which\n * should be written to the search engine. This method won't be called again\n * at least until it resolves.\n */\n public abstract index(documents: IndexableDocument[]): Promise<void>;\n\n /**\n * Any asynchronous setup tasks can be performed here.\n */\n public abstract initialize(): Promise<void>;\n\n /**\n * Any asynchronous teardown tasks can be performed here.\n */\n public abstract finalize(): Promise<void>;\n\n /**\n * Encapsulates batch stream write logic.\n * @internal\n */\n async _write(\n doc: IndexableDocument,\n _e: any,\n done: (error?: Error | null) => void,\n ) {\n // Wait for init before proceeding. Throw error if initialization failed.\n const maybeError = await this.initialized;\n if (maybeError) {\n done(maybeError);\n return;\n }\n\n this.currentBatch.push(doc);\n if (this.currentBatch.length < this.batchSize) {\n done();\n return;\n }\n\n try {\n await this.index(this.currentBatch);\n this.currentBatch = [];\n done();\n } catch (e) {\n assertError(e);\n done(e);\n }\n }\n\n /**\n * Encapsulates finalization and final error handling logic.\n * @internal\n */\n async _final(done: (error?: Error | null) => void) {\n try {\n // Index any remaining documents.\n if (this.currentBatch.length) {\n await this.index(this.currentBatch);\n this.currentBatch = [];\n }\n await this.finalize();\n done();\n } catch (e) {\n assertError(e);\n done(e);\n }\n }\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { assertError } from '@backstage/errors';\nimport { IndexableDocument } from '@backstage/plugin-search-common';\nimport { Transform } from 'stream';\n\n/**\n * Base class encapsulating simple async transformations. Useful as a base\n * class for Backstage search decorators.\n * @beta\n */\nexport abstract class DecoratorBase extends Transform {\n private initialized: Promise<undefined | Error>;\n\n constructor() {\n super({ objectMode: true });\n\n // @todo Once node v15 is minimum, convert to _construct implementation.\n this.initialized = new Promise(done => {\n // Necessary to allow concrete implementation classes to construct\n // themselves before calling their initialize() methods.\n setImmediate(async () => {\n try {\n await this.initialize();\n done(undefined);\n } catch (e) {\n assertError(e);\n done(e);\n }\n });\n });\n }\n\n /**\n * Any asynchronous setup tasks can be performed here.\n */\n public abstract initialize(): Promise<void>;\n\n /**\n * Receives a single indexable document. In your decorate method, you can:\n *\n * - Resolve `undefined` to indicate the record should be omitted.\n * - Resolve a single modified document, which could contain new fields,\n * edited fields, or removed fields.\n * - Resolve an array of indexable documents, if the purpose if the decorator\n * is to convert one document into multiple derivative documents.\n */\n public abstract decorate(\n document: IndexableDocument,\n ): Promise<IndexableDocument | IndexableDocument[] | undefined>;\n\n /**\n * Any asynchronous teardown tasks can be performed here.\n */\n public abstract finalize(): Promise<void>;\n\n /**\n * Encapsulates simple transform stream logic.\n * @internal\n */\n async _transform(\n document: IndexableDocument,\n _: any,\n done: (error?: Error | null) => void,\n ) {\n // Wait for init before proceeding. Throw error if initialization failed.\n const maybeError = await this.initialized;\n if (maybeError) {\n done(maybeError);\n return;\n }\n\n try {\n const decorated = await this.decorate(document);\n\n // If undefined was returned, omit the record and move on.\n if (decorated === undefined) {\n done();\n return;\n }\n\n // If an array of documents was given, push them all.\n if (Array.isArray(decorated)) {\n decorated.forEach(doc => {\n this.push(doc);\n });\n done();\n return;\n }\n\n // Otherwise, just push the decorated document.\n this.push(decorated);\n done();\n } catch (e) {\n assertError(e);\n done(e);\n }\n }\n\n /**\n * Encapsulates finalization and final error handling logic.\n * @internal\n */\n async _final(done: (error?: Error | null) => void) {\n try {\n await this.finalize();\n done();\n } catch (e) {\n assertError(e);\n done(e);\n }\n }\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { IndexableDocument } from '@backstage/plugin-search-common';\nimport lunr from 'lunr';\nimport { BatchSearchEngineIndexer } from '../indexing';\n\n/**\n * @beta\n */\nexport class LunrSearchEngineIndexer extends BatchSearchEngineIndexer {\n private schemaInitialized = false;\n private builder: lunr.Builder;\n private docStore: Record<string, IndexableDocument> = {};\n\n constructor() {\n super({ batchSize: 100 });\n\n this.builder = new lunr.Builder();\n this.builder.pipeline.add(lunr.trimmer, lunr.stopWordFilter, lunr.stemmer);\n this.builder.searchPipeline.add(lunr.stemmer);\n }\n\n // No async initialization required.\n async initialize(): Promise<void> {}\n async finalize(): Promise<void> {}\n\n async index(documents: IndexableDocument[]): Promise<void> {\n if (!this.schemaInitialized) {\n // Make this lunr index aware of all relevant fields.\n Object.keys(documents[0]).forEach(field => {\n this.builder.field(field);\n });\n\n // Set \"location\" field as reference field\n this.builder.ref('location');\n\n this.schemaInitialized = true;\n }\n\n documents.forEach(document => {\n // Add document to Lunar index\n this.builder.add(document);\n\n // Store documents in memory to be able to look up document using the ref during query time\n // This is not how you should implement your SearchEngine implementation! Do not copy!\n this.docStore[document.location] = document;\n });\n }\n\n buildIndex() {\n return this.builder.build();\n }\n\n getDocumentStore() {\n return this.docStore;\n }\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n IndexableDocument,\n IndexableResultSet,\n SearchQuery,\n QueryTranslator,\n SearchEngine,\n} from '@backstage/plugin-search-common';\nimport lunr from 'lunr';\nimport { Logger } from 'winston';\nimport { LunrSearchEngineIndexer } from './LunrSearchEngineIndexer';\n\n/**\n * @beta\n */\nexport type ConcreteLunrQuery = {\n lunrQueryBuilder: lunr.Index.QueryBuilder;\n documentTypes?: string[];\n pageSize: number;\n};\n\ntype LunrResultEnvelope = {\n result: lunr.Index.Result;\n type: string;\n};\n\n/**\n * @beta\n */\nexport type LunrQueryTranslator = (query: SearchQuery) => ConcreteLunrQuery;\n\n/**\n * @beta\n */\nexport class LunrSearchEngine implements SearchEngine {\n protected lunrIndices: Record<string, lunr.Index> = {};\n protected docStore: Record<string, IndexableDocument>;\n protected logger: Logger;\n\n constructor({ logger }: { logger: Logger }) {\n this.logger = logger;\n this.docStore = {};\n }\n\n protected translator: QueryTranslator = ({\n term,\n filters,\n types,\n }: SearchQuery): ConcreteLunrQuery => {\n const pageSize = 25;\n\n return {\n lunrQueryBuilder: q => {\n const termToken = lunr.tokenizer(term);\n\n // Support for typeahead search is based on https://github.com/olivernn/lunr.js/issues/256#issuecomment-295407852\n // look for an exact match and apply a large positive boost\n q.term(termToken, {\n usePipeline: true,\n boost: 100,\n });\n // look for terms that match the beginning of this term and apply a\n // medium boost\n q.term(termToken, {\n usePipeline: false,\n boost: 10,\n wildcard: lunr.Query.wildcard.TRAILING,\n });\n // look for terms that match with an edit distance of 2 and apply a\n // small boost\n q.term(termToken, {\n usePipeline: false,\n editDistance: 2,\n boost: 1,\n });\n\n if (filters) {\n Object.entries(filters).forEach(([field, fieldValue]) => {\n if (!q.allFields.includes(field)) {\n // Throw for unknown field, as this will be a non match\n throw new Error(`unrecognised field ${field}`);\n }\n // Arrays are poorly supported, but we can make it better for single-item arrays,\n // which should be a common case\n const value =\n Array.isArray(fieldValue) && fieldValue.length === 1\n ? fieldValue[0]\n : fieldValue;\n\n // Require that the given field has the given value\n if (['string', 'number', 'boolean'].includes(typeof value)) {\n q.term(lunr.tokenizer(value?.toString()), {\n presence: lunr.Query.presence.REQUIRED,\n fields: [field],\n });\n } else if (Array.isArray(value)) {\n // Illustrate how multi-value filters could work.\n // But warn that Lurn supports this poorly.\n this.logger.warn(\n `Non-scalar filter value used for field ${field}. Consider using a different Search Engine for better results.`,\n );\n q.term(lunr.tokenizer(value), {\n presence: lunr.Query.presence.OPTIONAL,\n fields: [field],\n });\n } else {\n // Log a warning or something about unknown filter value\n this.logger.warn(`Unknown filter type used on field ${field}`);\n }\n });\n }\n },\n documentTypes: types,\n pageSize,\n };\n };\n\n setTranslator(translator: LunrQueryTranslator) {\n this.translator = translator;\n }\n\n async getIndexer(type: string) {\n const indexer = new LunrSearchEngineIndexer();\n\n indexer.on('close', () => {\n // Once the stream is closed, build the index and store the documents in\n // memory for later retrieval.\n this.lunrIndices[type] = indexer.buildIndex();\n this.docStore = { ...this.docStore, ...indexer.getDocumentStore() };\n });\n\n return indexer;\n }\n\n async query(query: SearchQuery): Promise<IndexableResultSet> {\n const { lunrQueryBuilder, documentTypes, pageSize } = this.translator(\n query,\n ) as ConcreteLunrQuery;\n\n const results: LunrResultEnvelope[] = [];\n\n // Iterate over the filtered list of this.lunrIndex keys.\n Object.keys(this.lunrIndices)\n .filter(type => !documentTypes || documentTypes.includes(type))\n .forEach(type => {\n try {\n results.push(\n ...this.lunrIndices[type].query(lunrQueryBuilder).map(result => {\n return {\n result: result,\n type: type,\n };\n }),\n );\n } catch (err) {\n // if a field does not exist on a index, we can see that as a no-match\n if (\n err instanceof Error &&\n err.message.startsWith('unrecognised field')\n ) {\n return;\n }\n throw err;\n }\n });\n\n // Sort results.\n results.sort((doc1, doc2) => {\n return doc2.result.score - doc1.result.score;\n });\n\n // Perform paging\n const { page } = decodePageCursor(query.pageCursor);\n const offset = page * pageSize;\n const hasPreviousPage = page > 0;\n const hasNextPage = results.length > offset + pageSize;\n const nextPageCursor = hasNextPage\n ? encodePageCursor({ page: page + 1 })\n : undefined;\n const previousPageCursor = hasPreviousPage\n ? encodePageCursor({ page: page - 1 })\n : undefined;\n\n // Translate results into IndexableResultSet\n const realResultSet: IndexableResultSet = {\n results: results.slice(offset, offset + pageSize).map(d => {\n return { type: d.type, document: this.docStore[d.result.ref] };\n }),\n nextPageCursor,\n previousPageCursor,\n };\n\n return realResultSet;\n }\n}\n\nexport function decodePageCursor(pageCursor?: string): { page: number } {\n if (!pageCursor) {\n return { page: 0 };\n }\n\n return {\n page: Number(Buffer.from(pageCursor, 'base64').toString('utf-8')),\n };\n}\n\nexport function encodePageCursor({ page }: { page: number }): string {\n return Buffer.from(`${page}`, 'utf-8').toString('base64');\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { IndexableDocument } from '@backstage/plugin-search-common';\nimport { pipeline, Readable, Transform, Writable } from 'stream';\n\n/**\n * Object resolved after a test pipeline is executed.\n * @beta\n */\nexport type TestPipelineResult = {\n /**\n * If an error was emitted by the pipeline, it will be set here.\n */\n error: unknown;\n\n /**\n * A list of documents collected at the end of the pipeline. If the subject\n * under test is an indexer, this will be an empty array (because your\n * indexer should have received the documents instead).\n */\n documents: IndexableDocument[];\n};\n\n/**\n * Test utility for Backstage Search collators, decorators, and indexers.\n * @beta\n */\nexport class TestPipeline {\n private collator?: Readable;\n private decorator?: Transform;\n private indexer?: Writable;\n\n private constructor({\n collator,\n decorator,\n indexer,\n }: {\n collator?: Readable;\n decorator?: Transform;\n indexer?: Writable;\n }) {\n this.collator = collator;\n this.decorator = decorator;\n this.indexer = indexer;\n }\n\n /**\n * Provide the collator, decorator, or indexer to be tested.\n */\n static withSubject(subject: Readable | Transform | Writable) {\n if (subject instanceof Transform) {\n return new TestPipeline({ decorator: subject });\n }\n\n if (subject instanceof Readable) {\n return new TestPipeline({ collator: subject });\n }\n\n if (subject instanceof Writable) {\n return new TestPipeline({ indexer: subject });\n }\n\n throw new Error(\n 'Unknown test subject: are you passing a readable, writable, or transform stream?',\n );\n }\n\n /**\n * Provide documents for testing decorators and indexers.\n */\n withDocuments(documents: IndexableDocument[]): TestPipeline {\n if (this.collator) {\n throw new Error('Cannot provide documents when testing a collator.');\n }\n\n // Set a naive readable stream that just pushes all given documents.\n this.collator = new Readable({ objectMode: true });\n this.collator._read = () => {};\n process.nextTick(() => {\n documents.forEach(document => {\n this.collator!.push(document);\n });\n this.collator!.push(null);\n });\n\n return this;\n }\n\n /**\n * Execute the test pipeline so that you can make assertions about the result\n * or behavior of the given test subject.\n */\n async execute(): Promise<TestPipelineResult> {\n const documents: IndexableDocument[] = [];\n if (!this.collator) {\n throw new Error(\n 'Cannot execute pipeline without a collator or documents',\n );\n }\n\n // If we are here and there is no indexer, we are testing a collator or a\n // decorator. Set up a naive writable that captures documents in memory.\n if (!this.indexer) {\n this.indexer = new Writable({ objectMode: true });\n this.indexer._write = (document: IndexableDocument, _, done) => {\n documents.push(document);\n done();\n };\n }\n\n return new Promise<TestPipelineResult>(done => {\n const pipes: (Readable | Transform | Writable)[] = [this.collator!];\n if (this.decorator) {\n pipes.push(this.decorator);\n }\n pipes.push(this.indexer!);\n\n pipeline(pipes, (error: NodeJS.ErrnoException | null) => {\n done({\n error,\n documents,\n });\n });\n });\n }\n}\n"],"names":["AbortController","pipeline","Writable","assertError","Transform","lunr","Readable"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs.js","sources":["../src/Scheduler.ts","../src/IndexBuilder.ts","../src/indexing/BatchSearchEngineIndexer.ts","../src/indexing/DecoratorBase.ts","../src/engines/LunrSearchEngineIndexer.ts","../src/engines/LunrSearchEngine.ts","../src/test-utils/TestPipeline.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { AbortController } from 'node-abort-controller';\nimport { Logger } from 'winston';\nimport { TaskFunction, TaskRunner } from '@backstage/backend-tasks';\n\ntype TaskEnvelope = {\n task: TaskFunction;\n scheduledRunner: TaskRunner;\n};\n\n/**\n * @public ScheduleTaskParameters\n */\nexport interface ScheduleTaskParameters {\n id: string;\n task: TaskFunction;\n scheduledRunner: TaskRunner;\n}\n\n/**\n * @beta\n */\nexport class Scheduler {\n private logger: Logger;\n private schedule: { [id: string]: TaskEnvelope };\n private abortController: AbortController;\n private isRunning: boolean;\n\n constructor({ logger }: { logger: Logger }) {\n this.logger = logger;\n this.schedule = {};\n this.abortController = new AbortController();\n this.isRunning = false;\n }\n\n /**\n * Adds each task and interval to the schedule.\n * When running the tasks, the scheduler waits at least for the time specified\n * in the interval once the task was completed, before running it again.\n */\n addToSchedule({ id, task, scheduledRunner }: ScheduleTaskParameters) {\n if (this.isRunning) {\n throw new Error(\n 'Cannot add task to schedule that has already been started.',\n );\n }\n\n if (this.schedule[id]) {\n throw new Error(`Task with id ${id} already exists.`);\n }\n\n this.schedule[id] = { task, scheduledRunner };\n }\n\n /**\n * Starts the scheduling process for each task\n */\n start() {\n this.logger.info('Starting all scheduled search tasks.');\n this.isRunning = true;\n Object.keys(this.schedule).forEach(id => {\n const { task, scheduledRunner } = this.schedule[id];\n scheduledRunner.run({\n id,\n fn: task,\n signal: this.abortController.signal,\n });\n });\n }\n\n /**\n * Stop all scheduled tasks.\n */\n stop() {\n this.logger.info('Stopping all scheduled search tasks.');\n this.abortController.abort();\n this.isRunning = false;\n }\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport {\n DocumentDecoratorFactory,\n DocumentTypeInfo,\n SearchEngine,\n} from '@backstage/plugin-search-common';\nimport { Transform, pipeline } from 'stream';\nimport { Logger } from 'winston';\nimport { Scheduler } from './Scheduler';\nimport {\n IndexBuilderOptions,\n RegisterCollatorParameters,\n RegisterDecoratorParameters,\n} from './types';\n\n/**\n * @beta\n */\nexport class IndexBuilder {\n private collators: Record<string, RegisterCollatorParameters>;\n private decorators: Record<string, DocumentDecoratorFactory[]>;\n private documentTypes: Record<string, DocumentTypeInfo>;\n private searchEngine: SearchEngine;\n private logger: Logger;\n\n constructor({ logger, searchEngine }: IndexBuilderOptions) {\n this.collators = {};\n this.decorators = {};\n this.documentTypes = {};\n this.logger = logger;\n this.searchEngine = searchEngine;\n }\n\n getSearchEngine(): SearchEngine {\n return this.searchEngine;\n }\n\n getDocumentTypes(): Record<string, DocumentTypeInfo> {\n return this.documentTypes;\n }\n\n /**\n * Makes the index builder aware of a collator that should be executed at the\n * given refresh interval.\n */\n addCollator({ factory, schedule }: RegisterCollatorParameters): void {\n this.logger.info(\n `Added ${factory.constructor.name} collator factory for type ${factory.type}`,\n );\n this.collators[factory.type] = {\n factory,\n schedule,\n };\n this.documentTypes[factory.type] = {\n visibilityPermission: factory.visibilityPermission,\n };\n }\n\n /**\n * Makes the index builder aware of a decorator. If no types are provided on\n * the decorator, it will be applied to documents from all known collators,\n * otherwise it will only be applied to documents of the given types.\n */\n addDecorator({ factory }: RegisterDecoratorParameters): void {\n const types = factory.types || ['*'];\n this.logger.info(\n `Added decorator ${factory.constructor.name} to types ${types.join(\n ', ',\n )}`,\n );\n types.forEach(type => {\n if (this.decorators.hasOwnProperty(type)) {\n this.decorators[type].push(factory);\n } else {\n this.decorators[type] = [factory];\n }\n });\n }\n\n /**\n * Compiles collators and decorators into tasks, which are added to a\n * scheduler returned to the caller.\n */\n async build(): Promise<{ scheduler: Scheduler }> {\n const scheduler = new Scheduler({\n logger: this.logger,\n });\n\n Object.keys(this.collators).forEach(type => {\n scheduler.addToSchedule({\n id: `search_index_${type.replace('-', '_').toLocaleLowerCase('en-US')}`,\n scheduledRunner: this.collators[type].schedule,\n task: async () => {\n // Instantiate the collator.\n const collator = await this.collators[type].factory.getCollator();\n this.logger.info(\n `Collating documents for ${type} via ${this.collators[type].factory.constructor.name}`,\n );\n\n // Instantiate all relevant decorators.\n const decorators: Transform[] = await Promise.all(\n (this.decorators['*'] || [])\n .concat(this.decorators[type] || [])\n .map(async factory => {\n const decorator = await factory.getDecorator();\n this.logger.info(\n `Attached decorator via ${factory.constructor.name} to ${type} index pipeline.`,\n );\n return decorator;\n }),\n );\n\n // Instantiate the indexer.\n const indexer = await this.searchEngine.getIndexer(type);\n\n // Compose collator/decorators/indexer into a pipeline\n return new Promise<void>((resolve, reject) => {\n pipeline(\n [collator, ...decorators, indexer],\n (error: NodeJS.ErrnoException | null) => {\n if (error) {\n this.logger.error(\n `Collating documents for ${type} failed: ${error}`,\n );\n reject(error);\n } else {\n // Signal index pipeline completion!\n this.logger.info(`Collating documents for ${type} succeeded`);\n resolve();\n }\n },\n );\n });\n },\n });\n });\n\n return {\n scheduler,\n };\n }\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { assertError } from '@backstage/errors';\nimport { IndexableDocument } from '@backstage/plugin-search-common';\nimport { Writable } from 'stream';\n\n/**\n * @beta\n */\nexport type BatchSearchEngineOptions = {\n batchSize: number;\n};\n\n/**\n * Base class encapsulating batch-based stream processing. Useful as a base\n * class for search engine indexers.\n * @beta\n */\nexport abstract class BatchSearchEngineIndexer extends Writable {\n private batchSize: number;\n private currentBatch: IndexableDocument[] = [];\n private initialized: Promise<undefined | Error>;\n\n constructor(options: BatchSearchEngineOptions) {\n super({ objectMode: true });\n this.batchSize = options.batchSize;\n\n // @todo Once node v15 is minimum, convert to _construct implementation.\n this.initialized = new Promise(done => {\n // Necessary to allow concrete implementation classes to construct\n // themselves before calling their initialize() methods.\n setImmediate(async () => {\n try {\n await this.initialize();\n done(undefined);\n } catch (e) {\n assertError(e);\n done(e);\n }\n });\n });\n }\n\n /**\n * Receives an array of indexable documents (of size this.batchSize) which\n * should be written to the search engine. This method won't be called again\n * at least until it resolves.\n */\n public abstract index(documents: IndexableDocument[]): Promise<void>;\n\n /**\n * Any asynchronous setup tasks can be performed here.\n */\n public abstract initialize(): Promise<void>;\n\n /**\n * Any asynchronous teardown tasks can be performed here.\n */\n public abstract finalize(): Promise<void>;\n\n /**\n * Encapsulates batch stream write logic.\n * @internal\n */\n async _write(\n doc: IndexableDocument,\n _e: any,\n done: (error?: Error | null) => void,\n ) {\n // Wait for init before proceeding. Throw error if initialization failed.\n const maybeError = await this.initialized;\n if (maybeError) {\n done(maybeError);\n return;\n }\n\n this.currentBatch.push(doc);\n if (this.currentBatch.length < this.batchSize) {\n done();\n return;\n }\n\n try {\n await this.index(this.currentBatch);\n this.currentBatch = [];\n done();\n } catch (e) {\n assertError(e);\n done(e);\n }\n }\n\n /**\n * Encapsulates finalization and final error handling logic.\n * @internal\n */\n async _final(done: (error?: Error | null) => void) {\n try {\n // Index any remaining documents.\n if (this.currentBatch.length) {\n await this.index(this.currentBatch);\n this.currentBatch = [];\n }\n await this.finalize();\n done();\n } catch (e) {\n assertError(e);\n done(e);\n }\n }\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { assertError } from '@backstage/errors';\nimport { IndexableDocument } from '@backstage/plugin-search-common';\nimport { Transform } from 'stream';\n\n/**\n * Base class encapsulating simple async transformations. Useful as a base\n * class for Backstage search decorators.\n * @beta\n */\nexport abstract class DecoratorBase extends Transform {\n private initialized: Promise<undefined | Error>;\n\n constructor() {\n super({ objectMode: true });\n\n // @todo Once node v15 is minimum, convert to _construct implementation.\n this.initialized = new Promise(done => {\n // Necessary to allow concrete implementation classes to construct\n // themselves before calling their initialize() methods.\n setImmediate(async () => {\n try {\n await this.initialize();\n done(undefined);\n } catch (e) {\n assertError(e);\n done(e);\n }\n });\n });\n }\n\n /**\n * Any asynchronous setup tasks can be performed here.\n */\n public abstract initialize(): Promise<void>;\n\n /**\n * Receives a single indexable document. In your decorate method, you can:\n *\n * - Resolve `undefined` to indicate the record should be omitted.\n * - Resolve a single modified document, which could contain new fields,\n * edited fields, or removed fields.\n * - Resolve an array of indexable documents, if the purpose if the decorator\n * is to convert one document into multiple derivative documents.\n */\n public abstract decorate(\n document: IndexableDocument,\n ): Promise<IndexableDocument | IndexableDocument[] | undefined>;\n\n /**\n * Any asynchronous teardown tasks can be performed here.\n */\n public abstract finalize(): Promise<void>;\n\n /**\n * Encapsulates simple transform stream logic.\n * @internal\n */\n async _transform(\n document: IndexableDocument,\n _: any,\n done: (error?: Error | null) => void,\n ) {\n // Wait for init before proceeding. Throw error if initialization failed.\n const maybeError = await this.initialized;\n if (maybeError) {\n done(maybeError);\n return;\n }\n\n try {\n const decorated = await this.decorate(document);\n\n // If undefined was returned, omit the record and move on.\n if (decorated === undefined) {\n done();\n return;\n }\n\n // If an array of documents was given, push them all.\n if (Array.isArray(decorated)) {\n decorated.forEach(doc => {\n this.push(doc);\n });\n done();\n return;\n }\n\n // Otherwise, just push the decorated document.\n this.push(decorated);\n done();\n } catch (e) {\n assertError(e);\n done(e);\n }\n }\n\n /**\n * Encapsulates finalization and final error handling logic.\n * @internal\n */\n async _final(done: (error?: Error | null) => void) {\n try {\n await this.finalize();\n done();\n } catch (e) {\n assertError(e);\n done(e);\n }\n }\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { IndexableDocument } from '@backstage/plugin-search-common';\nimport lunr from 'lunr';\nimport { BatchSearchEngineIndexer } from '../indexing';\n\n/**\n * @beta\n */\nexport class LunrSearchEngineIndexer extends BatchSearchEngineIndexer {\n private schemaInitialized = false;\n private builder: lunr.Builder;\n private docStore: Record<string, IndexableDocument> = {};\n\n constructor() {\n super({ batchSize: 1000 });\n\n this.builder = new lunr.Builder();\n this.builder.pipeline.add(lunr.trimmer, lunr.stopWordFilter, lunr.stemmer);\n this.builder.searchPipeline.add(lunr.stemmer);\n this.builder.metadataWhitelist = ['position'];\n }\n\n // No async initialization required.\n async initialize(): Promise<void> {}\n async finalize(): Promise<void> {}\n\n async index(documents: IndexableDocument[]): Promise<void> {\n if (!this.schemaInitialized) {\n // Make this lunr index aware of all relevant fields.\n Object.keys(documents[0]).forEach(field => {\n this.builder.field(field);\n });\n\n // Set \"location\" field as reference field\n this.builder.ref('location');\n\n this.schemaInitialized = true;\n }\n\n documents.forEach(document => {\n // Add document to Lunar index\n this.builder.add(document);\n\n // Store documents in memory to be able to look up document using the ref during query time\n // This is not how you should implement your SearchEngine implementation! Do not copy!\n this.docStore[document.location] = document;\n });\n }\n\n buildIndex() {\n return this.builder.build();\n }\n\n getDocumentStore() {\n return this.docStore;\n }\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n IndexableDocument,\n IndexableResultSet,\n SearchQuery,\n QueryTranslator,\n SearchEngine,\n} from '@backstage/plugin-search-common';\nimport lunr from 'lunr';\nimport { v4 as uuid } from 'uuid';\nimport { Logger } from 'winston';\nimport { LunrSearchEngineIndexer } from './LunrSearchEngineIndexer';\n\n/**\n * @beta\n */\nexport type ConcreteLunrQuery = {\n lunrQueryBuilder: lunr.Index.QueryBuilder;\n documentTypes?: string[];\n pageSize: number;\n};\n\ntype LunrResultEnvelope = {\n result: lunr.Index.Result;\n type: string;\n};\n\n/**\n * @beta\n */\nexport type LunrQueryTranslator = (query: SearchQuery) => ConcreteLunrQuery;\n\n/**\n * @beta\n */\nexport class LunrSearchEngine implements SearchEngine {\n protected lunrIndices: Record<string, lunr.Index> = {};\n protected docStore: Record<string, IndexableDocument>;\n protected logger: Logger;\n protected highlightPreTag: string;\n protected highlightPostTag: string;\n\n constructor({ logger }: { logger: Logger }) {\n this.logger = logger;\n this.docStore = {};\n const uuidTag = uuid();\n this.highlightPreTag = `<${uuidTag}>`;\n this.highlightPostTag = `</${uuidTag}>`;\n }\n\n protected translator: QueryTranslator = ({\n term,\n filters,\n types,\n }: SearchQuery): ConcreteLunrQuery => {\n const pageSize = 25;\n\n return {\n lunrQueryBuilder: q => {\n const termToken = lunr.tokenizer(term);\n\n // Support for typeahead search is based on https://github.com/olivernn/lunr.js/issues/256#issuecomment-295407852\n // look for an exact match and apply a large positive boost\n q.term(termToken, {\n usePipeline: true,\n boost: 100,\n });\n // look for terms that match the beginning of this term and apply a\n // medium boost\n q.term(termToken, {\n usePipeline: false,\n boost: 10,\n wildcard: lunr.Query.wildcard.TRAILING,\n });\n // look for terms that match with an edit distance of 2 and apply a\n // small boost\n q.term(termToken, {\n usePipeline: false,\n editDistance: 2,\n boost: 1,\n });\n\n if (filters) {\n Object.entries(filters).forEach(([field, fieldValue]) => {\n if (!q.allFields.includes(field)) {\n // Throw for unknown field, as this will be a non match\n throw new Error(`unrecognised field ${field}`);\n }\n // Arrays are poorly supported, but we can make it better for single-item arrays,\n // which should be a common case\n const value =\n Array.isArray(fieldValue) && fieldValue.length === 1\n ? fieldValue[0]\n : fieldValue;\n\n // Require that the given field has the given value\n if (['string', 'number', 'boolean'].includes(typeof value)) {\n q.term(lunr.tokenizer(value?.toString()), {\n presence: lunr.Query.presence.REQUIRED,\n fields: [field],\n });\n } else if (Array.isArray(value)) {\n // Illustrate how multi-value filters could work.\n // But warn that Lurn supports this poorly.\n this.logger.warn(\n `Non-scalar filter value used for field ${field}. Consider using a different Search Engine for better results.`,\n );\n q.term(lunr.tokenizer(value), {\n presence: lunr.Query.presence.OPTIONAL,\n fields: [field],\n });\n } else {\n // Log a warning or something about unknown filter value\n this.logger.warn(`Unknown filter type used on field ${field}`);\n }\n });\n }\n },\n documentTypes: types,\n pageSize,\n };\n };\n\n setTranslator(translator: LunrQueryTranslator) {\n this.translator = translator;\n }\n\n async getIndexer(type: string) {\n const indexer = new LunrSearchEngineIndexer();\n\n indexer.on('close', () => {\n // Once the stream is closed, build the index and store the documents in\n // memory for later retrieval.\n this.lunrIndices[type] = indexer.buildIndex();\n this.docStore = { ...this.docStore, ...indexer.getDocumentStore() };\n });\n\n return indexer;\n }\n\n async query(query: SearchQuery): Promise<IndexableResultSet> {\n const { lunrQueryBuilder, documentTypes, pageSize } = this.translator(\n query,\n ) as ConcreteLunrQuery;\n\n const results: LunrResultEnvelope[] = [];\n\n // Iterate over the filtered list of this.lunrIndex keys.\n Object.keys(this.lunrIndices)\n .filter(type => !documentTypes || documentTypes.includes(type))\n .forEach(type => {\n try {\n results.push(\n ...this.lunrIndices[type].query(lunrQueryBuilder).map(result => {\n return {\n result: result,\n type: type,\n };\n }),\n );\n } catch (err) {\n // if a field does not exist on a index, we can see that as a no-match\n if (\n err instanceof Error &&\n err.message.startsWith('unrecognised field')\n ) {\n return;\n }\n throw err;\n }\n });\n\n // Sort results.\n results.sort((doc1, doc2) => {\n return doc2.result.score - doc1.result.score;\n });\n\n // Perform paging\n const { page } = decodePageCursor(query.pageCursor);\n const offset = page * pageSize;\n const hasPreviousPage = page > 0;\n const hasNextPage = results.length > offset + pageSize;\n const nextPageCursor = hasNextPage\n ? encodePageCursor({ page: page + 1 })\n : undefined;\n const previousPageCursor = hasPreviousPage\n ? encodePageCursor({ page: page - 1 })\n : undefined;\n\n // Translate results into IndexableResultSet\n const realResultSet: IndexableResultSet = {\n results: results.slice(offset, offset + pageSize).map(d => ({\n type: d.type,\n document: this.docStore[d.result.ref],\n highlight: {\n preTag: this.highlightPreTag,\n postTag: this.highlightPostTag,\n fields: parseHighlightFields({\n preTag: this.highlightPreTag,\n postTag: this.highlightPostTag,\n doc: this.docStore[d.result.ref],\n positionMetadata: d.result.matchData.metadata as any,\n }),\n },\n })),\n nextPageCursor,\n previousPageCursor,\n };\n\n return realResultSet;\n }\n}\n\nexport function decodePageCursor(pageCursor?: string): { page: number } {\n if (!pageCursor) {\n return { page: 0 };\n }\n\n return {\n page: Number(Buffer.from(pageCursor, 'base64').toString('utf-8')),\n };\n}\n\nexport function encodePageCursor({ page }: { page: number }): string {\n return Buffer.from(`${page}`, 'utf-8').toString('base64');\n}\n\ntype ParseHighlightFieldsProps = {\n preTag: string;\n postTag: string;\n doc: any;\n positionMetadata: {\n [term: string]: {\n [field: string]: {\n position: number[][];\n };\n };\n };\n};\n\nexport function parseHighlightFields({\n preTag,\n postTag,\n doc,\n positionMetadata,\n}: ParseHighlightFieldsProps): { [field: string]: string } {\n // Merge the field positions across all query terms\n const highlightFieldPositions = Object.values(positionMetadata).reduce(\n (fieldPositions, metadata) => {\n Object.keys(metadata).map(fieldKey => {\n fieldPositions[fieldKey] = fieldPositions[fieldKey] ?? [];\n fieldPositions[fieldKey].push(...metadata[fieldKey].position);\n });\n\n return fieldPositions;\n },\n {} as { [field: string]: number[][] },\n );\n\n return Object.fromEntries(\n Object.entries(highlightFieldPositions).map(([field, positions]) => {\n positions.sort((a, b) => b[0] - a[0]);\n\n const highlightedField = positions.reduce((content, pos) => {\n return (\n `${content.substring(0, pos[0])}${preTag}` +\n `${content.substring(pos[0], pos[0] + pos[1])}` +\n `${postTag}${content.substring(pos[0] + pos[1])}`\n );\n }, doc[field]);\n\n return [field, highlightedField];\n }),\n );\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { IndexableDocument } from '@backstage/plugin-search-common';\nimport { pipeline, Readable, Transform, Writable } from 'stream';\n\n/**\n * Object resolved after a test pipeline is executed.\n * @beta\n */\nexport type TestPipelineResult = {\n /**\n * If an error was emitted by the pipeline, it will be set here.\n */\n error: unknown;\n\n /**\n * A list of documents collected at the end of the pipeline. If the subject\n * under test is an indexer, this will be an empty array (because your\n * indexer should have received the documents instead).\n */\n documents: IndexableDocument[];\n};\n\n/**\n * Test utility for Backstage Search collators, decorators, and indexers.\n * @beta\n */\nexport class TestPipeline {\n private collator?: Readable;\n private decorator?: Transform;\n private indexer?: Writable;\n\n private constructor({\n collator,\n decorator,\n indexer,\n }: {\n collator?: Readable;\n decorator?: Transform;\n indexer?: Writable;\n }) {\n this.collator = collator;\n this.decorator = decorator;\n this.indexer = indexer;\n }\n\n /**\n * Provide the collator, decorator, or indexer to be tested.\n */\n static withSubject(subject: Readable | Transform | Writable) {\n if (subject instanceof Transform) {\n return new TestPipeline({ decorator: subject });\n }\n\n if (subject instanceof Readable) {\n return new TestPipeline({ collator: subject });\n }\n\n if (subject instanceof Writable) {\n return new TestPipeline({ indexer: subject });\n }\n\n throw new Error(\n 'Unknown test subject: are you passing a readable, writable, or transform stream?',\n );\n }\n\n /**\n * Provide documents for testing decorators and indexers.\n */\n withDocuments(documents: IndexableDocument[]): TestPipeline {\n if (this.collator) {\n throw new Error('Cannot provide documents when testing a collator.');\n }\n\n // Set a naive readable stream that just pushes all given documents.\n this.collator = new Readable({ objectMode: true });\n this.collator._read = () => {};\n process.nextTick(() => {\n documents.forEach(document => {\n this.collator!.push(document);\n });\n this.collator!.push(null);\n });\n\n return this;\n }\n\n /**\n * Execute the test pipeline so that you can make assertions about the result\n * or behavior of the given test subject.\n */\n async execute(): Promise<TestPipelineResult> {\n const documents: IndexableDocument[] = [];\n if (!this.collator) {\n throw new Error(\n 'Cannot execute pipeline without a collator or documents',\n );\n }\n\n // If we are here and there is no indexer, we are testing a collator or a\n // decorator. Set up a naive writable that captures documents in memory.\n if (!this.indexer) {\n this.indexer = new Writable({ objectMode: true });\n this.indexer._write = (document: IndexableDocument, _, done) => {\n documents.push(document);\n done();\n };\n }\n\n return new Promise<TestPipelineResult>(done => {\n const pipes: (Readable | Transform | Writable)[] = [this.collator!];\n if (this.decorator) {\n pipes.push(this.decorator);\n }\n pipes.push(this.indexer!);\n\n pipeline(pipes, (error: NodeJS.ErrnoException | null) => {\n done({\n error,\n documents,\n });\n });\n });\n }\n}\n"],"names":["AbortController","pipeline","Writable","assertError","Transform","lunr","uuid","Readable"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -200,6 +200,8 @@ declare class LunrSearchEngine implements SearchEngine {
|
|
|
200
200
|
protected lunrIndices: Record<string, lunr.Index>;
|
|
201
201
|
protected docStore: Record<string, IndexableDocument>;
|
|
202
202
|
protected logger: Logger;
|
|
203
|
+
protected highlightPreTag: string;
|
|
204
|
+
protected highlightPostTag: string;
|
|
203
205
|
constructor({ logger }: {
|
|
204
206
|
logger: Logger;
|
|
205
207
|
});
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backstage/plugin-search-backend-node",
|
|
3
3
|
"description": "A library for Backstage backend plugins that want to interact with the search backend plugin",
|
|
4
|
-
"version": "0.6.
|
|
4
|
+
"version": "0.6.2-next.0",
|
|
5
5
|
"main": "dist/index.cjs.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"license": "Apache-2.0",
|
|
@@ -23,21 +23,22 @@
|
|
|
23
23
|
"clean": "backstage-cli package clean"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@backstage/backend-tasks": "^0.3.
|
|
26
|
+
"@backstage/backend-tasks": "^0.3.2-next.0",
|
|
27
27
|
"@backstage/errors": "^1.0.0",
|
|
28
|
-
"@backstage/plugin-search-common": "^0.3.
|
|
28
|
+
"@backstage/plugin-search-common": "^0.3.4",
|
|
29
29
|
"@types/lunr": "^2.3.3",
|
|
30
30
|
"lodash": "^4.17.21",
|
|
31
31
|
"lunr": "^2.3.9",
|
|
32
32
|
"node-abort-controller": "^3.0.1",
|
|
33
|
+
"uuid": "^8.3.2",
|
|
33
34
|
"winston": "^3.2.1"
|
|
34
35
|
},
|
|
35
36
|
"devDependencies": {
|
|
36
|
-
"@backstage/backend-common": "^0.13.
|
|
37
|
-
"@backstage/cli": "^0.17.
|
|
37
|
+
"@backstage/backend-common": "^0.13.6-next.0",
|
|
38
|
+
"@backstage/cli": "^0.17.2-next.0"
|
|
38
39
|
},
|
|
39
40
|
"files": [
|
|
40
41
|
"dist"
|
|
41
42
|
],
|
|
42
|
-
"gitHead": "
|
|
43
|
+
"gitHead": "c1511c99a532aeb003a97510a5638bd939ee65ca"
|
|
43
44
|
}
|