@easyops-cn/docusaurus-search-local 0.29.2 → 0.30.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 +21 -0
- package/dist/client/client/theme/SearchBar/SearchBar.jsx +4 -0
- package/dist/client/client/theme/SearchBar/SearchBar.module.css +1 -0
- package/dist/client/client/theme/SearchBar/fetchIndexes.js +2 -2
- package/dist/client/client/utils/__mocks__/proxiedGenerated.js +1 -1
- package/dist/client/client/utils/highlightStemmed.js +33 -32
- package/dist/client/client/utils/looseTokenize.js +2 -2
- package/dist/server/server/index.js +2 -2
- package/dist/server/server/utils/generate.js +13 -1
- package/dist/server/server/utils/getCondensedText.js +3 -0
- package/dist/server/server/utils/postBuildFactory.js +2 -2
- package/dist/server/server/utils/validateOptions.js +2 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,27 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
## [0.30.0](https://github.com/easyops-cn/docusaurus-search-local/compare/v0.29.4...v0.30.0) (2022-07-22)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* support saving hash in filename instead of query ([4930a88](https://github.com/easyops-cn/docusaurus-search-local/commit/4930a88779813ffcaa932a56f786066f969aff6e)), closes [#171](https://github.com/easyops-cn/docusaurus-search-local/issues/171)
|
|
11
|
+
|
|
12
|
+
## [0.29.4](https://github.com/easyops-cn/docusaurus-search-local/compare/v0.29.3...v0.29.4) (2022-07-22)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### Bug Fixes
|
|
16
|
+
|
|
17
|
+
* fix call stack overflow with large code blocks ([e0b2cfd](https://github.com/easyops-cn/docusaurus-search-local/commit/e0b2cfd6e21f008609a85c42c0159ae25b575d6b)), closes [#164](https://github.com/easyops-cn/docusaurus-search-local/issues/164)
|
|
18
|
+
|
|
19
|
+
## [0.29.3](https://github.com/easyops-cn/docusaurus-search-local/compare/v0.29.2...v0.29.3) (2022-07-20)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
### Bug Fixes
|
|
23
|
+
|
|
24
|
+
* hide clear button on small screen when input is not focused ([c69fbf6](https://github.com/easyops-cn/docusaurus-search-local/commit/c69fbf64ff6ba11c32e63d89dada010bb1e521dc)), closes [#230](https://github.com/easyops-cn/docusaurus-search-local/issues/230)
|
|
25
|
+
|
|
5
26
|
## [0.29.2](https://github.com/easyops-cn/docusaurus-search-local/compare/v0.29.1...v0.29.2) (2022-07-19)
|
|
6
27
|
|
|
7
28
|
|
|
@@ -178,12 +178,15 @@ export default function SearchBar({ handleSearchBarToggle, }) {
|
|
|
178
178
|
search.current?.autocomplete.setVal(keywords.join(" "));
|
|
179
179
|
});
|
|
180
180
|
}, [location.search, location.pathname]);
|
|
181
|
+
const [focused, setFocused] = useState(false);
|
|
181
182
|
const onInputFocus = useCallback(() => {
|
|
182
183
|
focusAfterIndexLoaded.current = true;
|
|
183
184
|
loadIndex();
|
|
185
|
+
setFocused(true);
|
|
184
186
|
handleSearchBarToggle?.(true);
|
|
185
187
|
}, [handleSearchBarToggle, loadIndex]);
|
|
186
188
|
const onInputBlur = useCallback(() => {
|
|
189
|
+
setFocused(false);
|
|
187
190
|
handleSearchBarToggle?.(false);
|
|
188
191
|
}, [handleSearchBarToggle]);
|
|
189
192
|
const onInputMouseEnter = useCallback(() => {
|
|
@@ -232,6 +235,7 @@ export default function SearchBar({ handleSearchBarToggle, }) {
|
|
|
232
235
|
}, [location.pathname, location.search, location.hash, history]);
|
|
233
236
|
return (<div className={clsx("navbar__search", styles.searchBarContainer, {
|
|
234
237
|
[styles.searchIndexLoading]: loading && inputChanged,
|
|
238
|
+
[styles.focused]: focused,
|
|
235
239
|
})}>
|
|
236
240
|
<input placeholder={translate({
|
|
237
241
|
id: "theme.SearchBar.label",
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import lunr from "lunr";
|
|
2
|
-
import {
|
|
2
|
+
import { searchIndexUrl } from "../../utils/proxiedGenerated";
|
|
3
3
|
export async function fetchIndexes(baseUrl) {
|
|
4
4
|
if (process.env.NODE_ENV === "production") {
|
|
5
|
-
const json = (await (await fetch(`${baseUrl}
|
|
5
|
+
const json = (await (await fetch(`${baseUrl}${searchIndexUrl}`)).json());
|
|
6
6
|
const wrappedIndexes = json.map(({ documents, index }, type) => ({
|
|
7
7
|
type: type,
|
|
8
8
|
documents,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export let language = ["en", "zh"];
|
|
2
2
|
export let removeDefaultStopWordFilter = false;
|
|
3
3
|
export let removeDefaultStemmer = false;
|
|
4
|
-
export const
|
|
4
|
+
export const searchIndexUrl = "search-index.json?_=abc";
|
|
5
5
|
export const searchResultLimits = 8;
|
|
6
6
|
export const searchResultContextMaxLength = 50;
|
|
7
7
|
export const explicitSearchResultPath = false;
|
|
@@ -3,14 +3,11 @@ import { highlight } from "./highlight";
|
|
|
3
3
|
import { looseTokenize } from "./looseTokenize";
|
|
4
4
|
import { searchResultContextMaxLength } from "./proxiedGenerated";
|
|
5
5
|
export function highlightStemmed(content, positions, tokens, maxLength = searchResultContextMaxLength) {
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const chunks = splitIntoChunks(content, positions, tokens, 0, 0, chunkIndexRef);
|
|
10
|
-
const leadingChunks = chunks.slice(0, chunkIndexRef.chunkIndex);
|
|
11
|
-
const firstChunk = chunks[chunkIndexRef.chunkIndex];
|
|
6
|
+
const { chunkIndex, chunks } = splitIntoChunks(content, positions, tokens);
|
|
7
|
+
const leadingChunks = chunks.slice(0, chunkIndex);
|
|
8
|
+
const firstChunk = chunks[chunkIndex];
|
|
12
9
|
const html = [firstChunk.html];
|
|
13
|
-
const trailingChunks = chunks.slice(
|
|
10
|
+
const trailingChunks = chunks.slice(chunkIndex + 1);
|
|
14
11
|
let currentLength = firstChunk.textLength;
|
|
15
12
|
let leftPadding = 0;
|
|
16
13
|
let rightPadding = 0;
|
|
@@ -54,42 +51,46 @@ export function highlightStemmed(content, positions, tokens, maxLength = searchR
|
|
|
54
51
|
}
|
|
55
52
|
return html.join("");
|
|
56
53
|
}
|
|
57
|
-
export function splitIntoChunks(content, positions, tokens
|
|
54
|
+
export function splitIntoChunks(content, positions, tokens) {
|
|
58
55
|
const chunks = [];
|
|
59
|
-
|
|
60
|
-
|
|
56
|
+
let positionIndex = 0;
|
|
57
|
+
let cursor = 0;
|
|
58
|
+
let chunkIndex = -1;
|
|
59
|
+
while (positionIndex < positions.length) {
|
|
60
|
+
const [start, length] = positions[positionIndex];
|
|
61
61
|
positionIndex += 1;
|
|
62
|
-
if (
|
|
63
|
-
|
|
62
|
+
if (start < cursor) {
|
|
63
|
+
continue;
|
|
64
64
|
}
|
|
65
|
-
}
|
|
66
|
-
else {
|
|
67
65
|
if (start > cursor) {
|
|
68
|
-
|
|
66
|
+
const leadingChunks = looseTokenize(content.substring(cursor, start)).map((token) => ({
|
|
69
67
|
html: escapeHtml(token),
|
|
70
68
|
textLength: token.length,
|
|
71
|
-
}))
|
|
69
|
+
}));
|
|
70
|
+
for (const item of leadingChunks) {
|
|
71
|
+
chunks.push(item);
|
|
72
|
+
}
|
|
72
73
|
}
|
|
73
|
-
if (
|
|
74
|
-
|
|
74
|
+
if (chunkIndex === -1) {
|
|
75
|
+
chunkIndex = chunks.length;
|
|
75
76
|
}
|
|
77
|
+
cursor = start + length;
|
|
76
78
|
chunks.push({
|
|
77
|
-
html: highlight(content.
|
|
79
|
+
html: highlight(content.substring(start, cursor), tokens, true),
|
|
78
80
|
textLength: length,
|
|
79
81
|
});
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
html: escapeHtml(token),
|
|
89
|
-
textLength: token.length,
|
|
90
|
-
})));
|
|
91
|
-
}
|
|
82
|
+
}
|
|
83
|
+
if (cursor < content.length) {
|
|
84
|
+
const trailingChunks = looseTokenize(content.substring(cursor)).map((token) => ({
|
|
85
|
+
html: escapeHtml(token),
|
|
86
|
+
textLength: token.length,
|
|
87
|
+
}));
|
|
88
|
+
for (const item of trailingChunks) {
|
|
89
|
+
chunks.push(item);
|
|
92
90
|
}
|
|
93
91
|
}
|
|
94
|
-
return
|
|
92
|
+
return {
|
|
93
|
+
chunkIndex,
|
|
94
|
+
chunks,
|
|
95
|
+
};
|
|
95
96
|
}
|
|
@@ -11,11 +11,11 @@ export function looseTokenize(content) {
|
|
|
11
11
|
break;
|
|
12
12
|
}
|
|
13
13
|
if (match.index > 0) {
|
|
14
|
-
tokens.push(text.
|
|
14
|
+
tokens.push(text.substring(0, match.index));
|
|
15
15
|
}
|
|
16
16
|
tokens.push(match[0]);
|
|
17
17
|
start += match.index + match[0].length;
|
|
18
|
-
text = content.
|
|
18
|
+
text = content.substring(start);
|
|
19
19
|
}
|
|
20
20
|
return tokens;
|
|
21
21
|
}
|
|
@@ -14,7 +14,7 @@ function DocusaurusSearchLocalPlugin(context, options) {
|
|
|
14
14
|
const config = (0, processPluginOptions_1.processPluginOptions)(options, context.siteDir);
|
|
15
15
|
const dir = path_1.default.join(context.generatedFilesDir, PLUGIN_NAME, "default");
|
|
16
16
|
fs_extra_1.default.ensureDirSync(dir);
|
|
17
|
-
(0, generate_1.generate)(config, dir);
|
|
17
|
+
const searchIndexFilename = (0, generate_1.generate)(config, dir);
|
|
18
18
|
const themePath = path_1.default.resolve(__dirname, "../../client/client/theme");
|
|
19
19
|
const pagePath = path_1.default.join(themePath, "SearchPage/index.js");
|
|
20
20
|
return {
|
|
@@ -22,7 +22,7 @@ function DocusaurusSearchLocalPlugin(context, options) {
|
|
|
22
22
|
getThemePath() {
|
|
23
23
|
return themePath;
|
|
24
24
|
},
|
|
25
|
-
postBuild: (0, postBuildFactory_1.postBuildFactory)(config),
|
|
25
|
+
postBuild: (0, postBuildFactory_1.postBuildFactory)(config, searchIndexFilename),
|
|
26
26
|
getPathsToWatch() {
|
|
27
27
|
return [pagePath];
|
|
28
28
|
},
|
|
@@ -35,7 +35,18 @@ function generate(config, dir) {
|
|
|
35
35
|
else {
|
|
36
36
|
contents.push("export const Mark = null;");
|
|
37
37
|
}
|
|
38
|
-
|
|
38
|
+
let searchIndexFilename = "search-index.json";
|
|
39
|
+
let searchIndexQuery = "";
|
|
40
|
+
if (indexHash) {
|
|
41
|
+
if (config.hashed === "filename") {
|
|
42
|
+
searchIndexFilename = `search-index-${indexHash}.json`;
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
searchIndexQuery = `?_=${indexHash}`;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
const searchIndexUrl = searchIndexFilename + searchIndexQuery;
|
|
49
|
+
contents.push(`export const searchIndexUrl = ${JSON.stringify(searchIndexUrl)};`);
|
|
39
50
|
contents.push(`export const searchResultLimits = ${JSON.stringify(searchResultLimits)};`, `export const searchResultContextMaxLength = ${JSON.stringify(searchResultContextMaxLength)};`);
|
|
40
51
|
contents.push(`export const explicitSearchResultPath = ${JSON.stringify(explicitSearchResultPath)};`);
|
|
41
52
|
contents.push(`export const searchBarShortcut = ${JSON.stringify(searchBarShortcut)};`);
|
|
@@ -44,5 +55,6 @@ function generate(config, dir) {
|
|
|
44
55
|
? "undefined"
|
|
45
56
|
: JSON.stringify(docsPluginIdForPreferredVersion)};`);
|
|
46
57
|
fs_1.default.writeFileSync(path_1.default.join(dir, "generated.js"), contents.join("\n"));
|
|
58
|
+
return searchIndexFilename;
|
|
47
59
|
}
|
|
48
60
|
exports.generate = generate;
|
|
@@ -50,6 +50,9 @@ function getCondensedText(element, $) {
|
|
|
50
50
|
return element.data;
|
|
51
51
|
}
|
|
52
52
|
if (element.type === "tag") {
|
|
53
|
+
if (element.name === "br") {
|
|
54
|
+
return " ";
|
|
55
|
+
}
|
|
53
56
|
const content = getText($(element).contents().get());
|
|
54
57
|
if (BLOCK_TAGS.has(element.name)) {
|
|
55
58
|
return " " + content + " ";
|
|
@@ -10,7 +10,7 @@ const debug_1 = require("./debug");
|
|
|
10
10
|
const processDocInfos_1 = require("./processDocInfos");
|
|
11
11
|
const scanDocuments_1 = require("./scanDocuments");
|
|
12
12
|
const writeFileAsync = util_1.default.promisify(fs_1.default.writeFile);
|
|
13
|
-
function postBuildFactory(config) {
|
|
13
|
+
function postBuildFactory(config, searchIndexFilename) {
|
|
14
14
|
return function postBuild(buildData) {
|
|
15
15
|
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
16
16
|
(0, debug_1.debugInfo)("gathering documents");
|
|
@@ -22,7 +22,7 @@ function postBuildFactory(config) {
|
|
|
22
22
|
(0, debug_1.debugInfo)("building index");
|
|
23
23
|
const searchIndex = (0, buildIndex_1.buildIndex)(allDocuments, config);
|
|
24
24
|
(0, debug_1.debugInfo)("writing index to disk");
|
|
25
|
-
yield writeFileAsync(path_1.default.join(versionData.outDir,
|
|
25
|
+
yield writeFileAsync(path_1.default.join(versionData.outDir, searchIndexFilename), JSON.stringify(searchIndex), { encoding: "utf8" });
|
|
26
26
|
(0, debug_1.debugInfo)("index written to disk successfully!");
|
|
27
27
|
}
|
|
28
28
|
});
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.validateOptions = void 0;
|
|
4
4
|
const utils_validation_1 = require("@docusaurus/utils-validation");
|
|
5
5
|
const isStringOrArrayOfStrings = utils_validation_1.Joi.alternatives().try(utils_validation_1.Joi.string(), utils_validation_1.Joi.array().items(utils_validation_1.Joi.string()));
|
|
6
|
+
const isBooleanOrString = utils_validation_1.Joi.alternatives().try(utils_validation_1.Joi.boolean(), utils_validation_1.Joi.string());
|
|
6
7
|
const isArrayOfStringsOrRegExpsOrStringOrRegExp = utils_validation_1.Joi.alternatives().try(utils_validation_1.Joi.array().items(utils_validation_1.Joi.alternatives().try(utils_validation_1.Joi.string(), utils_validation_1.Joi.object().regex())), utils_validation_1.Joi.string(), utils_validation_1.Joi.object().regex());
|
|
7
8
|
const schema = utils_validation_1.Joi.object({
|
|
8
9
|
indexDocs: utils_validation_1.Joi.boolean().default(true),
|
|
@@ -11,7 +12,7 @@ const schema = utils_validation_1.Joi.object({
|
|
|
11
12
|
docsRouteBasePath: isStringOrArrayOfStrings.default(["docs"]),
|
|
12
13
|
blogRouteBasePath: isStringOrArrayOfStrings.default(["blog"]),
|
|
13
14
|
language: isStringOrArrayOfStrings.default(["en"]),
|
|
14
|
-
hashed:
|
|
15
|
+
hashed: isBooleanOrString.default(false),
|
|
15
16
|
docsDir: isStringOrArrayOfStrings.default(["docs"]),
|
|
16
17
|
blogDir: isStringOrArrayOfStrings.default(["blog"]),
|
|
17
18
|
removeDefaultStopWordFilter: utils_validation_1.Joi.boolean().default(false),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@easyops-cn/docusaurus-search-local",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.30.0",
|
|
4
4
|
"description": "An offline/local search plugin for Docusaurus v2",
|
|
5
5
|
"repository": "https://github.com/easyops-cn/docusaurus-search-local",
|
|
6
6
|
"homepage": "https://github.com/easyops-cn/docusaurus-search-local",
|