specra 0.1.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/LICENSE.MD +21 -0
- package/README.md +157 -0
- package/dist/app/api/mdx-watch/route.d.mts +12 -0
- package/dist/app/api/mdx-watch/route.d.ts +12 -0
- package/dist/app/api/mdx-watch/route.js +98 -0
- package/dist/app/api/mdx-watch/route.js.map +1 -0
- package/dist/app/api/mdx-watch/route.mjs +71 -0
- package/dist/app/api/mdx-watch/route.mjs.map +1 -0
- package/dist/app/docs-page.d.mts +32 -0
- package/dist/app/docs-page.d.ts +32 -0
- package/dist/app/docs-page.js +4072 -0
- package/dist/app/docs-page.js.map +1 -0
- package/dist/app/docs-page.mjs +14 -0
- package/dist/app/docs-page.mjs.map +1 -0
- package/dist/app/layout.css +297 -0
- package/dist/app/layout.css.map +1 -0
- package/dist/app/layout.d.mts +19 -0
- package/dist/app/layout.d.ts +19 -0
- package/dist/app/layout.js +112 -0
- package/dist/app/layout.js.map +1 -0
- package/dist/app/layout.mjs +13 -0
- package/dist/app/layout.mjs.map +1 -0
- package/dist/chunk-DR4EPLMT.mjs +1013 -0
- package/dist/chunk-DR4EPLMT.mjs.map +1 -0
- package/dist/chunk-INL2EC72.mjs +170 -0
- package/dist/chunk-INL2EC72.mjs.map +1 -0
- package/dist/chunk-IZFGEAD6.mjs +61 -0
- package/dist/chunk-IZFGEAD6.mjs.map +1 -0
- package/dist/chunk-KTRWWAGL.mjs +50 -0
- package/dist/chunk-KTRWWAGL.mjs.map +1 -0
- package/dist/chunk-MZJHJ6BV.mjs +21 -0
- package/dist/chunk-MZJHJ6BV.mjs.map +1 -0
- package/dist/chunk-NXRIAL7T.mjs +3119 -0
- package/dist/chunk-NXRIAL7T.mjs.map +1 -0
- package/dist/components/index.d.mts +822 -0
- package/dist/components/index.d.ts +822 -0
- package/dist/components/index.js +3738 -0
- package/dist/components/index.js.map +1 -0
- package/dist/components/index.mjs +3627 -0
- package/dist/components/index.mjs.map +1 -0
- package/dist/index.css +297 -0
- package/dist/index.css.map +1 -0
- package/dist/index.d.mts +545 -0
- package/dist/index.d.ts +545 -0
- package/dist/index.js +4648 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +347 -0
- package/dist/index.mjs.map +1 -0
- package/dist/lib/index.d.mts +798 -0
- package/dist/lib/index.d.ts +798 -0
- package/dist/lib/index.js +1301 -0
- package/dist/lib/index.js.map +1 -0
- package/dist/lib/index.mjs +89 -0
- package/dist/lib/index.mjs.map +1 -0
- package/package.json +119 -0
- package/src/app/api/mdx-watch/route.ts +86 -0
- package/src/app/docs-page.tsx +212 -0
- package/src/app/layout.tsx +74 -0
- package/src/components/docs/accordion.tsx +53 -0
- package/src/components/docs/api/api-endpoint.tsx +59 -0
- package/src/components/docs/api/api-params.tsx +43 -0
- package/src/components/docs/api/api-playground.tsx +233 -0
- package/src/components/docs/api/api-reference.tsx +291 -0
- package/src/components/docs/api/api-response.tsx +48 -0
- package/src/components/docs/api/index.ts +5 -0
- package/src/components/docs/badge.tsx +22 -0
- package/src/components/docs/breadcrumb.tsx +51 -0
- package/src/components/docs/callout.tsx +109 -0
- package/src/components/docs/card.tsx +84 -0
- package/src/components/docs/category-index.tsx +112 -0
- package/src/components/docs/code-block.tsx +129 -0
- package/src/components/docs/columns.tsx +45 -0
- package/src/components/docs/componentTextProps.ts +85 -0
- package/src/components/docs/dev-mode-badge.tsx +35 -0
- package/src/components/docs/doc-layout-wrapper.tsx +54 -0
- package/src/components/docs/doc-layout.tsx +111 -0
- package/src/components/docs/doc-loading.tsx +15 -0
- package/src/components/docs/doc-metadata.tsx +55 -0
- package/src/components/docs/doc-navigation.tsx +62 -0
- package/src/components/docs/doc-tags.tsx +25 -0
- package/src/components/docs/draft-badge.tsx +10 -0
- package/src/components/docs/footer.tsx +47 -0
- package/src/components/docs/frame.tsx +22 -0
- package/src/components/docs/header.tsx +122 -0
- package/src/components/docs/hot-reload-indicator.tsx +77 -0
- package/src/components/docs/icon.tsx +70 -0
- package/src/components/docs/image-card.tsx +95 -0
- package/src/components/docs/image.tsx +73 -0
- package/src/components/docs/index.ts +48 -0
- package/src/components/docs/math.tsx +46 -0
- package/src/components/docs/mdx-components.tsx +166 -0
- package/src/components/docs/mdx-hot-reload.tsx +37 -0
- package/src/components/docs/mermaid.tsx +77 -0
- package/src/components/docs/mobile-doc-layout.tsx +115 -0
- package/src/components/docs/not-found-content.tsx +55 -0
- package/src/components/docs/search-highlight.tsx +127 -0
- package/src/components/docs/search-modal.tsx +223 -0
- package/src/components/docs/sidebar-skeleton.tsx +39 -0
- package/src/components/docs/sidebar.tsx +323 -0
- package/src/components/docs/site-banner.tsx +92 -0
- package/src/components/docs/steps.tsx +29 -0
- package/src/components/docs/tab-context.tsx +28 -0
- package/src/components/docs/tab-groups.tsx +50 -0
- package/src/components/docs/table-of-contents.tsx +104 -0
- package/src/components/docs/tabs.tsx +63 -0
- package/src/components/docs/theme-toggle.tsx +39 -0
- package/src/components/docs/tooltip.tsx +37 -0
- package/src/components/docs/version-switcher.tsx +52 -0
- package/src/components/docs/video.tsx +80 -0
- package/src/components/global/index.ts +3 -0
- package/src/components/global/version-not-found.tsx +26 -0
- package/src/components/index.ts +8 -0
- package/src/components/theme-provider.tsx +11 -0
- package/src/components/ui/badge.tsx +46 -0
- package/src/components/ui/button.tsx +60 -0
- package/src/components/ui/dialog.tsx +143 -0
- package/src/components/ui/index.ts +6 -0
- package/src/components/ui/input.tsx +21 -0
- package/src/components/ui/textarea.tsx +18 -0
- package/src/index.ts +41 -0
- package/src/lib/api-parser.types.ts +78 -0
- package/src/lib/api.types.ts +202 -0
- package/src/lib/category.ts +71 -0
- package/src/lib/config.server.ts +170 -0
- package/src/lib/config.ts +20 -0
- package/src/lib/config.types.ts +295 -0
- package/src/lib/dev-utils.ts +75 -0
- package/src/lib/index.ts +27 -0
- package/src/lib/mdx-cache.ts +200 -0
- package/src/lib/mdx.ts +402 -0
- package/src/lib/parsers/base-parser.ts +16 -0
- package/src/lib/parsers/index.ts +69 -0
- package/src/lib/parsers/openapi-parser.ts +251 -0
- package/src/lib/parsers/postman-parser.ts +301 -0
- package/src/lib/parsers/specra-parser.ts +24 -0
- package/src/lib/redirects.ts +40 -0
- package/src/lib/remark-code-meta.ts +23 -0
- package/src/lib/sidebar-utils.ts +188 -0
- package/src/lib/toc.ts +24 -0
- package/src/lib/utils.ts +36 -0
- package/src/specra.config.json +124 -0
- package/src/styles/globals.css +427 -0
|
@@ -0,0 +1,1301 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/lib/index.ts
|
|
31
|
+
var lib_exports = {};
|
|
32
|
+
__export(lib_exports, {
|
|
33
|
+
OpenApiParser: () => OpenApiParser,
|
|
34
|
+
PerfTimer: () => PerfTimer,
|
|
35
|
+
PostmanParser: () => PostmanParser,
|
|
36
|
+
SpecraParser: () => SpecraParser,
|
|
37
|
+
buildRedirectMappings: () => buildRedirectMappings,
|
|
38
|
+
buildSidebarStructure: () => buildSidebarStructure,
|
|
39
|
+
clearAllCaches: () => clearAllCaches,
|
|
40
|
+
cn: () => cn,
|
|
41
|
+
debugLog: () => debugLog,
|
|
42
|
+
defaultConfig: () => defaultConfig,
|
|
43
|
+
detectParserType: () => detectParserType,
|
|
44
|
+
extractHeadings: () => extractHeadings,
|
|
45
|
+
extractTableOfContents: () => extractTableOfContents,
|
|
46
|
+
findRedirect: () => findRedirect,
|
|
47
|
+
getAdjacentDocs: () => getAdjacentDocs,
|
|
48
|
+
getAllCategoryConfigs: () => getAllCategoryConfigs,
|
|
49
|
+
getAllDocs: () => getAllDocs,
|
|
50
|
+
getAssetPath: () => getAssetPath,
|
|
51
|
+
getCacheStats: () => getCacheStats,
|
|
52
|
+
getCachedAllDocs: () => getCachedAllDocs,
|
|
53
|
+
getCachedDocBySlug: () => getCachedDocBySlug,
|
|
54
|
+
getCachedVersions: () => getCachedVersions,
|
|
55
|
+
getCategoryConfig: () => getCategoryConfig,
|
|
56
|
+
getConfig: () => getConfig,
|
|
57
|
+
getConfigValue: () => getConfigValue,
|
|
58
|
+
getDocBySlug: () => getDocBySlug,
|
|
59
|
+
getVersions: () => getVersions,
|
|
60
|
+
initConfig: () => initConfig,
|
|
61
|
+
isCategoryPage: () => isCategoryPage,
|
|
62
|
+
loadConfig: () => loadConfig,
|
|
63
|
+
logCacheOperation: () => logCacheOperation,
|
|
64
|
+
logFsOperation: () => logFsOperation,
|
|
65
|
+
logMemoryUsage: () => logMemoryUsage,
|
|
66
|
+
parseApiSpec: () => parseApiSpec,
|
|
67
|
+
processContentWithEnv: () => processContentWithEnv,
|
|
68
|
+
reloadConfig: () => reloadConfig,
|
|
69
|
+
replaceEnvVariables: () => replaceEnvVariables,
|
|
70
|
+
sortSidebarGroups: () => sortSidebarGroups,
|
|
71
|
+
sortSidebarItems: () => sortSidebarItems,
|
|
72
|
+
validateConfig: () => validateConfig
|
|
73
|
+
});
|
|
74
|
+
module.exports = __toCommonJS(lib_exports);
|
|
75
|
+
|
|
76
|
+
// src/lib/mdx.ts
|
|
77
|
+
var import_fs2 = __toESM(require("fs"));
|
|
78
|
+
var import_path2 = __toESM(require("path"));
|
|
79
|
+
var import_gray_matter = __toESM(require("gray-matter"));
|
|
80
|
+
|
|
81
|
+
// src/lib/category.ts
|
|
82
|
+
var import_fs = __toESM(require("fs"));
|
|
83
|
+
var import_path = __toESM(require("path"));
|
|
84
|
+
var DOCS_DIR = import_path.default.join(process.cwd(), "docs");
|
|
85
|
+
function getCategoryConfig(folderPath) {
|
|
86
|
+
try {
|
|
87
|
+
const categoryPath = import_path.default.join(folderPath, "_category_.json");
|
|
88
|
+
if (!import_fs.default.existsSync(categoryPath)) {
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
const content = import_fs.default.readFileSync(categoryPath, "utf8");
|
|
92
|
+
return JSON.parse(content);
|
|
93
|
+
} catch (error) {
|
|
94
|
+
console.error(`Error reading category config from ${folderPath}:`, error);
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
function getAllCategoryConfigs(version) {
|
|
99
|
+
const configs = /* @__PURE__ */ new Map();
|
|
100
|
+
const versionDir = import_path.default.join(DOCS_DIR, version);
|
|
101
|
+
if (!import_fs.default.existsSync(versionDir)) {
|
|
102
|
+
return configs;
|
|
103
|
+
}
|
|
104
|
+
function scanDirectory(dir, relativePath = "") {
|
|
105
|
+
const entries = import_fs.default.readdirSync(dir, { withFileTypes: true });
|
|
106
|
+
for (const entry of entries) {
|
|
107
|
+
if (entry.isDirectory()) {
|
|
108
|
+
const fullPath = import_path.default.join(dir, entry.name);
|
|
109
|
+
const relPath = relativePath ? `${relativePath}/${entry.name}` : entry.name;
|
|
110
|
+
const config = getCategoryConfig(fullPath);
|
|
111
|
+
if (config) {
|
|
112
|
+
configs.set(relPath, config);
|
|
113
|
+
}
|
|
114
|
+
scanDirectory(fullPath, relPath);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
scanDirectory(versionDir);
|
|
119
|
+
return configs;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// src/lib/sidebar-utils.ts
|
|
123
|
+
function sortSidebarItems(items) {
|
|
124
|
+
return [...items].sort((a, b) => {
|
|
125
|
+
const posA = a.sidebar_position ?? a.meta?.sidebar_position ?? a.meta?.order ?? 999;
|
|
126
|
+
const posB = b.sidebar_position ?? b.meta?.sidebar_position ?? b.meta?.order ?? 999;
|
|
127
|
+
return posA - posB;
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
function sortSidebarGroups(groups) {
|
|
131
|
+
return Object.entries(groups).sort(([, a], [, b]) => {
|
|
132
|
+
const posA = a.position ?? 999;
|
|
133
|
+
const posB = b.position ?? 999;
|
|
134
|
+
return posA - posB;
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
function buildSidebarStructure(docs) {
|
|
138
|
+
const rootGroups = {};
|
|
139
|
+
const standalone = [];
|
|
140
|
+
const categoryMetadata = /* @__PURE__ */ new Map();
|
|
141
|
+
docs.forEach((doc) => {
|
|
142
|
+
const pathParts = doc.filePath.split("/");
|
|
143
|
+
const folderPath = pathParts.length > 1 ? pathParts.slice(0, -1).join("/") : "";
|
|
144
|
+
if (folderPath && doc.categoryLabel) {
|
|
145
|
+
categoryMetadata.set(folderPath, {
|
|
146
|
+
label: doc.categoryLabel,
|
|
147
|
+
position: doc.categoryPosition,
|
|
148
|
+
icon: doc.categoryIcon,
|
|
149
|
+
collapsible: doc.categoryCollapsible,
|
|
150
|
+
collapsed: doc.categoryCollapsed
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
docs.forEach((doc) => {
|
|
155
|
+
const pathParts = doc.filePath.split("/");
|
|
156
|
+
const isIndexFile = doc.filePath.endsWith("/index") || doc.filePath === "index" || pathParts.length > 1 && doc.slug === pathParts.slice(0, -1).join("/");
|
|
157
|
+
const customGroup = doc.meta.sidebar || doc.meta.group;
|
|
158
|
+
if (customGroup) {
|
|
159
|
+
const groupName = customGroup.charAt(0).toUpperCase() + customGroup.slice(1);
|
|
160
|
+
if (!rootGroups[groupName]) {
|
|
161
|
+
rootGroups[groupName] = {
|
|
162
|
+
label: groupName,
|
|
163
|
+
path: customGroup,
|
|
164
|
+
items: [],
|
|
165
|
+
position: 999,
|
|
166
|
+
collapsible: doc.categoryCollapsible ?? true,
|
|
167
|
+
defaultCollapsed: doc.categoryCollapsed ?? false,
|
|
168
|
+
children: {}
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
if (isIndexFile) {
|
|
172
|
+
rootGroups[groupName].position = doc.categoryPosition ?? doc.meta.sidebar_position ?? 999;
|
|
173
|
+
rootGroups[groupName].icon = doc.categoryIcon;
|
|
174
|
+
} else {
|
|
175
|
+
rootGroups[groupName].items.push(doc);
|
|
176
|
+
}
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
if (pathParts.length > 1) {
|
|
180
|
+
const folderParts = pathParts.slice(0, -1);
|
|
181
|
+
let currentLevel = rootGroups;
|
|
182
|
+
let currentPath = "";
|
|
183
|
+
for (let i = 0; i < folderParts.length; i++) {
|
|
184
|
+
const folder = folderParts[i];
|
|
185
|
+
currentPath = currentPath ? `${currentPath}/${folder}` : folder;
|
|
186
|
+
const folderLabel = folder.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
187
|
+
const metadata = categoryMetadata.get(currentPath);
|
|
188
|
+
if (!currentLevel[folder]) {
|
|
189
|
+
currentLevel[folder] = {
|
|
190
|
+
label: metadata?.label ?? folderLabel,
|
|
191
|
+
path: currentPath,
|
|
192
|
+
icon: metadata?.icon,
|
|
193
|
+
items: [],
|
|
194
|
+
position: metadata?.position ?? 999,
|
|
195
|
+
collapsible: metadata?.collapsible ?? true,
|
|
196
|
+
defaultCollapsed: metadata?.collapsed ?? false,
|
|
197
|
+
children: {}
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
if (i === folderParts.length - 1) {
|
|
201
|
+
if (isIndexFile) {
|
|
202
|
+
currentLevel[folder].position = doc.categoryPosition ?? doc.meta.sidebar_position ?? currentLevel[folder].position;
|
|
203
|
+
if (doc.categoryLabel) {
|
|
204
|
+
currentLevel[folder].label = doc.categoryLabel;
|
|
205
|
+
}
|
|
206
|
+
if (doc.categoryIcon) {
|
|
207
|
+
currentLevel[folder].icon = doc.categoryIcon;
|
|
208
|
+
}
|
|
209
|
+
if (doc.categoryCollapsible !== void 0) {
|
|
210
|
+
currentLevel[folder].collapsible = doc.categoryCollapsible;
|
|
211
|
+
}
|
|
212
|
+
if (doc.categoryCollapsed !== void 0) {
|
|
213
|
+
currentLevel[folder].defaultCollapsed = doc.categoryCollapsed;
|
|
214
|
+
}
|
|
215
|
+
} else {
|
|
216
|
+
currentLevel[folder].items.push(doc);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
currentLevel = currentLevel[folder].children;
|
|
220
|
+
}
|
|
221
|
+
} else {
|
|
222
|
+
if (!isIndexFile) {
|
|
223
|
+
standalone.push(doc);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
return { rootGroups, standalone };
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// src/lib/mdx.ts
|
|
231
|
+
var DOCS_DIR2 = import_path2.default.join(process.cwd(), "docs");
|
|
232
|
+
function calculateReadingTime(content) {
|
|
233
|
+
const words = content.trim().split(/\s+/).length;
|
|
234
|
+
const minutes = Math.ceil(words / 200);
|
|
235
|
+
return { minutes, words };
|
|
236
|
+
}
|
|
237
|
+
function getVersions() {
|
|
238
|
+
try {
|
|
239
|
+
const versions = import_fs2.default.readdirSync(DOCS_DIR2);
|
|
240
|
+
return versions.filter((v) => import_fs2.default.statSync(import_path2.default.join(DOCS_DIR2, v)).isDirectory());
|
|
241
|
+
} catch (error) {
|
|
242
|
+
return ["v1.0.0"];
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
function findMdxFiles(dir, baseDir = dir) {
|
|
246
|
+
const files = [];
|
|
247
|
+
try {
|
|
248
|
+
const entries = import_fs2.default.readdirSync(dir, { withFileTypes: true });
|
|
249
|
+
for (const entry of entries) {
|
|
250
|
+
const fullPath = import_path2.default.join(dir, entry.name);
|
|
251
|
+
if (entry.isDirectory()) {
|
|
252
|
+
files.push(...findMdxFiles(fullPath, baseDir));
|
|
253
|
+
} else if (entry.isFile() && entry.name.endsWith(".mdx")) {
|
|
254
|
+
const relativePath = import_path2.default.relative(baseDir, fullPath).replace(/\\/g, "/");
|
|
255
|
+
files.push(relativePath);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
} catch (error) {
|
|
259
|
+
console.error(`Error reading directory ${dir}:`, error);
|
|
260
|
+
}
|
|
261
|
+
return files;
|
|
262
|
+
}
|
|
263
|
+
function readDocFromFile(filePath, originalSlug) {
|
|
264
|
+
try {
|
|
265
|
+
if (!import_fs2.default.existsSync(filePath)) {
|
|
266
|
+
return null;
|
|
267
|
+
}
|
|
268
|
+
const fileContents = import_fs2.default.readFileSync(filePath, "utf8");
|
|
269
|
+
const { data, content } = (0, import_gray_matter.default)(fileContents);
|
|
270
|
+
const { minutes, words } = calculateReadingTime(content);
|
|
271
|
+
let finalSlug = originalSlug;
|
|
272
|
+
if (data.slug) {
|
|
273
|
+
const customSlug = data.slug.replace(/^\//, "");
|
|
274
|
+
const parts = originalSlug.split("/");
|
|
275
|
+
if (parts.length > 1) {
|
|
276
|
+
parts[parts.length - 1] = customSlug;
|
|
277
|
+
finalSlug = parts.join("/");
|
|
278
|
+
} else {
|
|
279
|
+
finalSlug = customSlug;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
return {
|
|
283
|
+
slug: finalSlug,
|
|
284
|
+
filePath: originalSlug,
|
|
285
|
+
// Keep original file path for sidebar
|
|
286
|
+
title: data.title || originalSlug,
|
|
287
|
+
meta: {
|
|
288
|
+
...data,
|
|
289
|
+
content,
|
|
290
|
+
reading_time: minutes,
|
|
291
|
+
word_count: words
|
|
292
|
+
},
|
|
293
|
+
content
|
|
294
|
+
};
|
|
295
|
+
} catch (error) {
|
|
296
|
+
console.error(`Error reading file ${filePath}:`, error);
|
|
297
|
+
return null;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
async function getDocBySlug(slug, version = "v1.0.0") {
|
|
301
|
+
try {
|
|
302
|
+
let filePath = import_path2.default.join(DOCS_DIR2, version, `${slug}.mdx`);
|
|
303
|
+
let doc = readDocFromFile(filePath, slug);
|
|
304
|
+
if (doc) return doc;
|
|
305
|
+
filePath = import_path2.default.join(DOCS_DIR2, version, slug, "index.mdx");
|
|
306
|
+
doc = readDocFromFile(filePath, slug);
|
|
307
|
+
if (doc) return doc;
|
|
308
|
+
const versionDir = import_path2.default.join(DOCS_DIR2, version);
|
|
309
|
+
if (!import_fs2.default.existsSync(versionDir)) {
|
|
310
|
+
return null;
|
|
311
|
+
}
|
|
312
|
+
const mdxFiles = findMdxFiles(versionDir);
|
|
313
|
+
for (const file of mdxFiles) {
|
|
314
|
+
const fileSlug = file.replace(/\.mdx$/, "");
|
|
315
|
+
const testPath = import_path2.default.join(versionDir, file.endsWith("index.mdx") ? file : `${fileSlug}.mdx`);
|
|
316
|
+
const testDoc = readDocFromFile(testPath, fileSlug);
|
|
317
|
+
if (testDoc && testDoc.slug === slug) {
|
|
318
|
+
return testDoc;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
return null;
|
|
322
|
+
} catch (error) {
|
|
323
|
+
console.error(`Error reading doc ${slug}:`, error);
|
|
324
|
+
return null;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
async function getAllDocs(version = "v1.0.0") {
|
|
328
|
+
try {
|
|
329
|
+
const versionDir = import_path2.default.join(DOCS_DIR2, version);
|
|
330
|
+
if (!import_fs2.default.existsSync(versionDir)) {
|
|
331
|
+
return [];
|
|
332
|
+
}
|
|
333
|
+
const mdxFiles = findMdxFiles(versionDir);
|
|
334
|
+
const categoryConfigs = getAllCategoryConfigs(version);
|
|
335
|
+
const docs = await Promise.all(
|
|
336
|
+
mdxFiles.map(async (file) => {
|
|
337
|
+
const originalFilePath = file.replace(/\.mdx$/, "");
|
|
338
|
+
let slug = originalFilePath;
|
|
339
|
+
if (file.endsWith("/index.mdx") || file === "index.mdx") {
|
|
340
|
+
slug = import_path2.default.dirname(file).replace(/\\/g, "/");
|
|
341
|
+
if (slug === ".") slug = "";
|
|
342
|
+
}
|
|
343
|
+
const doc = await getDocBySlug(slug, version);
|
|
344
|
+
if (doc) {
|
|
345
|
+
doc.filePath = originalFilePath;
|
|
346
|
+
const folderPath = import_path2.default.dirname(originalFilePath).replace(/\\/g, "/");
|
|
347
|
+
if (folderPath !== ".") {
|
|
348
|
+
const categoryConfig = categoryConfigs.get(folderPath);
|
|
349
|
+
if (categoryConfig) {
|
|
350
|
+
doc.categoryLabel = categoryConfig.label;
|
|
351
|
+
doc.categoryPosition = categoryConfig.position ?? categoryConfig.sidebar_position;
|
|
352
|
+
doc.categoryCollapsible = categoryConfig.collapsible;
|
|
353
|
+
doc.categoryCollapsed = categoryConfig.collapsed;
|
|
354
|
+
doc.categoryIcon = categoryConfig.icon;
|
|
355
|
+
doc.categoryTabGroup = categoryConfig.tab_group;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
return doc;
|
|
360
|
+
})
|
|
361
|
+
);
|
|
362
|
+
const isDevelopment3 = process.env.NODE_ENV === "development";
|
|
363
|
+
const uniqueDocs = /* @__PURE__ */ new Map();
|
|
364
|
+
docs.filter((doc) => doc !== null).filter((doc) => isDevelopment3 || !doc.meta.draft).forEach((doc) => {
|
|
365
|
+
uniqueDocs.set(doc.slug, doc);
|
|
366
|
+
});
|
|
367
|
+
return Array.from(uniqueDocs.values()).sort((a, b) => {
|
|
368
|
+
const orderA = a.meta.sidebar_position ?? a.meta.order ?? 999;
|
|
369
|
+
const orderB = b.meta.sidebar_position ?? b.meta.order ?? 999;
|
|
370
|
+
return orderA - orderB;
|
|
371
|
+
});
|
|
372
|
+
} catch (error) {
|
|
373
|
+
console.error(`Error getting all docs for version ${version}:`, error);
|
|
374
|
+
return [];
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
function flattenSidebarOrder(rootGroups, standalone) {
|
|
378
|
+
const flatDocs = [];
|
|
379
|
+
const flattenGroup = (group) => {
|
|
380
|
+
const sortedChildren = sortSidebarGroups(group.children);
|
|
381
|
+
const sortedItems = sortSidebarItems(group.items);
|
|
382
|
+
const merged = [
|
|
383
|
+
...sortedChildren.map(([, childGroup]) => ({
|
|
384
|
+
type: "group",
|
|
385
|
+
group: childGroup,
|
|
386
|
+
position: childGroup.position
|
|
387
|
+
})),
|
|
388
|
+
...sortedItems.map((doc) => ({
|
|
389
|
+
type: "item",
|
|
390
|
+
doc,
|
|
391
|
+
position: doc.meta.sidebar_position ?? doc.meta.order ?? 999
|
|
392
|
+
}))
|
|
393
|
+
];
|
|
394
|
+
merged.sort((a, b) => a.position - b.position);
|
|
395
|
+
merged.forEach((item) => {
|
|
396
|
+
if (item.type === "group") {
|
|
397
|
+
flattenGroup(item.group);
|
|
398
|
+
} else {
|
|
399
|
+
flatDocs.push(item.doc);
|
|
400
|
+
}
|
|
401
|
+
});
|
|
402
|
+
};
|
|
403
|
+
sortSidebarItems(standalone).forEach((doc) => {
|
|
404
|
+
flatDocs.push(doc);
|
|
405
|
+
});
|
|
406
|
+
const sortedRootGroups = sortSidebarGroups(rootGroups);
|
|
407
|
+
sortedRootGroups.forEach(([, group]) => {
|
|
408
|
+
flattenGroup(group);
|
|
409
|
+
});
|
|
410
|
+
return flatDocs;
|
|
411
|
+
}
|
|
412
|
+
function getAdjacentDocs(currentSlug, allDocs) {
|
|
413
|
+
const { rootGroups, standalone } = buildSidebarStructure(allDocs);
|
|
414
|
+
const orderedDocs = flattenSidebarOrder(rootGroups, standalone);
|
|
415
|
+
const currentIndex = orderedDocs.findIndex((doc) => doc.slug === currentSlug);
|
|
416
|
+
if (currentIndex === -1) {
|
|
417
|
+
return {};
|
|
418
|
+
}
|
|
419
|
+
const currentDoc = orderedDocs[currentIndex];
|
|
420
|
+
const currentTabGroup = currentDoc.meta?.tab_group || currentDoc.categoryTabGroup;
|
|
421
|
+
const filteredDocs = orderedDocs.filter((doc) => {
|
|
422
|
+
const docTabGroup = doc.meta?.tab_group || doc.categoryTabGroup;
|
|
423
|
+
if (currentTabGroup) {
|
|
424
|
+
return docTabGroup === currentTabGroup;
|
|
425
|
+
}
|
|
426
|
+
return !docTabGroup;
|
|
427
|
+
});
|
|
428
|
+
const filteredIndex = filteredDocs.findIndex((doc) => doc.slug === currentSlug);
|
|
429
|
+
if (filteredIndex === -1) {
|
|
430
|
+
return {};
|
|
431
|
+
}
|
|
432
|
+
return {
|
|
433
|
+
previous: filteredIndex > 0 ? filteredDocs[filteredIndex - 1] : void 0,
|
|
434
|
+
next: filteredIndex < filteredDocs.length - 1 ? filteredDocs[filteredIndex + 1] : void 0
|
|
435
|
+
};
|
|
436
|
+
}
|
|
437
|
+
function extractTableOfContents(content) {
|
|
438
|
+
const headingRegex = /^(#{2,3})\s+(.+)$/gm;
|
|
439
|
+
const toc = [];
|
|
440
|
+
let match;
|
|
441
|
+
while ((match = headingRegex.exec(content)) !== null) {
|
|
442
|
+
const level = match[1].length;
|
|
443
|
+
const text = match[2];
|
|
444
|
+
const id = text.toLowerCase().replace(/\s+/g, "-").replace(/[^a-z0-9-]/g, "").replace(/^-|-$/g, "");
|
|
445
|
+
toc.push({ id, title: text, level });
|
|
446
|
+
}
|
|
447
|
+
return toc;
|
|
448
|
+
}
|
|
449
|
+
function isCategoryPage(slug, allDocs) {
|
|
450
|
+
return allDocs.some((doc) => {
|
|
451
|
+
const parts = doc.slug.split("/");
|
|
452
|
+
const docParent = parts.slice(0, -1).join("/");
|
|
453
|
+
return docParent === slug && doc.slug !== slug;
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
// src/lib/mdx-cache.ts
|
|
458
|
+
var import_fs3 = require("fs");
|
|
459
|
+
var import_path3 = require("path");
|
|
460
|
+
|
|
461
|
+
// src/lib/dev-utils.ts
|
|
462
|
+
var isDevelopment = process.env.NODE_ENV === "development";
|
|
463
|
+
var PerfTimer = class {
|
|
464
|
+
constructor(label) {
|
|
465
|
+
this.label = label;
|
|
466
|
+
this.startTime = isDevelopment ? performance.now() : 0;
|
|
467
|
+
}
|
|
468
|
+
end() {
|
|
469
|
+
if (!isDevelopment) return;
|
|
470
|
+
const duration = performance.now() - this.startTime;
|
|
471
|
+
const color = duration > 1e3 ? "\x1B[31m" : duration > 500 ? "\x1B[33m" : "\x1B[32m";
|
|
472
|
+
const reset = "\x1B[0m";
|
|
473
|
+
console.log(`${color}\u23F1\uFE0F ${this.label}: ${duration.toFixed(2)}ms${reset}`);
|
|
474
|
+
}
|
|
475
|
+
};
|
|
476
|
+
function logFsOperation(operation, path3, details) {
|
|
477
|
+
if (!isDevelopment) return;
|
|
478
|
+
console.log(`\u{1F4C1} [FS] ${operation}: ${path3}`, details || "");
|
|
479
|
+
}
|
|
480
|
+
function logCacheOperation(operation, key) {
|
|
481
|
+
if (!isDevelopment) return;
|
|
482
|
+
const emoji = operation === "hit" ? "\u2705" : operation === "miss" ? "\u274C" : "\u{1F504}";
|
|
483
|
+
console.log(`${emoji} [Cache] ${operation}: ${key}`);
|
|
484
|
+
}
|
|
485
|
+
function logMemoryUsage(label) {
|
|
486
|
+
if (!isDevelopment) return;
|
|
487
|
+
const used = process.memoryUsage();
|
|
488
|
+
const prefix = label ? `[${label}] ` : "";
|
|
489
|
+
console.log(`\u{1F4BE} ${prefix}Memory Usage:`, {
|
|
490
|
+
rss: `${Math.round(used.rss / 1024 / 1024)}MB`,
|
|
491
|
+
heapTotal: `${Math.round(used.heapTotal / 1024 / 1024)}MB`,
|
|
492
|
+
heapUsed: `${Math.round(used.heapUsed / 1024 / 1024)}MB`
|
|
493
|
+
});
|
|
494
|
+
}
|
|
495
|
+
function debugLog(label, data) {
|
|
496
|
+
if (!isDevelopment) return;
|
|
497
|
+
console.log(`
|
|
498
|
+
\u{1F50D} ${label}:`);
|
|
499
|
+
console.dir(data, { depth: null, colors: true });
|
|
500
|
+
console.log("");
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
// src/lib/mdx-cache.ts
|
|
504
|
+
var isDevelopment2 = process.env.NODE_ENV === "development";
|
|
505
|
+
var versionsCache = {
|
|
506
|
+
data: null,
|
|
507
|
+
timestamp: 0
|
|
508
|
+
};
|
|
509
|
+
var allDocsCache = /* @__PURE__ */ new Map();
|
|
510
|
+
var docBySlugCache = /* @__PURE__ */ new Map();
|
|
511
|
+
var CACHE_TTL = isDevelopment2 ? 5e3 : 6e4;
|
|
512
|
+
var watchersInitialized = false;
|
|
513
|
+
function initializeWatchers() {
|
|
514
|
+
if (!isDevelopment2 || watchersInitialized) return;
|
|
515
|
+
watchersInitialized = true;
|
|
516
|
+
const docsPath = (0, import_path3.join)(process.cwd(), "docs");
|
|
517
|
+
try {
|
|
518
|
+
(0, import_fs3.watch)(docsPath, { recursive: true }, (eventType, filename) => {
|
|
519
|
+
if (!filename) return;
|
|
520
|
+
if (filename.endsWith(".mdx") || filename.endsWith(".json")) {
|
|
521
|
+
const parts = filename.split(/[/\\]/);
|
|
522
|
+
const version = parts[0];
|
|
523
|
+
allDocsCache.delete(version);
|
|
524
|
+
const cacheKeysToDelete = [];
|
|
525
|
+
docBySlugCache.forEach((_, key) => {
|
|
526
|
+
if (key.startsWith(`${version}:`)) {
|
|
527
|
+
cacheKeysToDelete.push(key);
|
|
528
|
+
}
|
|
529
|
+
});
|
|
530
|
+
cacheKeysToDelete.forEach((key) => docBySlugCache.delete(key));
|
|
531
|
+
if (eventType === "rename") {
|
|
532
|
+
versionsCache.data = null;
|
|
533
|
+
}
|
|
534
|
+
console.log(`[MDX Cache] Invalidated cache for: ${filename}`);
|
|
535
|
+
}
|
|
536
|
+
});
|
|
537
|
+
console.log("[MDX Cache] File watchers initialized");
|
|
538
|
+
} catch (error) {
|
|
539
|
+
console.error("[MDX Cache] Failed to initialize watchers:", error);
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
function isCacheValid(timestamp) {
|
|
543
|
+
return Date.now() - timestamp < CACHE_TTL;
|
|
544
|
+
}
|
|
545
|
+
function getCachedVersions() {
|
|
546
|
+
initializeWatchers();
|
|
547
|
+
if (versionsCache.data && isCacheValid(versionsCache.timestamp)) {
|
|
548
|
+
logCacheOperation("hit", "versions");
|
|
549
|
+
return versionsCache.data;
|
|
550
|
+
}
|
|
551
|
+
logCacheOperation("miss", "versions");
|
|
552
|
+
const timer = new PerfTimer("getVersions");
|
|
553
|
+
const versions = getVersions();
|
|
554
|
+
timer.end();
|
|
555
|
+
versionsCache.data = versions;
|
|
556
|
+
versionsCache.timestamp = Date.now();
|
|
557
|
+
return versions;
|
|
558
|
+
}
|
|
559
|
+
async function getCachedAllDocs(version = "v1.0.0") {
|
|
560
|
+
initializeWatchers();
|
|
561
|
+
const cached = allDocsCache.get(version);
|
|
562
|
+
if (cached && isCacheValid(cached.timestamp)) {
|
|
563
|
+
logCacheOperation("hit", `getAllDocs:${version}`);
|
|
564
|
+
return cached.data;
|
|
565
|
+
}
|
|
566
|
+
logCacheOperation("miss", `getAllDocs:${version}`);
|
|
567
|
+
const timer = new PerfTimer(`getAllDocs(${version})`);
|
|
568
|
+
const docs = await getAllDocs(version);
|
|
569
|
+
timer.end();
|
|
570
|
+
allDocsCache.set(version, {
|
|
571
|
+
data: docs,
|
|
572
|
+
timestamp: Date.now()
|
|
573
|
+
});
|
|
574
|
+
return docs;
|
|
575
|
+
}
|
|
576
|
+
async function getCachedDocBySlug(slug, version = "v1.0.0") {
|
|
577
|
+
initializeWatchers();
|
|
578
|
+
const cacheKey = `${version}:${slug}`;
|
|
579
|
+
const cached = docBySlugCache.get(cacheKey);
|
|
580
|
+
if (cached && isCacheValid(cached.timestamp)) {
|
|
581
|
+
logCacheOperation("hit", `getDocBySlug:${cacheKey}`);
|
|
582
|
+
return cached.data;
|
|
583
|
+
}
|
|
584
|
+
logCacheOperation("miss", `getDocBySlug:${cacheKey}`);
|
|
585
|
+
const timer = new PerfTimer(`getDocBySlug(${slug})`);
|
|
586
|
+
const doc = await getDocBySlug(slug, version);
|
|
587
|
+
timer.end();
|
|
588
|
+
docBySlugCache.set(cacheKey, {
|
|
589
|
+
data: doc,
|
|
590
|
+
timestamp: Date.now()
|
|
591
|
+
});
|
|
592
|
+
return doc;
|
|
593
|
+
}
|
|
594
|
+
function clearAllCaches() {
|
|
595
|
+
versionsCache.data = null;
|
|
596
|
+
allDocsCache.clear();
|
|
597
|
+
docBySlugCache.clear();
|
|
598
|
+
console.log("[MDX Cache] All caches cleared");
|
|
599
|
+
}
|
|
600
|
+
function getCacheStats() {
|
|
601
|
+
return {
|
|
602
|
+
versions: {
|
|
603
|
+
cached: versionsCache.data !== null,
|
|
604
|
+
age: versionsCache.timestamp ? Date.now() - versionsCache.timestamp : 0
|
|
605
|
+
},
|
|
606
|
+
allDocs: {
|
|
607
|
+
entries: allDocsCache.size,
|
|
608
|
+
versions: Array.from(allDocsCache.keys())
|
|
609
|
+
},
|
|
610
|
+
docBySlug: {
|
|
611
|
+
entries: docBySlugCache.size
|
|
612
|
+
}
|
|
613
|
+
};
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
// src/lib/toc.ts
|
|
617
|
+
function extractHeadings(html) {
|
|
618
|
+
const headingRegex = /<h([2-3])[^>]*id="([^"]*)"[^>]*>(.*?)<\/h\1>/g;
|
|
619
|
+
const toc = [];
|
|
620
|
+
let match;
|
|
621
|
+
while ((match = headingRegex.exec(html)) !== null) {
|
|
622
|
+
const level = Number.parseInt(match[1]);
|
|
623
|
+
const id = match[2];
|
|
624
|
+
const title = match[3].replace(/<[^>]*>/g, "");
|
|
625
|
+
toc.push({ id, title, level });
|
|
626
|
+
}
|
|
627
|
+
return toc;
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
// src/lib/config.types.ts
|
|
631
|
+
var defaultConfig = {
|
|
632
|
+
site: {
|
|
633
|
+
title: "Documentation",
|
|
634
|
+
description: "Project documentation",
|
|
635
|
+
baseUrl: "/",
|
|
636
|
+
language: "en"
|
|
637
|
+
},
|
|
638
|
+
theme: {
|
|
639
|
+
defaultMode: "system",
|
|
640
|
+
respectPrefersColorScheme: true
|
|
641
|
+
},
|
|
642
|
+
navigation: {
|
|
643
|
+
showSidebar: true,
|
|
644
|
+
collapsibleSidebar: true,
|
|
645
|
+
showBreadcrumbs: true,
|
|
646
|
+
showTableOfContents: true,
|
|
647
|
+
tocPosition: "right",
|
|
648
|
+
tocMaxDepth: 3
|
|
649
|
+
},
|
|
650
|
+
search: {
|
|
651
|
+
enabled: true,
|
|
652
|
+
provider: "local",
|
|
653
|
+
placeholder: "Search documentation..."
|
|
654
|
+
},
|
|
655
|
+
features: {
|
|
656
|
+
showLastUpdated: true,
|
|
657
|
+
showReadingTime: true,
|
|
658
|
+
showAuthors: false,
|
|
659
|
+
showTags: true,
|
|
660
|
+
versioning: true,
|
|
661
|
+
i18n: false
|
|
662
|
+
}
|
|
663
|
+
};
|
|
664
|
+
|
|
665
|
+
// src/lib/config.server.ts
|
|
666
|
+
function deepMerge(target, source) {
|
|
667
|
+
const result = { ...target };
|
|
668
|
+
for (const key in source) {
|
|
669
|
+
const sourceValue = source[key];
|
|
670
|
+
const targetValue = result[key];
|
|
671
|
+
if (sourceValue && typeof sourceValue === "object" && !Array.isArray(sourceValue)) {
|
|
672
|
+
result[key] = deepMerge(
|
|
673
|
+
targetValue && typeof targetValue === "object" ? targetValue : {},
|
|
674
|
+
sourceValue
|
|
675
|
+
);
|
|
676
|
+
} else if (sourceValue !== void 0) {
|
|
677
|
+
result[key] = sourceValue;
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
return result;
|
|
681
|
+
}
|
|
682
|
+
function loadConfig(userConfig) {
|
|
683
|
+
try {
|
|
684
|
+
const config = deepMerge(defaultConfig, userConfig);
|
|
685
|
+
return config;
|
|
686
|
+
} catch (error) {
|
|
687
|
+
console.error(`\u274C Error loading configuration:`, error);
|
|
688
|
+
console.warn("Using default configuration.");
|
|
689
|
+
return defaultConfig;
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
function getConfigValue(path3, config) {
|
|
693
|
+
const cfg = config || loadConfig({});
|
|
694
|
+
const keys = path3.split(".");
|
|
695
|
+
let value = cfg;
|
|
696
|
+
for (const key of keys) {
|
|
697
|
+
if (value && typeof value === "object" && key in value) {
|
|
698
|
+
value = value[key];
|
|
699
|
+
} else {
|
|
700
|
+
return void 0;
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
return value;
|
|
704
|
+
}
|
|
705
|
+
function replaceEnvVariables(text, config) {
|
|
706
|
+
const cfg = config || loadConfig({});
|
|
707
|
+
const envVars = cfg.env || {};
|
|
708
|
+
let result = text;
|
|
709
|
+
result = result.replace(/\$\{([^}]+)\}/g, (match, varName) => {
|
|
710
|
+
return envVars[varName] || match;
|
|
711
|
+
});
|
|
712
|
+
result = result.replace(/\{\{([^}]+)\}\}/g, (match, varName) => {
|
|
713
|
+
return envVars[varName] || match;
|
|
714
|
+
});
|
|
715
|
+
return result;
|
|
716
|
+
}
|
|
717
|
+
function processContentWithEnv(content, config) {
|
|
718
|
+
return replaceEnvVariables(content, config);
|
|
719
|
+
}
|
|
720
|
+
function validateConfig(config) {
|
|
721
|
+
const errors = [];
|
|
722
|
+
if (!config.site?.title) {
|
|
723
|
+
errors.push("site.title is required");
|
|
724
|
+
}
|
|
725
|
+
if (config.site?.url) {
|
|
726
|
+
try {
|
|
727
|
+
new URL(config.site.url);
|
|
728
|
+
} catch {
|
|
729
|
+
errors.push("site.url must be a valid URL");
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
if (config.social) {
|
|
733
|
+
const socialKeys = ["github", "twitter", "discord", "linkedin", "youtube"];
|
|
734
|
+
for (const key of socialKeys) {
|
|
735
|
+
const url = config.social[key];
|
|
736
|
+
if (url) {
|
|
737
|
+
try {
|
|
738
|
+
new URL(url);
|
|
739
|
+
} catch {
|
|
740
|
+
errors.push(`social.${key} must be a valid URL`);
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
return {
|
|
746
|
+
valid: errors.length === 0,
|
|
747
|
+
errors
|
|
748
|
+
};
|
|
749
|
+
}
|
|
750
|
+
var configInstance = null;
|
|
751
|
+
function initConfig(userConfig) {
|
|
752
|
+
if (configInstance) {
|
|
753
|
+
throw new Error("Specra config has already been initialized");
|
|
754
|
+
}
|
|
755
|
+
configInstance = loadConfig(userConfig);
|
|
756
|
+
return configInstance;
|
|
757
|
+
}
|
|
758
|
+
function getConfig() {
|
|
759
|
+
if (!configInstance) {
|
|
760
|
+
throw new Error("Specra config has not been initialized");
|
|
761
|
+
}
|
|
762
|
+
return configInstance;
|
|
763
|
+
}
|
|
764
|
+
function reloadConfig(userConfig) {
|
|
765
|
+
configInstance = loadConfig(userConfig);
|
|
766
|
+
return configInstance;
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
// src/lib/parsers/specra-parser.ts
|
|
770
|
+
var SpecraParser = class {
|
|
771
|
+
validate(input) {
|
|
772
|
+
return typeof input === "object" && input !== null && "endpoints" in input && Array.isArray(input.endpoints);
|
|
773
|
+
}
|
|
774
|
+
parse(input) {
|
|
775
|
+
if (!this.validate(input)) {
|
|
776
|
+
throw new Error("Invalid Specra API spec format");
|
|
777
|
+
}
|
|
778
|
+
return input;
|
|
779
|
+
}
|
|
780
|
+
};
|
|
781
|
+
|
|
782
|
+
// src/lib/parsers/openapi-parser.ts
|
|
783
|
+
var OpenApiParser = class {
|
|
784
|
+
validate(input) {
|
|
785
|
+
return typeof input === "object" && input !== null && ("openapi" in input || "swagger" in input) && "paths" in input;
|
|
786
|
+
}
|
|
787
|
+
parse(input) {
|
|
788
|
+
if (!this.validate(input)) {
|
|
789
|
+
throw new Error("Invalid OpenAPI spec format");
|
|
790
|
+
}
|
|
791
|
+
const baseUrl = this.extractBaseUrl(input);
|
|
792
|
+
const endpoints = [];
|
|
793
|
+
for (const [path3, pathItem] of Object.entries(input.paths || {})) {
|
|
794
|
+
const methods = ["get", "post", "put", "patch", "delete"];
|
|
795
|
+
for (const method of methods) {
|
|
796
|
+
const operation = pathItem[method];
|
|
797
|
+
if (!operation) continue;
|
|
798
|
+
const endpoint = this.parseOperation(path3, method.toUpperCase(), operation, input);
|
|
799
|
+
endpoints.push(endpoint);
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
return {
|
|
803
|
+
version: input.info?.version,
|
|
804
|
+
title: input.info?.title,
|
|
805
|
+
description: input.info?.description,
|
|
806
|
+
baseUrl,
|
|
807
|
+
auth: this.extractAuth(input),
|
|
808
|
+
endpoints
|
|
809
|
+
};
|
|
810
|
+
}
|
|
811
|
+
extractBaseUrl(spec) {
|
|
812
|
+
if (spec.servers && spec.servers.length > 0) {
|
|
813
|
+
return spec.servers[0].url;
|
|
814
|
+
}
|
|
815
|
+
if (spec.host) {
|
|
816
|
+
const scheme = spec.schemes?.[0] || "https";
|
|
817
|
+
const basePath = spec.basePath || "";
|
|
818
|
+
return `${scheme}://${spec.host}${basePath}`;
|
|
819
|
+
}
|
|
820
|
+
return "";
|
|
821
|
+
}
|
|
822
|
+
extractAuth(spec) {
|
|
823
|
+
const securitySchemes = spec.components?.securitySchemes || spec.securityDefinitions;
|
|
824
|
+
if (!securitySchemes) return void 0;
|
|
825
|
+
const firstScheme = Object.values(securitySchemes)[0];
|
|
826
|
+
if (!firstScheme) return void 0;
|
|
827
|
+
if (firstScheme.type === "http" && firstScheme.scheme === "bearer") {
|
|
828
|
+
return {
|
|
829
|
+
type: "bearer",
|
|
830
|
+
description: firstScheme.description,
|
|
831
|
+
tokenPrefix: "Bearer"
|
|
832
|
+
};
|
|
833
|
+
}
|
|
834
|
+
if (firstScheme.type === "apiKey") {
|
|
835
|
+
return {
|
|
836
|
+
type: "apiKey",
|
|
837
|
+
description: firstScheme.description,
|
|
838
|
+
headerName: firstScheme.name || "X-API-Key"
|
|
839
|
+
};
|
|
840
|
+
}
|
|
841
|
+
if (firstScheme.type === "http" && firstScheme.scheme === "basic") {
|
|
842
|
+
return {
|
|
843
|
+
type: "basic",
|
|
844
|
+
description: firstScheme.description
|
|
845
|
+
};
|
|
846
|
+
}
|
|
847
|
+
return void 0;
|
|
848
|
+
}
|
|
849
|
+
parseOperation(path3, method, operation, spec) {
|
|
850
|
+
const endpoint = {
|
|
851
|
+
title: operation.summary || operation.operationId || `${method} ${path3}`,
|
|
852
|
+
method,
|
|
853
|
+
path: this.convertPathParams(path3),
|
|
854
|
+
description: operation.description
|
|
855
|
+
};
|
|
856
|
+
const params = this.parseParameters(operation.parameters || [], spec);
|
|
857
|
+
if (params.path.length > 0) endpoint.pathParams = params.path;
|
|
858
|
+
if (params.query.length > 0) endpoint.queryParams = params.query;
|
|
859
|
+
if (params.header.length > 0) {
|
|
860
|
+
endpoint.headers = params.header.map((p) => ({
|
|
861
|
+
name: p.name,
|
|
862
|
+
value: p.example || "",
|
|
863
|
+
description: p.description
|
|
864
|
+
}));
|
|
865
|
+
}
|
|
866
|
+
if (operation.requestBody) {
|
|
867
|
+
endpoint.body = this.parseRequestBody(operation.requestBody, spec);
|
|
868
|
+
}
|
|
869
|
+
const responses = this.parseResponses(operation.responses || {}, spec);
|
|
870
|
+
if (responses.success) endpoint.successResponse = responses.success;
|
|
871
|
+
if (responses.errors.length > 0) endpoint.errorResponses = responses.errors;
|
|
872
|
+
return endpoint;
|
|
873
|
+
}
|
|
874
|
+
convertPathParams(path3) {
|
|
875
|
+
return path3.replace(/\{([^}]+)\}/g, ":$1");
|
|
876
|
+
}
|
|
877
|
+
parseParameters(parameters, spec) {
|
|
878
|
+
const result = { path: [], query: [], header: [] };
|
|
879
|
+
for (const param of parameters) {
|
|
880
|
+
const resolved = param.$ref ? this.resolveRef(param.$ref, spec) : param;
|
|
881
|
+
const apiParam = {
|
|
882
|
+
name: resolved.name,
|
|
883
|
+
type: resolved.schema?.type || resolved.type || "string",
|
|
884
|
+
required: resolved.required,
|
|
885
|
+
description: resolved.description,
|
|
886
|
+
example: resolved.example || resolved.schema?.example
|
|
887
|
+
};
|
|
888
|
+
if (resolved.in === "path") result.path.push(apiParam);
|
|
889
|
+
else if (resolved.in === "query") result.query.push(apiParam);
|
|
890
|
+
else if (resolved.in === "header") result.header.push(apiParam);
|
|
891
|
+
}
|
|
892
|
+
return result;
|
|
893
|
+
}
|
|
894
|
+
parseRequestBody(requestBody, spec) {
|
|
895
|
+
const content = requestBody.content?.["application/json"];
|
|
896
|
+
if (!content) return void 0;
|
|
897
|
+
return {
|
|
898
|
+
description: requestBody.description,
|
|
899
|
+
example: content.example || this.generateExample(content.schema, spec),
|
|
900
|
+
schema: content.schema
|
|
901
|
+
};
|
|
902
|
+
}
|
|
903
|
+
parseResponses(responses, spec) {
|
|
904
|
+
const result = { errors: [] };
|
|
905
|
+
for (const [statusCode, response] of Object.entries(responses)) {
|
|
906
|
+
const status = parseInt(statusCode);
|
|
907
|
+
if (isNaN(status)) continue;
|
|
908
|
+
const resolved = response.$ref ? this.resolveRef(response.$ref, spec) : response;
|
|
909
|
+
const content = resolved.content?.["application/json"];
|
|
910
|
+
const apiResponse = {
|
|
911
|
+
status,
|
|
912
|
+
description: resolved.description,
|
|
913
|
+
example: content?.example || this.generateExample(content?.schema, spec),
|
|
914
|
+
schema: content?.schema
|
|
915
|
+
};
|
|
916
|
+
if (status >= 200 && status < 300) {
|
|
917
|
+
result.success = apiResponse;
|
|
918
|
+
} else {
|
|
919
|
+
result.errors.push(apiResponse);
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
return result;
|
|
923
|
+
}
|
|
924
|
+
generateExample(schema, spec) {
|
|
925
|
+
if (!schema) return void 0;
|
|
926
|
+
if (schema.$ref) schema = this.resolveRef(schema.$ref, spec);
|
|
927
|
+
if (schema.example) return schema.example;
|
|
928
|
+
if (schema.type === "object" && schema.properties) {
|
|
929
|
+
const example = {};
|
|
930
|
+
for (const [key, prop] of Object.entries(schema.properties)) {
|
|
931
|
+
example[key] = this.generateExample(prop, spec);
|
|
932
|
+
}
|
|
933
|
+
return example;
|
|
934
|
+
}
|
|
935
|
+
if (schema.type === "array" && schema.items) {
|
|
936
|
+
return [this.generateExample(schema.items, spec)];
|
|
937
|
+
}
|
|
938
|
+
const defaults = {
|
|
939
|
+
string: "string",
|
|
940
|
+
number: 0,
|
|
941
|
+
integer: 0,
|
|
942
|
+
boolean: false,
|
|
943
|
+
object: {},
|
|
944
|
+
array: []
|
|
945
|
+
};
|
|
946
|
+
return defaults[schema.type] || null;
|
|
947
|
+
}
|
|
948
|
+
resolveRef(ref, spec) {
|
|
949
|
+
const path3 = ref.replace(/^#\//, "").split("/");
|
|
950
|
+
let current = spec;
|
|
951
|
+
for (const segment of path3) {
|
|
952
|
+
current = current[segment];
|
|
953
|
+
if (!current) return {};
|
|
954
|
+
}
|
|
955
|
+
return current;
|
|
956
|
+
}
|
|
957
|
+
};
|
|
958
|
+
|
|
959
|
+
// src/lib/parsers/postman-parser.ts
|
|
960
|
+
var PostmanParser = class {
|
|
961
|
+
validate(input) {
|
|
962
|
+
return typeof input === "object" && input !== null && "info" in input && input.info?.schema?.includes("v2");
|
|
963
|
+
}
|
|
964
|
+
parse(input) {
|
|
965
|
+
if (!this.validate(input)) {
|
|
966
|
+
throw new Error("Invalid Postman Collection format (requires v2.0 or v2.1)");
|
|
967
|
+
}
|
|
968
|
+
const baseUrl = this.extractBaseUrl(input);
|
|
969
|
+
const endpoints = [];
|
|
970
|
+
this.parseItems(input.item || [], endpoints, baseUrl, input);
|
|
971
|
+
return {
|
|
972
|
+
version: input.info?.version,
|
|
973
|
+
title: input.info?.name,
|
|
974
|
+
description: input.info?.description,
|
|
975
|
+
baseUrl,
|
|
976
|
+
auth: this.extractAuth(input.auth),
|
|
977
|
+
globalHeaders: this.extractGlobalHeaders(input),
|
|
978
|
+
endpoints
|
|
979
|
+
};
|
|
980
|
+
}
|
|
981
|
+
extractBaseUrl(collection) {
|
|
982
|
+
const baseUrlVar = collection.variable?.find(
|
|
983
|
+
(v) => v.key === "baseUrl" || v.key === "base_url" || v.key === "url"
|
|
984
|
+
);
|
|
985
|
+
if (baseUrlVar) return baseUrlVar.value;
|
|
986
|
+
if (collection.item && collection.item.length > 0) {
|
|
987
|
+
const firstRequest = this.findFirstRequest(collection.item);
|
|
988
|
+
if (firstRequest?.request?.url) {
|
|
989
|
+
const url = this.parseUrl(firstRequest.request.url);
|
|
990
|
+
if (url.host) {
|
|
991
|
+
return `${url.protocol}://${url.host.join(".")}`;
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
return "";
|
|
996
|
+
}
|
|
997
|
+
findFirstRequest(items) {
|
|
998
|
+
for (const item of items) {
|
|
999
|
+
if (item.request) return item;
|
|
1000
|
+
if (item.item) {
|
|
1001
|
+
const found = this.findFirstRequest(item.item);
|
|
1002
|
+
if (found) return found;
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
return null;
|
|
1006
|
+
}
|
|
1007
|
+
extractAuth(auth) {
|
|
1008
|
+
if (!auth) return void 0;
|
|
1009
|
+
if (auth.type === "bearer") {
|
|
1010
|
+
return {
|
|
1011
|
+
type: "bearer",
|
|
1012
|
+
tokenPrefix: "Bearer"
|
|
1013
|
+
};
|
|
1014
|
+
}
|
|
1015
|
+
if (auth.type === "apikey") {
|
|
1016
|
+
const keyData = auth.apikey?.find((a) => a.key === "key");
|
|
1017
|
+
const keyName = keyData?.value || "X-API-Key";
|
|
1018
|
+
return {
|
|
1019
|
+
type: "apiKey",
|
|
1020
|
+
headerName: keyName
|
|
1021
|
+
};
|
|
1022
|
+
}
|
|
1023
|
+
if (auth.type === "basic") {
|
|
1024
|
+
return {
|
|
1025
|
+
type: "basic"
|
|
1026
|
+
};
|
|
1027
|
+
}
|
|
1028
|
+
return void 0;
|
|
1029
|
+
}
|
|
1030
|
+
extractGlobalHeaders(collection) {
|
|
1031
|
+
return [];
|
|
1032
|
+
}
|
|
1033
|
+
parseItems(items, endpoints, baseUrl, collection) {
|
|
1034
|
+
for (const item of items) {
|
|
1035
|
+
if (item.item && Array.isArray(item.item)) {
|
|
1036
|
+
this.parseItems(item.item, endpoints, baseUrl, collection);
|
|
1037
|
+
} else if (item.request) {
|
|
1038
|
+
const endpoint = this.parseRequest(item, baseUrl, collection);
|
|
1039
|
+
endpoints.push(endpoint);
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
}
|
|
1043
|
+
parseRequest(item, baseUrl, collection) {
|
|
1044
|
+
const request = item.request;
|
|
1045
|
+
const url = this.parseUrl(request.url);
|
|
1046
|
+
const endpoint = {
|
|
1047
|
+
title: item.name,
|
|
1048
|
+
method: request.method.toUpperCase(),
|
|
1049
|
+
path: this.buildPath(url, baseUrl),
|
|
1050
|
+
description: item.request.description || item.description
|
|
1051
|
+
};
|
|
1052
|
+
const params = this.parseUrlParams(url);
|
|
1053
|
+
if (params.path.length > 0) endpoint.pathParams = params.path;
|
|
1054
|
+
if (params.query.length > 0) endpoint.queryParams = params.query;
|
|
1055
|
+
if (request.header && request.header.length > 0) {
|
|
1056
|
+
endpoint.headers = request.header.filter((h) => !h.disabled).map((h) => ({
|
|
1057
|
+
name: h.key,
|
|
1058
|
+
value: h.value || "",
|
|
1059
|
+
description: h.description
|
|
1060
|
+
}));
|
|
1061
|
+
}
|
|
1062
|
+
if (request.body) {
|
|
1063
|
+
endpoint.body = this.parseBody(request.body);
|
|
1064
|
+
}
|
|
1065
|
+
const responses = this.parseResponses(item.response || []);
|
|
1066
|
+
if (responses.success) endpoint.successResponse = responses.success;
|
|
1067
|
+
if (responses.errors.length > 0) endpoint.errorResponses = responses.errors;
|
|
1068
|
+
return endpoint;
|
|
1069
|
+
}
|
|
1070
|
+
parseUrl(url) {
|
|
1071
|
+
if (typeof url === "string") {
|
|
1072
|
+
const urlObj = new URL(url);
|
|
1073
|
+
return {
|
|
1074
|
+
protocol: urlObj.protocol.replace(":", ""),
|
|
1075
|
+
host: urlObj.hostname.split("."),
|
|
1076
|
+
path: urlObj.pathname.split("/").filter(Boolean),
|
|
1077
|
+
query: [],
|
|
1078
|
+
variable: []
|
|
1079
|
+
};
|
|
1080
|
+
}
|
|
1081
|
+
return {
|
|
1082
|
+
protocol: url.protocol || "https",
|
|
1083
|
+
host: url.host || [],
|
|
1084
|
+
path: url.path || [],
|
|
1085
|
+
query: url.query || [],
|
|
1086
|
+
variable: url.variable || []
|
|
1087
|
+
};
|
|
1088
|
+
}
|
|
1089
|
+
buildPath(url, baseUrl) {
|
|
1090
|
+
let path3 = "/";
|
|
1091
|
+
if (url.path && url.path.length > 0) {
|
|
1092
|
+
path3 += url.path.join("/");
|
|
1093
|
+
}
|
|
1094
|
+
path3 = path3.replace(/\{\{([^}]+)\}\}/g, ":$1");
|
|
1095
|
+
return path3;
|
|
1096
|
+
}
|
|
1097
|
+
parseUrlParams(url) {
|
|
1098
|
+
const result = { path: [], query: [] };
|
|
1099
|
+
if (url.variable && url.variable.length > 0) {
|
|
1100
|
+
for (const v of url.variable) {
|
|
1101
|
+
result.path.push({
|
|
1102
|
+
name: v.key,
|
|
1103
|
+
type: v.type || "string",
|
|
1104
|
+
description: v.description,
|
|
1105
|
+
example: v.value
|
|
1106
|
+
});
|
|
1107
|
+
}
|
|
1108
|
+
}
|
|
1109
|
+
if (url.path && url.path.length > 0) {
|
|
1110
|
+
for (const segment of url.path) {
|
|
1111
|
+
if (segment.startsWith(":")) {
|
|
1112
|
+
const paramName = segment.slice(1);
|
|
1113
|
+
if (!result.path.find((p) => p.name === paramName)) {
|
|
1114
|
+
result.path.push({
|
|
1115
|
+
name: paramName,
|
|
1116
|
+
type: "string"
|
|
1117
|
+
});
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
if (url.query && url.query.length > 0) {
|
|
1123
|
+
for (const q of url.query) {
|
|
1124
|
+
if (q.disabled) continue;
|
|
1125
|
+
result.query.push({
|
|
1126
|
+
name: q.key,
|
|
1127
|
+
type: "string",
|
|
1128
|
+
description: q.description,
|
|
1129
|
+
example: q.value
|
|
1130
|
+
});
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
return result;
|
|
1134
|
+
}
|
|
1135
|
+
parseBody(body) {
|
|
1136
|
+
if (!body) return void 0;
|
|
1137
|
+
let example;
|
|
1138
|
+
let description = body.description;
|
|
1139
|
+
if (body.mode === "raw") {
|
|
1140
|
+
try {
|
|
1141
|
+
example = JSON.parse(body.raw);
|
|
1142
|
+
} catch {
|
|
1143
|
+
example = body.raw;
|
|
1144
|
+
}
|
|
1145
|
+
} else if (body.mode === "formdata" || body.mode === "urlencoded") {
|
|
1146
|
+
example = {};
|
|
1147
|
+
for (const item of body[body.mode] || []) {
|
|
1148
|
+
if (!item.disabled) {
|
|
1149
|
+
example[item.key] = item.value;
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
return {
|
|
1154
|
+
description,
|
|
1155
|
+
example
|
|
1156
|
+
};
|
|
1157
|
+
}
|
|
1158
|
+
parseResponses(responses) {
|
|
1159
|
+
const result = { errors: [] };
|
|
1160
|
+
for (const response of responses) {
|
|
1161
|
+
let example;
|
|
1162
|
+
try {
|
|
1163
|
+
example = JSON.parse(response.body);
|
|
1164
|
+
} catch {
|
|
1165
|
+
example = response.body;
|
|
1166
|
+
}
|
|
1167
|
+
const apiResponse = {
|
|
1168
|
+
status: response.code || 200,
|
|
1169
|
+
description: response.name,
|
|
1170
|
+
example
|
|
1171
|
+
};
|
|
1172
|
+
if (apiResponse.status >= 200 && apiResponse.status < 300) {
|
|
1173
|
+
if (!result.success) result.success = apiResponse;
|
|
1174
|
+
} else {
|
|
1175
|
+
result.errors.push(apiResponse);
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
return result;
|
|
1179
|
+
}
|
|
1180
|
+
};
|
|
1181
|
+
|
|
1182
|
+
// src/lib/parsers/index.ts
|
|
1183
|
+
var parsers = /* @__PURE__ */ new Map([
|
|
1184
|
+
["specra", new SpecraParser()],
|
|
1185
|
+
["openapi", new OpenApiParser()],
|
|
1186
|
+
["postman", new PostmanParser()]
|
|
1187
|
+
]);
|
|
1188
|
+
function detectParserType(input) {
|
|
1189
|
+
if (!input || typeof input !== "object") {
|
|
1190
|
+
throw new Error("Invalid API spec: input must be an object");
|
|
1191
|
+
}
|
|
1192
|
+
if (input.info?.schema?.includes("v2")) {
|
|
1193
|
+
return "postman";
|
|
1194
|
+
}
|
|
1195
|
+
if (input.openapi || input.swagger) {
|
|
1196
|
+
return "openapi";
|
|
1197
|
+
}
|
|
1198
|
+
if (input.endpoints && Array.isArray(input.endpoints)) {
|
|
1199
|
+
return "specra";
|
|
1200
|
+
}
|
|
1201
|
+
throw new Error(
|
|
1202
|
+
"Unable to auto-detect API spec format. Supported formats: Specra, OpenAPI 3.x, Postman Collection v2.x"
|
|
1203
|
+
);
|
|
1204
|
+
}
|
|
1205
|
+
function parseApiSpec(input, parserType = "auto") {
|
|
1206
|
+
const actualType = parserType === "auto" ? detectParserType(input) : parserType;
|
|
1207
|
+
const parser = parsers.get(actualType);
|
|
1208
|
+
if (!parser) {
|
|
1209
|
+
throw new Error(`Unknown parser type: ${actualType}`);
|
|
1210
|
+
}
|
|
1211
|
+
if (!parser.validate(input)) {
|
|
1212
|
+
throw new Error(`Input does not match ${actualType} format`);
|
|
1213
|
+
}
|
|
1214
|
+
return parser.parse(input);
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1217
|
+
// src/lib/utils.ts
|
|
1218
|
+
var import_clsx = require("clsx");
|
|
1219
|
+
var import_tailwind_merge = require("tailwind-merge");
|
|
1220
|
+
function cn(...inputs) {
|
|
1221
|
+
return (0, import_tailwind_merge.twMerge)((0, import_clsx.clsx)(inputs));
|
|
1222
|
+
}
|
|
1223
|
+
function getAssetPath(path3) {
|
|
1224
|
+
const basePath = process.env.NEXT_PUBLIC_BASE_PATH || process.env.__NEXT_ROUTER_BASEPATH || "";
|
|
1225
|
+
const normalizedPath = path3.startsWith("/") ? path3 : `/${path3}`;
|
|
1226
|
+
if (basePath) {
|
|
1227
|
+
const normalizedBase = basePath.startsWith("/") ? basePath : `/${basePath}`;
|
|
1228
|
+
const cleanBase = normalizedBase.replace(/\/$/, "");
|
|
1229
|
+
return `${cleanBase}${normalizedPath}`;
|
|
1230
|
+
}
|
|
1231
|
+
return normalizedPath;
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1234
|
+
// src/lib/redirects.ts
|
|
1235
|
+
async function buildRedirectMappings() {
|
|
1236
|
+
const versions = getVersions();
|
|
1237
|
+
const redirects = [];
|
|
1238
|
+
for (const version of versions) {
|
|
1239
|
+
const docs = await getAllDocs(version);
|
|
1240
|
+
for (const doc of docs) {
|
|
1241
|
+
if (doc.meta.redirect_from && Array.isArray(doc.meta.redirect_from)) {
|
|
1242
|
+
for (const oldPath of doc.meta.redirect_from) {
|
|
1243
|
+
redirects.push({
|
|
1244
|
+
from: oldPath,
|
|
1245
|
+
to: `/docs/${version}/${doc.slug}`
|
|
1246
|
+
});
|
|
1247
|
+
}
|
|
1248
|
+
}
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1251
|
+
return redirects;
|
|
1252
|
+
}
|
|
1253
|
+
async function findRedirect(path3) {
|
|
1254
|
+
const redirects = await buildRedirectMappings();
|
|
1255
|
+
const redirect = redirects.find((r) => r.from === path3);
|
|
1256
|
+
return redirect ? redirect.to : null;
|
|
1257
|
+
}
|
|
1258
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
1259
|
+
0 && (module.exports = {
|
|
1260
|
+
OpenApiParser,
|
|
1261
|
+
PerfTimer,
|
|
1262
|
+
PostmanParser,
|
|
1263
|
+
SpecraParser,
|
|
1264
|
+
buildRedirectMappings,
|
|
1265
|
+
buildSidebarStructure,
|
|
1266
|
+
clearAllCaches,
|
|
1267
|
+
cn,
|
|
1268
|
+
debugLog,
|
|
1269
|
+
defaultConfig,
|
|
1270
|
+
detectParserType,
|
|
1271
|
+
extractHeadings,
|
|
1272
|
+
extractTableOfContents,
|
|
1273
|
+
findRedirect,
|
|
1274
|
+
getAdjacentDocs,
|
|
1275
|
+
getAllCategoryConfigs,
|
|
1276
|
+
getAllDocs,
|
|
1277
|
+
getAssetPath,
|
|
1278
|
+
getCacheStats,
|
|
1279
|
+
getCachedAllDocs,
|
|
1280
|
+
getCachedDocBySlug,
|
|
1281
|
+
getCachedVersions,
|
|
1282
|
+
getCategoryConfig,
|
|
1283
|
+
getConfig,
|
|
1284
|
+
getConfigValue,
|
|
1285
|
+
getDocBySlug,
|
|
1286
|
+
getVersions,
|
|
1287
|
+
initConfig,
|
|
1288
|
+
isCategoryPage,
|
|
1289
|
+
loadConfig,
|
|
1290
|
+
logCacheOperation,
|
|
1291
|
+
logFsOperation,
|
|
1292
|
+
logMemoryUsage,
|
|
1293
|
+
parseApiSpec,
|
|
1294
|
+
processContentWithEnv,
|
|
1295
|
+
reloadConfig,
|
|
1296
|
+
replaceEnvVariables,
|
|
1297
|
+
sortSidebarGroups,
|
|
1298
|
+
sortSidebarItems,
|
|
1299
|
+
validateConfig
|
|
1300
|
+
});
|
|
1301
|
+
//# sourceMappingURL=index.js.map
|