Files
ai-agent-book/extras/search-index-router.js
liqiang b119135836
Build latest book artifacts / build (push) Canceled after 0s
dependency resolution / resolve (3.11) (push) Canceled after 0s
dependency resolution / resolve (3.13) (push) Canceled after 0s
deploy-pages / build (push) Canceled after 0s
deploy-pages / deploy (push) Canceled after 0s
i18n consistency check / check (push) Canceled after 0s
provider adoption tests / test (chapter2/context-compression) (push) Canceled after 0s
provider adoption tests / test (chapter2/prompt-injection) (push) Canceled after 0s
provider adoption tests / test (chapter2/system-hint) (push) Canceled after 0s
provider adoption tests / test (chapter3/log-sanitization) (push) Canceled after 0s
web-search-agent tests / test (push) Canceled after 0s
web-search-agent tests / agentbook (push) Canceled after 0s
ai-agent-book 精选快照(<2MB 代码与文档,来自 github.com/bojieli/ai-agent-book)
2026-08-20 13:12:50 +00:00

90 lines
3.6 KiB
JavaScript

// Point Material's search at this edition's slice of the search index.
//
// scripts/split_search_index.py splits the one 55 MB search_index.json the
// search plugin emits into `search/search_index.<slug>.json`, one per book
// edition (slug = the edition's URL directory: `book`, `book-en`, ...), each
// carrying that edition plus the shared experiment pages. This script decides
// which slice the current page needs and rewrites the request for it.
//
// Why an XHR patch rather than configuration: Material builds the index URL
// as `new URL("search/search_index.json", config.base)` and requests it via
// XMLHttpRequest while bundle.js initialises. There is no config seam for the
// path, and `extra_javascript` files load *after* bundle.js — too late. So
// overrides/main.html loads this file inside the `config` block, which base.html
// renders immediately before bundle.js, and we intercept the one request.
//
// If anything here fails to identify an edition we simply leave the URL alone:
// search_index.json still holds the default edition plus the shared pages, so
// search degrades to its previous behaviour rather than breaking.
(function () {
"use strict";
var INDEX_RE = /\/search\/search_index\.json$/;
// `chapterN/README.<readmeSuffix>/` and `index.<code>/` — pages that belong
// to an edition but live outside its book-*/ directory.
var README_RE = /\/chapter\d+\/README\.([A-Za-z-]+)\/?(?:index\.html)?$/;
var HOMEPAGE_RE = /\/index\.([A-Za-z-]+)\/?(?:index\.html)?$/;
// Mirrors edition_of() in scripts/split_search_index.py — keep the two in
// step, or a reader gets an index that omits the edition they are reading.
function slugForPath(path, cfg) {
var code, entry;
// 1. An explicit book-*/ path segment. Exact segment matches only, so the
// `/ai-agent-book/` site subpath can never be mistaken for an edition.
var slugs = {};
for (code in cfg) {
if (cfg.hasOwnProperty(code) && cfg[code].prefix) {
slugs[cfg[code].prefix.replace(/\/$/, "")] = true;
}
}
var segments = path.split("/");
for (var i = 0; i < segments.length; i++) {
if (slugs[segments[i]]) return segments[i];
}
// 2. Translated experiment indexes and homepages, keyed by their suffix.
var match = path.match(README_RE) || path.match(HOMEPAGE_RE);
if (match) {
for (code in cfg) {
if (!cfg.hasOwnProperty(code)) continue;
entry = cfg[code];
if (!entry.prefix) continue;
if (entry.readmeSuffix === match[1] || code === match[1]) {
return entry.prefix.replace(/\/$/, "");
}
}
}
// 3. Language-agnostic pages (the `chapterN/` experiments, the site root).
// Reuse the switcher's remembered locale so a reader who came from an
// edition keeps searching it; lang-switcher.js writes the same key.
var remembered = null;
try {
remembered = sessionStorage.getItem("lang-switcher-active");
} catch (_) {}
if (remembered && cfg[remembered] && cfg[remembered].prefix) {
return cfg[remembered].prefix.replace(/\/$/, "");
}
return null;
}
var cfg = window.LANG_CONFIG;
if (!cfg) return; // header.html emits it before this script; nothing to do.
var slug = slugForPath(location.pathname, cfg);
if (!slug) return;
var open = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function (method, url) {
var args = Array.prototype.slice.call(arguments);
if (typeof url === "string" && INDEX_RE.test(url)) {
args[1] = url.replace(INDEX_RE, "/search/search_index." + slug + ".json");
}
return open.apply(this, args);
};
})();