@thallylabs/migrate 0.2.38 → 0.2.39
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 +17 -3
- package/dist/index.d.ts +2 -2
- package/dist/index.js +620 -227
- package/dist/index.js.map +1 -1
- package/dist/url-migration.d.ts +11 -1
- package/dist/url-migration.js +460 -66
- package/dist/url-migration.js.map +1 -1
- package/dist/{url-migration-peVzTLjL.d.ts → url-run-BOZvcGs1.d.ts} +11 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -4462,9 +4462,9 @@ function jsonPointer(root, pointer) {
|
|
|
4462
4462
|
const index = Number(token);
|
|
4463
4463
|
return Number.isSafeInteger(index) && index >= 0 ? current[index] : void 0;
|
|
4464
4464
|
}
|
|
4465
|
-
const
|
|
4466
|
-
if (!
|
|
4467
|
-
return
|
|
4465
|
+
const object3 = objectValue2(current);
|
|
4466
|
+
if (!object3) return void 0;
|
|
4467
|
+
return object3[token.replace(/~1/g, "/").replace(/~0/g, "~")];
|
|
4468
4468
|
}, root);
|
|
4469
4469
|
}
|
|
4470
4470
|
function readMintlifyJson(path, repositoryRoot) {
|
|
@@ -4483,22 +4483,22 @@ function resolveJsonReferences(value, currentFile, repositoryRoot, stack) {
|
|
|
4483
4483
|
if (Array.isArray(value)) {
|
|
4484
4484
|
return value.map((entry) => resolveJsonReferences(entry, currentFile, repositoryRoot, stack));
|
|
4485
4485
|
}
|
|
4486
|
-
const
|
|
4487
|
-
if (!
|
|
4488
|
-
if (typeof
|
|
4489
|
-
const [filePart, pointer = ""] =
|
|
4486
|
+
const object3 = objectValue2(value);
|
|
4487
|
+
if (!object3) return value;
|
|
4488
|
+
if (typeof object3.$ref === "string") {
|
|
4489
|
+
const [filePart, pointer = ""] = object3.$ref.split("#", 2);
|
|
4490
4490
|
const referencedFile = filePart ? resolveWithin(dirname2(currentFile), filePart) : currentFile;
|
|
4491
4491
|
const relativePath = relative3(repositoryRoot, referencedFile);
|
|
4492
4492
|
resolveWithin(repositoryRoot, relativePath);
|
|
4493
4493
|
const stackKey = `${referencedFile}#${pointer}`;
|
|
4494
|
-
if (stack.has(stackKey)) throw new Error(`Circular Mintlify $ref: ${
|
|
4494
|
+
if (stack.has(stackKey)) throw new Error(`Circular Mintlify $ref: ${object3.$ref}`);
|
|
4495
4495
|
stack.add(stackKey);
|
|
4496
4496
|
const referencedRoot = readMintlifyJson(referencedFile, repositoryRoot);
|
|
4497
4497
|
const referenced = jsonPointer(referencedRoot, pointer ? `#${pointer}` : "");
|
|
4498
4498
|
const resolved = resolveJsonReferences(referenced, referencedFile, repositoryRoot, stack);
|
|
4499
4499
|
stack.delete(stackKey);
|
|
4500
4500
|
const siblings = Object.fromEntries(
|
|
4501
|
-
Object.entries(
|
|
4501
|
+
Object.entries(object3).filter(([key]) => key !== "$ref").map(([key, entry]) => [
|
|
4502
4502
|
key,
|
|
4503
4503
|
resolveJsonReferences(entry, currentFile, repositoryRoot, stack)
|
|
4504
4504
|
])
|
|
@@ -4506,7 +4506,7 @@ function resolveJsonReferences(value, currentFile, repositoryRoot, stack) {
|
|
|
4506
4506
|
return objectValue2(resolved) ? { ...resolved, ...siblings } : resolved;
|
|
4507
4507
|
}
|
|
4508
4508
|
return Object.fromEntries(
|
|
4509
|
-
Object.entries(
|
|
4509
|
+
Object.entries(object3).map(([key, entry]) => [
|
|
4510
4510
|
key,
|
|
4511
4511
|
resolveJsonReferences(entry, currentFile, repositoryRoot, stack)
|
|
4512
4512
|
])
|
|
@@ -4529,10 +4529,10 @@ function listedOperations(container) {
|
|
|
4529
4529
|
if (OPENAPI_OPERATION_REF.test(entry)) operations.push(entry.trim());
|
|
4530
4530
|
return;
|
|
4531
4531
|
}
|
|
4532
|
-
const
|
|
4533
|
-
if (!
|
|
4532
|
+
const object3 = objectValue2(entry);
|
|
4533
|
+
if (!object3 || depth > SWEEP_DEPTH_LIMIT || depth > 0 && (specSource(object3.openapi) || specSource(object3.asyncapi))) return;
|
|
4534
4534
|
for (const key of ["groups", "pages"]) {
|
|
4535
|
-
if (Array.isArray(
|
|
4535
|
+
if (Array.isArray(object3[key])) object3[key].forEach((child) => visit(child, depth + 1));
|
|
4536
4536
|
}
|
|
4537
4537
|
};
|
|
4538
4538
|
visit(container, 0);
|
|
@@ -4545,8 +4545,8 @@ var operationKey = (entry) => entry.trim().replace(/^(\S+)\s+/, "$1 ");
|
|
|
4545
4545
|
function operationGroups(container, maxLevel = API_GROUPS_MAX_DEPTH) {
|
|
4546
4546
|
const entries = (node, level) => ["groups", "pages"].flatMap((key) => (Array.isArray(node[key]) ? node[key] : []).flatMap((entry) => {
|
|
4547
4547
|
if (typeof entry === "string") return OPENAPI_OPERATION_REF.test(entry) ? [operationKey(entry)] : [];
|
|
4548
|
-
const
|
|
4549
|
-
const group =
|
|
4548
|
+
const object3 = objectValue2(entry);
|
|
4549
|
+
const group = object3 && !bindsSpec(object3) ? groupOf(object3, level + 1) : void 0;
|
|
4550
4550
|
return group ? [group] : [];
|
|
4551
4551
|
}));
|
|
4552
4552
|
const groupOf = (node, level) => {
|
|
@@ -4641,9 +4641,9 @@ function mintlifyNavigationApiReferences(config) {
|
|
|
4641
4641
|
const entries = node[key];
|
|
4642
4642
|
if (!Array.isArray(entries)) continue;
|
|
4643
4643
|
for (const entry of entries) {
|
|
4644
|
-
const
|
|
4645
|
-
if (!
|
|
4646
|
-
visit(
|
|
4644
|
+
const object3 = objectValue2(entry);
|
|
4645
|
+
if (!object3) continue;
|
|
4646
|
+
visit(object3, labelFor(object3, tabLabel ?? "Documentation"), gated, otherLanguage || key === "languages" && rawNode === navigation && object3 !== defaultLanguage, hidden);
|
|
4647
4647
|
}
|
|
4648
4648
|
}
|
|
4649
4649
|
for (const key of nestedKeys) {
|
|
@@ -4651,15 +4651,15 @@ function mintlifyNavigationApiReferences(config) {
|
|
|
4651
4651
|
if (!Array.isArray(entries)) continue;
|
|
4652
4652
|
for (const entry of entries) {
|
|
4653
4653
|
if (typeof entry === "string") continue;
|
|
4654
|
-
const
|
|
4655
|
-
if (
|
|
4654
|
+
const object3 = objectValue2(entry);
|
|
4655
|
+
if (object3) visit(object3, tabLabel, gated, otherLanguage, hidden || object3.hidden === true);
|
|
4656
4656
|
}
|
|
4657
4657
|
}
|
|
4658
4658
|
if (Array.isArray(node.menu)) {
|
|
4659
4659
|
const tab = tabLabel ?? "Documentation";
|
|
4660
4660
|
const items = node.menu.flatMap((entry) => {
|
|
4661
|
-
const
|
|
4662
|
-
return
|
|
4661
|
+
const object3 = objectValue2(entry);
|
|
4662
|
+
return object3 ? [object3] : [];
|
|
4663
4663
|
});
|
|
4664
4664
|
const apiItems = items.filter((item) => specSource(item.openapi) || specSource(item.asyncapi));
|
|
4665
4665
|
const soleContent = apiItems.length === 1 && !hasNavigationChildren(node) && !items.some(hasNavigationChildren);
|
|
@@ -4727,11 +4727,11 @@ function collectGatedSourceRefs(node, gate, out, limits, depth = 0) {
|
|
|
4727
4727
|
for (const item of node) collectGatedSourceRefs(item, gate, out, limits, depth + 1);
|
|
4728
4728
|
return;
|
|
4729
4729
|
}
|
|
4730
|
-
const
|
|
4731
|
-
if (!
|
|
4732
|
-
const reason = gate ?? navigationGateReason(
|
|
4733
|
-
if (reason && typeof
|
|
4734
|
-
for (const value of Object.values(
|
|
4730
|
+
const object3 = objectValue2(node);
|
|
4731
|
+
if (!object3) return;
|
|
4732
|
+
const reason = gate ?? navigationGateReason(object3);
|
|
4733
|
+
if (reason && typeof object3.sourceRef === "string") out.set(object3, reason);
|
|
4734
|
+
for (const value of Object.values(object3)) collectGatedSourceRefs(value, reason, out, limits, depth + 1);
|
|
4735
4735
|
}
|
|
4736
4736
|
function collectReferenceAccess(node, access, pathPrefix, out, depth = 0) {
|
|
4737
4737
|
if (depth > SWEEP_DEPTH_LIMIT) return;
|
|
@@ -4739,29 +4739,29 @@ function collectReferenceAccess(node, access, pathPrefix, out, depth = 0) {
|
|
|
4739
4739
|
for (const item of node) collectReferenceAccess(item, access, pathPrefix, out, depth + 1);
|
|
4740
4740
|
return;
|
|
4741
4741
|
}
|
|
4742
|
-
const
|
|
4743
|
-
if (!
|
|
4744
|
-
const nested = descendNavigationAccess(access, navigationAccess(
|
|
4742
|
+
const object3 = objectValue2(node);
|
|
4743
|
+
if (!object3) return;
|
|
4744
|
+
const nested = descendNavigationAccess(access, navigationAccess(object3));
|
|
4745
4745
|
if (hasNavigationRules(nested)) {
|
|
4746
|
-
const refs = [
|
|
4746
|
+
const refs = [object3.page, object3.root, object3.href, ...Array.isArray(object3.pages) ? object3.pages : []];
|
|
4747
4747
|
for (const ref of refs) {
|
|
4748
4748
|
if (typeof ref === "string" && normalizePageRef(ref, pathPrefix)) out.push({ ref, access: nested });
|
|
4749
4749
|
}
|
|
4750
4750
|
}
|
|
4751
|
-
for (const value of Object.values(
|
|
4751
|
+
for (const value of Object.values(object3)) collectReferenceAccess(value, nested, pathPrefix, out, depth + 1);
|
|
4752
4752
|
}
|
|
4753
|
-
function withContainerAccess(
|
|
4753
|
+
function withContainerAccess(object3, context, walk2, nested = false) {
|
|
4754
4754
|
const outer = context.access;
|
|
4755
|
-
context.access = descendNavigationAccess(outer, navigationAccess(
|
|
4755
|
+
context.access = descendNavigationAccess(outer, navigationAccess(object3));
|
|
4756
4756
|
try {
|
|
4757
|
-
return withOperationScope(
|
|
4757
|
+
return withOperationScope(object3, context, nested, walk2);
|
|
4758
4758
|
} finally {
|
|
4759
4759
|
context.access = outer;
|
|
4760
4760
|
}
|
|
4761
4761
|
}
|
|
4762
|
-
function withOperationScope(
|
|
4762
|
+
function withOperationScope(object3, context, nested, walk2) {
|
|
4763
4763
|
const outer = context.operations;
|
|
4764
|
-
context.operations = descendOperationScope(outer,
|
|
4764
|
+
context.operations = descendOperationScope(outer, object3, nested);
|
|
4765
4765
|
try {
|
|
4766
4766
|
return walk2();
|
|
4767
4767
|
} finally {
|
|
@@ -4835,9 +4835,9 @@ function convertPage(value, context) {
|
|
|
4835
4835
|
}
|
|
4836
4836
|
return registerReference(value, context);
|
|
4837
4837
|
}
|
|
4838
|
-
const
|
|
4839
|
-
if (!
|
|
4840
|
-
return withContainerAccess(
|
|
4838
|
+
const object3 = objectValue2(value);
|
|
4839
|
+
if (!object3) return null;
|
|
4840
|
+
return withContainerAccess(object3, context, () => convertPageObject(object3, context));
|
|
4841
4841
|
}
|
|
4842
4842
|
function gatedSourceRef(repo, context) {
|
|
4843
4843
|
if (!context.gatedSourceRefs.includes(repo)) context.gatedSourceRefs.push(repo);
|
|
@@ -4848,10 +4848,10 @@ function gatedSourceRef(repo, context) {
|
|
|
4848
4848
|
);
|
|
4849
4849
|
return null;
|
|
4850
4850
|
}
|
|
4851
|
-
function convertPageObject(
|
|
4852
|
-
if (typeof
|
|
4853
|
-
const href = projectedHref(
|
|
4854
|
-
if (href && !
|
|
4851
|
+
function convertPageObject(object3, context) {
|
|
4852
|
+
if (typeof object3.page === "string") return registerReference(object3.page, context);
|
|
4853
|
+
const href = projectedHref(object3.href);
|
|
4854
|
+
if (href && !object3.pages && !object3.groups) {
|
|
4855
4855
|
const page = registerReference(href, context);
|
|
4856
4856
|
if (page) return page;
|
|
4857
4857
|
warnOnce(
|
|
@@ -4861,25 +4861,25 @@ function convertPageObject(object2, context) {
|
|
|
4861
4861
|
);
|
|
4862
4862
|
return null;
|
|
4863
4863
|
}
|
|
4864
|
-
if (typeof
|
|
4865
|
-
if (isNavigationRestricted(context.access) || context.gatedNodes.has(
|
|
4866
|
-
const imported = context.resolveSourceRef?.(
|
|
4867
|
-
if (imported) return { group:
|
|
4864
|
+
if (typeof object3.sourceRef === "string") {
|
|
4865
|
+
if (isNavigationRestricted(context.access) || context.gatedNodes.has(object3) || context.limits.tooDeep) return gatedSourceRef(object3.sourceRef, context);
|
|
4866
|
+
const imported = context.resolveSourceRef?.(object3.sourceRef);
|
|
4867
|
+
if (imported) return { group: object3.sourceRef.split("/").pop() ?? object3.sourceRef, pages: imported };
|
|
4868
4868
|
const where = context.groupLabel ? `the "${context.groupLabel}" navigation group` : "the navigation";
|
|
4869
4869
|
warnOnce(
|
|
4870
4870
|
context,
|
|
4871
|
-
`source-ref:${context.groupLabel ?? ""}:${
|
|
4872
|
-
`Navigation in ${where} mounts the docs of the repository ${
|
|
4871
|
+
`source-ref:${context.groupLabel ?? ""}:${object3.sourceRef}`,
|
|
4872
|
+
`Navigation in ${where} mounts the docs of the repository ${object3.sourceRef} (sourceRef). Those pages were not migrated; pass --source-ref ${object3.sourceRef}=<path> to import them.`
|
|
4873
4873
|
);
|
|
4874
4874
|
return null;
|
|
4875
4875
|
}
|
|
4876
|
-
const pages = Array.isArray(
|
|
4877
|
-
if ("group" in
|
|
4876
|
+
const pages = Array.isArray(object3.pages) ? object3.pages : [];
|
|
4877
|
+
if ("group" in object3 || pages.length > 0) {
|
|
4878
4878
|
const children = [];
|
|
4879
4879
|
const outerGroupLabel = context.groupLabel;
|
|
4880
|
-
context.groupLabel = labelFor(
|
|
4881
|
-
if (typeof
|
|
4882
|
-
const root = registerReference(
|
|
4880
|
+
context.groupLabel = labelFor(object3, "Documentation");
|
|
4881
|
+
if (typeof object3.root === "string") {
|
|
4882
|
+
const root = registerReference(object3.root, context);
|
|
4883
4883
|
if (root) children.push(root);
|
|
4884
4884
|
}
|
|
4885
4885
|
try {
|
|
@@ -4899,9 +4899,9 @@ function convertPageObject(object2, context) {
|
|
|
4899
4899
|
}
|
|
4900
4900
|
if (children.length === 0) return null;
|
|
4901
4901
|
return {
|
|
4902
|
-
group: labelFor(
|
|
4903
|
-
...iconName(
|
|
4904
|
-
...
|
|
4902
|
+
group: labelFor(object3, "Documentation"),
|
|
4903
|
+
...iconName(object3.icon) ? { icon: iconName(object3.icon) } : {},
|
|
4904
|
+
...object3.hidden === true ? { hidden: true } : {},
|
|
4905
4905
|
pages: children
|
|
4906
4906
|
};
|
|
4907
4907
|
}
|
|
@@ -4991,37 +4991,37 @@ function convertContainerToTabs(containerValue, context, fallbackTab, trace, dep
|
|
|
4991
4991
|
entries.sort((left, right) => Number(objectValue2(right)?.default === true) - Number(objectValue2(left)?.default === true));
|
|
4992
4992
|
}
|
|
4993
4993
|
const tabs = entries.flatMap((value, index) => {
|
|
4994
|
-
const
|
|
4995
|
-
if (!
|
|
4996
|
-
const tab = labelFor(
|
|
4997
|
-
const href = projectedHref(
|
|
4998
|
-
const hasNestedContainers = [...containerKeys, "menu"].some((containerKey) => Array.isArray(
|
|
4999
|
-
if (href && !
|
|
4994
|
+
const object3 = objectValue2(value);
|
|
4995
|
+
if (!object3) return [];
|
|
4996
|
+
const tab = labelFor(object3, `${fallbackTab} ${index + 1}`);
|
|
4997
|
+
const href = projectedHref(object3.href);
|
|
4998
|
+
const hasNestedContainers = [...containerKeys, "menu"].some((containerKey) => Array.isArray(object3[containerKey]));
|
|
4999
|
+
if (href && !object3.pages && !object3.groups && !hasNestedContainers) {
|
|
5000
5000
|
return [{
|
|
5001
5001
|
tab,
|
|
5002
5002
|
href,
|
|
5003
|
-
...containerPresentation(
|
|
5004
|
-
...
|
|
5003
|
+
...containerPresentation(object3),
|
|
5004
|
+
...object3.hidden === true ? { hidden: true } : {}
|
|
5005
5005
|
}];
|
|
5006
5006
|
}
|
|
5007
|
-
const nested = withContainerAccess(
|
|
5007
|
+
const nested = withContainerAccess(object3, context, () => convertContainerToTabs(object3, context, tab, trace, depth + 1), true);
|
|
5008
5008
|
if (nested.length > 0) {
|
|
5009
5009
|
if (nested.length === 1) {
|
|
5010
5010
|
return [{
|
|
5011
5011
|
...nested[0],
|
|
5012
5012
|
tab,
|
|
5013
|
-
...containerPresentation(
|
|
5013
|
+
...containerPresentation(object3),
|
|
5014
5014
|
...href ? { href } : {},
|
|
5015
|
-
...
|
|
5015
|
+
...object3.hidden === true ? { hidden: true } : {}
|
|
5016
5016
|
}];
|
|
5017
5017
|
}
|
|
5018
|
-
const presentation = containerPresentation(
|
|
5018
|
+
const presentation = containerPresentation(object3);
|
|
5019
5019
|
return nested.map((item, childIndex) => ({
|
|
5020
5020
|
...presentation,
|
|
5021
5021
|
...item,
|
|
5022
5022
|
tab: `${tab}: ${item.tab}`,
|
|
5023
5023
|
...childIndex === 0 && href && !item.href ? { href } : {},
|
|
5024
|
-
...
|
|
5024
|
+
...object3.hidden === true ? { hidden: true } : {}
|
|
5025
5025
|
}));
|
|
5026
5026
|
}
|
|
5027
5027
|
return [];
|
|
@@ -5820,8 +5820,8 @@ function registerPageAt(rawPath, base, context, navTitle, hidden = false) {
|
|
|
5820
5820
|
context.sourcePathToNavigationId.set(sourcePath, navigationId);
|
|
5821
5821
|
return navigationId;
|
|
5822
5822
|
}
|
|
5823
|
-
function registerFolder(
|
|
5824
|
-
const rawPath = String(
|
|
5823
|
+
function registerFolder(object3, parentSegments, context) {
|
|
5824
|
+
const rawPath = String(object3.folder).trim();
|
|
5825
5825
|
let folder;
|
|
5826
5826
|
try {
|
|
5827
5827
|
folder = withinRealRoot(resolveWithinRoot(
|
|
@@ -5837,8 +5837,8 @@ function registerFolder(object2, parentSegments, context) {
|
|
|
5837
5837
|
warnOnce2(context, `fern-missing-folder-${rawPath}`, `Fern folder "${rawPath}" does not exist and was skipped.`);
|
|
5838
5838
|
return null;
|
|
5839
5839
|
}
|
|
5840
|
-
const label = typeof
|
|
5841
|
-
const segment = typeof
|
|
5840
|
+
const label = typeof object3.title === "string" && object3.title.trim() ? object3.title.trim() : titleCase2(basename2(folder));
|
|
5841
|
+
const segment = typeof object3.slug === "string" || object3["skip-slug"] === true ? segmentFor(object3, label, context) : fernBasicSlug(basename2(folder));
|
|
5842
5842
|
const segments = segment ? [...parentSegments, segment] : parentSegments;
|
|
5843
5843
|
const visit = (directory, routeSegments, depth) => {
|
|
5844
5844
|
if (depth > 12 || context.descriptors.length >= 5e3) {
|
|
@@ -5871,17 +5871,17 @@ function registerFolder(object2, parentSegments, context) {
|
|
|
5871
5871
|
addBareRouteRedirect(segments, pages, context);
|
|
5872
5872
|
return { group: label, pages };
|
|
5873
5873
|
}
|
|
5874
|
-
function registerPage(
|
|
5875
|
-
if (typeof
|
|
5876
|
-
const label = typeof
|
|
5877
|
-
const segment = segmentFor(
|
|
5874
|
+
function registerPage(object3, parentSegments, context) {
|
|
5875
|
+
if (typeof object3.path !== "string" || !object3.path.trim()) return null;
|
|
5876
|
+
const label = typeof object3.page === "string" && object3.page.trim() ? object3.page.trim() : "Untitled";
|
|
5877
|
+
const segment = segmentFor(object3, label, context);
|
|
5878
5878
|
const base = [...parentSegments, segment].filter(Boolean).join("/");
|
|
5879
|
-
return registerPageAt(
|
|
5879
|
+
return registerPageAt(object3.path, base, context, label, object3.hidden === true) || null;
|
|
5880
5880
|
}
|
|
5881
|
-
function isRestrictedNode(
|
|
5882
|
-
const viewers =
|
|
5881
|
+
function isRestrictedNode(object3) {
|
|
5882
|
+
const viewers = object3.viewers;
|
|
5883
5883
|
if (Array.isArray(viewers) ? viewers.length > 0 : typeof viewers === "string" ? viewers.trim() !== "" : viewers !== void 0 && viewers !== null && viewers !== false) return true;
|
|
5884
|
-
const authed =
|
|
5884
|
+
const authed = object3.authed;
|
|
5885
5885
|
return authed !== void 0 && authed !== null && authed !== false && !(typeof authed === "string" && ["", "false"].includes(authed.trim().toLowerCase()));
|
|
5886
5886
|
}
|
|
5887
5887
|
function restrictionMark(context) {
|
|
@@ -5892,67 +5892,67 @@ function markRestricted(context, mark) {
|
|
|
5892
5892
|
context.restrictedApiSections.push(...context.apiSections.splice(mark.apis));
|
|
5893
5893
|
}
|
|
5894
5894
|
function convertNode(node, parentSegments, context) {
|
|
5895
|
-
const
|
|
5896
|
-
if (!
|
|
5895
|
+
const object3 = objectValue3(node);
|
|
5896
|
+
if (!object3) return null;
|
|
5897
5897
|
const walk2 = context.navigationWalk;
|
|
5898
|
-
const reason = walk2.active.has(
|
|
5898
|
+
const reason = walk2.active.has(object3) ? "cyclic section" : walk2.active.size >= 64 ? "section depth exceeds 64" : walk2.visits >= 5e3 ? "node budget exceeds 5000" : void 0;
|
|
5899
5899
|
if (reason) {
|
|
5900
5900
|
walk2.incomplete = true;
|
|
5901
5901
|
warnOnce2(context, `navigation-${reason}`, `Fern navigation was skipped: ${reason}.`);
|
|
5902
5902
|
return null;
|
|
5903
5903
|
}
|
|
5904
5904
|
walk2.visits++;
|
|
5905
|
-
walk2.active.add(
|
|
5905
|
+
walk2.active.add(object3);
|
|
5906
5906
|
try {
|
|
5907
|
-
if (isRestrictedNode(
|
|
5907
|
+
if (isRestrictedNode(object3)) {
|
|
5908
5908
|
const before = restrictionMark(context);
|
|
5909
|
-
convertNodeContents({ ...
|
|
5909
|
+
convertNodeContents({ ...object3, viewers: void 0, authed: void 0 }, parentSegments, context);
|
|
5910
5910
|
markRestricted(context, before);
|
|
5911
5911
|
return null;
|
|
5912
5912
|
}
|
|
5913
|
-
return convertNodeContents(
|
|
5913
|
+
return convertNodeContents(object3, parentSegments, context);
|
|
5914
5914
|
} finally {
|
|
5915
|
-
walk2.active.delete(
|
|
5915
|
+
walk2.active.delete(object3);
|
|
5916
5916
|
}
|
|
5917
5917
|
}
|
|
5918
|
-
function convertNodeContents(
|
|
5919
|
-
if (typeof
|
|
5920
|
-
const page = registerPage(
|
|
5921
|
-
return
|
|
5918
|
+
function convertNodeContents(object3, parentSegments, context) {
|
|
5919
|
+
if (typeof object3.page === "string") {
|
|
5920
|
+
const page = registerPage(object3, parentSegments, context);
|
|
5921
|
+
return object3.hidden === true || context.hiddenInherited ? null : page;
|
|
5922
5922
|
}
|
|
5923
|
-
if (typeof
|
|
5924
|
-
const folder = registerFolder(
|
|
5925
|
-
return
|
|
5923
|
+
if (typeof object3.folder === "string") {
|
|
5924
|
+
const folder = registerFolder(object3, parentSegments, object3.hidden === true ? { ...context, hiddenInherited: true } : context);
|
|
5925
|
+
return object3.hidden === true || context.hiddenInherited ? null : folder;
|
|
5926
5926
|
}
|
|
5927
|
-
if (typeof
|
|
5928
|
-
const label =
|
|
5929
|
-
const segment = segmentFor(
|
|
5927
|
+
if (typeof object3.section === "string") {
|
|
5928
|
+
const label = object3.section;
|
|
5929
|
+
const segment = segmentFor(object3, label, context);
|
|
5930
5930
|
const segments = segment ? [...parentSegments, segment] : parentSegments;
|
|
5931
|
-
const contents = Array.isArray(
|
|
5931
|
+
const contents = Array.isArray(object3.contents) ? object3.contents : [];
|
|
5932
5932
|
const pages = [];
|
|
5933
|
-
const hasOwnPath = typeof
|
|
5933
|
+
const hasOwnPath = typeof object3.path === "string" && object3.path.trim().length > 0;
|
|
5934
5934
|
if (hasOwnPath) {
|
|
5935
|
-
const registered = registerPageAt(
|
|
5935
|
+
const registered = registerPageAt(object3.path, segments.join("/"), context, label, object3.hidden === true);
|
|
5936
5936
|
if (registered) pages.push(registered);
|
|
5937
5937
|
}
|
|
5938
5938
|
for (const child of contents) {
|
|
5939
|
-
const converted = convertNode(child, segments,
|
|
5939
|
+
const converted = convertNode(child, segments, object3.hidden === true ? { ...context, hiddenInherited: true } : context);
|
|
5940
5940
|
if (converted) pages.push(converted);
|
|
5941
5941
|
}
|
|
5942
5942
|
if (pages.length === 0) return null;
|
|
5943
5943
|
if (!hasOwnPath && segment) addBareRouteRedirect(segments, pages, context);
|
|
5944
|
-
if (
|
|
5944
|
+
if (object3.hidden === true || context.hiddenInherited) return null;
|
|
5945
5945
|
return {
|
|
5946
5946
|
group: label,
|
|
5947
|
-
...["open-by-default", "closed-by-default", true, false].includes(
|
|
5948
|
-
...typeof
|
|
5949
|
-
...
|
|
5947
|
+
...["open-by-default", "closed-by-default", true, false].includes(object3.collapsed) ? { defaultOpen: object3.collapsed === "open-by-default" || object3.collapsed === false } : {},
|
|
5948
|
+
...typeof object3.icon === "string" ? { icon: object3.icon } : {},
|
|
5949
|
+
...object3.hidden === true ? { hidden: true } : {},
|
|
5950
5950
|
pages
|
|
5951
5951
|
};
|
|
5952
5952
|
}
|
|
5953
|
-
if (typeof
|
|
5954
|
-
const label =
|
|
5955
|
-
const rawHref = typeof
|
|
5953
|
+
if (typeof object3.link === "string") {
|
|
5954
|
+
const label = object3.link.trim();
|
|
5955
|
+
const rawHref = typeof object3.href === "string" ? object3.href.trim() : "";
|
|
5956
5956
|
let href;
|
|
5957
5957
|
if (/^https?:\/\//i.test(rawHref) && !/[\\\u0000-\u0020\u007f]/.test(rawHref)) {
|
|
5958
5958
|
try {
|
|
@@ -5961,26 +5961,26 @@ function convertNodeContents(object2, parentSegments, context) {
|
|
|
5961
5961
|
} catch {
|
|
5962
5962
|
}
|
|
5963
5963
|
}
|
|
5964
|
-
if (label && href &&
|
|
5964
|
+
if (label && href && object3.hidden !== true && !context.hiddenInherited) {
|
|
5965
5965
|
if (!context.externalLinks.some((link) => link.label === label && link.href === href)) {
|
|
5966
5966
|
context.externalLinks.push({ label, href });
|
|
5967
5967
|
}
|
|
5968
|
-
} else if (!href &&
|
|
5968
|
+
} else if (!href && object3.hidden !== true && !context.hiddenInherited) {
|
|
5969
5969
|
warnOnce2(context, `fern-link-${rawHref}`, `Fern navigation link "${label}" has an unsafe or invalid external URL and was skipped.`);
|
|
5970
5970
|
}
|
|
5971
5971
|
return null;
|
|
5972
5972
|
}
|
|
5973
|
-
if (typeof
|
|
5974
|
-
const ownSegment = segmentFor(
|
|
5973
|
+
if (typeof object3.api === "string") {
|
|
5974
|
+
const ownSegment = segmentFor(object3, object3.api, context);
|
|
5975
5975
|
context.apiSections.push({
|
|
5976
|
-
name: typeof
|
|
5977
|
-
nameExplicit: typeof
|
|
5976
|
+
name: typeof object3["api-name"] === "string" ? object3["api-name"] : object3.api,
|
|
5977
|
+
nameExplicit: typeof object3["api-name"] === "string",
|
|
5978
5978
|
routeSegments: ownSegment ? [...parentSegments, ownSegment] : parentSegments
|
|
5979
5979
|
});
|
|
5980
5980
|
return null;
|
|
5981
5981
|
}
|
|
5982
|
-
if (typeof
|
|
5983
|
-
return registerFolder({ folder:
|
|
5982
|
+
if (typeof object3.changelog === "string") {
|
|
5983
|
+
return registerFolder({ folder: object3.changelog, title: "Changelog", "skip-slug": true }, parentSegments, context);
|
|
5984
5984
|
}
|
|
5985
5985
|
return null;
|
|
5986
5986
|
}
|
|
@@ -6643,14 +6643,14 @@ function parseStaticSidebarModule(source) {
|
|
|
6643
6643
|
literal
|
|
6644
6644
|
);
|
|
6645
6645
|
const parsed = JSON5.parse(substituted);
|
|
6646
|
-
const
|
|
6647
|
-
if (!
|
|
6646
|
+
const object3 = objectValue4(parsed);
|
|
6647
|
+
if (!object3) continue;
|
|
6648
6648
|
const bindingName = candidate[0].match(/\b(?:const|let|var)\s+([A-Za-z_$][\w$]*)/)?.[1];
|
|
6649
6649
|
if (bindingName) {
|
|
6650
|
-
bindings.set(bindingName,
|
|
6650
|
+
bindings.set(bindingName, object3);
|
|
6651
6651
|
continue;
|
|
6652
6652
|
}
|
|
6653
|
-
return
|
|
6653
|
+
return object3;
|
|
6654
6654
|
} catch (error) {
|
|
6655
6655
|
const message = error instanceof Error ? error.message : String(error);
|
|
6656
6656
|
const line = Number(message.match(/at (\d+):/)?.[1] ?? 0);
|
|
@@ -6739,8 +6739,8 @@ function configuredSidebarPath(repositoryRoot) {
|
|
|
6739
6739
|
if (!existsSync4(path)) continue;
|
|
6740
6740
|
const source = readBoundedText(path);
|
|
6741
6741
|
for (const docs of source.matchAll(/\bdocs\s*:\s*/g)) {
|
|
6742
|
-
const
|
|
6743
|
-
const candidate2 =
|
|
6742
|
+
const object3 = matchingObjectLiteral(source, (docs.index ?? 0) + docs[0].length);
|
|
6743
|
+
const candidate2 = object3 && staticStringField(object3, "sidebarPath")?.replace(/^\.\//, "");
|
|
6744
6744
|
if (candidate2) {
|
|
6745
6745
|
const resolved2 = withinRealRoot(resolveWithin(repositoryRoot, candidate2), repositoryRoot);
|
|
6746
6746
|
if (existsSync4(resolved2) && lstatSync4(resolved2).isFile()) return candidate2;
|
|
@@ -6851,12 +6851,12 @@ function readCategoryMetadata(contentRoot, directory) {
|
|
|
6851
6851
|
try {
|
|
6852
6852
|
const raw = readBoundedText(path);
|
|
6853
6853
|
const parsed = filename.endsWith(".json") ? JSON5.parse(raw) : parseYaml3(raw);
|
|
6854
|
-
const
|
|
6855
|
-
if (!
|
|
6854
|
+
const object3 = objectValue4(parsed);
|
|
6855
|
+
if (!object3) return {};
|
|
6856
6856
|
return {
|
|
6857
|
-
...typeof
|
|
6858
|
-
...typeof
|
|
6859
|
-
..."link" in
|
|
6857
|
+
...typeof object3.label === "string" ? { label: object3.label } : {},
|
|
6858
|
+
...typeof object3.position === "number" ? { position: object3.position } : {},
|
|
6859
|
+
..."link" in object3 ? { link: object3.link } : {}
|
|
6860
6860
|
};
|
|
6861
6861
|
} catch {
|
|
6862
6862
|
return {};
|
|
@@ -7040,7 +7040,7 @@ function readDocusaurusSiteSettings(repositoryRoot) {
|
|
|
7040
7040
|
const source = readBoundedText(configPath);
|
|
7041
7041
|
const bindings = staticStringBindings(source);
|
|
7042
7042
|
const presets = staticArrayField(source, "presets");
|
|
7043
|
-
const classicDocs = presets && [...presets.matchAll(/["']?docs["']?\s*:\s*/g)].map((match) => matchingObjectLiteral(presets, (match.index ?? 0) + match[0].length)).find((
|
|
7043
|
+
const classicDocs = presets && [...presets.matchAll(/["']?docs["']?\s*:\s*/g)].map((match) => matchingObjectLiteral(presets, (match.index ?? 0) + match[0].length)).find((object3) => Boolean(object3));
|
|
7044
7044
|
const docsRouteBasePath = classicDocs && staticStringField(classicDocs, "routeBasePath") || "docs";
|
|
7045
7045
|
const themeStart = propertyStart(source, "themeConfig");
|
|
7046
7046
|
const theme = themeStart < 0 ? null : matchingObjectLiteral(source, themeStart);
|
|
@@ -7163,24 +7163,24 @@ function convertItems(value, context) {
|
|
|
7163
7163
|
return page ? [page] : [];
|
|
7164
7164
|
}
|
|
7165
7165
|
if (Array.isArray(value)) return value.flatMap((entry) => convertItems(entry, context));
|
|
7166
|
-
const
|
|
7167
|
-
if (!
|
|
7168
|
-
if (
|
|
7169
|
-
const page = typeof
|
|
7166
|
+
const object3 = objectValue4(value);
|
|
7167
|
+
if (!object3) return [];
|
|
7168
|
+
if (object3.type === "doc" || object3.type === "ref") {
|
|
7169
|
+
const page = typeof object3.id === "string" ? registerDoc(object3.id, context) : null;
|
|
7170
7170
|
return page ? [page] : [];
|
|
7171
7171
|
}
|
|
7172
|
-
if (
|
|
7173
|
-
return autogeneratedItems(typeof
|
|
7172
|
+
if (object3.type === "autogenerated") {
|
|
7173
|
+
return autogeneratedItems(typeof object3.dirName === "string" ? object3.dirName : ".", context);
|
|
7174
7174
|
}
|
|
7175
|
-
if (
|
|
7176
|
-
const label = typeof
|
|
7177
|
-
const pages = convertItems(
|
|
7178
|
-
const landing = generatedIndexPage(label,
|
|
7175
|
+
if (object3.type === "category") {
|
|
7176
|
+
const label = typeof object3.label === "string" ? object3.label : "Documentation";
|
|
7177
|
+
const pages = convertItems(object3.items, context);
|
|
7178
|
+
const landing = generatedIndexPage(label, object3.link, context);
|
|
7179
7179
|
if (landing && !pages.includes(landing)) pages.unshift(landing);
|
|
7180
7180
|
return pages.length > 0 ? [{ group: label, pages }] : [];
|
|
7181
7181
|
}
|
|
7182
|
-
if (
|
|
7183
|
-
return Object.entries(
|
|
7182
|
+
if (object3.type === "link" || object3.type === "html") return [];
|
|
7183
|
+
return Object.entries(object3).flatMap(([label, items]) => {
|
|
7184
7184
|
const pages = convertItems(items, context);
|
|
7185
7185
|
return pages.length > 0 ? [{ group: label, pages }] : [];
|
|
7186
7186
|
});
|
|
@@ -7552,7 +7552,7 @@ import { lstatSync as lstatSync5, readdirSync as readdirSync3, readFileSync as r
|
|
|
7552
7552
|
import { isAbsolute as isAbsolute2, join, relative as relative5, resolve as resolve3, sep as sep2 } from "path";
|
|
7553
7553
|
|
|
7554
7554
|
// src/url.ts
|
|
7555
|
-
import { load as
|
|
7555
|
+
import { load as load3 } from "cheerio";
|
|
7556
7556
|
import remarkMdx3 from "remark-mdx";
|
|
7557
7557
|
import remarkParse3 from "remark-parse";
|
|
7558
7558
|
import TurndownService from "turndown";
|
|
@@ -7738,7 +7738,7 @@ function migrationImageUrl(value, base) {
|
|
|
7738
7738
|
if (!["http:", "https:"].includes(url.protocol) || url.username || url.password) throw new Error("Responsive image URL is not a credential-free HTTP(S) URL.");
|
|
7739
7739
|
return url.toString();
|
|
7740
7740
|
}
|
|
7741
|
-
function migrationImageCandidates(value, base,
|
|
7741
|
+
function migrationImageCandidates(value, base, resolve5 = true) {
|
|
7742
7742
|
if (value.length > 64e3) throw new Error("Responsive image candidate list exceeds its safety bound.");
|
|
7743
7743
|
const result = [];
|
|
7744
7744
|
let index = 0;
|
|
@@ -7756,7 +7756,7 @@ function migrationImageCandidates(value, base, resolve4 = true) {
|
|
|
7756
7756
|
if (descriptor && !/^(?:[1-9]\d*w|(?:\d+(?:\.\d+)?|\.\d+)x)$/.test(descriptor)) throw new Error("Responsive image has an unsupported descriptor.");
|
|
7757
7757
|
if (descriptor.endsWith("x") && Number(descriptor.slice(0, -1)) <= 0) throw new Error("Responsive image density must be positive.");
|
|
7758
7758
|
const resolved = migrationImageUrl(url, base);
|
|
7759
|
-
result.push({ url:
|
|
7759
|
+
result.push({ url: resolve5 ? resolved : url, descriptor });
|
|
7760
7760
|
if (result.length > 128) throw new Error("Responsive image has too many candidates.");
|
|
7761
7761
|
if (value[index] === ",") index++;
|
|
7762
7762
|
}
|
|
@@ -7770,6 +7770,86 @@ function migrationImageAttribute(value) {
|
|
|
7770
7770
|
return value.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">").replace(/\{/g, "{").replace(/\}/g, "}").replace(/\r/g, " ").replace(/\n/g, " ");
|
|
7771
7771
|
}
|
|
7772
7772
|
|
|
7773
|
+
// src/url-media.ts
|
|
7774
|
+
import { load as load2 } from "cheerio";
|
|
7775
|
+
var VIDEO_ATTRIBUTES = /* @__PURE__ */ new Set([
|
|
7776
|
+
"src",
|
|
7777
|
+
"title",
|
|
7778
|
+
"poster",
|
|
7779
|
+
"controls",
|
|
7780
|
+
"muted",
|
|
7781
|
+
"autoplay",
|
|
7782
|
+
"loop",
|
|
7783
|
+
"playsinline",
|
|
7784
|
+
"class",
|
|
7785
|
+
"id",
|
|
7786
|
+
"width",
|
|
7787
|
+
"height",
|
|
7788
|
+
"preload",
|
|
7789
|
+
"aria-label"
|
|
7790
|
+
]);
|
|
7791
|
+
var YOUTUBE_ATTRIBUTES = /* @__PURE__ */ new Set([
|
|
7792
|
+
"src",
|
|
7793
|
+
"title",
|
|
7794
|
+
"width",
|
|
7795
|
+
"height",
|
|
7796
|
+
"allow",
|
|
7797
|
+
"allowfullscreen",
|
|
7798
|
+
"referrerpolicy",
|
|
7799
|
+
"frameborder",
|
|
7800
|
+
"loading",
|
|
7801
|
+
"class",
|
|
7802
|
+
"id",
|
|
7803
|
+
"aria-label"
|
|
7804
|
+
]);
|
|
7805
|
+
var YOUTUBE_HOSTS = /* @__PURE__ */ new Set([
|
|
7806
|
+
"youtube.com",
|
|
7807
|
+
"www.youtube.com",
|
|
7808
|
+
"youtube-nocookie.com",
|
|
7809
|
+
"www.youtube-nocookie.com"
|
|
7810
|
+
]);
|
|
7811
|
+
function projectMigrationMedia(html, base) {
|
|
7812
|
+
const $ = load2(html, void 0, false);
|
|
7813
|
+
const nodes = $.root().contents().filter((_index, node2) => node2.type !== "text" || Boolean(node2.data.trim()));
|
|
7814
|
+
if (nodes.length !== 1) return null;
|
|
7815
|
+
const element = nodes.first();
|
|
7816
|
+
const node = element[0];
|
|
7817
|
+
if (node.type !== "tag" || !["video", "iframe"].includes(node.name)) return null;
|
|
7818
|
+
if (element.children().length || element.text().trim()) return null;
|
|
7819
|
+
const allowed = node.name === "video" ? VIDEO_ATTRIBUTES : YOUTUBE_ATTRIBUTES;
|
|
7820
|
+
if (Object.keys(node.attribs).some((name) => !allowed.has(name))) return null;
|
|
7821
|
+
const source = element.attr("src");
|
|
7822
|
+
if (!source) return null;
|
|
7823
|
+
try {
|
|
7824
|
+
let src = migrationImageUrl(source, base);
|
|
7825
|
+
let component = "Video";
|
|
7826
|
+
const props = [];
|
|
7827
|
+
if (node.name === "video") {
|
|
7828
|
+
if (!/\.(?:mp4|webm|ogg|mov|m4v)(?:[?#]|$)/i.test(src)) component = "video";
|
|
7829
|
+
const isMuted = element.attr("muted") !== void 0;
|
|
7830
|
+
const hasAutoplay = element.attr("autoplay") !== void 0;
|
|
7831
|
+
if (hasAutoplay && !isMuted) return null;
|
|
7832
|
+
props.push("controls={true}");
|
|
7833
|
+
for (const [attribute, prop] of [["muted", "muted"], ["loop", "loop"], ["playsinline", "playsInline"], ["autoplay", "autoPlay"]]) {
|
|
7834
|
+
if (element.attr(attribute) !== void 0) props.push(`${prop}={true}`);
|
|
7835
|
+
}
|
|
7836
|
+
const poster = element.attr("poster");
|
|
7837
|
+
if (poster) props.push(`poster="${migrationImageAttribute(migrationImageUrl(poster, base))}"`);
|
|
7838
|
+
} else {
|
|
7839
|
+
const url = new URL(src);
|
|
7840
|
+
if (url.protocol !== "https:" || url.port || !YOUTUBE_HOSTS.has(url.hostname)) return null;
|
|
7841
|
+
const id = url.pathname.match(/^\/embed\/([A-Za-z0-9_-]{11})$/)?.[1];
|
|
7842
|
+
if (!id || url.hash || [...url.searchParams.keys()].some((name) => name !== "si")) return null;
|
|
7843
|
+
src = `https://www.youtube-nocookie.com/embed/${id}`;
|
|
7844
|
+
}
|
|
7845
|
+
const title = element.attr("title") ?? element.attr("aria-label");
|
|
7846
|
+
if (title !== void 0) props.push(`title="${migrationImageAttribute(title)}"`);
|
|
7847
|
+
return `<${component} src="${migrationImageAttribute(src)}"${props.length ? ` ${props.join(" ")}` : ""} />`;
|
|
7848
|
+
} catch {
|
|
7849
|
+
return null;
|
|
7850
|
+
}
|
|
7851
|
+
}
|
|
7852
|
+
|
|
7773
7853
|
// src/redirects.ts
|
|
7774
7854
|
var LISTED = 10;
|
|
7775
7855
|
function exactRoute(route) {
|
|
@@ -7987,7 +8067,8 @@ var PORTABLE_MDX_COMPONENTS = /* @__PURE__ */ new Set([
|
|
|
7987
8067
|
"Warning",
|
|
7988
8068
|
"YouTube",
|
|
7989
8069
|
"picture",
|
|
7990
|
-
"source"
|
|
8070
|
+
"source",
|
|
8071
|
+
"video"
|
|
7991
8072
|
]);
|
|
7992
8073
|
var LOCALE_CODES = /* @__PURE__ */ new Set([
|
|
7993
8074
|
"ar",
|
|
@@ -8023,7 +8104,7 @@ var LOCALE_CODES = /* @__PURE__ */ new Set([
|
|
|
8023
8104
|
"zh-hans",
|
|
8024
8105
|
"zh-hant"
|
|
8025
8106
|
]);
|
|
8026
|
-
var PORTABLE_URL_PROPS = "href|src|img|primaryHref|secondaryHref";
|
|
8107
|
+
var PORTABLE_URL_PROPS = "href|src|poster|img|primaryHref|secondaryHref";
|
|
8027
8108
|
var PORTABLE_URL_PROP_NAMES = new Set(PORTABLE_URL_PROPS.split("|"));
|
|
8028
8109
|
var MINTLIFY_ARTICLE_LABELS = [
|
|
8029
8110
|
{ baseUrl: "Select base URL", permalink: "Navigate to header" },
|
|
@@ -8099,7 +8180,7 @@ function machineIndexScopePath(source, documents) {
|
|
|
8099
8180
|
if (!document) continue;
|
|
8100
8181
|
const references = [...headerLinks(document)];
|
|
8101
8182
|
if (/html/i.test(document.contentType)) {
|
|
8102
|
-
const $ =
|
|
8183
|
+
const $ = load3(document.body);
|
|
8103
8184
|
references.push(...$("link[href], a[href]").map((_index, element) => $(element).attr("href") ?? "").get().filter((href) => /\/(?:llms(?:-full)?\.txt|sitemap\.xml)(?:[?#]|$)/i.test(href)));
|
|
8104
8185
|
}
|
|
8105
8186
|
for (const reference of references) {
|
|
@@ -8210,7 +8291,7 @@ function jsonObjectAfterKey(value, key) {
|
|
|
8210
8291
|
return null;
|
|
8211
8292
|
}
|
|
8212
8293
|
function embeddedMintlifyConfig(body) {
|
|
8213
|
-
const $ =
|
|
8294
|
+
const $ = load3(body);
|
|
8214
8295
|
const flightPayloads = [];
|
|
8215
8296
|
$("script").each((_index, element) => {
|
|
8216
8297
|
const script = $(element).text();
|
|
@@ -8308,7 +8389,7 @@ function isSafePortableUrl(value) {
|
|
|
8308
8389
|
}
|
|
8309
8390
|
}
|
|
8310
8391
|
function decodeHtmlAttribute(value) {
|
|
8311
|
-
const document =
|
|
8392
|
+
const document = load3(`<i data-thally-value="${value.replace(/"/g, """)}"></i>`);
|
|
8312
8393
|
return document("i").attr("data-thally-value") ?? "";
|
|
8313
8394
|
}
|
|
8314
8395
|
function escapeMarkdownText(value, escapeTableSeparator = false) {
|
|
@@ -8394,7 +8475,7 @@ function replacePortableHtmlImages(value) {
|
|
|
8394
8475
|
if (start < cursor) continue;
|
|
8395
8476
|
const end = htmlOpeningTagEnd(value, start + match[0].length);
|
|
8396
8477
|
if (end === null) continue;
|
|
8397
|
-
const fragment =
|
|
8478
|
+
const fragment = load3(value.slice(start, end));
|
|
8398
8479
|
const image = fragment("img").first();
|
|
8399
8480
|
const source = image.attr("src");
|
|
8400
8481
|
const destination = source && isSafePortableUrl(source) ? markdownLinkDestination(source) : null;
|
|
@@ -8419,7 +8500,7 @@ function replacePortableHtmlAnchors(value) {
|
|
|
8419
8500
|
const closing = closingMatch.exec(value);
|
|
8420
8501
|
if (!closing) continue;
|
|
8421
8502
|
const end = closing.index + closing[0].length;
|
|
8422
|
-
const fragment =
|
|
8503
|
+
const fragment = load3(value.slice(start, end));
|
|
8423
8504
|
const anchor = fragment("a").first();
|
|
8424
8505
|
const href = anchor.attr("href");
|
|
8425
8506
|
const label = escapeMarkdownText(anchor.text().replace(/\s+/g, " ").trim());
|
|
@@ -8454,6 +8535,10 @@ function sanitizeMarkdownUrls(value) {
|
|
|
8454
8535
|
hasUnsafeMdxSyntax = true;
|
|
8455
8536
|
return;
|
|
8456
8537
|
}
|
|
8538
|
+
if (node.name === "video" && node.children?.length) {
|
|
8539
|
+
hasUnsafeMdxSyntax = true;
|
|
8540
|
+
return;
|
|
8541
|
+
}
|
|
8457
8542
|
for (const attribute of node.attributes ?? []) {
|
|
8458
8543
|
if (attribute.type !== "mdxJsxAttribute" || !attribute.name || /^on[A-Z]/.test(attribute.name)) {
|
|
8459
8544
|
hasUnsafeMdxSyntax = true;
|
|
@@ -8490,6 +8575,22 @@ function sanitizeMarkdownUrls(value) {
|
|
|
8490
8575
|
return;
|
|
8491
8576
|
}
|
|
8492
8577
|
}
|
|
8578
|
+
if (node.name === "video") {
|
|
8579
|
+
const isBoolean = ["controls", "muted", "autoPlay", "loop", "playsInline"].includes(attribute.name);
|
|
8580
|
+
const isText = ["src", "poster", "title"].includes(attribute.name);
|
|
8581
|
+
if (isBoolean && typeof staticValue !== "boolean" || isText && typeof attribute.value !== "string" || !isBoolean && !isText) {
|
|
8582
|
+
hasUnsafeMdxSyntax = true;
|
|
8583
|
+
return;
|
|
8584
|
+
}
|
|
8585
|
+
if (attribute.name === "src" || attribute.name === "poster") {
|
|
8586
|
+
try {
|
|
8587
|
+
migrationImageUrl(decodeHtmlAttribute(attribute.value), new URL("https://migration.invalid"));
|
|
8588
|
+
} catch {
|
|
8589
|
+
hasUnsafeMdxSyntax = true;
|
|
8590
|
+
return;
|
|
8591
|
+
}
|
|
8592
|
+
}
|
|
8593
|
+
}
|
|
8493
8594
|
}
|
|
8494
8595
|
}
|
|
8495
8596
|
for (const child of node.children ?? []) validateMdxSyntax(child);
|
|
@@ -8602,7 +8703,7 @@ function sanitizeRemoteMarkdown(body) {
|
|
|
8602
8703
|
const urlSafeMarkdown = sanitizeMarkdownUrls(sanitized);
|
|
8603
8704
|
if (urlSafeMarkdown === null) return null;
|
|
8604
8705
|
const executable = withoutFencedCode2(urlSafeMarkdown).replace(/\{\/\*[\s\S]*?\*\/\}/g, "").replace(/<(?:https?:\/\/|mailto:)[^>]+>/gi, "").replace(/(`+)[\s\S]*?\1/g, "");
|
|
8605
|
-
if (
|
|
8706
|
+
if (/^[\t ]*(?:import|export)[\t ]/m.test(executable)) return null;
|
|
8606
8707
|
let hasUnsafeExpression = false;
|
|
8607
8708
|
const withoutStaticProps = executable.replace(/=\{([^{}\n]*)\}/g, (original, value) => {
|
|
8608
8709
|
try {
|
|
@@ -8699,7 +8800,7 @@ function extractEmbeddedOpenApi(content) {
|
|
|
8699
8800
|
const root = embeddedOpenApiParser.parse(content);
|
|
8700
8801
|
const candidates = (root.children ?? []).flatMap((node2) => {
|
|
8701
8802
|
if (node2.type !== "code" || !/^(?:yaml|yml|json)$/i.test(node2.lang ?? "")) return [];
|
|
8702
|
-
const metadata = node2.meta?.match(/^(?:(
|
|
8803
|
+
const metadata = node2.meta?.match(/^(?:((?:\S+\.(?:yaml|yml|json)|[A-Za-z][A-Za-z0-9_-]{0,127}))\s+)?(delete|get|head|options|patch|post|put|trace)\s+(\/\S+)\s*$/i);
|
|
8703
8804
|
return metadata ? [{ node: node2, method: metadata[2].toUpperCase(), path: metadata[3] }] : [];
|
|
8704
8805
|
});
|
|
8705
8806
|
if (candidates.length !== 1) return { content };
|
|
@@ -8838,7 +8939,7 @@ function mergeEmbeddedOpenApi(fragments) {
|
|
|
8838
8939
|
return new TextEncoder().encode(stringifyYaml2(combined));
|
|
8839
8940
|
}
|
|
8840
8941
|
function migrationHtmlArticle(body) {
|
|
8841
|
-
const $ =
|
|
8942
|
+
const $ = load3(body);
|
|
8842
8943
|
const root = ["main article", "article", "main", '[role="main"]', "body"].map((selector) => $(selector).first()).find((candidate) => candidate.length);
|
|
8843
8944
|
root.find([
|
|
8844
8945
|
"script",
|
|
@@ -8856,7 +8957,10 @@ function migrationHtmlArticle(body) {
|
|
|
8856
8957
|
"#chat-assistant-sheet",
|
|
8857
8958
|
"#chat-assistant-textarea"
|
|
8858
8959
|
].join(",")).remove();
|
|
8859
|
-
|
|
8960
|
+
root.find('div[data-component-part="code-group-tab-content"]').each((_index, element) => {
|
|
8961
|
+
if ($(element).parents("pre").length === 0 && $(element).find("pre").length === 0) element.name = "pre";
|
|
8962
|
+
});
|
|
8963
|
+
const permalinkSelectors = MINTLIFY_ARTICLE_LABELS.map((labels2) => `a[aria-label="${labels2.permalink}"]`);
|
|
8860
8964
|
root.find([...permalinkSelectors, "h1 .hash-link", "h2 .hash-link", "h3 .hash-link", "h4 .hash-link", "h5 .hash-link", "h6 .hash-link"].join(",")).each((_index, link) => {
|
|
8861
8965
|
const parent = $(link).parent();
|
|
8862
8966
|
$(link).remove();
|
|
@@ -8867,7 +8971,7 @@ function migrationHtmlArticle(body) {
|
|
|
8867
8971
|
const isChecked = $(element).attr("checked") !== void 0;
|
|
8868
8972
|
$(element).replaceWith($("<span></span>").attr("data-thally-static-task-checkbox", isChecked ? "checked" : "unchecked").text(isChecked ? "[x] " : "[ ] "));
|
|
8869
8973
|
});
|
|
8870
|
-
root.find(MINTLIFY_ARTICLE_LABELS.map((
|
|
8974
|
+
root.find(MINTLIFY_ARTICLE_LABELS.map((labels2) => `select[aria-label="${labels2.baseUrl}"]`).join(",")).each((_index, element) => {
|
|
8871
8975
|
const select = $(element);
|
|
8872
8976
|
const options = select.children("option").toArray();
|
|
8873
8977
|
if (!options.length || options.length !== select.children().length) return;
|
|
@@ -8906,7 +9010,7 @@ function htmlPage(document, id, options = {}) {
|
|
|
8906
9010
|
const title = scopedTitle || $("main h1, article h1, h1").first().text().trim() || $('meta[property="og:title"]').attr("content")?.trim() || $("title").text().split("|")[0].trim();
|
|
8907
9011
|
const description = $('meta[name="description"]').attr("content")?.trim() || $('meta[property="og:description"]').attr("content")?.trim();
|
|
8908
9012
|
let documentHeadingAnchor = "";
|
|
8909
|
-
const excludedElements = options.omitDocumentHeading ? "script,style,noscript,nav,footer,aside,form,button,svg,
|
|
9013
|
+
const excludedElements = options.omitDocumentHeading ? "script,style,noscript,nav,footer,aside,form,button,svg,object,embed,link,meta" : "script,style,noscript,nav,header,footer,aside,form,button,svg,object,embed,link,meta";
|
|
8910
9014
|
root.find(excludedElements).remove();
|
|
8911
9015
|
root.find(".theme-doc-version-badge,.theme-doc-breadcrumbs,.theme-doc-toc-mobile,.table-of-contents,.hash-link").remove();
|
|
8912
9016
|
if (options.omitDocumentHeading) {
|
|
@@ -8964,6 +9068,18 @@ function htmlPage(document, id, options = {}) {
|
|
|
8964
9068
|
// Emit literal task-list syntax rather than escaping its brackets as copy.
|
|
8965
9069
|
replacement: (_content, node) => node.getAttribute("data-thally-static-task-checkbox") === "checked" ? "[x] " : "[ ] "
|
|
8966
9070
|
});
|
|
9071
|
+
turndown.addRule("migration-authored-paragraph", {
|
|
9072
|
+
filter: (node) => node.nodeName === "SPAN" && node.getAttribute("data-as") === "p",
|
|
9073
|
+
// Some publishers render authored paragraphs as spans. Their explicit
|
|
9074
|
+
// semantic hint must retain a block boundary: otherwise following copy
|
|
9075
|
+
// joins a picture's closing tag or an accordion's source anchor and can
|
|
9076
|
+
// change the resulting MDX grammar. Ordinary spans remain inline.
|
|
9077
|
+
replacement: (content) => `
|
|
9078
|
+
|
|
9079
|
+
${content}
|
|
9080
|
+
|
|
9081
|
+
`
|
|
9082
|
+
});
|
|
8967
9083
|
const anchor = (element) => {
|
|
8968
9084
|
const value = element.getAttribute("id");
|
|
8969
9085
|
return options.preserveAnchors && value ? `<a id="${value.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/\{/g, "{")}" />
|
|
@@ -8982,6 +9098,18 @@ ${anchor(element)}${heading ? `${"#".repeat(Number(heading[1]))} ${content.trim(
|
|
|
8982
9098
|
`;
|
|
8983
9099
|
}
|
|
8984
9100
|
});
|
|
9101
|
+
turndown.addRule("migration-static-media", {
|
|
9102
|
+
filter: (node) => node.nodeName === "VIDEO" || node.nodeName === "IFRAME",
|
|
9103
|
+
replacement: (_content, node) => {
|
|
9104
|
+
const element = node;
|
|
9105
|
+
const projected = projectMigrationMedia(element.outerHTML, document.finalUrl);
|
|
9106
|
+
return projected ? `
|
|
9107
|
+
|
|
9108
|
+
${anchor(element)}${projected}
|
|
9109
|
+
|
|
9110
|
+
` : "";
|
|
9111
|
+
}
|
|
9112
|
+
});
|
|
8985
9113
|
if (options.preserveResponsiveImages) {
|
|
8986
9114
|
const image = (element) => {
|
|
8987
9115
|
const tag = element.nodeName.toLowerCase();
|
|
@@ -9017,7 +9145,7 @@ ${content.trim()}
|
|
|
9017
9145
|
const element = node;
|
|
9018
9146
|
const className = element.className;
|
|
9019
9147
|
const tag = /admonition-(?:danger)/.test(className) ? "Error" : /admonition-(?:caution|warning)/.test(className) ? "Warning" : /admonition-info/.test(className) ? "Info" : "Note";
|
|
9020
|
-
const fragment =
|
|
9148
|
+
const fragment = load3(element.outerHTML);
|
|
9021
9149
|
const clone = fragment(".theme-admonition").first();
|
|
9022
9150
|
const title2 = clone.find('[class*="admonitionHeading"],.admonition-heading').first();
|
|
9023
9151
|
const titleText = title2.text().trim();
|
|
@@ -9038,15 +9166,15 @@ ${titleText ? `**${escapeMarkdownText(titleText)}**
|
|
|
9038
9166
|
filter: (node) => node.nodeName === "DIV" && node.classList.contains("tabs-container"),
|
|
9039
9167
|
replacement: (_content, node) => {
|
|
9040
9168
|
const element = node;
|
|
9041
|
-
const fragment =
|
|
9169
|
+
const fragment = load3(element.outerHTML);
|
|
9042
9170
|
const container = fragment(".tabs-container").first();
|
|
9043
|
-
const
|
|
9171
|
+
const labels2 = container.children("ul.tabs").children("li").toArray().map((item) => fragment(item).text().trim() || "Tab");
|
|
9044
9172
|
const panels = container.find('[role="tabpanel"]').toArray().filter((panel) => fragment(panel).closest(".tabs-container")[0] === container[0]);
|
|
9045
9173
|
if (panels.length === 0) return _content;
|
|
9046
9174
|
const tabs = panels.map((panel, index) => {
|
|
9047
9175
|
const panelId = fragment(panel).attr("id");
|
|
9048
9176
|
const tab = panelId ? container.find('[role="tab"]').toArray().find((item) => fragment(item).attr("aria-controls") === panelId) : void 0;
|
|
9049
|
-
const title2 = migrationImageAttribute((tab ? fragment(tab).text().trim() :
|
|
9177
|
+
const title2 = migrationImageAttribute((tab ? fragment(tab).text().trim() : labels2[index]) || `Tab ${index + 1}`);
|
|
9050
9178
|
const panelAnchor = options.preserveAnchors && panelId ? `<a id="${migrationImageAttribute(panelId)}" />
|
|
9051
9179
|
|
|
9052
9180
|
` : "";
|
|
@@ -9066,7 +9194,7 @@ ${tabs.join("\n\n")}
|
|
|
9066
9194
|
turndown.addRule("gfm-table", {
|
|
9067
9195
|
filter: "table",
|
|
9068
9196
|
replacement: (_content, node) => {
|
|
9069
|
-
const fragment =
|
|
9197
|
+
const fragment = load3(node.outerHTML);
|
|
9070
9198
|
const rows = fragment("tr").toArray().map((row) => fragment(row).children("th,td").toArray().map((cell) => {
|
|
9071
9199
|
const wasConvertingTableCell = isConvertingTableCell;
|
|
9072
9200
|
isConvertingTableCell = true;
|
|
@@ -9092,7 +9220,7 @@ ${normalized.slice(1).map((row) => `| ${row.join(" | ")} |`).join("\n")}
|
|
|
9092
9220
|
filter: (node) => node.nodeName === "PRE",
|
|
9093
9221
|
replacement: (_content, node) => {
|
|
9094
9222
|
const element = node;
|
|
9095
|
-
const fragment =
|
|
9223
|
+
const fragment = load3(element.outerHTML);
|
|
9096
9224
|
const tokenLines = fragment(".token-line").toArray();
|
|
9097
9225
|
const code = (tokenLines.length > 0 ? tokenLines.map((line) => fragment(line).text()).join("\n") : fragment("pre").text()).replace(/\n$/, "");
|
|
9098
9226
|
const language = ["code", "pre"].flatMap((selector) => {
|
|
@@ -9132,7 +9260,7 @@ ${fence}
|
|
|
9132
9260
|
};
|
|
9133
9261
|
}
|
|
9134
9262
|
function htmlNavigationLinks(document) {
|
|
9135
|
-
const $ =
|
|
9263
|
+
const $ = load3(document.body);
|
|
9136
9264
|
return $('.nav-tabs a[href], nav a[href], aside a[href], [role="navigation"] a[href]').map((_index, element) => $(element).attr("href") ?? "").get().filter(Boolean);
|
|
9137
9265
|
}
|
|
9138
9266
|
function normalizedLinkLabel(value) {
|
|
@@ -9140,7 +9268,7 @@ function normalizedLinkLabel(value) {
|
|
|
9140
9268
|
}
|
|
9141
9269
|
function readDocusaurusSidebar(document) {
|
|
9142
9270
|
if (!/html/i.test(document.contentType)) return null;
|
|
9143
|
-
const $ =
|
|
9271
|
+
const $ = load3(document.body);
|
|
9144
9272
|
const sidebar = $("ul.theme-doc-sidebar-menu").first();
|
|
9145
9273
|
if (sidebar.length === 0) return null;
|
|
9146
9274
|
function readList(list2) {
|
|
@@ -9176,7 +9304,7 @@ function docusaurusSidebarHrefs(snapshot) {
|
|
|
9176
9304
|
return hrefs;
|
|
9177
9305
|
}
|
|
9178
9306
|
function deriveDocusaurusScope(source, document, submittedScopePath) {
|
|
9179
|
-
const $ =
|
|
9307
|
+
const $ = load3(document.body);
|
|
9180
9308
|
const sidebar = readDocusaurusSidebar(document);
|
|
9181
9309
|
const internalPaths = docusaurusSidebarHrefs(sidebar).flatMap((href) => {
|
|
9182
9310
|
try {
|
|
@@ -9306,7 +9434,7 @@ function docusaurusNavigationFromSnapshots(snapshots, pages, scopePath) {
|
|
|
9306
9434
|
return { tabs };
|
|
9307
9435
|
}
|
|
9308
9436
|
function htmlTopLevelNavigation(document, source, scopePath) {
|
|
9309
|
-
const $ =
|
|
9437
|
+
const $ = load3(document.body);
|
|
9310
9438
|
const collectCandidates = (selector) => {
|
|
9311
9439
|
const candidates2 = [];
|
|
9312
9440
|
$(selector).each((_containerIndex, container) => {
|
|
@@ -9367,7 +9495,7 @@ function markdownLinks(body) {
|
|
|
9367
9495
|
return [...body.matchAll(/\[[^\]]+\]\(([^)\s]+)(?:\s+['"][^'"]*['"])?\)/g)].map((match) => match[1]);
|
|
9368
9496
|
}
|
|
9369
9497
|
function sitemapLinks(body) {
|
|
9370
|
-
const $ =
|
|
9498
|
+
const $ = load3(body, { xmlMode: true });
|
|
9371
9499
|
return $("url > loc, sitemap > loc").map((_index, element) => $(element).text().trim()).get().filter(Boolean);
|
|
9372
9500
|
}
|
|
9373
9501
|
function robotsSitemaps(body) {
|
|
@@ -9406,7 +9534,7 @@ async function migrateUrl(options) {
|
|
|
9406
9534
|
const platform = options.platform ?? detectUrlPlatform(scopedHtmlProbe ?? initial);
|
|
9407
9535
|
let docusaurusHtmlProbe = platform === "docusaurus" ? scopedHtmlProbe : null;
|
|
9408
9536
|
if (docusaurusHtmlProbe && !readDocusaurusSidebar(docusaurusHtmlProbe)) {
|
|
9409
|
-
const $ =
|
|
9537
|
+
const $ = load3(docusaurusHtmlProbe.body);
|
|
9410
9538
|
const docsHref = $("nav a[href]").toArray().map((element) => ({
|
|
9411
9539
|
href: $(element).attr("href"),
|
|
9412
9540
|
label: normalizedLinkLabel($(element).text())
|
|
@@ -9856,10 +9984,10 @@ function mainSiteLinkTarget(target2, mountPath, index, unresolved) {
|
|
|
9856
9984
|
unresolved.push(target2);
|
|
9857
9985
|
return void 0;
|
|
9858
9986
|
}
|
|
9859
|
-
function prefixRootLinks(body, mountPath,
|
|
9987
|
+
function prefixRootLinks(body, mountPath, resolve5, markdown = true) {
|
|
9860
9988
|
const mounted = `/${mountPath}`;
|
|
9861
9989
|
const alreadyMounted = (target2) => target2 === mounted || ["/", "?", "#"].some((next) => target2.startsWith(mounted + next));
|
|
9862
|
-
const fix = (target2) => alreadyMounted(target2) ? target2 :
|
|
9990
|
+
const fix = (target2) => alreadyMounted(target2) ? target2 : resolve5?.(target2) ?? `${mounted}${target2}`;
|
|
9863
9991
|
return replaceOutsideCodeAndComments(body, (text3) => text3.replace(markdown ? /(\]\(<?)(\/(?!\/)[^\s)>]*)/g : /(?!)/g, (_match, before, target2) => `${before}${fix(target2)}`).replace(/(\b(?:href|src|to|poster)=(['"]))(\/(?!\/)[^'"\n]*)\2/g, (_match, before, quote, target2) => `${before}${fix(target2)}${quote}`).replace(/(\b(?:href|src|to|poster)=\{\s*(['"]))(\/(?!\/)[^'"\n]*)\2(\s*\})/g, (_match, before, quote, target2, after) => `${before}${fix(target2)}${quote}${after}`).replace(markdown ? /^(\[[^\]\n]+\]:[ \t]*<?)(\/(?!\/)\S*)/gm : /(?!)/g, (_match, before, target2) => `${before}${fix(target2)}`));
|
|
9864
9992
|
}
|
|
9865
9993
|
function prefixNavigation(entries, mountPath) {
|
|
@@ -10383,8 +10511,8 @@ var HARD_TIMEOUT_REASON = `still running after ${MAX_GIT_PROCESS_MS / 6e4} minut
|
|
|
10383
10511
|
var GIT_EXIT_DRAIN_MS = 2e3;
|
|
10384
10512
|
var RETRYABLE_CLONE_ERROR = /RPC failed|Recv failure|early EOF|curl \d+|Could not resolve host|Connection (?:reset|refused|timed out)|The remote end hung up|SSL[_ ]?(?:read|connect|write) error|timed out|network is unreachable/i;
|
|
10385
10513
|
function delay(ms) {
|
|
10386
|
-
return new Promise((
|
|
10387
|
-
setTimeout(
|
|
10514
|
+
return new Promise((resolve5) => {
|
|
10515
|
+
setTimeout(resolve5, ms);
|
|
10388
10516
|
});
|
|
10389
10517
|
}
|
|
10390
10518
|
function gitIdleTimeoutMs() {
|
|
@@ -10396,7 +10524,7 @@ function gitErrorTail(stderr) {
|
|
|
10396
10524
|
return stderr.split(/[\r\n]+/).map((line) => line.trim()).filter((line) => line && !/^(?:remote: )?[A-Za-z][A-Za-z ]*:\s+\d+%/.test(line)).slice(-5).join("\n");
|
|
10397
10525
|
}
|
|
10398
10526
|
function runGit(args, options) {
|
|
10399
|
-
return new Promise((
|
|
10527
|
+
return new Promise((resolve5, reject) => {
|
|
10400
10528
|
const child = spawn("git", args, {
|
|
10401
10529
|
stdio: ["ignore", "ignore", "pipe"],
|
|
10402
10530
|
...options.cwd ? { cwd: options.cwd } : {},
|
|
@@ -10419,7 +10547,7 @@ function runGit(args, options) {
|
|
|
10419
10547
|
settled = true;
|
|
10420
10548
|
clearTimers();
|
|
10421
10549
|
child.stderr.destroy();
|
|
10422
|
-
if (code === 0)
|
|
10550
|
+
if (code === 0) resolve5();
|
|
10423
10551
|
else if (timeoutReason) {
|
|
10424
10552
|
const hint = timeoutReason === HARD_TIMEOUT_REASON ? "" : "; on a very slow link, raise THALLY_MIGRATE_CLONE_TIMEOUT_MS (milliseconds of allowed silence)";
|
|
10425
10553
|
reject(new Error(`${options.label}: timed out (${timeoutReason}) and was killed. Check your network connection and try again${hint}.`));
|
|
@@ -14350,7 +14478,7 @@ function renderMigrationFiles(bundle, options = {}) {
|
|
|
14350
14478
|
|
|
14351
14479
|
// src/url-run.ts
|
|
14352
14480
|
import { createHash as createHash3 } from "crypto";
|
|
14353
|
-
import { load as
|
|
14481
|
+
import { load as load6 } from "cheerio";
|
|
14354
14482
|
import remarkParse4 from "remark-parse";
|
|
14355
14483
|
import remarkMdx4 from "remark-mdx";
|
|
14356
14484
|
import { unified as unified4 } from "unified";
|
|
@@ -14728,7 +14856,53 @@ function cloneUrlMigrationCheckpoint(checkpoint) {
|
|
|
14728
14856
|
}
|
|
14729
14857
|
|
|
14730
14858
|
// src/url-navigation.ts
|
|
14731
|
-
import { load as
|
|
14859
|
+
import { load as load5 } from "cheerio";
|
|
14860
|
+
|
|
14861
|
+
// src/url-scope.ts
|
|
14862
|
+
import { load as load4 } from "cheerio";
|
|
14863
|
+
function inferUrlMigrationScope(capture) {
|
|
14864
|
+
const source = capture.finalUrl;
|
|
14865
|
+
let end = source.pathname.length;
|
|
14866
|
+
while (end > 0 && source.pathname.charCodeAt(end - 1) === 47) end--;
|
|
14867
|
+
const parent = end < source.pathname.length ? source.pathname.slice(0, end) || "/" : source.pathname.slice(0, source.pathname.lastIndexOf("/")) || "/";
|
|
14868
|
+
if (!/html/i.test(capture.contentType) || Buffer.byteLength(capture.body) > 8e6) return { scopePath: parent, evidence: "source-parent" };
|
|
14869
|
+
const $ = load4(capture.body);
|
|
14870
|
+
const ancestor = (path) => path === "/" || source.pathname === path || source.pathname.startsWith(`${path}/`);
|
|
14871
|
+
const observed = (reference) => {
|
|
14872
|
+
if (!reference || reference.length > 8192) return void 0;
|
|
14873
|
+
try {
|
|
14874
|
+
const url = new URL(reference, source);
|
|
14875
|
+
if (url.origin !== source.origin || url.username || url.password || url.search || url.hash || /%2f|%5c/i.test(url.pathname)) return void 0;
|
|
14876
|
+
return url;
|
|
14877
|
+
} catch {
|
|
14878
|
+
return void 0;
|
|
14879
|
+
}
|
|
14880
|
+
};
|
|
14881
|
+
const indexes = [];
|
|
14882
|
+
$("link[href],a[href]").slice(0, 1e4).each((_, node) => {
|
|
14883
|
+
const url = observed($(node).attr("href"));
|
|
14884
|
+
if (!url || !/\/(?:llms(?:-full)?\.txt|sitemap(?:[-_][^/]*)?\.xml)$/i.test(url.pathname)) return;
|
|
14885
|
+
const path = url.pathname.slice(0, url.pathname.lastIndexOf("/")) || "/";
|
|
14886
|
+
if (ancestor(path)) indexes.push(path);
|
|
14887
|
+
});
|
|
14888
|
+
if (indexes.length) return { scopePath: indexes.sort((a, b) => b.length - a.length)[0], evidence: "discovery-index" };
|
|
14889
|
+
const paths = [];
|
|
14890
|
+
$('nav a[href],aside a[href],[role="navigation"] a[href]').slice(0, 1e4).each((_, node) => {
|
|
14891
|
+
if ($(node).closest("header,footer").length) return;
|
|
14892
|
+
const url = observed($(node).attr("href"));
|
|
14893
|
+
if (url && !/\.[a-z0-9]+$/i.test(url.pathname)) paths.push(url.pathname);
|
|
14894
|
+
});
|
|
14895
|
+
if (new Set(paths).size >= 2 && paths.some((path) => path === source.pathname)) {
|
|
14896
|
+
const segments = paths.map((path) => path.split("/").filter(Boolean));
|
|
14897
|
+
let count = 0;
|
|
14898
|
+
while (segments.every((parts) => parts[count] !== void 0 && parts[count] === segments[0][count])) count++;
|
|
14899
|
+
const common = "/" + segments[0].slice(0, count).join("/");
|
|
14900
|
+
if (ancestor(common)) return { scopePath: common, evidence: "navigation" };
|
|
14901
|
+
}
|
|
14902
|
+
return { scopePath: parent, evidence: "source-parent" };
|
|
14903
|
+
}
|
|
14904
|
+
|
|
14905
|
+
// src/url-navigation.ts
|
|
14732
14906
|
var MAX_CAPTURE_BYTES = 8e6;
|
|
14733
14907
|
var MAX_JSON_BYTES = 2e6;
|
|
14734
14908
|
var MAX_NODES = 1e4;
|
|
@@ -14795,8 +14969,18 @@ function flightRecords(stream) {
|
|
|
14795
14969
|
}
|
|
14796
14970
|
return records;
|
|
14797
14971
|
}
|
|
14798
|
-
function mintlifyNavigation(body, base, locale) {
|
|
14799
|
-
const $ =
|
|
14972
|
+
function mintlifyNavigation(body, base, locale, selectedScope) {
|
|
14973
|
+
const $ = load5(body);
|
|
14974
|
+
const scope = inferUrlMigrationScope({ body, contentType: "text/html", finalUrl: base });
|
|
14975
|
+
const mount = scope.evidence === "source-parent" ? selectedScope ?? "/" : scope.scopePath;
|
|
14976
|
+
const configTarget = (value) => {
|
|
14977
|
+
const reference = text2(value);
|
|
14978
|
+
if (!reference) return void 0;
|
|
14979
|
+
if (/^(?:[a-z][a-z0-9+.-]*:|\/\/)/i.test(reference)) return target(reference, base);
|
|
14980
|
+
const path = reference.replace(/^\/+/, "");
|
|
14981
|
+
const prefix = mount.replace(/^\/|\/$/g, "");
|
|
14982
|
+
return target(prefix && path !== prefix && !path.startsWith(`${prefix}/`) ? `${prefix}/${path}` : path, new URL("/", base));
|
|
14983
|
+
};
|
|
14800
14984
|
let stream = "";
|
|
14801
14985
|
const records = [];
|
|
14802
14986
|
$("script").each((_index, script) => {
|
|
@@ -14833,7 +15017,7 @@ function mintlifyNavigation(body, base, locale) {
|
|
|
14833
15017
|
const walk2 = (value, depth = 0, activeLocale) => {
|
|
14834
15018
|
if (depth > MAX_DEPTH || ++count > MAX_NODES) throw new Error("Source navigation exceeds its safety bound.");
|
|
14835
15019
|
if (typeof value === "string") {
|
|
14836
|
-
const url2 =
|
|
15020
|
+
const url2 = configTarget(value);
|
|
14837
15021
|
return url2 ? [{ kind: "page", label: value, url: url2 }] : [];
|
|
14838
15022
|
}
|
|
14839
15023
|
if (Array.isArray(value)) return value.flatMap((child) => walk2(child, depth + 1, activeLocale));
|
|
@@ -14853,7 +15037,7 @@ function mintlifyNavigation(body, base, locale) {
|
|
|
14853
15037
|
return;
|
|
14854
15038
|
}
|
|
14855
15039
|
if (!object(node)) return;
|
|
14856
|
-
const href =
|
|
15040
|
+
const href = configTarget(node.href);
|
|
14857
15041
|
if (href) {
|
|
14858
15042
|
populated++;
|
|
14859
15043
|
const url2 = new URL(href);
|
|
@@ -14871,10 +15055,10 @@ function mintlifyNavigation(body, base, locale) {
|
|
|
14871
15055
|
const selected = matching[0]?.item ?? languages.find((item) => text2(item.language)?.toLowerCase() === language?.toLowerCase()) ?? languages.find((item) => text2(item.language)?.toLowerCase() === "en") ?? languages[0];
|
|
14872
15056
|
return selected ? walk2({ ...selected, languages: void 0 }, depth + 1, text2(selected.language)) : [];
|
|
14873
15057
|
}
|
|
14874
|
-
const label = text2(value.tab) ?? text2(value.group) ?? text2(value.title) ?? text2(value.label);
|
|
14875
|
-
const kind = text2(value.tab) ? "tab" : text2(value.group) ? "group" : "page";
|
|
15058
|
+
const label = text2(value.tab) ?? text2(value.dropdown) ?? text2(value.group) ?? text2(value.sidebarTitle) ?? text2(value.title) ?? text2(value.label);
|
|
15059
|
+
const kind = text2(value.tab) || text2(value.dropdown) ? "tab" : text2(value.group) ? "group" : "page";
|
|
14876
15060
|
const children = ["tabs", "groups", "pages", "dropdowns", "anchors", "versions"].flatMap((key) => Array.isArray(value[key]) ? walk2(value[key], depth + 1, activeLocale) : []);
|
|
14877
|
-
const url =
|
|
15061
|
+
const url = configTarget(value.href);
|
|
14878
15062
|
if (!label) return children;
|
|
14879
15063
|
if (!url && !children.length) return [];
|
|
14880
15064
|
return [{
|
|
@@ -14882,6 +15066,7 @@ function mintlifyNavigation(body, base, locale) {
|
|
|
14882
15066
|
label,
|
|
14883
15067
|
...url ? { url } : {},
|
|
14884
15068
|
...children.length ? { children } : {},
|
|
15069
|
+
...text2(value.dropdown) ? { presentation: "dropdown" } : {},
|
|
14885
15070
|
...kind === "tab" && activeLocale ? { locale: activeLocale } : {}
|
|
14886
15071
|
}];
|
|
14887
15072
|
};
|
|
@@ -14908,18 +15093,19 @@ function resolveNavigation(nodes, base) {
|
|
|
14908
15093
|
...url ? { url } : {},
|
|
14909
15094
|
...children.length ? { children } : {},
|
|
14910
15095
|
...["tab", "group", "page"].includes(node.kind ?? "") ? { kind: node.kind } : {},
|
|
15096
|
+
...node.presentation === "dropdown" ? { presentation: "dropdown" } : {},
|
|
14911
15097
|
...text2(node.locale) ? { locale: text2(node.locale) } : {}
|
|
14912
15098
|
}];
|
|
14913
15099
|
});
|
|
14914
15100
|
};
|
|
14915
15101
|
return walk2(nodes);
|
|
14916
15102
|
}
|
|
14917
|
-
function extractSourceNavigation(capture) {
|
|
15103
|
+
function extractSourceNavigation(capture, selectedScope) {
|
|
14918
15104
|
if (capture.navigation) return resolveNavigation(capture.navigation, capture.finalUrl);
|
|
14919
15105
|
if (!/html/i.test(capture.contentType) || Buffer.byteLength(capture.body) > MAX_CAPTURE_BYTES) return [];
|
|
14920
|
-
const mintlify = mintlifyNavigation(capture.body, capture.finalUrl, capture.locale);
|
|
15106
|
+
const mintlify = mintlifyNavigation(capture.body, capture.finalUrl, capture.locale, selectedScope);
|
|
14921
15107
|
if (mintlify.length) return mintlify;
|
|
14922
|
-
const $ =
|
|
15108
|
+
const $ = load5(capture.body);
|
|
14923
15109
|
const candidates = ['.theme-doc-sidebar-menu,[aria-label*="sidebar" i]', "aside", '[role="navigation"],nav'];
|
|
14924
15110
|
const root = candidates.map((selector) => $(selector).filter((_index, node) => $(node).find("a[href]").length > 0 && $(node).closest("header").length === 0).first()).find((candidate) => candidate.length);
|
|
14925
15111
|
if (!root) return [];
|
|
@@ -14995,8 +15181,127 @@ function mergeSourceNavigation(existing, incoming) {
|
|
|
14995
15181
|
return merge(existing, incoming);
|
|
14996
15182
|
}
|
|
14997
15183
|
|
|
15184
|
+
// src/url-api-schema-controls.ts
|
|
15185
|
+
var MAX_CAPTURE_BYTES2 = 8e6;
|
|
15186
|
+
var MAX_TAB_GROUPS = 256;
|
|
15187
|
+
var MAX_TABS = 1024;
|
|
15188
|
+
function object2(value) {
|
|
15189
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
15190
|
+
}
|
|
15191
|
+
function localReference2(document, reference) {
|
|
15192
|
+
if (typeof reference !== "string" || !reference.startsWith("#/")) return void 0;
|
|
15193
|
+
let target2 = document;
|
|
15194
|
+
try {
|
|
15195
|
+
for (const part of reference.slice(2).split("/")) {
|
|
15196
|
+
const key = decodeURIComponent(part).replace(/~1/g, "/").replace(/~0/g, "~");
|
|
15197
|
+
if (!target2 || typeof target2 !== "object" || !Object.hasOwn(target2, key)) return void 0;
|
|
15198
|
+
target2 = target2[key];
|
|
15199
|
+
}
|
|
15200
|
+
} catch {
|
|
15201
|
+
return void 0;
|
|
15202
|
+
}
|
|
15203
|
+
return target2;
|
|
15204
|
+
}
|
|
15205
|
+
function resolve4(document, value) {
|
|
15206
|
+
const seen = /* @__PURE__ */ new Set();
|
|
15207
|
+
for (let depth = 0; depth < 32; depth += 1) {
|
|
15208
|
+
const schema = object2(value);
|
|
15209
|
+
if (!schema || seen.has(schema)) return void 0;
|
|
15210
|
+
seen.add(schema);
|
|
15211
|
+
if (!Object.hasOwn(schema, "$ref")) return schema;
|
|
15212
|
+
value = localReference2(document, schema.$ref);
|
|
15213
|
+
}
|
|
15214
|
+
return void 0;
|
|
15215
|
+
}
|
|
15216
|
+
function complete(document) {
|
|
15217
|
+
let visited = 0;
|
|
15218
|
+
const active = /* @__PURE__ */ new Set();
|
|
15219
|
+
const visit = (value, depth) => {
|
|
15220
|
+
if (++visited > 1e5 || depth > 96) return false;
|
|
15221
|
+
if (typeof value === "number" && !Number.isFinite(value)) return false;
|
|
15222
|
+
if (!value || typeof value !== "object") return true;
|
|
15223
|
+
if (active.has(value)) return false;
|
|
15224
|
+
active.add(value);
|
|
15225
|
+
const schema = object2(value);
|
|
15226
|
+
const valid = (!schema || !Object.hasOwn(schema, "$ref") || Boolean(object2(localReference2(document, schema.$ref)))) && Object.values(value).every((child) => visit(child, depth + 1));
|
|
15227
|
+
active.delete(value);
|
|
15228
|
+
return valid;
|
|
15229
|
+
};
|
|
15230
|
+
return visit(document, 0);
|
|
15231
|
+
}
|
|
15232
|
+
function labels(document, value) {
|
|
15233
|
+
const schema = resolve4(document, value);
|
|
15234
|
+
if (!Array.isArray(schema?.oneOf) || schema.oneOf.length < 2 || schema.oneOf.length > 64) return void 0;
|
|
15235
|
+
const result = [];
|
|
15236
|
+
for (const [index, branch] of schema.oneOf.entries()) {
|
|
15237
|
+
const target2 = resolve4(document, branch);
|
|
15238
|
+
if (!target2) return void 0;
|
|
15239
|
+
const title = object2(branch)?.title ?? target2.title;
|
|
15240
|
+
result.push(typeof title === "string" && title.trim() ? title.trim().replace(/\s+/g, " ") : `Option ${index + 1}`);
|
|
15241
|
+
}
|
|
15242
|
+
return new Set(result).size === result.length ? result : void 0;
|
|
15243
|
+
}
|
|
15244
|
+
function apiSchemaTabGroups(body, document, operation) {
|
|
15245
|
+
if (Buffer.byteLength(body) > MAX_CAPTURE_BYTES2 || !complete(document)) return [];
|
|
15246
|
+
const path = object2(document.paths)?.[operation.path];
|
|
15247
|
+
const method = operation.method.toLowerCase();
|
|
15248
|
+
if (!/^(?:get|post|put|patch|delete|head|options|trace)$/.test(method)) return [];
|
|
15249
|
+
const selected = object2(object2(path)?.[method]);
|
|
15250
|
+
if (!selected) return [];
|
|
15251
|
+
const { $, root } = migrationHtmlArticle(body);
|
|
15252
|
+
const groups = root.find('[role="tablist"],[data-component-part="tabs-list"]');
|
|
15253
|
+
if (groups.length > MAX_TAB_GROUPS || root.find('[role="tab"]').length > MAX_TABS) return [];
|
|
15254
|
+
const idCounts = /* @__PURE__ */ new Map();
|
|
15255
|
+
root.find("[id]").each((_index, node) => {
|
|
15256
|
+
const id = $(node).attr("id");
|
|
15257
|
+
idCounts.set(id, (idCounts.get(id) ?? 0) + 1);
|
|
15258
|
+
});
|
|
15259
|
+
const proofs = [];
|
|
15260
|
+
groups.each((index, node) => {
|
|
15261
|
+
const group = $(node);
|
|
15262
|
+
const container = group.parent(".tabs.tab-container");
|
|
15263
|
+
const field = group.closest(".object-param-field");
|
|
15264
|
+
const section = field.parent(".api-section");
|
|
15265
|
+
if (!group.is('[role="tablist"][data-component-part="tabs-list"]') || !container.length || !section.length || !section.closest('[id^="api-playground-"][id$="-operation-page"]').length) return;
|
|
15266
|
+
if (field.parents(".object-param-field").length) return;
|
|
15267
|
+
const heading = section.children(".api-section-heading");
|
|
15268
|
+
const title = heading.find(".api-section-heading-title").text().trim().toLowerCase();
|
|
15269
|
+
const media = heading.find("*").toArray().filter((element) => $(element).children().length === 0).map((element) => $(element).text().trim()).filter((text3) => /^[a-z][a-z\d.+-]*\/[a-z\d.+-]+$/i.test(text3));
|
|
15270
|
+
if (heading.length !== 1 || !media || media.length !== 1) return;
|
|
15271
|
+
let schema;
|
|
15272
|
+
let scope;
|
|
15273
|
+
if (title === "body") {
|
|
15274
|
+
const request2 = resolve4(document, selected.requestBody);
|
|
15275
|
+
schema = object2(object2(request2?.content)?.[media[0]])?.schema;
|
|
15276
|
+
scope = `request:${media[0]}`;
|
|
15277
|
+
} else if (title === "response") {
|
|
15278
|
+
const statuses = heading.find('button[aria-haspopup="menu"]').toArray().map((button) => $(button).text().trim()).filter((text3) => /^(?:[1-5]\d{2}|default)$/.test(text3));
|
|
15279
|
+
if (statuses.length !== 1) return;
|
|
15280
|
+
const response = resolve4(document, object2(selected.responses)?.[statuses[0]]);
|
|
15281
|
+
schema = object2(object2(response?.content)?.[media[0]])?.schema;
|
|
15282
|
+
scope = `response:${statuses[0]}:${media[0]}`;
|
|
15283
|
+
} else return;
|
|
15284
|
+
const expected = labels(document, schema);
|
|
15285
|
+
const tabs = group.children('[role="tab"][data-component-part="tab"]');
|
|
15286
|
+
if (!expected || tabs.length !== expected.length || group.children().length !== tabs.length) return;
|
|
15287
|
+
const panels = container.children('[data-component-part="tabs-panels"]').children('[role="tabpanel"][data-component-part="tab-content"]');
|
|
15288
|
+
if (panels.length !== tabs.length) return;
|
|
15289
|
+
const ids = /* @__PURE__ */ new Set();
|
|
15290
|
+
for (const [position, tab] of tabs.toArray().entries()) {
|
|
15291
|
+
const control = $(tab).attr("aria-controls");
|
|
15292
|
+
const panel = panels.eq(position);
|
|
15293
|
+
if ($(tab).text().trim().replace(/\s+/g, " ") !== expected[position] || !control || ids.has(control) || panel.attr("id") !== control || !$(tab).attr("id") || panel.attr("aria-labelledby") !== $(tab).attr("id") || idCounts.get(control) !== 1 || panel.text().trim() || panel.children().length) return;
|
|
15294
|
+
ids.add(control);
|
|
15295
|
+
}
|
|
15296
|
+
proofs.push({ index, scope });
|
|
15297
|
+
});
|
|
15298
|
+
const scopeCounts = /* @__PURE__ */ new Map();
|
|
15299
|
+
for (const proof of proofs) scopeCounts.set(proof.scope, (scopeCounts.get(proof.scope) ?? 0) + 1);
|
|
15300
|
+
return proofs.filter((proof) => scopeCounts.get(proof.scope) === 1).map((proof) => proof.index);
|
|
15301
|
+
}
|
|
15302
|
+
|
|
14998
15303
|
// src/url-run.ts
|
|
14999
|
-
var CONVERTER_VERSION = "url-evidence-
|
|
15304
|
+
var CONVERTER_VERSION = "url-evidence-v5";
|
|
15000
15305
|
var parser2 = unified4().use(remarkParse4).use(remarkMdx4);
|
|
15001
15306
|
var ACCEPT = "text/markdown,text/html,application/xhtml+xml;q=0.9";
|
|
15002
15307
|
var MAX_RESPONSE_BYTES = 8e6;
|
|
@@ -15059,7 +15364,7 @@ function linksOf(document) {
|
|
|
15059
15364
|
return [...root.find("a[href]").toArray(), ...$('link[rel="sitemap"][href],link[rel="alternate"][href]').toArray()].map((node) => $(node).attr("href")).filter(Boolean);
|
|
15060
15365
|
}
|
|
15061
15366
|
if (/xml/i.test(document.contentType) || /<urlset|<sitemapindex/i.test(document.body)) {
|
|
15062
|
-
const $ =
|
|
15367
|
+
const $ = load6(document.body, { xmlMode: true });
|
|
15063
15368
|
return $("loc").toArray().map((node) => $(node).text().trim());
|
|
15064
15369
|
}
|
|
15065
15370
|
return [
|
|
@@ -15102,8 +15407,8 @@ function markdownHeadingAnchors(body) {
|
|
|
15102
15407
|
return occurrence ? `${base}-${occurrence}` : base;
|
|
15103
15408
|
});
|
|
15104
15409
|
}
|
|
15105
|
-
function sourceNavigation(capture) {
|
|
15106
|
-
return extractSourceNavigation(capture);
|
|
15410
|
+
function sourceNavigation(capture, selectedScope) {
|
|
15411
|
+
return extractSourceNavigation(capture, selectedScope);
|
|
15107
15412
|
}
|
|
15108
15413
|
function idForUrl(url, scope) {
|
|
15109
15414
|
const relative7 = scope === "/" ? url.pathname.slice(1) : url.pathname.slice(scope.length).replace(/^\//, "");
|
|
@@ -15112,7 +15417,7 @@ function idForUrl(url, scope) {
|
|
|
15112
15417
|
}
|
|
15113
15418
|
function articleIdentity(document) {
|
|
15114
15419
|
if (!/html/i.test(document.contentType)) return document.finalUrl;
|
|
15115
|
-
const $ =
|
|
15420
|
+
const $ = load6(document.body);
|
|
15116
15421
|
const reference = $('link[rel="canonical"][href]').first().attr("href");
|
|
15117
15422
|
if (!reference) return document.finalUrl;
|
|
15118
15423
|
try {
|
|
@@ -15168,16 +15473,24 @@ function assetReferences(capture) {
|
|
|
15168
15473
|
}
|
|
15169
15474
|
const { $, root } = migrationHtmlArticle(capture.body);
|
|
15170
15475
|
return [
|
|
15171
|
-
...root.find("img[src],video[poster],a[download][href]").toArray().map((node) => $(node).
|
|
15476
|
+
...root.find("img[src],video[poster],a[download][href]").toArray().map((node) => $(node).is("video") ? $(node).attr("poster") : $(node).is("a") ? $(node).attr("href") : $(node).attr("src")),
|
|
15172
15477
|
...root.find("[srcset]").toArray().flatMap((node) => migrationImageCandidates($(node).attr("srcset") ?? "", capture.finalUrl).map((candidate) => candidate.url))
|
|
15173
15478
|
].filter(Boolean);
|
|
15174
15479
|
}
|
|
15175
|
-
function unresolvedStaticControls(body, hasApiSchema = false) {
|
|
15480
|
+
function unresolvedStaticControls(body, hasApiSchema = false, coveredSchemaGroups = []) {
|
|
15176
15481
|
const { $, root } = migrationHtmlArticle(body);
|
|
15482
|
+
root.find('[role="tablist"],[data-component-part="tabs-list"]').each((index, node) => {
|
|
15483
|
+
if (coveredSchemaGroups.includes(index)) $(node).remove();
|
|
15484
|
+
});
|
|
15177
15485
|
const tabs = root.find('[role="tab"]').toArray();
|
|
15178
15486
|
for (const tab of tabs) {
|
|
15179
15487
|
const controls = $(tab).attr("aria-controls");
|
|
15180
|
-
const
|
|
15488
|
+
const group = $(tab).closest('[role="tablist"]');
|
|
15489
|
+
const container = group.closest(".code-group,.tabs-container,.tabs.tab-container");
|
|
15490
|
+
const peers = group.find('[role="tab"]').toArray().filter((node) => $(node).closest('[role="tablist"]')[0] === group[0]);
|
|
15491
|
+
const localPanels = container.find('[role="tabpanel"]').toArray().filter((node) => $(node).closest(".code-group,.tabs-container,.tabs.tab-container")[0] === container[0]);
|
|
15492
|
+
const owners = container.find('[role="tablist"]').toArray().filter((node) => $(node).closest(".code-group,.tabs-container,.tabs.tab-container")[0] === container[0]);
|
|
15493
|
+
const panels = controls ? root.find("[id]").filter((_index, node) => $(node).attr("id") === controls) : owners.length === 1 && peers.length === localPanels.length ? $(localPanels).eq(peers.indexOf(tab)) : $([]);
|
|
15181
15494
|
if (panels.length !== 1 || !panels.text().trim() && !panels.find("pre,img,table,svg").length || panels.find('[aria-busy="true"],[role="progressbar"]').length) return true;
|
|
15182
15495
|
}
|
|
15183
15496
|
return root.find("details:not([open])").toArray().some((node) => {
|
|
@@ -15228,12 +15541,12 @@ function hasCompleteLocalApiSchema(document) {
|
|
|
15228
15541
|
if (typeof value === "number" && !Number.isFinite(value)) return false;
|
|
15229
15542
|
if (!value || typeof value !== "object") return true;
|
|
15230
15543
|
if (Array.isArray(value)) return value.every((child) => visit(child, depth + 1));
|
|
15231
|
-
const
|
|
15232
|
-
if (Object.prototype.hasOwnProperty.call(
|
|
15233
|
-
if (typeof
|
|
15544
|
+
const object3 = value;
|
|
15545
|
+
if (Object.prototype.hasOwnProperty.call(object3, "$ref")) {
|
|
15546
|
+
if (typeof object3.$ref !== "string" || !object3.$ref.startsWith("#/")) return false;
|
|
15234
15547
|
let target2 = document;
|
|
15235
15548
|
try {
|
|
15236
|
-
for (const encoded of
|
|
15549
|
+
for (const encoded of object3.$ref.slice(2).split("/")) {
|
|
15237
15550
|
const key = decodeURIComponent(encoded).replace(/~1/g, "/").replace(/~0/g, "~");
|
|
15238
15551
|
if (!target2 || typeof target2 !== "object" || !Object.prototype.hasOwnProperty.call(target2, key)) return false;
|
|
15239
15552
|
target2 = target2[key];
|
|
@@ -15242,7 +15555,7 @@ function hasCompleteLocalApiSchema(document) {
|
|
|
15242
15555
|
return false;
|
|
15243
15556
|
}
|
|
15244
15557
|
}
|
|
15245
|
-
return Object.values(
|
|
15558
|
+
return Object.values(object3).every((child) => visit(child, depth + 1));
|
|
15246
15559
|
};
|
|
15247
15560
|
return visit(document);
|
|
15248
15561
|
}
|
|
@@ -15257,6 +15570,25 @@ function resolveMigrationRecord(records, record) {
|
|
|
15257
15570
|
}
|
|
15258
15571
|
function navigationConfig(checkpoint, records) {
|
|
15259
15572
|
const navigation = checkpoint.navigation;
|
|
15573
|
+
const shortcuts = [];
|
|
15574
|
+
const collectShortcuts = (nodes) => {
|
|
15575
|
+
for (const node of nodes) {
|
|
15576
|
+
if (node.url) {
|
|
15577
|
+
const record = records.get(canonical(node.url, checkpoint.sourceUrl) ?? "");
|
|
15578
|
+
const href = record?.redirectTo ?? node.url;
|
|
15579
|
+
const identity = canonical(href, checkpoint.sourceUrl);
|
|
15580
|
+
const target2 = identity ? new URL(href, checkpoint.sourceUrl).href : null;
|
|
15581
|
+
if (target2 && !inScope(new URL(target2), new URL(checkpoint.sourceUrl), checkpoint.scopePath) && !shortcuts.some((link) => link.label === node.label && link.href === target2)) shortcuts.push({ label: node.label, href: target2 });
|
|
15582
|
+
}
|
|
15583
|
+
collectShortcuts(node.children ?? []);
|
|
15584
|
+
}
|
|
15585
|
+
};
|
|
15586
|
+
collectShortcuts(navigation);
|
|
15587
|
+
const hasDropdown = navigation.some((node) => node.presentation === "dropdown");
|
|
15588
|
+
const externalNavigation = shortcuts.length || hasDropdown ? { navigation: {
|
|
15589
|
+
...shortcuts.length ? { shortcuts } : {},
|
|
15590
|
+
...hasDropdown ? { display: "dropdown" } : {}
|
|
15591
|
+
} } : {};
|
|
15260
15592
|
const projection = localeProjection(checkpoint);
|
|
15261
15593
|
const project2 = (nodes) => nodes.flatMap((node) => {
|
|
15262
15594
|
const record = node.url ? records.get(canonical(node.url, node.url) ?? "") : void 0;
|
|
@@ -15277,7 +15609,7 @@ function navigationConfig(checkpoint, records) {
|
|
|
15277
15609
|
return pages2.length || tab.url ? [{ tab: tab.label, ...pages2.length ? { pages: pages2 } : {}, ...tab.url ? { href: tab.url } : {} }] : [];
|
|
15278
15610
|
});
|
|
15279
15611
|
const primary = localizedTabs(projection.defaultLocale);
|
|
15280
|
-
return { tabs: primary.length ? primary : localizedTabs(locales[0]), ...locales.length > 1 ? {
|
|
15612
|
+
return { ...externalNavigation, tabs: primary.length ? primary : localizedTabs(locales[0]), ...locales.length > 1 ? {
|
|
15281
15613
|
i18n: {
|
|
15282
15614
|
defaultLocale: projection.defaultLocale,
|
|
15283
15615
|
locales: locales.map((code) => ({ code, label: code === "en" ? "English" : code })),
|
|
@@ -15286,7 +15618,7 @@ function navigationConfig(checkpoint, records) {
|
|
|
15286
15618
|
} : {} };
|
|
15287
15619
|
}
|
|
15288
15620
|
const pages = project2(navigation);
|
|
15289
|
-
return pages.length ? { tabs: [{ tab: "Documentation", pages }] } : null;
|
|
15621
|
+
return pages.length || shortcuts.length ? { ...externalNavigation, tabs: [{ tab: "Documentation", pages }] } : null;
|
|
15290
15622
|
}
|
|
15291
15623
|
function canonicalLanguage(value) {
|
|
15292
15624
|
if (!/^[a-z]{2,3}(?:-[a-z0-9]{2,8}){0,4}$/i.test(value)) return void 0;
|
|
@@ -15306,7 +15638,7 @@ function observedLocale(document, id, scopePath) {
|
|
|
15306
15638
|
}
|
|
15307
15639
|
const urlLocale = [id.split("/", 1)[0], ...scopePath.split("/"), document.finalUrl.pathname.split("/").filter(Boolean)[0]].find((segment) => segment && LOCALES.has(segment.toLowerCase()));
|
|
15308
15640
|
if (urlLocale) candidates.push({ source: "URL", value: canonicalLanguage(urlLocale) });
|
|
15309
|
-
const declared = /html/i.test(document.contentType) ?
|
|
15641
|
+
const declared = /html/i.test(document.contentType) ? load6(document.body)("html").attr("lang")?.trim() : void 0;
|
|
15310
15642
|
if (declared) {
|
|
15311
15643
|
const locale = canonicalLanguage(declared);
|
|
15312
15644
|
if (locale) candidates.push({ source: "html lang", value: locale });
|
|
@@ -15383,13 +15715,15 @@ function validateUrlMigration(checkpoint, cancelled = false) {
|
|
|
15383
15715
|
const projection = localeProjection(checkpoint);
|
|
15384
15716
|
const primaryIds = new Set(checkpoint.records.flatMap((record) => record.page && (!projection.canonicalLocale(record.page) || projection.canonicalLocale(record.page) === projection.defaultLocale) ? [projection.navigationId(record.page)] : []));
|
|
15385
15717
|
const outputIds = /* @__PURE__ */ new Set();
|
|
15386
|
-
const
|
|
15718
|
+
const resolve5 = (url) => {
|
|
15387
15719
|
const record = records.get(canonical(url, checkpoint.sourceUrl) ?? "");
|
|
15388
15720
|
return resolveMigrationRecord(records, record);
|
|
15389
15721
|
};
|
|
15390
15722
|
for (const record of checkpoint.records) {
|
|
15391
15723
|
counts[record.outcome]++;
|
|
15392
15724
|
issues.push(...record.issues ?? []);
|
|
15725
|
+
warnings.push(...record.warnings ?? []);
|
|
15726
|
+
if (record.outcome === "alias" && !resolveMigrationRecord(records, record)?.page) issues.push({ code: "missing-page", source: record.url, message: "An alias does not resolve to an imported source page." });
|
|
15393
15727
|
if (record.outcome === "pending" || record.outcome === "failed") issues.push({ code: "missing-page", source: record.url, message: record.reason ?? `Inventory entry is ${record.outcome}.` });
|
|
15394
15728
|
if (!record.page || !record.evidence) continue;
|
|
15395
15729
|
const outputId = projection.pageId(record.page);
|
|
@@ -15408,8 +15742,9 @@ function validateUrlMigration(checkpoint, cancelled = false) {
|
|
|
15408
15742
|
continue;
|
|
15409
15743
|
}
|
|
15410
15744
|
if (!inScope(link, source, checkpoint.scopePath)) continue;
|
|
15745
|
+
if (isDiscoveryIndex(link, source)) continue;
|
|
15411
15746
|
if (/\.(?:png|jpe?g|gif|svg|webp|avif|pdf|zip|mp4|webm|css|js|json|ya?ml)$/i.test(link.pathname)) continue;
|
|
15412
|
-
const destination =
|
|
15747
|
+
const destination = resolve5(link.toString());
|
|
15413
15748
|
if (!destination || !["imported", "excluded"].includes(destination.outcome)) {
|
|
15414
15749
|
issues.push({ code: "missing-page", source: record.url, message: `Unresolved internal destination: ${link}` });
|
|
15415
15750
|
} else if (link.hash && destination.outcome === "imported") {
|
|
@@ -15436,7 +15771,9 @@ function validateUrlMigration(checkpoint, cancelled = false) {
|
|
|
15436
15771
|
if (node.url) {
|
|
15437
15772
|
const url = new URL(node.url, source);
|
|
15438
15773
|
if (inScope(url, source, checkpoint.scopePath)) {
|
|
15439
|
-
const
|
|
15774
|
+
const destination = resolve5(url.toString());
|
|
15775
|
+
if (destination?.outcome === "excluded" && destination.redirectTo) continue;
|
|
15776
|
+
const page = destination?.page;
|
|
15440
15777
|
if (!page) issues.push({ code: "navigation-missing", source: node.url, message: `Source navigation target ${node.label} was not imported.` });
|
|
15441
15778
|
else if (locale && locale !== projection.defaultLocale && !outputIds.has(`${locale}/${projection.navigationId(page)}`)) {
|
|
15442
15779
|
issues.push({ code: "navigation-missing", source: node.url, message: `The ${locale} sidebar target ${node.label} has no authored localized runtime page.` });
|
|
@@ -15453,16 +15790,32 @@ function validateUrlMigration(checkpoint, cancelled = false) {
|
|
|
15453
15790
|
async function runUrlMigration(options) {
|
|
15454
15791
|
const source = validateMigrationUrl(options.sourceUrl);
|
|
15455
15792
|
const sourceUrl = canonical(source.toString(), source.toString());
|
|
15456
|
-
const requestedScope = options.scopePath ?? (source.pathname.endsWith("/") ? source.pathname : source.pathname.slice(0, source.pathname.lastIndexOf("/")) || "/");
|
|
15457
|
-
let scopeEnd = requestedScope.length;
|
|
15458
|
-
while (scopeEnd > 0 && requestedScope.charCodeAt(scopeEnd - 1) === 47) scopeEnd--;
|
|
15459
|
-
const scopePath = requestedScope.slice(0, scopeEnd) || "/";
|
|
15460
|
-
if (!scopePath.startsWith("/") || scopePath.includes("?") || scopePath.includes("#") || !inScope(source, source, scopePath)) throw new Error("The selected documentation scope must contain the source URL.");
|
|
15461
15793
|
const maxPages = options.maxPages ?? 1e3;
|
|
15462
15794
|
if (!Number.isInteger(maxPages) || maxPages < 1 || maxPages > 1e4) throw new Error("maxPages must be between 1 and 10000.");
|
|
15463
15795
|
const concurrency = Math.max(1, Math.min(32, Math.floor(options.concurrency ?? 5)));
|
|
15464
15796
|
const batchSize = Math.max(1, Math.min(500, Math.floor(options.batchSize ?? 50)));
|
|
15465
15797
|
if (!Number.isFinite(concurrency) || !Number.isFinite(batchSize) || options.maxCaptures !== void 0 && (!Number.isInteger(options.maxCaptures) || options.maxCaptures < 1) || options.maxTotalBytes !== void 0 && (!Number.isFinite(options.maxTotalBytes) || options.maxTotalBytes < 1)) throw new Error("Migration batch, concurrency and byte limits must be positive finite numbers.");
|
|
15798
|
+
const fetcher = options.fetcher ?? defaultMigrationFetcher;
|
|
15799
|
+
const acquire = options.captureProvider?.capture.bind(options.captureProvider) ?? (async ({ url }) => fetcher(url, { accept: ACCEPT }));
|
|
15800
|
+
let initial;
|
|
15801
|
+
let inferredScope;
|
|
15802
|
+
if (options.scopePath === void 0 && !options.checkpoint && !options.signal?.aborted) {
|
|
15803
|
+
initial = Promise.resolve().then(() => acquire({ url: source, signal: options.signal }));
|
|
15804
|
+
try {
|
|
15805
|
+
const document = await initial;
|
|
15806
|
+
if (document.finalUrl.origin === source.origin) {
|
|
15807
|
+
const inferred = inferUrlMigrationScope(document).scopePath;
|
|
15808
|
+
if (inScope(source, source, inferred)) inferredScope = inferred;
|
|
15809
|
+
}
|
|
15810
|
+
} catch {
|
|
15811
|
+
}
|
|
15812
|
+
}
|
|
15813
|
+
const capture = (request2) => initial && canonical(request2.url.href, sourceUrl) === sourceUrl ? initial : acquire(request2);
|
|
15814
|
+
const requestedScope = options.scopePath ?? options.checkpoint?.scopePath ?? inferredScope ?? (source.pathname.endsWith("/") ? source.pathname : source.pathname.slice(0, source.pathname.lastIndexOf("/")) || "/");
|
|
15815
|
+
let scopeEnd = requestedScope.length;
|
|
15816
|
+
while (scopeEnd > 0 && requestedScope.charCodeAt(scopeEnd - 1) === 47) scopeEnd--;
|
|
15817
|
+
const scopePath = requestedScope.slice(0, scopeEnd) || "/";
|
|
15818
|
+
if (!scopePath.startsWith("/") || scopePath.includes("?") || scopePath.includes("#") || !inScope(source, source, scopePath)) throw new Error("The selected documentation scope must contain the source URL.");
|
|
15466
15819
|
const captureVersion = options.captureVersion ?? "fetch-v1";
|
|
15467
15820
|
if (options.checkpoint && options.checkpoint.records.length > MAX_RECORDS) throw new Error("Checkpoint inventory exceeds its bound.");
|
|
15468
15821
|
const checkpoint = options.checkpoint ? cloneUrlMigrationCheckpoint(options.checkpoint) : { schemaVersion: 1, converterVersion: CONVERTER_VERSION, sourceUrl, scopePath, captureVersion, records: [], navigation: [] };
|
|
@@ -15481,6 +15834,8 @@ async function runUrlMigration(options) {
|
|
|
15481
15834
|
delete record.apiSpecification;
|
|
15482
15835
|
delete record.version;
|
|
15483
15836
|
delete record.issues;
|
|
15837
|
+
delete record.warnings;
|
|
15838
|
+
delete record.redirectTo;
|
|
15484
15839
|
delete record.reason;
|
|
15485
15840
|
delete record.aliasOf;
|
|
15486
15841
|
}
|
|
@@ -15493,6 +15848,7 @@ async function runUrlMigration(options) {
|
|
|
15493
15848
|
const enqueue = (value, base, discoveredBy) => {
|
|
15494
15849
|
const url = canonical(value, base);
|
|
15495
15850
|
if (!url || !inScope(new URL(url), source, scopePath) && !isDiscoveryIndex(new URL(url), source)) return;
|
|
15851
|
+
const isAttachment = discoveredBy !== "submitted" && /\.(?:json|ya?ml)$/i.test(new URL(url).pathname);
|
|
15496
15852
|
const existing = records.get(url);
|
|
15497
15853
|
if (existing) {
|
|
15498
15854
|
if (!existing.discoveredBy.includes(discoveredBy)) {
|
|
@@ -15502,10 +15858,15 @@ async function runUrlMigration(options) {
|
|
|
15502
15858
|
return;
|
|
15503
15859
|
}
|
|
15504
15860
|
if (records.size >= MAX_RECORDS) throw new Error("Discovered URL inventory exceeded the 100000 URL safety bound.");
|
|
15505
|
-
const record = {
|
|
15861
|
+
const record = {
|
|
15862
|
+
url,
|
|
15863
|
+
discoveredBy: [discoveredBy],
|
|
15864
|
+
outcome: isAttachment ? "excluded" : "pending",
|
|
15865
|
+
...isAttachment ? { reason: "Machine-readable attachment, not an authored article." } : {}
|
|
15866
|
+
};
|
|
15506
15867
|
records.set(url, record);
|
|
15507
15868
|
checkpoint.records.push(record);
|
|
15508
|
-
pending.push(record);
|
|
15869
|
+
if (!isAttachment) pending.push(record);
|
|
15509
15870
|
changed.push(record);
|
|
15510
15871
|
};
|
|
15511
15872
|
enqueue(sourceUrl, sourceUrl, "submitted");
|
|
@@ -15538,8 +15899,6 @@ async function runUrlMigration(options) {
|
|
|
15538
15899
|
}
|
|
15539
15900
|
}
|
|
15540
15901
|
enqueueNavigation(checkpoint.navigation, sourceUrl);
|
|
15541
|
-
const fetcher = options.fetcher ?? defaultMigrationFetcher;
|
|
15542
|
-
const capture = options.captureProvider?.capture.bind(options.captureProvider) ?? (async ({ url }) => fetcher(url, { accept: ACCEPT }));
|
|
15543
15902
|
const assetFetcher = options.assetFetcher ?? (!options.fetcher && !options.captureProvider ? defaultAssetFetcher : void 0);
|
|
15544
15903
|
const usedIds = new Map([...records.values()].filter((record) => record.page).map((record) => [record.page.id, record.url]));
|
|
15545
15904
|
const finalUrls = new Map([...records.values()].filter((record) => record.evidence && record.page).map((record) => [canonical(record.evidence.finalUrl, sourceUrl), record.url]));
|
|
@@ -15547,6 +15906,10 @@ async function runUrlMigration(options) {
|
|
|
15547
15906
|
const assetPayloads = new Map(checkpoint.records.flatMap((record) => (record.assets ?? []).map((asset) => [asset.sha256, asset])));
|
|
15548
15907
|
const assetBytes = /* @__PURE__ */ new Map();
|
|
15549
15908
|
const retainAsset = (asset) => {
|
|
15909
|
+
if (asset.unavailable) {
|
|
15910
|
+
if ([404, 410].includes(asset.unavailable.status) && asset.content.byteLength === 0) return asset;
|
|
15911
|
+
throw new Error("Invalid source asset availability evidence.");
|
|
15912
|
+
}
|
|
15550
15913
|
if (!acceptedAsset(asset)) throw new Error("Asset MIME/signature is unsupported or unsafe to serve.");
|
|
15551
15914
|
const sha256 = hash2(asset.content);
|
|
15552
15915
|
const content = assetBytes.get(sha256) ?? Buffer.from(asset.content);
|
|
@@ -15579,6 +15942,11 @@ async function runUrlMigration(options) {
|
|
|
15579
15942
|
let markdownRepresentation;
|
|
15580
15943
|
try {
|
|
15581
15944
|
delete record.reason;
|
|
15945
|
+
if (/\/llms-full\.txt$/i.test(new URL(record.url).pathname)) {
|
|
15946
|
+
record.outcome = "excluded";
|
|
15947
|
+
record.reason = "Aggregate documentation corpus; individual articles are inventoried separately.";
|
|
15948
|
+
return;
|
|
15949
|
+
}
|
|
15582
15950
|
delete record.apiSpecification;
|
|
15583
15951
|
const represented = resolveMigrationRecord(records, record.representationOf ? records.get(record.representationOf) : void 0);
|
|
15584
15952
|
if (represented?.outcome === "imported") {
|
|
@@ -15588,6 +15956,16 @@ async function runUrlMigration(options) {
|
|
|
15588
15956
|
}
|
|
15589
15957
|
const document = await capture({ url: new URL(record.url), signal: options.signal });
|
|
15590
15958
|
if (options.signal?.aborted) return;
|
|
15959
|
+
if (document.status && document.status >= 300 && document.status < 400 && document.headers?.location) {
|
|
15960
|
+
const destination = canonical(document.headers.location, document.finalUrl.href);
|
|
15961
|
+
if (destination && new URL(destination).origin !== source.origin) {
|
|
15962
|
+
record.outcome = "excluded";
|
|
15963
|
+
record.redirectTo = new URL(document.headers.location, document.finalUrl).href;
|
|
15964
|
+
record.reason = "The source entry is a redirect to an external public resource, retained as a link.";
|
|
15965
|
+
return;
|
|
15966
|
+
}
|
|
15967
|
+
throw new Error("Capture returned an unresolved redirect.");
|
|
15968
|
+
}
|
|
15591
15969
|
if (Buffer.byteLength(document.body) > MAX_RESPONSE_BYTES) throw new Error("Captured response exceeds the 8 MB safety bound.");
|
|
15592
15970
|
const identity = articleIdentity(document);
|
|
15593
15971
|
const final = canonical(identity.toString(), sourceUrl);
|
|
@@ -15595,6 +15973,7 @@ async function runUrlMigration(options) {
|
|
|
15595
15973
|
if (!inScope(document.finalUrl, source, scopePath) && !(role === "index" && isDiscoveryIndex(document.finalUrl, source))) {
|
|
15596
15974
|
record.outcome = "excluded";
|
|
15597
15975
|
record.reason = "Redirected outside the selected origin/path.";
|
|
15976
|
+
if (document.finalUrl.origin === source.origin && (!document.status || document.status >= 200 && document.status < 300)) record.redirectTo = document.finalUrl.href;
|
|
15598
15977
|
return;
|
|
15599
15978
|
}
|
|
15600
15979
|
if (document.status && document.status >= 400) throw new Error(`Source page returned HTTP ${document.status}.`);
|
|
@@ -15612,7 +15991,7 @@ async function runUrlMigration(options) {
|
|
|
15612
15991
|
return;
|
|
15613
15992
|
}
|
|
15614
15993
|
if (/html/i.test(document.contentType)) {
|
|
15615
|
-
const $ =
|
|
15994
|
+
const $ = load6(document.body);
|
|
15616
15995
|
$('link[rel="alternate"][type="text/markdown"][href]').each((_index, node) => {
|
|
15617
15996
|
const alternate = canonical($(node).attr("href"), final);
|
|
15618
15997
|
if (!alternate) return;
|
|
@@ -15626,7 +16005,7 @@ async function runUrlMigration(options) {
|
|
|
15626
16005
|
changed.push(sibling);
|
|
15627
16006
|
});
|
|
15628
16007
|
}
|
|
15629
|
-
const observedNavigation = sourceNavigation(document);
|
|
16008
|
+
const observedNavigation = sourceNavigation(document, scopePath);
|
|
15630
16009
|
if (observedNavigation.length && !(checkpoint.navigation.some((node) => node.kind === "tab") && !observedNavigation.some((node) => node.kind === "tab"))) {
|
|
15631
16010
|
const merged = mergeSourceNavigation(checkpoint.navigation, observedNavigation);
|
|
15632
16011
|
if (JSON.stringify(merged) !== JSON.stringify(checkpoint.navigation)) {
|
|
@@ -15668,6 +16047,7 @@ async function runUrlMigration(options) {
|
|
|
15668
16047
|
record.reason = "Content could not be represented as safe inert MDX.";
|
|
15669
16048
|
return;
|
|
15670
16049
|
}
|
|
16050
|
+
let coveredSchemaGroups = [];
|
|
15671
16051
|
const hasSchemaChoice = /html/i.test(document.contentType) && migrationHtmlArticle(document.body).root.find('select[aria-label="Select schema type"],select[aria-label="\u9009\u62E9\u67B6\u6784\u7C7B\u578B"]').length > 0;
|
|
15672
16052
|
if (/html/i.test(document.contentType) && markdownRepresentation && (unresolvedStaticControls(document.body) || hasSchemaChoice)) {
|
|
15673
16053
|
const schemaCapture = await capture({ url: new URL(markdownRepresentation), signal: options.signal });
|
|
@@ -15683,6 +16063,7 @@ async function runUrlMigration(options) {
|
|
|
15683
16063
|
const path = `openapi/migration-${sha256}.json`;
|
|
15684
16064
|
record.apiSpecification = { path, sha256, document: fragment.document };
|
|
15685
16065
|
page.openapi = `${path} ${fragment.method} ${fragment.path}`;
|
|
16066
|
+
coveredSchemaGroups = apiSchemaTabGroups(document.body, fragment.document, fragment);
|
|
15686
16067
|
}
|
|
15687
16068
|
}
|
|
15688
16069
|
const states = document.states ?? [];
|
|
@@ -15712,17 +16093,24 @@ ${difference}`;
|
|
|
15712
16093
|
}
|
|
15713
16094
|
record.assets = [];
|
|
15714
16095
|
record.issues = [];
|
|
16096
|
+
record.warnings = [];
|
|
15715
16097
|
if (/html/i.test(document.contentType)) {
|
|
15716
16098
|
const { $, root } = migrationHtmlArticle(document.body);
|
|
15717
16099
|
root.find("nav,footer,aside,.theme-doc-breadcrumbs,.theme-doc-toc-mobile,.table-of-contents,.hash-link").remove();
|
|
15718
16100
|
root.find('button svg,a.hash-link svg,[aria-hidden="true"] svg,svg[aria-hidden="true"],svg[data-lucide],svg[data-icon]').remove();
|
|
16101
|
+
root.find("video,iframe").each((_index, node) => {
|
|
16102
|
+
if (projectMigrationMedia($.html(node), document.finalUrl) !== null) {
|
|
16103
|
+
record.warnings.push({ code: "source-asset-warning", source: record.url, message: "Embedded video is preserved at its original public media URL; playback depends on the original host." });
|
|
16104
|
+
$(node).remove();
|
|
16105
|
+
}
|
|
16106
|
+
});
|
|
15719
16107
|
if (record.apiSpecification) {
|
|
15720
16108
|
root.find('select[aria-label="Select schema type"],select[aria-label="\u9009\u62E9\u67B6\u6784\u7C7B\u578B"]').remove();
|
|
15721
16109
|
root.find('.option-dropdown svg[data-component-part="icon-svg"]').remove();
|
|
15722
16110
|
}
|
|
15723
16111
|
const unsupported = [...new Set(root.find("iframe,object,embed,canvas,svg,form,input,textarea,select,math,video,audio").toArray().map((node) => node.tagName))];
|
|
15724
16112
|
if (unsupported.length) record.issues.push({ code: "unsupported-component", source: record.url, message: `Rendered content requires explicit review for: ${unsupported.join(", ")}.` });
|
|
15725
|
-
if (!states.length && unresolvedStaticControls(document.body, Boolean(record.apiSpecification))) record.issues.push({ code: "unsupported-component", source: record.url, message: "An interactive alternative has no complete captured panel or disclosure content." });
|
|
16113
|
+
if (!states.length && unresolvedStaticControls(document.body, Boolean(record.apiSpecification), coveredSchemaGroups)) record.issues.push({ code: "unsupported-component", source: record.url, message: "An interactive alternative has no complete captured panel or disclosure content." });
|
|
15726
16114
|
}
|
|
15727
16115
|
const suppliedAssets = new Map((document.assets ?? []).map((asset) => [canonical(asset.url, final), asset]));
|
|
15728
16116
|
const assetUrls = [...new Set([...assetReferences(document), ...states.flatMap((state) => assetReferences(state.response))].map((url) => canonical(url, final)).filter((url) => Boolean(url)))];
|
|
@@ -15736,6 +16124,11 @@ ${difference}`;
|
|
|
15736
16124
|
const supplied = suppliedAssets.get(url);
|
|
15737
16125
|
const asset = supplied ? retainAsset(supplied) : assetRequest ? await assetRequest : null;
|
|
15738
16126
|
if (!asset) throw new Error("Capture host did not supply asset bytes or a binary fetch boundary.");
|
|
16127
|
+
if (asset.unavailable && [404, 410].includes(asset.unavailable.status) && asset.content.byteLength === 0) {
|
|
16128
|
+
record.warnings.push({ code: "asset-failed", source: record.url, message: `The original source asset is unavailable (HTTP ${asset.unavailable.status}); its original URL was retained: ${url}` });
|
|
16129
|
+
page.body = rewriteMarkdownDestinations(page.body, (destination) => canonical(destination, final) === url ? url : destination);
|
|
16130
|
+
continue;
|
|
16131
|
+
}
|
|
15739
16132
|
const extension = acceptedAsset(asset);
|
|
15740
16133
|
if (!extension) throw new Error("Asset MIME/signature is unsupported or unsafe to serve.");
|
|
15741
16134
|
const sha256 = hash2(asset.content);
|
|
@@ -15777,7 +16170,7 @@ ${difference}`;
|
|
|
15777
16170
|
} catch (error) {
|
|
15778
16171
|
if (options.signal?.aborted) return;
|
|
15779
16172
|
const wasImported = record.outcome === "imported";
|
|
15780
|
-
record.outcome = record.discoveredBy.every((origin) => origin === "discovery-index") ? "excluded" : "failed";
|
|
16173
|
+
record.outcome = isDiscoveryIndex(new URL(record.url), source) || record.discoveredBy.every((origin) => origin === "discovery-index") ? "excluded" : "failed";
|
|
15781
16174
|
record.reason = error instanceof Error ? error.message : String(error);
|
|
15782
16175
|
if (record.page) {
|
|
15783
16176
|
if (wasImported) imported--;
|
|
@@ -15802,7 +16195,7 @@ ${difference}`;
|
|
|
15802
16195
|
for (const record of records.values()) {
|
|
15803
16196
|
if (!record.representationOf) continue;
|
|
15804
16197
|
const primary = resolveMigrationRecord(records, records.get(record.representationOf));
|
|
15805
|
-
if (!primary) continue;
|
|
16198
|
+
if (!primary || primary === record) continue;
|
|
15806
16199
|
const winner = primary.outcome === "imported" ? primary : record.outcome === "imported" && primary.outcome === "failed" ? record : void 0;
|
|
15807
16200
|
if (!winner) continue;
|
|
15808
16201
|
const alternate = winner === primary ? record : primary;
|
|
@@ -15928,7 +16321,7 @@ function rewriteMarkdownDestinations(body, rewrite) {
|
|
|
15928
16321
|
return { start: start + index, end: start + index + node.url.length, replacement };
|
|
15929
16322
|
}).filter((edit) => edit !== null).sort((a, b) => b.start - a.start);
|
|
15930
16323
|
for (const node of markdownNodes(body)) for (const attribute of node.attributes ?? []) {
|
|
15931
|
-
if (!attribute.name || !["src", "href", "srcSet", "srcset", "img", "primaryHref", "secondaryHref"].includes(attribute.name) || !attribute.position) continue;
|
|
16324
|
+
if (!attribute.name || !["src", "poster", "href", "srcSet", "srcset", "img", "primaryHref", "secondaryHref"].includes(attribute.name) || !attribute.position) continue;
|
|
15932
16325
|
let value = attribute.value;
|
|
15933
16326
|
if (typeof value !== "string") {
|
|
15934
16327
|
try {
|
|
@@ -15989,7 +16382,7 @@ async function getPinnedAddress(url) {
|
|
|
15989
16382
|
}
|
|
15990
16383
|
async function requestPinnedSpec(url) {
|
|
15991
16384
|
const pinned = await getPinnedAddress(url);
|
|
15992
|
-
return new Promise((
|
|
16385
|
+
return new Promise((resolve5, reject) => {
|
|
15993
16386
|
const req = request(url, {
|
|
15994
16387
|
headers: { Accept: "application/json, application/yaml, text/yaml, */*", "User-Agent": "Thally-Migrate/1.0 (+https://thally.io)" },
|
|
15995
16388
|
signal: AbortSignal.timeout(3e4),
|
|
@@ -16003,7 +16396,7 @@ async function requestPinnedSpec(url) {
|
|
|
16003
16396
|
const status = response.statusCode ?? 0;
|
|
16004
16397
|
if (status >= 300 && status < 400) {
|
|
16005
16398
|
response.resume();
|
|
16006
|
-
|
|
16399
|
+
resolve5({ status, location: response.headers.location, body: Buffer.alloc(0) });
|
|
16007
16400
|
return;
|
|
16008
16401
|
}
|
|
16009
16402
|
if (status < 200 || status >= 300) {
|
|
@@ -16027,7 +16420,7 @@ async function requestPinnedSpec(url) {
|
|
|
16027
16420
|
}
|
|
16028
16421
|
chunks.push(chunk);
|
|
16029
16422
|
});
|
|
16030
|
-
response.on("end", () =>
|
|
16423
|
+
response.on("end", () => resolve5({ status, body: Buffer.concat(chunks) }));
|
|
16031
16424
|
response.on("error", reject);
|
|
16032
16425
|
});
|
|
16033
16426
|
req.on("error", reject);
|