@ox-content/vite-plugin 2.8.0 → 2.10.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/dist/github.mjs +299 -2
- package/dist/github.mjs.map +1 -0
- package/dist/index.cjs +122 -1391
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +108 -1
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +108 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +192 -1502
- package/dist/index.mjs.map +1 -1
- package/dist/mermaid.cjs +22 -0
- package/dist/mermaid.cjs.map +1 -1
- package/dist/mermaid.mjs +57 -1
- package/dist/mermaid.mjs.map +1 -1
- package/dist/ogp.mjs +307 -2
- package/dist/ogp.mjs.map +1 -0
- package/dist/tabs.mjs +188 -2
- package/dist/tabs.mjs.map +1 -0
- package/dist/vitepress-cli.cjs +186 -0
- package/dist/vitepress-cli.cjs.map +1 -0
- package/dist/vitepress-cli.d.cts +1 -0
- package/dist/vitepress-cli.d.mts +1 -0
- package/dist/vitepress-cli.mjs +185 -0
- package/dist/vitepress-cli.mjs.map +1 -0
- package/dist/vitepress.cjs +548 -0
- package/dist/vitepress.cjs.map +1 -0
- package/dist/vitepress.mjs +489 -0
- package/dist/vitepress.mjs.map +1 -0
- package/dist/youtube.mjs +117 -2
- package/dist/youtube.mjs.map +1 -0
- package/package.json +9 -2
- package/dist/github2.mjs +0 -291
- package/dist/github2.mjs.map +0 -1
- package/dist/mermaid2.mjs +0 -2
- package/dist/ogp2.mjs +0 -299
- package/dist/ogp2.mjs.map +0 -1
- package/dist/tabs2.mjs +0 -182
- package/dist/tabs2.mjs.map +0 -1
- package/dist/youtube2.mjs +0 -112
- package/dist/youtube2.mjs.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -5,6 +5,7 @@ const require_tabs = require("./tabs.cjs");
|
|
|
5
5
|
const require_youtube = require("./youtube.cjs");
|
|
6
6
|
const require_github = require("./github.cjs");
|
|
7
7
|
const require_ogp = require("./ogp.cjs");
|
|
8
|
+
const require_vitepress = require("./vitepress.cjs");
|
|
8
9
|
let path = require("path");
|
|
9
10
|
path = require_chunk.__toESM(path);
|
|
10
11
|
let unified = require("unified");
|
|
@@ -17,7 +18,6 @@ let node_path = require("node:path");
|
|
|
17
18
|
node_path = require_chunk.__toESM(node_path);
|
|
18
19
|
let fs = require("fs");
|
|
19
20
|
fs = require_chunk.__toESM(fs);
|
|
20
|
-
let node_crypto = require("node:crypto");
|
|
21
21
|
let fs_promises = require("fs/promises");
|
|
22
22
|
fs_promises = require_chunk.__toESM(fs_promises);
|
|
23
23
|
let glob = require("glob");
|
|
@@ -7087,241 +7087,11 @@ if (import.meta.hot) {
|
|
|
7087
7087
|
}
|
|
7088
7088
|
//#endregion
|
|
7089
7089
|
//#region src/nav-generator.ts
|
|
7090
|
-
/**
|
|
7091
|
-
* Navigation Metadata Generator for API Documentation
|
|
7092
|
-
*
|
|
7093
|
-
* This module provides utilities for generating sidebar navigation structures
|
|
7094
|
-
* from extracted documentation. It automatically:
|
|
7095
|
-
*
|
|
7096
|
-
* - **Extracts file information**: Gets display names and file paths
|
|
7097
|
-
* - **Formats names**: Converts technical names to readable titles
|
|
7098
|
-
* - **Generates TypeScript**: Creates importable nav.ts files
|
|
7099
|
-
* - **Maintains hierarchy**: Supports nested navigation structures
|
|
7100
|
-
*
|
|
7101
|
-
* ## Generated Navigation Format
|
|
7102
|
-
*
|
|
7103
|
-
* The generated navigation is TypeScript-based for type safety and IDE support:
|
|
7104
|
-
*
|
|
7105
|
-
* ```typescript
|
|
7106
|
-
* export const apiNav: NavItem[] = [
|
|
7107
|
-
* { title: 'Overview', path: '/api/index' },
|
|
7108
|
-
* { title: 'Transform', path: '/api/transform' },
|
|
7109
|
-
* { title: 'Types', path: '/api/types' },
|
|
7110
|
-
* // ... auto-generated from documentation
|
|
7111
|
-
* ] as const;
|
|
7112
|
-
* ```
|
|
7113
|
-
*
|
|
7114
|
-
* ## Integration
|
|
7115
|
-
*
|
|
7116
|
-
* The generated nav.ts file can be imported directly:
|
|
7117
|
-
*
|
|
7118
|
-
* ```typescript
|
|
7119
|
-
* // In your Vue/React component
|
|
7120
|
-
* import { apiNav } from '../api/nav';
|
|
7121
|
-
*
|
|
7122
|
-
* const apiItems = apiNav.map(item => ({
|
|
7123
|
-
* ...item,
|
|
7124
|
-
* file: () => import(`../api/${item.path.split('/').pop()}.md`)
|
|
7125
|
-
* }));
|
|
7126
|
-
* ```
|
|
7127
|
-
*
|
|
7128
|
-
* @example
|
|
7129
|
-
* ```typescript
|
|
7130
|
-
* import { generateNavMetadata, generateNavCode } from './nav-generator';
|
|
7131
|
-
*
|
|
7132
|
-
* const extracted = [
|
|
7133
|
-
* { file: 'transform.ts', entries: [...] },
|
|
7134
|
-
* { file: 'types.ts', entries: [...] },
|
|
7135
|
-
* ];
|
|
7136
|
-
*
|
|
7137
|
-
* const navItems = generateNavMetadata(extracted);
|
|
7138
|
-
* // => [
|
|
7139
|
-
* // { title: 'Transform', path: '/api/transform' },
|
|
7140
|
-
* // { title: 'Types', path: '/api/types' },
|
|
7141
|
-
* // ]
|
|
7142
|
-
*
|
|
7143
|
-
* const code = generateNavCode(navItems);
|
|
7144
|
-
* // => TypeScript code ready to write to nav.ts
|
|
7145
|
-
* ```
|
|
7146
|
-
*/
|
|
7147
|
-
/**
|
|
7148
|
-
* Generates sidebar navigation metadata from extracted documentation.
|
|
7149
|
-
*
|
|
7150
|
-
* Takes an array of extracted documentation and produces a flat navigation
|
|
7151
|
-
* structure suitable for sidebar menus. Items are:
|
|
7152
|
-
* - Sorted alphabetically by display name
|
|
7153
|
-
* - Formatted with readable titles
|
|
7154
|
-
* - Prefixed with the specified base path
|
|
7155
|
-
*
|
|
7156
|
-
* ## Naming Conventions
|
|
7157
|
-
*
|
|
7158
|
-
* - `transform.ts` → `{ title: 'Transform', path: '/api/transform' }`
|
|
7159
|
-
* - `nav-generator.ts` → `{ title: 'Nav Generator', path: '/api/nav-generator' }`
|
|
7160
|
-
* - `index.ts` or `index-module.ts` → `{ title: 'Overview', path: '/api/index' }`
|
|
7161
|
-
* - `types.ts` → `{ title: 'Types', path: '/api/types' }`
|
|
7162
|
-
*
|
|
7163
|
-
* ## Sorting
|
|
7164
|
-
*
|
|
7165
|
-
* Items are sorted alphabetically by display title for consistent ordering.
|
|
7166
|
-
* Special item 'Overview' sorts naturally with others (O comes after most letters).
|
|
7167
|
-
*
|
|
7168
|
-
* ## Path Generation
|
|
7169
|
-
*
|
|
7170
|
-
* The generated paths are used to import corresponding Markdown files:
|
|
7171
|
-
* - Path `/api/transform` → Import from `../api/transform.md`
|
|
7172
|
-
* - Path `/api/index` → Import from `../api/index.md`
|
|
7173
|
-
*
|
|
7174
|
-
* @param docs - Array of extracted documentation (file + entries)
|
|
7175
|
-
* @param basePath - Base path prefix for navigation URLs (default: '/api')
|
|
7176
|
-
* Use '/api' for main API docs, '/helpers' for utilities, etc.
|
|
7177
|
-
*
|
|
7178
|
-
* @returns Array of navigation items ready to use or export to TypeScript
|
|
7179
|
-
*
|
|
7180
|
-
* @example
|
|
7181
|
-
* ```typescript
|
|
7182
|
-
* const navItems = generateNavMetadata(
|
|
7183
|
-
* [
|
|
7184
|
-
* { file: 'transform.ts', entries: [...] },
|
|
7185
|
-
* { file: 'docs.ts', entries: [...] },
|
|
7186
|
-
* { file: 'types.ts', entries: [...] },
|
|
7187
|
-
* ],
|
|
7188
|
-
* '/api'
|
|
7189
|
-
* );
|
|
7190
|
-
*
|
|
7191
|
-
* // Returns:
|
|
7192
|
-
* // [
|
|
7193
|
-
* // { title: 'Docs', path: '/api/docs' },
|
|
7194
|
-
* // { title: 'Transform', path: '/api/transform' },
|
|
7195
|
-
* // { title: 'Types', path: '/api/types' },
|
|
7196
|
-
* // ]
|
|
7197
|
-
* ```
|
|
7198
|
-
*
|
|
7199
|
-
* @see generateNavCode For converting these items to TypeScript code
|
|
7200
|
-
*/
|
|
7201
7090
|
function generateNavMetadata(docs, basePath = "/api") {
|
|
7202
|
-
return
|
|
7203
|
-
const aName = getDocDisplayName(a.file);
|
|
7204
|
-
const bName = getDocDisplayName(b.file);
|
|
7205
|
-
return aName.localeCompare(bName);
|
|
7206
|
-
}).map((doc) => ({
|
|
7207
|
-
title: getDocDisplayName(doc.file),
|
|
7208
|
-
path: `${basePath}/${getDocFileName(doc.file)}`
|
|
7209
|
-
}));
|
|
7210
|
-
}
|
|
7211
|
-
/**
|
|
7212
|
-
* Gets the human-readable display name for a documentation file.
|
|
7213
|
-
*
|
|
7214
|
-
* Transforms file paths and names into proper title case:
|
|
7215
|
-
* - Extracts base name (e.g., 'transform.ts' → 'transform')
|
|
7216
|
-
* - Converts kebab-case to Title Case (e.g., 'nav-generator' → 'Nav Generator')
|
|
7217
|
-
* - Converts camelCase to Title Case (e.g., 'transformMarkdown' → 'Transform Markdown')
|
|
7218
|
-
* - Handles special cases (index → 'Overview')
|
|
7219
|
-
*
|
|
7220
|
-
* ## Examples
|
|
7221
|
-
*
|
|
7222
|
-
* - `'/path/to/transform.ts'` → `'Transform'`
|
|
7223
|
-
* - `'nav-generator.ts'` → `'Nav Generator'`
|
|
7224
|
-
* - `'index.ts'` → `'Overview'`
|
|
7225
|
-
* - `'index-module.ts'` → `'Overview'`
|
|
7226
|
-
* - `'myFunction.ts'` → `'My Function'` (with camelCase handling)
|
|
7227
|
-
*
|
|
7228
|
-
* @param filePath - Full or relative file path
|
|
7229
|
-
* @returns Formatted display name suitable for UI labels
|
|
7230
|
-
*
|
|
7231
|
-
* @internal
|
|
7232
|
-
*/
|
|
7233
|
-
function getDocDisplayName(filePath) {
|
|
7234
|
-
const fileName = path.default.basename(filePath, path.default.extname(filePath));
|
|
7235
|
-
if (fileName === "index" || fileName === "index-module") return "Overview";
|
|
7236
|
-
return fileName.replace(/[-_]([a-z])/g, (_, char) => " " + char.toUpperCase()).replace(/^[a-z]/, (char) => char.toUpperCase());
|
|
7237
|
-
}
|
|
7238
|
-
/**
|
|
7239
|
-
* Gets the file name (without extension) for use in navigation paths.
|
|
7240
|
-
*
|
|
7241
|
-
* This handles filename conflicts that may occur during generation:
|
|
7242
|
-
* - Preserves most names as-is
|
|
7243
|
-
* - Special handling for index files to maintain consistency
|
|
7244
|
-
*
|
|
7245
|
-
* @param filePath - Source file path
|
|
7246
|
-
* @returns File name without extension, ready for URL paths
|
|
7247
|
-
*
|
|
7248
|
-
* @internal
|
|
7249
|
-
*/
|
|
7250
|
-
function getDocFileName(filePath) {
|
|
7251
|
-
const fileName = path.default.basename(filePath, path.default.extname(filePath));
|
|
7252
|
-
if (fileName === "index") return "index";
|
|
7253
|
-
return fileName;
|
|
7091
|
+
return require_mermaid.importNapiModuleSync().generateDocsNavMetadata(docs.map((doc) => doc.file), basePath);
|
|
7254
7092
|
}
|
|
7255
|
-
/**
|
|
7256
|
-
* Generates TypeScript code for navigation metadata export.
|
|
7257
|
-
*
|
|
7258
|
-
* Creates a complete, self-contained TypeScript file that:
|
|
7259
|
-
* - Defines the NavItem interface
|
|
7260
|
-
* - Exports navigation items as a const
|
|
7261
|
-
* - Uses `as const` for type-safe literal types
|
|
7262
|
-
* - Includes auto-generation notice
|
|
7263
|
-
*
|
|
7264
|
-
* The generated code is production-ready and suitable for direct import
|
|
7265
|
-
* in Vue, React, or vanilla TypeScript applications.
|
|
7266
|
-
*
|
|
7267
|
-
* ## Generated Code Example
|
|
7268
|
-
*
|
|
7269
|
-
* ```typescript
|
|
7270
|
-
* export interface NavItem {
|
|
7271
|
-
* title: string;
|
|
7272
|
-
* path: string;
|
|
7273
|
-
* children?: NavItem[];
|
|
7274
|
-
* }
|
|
7275
|
-
*
|
|
7276
|
-
* export const apiNav: NavItem[] = [
|
|
7277
|
-
* { "title": "Docs", "path": "/api/docs" },
|
|
7278
|
-
* { "title": "Transform", "path": "/api/transform" },
|
|
7279
|
-
* // ...
|
|
7280
|
-
* ] as const;
|
|
7281
|
-
* ```
|
|
7282
|
-
*
|
|
7283
|
-
* ## Features
|
|
7284
|
-
*
|
|
7285
|
-
* - **Type Safety**: Includes NavItem interface definition
|
|
7286
|
-
* - **Readonly**: Uses `as const` to ensure immutability
|
|
7287
|
-
* - **IDE Support**: Full IntelliSense and autocomplete
|
|
7288
|
-
* - **Self-Documenting**: Includes notice that file is auto-generated
|
|
7289
|
-
*
|
|
7290
|
-
* @param navItems - Array of navigation items to export
|
|
7291
|
-
* @param exportName - Name of the exported const (default: 'apiNav')
|
|
7292
|
-
* Use custom names for different navigation sections
|
|
7293
|
-
*
|
|
7294
|
-
* @returns Complete TypeScript source code as string,
|
|
7295
|
-
* ready to write to a .ts file
|
|
7296
|
-
*
|
|
7297
|
-
* @example
|
|
7298
|
-
* ```typescript
|
|
7299
|
-
* const navItems = [
|
|
7300
|
-
* { title: 'Home', path: '/api/index' },
|
|
7301
|
-
* { title: 'Transform', path: '/api/transform' },
|
|
7302
|
-
* ];
|
|
7303
|
-
*
|
|
7304
|
-
* const code = generateNavCode(navItems, 'apiNav');
|
|
7305
|
-
* await fs.promises.writeFile('docs/api/nav.ts', code, 'utf-8');
|
|
7306
|
-
* ```
|
|
7307
|
-
*
|
|
7308
|
-
* @see generateNavMetadata For generating NavItem arrays from extracted docs
|
|
7309
|
-
*/
|
|
7310
7093
|
function generateNavCode(navItems, exportName = "apiNav") {
|
|
7311
|
-
return
|
|
7312
|
-
* Auto-generated API documentation navigation.
|
|
7313
|
-
* This file is automatically generated by the docs plugin.
|
|
7314
|
-
* Do not edit manually.
|
|
7315
|
-
*/
|
|
7316
|
-
|
|
7317
|
-
export interface NavItem {
|
|
7318
|
-
title: string;
|
|
7319
|
-
path: string;
|
|
7320
|
-
children?: NavItem[];
|
|
7321
|
-
}
|
|
7322
|
-
|
|
7323
|
-
export const ${exportName}: NavItem[] = ${JSON.stringify(navItems, null, 2)} as const;
|
|
7324
|
-
`;
|
|
7094
|
+
return require_mermaid.importNapiModuleSync().generateDocsNavCode(navItems, exportName);
|
|
7325
7095
|
}
|
|
7326
7096
|
//#endregion
|
|
7327
7097
|
//#region src/docs.ts
|
|
@@ -7648,86 +7418,6 @@ function buildDocsData(docs) {
|
|
|
7648
7418
|
}))
|
|
7649
7419
|
};
|
|
7650
7420
|
}
|
|
7651
|
-
function consumeJSDocType(value) {
|
|
7652
|
-
const trimmed = value.trimStart();
|
|
7653
|
-
if (!trimmed.startsWith("{")) return { rest: trimmed };
|
|
7654
|
-
let depth = 0;
|
|
7655
|
-
for (let index = 0; index < trimmed.length; index++) {
|
|
7656
|
-
const char = trimmed[index];
|
|
7657
|
-
if (char === "{") depth++;
|
|
7658
|
-
else if (char === "}") {
|
|
7659
|
-
depth--;
|
|
7660
|
-
if (depth === 0) return {
|
|
7661
|
-
type: trimmed.slice(1, index).trim() || void 0,
|
|
7662
|
-
rest: trimmed.slice(index + 1).trimStart()
|
|
7663
|
-
};
|
|
7664
|
-
}
|
|
7665
|
-
}
|
|
7666
|
-
return { rest: trimmed };
|
|
7667
|
-
}
|
|
7668
|
-
function cleanTagDescription(value) {
|
|
7669
|
-
return value.trim().replace(/^-\s*/, "").trim();
|
|
7670
|
-
}
|
|
7671
|
-
function splitTagNameAndDescription(value) {
|
|
7672
|
-
const trimmed = value.trimStart();
|
|
7673
|
-
if (trimmed.startsWith("[")) {
|
|
7674
|
-
const closeIndex = trimmed.indexOf("]");
|
|
7675
|
-
if (closeIndex >= 0) return {
|
|
7676
|
-
name: trimmed.slice(0, closeIndex + 1),
|
|
7677
|
-
description: trimmed.slice(closeIndex + 1).trimStart()
|
|
7678
|
-
};
|
|
7679
|
-
}
|
|
7680
|
-
const match = /^(\S+)(?:\s+([\s\S]*))?$/u.exec(trimmed);
|
|
7681
|
-
return {
|
|
7682
|
-
name: match?.[1] ?? "",
|
|
7683
|
-
description: match?.[2] ?? ""
|
|
7684
|
-
};
|
|
7685
|
-
}
|
|
7686
|
-
function parseParamTagValue(value) {
|
|
7687
|
-
const { type, rest } = consumeJSDocType(value);
|
|
7688
|
-
const { name: rawName, description } = splitTagNameAndDescription(rest);
|
|
7689
|
-
let name = rawName.trim();
|
|
7690
|
-
if (!name) return null;
|
|
7691
|
-
let optional = false;
|
|
7692
|
-
let defaultValue;
|
|
7693
|
-
const optionalMatch = /^\[(.*)\]$/u.exec(name);
|
|
7694
|
-
if (optionalMatch) {
|
|
7695
|
-
optional = true;
|
|
7696
|
-
const [innerName, innerDefault] = optionalMatch[1].split(/=(.*)/su);
|
|
7697
|
-
name = innerName.trim();
|
|
7698
|
-
defaultValue = innerDefault?.trim() || void 0;
|
|
7699
|
-
}
|
|
7700
|
-
if (!name) return null;
|
|
7701
|
-
return {
|
|
7702
|
-
name,
|
|
7703
|
-
type: type || "unknown",
|
|
7704
|
-
description: cleanTagDescription(description),
|
|
7705
|
-
optional: optional || void 0,
|
|
7706
|
-
default: defaultValue
|
|
7707
|
-
};
|
|
7708
|
-
}
|
|
7709
|
-
function parseReturnsTagValue(value) {
|
|
7710
|
-
const { type, rest } = consumeJSDocType(value);
|
|
7711
|
-
return {
|
|
7712
|
-
type: type || "unknown",
|
|
7713
|
-
description: cleanTagDescription(rest)
|
|
7714
|
-
};
|
|
7715
|
-
}
|
|
7716
|
-
function normalizeReturnType(value) {
|
|
7717
|
-
const parsed = parseReturnsTagValue(value);
|
|
7718
|
-
return parsed.type === "unknown" ? value : parsed.type;
|
|
7719
|
-
}
|
|
7720
|
-
function mergeParam(params, next) {
|
|
7721
|
-
const existing = params.find((param) => param.name === next.name);
|
|
7722
|
-
if (!existing) {
|
|
7723
|
-
params.push(next);
|
|
7724
|
-
return;
|
|
7725
|
-
}
|
|
7726
|
-
if (next.type && (existing.type === "unknown" || next.type !== "unknown")) existing.type = next.type;
|
|
7727
|
-
if (next.description) existing.description = next.description;
|
|
7728
|
-
if (next.optional) existing.optional = true;
|
|
7729
|
-
if (next.default) existing.default = next.default;
|
|
7730
|
-
}
|
|
7731
7421
|
/**
|
|
7732
7422
|
* Extracts JSDoc documentation from source files in specified directories.
|
|
7733
7423
|
*
|
|
@@ -7794,13 +7484,13 @@ function mergeParam(params, next) {
|
|
|
7794
7484
|
* ```
|
|
7795
7485
|
*/
|
|
7796
7486
|
async function extractDocs(srcDirs, options) {
|
|
7797
|
-
const
|
|
7798
|
-
if (!
|
|
7487
|
+
const extractFileDocEntries = (await require_mermaid.importNapiModule()).extractFileDocEntries;
|
|
7488
|
+
if (!extractFileDocEntries) throw new Error("[ox-content] extractFileDocEntries is not available from @ox-content/napi.");
|
|
7799
7489
|
const results = [];
|
|
7800
7490
|
for (const srcDir of srcDirs) {
|
|
7801
7491
|
const files = await findFiles(srcDir, options);
|
|
7802
7492
|
for (const file of files) {
|
|
7803
|
-
const entries =
|
|
7493
|
+
const entries = extractFileDocEntries(file, options.private);
|
|
7804
7494
|
if (entries.length > 0) results.push({
|
|
7805
7495
|
file,
|
|
7806
7496
|
entries
|
|
@@ -7851,132 +7541,6 @@ function isExcluded(file, patterns) {
|
|
|
7851
7541
|
return false;
|
|
7852
7542
|
});
|
|
7853
7543
|
}
|
|
7854
|
-
function parseNapiDocItem(item) {
|
|
7855
|
-
const kind = normalizeNapiKind(item.kind);
|
|
7856
|
-
if (!kind) return null;
|
|
7857
|
-
const params = [];
|
|
7858
|
-
const examples = [];
|
|
7859
|
-
const tags = {};
|
|
7860
|
-
let description = "";
|
|
7861
|
-
let returns;
|
|
7862
|
-
let isPrivate = false;
|
|
7863
|
-
const rawLines = (item.jsdoc ?? "").split("\n").map((line) => {
|
|
7864
|
-
const trimmedStart = line.trimStart();
|
|
7865
|
-
const withoutStar = trimmedStart.startsWith("*") ? trimmedStart.slice(1) : trimmedStart;
|
|
7866
|
-
return withoutStar.startsWith(" ") ? withoutStar.slice(1) : withoutStar;
|
|
7867
|
-
});
|
|
7868
|
-
const cleanedLines = rawLines.map((line) => line.trim()).filter(Boolean);
|
|
7869
|
-
let currentExample = "";
|
|
7870
|
-
let inExample = false;
|
|
7871
|
-
let rawLineIndex = 0;
|
|
7872
|
-
for (const lineText of cleanedLines) {
|
|
7873
|
-
while (rawLineIndex < rawLines.length && rawLines[rawLineIndex].trim() !== lineText) rawLineIndex++;
|
|
7874
|
-
const rawLine = rawLineIndex < rawLines.length ? rawLines[rawLineIndex] : lineText;
|
|
7875
|
-
rawLineIndex++;
|
|
7876
|
-
if (lineText.startsWith("@")) {
|
|
7877
|
-
if (inExample) {
|
|
7878
|
-
examples.push(currentExample.trim());
|
|
7879
|
-
currentExample = "";
|
|
7880
|
-
inExample = false;
|
|
7881
|
-
}
|
|
7882
|
-
const tagMatch = /^@(\S+)\s*([\s\S]*)$/u.exec(lineText);
|
|
7883
|
-
if (tagMatch) {
|
|
7884
|
-
const [, tagName, tagValue = ""] = tagMatch;
|
|
7885
|
-
switch (tagName) {
|
|
7886
|
-
case "param":
|
|
7887
|
-
case "arg":
|
|
7888
|
-
case "argument": {
|
|
7889
|
-
const param = parseParamTagValue(tagValue);
|
|
7890
|
-
if (param) mergeParam(params, param);
|
|
7891
|
-
break;
|
|
7892
|
-
}
|
|
7893
|
-
case "returns":
|
|
7894
|
-
case "return":
|
|
7895
|
-
returns = parseReturnsTagValue(tagValue);
|
|
7896
|
-
break;
|
|
7897
|
-
case "example":
|
|
7898
|
-
inExample = true;
|
|
7899
|
-
currentExample = tagValue.trim() ? `${tagValue.trim()}\n` : "";
|
|
7900
|
-
break;
|
|
7901
|
-
case "private":
|
|
7902
|
-
isPrivate = true;
|
|
7903
|
-
break;
|
|
7904
|
-
default: tags[tagName] = tagValue.trim();
|
|
7905
|
-
}
|
|
7906
|
-
}
|
|
7907
|
-
} else if (inExample) currentExample += rawLine + "\n";
|
|
7908
|
-
else if (!description) description = lineText;
|
|
7909
|
-
else description += "\n" + lineText;
|
|
7910
|
-
}
|
|
7911
|
-
if (inExample && currentExample) examples.push(currentExample.trim());
|
|
7912
|
-
for (const param of item.params) {
|
|
7913
|
-
if (params.length > 0 && param.name === "param" && !param.typeAnnotation && !param.description && !param.defaultValue) continue;
|
|
7914
|
-
mergeParam(params, {
|
|
7915
|
-
name: param.name,
|
|
7916
|
-
type: param.typeAnnotation ?? "unknown",
|
|
7917
|
-
description: param.description ?? "",
|
|
7918
|
-
optional: param.optional || void 0,
|
|
7919
|
-
default: param.defaultValue
|
|
7920
|
-
});
|
|
7921
|
-
}
|
|
7922
|
-
if (!returns && item.returnType) returns = {
|
|
7923
|
-
type: normalizeReturnType(item.returnType),
|
|
7924
|
-
description: ""
|
|
7925
|
-
};
|
|
7926
|
-
else if (returns && item.returnType) returns.type = normalizeReturnType(item.returnType);
|
|
7927
|
-
if (!description) description = item.doc ?? "";
|
|
7928
|
-
for (const tag of item.tags) {
|
|
7929
|
-
if (tag.tag === "param" || tag.tag === "arg" || tag.tag === "argument" || tag.tag === "returns" || tag.tag === "return") {
|
|
7930
|
-
if (tag.tag === "param" || tag.tag === "arg" || tag.tag === "argument") {
|
|
7931
|
-
const param = parseParamTagValue(tag.value);
|
|
7932
|
-
if (param) mergeParam(params, param);
|
|
7933
|
-
} else {
|
|
7934
|
-
const parsedReturns = parseReturnsTagValue(tag.value);
|
|
7935
|
-
if (!returns) returns = parsedReturns;
|
|
7936
|
-
else {
|
|
7937
|
-
returns.type = returns.type === "unknown" ? parsedReturns.type : returns.type;
|
|
7938
|
-
returns.description ||= parsedReturns.description;
|
|
7939
|
-
}
|
|
7940
|
-
}
|
|
7941
|
-
continue;
|
|
7942
|
-
}
|
|
7943
|
-
if (tag.tag === "example") {
|
|
7944
|
-
if (tag.value && !examples.includes(tag.value)) examples.push(tag.value);
|
|
7945
|
-
continue;
|
|
7946
|
-
}
|
|
7947
|
-
if (tag.tag === "private") {
|
|
7948
|
-
isPrivate = true;
|
|
7949
|
-
continue;
|
|
7950
|
-
}
|
|
7951
|
-
if (!tags[tag.tag]) tags[tag.tag] = tag.value;
|
|
7952
|
-
}
|
|
7953
|
-
return {
|
|
7954
|
-
name: item.name,
|
|
7955
|
-
kind,
|
|
7956
|
-
description,
|
|
7957
|
-
params: params.length > 0 ? params : void 0,
|
|
7958
|
-
returns,
|
|
7959
|
-
examples: examples.length > 0 ? examples : void 0,
|
|
7960
|
-
tags: Object.keys(tags).length > 0 ? tags : void 0,
|
|
7961
|
-
private: isPrivate,
|
|
7962
|
-
file: item.sourcePath,
|
|
7963
|
-
line: item.line,
|
|
7964
|
-
endLine: item.endLine,
|
|
7965
|
-
signature: item.signature
|
|
7966
|
-
};
|
|
7967
|
-
}
|
|
7968
|
-
function normalizeNapiKind(kind) {
|
|
7969
|
-
switch (kind) {
|
|
7970
|
-
case "function":
|
|
7971
|
-
case "class":
|
|
7972
|
-
case "interface":
|
|
7973
|
-
case "type":
|
|
7974
|
-
case "variable":
|
|
7975
|
-
case "module": return kind;
|
|
7976
|
-
case "enum": return "type";
|
|
7977
|
-
default: return null;
|
|
7978
|
-
}
|
|
7979
|
-
}
|
|
7980
7544
|
/**
|
|
7981
7545
|
* Generates Markdown documentation from extracted docs.
|
|
7982
7546
|
*/
|
|
@@ -9246,213 +8810,6 @@ initIslands((el, props) => {
|
|
|
9246
8810
|
`;
|
|
9247
8811
|
}
|
|
9248
8812
|
//#endregion
|
|
9249
|
-
//#region src/theme.ts
|
|
9250
|
-
/**
|
|
9251
|
-
* Default theme configuration.
|
|
9252
|
-
* Based on the current ox-content SSG styles.
|
|
9253
|
-
*/
|
|
9254
|
-
const defaultTheme = {
|
|
9255
|
-
name: "default",
|
|
9256
|
-
colors: {
|
|
9257
|
-
primary: "#4f6fae",
|
|
9258
|
-
primaryHover: "#425f96",
|
|
9259
|
-
background: "#ffffff",
|
|
9260
|
-
backgroundAlt: "#f5f7fb",
|
|
9261
|
-
text: "#131a30",
|
|
9262
|
-
textMuted: "#4f607b",
|
|
9263
|
-
border: "#d2dbea",
|
|
9264
|
-
codeBackground: "#101a31",
|
|
9265
|
-
codeText: "#edf3ff"
|
|
9266
|
-
},
|
|
9267
|
-
darkColors: {
|
|
9268
|
-
primary: "#86a4da",
|
|
9269
|
-
primaryHover: "#a3bbe8",
|
|
9270
|
-
background: "#060816",
|
|
9271
|
-
backgroundAlt: "#0d1528",
|
|
9272
|
-
text: "#ebf2ff",
|
|
9273
|
-
textMuted: "#8ea0bf",
|
|
9274
|
-
border: "#223252",
|
|
9275
|
-
codeBackground: "#0a1020",
|
|
9276
|
-
codeText: "#e7f0ff"
|
|
9277
|
-
},
|
|
9278
|
-
fonts: {
|
|
9279
|
-
sans: "\"IBM Plex Sans\", \"Avenir Next\", \"Segoe UI Variable\", \"Segoe UI\", sans-serif",
|
|
9280
|
-
mono: "\"IBM Plex Mono\", \"SFMono-Regular\", Consolas, monospace"
|
|
9281
|
-
},
|
|
9282
|
-
entryPage: { mode: "default" },
|
|
9283
|
-
layout: {
|
|
9284
|
-
sidebarWidth: "260px",
|
|
9285
|
-
headerHeight: "60px",
|
|
9286
|
-
maxContentWidth: "960px"
|
|
9287
|
-
},
|
|
9288
|
-
header: {
|
|
9289
|
-
logo: void 0,
|
|
9290
|
-
logoLight: void 0,
|
|
9291
|
-
logoDark: void 0,
|
|
9292
|
-
showSiteNameText: true,
|
|
9293
|
-
logoWidth: 28,
|
|
9294
|
-
logoHeight: 28
|
|
9295
|
-
},
|
|
9296
|
-
footer: {
|
|
9297
|
-
message: void 0,
|
|
9298
|
-
copyright: void 0
|
|
9299
|
-
},
|
|
9300
|
-
socialLinks: {},
|
|
9301
|
-
embed: {},
|
|
9302
|
-
css: "",
|
|
9303
|
-
js: ""
|
|
9304
|
-
};
|
|
9305
|
-
/**
|
|
9306
|
-
* Deep merge two objects.
|
|
9307
|
-
*/
|
|
9308
|
-
function deepMerge(target, source) {
|
|
9309
|
-
const result = { ...target };
|
|
9310
|
-
for (const key of Object.keys(source)) {
|
|
9311
|
-
const sourceValue = source[key];
|
|
9312
|
-
const targetValue = target[key];
|
|
9313
|
-
if (sourceValue !== void 0 && typeof sourceValue === "object" && sourceValue !== null && !Array.isArray(sourceValue) && typeof targetValue === "object" && targetValue !== null && !Array.isArray(targetValue)) result[key] = deepMerge(targetValue, sourceValue);
|
|
9314
|
-
else if (sourceValue !== void 0) result[key] = sourceValue;
|
|
9315
|
-
}
|
|
9316
|
-
return result;
|
|
9317
|
-
}
|
|
9318
|
-
/**
|
|
9319
|
-
* Defines a theme configuration with type checking.
|
|
9320
|
-
*
|
|
9321
|
-
* @example
|
|
9322
|
-
* ```ts
|
|
9323
|
-
* const myTheme = defineTheme({
|
|
9324
|
-
* extends: defaultTheme,
|
|
9325
|
-
* colors: {
|
|
9326
|
-
* primary: '#3498db',
|
|
9327
|
-
* },
|
|
9328
|
-
* footer: {
|
|
9329
|
-
* copyright: '2025 My Company',
|
|
9330
|
-
* },
|
|
9331
|
-
* });
|
|
9332
|
-
* ```
|
|
9333
|
-
*/
|
|
9334
|
-
function defineTheme(config) {
|
|
9335
|
-
return config;
|
|
9336
|
-
}
|
|
9337
|
-
/**
|
|
9338
|
-
* Merges multiple theme configurations.
|
|
9339
|
-
* Later themes override earlier ones.
|
|
9340
|
-
*
|
|
9341
|
-
* @example
|
|
9342
|
-
* ```ts
|
|
9343
|
-
* const merged = mergeThemes(defaultTheme, customTheme, overrides);
|
|
9344
|
-
* ```
|
|
9345
|
-
*/
|
|
9346
|
-
function mergeThemes(...themes) {
|
|
9347
|
-
if (themes.length === 0) return { ...defaultTheme };
|
|
9348
|
-
let result = {};
|
|
9349
|
-
for (const theme of themes) result = deepMerge(result, theme);
|
|
9350
|
-
return result;
|
|
9351
|
-
}
|
|
9352
|
-
/**
|
|
9353
|
-
* Resolves a theme configuration by merging with its extends chain and defaults.
|
|
9354
|
-
*/
|
|
9355
|
-
function resolveTheme(config) {
|
|
9356
|
-
if (!config) return resolveTheme(defaultTheme);
|
|
9357
|
-
const chain = [];
|
|
9358
|
-
let current = config;
|
|
9359
|
-
while (current) {
|
|
9360
|
-
chain.unshift(current);
|
|
9361
|
-
current = current.extends;
|
|
9362
|
-
}
|
|
9363
|
-
if (chain[0] !== defaultTheme && chain[0]?.name !== "default") chain.unshift(defaultTheme);
|
|
9364
|
-
const merged = mergeThemes(...chain);
|
|
9365
|
-
return {
|
|
9366
|
-
name: merged.name ?? "custom",
|
|
9367
|
-
colors: merged.colors ?? defaultTheme.colors,
|
|
9368
|
-
darkColors: merged.darkColors ?? defaultTheme.darkColors,
|
|
9369
|
-
fonts: merged.fonts ?? defaultTheme.fonts,
|
|
9370
|
-
entryPage: merged.entryPage ?? defaultTheme.entryPage,
|
|
9371
|
-
layout: merged.layout ?? defaultTheme.layout,
|
|
9372
|
-
header: merged.header ?? defaultTheme.header,
|
|
9373
|
-
footer: merged.footer ?? defaultTheme.footer,
|
|
9374
|
-
socialLinks: merged.socialLinks ?? defaultTheme.socialLinks,
|
|
9375
|
-
sidebar: merged.sidebar ?? [],
|
|
9376
|
-
embed: merged.embed ?? {},
|
|
9377
|
-
css: merged.css ?? "",
|
|
9378
|
-
js: merged.js ?? ""
|
|
9379
|
-
};
|
|
9380
|
-
}
|
|
9381
|
-
/**
|
|
9382
|
-
* Converts resolved theme to the format expected by Rust NAPI.
|
|
9383
|
-
*/
|
|
9384
|
-
function themeToNapi(theme) {
|
|
9385
|
-
const socialLinks = socialLinksToNapi(theme.socialLinks);
|
|
9386
|
-
return {
|
|
9387
|
-
colors: theme.colors.primary ? {
|
|
9388
|
-
primary: theme.colors.primary,
|
|
9389
|
-
primaryHover: theme.colors.primaryHover,
|
|
9390
|
-
background: theme.colors.background,
|
|
9391
|
-
backgroundAlt: theme.colors.backgroundAlt,
|
|
9392
|
-
text: theme.colors.text,
|
|
9393
|
-
textMuted: theme.colors.textMuted,
|
|
9394
|
-
border: theme.colors.border,
|
|
9395
|
-
codeBackground: theme.colors.codeBackground,
|
|
9396
|
-
codeText: theme.colors.codeText
|
|
9397
|
-
} : void 0,
|
|
9398
|
-
darkColors: theme.darkColors.primary ? {
|
|
9399
|
-
primary: theme.darkColors.primary,
|
|
9400
|
-
primaryHover: theme.darkColors.primaryHover,
|
|
9401
|
-
background: theme.darkColors.background,
|
|
9402
|
-
backgroundAlt: theme.darkColors.backgroundAlt,
|
|
9403
|
-
text: theme.darkColors.text,
|
|
9404
|
-
textMuted: theme.darkColors.textMuted,
|
|
9405
|
-
border: theme.darkColors.border,
|
|
9406
|
-
codeBackground: theme.darkColors.codeBackground,
|
|
9407
|
-
codeText: theme.darkColors.codeText
|
|
9408
|
-
} : void 0,
|
|
9409
|
-
fonts: theme.fonts.sans ? {
|
|
9410
|
-
sans: theme.fonts.sans,
|
|
9411
|
-
mono: theme.fonts.mono
|
|
9412
|
-
} : void 0,
|
|
9413
|
-
entryPage: theme.entryPage.mode ? { mode: theme.entryPage.mode } : void 0,
|
|
9414
|
-
layout: theme.layout.sidebarWidth ? {
|
|
9415
|
-
sidebarWidth: theme.layout.sidebarWidth,
|
|
9416
|
-
headerHeight: theme.layout.headerHeight,
|
|
9417
|
-
maxContentWidth: theme.layout.maxContentWidth
|
|
9418
|
-
} : void 0,
|
|
9419
|
-
header: theme.header.logo || theme.header.logoLight || theme.header.logoDark ? {
|
|
9420
|
-
logo: theme.header.logo,
|
|
9421
|
-
logoLight: theme.header.logoLight,
|
|
9422
|
-
logoDark: theme.header.logoDark,
|
|
9423
|
-
showSiteNameText: theme.header.showSiteNameText,
|
|
9424
|
-
logoWidth: theme.header.logoWidth,
|
|
9425
|
-
logoHeight: theme.header.logoHeight
|
|
9426
|
-
} : void 0,
|
|
9427
|
-
footer: theme.footer.message || theme.footer.copyright ? {
|
|
9428
|
-
message: theme.footer.message,
|
|
9429
|
-
copyright: theme.footer.copyright
|
|
9430
|
-
} : void 0,
|
|
9431
|
-
socialLinks,
|
|
9432
|
-
embed: Object.keys(theme.embed).length > 0 ? theme.embed : void 0,
|
|
9433
|
-
css: theme.css || void 0,
|
|
9434
|
-
js: theme.js || void 0
|
|
9435
|
-
};
|
|
9436
|
-
}
|
|
9437
|
-
function socialLinksToNapi(links) {
|
|
9438
|
-
if (Array.isArray(links)) {
|
|
9439
|
-
const items = links.map((item) => {
|
|
9440
|
-
return {
|
|
9441
|
-
icon: typeof item.icon === "string" ? item.icon : void 0,
|
|
9442
|
-
iconSvg: typeof item.icon === "object" ? item.icon.svg : void 0,
|
|
9443
|
-
link: item.link,
|
|
9444
|
-
ariaLabel: item.ariaLabel
|
|
9445
|
-
};
|
|
9446
|
-
});
|
|
9447
|
-
return items.length > 0 ? { links: items } : void 0;
|
|
9448
|
-
}
|
|
9449
|
-
return links.github || links.twitter || links.discord ? {
|
|
9450
|
-
github: links.github,
|
|
9451
|
-
twitter: links.twitter,
|
|
9452
|
-
discord: links.discord
|
|
9453
|
-
} : void 0;
|
|
9454
|
-
}
|
|
9455
|
-
//#endregion
|
|
9456
8813
|
//#region src/ssg.ts
|
|
9457
8814
|
/**
|
|
9458
8815
|
* SSG (Static Site Generation) module for ox-content
|
|
@@ -10817,7 +10174,7 @@ function resolveSsgOptions(ssg) {
|
|
|
10817
10174
|
bare: false,
|
|
10818
10175
|
generateOgImage: false,
|
|
10819
10176
|
lastUpdated: false,
|
|
10820
|
-
theme: resolveTheme(void 0)
|
|
10177
|
+
theme: require_vitepress.resolveTheme(void 0)
|
|
10821
10178
|
};
|
|
10822
10179
|
return {
|
|
10823
10180
|
enabled: ssg.enabled ?? true,
|
|
@@ -10829,7 +10186,8 @@ function resolveSsgOptions(ssg) {
|
|
|
10829
10186
|
generateOgImage: ssg.generateOgImage ?? false,
|
|
10830
10187
|
lastUpdated: ssg.lastUpdated ?? false,
|
|
10831
10188
|
siteUrl: ssg.siteUrl,
|
|
10832
|
-
theme: resolveTheme(ssg.theme)
|
|
10189
|
+
theme: require_vitepress.resolveTheme(ssg.theme),
|
|
10190
|
+
navigation: ssg.navigation
|
|
10833
10191
|
};
|
|
10834
10192
|
}
|
|
10835
10193
|
/**
|
|
@@ -10857,10 +10215,7 @@ function renderTemplate(template, data) {
|
|
|
10857
10215
|
* Extracts title from content or frontmatter.
|
|
10858
10216
|
*/
|
|
10859
10217
|
function extractTitle$1(content, frontmatter) {
|
|
10860
|
-
|
|
10861
|
-
const h1Match = content.match(/<h1[^>]*>([^<]+)<\/h1>/i);
|
|
10862
|
-
if (h1Match) return h1Match[1].trim();
|
|
10863
|
-
return "Untitled";
|
|
10218
|
+
return require_mermaid.importNapiModuleSync().extractSsgTitle(content, typeof frontmatter.title === "string" ? frontmatter.title : void 0);
|
|
10864
10219
|
}
|
|
10865
10220
|
/**
|
|
10866
10221
|
* Generates bare HTML page (no navigation, no styles).
|
|
@@ -10893,7 +10248,7 @@ async function generateHtmlPage(pageData, navGroups, siteName, base, ogImage, th
|
|
|
10893
10248
|
collapsed: group.collapsed,
|
|
10894
10249
|
items: group.items.map(toRustNavItem)
|
|
10895
10250
|
}));
|
|
10896
|
-
const themeForRust = theme ? themeToNapi(theme) : void 0;
|
|
10251
|
+
const themeForRust = theme ? require_vitepress.themeToNapi(theme) : void 0;
|
|
10897
10252
|
const entryPageForRust = pageData.entryPage ? {
|
|
10898
10253
|
hero: pageData.entryPage.hero ? {
|
|
10899
10254
|
name: pageData.entryPage.hero.name,
|
|
@@ -10946,223 +10301,88 @@ async function generateHtmlPage(pageData, navGroups, siteName, base, ogImage, th
|
|
|
10946
10301
|
}))
|
|
10947
10302
|
});
|
|
10948
10303
|
}
|
|
10949
|
-
const SSG_STYLE_BLOCK_RE = /[ \t]*<!-- ox-content:styles:start -->\s*<style>([\s\S]*?)<\/style>\s*<!-- ox-content:styles:end -->/;
|
|
10950
|
-
const SSG_SCRIPT_BLOCK_RE = /[ \t]*<!-- ox-content:scripts:start -->\s*<script>([\s\S]*?)<\/script>\s*<!-- ox-content:scripts:end -->/;
|
|
10951
|
-
const FIRST_INLINE_STYLE_RE = /[ \t]*<style>([\s\S]*?)<\/style>/;
|
|
10952
|
-
const LAST_INLINE_BODY_SCRIPT_RE = /[ \t]*<script>([\s\S]*?)<\/script>\s*<\/body>/;
|
|
10953
|
-
const CSS_SECTION_RE = /\/\* ox-content:css:([a-z0-9-]+):start \*\/\s*([\s\S]*?)\s*\/\* ox-content:css:\1:end \*\//g;
|
|
10954
|
-
const SEARCH_CHUNK_RE = /\/\/ ox-content:search:start\s*([\s\S]*?)\s*\/\/ ox-content:search:end/;
|
|
10955
|
-
const SEARCH_CHUNK_PLACEHOLDER = "__OX_CONTENT_SEARCH_CHUNK__";
|
|
10956
|
-
const CORE_CSS_SECTION_NAMES = new Set(["base", "footer"]);
|
|
10957
|
-
const THEME_INLINE_CSS_MAX_BYTES = 2048;
|
|
10958
|
-
function createContentHash(content) {
|
|
10959
|
-
return (0, node_crypto.createHash)("sha256").update(content).digest("hex").slice(0, 10);
|
|
10960
|
-
}
|
|
10961
|
-
function sanitizeChunkLabel(label) {
|
|
10962
|
-
return label.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "asset";
|
|
10963
|
-
}
|
|
10964
|
-
function toPublicAssetPath(base, fileName) {
|
|
10965
|
-
return `${base.endsWith("/") ? base : `${base}/`}assets/${fileName}`;
|
|
10966
|
-
}
|
|
10967
|
-
function hasRelativeCssUrls(css) {
|
|
10968
|
-
let cursor = 0;
|
|
10969
|
-
while (cursor < css.length) {
|
|
10970
|
-
const urlIndex = css.indexOf("url(", cursor);
|
|
10971
|
-
if (urlIndex === -1) return false;
|
|
10972
|
-
let valueStart = urlIndex + 4;
|
|
10973
|
-
while (valueStart < css.length && /\s/.test(css[valueStart])) valueStart++;
|
|
10974
|
-
const quote = css[valueStart] === "\"" || css[valueStart] === "'" ? css[valueStart] : "";
|
|
10975
|
-
if (quote) valueStart++;
|
|
10976
|
-
let valueEnd = valueStart;
|
|
10977
|
-
while (valueEnd < css.length) {
|
|
10978
|
-
const char = css[valueEnd];
|
|
10979
|
-
if (quote) {
|
|
10980
|
-
if (char === "\\") {
|
|
10981
|
-
valueEnd += 2;
|
|
10982
|
-
continue;
|
|
10983
|
-
}
|
|
10984
|
-
if (char === quote) break;
|
|
10985
|
-
} else if (char === ")") break;
|
|
10986
|
-
valueEnd++;
|
|
10987
|
-
}
|
|
10988
|
-
const value = css.slice(valueStart, valueEnd).trim();
|
|
10989
|
-
if (value && !value.startsWith("data:") && !value.startsWith("http:") && !value.startsWith("https:") && !value.startsWith("//") && !value.startsWith("/") && !value.startsWith("#") && !value.startsWith("blob:") && !value.startsWith("var(")) return true;
|
|
10990
|
-
cursor = valueEnd + 1;
|
|
10991
|
-
}
|
|
10992
|
-
return false;
|
|
10993
|
-
}
|
|
10994
|
-
function createSharedAssetChunk(type, label, content, outDir, base) {
|
|
10995
|
-
const hash = createContentHash(content);
|
|
10996
|
-
const fileName = `ox-content-${sanitizeChunkLabel(label)}-${hash}.${type}`;
|
|
10997
|
-
return {
|
|
10998
|
-
outputPath: path.join(outDir, "assets", fileName),
|
|
10999
|
-
publicPath: toPublicAssetPath(base, fileName),
|
|
11000
|
-
content
|
|
11001
|
-
};
|
|
11002
|
-
}
|
|
11003
|
-
function extractCssSections(cssContent) {
|
|
11004
|
-
return Array.from(cssContent.matchAll(CSS_SECTION_RE)).map(([, name, content]) => ({
|
|
11005
|
-
name,
|
|
11006
|
-
content: content.trim()
|
|
11007
|
-
})).filter((section) => section.content.length > 0);
|
|
11008
|
-
}
|
|
11009
|
-
function getOrCreateSharedChunk(chunks, type, label, content, outDir, base) {
|
|
11010
|
-
let chunk = chunks.get(content);
|
|
11011
|
-
if (!chunk) {
|
|
11012
|
-
chunk = createSharedAssetChunk(type, label, content, outDir, base);
|
|
11013
|
-
chunks.set(content, chunk);
|
|
11014
|
-
}
|
|
11015
|
-
return chunk;
|
|
11016
|
-
}
|
|
11017
|
-
function buildStyleReplacement(cssContent, cssChunks, outDir, base) {
|
|
11018
|
-
const sections = extractCssSections(cssContent);
|
|
11019
|
-
const effectiveSections = sections.length > 0 ? sections : [{
|
|
11020
|
-
name: "css",
|
|
11021
|
-
content: cssContent.trim()
|
|
11022
|
-
}];
|
|
11023
|
-
const coreContent = effectiveSections.filter((section) => CORE_CSS_SECTION_NAMES.has(section.name)).map((section) => section.content).join("\n").trim();
|
|
11024
|
-
const fragments = [];
|
|
11025
|
-
if (coreContent) {
|
|
11026
|
-
const coreChunk = getOrCreateSharedChunk(cssChunks, "css", "core", coreContent, outDir, base);
|
|
11027
|
-
fragments.push(` <link rel="stylesheet" href="${coreChunk.publicPath}">`);
|
|
11028
|
-
}
|
|
11029
|
-
for (const section of effectiveSections) {
|
|
11030
|
-
if (CORE_CSS_SECTION_NAMES.has(section.name)) continue;
|
|
11031
|
-
if (section.name === "theme" && (hasRelativeCssUrls(section.content) || section.content.length <= THEME_INLINE_CSS_MAX_BYTES) || hasRelativeCssUrls(section.content)) {
|
|
11032
|
-
fragments.push(` <style>${section.content}</style>`);
|
|
11033
|
-
continue;
|
|
11034
|
-
}
|
|
11035
|
-
const chunk = getOrCreateSharedChunk(cssChunks, "css", section.name, section.content, outDir, base);
|
|
11036
|
-
fragments.push(` <link rel="stylesheet" href="${chunk.publicPath}">`);
|
|
11037
|
-
}
|
|
11038
|
-
return fragments.join("\n");
|
|
11039
|
-
}
|
|
11040
|
-
function buildScriptReplacement(jsContent, jsChunks, outDir, base) {
|
|
11041
|
-
const searchMatch = jsContent.match(SEARCH_CHUNK_RE);
|
|
11042
|
-
if (searchMatch && jsContent.includes(SEARCH_CHUNK_PLACEHOLDER)) {
|
|
11043
|
-
const searchContent = searchMatch[1].trim();
|
|
11044
|
-
if (searchContent) {
|
|
11045
|
-
const searchChunk = getOrCreateSharedChunk(jsChunks, "js", "search", searchContent, outDir, base);
|
|
11046
|
-
const coreContent = jsContent.replace(SEARCH_CHUNK_RE, "").replaceAll(SEARCH_CHUNK_PLACEHOLDER, searchChunk.publicPath).trim();
|
|
11047
|
-
if (coreContent) return ` <script defer src="${getOrCreateSharedChunk(jsChunks, "js", "core", coreContent, outDir, base).publicPath}"><\/script>`;
|
|
11048
|
-
}
|
|
11049
|
-
}
|
|
11050
|
-
const fallbackContent = jsContent.trim();
|
|
11051
|
-
if (!fallbackContent) return "";
|
|
11052
|
-
return ` <script defer src="${getOrCreateSharedChunk(jsChunks, "js", "js", fallbackContent, outDir, base).publicPath}"><\/script>`;
|
|
11053
|
-
}
|
|
11054
10304
|
async function externalizeSharedPageAssets(pages, outDir, base) {
|
|
11055
|
-
const
|
|
11056
|
-
|
|
11057
|
-
|
|
11058
|
-
|
|
11059
|
-
const styleMatch = html.match(SSG_STYLE_BLOCK_RE);
|
|
11060
|
-
if (styleMatch) {
|
|
11061
|
-
const replacement = buildStyleReplacement(styleMatch[1], cssChunks, outDir, base);
|
|
11062
|
-
html = html.replace(SSG_STYLE_BLOCK_RE, replacement);
|
|
11063
|
-
} else {
|
|
11064
|
-
const inlineStyleMatch = html.match(FIRST_INLINE_STYLE_RE);
|
|
11065
|
-
if (inlineStyleMatch) {
|
|
11066
|
-
const replacement = buildStyleReplacement(inlineStyleMatch[1], cssChunks, outDir, base);
|
|
11067
|
-
html = html.replace(FIRST_INLINE_STYLE_RE, replacement);
|
|
11068
|
-
}
|
|
11069
|
-
}
|
|
11070
|
-
const scriptMatch = html.match(SSG_SCRIPT_BLOCK_RE);
|
|
11071
|
-
if (scriptMatch) {
|
|
11072
|
-
const replacement = buildScriptReplacement(scriptMatch[1], jsChunks, outDir, base);
|
|
11073
|
-
html = html.replace(SSG_SCRIPT_BLOCK_RE, replacement);
|
|
11074
|
-
} else {
|
|
11075
|
-
const inlineScriptMatch = html.match(LAST_INLINE_BODY_SCRIPT_RE);
|
|
11076
|
-
if (inlineScriptMatch) {
|
|
11077
|
-
const replacement = buildScriptReplacement(inlineScriptMatch[1], jsChunks, outDir, base);
|
|
11078
|
-
html = html.replace(LAST_INLINE_BODY_SCRIPT_RE, replacement ? `${replacement}\n</body>` : "</body>");
|
|
11079
|
-
}
|
|
11080
|
-
}
|
|
11081
|
-
return {
|
|
11082
|
-
...page,
|
|
11083
|
-
html
|
|
11084
|
-
};
|
|
11085
|
-
});
|
|
11086
|
-
const chunks = [...cssChunks.values(), ...jsChunks.values()];
|
|
11087
|
-
await Promise.all(chunks.map(async (chunk) => {
|
|
11088
|
-
await fs_promises.mkdir(path.dirname(chunk.outputPath), { recursive: true });
|
|
11089
|
-
await fs_promises.writeFile(chunk.outputPath, chunk.content, "utf-8");
|
|
10305
|
+
const optimized = (await require_mermaid.importNapiModule()).externalizeSsgAssets(pages, outDir, base);
|
|
10306
|
+
await Promise.all(optimized.assets.map(async (asset) => {
|
|
10307
|
+
await fs_promises.mkdir(path.dirname(asset.outputPath), { recursive: true });
|
|
10308
|
+
await fs_promises.writeFile(asset.outputPath, asset.content, "utf-8");
|
|
11090
10309
|
}));
|
|
11091
10310
|
return {
|
|
11092
|
-
pages:
|
|
11093
|
-
assets:
|
|
10311
|
+
pages: optimized.pages,
|
|
10312
|
+
assets: optimized.assets.map((asset) => asset.outputPath)
|
|
11094
10313
|
};
|
|
11095
10314
|
}
|
|
11096
10315
|
/**
|
|
11097
|
-
* Converts a markdown file path to its corresponding HTML output path.
|
|
11098
|
-
*/
|
|
11099
|
-
function getOutputPath(inputPath, srcDir, outDir, extension) {
|
|
11100
|
-
const baseName = path.relative(srcDir, inputPath).replace(/\.(?:md|markdown)$/i, extension);
|
|
11101
|
-
if (baseName.endsWith(`index${extension}`)) return path.join(outDir, baseName);
|
|
11102
|
-
const dirName = baseName.replace(new RegExp(`\\${extension}$`), "");
|
|
11103
|
-
return path.join(outDir, dirName, `index${extension}`);
|
|
11104
|
-
}
|
|
11105
|
-
/**
|
|
11106
10316
|
* Converts a markdown file path to a relative URL path.
|
|
11107
10317
|
*/
|
|
11108
10318
|
function getUrlPath$1(inputPath, srcDir) {
|
|
11109
|
-
|
|
11110
|
-
if (baseName === "index" || baseName.endsWith("/index")) return baseName.replace(/\/?index$/, "") || "/";
|
|
11111
|
-
return baseName;
|
|
10319
|
+
return require_mermaid.importNapiModuleSync().getSsgUrlPath(inputPath, srcDir);
|
|
11112
10320
|
}
|
|
11113
|
-
|
|
11114
|
-
|
|
11115
|
-
*/
|
|
11116
|
-
function getHref(inputPath, srcDir, base, extension) {
|
|
11117
|
-
const urlPath = getUrlPath$1(inputPath, srcDir);
|
|
11118
|
-
if (urlPath === "/" || urlPath === "") return `${base}index${extension}`;
|
|
11119
|
-
return `${base}${urlPath}/index${extension}`;
|
|
10321
|
+
function isExternalHref(value) {
|
|
10322
|
+
return /^[a-z][a-z0-9+.-]*:/i.test(value) || value.startsWith("//");
|
|
11120
10323
|
}
|
|
11121
|
-
function
|
|
11122
|
-
|
|
11123
|
-
|
|
11124
|
-
|
|
10324
|
+
function splitHrefSuffix(value) {
|
|
10325
|
+
const match = /^([^?#]*)([?#].*)?$/.exec(value);
|
|
10326
|
+
return {
|
|
10327
|
+
pathname: match?.[1] ?? value,
|
|
10328
|
+
suffix: match?.[2] ?? ""
|
|
10329
|
+
};
|
|
11125
10330
|
}
|
|
11126
|
-
|
|
11127
|
-
|
|
11128
|
-
|
|
11129
|
-
|
|
11130
|
-
|
|
11131
|
-
if (
|
|
11132
|
-
|
|
11133
|
-
|
|
11134
|
-
|
|
11135
|
-
|
|
10331
|
+
function normalizeNavigationPath(value) {
|
|
10332
|
+
const { pathname, suffix } = splitHrefSuffix(value.trim());
|
|
10333
|
+
let normalized = pathname || "/";
|
|
10334
|
+
if (!normalized.startsWith("/")) normalized = `/${normalized}`;
|
|
10335
|
+
normalized = normalized.replace(/\/index(?:\.(?:html?|md|markdown))?$/i, "/").replace(/\.(?:html?|md|markdown)$/i, "");
|
|
10336
|
+
if (normalized !== "/") normalized = normalized.replace(/\/+$/, "");
|
|
10337
|
+
return {
|
|
10338
|
+
path: normalized || "/",
|
|
10339
|
+
suffix
|
|
10340
|
+
};
|
|
11136
10341
|
}
|
|
11137
|
-
|
|
11138
|
-
|
|
11139
|
-
|
|
11140
|
-
*/
|
|
11141
|
-
function getOgImageUrl(inputPath, srcDir, base, siteUrl) {
|
|
11142
|
-
const urlPath = getUrlPath$1(inputPath, srcDir);
|
|
11143
|
-
let relativePath;
|
|
11144
|
-
if (urlPath === "/" || urlPath === "") relativePath = `${base}og-image.png`;
|
|
11145
|
-
else relativePath = `${base}${urlPath}/og-image.png`;
|
|
11146
|
-
if (siteUrl) return `${siteUrl.replace(/\/$/, "")}${relativePath}`;
|
|
11147
|
-
return relativePath;
|
|
10342
|
+
function buildHrefFromNavigationPath(pathname, base, extension) {
|
|
10343
|
+
if (pathname === "/" || pathname === "") return `${base}index${extension}`;
|
|
10344
|
+
return `${base}${pathname.replace(/^\/+/, "")}/index${extension}`;
|
|
11148
10345
|
}
|
|
11149
10346
|
/**
|
|
11150
|
-
*
|
|
10347
|
+
* Resolves manual navigation config to the format used by the built-in SSG renderer.
|
|
11151
10348
|
*/
|
|
11152
|
-
function
|
|
11153
|
-
|
|
11154
|
-
|
|
11155
|
-
|
|
11156
|
-
|
|
11157
|
-
|
|
11158
|
-
|
|
11159
|
-
|
|
10349
|
+
function resolveNavigationGroups(navigation, base, extension) {
|
|
10350
|
+
if (!navigation) return;
|
|
10351
|
+
return navigation.map((group) => ({
|
|
10352
|
+
title: group.title,
|
|
10353
|
+
items: group.items.flatMap((item) => {
|
|
10354
|
+
const rawHref = item.href ?? item.path;
|
|
10355
|
+
if (!rawHref) return [];
|
|
10356
|
+
if (isExternalHref(rawHref) || rawHref.startsWith("#")) return [{
|
|
10357
|
+
title: item.title,
|
|
10358
|
+
path: item.path ?? rawHref,
|
|
10359
|
+
href: rawHref
|
|
10360
|
+
}];
|
|
10361
|
+
const { path: path$2 } = normalizeNavigationPath(item.path ?? rawHref);
|
|
10362
|
+
const href = item.href ? (() => {
|
|
10363
|
+
const normalized = normalizeNavigationPath(item.href);
|
|
10364
|
+
return `${buildHrefFromNavigationPath(normalized.path, base, extension)}${normalized.suffix}`;
|
|
10365
|
+
})() : buildHrefFromNavigationPath(path$2, base, extension);
|
|
10366
|
+
return [{
|
|
10367
|
+
title: item.title,
|
|
10368
|
+
path: path$2,
|
|
10369
|
+
href
|
|
10370
|
+
}];
|
|
10371
|
+
})
|
|
10372
|
+
}));
|
|
10373
|
+
}
|
|
10374
|
+
function getPageLocale(urlPath, i18n) {
|
|
10375
|
+
if (!i18n) return void 0;
|
|
10376
|
+
return require_mermaid.importNapiModuleSync().getSsgPageLocale(urlPath, i18n.defaultLocale, i18n.locales.map((locale) => locale.code)) ?? void 0;
|
|
10377
|
+
}
|
|
10378
|
+
function getRoutePaths(inputPath, srcDir, outDir, base, extension, siteUrl) {
|
|
10379
|
+
return require_mermaid.importNapiModuleSync().resolveSsgRoutePaths(inputPath, srcDir, outDir, base, extension, siteUrl);
|
|
11160
10380
|
}
|
|
11161
10381
|
/**
|
|
11162
10382
|
* Formats a file/dir name as a title.
|
|
11163
10383
|
*/
|
|
11164
10384
|
function formatTitle(name) {
|
|
11165
|
-
return
|
|
10385
|
+
return require_mermaid.importNapiModuleSync().formatSsgTitle(name);
|
|
11166
10386
|
}
|
|
11167
10387
|
/**
|
|
11168
10388
|
* Collects all markdown files from the source directory.
|
|
@@ -11181,110 +10401,13 @@ async function collectMarkdownFiles$1(srcDir) {
|
|
|
11181
10401
|
* Builds navigation items from markdown files, grouped by directory.
|
|
11182
10402
|
*/
|
|
11183
10403
|
function buildNavItems(markdownFiles, srcDir, base, extension) {
|
|
11184
|
-
|
|
11185
|
-
const groupOrder = [
|
|
11186
|
-
"",
|
|
11187
|
-
"examples",
|
|
11188
|
-
"packages",
|
|
11189
|
-
"api"
|
|
11190
|
-
];
|
|
11191
|
-
for (const file of markdownFiles) {
|
|
11192
|
-
const parts = path.relative(srcDir, file).split(path.sep);
|
|
11193
|
-
let groupKey = "";
|
|
11194
|
-
if (parts.length > 1) groupKey = parts[0];
|
|
11195
|
-
if (!groups.has(groupKey)) groups.set(groupKey, []);
|
|
11196
|
-
const urlPath = getUrlPath$1(file, srcDir);
|
|
11197
|
-
let title;
|
|
11198
|
-
if (urlPath === "/" || urlPath === "") title = "Overview";
|
|
11199
|
-
else title = getDisplayTitle(file);
|
|
11200
|
-
groups.get(groupKey).push({
|
|
11201
|
-
title,
|
|
11202
|
-
path: urlPath,
|
|
11203
|
-
href: getHref(file, srcDir, base, extension)
|
|
11204
|
-
});
|
|
11205
|
-
}
|
|
11206
|
-
const sortItems = (items) => {
|
|
11207
|
-
return items.sort((a, b) => {
|
|
11208
|
-
const aIsRoot = a.path === "/" || a.path === "";
|
|
11209
|
-
const bIsRoot = b.path === "/" || b.path === "";
|
|
11210
|
-
if (aIsRoot && !bIsRoot) return -1;
|
|
11211
|
-
if (!aIsRoot && bIsRoot) return 1;
|
|
11212
|
-
return a.title.localeCompare(b.title);
|
|
11213
|
-
});
|
|
11214
|
-
};
|
|
11215
|
-
const result = [];
|
|
11216
|
-
for (const key of groupOrder) {
|
|
11217
|
-
const items = groups.get(key);
|
|
11218
|
-
if (items && items.length > 0) {
|
|
11219
|
-
result.push({
|
|
11220
|
-
title: key === "" ? "Guide" : formatTitle(key),
|
|
11221
|
-
items: sortItems(items)
|
|
11222
|
-
});
|
|
11223
|
-
groups.delete(key);
|
|
11224
|
-
}
|
|
11225
|
-
}
|
|
11226
|
-
for (const [key, items] of groups) if (items.length > 0) result.push({
|
|
11227
|
-
title: formatTitle(key),
|
|
11228
|
-
items: sortItems(items)
|
|
11229
|
-
});
|
|
11230
|
-
return result;
|
|
11231
|
-
}
|
|
11232
|
-
function isSafeSidebarLink(link) {
|
|
11233
|
-
const trimmed = link.trim();
|
|
11234
|
-
if (trimmed.startsWith("//")) return false;
|
|
11235
|
-
return !/^[a-z][a-z0-9+.-]*:/i.test(trimmed) || /^(https?:|mailto:)/i.test(trimmed);
|
|
11236
|
-
}
|
|
11237
|
-
function sidebarPath(link) {
|
|
11238
|
-
if (!link || !isSafeSidebarLink(link)) return "";
|
|
11239
|
-
if (/^(https?:|mailto:|#)/i.test(link.trim())) return "";
|
|
11240
|
-
const bare = link.trim().split("#", 1)[0].split("?", 1)[0].replace(/^\/+/, "").replace(/\/$/, "").replace(/\.(md|markdown)$/i, "");
|
|
11241
|
-
if (!bare || bare === "index") return "/";
|
|
11242
|
-
return bare.replace(/\/index$/, "");
|
|
11243
|
-
}
|
|
11244
|
-
function sidebarHref(link, base, extension) {
|
|
11245
|
-
if (!link) return "#";
|
|
11246
|
-
const trimmed = link.trim();
|
|
11247
|
-
if (!isSafeSidebarLink(trimmed)) return "#";
|
|
11248
|
-
if (/^(https?:|mailto:|#)/i.test(trimmed)) return trimmed;
|
|
11249
|
-
const hash = trimmed.includes("#") ? `#${trimmed.split("#").slice(1).join("#")}` : "";
|
|
11250
|
-
const withoutExt = trimmed.split("#", 1)[0].replace(/^\/+/, "").replace(/\/$/, "").replace(/\.(md|markdown)$/i, "");
|
|
11251
|
-
return `${base}${!withoutExt || withoutExt === "index" ? "index" : `${withoutExt.replace(/\/index$/, "")}/index`}${extension}${hash}`;
|
|
10404
|
+
return require_mermaid.importNapiModuleSync().buildSsgNavItems(markdownFiles, srcDir, base, extension);
|
|
11252
10405
|
}
|
|
11253
10406
|
/**
|
|
11254
10407
|
* Builds navigation items from an explicit theme sidebar tree.
|
|
11255
10408
|
*/
|
|
11256
10409
|
function buildThemeNavItems(sidebar, base, extension) {
|
|
11257
|
-
|
|
11258
|
-
const navItem = {
|
|
11259
|
-
title: item.text ?? item.link ?? "Untitled",
|
|
11260
|
-
path: sidebarPath(item.link),
|
|
11261
|
-
href: sidebarHref(item.link, base, extension)
|
|
11262
|
-
};
|
|
11263
|
-
if (item.items?.length) navItem.children = item.items.map(toNavItem);
|
|
11264
|
-
if (item.collapsed !== void 0) navItem.collapsed = item.collapsed;
|
|
11265
|
-
return navItem;
|
|
11266
|
-
};
|
|
11267
|
-
const groups = [];
|
|
11268
|
-
let looseItems = [];
|
|
11269
|
-
const flushLooseItems = () => {
|
|
11270
|
-
if (looseItems.length > 0) {
|
|
11271
|
-
groups.push({
|
|
11272
|
-
title: "Guide",
|
|
11273
|
-
items: looseItems
|
|
11274
|
-
});
|
|
11275
|
-
looseItems = [];
|
|
11276
|
-
}
|
|
11277
|
-
};
|
|
11278
|
-
for (const item of sidebar) if (item.items?.length && !item.link) {
|
|
11279
|
-
flushLooseItems();
|
|
11280
|
-
groups.push({
|
|
11281
|
-
title: item.text ?? "Guide",
|
|
11282
|
-
items: item.items.map(toNavItem),
|
|
11283
|
-
collapsed: item.collapsed
|
|
11284
|
-
});
|
|
11285
|
-
} else looseItems.push(toNavItem(item));
|
|
11286
|
-
flushLooseItems();
|
|
11287
|
-
return groups;
|
|
10410
|
+
return require_mermaid.importNapiModuleSync().buildSsgThemeNavItems(sidebar, base, extension);
|
|
11288
10411
|
}
|
|
11289
10412
|
/**
|
|
11290
10413
|
* Builds all markdown files to static HTML.
|
|
@@ -11308,7 +10431,7 @@ async function buildSsg(options, root) {
|
|
|
11308
10431
|
});
|
|
11309
10432
|
} catch {}
|
|
11310
10433
|
const markdownFiles = await collectMarkdownFiles$1(srcDir);
|
|
11311
|
-
const navItems = ssgOptions.theme?.sidebar.length ? buildThemeNavItems(ssgOptions.theme.sidebar, base, ssgOptions.extension) : buildNavItems(markdownFiles, srcDir, base, ssgOptions.extension);
|
|
10434
|
+
const navItems = resolveNavigationGroups(ssgOptions.navigation, base, ssgOptions.extension) ?? (ssgOptions.theme?.sidebar.length ? buildThemeNavItems(ssgOptions.theme.sidebar, base, ssgOptions.extension) : buildNavItems(markdownFiles, srcDir, base, ssgOptions.extension));
|
|
11312
10435
|
let siteName = ssgOptions.siteName ?? "Documentation";
|
|
11313
10436
|
if (!ssgOptions.siteName) try {
|
|
11314
10437
|
const pkgPath = path.join(root, "package.json");
|
|
@@ -11327,6 +10450,7 @@ async function buildSsg(options, root) {
|
|
|
11327
10450
|
baseUrl: base,
|
|
11328
10451
|
sourcePath: inputPath
|
|
11329
10452
|
});
|
|
10453
|
+
const frontmatter = require_vitepress.normalizeVitePressFrontmatter(result.frontmatter);
|
|
11330
10454
|
let transformedHtml = result.html;
|
|
11331
10455
|
const { html: protectedHtml, svgs: mermaidSvgs } = protectMermaidSvgs(transformedHtml);
|
|
11332
10456
|
transformedHtml = protectedHtml;
|
|
@@ -11341,20 +10465,21 @@ async function buildSsg(options, root) {
|
|
|
11341
10465
|
transformedHtml = await transformAllPlugins(transformedHtml, pluginOptions);
|
|
11342
10466
|
if (hasIslands(transformedHtml)) transformedHtml = (await transformIslands(transformedHtml)).html;
|
|
11343
10467
|
transformedHtml = restoreMermaidSvgs(transformedHtml, mermaidSvgs);
|
|
11344
|
-
const title = extractTitle$1(transformedHtml,
|
|
11345
|
-
const description =
|
|
10468
|
+
const title = extractTitle$1(transformedHtml, frontmatter);
|
|
10469
|
+
const description = frontmatter.description;
|
|
10470
|
+
const routePaths = getRoutePaths(inputPath, srcDir, outDir, base, ssgOptions.extension, ssgOptions.siteUrl);
|
|
11346
10471
|
pageResults.push({
|
|
11347
10472
|
inputPath,
|
|
10473
|
+
routePaths,
|
|
11348
10474
|
transformedHtml,
|
|
11349
10475
|
title,
|
|
11350
10476
|
description,
|
|
11351
10477
|
lastUpdated: napi?.getGitLastUpdated(inputPath, root) ?? void 0,
|
|
11352
|
-
frontmatter
|
|
10478
|
+
frontmatter,
|
|
11353
10479
|
toc: result.toc
|
|
11354
10480
|
});
|
|
11355
10481
|
if (shouldGenerateOgImages) {
|
|
11356
|
-
const
|
|
11357
|
-
const { layout: _layout, ...frontmatterRest } = result.frontmatter;
|
|
10482
|
+
const { layout: _layout, ...frontmatterRest } = frontmatter;
|
|
11358
10483
|
ogImageEntries.push({
|
|
11359
10484
|
props: {
|
|
11360
10485
|
...frontmatterRest,
|
|
@@ -11362,10 +10487,10 @@ async function buildSsg(options, root) {
|
|
|
11362
10487
|
description,
|
|
11363
10488
|
siteName
|
|
11364
10489
|
},
|
|
11365
|
-
outputPath:
|
|
10490
|
+
outputPath: routePaths.ogImagePath
|
|
11366
10491
|
});
|
|
11367
10492
|
ogImageInputPaths.push(inputPath);
|
|
11368
|
-
ogImageUrlMap.set(inputPath,
|
|
10493
|
+
ogImageUrlMap.set(inputPath, routePaths.ogImageUrl);
|
|
11369
10494
|
}
|
|
11370
10495
|
} catch (err) {
|
|
11371
10496
|
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
@@ -11394,7 +10519,7 @@ async function buildSsg(options, root) {
|
|
|
11394
10519
|
ogImageUrlMap.clear();
|
|
11395
10520
|
}
|
|
11396
10521
|
for (const pageResult of pageResults) try {
|
|
11397
|
-
const { inputPath, transformedHtml, title, description, lastUpdated, frontmatter, toc } = pageResult;
|
|
10522
|
+
const { inputPath, routePaths, transformedHtml, title, description, lastUpdated, frontmatter, toc } = pageResult;
|
|
11398
10523
|
let pageOgImage = ssgOptions.ogImage;
|
|
11399
10524
|
if (shouldGenerateOgImages && ogImageUrlMap.has(inputPath)) pageOgImage = ogImageUrlMap.get(inputPath);
|
|
11400
10525
|
let entryPage;
|
|
@@ -11412,16 +10537,15 @@ async function buildSsg(options, root) {
|
|
|
11412
10537
|
toc,
|
|
11413
10538
|
lastUpdated,
|
|
11414
10539
|
frontmatter,
|
|
11415
|
-
path:
|
|
11416
|
-
href:
|
|
10540
|
+
path: routePaths.urlPath,
|
|
10541
|
+
href: routePaths.href,
|
|
11417
10542
|
entryPage
|
|
11418
10543
|
};
|
|
11419
10544
|
html = await generateHtmlPage(pageData, navItems, siteName, base, pageOgImage, ssgOptions.theme, getPageLocale(pageData.path, options.i18n), options.i18n ? options.i18n.locales : void 0);
|
|
11420
10545
|
}
|
|
11421
|
-
const outputPath = getOutputPath(inputPath, srcDir, outDir, ssgOptions.extension);
|
|
11422
10546
|
generatedPages.push({
|
|
11423
10547
|
inputPath,
|
|
11424
|
-
outputPath,
|
|
10548
|
+
outputPath: routePaths.outputPath,
|
|
11425
10549
|
html
|
|
11426
10550
|
});
|
|
11427
10551
|
} catch (err) {
|
|
@@ -11549,234 +10673,7 @@ async function writeSearchIndex(indexJson, outDir) {
|
|
|
11549
10673
|
* This is injected into the bundle as a virtual module.
|
|
11550
10674
|
*/
|
|
11551
10675
|
function generateSearchModule(options, indexPath) {
|
|
11552
|
-
return
|
|
11553
|
-
// Search module generated by ox-content
|
|
11554
|
-
const searchOptions = ${JSON.stringify(options)};
|
|
11555
|
-
|
|
11556
|
-
let searchIndex = null;
|
|
11557
|
-
let indexPromise = null;
|
|
11558
|
-
|
|
11559
|
-
function parseScopedQuery(query) {
|
|
11560
|
-
const scopes = [];
|
|
11561
|
-
const terms = [];
|
|
11562
|
-
|
|
11563
|
-
for (const part of query.trim().split(/\\s+/).filter(Boolean)) {
|
|
11564
|
-
if (part.startsWith('@') && part.length > 1) {
|
|
11565
|
-
scopes.push(part.slice(1).toLowerCase());
|
|
11566
|
-
} else {
|
|
11567
|
-
terms.push(part);
|
|
11568
|
-
}
|
|
11569
|
-
}
|
|
11570
|
-
|
|
11571
|
-
return {
|
|
11572
|
-
text: terms.join(' ').trim(),
|
|
11573
|
-
scopes: [...new Set(scopes)],
|
|
11574
|
-
};
|
|
11575
|
-
}
|
|
11576
|
-
|
|
11577
|
-
function getScopesForDoc(doc) {
|
|
11578
|
-
const source = (doc.id || doc.url || '').replace(/^\\/+/, '').toLowerCase();
|
|
11579
|
-
const segments = source.split('/').filter(Boolean);
|
|
11580
|
-
|
|
11581
|
-
if (segments.length <= 1) {
|
|
11582
|
-
return [];
|
|
11583
|
-
}
|
|
11584
|
-
|
|
11585
|
-
const scopes = [];
|
|
11586
|
-
let current = '';
|
|
11587
|
-
for (const segment of segments.slice(0, -1)) {
|
|
11588
|
-
current = current ? current + '/' + segment : segment;
|
|
11589
|
-
scopes.push(current);
|
|
11590
|
-
}
|
|
11591
|
-
|
|
11592
|
-
return scopes;
|
|
11593
|
-
}
|
|
11594
|
-
|
|
11595
|
-
function matchesScopes(doc, scopes) {
|
|
11596
|
-
if (!scopes.length) {
|
|
11597
|
-
return true;
|
|
11598
|
-
}
|
|
11599
|
-
|
|
11600
|
-
const docScopes = new Set(getScopesForDoc(doc));
|
|
11601
|
-
return scopes.some(scope => docScopes.has(scope));
|
|
11602
|
-
}
|
|
11603
|
-
|
|
11604
|
-
// Tokenizer for queries
|
|
11605
|
-
function tokenizeQuery(text) {
|
|
11606
|
-
const tokens = [];
|
|
11607
|
-
let current = '';
|
|
11608
|
-
|
|
11609
|
-
for (const char of text) {
|
|
11610
|
-
const isCjk = /[\\u4E00-\\u9FFF\\u3400-\\u4DBF\\u3040-\\u309F\\u30A0-\\u30FF\\uAC00-\\uD7AF]/.test(char);
|
|
11611
|
-
|
|
11612
|
-
if (isCjk) {
|
|
11613
|
-
if (current) {
|
|
11614
|
-
tokens.push(current.toLowerCase());
|
|
11615
|
-
current = '';
|
|
11616
|
-
}
|
|
11617
|
-
tokens.push(char);
|
|
11618
|
-
} else if (/[a-zA-Z0-9_]/.test(char)) {
|
|
11619
|
-
current += char;
|
|
11620
|
-
} else if (current) {
|
|
11621
|
-
tokens.push(current.toLowerCase());
|
|
11622
|
-
current = '';
|
|
11623
|
-
}
|
|
11624
|
-
}
|
|
11625
|
-
|
|
11626
|
-
if (current) {
|
|
11627
|
-
tokens.push(current.toLowerCase());
|
|
11628
|
-
}
|
|
11629
|
-
|
|
11630
|
-
return tokens;
|
|
11631
|
-
}
|
|
11632
|
-
|
|
11633
|
-
// BM25 scoring
|
|
11634
|
-
function computeIdf(df, docCount) {
|
|
11635
|
-
return Math.log((docCount - df + 0.5) / (df + 0.5) + 1.0);
|
|
11636
|
-
}
|
|
11637
|
-
|
|
11638
|
-
function getFieldBoost(field) {
|
|
11639
|
-
switch (field) {
|
|
11640
|
-
case 'Title': return 10.0;
|
|
11641
|
-
case 'Heading': return 5.0;
|
|
11642
|
-
case 'Body': return 1.0;
|
|
11643
|
-
case 'Code': return 0.5;
|
|
11644
|
-
default: return 1.0;
|
|
11645
|
-
}
|
|
11646
|
-
}
|
|
11647
|
-
|
|
11648
|
-
// Load the index
|
|
11649
|
-
async function loadIndex() {
|
|
11650
|
-
if (searchIndex) return searchIndex;
|
|
11651
|
-
if (indexPromise) return indexPromise;
|
|
11652
|
-
|
|
11653
|
-
indexPromise = fetch('${indexPath}')
|
|
11654
|
-
.then(res => res.json())
|
|
11655
|
-
.then(data => {
|
|
11656
|
-
searchIndex = data;
|
|
11657
|
-
return data;
|
|
11658
|
-
})
|
|
11659
|
-
.catch(err => {
|
|
11660
|
-
console.error('[ox-content] Failed to load search index:', err);
|
|
11661
|
-
return null;
|
|
11662
|
-
});
|
|
11663
|
-
|
|
11664
|
-
return indexPromise;
|
|
11665
|
-
}
|
|
11666
|
-
|
|
11667
|
-
// Search function
|
|
11668
|
-
export async function search(query, options = {}) {
|
|
11669
|
-
const index = await loadIndex();
|
|
11670
|
-
|
|
11671
|
-
if (!index) {
|
|
11672
|
-
return [];
|
|
11673
|
-
}
|
|
11674
|
-
|
|
11675
|
-
const parsedQuery = parseScopedQuery(query);
|
|
11676
|
-
|
|
11677
|
-
if (!parsedQuery.text && parsedQuery.scopes.length === 0) {
|
|
11678
|
-
return [];
|
|
11679
|
-
}
|
|
11680
|
-
|
|
11681
|
-
const limit = options.limit ?? searchOptions.limit;
|
|
11682
|
-
const prefix = options.prefix ?? searchOptions.prefix;
|
|
11683
|
-
const tokens = tokenizeQuery(parsedQuery.text);
|
|
11684
|
-
|
|
11685
|
-
const k1 = 1.2;
|
|
11686
|
-
const b = 0.75;
|
|
11687
|
-
const docScores = new Map();
|
|
11688
|
-
|
|
11689
|
-
if (tokens.length === 0) {
|
|
11690
|
-
index.documents.forEach((doc, docIdx) => {
|
|
11691
|
-
if (matchesScopes(doc, parsedQuery.scopes)) {
|
|
11692
|
-
docScores.set(docIdx, { score: 0, matches: new Set() });
|
|
11693
|
-
}
|
|
11694
|
-
});
|
|
11695
|
-
}
|
|
11696
|
-
|
|
11697
|
-
for (let i = 0; i < tokens.length; i++) {
|
|
11698
|
-
const token = tokens[i];
|
|
11699
|
-
const isLast = i === tokens.length - 1;
|
|
11700
|
-
|
|
11701
|
-
// Find matching terms
|
|
11702
|
-
let matchingTerms = [];
|
|
11703
|
-
if (prefix && isLast && token.length >= 2) {
|
|
11704
|
-
matchingTerms = Object.keys(index.index).filter(term => term.startsWith(token));
|
|
11705
|
-
} else if (index.index[token]) {
|
|
11706
|
-
matchingTerms = [token];
|
|
11707
|
-
}
|
|
11708
|
-
|
|
11709
|
-
for (const term of matchingTerms) {
|
|
11710
|
-
const postings = index.index[term] || [];
|
|
11711
|
-
const df = index.df[term] || 1;
|
|
11712
|
-
const idf = computeIdf(df, index.doc_count);
|
|
11713
|
-
|
|
11714
|
-
for (const posting of postings) {
|
|
11715
|
-
const doc = index.documents[posting.doc_idx];
|
|
11716
|
-
if (!doc) continue;
|
|
11717
|
-
if (!matchesScopes(doc, parsedQuery.scopes)) continue;
|
|
11718
|
-
|
|
11719
|
-
const docLen = doc.body.length;
|
|
11720
|
-
const tf = posting.tf;
|
|
11721
|
-
const boost = getFieldBoost(posting.field);
|
|
11722
|
-
|
|
11723
|
-
const score = idf * ((tf * (k1 + 1.0)) / (tf + k1 * (1.0 - b + b * docLen / index.avg_dl))) * boost;
|
|
11724
|
-
|
|
11725
|
-
if (!docScores.has(posting.doc_idx)) {
|
|
11726
|
-
docScores.set(posting.doc_idx, { score: 0, matches: new Set() });
|
|
11727
|
-
}
|
|
11728
|
-
const entry = docScores.get(posting.doc_idx);
|
|
11729
|
-
entry.score += score;
|
|
11730
|
-
entry.matches.add(term);
|
|
11731
|
-
}
|
|
11732
|
-
}
|
|
11733
|
-
}
|
|
11734
|
-
|
|
11735
|
-
// Convert to results
|
|
11736
|
-
const results = Array.from(docScores.entries())
|
|
11737
|
-
.map(([docIdx, data]) => {
|
|
11738
|
-
const doc = index.documents[docIdx];
|
|
11739
|
-
const matches = Array.from(data.matches);
|
|
11740
|
-
const scopes = getScopesForDoc(doc);
|
|
11741
|
-
|
|
11742
|
-
// Generate snippet
|
|
11743
|
-
let snippet = '';
|
|
11744
|
-
if (doc.body) {
|
|
11745
|
-
const bodyLower = doc.body.toLowerCase();
|
|
11746
|
-
let firstPos = -1;
|
|
11747
|
-
for (const match of matches) {
|
|
11748
|
-
const pos = bodyLower.indexOf(match);
|
|
11749
|
-
if (pos !== -1 && (firstPos === -1 || pos < firstPos)) {
|
|
11750
|
-
firstPos = pos;
|
|
11751
|
-
}
|
|
11752
|
-
}
|
|
11753
|
-
|
|
11754
|
-
const start = firstPos === -1 ? 0 : Math.max(0, firstPos - 50);
|
|
11755
|
-
const end = Math.min(doc.body.length, start + 150);
|
|
11756
|
-
snippet = doc.body.slice(start, end);
|
|
11757
|
-
if (start > 0) snippet = '...' + snippet;
|
|
11758
|
-
if (end < doc.body.length) snippet = snippet + '...';
|
|
11759
|
-
}
|
|
11760
|
-
|
|
11761
|
-
return {
|
|
11762
|
-
id: doc.id,
|
|
11763
|
-
title: doc.title,
|
|
11764
|
-
url: doc.url,
|
|
11765
|
-
score: data.score,
|
|
11766
|
-
matches,
|
|
11767
|
-
snippet,
|
|
11768
|
-
scopes,
|
|
11769
|
-
};
|
|
11770
|
-
})
|
|
11771
|
-
.sort((a, b) => b.score - a.score || a.title.localeCompare(b.title))
|
|
11772
|
-
.slice(0, limit);
|
|
11773
|
-
|
|
11774
|
-
return results;
|
|
11775
|
-
}
|
|
11776
|
-
|
|
11777
|
-
export { searchOptions };
|
|
11778
|
-
export default { search, searchOptions, loadIndex };
|
|
11779
|
-
`;
|
|
10676
|
+
return require_mermaid.importNapiModuleSync().generateSearchModule(JSON.stringify(options), indexPath);
|
|
11780
10677
|
}
|
|
11781
10678
|
//#endregion
|
|
11782
10679
|
//#region src/dev-server.ts
|
|
@@ -11909,6 +10806,7 @@ async function renderPage$1(filePath, options, navGroups, siteName, base, root)
|
|
|
11909
10806
|
baseUrl: base,
|
|
11910
10807
|
sourcePath: filePath
|
|
11911
10808
|
});
|
|
10809
|
+
const frontmatter = require_vitepress.normalizeVitePressFrontmatter(result.frontmatter);
|
|
11912
10810
|
let transformedHtml = result.html;
|
|
11913
10811
|
const { html: protectedHtml, svgs: mermaidSvgs } = protectMermaidSvgs(transformedHtml);
|
|
11914
10812
|
transformedHtml = protectedHtml;
|
|
@@ -11922,19 +10820,19 @@ async function renderPage$1(filePath, options, navGroups, siteName, base, root)
|
|
|
11922
10820
|
});
|
|
11923
10821
|
if (hasIslands(transformedHtml)) transformedHtml = (await transformIslands(transformedHtml)).html;
|
|
11924
10822
|
transformedHtml = restoreMermaidSvgs(transformedHtml, mermaidSvgs);
|
|
11925
|
-
const title = extractTitle$1(transformedHtml,
|
|
11926
|
-
const description =
|
|
10823
|
+
const title = extractTitle$1(transformedHtml, frontmatter);
|
|
10824
|
+
const description = frontmatter.description;
|
|
11927
10825
|
let entryPage;
|
|
11928
|
-
if (
|
|
11929
|
-
hero:
|
|
11930
|
-
features:
|
|
10826
|
+
if (frontmatter.layout === "entry") entryPage = {
|
|
10827
|
+
hero: frontmatter.hero,
|
|
10828
|
+
features: frontmatter.features
|
|
11931
10829
|
};
|
|
11932
10830
|
let html = await generateHtmlPage({
|
|
11933
10831
|
title,
|
|
11934
10832
|
description,
|
|
11935
10833
|
content: transformedHtml,
|
|
11936
10834
|
toc: result.toc,
|
|
11937
|
-
frontmatter
|
|
10835
|
+
frontmatter,
|
|
11938
10836
|
path: getUrlPath$1(filePath, srcDir),
|
|
11939
10837
|
href: getUrlPath$1(filePath, srcDir) || "/",
|
|
11940
10838
|
entryPage
|
|
@@ -11965,7 +10863,10 @@ function createDevServerMiddleware(options, root, cache) {
|
|
|
11965
10863
|
return;
|
|
11966
10864
|
}
|
|
11967
10865
|
if (!cache.siteName) cache.siteName = await resolveSiteName(options, root);
|
|
11968
|
-
if (!cache.navGroups)
|
|
10866
|
+
if (!cache.navGroups) {
|
|
10867
|
+
const markdownFiles = await collectMarkdownFiles$1(srcDir);
|
|
10868
|
+
cache.navGroups = resolveNavigationGroups(options.ssg.navigation, base, options.ssg.extension) ?? (options.ssg.theme?.sidebar.length ? buildThemeNavItems(options.ssg.theme.sidebar, base, options.ssg.extension) : buildNavItems(markdownFiles, srcDir, base, options.ssg.extension));
|
|
10869
|
+
}
|
|
11969
10870
|
const html = await renderPage$1(filePath, options, cache.navGroups, cache.siteName, base, root);
|
|
11970
10871
|
cache.pages.set(filePath, html);
|
|
11971
10872
|
res.setHeader("Content-Type", "text/html");
|
|
@@ -12060,7 +10961,7 @@ async function collectPages(options, root) {
|
|
|
12060
10961
|
const generateOgImage = options.ogImage || options.ssg.generateOgImage;
|
|
12061
10962
|
for (const file of files.sort()) {
|
|
12062
10963
|
const content = fs.readFileSync(file, "utf-8");
|
|
12063
|
-
const frontmatter = parseFrontmatter(content);
|
|
10964
|
+
const frontmatter = require_vitepress.normalizeVitePressFrontmatter(parseFrontmatter(content));
|
|
12064
10965
|
if (frontmatter.layout === "entry") continue;
|
|
12065
10966
|
const title = extractTitle(content, frontmatter);
|
|
12066
10967
|
const description = typeof frontmatter.description === "string" ? frontmatter.description : "";
|
|
@@ -12432,193 +11333,18 @@ function createI18nPlugin(resolvedOptions) {
|
|
|
12432
11333
|
*/
|
|
12433
11334
|
function generateI18nModule(options, root) {
|
|
12434
11335
|
const dictDir = path.resolve(root, options.dir);
|
|
12435
|
-
const
|
|
12436
|
-
|
|
12437
|
-
|
|
11336
|
+
const config = {
|
|
11337
|
+
defaultLocale: options.defaultLocale,
|
|
11338
|
+
locales: options.locales,
|
|
11339
|
+
hideDefaultLocale: options.hideDefaultLocale
|
|
11340
|
+
};
|
|
12438
11341
|
try {
|
|
12439
11342
|
const napi = require("@ox-content/napi");
|
|
12440
|
-
if (napi.
|
|
12441
|
-
|
|
12442
|
-
|
|
12443
|
-
} else dictionariesCode = JSON.stringify(loadDictionariesFallback(options, dictDir));
|
|
12444
|
-
} catch {
|
|
12445
|
-
try {
|
|
12446
|
-
dictionariesCode = JSON.stringify(loadDictionariesFallback(options, dictDir));
|
|
12447
|
-
} catch {}
|
|
12448
|
-
}
|
|
12449
|
-
return `
|
|
12450
|
-
export const i18nConfig = {
|
|
12451
|
-
enabled: true,
|
|
12452
|
-
defaultLocale: ${defaultLocale},
|
|
12453
|
-
locales: ${localesJson},
|
|
12454
|
-
hideDefaultLocale: ${JSON.stringify(options.hideDefaultLocale)},
|
|
12455
|
-
};
|
|
12456
|
-
|
|
12457
|
-
export const dictionaries = ${dictionariesCode};
|
|
12458
|
-
|
|
12459
|
-
export function t(key, params, locale) {
|
|
12460
|
-
const dict = dictionaries[locale || i18nConfig.defaultLocale] || {};
|
|
12461
|
-
let message = dict[key];
|
|
12462
|
-
if (!message) {
|
|
12463
|
-
const fallback = dictionaries[i18nConfig.defaultLocale] || {};
|
|
12464
|
-
message = fallback[key] || key;
|
|
12465
|
-
}
|
|
12466
|
-
if (params) {
|
|
12467
|
-
for (const [k, v] of Object.entries(params)) {
|
|
12468
|
-
message = message.split('{$' + k + '}').join(String(v));
|
|
12469
|
-
}
|
|
12470
|
-
}
|
|
12471
|
-
return message;
|
|
12472
|
-
}
|
|
12473
|
-
|
|
12474
|
-
export function getLocaleFromPath(pathname) {
|
|
12475
|
-
const match = pathname.match(new RegExp('^/([A-Za-z]{2,3}(?:-[A-Za-z0-9]+)*)(/|$)'));
|
|
12476
|
-
if (match) {
|
|
12477
|
-
const code = match[1];
|
|
12478
|
-
if (i18nConfig.locales.some(l => l.code === code)) {
|
|
12479
|
-
return code;
|
|
12480
|
-
}
|
|
12481
|
-
}
|
|
12482
|
-
return i18nConfig.defaultLocale;
|
|
12483
|
-
}
|
|
12484
|
-
|
|
12485
|
-
export function localePath(pathname, locale) {
|
|
12486
|
-
const current = getLocaleFromPath(pathname);
|
|
12487
|
-
let clean = pathname;
|
|
12488
|
-
if (current !== i18nConfig.defaultLocale || !i18nConfig.hideDefaultLocale) {
|
|
12489
|
-
const prefix = '/' + current;
|
|
12490
|
-
if (clean === prefix) clean = '/';
|
|
12491
|
-
else if (clean.startsWith(prefix + '/')) clean = clean.slice(prefix.length);
|
|
12492
|
-
}
|
|
12493
|
-
if (locale === i18nConfig.defaultLocale && i18nConfig.hideDefaultLocale) {
|
|
12494
|
-
return clean || '/';
|
|
12495
|
-
}
|
|
12496
|
-
return '/' + locale + (clean.startsWith('/') ? clean : '/' + clean);
|
|
12497
|
-
}
|
|
12498
|
-
|
|
12499
|
-
const formatterCache = new Map();
|
|
12500
|
-
|
|
12501
|
-
function getFormatter(kind, locale, options) {
|
|
12502
|
-
const key = kind + ':' + locale + ':' + JSON.stringify(options || {});
|
|
12503
|
-
if (!formatterCache.has(key)) {
|
|
12504
|
-
formatterCache.set(key, new Intl[kind](locale, options));
|
|
12505
|
-
}
|
|
12506
|
-
return formatterCache.get(key);
|
|
12507
|
-
}
|
|
12508
|
-
|
|
12509
|
-
export function getLocaleMeta(locale) {
|
|
12510
|
-
const code = locale || i18nConfig.defaultLocale;
|
|
12511
|
-
return i18nConfig.locales.find(l => l.code === code) || { code, name: code, dir: 'ltr' };
|
|
12512
|
-
}
|
|
12513
|
-
|
|
12514
|
-
export function formatDate(value, options, locale) {
|
|
12515
|
-
return getFormatter('DateTimeFormat', locale || i18nConfig.defaultLocale, options).format(
|
|
12516
|
-
value instanceof Date ? value : new Date(value),
|
|
12517
|
-
);
|
|
12518
|
-
}
|
|
12519
|
-
|
|
12520
|
-
export function formatDateParts(value, options, locale) {
|
|
12521
|
-
return getFormatter('DateTimeFormat', locale || i18nConfig.defaultLocale, options).formatToParts(
|
|
12522
|
-
value instanceof Date ? value : new Date(value),
|
|
12523
|
-
);
|
|
12524
|
-
}
|
|
12525
|
-
|
|
12526
|
-
export function formatNumber(value, options, locale) {
|
|
12527
|
-
return getFormatter('NumberFormat', locale || i18nConfig.defaultLocale, options).format(value);
|
|
12528
|
-
}
|
|
12529
|
-
|
|
12530
|
-
export function formatNumberParts(value, options, locale) {
|
|
12531
|
-
return getFormatter('NumberFormat', locale || i18nConfig.defaultLocale, options).formatToParts(value);
|
|
12532
|
-
}
|
|
12533
|
-
|
|
12534
|
-
export function formatRelativeTime(value, unit, options, locale) {
|
|
12535
|
-
return getFormatter('RelativeTimeFormat', locale || i18nConfig.defaultLocale, options).format(value, unit);
|
|
12536
|
-
}
|
|
12537
|
-
|
|
12538
|
-
export function formatList(values, options, locale) {
|
|
12539
|
-
return getFormatter('ListFormat', locale || i18nConfig.defaultLocale, options).format(values);
|
|
12540
|
-
}
|
|
12541
|
-
|
|
12542
|
-
export function formatListParts(values, options, locale) {
|
|
12543
|
-
return getFormatter('ListFormat', locale || i18nConfig.defaultLocale, options).formatToParts(values);
|
|
12544
|
-
}
|
|
12545
|
-
|
|
12546
|
-
export function formatDisplayName(value, type, options, locale) {
|
|
12547
|
-
if (!Intl.DisplayNames) return String(value);
|
|
12548
|
-
const displayType = type || 'language';
|
|
12549
|
-
return getFormatter('DisplayNames', locale || i18nConfig.defaultLocale, { type: displayType, ...options }).of(value) || String(value);
|
|
12550
|
-
}
|
|
12551
|
-
|
|
12552
|
-
export function createIntl(locale, defaults = {}) {
|
|
12553
|
-
const meta = getLocaleMeta(locale);
|
|
12554
|
-
const code = meta.code;
|
|
12555
|
-
return {
|
|
12556
|
-
locale: code,
|
|
12557
|
-
meta,
|
|
12558
|
-
dir: meta.dir || 'ltr',
|
|
12559
|
-
date: (value, options) => formatDate(value, { ...defaults.date, ...options }, code),
|
|
12560
|
-
dateParts: (value, options) => formatDateParts(value, { ...defaults.date, ...options }, code),
|
|
12561
|
-
number: (value, options) => formatNumber(value, { ...defaults.number, ...options }, code),
|
|
12562
|
-
numberParts: (value, options) => formatNumberParts(value, { ...defaults.number, ...options }, code),
|
|
12563
|
-
relativeTime: (value, unit, options) => formatRelativeTime(value, unit, { ...defaults.relativeTime, ...options }, code),
|
|
12564
|
-
list: (values, options) => formatList(values, { ...defaults.list, ...options }, code),
|
|
12565
|
-
listParts: (values, options) => formatListParts(values, { ...defaults.list, ...options }, code),
|
|
12566
|
-
displayName: (value, type, options) => formatDisplayName(value, type, { ...defaults.displayName, ...options }, code),
|
|
12567
|
-
};
|
|
12568
|
-
}
|
|
12569
|
-
|
|
12570
|
-
export default {
|
|
12571
|
-
i18nConfig,
|
|
12572
|
-
dictionaries,
|
|
12573
|
-
t,
|
|
12574
|
-
getLocaleFromPath,
|
|
12575
|
-
localePath,
|
|
12576
|
-
getLocaleMeta,
|
|
12577
|
-
createIntl,
|
|
12578
|
-
formatDate,
|
|
12579
|
-
formatDateParts,
|
|
12580
|
-
formatNumber,
|
|
12581
|
-
formatNumberParts,
|
|
12582
|
-
formatRelativeTime,
|
|
12583
|
-
formatList,
|
|
12584
|
-
formatListParts,
|
|
12585
|
-
formatDisplayName,
|
|
12586
|
-
};
|
|
12587
|
-
`;
|
|
12588
|
-
}
|
|
12589
|
-
/**
|
|
12590
|
-
* Flattens a nested object into dot-separated keys.
|
|
12591
|
-
*/
|
|
12592
|
-
function flattenObject(obj, prefix, result) {
|
|
12593
|
-
for (const [key, value] of Object.entries(obj)) {
|
|
12594
|
-
const fullKey = `${prefix}.${key}`;
|
|
12595
|
-
if (typeof value === "string") result[fullKey] = value;
|
|
12596
|
-
else if (typeof value === "object" && value !== null && !Array.isArray(value)) flattenObject(value, fullKey, result);
|
|
12597
|
-
else result[fullKey] = String(value);
|
|
12598
|
-
}
|
|
12599
|
-
}
|
|
12600
|
-
/**
|
|
12601
|
-
* Fallback dictionary loading using TS-based JSON file reading.
|
|
12602
|
-
*/
|
|
12603
|
-
function loadDictionariesFallback(options, dictDir) {
|
|
12604
|
-
const dictData = {};
|
|
12605
|
-
for (const locale of options.locales) {
|
|
12606
|
-
const localeDir = path.join(dictDir, locale.code);
|
|
12607
|
-
if (!fs.existsSync(localeDir)) continue;
|
|
12608
|
-
const files = fs.readdirSync(localeDir);
|
|
12609
|
-
const localeDict = {};
|
|
12610
|
-
for (const file of files) {
|
|
12611
|
-
if (!file.endsWith(".json")) continue;
|
|
12612
|
-
const filePath = path.join(localeDir, file);
|
|
12613
|
-
const content = fs.readFileSync(filePath, "utf-8");
|
|
12614
|
-
const namespace = path.basename(file, ".json");
|
|
12615
|
-
try {
|
|
12616
|
-
flattenObject(JSON.parse(content), namespace, localeDict);
|
|
12617
|
-
} catch {}
|
|
12618
|
-
}
|
|
12619
|
-
dictData[locale.code] = localeDict;
|
|
11343
|
+
if (typeof napi.generateI18nModule === "function") return napi.generateI18nModule(dictDir, config);
|
|
11344
|
+
} catch (error) {
|
|
11345
|
+
throw new Error(`[ox-content:i18n] Failed to load @ox-content/napi for i18n module generation: ${String(error)}`);
|
|
12620
11346
|
}
|
|
12621
|
-
|
|
11347
|
+
throw new Error("[ox-content:i18n] @ox-content/napi does not expose generateI18nModule. Please rebuild the NAPI package.");
|
|
12622
11348
|
}
|
|
12623
11349
|
/**
|
|
12624
11350
|
* Collects translation keys from source files using NAPI extractTranslationKeys.
|
|
@@ -13814,9 +12540,9 @@ function resolveCodeAnnotationsOptions(options) {
|
|
|
13814
12540
|
/**
|
|
13815
12541
|
* Generates virtual module content.
|
|
13816
12542
|
*/
|
|
13817
|
-
function generateVirtualModule(path$
|
|
13818
|
-
if (path$
|
|
13819
|
-
if (path$
|
|
12543
|
+
function generateVirtualModule(path$1, options) {
|
|
12544
|
+
if (path$1 === "config") return `export default ${JSON.stringify(options)};`;
|
|
12545
|
+
if (path$1 === "runtime") {
|
|
13820
12546
|
const base = normalizeRuntimeBase(options.base);
|
|
13821
12547
|
return `
|
|
13822
12548
|
export const base = ${JSON.stringify(base)};
|
|
@@ -13871,17 +12597,20 @@ exports.buildSsg = buildSsg;
|
|
|
13871
12597
|
exports.clearRenderContext = clearRenderContext;
|
|
13872
12598
|
exports.collectGitHubRepos = require_github.collectGitHubRepos;
|
|
13873
12599
|
exports.collectOgpUrls = require_ogp.collectOgpUrls;
|
|
12600
|
+
exports.convertVitePressNav = require_vitepress.convertVitePressNav;
|
|
12601
|
+
exports.convertVitePressSidebar = require_vitepress.convertVitePressSidebar;
|
|
13874
12602
|
exports.createI18nPlugin = createI18nPlugin;
|
|
13875
12603
|
exports.createMarkdownEnvironment = createMarkdownEnvironment;
|
|
13876
12604
|
exports.createTheme = createTheme;
|
|
13877
|
-
exports.defaultTheme = defaultTheme;
|
|
13878
|
-
exports.defineTheme = defineTheme;
|
|
12605
|
+
exports.defaultTheme = require_vitepress.defaultTheme;
|
|
12606
|
+
exports.defineTheme = require_vitepress.defineTheme;
|
|
13879
12607
|
exports.each = each;
|
|
13880
12608
|
exports.extractDocs = extractDocs;
|
|
13881
12609
|
exports.extractIslandInfo = extractIslandInfo;
|
|
13882
12610
|
exports.extractVideoId = require_youtube.extractVideoId;
|
|
13883
12611
|
exports.fetchOgpData = require_ogp.fetchOgpData;
|
|
13884
12612
|
exports.fetchRepoData = require_github.fetchRepoData;
|
|
12613
|
+
exports.fromVitePressConfig = require_vitepress.fromVitePressConfig;
|
|
13885
12614
|
exports.generateFrontmatterTypes = generateFrontmatterTypes;
|
|
13886
12615
|
exports.generateHydrationScript = generateHydrationScript;
|
|
13887
12616
|
exports.generateMarkdown = generateMarkdown;
|
|
@@ -13889,6 +12618,7 @@ exports.generateOgImages = generateOgImages;
|
|
|
13889
12618
|
exports.generateTabsCSS = require_tabs.generateTabsCSS;
|
|
13890
12619
|
exports.generateTypes = generateTypes;
|
|
13891
12620
|
exports.generateVirtualModule = generateVirtualModule;
|
|
12621
|
+
exports.generateVitePressMigrationConfig = require_vitepress.generateVitePressMigrationConfig;
|
|
13892
12622
|
exports.hasIslands = hasIslands;
|
|
13893
12623
|
exports.inferType = inferType;
|
|
13894
12624
|
exports.jsx = jsx;
|
|
@@ -13897,8 +12627,9 @@ exports.lintMarkdown = lintMarkdown;
|
|
|
13897
12627
|
exports.lintMarkdownAsync = lintMarkdownAsync;
|
|
13898
12628
|
exports.lintMarkdownFile = lintMarkdownFile;
|
|
13899
12629
|
exports.lintMarkdownFiles = lintMarkdownFiles;
|
|
13900
|
-
exports.mergeThemes = mergeThemes;
|
|
12630
|
+
exports.mergeThemes = require_vitepress.mergeThemes;
|
|
13901
12631
|
exports.mermaidClientScript = require_mermaid.mermaidClientScript;
|
|
12632
|
+
exports.normalizeVitePressFrontmatter = require_vitepress.normalizeVitePressFrontmatter;
|
|
13902
12633
|
exports.oxContent = oxContent;
|
|
13903
12634
|
exports.prefetchGitHubRepos = require_github.prefetchGitHubRepos;
|
|
13904
12635
|
exports.prefetchOgpData = require_ogp.prefetchOgpData;
|
|
@@ -13911,7 +12642,7 @@ exports.resolveI18nOptions = resolveI18nOptions;
|
|
|
13911
12642
|
exports.resolveOgImageOptions = resolveOgImageOptions;
|
|
13912
12643
|
exports.resolveSearchOptions = resolveSearchOptions;
|
|
13913
12644
|
exports.resolveSsgOptions = resolveSsgOptions;
|
|
13914
|
-
exports.resolveTheme = resolveTheme;
|
|
12645
|
+
exports.resolveTheme = require_vitepress.resolveTheme;
|
|
13915
12646
|
exports.setRenderContext = setRenderContext;
|
|
13916
12647
|
exports.shouldLintMarkdownFile = shouldLintMarkdownFile;
|
|
13917
12648
|
exports.transformAllPlugins = transformAllPlugins;
|