Skip to content

Commit 38ca18d

Browse files
committed
Log search results to the console for now
1 parent 9798444 commit 38ca18d

File tree

7 files changed

+115
-21
lines changed

7 files changed

+115
-21
lines changed

addon/components/docs-viewer/x-nav/component.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { computed } from '@ember/object';
22
import { inject as service } from '@ember/service';
3+
import { debounce } from '@ember/runloop';
34
import Component from '@ember/component';
45
import layout from './template';
56

@@ -19,7 +20,21 @@ export default Component.extend({
1920

2021
init() {
2122
this._super();
23+
24+
// Start downloading the search index immediately
2225
this.get('docsSearch').loadSearchIndex();
26+
},
27+
28+
search(text) {
29+
if (text.trim().length) {
30+
this.get('docsSearch').searchAndLog(text);
31+
}
32+
},
33+
34+
actions: {
35+
search(text) {
36+
debounce(this, 'search', text, 250);
37+
}
2338
}
2439

2540
// didInsertElement() {

addon/components/docs-viewer/x-nav/template.hbs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<div class="docs-viewer__nav-search">
2-
<input type="text" placeholder="Type to search">
2+
<input type="text" placeholder="Type to search" oninput={{action 'search' value='target.value'}}>
33
</div>
44

55
{{#docs-viewer/x-nav-list}}

addon/components/sample-component/component.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import layout from './template';
44
/**
55
Pretty cool component, right?
66
7-
Here's how you'd use it:
7+
To use it, you could enter the following in your template:
88
99
```handlebars
1010
{{sample-component foo='bar'}}

addon/services/docs-search.js

Lines changed: 78 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,80 @@
11
import Service from '@ember/service';
22
import { getOwner } from '@ember/application';
33
import { computed } from '@ember/object';
4+
import { resolve } from 'rsvp';
45
import $ from 'jquery';
56
import lunr from 'lunr';
67

7-
export default Service.extend({
8-
search(phrase, { exact = false } = {}) {
9-
if (!exact) {
10-
phrase = `*${phrase}*`;
11-
}
8+
const { Index, Query } = lunr;
129

10+
export default Service.extend({
11+
search(phrase) {
1312
return this.loadSearchIndex()
1413
.then(({ index, documents }) => {
15-
return index.search(phrase).map(resultInfo => {
14+
let words = phrase.split(/\s+/);
15+
let results = index.query((query) => {
16+
// In the future we could boost results based on the field they come from
17+
for (let word of words) {
18+
query.term(index.pipeline.runString(word)[0], {
19+
wildcard: Query.wildcard.LEADING | Query.wildcard.TRAILING
20+
});
21+
}
22+
})
23+
24+
return results.map(resultInfo => {
1625
let document = documents[resultInfo.ref];
1726
return { resultInfo, document };
1827
});
1928
});
2029
},
2130

31+
// temporary; just useful for tuning search config for now
32+
searchAndLog(phrase) {
33+
/* eslint-disable no-console */
34+
this.search(phrase)
35+
.then(results => {
36+
console.group(`Search For '${phrase}'`);
37+
for (let result of results) {
38+
let doc = result.document;
39+
if (doc.type === 'class') {
40+
console.groupCollapsed(`Class: %c${doc.title}`, 'font-family: monospace');
41+
for (let match of Object.values(result.resultInfo.matchData.metadata)) {
42+
for (let [key, data] of Object.entries(match)) {
43+
if (key === 'keywords') {
44+
for (let position of data.position) {
45+
console.log(`%c${extractKeyword(doc.keywords, position)} %c(field)`, 'font-family: monospace', 'font-family: inherit');
46+
}
47+
} else {
48+
for (let position of data.position) {
49+
logSnippet(doc, key, position);
50+
}
51+
}
52+
}
53+
}
54+
console.groupEnd();
55+
} else if (doc.type === 'template') {
56+
console.groupCollapsed(`Route: %c${doc.route}`, 'font-family: monospace');
57+
for (let match of Object.values(result.resultInfo.matchData.metadata)) {
58+
for (let [key, data] of Object.entries(match)) {
59+
for (let position of data.position) {
60+
logSnippet(doc, key, position);
61+
}
62+
}
63+
}
64+
console.groupEnd();
65+
}
66+
}
67+
console.groupEnd();
68+
});
69+
/* eslint-enable */
70+
},
71+
2272
loadSearchIndex() {
2373
if (!this._searchIndex) {
24-
this._searchIndex = $.get(this.get('_indexURL'))
74+
this._searchIndex = resolve($.get(this.get('_indexURL')))
2575
.then(json => {
2676
return {
27-
index: lunr.Index.load(json.index),
77+
index: Index.load(json.index),
2878
documents: json.documents
2979
};
3080
});
@@ -38,3 +88,23 @@ export default Service.extend({
3888
return `${config.rootURL}ember-cli-addon-docs/search-index.json`;
3989
})
4090
});
91+
92+
function extractKeyword(keywords, position) {
93+
let start = keywords.lastIndexOf('\0', position[0]);
94+
start = start === -1 ? 0 : start;
95+
let end = keywords.indexOf('\0', position[0] + position[1]);
96+
end = end === -1 ? keywords.length : end;
97+
return keywords.slice(start, end - start);
98+
}
99+
100+
function logSnippet(doc, key, position) {
101+
let field = doc[key];
102+
if (!field) { return; }
103+
104+
let start = Math.max(position[0] - 15, 0);
105+
let end = Math.min(position[0] + position[1] + 15, field.length);
106+
let pre = `${start === 0 ? '' : '...'}${field.slice(start, position[0])}`;
107+
let snippet = field.slice(position[0], position[0] + position[1]);
108+
let post = `${field.slice(position[0] + position[1], end)}${end === field.length ? '' : '...'}`;
109+
console.log(`${pre}%c${snippet}%c${post} (${key})`, 'font-weight: bold', 'font-weight: regular'); // eslint-disable-line no-console
110+
}

lib/broccoli/search-indexer.js

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,12 @@
33
const Writer = require('broccoli-caching-writer');
44
const lunr = require('lunr');
55
const striptags = require('striptags');
6+
const Entities = require('html-entities').AllHtmlEntities;
67
const fs = require('fs-extra');
78
const path = require('path');
89

10+
const htmlEntities = new Entities();
11+
912
module.exports = class SearchIndexCompiler extends Writer {
1013
constructor(input, options) {
1114
super([input]);
@@ -18,14 +21,10 @@ module.exports = class SearchIndexCompiler extends Writer {
1821
let documents = {};
1922
let index = lunr(function() {
2023
this.ref('id');
24+
this.metadataWhitelist = ['position'];
2125

22-
// Document title or class name
2326
this.field('title');
24-
25-
// Document contents or class/field descriptions
2627
this.field('text');
27-
28-
// Class field names or (in the future?) explicit page keywords
2928
this.field('keywords');
3029

3130
for (let doc of writer.buildDocuments()) {
@@ -71,10 +70,10 @@ module.exports = class SearchIndexCompiler extends Writer {
7170
return {
7271
id: `template:${routePath}`,
7372
type: 'template',
74-
title: contents.title,
75-
text: contents.body,
76-
route: routePath,
77-
keywords: [], // TODO allow for specifying keywords
73+
title: normalizeText(contents.title),
74+
text: normalizeText(contents.body),
75+
route: routePath.replace(/\//g, '.'),
76+
keywords: '', // TODO allow for specifying keywords
7877
};
7978
}
8079
}
@@ -97,12 +96,17 @@ module.exports = class SearchIndexCompiler extends Writer {
9796
id: `class:${item.id}`,
9897
type: 'class',
9998
title: item.attributes.name,
100-
text: striptags(item.attributes.description),
101-
keywords: keywords,
99+
text: htmlEntities.decode(striptags(normalizeText(item.attributes.description))),
100+
keywords: keywords.join('\0'),
102101
class: item
103102
};
104103
}
105104
}
106105
}
107106

108107
const POD_TEMPLATE_REGEX = /\/template\.template-contents$/;
108+
109+
function normalizeText(text) {
110+
if (!text) { return text; }
111+
return text.replace(/\s+/g, ' ');
112+
}

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
"git-repo-version": "^0.4.1",
4141
"highlightjs": "^9.10.0",
4242
"hosted-git-info": "^2.5.0",
43+
"html-entities": "^1.2.1",
4344
"inflected": "^2.0.2",
4445
"lunr": "^2.1.4",
4546
"marked": "^0.3.6",

yarn.lock

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4229,6 +4229,10 @@ hosted-git-info@^2.1.4, hosted-git-info@^2.1.5, hosted-git-info@^2.5.0:
42294229
version "2.5.0"
42304230
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.5.0.tgz#6d60e34b3abbc8313062c3b798ef8d901a07af3c"
42314231

4232+
html-entities@^1.2.1:
4233+
version "1.2.1"
4234+
resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.2.1.tgz#0df29351f0721163515dfb9e5543e5f6eed5162f"
4235+
42324236
htmlparser2@~3.8.1:
42334237
version "3.8.3"
42344238
resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.8.3.tgz#996c28b191516a8be86501a7d79757e5c70c1068"

0 commit comments

Comments
 (0)