@zohodesk/react-cli 1.1.29-exp.1 → 1.1.29-exp.2
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/lib/babel/babel-option-utils/babel-preset-react-option.js +0 -3
- package/lib/babel/cmjs-plugins-presets.js +1 -8
- package/lib/babel/es-plugins-presets.js +1 -8
- package/lib/common/buildEs.js +1 -0
- package/lib/common/getEntries.js +2 -13
- package/lib/common/getPublicPathConfig.js +0 -6
- package/lib/common/index.js +1 -6
- package/lib/common/runPreProcess.js +6 -15
- package/lib/common/splitChunks.js +2 -21
- package/lib/common/sslcertUpdater.js +7 -18
- package/lib/common/templateParameters.js +0 -2
- package/lib/common/testPattern.js +10 -21
- package/lib/common/valueReplacer.js +1 -16
- package/lib/configs/jest.config.js +1 -10
- package/lib/configs/libAlias.js +8 -14
- package/lib/configs/resolvers.js +4 -14
- package/lib/configs/webpack.component.umd.config.js +1 -6
- package/lib/configs/webpack.css.umd.config.js +6 -14
- package/lib/configs/webpack.dev.config.js +1 -14
- package/lib/configs/webpack.docs.config.js +1 -9
- package/lib/configs/webpack.impact.config.js +1 -8
- package/lib/configs/webpack.prod.config.js +4 -17
- package/lib/constants.js +9 -18
- package/lib/deprecationLogger.js +0 -7
- package/lib/hooks/docsProptypeHook.js +4 -8
- package/lib/jest/commitedFilesResult.js +4 -46
- package/lib/jest/coverageCollector.js +1 -12
- package/lib/jest/jsonMaker.js +0 -6
- package/lib/jest/preProcessors/cssPreprocessor.js +1 -9
- package/lib/jest/preProcessors/jsPreprocessor.js +1 -6
- package/lib/jest/preProcessors/otherFilesPreprocessor.js +1 -4
- package/lib/jest/result.js +1 -23
- package/lib/jest/run.js +7 -18
- package/lib/jest/setup.js +8 -60
- package/lib/loaderUtils/configsAssetsLoaders.js +2 -12
- package/lib/loaderUtils/getCSSLoaders.js +10 -22
- package/lib/loaderUtils/getDevJsLoaders.js +4 -13
- package/lib/loaderUtils/index.js +1 -4
- package/lib/loaderUtils/tests/windowsModification.test.js +0 -1
- package/lib/loaderUtils/windowsModification.js +2 -3
- package/lib/loaders/__test__/markdownLoader.spec.js +0 -1
- package/lib/loaders/composeLoader.js +13 -37
- package/lib/loaders/docsLoader.js +1 -12
- package/lib/loaders/docsPropsLoader.js +4 -8
- package/lib/loaders/enhancedReactLiveConverter.js +2 -23
- package/lib/loaders/fileBountryLoader.js +1 -3
- package/lib/loaders/fileLoader.js +12 -23
- package/lib/loaders/markdownLoader.js +14 -19
- package/lib/loaders/reactLiveConvertor.js +5 -15
- package/lib/loaders/scriptInstrumentLoader.js +7 -16
- package/lib/loaders/selectorMappingLoader.js +7 -26
- package/lib/loaders/workerLoader.js +9 -24
- package/lib/logger.js +0 -4
- package/lib/middlewares/HMRMiddleware.js +13 -27
- package/lib/middlewares/SSTMiddleware.js +1 -5
- package/lib/pluginUtils/configHtmlWebpackPlugins.js +1 -24
- package/lib/pluginUtils/getDevPlugins.js +9 -42
- package/lib/pluginUtils/getDocsPlugins.js +3 -13
- package/lib/pluginUtils/getLibraryImactPlugins.js +5 -6
- package/lib/pluginUtils/getLibraryPlugins.js +2 -8
- package/lib/pluginUtils/getProdPlugins.js +8 -47
- package/lib/pluginUtils/getServerPlugins.js +2 -8
- package/lib/pluginUtils/getUMDCSSPlugins.js +2 -10
- package/lib/pluginUtils/getUMDComponentPlugins.js +2 -10
- package/lib/pluginUtils/index.js +1 -9
- package/lib/plugins/CdnChangePlugin.js +2 -18
- package/lib/plugins/CleanupStatsPlugin.js +0 -5
- package/lib/plugins/CssOrderControlPlugin.js +3 -6
- package/lib/plugins/CustomAttributePlugin.js +14 -19
- package/lib/plugins/CustomScriptLoadingStrategyPlugin.js +3 -23
- package/lib/plugins/EFCPlugin.js +20 -34
- package/lib/plugins/EFCTemplatePlugin.js +19 -30
- package/lib/plugins/EfcResourceCleanupPlugin.js +0 -3
- package/lib/plugins/EventsHandlingPlugin.js +2 -4
- package/lib/plugins/I18NInjectIntoIndexPlugin.js +11 -37
- package/lib/plugins/I18nSplitPlugin/I18nDebugPlugin.js +10 -15
- package/lib/plugins/I18nSplitPlugin/I18nDependency.js +4 -10
- package/lib/plugins/I18nSplitPlugin/I18nDownlodLogic.js +12 -25
- package/lib/plugins/I18nSplitPlugin/I18nFilesEmitter.js +55 -133
- package/lib/plugins/I18nSplitPlugin/I18nKeysIdentifer.js +12 -23
- package/lib/plugins/I18nSplitPlugin/index.js +13 -24
- package/lib/plugins/I18nSplitPlugin/utils/applyMetaManifest.js +64 -58
- package/lib/plugins/I18nSplitPlugin/utils/collectI18nKeys.js +2 -12
- package/lib/plugins/I18nSplitPlugin/utils/createMetaManifest.js +10 -29
- package/lib/plugins/I18nSplitPlugin/utils/createRegularManifest.js +8 -19
- package/lib/plugins/I18nSplitPlugin/utils/getI18nFileUrlPathTemplate.js +0 -1
- package/lib/plugins/I18nSplitPlugin/utils/getI18nKeysFormModules.js +0 -5
- package/lib/plugins/I18nSplitPlugin/utils/hashUtils.js +1 -8
- package/lib/plugins/I18nSplitPlugin/utils/index.js +0 -4
- package/lib/plugins/I18nSplitPlugin/utils/propertiesUtils.js +0 -20
- package/lib/plugins/I18nSplitPlugin/utils/unicodeConversion.js +0 -1
- package/lib/plugins/ManifestPlugin.js +1 -18
- package/lib/plugins/MinifyPlugin.js +1 -10
- package/lib/plugins/ModuleStatsPlugin.js +1 -24
- package/lib/plugins/OptimizeJSPlugin.js +2 -10
- package/lib/plugins/PublicPathCallbackPlugin.js +1 -12
- package/lib/plugins/PublicPathChangePlugin.js +6 -39
- package/lib/plugins/ReportGeneratePlugin.js +5 -32
- package/lib/plugins/RequireVariablePublicPlugin.js +1 -8
- package/lib/plugins/ResourceHintsPlugin.js +4 -13
- package/lib/plugins/RtlSplitPlugin/OverwriteCssPathForRTL.js +12 -17
- package/lib/plugins/RtlSplitPlugin/RtlCssPlugin.js +10 -17
- package/lib/plugins/RtlSplitPlugin/replaceCssDirTemplate.js +2 -5
- package/lib/plugins/ScriptInstrumentPlugin.js +1 -8
- package/lib/plugins/SelectorPlugin.js +6 -32
- package/lib/plugins/ServiceWorkerPlugin.js +5 -22
- package/lib/plugins/ShadowDOMSupportPlugin.js +4 -41
- package/lib/plugins/SourceMapHookPlugin.js +2 -12
- package/lib/plugins/StatsPlugin.js +0 -14
- package/lib/plugins/TPHashMappingPlugin.js +3 -18
- package/lib/plugins/UnusedFilesFindPlugin.js +4 -39
- package/lib/plugins/VariableConversionCollector.js +15 -42
- package/lib/plugins/index.js +1 -20
- package/lib/plugins/libraryImpactPlugin.js +1 -33
- package/lib/plugins/newi18nsplitplugin/18nPlugin1.js +306 -0
- package/lib/plugins/newi18nsplitplugin/18nPlugin2.js +363 -0
- package/lib/plugins/newi18nsplitplugin/18nPlugin3.js +694 -0
- package/lib/plugins/newi18nsplitplugin/18nPlugin_hashed.js +1258 -0
- package/lib/plugins/newi18nsplitplugin/18nPlugin_working.js +542 -0
- package/lib/plugins/newi18nsplitplugin/18nplugin.js +974 -0
- package/lib/plugins/newi18nsplitplugin/ChunkManager.js +131 -0
- package/lib/plugins/newi18nsplitplugin/GenerateModuleIdToKeysMapPlugin.js +59 -0
- package/lib/plugins/newi18nsplitplugin/I18nDiffPlugin.js +262 -0
- package/lib/plugins/newi18nsplitplugin/I18nDownloadLogic.js +166 -0
- package/lib/plugins/newi18nsplitplugin/I18nPropertiesPlugin.js +111 -0
- package/lib/plugins/newi18nsplitplugin/KeyCollector.js +163 -0
- package/lib/plugins/newi18nsplitplugin/ManifestGenerator.js +88 -0
- package/lib/plugins/newi18nsplitplugin/UnicodeConversionPlugin.js +101 -0
- package/lib/plugins/newi18nsplitplugin/constants.js +162 -0
- package/lib/plugins/newi18nsplitplugin/utils/I18nKeyHasher.js +78 -0
- package/lib/plugins/newi18nsplitplugin/utils/getJsResourceKeys.js +22 -0
- package/lib/plugins/newi18nsplitplugin/utils/i18nChunkUtils.js +18 -0
- package/lib/plugins/newi18nsplitplugin/utils/manifestGenerator.js +580 -0
- package/lib/plugins/newi18nsplitplugin/utils/propertiesUtils.js +54 -0
- package/lib/plugins/utils/classHandling.js +0 -6
- package/lib/plugins/utils/fileHandling.js +6 -15
- package/lib/plugins/utils/tests/fileHandling.test.js +0 -4
- package/lib/plugins/variableConvertorUtils.js +14 -29
- package/lib/plugins/webpackwatchrunplugin.js +0 -5
- package/lib/postcss-plugins/EmptyPlugin.js +3 -4
- package/lib/postcss-plugins/ExcludePlugin.js +1 -5
- package/lib/postcss-plugins/IncludePlugin.js +1 -5
- package/lib/postcss-plugins/RTLSplitPlugin.js +14 -27
- package/lib/postcss-plugins/SelectorReplace.js +1 -16
- package/lib/postcss-plugins/ValueReplacer.js +7 -6
- package/lib/postcss-plugins/__test__/hoverActivePlugin.spec.js +0 -3
- package/lib/postcss-plugins/__test__/selectorReplace.test.js +6 -3
- package/lib/postcss-plugins/__test__/valueReplacer.spec.js +2 -5
- package/lib/postcss-plugins/hoverActivePlugin.js +31 -67
- package/lib/postcss-plugins/variableModificationPlugin/ErrorHandler.js +0 -7
- package/lib/postcss-plugins/variableModificationPlugin/index.js +28 -49
- package/lib/schemas/index.js +3 -9
- package/lib/servers/clusterHubServer.js +1 -11
- package/lib/servers/devBuild.js +14 -26
- package/lib/servers/docsServer.js +1 -3
- package/lib/servers/docsServerCore.js +1 -22
- package/lib/servers/getCliPath.js +0 -9
- package/lib/servers/helpServer.js +1 -6
- package/lib/servers/httpsOptions.js +2 -8
- package/lib/servers/impactServer.js +3 -35
- package/lib/servers/mockserver.js +1 -10
- package/lib/servers/nowatchserver.js +12 -37
- package/lib/servers/requireLocalOrGlobal.js +6 -17
- package/lib/servers/scrServer.js +14 -21
- package/lib/servers/server.js +6 -36
- package/lib/servers/ssServer.js +1 -17
- package/lib/templates/CoverageScriptTemplate.js +0 -14
- package/lib/templates/WMSTemplate.js +7 -13
- package/lib/templates/linterConstant.js +2 -4
- package/lib/utils/babelPresets.js +3 -7
- package/lib/utils/clean.js +3 -9
- package/lib/utils/copy.js +1 -7
- package/lib/utils/copyTimezones.js +1 -9
- package/lib/utils/createEventStream.js +1 -6
- package/lib/utils/cssClassNameGenerate.js +10 -30
- package/lib/utils/cssURLReplacer.js +1 -22
- package/lib/utils/dependencyPostPublish.js +1 -10
- package/lib/utils/deprecationSupport.js +7 -32
- package/lib/utils/fileUtils.js +1 -28
- package/lib/utils/folderIterator.js +2 -13
- package/lib/utils/getComponents.js +0 -21
- package/lib/utils/getCurrentBranch.js +0 -5
- package/lib/utils/getDependenciesImpactList.js +1 -22
- package/lib/utils/getFileType.js +2 -10
- package/lib/utils/getHash.js +1 -8
- package/lib/utils/getIp.js +0 -2
- package/lib/utils/getOptions.js +16 -53
- package/lib/utils/getServerURL.js +1 -10
- package/lib/utils/index.js +4 -51
- package/lib/utils/init.js +0 -1
- package/lib/utils/initPreCommitHook.js +7 -30
- package/lib/utils/jsonHelper.js +3 -22
- package/lib/utils/libraryImpactConfig.js +2 -5
- package/lib/utils/lint/addScripts.js +2 -5
- package/lib/utils/lint/checkExistingConfig.js +3 -12
- package/lib/utils/lint/copyConfigs.js +0 -3
- package/lib/utils/lint/index.js +0 -9
- package/lib/utils/lint/lintScripts.js +0 -1
- package/lib/utils/lint/lintSetup.js +3 -4
- package/lib/utils/lint/lintStagedPreCommitHook.js +0 -1
- package/lib/utils/lint/question.js +0 -7
- package/lib/utils/lintReporter.js +0 -20
- package/lib/utils/log.js +0 -1
- package/lib/utils/mailSender.js +1 -8
- package/lib/utils/object-manipulation.js +1 -17
- package/lib/utils/pullOrigin.js +0 -4
- package/lib/utils/reinstallDependencies.js +1 -29
- package/lib/utils/removeAttributes.js +1 -8
- package/lib/utils/repoClone.js +3 -28
- package/lib/utils/request.js +0 -12
- package/lib/utils/rtl.js +5 -17
- package/lib/utils/selectorReplacer.js +10 -16
- package/lib/utils/setEnvVariables.js +0 -2
- package/lib/utils/ssTestHack.js +1 -11
- package/lib/utils/switchBranch.js +0 -5
- package/lib/utils/typeCheck.js +0 -1
- package/lib/utils/urlConcat.js +0 -4
- package/lib/utils/useExitCleanup.js +9 -10
- package/lib/utils/variableConverter.js +22 -31
- package/{npm-shrinkwrap.json → package-lock.json} +2098 -1999
- package/package.json +1 -1
@@ -0,0 +1,111 @@
|
|
1
|
+
"use strict";
|
2
|
+
|
3
|
+
// I18nPropertiesPlugin.js
|
4
|
+
const fs = require('fs');
|
5
|
+
const path = require('path');
|
6
|
+
class I18nPropertiesPlugin {
|
7
|
+
constructor(options = {}) {
|
8
|
+
// Default options
|
9
|
+
this.options = Object.assign({
|
10
|
+
propertiesDir: '',
|
11
|
+
// Directory containing .properties files
|
12
|
+
outputDir: 'i18n',
|
13
|
+
// Output directory in the build output
|
14
|
+
outputFormat: 'json',
|
15
|
+
// Output format: 'json' or 'js'
|
16
|
+
encoding: 'utf8' // File encoding
|
17
|
+
}, options);
|
18
|
+
}
|
19
|
+
apply(compiler) {
|
20
|
+
compiler.hooks.thisCompilation.tap('I18nPropertiesPlugin', compilation => {
|
21
|
+
compilation.hooks.processAssets.tapAsync({
|
22
|
+
name: 'I18nPropertiesPlugin',
|
23
|
+
stage: compilation.constructor.PROCESS_ASSETS_STAGE_ADDITIONS
|
24
|
+
}, (assets, callback) => {
|
25
|
+
this.processPropertiesFiles(compilation).then(() => callback()).catch(error => callback(error));
|
26
|
+
});
|
27
|
+
});
|
28
|
+
}
|
29
|
+
async processPropertiesFiles(compilation) {
|
30
|
+
const propertiesDir = path.resolve(this.options.propertiesDir);
|
31
|
+
const files = await this.getPropertiesFiles(propertiesDir);
|
32
|
+
for (const file of files) {
|
33
|
+
const content = fs.readFileSync(file, this.options.encoding);
|
34
|
+
const transformed = this.transformProperties(content);
|
35
|
+
const relativePath = path.relative(propertiesDir, file);
|
36
|
+
const outputFileName = this.getOutputFileName(relativePath);
|
37
|
+
const outputContent = this.getOutputContent(transformed); // Emit the file into the Webpack output
|
38
|
+
|
39
|
+
compilation.emitAsset(outputFileName, {
|
40
|
+
source: () => outputContent,
|
41
|
+
size: () => outputContent.length
|
42
|
+
});
|
43
|
+
}
|
44
|
+
}
|
45
|
+
async getPropertiesFiles(dir) {
|
46
|
+
const entries = fs.readdirSync(dir, {
|
47
|
+
withFileTypes: true
|
48
|
+
});
|
49
|
+
const files = [];
|
50
|
+
for (const entry of entries) {
|
51
|
+
const fullPath = path.join(dir, entry.name);
|
52
|
+
if (entry.isDirectory()) {
|
53
|
+
files.push(...(await this.getPropertiesFiles(fullPath)));
|
54
|
+
} else if (entry.isFile() && entry.name.endsWith('.properties')) {
|
55
|
+
files.push(fullPath);
|
56
|
+
}
|
57
|
+
}
|
58
|
+
return files;
|
59
|
+
}
|
60
|
+
transformProperties(content) {
|
61
|
+
const properties = this.parseProperties(content);
|
62
|
+
const transformed = {};
|
63
|
+
for (const [key, value] of Object.entries(properties)) {
|
64
|
+
transformed[key] = this.convertUnicodeToNative(value);
|
65
|
+
}
|
66
|
+
return transformed;
|
67
|
+
}
|
68
|
+
parseProperties(content) {
|
69
|
+
const result = {};
|
70
|
+
const lines = content.split(/\r?\n/);
|
71
|
+
for (let line of lines) {
|
72
|
+
line = line.trim();
|
73
|
+
if (line && !line.startsWith('#')) {
|
74
|
+
const [key, ...valueParts] = line.split('=');
|
75
|
+
if (key && valueParts.length > 0) {
|
76
|
+
const value = valueParts.join('=').trim();
|
77
|
+
result[key.trim()] = value;
|
78
|
+
}
|
79
|
+
}
|
80
|
+
}
|
81
|
+
return result;
|
82
|
+
}
|
83
|
+
convertUnicodeToNative(str) {
|
84
|
+
return str.replace(/\\u([0-9a-fA-F]{4})/g, (match, hex) => {
|
85
|
+
try {
|
86
|
+
return String.fromCharCode(parseInt(hex, 16));
|
87
|
+
} catch (err) {
|
88
|
+
return match;
|
89
|
+
}
|
90
|
+
});
|
91
|
+
}
|
92
|
+
getOutputFileName(relativePath) {
|
93
|
+
const ext = path.extname(relativePath);
|
94
|
+
const baseName = path.basename(relativePath, ext);
|
95
|
+
const dirName = path.dirname(relativePath);
|
96
|
+
let outputFileName = `${baseName}.${this.options.outputFormat}`;
|
97
|
+
if (dirName && dirName !== '.') {
|
98
|
+
outputFileName = path.join(dirName, outputFileName);
|
99
|
+
}
|
100
|
+
return path.join(this.options.outputDir, outputFileName);
|
101
|
+
}
|
102
|
+
getOutputContent(transformed) {
|
103
|
+
if (this.options.outputFormat === 'json') {
|
104
|
+
return JSON.stringify(transformed, null, 2);
|
105
|
+
} else if (this.options.outputFormat === 'js') {
|
106
|
+
return `module.exports = ${JSON.stringify(transformed, null, 2)};`;
|
107
|
+
}
|
108
|
+
throw new Error(`Unsupported output format: ${this.options.outputFormat}`);
|
109
|
+
}
|
110
|
+
}
|
111
|
+
module.exports = I18nPropertiesPlugin;
|
@@ -0,0 +1,163 @@
|
|
1
|
+
"use strict";
|
2
|
+
|
3
|
+
const path = require('path');
|
4
|
+
const fs = require('fs');
|
5
|
+
const crypto = require('crypto');
|
6
|
+
const {
|
7
|
+
walk
|
8
|
+
} = require('estree-walker');
|
9
|
+
const {
|
10
|
+
RawSource
|
11
|
+
} = require('webpack-sources');
|
12
|
+
const parser = require('@babel/parser');
|
13
|
+
const generate = require('@babel/generator').default;
|
14
|
+
const pluginName = 'I18nKeyHashPlugin';
|
15
|
+
class I18nKeyHashPlugin {
|
16
|
+
constructor(options = {}) {
|
17
|
+
const {
|
18
|
+
jsResourcePath
|
19
|
+
} = options;
|
20
|
+
if (!jsResourcePath) {
|
21
|
+
throw new Error('jsResourcePath is required');
|
22
|
+
}
|
23
|
+
this.jsResourcePath = jsResourcePath;
|
24
|
+
this.keyToHashMap = new Map();
|
25
|
+
this.processedFiles = new WeakSet();
|
26
|
+
this.preserveStringKeys = new Set(['Delete',
|
27
|
+
// Common UI strings that shouldn't be hashed
|
28
|
+
'Cancel', 'Save', 'Close']);
|
29
|
+
}
|
30
|
+
hashKey(key) {
|
31
|
+
// Don't hash preserved strings
|
32
|
+
if (this.preserveStringKeys.has(key)) {
|
33
|
+
return key;
|
34
|
+
}
|
35
|
+
if (this.keyToHashMap.has(key)) {
|
36
|
+
return this.keyToHashMap.get(key);
|
37
|
+
}
|
38
|
+
const hash = crypto.createHash('md5').update(key).digest('hex').substring(0, 7);
|
39
|
+
this.keyToHashMap.set(key, hash);
|
40
|
+
return hash;
|
41
|
+
}
|
42
|
+
loadI18nKeys() {
|
43
|
+
try {
|
44
|
+
const content = fs.readFileSync(this.jsResourcePath, 'utf8');
|
45
|
+
const i18nObj = {};
|
46
|
+
content.split(/\r?\n/).forEach(line => {
|
47
|
+
const trimmedLine = line.trim();
|
48
|
+
if (!trimmedLine || trimmedLine.startsWith('#')) return;
|
49
|
+
const ind = trimmedLine.indexOf('=');
|
50
|
+
if (ind <= 0) return;
|
51
|
+
const key = trimmedLine.slice(0, ind).trim();
|
52
|
+
const value = trimmedLine.slice(ind + 1).trim();
|
53
|
+
if (key && value) {
|
54
|
+
i18nObj[key] = value; // Pre-generate hash
|
55
|
+
|
56
|
+
this.hashKey(key);
|
57
|
+
}
|
58
|
+
});
|
59
|
+
return i18nObj;
|
60
|
+
} catch (err) {
|
61
|
+
return {};
|
62
|
+
}
|
63
|
+
}
|
64
|
+
safeGenerateCode(ast) {
|
65
|
+
try {
|
66
|
+
const result = generate(ast, {
|
67
|
+
retainLines: true,
|
68
|
+
compact: false,
|
69
|
+
concise: false,
|
70
|
+
quotes: 'single',
|
71
|
+
jsonCompatibleStrings: true
|
72
|
+
});
|
73
|
+
return result.code;
|
74
|
+
} catch (err) {
|
75
|
+
throw new Error(`Code generation failed: ${err.message}`);
|
76
|
+
}
|
77
|
+
}
|
78
|
+
processSafeStringLiteral(node, hash) {
|
79
|
+
// Handle template literals more carefully
|
80
|
+
if (node.type === 'TemplateLiteral') {
|
81
|
+
return; // Skip template literals for safety
|
82
|
+
} // Handle regular string literals
|
83
|
+
|
84
|
+
if ((node.type === 'StringLiteral' || node.type === 'Literal') && typeof node.value === 'string') {
|
85
|
+
node.value = hash;
|
86
|
+
node.raw = `'${hash}'`;
|
87
|
+
if (node.extra) {
|
88
|
+
node.extra.raw = `'${hash}'`;
|
89
|
+
node.extra.rawValue = hash;
|
90
|
+
}
|
91
|
+
}
|
92
|
+
}
|
93
|
+
processAST(ast, i18nKeys) {
|
94
|
+
let modified = false;
|
95
|
+
try {
|
96
|
+
walk(ast, {
|
97
|
+
enter: node => {
|
98
|
+
// Handle string literals in JSX attributes
|
99
|
+
if ((node.type === 'StringLiteral' || node.type === 'Literal') && typeof node.value === 'string' && i18nKeys[node.value]) {
|
100
|
+
const hash = this.hashKey(node.value);
|
101
|
+
this.processSafeStringLiteral(node, hash);
|
102
|
+
modified = true;
|
103
|
+
} // Handle JSXText differently
|
104
|
+
|
105
|
+
if (node.type === 'JSXText' && i18nKeys[node.value.trim()]) {
|
106
|
+
const key = node.value.trim();
|
107
|
+
const hash = this.hashKey(key);
|
108
|
+
node.value = hash;
|
109
|
+
modified = true;
|
110
|
+
}
|
111
|
+
}
|
112
|
+
});
|
113
|
+
} catch (err) {
|
114
|
+
throw new Error(`AST processing failed: ${err.message}`);
|
115
|
+
}
|
116
|
+
return modified;
|
117
|
+
}
|
118
|
+
apply(compiler) {
|
119
|
+
let i18nKeys;
|
120
|
+
compiler.hooks.compilation.tap(pluginName, compilation => {
|
121
|
+
if (!i18nKeys) {
|
122
|
+
i18nKeys = this.loadI18nKeys();
|
123
|
+
}
|
124
|
+
compilation.hooks.succeedModule.tap(pluginName, module => {
|
125
|
+
if (!module.resource || !/\.(js|jsx|ts|tsx)$/.test(module.resource) || this.processedFiles.has(module)) {
|
126
|
+
return;
|
127
|
+
}
|
128
|
+
try {
|
129
|
+
const source = module._source.source(); // Parse with more precise settings
|
130
|
+
|
131
|
+
const ast = parser.parse(source, {
|
132
|
+
sourceType: 'module',
|
133
|
+
plugins: ['jsx', 'typescript', 'classProperties', 'decorators-legacy'],
|
134
|
+
tokens: true,
|
135
|
+
errorRecovery: true
|
136
|
+
});
|
137
|
+
if (this.processAST(ast, i18nKeys)) {
|
138
|
+
const newCode = this.safeGenerateCode(ast);
|
139
|
+
module._source = new RawSource(newCode); // Update module hash
|
140
|
+
|
141
|
+
module.buildInfo.hash = crypto.createHash('md5').update(newCode).digest('hex');
|
142
|
+
}
|
143
|
+
this.processedFiles.add(module);
|
144
|
+
} catch (err) {
|
145
|
+
// Log error but don't fail the build
|
146
|
+
compilation.warnings.push(new Error(`[${pluginName}] Processing ${module.resource} failed: ${err.message}`));
|
147
|
+
}
|
148
|
+
}); // Generate manifest after processing
|
149
|
+
|
150
|
+
compilation.hooks.afterOptimizeModules.tap(pluginName, () => {
|
151
|
+
const manifest = {
|
152
|
+
hashMapping: Object.fromEntries(this.keyToHashMap),
|
153
|
+
metadata: {
|
154
|
+
totalKeys: this.keyToHashMap.size,
|
155
|
+
timestamp: Date.now()
|
156
|
+
}
|
157
|
+
};
|
158
|
+
compilation.assets['i18n-hash-manifest.json'] = new RawSource(JSON.stringify(manifest, null, 2));
|
159
|
+
});
|
160
|
+
});
|
161
|
+
}
|
162
|
+
}
|
163
|
+
module.exports = I18nKeyHashPlugin;
|
@@ -0,0 +1,88 @@
|
|
1
|
+
"use strict";
|
2
|
+
|
3
|
+
const {
|
4
|
+
RawSource
|
5
|
+
} = require('webpack-sources');
|
6
|
+
function generateManifests({
|
7
|
+
compilation,
|
8
|
+
allI18nKeys,
|
9
|
+
moduleToKeysMap,
|
10
|
+
cacheGroupToModulesMap,
|
11
|
+
jsResourceI18nKeys
|
12
|
+
}) {
|
13
|
+
const manifest = {
|
14
|
+
cacheGroupToI18nMap: {},
|
15
|
+
locales: {}
|
16
|
+
};
|
17
|
+
const metaManifest = {
|
18
|
+
keyToCacheGroupMap: {}
|
19
|
+
};
|
20
|
+
const locales = Object.keys(allI18nKeys); // Map keys to cache groups
|
21
|
+
|
22
|
+
const keyToCacheGroupMap = {};
|
23
|
+
for (const [cacheGroupName, moduleResources] of cacheGroupToModulesMap.entries()) {
|
24
|
+
const cacheGroupI18nKeys = new Set();
|
25
|
+
for (const moduleResource of moduleResources) {
|
26
|
+
const keys = moduleToKeysMap.get(moduleResource);
|
27
|
+
if (keys) {
|
28
|
+
keys.forEach(key => {
|
29
|
+
if (jsResourceI18nKeys.hasOwnProperty(key)) {
|
30
|
+
cacheGroupI18nKeys.add(key); // Map key to cache group for meta manifest
|
31
|
+
|
32
|
+
if (!keyToCacheGroupMap[key]) {
|
33
|
+
keyToCacheGroupMap[key] = new Set();
|
34
|
+
}
|
35
|
+
keyToCacheGroupMap[key].add(cacheGroupName);
|
36
|
+
}
|
37
|
+
});
|
38
|
+
}
|
39
|
+
} // Generate i18n files per cache group and locale
|
40
|
+
|
41
|
+
for (const locale of locales) {
|
42
|
+
const i18nData = {};
|
43
|
+
const localeData = allI18nKeys[locale];
|
44
|
+
for (const key of cacheGroupI18nKeys) {
|
45
|
+
// Find the key in the locale data
|
46
|
+
let found = false;
|
47
|
+
for (const section of Object.values(localeData)) {
|
48
|
+
if (section.hasOwnProperty(key)) {
|
49
|
+
i18nData[key] = section[key];
|
50
|
+
found = true;
|
51
|
+
break;
|
52
|
+
}
|
53
|
+
}
|
54
|
+
if (!found) {
|
55
|
+
console.warn(`Key "${key}" not found in locale "${locale}"`);
|
56
|
+
}
|
57
|
+
} // Create the i18n chunk file
|
58
|
+
|
59
|
+
const moduleSource = `window.loadI18nChunk(${JSON.stringify(i18nData, null, 2)});`;
|
60
|
+
const filename = `i18n-chunks/${locale}/${cacheGroupName}.js`;
|
61
|
+
compilation.emitAsset(filename, new RawSource(moduleSource)); // Update the main manifest
|
62
|
+
|
63
|
+
if (!manifest.locales[locale]) {
|
64
|
+
manifest.locales[locale] = {};
|
65
|
+
}
|
66
|
+
manifest.locales[locale][cacheGroupName] = filename;
|
67
|
+
} // Update the cacheGroupToI18nMap
|
68
|
+
|
69
|
+
manifest.cacheGroupToI18nMap[cacheGroupName] = cacheGroupName;
|
70
|
+
} // Generate the meta manifest by converting Sets to Arrays
|
71
|
+
|
72
|
+
for (const [key, cacheGroupsSet] of Object.entries(keyToCacheGroupMap)) {
|
73
|
+
metaManifest.keyToCacheGroupMap[key] = Array.from(cacheGroupsSet);
|
74
|
+
} // Emit the main manifest file
|
75
|
+
|
76
|
+
const manifestSource = new RawSource(`window.i18n = window.i18n || {}; window.i18n.manifest = ${JSON.stringify(manifest, null, 2)};`);
|
77
|
+
const manifestFilename = 'i18n-chunk/manifest.js';
|
78
|
+
compilation.emitAsset(manifestFilename, manifestSource);
|
79
|
+
console.log(`Emitted i18n manifest: ${manifestFilename}`); // Emit the meta manifest file
|
80
|
+
|
81
|
+
const metaManifestSource = new RawSource(JSON.stringify(metaManifest, null, 2));
|
82
|
+
const metaManifestFilename = 'i18n-chunk/metaManifest.json';
|
83
|
+
compilation.emitAsset(metaManifestFilename, metaManifestSource);
|
84
|
+
console.log(`Emitted i18n meta manifest: ${metaManifestFilename}`);
|
85
|
+
}
|
86
|
+
module.exports = {
|
87
|
+
generateManifests
|
88
|
+
};
|
@@ -0,0 +1,101 @@
|
|
1
|
+
"use strict";
|
2
|
+
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
4
|
+
value: true
|
5
|
+
});
|
6
|
+
exports.default = void 0;
|
7
|
+
var _webpackSources = require("webpack-sources");
|
8
|
+
var _path = _interopRequireDefault(require("path"));
|
9
|
+
var _fs = _interopRequireDefault(require("fs"));
|
10
|
+
function _interopRequireDefault(obj) {
|
11
|
+
return obj && obj.__esModule ? obj : {
|
12
|
+
default: obj
|
13
|
+
};
|
14
|
+
}
|
15
|
+
|
16
|
+
// UnicodeConversionPlugin.js
|
17
|
+
class UnicodeConversionPlugin {
|
18
|
+
constructor(options = {}) {
|
19
|
+
this.options = {
|
20
|
+
test: '',
|
21
|
+
// i18nPublicPath
|
22
|
+
encoding: 'utf8',
|
23
|
+
debug: false,
|
24
|
+
...options
|
25
|
+
};
|
26
|
+
}
|
27
|
+
apply(compiler) {
|
28
|
+
// Run before the I18n plugin
|
29
|
+
compiler.hooks.beforeRun.tapAsync('UnicodeConversionPlugin', (compiler, callback) => {
|
30
|
+
try {
|
31
|
+
const targetPath = _path.default.resolve(compiler.context, this.options.test);
|
32
|
+
if (!_fs.default.existsSync(targetPath)) {
|
33
|
+
throw new Error(`Path not found: ${targetPath}`);
|
34
|
+
} // Convert files in place
|
35
|
+
|
36
|
+
this.convertFilesInPlace(targetPath);
|
37
|
+
callback();
|
38
|
+
} catch (err) {
|
39
|
+
callback(err);
|
40
|
+
}
|
41
|
+
});
|
42
|
+
}
|
43
|
+
convertFilesInPlace(targetPath) {
|
44
|
+
const processDir = dir => {
|
45
|
+
const files = _fs.default.readdirSync(dir);
|
46
|
+
files.forEach(file => {
|
47
|
+
const fullPath = _path.default.join(dir, file);
|
48
|
+
const stat = _fs.default.statSync(fullPath);
|
49
|
+
if (stat.isDirectory()) {
|
50
|
+
processDir(fullPath);
|
51
|
+
} else if (file.endsWith('.properties')) {
|
52
|
+
try {
|
53
|
+
// Read file
|
54
|
+
const content = _fs.default.readFileSync(fullPath, this.options.encoding); // Convert content
|
55
|
+
|
56
|
+
const convertedContent = this.convertUnicode(content); // Write back to same file
|
57
|
+
|
58
|
+
_fs.default.writeFileSync(fullPath, convertedContent, this.options.encoding);
|
59
|
+
if (this.options.debug) {
|
60
|
+
console.log(`[UnicodeConversionPlugin] Converted: ${_path.default.relative(targetPath, fullPath)}`);
|
61
|
+
}
|
62
|
+
} catch (error) {
|
63
|
+
console.error(`Error processing ${fullPath}: ${error.message}`);
|
64
|
+
}
|
65
|
+
}
|
66
|
+
});
|
67
|
+
};
|
68
|
+
processDir(targetPath);
|
69
|
+
}
|
70
|
+
convertUnicode(content) {
|
71
|
+
const lines = content.split(/\r?\n/);
|
72
|
+
const converted = lines.map(line => {
|
73
|
+
// Skip comments and empty lines
|
74
|
+
if (line.startsWith('#') || !line.trim()) {
|
75
|
+
return line;
|
76
|
+
} // Find key-value separator
|
77
|
+
|
78
|
+
const equalIndex = line.indexOf('=');
|
79
|
+
if (equalIndex === -1) {
|
80
|
+
return line;
|
81
|
+
}
|
82
|
+
const key = line.substring(0, equalIndex).trim();
|
83
|
+
const value = line.substring(equalIndex + 1).trim(); // Convert unicode escapes in the value
|
84
|
+
|
85
|
+
const convertedValue = this.convertUnicodeEscapes(value);
|
86
|
+
return `${key}=${convertedValue}`;
|
87
|
+
});
|
88
|
+
return converted.join('\n');
|
89
|
+
}
|
90
|
+
convertUnicodeEscapes(str) {
|
91
|
+
return str.replace(/\\u([0-9a-fA-F]{4})/g, (match, hex) => {
|
92
|
+
try {
|
93
|
+
return String.fromCharCode(parseInt(hex, 16));
|
94
|
+
} catch (err) {
|
95
|
+
throw new Error(`Invalid unicode escape sequence: ${match}`);
|
96
|
+
}
|
97
|
+
});
|
98
|
+
}
|
99
|
+
}
|
100
|
+
var _default = UnicodeConversionPlugin;
|
101
|
+
exports.default = _default;
|
@@ -0,0 +1,162 @@
|
|
1
|
+
"use strict";
|
2
|
+
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
4
|
+
value: true
|
5
|
+
});
|
6
|
+
exports.VALIDATION = exports.RUNTIME_CONFIG = exports.RETRY_STRATEGY = exports.PERFORMANCE = exports.MANIFEST_FIELDS = exports.LOADING_MODES = exports.FILE_PATTERNS = exports.FILE_DEFAULTS = exports.FEATURES = exports.ERROR_MESSAGES = exports.CHUNK_SIZE_LIMITS = exports.CHUNK_HINTS = exports.CACHE_CONFIG = exports.ALL_I18N_KEYS = void 0;
|
7
|
+
// constants.js
|
8
|
+
// Chunk size limits
|
9
|
+
const CHUNK_SIZE_LIMITS = {
|
10
|
+
// Maximum keys in a single chunk (prevent >60% keys in one chunk)
|
11
|
+
MAX_CHUNK_SIZE: 200,
|
12
|
+
// Minimum keys before considering chunk merge
|
13
|
+
MIN_CHUNK_SIZE: 50,
|
14
|
+
// Ideal chunk size for optimal loading
|
15
|
+
IDEAL_CHUNK_SIZE: 100,
|
16
|
+
// Maximum percentage of total keys in one chunk
|
17
|
+
MAX_CHUNK_PERCENTAGE: 0.2,
|
18
|
+
// 20%
|
19
|
+
// Chunk size variance allowed before rebalancing
|
20
|
+
CHUNK_SIZE_VARIANCE: 0.2 // 20% variance allowed
|
21
|
+
}; // Cache settings
|
22
|
+
|
23
|
+
exports.CHUNK_SIZE_LIMITS = CHUNK_SIZE_LIMITS;
|
24
|
+
const CACHE_CONFIG = {
|
25
|
+
// Maximum number of chunks to cache
|
26
|
+
MAX_CACHED_CHUNKS: 50,
|
27
|
+
// Maximum age of cached chunks (ms)
|
28
|
+
CACHE_TTL: 3600000,
|
29
|
+
// 1 hour
|
30
|
+
// Cache version for cache busting
|
31
|
+
CACHE_VERSION: '1.0.0'
|
32
|
+
}; // File patterns
|
33
|
+
|
34
|
+
exports.CACHE_CONFIG = CACHE_CONFIG;
|
35
|
+
const FILE_PATTERNS = {
|
36
|
+
// JavaScript file extensions to scan
|
37
|
+
JS_EXTENSIONS: /\.(js|jsx|ts|tsx)$/,
|
38
|
+
// i18n key patterns to match
|
39
|
+
I18N_KEY_PATTERN: /^[a-zA-Z0-9_.-]+$/,
|
40
|
+
// Comment patterns for i18n keys
|
41
|
+
I18N_COMMENT_PATTERN: /^i18n:/
|
42
|
+
}; // Loading modes
|
43
|
+
|
44
|
+
exports.FILE_PATTERNS = FILE_PATTERNS;
|
45
|
+
const LOADING_MODES = {
|
46
|
+
EAGER: 'eager',
|
47
|
+
// Load chunks immediately
|
48
|
+
LAZY: 'lazy',
|
49
|
+
// Load chunks on demand
|
50
|
+
PREFETCH: 'prefetch',
|
51
|
+
// Load chunks after main content
|
52
|
+
PRELOAD: 'preload' // Load chunks with high priority
|
53
|
+
}; // Default file names and paths
|
54
|
+
|
55
|
+
exports.LOADING_MODES = LOADING_MODES;
|
56
|
+
const FILE_DEFAULTS = {
|
57
|
+
// Default manifest file name
|
58
|
+
MANIFEST_FILE: 'i18n-manifest.json',
|
59
|
+
// Fallback manifest file name
|
60
|
+
FALLBACK_MANIFEST_FILE: 'i18n-manifest.main.json',
|
61
|
+
// Stats file name
|
62
|
+
STATS_FILE: 'i18n-stats.json',
|
63
|
+
// Default chunk file pattern
|
64
|
+
CHUNK_FILENAME: 'i18n-chunk/[locale]/[name].[chunkhash].i18n.js'
|
65
|
+
}; // Error messages
|
66
|
+
|
67
|
+
exports.FILE_DEFAULTS = FILE_DEFAULTS;
|
68
|
+
const ERROR_MESSAGES = {
|
69
|
+
NO_LOCALES: 'No locales specified in plugin options',
|
70
|
+
INVALID_KEY: 'Invalid i18n key format',
|
71
|
+
CHUNK_OVERFLOW: 'Chunk size exceeds maximum limit',
|
72
|
+
MANIFEST_ERROR: 'Failed to generate manifest',
|
73
|
+
LOAD_ERROR: 'Failed to load i18n chunk',
|
74
|
+
INVALID_CONFIG: 'Invalid plugin configuration'
|
75
|
+
}; // Feature flags for experimental features
|
76
|
+
|
77
|
+
exports.ERROR_MESSAGES = ERROR_MESSAGES;
|
78
|
+
const FEATURES = {
|
79
|
+
ENABLE_KEY_MOVEMENT_TRACKING: true,
|
80
|
+
ENABLE_CHUNK_STATS: true,
|
81
|
+
ENABLE_SMART_LOADING: true,
|
82
|
+
ENABLE_CACHE_OPTIMIZATION: true,
|
83
|
+
ENABLE_DEBUG_LOGGING: false
|
84
|
+
}; // Performance thresholds
|
85
|
+
|
86
|
+
exports.FEATURES = FEATURES;
|
87
|
+
const PERFORMANCE = {
|
88
|
+
// Maximum time to spend on chunk balancing (ms)
|
89
|
+
MAX_BALANCE_TIME: 1000,
|
90
|
+
// Maximum keys to process in one batch
|
91
|
+
BATCH_SIZE: 1000,
|
92
|
+
// Warning thresholds
|
93
|
+
WARNINGS: {
|
94
|
+
CHUNK_SIZE: 150,
|
95
|
+
// Warn when chunk exceeds this size
|
96
|
+
TOTAL_SIZE: 5000,
|
97
|
+
// Warn when total keys exceed this
|
98
|
+
LOAD_TIME: 500 // Warn when chunk load exceeds this (ms)
|
99
|
+
}
|
100
|
+
}; // Runtime configurations that can be overridden
|
101
|
+
|
102
|
+
exports.PERFORMANCE = PERFORMANCE;
|
103
|
+
const RUNTIME_CONFIG = {
|
104
|
+
// Default timeout for chunk loading (ms)
|
105
|
+
CHUNK_TIMEOUT: 30000,
|
106
|
+
// Number of retry attempts for failed loads
|
107
|
+
MAX_RETRIES: 3,
|
108
|
+
// Delay between retries (ms)
|
109
|
+
RETRY_DELAY: 1000,
|
110
|
+
// Enable verbose logging
|
111
|
+
DEBUG_MODE: false
|
112
|
+
}; // Manifest metadata fields
|
113
|
+
|
114
|
+
exports.RUNTIME_CONFIG = RUNTIME_CONFIG;
|
115
|
+
const MANIFEST_FIELDS = {
|
116
|
+
// Required fields in manifest
|
117
|
+
REQUIRED: ['version', 'generated', 'chunks', 'locales'],
|
118
|
+
// Optional metadata fields
|
119
|
+
METADATA: ['description', 'environment', 'buildId', 'commitHash']
|
120
|
+
}; // Default retry strategy
|
121
|
+
|
122
|
+
exports.MANIFEST_FIELDS = MANIFEST_FIELDS;
|
123
|
+
const RETRY_STRATEGY = {
|
124
|
+
// Initial delay (ms)
|
125
|
+
initialDelay: 1000,
|
126
|
+
// Maximum delay (ms)
|
127
|
+
maxDelay: 10000,
|
128
|
+
// Backoff factor
|
129
|
+
factor: 2,
|
130
|
+
// Maximum number of retries
|
131
|
+
maxRetries: 3
|
132
|
+
}; // Chunk optimization hints
|
133
|
+
|
134
|
+
exports.RETRY_STRATEGY = RETRY_STRATEGY;
|
135
|
+
const CHUNK_HINTS = {
|
136
|
+
// Threshold for splitting chunks
|
137
|
+
SPLIT_THRESHOLD: 0.8,
|
138
|
+
// 80% of max size
|
139
|
+
// Threshold for merging chunks
|
140
|
+
MERGE_THRESHOLD: 0.3,
|
141
|
+
// 30% of max size
|
142
|
+
// Preferred chunk size ranges
|
143
|
+
RANGES: {
|
144
|
+
SMALL: 50,
|
145
|
+
MEDIUM: 100,
|
146
|
+
LARGE: 150
|
147
|
+
}
|
148
|
+
}; // Validation schemas (using simple pattern matching)
|
149
|
+
|
150
|
+
exports.CHUNK_HINTS = CHUNK_HINTS;
|
151
|
+
const VALIDATION = {
|
152
|
+
KEY_PATTERN: /^[a-zA-Z0-9_.]+$/,
|
153
|
+
LOCALE_PATTERN: /^[a-z]{2}(_[A-Z]{2})?$/,
|
154
|
+
CHUNK_NAME_PATTERN: /^[a-zA-Z0-9-_]+$/
|
155
|
+
}; // Export all i18n keys for validation (this would be populated from your source)
|
156
|
+
|
157
|
+
exports.VALIDATION = VALIDATION;
|
158
|
+
const ALL_I18N_KEYS = new Set([
|
159
|
+
// Example keys - in real implementation, these would be loaded from your source
|
160
|
+
'common.ok', 'common.cancel', 'errors.notFound' // ... more keys
|
161
|
+
]);
|
162
|
+
exports.ALL_I18N_KEYS = ALL_I18N_KEYS;
|
@@ -0,0 +1,78 @@
|
|
1
|
+
"use strict";
|
2
|
+
|
3
|
+
const esprima = require('esprima');
|
4
|
+
const crypto = require('crypto');
|
5
|
+
class I18nKeyHasher {
|
6
|
+
constructor() {
|
7
|
+
this.keyHashMap = new Map();
|
8
|
+
this.hashKeyMap = new Map();
|
9
|
+
this.usedHashes = new Set();
|
10
|
+
this.hashLength = 5;
|
11
|
+
}
|
12
|
+
generateHash(key) {
|
13
|
+
const fullHash = crypto.createHash('md5').update(key).digest('hex');
|
14
|
+
let hash = fullHash.substring(0, this.hashLength);
|
15
|
+
let counter = 0;
|
16
|
+
let finalHash = hash;
|
17
|
+
while (this.usedHashes.has(finalHash)) {
|
18
|
+
counter++;
|
19
|
+
finalHash = hash + counter;
|
20
|
+
}
|
21
|
+
this.usedHashes.add(finalHash);
|
22
|
+
return finalHash;
|
23
|
+
}
|
24
|
+
hashKey(key) {
|
25
|
+
if (this.keyHashMap.has(key)) {
|
26
|
+
return this.keyHashMap.get(key);
|
27
|
+
}
|
28
|
+
const hash = this.generateHash(key);
|
29
|
+
this.keyHashMap.set(key, hash);
|
30
|
+
this.hashKeyMap.set(hash, key);
|
31
|
+
return hash;
|
32
|
+
}
|
33
|
+
replaceKeysInSource(sourceCode) {
|
34
|
+
try {
|
35
|
+
// Parse source using esprima
|
36
|
+
const ast = esprima.parse(sourceCode, {
|
37
|
+
range: true,
|
38
|
+
tokens: true,
|
39
|
+
comment: true,
|
40
|
+
jsx: true
|
41
|
+
}); // Track string literals to replace
|
42
|
+
|
43
|
+
const replacements = []; // Walk the AST to find string literals
|
44
|
+
|
45
|
+
const traverse = node => {
|
46
|
+
if (node.type === 'Literal' && typeof node.value === 'string' && this.keyHashMap.has(node.value)) {
|
47
|
+
replacements.push({
|
48
|
+
range: node.range,
|
49
|
+
value: this.keyHashMap.get(node.value)
|
50
|
+
});
|
51
|
+
} // Traverse child nodes
|
52
|
+
|
53
|
+
for (const key in node) {
|
54
|
+
if (node[key] && typeof node[key] === 'object') {
|
55
|
+
if (Array.isArray(node[key])) {
|
56
|
+
node[key].forEach(child => child && traverse(child));
|
57
|
+
} else {
|
58
|
+
traverse(node[key]);
|
59
|
+
}
|
60
|
+
}
|
61
|
+
}
|
62
|
+
};
|
63
|
+
traverse(ast); // Apply replacements in reverse order
|
64
|
+
|
65
|
+
replacements.sort((a, b) => b.range[0] - a.range[0]).forEach(({
|
66
|
+
range,
|
67
|
+
value
|
68
|
+
}) => {
|
69
|
+
sourceCode = sourceCode.slice(0, range[0]) + `"${value}"` + sourceCode.slice(range[1]);
|
70
|
+
});
|
71
|
+
return sourceCode;
|
72
|
+
} catch (err) {
|
73
|
+
console.warn('Error during source transformation:', err);
|
74
|
+
return sourceCode; // Return original source if transformation fails
|
75
|
+
}
|
76
|
+
}
|
77
|
+
}
|
78
|
+
module.exports = I18nKeyHasher;
|