@ubean/content 0.4.7 → 0.4.9

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/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { _ as SearchSection, a as ContentModuleOptions, b as SectionSearchOptions, c as ContentSchema, d as ContentTocItem, f as ContentType, g as SearchHit, h as ParsedContentMeta, i as ContentFieldSchema, l as ContentSearchOptions, m as MarkdownNode, n as ContentCollection, o as ContentNavigationItem, p as GenerateSearchSectionsOptions, r as ContentDocument, s as ContentQueryBuilder, t as ContentBody, u as ContentSourceConfig, v as SectionQueryOptions, y as SectionSearchEngine } from "./types-B9HP8tUf.js";
1
+ import { _ as SearchSection, a as ContentModuleOptions, b as SectionSearchOptions, c as ContentSchema, d as ContentTocItem, f as ContentType, g as SearchHit, h as ParsedContentMeta, i as ContentFieldSchema, l as ContentSearchOptions, m as MarkdownNode, n as ContentCollection, o as ContentNavigationItem, p as GenerateSearchSectionsOptions, r as ContentDocument, s as ContentQueryBuilder, t as ContentBody, u as ContentSourceConfig, v as SectionQueryOptions, y as SectionSearchEngine } from "./types-DN6hB1zj.js";
2
2
  import ubeanContentPlugin, { UbeanContentOptions } from "./vite.js";
3
- import { S as parseMarkdown, _ as createQueryBuilder, a as getCollection, b as parseContent, c as parseContentFile, d as registerContent, f as ContentSourceScanConfig, g as createContentCollection, h as buildNavigation, i as fetchContentNavigation, l as queryCollection, m as scanContentSources, n as configureContentRuntime, o as getContentItem, p as ScanContentSourcesOptions, r as defineCollection, s as listCollections, t as bootstrapContentFromDisk, u as queryCollectionSearchSections, v as defineContentCollection, x as parseFrontmatter, y as generateId } from "./runtime-DQ65gYP0.js";
3
+ import { S as parseMarkdown, _ as createQueryBuilder, a as getCollection, b as parseContent, c as parseContentFile, d as registerContent, f as ContentSourceScanConfig, g as createContentCollection, h as buildNavigation, i as fetchContentNavigation, l as queryCollection, m as scanContentSources, n as configureContentRuntime, o as getContentItem, p as ScanContentSourcesOptions, r as defineCollection, s as listCollections, t as bootstrapContentFromDisk, u as queryCollectionSearchSections, v as defineContentCollection, x as parseFrontmatter, y as generateId } from "./runtime-w0CWrefy.js";
4
4
  //#region src/search.d.ts
5
5
  /**
6
6
  * 将单个文档按标题层级切分为可搜索的 sections。
@@ -26,8 +26,11 @@ export declare function tokenizeText(text: string): string[];
26
26
  * 创建章节搜索引擎。
27
27
  *
28
28
  * 优先使用 MiniSearch(可选依赖,支持前缀 + 模糊匹配 + 字段加权),
29
- * 未安装时降级为内置 fallback 引擎(精确/前缀匹配)。
29
+ * 未安装/加载失败时降级为内置 fallback 引擎(精确/前缀匹配)。
30
30
  * 两条路径共享 CJK 感知分词器。
31
+ *
32
+ * 浏览器端必须通过 `options.loadMiniSearch` 注入字面量加载器,否则
33
+ * MiniSearch 无法加载(详见该选项文档)。
31
34
  */
32
35
  export declare function createSectionSearch(sections: SearchSection[], options?: SectionSearchOptions): Promise<SectionSearchEngine>;
33
36
  /** 一次性搜索便捷函数(每次调用重建引擎,适合低频场景;高频场景请缓存 `createSectionSearch` 结果) */
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { _ as generateId, a as getCollection, b as parseMarkdown, c as parseContentFile, d as registerContent, f as scanContentSources, g as defineContentCollection, h as createQueryBuilder, i as fetchContentNavigation, l as queryCollection, m as createContentCollection, n as configureContentRuntime, o as getContentItem, p as buildNavigation, r as defineCollection, s as listCollections, t as bootstrapContentFromDisk, u as queryCollectionSearchSections, v as parseContent, y as parseFrontmatter } from "./runtime-Cdi5T8aE.js";
2
- import { a as runPagefindIndex, c as tokenizeText, i as resolveContentSearchConfig, n as generateSearchSections, o as searchSections, r as generateSearchSectionsSnapshot, s as splitDocumentIntoSearchSections, t as createSectionSearch } from "./search-CNUu8Xvf.js";
1
+ import { _ as generateId, a as getCollection, b as parseMarkdown, c as parseContentFile, d as registerContent, f as scanContentSources, g as defineContentCollection, h as createQueryBuilder, i as fetchContentNavigation, l as queryCollection, m as createContentCollection, n as configureContentRuntime, o as getContentItem, p as buildNavigation, r as defineCollection, s as listCollections, t as bootstrapContentFromDisk, u as queryCollectionSearchSections, v as parseContent, y as parseFrontmatter } from "./runtime-DPsviqaI.js";
2
+ import { a as runPagefindIndex, c as tokenizeText, i as resolveContentSearchConfig, n as generateSearchSections, o as searchSections, r as generateSearchSectionsSnapshot, s as splitDocumentIntoSearchSections, t as createSectionSearch } from "./search-C73D12td.js";
3
3
  import ubeanContentPlugin from "./vite.js";
4
4
  //#region src/routing.ts
5
5
  function joinPrefix(prefix, path) {
@@ -1,4 +1,4 @@
1
- import { n as generateSearchSections } from "./search-CNUu8Xvf.js";
1
+ import { n as generateSearchSections } from "./search-C73D12td.js";
2
2
  import { join, relative } from "pathe";
3
3
  import { getBasename, getDirname, getExtension, getStem, normalizePath, pathToTitle } from "@ubean/shared";
4
4
  import { kebabCase } from "scule";
@@ -89,6 +89,8 @@ function parseMarkdown(content) {
89
89
  let foundExcerptSeparator = false;
90
90
  let headingStack = [toc];
91
91
  let headingDepths = [0];
92
+ /** 标题文本 → 已出现次数;重复标题追加 `-n` 后缀,保证锚点/搜索 section id 唯一 */
93
+ const headingIdCounts = /* @__PURE__ */ new Map();
92
94
  for (let i = 0; i < lines.length; i++) {
93
95
  const line = lines[i];
94
96
  if (line.startsWith("```")) {
@@ -130,7 +132,10 @@ function parseMarkdown(content) {
130
132
  flushParagraph();
131
133
  const depth = headingMatch[1].length;
132
134
  const text = headingMatch[2].replace(/[#*_`~[\]]/g, "").trim();
133
- const id = kebabCase(text.replace(/\s+/g, "-"));
135
+ const baseId = kebabCase(text.replace(/\s+/g, "-"));
136
+ const idCount = headingIdCounts.get(baseId) ?? 0;
137
+ headingIdCounts.set(baseId, idCount + 1);
138
+ const id = idCount === 0 ? baseId : `${baseId}-${idCount}`;
134
139
  while (headingDepths[headingDepths.length - 1] >= depth) {
135
140
  headingDepths.pop();
136
141
  headingStack.pop();
@@ -1,4 +1,4 @@
1
- import { _ as SearchSection, a as ContentModuleOptions, c as ContentSchema, n as ContentCollection, o as ContentNavigationItem, p as GenerateSearchSectionsOptions, r as ContentDocument, s as ContentQueryBuilder, t as ContentBody } from "./types-B9HP8tUf.js";
1
+ import { _ as SearchSection, a as ContentModuleOptions, c as ContentSchema, n as ContentCollection, o as ContentNavigationItem, p as GenerateSearchSectionsOptions, r as ContentDocument, s as ContentQueryBuilder, t as ContentBody } from "./types-DN6hB1zj.js";
2
2
  //#region src/core.d.ts
3
3
  declare function generateId(path: string, extension?: string): string;
4
4
  declare function parseFrontmatter(content: string): {
package/dist/runtime.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- import { _ as SearchSection, a as ContentModuleOptions, c as ContentSchema, d as ContentTocItem, f as ContentType, g as SearchHit, l as ContentSearchOptions, m as MarkdownNode, n as ContentCollection, o as ContentNavigationItem, p as GenerateSearchSectionsOptions, r as ContentDocument, s as ContentQueryBuilder, t as ContentBody, u as ContentSourceConfig } from "./types-B9HP8tUf.js";
2
- import { S as parseMarkdown, _ as createQueryBuilder, a as getCollection, b as parseContent, c as parseContentFile, d as registerContent, g as createContentCollection, h as buildNavigation, i as fetchContentNavigation, l as queryCollection, n as configureContentRuntime, o as getContentItem, r as defineCollection, s as listCollections, t as bootstrapContentFromDisk, u as queryCollectionSearchSections, v as defineContentCollection, x as parseFrontmatter, y as generateId } from "./runtime-DQ65gYP0.js";
1
+ import { _ as SearchSection, a as ContentModuleOptions, c as ContentSchema, d as ContentTocItem, f as ContentType, g as SearchHit, l as ContentSearchOptions, m as MarkdownNode, n as ContentCollection, o as ContentNavigationItem, p as GenerateSearchSectionsOptions, r as ContentDocument, s as ContentQueryBuilder, t as ContentBody, u as ContentSourceConfig } from "./types-DN6hB1zj.js";
2
+ import { S as parseMarkdown, _ as createQueryBuilder, a as getCollection, b as parseContent, c as parseContentFile, d as registerContent, g as createContentCollection, h as buildNavigation, i as fetchContentNavigation, l as queryCollection, n as configureContentRuntime, o as getContentItem, r as defineCollection, s as listCollections, t as bootstrapContentFromDisk, u as queryCollectionSearchSections, v as defineContentCollection, x as parseFrontmatter, y as generateId } from "./runtime-w0CWrefy.js";
3
3
  export { type ContentBody, type ContentCollection, type ContentDocument, type ContentModuleOptions, type ContentNavigationItem, type ContentQueryBuilder, type ContentSchema, type ContentSearchOptions, type ContentSourceConfig, type ContentTocItem, type ContentType, type GenerateSearchSectionsOptions, type MarkdownNode, type SearchHit, type SearchSection, bootstrapContentFromDisk, buildNavigation, configureContentRuntime, createContentCollection, createQueryBuilder, defineCollection, defineContentCollection, fetchContentNavigation, generateId, getCollection, getContentItem, listCollections, parseContent, parseContentFile, parseFrontmatter, parseMarkdown, queryCollection, queryCollectionSearchSections, registerContent };
package/dist/runtime.js CHANGED
@@ -1,2 +1,2 @@
1
- import { _ as generateId, a as getCollection, b as parseMarkdown, c as parseContentFile, d as registerContent, g as defineContentCollection, h as createQueryBuilder, i as fetchContentNavigation, l as queryCollection, m as createContentCollection, n as configureContentRuntime, o as getContentItem, p as buildNavigation, r as defineCollection, s as listCollections, t as bootstrapContentFromDisk, u as queryCollectionSearchSections, v as parseContent, y as parseFrontmatter } from "./runtime-Cdi5T8aE.js";
1
+ import { _ as generateId, a as getCollection, b as parseMarkdown, c as parseContentFile, d as registerContent, g as defineContentCollection, h as createQueryBuilder, i as fetchContentNavigation, l as queryCollection, m as createContentCollection, n as configureContentRuntime, o as getContentItem, p as buildNavigation, r as defineCollection, s as listCollections, t as bootstrapContentFromDisk, u as queryCollectionSearchSections, v as parseContent, y as parseFrontmatter } from "./runtime-DPsviqaI.js";
2
2
  export { bootstrapContentFromDisk, buildNavigation, configureContentRuntime, createContentCollection, createQueryBuilder, defineCollection, defineContentCollection, fetchContentNavigation, generateId, getCollection, getContentItem, listCollections, parseContent, parseContentFile, parseFrontmatter, parseMarkdown, queryCollection, queryCollectionSearchSections, registerContent };
@@ -191,21 +191,41 @@ function createFallbackEngine(sections) {
191
191
  };
192
192
  }
193
193
  /**
194
+ * 加载 MiniSearch 模块(可选依赖)。
195
+ *
196
+ * 优先使用 `options.loadMiniSearch`。默认实现是 `import(变量)` +
197
+ * `@vite-ignore`:它**只在 Node 下有效**(Node 在运行时解析裸说明符),
198
+ * 浏览器 ESM 不认裸模块名,会抛 `Failed to resolve module specifier
199
+ * "minisearch"`,被下方的 try/catch 静默降级为 fallback 引擎。
200
+ *
201
+ * 因此浏览器场景必须由应用侧注入加载器 —— 字面量 import 落在应用源码里,
202
+ * Vite 才能解析并预打包(见 `SectionSearchOptions.loadMiniSearch`):
203
+ *
204
+ * ```ts
205
+ * useContentSearch({ searchOptions: { loadMiniSearch: () => import('minisearch') } });
206
+ * ```
207
+ */
208
+ async function loadMiniSearchModule(loader) {
209
+ const mod = loader ? await loader() : await import(
210
+ /* @vite-ignore */
211
+ "minisearch"
212
+ );
213
+ return mod?.default ?? mod?.MiniSearch ?? mod;
214
+ }
215
+ /**
194
216
  * 创建章节搜索引擎。
195
217
  *
196
218
  * 优先使用 MiniSearch(可选依赖,支持前缀 + 模糊匹配 + 字段加权),
197
- * 未安装时降级为内置 fallback 引擎(精确/前缀匹配)。
219
+ * 未安装/加载失败时降级为内置 fallback 引擎(精确/前缀匹配)。
198
220
  * 两条路径共享 CJK 感知分词器。
221
+ *
222
+ * 浏览器端必须通过 `options.loadMiniSearch` 注入字面量加载器,否则
223
+ * MiniSearch 无法加载(详见该选项文档)。
199
224
  */
200
225
  async function createSectionSearch(sections, options = {}) {
201
- const moduleId = "minisearch";
202
226
  let MiniSearch = null;
203
227
  try {
204
- const mod = await import(
205
- /* @vite-ignore */
206
- moduleId
207
- );
208
- MiniSearch = mod.default ?? mod.MiniSearch ?? mod;
228
+ MiniSearch = await loadMiniSearchModule(options.loadMiniSearch);
209
229
  } catch {
210
230
  MiniSearch = null;
211
231
  }
@@ -201,6 +201,20 @@ interface SectionSearchOptions {
201
201
  miniSearch?: Record<string, any>;
202
202
  /** MiniSearch 搜索选项(默认 `{ prefix: true, fuzzy: 0.2 }`) */
203
203
  searchOptions?: Record<string, any>;
204
+ /**
205
+ * 注入 MiniSearch 模块加载器。**浏览器场景必须提供。**
206
+ *
207
+ * 包内的默认加载是 `import(变量)` + `@vite-ignore`,只在 Node 下有效
208
+ * (Node 运行时解析裸说明符);浏览器 ESM 不认裸模块名,会抛
209
+ * `Failed to resolve module specifier "minisearch"` 并被静默降级。
210
+ *
211
+ * 由应用侧注入,字面量 import 就落在应用源码里,Vite 可正常解析/预打包:
212
+ *
213
+ * ```ts
214
+ * useContentSearch({ searchOptions: { loadMiniSearch: () => import('minisearch') } });
215
+ * ```
216
+ */
217
+ loadMiniSearch?: () => Promise<any>;
204
218
  }
205
219
  /** 内容搜索配置(`UbeanContentOptions.search`) */
206
220
  interface ContentSearchOptions {
package/dist/vite.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { l as ContentSearchOptions } from "./types-B9HP8tUf.js";
1
+ import { l as ContentSearchOptions } from "./types-DN6hB1zj.js";
2
2
  import { Plugin } from "vite";
3
3
  //#region src/vite.d.ts
4
4
  export interface UbeanContentOptions {
package/dist/vite.js CHANGED
@@ -1,5 +1,5 @@
1
- import { d as registerContent, f as scanContentSources, n as configureContentRuntime } from "./runtime-Cdi5T8aE.js";
2
- import { r as generateSearchSectionsSnapshot } from "./search-CNUu8Xvf.js";
1
+ import { d as registerContent, f as scanContentSources, n as configureContentRuntime } from "./runtime-DPsviqaI.js";
2
+ import { r as generateSearchSectionsSnapshot } from "./search-C73D12td.js";
3
3
  import { defu } from "defu";
4
4
  import { join } from "pathe";
5
5
  //#region src/vite.ts
package/dist/vue.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { _ as SearchSection, b as SectionSearchOptions, g as SearchHit, v as SectionQueryOptions } from "./types-B9HP8tUf.js";
1
+ import { _ as SearchSection, b as SectionSearchOptions, g as SearchHit, v as SectionQueryOptions } from "./types-DN6hB1zj.js";
2
2
  import { Ref } from "vue";
3
3
  //#region src/vue.d.ts
4
4
  export interface UseContentSearchOptions {
@@ -35,8 +35,11 @@ export interface UseContentSearchReturn {
35
35
  * 1. `options.sections`(SSR 直传 / 静态导入)
36
36
  * 2. `fetch(options.sectionsUrl ?? '/__search.json')`(dev 中间件 / SSG 构建产物)
37
37
  *
38
- * 引擎:优先 MiniSearch(可选依赖,前缀 + 模糊匹配),未安装时降级内置
39
- * fallback 引擎(精确/前缀匹配)。两者共享 CJK 感知分词器。
38
+ * 引擎:优先 MiniSearch(可选依赖,前缀 + 模糊匹配),未安装/加载失败时降级
39
+ * 内置 fallback 引擎(精确/前缀匹配)。两者共享 CJK 感知分词器。
40
+ *
41
+ * 浏览器端必须注入 `searchOptions.loadMiniSearch`,字面量 import 才能被 Vite
42
+ * 解析(详见 `UseContentSearchOptions.searchOptions` / `SectionSearchOptions`)。
40
43
  */
41
44
  export declare function useContentSearch(options?: UseContentSearchOptions): UseContentSearchReturn;
42
45
  //#endregion
package/dist/vue.js CHANGED
@@ -1,4 +1,4 @@
1
- import { t as createSectionSearch } from "./search-CNUu8Xvf.js";
1
+ import { t as createSectionSearch } from "./search-C73D12td.js";
2
2
  import { ref } from "vue";
3
3
  //#region src/vue.ts
4
4
  /**
@@ -8,8 +8,11 @@ import { ref } from "vue";
8
8
  * 1. `options.sections`(SSR 直传 / 静态导入)
9
9
  * 2. `fetch(options.sectionsUrl ?? '/__search.json')`(dev 中间件 / SSG 构建产物)
10
10
  *
11
- * 引擎:优先 MiniSearch(可选依赖,前缀 + 模糊匹配),未安装时降级内置
12
- * fallback 引擎(精确/前缀匹配)。两者共享 CJK 感知分词器。
11
+ * 引擎:优先 MiniSearch(可选依赖,前缀 + 模糊匹配),未安装/加载失败时降级
12
+ * 内置 fallback 引擎(精确/前缀匹配)。两者共享 CJK 感知分词器。
13
+ *
14
+ * 浏览器端必须注入 `searchOptions.loadMiniSearch`,字面量 import 才能被 Vite
15
+ * 解析(详见 `UseContentSearchOptions.searchOptions` / `SectionSearchOptions`)。
13
16
  */
14
17
  function useContentSearch(options = {}) {
15
18
  const status = ref("idle");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ubean/content",
3
- "version": "0.4.7",
3
+ "version": "0.4.9",
4
4
  "description": "File-based content module for ubean (markdown/MDX/YAML/JSON)",
5
5
  "files": [
6
6
  "dist"
@@ -28,7 +28,7 @@
28
28
  }
29
29
  },
30
30
  "dependencies": {
31
- "@ubean/shared": "0.4.7",
31
+ "@ubean/shared": "0.4.9",
32
32
  "defu": "6.1.7",
33
33
  "pathe": "^2.0.3",
34
34
  "scule": "^1.3.0"