gt 2.12.1 → 2.13.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,11 @@
1
1
  # gtx-cli
2
2
 
3
+ ## 2.13.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#1141](https://github.com/generaltranslation/gt/pull/1141) [`4820643`](https://github.com/generaltranslation/gt/commit/4820643665d5aecacc34c52707c0c81bf4da18ca) Thanks [@ErnestM1234](https://github.com/ErnestM1234)! - feat: auto derive for the t() function
8
+
3
9
  ## 2.12.1
4
10
 
5
11
  ### Patch Changes
@@ -0,0 +1,11 @@
1
+ import { BaseParsingFlags, GTParsingFlags } from '../types/parsing.js';
2
+ /**
3
+ * Default parsing flags for GT files
4
+ * @property {boolean} autoDerive - Whether to enable auto-derive for the t() function. (true -> 'AUTO', false -> 'DISABLED' {@link ParsingConfig['autoDeriveMethod']})
5
+ * @property {boolean} includeSourceCodeContext - Include surrounding source code lines as context for translations.
6
+ */
7
+ export declare const GT_PARSING_FLAGS_DEFAULT: GTParsingFlags;
8
+ /**
9
+ * Default parsing flags for all files
10
+ */
11
+ export declare const BASE_PARSING_FLAGS_DEFAULT: BaseParsingFlags;
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Default parsing flags for GT files
3
+ * @property {boolean} autoDerive - Whether to enable auto-derive for the t() function. (true -> 'AUTO', false -> 'DISABLED' {@link ParsingConfig['autoDeriveMethod']})
4
+ * @property {boolean} includeSourceCodeContext - Include surrounding source code lines as context for translations.
5
+ */
6
+ export const GT_PARSING_FLAGS_DEFAULT = {
7
+ autoDerive: true,
8
+ includeSourceCodeContext: false,
9
+ };
10
+ /**
11
+ * Default parsing flags for all files
12
+ */
13
+ export const BASE_PARSING_FLAGS_DEFAULT = {};
@@ -1,4 +1,4 @@
1
- import { displayProjectId, exitSync, logErrorAndExit, warnApiKeyInConfig, } from '../console/logging.js';
1
+ import { displayProjectId, exitSync, logErrorAndExit, warnApiKeyInConfig, warnDeprecatedField, } from '../console/logging.js';
2
2
  import { loadConfig } from '../fs/config/loadConfig.js';
3
3
  import { defaultBaseUrl, libraryDefaultLocale, } from 'generaltranslation/internal';
4
4
  import fs from 'node:fs';
@@ -12,6 +12,7 @@ import chalk from 'chalk';
12
12
  import { resolveConfig } from './resolveConfig.js';
13
13
  import { gt } from '../utils/gt.js';
14
14
  import { generatePreset } from './optionPresets.js';
15
+ import { GT_PARSING_FLAGS_DEFAULT } from './defaults.js';
15
16
  export const DEFAULT_SRC_PATTERNS = [
16
17
  'src/**/*.{js,jsx,ts,tsx}',
17
18
  'app/**/*.{js,jsx,ts,tsx}',
@@ -85,6 +86,10 @@ export async function generateSettings(flags, cwd = process.cwd()) {
85
86
  }
86
87
  }
87
88
  }
89
+ // Warn on deprecated includeSourceCodeContext
90
+ if (gtConfig.files?.gt?.includeSourceCodeContext != null) {
91
+ warnDeprecatedField('files.gt.includeSourceCodeContext', 'files.gt.parsingFlags.includeSourceCodeContext');
92
+ }
88
93
  // merge options
89
94
  const mergedOptions = { ...gtConfig, ...flags };
90
95
  // Add defaultLocale if not provided
@@ -141,7 +146,10 @@ export async function generateSettings(flags, cwd = process.cwd()) {
141
146
  transformPaths: {},
142
147
  publishPaths: new Set(),
143
148
  unpublishPaths: new Set(),
144
- gtJson: {},
149
+ parsingFlags: {},
150
+ gtJson: {
151
+ parsingFlags: GT_PARSING_FLAGS_DEFAULT,
152
+ },
145
153
  };
146
154
  mergedOptions.options = {
147
155
  ...(mergedOptions.options || {}),
@@ -23,6 +23,7 @@ export declare const warnRecursiveFunctionCallSync: (file: string, functionName:
23
23
  export declare const warnDeriveFunctionNotWrappedSync: (file: string, functionName: string, location?: string) => string;
24
24
  export declare const warnDeriveNonConstVariableSync: (file: string, varName: string, kind: string, location?: string) => string;
25
25
  export declare const warnDeriveFunctionNoResultsSync: (file: string, functionName: string, location?: string) => string;
26
+ export declare const warnAutoDeriveNoResultsSync: (file: string, expression: string, location?: string) => string;
26
27
  export declare const warnDeriveUnresolvableValueSync: (file: string, key: string, location?: string) => string;
27
28
  export declare const warnDeriveCircularSpreadSync: (file: string, varName: string, location?: string) => string;
28
29
  export declare const warnDeriveDestructuringSync: (file: string, varName: string, location?: string) => string;
@@ -34,6 +34,7 @@ export const warnRecursiveFunctionCallSync = (file, functionName, location) => w
34
34
  export const warnDeriveFunctionNotWrappedSync = (file, functionName, location) => withLocation(file, withDeriveFunctionError(`Could not resolve ${colorizeFunctionName(formatCodeClamp(functionName))}. This call is not wrapped in derive() (formerly declareStatic()). Ensure the function is properly wrapped with derive() and does not have circular import dependencies.`), location);
35
35
  export const warnDeriveNonConstVariableSync = (file, varName, kind, location) => withLocation(file, withDeriveFunctionError(`Variable ${colorizeFunctionName(varName)} is declared with '${kind}' but only 'const' declarations can be resolved statically. Change it to 'const'.`), location);
36
36
  export const warnDeriveFunctionNoResultsSync = (file, functionName, location) => withLocation(file, withDeriveFunctionError(`Could not resolve ${colorizeFunctionName(formatCodeClamp(functionName))}. derive() (formerly declareStatic()) can only receive function invocations and cannot use undefined values or looped calls to construct its result.`), location);
37
+ export const warnAutoDeriveNoResultsSync = (file, expression, location) => withLocation(file, `Auto-derive could not resolve ${colorizeFunctionName(formatCodeClamp(expression))}. Only function calls with statically determinable return values can be used directly in t(). Consider wrapping with derive() for explicit derivation, or use an interpolation variable instead.`, location);
37
38
  export const warnDeriveUnresolvableValueSync = (file, key, location) => withLocation(file, withDeriveFunctionError(`Object property ${colorizeFunctionName(formatCodeClamp(key))} could not be resolved to a static string value. Only string literals, template literals, conditionals, and function calls returning strings are supported.`), location);
38
39
  export const warnDeriveCircularSpreadSync = (file, varName, location) => withLocation(file, withDeriveFunctionError(`Circular spread detected involving ${colorizeFunctionName(varName)}. Spread references that form a cycle cannot be resolved statically.`), location);
39
40
  export const warnDeriveDestructuringSync = (file, varName, location) => withLocation(file, withDeriveFunctionError(`Variable ${colorizeFunctionName(varName)} uses destructuring syntax, which is not yet supported in derive(). Assign the value to a const variable directly instead.`), location);
@@ -45,6 +45,7 @@ export declare function warnNoId(file: string): void;
45
45
  export declare function warnHasUnwrappedExpression(file: string, id: string, unwrappedExpressions: string[]): void;
46
46
  export declare function warnTemplateLiteral(file: string, value: string): void;
47
47
  export declare function warnTernary(file: string): void;
48
+ export declare function warnDeprecatedField(deprecatedField: string, replacement: string): void;
48
49
  /**
49
50
  * Helper: Log all collected files
50
51
  */
@@ -154,6 +154,10 @@ export function warnTernary(file) {
154
154
  logger.warn(`Found ternary expression in ${chalk.cyan(file)}. ` +
155
155
  chalk.white('A Branch component may be more appropriate here.'));
156
156
  }
157
+ export function warnDeprecatedField(deprecatedField, replacement) {
158
+ logger.warn(`${chalk.green(deprecatedField)} is deprecated. ` +
159
+ chalk.white(`Use ${chalk.green(replacement)} instead.`));
160
+ }
157
161
  /**
158
162
  * Helper: Log all collected files
159
163
  */
@@ -1,4 +1,4 @@
1
- import { FilesOptions, IncludePattern, ResolvedFiles, TransformFiles, TransformOption } from '../../types/index.js';
1
+ import { FilesOptions, IncludePattern, ResolvedFiles, Settings, 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
@@ -25,17 +25,7 @@ export declare function normalizeIncludePatterns(patterns: IncludePattern[]): {
25
25
  * @param files - The files object
26
26
  * @returns The resolved files
27
27
  */
28
- export declare function resolveFiles(files: FilesOptions, locale: string, locales: string[], cwd: string, compositePatterns?: string[]): {
29
- resolvedPaths: ResolvedFiles;
30
- placeholderPaths: ResolvedFiles;
31
- transformPaths: TransformFiles;
32
- publishPaths: Set<string>;
33
- unpublishPaths: Set<string>;
34
- gtJson: {
35
- publish?: boolean;
36
- includeSourceCodeContext?: boolean;
37
- };
38
- };
28
+ export declare function resolveFiles(files: FilesOptions, locale: string, locales: string[], cwd: string, compositePatterns?: string[]): Settings['files'];
39
29
  export declare function expandGlobPatterns(cwd: string, includePatterns: string[], excludePatterns: string[], locale: string, locales: string[], transformPatterns?: TransformOption | string | TransformOption[], compositePatterns?: string[]): {
40
30
  resolvedPaths: string[];
41
31
  placeholderPaths: string[];
@@ -4,6 +4,7 @@ import { SUPPORTED_FILE_EXTENSIONS } from '../../formats/files/supportedFiles.js
4
4
  import { logger } from '../../console/logger.js';
5
5
  import chalk from 'chalk';
6
6
  import micromatch from 'micromatch';
7
+ import { BASE_PARSING_FLAGS_DEFAULT, GT_PARSING_FLAGS_DEFAULT, } from '../../config/defaults.js';
7
8
  /**
8
9
  * Resolves the files from the files object
9
10
  * Replaces [locale] with the actual locale in the files
@@ -55,11 +56,12 @@ export function normalizeIncludePatterns(patterns) {
55
56
  */
56
57
  export function resolveFiles(files, locale, locales, cwd, compositePatterns) {
57
58
  // Initialize result object with empty arrays for each file type
58
- const result = {};
59
+ const resolvedPaths = {};
59
60
  const placeholderResult = {};
60
61
  const transformPaths = {};
61
62
  const publishPaths = new Set();
62
63
  const unpublishPaths = new Set();
64
+ const parsingFlags = {};
63
65
  // Process GT files
64
66
  if (files.gt?.output) {
65
67
  placeholderResult.gt = path.resolve(cwd, files.gt.output);
@@ -77,21 +79,32 @@ export function resolveFiles(files, locale, locales, cwd, compositePatterns) {
77
79
  if (files[fileType]?.include) {
78
80
  const { paths, publishPatterns, unpublishPatterns } = normalizeIncludePatterns(files[fileType].include);
79
81
  const filePaths = expandGlobPatterns(cwd, paths, files[fileType]?.exclude || [], locale, locales, transformPaths[fileType] || undefined, compositePatterns);
80
- result[fileType] = filePaths.resolvedPaths;
82
+ resolvedPaths[fileType] = filePaths.resolvedPaths;
81
83
  placeholderResult[fileType] = filePaths.placeholderPaths;
82
84
  // Classify resolved paths into publish/unpublish sets
83
85
  classifyPublishPaths(filePaths.resolvedPaths, publishPatterns, unpublishPatterns, cwd, locale, publishPaths, unpublishPaths);
84
86
  }
87
+ // ==== OTHER ==== //
88
+ if (files[fileType]?.parsingFlags) {
89
+ parsingFlags[fileType] = {
90
+ ...BASE_PARSING_FLAGS_DEFAULT,
91
+ ...files[fileType].parsingFlags,
92
+ };
93
+ }
85
94
  }
86
95
  return {
87
- resolvedPaths: result,
96
+ resolvedPaths,
88
97
  placeholderPaths: placeholderResult,
89
98
  transformPaths: transformPaths,
90
99
  publishPaths,
91
100
  unpublishPaths,
101
+ parsingFlags,
92
102
  gtJson: {
93
103
  publish: files.gt?.publish,
94
- includeSourceCodeContext: files.gt?.includeSourceCodeContext,
104
+ parsingFlags: {
105
+ ...GT_PARSING_FLAGS_DEFAULT,
106
+ ...(files.gt?.parsingFlags || {}),
107
+ },
95
108
  },
96
109
  };
97
110
  }
@@ -1 +1 @@
1
- export declare const PACKAGE_VERSION = "2.12.1";
1
+ export declare const PACKAGE_VERSION = "2.13.0";
@@ -1,2 +1,2 @@
1
1
  // This file is auto-generated. Do not edit manually.
2
- export const PACKAGE_VERSION = '2.12.1';
2
+ export const PACKAGE_VERSION = '2.13.0';
@@ -1,5 +1,5 @@
1
1
  import * as t from '@babel/types';
2
- import { INLINE_TRANSLATION_HOOK, INLINE_TRANSLATION_HOOK_ASYNC, INLINE_MESSAGE_HOOK, INLINE_MESSAGE_HOOK_ASYNC, STRING_REGISTRATION_FUNCS, T_GLOBAL_REGISTRATION_FUNCTION_MARKER, } from './constants.js';
2
+ import { INLINE_TRANSLATION_HOOK, INLINE_TRANSLATION_HOOK_ASYNC, INLINE_MESSAGE_HOOK, INLINE_MESSAGE_HOOK_ASYNC, STRING_REGISTRATION_FUNCS, T_GLOBAL_REGISTRATION_FUNCTION_MARKER, T_REGISTRATION_FUNCTION, } from './constants.js';
3
3
  import { warnAsyncUseGT, warnSyncGetGT } from '../../../console/index.js';
4
4
  import traverseModule from '@babel/traverse';
5
5
  // Handle CommonJS/ESM interop
@@ -80,8 +80,8 @@ export function resolveVariableAliases(scope, variableName, visited = new Set())
80
80
  }
81
81
  /**
82
82
  * Handles how translation callbacks are used within code.
83
- * This covers both direct translation calls (t('hello')) and prop drilling
84
- * where the translation callback is passed to other functions (getData(t)).
83
+ * This covers both direct translation calls (gt('hello')) and prop drilling
84
+ * where the translation callback is passed to other functions (getData(gt)).
85
85
  */
86
86
  function handleFunctionCall(tPath, config, state, output) {
87
87
  if (tPath.parent.type === 'CallExpression' &&
@@ -278,9 +278,16 @@ function processFunctionInFile(filePath, functionName, argIndex, config, state,
278
278
  */
279
279
  export function parseStrings(importName, originalName, path, config, output) {
280
280
  // Handle global t macro directly — path is already the tag identifier
281
+ // NOTE: if we decide to add support for a global t() function in addition to the macro,
282
+ // then we need to add support for skipDeriveInvocation here
281
283
  if (originalName === T_GLOBAL_REGISTRATION_FUNCTION_MARKER) {
282
284
  if (!config.ignoreGlobalTaggedTemplates) {
283
- processTaggedTemplateCall(path, config, output);
285
+ processTaggedTemplateCall(path, {
286
+ ...config,
287
+ autoDeriveMethod: config.autoDeriveMethod === 'AUTO'
288
+ ? 'DISABLED'
289
+ : config.autoDeriveMethod,
290
+ }, output);
284
291
  }
285
292
  return;
286
293
  }
@@ -300,11 +307,39 @@ export function parseStrings(importName, originalName, path, config, output) {
300
307
  includeSourceCodeContext: config.includeSourceCodeContext,
301
308
  ignoreTaggedTemplates: false,
302
309
  ignoreGlobalTaggedTemplates: false,
310
+ // User configurable, otherwise default to AUTO
311
+ autoDeriveMethod: config.autoDeriveMethod === 'AUTO'
312
+ ? 'DISABLED'
313
+ : config.autoDeriveMethod,
303
314
  };
304
315
  // Check if this is a direct call to msg('string') or t('string')
305
316
  if (refPath.parent.type === 'CallExpression' &&
306
317
  refPath.parent.callee === refPath.node) {
307
- processTranslationCall(refPath, stringRegistrationConfig, output);
318
+ /**
319
+ * SPECIAL CASE: Auto-derive t() function
320
+ * The t() function, will treat variable content as if it was marked for derivation
321
+ * without explicit calls to derive().
322
+ *
323
+ * @example
324
+ * const derivedValue = 'John';
325
+ * const interpolatedValue = "Ernest"
326
+ * t(
327
+ * "Hello, " + derivedValue + "! My name is {interpolatedValue}",
328
+ * { interpolatedValue }
329
+ * );
330
+ * // "Hello, John! My name is {interpolatedValue}"
331
+ */
332
+ if (originalName === T_REGISTRATION_FUNCTION) {
333
+ processTranslationCall(refPath, config.autoDeriveMethod === 'AUTO'
334
+ ? {
335
+ ...stringRegistrationConfig,
336
+ autoDeriveMethod: 'ENABLED',
337
+ }
338
+ : stringRegistrationConfig, output);
339
+ }
340
+ else {
341
+ processTranslationCall(refPath, stringRegistrationConfig, output);
342
+ }
308
343
  }
309
344
  else if (!stringRegistrationConfig.ignoreTaggedTemplates &&
310
345
  refPath.parent.type === 'TaggedTemplateExpression' &&
@@ -348,6 +383,10 @@ export function parseStrings(importName, originalName, path, config, output) {
348
383
  includeSourceCodeContext: config.includeSourceCodeContext,
349
384
  ignoreTaggedTemplates: false,
350
385
  ignoreGlobalTaggedTemplates: false,
386
+ // User configurable, otherwise default to DISABLED
387
+ autoDeriveMethod: config.autoDeriveMethod === 'AUTO'
388
+ ? 'DISABLED'
389
+ : config.autoDeriveMethod,
351
390
  };
352
391
  const effectiveParent = parentPath?.node.type === 'AwaitExpression'
353
392
  ? parentPath.parentPath
@@ -12,13 +12,15 @@ export type StringTree = (string | StringTree)[];
12
12
  * @param parsingOptions - Parsing configuration
13
13
  * @param errors - Errors to add to
14
14
  * @param runtimeInterpolationState - When provided, non-derive dynamic expressions become {n} placeholders instead of errors. Pass { index: 0 } at the entry point for template macros.
15
+ * @param skipDeriveInvocation - If true, skip derive invocation check
15
16
  * @returns Node | null - The parsed node, or null if invalid
16
17
  *
17
18
  * @note runtimeInterpolationState
18
19
  * - Only provide at entry for template macros, otherwise omit
19
20
  * - t`Hello {nonDerivableValue}` -> t`Hello {0}`
21
+ *
20
22
  */
21
- export declare function handleDerivation({ expr, tPath, file, parsingOptions, errors, warnings, runtimeInterpolationState, }: {
23
+ export declare function handleDerivation({ expr, tPath, file, parsingOptions, errors, warnings, runtimeInterpolationState, skipDeriveInvocation, }: {
22
24
  expr: t.Expression;
23
25
  tPath: NodePath;
24
26
  file: string;
@@ -28,4 +30,5 @@ export declare function handleDerivation({ expr, tPath, file, parsingOptions, er
28
30
  runtimeInterpolationState?: {
29
31
  index: number;
30
32
  };
33
+ skipDeriveInvocation?: boolean;
31
34
  }): StringNode | null;
@@ -4,7 +4,7 @@ import { buildImportMap } from '../../buildImportMap.js';
4
4
  import { resolveImportPath } from '../../resolveImportPath.js';
5
5
  import { parse } from '@babel/parser';
6
6
  import fs from 'node:fs';
7
- import { warnFunctionNotFoundSync, warnDeriveFunctionNoResultsSync, warnDeriveFunctionNotWrappedSync, } from '../../../../../console/index.js';
7
+ import { warnFunctionNotFoundSync, warnDeriveFunctionNoResultsSync, warnDeriveFunctionNotWrappedSync, warnAutoDeriveNoResultsSync, } from '../../../../../console/index.js';
8
8
  import traverseModule from '@babel/traverse';
9
9
  import generateModule from '@babel/generator';
10
10
  import { isDeriveCall } from './isDeriveCall.js';
@@ -32,13 +32,15 @@ const processFunctionCache = new Map();
32
32
  * @param parsingOptions - Parsing configuration
33
33
  * @param errors - Errors to add to
34
34
  * @param runtimeInterpolationState - When provided, non-derive dynamic expressions become {n} placeholders instead of errors. Pass { index: 0 } at the entry point for template macros.
35
+ * @param skipDeriveInvocation - If true, skip derive invocation check
35
36
  * @returns Node | null - The parsed node, or null if invalid
36
37
  *
37
38
  * @note runtimeInterpolationState
38
39
  * - Only provide at entry for template macros, otherwise omit
39
40
  * - t`Hello {nonDerivableValue}` -> t`Hello {0}`
41
+ *
40
42
  */
41
- export function handleDerivation({ expr, tPath, file, parsingOptions, errors, warnings, runtimeInterpolationState, }) {
43
+ export function handleDerivation({ expr, tPath, file, parsingOptions, errors, warnings, runtimeInterpolationState, skipDeriveInvocation, }) {
42
44
  if (!expr) {
43
45
  return null;
44
46
  }
@@ -115,6 +117,7 @@ export function handleDerivation({ expr, tPath, file, parsingOptions, errors, wa
115
117
  errors,
116
118
  warnings,
117
119
  runtimeInterpolationState,
120
+ skipDeriveInvocation,
118
121
  });
119
122
  if (result === null)
120
123
  return null;
@@ -143,6 +146,7 @@ export function handleDerivation({ expr, tPath, file, parsingOptions, errors, wa
143
146
  errors,
144
147
  warnings,
145
148
  runtimeInterpolationState,
149
+ skipDeriveInvocation,
146
150
  });
147
151
  const rightResult = handleDerivation({
148
152
  expr: expr.right,
@@ -152,6 +156,7 @@ export function handleDerivation({ expr, tPath, file, parsingOptions, errors, wa
152
156
  errors,
153
157
  warnings,
154
158
  runtimeInterpolationState,
159
+ skipDeriveInvocation,
155
160
  });
156
161
  if (leftResult === null || rightResult === null) {
157
162
  return null;
@@ -168,6 +173,7 @@ export function handleDerivation({ expr, tPath, file, parsingOptions, errors, wa
168
173
  errors,
169
174
  warnings,
170
175
  runtimeInterpolationState,
176
+ skipDeriveInvocation,
171
177
  });
172
178
  }
173
179
  // Handle numeric literals by converting them to strings
@@ -204,6 +210,21 @@ export function handleDerivation({ expr, tPath, file, parsingOptions, errors, wa
204
210
  if (t.isNullLiteral(expr)) {
205
211
  return { type: 'text', text: 'null' };
206
212
  }
213
+ // Non-static expression
214
+ if (skipDeriveInvocation) {
215
+ // Skip pass a `derive()` invocation to do derivation
216
+ const variants = resolveCallStringVariants(expr, tPath, file, parsingOptions, errors, warnings);
217
+ if (variants) {
218
+ return {
219
+ type: 'choice',
220
+ nodes: variants.map((v) => ({ type: 'text', text: v })),
221
+ };
222
+ }
223
+ // Auto-derive had no resolvable results
224
+ const code = generate(expr).code;
225
+ errors.push(warnAutoDeriveNoResultsSync(file, code, `${expr.loc?.start?.line}:${expr.loc?.start?.column}`));
226
+ return null;
227
+ }
207
228
  // Not a derivable expression
208
229
  if (runtimeInterpolationState) {
209
230
  return { type: 'text', text: `{${runtimeInterpolationState.index++}}` };
@@ -31,6 +31,7 @@ export function deriveExpression({ tPath, expr, metadata, config, output, index,
31
31
  runtimeInterpolationState: enableRuntimeInterpolation
32
32
  ? { index: 0 }
33
33
  : undefined,
34
+ skipDeriveInvocation: config.autoDeriveMethod === 'ENABLED',
34
35
  });
35
36
  // Nothing returned, push error
36
37
  if (!stringNode) {
@@ -35,6 +35,13 @@ export type ParsingConfig = {
35
35
  * If true, ignore global tagged template expressions (t`hello` without import)
36
36
  */
37
37
  ignoreGlobalTaggedTemplates: boolean;
38
+ /**
39
+ * Skip requirement for a derive() invocation to trigger derivation
40
+ * - ENABLED: Always auto-derive
41
+ * - DISABLED: Never auto-derive
42
+ * - AUTO: Only auto-derive for the t() function
43
+ */
44
+ autoDeriveMethod: 'ENABLED' | 'DISABLED' | 'AUTO';
38
45
  };
39
46
  /**
40
47
  * Mutable state for tracking parsing progress.
@@ -1,8 +1,8 @@
1
1
  import { Updates } from '../../types/index.js';
2
- import type { ParsingConfigOptions } from '../../types/parsing.js';
2
+ import type { ParsingConfigOptions, GTParsingFlags } from '../../types/parsing.js';
3
3
  import { GTLibrary } from '../../types/libraries.js';
4
4
  import { dedupeUpdates } from '../../extraction/postProcess.js';
5
- export declare function createInlineUpdates(pkg: GTLibrary, validate: boolean, filePatterns: string[] | undefined, parsingOptions: ParsingConfigOptions, includeSourceCodeContext?: boolean): Promise<{
5
+ export declare function createInlineUpdates(pkg: GTLibrary, validate: boolean, filePatterns: string[] | undefined, parsingFlags: GTParsingFlags, parsingOptions: ParsingConfigOptions): Promise<{
6
6
  updates: Updates;
7
7
  errors: string[];
8
8
  warnings: string[];
@@ -8,7 +8,7 @@ import { DEFAULT_SRC_PATTERNS } from '../../config/generateSettings.js';
8
8
  import { getPathsAndAliases } from '../jsx/utils/getPathsAndAliases.js';
9
9
  import { GT_LIBRARIES_UPSTREAM, REACT_LIBRARIES, } from '../../types/libraries.js';
10
10
  import { calculateHashes, dedupeUpdates, linkDeriveUpdates, } from '../../extraction/postProcess.js';
11
- export async function createInlineUpdates(pkg, validate, filePatterns, parsingOptions, includeSourceCodeContext = false) {
11
+ export async function createInlineUpdates(pkg, validate, filePatterns, parsingFlags, parsingOptions) {
12
12
  const updates = [];
13
13
  const errors = [];
14
14
  const warnings = new Set();
@@ -39,9 +39,11 @@ export async function createInlineUpdates(pkg, validate, filePatterns, parsingOp
39
39
  ignoreDynamicContent: false,
40
40
  ignoreInvalidIcu: false,
41
41
  ignoreInlineListContent: false,
42
- includeSourceCodeContext,
42
+ includeSourceCodeContext: parsingFlags.includeSourceCodeContext,
43
43
  ignoreTaggedTemplates: false,
44
44
  ignoreGlobalTaggedTemplates: false,
45
+ // User configurable, otherwise default to AUTO
46
+ autoDeriveMethod: parsingFlags.autoDerive ? 'AUTO' : 'DISABLED',
45
47
  }, { updates, errors, warnings });
46
48
  }
47
49
  // Parse <T> components
@@ -57,7 +59,7 @@ export async function createInlineUpdates(pkg, validate, filePatterns, parsingOp
57
59
  parsingOptions,
58
60
  pkgs,
59
61
  file,
60
- includeSourceCodeContext,
62
+ includeSourceCodeContext: parsingFlags.includeSourceCodeContext,
61
63
  },
62
64
  output: {
63
65
  errors,
@@ -1,5 +1,5 @@
1
1
  import { Updates, TranslateFlags } from '../types/index.js';
2
- import type { ParsingConfigOptions } from '../types/parsing.js';
2
+ import type { ParsingConfigOptions, GTParsingFlags } from '../types/parsing.js';
3
3
  import { InlineLibrary } from '../types/libraries.js';
4
4
  /**
5
5
  * Searches for gt-react or gt-next dictionary files and creates updates for them,
@@ -10,7 +10,7 @@ import { InlineLibrary } from '../types/libraries.js';
10
10
  * @param pkg - The package name
11
11
  * @returns An object containing the updates and errors
12
12
  */
13
- export declare function createUpdates(options: TranslateFlags, src: string[] | undefined, sourceDictionary: string | undefined, pkg: InlineLibrary, validate: boolean, parsingOptions: ParsingConfigOptions, includeSourceCodeContext?: boolean): Promise<{
13
+ export declare function createUpdates(options: TranslateFlags, src: string[] | undefined, sourceDictionary: string | undefined, pkg: InlineLibrary, validate: boolean, parsingFlags: GTParsingFlags, parsingOptions: ParsingConfigOptions): Promise<{
14
14
  updates: Updates;
15
15
  errors: string[];
16
16
  warnings: string[];
@@ -17,7 +17,7 @@ import { isPythonLibrary } from '../types/libraries.js';
17
17
  * @param pkg - The package name
18
18
  * @returns An object containing the updates and errors
19
19
  */
20
- export async function createUpdates(options, src, sourceDictionary, pkg, validate, parsingOptions, includeSourceCodeContext = false) {
20
+ export async function createUpdates(options, src, sourceDictionary, pkg, validate, parsingFlags, parsingOptions) {
21
21
  let updates = [];
22
22
  let errors = [];
23
23
  let warnings = [];
@@ -53,7 +53,7 @@ export async function createUpdates(options, src, sourceDictionary, pkg, validat
53
53
  // Scan through project for translatable content
54
54
  const { updates: newUpdates, errors: newErrors, warnings: newWarnings, } = isPythonLibrary(pkg)
55
55
  ? await createPythonInlineUpdates(src)
56
- : await createInlineUpdates(pkg, validate, src, parsingOptions, includeSourceCodeContext);
56
+ : await createInlineUpdates(pkg, validate, src, parsingFlags, parsingOptions);
57
57
  errors = [...errors, ...newErrors];
58
58
  warnings = [...warnings, ...newWarnings];
59
59
  updates = [...updates, ...newUpdates];
@@ -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?.gtJson.includeSourceCodeContext ?? false);
18
+ const { updates, errors, warnings } = await createUpdates(options, settings.src, options.dictionary, library, false, settings.files.gtJson.parsingFlags, settings.parsingOptions);
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?.gtJson.includeSourceCodeContext ?? false);
13
+ return createInlineUpdates(pkg, true, files, settings.files.gtJson.parsingFlags, settings.parsingOptions);
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?.gtJson.includeSourceCodeContext ?? false);
26
+ return createUpdates(settings, settings.src, dictionary, pkg, true, settings.files.gtJson.parsingFlags, settings.parsingOptions);
27
27
  }
28
28
  /**
29
29
  * Parse file path from error/warning string in withLocation format: "filepath (line:col): message"
@@ -1,6 +1,6 @@
1
1
  import { CustomMapping } from 'generaltranslation/types';
2
2
  import { SUPPORTED_FILE_EXTENSIONS } from '../formats/files/supportedFiles.js';
3
- import { ParsingConfigOptions } from './parsing.js';
3
+ import { ParsingConfigOptions, GTParsingFlags, BaseParsingFlags, ParseFlagsByFileType } from './parsing.js';
4
4
  import { Libraries, InlineLibrary } from './libraries.js';
5
5
  export type { Updates } from 'generaltranslation/types';
6
6
  export type Options = {
@@ -142,11 +142,17 @@ export type FilesOptions = {
142
142
  include: IncludePattern[];
143
143
  exclude?: string[];
144
144
  transform?: string | TransformOption | TransformOption[];
145
+ parsingFlags?: BaseParsingFlags;
145
146
  };
146
147
  } & {
147
148
  gt?: {
148
149
  output: string;
149
150
  publish?: boolean;
151
+ parsingFlags?: Partial<GTParsingFlags>;
152
+ /**
153
+ * @deprecated
154
+ * use `files.gt.parsingFlags.includeSourceCodeContext` instead
155
+ */
150
156
  includeSourceCodeContext?: boolean;
151
157
  };
152
158
  };
@@ -166,8 +172,14 @@ export type Settings = {
166
172
  transformPaths: TransformFiles;
167
173
  publishPaths: Set<string>;
168
174
  unpublishPaths: Set<string>;
175
+ parsingFlags: ParseFlagsByFileType;
169
176
  gtJson: {
170
177
  publish?: boolean;
178
+ parsingFlags: GTParsingFlags;
179
+ /**
180
+ * @deprecated
181
+ * use {@link files.gt.GTParsingFlags.parsingFlags.includeSourceCodeContext} instead
182
+ */
171
183
  includeSourceCodeContext?: boolean;
172
184
  };
173
185
  };
@@ -1,3 +1,46 @@
1
+ import { SupportedFileExtension } from './index.js';
2
+ /**
3
+ * For monorepo projects, checking for extra exports fields in resolved internal packages.
4
+ * For instance, an exported path may be labeled as 'browser' or 'module' or 'default'.
5
+ * These can resolve to different files in the compiled package. This helps us know
6
+ * which files to check when we do resolution.
7
+ *
8
+ * @property conditionNames - The condition names to check for in the resolved package.
9
+ *
10
+ * @example
11
+ * {
12
+ * conditionNames: ['development', 'browser', 'module', 'import', 'require', 'default']
13
+ * }
14
+ */
1
15
  export type ParsingConfigOptions = {
2
16
  conditionNames: string[];
3
17
  };
18
+ /**
19
+ * Base parsing flags for all files.
20
+ * Currently no supported properties
21
+ *
22
+ * Future ideas for flags:
23
+ * - flag for extraction of file name
24
+ * - flag for extraction of last modified timestamp
25
+ * - flag for extraction of git history
26
+ */
27
+ export type BaseParsingFlags = Record<string, unknown>;
28
+ /**
29
+ * Flags for parsing content. Not to be confused with ParsingConfig which helps us enable/disable
30
+ * parsing features depending on the function being parsed. Parsing flags is for users to override
31
+ * some of these defaults or enable/disable other features.
32
+ *
33
+ * @property {boolean} autoDerive - Whether to enable auto-derive for the t() function. (true -> 'AUTO', false -> 'DISABLED' {@link ParsingConfig['autoDeriveMethod']})
34
+ * @property {boolean} includeSourceCodeContext - Include surrounding source code lines as context for translations.
35
+ */
36
+ export type GTParsingFlags = BaseParsingFlags & {
37
+ autoDerive: boolean;
38
+ includeSourceCodeContext: boolean;
39
+ };
40
+ /**
41
+ * Flags for parsing content with each filetype having its own flags
42
+ * This is really a helper type that helps us map across filetypes
43
+ */
44
+ export type ParseFlagsByFileType = {
45
+ [K in SupportedFileExtension]?: BaseParsingFlags;
46
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gt",
3
- "version": "2.12.1",
3
+ "version": "2.13.0",
4
4
  "main": "dist/index.js",
5
5
  "bin": "dist/main.js",
6
6
  "files": [