Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .eslint-rules/custom.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = {};
11 changes: 11 additions & 0 deletions .eslint-rules/globals.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module.exports = {
// Globals can be disabled with the string "off"
// "writable" to allow the variable to be overwritten or "readonly" to disallow overwriting.
globals: {
Atomics: "readonly",
SharedArrayBuffer: "readonly",
// Makes logger function available everywhere. Else eslint will complaint of undef-var.
logger: "readonly",
module: "writable"
}
};
48 changes: 48 additions & 0 deletions .eslint-rules/helpers/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
const fs = require("fs");

const buildPathGroupsBasedOnWebpackAliases = () => {
const rootOfProject = __dirname + `/../../`;

const isFile = filePath =>
fs.existsSync(filePath) && fs.lstatSync(filePath).isFile();

const webpackAliasPath = rootOfProject + "config/webpack/alias.js";

const hasWebpackAliasConfig = isFile(webpackAliasPath);

const isRailsProject = isFile(rootOfProject + "Gemfile");

const emptyPathGroups = [];

if (!hasWebpackAliasConfig || !isRailsProject) return emptyPathGroups;

const {
resolve: { alias }
} = require(webpackAliasPath);

const railsJSFilesRoot = rootOfProject + "app/javascript/";

const pathGroups = Object.entries(alias).map(([name, path]) => {
// sometimes alias might be already resolved to full absolute path
const isAleadyAnAbsolutePath = path.includes("app/");

const absolutePath = isAleadyAnAbsolutePath
? path
: `${railsJSFilesRoot}${path}`;
const wildCard =
isFile(absolutePath + ".js") || isFile(absolutePath + ".jsx")
? ""
: "/**";

let group = "internal";
if (name === "neetoui") {
group = "external";
}

return { pattern: `${name}${wildCard}`, group };
});

return pathGroups;
};

module.exports = { buildPathGroupsBasedOnWebpackAliases };
20 changes: 20 additions & 0 deletions .eslint-rules/imports/enforced.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
module.exports = {
rules: {
// not-auto-fixable: Prefer a default export if module exports a single name.
"import/prefer-default-export": "off",
// not-auto-fixable: Forbid a module from importing a module with a dependency path back to itself.
"import/no-cycle": ["error", { maxDepth: 1, ignoreExternal: true }],
// not-auto-fixable: Prevent unnecessary path segments in import and require statements.
"import/no-useless-path-segments": ["error", { noUselessIndex: true }],
// not-auto-fixable: Report any invalid exports, i.e. re-export of the same name.
"import/export": "error",
// not-auto-fixable: Forbid the use of mutable exports with var or let.
"import/no-mutable-exports": "error",
// not-auto-fixable: Ensure all imports appear before other statements.
"import/first": "error",
// not-auto-fixable: Ensure all exports appear after other statements.
"import/exports-last": "error",
// auto-fixable: Enforce a newline after import statements.
"import/newline-after-import": ["error", { count: 1 }]
}
};
65 changes: 65 additions & 0 deletions .eslint-rules/imports/order.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
const { buildPathGroupsBasedOnWebpackAliases } = require(__dirname +
"/../helpers");
const pathGroups = buildPathGroupsBasedOnWebpackAliases();

const pathGroupForKeepingReactImportsAtTop = {
pattern: "react+(-native|)",
group: "external",
position: "before"
};

/*
Example pathGroups structure. Adding this here
so that if anyone wants to add custom config,
they can make use of this:
[
{ pattern: 'apis/**', group: 'internal' },
{ pattern: 'common/**', group: 'internal' },
{ pattern: 'components/**', group: 'internal' },
{ pattern: 'constants/**', group: 'internal' },
{ pattern: 'contexts/**', group: 'internal' },
{ pattern: 'reducers/**', group: 'internal' },
{ pattern: 'Constants', group: 'internal' },
{ pattern: 'neetoui/**', group: 'external' },
{
pattern: 'react+(-native|)',
group: 'external',
position: 'before'
}
]
*/
pathGroups.push(pathGroupForKeepingReactImportsAtTop);

module.exports = {
rules: {
// auto-fixable: Enforce a convention in module import order - we enforce https://www.bigbinary.com/react-best-practices/sort-import-statements
"import/order": [
"error",
{
"newlines-between": "always",
alphabetize: { order: "asc", caseInsensitive: true },
warnOnUnassignedImports: true,
groups: [
"builtin",
"external",
"internal",
"index",
"sibling",
"parent",
"object",
"type"
],
/*
* Currently we check for existence of webpack alias
* config and then iterate over the aliases and create
* these pathGroups. Only caveat with this mechanism
* is that in VSCode eslint plugin won't dynamically
* read it. But eslint cli would!
*/
pathGroups,
// Ignore react imports so that they're always ordered to the top of the file.
pathGroupsExcludedImportTypes: ["react", "react-native"]
}
]
}
};
24 changes: 24 additions & 0 deletions .eslint-rules/overrides.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
module.exports = {
// Currently we are using this section for excluding certain files from certain rules.
overrides: [
{
files: [
".eslintrc.js",
".prettierrc.js",
"app/assets/**/*",
"app/javascript/packs/**/*",
"*.json"
],
rules: {
"import/order": "off",
"react-hooks/rules-of-hooks": "off"
}
},
{
files: ["app/javascript/packs/**/*.{js,jsx}"],
rules: {
"no-redeclare": "off"
}
}
]
};
8 changes: 8 additions & 0 deletions .eslint-rules/promise.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module.exports = {
rules: {
// not-auto-fixable: ensure people use async/await promising chaining rather than using "then-catch-finally" statements
"promise/prefer-await-to-then": "error",
// auto-fixable: avoid calling "new" on a Promise static method like reject, resolve etc
"promise/no-new-statics": "error"
}
};
32 changes: 32 additions & 0 deletions .eslint-rules/react.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
module.exports = {
rules: {
// not-auto-fixable: Prevent missing props validation in a React component definition.
"react/prop-types": "off",
// not-auto-fixable: Detect unescaped HTML entities, which might represent malformed tags.
"react/no-unescaped-entities": "off",
// not-auto-fixable: Prevent missing displayName in a React component definition. Useful when using React extensions in browser and checking for component name.
"react/display-name": "error",
// not-auto-fixable: Reports when this.state is accessed within setState.
"react/no-access-state-in-setstate": "error",
// not-auto-fixable: Prevent usage of dangerous JSX props.
"react/no-danger": "error",
// not-auto-fixable: Report when a DOM element is using both children and dangerouslySetInnerHTML.
"react/no-danger-with-children": "error",
// not-auto-fixable: Prevent definitions of unused prop types.
"react/no-unused-prop-types": "error",
// not-auto-fixable: Report missing key props in iterators/collection literals. Important rule!
"react/jsx-key": "error",
// not-auto-fixable: Enforce no duplicate props.
"react/jsx-no-duplicate-props": "error",
// not-auto-fixable: Disallow undeclared variables in JSX.
"react/jsx-no-undef": "error",
// not-auto-fixable: Enforce PascalCase for user-defined JSX components.
"react/jsx-pascal-case": ["error", { allowNamespace: true }],
// not-auto-fixable: Prevent variables used in JSX to be marked as unused.
"react/jsx-uses-vars": "error",
// not-auto-fixable: Ensures https://reactjs.org/docs/hooks-rules.html.
"react-hooks/rules-of-hooks": "error",
// not-auto-fixable: Ensures https://reactjs.org/docs/hooks-rules.html - Checks effect dependencies.
"react-hooks/exhaustive-deps": "off"
}
};
138 changes: 17 additions & 121 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,23 @@ module.exports = {
"plugin:json/recommended",
"eslint:recommended",
"plugin:react/recommended",
"prettier"
"prettier",
"./.eslint-rules/globals",
"./.eslint-rules/imports/order",
"./.eslint-rules/overrides",
// ensure that you don't add custom rules
// without taking permission from team leads.
"./.eslint-rules/custom",
// custom rules cannot override the following rules.
"./.eslint-rules/imports/enforced",
"./.eslint-rules/react",
"./.eslint-rules/promise"
],
settings: {
react: {
version: "detect"
}
},
globals: {
Atomics: "readonly",
SharedArrayBuffer: "readonly",
// Makes logger function available everywhere. Else eslint will complaint of undef-var.
logger: true,
module: true
},
parserOptions: {
ecmaFeatures: {
jsx: true
Expand All @@ -42,7 +45,11 @@ module.exports = {
// auto-fixable: Respect all Prettier rules and apply it.
"prettier/prettier": "error",
// auto-fixable: Indent by 2 spaces. Same as editorconfig and Rubocop config.
indent: ["error", 2, { SwitchCase: 1 }],
indent: [
"error",
2,
{ SwitchCase: 1, ignoredNodes: ["LogicalExpression"] }
],
// not-auto-fixable: No unused variables allowed.
"no-unused-vars": "error",
// not-auto-fixable: No undefined variables allowed.
Expand All @@ -56,123 +63,12 @@ module.exports = {
"error",
{ blankLine: "always", prev: "var", next: "return" }
],
// not-auto-fixable: ensure people use async/await promising chaining rather than using "then-catch-finally" statements
"promise/prefer-await-to-then": "error",
// auto-fixable: avoid calling "new" on a Promise static method like reject, resolve etc
"promise/no-new-statics": "error",
// not-auto-fixable: Prevent missing props validation in a React component definition.
"react/prop-types": "off",
// not-auto-fixable: Detect unescaped HTML entities, which might represent malformed tags.
"react/no-unescaped-entities": "off",
// not-auto-fixable: Prevent missing displayName in a React component definition. Useful when using React extensions in browser and checking for component name.
"react/display-name": "error",
// not-auto-fixable: Reports when this.state is accessed within setState.
"react/no-access-state-in-setstate": "error",
// not-auto-fixable: Prevent un-sanitized dangerouslySetInnerHTML.
"jam3/no-sanitizer-with-danger": [
2,
{
wrapperName: ["dompurify", "sanitizer", "sanitize"]
}
],
// not-auto-fixable: Report when a DOM element is using both children and dangerouslySetInnerHTML.
"react/no-danger-with-children": "error",
// not-auto-fixable: Prevent definitions of unused prop types.
"react/no-unused-prop-types": "error",
// not-auto-fixable: Report missing key props in iterators/collection literals. Important rule!
"react/jsx-key": "error",
// not-auto-fixable: Enforce no duplicate props.
"react/jsx-no-duplicate-props": "error",
// not-auto-fixable: Disallow undeclared variables in JSX.
"react/jsx-no-undef": "error",
// not-auto-fixable: Enforce PascalCase for user-defined JSX components.
"react/jsx-pascal-case": ["error", { allowNamespace: true }],
// not-auto-fixable: Prevent variables used in JSX to be marked as unused.
"react/jsx-uses-vars": "error",
// not-auto-fixable: Ensures https://reactjs.org/docs/hooks-rules.html.
"react-hooks/rules-of-hooks": "error",
// not-auto-fixable: Ensures https://reactjs.org/docs/hooks-rules.html - Checks effect dependencies.
"react-hooks/exhaustive-deps": "off",
// not-auto-fixable: Prefer a default export if module exports a single name.
"import/prefer-default-export": "off",
// not-auto-fixable: Forbid a module from importing a module with a dependency path back to itself.
"import/no-cycle": ["error", { maxDepth: 1, ignoreExternal: true }],
// not-auto-fixable: Prevent unnecessary path segments in import and require statements.
"import/no-useless-path-segments": ["error", { noUselessIndex: true }],
// not-auto-fixable: Report any invalid exports, i.e. re-export of the same name.
"import/export": "error",
// not-auto-fixable: Forbid the use of mutable exports with var or let.
"import/no-mutable-exports": "error",
// not-auto-fixable: Ensure all imports appear before other statements.
"import/first": "error",
// not-auto-fixable: Ensure all exports appear after other statements.
"import/exports-last": "error",
// auto-fixable: Enforce a newline after import statements.
"import/newline-after-import": ["error", { count: 1 }],
// auto-fixable: Enforce a convention in module import order - we enforce https://www.bigbinary.com/react-best-practices/sort-import-statements
"import/order": [
"error",
{
"newlines-between": "always",
alphabetize: { order: "asc", caseInsensitive: true },
warnOnUnassignedImports: true,
groups: [
"builtin",
"external",
"internal",
"index",
"sibling",
"parent",
"object",
"type"
],
/*
* These are the paths defined in our alias.js file.
* Thus when making change in alias.js, ensure that
* change is reflected over here. All aliases should be
* marked as "internal" group.
* TODO: find a dynamic way to fetch this content
* from the alias.js itself.
* TODO: Also check the possiblity of using "@/" prefix
* to import aliases. This way we can mark all "@/" pattern
* as "internal" group.
*/
pathGroups: [
{ pattern: "apis/**", group: "internal" },
{ pattern: "common/**", group: "internal" },
{ pattern: "components/**", group: "internal" },
{ pattern: "constants/**", group: "internal" },
{ pattern: "contexts/**", group: "internal" },
{ pattern: "reducers/**", group: "internal" },
{ pattern: "neetoui/**", group: "external" },
// react imports should be at the top.
{ pattern: "react+(-native|)", group: "external", position: "before" }
],
// Ignore react imports so that they're always ordered to the top of the file.
pathGroupsExcludedImportTypes: ["react", "react-native"]
}
]
},
// Currently we are using this section for excluding certain files from certain rules.
overrides: [
{
files: [
".eslintrc.js",
".prettierrc.js",
"app/assets/**/*.{js,jsx}",
"app/javascript/packs/**/*.{js,jsx}",
"*.json"
],
rules: {
"import/order": "off",
"react-hooks/rules-of-hooks": "off"
}
},
{
files: ["app/javascript/packs/**/*.{js,jsx}"],
rules: {
"no-redeclare": "off"
}
}
]
}
};
Loading