@bigbinary/neeto-commons-frontend 3.0.7 → 3.0.9

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.
Files changed (48) hide show
  1. package/cjs/configs/babel.js +50 -0
  2. package/cjs/configs/eslint/globals.js +14 -0
  3. package/cjs/configs/eslint/helpers/index.js +74 -0
  4. package/cjs/configs/eslint/imports/enforced.js +29 -0
  5. package/cjs/configs/eslint/imports/order.js +65 -0
  6. package/cjs/configs/eslint/index.js +171 -0
  7. package/cjs/configs/eslint/overrides.js +30 -0
  8. package/cjs/configs/eslint/promise.js +8 -0
  9. package/cjs/configs/eslint/react.js +92 -0
  10. package/cjs/configs/nanos/eslint/imports/order.js +25 -0
  11. package/cjs/configs/nanos/eslint/index.js +28 -0
  12. package/cjs/configs/nanos/tailwind.js +11 -0
  13. package/cjs/configs/nanos/webpack/resolve.js +48 -0
  14. package/cjs/configs/nextjs/eslint/imports/order.js +25 -0
  15. package/cjs/configs/nextjs/eslint/index.js +22 -0
  16. package/cjs/configs/nextjs/webpack/resolve.js +1 -0
  17. package/cjs/configs/prettier.js +16 -0
  18. package/cjs/configs/scripts/dead-code-eliminator/constants.js +12 -0
  19. package/cjs/configs/scripts/dead-code-eliminator/index.js +266 -0
  20. package/cjs/configs/scripts/getPkgTranslations.js +45 -0
  21. package/cjs/configs/scripts/jsdoc-builder/constants.mjs +42 -0
  22. package/cjs/configs/scripts/jsdoc-builder/index.mjs +67 -0
  23. package/cjs/configs/scripts/jsdoc-builder/utils.mjs +219 -0
  24. package/cjs/configs/scripts/remove-unused-translation-keys/constants.js +11 -0
  25. package/cjs/configs/scripts/remove-unused-translation-keys/index.js +186 -0
  26. package/cjs/configs/tailwind.js +13 -0
  27. package/cjs/configs/webpack/helpers/customize-default-rules.js +54 -0
  28. package/cjs/configs/webpack/index.js +58 -0
  29. package/cjs/configs/webpack/resolve.js +53 -0
  30. package/cjs/configs/webpack/rules.js +34 -0
  31. package/cjs/cypress-configs/initializer.js +32 -0
  32. package/cjs/cypress-configs/plugins.js +105 -0
  33. package/cjs/cypress-configs/resolve.js +17 -0
  34. package/cjs/cypress-configs/webpack.config.js +19 -0
  35. package/cjs/initializers/constants.js +9 -3
  36. package/cjs/initializers/constants.js.map +1 -1
  37. package/cjs/initializers/i18n.js +8 -2
  38. package/cjs/initializers/i18n.js.map +1 -1
  39. package/cjs/initializers/utils/customFormatters.js +17 -8
  40. package/cjs/initializers/utils/customFormatters.js.map +1 -1
  41. package/cjs/translations/en.json +100 -0
  42. package/initializers/constants.js +6 -1
  43. package/initializers/constants.js.map +1 -1
  44. package/initializers/i18n.js +9 -3
  45. package/initializers/i18n.js.map +1 -1
  46. package/initializers/utils/customFormatters.js +16 -7
  47. package/initializers/utils/customFormatters.js.map +1 -1
  48. package/package.json +1 -1
@@ -0,0 +1,25 @@
1
+ const { assocPath } = require("ramda");
2
+
3
+ const {
4
+ buildPathGroupsBasedOnWebpackAliases,
5
+ } = require("../../../eslint/helpers");
6
+ const commonConfig = require("../../../eslint/imports/order");
7
+
8
+ const pathGroups = buildPathGroupsBasedOnWebpackAliases({
9
+ customAliasPath: "resolve.js",
10
+ commonAliasPath:
11
+ "node_modules/@bigbinary/neeto-commons-frontend/configs/nextjs/webpack/resolve.js",
12
+ });
13
+
14
+ const pathGroupForKeepingReactImportsAtTop = {
15
+ pattern: "react+(-native|)",
16
+ group: "external",
17
+ position: "before",
18
+ };
19
+ pathGroups.push(pathGroupForKeepingReactImportsAtTop);
20
+
21
+ module.exports = assocPath(
22
+ ["rules", "import/order", 1, "pathGroups"],
23
+ pathGroups,
24
+ commonConfig
25
+ );
@@ -0,0 +1,22 @@
1
+ const { mergeLeft } = require("ramda");
2
+
3
+ const commonConfiguration = require("../../eslint");
4
+
5
+ const nextjsConfiguration = {
6
+ extends: [
7
+ "plugin:@bigbinary/neeto/nextjs-recommended",
8
+ "plugin:cypress/recommended",
9
+ "plugin:json/recommended",
10
+ "eslint:recommended",
11
+ "plugin:react/recommended",
12
+ "./node_modules/@bigbinary/neeto-commons-frontend/configs/eslint/globals",
13
+ "./node_modules/@bigbinary/neeto-commons-frontend/configs/nextjs/eslint/imports/order",
14
+ "./node_modules/@bigbinary/neeto-commons-frontend/configs/eslint/overrides",
15
+ "./node_modules/@bigbinary/neeto-commons-frontend/configs/eslint/imports/enforced",
16
+ "./node_modules/@bigbinary/neeto-commons-frontend/configs/eslint/react",
17
+ "./node_modules/@bigbinary/neeto-commons-frontend/configs/eslint/promise",
18
+ "prettier",
19
+ ],
20
+ };
21
+
22
+ module.exports = mergeLeft(nextjsConfiguration, commonConfiguration);
@@ -0,0 +1 @@
1
+ module.exports = {};
@@ -0,0 +1,16 @@
1
+ module.exports = {
2
+ tailwindConfig: "./tailwind.config.js",
3
+ trailingComma: "es5",
4
+ arrowParens: "avoid",
5
+ printWidth: 80,
6
+ tabWidth: 2,
7
+ useTabs: false,
8
+ semi: true,
9
+ quoteProps: "as-needed",
10
+ jsxSingleQuote: false,
11
+ singleQuote: false,
12
+ bracketSpacing: true,
13
+ bracketSameLine: false,
14
+ proseWrap: "always",
15
+ endOfLine: "lf",
16
+ };
@@ -0,0 +1,12 @@
1
+ const RAILS_MOUNTED_COMPONENTS_REGEX = /app\/javascript\/src\/[^/]*\.(js|jsx)$/;
2
+ const PACKS_FILES_REGEX = /app\/javascript\/packs\/[^/]*\.(js|jsx)$/;
3
+
4
+ const TYPES = {
5
+ CLASS_DECLARATION: "ClassDeclaration",
6
+ FUNCTION_DECLARATION: "FunctionDeclaration",
7
+ IMPORT_DEFAULT_SPECIFIER: "ImportDefaultSpecifier",
8
+ IMPORT_NAMESPACE_SPECIFIER: "ImportNamespaceSpecifier",
9
+ VARIABLE_DECLARATION: "VariableDeclaration",
10
+ };
11
+
12
+ module.exports = { RAILS_MOUNTED_COMPONENTS_REGEX, PACKS_FILES_REGEX, TYPES };
@@ -0,0 +1,266 @@
1
+ #!/usr/bin/env node
2
+ /* eslint-disable no-console */
3
+
4
+ const { exec, execSync } = require("child_process");
5
+ const fs = require("fs");
6
+ const pathLib = require("path");
7
+
8
+ const generate = require("@babel/generator").default;
9
+ const babelParser = require("@babel/parser");
10
+ const traverse = require("@babel/traverse").default;
11
+ const { isNotEmpty, existsBy } = require("@bigbinary/neeto-cist");
12
+ const enhancedResolve = require("enhanced-resolve");
13
+ const { isEmpty, includes, __ } = require("ramda");
14
+
15
+ const {
16
+ RAILS_MOUNTED_COMPONENTS_REGEX,
17
+ TYPES,
18
+ PACKS_FILES_REGEX,
19
+ } = require("./constants");
20
+
21
+ // @ts-ignore
22
+ // eslint-disable-next-line import/extensions
23
+ const webpackConfig = require("../../../../../../config/webpack/webpack.config.js");
24
+
25
+ let modifiedFiles = [];
26
+ let importedItems = [];
27
+ let unusedFiles = [];
28
+ let iterationCount = 1;
29
+
30
+ const javascriptDir = pathLib.resolve(
31
+ __dirname,
32
+ "../../../../../../app/javascript"
33
+ );
34
+
35
+ const resolver = enhancedResolve.create.sync({
36
+ alias: webpackConfig.resolve.alias,
37
+ modules: webpackConfig.resolve.modules,
38
+ extensions: webpackConfig.resolve.extensions,
39
+ fallback: webpackConfig.resolve.fallback,
40
+ conditionNames: ["require", "import", "node", "default", "types"],
41
+ });
42
+
43
+ const isRailsMountedOrPacksFiles = filePath =>
44
+ RAILS_MOUNTED_COMPONENTS_REGEX.test(filePath) ||
45
+ PACKS_FILES_REGEX.test(filePath);
46
+
47
+ const isInImportedList = (item, filePath) =>
48
+ existsBy({ item: includes(__, [item, "*"]), filePath }, importedItems);
49
+
50
+ const findImports = filePath => {
51
+ const code = fs.readFileSync(filePath, "utf8");
52
+ const ast = babelParser.parse(code, {
53
+ sourceType: "module",
54
+ plugins: ["jsx"],
55
+ });
56
+
57
+ traverse(ast, {
58
+ ImportDeclaration(path) {
59
+ const { node } = path;
60
+
61
+ const currentDir = pathLib.dirname(filePath);
62
+ const importSource = node.source.value;
63
+
64
+ const resolvedPath = resolver(currentDir, importSource);
65
+ const isNodeModule = resolvedPath.includes("node_modules");
66
+ if (isNodeModule) return;
67
+
68
+ if (isEmpty(node.specifiers)) {
69
+ importedItems.push({ item: "*", filePath: resolvedPath });
70
+ }
71
+
72
+ node.specifiers.forEach(specifier => {
73
+ if (specifier.type === TYPES.IMPORT_NAMESPACE_SPECIFIER) {
74
+ importedItems.push({ item: "*", filePath: resolvedPath });
75
+ } else if (specifier.type === TYPES.IMPORT_DEFAULT_SPECIFIER) {
76
+ importedItems.push({ item: "default", filePath: resolvedPath });
77
+ } else {
78
+ const item = specifier.imported.name;
79
+ importedItems.push({ item, filePath: resolvedPath });
80
+ }
81
+ });
82
+ },
83
+ });
84
+ };
85
+
86
+ const removeUnusedExports = filePath => {
87
+ if (isRailsMountedOrPacksFiles(filePath)) return;
88
+
89
+ if (!existsBy({ filePath }, importedItems)) {
90
+ unusedFiles.push(filePath);
91
+
92
+ return;
93
+ }
94
+
95
+ let isPathModified = false;
96
+ const code = fs.readFileSync(filePath, "utf8");
97
+ const ast = babelParser.parse(code, {
98
+ sourceType: "module",
99
+ plugins: ["jsx"],
100
+ });
101
+
102
+ traverse(ast, {
103
+ ExportNamedDeclaration(path) {
104
+ const { node } = path;
105
+ if (node.declaration) {
106
+ if (node.declaration.type === TYPES.VARIABLE_DECLARATION) {
107
+ node.declaration.declarations.forEach(declaration => {
108
+ const exportedItem = declaration.id.name;
109
+ if (isInImportedList(exportedItem, filePath)) return;
110
+
111
+ path.replaceWith(path.node.declaration);
112
+ isPathModified = true;
113
+ });
114
+ } else if (
115
+ node.declaration.type === TYPES.FUNCTION_DECLARATION ||
116
+ node.declaration.type === TYPES.CLASS_DECLARATION
117
+ ) {
118
+ const exportedItem = node.declaration.id.name;
119
+ if (isInImportedList(exportedItem, filePath)) return;
120
+
121
+ path.replaceWith(path.node.declaration);
122
+ isPathModified = true;
123
+ }
124
+ } else {
125
+ path.get("specifiers").forEach(specifierPath => {
126
+ const exportedItem = specifierPath.node.exported.name;
127
+ if (isInImportedList(exportedItem, filePath)) return;
128
+
129
+ node.specifiers.length === 1 ? path.remove() : specifierPath.remove();
130
+ isPathModified = true;
131
+ });
132
+ }
133
+ },
134
+ ExportDefaultDeclaration(path) {
135
+ const exportedItem = "default";
136
+ if (isInImportedList(exportedItem, filePath)) return;
137
+
138
+ path.remove();
139
+ isPathModified = true;
140
+ },
141
+ });
142
+
143
+ if (!isPathModified) return;
144
+
145
+ const newCode = generate(ast, {
146
+ retainLines: true,
147
+ retainFunctionParens: true,
148
+ }).code;
149
+
150
+ fs.writeFileSync(filePath, newCode);
151
+ modifiedFiles.push(filePath);
152
+ };
153
+
154
+ const traverseDirectoryAndExecuteFunc = (dir, func) => {
155
+ const files = fs.readdirSync(dir);
156
+
157
+ files.forEach(file => {
158
+ const filePath = pathLib.join(dir, file);
159
+ const stats = fs.statSync(filePath);
160
+
161
+ if (stats.isFile() && [".js", ".jsx"].includes(pathLib.extname(filePath))) {
162
+ func(filePath);
163
+ } else if (stats.isDirectory()) {
164
+ traverseDirectoryAndExecuteFunc(filePath, func);
165
+ }
166
+ });
167
+ };
168
+
169
+ const runLintersAndRemoveUnusedFiles = () => {
170
+ const commands = [];
171
+
172
+ if (isNotEmpty(unusedFiles)) commands.push(`rm -f ${unusedFiles.join(" ")}`);
173
+
174
+ if (isNotEmpty(modifiedFiles)) {
175
+ commands.push(`npx prettier --write ${modifiedFiles.join(" ")}`);
176
+ commands.push(`npx eslint --fix ${modifiedFiles.join(" ")}`);
177
+ }
178
+
179
+ // script will be executed recursively until we have no modified files or unused files
180
+ exec(commands.join(" && "), () => run());
181
+ };
182
+
183
+ const restoreEslintNeetoVersion = () => {
184
+ execSync("git restore package.json yarn.lock", { stdio: "ignore" });
185
+ execSync("yarn", { stdio: "ignore" });
186
+ };
187
+
188
+ const reportNonFixableEslintErrors = () => {
189
+ const modifiedFiles = execSync("git diff --name-only --diff-filter=M")
190
+ .toString()
191
+ .split("\n")
192
+ .join(" ");
193
+
194
+ if (!modifiedFiles) {
195
+ console.log("✅ Script executed successfully!\n");
196
+
197
+ return;
198
+ }
199
+
200
+ exec(`npx eslint ${modifiedFiles} --fix --quiet`, (_, stdout) => {
201
+ if (stdout) {
202
+ console.log(stdout);
203
+ console.log(
204
+ "⭕️ Auto-fixing is not implemented for the above eslint errors. Please fix them manually.\n"
205
+ );
206
+ } else {
207
+ console.log("- No errors found.\n\n✅ Script executed successfully!\n");
208
+ }
209
+ });
210
+ };
211
+
212
+ const postExecution = () => {
213
+ console.log("\n4. Restoring @bigbinary/eslint-plugin-neeto version.");
214
+ restoreEslintNeetoVersion();
215
+
216
+ console.log("\n5. Checking if there are any non-fixable eslint errors.");
217
+ reportNonFixableEslintErrors();
218
+ };
219
+
220
+ const installCustomEslintNeetoVersion = () =>
221
+ execSync(
222
+ "yarn add @bigbinary/eslint-plugin-neeto@1.0.43-no-unused-vars-autofix",
223
+ { stdio: "ignore" }
224
+ );
225
+
226
+ const run = () => {
227
+ console.log(`\nIteration: ${iterationCount++}`);
228
+ console.log(".............");
229
+
230
+ modifiedFiles = [];
231
+ importedItems = [];
232
+ unusedFiles = [];
233
+
234
+ console.log("* Collecting all the imports.");
235
+ traverseDirectoryAndExecuteFunc(javascriptDir, findImports);
236
+
237
+ console.log("* Removing exports which are not imported.");
238
+ traverseDirectoryAndExecuteFunc(javascriptDir, removeUnusedExports);
239
+
240
+ const filesCountMsg = `\nModified files: ${modifiedFiles.length}\nUnused files: ${unusedFiles.length}`;
241
+
242
+ const isExecutionCompleted = isEmpty(modifiedFiles) && isEmpty(unusedFiles);
243
+ if (isExecutionCompleted) {
244
+ console.log(filesCountMsg);
245
+ postExecution();
246
+ } else {
247
+ console.log(
248
+ "* Running linters on modified files and removing unused files."
249
+ );
250
+ runLintersAndRemoveUnusedFiles();
251
+ console.log(filesCountMsg);
252
+ }
253
+ };
254
+
255
+ // Script execution starts here
256
+ console.log("\nPlease wait, this may take a few minutes...");
257
+
258
+ console.log(
259
+ "\n1. Installing @bigbinary/eslint-plugin-neeto custom release required for this script."
260
+ );
261
+ installCustomEslintNeetoVersion();
262
+
263
+ console.log(
264
+ "\n2. Executing script recursively until we have no modified or unused files."
265
+ );
266
+ run();
@@ -0,0 +1,45 @@
1
+ const fs = require("fs");
2
+ const path = require("path");
3
+
4
+ const { mergeDeepLeft } = require("ramda");
5
+
6
+ const packageDir = path.join(__dirname, "../../");
7
+
8
+ const getPkgTransPath = pkg => {
9
+ const basePath = path.join(packageDir, pkg);
10
+
11
+ const transPath1 = path.join(basePath, "app/javascript/src/translations");
12
+ const transPath2 = path.join(basePath, "src/translations");
13
+
14
+ return fs.existsSync(transPath1) ? transPath1 : transPath2;
15
+ };
16
+
17
+ const packages = fs.readdirSync(packageDir);
18
+
19
+ const loadTranslations = translationsDir => {
20
+ try {
21
+ const jsonFiles = fs
22
+ .readdirSync(translationsDir)
23
+ .filter(file => file.endsWith(".json"))
24
+ .map(file => path.join(translationsDir, file));
25
+
26
+ const translations = {};
27
+
28
+ jsonFiles.forEach(jsonFile => {
29
+ const content = fs.readFileSync(jsonFile, "utf8");
30
+ const basename = path.basename(jsonFile, ".json");
31
+
32
+ translations[basename] = { translation: JSON.parse(content) };
33
+ });
34
+
35
+ return translations;
36
+ } catch {
37
+ return {};
38
+ }
39
+ };
40
+
41
+ const packageTranslations = packages
42
+ .map(pkg => loadTranslations(getPkgTransPath(pkg)))
43
+ .reduce(mergeDeepLeft);
44
+
45
+ module.exports = packageTranslations;
@@ -0,0 +1,42 @@
1
+ /* eslint-disable @bigbinary/neeto/no-dangling-constants */
2
+ import { complement, startsWith } from "ramda";
3
+
4
+ export const REMARK_NODE_TYPES = {
5
+ HTML: "html",
6
+ PARAGRAPH: "paragraph",
7
+ CODE: "code",
8
+ HEADING: "heading",
9
+ TEXT: "text",
10
+ INLINE_CODE: "inlineCode",
11
+ };
12
+
13
+ export const BABEL_NODE_TYPES = { IDENTIFIER: "Identifier" };
14
+
15
+ export const SUBHEADING_PATTERN = { type: REMARK_NODE_TYPES.HEADING, depth: 2 };
16
+ export const HTML_PATTERN = { type: REMARK_NODE_TYPES.HTML };
17
+ export const IMG_PATTERN = {
18
+ type: REMARK_NODE_TYPES.HTML,
19
+ value: startsWith("<img"),
20
+ };
21
+ export const CODE_PATTERN = { type: REMARK_NODE_TYPES.CODE };
22
+ export const PARAGRAPH_PATTERN = { type: REMARK_NODE_TYPES.PARAGRAPH };
23
+ export const HTML_EXCEPT_IMG_PATTERN = {
24
+ type: REMARK_NODE_TYPES.HTML,
25
+ value: complement(startsWith("<img")),
26
+ };
27
+ export const INLINE_CODE_PATTERN = { type: REMARK_NODE_TYPES.INLINE_CODE };
28
+ export const TEXT_PATTERN = { type: REMARK_NODE_TYPES.TEXT };
29
+ export const DOCS_FOLDER_NAME = "docs";
30
+ export const TYPES_FOLDER_NAME = "typeTemplates";
31
+ export const EXPORTED_TYPES_FOLDER_NAME = "dist"; // root
32
+
33
+ export const JSDOC_IMG_HEIGHT = "200";
34
+ export const JSDOC_IMG_WIDTH = "300";
35
+
36
+ export const DOUBLE_LINE_BREAK_WITH_LEADING_COMMENT = "\n *\n";
37
+ export const LINE_BREAK = "\n";
38
+ export const JSDOC_EXAMPLE_TAG = "@example ";
39
+ export const JSDOC_END_EXAMPLE_TAG = "@endexample";
40
+ export const ASTERISK = "*";
41
+ export const ASTERISK_WITH_SPACES = " * ";
42
+ export const WHITESPACE_PARENTHESIS_REGEX = /[\s()]/g;
@@ -0,0 +1,67 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+
4
+ import _generate from "@babel/generator";
5
+ import _traverse from "@babel/traverse";
6
+ import * as babelTypes from "@babel/types";
7
+
8
+ import {
9
+ DOCS_FOLDER_NAME,
10
+ EXPORTED_TYPES_FOLDER_NAME,
11
+ TYPES_FOLDER_NAME,
12
+ } from "./constants.mjs";
13
+ import {
14
+ buildEntityTitleToEntityDescMap,
15
+ getFileContent,
16
+ getFileNameList,
17
+ parseMarkdown,
18
+ parseTypeFile,
19
+ syncTypeFiles,
20
+ defaultTypeFileTraverser,
21
+ } from "./utils.mjs";
22
+
23
+ const traverse = _traverse.default;
24
+ const generate = _generate.default;
25
+
26
+ const buildJsdoc = ({
27
+ customTypeFileTraverser = defaultTypeFileTraverser,
28
+ exportedTypesFolderName = EXPORTED_TYPES_FOLDER_NAME,
29
+ } = {}) => {
30
+ const fileNamesInsideDocs = getFileNameList(path.resolve(DOCS_FOLDER_NAME));
31
+ const typeFileNames = fs.readdirSync(path.resolve(TYPES_FOLDER_NAME));
32
+
33
+ syncTypeFiles(exportedTypesFolderName);
34
+
35
+ const entityTitleToDescMapOfAllFiles = {};
36
+
37
+ fileNamesInsideDocs.forEach(docFileName => {
38
+ const fileContent = getFileContent(docFileName);
39
+ const markdownAST = parseMarkdown(fileContent);
40
+
41
+ buildEntityTitleToEntityDescMap(
42
+ markdownAST.children,
43
+ entityTitleToDescMapOfAllFiles
44
+ );
45
+ });
46
+
47
+ // eslint-disable-next-line consistent-return
48
+ typeFileNames.forEach(typeFileName => {
49
+ const typeFileContent = getFileContent(
50
+ path.join(exportedTypesFolderName, typeFileName)
51
+ );
52
+ const typeFileAST = parseTypeFile(typeFileContent);
53
+
54
+ customTypeFileTraverser({
55
+ typeFileName: `${exportedTypesFolderName}/${typeFileName}`,
56
+ typeFileAST,
57
+ entityTitleToDescMapOfAllFiles,
58
+ babelTraverse: traverse,
59
+ babelCodeGenerator: generate,
60
+ babelTypes,
61
+ });
62
+ });
63
+
64
+ console.log("Successfully added JSDoc comments to type files.");
65
+ };
66
+
67
+ export default buildJsdoc;