gtx-cli 2.6.31 → 2.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +4 -1261
- package/README.md +12 -3
- package/dist/bin/bin-entry.js +2 -1
- package/dist/config/generateSettings.d.ts +1 -9
- package/dist/config/generateSettings.js +1 -214
- package/dist/config/resolveConfig.d.ts +1 -4
- package/dist/config/resolveConfig.js +1 -33
- package/dist/fs/config/setupConfig.d.ts +1 -17
- package/dist/fs/config/setupConfig.js +1 -50
- package/dist/fs/matchFiles.d.ts +1 -1
- package/dist/fs/matchFiles.js +1 -8
- package/dist/functions.d.ts +1 -7
- package/dist/functions.js +1 -6
- package/dist/index.d.ts +1 -4
- package/dist/index.js +1 -27
- package/dist/main.js +2 -2
- package/dist/next/parse/handleInitGT.d.ts +1 -7
- package/dist/next/parse/handleInitGT.js +1 -157
- package/dist/next/parse/wrapContent.d.ts +1 -12
- package/dist/next/parse/wrapContent.js +1 -164
- package/dist/react/parse/wrapContent.d.ts +1 -12
- package/dist/react/parse/wrapContent.js +1 -162
- package/dist/types/index.d.ts +1 -243
- package/dist/types/index.js +1 -1
- package/dist/utils/installPackage.d.ts +1 -3
- package/dist/utils/installPackage.js +1 -77
- package/dist/utils/packageInfo.d.ts +1 -3
- package/dist/utils/packageInfo.js +1 -17
- package/dist/utils/packageJson.d.ts +1 -6
- package/dist/utils/packageJson.js +1 -68
- package/dist/utils/packageManager.d.ts +1 -28
- package/dist/utils/packageManager.js +1 -269
- package/package.json +11 -97
- package/dist/api/collectUserEditDiffs.d.ts +0 -9
- package/dist/api/collectUserEditDiffs.js +0 -159
- package/dist/api/downloadFileBatch.d.ts +0 -23
- package/dist/api/downloadFileBatch.js +0 -190
- package/dist/api/saveLocalEdits.d.ts +0 -6
- package/dist/api/saveLocalEdits.js +0 -38
- package/dist/cli/base.d.ts +0 -59
- package/dist/cli/base.js +0 -529
- package/dist/cli/commands/download.d.ts +0 -8
- package/dist/cli/commands/download.js +0 -51
- package/dist/cli/commands/enqueue.d.ts +0 -9
- package/dist/cli/commands/enqueue.js +0 -27
- package/dist/cli/commands/setupProject.d.ts +0 -7
- package/dist/cli/commands/setupProject.js +0 -37
- package/dist/cli/commands/stage.d.ts +0 -9
- package/dist/cli/commands/stage.js +0 -59
- package/dist/cli/commands/translate.d.ts +0 -7
- package/dist/cli/commands/translate.js +0 -70
- package/dist/cli/commands/upload.d.ts +0 -13
- package/dist/cli/commands/upload.js +0 -142
- package/dist/cli/commands/utils/validation.d.ts +0 -13
- package/dist/cli/commands/utils/validation.js +0 -38
- package/dist/cli/flags.d.ts +0 -15
- package/dist/cli/flags.js +0 -70
- package/dist/cli/inline.d.ts +0 -17
- package/dist/cli/inline.js +0 -135
- package/dist/cli/next.d.ts +0 -10
- package/dist/cli/next.js +0 -12
- package/dist/cli/node.d.ts +0 -10
- package/dist/cli/node.js +0 -9
- package/dist/cli/react.d.ts +0 -12
- package/dist/cli/react.js +0 -72
- package/dist/config/optionPresets.d.ts +0 -3
- package/dist/config/optionPresets.js +0 -65
- package/dist/config/utils.d.ts +0 -2
- package/dist/config/utils.js +0 -4
- package/dist/config/validateSettings.d.ts +0 -3
- package/dist/config/validateSettings.js +0 -32
- package/dist/console/colors.d.ts +0 -6
- package/dist/console/colors.js +0 -19
- package/dist/console/displayTranslateSummary.d.ts +0 -1
- package/dist/console/displayTranslateSummary.js +0 -42
- package/dist/console/formatting.d.ts +0 -1
- package/dist/console/formatting.js +0 -7
- package/dist/console/index.d.ts +0 -34
- package/dist/console/index.js +0 -46
- package/dist/console/logger.d.ts +0 -35
- package/dist/console/logger.js +0 -250
- package/dist/console/logging.d.ts +0 -52
- package/dist/console/logging.js +0 -175
- package/dist/formats/files/aggregateFiles.d.ts +0 -4
- package/dist/formats/files/aggregateFiles.js +0 -156
- package/dist/formats/files/collectFiles.d.ts +0 -6
- package/dist/formats/files/collectFiles.js +0 -49
- package/dist/formats/files/convertToFileTranslationData.d.ts +0 -15
- package/dist/formats/files/convertToFileTranslationData.js +0 -21
- package/dist/formats/files/fileMapping.d.ts +0 -11
- package/dist/formats/files/fileMapping.js +0 -115
- package/dist/formats/files/preprocess/mdx.d.ts +0 -6
- package/dist/formats/files/preprocess/mdx.js +0 -14
- package/dist/formats/files/preprocess/mintlify.d.ts +0 -5
- package/dist/formats/files/preprocess/mintlify.js +0 -15
- package/dist/formats/files/preprocessContent.d.ts +0 -8
- package/dist/formats/files/preprocessContent.js +0 -23
- package/dist/formats/files/save.d.ts +0 -5
- package/dist/formats/files/save.js +0 -17
- package/dist/formats/files/supportedFiles.d.ts +0 -11
- package/dist/formats/files/supportedFiles.js +0 -20
- package/dist/formats/json/extractJson.d.ts +0 -15
- package/dist/formats/json/extractJson.js +0 -101
- package/dist/formats/json/flattenJson.d.ts +0 -14
- package/dist/formats/json/flattenJson.js +0 -64
- package/dist/formats/json/mergeJson.d.ts +0 -13
- package/dist/formats/json/mergeJson.js +0 -367
- package/dist/formats/json/parseJson.d.ts +0 -2
- package/dist/formats/json/parseJson.js +0 -109
- package/dist/formats/json/utils.d.ts +0 -47
- package/dist/formats/json/utils.js +0 -150
- package/dist/formats/utils.d.ts +0 -2
- package/dist/formats/utils.js +0 -24
- package/dist/formats/yaml/mergeYaml.d.ts +0 -5
- package/dist/formats/yaml/mergeYaml.js +0 -61
- package/dist/formats/yaml/parseYaml.d.ts +0 -5
- package/dist/formats/yaml/parseYaml.js +0 -24
- package/dist/formats/yaml/utils.d.ts +0 -2
- package/dist/formats/yaml/utils.js +0 -23
- package/dist/fs/clearLocaleDirs.d.ts +0 -8
- package/dist/fs/clearLocaleDirs.js +0 -126
- package/dist/fs/config/downloadedVersions.d.ts +0 -21
- package/dist/fs/config/downloadedVersions.js +0 -50
- package/dist/fs/config/loadConfig.d.ts +0 -1
- package/dist/fs/config/loadConfig.js +0 -9
- package/dist/fs/config/parseFilesConfig.d.ts +0 -27
- package/dist/fs/config/parseFilesConfig.js +0 -150
- package/dist/fs/config/updateConfig.d.ts +0 -21
- package/dist/fs/config/updateConfig.js +0 -57
- package/dist/fs/config/updateVersions.d.ts +0 -11
- package/dist/fs/config/updateVersions.js +0 -30
- package/dist/fs/copyFile.d.ts +0 -7
- package/dist/fs/copyFile.js +0 -39
- package/dist/fs/createLoadTranslationsFile.d.ts +0 -1
- package/dist/fs/createLoadTranslationsFile.js +0 -49
- package/dist/fs/determineFramework.d.ts +0 -5
- package/dist/fs/determineFramework.js +0 -53
- package/dist/fs/findFilepath.d.ts +0 -36
- package/dist/fs/findFilepath.js +0 -90
- package/dist/fs/index.d.ts +0 -1
- package/dist/fs/index.js +0 -1
- package/dist/fs/loadJSON.d.ts +0 -6
- package/dist/fs/loadJSON.js +0 -17
- package/dist/fs/saveJSON.d.ts +0 -1
- package/dist/fs/saveJSON.js +0 -7
- package/dist/fs/utils.d.ts +0 -1
- package/dist/fs/utils.js +0 -16
- package/dist/generated/version.d.ts +0 -1
- package/dist/generated/version.js +0 -2
- package/dist/git/branches.d.ts +0 -7
- package/dist/git/branches.js +0 -88
- package/dist/hooks/postProcess.d.ts +0 -4
- package/dist/hooks/postProcess.js +0 -110
- package/dist/locadex/setupFlow.d.ts +0 -2
- package/dist/locadex/setupFlow.js +0 -9
- package/dist/next/config/parseNextConfig.d.ts +0 -10
- package/dist/next/config/parseNextConfig.js +0 -53
- package/dist/next/jsx/utils.d.ts +0 -7
- package/dist/next/jsx/utils.js +0 -42
- package/dist/react/config/createESBuildConfig.d.ts +0 -2
- package/dist/react/config/createESBuildConfig.js +0 -119
- package/dist/react/jsx/evaluateJsx.d.ts +0 -24
- package/dist/react/jsx/evaluateJsx.js +0 -123
- package/dist/react/jsx/utils/buildImportMap.d.ts +0 -9
- package/dist/react/jsx/utils/buildImportMap.js +0 -30
- package/dist/react/jsx/utils/constants.d.ts +0 -15
- package/dist/react/jsx/utils/constants.js +0 -49
- package/dist/react/jsx/utils/getCalleeNameFromExpression.d.ts +0 -9
- package/dist/react/jsx/utils/getCalleeNameFromExpression.js +0 -32
- package/dist/react/jsx/utils/getPathsAndAliases.d.ts +0 -21
- package/dist/react/jsx/utils/getPathsAndAliases.js +0 -91
- package/dist/react/jsx/utils/isNumberLiteral.d.ts +0 -7
- package/dist/react/jsx/utils/isNumberLiteral.js +0 -13
- package/dist/react/jsx/utils/jsxParsing/addGTIdentifierToSyntaxTree.d.ts +0 -9
- package/dist/react/jsx/utils/jsxParsing/addGTIdentifierToSyntaxTree.js +0 -138
- package/dist/react/jsx/utils/jsxParsing/handleChildrenWhitespace.d.ts +0 -6
- package/dist/react/jsx/utils/jsxParsing/handleChildrenWhitespace.js +0 -197
- 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 -33
- package/dist/react/jsx/utils/jsxParsing/parseJsx.js +0 -918
- package/dist/react/jsx/utils/jsxParsing/parseTProps.d.ts +0 -8
- package/dist/react/jsx/utils/jsxParsing/parseTProps.js +0 -65
- package/dist/react/jsx/utils/jsxParsing/removeNullChildrenFields.d.ts +0 -2
- package/dist/react/jsx/utils/jsxParsing/removeNullChildrenFields.js +0 -61
- 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/mapAttributeName.d.ts +0 -11
- package/dist/react/jsx/utils/mapAttributeName.js +0 -12
- package/dist/react/jsx/utils/parseAst.d.ts +0 -31
- package/dist/react/jsx/utils/parseAst.js +0 -278
- package/dist/react/jsx/utils/parseDeclareStatic.d.ts +0 -15
- package/dist/react/jsx/utils/parseDeclareStatic.js +0 -540
- package/dist/react/jsx/utils/parseString.d.ts +0 -25
- package/dist/react/jsx/utils/parseString.js +0 -540
- package/dist/react/jsx/utils/parseStringFunction.d.ts +0 -30
- package/dist/react/jsx/utils/parseStringFunction.js +0 -348
- package/dist/react/jsx/utils/resolveImportPath.d.ts +0 -11
- package/dist/react/jsx/utils/resolveImportPath.js +0 -111
- package/dist/react/jsx/utils/stringParsing/processTranslationCall/extractStringEntryMetadata.d.ts +0 -29
- package/dist/react/jsx/utils/stringParsing/processTranslationCall/extractStringEntryMetadata.js +0 -86
- package/dist/react/jsx/utils/stringParsing/processTranslationCall/handleInvalidTranslationCall.d.ts +0 -14
- package/dist/react/jsx/utils/stringParsing/processTranslationCall/handleInvalidTranslationCall.js +0 -24
- package/dist/react/jsx/utils/stringParsing/processTranslationCall/handleLiteralTranslationCall.d.ts +0 -19
- package/dist/react/jsx/utils/stringParsing/processTranslationCall/handleLiteralTranslationCall.js +0 -31
- package/dist/react/jsx/utils/stringParsing/processTranslationCall/handleStaticTranslationCall.d.ts +0 -22
- package/dist/react/jsx/utils/stringParsing/processTranslationCall/handleStaticTranslationCall.js +0 -51
- package/dist/react/jsx/utils/stringParsing/processTranslationCall/index.d.ts +0 -18
- package/dist/react/jsx/utils/stringParsing/processTranslationCall/index.js +0 -39
- package/dist/react/jsx/utils/stringParsing/processTranslationCall/routeTranslationCall.d.ts +0 -24
- package/dist/react/jsx/utils/stringParsing/processTranslationCall/routeTranslationCall.js +0 -68
- package/dist/react/jsx/utils/stringParsing/types.d.ts +0 -41
- package/dist/react/jsx/utils/stringParsing/types.js +0 -1
- package/dist/react/jsx/utils/types.d.ts +0 -14
- package/dist/react/jsx/utils/types.js +0 -1
- package/dist/react/jsx/utils/validateStringFunction.d.ts +0 -7
- package/dist/react/jsx/utils/validateStringFunction.js +0 -31
- package/dist/react/jsx/wrapJsx.d.ts +0 -51
- package/dist/react/jsx/wrapJsx.js +0 -387
- package/dist/react/parse/addVitePlugin/index.d.ts +0 -22
- package/dist/react/parse/addVitePlugin/index.js +0 -41
- package/dist/react/parse/addVitePlugin/installCompiler.d.ts +0 -8
- package/dist/react/parse/addVitePlugin/installCompiler.js +0 -22
- package/dist/react/parse/addVitePlugin/updateViteConfig.d.ts +0 -19
- package/dist/react/parse/addVitePlugin/updateViteConfig.js +0 -120
- package/dist/react/parse/addVitePlugin/utils/addCompilerImport.d.ts +0 -9
- package/dist/react/parse/addVitePlugin/utils/addCompilerImport.js +0 -34
- package/dist/react/parse/addVitePlugin/utils/addPluginInvocation.d.ts +0 -11
- package/dist/react/parse/addVitePlugin/utils/addPluginInvocation.js +0 -48
- package/dist/react/parse/addVitePlugin/utils/checkCompilerImport.d.ts +0 -15
- package/dist/react/parse/addVitePlugin/utils/checkCompilerImport.js +0 -113
- package/dist/react/parse/addVitePlugin/utils/checkPluginInvocation.d.ts +0 -12
- package/dist/react/parse/addVitePlugin/utils/checkPluginInvocation.js +0 -32
- package/dist/react/parse/createDictionaryUpdates.d.ts +0 -3
- package/dist/react/parse/createDictionaryUpdates.js +0 -187
- package/dist/react/parse/createInlineUpdates.d.ts +0 -13
- package/dist/react/parse/createInlineUpdates.js +0 -161
- package/dist/react/utils/flattenDictionary.d.ts +0 -20
- package/dist/react/utils/flattenDictionary.js +0 -75
- package/dist/react/utils/getEntryAndMetadata.d.ts +0 -5
- package/dist/react/utils/getEntryAndMetadata.js +0 -11
- package/dist/react/utils/getVariableName.d.ts +0 -25
- package/dist/react/utils/getVariableName.js +0 -37
- package/dist/setup/agentInstructions.d.ts +0 -24
- package/dist/setup/agentInstructions.js +0 -138
- package/dist/setup/detectFramework.d.ts +0 -31
- package/dist/setup/detectFramework.js +0 -106
- package/dist/setup/frameworkUtils.d.ts +0 -3
- package/dist/setup/frameworkUtils.js +0 -30
- package/dist/setup/instructions/base.md +0 -29
- package/dist/setup/instructions/gt-next.md +0 -107
- package/dist/setup/instructions/gt-react.md +0 -98
- package/dist/setup/userInput.d.ts +0 -4
- package/dist/setup/userInput.js +0 -32
- package/dist/setup/wizard.d.ts +0 -3
- package/dist/setup/wizard.js +0 -147
- package/dist/state/recentDownloads.d.ts +0 -12
- package/dist/state/recentDownloads.js +0 -18
- package/dist/state/translateWarnings.d.ts +0 -10
- package/dist/state/translateWarnings.js +0 -13
- package/dist/translation/parse.d.ts +0 -17
- package/dist/translation/parse.js +0 -77
- package/dist/translation/stage.d.ts +0 -3
- package/dist/translation/stage.js +0 -44
- package/dist/translation/validate.d.ts +0 -14
- package/dist/translation/validate.js +0 -100
- package/dist/types/branch.d.ts +0 -14
- package/dist/types/branch.js +0 -1
- package/dist/types/data/json.d.ts +0 -6
- package/dist/types/data/json.js +0 -1
- package/dist/types/data.d.ts +0 -37
- package/dist/types/data.js +0 -1
- package/dist/types/files.d.ts +0 -8
- package/dist/types/files.js +0 -1
- package/dist/types/libraries.d.ts +0 -31
- package/dist/types/libraries.js +0 -72
- package/dist/types/parsing.d.ts +0 -3
- package/dist/types/parsing.js +0 -1
- package/dist/utils/addExplicitAnchorIds.d.ts +0 -24
- package/dist/utils/addExplicitAnchorIds.js +0 -416
- package/dist/utils/constants.d.ts +0 -5
- package/dist/utils/constants.js +0 -6
- package/dist/utils/credentials.d.ts +0 -12
- package/dist/utils/credentials.js +0 -120
- package/dist/utils/flattenJsonFiles.d.ts +0 -2
- package/dist/utils/flattenJsonFiles.js +0 -36
- package/dist/utils/gitDiff.d.ts +0 -8
- package/dist/utils/gitDiff.js +0 -34
- package/dist/utils/gt.d.ts +0 -2
- package/dist/utils/gt.js +0 -2
- package/dist/utils/hash.d.ts +0 -6
- package/dist/utils/hash.js +0 -11
- package/dist/utils/headers.d.ts +0 -1
- package/dist/utils/headers.js +0 -14
- package/dist/utils/localizeRelativeAssets.d.ts +0 -8
- package/dist/utils/localizeRelativeAssets.js +0 -166
- package/dist/utils/localizeStaticImports.d.ts +0 -15
- package/dist/utils/localizeStaticImports.js +0 -397
- package/dist/utils/localizeStaticUrls.d.ts +0 -19
- package/dist/utils/localizeStaticUrls.js +0 -450
- package/dist/utils/mintlifyTitleFallback.d.ts +0 -6
- package/dist/utils/mintlifyTitleFallback.js +0 -80
- package/dist/utils/parse/needsCJS.d.ts +0 -20
- package/dist/utils/parse/needsCJS.js +0 -72
- package/dist/utils/persistPostprocessHashes.d.ts +0 -12
- package/dist/utils/persistPostprocessHashes.js +0 -39
- package/dist/utils/processAnchorIds.d.ts +0 -6
- package/dist/utils/processAnchorIds.js +0 -56
- package/dist/utils/processOpenApi.d.ts +0 -8
- package/dist/utils/processOpenApi.js +0 -651
- package/dist/utils/sanitizeFileContent.d.ts +0 -6
- package/dist/utils/sanitizeFileContent.js +0 -29
- package/dist/utils/sharedStaticAssets.d.ts +0 -9
- package/dist/utils/sharedStaticAssets.js +0 -384
- package/dist/utils/validateMdx.d.ts +0 -10
- package/dist/utils/validateMdx.js +0 -25
- package/dist/utils/wrapPlainUrls.d.ts +0 -8
- package/dist/utils/wrapPlainUrls.js +0 -72
- package/dist/workflows/download.d.ts +0 -32
- package/dist/workflows/download.js +0 -131
- package/dist/workflows/enqueue.d.ts +0 -17
- package/dist/workflows/enqueue.js +0 -59
- package/dist/workflows/setupProject.d.ts +0 -13
- package/dist/workflows/setupProject.js +0 -48
- package/dist/workflows/stage.d.ts +0 -18
- package/dist/workflows/stage.js +0 -59
- package/dist/workflows/steps/BranchStep.d.ts +0 -13
- package/dist/workflows/steps/BranchStep.js +0 -161
- package/dist/workflows/steps/DownloadStep.d.ts +0 -19
- package/dist/workflows/steps/DownloadStep.js +0 -131
- package/dist/workflows/steps/EnqueueStep.d.ts +0 -15
- package/dist/workflows/steps/EnqueueStep.js +0 -33
- package/dist/workflows/steps/PollJobsStep.d.ts +0 -31
- package/dist/workflows/steps/PollJobsStep.js +0 -288
- package/dist/workflows/steps/SetupStep.d.ts +0 -16
- package/dist/workflows/steps/SetupStep.js +0 -72
- package/dist/workflows/steps/UploadSourcesStep.d.ts +0 -27
- package/dist/workflows/steps/UploadSourcesStep.js +0 -131
- package/dist/workflows/steps/UploadTranslationsStep.d.ts +0 -22
- package/dist/workflows/steps/UploadTranslationsStep.js +0 -71
- package/dist/workflows/steps/UserEditDiffsStep.d.ts +0 -11
- package/dist/workflows/steps/UserEditDiffsStep.js +0 -30
- package/dist/workflows/steps/WorkflowStep.d.ts +0 -4
- package/dist/workflows/steps/WorkflowStep.js +0 -2
- package/dist/workflows/upload.d.ts +0 -15
- package/dist/workflows/upload.js +0 -47
|
@@ -1,918 +0,0 @@
|
|
|
1
|
-
import { randomUUID } from 'node:crypto';
|
|
2
|
-
import generateModule from '@babel/generator';
|
|
3
|
-
// Handle CommonJS/ESM interop
|
|
4
|
-
const generate = generateModule.default || generateModule;
|
|
5
|
-
import * as t from '@babel/types';
|
|
6
|
-
import fs from 'node:fs';
|
|
7
|
-
import { parse } from '@babel/parser';
|
|
8
|
-
import addGTIdentifierToSyntaxTree from './addGTIdentifierToSyntaxTree.js';
|
|
9
|
-
import { warnHasUnwrappedExpressionSync, warnNestedTComponent, warnFunctionNotFoundSync, warnMissingReturnSync, warnDuplicateFunctionDefinitionSync, warnInvalidStaticInitSync, warnRecursiveFunctionCallSync, warnDataAttrOnBranch, } from '../../../../console/index.js';
|
|
10
|
-
import { isAcceptedPluralForm } from 'generaltranslation/internal';
|
|
11
|
-
import { isStaticExpression } from '../../evaluateJsx.js';
|
|
12
|
-
import { DATA_ATTR_PREFIX, STATIC_COMPONENT, TRANSLATION_COMPONENT, VARIABLE_COMPONENTS, } from '../constants.js';
|
|
13
|
-
import { HTML_CONTENT_PROPS } from 'generaltranslation/types';
|
|
14
|
-
import { resolveImportPath } from '../resolveImportPath.js';
|
|
15
|
-
import traverseModule from '@babel/traverse';
|
|
16
|
-
import { buildImportMap } from '../buildImportMap.js';
|
|
17
|
-
import { getPathsAndAliases } from '../getPathsAndAliases.js';
|
|
18
|
-
import { parseTProps } from './parseTProps.js';
|
|
19
|
-
import { handleChildrenWhitespace } from './handleChildrenWhitespace.js';
|
|
20
|
-
import { isElementNode } from './types.js';
|
|
21
|
-
import { multiplyJsxTree } from './multiplication/multiplyJsxTree.js';
|
|
22
|
-
import { removeNullChildrenFields } from './removeNullChildrenFields.js';
|
|
23
|
-
import path from 'node:path';
|
|
24
|
-
// Handle CommonJS/ESM interop
|
|
25
|
-
const traverse = traverseModule.default || traverseModule;
|
|
26
|
-
// TODO: currently we cover VariableDeclaration and FunctionDeclaration nodes, but are there others we should cover as well?
|
|
27
|
-
/**
|
|
28
|
-
* Cache for resolved import paths to avoid redundant I/O operations.
|
|
29
|
-
* Key: `${currentFile}::${importPath}`
|
|
30
|
-
* Value: resolved absolute path or null
|
|
31
|
-
*/
|
|
32
|
-
const resolveImportPathCache = new Map();
|
|
33
|
-
/**
|
|
34
|
-
* Cache for processed functions to avoid re-parsing the same files.
|
|
35
|
-
* Key: `${filePath}::${functionName}::${argIndex}`
|
|
36
|
-
* Value: boolean indicating whether the function was found and processed
|
|
37
|
-
*/
|
|
38
|
-
const processFunctionCache = new Map();
|
|
39
|
-
/**
|
|
40
|
-
* Entry point for JSX parsing
|
|
41
|
-
*/
|
|
42
|
-
export function parseTranslationComponent({ originalName, localName, path, updates, config, output, }) {
|
|
43
|
-
// First, collect all imports in this file to track cross-file function calls
|
|
44
|
-
const importedFunctionsMap = buildImportMap(path.scope.getProgramParent().path);
|
|
45
|
-
const referencePaths = path.scope.bindings[localName]?.referencePaths || [];
|
|
46
|
-
for (const refPath of referencePaths) {
|
|
47
|
-
// Only start at opening tag
|
|
48
|
-
if (!t.isJSXOpeningElement(refPath.parent) ||
|
|
49
|
-
!refPath.parentPath?.parentPath) {
|
|
50
|
-
continue;
|
|
51
|
-
}
|
|
52
|
-
// Get the JSX element NodePath
|
|
53
|
-
const jsxElementPath = refPath.parentPath
|
|
54
|
-
?.parentPath;
|
|
55
|
-
// Parse <T> component
|
|
56
|
-
parseJSXElement({
|
|
57
|
-
scopeNode: jsxElementPath,
|
|
58
|
-
node: jsxElementPath.node,
|
|
59
|
-
originalName,
|
|
60
|
-
updates,
|
|
61
|
-
config,
|
|
62
|
-
state: {
|
|
63
|
-
visited: null,
|
|
64
|
-
callStack: [],
|
|
65
|
-
staticTracker: { isStatic: false },
|
|
66
|
-
importedFunctionsMap,
|
|
67
|
-
},
|
|
68
|
-
output,
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
/**
|
|
73
|
-
* Builds a JSX tree from a given node, recursively handling children.
|
|
74
|
-
* @param node - The node to build the tree from
|
|
75
|
-
* @param helperPath - NodePath for AST traversal
|
|
76
|
-
* @param scopeNode - Scope node for binding resolution
|
|
77
|
-
* @param insideT - Whether the current node is inside a <T> component
|
|
78
|
-
* @param inStatic - Whether we're inside a Static component
|
|
79
|
-
* @param config - Immutable configuration options
|
|
80
|
-
* @param state - Mutable state tracking
|
|
81
|
-
* @param output - Error/warning collectors
|
|
82
|
-
* @returns The built JSX tree
|
|
83
|
-
*/
|
|
84
|
-
function buildJSXTree({ node, helperPath, scopeNode, insideT, inStatic, config, state, output, }) {
|
|
85
|
-
if (t.isJSXExpressionContainer(node)) {
|
|
86
|
-
// Skip JSX comments
|
|
87
|
-
if (t.isJSXEmptyExpression(node.expression)) {
|
|
88
|
-
return null;
|
|
89
|
-
}
|
|
90
|
-
if (inStatic) {
|
|
91
|
-
return processStaticExpression({
|
|
92
|
-
config,
|
|
93
|
-
state,
|
|
94
|
-
output,
|
|
95
|
-
expressionNodePath: helperPath.get('expression'),
|
|
96
|
-
scopeNode,
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
|
-
const expr = node.expression;
|
|
100
|
-
if (t.isJSXElement(expr) || t.isJSXFragment(expr)) {
|
|
101
|
-
return buildJSXTree({
|
|
102
|
-
node: expr,
|
|
103
|
-
insideT,
|
|
104
|
-
inStatic,
|
|
105
|
-
scopeNode,
|
|
106
|
-
helperPath: helperPath.get('expression'),
|
|
107
|
-
config,
|
|
108
|
-
state,
|
|
109
|
-
output,
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
const staticAnalysis = isStaticExpression(expr, true);
|
|
113
|
-
if (staticAnalysis.isStatic && staticAnalysis.value !== undefined) {
|
|
114
|
-
// Preserve the exact whitespace for static string expressions
|
|
115
|
-
return {
|
|
116
|
-
nodeType: 'expression',
|
|
117
|
-
result: staticAnalysis.value,
|
|
118
|
-
};
|
|
119
|
-
}
|
|
120
|
-
// Keep existing behavior for non-static expressions
|
|
121
|
-
const code = generate(node).code;
|
|
122
|
-
output.unwrappedExpressions.push(code); // Keep track of unwrapped expressions for error reporting
|
|
123
|
-
return code;
|
|
124
|
-
}
|
|
125
|
-
else if (t.isJSXText(node)) {
|
|
126
|
-
// Updated JSX Text handling
|
|
127
|
-
// JSX Text handling following React's rules
|
|
128
|
-
const text = node.value;
|
|
129
|
-
return text;
|
|
130
|
-
}
|
|
131
|
-
else if (t.isJSXElement(node)) {
|
|
132
|
-
const element = node;
|
|
133
|
-
const elementName = element.openingElement.name;
|
|
134
|
-
let typeName;
|
|
135
|
-
if (t.isJSXIdentifier(elementName)) {
|
|
136
|
-
typeName = elementName.name;
|
|
137
|
-
}
|
|
138
|
-
else if (t.isJSXMemberExpression(elementName)) {
|
|
139
|
-
typeName = generate(elementName).code;
|
|
140
|
-
}
|
|
141
|
-
else {
|
|
142
|
-
typeName = null;
|
|
143
|
-
}
|
|
144
|
-
// Convert from alias to original name
|
|
145
|
-
const componentType = config.importAliases[typeName ?? ''];
|
|
146
|
-
if (componentType === TRANSLATION_COMPONENT && insideT) {
|
|
147
|
-
// Add warning: Nested <T> components are allowed, but they are advised against
|
|
148
|
-
output.warnings.add(warnNestedTComponent(config.file, `${element.loc?.start?.line}:${element.loc?.start?.column}`));
|
|
149
|
-
}
|
|
150
|
-
// If this JSXElement is one of the recognized variable components,
|
|
151
|
-
const elementIsVariable = VARIABLE_COMPONENTS.includes(componentType);
|
|
152
|
-
const props = {};
|
|
153
|
-
const elementIsPlural = componentType === 'Plural';
|
|
154
|
-
const elementIsBranch = componentType === 'Branch';
|
|
155
|
-
element.openingElement.attributes.forEach((attr, index) => {
|
|
156
|
-
const helperAttribute = helperPath
|
|
157
|
-
.get('openingElement')
|
|
158
|
-
.get('attributes')[index];
|
|
159
|
-
if (t.isJSXAttribute(attr)) {
|
|
160
|
-
const attrName = typeof attr.name.name === 'string'
|
|
161
|
-
? attr.name.name
|
|
162
|
-
: attr.name.name.name;
|
|
163
|
-
let attrValue = null;
|
|
164
|
-
if (elementIsBranch && attrName.startsWith(DATA_ATTR_PREFIX)) {
|
|
165
|
-
const location = `${attr.loc?.start?.line}:${attr.loc?.start?.column}`;
|
|
166
|
-
output.errors.push(warnDataAttrOnBranch(config.file, attrName, location));
|
|
167
|
-
}
|
|
168
|
-
if (attr.value) {
|
|
169
|
-
if (t.isStringLiteral(attr.value)) {
|
|
170
|
-
attrValue = attr.value.value;
|
|
171
|
-
}
|
|
172
|
-
else if (t.isJSXExpressionContainer(attr.value)) {
|
|
173
|
-
const helperValue = helperAttribute.get('value');
|
|
174
|
-
// Check if this is an HTML content prop (title, placeholder, alt, etc.)
|
|
175
|
-
const isHtmlContentProp = Object.values(HTML_CONTENT_PROPS).includes(attrName);
|
|
176
|
-
// If its a plural or branch prop
|
|
177
|
-
if ((elementIsPlural && isAcceptedPluralForm(attrName)) ||
|
|
178
|
-
(elementIsBranch &&
|
|
179
|
-
attrName !== 'branch' &&
|
|
180
|
-
!attrName.startsWith(DATA_ATTR_PREFIX))) {
|
|
181
|
-
// Make sure that variable strings like {`I have ${count} book`} are invalid!
|
|
182
|
-
if (t.isTemplateLiteral(attr.value.expression) &&
|
|
183
|
-
!isStaticExpression(attr.value.expression, true).isStatic) {
|
|
184
|
-
output.unwrappedExpressions.push(generate(attr.value).code);
|
|
185
|
-
}
|
|
186
|
-
// If it's an array, flag as an unwrapped expression
|
|
187
|
-
if (t.isArrayExpression(attr.value.expression)) {
|
|
188
|
-
output.unwrappedExpressions.push(generate(attr.value.expression).code);
|
|
189
|
-
}
|
|
190
|
-
attrValue = buildJSXTree({
|
|
191
|
-
node: attr.value,
|
|
192
|
-
insideT: true,
|
|
193
|
-
inStatic,
|
|
194
|
-
scopeNode,
|
|
195
|
-
helperPath: helperValue,
|
|
196
|
-
config,
|
|
197
|
-
state,
|
|
198
|
-
output,
|
|
199
|
-
});
|
|
200
|
-
}
|
|
201
|
-
// For HTML content props, only accept static string expressions
|
|
202
|
-
else if (isHtmlContentProp) {
|
|
203
|
-
const staticAnalysis = isStaticExpression(attr.value.expression, true);
|
|
204
|
-
if (staticAnalysis.isStatic &&
|
|
205
|
-
staticAnalysis.value !== undefined) {
|
|
206
|
-
attrValue = staticAnalysis.value;
|
|
207
|
-
}
|
|
208
|
-
// Otherwise attrValue stays null and won't be included
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
props[attrName] = attrValue;
|
|
213
|
-
}
|
|
214
|
-
});
|
|
215
|
-
if (elementIsVariable) {
|
|
216
|
-
if (componentType === STATIC_COMPONENT) {
|
|
217
|
-
const helperElement = helperPath.get('children');
|
|
218
|
-
const results = {
|
|
219
|
-
nodeType: 'element',
|
|
220
|
-
type: STATIC_COMPONENT,
|
|
221
|
-
props,
|
|
222
|
-
};
|
|
223
|
-
// Create children array if necessary
|
|
224
|
-
const childrenArray = [];
|
|
225
|
-
if (state.visited === null) {
|
|
226
|
-
state.visited = new Set();
|
|
227
|
-
}
|
|
228
|
-
for (let index = 0; index < element.children.length; index++) {
|
|
229
|
-
const helperChild = helperElement[index];
|
|
230
|
-
const result = buildJSXTree({
|
|
231
|
-
node: helperChild.node,
|
|
232
|
-
insideT: true,
|
|
233
|
-
inStatic: true,
|
|
234
|
-
scopeNode,
|
|
235
|
-
helperPath: helperChild,
|
|
236
|
-
config,
|
|
237
|
-
state,
|
|
238
|
-
output,
|
|
239
|
-
});
|
|
240
|
-
childrenArray.push(result);
|
|
241
|
-
}
|
|
242
|
-
if (childrenArray.length) {
|
|
243
|
-
results.props.children = childrenArray;
|
|
244
|
-
}
|
|
245
|
-
return results;
|
|
246
|
-
}
|
|
247
|
-
return {
|
|
248
|
-
nodeType: 'element',
|
|
249
|
-
// if componentType is undefined, use typeName
|
|
250
|
-
// Basically, if componentType is not a GT component, use typeName such as <div>
|
|
251
|
-
type: componentType ?? typeName ?? '',
|
|
252
|
-
props,
|
|
253
|
-
};
|
|
254
|
-
}
|
|
255
|
-
const children = element.children
|
|
256
|
-
.map((child, index) => buildJSXTree({
|
|
257
|
-
node: child,
|
|
258
|
-
insideT: true,
|
|
259
|
-
inStatic,
|
|
260
|
-
scopeNode,
|
|
261
|
-
helperPath: helperPath.get('children')[index],
|
|
262
|
-
config,
|
|
263
|
-
state,
|
|
264
|
-
output,
|
|
265
|
-
}))
|
|
266
|
-
.filter((child) => child !== null && child !== '');
|
|
267
|
-
if (children.length === 1) {
|
|
268
|
-
props.children = children[0];
|
|
269
|
-
}
|
|
270
|
-
else if (children.length > 1) {
|
|
271
|
-
props.children = children;
|
|
272
|
-
}
|
|
273
|
-
return {
|
|
274
|
-
nodeType: 'element',
|
|
275
|
-
// if componentType is undefined, use typeName
|
|
276
|
-
// Basically, if componentType is not a GT component, use typeName such as <div>
|
|
277
|
-
type: componentType ?? typeName,
|
|
278
|
-
props,
|
|
279
|
-
};
|
|
280
|
-
}
|
|
281
|
-
// If it's a JSX fragment
|
|
282
|
-
else if (t.isJSXFragment(node)) {
|
|
283
|
-
const children = node.children
|
|
284
|
-
.map((child, index) => buildJSXTree({
|
|
285
|
-
node: child,
|
|
286
|
-
insideT: true,
|
|
287
|
-
inStatic,
|
|
288
|
-
scopeNode,
|
|
289
|
-
helperPath: helperPath.get('children')[index],
|
|
290
|
-
config,
|
|
291
|
-
state,
|
|
292
|
-
output,
|
|
293
|
-
}))
|
|
294
|
-
.filter((child) => child !== null && child !== '');
|
|
295
|
-
const props = {};
|
|
296
|
-
if (children.length === 1) {
|
|
297
|
-
props.children = children[0];
|
|
298
|
-
}
|
|
299
|
-
else if (children.length > 1) {
|
|
300
|
-
props.children = children;
|
|
301
|
-
}
|
|
302
|
-
return {
|
|
303
|
-
nodeType: 'element',
|
|
304
|
-
type: '',
|
|
305
|
-
props,
|
|
306
|
-
};
|
|
307
|
-
}
|
|
308
|
-
// If it's a string literal (standalone)
|
|
309
|
-
else if (t.isStringLiteral(node)) {
|
|
310
|
-
return node.value;
|
|
311
|
-
}
|
|
312
|
-
// If it's a template literal
|
|
313
|
-
else if (t.isTemplateLiteral(node)) {
|
|
314
|
-
// We've already checked that it's static, and and added a warning if it's not, this check is just for fallback behavior
|
|
315
|
-
if (!isStaticExpression(node, true).isStatic ||
|
|
316
|
-
node.quasis[0].value.cooked === undefined) {
|
|
317
|
-
return generate(node).code;
|
|
318
|
-
}
|
|
319
|
-
return node.quasis[0].value.cooked;
|
|
320
|
-
}
|
|
321
|
-
else if (t.isNullLiteral(node)) {
|
|
322
|
-
// If it's null, return null
|
|
323
|
-
return null;
|
|
324
|
-
}
|
|
325
|
-
else if (t.isBooleanLiteral(node)) {
|
|
326
|
-
// If it's a boolean, return the boolean
|
|
327
|
-
return node.value;
|
|
328
|
-
}
|
|
329
|
-
else if (t.isNumericLiteral(node)) {
|
|
330
|
-
// If it's a number, return the number
|
|
331
|
-
return node.value.toString();
|
|
332
|
-
}
|
|
333
|
-
// Negative
|
|
334
|
-
else if (t.isUnaryExpression(node)) {
|
|
335
|
-
// If it's a unary expression, return the expression
|
|
336
|
-
const staticAnalysis = isStaticExpression(node, true);
|
|
337
|
-
if (staticAnalysis.isStatic && staticAnalysis.value !== undefined) {
|
|
338
|
-
return staticAnalysis.value;
|
|
339
|
-
}
|
|
340
|
-
return generate(node).code;
|
|
341
|
-
}
|
|
342
|
-
else if ((t.isCallExpression(node) && t.isIdentifier(node.callee)) ||
|
|
343
|
-
(t.isAwaitExpression(node) &&
|
|
344
|
-
t.isCallExpression(node.argument) &&
|
|
345
|
-
t.isIdentifier(node.argument.callee))) {
|
|
346
|
-
if (inStatic) {
|
|
347
|
-
const callExpression = (node.type === 'AwaitExpression' ? node.argument : node);
|
|
348
|
-
const callee = callExpression.callee;
|
|
349
|
-
const calleeBinding = scopeNode.scope.getBinding(callee.name);
|
|
350
|
-
if (!calleeBinding) {
|
|
351
|
-
output.warnings.add(warnFunctionNotFoundSync(config.file, callee.name, `${callee.loc?.start?.line}:${callee.loc?.start?.column}`));
|
|
352
|
-
return null;
|
|
353
|
-
}
|
|
354
|
-
return resolveStaticFunctionInvocationFromBinding({
|
|
355
|
-
calleeBinding,
|
|
356
|
-
callee,
|
|
357
|
-
config,
|
|
358
|
-
state,
|
|
359
|
-
output,
|
|
360
|
-
});
|
|
361
|
-
}
|
|
362
|
-
else {
|
|
363
|
-
output.unwrappedExpressions.push(generate(node).code);
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
else if (t.isParenthesizedExpression(node)) {
|
|
367
|
-
const child = node.expression;
|
|
368
|
-
return buildJSXTree({
|
|
369
|
-
node: child,
|
|
370
|
-
insideT,
|
|
371
|
-
inStatic,
|
|
372
|
-
scopeNode,
|
|
373
|
-
helperPath: helperPath.get('expression'),
|
|
374
|
-
config,
|
|
375
|
-
state,
|
|
376
|
-
output,
|
|
377
|
-
});
|
|
378
|
-
}
|
|
379
|
-
// If it's some other JS expression
|
|
380
|
-
else if (t.isIdentifier(node) ||
|
|
381
|
-
t.isMemberExpression(node) ||
|
|
382
|
-
t.isCallExpression(node) ||
|
|
383
|
-
t.isBinaryExpression(node) ||
|
|
384
|
-
t.isLogicalExpression(node) ||
|
|
385
|
-
t.isConditionalExpression(node)) {
|
|
386
|
-
output.unwrappedExpressions.push(generate(node).code);
|
|
387
|
-
}
|
|
388
|
-
else {
|
|
389
|
-
if (node === undefined || node === null) {
|
|
390
|
-
output.unwrappedExpressions.push(String(node));
|
|
391
|
-
}
|
|
392
|
-
else {
|
|
393
|
-
output.unwrappedExpressions.push(generate(node).code);
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
return null;
|
|
397
|
-
}
|
|
398
|
-
// end buildJSXTree
|
|
399
|
-
// Parses a JSX element and adds it to the updates array
|
|
400
|
-
function parseJSXElement({ node, originalName, scopeNode, updates, config, state, output, }) {
|
|
401
|
-
const openingElement = node.openingElement;
|
|
402
|
-
const name = openingElement.name;
|
|
403
|
-
// Only proceed if it's <T> ...
|
|
404
|
-
// TODO: i don't think this condition is needed anymore
|
|
405
|
-
if (!(name.type === 'JSXIdentifier' && originalName === TRANSLATION_COMPONENT)) {
|
|
406
|
-
return;
|
|
407
|
-
}
|
|
408
|
-
const componentErrors = [];
|
|
409
|
-
const componentWarnings = new Set();
|
|
410
|
-
const metadata = {};
|
|
411
|
-
const relativeFilepath = path.relative(process.cwd(), config.file);
|
|
412
|
-
metadata.filePaths = [relativeFilepath];
|
|
413
|
-
// We'll track this flag to know if any unwrapped {variable} is found in children
|
|
414
|
-
const unwrappedExpressions = [];
|
|
415
|
-
// Gather <T>'s props
|
|
416
|
-
parseTProps({
|
|
417
|
-
openingElement,
|
|
418
|
-
metadata,
|
|
419
|
-
componentErrors,
|
|
420
|
-
file: config.file,
|
|
421
|
-
});
|
|
422
|
-
// Flag for if contains static content
|
|
423
|
-
const staticTracker = {
|
|
424
|
-
isStatic: false,
|
|
425
|
-
};
|
|
426
|
-
// Build the JSX tree for this component
|
|
427
|
-
const treeResult = buildJSXTree({
|
|
428
|
-
node,
|
|
429
|
-
scopeNode,
|
|
430
|
-
insideT: false,
|
|
431
|
-
inStatic: false,
|
|
432
|
-
helperPath: scopeNode,
|
|
433
|
-
config,
|
|
434
|
-
state: {
|
|
435
|
-
visited: null,
|
|
436
|
-
callStack: [],
|
|
437
|
-
staticTracker,
|
|
438
|
-
importedFunctionsMap: state.importedFunctionsMap,
|
|
439
|
-
},
|
|
440
|
-
output: {
|
|
441
|
-
unwrappedExpressions,
|
|
442
|
-
errors: componentErrors,
|
|
443
|
-
warnings: componentWarnings,
|
|
444
|
-
},
|
|
445
|
-
});
|
|
446
|
-
// Strip the outer <T> component if necessary
|
|
447
|
-
const jsxTree = isElementNode(treeResult) && treeResult.props?.children
|
|
448
|
-
? // We know this b/c the direct children of <T> will never be a multiplication node
|
|
449
|
-
treeResult.props.children
|
|
450
|
-
: treeResult;
|
|
451
|
-
// Update warnings
|
|
452
|
-
if (componentWarnings.size > 0) {
|
|
453
|
-
componentWarnings.forEach((warning) => output.warnings.add(warning));
|
|
454
|
-
}
|
|
455
|
-
// Update errors
|
|
456
|
-
if (componentErrors.length > 0) {
|
|
457
|
-
output.errors.push(...componentErrors);
|
|
458
|
-
return;
|
|
459
|
-
}
|
|
460
|
-
// Handle whitespace in children
|
|
461
|
-
const whitespaceHandledTree = handleChildrenWhitespace(jsxTree);
|
|
462
|
-
// Multiply the tree
|
|
463
|
-
const multipliedTrees = multiplyJsxTree(whitespaceHandledTree);
|
|
464
|
-
// Add GT identifiers to the tree
|
|
465
|
-
// TODO: do this in parallel
|
|
466
|
-
const minifiedTress = [];
|
|
467
|
-
for (const multipliedTree of multipliedTrees) {
|
|
468
|
-
const minifiedTree = addGTIdentifierToSyntaxTree(multipliedTree);
|
|
469
|
-
minifiedTress.push(Array.isArray(minifiedTree) && minifiedTree.length === 1
|
|
470
|
-
? minifiedTree[0]
|
|
471
|
-
: minifiedTree);
|
|
472
|
-
}
|
|
473
|
-
// If we found an unwrapped expression, skip
|
|
474
|
-
if (unwrappedExpressions.length > 0) {
|
|
475
|
-
output.errors.push(warnHasUnwrappedExpressionSync(config.file, unwrappedExpressions, metadata.id, `${node.loc?.start?.line}:${node.loc?.start?.column}`));
|
|
476
|
-
return;
|
|
477
|
-
}
|
|
478
|
-
// Create a temporary unique flag for static content
|
|
479
|
-
const temporaryStaticId = `static-temp-id-${randomUUID()}`;
|
|
480
|
-
const isStatic = staticTracker.isStatic;
|
|
481
|
-
// <T> is valid here
|
|
482
|
-
for (const minifiedTree of minifiedTress) {
|
|
483
|
-
// Clean the tree by removing null 'c' fields from JsxElements
|
|
484
|
-
const cleanedTree = removeNullChildrenFields(minifiedTree);
|
|
485
|
-
updates.push({
|
|
486
|
-
dataFormat: 'JSX',
|
|
487
|
-
source: cleanedTree,
|
|
488
|
-
metadata: {
|
|
489
|
-
// eslint-disable-next-line no-undef
|
|
490
|
-
...structuredClone(metadata),
|
|
491
|
-
...(isStatic && { staticId: temporaryStaticId }),
|
|
492
|
-
},
|
|
493
|
-
});
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
function resolveStaticFunctionInvocationFromBinding({ calleeBinding, callee, config, state, output, }) {
|
|
497
|
-
function withRecusionGuard({ cb, filename, functionName, }) {
|
|
498
|
-
const cacheKey = `${filename}::${functionName}`;
|
|
499
|
-
if (state.callStack.includes(cacheKey)) {
|
|
500
|
-
output.errors.push(warnRecursiveFunctionCallSync(config.file, functionName));
|
|
501
|
-
return null;
|
|
502
|
-
}
|
|
503
|
-
state.callStack.push(cacheKey);
|
|
504
|
-
const result = cb();
|
|
505
|
-
state.callStack.pop();
|
|
506
|
-
return result;
|
|
507
|
-
}
|
|
508
|
-
// check for recursive calls
|
|
509
|
-
if (calleeBinding.path.isFunctionDeclaration()) {
|
|
510
|
-
// Handle function declarations: function getSubject() { ... }
|
|
511
|
-
const functionName = callee.name;
|
|
512
|
-
const path = calleeBinding.path;
|
|
513
|
-
return withRecusionGuard({
|
|
514
|
-
filename: config.file,
|
|
515
|
-
functionName,
|
|
516
|
-
cb: () => processFunctionDeclarationNodePath({
|
|
517
|
-
config,
|
|
518
|
-
state,
|
|
519
|
-
output,
|
|
520
|
-
path,
|
|
521
|
-
}),
|
|
522
|
-
});
|
|
523
|
-
}
|
|
524
|
-
else if (calleeBinding.path.isVariableDeclarator() &&
|
|
525
|
-
calleeBinding.path.node.init &&
|
|
526
|
-
(t.isArrowFunctionExpression(calleeBinding.path.node.init) ||
|
|
527
|
-
t.isFunctionExpression(calleeBinding.path.node.init))) {
|
|
528
|
-
// Handle arrow functions assigned to variables: const getData = (t) => {...}
|
|
529
|
-
const functionName = callee.name;
|
|
530
|
-
const path = calleeBinding.path;
|
|
531
|
-
return withRecusionGuard({
|
|
532
|
-
filename: config.file,
|
|
533
|
-
functionName,
|
|
534
|
-
cb: () => processVariableDeclarationNodePath({
|
|
535
|
-
config,
|
|
536
|
-
state,
|
|
537
|
-
output,
|
|
538
|
-
functionName,
|
|
539
|
-
path,
|
|
540
|
-
}),
|
|
541
|
-
});
|
|
542
|
-
}
|
|
543
|
-
else if (state.importedFunctionsMap.has(callee.name)) {
|
|
544
|
-
// Get the original function name
|
|
545
|
-
let originalName;
|
|
546
|
-
if (calleeBinding.path.isImportSpecifier()) {
|
|
547
|
-
originalName = t.isIdentifier(calleeBinding.path.node.imported)
|
|
548
|
-
? calleeBinding.path.node.imported.name
|
|
549
|
-
: calleeBinding.path.node.imported.value;
|
|
550
|
-
}
|
|
551
|
-
else if (calleeBinding.path.isImportDefaultSpecifier()) {
|
|
552
|
-
originalName = calleeBinding.path.node.local.name;
|
|
553
|
-
}
|
|
554
|
-
else if (calleeBinding.path.isImportNamespaceSpecifier()) {
|
|
555
|
-
originalName = calleeBinding.path.node.local.name;
|
|
556
|
-
}
|
|
557
|
-
// Function is being imported
|
|
558
|
-
const importPath = state.importedFunctionsMap.get(callee.name);
|
|
559
|
-
const filePath = resolveImportPath(config.file, importPath, config.parsingOptions, resolveImportPathCache);
|
|
560
|
-
if (filePath && originalName) {
|
|
561
|
-
const result = withRecusionGuard({
|
|
562
|
-
filename: filePath,
|
|
563
|
-
functionName: originalName,
|
|
564
|
-
cb: () => processFunctionInFile({
|
|
565
|
-
config,
|
|
566
|
-
state,
|
|
567
|
-
output,
|
|
568
|
-
filePath,
|
|
569
|
-
functionName: originalName,
|
|
570
|
-
}),
|
|
571
|
-
});
|
|
572
|
-
if (result !== null) {
|
|
573
|
-
return result;
|
|
574
|
-
}
|
|
575
|
-
}
|
|
576
|
-
}
|
|
577
|
-
output.warnings.add(warnFunctionNotFoundSync(config.file, callee.name, `${callee.loc?.start?.line}:${callee.loc?.start?.column}`));
|
|
578
|
-
return null;
|
|
579
|
-
}
|
|
580
|
-
/**
|
|
581
|
-
* Searches for a specific user-defined function in a file.
|
|
582
|
-
* This is the resolution logic
|
|
583
|
-
*
|
|
584
|
-
* Handles multiple function declaration patterns:
|
|
585
|
-
* - function getInfo() { ... }
|
|
586
|
-
* - export function getInfo() { ... }
|
|
587
|
-
* - const getInfo = () => { ... }
|
|
588
|
-
*
|
|
589
|
-
* If the function is not found in the file, follows re-exports (export * from './other')
|
|
590
|
-
*/
|
|
591
|
-
function processFunctionInFile({ config, state, output, filePath, functionName, }) {
|
|
592
|
-
// Create a custom key for the function call
|
|
593
|
-
const cacheKey = `${filePath}::${functionName}`;
|
|
594
|
-
// Check cache first to avoid redundant parsing
|
|
595
|
-
if (processFunctionCache.has(cacheKey)) {
|
|
596
|
-
return processFunctionCache.get(cacheKey) ?? null;
|
|
597
|
-
}
|
|
598
|
-
// Prevent infinite loops from circular re-exports
|
|
599
|
-
if (state.visited && state.visited.has(filePath)) {
|
|
600
|
-
return null;
|
|
601
|
-
}
|
|
602
|
-
if (state.visited) {
|
|
603
|
-
state.visited.add(filePath);
|
|
604
|
-
}
|
|
605
|
-
let result = undefined;
|
|
606
|
-
try {
|
|
607
|
-
const code = fs.readFileSync(filePath, 'utf8');
|
|
608
|
-
const ast = parse(code, {
|
|
609
|
-
sourceType: 'module',
|
|
610
|
-
plugins: ['jsx', 'typescript'],
|
|
611
|
-
});
|
|
612
|
-
const { importAliases } = getPathsAndAliases(ast, config.pkgs);
|
|
613
|
-
// Collect all imports in this file to track cross-file function calls
|
|
614
|
-
let importedFunctionsMap = new Map();
|
|
615
|
-
traverse(ast, {
|
|
616
|
-
Program(path) {
|
|
617
|
-
importedFunctionsMap = buildImportMap(path);
|
|
618
|
-
},
|
|
619
|
-
});
|
|
620
|
-
const reExports = [];
|
|
621
|
-
const warnDuplicateFuncDef = (path) => {
|
|
622
|
-
output.warnings.add(warnDuplicateFunctionDefinitionSync(filePath, functionName, `${path.node.loc?.start?.line}:${path.node.loc?.start?.column}`));
|
|
623
|
-
};
|
|
624
|
-
traverse(ast, {
|
|
625
|
-
// Handle function declarations: function getInfo() { ... }
|
|
626
|
-
FunctionDeclaration(path) {
|
|
627
|
-
if (path.node.id?.name === functionName) {
|
|
628
|
-
if (result !== undefined)
|
|
629
|
-
return warnDuplicateFuncDef(path);
|
|
630
|
-
result = processFunctionDeclarationNodePath({
|
|
631
|
-
config: {
|
|
632
|
-
importAliases,
|
|
633
|
-
parsingOptions: config.parsingOptions,
|
|
634
|
-
pkgs: config.pkgs,
|
|
635
|
-
file: filePath,
|
|
636
|
-
},
|
|
637
|
-
state: {
|
|
638
|
-
...state,
|
|
639
|
-
importedFunctionsMap,
|
|
640
|
-
},
|
|
641
|
-
output,
|
|
642
|
-
path,
|
|
643
|
-
});
|
|
644
|
-
}
|
|
645
|
-
},
|
|
646
|
-
// Handle variable declarations: const getInfo = () => { ... }
|
|
647
|
-
VariableDeclarator(path) {
|
|
648
|
-
if (t.isIdentifier(path.node.id) &&
|
|
649
|
-
path.node.id.name === functionName &&
|
|
650
|
-
path.node.init &&
|
|
651
|
-
(t.isArrowFunctionExpression(path.node.init) ||
|
|
652
|
-
t.isFunctionExpression(path.node.init))) {
|
|
653
|
-
if (result !== undefined)
|
|
654
|
-
return warnDuplicateFuncDef(path);
|
|
655
|
-
result = processVariableDeclarationNodePath({
|
|
656
|
-
config: {
|
|
657
|
-
importAliases,
|
|
658
|
-
parsingOptions: config.parsingOptions,
|
|
659
|
-
pkgs: config.pkgs,
|
|
660
|
-
file: filePath,
|
|
661
|
-
},
|
|
662
|
-
state: {
|
|
663
|
-
...state,
|
|
664
|
-
importedFunctionsMap,
|
|
665
|
-
},
|
|
666
|
-
output,
|
|
667
|
-
functionName,
|
|
668
|
-
path,
|
|
669
|
-
});
|
|
670
|
-
}
|
|
671
|
-
},
|
|
672
|
-
// Collect re-exports: export * from './other'
|
|
673
|
-
ExportAllDeclaration(path) {
|
|
674
|
-
if (t.isStringLiteral(path.node.source)) {
|
|
675
|
-
reExports.push(path.node.source.value);
|
|
676
|
-
}
|
|
677
|
-
},
|
|
678
|
-
// Collect named re-exports: export { foo } from './other'
|
|
679
|
-
ExportNamedDeclaration(path) {
|
|
680
|
-
if (path.node.source && t.isStringLiteral(path.node.source)) {
|
|
681
|
-
// Check if this export includes our function
|
|
682
|
-
const exportsFunction = path.node.specifiers.some((spec) => {
|
|
683
|
-
if (t.isExportSpecifier(spec)) {
|
|
684
|
-
const exportedName = t.isIdentifier(spec.exported)
|
|
685
|
-
? spec.exported.name
|
|
686
|
-
: spec.exported.value;
|
|
687
|
-
return exportedName === functionName;
|
|
688
|
-
}
|
|
689
|
-
return false;
|
|
690
|
-
});
|
|
691
|
-
if (exportsFunction) {
|
|
692
|
-
reExports.push(path.node.source.value);
|
|
693
|
-
}
|
|
694
|
-
}
|
|
695
|
-
},
|
|
696
|
-
});
|
|
697
|
-
// If function not found, follow re-exports
|
|
698
|
-
if (result === undefined && reExports.length > 0) {
|
|
699
|
-
for (const reExportPath of reExports) {
|
|
700
|
-
const resolvedPath = resolveImportPath(filePath, reExportPath, config.parsingOptions, resolveImportPathCache);
|
|
701
|
-
if (resolvedPath) {
|
|
702
|
-
const foundResult = processFunctionInFile({
|
|
703
|
-
config: {
|
|
704
|
-
importAliases,
|
|
705
|
-
parsingOptions: config.parsingOptions,
|
|
706
|
-
pkgs: config.pkgs,
|
|
707
|
-
file: filePath,
|
|
708
|
-
},
|
|
709
|
-
state: {
|
|
710
|
-
...state,
|
|
711
|
-
importedFunctionsMap,
|
|
712
|
-
},
|
|
713
|
-
output,
|
|
714
|
-
filePath: resolvedPath,
|
|
715
|
-
functionName,
|
|
716
|
-
});
|
|
717
|
-
if (foundResult != null) {
|
|
718
|
-
result = foundResult;
|
|
719
|
-
break;
|
|
720
|
-
}
|
|
721
|
-
}
|
|
722
|
-
}
|
|
723
|
-
}
|
|
724
|
-
// Mark this function search as processed in the cache
|
|
725
|
-
processFunctionCache.set(cacheKey, result !== undefined ? result : null);
|
|
726
|
-
}
|
|
727
|
-
catch {
|
|
728
|
-
// Silently skip files that can't be parsed or accessed
|
|
729
|
-
// Still mark as processed to avoid retrying failed parses
|
|
730
|
-
processFunctionCache.set(cacheKey, null);
|
|
731
|
-
}
|
|
732
|
-
return result !== undefined ? result : null;
|
|
733
|
-
}
|
|
734
|
-
/**
|
|
735
|
-
* Process a function declaration
|
|
736
|
-
* function getInfo() { ... }
|
|
737
|
-
*/
|
|
738
|
-
function processFunctionDeclarationNodePath({ config, state, output, path, }) {
|
|
739
|
-
const result = {
|
|
740
|
-
nodeType: 'multiplication',
|
|
741
|
-
branches: [],
|
|
742
|
-
};
|
|
743
|
-
path.traverse({
|
|
744
|
-
Function(path) {
|
|
745
|
-
path.skip();
|
|
746
|
-
},
|
|
747
|
-
ReturnStatement(returnPath) {
|
|
748
|
-
const returnNodePath = returnPath.get('argument');
|
|
749
|
-
if (!returnNodePath.isExpression()) {
|
|
750
|
-
return;
|
|
751
|
-
}
|
|
752
|
-
result.branches.push(processStaticExpression({
|
|
753
|
-
config,
|
|
754
|
-
state,
|
|
755
|
-
output,
|
|
756
|
-
expressionNodePath: returnNodePath,
|
|
757
|
-
scopeNode: returnPath,
|
|
758
|
-
}));
|
|
759
|
-
},
|
|
760
|
-
});
|
|
761
|
-
if (result.branches.length === 0) {
|
|
762
|
-
return null;
|
|
763
|
-
}
|
|
764
|
-
return result;
|
|
765
|
-
}
|
|
766
|
-
/**
|
|
767
|
-
* Process a variable declaration of a function
|
|
768
|
-
* const getInfo = () => { ... }
|
|
769
|
-
*
|
|
770
|
-
* IMPORTANT: the RHand value must be the function definition, or this will fail
|
|
771
|
-
*/
|
|
772
|
-
function processVariableDeclarationNodePath({ config, state, output, functionName, path, }) {
|
|
773
|
-
const result = {
|
|
774
|
-
nodeType: 'multiplication',
|
|
775
|
-
branches: [],
|
|
776
|
-
};
|
|
777
|
-
// Enforce the Rhand is a function definition
|
|
778
|
-
const arrowFunctionPath = path.get('init');
|
|
779
|
-
if (!arrowFunctionPath.isArrowFunctionExpression()) {
|
|
780
|
-
output.errors.push(warnInvalidStaticInitSync(config.file, functionName, `${path.node.loc?.start?.line}:${path.node.loc?.start?.column}`));
|
|
781
|
-
return null;
|
|
782
|
-
}
|
|
783
|
-
const bodyNodePath = arrowFunctionPath.get('body');
|
|
784
|
-
if (bodyNodePath.isExpression()) {
|
|
785
|
-
// process expression return
|
|
786
|
-
result.branches.push(processStaticExpression({
|
|
787
|
-
config,
|
|
788
|
-
state,
|
|
789
|
-
output,
|
|
790
|
-
expressionNodePath: bodyNodePath,
|
|
791
|
-
scopeNode: arrowFunctionPath,
|
|
792
|
-
}));
|
|
793
|
-
}
|
|
794
|
-
else {
|
|
795
|
-
// search for a return statement
|
|
796
|
-
bodyNodePath.traverse({
|
|
797
|
-
Function(path) {
|
|
798
|
-
path.skip();
|
|
799
|
-
},
|
|
800
|
-
ReturnStatement(returnPath) {
|
|
801
|
-
const returnNodePath = returnPath.get('argument');
|
|
802
|
-
if (!returnNodePath.isExpression()) {
|
|
803
|
-
return;
|
|
804
|
-
}
|
|
805
|
-
result.branches.push(processStaticExpression({
|
|
806
|
-
config,
|
|
807
|
-
state,
|
|
808
|
-
output,
|
|
809
|
-
expressionNodePath: returnNodePath,
|
|
810
|
-
scopeNode: returnPath,
|
|
811
|
-
}));
|
|
812
|
-
},
|
|
813
|
-
});
|
|
814
|
-
}
|
|
815
|
-
if (result.branches.length === 0) {
|
|
816
|
-
output.errors.push(warnMissingReturnSync(config.file, functionName, `${path.node.loc?.start?.line}:${path.node.loc?.start?.column}`));
|
|
817
|
-
return null;
|
|
818
|
-
}
|
|
819
|
-
return result;
|
|
820
|
-
}
|
|
821
|
-
/**
|
|
822
|
-
* Process a <Static> expression
|
|
823
|
-
*/
|
|
824
|
-
function processStaticExpression({ config, state, output, expressionNodePath, scopeNode, }) {
|
|
825
|
-
// Mark the static tracker as true
|
|
826
|
-
state.staticTracker.isStatic = true;
|
|
827
|
-
// Remove parentheses if they exist
|
|
828
|
-
if (t.isParenthesizedExpression(expressionNodePath.node)) {
|
|
829
|
-
// ex: return (value)
|
|
830
|
-
return processStaticExpression({
|
|
831
|
-
config,
|
|
832
|
-
state,
|
|
833
|
-
output,
|
|
834
|
-
scopeNode,
|
|
835
|
-
expressionNodePath: expressionNodePath.get('expression'),
|
|
836
|
-
});
|
|
837
|
-
}
|
|
838
|
-
else if (t.isCallExpression(expressionNodePath.node) &&
|
|
839
|
-
t.isIdentifier(expressionNodePath.node.callee)) {
|
|
840
|
-
// ex: return someFunc()
|
|
841
|
-
const callee = expressionNodePath.node.callee;
|
|
842
|
-
const calleeBinding = scopeNode.scope.getBinding(callee.name);
|
|
843
|
-
if (!calleeBinding) {
|
|
844
|
-
output.warnings.add(warnFunctionNotFoundSync(config.file, callee.name, `${callee.loc?.start?.line}:${callee.loc?.start?.column}`));
|
|
845
|
-
return null;
|
|
846
|
-
}
|
|
847
|
-
// Function is found
|
|
848
|
-
return resolveStaticFunctionInvocationFromBinding({
|
|
849
|
-
calleeBinding,
|
|
850
|
-
callee,
|
|
851
|
-
config,
|
|
852
|
-
state,
|
|
853
|
-
output,
|
|
854
|
-
});
|
|
855
|
-
}
|
|
856
|
-
else if (t.isAwaitExpression(expressionNodePath.node) &&
|
|
857
|
-
t.isCallExpression(expressionNodePath.node.argument) &&
|
|
858
|
-
t.isIdentifier(expressionNodePath.node.argument.callee)) {
|
|
859
|
-
// ex: return await someFunc()
|
|
860
|
-
const callee = expressionNodePath.node.argument.callee;
|
|
861
|
-
const calleeBinding = scopeNode.scope.getBinding(callee.name);
|
|
862
|
-
if (!calleeBinding) {
|
|
863
|
-
output.warnings.add(warnFunctionNotFoundSync(config.file, callee.name, `${callee.loc?.start?.line}:${callee.loc?.start?.column}`));
|
|
864
|
-
return null;
|
|
865
|
-
}
|
|
866
|
-
// Function is found
|
|
867
|
-
return resolveStaticFunctionInvocationFromBinding({
|
|
868
|
-
calleeBinding,
|
|
869
|
-
callee,
|
|
870
|
-
config,
|
|
871
|
-
state,
|
|
872
|
-
output,
|
|
873
|
-
});
|
|
874
|
-
}
|
|
875
|
-
else if (t.isJSXElement(expressionNodePath.node) ||
|
|
876
|
-
t.isJSXFragment(expressionNodePath.node)) {
|
|
877
|
-
// ex: return <div>Jsx content</div>
|
|
878
|
-
return buildJSXTree({
|
|
879
|
-
node: expressionNodePath.node,
|
|
880
|
-
helperPath: expressionNodePath,
|
|
881
|
-
scopeNode,
|
|
882
|
-
insideT: true,
|
|
883
|
-
inStatic: true,
|
|
884
|
-
config,
|
|
885
|
-
state,
|
|
886
|
-
output,
|
|
887
|
-
});
|
|
888
|
-
}
|
|
889
|
-
else if (t.isConditionalExpression(expressionNodePath.node)) {
|
|
890
|
-
// ex: return condition ? <div>Jsx content</div> : <div>Jsx content</div>
|
|
891
|
-
// since two options here we must construct a new multiplication node
|
|
892
|
-
const consequentNodePath = expressionNodePath.get('consequent');
|
|
893
|
-
const alternateNodePath = expressionNodePath.get('alternate');
|
|
894
|
-
const result = {
|
|
895
|
-
nodeType: 'multiplication',
|
|
896
|
-
branches: [consequentNodePath, alternateNodePath].map((expressionNodePath) => processStaticExpression({
|
|
897
|
-
config,
|
|
898
|
-
state,
|
|
899
|
-
output,
|
|
900
|
-
scopeNode,
|
|
901
|
-
expressionNodePath,
|
|
902
|
-
})),
|
|
903
|
-
};
|
|
904
|
-
return result;
|
|
905
|
-
}
|
|
906
|
-
else {
|
|
907
|
-
return buildJSXTree({
|
|
908
|
-
node: expressionNodePath.node,
|
|
909
|
-
helperPath: expressionNodePath,
|
|
910
|
-
scopeNode,
|
|
911
|
-
insideT: true,
|
|
912
|
-
inStatic: true,
|
|
913
|
-
config,
|
|
914
|
-
state,
|
|
915
|
-
output,
|
|
916
|
-
});
|
|
917
|
-
}
|
|
918
|
-
}
|