@zeesoft/i18n-verify 3.2.0 → 3.2.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/dist/{executor.cjs → executor.mjs} +3873 -43
- package/dist/genrc.mjs +19 -9
- package/dist/index.mjs +40 -27
- package/package.json +8 -6
- package/postinstall.js +21 -0
- package/dist/genrc.cjs +0 -1
- package/dist/index.cjs +0 -1
|
@@ -1,4 +1,142 @@
|
|
|
1
|
-
|
|
1
|
+
import fs, { existsSync, statSync, readFileSync, mkdirSync, writeFileSync, readdirSync, appendFileSync, copyFileSync } from "fs";
|
|
2
|
+
import path, { join, dirname, extname } from "path";
|
|
3
|
+
import { Table } from "console-table-printer";
|
|
4
|
+
import CDP from "chrome-remote-interface";
|
|
5
|
+
import Globalize from "globalize";
|
|
6
|
+
import CldrData from "cldr-data";
|
|
7
|
+
import { en, uk, nl, ru, zh, ja, pt, fr, es, de } from "chrono-node";
|
|
8
|
+
import { DateTime } from "luxon";
|
|
9
|
+
import { detectTextLangEx } from "@isdk/detect-text-language";
|
|
10
|
+
import Jimp from "jimp";
|
|
11
|
+
const SYSTEM_TYPES = {
|
|
12
|
+
NIGHT_WATCH: "nightwatch",
|
|
13
|
+
WEB_DRIVER_IO: "webio",
|
|
14
|
+
CYPRESS: "cypress",
|
|
15
|
+
SELENIUMJS: "seleniumJS"
|
|
16
|
+
};
|
|
17
|
+
const COLOR = {
|
|
18
|
+
GRB_GREEN: "rgb(0, 154, 61)",
|
|
19
|
+
GRB_RED: "rgb(255, 0, 0)",
|
|
20
|
+
GRB_YELLOW: "rgb(255, 255, 0)",
|
|
21
|
+
GRB_BLUE: "rgb(0, 0, 255)",
|
|
22
|
+
ANSI_GREEN: "\x1B[32m",
|
|
23
|
+
ANSI_RED: "\x1B[31m",
|
|
24
|
+
ANSI_YELLOW: "\x1B[33m"
|
|
25
|
+
};
|
|
26
|
+
const I18N_STATUS = {
|
|
27
|
+
STRING_LOCALIZED: "STRING_LOCALIZED",
|
|
28
|
+
STRING_PARTIALLY_LOCALIZED: "STRING_PARTIALLY_LOCALIZED",
|
|
29
|
+
NUMBER_LOCALIZED: "NUMBER_LOCALIZED",
|
|
30
|
+
CURRENCY_LOCALIZED: "CURRENCY_LOCALIZED",
|
|
31
|
+
PERCENTAGE_LOCALIZED: "PERCENTAGE_LOCALIZED",
|
|
32
|
+
DATE_LOCALIZED: "DATE_LOCALIZED",
|
|
33
|
+
TIME_LOCALIZED: "TIME_LOCALIZED",
|
|
34
|
+
DATE_TIME_LOCALIZED: "DATE_TIME_LOCALIZED",
|
|
35
|
+
STRING_NOT_LOCALIZED: "STRING_NOT_LOCALIZED",
|
|
36
|
+
NUMBER_NOT_LOCALIZED: "NUMBER_NOT_LOCALIZED",
|
|
37
|
+
CURRENCY_NOT_LOCALIZED: "CURRENCY_NOT_LOCALIZED",
|
|
38
|
+
PERCENTAGE_NOT_LOCALIZED: "PERCENTAGE_NOT_LOCALIZED",
|
|
39
|
+
DATE_NOT_LOCALIZED: "DATE_NOT_LOCALIZED",
|
|
40
|
+
TIME_NOT_LOCALIZED: "TIME_NOT_LOCALIZED",
|
|
41
|
+
DATE_TIME_NOT_LOCALIZED: "DATE_TIME_NOT_LOCALIZED",
|
|
42
|
+
TRUNCATION_ISSUE: "TRUNCATION_ISSUE",
|
|
43
|
+
OVERLAPPING_ISSUE: "OVERLAPPING_ISSUE",
|
|
44
|
+
ENCODING_ISSUE: "ENCODING_ISSUE",
|
|
45
|
+
DNT: "DNT",
|
|
46
|
+
IGNORE: "IGNORE",
|
|
47
|
+
UNTRANSLATED: "UNTRANSLATED",
|
|
48
|
+
AUTO_IGNORE: "AUTO_IGNORE",
|
|
49
|
+
USER_INPUT: "USER_INPUT",
|
|
50
|
+
REVIEWED: "REVIEWED"
|
|
51
|
+
};
|
|
52
|
+
const REPORT_COUNTS = {
|
|
53
|
+
[I18N_STATUS.STRING_LOCALIZED]: 0,
|
|
54
|
+
[I18N_STATUS.STRING_NOT_LOCALIZED]: 0,
|
|
55
|
+
[I18N_STATUS.STRING_PARTIALLY_LOCALIZED]: 0,
|
|
56
|
+
[I18N_STATUS.NUMBER_LOCALIZED]: 0,
|
|
57
|
+
[I18N_STATUS.NUMBER_NOT_LOCALIZED]: 0,
|
|
58
|
+
[I18N_STATUS.DATE_LOCALIZED]: 0,
|
|
59
|
+
[I18N_STATUS.DATE_NOT_LOCALIZED]: 0,
|
|
60
|
+
[I18N_STATUS.DATE_TIME_LOCALIZED]: 0,
|
|
61
|
+
[I18N_STATUS.DATE_TIME_NOT_LOCALIZED]: 0,
|
|
62
|
+
[I18N_STATUS.TIME_LOCALIZED]: 0,
|
|
63
|
+
[I18N_STATUS.TIME_NOT_LOCALIZED]: 0,
|
|
64
|
+
[I18N_STATUS.CURRENCY_LOCALIZED]: 0,
|
|
65
|
+
[I18N_STATUS.CURRENCY_NOT_LOCALIZED]: 0,
|
|
66
|
+
[I18N_STATUS.PERCENTAGE_LOCALIZED]: 0,
|
|
67
|
+
[I18N_STATUS.PERCENTAGE_NOT_LOCALIZED]: 0,
|
|
68
|
+
[I18N_STATUS.TRUNCATION_ISSUE]: 0,
|
|
69
|
+
[I18N_STATUS.OVERLAPPING_ISSUE]: 0,
|
|
70
|
+
[I18N_STATUS.ENCODING_ISSUE]: 0,
|
|
71
|
+
[I18N_STATUS.DNT]: 0,
|
|
72
|
+
[I18N_STATUS.IGNORE]: 0,
|
|
73
|
+
[I18N_STATUS.UNTRANSLATED]: 0,
|
|
74
|
+
[I18N_STATUS.AUTO_IGNORE]: 0,
|
|
75
|
+
[I18N_STATUS.USER_INPUT]: 0,
|
|
76
|
+
[I18N_STATUS.REVIEWED]: 0
|
|
77
|
+
};
|
|
78
|
+
const STATUS_COLOR = {
|
|
79
|
+
[I18N_STATUS.STRING_LOCALIZED]: [COLOR.GRB_GREEN, COLOR.ANSI_GREEN],
|
|
80
|
+
[I18N_STATUS.STRING_PARTIALLY_LOCALIZED]: [
|
|
81
|
+
COLOR.GRB_YELLOW,
|
|
82
|
+
COLOR.ANSI_YELLOW
|
|
83
|
+
],
|
|
84
|
+
[I18N_STATUS.NUMBER_LOCALIZED]: [COLOR.GRB_GREEN, COLOR.ANSI_GREEN],
|
|
85
|
+
[I18N_STATUS.DATE_LOCALIZED]: [COLOR.GRB_GREEN, COLOR.ANSI_GREEN],
|
|
86
|
+
[I18N_STATUS.TIME_LOCALIZED]: [COLOR.GRB_GREEN, COLOR.ANSI_GREEN],
|
|
87
|
+
[I18N_STATUS.DATE_TIME_LOCALIZED]: [COLOR.GRB_GREEN, COLOR.ANSI_GREEN],
|
|
88
|
+
[I18N_STATUS.CURRENCY_LOCALIZED]: [COLOR.GRB_GREEN, COLOR.ANSI_GREEN],
|
|
89
|
+
[I18N_STATUS.PERCENTAGE_LOCALIZED]: [COLOR.GRB_GREEN, COLOR.ANSI_GREEN],
|
|
90
|
+
[I18N_STATUS.STRING_NOT_LOCALIZED]: [COLOR.GRB_RED, COLOR.ANSI_RED],
|
|
91
|
+
[I18N_STATUS.DATE_NOT_LOCALIZED]: [COLOR.GRB_RED, COLOR.ANSI_RED],
|
|
92
|
+
[I18N_STATUS.DATE_TIME_NOT_LOCALIZED]: [COLOR.GRB_RED, COLOR.ANSI_RED],
|
|
93
|
+
[I18N_STATUS.TIME_NOT_LOCALIZED]: [COLOR.GRB_RED, COLOR.ANSI_RED],
|
|
94
|
+
[I18N_STATUS.NUMBER_NOT_LOCALIZED]: [COLOR.GRB_RED, COLOR.ANSI_RED],
|
|
95
|
+
[I18N_STATUS.CURRENCY_NOT_LOCALIZED]: [COLOR.GRB_RED, COLOR.ANSI_RED],
|
|
96
|
+
[I18N_STATUS.PERCENTAGE_NOT_LOCALIZED]: [COLOR.GRB_RED, COLOR.ANSI_RED],
|
|
97
|
+
[I18N_STATUS.TRUNCATION_ISSUE]: [COLOR.GRB_RED, COLOR.ANSI_RED],
|
|
98
|
+
[I18N_STATUS.OVERLAPPING_ISSUE]: [COLOR.GRB_RED, COLOR.ANSI_RED],
|
|
99
|
+
[I18N_STATUS.ENCODING_ISSUE]: [COLOR.GRB_RED, COLOR.ANSI_RED],
|
|
100
|
+
[I18N_STATUS.DNT]: [COLOR.GRB_GREEN, COLOR.ANSI_GREEN],
|
|
101
|
+
[I18N_STATUS.IGNORE]: [COLOR.GRB_GREEN, COLOR.ANSI_GREEN],
|
|
102
|
+
[I18N_STATUS.UNTRANSLATED]: [COLOR.GRB_GREEN, COLOR.ANSI_GREEN],
|
|
103
|
+
[I18N_STATUS.AUTO_IGNORE]: [COLOR.GRB_GREEN, COLOR.ANSI_GREEN],
|
|
104
|
+
[I18N_STATUS.USER_INPUT]: [COLOR.GRB_GREEN, COLOR.ANSI_GREEN],
|
|
105
|
+
[I18N_STATUS.REVIEWED]: [COLOR.GRB_GREEN, COLOR.ANSI_GREEN]
|
|
106
|
+
};
|
|
107
|
+
const STATUS_INFO = {
|
|
108
|
+
[I18N_STATUS.STRING_LOCALIZED]: "string is localized",
|
|
109
|
+
[I18N_STATUS.STRING_PARTIALLY_LOCALIZED]: "string is partially localized",
|
|
110
|
+
[I18N_STATUS.NUMBER_LOCALIZED]: "number is localized",
|
|
111
|
+
[I18N_STATUS.DATE_LOCALIZED]: "date is localized",
|
|
112
|
+
[I18N_STATUS.DATE_TIME_LOCALIZED]: "dateTime is localized",
|
|
113
|
+
[I18N_STATUS.TIME_LOCALIZED]: "time is localized",
|
|
114
|
+
[I18N_STATUS.CURRENCY_LOCALIZED]: "currency is localized",
|
|
115
|
+
[I18N_STATUS.PERCENTAGE_LOCALIZED]: "percentage is localized",
|
|
116
|
+
[I18N_STATUS.STRING_NOT_LOCALIZED]: "string is not localized",
|
|
117
|
+
[I18N_STATUS.DATE_NOT_LOCALIZED]: "date is not localized",
|
|
118
|
+
[I18N_STATUS.DATE_TIME_NOT_LOCALIZED]: "dateTime is not localized",
|
|
119
|
+
[I18N_STATUS.TIME_NOT_LOCALIZED]: "time is not localized",
|
|
120
|
+
[I18N_STATUS.NUMBER_NOT_LOCALIZED]: "number is not localized",
|
|
121
|
+
[I18N_STATUS.CURRENCY_NOT_LOCALIZED]: "currency is not localized",
|
|
122
|
+
[I18N_STATUS.PERCENTAGE_NOT_LOCALIZED]: "percentage is not localized",
|
|
123
|
+
[I18N_STATUS.TRUNCATION_ISSUE]: "truncation issue detected",
|
|
124
|
+
[I18N_STATUS.OVERLAPPING_ISSUE]: "overlapping issue detected",
|
|
125
|
+
[I18N_STATUS.ENCODING_ISSUE]: "encoding issue detected",
|
|
126
|
+
[I18N_STATUS.DNT]: "do not translate",
|
|
127
|
+
[I18N_STATUS.IGNORE]: "ignored this issue",
|
|
128
|
+
[I18N_STATUS.UNTRANSLATED]: "string is untranslated",
|
|
129
|
+
[I18N_STATUS.AUTO_IGNORE]: "automatically ignored issue",
|
|
130
|
+
[I18N_STATUS.USER_INPUT]: "user input field",
|
|
131
|
+
[I18N_STATUS.REVIEWED]: "string has been reviewed"
|
|
132
|
+
};
|
|
133
|
+
const PATTERNS = {
|
|
134
|
+
EMAIL: /\b[A-Z0-9._%+-]+@[A-Z0-9.-]+.[A-Z]{2,4}\b/gi,
|
|
135
|
+
URL: /^(https?:\/\/)?(www\.)?[a-zA-Z0-9-]+\.[a-zA-Z]{2,}(\.[a-zA-Z]{2,})?$/
|
|
136
|
+
};
|
|
137
|
+
const USER_INPUT_PRE_FIX = "zqa_";
|
|
138
|
+
const RES_FILE_EXTENSIONS = [".txt", ".json"];
|
|
139
|
+
const SMART_SELECTOR = `//*[not(self::script or self::style or self::noscript)]
|
|
2
140
|
[string-length(normalize-space(.)) > 0]
|
|
3
141
|
[not(*)]
|
|
4
142
|
[not(ancestor::*[
|
|
@@ -36,8 +174,280 @@
|
|
|
36
174
|
or contains(@aria-hidden, 'true')
|
|
37
175
|
or @hidden
|
|
38
176
|
])]
|
|
39
|
-
|
|
40
|
-
|
|
177
|
+
`;
|
|
178
|
+
const DEBUG_MODE = true;
|
|
179
|
+
const GARBLED_CHARACTERS = [
|
|
180
|
+
"☐",
|
|
181
|
+
"�",
|
|
182
|
+
"",
|
|
183
|
+
"â€",
|
|
184
|
+
"î",
|
|
185
|
+
"ÃÂ",
|
|
186
|
+
"ÃÂ",
|
|
187
|
+
"ü",
|
|
188
|
+
"é",
|
|
189
|
+
"é",
|
|
190
|
+
"æ•°",
|
|
191
|
+
"æ®",
|
|
192
|
+
"ラã"
|
|
193
|
+
];
|
|
194
|
+
const CONFIG_FILE_NAME = ".i18n-verify.rc";
|
|
195
|
+
const SUPPORTED_REPORT_TYPES = {
|
|
196
|
+
HTML: "html",
|
|
197
|
+
ASCII_TABLE: "ascii_table"
|
|
198
|
+
};
|
|
199
|
+
const CACHE_FILE_NAME = "metrics.cache";
|
|
200
|
+
const DEFAULT_REPORT_NAME = "report";
|
|
201
|
+
const RUN_MODE = {
|
|
202
|
+
SANITY: "sanity",
|
|
203
|
+
I18N: "i18n",
|
|
204
|
+
CONTEXT: "context"
|
|
205
|
+
};
|
|
206
|
+
const CONTEXT_FILE_KEYS = {
|
|
207
|
+
BOOKMARK: "bookmark",
|
|
208
|
+
CATEGORY: "category",
|
|
209
|
+
FILE_NAME: "fileName",
|
|
210
|
+
SCREENSHOT: "screenshot",
|
|
211
|
+
STRINGS: "strings"
|
|
212
|
+
};
|
|
213
|
+
class BaseDriver {
|
|
214
|
+
constructor(driver) {
|
|
215
|
+
this.$driver = driver;
|
|
216
|
+
}
|
|
217
|
+
checkIfNullOrEmpty(value) {
|
|
218
|
+
return ![null, "", void 0].includes(value);
|
|
219
|
+
}
|
|
220
|
+
getElement() {
|
|
221
|
+
throw new Error("implementation is missing");
|
|
222
|
+
}
|
|
223
|
+
getElements() {
|
|
224
|
+
throw new Error("implementation is missing");
|
|
225
|
+
}
|
|
226
|
+
getText() {
|
|
227
|
+
throw new Error("implementation is missing");
|
|
228
|
+
}
|
|
229
|
+
getTitle() {
|
|
230
|
+
throw new Error("implementation is missing");
|
|
231
|
+
}
|
|
232
|
+
getPlaceholderText() {
|
|
233
|
+
throw new Error("implementation is missing");
|
|
234
|
+
}
|
|
235
|
+
getAltText() {
|
|
236
|
+
throw new Error("implementation is missing");
|
|
237
|
+
}
|
|
238
|
+
getWidth() {
|
|
239
|
+
throw new Error("implementation is missing");
|
|
240
|
+
}
|
|
241
|
+
getHeight() {
|
|
242
|
+
throw new Error("implementation is missing");
|
|
243
|
+
}
|
|
244
|
+
getTagName() {
|
|
245
|
+
throw new Error("implementation is missing");
|
|
246
|
+
}
|
|
247
|
+
getValue() {
|
|
248
|
+
throw new Error("implementation is missing");
|
|
249
|
+
}
|
|
250
|
+
getLocation() {
|
|
251
|
+
throw new Error("implementation is missing");
|
|
252
|
+
}
|
|
253
|
+
getElementDimension() {
|
|
254
|
+
throw new Error("implementation is missing");
|
|
255
|
+
}
|
|
256
|
+
getElementID() {
|
|
257
|
+
throw new Error("implementation is missing");
|
|
258
|
+
}
|
|
259
|
+
isElementDisplayed() {
|
|
260
|
+
throw new Error("implementation is missing");
|
|
261
|
+
}
|
|
262
|
+
isElementPresent() {
|
|
263
|
+
throw new Error("implementation is missing");
|
|
264
|
+
}
|
|
265
|
+
getElementString() {
|
|
266
|
+
throw new Error("implementation is missing");
|
|
267
|
+
}
|
|
268
|
+
getElementStrings() {
|
|
269
|
+
throw new Error("implementation is missing");
|
|
270
|
+
}
|
|
271
|
+
captureScreenshot() {
|
|
272
|
+
throw new Error("implementation is missing");
|
|
273
|
+
}
|
|
274
|
+
getElementsCount() {
|
|
275
|
+
throw new Error("implementation is missing");
|
|
276
|
+
}
|
|
277
|
+
switchToIFrame() {
|
|
278
|
+
throw new Error("implementation is missing");
|
|
279
|
+
}
|
|
280
|
+
switchToParentFrame() {
|
|
281
|
+
throw new Error("implementation is missing");
|
|
282
|
+
}
|
|
283
|
+
pause() {
|
|
284
|
+
throw new Error("implementation is missing");
|
|
285
|
+
}
|
|
286
|
+
onScreenStringHighlight() {
|
|
287
|
+
throw new Error("implementation is missing");
|
|
288
|
+
}
|
|
289
|
+
checkIfIframeIsPresent() {
|
|
290
|
+
throw new Error("implementation is missing");
|
|
291
|
+
}
|
|
292
|
+
checkIfIframeBodyIsEmpty() {
|
|
293
|
+
throw new Error("implementation is missing");
|
|
294
|
+
}
|
|
295
|
+
printOnConsole(str) {
|
|
296
|
+
console.log(str);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
const dirExists = (path2) => pathExists(path2) && statSync(path2).isDirectory();
|
|
300
|
+
const fileExists = (path2) => pathExists(path2) && statSync(path2).isFile();
|
|
301
|
+
const pathExists = (path2) => existsSync(path2);
|
|
302
|
+
const createFolder = (path2) => !pathExists(path2) && mkdirSync(path2, { recursive: true });
|
|
303
|
+
const ensureDirectoryExists = (path2, log2 = true) => {
|
|
304
|
+
if (!pathExists(path2) || !dirExists(path2)) {
|
|
305
|
+
log2 && Logger$1.debug(`Folder doesn't exists, creating \x1B[34m${path2}\x1B[0m`);
|
|
306
|
+
createFolder(path2);
|
|
307
|
+
}
|
|
308
|
+
};
|
|
309
|
+
const getFileContent = (path2) => fileExists(path2) ? readFileSync(path2, { encoding: "utf-8" }) : "";
|
|
310
|
+
const getDirContents = (path2) => dirExists(path2) ? readdirSync(path2) : [];
|
|
311
|
+
const getFileExtenstion = (path2) => fileExists(path2) ? extname(path2) : "";
|
|
312
|
+
const joinPaths = (...paths) => paths?.every((p) => typeof p == "string") ? join(...paths) : "";
|
|
313
|
+
const saveToFile = (path2, content, encoding = "utf-8") => writeFileSync(path2, content, {
|
|
314
|
+
encoding
|
|
315
|
+
});
|
|
316
|
+
const addContentToFile = (path2, content, encoding = "utf-8") => {
|
|
317
|
+
if (!path2 || !content) return;
|
|
318
|
+
try {
|
|
319
|
+
appendFileSync(path2, content + "\n", {
|
|
320
|
+
encoding,
|
|
321
|
+
flag: "a"
|
|
322
|
+
});
|
|
323
|
+
} catch (err) {
|
|
324
|
+
Logger$1.error(err);
|
|
325
|
+
}
|
|
326
|
+
};
|
|
327
|
+
const getDirPath = (filePath) => dirname(filePath);
|
|
328
|
+
const toFileNameFormat = (name) => name.replace(/[^a-zA-Z0-9]+/g, "_");
|
|
329
|
+
const imageToBase64 = (imagePath) => {
|
|
330
|
+
const imgInput = readFileSync(imagePath);
|
|
331
|
+
return imgInput.toString("base64");
|
|
332
|
+
};
|
|
333
|
+
class ReportData {
|
|
334
|
+
/**
|
|
335
|
+
* @type {String}
|
|
336
|
+
*/
|
|
337
|
+
#appName;
|
|
338
|
+
/**
|
|
339
|
+
* @type {String}
|
|
340
|
+
*/
|
|
341
|
+
#defaultLocale;
|
|
342
|
+
/**
|
|
343
|
+
* @type {String}
|
|
344
|
+
*/
|
|
345
|
+
#reportTime;
|
|
346
|
+
/**
|
|
347
|
+
* @type {Boolean}
|
|
348
|
+
*/
|
|
349
|
+
#isContext;
|
|
350
|
+
/**
|
|
351
|
+
* @type {Boolean}
|
|
352
|
+
*/
|
|
353
|
+
#isSanity;
|
|
354
|
+
/**
|
|
355
|
+
* @type {String}
|
|
356
|
+
*/
|
|
357
|
+
#reportFolderTimestamp;
|
|
358
|
+
constructor({
|
|
359
|
+
appName,
|
|
360
|
+
reportTime,
|
|
361
|
+
isContext,
|
|
362
|
+
isSanity,
|
|
363
|
+
defaultLocale,
|
|
364
|
+
reportFolderTimestamp
|
|
365
|
+
}) {
|
|
366
|
+
this.#appName = appName;
|
|
367
|
+
this.#reportTime = reportTime;
|
|
368
|
+
this.#isContext = isContext;
|
|
369
|
+
this.#isSanity = isSanity;
|
|
370
|
+
this.#defaultLocale = defaultLocale;
|
|
371
|
+
this.#reportFolderTimestamp = reportFolderTimestamp;
|
|
372
|
+
}
|
|
373
|
+
getAppName() {
|
|
374
|
+
return this.#appName;
|
|
375
|
+
}
|
|
376
|
+
getReportTime() {
|
|
377
|
+
return this.#reportTime;
|
|
378
|
+
}
|
|
379
|
+
isSanityRun() {
|
|
380
|
+
return this.#isSanity;
|
|
381
|
+
}
|
|
382
|
+
isContextRun() {
|
|
383
|
+
return this.#isContext;
|
|
384
|
+
}
|
|
385
|
+
getDefaultLocale() {
|
|
386
|
+
return this.#defaultLocale;
|
|
387
|
+
}
|
|
388
|
+
getDefaultLocale() {
|
|
389
|
+
return this.#defaultLocale;
|
|
390
|
+
}
|
|
391
|
+
getReportFolderTimestamp() {
|
|
392
|
+
return this.#reportFolderTimestamp;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
class BaseReport {
|
|
396
|
+
/**
|
|
397
|
+
* @type {ReportData}
|
|
398
|
+
*/
|
|
399
|
+
#reportData;
|
|
400
|
+
/**
|
|
401
|
+
* @type {String | any}
|
|
402
|
+
*/
|
|
403
|
+
$generatedContent;
|
|
404
|
+
/**
|
|
405
|
+
* @type {String}
|
|
406
|
+
*/
|
|
407
|
+
$type;
|
|
408
|
+
constructor(type) {
|
|
409
|
+
this.$type = type;
|
|
410
|
+
}
|
|
411
|
+
generate(data2) {
|
|
412
|
+
this.#reportData = data2;
|
|
413
|
+
this.$generatedContent = this.buildContent();
|
|
414
|
+
}
|
|
415
|
+
export(path2, name = DEFAULT_REPORT_NAME) {
|
|
416
|
+
this.write(path2, name, this.$generatedContent);
|
|
417
|
+
Logger$1.info(
|
|
418
|
+
`Exported consolidated I18n Verification ${this.$type} report in ${path2}`
|
|
419
|
+
);
|
|
420
|
+
}
|
|
421
|
+
write(path2, name, data2) {
|
|
422
|
+
throw new Error("should be implemented by child report classes");
|
|
423
|
+
}
|
|
424
|
+
buildContent() {
|
|
425
|
+
throw new Error("should be implemented by child report classes");
|
|
426
|
+
}
|
|
427
|
+
/**
|
|
428
|
+
*
|
|
429
|
+
* @returns {{
|
|
430
|
+
* appName: String,
|
|
431
|
+
* defaultLocale: String,
|
|
432
|
+
* reportTime: String,
|
|
433
|
+
* isSanity: Boolean
|
|
434
|
+
* isContext: Boolean
|
|
435
|
+
* reportFolderTimestamp: String
|
|
436
|
+
* }}
|
|
437
|
+
*/
|
|
438
|
+
getMetaInfo() {
|
|
439
|
+
return {
|
|
440
|
+
defaultLocale: this.#reportData.getDefaultLocale(),
|
|
441
|
+
appName: this.#reportData.getAppName(),
|
|
442
|
+
reportTime: this.#reportData.getReportTime(),
|
|
443
|
+
isSanity: this.#reportData.isSanityRun(),
|
|
444
|
+
isContext: this.#reportData.isContextRun(),
|
|
445
|
+
reportFolderTimestamp: this.#reportData.getReportFolderTimestamp()
|
|
446
|
+
};
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
function getBodyData() {
|
|
450
|
+
return `<header><div class="logo">zAutomate.AI</div><div class="report-timestamp"><span class="info"></span></div></header>
|
|
41
451
|
<main>
|
|
42
452
|
<div class="sidebar">
|
|
43
453
|
<ul class="menu" id="menu">
|
|
@@ -158,7 +568,10 @@
|
|
|
158
568
|
</div>
|
|
159
569
|
</div>
|
|
160
570
|
</div>
|
|
161
|
-
</main
|
|
571
|
+
</main>`;
|
|
572
|
+
}
|
|
573
|
+
function getCssData() {
|
|
574
|
+
return `html {
|
|
162
575
|
width: 100vw;
|
|
163
576
|
height: 100vh;
|
|
164
577
|
}
|
|
@@ -1103,7 +1516,18 @@
|
|
|
1103
1516
|
background: #00000014 !important;
|
|
1104
1517
|
transform: none !important;
|
|
1105
1518
|
transition: none !important;
|
|
1106
|
-
}
|
|
1519
|
+
}`;
|
|
1520
|
+
}
|
|
1521
|
+
function renderHtml({
|
|
1522
|
+
appName,
|
|
1523
|
+
reportTime,
|
|
1524
|
+
script,
|
|
1525
|
+
style,
|
|
1526
|
+
body,
|
|
1527
|
+
dataFilePaths = [],
|
|
1528
|
+
logData
|
|
1529
|
+
}) {
|
|
1530
|
+
return `<!DOCTYPE html>
|
|
1107
1531
|
<html lang="en">
|
|
1108
1532
|
<head>
|
|
1109
1533
|
<meta charset="UTF-8" />
|
|
@@ -1117,17 +1541,19 @@
|
|
|
1117
1541
|
name="description"
|
|
1118
1542
|
content="zAutomate.AI report"
|
|
1119
1543
|
/>
|
|
1120
|
-
<title>${
|
|
1544
|
+
<title>${appName} - zAutomate.AI report | ${reportTime}</title>
|
|
1121
1545
|
<!-- 3rd party dependencies -->
|
|
1122
1546
|
<link
|
|
1123
1547
|
rel="stylesheet"
|
|
1124
1548
|
href="https://cdn.datatables.net/2.0.3/css/dataTables.dataTables.min.css"
|
|
1125
1549
|
/>
|
|
1126
|
-
${
|
|
1127
|
-
|
|
1550
|
+
${dataFilePaths.map(
|
|
1551
|
+
(v) => `<script
|
|
1552
|
+
src="${v}"
|
|
1128
1553
|
type="text/javascript">
|
|
1129
|
-
<\/script>`
|
|
1130
|
-
|
|
1554
|
+
<\/script>`
|
|
1555
|
+
).join("")}
|
|
1556
|
+
${logData ? `<script type="text/javascript" async/>window.logData = \`${logData}\`;<\/script>` : ""}
|
|
1131
1557
|
<script
|
|
1132
1558
|
src="https://code.jquery.com/jquery-3.7.1.slim.min.js"
|
|
1133
1559
|
integrity="sha256-kmHvs0B+OpCW5GVHUNjv9rOmY0IvSIRcf7zGUDTDQM8="
|
|
@@ -1140,17 +1566,19 @@
|
|
|
1140
1566
|
defer
|
|
1141
1567
|
><\/script>
|
|
1142
1568
|
<style>
|
|
1143
|
-
${
|
|
1569
|
+
${style}
|
|
1144
1570
|
</style>
|
|
1145
1571
|
</head>
|
|
1146
1572
|
<body>
|
|
1147
|
-
${
|
|
1573
|
+
${body}
|
|
1148
1574
|
</body>
|
|
1149
1575
|
<script type="text/javascript" defer>
|
|
1150
|
-
${
|
|
1576
|
+
${script}
|
|
1151
1577
|
<\/script>
|
|
1152
1578
|
</html>
|
|
1153
|
-
|
|
1579
|
+
`;
|
|
1580
|
+
}
|
|
1581
|
+
const menuBar = () => `(() => {
|
|
1154
1582
|
// for sidebar menu
|
|
1155
1583
|
// hide insights tab
|
|
1156
1584
|
if(DataStore.hasRuntimeError() || !DataStore.ranSuccessfully() || DataStore.isContextRun()) {
|
|
@@ -1279,7 +1707,8 @@
|
|
|
1279
1707
|
'header .report-timestamp .info'
|
|
1280
1708
|
).innerHTML = \`Report generated at: \${toLocaleString(Datastore.getTimestamp())}\`;
|
|
1281
1709
|
});
|
|
1282
|
-
})()
|
|
1710
|
+
})();`;
|
|
1711
|
+
const overview = () => `//overview content
|
|
1283
1712
|
(() => {
|
|
1284
1713
|
if (DataStore.hasRuntimeError()) {
|
|
1285
1714
|
document.getElementById('overview').innerHtml =
|
|
@@ -2970,7 +3399,8 @@
|
|
|
2970
3399
|
}
|
|
2971
3400
|
}
|
|
2972
3401
|
});
|
|
2973
|
-
})()
|
|
3402
|
+
})();`;
|
|
3403
|
+
const insight = () => `// insights content
|
|
2974
3404
|
(() => {
|
|
2975
3405
|
if (!DataStore.ranSuccessfully()) {
|
|
2976
3406
|
document.getElementById('overview').innerHTML =
|
|
@@ -3220,7 +3650,8 @@
|
|
|
3220
3650
|
}
|
|
3221
3651
|
}
|
|
3222
3652
|
});
|
|
3223
|
-
})()
|
|
3653
|
+
})();`;
|
|
3654
|
+
const localeGrid = () => `// locale grid
|
|
3224
3655
|
(() => {
|
|
3225
3656
|
if (!DataStore.ranSuccessfully()) {
|
|
3226
3657
|
return;
|
|
@@ -3431,16 +3862,17 @@
|
|
|
3431
3862
|
};
|
|
3432
3863
|
});
|
|
3433
3864
|
})();
|
|
3434
|
-
|
|
3865
|
+
`;
|
|
3866
|
+
const data = (metaData) => `// DataStore
|
|
3435
3867
|
(() => {
|
|
3436
3868
|
// prepare appData and set DataStore
|
|
3437
3869
|
var appData = {
|
|
3438
|
-
appName: '${
|
|
3439
|
-
defaultLocale: '${
|
|
3440
|
-
sanityRun: ${
|
|
3441
|
-
contextRun: ${
|
|
3442
|
-
timeStamp: '${
|
|
3443
|
-
reportFolderTimestamp: '${
|
|
3870
|
+
appName: '${metaData.appName}',
|
|
3871
|
+
defaultLocale: '${metaData.defaultLocale}',
|
|
3872
|
+
sanityRun: ${metaData.isSanity},
|
|
3873
|
+
contextRun: ${metaData.isContext},
|
|
3874
|
+
timeStamp: '${metaData.reportTime}',
|
|
3875
|
+
reportFolderTimestamp: '${metaData.reportFolderTimestamp}',
|
|
3444
3876
|
pagesByLocale: {},
|
|
3445
3877
|
metaData: {
|
|
3446
3878
|
stats: {},
|
|
@@ -3528,7 +3960,8 @@
|
|
|
3528
3960
|
}
|
|
3529
3961
|
|
|
3530
3962
|
DataStore = new SimpleDataStore();
|
|
3531
|
-
})()
|
|
3963
|
+
})();`;
|
|
3964
|
+
const global = () => `var DataStore;
|
|
3532
3965
|
// global functions
|
|
3533
3966
|
function openImageViewer(imageSrc) {
|
|
3534
3967
|
var imageView = document.getElementById('imageView');
|
|
@@ -3572,7 +4005,8 @@
|
|
|
3572
4005
|
}
|
|
3573
4006
|
} else {
|
|
3574
4007
|
window.isStandaloneReport = true;
|
|
3575
|
-
}
|
|
4008
|
+
}`;
|
|
4009
|
+
const log = () => `// log content
|
|
3576
4010
|
(() => {
|
|
3577
4011
|
document.addEventListener('DOMContentLoaded', function () {
|
|
3578
4012
|
const pre = document.querySelector('#log .log-content pre');
|
|
@@ -3583,21 +4017,2671 @@
|
|
|
3583
4017
|
pre.textContent = window.logData || (DataStore.hasRuntimeError() ? 'We are facing internal issue. Please try again after sometime.' : 'No log data found!');
|
|
3584
4018
|
});
|
|
3585
4019
|
});
|
|
3586
|
-
})()
|
|
3587
|
-
|
|
3588
|
-
${
|
|
3589
|
-
${
|
|
3590
|
-
${
|
|
3591
|
-
${
|
|
3592
|
-
${Ze()}`;class Ve extends Ee{constructor(){super(k.HTML)}buildContent(){const e=this.getMetaInfo(),t=Fe(e),a=Me(),n=ze(),s=[],o=g(l.getReportPath(),"logs","log"),u=c.isSanityRun()||c.isContextRun(),h=[c.getQALocale(),...c.getOptions()?.supportedLocales||[]].filter(Boolean).map(L=>O(L)),p=ae(l.getReportPath()).filter(L=>h.includes(L)),U=p.length===1&&p[0]===O(c.getDefaultLocale());let T="";if(p.forEach(L=>(u||L!==e.defaultLocale||L===e.defaultLocale&&U)&&x(g(l.getReportPath(),L,ee))&&s.push(g(L,ee).replace(/\\/g,"/"))),x(o)){const L=[e.appName,...c.getL10nReportsPath().split(/[\\/]+/g),c.getMode()];L.push(l.getReportTimeStamp()),T=M(o).replace(new RegExp(l.getReportPath().replace(/\\/g,"\\\\"),"g"),g(...L)).replace(/\\/g,"\\\\").replace(/`/g,"\\`")}return Pe({appName:e.appName,reportTime:e.reportTime,body:n,script:t,style:a,dataFilePaths:s,logData:T})}write(e,t,a){q(g(e,`${t}.html`),a,"utf-8")}}class W extends Ee{#e;#t=!1;static#r="STATUS";static#a="COUNTS";constructor(){super(k.ASCII_TABLE),this.#i()}#i(){this.#e=new ye.Table({style:{headerTop:{left:"\x1B[94m╔\x1B[0m",mid:"\x1B[94m╦\x1B[0m",right:"\x1B[94m╗\x1B[0m",other:"\x1B[94m═"},headerBottom:{left:"\x1B[94m╟\x1B[0m",mid:"\x1B[94m╬\x1B[0m",right:"\x1B[94m╢\x1B[0m",other:"\x1B[94m═"},tableBottom:{left:"\x1B[94m╚\x1B[0m",mid:"\x1B[94m╩\x1B[0m",right:"\x1B[94m╝\x1B[0m",other:"\x1B[94m═\x1B[0m"},vertical:"\x1B[94m║\x1B[0m"},columns:[{name:W.#r,alignment:"left"},{name:W.#a,alignment:"center"}]})}buildContent(){if(R[r.REVIEWED]>0){this.#t=!0;for(const e in R)e!==r.REVIEWED?R.hasOwnProperty(e)&&this.#e.addRows([{STATUS:e,COUNTS:`${R[e]}`}]):(this.#e.addRows([{STATUS:"\x1B[94m"+"═".repeat(28)+"\x1B[0m",COUNTS:"\x1B[94m"+"═".repeat(8)+"\x1B[0m"}]),this.#e.addRows([{STATUS:"OVERALL_REVIEWED",COUNTS:`${R[e]}`}]))}}export(){this.#t?this.#e.printTable():f.info("There are no visbile elements with UI strings")}}class re{static#e(e){switch(e){case k.HTML:return new Ve;case k.ASCII_TABLE:return new W;default:throw new Error("unsupported report type requested")}}static export(e,t,a){const n=re.#e(e),s=new Re({appName:c.getAppName(),reportTime:new Date().toLocaleString(),isContext:c.isContextRun(),isSanity:c.isSanityRun(),defaultLocale:c.getDefaultLocale(),reportFolderTimestamp:l.getReportTimeStamp()});n.generate(s),n.export(t,a)}}class S{static#e;static#t;static init(){S.#t=g(l.getReportPath(),O(c.getLocale())),S.#e=g(S.#t,ee),this.#r()}static exists(){return x(S.#e)}static save(e){this.#r();const t=`!window.rawData && (window.rawData={'${c.getLocale()}':{}});window.rawData['${c.getLocale()}']=${JSON.stringify(e)};`;q(S.#e,t)}static getData(){if(this.exists())try{return JSON.parse(M(S.#e).replace(new RegExp(`(\\!window.rawData && \\(window\\.rawData=\\{'${c.getLocale()}':\\{\\}\\}\\);window\\.rawData\\['${c.getLocale()}'\\]=)|(;$)`,"g"),""))}catch{return{}}else return{}}static#r(){j(S.#t)}static getCacheDirPath(){return S.#t}}class We{#e;#t;#r;#a;#i;#n;#s;#o;#l;#c;#d;#m;#p;#g;#h;#E;#f;#v;#w;#L;#u;#y;#I;#b;#S;constructor(e={}){this.#e=e?.localizedStrings||0,this.#t=e?.notLocalizedStrings||0,this.#r=e?.untranslatedStrings||0,this.#a=e?.partialStrings||0,this.#i=e?.localizedDateTime||0,this.#n=e?.localizedDate||0,this.#s=e?.localizedTime||0,this.#o=e?.notLocalizedDateTime||0,this.#l=e?.notLocalizedDate||0,this.#c=e?.notLocalizedTime||0,this.#d=e?.localizedNumber||0,this.#m=e?.notLocalizedNumber||0,this.#p=e?.localizedCurrency||0,this.#g=e?.notLocalizedCurrency||0,this.#h=e?.localizedPercentage||0,this.#E=e?.notLocalizedPercentage||0,this.#f=e?.ignored||0,this.#v=e?.dnt||0,this.#w=e?.autoIgnored||0,this.#L=e?.userInput||0,this.#u=e?.encoding||0,this.#y=e?.truncation||0,this.#I=e?.overlapping||0,this.#b=e?.reviewed||0,this.#S=e?.context||0}getLocalizedStrings(){return this.#e}setLocalizedStrings(e){this.#e=e}getUntranslatedStrings(){return this.#r}setUntranslatedStrings(e){this.#r=e}getNotLocalizedStrings(){return this.#t}setNotLocalizedStrings(e){this.#t=e}getPartialStrings(){return this.#a}setPartialStrings(e){this.#a=e}getLocalizedDateTime(){return this.#i}setLocalizedDateTime(e){this.#i=e}getLocalizedDate(){return this.#n}setLocalizedDate(e){this.#n=e}getLocalizedTime(){return this.#s}setLocalizedTime(e){this.#s=e}getNotLocalizedDateTime(){return this.#o}setNotLocalizedDateTime(e){this.#o=e}getNotLocalizedDate(){return this.#l}setNotLocalizedDate(e){this.#l=e}getNotLocalizedTime(){return this.#c}setNotLocalizedTime(e){this.#c=e}getLocalizedNumber(){return this.#d}setLocalizedNumber(e){this.#d=e}getNotLocalizeNumber(){return this.#m}setNotLocalizeNumber(e){this.#m=e}getCurrency(){return this.#p}setCurrency(e){this.#p=e}getNotLocalizeCurrency(){return this.#g}setNotLocalizeCurrency(e){this.#g=e}getPercentage(){return this.#h}setPercentage(e){this.#h=e}getNotLocalizePercentage(){return this.#E}setNotLocalizePercentage(e){this.#E=e}getIgnored(){return this.#f}setIgnored(e){this.#f=e}getUserInput(){return this.#L}setUserInput(e){this.#L=e}getDnt(){return this.#v}setDnt(e){this.#v=e}getAutoIgnored(){return this.#w}setAutoIgnored(e){this.#w=e}getEncoding(){return this.#u}setEncoding(e){this.#u=e}getTruncation(){return this.#y}setTruncation(e){this.#y=e}getOverlapping(){return this.#I}setOverlapping(e){this.#I=e}getReviewed(){return this.#b}setReviewed(e){this.#b=e}getContext(){return this.#S}setContext(e){this.#S=e}incrementByType(e){switch(e){case r.STRING_LOCALIZED:++this.#e;break;case r.STRING_NOT_LOCALIZED:++this.#t;break;case r.UNTRANSLATED:++this.#r;break;case r.STRING_PARTIALLY_LOCALIZED:++this.#a;break;case r.AUTO_IGNORE:++this.#w;break;case r.IGNORE:++this.#f;break;case r.DNT:++this.#v;break;case r.ENCODING_ISSUE:++this.#u;break;case r.DATE_LOCALIZED:++this.#n;break;case r.TIME_LOCALIZED:++this.#s;break;case r.DATE_TIME_LOCALIZED:++this.#i;break;case r.DATE_NOT_LOCALIZED:++this.#l;break;case r.TIME_NOT_LOCALIZED:++this.#c;break;case r.DATE_TIME_NOT_LOCALIZED:++this.#o;break;case r.NUMBER_LOCALIZED:++this.#d;break;case r.NUMBER_NOT_LOCALIZED:++this.#m;break;case r.CURRENCY_LOCALIZED:++this.#p;break;case r.CURRENCY_NOT_LOCALIZED:++this.#g;break;case r.PERCENTAGE_LOCALIZED:++this.#h;break;case r.PERCENTAGE_NOT_LOCALIZED:++this.#E;break;case r.TRUNCATION_ISSUE:++this.#y;break;case r.OVERLAPPING_ISSUE:++this.#I;break;case r.REVIEWED:++this.#b;break;case r.USER_INPUT:++this.#L;break;case"context":++this.#S;break}}toJSON(){return{localizedStrings:this.#e,notLocalizedStrings:this.#t,untranslatedStrings:this.#r,partialStrings:this.#a,localizedDateTime:this.#i,localizedDate:this.#n,localizedTime:this.#s,notLocalizedDateTime:this.#o,notLocalizedDate:this.#l,notLocalizedTime:this.#c,localizedNumber:this.#d,notLocalizedNumber:this.#m,localizedCurrency:this.#p,notLocalizedCurrency:this.#g,localizedPercentage:this.#h,notLocalizedPercentage:this.#E,ignored:this.#f,dnt:this.#v,autoIgnored:this.#w,userInput:this.#L,encoding:this.#u,truncation:this.#y,overlapping:this.#I,reviewed:this.#b,context:this.#S}}}class Ye{#e;constructor(e={}){this.#e=new We(e.stats)}getStats(){return this.#e}setStats(e){this.#e=e}toJSON(){return{stats:this.#e}}}class me{#e;#t;#r;constructor(e){this.#e=e?.type||"",this.#t=e?.imagePath||"",this.#r=e?.description||""}getType(){return this.#e}setType(e){this.#e=e}getImagePath(){return this.#t}setImagePath(e){this.#t=e}getDescription(){return this.#r}setDescription(e){this.#r=e}toJSON(){return{type:this.#e,description:this.#r,imagePath:this.#t}}}class ie{#e={};constructor(e){if(e)for(const t in e)e[t].forEach(a=>{this.#e[t]||(this.#e[t]=[]),this.#e[t].push(new me(a))})}getStringData(e){return this.#e[e]||[]}setStringData(e,t){return!this.#e[e]&&(this.#e[e]=[]),this.#e[e].push(new me(t)),!0}checkAndAdd(e,t){!this.#e[e]&&(this.#e[e]=[]);const a=this.getStringData(e).some(n=>n.getDescription()!==t.description||n.getImagePath()!==t.imagePath||n.getType()!==n.type);return a&&this.setStringData(e,t),a}hasStringData(e){return e in this.#e}static createNew(e,t){return t=Array.isArray(t)?t:[t],new ie({data:{[e]:t}})}toJSON(){return this.#e}}class B{#e;#t;constructor(e={}){this.#e=new Ye(e.metaData),this.#t=new ie(e.stringsData)}getMetaData(){return this.#e}setMetaData(e){this.#e=e}getStringEntry(e){return this.#t.getStringData(e)}static addString(e,t,a,n){const s=B.getInstance(),o=s.#r(e,t,a,n.replace(/\\/g,"/"));return o&&s.save(),o}#r(e,t,a,n){let s=!1;const o={type:t,description:a,imagePath:n};return this.#t.hasStringData(e)?s=this.#t.checkAndAdd(e,o):s=this.#t.setStringData(e,o),s&&this.#e.getStats().incrementByType(t),s}static incrementCountByType(e){const t=B.getInstance();t.#e.getStats().incrementByType(e),t.save()}toJSON(){return{metaData:this.#e,stringsData:this.#t}}save(){S.save(this)}remove(){S.delete()}static getInstance(){return new B(S.getData())}}class l{static#e;static#t;static setup(){l.#t||(l.#t=l.#r());const e=Z.resolve();l.#e=g(e,c.getL10nReportsPath(),c.getMode(),l.#t)}static getReportTimeStamp(){return l.#t}static getReportPath(){return l.#e}static reviewedReports(e=null,t=null){return l.#a(r.REVIEWED,e,t)}static getContextPath(){return this.#i()}static[r.STRING_LOCALIZED](e,t){return l.#a(r.STRING_LOCALIZED,e,t)}static[r.STRING_NOT_LOCALIZED](e,t){return l.#a(r.STRING_NOT_LOCALIZED,e,t)}static[r.STRING_PARTIALLY_LOCALIZED](e,t){return l.#a(r.STRING_PARTIALLY_LOCALIZED,e,t)}static[r.DNT](e,t){return l.#a(r.DNT,e,t)}static[r.IGNORE](e,t){return l.#a(r.IGNORE,e,t)}static[r.AUTO_IGNORE](e,t){return l.#a(r.AUTO_IGNORE,e,t)}static[r.UNTRANSLATED](e,t){return l.#a(r.UNTRANSLATED,e,t)}static[r.ENCODING_ISSUE](e,t){return l.#a(r.ENCODING_ISSUE,e,t)}static[r.DATE_TIME_LOCALIZED](e,t){return l.#a(r.DATE_TIME_LOCALIZED,e,t)}static[r.DATE_TIME_NOT_LOCALIZED](e,t){return l.#a(r.DATE_TIME_NOT_LOCALIZED,e,t)}static[r.DATE_LOCALIZED](e,t){return l.#a(r.DATE_LOCALIZED,e,t)}static[r.DATE_NOT_LOCALIZED](e,t){return l.#a(r.DATE_NOT_LOCALIZED,e,t)}static[r.TIME_LOCALIZED](e,t){return l.#a(r.TIME_LOCALIZED,e,t)}static[r.TIME_NOT_LOCALIZED](e,t){return l.#a(r.TIME_NOT_LOCALIZED,e,t)}static[r.CURRENCY_LOCALIZED](e,t){return l.#a(r.CURRENCY_LOCALIZED,e,t)}static[r.CURRENCY_NOT_LOCALIZED](e,t){return l.#a(r.CURRENCY_NOT_LOCALIZED,e,t)}static[r.PERCENTAGE_LOCALIZED](e,t){return l.#a(r.PERCENTAGE_LOCALIZED,e,t)}static[r.PERCENTAGE_NOT_LOCALIZED](e,t){return l.#a(r.PERCENTAGE_NOT_LOCALIZED,e,t)}static[r.NUMBER_LOCALIZED](e,t){return l.#a(r.NUMBER_LOCALIZED,e,t)}static[r.NUMBER_NOT_LOCALIZED](e,t){return l.#a(r.NUMBER_NOT_LOCALIZED,e,t)}static incrementCount(e,t,a,n){R.hasOwnProperty(e)&&(R[e]++,B.addString(t,e,n,a.replace(l.#e,"")))}static#r(){const e=new Date,t=e.getFullYear(),a=String(e.getMonth()+1).padStart(2,"0"),n=String(e.getDate()).padStart(2,"0"),s=String(e.getHours()).padStart(2,"0"),o=String(e.getMinutes()).padStart(2,"0");return`${t}-${a}-${n}-${s}-${o}`}static#a=(e,t,a)=>{const n=g(l.#e,O(c.getLocale()),"screenshots",String(e).toLowerCase());if(j(n,V),t!=null){const s=g(l.#e,O(c.getLocale()),"strings");j(s,V);let o="";const u=g(s,e+".txt");F(u)?(M(u).includes(a)||(o+=`
|
|
3593
|
-
|
|
3594
|
-
|
|
3595
|
-
|
|
3596
|
-
|
|
3597
|
-
|
|
3598
|
-
`),w.#r=[],e&&w.#i(e))},10);else{w.#e=!0;const t=g(l.getReportPath(),"logs"),a=g(t,"log");j(t,V),v.appendFileSync(a,e),w.#e=!1}}};class He extends H{constructor(e){super(e)}async getElement(e,t=!1){return await this.$driver.element.find({selector:e,locateStrategy:e.startsWith("/")?"xpath":"css selector",suppressNotFoundErrors:t})}async getElements(e,t=!1){return await this.$driver.element.findAll({selector:e,locateStrategy:e.startsWith("/")?"xpath":"css selector",suppressNotFoundErrors:t})}async getText(e){return await e.getText()}async getTitle(e){return await e.getAttribute("title")}async getPlaceholderText(e){return await e.getAttribute("placeholder")}async getAltText(e){return await e.getAttribute("alt")}async getTagName(e){return await e.getTagName()}async getValue(e){return await e.getAttribute("value")}async getElementID(e){return await e.getAttribute("id")}async getElementDimension(e){const t=await e.getRect();if(![null,"",void 0].includes(t))return[t.x,t.y,t.height,t.width]}async isElementDisplayed(e){return await this.$driver.isVisible(e)}async isElementPresent(e){return await this.$driver.isPresent(e)}async getElementStrings(e){const t=[];return this.isElementDisplayed(e)&&[{type:"eleTxt",value:await this.getText(e)},{type:"altTxt",value:await this.getAltText(e)},{type:"titleTxt",value:await this.getTitle(e)},{type:"placeTxt",value:await this.getPlaceholderText(e)},{type:"valueTxt",value:await this.getValue(e)}].forEach(({value:n})=>{this.checkIfNullOrEmpty(n)&&t.push(n)}),t}async getElementString(e){let t=null;const a=[this.getText,this.getAltText,this.getTitle,this.getPlaceholderText,this.getValue];for(const n of a)if(t=await n(e),t!==null)return t;return t}async captureScreenshot(e){await qe(this.$driver,e)}async getElementsCount(e){return e.length}async switchToIFrame(e,t){return new Promise(a=>{this.$driver.frame(e,function(){a(!0)})})}async switchToParentFrame(){return new Promise(e=>this.$driver.frame(null,function(){e(!0)}))}pause(e){this.$driver.pause(e*1e3)}async onScreenStringHighlight(e,t){await this.$driver.execute((a,n)=>{const s=window.getComputedStyle(a).border;a.style.border=`3px solid ${n}`,setTimeout(()=>{a.style.border=s},40)},[e,t])}async checkIfIframeIsPresent(){return new Promise(e=>{this.$driver.isPresent({selector:"//iframe",locateStrategy:"xpath",suppressNotFoundErrors:!0},t=>{e(t.value)})})}async checkIfIframeBodyIsEmpty(){return(await this.$driver.executeScript(function(){return document.body.innerHTML})).trim()===""}}const qe=async(i,e)=>{const t=await he({host:"localhost",port:Qe(i)}),{Page:a}=t;await a.enable();const{data:n}=await a.captureScreenshot({format:"png",captureBeyondViewport:!0}),s=Buffer.from(n,"base64");v.writeFileSync(e,s),f.debug(`Screenshot saved as: ${e}`),await t.close()},Qe=i=>{const e=i?.capabilities?.["goog:chromeOptions"]?.debuggerAddress;return e&&e.split(":")?.[1]||9229};class Xe extends H{constructor(e){super(e)}async getElement(e){return await this.$driver.$(e)}async getElements(e){return await this.$driver.$$(e)}async getText(e){return await $(e).getText()}async getTitle(e){return await $(e).getAttribute("title")}async getPlaceholderText(e){return await $(e).getAttribute("placeholder")}async getAltText(e){return await $(e).getAttribute("alt")}async getTagName(e){return await $(e).getTagName()}async getValue(e){return await $(e).getValue()}async getElementID(e){return await $(e).getAttribute("id")}async getElementDimension(e){if(!e)return null;try{const t=await e.getLocation(),a=await e.getSize();return!t||!a?null:[t.x,t.y,a.height,a.width]}catch(t){return console.error("Error getting element dimensions:",t),null}}async isElementDisplayed(e){return await $(e).isDisplayed()}async isElementPresent(e){return await $(e).isExisting()}async getElementStrings(e){const t=[];return[{type:"elTxt",value:await this.getText(e)},{type:"altTxt",value:await this.getAltText(e)},{type:"titleTxt",value:await this.getTitle(e)},{type:"placeTxt",value:await this.getPlaceholderText(e)},{type:"valueTxt",value:await this.getValue(e)}].forEach(({value:n})=>{this.checkIfNullOrEmpty(n)&&t.push(n)}),t}async getElementString(e){let t=null;const a=[this.getText,this.getAltText,this.getTitle,this.getPlaceholderText,this.getValue];for(const n of a)if(t=await n(e),t!==null)return t;return t}async captureScreenshot(e){await Je(this.$driver,e)}async getElementsCount(e){return e.length}async switchToIFrame(e,t){await this.$driver.switchFrame(t)}async switchToParentFrame(){await this.$driver.switchToParentFrame()}pause(e){this.$driver.pause(e*1e3)}async onScreenStringHighlight(e,t){await this.$driver.execute((a,n)=>{const s=window.getComputedStyle(a).border;a.style.border=`3px solid ${n}`,setTimeout(()=>{a.style.border=s},40)},e,t)}async checkIfIframeIsPresent(){return new Promise(e=>{this.$driver.$("//iframe").isExisting().then(()=>{e(!0)})})}async checkIfIframeBodyIsEmpty(){return(await this.$driver.executeScript("return document.body.innerHTML;",[])).trim()===""}}const Je=async(i,e)=>{const t=Ke(i),a=await he({host:"localhost",port:t}),{Page:n}=a;await n.enable();const{data:s}=await n.captureScreenshot({format:"png",captureBeyondViewport:!0});v.writeFileSync(e,Buffer.from(s,"base64")),await a.close()},Ke=i=>{const e=i.capabilities?.["goog:chromeOptions"]?.debuggerAddress;return e&&e.split(":")[1]||9229},et=({subject:i,selector:e,options:t={},driver:a})=>{if(!Cypress){a.printOnConsole("Cypress object is inaccessible");return}const n=m=>m.resultType===XPathResult.NUMBER_TYPE,s=m=>m.numberValue,o=m=>m.resultType===XPathResult.STRING_TYPE,u=m=>m.stringValue,h=m=>m.resultType===XPathResult.BOOLEAN_TYPE,p=m=>m.booleanValue,U=m=>Cypress._.isNumber(m)||Cypress._.isString(m)||Cypress._.isBoolean(m),T={name:"xpath",message:e};if(Cypress.dom.isElement(i)&&i.length>1)throw new Error("xpath() can only be called on a single element. Your subject contained "+i.length+" elements.");const L=()=>{let m=[],_,ce=cy.state("withinSubject");Cypress.dom.isElement(i)?_=i[0]:Cypress.dom.isDocument(i)?_=i:ce?_=ce[0]:_=cy.state("window").document;let A=(_.ownerDocument||_).evaluate(e,_);if(n(A)){const I=s(A);return T.consoleProps=()=>({XPath:e,type:"number",result:I}),I}if(o(A)){const I=u(A);return T.consoleProps=()=>({XPath:e,type:"string",result:I}),I}if(h(A)){const I=p(A);return T.consoleProps=()=>({XPath:e,type:"boolean",result:I}),I}try{let I=A.iterateNext();for(;I;)m.push(I),I=A.iterateNext();return T.consoleProps=()=>({XPath:e,result:m.length===1?m[0]:m}),m}catch(I){return console.error("Document tree modified during iteration",I),null}},le=()=>Cypress.Promise.try(L).then(m=>(U(m)||(m=Cypress.$(m),m.selector=e),cy.verifyUpcomingAssertions(m,t,{onRetry:le})));return le().then(m=>(t.log!==!1&&Cypress.log(T),m)).catch(m=>console.log(m))};class tt extends H{constructor(e){super(e)}async getElement(e){return typeof e!="string"?this.$driver.wrap(e):e.startsWith("//")?await this.xpath(e).first():await this.$driver.get(e).first()}async getElements(e){return typeof e!="string"?this.$driver.wrap(e):e.startsWith("//")?await this.xpath(e):await this.$driver.get(e)}async getText(e){return typeof e=="string"?await this.$driver.get(e).invoke("text"):await this.$driver.wrap(e).invoke("text")}async getTitle(e){return typeof e=="string"?await this.$driver.get(e).title():this.$driver.wrap().title()}async getPlaceholderText(e){return typeof e=="string"?this.$driver.get(e).filter("input").invoke("attr","placeholder").then(t=>t):this.$driver.$$(e).attr("placeholder")}async getAltText(e){return this.$driver.get(e).invoke("attr","alt")}async getWidth(e){return typeof e=="string"?this.$driver.get(e).invoke("width"):this.$driver.$$(e).width()}async getHeight(e){return typeof e=="string"?this.$driver.get(e).invoke("height"):this.$driver.$$(e).height()}async getTagName(e){return typeof e=="string"?this.$driver.get(e).invoke("prop","tagName").then(t=>t.toLowerCase()):this.$driver.$$(e).tagName}async getValue(e){return typeof e=="string"?this.$driver.get(e).invoke("val"):this.$driver.wrap(e).invoke("val")}async getLocation(e){if(typeof e=="string")return this.$driver.get(e).invoke("offset").then(t=>({x:t.left,y:t.top}));{const t=this.$driver.$$(e).offset();return{x:t.left,y:t.top}}}async isElementDisplayed(e){return typeof e=="string"?this.$driver.get(e).then(t=>t.is(":visible")):this.$driver.$$(e).is(":visible")}async captureScreenshot(e){this.$driver.screenshot(e)}async getElementsCount(e){return new Promise(t=>typeof e=="string"?this.$driver.get(e).its("length").then(a=>t(a)):this.$driver.wrap(e,{timeout:8e3}).its("length").then(a=>t(a)))}async getElementStrings(e){const t=[];try{[{type:"elTxt",value:await this.getText(e)},{type:"altTxt",value:await this.getAltText(e)},{type:"placetxt",value:await this.getPlaceholderText(e)}].forEach(({value:n})=>{this.checkIfNullOrEmpty(n)&&t.push(n)})}catch(a){f.error("Error getting text of element:",a)}return t}printOnConsole(e){this.$driver.log(e)}xpath(e,t,a={}){return et({subject:e,selector:t,options:a,driver:this.$driver})}}class at extends H{constructor(e){super(e)}async getElement(e){return await this.driver.findElement(e)}async getElements(e){return await this.driver.findElements(e)}async getText(e){return await e.getText()}async getTitle(){return await this.driver.getTitle()}async getAttribute(e,t){return await e.getAttribute(t)}async getTagName(e){return await e.getTagName()}async getElementDimension(e){const t=await e.getRect();if(![null,"",void 0].includes(t))return[t.x,t.y,t.height,t.width]}async isElementDisplayed(e){return await e.isDisplayed()}async getElementStrings(e){const t=[];return[{type:"elTxt",value:await this.getText(e)},{type:"altTxt",value:await this.getAttribute(e,"alt")},{type:"titleTxt",value:await this.getAttribute(e,"title")},{type:"placeTxt",value:await this.getAttribute(e,"placeholder")},{type:"valueTxt",value:await this.getAttribute(e,"value")}].forEach(({value:n})=>{this.checkIfNullOrEmpty(n)&&t.push(n)}),t}async getElementsCount(e){return e.length}}const rt=(i,e)=>{switch(i){case z.NIGHT_WATCH:return new He(e);case z.WEB_DRIVER_IO:return new Xe(e);case z.CYPRESS:return new tt(e);case z.SELENIUMJS:return new at(e);default:throw new Error("Unsupported framework")}},it=(i,e)=>i in e,nt=(i,e,t=[])=>i.every(a=>(it(a,e)||t.push(a),!0)),fe=(i,e=", ")=>i.join(e),D=(i=!0)=>i?"(?:\\s|\\t|(?: ))":/(?:\s|\t|(?: ))/g;class P{#e={};#t;constructor(e){this.#t=e,this.#r(),this.buildConfig(),this.#a()}#r(){this.addToConfig("supportedLocales",c.getOptions()?.supportedLocales,[]),this.addToConfig("defaultLocale",c.getDefaultLocale()),this.addToConfig("defaultLanguage",c.getDefaultLocale()?.split(/[-_ ]/g)[0]),this.addToConfig("language",c.getLocale()?.split(/[-_ ]/g)[0]),this.addToConfig("locale",c.getLocale()),this.addToConfig("qaLocale",c.getQALocale())}buildConfig(){throw new Error(`{{${this.#t}}} buildConfig should be implemented by child class`)}#a(){Q.load(X.entireSupplemental()),Q.load(X.entireMainFor(this.#i(this.#e.defaultLocale),this.#i(this.#e.locale)))}#i(e){if(this.isQaLocale())return"en";e=e.replace(/[-_ ]/g,"-");const t=X.availableLocales;let a;if(t.find(n=>n===e))a=e;else{const n=e.split("-")[0];t.find(s=>s===n)?a=n:a=e}return a}validate(e){throw new Error(`{{${this.#t}}} validate should be implemented by child class`)}isInternationalized(e){throw new Error(`{{${this.#t}}} isInternationalized should be implemented by child class`)}setConfig(e){this.#e=e}addToConfig(e,t,a){this.#e[e]=t??a}getConfig(){return this.#e}isSupportedLocale(){return this.#e.supportedLocales.includes(this.currentLocale())}isQaLocale(){return this.currentLocale()===this.#e?.qaLocale}isDefaultLocale(){return this.currentLocale()===this.defaultLocale()}defaultLocale(){return this.#e?.defaultLocale}defaultLanguage(){return this.#e?.defaultLanguage}currentLocale(){return this.#e?.locale}currentLanguage(){return this.#e.language}getGlobalize(e){return Q(this.#i(e))}}class st extends P{constructor(){super("currency")}validate(e){return this.#s(e)||this.isInternationalized(e)}isInternationalized(e){return this.#e(this.currentLocale(),e)}buildConfig(){}#e(e,t){const a=this.#i(e),n=this.#n(e,a);if(!this.#t(a,n,t))return!1;const o=this.#r(a,n,t);return!isNaN(this.getGlobalize(e).numberParser()(o))}#t(e,t,a){return new RegExp(`^(?:-)?(?:${e}|\\${t})(?:${D()})?(?:-)?[0-9,. ]+$`,"gi").test(a)||new RegExp(`^(?:[- ]?)[0-9,. ]+(?:${D()})?(?:${e}|\\${t})$`,"gi").test(a)}#r(e,t,a){return a.replace(new RegExp(`^(?:-)(?:${D()})?`,"gi"),"").replace(new RegExp(`^(?:${D()})?(?:${e}|\\${t})`,"gi"),"").replace(new RegExp(`^(?:-)(?:${D()})?`,"gi"),"").replace(new RegExp(`(?:${D()})?(?:${e}|\\${t})$`,"gi"),"").trim()}#a(e){return(this.getGlobalize(e).cldr.supplemental(["likelySubtags",e])||e).split(/[-_ ]/).pop()}#i(e){const t=this.#a(e),n=this.getGlobalize(e).cldr.supplemental("currencyData").region[t];if(n){const s=n.find(o=>{const u=Object.values(o)[0];return!u._tender&&(!u._to||new Date(u._to)>=new Date)});return s?Object.keys(s)[0]:"USD"}return"USD"}#n(e,t){return this.getGlobalize(e).cldr.main(`numbers/currencies/${t}`)?.symbol||"$"}#s(e){return this.#e(this.defaultLocale(),e)}}const ot=i=>{let[e="en",t="us"]=i.split(/[-_ ]/g);switch(t=String(t).toLowerCase(),e){case"en":return t==="gb"?b.en.GB:b.en;case"de":return b.de;case"es":return b.es;case"fr":return b.fr;case"pt":return b.pt;case"ja":return b.ja;case"zh":return["hans","cn","sg","hans-cn"].includes(t)?b.zh.hans:["hant","tw","hk","mo","hant-tw"].includes(t)?b.zh.hant:b.zh;case"ru":return b.ru;case"nl":return b.nl;case"uk":return b.uk;default:return b.en}},ne=(i,e)=>(e=String(e),ot(i).parse(String(e).trim()).forEach(a=>{e=e.replace(a.text,"")}),e.replace(/[^\p{L}\p{N}]+/gu,"").trim().length===0),pe=i=>{try{return i=i.replace("_","-"),Intl.DateTimeFormat.supportedLocalesOf(i)[0]}catch{return Logger.warn(`${i} is unsupported by Intl`),!1}},se=(i,e,t)=>(i=pe(i),!!(i!==!1&&E.DateTime.fromFormat(t,e,{locale:pe(i)}).isValid));class lt extends P{constructor(){super("date")}validate(e){return this.#t(e)||this.isInternationalized(e)}isInternationalized(e){return this.#e(this.isQaLocale()?this.defaultLocale():this.currentLocale(),e)}buildConfig(){}#e(e,t){return this.#r(e,t)||this.#a(e,t)||this.#i(e,t)}#t(e){return this.#e(this.defaultLocale(),e)}#r(e,t){const a=["short","medium","long","full"];for(let n of a)if(this.getGlobalize(e).dateParser({date:n})(t))return!0;return!1}#a(e,t){const a=[E.DateTime.DATE_SHORT,E.DateTime.DATE_MED,E.DateTime.DATE_FULL,E.DateTime.DATE_HUGE,E.DateTime.DATE_MED_WITH_WEEKDAY,"D","DD","DDD","DDDD"];for(let n of a)if(se(e,n,t))return!0;return!1}#i(e,t){return ne(this.isQaLocale()?this.defaultLocale():e,t)}}class ct extends P{constructor(){super("dateTime")}validate(e){return this.#t(e)||this.isInternationalized(e)}isInternationalized(e){return this.#e(this.isQaLocale()?this.defaultLocale():this.currentLocale(),e)}buildConfig(){}#e(e,t){return this.#r(e,t)||this.#a(e,t)||this.#i(e,t)}#t(e){return this.#e(this.defaultLocale(),e)}#r(e,t){const a=["short","medium","long","full"];for(let n of a)if(this.getGlobalize(e).dateParser({datetime:n})(t))return!0;return!1}#a(e,t){const a=[E.DateTime.DATETIME_SHORT,E.DateTime.DATETIME_SHORT_WITH_SECONDS,E.DateTime.DATETIME_MED,E.DateTime.DATETIME_MED_WITH_SECONDS,E.DateTime.DATETIME_MED_WITH_WEEKDAY,E.DateTime.DATETIME_FULL,E.DateTime.DATETIME_FULL_WITH_SECONDS,E.DateTime.DATETIME_HUGE,E.DateTime.DATETIME_HUGE_WITH_SECONDS,"f","F","ff","FF"];for(let n of a)if(se(e,n,t))return!0;return!1}#i(e,t){return ne(this.isQaLocale()?this.defaultLocale():e,t)}}class dt extends P{constructor(){super("number")}validate(e){return this.#t(e)||this.isInternationalized(e)}isInternationalized(e){return this.#e(this.currentLocale(),e)}buildConfig(){}#e(e,t){const a=this.getGlobalize(e).numberParser();return!isNaN(a(t))}#t(e){return this.#e(this.defaultLocale(),e)}}class ut extends P{constructor(){super("percentage")}validate(e){return this.#a(e)||this.isInternationalized(e)}isInternationalized(e){return this.#e(this.currentLocale(),e)}buildConfig(){}#e(e,t){if(!this.#r(e,t))return!1;const n=this.#t(t);return!isNaN(this.getGlobalize(e).numberParser()(n))}#t(e=""){return e.replace(new RegExp(`(^(?:${D()})*|(?:${D()})*$)`,"g"),"").replace(/^-/,"").replace(/٪|%/g,"").trim()}#r(e,t){const a="[0-9,. ]+";let n;return["fa-IR","fa-ir"].includes(e)||e.startsWith("ar")?n=new RegExp(`(?:-)?(?:${D()})?(?:٪|%)(?:${D()})?${a}`,"g"):n=new RegExp(`(?:-)?(?:${D()})?${a}(?:${D()})?(?:٪|%)`,"g"),n.test(t)}#a(e){return this.#e(this.defaultLocale(),e)}}class mt extends P{constructor(){super("string")}buildConfig(){const e=c.getOptions();this.addToConfig("mockChars",e?.qaMock),this.addToConfig("resource",c.getResourceBundle(),{}),this.addToConfig("garbledChars",c.getGarbledChars()?.filter(t=>String(t).trim()).filter(Boolean),[])}isInternationalized(e){const t=e.trim().replace(/\s*:\s*$/,""),a=this.getConfig()?.resource?.[this.defaultLocale()];return a?.includes(e)||a?.includes(t)}validate(e){return typeof e=="string"}isDntText(e){return this.getConfig()?.resource?.dnt?.includes(e)}isAutoIgnoredText(e){return this.isDefaultLocale()||this.isUserInputText(e)||this.isEmailText(e)||this.isUrlText(e)}isIgnoredText(e){return this.getConfig()?.resource?.ignore?.includes(e)}isUserInputText(e){return e.startsWith(Se)}isEmailText(e){return ue.EMAIL.test(e)}isUrlText(e){return ue.URL.test(e)}isFullQaLanguageText(e){const t=this.getConfig();return(e.slice(0,2)===t?.mockChars?.prefix||e.slice(0,2)===t?.mockChars?.prefix.toUpperCase())&&e.slice(-2)===t?.mockChars.suffix}isPartialQaLanguageText(e){const t=this.getConfig();return e.slice(0,2)===t?.mockChars.prefix||e.slice(0,2)===t?.mockChars.prefix.toUpperCase()||e.slice(-2)===t?.mockChars.suffix}hasEncodingIssue(e){return this.getConfig()?.garbledChars?.length>0&&this.getConfig().garbledChars.some(t=>e.includes(t))}isPartiallyLocalizedText(e){return this.#e(e)===this.currentLanguage()}#e(e){const t=Object.keys(Ie.detectTextLangEx(e)?.scores||{}).filter(Boolean)||[],a=this.currentLanguage();return t.length?t.includes(a)?a:t[0]:this.defaultLanguage()}isLocalized(e){const t=e.trim().replace(/\s*:\s*$/,""),a=this.getConfig()?.resource?.[this.currentLocale()];return a?.includes(e)||a?.includes(t)}}class pt extends P{constructor(){super("time")}validate(e){return this.#t(e)||this.isInternationalized(e)}isInternationalized(e){return this.#e(this.isQaLocale()?this.defaultLocale():this.currentLocale(),e)}buildConfig(){}#e(e,t){return this.#r(e,t)||this.#a(e,t)||this.#i(e,t)}#t(e){return this.#e(this.defaultLocale(),e)}#r(e,t){const a=["short","medium","long","full"];for(let n of a)if(this.getGlobalize(e).dateParser({time:n})(t))return!0;return!1}#a(e,t){const a=[E.DateTime.TIME_SIMPLE,E.DateTime.TIME_WITH_SECONDS,E.DateTime.TIME_WITH_SHORT_OFFSET,E.DateTime.TIME_WITH_LONG_OFFSET,E.DateTime.TIME_24_SIMPLE,E.DateTime.TIME_24_WITH_LONG_OFFSET,E.DateTime.TIME_24_WITH_SECONDS,E.DateTime.TIME_24_WITH_SHORT_OFFSET,"t","T","tt","TT"];for(let n of a)if(se(e,n,t))return!0;return!1}#i(e,t){return ne(this.isQaLocale()?this.defaultLocale():e,t)}}class y{static#e={};static#t;static#r;static#a;static#i;static#n;static#s;static#o;static load(){y.#t=new mt,y.#r=new dt,y.#a=new lt,y.#i=new pt,y.#n=new ct,y.#s=new st,y.#o=new ut}static getIssueType(e){const t=c.getLocale();if(t){let a=r.UNTRANSLATED;return y.#e[t]||(y.#e[t]={}),y.#e[t][e]?y.#e[t][e]:(this.#t.isAutoIgnoredText(e)?a=r.AUTO_IGNORE:this.#t.isDntText(e)?a=r.DNT:this.#t.isIgnoredText(e)?a=r.IGNORE:this.#t.hasEncodingIssue(e)?a=r.ENCODING_ISSUE:this.#s.validate(e)?a=this.#s.isInternationalized(e)?r.CURRENCY_LOCALIZED:r.CURRENCY_NOT_LOCALIZED:this.#o.validate(e)?a=this.#o.isInternationalized(e)?r.PERCENTAGE_LOCALIZED:r.PERCENTAGE_NOT_LOCALIZED:this.#r.validate(e)?a=this.#r.isInternationalized(e)?r.NUMBER_LOCALIZED:r.NUMBER_NOT_LOCALIZED:this.#a.validate(e)?a=this.#a.isInternationalized(e)?r.DATE_LOCALIZED:r.DATE_NOT_LOCALIZED:this.#i.validate(e)?a=this.#i.isInternationalized(e)?r.TIME_LOCALIZED:r.TIME_NOT_LOCALIZED:this.#n.validate(e)?a=this.#n.isInternationalized(e)?r.DATE_TIME_LOCALIZED:r.DATE_TIME_NOT_LOCALIZED:this.#t.validate(e)?this.#t.isQaLocale()?this.#t.isFullQaLanguageText(e)?a=r.STRING_LOCALIZED:this.#t.isPartialQaLanguageText(e)?a=r.STRING_PARTIALLY_LOCALIZED:a=r.STRING_NOT_LOCALIZED:!this.#t.isDefaultLocale()&&this.#t.isSupportedLocale()&&(this.#t.isLocalized(e)?a=r.STRING_LOCALIZED:this.#t.isPartiallyLocalizedText(e)?a=r.STRING_PARTIALLY_LOCALIZED:this.#t.isInternationalized(e)?a=r.UNTRANSLATED:a=r.STRING_NOT_LOCALIZED):this.#t.isDefaultLocale()&&(a=r.AUTO_IGNORE),y.#e[t][e]=a,a)}return r.UNTRANSLATED}}class Y{static load(){const e={};if(c.getOptions()?.l10nResourcePath){const t=g(process.cwd(),c.getOptions()?.l10nResourcePath);if(x(t))Y.#e(t,e);else if(te(t))for(const a of ae(t)){const n=g(t,a);Y.#e(n,e)}else{console.error(`${t} invalid resource path`);return}c.setResourceBundle(e)}}static#e(e,t){const a=c.getLocale(),n=c.getDefaultLocale(),s=M(e),o=xe(e);if(De.includes(o)){if(!s){console.error(`${e} is empty or invalid`);return}if(e.toLowerCase().includes("dnt"))t.dnt=s.split(/\r?\n/);else if(e.toLowerCase().includes("ignore"))t.ignore=s.split(/\r?\n/);else if(e.includes(a)){const u=s.split(/\r?\n/);t[a]=u.map(gt)}else e.includes(n)&&(t[n]=s.split(/\r?\n/))}}}function gt(i){const e=/<\/?[^>]+>/gi;return i.replace(e,"")}const ht=()=>{c.getDriver()&&!c.isLoaded()&&c.getLocale()&&(c.build(),Y.load(),y.load(),l.setup(),S.init(),c.setIsLoaded(!0))},ve=()=>{let e=process.cwd(),t=0;for(;t<10;){const a=g(e,"package.json");if(x(a)){const n=M(a),s=JSON.parse(n),o={...s?.dependencies||{},...s?.devDependencies||{},...s?.peerDependencies||{}};if(s.name!=="@zeesoft/i18n-verify"&&JSON.stringify(o).includes('"@zeesoft/i18n-verify"'))break}e=Oe(e),t++}return e},we=(i=ve())=>M(g(i,"package.json")),Et=()=>we()?.match(/"name": "([^"]+)",/)?.[1]||"",ft=()=>g(process.cwd(),C),vt=(i="")=>`{
|
|
3599
|
-
"
|
|
3600
|
-
|
|
4020
|
+
})();`;
|
|
4021
|
+
const getJsData = (metaData) => `${global()}
|
|
4022
|
+
${data(metaData)}
|
|
4023
|
+
${menuBar()}
|
|
4024
|
+
${overview()}
|
|
4025
|
+
${insight()}
|
|
4026
|
+
${localeGrid()}
|
|
4027
|
+
${log()}`;
|
|
4028
|
+
class HtmlReport extends BaseReport {
|
|
4029
|
+
constructor() {
|
|
4030
|
+
super(SUPPORTED_REPORT_TYPES.HTML);
|
|
4031
|
+
}
|
|
4032
|
+
buildContent() {
|
|
4033
|
+
const metaInfo = this.getMetaInfo(), script = getJsData(metaInfo), style = getCssData(), body = getBodyData(), dataFilePaths = [], logDataFilePath = joinPaths(Reports.getReportPath(), "logs", "log"), captureAll = Config.isSanityRun() || Config.isContextRun(), expectedLocaleDirs = [
|
|
4034
|
+
Config.getQALocale(),
|
|
4035
|
+
...Config.getOptions()?.supportedLocales || []
|
|
4036
|
+
].filter(Boolean).map((v) => toFileNameFormat(v)), localeDirs = getDirContents(Reports.getReportPath()).filter(
|
|
4037
|
+
(v) => expectedLocaleDirs.includes(v)
|
|
4038
|
+
), includeDefaultLocaleDir = localeDirs.length === 1 && localeDirs[0] === toFileNameFormat(Config.getDefaultLocale());
|
|
4039
|
+
let logData = "";
|
|
4040
|
+
localeDirs.forEach(
|
|
4041
|
+
(file) => (captureAll || file !== metaInfo.defaultLocale || file === metaInfo.defaultLocale && includeDefaultLocaleDir) && fileExists(joinPaths(Reports.getReportPath(), file, CACHE_FILE_NAME)) && dataFilePaths.push(joinPaths(file, CACHE_FILE_NAME).replace(/\\/g, "/"))
|
|
4042
|
+
);
|
|
4043
|
+
if (fileExists(logDataFilePath)) {
|
|
4044
|
+
const paths = [
|
|
4045
|
+
metaInfo.appName,
|
|
4046
|
+
...Config.getL10nReportsPath().split(/[\\/]+/g),
|
|
4047
|
+
Config.getMode()
|
|
4048
|
+
];
|
|
4049
|
+
paths.push(Reports.getReportTimeStamp());
|
|
4050
|
+
logData = getFileContent(logDataFilePath).replace(
|
|
4051
|
+
new RegExp(Reports.getReportPath().replace(/\\/g, "\\\\"), "g"),
|
|
4052
|
+
joinPaths(...paths)
|
|
4053
|
+
).replace(/\\/g, "\\\\").replace(/`/g, "\\`");
|
|
4054
|
+
}
|
|
4055
|
+
return renderHtml({
|
|
4056
|
+
appName: metaInfo.appName,
|
|
4057
|
+
reportTime: metaInfo.reportTime,
|
|
4058
|
+
body,
|
|
4059
|
+
script,
|
|
4060
|
+
style,
|
|
4061
|
+
dataFilePaths,
|
|
4062
|
+
logData
|
|
4063
|
+
});
|
|
4064
|
+
}
|
|
4065
|
+
write(path2, name, data2) {
|
|
4066
|
+
saveToFile(joinPaths(path2, `${name}.html`), data2, "utf-8");
|
|
4067
|
+
}
|
|
4068
|
+
}
|
|
4069
|
+
class TableReport extends BaseReport {
|
|
4070
|
+
/**
|
|
4071
|
+
* @type {Table}
|
|
4072
|
+
*/
|
|
4073
|
+
#printer;
|
|
4074
|
+
/**
|
|
4075
|
+
* @type {Boolean}
|
|
4076
|
+
*/
|
|
4077
|
+
#hasData = false;
|
|
4078
|
+
static #column1 = "STATUS";
|
|
4079
|
+
static #column2 = "COUNTS";
|
|
4080
|
+
constructor() {
|
|
4081
|
+
super(SUPPORTED_REPORT_TYPES.ASCII_TABLE);
|
|
4082
|
+
this.#preparePrinter();
|
|
4083
|
+
}
|
|
4084
|
+
#preparePrinter() {
|
|
4085
|
+
this.#printer = new Table({
|
|
4086
|
+
style: {
|
|
4087
|
+
headerTop: {
|
|
4088
|
+
left: "\x1B[94m╔\x1B[0m",
|
|
4089
|
+
mid: "\x1B[94m╦\x1B[0m",
|
|
4090
|
+
right: "\x1B[94m╗\x1B[0m",
|
|
4091
|
+
other: "\x1B[94m═"
|
|
4092
|
+
},
|
|
4093
|
+
headerBottom: {
|
|
4094
|
+
left: "\x1B[94m╟\x1B[0m",
|
|
4095
|
+
mid: "\x1B[94m╬\x1B[0m",
|
|
4096
|
+
right: "\x1B[94m╢\x1B[0m",
|
|
4097
|
+
other: "\x1B[94m═"
|
|
4098
|
+
},
|
|
4099
|
+
tableBottom: {
|
|
4100
|
+
left: "\x1B[94m╚\x1B[0m",
|
|
4101
|
+
mid: "\x1B[94m╩\x1B[0m",
|
|
4102
|
+
right: "\x1B[94m╝\x1B[0m",
|
|
4103
|
+
other: "\x1B[94m═\x1B[0m"
|
|
4104
|
+
},
|
|
4105
|
+
vertical: "\x1B[94m║\x1B[0m"
|
|
4106
|
+
},
|
|
4107
|
+
columns: [
|
|
4108
|
+
{ name: TableReport.#column1, alignment: "left" },
|
|
4109
|
+
{ name: TableReport.#column2, alignment: "center" }
|
|
4110
|
+
]
|
|
4111
|
+
});
|
|
4112
|
+
}
|
|
4113
|
+
/**
|
|
4114
|
+
* @override
|
|
4115
|
+
*/
|
|
4116
|
+
buildContent() {
|
|
4117
|
+
if (REPORT_COUNTS[I18N_STATUS.REVIEWED] > 0) {
|
|
4118
|
+
this.#hasData = true;
|
|
4119
|
+
for (const key in REPORT_COUNTS) {
|
|
4120
|
+
if (key !== I18N_STATUS.REVIEWED) {
|
|
4121
|
+
if (REPORT_COUNTS.hasOwnProperty(key)) {
|
|
4122
|
+
this.#printer.addRows([
|
|
4123
|
+
{ STATUS: key, COUNTS: `${REPORT_COUNTS[key]}` }
|
|
4124
|
+
]);
|
|
4125
|
+
}
|
|
4126
|
+
} else {
|
|
4127
|
+
this.#printer.addRows([
|
|
4128
|
+
{
|
|
4129
|
+
STATUS: "\x1B[94m" + "═".repeat(28) + "\x1B[0m",
|
|
4130
|
+
COUNTS: "\x1B[94m" + "═".repeat(8) + "\x1B[0m"
|
|
4131
|
+
}
|
|
4132
|
+
]);
|
|
4133
|
+
this.#printer.addRows([
|
|
4134
|
+
{ STATUS: "OVERALL_REVIEWED", COUNTS: `${REPORT_COUNTS[key]}` }
|
|
4135
|
+
]);
|
|
4136
|
+
}
|
|
4137
|
+
}
|
|
4138
|
+
}
|
|
4139
|
+
}
|
|
4140
|
+
/**
|
|
4141
|
+
* @override
|
|
4142
|
+
*/
|
|
4143
|
+
export() {
|
|
4144
|
+
this.#hasData ? this.#printer.printTable() : Logger$1.info("There are no visbile elements with UI strings");
|
|
4145
|
+
}
|
|
4146
|
+
}
|
|
4147
|
+
class ReportFactory {
|
|
4148
|
+
static #build(type) {
|
|
4149
|
+
switch (type) {
|
|
4150
|
+
case SUPPORTED_REPORT_TYPES.HTML:
|
|
4151
|
+
return new HtmlReport();
|
|
4152
|
+
case SUPPORTED_REPORT_TYPES.ASCII_TABLE:
|
|
4153
|
+
return new TableReport();
|
|
4154
|
+
default:
|
|
4155
|
+
throw new Error("unsupported report type requested");
|
|
4156
|
+
}
|
|
4157
|
+
}
|
|
4158
|
+
static export(type, path2, name) {
|
|
4159
|
+
const builder = ReportFactory.#build(type);
|
|
4160
|
+
const reportData = new ReportData({
|
|
4161
|
+
appName: Config.getAppName(),
|
|
4162
|
+
reportTime: (/* @__PURE__ */ new Date()).toLocaleString(),
|
|
4163
|
+
isContext: Config.isContextRun(),
|
|
4164
|
+
isSanity: Config.isSanityRun(),
|
|
4165
|
+
defaultLocale: Config.getDefaultLocale(),
|
|
4166
|
+
reportFolderTimestamp: Reports.getReportTimeStamp()
|
|
4167
|
+
});
|
|
4168
|
+
builder.generate(reportData);
|
|
4169
|
+
builder.export(path2, name);
|
|
4170
|
+
}
|
|
4171
|
+
}
|
|
4172
|
+
class Cache {
|
|
4173
|
+
/** @type {String} */
|
|
4174
|
+
static #cachePath;
|
|
4175
|
+
static #cacheDirPath;
|
|
4176
|
+
static init() {
|
|
4177
|
+
Cache.#cacheDirPath = joinPaths(
|
|
4178
|
+
Reports.getReportPath(),
|
|
4179
|
+
toFileNameFormat(Config.getLocale())
|
|
4180
|
+
);
|
|
4181
|
+
Cache.#cachePath = joinPaths(Cache.#cacheDirPath, CACHE_FILE_NAME);
|
|
4182
|
+
this.#ensureFileExists();
|
|
4183
|
+
}
|
|
4184
|
+
static exists() {
|
|
4185
|
+
return fileExists(Cache.#cachePath);
|
|
4186
|
+
}
|
|
4187
|
+
static save(data2) {
|
|
4188
|
+
this.#ensureFileExists();
|
|
4189
|
+
const source = `!window.rawData && (window.rawData={'${Config.getLocale()}':{}});window.rawData['${Config.getLocale()}']=${JSON.stringify(
|
|
4190
|
+
data2
|
|
4191
|
+
)};`;
|
|
4192
|
+
saveToFile(Cache.#cachePath, source);
|
|
4193
|
+
}
|
|
4194
|
+
static getData() {
|
|
4195
|
+
if (!this.exists()) {
|
|
4196
|
+
return {};
|
|
4197
|
+
} else {
|
|
4198
|
+
try {
|
|
4199
|
+
return JSON.parse(
|
|
4200
|
+
getFileContent(Cache.#cachePath).replace(
|
|
4201
|
+
new RegExp(
|
|
4202
|
+
`(\\!window.rawData && \\(window\\.rawData=\\{'${Config.getLocale()}':\\{\\}\\}\\);window\\.rawData\\['${Config.getLocale()}'\\]=)|(;$)`,
|
|
4203
|
+
"g"
|
|
4204
|
+
),
|
|
4205
|
+
""
|
|
4206
|
+
)
|
|
4207
|
+
);
|
|
4208
|
+
} catch (ex) {
|
|
4209
|
+
return {};
|
|
4210
|
+
}
|
|
4211
|
+
}
|
|
4212
|
+
}
|
|
4213
|
+
static #ensureFileExists() {
|
|
4214
|
+
ensureDirectoryExists(Cache.#cacheDirPath);
|
|
4215
|
+
}
|
|
4216
|
+
static getCacheDirPath() {
|
|
4217
|
+
return Cache.#cacheDirPath;
|
|
4218
|
+
}
|
|
4219
|
+
}
|
|
4220
|
+
class StatData {
|
|
4221
|
+
/**
|
|
4222
|
+
* @type {Number}
|
|
4223
|
+
*/
|
|
4224
|
+
#localizedStrings;
|
|
4225
|
+
/**
|
|
4226
|
+
* @type {Number}
|
|
4227
|
+
*/
|
|
4228
|
+
#notLocalizedStrings;
|
|
4229
|
+
/**
|
|
4230
|
+
* @type {Number}
|
|
4231
|
+
*/
|
|
4232
|
+
#untranslatedStrings;
|
|
4233
|
+
/**
|
|
4234
|
+
* @type {Number}
|
|
4235
|
+
*/
|
|
4236
|
+
#partialStrings;
|
|
4237
|
+
/**
|
|
4238
|
+
* @type {Number}
|
|
4239
|
+
*/
|
|
4240
|
+
#localizedDateTime;
|
|
4241
|
+
/**
|
|
4242
|
+
* @type {Number}
|
|
4243
|
+
*/
|
|
4244
|
+
#localizedDate;
|
|
4245
|
+
/**
|
|
4246
|
+
* @type {Number}
|
|
4247
|
+
*/
|
|
4248
|
+
#localizedTime;
|
|
4249
|
+
/**
|
|
4250
|
+
* @type {Number}
|
|
4251
|
+
*/
|
|
4252
|
+
#notLocalizedDateTime;
|
|
4253
|
+
/**
|
|
4254
|
+
* @type {Number}
|
|
4255
|
+
*/
|
|
4256
|
+
#notLocalizedDate;
|
|
4257
|
+
/**
|
|
4258
|
+
* @type {Number}
|
|
4259
|
+
*/
|
|
4260
|
+
#notLocalizedTime;
|
|
4261
|
+
/**
|
|
4262
|
+
* @type {Number}
|
|
4263
|
+
*/
|
|
4264
|
+
#localizedNumber;
|
|
4265
|
+
/**
|
|
4266
|
+
* @type {Number}
|
|
4267
|
+
*/
|
|
4268
|
+
#notLocalizedNumber;
|
|
4269
|
+
/**
|
|
4270
|
+
* @type {Number}
|
|
4271
|
+
*/
|
|
4272
|
+
#localizedCurrency;
|
|
4273
|
+
/**
|
|
4274
|
+
* @type {Number}
|
|
4275
|
+
*/
|
|
4276
|
+
#notLocalizedCurrency;
|
|
4277
|
+
/**
|
|
4278
|
+
* @type {Number}
|
|
4279
|
+
*/
|
|
4280
|
+
#localizedPercentage;
|
|
4281
|
+
/**
|
|
4282
|
+
* @type {Number}
|
|
4283
|
+
*/
|
|
4284
|
+
#notLocalizedPercentage;
|
|
4285
|
+
/**
|
|
4286
|
+
* @type {Number}
|
|
4287
|
+
*/
|
|
4288
|
+
#ignored;
|
|
4289
|
+
/**
|
|
4290
|
+
* @type {Number}
|
|
4291
|
+
*/
|
|
4292
|
+
#dnt;
|
|
4293
|
+
/**
|
|
4294
|
+
* @type {Number}
|
|
4295
|
+
*/
|
|
4296
|
+
#autoIgnored;
|
|
4297
|
+
/**
|
|
4298
|
+
* @type {Number}
|
|
4299
|
+
*/
|
|
4300
|
+
#userInput;
|
|
4301
|
+
/**
|
|
4302
|
+
* @type {Number}
|
|
4303
|
+
*/
|
|
4304
|
+
#encoding;
|
|
4305
|
+
/**
|
|
4306
|
+
* @type {Number}
|
|
4307
|
+
*/
|
|
4308
|
+
#truncation;
|
|
4309
|
+
/**
|
|
4310
|
+
* @type {Number}
|
|
4311
|
+
*/
|
|
4312
|
+
#overlapping;
|
|
4313
|
+
/**
|
|
4314
|
+
* @type {Number}
|
|
4315
|
+
*/
|
|
4316
|
+
#reviewed;
|
|
4317
|
+
/**
|
|
4318
|
+
* @type {Number}
|
|
4319
|
+
*/
|
|
4320
|
+
#context;
|
|
4321
|
+
constructor(data2 = {}) {
|
|
4322
|
+
this.#localizedStrings = data2?.localizedStrings || 0;
|
|
4323
|
+
this.#notLocalizedStrings = data2?.notLocalizedStrings || 0;
|
|
4324
|
+
this.#untranslatedStrings = data2?.untranslatedStrings || 0;
|
|
4325
|
+
this.#partialStrings = data2?.partialStrings || 0;
|
|
4326
|
+
this.#localizedDateTime = data2?.localizedDateTime || 0;
|
|
4327
|
+
this.#localizedDate = data2?.localizedDate || 0;
|
|
4328
|
+
this.#localizedTime = data2?.localizedTime || 0;
|
|
4329
|
+
this.#notLocalizedDateTime = data2?.notLocalizedDateTime || 0;
|
|
4330
|
+
this.#notLocalizedDate = data2?.notLocalizedDate || 0;
|
|
4331
|
+
this.#notLocalizedTime = data2?.notLocalizedTime || 0;
|
|
4332
|
+
this.#localizedNumber = data2?.localizedNumber || 0;
|
|
4333
|
+
this.#notLocalizedNumber = data2?.notLocalizedNumber || 0;
|
|
4334
|
+
this.#localizedCurrency = data2?.localizedCurrency || 0;
|
|
4335
|
+
this.#notLocalizedCurrency = data2?.notLocalizedCurrency || 0;
|
|
4336
|
+
this.#localizedPercentage = data2?.localizedPercentage || 0;
|
|
4337
|
+
this.#notLocalizedPercentage = data2?.notLocalizedPercentage || 0;
|
|
4338
|
+
this.#ignored = data2?.ignored || 0;
|
|
4339
|
+
this.#dnt = data2?.dnt || 0;
|
|
4340
|
+
this.#autoIgnored = data2?.autoIgnored || 0;
|
|
4341
|
+
this.#userInput = data2?.userInput || 0;
|
|
4342
|
+
this.#encoding = data2?.encoding || 0;
|
|
4343
|
+
this.#truncation = data2?.truncation || 0;
|
|
4344
|
+
this.#overlapping = data2?.overlapping || 0;
|
|
4345
|
+
this.#reviewed = data2?.reviewed || 0;
|
|
4346
|
+
this.#context = data2?.context || 0;
|
|
4347
|
+
}
|
|
4348
|
+
getLocalizedStrings() {
|
|
4349
|
+
return this.#localizedStrings;
|
|
4350
|
+
}
|
|
4351
|
+
setLocalizedStrings(translatedStrings) {
|
|
4352
|
+
this.#localizedStrings = translatedStrings;
|
|
4353
|
+
}
|
|
4354
|
+
getUntranslatedStrings() {
|
|
4355
|
+
return this.#untranslatedStrings;
|
|
4356
|
+
}
|
|
4357
|
+
setUntranslatedStrings(untranslatedStrings) {
|
|
4358
|
+
this.#untranslatedStrings = untranslatedStrings;
|
|
4359
|
+
}
|
|
4360
|
+
getNotLocalizedStrings() {
|
|
4361
|
+
return this.#notLocalizedStrings;
|
|
4362
|
+
}
|
|
4363
|
+
setNotLocalizedStrings(notLocalizedStrings) {
|
|
4364
|
+
this.#notLocalizedStrings = notLocalizedStrings;
|
|
4365
|
+
}
|
|
4366
|
+
getPartialStrings() {
|
|
4367
|
+
return this.#partialStrings;
|
|
4368
|
+
}
|
|
4369
|
+
setPartialStrings(partialStrings) {
|
|
4370
|
+
this.#partialStrings = partialStrings;
|
|
4371
|
+
}
|
|
4372
|
+
getLocalizedDateTime() {
|
|
4373
|
+
return this.#localizedDateTime;
|
|
4374
|
+
}
|
|
4375
|
+
setLocalizedDateTime(localizedDateTime) {
|
|
4376
|
+
this.#localizedDateTime = localizedDateTime;
|
|
4377
|
+
}
|
|
4378
|
+
getLocalizedDate() {
|
|
4379
|
+
return this.#localizedDate;
|
|
4380
|
+
}
|
|
4381
|
+
setLocalizedDate(localizedDate) {
|
|
4382
|
+
this.#localizedDate = localizedDate;
|
|
4383
|
+
}
|
|
4384
|
+
getLocalizedTime() {
|
|
4385
|
+
return this.#localizedTime;
|
|
4386
|
+
}
|
|
4387
|
+
setLocalizedTime(localizedTime) {
|
|
4388
|
+
this.#localizedTime = localizedTime;
|
|
4389
|
+
}
|
|
4390
|
+
getNotLocalizedDateTime() {
|
|
4391
|
+
return this.#notLocalizedDateTime;
|
|
4392
|
+
}
|
|
4393
|
+
setNotLocalizedDateTime(notLocalizedDateTime) {
|
|
4394
|
+
this.#notLocalizedDateTime = notLocalizedDateTime;
|
|
4395
|
+
}
|
|
4396
|
+
getNotLocalizedDate() {
|
|
4397
|
+
return this.#notLocalizedDate;
|
|
4398
|
+
}
|
|
4399
|
+
setNotLocalizedDate(notLocalizedDate) {
|
|
4400
|
+
this.#notLocalizedDate = notLocalizedDate;
|
|
4401
|
+
}
|
|
4402
|
+
getNotLocalizedTime() {
|
|
4403
|
+
return this.#notLocalizedTime;
|
|
4404
|
+
}
|
|
4405
|
+
setNotLocalizedTime(notLocalizedTime) {
|
|
4406
|
+
this.#notLocalizedTime = notLocalizedTime;
|
|
4407
|
+
}
|
|
4408
|
+
getLocalizedNumber() {
|
|
4409
|
+
return this.#localizedNumber;
|
|
4410
|
+
}
|
|
4411
|
+
setLocalizedNumber(localizedNumber) {
|
|
4412
|
+
this.#localizedNumber = localizedNumber;
|
|
4413
|
+
}
|
|
4414
|
+
getNotLocalizeNumber() {
|
|
4415
|
+
return this.#notLocalizedNumber;
|
|
4416
|
+
}
|
|
4417
|
+
setNotLocalizeNumber(notLocalizedNumber) {
|
|
4418
|
+
this.#notLocalizedNumber = notLocalizedNumber;
|
|
4419
|
+
}
|
|
4420
|
+
getCurrency() {
|
|
4421
|
+
return this.#localizedCurrency;
|
|
4422
|
+
}
|
|
4423
|
+
setCurrency(currency) {
|
|
4424
|
+
this.#localizedCurrency = currency;
|
|
4425
|
+
}
|
|
4426
|
+
getNotLocalizeCurrency() {
|
|
4427
|
+
return this.#notLocalizedCurrency;
|
|
4428
|
+
}
|
|
4429
|
+
setNotLocalizeCurrency(notLocalizedCurrency) {
|
|
4430
|
+
this.#notLocalizedCurrency = notLocalizedCurrency;
|
|
4431
|
+
}
|
|
4432
|
+
getPercentage() {
|
|
4433
|
+
return this.#localizedPercentage;
|
|
4434
|
+
}
|
|
4435
|
+
setPercentage(percentage) {
|
|
4436
|
+
this.#localizedPercentage = percentage;
|
|
4437
|
+
}
|
|
4438
|
+
getNotLocalizePercentage() {
|
|
4439
|
+
return this.#notLocalizedPercentage;
|
|
4440
|
+
}
|
|
4441
|
+
setNotLocalizePercentage(notLocalizedPercentage) {
|
|
4442
|
+
this.#notLocalizedPercentage = notLocalizedPercentage;
|
|
4443
|
+
}
|
|
4444
|
+
getIgnored() {
|
|
4445
|
+
return this.#ignored;
|
|
4446
|
+
}
|
|
4447
|
+
setIgnored(ignored) {
|
|
4448
|
+
this.#ignored = ignored;
|
|
4449
|
+
}
|
|
4450
|
+
getUserInput() {
|
|
4451
|
+
return this.#userInput;
|
|
4452
|
+
}
|
|
4453
|
+
setUserInput(userInput) {
|
|
4454
|
+
this.#userInput = userInput;
|
|
4455
|
+
}
|
|
4456
|
+
getDnt() {
|
|
4457
|
+
return this.#dnt;
|
|
4458
|
+
}
|
|
4459
|
+
setDnt(dnt) {
|
|
4460
|
+
this.#dnt = dnt;
|
|
4461
|
+
}
|
|
4462
|
+
getAutoIgnored() {
|
|
4463
|
+
return this.#autoIgnored;
|
|
4464
|
+
}
|
|
4465
|
+
setAutoIgnored(autoIgnored) {
|
|
4466
|
+
this.#autoIgnored = autoIgnored;
|
|
4467
|
+
}
|
|
4468
|
+
getEncoding() {
|
|
4469
|
+
return this.#encoding;
|
|
4470
|
+
}
|
|
4471
|
+
setEncoding(encoding) {
|
|
4472
|
+
this.#encoding = encoding;
|
|
4473
|
+
}
|
|
4474
|
+
getTruncation() {
|
|
4475
|
+
return this.#truncation;
|
|
4476
|
+
}
|
|
4477
|
+
setTruncation(truncation) {
|
|
4478
|
+
this.#truncation = truncation;
|
|
4479
|
+
}
|
|
4480
|
+
getOverlapping() {
|
|
4481
|
+
return this.#overlapping;
|
|
4482
|
+
}
|
|
4483
|
+
setOverlapping(overlapping) {
|
|
4484
|
+
this.#overlapping = overlapping;
|
|
4485
|
+
}
|
|
4486
|
+
getReviewed() {
|
|
4487
|
+
return this.#reviewed;
|
|
4488
|
+
}
|
|
4489
|
+
setReviewed(reviewed) {
|
|
4490
|
+
this.#reviewed = reviewed;
|
|
4491
|
+
}
|
|
4492
|
+
getContext() {
|
|
4493
|
+
return this.#context;
|
|
4494
|
+
}
|
|
4495
|
+
setContext(context) {
|
|
4496
|
+
this.#context = context;
|
|
4497
|
+
}
|
|
4498
|
+
incrementByType(type) {
|
|
4499
|
+
switch (type) {
|
|
4500
|
+
case I18N_STATUS.STRING_LOCALIZED:
|
|
4501
|
+
++this.#localizedStrings;
|
|
4502
|
+
break;
|
|
4503
|
+
case I18N_STATUS.STRING_NOT_LOCALIZED:
|
|
4504
|
+
++this.#notLocalizedStrings;
|
|
4505
|
+
break;
|
|
4506
|
+
case I18N_STATUS.UNTRANSLATED:
|
|
4507
|
+
++this.#untranslatedStrings;
|
|
4508
|
+
break;
|
|
4509
|
+
case I18N_STATUS.STRING_PARTIALLY_LOCALIZED:
|
|
4510
|
+
++this.#partialStrings;
|
|
4511
|
+
break;
|
|
4512
|
+
case I18N_STATUS.AUTO_IGNORE:
|
|
4513
|
+
++this.#autoIgnored;
|
|
4514
|
+
break;
|
|
4515
|
+
case I18N_STATUS.IGNORE:
|
|
4516
|
+
++this.#ignored;
|
|
4517
|
+
break;
|
|
4518
|
+
case I18N_STATUS.DNT:
|
|
4519
|
+
++this.#dnt;
|
|
4520
|
+
break;
|
|
4521
|
+
case I18N_STATUS.ENCODING_ISSUE:
|
|
4522
|
+
++this.#encoding;
|
|
4523
|
+
break;
|
|
4524
|
+
case I18N_STATUS.DATE_LOCALIZED:
|
|
4525
|
+
++this.#localizedDate;
|
|
4526
|
+
break;
|
|
4527
|
+
case I18N_STATUS.TIME_LOCALIZED:
|
|
4528
|
+
++this.#localizedTime;
|
|
4529
|
+
break;
|
|
4530
|
+
case I18N_STATUS.DATE_TIME_LOCALIZED:
|
|
4531
|
+
++this.#localizedDateTime;
|
|
4532
|
+
break;
|
|
4533
|
+
case I18N_STATUS.DATE_NOT_LOCALIZED:
|
|
4534
|
+
++this.#notLocalizedDate;
|
|
4535
|
+
break;
|
|
4536
|
+
case I18N_STATUS.TIME_NOT_LOCALIZED:
|
|
4537
|
+
++this.#notLocalizedTime;
|
|
4538
|
+
break;
|
|
4539
|
+
case I18N_STATUS.DATE_TIME_NOT_LOCALIZED:
|
|
4540
|
+
++this.#notLocalizedDateTime;
|
|
4541
|
+
break;
|
|
4542
|
+
case I18N_STATUS.NUMBER_LOCALIZED:
|
|
4543
|
+
++this.#localizedNumber;
|
|
4544
|
+
break;
|
|
4545
|
+
case I18N_STATUS.NUMBER_NOT_LOCALIZED:
|
|
4546
|
+
++this.#notLocalizedNumber;
|
|
4547
|
+
break;
|
|
4548
|
+
case I18N_STATUS.CURRENCY_LOCALIZED:
|
|
4549
|
+
++this.#localizedCurrency;
|
|
4550
|
+
break;
|
|
4551
|
+
case I18N_STATUS.CURRENCY_NOT_LOCALIZED:
|
|
4552
|
+
++this.#notLocalizedCurrency;
|
|
4553
|
+
break;
|
|
4554
|
+
case I18N_STATUS.PERCENTAGE_LOCALIZED:
|
|
4555
|
+
++this.#localizedPercentage;
|
|
4556
|
+
break;
|
|
4557
|
+
case I18N_STATUS.PERCENTAGE_NOT_LOCALIZED:
|
|
4558
|
+
++this.#notLocalizedPercentage;
|
|
4559
|
+
break;
|
|
4560
|
+
case I18N_STATUS.TRUNCATION_ISSUE:
|
|
4561
|
+
++this.#truncation;
|
|
4562
|
+
break;
|
|
4563
|
+
case I18N_STATUS.OVERLAPPING_ISSUE:
|
|
4564
|
+
++this.#overlapping;
|
|
4565
|
+
break;
|
|
4566
|
+
case I18N_STATUS.REVIEWED:
|
|
4567
|
+
++this.#reviewed;
|
|
4568
|
+
break;
|
|
4569
|
+
case I18N_STATUS.USER_INPUT:
|
|
4570
|
+
++this.#userInput;
|
|
4571
|
+
break;
|
|
4572
|
+
case "context":
|
|
4573
|
+
++this.#context;
|
|
4574
|
+
break;
|
|
4575
|
+
}
|
|
4576
|
+
}
|
|
4577
|
+
toJSON() {
|
|
4578
|
+
return {
|
|
4579
|
+
localizedStrings: this.#localizedStrings,
|
|
4580
|
+
notLocalizedStrings: this.#notLocalizedStrings,
|
|
4581
|
+
untranslatedStrings: this.#untranslatedStrings,
|
|
4582
|
+
partialStrings: this.#partialStrings,
|
|
4583
|
+
localizedDateTime: this.#localizedDateTime,
|
|
4584
|
+
localizedDate: this.#localizedDate,
|
|
4585
|
+
localizedTime: this.#localizedTime,
|
|
4586
|
+
notLocalizedDateTime: this.#notLocalizedDateTime,
|
|
4587
|
+
notLocalizedDate: this.#notLocalizedDate,
|
|
4588
|
+
notLocalizedTime: this.#notLocalizedTime,
|
|
4589
|
+
localizedNumber: this.#localizedNumber,
|
|
4590
|
+
notLocalizedNumber: this.#notLocalizedNumber,
|
|
4591
|
+
localizedCurrency: this.#localizedCurrency,
|
|
4592
|
+
notLocalizedCurrency: this.#notLocalizedCurrency,
|
|
4593
|
+
localizedPercentage: this.#localizedPercentage,
|
|
4594
|
+
notLocalizedPercentage: this.#notLocalizedPercentage,
|
|
4595
|
+
ignored: this.#ignored,
|
|
4596
|
+
dnt: this.#dnt,
|
|
4597
|
+
autoIgnored: this.#autoIgnored,
|
|
4598
|
+
userInput: this.#userInput,
|
|
4599
|
+
encoding: this.#encoding,
|
|
4600
|
+
truncation: this.#truncation,
|
|
4601
|
+
overlapping: this.#overlapping,
|
|
4602
|
+
reviewed: this.#reviewed,
|
|
4603
|
+
context: this.#context
|
|
4604
|
+
};
|
|
4605
|
+
}
|
|
4606
|
+
}
|
|
4607
|
+
class MetaData {
|
|
4608
|
+
/**
|
|
4609
|
+
* @type {StatData}
|
|
4610
|
+
*/
|
|
4611
|
+
#stats;
|
|
4612
|
+
constructor(data2 = {}) {
|
|
4613
|
+
this.#stats = new StatData(data2.stats);
|
|
4614
|
+
}
|
|
4615
|
+
getStats() {
|
|
4616
|
+
return this.#stats;
|
|
4617
|
+
}
|
|
4618
|
+
setStats(stats) {
|
|
4619
|
+
this.#stats = stats;
|
|
4620
|
+
}
|
|
4621
|
+
toJSON() {
|
|
4622
|
+
return {
|
|
4623
|
+
stats: this.#stats
|
|
4624
|
+
};
|
|
4625
|
+
}
|
|
4626
|
+
}
|
|
4627
|
+
class StringInfo {
|
|
4628
|
+
/**
|
|
4629
|
+
* @type {String}
|
|
4630
|
+
*/
|
|
4631
|
+
#type;
|
|
4632
|
+
/**
|
|
4633
|
+
* @type {String}
|
|
4634
|
+
*/
|
|
4635
|
+
#imagePath;
|
|
4636
|
+
/**
|
|
4637
|
+
* @type {String}
|
|
4638
|
+
*/
|
|
4639
|
+
#description;
|
|
4640
|
+
constructor(data2) {
|
|
4641
|
+
this.#type = data2?.type || "";
|
|
4642
|
+
this.#imagePath = data2?.imagePath || "";
|
|
4643
|
+
this.#description = data2?.description || "";
|
|
4644
|
+
}
|
|
4645
|
+
getType() {
|
|
4646
|
+
return this.#type;
|
|
4647
|
+
}
|
|
4648
|
+
setType(type) {
|
|
4649
|
+
this.#type = type;
|
|
4650
|
+
}
|
|
4651
|
+
getImagePath() {
|
|
4652
|
+
return this.#imagePath;
|
|
4653
|
+
}
|
|
4654
|
+
setImagePath(imagePath) {
|
|
4655
|
+
this.#imagePath = imagePath;
|
|
4656
|
+
}
|
|
4657
|
+
getDescription() {
|
|
4658
|
+
return this.#description;
|
|
4659
|
+
}
|
|
4660
|
+
setDescription(description) {
|
|
4661
|
+
this.#description = description;
|
|
4662
|
+
}
|
|
4663
|
+
toJSON() {
|
|
4664
|
+
return {
|
|
4665
|
+
type: this.#type,
|
|
4666
|
+
description: this.#description,
|
|
4667
|
+
imagePath: this.#imagePath
|
|
4668
|
+
};
|
|
4669
|
+
}
|
|
4670
|
+
}
|
|
4671
|
+
class StringData {
|
|
4672
|
+
/**
|
|
4673
|
+
* @type {{[key: string]: StringInfo[]}}
|
|
4674
|
+
*/
|
|
4675
|
+
#data = {};
|
|
4676
|
+
constructor(data2) {
|
|
4677
|
+
if (data2) {
|
|
4678
|
+
for (const string in data2) {
|
|
4679
|
+
data2[string].forEach((info) => {
|
|
4680
|
+
if (!this.#data[string]) {
|
|
4681
|
+
this.#data[string] = [];
|
|
4682
|
+
}
|
|
4683
|
+
this.#data[string].push(new StringInfo(info));
|
|
4684
|
+
});
|
|
4685
|
+
}
|
|
4686
|
+
}
|
|
4687
|
+
}
|
|
4688
|
+
getStringData(string) {
|
|
4689
|
+
return this.#data[string] || [];
|
|
4690
|
+
}
|
|
4691
|
+
setStringData(string, info) {
|
|
4692
|
+
!this.#data[string] && (this.#data[string] = []);
|
|
4693
|
+
this.#data[string].push(new StringInfo(info));
|
|
4694
|
+
return true;
|
|
4695
|
+
}
|
|
4696
|
+
checkAndAdd(string, info) {
|
|
4697
|
+
!this.#data[string] && (this.#data[string] = []);
|
|
4698
|
+
const canAdd = this.getStringData(string).some(
|
|
4699
|
+
(data2) => data2.getDescription() !== info.description || data2.getImagePath() !== info.imagePath || data2.getType() !== data2.type
|
|
4700
|
+
);
|
|
4701
|
+
if (canAdd) {
|
|
4702
|
+
this.setStringData(string, info);
|
|
4703
|
+
}
|
|
4704
|
+
return canAdd;
|
|
4705
|
+
}
|
|
4706
|
+
hasStringData(string) {
|
|
4707
|
+
return string in this.#data;
|
|
4708
|
+
}
|
|
4709
|
+
/**
|
|
4710
|
+
*
|
|
4711
|
+
* @param {String} string
|
|
4712
|
+
* @param {Object[] | Object} info
|
|
4713
|
+
* @returns {StringData}
|
|
4714
|
+
*/
|
|
4715
|
+
static createNew(string, info) {
|
|
4716
|
+
info = Array.isArray(info) ? info : [info];
|
|
4717
|
+
return new StringData({ data: { [string]: info } });
|
|
4718
|
+
}
|
|
4719
|
+
toJSON() {
|
|
4720
|
+
return this.#data;
|
|
4721
|
+
}
|
|
4722
|
+
}
|
|
4723
|
+
class CacheData {
|
|
4724
|
+
/**
|
|
4725
|
+
* @type {MetaData}
|
|
4726
|
+
*/
|
|
4727
|
+
#metaData;
|
|
4728
|
+
/**
|
|
4729
|
+
* @type {StringData}
|
|
4730
|
+
*/
|
|
4731
|
+
#stringsData;
|
|
4732
|
+
constructor(data2 = {}) {
|
|
4733
|
+
this.#metaData = new MetaData(data2.metaData);
|
|
4734
|
+
this.#stringsData = new StringData(data2.stringsData);
|
|
4735
|
+
}
|
|
4736
|
+
getMetaData() {
|
|
4737
|
+
return this.#metaData;
|
|
4738
|
+
}
|
|
4739
|
+
setMetaData(metaData) {
|
|
4740
|
+
this.#metaData = metaData;
|
|
4741
|
+
}
|
|
4742
|
+
getStringEntry(string) {
|
|
4743
|
+
return this.#stringsData.getStringData(string);
|
|
4744
|
+
}
|
|
4745
|
+
static addString(string, type, description, imagePath) {
|
|
4746
|
+
const cache = CacheData.getInstance();
|
|
4747
|
+
const added = cache.#addStringEntry(
|
|
4748
|
+
string,
|
|
4749
|
+
type,
|
|
4750
|
+
description,
|
|
4751
|
+
imagePath.replace(/\\/g, "/")
|
|
4752
|
+
);
|
|
4753
|
+
added && cache.save();
|
|
4754
|
+
return added;
|
|
4755
|
+
}
|
|
4756
|
+
#addStringEntry(string, type, description, imagePath) {
|
|
4757
|
+
let dataAdded = false;
|
|
4758
|
+
const info = {
|
|
4759
|
+
type,
|
|
4760
|
+
description,
|
|
4761
|
+
imagePath
|
|
4762
|
+
};
|
|
4763
|
+
if (!this.#stringsData.hasStringData(string)) {
|
|
4764
|
+
dataAdded = this.#stringsData.setStringData(string, info);
|
|
4765
|
+
} else {
|
|
4766
|
+
dataAdded = this.#stringsData.checkAndAdd(string, info);
|
|
4767
|
+
}
|
|
4768
|
+
if (dataAdded) {
|
|
4769
|
+
this.#metaData.getStats().incrementByType(type);
|
|
4770
|
+
}
|
|
4771
|
+
return dataAdded;
|
|
4772
|
+
}
|
|
4773
|
+
static incrementCountByType(type) {
|
|
4774
|
+
const cache = CacheData.getInstance();
|
|
4775
|
+
cache.#metaData.getStats().incrementByType(type);
|
|
4776
|
+
cache.save();
|
|
4777
|
+
}
|
|
4778
|
+
toJSON() {
|
|
4779
|
+
return {
|
|
4780
|
+
metaData: this.#metaData,
|
|
4781
|
+
stringsData: this.#stringsData
|
|
4782
|
+
};
|
|
4783
|
+
}
|
|
4784
|
+
save() {
|
|
4785
|
+
Cache.save(this);
|
|
4786
|
+
}
|
|
4787
|
+
remove() {
|
|
4788
|
+
Cache.delete();
|
|
4789
|
+
}
|
|
4790
|
+
static getInstance() {
|
|
4791
|
+
return new CacheData(Cache.getData());
|
|
4792
|
+
}
|
|
4793
|
+
}
|
|
4794
|
+
class Reports {
|
|
4795
|
+
static #baseReportPath;
|
|
4796
|
+
static #reportTimeStamp;
|
|
4797
|
+
static setup() {
|
|
4798
|
+
if (!Reports.#reportTimeStamp) {
|
|
4799
|
+
Reports.#reportTimeStamp = Reports.#dateTime();
|
|
4800
|
+
}
|
|
4801
|
+
const rootFolder = path.resolve();
|
|
4802
|
+
Reports.#baseReportPath = joinPaths(
|
|
4803
|
+
rootFolder,
|
|
4804
|
+
Config.getL10nReportsPath(),
|
|
4805
|
+
Config.getMode(),
|
|
4806
|
+
Reports.#reportTimeStamp
|
|
4807
|
+
);
|
|
4808
|
+
}
|
|
4809
|
+
static getReportTimeStamp() {
|
|
4810
|
+
return Reports.#reportTimeStamp;
|
|
4811
|
+
}
|
|
4812
|
+
static getReportPath() {
|
|
4813
|
+
return Reports.#baseReportPath;
|
|
4814
|
+
}
|
|
4815
|
+
static reviewedReports(str = null, imgName = null) {
|
|
4816
|
+
return Reports.#generateFullReportPath(I18N_STATUS.REVIEWED, str, imgName);
|
|
4817
|
+
}
|
|
4818
|
+
static getContextPath() {
|
|
4819
|
+
return this.#generateContextReportPath();
|
|
4820
|
+
}
|
|
4821
|
+
static [I18N_STATUS.STRING_LOCALIZED](str, imgName) {
|
|
4822
|
+
return Reports.#generateFullReportPath(
|
|
4823
|
+
I18N_STATUS.STRING_LOCALIZED,
|
|
4824
|
+
str,
|
|
4825
|
+
imgName
|
|
4826
|
+
);
|
|
4827
|
+
}
|
|
4828
|
+
static [I18N_STATUS.STRING_NOT_LOCALIZED](str, imgName) {
|
|
4829
|
+
return Reports.#generateFullReportPath(
|
|
4830
|
+
I18N_STATUS.STRING_NOT_LOCALIZED,
|
|
4831
|
+
str,
|
|
4832
|
+
imgName
|
|
4833
|
+
);
|
|
4834
|
+
}
|
|
4835
|
+
static [I18N_STATUS.STRING_PARTIALLY_LOCALIZED](str, imgName) {
|
|
4836
|
+
return Reports.#generateFullReportPath(
|
|
4837
|
+
I18N_STATUS.STRING_PARTIALLY_LOCALIZED,
|
|
4838
|
+
str,
|
|
4839
|
+
imgName
|
|
4840
|
+
);
|
|
4841
|
+
}
|
|
4842
|
+
static [I18N_STATUS.DNT](str, imgName) {
|
|
4843
|
+
return Reports.#generateFullReportPath(I18N_STATUS.DNT, str, imgName);
|
|
4844
|
+
}
|
|
4845
|
+
static [I18N_STATUS.IGNORE](str, imgName) {
|
|
4846
|
+
return Reports.#generateFullReportPath(I18N_STATUS.IGNORE, str, imgName);
|
|
4847
|
+
}
|
|
4848
|
+
static [I18N_STATUS.AUTO_IGNORE](str, imgName) {
|
|
4849
|
+
return Reports.#generateFullReportPath(
|
|
4850
|
+
I18N_STATUS.AUTO_IGNORE,
|
|
4851
|
+
str,
|
|
4852
|
+
imgName
|
|
4853
|
+
);
|
|
4854
|
+
}
|
|
4855
|
+
static [I18N_STATUS.UNTRANSLATED](str, imgName) {
|
|
4856
|
+
return Reports.#generateFullReportPath(
|
|
4857
|
+
I18N_STATUS.UNTRANSLATED,
|
|
4858
|
+
str,
|
|
4859
|
+
imgName
|
|
4860
|
+
);
|
|
4861
|
+
}
|
|
4862
|
+
static [I18N_STATUS.ENCODING_ISSUE](str, imgName) {
|
|
4863
|
+
return Reports.#generateFullReportPath(
|
|
4864
|
+
I18N_STATUS.ENCODING_ISSUE,
|
|
4865
|
+
str,
|
|
4866
|
+
imgName
|
|
4867
|
+
);
|
|
4868
|
+
}
|
|
4869
|
+
static [I18N_STATUS.DATE_TIME_LOCALIZED](str, imgName) {
|
|
4870
|
+
return Reports.#generateFullReportPath(
|
|
4871
|
+
I18N_STATUS.DATE_TIME_LOCALIZED,
|
|
4872
|
+
str,
|
|
4873
|
+
imgName
|
|
4874
|
+
);
|
|
4875
|
+
}
|
|
4876
|
+
static [I18N_STATUS.DATE_TIME_NOT_LOCALIZED](str, imgName) {
|
|
4877
|
+
return Reports.#generateFullReportPath(
|
|
4878
|
+
I18N_STATUS.DATE_TIME_NOT_LOCALIZED,
|
|
4879
|
+
str,
|
|
4880
|
+
imgName
|
|
4881
|
+
);
|
|
4882
|
+
}
|
|
4883
|
+
static [I18N_STATUS.DATE_LOCALIZED](str, imgName) {
|
|
4884
|
+
return Reports.#generateFullReportPath(
|
|
4885
|
+
I18N_STATUS.DATE_LOCALIZED,
|
|
4886
|
+
str,
|
|
4887
|
+
imgName
|
|
4888
|
+
);
|
|
4889
|
+
}
|
|
4890
|
+
static [I18N_STATUS.DATE_NOT_LOCALIZED](str, imgName) {
|
|
4891
|
+
return Reports.#generateFullReportPath(
|
|
4892
|
+
I18N_STATUS.DATE_NOT_LOCALIZED,
|
|
4893
|
+
str,
|
|
4894
|
+
imgName
|
|
4895
|
+
);
|
|
4896
|
+
}
|
|
4897
|
+
static [I18N_STATUS.TIME_LOCALIZED](str, imgName) {
|
|
4898
|
+
return Reports.#generateFullReportPath(
|
|
4899
|
+
I18N_STATUS.TIME_LOCALIZED,
|
|
4900
|
+
str,
|
|
4901
|
+
imgName
|
|
4902
|
+
);
|
|
4903
|
+
}
|
|
4904
|
+
static [I18N_STATUS.TIME_NOT_LOCALIZED](str, imgName) {
|
|
4905
|
+
return Reports.#generateFullReportPath(
|
|
4906
|
+
I18N_STATUS.TIME_NOT_LOCALIZED,
|
|
4907
|
+
str,
|
|
4908
|
+
imgName
|
|
4909
|
+
);
|
|
4910
|
+
}
|
|
4911
|
+
static [I18N_STATUS.CURRENCY_LOCALIZED](str, imgName) {
|
|
4912
|
+
return Reports.#generateFullReportPath(
|
|
4913
|
+
I18N_STATUS.CURRENCY_LOCALIZED,
|
|
4914
|
+
str,
|
|
4915
|
+
imgName
|
|
4916
|
+
);
|
|
4917
|
+
}
|
|
4918
|
+
static [I18N_STATUS.CURRENCY_NOT_LOCALIZED](str, imgName) {
|
|
4919
|
+
return Reports.#generateFullReportPath(
|
|
4920
|
+
I18N_STATUS.CURRENCY_NOT_LOCALIZED,
|
|
4921
|
+
str,
|
|
4922
|
+
imgName
|
|
4923
|
+
);
|
|
4924
|
+
}
|
|
4925
|
+
static [I18N_STATUS.PERCENTAGE_LOCALIZED](str, imgName) {
|
|
4926
|
+
return Reports.#generateFullReportPath(
|
|
4927
|
+
I18N_STATUS.PERCENTAGE_LOCALIZED,
|
|
4928
|
+
str,
|
|
4929
|
+
imgName
|
|
4930
|
+
);
|
|
4931
|
+
}
|
|
4932
|
+
static [I18N_STATUS.PERCENTAGE_NOT_LOCALIZED](str, imgName) {
|
|
4933
|
+
return Reports.#generateFullReportPath(
|
|
4934
|
+
I18N_STATUS.PERCENTAGE_NOT_LOCALIZED,
|
|
4935
|
+
str,
|
|
4936
|
+
imgName
|
|
4937
|
+
);
|
|
4938
|
+
}
|
|
4939
|
+
static [I18N_STATUS.NUMBER_LOCALIZED](str, imgName) {
|
|
4940
|
+
return Reports.#generateFullReportPath(
|
|
4941
|
+
I18N_STATUS.NUMBER_LOCALIZED,
|
|
4942
|
+
str,
|
|
4943
|
+
imgName
|
|
4944
|
+
);
|
|
4945
|
+
}
|
|
4946
|
+
static [I18N_STATUS.NUMBER_NOT_LOCALIZED](str, imgName) {
|
|
4947
|
+
return Reports.#generateFullReportPath(
|
|
4948
|
+
I18N_STATUS.NUMBER_NOT_LOCALIZED,
|
|
4949
|
+
str,
|
|
4950
|
+
imgName
|
|
4951
|
+
);
|
|
4952
|
+
}
|
|
4953
|
+
static incrementCount(type, str, imgPath, desc) {
|
|
4954
|
+
if (REPORT_COUNTS.hasOwnProperty(type)) {
|
|
4955
|
+
REPORT_COUNTS[type]++;
|
|
4956
|
+
CacheData.addString(
|
|
4957
|
+
str,
|
|
4958
|
+
type,
|
|
4959
|
+
desc,
|
|
4960
|
+
imgPath.replace(Reports.#baseReportPath, "")
|
|
4961
|
+
);
|
|
4962
|
+
}
|
|
4963
|
+
}
|
|
4964
|
+
static #dateTime() {
|
|
4965
|
+
const now = /* @__PURE__ */ new Date();
|
|
4966
|
+
const year = now.getFullYear();
|
|
4967
|
+
const month = String(now.getMonth() + 1).padStart(2, "0");
|
|
4968
|
+
const day = String(now.getDate()).padStart(2, "0");
|
|
4969
|
+
const hours = String(now.getHours()).padStart(2, "0");
|
|
4970
|
+
const minutes = String(now.getMinutes()).padStart(2, "0");
|
|
4971
|
+
const timeStamp = `${year}-${month}-${day}-${hours}-${minutes}`;
|
|
4972
|
+
return timeStamp;
|
|
4973
|
+
}
|
|
4974
|
+
static #generateFullReportPath = (type, str, imgName) => {
|
|
4975
|
+
const _screenshotPath = joinPaths(
|
|
4976
|
+
Reports.#baseReportPath,
|
|
4977
|
+
toFileNameFormat(Config.getLocale()),
|
|
4978
|
+
"screenshots",
|
|
4979
|
+
String(type).toLowerCase()
|
|
4980
|
+
);
|
|
4981
|
+
ensureDirectoryExists(_screenshotPath, DEBUG_MODE);
|
|
4982
|
+
if (str !== null && str !== void 0) {
|
|
4983
|
+
const _stringsPath = joinPaths(
|
|
4984
|
+
Reports.#baseReportPath,
|
|
4985
|
+
toFileNameFormat(Config.getLocale()),
|
|
4986
|
+
"strings"
|
|
4987
|
+
);
|
|
4988
|
+
ensureDirectoryExists(_stringsPath, DEBUG_MODE);
|
|
4989
|
+
let content = "";
|
|
4990
|
+
const filePath = joinPaths(_stringsPath, type + ".txt");
|
|
4991
|
+
if (pathExists(filePath)) {
|
|
4992
|
+
const existingContent = getFileContent(filePath);
|
|
4993
|
+
if (existingContent.includes(imgName)) {
|
|
4994
|
+
content += str;
|
|
4995
|
+
} else {
|
|
4996
|
+
content += `
|
|
4997
|
+
|<<<<<<<<<<<<<------${imgName}------>>>>>>>>>>>>>|
|
|
4998
|
+
`;
|
|
4999
|
+
content += str;
|
|
5000
|
+
}
|
|
5001
|
+
} else {
|
|
5002
|
+
content += `
|
|
5003
|
+
|<<<<<<<<<<<<<------${imgName}------>>>>>>>>>>>>>|
|
|
5004
|
+
`;
|
|
5005
|
+
content += str;
|
|
5006
|
+
}
|
|
5007
|
+
addContentToFile(filePath, content);
|
|
5008
|
+
}
|
|
5009
|
+
return _screenshotPath;
|
|
5010
|
+
};
|
|
5011
|
+
static #generateContextReportPath = () => {
|
|
5012
|
+
const contextPath = joinPaths(
|
|
5013
|
+
Reports.#baseReportPath,
|
|
5014
|
+
toFileNameFormat(Config.getLocale()),
|
|
5015
|
+
"contexts"
|
|
5016
|
+
);
|
|
5017
|
+
ensureDirectoryExists(contextPath, DEBUG_MODE);
|
|
5018
|
+
return contextPath;
|
|
5019
|
+
};
|
|
5020
|
+
static #generateReport(type) {
|
|
5021
|
+
ReportFactory.export(type, Reports.#baseReportPath);
|
|
5022
|
+
}
|
|
5023
|
+
static generateHtml() {
|
|
5024
|
+
Reports.#generateReport(SUPPORTED_REPORT_TYPES.HTML);
|
|
5025
|
+
}
|
|
5026
|
+
static generateAsciiTable() {
|
|
5027
|
+
Reports.#generateReport(SUPPORTED_REPORT_TYPES.ASCII_TABLE);
|
|
5028
|
+
}
|
|
5029
|
+
}
|
|
5030
|
+
let Logger$1 = class Logger2 {
|
|
5031
|
+
static #isLogAppending = false;
|
|
5032
|
+
static #appenderInterval;
|
|
5033
|
+
static #appenderQueue = [];
|
|
5034
|
+
static info(message) {
|
|
5035
|
+
Logger2.#print("info", message);
|
|
5036
|
+
}
|
|
5037
|
+
static warn(message) {
|
|
5038
|
+
Logger2.#print("warn", message);
|
|
5039
|
+
}
|
|
5040
|
+
static error(message, err) {
|
|
5041
|
+
Logger2.#print("errr", message, err);
|
|
5042
|
+
}
|
|
5043
|
+
static debug(message) {
|
|
5044
|
+
Logger2.#print("dbug", message);
|
|
5045
|
+
}
|
|
5046
|
+
static #print(type, message, additionalObj = "") {
|
|
5047
|
+
const colors = {
|
|
5048
|
+
INFO: "\x1B[37m",
|
|
5049
|
+
WARN: "\x1B[33m",
|
|
5050
|
+
ERRR: "\x1B[31m",
|
|
5051
|
+
DBUG: "\x1B[34m"
|
|
5052
|
+
};
|
|
5053
|
+
type = type.toUpperCase();
|
|
5054
|
+
let color = colors[type] || colors.DEFAULT;
|
|
5055
|
+
additionalObj = additionalObj ? ` reason: ${additionalObj.toString()}` : "";
|
|
5056
|
+
let logMessage = `[${(/* @__PURE__ */ new Date()).toLocaleString()}] [${color}${type}\x1B[0m] [${Config.getLocale()}] - ${message}${additionalObj}`;
|
|
5057
|
+
switch (type) {
|
|
5058
|
+
case "INFO":
|
|
5059
|
+
console.info(logMessage);
|
|
5060
|
+
break;
|
|
5061
|
+
case "WARN":
|
|
5062
|
+
console.warn(logMessage);
|
|
5063
|
+
break;
|
|
5064
|
+
case "ERRR":
|
|
5065
|
+
console.error(logMessage);
|
|
5066
|
+
break;
|
|
5067
|
+
case "DBUG":
|
|
5068
|
+
console.debug(logMessage);
|
|
5069
|
+
break;
|
|
5070
|
+
default:
|
|
5071
|
+
console.log(logMessage);
|
|
5072
|
+
}
|
|
5073
|
+
logMessage = logMessage.replace(/\x1b\[\d+m/g, "");
|
|
5074
|
+
Logger2.#customLog(`${logMessage}
|
|
5075
|
+
`);
|
|
5076
|
+
}
|
|
5077
|
+
static #customLog = (message) => {
|
|
5078
|
+
if (Logger2.#isLogAppending) {
|
|
5079
|
+
Logger2.#appenderQueue.push(message);
|
|
5080
|
+
Logger2.#appenderInterval = setInterval(() => {
|
|
5081
|
+
if (!Logger2.#isLogAppending) {
|
|
5082
|
+
clearInterval(Logger2.#appenderInterval);
|
|
5083
|
+
message = Logger2.#appenderQueue.join("\n");
|
|
5084
|
+
Logger2.#appenderQueue = [];
|
|
5085
|
+
message && Logger2.#customLog(message);
|
|
5086
|
+
}
|
|
5087
|
+
}, 10);
|
|
5088
|
+
} else {
|
|
5089
|
+
Logger2.#isLogAppending = true;
|
|
5090
|
+
const LOGS_DIR = joinPaths(Reports.getReportPath(), "logs");
|
|
5091
|
+
const logFilePath = joinPaths(LOGS_DIR, "log");
|
|
5092
|
+
ensureDirectoryExists(LOGS_DIR, DEBUG_MODE);
|
|
5093
|
+
fs.appendFileSync(logFilePath, message);
|
|
5094
|
+
Logger2.#isLogAppending = false;
|
|
5095
|
+
}
|
|
5096
|
+
};
|
|
5097
|
+
};
|
|
5098
|
+
class NightWatchDriver extends BaseDriver {
|
|
5099
|
+
constructor(driver) {
|
|
5100
|
+
super(driver);
|
|
5101
|
+
}
|
|
5102
|
+
async getElement(locator, suppressNotFoundErrors = false) {
|
|
5103
|
+
return await this.$driver.element.find({
|
|
5104
|
+
selector: locator,
|
|
5105
|
+
locateStrategy: locator.startsWith("/") ? "xpath" : "css selector",
|
|
5106
|
+
suppressNotFoundErrors
|
|
5107
|
+
});
|
|
5108
|
+
}
|
|
5109
|
+
async getElements(locator, suppressNotFoundErrors = false) {
|
|
5110
|
+
return await this.$driver.element.findAll({
|
|
5111
|
+
selector: locator,
|
|
5112
|
+
locateStrategy: locator.startsWith("/") ? "xpath" : "css selector",
|
|
5113
|
+
suppressNotFoundErrors
|
|
5114
|
+
});
|
|
5115
|
+
}
|
|
5116
|
+
async getText(element) {
|
|
5117
|
+
return await element.getText();
|
|
5118
|
+
}
|
|
5119
|
+
async getTitle(element) {
|
|
5120
|
+
return await element.getAttribute("title");
|
|
5121
|
+
}
|
|
5122
|
+
async getPlaceholderText(element) {
|
|
5123
|
+
return await element.getAttribute("placeholder");
|
|
5124
|
+
}
|
|
5125
|
+
async getAltText(element) {
|
|
5126
|
+
return await element.getAttribute("alt");
|
|
5127
|
+
}
|
|
5128
|
+
async getTagName(element) {
|
|
5129
|
+
return await element.getTagName();
|
|
5130
|
+
}
|
|
5131
|
+
async getValue(element) {
|
|
5132
|
+
return await element.getAttribute("value");
|
|
5133
|
+
}
|
|
5134
|
+
async getElementID(element) {
|
|
5135
|
+
return await element.getAttribute("id");
|
|
5136
|
+
}
|
|
5137
|
+
async getElementDimension(element) {
|
|
5138
|
+
const eleSize = await element.getRect();
|
|
5139
|
+
if (![null, "", void 0].includes(eleSize)) {
|
|
5140
|
+
return [eleSize.x, eleSize.y, eleSize.height, eleSize.width];
|
|
5141
|
+
}
|
|
5142
|
+
}
|
|
5143
|
+
async isElementDisplayed(element) {
|
|
5144
|
+
return await this.$driver.isVisible(element);
|
|
5145
|
+
}
|
|
5146
|
+
async isElementPresent(element) {
|
|
5147
|
+
return await this.$driver.isPresent(element);
|
|
5148
|
+
}
|
|
5149
|
+
async getElementStrings(element) {
|
|
5150
|
+
const elementStrings = [];
|
|
5151
|
+
if (this.isElementDisplayed(element)) {
|
|
5152
|
+
const textFields = [
|
|
5153
|
+
{ type: "eleTxt", value: await this.getText(element) },
|
|
5154
|
+
{ type: "altTxt", value: await this.getAltText(element) },
|
|
5155
|
+
{ type: "titleTxt", value: await this.getTitle(element) },
|
|
5156
|
+
{ type: "placeTxt", value: await this.getPlaceholderText(element) },
|
|
5157
|
+
{ type: "valueTxt", value: await this.getValue(element) }
|
|
5158
|
+
];
|
|
5159
|
+
textFields.forEach(({ value }) => {
|
|
5160
|
+
if (this.checkIfNullOrEmpty(value)) {
|
|
5161
|
+
elementStrings.push(value);
|
|
5162
|
+
}
|
|
5163
|
+
});
|
|
5164
|
+
}
|
|
5165
|
+
return elementStrings;
|
|
5166
|
+
}
|
|
5167
|
+
async getElementString(element) {
|
|
5168
|
+
let eleStr = null;
|
|
5169
|
+
const textFunctions = [
|
|
5170
|
+
this.getText,
|
|
5171
|
+
this.getAltText,
|
|
5172
|
+
this.getTitle,
|
|
5173
|
+
this.getPlaceholderText,
|
|
5174
|
+
this.getValue
|
|
5175
|
+
];
|
|
5176
|
+
for (const func of textFunctions) {
|
|
5177
|
+
eleStr = await func(element);
|
|
5178
|
+
if (eleStr !== null) return eleStr;
|
|
5179
|
+
}
|
|
5180
|
+
return eleStr;
|
|
5181
|
+
}
|
|
5182
|
+
async captureScreenshot(file) {
|
|
5183
|
+
await captureFullPage$1(this.$driver, file);
|
|
5184
|
+
}
|
|
5185
|
+
async getElementsCount(elements) {
|
|
5186
|
+
return elements.length;
|
|
5187
|
+
}
|
|
5188
|
+
async switchToIFrame(frameID, frameValue) {
|
|
5189
|
+
return new Promise((res) => {
|
|
5190
|
+
this.$driver.frame(frameID, function() {
|
|
5191
|
+
res(true);
|
|
5192
|
+
});
|
|
5193
|
+
});
|
|
5194
|
+
}
|
|
5195
|
+
async switchToParentFrame() {
|
|
5196
|
+
return new Promise(
|
|
5197
|
+
(res) => this.$driver.frame(null, function() {
|
|
5198
|
+
res(true);
|
|
5199
|
+
})
|
|
5200
|
+
);
|
|
5201
|
+
}
|
|
5202
|
+
pause(time) {
|
|
5203
|
+
this.$driver.pause(time * 1e3);
|
|
5204
|
+
}
|
|
5205
|
+
async onScreenStringHighlight(el, color) {
|
|
5206
|
+
await this.$driver.execute(
|
|
5207
|
+
(el2, color2) => {
|
|
5208
|
+
const oldBorder = window.getComputedStyle(el2).border;
|
|
5209
|
+
el2.style.border = `3px solid ${color2}`;
|
|
5210
|
+
setTimeout(() => {
|
|
5211
|
+
el2.style.border = oldBorder;
|
|
5212
|
+
}, 40);
|
|
5213
|
+
},
|
|
5214
|
+
[el, color]
|
|
5215
|
+
);
|
|
5216
|
+
}
|
|
5217
|
+
async checkIfIframeIsPresent() {
|
|
5218
|
+
return new Promise((res) => {
|
|
5219
|
+
this.$driver.isPresent(
|
|
5220
|
+
{
|
|
5221
|
+
selector: "//iframe",
|
|
5222
|
+
locateStrategy: "xpath",
|
|
5223
|
+
suppressNotFoundErrors: true
|
|
5224
|
+
},
|
|
5225
|
+
(result) => {
|
|
5226
|
+
res(result.value);
|
|
5227
|
+
}
|
|
5228
|
+
);
|
|
5229
|
+
});
|
|
5230
|
+
}
|
|
5231
|
+
async checkIfIframeBodyIsEmpty() {
|
|
5232
|
+
const bodyContent = await this.$driver.executeScript(function() {
|
|
5233
|
+
return document.body.innerHTML;
|
|
5234
|
+
});
|
|
5235
|
+
return bodyContent.trim() === "";
|
|
5236
|
+
}
|
|
5237
|
+
}
|
|
5238
|
+
const captureFullPage$1 = async (driver, filePath) => {
|
|
5239
|
+
const client = await CDP({
|
|
5240
|
+
host: "localhost",
|
|
5241
|
+
port: getRemoteDebuggerPort$1(driver)
|
|
5242
|
+
});
|
|
5243
|
+
const { Page } = client;
|
|
5244
|
+
await Page.enable();
|
|
5245
|
+
const { data: data2 } = await Page.captureScreenshot({
|
|
5246
|
+
format: "png",
|
|
5247
|
+
captureBeyondViewport: true
|
|
5248
|
+
});
|
|
5249
|
+
const screenshotBuffer = Buffer.from(data2, "base64");
|
|
5250
|
+
writeFileSync(filePath, screenshotBuffer);
|
|
5251
|
+
Logger$1.debug(`Screenshot saved as: ${filePath}`);
|
|
5252
|
+
await client.close();
|
|
5253
|
+
};
|
|
5254
|
+
const getRemoteDebuggerPort$1 = (driver) => {
|
|
5255
|
+
const debuggerAddress = driver?.capabilities?.["goog:chromeOptions"]?.debuggerAddress;
|
|
5256
|
+
if (debuggerAddress) {
|
|
5257
|
+
return debuggerAddress.split(":")?.[1] || 9229;
|
|
5258
|
+
}
|
|
5259
|
+
return 9229;
|
|
5260
|
+
};
|
|
5261
|
+
class WebDriverIoDriver extends BaseDriver {
|
|
5262
|
+
constructor(driver) {
|
|
5263
|
+
super(driver);
|
|
5264
|
+
}
|
|
5265
|
+
async getElement(locator) {
|
|
5266
|
+
return await this.$driver.$(locator);
|
|
5267
|
+
}
|
|
5268
|
+
async getElements(locator) {
|
|
5269
|
+
return await this.$driver.$$(locator);
|
|
5270
|
+
}
|
|
5271
|
+
async getText(element) {
|
|
5272
|
+
return await $(element).getText();
|
|
5273
|
+
}
|
|
5274
|
+
async getTitle(element) {
|
|
5275
|
+
return await $(element).getAttribute("title");
|
|
5276
|
+
}
|
|
5277
|
+
async getPlaceholderText(element) {
|
|
5278
|
+
return await $(element).getAttribute("placeholder");
|
|
5279
|
+
}
|
|
5280
|
+
async getAltText(element) {
|
|
5281
|
+
return await $(element).getAttribute("alt");
|
|
5282
|
+
}
|
|
5283
|
+
async getTagName(element) {
|
|
5284
|
+
return await $(element).getTagName();
|
|
5285
|
+
}
|
|
5286
|
+
async getValue(element) {
|
|
5287
|
+
return await $(element).getValue();
|
|
5288
|
+
}
|
|
5289
|
+
async getElementID(element) {
|
|
5290
|
+
return await $(element).getAttribute("id");
|
|
5291
|
+
}
|
|
5292
|
+
async getElementDimension(element) {
|
|
5293
|
+
if (!element) return null;
|
|
5294
|
+
try {
|
|
5295
|
+
const location = await element.getLocation();
|
|
5296
|
+
const size = await element.getSize();
|
|
5297
|
+
if (!location || !size) return null;
|
|
5298
|
+
return [location.x, location.y, size.height, size.width];
|
|
5299
|
+
} catch (error) {
|
|
5300
|
+
console.error("Error getting element dimensions:", error);
|
|
5301
|
+
return null;
|
|
5302
|
+
}
|
|
5303
|
+
}
|
|
5304
|
+
async isElementDisplayed(element) {
|
|
5305
|
+
return await $(element).isDisplayed();
|
|
5306
|
+
}
|
|
5307
|
+
async isElementPresent(element) {
|
|
5308
|
+
return await $(element).isExisting();
|
|
5309
|
+
}
|
|
5310
|
+
async getElementStrings(element) {
|
|
5311
|
+
const elementStrings = [];
|
|
5312
|
+
const textFields = [
|
|
5313
|
+
{ type: "elTxt", value: await this.getText(element) },
|
|
5314
|
+
{ type: "altTxt", value: await this.getAltText(element) },
|
|
5315
|
+
{ type: "titleTxt", value: await this.getTitle(element) },
|
|
5316
|
+
{ type: "placeTxt", value: await this.getPlaceholderText(element) },
|
|
5317
|
+
{ type: "valueTxt", value: await this.getValue(element) }
|
|
5318
|
+
];
|
|
5319
|
+
textFields.forEach(({ value }) => {
|
|
5320
|
+
if (this.checkIfNullOrEmpty(value)) {
|
|
5321
|
+
elementStrings.push(value);
|
|
5322
|
+
}
|
|
5323
|
+
});
|
|
5324
|
+
return elementStrings;
|
|
5325
|
+
}
|
|
5326
|
+
async getElementString(element) {
|
|
5327
|
+
let eleStr = null;
|
|
5328
|
+
const textFunctions = [
|
|
5329
|
+
this.getText,
|
|
5330
|
+
this.getAltText,
|
|
5331
|
+
this.getTitle,
|
|
5332
|
+
this.getPlaceholderText,
|
|
5333
|
+
this.getValue
|
|
5334
|
+
];
|
|
5335
|
+
for (const func of textFunctions) {
|
|
5336
|
+
eleStr = await func(element);
|
|
5337
|
+
if (eleStr !== null) return eleStr;
|
|
5338
|
+
}
|
|
5339
|
+
return eleStr;
|
|
5340
|
+
}
|
|
5341
|
+
async captureScreenshot(file) {
|
|
5342
|
+
await captureFullPage(this.$driver, file);
|
|
5343
|
+
}
|
|
5344
|
+
async getElementsCount(elements) {
|
|
5345
|
+
return elements.length;
|
|
5346
|
+
}
|
|
5347
|
+
async switchToIFrame(frameID, frameValue) {
|
|
5348
|
+
await this.$driver.switchFrame(frameValue);
|
|
5349
|
+
}
|
|
5350
|
+
async switchToParentFrame() {
|
|
5351
|
+
await this.$driver.switchToParentFrame();
|
|
5352
|
+
}
|
|
5353
|
+
pause(time) {
|
|
5354
|
+
this.$driver.pause(time * 1e3);
|
|
5355
|
+
}
|
|
5356
|
+
async onScreenStringHighlight(el, color) {
|
|
5357
|
+
await this.$driver.execute(
|
|
5358
|
+
(el2, color2) => {
|
|
5359
|
+
const oldBorder = window.getComputedStyle(el2).border;
|
|
5360
|
+
el2.style.border = `3px solid ${color2}`;
|
|
5361
|
+
setTimeout(() => {
|
|
5362
|
+
el2.style.border = oldBorder;
|
|
5363
|
+
}, 40);
|
|
5364
|
+
},
|
|
5365
|
+
el,
|
|
5366
|
+
color
|
|
5367
|
+
);
|
|
5368
|
+
}
|
|
5369
|
+
async checkIfIframeIsPresent() {
|
|
5370
|
+
return new Promise((res) => {
|
|
5371
|
+
this.$driver.$("//iframe").isExisting().then(() => {
|
|
5372
|
+
res(true);
|
|
5373
|
+
});
|
|
5374
|
+
});
|
|
5375
|
+
}
|
|
5376
|
+
async checkIfIframeBodyIsEmpty() {
|
|
5377
|
+
const bodyContent = await this.$driver.executeScript(
|
|
5378
|
+
"return document.body.innerHTML;",
|
|
5379
|
+
[]
|
|
5380
|
+
);
|
|
5381
|
+
return bodyContent.trim() === "";
|
|
5382
|
+
}
|
|
5383
|
+
}
|
|
5384
|
+
const captureFullPage = async (driver, filePath) => {
|
|
5385
|
+
const port = getRemoteDebuggerPort(driver);
|
|
5386
|
+
const client = await CDP({ host: "localhost", port });
|
|
5387
|
+
const { Page } = client;
|
|
5388
|
+
await Page.enable();
|
|
5389
|
+
const { data: data2 } = await Page.captureScreenshot({
|
|
5390
|
+
format: "png",
|
|
5391
|
+
captureBeyondViewport: true
|
|
5392
|
+
});
|
|
5393
|
+
fs.writeFileSync(filePath, Buffer.from(data2, "base64"));
|
|
5394
|
+
await client.close();
|
|
5395
|
+
};
|
|
5396
|
+
const getRemoteDebuggerPort = (driver) => {
|
|
5397
|
+
const debuggerAddress = driver.capabilities?.["goog:chromeOptions"]?.debuggerAddress;
|
|
5398
|
+
return debuggerAddress ? debuggerAddress.split(":")[1] || 9229 : 9229;
|
|
5399
|
+
};
|
|
5400
|
+
const xpath = ({ subject, selector, options = {}, driver }) => {
|
|
5401
|
+
if (!Cypress) {
|
|
5402
|
+
driver.printOnConsole("Cypress object is inaccessible");
|
|
5403
|
+
return;
|
|
5404
|
+
}
|
|
5405
|
+
const isNumber = (xpathResult) => xpathResult.resultType === XPathResult.NUMBER_TYPE;
|
|
5406
|
+
const numberResult = (xpathResult) => xpathResult.numberValue;
|
|
5407
|
+
const isString = (xpathResult) => xpathResult.resultType === XPathResult.STRING_TYPE;
|
|
5408
|
+
const stringResult = (xpathResult) => xpathResult.stringValue;
|
|
5409
|
+
const isBoolean = (xpathResult) => xpathResult.resultType === XPathResult.BOOLEAN_TYPE;
|
|
5410
|
+
const booleanResult = (xpathResult) => xpathResult.booleanValue;
|
|
5411
|
+
const isPrimitive = (x) => Cypress._.isNumber(x) || Cypress._.isString(x) || Cypress._.isBoolean(x);
|
|
5412
|
+
const log2 = {
|
|
5413
|
+
name: "xpath",
|
|
5414
|
+
message: selector
|
|
5415
|
+
};
|
|
5416
|
+
if (Cypress.dom.isElement(subject) && subject.length > 1) {
|
|
5417
|
+
throw new Error(
|
|
5418
|
+
"xpath() can only be called on a single element. Your subject contained " + subject.length + " elements."
|
|
5419
|
+
);
|
|
5420
|
+
}
|
|
5421
|
+
const getValue = () => {
|
|
5422
|
+
let nodes = [];
|
|
5423
|
+
let contextNode;
|
|
5424
|
+
let withinSubject = cy.state("withinSubject");
|
|
5425
|
+
if (Cypress.dom.isElement(subject)) {
|
|
5426
|
+
contextNode = subject[0];
|
|
5427
|
+
} else if (Cypress.dom.isDocument(subject)) {
|
|
5428
|
+
contextNode = subject;
|
|
5429
|
+
} else if (withinSubject) {
|
|
5430
|
+
contextNode = withinSubject[0];
|
|
5431
|
+
} else {
|
|
5432
|
+
contextNode = cy.state("window").document;
|
|
5433
|
+
}
|
|
5434
|
+
let iterator = (contextNode.ownerDocument || contextNode).evaluate(
|
|
5435
|
+
selector,
|
|
5436
|
+
contextNode
|
|
5437
|
+
);
|
|
5438
|
+
if (isNumber(iterator)) {
|
|
5439
|
+
const result = numberResult(iterator);
|
|
5440
|
+
log2.consoleProps = () => {
|
|
5441
|
+
return {
|
|
5442
|
+
XPath: selector,
|
|
5443
|
+
type: "number",
|
|
5444
|
+
result
|
|
5445
|
+
};
|
|
5446
|
+
};
|
|
5447
|
+
return result;
|
|
5448
|
+
}
|
|
5449
|
+
if (isString(iterator)) {
|
|
5450
|
+
const result = stringResult(iterator);
|
|
5451
|
+
log2.consoleProps = () => {
|
|
5452
|
+
return {
|
|
5453
|
+
XPath: selector,
|
|
5454
|
+
type: "string",
|
|
5455
|
+
result
|
|
5456
|
+
};
|
|
5457
|
+
};
|
|
5458
|
+
return result;
|
|
5459
|
+
}
|
|
5460
|
+
if (isBoolean(iterator)) {
|
|
5461
|
+
const result = booleanResult(iterator);
|
|
5462
|
+
log2.consoleProps = () => {
|
|
5463
|
+
return {
|
|
5464
|
+
XPath: selector,
|
|
5465
|
+
type: "boolean",
|
|
5466
|
+
result
|
|
5467
|
+
};
|
|
5468
|
+
};
|
|
5469
|
+
return result;
|
|
5470
|
+
}
|
|
5471
|
+
try {
|
|
5472
|
+
let node = iterator.iterateNext();
|
|
5473
|
+
while (node) {
|
|
5474
|
+
nodes.push(node);
|
|
5475
|
+
node = iterator.iterateNext();
|
|
5476
|
+
}
|
|
5477
|
+
log2.consoleProps = () => {
|
|
5478
|
+
return {
|
|
5479
|
+
XPath: selector,
|
|
5480
|
+
result: nodes.length === 1 ? nodes[0] : nodes
|
|
5481
|
+
};
|
|
5482
|
+
};
|
|
5483
|
+
return nodes;
|
|
5484
|
+
} catch (e) {
|
|
5485
|
+
console.error("Document tree modified during iteration", e);
|
|
5486
|
+
return null;
|
|
5487
|
+
}
|
|
5488
|
+
};
|
|
5489
|
+
const resolveValue = () => {
|
|
5490
|
+
return Cypress.Promise.try(getValue).then((value) => {
|
|
5491
|
+
if (!isPrimitive(value)) {
|
|
5492
|
+
value = Cypress.$(value);
|
|
5493
|
+
value.selector = selector;
|
|
5494
|
+
}
|
|
5495
|
+
return cy.verifyUpcomingAssertions(value, options, {
|
|
5496
|
+
onRetry: resolveValue
|
|
5497
|
+
});
|
|
5498
|
+
});
|
|
5499
|
+
};
|
|
5500
|
+
return resolveValue().then((value) => {
|
|
5501
|
+
if (options.log !== false) {
|
|
5502
|
+
Cypress.log(log2);
|
|
5503
|
+
}
|
|
5504
|
+
return value;
|
|
5505
|
+
}).catch((ex) => console.log(ex));
|
|
5506
|
+
};
|
|
5507
|
+
class CypressDriver extends BaseDriver {
|
|
5508
|
+
/**
|
|
5509
|
+
*
|
|
5510
|
+
* @param {this.$driver} driver
|
|
5511
|
+
*/
|
|
5512
|
+
constructor(driver) {
|
|
5513
|
+
super(driver);
|
|
5514
|
+
}
|
|
5515
|
+
async getElement(el) {
|
|
5516
|
+
if (typeof el !== "string") {
|
|
5517
|
+
return this.$driver.wrap(el);
|
|
5518
|
+
} else if (el.startsWith("//")) {
|
|
5519
|
+
return await this.xpath(el).first();
|
|
5520
|
+
} else {
|
|
5521
|
+
return await this.$driver.get(el).first();
|
|
5522
|
+
}
|
|
5523
|
+
}
|
|
5524
|
+
async getElements(el) {
|
|
5525
|
+
if (typeof el !== "string") {
|
|
5526
|
+
return this.$driver.wrap(el);
|
|
5527
|
+
} else if (el.startsWith("//")) {
|
|
5528
|
+
return await this.xpath(el);
|
|
5529
|
+
} else {
|
|
5530
|
+
return await this.$driver.get(el);
|
|
5531
|
+
}
|
|
5532
|
+
}
|
|
5533
|
+
async getText(el) {
|
|
5534
|
+
return typeof el === "string" ? await this.$driver.get(el).invoke("text") : await this.$driver.wrap(el).invoke("text");
|
|
5535
|
+
}
|
|
5536
|
+
async getTitle(el) {
|
|
5537
|
+
return typeof el === "string" ? await this.$driver.get(el).title() : this.$driver.wrap().title();
|
|
5538
|
+
}
|
|
5539
|
+
async getPlaceholderText(el) {
|
|
5540
|
+
if (typeof el === "string") {
|
|
5541
|
+
return this.$driver.get(el).filter("input").invoke("attr", "placeholder").then((placeholder) => {
|
|
5542
|
+
return placeholder;
|
|
5543
|
+
});
|
|
5544
|
+
} else {
|
|
5545
|
+
return this.$driver.$$(el).attr("placeholder");
|
|
5546
|
+
}
|
|
5547
|
+
}
|
|
5548
|
+
async getAltText(locator) {
|
|
5549
|
+
return this.$driver.get(locator).invoke("attr", "alt");
|
|
5550
|
+
}
|
|
5551
|
+
async getWidth(el) {
|
|
5552
|
+
if (typeof el === "string") {
|
|
5553
|
+
return this.$driver.get(el).invoke("width");
|
|
5554
|
+
} else {
|
|
5555
|
+
return this.$driver.$$(el).width();
|
|
5556
|
+
}
|
|
5557
|
+
}
|
|
5558
|
+
async getHeight(el) {
|
|
5559
|
+
if (typeof el === "string") {
|
|
5560
|
+
return this.$driver.get(el).invoke("height");
|
|
5561
|
+
} else {
|
|
5562
|
+
return this.$driver.$$(el).height();
|
|
5563
|
+
}
|
|
5564
|
+
}
|
|
5565
|
+
async getTagName(el) {
|
|
5566
|
+
if (typeof el === "string") {
|
|
5567
|
+
return this.$driver.get(el).invoke("prop", "tagName").then((tagName) => tagName.toLowerCase());
|
|
5568
|
+
} else {
|
|
5569
|
+
return this.$driver.$$(el).tagName;
|
|
5570
|
+
}
|
|
5571
|
+
}
|
|
5572
|
+
async getValue(el) {
|
|
5573
|
+
if (typeof el === "string") {
|
|
5574
|
+
return this.$driver.get(el).invoke("val");
|
|
5575
|
+
} else {
|
|
5576
|
+
return this.$driver.wrap(el).invoke("val");
|
|
5577
|
+
}
|
|
5578
|
+
}
|
|
5579
|
+
async getLocation(el) {
|
|
5580
|
+
if (typeof el === "string") {
|
|
5581
|
+
return this.$driver.get(el).invoke("offset").then((offset) => {
|
|
5582
|
+
return { x: offset.left, y: offset.top };
|
|
5583
|
+
});
|
|
5584
|
+
} else {
|
|
5585
|
+
const offset = this.$driver.$$(el).offset();
|
|
5586
|
+
return { x: offset.left, y: offset.top };
|
|
5587
|
+
}
|
|
5588
|
+
}
|
|
5589
|
+
async isElementDisplayed(el) {
|
|
5590
|
+
if (typeof el === "string") {
|
|
5591
|
+
return this.$driver.get(el).then(($element) => {
|
|
5592
|
+
return $element.is(":visible");
|
|
5593
|
+
});
|
|
5594
|
+
} else {
|
|
5595
|
+
return this.$driver.$$(el).is(":visible");
|
|
5596
|
+
}
|
|
5597
|
+
}
|
|
5598
|
+
async captureScreenshot(file) {
|
|
5599
|
+
this.$driver.screenshot(file);
|
|
5600
|
+
}
|
|
5601
|
+
async getElementsCount(el) {
|
|
5602
|
+
return new Promise((res) => {
|
|
5603
|
+
if (typeof el === "string") {
|
|
5604
|
+
return this.$driver.get(el).its("length").then((l) => res(l));
|
|
5605
|
+
} else {
|
|
5606
|
+
return this.$driver.wrap(el, { timeout: 8e3 }).its("length").then((l) => res(l));
|
|
5607
|
+
}
|
|
5608
|
+
});
|
|
5609
|
+
}
|
|
5610
|
+
async getElementStrings(el) {
|
|
5611
|
+
const elementStrings = [];
|
|
5612
|
+
try {
|
|
5613
|
+
const textFields = [
|
|
5614
|
+
{ type: "elTxt", value: await this.getText(el) },
|
|
5615
|
+
{ type: "altTxt", value: await this.getAltText(el) },
|
|
5616
|
+
// { type: 'titleTxt', value: await this.getTitle(el) },
|
|
5617
|
+
{ type: "placetxt", value: await this.getPlaceholderText(el) }
|
|
5618
|
+
];
|
|
5619
|
+
textFields.forEach(({ value }) => {
|
|
5620
|
+
if (this.checkIfNullOrEmpty(value)) {
|
|
5621
|
+
elementStrings.push(value);
|
|
5622
|
+
}
|
|
5623
|
+
});
|
|
5624
|
+
} catch (textError) {
|
|
5625
|
+
Logger$1.error("Error getting text of element:", textError);
|
|
5626
|
+
}
|
|
5627
|
+
return elementStrings;
|
|
5628
|
+
}
|
|
5629
|
+
printOnConsole(str) {
|
|
5630
|
+
this.$driver.log(str);
|
|
5631
|
+
}
|
|
5632
|
+
xpath(subject, selector, options = {}) {
|
|
5633
|
+
return xpath({ subject, selector, options, driver: this.$driver });
|
|
5634
|
+
}
|
|
5635
|
+
}
|
|
5636
|
+
class SeleniumDriver extends BaseDriver {
|
|
5637
|
+
constructor(driver) {
|
|
5638
|
+
super(driver);
|
|
5639
|
+
}
|
|
5640
|
+
async getElement(locator) {
|
|
5641
|
+
return await this.driver.findElement(locator);
|
|
5642
|
+
}
|
|
5643
|
+
async getElements(locator) {
|
|
5644
|
+
return await this.driver.findElements(locator);
|
|
5645
|
+
}
|
|
5646
|
+
async getText(element) {
|
|
5647
|
+
return await element.getText();
|
|
5648
|
+
}
|
|
5649
|
+
async getTitle() {
|
|
5650
|
+
return await this.driver.getTitle();
|
|
5651
|
+
}
|
|
5652
|
+
// async getTitle(element) {
|
|
5653
|
+
// return await element.getAttribute('title');
|
|
5654
|
+
// }
|
|
5655
|
+
// async getPlaceholderText(element, placeholder) {
|
|
5656
|
+
// return await element.getAttribute(placeholder);
|
|
5657
|
+
// }
|
|
5658
|
+
// async getAltText(element, alt) {
|
|
5659
|
+
// return await element.getAttribute(alt);
|
|
5660
|
+
// }
|
|
5661
|
+
async getAttribute(element, attributeName) {
|
|
5662
|
+
return await element.getAttribute(attributeName);
|
|
5663
|
+
}
|
|
5664
|
+
async getTagName(element) {
|
|
5665
|
+
return await element.getTagName();
|
|
5666
|
+
}
|
|
5667
|
+
// async getValue(element, value) {
|
|
5668
|
+
// return await element.getAttribute(value);
|
|
5669
|
+
// }
|
|
5670
|
+
async getElementDimension(element) {
|
|
5671
|
+
const eleSize = await element.getRect();
|
|
5672
|
+
if (![null, "", void 0].includes(eleSize)) {
|
|
5673
|
+
return [eleSize.x, eleSize.y, eleSize.height, eleSize.width];
|
|
5674
|
+
}
|
|
5675
|
+
}
|
|
5676
|
+
async isElementDisplayed(element) {
|
|
5677
|
+
return await element.isDisplayed();
|
|
5678
|
+
}
|
|
5679
|
+
async getElementStrings(element) {
|
|
5680
|
+
const elementStrings = [];
|
|
5681
|
+
const textFields = [
|
|
5682
|
+
{ type: "elTxt", value: await this.getText(element) },
|
|
5683
|
+
{ type: "altTxt", value: await this.getAttribute(element, "alt") },
|
|
5684
|
+
{ type: "titleTxt", value: await this.getAttribute(element, "title") },
|
|
5685
|
+
{
|
|
5686
|
+
type: "placeTxt",
|
|
5687
|
+
value: await this.getAttribute(element, "placeholder")
|
|
5688
|
+
},
|
|
5689
|
+
{ type: "valueTxt", value: await this.getAttribute(element, "value") }
|
|
5690
|
+
];
|
|
5691
|
+
textFields.forEach(({ value }) => {
|
|
5692
|
+
if (this.checkIfNullOrEmpty(value)) {
|
|
5693
|
+
elementStrings.push(value);
|
|
5694
|
+
}
|
|
5695
|
+
});
|
|
5696
|
+
return elementStrings;
|
|
5697
|
+
}
|
|
5698
|
+
async getElementsCount(elements) {
|
|
5699
|
+
return elements.length;
|
|
5700
|
+
}
|
|
5701
|
+
}
|
|
5702
|
+
const build$1 = (type, driver) => {
|
|
5703
|
+
switch (type) {
|
|
5704
|
+
case SYSTEM_TYPES.NIGHT_WATCH:
|
|
5705
|
+
return new NightWatchDriver(driver);
|
|
5706
|
+
case SYSTEM_TYPES.WEB_DRIVER_IO:
|
|
5707
|
+
return new WebDriverIoDriver(driver);
|
|
5708
|
+
case SYSTEM_TYPES.CYPRESS:
|
|
5709
|
+
return new CypressDriver(driver);
|
|
5710
|
+
case SYSTEM_TYPES.SELENIUMJS:
|
|
5711
|
+
return new SeleniumDriver(driver);
|
|
5712
|
+
default:
|
|
5713
|
+
throw new Error("Unsupported framework");
|
|
5714
|
+
}
|
|
5715
|
+
};
|
|
5716
|
+
const propertExists = (key, obj) => key in obj;
|
|
5717
|
+
const allPropertyExists = (keys, obj, missingKeys = []) => keys.every((key) => {
|
|
5718
|
+
if (!propertExists(key, obj)) {
|
|
5719
|
+
missingKeys.push(key);
|
|
5720
|
+
return true;
|
|
5721
|
+
}
|
|
5722
|
+
return true;
|
|
5723
|
+
});
|
|
5724
|
+
const arr2Txt = (array, demiliter = ", ") => array.join(demiliter);
|
|
5725
|
+
const getSpacePattern = (asStr = true) => asStr ? "(?:\\s|\\t|(?: ))" : /(?:\s|\t|(?: ))/g;
|
|
5726
|
+
class BaseValidator {
|
|
5727
|
+
#config = {};
|
|
5728
|
+
#type;
|
|
5729
|
+
constructor(type) {
|
|
5730
|
+
this.#type = type;
|
|
5731
|
+
this.#addBaseConfig();
|
|
5732
|
+
this.buildConfig();
|
|
5733
|
+
this.#buildParser();
|
|
5734
|
+
}
|
|
5735
|
+
#addBaseConfig() {
|
|
5736
|
+
this.addToConfig(
|
|
5737
|
+
"supportedLocales",
|
|
5738
|
+
Config.getOptions()?.supportedLocales,
|
|
5739
|
+
[]
|
|
5740
|
+
);
|
|
5741
|
+
this.addToConfig("defaultLocale", Config.getDefaultLocale());
|
|
5742
|
+
this.addToConfig(
|
|
5743
|
+
"defaultLanguage",
|
|
5744
|
+
Config.getDefaultLocale()?.split(/[-_ ]/g)[0]
|
|
5745
|
+
);
|
|
5746
|
+
this.addToConfig("language", Config.getLocale()?.split(/[-_ ]/g)[0]);
|
|
5747
|
+
this.addToConfig("locale", Config.getLocale());
|
|
5748
|
+
this.addToConfig("qaLocale", Config.getQALocale());
|
|
5749
|
+
}
|
|
5750
|
+
buildConfig() {
|
|
5751
|
+
throw new Error(
|
|
5752
|
+
`{{${this.#type}}} buildConfig should be implemented by child class`
|
|
5753
|
+
);
|
|
5754
|
+
}
|
|
5755
|
+
#buildParser() {
|
|
5756
|
+
Globalize.load(CldrData.entireSupplemental());
|
|
5757
|
+
Globalize.load(
|
|
5758
|
+
CldrData.entireMainFor(
|
|
5759
|
+
this.#getCompatibleLocale(this.#config.defaultLocale),
|
|
5760
|
+
this.#getCompatibleLocale(this.#config.locale)
|
|
5761
|
+
)
|
|
5762
|
+
);
|
|
5763
|
+
}
|
|
5764
|
+
#getCompatibleLocale(locale) {
|
|
5765
|
+
if (this.isQaLocale()) {
|
|
5766
|
+
return "en";
|
|
5767
|
+
}
|
|
5768
|
+
locale = locale.replace(/[-_ ]/g, "-");
|
|
5769
|
+
const locales = CldrData.availableLocales;
|
|
5770
|
+
let suitableLocale;
|
|
5771
|
+
if (locales.find((l) => l === locale)) {
|
|
5772
|
+
suitableLocale = locale;
|
|
5773
|
+
} else {
|
|
5774
|
+
const temp = locale.split("-")[0];
|
|
5775
|
+
if (locales.find((l) => l === temp)) {
|
|
5776
|
+
suitableLocale = temp;
|
|
5777
|
+
} else {
|
|
5778
|
+
suitableLocale = locale;
|
|
5779
|
+
}
|
|
5780
|
+
}
|
|
5781
|
+
return suitableLocale;
|
|
5782
|
+
}
|
|
5783
|
+
/**
|
|
5784
|
+
* to check if the given text is a valid issue type
|
|
5785
|
+
* @param {String} string
|
|
5786
|
+
* @returns {Boolean}
|
|
5787
|
+
*/
|
|
5788
|
+
validate(string) {
|
|
5789
|
+
throw new Error(
|
|
5790
|
+
`{{${this.#type}}} validate should be implemented by child class`
|
|
5791
|
+
);
|
|
5792
|
+
}
|
|
5793
|
+
/**
|
|
5794
|
+
* check whether the given value is a valid type of the supplied locale
|
|
5795
|
+
*
|
|
5796
|
+
* @param {String} string
|
|
5797
|
+
* @returns {Boolean}
|
|
5798
|
+
*/
|
|
5799
|
+
isInternationalized(string) {
|
|
5800
|
+
throw new Error(
|
|
5801
|
+
`{{${this.#type}}} isInternationalized should be implemented by child class`
|
|
5802
|
+
);
|
|
5803
|
+
}
|
|
5804
|
+
setConfig(data2) {
|
|
5805
|
+
this.#config = data2;
|
|
5806
|
+
}
|
|
5807
|
+
addToConfig(prop, value, defaultValue) {
|
|
5808
|
+
this.#config[prop] = value ?? defaultValue;
|
|
5809
|
+
}
|
|
5810
|
+
getConfig() {
|
|
5811
|
+
return this.#config;
|
|
5812
|
+
}
|
|
5813
|
+
isSupportedLocale() {
|
|
5814
|
+
return this.#config.supportedLocales.includes(this.currentLocale());
|
|
5815
|
+
}
|
|
5816
|
+
isQaLocale() {
|
|
5817
|
+
return this.currentLocale() === this.#config?.qaLocale;
|
|
5818
|
+
}
|
|
5819
|
+
isDefaultLocale() {
|
|
5820
|
+
return this.currentLocale() === this.defaultLocale();
|
|
5821
|
+
}
|
|
5822
|
+
defaultLocale() {
|
|
5823
|
+
return this.#config?.defaultLocale;
|
|
5824
|
+
}
|
|
5825
|
+
defaultLanguage() {
|
|
5826
|
+
return this.#config?.defaultLanguage;
|
|
5827
|
+
}
|
|
5828
|
+
currentLocale() {
|
|
5829
|
+
return this.#config?.locale;
|
|
5830
|
+
}
|
|
5831
|
+
currentLanguage() {
|
|
5832
|
+
return this.#config.language;
|
|
5833
|
+
}
|
|
5834
|
+
/**
|
|
5835
|
+
*
|
|
5836
|
+
* @param {String} locale
|
|
5837
|
+
* @returns {Globalize}
|
|
5838
|
+
*/
|
|
5839
|
+
getGlobalize(locale) {
|
|
5840
|
+
return Globalize(this.#getCompatibleLocale(locale));
|
|
5841
|
+
}
|
|
5842
|
+
}
|
|
5843
|
+
class CurrencyValidator extends BaseValidator {
|
|
5844
|
+
constructor() {
|
|
5845
|
+
super("currency");
|
|
5846
|
+
}
|
|
5847
|
+
/**
|
|
5848
|
+
*
|
|
5849
|
+
* @override
|
|
5850
|
+
*/
|
|
5851
|
+
validate(string) {
|
|
5852
|
+
return this.#isDefaultCurrency(string) || this.isInternationalized(string);
|
|
5853
|
+
}
|
|
5854
|
+
/**
|
|
5855
|
+
*
|
|
5856
|
+
* @override
|
|
5857
|
+
*/
|
|
5858
|
+
isInternationalized(string) {
|
|
5859
|
+
return this.#isValidCurrency(this.currentLocale(), string);
|
|
5860
|
+
}
|
|
5861
|
+
/**
|
|
5862
|
+
*
|
|
5863
|
+
* @override
|
|
5864
|
+
*/
|
|
5865
|
+
buildConfig() {
|
|
5866
|
+
}
|
|
5867
|
+
/**
|
|
5868
|
+
* check whether the given value is a valid percentage of the supplied locale
|
|
5869
|
+
*
|
|
5870
|
+
* @param {String} locale
|
|
5871
|
+
* @param {String} string
|
|
5872
|
+
* @returns {Boolean}
|
|
5873
|
+
*/
|
|
5874
|
+
#isValidCurrency(locale, string) {
|
|
5875
|
+
const currencyCode = this.#getCurrencyCode(locale);
|
|
5876
|
+
const currencySymbol = this.#getCurrencySymbol(locale, currencyCode);
|
|
5877
|
+
const hasCurrencySymbolOrCode = this.#hasCurrencyCodeOrSymbol(
|
|
5878
|
+
currencyCode,
|
|
5879
|
+
currencySymbol,
|
|
5880
|
+
string
|
|
5881
|
+
);
|
|
5882
|
+
if (!hasCurrencySymbolOrCode) {
|
|
5883
|
+
return false;
|
|
5884
|
+
}
|
|
5885
|
+
const clearNumber = this.#clearNumber(currencyCode, currencySymbol, string);
|
|
5886
|
+
return !isNaN(this.getGlobalize(locale).numberParser()(clearNumber));
|
|
5887
|
+
}
|
|
5888
|
+
#hasCurrencyCodeOrSymbol(code, symbol, string) {
|
|
5889
|
+
return new RegExp(
|
|
5890
|
+
`^(?:-)?(?:${code}|\\${symbol})(?:${getSpacePattern()})?(?:-)?[0-9,. ]+$`,
|
|
5891
|
+
"gi"
|
|
5892
|
+
).test(string) || new RegExp(
|
|
5893
|
+
`^(?:[- ]?)[0-9,. ]+(?:${getSpacePattern()})?(?:${code}|\\${symbol})$`,
|
|
5894
|
+
"gi"
|
|
5895
|
+
).test(string);
|
|
5896
|
+
}
|
|
5897
|
+
#clearNumber(code, symbol, string) {
|
|
5898
|
+
return string.replace(new RegExp(`^(?:-)(?:${getSpacePattern()})?`, "gi"), "").replace(
|
|
5899
|
+
new RegExp(`^(?:${getSpacePattern()})?(?:${code}|\\${symbol})`, "gi"),
|
|
5900
|
+
""
|
|
5901
|
+
).replace(new RegExp(`^(?:-)(?:${getSpacePattern()})?`, "gi"), "").replace(
|
|
5902
|
+
new RegExp(`(?:${getSpacePattern()})?(?:${code}|\\${symbol})$`, "gi"),
|
|
5903
|
+
""
|
|
5904
|
+
).trim();
|
|
5905
|
+
}
|
|
5906
|
+
#getTerritory(locale) {
|
|
5907
|
+
const maxLocale = this.getGlobalize(locale).cldr.supplemental(["likelySubtags", locale]) || locale;
|
|
5908
|
+
return maxLocale.split(/[-_ ]/).pop();
|
|
5909
|
+
}
|
|
5910
|
+
#getCurrencyCode(locale) {
|
|
5911
|
+
const territory = this.#getTerritory(locale);
|
|
5912
|
+
const currencyData = this.getGlobalize(locale).cldr.supplemental("currencyData");
|
|
5913
|
+
const currencies = currencyData.region[territory];
|
|
5914
|
+
if (currencies) {
|
|
5915
|
+
const currency = currencies.find((currency2) => {
|
|
5916
|
+
const values = Object.values(currency2)[0];
|
|
5917
|
+
return !values._tender && (!values._to || new Date(values._to) >= /* @__PURE__ */ new Date());
|
|
5918
|
+
});
|
|
5919
|
+
return currency ? Object.keys(currency)[0] : "USD";
|
|
5920
|
+
}
|
|
5921
|
+
return "USD";
|
|
5922
|
+
}
|
|
5923
|
+
#getCurrencySymbol(locale, currencyCode) {
|
|
5924
|
+
const currencyData = this.getGlobalize(locale).cldr.main(
|
|
5925
|
+
`numbers/currencies/${currencyCode}`
|
|
5926
|
+
);
|
|
5927
|
+
return currencyData?.symbol || "$";
|
|
5928
|
+
}
|
|
5929
|
+
/**
|
|
5930
|
+
* check whether the given value is a valid currency of default locale
|
|
5931
|
+
*
|
|
5932
|
+
* @param {String} string
|
|
5933
|
+
* @returns {Boolean}
|
|
5934
|
+
*/
|
|
5935
|
+
#isDefaultCurrency(string) {
|
|
5936
|
+
return this.#isValidCurrency(this.defaultLocale(), string);
|
|
5937
|
+
}
|
|
5938
|
+
}
|
|
5939
|
+
const getParser = (locale) => {
|
|
5940
|
+
let [lang = "en", country = "us"] = locale.split(/[-_ ]/g);
|
|
5941
|
+
country = String(country).toLowerCase();
|
|
5942
|
+
switch (lang) {
|
|
5943
|
+
case "en":
|
|
5944
|
+
return country === "gb" ? en.GB : en;
|
|
5945
|
+
case "de":
|
|
5946
|
+
return de;
|
|
5947
|
+
case "es":
|
|
5948
|
+
return es;
|
|
5949
|
+
case "fr":
|
|
5950
|
+
return fr;
|
|
5951
|
+
case "pt":
|
|
5952
|
+
return pt;
|
|
5953
|
+
case "ja":
|
|
5954
|
+
return ja;
|
|
5955
|
+
case "zh":
|
|
5956
|
+
if (["hans", "cn", "sg", "hans-cn"].includes(country)) {
|
|
5957
|
+
return zh.hans;
|
|
5958
|
+
} else if (["hant", "tw", "hk", "mo", "hant-tw"].includes(country)) {
|
|
5959
|
+
return zh.hant;
|
|
5960
|
+
}
|
|
5961
|
+
return zh;
|
|
5962
|
+
case "ru":
|
|
5963
|
+
return ru;
|
|
5964
|
+
case "nl":
|
|
5965
|
+
return nl;
|
|
5966
|
+
case "uk":
|
|
5967
|
+
return uk;
|
|
5968
|
+
default:
|
|
5969
|
+
return en;
|
|
5970
|
+
}
|
|
5971
|
+
};
|
|
5972
|
+
const isValid$1 = (locale, string) => {
|
|
5973
|
+
string = String(string);
|
|
5974
|
+
const parsedResults = getParser(locale).parse(String(string).trim());
|
|
5975
|
+
parsedResults.forEach((r) => {
|
|
5976
|
+
string = string.replace(r.text, "");
|
|
5977
|
+
});
|
|
5978
|
+
return string.replace(/[^\p{L}\p{N}]+/gu, "").trim().length === 0;
|
|
5979
|
+
};
|
|
5980
|
+
const toLuxonLocale = (locale) => {
|
|
5981
|
+
try {
|
|
5982
|
+
locale = locale.replace("_", "-");
|
|
5983
|
+
return Intl.DateTimeFormat.supportedLocalesOf(locale)[0];
|
|
5984
|
+
} catch (ex) {
|
|
5985
|
+
Logger.warn(`${locale} is unsupported by Intl`);
|
|
5986
|
+
return false;
|
|
5987
|
+
}
|
|
5988
|
+
};
|
|
5989
|
+
const isValid = (locale, format, value) => {
|
|
5990
|
+
locale = toLuxonLocale(locale);
|
|
5991
|
+
if (locale !== false) {
|
|
5992
|
+
const parsed = DateTime.fromFormat(value, format, {
|
|
5993
|
+
locale: toLuxonLocale(locale)
|
|
5994
|
+
});
|
|
5995
|
+
if (parsed.isValid) {
|
|
5996
|
+
return true;
|
|
5997
|
+
}
|
|
5998
|
+
}
|
|
5999
|
+
return false;
|
|
6000
|
+
};
|
|
6001
|
+
class DateValidator extends BaseValidator {
|
|
6002
|
+
constructor() {
|
|
6003
|
+
super("date");
|
|
6004
|
+
}
|
|
6005
|
+
/**
|
|
6006
|
+
*
|
|
6007
|
+
* @override
|
|
6008
|
+
*/
|
|
6009
|
+
validate(string) {
|
|
6010
|
+
return this.#isDefaultDate(string) || this.isInternationalized(string);
|
|
6011
|
+
}
|
|
6012
|
+
/**
|
|
6013
|
+
*
|
|
6014
|
+
* @override
|
|
6015
|
+
*/
|
|
6016
|
+
isInternationalized(string) {
|
|
6017
|
+
return this.#isValidDate(
|
|
6018
|
+
this.isQaLocale() ? this.defaultLocale() : this.currentLocale(),
|
|
6019
|
+
string
|
|
6020
|
+
);
|
|
6021
|
+
}
|
|
6022
|
+
/**
|
|
6023
|
+
*
|
|
6024
|
+
* @override
|
|
6025
|
+
*/
|
|
6026
|
+
buildConfig() {
|
|
6027
|
+
}
|
|
6028
|
+
#isValidDate(locale, string) {
|
|
6029
|
+
return this.#verifyUsingGlobalize(locale, string) || this.#verifyUsingLuxon(locale, string) || this.#verifyUsingChrono(locale, string);
|
|
6030
|
+
}
|
|
6031
|
+
#isDefaultDate(string) {
|
|
6032
|
+
return this.#isValidDate(this.defaultLocale(), string);
|
|
6033
|
+
}
|
|
6034
|
+
#verifyUsingGlobalize(locale, string) {
|
|
6035
|
+
const formats = ["short", "medium", "long", "full"];
|
|
6036
|
+
for (let format of formats) {
|
|
6037
|
+
const dateParser = this.getGlobalize(locale).dateParser({ date: format });
|
|
6038
|
+
if (dateParser(string)) {
|
|
6039
|
+
return true;
|
|
6040
|
+
}
|
|
6041
|
+
}
|
|
6042
|
+
return false;
|
|
6043
|
+
}
|
|
6044
|
+
#verifyUsingLuxon(locale, string) {
|
|
6045
|
+
const formats = [
|
|
6046
|
+
DateTime.DATE_SHORT,
|
|
6047
|
+
DateTime.DATE_MED,
|
|
6048
|
+
DateTime.DATE_FULL,
|
|
6049
|
+
DateTime.DATE_HUGE,
|
|
6050
|
+
DateTime.DATE_MED_WITH_WEEKDAY,
|
|
6051
|
+
"D",
|
|
6052
|
+
"DD",
|
|
6053
|
+
"DDD",
|
|
6054
|
+
"DDDD"
|
|
6055
|
+
];
|
|
6056
|
+
for (let format of formats) {
|
|
6057
|
+
const result = isValid(locale, format, string);
|
|
6058
|
+
if (result) {
|
|
6059
|
+
return true;
|
|
6060
|
+
}
|
|
6061
|
+
}
|
|
6062
|
+
return false;
|
|
6063
|
+
}
|
|
6064
|
+
#verifyUsingChrono(locale, string) {
|
|
6065
|
+
return isValid$1(
|
|
6066
|
+
this.isQaLocale() ? this.defaultLocale() : locale,
|
|
6067
|
+
string
|
|
6068
|
+
);
|
|
6069
|
+
}
|
|
6070
|
+
}
|
|
6071
|
+
class DateTimeValidator extends BaseValidator {
|
|
6072
|
+
constructor() {
|
|
6073
|
+
super("dateTime");
|
|
6074
|
+
}
|
|
6075
|
+
/**
|
|
6076
|
+
*
|
|
6077
|
+
* @override
|
|
6078
|
+
*/
|
|
6079
|
+
validate(string) {
|
|
6080
|
+
return this.#isDefaultDateTime(string) || this.isInternationalized(string);
|
|
6081
|
+
}
|
|
6082
|
+
/**
|
|
6083
|
+
*
|
|
6084
|
+
* @override
|
|
6085
|
+
*/
|
|
6086
|
+
isInternationalized(string) {
|
|
6087
|
+
return this.#isValidDateTime(
|
|
6088
|
+
this.isQaLocale() ? this.defaultLocale() : this.currentLocale(),
|
|
6089
|
+
string
|
|
6090
|
+
);
|
|
6091
|
+
}
|
|
6092
|
+
/**
|
|
6093
|
+
*
|
|
6094
|
+
* @override
|
|
6095
|
+
*/
|
|
6096
|
+
buildConfig() {
|
|
6097
|
+
}
|
|
6098
|
+
#isValidDateTime(locale, string) {
|
|
6099
|
+
return this.#verifyUsingGlobalize(locale, string) || this.#verifyUsingLuxon(locale, string) || this.#verifyUsingChrono(locale, string);
|
|
6100
|
+
}
|
|
6101
|
+
#isDefaultDateTime(string) {
|
|
6102
|
+
return this.#isValidDateTime(this.defaultLocale(), string);
|
|
6103
|
+
}
|
|
6104
|
+
#verifyUsingGlobalize(locale, string) {
|
|
6105
|
+
const formats = ["short", "medium", "long", "full"];
|
|
6106
|
+
for (let format of formats) {
|
|
6107
|
+
const timeParser = this.getGlobalize(locale).dateParser({
|
|
6108
|
+
datetime: format
|
|
6109
|
+
});
|
|
6110
|
+
if (timeParser(string)) {
|
|
6111
|
+
return true;
|
|
6112
|
+
}
|
|
6113
|
+
}
|
|
6114
|
+
return false;
|
|
6115
|
+
}
|
|
6116
|
+
#verifyUsingLuxon(locale, string) {
|
|
6117
|
+
const formats = [
|
|
6118
|
+
DateTime.DATETIME_SHORT,
|
|
6119
|
+
DateTime.DATETIME_SHORT_WITH_SECONDS,
|
|
6120
|
+
DateTime.DATETIME_MED,
|
|
6121
|
+
DateTime.DATETIME_MED_WITH_SECONDS,
|
|
6122
|
+
DateTime.DATETIME_MED_WITH_WEEKDAY,
|
|
6123
|
+
DateTime.DATETIME_FULL,
|
|
6124
|
+
DateTime.DATETIME_FULL_WITH_SECONDS,
|
|
6125
|
+
DateTime.DATETIME_HUGE,
|
|
6126
|
+
DateTime.DATETIME_HUGE_WITH_SECONDS,
|
|
6127
|
+
"f",
|
|
6128
|
+
"F",
|
|
6129
|
+
"ff",
|
|
6130
|
+
"FF"
|
|
6131
|
+
];
|
|
6132
|
+
for (let format of formats) {
|
|
6133
|
+
const result = isValid(locale, format, string);
|
|
6134
|
+
if (result) {
|
|
6135
|
+
return true;
|
|
6136
|
+
}
|
|
6137
|
+
}
|
|
6138
|
+
return false;
|
|
6139
|
+
}
|
|
6140
|
+
#verifyUsingChrono(locale, string) {
|
|
6141
|
+
return isValid$1(
|
|
6142
|
+
this.isQaLocale() ? this.defaultLocale() : locale,
|
|
6143
|
+
string
|
|
6144
|
+
);
|
|
6145
|
+
}
|
|
6146
|
+
}
|
|
6147
|
+
class NumberValidator extends BaseValidator {
|
|
6148
|
+
constructor() {
|
|
6149
|
+
super("number");
|
|
6150
|
+
}
|
|
6151
|
+
/**
|
|
6152
|
+
*
|
|
6153
|
+
* @override
|
|
6154
|
+
*/
|
|
6155
|
+
validate(string) {
|
|
6156
|
+
return this.#isDefaultNumber(string) || this.isInternationalized(string);
|
|
6157
|
+
}
|
|
6158
|
+
/**
|
|
6159
|
+
*
|
|
6160
|
+
* @override
|
|
6161
|
+
*/
|
|
6162
|
+
isInternationalized(string) {
|
|
6163
|
+
return this.#isValidNumber(this.currentLocale(), string);
|
|
6164
|
+
}
|
|
6165
|
+
/**
|
|
6166
|
+
*
|
|
6167
|
+
* @override
|
|
6168
|
+
*/
|
|
6169
|
+
buildConfig() {
|
|
6170
|
+
}
|
|
6171
|
+
/**
|
|
6172
|
+
* check whether the given value is a valid number of the supplied locale
|
|
6173
|
+
*
|
|
6174
|
+
* @param {String} locale
|
|
6175
|
+
* @param {String} string
|
|
6176
|
+
* @returns {Boolean}
|
|
6177
|
+
*/
|
|
6178
|
+
#isValidNumber(locale, string) {
|
|
6179
|
+
const parser = this.getGlobalize(locale).numberParser();
|
|
6180
|
+
return !isNaN(parser(string));
|
|
6181
|
+
}
|
|
6182
|
+
/**
|
|
6183
|
+
* check whether the given value is a valid number of default locale
|
|
6184
|
+
*
|
|
6185
|
+
* @param {String} string
|
|
6186
|
+
* @returns {Boolean}
|
|
6187
|
+
*/
|
|
6188
|
+
#isDefaultNumber(string) {
|
|
6189
|
+
return this.#isValidNumber(this.defaultLocale(), string);
|
|
6190
|
+
}
|
|
6191
|
+
}
|
|
6192
|
+
class PercentageValidator extends BaseValidator {
|
|
6193
|
+
constructor() {
|
|
6194
|
+
super("percentage");
|
|
6195
|
+
}
|
|
6196
|
+
/**
|
|
6197
|
+
*
|
|
6198
|
+
* @override
|
|
6199
|
+
*/
|
|
6200
|
+
validate(string) {
|
|
6201
|
+
return this.#isDefaultPercentage(string) || this.isInternationalized(string);
|
|
6202
|
+
}
|
|
6203
|
+
/**
|
|
6204
|
+
*
|
|
6205
|
+
* @override
|
|
6206
|
+
*/
|
|
6207
|
+
isInternationalized(string) {
|
|
6208
|
+
return this.#isValidPercentage(this.currentLocale(), string);
|
|
6209
|
+
}
|
|
6210
|
+
/**
|
|
6211
|
+
*
|
|
6212
|
+
* @override
|
|
6213
|
+
*/
|
|
6214
|
+
buildConfig() {
|
|
6215
|
+
}
|
|
6216
|
+
/**
|
|
6217
|
+
* check whether the given value is a valid percentage of the supplied locale
|
|
6218
|
+
*
|
|
6219
|
+
* @param {String} locale
|
|
6220
|
+
* @param {String} string
|
|
6221
|
+
* @returns {Boolean}
|
|
6222
|
+
*/
|
|
6223
|
+
#isValidPercentage(locale, string) {
|
|
6224
|
+
const hasPercentageSymbol = this.#hasPercentage(locale, string);
|
|
6225
|
+
if (!hasPercentageSymbol) {
|
|
6226
|
+
return false;
|
|
6227
|
+
}
|
|
6228
|
+
const clearNumber = this.#getClearNumber(string);
|
|
6229
|
+
return !isNaN(this.getGlobalize(locale).numberParser()(clearNumber));
|
|
6230
|
+
}
|
|
6231
|
+
#getClearNumber(string = "") {
|
|
6232
|
+
return string.replace(
|
|
6233
|
+
new RegExp(
|
|
6234
|
+
`(^(?:${getSpacePattern()})*|(?:${getSpacePattern()})*$)`,
|
|
6235
|
+
"g"
|
|
6236
|
+
),
|
|
6237
|
+
""
|
|
6238
|
+
).replace(/^-/, "").replace(/٪|%/g, "").trim();
|
|
6239
|
+
}
|
|
6240
|
+
#hasPercentage(locale, string) {
|
|
6241
|
+
const baseNumber = "[0-9,. ]+";
|
|
6242
|
+
let pattern;
|
|
6243
|
+
if (["fa-IR", "fa-ir"].includes(locale) || locale.startsWith("ar")) {
|
|
6244
|
+
pattern = new RegExp(
|
|
6245
|
+
`(?:-)?(?:${getSpacePattern()})?(?:٪|%)(?:${getSpacePattern()})?${baseNumber}`,
|
|
6246
|
+
"g"
|
|
6247
|
+
);
|
|
6248
|
+
} else {
|
|
6249
|
+
pattern = new RegExp(
|
|
6250
|
+
`(?:-)?(?:${getSpacePattern()})?${baseNumber}(?:${getSpacePattern()})?(?:٪|%)`,
|
|
6251
|
+
"g"
|
|
6252
|
+
);
|
|
6253
|
+
}
|
|
6254
|
+
return pattern.test(string);
|
|
6255
|
+
}
|
|
6256
|
+
/**
|
|
6257
|
+
* check whether the given value is a valid percentage of default locale
|
|
6258
|
+
*
|
|
6259
|
+
* @param {String} string
|
|
6260
|
+
* @returns {Boolean}
|
|
6261
|
+
*/
|
|
6262
|
+
#isDefaultPercentage(string) {
|
|
6263
|
+
return this.#isValidPercentage(this.defaultLocale(), string);
|
|
6264
|
+
}
|
|
6265
|
+
}
|
|
6266
|
+
class StringValidator extends BaseValidator {
|
|
6267
|
+
constructor() {
|
|
6268
|
+
super("string");
|
|
6269
|
+
}
|
|
6270
|
+
/**
|
|
6271
|
+
*
|
|
6272
|
+
* @override
|
|
6273
|
+
*/
|
|
6274
|
+
buildConfig() {
|
|
6275
|
+
const options = Config.getOptions();
|
|
6276
|
+
this.addToConfig("mockChars", options?.qaMock);
|
|
6277
|
+
this.addToConfig("resource", Config.getResourceBundle(), {});
|
|
6278
|
+
this.addToConfig(
|
|
6279
|
+
"garbledChars",
|
|
6280
|
+
Config.getGarbledChars()?.filter((v) => String(v).trim()).filter(Boolean),
|
|
6281
|
+
[]
|
|
6282
|
+
);
|
|
6283
|
+
}
|
|
6284
|
+
/**
|
|
6285
|
+
*
|
|
6286
|
+
* @override
|
|
6287
|
+
*/
|
|
6288
|
+
isInternationalized(string) {
|
|
6289
|
+
const cleanedString = string.trim().replace(/\s*:\s*$/, "");
|
|
6290
|
+
const resources = this.getConfig()?.resource?.[this.defaultLocale()];
|
|
6291
|
+
return resources?.includes(string) || resources?.includes(cleanedString);
|
|
6292
|
+
}
|
|
6293
|
+
/**
|
|
6294
|
+
*
|
|
6295
|
+
* @override
|
|
6296
|
+
*/
|
|
6297
|
+
validate(string) {
|
|
6298
|
+
return typeof string === "string";
|
|
6299
|
+
}
|
|
6300
|
+
/**
|
|
6301
|
+
* to check if the string is a DNT string
|
|
6302
|
+
*
|
|
6303
|
+
* @param {String} string
|
|
6304
|
+
* @returns {Boolean}
|
|
6305
|
+
*/
|
|
6306
|
+
isDntText(string) {
|
|
6307
|
+
return this.getConfig()?.resource?.dnt?.includes(string);
|
|
6308
|
+
}
|
|
6309
|
+
/**
|
|
6310
|
+
* to check if the string can be treated as an auto ingored string
|
|
6311
|
+
*
|
|
6312
|
+
* @param {String} string
|
|
6313
|
+
* @returns {Boolean}
|
|
6314
|
+
*/
|
|
6315
|
+
isAutoIgnoredText(string) {
|
|
6316
|
+
return this.isDefaultLocale() || this.isUserInputText(string) || this.isEmailText(string) || this.isUrlText(string);
|
|
6317
|
+
}
|
|
6318
|
+
/**
|
|
6319
|
+
* to check if the string is an Ignored string
|
|
6320
|
+
*
|
|
6321
|
+
* @param {String} string
|
|
6322
|
+
* @returns {Boolean}
|
|
6323
|
+
*/
|
|
6324
|
+
isIgnoredText(string) {
|
|
6325
|
+
return this.getConfig()?.resource?.ignore?.includes(string);
|
|
6326
|
+
}
|
|
6327
|
+
/**
|
|
6328
|
+
* to check if the string is a user input
|
|
6329
|
+
*
|
|
6330
|
+
* @param {String} string
|
|
6331
|
+
* @returns {Boolean}
|
|
6332
|
+
*/
|
|
6333
|
+
isUserInputText(string) {
|
|
6334
|
+
return string.startsWith(USER_INPUT_PRE_FIX);
|
|
6335
|
+
}
|
|
6336
|
+
/**
|
|
6337
|
+
* to check if the string is a email string
|
|
6338
|
+
*
|
|
6339
|
+
* @param {String} string
|
|
6340
|
+
* @returns {Boolean}
|
|
6341
|
+
*/
|
|
6342
|
+
isEmailText(string) {
|
|
6343
|
+
return PATTERNS.EMAIL.test(string);
|
|
6344
|
+
}
|
|
6345
|
+
/**
|
|
6346
|
+
* to check if the string is a Url string
|
|
6347
|
+
*
|
|
6348
|
+
* @param {String} string
|
|
6349
|
+
* @returns {Boolean}
|
|
6350
|
+
*/
|
|
6351
|
+
isUrlText(string) {
|
|
6352
|
+
return PATTERNS.URL.test(string);
|
|
6353
|
+
}
|
|
6354
|
+
/**
|
|
6355
|
+
* to check if the string is fully localized in QA
|
|
6356
|
+
*
|
|
6357
|
+
* @param {String} string
|
|
6358
|
+
* @returns {Boolean}
|
|
6359
|
+
*/
|
|
6360
|
+
isFullQaLanguageText(string) {
|
|
6361
|
+
const config = this.getConfig();
|
|
6362
|
+
return (string.slice(0, 2) === config?.mockChars?.prefix || string.slice(0, 2) === config?.mockChars?.prefix.toUpperCase()) && string.slice(-2) === config?.mockChars.suffix;
|
|
6363
|
+
}
|
|
6364
|
+
/**
|
|
6365
|
+
* to check if the string is a DNT string
|
|
6366
|
+
*
|
|
6367
|
+
* @param {String} string
|
|
6368
|
+
* @returns {Boolean}
|
|
6369
|
+
*/
|
|
6370
|
+
isPartialQaLanguageText(string) {
|
|
6371
|
+
const config = this.getConfig();
|
|
6372
|
+
return string.slice(0, 2) === config?.mockChars.prefix || string.slice(0, 2) === config?.mockChars.prefix.toUpperCase() || string.slice(-2) === config?.mockChars.suffix;
|
|
6373
|
+
}
|
|
6374
|
+
/**
|
|
6375
|
+
* to check if the string has encoding issues
|
|
6376
|
+
*
|
|
6377
|
+
* @param {String} string
|
|
6378
|
+
* @returns {Boolean}
|
|
6379
|
+
*/
|
|
6380
|
+
hasEncodingIssue(string) {
|
|
6381
|
+
return this.getConfig()?.garbledChars?.length > 0 && this.getConfig().garbledChars.some((char) => string.includes(char));
|
|
6382
|
+
}
|
|
6383
|
+
/**
|
|
6384
|
+
* to check if the string is a partially localized
|
|
6385
|
+
*
|
|
6386
|
+
* @param {String} string
|
|
6387
|
+
* @returns {Promise<Boolean>}
|
|
6388
|
+
*/
|
|
6389
|
+
isPartiallyLocalizedText(string) {
|
|
6390
|
+
return this.#detectLanguageCode(string) === this.currentLanguage();
|
|
6391
|
+
}
|
|
6392
|
+
/**
|
|
6393
|
+
* detects given string language code
|
|
6394
|
+
* @param {String} string
|
|
6395
|
+
*/
|
|
6396
|
+
#detectLanguageCode(string) {
|
|
6397
|
+
const matches = Object.keys(detectTextLangEx(string)?.scores || {}).filter(Boolean) || [];
|
|
6398
|
+
const currLang = this.currentLanguage();
|
|
6399
|
+
if (matches.length) {
|
|
6400
|
+
return matches.includes(currLang) ? currLang : matches[0];
|
|
6401
|
+
}
|
|
6402
|
+
return this.defaultLanguage();
|
|
6403
|
+
}
|
|
6404
|
+
/**
|
|
6405
|
+
* to check if the string is a fully localized
|
|
6406
|
+
*
|
|
6407
|
+
* @param {String} string
|
|
6408
|
+
* @returns {Boolean}
|
|
6409
|
+
*/
|
|
6410
|
+
isLocalized(string) {
|
|
6411
|
+
const cleanedString = string.trim().replace(/\s*:\s*$/, "");
|
|
6412
|
+
const resources = this.getConfig()?.resource?.[this.currentLocale()];
|
|
6413
|
+
return resources?.includes(string) || resources?.includes(cleanedString);
|
|
6414
|
+
}
|
|
6415
|
+
}
|
|
6416
|
+
class TimeValidator extends BaseValidator {
|
|
6417
|
+
constructor() {
|
|
6418
|
+
super("time");
|
|
6419
|
+
}
|
|
6420
|
+
/**
|
|
6421
|
+
*
|
|
6422
|
+
* @override
|
|
6423
|
+
*/
|
|
6424
|
+
validate(string) {
|
|
6425
|
+
return this.#isDefaultTime(string) || this.isInternationalized(string);
|
|
6426
|
+
}
|
|
6427
|
+
/**
|
|
6428
|
+
*
|
|
6429
|
+
* @override
|
|
6430
|
+
*/
|
|
6431
|
+
isInternationalized(string) {
|
|
6432
|
+
return this.#isValidTime(
|
|
6433
|
+
this.isQaLocale() ? this.defaultLocale() : this.currentLocale(),
|
|
6434
|
+
string
|
|
6435
|
+
);
|
|
6436
|
+
}
|
|
6437
|
+
/**
|
|
6438
|
+
*
|
|
6439
|
+
* @override
|
|
6440
|
+
*/
|
|
6441
|
+
buildConfig() {
|
|
6442
|
+
}
|
|
6443
|
+
#isValidTime(locale, string) {
|
|
6444
|
+
return this.#verifyUsingGlobalize(locale, string) || this.#verifyUsingLuxon(locale, string) || this.#verifyUsingChrono(locale, string);
|
|
6445
|
+
}
|
|
6446
|
+
#isDefaultTime(string) {
|
|
6447
|
+
return this.#isValidTime(this.defaultLocale(), string);
|
|
6448
|
+
}
|
|
6449
|
+
#verifyUsingGlobalize(locale, string) {
|
|
6450
|
+
const formats = ["short", "medium", "long", "full"];
|
|
6451
|
+
for (let format of formats) {
|
|
6452
|
+
const timeParser = this.getGlobalize(locale).dateParser({ time: format });
|
|
6453
|
+
if (timeParser(string)) {
|
|
6454
|
+
return true;
|
|
6455
|
+
}
|
|
6456
|
+
}
|
|
6457
|
+
return false;
|
|
6458
|
+
}
|
|
6459
|
+
#verifyUsingLuxon(locale, string) {
|
|
6460
|
+
const formats = [
|
|
6461
|
+
DateTime.TIME_SIMPLE,
|
|
6462
|
+
DateTime.TIME_WITH_SECONDS,
|
|
6463
|
+
DateTime.TIME_WITH_SHORT_OFFSET,
|
|
6464
|
+
DateTime.TIME_WITH_LONG_OFFSET,
|
|
6465
|
+
DateTime.TIME_24_SIMPLE,
|
|
6466
|
+
DateTime.TIME_24_WITH_LONG_OFFSET,
|
|
6467
|
+
DateTime.TIME_24_WITH_SECONDS,
|
|
6468
|
+
DateTime.TIME_24_WITH_SHORT_OFFSET,
|
|
6469
|
+
"t",
|
|
6470
|
+
"T",
|
|
6471
|
+
"tt",
|
|
6472
|
+
"TT"
|
|
6473
|
+
];
|
|
6474
|
+
for (let format of formats) {
|
|
6475
|
+
const result = isValid(locale, format, string);
|
|
6476
|
+
if (result) {
|
|
6477
|
+
return true;
|
|
6478
|
+
}
|
|
6479
|
+
}
|
|
6480
|
+
return false;
|
|
6481
|
+
}
|
|
6482
|
+
#verifyUsingChrono(locale, string) {
|
|
6483
|
+
return isValid$1(
|
|
6484
|
+
this.isQaLocale() ? this.defaultLocale() : locale,
|
|
6485
|
+
string
|
|
6486
|
+
);
|
|
6487
|
+
}
|
|
6488
|
+
}
|
|
6489
|
+
class Validator {
|
|
6490
|
+
static #issuesMap = {};
|
|
6491
|
+
/**
|
|
6492
|
+
* Collection of methods to validate and determine string issues
|
|
6493
|
+
* @type {StringValidator}
|
|
6494
|
+
*/
|
|
6495
|
+
static #string;
|
|
6496
|
+
/**
|
|
6497
|
+
* Collection of methods to validate and determine number issues
|
|
6498
|
+
* @type {NumberValidator}
|
|
6499
|
+
*/
|
|
6500
|
+
static #number;
|
|
6501
|
+
/**
|
|
6502
|
+
* Collection of methods to validate and determine date issues
|
|
6503
|
+
* @type {DateValidator}
|
|
6504
|
+
*/
|
|
6505
|
+
static #date;
|
|
6506
|
+
/**
|
|
6507
|
+
* Collection of methods to validate and determine date issues
|
|
6508
|
+
* @type {TimeValidator}
|
|
6509
|
+
*/
|
|
6510
|
+
static #time;
|
|
6511
|
+
/**
|
|
6512
|
+
* Collection of methods to validate and determine dateTime issues
|
|
6513
|
+
* @type {DateTimeValidator}
|
|
6514
|
+
*/
|
|
6515
|
+
static #dateTime;
|
|
6516
|
+
/**
|
|
6517
|
+
* Collection of methods to validate and determine currency issues
|
|
6518
|
+
* @type {CurrencyValidator}
|
|
6519
|
+
*/
|
|
6520
|
+
static #currency;
|
|
6521
|
+
/**
|
|
6522
|
+
* Collection of methods to validate and determine percentage issues
|
|
6523
|
+
* @type {PercentageValidator}
|
|
6524
|
+
*/
|
|
6525
|
+
static #percentage;
|
|
6526
|
+
static load() {
|
|
6527
|
+
Validator.#string = new StringValidator();
|
|
6528
|
+
Validator.#number = new NumberValidator();
|
|
6529
|
+
Validator.#date = new DateValidator();
|
|
6530
|
+
Validator.#time = new TimeValidator();
|
|
6531
|
+
Validator.#dateTime = new DateTimeValidator();
|
|
6532
|
+
Validator.#currency = new CurrencyValidator();
|
|
6533
|
+
Validator.#percentage = new PercentageValidator();
|
|
6534
|
+
}
|
|
6535
|
+
/**
|
|
6536
|
+
*
|
|
6537
|
+
* @param {String} string
|
|
6538
|
+
* @returns {String} issue type
|
|
6539
|
+
*/
|
|
6540
|
+
static getIssueType(string) {
|
|
6541
|
+
const locale = Config.getLocale();
|
|
6542
|
+
if (locale) {
|
|
6543
|
+
let type = I18N_STATUS.UNTRANSLATED;
|
|
6544
|
+
if (!Validator.#issuesMap[locale]) {
|
|
6545
|
+
Validator.#issuesMap[locale] = {};
|
|
6546
|
+
}
|
|
6547
|
+
if (Validator.#issuesMap[locale][string]) {
|
|
6548
|
+
return Validator.#issuesMap[locale][string];
|
|
6549
|
+
}
|
|
6550
|
+
if (this.#string.isAutoIgnoredText(string)) {
|
|
6551
|
+
type = I18N_STATUS.AUTO_IGNORE;
|
|
6552
|
+
} else if (this.#string.isDntText(string)) {
|
|
6553
|
+
type = I18N_STATUS.DNT;
|
|
6554
|
+
} else if (this.#string.isIgnoredText(string)) {
|
|
6555
|
+
type = I18N_STATUS.IGNORE;
|
|
6556
|
+
} else if (this.#string.hasEncodingIssue(string)) {
|
|
6557
|
+
type = I18N_STATUS.ENCODING_ISSUE;
|
|
6558
|
+
} else if (this.#currency.validate(string)) {
|
|
6559
|
+
type = this.#currency.isInternationalized(string) ? I18N_STATUS.CURRENCY_LOCALIZED : I18N_STATUS.CURRENCY_NOT_LOCALIZED;
|
|
6560
|
+
} else if (this.#percentage.validate(string)) {
|
|
6561
|
+
type = this.#percentage.isInternationalized(string) ? I18N_STATUS.PERCENTAGE_LOCALIZED : I18N_STATUS.PERCENTAGE_NOT_LOCALIZED;
|
|
6562
|
+
} else if (this.#number.validate(string)) {
|
|
6563
|
+
type = this.#number.isInternationalized(string) ? I18N_STATUS.NUMBER_LOCALIZED : I18N_STATUS.NUMBER_NOT_LOCALIZED;
|
|
6564
|
+
} else if (this.#date.validate(string)) {
|
|
6565
|
+
type = this.#date.isInternationalized(string) ? I18N_STATUS.DATE_LOCALIZED : I18N_STATUS.DATE_NOT_LOCALIZED;
|
|
6566
|
+
} else if (this.#time.validate(string)) {
|
|
6567
|
+
type = this.#time.isInternationalized(string) ? I18N_STATUS.TIME_LOCALIZED : I18N_STATUS.TIME_NOT_LOCALIZED;
|
|
6568
|
+
} else if (this.#dateTime.validate(string)) {
|
|
6569
|
+
type = this.#dateTime.isInternationalized(string) ? I18N_STATUS.DATE_TIME_LOCALIZED : I18N_STATUS.DATE_TIME_NOT_LOCALIZED;
|
|
6570
|
+
} else if (this.#string.validate(string)) {
|
|
6571
|
+
if (this.#string.isQaLocale()) {
|
|
6572
|
+
if (this.#string.isFullQaLanguageText(string)) {
|
|
6573
|
+
type = I18N_STATUS.STRING_LOCALIZED;
|
|
6574
|
+
} else if (this.#string.isPartialQaLanguageText(string)) {
|
|
6575
|
+
type = I18N_STATUS.STRING_PARTIALLY_LOCALIZED;
|
|
6576
|
+
} else {
|
|
6577
|
+
type = I18N_STATUS.STRING_NOT_LOCALIZED;
|
|
6578
|
+
}
|
|
6579
|
+
} else if (!this.#string.isDefaultLocale() && this.#string.isSupportedLocale()) {
|
|
6580
|
+
if (this.#string.isLocalized(string)) {
|
|
6581
|
+
type = I18N_STATUS.STRING_LOCALIZED;
|
|
6582
|
+
} else if (this.#string.isPartiallyLocalizedText(string)) {
|
|
6583
|
+
type = I18N_STATUS.STRING_PARTIALLY_LOCALIZED;
|
|
6584
|
+
} else if (!this.#string.isInternationalized(string)) {
|
|
6585
|
+
type = I18N_STATUS.STRING_NOT_LOCALIZED;
|
|
6586
|
+
} else {
|
|
6587
|
+
type = I18N_STATUS.UNTRANSLATED;
|
|
6588
|
+
}
|
|
6589
|
+
}
|
|
6590
|
+
} else if (this.#string.isDefaultLocale()) {
|
|
6591
|
+
type = I18N_STATUS.AUTO_IGNORE;
|
|
6592
|
+
}
|
|
6593
|
+
Validator.#issuesMap[locale][string] = type;
|
|
6594
|
+
return type;
|
|
6595
|
+
}
|
|
6596
|
+
return I18N_STATUS.UNTRANSLATED;
|
|
6597
|
+
}
|
|
6598
|
+
}
|
|
6599
|
+
class Resource {
|
|
6600
|
+
static load() {
|
|
6601
|
+
const bundle = {};
|
|
6602
|
+
if (Config.getOptions()?.l10nResourcePath) {
|
|
6603
|
+
const resourcePath = joinPaths(
|
|
6604
|
+
process.cwd(),
|
|
6605
|
+
Config.getOptions()?.l10nResourcePath
|
|
6606
|
+
);
|
|
6607
|
+
if (fileExists(resourcePath)) {
|
|
6608
|
+
Resource.#processFile(resourcePath, bundle);
|
|
6609
|
+
} else if (dirExists(resourcePath)) {
|
|
6610
|
+
for (const file of getDirContents(resourcePath)) {
|
|
6611
|
+
const filePath = joinPaths(resourcePath, file);
|
|
6612
|
+
Resource.#processFile(filePath, bundle);
|
|
6613
|
+
}
|
|
6614
|
+
} else {
|
|
6615
|
+
console.error(`${resourcePath} invalid resource path`);
|
|
6616
|
+
return;
|
|
6617
|
+
}
|
|
6618
|
+
Config.setResourceBundle(bundle);
|
|
6619
|
+
}
|
|
6620
|
+
}
|
|
6621
|
+
static #processFile(filePath, bundle) {
|
|
6622
|
+
const locale = Config.getLocale(), defaultLocale = Config.getDefaultLocale(), fileContent = getFileContent(filePath), ext = getFileExtenstion(filePath);
|
|
6623
|
+
if (RES_FILE_EXTENSIONS.includes(ext)) {
|
|
6624
|
+
if (!fileContent) {
|
|
6625
|
+
console.error(`${filePath} is empty or invalid`);
|
|
6626
|
+
return;
|
|
6627
|
+
}
|
|
6628
|
+
if (filePath.toLowerCase().includes("dnt")) {
|
|
6629
|
+
bundle["dnt"] = fileContent.split(/\r?\n/);
|
|
6630
|
+
} else if (filePath.toLowerCase().includes("ignore")) {
|
|
6631
|
+
bundle["ignore"] = fileContent.split(/\r?\n/);
|
|
6632
|
+
} else if (filePath.includes(locale)) {
|
|
6633
|
+
const lines = fileContent.split(/\r?\n/);
|
|
6634
|
+
bundle[locale] = lines.map(removeHtmlTags);
|
|
6635
|
+
} else if (filePath.includes(defaultLocale)) {
|
|
6636
|
+
bundle[defaultLocale] = fileContent.split(/\r?\n/);
|
|
6637
|
+
}
|
|
6638
|
+
}
|
|
6639
|
+
}
|
|
6640
|
+
}
|
|
6641
|
+
function removeHtmlTags(str) {
|
|
6642
|
+
const htmlTagPattern = /<\/?[^>]+>/gi;
|
|
6643
|
+
return str.replace(htmlTagPattern, "");
|
|
6644
|
+
}
|
|
6645
|
+
const loadDependencies = () => {
|
|
6646
|
+
if (Config.getDriver() && !Config.isLoaded() && Config.getLocale()) {
|
|
6647
|
+
Config.build();
|
|
6648
|
+
Resource.load();
|
|
6649
|
+
Validator.load();
|
|
6650
|
+
Reports.setup();
|
|
6651
|
+
Cache.init();
|
|
6652
|
+
Config.setIsLoaded(true);
|
|
6653
|
+
}
|
|
6654
|
+
};
|
|
6655
|
+
const getRootProjectMainDir = () => {
|
|
6656
|
+
const maxDepth = 10;
|
|
6657
|
+
let currentDir = process.cwd(), currDepth = 0;
|
|
6658
|
+
while (currDepth < maxDepth) {
|
|
6659
|
+
const packageJsonPath = joinPaths(currentDir, "package.json");
|
|
6660
|
+
if (fileExists(packageJsonPath)) {
|
|
6661
|
+
const src = getFileContent(packageJsonPath);
|
|
6662
|
+
const json = JSON.parse(src);
|
|
6663
|
+
const deps = {
|
|
6664
|
+
...json?.dependencies || {},
|
|
6665
|
+
...json?.devDependencies || {},
|
|
6666
|
+
...json?.peerDependencies || {}
|
|
6667
|
+
};
|
|
6668
|
+
if (json.name !== "@zeesoft/i18n-verify" && JSON.stringify(deps).includes('"@zeesoft/i18n-verify"')) {
|
|
6669
|
+
break;
|
|
6670
|
+
}
|
|
6671
|
+
}
|
|
6672
|
+
currentDir = getDirPath(currentDir);
|
|
6673
|
+
currDepth++;
|
|
6674
|
+
}
|
|
6675
|
+
return currentDir;
|
|
6676
|
+
};
|
|
6677
|
+
const getRootProjectPackageJson = (rootProjectPath = getRootProjectMainDir()) => getFileContent(joinPaths(rootProjectPath, "package.json"));
|
|
6678
|
+
const getRootProjectName = () => getRootProjectPackageJson()?.match(/"name": "([^"]+)",/)?.[1] || "";
|
|
6679
|
+
const getConfigFilePath = () => joinPaths(process.cwd(), CONFIG_FILE_NAME);
|
|
6680
|
+
const getConfigTemplate = (type = "") => `{
|
|
6681
|
+
"appName": "${getRootProjectName()}",
|
|
6682
|
+
"type": "${type}", // set automation framework type ${arr2Txt(
|
|
6683
|
+
Object.values(SYSTEM_TYPES)
|
|
6684
|
+
)}
|
|
3601
6685
|
"qaLocale": "", // set the qa locale used in your project
|
|
3602
6686
|
"l10nResourcePath": "./l10nResources", // set the dir path of l10n resources
|
|
3603
6687
|
"l10nReportsPath": "./l10nReports/", // set the dir path of l10n reports
|
|
@@ -3607,6 +6691,752 @@
|
|
|
3607
6691
|
"prefix": "à_",
|
|
3608
6692
|
"suffix": "_海"
|
|
3609
6693
|
},
|
|
3610
|
-
"mode": "${
|
|
6694
|
+
"mode": "${RUN_MODE.I18N}", // should be one of the following: ${Object.values(RUN_MODE).join(", ")}
|
|
3611
6695
|
"garbledChars": [""]
|
|
3612
|
-
}
|
|
6696
|
+
}`;
|
|
6697
|
+
const readConfigFile = () => {
|
|
6698
|
+
const rcFilePath = getConfigFilePath();
|
|
6699
|
+
if (!fileExists(rcFilePath)) {
|
|
6700
|
+
throw new Error(
|
|
6701
|
+
`${CONFIG_FILE_NAME} file is missing. Please add the file in your project root dir`
|
|
6702
|
+
);
|
|
6703
|
+
}
|
|
6704
|
+
let rcFile = getFileContent(rcFilePath);
|
|
6705
|
+
if (!rcFile) {
|
|
6706
|
+
throw new Error(
|
|
6707
|
+
`invalid ${CONFIG_FILE_NAME} file. Please add valid file in your project root dir`
|
|
6708
|
+
);
|
|
6709
|
+
}
|
|
6710
|
+
rcFile = rcFile.replace(/\/\/.+$/gm, "");
|
|
6711
|
+
try {
|
|
6712
|
+
rcFile = JSON.parse(rcFile);
|
|
6713
|
+
} catch (ex) {
|
|
6714
|
+
throw new Error(
|
|
6715
|
+
`invalid ${CONFIG_FILE_NAME} file. Please add valid file in your project root dir`
|
|
6716
|
+
);
|
|
6717
|
+
}
|
|
6718
|
+
return rcFile;
|
|
6719
|
+
};
|
|
6720
|
+
const validateConfig = (config) => {
|
|
6721
|
+
if (typeof config !== "object" || Object.keys(config).length < 1) {
|
|
6722
|
+
throw new Error(`empty ${CONFIG_FILE_NAME} file`);
|
|
6723
|
+
}
|
|
6724
|
+
const missingKeys = [];
|
|
6725
|
+
if (!allPropertyExists(
|
|
6726
|
+
[
|
|
6727
|
+
"l10nResourcePath",
|
|
6728
|
+
"l10nReportsPath",
|
|
6729
|
+
"supportedLocales",
|
|
6730
|
+
"defaultLocale",
|
|
6731
|
+
"type",
|
|
6732
|
+
"mode"
|
|
6733
|
+
],
|
|
6734
|
+
config,
|
|
6735
|
+
missingKeys
|
|
6736
|
+
)) {
|
|
6737
|
+
throw new Error(
|
|
6738
|
+
`following properties are missing in ${CONFIG_FILE_NAME} file: ${arr2Txt(
|
|
6739
|
+
missingKeys
|
|
6740
|
+
)}`
|
|
6741
|
+
);
|
|
6742
|
+
}
|
|
6743
|
+
if (!Object.values(SYSTEM_TYPES).includes(config?.type || "")) {
|
|
6744
|
+
throw new Error(`${CONFIG_FILE_NAME} has invalid system type`);
|
|
6745
|
+
}
|
|
6746
|
+
if (!Object.values(RUN_MODE).includes(config?.mode || "")) {
|
|
6747
|
+
throw new Error(`${CONFIG_FILE_NAME} has invalid mode option`);
|
|
6748
|
+
}
|
|
6749
|
+
};
|
|
6750
|
+
const checkAndExportConfig = (filePath, type = "") => {
|
|
6751
|
+
if (filePath && !fileExists(filePath)) {
|
|
6752
|
+
saveToFile(filePath, getConfigTemplate(type));
|
|
6753
|
+
}
|
|
6754
|
+
};
|
|
6755
|
+
class Config {
|
|
6756
|
+
static #driver;
|
|
6757
|
+
static #executor;
|
|
6758
|
+
static #type;
|
|
6759
|
+
static #mode;
|
|
6760
|
+
static #locale;
|
|
6761
|
+
static #qaLocale;
|
|
6762
|
+
static #options;
|
|
6763
|
+
static #resources;
|
|
6764
|
+
static #ssCount;
|
|
6765
|
+
static #appName;
|
|
6766
|
+
static #isLoaded;
|
|
6767
|
+
static init() {
|
|
6768
|
+
try {
|
|
6769
|
+
const config = readConfigFile();
|
|
6770
|
+
validateConfig(config);
|
|
6771
|
+
this.#type = config?.type;
|
|
6772
|
+
this.#mode = config?.mode;
|
|
6773
|
+
this.#qaLocale = config?.qaLocale;
|
|
6774
|
+
this.#appName = config?.appName;
|
|
6775
|
+
this.#options = config;
|
|
6776
|
+
this.#ssCount = 0;
|
|
6777
|
+
this.getGarbledChars();
|
|
6778
|
+
} catch (ex) {
|
|
6779
|
+
Logger$1.error(ex.message);
|
|
6780
|
+
throw ex;
|
|
6781
|
+
}
|
|
6782
|
+
}
|
|
6783
|
+
static build() {
|
|
6784
|
+
this.#driver = build$1(this.#type, this.#driver);
|
|
6785
|
+
this.resetCounter();
|
|
6786
|
+
}
|
|
6787
|
+
static getGarbledChars() {
|
|
6788
|
+
return [...this.#options.garbledChars || [], ...GARBLED_CHARACTERS];
|
|
6789
|
+
}
|
|
6790
|
+
static getL10nReportsPath() {
|
|
6791
|
+
return this.#options.l10nReportsPath;
|
|
6792
|
+
}
|
|
6793
|
+
static setDriver(driver) {
|
|
6794
|
+
this.#driver = driver;
|
|
6795
|
+
}
|
|
6796
|
+
static setType(type) {
|
|
6797
|
+
this.#type = type;
|
|
6798
|
+
}
|
|
6799
|
+
static setLocale(locale) {
|
|
6800
|
+
this.#locale = locale;
|
|
6801
|
+
}
|
|
6802
|
+
static setOptions(options) {
|
|
6803
|
+
this.#options = options;
|
|
6804
|
+
}
|
|
6805
|
+
static getExecutor() {
|
|
6806
|
+
if (Config.#executor) {
|
|
6807
|
+
return Config.#executor;
|
|
6808
|
+
}
|
|
6809
|
+
if (!Config.#driver) {
|
|
6810
|
+
throw new Error(
|
|
6811
|
+
"Unable to initialize process executor, driver is missing"
|
|
6812
|
+
);
|
|
6813
|
+
}
|
|
6814
|
+
this.#executor = new Executor(this.#driver);
|
|
6815
|
+
return this.#executor;
|
|
6816
|
+
}
|
|
6817
|
+
static getDriver() {
|
|
6818
|
+
return this.#driver;
|
|
6819
|
+
}
|
|
6820
|
+
static getLocale() {
|
|
6821
|
+
return this.#locale;
|
|
6822
|
+
}
|
|
6823
|
+
static getDefaultLocale() {
|
|
6824
|
+
return this.#options.defaultLocale;
|
|
6825
|
+
}
|
|
6826
|
+
static getType() {
|
|
6827
|
+
return this.#type;
|
|
6828
|
+
}
|
|
6829
|
+
static getOptions() {
|
|
6830
|
+
return this.#options;
|
|
6831
|
+
}
|
|
6832
|
+
static setQALocale(locale) {
|
|
6833
|
+
this.#qaLocale = locale;
|
|
6834
|
+
}
|
|
6835
|
+
static getQALocale() {
|
|
6836
|
+
return this.#qaLocale;
|
|
6837
|
+
}
|
|
6838
|
+
static setResourceBundle(resources) {
|
|
6839
|
+
this.#resources = resources;
|
|
6840
|
+
}
|
|
6841
|
+
static getResourceBundle(value) {
|
|
6842
|
+
return this.#resources?.[value] || this.#resources || [];
|
|
6843
|
+
}
|
|
6844
|
+
static incrementCounter() {
|
|
6845
|
+
this.#ssCount++;
|
|
6846
|
+
}
|
|
6847
|
+
static resetCounter() {
|
|
6848
|
+
this.#ssCount = 0;
|
|
6849
|
+
}
|
|
6850
|
+
static getSSCount(incrementCount = false) {
|
|
6851
|
+
return incrementCount ? ++this.#ssCount : this.#ssCount;
|
|
6852
|
+
}
|
|
6853
|
+
static getMode() {
|
|
6854
|
+
return this.#mode;
|
|
6855
|
+
}
|
|
6856
|
+
static isSanityRun() {
|
|
6857
|
+
return this.#mode === RUN_MODE.SANITY;
|
|
6858
|
+
}
|
|
6859
|
+
static isI18nVerificationRun() {
|
|
6860
|
+
return this.#mode === RUN_MODE.I18N;
|
|
6861
|
+
}
|
|
6862
|
+
static isContextRun() {
|
|
6863
|
+
return this.#mode === RUN_MODE.CONTEXT;
|
|
6864
|
+
}
|
|
6865
|
+
static getAppName() {
|
|
6866
|
+
return this.#appName;
|
|
6867
|
+
}
|
|
6868
|
+
static isLoaded() {
|
|
6869
|
+
return this.#isLoaded;
|
|
6870
|
+
}
|
|
6871
|
+
static setIsLoaded(value) {
|
|
6872
|
+
this.#isLoaded = value;
|
|
6873
|
+
}
|
|
6874
|
+
}
|
|
6875
|
+
class BaseRunner {
|
|
6876
|
+
/**
|
|
6877
|
+
* @type {import('../../driver/baseDriver.js').default}
|
|
6878
|
+
*/
|
|
6879
|
+
#driver;
|
|
6880
|
+
/**
|
|
6881
|
+
* @type {String}
|
|
6882
|
+
*/
|
|
6883
|
+
#verificationArea;
|
|
6884
|
+
/**
|
|
6885
|
+
* @type {Array<String>}
|
|
6886
|
+
*/
|
|
6887
|
+
#selectors;
|
|
6888
|
+
/**
|
|
6889
|
+
* @type {String}
|
|
6890
|
+
*/
|
|
6891
|
+
#description;
|
|
6892
|
+
/**
|
|
6893
|
+
* @type {Array<String>}
|
|
6894
|
+
*/
|
|
6895
|
+
#preparedSelectors = [];
|
|
6896
|
+
/**
|
|
6897
|
+
* @type {String}
|
|
6898
|
+
*/
|
|
6899
|
+
#preparedSelector;
|
|
6900
|
+
/**
|
|
6901
|
+
* @type {String}
|
|
6902
|
+
*/
|
|
6903
|
+
#baseImageName;
|
|
6904
|
+
/**
|
|
6905
|
+
* @type {Element}
|
|
6906
|
+
*/
|
|
6907
|
+
#verificationAreaEl;
|
|
6908
|
+
/**
|
|
6909
|
+
* @type {{x:Number, y: Number, height: Number, width: Number}}
|
|
6910
|
+
*/
|
|
6911
|
+
#verificationAreaOffsets;
|
|
6912
|
+
/**
|
|
6913
|
+
* @type {Boolean}
|
|
6914
|
+
*/
|
|
6915
|
+
#useSmartSelector;
|
|
6916
|
+
constructor(driver, verificationArea, selectors, useSmartSelector, description) {
|
|
6917
|
+
this.#driver = driver;
|
|
6918
|
+
this.#verificationArea = verificationArea;
|
|
6919
|
+
this.#selectors = selectors;
|
|
6920
|
+
this.#useSmartSelector = useSmartSelector;
|
|
6921
|
+
this.#description = description;
|
|
6922
|
+
}
|
|
6923
|
+
async run() {
|
|
6924
|
+
try {
|
|
6925
|
+
await this.#preRun();
|
|
6926
|
+
if (this.shouldCollectStrings()) {
|
|
6927
|
+
await this.#executeStringProcess();
|
|
6928
|
+
} else {
|
|
6929
|
+
await this.#executePageProcess();
|
|
6930
|
+
}
|
|
6931
|
+
} catch (ex) {
|
|
6932
|
+
Logger$1.error("unable to run the process", ex);
|
|
6933
|
+
} finally {
|
|
6934
|
+
await this.#postRun();
|
|
6935
|
+
}
|
|
6936
|
+
}
|
|
6937
|
+
/**---------------------public helper methods----------------------*/
|
|
6938
|
+
// should be implemented by child classes
|
|
6939
|
+
async process(_string, _element, _offsets, _frameId) {
|
|
6940
|
+
throw new Error("should be implemeneted by the child class");
|
|
6941
|
+
}
|
|
6942
|
+
// can be implemented by child classes to avoid collecting strings and looping to each item
|
|
6943
|
+
shouldCollectStrings() {
|
|
6944
|
+
return true;
|
|
6945
|
+
}
|
|
6946
|
+
// can be implemented by child classes to configure dependencies
|
|
6947
|
+
async preProcess() {
|
|
6948
|
+
}
|
|
6949
|
+
// can be implemented by child classes to perform cleanup tasks
|
|
6950
|
+
async postProcess() {
|
|
6951
|
+
}
|
|
6952
|
+
async captureScreen(imagePath) {
|
|
6953
|
+
try {
|
|
6954
|
+
await this.#driver.captureScreenshot(imagePath);
|
|
6955
|
+
Logger$1.debug("reviewed image has been saved");
|
|
6956
|
+
return true;
|
|
6957
|
+
} catch (ex) {
|
|
6958
|
+
Logger$1.error("unable to capture screenshot");
|
|
6959
|
+
return false;
|
|
6960
|
+
}
|
|
6961
|
+
}
|
|
6962
|
+
getBaseImageName() {
|
|
6963
|
+
return this.#baseImageName;
|
|
6964
|
+
}
|
|
6965
|
+
getDescription() {
|
|
6966
|
+
return this.#description;
|
|
6967
|
+
}
|
|
6968
|
+
getVerificationArea() {
|
|
6969
|
+
return this.#verificationArea;
|
|
6970
|
+
}
|
|
6971
|
+
getVerificationAreaEl() {
|
|
6972
|
+
return this.#verificationAreaEl;
|
|
6973
|
+
}
|
|
6974
|
+
getVerificationAreaOffsets() {
|
|
6975
|
+
return this.#verificationAreaOffsets;
|
|
6976
|
+
}
|
|
6977
|
+
getDriver() {
|
|
6978
|
+
return this.#driver;
|
|
6979
|
+
}
|
|
6980
|
+
async getElementOffsets(element) {
|
|
6981
|
+
const offset = await this.#driver.getElementDimension(element);
|
|
6982
|
+
return {
|
|
6983
|
+
x: offset[0],
|
|
6984
|
+
y: offset[1],
|
|
6985
|
+
height: offset[2],
|
|
6986
|
+
width: offset[3]
|
|
6987
|
+
};
|
|
6988
|
+
}
|
|
6989
|
+
/**---------------------private helper methods----------------------*/
|
|
6990
|
+
async #executeStringProcess() {
|
|
6991
|
+
if (this.#preparedSelectors.length) {
|
|
6992
|
+
await this.#processLocatorElements();
|
|
6993
|
+
await this.#processIFrames();
|
|
6994
|
+
} else {
|
|
6995
|
+
Logger$1.debug("No locators provided");
|
|
6996
|
+
}
|
|
6997
|
+
}
|
|
6998
|
+
async #executePageProcess() {
|
|
6999
|
+
await this.process(this.#description);
|
|
7000
|
+
}
|
|
7001
|
+
async #preRun() {
|
|
7002
|
+
this.#prepareXpaths();
|
|
7003
|
+
this.#prepareBaseImage();
|
|
7004
|
+
await this.#prepareVerificationArea();
|
|
7005
|
+
await this.#collectReviewedImage();
|
|
7006
|
+
await this.preProcess();
|
|
7007
|
+
}
|
|
7008
|
+
async #postRun() {
|
|
7009
|
+
await this.postProcess();
|
|
7010
|
+
}
|
|
7011
|
+
#prepareXpaths() {
|
|
7012
|
+
const verificationArea = this.#verificationArea || "";
|
|
7013
|
+
if (this.#selectors?.length > 0) {
|
|
7014
|
+
for (const selector of this.#selectors) {
|
|
7015
|
+
this.#preparedSelectors.push(verificationArea + selector);
|
|
7016
|
+
}
|
|
7017
|
+
}
|
|
7018
|
+
if (this.#useSmartSelector) {
|
|
7019
|
+
this.#preparedSelector = verificationArea !== "" ? verificationArea + SMART_SELECTOR : SMART_SELECTOR;
|
|
7020
|
+
this.#preparedSelectors.push(this.#preparedSelector.toString());
|
|
7021
|
+
}
|
|
7022
|
+
}
|
|
7023
|
+
#prepareBaseImage() {
|
|
7024
|
+
this.#baseImageName = `${Config.getSSCount(true).toString().padStart(3, "0")}_${this.#description.replace(/[^\w\s]/gi, "").replace(/\s+/g, "")}.png`;
|
|
7025
|
+
}
|
|
7026
|
+
async #collectReviewedImage() {
|
|
7027
|
+
const path2 = joinPaths(Reports.reviewedReports(), this.#baseImageName);
|
|
7028
|
+
await this.captureScreen(path2);
|
|
7029
|
+
}
|
|
7030
|
+
async #prepareVerificationArea() {
|
|
7031
|
+
this.#verificationAreaEl = await this.#driver.getElement(
|
|
7032
|
+
this.#verificationArea
|
|
7033
|
+
);
|
|
7034
|
+
if (this.#verificationAreaEl) {
|
|
7035
|
+
this.#verificationAreaOffsets = await this.getElementOffsets(
|
|
7036
|
+
this.#verificationAreaEl
|
|
7037
|
+
);
|
|
7038
|
+
} else {
|
|
7039
|
+
throw new Error("invalid verification area selector is supplied");
|
|
7040
|
+
}
|
|
7041
|
+
}
|
|
7042
|
+
async #processLocatorElements() {
|
|
7043
|
+
let hasElements = false;
|
|
7044
|
+
for (const locator of this.#preparedSelectors) {
|
|
7045
|
+
const elements = await this.#driver.getElements(locator, true);
|
|
7046
|
+
if (elements?.length) {
|
|
7047
|
+
!hasElements && (hasElements = true);
|
|
7048
|
+
for (const el of elements) {
|
|
7049
|
+
await this.#processElement(el, true);
|
|
7050
|
+
}
|
|
7051
|
+
}
|
|
7052
|
+
}
|
|
7053
|
+
if (!hasElements) {
|
|
7054
|
+
Logger$1.debug("No UI elements found from the provided locators");
|
|
7055
|
+
}
|
|
7056
|
+
}
|
|
7057
|
+
async #processIFrames() {
|
|
7058
|
+
if (await this.#driver.checkIfIframeIsPresent()) {
|
|
7059
|
+
const frames = await this.#driver.getElements("//iframe");
|
|
7060
|
+
Logger$1.debug(
|
|
7061
|
+
`Total ${frames.length} iframes are located on the ${this.#description}`
|
|
7062
|
+
);
|
|
7063
|
+
for (let fID = 0; fID < frames.length; fID++) {
|
|
7064
|
+
const frame = frames[fID];
|
|
7065
|
+
const offsets = await this.getElementOffsets(frame);
|
|
7066
|
+
Logger$1.debug(`Switching to iFrame: ${fID}`);
|
|
7067
|
+
await this.#driver.switchToIFrame(fID, frame);
|
|
7068
|
+
this.#driver.pause(1);
|
|
7069
|
+
const iframeBody = await this.#driver.getElement("//body");
|
|
7070
|
+
await this.#driver.isElementPresent(iframeBody);
|
|
7071
|
+
let hasAtLeastOneString = false;
|
|
7072
|
+
if (!await this.#driver.checkIfIframeBodyIsEmpty()) {
|
|
7073
|
+
const iframeElements = await this.#driver.getElements(
|
|
7074
|
+
SMART_SELECTOR,
|
|
7075
|
+
true
|
|
7076
|
+
);
|
|
7077
|
+
if (iframeElements?.length) {
|
|
7078
|
+
for (const el of iframeElements) {
|
|
7079
|
+
const result = await this.#processElement(el, true, offsets, fID);
|
|
7080
|
+
!hasAtLeastOneString && result && (hasAtLeastOneString = true);
|
|
7081
|
+
}
|
|
7082
|
+
}
|
|
7083
|
+
}
|
|
7084
|
+
!hasAtLeastOneString && Logger$1.debug("No valid UI elements found in the iFrame");
|
|
7085
|
+
await this.#driver.switchToParentFrame();
|
|
7086
|
+
}
|
|
7087
|
+
}
|
|
7088
|
+
}
|
|
7089
|
+
async #processElement(element, collectAll = false, offsets, frameId) {
|
|
7090
|
+
if (await this.#isValidElement(element)) {
|
|
7091
|
+
const strings = collectAll ? await this.#driver.getElementStrings(element) : [await this.#driver.getElementString(element)];
|
|
7092
|
+
if (strings?.length) {
|
|
7093
|
+
for (const string of strings) {
|
|
7094
|
+
try {
|
|
7095
|
+
await this.process(string, element, offsets, frameId);
|
|
7096
|
+
} catch (ex) {
|
|
7097
|
+
Logger$1.error(
|
|
7098
|
+
`unable to process the ${frameId ? `iframe-[${frameId}] ` : ""}string "${string}"`,
|
|
7099
|
+
ex
|
|
7100
|
+
);
|
|
7101
|
+
}
|
|
7102
|
+
}
|
|
7103
|
+
return true;
|
|
7104
|
+
} else {
|
|
7105
|
+
return false;
|
|
7106
|
+
}
|
|
7107
|
+
} else {
|
|
7108
|
+
return false;
|
|
7109
|
+
}
|
|
7110
|
+
}
|
|
7111
|
+
async #isValidElement(element) {
|
|
7112
|
+
return element && await this.#driver.isElementDisplayed(element);
|
|
7113
|
+
}
|
|
7114
|
+
}
|
|
7115
|
+
class ContextRunner extends BaseRunner {
|
|
7116
|
+
#data = {
|
|
7117
|
+
screenshot: "",
|
|
7118
|
+
category: "",
|
|
7119
|
+
fileName: "",
|
|
7120
|
+
bookmark: true,
|
|
7121
|
+
pageTitle: "",
|
|
7122
|
+
strings: {}
|
|
7123
|
+
};
|
|
7124
|
+
#contextCount = 0;
|
|
7125
|
+
#stringIdPrefix = "";
|
|
7126
|
+
constructor(...args) {
|
|
7127
|
+
super(...args);
|
|
7128
|
+
}
|
|
7129
|
+
/**
|
|
7130
|
+
* @override
|
|
7131
|
+
*/
|
|
7132
|
+
async preProcess() {
|
|
7133
|
+
this.#determineContextsCounts();
|
|
7134
|
+
this.#configureCategory();
|
|
7135
|
+
this.#configurePageTitle();
|
|
7136
|
+
this.#configureFileName();
|
|
7137
|
+
this.#configureStringId();
|
|
7138
|
+
}
|
|
7139
|
+
/**
|
|
7140
|
+
*
|
|
7141
|
+
* @override
|
|
7142
|
+
*/
|
|
7143
|
+
async process(string, element, offsets) {
|
|
7144
|
+
Reports.incrementCount(
|
|
7145
|
+
I18N_STATUS.REVIEWED,
|
|
7146
|
+
string,
|
|
7147
|
+
this.getBaseImageName(),
|
|
7148
|
+
this.getDescription()
|
|
7149
|
+
);
|
|
7150
|
+
Logger$1.debug(`context creation for "${string}"`);
|
|
7151
|
+
await this.#addToContext(string, element, offsets);
|
|
7152
|
+
}
|
|
7153
|
+
/**
|
|
7154
|
+
* @override
|
|
7155
|
+
*/
|
|
7156
|
+
async postProcess() {
|
|
7157
|
+
this.#prepareImage();
|
|
7158
|
+
const data2 = this.#getJsonData();
|
|
7159
|
+
saveToFile(
|
|
7160
|
+
joinPaths(Reports.getContextPath(), `${this.#data.fileName}.json`),
|
|
7161
|
+
JSON.stringify(data2)
|
|
7162
|
+
);
|
|
7163
|
+
CacheData.incrementCountByType("context");
|
|
7164
|
+
}
|
|
7165
|
+
#determineContextsCounts() {
|
|
7166
|
+
this.#contextCount = getDirContents(Reports.getContextPath()).length + 1;
|
|
7167
|
+
}
|
|
7168
|
+
#configureCategory() {
|
|
7169
|
+
this.#data.category = this.getDescription();
|
|
7170
|
+
}
|
|
7171
|
+
#configurePageTitle() {
|
|
7172
|
+
this.#data.pageTitle = `TC-${Config.getAppName()}-${this.getDescription().trim().slice(0, 2).toUpperCase()}-${`${this.#contextCount}`.padStart(3, "0")}`;
|
|
7173
|
+
}
|
|
7174
|
+
#configureFileName() {
|
|
7175
|
+
this.#data.fileName = `${toFileNameFormat(Config.getAppName())}-${`${this.#contextCount}`.padStart(3, "0")}`;
|
|
7176
|
+
}
|
|
7177
|
+
#configureStringId() {
|
|
7178
|
+
this.#stringIdPrefix = `${toFileNameFormat(Config.getAppName())}_${`${this.#contextCount}`.padStart(3, "0")}`;
|
|
7179
|
+
}
|
|
7180
|
+
#prepareImage() {
|
|
7181
|
+
this.#data.screenshot = `data:image/png;base64,${imageToBase64(
|
|
7182
|
+
joinPaths(Reports.reviewedReports(), this.getBaseImageName())
|
|
7183
|
+
)}`;
|
|
7184
|
+
}
|
|
7185
|
+
#getJsonData() {
|
|
7186
|
+
return {
|
|
7187
|
+
[CONTEXT_FILE_KEYS.BOOKMARK]: this.#data.bookmark,
|
|
7188
|
+
[CONTEXT_FILE_KEYS.CATEGORY]: this.#data.category,
|
|
7189
|
+
[CONTEXT_FILE_KEYS.FILE_NAME]: this.#data.fileName,
|
|
7190
|
+
[CONTEXT_FILE_KEYS.SCREENSHOT]: this.#data.screenshot,
|
|
7191
|
+
[CONTEXT_FILE_KEYS.STRINGS]: JSON.stringify(this.#data.strings)
|
|
7192
|
+
};
|
|
7193
|
+
}
|
|
7194
|
+
async #addToContext(string, element, offsets) {
|
|
7195
|
+
const elRec = await this.getElementOffsets(element), uniqueId = `${this.#stringIdPrefix}_${`${Object.keys(this.#data.strings).length + 1}`.padStart(3, "0")}`;
|
|
7196
|
+
if (offsets && Object.keys(offsets || {}).length) {
|
|
7197
|
+
const areaRec = offsets;
|
|
7198
|
+
const keysToUpdate = ["x", "y"];
|
|
7199
|
+
for (const key of keysToUpdate) {
|
|
7200
|
+
if (key in elRec && key in areaRec) {
|
|
7201
|
+
elRec[key] += areaRec[key];
|
|
7202
|
+
}
|
|
7203
|
+
}
|
|
7204
|
+
}
|
|
7205
|
+
this.#data.strings[uniqueId] = {
|
|
7206
|
+
text: string,
|
|
7207
|
+
coordinates: {
|
|
7208
|
+
...elRec
|
|
7209
|
+
}
|
|
7210
|
+
};
|
|
7211
|
+
}
|
|
7212
|
+
}
|
|
7213
|
+
class Graphic {
|
|
7214
|
+
/**
|
|
7215
|
+
* Draws a rectangle on an image.
|
|
7216
|
+
* @param {object} eleRec - The element rectangle object.
|
|
7217
|
+
* @param {string} color - The color of the rectangle border.
|
|
7218
|
+
* @param {string} report_img - The path to the image file.
|
|
7219
|
+
*/
|
|
7220
|
+
static async drawRectangle(eleRec, color, report_img) {
|
|
7221
|
+
const rectX = eleRec?.x - 2;
|
|
7222
|
+
const rectY = eleRec?.y - 2;
|
|
7223
|
+
const rectWidth = eleRec?.width + 2;
|
|
7224
|
+
const rectHeight = eleRec?.height + 2;
|
|
7225
|
+
const thickness = 2;
|
|
7226
|
+
try {
|
|
7227
|
+
const image = await Jimp.read(report_img);
|
|
7228
|
+
const rectangleColor = Jimp.cssColorToHex(color);
|
|
7229
|
+
this.drawRectangleOutline(
|
|
7230
|
+
image,
|
|
7231
|
+
rectX,
|
|
7232
|
+
rectY,
|
|
7233
|
+
rectWidth,
|
|
7234
|
+
rectHeight,
|
|
7235
|
+
rectangleColor,
|
|
7236
|
+
thickness
|
|
7237
|
+
);
|
|
7238
|
+
const targetDir = path.dirname(report_img);
|
|
7239
|
+
const buffer = await image.getBufferAsync(Jimp.MIME_PNG);
|
|
7240
|
+
if (!fs.existsSync(targetDir)) {
|
|
7241
|
+
Logger$1.debug("folder not found");
|
|
7242
|
+
fs.mkdirSync(targetDir, { recursive: true });
|
|
7243
|
+
}
|
|
7244
|
+
fs.writeFileSync(report_img, buffer);
|
|
7245
|
+
} catch (err) {
|
|
7246
|
+
Logger$1.error(`Error: ${err}`);
|
|
7247
|
+
}
|
|
7248
|
+
}
|
|
7249
|
+
static async drawRectangleOutline(image, x, y, width, height, color, thickness) {
|
|
7250
|
+
for (let i = x; i < x + width; i++) {
|
|
7251
|
+
for (let t = 0; t < thickness; t++) {
|
|
7252
|
+
image.setPixelColor(color, i, y + t);
|
|
7253
|
+
image.setPixelColor(color, i, y + height - 1 - t);
|
|
7254
|
+
}
|
|
7255
|
+
}
|
|
7256
|
+
for (let j = y; j < y + height; j++) {
|
|
7257
|
+
for (let t = 0; t < thickness; t++) {
|
|
7258
|
+
image.setPixelColor(color, x + t, j);
|
|
7259
|
+
image.setPixelColor(color, x + width - 1 - t, j);
|
|
7260
|
+
}
|
|
7261
|
+
}
|
|
7262
|
+
}
|
|
7263
|
+
}
|
|
7264
|
+
class I18nRunner extends BaseRunner {
|
|
7265
|
+
constructor(...args) {
|
|
7266
|
+
super(...args);
|
|
7267
|
+
}
|
|
7268
|
+
/**
|
|
7269
|
+
*
|
|
7270
|
+
* @override
|
|
7271
|
+
*/
|
|
7272
|
+
async process(string, element, offsets) {
|
|
7273
|
+
if (typeof string !== "string" || !string || Number(string) === 0) {
|
|
7274
|
+
return;
|
|
7275
|
+
}
|
|
7276
|
+
const src_img = joinPaths(
|
|
7277
|
+
Reports.reviewedReports(string, this.getBaseImageName()),
|
|
7278
|
+
this.getBaseImageName()
|
|
7279
|
+
), status = Validator.getIssueType(string), dest_img = joinPaths(
|
|
7280
|
+
Reports[status](string, this.getBaseImageName()),
|
|
7281
|
+
this.getBaseImageName()
|
|
7282
|
+
);
|
|
7283
|
+
Reports.incrementCount(
|
|
7284
|
+
I18N_STATUS.REVIEWED,
|
|
7285
|
+
string,
|
|
7286
|
+
this.getBaseImageName(),
|
|
7287
|
+
this.getDescription()
|
|
7288
|
+
);
|
|
7289
|
+
if (!existsSync(src_img)) {
|
|
7290
|
+
copyFileSync(
|
|
7291
|
+
joinPaths(Reports.reviewedReports(), this.getBaseImageName()),
|
|
7292
|
+
src_img
|
|
7293
|
+
);
|
|
7294
|
+
}
|
|
7295
|
+
if (existsSync(src_img) && !existsSync(dest_img)) {
|
|
7296
|
+
copyFileSync(src_img, dest_img);
|
|
7297
|
+
}
|
|
7298
|
+
const color = this.#defineColor(status, string);
|
|
7299
|
+
Reports.incrementCount(status, string, dest_img, this.getDescription());
|
|
7300
|
+
await this.#highlightString(element, color, dest_img, offsets);
|
|
7301
|
+
}
|
|
7302
|
+
/**-----------------private helper methods----------------*/
|
|
7303
|
+
async #highlightString(element, color, image, offsets) {
|
|
7304
|
+
await this.#highlightStringInUI(element, color);
|
|
7305
|
+
await this.#highlightStringInReport(element, color, image, offsets);
|
|
7306
|
+
}
|
|
7307
|
+
async #highlightStringInUI(element, color) {
|
|
7308
|
+
await this.getDriver().onScreenStringHighlight(element, color);
|
|
7309
|
+
}
|
|
7310
|
+
async #highlightStringInReport(element, color, image, offsets) {
|
|
7311
|
+
let areaRec;
|
|
7312
|
+
const elRec = await this.getElementOffsets(element), areaColor = COLOR.GRB_BLUE;
|
|
7313
|
+
if (offsets) {
|
|
7314
|
+
areaRec = offsets;
|
|
7315
|
+
const keysToUpdate = ["x", "y"];
|
|
7316
|
+
for (const key of keysToUpdate) {
|
|
7317
|
+
if (key in elRec && key in areaRec) {
|
|
7318
|
+
elRec[key] = areaRec[key] + elRec[key];
|
|
7319
|
+
}
|
|
7320
|
+
}
|
|
7321
|
+
} else {
|
|
7322
|
+
areaRec = this.getVerificationAreaOffsets();
|
|
7323
|
+
}
|
|
7324
|
+
await Graphic.drawRectangle(areaRec, areaColor, image);
|
|
7325
|
+
await Graphic.drawRectangle(elRec, color, image);
|
|
7326
|
+
}
|
|
7327
|
+
#defineColor(status, string) {
|
|
7328
|
+
Logger$1.debug(
|
|
7329
|
+
`"${string}" - ${STATUS_COLOR[status][1]}${STATUS_INFO[status]}${"\x1B[0m"}`
|
|
7330
|
+
);
|
|
7331
|
+
return STATUS_COLOR[status][0];
|
|
7332
|
+
}
|
|
7333
|
+
}
|
|
7334
|
+
class SanityRunner extends BaseRunner {
|
|
7335
|
+
constructor(...args) {
|
|
7336
|
+
super(...args);
|
|
7337
|
+
}
|
|
7338
|
+
/**
|
|
7339
|
+
* @override
|
|
7340
|
+
*/
|
|
7341
|
+
shouldCollectStrings() {
|
|
7342
|
+
return false;
|
|
7343
|
+
}
|
|
7344
|
+
/**
|
|
7345
|
+
*
|
|
7346
|
+
* @override
|
|
7347
|
+
*/
|
|
7348
|
+
async process(page) {
|
|
7349
|
+
Logger$1.info(`${page} loaded`);
|
|
7350
|
+
const src_img = joinPaths(
|
|
7351
|
+
Reports.reviewedReports(page, this.getBaseImageName()),
|
|
7352
|
+
this.getBaseImageName()
|
|
7353
|
+
);
|
|
7354
|
+
Reports.incrementCount(
|
|
7355
|
+
I18N_STATUS.REVIEWED,
|
|
7356
|
+
page,
|
|
7357
|
+
src_img,
|
|
7358
|
+
this.getDescription()
|
|
7359
|
+
);
|
|
7360
|
+
if (!existsSync(src_img)) {
|
|
7361
|
+
copyFileSync(
|
|
7362
|
+
joinPaths(Reports.reviewedReports(), this.getBaseImageName()),
|
|
7363
|
+
src_img
|
|
7364
|
+
);
|
|
7365
|
+
}
|
|
7366
|
+
}
|
|
7367
|
+
}
|
|
7368
|
+
const build = (driver, verificationArea, selectors, useSmartSelector, description) => {
|
|
7369
|
+
switch (Config.getMode()) {
|
|
7370
|
+
case RUN_MODE.I18N:
|
|
7371
|
+
return new I18nRunner(
|
|
7372
|
+
driver,
|
|
7373
|
+
verificationArea,
|
|
7374
|
+
selectors,
|
|
7375
|
+
useSmartSelector,
|
|
7376
|
+
description
|
|
7377
|
+
);
|
|
7378
|
+
case RUN_MODE.CONTEXT:
|
|
7379
|
+
return new ContextRunner(
|
|
7380
|
+
driver,
|
|
7381
|
+
verificationArea,
|
|
7382
|
+
selectors,
|
|
7383
|
+
useSmartSelector,
|
|
7384
|
+
description
|
|
7385
|
+
);
|
|
7386
|
+
case RUN_MODE.SANITY:
|
|
7387
|
+
return new SanityRunner(
|
|
7388
|
+
driver,
|
|
7389
|
+
verificationArea,
|
|
7390
|
+
selectors,
|
|
7391
|
+
useSmartSelector,
|
|
7392
|
+
description
|
|
7393
|
+
);
|
|
7394
|
+
default:
|
|
7395
|
+
throw new Error("unsupported runner type");
|
|
7396
|
+
}
|
|
7397
|
+
};
|
|
7398
|
+
class Executor {
|
|
7399
|
+
/**
|
|
7400
|
+
* @type {import('../driver/baseDriver.js').default}
|
|
7401
|
+
*/
|
|
7402
|
+
#driver;
|
|
7403
|
+
/**
|
|
7404
|
+
* @param {BaseDriver} driver
|
|
7405
|
+
*/
|
|
7406
|
+
constructor(driver) {
|
|
7407
|
+
this.#driver = driver;
|
|
7408
|
+
}
|
|
7409
|
+
/**
|
|
7410
|
+
* @param {string} verificationArea - xpath selector of verification area
|
|
7411
|
+
* @param {string} staticLocators - user parsed xpath selectors to find text of elements under verification area
|
|
7412
|
+
* @param {string} description - identity of verification area ex: page, popup, form etc name
|
|
7413
|
+
*/
|
|
7414
|
+
async start({
|
|
7415
|
+
verificationArea,
|
|
7416
|
+
staticLocators,
|
|
7417
|
+
useSmartSelector,
|
|
7418
|
+
description
|
|
7419
|
+
}) {
|
|
7420
|
+
const runner = build(
|
|
7421
|
+
this.#driver,
|
|
7422
|
+
verificationArea,
|
|
7423
|
+
staticLocators,
|
|
7424
|
+
useSmartSelector,
|
|
7425
|
+
description
|
|
7426
|
+
);
|
|
7427
|
+
await runner.run();
|
|
7428
|
+
}
|
|
7429
|
+
}
|
|
7430
|
+
export {
|
|
7431
|
+
Config as C,
|
|
7432
|
+
Executor as E,
|
|
7433
|
+
Logger$1 as L,
|
|
7434
|
+
Reports as R,
|
|
7435
|
+
SYSTEM_TYPES as S,
|
|
7436
|
+
getRootProjectPackageJson as a,
|
|
7437
|
+
CONFIG_FILE_NAME as b,
|
|
7438
|
+
checkAndExportConfig as c,
|
|
7439
|
+
getRootProjectMainDir as g,
|
|
7440
|
+
joinPaths as j,
|
|
7441
|
+
loadDependencies as l
|
|
7442
|
+
};
|