gt 2.20.4 → 2.21.1
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 +28 -0
- package/dist/api/collectUserEditDiffs.d.ts +2 -0
- package/dist/api/collectUserEditDiffs.js +31 -8
- package/dist/api/collectUserEditDiffs.js.map +1 -1
- package/dist/api/downloadFileBatch.js +13 -6
- package/dist/api/downloadFileBatch.js.map +1 -1
- package/dist/cli/base.js +2 -2
- package/dist/cli/base.js.map +1 -1
- package/dist/cli/commands/upload.js +30 -11
- package/dist/cli/commands/upload.js.map +1 -1
- package/dist/console/index.d.ts +4 -0
- package/dist/console/index.js +2 -1
- package/dist/console/index.js.map +1 -1
- package/dist/formats/files/aggregateFiles.js +39 -2
- package/dist/formats/files/aggregateFiles.js.map +1 -1
- package/dist/formats/files/localeContent.d.ts +18 -0
- package/dist/formats/files/localeContent.js +34 -0
- package/dist/formats/files/localeContent.js.map +1 -0
- package/dist/formats/files/supportedFiles.d.ts +2 -1
- package/dist/formats/files/supportedFiles.js +4 -2
- package/dist/formats/files/supportedFiles.js.map +1 -1
- package/dist/formats/files/transformFormat.d.ts +2 -0
- package/dist/formats/files/transformFormat.js +6 -3
- package/dist/formats/files/transformFormat.js.map +1 -1
- package/dist/formats/xcstrings/mergeXcstrings.d.ts +13 -0
- package/dist/formats/xcstrings/mergeXcstrings.js +71 -0
- package/dist/formats/xcstrings/mergeXcstrings.js.map +1 -0
- package/dist/formats/xcstrings/parseXcstrings.d.ts +43 -0
- package/dist/formats/xcstrings/parseXcstrings.js +123 -0
- package/dist/formats/xcstrings/parseXcstrings.js.map +1 -0
- package/dist/fs/config/parseFilesConfig.d.ts +2 -2
- package/dist/fs/config/parseFilesConfig.js +17 -3
- package/dist/fs/config/parseFilesConfig.js.map +1 -1
- package/dist/generated/version.d.ts +1 -1
- package/dist/generated/version.js +1 -1
- package/dist/generated/version.js.map +1 -1
- package/dist/state/recentDownloads.d.ts +1 -1
- package/dist/state/recentDownloads.js +3 -1
- package/dist/state/recentDownloads.js.map +1 -1
- package/dist/utils/api.d.ts +1 -1
- package/dist/utils/api.js +2 -1
- package/dist/utils/api.js.map +1 -1
- package/dist/utils/persistPostprocessHashes.d.ts +1 -1
- package/dist/utils/persistPostprocessHashes.js +18 -14
- package/dist/utils/persistPostprocessHashes.js.map +1 -1
- package/package.json +7 -7
|
@@ -65,13 +65,14 @@ function resolveFiles(files, locale, locales, cwd, compositePatterns, requiresRe
|
|
|
65
65
|
const parsingFlags = {};
|
|
66
66
|
if (files.gt?.output) placeholderResult.gt = path.resolve(cwd, files.gt.output);
|
|
67
67
|
for (const fileType of SUPPORTED_FILE_EXTENSIONS) {
|
|
68
|
+
if (fileType === "xcstrings") validateXcstringsInPlace(files.xcstrings);
|
|
68
69
|
const transform = files[fileType]?.transform;
|
|
69
70
|
if (transform && (typeof transform === "string" || typeof transform === "object" || Array.isArray(transform))) transformPaths[fileType] = transform;
|
|
70
71
|
const transformFormat = resolveTransformationFormat(fileType, files[fileType]?.transformationFormat);
|
|
71
72
|
if (transformFormat) transformFormats[fileType] = transformFormat;
|
|
72
73
|
if (files[fileType]?.include) {
|
|
73
74
|
const { paths, publishPatterns, unpublishPatterns } = normalizeIncludePatterns(files[fileType].include);
|
|
74
|
-
const filePaths = expandGlobPatterns(cwd, paths, files[fileType]?.exclude || [], locale, locales, transformPaths[fileType] || void 0, compositePatterns);
|
|
75
|
+
const filePaths = expandGlobPatterns(cwd, paths, files[fileType]?.exclude || [], locale, locales, transformPaths[fileType] || void 0, compositePatterns, fileType);
|
|
75
76
|
resolvedPaths[fileType] = filePaths.resolvedPaths;
|
|
76
77
|
placeholderResult[fileType] = filePaths.placeholderPaths;
|
|
77
78
|
classifyPublishPaths(filePaths.resolvedPaths, publishPatterns, unpublishPatterns, cwd, locale, publishPaths, unpublishPaths);
|
|
@@ -103,11 +104,11 @@ function resolveFiles(files, locale, locales, cwd, compositePatterns, requiresRe
|
|
|
103
104
|
})()
|
|
104
105
|
};
|
|
105
106
|
}
|
|
106
|
-
function expandGlobPatterns(cwd, includePatterns, excludePatterns, locale, locales, transformPatterns, compositePatterns) {
|
|
107
|
+
function expandGlobPatterns(cwd, includePatterns, excludePatterns, locale, locales, transformPatterns, compositePatterns, fileType) {
|
|
107
108
|
const resolvedPaths = [];
|
|
108
109
|
const placeholderPaths = [];
|
|
109
110
|
for (const pattern of includePatterns) {
|
|
110
|
-
if (!pattern.includes("[locale]") && !transformPatterns && !compositePatterns?.includes(pattern)) logger.warn(chalk.yellow(`Pattern "${pattern}" does not include [locale], so the CLI tool may incorrectly save translated files.`));
|
|
111
|
+
if (!pattern.includes("[locale]") && !transformPatterns && !compositePatterns?.includes(pattern) && fileType !== "xcstrings") logger.warn(chalk.yellow(`Pattern "${pattern}" does not include [locale], so the CLI tool may incorrectly save translated files.`));
|
|
111
112
|
const localePositions = [];
|
|
112
113
|
let searchIndex = 0;
|
|
113
114
|
const localeTag = "[locale]";
|
|
@@ -179,6 +180,19 @@ function classifyPublishPaths(resolvedPaths, publishPatterns, unpublishPatterns,
|
|
|
179
180
|
}
|
|
180
181
|
}
|
|
181
182
|
/**
|
|
183
|
+
* An .xcstrings catalog holds every locale in one file and is updated in
|
|
184
|
+
* place: each locale's download is merged into the source catalog. A path
|
|
185
|
+
* transform or a `[locale]` placeholder would map each locale to a separate
|
|
186
|
+
* output, and every write would start from the source catalog and discard the
|
|
187
|
+
* locales written before it.
|
|
188
|
+
*/
|
|
189
|
+
function validateXcstringsInPlace(config) {
|
|
190
|
+
if (!config) return;
|
|
191
|
+
if (config.transform) logErrorAndExit("files.xcstrings.transform is not supported. An .xcstrings catalog holds every locale in one file and is updated in place, so remove the transform.");
|
|
192
|
+
const localePatterns = normalizeIncludePatterns(config.include ?? []).paths.filter((pattern) => pattern.includes("[locale]"));
|
|
193
|
+
if (localePatterns.length > 0) logErrorAndExit(`files.xcstrings.include must not contain [locale]: ${localePatterns.map((pattern) => `"${pattern}"`).join(", ")}. An .xcstrings catalog holds every locale in one file and is updated in place, so point the pattern at the catalog itself.`);
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
182
196
|
* Validates a file-type requiresReview config value. Only a boolean or an
|
|
183
197
|
* object of include/exclude glob string arrays is accepted — notably not
|
|
184
198
|
* string "true"/"false", so a misquoted boolean fails loudly instead of
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parseFilesConfig.js","names":[],"sources":["../../../src/fs/config/parseFilesConfig.ts"],"sourcesContent":["import path from 'node:path';\nimport {\n FilesOptions,\n IncludePattern,\n RequiresReviewConfig,\n ResolvedFiles,\n Settings,\n TransformFormats,\n TransformFiles,\n TransformOption,\n} from '../../types/index.js';\nimport { logErrorAndExit } from '../../console/logging.js';\nimport fg from 'fast-glob';\nimport { SUPPORTED_FILE_EXTENSIONS } from '../../formats/files/supportedFiles.js';\nimport { logger } from '../../console/logger.js';\nimport chalk from 'chalk';\nimport micromatch from 'micromatch';\nimport { ParseFlagsByFileType } from '../../types/parsing.js';\nimport {\n BASE_PARSING_FLAGS_DEFAULT,\n GT_PARSING_FLAGS_DEFAULT,\n} from '../../config/defaults.js';\nimport { resolveTransformationFormat } from '../../formats/files/transformFormat.js';\nimport { localeForFilePath } from '../../formats/files/localePath.js';\n\n/**\n * Resolves the files from the files object\n * Replaces [locale] with the actual locale in the files\n *\n * @param files - The files object\n * @param locale - The locale to replace [locale] with\n * @returns The resolved files\n */\nexport function resolveLocaleFiles(\n files: ResolvedFiles,\n locale: string\n): ResolvedFiles {\n const result: ResolvedFiles = {};\n\n for (const fileType of SUPPORTED_FILE_EXTENSIONS) {\n const replacement = localeForFilePath(fileType, locale);\n result[fileType] = files[fileType]?.map((filepath) =>\n filepath.replace(/\\[locale\\]/g, replacement)\n );\n }\n\n // Replace [locale] with locale in all paths\n result.gt = files.gt?.replace(/\\[locale\\]/g, locale);\n\n return result;\n}\n/**\n * Normalizes include patterns into plain path strings and tracks which\n * patterns have explicit publish flags.\n */\nexport function normalizeIncludePatterns(patterns: IncludePattern[]): {\n paths: string[];\n publishPatterns: string[];\n unpublishPatterns: string[];\n} {\n const paths: string[] = [];\n const publishPatterns: string[] = [];\n const unpublishPatterns: string[] = [];\n\n for (const pattern of patterns) {\n if (typeof pattern === 'string') {\n paths.push(pattern);\n } else {\n paths.push(pattern.pattern);\n if (pattern.publish === true) {\n publishPatterns.push(pattern.pattern);\n } else if (pattern.publish === false) {\n unpublishPatterns.push(pattern.pattern);\n }\n }\n }\n\n return { paths, publishPatterns, unpublishPatterns };\n}\n\n/**\n * Resolves the files from the files object.\n * Performs glob pattern expansion on the files.\n * Replaces [locale] with the actual locale in the files.\n *\n * @param files - The files object\n * @returns The resolved files\n */\nexport function resolveFiles(\n files: FilesOptions,\n locale: string,\n locales: string[],\n cwd: string,\n compositePatterns?: string[],\n requiresReviewDefault: boolean = false\n): Settings['files'] {\n // Initialize result object with empty arrays for each file type\n const resolvedPaths: ResolvedFiles = {};\n const placeholderResult: ResolvedFiles = {};\n const transformPaths: TransformFiles = {};\n // Output format transforms are tracked separately from path transforms.\n const transformFormats: TransformFormats = {};\n const publishPaths = new Set<string>();\n const unpublishPaths = new Set<string>();\n const requiresReviewPaths = new Set<string>();\n const parsingFlags: ParseFlagsByFileType = {};\n\n // Process GT files\n if (files.gt?.output) {\n placeholderResult.gt = path.resolve(cwd, files.gt.output);\n }\n\n for (const fileType of SUPPORTED_FILE_EXTENSIONS) {\n // ==== TRANSFORMS ==== //\n const transform = files[fileType]?.transform;\n if (\n transform &&\n (typeof transform === 'string' ||\n typeof transform === 'object' ||\n Array.isArray(transform))\n ) {\n transformPaths[fileType] = transform;\n }\n // Validate source -> output format transforms during settings generation.\n const transformFormat = resolveTransformationFormat(\n fileType,\n files[fileType]?.transformationFormat\n );\n if (transformFormat) {\n transformFormats[fileType] = transformFormat;\n }\n // ==== PLACEHOLDERS ==== //\n if (files[fileType]?.include) {\n const { paths, publishPatterns, unpublishPatterns } =\n normalizeIncludePatterns(files[fileType].include);\n\n const filePaths = expandGlobPatterns(\n cwd,\n paths,\n files[fileType]?.exclude || [],\n locale,\n locales,\n transformPaths[fileType] || undefined,\n compositePatterns\n );\n resolvedPaths[fileType] = filePaths.resolvedPaths;\n placeholderResult[fileType] = filePaths.placeholderPaths;\n\n // Classify resolved paths into publish/unpublish sets\n classifyPublishPaths(\n filePaths.resolvedPaths,\n publishPatterns,\n unpublishPatterns,\n cwd,\n locale,\n publishPaths,\n unpublishPaths\n );\n\n // Classify resolved paths by effective requiresReview policy\n classifyRequiresReviewPaths(\n filePaths.resolvedPaths,\n validateRequiresReviewConfig(files[fileType]?.requiresReview, fileType),\n requiresReviewDefault,\n cwd,\n locale,\n requiresReviewPaths\n );\n }\n // ==== OTHER ==== //\n if (files[fileType]?.parsingFlags) {\n parsingFlags[fileType] = {\n ...BASE_PARSING_FLAGS_DEFAULT,\n ...files[fileType].parsingFlags,\n };\n }\n }\n\n return {\n resolvedPaths,\n placeholderPaths: placeholderResult,\n transformPaths: transformPaths,\n transformFormats,\n publishPaths,\n unpublishPaths,\n requiresReviewPaths,\n parsingFlags,\n gtJson: (() => {\n const rawGtFlags = (files.gt?.parsingFlags || {}) as Record<\n string,\n unknown\n >;\n return {\n publish: files.gt?.publish,\n parsingFlags: {\n ...GT_PARSING_FLAGS_DEFAULT,\n ...rawGtFlags,\n },\n };\n })(),\n };\n}\n\n// Helper function to expand glob patterns\nexport function expandGlobPatterns(\n cwd: string,\n includePatterns: string[],\n excludePatterns: string[],\n locale: string,\n locales: string[],\n transformPatterns?: TransformOption | string | TransformOption[],\n compositePatterns?: string[]\n): {\n resolvedPaths: string[];\n placeholderPaths: string[];\n} {\n // Expand glob patterns to include all matching files\n const resolvedPaths: string[] = [];\n const placeholderPaths: string[] = [];\n\n // Process include patterns\n for (const pattern of includePatterns) {\n // Track positions where [locale] appears in the original pattern\n // It must be included in the pattern, otherwise the CLI tool will not be able to find the correct output path\n // Warn if it's not included\n // Ignore if is composite pattern\n if (\n !pattern.includes('[locale]') &&\n !transformPatterns &&\n !compositePatterns?.includes(pattern)\n ) {\n logger.warn(\n chalk.yellow(\n `Pattern \"${pattern}\" does not include [locale], so the CLI tool may incorrectly save translated files.`\n )\n );\n }\n const localePositions: number[] = [];\n let searchIndex = 0;\n const localeTag = '[locale]';\n\n while (true) {\n const foundIndex = pattern.indexOf(localeTag, searchIndex);\n if (foundIndex === -1) break;\n localePositions.push(foundIndex);\n searchIndex = foundIndex + localeTag.length;\n }\n\n const expandedPattern = pattern.replace(/\\[locale\\]/g, locale);\n\n // Resolve the absolute pattern path\n const absolutePattern = path.resolve(cwd, expandedPattern);\n\n // Prepare exclude patterns with locale replaced\n const expandedExcludePatterns = Array.from(\n new Set(\n excludePatterns.flatMap((p) =>\n locales.map((targetLocale) =>\n path.resolve(\n cwd,\n p\n .replace(/\\[locale\\]/g, locale)\n .replace(/\\[locales\\]/g, targetLocale)\n )\n )\n )\n )\n );\n\n // Use fast-glob to find all matching files, excluding the patterns\n const matches = fg.sync(absolutePattern, {\n absolute: true,\n ignore: expandedExcludePatterns,\n });\n\n resolvedPaths.push(...matches);\n\n // For each match, create a version with [locale] in the correct positions\n matches.forEach((match) => {\n const absolutePath = path.resolve(cwd, match);\n const patternPath = path.resolve(cwd, pattern);\n let originalAbsolutePath = absolutePath;\n\n if (localePositions.length > 0) {\n const placeholderPath = buildPlaceholderPathFromPattern(\n patternPath,\n absolutePath,\n localeTag\n );\n originalAbsolutePath = placeholderPath;\n }\n\n placeholderPaths.push(originalAbsolutePath);\n });\n }\n\n return { resolvedPaths, placeholderPaths };\n}\n\nfunction buildPlaceholderPathFromPattern(\n patternPath: string,\n absolutePath: string,\n localeTag: string\n): string {\n if (!patternPath.includes(localeTag)) {\n return absolutePath;\n }\n\n const posixPattern = toPosixPath(patternPath);\n const posixPath = toPosixPath(absolutePath);\n\n const baseRegex = micromatch.makeRe(posixPattern, {\n literalBrackets: true,\n });\n const localeRegexSource = baseRegex.source.replace(\n /\\\\\\[locale\\\\\\]/g,\n '([^/]+)'\n );\n const flags = baseRegex.flags.includes('d')\n ? baseRegex.flags\n : `${baseRegex.flags}d`;\n const matcher = new RegExp(localeRegexSource, flags);\n const match = matcher.exec(posixPath);\n\n const matchWithIndices = match as RegExpExecArray & {\n indices?: Array<[number, number]>;\n };\n\n if (!match || !matchWithIndices.indices) {\n return absolutePath;\n }\n\n let placeholderPosixPath = posixPath;\n const indices = matchWithIndices.indices;\n\n for (let i = indices.length - 1; i >= 1; i--) {\n const [start, end] = indices[i];\n if (start === -1 || end === -1) continue;\n placeholderPosixPath =\n placeholderPosixPath.slice(0, start) +\n localeTag +\n placeholderPosixPath.slice(end);\n }\n\n return path.normalize(placeholderPosixPath);\n}\n\nfunction toPosixPath(value: string): string {\n return value.split(path.sep).join(path.posix.sep);\n}\n\n/**\n * Classifies resolved file paths into publish/unpublish sets by matching\n * them against the given glob patterns. Uses POSIX paths for micromatch\n * compatibility but stores platform-native paths in the output sets.\n */\nfunction classifyPublishPaths(\n resolvedPaths: string[],\n publishPatterns: string[],\n unpublishPatterns: string[],\n cwd: string,\n locale: string,\n publishPaths: Set<string>,\n unpublishPaths: Set<string>\n): void {\n if (publishPatterns.length === 0 && unpublishPatterns.length === 0) return;\n\n const posixPaths = resolvedPaths.map(toPosixPath);\n const toAbsoluteGlob = (p: string) =>\n toPosixPath(path.resolve(cwd, p.replace(/\\[locale\\]/g, locale)));\n\n for (const pattern of publishPatterns) {\n const matched = new Set(micromatch(posixPaths, toAbsoluteGlob(pattern)));\n for (let i = 0; i < posixPaths.length; i++) {\n if (matched.has(posixPaths[i])) {\n publishPaths.add(resolvedPaths[i]);\n }\n }\n }\n\n for (const pattern of unpublishPatterns) {\n const matched = new Set(micromatch(posixPaths, toAbsoluteGlob(pattern)));\n for (let i = 0; i < posixPaths.length; i++) {\n if (matched.has(posixPaths[i])) {\n unpublishPaths.add(resolvedPaths[i]);\n }\n }\n }\n}\n\n/**\n * Validates a file-type requiresReview config value. Only a boolean or an\n * object of include/exclude glob string arrays is accepted — notably not\n * string \"true\"/\"false\", so a misquoted boolean fails loudly instead of\n * silently changing review policy (and with it, version identity).\n */\nfunction validateRequiresReviewConfig(\n config: unknown,\n fileType: string\n): RequiresReviewConfig | undefined {\n if (config === undefined || typeof config === 'boolean') {\n return config;\n }\n const isStringArray = (value: unknown): value is string[] =>\n Array.isArray(value) && value.every((item) => typeof item === 'string');\n if (\n config !== null &&\n typeof config === 'object' &&\n !Array.isArray(config) &&\n Object.keys(config).every((key) => key === 'include' || key === 'exclude')\n ) {\n const { include, exclude } = config as Record<string, unknown>;\n if (\n (include === undefined || isStringArray(include)) &&\n (exclude === undefined || isStringArray(exclude))\n ) {\n return config as RequiresReviewConfig;\n }\n }\n return logErrorAndExit(\n `files.${fileType}.requiresReview must be a boolean or an object of glob string arrays: { include?: string[], exclude?: string[] }`\n );\n}\n\n/**\n * Classifies resolved file paths by effective requiresReview policy and adds\n * paths whose policy is true to requiresReviewPaths. Precedence: file-type\n * include/exclude globs (exclude wins) > file-type boolean > top-level default.\n */\nfunction classifyRequiresReviewPaths(\n resolvedPaths: string[],\n config: RequiresReviewConfig | undefined,\n requiresReviewDefault: boolean,\n cwd: string,\n locale: string,\n requiresReviewPaths: Set<string>\n): void {\n if (typeof config === 'boolean' || config === undefined) {\n if (config ?? requiresReviewDefault) {\n for (const resolvedPath of resolvedPaths) {\n requiresReviewPaths.add(resolvedPath);\n }\n }\n return;\n }\n\n const posixPaths = resolvedPaths.map(toPosixPath);\n const toAbsoluteGlob = (p: string) =>\n toPosixPath(path.resolve(cwd, p.replace(/\\[locale\\]/g, locale)));\n const matchAny = (patterns: string[]) => {\n const matched = new Set<string>();\n for (const pattern of patterns) {\n for (const match of micromatch(posixPaths, toAbsoluteGlob(pattern))) {\n matched.add(match);\n }\n }\n return matched;\n };\n\n const included = matchAny(config.include ?? []);\n const excluded = matchAny(config.exclude ?? []);\n\n for (let i = 0; i < posixPaths.length; i++) {\n const requiresReview = excluded.has(posixPaths[i])\n ? false\n : included.has(posixPaths[i]) || requiresReviewDefault;\n if (requiresReview) {\n requiresReviewPaths.add(resolvedPaths[i]);\n }\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"parseFilesConfig.js","names":[],"sources":["../../../src/fs/config/parseFilesConfig.ts"],"sourcesContent":["import path from 'node:path';\nimport {\n FilesOptions,\n IncludePattern,\n RequiresReviewConfig,\n ResolvedFiles,\n Settings,\n SupportedFileExtension,\n TransformFormats,\n TransformFiles,\n TransformOption,\n} from '../../types/index.js';\nimport { logErrorAndExit } from '../../console/logging.js';\nimport fg from 'fast-glob';\nimport { SUPPORTED_FILE_EXTENSIONS } from '../../formats/files/supportedFiles.js';\nimport { logger } from '../../console/logger.js';\nimport chalk from 'chalk';\nimport micromatch from 'micromatch';\nimport { ParseFlagsByFileType } from '../../types/parsing.js';\nimport {\n BASE_PARSING_FLAGS_DEFAULT,\n GT_PARSING_FLAGS_DEFAULT,\n} from '../../config/defaults.js';\nimport { resolveTransformationFormat } from '../../formats/files/transformFormat.js';\nimport { localeForFilePath } from '../../formats/files/localePath.js';\n\n/**\n * Resolves the files from the files object\n * Replaces [locale] with the actual locale in the files\n *\n * @param files - The files object\n * @param locale - The locale to replace [locale] with\n * @returns The resolved files\n */\nexport function resolveLocaleFiles(\n files: ResolvedFiles,\n locale: string\n): ResolvedFiles {\n const result: ResolvedFiles = {};\n\n for (const fileType of SUPPORTED_FILE_EXTENSIONS) {\n const replacement = localeForFilePath(fileType, locale);\n result[fileType] = files[fileType]?.map((filepath) =>\n filepath.replace(/\\[locale\\]/g, replacement)\n );\n }\n\n // Replace [locale] with locale in all paths\n result.gt = files.gt?.replace(/\\[locale\\]/g, locale);\n\n return result;\n}\n/**\n * Normalizes include patterns into plain path strings and tracks which\n * patterns have explicit publish flags.\n */\nexport function normalizeIncludePatterns(patterns: IncludePattern[]): {\n paths: string[];\n publishPatterns: string[];\n unpublishPatterns: string[];\n} {\n const paths: string[] = [];\n const publishPatterns: string[] = [];\n const unpublishPatterns: string[] = [];\n\n for (const pattern of patterns) {\n if (typeof pattern === 'string') {\n paths.push(pattern);\n } else {\n paths.push(pattern.pattern);\n if (pattern.publish === true) {\n publishPatterns.push(pattern.pattern);\n } else if (pattern.publish === false) {\n unpublishPatterns.push(pattern.pattern);\n }\n }\n }\n\n return { paths, publishPatterns, unpublishPatterns };\n}\n\n/**\n * Resolves the files from the files object.\n * Performs glob pattern expansion on the files.\n * Replaces [locale] with the actual locale in the files.\n *\n * @param files - The files object\n * @returns The resolved files\n */\nexport function resolveFiles(\n files: FilesOptions,\n locale: string,\n locales: string[],\n cwd: string,\n compositePatterns?: string[],\n requiresReviewDefault: boolean = false\n): Settings['files'] {\n // Initialize result object with empty arrays for each file type\n const resolvedPaths: ResolvedFiles = {};\n const placeholderResult: ResolvedFiles = {};\n const transformPaths: TransformFiles = {};\n // Output format transforms are tracked separately from path transforms.\n const transformFormats: TransformFormats = {};\n const publishPaths = new Set<string>();\n const unpublishPaths = new Set<string>();\n const requiresReviewPaths = new Set<string>();\n const parsingFlags: ParseFlagsByFileType = {};\n\n // Process GT files\n if (files.gt?.output) {\n placeholderResult.gt = path.resolve(cwd, files.gt.output);\n }\n\n for (const fileType of SUPPORTED_FILE_EXTENSIONS) {\n if (fileType === 'xcstrings') validateXcstringsInPlace(files.xcstrings);\n // ==== TRANSFORMS ==== //\n const transform = files[fileType]?.transform;\n if (\n transform &&\n (typeof transform === 'string' ||\n typeof transform === 'object' ||\n Array.isArray(transform))\n ) {\n transformPaths[fileType] = transform;\n }\n // Validate source -> output format transforms during settings generation.\n const transformFormat = resolveTransformationFormat(\n fileType,\n files[fileType]?.transformationFormat\n );\n if (transformFormat) {\n transformFormats[fileType] = transformFormat;\n }\n // ==== PLACEHOLDERS ==== //\n if (files[fileType]?.include) {\n const { paths, publishPatterns, unpublishPatterns } =\n normalizeIncludePatterns(files[fileType].include);\n\n const filePaths = expandGlobPatterns(\n cwd,\n paths,\n files[fileType]?.exclude || [],\n locale,\n locales,\n transformPaths[fileType] || undefined,\n compositePatterns,\n fileType\n );\n resolvedPaths[fileType] = filePaths.resolvedPaths;\n placeholderResult[fileType] = filePaths.placeholderPaths;\n\n // Classify resolved paths into publish/unpublish sets\n classifyPublishPaths(\n filePaths.resolvedPaths,\n publishPatterns,\n unpublishPatterns,\n cwd,\n locale,\n publishPaths,\n unpublishPaths\n );\n\n // Classify resolved paths by effective requiresReview policy\n classifyRequiresReviewPaths(\n filePaths.resolvedPaths,\n validateRequiresReviewConfig(files[fileType]?.requiresReview, fileType),\n requiresReviewDefault,\n cwd,\n locale,\n requiresReviewPaths\n );\n }\n // ==== OTHER ==== //\n if (files[fileType]?.parsingFlags) {\n parsingFlags[fileType] = {\n ...BASE_PARSING_FLAGS_DEFAULT,\n ...files[fileType].parsingFlags,\n };\n }\n }\n\n return {\n resolvedPaths,\n placeholderPaths: placeholderResult,\n transformPaths: transformPaths,\n transformFormats,\n publishPaths,\n unpublishPaths,\n requiresReviewPaths,\n parsingFlags,\n gtJson: (() => {\n const rawGtFlags = (files.gt?.parsingFlags || {}) as Record<\n string,\n unknown\n >;\n return {\n publish: files.gt?.publish,\n parsingFlags: {\n ...GT_PARSING_FLAGS_DEFAULT,\n ...rawGtFlags,\n },\n };\n })(),\n };\n}\n\n// Helper function to expand glob patterns\nexport function expandGlobPatterns(\n cwd: string,\n includePatterns: string[],\n excludePatterns: string[],\n locale: string,\n locales: string[],\n transformPatterns?: TransformOption | string | TransformOption[],\n compositePatterns?: string[],\n fileType?: SupportedFileExtension\n): {\n resolvedPaths: string[];\n placeholderPaths: string[];\n} {\n // Expand glob patterns to include all matching files\n const resolvedPaths: string[] = [];\n const placeholderPaths: string[] = [];\n\n // Process include patterns\n for (const pattern of includePatterns) {\n // Track positions where [locale] appears in the original pattern\n // It must be included in the pattern, otherwise the CLI tool will not be able to find the correct output path\n // Warn if it's not included\n // Ignore if is composite pattern\n // xcstrings catalogs hold every locale in one shared file, so a pattern\n // without [locale] is the expected layout there, not a misconfiguration\n if (\n !pattern.includes('[locale]') &&\n !transformPatterns &&\n !compositePatterns?.includes(pattern) &&\n fileType !== 'xcstrings'\n ) {\n logger.warn(\n chalk.yellow(\n `Pattern \"${pattern}\" does not include [locale], so the CLI tool may incorrectly save translated files.`\n )\n );\n }\n const localePositions: number[] = [];\n let searchIndex = 0;\n const localeTag = '[locale]';\n\n while (true) {\n const foundIndex = pattern.indexOf(localeTag, searchIndex);\n if (foundIndex === -1) break;\n localePositions.push(foundIndex);\n searchIndex = foundIndex + localeTag.length;\n }\n\n const expandedPattern = pattern.replace(/\\[locale\\]/g, locale);\n\n // Resolve the absolute pattern path\n const absolutePattern = path.resolve(cwd, expandedPattern);\n\n // Prepare exclude patterns with locale replaced\n const expandedExcludePatterns = Array.from(\n new Set(\n excludePatterns.flatMap((p) =>\n locales.map((targetLocale) =>\n path.resolve(\n cwd,\n p\n .replace(/\\[locale\\]/g, locale)\n .replace(/\\[locales\\]/g, targetLocale)\n )\n )\n )\n )\n );\n\n // Use fast-glob to find all matching files, excluding the patterns\n const matches = fg.sync(absolutePattern, {\n absolute: true,\n ignore: expandedExcludePatterns,\n });\n\n resolvedPaths.push(...matches);\n\n // For each match, create a version with [locale] in the correct positions\n matches.forEach((match) => {\n const absolutePath = path.resolve(cwd, match);\n const patternPath = path.resolve(cwd, pattern);\n let originalAbsolutePath = absolutePath;\n\n if (localePositions.length > 0) {\n const placeholderPath = buildPlaceholderPathFromPattern(\n patternPath,\n absolutePath,\n localeTag\n );\n originalAbsolutePath = placeholderPath;\n }\n\n placeholderPaths.push(originalAbsolutePath);\n });\n }\n\n return { resolvedPaths, placeholderPaths };\n}\n\nfunction buildPlaceholderPathFromPattern(\n patternPath: string,\n absolutePath: string,\n localeTag: string\n): string {\n if (!patternPath.includes(localeTag)) {\n return absolutePath;\n }\n\n const posixPattern = toPosixPath(patternPath);\n const posixPath = toPosixPath(absolutePath);\n\n const baseRegex = micromatch.makeRe(posixPattern, {\n literalBrackets: true,\n });\n const localeRegexSource = baseRegex.source.replace(\n /\\\\\\[locale\\\\\\]/g,\n '([^/]+)'\n );\n const flags = baseRegex.flags.includes('d')\n ? baseRegex.flags\n : `${baseRegex.flags}d`;\n const matcher = new RegExp(localeRegexSource, flags);\n const match = matcher.exec(posixPath);\n\n const matchWithIndices = match as RegExpExecArray & {\n indices?: Array<[number, number]>;\n };\n\n if (!match || !matchWithIndices.indices) {\n return absolutePath;\n }\n\n let placeholderPosixPath = posixPath;\n const indices = matchWithIndices.indices;\n\n for (let i = indices.length - 1; i >= 1; i--) {\n const [start, end] = indices[i];\n if (start === -1 || end === -1) continue;\n placeholderPosixPath =\n placeholderPosixPath.slice(0, start) +\n localeTag +\n placeholderPosixPath.slice(end);\n }\n\n return path.normalize(placeholderPosixPath);\n}\n\nfunction toPosixPath(value: string): string {\n return value.split(path.sep).join(path.posix.sep);\n}\n\n/**\n * Classifies resolved file paths into publish/unpublish sets by matching\n * them against the given glob patterns. Uses POSIX paths for micromatch\n * compatibility but stores platform-native paths in the output sets.\n */\nfunction classifyPublishPaths(\n resolvedPaths: string[],\n publishPatterns: string[],\n unpublishPatterns: string[],\n cwd: string,\n locale: string,\n publishPaths: Set<string>,\n unpublishPaths: Set<string>\n): void {\n if (publishPatterns.length === 0 && unpublishPatterns.length === 0) return;\n\n const posixPaths = resolvedPaths.map(toPosixPath);\n const toAbsoluteGlob = (p: string) =>\n toPosixPath(path.resolve(cwd, p.replace(/\\[locale\\]/g, locale)));\n\n for (const pattern of publishPatterns) {\n const matched = new Set(micromatch(posixPaths, toAbsoluteGlob(pattern)));\n for (let i = 0; i < posixPaths.length; i++) {\n if (matched.has(posixPaths[i])) {\n publishPaths.add(resolvedPaths[i]);\n }\n }\n }\n\n for (const pattern of unpublishPatterns) {\n const matched = new Set(micromatch(posixPaths, toAbsoluteGlob(pattern)));\n for (let i = 0; i < posixPaths.length; i++) {\n if (matched.has(posixPaths[i])) {\n unpublishPaths.add(resolvedPaths[i]);\n }\n }\n }\n}\n\n/**\n * An .xcstrings catalog holds every locale in one file and is updated in\n * place: each locale's download is merged into the source catalog. A path\n * transform or a `[locale]` placeholder would map each locale to a separate\n * output, and every write would start from the source catalog and discard the\n * locales written before it.\n */\nfunction validateXcstringsInPlace(config: FilesOptions['xcstrings']): void {\n if (!config) return;\n if (config.transform) {\n logErrorAndExit(\n 'files.xcstrings.transform is not supported. An .xcstrings catalog holds every locale in one file and is updated in place, so remove the transform.'\n );\n }\n const localePatterns = normalizeIncludePatterns(\n config.include ?? []\n ).paths.filter((pattern) => pattern.includes('[locale]'));\n if (localePatterns.length > 0) {\n logErrorAndExit(\n `files.xcstrings.include must not contain [locale]: ${localePatterns\n .map((pattern) => `\"${pattern}\"`)\n .join(\n ', '\n )}. An .xcstrings catalog holds every locale in one file and is updated in place, so point the pattern at the catalog itself.`\n );\n }\n}\n\n/**\n * Validates a file-type requiresReview config value. Only a boolean or an\n * object of include/exclude glob string arrays is accepted — notably not\n * string \"true\"/\"false\", so a misquoted boolean fails loudly instead of\n * silently changing review policy (and with it, version identity).\n */\nfunction validateRequiresReviewConfig(\n config: unknown,\n fileType: string\n): RequiresReviewConfig | undefined {\n if (config === undefined || typeof config === 'boolean') {\n return config;\n }\n const isStringArray = (value: unknown): value is string[] =>\n Array.isArray(value) && value.every((item) => typeof item === 'string');\n if (\n config !== null &&\n typeof config === 'object' &&\n !Array.isArray(config) &&\n Object.keys(config).every((key) => key === 'include' || key === 'exclude')\n ) {\n const { include, exclude } = config as Record<string, unknown>;\n if (\n (include === undefined || isStringArray(include)) &&\n (exclude === undefined || isStringArray(exclude))\n ) {\n return config as RequiresReviewConfig;\n }\n }\n return logErrorAndExit(\n `files.${fileType}.requiresReview must be a boolean or an object of glob string arrays: { include?: string[], exclude?: string[] }`\n );\n}\n\n/**\n * Classifies resolved file paths by effective requiresReview policy and adds\n * paths whose policy is true to requiresReviewPaths. Precedence: file-type\n * include/exclude globs (exclude wins) > file-type boolean > top-level default.\n */\nfunction classifyRequiresReviewPaths(\n resolvedPaths: string[],\n config: RequiresReviewConfig | undefined,\n requiresReviewDefault: boolean,\n cwd: string,\n locale: string,\n requiresReviewPaths: Set<string>\n): void {\n if (typeof config === 'boolean' || config === undefined) {\n if (config ?? requiresReviewDefault) {\n for (const resolvedPath of resolvedPaths) {\n requiresReviewPaths.add(resolvedPath);\n }\n }\n return;\n }\n\n const posixPaths = resolvedPaths.map(toPosixPath);\n const toAbsoluteGlob = (p: string) =>\n toPosixPath(path.resolve(cwd, p.replace(/\\[locale\\]/g, locale)));\n const matchAny = (patterns: string[]) => {\n const matched = new Set<string>();\n for (const pattern of patterns) {\n for (const match of micromatch(posixPaths, toAbsoluteGlob(pattern))) {\n matched.add(match);\n }\n }\n return matched;\n };\n\n const included = matchAny(config.include ?? []);\n const excluded = matchAny(config.exclude ?? []);\n\n for (let i = 0; i < posixPaths.length; i++) {\n const requiresReview = excluded.has(posixPaths[i])\n ? false\n : included.has(posixPaths[i]) || requiresReviewDefault;\n if (requiresReview) {\n requiresReviewPaths.add(resolvedPaths[i]);\n }\n }\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const PACKAGE_VERSION = "2.
|
|
1
|
+
export declare const PACKAGE_VERSION = "2.21.1";
|
|
@@ -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.
|
|
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.21.1';\n"],"mappings":";AACA,MAAa,kBAAkB"}
|
|
@@ -16,5 +16,5 @@ export declare function recordRemerged(filePath: string): void;
|
|
|
16
16
|
export declare function getDownloaded(): Set<string>;
|
|
17
17
|
/** Files that need postprocessing: downloaded OR re-merged */
|
|
18
18
|
export declare function getNeedsPostprocessing(): Set<string>;
|
|
19
|
-
export declare function getDownloadedMeta(): Map<string, DownloadMeta>;
|
|
19
|
+
export declare function getDownloadedMeta(): Map<string, DownloadMeta[]>;
|
|
20
20
|
export declare function clearDownloaded(): void;
|
|
@@ -4,7 +4,9 @@ const recentMeta = /* @__PURE__ */ new Map();
|
|
|
4
4
|
const remerged = /* @__PURE__ */ new Set();
|
|
5
5
|
function recordDownloaded(filePath, meta) {
|
|
6
6
|
recent.add(filePath);
|
|
7
|
-
if (meta)
|
|
7
|
+
if (!meta) return;
|
|
8
|
+
const metas = recentMeta.get(filePath) ?? [];
|
|
9
|
+
recentMeta.set(filePath, [...metas.filter((existing) => existing.locale !== meta.locale), meta]);
|
|
8
10
|
}
|
|
9
11
|
/**
|
|
10
12
|
* Track a file that was re-merged with the source
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"recentDownloads.js","names":[],"sources":["../../src/state/recentDownloads.ts"],"sourcesContent":["import type { FileFormat } from 'generaltranslation/types';\n\nexport type DownloadMeta = {\n branchId: string;\n fileId: string;\n versionId: string;\n locale: string;\n // The format the file was written as, so it can be read back the same way.\n fileFormat: FileFormat;\n inputPath?: string;\n};\n\nconst recent = new Set<string>();\nconst recentMeta = new Map<string, DownloadMeta>();\nconst remerged = new Set<string>();\n\nexport function recordDownloaded(filePath: string, meta?: DownloadMeta) {\n recent.add(filePath);\n if (meta)
|
|
1
|
+
{"version":3,"file":"recentDownloads.js","names":[],"sources":["../../src/state/recentDownloads.ts"],"sourcesContent":["import type { FileFormat } from 'generaltranslation/types';\n\nexport type DownloadMeta = {\n branchId: string;\n fileId: string;\n versionId: string;\n locale: string;\n // The format the file was written as, so it can be read back the same way.\n fileFormat: FileFormat;\n inputPath?: string;\n};\n\nconst recent = new Set<string>();\n// A file that holds every locale (a Mintlify composite docs.json) is written once per\n// locale, so a path keeps one entry per locale rather than the last one.\nconst recentMeta = new Map<string, DownloadMeta[]>();\nconst remerged = new Set<string>();\n\nexport function recordDownloaded(filePath: string, meta?: DownloadMeta) {\n recent.add(filePath);\n if (!meta) return;\n const metas = recentMeta.get(filePath) ?? [];\n recentMeta.set(filePath, [\n ...metas.filter((existing) => existing.locale !== meta.locale),\n meta,\n ]);\n}\n\n/**\n * Track a file that was re-merged with the source\n * so that postprocessing still runs on it.\n */\nexport function recordRemerged(filePath: string) {\n remerged.add(filePath);\n}\n\nexport function getDownloaded(): Set<string> {\n return recent;\n}\n\n/** Files that need postprocessing: downloaded OR re-merged */\nexport function getNeedsPostprocessing(): Set<string> {\n return new Set([...recent, ...remerged]);\n}\n\nexport function getDownloadedMeta(): Map<string, DownloadMeta[]> {\n return recentMeta;\n}\n\nexport function clearDownloaded() {\n recent.clear();\n recentMeta.clear();\n remerged.clear();\n}\n"],"mappings":";AAYA,MAAM,yBAAS,IAAI,KAAa;AAGhC,MAAM,6BAAa,IAAI,KAA6B;AACpD,MAAM,2BAAW,IAAI,KAAa;AAElC,SAAgB,iBAAiB,UAAkB,MAAqB;AACtE,QAAO,IAAI,SAAS;AACpB,KAAI,CAAC,KAAM;CACX,MAAM,QAAQ,WAAW,IAAI,SAAS,IAAI,EAAE;AAC5C,YAAW,IAAI,UAAU,CACvB,GAAG,MAAM,QAAQ,aAAa,SAAS,WAAW,KAAK,OAAO,EAC9D,KACD,CAAC;;;;;;AAOJ,SAAgB,eAAe,UAAkB;AAC/C,UAAS,IAAI,SAAS;;AAGxB,SAAgB,gBAA6B;AAC3C,QAAO;;;AAIT,SAAgB,yBAAsC;AACpD,QAAO,IAAI,IAAI,CAAC,GAAG,QAAQ,GAAG,SAAS,CAAC;;AAG1C,SAAgB,oBAAiD;AAC/D,QAAO;;AAGT,SAAgB,kBAAkB;AAChC,QAAO,OAAO;AACd,YAAW,OAAO;AAClB,UAAS,OAAO"}
|
package/dist/utils/api.d.ts
CHANGED
|
@@ -113,7 +113,7 @@ export declare const api: {
|
|
|
113
113
|
updatedAt: string;
|
|
114
114
|
};
|
|
115
115
|
}>;
|
|
116
|
-
createProject(body: CreateProjectData["body"]): Promise<{
|
|
116
|
+
createProject(orgId: CreateProjectData["path"]["orgId"], body: CreateProjectData["body"]): Promise<{
|
|
117
117
|
project: {
|
|
118
118
|
id: string;
|
|
119
119
|
name: string;
|
package/dist/utils/api.js
CHANGED
|
@@ -129,8 +129,9 @@ const api = {
|
|
|
129
129
|
client: getClient()
|
|
130
130
|
}));
|
|
131
131
|
},
|
|
132
|
-
async createProject(body) {
|
|
132
|
+
async createProject(orgId, body) {
|
|
133
133
|
return unwrapApiResult(await createProject({
|
|
134
|
+
path: { orgId },
|
|
134
135
|
body: {
|
|
135
136
|
...body,
|
|
136
137
|
defaultLocale: resolveCanonicalLocale(body.defaultLocale, customMapping)
|
package/dist/utils/api.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.js","names":[],"sources":["../../src/utils/api.ts"],"sourcesContent":["import {\n resolveAliasLocale,\n resolveCanonicalLocale,\n} from '@generaltranslation/format';\nimport type { CustomMapping } from '@generaltranslation/format/types';\nimport {\n createApiClient,\n createBranch,\n createProject,\n createTag,\n decodeFileContent,\n DEFAULT_BATCH_SIZE,\n downloadFiles,\n encodeFileContent,\n enqueueFileTranslations,\n generateProjectContext,\n getBranchInfo,\n getFileInfo,\n getOrphanedFiles,\n getProjectInfo,\n getTranslationJobInfo,\n pollJobs,\n processBatches,\n processFileMoves,\n publishFiles,\n submitUserEditDiffs,\n uploadSourceFiles,\n uploadTranslations,\n type ApiClientConfig,\n type AwaitJobsOptions,\n type CreateBranchData,\n type CreateProjectData,\n type CreateTagData,\n type DownloadFilesData,\n type EnqueueFileTranslationsData,\n type GenerateProjectContextData,\n type GetBranchInfoData,\n type GetFileInfoData,\n type ProcessFileMovesData,\n type PublishFilesData,\n type SubmitUserEditDiffsData,\n type UploadSourceFilesData,\n type UploadTranslationsData,\n} from 'generaltranslation/api';\nimport { unwrapApiResult } from 'generaltranslation/internal';\n\nlet client: ReturnType<typeof createApiClient> | undefined;\nlet configuredClientConfig: ApiClientConfig | undefined;\nlet customMapping: CustomMapping | undefined;\n\nfunction getConfiguredClient(): {\n client: ReturnType<typeof createApiClient>;\n config: ApiClientConfig;\n} {\n if (!client || !configuredClientConfig) {\n throw new Error(\n 'API client not configured — call configureApiClient first'\n );\n }\n return { client, config: configuredClientConfig };\n}\n\nfunction getClient(): ReturnType<typeof createApiClient> {\n return getConfiguredClient().client;\n}\n\nfunction getClientConfig(): ApiClientConfig {\n return getConfiguredClient().config;\n}\n\nexport function configureApiClient(\n config: ApiClientConfig & { customMapping?: CustomMapping }\n): void {\n const { customMapping: mapping, ...clientConfig } = config;\n client = createApiClient(clientConfig);\n // Retain the resolved config for the one project-info call that deliberately\n // uses a shorter timeout than normal translation requests.\n configuredClientConfig = clientConfig;\n customMapping = mapping;\n}\n\nexport const api = {\n async queryBranchData(body: GetBranchInfoData['body']) {\n return unwrapApiResult(await getBranchInfo({ body, client: getClient() }));\n },\n\n async createBranch(body: CreateBranchData['body']) {\n return unwrapApiResult(await createBranch({ body, client: getClient() }));\n },\n\n async queryFileData(body: GetFileInfoData['body']) {\n const result = unwrapApiResult(\n await getFileInfo({\n body: {\n ...body,\n translatedFiles: body.translatedFiles?.map((file) => ({\n ...file,\n locale: resolveCanonicalLocale(file.locale, customMapping),\n })),\n },\n client: getClient(),\n })\n );\n return {\n ...result,\n translatedFiles: result.translatedFiles.map((file) => ({\n ...file,\n locale: resolveAliasLocale(file.locale, customMapping),\n })),\n sourceFiles: result.sourceFiles.map((file) => ({\n ...file,\n sourceLocale: resolveAliasLocale(file.sourceLocale, customMapping),\n locales: file.locales.map((locale) =>\n resolveAliasLocale(locale, customMapping)\n ),\n })),\n };\n },\n\n async checkJobStatus(jobIds: string[]) {\n return unwrapApiResult(\n await getTranslationJobInfo({\n body: { jobIds },\n client: getClient(),\n })\n );\n },\n\n async getProjectInfo(timeoutMs: number) {\n const config = getClientConfig();\n if (!config.projectId) {\n throw new Error('Project ID is required to fetch project information');\n }\n const projectInfoClient = createApiClient({ ...config, timeoutMs });\n return unwrapApiResult(\n await getProjectInfo({\n client: projectInfoClient,\n path: { projectId: config.projectId },\n })\n );\n },\n\n resolveAliasLocale(locale: string) {\n return resolveAliasLocale(locale, customMapping);\n },\n\n async downloadFileBatch(files: DownloadFilesData['body']) {\n if (files.length === 0) return { files: [], count: 0, pending: [] };\n\n const request = async (batch: DownloadFilesData['body']) =>\n unwrapApiResult(\n await downloadFiles({\n body: batch.map((file) => ({\n ...file,\n locale: file.locale\n ? resolveCanonicalLocale(file.locale, customMapping)\n : undefined,\n })),\n client: getClient(),\n })\n );\n const responses = await processBatches(files, async (batch) => [\n await request(batch),\n ]);\n return {\n files: responses.flatMap((response) =>\n response.files.map((file) => ({\n ...file,\n ...(file.locale && {\n locale: resolveAliasLocale(file.locale, customMapping),\n }),\n data: decodeFileContent(file.data, file.fileFormat),\n }))\n ),\n count: responses.reduce((count, response) => count + response.count, 0),\n pending: responses.flatMap((response) => response.pending ?? []),\n };\n },\n\n async publishFiles(files: PublishFilesData['body']['files']) {\n return unwrapApiResult(\n await publishFiles({ body: { files }, client: getClient() })\n );\n },\n\n async submitUserEditDiffs(body: SubmitUserEditDiffsData['body']) {\n return processBatches(body.diffs, async (diffs) => [\n unwrapApiResult(\n await submitUserEditDiffs({\n body: {\n projectId: body.projectId,\n diffs: diffs.map((diff) => ({\n ...diff,\n locale: resolveCanonicalLocale(diff.locale, customMapping),\n })),\n },\n client: getClient(),\n })\n ),\n ]);\n },\n\n async createTag(body: CreateTagData['body']) {\n return unwrapApiResult(await createTag({ body, client: getClient() }));\n },\n\n async createProject(body: CreateProjectData['body']) {\n return unwrapApiResult(\n await createProject({\n body: {\n ...body,\n defaultLocale: resolveCanonicalLocale(\n body.defaultLocale,\n customMapping\n ),\n },\n client: getClient(),\n })\n );\n },\n\n // ponytail: duplicates core/src/translate/getOrphanedFiles.ts batching +\n // intersection; delete one copy when utils/gt.ts is removed.\n async getOrphanedFiles(branchId: string, fileIds: string[]) {\n const request = async (batch: string[]) =>\n unwrapApiResult(\n await getOrphanedFiles({\n body: { branchId, fileIds: batch },\n client: getClient(),\n })\n );\n\n if (fileIds.length === 0) return request([]);\n\n const results = await processBatches(fileIds, async (batch) => [\n await request(batch),\n ]);\n const orphanedFiles = new Map(\n results[0].orphanedFiles.map((file) => [file.fileId, file])\n );\n for (const result of results.slice(1)) {\n const batchFileIds = new Set(\n result.orphanedFiles.map((file) => file.fileId)\n );\n for (const fileId of orphanedFiles.keys()) {\n if (!batchFileIds.has(fileId)) orphanedFiles.delete(fileId);\n }\n }\n return { orphanedFiles: [...orphanedFiles.values()] };\n },\n\n async processFileMoves(\n moves: ProcessFileMovesData['body']['moves'],\n options: Pick<ProcessFileMovesData['body'], 'branchId'>\n ) {\n const result = await processBatches(moves, async (batch) => {\n const response = unwrapApiResult(\n await processFileMoves({\n body: { branchId: options.branchId, moves: batch },\n client: getClient(),\n })\n );\n return response.results;\n });\n const succeeded = result.filter(({ success }) => success).length;\n\n return {\n results: result,\n summary: {\n total: moves.length,\n succeeded,\n failed: result.length - succeeded,\n },\n };\n },\n\n async setupProject(\n files: GenerateProjectContextData['body']['files'],\n options: Omit<GenerateProjectContextData['body'], 'files'> = {}\n ) {\n return unwrapApiResult(\n await generateProjectContext({\n body: {\n files: files.map(({ branchId, fileId, versionId }) => ({\n branchId,\n fileId,\n versionId,\n })),\n locales: options.locales?.map((locale) =>\n resolveCanonicalLocale(locale, customMapping)\n ),\n force: options.force,\n },\n client: getClient(),\n })\n );\n },\n\n async awaitJobs(jobIds: readonly string[], options?: AwaitJobsOptions) {\n // Poll through unwrapApiResult so HTTP failures throw ApiError with the\n // status code instead of the decoded response body.\n return pollJobs(\n jobIds,\n async (pendingJobIds, signal) =>\n unwrapApiResult(\n await getTranslationJobInfo({\n body: { jobIds: pendingJobIds },\n client: getClient(),\n signal,\n })\n ),\n options\n );\n },\n\n async enqueueFiles(\n files: EnqueueFileTranslationsData['body']['files'],\n options: {\n sourceLocale?: string;\n targetLocales: string[];\n modelProvider?: string;\n force?: boolean;\n }\n ) {\n const targetLocales = options.targetLocales.map((locale) =>\n resolveCanonicalLocale(locale, customMapping)\n );\n const result = await processBatches(files, async (batch) => {\n const response = unwrapApiResult(\n await enqueueFileTranslations({\n body: {\n files: batch.map(\n ({ branchId, fileId, versionId, fileName, transformFormat }) => ({\n branchId,\n fileId,\n versionId,\n fileName,\n transformFormat,\n })\n ),\n targetLocales,\n sourceLocale: options.sourceLocale\n ? resolveCanonicalLocale(options.sourceLocale, customMapping)\n : undefined,\n // The CLI intentionally accepts custom model-provider strings beyond\n // the OpenAPI ANTHROPIC|OPENAI|XAI|GOOGLE enum; preserve wire behavior.\n modelProvider:\n options.modelProvider as EnqueueFileTranslationsData['body']['modelProvider'],\n force: options.force,\n },\n client: getClient(),\n })\n );\n const jobData = 'jobData' in response ? response.jobData : response.data;\n return Object.entries(jobData);\n });\n\n return {\n jobData: Object.fromEntries(result),\n locales: targetLocales,\n message: `Successfully enqueued ${result.length} file translation jobs in ${Math.ceil(files.length / DEFAULT_BATCH_SIZE)} batch(es)`,\n };\n },\n\n async uploadSourceFiles(\n files: Array<{\n source: UploadSourceFilesData['body']['data'][number]['source'];\n }>,\n options: { sourceLocale: string }\n ) {\n const sourceLocale = resolveCanonicalLocale(\n options.sourceLocale,\n customMapping\n );\n const result = await processBatches(files, async (batch) => {\n const response = unwrapApiResult(\n await uploadSourceFiles({\n body: {\n data: batch.map(({ source }) => ({\n source: {\n ...source,\n content: encodeFileContent(source.content, source.fileFormat),\n locale: resolveCanonicalLocale(source.locale, customMapping),\n },\n })),\n sourceLocale,\n },\n client: getClient(),\n })\n );\n return response.uploadedFiles;\n });\n\n return { uploadedFiles: result };\n },\n\n async uploadTranslations(\n files: UploadTranslationsData['body']['data'],\n options: { sourceLocale: string }\n ) {\n const result = await processBatches(files, async (batch) => {\n const response = unwrapApiResult(\n await uploadTranslations({\n body: {\n data: batch.map(({ source, translations }) => ({\n source: {\n ...source,\n content: encodeFileContent(source.content, source.fileFormat),\n },\n translations: translations.map((translation) => ({\n ...translation,\n locale: resolveCanonicalLocale(\n translation.locale,\n customMapping\n ),\n content: encodeFileContent(\n translation.content,\n translation.fileFormat\n ),\n })),\n })),\n sourceLocale: resolveCanonicalLocale(\n options.sourceLocale,\n customMapping\n ),\n },\n client: getClient(),\n })\n );\n return response.uploadedFiles;\n });\n\n return { uploadedFiles: result };\n },\n};\n\nexport type ApiClient = typeof api;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"api.js","names":[],"sources":["../../src/utils/api.ts"],"sourcesContent":["import {\n resolveAliasLocale,\n resolveCanonicalLocale,\n} from '@generaltranslation/format';\nimport type { CustomMapping } from '@generaltranslation/format/types';\nimport {\n createApiClient,\n createBranch,\n createProject,\n createTag,\n decodeFileContent,\n DEFAULT_BATCH_SIZE,\n downloadFiles,\n encodeFileContent,\n enqueueFileTranslations,\n generateProjectContext,\n getBranchInfo,\n getFileInfo,\n getOrphanedFiles,\n getProjectInfo,\n getTranslationJobInfo,\n pollJobs,\n processBatches,\n processFileMoves,\n publishFiles,\n submitUserEditDiffs,\n uploadSourceFiles,\n uploadTranslations,\n type ApiClientConfig,\n type AwaitJobsOptions,\n type CreateBranchData,\n type CreateProjectData,\n type CreateTagData,\n type DownloadFilesData,\n type EnqueueFileTranslationsData,\n type GenerateProjectContextData,\n type GetBranchInfoData,\n type GetFileInfoData,\n type ProcessFileMovesData,\n type PublishFilesData,\n type SubmitUserEditDiffsData,\n type UploadSourceFilesData,\n type UploadTranslationsData,\n} from 'generaltranslation/api';\nimport { unwrapApiResult } from 'generaltranslation/internal';\n\nlet client: ReturnType<typeof createApiClient> | undefined;\nlet configuredClientConfig: ApiClientConfig | undefined;\nlet customMapping: CustomMapping | undefined;\n\nfunction getConfiguredClient(): {\n client: ReturnType<typeof createApiClient>;\n config: ApiClientConfig;\n} {\n if (!client || !configuredClientConfig) {\n throw new Error(\n 'API client not configured — call configureApiClient first'\n );\n }\n return { client, config: configuredClientConfig };\n}\n\nfunction getClient(): ReturnType<typeof createApiClient> {\n return getConfiguredClient().client;\n}\n\nfunction getClientConfig(): ApiClientConfig {\n return getConfiguredClient().config;\n}\n\nexport function configureApiClient(\n config: ApiClientConfig & { customMapping?: CustomMapping }\n): void {\n const { customMapping: mapping, ...clientConfig } = config;\n client = createApiClient(clientConfig);\n // Retain the resolved config for the one project-info call that deliberately\n // uses a shorter timeout than normal translation requests.\n configuredClientConfig = clientConfig;\n customMapping = mapping;\n}\n\nexport const api = {\n async queryBranchData(body: GetBranchInfoData['body']) {\n return unwrapApiResult(await getBranchInfo({ body, client: getClient() }));\n },\n\n async createBranch(body: CreateBranchData['body']) {\n return unwrapApiResult(await createBranch({ body, client: getClient() }));\n },\n\n async queryFileData(body: GetFileInfoData['body']) {\n const result = unwrapApiResult(\n await getFileInfo({\n body: {\n ...body,\n translatedFiles: body.translatedFiles?.map((file) => ({\n ...file,\n locale: resolveCanonicalLocale(file.locale, customMapping),\n })),\n },\n client: getClient(),\n })\n );\n return {\n ...result,\n translatedFiles: result.translatedFiles.map((file) => ({\n ...file,\n locale: resolveAliasLocale(file.locale, customMapping),\n })),\n sourceFiles: result.sourceFiles.map((file) => ({\n ...file,\n sourceLocale: resolveAliasLocale(file.sourceLocale, customMapping),\n locales: file.locales.map((locale) =>\n resolveAliasLocale(locale, customMapping)\n ),\n })),\n };\n },\n\n async checkJobStatus(jobIds: string[]) {\n return unwrapApiResult(\n await getTranslationJobInfo({\n body: { jobIds },\n client: getClient(),\n })\n );\n },\n\n async getProjectInfo(timeoutMs: number) {\n const config = getClientConfig();\n if (!config.projectId) {\n throw new Error('Project ID is required to fetch project information');\n }\n const projectInfoClient = createApiClient({ ...config, timeoutMs });\n return unwrapApiResult(\n await getProjectInfo({\n client: projectInfoClient,\n path: { projectId: config.projectId },\n })\n );\n },\n\n resolveAliasLocale(locale: string) {\n return resolveAliasLocale(locale, customMapping);\n },\n\n async downloadFileBatch(files: DownloadFilesData['body']) {\n if (files.length === 0) return { files: [], count: 0, pending: [] };\n\n const request = async (batch: DownloadFilesData['body']) =>\n unwrapApiResult(\n await downloadFiles({\n body: batch.map((file) => ({\n ...file,\n locale: file.locale\n ? resolveCanonicalLocale(file.locale, customMapping)\n : undefined,\n })),\n client: getClient(),\n })\n );\n const responses = await processBatches(files, async (batch) => [\n await request(batch),\n ]);\n return {\n files: responses.flatMap((response) =>\n response.files.map((file) => ({\n ...file,\n ...(file.locale && {\n locale: resolveAliasLocale(file.locale, customMapping),\n }),\n data: decodeFileContent(file.data, file.fileFormat),\n }))\n ),\n count: responses.reduce((count, response) => count + response.count, 0),\n pending: responses.flatMap((response) => response.pending ?? []),\n };\n },\n\n async publishFiles(files: PublishFilesData['body']['files']) {\n return unwrapApiResult(\n await publishFiles({ body: { files }, client: getClient() })\n );\n },\n\n async submitUserEditDiffs(body: SubmitUserEditDiffsData['body']) {\n return processBatches(body.diffs, async (diffs) => [\n unwrapApiResult(\n await submitUserEditDiffs({\n body: {\n projectId: body.projectId,\n diffs: diffs.map((diff) => ({\n ...diff,\n locale: resolveCanonicalLocale(diff.locale, customMapping),\n })),\n },\n client: getClient(),\n })\n ),\n ]);\n },\n\n async createTag(body: CreateTagData['body']) {\n return unwrapApiResult(await createTag({ body, client: getClient() }));\n },\n\n async createProject(\n orgId: CreateProjectData['path']['orgId'],\n body: CreateProjectData['body']\n ) {\n return unwrapApiResult(\n await createProject({\n path: { orgId },\n body: {\n ...body,\n defaultLocale: resolveCanonicalLocale(\n body.defaultLocale,\n customMapping\n ),\n },\n client: getClient(),\n })\n );\n },\n\n // ponytail: duplicates core/src/translate/getOrphanedFiles.ts batching +\n // intersection; delete one copy when utils/gt.ts is removed.\n async getOrphanedFiles(branchId: string, fileIds: string[]) {\n const request = async (batch: string[]) =>\n unwrapApiResult(\n await getOrphanedFiles({\n body: { branchId, fileIds: batch },\n client: getClient(),\n })\n );\n\n if (fileIds.length === 0) return request([]);\n\n const results = await processBatches(fileIds, async (batch) => [\n await request(batch),\n ]);\n const orphanedFiles = new Map(\n results[0].orphanedFiles.map((file) => [file.fileId, file])\n );\n for (const result of results.slice(1)) {\n const batchFileIds = new Set(\n result.orphanedFiles.map((file) => file.fileId)\n );\n for (const fileId of orphanedFiles.keys()) {\n if (!batchFileIds.has(fileId)) orphanedFiles.delete(fileId);\n }\n }\n return { orphanedFiles: [...orphanedFiles.values()] };\n },\n\n async processFileMoves(\n moves: ProcessFileMovesData['body']['moves'],\n options: Pick<ProcessFileMovesData['body'], 'branchId'>\n ) {\n const result = await processBatches(moves, async (batch) => {\n const response = unwrapApiResult(\n await processFileMoves({\n body: { branchId: options.branchId, moves: batch },\n client: getClient(),\n })\n );\n return response.results;\n });\n const succeeded = result.filter(({ success }) => success).length;\n\n return {\n results: result,\n summary: {\n total: moves.length,\n succeeded,\n failed: result.length - succeeded,\n },\n };\n },\n\n async setupProject(\n files: GenerateProjectContextData['body']['files'],\n options: Omit<GenerateProjectContextData['body'], 'files'> = {}\n ) {\n return unwrapApiResult(\n await generateProjectContext({\n body: {\n files: files.map(({ branchId, fileId, versionId }) => ({\n branchId,\n fileId,\n versionId,\n })),\n locales: options.locales?.map((locale) =>\n resolveCanonicalLocale(locale, customMapping)\n ),\n force: options.force,\n },\n client: getClient(),\n })\n );\n },\n\n async awaitJobs(jobIds: readonly string[], options?: AwaitJobsOptions) {\n // Poll through unwrapApiResult so HTTP failures throw ApiError with the\n // status code instead of the decoded response body.\n return pollJobs(\n jobIds,\n async (pendingJobIds, signal) =>\n unwrapApiResult(\n await getTranslationJobInfo({\n body: { jobIds: pendingJobIds },\n client: getClient(),\n signal,\n })\n ),\n options\n );\n },\n\n async enqueueFiles(\n files: EnqueueFileTranslationsData['body']['files'],\n options: {\n sourceLocale?: string;\n targetLocales: string[];\n modelProvider?: string;\n force?: boolean;\n }\n ) {\n const targetLocales = options.targetLocales.map((locale) =>\n resolveCanonicalLocale(locale, customMapping)\n );\n const result = await processBatches(files, async (batch) => {\n const response = unwrapApiResult(\n await enqueueFileTranslations({\n body: {\n files: batch.map(\n ({ branchId, fileId, versionId, fileName, transformFormat }) => ({\n branchId,\n fileId,\n versionId,\n fileName,\n transformFormat,\n })\n ),\n targetLocales,\n sourceLocale: options.sourceLocale\n ? resolveCanonicalLocale(options.sourceLocale, customMapping)\n : undefined,\n // The CLI intentionally accepts custom model-provider strings beyond\n // the OpenAPI ANTHROPIC|OPENAI|XAI|GOOGLE enum; preserve wire behavior.\n modelProvider:\n options.modelProvider as EnqueueFileTranslationsData['body']['modelProvider'],\n force: options.force,\n },\n client: getClient(),\n })\n );\n const jobData = 'jobData' in response ? response.jobData : response.data;\n return Object.entries(jobData);\n });\n\n return {\n jobData: Object.fromEntries(result),\n locales: targetLocales,\n message: `Successfully enqueued ${result.length} file translation jobs in ${Math.ceil(files.length / DEFAULT_BATCH_SIZE)} batch(es)`,\n };\n },\n\n async uploadSourceFiles(\n files: Array<{\n source: UploadSourceFilesData['body']['data'][number]['source'];\n }>,\n options: { sourceLocale: string }\n ) {\n const sourceLocale = resolveCanonicalLocale(\n options.sourceLocale,\n customMapping\n );\n const result = await processBatches(files, async (batch) => {\n const response = unwrapApiResult(\n await uploadSourceFiles({\n body: {\n data: batch.map(({ source }) => ({\n source: {\n ...source,\n content: encodeFileContent(source.content, source.fileFormat),\n locale: resolveCanonicalLocale(source.locale, customMapping),\n },\n })),\n sourceLocale,\n },\n client: getClient(),\n })\n );\n return response.uploadedFiles;\n });\n\n return { uploadedFiles: result };\n },\n\n async uploadTranslations(\n files: UploadTranslationsData['body']['data'],\n options: { sourceLocale: string }\n ) {\n const result = await processBatches(files, async (batch) => {\n const response = unwrapApiResult(\n await uploadTranslations({\n body: {\n data: batch.map(({ source, translations }) => ({\n source: {\n ...source,\n content: encodeFileContent(source.content, source.fileFormat),\n },\n translations: translations.map((translation) => ({\n ...translation,\n locale: resolveCanonicalLocale(\n translation.locale,\n customMapping\n ),\n content: encodeFileContent(\n translation.content,\n translation.fileFormat\n ),\n })),\n })),\n sourceLocale: resolveCanonicalLocale(\n options.sourceLocale,\n customMapping\n ),\n },\n client: getClient(),\n })\n );\n return response.uploadedFiles;\n });\n\n return { uploadedFiles: result };\n },\n};\n\nexport type ApiClient = typeof api;\n"],"mappings":"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"}
|
|
@@ -3,4 +3,4 @@ import type { Settings } from '../types/index.js';
|
|
|
3
3
|
/**
|
|
4
4
|
* Persist postprocessed content hashes for recently downloaded files into gt-lock.json.
|
|
5
5
|
*/
|
|
6
|
-
export declare function persistPostProcessHashes(settings: Settings, includeFiles: Set<string> | undefined, downloadedMeta: Map<string, DownloadMeta>): void;
|
|
6
|
+
export declare function persistPostProcessHashes(settings: Settings, includeFiles: Set<string> | undefined, downloadedMeta: Map<string, DownloadMeta[]>): void;
|
|
@@ -5,6 +5,7 @@ import { fileEncodingSkipReason } from "../console/index.js";
|
|
|
5
5
|
import { readFileContent } from "../fs/fileContent.js";
|
|
6
6
|
import { recordWarning } from "../state/translateWarnings.js";
|
|
7
7
|
import { findOrCreateEntry, readLockfile, writeLockfile } from "../fs/config/downloadedVersions.js";
|
|
8
|
+
import { emptyLocaleContent, localeContent } from "../formats/files/localeContent.js";
|
|
8
9
|
import * as fs$1 from "node:fs";
|
|
9
10
|
//#region src/utils/persistPostprocessHashes.ts
|
|
10
11
|
/**
|
|
@@ -20,12 +21,13 @@ function persistPostProcessHashes(settings, includeFiles, downloadedMeta) {
|
|
|
20
21
|
});
|
|
21
22
|
let lockUpdated = false;
|
|
22
23
|
for (const filePath of includeFiles) {
|
|
23
|
-
const
|
|
24
|
-
if (!
|
|
24
|
+
const metas = downloadedMeta.get(filePath);
|
|
25
|
+
if (!metas) continue;
|
|
25
26
|
if (!fs$1.existsSync(filePath)) continue;
|
|
26
|
-
|
|
27
|
+
const hashes = [];
|
|
27
28
|
try {
|
|
28
|
-
|
|
29
|
+
const content = readFileContent(filePath, metas[0].fileFormat);
|
|
30
|
+
for (const meta of metas) hashes.push([meta, hashStringSync(localeContent(content, meta.fileFormat, meta.locale) ?? emptyLocaleContent(content, meta.fileFormat))]);
|
|
29
31
|
} catch (error) {
|
|
30
32
|
const relativePath = getRelative(filePath);
|
|
31
33
|
const reason = fileEncodingSkipReason(error);
|
|
@@ -33,22 +35,24 @@ function persistPostProcessHashes(settings, includeFiles, downloadedMeta) {
|
|
|
33
35
|
recordWarning("skipped_file", relativePath, reason);
|
|
34
36
|
continue;
|
|
35
37
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
38
|
+
for (const [meta, hash] of hashes) {
|
|
39
|
+
const entry = findOrCreateEntry(entryMap, data.entries, meta.fileId, meta.versionId);
|
|
40
|
+
const existing = entry.translations[meta.locale] || {};
|
|
41
|
+
if (existing.postProcessHash !== hash) {
|
|
42
|
+
entry.translations[meta.locale] = {
|
|
43
|
+
...existing,
|
|
44
|
+
postProcessHash: hash
|
|
45
|
+
};
|
|
46
|
+
lockUpdated = true;
|
|
47
|
+
}
|
|
44
48
|
}
|
|
45
49
|
}
|
|
46
50
|
if (lockUpdated) writeLockfile(data, originalV1);
|
|
47
51
|
}
|
|
48
52
|
function findDownloadedBranchId(includeFiles, downloadedMeta) {
|
|
49
53
|
for (const filePath of includeFiles) {
|
|
50
|
-
const
|
|
51
|
-
if (
|
|
54
|
+
const branchId = downloadedMeta.get(filePath)?.[0]?.branchId;
|
|
55
|
+
if (branchId) return branchId;
|
|
52
56
|
}
|
|
53
57
|
}
|
|
54
58
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"persistPostprocessHashes.js","names":["fs"],"sources":["../../src/utils/persistPostprocessHashes.ts"],"sourcesContent":["import * as fs from 'node:fs';\nimport {\n findOrCreateEntry,\n readLockfile,\n writeLockfile,\n} from '../fs/config/downloadedVersions.js';\nimport { hashStringSync } from './hash.js';\nimport { fileEncodingSkipReason } from '../console/index.js';\nimport { logger } from '../console/logger.js';\nimport { getRelative } from '../fs/findFilepath.js';\nimport { recordWarning } from '../state/translateWarnings.js';\nimport { readFileContent } from '../fs/fileContent.js';\nimport type { DownloadMeta } from '../state/recentDownloads.js';\nimport type { Settings } from '../types/index.js';\n\n/**\n * Persist postprocessed content hashes for recently downloaded files into gt-lock.json.\n */\nexport function persistPostProcessHashes(\n settings: Settings,\n includeFiles: Set<string> | undefined,\n downloadedMeta: Map<string, DownloadMeta>\n): void {\n if (!includeFiles || includeFiles.size === 0 || downloadedMeta.size === 0) {\n return;\n }\n\n const branchId = findDownloadedBranchId(includeFiles, downloadedMeta);\n if (!branchId) return;\n\n const { data, entryMap, originalV1 } = readLockfile({\n ...settings,\n _branchId: branchId,\n });\n let lockUpdated = false;\n\n for (const filePath of includeFiles) {\n const
|
|
1
|
+
{"version":3,"file":"persistPostprocessHashes.js","names":["fs"],"sources":["../../src/utils/persistPostprocessHashes.ts"],"sourcesContent":["import * as fs from 'node:fs';\nimport {\n findOrCreateEntry,\n readLockfile,\n writeLockfile,\n} from '../fs/config/downloadedVersions.js';\nimport { hashStringSync } from './hash.js';\nimport { fileEncodingSkipReason } from '../console/index.js';\nimport { logger } from '../console/logger.js';\nimport { getRelative } from '../fs/findFilepath.js';\nimport { recordWarning } from '../state/translateWarnings.js';\nimport { readFileContent } from '../fs/fileContent.js';\nimport {\n emptyLocaleContent,\n localeContent,\n} from '../formats/files/localeContent.js';\nimport type { DownloadMeta } from '../state/recentDownloads.js';\nimport type { Settings } from '../types/index.js';\n\n/**\n * Persist postprocessed content hashes for recently downloaded files into gt-lock.json.\n */\nexport function persistPostProcessHashes(\n settings: Settings,\n includeFiles: Set<string> | undefined,\n downloadedMeta: Map<string, DownloadMeta[]>\n): void {\n if (!includeFiles || includeFiles.size === 0 || downloadedMeta.size === 0) {\n return;\n }\n\n const branchId = findDownloadedBranchId(includeFiles, downloadedMeta);\n if (!branchId) return;\n\n const { data, entryMap, originalV1 } = readLockfile({\n ...settings,\n _branchId: branchId,\n });\n let lockUpdated = false;\n\n for (const filePath of includeFiles) {\n const metas = downloadedMeta.get(filePath);\n if (!metas) continue;\n if (!fs.existsSync(filePath)) continue;\n\n // Each hash stands for the locale's share of the file's pipeline content,\n // which is what upload records and user-edit detection compares against.\n const hashes: [DownloadMeta, string][] = [];\n try {\n const content = readFileContent(filePath, metas[0].fileFormat);\n for (const meta of metas) {\n hashes.push([\n meta,\n hashStringSync(\n localeContent(content, meta.fileFormat, meta.locale) ??\n emptyLocaleContent(content, meta.fileFormat)\n ),\n ]);\n }\n } catch (error) {\n // The translation is already written; failing here would lose the whole\n // run's lockfile update over one unreadable file. Skip it and report it\n const relativePath = getRelative(filePath);\n const reason = fileEncodingSkipReason(error);\n logger.warn(`Skipping ${relativePath}: ${reason}`);\n recordWarning('skipped_file', relativePath, reason);\n continue;\n }\n\n for (const [meta, hash] of hashes) {\n const entry = findOrCreateEntry(\n entryMap,\n data.entries,\n meta.fileId,\n meta.versionId\n );\n\n const existing = entry.translations[meta.locale] || {};\n\n if (existing.postProcessHash !== hash) {\n entry.translations[meta.locale] = {\n ...existing,\n postProcessHash: hash,\n };\n lockUpdated = true;\n }\n }\n }\n\n if (lockUpdated) {\n writeLockfile(data, originalV1);\n }\n}\n\nfunction findDownloadedBranchId(\n includeFiles: Set<string>,\n downloadedMeta: Map<string, DownloadMeta[]>\n): string | undefined {\n for (const filePath of includeFiles) {\n const branchId = downloadedMeta.get(filePath)?.[0]?.branchId;\n if (branchId) return branchId;\n }\n return undefined;\n}\n"],"mappings":";;;;;;;;;;;;;AAsBA,SAAgB,yBACd,UACA,cACA,gBACM;AACN,KAAI,CAAC,gBAAgB,aAAa,SAAS,KAAK,eAAe,SAAS,EACtE;CAGF,MAAM,WAAW,uBAAuB,cAAc,eAAe;AACrE,KAAI,CAAC,SAAU;CAEf,MAAM,EAAE,MAAM,UAAU,eAAe,aAAa;EAClD,GAAG;EACH,WAAW;EACZ,CAAC;CACF,IAAI,cAAc;AAElB,MAAK,MAAM,YAAY,cAAc;EACnC,MAAM,QAAQ,eAAe,IAAI,SAAS;AAC1C,MAAI,CAAC,MAAO;AACZ,MAAI,CAACA,KAAG,WAAW,SAAS,CAAE;EAI9B,MAAM,SAAmC,EAAE;AAC3C,MAAI;GACF,MAAM,UAAU,gBAAgB,UAAU,MAAM,GAAG,WAAW;AAC9D,QAAK,MAAM,QAAQ,MACjB,QAAO,KAAK,CACV,MACA,eACE,cAAc,SAAS,KAAK,YAAY,KAAK,OAAO,IAClD,mBAAmB,SAAS,KAAK,WAAW,CAC/C,CACF,CAAC;WAEG,OAAO;GAGd,MAAM,eAAe,YAAY,SAAS;GAC1C,MAAM,SAAS,uBAAuB,MAAM;AAC5C,UAAO,KAAK,YAAY,aAAa,IAAI,SAAS;AAClD,iBAAc,gBAAgB,cAAc,OAAO;AACnD;;AAGF,OAAK,MAAM,CAAC,MAAM,SAAS,QAAQ;GACjC,MAAM,QAAQ,kBACZ,UACA,KAAK,SACL,KAAK,QACL,KAAK,UACN;GAED,MAAM,WAAW,MAAM,aAAa,KAAK,WAAW,EAAE;AAEtD,OAAI,SAAS,oBAAoB,MAAM;AACrC,UAAM,aAAa,KAAK,UAAU;KAChC,GAAG;KACH,iBAAiB;KAClB;AACD,kBAAc;;;;AAKpB,KAAI,YACF,eAAc,MAAM,WAAW;;AAInC,SAAS,uBACP,cACA,gBACoB;AACpB,MAAK,MAAM,YAAY,cAAc;EACnC,MAAM,WAAW,eAAe,IAAI,SAAS,GAAG,IAAI;AACpD,MAAI,SAAU,QAAO"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gt",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.21.1",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"bin": "bin/main.js",
|
|
6
6
|
"files": [
|
|
@@ -115,13 +115,13 @@
|
|
|
115
115
|
"unified": "^11.0.5",
|
|
116
116
|
"unist-util-visit": "^5.0.0",
|
|
117
117
|
"yaml": "^2.8.0",
|
|
118
|
+
"@generaltranslation/icu": "0.1.2",
|
|
118
119
|
"@generaltranslation/format": "0.1.8",
|
|
119
|
-
"@generaltranslation/
|
|
120
|
-
"generaltranslation": "
|
|
121
|
-
"@generaltranslation/vue-extractor": "0.1.
|
|
122
|
-
"
|
|
123
|
-
"
|
|
124
|
-
"@generaltranslation/icu": "0.1.2"
|
|
120
|
+
"@generaltranslation/python-extractor": "0.2.49",
|
|
121
|
+
"@generaltranslation/supported-locales": "2.1.29",
|
|
122
|
+
"@generaltranslation/vue-extractor": "0.1.9",
|
|
123
|
+
"generaltranslation": "9.3.1",
|
|
124
|
+
"gt-remark": "1.0.12"
|
|
125
125
|
},
|
|
126
126
|
"devDependencies": {
|
|
127
127
|
"@types/babel__generator": "^7.27.0",
|