@farming-labs/docs 0.2.60 → 0.2.62

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.
Files changed (51) hide show
  1. package/README.md +1 -1
  2. package/package.json +11 -1
  3. package/dist/agent-BFqyqEnC.mjs +0 -4547
  4. package/dist/agent-DlxriaTs.mjs +0 -624
  5. package/dist/agent-evals-kJs2Y9xR.mjs +0 -2144
  6. package/dist/agent-export-BgUaiW8f.mjs +0 -869
  7. package/dist/agent-scope-CCaIY1aK.mjs +0 -283
  8. package/dist/agents-Djh-HXih.mjs +0 -219
  9. package/dist/analytics-Bx44lg6d.mjs +0 -177
  10. package/dist/cli/index.d.mts +0 -15
  11. package/dist/cli/index.mjs +0 -452
  12. package/dist/client/react.d.mts +0 -45
  13. package/dist/client/react.mjs +0 -223
  14. package/dist/cloud-BH_sHX64.mjs +0 -1615
  15. package/dist/cloud-analytics-CSyFE6SS.mjs +0 -132
  16. package/dist/cloud-ask-ai-B2WnG4fF.d.mts +0 -23
  17. package/dist/cloud-ask-ai-hnJfj8-X.mjs +0 -382
  18. package/dist/code-blocks-qe0T8-xe.mjs +0 -871
  19. package/dist/codeblocks-Bq67u32v.mjs +0 -250
  20. package/dist/config-DASewQ0x.mjs +0 -363
  21. package/dist/dev-DgY5xGl9.mjs +0 -1333
  22. package/dist/docs-cloud-server.d.mts +0 -70
  23. package/dist/docs-cloud-server.mjs +0 -310
  24. package/dist/doctor-CO1VMcF_.mjs +0 -1906
  25. package/dist/downgrade-BZs86NVr.mjs +0 -184
  26. package/dist/errors-CVqZ3kOO.mjs +0 -20
  27. package/dist/golden-evaluations-BN9u2wxw.mjs +0 -1483
  28. package/dist/i18n-CAlj1ADU.mjs +0 -40
  29. package/dist/index.d.mts +0 -1099
  30. package/dist/index.mjs +0 -9
  31. package/dist/init-Bd_k06bR.mjs +0 -1233
  32. package/dist/mcp-B_yXL5G5.mjs +0 -137
  33. package/dist/mcp.d.mts +0 -287
  34. package/dist/mcp.mjs +0 -4135
  35. package/dist/metadata-BDuewuzq.mjs +0 -237
  36. package/dist/package-version-qik_4J6C.mjs +0 -128
  37. package/dist/reading-time-BkEft6SD.mjs +0 -741
  38. package/dist/review-NC-sOdXn.mjs +0 -665
  39. package/dist/robots-DskPvGPw.mjs +0 -178
  40. package/dist/robots-ltltiLJF.mjs +0 -197
  41. package/dist/search-C1JitPwi.d.mts +0 -397
  42. package/dist/search-D57JXQLj.mjs +0 -1758
  43. package/dist/search-o4Ud6OXv.mjs +0 -102
  44. package/dist/server.d.mts +0 -341
  45. package/dist/server.mjs +0 -11
  46. package/dist/sitemap-Cq-Yj_iA.mjs +0 -247
  47. package/dist/sitemap-server-C1ibVKOy.mjs +0 -1137
  48. package/dist/templates-DNw15P-x.mjs +0 -2373
  49. package/dist/types-XHABMh_f.d.mts +0 -3248
  50. package/dist/upgrade-BCJTCW3O.mjs +0 -56
  51. package/dist/utils-6UCLxv4B.mjs +0 -225
@@ -1,250 +0,0 @@
1
- import { a as validateCodeBlocks, r as resolveDocsCodeBlocksValidateConfig } from "./code-blocks-qe0T8-xe.mjs";
2
- import { d as readStringProperty, h as resolveDocsContentDir, i as loadDocsConfigModule, m as resolveDocsConfigPath, p as readTopLevelStringProperty, s as readBooleanProperty, t as extractNestedObjectLiteral, u as readNumberProperty } from "./config-DASewQ0x.mjs";
3
- import { existsSync, readFileSync } from "node:fs";
4
- import pc from "picocolors";
5
-
6
- //#region src/cli/codeblocks.ts
7
- function parseInlineFlag(arg) {
8
- const [rawKey, value] = arg.slice(2).split("=", 2);
9
- return {
10
- key: rawKey.trim(),
11
- value
12
- };
13
- }
14
- function parseCodeBlocksValidateArgs(argv) {
15
- const parsed = {};
16
- for (let index = 0; index < argv.length; index += 1) {
17
- const arg = argv[index];
18
- if (arg === "--help" || arg === "-h") {
19
- parsed.help = true;
20
- continue;
21
- }
22
- if (arg === "--json") {
23
- parsed.json = true;
24
- continue;
25
- }
26
- if (arg === "--plan") {
27
- parsed.plan = true;
28
- continue;
29
- }
30
- if (arg === "--run") {
31
- parsed.run = true;
32
- continue;
33
- }
34
- if (arg.startsWith("--config=")) {
35
- const value = parseInlineFlag(arg).value;
36
- if (!value) throw new Error("Missing value for --config.");
37
- parsed.configPath = value;
38
- continue;
39
- }
40
- if (arg === "--config") {
41
- const value = argv[index + 1];
42
- if (!value || value.startsWith("--")) throw new Error("Missing value for --config.");
43
- parsed.configPath = value;
44
- index += 1;
45
- continue;
46
- }
47
- throw new Error(`Unknown codeblocks validate flag: ${arg}.`);
48
- }
49
- return parsed;
50
- }
51
- function printCodeBlocksValidateHelp() {
52
- console.log(`
53
- ${pc.bold("@farming-labs/docs codeblocks validate")}
54
-
55
- ${pc.dim("Usage:")}
56
- pnpm exec docs codeblocks validate
57
- pnpm exec docs codeblocks validate --plan
58
- pnpm exec docs codeblocks validate --json
59
- pnpm exec docs codeblocks validate --config docs.config.ts
60
-
61
- ${pc.dim("Options:")}
62
- ${pc.cyan("--plan")} Build the execution plan without running code
63
- ${pc.cyan("--run")} Force execution even when config mode is ${pc.dim("\"plan\"")}
64
- ${pc.cyan("--json")} Print machine-readable output
65
- ${pc.cyan("--config <path>")} Use a custom docs config path instead of ${pc.dim("docs.config.ts[x]")}
66
- ${pc.cyan("-h, --help")} Show this help message
67
- `);
68
- }
69
- async function runCodeBlocksValidate(options = {}) {
70
- const rootDir = process.cwd();
71
- const loaded = await loadDocsConfigModule(rootDir, options.configPath, { silent: options.json });
72
- const configPath = loaded?.path ?? resolveDocsConfigPath(rootDir, options.configPath);
73
- const configContent = existsSync(configPath) ? readFileSync(configPath, "utf-8") : "";
74
- const entry = loaded?.config.entry ?? readTopLevelStringProperty(configContent, "entry") ?? "docs";
75
- const contentDir = loaded?.config.contentDir ?? resolveDocsContentDir(rootDir, configContent, entry);
76
- const config = resolveDocsCodeBlocksValidateConfig(loaded?.config.codeBlocks?.validate ?? readStaticCodeBlocksValidateConfig(configContent));
77
- if (!config.enabled) {
78
- const disabledReport = {
79
- summary: {
80
- total: 0,
81
- planned: 0,
82
- pass: 0,
83
- skip: 0,
84
- fail: 0
85
- },
86
- config,
87
- targets: [],
88
- plans: [],
89
- results: []
90
- };
91
- if (options.json) console.log(JSON.stringify(redactReport(disabledReport), null, 2));
92
- else console.log(pc.yellow("codeBlocks.validate is disabled. Add `codeBlocks: { validate: true }` to docs.config.ts."));
93
- return disabledReport;
94
- }
95
- const effectiveConfig = {
96
- ...config,
97
- mode: options.run ? "report" : config.mode
98
- };
99
- const planOnly = options.plan === true || effectiveConfig.mode === "plan";
100
- const report = await validateCodeBlocks({
101
- rootDir,
102
- contentDir,
103
- config: effectiveConfig,
104
- planOnly: options.plan
105
- });
106
- if (options.json) console.log(JSON.stringify(redactReport(report), null, 2));
107
- else printCodeBlocksReport(report, planOnly);
108
- if (!options.plan && report.summary.fail > 0) process.exitCode = 1;
109
- return report;
110
- }
111
- function readStaticCodeBlocksValidateConfig(content) {
112
- const block = extractNestedObjectLiteral(content, ["codeBlocks"]);
113
- if (!block) return void 0;
114
- if (/\bvalidate\s*:\s*true\b/.test(block)) return true;
115
- if (/\bvalidate\s*:\s*false\b/.test(block)) return false;
116
- const validateBlock = extractNestedObjectLiteral(content, ["codeBlocks", "validate"]);
117
- if (validateBlock) {
118
- const config = {};
119
- const enabled = readBooleanProperty(validateBlock, "enabled");
120
- const mode = readStringProperty(validateBlock, "mode");
121
- const missingEnv = readStringProperty(validateBlock, "missingEnv");
122
- const unsupportedLanguage = readStringProperty(validateBlock, "unsupportedLanguage");
123
- const envFile = readStringArrayProperty(validateBlock, "envFile");
124
- if (enabled !== void 0) config.enabled = enabled;
125
- if (mode === "plan" || mode === "report") config.mode = mode;
126
- if (missingEnv === "skip" || missingEnv === "warn" || missingEnv === "error") config.missingEnv = missingEnv;
127
- if (unsupportedLanguage === "skip" || unsupportedLanguage === "warn" || unsupportedLanguage === "error") config.unsupportedLanguage = unsupportedLanguage;
128
- if (envFile) config.envFile = envFile;
129
- const planner = readStaticPlannerConfig(extractNestedObjectLiteral(content, [
130
- "codeBlocks",
131
- "validate",
132
- "planner"
133
- ]));
134
- if (planner) config.planner = planner;
135
- const runner = readStaticRunnerConfig(extractNestedObjectLiteral(content, [
136
- "codeBlocks",
137
- "validate",
138
- "runner"
139
- ]));
140
- if (runner) config.runner = runner;
141
- const env = readStringRecord(extractNestedObjectLiteral(content, [
142
- "codeBlocks",
143
- "validate",
144
- "env"
145
- ]));
146
- if (env && Object.keys(env).length > 0) config.env = env;
147
- return config;
148
- }
149
- if (/\bvalidate\s*:\s*\{/.test(block)) return true;
150
- }
151
- function readStaticPlannerConfig(block) {
152
- if (!block) return void 0;
153
- const provider = readStringProperty(block, "provider");
154
- const model = readStringProperty(block, "model");
155
- const baseUrl = readStringProperty(block, "baseUrl");
156
- const baseUrlEnv = readStringProperty(block, "baseUrlEnv");
157
- const apiKeyEnv = readStringProperty(block, "apiKeyEnv");
158
- if (provider !== "metadata" && provider !== "openai" && provider !== "openai-compatible" && provider !== "cloud") return;
159
- return {
160
- provider,
161
- ...model ? { model } : {},
162
- ...baseUrl ? { baseUrl } : {},
163
- ...baseUrlEnv ? { baseUrlEnv } : {},
164
- ...apiKeyEnv ? { apiKeyEnv } : {}
165
- };
166
- }
167
- function readStaticRunnerConfig(block) {
168
- if (!block) return void 0;
169
- const provider = readStringProperty(block, "provider");
170
- const tokenEnv = readStringProperty(block, "tokenEnv");
171
- const projectIdEnv = readStringProperty(block, "projectIdEnv");
172
- const teamIdEnv = readStringProperty(block, "teamIdEnv");
173
- const projectJson = readStringProperty(block, "projectJson");
174
- const runtime = readStringProperty(block, "runtime");
175
- const apiUrlEnv = readStringProperty(block, "apiUrlEnv");
176
- const targetEnv = readStringProperty(block, "targetEnv");
177
- const timeoutMs = readNumberProperty(block, "timeoutMs");
178
- if (provider !== "local" && provider !== "vercel-sandbox" && provider !== "e2b" && provider !== "daytona" && provider !== "cloud") return;
179
- return {
180
- provider,
181
- ...tokenEnv ? { tokenEnv } : {},
182
- ...projectIdEnv ? { projectIdEnv } : {},
183
- ...teamIdEnv ? { teamIdEnv } : {},
184
- ...projectJson ? { projectJson } : {},
185
- ...runtime === "node24" || runtime === "node22" || runtime === "python3.13" ? { runtime } : {},
186
- ...apiUrlEnv ? { apiUrlEnv } : {},
187
- ...targetEnv ? { targetEnv } : {},
188
- ...timeoutMs !== void 0 ? { timeoutMs } : {}
189
- };
190
- }
191
- function readStringArrayProperty(content, key) {
192
- const single = readStringProperty(content, key);
193
- if (single) return [single];
194
- const match = content.match(new RegExp(`\\b${key}\\b\\s*:\\s*\\[([\\s\\S]*?)\\]`));
195
- if (!match) return void 0;
196
- const values = [...match[1].matchAll(/["']([^"']+)["']/g)].map((item) => item[1]);
197
- return values.length > 0 ? values : void 0;
198
- }
199
- function readStringRecord(block) {
200
- if (!block) return void 0;
201
- const record = {};
202
- for (const pattern of [/(?:^|,)\s*([A-Za-z_$][\w$]*)\s*:\s*["']([^"']+)["']/g, /(?:^|,)\s*["']([^"']+)["']\s*:\s*["']([^"']+)["']/g]) {
203
- let match;
204
- while (match = pattern.exec(block)) record[match[1]] = match[2];
205
- }
206
- return record;
207
- }
208
- function printCodeBlocksReport(report, planOnly) {
209
- const label = planOnly ? "Code block plan" : "Code block validation";
210
- console.log(pc.bold(label));
211
- console.log([
212
- ...report.summary.planned > 0 ? [`${pc.cyan(`${report.summary.planned} planned`)}`] : [],
213
- `${pc.green(`${report.summary.pass} pass`)}`,
214
- `${pc.yellow(`${report.summary.skip} skip`)}`,
215
- `${report.summary.fail > 0 ? pc.red(`${report.summary.fail} fail`) : pc.dim("0 fail")}`,
216
- `${report.targets.length} code blocks`
217
- ].join(pc.dim(" • ")));
218
- if (report.results.length === 0) return;
219
- console.log();
220
- for (const result of report.results) {
221
- const status = result.status === "PLAN" ? pc.cyan(result.status) : result.status === "PASS" ? pc.green(result.status) : result.status === "FAIL" ? pc.red(result.status) : pc.yellow(result.status);
222
- const location = `${result.target.relativePath}:${result.target.lineStart}`;
223
- const detail = result.reason ?? result.plan.reason ?? result.plan.template;
224
- console.log(`${status} ${pc.cyan(location)} ${pc.dim(detail)}`);
225
- }
226
- }
227
- function redactReport(report) {
228
- return {
229
- ...report,
230
- config: {
231
- ...report.config,
232
- planner: {
233
- ...report.config.planner,
234
- apiKey: report.config.planner.apiKey ? "[REDACTED]" : void 0
235
- }
236
- },
237
- results: report.results.map((result) => ({
238
- ...result,
239
- stdout: trimOutput(result.stdout),
240
- stderr: trimOutput(result.stderr)
241
- }))
242
- };
243
- }
244
- function trimOutput(value) {
245
- if (!value) return value;
246
- return value.length > 4e3 ? `${value.slice(0, 4e3)}...` : value;
247
- }
248
-
249
- //#endregion
250
- export { parseCodeBlocksValidateArgs, printCodeBlocksValidateHelp, runCodeBlocksValidate };
@@ -1,363 +0,0 @@
1
- import { existsSync, readFileSync } from "node:fs";
2
- import { dirname, join, relative, resolve, sep } from "node:path";
3
-
4
- //#region src/cli/config.ts
5
- const FILE_EXTS = [
6
- "tsx",
7
- "ts",
8
- "jsx",
9
- "js"
10
- ];
11
- function escapeRegExp(value) {
12
- return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
13
- }
14
- function createPropertyPattern(key, valuePattern) {
15
- return new RegExp(`\\b${escapeRegExp(key)}\\b\\s*:\\s*${valuePattern}`);
16
- }
17
- function findBalancedBraceEnd(content, braceStart) {
18
- let depth = 0;
19
- let stringQuote = null;
20
- let escaped = false;
21
- let lineComment = false;
22
- let blockComment = false;
23
- for (let index = braceStart; index < content.length; index += 1) {
24
- const char = content[index];
25
- const next = content[index + 1];
26
- if (lineComment) {
27
- if (char === "\n") lineComment = false;
28
- continue;
29
- }
30
- if (blockComment) {
31
- if (char === "*" && next === "/") {
32
- blockComment = false;
33
- index += 1;
34
- }
35
- continue;
36
- }
37
- if (stringQuote) {
38
- if (escaped) {
39
- escaped = false;
40
- continue;
41
- }
42
- if (char === "\\") {
43
- escaped = true;
44
- continue;
45
- }
46
- if (char === stringQuote) stringQuote = null;
47
- continue;
48
- }
49
- if (char === "/" && next === "/") {
50
- lineComment = true;
51
- index += 1;
52
- continue;
53
- }
54
- if (char === "/" && next === "*") {
55
- blockComment = true;
56
- index += 1;
57
- continue;
58
- }
59
- if (char === "\"" || char === "'" || char === "`") {
60
- stringQuote = char;
61
- continue;
62
- }
63
- if (char === "{") {
64
- depth += 1;
65
- continue;
66
- }
67
- if (char !== "}") continue;
68
- depth -= 1;
69
- if (depth === 0) return index;
70
- }
71
- return -1;
72
- }
73
- function resolveDocsConfigPath(rootDir, explicitPath) {
74
- if (explicitPath) {
75
- const resolvedPath = resolve(rootDir, explicitPath);
76
- if (!existsSync(resolvedPath)) throw new Error(`Could not find docs config at ${explicitPath}.`);
77
- return resolvedPath;
78
- }
79
- for (const ext of FILE_EXTS) {
80
- const configPath = join(rootDir, `docs.config.${ext}`);
81
- if (existsSync(configPath)) return configPath;
82
- }
83
- throw new Error("Could not find docs.config.ts or docs.config.tsx in the current project. Use --config to point at a custom path.");
84
- }
85
- function readStringProperty(content, key) {
86
- return content.match(createPropertyPattern(key, `["']([^"']+)["']`))?.[1];
87
- }
88
- function readEnvReferenceProperty(content, key) {
89
- const patterns = [
90
- createPropertyPattern(key, `process\\.env\\.([A-Za-z_$][\\w$]*)`),
91
- createPropertyPattern(key, `process\\.env\\[['"]([^"'\\]]+)['"]\\]`),
92
- createPropertyPattern(key, `import\\.meta\\.env\\.([A-Za-z_$][\\w$]*)`),
93
- createPropertyPattern(key, `import\\.meta\\.env\\[['"]([^"'\\]]+)['"]\\]`)
94
- ];
95
- for (const pattern of patterns) {
96
- const match = content.match(pattern);
97
- if (match?.[1]) return match[1];
98
- }
99
- }
100
- function readBooleanProperty(content, key) {
101
- const match = content.match(createPropertyPattern(key, "(true|false)"));
102
- return match ? match[1] === "true" : void 0;
103
- }
104
- function readNumberProperty(content, key) {
105
- const match = content.match(createPropertyPattern(key, "(-?\\d+(?:\\.\\d+)?)"));
106
- if (!match) return void 0;
107
- const parsed = Number.parseFloat(match[1]);
108
- return Number.isFinite(parsed) ? parsed : void 0;
109
- }
110
- function extractObjectLiteral(content, key) {
111
- const keyIndex = content.search(new RegExp(`${key}\\s*:\\s*\\{`));
112
- if (keyIndex === -1) return void 0;
113
- const braceStart = content.indexOf("{", keyIndex);
114
- if (braceStart === -1) return void 0;
115
- const braceEnd = findBalancedBraceEnd(content, braceStart);
116
- return braceEnd === -1 ? void 0 : content.slice(braceStart + 1, braceEnd);
117
- }
118
- function stripLeadingPropertyTrivia(content) {
119
- let current = content;
120
- while (true) {
121
- const trimmed = current.replace(/^\s+/, "");
122
- if (trimmed.startsWith("//")) {
123
- const lineEnd = trimmed.indexOf("\n");
124
- current = lineEnd === -1 ? "" : trimmed.slice(lineEnd + 1);
125
- continue;
126
- }
127
- if (trimmed.startsWith("/*")) {
128
- const blockEnd = trimmed.indexOf("*/");
129
- current = blockEnd === -1 ? trimmed : trimmed.slice(blockEnd + 2);
130
- continue;
131
- }
132
- return trimmed;
133
- }
134
- }
135
- function extractTopLevelObjectLiteral(content, key) {
136
- const propertyPattern = new RegExp(`^${escapeRegExp(key)}\\s*:\\s*\\{`);
137
- for (const property of splitTopLevelProperties(content)) {
138
- const normalizedProperty = stripLeadingPropertyTrivia(property);
139
- if (!propertyPattern.test(normalizedProperty)) continue;
140
- const braceStart = normalizedProperty.indexOf("{");
141
- if (braceStart === -1) return void 0;
142
- const braceEnd = findBalancedBraceEnd(normalizedProperty, braceStart);
143
- return braceEnd === -1 ? void 0 : normalizedProperty.slice(braceStart + 1, braceEnd);
144
- }
145
- }
146
- function extractTopLevelConfigObject(content) {
147
- for (const marker of ["defineDocs(", "export default"]) {
148
- const markerIndex = content.indexOf(marker);
149
- if (markerIndex === -1) continue;
150
- const braceStart = content.indexOf("{", markerIndex);
151
- if (braceStart === -1) continue;
152
- const braceEnd = findBalancedBraceEnd(content, braceStart);
153
- if (braceEnd !== -1) return content.slice(braceStart + 1, braceEnd);
154
- }
155
- }
156
- function extractNestedObjectLiteral(content, keys) {
157
- if (keys.length === 0) return void 0;
158
- let current = extractTopLevelConfigObject(content) ?? content;
159
- for (const key of keys) {
160
- const next = extractTopLevelObjectLiteral(current, key);
161
- if (!next) return void 0;
162
- current = next;
163
- }
164
- return current;
165
- }
166
- function splitTopLevelProperties(content) {
167
- const properties = [];
168
- let start = 0;
169
- let stringQuote = null;
170
- let escaped = false;
171
- let braceDepth = 0;
172
- let bracketDepth = 0;
173
- let parenDepth = 0;
174
- for (let index = 0; index < content.length; index += 1) {
175
- const char = content[index];
176
- if (stringQuote) {
177
- if (escaped) {
178
- escaped = false;
179
- continue;
180
- }
181
- if (char === "\\") {
182
- escaped = true;
183
- continue;
184
- }
185
- if (char === stringQuote) stringQuote = null;
186
- continue;
187
- }
188
- if (char === "\"" || char === "'" || char === "`") {
189
- stringQuote = char;
190
- continue;
191
- }
192
- if (char === "{") {
193
- braceDepth += 1;
194
- continue;
195
- }
196
- if (char === "}") {
197
- braceDepth = Math.max(0, braceDepth - 1);
198
- continue;
199
- }
200
- if (char === "[") {
201
- bracketDepth += 1;
202
- continue;
203
- }
204
- if (char === "]") {
205
- bracketDepth = Math.max(0, bracketDepth - 1);
206
- continue;
207
- }
208
- if (char === "(") {
209
- parenDepth += 1;
210
- continue;
211
- }
212
- if (char === ")") {
213
- parenDepth = Math.max(0, parenDepth - 1);
214
- continue;
215
- }
216
- if (char === "," && braceDepth === 0 && bracketDepth === 0 && parenDepth === 0) {
217
- properties.push(content.slice(start, index));
218
- start = index + 1;
219
- }
220
- }
221
- const trailing = content.slice(start);
222
- if (trailing.trim().length > 0) properties.push(trailing);
223
- return properties;
224
- }
225
- function readTopLevelStringProperty(content, key) {
226
- const source = extractTopLevelConfigObject(content) ?? content;
227
- const propertyPattern = new RegExp(`^\\s*${escapeRegExp(key)}\\s*:\\s*["']([^"']+)["']`);
228
- for (const property of splitTopLevelProperties(source)) {
229
- const match = property.trim().match(propertyPattern);
230
- if (match) return match[1];
231
- }
232
- }
233
- function readTopLevelBooleanProperty(content, key) {
234
- const source = extractTopLevelConfigObject(content) ?? content;
235
- const propertyPattern = new RegExp(`^\\s*${escapeRegExp(key)}\\s*:\\s*(true|false)\\b`);
236
- for (const property of splitTopLevelProperties(source)) {
237
- const match = property.trim().match(propertyPattern);
238
- if (match) return match[1] === "true";
239
- }
240
- }
241
- function readNavTitle(content) {
242
- const block = extractObjectLiteral(extractTopLevelConfigObject(content) ?? content, "nav");
243
- if (!block) return void 0;
244
- return readStringProperty(block, "title");
245
- }
246
- function resolveDocsContentDir(rootDir, content, entry) {
247
- const configuredContentDir = readTopLevelStringProperty(content, "contentDir");
248
- if (configuredContentDir) return configuredContentDir;
249
- const candidates = [
250
- entry,
251
- join("app", entry),
252
- join("src", "app", entry)
253
- ];
254
- for (const candidate of candidates) if (existsSync(join(rootDir, candidate))) return candidate;
255
- return entry;
256
- }
257
- function parseEnvValue(rawValue) {
258
- const value = rawValue.trim();
259
- if (value.startsWith("\"") && value.endsWith("\"") || value.startsWith("'") && value.endsWith("'")) return value.slice(1, -1);
260
- return value;
261
- }
262
- function loadProjectEnv(rootDir) {
263
- const env = {};
264
- for (const filename of [".env", ".env.local"]) {
265
- const fullPath = join(rootDir, filename);
266
- if (!existsSync(fullPath)) continue;
267
- const lines = readFileSync(fullPath, "utf-8").split(/\r?\n/);
268
- for (const line of lines) {
269
- const trimmed = line.trim();
270
- if (!trimmed || trimmed.startsWith("#")) continue;
271
- const equalsIndex = trimmed.indexOf("=");
272
- if (equalsIndex === -1) continue;
273
- const key = trimmed.slice(0, equalsIndex).trim();
274
- const rawValue = trimmed.slice(equalsIndex + 1);
275
- if (!key) continue;
276
- env[key] = parseEnvValue(rawValue);
277
- }
278
- }
279
- return env;
280
- }
281
- async function loadDocsConfigModule(rootDir, explicitPath, options = {}) {
282
- const result = await loadDocsConfigModuleResult(rootDir, explicitPath, options);
283
- return result.status === "evaluated" ? {
284
- path: result.path,
285
- config: result.config
286
- } : null;
287
- }
288
- function resolveDocsConfigModuleExport(loaded) {
289
- if (!loaded || typeof loaded !== "object" || Array.isArray(loaded)) return loaded;
290
- const record = loaded;
291
- return Object.prototype.hasOwnProperty.call(record, "default") ? record.default : loaded;
292
- }
293
- function isPlainDocsConfig(value) {
294
- if (!value || typeof value !== "object" || Array.isArray(value)) return false;
295
- const prototype = Object.getPrototypeOf(value);
296
- return prototype === Object.prototype || prototype === null;
297
- }
298
- function resolveDocsConfigTsconfigPath(rootDir, configPath) {
299
- const projectRoot = resolve(rootDir);
300
- let currentDir = dirname(configPath);
301
- while (true) {
302
- const tsconfigPath = join(currentDir, "tsconfig.json");
303
- if (existsSync(tsconfigPath)) return tsconfigPath;
304
- if (currentDir === projectRoot) return false;
305
- const parentDir = dirname(currentDir);
306
- if (parentDir === currentDir) return false;
307
- const relativeParent = relative(projectRoot, parentDir);
308
- if (relativeParent === ".." || relativeParent.startsWith(`..${sep}`)) return false;
309
- currentDir = parentDir;
310
- }
311
- }
312
- /**
313
- * Load docs.config with an explicit confidence signal for diagnostics.
314
- * Existing callers can keep using `loadDocsConfigModule`, which preserves the
315
- * previous evaluated-config-or-null contract.
316
- */
317
- async function loadDocsConfigModuleResult(rootDir, explicitPath, options = {}) {
318
- const configPath = resolveDocsConfigPath(rootDir, explicitPath);
319
- try {
320
- const { createJiti } = await import("jiti");
321
- const config = resolveDocsConfigModuleExport(await createJiti(import.meta.url, {
322
- moduleCache: false,
323
- fsCache: false,
324
- interopDefault: false,
325
- jsx: { runtime: "automatic" },
326
- tsconfigPaths: resolveDocsConfigTsconfigPath(rootDir, configPath)
327
- }).import(configPath));
328
- if (!isPlainDocsConfig(config)) return {
329
- status: "static-fallback",
330
- path: configPath,
331
- error: "The config module did not export a plain object."
332
- };
333
- return {
334
- status: "evaluated",
335
- path: configPath,
336
- config
337
- };
338
- } catch (error) {
339
- const message = error instanceof Error ? error.message : String(error);
340
- if (!options.silent && process.env.NODE_ENV !== "test") console.warn(`[docs] Could not evaluate ${configPath} as a module; falling back to static parsing. ${message}`);
341
- return {
342
- status: "static-fallback",
343
- path: configPath,
344
- error: message
345
- };
346
- }
347
- }
348
- /** Evaluate docs.config after loading project-local env files, then restore process.env. */
349
- async function loadDocsConfigModuleResultWithProjectEnv(rootDir, explicitPath, options = {}) {
350
- const env = loadProjectEnv(rootDir);
351
- const injectedKeys = Object.entries(env).filter(([key]) => process.env[key] === void 0).map(([key, value]) => {
352
- process.env[key] = value;
353
- return key;
354
- });
355
- try {
356
- return await loadDocsConfigModuleResult(rootDir, explicitPath, options);
357
- } finally {
358
- for (const key of injectedKeys) delete process.env[key];
359
- }
360
- }
361
-
362
- //#endregion
363
- export { loadDocsConfigModuleResultWithProjectEnv as a, readEnvReferenceProperty as c, readStringProperty as d, readTopLevelBooleanProperty as f, resolveDocsContentDir as h, loadDocsConfigModule as i, readNavTitle as l, resolveDocsConfigPath as m, extractObjectLiteral as n, loadProjectEnv as o, readTopLevelStringProperty as p, extractTopLevelConfigObject as r, readBooleanProperty as s, extractNestedObjectLiteral as t, readNumberProperty as u };