gt 2.10.8 → 2.11.0

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,17 @@
1
1
  # gtx-cli
2
2
 
3
+ ## 2.11.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#1122](https://github.com/generaltranslation/gt/pull/1122) [`6d516a7`](https://github.com/generaltranslation/gt/commit/6d516a784f1192f7758689fcf4557e8a19de740a) Thanks [@fernando-aviles](https://github.com/fernando-aviles)! - Adding CDN publishing for all file types
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies [[`6d516a7`](https://github.com/generaltranslation/gt/commit/6d516a784f1192f7758689fcf4557e8a19de740a)]:
12
+ - generaltranslation@8.1.18
13
+ - @generaltranslation/python-extractor@0.1.4
14
+
3
15
  ## 2.10.8
4
16
 
5
17
  ### Patch Changes
@@ -13,7 +13,7 @@ export async function saveLocalEdits(settings) {
13
13
  if (!settings.files)
14
14
  return;
15
15
  // Collect current files from config
16
- const files = await aggregateFiles(settings);
16
+ const { files } = await aggregateFiles(settings);
17
17
  if (!files.length)
18
18
  return;
19
19
  // run branch query to get branch id
package/dist/cli/base.js CHANGED
@@ -172,7 +172,7 @@ export class BaseCLI {
172
172
  if (!settings.stageTranslations) {
173
173
  const results = await handleStage(initOptions, settings, this.library, false);
174
174
  if (results) {
175
- await handleTranslate(initOptions, settings, results.fileVersionData, results.jobData, results.branchData);
175
+ await handleTranslate(initOptions, settings, results.fileVersionData, results.jobData, results.branchData, results.publishMap);
176
176
  }
177
177
  }
178
178
  else {
@@ -6,4 +6,5 @@ export declare function handleStage(options: TranslateFlags, settings: Settings,
6
6
  fileVersionData: FileTranslationData | undefined;
7
7
  jobData: EnqueueFilesResult | undefined;
8
8
  branchData: BranchData | undefined;
9
+ publishMap: Map<string, boolean>;
9
10
  } | null>;
@@ -13,7 +13,7 @@ export async function handleStage(options, settings, library, stage) {
13
13
  // Validate credentials if not in dry run
14
14
  if (!options.dryRun && !hasValidCredentials(settings))
15
15
  return exitSync(1);
16
- const { files: allFiles, reactComponents } = await collectFiles(options, settings, library);
16
+ const { files: allFiles, reactComponents, publishMap, } = await collectFiles(options, settings, library);
17
17
  // Dry run
18
18
  if (options.dryRun) {
19
19
  logger.success(`Dry run: No files were sent to General Translation.`);
@@ -55,5 +55,6 @@ export async function handleStage(options, settings, library, stage) {
55
55
  fileVersionData,
56
56
  jobData,
57
57
  branchData,
58
+ publishMap,
58
59
  };
59
60
  }
@@ -3,5 +3,5 @@ import { TranslateFlags } from '../../types/index.js';
3
3
  import { Settings } from '../../types/index.js';
4
4
  import { FileTranslationData } from '../../workflows/download.js';
5
5
  import { BranchData } from '../../types/branch.js';
6
- export declare function handleTranslate(options: TranslateFlags, settings: Settings, fileVersionData: FileTranslationData | undefined, jobData: EnqueueFilesResult | undefined, branchData: BranchData | undefined): Promise<void>;
6
+ export declare function handleTranslate(options: TranslateFlags, settings: Settings, fileVersionData: FileTranslationData | undefined, jobData: EnqueueFilesResult | undefined, branchData: BranchData | undefined, publishMap?: Map<string, boolean>): Promise<void>;
7
7
  export declare function postProcessTranslations(settings: Settings, includeFiles?: Set<string>): Promise<void>;
@@ -9,8 +9,11 @@ import processOpenApi from '../../utils/processOpenApi.js';
9
9
  import localizeStaticImports from '../../utils/localizeStaticImports.js';
10
10
  import { getDownloadedMeta } from '../../state/recentDownloads.js';
11
11
  import { persistPostProcessHashes } from '../../utils/persistPostprocessHashes.js';
12
+ import { PublishStep } from '../../workflows/steps/PublishStep.js';
13
+ import { gt } from '../../utils/gt.js';
14
+ import { hasPublishConfig } from '../../utils/resolvePublish.js';
12
15
  // Downloads translations that were completed
13
- export async function handleTranslate(options, settings, fileVersionData, jobData, branchData) {
16
+ export async function handleTranslate(options, settings, fileVersionData, jobData, branchData, publishMap) {
14
17
  if (fileVersionData) {
15
18
  const { resolvedPaths, placeholderPaths, transformPaths } = settings.files;
16
19
  const fileMapping = createFileMapping(resolvedPaths, placeholderPaths, transformPaths, settings.locales, settings.defaultLocale);
@@ -26,6 +29,21 @@ export async function handleTranslate(options, settings, fileVersionData, jobDat
26
29
  forceRetranslation: options.force,
27
30
  forceDownload: options.forceDownload || options.force, // if force is true should also force download
28
31
  });
32
+ // Publish/unpublish files after translations are downloaded
33
+ if (publishMap && hasPublishConfig(settings)) {
34
+ const allFileRefs = Object.entries(fileVersionData)
35
+ .filter(([fileId]) => publishMap.has(fileId))
36
+ .map(([fileId, data]) => ({
37
+ fileId,
38
+ versionId: data.versionId,
39
+ branchId: branchData?.currentBranch.id,
40
+ publish: publishMap.get(fileId),
41
+ fileName: data.fileName,
42
+ }));
43
+ const publishStep = new PublishStep(gt);
44
+ await publishStep.run(allFileRefs);
45
+ await publishStep.wait();
46
+ }
29
47
  }
30
48
  }
31
49
  export async function postProcessTranslations(settings, includeFiles) {
@@ -125,7 +125,14 @@ export async function generateSettings(flags, cwd = process.cwd()) {
125
125
  .map(([key]) => key);
126
126
  mergedOptions.files = mergedOptions.files
127
127
  ? resolveFiles(mergedOptions.files, mergedOptions.defaultLocale, mergedOptions.locales, cwd, compositePatterns)
128
- : { resolvedPaths: {}, placeholderPaths: {}, transformPaths: {} };
128
+ : {
129
+ resolvedPaths: {},
130
+ placeholderPaths: {},
131
+ transformPaths: {},
132
+ publishPaths: new Set(),
133
+ unpublishPaths: new Set(),
134
+ gtJson: {},
135
+ };
129
136
  mergedOptions.options = {
130
137
  ...(mergedOptions.options || {}),
131
138
  mintlify: {
@@ -1,4 +1,7 @@
1
1
  import { Settings } from '../../types/index.js';
2
2
  import type { FileToUpload } from '../../types/data.js';
3
3
  export declare const SUPPORTED_DATA_FORMATS: string[];
4
- export declare function aggregateFiles(settings: Settings): Promise<FileToUpload[]>;
4
+ export declare function aggregateFiles(settings: Settings): Promise<{
5
+ files: FileToUpload[];
6
+ publishMap: Map<string, boolean>;
7
+ }>;
@@ -11,6 +11,7 @@ import { determineLibrary } from '../../fs/determineFramework/index.js';
11
11
  import { hashStringSync } from '../../utils/hash.js';
12
12
  import { preprocessContent } from './preprocessContent.js';
13
13
  import { parseKeyedMetadata, } from '../parseKeyedMetadata.js';
14
+ import { shouldPublishFile } from '../../utils/resolvePublish.js';
14
15
  /**
15
16
  * Checks if a file path is a metadata companion file (e.g. foo.metadata.json)
16
17
  * AND its corresponding source file (e.g. foo.json) exists in the file list.
@@ -27,14 +28,25 @@ function isCompanionMetadataFile(filePath, allFilePaths) {
27
28
  export const SUPPORTED_DATA_FORMATS = ['JSX', 'ICU', 'I18NEXT'];
28
29
  export async function aggregateFiles(settings) {
29
30
  // Aggregate all files to translate
30
- const allFiles = [];
31
+ const files = [];
32
+ const publishMap = new Map();
31
33
  if (!settings.files ||
32
34
  (Object.keys(settings.files.placeholderPaths).length === 1 &&
33
35
  settings.files.placeholderPaths.gt)) {
34
- return allFiles;
36
+ return { files, publishMap };
35
37
  }
36
38
  const { resolvedPaths: filePaths } = settings.files;
37
39
  const skipValidation = settings.options?.skipFileValidation;
40
+ // Build publish map upfront from resolved paths
41
+ for (const fileType of SUPPORTED_FILE_EXTENSIONS) {
42
+ if (filePaths[fileType]) {
43
+ for (const absolutePath of filePaths[fileType]) {
44
+ const relativePath = getRelative(absolutePath);
45
+ const fileId = hashStringSync(relativePath);
46
+ publishMap.set(fileId, shouldPublishFile(absolutePath, settings));
47
+ }
48
+ }
49
+ }
38
50
  // Process JSON files
39
51
  if (filePaths.json) {
40
52
  const { library, additionalModules } = determineLibrary();
@@ -122,7 +134,7 @@ export async function aggregateFiles(settings) {
122
134
  }
123
135
  return true;
124
136
  });
125
- allFiles.push(...jsonFiles.filter((file) => file !== null));
137
+ files.push(...jsonFiles.filter((file) => file !== null));
126
138
  }
127
139
  // Process YAML files
128
140
  if (filePaths.yaml) {
@@ -191,7 +203,7 @@ export async function aggregateFiles(settings) {
191
203
  }
192
204
  return true;
193
205
  });
194
- allFiles.push(...yamlFiles.filter((file) => file !== null));
206
+ files.push(...yamlFiles.filter((file) => file !== null));
195
207
  }
196
208
  // Process Twilio Content JSON files
197
209
  if (filePaths.twilioContentJson) {
@@ -231,7 +243,7 @@ export async function aggregateFiles(settings) {
231
243
  }
232
244
  return true;
233
245
  });
234
- allFiles.push(...twilioContentJsonFiles.filter((file) => file !== null));
246
+ files.push(...twilioContentJsonFiles.filter((file) => file !== null));
235
247
  }
236
248
  for (const fileType of SUPPORTED_FILE_EXTENSIONS) {
237
249
  if (fileType === 'json' ||
@@ -239,7 +251,7 @@ export async function aggregateFiles(settings) {
239
251
  fileType === 'twilioContentJson')
240
252
  continue;
241
253
  if (filePaths[fileType]) {
242
- const files = filePaths[fileType]
254
+ const parsed = filePaths[fileType]
243
255
  .map((filePath) => {
244
256
  const content = readFile(filePath);
245
257
  const relativePath = getRelative(filePath);
@@ -268,11 +280,18 @@ export async function aggregateFiles(settings) {
268
280
  }
269
281
  return true;
270
282
  });
271
- allFiles.push(...files.filter((file) => file !== null));
283
+ files.push(...parsed.filter((file) => file !== null));
272
284
  }
273
285
  }
274
- if (allFiles.length === 0 && !settings.publish) {
286
+ if (files.length === 0 && !settings.publish) {
275
287
  logger.error('No files to translate were found. Check your configuration and try again.');
276
288
  }
277
- return allFiles;
289
+ // Remove stale entries for files that were skipped during validation
290
+ const validFileIds = new Set(files.map((f) => f.fileId));
291
+ for (const fileId of publishMap.keys()) {
292
+ if (!validFileIds.has(fileId)) {
293
+ publishMap.delete(fileId);
294
+ }
295
+ }
296
+ return { files, publishMap };
278
297
  }
@@ -3,4 +3,5 @@ import type { FileToUpload } from 'generaltranslation/types';
3
3
  export declare function collectFiles(options: TranslateFlags, settings: Settings, library: SupportedLibraries): Promise<{
4
4
  files: FileToUpload[];
5
5
  reactComponents: number;
6
+ publishMap: Map<string, boolean>;
6
7
  }>;
@@ -5,9 +5,10 @@ import { aggregateInlineTranslations } from '../../translation/stage.js';
5
5
  import { hashStringSync } from '../../utils/hash.js';
6
6
  import { TEMPLATE_FILE_NAME, TEMPLATE_FILE_ID } from '../../utils/constants.js';
7
7
  import { isInlineLibrary } from '../../types/libraries.js';
8
+ import { shouldPublishGt } from '../../utils/resolvePublish.js';
8
9
  export async function collectFiles(options, settings, library) {
9
10
  // Aggregate files
10
- const allFiles = await aggregateFiles(settings);
11
+ const { files, publishMap } = await aggregateFiles(settings);
11
12
  // Parse for React components
12
13
  let reactComponents = 0;
13
14
  if (isInlineLibrary(library)) {
@@ -34,7 +35,7 @@ export async function collectFiles(options, settings, library) {
34
35
  }
35
36
  }
36
37
  reactComponents = updates.length;
37
- allFiles.push({
38
+ files.push({
38
39
  fileName: TEMPLATE_FILE_NAME,
39
40
  content: JSON.stringify(fileData),
40
41
  fileFormat: 'GTJSON',
@@ -43,7 +44,8 @@ export async function collectFiles(options, settings, library) {
43
44
  versionId: hashStringSync(JSON.stringify(Object.keys(fileData).sort())),
44
45
  locale: settings.defaultLocale,
45
46
  });
47
+ publishMap.set(TEMPLATE_FILE_ID, shouldPublishGt(settings));
46
48
  }
47
49
  }
48
- return { files: allFiles, reactComponents };
50
+ return { files, reactComponents, publishMap };
49
51
  }
@@ -1,4 +1,4 @@
1
- import { FilesOptions, ResolvedFiles, TransformFiles, TransformOption } from '../../types/index.js';
1
+ import { FilesOptions, IncludePattern, ResolvedFiles, TransformFiles, TransformOption } from '../../types/index.js';
2
2
  /**
3
3
  * Resolves the files from the files object
4
4
  * Replaces [locale] with the actual locale in the files
@@ -9,9 +9,18 @@ import { FilesOptions, ResolvedFiles, TransformFiles, TransformOption } from '..
9
9
  */
10
10
  export declare function resolveLocaleFiles(files: ResolvedFiles, locale: string): ResolvedFiles;
11
11
  /**
12
- * Resolves the files from the files object
13
- * Performs glob pattern expansion on the files
14
- * Replaces [locale] with the actual locale in the files
12
+ * Normalizes include patterns into plain path strings and tracks which
13
+ * patterns have explicit publish flags.
14
+ */
15
+ export declare function normalizeIncludePatterns(patterns: IncludePattern[]): {
16
+ paths: string[];
17
+ publishPatterns: string[];
18
+ unpublishPatterns: string[];
19
+ };
20
+ /**
21
+ * Resolves the files from the files object.
22
+ * Performs glob pattern expansion on the files.
23
+ * Replaces [locale] with the actual locale in the files.
15
24
  *
16
25
  * @param files - The files object
17
26
  * @returns The resolved files
@@ -20,7 +29,12 @@ export declare function resolveFiles(files: FilesOptions, locale: string, locale
20
29
  resolvedPaths: ResolvedFiles;
21
30
  placeholderPaths: ResolvedFiles;
22
31
  transformPaths: TransformFiles;
23
- includeSourceCodeContext?: boolean;
32
+ publishPaths: Set<string>;
33
+ unpublishPaths: Set<string>;
34
+ gtJson: {
35
+ publish?: boolean;
36
+ includeSourceCodeContext?: boolean;
37
+ };
24
38
  };
25
39
  export declare function expandGlobPatterns(cwd: string, includePatterns: string[], excludePatterns: string[], locale: string, locales: string[], transformPatterns?: TransformOption | string | TransformOption[], compositePatterns?: string[]): {
26
40
  resolvedPaths: string[];
@@ -22,9 +22,33 @@ export function resolveLocaleFiles(files, locale) {
22
22
  return result;
23
23
  }
24
24
  /**
25
- * Resolves the files from the files object
26
- * Performs glob pattern expansion on the files
27
- * Replaces [locale] with the actual locale in the files
25
+ * Normalizes include patterns into plain path strings and tracks which
26
+ * patterns have explicit publish flags.
27
+ */
28
+ export function normalizeIncludePatterns(patterns) {
29
+ const paths = [];
30
+ const publishPatterns = [];
31
+ const unpublishPatterns = [];
32
+ for (const pattern of patterns) {
33
+ if (typeof pattern === 'string') {
34
+ paths.push(pattern);
35
+ }
36
+ else {
37
+ paths.push(pattern.pattern);
38
+ if (pattern.publish === true) {
39
+ publishPatterns.push(pattern.pattern);
40
+ }
41
+ else if (pattern.publish === false) {
42
+ unpublishPatterns.push(pattern.pattern);
43
+ }
44
+ }
45
+ }
46
+ return { paths, publishPatterns, unpublishPatterns };
47
+ }
48
+ /**
49
+ * Resolves the files from the files object.
50
+ * Performs glob pattern expansion on the files.
51
+ * Replaces [locale] with the actual locale in the files.
28
52
  *
29
53
  * @param files - The files object
30
54
  * @returns The resolved files
@@ -34,6 +58,8 @@ export function resolveFiles(files, locale, locales, cwd, compositePatterns) {
34
58
  const result = {};
35
59
  const placeholderResult = {};
36
60
  const transformPaths = {};
61
+ const publishPaths = new Set();
62
+ const unpublishPaths = new Set();
37
63
  // Process GT files
38
64
  if (files.gt?.output) {
39
65
  placeholderResult.gt = path.resolve(cwd, files.gt.output);
@@ -49,16 +75,24 @@ export function resolveFiles(files, locale, locales, cwd, compositePatterns) {
49
75
  }
50
76
  // ==== PLACEHOLDERS ==== //
51
77
  if (files[fileType]?.include) {
52
- const filePaths = expandGlobPatterns(cwd, files[fileType].include, files[fileType]?.exclude || [], locale, locales, transformPaths[fileType] || undefined, compositePatterns);
78
+ const { paths, publishPatterns, unpublishPatterns } = normalizeIncludePatterns(files[fileType].include);
79
+ const filePaths = expandGlobPatterns(cwd, paths, files[fileType]?.exclude || [], locale, locales, transformPaths[fileType] || undefined, compositePatterns);
53
80
  result[fileType] = filePaths.resolvedPaths;
54
81
  placeholderResult[fileType] = filePaths.placeholderPaths;
82
+ // Classify resolved paths into publish/unpublish sets
83
+ classifyPublishPaths(filePaths.resolvedPaths, publishPatterns, unpublishPatterns, cwd, locale, publishPaths, unpublishPaths);
55
84
  }
56
85
  }
57
86
  return {
58
87
  resolvedPaths: result,
59
88
  placeholderPaths: placeholderResult,
60
89
  transformPaths: transformPaths,
61
- includeSourceCodeContext: files.gt?.includeSourceCodeContext,
90
+ publishPaths,
91
+ unpublishPaths,
92
+ gtJson: {
93
+ publish: files.gt?.publish,
94
+ includeSourceCodeContext: files.gt?.includeSourceCodeContext,
95
+ },
62
96
  };
63
97
  }
64
98
  // Helper function to expand glob patterns
@@ -149,3 +183,30 @@ function buildPlaceholderPathFromPattern(patternPath, absolutePath, localeTag) {
149
183
  function toPosixPath(value) {
150
184
  return value.split(path.sep).join(path.posix.sep);
151
185
  }
186
+ /**
187
+ * Classifies resolved file paths into publish/unpublish sets by matching
188
+ * them against the given glob patterns. Uses POSIX paths for micromatch
189
+ * compatibility but stores platform-native paths in the output sets.
190
+ */
191
+ function classifyPublishPaths(resolvedPaths, publishPatterns, unpublishPatterns, cwd, locale, publishPaths, unpublishPaths) {
192
+ if (publishPatterns.length === 0 && unpublishPatterns.length === 0)
193
+ return;
194
+ const posixPaths = resolvedPaths.map(toPosixPath);
195
+ const toAbsoluteGlob = (p) => toPosixPath(path.resolve(cwd, p.replace(/\[locale\]/g, locale)));
196
+ for (const pattern of publishPatterns) {
197
+ const matched = new Set(micromatch(posixPaths, toAbsoluteGlob(pattern)));
198
+ for (let i = 0; i < posixPaths.length; i++) {
199
+ if (matched.has(posixPaths[i])) {
200
+ publishPaths.add(resolvedPaths[i]);
201
+ }
202
+ }
203
+ }
204
+ for (const pattern of unpublishPatterns) {
205
+ const matched = new Set(micromatch(posixPaths, toAbsoluteGlob(pattern)));
206
+ for (let i = 0; i < posixPaths.length; i++) {
207
+ if (matched.has(posixPaths[i])) {
208
+ unpublishPaths.add(resolvedPaths[i]);
209
+ }
210
+ }
211
+ }
212
+ }
@@ -1 +1 @@
1
- export declare const PACKAGE_VERSION = "2.10.8";
1
+ export declare const PACKAGE_VERSION = "2.11.0";
@@ -1,2 +1,2 @@
1
1
  // This file is auto-generated. Do not edit manually.
2
- export const PACKAGE_VERSION = '2.10.8';
2
+ export const PACKAGE_VERSION = '2.11.0';
@@ -15,7 +15,7 @@ export async function aggregateInlineTranslations(options, settings, library) {
15
15
  ]);
16
16
  }
17
17
  // ---- CREATING UPDATES ---- //
18
- const { updates, errors, warnings } = await createUpdates(options, settings.src, options.dictionary, library, false, settings.parsingOptions, settings.files?.includeSourceCodeContext ?? false);
18
+ const { updates, errors, warnings } = await createUpdates(options, settings.src, options.dictionary, library, false, settings.parsingOptions, settings.files?.gtJson.includeSourceCodeContext ?? false);
19
19
  if (warnings.length > 0) {
20
20
  logger.warn(chalk.yellow(`CLI tool encountered ${warnings.length} warnings while scanning for translatable content.\n` +
21
21
  warnings
@@ -10,7 +10,7 @@ import { Libraries } from '../types/libraries.js';
10
10
  */
11
11
  async function runValidation(settings, pkg, files) {
12
12
  if (files && files.length > 0) {
13
- return createInlineUpdates(pkg, true, files, settings.parsingOptions, settings.files?.includeSourceCodeContext ?? false);
13
+ return createInlineUpdates(pkg, true, files, settings.parsingOptions, settings.files?.gtJson.includeSourceCodeContext ?? false);
14
14
  }
15
15
  // Full project validation
16
16
  // Use local variable to avoid mutating caller's settings object
@@ -23,7 +23,7 @@ async function runValidation(settings, pkg, files) {
23
23
  './dictionary.ts',
24
24
  './src/dictionary.ts',
25
25
  ]);
26
- return createUpdates(settings, settings.src, dictionary, pkg, true, settings.parsingOptions, settings.files?.includeSourceCodeContext ?? false);
26
+ return createUpdates(settings, settings.src, dictionary, pkg, true, settings.parsingOptions, settings.files?.gtJson.includeSourceCodeContext ?? false);
27
27
  }
28
28
  /**
29
29
  * Parse file path from error/warning string in withLocation format: "filepath (line:col): message"
@@ -133,15 +133,20 @@ export type TransformOption = {
133
133
  export type TransformFiles = {
134
134
  [K in SupportedFileExtension]?: TransformOption | string | TransformOption[];
135
135
  };
136
+ export type IncludePattern = string | {
137
+ pattern: string;
138
+ publish?: boolean;
139
+ };
136
140
  export type FilesOptions = {
137
141
  [K in SupportedFileExtension]?: {
138
- include: string[];
142
+ include: IncludePattern[];
139
143
  exclude?: string[];
140
144
  transform?: string | TransformOption | TransformOption[];
141
145
  };
142
146
  } & {
143
147
  gt?: {
144
148
  output: string;
149
+ publish?: boolean;
145
150
  includeSourceCodeContext?: boolean;
146
151
  };
147
152
  };
@@ -159,7 +164,12 @@ export type Settings = {
159
164
  resolvedPaths: ResolvedFiles;
160
165
  placeholderPaths: ResolvedFiles;
161
166
  transformPaths: TransformFiles;
162
- includeSourceCodeContext?: boolean;
167
+ publishPaths: Set<string>;
168
+ unpublishPaths: Set<string>;
169
+ gtJson: {
170
+ publish?: boolean;
171
+ includeSourceCodeContext?: boolean;
172
+ };
163
173
  };
164
174
  stageTranslations: boolean;
165
175
  publish: boolean;
@@ -0,0 +1,18 @@
1
+ import { Settings } from '../types/index.js';
2
+ /**
3
+ * Determines whether a file should be published based on the publish resolution logic:
4
+ * - If the file is explicitly opted OUT (unpublishPaths), never publish
5
+ * - If the file is explicitly opted IN (publishPaths), always publish
6
+ * - Otherwise, fall back to the global publish setting
7
+ */
8
+ export declare function shouldPublishFile(resolvedPath: string, settings: Settings): boolean;
9
+ /**
10
+ * Returns true if the user has any explicit publish configuration —
11
+ * global flag, gt-specific flag, or per-file publish/unpublish patterns.
12
+ */
13
+ export declare function hasPublishConfig(settings: Settings): boolean;
14
+ /**
15
+ * Determines whether gtjson content should be published.
16
+ * Uses the gt-specific publish flag if set, otherwise falls back to global.
17
+ */
18
+ export declare function shouldPublishGt(settings: Settings): boolean;
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Determines whether a file should be published based on the publish resolution logic:
3
+ * - If the file is explicitly opted OUT (unpublishPaths), never publish
4
+ * - If the file is explicitly opted IN (publishPaths), always publish
5
+ * - Otherwise, fall back to the global publish setting
6
+ */
7
+ export function shouldPublishFile(resolvedPath, settings) {
8
+ if (settings.files.unpublishPaths?.has(resolvedPath))
9
+ return false;
10
+ if (settings.files.publishPaths?.has(resolvedPath))
11
+ return true;
12
+ return settings.publish ?? false;
13
+ }
14
+ /**
15
+ * Returns true if the user has any explicit publish configuration —
16
+ * global flag, gt-specific flag, or per-file publish/unpublish patterns.
17
+ */
18
+ export function hasPublishConfig(settings) {
19
+ return (settings.publish ||
20
+ settings.files.gtJson.publish !== undefined ||
21
+ (settings.files.publishPaths?.size ?? 0) > 0 ||
22
+ (settings.files.unpublishPaths?.size ?? 0) > 0);
23
+ }
24
+ /**
25
+ * Determines whether gtjson content should be published.
26
+ * Uses the gt-specific publish flag if set, otherwise falls back to global.
27
+ */
28
+ export function shouldPublishGt(settings) {
29
+ if (settings.files.gtJson.publish === false)
30
+ return false;
31
+ if (settings.files.gtJson.publish === true)
32
+ return true;
33
+ return settings.publish;
34
+ }
@@ -18,7 +18,6 @@ export class EnqueueStep extends WorkflowStep {
18
18
  this.result = await this.gt.enqueueFiles(files, {
19
19
  sourceLocale: this.settings.defaultLocale,
20
20
  targetLocales: this.settings.locales,
21
- publish: this.settings.publish,
22
21
  requireApproval: this.settings.stageTranslations,
23
22
  modelProvider: this.settings.modelProvider,
24
23
  force: this.force,
@@ -0,0 +1,10 @@
1
+ import { WorkflowStep } from './WorkflowStep.js';
2
+ import { GT } from 'generaltranslation';
3
+ import type { PublishFileEntry } from 'generaltranslation/types';
4
+ export declare class PublishStep extends WorkflowStep<PublishFileEntry[], void> {
5
+ private gt;
6
+ private spinner;
7
+ constructor(gt: GT);
8
+ run(files: PublishFileEntry[]): Promise<void>;
9
+ wait(): Promise<void>;
10
+ }
@@ -0,0 +1,38 @@
1
+ import { WorkflowStep } from './WorkflowStep.js';
2
+ import { logger } from '../../console/logger.js';
3
+ import chalk from 'chalk';
4
+ export class PublishStep extends WorkflowStep {
5
+ gt;
6
+ spinner = logger.createSpinner('dots');
7
+ constructor(gt) {
8
+ super();
9
+ this.gt = gt;
10
+ }
11
+ async run(files) {
12
+ if (files.length === 0)
13
+ return;
14
+ this.spinner.start('Updating CDN...');
15
+ try {
16
+ const result = await this.gt.publishFiles(files);
17
+ const failed = result.results.filter((r) => !r.success);
18
+ if (failed.length > 0) {
19
+ this.spinner.stop(chalk.yellow('CDN updated with errors'));
20
+ for (const f of failed) {
21
+ const file = files.find((p) => p.fileId === f.fileId);
22
+ const name = file?.fileName ?? f.fileId;
23
+ logger.warn(`Failed to update ${name}: ${f.error ?? 'unknown error'}`);
24
+ }
25
+ }
26
+ else {
27
+ this.spinner.stop(chalk.green('CDN updated'));
28
+ }
29
+ }
30
+ catch (err) {
31
+ this.spinner.stop(chalk.red('Failed to update CDN'));
32
+ logger.warn(`Publish error: ${err instanceof Error ? err.message : String(err)}`);
33
+ }
34
+ }
35
+ async wait() {
36
+ return;
37
+ }
38
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gt",
3
- "version": "2.10.8",
3
+ "version": "2.11.0",
4
4
  "main": "dist/index.js",
5
5
  "bin": "dist/main.js",
6
6
  "files": [
@@ -110,8 +110,8 @@
110
110
  "unified": "^11.0.5",
111
111
  "unist-util-visit": "^5.0.0",
112
112
  "yaml": "^2.8.0",
113
- "@generaltranslation/python-extractor": "0.1.3",
114
- "generaltranslation": "8.1.17",
113
+ "@generaltranslation/python-extractor": "0.1.4",
114
+ "generaltranslation": "8.1.18",
115
115
  "gt-remark": "1.0.5"
116
116
  },
117
117
  "devDependencies": {