@thallylabs/migrate 0.2.33 → 0.2.35
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/README.md +40 -1
- package/dist/index.d.ts +7 -2
- package/dist/index.js +569 -170
- package/dist/index.js.map +1 -1
- package/dist/{url-migration-_wVauqSg.d.ts → url-migration-peVzTLjL.d.ts} +14 -0
- package/dist/url-migration.d.ts +1 -1
- package/dist/url-migration.js +54 -22
- package/dist/url-migration.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -230,8 +230,11 @@ var JS_GLOBALS = /* @__PURE__ */ new Set([
|
|
|
230
230
|
"BroadcastChannel"
|
|
231
231
|
]);
|
|
232
232
|
var IMPLICIT_MODULE_NAMES = /* @__PURE__ */ new Set(["React", "MintlifyComponents"]);
|
|
233
|
-
function
|
|
234
|
-
return ts
|
|
233
|
+
function scriptKindFor(fileName) {
|
|
234
|
+
return /\.[cm]?ts$/.test(fileName) ? ts.ScriptKind.TS : ts.ScriptKind.TSX;
|
|
235
|
+
}
|
|
236
|
+
function parse(source, fileName = "inline.tsx") {
|
|
237
|
+
return ts.createSourceFile(fileName, source, ts.ScriptTarget.Latest, true, scriptKindFor(fileName));
|
|
235
238
|
}
|
|
236
239
|
function bindingNames(name, into) {
|
|
237
240
|
if (ts.isIdentifier(name)) into.add(name.text);
|
|
@@ -240,20 +243,44 @@ function bindingNames(name, into) {
|
|
|
240
243
|
function isFunctionLike(node) {
|
|
241
244
|
return ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node) || ts.isArrowFunction(node) || ts.isMethodDeclaration(node) || ts.isConstructorDeclaration(node) || ts.isGetAccessorDeclaration(node) || ts.isSetAccessorDeclaration(node);
|
|
242
245
|
}
|
|
246
|
+
function hoistedVarNames(root, into) {
|
|
247
|
+
const collect = (node) => {
|
|
248
|
+
if (isFunctionLike(node) || ts.isClassLike(node) || ts.isModuleDeclaration(node)) return;
|
|
249
|
+
if (ts.isVariableDeclaration(node) && !ts.isCatchClause(node.parent) && !(ts.getCombinedNodeFlags(node) & ts.NodeFlags.BlockScoped)) bindingNames(node.name, into);
|
|
250
|
+
ts.forEachChild(node, collect);
|
|
251
|
+
};
|
|
252
|
+
collect(root);
|
|
253
|
+
}
|
|
243
254
|
function functionScope(fn) {
|
|
244
255
|
const scope = /* @__PURE__ */ new Set();
|
|
245
256
|
if ((ts.isFunctionExpression(fn) || ts.isFunctionDeclaration(fn)) && fn.name) scope.add(fn.name.text);
|
|
246
257
|
for (const parameter of fn.parameters) bindingNames(parameter.name, scope);
|
|
247
|
-
function collect(node) {
|
|
248
|
-
if (ts.isVariableDeclaration(node)) bindingNames(node.name, scope);
|
|
249
|
-
if ((ts.isFunctionDeclaration(node) || ts.isClassDeclaration(node)) && node.name) scope.add(node.name.text);
|
|
250
|
-
if (isFunctionLike(node)) return;
|
|
251
|
-
ts.forEachChild(node, collect);
|
|
252
|
-
}
|
|
253
|
-
if (fn.body) ts.forEachChild(fn.body, collect);
|
|
254
|
-
if (fn.body && !ts.isBlock(fn.body)) collect(fn.body);
|
|
255
258
|
return scope;
|
|
256
259
|
}
|
|
260
|
+
function lexicalNames(statements) {
|
|
261
|
+
const names = /* @__PURE__ */ new Set();
|
|
262
|
+
for (const statement of statements) {
|
|
263
|
+
if (ts.isVariableStatement(statement)) {
|
|
264
|
+
if (statement.declarationList.flags & ts.NodeFlags.BlockScoped) for (const declaration of statement.declarationList.declarations) bindingNames(declaration.name, names);
|
|
265
|
+
} else if ((ts.isFunctionDeclaration(statement) || ts.isClassDeclaration(statement)) && statement.name) names.add(statement.name.text);
|
|
266
|
+
}
|
|
267
|
+
return names;
|
|
268
|
+
}
|
|
269
|
+
function ownScope(node) {
|
|
270
|
+
if (ts.isBlock(node)) return lexicalNames(node.statements);
|
|
271
|
+
if (ts.isCaseBlock(node)) return lexicalNames(node.clauses.flatMap((clause) => [...clause.statements]));
|
|
272
|
+
if ((ts.isForStatement(node) || ts.isForInStatement(node) || ts.isForOfStatement(node)) && node.initializer && ts.isVariableDeclarationList(node.initializer)) {
|
|
273
|
+
const names = /* @__PURE__ */ new Set();
|
|
274
|
+
if (node.initializer.flags & ts.NodeFlags.BlockScoped) for (const declaration of node.initializer.declarations) bindingNames(declaration.name, names);
|
|
275
|
+
return names;
|
|
276
|
+
}
|
|
277
|
+
if (ts.isCatchClause(node) && node.variableDeclaration) {
|
|
278
|
+
const names = /* @__PURE__ */ new Set();
|
|
279
|
+
bindingNames(node.variableDeclaration.name, names);
|
|
280
|
+
return names;
|
|
281
|
+
}
|
|
282
|
+
return void 0;
|
|
283
|
+
}
|
|
257
284
|
function collectRefs(root) {
|
|
258
285
|
const refs = [];
|
|
259
286
|
const assigned = [];
|
|
@@ -268,13 +295,22 @@ function collectRefs(root) {
|
|
|
268
295
|
function walkNode(node, scopes, inAsync) {
|
|
269
296
|
if (ts.isTypeNode(node)) return;
|
|
270
297
|
if (isFunctionLike(node)) {
|
|
271
|
-
const
|
|
298
|
+
const parameterScopes = [...scopes, functionScope(node)];
|
|
272
299
|
const async = !!node.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.AsyncKeyword);
|
|
273
300
|
for (const parameter of node.parameters) {
|
|
274
|
-
if (!ts.isIdentifier(parameter.name)) walkNode(parameter.name,
|
|
275
|
-
if (parameter.initializer) walkNode(parameter.initializer,
|
|
301
|
+
if (!ts.isIdentifier(parameter.name)) walkNode(parameter.name, parameterScopes, async);
|
|
302
|
+
if (parameter.initializer) walkNode(parameter.initializer, parameterScopes, async);
|
|
303
|
+
}
|
|
304
|
+
if (node.body) {
|
|
305
|
+
const hoisted = /* @__PURE__ */ new Set();
|
|
306
|
+
hoistedVarNames(node.body, hoisted);
|
|
307
|
+
walkNode(node.body, [...parameterScopes, hoisted], async);
|
|
276
308
|
}
|
|
277
|
-
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
const own2 = ownScope(node);
|
|
312
|
+
if (own2) {
|
|
313
|
+
ts.forEachChild(node, (child) => walkNode(child, [...scopes, own2], inAsync));
|
|
278
314
|
return;
|
|
279
315
|
}
|
|
280
316
|
if (ts.isAwaitExpression(node) && !inAsync) awaitOutsideAsync = true;
|
|
@@ -651,6 +687,23 @@ function unboundTags(moduleSource, boundNames) {
|
|
|
651
687
|
}
|
|
652
688
|
return [...tags].sort();
|
|
653
689
|
}
|
|
690
|
+
function unboundBuiltinTags(moduleSource, boundNames, fileName) {
|
|
691
|
+
const tags = /* @__PURE__ */ new Set();
|
|
692
|
+
const values = /* @__PURE__ */ new Set();
|
|
693
|
+
for (const statement of parse(moduleSource, fileName).statements) {
|
|
694
|
+
if (ts.isImportDeclaration(statement)) continue;
|
|
695
|
+
for (const { name, kind } of collectRefs(statement).refs) {
|
|
696
|
+
if (boundNames.has(name)) continue;
|
|
697
|
+
if (kind === "tag" || kind === "member") tags.add(name);
|
|
698
|
+
else values.add(name);
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
const isGlobal = (name) => JS_GLOBALS.has(name) || BROWSER_IDENTIFIERS.has(name) || SERVER_ONLY_IDENTIFIERS.has(name);
|
|
702
|
+
const builtinTags = [...tags].filter(isThallyBuiltinComponent);
|
|
703
|
+
const shadowed = builtinTags.filter((name) => JS_GLOBALS.has(name) && values.has(name)).sort();
|
|
704
|
+
const builtinValues = [...values].filter((name) => isThallyBuiltinComponent(name) && !isGlobal(name));
|
|
705
|
+
return { bind: [.../* @__PURE__ */ new Set([...builtinTags.filter((name) => !shadowed.includes(name)), ...builtinValues])].sort(), shadowed };
|
|
706
|
+
}
|
|
654
707
|
var INLINE_SAFE_GLOBALS = /* @__PURE__ */ new Set([
|
|
655
708
|
"undefined",
|
|
656
709
|
"NaN",
|
|
@@ -719,12 +772,14 @@ function isSelfContainedFunction(node) {
|
|
|
719
772
|
function pageScopeNames(esmSources) {
|
|
720
773
|
const names = /* @__PURE__ */ new Set();
|
|
721
774
|
for (const source of esmSources) {
|
|
722
|
-
|
|
775
|
+
const sf = parse(source);
|
|
776
|
+
for (const statement of sf.statements) {
|
|
723
777
|
for (const local of importLocals(statement.getText())) names.add(local);
|
|
724
778
|
if (ts.isImportDeclaration(statement)) continue;
|
|
725
779
|
const target2 = ts.isExportDeclaration(statement) || ts.isExportAssignment(statement) ? void 0 : statement;
|
|
726
780
|
if (target2) for (const name of declaredNames(target2).names) names.add(name);
|
|
727
781
|
}
|
|
782
|
+
hoistedVarNames(sf, names);
|
|
728
783
|
}
|
|
729
784
|
return names;
|
|
730
785
|
}
|
|
@@ -2934,13 +2989,7 @@ function sanitizeCssModuleSelectors(css) {
|
|
|
2934
2989
|
return { css: root.toString(), omitted };
|
|
2935
2990
|
}
|
|
2936
2991
|
function sourceFile(source, filename) {
|
|
2937
|
-
return ts2.createSourceFile(
|
|
2938
|
-
filename,
|
|
2939
|
-
source,
|
|
2940
|
-
ts2.ScriptTarget.Latest,
|
|
2941
|
-
true,
|
|
2942
|
-
/\.[cm]?ts$/.test(filename) ? ts2.ScriptKind.TS : ts2.ScriptKind.TSX
|
|
2943
|
-
);
|
|
2992
|
+
return ts2.createSourceFile(filename, source, ts2.ScriptTarget.Latest, true, scriptKindFor(filename));
|
|
2944
2993
|
}
|
|
2945
2994
|
function walk(node, visitor) {
|
|
2946
2995
|
visitor(node);
|
|
@@ -2997,7 +3046,7 @@ function needsClientBoundary(source) {
|
|
|
2997
3046
|
visitNode(source);
|
|
2998
3047
|
return needed;
|
|
2999
3048
|
}
|
|
3000
|
-
function implicitReactImports(source) {
|
|
3049
|
+
function implicitReactImports(source, onShadowed) {
|
|
3001
3050
|
const bindings = /* @__PURE__ */ new Set();
|
|
3002
3051
|
const references = /* @__PURE__ */ new Set();
|
|
3003
3052
|
function bind(name) {
|
|
@@ -3015,7 +3064,9 @@ function implicitReactImports(source) {
|
|
|
3015
3064
|
}
|
|
3016
3065
|
if (ts2.isVariableStatement(statement)) for (const declaration of statement.declarationList.declarations) bind(declaration.name);
|
|
3017
3066
|
if ((ts2.isFunctionDeclaration(statement) || ts2.isClassDeclaration(statement)) && statement.name) bindings.add(statement.name.text);
|
|
3067
|
+
if ((ts2.isEnumDeclaration(statement) || ts2.isModuleDeclaration(statement) || ts2.isImportEqualsDeclaration(statement)) && ts2.isIdentifier(statement.name)) bindings.add(statement.name.text);
|
|
3018
3068
|
}
|
|
3069
|
+
hoistedVarNames(source, bindings);
|
|
3019
3070
|
function visit(node) {
|
|
3020
3071
|
if (ts2.isIdentifier(node) && !(ts2.isPropertyAccessExpression(node.parent) && node.parent.name === node) && !(ts2.isPropertyAssignment(node.parent) && node.parent.name === node)) references.add(node.text);
|
|
3021
3072
|
ts2.forEachChild(node, visit);
|
|
@@ -3023,26 +3074,50 @@ function implicitReactImports(source) {
|
|
|
3023
3074
|
visit(source);
|
|
3024
3075
|
const hooks = [...REACT_GLOBALS].filter((name) => references.has(name) && !bindings.has(name)).sort();
|
|
3025
3076
|
const usesMintlifyComponents = references.has("MintlifyComponents") && !bindings.has("MintlifyComponents");
|
|
3077
|
+
const leafBound = /* @__PURE__ */ new Set();
|
|
3026
3078
|
const implicitComponents = MINTLIFY_COMPONENT_MODULES.map(({ module, names }) => {
|
|
3027
|
-
const needed = names.filter((name) => references.has(name) && !bindings.has(name));
|
|
3079
|
+
const needed = names.filter((name) => name !== "Note" && references.has(name) && !bindings.has(name));
|
|
3080
|
+
for (const name of needed) leafBound.add(name);
|
|
3028
3081
|
return needed.length ? `import { ${needed.join(", ")} } from '${module}';` : "";
|
|
3029
3082
|
}).filter(Boolean);
|
|
3083
|
+
const { bind: builtinTags, shadowed } = unboundBuiltinTags(source.text, bindings, source.fileName);
|
|
3084
|
+
const registryNames = builtinTags.filter((name) => !leafBound.has(name));
|
|
3085
|
+
if (shadowed.length) onShadowed?.(shadowed);
|
|
3030
3086
|
return [
|
|
3031
3087
|
references.has("React") && !bindings.has("React") ? "import * as React from 'react';" : "",
|
|
3032
3088
|
hooks.length ? `import { ${hooks.join(", ")} } from 'react';` : "",
|
|
3033
3089
|
...implicitComponents,
|
|
3090
|
+
registryNames.length ? builtinRegistryBindings(registryNames, identifierNames(source)) : "",
|
|
3034
3091
|
usesMintlifyComponents ? mintlifyComponentsShim() : ""
|
|
3035
3092
|
].filter(Boolean).join("\n");
|
|
3036
3093
|
}
|
|
3037
3094
|
function resolveInlineBuiltinReferences(source, moduleNames) {
|
|
3038
3095
|
const unresolved = unboundTags(source, moduleNames);
|
|
3039
3096
|
if (unresolved.length === 0) return source;
|
|
3097
|
+
return [builtinRegistryBindings(unresolved, identifierNames(sourceFile(source, "inline.jsx"))), source].join("\n");
|
|
3098
|
+
}
|
|
3099
|
+
function identifierNames(root) {
|
|
3100
|
+
const names = /* @__PURE__ */ new Set();
|
|
3101
|
+
const visit = (node) => {
|
|
3102
|
+
if (ts2.isIdentifier(node)) names.add(node.text);
|
|
3103
|
+
ts2.forEachChild(node, visit);
|
|
3104
|
+
};
|
|
3105
|
+
visit(root);
|
|
3106
|
+
return names;
|
|
3107
|
+
}
|
|
3108
|
+
function builtinRegistryBindings(names, used) {
|
|
3109
|
+
const registry = "builtinMdxComponents";
|
|
3110
|
+
let alias = registry;
|
|
3111
|
+
for (let suffix = 2; used.has(alias); suffix++) alias = `${registry}${suffix}`;
|
|
3040
3112
|
return [
|
|
3041
|
-
|
|
3042
|
-
`const { ${
|
|
3043
|
-
source
|
|
3113
|
+
`import { ${alias === registry ? registry : `${registry} as ${alias}`} } from '@/components/mdx/builtin-components';`,
|
|
3114
|
+
`const { ${names.join(", ")} } = ${alias};`
|
|
3044
3115
|
].join("\n");
|
|
3045
3116
|
}
|
|
3117
|
+
function shadowedBuiltinMessage(file, names) {
|
|
3118
|
+
const tags = names.map((name) => `<${name}>`).join(", ");
|
|
3119
|
+
return `${file} renders ${tags} as a Thally built-in component but also uses the JavaScript global of the same name, so the tag was left unbound. Rename the component or the global use in the source.`;
|
|
3120
|
+
}
|
|
3046
3121
|
function imports(statement) {
|
|
3047
3122
|
if (!ts2.isStringLiteral(statement.moduleSpecifier) || !statement.importClause) return [];
|
|
3048
3123
|
const clause = statement.importClause;
|
|
@@ -3269,6 +3344,7 @@ function createComponentMigrator(siteRoot, confinementRoot, warnings, sourceIden
|
|
|
3269
3344
|
function copyGraph(entry) {
|
|
3270
3345
|
const staged = /* @__PURE__ */ new Map();
|
|
3271
3346
|
const stagedWarnings = [];
|
|
3347
|
+
const stagedShadowed = [];
|
|
3272
3348
|
const modules = /* @__PURE__ */ new Map();
|
|
3273
3349
|
let stagedBytes = 0;
|
|
3274
3350
|
function stageShim(filename, content) {
|
|
@@ -3373,7 +3449,8 @@ function createComponentMigrator(siteRoot, confinementRoot, warnings, sourceIden
|
|
|
3373
3449
|
const prologue = `// @ts-nocheck
|
|
3374
3450
|
${client ? "'use client';\n" : ""}
|
|
3375
3451
|
`;
|
|
3376
|
-
|
|
3452
|
+
const implicit = implicitReactImports(ast, (names) => stagedShadowed.push({ path, names }));
|
|
3453
|
+
return shebangMatch ? shebangMatch[0] + prologue + implicit + "\n" + replaced.slice(shebangMatch[0].length) : prologue + implicit + "\n" + replaced;
|
|
3377
3454
|
}
|
|
3378
3455
|
});
|
|
3379
3456
|
}
|
|
@@ -3391,6 +3468,7 @@ ${client ? "'use client';\n" : ""}
|
|
|
3391
3468
|
}
|
|
3392
3469
|
for (const [path, module] of modules) staged.set(path, { path, content: module.render(clientModules.has(path)) });
|
|
3393
3470
|
for (const [path, file] of staged) copied.set(path, file);
|
|
3471
|
+
for (const { path, names } of stagedShadowed) warn(shadowedBuiltinMessage(relative2(root, path).replace(/\\/g, "/"), names), path);
|
|
3394
3472
|
for (const { path, omitted } of stagedWarnings) {
|
|
3395
3473
|
warn(`Site-authored CSS module ${relative2(root, path).replace(/\\/g, "/")} has ${omitted} global-only selector branch(es) that cannot be copied into Thally CSS Modules; those styles were omitted.`, path);
|
|
3396
3474
|
}
|
|
@@ -3845,8 +3923,12 @@ ${inlineSource}` });
|
|
|
3845
3923
|
}`),
|
|
3846
3924
|
""
|
|
3847
3925
|
].join("\n");
|
|
3926
|
+
const implicit = implicitReactImports(
|
|
3927
|
+
sourceFile(inlineSource, "inline.jsx"),
|
|
3928
|
+
(names) => warn(shadowedBuiltinMessage(relative2(root, currentFile).replace(/\\/g, "/"), names), currentFile)
|
|
3929
|
+
);
|
|
3848
3930
|
copied.set(path, { path, content: `'use client';
|
|
3849
|
-
${
|
|
3931
|
+
${implicit}
|
|
3850
3932
|
${inlineSource}` });
|
|
3851
3933
|
copiedBytes += Buffer.byteLength(inlineSource);
|
|
3852
3934
|
for (const { node, name } of extracted) {
|
|
@@ -4442,39 +4524,106 @@ function specSource(value) {
|
|
|
4442
4524
|
}
|
|
4443
4525
|
function listedOperations(container) {
|
|
4444
4526
|
const operations = [];
|
|
4445
|
-
const visit = (entry,
|
|
4527
|
+
const visit = (entry, depth) => {
|
|
4446
4528
|
if (typeof entry === "string") {
|
|
4447
4529
|
if (OPENAPI_OPERATION_REF.test(entry)) operations.push(entry.trim());
|
|
4448
4530
|
return;
|
|
4449
4531
|
}
|
|
4450
4532
|
const object2 = objectValue2(entry);
|
|
4451
|
-
if (!object2 ||
|
|
4533
|
+
if (!object2 || depth > SWEEP_DEPTH_LIMIT || depth > 0 && (specSource(object2.openapi) || specSource(object2.asyncapi))) return;
|
|
4452
4534
|
for (const key of ["groups", "pages"]) {
|
|
4453
|
-
if (Array.isArray(object2[key])) object2[key].forEach((child) => visit(child,
|
|
4535
|
+
if (Array.isArray(object2[key])) object2[key].forEach((child) => visit(child, depth + 1));
|
|
4454
4536
|
}
|
|
4455
4537
|
};
|
|
4456
|
-
visit(container,
|
|
4538
|
+
visit(container, 0);
|
|
4457
4539
|
return operations;
|
|
4458
4540
|
}
|
|
4541
|
+
var bindsSpec = (node) => Boolean(specSource(node.openapi) || specSource(node.asyncapi));
|
|
4542
|
+
var hasGroupShape = (node) => "group" in node || Array.isArray(node.pages);
|
|
4543
|
+
var API_GROUPS_MAX_DEPTH = 32;
|
|
4544
|
+
var operationKey = (entry) => entry.trim().replace(/^(\S+)\s+/, "$1 ");
|
|
4545
|
+
function operationGroups(container, maxLevel = API_GROUPS_MAX_DEPTH) {
|
|
4546
|
+
const entries = (node, level) => ["groups", "pages"].flatMap((key) => (Array.isArray(node[key]) ? node[key] : []).flatMap((entry) => {
|
|
4547
|
+
if (typeof entry === "string") return OPENAPI_OPERATION_REF.test(entry) ? [operationKey(entry)] : [];
|
|
4548
|
+
const object2 = objectValue2(entry);
|
|
4549
|
+
const group = object2 && !bindsSpec(object2) ? groupOf(object2, level + 1) : void 0;
|
|
4550
|
+
return group ? [group] : [];
|
|
4551
|
+
}));
|
|
4552
|
+
const groupOf = (node, level) => {
|
|
4553
|
+
if (level > maxLevel || node.hidden === true || navigationGateReason(node)) return void 0;
|
|
4554
|
+
if (!hasGroupShape(node)) return void 0;
|
|
4555
|
+
const pages = entries(node, level);
|
|
4556
|
+
const icon = iconName(node.icon);
|
|
4557
|
+
return pages.length > 0 ? { group: labelFor(node, "Documentation"), ...icon ? { icon } : {}, pages } : void 0;
|
|
4558
|
+
};
|
|
4559
|
+
if (typeof container.group === "string") {
|
|
4560
|
+
const group = groupOf(container, 1);
|
|
4561
|
+
return group ? [group] : [];
|
|
4562
|
+
}
|
|
4563
|
+
const label = labelFor(container, "API reference");
|
|
4564
|
+
const groups = [];
|
|
4565
|
+
let run;
|
|
4566
|
+
for (const entry of entries(container, 0)) {
|
|
4567
|
+
if (typeof entry !== "string") {
|
|
4568
|
+
groups.push(entry);
|
|
4569
|
+
run = void 0;
|
|
4570
|
+
} else if (run) {
|
|
4571
|
+
run.push(entry);
|
|
4572
|
+
} else {
|
|
4573
|
+
run = [entry];
|
|
4574
|
+
groups.push({ group: label, pages: run });
|
|
4575
|
+
}
|
|
4576
|
+
}
|
|
4577
|
+
return groups;
|
|
4578
|
+
}
|
|
4579
|
+
var groupOperationKeys = (groups) => groups.flatMap(({ pages }) => pages.flatMap((page) => typeof page === "string" ? [page] : groupOperationKeys([page])));
|
|
4580
|
+
function mergeApiGroups(existing, incoming) {
|
|
4581
|
+
const identity = (key) => key.replace(/^(\S+)/, (method) => method.toLowerCase());
|
|
4582
|
+
const seen = new Set(groupOperationKeys(existing ?? []).map(identity));
|
|
4583
|
+
const unseen = (groups) => groups.flatMap((group) => {
|
|
4584
|
+
const pages = group.pages.flatMap((page) => {
|
|
4585
|
+
if (typeof page !== "string") return unseen([page]);
|
|
4586
|
+
if (seen.has(identity(page))) return [];
|
|
4587
|
+
seen.add(identity(page));
|
|
4588
|
+
return [page];
|
|
4589
|
+
});
|
|
4590
|
+
return pages.length > 0 ? [{ ...group, pages }] : [];
|
|
4591
|
+
});
|
|
4592
|
+
const merged = [...existing ?? [], ...unseen(incoming ?? [])];
|
|
4593
|
+
return merged.length > 0 ? merged : void 0;
|
|
4594
|
+
}
|
|
4459
4595
|
var hasNavigationChildren = (node) => ["groups", "pages"].some((key) => Array.isArray(node[key]) && node[key].length > 0);
|
|
4460
4596
|
function mintlifyNavigationApiReferences(config) {
|
|
4461
4597
|
const navigation = objectValue2(config.navigation) ?? config;
|
|
4462
4598
|
const references = [];
|
|
4599
|
+
const defaultLanguage = pickDefaultLanguage(
|
|
4600
|
+
(Array.isArray(navigation.languages) ? navigation.languages : []).flatMap((value) => {
|
|
4601
|
+
const language = objectValue2(value);
|
|
4602
|
+
return language && withLanguageCode(language) ? [language] : [];
|
|
4603
|
+
})
|
|
4604
|
+
);
|
|
4463
4605
|
const containerKeys = ["tabs", "anchors", "products", "dropdowns", "versions", "menus", "languages"];
|
|
4464
4606
|
const nestedKeys = ["groups", "pages"];
|
|
4465
|
-
function collect(node, tabLabel, sibling) {
|
|
4607
|
+
function collect(node, tabLabel, gated, otherLanguage, hidden, sibling) {
|
|
4466
4608
|
for (const kind of ["openapi", "asyncapi"]) {
|
|
4467
4609
|
const value = specSource(node[kind]);
|
|
4468
4610
|
const directory = objectValue2(node[kind])?.directory;
|
|
4469
4611
|
if (value) {
|
|
4470
|
-
const
|
|
4612
|
+
const listed = listedOperations(node);
|
|
4613
|
+
const operations = typeof directory === "string" && directory.trim() ? listed : [];
|
|
4614
|
+
const groups = gated || otherLanguage || hidden ? [] : operationGroups(node);
|
|
4615
|
+
const tooDeepOnly = groups.length === 0 && listed.length > 0 && !gated && !hidden && groupOperationKeys(operationGroups(node, SWEEP_DEPTH_LIMIT)).length === listed.length;
|
|
4616
|
+
const operationsWithheld = !otherLanguage && (hidden || groups.length === 0 && listed.length > 0 && !tooDeepOnly);
|
|
4471
4617
|
references.push({
|
|
4472
4618
|
value,
|
|
4473
4619
|
kind,
|
|
4474
4620
|
tabLabel,
|
|
4475
4621
|
...sibling,
|
|
4476
4622
|
...typeof directory === "string" && directory.trim() ? { directory: directory.trim() } : {},
|
|
4477
|
-
...operations.length > 0 ? { operations } : {}
|
|
4623
|
+
...operations.length > 0 ? { operations } : {},
|
|
4624
|
+
...groups.length > 0 ? { groups } : {},
|
|
4625
|
+
...operationsWithheld ? { operationsWithheld: true } : {},
|
|
4626
|
+
...otherLanguage ? { otherLanguage: true } : {}
|
|
4478
4627
|
});
|
|
4479
4628
|
}
|
|
4480
4629
|
}
|
|
@@ -4486,7 +4635,7 @@ function mintlifyNavigationApiReferences(config) {
|
|
|
4486
4635
|
siblingSources.set(candidate, source);
|
|
4487
4636
|
return candidate;
|
|
4488
4637
|
}
|
|
4489
|
-
function visitChildren(rawNode, tabLabel) {
|
|
4638
|
+
function visitChildren(rawNode, tabLabel, gated, otherLanguage, hidden) {
|
|
4490
4639
|
const node = withFlattenedProductGroups(rawNode);
|
|
4491
4640
|
for (const key of containerKeys) {
|
|
4492
4641
|
const entries = node[key];
|
|
@@ -4494,7 +4643,7 @@ function mintlifyNavigationApiReferences(config) {
|
|
|
4494
4643
|
for (const entry of entries) {
|
|
4495
4644
|
const object2 = objectValue2(entry);
|
|
4496
4645
|
if (!object2) continue;
|
|
4497
|
-
visit(object2, labelFor(object2, tabLabel ?? "Documentation"));
|
|
4646
|
+
visit(object2, labelFor(object2, tabLabel ?? "Documentation"), gated, otherLanguage || key === "languages" && rawNode === navigation && object2 !== defaultLanguage, hidden);
|
|
4498
4647
|
}
|
|
4499
4648
|
}
|
|
4500
4649
|
for (const key of nestedKeys) {
|
|
@@ -4503,7 +4652,7 @@ function mintlifyNavigationApiReferences(config) {
|
|
|
4503
4652
|
for (const entry of entries) {
|
|
4504
4653
|
if (typeof entry === "string") continue;
|
|
4505
4654
|
const object2 = objectValue2(entry);
|
|
4506
|
-
if (object2) visit(object2, tabLabel);
|
|
4655
|
+
if (object2) visit(object2, tabLabel, gated, otherLanguage, hidden || object2.hidden === true);
|
|
4507
4656
|
}
|
|
4508
4657
|
}
|
|
4509
4658
|
if (Array.isArray(node.menu)) {
|
|
@@ -4515,24 +4664,26 @@ function mintlifyNavigationApiReferences(config) {
|
|
|
4515
4664
|
const apiItems = items.filter((item) => specSource(item.openapi) || specSource(item.asyncapi));
|
|
4516
4665
|
const soleContent = apiItems.length === 1 && !hasNavigationChildren(node) && !items.some(hasNavigationChildren);
|
|
4517
4666
|
items.forEach((item, index) => {
|
|
4518
|
-
|
|
4667
|
+
const itemGated = gated || Boolean(navigationGateReason(item));
|
|
4668
|
+
if (soleContent && apiItems[0] === item) collect(item, tab, itemGated, otherLanguage, hidden);
|
|
4519
4669
|
else if (apiItems.includes(item)) {
|
|
4520
4670
|
const label = uniqueSiblingLabel(
|
|
4521
4671
|
`${tab}: ${labelFor(item, `Menu item ${index + 1}`)}`,
|
|
4522
4672
|
`${specSource(item.openapi) ?? ""}|${specSource(item.asyncapi) ?? ""}`
|
|
4523
4673
|
);
|
|
4524
4674
|
const icon = iconName(item.icon);
|
|
4525
|
-
collect(item, label, { parentTab: tab, ...icon ? { icon } : {}, ...item.hidden === true ? { hidden: true } : {} });
|
|
4675
|
+
collect(item, label, itemGated, otherLanguage, hidden, { parentTab: tab, ...icon ? { icon } : {}, ...item.hidden === true ? { hidden: true } : {} });
|
|
4526
4676
|
}
|
|
4527
|
-
visitChildren(item, tabLabel);
|
|
4677
|
+
visitChildren(item, tabLabel, itemGated, otherLanguage, hidden);
|
|
4528
4678
|
});
|
|
4529
4679
|
}
|
|
4530
4680
|
}
|
|
4531
|
-
function visit(node, tabLabel) {
|
|
4532
|
-
|
|
4533
|
-
|
|
4681
|
+
function visit(node, tabLabel, outerGated, otherLanguage, hidden) {
|
|
4682
|
+
const gated = outerGated || Boolean(navigationGateReason(node));
|
|
4683
|
+
collect(node, tabLabel, gated, otherLanguage, hidden);
|
|
4684
|
+
visitChildren(node, tabLabel, gated, otherLanguage, hidden);
|
|
4534
4685
|
}
|
|
4535
|
-
visit(navigation, void 0);
|
|
4686
|
+
visit(navigation, void 0, false, false, false);
|
|
4536
4687
|
return references;
|
|
4537
4688
|
}
|
|
4538
4689
|
function insertApiTab(tabs, tab, parentTab) {
|
|
@@ -4555,6 +4706,17 @@ function normalizePageRef(value, pathPrefix = "") {
|
|
|
4555
4706
|
ref = ref.replace(/\.(?:mdx?|rst|txt)$/i, "");
|
|
4556
4707
|
return pageIdFromReference(ref, true);
|
|
4557
4708
|
}
|
|
4709
|
+
var UNBOUND_OPERATIONS = { bound: false, gated: false, hidden: false, level: 0 };
|
|
4710
|
+
function descendOperationScope(scope, node, nested) {
|
|
4711
|
+
const binds = bindsSpec(node);
|
|
4712
|
+
return {
|
|
4713
|
+
bound: !nested && scope.bound || binds,
|
|
4714
|
+
gated: scope.gated || Boolean(navigationGateReason(node)),
|
|
4715
|
+
hidden: scope.hidden || !nested && node.hidden === true,
|
|
4716
|
+
// A container that binds a spec roots a tree of its own, where it is the first level when it is a group (as `operationGroups` reads it).
|
|
4717
|
+
level: binds ? typeof node.group === "string" ? 1 : 0 : !nested && scope.bound && hasGroupShape(node) ? scope.level + 1 : scope.level
|
|
4718
|
+
};
|
|
4719
|
+
}
|
|
4558
4720
|
var SWEEP_DEPTH_LIMIT = 256;
|
|
4559
4721
|
function collectGatedSourceRefs(node, gate, out, limits, depth = 0) {
|
|
4560
4722
|
if (depth > SWEEP_DEPTH_LIMIT) {
|
|
@@ -4588,15 +4750,24 @@ function collectReferenceAccess(node, access, pathPrefix, out, depth = 0) {
|
|
|
4588
4750
|
}
|
|
4589
4751
|
for (const value of Object.values(object2)) collectReferenceAccess(value, nested, pathPrefix, out, depth + 1);
|
|
4590
4752
|
}
|
|
4591
|
-
function withContainerAccess(object2, context, walk2) {
|
|
4753
|
+
function withContainerAccess(object2, context, walk2, nested = false) {
|
|
4592
4754
|
const outer = context.access;
|
|
4593
4755
|
context.access = descendNavigationAccess(outer, navigationAccess(object2));
|
|
4594
4756
|
try {
|
|
4595
|
-
return walk2
|
|
4757
|
+
return withOperationScope(object2, context, nested, walk2);
|
|
4596
4758
|
} finally {
|
|
4597
4759
|
context.access = outer;
|
|
4598
4760
|
}
|
|
4599
4761
|
}
|
|
4762
|
+
function withOperationScope(object2, context, nested, walk2) {
|
|
4763
|
+
const outer = context.operations;
|
|
4764
|
+
context.operations = descendOperationScope(outer, object2, nested);
|
|
4765
|
+
try {
|
|
4766
|
+
return walk2();
|
|
4767
|
+
} finally {
|
|
4768
|
+
context.operations = outer;
|
|
4769
|
+
}
|
|
4770
|
+
}
|
|
4600
4771
|
function warnOnce(context, key, message) {
|
|
4601
4772
|
if (context.warningKeys.has(key)) return;
|
|
4602
4773
|
context.warningKeys.add(key);
|
|
@@ -4634,11 +4805,32 @@ var OPENAPI_OPERATION_REF = /^(?:GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)\s+\S/;
|
|
|
4634
4805
|
function convertPage(value, context) {
|
|
4635
4806
|
if (typeof value === "string") {
|
|
4636
4807
|
if (OPENAPI_OPERATION_REF.test(value)) {
|
|
4637
|
-
|
|
4638
|
-
|
|
4639
|
-
|
|
4640
|
-
|
|
4641
|
-
|
|
4808
|
+
const { bound, gated, hidden, level } = context.operations;
|
|
4809
|
+
if (!context.operationGroups || !bound) {
|
|
4810
|
+
warnOnce(
|
|
4811
|
+
context,
|
|
4812
|
+
"openapi-operation-list",
|
|
4813
|
+
'Navigation lists individual OpenAPI operations (e.g. "GET /users") that were not added to the API navigation: an operation list is carried over only from a tab or group that names an openapi spec in a migrated docs.json. The operations themselves still have pages in the API reference.'
|
|
4814
|
+
);
|
|
4815
|
+
} else if (gated) {
|
|
4816
|
+
warnOnce(
|
|
4817
|
+
context,
|
|
4818
|
+
"openapi-operation-list-gated",
|
|
4819
|
+
'Navigation lists individual OpenAPI operations (e.g. "GET /users") under access-restricted groups, so they were not added to the API navigation. The operations themselves still have pages in the API reference.'
|
|
4820
|
+
);
|
|
4821
|
+
} else if (context.otherLanguage) {
|
|
4822
|
+
warnOnce(
|
|
4823
|
+
context,
|
|
4824
|
+
"openapi-operation-list-language",
|
|
4825
|
+
'Navigation lists individual OpenAPI operations (e.g. "GET /users") under a language other than the default, so they were not added to the API navigation: the API tab follows the default language. The operations themselves still have pages in the API reference.'
|
|
4826
|
+
);
|
|
4827
|
+
} else if (!hidden && level > API_GROUPS_MAX_DEPTH) {
|
|
4828
|
+
warnOnce(
|
|
4829
|
+
context,
|
|
4830
|
+
"openapi-operation-list-depth",
|
|
4831
|
+
`Navigation lists individual OpenAPI operations (e.g. "GET /users") in groups nested more than ${API_GROUPS_MAX_DEPTH} levels deep, so they were not added to the API navigation: the API navigation follows no deeper groups. The operations themselves still have pages in the API reference.`
|
|
4832
|
+
);
|
|
4833
|
+
}
|
|
4642
4834
|
return null;
|
|
4643
4835
|
}
|
|
4644
4836
|
return registerReference(value, context);
|
|
@@ -4749,10 +4941,10 @@ function convertMenuItems(items, context) {
|
|
|
4749
4941
|
`Mintlify menu item "${label}" has an openapi/asyncapi value without a "source", so its API reference was not migrated.`
|
|
4750
4942
|
);
|
|
4751
4943
|
}
|
|
4752
|
-
const children = convertNavigationValues([
|
|
4944
|
+
const children = withOperationScope(item, context, true, () => convertNavigationValues([
|
|
4753
4945
|
...Array.isArray(item.groups) ? item.groups : [],
|
|
4754
4946
|
...Array.isArray(item.pages) ? item.pages : []
|
|
4755
|
-
], context);
|
|
4947
|
+
], context));
|
|
4756
4948
|
if (typeof item.href === "string" && item.href) {
|
|
4757
4949
|
warnOnce(
|
|
4758
4950
|
context,
|
|
@@ -4812,7 +5004,7 @@ function convertContainerToTabs(containerValue, context, fallbackTab, trace, dep
|
|
|
4812
5004
|
...object2.hidden === true ? { hidden: true } : {}
|
|
4813
5005
|
}];
|
|
4814
5006
|
}
|
|
4815
|
-
const nested = withContainerAccess(object2, context, () => convertContainerToTabs(object2, context, tab, trace, depth + 1));
|
|
5007
|
+
const nested = withContainerAccess(object2, context, () => convertContainerToTabs(object2, context, tab, trace, depth + 1), true);
|
|
4816
5008
|
if (nested.length > 0) {
|
|
4817
5009
|
if (nested.length === 1) {
|
|
4818
5010
|
return [{
|
|
@@ -5036,6 +5228,8 @@ function projectedCompatibleConfig(config, warnings) {
|
|
|
5036
5228
|
return {
|
|
5037
5229
|
// Mintlify pages show a group eyebrow above the title and no breadcrumb trail.
|
|
5038
5230
|
breadcrumbs: false,
|
|
5231
|
+
// `styling.eyebrows: "breadcrumbs"` shows the whole group path; "section" (the default) shows the nearest group.
|
|
5232
|
+
...objectValue2(config.styling)?.eyebrows === "breadcrumbs" ? { eyebrow: "path" } : {},
|
|
5039
5233
|
...projectedTheme(config.theme) ? { theme: projectedTheme(config.theme) } : {},
|
|
5040
5234
|
...projectedContextual.length > 0 ? { contextual: { options: projectedContextual } } : {},
|
|
5041
5235
|
...projectedColorsValue ? { colors: projectedColorsValue } : {},
|
|
@@ -5181,6 +5375,16 @@ function mintlifyAllVersionPrefixes(config) {
|
|
|
5181
5375
|
collect(navigation);
|
|
5182
5376
|
return prefixes;
|
|
5183
5377
|
}
|
|
5378
|
+
function withLanguageCode(language) {
|
|
5379
|
+
try {
|
|
5380
|
+
return { ...language, language: Intl.getCanonicalLocales(String(language.language ?? language.locale ?? "en"))[0] };
|
|
5381
|
+
} catch {
|
|
5382
|
+
return void 0;
|
|
5383
|
+
}
|
|
5384
|
+
}
|
|
5385
|
+
function pickDefaultLanguage(languages) {
|
|
5386
|
+
return languages.find((entry) => entry.default === true) ?? languages[0];
|
|
5387
|
+
}
|
|
5184
5388
|
function projectMintlifyNavigation(config, options = {}) {
|
|
5185
5389
|
const warnings = [];
|
|
5186
5390
|
const references = [];
|
|
@@ -5191,6 +5395,8 @@ function projectMintlifyNavigation(config, options = {}) {
|
|
|
5191
5395
|
const gatedNodes = /* @__PURE__ */ new Map();
|
|
5192
5396
|
const navigation = objectValue2(config.navigation) ?? config;
|
|
5193
5397
|
const rootAccess = descendNavigationAccess(OPEN_NAVIGATION_ACCESS, navigationAccess(navigation));
|
|
5398
|
+
const rootOperations = descendOperationScope(UNBOUND_OPERATIONS, navigation, true);
|
|
5399
|
+
const operationGroups2 = options.operationGroups === true;
|
|
5194
5400
|
const limits = { tooDeep: false };
|
|
5195
5401
|
collectGatedSourceRefs(navigation, void 0, gatedNodes, limits);
|
|
5196
5402
|
if (limits.tooDeep) {
|
|
@@ -5202,20 +5408,16 @@ function projectMintlifyNavigation(config, options = {}) {
|
|
|
5202
5408
|
const languages = Array.isArray(navigation.languages) ? navigation.languages.flatMap((value) => {
|
|
5203
5409
|
const language = objectValue2(value);
|
|
5204
5410
|
if (!language) return [];
|
|
5205
|
-
|
|
5206
|
-
|
|
5207
|
-
|
|
5208
|
-
} catch {
|
|
5209
|
-
warnings.push({ code: "unsupported-config", message: "A navigation language with an invalid locale code was skipped." });
|
|
5210
|
-
return [];
|
|
5211
|
-
}
|
|
5411
|
+
const withCode = withLanguageCode(language);
|
|
5412
|
+
if (!withCode) warnings.push({ code: "unsupported-config", message: "A navigation language with an invalid locale code was skipped." });
|
|
5413
|
+
return withCode ? [withCode] : [];
|
|
5212
5414
|
}) : [];
|
|
5415
|
+
const defaultLanguage = pickDefaultLanguage(languages);
|
|
5213
5416
|
let tabs = [];
|
|
5214
5417
|
let i18n;
|
|
5215
5418
|
const localizedNavigation = {};
|
|
5216
5419
|
const projectionTrace = {};
|
|
5217
|
-
if (
|
|
5218
|
-
const defaultLanguage = languages.find((entry) => entry.default === true) ?? languages[0];
|
|
5420
|
+
if (defaultLanguage) {
|
|
5219
5421
|
const defaultLocale = String(defaultLanguage.language);
|
|
5220
5422
|
const locales = languages.map((entry) => {
|
|
5221
5423
|
const code = String(entry.language);
|
|
@@ -5241,6 +5443,9 @@ function projectMintlifyNavigation(config, options = {}) {
|
|
|
5241
5443
|
warningKeys,
|
|
5242
5444
|
appearances,
|
|
5243
5445
|
access: descendNavigationAccess(rootAccess, navigationAccess(language)),
|
|
5446
|
+
operations: descendOperationScope(rootOperations, language, true),
|
|
5447
|
+
operationGroups: operationGroups2,
|
|
5448
|
+
otherLanguage: language !== defaultLanguage,
|
|
5244
5449
|
gatedSourceRefs,
|
|
5245
5450
|
gatedNodes,
|
|
5246
5451
|
limits
|
|
@@ -5260,9 +5465,10 @@ function projectMintlifyNavigation(config, options = {}) {
|
|
|
5260
5465
|
}
|
|
5261
5466
|
if (Object.keys(localizedNavigation).length > 0) i18n.navigation = localizedNavigation;
|
|
5262
5467
|
} else {
|
|
5263
|
-
const context = { references, seenReferences, warnings, warningKeys, appearances, access: rootAccess, gatedSourceRefs, gatedNodes, limits, pathPrefix: options.pathPrefix, resolveSourceRef: options.resolveSourceRef };
|
|
5468
|
+
const context = { references, seenReferences, warnings, warningKeys, appearances, access: rootAccess, operations: rootOperations, operationGroups: operationGroups2, gatedSourceRefs, gatedNodes, limits, pathPrefix: options.pathPrefix, resolveSourceRef: options.resolveSourceRef };
|
|
5264
5469
|
tabs = convertContainerToTabs(navigation, context, "Documentation", projectionTrace);
|
|
5265
5470
|
if (tabs.length === 0 && Array.isArray(config.navigation)) {
|
|
5471
|
+
context.operations = UNBOUND_OPERATIONS;
|
|
5266
5472
|
const children = convertNavigationValues(config.navigation, context);
|
|
5267
5473
|
if (children.length > 0) {
|
|
5268
5474
|
const hasRootPages = children.some((page) => typeof page === "string");
|
|
@@ -5279,7 +5485,7 @@ function projectMintlifyNavigation(config, options = {}) {
|
|
|
5279
5485
|
message: "Mintlify navigation could not be projected; generated navigation will be used."
|
|
5280
5486
|
});
|
|
5281
5487
|
}
|
|
5282
|
-
const versionOwner =
|
|
5488
|
+
const versionOwner = defaultLanguage ?? navigation;
|
|
5283
5489
|
const globalNavigation = objectValue2(versionOwner.global) ?? objectValue2(navigation.global);
|
|
5284
5490
|
const shortcuts = Array.isArray(globalNavigation?.anchors) ? globalNavigation.anchors.flatMap((value) => {
|
|
5285
5491
|
const anchor = objectValue2(value);
|
|
@@ -7196,8 +7402,49 @@ function splitOpenApiRef(raw) {
|
|
|
7196
7402
|
const specRef = match[1] ? unquote(match[1]) : void 0;
|
|
7197
7403
|
return { ...specRef ? { specRef } : {}, operation: match[2] };
|
|
7198
7404
|
}
|
|
7405
|
+
function canonicalSpecRef(specRef) {
|
|
7406
|
+
return specRef.trim().split(/[?#]/, 1)[0].replace(/\\/g, "/").replace(/^(?:\.?\/+)+/, "");
|
|
7407
|
+
}
|
|
7408
|
+
function isRemoteSpecRef(specRef) {
|
|
7409
|
+
return /^[a-z][a-z0-9+.-]*:/i.test(specRef);
|
|
7410
|
+
}
|
|
7199
7411
|
function specRefBaseName(specRef) {
|
|
7200
|
-
return specRef
|
|
7412
|
+
return canonicalSpecRef(specRef).split("/").filter(Boolean).pop()?.toLowerCase() ?? "";
|
|
7413
|
+
}
|
|
7414
|
+
function withoutSpecExtension(value) {
|
|
7415
|
+
return value.replace(/\.(?:json|ya?ml)$/i, "");
|
|
7416
|
+
}
|
|
7417
|
+
function resolveSpecRef(specRef, candidates, anyFolder = true) {
|
|
7418
|
+
const key = canonicalSpecRef(specRef);
|
|
7419
|
+
const byId = /* @__PURE__ */ new Map();
|
|
7420
|
+
for (const candidate of candidates) {
|
|
7421
|
+
const id = candidate.sourcePath ?? candidate.filename;
|
|
7422
|
+
if (!byId.has(id)) byId.set(id, candidate);
|
|
7423
|
+
}
|
|
7424
|
+
const unique = [...byId.values()];
|
|
7425
|
+
const exact = unique.find((candidate) => candidate.sourcePath === key);
|
|
7426
|
+
if (exact) return { kind: "match", spec: exact };
|
|
7427
|
+
if (!anyFolder && key.includes("/")) return { kind: "none" };
|
|
7428
|
+
const name = specRefBaseName(key);
|
|
7429
|
+
const names = unique.map((candidate) => specRefBaseName(candidate.sourcePath ?? candidate.filename));
|
|
7430
|
+
for (const fits of [unique.filter((_, index) => names[index] === name), unique.filter((_, index) => withoutSpecExtension(names[index]) === name)]) {
|
|
7431
|
+
if (fits.length === 1) return { kind: "match", spec: fits[0] };
|
|
7432
|
+
if (fits.length > 1) return { kind: "ambiguous", candidates: fits };
|
|
7433
|
+
}
|
|
7434
|
+
return { kind: "none" };
|
|
7435
|
+
}
|
|
7436
|
+
function localSpecRef(openapi) {
|
|
7437
|
+
const specRef = openapi ? splitOpenApiRef(openapi)?.specRef : void 0;
|
|
7438
|
+
return specRef && !isRemoteSpecRef(specRef) ? specRef : void 0;
|
|
7439
|
+
}
|
|
7440
|
+
function specNamedByPage(openapi, specs) {
|
|
7441
|
+
const specRef = localSpecRef(openapi);
|
|
7442
|
+
const resolved = specRef ? resolveSpecRef(specRef, specs) : void 0;
|
|
7443
|
+
return resolved?.kind === "match" ? resolved.spec : void 0;
|
|
7444
|
+
}
|
|
7445
|
+
function namesSeveralSpecs(openapi, specs) {
|
|
7446
|
+
const specRef = localSpecRef(openapi);
|
|
7447
|
+
return Boolean(specRef) && resolveSpecRef(specRef, specs).kind === "ambiguous";
|
|
7201
7448
|
}
|
|
7202
7449
|
function withSpecRef(ref, specRef) {
|
|
7203
7450
|
return `${specRef} ${ref.operation}`;
|
|
@@ -7205,25 +7452,44 @@ function withSpecRef(ref, specRef) {
|
|
|
7205
7452
|
|
|
7206
7453
|
// src/spec-exclude.ts
|
|
7207
7454
|
import { parse as parseYaml4, stringify as stringifyYaml } from "yaml";
|
|
7208
|
-
function specRefMatches(ref, specPath,
|
|
7209
|
-
const prefix =
|
|
7455
|
+
function specRefMatches(ref, specPath, isDefault) {
|
|
7456
|
+
const prefix = splitOpenApiRef(ref)?.specRef;
|
|
7210
7457
|
if (!prefix) return isDefault;
|
|
7211
|
-
const wanted = prefix.
|
|
7458
|
+
const wanted = (isRemoteSpecRef(prefix) ? prefix.trim() : canonicalSpecRef(prefix)).toLowerCase();
|
|
7212
7459
|
const lowerPath = specPath.toLowerCase();
|
|
7213
|
-
|
|
7214
|
-
}
|
|
7215
|
-
|
|
7460
|
+
const stem = withoutSpecExtension(lowerPath);
|
|
7461
|
+
return lowerPath === wanted || lowerPath.endsWith(`/${wanted}`) || stem === wanted || stem.endsWith(`/${wanted}`);
|
|
7462
|
+
}
|
|
7463
|
+
function resolvedSources(ref, specs) {
|
|
7464
|
+
const specRef = splitOpenApiRef(ref)?.specRef;
|
|
7465
|
+
if (!specRef || isRemoteSpecRef(specRef)) return { unique: false, sources: [] };
|
|
7466
|
+
const resolved = resolveSpecRef(specRef, specs);
|
|
7467
|
+
if (resolved.kind === "match") return { unique: true, sources: [resolved.spec.sourcePath] };
|
|
7468
|
+
return { unique: false, sources: resolved.kind === "ambiguous" ? resolved.candidates.map((candidate) => candidate.sourcePath) : [] };
|
|
7469
|
+
}
|
|
7470
|
+
function refWithholdsFrom(ref, spec, specs) {
|
|
7471
|
+
const { unique, sources } = resolvedSources(ref, specs);
|
|
7472
|
+
return unique ? sources[0] === spec.sourcePath : specRefMatches(ref, spec.sourcePath, true) || sources.includes(spec.sourcePath);
|
|
7473
|
+
}
|
|
7474
|
+
function refKeepsIn(ref, spec, specs) {
|
|
7475
|
+
const specRef = splitOpenApiRef(ref)?.specRef;
|
|
7476
|
+
if (!specRef) return false;
|
|
7477
|
+
if (isRemoteSpecRef(specRef)) return specRefMatches(ref, spec.sourcePath, false);
|
|
7478
|
+
const { unique, sources } = resolvedSources(ref, specs);
|
|
7479
|
+
return unique && sources[0] === spec.sourcePath;
|
|
7480
|
+
}
|
|
7481
|
+
function operationKey2(operation) {
|
|
7216
7482
|
const [first, ...rest] = operation.trim().split(/\s+/);
|
|
7217
7483
|
return `${first.toLowerCase()} ${rest.join(" ")}`;
|
|
7218
7484
|
}
|
|
7219
|
-
function keysFor(
|
|
7485
|
+
function keysFor(refs, names) {
|
|
7220
7486
|
return [...new Set(
|
|
7221
|
-
refs.filter(
|
|
7487
|
+
refs.filter(names).map((ref) => splitOpenApiRef(ref)?.operation).filter((op) => !!op).map(operationKey2)
|
|
7222
7488
|
)];
|
|
7223
7489
|
}
|
|
7224
|
-
function withheldOperationKeys(spec, withheldRefs, keptRefs) {
|
|
7225
|
-
const kept = keysFor(spec,
|
|
7226
|
-
return { withheld: keysFor(spec,
|
|
7490
|
+
function withheldOperationKeys(spec, withheldRefs, keptRefs, specs = [spec]) {
|
|
7491
|
+
const kept = keysFor(keptRefs, (ref) => refKeepsIn(ref, spec, specs));
|
|
7492
|
+
return { withheld: keysFor(withheldRefs, (ref) => refWithholdsFrom(ref, spec, specs)).filter((key) => !kept.includes(key)), kept };
|
|
7227
7493
|
}
|
|
7228
7494
|
function withoutByteOrderMark(content) {
|
|
7229
7495
|
return content.length >= 3 && content[0] === 239 && content[1] === 187 && content[2] === 191 ? content.subarray(3) : content;
|
|
@@ -10474,22 +10740,56 @@ function normalizedReferenceKey(value) {
|
|
|
10474
10740
|
function exactReferenceKey(value) {
|
|
10475
10741
|
return value.split(/[?#]/, 1)[0].replace(/^\/+/, "").replace(/\\/g, "/").replace(/\.(?:mdx?|rst|txt)$/i, "");
|
|
10476
10742
|
}
|
|
10477
|
-
function
|
|
10478
|
-
const
|
|
10479
|
-
|
|
10743
|
+
function containerSpec(node) {
|
|
10744
|
+
const value = node.openapi;
|
|
10745
|
+
if (value === void 0) return void 0;
|
|
10746
|
+
const source = value && typeof value === "object" && !Array.isArray(value) ? value.source : value;
|
|
10747
|
+
return typeof source === "string" && source.trim() && !splitOpenApiRef(source) ? source.trim() : null;
|
|
10748
|
+
}
|
|
10749
|
+
function navigationSpecContext(config, pageIdentity) {
|
|
10750
|
+
const context = { operations: [], pageOwners: /* @__PURE__ */ new Map(), pageIdentity };
|
|
10751
|
+
const visit = (node, owner, listed) => {
|
|
10480
10752
|
if (typeof node === "string") {
|
|
10481
|
-
if (splitOpenApiRef(node))
|
|
10482
|
-
|
|
10753
|
+
if (splitOpenApiRef(node)) context.operations.push({ ref: node, owner });
|
|
10754
|
+
else if (listed) {
|
|
10755
|
+
const page = pageIdentity(node);
|
|
10756
|
+
if (page !== null) context.pageOwners.set(page, (context.pageOwners.get(page) ?? /* @__PURE__ */ new Set()).add(owner));
|
|
10757
|
+
}
|
|
10758
|
+
} else if (Array.isArray(node)) node.forEach((child) => visit(child, owner, true));
|
|
10483
10759
|
else if (node && typeof node === "object") {
|
|
10484
10760
|
if (navigationGateReason(node)) return;
|
|
10485
|
-
|
|
10486
|
-
|
|
10487
|
-
|
|
10488
|
-
|
|
10489
|
-
|
|
10490
|
-
|
|
10491
|
-
|
|
10492
|
-
|
|
10761
|
+
const own2 = containerSpec(node);
|
|
10762
|
+
Object.values(node).forEach((child) => visit(child, own2 === void 0 ? owner : own2, false));
|
|
10763
|
+
}
|
|
10764
|
+
};
|
|
10765
|
+
visit(config?.navigation, void 0, false);
|
|
10766
|
+
return context;
|
|
10767
|
+
}
|
|
10768
|
+
function keptOperationRefs(published, navigation, defaultSpec, specs) {
|
|
10769
|
+
const kept = [];
|
|
10770
|
+
const unowned = [];
|
|
10771
|
+
const source = (owner) => {
|
|
10772
|
+
if (!owner || isRemoteSpecRef(owner)) return owner;
|
|
10773
|
+
const resolved = resolveSpecRef(owner, specs);
|
|
10774
|
+
return resolved.kind === "match" ? resolved.spec.sourcePath ?? resolved.spec.filename : owner;
|
|
10775
|
+
};
|
|
10776
|
+
const add = (raw, owner) => {
|
|
10777
|
+
const ref = splitOpenApiRef(raw);
|
|
10778
|
+
if (!ref) return;
|
|
10779
|
+
if (ref.specRef) kept.push(raw);
|
|
10780
|
+
else if (owner) kept.push(withSpecRef(ref, owner));
|
|
10781
|
+
else unowned.push(ref.operation);
|
|
10782
|
+
};
|
|
10783
|
+
for (const { ref, file } of published) {
|
|
10784
|
+
const page = navigation.pageIdentity(file);
|
|
10785
|
+
const owners = new Set([...(page === null ? void 0 : navigation.pageOwners.get(page)) ?? [void 0]].map((owner) => source(owner === void 0 ? defaultSpec : owner)));
|
|
10786
|
+
add(ref, owners.size === 1 ? [...owners][0] : null);
|
|
10787
|
+
}
|
|
10788
|
+
for (const { ref, owner } of navigation.operations) add(ref, source(owner === void 0 ? defaultSpec : owner));
|
|
10789
|
+
return { kept, unowned };
|
|
10790
|
+
}
|
|
10791
|
+
function excludeWithheldOperations(spec, withheldRefs, keptRefs, specs) {
|
|
10792
|
+
const { withheld, kept } = withheldOperationKeys(spec, withheldRefs, keptRefs, specs);
|
|
10493
10793
|
return markExcluded(spec.content, withheld, kept);
|
|
10494
10794
|
}
|
|
10495
10795
|
var TOKEN_SEPARATORS = /[\s"'()<>[\]{}=,;:|\\/`*!?#&]+/;
|
|
@@ -10590,6 +10890,23 @@ function specAssetPath(filename) {
|
|
|
10590
10890
|
function specAsset(filename, content) {
|
|
10591
10891
|
return { path: specAssetPath(filename), content, projectRelative: true };
|
|
10592
10892
|
}
|
|
10893
|
+
function createSpecAssetNamer() {
|
|
10894
|
+
const nameBySource = /* @__PURE__ */ new Map();
|
|
10895
|
+
const sourceByName = /* @__PURE__ */ new Map();
|
|
10896
|
+
return ({ sourcePath, filename, tabLabel }) => {
|
|
10897
|
+
let name = nameBySource.get(sourcePath);
|
|
10898
|
+
if (name === void 0) {
|
|
10899
|
+
name = filename;
|
|
10900
|
+
if (sourceByName.has(name.toLowerCase())) {
|
|
10901
|
+
name = sourcePath.replace(/\//g, "-");
|
|
10902
|
+
while (sourceByName.has(name.toLowerCase())) name = `${(tabLabel ?? "default").replace(/\W+/g, "-")}-${name}`;
|
|
10903
|
+
}
|
|
10904
|
+
nameBySource.set(sourcePath, name);
|
|
10905
|
+
sourceByName.set(name.toLowerCase(), sourcePath);
|
|
10906
|
+
}
|
|
10907
|
+
return name;
|
|
10908
|
+
};
|
|
10909
|
+
}
|
|
10593
10910
|
function mintlifyTopLevelApiReferences(config) {
|
|
10594
10911
|
const api = config?.api && typeof config.api === "object" && !Array.isArray(config.api) ? config.api : null;
|
|
10595
10912
|
if (!api) return [];
|
|
@@ -10601,19 +10918,25 @@ function mintlifyTopLevelApiReferences(config) {
|
|
|
10601
10918
|
}
|
|
10602
10919
|
return references;
|
|
10603
10920
|
}
|
|
10604
|
-
function
|
|
10921
|
+
function specFileCandidates(files) {
|
|
10922
|
+
return files.filter((file) => /\.(?:json|ya?ml)$/i.test(file.relativePath)).map((file) => ({ sourcePath: file.relativePath, filename: specRefBaseName(file.relativePath) }));
|
|
10923
|
+
}
|
|
10924
|
+
function resolveMintlifyApiSpecs(mintlifyConfig, files, warnings, remoteSpecs, nameSpec, pages = []) {
|
|
10605
10925
|
if (!mintlifyConfig) return [];
|
|
10606
10926
|
const references = [
|
|
10607
10927
|
...mintlifyTopLevelApiReferences(mintlifyConfig),
|
|
10608
10928
|
...mintlifyNavigationApiReferences(mintlifyConfig)
|
|
10609
10929
|
];
|
|
10610
|
-
const
|
|
10611
|
-
const
|
|
10930
|
+
const known = new Set(references.map((reference) => canonicalSpecRef(reference.value)));
|
|
10931
|
+
const specFiles = specFileCandidates(files);
|
|
10932
|
+
const namedFiles = /* @__PURE__ */ new Map();
|
|
10612
10933
|
for (const page of pages) {
|
|
10613
10934
|
const specRef = page.openapi ? splitOpenApiRef(page.openapi)?.specRef : void 0;
|
|
10614
10935
|
if (!specRef || /^[a-z][a-z0-9+.-]*:/i.test(specRef)) continue;
|
|
10615
|
-
const
|
|
10616
|
-
|
|
10936
|
+
const named = namedFiles.get(specRef) ?? resolveSpecRef(specRef, specFiles, false);
|
|
10937
|
+
namedFiles.set(specRef, named);
|
|
10938
|
+
const key = named.kind === "match" ? named.spec.sourcePath : "";
|
|
10939
|
+
if (!key || known.has(key)) continue;
|
|
10617
10940
|
known.add(key);
|
|
10618
10941
|
references.push({ value: key, kind: "openapi", tabLabel: `OpenAPI: ${key}`, hidden: true, pageOnly: true });
|
|
10619
10942
|
}
|
|
@@ -10631,14 +10954,28 @@ function resolveMintlifyApiSpecs(mintlifyConfig, files, warnings, remoteSpecs, p
|
|
|
10631
10954
|
delete mount.operations;
|
|
10632
10955
|
}
|
|
10633
10956
|
};
|
|
10957
|
+
const listsNothing = (reference) => !reference.groups && !reference.operationsWithheld && !reference.otherLanguage;
|
|
10958
|
+
const groupTargets = /* @__PURE__ */ new Map();
|
|
10634
10959
|
const specs = [];
|
|
10635
10960
|
for (const reference of references) {
|
|
10636
10961
|
const dedupeKey = `${reference.kind}:${reference.value}:${reference.tabLabel ?? ""}`;
|
|
10637
10962
|
if (seen.has(dedupeKey)) {
|
|
10638
10963
|
mountDirectory(remoteByKey.get(dedupeKey), reference);
|
|
10964
|
+
const shared = groupTargets.get(dedupeKey);
|
|
10965
|
+
if (shared && !shared.unlisted) {
|
|
10966
|
+
if (reference.operationsWithheld) shared.withheld = true;
|
|
10967
|
+
if (reference.groups) {
|
|
10968
|
+
const merged = mergeApiGroups(shared.target.groups, reference.groups);
|
|
10969
|
+
if (merged) shared.target.groups = merged;
|
|
10970
|
+
} else if (listsNothing(reference)) {
|
|
10971
|
+
shared.unlisted = true;
|
|
10972
|
+
delete shared.target.groups;
|
|
10973
|
+
}
|
|
10974
|
+
}
|
|
10639
10975
|
continue;
|
|
10640
10976
|
}
|
|
10641
10977
|
seen.add(dedupeKey);
|
|
10978
|
+
const groups = mergeApiGroups(void 0, reference.groups);
|
|
10642
10979
|
const tabSuffix = reference.tabLabel ? ` (tab "${reference.tabLabel}")` : "";
|
|
10643
10980
|
if (reference.kind === "asyncapi") {
|
|
10644
10981
|
warnings.push({
|
|
@@ -10648,10 +10985,11 @@ function resolveMintlifyApiSpecs(mintlifyConfig, files, warnings, remoteSpecs, p
|
|
|
10648
10985
|
continue;
|
|
10649
10986
|
}
|
|
10650
10987
|
if (/^https:\/\//i.test(reference.value)) {
|
|
10651
|
-
const remote = { url: reference.value, ...reference.tabLabel ? { tabLabel: reference.tabLabel } : {}, ...reference.parentTab ? { parentTab: reference.parentTab } : {}, ...reference.icon ? { icon: reference.icon } : {}, ...reference.hidden ? { hidden: true } : {} };
|
|
10988
|
+
const remote = { url: reference.value, ...reference.tabLabel ? { tabLabel: reference.tabLabel } : {}, ...reference.parentTab ? { parentTab: reference.parentTab } : {}, ...reference.icon ? { icon: reference.icon } : {}, ...reference.hidden ? { hidden: true } : {}, ...groups ? { groups } : {} };
|
|
10652
10989
|
mountDirectory(remote, reference);
|
|
10653
10990
|
remoteSpecs.push(remote);
|
|
10654
10991
|
remoteByKey.set(dedupeKey, remote);
|
|
10992
|
+
groupTargets.set(dedupeKey, { target: remote, unlisted: listsNothing(reference), withheld: reference.operationsWithheld === true });
|
|
10655
10993
|
warnings.push({
|
|
10656
10994
|
code: "unsupported-config",
|
|
10657
10995
|
message: `The remote OpenAPI spec "${reference.value}"${tabSuffix} requires a network download before this import is complete.`,
|
|
@@ -10663,7 +11001,7 @@ function resolveMintlifyApiSpecs(mintlifyConfig, files, warnings, remoteSpecs, p
|
|
|
10663
11001
|
warnings.push({ code: "unsupported-config", message: `The OpenAPI spec "${reference.value}"${tabSuffix} uses insecure HTTP and was not imported.`, source: reference.value });
|
|
10664
11002
|
continue;
|
|
10665
11003
|
}
|
|
10666
|
-
const key = reference.value
|
|
11004
|
+
const key = canonicalSpecRef(reference.value);
|
|
10667
11005
|
const match = files.find((file) => file.relativePath === key);
|
|
10668
11006
|
if (!match) {
|
|
10669
11007
|
warnings.push({
|
|
@@ -10680,7 +11018,7 @@ function resolveMintlifyApiSpecs(mintlifyConfig, files, warnings, remoteSpecs, p
|
|
|
10680
11018
|
}
|
|
10681
11019
|
const content = readSpecFile(match.absolutePath, match.relativePath, warnings);
|
|
10682
11020
|
if (!content) continue;
|
|
10683
|
-
|
|
11021
|
+
const spec = {
|
|
10684
11022
|
filename: basename3(match.relativePath),
|
|
10685
11023
|
content,
|
|
10686
11024
|
tabLabel: reference.tabLabel,
|
|
@@ -10689,24 +11027,16 @@ function resolveMintlifyApiSpecs(mintlifyConfig, files, warnings, remoteSpecs, p
|
|
|
10689
11027
|
hidden: reference.hidden,
|
|
10690
11028
|
...reference.pageOnly ? { pageOnly: true } : {},
|
|
10691
11029
|
sourcePath: match.relativePath,
|
|
10692
|
-
directory: reference.directory
|
|
10693
|
-
|
|
11030
|
+
directory: reference.directory,
|
|
11031
|
+
...groups ? { groups } : {}
|
|
11032
|
+
};
|
|
11033
|
+
specs.push(spec);
|
|
11034
|
+
groupTargets.set(dedupeKey, { target: spec, unlisted: listsNothing(reference), withheld: reference.operationsWithheld === true });
|
|
10694
11035
|
}
|
|
10695
|
-
const
|
|
10696
|
-
|
|
10697
|
-
for (const spec of specs) {
|
|
10698
|
-
const groupKey = spec.tabLabel ?? "\0default";
|
|
10699
|
-
const owner = filenameOwners.get(spec.filename);
|
|
10700
|
-
if (owner !== void 0 && owner !== groupKey && filenameSources.get(spec.filename) !== spec.sourcePath) {
|
|
10701
|
-
let disambiguated = spec.sourcePath.replace(/\//g, "-");
|
|
10702
|
-
while (filenameOwners.has(disambiguated) && filenameOwners.get(disambiguated) !== groupKey) {
|
|
10703
|
-
disambiguated = `${groupKey.replace(/\W+/g, "-")}-${disambiguated}`;
|
|
10704
|
-
}
|
|
10705
|
-
spec.filename = disambiguated;
|
|
10706
|
-
}
|
|
10707
|
-
filenameOwners.set(spec.filename, groupKey);
|
|
10708
|
-
filenameSources.set(spec.filename, spec.sourcePath);
|
|
11036
|
+
for (const { target: target2, unlisted, withheld } of groupTargets.values()) {
|
|
11037
|
+
if (withheld && !unlisted && !target2.groups) target2.navigation = false;
|
|
10709
11038
|
}
|
|
11039
|
+
for (const spec of specs) spec.filename = nameSpec(spec);
|
|
10710
11040
|
return specs;
|
|
10711
11041
|
}
|
|
10712
11042
|
function rewriteMintlifyPageSpecRefs(pages, specs, remoteUrls, warnings, explainMissing = () => "no such file was found") {
|
|
@@ -10719,12 +11049,13 @@ function rewriteMintlifyPageSpecRefs(pages, specs, remoteUrls, warnings, explain
|
|
|
10719
11049
|
}
|
|
10720
11050
|
continue;
|
|
10721
11051
|
}
|
|
10722
|
-
const key = ref.specRef
|
|
10723
|
-
const
|
|
10724
|
-
|
|
10725
|
-
|
|
10726
|
-
if (
|
|
10727
|
-
|
|
11052
|
+
const key = canonicalSpecRef(ref.specRef);
|
|
11053
|
+
const resolved = resolveSpecRef(ref.specRef, specs);
|
|
11054
|
+
if (resolved.kind === "match") {
|
|
11055
|
+
page.openapi = withSpecRef(ref, specAssetPath(resolved.spec.filename));
|
|
11056
|
+
} else if (resolved.kind === "ambiguous") {
|
|
11057
|
+
const candidates = resolved.candidates.map((spec) => spec.sourcePath ?? spec.filename).join(", ");
|
|
11058
|
+
warnings.push({ code: "unsupported-config", message: `Page "${page.id}" references the OpenAPI spec "${ref.specRef}", which fits more than one spec (${candidates}), so it was left as written and the page will not render an endpoint. Write the full path of the spec in the page's openapi frontmatter.`, source: page.source });
|
|
10728
11059
|
} else {
|
|
10729
11060
|
warnings.push({ code: "unsupported-config", message: `Page "${page.id}" references the OpenAPI spec "${ref.specRef}", which was not migrated (${explainMissing(key)}); the page will not render an endpoint.`, source: page.source });
|
|
10730
11061
|
}
|
|
@@ -12055,9 +12386,12 @@ function injectOpenApiSpecs(config, specs, warnings) {
|
|
|
12055
12386
|
const apiTab = spec.tabLabel ? tabs.find((tab) => tab.tab === spec.tabLabel) : tabs.find((tab) => tab.tab.toLowerCase().includes("api"));
|
|
12056
12387
|
if (apiTab) {
|
|
12057
12388
|
if (apiTab.api && warnings) {
|
|
12389
|
+
const source = specAssetPath(spec.filename);
|
|
12390
|
+
const pageBound = spec.pageReferenced && !tabs.some((tab) => tab.api?.source === source);
|
|
12391
|
+
if (pageBound) insertApiTab(tabs, { tab: `OpenAPI: ${spec.sourcePath ?? spec.filename}`, hidden: true, api: { source } });
|
|
12058
12392
|
warnings.push({
|
|
12059
12393
|
code: "unsupported-config",
|
|
12060
|
-
message: `Tab "${apiTab.tab}" already uses another OpenAPI spec, and Thally supports one API spec per tab, so "${
|
|
12394
|
+
message: `Tab "${apiTab.tab}" already uses another OpenAPI spec, and Thally supports one API spec per tab, so "${source}" ${pageBound ? "gets no endpoint list of its own; the pages that name it still show their endpoint. Put it in its own tab to list all its endpoints." : "was not added. Put it in its own tab to include it."}`
|
|
12061
12395
|
});
|
|
12062
12396
|
continue;
|
|
12063
12397
|
}
|
|
@@ -12066,15 +12400,18 @@ function injectOpenApiSpecs(config, specs, warnings) {
|
|
|
12066
12400
|
// An API-only tab needs generated endpoint navigation; an authored
|
|
12067
12401
|
// page tab keeps its own groups alongside the bound spec, unless
|
|
12068
12402
|
// Mintlify generated the endpoint pages (the renderer appends the
|
|
12069
|
-
// endpoint groups after the authored ones).
|
|
12070
|
-
|
|
12403
|
+
// endpoint groups after the authored ones) or docs.json lists the
|
|
12404
|
+
// operations itself (those authored groups are the API navigation).
|
|
12405
|
+
// A spec whose listed operations are all withheld has no endpoint navigation either way.
|
|
12406
|
+
...spec.navigation === false || (apiTab.groups?.length || apiTab.pages?.length) && !spec.generatedNavigation && !spec.groups ? { navigation: false } : {},
|
|
12407
|
+
...spec.groups ? { groups: spec.groups } : {}
|
|
12071
12408
|
};
|
|
12072
12409
|
} else {
|
|
12073
12410
|
insertApiTab(tabs, {
|
|
12074
12411
|
tab: spec.tabLabel ?? "API Reference",
|
|
12075
12412
|
...spec.icon ? { icon: spec.icon } : {},
|
|
12076
12413
|
...spec.hidden ? { hidden: true } : {},
|
|
12077
|
-
api: { source: specAssetPath(spec.filename) }
|
|
12414
|
+
api: { source: specAssetPath(spec.filename), ...spec.navigation === false ? { navigation: false } : {}, ...spec.groups ? { groups: spec.groups } : {} }
|
|
12078
12415
|
}, spec.parentTab);
|
|
12079
12416
|
}
|
|
12080
12417
|
}
|
|
@@ -12159,6 +12496,8 @@ function migrateRepository(options) {
|
|
|
12159
12496
|
defaultVersionPrefixes = mintlifyDefaultVersionPrefixes(config);
|
|
12160
12497
|
allVersionPrefixes = mintlifyAllVersionPrefixes(config);
|
|
12161
12498
|
const projected = projectMintlifyNavigation(config, {
|
|
12499
|
+
// injectOpenApiSpecs / hydrateRemoteApiSpecs bind the authored operation lists to their API tabs.
|
|
12500
|
+
operationGroups: true,
|
|
12162
12501
|
resolveSourceRef: (repo) => {
|
|
12163
12502
|
const ref = activeSourceRefs.find((candidate) => candidate.repo.toLowerCase() === repo.toLowerCase());
|
|
12164
12503
|
if (!ref) return null;
|
|
@@ -12316,6 +12655,7 @@ ${warnings.map((warning) => `- ${warning.message}`).join("\n")}`);
|
|
|
12316
12655
|
const gateByPath = /* @__PURE__ */ new Map();
|
|
12317
12656
|
const withheldSpecRefs = [];
|
|
12318
12657
|
const publishedSpecRefs = [];
|
|
12658
|
+
const publishedSpecPages = [];
|
|
12319
12659
|
const withheldPaths = /* @__PURE__ */ new Set();
|
|
12320
12660
|
const isDocFile = (file) => [".md", ".mdx"].includes(extname6(file.relativePath).toLowerCase());
|
|
12321
12661
|
const isGateCandidate = (file) => isDocFile(file) && !file.relativePath.split("/").some((segment) => SNIPPET_DIRECTORIES.has(segment.toLowerCase()));
|
|
@@ -12352,6 +12692,7 @@ ${warnings.map((warning) => `- ${warning.message}`).join("\n")}`);
|
|
|
12352
12692
|
const verdict = classifyPageGate(file);
|
|
12353
12693
|
gateByPath.set(file.absolutePath, verdict);
|
|
12354
12694
|
if (verdict.openapi) (verdict.reason ? withheldSpecRefs : publishedSpecRefs).push(verdict.openapi);
|
|
12695
|
+
if (verdict.openapi && !verdict.reason) publishedSpecPages.push({ ref: verdict.openapi, file: file.relativePath });
|
|
12355
12696
|
if (verdict.reason) withheldPaths.add(file.absolutePath);
|
|
12356
12697
|
}
|
|
12357
12698
|
for (const file of mintignoreFilteredFiles) {
|
|
@@ -12455,6 +12796,23 @@ ${warnings.map((warning) => `- ${warning.message}`).join("\n")}`);
|
|
|
12455
12796
|
let discovered = files.length;
|
|
12456
12797
|
const localeConfig = docsConfig.i18n;
|
|
12457
12798
|
const defaultPageIds = new Set([...referenceMap.values()].filter((reference) => !reference.locale || reference.locale === localeConfig?.defaultLocale).map((reference) => reference.navigationId));
|
|
12799
|
+
const resolvePageIdentity = (path) => {
|
|
12800
|
+
const referenced = exactReferenceMap.get(exactReferenceKey(path)) ?? referenceMap.get(normalizedReferenceKey(path));
|
|
12801
|
+
let locale = referenced?.locale;
|
|
12802
|
+
let navigationId = referenced?.navigationId ?? pageIdFromReference(path, platform === "mintlify");
|
|
12803
|
+
if (!referenced && localeConfig) {
|
|
12804
|
+
for (const entry of localeConfig.locales) {
|
|
12805
|
+
const localized = mintlifyLocalizedReference(path, entry.code, defaultPageIds);
|
|
12806
|
+
if (localized === path) continue;
|
|
12807
|
+
locale = entry.code;
|
|
12808
|
+
navigationId = pageIdFromReference(localized, platform === "mintlify");
|
|
12809
|
+
break;
|
|
12810
|
+
}
|
|
12811
|
+
}
|
|
12812
|
+
if (!navigationId) return null;
|
|
12813
|
+
const isDefaultLocale = !locale || locale === localeConfig?.defaultLocale;
|
|
12814
|
+
return { locale, navigationId, id: isDefaultLocale ? navigationId : `${locale}/${navigationId}` };
|
|
12815
|
+
};
|
|
12458
12816
|
const routeAliases = [];
|
|
12459
12817
|
const pageFiles = [...files].sort((left, right) => {
|
|
12460
12818
|
const leftOrder = referenceOrder.get(normalizedReferenceKey(left.relativePath)) ?? Number.MAX_SAFE_INTEGER;
|
|
@@ -12550,7 +12908,6 @@ ${warnings.map((warning) => `- ${warning.message}`).join("\n")}`);
|
|
|
12550
12908
|
}
|
|
12551
12909
|
continue;
|
|
12552
12910
|
}
|
|
12553
|
-
const key = normalizedReferenceKey(file.relativePath);
|
|
12554
12911
|
let pageGate;
|
|
12555
12912
|
{
|
|
12556
12913
|
pageGate = gateByPath.get(file.absolutePath);
|
|
@@ -12600,25 +12957,13 @@ ${warnings.map((warning) => `- ${warning.message}`).join("\n")}`);
|
|
|
12600
12957
|
}
|
|
12601
12958
|
}
|
|
12602
12959
|
const isRestrictedPage = Boolean(pageGate?.reason);
|
|
12603
|
-
const
|
|
12604
|
-
|
|
12605
|
-
let navigationId = referenced?.navigationId ?? pageIdFromReference(file.relativePath, platform === "mintlify");
|
|
12606
|
-
if (!referenced && localeConfig) {
|
|
12607
|
-
for (const entry of localeConfig.locales) {
|
|
12608
|
-
const localized = mintlifyLocalizedReference(file.relativePath, entry.code, defaultPageIds);
|
|
12609
|
-
if (localized === file.relativePath) continue;
|
|
12610
|
-
locale = entry.code;
|
|
12611
|
-
navigationId = pageIdFromReference(localized, platform === "mintlify");
|
|
12612
|
-
break;
|
|
12613
|
-
}
|
|
12614
|
-
}
|
|
12615
|
-
if (!navigationId) {
|
|
12960
|
+
const identity = resolvePageIdentity(file.relativePath);
|
|
12961
|
+
if (!identity) {
|
|
12616
12962
|
skipped++;
|
|
12617
12963
|
warnings.push({ code: "invalid-page", message: "Page path could not be normalized safely.", source: file.relativePath });
|
|
12618
12964
|
continue;
|
|
12619
12965
|
}
|
|
12620
|
-
const
|
|
12621
|
-
const id = isDefaultLocale ? navigationId : `${locale}/${navigationId}`;
|
|
12966
|
+
const { locale, navigationId, id } = identity;
|
|
12622
12967
|
let raw = inlineMdxSnippets(
|
|
12623
12968
|
mintlifyProjectRoot ? importUndeclaredSnippetComponents(readFileSync6(file.absolutePath, "utf8"), file.absolutePath, repositoryDir, mintlifyProjectRoot, snippetExports, snippetAliases, inlineGate, warnings) : injectDocusaurusGlobalImports(readFileSync6(file.absolutePath, "utf8"), globalDocusaurusImports),
|
|
12624
12969
|
file.absolutePath,
|
|
@@ -13267,8 +13612,21 @@ ${warnings.map((warning) => `- ${warning.message}`).join("\n")}`);
|
|
|
13267
13612
|
const warnSharedSpec = (path, excluded = []) => {
|
|
13268
13613
|
warnings.push({ code: "gated-page", message: sharedSpecMessage(path, excluded), source: path });
|
|
13269
13614
|
};
|
|
13270
|
-
const
|
|
13271
|
-
const allSpecs = resolveMintlifyApiSpecs(mintlifyConfig, files, warnings, remoteApiSpecs, pages.filter((page) => !restrictedPages.has(page)));
|
|
13615
|
+
const nameSpec = createSpecAssetNamer();
|
|
13616
|
+
const allSpecs = resolveMintlifyApiSpecs(mintlifyConfig, files, warnings, remoteApiSpecs, nameSpec, pages.filter((page) => !restrictedPages.has(page)));
|
|
13617
|
+
const navigation = navigationSpecContext(mintlifyConfig, (path) => resolvePageIdentity(path)?.id ?? null);
|
|
13618
|
+
const defaultSources = /* @__PURE__ */ new Set([
|
|
13619
|
+
...allSpecs.filter((spec) => !spec.pageOnly && spec.tabLabel === void 0).map((spec) => spec.sourcePath),
|
|
13620
|
+
...remoteApiSpecs.filter((spec) => spec.tabLabel === void 0).map((spec) => spec.url)
|
|
13621
|
+
]);
|
|
13622
|
+
const keptOperations = (fallbackSource) => {
|
|
13623
|
+
const defaultSpec = defaultSources.size === 0 ? fallbackSource : defaultSources.size === 1 ? [...defaultSources][0] : void 0;
|
|
13624
|
+
const candidates = fallbackSource ? [{ sourcePath: fallbackSource, filename: basename3(fallbackSource) }, ...allSpecs] : allSpecs;
|
|
13625
|
+
const { kept, unowned } = keptOperationRefs(publishedSpecPages, navigation, defaultSpec, candidates);
|
|
13626
|
+
return { kept: kept.filter((ref) => !namesSeveralSpecs(ref, allSpecs)), unowned };
|
|
13627
|
+
};
|
|
13628
|
+
let { kept: keptSpecRefs, unowned: unownedOperations } = keptOperations();
|
|
13629
|
+
const withheldKeys = /* @__PURE__ */ new Set();
|
|
13272
13630
|
for (const remote of remoteApiSpecs) {
|
|
13273
13631
|
const { withheld, kept } = withheldOperationKeys({ sourcePath: remote.url, filename: remote.url }, withheldSpecRefs, keptSpecRefs);
|
|
13274
13632
|
if (withheld.length > 0) {
|
|
@@ -13278,9 +13636,10 @@ ${warnings.map((warning) => `- ${warning.message}`).join("\n")}`);
|
|
|
13278
13636
|
}
|
|
13279
13637
|
const withheldOperations = /* @__PURE__ */ new Map();
|
|
13280
13638
|
for (const spec of allSpecs) {
|
|
13281
|
-
const result = excludeWithheldOperations(spec, withheldSpecRefs, keptSpecRefs);
|
|
13639
|
+
const result = excludeWithheldOperations(spec, withheldSpecRefs, keptSpecRefs, allSpecs);
|
|
13282
13640
|
spec.content = result.content;
|
|
13283
13641
|
withheldOperations.set(spec, result.excluded);
|
|
13642
|
+
result.excluded.forEach((operation) => withheldKeys.add(operationKey2(operation)));
|
|
13284
13643
|
}
|
|
13285
13644
|
const resolvedSpecs = allSpecs.filter((spec) => !spec.pageOnly);
|
|
13286
13645
|
const pageOnlySpecs = allSpecs.filter((spec) => spec.pageOnly);
|
|
@@ -13288,12 +13647,14 @@ ${warnings.map((warning) => `- ${warning.message}`).join("\n")}`);
|
|
|
13288
13647
|
if (!assets.some((asset) => asset.path === specAssetPath(spec.filename))) {
|
|
13289
13648
|
assets.push(specAsset(spec.filename, spec.content));
|
|
13290
13649
|
}
|
|
13291
|
-
if (withheldSpecRefs.some((ref) => specRefMatches(ref, spec.sourcePath,
|
|
13650
|
+
if (withheldSpecRefs.some((ref) => specRefMatches(ref, spec.sourcePath, true))) warnSharedSpec(spec.sourcePath, withheldOperations.get(spec));
|
|
13292
13651
|
}
|
|
13293
13652
|
let pageSpecs = resolvedSpecs;
|
|
13294
13653
|
if (resolvedSpecs.length > 0) {
|
|
13654
|
+
const namedByPages = new Set(pages.filter((page) => !restrictedPages.has(page)).map((page) => specNamedByPage(page.openapi, resolvedSpecs)));
|
|
13295
13655
|
for (const spec of resolvedSpecs) {
|
|
13296
|
-
spec.
|
|
13656
|
+
spec.pageReferenced = namedByPages.has(spec);
|
|
13657
|
+
spec.generatedNavigation = Boolean(spec.directory) && !publishedSpecRefs.some((ref) => specRefMatches(ref, spec.sourcePath, true));
|
|
13297
13658
|
}
|
|
13298
13659
|
docsConfig = injectOpenApiSpecs(docsConfig, resolvedSpecs, warnings);
|
|
13299
13660
|
if (remoteApiSpecs.length > 0) {
|
|
@@ -13311,13 +13672,16 @@ ${warnings.map((warning) => `- ${warning.message}`).join("\n")}`);
|
|
|
13311
13672
|
const fallback = findOpenApi(files);
|
|
13312
13673
|
const fallbackContent = fallback ? readSpecFile(fallback.absolutePath, fallback.relativePath, warnings) : void 0;
|
|
13313
13674
|
if (fallback && fallbackContent) {
|
|
13314
|
-
const
|
|
13315
|
-
const matches = (ref) => specRefMatches(ref, fallback.relativePath, filename, true);
|
|
13675
|
+
const matches = (ref) => specRefMatches(ref, fallback.relativePath, true);
|
|
13316
13676
|
if (withheldSpecRefs.some(matches) && !publishedSpecRefs.some(matches)) {
|
|
13317
|
-
quarantinedFiles.push({ path: `${QUARANTINE_DIRECTORY}/assets/${specAssetPath(
|
|
13677
|
+
quarantinedFiles.push({ path: `${QUARANTINE_DIRECTORY}/assets/${specAssetPath(basename3(fallback.relativePath))}`, content: fallbackContent });
|
|
13318
13678
|
withheldAssetCount++;
|
|
13319
13679
|
} else {
|
|
13320
|
-
const
|
|
13680
|
+
const filename = nameSpec({ sourcePath: fallback.relativePath, filename: basename3(fallback.relativePath) });
|
|
13681
|
+
const fallbackSpec = { sourcePath: fallback.relativePath, filename, content: fallbackContent };
|
|
13682
|
+
({ kept: keptSpecRefs, unowned: unownedOperations } = keptOperations(fallback.relativePath));
|
|
13683
|
+
const pruned = excludeWithheldOperations(fallbackSpec, withheldSpecRefs, keptSpecRefs, [fallbackSpec, ...allSpecs]);
|
|
13684
|
+
pruned.excluded.forEach((operation) => withheldKeys.add(operationKey2(operation)));
|
|
13321
13685
|
if (!assets.some((asset) => asset.path === specAssetPath(filename))) {
|
|
13322
13686
|
assets.push(specAsset(filename, pruned.content));
|
|
13323
13687
|
}
|
|
@@ -13329,13 +13693,22 @@ ${warnings.map((warning) => `- ${warning.message}`).join("\n")}`);
|
|
|
13329
13693
|
}
|
|
13330
13694
|
for (const spec of pageOnlySpecs) {
|
|
13331
13695
|
if (!assets.some((asset) => asset.path === specAssetPath(spec.filename))) assets.push(specAsset(spec.filename, spec.content));
|
|
13332
|
-
if (withheldSpecRefs.some((ref) => specRefMatches(ref, spec.sourcePath,
|
|
13696
|
+
if (withheldSpecRefs.some((ref) => specRefMatches(ref, spec.sourcePath, true))) warnSharedSpec(spec.sourcePath, withheldOperations.get(spec));
|
|
13333
13697
|
}
|
|
13334
13698
|
if (pageOnlySpecs.length > 0) {
|
|
13335
13699
|
docsConfig = injectOpenApiSpecs(docsConfig, pageOnlySpecs, warnings);
|
|
13336
13700
|
pageSpecs = [...pageSpecs, ...pageOnlySpecs];
|
|
13337
13701
|
}
|
|
13702
|
+
const notKeptPublic = [...new Set(unownedOperations.filter((operation) => withheldKeys.has(operationKey2(operation))))];
|
|
13703
|
+
if (notKeptPublic.length > 0) {
|
|
13704
|
+
warnings.push({
|
|
13705
|
+
code: "gated-page",
|
|
13706
|
+
message: `${notKeptPublic.length} operation(s) withheld from a published OpenAPI spec (${notKeptPublic.join(", ")}) are also named by a published page or navigation entry that does not say which spec it means, so that reference did not keep them public. Write the spec in its openapi value (for example "openapi.json GET /x") to publish the operation.`
|
|
13707
|
+
});
|
|
13708
|
+
}
|
|
13338
13709
|
const explainMissingSpec = (key) => {
|
|
13710
|
+
const fits = resolveSpecRef(key, specFileCandidates(files), false);
|
|
13711
|
+
if (fits.kind === "ambiguous") return `several spec files fit that name (${fits.candidates.map((spec) => spec.sourcePath).join(", ")}); write the full path in the page's openapi frontmatter`;
|
|
13339
13712
|
const sameName = scannedFiles.find((file) => file.relativePath.toLowerCase() === key.toLowerCase());
|
|
13340
13713
|
if (sameName && sameName.relativePath !== key) return `paths are case-sensitive; the file is at "${sameName.relativePath}"`;
|
|
13341
13714
|
if (sameName && mintignoreMatcher?.ignores(sameName.relativePath)) return "the file is excluded by .mintignore";
|
|
@@ -13675,10 +14048,10 @@ ${reasons.map((reason) => `- ${reason}`).join("\n")}` : "No importable Markdown
|
|
|
13675
14048
|
const sourceFavicon = mintlifyConfig?.favicon ?? fernRawConfig?.favicon ?? docusaurusSettings?.favicon;
|
|
13676
14049
|
const logo = brandVariants(sourceLogo);
|
|
13677
14050
|
const favicon = brandVariants(sourceFavicon);
|
|
13678
|
-
const logoLight = publicBrandPath(logo.light);
|
|
13679
14051
|
const logoDark = publicBrandPath(logo.dark);
|
|
13680
|
-
const
|
|
14052
|
+
const logoLight = publicBrandPath(logo.light) ?? logoDark;
|
|
13681
14053
|
const faviconDark = publicBrandPath(favicon.dark);
|
|
14054
|
+
const faviconLight = publicBrandPath(favicon.light) ?? faviconDark;
|
|
13682
14055
|
if (logoLight) docsConfig = {
|
|
13683
14056
|
...docsConfig,
|
|
13684
14057
|
navbar: {
|
|
@@ -13707,15 +14080,30 @@ ${reasons.map((reason) => `- ${reason}`).join("\n")}` : "No importable Markdown
|
|
|
13707
14080
|
const decoration = background.decoration;
|
|
13708
14081
|
const image = publicBrandPath(background.image);
|
|
13709
14082
|
const imageDark = publicBrandPath(background.imageDark);
|
|
13710
|
-
|
|
13711
|
-
...docsConfig,
|
|
13712
|
-
|
|
13713
|
-
|
|
13714
|
-
|
|
13715
|
-
...image ? { image } : {},
|
|
13716
|
-
...imageDark ? { imageDark } : {}
|
|
13717
|
-
}
|
|
14083
|
+
const mapped = {
|
|
14084
|
+
...docsConfig.background,
|
|
14085
|
+
...decoration === "none" || decoration === "grid" || decoration === "gradient" ? { decoration } : {},
|
|
14086
|
+
...image ? { image } : {},
|
|
14087
|
+
...imageDark ? { imageDark } : {}
|
|
13718
14088
|
};
|
|
14089
|
+
if (Object.keys(mapped).length > 0) docsConfig = { ...docsConfig, background: mapped };
|
|
14090
|
+
const canvas = background.color && typeof background.color === "object" ? background.color : {};
|
|
14091
|
+
for (const mode of ["light", "dark"]) {
|
|
14092
|
+
if (canvas[mode] === void 0) continue;
|
|
14093
|
+
const hex = typeof canvas[mode] === "string" ? cssColorToHex(canvas[mode]) : void 0;
|
|
14094
|
+
if (!hex) {
|
|
14095
|
+
warnings.push({
|
|
14096
|
+
code: "unsupported-config",
|
|
14097
|
+
message: `background.color.${mode} ${JSON.stringify(canvas[mode])?.slice(0, 40)} is not a hex or rgb() colour (for example #121317) and was dropped, so that mode keeps Thally's default canvas. Use a hex value in docs.json to set it.`,
|
|
14098
|
+
source: "docs.json"
|
|
14099
|
+
});
|
|
14100
|
+
continue;
|
|
14101
|
+
}
|
|
14102
|
+
docsConfig = {
|
|
14103
|
+
...docsConfig,
|
|
14104
|
+
colors: { ...docsConfig.colors, [mode]: { ...docsConfig.colors?.[mode], background: hex } }
|
|
14105
|
+
};
|
|
14106
|
+
}
|
|
13719
14107
|
}
|
|
13720
14108
|
}
|
|
13721
14109
|
if (platform === "docusaurus") {
|
|
@@ -13725,13 +14113,23 @@ ${reasons.map((reason) => `- ${reason}`).join("\n")}` : "No importable Markdown
|
|
|
13725
14113
|
...docsConfig,
|
|
13726
14114
|
favicon: { light: faviconLight, ...faviconDark ? { dark: faviconDark } : {} }
|
|
13727
14115
|
};
|
|
13728
|
-
const
|
|
13729
|
-
|
|
13730
|
-
|
|
13731
|
-
];
|
|
14116
|
+
const notImported = (variants) => [variants.light, variants.dark].filter((value) => typeof value === "string" && !publicBrandPath(value));
|
|
14117
|
+
const missingLogo = notImported(logo);
|
|
14118
|
+
const missingFavicon = notImported(favicon);
|
|
14119
|
+
const missingBrand = [...missingLogo, ...missingFavicon];
|
|
14120
|
+
const substituted = [
|
|
14121
|
+
...missingLogo.length > 0 && logoLight ? [`logo (${logoLight})`] : [],
|
|
14122
|
+
...missingFavicon.length > 0 && faviconLight ? [`favicon (${faviconLight})`] : []
|
|
14123
|
+
].map((asset) => ` The imported ${asset} is used for both light and dark mode.`).join("");
|
|
13732
14124
|
if (missingBrand.length > 0) warnings.push({
|
|
13733
14125
|
code: "unsupported-config",
|
|
13734
|
-
message: `Brand asset(s) were referenced but not imported: ${[...new Set(missingBrand)].join(", ")}. Add these files under public/ or update docs.json
|
|
14126
|
+
message: `Brand asset(s) were referenced but not imported: ${[...new Set(missingBrand)].join(", ")}. Add these files under public/ or update docs.json.${substituted}`
|
|
14127
|
+
});
|
|
14128
|
+
const logoHref = sourceLogo && typeof sourceLogo === "object" ? sourceLogo.href : void 0;
|
|
14129
|
+
if (typeof logoHref === "string" && logoHref.trim() && logoHref.trim() !== "/") warnings.push({
|
|
14130
|
+
code: "unsupported-config",
|
|
14131
|
+
message: `logo.href ${JSON.stringify(logoHref.trim().slice(0, 120))} was dropped: the header logo always links to the docs home page. Add it as a navbar link in docs.json if readers need it.`,
|
|
14132
|
+
source: mintlifyConfig ? "docs.json" : "docs.yml"
|
|
13735
14133
|
});
|
|
13736
14134
|
if (platform === "mintlify") {
|
|
13737
14135
|
docsConfig = { ...docsConfig, markdown: { enabled: true } };
|
|
@@ -13764,7 +14162,7 @@ ${reasons.map((reason) => `- ${reason}`).join("\n")}` : "No importable Markdown
|
|
|
13764
14162
|
message: `Fern global theme ${JSON.stringify(fernRawConfig["global-theme"])} could not be fetched during local migration; local overrides and Thally default styling tokens were applied.`,
|
|
13765
14163
|
source: "global-theme"
|
|
13766
14164
|
});
|
|
13767
|
-
if (fernRawConfig?.logo && !fernRawConfig["global-theme"] && !logoLight && !logo.light) warnings.push({
|
|
14165
|
+
if (fernRawConfig?.logo && !fernRawConfig["global-theme"] && !logoLight && !logo.light && !logo.dark) warnings.push({
|
|
13768
14166
|
code: "unsupported-config",
|
|
13769
14167
|
message: "Fern supplied a logo through its global theme without a local asset; add a logo path to docs.json after import."
|
|
13770
14168
|
});
|
|
@@ -15714,8 +16112,9 @@ async function hydrateRemoteApiSpecs(bundle, fetcher) {
|
|
|
15714
16112
|
if (ref?.specRef === reference.url) page.openapi = withSpecRef(ref, `openapi/${filename}`);
|
|
15715
16113
|
}
|
|
15716
16114
|
const tab = reference.tabLabel ? tabs.find((candidate) => candidate.tab === reference.tabLabel) : tabs.find((candidate) => candidate.tab.toLowerCase().includes("api"));
|
|
15717
|
-
|
|
15718
|
-
|
|
16115
|
+
const api = { source: `openapi/${filename}`, ...reference.navigation === false ? { navigation: false } : {}, ...reference.groups ? { groups: reference.groups } : {} };
|
|
16116
|
+
if (tab) tab.api = api;
|
|
16117
|
+
else insertApiTab(tabs, { tab: reference.tabLabel ?? "API Reference", ...reference.icon ? { icon: reference.icon } : {}, ...reference.hidden ? { hidden: true } : {}, api }, reference.parentTab);
|
|
15719
16118
|
bound.push({ reference, filename, content: body, operations, tabName: tab?.tab ?? reference.tabLabel ?? "API Reference" });
|
|
15720
16119
|
} catch (error) {
|
|
15721
16120
|
warnings.push({
|