@zohodesk/client_build_tool 0.0.1-0.exp.0.0.3 → 0.0.1-0.exp.0.0.8

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.
@@ -7,7 +7,7 @@ exports.configI18nNumericIndexPlugin = configI18nNumericIndexPlugin;
7
7
 
8
8
  var {
9
9
  I18nNumericIndexPlugin
10
- } = require("@zohodesk/client_build_tool/lib/shared/bundler/webpack/custom_plugins/I18nNumericIndexPlugin/I18nNumericIndexPlugin");
10
+ } = require("../custom_plugins/I18nNumericIndexPlugin/I18nNumericIndexPlugin");
11
11
 
12
12
  var {
13
13
  I18nNumericIndexHtmlInjectorPlugin
@@ -31,6 +31,18 @@ function urlJoin(...args) {
31
31
  return args.map(part => typeof part === 'string' ? part.replace(/(^\/+|\/+$)/g, '') : '').filter(part => part !== '').join('/');
32
32
  }
33
33
 
34
+ function validateAndGetFilenameTemplate(template, chunkType) {
35
+ if (!template || typeof template !== 'string') {
36
+ throw new Error(`Missing required ${chunkType} filename template in i18nIndexing options`);
37
+ }
38
+
39
+ if (!template.includes('[locale]')) {
40
+ throw new Error(`${chunkType} filename template must include '[locale]' placeholder: ${template}`);
41
+ }
42
+
43
+ return template;
44
+ }
45
+
34
46
  function configI18nNumericIndexPlugin(options) {
35
47
  if (!(options.i18nIndexing && options.i18nIndexing.enable)) {
36
48
  return null;
@@ -38,43 +50,52 @@ function configI18nNumericIndexPlugin(options) {
38
50
 
39
51
  const i18nOpts = options.i18nIndexing;
40
52
  const cdnConfig = options.cdnMapping || {};
53
+
54
+ if (!i18nOpts.jsResourcePath) {
55
+ throw new Error('Missing required jsResourcePath in i18nIndexing options');
56
+ }
57
+
58
+ if (!i18nOpts.propertiesFolderPath) {
59
+ throw new Error('Missing required propertiesFolderPath in i18nIndexing options');
60
+ }
61
+
62
+ if (!i18nOpts.numericMapPath) {
63
+ throw new Error('Missing required numericMapPath in i18nIndexing options');
64
+ }
65
+
66
+ if (!i18nOpts.jsonpFunc) {
67
+ throw new Error('Missing required jsonpFunc in i18nIndexing options');
68
+ }
69
+
70
+ if (!i18nOpts.htmlTemplateLabel) {
71
+ throw new Error('Missing required htmlTemplateLabel in i18nIndexing options');
72
+ }
73
+
74
+ if (!i18nOpts.localeVarName) {
75
+ throw new Error('Missing required localeVarName in i18nIndexing options');
76
+ }
77
+
78
+ console.log('I18n Indexing Options:', {
79
+ enable: i18nOpts.enable,
80
+ jsResourcePath: i18nOpts.jsResourcePath,
81
+ propertiesFolderPath: i18nOpts.propertiesFolderPath,
82
+ numericMapPath: i18nOpts.numericMapPath,
83
+ numericFilenameTemplate: i18nOpts.numericFilenameTemplate,
84
+ dynamicFilenameTemplate: i18nOpts.dynamicFilenameTemplate,
85
+ jsonpFunc: i18nOpts.jsonpFunc,
86
+ htmlTemplateLabel: i18nOpts.htmlTemplateLabel,
87
+ localeVarName: i18nOpts.localeVarName
88
+ });
41
89
  const {
42
90
  locales,
43
91
  allI18nObject
44
92
  } = readI18nValues({
45
93
  jsResource: i18nOpts.jsResourcePath,
46
94
  propertiesFolder: i18nOpts.propertiesFolderPath,
47
- disableDefault: i18nOpts.disableDefaultMerge !== undefined ? i18nOpts.disableDefaultMerge : false
95
+ disableDefault: false
48
96
  });
49
- const hardcodedDefaultNumericTemplate = 'i18n-chunks/[locale]/numeric.i18n.js';
50
- const hardcodedDefaultDynamicTemplate = 'i18n-chunks/[locale]/dynamic.i18n.js';
51
- let numericFilenameTemplate = i18nOpts.numericFilenameTemplate || hardcodedDefaultNumericTemplate;
52
- let dynamicFilenameTemplate = i18nOpts.dynamicFilenameTemplate || hardcodedDefaultDynamicTemplate;
53
-
54
- if (i18nOpts.numericFilenameTemplate === undefined) {
55
- // Check if explicitly undefined or missing
56
- const i18nSplitFilename = options.i18nChunkSplit && options.i18nChunkSplit.filename;
57
-
58
- if (i18nSplitFilename && typeof i18nSplitFilename === 'string') {
59
- // This adaptation logic might need to be more robust
60
- numericFilenameTemplate = `i18n-chunks/[locale]/${path.basename(i18nSplitFilename).replace(/(\.i18n)?\.js$/, '.numeric.i18n.js')}`;
61
- } else {
62
- numericFilenameTemplate = hardcodedDefaultNumericTemplate;
63
- }
64
- }
65
-
66
- if (i18nOpts.dynamicFilenameTemplate === undefined) {
67
- const i18nSplitFilename = options.i18nChunkSplit && options.i18nChunkSplit.filename;
68
-
69
- if (i18nSplitFilename && typeof i18nSplitFilename === 'string') {
70
- dynamicFilenameTemplate = `i18n-chunks/[locale]/${path.basename(i18nSplitFilename).replace(/(\.i18n)?\.js$/, '.dynamic.i18n.js')}`;
71
- } else {
72
- dynamicFilenameTemplate = hardcodedDefaultDynamicTemplate;
73
- }
74
- }
75
-
76
- const htmlTemplateLabel = i18nOpts.htmlTemplateLabel || '{{--user-locale}}';
77
- const defaultJsonpFunc = options.i18nChunkSplit && options.i18nChunkSplit.jsonpFunc || 'window.loadI18nChunk';
97
+ const numericFilenameTemplate = validateAndGetFilenameTemplate(i18nOpts.numericFilenameTemplate, 'numericFilenameTemplate');
98
+ const dynamicFilenameTemplate = validateAndGetFilenameTemplate(i18nOpts.dynamicFilenameTemplate, 'dynamicFilenameTemplate');
78
99
  let i18nAssetsPublicPathPrefix = '';
79
100
 
80
101
  if (cdnConfig.isCdnEnabled) {
@@ -90,24 +111,32 @@ function configI18nNumericIndexPlugin(options) {
90
111
  i18nAssetsPublicPathPrefix = urlConcat(options.publicPath === undefined ? '' : options.publicPath);
91
112
  }
92
113
 
93
- const pluginBaseOptions = {
114
+ const numericIndexPluginOptions = {
115
+ enable: i18nOpts.enable,
116
+ jsResourcePath: i18nOpts.jsResourcePath,
117
+ propertiesFolderPath: i18nOpts.propertiesFolderPath,
118
+ numericMapPath: i18nOpts.numericMapPath,
94
119
  locales,
95
120
  allI18nObject,
96
- numericMapPath: i18nOpts.numericMapPath,
97
- numericJsonpFunc: i18nOpts.numericJsonpFunc || defaultJsonpFunc,
98
- dynamicJsonpFunc: i18nOpts.dynamicJsonpFunc || defaultJsonpFunc,
99
- numericFilenameTemplate,
100
- // This will now include "i18n-chunks/[locale]/"
101
- dynamicFilenameTemplate,
102
- // This will now include "i18n-chunks/[locale]/"
103
- moduleType: 'i18n/mini-extract',
104
- mainChunkName: options.i18nChunkSplit && options.i18nChunkSplit.mainChunkName || 'main',
105
- htmlTemplateLabel,
106
- localeVarName: i18nOpts.localeVarName
121
+ numericFilenameTemplate: numericFilenameTemplate,
122
+ dynamicFilenameTemplate: dynamicFilenameTemplate,
123
+ numericJsonpFunction: i18nOpts.jsonpFunc,
124
+ dynamicJsonpFunction: i18nOpts.jsonpFunc,
125
+ moduleType: 'i18n/mini-extract'
107
126
  };
108
- const htmlInjectorOptions = { ...pluginBaseOptions,
127
+ const htmlInjectorOptions = {
128
+ locales,
129
+ numericFilenameTemplate: numericFilenameTemplate,
130
+ numericJsonpFunc: i18nOpts.jsonpFunc,
131
+ dynamicFilenameTemplate: dynamicFilenameTemplate,
132
+ dynamicJsonpFunc: i18nOpts.jsonpFunc,
133
+ mainChunkName: options.i18nChunkSplit && options.i18nChunkSplit.mainChunkName || 'main',
134
+ htmlTemplateLabel: i18nOpts.htmlTemplateLabel,
135
+ localeVarName: i18nOpts.localeVarName,
109
136
  i18nAssetsPublicPathPrefix: i18nAssetsPublicPathPrefix,
110
137
  cspNoncePlaceholder: i18nOpts.cspNoncePlaceholder || '{{--CSP-nonce}}'
111
138
  };
112
- return [new I18nNumericIndexPlugin(pluginBaseOptions), new I18nNumericIndexHtmlInjectorPlugin(htmlInjectorOptions)];
139
+ const i18nNumericPluginInstance = new I18nNumericIndexPlugin(numericIndexPluginOptions);
140
+ const htmlInjectorPluginInstance = new I18nNumericIndexHtmlInjectorPlugin(htmlInjectorOptions);
141
+ return [i18nNumericPluginInstance, htmlInjectorPluginInstance];
113
142
  }
@@ -36,6 +36,9 @@ function configI18nSplitPlugin(options) {
36
36
  publicPath: i18nPublicPath,
37
37
  i18nManifestFileName: (0, _nameTemplates.nameTemplates)('i18nmanifest', options),
38
38
  // template: (object, locale) => `window.loadI18n(${JSON.stringify(object)}, ${JSON.stringify(locale)})`,
39
- propertiesFolder: i18nChunkSplit.propertiesFolder
39
+ propertiesFolder: i18nChunkSplit.propertiesFolder,
40
+ // NEW OPTIONS FOR NUMERIC INDEXING
41
+ useNumericIndexing: i18nChunkSplit.useNumericIndexing,
42
+ numericMapPath: i18nChunkSplit.numericMapPath
40
43
  });
41
44
  }
@@ -0,0 +1,103 @@
1
+ "use strict";
2
+ /**
3
+ * Shared properties file parsing utility
4
+ * Handles consistent parsing across all i18n tools
5
+ */
6
+ // Decode Unicode escape sequences (for values only)
7
+
8
+ function decodeUnicodeEscapes(str) {
9
+ if (typeof str !== 'string') {
10
+ return str;
11
+ }
12
+
13
+ return str.replace(/\\u([0-9a-fA-F]{4})/g, (match, hex) => {
14
+ return String.fromCharCode(parseInt(hex, 16));
15
+ });
16
+ }
17
+ /**
18
+ * Parse properties file content into key-value pairs
19
+ * @param {string} content - Properties file content
20
+ * @returns {Object} Parsed key-value pairs
21
+ */
22
+
23
+
24
+ function parseProperties(content) {
25
+ const lines = content.split(/\r?\n/);
26
+ const data = {};
27
+ lines.forEach(line => {
28
+ const trimmedLine = line.trim();
29
+
30
+ if (trimmedLine.startsWith('#') || trimmedLine.startsWith('!') || trimmedLine === '') {
31
+ return;
32
+ } // Find unescaped separator (= or :)
33
+
34
+
35
+ let separatorIndex = -1;
36
+
37
+ for (let i = 0; i < trimmedLine.length; i++) {
38
+ if ((trimmedLine[i] === '=' || trimmedLine[i] === ':') && (i === 0 || trimmedLine[i - 1] !== '\\')) {
39
+ separatorIndex = i;
40
+ break;
41
+ }
42
+ }
43
+
44
+ if (separatorIndex > 0) {
45
+ let key = trimmedLine.substring(0, separatorIndex).trim();
46
+ let value = trimmedLine.substring(separatorIndex + 1).trim();
47
+
48
+ if (key) {
49
+ // Handle escaped spaces in keys only
50
+ key = key.replace(/\\ /g, ' '); // Decode Unicode escape sequences ONLY in values, not keys
51
+
52
+ value = decodeUnicodeEscapes(value);
53
+ data[key] = value;
54
+ }
55
+ }
56
+ });
57
+ return data;
58
+ }
59
+ /**
60
+ * Parse properties file content into a Set of keys only
61
+ * @param {string} content - Properties file content
62
+ * @returns {Set<string>} Set of keys
63
+ */
64
+
65
+
66
+ function parsePropertiesToKeySet(content) {
67
+ const lines = content.split(/\r?\n/);
68
+ const keys = new Set();
69
+ lines.forEach(line => {
70
+ const trimmedLine = line.trim();
71
+
72
+ if (trimmedLine.startsWith('#') || trimmedLine.startsWith('!') || trimmedLine === '') {
73
+ return;
74
+ } // Find unescaped separator (= or :)
75
+
76
+
77
+ let separatorIndex = -1;
78
+
79
+ for (let i = 0; i < trimmedLine.length; i++) {
80
+ if ((trimmedLine[i] === '=' || trimmedLine[i] === ':') && (i === 0 || trimmedLine[i - 1] !== '\\')) {
81
+ separatorIndex = i;
82
+ break;
83
+ }
84
+ }
85
+
86
+ if (separatorIndex > 0) {
87
+ let key = trimmedLine.substring(0, separatorIndex).trim();
88
+
89
+ if (key) {
90
+ // Handle escaped spaces in keys only
91
+ key = key.replace(/\\ /g, ' ');
92
+ keys.add(key);
93
+ }
94
+ }
95
+ });
96
+ return keys;
97
+ }
98
+
99
+ module.exports = {
100
+ parseProperties,
101
+ parsePropertiesToKeySet,
102
+ decodeUnicodeEscapes
103
+ };