gt 2.14.38 → 2.14.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/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # gtx-cli
2
2
 
3
+ ## 2.14.39
4
+
5
+ ### Patch Changes
6
+
7
+ - [#1455](https://github.com/generaltranslation/gt/pull/1455) [`cd8fa50`](https://github.com/generaltranslation/gt/commit/cd8fa505c90624160d6ef4d044946b3bf230f646) Thanks [@fernando-aviles](https://github.com/fernando-aviles)! - Handle Mintlify `docs.json` `directory` field
8
+
9
+ - [#1448](https://github.com/generaltranslation/gt/pull/1448) [`f19bade`](https://github.com/generaltranslation/gt/commit/f19bade4741e934505e75880218599d27873e864) Thanks [@ErnestM1234](https://github.com/ErnestM1234)! - Fix CLI binary release builds by resolving Ink's devtools peer dependency and failing binary build scripts on compile errors.
10
+
3
11
  ## 2.14.38
4
12
 
5
13
  ### Patch Changes
@@ -10,8 +10,8 @@ import flattenJsonFiles from "../../utils/flattenJsonFiles.js";
10
10
  import localizeStaticUrls from "../../utils/localizeStaticUrls.js";
11
11
  import localizeRelativeAssets from "../../utils/localizeRelativeAssets.js";
12
12
  import processAnchorIds from "../../utils/processAnchorIds.js";
13
- import processOpenApi from "../../utils/processOpenApi.js";
14
13
  import localizeStaticImports from "../../utils/localizeStaticImports.js";
14
+ import { postprocessMintlify } from "../../formats/files/postprocess/mintlify.js";
15
15
  import { persistPostProcessHashes } from "../../utils/persistPostprocessHashes.js";
16
16
  //#region src/cli/commands/translate.ts
17
17
  async function handleTranslate(options, settings, fileVersionData, jobData, branchData, publishMap) {
@@ -39,7 +39,7 @@ async function handleTranslate(options, settings, fileVersionData, jobData, bran
39
39
  async function postProcessTranslations(settings, includeFiles) {
40
40
  const postProcessIncludes = filterPostProcessIncludesForFormatTransforms(settings, includeFiles);
41
41
  if (includeFiles && postProcessIncludes?.size === 0) return;
42
- await processOpenApi(settings, postProcessIncludes);
42
+ await postprocessMintlify(settings, postProcessIncludes);
43
43
  if (settings.options?.experimentalLocalizeStaticUrls) {
44
44
  const nonDefaultLocales = settings.locales.filter((locale) => locale !== settings.defaultLocale);
45
45
  if (nonDefaultLocales.length > 0) await localizeStaticUrls(settings, nonDefaultLocales, postProcessIncludes);
@@ -1 +1 @@
1
- {"version":3,"file":"translate.js","names":[],"sources":["../../../src/cli/commands/translate.ts"],"sourcesContent":["import { EnqueueFilesResult } from 'generaltranslation/types';\nimport { TranslateFlags } from '../../types/index.js';\nimport { Settings } from '../../types/index.js';\nimport {\n FileTranslationData,\n runDownloadWorkflow,\n} from '../../workflows/download.js';\nimport { createFileMapping } from '../../formats/files/fileMapping.js';\nimport copyFile from '../../fs/copyFile.js';\nimport flattenJsonFiles from '../../utils/flattenJsonFiles.js';\nimport localizeStaticUrls from '../../utils/localizeStaticUrls.js';\nimport localizeRelativeAssets from '../../utils/localizeRelativeAssets.js';\nimport processAnchorIds from '../../utils/processAnchorIds.js';\nimport processOpenApi from '../../utils/processOpenApi.js';\nimport localizeStaticImports from '../../utils/localizeStaticImports.js';\nimport { BranchData } from '../../types/branch.js';\nimport { getDownloadedMeta } from '../../state/recentDownloads.js';\nimport { persistPostProcessHashes } from '../../utils/persistPostprocessHashes.js';\nimport { runPublishWorkflow } from '../../workflows/publish.js';\nimport { SUPPORTED_FILE_EXTENSIONS } from '../../formats/files/supportedFiles.js';\nimport { hasNonIdentityFileFormatTransformForType } from '../../formats/files/transformFormat.js';\nimport { getRelative } from '../../fs/findFilepath.js';\n\n// Downloads translations that were completed\nexport async function handleTranslate(\n options: TranslateFlags,\n settings: Settings,\n fileVersionData: FileTranslationData | undefined,\n jobData: EnqueueFilesResult | undefined,\n branchData: BranchData | undefined,\n publishMap?: Map<string, boolean>\n) {\n if (fileVersionData) {\n const {\n resolvedPaths,\n placeholderPaths,\n transformPaths,\n transformFormats,\n } = settings.files;\n\n const fileMapping = createFileMapping(\n resolvedPaths,\n placeholderPaths,\n transformPaths,\n transformFormats,\n settings.locales,\n settings.defaultLocale\n );\n // Check for remaining translations\n await runDownloadWorkflow({\n fileVersionData: fileVersionData,\n jobData: jobData,\n branchData: branchData,\n locales: settings.locales,\n timeoutDuration: options.timeout,\n resolveOutputPath: (sourcePath, locale) =>\n fileMapping[locale]?.[sourcePath] ?? null,\n options: settings,\n forceRetranslation: options.force,\n forceDownload: options.forceDownload || options.force, // if force is true should also force download\n });\n\n // Publish/unpublish files after translations are downloaded\n if (publishMap && branchData?.currentBranch.id) {\n const files = Object.entries(fileVersionData).map(([fileId, data]) => ({\n fileId,\n versionId: data.versionId,\n fileName: data.fileName,\n }));\n await runPublishWorkflow(\n files,\n publishMap,\n branchData.currentBranch.id,\n settings\n );\n }\n }\n}\n\nexport async function postProcessTranslations(\n settings: Settings,\n includeFiles?: Set<string>\n) {\n const postProcessIncludes = filterPostProcessIncludesForFormatTransforms(\n settings,\n includeFiles\n );\n if (includeFiles && postProcessIncludes?.size === 0) return;\n\n // Mintlify OpenAPI localization (spec routing + validation)\n await processOpenApi(settings, postProcessIncludes);\n\n // Localize static urls (/docs -> /[locale]/docs) and preserve anchor IDs for non-default locales\n // Default locale is processed earlier in the flow in base.ts\n if (settings.options?.experimentalLocalizeStaticUrls) {\n const nonDefaultLocales = settings.locales.filter(\n (locale) => locale !== settings.defaultLocale\n );\n if (nonDefaultLocales.length > 0) {\n await localizeStaticUrls(\n settings,\n nonDefaultLocales,\n postProcessIncludes\n );\n }\n }\n\n // Rewrite relative asset URLs in translated md/mdx files\n if (settings.options?.experimentalLocalizeRelativeAssets) {\n const nonDefaultLocales = settings.locales.filter(\n (locale) => locale !== settings.defaultLocale\n );\n if (nonDefaultLocales.length > 0) {\n await localizeRelativeAssets(\n settings,\n nonDefaultLocales,\n postProcessIncludes\n );\n }\n }\n\n const shouldProcessAnchorIds =\n settings.options?.experimentalLocalizeStaticUrls ||\n settings.options?.experimentalAddHeaderAnchorIds;\n\n // Add explicit anchor IDs to translated MDX/MD files to preserve navigation\n // Uses inline {#id} format by default, or div wrapping if experimentalAddHeaderAnchorIds is 'mintlify'\n if (shouldProcessAnchorIds) {\n await processAnchorIds(settings, postProcessIncludes);\n }\n\n // Localize static imports (import Snippet from /snippets/file.mdx -> import Snippet from /snippets/[locale]/file.mdx)\n if (settings.options?.experimentalLocalizeStaticImports) {\n await localizeStaticImports(settings, postProcessIncludes);\n }\n\n // Flatten json files into a single file\n if (settings.options?.experimentalFlattenJsonFiles) {\n await flattenJsonFiles(settings, postProcessIncludes);\n }\n\n // Copy files to the target locale\n if (settings.options?.copyFiles) {\n await copyFile(settings);\n }\n\n // Record postprocessed content hashes for newly downloaded files\n persistPostProcessHashes(settings, postProcessIncludes, getDownloadedMeta());\n}\n\n/**\n * Exclude only outputs whose source file was translated into a different format.\n * @param settings - The settings for the project\n * @param includeFiles - The files to include in the post-processing\n * @returns The files to exclude in the post-processing\n */\nfunction filterPostProcessIncludesForFormatTransforms(\n settings: Settings,\n includeFiles?: Set<string>\n): Set<string> | undefined {\n if (!includeFiles) return includeFiles;\n\n const transformedSourcePaths = new Set<string>();\n for (const fileType of SUPPORTED_FILE_EXTENSIONS) {\n if (!hasNonIdentityFileFormatTransformForType(settings, fileType)) continue;\n\n for (const sourcePath of settings.files.resolvedPaths[fileType] || []) {\n transformedSourcePaths.add(getRelative(sourcePath));\n }\n }\n if (transformedSourcePaths.size === 0) return includeFiles;\n\n const { resolvedPaths, placeholderPaths, transformPaths, transformFormats } =\n settings.files;\n const fileMapping = createFileMapping(\n resolvedPaths,\n placeholderPaths,\n transformPaths,\n transformFormats,\n settings.locales,\n settings.defaultLocale\n );\n\n const transformedOutputPaths = new Set<string>();\n for (const localeMapping of Object.values(fileMapping)) {\n for (const [sourcePath, outputPath] of Object.entries(localeMapping)) {\n if (transformedSourcePaths.has(sourcePath)) {\n transformedOutputPaths.add(outputPath);\n }\n }\n }\n\n return new Set(\n [...includeFiles].filter(\n (filePath) => !transformedOutputPaths.has(filePath)\n )\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAwBA,eAAsB,gBACpB,SACA,UACA,iBACA,SACA,YACA,YACA;AACA,KAAI,iBAAiB;EACnB,MAAM,EACJ,eACA,kBACA,gBACA,qBACE,SAAS;EAEb,MAAM,cAAc,kBAClB,eACA,kBACA,gBACA,kBACA,SAAS,SACT,SAAS,cACV;AAED,QAAM,oBAAoB;GACP;GACR;GACG;GACZ,SAAS,SAAS;GAClB,iBAAiB,QAAQ;GACzB,oBAAoB,YAAY,WAC9B,YAAY,UAAU,eAAe;GACvC,SAAS;GACT,oBAAoB,QAAQ;GAC5B,eAAe,QAAQ,iBAAiB,QAAQ;GACjD,CAAC;AAGF,MAAI,cAAc,YAAY,cAAc,GAM1C,OAAM,mBALQ,OAAO,QAAQ,gBAAgB,CAAC,KAAK,CAAC,QAAQ,WAAW;GACrE;GACA,WAAW,KAAK;GAChB,UAAU,KAAK;GAChB,EAEM,EACL,YACA,WAAW,cAAc,IACzB,SACD;;;AAKP,eAAsB,wBACpB,UACA,cACA;CACA,MAAM,sBAAsB,6CAC1B,UACA,aACD;AACD,KAAI,gBAAgB,qBAAqB,SAAS,EAAG;AAGrD,OAAM,eAAe,UAAU,oBAAoB;AAInD,KAAI,SAAS,SAAS,gCAAgC;EACpD,MAAM,oBAAoB,SAAS,QAAQ,QACxC,WAAW,WAAW,SAAS,cACjC;AACD,MAAI,kBAAkB,SAAS,EAC7B,OAAM,mBACJ,UACA,mBACA,oBACD;;AAKL,KAAI,SAAS,SAAS,oCAAoC;EACxD,MAAM,oBAAoB,SAAS,QAAQ,QACxC,WAAW,WAAW,SAAS,cACjC;AACD,MAAI,kBAAkB,SAAS,EAC7B,OAAM,uBACJ,UACA,mBACA,oBACD;;AAUL,KALE,SAAS,SAAS,kCAClB,SAAS,SAAS,+BAKlB,OAAM,iBAAiB,UAAU,oBAAoB;AAIvD,KAAI,SAAS,SAAS,kCACpB,OAAM,sBAAsB,UAAU,oBAAoB;AAI5D,KAAI,SAAS,SAAS,6BACpB,OAAM,iBAAiB,UAAU,oBAAoB;AAIvD,KAAI,SAAS,SAAS,UACpB,OAAM,SAAS,SAAS;AAI1B,0BAAyB,UAAU,qBAAqB,mBAAmB,CAAC;;;;;;;;AAS9E,SAAS,6CACP,UACA,cACyB;AACzB,KAAI,CAAC,aAAc,QAAO;CAE1B,MAAM,yCAAyB,IAAI,KAAa;AAChD,MAAK,MAAM,YAAY,2BAA2B;AAChD,MAAI,CAAC,yCAAyC,UAAU,SAAS,CAAE;AAEnE,OAAK,MAAM,cAAc,SAAS,MAAM,cAAc,aAAa,EAAE,CACnE,wBAAuB,IAAI,YAAY,WAAW,CAAC;;AAGvD,KAAI,uBAAuB,SAAS,EAAG,QAAO;CAE9C,MAAM,EAAE,eAAe,kBAAkB,gBAAgB,qBACvD,SAAS;CACX,MAAM,cAAc,kBAClB,eACA,kBACA,gBACA,kBACA,SAAS,SACT,SAAS,cACV;CAED,MAAM,yCAAyB,IAAI,KAAa;AAChD,MAAK,MAAM,iBAAiB,OAAO,OAAO,YAAY,CACpD,MAAK,MAAM,CAAC,YAAY,eAAe,OAAO,QAAQ,cAAc,CAClE,KAAI,uBAAuB,IAAI,WAAW,CACxC,wBAAuB,IAAI,WAAW;AAK5C,QAAO,IAAI,IACT,CAAC,GAAG,aAAa,CAAC,QACf,aAAa,CAAC,uBAAuB,IAAI,SAAS,CACpD,CACF"}
1
+ {"version":3,"file":"translate.js","names":[],"sources":["../../../src/cli/commands/translate.ts"],"sourcesContent":["import { EnqueueFilesResult } from 'generaltranslation/types';\nimport { TranslateFlags } from '../../types/index.js';\nimport { Settings } from '../../types/index.js';\nimport {\n FileTranslationData,\n runDownloadWorkflow,\n} from '../../workflows/download.js';\nimport { createFileMapping } from '../../formats/files/fileMapping.js';\nimport copyFile from '../../fs/copyFile.js';\nimport flattenJsonFiles from '../../utils/flattenJsonFiles.js';\nimport localizeStaticUrls from '../../utils/localizeStaticUrls.js';\nimport localizeRelativeAssets from '../../utils/localizeRelativeAssets.js';\nimport processAnchorIds from '../../utils/processAnchorIds.js';\nimport localizeStaticImports from '../../utils/localizeStaticImports.js';\nimport { postprocessMintlify } from '../../formats/files/postprocess/mintlify.js';\nimport { BranchData } from '../../types/branch.js';\nimport { getDownloadedMeta } from '../../state/recentDownloads.js';\nimport { persistPostProcessHashes } from '../../utils/persistPostprocessHashes.js';\nimport { runPublishWorkflow } from '../../workflows/publish.js';\nimport { SUPPORTED_FILE_EXTENSIONS } from '../../formats/files/supportedFiles.js';\nimport { hasNonIdentityFileFormatTransformForType } from '../../formats/files/transformFormat.js';\nimport { getRelative } from '../../fs/findFilepath.js';\n\n// Downloads translations that were completed\nexport async function handleTranslate(\n options: TranslateFlags,\n settings: Settings,\n fileVersionData: FileTranslationData | undefined,\n jobData: EnqueueFilesResult | undefined,\n branchData: BranchData | undefined,\n publishMap?: Map<string, boolean>\n) {\n if (fileVersionData) {\n const {\n resolvedPaths,\n placeholderPaths,\n transformPaths,\n transformFormats,\n } = settings.files;\n\n const fileMapping = createFileMapping(\n resolvedPaths,\n placeholderPaths,\n transformPaths,\n transformFormats,\n settings.locales,\n settings.defaultLocale\n );\n // Check for remaining translations\n await runDownloadWorkflow({\n fileVersionData: fileVersionData,\n jobData: jobData,\n branchData: branchData,\n locales: settings.locales,\n timeoutDuration: options.timeout,\n resolveOutputPath: (sourcePath, locale) =>\n fileMapping[locale]?.[sourcePath] ?? null,\n options: settings,\n forceRetranslation: options.force,\n forceDownload: options.forceDownload || options.force, // if force is true should also force download\n });\n\n // Publish/unpublish files after translations are downloaded\n if (publishMap && branchData?.currentBranch.id) {\n const files = Object.entries(fileVersionData).map(([fileId, data]) => ({\n fileId,\n versionId: data.versionId,\n fileName: data.fileName,\n }));\n await runPublishWorkflow(\n files,\n publishMap,\n branchData.currentBranch.id,\n settings\n );\n }\n }\n}\n\nexport async function postProcessTranslations(\n settings: Settings,\n includeFiles?: Set<string>\n) {\n const postProcessIncludes = filterPostProcessIncludesForFormatTransforms(\n settings,\n includeFiles\n );\n if (includeFiles && postProcessIncludes?.size === 0) return;\n\n await postprocessMintlify(settings, postProcessIncludes);\n\n // Localize static urls (/docs -> /[locale]/docs) and preserve anchor IDs for non-default locales\n // Default locale is processed earlier in the flow in base.ts\n if (settings.options?.experimentalLocalizeStaticUrls) {\n const nonDefaultLocales = settings.locales.filter(\n (locale) => locale !== settings.defaultLocale\n );\n if (nonDefaultLocales.length > 0) {\n await localizeStaticUrls(\n settings,\n nonDefaultLocales,\n postProcessIncludes\n );\n }\n }\n\n // Rewrite relative asset URLs in translated md/mdx files\n if (settings.options?.experimentalLocalizeRelativeAssets) {\n const nonDefaultLocales = settings.locales.filter(\n (locale) => locale !== settings.defaultLocale\n );\n if (nonDefaultLocales.length > 0) {\n await localizeRelativeAssets(\n settings,\n nonDefaultLocales,\n postProcessIncludes\n );\n }\n }\n\n const shouldProcessAnchorIds =\n settings.options?.experimentalLocalizeStaticUrls ||\n settings.options?.experimentalAddHeaderAnchorIds;\n\n // Add explicit anchor IDs to translated MDX/MD files to preserve navigation\n // Uses inline {#id} format by default, or div wrapping if experimentalAddHeaderAnchorIds is 'mintlify'\n if (shouldProcessAnchorIds) {\n await processAnchorIds(settings, postProcessIncludes);\n }\n\n // Localize static imports (import Snippet from /snippets/file.mdx -> import Snippet from /snippets/[locale]/file.mdx)\n if (settings.options?.experimentalLocalizeStaticImports) {\n await localizeStaticImports(settings, postProcessIncludes);\n }\n\n // Flatten json files into a single file\n if (settings.options?.experimentalFlattenJsonFiles) {\n await flattenJsonFiles(settings, postProcessIncludes);\n }\n\n // Copy files to the target locale\n if (settings.options?.copyFiles) {\n await copyFile(settings);\n }\n\n // Record postprocessed content hashes for newly downloaded files\n persistPostProcessHashes(settings, postProcessIncludes, getDownloadedMeta());\n}\n\n/**\n * Exclude only outputs whose source file was translated into a different format.\n * @param settings - The settings for the project\n * @param includeFiles - The files to include in the post-processing\n * @returns The files to exclude in the post-processing\n */\nfunction filterPostProcessIncludesForFormatTransforms(\n settings: Settings,\n includeFiles?: Set<string>\n): Set<string> | undefined {\n if (!includeFiles) return includeFiles;\n\n const transformedSourcePaths = new Set<string>();\n for (const fileType of SUPPORTED_FILE_EXTENSIONS) {\n if (!hasNonIdentityFileFormatTransformForType(settings, fileType)) continue;\n\n for (const sourcePath of settings.files.resolvedPaths[fileType] || []) {\n transformedSourcePaths.add(getRelative(sourcePath));\n }\n }\n if (transformedSourcePaths.size === 0) return includeFiles;\n\n const { resolvedPaths, placeholderPaths, transformPaths, transformFormats } =\n settings.files;\n const fileMapping = createFileMapping(\n resolvedPaths,\n placeholderPaths,\n transformPaths,\n transformFormats,\n settings.locales,\n settings.defaultLocale\n );\n\n const transformedOutputPaths = new Set<string>();\n for (const localeMapping of Object.values(fileMapping)) {\n for (const [sourcePath, outputPath] of Object.entries(localeMapping)) {\n if (transformedSourcePaths.has(sourcePath)) {\n transformedOutputPaths.add(outputPath);\n }\n }\n }\n\n return new Set(\n [...includeFiles].filter(\n (filePath) => !transformedOutputPaths.has(filePath)\n )\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAwBA,eAAsB,gBACpB,SACA,UACA,iBACA,SACA,YACA,YACA;AACA,KAAI,iBAAiB;EACnB,MAAM,EACJ,eACA,kBACA,gBACA,qBACE,SAAS;EAEb,MAAM,cAAc,kBAClB,eACA,kBACA,gBACA,kBACA,SAAS,SACT,SAAS,cACV;AAED,QAAM,oBAAoB;GACP;GACR;GACG;GACZ,SAAS,SAAS;GAClB,iBAAiB,QAAQ;GACzB,oBAAoB,YAAY,WAC9B,YAAY,UAAU,eAAe;GACvC,SAAS;GACT,oBAAoB,QAAQ;GAC5B,eAAe,QAAQ,iBAAiB,QAAQ;GACjD,CAAC;AAGF,MAAI,cAAc,YAAY,cAAc,GAM1C,OAAM,mBALQ,OAAO,QAAQ,gBAAgB,CAAC,KAAK,CAAC,QAAQ,WAAW;GACrE;GACA,WAAW,KAAK;GAChB,UAAU,KAAK;GAChB,EAEM,EACL,YACA,WAAW,cAAc,IACzB,SACD;;;AAKP,eAAsB,wBACpB,UACA,cACA;CACA,MAAM,sBAAsB,6CAC1B,UACA,aACD;AACD,KAAI,gBAAgB,qBAAqB,SAAS,EAAG;AAErD,OAAM,oBAAoB,UAAU,oBAAoB;AAIxD,KAAI,SAAS,SAAS,gCAAgC;EACpD,MAAM,oBAAoB,SAAS,QAAQ,QACxC,WAAW,WAAW,SAAS,cACjC;AACD,MAAI,kBAAkB,SAAS,EAC7B,OAAM,mBACJ,UACA,mBACA,oBACD;;AAKL,KAAI,SAAS,SAAS,oCAAoC;EACxD,MAAM,oBAAoB,SAAS,QAAQ,QACxC,WAAW,WAAW,SAAS,cACjC;AACD,MAAI,kBAAkB,SAAS,EAC7B,OAAM,uBACJ,UACA,mBACA,oBACD;;AAUL,KALE,SAAS,SAAS,kCAClB,SAAS,SAAS,+BAKlB,OAAM,iBAAiB,UAAU,oBAAoB;AAIvD,KAAI,SAAS,SAAS,kCACpB,OAAM,sBAAsB,UAAU,oBAAoB;AAI5D,KAAI,SAAS,SAAS,6BACpB,OAAM,iBAAiB,UAAU,oBAAoB;AAIvD,KAAI,SAAS,SAAS,UACpB,OAAM,SAAS,SAAS;AAI1B,0BAAyB,UAAU,qBAAqB,mBAAmB,CAAC;;;;;;;;AAS9E,SAAS,6CACP,UACA,cACyB;AACzB,KAAI,CAAC,aAAc,QAAO;CAE1B,MAAM,yCAAyB,IAAI,KAAa;AAChD,MAAK,MAAM,YAAY,2BAA2B;AAChD,MAAI,CAAC,yCAAyC,UAAU,SAAS,CAAE;AAEnE,OAAK,MAAM,cAAc,SAAS,MAAM,cAAc,aAAa,EAAE,CACnE,wBAAuB,IAAI,YAAY,WAAW,CAAC;;AAGvD,KAAI,uBAAuB,SAAS,EAAG,QAAO;CAE9C,MAAM,EAAE,eAAe,kBAAkB,gBAAgB,qBACvD,SAAS;CACX,MAAM,cAAc,kBAClB,eACA,kBACA,gBACA,kBACA,SAAS,SACT,SAAS,cACV;CAED,MAAM,yCAAyB,IAAI,KAAa;AAChD,MAAK,MAAM,iBAAiB,OAAO,OAAO,YAAY,CACpD,MAAK,MAAM,CAAC,YAAY,eAAe,OAAO,QAAQ,cAAc,CAClE,KAAI,uBAAuB,IAAI,WAAW,CACxC,wBAAuB,IAAI,WAAW;AAK5C,QAAO,IAAI,IACT,CAAC,GAAG,aAAa,CAAC,QACf,aAAa,CAAC,uBAAuB,IAAI,SAAS,CACpD,CACF"}
@@ -0,0 +1,5 @@
1
+ import type { Settings } from '../../../types/index.js';
2
+ /**
3
+ * Runs all Mintlify-specific postprocessing on translated files.
4
+ */
5
+ export declare function postprocessMintlify(settings: Settings, includeFiles?: Set<string>): Promise<void>;
@@ -0,0 +1,16 @@
1
+ import localizeMintlifyFrontmatterUrls from "../../../utils/localizeMintlifyFrontmatterUrls.js";
2
+ import processOpenApi from "../../../utils/processOpenApi.js";
3
+ //#region src/formats/files/postprocess/mintlify.ts
4
+ /**
5
+ * Runs all Mintlify-specific postprocessing on translated files.
6
+ */
7
+ async function postprocessMintlify(settings, includeFiles) {
8
+ if (settings.framework !== "mintlify" && !settings.options?.mintlify?.openapi) return;
9
+ await processOpenApi(settings, includeFiles);
10
+ if (settings.framework !== "mintlify") return;
11
+ await localizeMintlifyFrontmatterUrls(settings, includeFiles);
12
+ }
13
+ //#endregion
14
+ export { postprocessMintlify };
15
+
16
+ //# sourceMappingURL=mintlify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mintlify.js","names":[],"sources":["../../../../src/formats/files/postprocess/mintlify.ts"],"sourcesContent":["import type { Settings } from '../../../types/index.js';\nimport localizeMintlifyFrontmatterUrls from '../../../utils/localizeMintlifyFrontmatterUrls.js';\nimport processOpenApi from '../../../utils/processOpenApi.js';\n\n/**\n * Runs all Mintlify-specific postprocessing on translated files.\n */\nexport async function postprocessMintlify(\n settings: Settings,\n includeFiles?: Set<string>\n) {\n if (settings.framework !== 'mintlify' && !settings.options?.mintlify?.openapi)\n return;\n\n await processOpenApi(settings, includeFiles);\n\n if (settings.framework !== 'mintlify') return;\n\n await localizeMintlifyFrontmatterUrls(settings, includeFiles);\n}\n"],"mappings":";;;;;;AAOA,eAAsB,oBACpB,UACA,cACA;AACA,KAAI,SAAS,cAAc,cAAc,CAAC,SAAS,SAAS,UAAU,QACpE;AAEF,OAAM,eAAe,UAAU,aAAa;AAE5C,KAAI,SAAS,cAAc,WAAY;AAEvC,OAAM,gCAAgC,UAAU,aAAa"}
@@ -1 +1 @@
1
- export declare const PACKAGE_VERSION = "2.14.38";
1
+ export declare const PACKAGE_VERSION = "2.14.39";
@@ -1,5 +1,5 @@
1
1
  //#region src/generated/version.ts
2
- const PACKAGE_VERSION = "2.14.38";
2
+ const PACKAGE_VERSION = "2.14.39";
3
3
  //#endregion
4
4
  export { PACKAGE_VERSION };
5
5
 
@@ -1 +1 @@
1
- {"version":3,"file":"version.js","names":[],"sources":["../../src/generated/version.ts"],"sourcesContent":["// This file is auto-generated. Do not edit manually.\nexport const PACKAGE_VERSION = '2.14.38';\n"],"mappings":";AACA,MAAa,kBAAkB"}
1
+ {"version":3,"file":"version.js","names":[],"sources":["../../src/generated/version.ts"],"sourcesContent":["// This file is auto-generated. Do not edit manually.\nexport const PACKAGE_VERSION = '2.14.39';\n"],"mappings":";AACA,MAAa,kBAAkB"}
@@ -0,0 +1,6 @@
1
+ import type { Settings } from '../types/index.js';
2
+ export declare function localizeMintlifyFrontmatterUrlForContent(content: string, targetLocale: string, knownLocaleValues: string[]): {
3
+ content: string;
4
+ changed: boolean;
5
+ };
6
+ export default function localizeMintlifyFrontmatterUrls(settings: Settings, includeFiles?: Set<string>): Promise<void>;
@@ -0,0 +1,91 @@
1
+ import { createFileMapping } from "../formats/files/fileMapping.js";
2
+ import path from "node:path";
3
+ import fs from "node:fs";
4
+ import YAML, { isMap, isScalar } from "yaml";
5
+ import { unified } from "unified";
6
+ import remarkParse from "remark-parse";
7
+ import remarkFrontmatter from "remark-frontmatter";
8
+ //#region src/utils/localizeMintlifyFrontmatterUrls.ts
9
+ const SKIPPABLE_URL_REGEX = /^(?:[a-z][a-z0-9+.-]*:|\/\/|#|\.\/|\.\.\/)/i;
10
+ function getYamlFrontmatter(content) {
11
+ let tree;
12
+ try {
13
+ tree = unified().use(remarkParse).use(remarkFrontmatter, ["yaml"]).parse(content);
14
+ } catch {
15
+ return null;
16
+ }
17
+ const yamlNode = tree.children.find((node) => node.type === "yaml");
18
+ if (!yamlNode || !yamlNode.position || yamlNode.position.start?.offset === void 0 || yamlNode.position.end?.offset === void 0) return null;
19
+ return yamlNode;
20
+ }
21
+ function normalizeMintlifyFrontmatterUrl(url, targetLocale, knownLocales) {
22
+ const trimmed = url.trim();
23
+ if (!trimmed || SKIPPABLE_URL_REGEX.test(trimmed)) return null;
24
+ const leadingWhitespace = url.match(/^\s*/)?.[0] ?? "";
25
+ const trailingWhitespace = url.match(/\s*$/)?.[0] ?? "";
26
+ const pathBody = trimmed.replace(/^\/+/, "");
27
+ const [firstSegment, ...restSegments] = pathBody.split("/");
28
+ if (firstSegment === targetLocale) {
29
+ const normalized = `${leadingWhitespace}${pathBody}${trailingWhitespace}`;
30
+ return normalized === url ? null : normalized;
31
+ }
32
+ const unprefixedPath = knownLocales.has(firstSegment) ? restSegments.join("/") : pathBody;
33
+ const normalized = `${leadingWhitespace}${unprefixedPath ? `${targetLocale}/${unprefixedPath}` : `${targetLocale}/`}${trailingWhitespace}`;
34
+ return normalized === url ? null : normalized;
35
+ }
36
+ function localizeMintlifyFrontmatterUrlForContent(content, targetLocale, knownLocaleValues) {
37
+ const yamlNode = getYamlFrontmatter(content);
38
+ if (!yamlNode) return {
39
+ content,
40
+ changed: false
41
+ };
42
+ const frontmatterRaw = yamlNode.value || "";
43
+ const doc = YAML.parseDocument(frontmatterRaw, {
44
+ prettyErrors: false,
45
+ keepSourceTokens: true
46
+ });
47
+ if (doc.errors?.length || !isMap(doc.contents)) return {
48
+ content,
49
+ changed: false
50
+ };
51
+ const urlNode = doc.get("url", true);
52
+ if (!isScalar(urlNode) || typeof urlNode.value !== "string") return {
53
+ content,
54
+ changed: false
55
+ };
56
+ const localizedUrl = normalizeMintlifyFrontmatterUrl(urlNode.value, targetLocale, new Set(knownLocaleValues));
57
+ if (!localizedUrl) return {
58
+ content,
59
+ changed: false
60
+ };
61
+ urlNode.value = localizedUrl;
62
+ const start = yamlNode.position.start.offset;
63
+ const end = yamlNode.position.end.offset;
64
+ const newline = content.includes("\r\n") ? "\r\n" : "\n";
65
+ const frontmatter = doc.toString().trimEnd().replace(/\n/g, newline);
66
+ return {
67
+ content: `${content.slice(0, start)}---${newline}${frontmatter}${newline}---${content.slice(end)}`,
68
+ changed: true
69
+ };
70
+ }
71
+ function shouldProcessFile(filePath, includeFiles) {
72
+ if (!includeFiles) return true;
73
+ return includeFiles.has(filePath) || includeFiles.has(path.resolve(filePath));
74
+ }
75
+ async function localizeMintlifyFrontmatterUrls(settings, includeFiles) {
76
+ if (settings.framework !== "mintlify" || !settings.files) return;
77
+ const fileMapping = createFileMapping(settings.files.resolvedPaths, settings.files.placeholderPaths, settings.files.transformPaths ?? {}, settings.files.transformFormats ?? {}, settings.locales, settings.defaultLocale);
78
+ const knownLocaleValues = [settings.defaultLocale, ...settings.locales];
79
+ for (const [locale, filesMap] of Object.entries(fileMapping)) {
80
+ const targetFiles = Object.values(filesMap).filter((filePath) => (filePath.endsWith(".md") || filePath.endsWith(".mdx")) && shouldProcessFile(filePath, includeFiles));
81
+ await Promise.all(targetFiles.map(async (filePath) => {
82
+ if (!fs.existsSync(filePath)) return;
83
+ const result = localizeMintlifyFrontmatterUrlForContent(await fs.promises.readFile(filePath, "utf8"), locale, knownLocaleValues);
84
+ if (result.changed) await fs.promises.writeFile(filePath, result.content, "utf8");
85
+ }));
86
+ }
87
+ }
88
+ //#endregion
89
+ export { localizeMintlifyFrontmatterUrls as default, localizeMintlifyFrontmatterUrlForContent };
90
+
91
+ //# sourceMappingURL=localizeMintlifyFrontmatterUrls.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"localizeMintlifyFrontmatterUrls.js","names":[],"sources":["../../src/utils/localizeMintlifyFrontmatterUrls.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport { unified } from 'unified';\nimport remarkParse from 'remark-parse';\nimport remarkFrontmatter from 'remark-frontmatter';\nimport YAML, { isMap, isScalar } from 'yaml';\nimport type { Content, Root, Yaml } from 'mdast';\nimport { createFileMapping } from '../formats/files/fileMapping.js';\nimport type { Settings } from '../types/index.js';\n\nconst SKIPPABLE_URL_REGEX = /^(?:[a-z][a-z0-9+.-]*:|\\/\\/|#|\\.\\/|\\.\\.\\/)/i;\n\nfunction getYamlFrontmatter(content: string): Yaml | null {\n let tree: Root;\n try {\n tree = unified()\n .use(remarkParse)\n .use(remarkFrontmatter, ['yaml'])\n .parse(content) as Root;\n } catch {\n return null;\n }\n\n const yamlNode = (tree.children as Content[]).find(\n (node): node is Yaml => (node as Yaml).type === 'yaml'\n );\n if (\n !yamlNode ||\n !yamlNode.position ||\n yamlNode.position.start?.offset === undefined ||\n yamlNode.position.end?.offset === undefined\n ) {\n return null;\n }\n return yamlNode;\n}\n\nfunction normalizeMintlifyFrontmatterUrl(\n url: string,\n targetLocale: string,\n knownLocales: Set<string>\n): string | null {\n const trimmed = url.trim();\n if (!trimmed || SKIPPABLE_URL_REGEX.test(trimmed)) {\n return null;\n }\n\n const leadingWhitespace = url.match(/^\\s*/)?.[0] ?? '';\n const trailingWhitespace = url.match(/\\s*$/)?.[0] ?? '';\n const pathBody = trimmed.replace(/^\\/+/, '');\n const [firstSegment, ...restSegments] = pathBody.split('/');\n\n if (firstSegment === targetLocale) {\n const normalized = `${leadingWhitespace}${pathBody}${trailingWhitespace}`;\n return normalized === url ? null : normalized;\n }\n\n const unprefixedPath = knownLocales.has(firstSegment)\n ? restSegments.join('/')\n : pathBody;\n const localizedPath = unprefixedPath\n ? `${targetLocale}/${unprefixedPath}`\n : `${targetLocale}/`;\n const normalized = `${leadingWhitespace}${localizedPath}${trailingWhitespace}`;\n\n return normalized === url ? null : normalized;\n}\n\nexport function localizeMintlifyFrontmatterUrlForContent(\n content: string,\n targetLocale: string,\n knownLocaleValues: string[]\n): { content: string; changed: boolean } {\n const yamlNode = getYamlFrontmatter(content);\n if (!yamlNode) {\n return { content, changed: false };\n }\n\n const frontmatterRaw: string = yamlNode.value || '';\n const doc = YAML.parseDocument(frontmatterRaw, {\n prettyErrors: false,\n keepSourceTokens: true,\n });\n if (doc.errors?.length || !isMap(doc.contents)) {\n return { content, changed: false };\n }\n\n const urlNode = doc.get('url', true);\n if (!isScalar(urlNode) || typeof urlNode.value !== 'string') {\n return { content, changed: false };\n }\n\n const localizedUrl = normalizeMintlifyFrontmatterUrl(\n urlNode.value,\n targetLocale,\n new Set(knownLocaleValues)\n );\n if (!localizedUrl) {\n return { content, changed: false };\n }\n\n urlNode.value = localizedUrl;\n\n const start = yamlNode.position!.start.offset as number;\n const end = yamlNode.position!.end.offset as number;\n const newline = content.includes('\\r\\n') ? '\\r\\n' : '\\n';\n const frontmatter = doc.toString().trimEnd().replace(/\\n/g, newline);\n return {\n content: `${content.slice(0, start)}---${newline}${frontmatter}${newline}---${content.slice(end)}`,\n changed: true,\n };\n}\n\nfunction shouldProcessFile(filePath: string, includeFiles?: Set<string>) {\n if (!includeFiles) return true;\n return includeFiles.has(filePath) || includeFiles.has(path.resolve(filePath));\n}\n\nexport default async function localizeMintlifyFrontmatterUrls(\n settings: Settings,\n includeFiles?: Set<string>\n) {\n if (settings.framework !== 'mintlify' || !settings.files) return;\n\n const fileMapping = createFileMapping(\n settings.files.resolvedPaths,\n settings.files.placeholderPaths,\n settings.files.transformPaths ?? {},\n settings.files.transformFormats ?? {},\n settings.locales,\n settings.defaultLocale\n );\n const knownLocaleValues = [settings.defaultLocale, ...settings.locales];\n\n for (const [locale, filesMap] of Object.entries(fileMapping)) {\n const targetFiles = Object.values(filesMap).filter(\n (filePath) =>\n (filePath.endsWith('.md') || filePath.endsWith('.mdx')) &&\n shouldProcessFile(filePath, includeFiles)\n );\n\n await Promise.all(\n targetFiles.map(async (filePath) => {\n if (!fs.existsSync(filePath)) return;\n\n const content = await fs.promises.readFile(filePath, 'utf8');\n const result = localizeMintlifyFrontmatterUrlForContent(\n content,\n locale,\n knownLocaleValues\n );\n if (result.changed) {\n await fs.promises.writeFile(filePath, result.content, 'utf8');\n }\n })\n );\n }\n}\n"],"mappings":"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"}
@@ -135,6 +135,14 @@ function rewriteDocsJsonOpenApi(content, filePath, localeHint, specs, fileMappin
135
135
  changed = true;
136
136
  }
137
137
  }
138
+ const directoryValue = openapiConfig.directory;
139
+ if (typeof directoryValue === "string") {
140
+ const localizedDirectory = localizeDocsJsonDirectory(directoryValue, locale, defaultLocale, new Set([defaultLocale, ...Object.keys(fileMappingRel)]));
141
+ if (localizedDirectory && localizedDirectory !== directoryValue) {
142
+ openapiConfig.directory = localizedDirectory;
143
+ changed = true;
144
+ }
145
+ }
138
146
  }
139
147
  if (Array.isArray(node.pages)) {
140
148
  const pages = node.pages;
@@ -165,6 +173,23 @@ function stripLocaleFromOpenApiPage(value, locale) {
165
173
  if (!parseOpenApiValue(candidate)) return value;
166
174
  return candidate;
167
175
  }
176
+ function localizeDocsJsonDirectory(directory, locale, defaultLocale, knownLocales) {
177
+ if (locale === defaultLocale) return null;
178
+ const trimmed = directory.trim();
179
+ if (!trimmed || /^(?:[a-z][a-z0-9+.-]*:|\/\/|#|\.\/|\.\.\/)/i.test(trimmed)) return null;
180
+ const leadingWhitespace = directory.match(/^\s*/)?.[0] ?? "";
181
+ const trailingWhitespace = directory.match(/\s*$/)?.[0] ?? "";
182
+ const leadingSlash = trimmed.startsWith("/") ? "/" : "";
183
+ const pathBody = trimmed.replace(/^\/+/, "");
184
+ const [firstSegment, ...restSegments] = pathBody.split("/");
185
+ if (firstSegment === locale) {
186
+ const normalized = `${leadingWhitespace}${leadingSlash}${pathBody}${trailingWhitespace}`;
187
+ return normalized === directory ? null : normalized;
188
+ }
189
+ const unprefixedPath = knownLocales.has(firstSegment) ? restSegments.join("/") : pathBody;
190
+ const normalized = `${leadingWhitespace}${leadingSlash}${unprefixedPath ? `${locale}/${unprefixedPath}` : locale}${trailingWhitespace}`;
191
+ return normalized === directory ? null : normalized;
192
+ }
168
193
  function localizeDocsJsonSpecPath(source, locale, filePath, specs, fileMappingAbs, _fileMappingRel, warnings, configDir) {
169
194
  const matched = matchSpecBySource(source, resolveDocsJsonSpecPath(source, filePath, configDir), specs, warnings);
170
195
  if (!matched) return source;
@@ -1 +1 @@
1
- {"version":3,"file":"processOpenApi.js","names":[],"sources":["../../src/utils/processOpenApi.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport { unified } from 'unified';\nimport remarkParse from 'remark-parse';\nimport remarkFrontmatter from 'remark-frontmatter';\nimport YAML, { isMap, isScalar } from 'yaml';\nimport type { Root, Content, Yaml } from 'mdast';\nimport { logger } from '../console/logger.js';\nimport { createFileMapping } from '../formats/files/fileMapping.js';\nimport { Settings } from '../types/index.js';\n\ntype SpecAnalysis = {\n absPath: string;\n configPath: string; // as provided in config (for formatting)\n operations: Set<string>;\n schemas: Set<string>;\n webhooks: Set<string>;\n};\n\ntype ParsedOpenApiValue =\n | {\n kind: 'operation';\n specPath?: string;\n method: string;\n operationPath: string;\n }\n | {\n kind: 'webhook';\n specPath?: string;\n name: string;\n };\n\ntype ParsedSchemaValue = {\n specPath?: string;\n schemaName: string;\n};\n\nconst HTTP_METHODS = new Set([\n 'GET',\n 'POST',\n 'PUT',\n 'PATCH',\n 'DELETE',\n 'OPTIONS',\n 'HEAD',\n 'TRACE',\n]);\nconst OPENAPI_SPEC_EXTENSIONS = new Set(['.json', '.yaml', '.yml']);\n\n/**\n * Postprocess Mintlify OpenAPI references to point to locale-specific spec files.\n * - Uses openapi.files (ordered) to resolve ambiguities (first match wins).\n * - Relies on the user's json transform rules for locale paths.\n * - Warns on missing/ambiguous references but keeps behavior deterministic.\n */\nexport default async function processOpenApi(\n settings: Settings,\n includeFiles?: Set<string>\n) {\n const openapiConfig = settings.options?.mintlify?.openapi;\n if (!openapiConfig || !openapiConfig.files?.length) return;\n if (!settings.files) return;\n\n const configDir = path.dirname(settings.config);\n const specAnalyses = buildSpecAnalyses(openapiConfig.files, configDir);\n if (!specAnalyses.length) return;\n\n const warnings = new Set<string>();\n const { resolvedPaths, placeholderPaths, transformPaths, transformFormats } =\n settings.files;\n const fileMapping = createFileMapping(\n resolvedPaths,\n placeholderPaths,\n transformPaths,\n transformFormats,\n settings.locales,\n settings.defaultLocale\n );\n const fileMappingAbs: Record<string, Record<string, string>> = {};\n for (const [locale, mapping] of Object.entries(fileMapping)) {\n fileMappingAbs[locale] = {};\n for (const [src, dest] of Object.entries(mapping)) {\n const absSrc = path.resolve(configDir, src);\n const absDest = path.resolve(configDir, dest);\n fileMappingAbs[locale][absSrc] = absDest;\n }\n }\n\n // Also rewrite default-locale source files so they use the deterministic spec selection\n const defaultFiles = [\n ...(resolvedPaths.mdx || []),\n ...(resolvedPaths.md || []),\n ];\n for (const filePath of defaultFiles) {\n if (!fs.existsSync(filePath)) continue;\n const content = fs.readFileSync(filePath, 'utf8');\n const updated = rewriteFrontmatter(\n content,\n filePath,\n settings.defaultLocale,\n specAnalyses,\n fileMappingAbs,\n warnings,\n configDir\n );\n if (updated?.changed) {\n await fs.promises.writeFile(filePath, updated.content, 'utf8');\n }\n }\n\n for (const [locale, filesMap] of Object.entries(fileMapping)) {\n const targetFiles = Object.values(filesMap).filter(\n (p) =>\n (p.endsWith('.md') || p.endsWith('.mdx')) &&\n (!includeFiles || includeFiles.has(p))\n );\n\n for (const filePath of targetFiles) {\n if (!fs.existsSync(filePath)) continue;\n const content = fs.readFileSync(filePath, 'utf8');\n const updated = rewriteFrontmatter(\n content,\n filePath,\n locale,\n specAnalyses,\n fileMappingAbs,\n warnings,\n configDir\n );\n\n if (updated?.changed) {\n await fs.promises.writeFile(filePath, updated.content, 'utf8');\n }\n }\n }\n\n const docsJsonTargets = collectDocsJsonTargets(\n settings,\n fileMapping,\n includeFiles\n );\n for (const target of docsJsonTargets) {\n if (!fs.existsSync(target.path)) continue;\n const content = fs.readFileSync(target.path, 'utf8');\n const updated = rewriteDocsJsonOpenApi(\n content,\n target.path,\n target.localeHint,\n specAnalyses,\n fileMappingAbs,\n fileMapping,\n warnings,\n configDir,\n settings.defaultLocale\n );\n if (updated?.changed) {\n await fs.promises.writeFile(target.path, updated.content, 'utf8');\n }\n }\n\n for (const message of warnings) {\n logger.warn(message);\n }\n}\n\nfunction collectDocsJsonTargets(\n settings: Settings,\n fileMapping: Record<string, Record<string, string>>,\n includeFiles?: Set<string>\n): Array<{ path: string; localeHint?: string }> {\n const targets: Array<{ path: string; localeHint?: string }> = [];\n const seen = new Map<string, Set<string>>();\n\n const addTarget = (filePath: string, locale?: string) => {\n const canonicalPath = path.resolve(filePath);\n if (\n includeFiles &&\n !includeFiles.has(filePath) &&\n !includeFiles.has(canonicalPath)\n ) {\n return;\n }\n const locales = seen.get(canonicalPath) ?? new Set<string>();\n if (locale) locales.add(locale);\n seen.set(canonicalPath, locales);\n };\n\n if (!includeFiles && settings.files?.resolvedPaths.json) {\n for (const filePath of settings.files.resolvedPaths.json) {\n addTarget(filePath, settings.defaultLocale);\n }\n }\n\n for (const [locale, filesMap] of Object.entries(fileMapping)) {\n for (const filePath of Object.values(filesMap)) {\n if (!filePath.endsWith('.json')) continue;\n addTarget(filePath, locale);\n }\n }\n\n for (const [filePath, locales] of seen.entries()) {\n const localeHint = locales.size === 1 ? Array.from(locales)[0] : undefined;\n targets.push({ path: filePath, localeHint });\n }\n\n return targets;\n}\n\nfunction isMintlifyDocsJson(filePath: string, json: unknown): boolean {\n if (!isRecord(json)) return false;\n const schema = json.$schema;\n if (typeof schema === 'string') {\n return (\n schema.includes('mintlify.com/docs.json') ||\n schema.includes('mintlify.com/mint.json')\n );\n }\n const base = path.basename(filePath);\n return base === 'docs.json' || base === 'mint.json';\n}\n\nfunction rewriteDocsJsonOpenApi(\n content: string,\n filePath: string,\n localeHint: string | undefined,\n specs: SpecAnalysis[],\n fileMappingAbs: Record<string, Record<string, string>>,\n fileMappingRel: Record<string, Record<string, string>>,\n warnings: Set<string>,\n configDir: string,\n defaultLocale: string\n): { changed: boolean; content: string } | null {\n let json: unknown;\n try {\n json = JSON.parse(content);\n } catch {\n return null;\n }\n\n if (!isMintlifyDocsJson(filePath, json)) return null;\n\n let changed = false;\n\n const visitNode = (node: unknown, activeLocale?: string) => {\n if (Array.isArray(node)) {\n node.forEach((item) => visitNode(item, activeLocale));\n return;\n }\n if (!isRecord(node)) return;\n\n let nextLocale = activeLocale;\n if (typeof node.language === 'string') {\n nextLocale = node.language;\n }\n\n const locale = nextLocale || localeHint || defaultLocale;\n\n if (typeof node.openapi === 'string') {\n const sourceValue = node.openapi;\n const localizedSource = localizeDocsJsonSpecPath(\n sourceValue,\n locale,\n filePath,\n specs,\n fileMappingAbs,\n fileMappingRel,\n warnings,\n configDir\n );\n if (localizedSource && localizedSource !== sourceValue) {\n node.openapi = localizedSource;\n changed = true;\n }\n } else if (isRecord(node.openapi)) {\n const openapiConfig = node.openapi as Record<string, unknown>;\n const sourceValue = openapiConfig.source;\n if (typeof sourceValue === 'string') {\n const localizedSource = localizeDocsJsonSpecPath(\n sourceValue,\n locale,\n filePath,\n specs,\n fileMappingAbs,\n fileMappingRel,\n warnings,\n configDir\n );\n if (localizedSource && localizedSource !== sourceValue) {\n openapiConfig.source = localizedSource;\n changed = true;\n }\n }\n }\n\n if (Array.isArray(node.pages)) {\n const pages = node.pages;\n for (let i = 0; i < pages.length; i += 1) {\n const page = pages[i];\n if (typeof page !== 'string') continue;\n const updated = stripLocaleFromOpenApiPage(page, locale);\n if (updated !== page) {\n pages[i] = updated;\n changed = true;\n }\n }\n }\n\n for (const value of Object.values(node)) {\n visitNode(value, nextLocale);\n }\n };\n\n visitNode(json, undefined);\n\n if (!changed) return null;\n return { changed, content: JSON.stringify(json, null, 2) };\n}\n\nfunction stripLocaleFromOpenApiPage(value: string, locale: string): string {\n const trimmed = value.trim();\n const prefix = `${locale}/`;\n if (!trimmed.startsWith(prefix)) return value;\n const candidate = trimmed.slice(prefix.length);\n const parsed = parseOpenApiValue(candidate);\n if (!parsed) return value;\n return candidate;\n}\n\nfunction localizeDocsJsonSpecPath(\n source: string,\n locale: string,\n filePath: string,\n specs: SpecAnalysis[],\n fileMappingAbs: Record<string, Record<string, string>>,\n _fileMappingRel: Record<string, Record<string, string>>,\n warnings: Set<string>,\n configDir: string\n): string | null {\n const resolvedAbs = resolveDocsJsonSpecPath(source, filePath, configDir);\n const matched = matchSpecBySource(source, resolvedAbs, specs, warnings);\n if (!matched) return source;\n\n const localizedSpecPath = resolveLocalizedSpecPath(\n matched,\n locale,\n fileMappingAbs,\n configDir,\n source\n );\n const localizedAbs = resolveDocsJsonSpecPath(\n localizedSpecPath,\n filePath,\n configDir\n );\n if (!fs.existsSync(localizedAbs)) {\n warnings.add(\n `OpenAPI source \"${source}\" localized for locale \"${locale}\" points to a missing file (${localizedAbs}). Keeping original source.`\n );\n return source;\n }\n\n const rel = normalizeSlashes(path.relative(configDir, localizedAbs));\n return formatSpecPathForDocsJson(rel, source);\n}\n\nfunction resolveDocsJsonSpecPath(\n source: string,\n filePath: string,\n configDir: string\n): string {\n if (source.startsWith('/')) {\n return path.resolve(configDir, source.replace(/^\\/+/, ''));\n }\n if (source.startsWith('./') || source.startsWith('../')) {\n return path.resolve(path.dirname(filePath), source);\n }\n return path.resolve(configDir, source);\n}\n\nfunction matchSpecBySource(\n source: string,\n resolvedAbs: string,\n specs: SpecAnalysis[],\n warnings: Set<string>\n): SpecAnalysis | null {\n const exact = specs.find((spec) => samePath(resolvedAbs, spec.absPath));\n if (exact) return exact;\n\n const normalizedExplicit = normalizeSlashes(source).replace(/^\\.?\\/+/, '');\n const explicitWithoutExt = stripExtension(normalizedExplicit);\n const explicitBase = path.basename(normalizedExplicit);\n const explicitBaseWithoutExt = stripExtension(explicitBase);\n const matches = specs.filter((spec) => {\n const configPath = normalizeSlashes(spec.configPath).replace(/^\\.?\\/+/, '');\n const configBase = path.basename(configPath);\n const configPathNoExt = stripExtension(configPath);\n const configBaseNoExt = stripExtension(configBase);\n return (\n configPath === normalizedExplicit ||\n configPathNoExt === explicitWithoutExt ||\n configBase === explicitBase ||\n configBaseNoExt === explicitBaseWithoutExt\n );\n });\n\n if (matches.length === 1) return matches[0];\n if (matches.length > 1) {\n warnings.add(\n `OpenAPI source \"${source}\" matches multiple specs (${matches\n .map((m) => m.configPath)\n .join(\n ', '\n )}). Using the first configured match (${matches[0].configPath}).`\n );\n return matches[0];\n }\n\n return null;\n}\n\nfunction formatSpecPathForDocsJson(\n relativePath: string,\n originalPathText: string\n): string {\n const normalized = normalizeSlashes(relativePath);\n const base = normalized.replace(/^\\.\\//, '').replace(/\\/+/g, '/');\n\n if (originalPathText.startsWith('/')) {\n return `/${base.replace(/^\\/+/, '')}`;\n }\n if (originalPathText.startsWith('../')) {\n return normalized;\n }\n if (originalPathText.startsWith('./')) {\n return `./${base.replace(/^\\/+/, '')}`;\n }\n return base.replace(/^\\/+/, '');\n}\n\n/**\n * Resolve configured OpenAPI files to absolute paths and collect the operations,\n * schemas, and webhooks they expose. Warns and skips when files are missing,\n * unsupported (non-JSON/YAML), or fail to parse so later steps can continue gracefully.\n */\nfunction buildSpecAnalyses(\n openapiFiles: string[],\n configDir: string\n): SpecAnalysis[] {\n const analyses: SpecAnalysis[] = [];\n\n for (const configEntry of openapiFiles) {\n const absPath = path.resolve(configDir, configEntry);\n if (!fs.existsSync(absPath)) {\n logger.warn(`OpenAPI file not found: ${configEntry}`);\n continue;\n }\n const ext = path.extname(absPath).toLowerCase();\n if (!OPENAPI_SPEC_EXTENSIONS.has(ext)) {\n logger.warn(\n `Skipping OpenAPI file (only .json/.yml/.yaml supported): ${configEntry}`\n );\n continue;\n }\n\n let spec: unknown;\n try {\n const raw = fs.readFileSync(absPath, 'utf8');\n spec = ext === '.json' ? JSON.parse(raw) : YAML.parse(raw);\n } catch {\n const format = ext === '.json' ? 'JSON' : 'YAML';\n logger.warn(`Failed to parse OpenAPI ${format}: ${configEntry}`);\n continue;\n }\n\n analyses.push({\n absPath,\n configPath: configEntry,\n operations: extractOperations(spec),\n schemas: extractSchemas(spec),\n webhooks: extractWebhooks(spec),\n });\n }\n\n return analyses;\n}\n\nfunction isRecord(val: unknown): val is Record<string, unknown> {\n return typeof val === 'object' && val !== null;\n}\n\n/**\n * Collect path+method identifiers (e.g., \"POST /foo\") from an OpenAPI spec.\n * Safely no-ops when paths is missing or malformed.\n */\nfunction extractOperations(spec: unknown): Set<string> {\n const ops = new Set<string>();\n if (!isRecord(spec) || !isRecord(spec.paths)) return ops;\n const paths = spec.paths as Record<string, unknown>;\n\n for (const [route, methods] of Object.entries(paths)) {\n if (!isRecord(methods)) continue;\n for (const [method, operation] of Object.entries(methods)) {\n if (!isRecord(operation)) continue;\n const upper = method.toUpperCase();\n if (!HTTP_METHODS.has(upper)) continue;\n ops.add(`${upper} ${route}`);\n }\n }\n return ops;\n}\n\n/**\n * Collect schema names from components.schemas.\n * Returns empty set if components/schemas are missing or malformed.\n */\nfunction extractSchemas(spec: unknown): Set<string> {\n if (!isRecord(spec) || !isRecord(spec.components)) return new Set();\n const components = spec.components as Record<string, unknown>;\n if (!isRecord(components.schemas)) return new Set();\n return new Set(Object.keys(components.schemas as Record<string, unknown>));\n}\n\n/**\n * Collect webhook names from webhooks (OpenAPI 3.1+).\n * Returns empty set if webhooks is missing or malformed.\n */\nfunction extractWebhooks(spec: unknown): Set<string> {\n if (!isRecord(spec) || !isRecord(spec.webhooks)) return new Set();\n return new Set(Object.keys(spec.webhooks as Record<string, unknown>));\n}\n\n/**\n * Parse MDX/MD frontmatter, rewrite openapi/openapi-schema entries to the\n * resolved (possibly localized) spec path, and return updated content.\n * Uses remark to find the YAML node so the rest of the document remains\n * untouched. When parsing fails or no relevant keys exist, it returns null.\n */\nfunction rewriteFrontmatter(\n content: string,\n filePath: string,\n locale: string,\n specs: SpecAnalysis[],\n fileMapping: Record<string, Record<string, string>>,\n warnings: Set<string>,\n configDir: string\n): { changed: boolean; content: string } | null {\n let tree: Root;\n try {\n tree = unified()\n .use(remarkParse)\n .use(remarkFrontmatter, ['yaml', 'toml'])\n .parse(content) as Root;\n } catch {\n return null;\n }\n\n const yamlNode = (tree.children as Content[]).find(\n (node): node is Yaml => (node as Yaml).type === 'yaml'\n );\n if (\n !yamlNode ||\n !yamlNode.position ||\n yamlNode.position.start?.offset === undefined\n ) {\n return null;\n }\n\n const start = yamlNode.position.start.offset as number;\n const end = yamlNode.position.end.offset as number;\n const frontmatterRaw: string = yamlNode.value || '';\n\n const doc = YAML.parseDocument(frontmatterRaw, {\n prettyErrors: false,\n keepSourceTokens: true,\n });\n if (doc.errors?.length) return null;\n if (!isMap(doc.contents)) return null;\n\n let changed = false;\n\n const openapiNode = doc.get('openapi', true);\n if (isScalar(openapiNode) && typeof openapiNode.value === 'string') {\n const parsedValue = parseOpenApiValue(openapiNode.value);\n if (parsedValue) {\n const matchKey =\n parsedValue.kind === 'operation'\n ? {\n type: 'operation' as const,\n key: `${parsedValue.method.toUpperCase()} ${parsedValue.operationPath}`,\n }\n : { type: 'webhook' as const, key: parsedValue.name };\n\n const spec = resolveSpec(\n parsedValue.specPath,\n specs,\n filePath,\n configDir,\n warnings,\n describeOpenApiRef(parsedValue),\n matchKey\n );\n if (spec) {\n const descriptor = formatOpenApiDescriptor(parsedValue);\n const localizedSpecPath = resolveLocalizedSpecPath(\n spec,\n locale,\n fileMapping,\n configDir,\n parsedValue.specPath || spec.configPath\n );\n const newValue = `${localizedSpecPath} ${descriptor}`.trim();\n if (newValue !== openapiNode.value) {\n doc.set('openapi', newValue);\n changed = true;\n }\n }\n }\n }\n\n const schemaNode = doc.get('openapi-schema', true);\n if (isScalar(schemaNode) && typeof schemaNode.value === 'string') {\n const parsedValue = parseSchemaValue(schemaNode.value);\n if (parsedValue) {\n const spec = resolveSpec(\n parsedValue.specPath,\n specs,\n filePath,\n configDir,\n warnings,\n `schema \"${parsedValue.schemaName}\"`,\n { type: 'schema', key: parsedValue.schemaName }\n );\n if (spec) {\n const localizedSpecPath = resolveLocalizedSpecPath(\n spec,\n locale,\n fileMapping,\n configDir,\n parsedValue.specPath || spec.configPath\n );\n const newValue =\n `${localizedSpecPath} ${parsedValue.schemaName}`.trim();\n if (newValue !== schemaNode.value) {\n doc.set('openapi-schema', newValue);\n changed = true;\n }\n }\n }\n }\n\n if (!changed) return null;\n\n const fmString = doc.toString().trimEnd();\n const rebuilt = `${content.slice(0, start)}---\\n${fmString}\\n---${content.slice(end)}`;\n return { changed, content: rebuilt };\n}\n\nfunction stripWrappingQuotes(value: string): string {\n return value.trim().replace(/^['\"]|['\"]$/g, '');\n}\n\n/**\n * Parse frontmatter openapi string into spec/method/path or webhook.\n * Supports optional leading spec file, the webhook keyword, quoted values,\n * and forgiving whitespace. Returns null when the structure is unrecognized.\n */\nfunction parseOpenApiValue(value: string): ParsedOpenApiValue | null {\n const stripped = stripWrappingQuotes(value);\n const tokens = stripped.split(/\\s+/).filter(Boolean);\n if (!tokens.length) return null;\n\n let cursor = 0;\n let specPath: string | undefined;\n const first = tokens[0];\n const second = tokens[1];\n const methodCandidate = second?.toUpperCase();\n const firstLooksLikeSpec =\n hasOpenApiSpecExtension(first) ||\n (second &&\n (second.toLowerCase() === 'webhook' ||\n (methodCandidate && HTTP_METHODS.has(methodCandidate))));\n\n if (firstLooksLikeSpec) {\n specPath = tokens[0];\n cursor = 1;\n }\n if (cursor >= tokens.length) return null;\n\n const keyword = tokens[cursor];\n if (keyword.toLowerCase() === 'webhook') {\n const name = tokens.slice(cursor + 1).join(' ');\n if (!name) return null;\n return { kind: 'webhook', specPath, name };\n }\n\n const method = keyword.toUpperCase();\n if (!HTTP_METHODS.has(method)) return null;\n const operationPath = tokens.slice(cursor + 1).join(' ');\n if (!operationPath) return null;\n return { kind: 'operation', specPath, method, operationPath };\n}\n\n/**\n * Parse frontmatter openapi-schema string into spec/schemaName.\n * Accepts optional leading spec file and quoted values; returns null on invalid\n * shapes so callers can skip rewrites gracefully.\n */\nfunction parseSchemaValue(value: string): ParsedSchemaValue | null {\n const stripped = stripWrappingQuotes(value);\n const tokens = stripped.split(/\\s+/).filter(Boolean);\n if (!tokens.length) return null;\n let cursor = 0;\n let specPath: string | undefined;\n if (hasOpenApiSpecExtension(tokens[0])) {\n specPath = tokens[0];\n cursor = 1;\n }\n const schemaName = tokens.slice(cursor).join(' ');\n if (!schemaName) return null;\n return { specPath, schemaName };\n}\n\n/**\n * Choose which configured spec a reference should use.\n * - If an explicit spec path is provided, resolve it relative to the config\n * and the referencing file, warn when unknown, and bail.\n * - Otherwise, try to match by operation/webhook/schema name; resolve\n * ambiguity using config order and warn when ambiguous or missing.\n */\nfunction resolveSpec(\n explicitPath: string | undefined,\n specs: SpecAnalysis[],\n filePath: string,\n configDir: string,\n warnings: Set<string>,\n refDescription: string,\n match: { type: 'operation' | 'webhook' | 'schema'; key: string }\n): SpecAnalysis | null {\n if (!specs.length) return null;\n\n if (explicitPath) {\n const normalizedExplicit = normalizeSlashes(\n explicitPath.replace(/^\\.?\\/+/, '')\n );\n const candidates = [\n path.resolve(configDir, normalizedExplicit),\n path.resolve(path.dirname(filePath), normalizedExplicit),\n ];\n const foundSpec = specs.find((spec) => {\n const normalizedSpecPath = normalizeSlashes(spec.absPath);\n return candidates.some((candidate) =>\n samePath(candidate, normalizedSpecPath)\n );\n });\n if (foundSpec) {\n if (specHasMatch(foundSpec, match)) {\n return foundSpec;\n }\n\n const alternatives = specs.filter(\n (spec) => spec !== foundSpec && specHasMatch(spec, match)\n );\n if (alternatives.length === 1) {\n warnings.add(\n `OpenAPI reference ${refDescription} in ${filePath} points to ${foundSpec.configPath}, but the entry was not found there. Using ${alternatives[0].configPath} instead.`\n );\n return alternatives[0];\n }\n if (alternatives.length > 1) {\n warnings.add(\n `OpenAPI reference ${refDescription} in ${filePath} points to ${foundSpec.configPath}, but the entry was not found there and matches multiple specs (${alternatives\n .map((spec) => spec.configPath)\n .join(', ')}). Skipping localization for this reference.`\n );\n return null;\n }\n\n warnings.add(\n `OpenAPI reference ${refDescription} in ${filePath} points to ${foundSpec.configPath}, but the entry was not found in any configured spec. Skipping localization for this reference.`\n );\n return null;\n }\n\n const explicitWithoutExt = stripExtension(normalizedExplicit);\n const explicitBase = path.basename(normalizedExplicit);\n const explicitBaseWithoutExt = stripExtension(explicitBase);\n const matches = specs.filter((spec) => {\n const configPath = normalizeSlashes(spec.configPath).replace(\n /^\\.?\\/+/,\n ''\n );\n const configBase = path.basename(configPath);\n const configPathNoExt = stripExtension(configPath);\n const configBaseNoExt = stripExtension(configBase);\n return (\n configPath === normalizedExplicit ||\n configPathNoExt === explicitWithoutExt ||\n configBase === explicitBase ||\n configBaseNoExt === explicitBaseWithoutExt\n );\n });\n if (matches.length === 1) return matches[0];\n if (matches.length > 1) {\n warnings.add(\n `OpenAPI reference ${refDescription} in ${filePath} matches multiple specs (${matches\n .map((m) => m.configPath)\n .join(\n ', '\n )}). Using the first configured match (${matches[0].configPath}).`\n );\n return matches[0];\n }\n\n warnings.add(\n `OpenAPI reference ${refDescription} in ${filePath} points to an unconfigured spec (${explicitPath}). Skipping localization for this reference.`\n );\n return null;\n }\n\n // No explicit spec: try to find by contents\n const matches = specs.filter((spec) => {\n if (match.type === 'schema') {\n return spec.schemas.has(match.key);\n }\n if (match.type === 'webhook') {\n return spec.webhooks.has(match.key);\n }\n // operation\n return spec.operations.has(match.key);\n });\n\n if (matches.length === 1) return matches[0];\n if (matches.length > 1) {\n warnings.add(\n `OpenAPI reference ${refDescription} in ${filePath} is available in multiple specs. Skipping localization for this reference.`\n );\n return null;\n }\n\n warnings.add(\n `OpenAPI reference ${refDescription} in ${filePath} was not found in any configured spec. Skipping localization for this reference.`\n );\n return null;\n}\n\nfunction specHasMatch(\n spec: SpecAnalysis,\n match: { type: 'operation' | 'webhook' | 'schema'; key: string }\n): boolean {\n if (match.type === 'schema') {\n return spec.schemas.has(match.key);\n }\n if (match.type === 'webhook') {\n return spec.webhooks.has(match.key);\n }\n return spec.operations.has(match.key);\n}\n\n/**\n * Map a spec to the locale-specific file path when available and normalize it\n * for frontmatter. Falls back to the source spec when the locale copy does\n * not exist to preserve deterministic behavior.\n */\nfunction resolveLocalizedSpecPath(\n spec: SpecAnalysis,\n locale: string,\n fileMapping: Record<string, Record<string, string>>,\n configDir: string,\n originalPathText?: string\n): string {\n const mapping = fileMapping[locale]?.[spec.absPath];\n const chosenAbs = mapping || spec.absPath;\n const rel = normalizeSlashes(path.relative(configDir, chosenAbs));\n const rooted = `/${rel.replace(/^\\/+/, '')}`;\n return formatSpecPathForFrontmatter(\n rooted,\n originalPathText || spec.configPath\n );\n}\n\n/**\n * Format the path that will be written back to frontmatter:\n * - Preserve the user's absolute style when they used a leading slash.\n * - Preserve upward relative references (../) exactly.\n * - Otherwise return a repo-root-relative path with a leading slash so Mintlify\n * resolves consistently regardless of the MDX file location.\n */\nfunction formatSpecPathForFrontmatter(\n relativePath: string,\n originalPathText: string\n): string {\n const normalized = normalizeSlashes(relativePath);\n const base = normalized.replace(/^\\.\\//, '').replace(/\\/+/g, '/');\n\n if (originalPathText.startsWith('/')) {\n // Force repo-root absolute style\n return `/${base.replace(/^\\/+/, '')}`;\n }\n\n if (originalPathText.startsWith('../')) {\n // Preserve explicit relative upward references\n return normalized;\n }\n\n // Default to repo-root relative with leading slash to avoid resolving relative to the MDX directory\n return `/${base.replace(/^\\/+/, '')}`;\n}\n\n/** Normalize the descriptive portion after the spec path for frontmatter. */\nfunction formatOpenApiDescriptor(value: ParsedOpenApiValue): string {\n if (value.kind === 'webhook') return `webhook ${value.name}`;\n return `${value.method.toUpperCase()} ${value.operationPath}`;\n}\n\n/** Human-readable description a specific OpenAPI reference. */\nfunction describeOpenApiRef(value: ParsedOpenApiValue): string {\n if (value.kind === 'webhook') return `webhook ${value.name}`;\n return `${value.method.toUpperCase()} ${value.operationPath}`;\n}\n\n/** Remove a single trailing file extension while preserving directory segments. */\nfunction stripExtension(p: string): string {\n const parsed = path.parse(p);\n return normalizeSlashes(path.join(parsed.dir, parsed.name));\n}\n\nfunction hasOpenApiSpecExtension(value: string): boolean {\n return OPENAPI_SPEC_EXTENSIONS.has(path.extname(value).toLowerCase());\n}\n\n/** Normalize separators for stable comparisons and output. */\nfunction normalizeSlashes(p: string): string {\n return p.replace(/\\\\/g, '/');\n}\n\n/** Compare paths after resolution to avoid casing/separator mismatches. */\nfunction samePath(a: string, b: string): boolean {\n return path.resolve(a) === path.resolve(b);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"processOpenApi.js","names":[],"sources":["../../src/utils/processOpenApi.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport { unified } from 'unified';\nimport remarkParse from 'remark-parse';\nimport remarkFrontmatter from 'remark-frontmatter';\nimport YAML, { isMap, isScalar } from 'yaml';\nimport type { Root, Content, Yaml } from 'mdast';\nimport { logger } from '../console/logger.js';\nimport { createFileMapping } from '../formats/files/fileMapping.js';\nimport { Settings } from '../types/index.js';\n\ntype SpecAnalysis = {\n absPath: string;\n configPath: string; // as provided in config (for formatting)\n operations: Set<string>;\n schemas: Set<string>;\n webhooks: Set<string>;\n};\n\ntype ParsedOpenApiValue =\n | {\n kind: 'operation';\n specPath?: string;\n method: string;\n operationPath: string;\n }\n | {\n kind: 'webhook';\n specPath?: string;\n name: string;\n };\n\ntype ParsedSchemaValue = {\n specPath?: string;\n schemaName: string;\n};\n\nconst HTTP_METHODS = new Set([\n 'GET',\n 'POST',\n 'PUT',\n 'PATCH',\n 'DELETE',\n 'OPTIONS',\n 'HEAD',\n 'TRACE',\n]);\nconst OPENAPI_SPEC_EXTENSIONS = new Set(['.json', '.yaml', '.yml']);\n\n/**\n * Postprocess Mintlify OpenAPI references to point to locale-specific spec files.\n * - Uses openapi.files (ordered) to resolve ambiguities (first match wins).\n * - Relies on the user's json transform rules for locale paths.\n * - Warns on missing/ambiguous references but keeps behavior deterministic.\n */\nexport default async function processOpenApi(\n settings: Settings,\n includeFiles?: Set<string>\n) {\n const openapiConfig = settings.options?.mintlify?.openapi;\n if (!openapiConfig || !openapiConfig.files?.length) return;\n if (!settings.files) return;\n\n const configDir = path.dirname(settings.config);\n const specAnalyses = buildSpecAnalyses(openapiConfig.files, configDir);\n if (!specAnalyses.length) return;\n\n const warnings = new Set<string>();\n const { resolvedPaths, placeholderPaths, transformPaths, transformFormats } =\n settings.files;\n const fileMapping = createFileMapping(\n resolvedPaths,\n placeholderPaths,\n transformPaths,\n transformFormats,\n settings.locales,\n settings.defaultLocale\n );\n const fileMappingAbs: Record<string, Record<string, string>> = {};\n for (const [locale, mapping] of Object.entries(fileMapping)) {\n fileMappingAbs[locale] = {};\n for (const [src, dest] of Object.entries(mapping)) {\n const absSrc = path.resolve(configDir, src);\n const absDest = path.resolve(configDir, dest);\n fileMappingAbs[locale][absSrc] = absDest;\n }\n }\n\n // Also rewrite default-locale source files so they use the deterministic spec selection\n const defaultFiles = [\n ...(resolvedPaths.mdx || []),\n ...(resolvedPaths.md || []),\n ];\n for (const filePath of defaultFiles) {\n if (!fs.existsSync(filePath)) continue;\n const content = fs.readFileSync(filePath, 'utf8');\n const updated = rewriteFrontmatter(\n content,\n filePath,\n settings.defaultLocale,\n specAnalyses,\n fileMappingAbs,\n warnings,\n configDir\n );\n if (updated?.changed) {\n await fs.promises.writeFile(filePath, updated.content, 'utf8');\n }\n }\n\n for (const [locale, filesMap] of Object.entries(fileMapping)) {\n const targetFiles = Object.values(filesMap).filter(\n (p) =>\n (p.endsWith('.md') || p.endsWith('.mdx')) &&\n (!includeFiles || includeFiles.has(p))\n );\n\n for (const filePath of targetFiles) {\n if (!fs.existsSync(filePath)) continue;\n const content = fs.readFileSync(filePath, 'utf8');\n const updated = rewriteFrontmatter(\n content,\n filePath,\n locale,\n specAnalyses,\n fileMappingAbs,\n warnings,\n configDir\n );\n\n if (updated?.changed) {\n await fs.promises.writeFile(filePath, updated.content, 'utf8');\n }\n }\n }\n\n const docsJsonTargets = collectDocsJsonTargets(\n settings,\n fileMapping,\n includeFiles\n );\n for (const target of docsJsonTargets) {\n if (!fs.existsSync(target.path)) continue;\n const content = fs.readFileSync(target.path, 'utf8');\n const updated = rewriteDocsJsonOpenApi(\n content,\n target.path,\n target.localeHint,\n specAnalyses,\n fileMappingAbs,\n fileMapping,\n warnings,\n configDir,\n settings.defaultLocale\n );\n if (updated?.changed) {\n await fs.promises.writeFile(target.path, updated.content, 'utf8');\n }\n }\n\n for (const message of warnings) {\n logger.warn(message);\n }\n}\n\nfunction collectDocsJsonTargets(\n settings: Settings,\n fileMapping: Record<string, Record<string, string>>,\n includeFiles?: Set<string>\n): Array<{ path: string; localeHint?: string }> {\n const targets: Array<{ path: string; localeHint?: string }> = [];\n const seen = new Map<string, Set<string>>();\n\n const addTarget = (filePath: string, locale?: string) => {\n const canonicalPath = path.resolve(filePath);\n if (\n includeFiles &&\n !includeFiles.has(filePath) &&\n !includeFiles.has(canonicalPath)\n ) {\n return;\n }\n const locales = seen.get(canonicalPath) ?? new Set<string>();\n if (locale) locales.add(locale);\n seen.set(canonicalPath, locales);\n };\n\n if (!includeFiles && settings.files?.resolvedPaths.json) {\n for (const filePath of settings.files.resolvedPaths.json) {\n addTarget(filePath, settings.defaultLocale);\n }\n }\n\n for (const [locale, filesMap] of Object.entries(fileMapping)) {\n for (const filePath of Object.values(filesMap)) {\n if (!filePath.endsWith('.json')) continue;\n addTarget(filePath, locale);\n }\n }\n\n for (const [filePath, locales] of seen.entries()) {\n const localeHint = locales.size === 1 ? Array.from(locales)[0] : undefined;\n targets.push({ path: filePath, localeHint });\n }\n\n return targets;\n}\n\nfunction isMintlifyDocsJson(filePath: string, json: unknown): boolean {\n if (!isRecord(json)) return false;\n const schema = json.$schema;\n if (typeof schema === 'string') {\n return (\n schema.includes('mintlify.com/docs.json') ||\n schema.includes('mintlify.com/mint.json')\n );\n }\n const base = path.basename(filePath);\n return base === 'docs.json' || base === 'mint.json';\n}\n\nfunction rewriteDocsJsonOpenApi(\n content: string,\n filePath: string,\n localeHint: string | undefined,\n specs: SpecAnalysis[],\n fileMappingAbs: Record<string, Record<string, string>>,\n fileMappingRel: Record<string, Record<string, string>>,\n warnings: Set<string>,\n configDir: string,\n defaultLocale: string\n): { changed: boolean; content: string } | null {\n let json: unknown;\n try {\n json = JSON.parse(content);\n } catch {\n return null;\n }\n\n if (!isMintlifyDocsJson(filePath, json)) return null;\n\n let changed = false;\n\n const visitNode = (node: unknown, activeLocale?: string) => {\n if (Array.isArray(node)) {\n node.forEach((item) => visitNode(item, activeLocale));\n return;\n }\n if (!isRecord(node)) return;\n\n let nextLocale = activeLocale;\n if (typeof node.language === 'string') {\n nextLocale = node.language;\n }\n\n const locale = nextLocale || localeHint || defaultLocale;\n\n if (typeof node.openapi === 'string') {\n const sourceValue = node.openapi;\n const localizedSource = localizeDocsJsonSpecPath(\n sourceValue,\n locale,\n filePath,\n specs,\n fileMappingAbs,\n fileMappingRel,\n warnings,\n configDir\n );\n if (localizedSource && localizedSource !== sourceValue) {\n node.openapi = localizedSource;\n changed = true;\n }\n } else if (isRecord(node.openapi)) {\n const openapiConfig = node.openapi as Record<string, unknown>;\n const sourceValue = openapiConfig.source;\n if (typeof sourceValue === 'string') {\n const localizedSource = localizeDocsJsonSpecPath(\n sourceValue,\n locale,\n filePath,\n specs,\n fileMappingAbs,\n fileMappingRel,\n warnings,\n configDir\n );\n if (localizedSource && localizedSource !== sourceValue) {\n openapiConfig.source = localizedSource;\n changed = true;\n }\n }\n\n const directoryValue = openapiConfig.directory;\n if (typeof directoryValue === 'string') {\n const localizedDirectory = localizeDocsJsonDirectory(\n directoryValue,\n locale,\n defaultLocale,\n new Set([defaultLocale, ...Object.keys(fileMappingRel)])\n );\n if (localizedDirectory && localizedDirectory !== directoryValue) {\n openapiConfig.directory = localizedDirectory;\n changed = true;\n }\n }\n }\n\n if (Array.isArray(node.pages)) {\n const pages = node.pages;\n for (let i = 0; i < pages.length; i += 1) {\n const page = pages[i];\n if (typeof page !== 'string') continue;\n const updated = stripLocaleFromOpenApiPage(page, locale);\n if (updated !== page) {\n pages[i] = updated;\n changed = true;\n }\n }\n }\n\n for (const value of Object.values(node)) {\n visitNode(value, nextLocale);\n }\n };\n\n visitNode(json, undefined);\n\n if (!changed) return null;\n return { changed, content: JSON.stringify(json, null, 2) };\n}\n\nfunction stripLocaleFromOpenApiPage(value: string, locale: string): string {\n const trimmed = value.trim();\n const prefix = `${locale}/`;\n if (!trimmed.startsWith(prefix)) return value;\n const candidate = trimmed.slice(prefix.length);\n const parsed = parseOpenApiValue(candidate);\n if (!parsed) return value;\n return candidate;\n}\n\nfunction localizeDocsJsonDirectory(\n directory: string,\n locale: string,\n defaultLocale: string,\n knownLocales: Set<string>\n): string | null {\n if (locale === defaultLocale) return null;\n\n const trimmed = directory.trim();\n if (!trimmed || /^(?:[a-z][a-z0-9+.-]*:|\\/\\/|#|\\.\\/|\\.\\.\\/)/i.test(trimmed)) {\n return null;\n }\n\n const leadingWhitespace = directory.match(/^\\s*/)?.[0] ?? '';\n const trailingWhitespace = directory.match(/\\s*$/)?.[0] ?? '';\n const leadingSlash = trimmed.startsWith('/') ? '/' : '';\n const pathBody = trimmed.replace(/^\\/+/, '');\n const [firstSegment, ...restSegments] = pathBody.split('/');\n\n if (firstSegment === locale) {\n const normalized = `${leadingWhitespace}${leadingSlash}${pathBody}${trailingWhitespace}`;\n return normalized === directory ? null : normalized;\n }\n\n const unprefixedPath = knownLocales.has(firstSegment)\n ? restSegments.join('/')\n : pathBody;\n const localizedPath = unprefixedPath ? `${locale}/${unprefixedPath}` : locale;\n const normalized = `${leadingWhitespace}${leadingSlash}${localizedPath}${trailingWhitespace}`;\n\n return normalized === directory ? null : normalized;\n}\n\nfunction localizeDocsJsonSpecPath(\n source: string,\n locale: string,\n filePath: string,\n specs: SpecAnalysis[],\n fileMappingAbs: Record<string, Record<string, string>>,\n _fileMappingRel: Record<string, Record<string, string>>,\n warnings: Set<string>,\n configDir: string\n): string | null {\n const resolvedAbs = resolveDocsJsonSpecPath(source, filePath, configDir);\n const matched = matchSpecBySource(source, resolvedAbs, specs, warnings);\n if (!matched) return source;\n\n const localizedSpecPath = resolveLocalizedSpecPath(\n matched,\n locale,\n fileMappingAbs,\n configDir,\n source\n );\n const localizedAbs = resolveDocsJsonSpecPath(\n localizedSpecPath,\n filePath,\n configDir\n );\n if (!fs.existsSync(localizedAbs)) {\n warnings.add(\n `OpenAPI source \"${source}\" localized for locale \"${locale}\" points to a missing file (${localizedAbs}). Keeping original source.`\n );\n return source;\n }\n\n const rel = normalizeSlashes(path.relative(configDir, localizedAbs));\n return formatSpecPathForDocsJson(rel, source);\n}\n\nfunction resolveDocsJsonSpecPath(\n source: string,\n filePath: string,\n configDir: string\n): string {\n if (source.startsWith('/')) {\n return path.resolve(configDir, source.replace(/^\\/+/, ''));\n }\n if (source.startsWith('./') || source.startsWith('../')) {\n return path.resolve(path.dirname(filePath), source);\n }\n return path.resolve(configDir, source);\n}\n\nfunction matchSpecBySource(\n source: string,\n resolvedAbs: string,\n specs: SpecAnalysis[],\n warnings: Set<string>\n): SpecAnalysis | null {\n const exact = specs.find((spec) => samePath(resolvedAbs, spec.absPath));\n if (exact) return exact;\n\n const normalizedExplicit = normalizeSlashes(source).replace(/^\\.?\\/+/, '');\n const explicitWithoutExt = stripExtension(normalizedExplicit);\n const explicitBase = path.basename(normalizedExplicit);\n const explicitBaseWithoutExt = stripExtension(explicitBase);\n const matches = specs.filter((spec) => {\n const configPath = normalizeSlashes(spec.configPath).replace(/^\\.?\\/+/, '');\n const configBase = path.basename(configPath);\n const configPathNoExt = stripExtension(configPath);\n const configBaseNoExt = stripExtension(configBase);\n return (\n configPath === normalizedExplicit ||\n configPathNoExt === explicitWithoutExt ||\n configBase === explicitBase ||\n configBaseNoExt === explicitBaseWithoutExt\n );\n });\n\n if (matches.length === 1) return matches[0];\n if (matches.length > 1) {\n warnings.add(\n `OpenAPI source \"${source}\" matches multiple specs (${matches\n .map((m) => m.configPath)\n .join(\n ', '\n )}). Using the first configured match (${matches[0].configPath}).`\n );\n return matches[0];\n }\n\n return null;\n}\n\nfunction formatSpecPathForDocsJson(\n relativePath: string,\n originalPathText: string\n): string {\n const normalized = normalizeSlashes(relativePath);\n const base = normalized.replace(/^\\.\\//, '').replace(/\\/+/g, '/');\n\n if (originalPathText.startsWith('/')) {\n return `/${base.replace(/^\\/+/, '')}`;\n }\n if (originalPathText.startsWith('../')) {\n return normalized;\n }\n if (originalPathText.startsWith('./')) {\n return `./${base.replace(/^\\/+/, '')}`;\n }\n return base.replace(/^\\/+/, '');\n}\n\n/**\n * Resolve configured OpenAPI files to absolute paths and collect the operations,\n * schemas, and webhooks they expose. Warns and skips when files are missing,\n * unsupported (non-JSON/YAML), or fail to parse so later steps can continue gracefully.\n */\nfunction buildSpecAnalyses(\n openapiFiles: string[],\n configDir: string\n): SpecAnalysis[] {\n const analyses: SpecAnalysis[] = [];\n\n for (const configEntry of openapiFiles) {\n const absPath = path.resolve(configDir, configEntry);\n if (!fs.existsSync(absPath)) {\n logger.warn(`OpenAPI file not found: ${configEntry}`);\n continue;\n }\n const ext = path.extname(absPath).toLowerCase();\n if (!OPENAPI_SPEC_EXTENSIONS.has(ext)) {\n logger.warn(\n `Skipping OpenAPI file (only .json/.yml/.yaml supported): ${configEntry}`\n );\n continue;\n }\n\n let spec: unknown;\n try {\n const raw = fs.readFileSync(absPath, 'utf8');\n spec = ext === '.json' ? JSON.parse(raw) : YAML.parse(raw);\n } catch {\n const format = ext === '.json' ? 'JSON' : 'YAML';\n logger.warn(`Failed to parse OpenAPI ${format}: ${configEntry}`);\n continue;\n }\n\n analyses.push({\n absPath,\n configPath: configEntry,\n operations: extractOperations(spec),\n schemas: extractSchemas(spec),\n webhooks: extractWebhooks(spec),\n });\n }\n\n return analyses;\n}\n\nfunction isRecord(val: unknown): val is Record<string, unknown> {\n return typeof val === 'object' && val !== null;\n}\n\n/**\n * Collect path+method identifiers (e.g., \"POST /foo\") from an OpenAPI spec.\n * Safely no-ops when paths is missing or malformed.\n */\nfunction extractOperations(spec: unknown): Set<string> {\n const ops = new Set<string>();\n if (!isRecord(spec) || !isRecord(spec.paths)) return ops;\n const paths = spec.paths as Record<string, unknown>;\n\n for (const [route, methods] of Object.entries(paths)) {\n if (!isRecord(methods)) continue;\n for (const [method, operation] of Object.entries(methods)) {\n if (!isRecord(operation)) continue;\n const upper = method.toUpperCase();\n if (!HTTP_METHODS.has(upper)) continue;\n ops.add(`${upper} ${route}`);\n }\n }\n return ops;\n}\n\n/**\n * Collect schema names from components.schemas.\n * Returns empty set if components/schemas are missing or malformed.\n */\nfunction extractSchemas(spec: unknown): Set<string> {\n if (!isRecord(spec) || !isRecord(spec.components)) return new Set();\n const components = spec.components as Record<string, unknown>;\n if (!isRecord(components.schemas)) return new Set();\n return new Set(Object.keys(components.schemas as Record<string, unknown>));\n}\n\n/**\n * Collect webhook names from webhooks (OpenAPI 3.1+).\n * Returns empty set if webhooks is missing or malformed.\n */\nfunction extractWebhooks(spec: unknown): Set<string> {\n if (!isRecord(spec) || !isRecord(spec.webhooks)) return new Set();\n return new Set(Object.keys(spec.webhooks as Record<string, unknown>));\n}\n\n/**\n * Parse MDX/MD frontmatter, rewrite openapi/openapi-schema entries to the\n * resolved (possibly localized) spec path, and return updated content.\n * Uses remark to find the YAML node so the rest of the document remains\n * untouched. When parsing fails or no relevant keys exist, it returns null.\n */\nfunction rewriteFrontmatter(\n content: string,\n filePath: string,\n locale: string,\n specs: SpecAnalysis[],\n fileMapping: Record<string, Record<string, string>>,\n warnings: Set<string>,\n configDir: string\n): { changed: boolean; content: string } | null {\n let tree: Root;\n try {\n tree = unified()\n .use(remarkParse)\n .use(remarkFrontmatter, ['yaml', 'toml'])\n .parse(content) as Root;\n } catch {\n return null;\n }\n\n const yamlNode = (tree.children as Content[]).find(\n (node): node is Yaml => (node as Yaml).type === 'yaml'\n );\n if (\n !yamlNode ||\n !yamlNode.position ||\n yamlNode.position.start?.offset === undefined\n ) {\n return null;\n }\n\n const start = yamlNode.position.start.offset as number;\n const end = yamlNode.position.end.offset as number;\n const frontmatterRaw: string = yamlNode.value || '';\n\n const doc = YAML.parseDocument(frontmatterRaw, {\n prettyErrors: false,\n keepSourceTokens: true,\n });\n if (doc.errors?.length) return null;\n if (!isMap(doc.contents)) return null;\n\n let changed = false;\n\n const openapiNode = doc.get('openapi', true);\n if (isScalar(openapiNode) && typeof openapiNode.value === 'string') {\n const parsedValue = parseOpenApiValue(openapiNode.value);\n if (parsedValue) {\n const matchKey =\n parsedValue.kind === 'operation'\n ? {\n type: 'operation' as const,\n key: `${parsedValue.method.toUpperCase()} ${parsedValue.operationPath}`,\n }\n : { type: 'webhook' as const, key: parsedValue.name };\n\n const spec = resolveSpec(\n parsedValue.specPath,\n specs,\n filePath,\n configDir,\n warnings,\n describeOpenApiRef(parsedValue),\n matchKey\n );\n if (spec) {\n const descriptor = formatOpenApiDescriptor(parsedValue);\n const localizedSpecPath = resolveLocalizedSpecPath(\n spec,\n locale,\n fileMapping,\n configDir,\n parsedValue.specPath || spec.configPath\n );\n const newValue = `${localizedSpecPath} ${descriptor}`.trim();\n if (newValue !== openapiNode.value) {\n doc.set('openapi', newValue);\n changed = true;\n }\n }\n }\n }\n\n const schemaNode = doc.get('openapi-schema', true);\n if (isScalar(schemaNode) && typeof schemaNode.value === 'string') {\n const parsedValue = parseSchemaValue(schemaNode.value);\n if (parsedValue) {\n const spec = resolveSpec(\n parsedValue.specPath,\n specs,\n filePath,\n configDir,\n warnings,\n `schema \"${parsedValue.schemaName}\"`,\n { type: 'schema', key: parsedValue.schemaName }\n );\n if (spec) {\n const localizedSpecPath = resolveLocalizedSpecPath(\n spec,\n locale,\n fileMapping,\n configDir,\n parsedValue.specPath || spec.configPath\n );\n const newValue =\n `${localizedSpecPath} ${parsedValue.schemaName}`.trim();\n if (newValue !== schemaNode.value) {\n doc.set('openapi-schema', newValue);\n changed = true;\n }\n }\n }\n }\n\n if (!changed) return null;\n\n const fmString = doc.toString().trimEnd();\n const rebuilt = `${content.slice(0, start)}---\\n${fmString}\\n---${content.slice(end)}`;\n return { changed, content: rebuilt };\n}\n\nfunction stripWrappingQuotes(value: string): string {\n return value.trim().replace(/^['\"]|['\"]$/g, '');\n}\n\n/**\n * Parse frontmatter openapi string into spec/method/path or webhook.\n * Supports optional leading spec file, the webhook keyword, quoted values,\n * and forgiving whitespace. Returns null when the structure is unrecognized.\n */\nfunction parseOpenApiValue(value: string): ParsedOpenApiValue | null {\n const stripped = stripWrappingQuotes(value);\n const tokens = stripped.split(/\\s+/).filter(Boolean);\n if (!tokens.length) return null;\n\n let cursor = 0;\n let specPath: string | undefined;\n const first = tokens[0];\n const second = tokens[1];\n const methodCandidate = second?.toUpperCase();\n const firstLooksLikeSpec =\n hasOpenApiSpecExtension(first) ||\n (second &&\n (second.toLowerCase() === 'webhook' ||\n (methodCandidate && HTTP_METHODS.has(methodCandidate))));\n\n if (firstLooksLikeSpec) {\n specPath = tokens[0];\n cursor = 1;\n }\n if (cursor >= tokens.length) return null;\n\n const keyword = tokens[cursor];\n if (keyword.toLowerCase() === 'webhook') {\n const name = tokens.slice(cursor + 1).join(' ');\n if (!name) return null;\n return { kind: 'webhook', specPath, name };\n }\n\n const method = keyword.toUpperCase();\n if (!HTTP_METHODS.has(method)) return null;\n const operationPath = tokens.slice(cursor + 1).join(' ');\n if (!operationPath) return null;\n return { kind: 'operation', specPath, method, operationPath };\n}\n\n/**\n * Parse frontmatter openapi-schema string into spec/schemaName.\n * Accepts optional leading spec file and quoted values; returns null on invalid\n * shapes so callers can skip rewrites gracefully.\n */\nfunction parseSchemaValue(value: string): ParsedSchemaValue | null {\n const stripped = stripWrappingQuotes(value);\n const tokens = stripped.split(/\\s+/).filter(Boolean);\n if (!tokens.length) return null;\n let cursor = 0;\n let specPath: string | undefined;\n if (hasOpenApiSpecExtension(tokens[0])) {\n specPath = tokens[0];\n cursor = 1;\n }\n const schemaName = tokens.slice(cursor).join(' ');\n if (!schemaName) return null;\n return { specPath, schemaName };\n}\n\n/**\n * Choose which configured spec a reference should use.\n * - If an explicit spec path is provided, resolve it relative to the config\n * and the referencing file, warn when unknown, and bail.\n * - Otherwise, try to match by operation/webhook/schema name; resolve\n * ambiguity using config order and warn when ambiguous or missing.\n */\nfunction resolveSpec(\n explicitPath: string | undefined,\n specs: SpecAnalysis[],\n filePath: string,\n configDir: string,\n warnings: Set<string>,\n refDescription: string,\n match: { type: 'operation' | 'webhook' | 'schema'; key: string }\n): SpecAnalysis | null {\n if (!specs.length) return null;\n\n if (explicitPath) {\n const normalizedExplicit = normalizeSlashes(\n explicitPath.replace(/^\\.?\\/+/, '')\n );\n const candidates = [\n path.resolve(configDir, normalizedExplicit),\n path.resolve(path.dirname(filePath), normalizedExplicit),\n ];\n const foundSpec = specs.find((spec) => {\n const normalizedSpecPath = normalizeSlashes(spec.absPath);\n return candidates.some((candidate) =>\n samePath(candidate, normalizedSpecPath)\n );\n });\n if (foundSpec) {\n if (specHasMatch(foundSpec, match)) {\n return foundSpec;\n }\n\n const alternatives = specs.filter(\n (spec) => spec !== foundSpec && specHasMatch(spec, match)\n );\n if (alternatives.length === 1) {\n warnings.add(\n `OpenAPI reference ${refDescription} in ${filePath} points to ${foundSpec.configPath}, but the entry was not found there. Using ${alternatives[0].configPath} instead.`\n );\n return alternatives[0];\n }\n if (alternatives.length > 1) {\n warnings.add(\n `OpenAPI reference ${refDescription} in ${filePath} points to ${foundSpec.configPath}, but the entry was not found there and matches multiple specs (${alternatives\n .map((spec) => spec.configPath)\n .join(', ')}). Skipping localization for this reference.`\n );\n return null;\n }\n\n warnings.add(\n `OpenAPI reference ${refDescription} in ${filePath} points to ${foundSpec.configPath}, but the entry was not found in any configured spec. Skipping localization for this reference.`\n );\n return null;\n }\n\n const explicitWithoutExt = stripExtension(normalizedExplicit);\n const explicitBase = path.basename(normalizedExplicit);\n const explicitBaseWithoutExt = stripExtension(explicitBase);\n const matches = specs.filter((spec) => {\n const configPath = normalizeSlashes(spec.configPath).replace(\n /^\\.?\\/+/,\n ''\n );\n const configBase = path.basename(configPath);\n const configPathNoExt = stripExtension(configPath);\n const configBaseNoExt = stripExtension(configBase);\n return (\n configPath === normalizedExplicit ||\n configPathNoExt === explicitWithoutExt ||\n configBase === explicitBase ||\n configBaseNoExt === explicitBaseWithoutExt\n );\n });\n if (matches.length === 1) return matches[0];\n if (matches.length > 1) {\n warnings.add(\n `OpenAPI reference ${refDescription} in ${filePath} matches multiple specs (${matches\n .map((m) => m.configPath)\n .join(\n ', '\n )}). Using the first configured match (${matches[0].configPath}).`\n );\n return matches[0];\n }\n\n warnings.add(\n `OpenAPI reference ${refDescription} in ${filePath} points to an unconfigured spec (${explicitPath}). Skipping localization for this reference.`\n );\n return null;\n }\n\n // No explicit spec: try to find by contents\n const matches = specs.filter((spec) => {\n if (match.type === 'schema') {\n return spec.schemas.has(match.key);\n }\n if (match.type === 'webhook') {\n return spec.webhooks.has(match.key);\n }\n // operation\n return spec.operations.has(match.key);\n });\n\n if (matches.length === 1) return matches[0];\n if (matches.length > 1) {\n warnings.add(\n `OpenAPI reference ${refDescription} in ${filePath} is available in multiple specs. Skipping localization for this reference.`\n );\n return null;\n }\n\n warnings.add(\n `OpenAPI reference ${refDescription} in ${filePath} was not found in any configured spec. Skipping localization for this reference.`\n );\n return null;\n}\n\nfunction specHasMatch(\n spec: SpecAnalysis,\n match: { type: 'operation' | 'webhook' | 'schema'; key: string }\n): boolean {\n if (match.type === 'schema') {\n return spec.schemas.has(match.key);\n }\n if (match.type === 'webhook') {\n return spec.webhooks.has(match.key);\n }\n return spec.operations.has(match.key);\n}\n\n/**\n * Map a spec to the locale-specific file path when available and normalize it\n * for frontmatter. Falls back to the source spec when the locale copy does\n * not exist to preserve deterministic behavior.\n */\nfunction resolveLocalizedSpecPath(\n spec: SpecAnalysis,\n locale: string,\n fileMapping: Record<string, Record<string, string>>,\n configDir: string,\n originalPathText?: string\n): string {\n const mapping = fileMapping[locale]?.[spec.absPath];\n const chosenAbs = mapping || spec.absPath;\n const rel = normalizeSlashes(path.relative(configDir, chosenAbs));\n const rooted = `/${rel.replace(/^\\/+/, '')}`;\n return formatSpecPathForFrontmatter(\n rooted,\n originalPathText || spec.configPath\n );\n}\n\n/**\n * Format the path that will be written back to frontmatter:\n * - Preserve the user's absolute style when they used a leading slash.\n * - Preserve upward relative references (../) exactly.\n * - Otherwise return a repo-root-relative path with a leading slash so Mintlify\n * resolves consistently regardless of the MDX file location.\n */\nfunction formatSpecPathForFrontmatter(\n relativePath: string,\n originalPathText: string\n): string {\n const normalized = normalizeSlashes(relativePath);\n const base = normalized.replace(/^\\.\\//, '').replace(/\\/+/g, '/');\n\n if (originalPathText.startsWith('/')) {\n // Force repo-root absolute style\n return `/${base.replace(/^\\/+/, '')}`;\n }\n\n if (originalPathText.startsWith('../')) {\n // Preserve explicit relative upward references\n return normalized;\n }\n\n // Default to repo-root relative with leading slash to avoid resolving relative to the MDX directory\n return `/${base.replace(/^\\/+/, '')}`;\n}\n\n/** Normalize the descriptive portion after the spec path for frontmatter. */\nfunction formatOpenApiDescriptor(value: ParsedOpenApiValue): string {\n if (value.kind === 'webhook') return `webhook ${value.name}`;\n return `${value.method.toUpperCase()} ${value.operationPath}`;\n}\n\n/** Human-readable description a specific OpenAPI reference. */\nfunction describeOpenApiRef(value: ParsedOpenApiValue): string {\n if (value.kind === 'webhook') return `webhook ${value.name}`;\n return `${value.method.toUpperCase()} ${value.operationPath}`;\n}\n\n/** Remove a single trailing file extension while preserving directory segments. */\nfunction stripExtension(p: string): string {\n const parsed = path.parse(p);\n return normalizeSlashes(path.join(parsed.dir, parsed.name));\n}\n\nfunction hasOpenApiSpecExtension(value: string): boolean {\n return OPENAPI_SPEC_EXTENSIONS.has(path.extname(value).toLowerCase());\n}\n\n/** Normalize separators for stable comparisons and output. */\nfunction normalizeSlashes(p: string): string {\n return p.replace(/\\\\/g, '/');\n}\n\n/** Compare paths after resolution to avoid casing/separator mismatches. */\nfunction samePath(a: string, b: string): boolean {\n return path.resolve(a) === path.resolve(b);\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gt",
3
- "version": "2.14.38",
3
+ "version": "2.14.39",
4
4
  "main": "dist/index.js",
5
5
  "bin": "bin/main.js",
6
6
  "files": [
@@ -135,6 +135,7 @@
135
135
  "mdast-util-mdx-jsx": "^3.2.0",
136
136
  "mdast-util-mdxjs-esm": "^2.0.1",
137
137
  "prettier": "^3.4.2",
138
+ "react-devtools-core": "^4.28.5",
138
139
  "ts-node": "^10.9.2",
139
140
  "tsdown": "^0.21.10",
140
141
  "tslib": "^2.8.1",
@@ -149,14 +150,14 @@
149
150
  "build": "pnpm run transpile && pnpm run copy-instructions",
150
151
  "build:clean": "sh ../../scripts/clean.sh && pnpm bin:restore && rm -rf binaries && pnpm run build",
151
152
  "build:release": "pnpm run build:clean",
152
- "build:bin": "pnpm run build && sh scripts/build-exe.sh all",
153
+ "build:bin": "pnpm run build && bash scripts/build-exe.sh all",
153
154
  "build:bin:clean": "sh ../../scripts/clean.sh && rm -rf binaries && pnpm run build:bin",
154
155
  "build:bin:release": "pnpm run build:bin:clean",
155
- "build:bin:darwin-x64": "sh scripts/build-exe.sh darwin-x64",
156
- "build:bin:darwin-arm64": "sh scripts/build-exe.sh darwin-arm64",
157
- "build:bin:linux-x64": "sh scripts/build-exe.sh linux-x64",
158
- "build:bin:linux-arm64": "sh scripts/build-exe.sh linux-arm64",
159
- "build:bin:windows-x64": "sh scripts/build-exe.sh windows-x64",
156
+ "build:bin:darwin-x64": "bash scripts/build-exe.sh darwin-x64",
157
+ "build:bin:darwin-arm64": "bash scripts/build-exe.sh darwin-arm64",
158
+ "build:bin:linux-x64": "bash scripts/build-exe.sh linux-x64",
159
+ "build:bin:linux-arm64": "bash scripts/build-exe.sh linux-arm64",
160
+ "build:bin:windows-x64": "bash scripts/build-exe.sh windows-x64",
160
161
  "test": "pnpm run generate-version && vitest run --config=./vitest.config.ts",
161
162
  "test:watch": "pnpm run generate-version && vitest --config=./vitest.config.ts",
162
163
  "release": "pnpm run release:normal && pnpm run release:bin",