Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LINT-45: Split layers-slices-boundaries #46

Draft
wants to merge 16 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 14 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
10 changes: 4 additions & 6 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
const path = require("path");

module.exports = {
parserOptions: {
"ecmaVersion": "2015",
"sourceType": "module",
},
extends: [
path.resolve(__dirname, "./rules/public-api"),
path.resolve(__dirname, "./rules/layers-slices"),
path.resolve(__dirname, "./rules/import-order")
],
"./rules/public-api",
"./rules/layers-slices",
"./rules/import-order",
].map(require.resolve),
azinit marked this conversation as resolved.
Show resolved Hide resolved
};
330 changes: 330 additions & 0 deletions rules/integration.custom.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,330 @@
const { ESLint } = require("eslint");
const assert = require("assert");
const { configLib } = require("../utils");

describe("Integration Custom configs tests:", () => {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Тестируем варианты кастмоного подключения правил.


describe("With custom recommended rules: ", () => {

const cfg = {
parserOptions: {
"ecmaVersion": "2015",
"sourceType": "module",
},
extends: [
"./layers-slices",
"./public-api",
"./import-order",
].map(require.resolve),
};

const eslint = new ESLint({
useEslintrc: false,
baseConfig: configLib.mockImports(cfg),
});

it("Custom config should lint with errors", async () => {
const report = await eslint.lintText(`
import { getSmth } from "./lib"; // import-order
import axios from "axios";
import { data } from "../fixtures"; // import-order
import { authModel } from "entities/auth"; // import-order
import { Button } from "shared/ui"; // import-order
import { LoginForm } from "features/login-form"; // import-order
import { Header } from "widgets/header"; // import-order, import-boundaries
import { debounce } from "shared/lib/fp"; // import-order
import { AuthPage } from "pages/auth"; // import-boundaries
import { IssueDetails } from "widgets/issue-details/ui/details"; // import-order, publicAPI
`, {
filePath: "src/widgets/mock/index.js",
});
assert.strictEqual(report[0].errorCount, 11);
});

it("Custom config should lint without errors", async () => {
const report = await eslint.lintText(`
import { getRoute } from "pages/auth";
import { Header } from "widgets/header";
import { LoginForm } from "features/login-form";
import { Phone } from "features/login-form/phone";
import { Article } from "entities/article";
import { Button } from "shared/ui/button";
import { LoginAPI } from "shared/api";
import { model } from "../model";
import { styles } from "./styles.module.scss";
`, { filePath: "src/app/ui/index.js" });

assert.strictEqual(report[0].errorCount, 0);
});

it("Custom config should lint only with import-order error", async () => {
const report = await eslint.lintText(`
import { LoginAPI } from "shared/api";
import { getRoute } from "pages/auth";
`, { filePath: "src/app/ui/index.js" });

assert.strictEqual(report[0].errorCount, 1);
});

it("Custom config should lint only with layer error", async () => {
const report = await eslint.lintText(`
import { LoginForm } from "features/login-form";
`, { filePath: "src/entities/ui/index.js" });

assert.strictEqual(report[0].errorCount, 1);
});

it("Custom config should lint only with slice error", async () => {
const report = await eslint.lintText(`
import { Article } from "entities/article";
`, { filePath: "src/entities/avatar/ui/index.js" });

assert.strictEqual(report[0].errorCount, 1);
});

it("Custom config should lint only with PublicAPI error", async () => {
const report = await eslint.lintText(`
import { orderModel } from "entities/order/model";
`, { filePath: "src/features/profile/ui/index.js" });

assert.strictEqual(report[0].errorCount, 1);
});
})

describe("Without publicAPI: ", () => {

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Без PublicAPI

const cfg = {
parserOptions: {
"ecmaVersion": "2015",
"sourceType": "module",
},
extends: [
"./layers-slices",
"./import-order",
].map(require.resolve),
};

const eslint = new ESLint({
useEslintrc: false,
baseConfig: configLib.mockImports(cfg),
});

it("Custom config should lint with errors", async () => {
const report = await eslint.lintText(`
import { getSmth } from "./lib"; // import-order
import axios from "axios";
import { data } from "../fixtures"; // import-order
import { authModel } from "entities/auth"; // import-order
import { Button } from "shared/ui"; // import-order
import { LoginForm } from "features/login-form"; // import-order
import { Header } from "widgets/header"; // import-order, import-boundaries
import { debounce } from "shared/lib/fp"; // import-order
import { AuthPage } from "pages/auth"; // import-boundaries
`, {
filePath: "src/widgets/mock/index.js",
});
assert.strictEqual(report[0].errorCount, 9);
});

it("Custom config should lint without errors", async () => {
const report = await eslint.lintText(`
import { getRoute } from "pages/auth";
import { Header } from "widgets/header";
import { LoginForm } from "features/login-form";
import { Phone } from "features/login-form/phone";
import { Article } from "entities/article";
import { Button } from "shared/ui/button";
import { LoginAPI } from "shared/api";
import { model } from "../model";
import { styles } from "./styles.module.scss";
`, { filePath: "src/app/ui/index.js" });

assert.strictEqual(report[0].errorCount, 0);
});

it("Custom config should lint only with import-order error", async () => {
const report = await eslint.lintText(`
import { LoginAPI } from "shared/api";
import { getRoute } from "pages/auth";
`, { filePath: "src/app/ui/index.js" });

assert.strictEqual(report[0].errorCount, 1);
});

it("Custom config should lint only with layer error", async () => {
const report = await eslint.lintText(`
import { LoginForm } from "features/login-form";
`, { filePath: "src/entities/ui/index.js" });

assert.strictEqual(report[0].errorCount, 1);
});

it("Custom config should lint only with slice error", async () => {
const report = await eslint.lintText(`
import { Article } from "entities/article";
`, { filePath: "src/entities/avatar/ui/index.js" });

assert.strictEqual(report[0].errorCount, 1);
});

})

describe("Without import-order: ", () => {

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Без Import-order

const cfg = {
parserOptions: {
"ecmaVersion": "2015",
"sourceType": "module",
},
extends: [
"./public-api",
"./layers-slices",
].map(require.resolve),
};

const eslint = new ESLint({
useEslintrc: false,
baseConfig: configLib.mockImports(cfg),
});

it("Custom config should lint with errors", async () => {
const report = await eslint.lintText(`
import { getSmth } from "./lib";
import axios from "axios";
import { data } from "../fixtures";
import { authModel } from "entities/auth";
import { Button } from "shared/ui";
import { LoginForm } from "features/login-form";
import { Header } from "widgets/header"; // import-boundaries
import { debounce } from "shared/lib/fp";
import { AuthPage } from "pages/auth"; // import-boundaries
import { IssueDetails } from "widgets/issue-details/ui/details"; // import-boundaries, publicAPI
`, {
filePath: "src/widgets/mock/index.js",
});

assert.strictEqual(report[0].errorCount, 4);
});

it("Custom config should lint without errors", async () => {
const report = await eslint.lintText(`
import { getRoute } from "pages/auth";
import { Header } from "widgets/header";
import { LoginForm } from "features/login-form";
import { Phone } from "features/login-form/phone";
import { Article } from "entities/article";
import { Button } from "shared/ui/button";
import { LoginAPI } from "shared/api";
import { model } from "../model";
import { styles } from "./styles.module.scss";
`, { filePath: "src/app/ui/index.js" });

assert.strictEqual(report[0].errorCount, 0);
});

it("Custom config should lint only with layer error", async () => {
const report = await eslint.lintText(`
import { LoginForm } from "features/login-form";
`, { filePath: "src/entities/ui/index.js" });

assert.strictEqual(report[0].errorCount, 1);
});

it("Custom config should lint only with slice error", async () => {
const report = await eslint.lintText(`
import { Article } from "entities/article";
`, { filePath: "src/entities/avatar/ui/index.js" });

assert.strictEqual(report[0].errorCount, 1);
});

it("Custom config should lint only with PublicAPI error", async () => {
const report = await eslint.lintText(`
import { orderModel } from "entities/order/model";
`, { filePath: "src/features/profile/ui/index.js" });

assert.strictEqual(report[0].errorCount, 1);
});
})

describe("Without layers-slice, but with layers: ", () => {

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

С отдельно подключенным layers, на этом я думаю достаточно и отдельно проверять slices не имеет смысла, т.к. layers и slices имеют одинаковое правило под собой и влияют только друг на друга.

const cfg = {
parserOptions: {
"ecmaVersion": "2015",
"sourceType": "module",
},
extends: [
"./public-api",
"./import-order",
"./layers",
].map(require.resolve),
};

const eslint = new ESLint({
useEslintrc: false,
baseConfig: configLib.mockImports(cfg),
});

it("Custom config should lint with errors", async () => {
const report = await eslint.lintText(`
import { getSmth } from "./lib"; // import-order
import axios from "axios";
import { authProcess } from "processes/auth-process"; // layers
import { data } from "../fixtures"; // import-order
import { authModel } from "entities/auth"; // import-order
import { Button } from "shared/ui"; // import-order
import { LoginForm } from "features/login-form"; // import-order
import { Header } from "widgets/header"; // import-order
import { debounce } from "shared/lib/fp"; // import-order
import { AuthPage } from "pages/auth"; // layers
import { IssueDetails } from "widgets/issue-details/ui/details"; // publicAPI
`, {
filePath: "src/widgets/mock/index.js",
});

assert.strictEqual(report[0].errorCount, 10);
});

it("Custom config should lint without errors", async () => {
const report = await eslint.lintText(`
import { getRoute } from "pages/auth";
import { Header } from "widgets/header";
import { LoginForm } from "features/login-form";
import { Phone } from "features/login-form/phone";
import { Article } from "entities/article";
import { Button } from "shared/ui/button";
import { LoginAPI } from "shared/api";
import { model } from "../model";
import { styles } from "./styles.module.scss";
`, { filePath: "src/app/ui/index.js" });

assert.strictEqual(report[0].errorCount, 0);
});

it("Custom config should lint only with import-order error", async () => {
const report = await eslint.lintText(`
import { LoginAPI } from "shared/api";
import { getRoute } from "pages/auth";
`, { filePath: "src/app/ui/index.js" });

assert.strictEqual(report[0].errorCount, 1);
});

it("Custom config should lint only with layer error", async () => {
const report = await eslint.lintText(`
import { LoginForm } from "features/login-form";
`, { filePath: "src/entities/ui/index.js" });

assert.strictEqual(report[0].errorCount, 1);
});

it("Custom config should lint only with PublicAPI error", async () => {
const report = await eslint.lintText(`
import { orderModel } from "entities/order/model";
`, { filePath: "src/features/profile/ui/index.js" });

assert.strictEqual(report[0].errorCount, 1);
});
})
});
1 change: 0 additions & 1 deletion rules/integration.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ describe("Integration tests:", () => {
`, {
filePath: "src/widgets/mock/index.js",
});

assert.strictEqual(report[0].errorCount, 11);
});

Expand Down
2 changes: 1 addition & 1 deletion rules/layers-slices/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,4 @@ import { sessionModel } from "entities/session";
import { Form, Button } from "shared/ui";
import { getAuthCtx } from "entities/session";
import { UserAvatar } from "entities/user";
```
```
7 changes: 3 additions & 4 deletions rules/layers-slices/index.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
const { layersLib } = require("../../utils");

const getLayersRules = () =>

layersLib.FS_LAYERS.map((layer) => ({
from: layer,
allow: layersLib.getLowerLayers(layer),
}));

const getLayersBoundariesElements = () =>
const getAllBoundariesElements = () =>
layersLib.FS_LAYERS.map((layer) => ({
type: layer,
pattern: `${layer}/*`,
Expand All @@ -20,7 +19,7 @@ module.exports = {
extends: ["plugin:boundaries/recommended"],
ignorePatterns: [".eslintrc.js"],
settings: {
"boundaries/elements": getLayersBoundariesElements(),
"boundaries/elements": getAllBoundariesElements(),
},
rules: {
"boundaries/element-types": [
Expand All @@ -32,4 +31,4 @@ module.exports = {
},
],
},
};
};
Loading