@thallylabs/migrate 0.2.14 → 0.2.17
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 +50 -0
- package/dist/index.d.ts +20 -1
- package/dist/index.js +732 -125
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
statSync
|
|
15
15
|
} from "fs";
|
|
16
16
|
import { createRequire } from "module";
|
|
17
|
-
import { basename as basename3, dirname as dirname4, extname as
|
|
17
|
+
import { basename as basename3, dirname as dirname4, extname as extname6, isAbsolute as isAbsolute2, posix as posix3, relative as relative5, resolve as resolvePath, sep as sep2 } from "path";
|
|
18
18
|
import { parse as parseYaml4 } from "yaml";
|
|
19
19
|
import * as ts3 from "typescript";
|
|
20
20
|
|
|
@@ -3104,13 +3104,96 @@ import { customComponents as ${name} } from ${JSON.stringify(registryPath)}
|
|
|
3104
3104
|
|
|
3105
3105
|
// src/docusaurus.ts
|
|
3106
3106
|
import { existsSync as existsSync3, lstatSync as lstatSync3, readFileSync as readFileSync3 } from "fs";
|
|
3107
|
-
import { extname as
|
|
3107
|
+
import { extname as extname4, posix as posix2 } from "path";
|
|
3108
3108
|
import JSON5 from "json5";
|
|
3109
3109
|
import { parse as parseYaml2 } from "yaml";
|
|
3110
3110
|
|
|
3111
3111
|
// src/navigation.ts
|
|
3112
3112
|
import { existsSync as existsSync2, lstatSync as lstatSync2, readFileSync as readFileSync2, realpathSync } from "fs";
|
|
3113
|
-
import { dirname as dirname2, extname as
|
|
3113
|
+
import { dirname as dirname2, extname as extname3, relative as relative3 } from "path";
|
|
3114
|
+
|
|
3115
|
+
// src/mintlify-extras.ts
|
|
3116
|
+
import { extname as extname2 } from "path";
|
|
3117
|
+
function objectValue(value) {
|
|
3118
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
3119
|
+
}
|
|
3120
|
+
var PUBLIC_FALSE_STRINGS = /* @__PURE__ */ new Set(["false", "no", "off", "0"]);
|
|
3121
|
+
function isPublicFalse(value) {
|
|
3122
|
+
return value === false || value === 0 || typeof value === "string" && PUBLIC_FALSE_STRINGS.has(value.trim().toLowerCase());
|
|
3123
|
+
}
|
|
3124
|
+
function isPublicTrue(value) {
|
|
3125
|
+
return value === true || typeof value === "string" && value.trim().toLowerCase() === "true";
|
|
3126
|
+
}
|
|
3127
|
+
function frontmatterGateReason(data) {
|
|
3128
|
+
const groups = data.groups;
|
|
3129
|
+
const hasGroups = Array.isArray(groups) ? groups.length > 0 : typeof groups === "string" ? groups.trim() !== "" : groups !== void 0 && groups !== null && groups !== false;
|
|
3130
|
+
if (hasGroups) return "frontmatter `groups` restricts it to authenticated groups";
|
|
3131
|
+
if (isPublicFalse(data.public)) return "frontmatter `public: false`";
|
|
3132
|
+
return void 0;
|
|
3133
|
+
}
|
|
3134
|
+
function navigationGateReason(node) {
|
|
3135
|
+
const groups = node.groups;
|
|
3136
|
+
const isContainer = (entry) => typeof entry === "object" && entry !== null && !Array.isArray(entry) && ["group", "pages", "tab", "groups", "page", "root", "menu", "href"].some((key) => key in entry);
|
|
3137
|
+
const restricted = typeof groups === "string" ? groups.trim() !== "" : Array.isArray(groups) && groups.length > 0 && !groups.every(isContainer);
|
|
3138
|
+
if (restricted) return "its navigation container sets `groups`";
|
|
3139
|
+
if (isPublicFalse(node.public)) return "its navigation container sets `public: false`";
|
|
3140
|
+
return void 0;
|
|
3141
|
+
}
|
|
3142
|
+
var CONFIG_BASENAME = /(?:^|[.-])(?:config|rc)\.[cm]?js$|^(?:tailwind|postcss|next|eslint|prettier|babel|webpack|vite|vitest|jest|rollup|gulpfile|gruntfile|stylelint|commitlint|lint-staged|svgo|metro)[.-]/i;
|
|
3143
|
+
var BUILD_OUTPUT_SEGMENTS = /* @__PURE__ */ new Set(["dist", "build", "coverage"]);
|
|
3144
|
+
var FONT_EXTENSIONS = /* @__PURE__ */ new Set([".woff", ".woff2", ".ttf", ".otf"]);
|
|
3145
|
+
function isMintlifyServedScriptOrStyle(relativePath) {
|
|
3146
|
+
const extension = extname2(relativePath).toLowerCase();
|
|
3147
|
+
if (extension !== ".css" && extension !== ".js") return false;
|
|
3148
|
+
const segments = relativePath.split("/");
|
|
3149
|
+
if (segments.slice(0, -1).some((segment) => BUILD_OUTPUT_SEGMENTS.has(segment.toLowerCase()))) return false;
|
|
3150
|
+
return extension === ".css" || !CONFIG_BASENAME.test(segments[segments.length - 1]);
|
|
3151
|
+
}
|
|
3152
|
+
function mintlifyFontSources(config) {
|
|
3153
|
+
const fonts = objectValue(config?.fonts);
|
|
3154
|
+
if (!fonts) return [];
|
|
3155
|
+
const found = [];
|
|
3156
|
+
for (const entry of [fonts, objectValue(fonts.heading), objectValue(fonts.body)]) {
|
|
3157
|
+
if (!entry || typeof entry.source !== "string" || !entry.source.trim()) continue;
|
|
3158
|
+
const source = entry.source.trim();
|
|
3159
|
+
const family = typeof entry.family === "string" ? entry.family : "a font";
|
|
3160
|
+
const remote = /^(?:[a-z][a-z0-9+.-]*:|\/\/)/i.test(source);
|
|
3161
|
+
const path = remote || /^[a-z]:[\\/]/i.test(source) ? null : normalizeAssetPath(source);
|
|
3162
|
+
found.push({ family, source, path: path && FONT_EXTENSIONS.has(extname2(path).toLowerCase()) ? path : null, remote });
|
|
3163
|
+
}
|
|
3164
|
+
return found;
|
|
3165
|
+
}
|
|
3166
|
+
function mintlifyAppearance(config, warnings) {
|
|
3167
|
+
const appearance = objectValue(config.appearance);
|
|
3168
|
+
const legacy = objectValue(config.modeToggle);
|
|
3169
|
+
const result = {};
|
|
3170
|
+
const isMode = (value) => value === "system" || value === "light" || value === "dark";
|
|
3171
|
+
const skip = (field, value) => {
|
|
3172
|
+
warnings.push({
|
|
3173
|
+
code: "unsupported-config",
|
|
3174
|
+
message: `Ignored invalid ${field} value ${JSON.stringify(value)?.slice(0, 40)}; the appearance default was left unchanged.`
|
|
3175
|
+
});
|
|
3176
|
+
};
|
|
3177
|
+
if (appearance?.default !== void 0) {
|
|
3178
|
+
if (isMode(appearance.default)) result.default = appearance.default;
|
|
3179
|
+
else skip("appearance.default", appearance.default);
|
|
3180
|
+
} else if (legacy?.default !== void 0) {
|
|
3181
|
+
if (isMode(legacy.default)) result.default = legacy.default;
|
|
3182
|
+
else skip("modeToggle.default", legacy.default);
|
|
3183
|
+
}
|
|
3184
|
+
if (appearance?.strict !== void 0) {
|
|
3185
|
+
if (typeof appearance.strict === "boolean") {
|
|
3186
|
+
if (appearance.strict) result.showToggle = false;
|
|
3187
|
+
} else skip("appearance.strict", appearance.strict);
|
|
3188
|
+
} else if (legacy?.isHidden !== void 0) {
|
|
3189
|
+
if (typeof legacy.isHidden === "boolean") {
|
|
3190
|
+
if (legacy.isHidden) result.showToggle = false;
|
|
3191
|
+
} else skip("modeToggle.isHidden", legacy.isHidden);
|
|
3192
|
+
}
|
|
3193
|
+
return result;
|
|
3194
|
+
}
|
|
3195
|
+
|
|
3196
|
+
// src/navigation.ts
|
|
3114
3197
|
var MAX_MINTLIFY_CONFIG_BYTES = 2e7;
|
|
3115
3198
|
function addMintlifyDirectoryRedirects(config, pages) {
|
|
3116
3199
|
const pageIds = new Set(pages.map((page) => page.id));
|
|
@@ -3210,13 +3293,13 @@ var LANGUAGE_LABELS = {
|
|
|
3210
3293
|
uk: "Ukrainian",
|
|
3211
3294
|
zh: "Chinese"
|
|
3212
3295
|
};
|
|
3213
|
-
function
|
|
3296
|
+
function objectValue2(value) {
|
|
3214
3297
|
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
3215
3298
|
}
|
|
3216
3299
|
function withFlattenedProductGroups(container) {
|
|
3217
3300
|
if (!Array.isArray(container.productGroups)) return container;
|
|
3218
3301
|
const flattened = container.productGroups.flatMap((entry) => {
|
|
3219
|
-
const group =
|
|
3302
|
+
const group = objectValue2(entry);
|
|
3220
3303
|
return group && Array.isArray(group.products) ? group.products : [];
|
|
3221
3304
|
});
|
|
3222
3305
|
if (flattened.length === 0) return container;
|
|
@@ -3251,7 +3334,7 @@ function jsonPointer(root, pointer) {
|
|
|
3251
3334
|
const index = Number(token);
|
|
3252
3335
|
return Number.isSafeInteger(index) && index >= 0 ? current[index] : void 0;
|
|
3253
3336
|
}
|
|
3254
|
-
const object =
|
|
3337
|
+
const object = objectValue2(current);
|
|
3255
3338
|
if (!object) return void 0;
|
|
3256
3339
|
return object[token.replace(/~1/g, "/").replace(/~0/g, "~")];
|
|
3257
3340
|
}, root);
|
|
@@ -3272,7 +3355,7 @@ function resolveJsonReferences(value, currentFile, repositoryRoot, stack) {
|
|
|
3272
3355
|
if (Array.isArray(value)) {
|
|
3273
3356
|
return value.map((entry) => resolveJsonReferences(entry, currentFile, repositoryRoot, stack));
|
|
3274
3357
|
}
|
|
3275
|
-
const object =
|
|
3358
|
+
const object = objectValue2(value);
|
|
3276
3359
|
if (!object) return value;
|
|
3277
3360
|
if (typeof object.$ref === "string") {
|
|
3278
3361
|
const [filePart, pointer = ""] = object.$ref.split("#", 2);
|
|
@@ -3292,7 +3375,7 @@ function resolveJsonReferences(value, currentFile, repositoryRoot, stack) {
|
|
|
3292
3375
|
resolveJsonReferences(entry, currentFile, repositoryRoot, stack)
|
|
3293
3376
|
])
|
|
3294
3377
|
);
|
|
3295
|
-
return
|
|
3378
|
+
return objectValue2(resolved) ? { ...resolved, ...siblings } : resolved;
|
|
3296
3379
|
}
|
|
3297
3380
|
return Object.fromEntries(
|
|
3298
3381
|
Object.entries(object).map(([key, entry]) => [
|
|
@@ -3308,19 +3391,19 @@ function readMintlifyConfig(repositoryRoot) {
|
|
|
3308
3391
|
return resolveJsonReferences(raw, configPath, repositoryRoot, /* @__PURE__ */ new Set());
|
|
3309
3392
|
}
|
|
3310
3393
|
function specSource(value) {
|
|
3311
|
-
const source = typeof value === "string" ? value :
|
|
3394
|
+
const source = typeof value === "string" ? value : objectValue2(value)?.source;
|
|
3312
3395
|
return typeof source === "string" && source.trim() ? source.trim() : void 0;
|
|
3313
3396
|
}
|
|
3314
3397
|
var hasNavigationChildren = (node) => ["groups", "pages"].some((key) => Array.isArray(node[key]) && node[key].length > 0);
|
|
3315
3398
|
function mintlifyNavigationApiReferences(config) {
|
|
3316
|
-
const navigation =
|
|
3399
|
+
const navigation = objectValue2(config.navigation) ?? config;
|
|
3317
3400
|
const references = [];
|
|
3318
3401
|
const containerKeys = ["tabs", "anchors", "products", "dropdowns", "versions", "menus", "languages"];
|
|
3319
3402
|
const nestedKeys = ["groups", "pages"];
|
|
3320
3403
|
function collect(node, tabLabel, sibling) {
|
|
3321
3404
|
for (const kind of ["openapi", "asyncapi"]) {
|
|
3322
3405
|
const value = specSource(node[kind]);
|
|
3323
|
-
const directory =
|
|
3406
|
+
const directory = objectValue2(node[kind])?.directory;
|
|
3324
3407
|
if (value) {
|
|
3325
3408
|
references.push({
|
|
3326
3409
|
value,
|
|
@@ -3345,7 +3428,7 @@ function mintlifyNavigationApiReferences(config) {
|
|
|
3345
3428
|
const entries = node[key];
|
|
3346
3429
|
if (!Array.isArray(entries)) continue;
|
|
3347
3430
|
for (const entry of entries) {
|
|
3348
|
-
const object =
|
|
3431
|
+
const object = objectValue2(entry);
|
|
3349
3432
|
if (!object) continue;
|
|
3350
3433
|
visit(object, labelFor(object, tabLabel ?? "Documentation"));
|
|
3351
3434
|
}
|
|
@@ -3355,14 +3438,14 @@ function mintlifyNavigationApiReferences(config) {
|
|
|
3355
3438
|
if (!Array.isArray(entries)) continue;
|
|
3356
3439
|
for (const entry of entries) {
|
|
3357
3440
|
if (typeof entry === "string") continue;
|
|
3358
|
-
const object =
|
|
3441
|
+
const object = objectValue2(entry);
|
|
3359
3442
|
if (object) visit(object, tabLabel);
|
|
3360
3443
|
}
|
|
3361
3444
|
}
|
|
3362
3445
|
if (Array.isArray(node.menu)) {
|
|
3363
3446
|
const tab = tabLabel ?? "Documentation";
|
|
3364
3447
|
const items = node.menu.flatMap((entry) => {
|
|
3365
|
-
const object =
|
|
3448
|
+
const object = objectValue2(entry);
|
|
3366
3449
|
return object ? [object] : [];
|
|
3367
3450
|
});
|
|
3368
3451
|
const apiItems = items.filter((item) => specSource(item.openapi) || specSource(item.asyncapi));
|
|
@@ -3408,6 +3491,23 @@ function normalizePageRef(value, pathPrefix = "") {
|
|
|
3408
3491
|
ref = ref.replace(/\.(?:mdx?|rst|txt)$/i, "");
|
|
3409
3492
|
return pageIdFromReference(ref, true);
|
|
3410
3493
|
}
|
|
3494
|
+
function collectGatedReferences(node, gate, pathPrefix, out, depth = 0) {
|
|
3495
|
+
if (depth > 32) return;
|
|
3496
|
+
if (Array.isArray(node)) {
|
|
3497
|
+
for (const item of node) collectGatedReferences(item, gate, pathPrefix, out, depth + 1);
|
|
3498
|
+
return;
|
|
3499
|
+
}
|
|
3500
|
+
const object = objectValue2(node);
|
|
3501
|
+
if (!object) return;
|
|
3502
|
+
const reason = gate ?? navigationGateReason(object);
|
|
3503
|
+
if (reason) {
|
|
3504
|
+
const refs = [object.page, object.root, ...Array.isArray(object.pages) ? object.pages : []];
|
|
3505
|
+
for (const ref of refs) {
|
|
3506
|
+
if (typeof ref === "string" && normalizePageRef(ref, pathPrefix)) out.push({ ref, reason });
|
|
3507
|
+
}
|
|
3508
|
+
}
|
|
3509
|
+
for (const value of Object.values(object)) collectGatedReferences(value, reason, pathPrefix, out, depth + 1);
|
|
3510
|
+
}
|
|
3411
3511
|
function warnOnce(context, key, message) {
|
|
3412
3512
|
if (context.warningKeys.has(key)) return;
|
|
3413
3513
|
context.warningKeys.add(key);
|
|
@@ -3415,7 +3515,7 @@ function warnOnce(context, key, message) {
|
|
|
3415
3515
|
}
|
|
3416
3516
|
function iconName(value) {
|
|
3417
3517
|
if (typeof value === "string" && value) return value;
|
|
3418
|
-
const icon =
|
|
3518
|
+
const icon = objectValue2(value);
|
|
3419
3519
|
return typeof icon?.name === "string" && icon.name ? icon.name : void 0;
|
|
3420
3520
|
}
|
|
3421
3521
|
function containerPresentation(value) {
|
|
@@ -3425,6 +3525,10 @@ function containerPresentation(value) {
|
|
|
3425
3525
|
};
|
|
3426
3526
|
}
|
|
3427
3527
|
function registerReference(value, context) {
|
|
3528
|
+
if (context.gateReason) {
|
|
3529
|
+
if (normalizePageRef(value, context.pathPrefix)) context.gated.push({ ref: value, reason: context.gateReason });
|
|
3530
|
+
return null;
|
|
3531
|
+
}
|
|
3428
3532
|
const localizedValue = context.locale ? mintlifyLocalizedReference(value, context.locale, context.defaultPageIds) : value;
|
|
3429
3533
|
const navigationId = normalizePageRef(localizedValue, context.pathPrefix);
|
|
3430
3534
|
if (!navigationId) return null;
|
|
@@ -3448,13 +3552,24 @@ function convertPage(value, context) {
|
|
|
3448
3552
|
}
|
|
3449
3553
|
return registerReference(value, context);
|
|
3450
3554
|
}
|
|
3451
|
-
const object =
|
|
3555
|
+
const object = objectValue2(value);
|
|
3452
3556
|
if (!object) return null;
|
|
3557
|
+
const outerGate = context.gateReason;
|
|
3558
|
+
const gate = navigationGateReason(object);
|
|
3559
|
+
if (gate && !outerGate) context.gateReason = gate;
|
|
3560
|
+
try {
|
|
3561
|
+
return convertPageObject(object, context);
|
|
3562
|
+
} finally {
|
|
3563
|
+
context.gateReason = outerGate;
|
|
3564
|
+
}
|
|
3565
|
+
}
|
|
3566
|
+
function convertPageObject(object, context) {
|
|
3453
3567
|
if (typeof object.page === "string") return registerReference(object.page, context);
|
|
3454
3568
|
const href = projectedHref(object.href);
|
|
3455
3569
|
if (href && !object.pages && !object.groups) {
|
|
3456
3570
|
const page = registerReference(href, context);
|
|
3457
3571
|
if (page) return page;
|
|
3572
|
+
if (context.gateReason) return null;
|
|
3458
3573
|
warnOnce(
|
|
3459
3574
|
context,
|
|
3460
3575
|
"external-page-link",
|
|
@@ -3499,7 +3614,7 @@ var KNOWN_NAVIGATION_KEYS = /* @__PURE__ */ new Set([
|
|
|
3499
3614
|
]);
|
|
3500
3615
|
function convertMenuItems(items, context) {
|
|
3501
3616
|
return items.flatMap((value, index) => {
|
|
3502
|
-
const item =
|
|
3617
|
+
const item = objectValue2(value);
|
|
3503
3618
|
if (!item) return [];
|
|
3504
3619
|
const label = labelFor(item, `Menu item ${index + 1}`);
|
|
3505
3620
|
if (typeof item.description === "string" && item.description.trim()) {
|
|
@@ -3549,14 +3664,14 @@ function convertNavigationValues(values, context) {
|
|
|
3549
3664
|
});
|
|
3550
3665
|
}
|
|
3551
3666
|
function convertContainerToTabs(containerValue, context, fallbackTab, trace, depth = 0) {
|
|
3552
|
-
const rawContainer =
|
|
3667
|
+
const rawContainer = objectValue2(containerValue);
|
|
3553
3668
|
if (!rawContainer) return [];
|
|
3554
3669
|
const container = withFlattenedProductGroups(rawContainer);
|
|
3555
3670
|
const containerKeys = ["tabs", "anchors", "products", "dropdowns", "versions", "menus"];
|
|
3556
3671
|
for (const key of Object.keys(container)) {
|
|
3557
3672
|
if (KNOWN_NAVIGATION_KEYS.has(key)) continue;
|
|
3558
3673
|
const entries = container[key];
|
|
3559
|
-
if (Array.isArray(entries) && entries.some((entry) =>
|
|
3674
|
+
if (Array.isArray(entries) && entries.some((entry) => objectValue2(entry))) {
|
|
3560
3675
|
warnOnce(context, `unknown-container:${key}`, `Mintlify navigation key "${key}" is not supported and its contents were not projected.`);
|
|
3561
3676
|
}
|
|
3562
3677
|
}
|
|
@@ -3564,10 +3679,10 @@ function convertContainerToTabs(containerValue, context, fallbackTab, trace, dep
|
|
|
3564
3679
|
if (!Array.isArray(container[key])) continue;
|
|
3565
3680
|
const entries = [...container[key]];
|
|
3566
3681
|
if (key === "versions") {
|
|
3567
|
-
entries.sort((left, right) => Number(
|
|
3682
|
+
entries.sort((left, right) => Number(objectValue2(right)?.default === true) - Number(objectValue2(left)?.default === true));
|
|
3568
3683
|
}
|
|
3569
3684
|
const tabs = entries.flatMap((value, index) => {
|
|
3570
|
-
const object =
|
|
3685
|
+
const object = objectValue2(value);
|
|
3571
3686
|
if (!object) return [];
|
|
3572
3687
|
const tab = labelFor(object, `${fallbackTab} ${index + 1}`);
|
|
3573
3688
|
const href = projectedHref(object.href);
|
|
@@ -3580,7 +3695,15 @@ function convertContainerToTabs(containerValue, context, fallbackTab, trace, dep
|
|
|
3580
3695
|
...object.hidden === true ? { hidden: true } : {}
|
|
3581
3696
|
}];
|
|
3582
3697
|
}
|
|
3583
|
-
const
|
|
3698
|
+
const outerGate = context.gateReason;
|
|
3699
|
+
const gate = navigationGateReason(object);
|
|
3700
|
+
if (gate && !outerGate) context.gateReason = gate;
|
|
3701
|
+
let nested;
|
|
3702
|
+
try {
|
|
3703
|
+
nested = convertContainerToTabs(object, context, tab, trace, depth + 1);
|
|
3704
|
+
} finally {
|
|
3705
|
+
context.gateReason = outerGate;
|
|
3706
|
+
}
|
|
3584
3707
|
if (nested.length > 0) {
|
|
3585
3708
|
if (nested.length === 1) {
|
|
3586
3709
|
return [{
|
|
@@ -3639,17 +3762,17 @@ function projectedTheme(value) {
|
|
|
3639
3762
|
return typeof value === "string" ? "default" : void 0;
|
|
3640
3763
|
}
|
|
3641
3764
|
function projectedNavbar(value) {
|
|
3642
|
-
const navbar =
|
|
3765
|
+
const navbar = objectValue2(value);
|
|
3643
3766
|
if (!navbar) return void 0;
|
|
3644
3767
|
const links = Array.isArray(navbar.links) ? navbar.links.flatMap((entry) => {
|
|
3645
|
-
const link =
|
|
3768
|
+
const link = objectValue2(entry);
|
|
3646
3769
|
const href = projectedHref(link?.href);
|
|
3647
3770
|
if (!link || !href) return [];
|
|
3648
3771
|
const label = typeof link.label === "string" ? link.label : typeof link.name === "string" ? link.name : "";
|
|
3649
3772
|
if (!label) return [];
|
|
3650
3773
|
return [{ label, href, ...link.type === "github" ? { type: "github" } : {} }];
|
|
3651
3774
|
}) : [];
|
|
3652
|
-
const primaryValue =
|
|
3775
|
+
const primaryValue = objectValue2(navbar.primary);
|
|
3653
3776
|
const primaryHref = projectedHref(primaryValue?.href);
|
|
3654
3777
|
const primary = primaryValue && primaryHref ? {
|
|
3655
3778
|
label: typeof primaryValue.label === "string" ? primaryValue.label : primaryValue.type === "github" ? "GitHub" : "Get started",
|
|
@@ -3657,8 +3780,22 @@ function projectedNavbar(value) {
|
|
|
3657
3780
|
} : void 0;
|
|
3658
3781
|
return links.length > 0 || primary ? { ...links.length > 0 ? { links } : {}, ...primary ? { primary } : {} } : void 0;
|
|
3659
3782
|
}
|
|
3783
|
+
function legacyTopbarNavbar(config) {
|
|
3784
|
+
const links = Array.isArray(config.topbarLinks) ? config.topbarLinks.flatMap((entry) => {
|
|
3785
|
+
const link = objectValue2(entry);
|
|
3786
|
+
if (!link) return [];
|
|
3787
|
+
return [{
|
|
3788
|
+
label: link.name ?? link.label ?? (link.type === "github" ? "GitHub" : void 0),
|
|
3789
|
+
href: link.url ?? link.href,
|
|
3790
|
+
...link.type === "github" ? { type: "github" } : {}
|
|
3791
|
+
}];
|
|
3792
|
+
}) : [];
|
|
3793
|
+
const cta = objectValue2(config.topbarCtaButton);
|
|
3794
|
+
const primary = cta ? { label: cta.name ?? cta.label, href: cta.url ?? cta.href, type: cta.type } : void 0;
|
|
3795
|
+
return links.length > 0 || primary ? { ...links.length > 0 ? { links } : {}, ...primary ? { primary } : {} } : void 0;
|
|
3796
|
+
}
|
|
3660
3797
|
function projectedGlobalNavigationLinks(value) {
|
|
3661
|
-
const global =
|
|
3798
|
+
const global = objectValue2(value);
|
|
3662
3799
|
if (!global) return [];
|
|
3663
3800
|
const links = [];
|
|
3664
3801
|
const visit = (entry) => {
|
|
@@ -3666,7 +3803,7 @@ function projectedGlobalNavigationLinks(value) {
|
|
|
3666
3803
|
entry.forEach(visit);
|
|
3667
3804
|
return;
|
|
3668
3805
|
}
|
|
3669
|
-
const item =
|
|
3806
|
+
const item = objectValue2(entry);
|
|
3670
3807
|
if (!item) return;
|
|
3671
3808
|
const href = projectedHref(item.href);
|
|
3672
3809
|
if (href) {
|
|
@@ -3681,19 +3818,19 @@ function projectedGlobalNavigationLinks(value) {
|
|
|
3681
3818
|
return links;
|
|
3682
3819
|
}
|
|
3683
3820
|
function projectedFooter(value) {
|
|
3684
|
-
const footer =
|
|
3821
|
+
const footer = objectValue2(value);
|
|
3685
3822
|
if (!footer) return void 0;
|
|
3686
|
-
const socials =
|
|
3823
|
+
const socials = objectValue2(footer.socials);
|
|
3687
3824
|
const socialLinks = socials ? Object.fromEntries(Object.entries(socials).flatMap(([key, value2]) => {
|
|
3688
3825
|
const href = projectedHref(value2);
|
|
3689
3826
|
return href ? [[key, href]] : [];
|
|
3690
3827
|
})) : void 0;
|
|
3691
3828
|
const links = Array.isArray(footer.links) ? footer.links.flatMap((entry) => {
|
|
3692
|
-
const column =
|
|
3829
|
+
const column = objectValue2(entry);
|
|
3693
3830
|
if (!column || !Array.isArray(column.items)) return [];
|
|
3694
3831
|
const heading = typeof column.heading === "string" ? column.heading : typeof column.header === "string" ? column.header : "";
|
|
3695
3832
|
const items = column.items.flatMap((item) => {
|
|
3696
|
-
const link =
|
|
3833
|
+
const link = objectValue2(item);
|
|
3697
3834
|
const href = projectedHref(link?.href);
|
|
3698
3835
|
return link && typeof link.label === "string" && href ? [{ label: link.label, href }] : [];
|
|
3699
3836
|
});
|
|
@@ -3703,26 +3840,45 @@ function projectedFooter(value) {
|
|
|
3703
3840
|
}
|
|
3704
3841
|
function projectedFont(value) {
|
|
3705
3842
|
if (typeof value === "string" && value) return { family: value };
|
|
3706
|
-
const font =
|
|
3843
|
+
const font = objectValue2(value);
|
|
3707
3844
|
if (!font) return void 0;
|
|
3708
3845
|
const family = typeof font.family === "string" ? font.family : typeof font.name === "string" ? font.name : void 0;
|
|
3709
3846
|
if (!family) return void 0;
|
|
3710
3847
|
const weight = Array.isArray(font.weight) ? font.weight.map(String) : Array.isArray(font.weights) ? font.weights.map(String) : void 0;
|
|
3711
3848
|
return { family, ...weight && weight.length > 0 ? { weight } : {} };
|
|
3712
3849
|
}
|
|
3713
|
-
function projectedCompatibleConfig(config) {
|
|
3714
|
-
const banner =
|
|
3715
|
-
const bannerContent = banner && (typeof banner.content === "string" ||
|
|
3850
|
+
function projectedCompatibleConfig(config, warnings) {
|
|
3851
|
+
const banner = objectValue2(config.banner);
|
|
3852
|
+
const bannerContent = banner && (typeof banner.content === "string" || objectValue2(banner.content)) ? banner.content : void 0;
|
|
3716
3853
|
const bannerType = banner && ["info", "warning", "critical"].includes(String(banner.type ?? banner.variant)) ? String(banner.type ?? banner.variant) : void 0;
|
|
3717
|
-
const bannerColor =
|
|
3718
|
-
const bodyFont = projectedFont(
|
|
3719
|
-
const headingFont = projectedFont(
|
|
3720
|
-
const feedback =
|
|
3721
|
-
const seo =
|
|
3722
|
-
const iconLibrary =
|
|
3854
|
+
const bannerColor = objectValue2(banner?.color);
|
|
3855
|
+
const bodyFont = projectedFont(objectValue2(config.fonts)?.body ?? config.fonts);
|
|
3856
|
+
const headingFont = projectedFont(objectValue2(config.fonts)?.heading);
|
|
3857
|
+
const feedback = objectValue2(config.feedback);
|
|
3858
|
+
const seo = objectValue2(config.seo);
|
|
3859
|
+
const iconLibrary = objectValue2(config.icons)?.library;
|
|
3723
3860
|
const projectedIconLibrary = ["lucide", "fontawesome", "tabler"].includes(String(iconLibrary)) ? String(iconLibrary) : void 0;
|
|
3724
|
-
const
|
|
3725
|
-
const
|
|
3861
|
+
const docsNavbar = projectedNavbar(config.navbar);
|
|
3862
|
+
const legacyRaw = legacyTopbarNavbar(config);
|
|
3863
|
+
const legacyNavbar = projectedNavbar(legacyRaw);
|
|
3864
|
+
const legacyLinkCount = Array.isArray(legacyRaw?.links) ? legacyRaw.links.length : 0;
|
|
3865
|
+
if (legacyNavbar?.links && legacyNavbar.links.length < legacyLinkCount) {
|
|
3866
|
+
warnings.push({ code: "unsupported-config", message: `${legacyLinkCount - legacyNavbar.links.length} mint.json topbarLinks entr${legacyLinkCount - legacyNavbar.links.length === 1 ? "y" : "ies"} without a valid name and url were skipped.` });
|
|
3867
|
+
}
|
|
3868
|
+
if (docsNavbar?.links && legacyNavbar?.links) {
|
|
3869
|
+
warnings.push({ code: "unsupported-config", message: "Both docs.json navbar.links and mint.json topbarLinks are set; the docs.json navbar.links were used and topbarLinks ignored." });
|
|
3870
|
+
}
|
|
3871
|
+
if (docsNavbar?.primary && legacyNavbar?.primary) {
|
|
3872
|
+
warnings.push({ code: "unsupported-config", message: "Both docs.json navbar.primary and mint.json topbarCtaButton are set; navbar.primary was used and topbarCtaButton ignored." });
|
|
3873
|
+
}
|
|
3874
|
+
if (legacyRaw?.primary && !legacyNavbar?.primary) {
|
|
3875
|
+
warnings.push({ code: "unsupported-config", message: "mint.json topbarCtaButton has no valid url and was skipped." });
|
|
3876
|
+
}
|
|
3877
|
+
const navbar = docsNavbar || legacyNavbar ? {
|
|
3878
|
+
...docsNavbar?.links ?? legacyNavbar?.links ? { links: docsNavbar?.links ?? legacyNavbar?.links } : {},
|
|
3879
|
+
...docsNavbar?.primary ?? legacyNavbar?.primary ? { primary: docsNavbar?.primary ?? legacyNavbar?.primary } : {}
|
|
3880
|
+
} : void 0;
|
|
3881
|
+
const globalLinks = projectedGlobalNavigationLinks(objectValue2(config.navigation)?.global);
|
|
3726
3882
|
const navbarLinks = [...new Map(
|
|
3727
3883
|
[...navbar?.links ?? [], ...globalLinks].map((link) => [`${link.label}:${link.href}`, link])
|
|
3728
3884
|
).values()];
|
|
@@ -3789,11 +3945,11 @@ function isRedirectPathSafe(rawSource, rawDestination) {
|
|
|
3789
3945
|
return true;
|
|
3790
3946
|
}
|
|
3791
3947
|
function mintlifyDefaultVersionPrefixes(config) {
|
|
3792
|
-
const navigation =
|
|
3948
|
+
const navigation = objectValue2(config.navigation) ?? config;
|
|
3793
3949
|
const prefixes = /* @__PURE__ */ new Set();
|
|
3794
3950
|
function collect(container) {
|
|
3795
3951
|
if (Array.isArray(container.versions)) {
|
|
3796
|
-
const entries = container.versions.map((value) =>
|
|
3952
|
+
const entries = container.versions.map((value) => objectValue2(value)).filter((value) => value !== null);
|
|
3797
3953
|
const defaultEntry = entries.find((entry) => entry.default === true) ?? entries[0];
|
|
3798
3954
|
if (defaultEntry && typeof defaultEntry.version === "string" && defaultEntry.version.trim()) {
|
|
3799
3955
|
prefixes.add(defaultEntry.version.trim());
|
|
@@ -3801,7 +3957,7 @@ function mintlifyDefaultVersionPrefixes(config) {
|
|
|
3801
3957
|
}
|
|
3802
3958
|
if (Array.isArray(container.languages)) {
|
|
3803
3959
|
for (const value of container.languages) {
|
|
3804
|
-
const language =
|
|
3960
|
+
const language = objectValue2(value);
|
|
3805
3961
|
if (language) collect(language);
|
|
3806
3962
|
}
|
|
3807
3963
|
}
|
|
@@ -3810,18 +3966,18 @@ function mintlifyDefaultVersionPrefixes(config) {
|
|
|
3810
3966
|
return prefixes;
|
|
3811
3967
|
}
|
|
3812
3968
|
function mintlifyAllVersionPrefixes(config) {
|
|
3813
|
-
const navigation =
|
|
3969
|
+
const navigation = objectValue2(config.navigation) ?? config;
|
|
3814
3970
|
const prefixes = /* @__PURE__ */ new Set();
|
|
3815
3971
|
function collect(container) {
|
|
3816
3972
|
if (Array.isArray(container.versions)) {
|
|
3817
3973
|
for (const value of container.versions) {
|
|
3818
|
-
const entry =
|
|
3974
|
+
const entry = objectValue2(value);
|
|
3819
3975
|
if (entry && typeof entry.version === "string" && entry.version.trim()) prefixes.add(entry.version.trim());
|
|
3820
3976
|
}
|
|
3821
3977
|
}
|
|
3822
3978
|
if (Array.isArray(container.languages)) {
|
|
3823
3979
|
for (const value of container.languages) {
|
|
3824
|
-
const language =
|
|
3980
|
+
const language = objectValue2(value);
|
|
3825
3981
|
if (language) collect(language);
|
|
3826
3982
|
}
|
|
3827
3983
|
}
|
|
@@ -3834,9 +3990,10 @@ function projectMintlifyNavigation(config, options = {}) {
|
|
|
3834
3990
|
const references = [];
|
|
3835
3991
|
const seenReferences = /* @__PURE__ */ new Set();
|
|
3836
3992
|
const warningKeys = /* @__PURE__ */ new Set();
|
|
3837
|
-
const
|
|
3993
|
+
const gated = [];
|
|
3994
|
+
const navigation = objectValue2(config.navigation) ?? config;
|
|
3838
3995
|
const languages = Array.isArray(navigation.languages) ? navigation.languages.flatMap((value) => {
|
|
3839
|
-
const language =
|
|
3996
|
+
const language = objectValue2(value);
|
|
3840
3997
|
if (!language) return [];
|
|
3841
3998
|
try {
|
|
3842
3999
|
const code = Intl.getCanonicalLocales(String(language.language ?? language.locale ?? "en"))[0];
|
|
@@ -3873,7 +4030,8 @@ function projectMintlifyNavigation(config, options = {}) {
|
|
|
3873
4030
|
references,
|
|
3874
4031
|
seenReferences,
|
|
3875
4032
|
warnings,
|
|
3876
|
-
warningKeys
|
|
4033
|
+
warningKeys,
|
|
4034
|
+
gated
|
|
3877
4035
|
};
|
|
3878
4036
|
const languageTabs = convertContainerToTabs(
|
|
3879
4037
|
language,
|
|
@@ -3890,7 +4048,7 @@ function projectMintlifyNavigation(config, options = {}) {
|
|
|
3890
4048
|
}
|
|
3891
4049
|
if (Object.keys(localizedNavigation).length > 0) i18n.navigation = localizedNavigation;
|
|
3892
4050
|
} else {
|
|
3893
|
-
const context = { references, seenReferences, warnings, warningKeys, pathPrefix: options.pathPrefix };
|
|
4051
|
+
const context = { references, seenReferences, warnings, warningKeys, gated, pathPrefix: options.pathPrefix };
|
|
3894
4052
|
tabs = convertContainerToTabs(navigation, context, "Documentation", projectionTrace);
|
|
3895
4053
|
if (tabs.length === 0 && Array.isArray(config.navigation)) {
|
|
3896
4054
|
const children = convertNavigationValues(config.navigation, context);
|
|
@@ -3910,7 +4068,7 @@ function projectMintlifyNavigation(config, options = {}) {
|
|
|
3910
4068
|
});
|
|
3911
4069
|
}
|
|
3912
4070
|
const redirects = Array.isArray(config.redirects) ? config.redirects.flatMap((value) => {
|
|
3913
|
-
const redirect =
|
|
4071
|
+
const redirect = objectValue2(value);
|
|
3914
4072
|
if (!redirect || typeof redirect.source !== "string" || typeof redirect.destination !== "string") return [];
|
|
3915
4073
|
const rawSource = redirect.source.trim();
|
|
3916
4074
|
const rawDestination = redirect.destination.trim();
|
|
@@ -3929,15 +4087,17 @@ function projectMintlifyNavigation(config, options = {}) {
|
|
|
3929
4087
|
...typeof redirect.permanent === "boolean" ? { permanent: redirect.permanent } : {}
|
|
3930
4088
|
}];
|
|
3931
4089
|
}) : [];
|
|
4090
|
+
collectGatedReferences(navigation, void 0, options.pathPrefix, gated);
|
|
3932
4091
|
return {
|
|
3933
4092
|
docsConfig: {
|
|
3934
4093
|
tabs,
|
|
3935
4094
|
...projectionTrace.rootContainerKind === "dropdowns" ? { navigation: { display: "dropdown" } } : {},
|
|
3936
|
-
...projectedCompatibleConfig(config),
|
|
4095
|
+
...projectedCompatibleConfig(config, warnings),
|
|
3937
4096
|
...i18n ? { i18n } : {},
|
|
3938
4097
|
...redirects.length > 0 ? { redirects } : {}
|
|
3939
4098
|
},
|
|
3940
4099
|
pageReferences: references,
|
|
4100
|
+
gatedReferences: gated,
|
|
3941
4101
|
warnings
|
|
3942
4102
|
};
|
|
3943
4103
|
}
|
|
@@ -4043,7 +4203,7 @@ function buildNavigationFromPages(pages, options = {}) {
|
|
|
4043
4203
|
return { tabs: [{ tab: "Documentation", groups }] };
|
|
4044
4204
|
}
|
|
4045
4205
|
function isDocumentationExtension(filename) {
|
|
4046
|
-
return [".md", ".mdx", ".rst", ".txt"].includes(
|
|
4206
|
+
return [".md", ".mdx", ".rst", ".txt"].includes(extname3(filename).toLowerCase());
|
|
4047
4207
|
}
|
|
4048
4208
|
function pruneMissingNavigationPages(config, availableIds) {
|
|
4049
4209
|
const pruneNodes = (nodes) => {
|
|
@@ -4083,7 +4243,7 @@ var SIDEBAR_FILENAMES = [
|
|
|
4083
4243
|
"sidebars.mjs",
|
|
4084
4244
|
"sidebars.ts"
|
|
4085
4245
|
];
|
|
4086
|
-
function
|
|
4246
|
+
function objectValue3(value) {
|
|
4087
4247
|
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
4088
4248
|
}
|
|
4089
4249
|
function stripNumberPrefix(value) {
|
|
@@ -4405,7 +4565,7 @@ function parseStaticSidebarModule(source) {
|
|
|
4405
4565
|
literal
|
|
4406
4566
|
);
|
|
4407
4567
|
const parsed = JSON5.parse(substituted);
|
|
4408
|
-
const object =
|
|
4568
|
+
const object = objectValue3(parsed);
|
|
4409
4569
|
if (!object) continue;
|
|
4410
4570
|
const bindingName = candidate[0].match(/\b(?:const|let|var)\s+([A-Za-z_$][\w$]*)/)?.[1];
|
|
4411
4571
|
if (bindingName) {
|
|
@@ -4510,7 +4670,7 @@ function readDocusaurusSidebars(repositoryRoot, versionedSidebarPath) {
|
|
|
4510
4670
|
if (!sourcePath) return null;
|
|
4511
4671
|
const absolutePath = resolveWithin(repositoryRoot, sourcePath);
|
|
4512
4672
|
const source = readBoundedText(absolutePath);
|
|
4513
|
-
const parsed =
|
|
4673
|
+
const parsed = extname4(sourcePath).toLowerCase() === ".json" ? objectValue3(JSON5.parse(source)) : parseStaticSidebarModule(source);
|
|
4514
4674
|
if (!parsed) throw new Error("Docusaurus sidebar config must export an object.");
|
|
4515
4675
|
return { config: parsed, sourcePath };
|
|
4516
4676
|
}
|
|
@@ -4536,7 +4696,7 @@ function redirectEntriesFromObjectLiteralText(objectLiteral) {
|
|
|
4536
4696
|
if (!Array.isArray(parsed)) return [];
|
|
4537
4697
|
const entries = [];
|
|
4538
4698
|
for (const raw of parsed) {
|
|
4539
|
-
const entry =
|
|
4699
|
+
const entry = objectValue3(raw);
|
|
4540
4700
|
if (!entry || typeof entry.to !== "string") continue;
|
|
4541
4701
|
const froms = Array.isArray(entry.from) ? entry.from : [entry.from];
|
|
4542
4702
|
for (const from of froms) {
|
|
@@ -4588,7 +4748,7 @@ function readCategoryMetadata(contentRoot, directory) {
|
|
|
4588
4748
|
try {
|
|
4589
4749
|
const raw = readBoundedText(path);
|
|
4590
4750
|
const parsed = filename.endsWith(".json") ? JSON5.parse(raw) : parseYaml2(raw);
|
|
4591
|
-
const object =
|
|
4751
|
+
const object = objectValue3(parsed);
|
|
4592
4752
|
if (!object) return {};
|
|
4593
4753
|
return {
|
|
4594
4754
|
...typeof object.label === "string" ? { label: object.label } : {},
|
|
@@ -4622,7 +4782,7 @@ function registerDoc(docId, context) {
|
|
|
4622
4782
|
return descriptor.navigationId;
|
|
4623
4783
|
}
|
|
4624
4784
|
function generatedIndexPage(label, linkValue, context) {
|
|
4625
|
-
const link =
|
|
4785
|
+
const link = objectValue3(linkValue);
|
|
4626
4786
|
if (!link) return null;
|
|
4627
4787
|
if (link.type === "doc" && typeof link.id === "string") return registerDoc(link.id, context);
|
|
4628
4788
|
if (link.type !== "generated-index") return null;
|
|
@@ -4889,7 +5049,7 @@ function convertItems(value, context) {
|
|
|
4889
5049
|
return page ? [page] : [];
|
|
4890
5050
|
}
|
|
4891
5051
|
if (Array.isArray(value)) return value.flatMap((entry) => convertItems(entry, context));
|
|
4892
|
-
const object =
|
|
5052
|
+
const object = objectValue3(value);
|
|
4893
5053
|
if (!object) return [];
|
|
4894
5054
|
if (object.type === "doc" || object.type === "ref") {
|
|
4895
5055
|
const page = typeof object.id === "string" ? registerDoc(object.id, context) : null;
|
|
@@ -4955,7 +5115,7 @@ function projectDocusaurusNavigation(input) {
|
|
|
4955
5115
|
|
|
4956
5116
|
// src/fern.ts
|
|
4957
5117
|
import { existsSync as existsSync4, lstatSync as lstatSync4, readFileSync as readFileSync4, readdirSync } from "fs";
|
|
4958
|
-
import { basename as basename2, dirname as dirname3, extname as
|
|
5118
|
+
import { basename as basename2, dirname as dirname3, extname as extname5, relative as relative4 } from "path";
|
|
4959
5119
|
import { load } from "cheerio";
|
|
4960
5120
|
import { parse as parseYaml3 } from "yaml";
|
|
4961
5121
|
var MAX_CONFIG_BYTES2 = 2e7;
|
|
@@ -4985,7 +5145,7 @@ function announcementMarkdown(message) {
|
|
|
4985
5145
|
for (const [marker, link] of links) text = text.replaceAll(marker, link);
|
|
4986
5146
|
return text.trim();
|
|
4987
5147
|
}
|
|
4988
|
-
function
|
|
5148
|
+
function objectValue4(value) {
|
|
4989
5149
|
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
4990
5150
|
}
|
|
4991
5151
|
function titleCase3(value) {
|
|
@@ -5001,7 +5161,7 @@ function readFernConfig(fernRoot) {
|
|
|
5001
5161
|
const sourcePath = "docs.yml";
|
|
5002
5162
|
const path = resolveWithin(fernRoot, sourcePath);
|
|
5003
5163
|
if (!existsSync4(path) || !lstatSync4(path).isFile()) return null;
|
|
5004
|
-
const config =
|
|
5164
|
+
const config = objectValue4(readBoundedYaml(path));
|
|
5005
5165
|
if (!config) throw new Error("fern/docs.yml must contain an object.");
|
|
5006
5166
|
return { config, sourcePath };
|
|
5007
5167
|
}
|
|
@@ -5108,8 +5268,8 @@ function registerFolder(object, parentSegments, context) {
|
|
|
5108
5268
|
if (entry.isDirectory()) {
|
|
5109
5269
|
const nested = visit(path, [...routeSegments, fernBasicSlug(entry.name)], depth + 1);
|
|
5110
5270
|
if (nested.length) pages2.push({ group: titleCase3(entry.name), pages: nested });
|
|
5111
|
-
} else if (entry.isFile() && [".md", ".mdx"].includes(
|
|
5112
|
-
const stem = basename2(entry.name,
|
|
5271
|
+
} else if (entry.isFile() && [".md", ".mdx"].includes(extname5(entry.name).toLowerCase())) {
|
|
5272
|
+
const stem = basename2(entry.name, extname5(entry.name));
|
|
5113
5273
|
const pageSegment = stem.toLowerCase() === "index" ? null : fernBasicSlug(stem);
|
|
5114
5274
|
const route = [...routeSegments, ...pageSegment ? [pageSegment] : []].join("/");
|
|
5115
5275
|
const source = lstatSync4(path).size <= MAX_CONFIG_BYTES2 ? readFileSync4(path, "utf8") : "";
|
|
@@ -5134,7 +5294,7 @@ function registerPage(object, parentSegments, context) {
|
|
|
5134
5294
|
return registerPageAt(object.path, base, context, label, object.hidden === true) || null;
|
|
5135
5295
|
}
|
|
5136
5296
|
function convertNode(node, parentSegments, context) {
|
|
5137
|
-
const object =
|
|
5297
|
+
const object = objectValue4(node);
|
|
5138
5298
|
if (!object) return null;
|
|
5139
5299
|
if (typeof object.page === "string") {
|
|
5140
5300
|
const page = registerPage(object, parentSegments, context);
|
|
@@ -5222,7 +5382,7 @@ function resolveVersionedNavigation(config, configDir, fernRoot, context) {
|
|
|
5222
5382
|
}
|
|
5223
5383
|
if (!Array.isArray(config.versions)) return config;
|
|
5224
5384
|
const versions = config.versions.flatMap((entry) => {
|
|
5225
|
-
const version =
|
|
5385
|
+
const version = objectValue4(entry);
|
|
5226
5386
|
return version ? [version] : [];
|
|
5227
5387
|
});
|
|
5228
5388
|
const chosen = versions.find((version) => version.default === true) ?? versions[0];
|
|
@@ -5241,7 +5401,7 @@ function resolveVersionedNavigation(config, configDir, fernRoot, context) {
|
|
|
5241
5401
|
warnOnce2(context, "fern-version-not-file", `Fern version file "${chosen.path}" is not a regular file and was skipped.`);
|
|
5242
5402
|
return config;
|
|
5243
5403
|
}
|
|
5244
|
-
const versionConfig =
|
|
5404
|
+
const versionConfig = objectValue4(readBoundedYaml(versionPath));
|
|
5245
5405
|
if (!versionConfig) return config;
|
|
5246
5406
|
context.pathPrefix = relative4(fernRoot, dirname3(versionPath)).replace(/\\/g, "/");
|
|
5247
5407
|
return { ...config, navigation: versionConfig.navigation, tabs: versionConfig.tabs ?? config.tabs };
|
|
@@ -5256,13 +5416,13 @@ function resolveVersionedNavigation(config, configDir, fernRoot, context) {
|
|
|
5256
5416
|
}
|
|
5257
5417
|
function buildTabsFromConfig(rawConfig, configDir, fernRoot, routePrefix, fallbackTabLabel, context) {
|
|
5258
5418
|
const config = resolveVersionedNavigation(rawConfig, configDir, fernRoot, context);
|
|
5259
|
-
const tabsMeta =
|
|
5419
|
+
const tabsMeta = objectValue4(config.tabs) ?? {};
|
|
5260
5420
|
const navigation = config.navigation;
|
|
5261
|
-
const isTabbedNavigation = Array.isArray(navigation) && navigation.length > 0 && navigation.every((entry) => typeof
|
|
5421
|
+
const isTabbedNavigation = Array.isArray(navigation) && navigation.length > 0 && navigation.every((entry) => typeof objectValue4(entry)?.tab === "string");
|
|
5262
5422
|
if (isTabbedNavigation) {
|
|
5263
5423
|
return navigation.flatMap((entry) => {
|
|
5264
5424
|
const id = String(entry.tab);
|
|
5265
|
-
const meta =
|
|
5425
|
+
const meta = objectValue4(tabsMeta[id]) ?? {};
|
|
5266
5426
|
const label = typeof meta["display-name"] === "string" ? meta["display-name"] : titleCase3(id);
|
|
5267
5427
|
const tabSegment = segmentFor(meta, label, context);
|
|
5268
5428
|
const segments = [...routePrefix, ...tabSegment ? [tabSegment] : []];
|
|
@@ -5284,7 +5444,7 @@ function buildTabsFromConfig(rawConfig, configDir, fernRoot, routePrefix, fallba
|
|
|
5284
5444
|
const index = visiblePages.find((page) => {
|
|
5285
5445
|
const descriptor = descriptors.get(page);
|
|
5286
5446
|
if (!descriptor) return false;
|
|
5287
|
-
const stem = basename2(descriptor.sourcePath,
|
|
5447
|
+
const stem = basename2(descriptor.sourcePath, extname5(descriptor.sourcePath));
|
|
5288
5448
|
return page === indexRoute || stem === "overview" || stem === "index";
|
|
5289
5449
|
});
|
|
5290
5450
|
const entries = visiblePages.filter((page) => page !== index).sort((left, right) => {
|
|
@@ -5333,7 +5493,7 @@ function buildTabsFromConfig(rawConfig, configDir, fernRoot, routePrefix, fallba
|
|
|
5333
5493
|
}
|
|
5334
5494
|
function projectFernProducts(rawProducts, fernRoot, context) {
|
|
5335
5495
|
return rawProducts.flatMap((entry) => {
|
|
5336
|
-
const product =
|
|
5496
|
+
const product = objectValue4(entry);
|
|
5337
5497
|
const rawPath = typeof product?.path === "string" ? product.path.trim() : "";
|
|
5338
5498
|
if (!product || !rawPath) return [];
|
|
5339
5499
|
const label = typeof product["display-name"] === "string" && product["display-name"].trim() ? product["display-name"].trim() : "Product";
|
|
@@ -5350,7 +5510,7 @@ function projectFernProducts(rawProducts, fernRoot, context) {
|
|
|
5350
5510
|
}
|
|
5351
5511
|
let productConfig;
|
|
5352
5512
|
try {
|
|
5353
|
-
productConfig =
|
|
5513
|
+
productConfig = objectValue4(readBoundedYaml(productPath));
|
|
5354
5514
|
} catch (error) {
|
|
5355
5515
|
warnOnce2(
|
|
5356
5516
|
context,
|
|
@@ -5404,7 +5564,7 @@ function projectFernNavigation(input) {
|
|
|
5404
5564
|
});
|
|
5405
5565
|
}
|
|
5406
5566
|
const navbarLinks = Array.isArray(config["navbar-links"]) ? config["navbar-links"].flatMap((entry) => {
|
|
5407
|
-
const link =
|
|
5567
|
+
const link = objectValue4(entry);
|
|
5408
5568
|
const href = typeof link?.url === "string" ? link.url : typeof link?.href === "string" ? link.href : typeof link?.value === "string" ? link.value : void 0;
|
|
5409
5569
|
const label = typeof link?.text === "string" ? link.text : typeof link?.label === "string" ? link.label : link?.type === "github" ? "GitHub" : void 0;
|
|
5410
5570
|
return href && label ? [{ label, href, ...link?.type === "github" ? { type: "github" } : {} }] : [];
|
|
@@ -5414,11 +5574,11 @@ function projectFernNavigation(input) {
|
|
|
5414
5574
|
navbarLinks.push(link);
|
|
5415
5575
|
}
|
|
5416
5576
|
}
|
|
5417
|
-
const announcement =
|
|
5577
|
+
const announcement = objectValue4(config.announcement);
|
|
5418
5578
|
const announcementMessage = typeof announcement?.message === "string" ? announcement.message.trim() : "";
|
|
5419
5579
|
const bannerContent = announcementMarkdown(announcementMessage);
|
|
5420
5580
|
const redirects = Array.isArray(config.redirects) ? config.redirects.flatMap((value) => {
|
|
5421
|
-
const redirect =
|
|
5581
|
+
const redirect = objectValue4(value);
|
|
5422
5582
|
if (!redirect || typeof redirect.source !== "string" || typeof redirect.destination !== "string") return [];
|
|
5423
5583
|
const rawSource = redirect.source.trim();
|
|
5424
5584
|
const rawDestination = redirect.destination.trim();
|
|
@@ -5504,6 +5664,9 @@ function projectFernNavigation(input) {
|
|
|
5504
5664
|
// src/repository.ts
|
|
5505
5665
|
var MAX_SOURCE_FILES = 5e3;
|
|
5506
5666
|
var MAX_PAGE_BYTES = 2e6;
|
|
5667
|
+
var FRONTMATTER_HEAD_BYTES = 65536;
|
|
5668
|
+
var MAX_WITHHELD_SCAN_BYTES = MAX_PAGE_BYTES * 8;
|
|
5669
|
+
var MAX_DROPPED_GATED_WARNINGS = 20;
|
|
5507
5670
|
var MAX_ASSET_BYTES = 25e6;
|
|
5508
5671
|
var MAX_TOTAL_ASSET_BYTES = 5e8;
|
|
5509
5672
|
var GIT_LFS_POINTER_PREFIX = "version https://git-lfs.github.com/spec/v1";
|
|
@@ -5529,6 +5692,7 @@ var IGNORED_DIRECTORIES = /* @__PURE__ */ new Set([
|
|
|
5529
5692
|
function isIgnoredContentDirectory(name) {
|
|
5530
5693
|
return name.startsWith(".") || name === "node_modules";
|
|
5531
5694
|
}
|
|
5695
|
+
var QUARANTINE_DIRECTORY = "migration-quarantine";
|
|
5532
5696
|
var ASSET_DIRECTORIES = /* @__PURE__ */ new Set(["assets", "images", "img", "media", "public", "static"]);
|
|
5533
5697
|
var ASSET_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
5534
5698
|
".avif",
|
|
@@ -6144,7 +6308,7 @@ function containsMarkdown(directory, depth = 0) {
|
|
|
6144
6308
|
for (const entry of readdirSync2(directory, { withFileTypes: true })) {
|
|
6145
6309
|
if (isIgnoredDirectory(entry.name) || entry.isSymbolicLink()) continue;
|
|
6146
6310
|
const path = resolveWithin(directory, entry.name);
|
|
6147
|
-
if (entry.isFile() && [".md", ".mdx"].includes(
|
|
6311
|
+
if (entry.isFile() && [".md", ".mdx"].includes(extname6(entry.name).toLowerCase())) return true;
|
|
6148
6312
|
if (entry.isDirectory() && containsMarkdown(path, depth + 1)) return true;
|
|
6149
6313
|
}
|
|
6150
6314
|
return false;
|
|
@@ -6156,10 +6320,10 @@ function detectRepositoryDocsDir(repositoryDir) {
|
|
|
6156
6320
|
}
|
|
6157
6321
|
return "";
|
|
6158
6322
|
}
|
|
6159
|
-
var
|
|
6160
|
-
function scanFiles(root, confinementRoot = root, warnings, rank) {
|
|
6323
|
+
var RANKED_WALK_FACTOR = 20;
|
|
6324
|
+
function scanFiles(root, confinementRoot = root, warnings, rank, budget = MAX_SOURCE_FILES) {
|
|
6161
6325
|
const files = [];
|
|
6162
|
-
const walkCap = rank ?
|
|
6326
|
+
const walkCap = rank ? budget * RANKED_WALK_FACTOR : budget;
|
|
6163
6327
|
let confinementReal;
|
|
6164
6328
|
try {
|
|
6165
6329
|
confinementReal = realpathSync2(confinementRoot);
|
|
@@ -6229,10 +6393,10 @@ function scanFiles(root, confinementRoot = root, warnings, rank) {
|
|
|
6229
6393
|
}
|
|
6230
6394
|
return files;
|
|
6231
6395
|
}
|
|
6232
|
-
function selectGroupWithinBudget(scanned, rank, warnings, allVersionPrefixes, label) {
|
|
6233
|
-
if (scanned.length <=
|
|
6396
|
+
function selectGroupWithinBudget(scanned, rank, warnings, allVersionPrefixes, label, budget = MAX_SOURCE_FILES) {
|
|
6397
|
+
if (scanned.length <= budget) return scanned;
|
|
6234
6398
|
const ranked = scanned.map((file) => ({ file, priority: rank(file.relativePath) })).sort((left, right) => left.priority - right.priority || (left.file.relativePath < right.file.relativePath ? -1 : left.file.relativePath > right.file.relativePath ? 1 : 0));
|
|
6235
|
-
const dropped = ranked.slice(
|
|
6399
|
+
const dropped = ranked.slice(budget).map(({ file }) => file);
|
|
6236
6400
|
if (warnings) {
|
|
6237
6401
|
const droppedPages = label === "file" ? dropped.filter((file) => isDocumentationExtension(file.relativePath)) : dropped;
|
|
6238
6402
|
const noun = label === "file" ? "page" : "image or media file";
|
|
@@ -6245,18 +6409,18 @@ function selectGroupWithinBudget(scanned, rank, warnings, allVersionPrefixes, la
|
|
|
6245
6409
|
const rest = droppedPages.length - examples.length;
|
|
6246
6410
|
warnings.push({
|
|
6247
6411
|
code: "limit-reached",
|
|
6248
|
-
message: `This repository has more than ${
|
|
6412
|
+
message: `This repository has more than ${budget} ${label === "file" ? "files" : "assets"}, so only the first ${budget} (in navigation order, default version first) were migrated. ${droppedPages.length} ${noun}(s) were left out` + (examples.length > 0 ? `: ${examples.join(", ")}${rest > 0 ? `, and ${rest} more` : ""}` : "") + (droppedVersions.size > 0 ? ` (versions: ${[...droppedVersions].slice(0, 5).join(", ")}${droppedVersions.size > 5 ? `, and ${droppedVersions.size - 5} more` : ""})` : "") + (label === "file" ? ". To include them, run the migration on a smaller part of the repository with --docs-dir." : ". Copy them into public/ manually if your pages use them.")
|
|
6249
6413
|
});
|
|
6250
6414
|
}
|
|
6251
|
-
return ranked.slice(0,
|
|
6415
|
+
return ranked.slice(0, budget).map(({ file }) => file);
|
|
6252
6416
|
}
|
|
6253
|
-
function selectFilesWithinBudget(scanned, rank, warnings, allVersionPrefixes) {
|
|
6254
|
-
const isAsset = (file) => ASSET_EXTENSIONS.has(
|
|
6417
|
+
function selectFilesWithinBudget(scanned, rank, warnings, allVersionPrefixes, budget = MAX_SOURCE_FILES) {
|
|
6418
|
+
const isAsset = (file) => ASSET_EXTENSIONS.has(extname6(file.relativePath).toLowerCase());
|
|
6255
6419
|
const assetFiles = scanned.filter(isAsset);
|
|
6256
6420
|
const otherFiles = scanned.filter((file) => !isAsset(file));
|
|
6257
6421
|
return [
|
|
6258
|
-
...selectGroupWithinBudget(otherFiles, rank, warnings, allVersionPrefixes, "file"),
|
|
6259
|
-
...selectGroupWithinBudget(assetFiles, rank, warnings, allVersionPrefixes, "asset")
|
|
6422
|
+
...selectGroupWithinBudget(otherFiles, rank, warnings, allVersionPrefixes, "file", budget),
|
|
6423
|
+
...selectGroupWithinBudget(assetFiles, rank, warnings, allVersionPrefixes, "asset", budget)
|
|
6260
6424
|
];
|
|
6261
6425
|
}
|
|
6262
6426
|
function readMintignoreMatcher(mintlifyRoot) {
|
|
@@ -6301,6 +6465,45 @@ function normalizedReferenceKey(value) {
|
|
|
6301
6465
|
function exactReferenceKey(value) {
|
|
6302
6466
|
return value.split(/[?#]/, 1)[0].replace(/^\/+/, "").replace(/\\/g, "/").replace(/\.(?:mdx?|rst|txt)$/i, "");
|
|
6303
6467
|
}
|
|
6468
|
+
function specRefMatches(ref, specPath, specFilename, isDefault) {
|
|
6469
|
+
const prefix = /^(?:(\S+)\s+)?(?:GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS|TRACE|WEBHOOK)\s/i.exec(`${ref} `)?.[1];
|
|
6470
|
+
if (!prefix) return isDefault;
|
|
6471
|
+
const wanted = prefix.replace(/^\/+/, "").toLowerCase();
|
|
6472
|
+
const lowerPath = specPath.toLowerCase();
|
|
6473
|
+
return lowerPath === wanted || lowerPath.endsWith(`/${wanted}`) || specFilename.toLowerCase() === wanted;
|
|
6474
|
+
}
|
|
6475
|
+
var TOKEN_SEPARATORS = /[\s"'()<>[\]{}=,;:|\\/`*!?#&]+/;
|
|
6476
|
+
var PATH_SEPARATORS = /[\s"'()<>[\]{}=,;:|\\`*!?#&]+/;
|
|
6477
|
+
function publicAssetKey(repoRelative) {
|
|
6478
|
+
return repoRelative.split("/", 1)[0].toLowerCase() === "public" ? repoRelative.slice("public/".length) : repoRelative;
|
|
6479
|
+
}
|
|
6480
|
+
function addPathReferences(text, baseDir, exact, loose) {
|
|
6481
|
+
for (const word of text.split(PATH_SEPARATORS)) {
|
|
6482
|
+
let token = word.replace(/\.+$/, "");
|
|
6483
|
+
if (!/\.[a-z0-9]{2,5}$/i.test(token) || token.startsWith("//")) continue;
|
|
6484
|
+
if (token.includes("%")) {
|
|
6485
|
+
try {
|
|
6486
|
+
token = decodeURIComponent(token);
|
|
6487
|
+
} catch {
|
|
6488
|
+
}
|
|
6489
|
+
}
|
|
6490
|
+
if (!token.includes("/")) {
|
|
6491
|
+
loose.add(token.toLowerCase());
|
|
6492
|
+
continue;
|
|
6493
|
+
}
|
|
6494
|
+
if (!token.startsWith("/") && baseDir === void 0) continue;
|
|
6495
|
+
const resolved = normalizeAssetPath(posix3.normalize(token.startsWith("/") ? token.slice(1) : posix3.join(baseDir ?? "", token)));
|
|
6496
|
+
if (!resolved) continue;
|
|
6497
|
+
const key = publicAssetKey(resolved);
|
|
6498
|
+
exact.add(key);
|
|
6499
|
+
loose.add(key.toLowerCase());
|
|
6500
|
+
}
|
|
6501
|
+
}
|
|
6502
|
+
function looselyNamed(assetPath, loose) {
|
|
6503
|
+
const lower = assetPath.toLowerCase();
|
|
6504
|
+
const name = lower.split("/").pop() ?? lower;
|
|
6505
|
+
return loose.has(lower) || loose.has(name) || loose.has(name.split(TOKEN_SEPARATORS).filter(Boolean).pop() ?? name);
|
|
6506
|
+
}
|
|
6304
6507
|
function findOpenApi(files) {
|
|
6305
6508
|
return files.find((file) => OPENAPI_FILENAMES.has(basename3(file.relativePath).toLowerCase()) && classifyApiSpec(file.absolutePath) === "openapi") ?? null;
|
|
6306
6509
|
}
|
|
@@ -6635,6 +6838,31 @@ function fernDefinitionExists(fernRoot, apiName) {
|
|
|
6635
6838
|
}
|
|
6636
6839
|
return candidateDirs.some((dir) => existsSync5(dir) && lstatSync5(dir).isDirectory());
|
|
6637
6840
|
}
|
|
6841
|
+
function readFrontmatterHead(path) {
|
|
6842
|
+
const fd = openSync(path, "r");
|
|
6843
|
+
try {
|
|
6844
|
+
const buffer = Buffer.alloc(FRONTMATTER_HEAD_BYTES);
|
|
6845
|
+
const head = buffer.toString("utf8", 0, readSync(fd, buffer, 0, buffer.length, 0));
|
|
6846
|
+
const opening = /^\uFEFF?---([^\r\n]*)\r?\n/.exec(head);
|
|
6847
|
+
if (!opening || opening[1].startsWith("-")) return head;
|
|
6848
|
+
return /^---[ \t]*\r?\n/m.test(head.slice(opening[0].length)) ? head : void 0;
|
|
6849
|
+
} finally {
|
|
6850
|
+
closeSync(fd);
|
|
6851
|
+
}
|
|
6852
|
+
}
|
|
6853
|
+
function canonicalPath(path) {
|
|
6854
|
+
try {
|
|
6855
|
+
return realpathSync2.native(path);
|
|
6856
|
+
} catch {
|
|
6857
|
+
return path;
|
|
6858
|
+
}
|
|
6859
|
+
}
|
|
6860
|
+
function pageHeadGateReason(raw) {
|
|
6861
|
+
const parsed = parseFrontmatter(raw);
|
|
6862
|
+
const unreadable = parsed.error && /^(groups|public)\s*:/m.test(raw.slice(0, raw.length - parsed.content.length)) ? "frontmatter could not be parsed and declares `groups` or `public`" : void 0;
|
|
6863
|
+
const openapi = typeof parsed.data.openapi === "string" ? parsed.data.openapi.trim() : void 0;
|
|
6864
|
+
return { reason: frontmatterGateReason(parsed.data) ?? unreadable, publicTrue: isPublicTrue(parsed.data.public), openapi };
|
|
6865
|
+
}
|
|
6638
6866
|
function withoutFrontmatter(value) {
|
|
6639
6867
|
return value.replace(/^---\r?\n[\s\S]*?\r?\n---\r?\n?/, "").trim();
|
|
6640
6868
|
}
|
|
@@ -6769,7 +6997,7 @@ function fernSourceSiteUrl(config) {
|
|
|
6769
6997
|
function externalizeMissingFernLinks(body, pageIds, sourceSiteUrl, externalized) {
|
|
6770
6998
|
const rewrite = (target) => {
|
|
6771
6999
|
const path = target.split(/[?#]/, 1)[0].replace(/^\//, "").replace(/\/$/, "");
|
|
6772
|
-
if (!path || pageIds.has(path) || ASSET_EXTENSIONS.has(
|
|
7000
|
+
if (!path || pageIds.has(path) || ASSET_EXTENSIONS.has(extname6(path).toLowerCase())) return target;
|
|
6773
7001
|
try {
|
|
6774
7002
|
const base = new URL(`${sourceSiteUrl}/`);
|
|
6775
7003
|
const sourceLinkUrl = new URL(target.slice(1), base);
|
|
@@ -6963,8 +7191,13 @@ function globalSnippetAliases(files, repositoryRoot, siteRoot) {
|
|
|
6963
7191
|
if (conventionalAlias) aliases.set(conventionalAlias, file.absolutePath);
|
|
6964
7192
|
}
|
|
6965
7193
|
for (const file of files) {
|
|
6966
|
-
if (![".md", ".mdx"].includes(
|
|
6967
|
-
|
|
7194
|
+
if (![".md", ".mdx"].includes(extname6(file.relativePath).toLowerCase())) continue;
|
|
7195
|
+
let raw;
|
|
7196
|
+
try {
|
|
7197
|
+
raw = readFileSync5(file.absolutePath, "utf8");
|
|
7198
|
+
} catch {
|
|
7199
|
+
continue;
|
|
7200
|
+
}
|
|
6968
7201
|
for (const match of raw.matchAll(SNIPPET_IMPORT_PATTERN)) {
|
|
6969
7202
|
try {
|
|
6970
7203
|
const componentName = match[1] ?? match[2];
|
|
@@ -6991,7 +7224,7 @@ function repositoryAssetHref(value, currentFile, siteRoot, onReferenced) {
|
|
|
6991
7224
|
} catch {
|
|
6992
7225
|
return null;
|
|
6993
7226
|
}
|
|
6994
|
-
if (!ASSET_EXTENSIONS.has(
|
|
7227
|
+
if (!ASSET_EXTENSIONS.has(extname6(decodedPath).toLowerCase())) return null;
|
|
6995
7228
|
try {
|
|
6996
7229
|
const candidate = decodedPath.startsWith("/") ? resolveWithin(siteRoot, decodedPath.replace(/^\/+/, "")) : resolveWithinRoot(dirname4(currentFile), decodedPath, siteRoot);
|
|
6997
7230
|
const realRoot = realpathSync2(siteRoot);
|
|
@@ -7003,7 +7236,9 @@ function repositoryAssetHref(value, currentFile, siteRoot, onReferenced) {
|
|
|
7003
7236
|
if (!existsSync5(candidate) || !lstatSync5(candidate).isFile()) return null;
|
|
7004
7237
|
const normalized = normalizeAssetPath(siteRelative);
|
|
7005
7238
|
if (!normalized) return null;
|
|
7006
|
-
|
|
7239
|
+
const onDiskRelative = relative5(realRoot, realpathSync2.native(candidate)).replace(/\\/g, "/");
|
|
7240
|
+
const onDisk = onDiskRelative.toLowerCase() === siteRelative.toLowerCase() ? normalizeAssetPath(onDiskRelative) : null;
|
|
7241
|
+
onReferenced?.(normalized, onDisk ?? void 0);
|
|
7007
7242
|
const rewritten = `/${normalized}${suffix}`;
|
|
7008
7243
|
return isBracketed ? `<${rewritten}>` : rewritten;
|
|
7009
7244
|
} catch {
|
|
@@ -7048,18 +7283,47 @@ function locallyDeclaredNames(raw) {
|
|
|
7048
7283
|
}
|
|
7049
7284
|
return names;
|
|
7050
7285
|
}
|
|
7051
|
-
function inlineMdxSnippets(raw, currentFile, repositoryRoot, warnings, depth = 0, siteRoot = repositoryRoot, globalAliases = /* @__PURE__ */ new Map()) {
|
|
7286
|
+
function inlineMdxSnippets(raw, currentFile, repositoryRoot, warnings, depth = 0, siteRoot = repositoryRoot, globalAliases = /* @__PURE__ */ new Map(), gate) {
|
|
7052
7287
|
if (depth >= 8) return raw;
|
|
7053
7288
|
raw = normalizeIndentedFences(raw);
|
|
7054
7289
|
const snippets = /* @__PURE__ */ new Map();
|
|
7055
7290
|
const preservedDeclarations = /* @__PURE__ */ new Map();
|
|
7056
|
-
|
|
7291
|
+
const source = relative5(repositoryRoot, currentFile).replace(/\\/g, "/");
|
|
7292
|
+
const blockInline = (candidate, shownPath, label = shownPath) => {
|
|
7293
|
+
const verdict = gate?.(candidate);
|
|
7294
|
+
if (!verdict) return void 0;
|
|
7295
|
+
const shown = shownPath.replace(/\*\//g, "* /");
|
|
7296
|
+
if (verdict.kind === "gated") {
|
|
7297
|
+
warnings.push({ code: "gated-page", message: `${label} is access-restricted and was NOT inlined; it was left as a comment.`, source });
|
|
7298
|
+
return `{/* Access-restricted content withheld: ${shown} */}`;
|
|
7299
|
+
}
|
|
7300
|
+
if (verdict.kind === "snippet-gated") {
|
|
7301
|
+
warnings.push({
|
|
7302
|
+
code: "gated-page",
|
|
7303
|
+
message: `${label} declares access rules (${verdict.reason}). Mintlify does not enforce groups on snippets, but it was NOT inlined to be safe; it was left as a comment.`,
|
|
7304
|
+
source
|
|
7305
|
+
});
|
|
7306
|
+
return `{/* Access-restricted content withheld: ${shown} */}`;
|
|
7307
|
+
}
|
|
7308
|
+
warnings.push({
|
|
7309
|
+
code: "skipped-file",
|
|
7310
|
+
message: `${label} ${verdict.kind === "oversized" ? "is too large to inline (over 2 MB)" : "has frontmatter that could not be read"} and was NOT inlined; it was left as a comment.`,
|
|
7311
|
+
source
|
|
7312
|
+
});
|
|
7313
|
+
return `{/* ${verdict.kind === "oversized" ? "Oversized" : "Unreadable"} content not inlined: ${shown} */}`;
|
|
7314
|
+
};
|
|
7315
|
+
let withoutImports = replaceOutsideCode(raw, (source2) => source2.replace(
|
|
7057
7316
|
SNIPPET_IMPORT_PATTERN,
|
|
7058
7317
|
(_statement, namedComponent, defaultComponent, sourcePath) => {
|
|
7059
7318
|
const componentName = namedComponent ?? defaultComponent;
|
|
7060
7319
|
try {
|
|
7061
7320
|
const candidate = resolveSnippetPath(sourcePath, currentFile, repositoryRoot, siteRoot);
|
|
7062
7321
|
if (!existsSync5(candidate) || !lstatSync5(candidate).isFile()) throw new Error("file not found");
|
|
7322
|
+
const blocked = blockInline(candidate, sourcePath, `Imported ${sourcePath}`);
|
|
7323
|
+
if (blocked) {
|
|
7324
|
+
snippets.set(componentName, blocked);
|
|
7325
|
+
return "";
|
|
7326
|
+
}
|
|
7063
7327
|
const nested = inlineMdxSnippets(
|
|
7064
7328
|
withoutFrontmatter(readFileSync5(candidate, "utf8")),
|
|
7065
7329
|
candidate,
|
|
@@ -7067,7 +7331,8 @@ function inlineMdxSnippets(raw, currentFile, repositoryRoot, warnings, depth = 0
|
|
|
7067
7331
|
warnings,
|
|
7068
7332
|
depth + 1,
|
|
7069
7333
|
siteRoot,
|
|
7070
|
-
globalAliases
|
|
7334
|
+
globalAliases,
|
|
7335
|
+
gate
|
|
7071
7336
|
);
|
|
7072
7337
|
const declaration = statefulSnippetDeclaration(nested, componentName);
|
|
7073
7338
|
if (declaration) preservedDeclarations.set(componentName, declaration);
|
|
@@ -7084,7 +7349,7 @@ function inlineMdxSnippets(raw, currentFile, repositoryRoot, warnings, depth = 0
|
|
|
7084
7349
|
}
|
|
7085
7350
|
}
|
|
7086
7351
|
));
|
|
7087
|
-
withoutImports = replaceOutsideCode(withoutImports, (
|
|
7352
|
+
withoutImports = replaceOutsideCode(withoutImports, (source2) => source2.replace(
|
|
7088
7353
|
SNIPPET_VALUE_IMPORT_PATTERN,
|
|
7089
7354
|
(statement, names, sourcePath) => {
|
|
7090
7355
|
const bindings = names.split(",").map((name) => name.trim()).filter(Boolean).map((name) => {
|
|
@@ -7094,7 +7359,16 @@ function inlineMdxSnippets(raw, currentFile, repositoryRoot, warnings, depth = 0
|
|
|
7094
7359
|
if (bindings.length === 0 || bindings.some((binding) => !binding)) return statement;
|
|
7095
7360
|
try {
|
|
7096
7361
|
const candidate = resolveSnippetPath(sourcePath, currentFile, repositoryRoot, siteRoot);
|
|
7097
|
-
if (!existsSync5(candidate) || !lstatSync5(candidate).isFile()) return statement;
|
|
7362
|
+
if (!existsSync5(candidate) || !lstatSync5(candidate).isFile() || gate?.(candidate)?.kind === "gated") return statement;
|
|
7363
|
+
const blocked = blockInline(candidate, sourcePath);
|
|
7364
|
+
if (blocked) {
|
|
7365
|
+
const declarations2 = [];
|
|
7366
|
+
for (const binding of bindings) {
|
|
7367
|
+
if (/^[A-Z]/.test(binding.exported)) snippets.set(binding.local, blocked);
|
|
7368
|
+
else declarations2.push(`export const ${binding.local} = undefined;`);
|
|
7369
|
+
}
|
|
7370
|
+
return declarations2.join("\n");
|
|
7371
|
+
}
|
|
7098
7372
|
const snippetSource = readFileSync5(candidate, "utf8");
|
|
7099
7373
|
const values = staticNamedSnippetValues(snippetSource);
|
|
7100
7374
|
const declarations = [];
|
|
@@ -7119,7 +7393,12 @@ function inlineMdxSnippets(raw, currentFile, repositoryRoot, warnings, depth = 0
|
|
|
7119
7393
|
));
|
|
7120
7394
|
const localNames = locallyDeclaredNames(withoutImports);
|
|
7121
7395
|
for (const [componentName, candidate] of globalAliases) {
|
|
7122
|
-
if (snippets.has(componentName) || localNames.has(componentName) || !new RegExp(`<${componentName}(?:\\s|/?>)`).test(withoutImports)) continue;
|
|
7396
|
+
if (snippets.has(componentName) || localNames.has(componentName) || gate?.(candidate)?.kind === "gated" || !new RegExp(`<${componentName}(?:\\s|/?>)`).test(withoutImports)) continue;
|
|
7397
|
+
const blocked = blockInline(candidate, relative5(repositoryRoot, candidate).replace(/\\/g, "/"));
|
|
7398
|
+
if (blocked) {
|
|
7399
|
+
snippets.set(componentName, blocked);
|
|
7400
|
+
continue;
|
|
7401
|
+
}
|
|
7123
7402
|
const nested = inlineMdxSnippets(
|
|
7124
7403
|
withoutFrontmatter(readFileSync5(candidate, "utf8")),
|
|
7125
7404
|
candidate,
|
|
@@ -7127,7 +7406,8 @@ function inlineMdxSnippets(raw, currentFile, repositoryRoot, warnings, depth = 0
|
|
|
7127
7406
|
warnings,
|
|
7128
7407
|
depth + 1,
|
|
7129
7408
|
siteRoot,
|
|
7130
|
-
globalAliases
|
|
7409
|
+
globalAliases,
|
|
7410
|
+
gate
|
|
7131
7411
|
);
|
|
7132
7412
|
const declaration = statefulSnippetDeclaration(nested, componentName);
|
|
7133
7413
|
if (declaration) preservedDeclarations.set(componentName, declaration);
|
|
@@ -7155,6 +7435,8 @@ function inlineMdxSnippets(raw, currentFile, repositoryRoot, warnings, depth = 0
|
|
|
7155
7435
|
}
|
|
7156
7436
|
}).find((path) => path !== void 0 && existsSync5(path) && lstatSync5(path).isFile());
|
|
7157
7437
|
if (!candidate) throw new Error("file not found");
|
|
7438
|
+
const blocked = blockInline(candidate, filePath, `Snippet file="${filePath}"`);
|
|
7439
|
+
if (blocked) return blocked;
|
|
7158
7440
|
return inlineMdxSnippets(
|
|
7159
7441
|
withoutFrontmatter(readFileSync5(candidate, "utf8")),
|
|
7160
7442
|
candidate,
|
|
@@ -7162,7 +7444,8 @@ function inlineMdxSnippets(raw, currentFile, repositoryRoot, warnings, depth = 0
|
|
|
7162
7444
|
warnings,
|
|
7163
7445
|
depth + 1,
|
|
7164
7446
|
siteRoot,
|
|
7165
|
-
globalAliases
|
|
7447
|
+
globalAliases,
|
|
7448
|
+
gate
|
|
7166
7449
|
);
|
|
7167
7450
|
} catch {
|
|
7168
7451
|
warnings.push({
|
|
@@ -7254,6 +7537,7 @@ function migrateRepository(options) {
|
|
|
7254
7537
|
const referenceOrder = /* @__PURE__ */ new Map();
|
|
7255
7538
|
let docusaurusSidebars = null;
|
|
7256
7539
|
let mintlifyConfig = null;
|
|
7540
|
+
const mintlifyGatedRefs = /* @__PURE__ */ new Map();
|
|
7257
7541
|
let fernRawConfig = null;
|
|
7258
7542
|
let fernBasePath = "";
|
|
7259
7543
|
let fernVersionPath = "";
|
|
@@ -7274,6 +7558,10 @@ function migrateRepository(options) {
|
|
|
7274
7558
|
const projected = projectMintlifyNavigation(config);
|
|
7275
7559
|
docsConfig = projected.docsConfig;
|
|
7276
7560
|
warnings.push(...projected.warnings);
|
|
7561
|
+
for (const gated of projected.gatedReferences) {
|
|
7562
|
+
const gatedKey = normalizedReferenceKey(gated.ref).toLowerCase();
|
|
7563
|
+
if (!mintlifyGatedRefs.has(gatedKey)) mintlifyGatedRefs.set(gatedKey, gated.reason);
|
|
7564
|
+
}
|
|
7277
7565
|
for (const [index, reference] of projected.pageReferences.entries()) {
|
|
7278
7566
|
const key = normalizedReferenceKey(reference.ref);
|
|
7279
7567
|
if (!referenceMap.has(key)) referenceMap.set(key, reference);
|
|
@@ -7359,10 +7647,11 @@ function migrateRepository(options) {
|
|
|
7359
7647
|
const versionCeiling = lastReferencedIndexByVersionLocale.get(blockKey);
|
|
7360
7648
|
return versionCeiling !== void 0 ? versionCeiling + 1 : Number.MAX_SAFE_INTEGER;
|
|
7361
7649
|
} : void 0;
|
|
7362
|
-
const
|
|
7650
|
+
const sourceBudget = options.maxSourceFiles ?? MAX_SOURCE_FILES;
|
|
7651
|
+
const scannedFiles = scanFiles(contentRoot, repositoryDir, warnings, discoveryRank, sourceBudget);
|
|
7363
7652
|
const mintignoreFilteredFiles = mintignoreMatcher ? scannedFiles.filter((file) => !mintignoreMatcher.ignores(file.relativePath)) : scannedFiles;
|
|
7364
|
-
const discoveryBudgetApplied = discoveryRank !== void 0 && mintignoreFilteredFiles.length >
|
|
7365
|
-
const files = discoveryRank ? selectFilesWithinBudget(mintignoreFilteredFiles, discoveryRank, warnings, allVersionPrefixes) : mintignoreFilteredFiles;
|
|
7653
|
+
const discoveryBudgetApplied = discoveryRank !== void 0 && mintignoreFilteredFiles.length > sourceBudget;
|
|
7654
|
+
const files = discoveryRank ? selectFilesWithinBudget(mintignoreFilteredFiles, discoveryRank, warnings, allVersionPrefixes, sourceBudget) : mintignoreFilteredFiles;
|
|
7366
7655
|
if (platform === "fern" && fernProjectRoot) {
|
|
7367
7656
|
const discovered2 = new Set(files.map((file) => file.relativePath));
|
|
7368
7657
|
for (const sourcePath of fernExternalSourcePaths) {
|
|
@@ -7392,6 +7681,108 @@ function migrateRepository(options) {
|
|
|
7392
7681
|
const docusaurusDescriptors = [];
|
|
7393
7682
|
const docusaurusDocCardRoutes = /* @__PURE__ */ new Set();
|
|
7394
7683
|
const seenPageIds = /* @__PURE__ */ new Set();
|
|
7684
|
+
const quarantinedFiles = [];
|
|
7685
|
+
const withheldAssetPaths = /* @__PURE__ */ new Set();
|
|
7686
|
+
const publishedExact = /* @__PURE__ */ new Set();
|
|
7687
|
+
const publishedLoose = /* @__PURE__ */ new Set();
|
|
7688
|
+
const withholdAsset = (assetPath, onDiskSpelling) => {
|
|
7689
|
+
withheldAssetPaths.add(publicAssetKey(onDiskSpelling ?? assetPath));
|
|
7690
|
+
};
|
|
7691
|
+
let sawPublicTrue = false;
|
|
7692
|
+
const gateByPath = /* @__PURE__ */ new Map();
|
|
7693
|
+
const withheldSpecRefs = [];
|
|
7694
|
+
const publishedSpecRefs = [];
|
|
7695
|
+
const withheldPaths = /* @__PURE__ */ new Set();
|
|
7696
|
+
const isDocFile = (file) => [".md", ".mdx"].includes(extname6(file.relativePath).toLowerCase());
|
|
7697
|
+
const isGateCandidate = (file) => isDocFile(file) && !file.relativePath.split("/").some((segment) => SNIPPET_DIRECTORIES.has(segment.toLowerCase()));
|
|
7698
|
+
const classifyPageGate = (file) => {
|
|
7699
|
+
let head = { publicTrue: false };
|
|
7700
|
+
let unreadableGate;
|
|
7701
|
+
try {
|
|
7702
|
+
const size = lstatSync5(file.absolutePath).size;
|
|
7703
|
+
const raw = readFrontmatterHead(file.absolutePath) ?? (size > MAX_PAGE_BYTES ? void 0 : readFileSync5(file.absolutePath, "utf8"));
|
|
7704
|
+
if (raw === void 0) throw new Error("frontmatter is not terminated within the bounded read");
|
|
7705
|
+
head = pageHeadGateReason(raw);
|
|
7706
|
+
} catch {
|
|
7707
|
+
unreadableGate = "frontmatter could not be read";
|
|
7708
|
+
}
|
|
7709
|
+
const reason = head.reason ?? unreadableGate ?? mintlifyGatedRefs.get(normalizedReferenceKey(file.relativePath).toLowerCase());
|
|
7710
|
+
return { reason, publicTrue: head.publicTrue, openapi: head.openapi };
|
|
7711
|
+
};
|
|
7712
|
+
const keptFiles = new Set(files);
|
|
7713
|
+
const droppedGatedFiles = [];
|
|
7714
|
+
const withheldDocFiles = [];
|
|
7715
|
+
let droppedPageCount = 0;
|
|
7716
|
+
const scanTruncated = scannedFiles.length >= (discoveryRank ? sourceBudget * RANKED_WALK_FACTOR : sourceBudget);
|
|
7717
|
+
if (platform === "mintlify") {
|
|
7718
|
+
for (const file of files) {
|
|
7719
|
+
if (isDocFile(file) && !isGateCandidate(file)) {
|
|
7720
|
+
const snippetReason = classifyPageGate(file).reason;
|
|
7721
|
+
if (snippetReason) withheldDocFiles.push(file);
|
|
7722
|
+
continue;
|
|
7723
|
+
}
|
|
7724
|
+
if (!isGateCandidate(file)) continue;
|
|
7725
|
+
const verdict = classifyPageGate(file);
|
|
7726
|
+
gateByPath.set(file.absolutePath, { reason: verdict.reason, publicTrue: verdict.publicTrue });
|
|
7727
|
+
if (verdict.openapi) (verdict.reason ? withheldSpecRefs : publishedSpecRefs).push(verdict.openapi);
|
|
7728
|
+
if (verdict.reason) withheldPaths.add(file.absolutePath);
|
|
7729
|
+
}
|
|
7730
|
+
for (const file of mintignoreFilteredFiles) {
|
|
7731
|
+
if (keptFiles.has(file) || !isDocFile(file)) continue;
|
|
7732
|
+
droppedPageCount++;
|
|
7733
|
+
if (!isGateCandidate(file)) {
|
|
7734
|
+
const snippetReason = classifyPageGate(file).reason;
|
|
7735
|
+
if (snippetReason) {
|
|
7736
|
+
withheldDocFiles.push(file);
|
|
7737
|
+
warnings.push({ code: "gated-page", message: `Access-restricted snippet (${snippetReason}) was dropped by the file limit; its assets were kept out of public/.`, source: file.relativePath });
|
|
7738
|
+
}
|
|
7739
|
+
continue;
|
|
7740
|
+
}
|
|
7741
|
+
const verdict = classifyPageGate(file);
|
|
7742
|
+
if (!verdict.reason) continue;
|
|
7743
|
+
if (verdict.openapi) withheldSpecRefs.push(verdict.openapi);
|
|
7744
|
+
withheldPaths.add(file.absolutePath);
|
|
7745
|
+
droppedGatedFiles.push({ file, reason: verdict.reason });
|
|
7746
|
+
}
|
|
7747
|
+
for (const file of scannedFiles) {
|
|
7748
|
+
if (!mintignoreMatcher?.ignores(file.relativePath) || !isDocFile(file)) continue;
|
|
7749
|
+
const verdict = classifyPageGate(file);
|
|
7750
|
+
if (!verdict.reason) continue;
|
|
7751
|
+
if (verdict.openapi) withheldSpecRefs.push(verdict.openapi);
|
|
7752
|
+
withheldDocFiles.push(file);
|
|
7753
|
+
}
|
|
7754
|
+
}
|
|
7755
|
+
const pagesNotClassified = droppedPageCount > 0 || platform === "mintlify" && scanTruncated;
|
|
7756
|
+
const hasWithheldContent = withheldPaths.size > 0 || withheldDocFiles.length > 0;
|
|
7757
|
+
const trackPublishedRefs = platform === "mintlify" && (hasWithheldContent || pagesNotClassified);
|
|
7758
|
+
const withheldCanonical = new Set([...withheldPaths].map(canonicalPath));
|
|
7759
|
+
const verdictCache = /* @__PURE__ */ new Map();
|
|
7760
|
+
const classifyInlineCandidate = (candidate, key) => {
|
|
7761
|
+
if (withheldCanonical.has(key)) return { kind: "gated", reason: "access-restricted" };
|
|
7762
|
+
const shown = relative5(contentRoot, candidate).replace(/\\/g, "/");
|
|
7763
|
+
const inSnippetDirectory = shown.split("/").some((segment) => SNIPPET_DIRECTORIES.has(segment.toLowerCase()));
|
|
7764
|
+
let head;
|
|
7765
|
+
try {
|
|
7766
|
+
head = readFrontmatterHead(candidate);
|
|
7767
|
+
} catch {
|
|
7768
|
+
return { kind: "unreadable", reason: "could not be read" };
|
|
7769
|
+
}
|
|
7770
|
+
const gated = head === void 0 ? void 0 : pageHeadGateReason(head).reason;
|
|
7771
|
+
if (gated) return { kind: inSnippetDirectory ? "snippet-gated" : "gated", reason: gated };
|
|
7772
|
+
const navigationGated = inSnippetDirectory ? void 0 : mintlifyGatedRefs.get(normalizedReferenceKey(shown).toLowerCase());
|
|
7773
|
+
if (navigationGated) return { kind: "gated", reason: navigationGated };
|
|
7774
|
+
if (lstatSync5(candidate).size > MAX_PAGE_BYTES) return { kind: "oversized", reason: "over 2 MB" };
|
|
7775
|
+
return head === void 0 ? { kind: "unreadable", reason: "frontmatter not terminated in the bounded read" } : void 0;
|
|
7776
|
+
};
|
|
7777
|
+
const inlineGate = platform === "mintlify" ? (candidate) => {
|
|
7778
|
+
const key = canonicalPath(candidate);
|
|
7779
|
+
let verdict = verdictCache.get(key);
|
|
7780
|
+
if (verdict === void 0) {
|
|
7781
|
+
verdict = classifyInlineCandidate(candidate, key) ?? null;
|
|
7782
|
+
verdictCache.set(key, verdict);
|
|
7783
|
+
}
|
|
7784
|
+
return verdict ?? void 0;
|
|
7785
|
+
} : void 0;
|
|
7395
7786
|
const fernIdRenames = /* @__PURE__ */ new Map();
|
|
7396
7787
|
let skipped = 0;
|
|
7397
7788
|
let discovered = files.length;
|
|
@@ -7404,6 +7795,47 @@ function migrateRepository(options) {
|
|
|
7404
7795
|
return leftOrder - rightOrder || left.relativePath.localeCompare(right.relativePath);
|
|
7405
7796
|
});
|
|
7406
7797
|
const snippetAliases = platform === "mintlify" && mintlifyProjectRoot ? globalSnippetAliases(files, repositoryDir, mintlifyProjectRoot) : /* @__PURE__ */ new Map();
|
|
7798
|
+
droppedGatedFiles.forEach(({ file, reason }, index) => {
|
|
7799
|
+
if (index < MAX_DROPPED_GATED_WARNINGS) {
|
|
7800
|
+
warnings.push({
|
|
7801
|
+
code: "gated-page",
|
|
7802
|
+
message: `Access-restricted page (${reason}) was dropped by the file limit, so it was NOT published and was not saved under ${QUARANTINE_DIRECTORY}/; recover it from the source repository.`,
|
|
7803
|
+
source: file.relativePath
|
|
7804
|
+
});
|
|
7805
|
+
}
|
|
7806
|
+
if (!mintlifyProjectRoot) return;
|
|
7807
|
+
try {
|
|
7808
|
+
if (lstatSync5(file.absolutePath).size > MAX_WITHHELD_SCAN_BYTES) throw new Error("too large to scan");
|
|
7809
|
+
rewriteRepositoryAssetLinks(
|
|
7810
|
+
inlineMdxSnippets(readFileSync5(file.absolutePath, "utf8"), file.absolutePath, repositoryDir, [], 0, mintlifyProjectRoot, snippetAliases, inlineGate),
|
|
7811
|
+
file.absolutePath,
|
|
7812
|
+
mintlifyProjectRoot,
|
|
7813
|
+
withholdAsset
|
|
7814
|
+
);
|
|
7815
|
+
} catch {
|
|
7816
|
+
}
|
|
7817
|
+
});
|
|
7818
|
+
for (const file of withheldDocFiles) {
|
|
7819
|
+
try {
|
|
7820
|
+
if (!mintlifyProjectRoot) continue;
|
|
7821
|
+
if (lstatSync5(file.absolutePath).size > MAX_WITHHELD_SCAN_BYTES) {
|
|
7822
|
+
warnings.push({
|
|
7823
|
+
code: "gated-page",
|
|
7824
|
+
message: "Access-restricted file is too large to scan, so the assets it uses could not be checked and may have been copied to public/. Review them before publishing.",
|
|
7825
|
+
source: file.relativePath
|
|
7826
|
+
});
|
|
7827
|
+
continue;
|
|
7828
|
+
}
|
|
7829
|
+
rewriteRepositoryAssetLinks(readFileSync5(file.absolutePath, "utf8"), file.absolutePath, mintlifyProjectRoot, withholdAsset);
|
|
7830
|
+
} catch {
|
|
7831
|
+
}
|
|
7832
|
+
}
|
|
7833
|
+
if (droppedGatedFiles.length > MAX_DROPPED_GATED_WARNINGS) {
|
|
7834
|
+
warnings.push({
|
|
7835
|
+
code: "gated-page",
|
|
7836
|
+
message: `${droppedGatedFiles.length - MAX_DROPPED_GATED_WARNINGS} more access-restricted page(s) were dropped by the file limit and NOT published; recover them from the source repository.`
|
|
7837
|
+
});
|
|
7838
|
+
}
|
|
7407
7839
|
for (const file of pageFiles) {
|
|
7408
7840
|
if (!isDocumentationExtension(file.relativePath)) continue;
|
|
7409
7841
|
if (platform === "fern" && !exactReferenceMap.has(exactReferenceKey(file.relativePath)) && !referenceMap.has(normalizedReferenceKey(file.relativePath))) {
|
|
@@ -7420,7 +7852,7 @@ function migrateRepository(options) {
|
|
|
7420
7852
|
skipped++;
|
|
7421
7853
|
continue;
|
|
7422
7854
|
}
|
|
7423
|
-
if (![".md", ".mdx"].includes(
|
|
7855
|
+
if (![".md", ".mdx"].includes(extname6(file.relativePath).toLowerCase())) {
|
|
7424
7856
|
skipped++;
|
|
7425
7857
|
warnings.push({ code: "skipped-file", message: "Only Markdown and MDX are imported without an explicit converter.", source: file.relativePath });
|
|
7426
7858
|
continue;
|
|
@@ -7429,9 +7861,64 @@ function migrateRepository(options) {
|
|
|
7429
7861
|
if (size > MAX_PAGE_BYTES) {
|
|
7430
7862
|
skipped++;
|
|
7431
7863
|
warnings.push({ code: "skipped-file", message: "Page exceeded the 2 MB repository import limit.", source: file.relativePath });
|
|
7864
|
+
const oversizedGate = gateByPath.get(file.absolutePath)?.reason;
|
|
7865
|
+
if (oversizedGate) {
|
|
7866
|
+
warnings.push({
|
|
7867
|
+
code: "gated-page",
|
|
7868
|
+
message: `Access-restricted page (${oversizedGate}) is too large to migrate (over 2 MB), so it was NOT published and was not saved under ${QUARANTINE_DIRECTORY}/; recover it from the source repository.`,
|
|
7869
|
+
source: file.relativePath
|
|
7870
|
+
});
|
|
7871
|
+
}
|
|
7872
|
+
if (oversizedGate && mintlifyProjectRoot) {
|
|
7873
|
+
if (size > MAX_WITHHELD_SCAN_BYTES) {
|
|
7874
|
+
warnings.push({
|
|
7875
|
+
code: "gated-page",
|
|
7876
|
+
message: "Access-restricted page is too large to scan, so the assets it uses could not be checked and may have been copied to public/. Review them before publishing.",
|
|
7877
|
+
source: file.relativePath
|
|
7878
|
+
});
|
|
7879
|
+
} else {
|
|
7880
|
+
rewriteRepositoryAssetLinks(readFileSync5(file.absolutePath, "utf8"), file.absolutePath, mintlifyProjectRoot, withholdAsset);
|
|
7881
|
+
}
|
|
7882
|
+
}
|
|
7432
7883
|
continue;
|
|
7433
7884
|
}
|
|
7434
7885
|
const key = normalizedReferenceKey(file.relativePath);
|
|
7886
|
+
if (platform === "mintlify") {
|
|
7887
|
+
const gate = gateByPath.get(file.absolutePath);
|
|
7888
|
+
if (gate?.publicTrue) sawPublicTrue = true;
|
|
7889
|
+
const gateReason = gate?.reason;
|
|
7890
|
+
if (gateReason) {
|
|
7891
|
+
skipped++;
|
|
7892
|
+
if (file.relativePath.split("/").some((segment) => segment === "..")) {
|
|
7893
|
+
warnings.push({ code: "gated-page", message: `Access-restricted page (${gateReason}) was withheld from the site, but its path could not be preserved safely; recover it from the source repository.`, source: file.relativePath });
|
|
7894
|
+
continue;
|
|
7895
|
+
}
|
|
7896
|
+
try {
|
|
7897
|
+
if (mintlifyProjectRoot) {
|
|
7898
|
+
rewriteRepositoryAssetLinks(
|
|
7899
|
+
inlineMdxSnippets(readFileSync5(file.absolutePath, "utf8"), file.absolutePath, repositoryDir, [], 0, mintlifyProjectRoot, snippetAliases, inlineGate),
|
|
7900
|
+
file.absolutePath,
|
|
7901
|
+
mintlifyProjectRoot,
|
|
7902
|
+
withholdAsset
|
|
7903
|
+
);
|
|
7904
|
+
}
|
|
7905
|
+
quarantinedFiles.push({ path: `${QUARANTINE_DIRECTORY}/${file.relativePath}`, content: readFileSync5(file.absolutePath) });
|
|
7906
|
+
} catch {
|
|
7907
|
+
warnings.push({
|
|
7908
|
+
code: "gated-page",
|
|
7909
|
+
message: `Access-restricted page (${gateReason}) was NOT published, but it could not be read, so it was not copied to ${QUARANTINE_DIRECTORY}/; recover it from the source repository.`,
|
|
7910
|
+
source: file.relativePath
|
|
7911
|
+
});
|
|
7912
|
+
continue;
|
|
7913
|
+
}
|
|
7914
|
+
warnings.push({
|
|
7915
|
+
code: "gated-page",
|
|
7916
|
+
message: `Access-restricted on the source site (${gateReason}), so it was NOT published. The original is saved at ${QUARANTINE_DIRECTORY}/${file.relativePath}; links from other pages to it will break.`,
|
|
7917
|
+
source: file.relativePath
|
|
7918
|
+
});
|
|
7919
|
+
continue;
|
|
7920
|
+
}
|
|
7921
|
+
}
|
|
7435
7922
|
const referenced = exactReferenceMap.get(exactReferenceKey(file.relativePath)) ?? referenceMap.get(key);
|
|
7436
7923
|
let locale = referenced?.locale;
|
|
7437
7924
|
let navigationId = referenced?.navigationId ?? pageIdFromReference(file.relativePath, platform === "mintlify");
|
|
@@ -7458,8 +7945,11 @@ function migrateRepository(options) {
|
|
|
7458
7945
|
warnings,
|
|
7459
7946
|
0,
|
|
7460
7947
|
mintlifyProjectRoot ?? docusaurusProjectRoot ?? fernProjectRoot ?? repositoryDir,
|
|
7461
|
-
snippetAliases
|
|
7948
|
+
snippetAliases,
|
|
7949
|
+
inlineGate
|
|
7462
7950
|
);
|
|
7951
|
+
const publishedText = trackPublishedRefs ? raw : void 0;
|
|
7952
|
+
const pageAssetReferences = [];
|
|
7463
7953
|
if (platform === "fern" || platform === "mintlify" || platform === "docusaurus") {
|
|
7464
7954
|
raw = normalizeExplicitHeadingIds(raw);
|
|
7465
7955
|
}
|
|
@@ -7551,8 +8041,8 @@ function migrateRepository(options) {
|
|
|
7551
8041
|
}
|
|
7552
8042
|
if (platform === "fern" && fernHiddenIds.has(navigationId)) page.hidden = true;
|
|
7553
8043
|
if (platform === "mintlify" && mintlifyProjectRoot) {
|
|
7554
|
-
page.body = rewriteRepositoryAssetLinks(page.body, file.absolutePath, mintlifyProjectRoot, (assetPath) => {
|
|
7555
|
-
|
|
8044
|
+
page.body = rewriteRepositoryAssetLinks(page.body, file.absolutePath, mintlifyProjectRoot, (assetPath, onDiskSpelling) => {
|
|
8045
|
+
pageAssetReferences.push(publicAssetKey(onDiskSpelling ?? assetPath));
|
|
7556
8046
|
});
|
|
7557
8047
|
}
|
|
7558
8048
|
if (platform === "fern" && fernProjectRoot) {
|
|
@@ -7616,6 +8106,8 @@ function migrateRepository(options) {
|
|
|
7616
8106
|
}
|
|
7617
8107
|
seenPageIds.add(page.id);
|
|
7618
8108
|
pages.push(page);
|
|
8109
|
+
for (const assetPath of pageAssetReferences) addAssetReference(assetPath, file.relativePath);
|
|
8110
|
+
if (publishedText !== void 0) addPathReferences(publishedText, posix3.dirname(file.relativePath).replace(/^\.$/, ""), publishedExact, publishedLoose);
|
|
7619
8111
|
if (hasDocusaurusDocCardList) {
|
|
7620
8112
|
docusaurusDocCardRoutes.add(page.navigationId);
|
|
7621
8113
|
}
|
|
@@ -7658,7 +8150,7 @@ function migrateRepository(options) {
|
|
|
7658
8150
|
const withinFern = relative5(fernProjectRoot, absolutePath);
|
|
7659
8151
|
const assetRelative = withinFern !== ".." && !withinFern.startsWith(`..${sep2}`) && !isAbsolute2(withinFern) ? withinFern : relative5(repositoryDir, absolutePath);
|
|
7660
8152
|
const assetPath = normalizeAssetPath(assetRelative.replace(/\\/g, "/"));
|
|
7661
|
-
if (!assetPath || !ASSET_EXTENSIONS.has(
|
|
8153
|
+
if (!assetPath || !ASSET_EXTENSIONS.has(extname6(assetPath).toLowerCase())) return;
|
|
7662
8154
|
if (source) {
|
|
7663
8155
|
fernBrandAssetPaths.set(source, assetPath);
|
|
7664
8156
|
addAssetReference(assetPath, "fern/docs.yml");
|
|
@@ -7689,24 +8181,59 @@ function migrateRepository(options) {
|
|
|
7689
8181
|
}));
|
|
7690
8182
|
}) : [];
|
|
7691
8183
|
const assetCandidates = [];
|
|
8184
|
+
const mintlifyFonts = platform === "mintlify" ? mintlifyFontSources(mintlifyConfig) : [];
|
|
8185
|
+
const fontRelativePaths = new Set(mintlifyFonts.flatMap((font) => font.path ? [font.path] : []));
|
|
8186
|
+
const importedComponentSources = new Set((componentMigrator?.files() ?? []).flatMap((file) => {
|
|
8187
|
+
const source = /^src\/mdx\/migrated\/[^/]+\/source\/(.+)$/.exec(file.path)?.[1];
|
|
8188
|
+
return source ? [resolvePath(repositoryDir, source)] : [];
|
|
8189
|
+
}));
|
|
8190
|
+
const siteAssetPaths = /* @__PURE__ */ new Map();
|
|
8191
|
+
const fontAssetByRelative = /* @__PURE__ */ new Map();
|
|
7692
8192
|
for (const file of [...files, ...repositoryAssets, ...fernReferencedAssets]) {
|
|
7693
8193
|
const firstSegment = file.relativePath.split("/", 1)[0].toLowerCase();
|
|
7694
|
-
|
|
8194
|
+
const siteKind = platform !== "mintlify" ? void 0 : fontRelativePaths.has(file.relativePath) ? "font" : isMintlifyServedScriptOrStyle(file.relativePath) && !importedComponentSources.has(file.absolutePath) ? extname6(file.relativePath).toLowerCase() === ".css" ? "style" : "script" : void 0;
|
|
8195
|
+
if (!siteKind && !ASSET_EXTENSIONS.has(extname6(file.relativePath).toLowerCase())) continue;
|
|
7695
8196
|
if (platform !== "mintlify" && !ASSET_DIRECTORIES.has(firstSegment) && !(platform === "fern" && referencedAssetPaths.has(file.relativePath))) continue;
|
|
7696
8197
|
const isDocusaurusStatic = platform === "docusaurus" && firstSegment === "static";
|
|
7697
8198
|
const assetPath = normalizeAssetPath(firstSegment === "public" ? file.relativePath.slice("public/".length) : isDocusaurusStatic ? file.relativePath.slice("static/".length) : file.relativePath);
|
|
7698
8199
|
if (!assetPath) continue;
|
|
7699
|
-
|
|
8200
|
+
if (siteKind) {
|
|
8201
|
+
siteAssetPaths.set(assetPath, siteKind);
|
|
8202
|
+
if (siteKind === "font") fontAssetByRelative.set(file.relativePath, assetPath);
|
|
8203
|
+
}
|
|
8204
|
+
const candidateSize = lstatSync5(file.absolutePath).size;
|
|
8205
|
+
if (siteKind === "style" || siteKind === "script") {
|
|
8206
|
+
if (trackPublishedRefs && candidateSize <= MAX_PAGE_BYTES) addPathReferences(readFileSync5(file.absolutePath, "utf8"), posix3.dirname(file.relativePath).replace(/^\.$/, ""), publishedExact, publishedLoose);
|
|
8207
|
+
}
|
|
8208
|
+
assetCandidates.push({ file, assetPath, size: candidateSize });
|
|
7700
8209
|
}
|
|
7701
8210
|
const isReferenced = (candidate) => referencedAssetPaths.has(candidate.assetPath);
|
|
7702
8211
|
const orderedAssetCandidates = [
|
|
7703
8212
|
...assetCandidates.filter((candidate) => isReferenced(candidate)),
|
|
7704
8213
|
...assetCandidates.filter((candidate) => !isReferenced(candidate))
|
|
7705
8214
|
];
|
|
8215
|
+
const quarantinedPageCount = quarantinedFiles.length;
|
|
8216
|
+
const destinationCounts = /* @__PURE__ */ new Map();
|
|
8217
|
+
for (const { assetPath } of assetCandidates) destinationCounts.set(assetPath, (destinationCounts.get(assetPath) ?? 0) + 1);
|
|
8218
|
+
if (trackPublishedRefs) {
|
|
8219
|
+
const publishedConfig = JSON.stringify(mintlifyConfig ?? {}, (_key, value) => value && typeof value === "object" && !Array.isArray(value) && navigationGateReason(value) ? void 0 : value);
|
|
8220
|
+
addPathReferences(publishedConfig, "", publishedExact, publishedLoose);
|
|
8221
|
+
}
|
|
8222
|
+
for (const file of componentMigrator?.files() ?? []) {
|
|
8223
|
+
if (!trackPublishedRefs || typeof file.content !== "string") continue;
|
|
8224
|
+
const original = /^src\/mdx\/migrated\/[^/]+\/source\/(.+)$/.exec(file.path)?.[1];
|
|
8225
|
+
addPathReferences(file.content, original === void 0 ? "" : posix3.dirname(original).replace(/^\.$/, ""), publishedExact, publishedLoose);
|
|
8226
|
+
}
|
|
8227
|
+
const failClosedAssets = trackPublishedRefs;
|
|
8228
|
+
const isPublicReachable = (assetPath) => referencedAssetPaths.has(assetPath) || publishedExact.has(assetPath);
|
|
8229
|
+
const isQuarantinedAsset = (assetPath) => (withheldAssetPaths.has(assetPath) || failClosedAssets && !siteAssetPaths.has(assetPath)) && platform === "mintlify" && !(isPublicReachable(assetPath) && !(failClosedAssets && (destinationCounts.get(assetPath) ?? 0) > 1));
|
|
8230
|
+
let withheldAssetCount = 0;
|
|
8231
|
+
let unreferencedAssetCount = 0;
|
|
7706
8232
|
let totalAssetBytes = 0;
|
|
7707
8233
|
const overBudgetAssets = [];
|
|
7708
8234
|
let overBudgetReferenced = 0;
|
|
7709
8235
|
const lfsPointerAssets = [];
|
|
8236
|
+
const ambiguouslyNamedAssets = [];
|
|
7710
8237
|
for (const { file, assetPath, size } of orderedAssetCandidates) {
|
|
7711
8238
|
if (size > MAX_ASSET_BYTES || totalAssetBytes + size > MAX_TOTAL_ASSET_BYTES) {
|
|
7712
8239
|
overBudgetAssets.push(file.relativePath);
|
|
@@ -7718,9 +8245,53 @@ function migrateRepository(options) {
|
|
|
7718
8245
|
lfsPointerAssets.push(file.relativePath);
|
|
7719
8246
|
continue;
|
|
7720
8247
|
}
|
|
8248
|
+
if (isQuarantinedAsset(assetPath)) {
|
|
8249
|
+
quarantinedFiles.push({ path: `${QUARANTINE_DIRECTORY}/assets/${assetPath}`, content });
|
|
8250
|
+
if (looselyNamed(assetPath, publishedLoose) || (destinationCounts.get(assetPath) ?? 0) > 1) ambiguouslyNamedAssets.push(assetPath);
|
|
8251
|
+
if (withheldAssetPaths.has(assetPath)) withheldAssetCount++;
|
|
8252
|
+
else unreferencedAssetCount++;
|
|
8253
|
+
continue;
|
|
8254
|
+
}
|
|
7721
8255
|
assets.push({ path: assetPath, content });
|
|
7722
8256
|
totalAssetBytes += size;
|
|
7723
8257
|
}
|
|
8258
|
+
if (ambiguouslyNamedAssets.length > 0) {
|
|
8259
|
+
warnings.push({
|
|
8260
|
+
code: "gated-page",
|
|
8261
|
+
message: `${ambiguouslyNamedAssets.length} asset(s) were kept out of public/ because a published page names a file like ${ambiguouslyNamedAssets.length === 1 ? "it" : "them"} in a way that does not give its folder (or differs in letter case), so it cannot be matched to one file (or two files share one public path): ${listAssetPaths(ambiguouslyNamedAssets)}. Copy any that published pages need from ${QUARANTINE_DIRECTORY}/assets/ into public/ by hand.`
|
|
8262
|
+
});
|
|
8263
|
+
}
|
|
8264
|
+
if (platform === "mintlify") {
|
|
8265
|
+
const copiedSite = assets.flatMap((asset) => siteAssetPaths.has(asset.path) ? [{ path: asset.path, kind: siteAssetPaths.get(asset.path) }] : []);
|
|
8266
|
+
const scripts = copiedSite.filter((entry) => entry.kind === "script");
|
|
8267
|
+
if (scripts.length > 0) {
|
|
8268
|
+
docsConfig = {
|
|
8269
|
+
...docsConfig,
|
|
8270
|
+
customScripts: [...docsConfig.customScripts ?? [], ...scripts.map((entry) => ({ src: `/${entry.path.split("/").map(encodeURIComponent).join("/")}`, strategy: "afterInteractive" }))]
|
|
8271
|
+
};
|
|
8272
|
+
warnings.push({
|
|
8273
|
+
code: "unsupported-config",
|
|
8274
|
+
message: `${scripts.length} script(s) from the content directory (${scripts.map((entry) => entry.path).join(", ")}) now load on every page via docs.json customScripts, as they did on Mintlify. They may target Mintlify's page structure; review them.`
|
|
8275
|
+
});
|
|
8276
|
+
}
|
|
8277
|
+
for (const entry of copiedSite.filter((item) => item.kind === "style")) {
|
|
8278
|
+
warnings.push({
|
|
8279
|
+
code: "unsupported-config",
|
|
8280
|
+
message: `Migration gap: custom stylesheet ${entry.path} is NOT applied. It was copied to public/${entry.path} but no page loads it, Thally cannot load a stylesheet from docs.json, and Mintlify-specific selectors will not match Thally's markup. Port the styles you need by hand into src/app/globals.css.`,
|
|
8281
|
+
source: entry.path
|
|
8282
|
+
});
|
|
8283
|
+
}
|
|
8284
|
+
for (const font of mintlifyFonts) {
|
|
8285
|
+
const copiedPath = font.path ? fontAssetByRelative.get(font.path) : void 0;
|
|
8286
|
+
const copied = copiedPath !== void 0 && assets.some((asset) => asset.path === copiedPath);
|
|
8287
|
+
const detail = font.remote ? `its source ${font.source} is a remote URL and was not downloaded` : !font.path ? `its source ${font.source} is not a safe local .woff/.woff2/.ttf/.otf path inside the docs directory and was not imported` : !copiedPath ? `its source file ${font.source} was not found in the docs directory` : copied ? `its file was copied to public/${copiedPath}` : null;
|
|
8288
|
+
if (detail === null) continue;
|
|
8289
|
+
warnings.push({
|
|
8290
|
+
code: "unsupported-config",
|
|
8291
|
+
message: `Self-hosted font "${font.family}" is not applied: Thally's fonts setting loads Google Fonts by family only; ${detail}. The family name was still mapped, which loads a Google font of that name if one exists.`
|
|
8292
|
+
});
|
|
8293
|
+
}
|
|
8294
|
+
}
|
|
7724
8295
|
if (overBudgetAssets.length > 0) {
|
|
7725
8296
|
warnings.push({
|
|
7726
8297
|
code: "limit-reached",
|
|
@@ -7733,8 +8304,8 @@ function migrateRepository(options) {
|
|
|
7733
8304
|
message: `${lfsPointerAssets.length} asset file${lfsPointerAssets.length === 1 ? " is a Git LFS pointer" : "s are Git LFS pointers"}, not real content, and ${lfsPointerAssets.length === 1 ? "was" : "were"} not copied (Git LFS was skipped during clone because the host has no git-lfs binary): ${listAssetPaths(lfsPointerAssets)}. Install git-lfs and re-run the migration, or copy the real files into public/ manually.`
|
|
7734
8305
|
});
|
|
7735
8306
|
}
|
|
7736
|
-
if (!discoveryBudgetApplied && files.length >=
|
|
7737
|
-
warnings.push({ code: "limit-reached", message: `Stopped scanning after ${
|
|
8307
|
+
if (!discoveryBudgetApplied && files.length >= sourceBudget) {
|
|
8308
|
+
warnings.push({ code: "limit-reached", message: `Stopped scanning after ${sourceBudget} files, so the rest of the repository was not looked at. Run the migration on a smaller part of the repository with --docs-dir.` });
|
|
7738
8309
|
}
|
|
7739
8310
|
if (platform === "docusaurus") {
|
|
7740
8311
|
const projected = projectDocusaurusNavigation({
|
|
@@ -7861,11 +8432,19 @@ function migrateRepository(options) {
|
|
|
7861
8432
|
rewriteApiLinksInPages(pages, operationLinks, prefixLandings, warnings);
|
|
7862
8433
|
}
|
|
7863
8434
|
} else if (platform === "mintlify") {
|
|
8435
|
+
const warnSharedSpec = (path) => {
|
|
8436
|
+
warnings.push({
|
|
8437
|
+
code: "gated-page",
|
|
8438
|
+
message: `OpenAPI spec ${path} is shared with access-restricted pages and is published; it may describe restricted endpoints. Review it before publishing.`,
|
|
8439
|
+
source: path
|
|
8440
|
+
});
|
|
8441
|
+
};
|
|
7864
8442
|
const resolvedSpecs = resolveMintlifyApiSpecs(mintlifyConfig, files, warnings, remoteApiSpecs);
|
|
7865
8443
|
for (const spec of resolvedSpecs) {
|
|
7866
8444
|
if (!assets.some((asset) => asset.path === specAssetPath(spec.filename))) {
|
|
7867
8445
|
assets.push(specAsset(spec.filename, spec.content));
|
|
7868
8446
|
}
|
|
8447
|
+
if (withheldSpecRefs.some((ref) => specRefMatches(ref, spec.sourcePath, spec.filename, true))) warnSharedSpec(spec.sourcePath);
|
|
7869
8448
|
}
|
|
7870
8449
|
if (resolvedSpecs.length > 0) {
|
|
7871
8450
|
docsConfig = injectOpenApiSpecs(docsConfig, resolvedSpecs, warnings);
|
|
@@ -7878,10 +8457,17 @@ function migrateRepository(options) {
|
|
|
7878
8457
|
const fallback = findOpenApi(files);
|
|
7879
8458
|
if (fallback) {
|
|
7880
8459
|
const filename = basename3(fallback.relativePath);
|
|
7881
|
-
|
|
7882
|
-
|
|
8460
|
+
const matches = (ref) => specRefMatches(ref, fallback.relativePath, filename, true);
|
|
8461
|
+
if (withheldSpecRefs.some(matches) && !publishedSpecRefs.some(matches)) {
|
|
8462
|
+
quarantinedFiles.push({ path: `${QUARANTINE_DIRECTORY}/assets/${specAssetPath(filename)}`, content: readFileSync5(fallback.absolutePath) });
|
|
8463
|
+
withheldAssetCount++;
|
|
8464
|
+
} else {
|
|
8465
|
+
if (!assets.some((asset) => asset.path === specAssetPath(filename))) {
|
|
8466
|
+
assets.push(specAsset(filename, readFileSync5(fallback.absolutePath)));
|
|
8467
|
+
}
|
|
8468
|
+
docsConfig = injectOpenApiSpecs(docsConfig, [{ filename }]);
|
|
8469
|
+
if (withheldSpecRefs.some(matches)) warnSharedSpec(fallback.relativePath);
|
|
7883
8470
|
}
|
|
7884
|
-
docsConfig = injectOpenApiSpecs(docsConfig, [{ filename }]);
|
|
7885
8471
|
}
|
|
7886
8472
|
}
|
|
7887
8473
|
}
|
|
@@ -8192,10 +8778,9 @@ ${reasons.map((reason) => `- ${reason}`).join("\n")}` : "No importable Markdown
|
|
|
8192
8778
|
docsConfig = { ...docsConfig, navbar: { ...docsConfig.navbar, logo: null } };
|
|
8193
8779
|
}
|
|
8194
8780
|
if (mintlifyConfig) {
|
|
8195
|
-
const appearance = mintlifyConfig
|
|
8196
|
-
|
|
8197
|
-
|
|
8198
|
-
docsConfig = { ...docsConfig, appearance: { ...docsConfig.appearance, default: defaultMode } };
|
|
8781
|
+
const appearance = mintlifyAppearance(mintlifyConfig, warnings);
|
|
8782
|
+
if (Object.keys(appearance).length > 0) {
|
|
8783
|
+
docsConfig = { ...docsConfig, appearance: { ...docsConfig.appearance, ...appearance } };
|
|
8199
8784
|
}
|
|
8200
8785
|
const background = mintlifyConfig.background && typeof mintlifyConfig.background === "object" ? mintlifyConfig.background : null;
|
|
8201
8786
|
if (background) {
|
|
@@ -8228,6 +8813,25 @@ ${reasons.map((reason) => `- ${reason}`).join("\n")}` : "No importable Markdown
|
|
|
8228
8813
|
code: "unsupported-config",
|
|
8229
8814
|
message: `Brand asset(s) were referenced but not imported: ${[...new Set(missingBrand)].join(", ")}. Add these files under public/ or update docs.json.`
|
|
8230
8815
|
});
|
|
8816
|
+
if (platform === "mintlify") {
|
|
8817
|
+
docsConfig = { ...docsConfig, markdown: { enabled: true } };
|
|
8818
|
+
if (quarantinedPageCount > 0 || withheldAssetCount > 0 || unreferencedAssetCount > 0) {
|
|
8819
|
+
const assetNote = withheldAssetCount > 0 ? `${withheldAssetCount} file(s) used only by access-restricted pages were kept out of public/ and saved under ${QUARANTINE_DIRECTORY}/assets/. ` : "";
|
|
8820
|
+
const unreferencedReason = [
|
|
8821
|
+
...hasWithheldContent ? ["this site has access-restricted content"] : [],
|
|
8822
|
+
...pagesNotClassified ? ["pages were dropped by the file limit (or the file scan stopped at its cap) and could not all be checked for access restrictions"] : []
|
|
8823
|
+
].join(" and ");
|
|
8824
|
+
const unreferencedNote = unreferencedAssetCount > 0 ? `${unreferencedAssetCount} unreferenced asset(s) were kept out of public/ because ${unreferencedReason}; review ${QUARANTINE_DIRECTORY}/assets/ and copy any that published pages need. ` : "";
|
|
8825
|
+
warnings.push({
|
|
8826
|
+
code: "gated-page",
|
|
8827
|
+
message: (quarantinedPageCount > 0 ? `${quarantinedPageCount} access-restricted page(s) were withheld from the published site and saved under ${QUARANTINE_DIRECTORY}/ (local only: git-ignored, never served or deployed). ` : "") + assetNote + unreferencedNote + "Assets that published pages also use are still copied to public/. Review them before deciding how to publish or protect that content."
|
|
8828
|
+
});
|
|
8829
|
+
}
|
|
8830
|
+
warnings.push({
|
|
8831
|
+
code: "gated-page",
|
|
8832
|
+
message: (sawPublicTrue ? "Some pages set `public: true`, which means the source site used Mintlify authentication and every page WITHOUT it was private. " : "") + "Access control set in the Mintlify dashboard is not visible in the repository. Check the source site's dashboard access settings before publishing: Thally will publish ALL imported pages publicly. Confirm nothing here was meant to stay private before deploying."
|
|
8833
|
+
});
|
|
8834
|
+
}
|
|
8231
8835
|
if (fernRawConfig?.logo && !logoLight && !logo.light) warnings.push({
|
|
8232
8836
|
code: "unsupported-config",
|
|
8233
8837
|
message: "Fern supplied a logo through its global theme without a local asset; add a logo path to docs.json after import."
|
|
@@ -8240,6 +8844,8 @@ ${reasons.map((reason) => `- ${reason}`).join("\n")}` : "No importable Markdown
|
|
|
8240
8844
|
assets,
|
|
8241
8845
|
...remoteApiSpecs.length > 0 ? { remoteApiSpecs } : {},
|
|
8242
8846
|
...componentMigrator ? { componentFiles: componentMigrator.files() } : {},
|
|
8847
|
+
...quarantinedFiles.length > 0 ? { quarantinedFiles } : {},
|
|
8848
|
+
...droppedGatedFiles.length > 0 ? { droppedGatedPages: droppedGatedFiles.length } : {},
|
|
8243
8849
|
docsConfig,
|
|
8244
8850
|
...mintlifyConfig ? {
|
|
8245
8851
|
site: {
|
|
@@ -8372,6 +8978,7 @@ function renderMigrationFiles(bundle, options = {}) {
|
|
|
8372
8978
|
})),
|
|
8373
8979
|
...bundle.assets.map((asset) => ({ path: asset.projectRelative ? asset.path : `public/${asset.path}`, content: asset.content })),
|
|
8374
8980
|
...(bundle.componentFiles ?? []).flatMap((file) => file.path === "src/mdx/custom-components.tsx" && options.existingComponentRegistry !== void 0 && typeof file.content === "string" ? mergeComponentRegistry(options.existingComponentRegistry, file.content) : [file]),
|
|
8981
|
+
...bundle.quarantinedFiles ?? [],
|
|
8375
8982
|
{ path: "docs.json", content: `${JSON.stringify(config, null, 2)}
|
|
8376
8983
|
` }
|
|
8377
8984
|
];
|