gt 2.14.49 → 2.14.50

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,11 @@
1
1
  # gtx-cli
2
2
 
3
+ ## 2.14.50
4
+
5
+ ### Patch Changes
6
+
7
+ - [#1586](https://github.com/generaltranslation/gt/pull/1586) [`81d0d09`](https://github.com/generaltranslation/gt/commit/81d0d09db3f0d9d8a2ce7fc45f76bf5dd34fa34a) Thanks [@fernando-aviles](https://github.com/fernando-aviles)! - Refetch composite content
8
+
3
9
  ## 2.14.49
4
10
 
5
11
  ### Patch Changes
@@ -103,7 +103,8 @@ async function downloadFileBatch(fileTracker, files, options, forceDownload = fa
103
103
  const existingEntry = entryMap.get(fileId);
104
104
  const downloadedTranslation = existingEntry?.versionId === versionId ? existingEntry.translations[locale] : void 0;
105
105
  const fileExists = fs$1.existsSync(outputPath);
106
- if (!forceDownload && fileExists && downloadedTranslation) {
106
+ const isInPlaceComposite = options.options?.jsonSchema ? !!validateJsonSchema(options.options, inputPath)?.composite : false;
107
+ if (!forceDownload && fileExists && downloadedTranslation && !isInPlaceComposite) {
107
108
  try {
108
109
  let existingContent = fs$1.readFileSync(outputPath, "utf8");
109
110
  if (shouldResolveRefs(outputPath, options.options)) try {
@@ -119,7 +120,9 @@ async function downloadFileBatch(fileTracker, files, options, forceDownload = fa
119
120
  if (remergedData !== existingContent) await fs$1.promises.writeFile(outputPath, remergedData);
120
121
  recordRemerged(outputPath);
121
122
  }
122
- } catch {}
123
+ } catch (error) {
124
+ logger.warn(`Failed to re-merge existing translation for ${outputPath} (${locale}): ${error}`);
125
+ }
123
126
  result.skipped.push(requestedFile);
124
127
  continue;
125
128
  }
@@ -1 +1 @@
1
- {"version":3,"file":"downloadFileBatch.js","names":["fs","path"],"sources":["../../src/api/downloadFileBatch.ts"],"sourcesContent":["import * as fs from 'fs';\nimport * as path from 'path';\nimport { logger } from '../console/logger.js';\nimport { gt } from '../utils/gt.js';\nimport { Settings } from '../types/index.js';\nimport { validateJsonSchema } from '../formats/json/utils.js';\nimport { validateYamlSchema } from '../formats/yaml/utils.js';\nimport { mergeJson } from '../formats/json/mergeJson.js';\nimport { extractJson } from '../formats/json/extractJson.js';\nimport mergeYaml from '../formats/yaml/mergeYaml.js';\nimport { extractYaml } from '../formats/yaml/extractYaml.js';\nimport {\n resolveMintlifyRefs,\n shouldResolveRefs,\n} from '../utils/resolveMintlifyRefs.js';\nimport {\n readLockfile,\n writeLockfile,\n findOrCreateEntry,\n} from '../fs/config/downloadedVersions.js';\nimport { recordDownloaded, recordRemerged } from '../state/recentDownloads.js';\nimport { recordWarning } from '../state/translateWarnings.js';\nimport stringify from 'fast-json-stable-stringify';\nimport type { FileStatusTracker } from '../workflows/steps/PollJobsStep.js';\nimport { SUPPORTED_FILE_EXTENSIONS } from '../formats/files/supportedFiles.js';\nimport { hasNonIdentityFileFormatTransformForType } from '../formats/files/transformFormat.js';\nimport { getRelative } from '../fs/findFilepath.js';\n\nfunction sortJsonString(data: string): string {\n const sortedData = stringify(JSON.parse(data));\n return JSON.stringify(JSON.parse(sortedData), null, 2);\n}\n\n/**\n * Merges translated content with the current source file for schema-based formats.\n */\nfunction mergeWithSource(\n translatedContent: string,\n locale: string,\n inputPath: string,\n options: Settings\n): string {\n if (shouldSkipSourceFormatMerge(inputPath, options)) {\n return translatedContent;\n }\n if (!options.options) return translatedContent;\n\n const jsonSchema = options.options.jsonSchema\n ? validateJsonSchema(options.options, inputPath)\n : null;\n const yamlSchema =\n !jsonSchema && options.options.yamlSchema\n ? validateYamlSchema(options.options, inputPath)\n : null;\n\n if (!jsonSchema && !yamlSchema) return translatedContent;\n\n const sourceContent = fs.readFileSync(inputPath, 'utf8');\n if (!sourceContent) return translatedContent;\n\n if (jsonSchema) {\n // Resolve $ref before merging if configured\n let resolvedSourceContent = sourceContent;\n if (shouldResolveRefs(inputPath, options.options)) {\n try {\n const json = JSON.parse(sourceContent);\n const { resolved } = resolveMintlifyRefs(json, inputPath);\n resolvedSourceContent = JSON.stringify(resolved, null, 2);\n } catch {\n // Fall through with original content\n }\n }\n return mergeJson(\n resolvedSourceContent,\n inputPath,\n options.options,\n [{ translatedContent, targetLocale: locale }],\n options.defaultLocale,\n options.locales\n )[0];\n } else {\n return mergeYaml(\n sourceContent,\n inputPath,\n options.options,\n [{ translatedContent, targetLocale: locale }],\n options.defaultLocale\n )[0];\n }\n}\n\n/**\n * Determines whether a source file should be skipped for schema re-merging.\n * @param inputPath - The path of the source file\n * @param options - The settings for the project\n * @returns True if the source file should be skipped for schema re-merging, false otherwise\n */\nfunction shouldSkipSourceFormatMerge(\n inputPath: string,\n options: Settings\n): boolean {\n for (const fileType of SUPPORTED_FILE_EXTENSIONS) {\n if (!hasNonIdentityFileFormatTransformForType(options, fileType)) continue;\n\n const transformedSourcePaths = options.files.resolvedPaths[fileType] || [];\n if (\n transformedSourcePaths.some(\n (sourcePath) => getRelative(sourcePath) === inputPath\n )\n ) {\n return true;\n }\n }\n\n return false;\n}\n\nexport type BatchedFiles = {\n branchId: string;\n fileId: string;\n versionId: string;\n locale: string;\n outputPath: string;\n inputPath: string;\n}[];\n\nexport type DownloadFileBatchResult = {\n successful: BatchedFiles;\n failed: BatchedFiles;\n skipped: BatchedFiles;\n};\n/**\n * Downloads multiple translation files in a single batch request\n * @param files - Array of files to download with their output paths\n * @param maxRetries - Maximum number of retry attempts\n * @param retryDelay - Delay between retries in milliseconds\n * @returns Object containing successful and failed file IDs\n */\nexport async function downloadFileBatch(\n fileTracker: FileStatusTracker,\n files: BatchedFiles,\n options: Settings,\n forceDownload: boolean = false\n): Promise<DownloadFileBatchResult> {\n // Local record of what version was last downloaded for each fileName:locale\n const {\n data: downloadedVersions,\n entryMap,\n originalV1,\n } = readLockfile(options);\n let didUpdateDownloadedLock = false;\n\n // Create a map of requested file keys to the file object\n const requestedFileMap = new Map(\n files.map((file) => [\n `${file.branchId}:${file.fileId}:${file.versionId}:${file.locale}`,\n file,\n ])\n );\n const result: DownloadFileBatchResult = {\n successful: [],\n failed: [],\n skipped: [],\n };\n\n // Create a map of translationId to outputPath for easier lookup\n const outputPathMap = new Map(\n files.map((file) => [\n `${file.branchId}:${file.fileId}:${file.versionId}:${file.locale}`,\n file.outputPath,\n ])\n );\n\n try {\n // Download the files\n const responseData = await gt.downloadFileBatch(\n files.map((file) => ({\n fileId: file.fileId,\n branchId: file.branchId,\n versionId: file.versionId,\n locale: file.locale,\n }))\n );\n const downloadedFiles = responseData.files || [];\n\n // Process each file in the response\n for (const file of downloadedFiles) {\n const fileKey = `${file.branchId}:${file.fileId}:${file.versionId}:${file.locale}`;\n const requestedFile = requestedFileMap.get(fileKey);\n if (!requestedFile) {\n continue;\n }\n try {\n const outputPath = outputPathMap.get(fileKey);\n const fileProperties = fileTracker.completed.get(fileKey);\n\n if (!outputPath || !fileProperties) {\n logger.warn(`No input/output path found for file: ${fileKey}`);\n recordWarning(\n 'failed_download',\n fileKey,\n 'No input/output path found'\n );\n result.failed.push(requestedFile);\n continue;\n }\n\n const {\n fileId,\n versionId,\n locale,\n branchId,\n fileName: inputPath,\n } = fileProperties;\n\n // Ensure the directory exists\n const dir = path.dirname(outputPath);\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true });\n }\n // If a local translation already exists for the same source version, skip overwrite\n const existingEntry = entryMap.get(fileId);\n const downloadedTranslation =\n existingEntry?.versionId === versionId\n ? existingEntry.translations[locale]\n : undefined;\n const fileExists = fs.existsSync(outputPath);\n\n if (!forceDownload && fileExists && downloadedTranslation) {\n // For schema-based files, re-merge with current source in case\n // non-translatable fields changed (skip the API download, not the merge)\n try {\n let existingContent = fs.readFileSync(outputPath, 'utf8');\n // Resolve $ref before extraction if configured\n if (shouldResolveRefs(outputPath, options.options)) {\n try {\n const json = JSON.parse(existingContent);\n const { resolved } = resolveMintlifyRefs(json, outputPath);\n existingContent = JSON.stringify(resolved, null, 2);\n } catch {\n // Fall through with original content\n }\n }\n const jsonExtracted = options.options?.jsonSchema\n ? extractJson(\n existingContent,\n inputPath,\n options.options,\n locale,\n options.defaultLocale\n )\n : null;\n const extracted =\n jsonExtracted ??\n (options.options?.yamlSchema\n ? extractYaml(existingContent, inputPath, options.options)\n : null);\n if (extracted) {\n const remerged = mergeWithSource(\n extracted,\n locale,\n inputPath,\n options\n );\n let remergedData = remerged;\n if (outputPath.endsWith('.json')) {\n try {\n remergedData = sortJsonString(remergedData);\n } catch {\n // Fall through with unsorted content\n }\n }\n if (remergedData !== existingContent) {\n await fs.promises.writeFile(outputPath, remergedData);\n }\n // Track for postprocessing (e.g. openapi path localization)\n // even when the API download was skipped\n recordRemerged(outputPath);\n }\n } catch {\n // If re-merge fails, still count as skipped — not worth failing the download\n }\n result.skipped.push(requestedFile);\n continue;\n }\n let data = mergeWithSource(file.data, locale, inputPath, options);\n\n // Stable sort JSON keys for deterministic output\n if (file.fileFormat === 'GTJSON' || outputPath.endsWith('.json')) {\n try {\n data = sortJsonString(data);\n } catch (error) {\n logger.warn(`Failed to sort JSON file: ${file.id}: ` + error);\n }\n }\n\n // Write the file to disk\n await fs.promises.writeFile(outputPath, data);\n // Track as downloaded with metadata for downstream postprocessing\n recordDownloaded(outputPath, {\n branchId,\n fileId,\n versionId,\n locale,\n inputPath,\n });\n\n result.successful.push(requestedFile);\n if (fileId && versionId && locale) {\n const entry = findOrCreateEntry(\n entryMap,\n downloadedVersions.entries,\n fileId,\n versionId\n );\n entry.fileName = inputPath;\n entry.staged = false;\n entry.translations[locale] = {\n updatedAt: new Date().toISOString(),\n fileName: outputPath,\n };\n didUpdateDownloadedLock = true;\n }\n } catch (error) {\n logger.error(`Error saving file ${fileKey}: ` + error);\n recordWarning(\n 'failed_download',\n fileKey,\n `Error saving file: ${error}`\n );\n result.failed.push(requestedFile);\n }\n }\n\n // Add any files that weren't in the response to the failed list\n const downloadedFileKeys = new Set(\n downloadedFiles.map(\n (file) =>\n `${file.branchId}:${file.fileId}:${file.versionId}:${file.locale}`\n )\n );\n for (const [fileKey, requestedFile] of requestedFileMap.entries()) {\n if (!downloadedFileKeys.has(fileKey)) {\n result.failed.push(requestedFile);\n }\n }\n\n // Persist any updates to the downloaded map at the end of a successful cycle\n if (didUpdateDownloadedLock) {\n writeLockfile(downloadedVersions, originalV1);\n didUpdateDownloadedLock = false;\n }\n return result;\n } catch (error) {\n logger.error(\n `An unexpected error occurred while downloading files: ` + error\n );\n }\n\n // Mark all files as failed if we get here\n result.failed = [...requestedFileMap.values()];\n if (didUpdateDownloadedLock) {\n writeLockfile(downloadedVersions, originalV1);\n }\n return result;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"downloadFileBatch.js","names":["fs","path"],"sources":["../../src/api/downloadFileBatch.ts"],"sourcesContent":["import * as fs from 'fs';\nimport * as path from 'path';\nimport { logger } from '../console/logger.js';\nimport { gt } from '../utils/gt.js';\nimport { Settings } from '../types/index.js';\nimport { validateJsonSchema } from '../formats/json/utils.js';\nimport { validateYamlSchema } from '../formats/yaml/utils.js';\nimport { mergeJson } from '../formats/json/mergeJson.js';\nimport { extractJson } from '../formats/json/extractJson.js';\nimport mergeYaml from '../formats/yaml/mergeYaml.js';\nimport { extractYaml } from '../formats/yaml/extractYaml.js';\nimport {\n resolveMintlifyRefs,\n shouldResolveRefs,\n} from '../utils/resolveMintlifyRefs.js';\nimport {\n readLockfile,\n writeLockfile,\n findOrCreateEntry,\n} from '../fs/config/downloadedVersions.js';\nimport { recordDownloaded, recordRemerged } from '../state/recentDownloads.js';\nimport { recordWarning } from '../state/translateWarnings.js';\nimport stringify from 'fast-json-stable-stringify';\nimport type { FileStatusTracker } from '../workflows/steps/PollJobsStep.js';\nimport { SUPPORTED_FILE_EXTENSIONS } from '../formats/files/supportedFiles.js';\nimport { hasNonIdentityFileFormatTransformForType } from '../formats/files/transformFormat.js';\nimport { getRelative } from '../fs/findFilepath.js';\n\nfunction sortJsonString(data: string): string {\n const sortedData = stringify(JSON.parse(data));\n return JSON.stringify(JSON.parse(sortedData), null, 2);\n}\n\n/**\n * Merges translated content with the current source file for schema-based formats.\n */\nfunction mergeWithSource(\n translatedContent: string,\n locale: string,\n inputPath: string,\n options: Settings\n): string {\n if (shouldSkipSourceFormatMerge(inputPath, options)) {\n return translatedContent;\n }\n if (!options.options) return translatedContent;\n\n const jsonSchema = options.options.jsonSchema\n ? validateJsonSchema(options.options, inputPath)\n : null;\n const yamlSchema =\n !jsonSchema && options.options.yamlSchema\n ? validateYamlSchema(options.options, inputPath)\n : null;\n\n if (!jsonSchema && !yamlSchema) return translatedContent;\n\n const sourceContent = fs.readFileSync(inputPath, 'utf8');\n if (!sourceContent) return translatedContent;\n\n if (jsonSchema) {\n // Resolve $ref before merging if configured\n let resolvedSourceContent = sourceContent;\n if (shouldResolveRefs(inputPath, options.options)) {\n try {\n const json = JSON.parse(sourceContent);\n const { resolved } = resolveMintlifyRefs(json, inputPath);\n resolvedSourceContent = JSON.stringify(resolved, null, 2);\n } catch {\n // Fall through with original content\n }\n }\n return mergeJson(\n resolvedSourceContent,\n inputPath,\n options.options,\n [{ translatedContent, targetLocale: locale }],\n options.defaultLocale,\n options.locales\n )[0];\n } else {\n return mergeYaml(\n sourceContent,\n inputPath,\n options.options,\n [{ translatedContent, targetLocale: locale }],\n options.defaultLocale\n )[0];\n }\n}\n\n/**\n * Determines whether a source file should be skipped for schema re-merging.\n * @param inputPath - The path of the source file\n * @param options - The settings for the project\n * @returns True if the source file should be skipped for schema re-merging, false otherwise\n */\nfunction shouldSkipSourceFormatMerge(\n inputPath: string,\n options: Settings\n): boolean {\n for (const fileType of SUPPORTED_FILE_EXTENSIONS) {\n if (!hasNonIdentityFileFormatTransformForType(options, fileType)) continue;\n\n const transformedSourcePaths = options.files.resolvedPaths[fileType] || [];\n if (\n transformedSourcePaths.some(\n (sourcePath) => getRelative(sourcePath) === inputPath\n )\n ) {\n return true;\n }\n }\n\n return false;\n}\n\nexport type BatchedFiles = {\n branchId: string;\n fileId: string;\n versionId: string;\n locale: string;\n outputPath: string;\n inputPath: string;\n}[];\n\nexport type DownloadFileBatchResult = {\n successful: BatchedFiles;\n failed: BatchedFiles;\n skipped: BatchedFiles;\n};\n/**\n * Downloads multiple translation files in a single batch request\n * @param files - Array of files to download with their output paths\n * @param maxRetries - Maximum number of retry attempts\n * @param retryDelay - Delay between retries in milliseconds\n * @returns Object containing successful and failed file IDs\n */\nexport async function downloadFileBatch(\n fileTracker: FileStatusTracker,\n files: BatchedFiles,\n options: Settings,\n forceDownload: boolean = false\n): Promise<DownloadFileBatchResult> {\n // Local record of what version was last downloaded for each fileName:locale\n const {\n data: downloadedVersions,\n entryMap,\n originalV1,\n } = readLockfile(options);\n let didUpdateDownloadedLock = false;\n\n // Create a map of requested file keys to the file object\n const requestedFileMap = new Map(\n files.map((file) => [\n `${file.branchId}:${file.fileId}:${file.versionId}:${file.locale}`,\n file,\n ])\n );\n const result: DownloadFileBatchResult = {\n successful: [],\n failed: [],\n skipped: [],\n };\n\n // Create a map of translationId to outputPath for easier lookup\n const outputPathMap = new Map(\n files.map((file) => [\n `${file.branchId}:${file.fileId}:${file.versionId}:${file.locale}`,\n file.outputPath,\n ])\n );\n\n try {\n // Download the files\n const responseData = await gt.downloadFileBatch(\n files.map((file) => ({\n fileId: file.fileId,\n branchId: file.branchId,\n versionId: file.versionId,\n locale: file.locale,\n }))\n );\n const downloadedFiles = responseData.files || [];\n\n // Process each file in the response\n for (const file of downloadedFiles) {\n const fileKey = `${file.branchId}:${file.fileId}:${file.versionId}:${file.locale}`;\n const requestedFile = requestedFileMap.get(fileKey);\n if (!requestedFile) {\n continue;\n }\n try {\n const outputPath = outputPathMap.get(fileKey);\n const fileProperties = fileTracker.completed.get(fileKey);\n\n if (!outputPath || !fileProperties) {\n logger.warn(`No input/output path found for file: ${fileKey}`);\n recordWarning(\n 'failed_download',\n fileKey,\n 'No input/output path found'\n );\n result.failed.push(requestedFile);\n continue;\n }\n\n const {\n fileId,\n versionId,\n locale,\n branchId,\n fileName: inputPath,\n } = fileProperties;\n\n // Ensure the directory exists\n const dir = path.dirname(outputPath);\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true });\n }\n // If a local translation already exists for the same source version, skip overwrite\n const existingEntry = entryMap.get(fileId);\n const downloadedTranslation =\n existingEntry?.versionId === versionId\n ? existingEntry.translations[locale]\n : undefined;\n const fileExists = fs.existsSync(outputPath);\n\n // Composite schema files merge translations into the source file itself,\n // so outputPath always exists and the lock can't tell whether derived\n // split outputs (e.g. {locale}/docs.json) are still on disk. Always\n // merge fresh API data so derived files are regenerated every run;\n // local edits to translated output are preserved via `gt save-local`.\n const isInPlaceComposite = options.options?.jsonSchema\n ? !!validateJsonSchema(options.options, inputPath)?.composite\n : false;\n\n if (\n !forceDownload &&\n fileExists &&\n downloadedTranslation &&\n !isInPlaceComposite\n ) {\n // For schema-based files, re-merge with current source in case\n // non-translatable fields changed (skip the API download, not the merge)\n try {\n let existingContent = fs.readFileSync(outputPath, 'utf8');\n // Resolve $ref before extraction if configured\n if (shouldResolveRefs(outputPath, options.options)) {\n try {\n const json = JSON.parse(existingContent);\n const { resolved } = resolveMintlifyRefs(json, outputPath);\n existingContent = JSON.stringify(resolved, null, 2);\n } catch {\n // Fall through with original content\n }\n }\n const jsonExtracted = options.options?.jsonSchema\n ? extractJson(\n existingContent,\n inputPath,\n options.options,\n locale,\n options.defaultLocale\n )\n : null;\n const extracted =\n jsonExtracted ??\n (options.options?.yamlSchema\n ? extractYaml(existingContent, inputPath, options.options)\n : null);\n if (extracted) {\n const remerged = mergeWithSource(\n extracted,\n locale,\n inputPath,\n options\n );\n let remergedData = remerged;\n if (outputPath.endsWith('.json')) {\n try {\n remergedData = sortJsonString(remergedData);\n } catch {\n // Fall through with unsorted content\n }\n }\n if (remergedData !== existingContent) {\n await fs.promises.writeFile(outputPath, remergedData);\n }\n // Track for postprocessing (e.g. openapi path localization)\n // even when the API download was skipped\n recordRemerged(outputPath);\n }\n } catch (error) {\n // If re-merge fails, still count as skipped — not worth failing\n // the download, but surface it so missing output is diagnosable\n logger.warn(\n `Failed to re-merge existing translation for ${outputPath} (${locale}): ${error}`\n );\n }\n result.skipped.push(requestedFile);\n continue;\n }\n let data = mergeWithSource(file.data, locale, inputPath, options);\n\n // Stable sort JSON keys for deterministic output\n if (file.fileFormat === 'GTJSON' || outputPath.endsWith('.json')) {\n try {\n data = sortJsonString(data);\n } catch (error) {\n logger.warn(`Failed to sort JSON file: ${file.id}: ` + error);\n }\n }\n\n // Write the file to disk\n await fs.promises.writeFile(outputPath, data);\n // Track as downloaded with metadata for downstream postprocessing\n recordDownloaded(outputPath, {\n branchId,\n fileId,\n versionId,\n locale,\n inputPath,\n });\n\n result.successful.push(requestedFile);\n if (fileId && versionId && locale) {\n const entry = findOrCreateEntry(\n entryMap,\n downloadedVersions.entries,\n fileId,\n versionId\n );\n entry.fileName = inputPath;\n entry.staged = false;\n entry.translations[locale] = {\n updatedAt: new Date().toISOString(),\n fileName: outputPath,\n };\n didUpdateDownloadedLock = true;\n }\n } catch (error) {\n logger.error(`Error saving file ${fileKey}: ` + error);\n recordWarning(\n 'failed_download',\n fileKey,\n `Error saving file: ${error}`\n );\n result.failed.push(requestedFile);\n }\n }\n\n // Add any files that weren't in the response to the failed list\n const downloadedFileKeys = new Set(\n downloadedFiles.map(\n (file) =>\n `${file.branchId}:${file.fileId}:${file.versionId}:${file.locale}`\n )\n );\n for (const [fileKey, requestedFile] of requestedFileMap.entries()) {\n if (!downloadedFileKeys.has(fileKey)) {\n result.failed.push(requestedFile);\n }\n }\n\n // Persist any updates to the downloaded map at the end of a successful cycle\n if (didUpdateDownloadedLock) {\n writeLockfile(downloadedVersions, originalV1);\n didUpdateDownloadedLock = false;\n }\n return result;\n } catch (error) {\n logger.error(\n `An unexpected error occurred while downloading files: ` + error\n );\n }\n\n // Mark all files as failed if we get here\n result.failed = [...requestedFileMap.values()];\n if (didUpdateDownloadedLock) {\n writeLockfile(downloadedVersions, originalV1);\n }\n return result;\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- export declare const PACKAGE_VERSION = "2.14.49";
1
+ export declare const PACKAGE_VERSION = "2.14.50";
@@ -1,5 +1,5 @@
1
1
  //#region src/generated/version.ts
2
- const PACKAGE_VERSION = "2.14.49";
2
+ const PACKAGE_VERSION = "2.14.50";
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.49';\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.50';\n"],"mappings":";AACA,MAAa,kBAAkB"}
@@ -159,6 +159,7 @@ function processSplitEntries(fileJson, compositeFilePath, docsDir, splitConfig,
159
159
  if (typeof keyValue !== "string" || keyValue === defaultKeyValue) continue;
160
160
  if (!isJsonContainer(entry) || Array.isArray(entry)) continue;
161
161
  const { [keyPropertyName]: _, ...contentWithoutKey } = entry;
162
+ if (typeof contentWithoutKey.$ref === "string") continue;
162
163
  const entryFilePath = path.resolve(entryBaseDir, path.join(keyValue, navFileName));
163
164
  writeJsonFile(entryFilePath, contentWithoutKey);
164
165
  entries[i] = {
@@ -1 +1 @@
1
- {"version":3,"file":"splitMintlifyLanguageRefs.js","names":[],"sources":["../../src/utils/splitMintlifyLanguageRefs.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport { logger } from '../console/logger.js';\nimport { Settings, JsonSchema, SourceObjectOptions } from '../types/index.js';\nimport type { RefMap } from './resolveMintlifyRefs.js';\nimport { validateJsonSchema } from '../formats/json/utils.js';\nimport { getStoredRefMap, clearStoredRefMap } from '../state/mintlifyRefMap.js';\nimport { JSONPath } from 'jsonpath-plus';\nimport { getLocaleProperties } from '@generaltranslation/format';\n\ntype JsonContainer = Record<string, unknown> | unknown[];\n\nfunction isJsonContainer(value: unknown): value is JsonContainer {\n return typeof value === 'object' && value !== null;\n}\n\n/**\n * Post-processing step for composite JSON files with splitEntries enabled.\n *\n * After mergeJson writes a fully-inlined composite file, this function:\n * 1. Restores the original $ref structure (if the source used $ref / resolveRefs)\n * 2. Extracts non-default keyed entries into their own ref files\n * to keep the source file compact\n *\n * Driven entirely by the jsonSchema config — reads the composite path,\n * key field, and splitEntries flag from the schema.\n */\nexport async function splitMintlifyLanguageRefs(\n settings: Settings\n): Promise<void> {\n const refMap = getStoredRefMap();\n\n try {\n const resolvedJsonPaths = settings.files?.resolvedPaths?.json;\n if (!resolvedJsonPaths) return;\n\n // Find a JSON file that has splitEntries enabled or resolveRefs\n const targetFile = findTargetFile(resolvedJsonPaths, settings);\n if (!targetFile) return;\n\n const { filePath: compositeFilePath, splitConfig } = targetFile;\n if (!fs.existsSync(compositeFilePath)) return;\n\n let fileJson: unknown;\n try {\n fileJson = JSON.parse(fs.readFileSync(compositeFilePath, 'utf-8'));\n } catch {\n return;\n }\n\n const docsDir = path.dirname(compositeFilePath);\n\n // If splitEntries is configured, process it\n if (splitConfig) {\n processSplitEntries(\n fileJson,\n compositeFilePath,\n docsDir,\n splitConfig,\n settings,\n refMap\n );\n }\n\n // Restore top-level refs if any exist\n if (refMap && refMap.size > 0) {\n restoreTopLevelRefs(fileJson, refMap, splitConfig);\n }\n\n // Always write the composite file back — splitEntries modified the\n // languages array, and restoreTopLevelRefs may not have written it\n // (e.g., when all refs are inside language entries, not top-level)\n fs.writeFileSync(\n compositeFilePath,\n JSON.stringify(fileJson, null, 2),\n 'utf-8'\n );\n } finally {\n clearStoredRefMap();\n }\n}\n\ntype SplitConfig = {\n compositePath: string;\n jsonPointer: string;\n keyField: string;\n keyJsonPath: string;\n sourceObjectOptions: SourceObjectOptions;\n};\n\n/**\n * Find the target file and extract split configuration from the schema.\n */\nfunction findTargetFile(\n resolvedPaths: string[],\n settings: Settings\n): {\n filePath: string;\n schema: JsonSchema;\n splitConfig: SplitConfig | null;\n} | null {\n if (!settings.options?.jsonSchema) return null;\n\n for (const filePath of resolvedPaths) {\n const schema = validateJsonSchema(settings.options, filePath);\n if (!schema) continue;\n\n const hasSplitEntries = schema.composite\n ? Object.entries(schema.composite).some(([, opts]) => opts.splitEntries)\n : false;\n\n const hasResolveRefs = schema.resolveRefs;\n\n if (!hasSplitEntries && !hasResolveRefs) continue;\n\n // Extract split config if available\n let splitConfig: SplitConfig | null = null;\n if (schema.composite) {\n for (const [compositePath, opts] of Object.entries(schema.composite)) {\n if (opts.splitEntries && opts.type === 'array' && opts.key) {\n splitConfig = {\n compositePath,\n jsonPointer: jsonPathToPointer(compositePath),\n keyField: opts.key,\n keyJsonPath: opts.key,\n sourceObjectOptions: opts,\n };\n break;\n }\n }\n }\n\n return { filePath, schema, splitConfig };\n }\n\n return null;\n}\n\n/**\n * Process splitEntries: extract non-default keyed entries into ref files.\n */\nfunction processSplitEntries(\n fileJson: unknown,\n compositeFilePath: string,\n docsDir: string,\n splitConfig: SplitConfig,\n settings: Settings,\n refMap: RefMap | null\n): void {\n const { jsonPointer, keyJsonPath } = splitConfig;\n\n // Find the composite array — may be behind a $ref\n const parentPointer = jsonPointer.split('/').slice(0, -1).join('/') || '';\n const arrayKey = jsonPointer.split('/').pop() || '';\n const navRefEntry = parentPointer ? refMap?.get(parentPointer) : undefined;\n\n // Get the array from the file\n const arrayContainer = parentPointer\n ? getAtPointer(fileJson, parentPointer)\n : fileJson;\n if (!isJsonContainer(arrayContainer)) return;\n\n const entries = Array.isArray(arrayContainer)\n ? arrayContainer[Number(arrayKey)]\n : arrayContainer[arrayKey];\n if (!Array.isArray(entries) || entries.length <= 1) return;\n\n // Determine the default key value (the source entry)\n const defaultKeyValue = getDefaultKeyValue(\n settings.defaultLocale,\n splitConfig.sourceObjectOptions\n );\n\n const defaultIndex = entries.findIndex((e: unknown) => {\n if (!e || typeof e !== 'object') return false;\n const values = JSONPath({\n json: e,\n path: keyJsonPath,\n resultType: 'value',\n flatten: true,\n wrap: true,\n }) as unknown[];\n return values?.[0] === defaultKeyValue;\n });\n if (defaultIndex < 0) return;\n\n // Detect whether each language entry is itself a $ref (per-entry refs), as\n // opposed to the case where the *container* of the languages array is a $ref\n // (navRefEntry). With per-entry refs, the languages array still lives in the\n // composite file, but each entry's content lives in a separate ref file.\n const defaultEntryPointer = `${jsonPointer}/${defaultIndex}`;\n const defaultEntryRef = refMap?.get(defaultEntryPointer);\n\n // arrayHostDir: directory of the file that physically holds the languages\n // array — entry $refs in the array are written relative to this.\n // entryBaseDir: directory under which per-entry ref files (and their nested\n // refs) are written — mirrors the source entry file's location.\n // These coincide for the container-ref and fully-inline cases; they differ\n // only for per-entry refs, where the array lives in the composite file but\n // the entry files live next to the (default) entry's source ref.\n const arrayHostDir = navRefEntry\n ? path.dirname(navRefEntry.sourceFile)\n : docsDir;\n const entryBaseDir = navRefEntry\n ? path.dirname(navRefEntry.sourceFile)\n : defaultEntryRef\n ? path.dirname(defaultEntryRef.sourceFile)\n : docsDir;\n const navFileName = navRefEntry\n ? path.basename(navRefEntry.sourceFile)\n : defaultEntryRef\n ? path.basename(defaultEntryRef.sourceFile)\n : path.basename(compositeFilePath);\n\n // Restore $ref structure if the source used $ref\n if (refMap && refMap.size > 0) {\n const internalRefs = collectInternalRefs(refMap, defaultEntryPointer);\n\n if (internalRefs.length > 0) {\n // When the default entry is itself a $ref, it is restored to that single\n // $ref below and its source file is left untouched, so we must not restore\n // its nested refs in place. Otherwise (inlined default entry) we do.\n if (!defaultEntryRef) {\n const defaultEntry = entries[defaultIndex];\n for (const ref of internalRefs) {\n setAtPointer(defaultEntry, ref.relativePointer, {\n ...ref.siblings,\n $ref: ref.refPath,\n });\n }\n }\n\n // For each non-default entry, write localized copies of the nested ref\n // files (mirroring the source topology under the locale dir) and replace\n // the inlined subtrees with their $refs.\n for (let i = 0; i < entries.length; i++) {\n if (i === defaultIndex) continue;\n const entry = entries[i];\n\n const entryKeyValues = JSONPath({\n json: entry,\n path: keyJsonPath,\n resultType: 'value',\n flatten: true,\n wrap: true,\n }) as unknown[];\n if (entryKeyValues?.[0] === defaultKeyValue) continue;\n const keyValue =\n typeof entryKeyValues?.[0] === 'string'\n ? entryKeyValues[0]\n : 'unknown';\n\n for (const ref of internalRefs) {\n const subtree = getAtPointer(entry, ref.relativePointer);\n if (subtree === undefined) continue;\n\n const originalAbsPath = path.resolve(ref.resolvedDir, ref.refPath);\n const relToBaseDir = path.relative(entryBaseDir, originalAbsPath);\n const localeRelPath = path.join(keyValue, relToBaseDir);\n const outputPath = path.resolve(entryBaseDir, localeRelPath);\n\n const { siblings, content } = extractRefSiblings(subtree, ref);\n writeJsonFile(outputPath, content);\n\n setAtPointer(entry, ref.relativePointer, {\n ...siblings,\n $ref: ref.refPath,\n });\n }\n }\n\n logger.info(`Restored $ref structure for default entry`);\n }\n }\n\n // Get the actual property name from the key JSONPath (e.g., \"$.language\" → \"language\")\n const keyPropertyName = keyJsonPath.replace(/^\\$\\.?/, '');\n\n // Extract each non-default entry into its own ref file\n for (let i = 0; i < entries.length; i++) {\n if (i === defaultIndex) continue;\n const entry = entries[i];\n if (!entry || typeof entry !== 'object') continue;\n\n const keyValues = JSONPath({\n json: entry,\n path: keyJsonPath,\n resultType: 'value',\n flatten: true,\n wrap: true,\n }) as unknown[];\n const keyValue = keyValues?.[0];\n if (typeof keyValue !== 'string' || keyValue === defaultKeyValue) continue;\n\n if (!isJsonContainer(entry) || Array.isArray(entry)) continue;\n const { [keyPropertyName]: _, ...contentWithoutKey } = entry;\n const entryFilePath = path.resolve(\n entryBaseDir,\n path.join(keyValue, navFileName)\n );\n writeJsonFile(entryFilePath, contentWithoutKey);\n\n entries[i] = {\n [keyPropertyName]: keyValue,\n $ref: toRelativeRefPath(arrayHostDir, entryFilePath),\n };\n }\n\n // When the default entry was itself a $ref, restore it to that single $ref;\n // its source file is the untouched English source already on disk.\n if (defaultEntryRef) {\n entries[defaultIndex] = {\n ...defaultEntryRef.siblings,\n $ref: defaultEntryRef.refPath,\n };\n }\n\n logger.info(`Split keyed entries into ref files`);\n}\n\n/**\n * Get the identifying key value for the default locale.\n */\nfunction getDefaultKeyValue(\n defaultLocale: string,\n sourceObjectOptions: SourceObjectOptions\n): string {\n const localeProperty = sourceObjectOptions.localeProperty || 'code';\n const localeProperties = getLocaleProperties(defaultLocale);\n return (\n (localeProperties as Record<string, string | undefined>)[localeProperty] ||\n localeProperties.code ||\n defaultLocale\n );\n}\n\n/**\n * Convert a JSONPath like \"$.navigation.languages\" to a JSON pointer like \"/navigation/languages\".\n */\nfunction jsonPathToPointer(jsonPath: string): string {\n return jsonPath\n .replace(/^\\$\\.?/, '')\n .split('.')\n .filter(Boolean)\n .map((segment) => `/${segment}`)\n .join('');\n}\n\n/**\n * Restore top-level $ref pointers in the composite file.\n * Sorted deepest-first so nested refs are written before parents.\n */\nfunction restoreTopLevelRefs(\n fileJson: unknown,\n refMap: RefMap,\n splitConfig: SplitConfig | null\n): void {\n // Build a regex to exclude entries inside the composite array\n const arrayPointerPattern = splitConfig\n ? new RegExp(\n `^${splitConfig.jsonPointer.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')}\\\\/\\\\d+`\n )\n : null;\n\n const entries = [...refMap.entries()]\n .filter(\n ([pointer]) => !arrayPointerPattern || !arrayPointerPattern.test(pointer)\n )\n .sort(([a], [b]) => b.length - a.length);\n\n for (const [pointer, entry] of entries) {\n const subtree = getAtPointer(fileJson, pointer);\n if (subtree === undefined) continue;\n\n // If the value here is still an unresolved $ref placeholder, the referenced\n // file was never inlined at this pointer (e.g. mergeJson leaves non-composite\n // refs like `redirects` collapsed). Writing it back would overwrite the\n // source file with a self-referential stub and destroy its real contents —\n // the source already holds the correct data, so leave it untouched.\n if (\n isJsonContainer(subtree) &&\n !Array.isArray(subtree) &&\n typeof (subtree as Record<string, unknown>).$ref === 'string'\n ) {\n continue;\n }\n\n const { siblings, content } = extractRefSiblings(subtree, entry);\n writeJsonFile(entry.sourceFile, content);\n setAtPointer(fileJson, pointer, { ...siblings, $ref: entry.refPath });\n }\n}\n\n/**\n * Mintlify merges keys placed next to a `$ref` on top of the referenced file's\n * content, so ref resolution folds them into the inlined subtree. When\n * restoring the `$ref`, lift those keys back out: they stay next to the `$ref`\n * (with their possibly translated values) and are dropped from the content\n * written to the ref file — unless the referenced file also defined the key,\n * in which case it stays in both, preserving the source topology and\n * Mintlify's sibling-precedence semantics.\n */\nfunction extractRefSiblings(\n subtree: unknown,\n ref: {\n siblings?: Record<string, unknown>;\n originalContent?: unknown;\n refPath?: string;\n }\n): { siblings: Record<string, unknown>; content: unknown } {\n const originalSiblings = ref.siblings ?? {};\n const siblingKeys = Object.keys(originalSiblings);\n if (siblingKeys.length === 0) {\n return { siblings: {}, content: subtree };\n }\n if (!isJsonContainer(subtree) || Array.isArray(subtree)) {\n // Non-object content cannot carry merged siblings; restore the originals\n return { siblings: { ...originalSiblings }, content: subtree };\n }\n const content = { ...subtree };\n const siblings: Record<string, unknown> = {};\n const original = ref.originalContent;\n const originalContentHasKey = (key: string) =>\n isJsonContainer(original) && !Array.isArray(original) && key in original;\n for (const key of siblingKeys) {\n if (key in content) {\n siblings[key] = content[key];\n if (!originalContentHasKey(key)) {\n delete content[key];\n }\n } else {\n // Object resolutions always merge siblings into the subtree, so this\n // only fires if that invariant breaks upstream. Restoring the source\n // value keeps the output schema-valid, but it skips translation — warn\n // so the regression is visible.\n logger.warn(\n `Sibling key \"${key}\" missing from translated content for $ref ${ref.refPath ?? '(unknown)'}; restoring source value`\n );\n siblings[key] = originalSiblings[key];\n }\n }\n return { siblings, content };\n}\n\n/**\n * Collect refMap entries that describe an entry's internal $ref chain.\n * Sorted deepest-first so nested content is extracted before parents.\n */\nfunction collectInternalRefs(\n refMap: RefMap,\n entryPointerPrefix: string\n): {\n relativePointer: string;\n refPath: string;\n resolvedDir: string;\n siblings?: Record<string, unknown>;\n originalContent?: unknown;\n}[] {\n const refs: {\n relativePointer: string;\n refPath: string;\n resolvedDir: string;\n siblings?: Record<string, unknown>;\n originalContent?: unknown;\n }[] = [];\n\n for (const [pointer, entry] of refMap.entries()) {\n if (!pointer.startsWith(entryPointerPrefix + '/')) continue;\n refs.push({\n relativePointer: pointer.slice(entryPointerPrefix.length),\n refPath: entry.refPath,\n resolvedDir: entry.containingDir,\n siblings: entry.siblings,\n originalContent: entry.originalContent,\n });\n }\n\n refs.sort((a, b) => b.relativePointer.length - a.relativePointer.length);\n return refs;\n}\n\nfunction writeJsonFile(filePath: string, data: unknown): void {\n const dir = path.dirname(filePath);\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true });\n }\n fs.writeFileSync(filePath, JSON.stringify(data, null, 2), 'utf-8');\n}\n\n/**\n * Build a relative $ref path (POSIX separators, \"./\"-prefixed when it isn't\n * already a relative or absolute path) from the directory that hosts the\n * languages array to a written entry file.\n */\nfunction toRelativeRefPath(fromDir: string, toPath: string): string {\n const rel = path.relative(fromDir, toPath).split(path.sep).join('/');\n return rel.startsWith('.') || rel.startsWith('/') ? rel : `./${rel}`;\n}\n\nfunction getAtPointer(obj: unknown, pointer: string): unknown {\n if (!pointer || pointer === '/') return obj;\n const parts = pointer.split('/').filter(Boolean);\n let current = obj;\n for (const part of parts) {\n if (!isJsonContainer(current)) return undefined;\n const index = /^\\d+$/.test(part) ? parseInt(part) : part;\n current = Array.isArray(current)\n ? current[index as number]\n : current[index];\n }\n return current;\n}\n\nfunction setAtPointer(obj: unknown, pointer: string, value: unknown): void {\n if (!pointer || pointer === '/') return;\n const parts = pointer.split('/').filter(Boolean);\n let current = obj;\n for (let i = 0; i < parts.length - 1; i++) {\n if (!isJsonContainer(current)) return;\n const index = /^\\d+$/.test(parts[i]) ? parseInt(parts[i]) : parts[i];\n const next = Array.isArray(current)\n ? current[index as number]\n : current[index];\n if (next === undefined) return;\n current = next;\n }\n const lastPart = parts[parts.length - 1];\n const lastIndex = /^\\d+$/.test(lastPart) ? parseInt(lastPart) : lastPart;\n if (!isJsonContainer(current)) return;\n if (Array.isArray(current)) {\n current[lastIndex as number] = value;\n } else {\n current[lastIndex] = value;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"splitMintlifyLanguageRefs.js","names":[],"sources":["../../src/utils/splitMintlifyLanguageRefs.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport { logger } from '../console/logger.js';\nimport { Settings, JsonSchema, SourceObjectOptions } from '../types/index.js';\nimport type { RefMap } from './resolveMintlifyRefs.js';\nimport { validateJsonSchema } from '../formats/json/utils.js';\nimport { getStoredRefMap, clearStoredRefMap } from '../state/mintlifyRefMap.js';\nimport { JSONPath } from 'jsonpath-plus';\nimport { getLocaleProperties } from '@generaltranslation/format';\n\ntype JsonContainer = Record<string, unknown> | unknown[];\n\nfunction isJsonContainer(value: unknown): value is JsonContainer {\n return typeof value === 'object' && value !== null;\n}\n\n/**\n * Post-processing step for composite JSON files with splitEntries enabled.\n *\n * After mergeJson writes a fully-inlined composite file, this function:\n * 1. Restores the original $ref structure (if the source used $ref / resolveRefs)\n * 2. Extracts non-default keyed entries into their own ref files\n * to keep the source file compact\n *\n * Driven entirely by the jsonSchema config — reads the composite path,\n * key field, and splitEntries flag from the schema.\n */\nexport async function splitMintlifyLanguageRefs(\n settings: Settings\n): Promise<void> {\n const refMap = getStoredRefMap();\n\n try {\n const resolvedJsonPaths = settings.files?.resolvedPaths?.json;\n if (!resolvedJsonPaths) return;\n\n // Find a JSON file that has splitEntries enabled or resolveRefs\n const targetFile = findTargetFile(resolvedJsonPaths, settings);\n if (!targetFile) return;\n\n const { filePath: compositeFilePath, splitConfig } = targetFile;\n if (!fs.existsSync(compositeFilePath)) return;\n\n let fileJson: unknown;\n try {\n fileJson = JSON.parse(fs.readFileSync(compositeFilePath, 'utf-8'));\n } catch {\n return;\n }\n\n const docsDir = path.dirname(compositeFilePath);\n\n // If splitEntries is configured, process it\n if (splitConfig) {\n processSplitEntries(\n fileJson,\n compositeFilePath,\n docsDir,\n splitConfig,\n settings,\n refMap\n );\n }\n\n // Restore top-level refs if any exist\n if (refMap && refMap.size > 0) {\n restoreTopLevelRefs(fileJson, refMap, splitConfig);\n }\n\n // Always write the composite file back — splitEntries modified the\n // languages array, and restoreTopLevelRefs may not have written it\n // (e.g., when all refs are inside language entries, not top-level)\n fs.writeFileSync(\n compositeFilePath,\n JSON.stringify(fileJson, null, 2),\n 'utf-8'\n );\n } finally {\n clearStoredRefMap();\n }\n}\n\ntype SplitConfig = {\n compositePath: string;\n jsonPointer: string;\n keyField: string;\n keyJsonPath: string;\n sourceObjectOptions: SourceObjectOptions;\n};\n\n/**\n * Find the target file and extract split configuration from the schema.\n */\nfunction findTargetFile(\n resolvedPaths: string[],\n settings: Settings\n): {\n filePath: string;\n schema: JsonSchema;\n splitConfig: SplitConfig | null;\n} | null {\n if (!settings.options?.jsonSchema) return null;\n\n for (const filePath of resolvedPaths) {\n const schema = validateJsonSchema(settings.options, filePath);\n if (!schema) continue;\n\n const hasSplitEntries = schema.composite\n ? Object.entries(schema.composite).some(([, opts]) => opts.splitEntries)\n : false;\n\n const hasResolveRefs = schema.resolveRefs;\n\n if (!hasSplitEntries && !hasResolveRefs) continue;\n\n // Extract split config if available\n let splitConfig: SplitConfig | null = null;\n if (schema.composite) {\n for (const [compositePath, opts] of Object.entries(schema.composite)) {\n if (opts.splitEntries && opts.type === 'array' && opts.key) {\n splitConfig = {\n compositePath,\n jsonPointer: jsonPathToPointer(compositePath),\n keyField: opts.key,\n keyJsonPath: opts.key,\n sourceObjectOptions: opts,\n };\n break;\n }\n }\n }\n\n return { filePath, schema, splitConfig };\n }\n\n return null;\n}\n\n/**\n * Process splitEntries: extract non-default keyed entries into ref files.\n */\nfunction processSplitEntries(\n fileJson: unknown,\n compositeFilePath: string,\n docsDir: string,\n splitConfig: SplitConfig,\n settings: Settings,\n refMap: RefMap | null\n): void {\n const { jsonPointer, keyJsonPath } = splitConfig;\n\n // Find the composite array — may be behind a $ref\n const parentPointer = jsonPointer.split('/').slice(0, -1).join('/') || '';\n const arrayKey = jsonPointer.split('/').pop() || '';\n const navRefEntry = parentPointer ? refMap?.get(parentPointer) : undefined;\n\n // Get the array from the file\n const arrayContainer = parentPointer\n ? getAtPointer(fileJson, parentPointer)\n : fileJson;\n if (!isJsonContainer(arrayContainer)) return;\n\n const entries = Array.isArray(arrayContainer)\n ? arrayContainer[Number(arrayKey)]\n : arrayContainer[arrayKey];\n if (!Array.isArray(entries) || entries.length <= 1) return;\n\n // Determine the default key value (the source entry)\n const defaultKeyValue = getDefaultKeyValue(\n settings.defaultLocale,\n splitConfig.sourceObjectOptions\n );\n\n const defaultIndex = entries.findIndex((e: unknown) => {\n if (!e || typeof e !== 'object') return false;\n const values = JSONPath({\n json: e,\n path: keyJsonPath,\n resultType: 'value',\n flatten: true,\n wrap: true,\n }) as unknown[];\n return values?.[0] === defaultKeyValue;\n });\n if (defaultIndex < 0) return;\n\n // Detect whether each language entry is itself a $ref (per-entry refs), as\n // opposed to the case where the *container* of the languages array is a $ref\n // (navRefEntry). With per-entry refs, the languages array still lives in the\n // composite file, but each entry's content lives in a separate ref file.\n const defaultEntryPointer = `${jsonPointer}/${defaultIndex}`;\n const defaultEntryRef = refMap?.get(defaultEntryPointer);\n\n // arrayHostDir: directory of the file that physically holds the languages\n // array — entry $refs in the array are written relative to this.\n // entryBaseDir: directory under which per-entry ref files (and their nested\n // refs) are written — mirrors the source entry file's location.\n // These coincide for the container-ref and fully-inline cases; they differ\n // only for per-entry refs, where the array lives in the composite file but\n // the entry files live next to the (default) entry's source ref.\n const arrayHostDir = navRefEntry\n ? path.dirname(navRefEntry.sourceFile)\n : docsDir;\n const entryBaseDir = navRefEntry\n ? path.dirname(navRefEntry.sourceFile)\n : defaultEntryRef\n ? path.dirname(defaultEntryRef.sourceFile)\n : docsDir;\n const navFileName = navRefEntry\n ? path.basename(navRefEntry.sourceFile)\n : defaultEntryRef\n ? path.basename(defaultEntryRef.sourceFile)\n : path.basename(compositeFilePath);\n\n // Restore $ref structure if the source used $ref\n if (refMap && refMap.size > 0) {\n const internalRefs = collectInternalRefs(refMap, defaultEntryPointer);\n\n if (internalRefs.length > 0) {\n // When the default entry is itself a $ref, it is restored to that single\n // $ref below and its source file is left untouched, so we must not restore\n // its nested refs in place. Otherwise (inlined default entry) we do.\n if (!defaultEntryRef) {\n const defaultEntry = entries[defaultIndex];\n for (const ref of internalRefs) {\n setAtPointer(defaultEntry, ref.relativePointer, {\n ...ref.siblings,\n $ref: ref.refPath,\n });\n }\n }\n\n // For each non-default entry, write localized copies of the nested ref\n // files (mirroring the source topology under the locale dir) and replace\n // the inlined subtrees with their $refs.\n for (let i = 0; i < entries.length; i++) {\n if (i === defaultIndex) continue;\n const entry = entries[i];\n\n const entryKeyValues = JSONPath({\n json: entry,\n path: keyJsonPath,\n resultType: 'value',\n flatten: true,\n wrap: true,\n }) as unknown[];\n if (entryKeyValues?.[0] === defaultKeyValue) continue;\n const keyValue =\n typeof entryKeyValues?.[0] === 'string'\n ? entryKeyValues[0]\n : 'unknown';\n\n for (const ref of internalRefs) {\n const subtree = getAtPointer(entry, ref.relativePointer);\n if (subtree === undefined) continue;\n\n const originalAbsPath = path.resolve(ref.resolvedDir, ref.refPath);\n const relToBaseDir = path.relative(entryBaseDir, originalAbsPath);\n const localeRelPath = path.join(keyValue, relToBaseDir);\n const outputPath = path.resolve(entryBaseDir, localeRelPath);\n\n const { siblings, content } = extractRefSiblings(subtree, ref);\n writeJsonFile(outputPath, content);\n\n setAtPointer(entry, ref.relativePointer, {\n ...siblings,\n $ref: ref.refPath,\n });\n }\n }\n\n logger.info(`Restored $ref structure for default entry`);\n }\n }\n\n // Get the actual property name from the key JSONPath (e.g., \"$.language\" → \"language\")\n const keyPropertyName = keyJsonPath.replace(/^\\$\\.?/, '');\n\n // Extract each non-default entry into its own ref file\n for (let i = 0; i < entries.length; i++) {\n if (i === defaultIndex) continue;\n const entry = entries[i];\n if (!entry || typeof entry !== 'object') continue;\n\n const keyValues = JSONPath({\n json: entry,\n path: keyJsonPath,\n resultType: 'value',\n flatten: true,\n wrap: true,\n }) as unknown[];\n const keyValue = keyValues?.[0];\n if (typeof keyValue !== 'string' || keyValue === defaultKeyValue) continue;\n\n if (!isJsonContainer(entry) || Array.isArray(entry)) continue;\n const { [keyPropertyName]: _, ...contentWithoutKey } = entry;\n\n // If the entry still carries a top-level $ref, it was never inlined this\n // run (e.g. the merge step didn't process this file). There is no content\n // to extract — writing would produce a self-referential stub that\n // overwrites or shadows the real ref file. Leave the entry untouched.\n if (typeof contentWithoutKey.$ref === 'string') {\n continue;\n }\n\n const entryFilePath = path.resolve(\n entryBaseDir,\n path.join(keyValue, navFileName)\n );\n writeJsonFile(entryFilePath, contentWithoutKey);\n\n entries[i] = {\n [keyPropertyName]: keyValue,\n $ref: toRelativeRefPath(arrayHostDir, entryFilePath),\n };\n }\n\n // When the default entry was itself a $ref, restore it to that single $ref;\n // its source file is the untouched English source already on disk.\n if (defaultEntryRef) {\n entries[defaultIndex] = {\n ...defaultEntryRef.siblings,\n $ref: defaultEntryRef.refPath,\n };\n }\n\n logger.info(`Split keyed entries into ref files`);\n}\n\n/**\n * Get the identifying key value for the default locale.\n */\nfunction getDefaultKeyValue(\n defaultLocale: string,\n sourceObjectOptions: SourceObjectOptions\n): string {\n const localeProperty = sourceObjectOptions.localeProperty || 'code';\n const localeProperties = getLocaleProperties(defaultLocale);\n return (\n (localeProperties as Record<string, string | undefined>)[localeProperty] ||\n localeProperties.code ||\n defaultLocale\n );\n}\n\n/**\n * Convert a JSONPath like \"$.navigation.languages\" to a JSON pointer like \"/navigation/languages\".\n */\nfunction jsonPathToPointer(jsonPath: string): string {\n return jsonPath\n .replace(/^\\$\\.?/, '')\n .split('.')\n .filter(Boolean)\n .map((segment) => `/${segment}`)\n .join('');\n}\n\n/**\n * Restore top-level $ref pointers in the composite file.\n * Sorted deepest-first so nested refs are written before parents.\n */\nfunction restoreTopLevelRefs(\n fileJson: unknown,\n refMap: RefMap,\n splitConfig: SplitConfig | null\n): void {\n // Build a regex to exclude entries inside the composite array\n const arrayPointerPattern = splitConfig\n ? new RegExp(\n `^${splitConfig.jsonPointer.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')}\\\\/\\\\d+`\n )\n : null;\n\n const entries = [...refMap.entries()]\n .filter(\n ([pointer]) => !arrayPointerPattern || !arrayPointerPattern.test(pointer)\n )\n .sort(([a], [b]) => b.length - a.length);\n\n for (const [pointer, entry] of entries) {\n const subtree = getAtPointer(fileJson, pointer);\n if (subtree === undefined) continue;\n\n // If the value here is still an unresolved $ref placeholder, the referenced\n // file was never inlined at this pointer (e.g. mergeJson leaves non-composite\n // refs like `redirects` collapsed). Writing it back would overwrite the\n // source file with a self-referential stub and destroy its real contents —\n // the source already holds the correct data, so leave it untouched.\n if (\n isJsonContainer(subtree) &&\n !Array.isArray(subtree) &&\n typeof (subtree as Record<string, unknown>).$ref === 'string'\n ) {\n continue;\n }\n\n const { siblings, content } = extractRefSiblings(subtree, entry);\n writeJsonFile(entry.sourceFile, content);\n setAtPointer(fileJson, pointer, { ...siblings, $ref: entry.refPath });\n }\n}\n\n/**\n * Mintlify merges keys placed next to a `$ref` on top of the referenced file's\n * content, so ref resolution folds them into the inlined subtree. When\n * restoring the `$ref`, lift those keys back out: they stay next to the `$ref`\n * (with their possibly translated values) and are dropped from the content\n * written to the ref file — unless the referenced file also defined the key,\n * in which case it stays in both, preserving the source topology and\n * Mintlify's sibling-precedence semantics.\n */\nfunction extractRefSiblings(\n subtree: unknown,\n ref: {\n siblings?: Record<string, unknown>;\n originalContent?: unknown;\n refPath?: string;\n }\n): { siblings: Record<string, unknown>; content: unknown } {\n const originalSiblings = ref.siblings ?? {};\n const siblingKeys = Object.keys(originalSiblings);\n if (siblingKeys.length === 0) {\n return { siblings: {}, content: subtree };\n }\n if (!isJsonContainer(subtree) || Array.isArray(subtree)) {\n // Non-object content cannot carry merged siblings; restore the originals\n return { siblings: { ...originalSiblings }, content: subtree };\n }\n const content = { ...subtree };\n const siblings: Record<string, unknown> = {};\n const original = ref.originalContent;\n const originalContentHasKey = (key: string) =>\n isJsonContainer(original) && !Array.isArray(original) && key in original;\n for (const key of siblingKeys) {\n if (key in content) {\n siblings[key] = content[key];\n if (!originalContentHasKey(key)) {\n delete content[key];\n }\n } else {\n // Object resolutions always merge siblings into the subtree, so this\n // only fires if that invariant breaks upstream. Restoring the source\n // value keeps the output schema-valid, but it skips translation — warn\n // so the regression is visible.\n logger.warn(\n `Sibling key \"${key}\" missing from translated content for $ref ${ref.refPath ?? '(unknown)'}; restoring source value`\n );\n siblings[key] = originalSiblings[key];\n }\n }\n return { siblings, content };\n}\n\n/**\n * Collect refMap entries that describe an entry's internal $ref chain.\n * Sorted deepest-first so nested content is extracted before parents.\n */\nfunction collectInternalRefs(\n refMap: RefMap,\n entryPointerPrefix: string\n): {\n relativePointer: string;\n refPath: string;\n resolvedDir: string;\n siblings?: Record<string, unknown>;\n originalContent?: unknown;\n}[] {\n const refs: {\n relativePointer: string;\n refPath: string;\n resolvedDir: string;\n siblings?: Record<string, unknown>;\n originalContent?: unknown;\n }[] = [];\n\n for (const [pointer, entry] of refMap.entries()) {\n if (!pointer.startsWith(entryPointerPrefix + '/')) continue;\n refs.push({\n relativePointer: pointer.slice(entryPointerPrefix.length),\n refPath: entry.refPath,\n resolvedDir: entry.containingDir,\n siblings: entry.siblings,\n originalContent: entry.originalContent,\n });\n }\n\n refs.sort((a, b) => b.relativePointer.length - a.relativePointer.length);\n return refs;\n}\n\nfunction writeJsonFile(filePath: string, data: unknown): void {\n const dir = path.dirname(filePath);\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true });\n }\n fs.writeFileSync(filePath, JSON.stringify(data, null, 2), 'utf-8');\n}\n\n/**\n * Build a relative $ref path (POSIX separators, \"./\"-prefixed when it isn't\n * already a relative or absolute path) from the directory that hosts the\n * languages array to a written entry file.\n */\nfunction toRelativeRefPath(fromDir: string, toPath: string): string {\n const rel = path.relative(fromDir, toPath).split(path.sep).join('/');\n return rel.startsWith('.') || rel.startsWith('/') ? rel : `./${rel}`;\n}\n\nfunction getAtPointer(obj: unknown, pointer: string): unknown {\n if (!pointer || pointer === '/') return obj;\n const parts = pointer.split('/').filter(Boolean);\n let current = obj;\n for (const part of parts) {\n if (!isJsonContainer(current)) return undefined;\n const index = /^\\d+$/.test(part) ? parseInt(part) : part;\n current = Array.isArray(current)\n ? current[index as number]\n : current[index];\n }\n return current;\n}\n\nfunction setAtPointer(obj: unknown, pointer: string, value: unknown): void {\n if (!pointer || pointer === '/') return;\n const parts = pointer.split('/').filter(Boolean);\n let current = obj;\n for (let i = 0; i < parts.length - 1; i++) {\n if (!isJsonContainer(current)) return;\n const index = /^\\d+$/.test(parts[i]) ? parseInt(parts[i]) : parts[i];\n const next = Array.isArray(current)\n ? current[index as number]\n : current[index];\n if (next === undefined) return;\n current = next;\n }\n const lastPart = parts[parts.length - 1];\n const lastIndex = /^\\d+$/.test(lastPart) ? parseInt(lastPart) : lastPart;\n if (!isJsonContainer(current)) return;\n if (Array.isArray(current)) {\n current[lastIndex as number] = value;\n } else {\n current[lastIndex] = value;\n }\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.49",
3
+ "version": "2.14.50",
4
4
  "main": "dist/index.js",
5
5
  "bin": "bin/main.js",
6
6
  "files": [