@farm.js/search 0.1.0-beta.1 → 0.1.0-beta.2
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/build.d.ts +2 -0
- package/dist/build.d.ts.map +1 -1
- package/dist/build.js +29 -18
- package/dist/client-runtime.d.ts.map +1 -1
- package/dist/client-runtime.js +89 -32
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -0
- package/package.json +2 -2
package/dist/build.d.ts
CHANGED
|
@@ -4,6 +4,8 @@ export interface SearchBuildInput {
|
|
|
4
4
|
publicDir?: string;
|
|
5
5
|
preset: string;
|
|
6
6
|
basePath: string;
|
|
7
|
+
/** Prefix already present in emitted HTML paths (localized Farm SSG output). */
|
|
8
|
+
htmlBasePath?: string;
|
|
7
9
|
options: ResolvedSearchOptions;
|
|
8
10
|
}
|
|
9
11
|
export interface SearchBuildResult {
|
package/dist/build.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../src/build.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAEzD,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,qBAAqB,CAAC;CAChC;AAED,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,aAAa,EAAE,MAAM,EAAE,CAAC;CACzB;AAED,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,iBAAiB,CAAC,
|
|
1
|
+
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../src/build.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAEzD,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,gFAAgF;IAChF,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,qBAAqB,CAAC;CAChC;AAED,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,aAAa,EAAE,MAAM,EAAE,CAAC;CACzB;AAED,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAmF1F;AAED,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAKhF;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAGnE;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAKpE;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAKrE;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAKtD;AAYD,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAwB3E"}
|
package/dist/build.js
CHANGED
|
@@ -11,13 +11,13 @@ export async function writeSearchIndex(input) {
|
|
|
11
11
|
const routes = htmlFiles
|
|
12
12
|
.map((file) => ({
|
|
13
13
|
file,
|
|
14
|
-
logicalRoute: stripBasePath(routeFromHtmlFile(path.relative(publicDir, file)),
|
|
14
|
+
logicalRoute: stripBasePath(routeFromHtmlFile(path.relative(publicDir, file)), input.htmlBasePath ?? "/"),
|
|
15
15
|
}))
|
|
16
16
|
.sort((left, right) => left.logicalRoute.localeCompare(right.logicalRoute));
|
|
17
17
|
const selected = routes.filter(({ logicalRoute }) => shouldIndexRoute(logicalRoute, input.options));
|
|
18
18
|
const skippedRoutes = routes
|
|
19
19
|
.filter(({ logicalRoute }) => !shouldIndexRoute(logicalRoute, input.options))
|
|
20
|
-
.map(({ logicalRoute }) =>
|
|
20
|
+
.map(({ logicalRoute }) => toResultUrl(logicalRoute, basePath));
|
|
21
21
|
if (selected.length === 0) {
|
|
22
22
|
throw new Error("[farm:search] No static HTML pages matched the configured routes. " +
|
|
23
23
|
"Mark searchable pages as static or update search include/exclude patterns.");
|
|
@@ -43,7 +43,7 @@ export async function writeSearchIndex(input) {
|
|
|
43
43
|
const indexedRoutes = [];
|
|
44
44
|
try {
|
|
45
45
|
for (const { file, logicalRoute } of selected) {
|
|
46
|
-
const route =
|
|
46
|
+
const route = toResultUrl(logicalRoute, basePath);
|
|
47
47
|
const result = await index.addHTMLFile({
|
|
48
48
|
url: route,
|
|
49
49
|
content: await readFile(file, "utf8"),
|
|
@@ -87,9 +87,6 @@ export function withBasePath(route, basePath) {
|
|
|
87
87
|
const normalizedRoute = route === "/" ? "/" : `/${route.replace(/^\/+|\/+$/g, "")}`;
|
|
88
88
|
if (normalizedBase === "/")
|
|
89
89
|
return normalizedRoute;
|
|
90
|
-
if (normalizedRoute === normalizedBase || normalizedRoute.startsWith(`${normalizedBase}/`)) {
|
|
91
|
-
return normalizedRoute;
|
|
92
|
-
}
|
|
93
90
|
return normalizedRoute === "/" ? normalizedBase : `${normalizedBase}${normalizedRoute}`;
|
|
94
91
|
}
|
|
95
92
|
export function stripBasePath(route, basePath) {
|
|
@@ -106,20 +103,31 @@ export function routeFromHtmlFile(file) {
|
|
|
106
103
|
const route = withoutIndex ? withoutIndex.replace(/\.html$/i, "").replace(/^\/+|\/+$/g, "") : "";
|
|
107
104
|
return route ? `/${route}` : "/";
|
|
108
105
|
}
|
|
106
|
+
function toResultUrl(route, basePath) {
|
|
107
|
+
// Routes came from decoded filesystem names. Encode each segment once, after
|
|
108
|
+
// filtering and removing any explicit HTML prefix; basePath is already a URL path.
|
|
109
|
+
const pathname = route
|
|
110
|
+
.split("/")
|
|
111
|
+
.map((segment) => encodeURIComponent(segment))
|
|
112
|
+
.join("/");
|
|
113
|
+
return withBasePath(pathname, basePath);
|
|
114
|
+
}
|
|
109
115
|
export function matchesRoutePattern(route, pattern) {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
return route === parent || route.startsWith(parent === "/" ? "/" : `${parent}/`);
|
|
113
|
-
}
|
|
116
|
+
const descendants = pattern.endsWith("/**");
|
|
117
|
+
const parentPattern = descendants ? pattern.slice(0, -3) : pattern;
|
|
114
118
|
let source = "";
|
|
115
|
-
for (let index = 0; index <
|
|
116
|
-
const character =
|
|
117
|
-
if (character === "*"
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
119
|
+
for (let index = 0; index < parentPattern.length; index++) {
|
|
120
|
+
const character = parentPattern[index];
|
|
121
|
+
if (character === "*") {
|
|
122
|
+
// Collapse the whole run. Emitting one `.*` per adjacent pair turned
|
|
123
|
+
// `****` into `.*.*`, and each extra pair multiplied the ways a failing
|
|
124
|
+
// route could be split between them, so a pattern with a handful of
|
|
125
|
+
// consecutive stars hung the build instead of matching.
|
|
126
|
+
let run = 1;
|
|
127
|
+
while (parentPattern[index + run] === "*")
|
|
128
|
+
run++;
|
|
129
|
+
source += run > 1 ? ".*" : "[^/]*";
|
|
130
|
+
index += run - 1;
|
|
123
131
|
}
|
|
124
132
|
else if (character === "?") {
|
|
125
133
|
source += "[^/]";
|
|
@@ -128,6 +136,9 @@ export function matchesRoutePattern(route, pattern) {
|
|
|
128
136
|
source += character.replace(/[|\\{}()[\]^$+?.]/g, "\\$&");
|
|
129
137
|
}
|
|
130
138
|
}
|
|
139
|
+
// Compile the parent too: a terminal /** must not turn earlier wildcards into literals.
|
|
140
|
+
if (descendants)
|
|
141
|
+
source += parentPattern ? "(?:/.*)?" : "/.*";
|
|
131
142
|
return new RegExp(`^${source}/?$`).test(route);
|
|
132
143
|
}
|
|
133
144
|
function shouldIndexRoute(route, options) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client-runtime.d.ts","sourceRoot":"","sources":["../src/client-runtime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,gBAAgB,EAChB,sBAAsB,EACtB,mBAAmB,EACnB,kBAAkB,EAInB,MAAM,YAAY,CAAC;AAEpB,UAAU,sBAAsB;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAClC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,WAAW,EAAE,KAAK,CAAC;QACjB,KAAK,EAAE,MAAM,CAAC;QACd,GAAG,EAAE,MAAM,CAAC;QACZ,OAAO,EAAE,MAAM,CAAC;QAChB,aAAa,EAAE,MAAM,CAAC;KACvB,CAAC,CAAC;CACJ;AAED,UAAU,oBAAoB;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,IAAI,IAAI,OAAO,CAAC,sBAAsB,CAAC,CAAC;CACzC;AAED,UAAU,sBAAsB;IAC9B,OAAO,EAAE,oBAAoB,EAAE,CAAC;IAChC,qBAAqB,EAAE,MAAM,CAAC;IAC9B,OAAO,EAAE,kBAAkB,CAAC;IAC5B,YAAY,EAAE,kBAAkB,CAAC;IACjC,OAAO,EACH;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAClD,KAAK,CAAC;QACJ,OAAO,EAAE,MAAM,CAAC;QAChB,MAAM,EAAE,MAAM,CAAC;QACf,KAAK,EAAE,MAAM,CAAC;KACf,CAAC,CAAC;CACR;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzD,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACtB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAAC;IAChG,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxE,OAAO,IAAI,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACvC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B;AAED,MAAM,WAAW,qBAAsB,SAAQ,kBAAkB;IAC/D,cAAc,CAAC,CACb,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,kBAAkB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;CACrD;AAED,MAAM,MAAM,oBAAoB,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,qBAAqB,CAAC,CAAC;AAEnF,wBAAgB,kBAAkB,CAChC,aAAa,EAAE,MAAM,sBAAsB,EAC3C,OAAO,EAAE,mBAAmB,EAC5B,UAAU,EAAE,oBAAoB,GAC/B,gBAAgB,
|
|
1
|
+
{"version":3,"file":"client-runtime.d.ts","sourceRoot":"","sources":["../src/client-runtime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,gBAAgB,EAChB,sBAAsB,EACtB,mBAAmB,EACnB,kBAAkB,EAInB,MAAM,YAAY,CAAC;AAEpB,UAAU,sBAAsB;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAClC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,WAAW,EAAE,KAAK,CAAC;QACjB,KAAK,EAAE,MAAM,CAAC;QACd,GAAG,EAAE,MAAM,CAAC;QACZ,OAAO,EAAE,MAAM,CAAC;QAChB,aAAa,EAAE,MAAM,CAAC;KACvB,CAAC,CAAC;CACJ;AAED,UAAU,oBAAoB;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,IAAI,IAAI,OAAO,CAAC,sBAAsB,CAAC,CAAC;CACzC;AAED,UAAU,sBAAsB;IAC9B,OAAO,EAAE,oBAAoB,EAAE,CAAC;IAChC,qBAAqB,EAAE,MAAM,CAAC;IAC9B,OAAO,EAAE,kBAAkB,CAAC;IAC5B,YAAY,EAAE,kBAAkB,CAAC;IACjC,OAAO,EACH;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAClD,KAAK,CAAC;QACJ,OAAO,EAAE,MAAM,CAAC;QAChB,MAAM,EAAE,MAAM,CAAC;QACf,KAAK,EAAE,MAAM,CAAC;KACf,CAAC,CAAC;CACR;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzD,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACtB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAAC;IAChG,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxE,OAAO,IAAI,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACvC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B;AAED,MAAM,WAAW,qBAAsB,SAAQ,kBAAkB;IAC/D,cAAc,CAAC,CACb,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,kBAAkB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;CACrD;AAED,MAAM,MAAM,oBAAoB,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,qBAAqB,CAAC,CAAC;AAEnF,wBAAgB,kBAAkB,CAChC,aAAa,EAAE,MAAM,sBAAsB,EAC3C,OAAO,EAAE,mBAAmB,EAC5B,UAAU,EAAE,oBAAoB,GAC/B,gBAAgB,CA2JlB"}
|
package/dist/client-runtime.js
CHANGED
|
@@ -1,14 +1,39 @@
|
|
|
1
1
|
export function createSearchClient(resolveConfig, options, loadModule) {
|
|
2
|
-
let
|
|
3
|
-
|
|
2
|
+
let loading;
|
|
3
|
+
/**
|
|
4
|
+
* Stop handing this instance out and destroy it once every in-flight call
|
|
5
|
+
* has released it. Destroying eagerly is the bug this replaces: a
|
|
6
|
+
* bundle-path change or destroy() could tear the engine down under a
|
|
7
|
+
* search(), preload(), or filters() call that had already resolved it.
|
|
8
|
+
*/
|
|
9
|
+
const retire = (instance) => {
|
|
10
|
+
if (!instance.retired) {
|
|
11
|
+
instance.retired = true;
|
|
12
|
+
instance.drained = (async () => {
|
|
13
|
+
if (instance.uses > 0) {
|
|
14
|
+
await new Promise((resolve) => {
|
|
15
|
+
instance.resolveDrained = resolve;
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
await instance.api.destroy();
|
|
19
|
+
})();
|
|
20
|
+
}
|
|
21
|
+
return instance.drained;
|
|
22
|
+
};
|
|
23
|
+
const release = (instance) => {
|
|
24
|
+
instance.uses -= 1;
|
|
25
|
+
if (instance.retired && instance.uses === 0)
|
|
26
|
+
instance.resolveDrained?.();
|
|
27
|
+
};
|
|
28
|
+
const getInstance = async () => {
|
|
4
29
|
const config = resolveConfig();
|
|
5
30
|
if (!config.available && !options.bundlePath) {
|
|
6
31
|
throw new Error("[farm:search] The search index is generated by production builds. " +
|
|
7
32
|
"Run farm build and serve the production output before searching.");
|
|
8
33
|
}
|
|
9
34
|
const bundlePath = normalizeBundlePath(options.bundlePath ?? config.bundlePath);
|
|
10
|
-
if (!
|
|
11
|
-
const
|
|
35
|
+
if (!loading) {
|
|
36
|
+
const attempt = loadModule(`${bundlePath}pagefind.js`)
|
|
12
37
|
.then(async (module) => {
|
|
13
38
|
const highlightParam = options.highlightParam === false
|
|
14
39
|
? undefined
|
|
@@ -22,21 +47,49 @@ export function createSearchClient(resolveConfig, options, loadModule) {
|
|
|
22
47
|
if (!module.createInstance)
|
|
23
48
|
await api.options(pagefindOptions);
|
|
24
49
|
await api.init();
|
|
25
|
-
return { api, bundlePath };
|
|
50
|
+
return { api, bundlePath, uses: 0, retired: false };
|
|
26
51
|
})
|
|
27
52
|
.catch((error) => {
|
|
28
|
-
|
|
53
|
+
if (loading === attempt)
|
|
54
|
+
loading = undefined;
|
|
29
55
|
throw error;
|
|
30
56
|
});
|
|
31
|
-
|
|
57
|
+
loading = attempt;
|
|
32
58
|
}
|
|
33
|
-
const
|
|
59
|
+
const attempt = loading;
|
|
60
|
+
const current = await attempt;
|
|
34
61
|
if (current.bundlePath !== bundlePath) {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
62
|
+
// Only clear our own load: a concurrent caller that noticed the same
|
|
63
|
+
// stale bundle may already have started the replacement.
|
|
64
|
+
if (loading === attempt)
|
|
65
|
+
loading = undefined;
|
|
66
|
+
// Drain the old engine in the background; the swap must not wait for
|
|
67
|
+
// calls that are still finishing against it. Its destroy() failure has
|
|
68
|
+
// no caller to surface to here — an explicit destroy() still reports it.
|
|
69
|
+
void retire(current).catch(() => { });
|
|
70
|
+
return getInstance();
|
|
71
|
+
}
|
|
72
|
+
return current;
|
|
73
|
+
};
|
|
74
|
+
/** Resolve an instance and hold it for the duration of one call. */
|
|
75
|
+
const withApi = async (run) => {
|
|
76
|
+
for (;;) {
|
|
77
|
+
const instance = await getInstance();
|
|
78
|
+
instance.uses += 1;
|
|
79
|
+
if (instance.retired) {
|
|
80
|
+
// Retired between resolving and acquiring; hand it back and take the
|
|
81
|
+
// replacement instead of running against an engine that may already
|
|
82
|
+
// be destroyed.
|
|
83
|
+
release(instance);
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
try {
|
|
87
|
+
return await run(instance.api);
|
|
88
|
+
}
|
|
89
|
+
finally {
|
|
90
|
+
release(instance);
|
|
91
|
+
}
|
|
38
92
|
}
|
|
39
|
-
return current.api;
|
|
40
93
|
};
|
|
41
94
|
return {
|
|
42
95
|
async search(term, queryOptions = {}) {
|
|
@@ -46,36 +99,40 @@ export function createSearchClient(resolveConfig, options, loadModule) {
|
|
|
46
99
|
const limit = normalizePositiveInteger(queryOptions.limit ?? 20, "limit");
|
|
47
100
|
const offset = normalizeOffset(queryOptions.offset ?? 0);
|
|
48
101
|
const pagefindOptions = engineOptions(queryOptions);
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
results
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
102
|
+
// Result fragments load lazily, so the instance stays held until they
|
|
103
|
+
// have loaded too, not just through the initial query.
|
|
104
|
+
return withApi(async (api) => {
|
|
105
|
+
const response = await api.search(term, pagefindOptions);
|
|
106
|
+
const handles = response.results.slice(offset, offset + limit);
|
|
107
|
+
const results = await Promise.all(handles.map(loadResult));
|
|
108
|
+
return {
|
|
109
|
+
results,
|
|
110
|
+
total: response.results.length,
|
|
111
|
+
unfilteredTotal: response.unfilteredResultCount,
|
|
112
|
+
filters: response.filters,
|
|
113
|
+
totalFilters: response.totalFilters,
|
|
114
|
+
timings: combineTimings(response.timings),
|
|
115
|
+
};
|
|
116
|
+
});
|
|
61
117
|
},
|
|
62
118
|
async preload(term, queryOptions = {}) {
|
|
63
119
|
if (typeof term !== "string")
|
|
64
120
|
throw new TypeError("Search preload term must be a string");
|
|
65
121
|
const pagefindOptions = engineOptions(queryOptions);
|
|
66
|
-
|
|
67
|
-
await api.preload(term, pagefindOptions);
|
|
122
|
+
await withApi((api) => api.preload(term, pagefindOptions));
|
|
68
123
|
},
|
|
69
124
|
async filters() {
|
|
70
|
-
|
|
71
|
-
return api.filters();
|
|
125
|
+
return withApi((api) => api.filters());
|
|
72
126
|
},
|
|
73
127
|
async destroy() {
|
|
74
|
-
if (!
|
|
128
|
+
if (!loading)
|
|
75
129
|
return;
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
|
|
130
|
+
const attempt = loading;
|
|
131
|
+
const current = await attempt.catch(() => undefined);
|
|
132
|
+
if (loading === attempt)
|
|
133
|
+
loading = undefined;
|
|
134
|
+
if (current)
|
|
135
|
+
await retire(current);
|
|
79
136
|
},
|
|
80
137
|
};
|
|
81
138
|
}
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAwB,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAGvE,YAAY,EAAE,qBAAqB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACxE,YAAY,EACV,gBAAgB,EAChB,mBAAmB,EACnB,kBAAkB,EAClB,sBAAsB,EACtB,qBAAqB,EACrB,aAAa,EACb,kBAAkB,EAClB,cAAc,EACd,YAAY,EACZ,UAAU,EACV,eAAe,EACf,aAAa,GACd,MAAM,YAAY,CAAC;AAEpB,oEAAoE;AACpE,wBAAgB,MAAM,CAAC,OAAO,GAAE,aAAkB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAwB,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAGvE,YAAY,EAAE,qBAAqB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACxE,YAAY,EACV,gBAAgB,EAChB,mBAAmB,EACnB,kBAAkB,EAClB,sBAAsB,EACtB,qBAAqB,EACrB,aAAa,EACb,kBAAkB,EAClB,cAAc,EACd,YAAY,EACZ,UAAU,EACV,eAAe,EACf,aAAa,GACd,MAAM,YAAY,CAAC;AAEpB,oEAAoE;AACpE,wBAAgB,MAAM,CAAC,OAAO,GAAE,aAAkB,6CAkGjD"}
|
package/dist/index.js
CHANGED
|
@@ -5,6 +5,7 @@ import { resolveSearchOptions } from "./config.js";
|
|
|
5
5
|
export function search(options = {}) {
|
|
6
6
|
const resolved = resolveSearchOptions(options);
|
|
7
7
|
let configuredBasePath = "/";
|
|
8
|
+
let htmlBasePath = "/";
|
|
8
9
|
let generated = false;
|
|
9
10
|
const publicConfig = {
|
|
10
11
|
available: false,
|
|
@@ -20,6 +21,14 @@ export function search(options = {}) {
|
|
|
20
21
|
throw new Error("[farm:search] Configure search in one search() plugin instance");
|
|
21
22
|
}
|
|
22
23
|
configuredBasePath = normalizeBasePath(config.basePath);
|
|
24
|
+
// RouteManager emits ordinary SSG paths relative to the app, while its
|
|
25
|
+
// localized SSG paths already include basePath. Do not infer this from
|
|
26
|
+
// folder names: an application route can have the same name as basePath.
|
|
27
|
+
const i18n = config.i18n;
|
|
28
|
+
htmlBasePath =
|
|
29
|
+
i18n && typeof i18n === "object" && "enabled" in i18n && i18n.enabled
|
|
30
|
+
? configuredBasePath
|
|
31
|
+
: "/";
|
|
23
32
|
publicConfig.bundlePath = `${withBasePath(`/${resolved.output}`, configuredBasePath)}/`;
|
|
24
33
|
},
|
|
25
34
|
build: {
|
|
@@ -37,6 +46,7 @@ export function search(options = {}) {
|
|
|
37
46
|
publicDir: nitroConfig.output?.publicDir,
|
|
38
47
|
preset: nitroConfig.preset ?? "node-server",
|
|
39
48
|
basePath: configuredBasePath,
|
|
49
|
+
htmlBasePath,
|
|
40
50
|
options: resolved,
|
|
41
51
|
});
|
|
42
52
|
generated = true;
|
|
@@ -60,6 +70,7 @@ export function search(options = {}) {
|
|
|
60
70
|
outputDir: result.outputDir ?? `${result.root}/.farm/.output`,
|
|
61
71
|
preset: result.preset,
|
|
62
72
|
basePath: configuredBasePath,
|
|
73
|
+
htmlBasePath,
|
|
63
74
|
options: resolved,
|
|
64
75
|
});
|
|
65
76
|
generated = true;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@farm.js/search",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.2",
|
|
4
4
|
"description": "Build-time static page search for Farm.js applications",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"farm.js",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
39
|
"pagefind": "^1.5.2",
|
|
40
|
-
"@farm.js/core": "0.1.0-beta.
|
|
40
|
+
"@farm.js/core": "0.1.0-beta.105"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@types/node": "^20.10.5",
|