gt 2.10.5 → 2.10.6
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 +10 -0
- package/dist/console/index.d.ts +3 -3
- package/dist/console/index.js +10 -10
- package/dist/console/logging.d.ts +0 -1
- package/dist/console/logging.js +0 -4
- package/dist/extraction/index.d.ts +1 -1
- package/dist/extraction/index.js +1 -1
- package/dist/extraction/postProcess.d.ts +3 -3
- package/dist/extraction/postProcess.js +9 -9
- package/dist/generated/version.d.ts +1 -1
- package/dist/generated/version.js +1 -1
- package/dist/python/parse/createPythonInlineUpdates.js +2 -2
- package/dist/react/jsx/evaluateJsx.d.ts +10 -0
- package/dist/react/jsx/evaluateJsx.js +15 -5
- package/dist/react/jsx/utils/constants.d.ts +8 -0
- package/dist/react/jsx/utils/constants.js +11 -0
- package/dist/react/jsx/utils/jsxParsing/handleChildrenWhitespace.js +1 -1
- package/dist/react/jsx/utils/jsxParsing/multiplication/multiplyJsxTree.d.ts +1 -1
- package/dist/react/jsx/utils/jsxParsing/multiplication/multiplyJsxTree.js +1 -1
- package/dist/react/jsx/utils/jsxParsing/parseJsx.js +42 -42
- package/dist/react/jsx/utils/jsxParsing/parseTProps.js +3 -3
- package/dist/react/jsx/utils/{parseDeclareStatic.d.ts → parseDerive.d.ts} +2 -2
- package/dist/react/jsx/utils/{parseDeclareStatic.js → parseDerive.js} +29 -50
- package/dist/react/jsx/utils/parseString.js +2 -2
- package/dist/react/jsx/utils/stringParsing/processTranslationCall/{handleStaticTranslationCall.d.ts → handleDeriveTranslationCall.d.ts} +2 -2
- package/dist/react/jsx/utils/stringParsing/processTranslationCall/{handleStaticTranslationCall.js → handleDeriveTranslationCall.js} +7 -7
- package/dist/react/jsx/utils/stringParsing/processTranslationCall/index.d.ts +1 -1
- package/dist/react/jsx/utils/stringParsing/processTranslationCall/index.js +1 -1
- package/dist/react/jsx/utils/stringParsing/processTranslationCall/routeTranslationCall.js +3 -3
- package/dist/react/jsx/wrapJsx.js +3 -3
- package/dist/react/parse/createInlineUpdates.js +2 -2
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# gtx-cli
|
|
2
2
|
|
|
3
|
+
## 2.10.6
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#1062](https://github.com/generaltranslation/gt/pull/1062) [`2274e23`](https://github.com/generaltranslation/gt/commit/2274e23d448c8a96d661d30e5c7fc737814c1fb0) Thanks [@ErnestM1234](https://github.com/ErnestM1234)! - refactor: rename static to derive, and deprecate static
|
|
8
|
+
|
|
9
|
+
- Updated dependencies [[`2274e23`](https://github.com/generaltranslation/gt/commit/2274e23d448c8a96d661d30e5c7fc737814c1fb0)]:
|
|
10
|
+
- generaltranslation@8.1.17
|
|
11
|
+
- @generaltranslation/python-extractor@0.1.3
|
|
12
|
+
|
|
3
13
|
## 2.10.5
|
|
4
14
|
|
|
5
15
|
### Patch Changes
|
package/dist/console/index.d.ts
CHANGED
|
@@ -17,11 +17,11 @@ export declare const withLocation: (file: string, message: string, location?: st
|
|
|
17
17
|
export declare const warnFunctionNotFoundSync: (file: string, functionName: string, location?: string) => string;
|
|
18
18
|
export declare const warnInvalidDeclareVarNameSync: (file: string, value: string, location?: string) => string;
|
|
19
19
|
export declare const warnDuplicateFunctionDefinitionSync: (file: string, functionName: string, location?: string) => string;
|
|
20
|
-
export declare const
|
|
20
|
+
export declare const warnInvalidDeriveInitSync: (file: string, functionName: string, location?: string) => string;
|
|
21
21
|
export declare const warnDataAttrOnBranch: (file: string, attrName: string, location?: string) => string;
|
|
22
22
|
export declare const warnRecursiveFunctionCallSync: (file: string, functionName: string, location?: string) => string;
|
|
23
|
-
export declare const
|
|
24
|
-
export declare const
|
|
23
|
+
export declare const warnDeriveFunctionNotWrappedSync: (file: string, functionName: string, location?: string) => string;
|
|
24
|
+
export declare const warnDeriveFunctionNoResultsSync: (file: string, functionName: string, location?: string) => string;
|
|
25
25
|
export declare const noLocalesError = "No locales found! Provide a list of locales for translation, or specify them in your gt.config.json file.";
|
|
26
26
|
export declare const noDefaultLocaleError = "No default locale found! Provide a default locale, or specify it in your gt.config.json file.";
|
|
27
27
|
export declare const noFilesError = "Incorrect or missing files configuration! Make sure your files are configured correctly in your gt.config.json file.";
|
package/dist/console/index.js
CHANGED
|
@@ -2,15 +2,15 @@ import { BRANCH_COMPONENT } from '../react/jsx/utils/constants.js';
|
|
|
2
2
|
import { colorizeFilepath, colorizeComponent, colorizeIdString, colorizeContent, colorizeLine, colorizeFunctionName, } from './colors.js';
|
|
3
3
|
import { formatCodeClamp } from './formatting.js';
|
|
4
4
|
const withWillErrorInNextVersion = (message) => `${message} (This will become an error in the next major version of the CLI.)`;
|
|
5
|
-
//
|
|
6
|
-
const
|
|
7
|
-
const
|
|
5
|
+
// Derive function related errors
|
|
6
|
+
const withDeriveComponentError = (message) => `<Derive> rules violation: ${message}`;
|
|
7
|
+
const withDeriveFunctionError = (message) => `derive() rules violation: ${message}`;
|
|
8
8
|
// Synchronous wrappers for backward compatibility
|
|
9
9
|
export const warnApiKeyInConfigSync = (optionsFilepath) => `${colorizeFilepath(optionsFilepath)}: Your API key is exposed! Remove it from the file and include it as an environment variable.`;
|
|
10
10
|
export const warnVariablePropSync = (file, attrName, value, location) => withLocation(file, `${colorizeComponent('<T>')} component has dynamic attribute ${colorizeIdString(attrName)} with value: ${colorizeContent(value)}. Change ${colorizeIdString(attrName)} to ensure this content is translated.`, location);
|
|
11
|
-
export const warnInvalidReturnSync = (file, functionName, expression, location) => withLocation(file,
|
|
11
|
+
export const warnInvalidReturnSync = (file, functionName, expression, location) => withLocation(file, withDeriveComponentError(`Function ${colorizeFunctionName(functionName)} does not return a derivable (statically analyzable) expression. ${colorizeFunctionName(functionName)} must return either (1) a derivable string literal, (2) another derivable function invocation, (3) derivable JSX content, or (4) a ternary expression. Instead got:\n${colorizeContent(expression)}`), location);
|
|
12
12
|
// TODO: this is temporary until we handle implicit returns
|
|
13
|
-
export const warnMissingReturnSync = (file, functionName, location) => withLocation(file, `Function ${colorizeFunctionName(functionName)} is wrapped in ${colorizeComponent('<Static>')} tags but does have an explicit return statement.
|
|
13
|
+
export const warnMissingReturnSync = (file, functionName, location) => withLocation(file, `Function ${colorizeFunctionName(functionName)} is wrapped in ${colorizeComponent('<Derive>')} (formerly ${colorizeComponent('<Static>')}) tags but does not have an explicit return statement. Derivable functions must have an explicit return statement.`, location);
|
|
14
14
|
export const warnHasUnwrappedExpressionSync = (file, unwrappedExpressions, id, location) => withLocation(file, `${colorizeComponent('<T>')} component${id ? ` with id ${colorizeIdString(id)}` : ''} has children that could change at runtime. Use a variable component like ${colorizeComponent('<Var>')} to ensure this content is translated.\n${colorizeContent(unwrappedExpressions.join('\n'))}`, location);
|
|
15
15
|
export const warnFailedToConstructJsxTreeSync = (file, code, location) => withLocation(file, `Failed to construct JsxTree! Call expression is not a valid createElement call: ${colorizeContent(code)}`, location);
|
|
16
16
|
export const warnNestedTComponent = (file, location) => withLocation(file, `Found nested <T> component. <T> components cannot be directly nested.`, location);
|
|
@@ -24,15 +24,15 @@ export const warnSyncGetGT = (file, location) => withLocation(file, `Found getGT
|
|
|
24
24
|
export const warnTernarySync = (file, location) => withLocation(file, 'Found ternary expression. A Branch component may be more appropriate here.', location);
|
|
25
25
|
export const withLocation = (file, message, location) => `${colorizeFilepath(file)}${location ? ` (${colorizeLine(location)})` : ''}: ${message}`;
|
|
26
26
|
export const warnFunctionNotFoundSync = (file, functionName, location) => withLocation(file, `Function ${colorizeFunctionName(functionName)} definition could not be resolved. This might affect translation resolution for this ${colorizeComponent('<T>')} component.`, location);
|
|
27
|
-
export const warnInvalidDeclareVarNameSync = (file, value, location) => withLocation(file, `Found invalid declareVar() $name tag. Must be a
|
|
27
|
+
export const warnInvalidDeclareVarNameSync = (file, value, location) => withLocation(file, `Found invalid declareVar() $name tag. Must be a derivable (statically analyzable) expression. Received: ${colorizeContent(value)}.`, location);
|
|
28
28
|
export const warnDuplicateFunctionDefinitionSync = (file, functionName, location) => withLocation(file, `Function ${colorizeFunctionName(functionName)} is defined multiple times. Only the first definition will be used.`, location);
|
|
29
|
-
export const
|
|
29
|
+
export const warnInvalidDeriveInitSync = (file, functionName, location) => withLocation(file, withDeriveComponentError(`The definition for ${colorizeFunctionName(functionName)} could not be resolved. When using arrow syntax to define a derivable (statically analyzable) function, the right hand side or the assignment MUST only contain the arrow function itself and no other expressions.
|
|
30
30
|
Example: ${colorizeContent(`const ${colorizeFunctionName(functionName)} = () => { ... }`)}
|
|
31
31
|
Invalid: ${colorizeContent(`const ${colorizeFunctionName(functionName)} = [() => { ... }][0]`)}`), location);
|
|
32
32
|
export const warnDataAttrOnBranch = (file, attrName, location) => withLocation(file, `${colorizeComponent(`<${BRANCH_COMPONENT}>`)} component ignores attributes prefixed with ${colorizeIdString('"data-"')}. Found ${colorizeIdString(attrName)}. Remove it or use a different attribute name.`, location);
|
|
33
|
-
export const warnRecursiveFunctionCallSync = (file, functionName, location) => withLocation(file,
|
|
34
|
-
export const
|
|
35
|
-
export const
|
|
33
|
+
export const warnRecursiveFunctionCallSync = (file, functionName, location) => withLocation(file, withDeriveComponentError(`Recursive function call detected: ${colorizeFunctionName(functionName)}. A derivable (statically analyzable) function cannot use recursive calls to construct its result.`), location);
|
|
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
|
+
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);
|
|
36
36
|
// Re-export error messages
|
|
37
37
|
export const noLocalesError = `No locales found! Provide a list of locales for translation, or specify them in your gt.config.json file.`;
|
|
38
38
|
export const noDefaultLocaleError = `No default locale found! Provide a default locale, or specify it in your gt.config.json file.`;
|
|
@@ -43,7 +43,6 @@ export declare function warnApiKeyInConfig(optionsFilepath: string): void;
|
|
|
43
43
|
export declare function warnVariableProp(file: string, attrName: string, value: string): void;
|
|
44
44
|
export declare function warnNoId(file: string): void;
|
|
45
45
|
export declare function warnHasUnwrappedExpression(file: string, id: string, unwrappedExpressions: string[]): void;
|
|
46
|
-
export declare function warnNonStaticExpression(file: string, attrName: string, value: string): void;
|
|
47
46
|
export declare function warnTemplateLiteral(file: string, value: string): void;
|
|
48
47
|
export declare function warnTernary(file: string): void;
|
|
49
48
|
/**
|
package/dist/console/logging.js
CHANGED
|
@@ -146,10 +146,6 @@ export function warnHasUnwrappedExpression(file, id, unwrappedExpressions) {
|
|
|
146
146
|
chalk.blue('https://generaltranslation.com/docs') +
|
|
147
147
|
chalk.white(') to translate this properly.'));
|
|
148
148
|
}
|
|
149
|
-
export function warnNonStaticExpression(file, attrName, value) {
|
|
150
|
-
logger.warn(`Found non-static expression in ${chalk.cyan(file)} for attribute ${attrName}: "${chalk.white(value)}". ` +
|
|
151
|
-
`Change "${attrName}" to ensure this content is translated.`);
|
|
152
|
-
}
|
|
153
149
|
export function warnTemplateLiteral(file, value) {
|
|
154
150
|
logger.warn(`Found template literal with quasis (${value}) in ${chalk.cyan(file)}. ` +
|
|
155
151
|
chalk.white('Change the template literal to a string to ensure this content is translated.'));
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export type { ExtractionResult, ExtractionMetadata } from './types.js';
|
|
2
2
|
export { mapExtractionResultsToUpdates } from './mapToUpdates.js';
|
|
3
|
-
export { calculateHashes, dedupeUpdates,
|
|
3
|
+
export { calculateHashes, dedupeUpdates, linkDeriveUpdates, } from './postProcess.js';
|
package/dist/extraction/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { mapExtractionResultsToUpdates } from './mapToUpdates.js';
|
|
2
|
-
export { calculateHashes, dedupeUpdates,
|
|
2
|
+
export { calculateHashes, dedupeUpdates, linkDeriveUpdates, } from './postProcess.js';
|
|
@@ -8,7 +8,7 @@ export declare function calculateHashes(updates: Updates): Promise<void>;
|
|
|
8
8
|
*/
|
|
9
9
|
export declare function dedupeUpdates(updates: Updates): void;
|
|
10
10
|
/**
|
|
11
|
-
* Mark
|
|
12
|
-
* Id is calculated as the hash of the
|
|
11
|
+
* Mark derive updates as related by attaching a shared id to derive content.
|
|
12
|
+
* Id is calculated as the hash of the derive children's combined hashes.
|
|
13
13
|
*/
|
|
14
|
-
export declare function
|
|
14
|
+
export declare function linkDeriveUpdates(updates: Updates): void;
|
|
@@ -66,11 +66,11 @@ export function dedupeUpdates(updates) {
|
|
|
66
66
|
updates.splice(0, updates.length, ...mergedUpdates);
|
|
67
67
|
}
|
|
68
68
|
/**
|
|
69
|
-
* Mark
|
|
70
|
-
* Id is calculated as the hash of the
|
|
69
|
+
* Mark derive updates as related by attaching a shared id to derive content.
|
|
70
|
+
* Id is calculated as the hash of the derive children's combined hashes.
|
|
71
71
|
*/
|
|
72
|
-
export function
|
|
73
|
-
const
|
|
72
|
+
export function linkDeriveUpdates(updates) {
|
|
73
|
+
const temporaryDeriveIdToUpdates = updates.reduce((acc, update) => {
|
|
74
74
|
if (update.metadata.staticId) {
|
|
75
75
|
if (!acc[update.metadata.staticId]) {
|
|
76
76
|
acc[update.metadata.staticId] = [];
|
|
@@ -79,14 +79,14 @@ export function linkStaticUpdates(updates) {
|
|
|
79
79
|
}
|
|
80
80
|
return acc;
|
|
81
81
|
}, {});
|
|
82
|
-
Object.values(
|
|
83
|
-
const hashes =
|
|
82
|
+
Object.values(temporaryDeriveIdToUpdates).forEach((deriveUpdates) => {
|
|
83
|
+
const hashes = deriveUpdates
|
|
84
84
|
.map((update) => update.metadata.hash)
|
|
85
85
|
.sort()
|
|
86
86
|
.join('-');
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
update.metadata.staticId =
|
|
87
|
+
const sharedDeriveId = hashString(hashes);
|
|
88
|
+
deriveUpdates.forEach((update) => {
|
|
89
|
+
update.metadata.staticId = sharedDeriveId;
|
|
90
90
|
});
|
|
91
91
|
});
|
|
92
92
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const PACKAGE_VERSION = "2.10.
|
|
1
|
+
export declare const PACKAGE_VERSION = "2.10.6";
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// This file is auto-generated. Do not edit manually.
|
|
2
|
-
export const PACKAGE_VERSION = '2.10.
|
|
2
|
+
export const PACKAGE_VERSION = '2.10.6';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import { extractFromPythonSource } from '@generaltranslation/python-extractor';
|
|
3
3
|
import { mapExtractionResultsToUpdates } from '../../extraction/mapToUpdates.js';
|
|
4
|
-
import { calculateHashes, dedupeUpdates,
|
|
4
|
+
import { calculateHashes, dedupeUpdates, linkDeriveUpdates, } from '../../extraction/postProcess.js';
|
|
5
5
|
import { matchFiles } from '../../fs/matchFiles.js';
|
|
6
6
|
import { DEFAULT_PYTHON_SRC_PATTERNS, DEFAULT_PYTHON_SRC_EXCLUDES, } from '../../config/generateSettings.js';
|
|
7
7
|
export async function createPythonInlineUpdates(filePatterns) {
|
|
@@ -29,6 +29,6 @@ export async function createPythonInlineUpdates(filePatterns) {
|
|
|
29
29
|
// Post processing steps
|
|
30
30
|
await calculateHashes(updates);
|
|
31
31
|
dedupeUpdates(updates);
|
|
32
|
-
|
|
32
|
+
linkDeriveUpdates(updates);
|
|
33
33
|
return { updates, errors, warnings };
|
|
34
34
|
}
|
|
@@ -17,7 +17,17 @@ export declare function isStaticExpression(expr: t.Expression | t.JSXEmptyExpres
|
|
|
17
17
|
isStatic: boolean;
|
|
18
18
|
value?: string | boolean | null;
|
|
19
19
|
};
|
|
20
|
+
/**
|
|
21
|
+
* Checks if an expression is a static value (a string, number, or template literal).
|
|
22
|
+
* @param expr - The expression to check
|
|
23
|
+
* @returns Whether the expression is a static value
|
|
24
|
+
*/
|
|
20
25
|
export declare function isStaticValue(expr: t.Expression | t.JSXEmptyExpression): boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Checks if a string is a valid ICU message format.
|
|
28
|
+
* @param string - The string to check
|
|
29
|
+
* @returns Whether the string is a valid ICU message format
|
|
30
|
+
*/
|
|
21
31
|
export declare function isValidIcu(string: string): {
|
|
22
32
|
isValid: boolean;
|
|
23
33
|
error?: string;
|
|
@@ -28,9 +28,9 @@ export function isMeaningful(node) {
|
|
|
28
28
|
return false;
|
|
29
29
|
}
|
|
30
30
|
/**
|
|
31
|
-
* Checks if an expression is static (does not contain any variables which could change at runtime).
|
|
31
|
+
* Checks if an expression is a static expression (does not contain any variables which could change at runtime).
|
|
32
32
|
* @param expr - The expression to check
|
|
33
|
-
* @param
|
|
33
|
+
* @param jsxStatic - Whether to return JSX-compatible values (boolean, null) in addition to strings
|
|
34
34
|
* @returns An object containing the result of the static check
|
|
35
35
|
*/
|
|
36
36
|
export function isStaticExpression(expr, jsxStatic = false) {
|
|
@@ -49,9 +49,9 @@ export function isStaticExpression(expr, jsxStatic = false) {
|
|
|
49
49
|
value: jsxStatic ? expr.quasis[0].value.cooked : expr.quasis[0].value.raw,
|
|
50
50
|
};
|
|
51
51
|
}
|
|
52
|
-
// Binary expressions are not
|
|
52
|
+
// Binary expressions are not derivable
|
|
53
53
|
if (t.isBinaryExpression(expr)) {
|
|
54
|
-
// Not a
|
|
54
|
+
// Not a derivable expression
|
|
55
55
|
return { isStatic: false };
|
|
56
56
|
}
|
|
57
57
|
// Handle parenthesized expressions
|
|
@@ -94,9 +94,14 @@ export function isStaticExpression(expr, jsxStatic = false) {
|
|
|
94
94
|
if (t.isNullLiteral(expr)) {
|
|
95
95
|
return { isStatic: true, value: jsxStatic ? null : 'null' };
|
|
96
96
|
}
|
|
97
|
-
// Not a
|
|
97
|
+
// Not a derivable expression
|
|
98
98
|
return { isStatic: false };
|
|
99
99
|
}
|
|
100
|
+
/**
|
|
101
|
+
* Checks if an expression is a static value (a string, number, or template literal).
|
|
102
|
+
* @param expr - The expression to check
|
|
103
|
+
* @returns Whether the expression is a static value
|
|
104
|
+
*/
|
|
100
105
|
export function isStaticValue(expr) {
|
|
101
106
|
if (t.isStringLiteral(expr)) {
|
|
102
107
|
return true;
|
|
@@ -109,6 +114,11 @@ export function isStaticValue(expr) {
|
|
|
109
114
|
}
|
|
110
115
|
return false;
|
|
111
116
|
}
|
|
117
|
+
/**
|
|
118
|
+
* Checks if a string is a valid ICU message format.
|
|
119
|
+
* @param string - The string to check
|
|
120
|
+
* @returns Whether the string is a valid ICU message format
|
|
121
|
+
*/
|
|
112
122
|
export function isValidIcu(string) {
|
|
113
123
|
try {
|
|
114
124
|
parse(string);
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
export declare const DECLARE_VAR_FUNCTION = "declareVar";
|
|
2
|
+
/**
|
|
3
|
+
* COMPAT: Legacy support for declareStatic function.
|
|
4
|
+
*/
|
|
2
5
|
export declare const DECLARE_STATIC_FUNCTION = "declareStatic";
|
|
6
|
+
export declare const DERIVE_FUNCTION = "derive";
|
|
3
7
|
export declare const MSG_REGISTRATION_FUNCTION = "msg";
|
|
4
8
|
export declare const T_REGISTRATION_FUNCTION = "t";
|
|
5
9
|
export declare const INLINE_TRANSLATION_HOOK = "useGT";
|
|
@@ -7,7 +11,11 @@ export declare const INLINE_TRANSLATION_HOOK_ASYNC = "getGT";
|
|
|
7
11
|
export declare const INLINE_MESSAGE_HOOK = "useMessages";
|
|
8
12
|
export declare const INLINE_MESSAGE_HOOK_ASYNC = "getMessages";
|
|
9
13
|
export declare const TRANSLATION_COMPONENT = "T";
|
|
14
|
+
/**
|
|
15
|
+
* COMPAT: Legacy support for Static component.
|
|
16
|
+
*/
|
|
10
17
|
export declare const STATIC_COMPONENT = "Static";
|
|
18
|
+
export declare const DERIVE_COMPONENT = "Derive";
|
|
11
19
|
export declare const BRANCH_COMPONENT = "Branch";
|
|
12
20
|
export declare const GT_TRANSLATION_FUNCS: string[];
|
|
13
21
|
export declare const STRING_REGISTRATION_FUNCS: readonly ["msg", "t"];
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
export const DECLARE_VAR_FUNCTION = 'declareVar';
|
|
2
|
+
/**
|
|
3
|
+
* COMPAT: Legacy support for declareStatic function.
|
|
4
|
+
*/
|
|
2
5
|
export const DECLARE_STATIC_FUNCTION = 'declareStatic';
|
|
6
|
+
export const DERIVE_FUNCTION = 'derive';
|
|
3
7
|
export const MSG_REGISTRATION_FUNCTION = 'msg';
|
|
4
8
|
export const T_REGISTRATION_FUNCTION = 't';
|
|
5
9
|
export const INLINE_TRANSLATION_HOOK = 'useGT';
|
|
@@ -7,7 +11,11 @@ export const INLINE_TRANSLATION_HOOK_ASYNC = 'getGT';
|
|
|
7
11
|
export const INLINE_MESSAGE_HOOK = 'useMessages';
|
|
8
12
|
export const INLINE_MESSAGE_HOOK_ASYNC = 'getMessages';
|
|
9
13
|
export const TRANSLATION_COMPONENT = 'T';
|
|
14
|
+
/**
|
|
15
|
+
* COMPAT: Legacy support for Static component.
|
|
16
|
+
*/
|
|
10
17
|
export const STATIC_COMPONENT = 'Static';
|
|
18
|
+
export const DERIVE_COMPONENT = 'Derive';
|
|
11
19
|
export const BRANCH_COMPONENT = 'Branch';
|
|
12
20
|
// GT translation functions
|
|
13
21
|
export const GT_TRANSLATION_FUNCS = [
|
|
@@ -19,8 +27,10 @@ export const GT_TRANSLATION_FUNCS = [
|
|
|
19
27
|
T_REGISTRATION_FUNCTION,
|
|
20
28
|
DECLARE_VAR_FUNCTION,
|
|
21
29
|
DECLARE_STATIC_FUNCTION,
|
|
30
|
+
DERIVE_FUNCTION,
|
|
22
31
|
TRANSLATION_COMPONENT,
|
|
23
32
|
STATIC_COMPONENT,
|
|
33
|
+
DERIVE_COMPONENT,
|
|
24
34
|
'Var',
|
|
25
35
|
'DateTime',
|
|
26
36
|
'Currency',
|
|
@@ -40,6 +50,7 @@ export const VARIABLE_COMPONENTS = [
|
|
|
40
50
|
'Currency',
|
|
41
51
|
'Num',
|
|
42
52
|
STATIC_COMPONENT,
|
|
53
|
+
DERIVE_COMPONENT,
|
|
43
54
|
];
|
|
44
55
|
export const GT_ATTRIBUTES_WITH_SUGAR = [
|
|
45
56
|
'$id',
|
|
@@ -67,7 +67,7 @@ export function trimJsxStringChild(child) {
|
|
|
67
67
|
* @param currentTree - The current tree to handle
|
|
68
68
|
* @returns The processed tree with whitespace handled
|
|
69
69
|
*
|
|
70
|
-
* For unresolved functions, we just make it so that
|
|
70
|
+
* For unresolved functions, we just make it so that Derive has no children
|
|
71
71
|
*
|
|
72
72
|
* The typing was so much worse before this. Don't come for me. All I did was enforce the typing.
|
|
73
73
|
*/
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { MultipliedTreeNode, WhitespaceJsxTreeResult } from '../types.js';
|
|
2
2
|
/**
|
|
3
|
-
* Given a JSX tree, multiply the
|
|
3
|
+
* Given a JSX tree, multiply the derived function nodes
|
|
4
4
|
*/
|
|
5
5
|
export declare function multiplyJsxTree(tree: WhitespaceJsxTreeResult | WhitespaceJsxTreeResult[]): MultipliedTreeNode[];
|
|
@@ -6,10 +6,10 @@ import * as t from '@babel/types';
|
|
|
6
6
|
import fs from 'node:fs';
|
|
7
7
|
import { parse } from '@babel/parser';
|
|
8
8
|
import addGTIdentifierToSyntaxTree from './addGTIdentifierToSyntaxTree.js';
|
|
9
|
-
import { warnHasUnwrappedExpressionSync, warnNestedTComponent, warnFunctionNotFoundSync, warnMissingReturnSync, warnDuplicateFunctionDefinitionSync,
|
|
9
|
+
import { warnHasUnwrappedExpressionSync, warnNestedTComponent, warnFunctionNotFoundSync, warnMissingReturnSync, warnDuplicateFunctionDefinitionSync, warnInvalidDeriveInitSync, warnRecursiveFunctionCallSync, warnDataAttrOnBranch, } from '../../../../console/index.js';
|
|
10
10
|
import { isAcceptedPluralForm } from 'generaltranslation/internal';
|
|
11
11
|
import { isStaticExpression } from '../../evaluateJsx.js';
|
|
12
|
-
import { DATA_ATTR_PREFIX, STATIC_COMPONENT, TRANSLATION_COMPONENT, VARIABLE_COMPONENTS, } from '../constants.js';
|
|
12
|
+
import { DATA_ATTR_PREFIX, STATIC_COMPONENT, DERIVE_COMPONENT, TRANSLATION_COMPONENT, VARIABLE_COMPONENTS, } from '../constants.js';
|
|
13
13
|
import { HTML_CONTENT_PROPS } from 'generaltranslation/types';
|
|
14
14
|
import { resolveImportPath } from '../resolveImportPath.js';
|
|
15
15
|
import traverseModule from '@babel/traverse';
|
|
@@ -64,7 +64,7 @@ export function parseTranslationComponent({ originalName, localName, path, updat
|
|
|
64
64
|
state: {
|
|
65
65
|
visited: null,
|
|
66
66
|
callStack: [],
|
|
67
|
-
|
|
67
|
+
derivableTracker: { isDerivable: false },
|
|
68
68
|
importedFunctionsMap,
|
|
69
69
|
},
|
|
70
70
|
output,
|
|
@@ -77,20 +77,20 @@ export function parseTranslationComponent({ originalName, localName, path, updat
|
|
|
77
77
|
* @param helperPath - NodePath for AST traversal
|
|
78
78
|
* @param scopeNode - Scope node for binding resolution
|
|
79
79
|
* @param insideT - Whether the current node is inside a <T> component
|
|
80
|
-
* @param
|
|
80
|
+
* @param inDerive - Whether we're inside a <Derive> component
|
|
81
81
|
* @param config - Immutable configuration options
|
|
82
82
|
* @param state - Mutable state tracking
|
|
83
83
|
* @param output - Error/warning collectors
|
|
84
84
|
* @returns The built JSX tree
|
|
85
85
|
*/
|
|
86
|
-
function buildJSXTree({ node, helperPath, scopeNode, insideT,
|
|
86
|
+
function buildJSXTree({ node, helperPath, scopeNode, insideT, inDerive, config, state, output, }) {
|
|
87
87
|
if (t.isJSXExpressionContainer(node)) {
|
|
88
88
|
// Skip JSX comments
|
|
89
89
|
if (t.isJSXEmptyExpression(node.expression)) {
|
|
90
90
|
return null;
|
|
91
91
|
}
|
|
92
|
-
if (
|
|
93
|
-
return
|
|
92
|
+
if (inDerive) {
|
|
93
|
+
return processDeriveExpression({
|
|
94
94
|
config,
|
|
95
95
|
state,
|
|
96
96
|
output,
|
|
@@ -103,7 +103,7 @@ function buildJSXTree({ node, helperPath, scopeNode, insideT, inStatic, config,
|
|
|
103
103
|
return buildJSXTree({
|
|
104
104
|
node: expr,
|
|
105
105
|
insideT,
|
|
106
|
-
|
|
106
|
+
inDerive: inDerive,
|
|
107
107
|
scopeNode,
|
|
108
108
|
helperPath: helperPath.get('expression'),
|
|
109
109
|
config,
|
|
@@ -192,7 +192,7 @@ function buildJSXTree({ node, helperPath, scopeNode, insideT, inStatic, config,
|
|
|
192
192
|
attrValue = buildJSXTree({
|
|
193
193
|
node: attr.value,
|
|
194
194
|
insideT: true,
|
|
195
|
-
|
|
195
|
+
inDerive: inDerive,
|
|
196
196
|
scopeNode,
|
|
197
197
|
helperPath: helperValue,
|
|
198
198
|
config,
|
|
@@ -215,11 +215,12 @@ function buildJSXTree({ node, helperPath, scopeNode, insideT, inStatic, config,
|
|
|
215
215
|
}
|
|
216
216
|
});
|
|
217
217
|
if (elementIsVariable) {
|
|
218
|
-
if (componentType === STATIC_COMPONENT
|
|
218
|
+
if (componentType === STATIC_COMPONENT ||
|
|
219
|
+
componentType === DERIVE_COMPONENT) {
|
|
219
220
|
const helperElement = helperPath.get('children');
|
|
220
221
|
const results = {
|
|
221
222
|
nodeType: 'element',
|
|
222
|
-
type:
|
|
223
|
+
type: componentType,
|
|
223
224
|
props,
|
|
224
225
|
};
|
|
225
226
|
// Create children array if necessary
|
|
@@ -232,7 +233,7 @@ function buildJSXTree({ node, helperPath, scopeNode, insideT, inStatic, config,
|
|
|
232
233
|
const result = buildJSXTree({
|
|
233
234
|
node: helperChild.node,
|
|
234
235
|
insideT: true,
|
|
235
|
-
|
|
236
|
+
inDerive: true,
|
|
236
237
|
scopeNode,
|
|
237
238
|
helperPath: helperChild,
|
|
238
239
|
config,
|
|
@@ -258,7 +259,7 @@ function buildJSXTree({ node, helperPath, scopeNode, insideT, inStatic, config,
|
|
|
258
259
|
.map((child, index) => buildJSXTree({
|
|
259
260
|
node: child,
|
|
260
261
|
insideT: true,
|
|
261
|
-
|
|
262
|
+
inDerive: inDerive,
|
|
262
263
|
scopeNode,
|
|
263
264
|
helperPath: helperPath.get('children')[index],
|
|
264
265
|
config,
|
|
@@ -286,7 +287,7 @@ function buildJSXTree({ node, helperPath, scopeNode, insideT, inStatic, config,
|
|
|
286
287
|
.map((child, index) => buildJSXTree({
|
|
287
288
|
node: child,
|
|
288
289
|
insideT: true,
|
|
289
|
-
|
|
290
|
+
inDerive: inDerive,
|
|
290
291
|
scopeNode,
|
|
291
292
|
helperPath: helperPath.get('children')[index],
|
|
292
293
|
config,
|
|
@@ -313,7 +314,7 @@ function buildJSXTree({ node, helperPath, scopeNode, insideT, inStatic, config,
|
|
|
313
314
|
}
|
|
314
315
|
// If it's a template literal
|
|
315
316
|
else if (t.isTemplateLiteral(node)) {
|
|
316
|
-
// We've already checked that it's
|
|
317
|
+
// We've already checked that it's derivable, and and added a warning if it's not, this check is just for fallback behavior
|
|
317
318
|
if (!isStaticExpression(node, true).isStatic ||
|
|
318
319
|
node.quasis[0].value.cooked === undefined) {
|
|
319
320
|
return generate(node).code;
|
|
@@ -345,7 +346,7 @@ function buildJSXTree({ node, helperPath, scopeNode, insideT, inStatic, config,
|
|
|
345
346
|
(t.isAwaitExpression(node) &&
|
|
346
347
|
t.isCallExpression(node.argument) &&
|
|
347
348
|
t.isIdentifier(node.argument.callee))) {
|
|
348
|
-
if (
|
|
349
|
+
if (inDerive) {
|
|
349
350
|
const callExpression = (node.type === 'AwaitExpression' ? node.argument : node);
|
|
350
351
|
const callee = callExpression.callee;
|
|
351
352
|
const calleeBinding = scopeNode.scope.getBinding(callee.name);
|
|
@@ -353,7 +354,7 @@ function buildJSXTree({ node, helperPath, scopeNode, insideT, inStatic, config,
|
|
|
353
354
|
output.warnings.add(warnFunctionNotFoundSync(config.file, callee.name, `${callee.loc?.start?.line}:${callee.loc?.start?.column}`));
|
|
354
355
|
return null;
|
|
355
356
|
}
|
|
356
|
-
return
|
|
357
|
+
return resolveDeriveFunctionInvocationFromBinding({
|
|
357
358
|
calleeBinding,
|
|
358
359
|
callee,
|
|
359
360
|
config,
|
|
@@ -370,7 +371,7 @@ function buildJSXTree({ node, helperPath, scopeNode, insideT, inStatic, config,
|
|
|
370
371
|
return buildJSXTree({
|
|
371
372
|
node: child,
|
|
372
373
|
insideT,
|
|
373
|
-
|
|
374
|
+
inDerive: inDerive,
|
|
374
375
|
scopeNode,
|
|
375
376
|
helperPath: helperPath.get('expression'),
|
|
376
377
|
config,
|
|
@@ -430,22 +431,22 @@ function parseJSXElement({ node, originalName, scopeNode, updates, config, state
|
|
|
430
431
|
componentErrors,
|
|
431
432
|
file: config.file,
|
|
432
433
|
});
|
|
433
|
-
// Flag for if contains
|
|
434
|
-
const
|
|
435
|
-
|
|
434
|
+
// Flag for if contains derivable content
|
|
435
|
+
const derivableTracker = {
|
|
436
|
+
isDerivable: false,
|
|
436
437
|
};
|
|
437
438
|
// Build the JSX tree for this component
|
|
438
439
|
const treeResult = buildJSXTree({
|
|
439
440
|
node,
|
|
440
441
|
scopeNode,
|
|
441
442
|
insideT: false,
|
|
442
|
-
|
|
443
|
+
inDerive: false,
|
|
443
444
|
helperPath: scopeNode,
|
|
444
445
|
config,
|
|
445
446
|
state: {
|
|
446
447
|
visited: null,
|
|
447
448
|
callStack: [],
|
|
448
|
-
|
|
449
|
+
derivableTracker: derivableTracker,
|
|
449
450
|
importedFunctionsMap: state.importedFunctionsMap,
|
|
450
451
|
},
|
|
451
452
|
output: {
|
|
@@ -486,9 +487,8 @@ function parseJSXElement({ node, originalName, scopeNode, updates, config, state
|
|
|
486
487
|
output.errors.push(warnHasUnwrappedExpressionSync(config.file, unwrappedExpressions, metadata.id, `${node.loc?.start?.line}:${node.loc?.start?.column}`));
|
|
487
488
|
return;
|
|
488
489
|
}
|
|
489
|
-
// Create a temporary unique flag for
|
|
490
|
-
const
|
|
491
|
-
const isStatic = staticTracker.isStatic;
|
|
490
|
+
// Create a temporary unique flag for derivable content
|
|
491
|
+
const temporaryDeriveId = `derive-temp-id-${randomUUID()}`;
|
|
492
492
|
// <T> is valid here
|
|
493
493
|
for (const minifiedTree of minifiedTress) {
|
|
494
494
|
// Clean the tree by removing null 'c' fields from JsxElements
|
|
@@ -499,12 +499,12 @@ function parseJSXElement({ node, originalName, scopeNode, updates, config, state
|
|
|
499
499
|
metadata: {
|
|
500
500
|
// eslint-disable-next-line no-undef
|
|
501
501
|
...structuredClone(metadata),
|
|
502
|
-
...(
|
|
502
|
+
...(derivableTracker.isDerivable && { staticId: temporaryDeriveId }),
|
|
503
503
|
},
|
|
504
504
|
});
|
|
505
505
|
}
|
|
506
506
|
}
|
|
507
|
-
function
|
|
507
|
+
function resolveDeriveFunctionInvocationFromBinding({ calleeBinding, callee, config, state, output, }) {
|
|
508
508
|
function withRecusionGuard({ cb, filename, functionName, }) {
|
|
509
509
|
const cacheKey = `${filename}::${functionName}`;
|
|
510
510
|
if (state.callStack.includes(cacheKey)) {
|
|
@@ -760,7 +760,7 @@ function processFunctionDeclarationNodePath({ config, state, output, path, }) {
|
|
|
760
760
|
if (!returnNodePath.isExpression()) {
|
|
761
761
|
return;
|
|
762
762
|
}
|
|
763
|
-
result.branches.push(
|
|
763
|
+
result.branches.push(processDeriveExpression({
|
|
764
764
|
config,
|
|
765
765
|
state,
|
|
766
766
|
output,
|
|
@@ -788,13 +788,13 @@ function processVariableDeclarationNodePath({ config, state, output, functionNam
|
|
|
788
788
|
// Enforce the Rhand is a function definition
|
|
789
789
|
const arrowFunctionPath = path.get('init');
|
|
790
790
|
if (!arrowFunctionPath.isArrowFunctionExpression()) {
|
|
791
|
-
output.errors.push(
|
|
791
|
+
output.errors.push(warnInvalidDeriveInitSync(config.file, functionName, `${path.node.loc?.start?.line}:${path.node.loc?.start?.column}`));
|
|
792
792
|
return null;
|
|
793
793
|
}
|
|
794
794
|
const bodyNodePath = arrowFunctionPath.get('body');
|
|
795
795
|
if (bodyNodePath.isExpression()) {
|
|
796
796
|
// process expression return
|
|
797
|
-
result.branches.push(
|
|
797
|
+
result.branches.push(processDeriveExpression({
|
|
798
798
|
config,
|
|
799
799
|
state,
|
|
800
800
|
output,
|
|
@@ -813,7 +813,7 @@ function processVariableDeclarationNodePath({ config, state, output, functionNam
|
|
|
813
813
|
if (!returnNodePath.isExpression()) {
|
|
814
814
|
return;
|
|
815
815
|
}
|
|
816
|
-
result.branches.push(
|
|
816
|
+
result.branches.push(processDeriveExpression({
|
|
817
817
|
config,
|
|
818
818
|
state,
|
|
819
819
|
output,
|
|
@@ -830,15 +830,15 @@ function processVariableDeclarationNodePath({ config, state, output, functionNam
|
|
|
830
830
|
return result;
|
|
831
831
|
}
|
|
832
832
|
/**
|
|
833
|
-
* Process a <
|
|
833
|
+
* Process a <Derive> expression
|
|
834
834
|
*/
|
|
835
|
-
function
|
|
836
|
-
// Mark the
|
|
837
|
-
state.
|
|
835
|
+
function processDeriveExpression({ config, state, output, expressionNodePath, scopeNode, }) {
|
|
836
|
+
// Mark the derivable tracker as true
|
|
837
|
+
state.derivableTracker.isDerivable = true;
|
|
838
838
|
// Remove parentheses if they exist
|
|
839
839
|
if (t.isParenthesizedExpression(expressionNodePath.node)) {
|
|
840
840
|
// ex: return (value)
|
|
841
|
-
return
|
|
841
|
+
return processDeriveExpression({
|
|
842
842
|
config,
|
|
843
843
|
state,
|
|
844
844
|
output,
|
|
@@ -856,7 +856,7 @@ function processStaticExpression({ config, state, output, expressionNodePath, sc
|
|
|
856
856
|
return null;
|
|
857
857
|
}
|
|
858
858
|
// Function is found
|
|
859
|
-
return
|
|
859
|
+
return resolveDeriveFunctionInvocationFromBinding({
|
|
860
860
|
calleeBinding,
|
|
861
861
|
callee,
|
|
862
862
|
config,
|
|
@@ -875,7 +875,7 @@ function processStaticExpression({ config, state, output, expressionNodePath, sc
|
|
|
875
875
|
return null;
|
|
876
876
|
}
|
|
877
877
|
// Function is found
|
|
878
|
-
return
|
|
878
|
+
return resolveDeriveFunctionInvocationFromBinding({
|
|
879
879
|
calleeBinding,
|
|
880
880
|
callee,
|
|
881
881
|
config,
|
|
@@ -891,7 +891,7 @@ function processStaticExpression({ config, state, output, expressionNodePath, sc
|
|
|
891
891
|
helperPath: expressionNodePath,
|
|
892
892
|
scopeNode,
|
|
893
893
|
insideT: true,
|
|
894
|
-
|
|
894
|
+
inDerive: true,
|
|
895
895
|
config,
|
|
896
896
|
state,
|
|
897
897
|
output,
|
|
@@ -904,7 +904,7 @@ function processStaticExpression({ config, state, output, expressionNodePath, sc
|
|
|
904
904
|
const alternateNodePath = expressionNodePath.get('alternate');
|
|
905
905
|
const result = {
|
|
906
906
|
nodeType: 'multiplication',
|
|
907
|
-
branches: [consequentNodePath, alternateNodePath].map((expressionNodePath) =>
|
|
907
|
+
branches: [consequentNodePath, alternateNodePath].map((expressionNodePath) => processDeriveExpression({
|
|
908
908
|
config,
|
|
909
909
|
state,
|
|
910
910
|
output,
|
|
@@ -920,7 +920,7 @@ function processStaticExpression({ config, state, output, expressionNodePath, sc
|
|
|
920
920
|
helperPath: expressionNodePath,
|
|
921
921
|
scopeNode,
|
|
922
922
|
insideT: true,
|
|
923
|
-
|
|
923
|
+
inDerive: true,
|
|
924
924
|
config,
|
|
925
925
|
state,
|
|
926
926
|
output,
|
|
@@ -24,13 +24,13 @@ export function parseTProps({ openingElement, metadata, componentErrors, file, }
|
|
|
24
24
|
else if (t.isJSXExpressionContainer(attr.value)) {
|
|
25
25
|
const expr = attr.value.expression;
|
|
26
26
|
const code = generate(expr).code;
|
|
27
|
-
// Only check for
|
|
27
|
+
// Only check for derivable expressions on id and context and maxChars props
|
|
28
28
|
if (GT_ATTRIBUTES.includes(attrName)) {
|
|
29
29
|
const staticAnalysis = isStaticExpression(expr);
|
|
30
30
|
if (!staticAnalysis.isStatic) {
|
|
31
31
|
componentErrors.push(warnVariablePropSync(file, attrName, code, `${expr.loc?.start?.line}:${expr.loc?.start?.column}`));
|
|
32
32
|
}
|
|
33
|
-
// Use the
|
|
33
|
+
// Use the derived value if available
|
|
34
34
|
if (staticAnalysis.isStatic && staticAnalysis.value !== undefined) {
|
|
35
35
|
// Check for invalid maxChars values
|
|
36
36
|
if (attrName === '$maxChars' || attrName === 'maxChars') {
|
|
@@ -51,7 +51,7 @@ export function parseTProps({ openingElement, metadata, componentErrors, file, }
|
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
53
|
else {
|
|
54
|
-
// Only store the code if we couldn't extract a
|
|
54
|
+
// Only store the code if we couldn't extract a derivable value
|
|
55
55
|
metadata[attrName] = code;
|
|
56
56
|
}
|
|
57
57
|
}
|
|
@@ -4,7 +4,7 @@ import { ParsingConfigOptions } from '../../../types/parsing.js';
|
|
|
4
4
|
import { StringNode } from './types.js';
|
|
5
5
|
export type StringTree = (string | StringTree)[];
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
7
|
+
* Extracts content if an expression is derivable (statically analyzable) or uses derive()
|
|
8
8
|
* Returns a Node representing the parsed expression
|
|
9
9
|
* @param expr - The expression to check
|
|
10
10
|
* @param tPath - NodePath for scope resolution
|
|
@@ -12,4 +12,4 @@ export type StringTree = (string | StringTree)[];
|
|
|
12
12
|
* @param parsingOptions - Parsing configuration
|
|
13
13
|
* @returns Node | null - The parsed node, or null if invalid
|
|
14
14
|
*/
|
|
15
|
-
export declare function
|
|
15
|
+
export declare function handleDeriveExpression(expr: t.Expression, tPath: NodePath, file: string, parsingOptions: ParsingConfigOptions, errors: string[]): StringNode | null;
|
|
@@ -4,8 +4,8 @@ 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,
|
|
8
|
-
import { DECLARE_STATIC_FUNCTION } from './constants.js';
|
|
7
|
+
import { warnFunctionNotFoundSync, warnDeriveFunctionNoResultsSync, warnDeriveFunctionNotWrappedSync, } from '../../../console/index.js';
|
|
8
|
+
import { DECLARE_STATIC_FUNCTION, DERIVE_FUNCTION } from './constants.js';
|
|
9
9
|
import traverseModule from '@babel/traverse';
|
|
10
10
|
import generateModule from '@babel/generator';
|
|
11
11
|
// Handle CommonJS/ESM interop
|
|
@@ -24,7 +24,7 @@ const resolveImportPathCache = new Map();
|
|
|
24
24
|
*/
|
|
25
25
|
const processFunctionCache = new Map();
|
|
26
26
|
/**
|
|
27
|
-
*
|
|
27
|
+
* Extracts content if an expression is derivable (statically analyzable) or uses derive()
|
|
28
28
|
* Returns a Node representing the parsed expression
|
|
29
29
|
* @param expr - The expression to check
|
|
30
30
|
* @param tPath - NodePath for scope resolution
|
|
@@ -32,15 +32,15 @@ const processFunctionCache = new Map();
|
|
|
32
32
|
* @param parsingOptions - Parsing configuration
|
|
33
33
|
* @returns Node | null - The parsed node, or null if invalid
|
|
34
34
|
*/
|
|
35
|
-
export function
|
|
35
|
+
export function handleDeriveExpression(expr, tPath, file, parsingOptions, errors) {
|
|
36
36
|
if (!expr) {
|
|
37
37
|
return null;
|
|
38
38
|
}
|
|
39
39
|
// Handle expressions
|
|
40
40
|
if (t.isCallExpression(expr)) {
|
|
41
|
-
const variants =
|
|
41
|
+
const variants = getDeriveVariants(expr, tPath, file, parsingOptions, errors);
|
|
42
42
|
if (variants) {
|
|
43
|
-
// We found
|
|
43
|
+
// We found derive() -> return as ChoiceNode
|
|
44
44
|
return {
|
|
45
45
|
type: 'choice',
|
|
46
46
|
nodes: variants.map((v) => ({ type: 'text', text: v })),
|
|
@@ -50,7 +50,7 @@ export function handleStaticExpression(expr, tPath, file, parsingOptions, errors
|
|
|
50
50
|
const code = expr.arguments.length > 0
|
|
51
51
|
? generate(expr.arguments[0]).code
|
|
52
52
|
: 'no arguments';
|
|
53
|
-
errors.push(
|
|
53
|
+
errors.push(warnDeriveFunctionNoResultsSync(file, code, `${expr.loc?.start?.line}:${expr.loc?.start?.column}`));
|
|
54
54
|
return null;
|
|
55
55
|
}
|
|
56
56
|
// Handle direct string literals
|
|
@@ -68,7 +68,7 @@ export function handleStaticExpression(expr, tPath, file, parsingOptions, errors
|
|
|
68
68
|
}
|
|
69
69
|
const exprNode = expr.expressions[index];
|
|
70
70
|
if (exprNode && t.isExpression(exprNode)) {
|
|
71
|
-
const result =
|
|
71
|
+
const result = handleDeriveExpression(exprNode, tPath, file, parsingOptions, errors);
|
|
72
72
|
if (result === null) {
|
|
73
73
|
// Early bailout if we can't handle something inside interpolation
|
|
74
74
|
return null;
|
|
@@ -89,8 +89,8 @@ export function handleStaticExpression(expr, tPath, file, parsingOptions, errors
|
|
|
89
89
|
if (!t.isExpression(expr.left) || !t.isExpression(expr.right)) {
|
|
90
90
|
return null;
|
|
91
91
|
}
|
|
92
|
-
const leftResult =
|
|
93
|
-
const rightResult =
|
|
92
|
+
const leftResult = handleDeriveExpression(expr.left, tPath, file, parsingOptions, errors);
|
|
93
|
+
const rightResult = handleDeriveExpression(expr.right, tPath, file, parsingOptions, errors);
|
|
94
94
|
if (leftResult === null || rightResult === null) {
|
|
95
95
|
return null;
|
|
96
96
|
}
|
|
@@ -98,7 +98,7 @@ export function handleStaticExpression(expr, tPath, file, parsingOptions, errors
|
|
|
98
98
|
}
|
|
99
99
|
// Handle parenthesized expressions
|
|
100
100
|
if (t.isParenthesizedExpression(expr)) {
|
|
101
|
-
return
|
|
101
|
+
return handleDeriveExpression(expr.expression, tPath, file, parsingOptions, errors);
|
|
102
102
|
}
|
|
103
103
|
// Handle numeric literals by converting them to strings
|
|
104
104
|
if (t.isNumericLiteral(expr)) {
|
|
@@ -134,33 +134,33 @@ export function handleStaticExpression(expr, tPath, file, parsingOptions, errors
|
|
|
134
134
|
if (t.isNullLiteral(expr)) {
|
|
135
135
|
return { type: 'text', text: 'null' };
|
|
136
136
|
}
|
|
137
|
-
// Not a
|
|
137
|
+
// Not a derivable expression
|
|
138
138
|
return null;
|
|
139
139
|
}
|
|
140
140
|
/**
|
|
141
|
-
* Given a CallExpression, if it is
|
|
141
|
+
* Given a CallExpression, if it is derive(<call>) or derive(await <call>),
|
|
142
142
|
* return all possible string outcomes of that argument call as an array of strings.
|
|
143
143
|
*
|
|
144
144
|
* Examples:
|
|
145
|
-
*
|
|
146
|
-
*
|
|
145
|
+
* derive(time()) -> ["day", "night"]
|
|
146
|
+
* derive(await time()) -> ["day", "night"]
|
|
147
147
|
*
|
|
148
148
|
* Returns null if it can't be resolved.
|
|
149
149
|
*/
|
|
150
|
-
function
|
|
150
|
+
function getDeriveVariants(call, tPath, file, parsingOptions, errors) {
|
|
151
151
|
// --- Validate Callee --- //
|
|
152
|
-
// Must be
|
|
152
|
+
// Must be derive(...) or an alias of it
|
|
153
153
|
if (!t.isIdentifier(call.callee)) {
|
|
154
154
|
const code = call.arguments.length > 0
|
|
155
155
|
? generate(call.arguments[0]).code
|
|
156
156
|
: 'no arguments';
|
|
157
|
-
errors.push(
|
|
157
|
+
errors.push(warnDeriveFunctionNotWrappedSync(file, code, `${call.callee.loc?.start?.line}:${call.callee.loc?.start?.column}`));
|
|
158
158
|
return null;
|
|
159
159
|
}
|
|
160
|
-
// Check if this is
|
|
160
|
+
// Check if this is derive by name or by checking the import
|
|
161
161
|
const calleeName = call.callee.name;
|
|
162
162
|
const calleeBinding = tPath.scope.getBinding(calleeName);
|
|
163
|
-
// If it's not literally named '
|
|
163
|
+
// If it's not literally named 'derive', check if it's imported from GT
|
|
164
164
|
if (!calleeBinding) {
|
|
165
165
|
return null;
|
|
166
166
|
}
|
|
@@ -170,14 +170,15 @@ function getDeclareStaticVariants(call, tPath, file, parsingOptions, errors) {
|
|
|
170
170
|
const originalName = t.isIdentifier(imported)
|
|
171
171
|
? imported.name
|
|
172
172
|
: imported.value;
|
|
173
|
-
// Only proceed if the original name is 'declareStatic'
|
|
174
|
-
if (originalName !== DECLARE_STATIC_FUNCTION
|
|
173
|
+
// Only proceed if the original name is 'derive' (or the deprecated 'declareStatic')
|
|
174
|
+
if (originalName !== DECLARE_STATIC_FUNCTION &&
|
|
175
|
+
originalName !== DERIVE_FUNCTION) {
|
|
175
176
|
return null;
|
|
176
177
|
}
|
|
177
178
|
}
|
|
178
179
|
else {
|
|
179
|
-
// Not an import specifier, so it's not
|
|
180
|
-
errors.push(
|
|
180
|
+
// Not an import specifier, so it's not derive
|
|
181
|
+
errors.push(warnDeriveFunctionNotWrappedSync(file, calleeName, `${call.callee.loc?.start?.line}:${call.callee.loc?.start?.column}`));
|
|
181
182
|
return null;
|
|
182
183
|
}
|
|
183
184
|
// --- Validate Arguments --- //
|
|
@@ -186,7 +187,7 @@ function getDeclareStaticVariants(call, tPath, file, parsingOptions, errors) {
|
|
|
186
187
|
const arg = call.arguments[0];
|
|
187
188
|
if (!t.isExpression(arg))
|
|
188
189
|
return null;
|
|
189
|
-
// Handle await expression:
|
|
190
|
+
// Handle await expression: derive(await time())
|
|
190
191
|
if (t.isAwaitExpression(arg)) {
|
|
191
192
|
// Resolve the inner call's possible string outcomes
|
|
192
193
|
return resolveCallStringVariants(arg.argument, tPath, file, parsingOptions, errors);
|
|
@@ -195,29 +196,7 @@ function getDeclareStaticVariants(call, tPath, file, parsingOptions, errors) {
|
|
|
195
196
|
return resolveCallStringVariants(arg, tPath, file, parsingOptions, errors);
|
|
196
197
|
}
|
|
197
198
|
function resolveCallStringVariants(expression, tPath, file, parsingOptions, errors) {
|
|
198
|
-
|
|
199
|
-
// // Handle inline arrow functions: declareStatic((() => "day")())
|
|
200
|
-
// if (
|
|
201
|
-
// t.isCallExpression(expression) &&
|
|
202
|
-
// t.isParenthesizedExpression(expression.callee) &&
|
|
203
|
-
// t.isArrowFunctionExpression(expression.callee.expression)
|
|
204
|
-
// ) {
|
|
205
|
-
// const body = expression.callee.expression.body;
|
|
206
|
-
// if (t.isStringLiteral(body)) {
|
|
207
|
-
// results.add(body.value);
|
|
208
|
-
// } else if (t.isConditionalExpression(body)) {
|
|
209
|
-
// collectConditionalStringVariants(body, results);
|
|
210
|
-
// }
|
|
211
|
-
// return results.size ? [...results] : null;
|
|
212
|
-
// }
|
|
213
|
-
// // Handle explicit conditional expression call:
|
|
214
|
-
// // declareStatic(cond ? "day" : "night")
|
|
215
|
-
// // TODO: this makes no sense
|
|
216
|
-
// if (t.isConditionalExpression(expression)) {
|
|
217
|
-
// collectConditionalStringVariants(expression, results);
|
|
218
|
-
// return results.size ? [...results] : null;
|
|
219
|
-
// }
|
|
220
|
-
// Handle function identifier calls: declareStatic(time())
|
|
199
|
+
// Handle function identifier calls: derive(time())
|
|
221
200
|
if (t.isCallExpression(expression) && t.isIdentifier(expression.callee)) {
|
|
222
201
|
const functionName = expression.callee.name;
|
|
223
202
|
// Use Binding to resolve the function
|
|
@@ -267,7 +246,7 @@ function resolveCallStringVariants(expression, tPath, file, parsingOptions, erro
|
|
|
267
246
|
return null;
|
|
268
247
|
}
|
|
269
248
|
}
|
|
270
|
-
// If we get here: analyze this call statically
|
|
249
|
+
// If we get here: analyze this call as derivable (statically analyzable)
|
|
271
250
|
const node = parseStringExpression(expression, tPath, file, parsingOptions);
|
|
272
251
|
if (node) {
|
|
273
252
|
return nodeToStrings(node);
|
|
@@ -521,7 +500,7 @@ function resolveFunctionInFile(filePath, functionName, parsingOptions, errors) {
|
|
|
521
500
|
}
|
|
522
501
|
catch (error) {
|
|
523
502
|
// File read or parse error - return null
|
|
524
|
-
errors.push(
|
|
503
|
+
errors.push(warnDeriveFunctionNoResultsSync(filePath, functionName, 'file read/parse error: ' + error));
|
|
525
504
|
result = null;
|
|
526
505
|
}
|
|
527
506
|
// Cache the result
|
|
@@ -3,7 +3,7 @@ import { buildImportMap } from './buildImportMap.js';
|
|
|
3
3
|
import { resolveImportPath } from './resolveImportPath.js';
|
|
4
4
|
import { parse } from '@babel/parser';
|
|
5
5
|
import fs from 'node:fs';
|
|
6
|
-
import {
|
|
6
|
+
import { warnDeriveFunctionNoResultsSync, warnFunctionNotFoundSync, warnInvalidDeclareVarNameSync, } from '../../../console/index.js';
|
|
7
7
|
import traverseModule from '@babel/traverse';
|
|
8
8
|
import { DECLARE_VAR_FUNCTION } from '../../jsx/utils/constants.js';
|
|
9
9
|
import { GT_LIBRARIES } from '../../../types/libraries.js';
|
|
@@ -470,7 +470,7 @@ function resolveFunctionInFile(filePath, functionName, parsingOptions, warnings)
|
|
|
470
470
|
}
|
|
471
471
|
catch (error) {
|
|
472
472
|
// File read or parse error - return null
|
|
473
|
-
warnings.add(
|
|
473
|
+
warnings.add(warnDeriveFunctionNoResultsSync(filePath, functionName, 'file read/parse error: ' + error));
|
|
474
474
|
result = null;
|
|
475
475
|
}
|
|
476
476
|
// Cache the result
|
|
@@ -4,7 +4,7 @@ import { ParsingConfig } from '../types.js';
|
|
|
4
4
|
import { ParsingOutput } from '../types.js';
|
|
5
5
|
import { InlineMetadata } from './extractStringEntryMetadata.js';
|
|
6
6
|
/**
|
|
7
|
-
* For the processTranslationCall function, this function handles the case where a string with
|
|
7
|
+
* For the processTranslationCall function, this function handles the case where a string with derive is used.
|
|
8
8
|
* @param arg - The argument to parse
|
|
9
9
|
* @param metadata - The metadata to use
|
|
10
10
|
* @param tPath - The path to the argument
|
|
@@ -12,7 +12,7 @@ import { InlineMetadata } from './extractStringEntryMetadata.js';
|
|
|
12
12
|
* @param output - The output to use
|
|
13
13
|
* @param index - Current index in array of strings being extracted
|
|
14
14
|
*/
|
|
15
|
-
export declare function
|
|
15
|
+
export declare function handleDeriveTranslationCall({ arg, metadata, tPath, config, output, index, }: {
|
|
16
16
|
arg: t.Expression;
|
|
17
17
|
metadata: InlineMetadata;
|
|
18
18
|
tPath: NodePath;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { handleDeriveExpression } from '../../parseDerive.js';
|
|
2
2
|
import { nodeToStrings } from '../../parseString.js';
|
|
3
3
|
import { indexVars } from 'generaltranslation/internal';
|
|
4
4
|
import { isValidIcu } from '../../../evaluateJsx.js';
|
|
@@ -8,7 +8,7 @@ import { randomUUID } from 'node:crypto';
|
|
|
8
8
|
// Handle CommonJS/ESM interop
|
|
9
9
|
const generate = generateModule.default || generateModule;
|
|
10
10
|
/**
|
|
11
|
-
* For the processTranslationCall function, this function handles the case where a string with
|
|
11
|
+
* For the processTranslationCall function, this function handles the case where a string with derive is used.
|
|
12
12
|
* @param arg - The argument to parse
|
|
13
13
|
* @param metadata - The metadata to use
|
|
14
14
|
* @param tPath - The path to the argument
|
|
@@ -16,9 +16,9 @@ const generate = generateModule.default || generateModule;
|
|
|
16
16
|
* @param output - The output to use
|
|
17
17
|
* @param index - Current index in array of strings being extracted
|
|
18
18
|
*/
|
|
19
|
-
export function
|
|
20
|
-
// parse
|
|
21
|
-
const result =
|
|
19
|
+
export function handleDeriveTranslationCall({ arg, metadata, tPath, config, output, index, }) {
|
|
20
|
+
// parse derivable expression
|
|
21
|
+
const result = handleDeriveExpression(arg, tPath, config.file, config.parsingOptions, output.errors);
|
|
22
22
|
// Nothing returned, push error
|
|
23
23
|
if (!result) {
|
|
24
24
|
output.errors.push(warnNonStringSync(config.file, generate(arg).code, `${arg.loc?.start?.line}:${arg.loc?.start?.column}`));
|
|
@@ -35,7 +35,7 @@ export function handleStaticTranslationCall({ arg, metadata, tPath, config, outp
|
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
|
-
const
|
|
38
|
+
const temporaryDeriveId = `derive-temp-id-${randomUUID()}`;
|
|
39
39
|
for (const string of strings) {
|
|
40
40
|
output.updates.push({
|
|
41
41
|
dataFormat: 'ICU',
|
|
@@ -44,7 +44,7 @@ export function handleStaticTranslationCall({ arg, metadata, tPath, config, outp
|
|
|
44
44
|
...metadata,
|
|
45
45
|
// Add the index if an id and index is provided (for handling when registering an array of strings)
|
|
46
46
|
...(metadata.id && index != null && { id: `${metadata.id}.${index}` }),
|
|
47
|
-
staticId:
|
|
47
|
+
staticId: temporaryDeriveId,
|
|
48
48
|
},
|
|
49
49
|
});
|
|
50
50
|
}
|
|
@@ -9,7 +9,7 @@ import { ParsingOutput } from '../types.js';
|
|
|
9
9
|
* - String literals: t('hello')
|
|
10
10
|
* - Template literals without expressions: t(`hello`)
|
|
11
11
|
* - Metadata extraction from options object
|
|
12
|
-
* - Error reporting for non-
|
|
12
|
+
* - Error reporting for non-derivable expressions and template literals with expressions
|
|
13
13
|
*
|
|
14
14
|
* @param tPath - The path to the translation call
|
|
15
15
|
* @param config - The configuration to use
|
|
@@ -9,7 +9,7 @@ import { SURROUNDING_LINE_COUNT } from '../../../../../utils/constants.js';
|
|
|
9
9
|
* - String literals: t('hello')
|
|
10
10
|
* - Template literals without expressions: t(`hello`)
|
|
11
11
|
* - Metadata extraction from options object
|
|
12
|
-
* - Error reporting for non-
|
|
12
|
+
* - Error reporting for non-derivable expressions and template literals with expressions
|
|
13
13
|
*
|
|
14
14
|
* @param tPath - The path to the translation call
|
|
15
15
|
* @param config - The configuration to use
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { isStaticExpression } from '../../../evaluateJsx.js';
|
|
2
|
-
import {
|
|
2
|
+
import { handleDeriveTranslationCall } from './handleDeriveTranslationCall.js';
|
|
3
3
|
import { handleLiteralTranslationCall } from './handleLiteralTranslationCall.js';
|
|
4
4
|
import { handleInvalidTranslationCall } from './handleInvalidTranslationCall.js';
|
|
5
5
|
import * as t from '@babel/types';
|
|
@@ -36,8 +36,8 @@ export function routeTranslationCall({ tPath, config, output, arg, metadata, ind
|
|
|
36
36
|
else if (!config.ignoreDynamicContent &&
|
|
37
37
|
t.isExpression(arg) &&
|
|
38
38
|
!isStaticExpression(arg).isStatic) {
|
|
39
|
-
// handle
|
|
40
|
-
|
|
39
|
+
// handle derive translation call
|
|
40
|
+
handleDeriveTranslationCall({
|
|
41
41
|
arg,
|
|
42
42
|
metadata,
|
|
43
43
|
tPath,
|
|
@@ -236,7 +236,7 @@ function wrapJsxExpression(node, options, isMeaningful, mark) {
|
|
|
236
236
|
}
|
|
237
237
|
}
|
|
238
238
|
const staticCheck = isStaticExpression(expression);
|
|
239
|
-
// If the expression is not
|
|
239
|
+
// If the expression is not derivable or if it's already wrapped in T,
|
|
240
240
|
// wrap with Var
|
|
241
241
|
if (!staticCheck.isStatic) {
|
|
242
242
|
return {
|
|
@@ -245,7 +245,7 @@ function wrapJsxExpression(node, options, isMeaningful, mark) {
|
|
|
245
245
|
wrappedInT: false,
|
|
246
246
|
};
|
|
247
247
|
}
|
|
248
|
-
// If it's a
|
|
248
|
+
// If it's a derivable expression, check if it's meaningful
|
|
249
249
|
return {
|
|
250
250
|
node,
|
|
251
251
|
hasMeaningfulContent: false,
|
|
@@ -294,7 +294,7 @@ export function wrapJsxElement(node, options, isMeaningful, mark) {
|
|
|
294
294
|
hasMeaningfulContent || result.hasMeaningfulContent;
|
|
295
295
|
// Expressions are never meaningful because they will either:
|
|
296
296
|
// 1. be sub-wrapped in a T (if they contain meaningful content)
|
|
297
|
-
// 2. be wrapped in a Var (if they are not
|
|
297
|
+
// 2. be wrapped in a Var (if they are not marked as derivable)
|
|
298
298
|
return result.node;
|
|
299
299
|
}
|
|
300
300
|
const isMeaningfulVal = isMeaningful(child);
|
|
@@ -7,7 +7,7 @@ import { matchFiles } from '../../fs/matchFiles.js';
|
|
|
7
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
|
-
import { calculateHashes, dedupeUpdates,
|
|
10
|
+
import { calculateHashes, dedupeUpdates, linkDeriveUpdates, } from '../../extraction/postProcess.js';
|
|
11
11
|
export async function createInlineUpdates(pkg, validate, filePatterns, parsingOptions, includeSourceCodeContext = false) {
|
|
12
12
|
const updates = [];
|
|
13
13
|
const errors = [];
|
|
@@ -69,7 +69,7 @@ export async function createInlineUpdates(pkg, validate, filePatterns, parsingOp
|
|
|
69
69
|
// Post processing steps:
|
|
70
70
|
await calculateHashes(updates);
|
|
71
71
|
dedupeUpdates(updates);
|
|
72
|
-
|
|
72
|
+
linkDeriveUpdates(updates);
|
|
73
73
|
return { updates, errors, warnings: [...warnings] };
|
|
74
74
|
}
|
|
75
75
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gt",
|
|
3
|
-
"version": "2.10.
|
|
3
|
+
"version": "2.10.6",
|
|
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.
|
|
114
|
-
"generaltranslation": "8.1.
|
|
113
|
+
"@generaltranslation/python-extractor": "0.1.3",
|
|
114
|
+
"generaltranslation": "8.1.17",
|
|
115
115
|
"gt-remark": "1.0.5"
|
|
116
116
|
},
|
|
117
117
|
"devDependencies": {
|