gtx-cli 2.5.0-alpha.0 → 2.5.0-alpha.1
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 +13 -0
- package/dist/api/collectUserEditDiffs.d.ts +2 -7
- package/dist/api/collectUserEditDiffs.js +33 -78
- package/dist/api/downloadFileBatch.d.ts +11 -10
- package/dist/api/downloadFileBatch.js +120 -127
- package/dist/api/saveLocalEdits.js +18 -15
- package/dist/cli/base.js +1 -1
- package/dist/cli/commands/stage.d.ts +8 -2
- package/dist/cli/commands/stage.js +25 -7
- package/dist/cli/commands/translate.d.ts +4 -2
- package/dist/cli/commands/translate.js +5 -6
- package/dist/cli/flags.js +4 -1
- package/dist/config/generateSettings.js +10 -0
- package/dist/console/colors.d.ts +0 -1
- package/dist/console/colors.js +0 -3
- package/dist/console/index.d.ts +0 -6
- package/dist/console/index.js +2 -13
- package/dist/console/logging.d.ts +1 -1
- package/dist/console/logging.js +3 -4
- package/dist/formats/files/translate.d.ts +2 -2
- package/dist/formats/files/translate.js +31 -5
- package/dist/fs/config/downloadedVersions.d.ts +10 -3
- package/dist/fs/config/downloadedVersions.js +8 -0
- package/dist/fs/config/updateVersions.d.ts +2 -1
- package/dist/git/branches.d.ts +7 -0
- package/dist/git/branches.js +88 -0
- package/dist/react/{jsx/utils/jsxParsing → data-_gt}/addGTIdentifierToSyntaxTree.d.ts +1 -2
- package/dist/react/{jsx/utils/jsxParsing → data-_gt}/addGTIdentifierToSyntaxTree.js +6 -30
- package/dist/react/jsx/evaluateJsx.d.ts +6 -5
- package/dist/react/jsx/evaluateJsx.js +4 -32
- package/dist/react/jsx/trimJsxStringChildren.d.ts +7 -0
- package/dist/react/jsx/trimJsxStringChildren.js +122 -0
- package/dist/react/jsx/utils/constants.d.ts +0 -2
- package/dist/react/jsx/utils/constants.js +2 -11
- package/dist/react/jsx/utils/parseJsx.d.ts +21 -0
- package/dist/react/jsx/utils/parseJsx.js +259 -0
- package/dist/react/jsx/utils/parseStringFunction.js +141 -4
- package/dist/react/parse/createInlineUpdates.js +70 -19
- package/dist/types/branch.d.ts +14 -0
- package/dist/types/branch.js +1 -0
- package/dist/types/data.d.ts +1 -1
- package/dist/types/files.d.ts +7 -0
- package/dist/types/index.d.ts +7 -0
- package/dist/utils/SpinnerManager.d.ts +30 -0
- package/dist/utils/SpinnerManager.js +73 -0
- package/dist/utils/gitDiff.js +18 -16
- package/dist/workflow/BranchStep.d.ts +13 -0
- package/dist/workflow/BranchStep.js +131 -0
- package/dist/workflow/DownloadStep.d.ts +19 -0
- package/dist/workflow/DownloadStep.js +127 -0
- package/dist/workflow/EnqueueStep.d.ts +15 -0
- package/dist/workflow/EnqueueStep.js +33 -0
- package/dist/workflow/PollJobsStep.d.ts +31 -0
- package/dist/workflow/PollJobsStep.js +284 -0
- package/dist/workflow/SetupStep.d.ts +16 -0
- package/dist/workflow/SetupStep.js +71 -0
- package/dist/workflow/UploadStep.d.ts +21 -0
- package/dist/workflow/UploadStep.js +72 -0
- package/dist/workflow/UserEditDiffsStep.d.ts +11 -0
- package/dist/workflow/UserEditDiffsStep.js +30 -0
- package/dist/workflow/Workflow.d.ts +4 -0
- package/dist/workflow/Workflow.js +2 -0
- package/dist/workflow/download.d.ts +22 -0
- package/dist/workflow/download.js +104 -0
- package/dist/workflow/stage.d.ts +14 -0
- package/dist/workflow/stage.js +76 -0
- package/package.json +4 -5
- package/dist/api/checkFileTranslations.d.ts +0 -23
- package/dist/api/checkFileTranslations.js +0 -281
- package/dist/api/sendFiles.d.ts +0 -17
- package/dist/api/sendFiles.js +0 -127
- package/dist/api/sendUserEdits.d.ts +0 -19
- package/dist/api/sendUserEdits.js +0 -15
- package/dist/cli/commands/edits.d.ts +0 -8
- package/dist/cli/commands/edits.js +0 -32
- package/dist/react/jsx/utils/buildImportMap.d.ts +0 -9
- package/dist/react/jsx/utils/buildImportMap.js +0 -30
- package/dist/react/jsx/utils/getPathsAndAliases.d.ts +0 -17
- package/dist/react/jsx/utils/getPathsAndAliases.js +0 -89
- package/dist/react/jsx/utils/jsxParsing/handleChildrenWhitespace.d.ts +0 -6
- package/dist/react/jsx/utils/jsxParsing/handleChildrenWhitespace.js +0 -199
- package/dist/react/jsx/utils/jsxParsing/multiplication/findMultiplicationNode.d.ts +0 -13
- package/dist/react/jsx/utils/jsxParsing/multiplication/findMultiplicationNode.js +0 -42
- package/dist/react/jsx/utils/jsxParsing/multiplication/multiplyJsxTree.d.ts +0 -5
- package/dist/react/jsx/utils/jsxParsing/multiplication/multiplyJsxTree.js +0 -69
- package/dist/react/jsx/utils/jsxParsing/parseJsx.d.ts +0 -60
- package/dist/react/jsx/utils/jsxParsing/parseJsx.js +0 -949
- package/dist/react/jsx/utils/jsxParsing/parseTProps.d.ts +0 -8
- package/dist/react/jsx/utils/jsxParsing/parseTProps.js +0 -47
- package/dist/react/jsx/utils/jsxParsing/types.d.ts +0 -48
- package/dist/react/jsx/utils/jsxParsing/types.js +0 -34
- package/dist/react/jsx/utils/resolveImportPath.d.ts +0 -11
- package/dist/react/jsx/utils/resolveImportPath.js +0 -111
package/dist/api/sendFiles.js
DELETED
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
import chalk from 'chalk';
|
|
2
|
-
import { createSpinner, logErrorAndExit, logMessage, logSuccess, } from '../console/logging.js';
|
|
3
|
-
import { gt } from '../utils/gt.js';
|
|
4
|
-
import { TEMPLATE_FILE_NAME } from '../cli/commands/stage.js';
|
|
5
|
-
import { collectAndSendUserEditDiffs } from './collectUserEditDiffs.js';
|
|
6
|
-
/**
|
|
7
|
-
* Sends multiple files for translation to the API
|
|
8
|
-
* @param files - Array of file objects to translate
|
|
9
|
-
* @param options - The options for the API call
|
|
10
|
-
* @returns The translated content or version ID
|
|
11
|
-
*/
|
|
12
|
-
export async function sendFiles(files, options, settings) {
|
|
13
|
-
// Keep track of the most recent spinner so we can stop it on error
|
|
14
|
-
let currentSpinner = null;
|
|
15
|
-
logMessage(chalk.cyan('Files to translate:') +
|
|
16
|
-
'\n' +
|
|
17
|
-
files
|
|
18
|
-
.map((file) => {
|
|
19
|
-
if (file.fileName === TEMPLATE_FILE_NAME) {
|
|
20
|
-
return `- <React Elements>`;
|
|
21
|
-
}
|
|
22
|
-
return `- ${file.fileName}`;
|
|
23
|
-
})
|
|
24
|
-
.join('\n'));
|
|
25
|
-
try {
|
|
26
|
-
// Step 1: Upload files (get references)
|
|
27
|
-
const uploadSpinner = createSpinner('dots');
|
|
28
|
-
currentSpinner = uploadSpinner;
|
|
29
|
-
uploadSpinner.start(`Uploading ${files.length} file${files.length !== 1 ? 's' : ''} to General Translation API...`);
|
|
30
|
-
const sourceLocale = settings.defaultLocale;
|
|
31
|
-
if (!sourceLocale) {
|
|
32
|
-
uploadSpinner.stop(chalk.red('Missing default source locale'));
|
|
33
|
-
logErrorAndExit('sendFiles: settings.defaultLocale is required to upload source files');
|
|
34
|
-
}
|
|
35
|
-
// Convert FileToTranslate[] -> { source: FileUpload }[]
|
|
36
|
-
const uploads = files.map(({ content, fileName, fileFormat, dataFormat }) => ({
|
|
37
|
-
source: {
|
|
38
|
-
content,
|
|
39
|
-
fileName,
|
|
40
|
-
fileFormat,
|
|
41
|
-
dataFormat,
|
|
42
|
-
locale: sourceLocale,
|
|
43
|
-
},
|
|
44
|
-
}));
|
|
45
|
-
const upload = await gt.uploadSourceFiles(uploads, {
|
|
46
|
-
sourceLocale,
|
|
47
|
-
modelProvider: settings.modelProvider,
|
|
48
|
-
});
|
|
49
|
-
uploadSpinner.stop(chalk.green('Files uploaded successfully'));
|
|
50
|
-
// Calculate timeout once for setup fetching
|
|
51
|
-
// Accept number or numeric string, default to 600s
|
|
52
|
-
const timeoutVal = options?.timeout !== undefined ? Number(options.timeout) : 600;
|
|
53
|
-
const setupTimeoutMs = (Number.isFinite(timeoutVal) ? timeoutVal : 600) * 1000;
|
|
54
|
-
const setupResult = await gt.setupProject(upload.uploadedFiles, {
|
|
55
|
-
locales: settings.locales,
|
|
56
|
-
});
|
|
57
|
-
if (setupResult?.status === 'queued') {
|
|
58
|
-
const { setupJobId } = setupResult;
|
|
59
|
-
const setupSpinner = createSpinner('dots');
|
|
60
|
-
currentSpinner = setupSpinner;
|
|
61
|
-
setupSpinner.start('Setting up project...');
|
|
62
|
-
const start = Date.now();
|
|
63
|
-
const pollInterval = 2000;
|
|
64
|
-
let setupCompleted = false;
|
|
65
|
-
let setupFailedMessage = null;
|
|
66
|
-
while (true) {
|
|
67
|
-
const status = await gt.checkSetupStatus(setupJobId);
|
|
68
|
-
if (status.status === 'completed') {
|
|
69
|
-
setupCompleted = true;
|
|
70
|
-
break;
|
|
71
|
-
}
|
|
72
|
-
if (status.status === 'failed') {
|
|
73
|
-
setupFailedMessage = status.error?.message || 'Unknown error';
|
|
74
|
-
break;
|
|
75
|
-
}
|
|
76
|
-
if (Date.now() - start > setupTimeoutMs) {
|
|
77
|
-
setupFailedMessage = 'Timed out while waiting for setup generation';
|
|
78
|
-
break;
|
|
79
|
-
}
|
|
80
|
-
await new Promise((r) => setTimeout(r, pollInterval));
|
|
81
|
-
}
|
|
82
|
-
if (setupCompleted) {
|
|
83
|
-
setupSpinner.stop(chalk.green('Setup successfully completed'));
|
|
84
|
-
}
|
|
85
|
-
else {
|
|
86
|
-
setupSpinner.stop(chalk.yellow(`Setup ${setupFailedMessage ? 'failed' : 'timed out'} — proceeding without setup${setupFailedMessage ? ` (${setupFailedMessage})` : ''}`));
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
// Step 3 (optional): Prior to enqueue, detect and submit user edit diffs
|
|
90
|
-
if (options?.saveLocal) {
|
|
91
|
-
const prepSpinner = createSpinner('dots');
|
|
92
|
-
currentSpinner = prepSpinner;
|
|
93
|
-
prepSpinner.start('Updating translations...');
|
|
94
|
-
try {
|
|
95
|
-
await collectAndSendUserEditDiffs(upload.uploadedFiles, settings);
|
|
96
|
-
}
|
|
97
|
-
catch {
|
|
98
|
-
// Non-fatal; keep going to enqueue
|
|
99
|
-
}
|
|
100
|
-
finally {
|
|
101
|
-
prepSpinner.stop('Updated translations');
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
// Step 4: Enqueue translations by reference
|
|
105
|
-
const enqueueSpinner = createSpinner('dots');
|
|
106
|
-
currentSpinner = enqueueSpinner;
|
|
107
|
-
enqueueSpinner.start('Enqueuing translations...');
|
|
108
|
-
const enqueueResult = await gt.enqueueFiles(upload.uploadedFiles, {
|
|
109
|
-
sourceLocale: settings.defaultLocale,
|
|
110
|
-
targetLocales: settings.locales,
|
|
111
|
-
publish: settings.publish,
|
|
112
|
-
requireApproval: settings.stageTranslations,
|
|
113
|
-
modelProvider: settings.modelProvider,
|
|
114
|
-
force: options?.force,
|
|
115
|
-
});
|
|
116
|
-
const { data, message, locales, translations } = enqueueResult;
|
|
117
|
-
enqueueSpinner.stop(chalk.green('Files for translation uploaded successfully'));
|
|
118
|
-
logSuccess(message);
|
|
119
|
-
return { data, locales, translations };
|
|
120
|
-
}
|
|
121
|
-
catch {
|
|
122
|
-
if (currentSpinner) {
|
|
123
|
-
currentSpinner.stop();
|
|
124
|
-
}
|
|
125
|
-
logErrorAndExit('Failed to send files for translation');
|
|
126
|
-
}
|
|
127
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { Settings } from '../types/index.js';
|
|
2
|
-
export type UserEditDiff = {
|
|
3
|
-
fileName: string;
|
|
4
|
-
locale: string;
|
|
5
|
-
diff: string;
|
|
6
|
-
versionId?: string;
|
|
7
|
-
fileId?: string;
|
|
8
|
-
localContent?: string;
|
|
9
|
-
};
|
|
10
|
-
export type SendUserEditsPayload = {
|
|
11
|
-
projectId?: string;
|
|
12
|
-
diffs: UserEditDiff[];
|
|
13
|
-
};
|
|
14
|
-
/**
|
|
15
|
-
* Sends user edit diffs to the API for persistence/rule extraction.
|
|
16
|
-
* This function is intentionally decoupled from the translate pipeline
|
|
17
|
-
* so it can be called as an independent action.
|
|
18
|
-
*/
|
|
19
|
-
export declare function sendUserEditDiffs(diffs: UserEditDiff[], settings: Settings): Promise<void>;
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { gt } from '../utils/gt.js';
|
|
2
|
-
/**
|
|
3
|
-
* Sends user edit diffs to the API for persistence/rule extraction.
|
|
4
|
-
* This function is intentionally decoupled from the translate pipeline
|
|
5
|
-
* so it can be called as an independent action.
|
|
6
|
-
*/
|
|
7
|
-
export async function sendUserEditDiffs(diffs, settings) {
|
|
8
|
-
if (!diffs.length)
|
|
9
|
-
return;
|
|
10
|
-
const payload = {
|
|
11
|
-
projectId: settings.projectId,
|
|
12
|
-
diffs,
|
|
13
|
-
};
|
|
14
|
-
await gt.submitUserEditDiffs(payload);
|
|
15
|
-
}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs';
|
|
2
|
-
import { getGitUnifiedDiff } from '../../utils/gitDiff.js';
|
|
3
|
-
import { sendUserEditDiffs } from '../../api/sendUserEdits.js';
|
|
4
|
-
import { logErrorAndExit, logMessage } from '../../console/logging.js';
|
|
5
|
-
export async function handleSendDiffs(flags, settings) {
|
|
6
|
-
const { fileName, locale, old, next } = flags;
|
|
7
|
-
if (!fs.existsSync(old)) {
|
|
8
|
-
logErrorAndExit(`Old/original file not found: ${old}`);
|
|
9
|
-
}
|
|
10
|
-
if (!fs.existsSync(next)) {
|
|
11
|
-
logErrorAndExit(`New/local file not found: ${next}`);
|
|
12
|
-
}
|
|
13
|
-
let diff;
|
|
14
|
-
try {
|
|
15
|
-
diff = await getGitUnifiedDiff(old, next);
|
|
16
|
-
}
|
|
17
|
-
catch (e) {
|
|
18
|
-
logErrorAndExit('Git is required to compute diffs. Please install Git and ensure it is available on your PATH.');
|
|
19
|
-
return; // unreachable
|
|
20
|
-
}
|
|
21
|
-
if (!diff || diff.trim().length === 0) {
|
|
22
|
-
logMessage('No differences detected — nothing to send.');
|
|
23
|
-
return;
|
|
24
|
-
}
|
|
25
|
-
await sendUserEditDiffs([
|
|
26
|
-
{
|
|
27
|
-
fileName,
|
|
28
|
-
locale,
|
|
29
|
-
diff,
|
|
30
|
-
},
|
|
31
|
-
], settings);
|
|
32
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { NodePath } from '@babel/traverse';
|
|
2
|
-
/**
|
|
3
|
-
* Builds a map of imported function names to their import paths from a given program path.
|
|
4
|
-
* Handles both named imports and default imports.
|
|
5
|
-
*
|
|
6
|
-
* Example: import { getInfo } from './constants' -> Map { 'getInfo' => './constants' }
|
|
7
|
-
* Example: import utils from './utils' -> Map { 'utils' => './utils' }
|
|
8
|
-
*/
|
|
9
|
-
export declare function buildImportMap(programPath: NodePath): Map<string, string>;
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import * as t from '@babel/types';
|
|
2
|
-
/**
|
|
3
|
-
* Builds a map of imported function names to their import paths from a given program path.
|
|
4
|
-
* Handles both named imports and default imports.
|
|
5
|
-
*
|
|
6
|
-
* Example: import { getInfo } from './constants' -> Map { 'getInfo' => './constants' }
|
|
7
|
-
* Example: import utils from './utils' -> Map { 'utils' => './utils' }
|
|
8
|
-
*/
|
|
9
|
-
export function buildImportMap(programPath) {
|
|
10
|
-
const importMap = new Map();
|
|
11
|
-
programPath.traverse({
|
|
12
|
-
ImportDeclaration(importPath) {
|
|
13
|
-
if (t.isStringLiteral(importPath.node.source)) {
|
|
14
|
-
const importSource = importPath.node.source.value;
|
|
15
|
-
importPath.node.specifiers.forEach((spec) => {
|
|
16
|
-
if (t.isImportSpecifier(spec) &&
|
|
17
|
-
t.isIdentifier(spec.imported) &&
|
|
18
|
-
t.isIdentifier(spec.local)) {
|
|
19
|
-
importMap.set(spec.local.name, importSource);
|
|
20
|
-
}
|
|
21
|
-
else if (t.isImportDefaultSpecifier(spec) &&
|
|
22
|
-
t.isIdentifier(spec.local)) {
|
|
23
|
-
importMap.set(spec.local.name, importSource);
|
|
24
|
-
}
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
},
|
|
28
|
-
});
|
|
29
|
-
return importMap;
|
|
30
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { NodePath } from '@babel/traverse';
|
|
2
|
-
/**
|
|
3
|
-
*
|
|
4
|
-
*/
|
|
5
|
-
export declare function getPathsAndAliases(ast: any, pkg: 'gt-react' | 'gt-next'): {
|
|
6
|
-
importAliases: Record<string, string>;
|
|
7
|
-
inlineTranslationPaths: Array<{
|
|
8
|
-
localName: string;
|
|
9
|
-
path: NodePath;
|
|
10
|
-
originalName: string;
|
|
11
|
-
}>;
|
|
12
|
-
translationComponentPaths: Array<{
|
|
13
|
-
localName: string;
|
|
14
|
-
path: NodePath;
|
|
15
|
-
originalName: string;
|
|
16
|
-
}>;
|
|
17
|
-
};
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
import traverseModule from '@babel/traverse';
|
|
2
|
-
import { GT_TRANSLATION_FUNCS, INLINE_TRANSLATION_HOOK, INLINE_TRANSLATION_HOOK_ASYNC, INLINE_MESSAGE_HOOK, INLINE_MESSAGE_HOOK_ASYNC, MSG_TRANSLATION_HOOK, TRANSLATION_COMPONENT, } from '../../jsx/utils/constants.js';
|
|
3
|
-
import { extractImportName } from './parseAst.js';
|
|
4
|
-
// Handle CommonJS/ESM interop
|
|
5
|
-
const traverse = traverseModule.default || traverseModule;
|
|
6
|
-
/**
|
|
7
|
-
*
|
|
8
|
-
*/
|
|
9
|
-
export function getPathsAndAliases(ast, pkg) {
|
|
10
|
-
// First pass: collect imports and process translation functions
|
|
11
|
-
const importAliases = {};
|
|
12
|
-
const inlineTranslationPaths = [];
|
|
13
|
-
const translationComponentPaths = [];
|
|
14
|
-
traverse(ast, {
|
|
15
|
-
ImportDeclaration(path) {
|
|
16
|
-
if (path.node.source.value.startsWith(pkg)) {
|
|
17
|
-
const importName = extractImportName(path.node, pkg, GT_TRANSLATION_FUNCS);
|
|
18
|
-
for (const name of importName) {
|
|
19
|
-
if (name.original === INLINE_TRANSLATION_HOOK ||
|
|
20
|
-
name.original === INLINE_TRANSLATION_HOOK_ASYNC ||
|
|
21
|
-
name.original === INLINE_MESSAGE_HOOK ||
|
|
22
|
-
name.original === INLINE_MESSAGE_HOOK_ASYNC ||
|
|
23
|
-
name.original === MSG_TRANSLATION_HOOK) {
|
|
24
|
-
inlineTranslationPaths.push({
|
|
25
|
-
localName: name.local,
|
|
26
|
-
path,
|
|
27
|
-
originalName: name.original,
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
else if (name.original === TRANSLATION_COMPONENT) {
|
|
31
|
-
translationComponentPaths.push({
|
|
32
|
-
localName: name.local,
|
|
33
|
-
path,
|
|
34
|
-
originalName: name.original,
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
else {
|
|
38
|
-
importAliases[name.local] = name.original;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
},
|
|
43
|
-
VariableDeclarator(path) {
|
|
44
|
-
// Check if the init is a require call
|
|
45
|
-
if (path.node.init?.type === 'CallExpression' &&
|
|
46
|
-
path.node.init.callee.type === 'Identifier' &&
|
|
47
|
-
path.node.init.callee.name === 'require') {
|
|
48
|
-
// Check if it's requiring our package
|
|
49
|
-
const args = path.node.init.arguments;
|
|
50
|
-
if (args.length === 1 &&
|
|
51
|
-
args[0].type === 'StringLiteral' &&
|
|
52
|
-
args[0].value.startsWith(pkg)) {
|
|
53
|
-
const parentPath = path.parentPath;
|
|
54
|
-
if (parentPath.isVariableDeclaration()) {
|
|
55
|
-
const importName = extractImportName(parentPath.node, pkg, GT_TRANSLATION_FUNCS);
|
|
56
|
-
for (const name of importName) {
|
|
57
|
-
if (name.original === INLINE_TRANSLATION_HOOK ||
|
|
58
|
-
name.original === INLINE_TRANSLATION_HOOK_ASYNC ||
|
|
59
|
-
name.original === INLINE_MESSAGE_HOOK ||
|
|
60
|
-
name.original === INLINE_MESSAGE_HOOK_ASYNC ||
|
|
61
|
-
name.original === MSG_TRANSLATION_HOOK) {
|
|
62
|
-
inlineTranslationPaths.push({
|
|
63
|
-
localName: name.local,
|
|
64
|
-
path: parentPath,
|
|
65
|
-
originalName: name.original,
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
|
-
else if (name.original === TRANSLATION_COMPONENT) {
|
|
69
|
-
translationComponentPaths.push({
|
|
70
|
-
localName: name.local,
|
|
71
|
-
path: parentPath,
|
|
72
|
-
originalName: name.original,
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
else {
|
|
76
|
-
importAliases[name.local] = name.original;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
},
|
|
83
|
-
});
|
|
84
|
-
return {
|
|
85
|
-
importAliases,
|
|
86
|
-
inlineTranslationPaths,
|
|
87
|
-
translationComponentPaths,
|
|
88
|
-
};
|
|
89
|
-
}
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import { JsxTree, MultiplicationNode, WhitespaceJsxTreeResult, WhitespaceMultiplicationNode } from './types.js';
|
|
2
|
-
export declare function trimJsxStringChild(child: string, index: number, childrenTypes: ('expression' | 'text' | 'element' | 'multiplication' | 'other')[]): string;
|
|
3
|
-
export declare function handleChildrenWhitespace(currentTree: MultiplicationNode['branches'], parentNodeType: 'multiplication'): (WhitespaceJsxTreeResult | WhitespaceMultiplicationNode)[];
|
|
4
|
-
export declare function handleChildrenWhitespace(currentTree: MultiplicationNode['branches'], parentNodeType?: 'element' | 'expression' | undefined): WhitespaceJsxTreeResult | WhitespaceMultiplicationNode | (WhitespaceJsxTreeResult | WhitespaceMultiplicationNode)[];
|
|
5
|
-
export declare function handleChildrenWhitespace(currentTree: MultiplicationNode | JsxTree, parentNodeType?: 'multiplication' | 'element' | 'expression' | undefined): null | WhitespaceJsxTreeResult | WhitespaceMultiplicationNode;
|
|
6
|
-
export declare function handleChildrenWhitespace(currentTree: JsxTree | JsxTree[]): null | WhitespaceJsxTreeResult | WhitespaceJsxTreeResult[];
|
|
@@ -1,199 +0,0 @@
|
|
|
1
|
-
import { isAcceptedPluralForm } from 'generaltranslation/internal';
|
|
2
|
-
import { isElementNode, isExpressionNode, isMultiplicationNode, } from './types.js';
|
|
3
|
-
// JSX whitespace characters (space, tab, newline, carriage return)
|
|
4
|
-
// Does NOT include non-breaking space (U+00A0) which should be preserved
|
|
5
|
-
const isJsxWhitespace = (char) => {
|
|
6
|
-
return char === ' ' || char === '\t' || char === '\n' || char === '\r';
|
|
7
|
-
};
|
|
8
|
-
const trimJsxWhitespace = (str, side = 'both') => {
|
|
9
|
-
let start = 0;
|
|
10
|
-
let end = str.length;
|
|
11
|
-
if (side === 'start' || side === 'both') {
|
|
12
|
-
while (start < end && isJsxWhitespace(str[start])) {
|
|
13
|
-
start++;
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
if (side === 'end' || side === 'both') {
|
|
17
|
-
while (end > start && isJsxWhitespace(str[end - 1])) {
|
|
18
|
-
end--;
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
return str.slice(start, end);
|
|
22
|
-
};
|
|
23
|
-
const hasNonJsxWhitespace = (str) => {
|
|
24
|
-
for (const char of str) {
|
|
25
|
-
if (!isJsxWhitespace(char))
|
|
26
|
-
return true;
|
|
27
|
-
}
|
|
28
|
-
return false;
|
|
29
|
-
};
|
|
30
|
-
export function trimJsxStringChild(child, index, childrenTypes) {
|
|
31
|
-
if (!child.includes('\n') && !child.includes('\r')) {
|
|
32
|
-
return child;
|
|
33
|
-
}
|
|
34
|
-
// Normalize line endings to \n for consistency across platforms
|
|
35
|
-
let result = child.replace(/\r\n|\r/g, '\n');
|
|
36
|
-
// Collapse multiple spaces/tabs into a single space (but not nbsp)
|
|
37
|
-
result = result.replace(/[\t ]+/g, ' ');
|
|
38
|
-
let newResult = '';
|
|
39
|
-
let newline = false;
|
|
40
|
-
for (const char of result) {
|
|
41
|
-
if (char === '\n') {
|
|
42
|
-
if (hasNonJsxWhitespace(newResult))
|
|
43
|
-
newResult += ' ';
|
|
44
|
-
else
|
|
45
|
-
newResult = '';
|
|
46
|
-
newline = true;
|
|
47
|
-
continue;
|
|
48
|
-
}
|
|
49
|
-
if (!newline) {
|
|
50
|
-
newResult += char;
|
|
51
|
-
continue;
|
|
52
|
-
}
|
|
53
|
-
if (isJsxWhitespace(char))
|
|
54
|
-
continue;
|
|
55
|
-
newResult += char;
|
|
56
|
-
newline = false;
|
|
57
|
-
}
|
|
58
|
-
if (newline)
|
|
59
|
-
newResult = trimJsxWhitespace(newResult, 'end');
|
|
60
|
-
result = newResult;
|
|
61
|
-
// Collapse multiple spaces/tabs into a single space (but not nbsp)
|
|
62
|
-
result = result.replace(/[\t ]+/g, ' ');
|
|
63
|
-
return result;
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* Handles whitespace in children of a JSX element, and strips elements
|
|
67
|
-
* @param currentTree - The current tree to handle
|
|
68
|
-
* @returns The processed tree with whitespace handled
|
|
69
|
-
*
|
|
70
|
-
* For unresolved functions, we just make it so that Static has no children
|
|
71
|
-
*
|
|
72
|
-
* The typing was so much worse before this. Don't come for me. All I did was enforce the typing.
|
|
73
|
-
*/
|
|
74
|
-
export function handleChildrenWhitespace(currentTree, parentNodeType = undefined) {
|
|
75
|
-
if (Array.isArray(currentTree)) {
|
|
76
|
-
const childrenTypes = currentTree.map((child) => {
|
|
77
|
-
if (typeof child === 'string')
|
|
78
|
-
return 'text';
|
|
79
|
-
if (isExpressionNode(child))
|
|
80
|
-
return 'expression';
|
|
81
|
-
if (isElementNode(child))
|
|
82
|
-
return 'element';
|
|
83
|
-
if (isMultiplicationNode(child))
|
|
84
|
-
return 'multiplication';
|
|
85
|
-
return 'other';
|
|
86
|
-
});
|
|
87
|
-
const newChildren = [];
|
|
88
|
-
currentTree.forEach((child, index) => {
|
|
89
|
-
switch (childrenTypes[index]) {
|
|
90
|
-
case 'text':
|
|
91
|
-
const textNode = child;
|
|
92
|
-
if (parentNodeType === 'multiplication') {
|
|
93
|
-
// This should be treated like a new tree (no parent here b/c its a new tree)
|
|
94
|
-
const result = handleChildrenWhitespace(textNode);
|
|
95
|
-
if (result)
|
|
96
|
-
newChildren.push(result);
|
|
97
|
-
}
|
|
98
|
-
else {
|
|
99
|
-
const string = trimJsxStringChild(textNode, index, childrenTypes);
|
|
100
|
-
if (string)
|
|
101
|
-
newChildren.push(string);
|
|
102
|
-
}
|
|
103
|
-
break;
|
|
104
|
-
case 'expression':
|
|
105
|
-
// Strip expressions
|
|
106
|
-
const result = child.result;
|
|
107
|
-
if (isMultiplicationNode(result)) {
|
|
108
|
-
newChildren.push(handleChildrenWhitespace(result));
|
|
109
|
-
}
|
|
110
|
-
else if (typeof result === 'string') {
|
|
111
|
-
newChildren.push(result);
|
|
112
|
-
}
|
|
113
|
-
else {
|
|
114
|
-
// other case
|
|
115
|
-
newChildren.push(result);
|
|
116
|
-
}
|
|
117
|
-
break;
|
|
118
|
-
case 'element':
|
|
119
|
-
const newElement = handleChildrenWhitespace(child);
|
|
120
|
-
newChildren.push(newElement);
|
|
121
|
-
break;
|
|
122
|
-
case 'multiplication':
|
|
123
|
-
// I dont think this case is possible, at least in the array case
|
|
124
|
-
// Can only be child of element or multiplication nodes
|
|
125
|
-
newChildren.push({
|
|
126
|
-
nodeType: 'multiplication',
|
|
127
|
-
branches: handleChildrenWhitespace(child.branches, 'multiplication'),
|
|
128
|
-
});
|
|
129
|
-
break;
|
|
130
|
-
case 'other':
|
|
131
|
-
// Return number or boolean or null
|
|
132
|
-
newChildren.push(child);
|
|
133
|
-
break;
|
|
134
|
-
}
|
|
135
|
-
});
|
|
136
|
-
if (parentNodeType === 'multiplication') {
|
|
137
|
-
// Return the branches as an array
|
|
138
|
-
return newChildren;
|
|
139
|
-
}
|
|
140
|
-
return newChildren.length === 1 ? newChildren[0] : newChildren;
|
|
141
|
-
}
|
|
142
|
-
else if (isElementNode(currentTree)) {
|
|
143
|
-
// Process all props recursively
|
|
144
|
-
// What if there is a different component sharing the same name?
|
|
145
|
-
const elementIsPlural = currentTree.type === 'Plural';
|
|
146
|
-
const elementIsBranch = currentTree.type === 'Branch';
|
|
147
|
-
const processedProps = !currentTree.props
|
|
148
|
-
? undefined
|
|
149
|
-
: Object.fromEntries(Object.entries(currentTree.props).map(([key, value]) => {
|
|
150
|
-
let shouldProcess = false;
|
|
151
|
-
// Process children
|
|
152
|
-
if (key === 'children')
|
|
153
|
-
shouldProcess = true;
|
|
154
|
-
// Process plural children
|
|
155
|
-
if (elementIsPlural && isAcceptedPluralForm(key))
|
|
156
|
-
shouldProcess = true;
|
|
157
|
-
// Process branch children
|
|
158
|
-
if (elementIsBranch && key !== 'branch')
|
|
159
|
-
shouldProcess = true;
|
|
160
|
-
// Do not process raw strings
|
|
161
|
-
if (typeof value === 'string' && key !== 'children')
|
|
162
|
-
shouldProcess = false;
|
|
163
|
-
// Process props
|
|
164
|
-
if (!shouldProcess) {
|
|
165
|
-
return [key, value];
|
|
166
|
-
}
|
|
167
|
-
return [key, handleChildrenWhitespace(value)];
|
|
168
|
-
}));
|
|
169
|
-
return {
|
|
170
|
-
nodeType: 'element',
|
|
171
|
-
type: currentTree.type,
|
|
172
|
-
...(processedProps ? { props: processedProps } : {}),
|
|
173
|
-
};
|
|
174
|
-
}
|
|
175
|
-
else if (isExpressionNode(currentTree)) {
|
|
176
|
-
// Strip expression
|
|
177
|
-
const result = currentTree.result;
|
|
178
|
-
if (isMultiplicationNode(result)) {
|
|
179
|
-
return handleChildrenWhitespace(result);
|
|
180
|
-
}
|
|
181
|
-
else if (typeof result === 'string') {
|
|
182
|
-
return result;
|
|
183
|
-
}
|
|
184
|
-
else {
|
|
185
|
-
return result;
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
else if (isMultiplicationNode(currentTree)) {
|
|
189
|
-
return {
|
|
190
|
-
nodeType: 'multiplication',
|
|
191
|
-
branches: handleChildrenWhitespace(currentTree.branches, 'multiplication'),
|
|
192
|
-
};
|
|
193
|
-
}
|
|
194
|
-
else if (typeof currentTree === 'string') {
|
|
195
|
-
return trimJsxStringChild(currentTree, 0, ['text']);
|
|
196
|
-
}
|
|
197
|
-
// null or number or boolean
|
|
198
|
-
return currentTree;
|
|
199
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { WhitespaceJsxTreeResult, WhitespaceMultiplicationNode } from '../types.js';
|
|
2
|
-
export type MultiplicationNodeResult = {
|
|
3
|
-
parent: any | undefined;
|
|
4
|
-
key: string | undefined;
|
|
5
|
-
node: WhitespaceMultiplicationNode;
|
|
6
|
-
};
|
|
7
|
-
/**
|
|
8
|
-
* Finds the immediate multiplication node from the given root (eg no nested multiplication nodes)
|
|
9
|
-
* TODO: I am sure there is some optimization to be done here
|
|
10
|
-
*
|
|
11
|
-
* Maybe there is an optimization here with caching used paths btwn calls
|
|
12
|
-
*/
|
|
13
|
-
export declare function findMultiplicationNode(root: WhitespaceJsxTreeResult | WhitespaceMultiplicationNode | (WhitespaceJsxTreeResult | WhitespaceMultiplicationNode)[]): MultiplicationNodeResult | undefined;
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { isWhitespaceMultiplicationNode, isWhitespaceJsxTree, } from '../types.js';
|
|
2
|
-
/**
|
|
3
|
-
* Finds the immediate multiplication node from the given root (eg no nested multiplication nodes)
|
|
4
|
-
* TODO: I am sure there is some optimization to be done here
|
|
5
|
-
*
|
|
6
|
-
* Maybe there is an optimization here with caching used paths btwn calls
|
|
7
|
-
*/
|
|
8
|
-
export function findMultiplicationNode(root) {
|
|
9
|
-
// Entry point
|
|
10
|
-
return handleChildren(root, undefined, undefined);
|
|
11
|
-
// Helper function to handle children
|
|
12
|
-
function handleChildren(curr, parent, key) {
|
|
13
|
-
if (Array.isArray(curr)) {
|
|
14
|
-
for (const [index, child] of Object.entries(curr)) {
|
|
15
|
-
const result = handleChild(child, parent, index);
|
|
16
|
-
if (result)
|
|
17
|
-
return result;
|
|
18
|
-
}
|
|
19
|
-
return undefined;
|
|
20
|
-
}
|
|
21
|
-
else {
|
|
22
|
-
return handleChild(curr, parent, key);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
// Helper function to handle a single child
|
|
26
|
-
function handleChild(curr, parent, key) {
|
|
27
|
-
if (isWhitespaceMultiplicationNode(curr)) {
|
|
28
|
-
return { parent, key, node: curr };
|
|
29
|
-
}
|
|
30
|
-
else if (isWhitespaceJsxTree(curr)) {
|
|
31
|
-
if (curr.props?.children) {
|
|
32
|
-
return handleChildren(curr.props.children, curr.props, 'children');
|
|
33
|
-
}
|
|
34
|
-
else {
|
|
35
|
-
return undefined;
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
else {
|
|
39
|
-
return undefined;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
}
|