gtx-cli 2.6.26 → 2.6.27

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.
Files changed (24) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/generated/version.d.ts +1 -1
  3. package/dist/generated/version.js +1 -1
  4. package/dist/react/jsx/evaluateJsx.js +0 -3
  5. package/dist/react/jsx/utils/mapAttributeName.d.ts +6 -1
  6. package/dist/react/jsx/utils/mapAttributeName.js +10 -12
  7. package/dist/react/jsx/utils/parseStringFunction.d.ts +1 -21
  8. package/dist/react/jsx/utils/parseStringFunction.js +10 -163
  9. package/dist/react/jsx/utils/stringParsing/processTranslationCall/extractStringEntryMetadata.d.ts +29 -0
  10. package/dist/react/jsx/utils/stringParsing/processTranslationCall/extractStringEntryMetadata.js +86 -0
  11. package/dist/react/jsx/utils/stringParsing/processTranslationCall/handleInvalidTranslationCall.d.ts +14 -0
  12. package/dist/react/jsx/utils/stringParsing/processTranslationCall/handleInvalidTranslationCall.js +24 -0
  13. package/dist/react/jsx/utils/stringParsing/processTranslationCall/handleLiteralTranslationCall.d.ts +19 -0
  14. package/dist/react/jsx/utils/stringParsing/processTranslationCall/handleLiteralTranslationCall.js +31 -0
  15. package/dist/react/jsx/utils/stringParsing/processTranslationCall/handleStaticTranslationCall.d.ts +22 -0
  16. package/dist/react/jsx/utils/stringParsing/processTranslationCall/handleStaticTranslationCall.js +51 -0
  17. package/dist/react/jsx/utils/stringParsing/processTranslationCall/index.d.ts +18 -0
  18. package/dist/react/jsx/utils/stringParsing/processTranslationCall/index.js +39 -0
  19. package/dist/react/jsx/utils/stringParsing/processTranslationCall/routeTranslationCall.d.ts +24 -0
  20. package/dist/react/jsx/utils/stringParsing/processTranslationCall/routeTranslationCall.js +68 -0
  21. package/dist/react/jsx/utils/stringParsing/types.d.ts +41 -0
  22. package/dist/react/jsx/utils/stringParsing/types.js +1 -0
  23. package/dist/react/parse/createInlineUpdates.js +2 -1
  24. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # gtx-cli
2
2
 
3
+ ## 2.6.27
4
+
5
+ ### Patch Changes
6
+
7
+ - [#1051](https://github.com/generaltranslation/gt/pull/1051) [`d36d4b8`](https://github.com/generaltranslation/gt/commit/d36d4b8459626c552c143fbdfa6d01f647a66533) Thanks [@ErnestM1234](https://github.com/ErnestM1234)! - feat: string list registration
8
+
3
9
  ## 2.6.26
4
10
 
5
11
  ### Patch Changes
@@ -1 +1 @@
1
- export declare const PACKAGE_VERSION = "2.6.26";
1
+ export declare const PACKAGE_VERSION = "2.6.27";
@@ -1,2 +1,2 @@
1
1
  // This file is auto-generated. Do not edit manually.
2
- export const PACKAGE_VERSION = '2.6.26';
2
+ export const PACKAGE_VERSION = '2.6.27';
@@ -1,8 +1,5 @@
1
1
  import * as t from '@babel/types';
2
2
  import { parse } from '@formatjs/icu-messageformat-parser';
3
- import generateModule from '@babel/generator';
4
- // Handle CommonJS/ESM interop
5
- const generate = generateModule.default || generateModule;
6
3
  const MEANINGFUL_REGEX = /[\p{L}\p{N}]/u;
7
4
  /**
8
5
  * Checks if a node is meaningful. Does not recurse into children.
@@ -1,6 +1,11 @@
1
+ /**
2
+ * Type logic implementation
3
+ */
4
+ type MapAttributeName<T extends string> = T extends '$id' ? 'id' : T extends '$context' ? 'context' : T extends '$maxChars' ? 'maxChars' : T;
1
5
  /**
2
6
  * Map the attribute name to the corresponding attribute name in the metadata
3
7
  * @param attrName - The attribute name to map
4
8
  * @returns The mapped attribute name
5
9
  */
6
- export declare function mapAttributeName(attrName: string): string;
10
+ export declare function mapAttributeName<T extends string>(attrName: T): MapAttributeName<T>;
11
+ export {};
@@ -1,14 +1,12 @@
1
- /**
2
- * Map the attribute name to the corresponding attribute name in the metadata
3
- * @param attrName - The attribute name to map
4
- * @returns The mapped attribute name
5
- */
6
1
  export function mapAttributeName(attrName) {
7
- if (attrName === '$id')
8
- return 'id';
9
- if (attrName === '$context')
10
- return 'context';
11
- if (attrName === '$maxChars')
12
- return 'maxChars';
13
- return attrName;
2
+ switch (attrName) {
3
+ case '$id':
4
+ return 'id';
5
+ case '$context':
6
+ return 'context';
7
+ case '$maxChars':
8
+ return 'maxChars';
9
+ default:
10
+ return attrName;
11
+ }
14
12
  }
@@ -1,28 +1,9 @@
1
1
  import { NodePath, Scope } from '@babel/traverse';
2
- import { Updates } from '../../../types/index.js';
3
- import type { ParsingConfigOptions } from '../../../types/parsing.js';
2
+ import type { ParsingConfig, ParsingOutput } from './stringParsing/types.js';
4
3
  /**
5
4
  * Clears all caches. Useful for testing or when file system changes.
6
5
  */
7
6
  export declare function clearParsingCaches(): void;
8
- /**
9
- * Immutable configuration options for string parsing.
10
- */
11
- type ParsingConfig = {
12
- parsingOptions: ParsingConfigOptions;
13
- file: string;
14
- ignoreAdditionalData: boolean;
15
- ignoreDynamicContent: boolean;
16
- ignoreInvalidIcu: boolean;
17
- };
18
- /**
19
- * Collectors for updates, errors, and warnings.
20
- */
21
- type ParsingOutput = {
22
- updates: Updates;
23
- errors: string[];
24
- warnings: Set<string>;
25
- };
26
7
  /**
27
8
  * Recursively resolves variable assignments to find all aliases of a translation callback parameter.
28
9
  * Handles cases like: const t = translate; const a = translate; const b = a; const c = b;
@@ -47,4 +28,3 @@ export declare function resolveVariableAliases(scope: Scope, variableName: strin
47
28
  * - This will parse constants.ts to find translation calls within getInfo function
48
29
  */
49
30
  export declare function parseStrings(importName: string, originalName: string, path: NodePath, config: ParsingConfig, output: ParsingOutput): void;
50
- export {};
@@ -1,23 +1,14 @@
1
1
  import * as t from '@babel/types';
2
- import { isStaticExpression, isValidIcu } from '../evaluateJsx.js';
3
- import { GT_ATTRIBUTES_WITH_SUGAR, MSG_REGISTRATION_FUNCTION, INLINE_TRANSLATION_HOOK, INLINE_TRANSLATION_HOOK_ASYNC, INLINE_MESSAGE_HOOK, INLINE_MESSAGE_HOOK_ASYNC, } from './constants.js';
4
- import { mapAttributeName } from './mapAttributeName.js';
5
- import { warnNonStaticExpressionSync, warnNonStringSync, warnTemplateLiteralSync, warnAsyncUseGT, warnSyncGetGT, warnInvalidIcuSync, warnInvalidMaxCharsSync, } from '../../../console/index.js';
6
- import generateModule from '@babel/generator';
2
+ import { MSG_REGISTRATION_FUNCTION, INLINE_TRANSLATION_HOOK, INLINE_TRANSLATION_HOOK_ASYNC, INLINE_MESSAGE_HOOK, INLINE_MESSAGE_HOOK_ASYNC, } from './constants.js';
3
+ import { warnAsyncUseGT, warnSyncGetGT } from '../../../console/index.js';
7
4
  import traverseModule from '@babel/traverse';
8
5
  // Handle CommonJS/ESM interop
9
- const generate = generateModule.default || generateModule;
10
6
  const traverse = traverseModule.default || traverseModule;
11
7
  import fs from 'node:fs';
12
- import pathModule from 'node:path';
13
8
  import { parse } from '@babel/parser';
14
9
  import { resolveImportPath } from './resolveImportPath.js';
15
10
  import { buildImportMap } from './buildImportMap.js';
16
- import { handleStaticExpression } from './parseDeclareStatic.js';
17
- import { nodeToStrings } from './parseString.js';
18
- import { isNumberLiteral } from './isNumberLiteral.js';
19
- import { indexVars } from 'generaltranslation/internal';
20
- import { randomUUID } from 'node:crypto';
11
+ import { processTranslationCall } from './stringParsing/processTranslationCall/index.js';
21
12
  /**
22
13
  * Cache for resolved import paths to avoid redundant I/O operations.
23
14
  * Key: `${currentFile}::${importPath}`
@@ -37,155 +28,6 @@ export function clearParsingCaches() {
37
28
  resolveImportPathCache.clear();
38
29
  processFunctionCache.clear();
39
30
  }
40
- /**
41
- * Processes a single translation function call (e.g., t('hello world', { id: 'greeting' })).
42
- * Extracts the translatable string content and metadata, then adds it to the updates array.
43
- *
44
- * Handles:
45
- * - String literals: t('hello')
46
- * - Template literals without expressions: t(`hello`)
47
- * - Metadata extraction from options object
48
- * - Error reporting for non-static expressions and template literals with expressions
49
- */
50
- function processTranslationCall(tPath, config, output) {
51
- if (tPath.parent.type === 'CallExpression' &&
52
- tPath.parent.arguments.length > 0) {
53
- const arg = tPath.parent.arguments[0];
54
- // if (t.isExpression(arg)) {
55
- if (!config.ignoreDynamicContent &&
56
- t.isExpression(arg) &&
57
- !isStaticExpression(arg).isStatic) {
58
- const result = handleStaticExpression(arg, tPath, config.file, config.parsingOptions, output.errors);
59
- if (result) {
60
- const strings = nodeToStrings(result).map(indexVars);
61
- if (!config.ignoreInvalidIcu) {
62
- for (const string of strings) {
63
- const { isValid, error } = isValidIcu(string);
64
- if (!isValid) {
65
- output.warnings.add(warnInvalidIcuSync(config.file, string, error ?? 'Unknown error', `${arg.loc?.start?.line}:${arg.loc?.start?.column}`));
66
- return;
67
- }
68
- }
69
- }
70
- // get metadata and id from options
71
- const options = tPath.parent.arguments[1];
72
- const metadata = {};
73
- if (options && options.type === 'ObjectExpression') {
74
- options.properties.forEach((prop) => {
75
- if (prop.type === 'ObjectProperty' &&
76
- prop.key.type === 'Identifier') {
77
- const attribute = prop.key.name;
78
- if (GT_ATTRIBUTES_WITH_SUGAR.includes(attribute) &&
79
- t.isExpression(prop.value)) {
80
- const result = isStaticExpression(prop.value);
81
- if (!result.isStatic) {
82
- output.errors.push(warnNonStaticExpressionSync(config.file, attribute, generate(prop.value).code, `${prop.loc?.start?.line}:${prop.loc?.start?.column}`));
83
- }
84
- if (result.isStatic &&
85
- result.value &&
86
- !config.ignoreAdditionalData) {
87
- // Map $id and $context to id and context
88
- metadata[mapAttributeName(attribute)] = result.value;
89
- }
90
- }
91
- }
92
- });
93
- }
94
- const temporaryStaticId = `static-temp-id-${randomUUID()}`;
95
- for (const string of strings) {
96
- output.updates.push({
97
- dataFormat: 'ICU',
98
- source: string,
99
- metadata: { ...metadata, staticId: temporaryStaticId },
100
- });
101
- }
102
- return;
103
- }
104
- // Nothing returned, push error
105
- output.errors.push(warnNonStringSync(config.file, generate(arg).code, `${arg.loc?.start?.line}:${arg.loc?.start?.column}`));
106
- // ignore dynamic content flag is triggered, check strings are valid ICU
107
- }
108
- else if (arg.type === 'StringLiteral' ||
109
- (t.isTemplateLiteral(arg) && arg.expressions.length === 0)) {
110
- const source = arg.type === 'StringLiteral' ? arg.value : arg.quasis[0].value.raw;
111
- // Validate is ICU
112
- if (!config.ignoreInvalidIcu) {
113
- const { isValid, error } = isValidIcu(source);
114
- if (!isValid) {
115
- output.warnings.add(warnInvalidIcuSync(config.file, source, error ?? 'Unknown error', `${arg.loc?.start?.line}:${arg.loc?.start?.column}`));
116
- return;
117
- }
118
- }
119
- // get metadata and id from options
120
- const options = tPath.parent.arguments[1];
121
- const metadata = {};
122
- if (options && options.type === 'ObjectExpression') {
123
- options.properties.forEach((prop) => {
124
- if (prop.type === 'ObjectProperty' &&
125
- prop.key.type === 'Identifier') {
126
- const attribute = prop.key.name;
127
- if (GT_ATTRIBUTES_WITH_SUGAR.includes(attribute) &&
128
- t.isExpression(prop.value)) {
129
- const result = isStaticExpression(prop.value);
130
- if (!result.isStatic) {
131
- output.errors.push(warnNonStaticExpressionSync(config.file, attribute, generate(prop.value).code, `${prop.loc?.start?.line}:${prop.loc?.start?.column}`));
132
- }
133
- if (result.isStatic &&
134
- result.value &&
135
- !config.ignoreAdditionalData) {
136
- const mappedKey = mapAttributeName(attribute);
137
- if (attribute === '$maxChars') {
138
- if ((typeof result.value === 'string' &&
139
- (isNaN(Number(result.value)) ||
140
- !isNumberLiteral(prop.value))) ||
141
- !Number.isInteger(Number(result.value))) {
142
- output.errors.push(warnInvalidMaxCharsSync(config.file, generate(prop).code, `${prop.loc?.start?.line}:${prop.loc?.start?.column}`));
143
- }
144
- else if (typeof result.value === 'string') {
145
- // Add the maxChars value to the metadata
146
- metadata[mappedKey] = Math.abs(Number(result.value));
147
- }
148
- }
149
- else {
150
- // Add the $context or $id or other attributes value to the metadata
151
- metadata[mappedKey] = result.value;
152
- }
153
- }
154
- }
155
- }
156
- });
157
- }
158
- const relativeFilepath = pathModule.relative(process.cwd(), config.file);
159
- if (relativeFilepath) {
160
- if (!metadata.filePaths) {
161
- metadata.filePaths = [relativeFilepath];
162
- }
163
- else if (Array.isArray(metadata.filePaths)) {
164
- if (!metadata.filePaths.includes(relativeFilepath)) {
165
- metadata.filePaths.push(relativeFilepath);
166
- }
167
- }
168
- }
169
- output.updates.push({
170
- dataFormat: 'ICU',
171
- source,
172
- metadata,
173
- });
174
- }
175
- else if (t.isTemplateLiteral(arg)) {
176
- // warn if template literal
177
- if (!config.ignoreDynamicContent) {
178
- output.errors.push(warnTemplateLiteralSync(config.file, generate(arg).code, `${arg.loc?.start?.line}:${arg.loc?.start?.column}`));
179
- }
180
- }
181
- else {
182
- if (!config.ignoreDynamicContent) {
183
- output.errors.push(warnNonStringSync(config.file, generate(arg).code, `${arg.loc?.start?.line}:${arg.loc?.start?.column}`));
184
- }
185
- }
186
- // }
187
- }
188
- }
189
31
  /**
190
32
  * Extracts the parameter name from a function parameter node, handling TypeScript annotations and default values.
191
33
  */
@@ -437,9 +279,10 @@ export function parseStrings(importName, originalName, path, config, output) {
437
279
  const msgConfig = {
438
280
  parsingOptions: config.parsingOptions,
439
281
  file: config.file,
440
- ignoreAdditionalData: false,
282
+ ignoreInlineMetadata: false,
441
283
  ignoreDynamicContent: false,
442
284
  ignoreInvalidIcu: false,
285
+ ignoreInlineListContent: false,
443
286
  };
444
287
  // Check if this is a direct call to msg('string')
445
288
  if (refPath.parent.type === 'CallExpression' &&
@@ -469,12 +312,16 @@ export function parseStrings(importName, originalName, path, config, output) {
469
312
  }
470
313
  const isMessageHook = originalName === INLINE_MESSAGE_HOOK ||
471
314
  originalName === INLINE_MESSAGE_HOOK_ASYNC;
315
+ const isInlineGT = originalName === INLINE_TRANSLATION_HOOK ||
316
+ originalName === INLINE_TRANSLATION_HOOK_ASYNC;
472
317
  const hookConfig = {
473
318
  parsingOptions: config.parsingOptions,
474
319
  file: config.file,
475
- ignoreAdditionalData: isMessageHook,
320
+ ignoreInlineMetadata: isMessageHook,
476
321
  ignoreDynamicContent: isMessageHook,
477
322
  ignoreInvalidIcu: isMessageHook,
323
+ // TODO: when we add support for array content in gt function, this should just always be false
324
+ ignoreInlineListContent: isInlineGT,
478
325
  };
479
326
  const effectiveParent = parentPath?.node.type === 'AwaitExpression'
480
327
  ? parentPath.parentPath
@@ -0,0 +1,29 @@
1
+ import * as t from '@babel/types';
2
+ import { ParsingConfig } from '../types.js';
3
+ import { ParsingOutput } from '../types.js';
4
+ /**
5
+ * Metadata record type
6
+ */
7
+ export type InlineMetadata = {
8
+ maxChars?: number;
9
+ context?: string;
10
+ id?: string;
11
+ hash?: string;
12
+ filePaths?: string[];
13
+ };
14
+ /**
15
+ * Extracts inline metadata from a string entry
16
+ * @param metadata - The metadata record to inject the data into
17
+ * @param entry - The string entry to extract the metadata from
18
+ * @param output - The output to use
19
+ * @param config - The configuration to use
20
+ * @returns The inline metadata
21
+ *
22
+ * @note - this function does not automatically append the index to the id, this must be done manually in the caller.
23
+ *
24
+ */
25
+ export declare function extractStringEntryMetadata({ options, output, config, }: {
26
+ options?: t.CallExpression['arguments'][number];
27
+ output: ParsingOutput;
28
+ config: ParsingConfig;
29
+ }): InlineMetadata;
@@ -0,0 +1,86 @@
1
+ import * as t from '@babel/types';
2
+ import { isStaticExpression } from '../../../evaluateJsx.js';
3
+ import { warnInvalidMaxCharsSync } from '../../../../../console/index.js';
4
+ import { warnNonStaticExpressionSync } from '../../../../../console/index.js';
5
+ import { GT_ATTRIBUTES_WITH_SUGAR } from '../../constants.js';
6
+ import generateModule from '@babel/generator';
7
+ import { mapAttributeName } from '../../mapAttributeName.js';
8
+ import pathModule from 'node:path';
9
+ import { isNumberLiteral } from '../../isNumberLiteral.js';
10
+ // Handle CommonJS/ESM interop
11
+ const generate = generateModule.default || generateModule;
12
+ /**
13
+ * Extracts inline metadata from a string entry
14
+ * @param metadata - The metadata record to inject the data into
15
+ * @param entry - The string entry to extract the metadata from
16
+ * @param output - The output to use
17
+ * @param config - The configuration to use
18
+ * @returns The inline metadata
19
+ *
20
+ * @note - this function does not automatically append the index to the id, this must be done manually in the caller.
21
+ *
22
+ */
23
+ export function extractStringEntryMetadata({ options, output, config, }) {
24
+ // extract filepath for entry
25
+ const relativeFilepath = pathModule.relative(process.cwd(), config.file);
26
+ // extract inline metadata
27
+ const inlineMetadata = extractInlineMetadata({
28
+ options,
29
+ output,
30
+ config,
31
+ });
32
+ return {
33
+ ...inlineMetadata,
34
+ filePaths: relativeFilepath ? [relativeFilepath] : undefined,
35
+ };
36
+ }
37
+ // ----- Helper Functions ----- //
38
+ /**
39
+ * Extracts inline metadata specified e.g. gt('Hello', { $context: 'greeting' })
40
+ * @param options - The options to extract the metadata from
41
+ * @param output - The output to use
42
+ * @param config - The configuration to use
43
+ * @param index - The index of the string entry
44
+ * @returns The inline metadata
45
+ */
46
+ function extractInlineMetadata({ options, output, config, }) {
47
+ const metadata = {};
48
+ if (options && options.type === 'ObjectExpression') {
49
+ options.properties.forEach((prop) => {
50
+ if (prop.type === 'ObjectProperty' && prop.key.type === 'Identifier') {
51
+ const attribute = prop.key.name;
52
+ if (GT_ATTRIBUTES_WITH_SUGAR.includes(attribute) &&
53
+ t.isExpression(prop.value)) {
54
+ const result = isStaticExpression(prop.value);
55
+ if (!result.isStatic) {
56
+ output.errors.push(warnNonStaticExpressionSync(config.file, attribute, generate(prop.value).code, `${prop.loc?.start?.line}:${prop.loc?.start?.column}`));
57
+ }
58
+ if (result.isStatic &&
59
+ result.value != null &&
60
+ !config.ignoreInlineMetadata) {
61
+ const mappedKey = mapAttributeName(attribute);
62
+ if (mappedKey === 'maxChars') {
63
+ // Handle maxChars attribute
64
+ if ((typeof result.value === 'string' &&
65
+ (isNaN(Number(result.value)) ||
66
+ !isNumberLiteral(prop.value))) ||
67
+ !Number.isInteger(Number(result.value))) {
68
+ output.errors.push(warnInvalidMaxCharsSync(config.file, generate(prop).code, `${prop.loc?.start?.line}:${prop.loc?.start?.column}`));
69
+ }
70
+ else if (typeof result.value === 'string') {
71
+ // Add the maxChars value to the metadata
72
+ metadata[mappedKey] = Math.abs(Number(result.value));
73
+ }
74
+ }
75
+ else {
76
+ // Add the $context or $id or other attributes value to the metadata
77
+ // TODO: why are we including everything? arent we only interested in relevant inline metadata?
78
+ metadata[mappedKey] = result.value;
79
+ }
80
+ }
81
+ }
82
+ }
83
+ });
84
+ }
85
+ return metadata;
86
+ }
@@ -0,0 +1,14 @@
1
+ import * as t from '@babel/types';
2
+ import { ParsingConfig, ParsingOutput } from '../types.js';
3
+ /**
4
+ * For the processTranslationCall function, this function handles the case where a other translation call is used.
5
+ * Error is pushed if the other translation call is used.
6
+ * @param arg - The argument to parse
7
+ * @param config - The configuration to use
8
+ * @param output - The output to use
9
+ */
10
+ export declare function handleInvalidTranslationCall({ arg, config, output, }: {
11
+ arg: t.ArgumentPlaceholder | t.SpreadElement | t.Expression;
12
+ config: ParsingConfig;
13
+ output: ParsingOutput;
14
+ }): void;
@@ -0,0 +1,24 @@
1
+ import * as t from '@babel/types';
2
+ import { warnNonStringSync, warnTemplateLiteralSync, } from '../../../../../console/index.js';
3
+ import generateModule from '@babel/generator';
4
+ // Handle CommonJS/ESM interop
5
+ const generate = generateModule.default || generateModule;
6
+ /**
7
+ * For the processTranslationCall function, this function handles the case where a other translation call is used.
8
+ * Error is pushed if the other translation call is used.
9
+ * @param arg - The argument to parse
10
+ * @param config - The configuration to use
11
+ * @param output - The output to use
12
+ */
13
+ export function handleInvalidTranslationCall({ arg, config, output, }) {
14
+ if (config.ignoreDynamicContent)
15
+ return;
16
+ if (t.isTemplateLiteral(arg)) {
17
+ // Specific error for template literals
18
+ output.errors.push(warnTemplateLiteralSync(config.file, generate(arg).code, `${arg.loc?.start?.line}:${arg.loc?.start?.column}`));
19
+ }
20
+ else {
21
+ // Generic error
22
+ output.errors.push(warnNonStringSync(config.file, generate(arg).code, `${arg.loc?.start?.line}:${arg.loc?.start?.column}`));
23
+ }
24
+ }
@@ -0,0 +1,19 @@
1
+ import * as t from '@babel/types';
2
+ import { ParsingConfig } from '../types.js';
3
+ import { ParsingOutput } from '../types.js';
4
+ import { InlineMetadata } from './extractStringEntryMetadata.js';
5
+ /**
6
+ * For the processTranslationCall function, this function handles the case where a string literal or template literal is used.
7
+ * @param arg - The argument to parse
8
+ * @param metadata - The metadata to use
9
+ * @param config - The configuration to use
10
+ * @param output - The output to use
11
+ * @param index - The index of the argument
12
+ */
13
+ export declare function handleLiteralTranslationCall({ arg, metadata, config, output, index, }: {
14
+ arg: t.StringLiteral | t.TemplateLiteral;
15
+ metadata: InlineMetadata;
16
+ config: ParsingConfig;
17
+ output: ParsingOutput;
18
+ index?: number;
19
+ }): void;
@@ -0,0 +1,31 @@
1
+ import { isValidIcu } from '../../../evaluateJsx.js';
2
+ import { warnInvalidIcuSync } from '../../../../../console/index.js';
3
+ /**
4
+ * For the processTranslationCall function, this function handles the case where a string literal or template literal is used.
5
+ * @param arg - The argument to parse
6
+ * @param metadata - The metadata to use
7
+ * @param config - The configuration to use
8
+ * @param output - The output to use
9
+ * @param index - The index of the argument
10
+ */
11
+ export function handleLiteralTranslationCall({ arg, metadata, config, output, index, }) {
12
+ // ignore dynamic content flag is triggered, check strings are valid ICU
13
+ const source = arg.type === 'StringLiteral' ? arg.value : arg.quasis[0].value.raw;
14
+ // Validate is ICU
15
+ if (!config.ignoreInvalidIcu) {
16
+ const { isValid, error } = isValidIcu(source);
17
+ if (!isValid) {
18
+ output.warnings.add(warnInvalidIcuSync(config.file, source, error ?? 'Unknown error', `${arg.loc?.start?.line}:${arg.loc?.start?.column}`));
19
+ return;
20
+ }
21
+ }
22
+ output.updates.push({
23
+ dataFormat: 'ICU',
24
+ source,
25
+ metadata: {
26
+ ...metadata,
27
+ // Add the index if an id and index is provided (for handling when registering an array of strings)
28
+ ...(metadata.id && index != null && { id: `${metadata.id}.${index}` }),
29
+ },
30
+ });
31
+ }
@@ -0,0 +1,22 @@
1
+ import { NodePath } from '@babel/traverse';
2
+ import * as t from '@babel/types';
3
+ import { ParsingConfig } from '../types.js';
4
+ import { ParsingOutput } from '../types.js';
5
+ import { InlineMetadata } from './extractStringEntryMetadata.js';
6
+ /**
7
+ * For the processTranslationCall function, this function handles the case where a string with declareStatic is used.
8
+ * @param arg - The argument to parse
9
+ * @param metadata - The metadata to use
10
+ * @param tPath - The path to the argument
11
+ * @param config - The configuration to use
12
+ * @param output - The output to use
13
+ * @param index - Current index in array of strings being extracted
14
+ */
15
+ export declare function handleStaticTranslationCall({ arg, metadata, tPath, config, output, index, }: {
16
+ arg: t.Expression;
17
+ metadata: InlineMetadata;
18
+ tPath: NodePath;
19
+ config: ParsingConfig;
20
+ output: ParsingOutput;
21
+ index?: number;
22
+ }): void;
@@ -0,0 +1,51 @@
1
+ import { handleStaticExpression } from '../../parseDeclareStatic.js';
2
+ import { nodeToStrings } from '../../parseString.js';
3
+ import { indexVars } from 'generaltranslation/internal';
4
+ import { isValidIcu } from '../../../evaluateJsx.js';
5
+ import { warnInvalidIcuSync, warnNonStringSync, } from '../../../../../console/index.js';
6
+ import generateModule from '@babel/generator';
7
+ import { randomUUID } from 'node:crypto';
8
+ // Handle CommonJS/ESM interop
9
+ const generate = generateModule.default || generateModule;
10
+ /**
11
+ * For the processTranslationCall function, this function handles the case where a string with declareStatic is used.
12
+ * @param arg - The argument to parse
13
+ * @param metadata - The metadata to use
14
+ * @param tPath - The path to the argument
15
+ * @param config - The configuration to use
16
+ * @param output - The output to use
17
+ * @param index - Current index in array of strings being extracted
18
+ */
19
+ export function handleStaticTranslationCall({ arg, metadata, tPath, config, output, index, }) {
20
+ // parse static expression
21
+ const result = handleStaticExpression(arg, tPath, config.file, config.parsingOptions, output.errors);
22
+ // Nothing returned, push error
23
+ if (!result) {
24
+ output.errors.push(warnNonStringSync(config.file, generate(arg).code, `${arg.loc?.start?.line}:${arg.loc?.start?.column}`));
25
+ return;
26
+ }
27
+ // validate ICU
28
+ const strings = nodeToStrings(result).map(indexVars);
29
+ if (!config.ignoreInvalidIcu) {
30
+ for (const string of strings) {
31
+ const { isValid, error } = isValidIcu(string);
32
+ if (!isValid) {
33
+ output.warnings.add(warnInvalidIcuSync(config.file, string, error ?? 'Unknown error', `${arg.loc?.start?.line}:${arg.loc?.start?.column}`));
34
+ return;
35
+ }
36
+ }
37
+ }
38
+ const temporaryStaticId = `static-temp-id-${randomUUID()}`;
39
+ for (const string of strings) {
40
+ output.updates.push({
41
+ dataFormat: 'ICU',
42
+ source: string,
43
+ metadata: {
44
+ ...metadata,
45
+ // Add the index if an id and index is provided (for handling when registering an array of strings)
46
+ ...(metadata.id && index != null && { id: `${metadata.id}.${index}` }),
47
+ staticId: temporaryStaticId,
48
+ },
49
+ });
50
+ }
51
+ }
@@ -0,0 +1,18 @@
1
+ import { NodePath } from '@babel/traverse';
2
+ import { ParsingConfig } from '../types.js';
3
+ import { ParsingOutput } from '../types.js';
4
+ /**
5
+ * Processes a single translation function call (e.g., t('hello world', { id: 'greeting' })).
6
+ * Extracts the translatable string content and metadata, then adds it to the updates array.
7
+ *
8
+ * Handles:
9
+ * - String literals: t('hello')
10
+ * - Template literals without expressions: t(`hello`)
11
+ * - Metadata extraction from options object
12
+ * - Error reporting for non-static expressions and template literals with expressions
13
+ *
14
+ * @param tPath - The path to the translation call
15
+ * @param config - The configuration to use
16
+ * @param output - The output to use
17
+ */
18
+ export declare function processTranslationCall(tPath: NodePath, config: ParsingConfig, output: ParsingOutput): void;
@@ -0,0 +1,39 @@
1
+ import { routeTranslationCall } from './routeTranslationCall.js';
2
+ import { extractStringEntryMetadata } from './extractStringEntryMetadata.js';
3
+ /**
4
+ * Processes a single translation function call (e.g., t('hello world', { id: 'greeting' })).
5
+ * Extracts the translatable string content and metadata, then adds it to the updates array.
6
+ *
7
+ * Handles:
8
+ * - String literals: t('hello')
9
+ * - Template literals without expressions: t(`hello`)
10
+ * - Metadata extraction from options object
11
+ * - Error reporting for non-static expressions and template literals with expressions
12
+ *
13
+ * @param tPath - The path to the translation call
14
+ * @param config - The configuration to use
15
+ * @param output - The output to use
16
+ */
17
+ export function processTranslationCall(tPath, config, output) {
18
+ if (tPath.parent.type !== 'CallExpression' ||
19
+ tPath.parent.arguments.length === 0) {
20
+ return;
21
+ }
22
+ // Get arg and options
23
+ const arg = tPath.parent.arguments[0];
24
+ const options = tPath.parent.arguments.at(1);
25
+ // get metadata and id from options
26
+ const metadata = extractStringEntryMetadata({
27
+ options,
28
+ output,
29
+ config,
30
+ });
31
+ // Route tx call to appropriate handler
32
+ routeTranslationCall({
33
+ tPath,
34
+ config,
35
+ output,
36
+ arg,
37
+ metadata,
38
+ });
39
+ }
@@ -0,0 +1,24 @@
1
+ import * as t from '@babel/types';
2
+ import { ParsingConfig } from '../types.js';
3
+ import { ParsingOutput } from '../types.js';
4
+ import { NodePath } from '@babel/traverse';
5
+ import { InlineMetadata } from './extractStringEntryMetadata.js';
6
+ /**
7
+ * Helper function for processTranslationCall
8
+ * Given arg and options, maps to appropriate translation call handler
9
+ * @param tPath - The path to the translation call
10
+ * @param config - The configuration to use
11
+ * @param output - The output to use
12
+ * @param arg - The argument to parse
13
+ * @param metadata - The metadata to use
14
+ * @param index - The index of the argument
15
+ * @returns void
16
+ */
17
+ export declare function routeTranslationCall({ tPath, config, output, arg, metadata, index, }: {
18
+ tPath: NodePath;
19
+ config: ParsingConfig;
20
+ output: ParsingOutput;
21
+ arg: t.CallExpression['arguments'][number];
22
+ metadata: InlineMetadata;
23
+ index?: number;
24
+ }): void;
@@ -0,0 +1,68 @@
1
+ import { isStaticExpression } from '../../../evaluateJsx.js';
2
+ import { handleStaticTranslationCall } from './handleStaticTranslationCall.js';
3
+ import { handleLiteralTranslationCall } from './handleLiteralTranslationCall.js';
4
+ import { handleInvalidTranslationCall } from './handleInvalidTranslationCall.js';
5
+ import * as t from '@babel/types';
6
+ /**
7
+ * Helper function for processTranslationCall
8
+ * Given arg and options, maps to appropriate translation call handler
9
+ * @param tPath - The path to the translation call
10
+ * @param config - The configuration to use
11
+ * @param output - The output to use
12
+ * @param arg - The argument to parse
13
+ * @param metadata - The metadata to use
14
+ * @param index - The index of the argument
15
+ * @returns void
16
+ */
17
+ export function routeTranslationCall({ tPath, config, output, arg, metadata, index, }) {
18
+ if (t.isArrayExpression(arg) &&
19
+ index == null &&
20
+ !config.ignoreInlineListContent) {
21
+ // handle array translation call
22
+ for (let i = 0; i < arg.elements.length; i++) {
23
+ const element = arg.elements[i];
24
+ if (element == null)
25
+ continue;
26
+ routeTranslationCall({
27
+ tPath,
28
+ config,
29
+ output,
30
+ arg: element,
31
+ index: i,
32
+ metadata,
33
+ });
34
+ }
35
+ }
36
+ else if (!config.ignoreDynamicContent &&
37
+ t.isExpression(arg) &&
38
+ !isStaticExpression(arg).isStatic) {
39
+ // handle static translation call
40
+ handleStaticTranslationCall({
41
+ arg,
42
+ metadata,
43
+ tPath,
44
+ config,
45
+ output,
46
+ index,
47
+ });
48
+ }
49
+ else if (arg.type === 'StringLiteral' ||
50
+ (t.isTemplateLiteral(arg) && arg.expressions.length === 0)) {
51
+ // Handle string and template literals
52
+ handleLiteralTranslationCall({
53
+ arg,
54
+ metadata,
55
+ config,
56
+ output,
57
+ index,
58
+ });
59
+ }
60
+ else {
61
+ // error on invalid translation call
62
+ handleInvalidTranslationCall({
63
+ arg,
64
+ config,
65
+ output,
66
+ });
67
+ }
68
+ }
@@ -0,0 +1,41 @@
1
+ import { ParsingConfigOptions } from '../../../../types/parsing.js';
2
+ import { Updates } from '../../../../types/index.js';
3
+ /**
4
+ * Immutable configuration options for string parsing.
5
+ */
6
+ export type ParsingConfig = {
7
+ parsingOptions: ParsingConfigOptions;
8
+ file: string;
9
+ /**
10
+ * If true, ignores fields like $context, $id, etc. when extracting metadata from a string entry
11
+ */
12
+ ignoreInlineMetadata: boolean;
13
+ /**
14
+ * If true, dynamic content will not be treated as errors
15
+ */
16
+ ignoreDynamicContent: boolean;
17
+ /**
18
+ * If true, invalid ICU strings will not be treated as errors
19
+ */
20
+ ignoreInvalidIcu: boolean;
21
+ /**
22
+ * If true, will ignore registration of list content
23
+ * eg msg(['hello', 'world', 'foo', 'bar']) will not be registered
24
+ */
25
+ ignoreInlineListContent: boolean;
26
+ };
27
+ /**
28
+ * Mutable state for tracking parsing progress.
29
+ */
30
+ export type ParsingState = {
31
+ visited: Set<string>;
32
+ importMap: Map<string, string>;
33
+ };
34
+ /**
35
+ * Collectors for updates, errors, and warnings.
36
+ */
37
+ export type ParsingOutput = {
38
+ updates: Updates;
39
+ errors: string[];
40
+ warnings: Set<string>;
41
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -35,9 +35,10 @@ export async function createInlineUpdates(pkg, validate, filePatterns, parsingOp
35
35
  parseStrings(name, originalName, path, {
36
36
  parsingOptions,
37
37
  file,
38
- ignoreAdditionalData: false,
38
+ ignoreInlineMetadata: false,
39
39
  ignoreDynamicContent: false,
40
40
  ignoreInvalidIcu: false,
41
+ ignoreInlineListContent: false,
41
42
  }, { updates, errors, warnings });
42
43
  }
43
44
  // Parse <T> components
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gtx-cli",
3
- "version": "2.6.26",
3
+ "version": "2.6.27",
4
4
  "main": "dist/index.js",
5
5
  "bin": "dist/main.js",
6
6
  "files": [