gtx-cli 2.5.0-alpha.3 → 2.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/dist/config/generateSettings.js +8 -1
  3. package/dist/console/colors.d.ts +1 -0
  4. package/dist/console/colors.js +3 -0
  5. package/dist/console/index.d.ts +8 -0
  6. package/dist/console/index.js +15 -2
  7. package/dist/react/jsx/evaluateJsx.d.ts +9 -6
  8. package/dist/react/jsx/evaluateJsx.js +33 -5
  9. package/dist/react/jsx/utils/buildImportMap.d.ts +9 -0
  10. package/dist/react/jsx/utils/buildImportMap.js +30 -0
  11. package/dist/react/jsx/utils/constants.d.ts +2 -0
  12. package/dist/react/jsx/utils/constants.js +11 -2
  13. package/dist/react/jsx/utils/getPathsAndAliases.d.ts +17 -0
  14. package/dist/react/jsx/utils/getPathsAndAliases.js +89 -0
  15. package/dist/react/{data-_gt → jsx/utils/jsxParsing}/addGTIdentifierToSyntaxTree.d.ts +2 -1
  16. package/dist/react/{data-_gt → jsx/utils/jsxParsing}/addGTIdentifierToSyntaxTree.js +30 -6
  17. package/dist/react/jsx/utils/jsxParsing/handleChildrenWhitespace.d.ts +6 -0
  18. package/dist/react/jsx/utils/jsxParsing/handleChildrenWhitespace.js +199 -0
  19. package/dist/react/jsx/utils/jsxParsing/multiplication/findMultiplicationNode.d.ts +13 -0
  20. package/dist/react/jsx/utils/jsxParsing/multiplication/findMultiplicationNode.js +42 -0
  21. package/dist/react/jsx/utils/jsxParsing/multiplication/multiplyJsxTree.d.ts +5 -0
  22. package/dist/react/jsx/utils/jsxParsing/multiplication/multiplyJsxTree.js +69 -0
  23. package/dist/react/jsx/utils/jsxParsing/parseJsx.d.ts +61 -0
  24. package/dist/react/jsx/utils/jsxParsing/parseJsx.js +1005 -0
  25. package/dist/react/jsx/utils/jsxParsing/parseTProps.d.ts +8 -0
  26. package/dist/react/jsx/utils/jsxParsing/parseTProps.js +47 -0
  27. package/dist/react/jsx/utils/jsxParsing/types.d.ts +48 -0
  28. package/dist/react/jsx/utils/jsxParsing/types.js +34 -0
  29. package/dist/react/jsx/utils/parseStringFunction.js +4 -141
  30. package/dist/react/jsx/utils/resolveImportPath.d.ts +11 -0
  31. package/dist/react/jsx/utils/resolveImportPath.js +111 -0
  32. package/dist/react/parse/createInlineUpdates.js +19 -70
  33. package/package.json +2 -2
  34. package/dist/react/jsx/trimJsxStringChildren.d.ts +0 -7
  35. package/dist/react/jsx/trimJsxStringChildren.js +0 -122
  36. package/dist/react/jsx/utils/parseJsx.d.ts +0 -21
  37. package/dist/react/jsx/utils/parseJsx.js +0 -259
@@ -1,122 +0,0 @@
1
- import { isAcceptedPluralForm } from 'generaltranslation/internal';
2
- // JSX whitespace characters (space, tab, newline, carriage return)
3
- // Does NOT include non-breaking space (U+00A0) which should be preserved
4
- const isJsxWhitespace = (char) => {
5
- return char === ' ' || char === '\t' || char === '\n' || char === '\r';
6
- };
7
- const trimJsxWhitespace = (str, side = 'both') => {
8
- let start = 0;
9
- let end = str.length;
10
- if (side === 'start' || side === 'both') {
11
- while (start < end && isJsxWhitespace(str[start])) {
12
- start++;
13
- }
14
- }
15
- if (side === 'end' || side === 'both') {
16
- while (end > start && isJsxWhitespace(str[end - 1])) {
17
- end--;
18
- }
19
- }
20
- return str.slice(start, end);
21
- };
22
- const hasNonJsxWhitespace = (str) => {
23
- for (const char of str) {
24
- if (!isJsxWhitespace(char))
25
- return true;
26
- }
27
- return false;
28
- };
29
- export function trimJsxStringChild(child, index, childrenTypes) {
30
- // Normalize line endings to \n for consistency across platforms
31
- let result = child.replace(/\r\n|\r/g, '\n');
32
- // Collapse multiple spaces/tabs into a single space (but not nbsp)
33
- result = result.replace(/[\t ]+/g, ' ');
34
- let newResult = '';
35
- let newline = false;
36
- for (const char of result) {
37
- if (char === '\n') {
38
- if (hasNonJsxWhitespace(newResult))
39
- newResult += ' ';
40
- else
41
- newResult = '';
42
- newline = true;
43
- continue;
44
- }
45
- if (!newline) {
46
- newResult += char;
47
- continue;
48
- }
49
- if (isJsxWhitespace(char))
50
- continue;
51
- newResult += char;
52
- newline = false;
53
- }
54
- if (newline)
55
- newResult = trimJsxWhitespace(newResult, 'end');
56
- result = newResult;
57
- // Collapse multiple spaces/tabs into a single space (but not nbsp)
58
- result = result.replace(/[\t ]+/g, ' ');
59
- return result;
60
- }
61
- /**
62
- * Handles whitespace in children of a JSX element.
63
- * @param currentTree - The current tree to handle
64
- * @returns The processed tree with whitespace handled
65
- */
66
- export const handleChildrenWhitespace = (currentTree) => {
67
- if (Array.isArray(currentTree)) {
68
- const childrenTypes = currentTree.map((child) => {
69
- if (typeof child === 'string')
70
- return 'text';
71
- if (typeof child === 'object' && 'expression' in child)
72
- return 'expression';
73
- return 'element';
74
- });
75
- const newChildren = [];
76
- currentTree.forEach((child, index) => {
77
- if (childrenTypes[index] === 'text') {
78
- const string = trimJsxStringChild(child, index, childrenTypes);
79
- if (string)
80
- newChildren.push(string);
81
- }
82
- else if (childrenTypes[index] === 'expression') {
83
- newChildren.push(child.result);
84
- }
85
- else {
86
- newChildren.push(handleChildrenWhitespace(child));
87
- }
88
- });
89
- return newChildren.length === 1 ? newChildren[0] : newChildren;
90
- }
91
- else if (currentTree?.props) {
92
- // Process all props recursively
93
- const elementIsPlural = currentTree.type === 'Plural';
94
- const elementIsBranch = currentTree.type === 'Branch';
95
- const processedProps = Object.fromEntries(Object.entries(currentTree.props).map(([key, value]) => {
96
- let shouldProcess = false;
97
- if (key === 'children')
98
- shouldProcess = true;
99
- if (elementIsPlural && isAcceptedPluralForm(key))
100
- shouldProcess = true;
101
- if (elementIsBranch && key !== 'branch')
102
- shouldProcess = true;
103
- // Add your validation logic here
104
- if (shouldProcess) {
105
- return [key, handleChildrenWhitespace(value)];
106
- }
107
- return [key, value];
108
- }));
109
- return {
110
- ...currentTree,
111
- props: processedProps,
112
- };
113
- }
114
- else if (typeof currentTree === 'object' &&
115
- 'expression' in currentTree === true) {
116
- return currentTree.result;
117
- }
118
- else if (typeof currentTree === 'string') {
119
- return trimJsxStringChild(currentTree, 0, ['text']);
120
- }
121
- return currentTree;
122
- };
@@ -1,21 +0,0 @@
1
- import { Updates } from '../../../types/index.js';
2
- import * as t from '@babel/types';
3
- /**
4
- * Builds a JSX tree from a given node, recursively handling children.
5
- * @param node - The node to build the tree from
6
- * @param unwrappedExpressions - An array to store unwrapped expressions
7
- * @param updates - The updates array
8
- * @param errors - The errors array
9
- * @param file - The file name
10
- * @param insideT - Whether the current node is inside a <T> component
11
- * @returns The built JSX tree
12
- */
13
- export declare function buildJSXTree(importAliases: Record<string, string>, node: any, unwrappedExpressions: string[], updates: Updates, errors: string[], warnings: Set<string>, file: string, insideT: boolean): {
14
- expression?: boolean;
15
- result?: string;
16
- type?: string;
17
- props?: {
18
- children?: any;
19
- };
20
- } | string | null;
21
- export declare function parseJSXElement(importAliases: Record<string, string>, node: t.JSXElement, updates: Updates, errors: string[], warnings: Set<string>, file: string): void;
@@ -1,259 +0,0 @@
1
- import generateModule from '@babel/generator';
2
- // Handle CommonJS/ESM interop
3
- const generate = generateModule.default || generateModule;
4
- import * as t from '@babel/types';
5
- import addGTIdentifierToSyntaxTree from '../../data-_gt/addGTIdentifierToSyntaxTree.js';
6
- import { warnHasUnwrappedExpressionSync, warnVariablePropSync, warnNestedTComponent, } from '../../../console/index.js';
7
- import { isAcceptedPluralForm } from 'generaltranslation/internal';
8
- import { handleChildrenWhitespace } from '../trimJsxStringChildren.js';
9
- import { isStaticExpression } from '../evaluateJsx.js';
10
- import { GT_ATTRIBUTES, mapAttributeName, VARIABLE_COMPONENTS, } from './constants.js';
11
- import { HTML_CONTENT_PROPS } from 'generaltranslation/types';
12
- /**
13
- * Builds a JSX tree from a given node, recursively handling children.
14
- * @param node - The node to build the tree from
15
- * @param unwrappedExpressions - An array to store unwrapped expressions
16
- * @param updates - The updates array
17
- * @param errors - The errors array
18
- * @param file - The file name
19
- * @param insideT - Whether the current node is inside a <T> component
20
- * @returns The built JSX tree
21
- */
22
- export function buildJSXTree(importAliases, node, unwrappedExpressions, updates, errors, warnings, file, insideT) {
23
- if (t.isJSXExpressionContainer(node)) {
24
- // Skip JSX comments
25
- if (t.isJSXEmptyExpression(node.expression)) {
26
- return null;
27
- }
28
- const expr = node.expression;
29
- if (t.isJSXElement(expr)) {
30
- return buildJSXTree(importAliases, expr, unwrappedExpressions, updates, errors, warnings, file, insideT);
31
- }
32
- const staticAnalysis = isStaticExpression(expr);
33
- if (staticAnalysis.isStatic && staticAnalysis.value !== undefined) {
34
- // Preserve the exact whitespace for static string expressions
35
- return {
36
- expression: true,
37
- result: staticAnalysis.value,
38
- };
39
- }
40
- // Keep existing behavior for non-static expressions
41
- const code = generate(node).code;
42
- unwrappedExpressions.push(code); // Keep track of unwrapped expressions for error reporting
43
- return code;
44
- }
45
- else if (t.isJSXText(node)) {
46
- // Updated JSX Text handling
47
- // JSX Text handling following React's rules
48
- const text = node.value;
49
- return text;
50
- }
51
- else if (t.isJSXElement(node)) {
52
- const element = node;
53
- const elementName = element.openingElement.name;
54
- let typeName;
55
- if (t.isJSXIdentifier(elementName)) {
56
- typeName = elementName.name;
57
- }
58
- else if (t.isJSXMemberExpression(elementName)) {
59
- typeName = generate(elementName).code;
60
- }
61
- else {
62
- typeName = null;
63
- }
64
- // Convert from alias to original name
65
- const componentType = importAliases[typeName ?? ''];
66
- if (componentType === 'T' && insideT) {
67
- // Add warning: Nested <T> components are allowed, but they are advised against
68
- warnings.add(warnNestedTComponent(file, `${element.loc?.start?.line}:${element.loc?.start?.column}`));
69
- }
70
- // If this JSXElement is one of the recognized variable components,
71
- const elementIsVariable = VARIABLE_COMPONENTS.includes(componentType);
72
- const props = {};
73
- const elementIsPlural = componentType === 'Plural';
74
- const elementIsBranch = componentType === 'Branch';
75
- element.openingElement.attributes.forEach((attr) => {
76
- if (t.isJSXAttribute(attr)) {
77
- const attrName = attr.name.name;
78
- let attrValue = null;
79
- if (attr.value) {
80
- if (t.isStringLiteral(attr.value)) {
81
- attrValue = attr.value.value;
82
- }
83
- else if (t.isJSXExpressionContainer(attr.value)) {
84
- // Check if this is an HTML content prop (title, placeholder, alt, etc.)
85
- const isHtmlContentProp = Object.values(HTML_CONTENT_PROPS).includes(attrName);
86
- if (isHtmlContentProp) {
87
- // For HTML content props, only accept static string expressions
88
- const staticAnalysis = isStaticExpression(attr.value.expression);
89
- if (staticAnalysis.isStatic &&
90
- staticAnalysis.value !== undefined) {
91
- attrValue = staticAnalysis.value;
92
- }
93
- // Otherwise attrValue stays null and won't be included
94
- }
95
- else {
96
- // For non-HTML-content props, validate plural/branch then build tree
97
- if ((elementIsPlural && isAcceptedPluralForm(attrName)) ||
98
- (elementIsBranch && attrName !== 'branch')) {
99
- // Make sure that variable strings like {`I have ${count} book`} are invalid!
100
- if (t.isTemplateLiteral(attr.value.expression) &&
101
- !isStaticExpression(attr.value.expression).isStatic) {
102
- unwrappedExpressions.push(generate(attr.value).code);
103
- }
104
- }
105
- attrValue = buildJSXTree(importAliases, attr.value.expression, unwrappedExpressions, updates, errors, warnings, file, true);
106
- }
107
- }
108
- }
109
- props[attrName] = attrValue;
110
- }
111
- });
112
- if (elementIsVariable) {
113
- parseJSXElement(importAliases, element, updates, errors, warnings, file);
114
- return {
115
- // if componentType is undefined, use typeName
116
- // Basically, if componentType is not a GT component, use typeName such as <div>
117
- type: componentType ?? typeName,
118
- props,
119
- };
120
- }
121
- const children = element.children
122
- .map((child) => buildJSXTree(importAliases, child, unwrappedExpressions, updates, errors, warnings, file, true))
123
- .filter((child) => child !== null && child !== '');
124
- if (children.length === 1) {
125
- props.children = children[0];
126
- }
127
- else if (children.length > 1) {
128
- props.children = children;
129
- }
130
- return {
131
- // if componentType is undefined, use typeName
132
- // Basically, if componentType is not a GT component, use typeName such as <div>
133
- type: componentType ?? typeName,
134
- props,
135
- };
136
- }
137
- // If it's a JSX fragment
138
- else if (t.isJSXFragment(node)) {
139
- const children = node.children
140
- .map((child) => buildJSXTree(importAliases, child, unwrappedExpressions, updates, errors, warnings, file, true))
141
- .filter((child) => child !== null && child !== '');
142
- const props = {};
143
- if (children.length === 1) {
144
- props.children = children[0];
145
- }
146
- else if (children.length > 1) {
147
- props.children = children;
148
- }
149
- return {
150
- type: '',
151
- props,
152
- };
153
- }
154
- // If it's a string literal (standalone)
155
- else if (t.isStringLiteral(node)) {
156
- return node.value;
157
- }
158
- // If it's some other JS expression
159
- else if (t.isIdentifier(node) ||
160
- t.isMemberExpression(node) ||
161
- t.isCallExpression(node) ||
162
- t.isBinaryExpression(node) ||
163
- t.isLogicalExpression(node) ||
164
- t.isConditionalExpression(node)) {
165
- return generate(node).code;
166
- }
167
- else {
168
- return generate(node).code;
169
- }
170
- }
171
- // end buildJSXTree
172
- // Parses a JSX element and adds it to the updates array
173
- export function parseJSXElement(importAliases, node, updates, errors, warnings, file) {
174
- const openingElement = node.openingElement;
175
- const name = openingElement.name;
176
- // Only proceed if it's <T> ...
177
- if (!(name.type === 'JSXIdentifier' && importAliases[name.name] === 'T')) {
178
- return;
179
- }
180
- const componentErrors = [];
181
- const componentWarnings = new Set();
182
- const metadata = {};
183
- // We'll track this flag to know if any unwrapped {variable} is found in children
184
- const unwrappedExpressions = [];
185
- // Gather <T>'s props
186
- openingElement.attributes.forEach((attr) => {
187
- if (!t.isJSXAttribute(attr))
188
- return;
189
- const attrName = attr.name.name;
190
- if (typeof attrName !== 'string')
191
- return;
192
- if (attr.value) {
193
- // If it's a plain string literal like id="hello"
194
- if (t.isStringLiteral(attr.value)) {
195
- metadata[attrName] = attr.value.value;
196
- }
197
- // If it's an expression container like id={"hello"}, id={someVar}, etc.
198
- else if (t.isJSXExpressionContainer(attr.value)) {
199
- const expr = attr.value.expression;
200
- const code = generate(expr).code;
201
- // Only check for static expressions on id and context props
202
- if (GT_ATTRIBUTES.includes(attrName)) {
203
- const staticAnalysis = isStaticExpression(expr);
204
- if (!staticAnalysis.isStatic) {
205
- componentErrors.push(warnVariablePropSync(file, attrName, code, `${expr.loc?.start?.line}:${expr.loc?.start?.column}`));
206
- }
207
- // Use the static value if available
208
- if (staticAnalysis.isStatic && staticAnalysis.value !== undefined) {
209
- metadata[mapAttributeName(attrName)] = staticAnalysis.value;
210
- }
211
- else {
212
- // Only store the code if we couldn't extract a static value
213
- metadata[attrName] = code;
214
- }
215
- }
216
- else {
217
- // For other attributes that aren't id or context
218
- metadata[attrName] = code;
219
- }
220
- }
221
- }
222
- });
223
- // Build the JSX tree for this component
224
- const treeResult = buildJSXTree(importAliases, node, unwrappedExpressions, updates, componentErrors, componentWarnings, file, false);
225
- let jsxTree = undefined;
226
- if (treeResult && typeof treeResult === 'object') {
227
- jsxTree = treeResult.props?.children;
228
- }
229
- else {
230
- jsxTree = treeResult;
231
- }
232
- if (componentWarnings.size > 0) {
233
- componentWarnings.forEach((warning) => warnings.add(warning));
234
- }
235
- if (componentErrors.length > 0) {
236
- errors.push(...componentErrors);
237
- return;
238
- }
239
- // Handle whitespace in children
240
- const whitespaceHandledTree = handleChildrenWhitespace(jsxTree);
241
- // Add GT identifiers to the tree
242
- let minifiedTree = addGTIdentifierToSyntaxTree(whitespaceHandledTree);
243
- minifiedTree =
244
- Array.isArray(minifiedTree) && minifiedTree.length === 1
245
- ? minifiedTree[0]
246
- : minifiedTree;
247
- const id = metadata.id;
248
- // If we found an unwrapped expression, skip
249
- if (unwrappedExpressions.length > 0) {
250
- errors.push(warnHasUnwrappedExpressionSync(file, unwrappedExpressions, id, `${node.loc?.start?.line}:${node.loc?.start?.column}`));
251
- return;
252
- }
253
- // <T> is valid here
254
- updates.push({
255
- dataFormat: 'JSX',
256
- source: minifiedTree,
257
- metadata,
258
- });
259
- }