1 | import * as Handlebars from 'handlebars';
|
2 | import * as path from 'path';
|
3 |
|
4 | import { decode } from 'html-entities';
|
5 |
|
6 | import { MAX_SIZE_FILE_CHEERIO_PARSING, MAX_SIZE_FILE_SEARCH_INDEX } from '../../utils/constants';
|
7 |
|
8 | import { logger } from '../../utils/logger';
|
9 | import Configuration from '../configuration';
|
10 | import FileEngine from './file.engine';
|
11 |
|
12 | const lunr: any = require('lunr');
|
13 | const cheerio: any = require('cheerio');
|
14 |
|
15 | export class SearchEngine {
|
16 | public searchIndex: any;
|
17 | private searchDocuments = [];
|
18 | public documentsStore: Object = {};
|
19 | public indexSize: number;
|
20 | public amountOfMemory = 0;
|
21 |
|
22 | private static instance: SearchEngine;
|
23 | private constructor() {}
|
24 | public static getInstance() {
|
25 | if (!SearchEngine.instance) {
|
26 | SearchEngine.instance = new SearchEngine();
|
27 | }
|
28 | return SearchEngine.instance;
|
29 | }
|
30 |
|
31 | public indexPage(page) {
|
32 | let text;
|
33 | this.amountOfMemory += page.rawData.length;
|
34 | if (this.amountOfMemory < MAX_SIZE_FILE_CHEERIO_PARSING) {
|
35 | let indexStartContent = page.rawData.indexOf('<!-- START CONTENT -->');
|
36 | let indexEndContent = page.rawData.indexOf('<!-- END CONTENT -->');
|
37 |
|
38 | let $ = cheerio.load(page.rawData.substring(indexStartContent + 1, indexEndContent));
|
39 |
|
40 | text = $('.content').html();
|
41 | text = decode(text);
|
42 | text = text.replace(/(<([^>]+)>)/gi, '');
|
43 |
|
44 | page.url = page.url.replace(Configuration.mainData.output, '');
|
45 |
|
46 | let doc = {
|
47 | url: page.url,
|
48 | title: page.infos.context + ' - ' + page.infos.name,
|
49 | body: text
|
50 | };
|
51 |
|
52 | if (
|
53 | !this.documentsStore.hasOwnProperty(doc.url) &&
|
54 | doc.body.length < MAX_SIZE_FILE_SEARCH_INDEX
|
55 | ) {
|
56 | this.documentsStore[doc.url] = doc;
|
57 | this.searchDocuments.push(doc);
|
58 | }
|
59 | }
|
60 | }
|
61 |
|
62 | public generateSearchIndexJson(outputFolder: string): Promise<void> {
|
63 | let that = this;
|
64 | let searchIndex = lunr(function () {
|
65 |
|
66 | this.ref('url');
|
67 | this.field('title');
|
68 | this.field('body');
|
69 | this.pipeline.remove(lunr.stemmer);
|
70 |
|
71 | let i = 0;
|
72 | let len = that.searchDocuments.length;
|
73 | for (i; i < len; i++) {
|
74 | this.add(that.searchDocuments[i]);
|
75 | }
|
76 | });
|
77 | return FileEngine.get(__dirname + '/../src/templates/partials/search-index.hbs').then(
|
78 | data => {
|
79 | let template: any = Handlebars.compile(data);
|
80 | let result = template({
|
81 | index: JSON.stringify(searchIndex),
|
82 | store: JSON.stringify(this.documentsStore)
|
83 | });
|
84 | let testOutputDir = outputFolder.match(process.cwd());
|
85 | if (testOutputDir && testOutputDir.length > 0) {
|
86 | outputFolder = outputFolder.replace(process.cwd() + path.sep, '');
|
87 | }
|
88 |
|
89 | return FileEngine.write(
|
90 | outputFolder + path.sep + '/js/search/search_index.js',
|
91 | result
|
92 | ).catch(err => {
|
93 | logger.error('Error during search index file generation ', err);
|
94 | return Promise.reject(err);
|
95 | });
|
96 | },
|
97 | err => Promise.reject('Error during search index generation')
|
98 | );
|
99 | }
|
100 | }
|
101 |
|
102 | export default SearchEngine.getInstance();
|