297 lines
6.6 KiB
JavaScript
297 lines
6.6 KiB
JavaScript
import babelParser from "@babel/eslint-parser";
|
|
import eslint from "@eslint/js";
|
|
import reactHooks from "eslint-plugin-react-hooks";
|
|
import globals from "globals";
|
|
|
|
const sourceExtensions = "{js,jsx,mjs,ts,tsx,mts}";
|
|
|
|
const layerPatterns = {
|
|
domain: [
|
|
"**/application/**",
|
|
"**/presentation/**",
|
|
"**/adapters/**",
|
|
"**/bootstrap/**",
|
|
"react",
|
|
"react-dom",
|
|
"@tanstack/**",
|
|
],
|
|
application: [
|
|
"**/presentation/**",
|
|
"**/adapters/**",
|
|
"**/bootstrap/**",
|
|
"react",
|
|
"react-dom",
|
|
"@tanstack/**",
|
|
],
|
|
presentation: [
|
|
"**/adapters/**",
|
|
"**/bootstrap/**",
|
|
"**/application/ports/out/**",
|
|
"@tanstack/**",
|
|
],
|
|
adapters: ["**/presentation/**", "**/bootstrap/**"],
|
|
};
|
|
|
|
function restrictedImports(patterns) {
|
|
return ["error", { patterns }];
|
|
}
|
|
|
|
const commonLanguageOptions = {
|
|
ecmaVersion: "latest",
|
|
sourceType: "module",
|
|
globals: {
|
|
...globals.browser,
|
|
...globals.node,
|
|
},
|
|
};
|
|
|
|
const commonSecurityRules = {
|
|
"no-eval": "error",
|
|
"no-new-func": "error",
|
|
"no-script-url": "error",
|
|
"no-restricted-syntax": [
|
|
"error",
|
|
{
|
|
selector: "JSXAttribute[name.name='dangerouslySetInnerHTML']",
|
|
message: "Raw HTML injection is prohibited by FE-OC-019.",
|
|
},
|
|
{
|
|
selector:
|
|
"CallExpression[callee.object.name='document'][callee.property.name='createElement'][arguments.0.value='script']",
|
|
message: "Runtime script construction is prohibited by FE-OC-019.",
|
|
},
|
|
],
|
|
};
|
|
|
|
const hookRules = {
|
|
"react-hooks/rules-of-hooks": "error",
|
|
"react-hooks/exhaustive-deps": "error",
|
|
};
|
|
|
|
export default [
|
|
{
|
|
ignores: [
|
|
"dist/**",
|
|
"node_modules/**",
|
|
"artifacts/**",
|
|
"tests/fixtures/typecheck/**",
|
|
"tests/fixtures/architecture/forbidden/**",
|
|
"tests/fixtures/security/forbidden/**",
|
|
],
|
|
},
|
|
eslint.configs.recommended,
|
|
{
|
|
files: [`**/*.${sourceExtensions}`],
|
|
languageOptions: {
|
|
...commonLanguageOptions,
|
|
parserOptions: {
|
|
ecmaFeatures: { jsx: true },
|
|
},
|
|
},
|
|
plugins: {
|
|
"react-hooks": reactHooks,
|
|
},
|
|
rules: {
|
|
...commonSecurityRules,
|
|
...hookRules,
|
|
},
|
|
},
|
|
{
|
|
files: ["**/*.{ts,mts}"],
|
|
languageOptions: {
|
|
...commonLanguageOptions,
|
|
parser: babelParser,
|
|
parserOptions: {
|
|
requireConfigFile: false,
|
|
babelOptions: {
|
|
plugins: [
|
|
["@babel/plugin-syntax-typescript", { isTSX: false }],
|
|
],
|
|
},
|
|
},
|
|
},
|
|
rules: {
|
|
"no-undef": "off",
|
|
"no-unused-vars": "off",
|
|
},
|
|
},
|
|
{
|
|
files: ["**/*.tsx"],
|
|
languageOptions: {
|
|
...commonLanguageOptions,
|
|
parser: babelParser,
|
|
parserOptions: {
|
|
requireConfigFile: false,
|
|
babelOptions: {
|
|
plugins: [
|
|
[
|
|
"@babel/plugin-syntax-typescript",
|
|
{ allExtensions: true, isTSX: true },
|
|
],
|
|
"@babel/plugin-syntax-jsx",
|
|
],
|
|
},
|
|
},
|
|
},
|
|
rules: {
|
|
"no-undef": "off",
|
|
"no-unused-vars": "off",
|
|
},
|
|
},
|
|
{
|
|
files: [`src/domain/**/*.${sourceExtensions}`],
|
|
rules: {
|
|
"no-restricted-imports": restrictedImports(layerPatterns.domain),
|
|
"no-restricted-globals": [
|
|
"error",
|
|
"window",
|
|
"document",
|
|
"localStorage",
|
|
"fetch",
|
|
],
|
|
},
|
|
},
|
|
{
|
|
files: [`src/application/**/*.${sourceExtensions}`],
|
|
rules: {
|
|
"no-restricted-imports": restrictedImports(layerPatterns.application),
|
|
"no-restricted-globals": [
|
|
"error",
|
|
"window",
|
|
"document",
|
|
"localStorage",
|
|
"fetch",
|
|
],
|
|
},
|
|
},
|
|
{
|
|
files: [`src/presentation/**/*.${sourceExtensions}`],
|
|
rules: {
|
|
"no-restricted-imports": restrictedImports(layerPatterns.presentation),
|
|
"no-restricted-globals": [
|
|
"error",
|
|
"fetch",
|
|
"localStorage",
|
|
"sessionStorage",
|
|
],
|
|
},
|
|
},
|
|
{
|
|
files: [
|
|
`src/presentation/adapters/query/**/*.${sourceExtensions}`,
|
|
],
|
|
rules: {
|
|
"no-restricted-imports": restrictedImports([
|
|
"**/adapters/http/**",
|
|
"**/adapters/storage/**",
|
|
"**/adapters/auth/**",
|
|
"**/bootstrap/**",
|
|
"**/application/ports/out/**",
|
|
]),
|
|
},
|
|
},
|
|
{
|
|
files: [`src/presentation/templates/**/*.${sourceExtensions}`],
|
|
rules: {
|
|
"no-restricted-imports": restrictedImports([
|
|
"**/application/**",
|
|
"**/adapters/**",
|
|
"**/bootstrap/**",
|
|
"@tanstack/**",
|
|
]),
|
|
},
|
|
},
|
|
{
|
|
files: [`src/adapters/**/*.${sourceExtensions}`],
|
|
rules: {
|
|
"no-restricted-imports": restrictedImports(layerPatterns.adapters),
|
|
},
|
|
},
|
|
{
|
|
files: [`src/features/*/domain/**/*.${sourceExtensions}`],
|
|
rules: {
|
|
"no-restricted-imports": restrictedImports(layerPatterns.domain),
|
|
"no-restricted-globals": [
|
|
"error",
|
|
"window",
|
|
"document",
|
|
"localStorage",
|
|
"fetch",
|
|
],
|
|
},
|
|
},
|
|
{
|
|
files: [`src/features/*/application/**/*.${sourceExtensions}`],
|
|
rules: {
|
|
"no-restricted-imports": restrictedImports(layerPatterns.application),
|
|
"no-restricted-globals": [
|
|
"error",
|
|
"window",
|
|
"document",
|
|
"localStorage",
|
|
"fetch",
|
|
],
|
|
},
|
|
},
|
|
{
|
|
files: [`src/features/*/presentation/**/*.${sourceExtensions}`],
|
|
rules: {
|
|
"no-restricted-imports": restrictedImports([
|
|
"**/features/*/adapters/**",
|
|
"**/adapters/http/**",
|
|
"**/adapters/storage/**",
|
|
"**/adapters/auth/**",
|
|
"**/bootstrap/**",
|
|
"**/application/ports/out/**",
|
|
"@tanstack/**",
|
|
]),
|
|
"no-restricted-globals": [
|
|
"error",
|
|
"fetch",
|
|
"localStorage",
|
|
"sessionStorage",
|
|
],
|
|
},
|
|
},
|
|
{
|
|
files: [`src/features/*/adapters/**/*.${sourceExtensions}`],
|
|
rules: {
|
|
"no-restricted-imports": restrictedImports([
|
|
"**/presentation/**",
|
|
"**/bootstrap/**",
|
|
"@tanstack/**",
|
|
]),
|
|
},
|
|
},
|
|
{
|
|
files: [`tests/**/*.${sourceExtensions}`],
|
|
languageOptions: {
|
|
globals: {
|
|
...globals.browser,
|
|
...globals.node,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
files: [
|
|
`tests/fixtures/architecture/forbidden/**/*.${sourceExtensions}`,
|
|
],
|
|
rules: {
|
|
"no-restricted-imports": restrictedImports([
|
|
"**/adapters/**",
|
|
"**/application/ports/out/**",
|
|
"@tanstack/**",
|
|
"react",
|
|
"react-dom",
|
|
"**/application/**",
|
|
]),
|
|
"no-restricted-globals": [
|
|
"error",
|
|
"fetch",
|
|
"localStorage",
|
|
"sessionStorage",
|
|
],
|
|
},
|
|
},
|
|
];
|