@zohodesk/client_build_tool 0.0.11-exp.15 → 0.0.11-exp.16

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zohodesk/client_build_tool",
3
- "version": "0.0.11-exp.15",
3
+ "version": "0.0.11-exp.16",
4
4
  "description": "A CLI tool to build web applications and client libraries",
5
5
  "main": "lib/index.js",
6
6
  "bin": {
@@ -31,8 +31,10 @@
31
31
  "@babel/core": "7.18.5",
32
32
  "@babel/preset-env": "7.18.2",
33
33
  "@babel/preset-react": "7.17.12",
34
+ "@babel/preset-typescript": "7.23.2",
34
35
  "@zohodesk/client_packages_group": "1.0.2",
35
36
  "babel-loader": "9.1.2",
37
+ "babel-plugin-module-resolver": "5.0.2",
36
38
  "babel-plugin-transform-react-remove-prop-types": "0.4.24",
37
39
  "babel-plugin-transform-remove-console": "6.9.4",
38
40
  "copy-webpack-plugin": "11.0.0",
@@ -50,14 +52,13 @@
50
52
  "postcss": "8.4.21",
51
53
  "postcss-loader": "7.0.2",
52
54
  "postcss-rtl": "2.0.0",
55
+ "ts-loader": "8.2.0",
56
+ "typescript": "5.2.2",
53
57
  "uglifycss": "0.0.29",
54
58
  "watcher": "1.2.0",
55
59
  "webpack": "5.79.0",
56
60
  "webpack-bundle-analyzer": "4.8.0",
57
61
  "webpack-cli": "4.10.0",
58
- "webpack-dev-middleware": "6.1.1",
59
- "typescript": "5.2.2",
60
- "ts-loader": "8.2.0",
61
- "@babel/preset-typescript": "7.23.2"
62
+ "webpack-dev-middleware": "6.1.1"
62
63
  }
63
64
  }
@@ -1,49 +0,0 @@
1
- "use strict";
2
-
3
- const HtmlWebpackPlugin = require('html-webpack-plugin');
4
-
5
- const pluginName = 'I18nNumericIndexHtmlInjectorPlugin';
6
-
7
- class I18nNumericIndexHtmlInjectorPlugin {
8
- constructor(options) {
9
- this.options = options;
10
- }
11
-
12
- apply(compiler) {
13
- compiler.hooks.thisCompilation.tap(pluginName, compilation => {
14
- HtmlWebpackPlugin.getHooks(compilation).beforeAssetTagGeneration.tapAsync(pluginName, (hookData, cb) => {
15
- const {
16
- assets
17
- } = hookData;
18
- const {
19
- numericFilenameTemplate,
20
- dynamicFilenameTemplate,
21
- htmlTemplateLabel,
22
- i18nAssetsPublicPathPrefix = ''
23
- } = this.options;
24
- const newI18nAssetUrlsToAdd = [];
25
-
26
- if (numericFilenameTemplate) {
27
- const numericFilename = numericFilenameTemplate.replace(/\[locale\]/g, htmlTemplateLabel);
28
- newI18nAssetUrlsToAdd.push(numericFilename);
29
- }
30
-
31
- if (dynamicFilenameTemplate) {
32
- const dynamicFilename = dynamicFilenameTemplate.replace(/\[locale\]/g, htmlTemplateLabel);
33
- newI18nAssetUrlsToAdd.push(dynamicFilename);
34
- }
35
-
36
- if (newI18nAssetUrlsToAdd.length > 0) {
37
- assets.js = [...assets.js, ...newI18nAssetUrlsToAdd];
38
- }
39
-
40
- cb(null, hookData);
41
- });
42
- });
43
- }
44
-
45
- }
46
-
47
- module.exports = {
48
- I18nNumericIndexHtmlInjectorPlugin
49
- };
@@ -1,186 +0,0 @@
1
- "use strict";
2
-
3
- const path = require('path');
4
-
5
- const {
6
- sources,
7
- Compilation,
8
- util
9
- } = require('webpack');
10
-
11
- const {
12
- decodeUnicodeEscapes
13
- } = require('../../utils/propertiesParser');
14
-
15
- const {
16
- loadNumericMap,
17
- loadI18nData
18
- } = require('./utils/i18nDataLoader');
19
-
20
- const {
21
- RawSource
22
- } = sources;
23
- const pluginName = 'I18nNumericIndexPlugin';
24
-
25
- class I18nNumericIndexPlugin {
26
- constructor(options = {}) {
27
- this.options = { ...options,
28
- singleFile: options.singleFile || false,
29
- singleFileTemplate: options.singleFileTemplate,
30
- includeContentHash: options.includeContentHash || false,
31
- generateManifest: options.generateManifest || false,
32
- manifestPath: options.manifestPath || 'i18n/manifest.json'
33
- };
34
- this.numericMap = null;
35
- this.i18nData = null;
36
- this.manifest = {};
37
- }
38
-
39
- getNumericMap(compilation) {
40
- if (!this.numericMap) {
41
- const mapPath = path.resolve(compilation.compiler.context, this.options.numericMapPath);
42
- this.numericMap = loadNumericMap(mapPath, compilation);
43
- }
44
-
45
- return this.numericMap;
46
- }
47
-
48
- getI18nData(compilation) {
49
- if (!this.i18nData) {
50
- this.i18nData = loadI18nData(this.options, compilation);
51
- }
52
-
53
- return this.i18nData;
54
- }
55
-
56
- generateContentHash(content, compilation) {
57
- const {
58
- hashFunction,
59
- hashDigest,
60
- hashDigestLength
61
- } = compilation.outputOptions;
62
- const hash = util.createHash(hashFunction || 'xxhash64');
63
- hash.update(content);
64
- return hash.digest(hashDigest || 'hex').substring(0, hashDigestLength || 20);
65
- }
66
-
67
- emitChunk(compilation, filename, locale, data, fileType = null) {
68
- const content = decodeUnicodeEscapes(JSON.stringify(data));
69
- const fileContent = `${this.options.jsonpFunc}(${content});`;
70
- let outputPath = filename.replace(/\[locale\]/g, locale);
71
- const hasContentHashPlaceholder = filename.includes('[contenthash]');
72
- const shouldIncludeHash = hasContentHashPlaceholder || this.options.includeContentHash;
73
-
74
- if (shouldIncludeHash) {
75
- const contentHash = this.generateContentHash(fileContent, compilation);
76
-
77
- if (hasContentHashPlaceholder) {
78
- outputPath = outputPath.replace(/\[contenthash\]/g, contentHash);
79
- } else {
80
- outputPath = outputPath.replace(/\.js$/, `.${contentHash}.js`);
81
- }
82
- }
83
-
84
- if (this.options.generateManifest) {
85
- const cleanName = filename.replace(/\[locale\]/g, locale).replace(/\.\[contenthash\]/g, '').replace(/\.js$/, '.js');
86
- const cleanNameWithType = fileType ? cleanName.replace(/\.js$/, `.${fileType}.js`) : cleanName;
87
- const manifestKey = cleanNameWithType.split('/').pop();
88
- this.manifest[manifestKey] = outputPath.split('/').pop();
89
- }
90
-
91
- compilation.emitAsset(outputPath, new RawSource(fileContent));
92
- return outputPath;
93
- }
94
-
95
- apply(compiler) {
96
- compiler.hooks.thisCompilation.tap(pluginName, compilation => {
97
- compilation.hooks.processAssets.tapAsync({
98
- name: pluginName,
99
- stage: Compilation.PROCESS_ASSETS_STAGE_SUMMARIZE
100
- }, (assets, callback) => {
101
- if (!this.options.enable) {
102
- return callback();
103
- }
104
-
105
- const {
106
- sortedKeys,
107
- totalKeys,
108
- originalKeyToNumericId
109
- } = this.getNumericMap(compilation);
110
- const {
111
- jsResourceBase,
112
- allI18n,
113
- locales
114
- } = this.getI18nData(compilation);
115
- if (!locales.length) return callback();
116
- const numericKeysSet = new Set(sortedKeys);
117
- const englishData = allI18n.en_US || jsResourceBase;
118
- const isDevMode = this.options.devMode || process.env.NODE_ENV === 'development';
119
- locales.forEach(locale => {
120
- const localeData = allI18n[locale] || {};
121
- const numericData = {};
122
- const unmappedData = {};
123
- Object.keys(jsResourceBase).forEach(key => {
124
- const translation = localeData[key] ?? englishData[key];
125
-
126
- if (originalKeyToNumericId && originalKeyToNumericId.hasOwnProperty(key)) {
127
- const numericId = originalKeyToNumericId[key];
128
- numericData[numericId] = translation;
129
- } else if (numericKeysSet.has(key)) {
130
- const index = sortedKeys.indexOf(key);
131
-
132
- if (index !== -1) {
133
- numericData[index] = translation;
134
- }
135
- } else {
136
- unmappedData[key] = translation;
137
- }
138
- });
139
-
140
- if (this.options.singleFile) {
141
- const combinedData = { ...numericData,
142
- ...unmappedData
143
- };
144
-
145
- if (Object.keys(combinedData).length > 0) {
146
- const filename = this.options.singleFileTemplate || this.options.numericFilenameTemplate || this.options.dynamicFilenameTemplate;
147
- this.emitChunk(compilation, filename, locale, combinedData);
148
- }
149
- } else {
150
- if (Object.keys(numericData).length > 0) {
151
- this.emitChunk(compilation, this.options.numericFilenameTemplate, locale, numericData, 'numeric');
152
- }
153
-
154
- if (Object.keys(unmappedData).length > 0) {
155
- this.emitChunk(compilation, this.options.dynamicFilenameTemplate, locale, unmappedData, 'dynamic');
156
- }
157
- }
158
- });
159
-
160
- if (this.options.generateManifest && Object.keys(this.manifest).length > 0) {
161
- // Determine manifest path
162
- let manifestPath;
163
-
164
- if (this.options.manifestPath) {
165
- // Use explicitly configured path
166
- manifestPath = this.options.manifestPath;
167
- } else {
168
- // Default to same directory as i18n files with manifest.json name
169
- const template = this.options.singleFileTemplate || this.options.numericFilenameTemplate;
170
- manifestPath = path.dirname(template) + '/manifest.json';
171
- }
172
-
173
- const manifestContent = JSON.stringify(this.manifest, null, 2);
174
- compilation.emitAsset(manifestPath, new RawSource(manifestContent));
175
- }
176
-
177
- callback();
178
- });
179
- });
180
- }
181
-
182
- }
183
-
184
- module.exports = {
185
- I18nNumericIndexPlugin
186
- };
@@ -1,106 +0,0 @@
1
- "use strict";
2
-
3
- const fs = require('fs');
4
-
5
- const path = require('path');
6
-
7
- const {
8
- parseProperties
9
- } = require('../../../utils/propertiesParser');
10
-
11
- function loadPropertiesFile(filePath, compilation, description) {
12
- try {
13
- const content = fs.readFileSync(filePath, 'utf-8');
14
- const parsed = parseProperties(content);
15
- return parsed;
16
- } catch (err) {
17
- if (compilation) {
18
- compilation.errors.push(new Error(`I18nNumericIndexPlugin: Error loading ${description}: ${err.message}`));
19
- }
20
-
21
- return {};
22
- }
23
- }
24
-
25
- function loadNumericMap(numericMapPath, compilation) {
26
- try {
27
- const fileContent = fs.readFileSync(numericMapPath, 'utf-8');
28
- const parsedData = JSON.parse(fileContent);
29
- const sortedKeys = new Array(parsedData.totalKeysInMap);
30
- Object.entries(parsedData.originalKeyToNumericId).forEach(([key, id]) => {
31
- sortedKeys[id] = key;
32
- });
33
- return {
34
- sortedKeys,
35
- totalKeys: parsedData.totalKeysInMap
36
- };
37
- } catch (err) {
38
- if (compilation) {
39
- compilation.errors.push(new Error(`I18nNumericIndexPlugin: Error loading numeric map: ${err.message}`));
40
- }
41
-
42
- return {
43
- sortedKeys: [],
44
- totalKeys: 0
45
- };
46
- }
47
- }
48
-
49
- function loadAllLocaleFiles(propertiesPath, compilation, jsResourceBase) {
50
- const allI18n = {};
51
- const locales = [];
52
- allI18n['en_US'] = jsResourceBase;
53
- locales.push('en_US');
54
-
55
- try {
56
- const files = fs.readdirSync(propertiesPath);
57
- files.forEach(file => {
58
- if (!file.endsWith('.properties')) return;
59
- const match = file.match(/^ApplicationResources_([a-z]{2}_[A-Z]{2})\.properties$/);
60
-
61
- if (match) {
62
- const locale = match[1];
63
- const filePath = path.join(propertiesPath, file);
64
- const localeData = loadPropertiesFile(filePath, compilation, `locale ${locale}`);
65
- allI18n[locale] = { ...jsResourceBase,
66
- ...localeData
67
- };
68
-
69
- if (!locales.includes(locale)) {
70
- locales.push(locale);
71
- }
72
- }
73
- });
74
- } catch (err) {
75
- if (compilation) {
76
- compilation.errors.push(new Error(`I18nNumericIndexPlugin: Error reading properties folder: ${err.message}`));
77
- }
78
- }
79
-
80
- return {
81
- allI18n,
82
- locales
83
- };
84
- }
85
-
86
- function loadI18nData(options, compilation) {
87
- const jsResourcePath = path.resolve(compilation.compiler.context, options.jsResourcePath);
88
- const propertiesPath = path.resolve(compilation.compiler.context, options.propertiesFolderPath);
89
- const jsResourceBase = loadPropertiesFile(jsResourcePath, compilation, 'JS resources');
90
- const {
91
- allI18n,
92
- locales
93
- } = loadAllLocaleFiles(propertiesPath, compilation, jsResourceBase);
94
- return {
95
- jsResourceBase,
96
- allI18n,
97
- locales
98
- };
99
- }
100
-
101
- module.exports = {
102
- loadPropertiesFile,
103
- loadNumericMap,
104
- loadAllLocaleFiles,
105
- loadI18nData
106
- };
@@ -1,96 +0,0 @@
1
- "use strict";
2
-
3
- const {
4
- walk
5
- } = require('estree-walker');
6
-
7
- const PREFIX_I18N_COMMENT = 'I18N';
8
- const PREFIX_I18N_COMMENT_DYNAMIC = 'dynamic-i18n-key';
9
-
10
- function getI18nKeysFromSingleComment(commentNode, validKeysSet) {
11
- const foundKeysInComment = [];
12
-
13
- if (!commentNode || typeof commentNode.value !== 'string') {
14
- return foundKeysInComment;
15
- }
16
-
17
- const commentString = commentNode.value.trim();
18
- let i18nKeyStr;
19
-
20
- if (commentString.startsWith(PREFIX_I18N_COMMENT)) {
21
- i18nKeyStr = commentString.slice(PREFIX_I18N_COMMENT.length).trim();
22
- } else if (commentString.startsWith(PREFIX_I18N_COMMENT_DYNAMIC)) {
23
- i18nKeyStr = commentString.slice(PREFIX_I18N_COMMENT_DYNAMIC.length).trim();
24
- }
25
-
26
- if (!i18nKeyStr) {
27
- return foundKeysInComment;
28
- }
29
-
30
- const potentialKeys = i18nKeyStr.split(',').map(key => key.trim()).filter(key => key);
31
- potentialKeys.forEach(key => {
32
- if (validKeysSet.has(key)) {
33
- foundKeysInComment.push(key);
34
- }
35
- });
36
- return foundKeysInComment;
37
- }
38
- /**
39
- * Traverses an AST and its comments to collect and categorize i18n keys.
40
- *
41
- * @param {object} astProgramNode - The Program node of the AST.
42
- * @param {object[]} commentsArray - An array of comment nodes from the AST.
43
- * @param {object} allI18nKeysMasterMap - Object map of all valid i18n keys (from JSResources).
44
- * @param {boolean} [isDebug=false] - Flag for verbose logging.
45
- * @returns {{literalKeys: Set<string>, commentKeys: Set<string>}}
46
- * literalKeys: Set of valid i18n keys found as string literals.
47
- * commentKeys: Set of valid i18n keys found in comments.
48
- */
49
-
50
-
51
- function collectAndCategorizeUsedI18nKeys(astProgramNode, commentsArray, allI18nKeysMasterMap, isDebug = false) {
52
- const foundLiteralKeys = new Set();
53
- const foundCommentKeys = new Set();
54
- const validKeysSet = new Set(Object.keys(allI18nKeysMasterMap || {}));
55
-
56
- if (validKeysSet.size === 0 && isDebug) {
57
- console.warn('[collectAndCategorizeUsedI18nKeys] allI18nKeysMasterMap is empty. No keys can be collected.');
58
- } // 1. Collect keys from AST string literals
59
-
60
-
61
- if (astProgramNode) {
62
- try {
63
- walk(astProgramNode, {
64
- enter(node) {
65
- if ((node.type === 'Literal' || node.type === 'StringLiteral') && typeof node.value === 'string') {
66
- if (validKeysSet.has(node.value)) {
67
- foundLiteralKeys.add(node.value);
68
- }
69
- }
70
- }
71
-
72
- });
73
- } catch (error) {
74
- console.error('[collectAndCategorizeUsedI18nKeys] Error during AST walk:', error);
75
- }
76
- } // 2. Collect keys from comments
77
-
78
-
79
- if (commentsArray && Array.isArray(commentsArray)) {
80
- commentsArray.forEach(commentNode => {
81
- const keysFromComment = getI18nKeysFromSingleComment(commentNode, validKeysSet);
82
- keysFromComment.forEach(key => {
83
- foundCommentKeys.add(key);
84
- });
85
- });
86
- }
87
-
88
- return {
89
- literalKeys: foundLiteralKeys,
90
- commentKeys: foundCommentKeys
91
- };
92
- }
93
-
94
- module.exports = {
95
- collectAndCategorizeUsedI18nKeys: collectAndCategorizeUsedI18nKeys
96
- };
@@ -1,71 +0,0 @@
1
- "use strict";
2
-
3
- const {
4
- getPropertiesAsJSON
5
- } = require('../custom_plugins/I18nSplitPlugin/utils/propertiesUtils');
6
-
7
- function loadJSResourcesOnce(options) {
8
- let jsResourcePath;
9
-
10
- if (options.i18nIndexing && options.i18nIndexing.enable) {
11
- jsResourcePath = options.i18nIndexing.jsResourcePath;
12
- } else if (options.i18nChunkSplit && options.i18nChunkSplit.chunkSplitEnable && options.i18nChunkSplit.useNumericIndexing) {
13
- jsResourcePath = options.i18nChunkSplit.jsResource;
14
- } else {
15
- throw new Error('i18nIdReplaceLoader requires either i18nIndexing to be enabled or i18nChunkSplit with useNumericIndexing');
16
- }
17
-
18
- if (!jsResourcePath) {
19
- throw new Error('Missing required jsResourcePath in i18n options');
20
- }
21
-
22
- try {
23
- const i18nData = getPropertiesAsJSON(jsResourcePath);
24
-
25
- if (Object.keys(i18nData).length === 0) {
26
- console.warn(`[i18nIdReplaceLoaderConfig] Warning: No i18n data found in JSResource file: ${jsResourcePath}`);
27
- return {};
28
- }
29
-
30
- return i18nData;
31
- } catch (err) {
32
- throw new Error(`Error reading JSResource file ${jsResourcePath}: ${err.message}`);
33
- }
34
- }
35
-
36
- function i18nIdReplaceLoaderConfig(options, webpackContext) {
37
- let numericMapPath;
38
-
39
- if (options.i18nIndexing && options.i18nIndexing.enable) {
40
- numericMapPath = options.i18nIndexing.numericMapPath;
41
- } else if (options.i18nChunkSplit && options.i18nChunkSplit.chunkSplitEnable && options.i18nChunkSplit.useNumericIndexing) {
42
- numericMapPath = options.i18nChunkSplit.numericMapPath;
43
- } else {
44
- throw new Error('i18nIdReplaceLoader requires either i18nIndexing to be enabled or i18nChunkSplit with useNumericIndexing');
45
- }
46
-
47
- if (!numericMapPath) {
48
- throw new Error('numericMapPath is required in i18nIndexing or i18nChunkSplit config');
49
- }
50
-
51
- const allI18nData = loadJSResourcesOnce(options);
52
-
53
- const i18nKeyReplaceLoaderPath = require.resolve('../loaders/i18nIdReplaceLoader.js');
54
-
55
- const loaderOptions = {
56
- allI18nData: allI18nData,
57
- sourceMaps: false,
58
- numericMapPath: numericMapPath,
59
- devMode: options.i18nIndexing?.devMode || false,
60
- includePaths: options.i18nIndexing?.loaderOptions?.includePaths || [],
61
- excludePaths: options.i18nIndexing?.loaderOptions?.excludePaths || ['node_modules', 'tests']
62
- };
63
- return {
64
- loader: i18nKeyReplaceLoaderPath,
65
- options: loaderOptions
66
- };
67
- }
68
-
69
- module.exports = {
70
- i18nIdReplaceLoaderConfig
71
- };
@@ -1,106 +0,0 @@
1
- "use strict";
2
-
3
- const fs = require('fs');
4
-
5
- const path = require('path');
6
-
7
- const parser = require('@babel/parser');
8
-
9
- const traverse = require('@babel/traverse').default;
10
-
11
- const generator = require('@babel/generator').default;
12
-
13
- const t = require('@babel/types');
14
-
15
- const {
16
- getOptions
17
- } = require('loader-utils');
18
-
19
- module.exports = function i18nIdReplaceLoader(source, map) {
20
- const resourcePath = this.resourcePath;
21
- this.cacheable && this.cacheable();
22
- const options = getOptions(this) || {};
23
- const callback = this.async();
24
-
25
- if (options.excludePaths) {
26
- const shouldExclude = options.excludePaths.some(excludePath => resourcePath.includes(excludePath));
27
-
28
- if (shouldExclude) {
29
- return callback(null, source, map);
30
- }
31
- }
32
-
33
- if (options.includePaths && options.includePaths.length > 0) {
34
- const shouldInclude = options.includePaths.some(includePath => resourcePath.includes(includePath));
35
-
36
- if (!shouldInclude) {
37
- return callback(null, source, map);
38
- }
39
- }
40
-
41
- if (!options.allI18nData || Object.keys(options.allI18nData).length === 0) {
42
- return callback(new Error(`i18nIdReplaceLoader: 'allI18nData' option is missing or empty`));
43
- }
44
-
45
- let numericIdMap = null;
46
-
47
- if (options.numericMapPath) {
48
- try {
49
- if (fs.existsSync(options.numericMapPath)) {
50
- const fileContent = fs.readFileSync(options.numericMapPath, 'utf-8');
51
- const parsedData = JSON.parse(fileContent);
52
-
53
- if (parsedData && parsedData.originalKeyToNumericId) {
54
- numericIdMap = parsedData.originalKeyToNumericId;
55
- }
56
- }
57
- } catch (err) {}
58
- }
59
-
60
- if (!numericIdMap) {
61
- return callback(null, source, map);
62
- }
63
-
64
- const isDevMode = options.devMode || process.env.NODE_ENV === 'development';
65
-
66
- try {
67
- const ast = parser.parse(source, {
68
- sourceType: 'module',
69
- plugins: ['jsx', 'typescript', 'classProperties', 'optionalChaining', 'nullishCoalescingOperator'],
70
- sourceFilename: resourcePath
71
- });
72
- let hasTransformations = false;
73
- traverse(ast, {
74
- StringLiteral(path) {
75
- const {
76
- node
77
- } = path;
78
-
79
- if (!options.allI18nData.hasOwnProperty(node.value)) {
80
- return;
81
- }
82
-
83
- if (numericIdMap.hasOwnProperty(node.value)) {
84
- const numericId = String(numericIdMap[node.value]);
85
- path.replaceWith(t.stringLiteral(numericId));
86
- hasTransformations = true;
87
- }
88
- }
89
-
90
- });
91
-
92
- if (hasTransformations) {
93
- const output = generator(ast, {
94
- sourceMaps: !!options.sourceMaps,
95
- sourceFileName: resourcePath,
96
- retainLines: false,
97
- comments: true
98
- }, source);
99
- callback(null, output.code, output.map);
100
- } else {
101
- callback(null, source, map);
102
- }
103
- } catch (err) {
104
- callback(err);
105
- }
106
- };