gtx-cli 2.6.14 → 2.6.15
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 +6 -0
- package/dist/cli/base.js +3 -1
- package/dist/generated/version.d.ts +1 -1
- package/dist/generated/version.js +1 -1
- package/dist/types/index.d.ts +2 -1
- package/dist/utils/addExplicitAnchorIds.js +3 -6
- package/dist/utils/localizeStaticImports.js +1 -3
- package/dist/utils/localizeStaticUrls.js +1 -3
- package/dist/utils/sharedStaticAssets.d.ts +1 -0
- package/dist/utils/sharedStaticAssets.js +112 -9
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# gtx-cli
|
|
2
2
|
|
|
3
|
+
## 2.6.15
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#999](https://github.com/generaltranslation/gt/pull/999) [`09f3e68`](https://github.com/generaltranslation/gt/commit/09f3e6829243decffa795251d46c9e6a0d1ed878) Thanks [@fernando-aviles](https://github.com/fernando-aviles)! - Allow `sharedStaticAssets` configuration to mirror shared asset structure
|
|
8
|
+
|
|
3
9
|
## 2.6.14
|
|
4
10
|
|
|
5
11
|
### Patch Changes
|
package/dist/cli/base.js
CHANGED
|
@@ -25,7 +25,7 @@ import { displayTranslateSummary } from '../console/displayTranslateSummary.js';
|
|
|
25
25
|
import updateConfig from '../fs/config/updateConfig.js';
|
|
26
26
|
import { createLoadTranslationsFile } from '../fs/createLoadTranslationsFile.js';
|
|
27
27
|
import { saveLocalEdits } from '../api/saveLocalEdits.js';
|
|
28
|
-
import processSharedStaticAssets from '../utils/sharedStaticAssets.js';
|
|
28
|
+
import processSharedStaticAssets, { mirrorAssetsToLocales, } from '../utils/sharedStaticAssets.js';
|
|
29
29
|
import { setupLocadex } from '../locadex/setupFlow.js';
|
|
30
30
|
import { detectFramework } from '../setup/detectFramework.js';
|
|
31
31
|
import { getFrameworkDisplayName, getReactFrameworkLibrary, } from '../setup/frameworkUtils.js';
|
|
@@ -131,6 +131,8 @@ export class BaseCLI {
|
|
|
131
131
|
if (include.size > 0) {
|
|
132
132
|
await postProcessTranslations(settings, include);
|
|
133
133
|
}
|
|
134
|
+
// Mirror assets after translations are downloaded and locale dirs are populated
|
|
135
|
+
await mirrorAssetsToLocales(settings);
|
|
134
136
|
clearDownloaded();
|
|
135
137
|
displayTranslateSummary();
|
|
136
138
|
clearWarnings();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const PACKAGE_VERSION = "2.6.
|
|
1
|
+
export declare const PACKAGE_VERSION = "2.6.15";
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// This file is auto-generated. Do not edit manually.
|
|
2
|
-
export const PACKAGE_VERSION = '2.6.
|
|
2
|
+
export const PACKAGE_VERSION = '2.6.15';
|
package/dist/types/index.d.ts
CHANGED
|
@@ -213,8 +213,9 @@ export type AdditionalOptions = {
|
|
|
213
213
|
};
|
|
214
214
|
export type SharedStaticAssetsConfig = {
|
|
215
215
|
include: string | string[];
|
|
216
|
-
outDir
|
|
216
|
+
outDir?: string;
|
|
217
217
|
publicPath?: string;
|
|
218
|
+
mirrorToLocales?: boolean;
|
|
218
219
|
};
|
|
219
220
|
export type JsonSchema = {
|
|
220
221
|
preset?: 'mintlify' | 'openapi';
|
|
@@ -113,8 +113,7 @@ export function extractHeadingInfo(mdxContent) {
|
|
|
113
113
|
const ast = parseProcessor.parse(mdxContent);
|
|
114
114
|
processedAst = parseProcessor.runSync(ast);
|
|
115
115
|
}
|
|
116
|
-
catch
|
|
117
|
-
console.warn(`Failed to parse MDX content: ${error instanceof Error ? error.message : String(error)}`);
|
|
116
|
+
catch {
|
|
118
117
|
// Fallback: line-by-line extraction skipping fenced code blocks
|
|
119
118
|
return extractHeadingsWithFallback(mdxContent);
|
|
120
119
|
}
|
|
@@ -220,8 +219,7 @@ function applyInlineIds(translatedContent, idMappings, escapeAnchors) {
|
|
|
220
219
|
const ast = parseProcessor.parse(translatedContent);
|
|
221
220
|
processedAst = parseProcessor.runSync(ast);
|
|
222
221
|
}
|
|
223
|
-
catch
|
|
224
|
-
console.warn(`Failed to parse translated MDX content: ${error instanceof Error ? error.message : String(error)}`);
|
|
222
|
+
catch {
|
|
225
223
|
return applyInlineIdsStringFallback(translatedContent, idMappings, escapeAnchors);
|
|
226
224
|
}
|
|
227
225
|
// Apply IDs to headings based on position
|
|
@@ -296,8 +294,7 @@ function applyInlineIds(translatedContent, idMappings, escapeAnchors) {
|
|
|
296
294
|
}
|
|
297
295
|
return content;
|
|
298
296
|
}
|
|
299
|
-
catch
|
|
300
|
-
console.warn(`Failed to stringify translated MDX content: ${error instanceof Error ? error.message : String(error)}`);
|
|
297
|
+
catch {
|
|
301
298
|
return translatedContent;
|
|
302
299
|
}
|
|
303
300
|
}
|
|
@@ -291,9 +291,7 @@ function transformMdxImports(mdxContent, defaultLocale, targetLocale, hideDefaul
|
|
|
291
291
|
const ast = parseProcessor.parse(mdxContent);
|
|
292
292
|
processedAst = parseProcessor.runSync(ast);
|
|
293
293
|
}
|
|
294
|
-
catch
|
|
295
|
-
console.warn(`Failed to parse MDX content: ${error instanceof Error ? error.message : String(error)}`);
|
|
296
|
-
console.warn('Falling back to string-based import localization.');
|
|
294
|
+
catch {
|
|
297
295
|
return transformImportsStringFallback(mdxContent, defaultLocale, targetLocale, hideDefaultLocale, pattern, exclude, currentFilePath, options);
|
|
298
296
|
}
|
|
299
297
|
let content = mdxContent;
|
|
@@ -249,9 +249,7 @@ function transformMdxUrls(mdxContent, defaultLocale, targetLocale, hideDefaultLo
|
|
|
249
249
|
const ast = parseProcessor.parse(mdxContent);
|
|
250
250
|
processedAst = parseProcessor.runSync(ast);
|
|
251
251
|
}
|
|
252
|
-
catch
|
|
253
|
-
console.warn(`Failed to parse MDX content: ${error instanceof Error ? error.message : String(error)}`);
|
|
254
|
-
console.warn('Returning original content unchanged due to parsing error.');
|
|
252
|
+
catch {
|
|
255
253
|
return {
|
|
256
254
|
content: mdxContent,
|
|
257
255
|
hasChanges: false,
|
|
@@ -8,6 +8,8 @@ import remarkFrontmatter from 'remark-frontmatter';
|
|
|
8
8
|
import remarkStringify from 'remark-stringify';
|
|
9
9
|
import { visit } from 'unist-util-visit';
|
|
10
10
|
import escapeHtmlInTextNodes from 'gt-remark';
|
|
11
|
+
import { createFileMapping } from '../formats/files/fileMapping.js';
|
|
12
|
+
import { TEMPLATE_FILE_NAME } from './constants.js';
|
|
11
13
|
function derivePublicPath(outDir, provided) {
|
|
12
14
|
if (provided)
|
|
13
15
|
return provided;
|
|
@@ -199,26 +201,127 @@ function rewriteMdxContent(content, filePath, pathMap) {
|
|
|
199
201
|
return { content, changed: false };
|
|
200
202
|
}
|
|
201
203
|
}
|
|
204
|
+
function resolveAssetPaths(include, cwd) {
|
|
205
|
+
const assetPaths = new Set();
|
|
206
|
+
for (let pattern of include) {
|
|
207
|
+
if (pattern.startsWith('/'))
|
|
208
|
+
pattern = pattern.slice(1);
|
|
209
|
+
const matches = fg.sync(path.resolve(cwd, pattern), { absolute: true });
|
|
210
|
+
for (const m of matches)
|
|
211
|
+
assetPaths.add(path.normalize(m));
|
|
212
|
+
}
|
|
213
|
+
return assetPaths;
|
|
214
|
+
}
|
|
215
|
+
export async function mirrorAssetsToLocales(settings) {
|
|
216
|
+
const cfg = settings.sharedStaticAssets;
|
|
217
|
+
if (!cfg?.mirrorToLocales)
|
|
218
|
+
return;
|
|
219
|
+
if (!settings.files)
|
|
220
|
+
return;
|
|
221
|
+
const cwd = process.cwd();
|
|
222
|
+
const include = toArray(cfg.include);
|
|
223
|
+
if (include.length === 0)
|
|
224
|
+
return;
|
|
225
|
+
const assetPaths = resolveAssetPaths(include, cwd);
|
|
226
|
+
if (assetPaths.size === 0)
|
|
227
|
+
return;
|
|
228
|
+
const { resolvedPaths, placeholderPaths, transformPaths } = settings.files;
|
|
229
|
+
const targetLocales = settings.locales.filter((l) => l !== settings.defaultLocale);
|
|
230
|
+
if (targetLocales.length === 0)
|
|
231
|
+
return;
|
|
232
|
+
const fileMapping = createFileMapping(resolvedPaths, placeholderPaths, transformPaths, targetLocales, settings.defaultLocale);
|
|
233
|
+
for (const locale of targetLocales) {
|
|
234
|
+
const filesMap = fileMapping[locale];
|
|
235
|
+
if (!filesMap)
|
|
236
|
+
continue;
|
|
237
|
+
// Extract unique (sourceDir, targetDir) pairs from the file mapping
|
|
238
|
+
const dirPairs = new Map();
|
|
239
|
+
for (const [sourcePath, targetPath] of Object.entries(filesMap)) {
|
|
240
|
+
if (sourcePath === TEMPLATE_FILE_NAME)
|
|
241
|
+
continue;
|
|
242
|
+
const sourceDir = path.dirname(path.resolve(cwd, sourcePath));
|
|
243
|
+
const targetDir = path.dirname(path.resolve(cwd, targetPath));
|
|
244
|
+
if (sourceDir !== targetDir) {
|
|
245
|
+
dirPairs.set(sourceDir, targetDir);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
if (dirPairs.size === 0)
|
|
249
|
+
continue;
|
|
250
|
+
// Derive ancestor directory pairs by walking up from each known pair.
|
|
251
|
+
// e.g. if docs/guide → ja/docs/guide, infer docs → ja/docs.
|
|
252
|
+
// Stop at cwd or when an existing pair conflicts.
|
|
253
|
+
const ancestorPairs = new Map();
|
|
254
|
+
for (const [sourceDir, targetDir] of dirPairs) {
|
|
255
|
+
let s = path.dirname(sourceDir);
|
|
256
|
+
let t = path.dirname(targetDir);
|
|
257
|
+
while (s.startsWith(cwd) && s !== cwd) {
|
|
258
|
+
const existing = dirPairs.get(s) ?? ancestorPairs.get(s);
|
|
259
|
+
if (existing !== undefined) {
|
|
260
|
+
if (existing !== t)
|
|
261
|
+
break; // conflict — different transforms
|
|
262
|
+
}
|
|
263
|
+
else {
|
|
264
|
+
ancestorPairs.set(s, t);
|
|
265
|
+
}
|
|
266
|
+
s = path.dirname(s);
|
|
267
|
+
t = path.dirname(t);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
for (const [s, t] of ancestorPairs) {
|
|
271
|
+
dirPairs.set(s, t);
|
|
272
|
+
}
|
|
273
|
+
// Sort source dirs by length descending so longest prefix matches first
|
|
274
|
+
const sortedPairs = [...dirPairs.entries()].sort((a, b) => b[0].length - a[0].length);
|
|
275
|
+
for (const assetAbs of assetPaths) {
|
|
276
|
+
// Find the directory pair whose sourceDir is the longest prefix of the asset
|
|
277
|
+
let bestSource;
|
|
278
|
+
let bestTarget;
|
|
279
|
+
for (const [sourceDir, targetDir] of sortedPairs) {
|
|
280
|
+
if (assetAbs.startsWith(sourceDir + path.sep) ||
|
|
281
|
+
assetAbs.startsWith(sourceDir + '/')) {
|
|
282
|
+
bestSource = sourceDir;
|
|
283
|
+
bestTarget = targetDir;
|
|
284
|
+
break;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
if (!bestSource || !bestTarget)
|
|
288
|
+
continue;
|
|
289
|
+
const relFromSource = path.relative(bestSource, assetAbs);
|
|
290
|
+
const targetAsset = path.resolve(bestTarget, relFromSource);
|
|
291
|
+
// Skip if target already exists with same size
|
|
292
|
+
try {
|
|
293
|
+
const [srcStat, dstStat] = await Promise.all([
|
|
294
|
+
fs.promises.stat(assetAbs),
|
|
295
|
+
fs.promises.stat(targetAsset),
|
|
296
|
+
]);
|
|
297
|
+
if (dstStat.isFile() && srcStat.size === dstStat.size)
|
|
298
|
+
continue;
|
|
299
|
+
}
|
|
300
|
+
catch {
|
|
301
|
+
// target doesn't exist, proceed with copy
|
|
302
|
+
}
|
|
303
|
+
await ensureDir(path.dirname(targetAsset));
|
|
304
|
+
await fs.promises.copyFile(assetAbs, targetAsset);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
}
|
|
202
308
|
export default async function processSharedStaticAssets(settings) {
|
|
203
309
|
const cfg = settings.sharedStaticAssets;
|
|
204
310
|
if (!cfg)
|
|
205
311
|
return;
|
|
312
|
+
// mirrorToLocales is handled separately after translations are downloaded
|
|
313
|
+
if (cfg.mirrorToLocales)
|
|
314
|
+
return;
|
|
206
315
|
const cwd = process.cwd();
|
|
207
316
|
const include = toArray(cfg.include);
|
|
208
317
|
if (include.length === 0)
|
|
209
318
|
return;
|
|
210
319
|
// Resolve assets
|
|
211
|
-
const assetPaths =
|
|
212
|
-
for (let pattern of include) {
|
|
213
|
-
// Treat leading '/' as repo-relative, not filesystem root
|
|
214
|
-
if (pattern.startsWith('/'))
|
|
215
|
-
pattern = pattern.slice(1);
|
|
216
|
-
const matches = fg.sync(path.resolve(cwd, pattern), { absolute: true });
|
|
217
|
-
for (const m of matches)
|
|
218
|
-
assetPaths.add(path.normalize(m));
|
|
219
|
-
}
|
|
320
|
+
const assetPaths = resolveAssetPaths(include, cwd);
|
|
220
321
|
if (assetPaths.size === 0)
|
|
221
322
|
return;
|
|
323
|
+
if (!cfg.outDir)
|
|
324
|
+
return;
|
|
222
325
|
const outDirInput = cfg.outDir.startsWith('/')
|
|
223
326
|
? cfg.outDir.slice(1)
|
|
224
327
|
: cfg.outDir;
|