@bigbinary/neeto-commons-frontend 3.0.7 → 3.0.10
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/cjs/configs/babel.js +50 -0
- package/cjs/configs/eslint/globals.js +14 -0
- package/cjs/configs/eslint/helpers/index.js +74 -0
- package/cjs/configs/eslint/imports/enforced.js +29 -0
- package/cjs/configs/eslint/imports/order.js +65 -0
- package/cjs/configs/eslint/index.js +171 -0
- package/cjs/configs/eslint/overrides.js +26 -0
- package/cjs/configs/eslint/promise.js +8 -0
- package/cjs/configs/eslint/react.js +92 -0
- package/cjs/configs/nanos/eslint/imports/order.js +25 -0
- package/cjs/configs/nanos/eslint/index.js +28 -0
- package/cjs/configs/nanos/tailwind.js +11 -0
- package/cjs/configs/nanos/webpack/resolve.js +48 -0
- package/cjs/configs/nextjs/eslint/imports/order.js +25 -0
- package/cjs/configs/nextjs/eslint/index.js +22 -0
- package/cjs/configs/nextjs/webpack/resolve.js +1 -0
- package/cjs/configs/prettier.js +16 -0
- package/cjs/configs/scripts/dead-code-eliminator/constants.js +12 -0
- package/cjs/configs/scripts/dead-code-eliminator/index.js +266 -0
- package/cjs/configs/scripts/getPkgTranslations.js +45 -0
- package/cjs/configs/scripts/jsdoc-builder/constants.mjs +42 -0
- package/cjs/configs/scripts/jsdoc-builder/index.mjs +67 -0
- package/cjs/configs/scripts/jsdoc-builder/utils.mjs +219 -0
- package/cjs/configs/scripts/remove-unused-translation-keys/constants.js +11 -0
- package/cjs/configs/scripts/remove-unused-translation-keys/index.js +186 -0
- package/cjs/configs/tailwind.js +13 -0
- package/cjs/configs/webpack/helpers/customize-default-rules.js +54 -0
- package/cjs/configs/webpack/index.js +59 -0
- package/cjs/configs/webpack/resolve.js +53 -0
- package/cjs/configs/webpack/rules.js +34 -0
- package/cjs/cypress-configs/initializer.js +32 -0
- package/cjs/cypress-configs/plugins.js +105 -0
- package/cjs/cypress-configs/resolve.js +17 -0
- package/cjs/cypress-configs/webpack.config.js +19 -0
- package/cjs/initializers/axios/index.js +1 -2
- package/cjs/initializers/axios/index.js.map +1 -1
- package/cjs/initializers/constants.js +9 -3
- package/cjs/initializers/constants.js.map +1 -1
- package/cjs/initializers/i18n.js +8 -2
- package/cjs/initializers/i18n.js.map +1 -1
- package/cjs/initializers/utils/customFormatters.js +17 -8
- package/cjs/initializers/utils/customFormatters.js.map +1 -1
- package/cjs/translations/en.json +100 -0
- package/configs/eslint/overrides.js +3 -7
- package/configs/webpack/index.js +1 -0
- package/initializers/axios/index.js +2 -3
- package/initializers/axios/index.js.map +1 -1
- package/initializers/constants.js +6 -1
- package/initializers/constants.js.map +1 -1
- package/initializers/i18n.js +9 -3
- package/initializers/i18n.js.map +1 -1
- package/initializers/utils/customFormatters.js +16 -7
- package/initializers/utils/customFormatters.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
|
|
4
|
+
import * as babelParser from "@babel/parser";
|
|
5
|
+
import { curry, __, mergeLeft } from "ramda";
|
|
6
|
+
import remarkParse from "remark-parse";
|
|
7
|
+
import { unified } from "unified";
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
ASTERISK,
|
|
11
|
+
ASTERISK_WITH_SPACES,
|
|
12
|
+
CODE_PATTERN,
|
|
13
|
+
DOUBLE_LINE_BREAK_WITH_LEADING_COMMENT,
|
|
14
|
+
EXPORTED_TYPES_FOLDER_NAME,
|
|
15
|
+
HTML_EXCEPT_IMG_PATTERN,
|
|
16
|
+
IMG_PATTERN,
|
|
17
|
+
JSDOC_EXAMPLE_TAG,
|
|
18
|
+
JSDOC_END_EXAMPLE_TAG,
|
|
19
|
+
JSDOC_IMG_HEIGHT,
|
|
20
|
+
JSDOC_IMG_WIDTH,
|
|
21
|
+
LINE_BREAK,
|
|
22
|
+
PARAGRAPH_PATTERN,
|
|
23
|
+
SUBHEADING_PATTERN,
|
|
24
|
+
TYPES_FOLDER_NAME,
|
|
25
|
+
WHITESPACE_PARENTHESIS_REGEX,
|
|
26
|
+
} from "./constants.mjs";
|
|
27
|
+
import * as babelTypes from "@babel/types";
|
|
28
|
+
import _traverse from "@babel/traverse";
|
|
29
|
+
import _generate from "@babel/generator";
|
|
30
|
+
|
|
31
|
+
import { matches } from "@bigbinary/neeto-cist";
|
|
32
|
+
|
|
33
|
+
const traverse = _traverse.default;
|
|
34
|
+
const generate = _generate.default;
|
|
35
|
+
|
|
36
|
+
const removeWhiteSpaceAndParentheses = string =>
|
|
37
|
+
string.replace(WHITESPACE_PARENTHESIS_REGEX, "");
|
|
38
|
+
|
|
39
|
+
const addLeadingCommentForTextWithLineBreaks = ({
|
|
40
|
+
text,
|
|
41
|
+
addCommentForFirstItem = true,
|
|
42
|
+
addDoubleLineBreaks = true,
|
|
43
|
+
}) => {
|
|
44
|
+
if (!hasLineBreaks(text)) return addLeadingComment(text);
|
|
45
|
+
const joinString = addDoubleLineBreaks
|
|
46
|
+
? DOUBLE_LINE_BREAK_WITH_LEADING_COMMENT
|
|
47
|
+
: LINE_BREAK;
|
|
48
|
+
|
|
49
|
+
return text
|
|
50
|
+
.split(LINE_BREAK)
|
|
51
|
+
.map((item, idx) => {
|
|
52
|
+
if (!addCommentForFirstItem && idx === 0) return item;
|
|
53
|
+
|
|
54
|
+
return addLeadingComment(item);
|
|
55
|
+
})
|
|
56
|
+
.join(joinString);
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const addLeadingComment = (text, trimWhiteSpace = false) =>
|
|
60
|
+
(trimWhiteSpace ? ASTERISK : ASTERISK_WITH_SPACES) + text;
|
|
61
|
+
|
|
62
|
+
const transformCode = node => {
|
|
63
|
+
let text = "";
|
|
64
|
+
text += addLeadingComment(JSDOC_EXAMPLE_TAG);
|
|
65
|
+
text += DOUBLE_LINE_BREAK_WITH_LEADING_COMMENT;
|
|
66
|
+
text += addLeadingCommentForTextWithLineBreaks({
|
|
67
|
+
text: removeCommentTags(node.value),
|
|
68
|
+
addDoubleLineBreaks: false,
|
|
69
|
+
});
|
|
70
|
+
text += LINE_BREAK;
|
|
71
|
+
text += addLeadingComment(JSDOC_END_EXAMPLE_TAG);
|
|
72
|
+
text += LINE_BREAK;
|
|
73
|
+
|
|
74
|
+
return text;
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const hasLineBreaks = text => text?.includes(LINE_BREAK);
|
|
78
|
+
|
|
79
|
+
const getParagraphChildrenText = node => {
|
|
80
|
+
const children = node.children;
|
|
81
|
+
if (children.length === 1) return children[0].value;
|
|
82
|
+
|
|
83
|
+
return children.map(child => child.value || child.children[0].value).join("");
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
const transformParagraph = node => {
|
|
87
|
+
let text = "";
|
|
88
|
+
text += ASTERISK_WITH_SPACES;
|
|
89
|
+
const childrenText = getParagraphChildrenText(node);
|
|
90
|
+
|
|
91
|
+
if (hasLineBreaks(childrenText)) {
|
|
92
|
+
text += addLeadingCommentForTextWithLineBreaks({
|
|
93
|
+
text: childrenText,
|
|
94
|
+
addCommentForFirstItem: false,
|
|
95
|
+
});
|
|
96
|
+
} else {
|
|
97
|
+
text += childrenText;
|
|
98
|
+
}
|
|
99
|
+
text += DOUBLE_LINE_BREAK_WITH_LEADING_COMMENT;
|
|
100
|
+
|
|
101
|
+
return text;
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
const transformImg = node => {
|
|
105
|
+
const { src, alt } = parseImgTag(node.value);
|
|
106
|
+
let text = ASTERISK_WITH_SPACES;
|
|
107
|
+
text += ``;
|
|
108
|
+
text += DOUBLE_LINE_BREAK_WITH_LEADING_COMMENT;
|
|
109
|
+
|
|
110
|
+
return text;
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
const transformNodesToText = nodes => {
|
|
114
|
+
let text = DOUBLE_LINE_BREAK_WITH_LEADING_COMMENT;
|
|
115
|
+
|
|
116
|
+
nodes.forEach(node => {
|
|
117
|
+
if (matches(CODE_PATTERN, node)) {
|
|
118
|
+
text += transformCode(node);
|
|
119
|
+
} else if (matches(IMG_PATTERN, node)) {
|
|
120
|
+
text += transformImg(node);
|
|
121
|
+
} else if (matches(PARAGRAPH_PATTERN, node)) {
|
|
122
|
+
text += transformParagraph(node);
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
return addLeadingComment(text, true);
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
const parseImgTag = imgTagStr =>
|
|
130
|
+
imgTagStr.split(" ").reduce((acc, item) => {
|
|
131
|
+
let [attrName, attrValue] = item.split("=");
|
|
132
|
+
attrValue = attrValue?.replaceAll(">", "").replaceAll('"', "");
|
|
133
|
+
|
|
134
|
+
return mergeLeft({ [attrName]: attrValue }, acc);
|
|
135
|
+
}, {});
|
|
136
|
+
|
|
137
|
+
const removeCommentTags = str => str.replaceAll("/*", "").replaceAll("*/", "");
|
|
138
|
+
|
|
139
|
+
export const parseTypeFile = typeFileContent =>
|
|
140
|
+
babelParser.parse(typeFileContent, {
|
|
141
|
+
sourceType: "module",
|
|
142
|
+
plugins: [["typescript", { dts: true }]],
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
export const buildEntityTitleToEntityDescMap = (nodes, map) => {
|
|
146
|
+
nodes.forEach((node, idx) => {
|
|
147
|
+
if (!matches(SUBHEADING_PATTERN, node)) return;
|
|
148
|
+
|
|
149
|
+
const entityName = removeWhiteSpaceAndParentheses(node.children[0].value);
|
|
150
|
+
const entityRightSiblings = [];
|
|
151
|
+
|
|
152
|
+
for (let i = idx + 1; i < nodes.length; i++) {
|
|
153
|
+
const siblingNode = nodes[i];
|
|
154
|
+
|
|
155
|
+
if (matches(HTML_EXCEPT_IMG_PATTERN, siblingNode)) continue;
|
|
156
|
+
|
|
157
|
+
if (matches(SUBHEADING_PATTERN, siblingNode)) break;
|
|
158
|
+
|
|
159
|
+
entityRightSiblings.push(siblingNode);
|
|
160
|
+
}
|
|
161
|
+
const entityRightSiblingsText = transformNodesToText(entityRightSiblings);
|
|
162
|
+
map[entityName] = entityRightSiblingsText;
|
|
163
|
+
});
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
export const defaultTypeFileTraverser = ({
|
|
167
|
+
typeFileAST,
|
|
168
|
+
typeFileName,
|
|
169
|
+
entityTitleToDescMapOfAllFiles,
|
|
170
|
+
}) =>
|
|
171
|
+
traverse(typeFileAST, {
|
|
172
|
+
ExportNamedDeclaration: ({ node }) => {
|
|
173
|
+
const entityName = findEntityName(node);
|
|
174
|
+
const entityDesc = entityTitleToDescMapOfAllFiles[entityName];
|
|
175
|
+
|
|
176
|
+
if (!entityName || !entityDesc) {
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
babelTypes.addComment(node, "leading", entityDesc);
|
|
181
|
+
|
|
182
|
+
const { code } = generate(typeFileAST, {});
|
|
183
|
+
|
|
184
|
+
fs.writeFileSync(path.resolve(typeFileName), code);
|
|
185
|
+
},
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
export const syncTypeFiles = exportedTypesFolderName => {
|
|
189
|
+
const sourceDir = path.resolve(TYPES_FOLDER_NAME);
|
|
190
|
+
const destDir = path.resolve(exportedTypesFolderName);
|
|
191
|
+
|
|
192
|
+
fs.cpSync(sourceDir, destDir, { recursive: true });
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
export const getFileNameList = dirPath => {
|
|
196
|
+
let files = [];
|
|
197
|
+
const items = fs.readdirSync(dirPath, { withFileTypes: true });
|
|
198
|
+
|
|
199
|
+
for (const item of items) {
|
|
200
|
+
if (item.isDirectory()) {
|
|
201
|
+
files = [...files, ...getFileNameList(path.join(dirPath, item.name))];
|
|
202
|
+
} else {
|
|
203
|
+
files.push(path.join(dirPath, item.name));
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
return files;
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
export const getFileContent = fileName =>
|
|
211
|
+
fs.readFileSync(path.resolve(fileName), "utf8").toString();
|
|
212
|
+
|
|
213
|
+
export const parseMarkdown = fileContent =>
|
|
214
|
+
unified().use(remarkParse).parse(fileContent);
|
|
215
|
+
|
|
216
|
+
export const findEntityName = node =>
|
|
217
|
+
node?.declaration?.declarations?.[0]?.id?.name || node?.declaration?.id?.name;
|
|
218
|
+
|
|
219
|
+
export const matchesAny = curry((list, obj) => list.some(matches(__, obj)));
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
const I18NEXT_PLURALS = ["zero", "one", "two", "few", "many", "other"];
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
Matches the following:
|
|
5
|
+
- t(`some.${key}`), t(key), t(getKey()), t(key, { count: 1 })
|
|
6
|
+
- i18nKey={`some.${key}`}, i18nKey={key}, i18nKey={getKey()}
|
|
7
|
+
*/
|
|
8
|
+
const INTERPOLATED_TRANSLATION_KEY_REGEX =
|
|
9
|
+
/(?<![a-z0-9])t\((?:\s*`.*`|\s*[a-z0-9\-_()]*)(?:,.*)?\s*\)|i18nKey={\s*(`.*`|[a-z0-9-_()]*)\s*}/gi;
|
|
10
|
+
|
|
11
|
+
module.exports = { I18NEXT_PLURALS, INTERPOLATED_TRANSLATION_KEY_REGEX };
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/* eslint-disable no-console */
|
|
3
|
+
|
|
4
|
+
const fs = require("fs");
|
|
5
|
+
const path = require("path");
|
|
6
|
+
|
|
7
|
+
const { Command } = require("commander");
|
|
8
|
+
const { isEmpty, path: rPath } = require("ramda");
|
|
9
|
+
|
|
10
|
+
const {
|
|
11
|
+
I18NEXT_PLURALS,
|
|
12
|
+
INTERPOLATED_TRANSLATION_KEY_REGEX,
|
|
13
|
+
} = require("./constants");
|
|
14
|
+
|
|
15
|
+
const isI18nextPlural = key =>
|
|
16
|
+
I18NEXT_PLURALS.some(pluralKey => key.endsWith(`_${pluralKey}`));
|
|
17
|
+
|
|
18
|
+
const logUnusedKeysAndInterpolatedKeys = (
|
|
19
|
+
unusedTranslationKeys,
|
|
20
|
+
transFuncWithInterpolatedKeys
|
|
21
|
+
) => {
|
|
22
|
+
console.log("\nUnused translation keys");
|
|
23
|
+
console.log("-----------------------");
|
|
24
|
+
|
|
25
|
+
if (isEmpty(unusedTranslationKeys)) {
|
|
26
|
+
console.log("No unused keys found.");
|
|
27
|
+
} else {
|
|
28
|
+
const unusedKeyCount = unusedTranslationKeys.length;
|
|
29
|
+
unusedTranslationKeys.forEach(key => console.log(key));
|
|
30
|
+
console.log(`\nDeleted ${unusedKeyCount} unused keys successfully.`);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
console.log("\n\nTranslation functions with interpolated keys");
|
|
34
|
+
console.log("--------------------------------------------");
|
|
35
|
+
|
|
36
|
+
if (isEmpty(transFuncWithInterpolatedKeys)) {
|
|
37
|
+
console.log("No translation functions with interpolated keys found.\n");
|
|
38
|
+
} else {
|
|
39
|
+
transFuncWithInterpolatedKeys.forEach(hash => {
|
|
40
|
+
console.log(`Code: ${hash.code}`);
|
|
41
|
+
console.log(`File path: ${hash.filePath}\n`);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
console.log(
|
|
45
|
+
"Please verify whether the keys required by the above translation functions have been removed or not. If removed, please restore them.\n"
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const deleteUnusedKeysFromData = (translationData, unusedTranslationKeys) => {
|
|
51
|
+
unusedTranslationKeys.forEach(translationKey => {
|
|
52
|
+
const keys = translationKey.split(".");
|
|
53
|
+
const lastKey = keys.pop();
|
|
54
|
+
|
|
55
|
+
if (isEmpty(keys)) {
|
|
56
|
+
delete translationData[lastKey];
|
|
57
|
+
} else {
|
|
58
|
+
const currentData = rPath(keys, translationData);
|
|
59
|
+
if (currentData) delete currentData[lastKey];
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const deleteEmptyValuesFromData = translationData => {
|
|
65
|
+
for (const [key, value] of Object.entries(translationData)) {
|
|
66
|
+
if (typeof value === "object") {
|
|
67
|
+
if (isEmpty(value)) delete translationData[key];
|
|
68
|
+
else deleteEmptyValuesFromData(value);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const deleteUsedKeysFromKeysList = (dirPath, keys) => {
|
|
74
|
+
fs.readdirSync(dirPath).forEach(fileName => {
|
|
75
|
+
const filePath = path.join(dirPath, fileName);
|
|
76
|
+
if (fs.statSync(filePath).isFile()) {
|
|
77
|
+
const extension = path.extname(filePath);
|
|
78
|
+
if (![".js", ".jsx", ".rb", ".jbuilder"].includes(extension)) return;
|
|
79
|
+
|
|
80
|
+
const data = fs.readFileSync(filePath, "utf8");
|
|
81
|
+
for (let i = 0; i < keys.length; i++) {
|
|
82
|
+
const key = keys[i];
|
|
83
|
+
const isKeyFound =
|
|
84
|
+
data.includes(key) ||
|
|
85
|
+
(isI18nextPlural(key) && data.includes(key.replace(/_[^_]*$/, "")));
|
|
86
|
+
|
|
87
|
+
if (isKeyFound) {
|
|
88
|
+
keys.splice(i, 1);
|
|
89
|
+
i--;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
} else if (fs.statSync(filePath).isDirectory()) {
|
|
93
|
+
deleteUsedKeysFromKeysList(filePath, keys);
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
const getUnusedKeys = (searchPath, translationKeys) => {
|
|
99
|
+
const keys = [...translationKeys];
|
|
100
|
+
deleteUsedKeysFromKeysList(searchPath, keys);
|
|
101
|
+
|
|
102
|
+
return keys;
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
const findTransFuncWithInterpolatedKeys = dirPath => {
|
|
106
|
+
const transFuncWithInterpolatedKeys = [];
|
|
107
|
+
|
|
108
|
+
fs.readdirSync(dirPath).forEach(fileName => {
|
|
109
|
+
const filePath = path.join(dirPath, fileName);
|
|
110
|
+
if (fs.statSync(filePath).isFile()) {
|
|
111
|
+
const extension = path.extname(filePath);
|
|
112
|
+
if (![".js", ".jsx"].includes(extension)) return;
|
|
113
|
+
|
|
114
|
+
const data = fs.readFileSync(filePath, "utf8");
|
|
115
|
+
const relativePath = path.relative(process.cwd(), filePath);
|
|
116
|
+
const matchedCodes = data.match(INTERPOLATED_TRANSLATION_KEY_REGEX);
|
|
117
|
+
|
|
118
|
+
matchedCodes?.forEach(code => {
|
|
119
|
+
transFuncWithInterpolatedKeys.push({
|
|
120
|
+
code,
|
|
121
|
+
filePath: relativePath,
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
} else if (fs.statSync(filePath).isDirectory()) {
|
|
125
|
+
transFuncWithInterpolatedKeys.push(
|
|
126
|
+
...findTransFuncWithInterpolatedKeys(filePath)
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
return transFuncWithInterpolatedKeys;
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
const generateTranslationKeys = (data, parentKey = null) => {
|
|
135
|
+
const translationKeys = [];
|
|
136
|
+
|
|
137
|
+
for (const [key, value] of Object.entries(data)) {
|
|
138
|
+
const currentKey = parentKey ? `${parentKey}.${key}` : key;
|
|
139
|
+
|
|
140
|
+
if (typeof value === "object") {
|
|
141
|
+
translationKeys.push(...generateTranslationKeys(value, currentKey));
|
|
142
|
+
} else {
|
|
143
|
+
translationKeys.push(currentKey);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return translationKeys;
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
const getCommandLineOptions = () => {
|
|
151
|
+
const program = new Command();
|
|
152
|
+
program
|
|
153
|
+
.option("--translation-path <path>", "Path to translation file")
|
|
154
|
+
.option("--search-path <path>", "Path to search for unused keys")
|
|
155
|
+
.parse(process.argv);
|
|
156
|
+
|
|
157
|
+
return program.opts();
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
// Script execution starts here
|
|
161
|
+
const {
|
|
162
|
+
translationPath = "app/javascript/src/translations/en.json",
|
|
163
|
+
searchPath = "app",
|
|
164
|
+
} = getCommandLineOptions();
|
|
165
|
+
|
|
166
|
+
console.log("\nPlease wait, this may take a few seconds...");
|
|
167
|
+
|
|
168
|
+
const translationData = JSON.parse(fs.readFileSync(translationPath, "utf8"));
|
|
169
|
+
const translationKeys = generateTranslationKeys(translationData);
|
|
170
|
+
const unusedTranslationKeys = getUnusedKeys(searchPath, translationKeys);
|
|
171
|
+
|
|
172
|
+
deleteUnusedKeysFromData(translationData, unusedTranslationKeys);
|
|
173
|
+
deleteEmptyValuesFromData(translationData);
|
|
174
|
+
|
|
175
|
+
fs.writeFileSync(
|
|
176
|
+
translationPath,
|
|
177
|
+
`${JSON.stringify(translationData, null, 2)}\n`
|
|
178
|
+
);
|
|
179
|
+
|
|
180
|
+
const transFuncWithInterpolatedKeys =
|
|
181
|
+
findTransFuncWithInterpolatedKeys(searchPath);
|
|
182
|
+
|
|
183
|
+
logUnusedKeysAndInterpolatedKeys(
|
|
184
|
+
unusedTranslationKeys,
|
|
185
|
+
transFuncWithInterpolatedKeys
|
|
186
|
+
);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
important: true,
|
|
3
|
+
purge: {
|
|
4
|
+
enabled: process.env.NODE_ENV === "production",
|
|
5
|
+
content: [
|
|
6
|
+
"./app/javascript/**/*.{js,jsx}",
|
|
7
|
+
"./app/views/**/*.html.erb",
|
|
8
|
+
"./app/views/**/*.slim",
|
|
9
|
+
"./node_modules/@bigbinary/**/*.js",
|
|
10
|
+
],
|
|
11
|
+
defaultExtractor: content => content.match(/[A-Za-z0-9-_:/]+/g) || [],
|
|
12
|
+
},
|
|
13
|
+
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Customize default webpack rules/loaders configuration.
|
|
3
|
+
A custom helpers till shakapacker introduces the feature.
|
|
4
|
+
Track the following the issues to get the status of feature development in shakapacker:
|
|
5
|
+
https://github.com/shakacode/shakapacker/issues/80
|
|
6
|
+
https://github.com/shakacode/shakapacker/issues/87
|
|
7
|
+
Usage:
|
|
8
|
+
const customizeWebpackDefaultRules = require("./helpers/customize-default-rules");
|
|
9
|
+
const defaultRules = {
|
|
10
|
+
"asset/resource": {
|
|
11
|
+
test: /\.(bmp|gif|jpe?g|png|tiff|ico|avif|webp|eot|otf|ttf|woff|woff2)$/
|
|
12
|
+
},
|
|
13
|
+
"asset/source": {
|
|
14
|
+
exclude: /\.(js|mjs|jsx|ts|tsx|js)$/,
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
const customWebpackConfig = customizeWebpackDefaultRules(webpackConfig, defaultRules);
|
|
18
|
+
NOTE:
|
|
19
|
+
- Check if the option to output default configuration is introduced or not before upgrading further.
|
|
20
|
+
- Update the defaultRuleType constant whenever shakapacker introduces a new default rule/loader.
|
|
21
|
+
*/
|
|
22
|
+
const { findBy, findIndexBy } = require("@bigbinary/neeto-cist");
|
|
23
|
+
|
|
24
|
+
const modifyDefaultRulesConfig = (webpackConfig, rules = {}) => {
|
|
25
|
+
const defaultRuleType = ["asset/resource", "asset/source"];
|
|
26
|
+
|
|
27
|
+
Object.keys(rules).forEach(ruleName => {
|
|
28
|
+
if (defaultRuleType.includes(ruleName)) {
|
|
29
|
+
const rule = findBy(
|
|
30
|
+
{ type: "asset/resource" },
|
|
31
|
+
webpackConfig.module.rules
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
const rulePosition = findIndexBy(
|
|
35
|
+
{ type: ruleName },
|
|
36
|
+
webpackConfig.module.rules
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
Object.keys(rules[ruleName]).forEach(attribute => {
|
|
40
|
+
if (rule[attribute] !== undefined) {
|
|
41
|
+
rule[attribute] = rules[ruleName][attribute];
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
webpackConfig.module.rules[rulePosition] = rule;
|
|
46
|
+
} else {
|
|
47
|
+
throw new Error("Invalid default rule type");
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
return webpackConfig;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
module.exports = modifyDefaultRulesConfig;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
const process = require("process");
|
|
2
|
+
|
|
3
|
+
const Dotenv = require("dotenv-webpack");
|
|
4
|
+
const { webpackConfig, merge } = require("shakapacker");
|
|
5
|
+
const webpack = require("webpack");
|
|
6
|
+
|
|
7
|
+
const customizeWebpackDefaultRules = require("./helpers/customize-default-rules");
|
|
8
|
+
const resolve = require("./resolve");
|
|
9
|
+
const rules = require("./rules");
|
|
10
|
+
|
|
11
|
+
const dotEnvFileSuffix =
|
|
12
|
+
process.env.NODE_ENV === "production" ? "" : `.${process.env.NODE_ENV}`;
|
|
13
|
+
|
|
14
|
+
let devtool = "hidden-source-map",
|
|
15
|
+
mode = "production";
|
|
16
|
+
if (process.env.RAILS_ENV === "test") {
|
|
17
|
+
devtool = false;
|
|
18
|
+
mode = "none";
|
|
19
|
+
} else if (process.env.RAILS_ENV === "development") {
|
|
20
|
+
devtool = "eval-cheap-module-source-map";
|
|
21
|
+
mode = "development";
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const commonOptions = {
|
|
25
|
+
mode,
|
|
26
|
+
infrastructureLogging: { level: "warn" },
|
|
27
|
+
devtool,
|
|
28
|
+
resolve,
|
|
29
|
+
optimization: {
|
|
30
|
+
splitChunks: {
|
|
31
|
+
maxSize: 15000000, // 15MB
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
module: { rules },
|
|
35
|
+
plugins: [
|
|
36
|
+
new webpack.ProvidePlugin({ process: "process/browser" }),
|
|
37
|
+
new Dotenv({
|
|
38
|
+
path: `./.env${dotEnvFileSuffix}`,
|
|
39
|
+
systemvars: true,
|
|
40
|
+
silent: true,
|
|
41
|
+
}),
|
|
42
|
+
],
|
|
43
|
+
ignoreWarnings: [/Failed to parse source map/],
|
|
44
|
+
snapshot: { managedPaths: [/^(node_modules\/@bigbinary\/.+)/] },
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
// This rule is causing issues to react-svg-loader
|
|
48
|
+
const defaultRules = {
|
|
49
|
+
"asset/resource": {
|
|
50
|
+
test: /\.(bmp|gif|jpe?g|png|tiff|ico|avif|webp|eot|otf|ttf|woff|woff2)$/,
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const customWebpackConfig = customizeWebpackDefaultRules(
|
|
55
|
+
webpackConfig,
|
|
56
|
+
defaultRules
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
module.exports = merge(customWebpackConfig, commonOptions);
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
const path = require("path");
|
|
2
|
+
|
|
3
|
+
const absolutePath = basePath =>
|
|
4
|
+
path.resolve(__dirname, "../../../../../", `app/javascript/${basePath}`);
|
|
5
|
+
|
|
6
|
+
module.exports = {
|
|
7
|
+
alias: {
|
|
8
|
+
apis: absolutePath("src/apis"),
|
|
9
|
+
assets: absolutePath("src/assets"),
|
|
10
|
+
components: absolutePath("src/components"),
|
|
11
|
+
hooks: absolutePath("src/hooks"),
|
|
12
|
+
reducers: absolutePath("src/reducers"),
|
|
13
|
+
routes: absolutePath("src/routes"),
|
|
14
|
+
stores: absolutePath("src/stores"),
|
|
15
|
+
translations: absolutePath("src/translations"),
|
|
16
|
+
utils: absolutePath("src/utils"),
|
|
17
|
+
src: absolutePath("src"),
|
|
18
|
+
neetoui: "@bigbinary/neetoui",
|
|
19
|
+
neetocommons: "@bigbinary/neeto-commons-frontend",
|
|
20
|
+
neetoicons: "@bigbinary/neeto-icons",
|
|
21
|
+
neetoteam: "@bigbinary/neeto-team-members-frontend",
|
|
22
|
+
neetoeditor: "@bigbinary/neeto-editor",
|
|
23
|
+
neetofilters: "@bigbinary/neeto-filters-frontend",
|
|
24
|
+
neetomolecules: "@bigbinary/neeto-molecules",
|
|
25
|
+
neetopayments: "@bigbinary/neeto-payments-frontend",
|
|
26
|
+
neetocist: "@bigbinary/neeto-cist",
|
|
27
|
+
images: path.resolve(__dirname, "../../../../../", "app/assets/images"),
|
|
28
|
+
},
|
|
29
|
+
extensions: [
|
|
30
|
+
".ts",
|
|
31
|
+
".mjs",
|
|
32
|
+
".js",
|
|
33
|
+
".sass",
|
|
34
|
+
".scss",
|
|
35
|
+
".css",
|
|
36
|
+
".module.sass",
|
|
37
|
+
".module.scss",
|
|
38
|
+
".module.css",
|
|
39
|
+
".png",
|
|
40
|
+
".svg",
|
|
41
|
+
".gif",
|
|
42
|
+
".jpeg",
|
|
43
|
+
".jpg",
|
|
44
|
+
],
|
|
45
|
+
fallback: {
|
|
46
|
+
util: require.resolve("util/"),
|
|
47
|
+
url: require.resolve("url/"),
|
|
48
|
+
fs: false,
|
|
49
|
+
buffer: require.resolve("buffer/"),
|
|
50
|
+
crypto: require.resolve("crypto-browserify"),
|
|
51
|
+
stream: require.resolve("stream-browserify"),
|
|
52
|
+
},
|
|
53
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
module.exports = [
|
|
2
|
+
{
|
|
3
|
+
test: /\.svg$/i,
|
|
4
|
+
use: [
|
|
5
|
+
{
|
|
6
|
+
loader: "@svgr/webpack",
|
|
7
|
+
options: { svgoConfig: { plugins: ["preset-default"] } },
|
|
8
|
+
},
|
|
9
|
+
],
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
test: /\.ts$/,
|
|
13
|
+
exclude: /node_modules/,
|
|
14
|
+
use: {
|
|
15
|
+
loader: "babel-loader",
|
|
16
|
+
options: {
|
|
17
|
+
presets: ["@babel/preset-env", "@babel/preset-typescript"],
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
test: /\.js$/,
|
|
23
|
+
include:
|
|
24
|
+
/node_modules\/@bigbinary\/neeto-commons-frontend\/initializers\/i18n/,
|
|
25
|
+
use: { loader: "babel-loader", options: { plugins: ["preval"] } },
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
test: /\.m?js$/,
|
|
29
|
+
resolve: {
|
|
30
|
+
fullySpecified: false, // allows webpack to ignore some package rules as the Strict EcmaScript Module mode.
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
{ test: /\.js$/, enforce: "pre", use: ["source-map-loader"] },
|
|
34
|
+
];
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
const { defineConfig } = require("cypress");
|
|
2
|
+
|
|
3
|
+
const defineCypressConfig = (overrides = {}) => {
|
|
4
|
+
const { e2e: e2eOverrides = {}, ...otherProps } = overrides;
|
|
5
|
+
|
|
6
|
+
return defineConfig({
|
|
7
|
+
execTimeout: 1800000,
|
|
8
|
+
defaultCommandTimeout: 8000,
|
|
9
|
+
requestTimeout: 15000,
|
|
10
|
+
pageLoadTimeout: 30000,
|
|
11
|
+
responseTimeout: 45000,
|
|
12
|
+
viewportWidth: 1440,
|
|
13
|
+
viewportHeight: 960,
|
|
14
|
+
chromeWebSecurity: false,
|
|
15
|
+
env: { grepFilterSpecs: true, grepOmitFiltered: true },
|
|
16
|
+
retries: { runMode: 1, openMode: 0 },
|
|
17
|
+
e2e: {
|
|
18
|
+
setupNodeEvents(on, config) {
|
|
19
|
+
return require("./plugins")(on, config);
|
|
20
|
+
},
|
|
21
|
+
specPattern: "cypress/e2e/**/*.spec.js",
|
|
22
|
+
excludeSpecPattern: ["cypress/e2e/**/*.wip.spec.js"],
|
|
23
|
+
experimentalRunAllSpecs: true,
|
|
24
|
+
testIsolation: true,
|
|
25
|
+
experimentalMemoryManagement: true,
|
|
26
|
+
...e2eOverrides,
|
|
27
|
+
},
|
|
28
|
+
...otherProps,
|
|
29
|
+
});
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
module.exports = { defineCypressConfig };
|