@boundaries/eslint-plugin 5.4.0 → 6.0.0-beta.2
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/README.md +9 -9
- package/dist/Config/Config.d.ts +6 -3
- package/dist/Config/Config.js +18 -7
- package/dist/Config/Recommended.d.ts +1 -1
- package/dist/Config/Recommended.js +4 -8
- package/dist/Config/Strict.d.ts +1 -1
- package/dist/Config/Strict.js +2 -2
- package/dist/Debug/Debug.d.ts +34 -0
- package/dist/Debug/Debug.js +285 -0
- package/dist/Debug/index.d.ts +1 -0
- package/dist/{Support → Debug}/index.js +0 -1
- package/dist/Elements/Elements.d.ts +9 -7
- package/dist/Elements/Elements.js +12 -7
- package/dist/Elements/Elements.types.d.ts +1 -0
- package/dist/Messages/CustomMessages.d.ts +44 -0
- package/dist/Messages/CustomMessages.js +156 -0
- package/dist/Messages/CustomMessages.types.d.ts +25 -0
- package/dist/Messages/CustomMessages.types.js +2 -0
- package/dist/Messages/Messages.d.ts +42 -13
- package/dist/Messages/Messages.js +400 -177
- package/dist/Messages/index.d.ts +2 -0
- package/dist/Messages/index.js +2 -0
- package/dist/Public/Config.types.d.ts +2 -2
- package/dist/Public/Config.types.js +2 -2
- package/dist/Public/Rules.types.d.ts +5 -4
- package/dist/Public/Rules.types.js +5 -6
- package/dist/Public/Settings.types.d.ts +3 -2
- package/dist/Public/Settings.types.js +4 -3
- package/dist/Public/index.d.ts +1 -0
- package/dist/Rules/Dependencies.d.ts +59 -0
- package/dist/Rules/Dependencies.js +439 -0
- package/dist/Rules/EntryPoint.js +44 -94
- package/dist/Rules/External.js +93 -68
- package/dist/Rules/NoIgnored.js +4 -4
- package/dist/Rules/NoPrivate.js +18 -5
- package/dist/Rules/NoUnknown.js +5 -5
- package/dist/Rules/NoUnknownFiles.js +4 -3
- package/dist/Rules/Support/DependencyRule.d.ts +9 -1
- package/dist/Rules/Support/DependencyRule.js +15 -6
- package/dist/Rules/Support/DependencyRule.types.d.ts +1 -1
- package/dist/Rules/Support/Helpers.d.ts +6 -2
- package/dist/Rules/Support/Helpers.js +7 -31
- package/dist/Settings/Helpers.d.ts +83 -1
- package/dist/Settings/Helpers.js +197 -7
- package/dist/Settings/Settings.d.ts +19 -2
- package/dist/Settings/Settings.js +20 -11
- package/dist/Settings/Validations.d.ts +11958 -43
- package/dist/Settings/Validations.js +783 -157
- package/dist/Settings/index.d.ts +0 -1
- package/dist/Settings/index.js +0 -1
- package/dist/{Settings → Shared}/Settings.types.d.ts +137 -37
- package/dist/{Settings → Shared}/Settings.types.js +30 -6
- package/dist/{Support/Common.d.ts → Shared/TypeHelpers.d.ts} +18 -0
- package/dist/{Support/Common.js → Shared/TypeHelpers.js} +28 -1
- package/dist/Shared/index.d.ts +2 -0
- package/dist/Shared/index.js +18 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +16 -14
- package/package.json +9 -8
- package/dist/Rules/ElementTypes.d.ts +0 -25
- package/dist/Rules/ElementTypes.js +0 -279
- package/dist/Support/Debug.d.ts +0 -5
- package/dist/Support/Debug.js +0 -54
- package/dist/Support/index.d.ts +0 -2
package/README.md
CHANGED
|
@@ -25,8 +25,8 @@ Enforce architectural boundaries in your JavaScript and TypeScript projects.
|
|
|
25
25
|
|
|
26
26
|
**ESLint Plugin Boundaries** is an ESLint plugin that helps you maintain clean architecture by enforcing boundaries between different parts of your codebase. Define your architectural layers, specify how they can interact, and get instant feedback when boundaries are violated.
|
|
27
27
|
|
|
28
|
-
- **Architectural Enforcement**: Define
|
|
29
|
-
- **Flexible Configuration**: Adapt the plugin to any project structure. It works with monorepos, modular architectures, layered patterns, and
|
|
28
|
+
- **Architectural Enforcement**: Define elements and dependency rules that match your project's architecture
|
|
29
|
+
- **Flexible Configuration**: Adapt the plugin to any project structure. It works with monorepos, modular architectures, layered patterns, and any custom structure you can imagine
|
|
30
30
|
- **Real-time Feedback**: Get immediate ESLint errors when imports violate your architectural rules
|
|
31
31
|
|
|
32
32
|
## Documentation
|
|
@@ -63,9 +63,9 @@ export default [
|
|
|
63
63
|
plugins: { boundaries },
|
|
64
64
|
settings: {
|
|
65
65
|
"boundaries/elements": [
|
|
66
|
-
{ type: "
|
|
67
|
-
{ type: "
|
|
68
|
-
{ type: "
|
|
66
|
+
{ type: "controller", pattern: "controllers/*" },
|
|
67
|
+
{ type: "model", pattern: "models/*" },
|
|
68
|
+
{ type: "view", pattern: "views/*" }
|
|
69
69
|
]
|
|
70
70
|
}
|
|
71
71
|
}
|
|
@@ -77,12 +77,12 @@ Define your dependency rules:
|
|
|
77
77
|
```javascript
|
|
78
78
|
{
|
|
79
79
|
rules: {
|
|
80
|
-
"boundaries/
|
|
80
|
+
"boundaries/dependencies": [2, {
|
|
81
81
|
default: "disallow",
|
|
82
82
|
rules: [
|
|
83
|
-
{ from: "
|
|
84
|
-
{ from: "
|
|
85
|
-
{ from: "
|
|
83
|
+
{ from: { type: "controller" }, allow: { to: { type: ["model", "view"] } } },
|
|
84
|
+
{ from: { type: "view" }, allow: { to: { type: "model" } } },
|
|
85
|
+
{ from: { type: "model" }, disallow: { to: { type: "*" } } }
|
|
86
86
|
]
|
|
87
87
|
}]
|
|
88
88
|
}
|
package/dist/Config/Config.d.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import type { Linter } from "eslint";
|
|
2
|
-
import type { PluginBoundaries, Config } from "../
|
|
3
|
-
import { PLUGIN_NAME } from "../
|
|
2
|
+
import type { PluginBoundaries, Config } from "../Shared";
|
|
3
|
+
import { PLUGIN_NAME } from "../Shared";
|
|
4
4
|
export * from "../Public";
|
|
5
|
+
/**
|
|
6
|
+
* The full ESLint config object returned by createConfig, including the plugins field with the boundaries plugin registered.
|
|
7
|
+
*/
|
|
5
8
|
type PluginFullConfig<PluginName extends string = typeof PLUGIN_NAME> = {
|
|
6
9
|
plugins: Record<PluginName, PluginBoundaries>;
|
|
7
10
|
files: Linter.Config["files"];
|
|
@@ -28,7 +31,7 @@ type PluginFullConfig<PluginName extends string = typeof PLUGIN_NAME> = {
|
|
|
28
31
|
* },
|
|
29
32
|
* rules: {
|
|
30
33
|
* ...recommended.rules,
|
|
31
|
-
* "boundaries/
|
|
34
|
+
* "boundaries/dependencies": ["error", { default: "disallow" }],
|
|
32
35
|
* }
|
|
33
36
|
* });
|
|
34
37
|
*
|
package/dist/Config/Config.js
CHANGED
|
@@ -21,31 +21,42 @@ exports.strict = exports.recommended = void 0;
|
|
|
21
21
|
exports.createConfig = createConfig;
|
|
22
22
|
const index_1 = __importDefault(require("../index"));
|
|
23
23
|
const Settings_1 = require("../Settings");
|
|
24
|
+
const Shared_1 = require("../Shared");
|
|
24
25
|
const Recommended_1 = __importDefault(require("./Recommended"));
|
|
25
26
|
const Strict_1 = __importDefault(require("./Strict"));
|
|
26
27
|
__exportStar(require("../Public"), exports);
|
|
28
|
+
/**
|
|
29
|
+
* Rewrites rule keys to the effective plugin namespace used by `createConfig`.
|
|
30
|
+
*
|
|
31
|
+
* It accepts rules prefixed either with the default plugin name (`boundaries`)
|
|
32
|
+
* or with the custom plugin name passed to `createConfig`.
|
|
33
|
+
*
|
|
34
|
+
* @param pluginName - Plugin namespace to enforce in output rule keys.
|
|
35
|
+
* @param rules - Input rule entries from the user config.
|
|
36
|
+
* @returns Rules object normalized to the requested plugin namespace.
|
|
37
|
+
*/
|
|
27
38
|
function renamePluginRules(pluginName, rules) {
|
|
28
39
|
if (!rules) {
|
|
29
40
|
return {};
|
|
30
41
|
}
|
|
31
|
-
const allowedPrefixes = new Set([
|
|
42
|
+
const allowedPrefixes = new Set([Shared_1.PLUGIN_NAME, pluginName]);
|
|
32
43
|
// Return the same rules objects, but converting plugin default rule keys with provided plugin name
|
|
33
44
|
return Object.entries(rules).reduce((acc, [key, value]) => {
|
|
34
45
|
if (!key.includes("/")) {
|
|
35
|
-
throw new Error(`Invalid rule key "${key}". When using createConfig, all rules must belong to eslint-plugin-boundaries. You can prefix them with the original plugin name "${
|
|
46
|
+
throw new Error(`Invalid rule key "${key}". When using createConfig, all rules must belong to eslint-plugin-boundaries. You can prefix them with the original plugin name "${Shared_1.PLUGIN_NAME}/", or with the provided plugin name "${pluginName}/".`);
|
|
36
47
|
}
|
|
37
48
|
const splittedRuleKey = key.split("/");
|
|
38
49
|
const rulePrefix = splittedRuleKey[0];
|
|
39
50
|
const ruleName = splittedRuleKey[1];
|
|
40
51
|
if (!allowedPrefixes.has(rulePrefix)) {
|
|
41
|
-
throw new Error(`Invalid rule key "${key}". When using createConfig, all rules must belong to eslint-plugin-boundaries. You can prefix them with the original plugin name "${
|
|
52
|
+
throw new Error(`Invalid rule key "${key}". When using createConfig, all rules must belong to eslint-plugin-boundaries. You can prefix them with the original plugin name "${Shared_1.PLUGIN_NAME}/", or with the provided plugin name "${pluginName}/".`);
|
|
42
53
|
}
|
|
43
54
|
if (!(0, Settings_1.isRuleShortName)(ruleName)) {
|
|
44
55
|
throw new Error(`Invalid rule name "${ruleName}". When using createConfig, all rules must belong to eslint-plugin-boundaries.`);
|
|
45
56
|
}
|
|
46
57
|
let newKey;
|
|
47
|
-
if (rulePrefix ===
|
|
48
|
-
const suffix = key.slice(
|
|
58
|
+
if (rulePrefix === Shared_1.PLUGIN_NAME) {
|
|
59
|
+
const suffix = key.slice(Shared_1.PLUGIN_NAME.length + 1);
|
|
49
60
|
newKey = `${pluginName}/${suffix}`;
|
|
50
61
|
}
|
|
51
62
|
else {
|
|
@@ -77,14 +88,14 @@ function renamePluginRules(pluginName, rules) {
|
|
|
77
88
|
* },
|
|
78
89
|
* rules: {
|
|
79
90
|
* ...recommended.rules,
|
|
80
|
-
* "boundaries/
|
|
91
|
+
* "boundaries/dependencies": ["error", { default: "disallow" }],
|
|
81
92
|
* }
|
|
82
93
|
* });
|
|
83
94
|
*
|
|
84
95
|
* export default [config];
|
|
85
96
|
* ```
|
|
86
97
|
*/
|
|
87
|
-
function createConfig(config, name =
|
|
98
|
+
function createConfig(config, name = Shared_1.PLUGIN_NAME) {
|
|
88
99
|
const pluginsRegistration = {
|
|
89
100
|
[name]: index_1.default,
|
|
90
101
|
};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const
|
|
3
|
+
const Shared_1 = require("../Shared");
|
|
4
4
|
const { ELEMENTS,
|
|
5
5
|
// rules
|
|
6
|
-
RULE_ELEMENT_TYPES, RULE_ENTRY_POINT, RULE_EXTERNAL, RULE_NO_IGNORED, RULE_NO_PRIVATE, RULE_NO_UNKNOWN_FILES, RULE_NO_UNKNOWN, } =
|
|
6
|
+
RULE_ELEMENT_TYPES, RULE_DEPENDENCIES, RULE_ENTRY_POINT, RULE_EXTERNAL, RULE_NO_IGNORED, RULE_NO_PRIVATE, RULE_NO_UNKNOWN_FILES, RULE_NO_UNKNOWN, } = Shared_1.SETTINGS;
|
|
7
7
|
// TODO In next major version: Export also files, plugin, etc.
|
|
8
8
|
/**
|
|
9
9
|
* Recommended configuration for eslint-plugin-boundaries.
|
|
@@ -15,15 +15,11 @@ RULE_ELEMENT_TYPES, RULE_ENTRY_POINT, RULE_EXTERNAL, RULE_NO_IGNORED, RULE_NO_PR
|
|
|
15
15
|
const config = {
|
|
16
16
|
rules: {
|
|
17
17
|
[RULE_ELEMENT_TYPES]: [2],
|
|
18
|
+
[RULE_DEPENDENCIES]: [2],
|
|
18
19
|
[RULE_ENTRY_POINT]: [2],
|
|
19
20
|
[RULE_EXTERNAL]: [2],
|
|
20
21
|
[RULE_NO_IGNORED]: 0,
|
|
21
|
-
[RULE_NO_PRIVATE]:
|
|
22
|
-
2,
|
|
23
|
-
{
|
|
24
|
-
allowUncles: true,
|
|
25
|
-
},
|
|
26
|
-
],
|
|
22
|
+
[RULE_NO_PRIVATE]: 0,
|
|
27
23
|
[RULE_NO_UNKNOWN_FILES]: 0,
|
|
28
24
|
[RULE_NO_UNKNOWN]: 0,
|
|
29
25
|
},
|
package/dist/Config/Strict.d.ts
CHANGED
package/dist/Config/Strict.js
CHANGED
|
@@ -3,9 +3,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const
|
|
6
|
+
const Shared_1 = require("../Shared");
|
|
7
7
|
const Recommended_1 = __importDefault(require("./Recommended"));
|
|
8
|
-
const { RULE_NO_IGNORED, RULE_NO_UNKNOWN_FILES, RULE_NO_UNKNOWN } =
|
|
8
|
+
const { RULE_NO_IGNORED, RULE_NO_UNKNOWN_FILES, RULE_NO_UNKNOWN } = Shared_1.SETTINGS;
|
|
9
9
|
// TODO In next major version: Export also files, plugin, etc.
|
|
10
10
|
/**
|
|
11
11
|
* Strict configuration for eslint-plugin-boundaries.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { DependencyDescription, ElementDescription, Matcher, DependencyMatchResult } from "@boundaries/elements";
|
|
2
|
+
import type { SettingsNormalized } from "../Shared";
|
|
3
|
+
/**
|
|
4
|
+
* Prints a warning message using warning color.
|
|
5
|
+
* @param title - Warning title shown before message.
|
|
6
|
+
* @param message - Warning message.
|
|
7
|
+
*/
|
|
8
|
+
export declare function warn(title: string, message?: string): void;
|
|
9
|
+
/**
|
|
10
|
+
* Prints a warning only once for each unique message.
|
|
11
|
+
*
|
|
12
|
+
* @param title - Warning title shown before message.
|
|
13
|
+
* @param message - Warning message candidate.
|
|
14
|
+
* @returns `true` when warning was emitted, `false` when skipped.
|
|
15
|
+
*/
|
|
16
|
+
export declare function warnOnce(title: string, message?: string): boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Emits debug output for file or dependency descriptions when enabled.
|
|
19
|
+
*
|
|
20
|
+
* @param description - Element or dependency description to debug.
|
|
21
|
+
* @param settings - Normalized plugin settings including debug filters.
|
|
22
|
+
* @param matcher - Matcher used to evaluate debug filters.
|
|
23
|
+
*/
|
|
24
|
+
export declare function debugDescription(description: ElementDescription | DependencyDescription, settings: SettingsNormalized, matcher: Matcher): void;
|
|
25
|
+
/**
|
|
26
|
+
* Prints debug information for a rule result when debug mode is enabled
|
|
27
|
+
*
|
|
28
|
+
* @param dependencyMatchResult - The result of matching a dependency against rules, including match status and captured values.
|
|
29
|
+
* @param ruleIndex - The index of the rule that was matched, if any.
|
|
30
|
+
* @param dependency - The original dependency description that was evaluated against the rules.
|
|
31
|
+
* @param settings - Normalized plugin settings including debug filters.
|
|
32
|
+
* @param matcher - Matcher used to evaluate debug filters.
|
|
33
|
+
*/
|
|
34
|
+
export declare function printDependenciesRuleResult(dependencyMatchResult: DependencyMatchResult | null, ruleIndex: number | null, dependency: DependencyDescription, settings: SettingsNormalized, matcher: Matcher): void;
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.warn = warn;
|
|
7
|
+
exports.warnOnce = warnOnce;
|
|
8
|
+
exports.debugDescription = debugDescription;
|
|
9
|
+
exports.printDependenciesRuleResult = printDependenciesRuleResult;
|
|
10
|
+
const elements_1 = require("@boundaries/elements");
|
|
11
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
12
|
+
const Shared_1 = require("../Shared");
|
|
13
|
+
const warns = new Set();
|
|
14
|
+
const debuggedFiles = new Set();
|
|
15
|
+
const debuggedDependencies = new Set();
|
|
16
|
+
const PREFIX_COLOR = "#A8B3D8";
|
|
17
|
+
const CONSOLE_LEVELS = {
|
|
18
|
+
log: "log",
|
|
19
|
+
warn: "warn",
|
|
20
|
+
};
|
|
21
|
+
const LOG_LEVELS = {
|
|
22
|
+
debug: "debug",
|
|
23
|
+
warning: "warning",
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Checks whether debug mode is globally enabled through environment variable.
|
|
27
|
+
*
|
|
28
|
+
* @returns `true` when debug env flag is active.
|
|
29
|
+
*/
|
|
30
|
+
function isDebugModeEnabled() {
|
|
31
|
+
return Boolean(process.env[Shared_1.SETTINGS.DEBUG]);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Computes final debug activation combining setting flag and environment flag.
|
|
35
|
+
*
|
|
36
|
+
* @param settingEnabled - Debug flag configured in plugin settings.
|
|
37
|
+
* @returns `true` when either setting or environment enables debug mode.
|
|
38
|
+
*/
|
|
39
|
+
function isDebugEnabled(settingEnabled) {
|
|
40
|
+
return settingEnabled || isDebugModeEnabled();
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Prints a log line to stdout with optional color formatting.
|
|
44
|
+
*
|
|
45
|
+
* @param message - Message text to print.
|
|
46
|
+
* @param options - Optional parameters for color and log level.
|
|
47
|
+
* @param options.color - Optional color key from the internal color map.
|
|
48
|
+
* @param options.level - Optional log level determining which console method to use (default is "log").
|
|
49
|
+
*/
|
|
50
|
+
function printLog(message, level) {
|
|
51
|
+
// eslint-disable-next-line no-console
|
|
52
|
+
console[level](message);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Indents every line except the first one by a fixed number of spaces.
|
|
56
|
+
*
|
|
57
|
+
* @param text - Multi-line text to indent.
|
|
58
|
+
* @param spaces - Number of spaces to prepend.
|
|
59
|
+
* @returns Text with indentation applied.
|
|
60
|
+
*/
|
|
61
|
+
function indentLines(text, spaces) {
|
|
62
|
+
const pad = " ".repeat(spaces);
|
|
63
|
+
return text
|
|
64
|
+
.split("\n")
|
|
65
|
+
.map((line) => `${pad}${line}`)
|
|
66
|
+
.join("\n");
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Generates a log prefix with plugin name and log level, applying color formatting based on log level.
|
|
70
|
+
* @param logLevel Type of log level to determine prefix formatting (default is "debug").
|
|
71
|
+
* @returns The formatted log prefix string to prepend to debug messages.
|
|
72
|
+
*/
|
|
73
|
+
function getLogPrefix(logLevel) {
|
|
74
|
+
const colorMethod = logLevel === LOG_LEVELS.warning ? chalk_1.default.yellow : chalk_1.default.blue;
|
|
75
|
+
const pluginTag = `[${Shared_1.PLUGIN_NAME}]`;
|
|
76
|
+
const levelTag = `[${logLevel}]`;
|
|
77
|
+
return `${chalk_1.default.hex(PREFIX_COLOR)(pluginTag)}${colorMethod(levelTag)}:`;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Prints a titled block of text in debug output, with the title formatted according to the log level.
|
|
81
|
+
* @param title - Block title shown before the message.
|
|
82
|
+
* @param options - Optional parameters for log level.
|
|
83
|
+
* @param options.level - Log level determining the title formatting (default is "debug").
|
|
84
|
+
* @param options.message - Message text to print within the block.
|
|
85
|
+
* @param level - Log level determining the title formatting (default is "debug").
|
|
86
|
+
*/
|
|
87
|
+
function printBlock(title, { level, message, }) {
|
|
88
|
+
const header = `${getLogPrefix(level)} ${title}`;
|
|
89
|
+
const consoleLevel = level === LOG_LEVELS.warning ? CONSOLE_LEVELS.warn : CONSOLE_LEVELS.log;
|
|
90
|
+
if (!message) {
|
|
91
|
+
printLog(header, consoleLevel);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
printLog(`${header}\n${indentLines(message, 2)}\n`, consoleLevel);
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Prints a titled JSON block in debug output.
|
|
98
|
+
*
|
|
99
|
+
* @param title - Block title shown before data.
|
|
100
|
+
* @param data - Data serialized as formatted JSON.
|
|
101
|
+
*/
|
|
102
|
+
function printDebugBlock(title, data) {
|
|
103
|
+
printBlock(title, {
|
|
104
|
+
message: JSON.stringify(data, null, 2),
|
|
105
|
+
level: LOG_LEVELS.debug,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Prints a warning message using warning color.
|
|
110
|
+
* @param title - Warning title shown before message.
|
|
111
|
+
* @param message - Warning message.
|
|
112
|
+
*/
|
|
113
|
+
function warn(title, message) {
|
|
114
|
+
printBlock(title, { message, level: LOG_LEVELS.warning });
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Prints a warning only once for each unique message.
|
|
118
|
+
*
|
|
119
|
+
* @param title - Warning title shown before message.
|
|
120
|
+
* @param message - Warning message candidate.
|
|
121
|
+
* @returns `true` when warning was emitted, `false` when skipped.
|
|
122
|
+
*/
|
|
123
|
+
function warnOnce(title, message) {
|
|
124
|
+
const messageKey = `${title}-${message}`;
|
|
125
|
+
if (warns.has(messageKey)) {
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
warns.add(messageKey);
|
|
129
|
+
warn(title, message);
|
|
130
|
+
return true;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Emits debug output for file or dependency descriptions when enabled.
|
|
134
|
+
*
|
|
135
|
+
* @param description - Element or dependency description to debug.
|
|
136
|
+
* @param settings - Normalized plugin settings including debug filters.
|
|
137
|
+
* @param matcher - Matcher used to evaluate debug filters.
|
|
138
|
+
*/
|
|
139
|
+
function debugDescription(description, settings, matcher) {
|
|
140
|
+
if (!isDebugEnabled(settings.debug.enabled)) {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
if ((0, elements_1.isDependencyDescription)(description)) {
|
|
144
|
+
printDependencyDebug(description, settings, matcher);
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
printFileDebug(description, settings, matcher);
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Returns an unique identifier for a file description, used to track which files have already been debugged.
|
|
151
|
+
* @param description - File element description.
|
|
152
|
+
* @returns Unique identifier string for the file.
|
|
153
|
+
*/
|
|
154
|
+
function getFileIdentifier(description) {
|
|
155
|
+
/* istanbul ignore next - Fallback for descriptions missing path, which should not happen but ensures stability of debug logging. */
|
|
156
|
+
return description.path || "<unknown-file>";
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Prints debug info for a file description once per file path.
|
|
160
|
+
*
|
|
161
|
+
* @param description - File element description.
|
|
162
|
+
* @param settings - Normalized plugin settings.
|
|
163
|
+
* @param matcher - Matcher used for filter checks.
|
|
164
|
+
*/
|
|
165
|
+
function printFileDebug(description, settings, matcher) {
|
|
166
|
+
if (!settings.debug.messages.files) {
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
const fileIdentifier = getFileIdentifier(description);
|
|
170
|
+
if (debuggedFiles.has(fileIdentifier)) {
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
debuggedFiles.add(fileIdentifier);
|
|
174
|
+
if (shouldPrintFile(description, settings, matcher)) {
|
|
175
|
+
const title = `Description of file "${chalk_1.default.green(fileIdentifier)}":`;
|
|
176
|
+
printDebugBlock(title, description);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Prints debug info for a dependency description once per file/source pair.
|
|
181
|
+
*
|
|
182
|
+
* @param description - Dependency description.
|
|
183
|
+
* @param settings - Normalized plugin settings.
|
|
184
|
+
* @param matcher - Matcher used for filter checks.
|
|
185
|
+
*/
|
|
186
|
+
function printDependencyDebug(description, settings, matcher) {
|
|
187
|
+
printFileDebug(description.from, settings, matcher);
|
|
188
|
+
if (!settings.debug.messages.dependencies) {
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
/* istanbul ignore next - Fallback for descriptions missing path, which should not happen but ensures stability of debug logging. */
|
|
192
|
+
const dependencySource = description.dependency.source || "<unknown-source>";
|
|
193
|
+
const fileIdentifier = getFileIdentifier(description.from);
|
|
194
|
+
const dependencyIdentifier = `${dependencySource}-${fileIdentifier}`;
|
|
195
|
+
if (debuggedDependencies.has(dependencyIdentifier)) {
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
debuggedDependencies.add(dependencyIdentifier);
|
|
199
|
+
if (shouldPrintDependency(description, settings, matcher)) {
|
|
200
|
+
const title = `Description of dependency "${chalk_1.default.green(dependencySource)}" in file "${chalk_1.default.green(fileIdentifier)}":`;
|
|
201
|
+
printDebugBlock(title, description);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
const DEPENDENCIES_VIOLATION_PREFIX = `${Shared_1.DEPENDENCIES} rule violation:`;
|
|
205
|
+
/**
|
|
206
|
+
* Prints debug information for a rule result when debug mode is enabled
|
|
207
|
+
*
|
|
208
|
+
* @param dependencyMatchResult - The result of matching a dependency against rules, including match status and captured values.
|
|
209
|
+
* @param ruleIndex - The index of the rule that was matched, if any.
|
|
210
|
+
* @param dependency - The original dependency description that was evaluated against the rules.
|
|
211
|
+
* @param settings - Normalized plugin settings including debug filters.
|
|
212
|
+
* @param matcher - Matcher used to evaluate debug filters.
|
|
213
|
+
*/
|
|
214
|
+
function printDependenciesRuleResult(dependencyMatchResult, ruleIndex, dependency, settings, matcher) {
|
|
215
|
+
if (!isDebugEnabled(settings.debug.enabled) ||
|
|
216
|
+
!settings.debug.messages.violations ||
|
|
217
|
+
!shouldPrintDependency(dependency, settings, matcher) ||
|
|
218
|
+
!shouldPrintFile(dependency.from, settings, matcher)) {
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
if ((0, Shared_1.isNull)(ruleIndex) || !dependencyMatchResult) {
|
|
222
|
+
printDebugBlock(`${DEPENDENCIES_VIOLATION_PREFIX} Dependency did not match any rule, and default policy is to deny.`, {
|
|
223
|
+
dependency,
|
|
224
|
+
});
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
const title = `${DEPENDENCIES_VIOLATION_PREFIX} Rule at index ${ruleIndex} reported a violation because the following selector matched the dependency:`;
|
|
228
|
+
const selectorRelevantData = {};
|
|
229
|
+
if (dependencyMatchResult.from) {
|
|
230
|
+
selectorRelevantData.from = dependencyMatchResult.from;
|
|
231
|
+
}
|
|
232
|
+
if (dependencyMatchResult.to) {
|
|
233
|
+
selectorRelevantData.to = dependencyMatchResult.to;
|
|
234
|
+
}
|
|
235
|
+
if (dependencyMatchResult.dependency) {
|
|
236
|
+
selectorRelevantData.dependency = dependencyMatchResult.dependency;
|
|
237
|
+
}
|
|
238
|
+
printDebugBlock(title, {
|
|
239
|
+
rule: {
|
|
240
|
+
index: ruleIndex,
|
|
241
|
+
selector: selectorRelevantData,
|
|
242
|
+
},
|
|
243
|
+
dependency,
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Checks whether a file description passes debug file filters.
|
|
248
|
+
*
|
|
249
|
+
* @param description - File description to evaluate.
|
|
250
|
+
* @param settings - Normalized plugin settings.
|
|
251
|
+
* @param matcher - Matcher used to evaluate selectors.
|
|
252
|
+
* @returns `true` when file should be printed in debug output.
|
|
253
|
+
*/
|
|
254
|
+
function shouldPrintFile(description, settings, matcher) {
|
|
255
|
+
const fileFilters = settings.debug.filter.files;
|
|
256
|
+
if ((0, Shared_1.isUndefined)(fileFilters)) {
|
|
257
|
+
return true;
|
|
258
|
+
}
|
|
259
|
+
if (fileFilters.length === 0) {
|
|
260
|
+
return false;
|
|
261
|
+
}
|
|
262
|
+
return fileFilters.some((selector) => !(0, Shared_1.isNull)(matcher.getElementSelectorMatchingDescription(description, selector)));
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Checks whether a dependency description passes debug dependency filters.
|
|
266
|
+
*
|
|
267
|
+
* @param description - Dependency description to evaluate.
|
|
268
|
+
* @param settings - Normalized plugin settings.
|
|
269
|
+
* @param matcher - Matcher used to evaluate selectors.
|
|
270
|
+
* @returns `true` when dependency should be printed in debug output.
|
|
271
|
+
*/
|
|
272
|
+
function shouldPrintDependency(description, settings, matcher) {
|
|
273
|
+
const dependencyFilters = settings.debug.filter.dependencies;
|
|
274
|
+
if ((0, Shared_1.isUndefined)(dependencyFilters)) {
|
|
275
|
+
return true;
|
|
276
|
+
}
|
|
277
|
+
if (dependencyFilters.length === 0) {
|
|
278
|
+
return false;
|
|
279
|
+
}
|
|
280
|
+
if (!shouldPrintFile(description.from, settings, matcher)) {
|
|
281
|
+
return false;
|
|
282
|
+
}
|
|
283
|
+
return dependencyFilters.some((selector) => matcher.getDependencySelectorMatchingDescription(description, selector)
|
|
284
|
+
.isMatch);
|
|
285
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./Debug";
|
|
@@ -14,5 +14,4 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
__exportStar(require("./Common"), exports);
|
|
18
17
|
__exportStar(require("./Debug"), exports);
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { Matcher, DependencyDescription, DependencyKind, ElementDescription } from "@boundaries/elements";
|
|
2
2
|
import type { Rule } from "eslint";
|
|
3
|
-
import type { SettingsNormalized } from "../
|
|
3
|
+
import type { SettingsNormalized } from "../Shared";
|
|
4
4
|
import type { EslintLiteralNode } from "./Elements.types";
|
|
5
5
|
/**
|
|
6
|
-
* Returns the elements matcher based on the ESLint rule context, filtering out invalid descriptors
|
|
7
|
-
* @param
|
|
6
|
+
* Returns the elements matcher based on the ESLint rule context settings already normalized, filtering out invalid descriptors
|
|
7
|
+
* @param settings The ESLint rule context settings normalized
|
|
8
8
|
* @returns The elements matcher
|
|
9
9
|
*/
|
|
10
10
|
export declare function getElementsMatcher(settings: SettingsNormalized): Matcher;
|
|
@@ -23,16 +23,18 @@ export declare function getSpecifiers(node: Rule.Node): string[];
|
|
|
23
23
|
export declare function elementDescription(fileName: string, settings: SettingsNormalized): ElementDescription;
|
|
24
24
|
/**
|
|
25
25
|
* Returns the description of a dependency node
|
|
26
|
-
* @param
|
|
26
|
+
* @param options The dependency node info
|
|
27
|
+
* @param options.node The dependency node
|
|
28
|
+
* @param options.kind The kind of the dependency
|
|
29
|
+
* @param options.nodeKind The kind of the node generating the dependency
|
|
30
|
+
* @param fileName The file name (absolute path)
|
|
31
|
+
* @param settings The ESLint rule context settings normalized
|
|
27
32
|
* @param context The ESLint rule context
|
|
28
33
|
* @returns The description of the dependency node
|
|
29
34
|
*/
|
|
30
35
|
export declare function dependencyDescription({ node, kind, nodeKind, }: {
|
|
31
|
-
/** The dependency node */
|
|
32
36
|
node: EslintLiteralNode;
|
|
33
|
-
/** The kind of the dependency */
|
|
34
37
|
kind: DependencyKind;
|
|
35
|
-
/** The kind of the node generating the dependency */
|
|
36
38
|
nodeKind?: string;
|
|
37
39
|
},
|
|
38
40
|
/** The file name (absolute path) */
|
|
@@ -9,11 +9,11 @@ exports.elementDescription = elementDescription;
|
|
|
9
9
|
exports.dependencyDescription = dependencyDescription;
|
|
10
10
|
const elements_1 = require("@boundaries/elements");
|
|
11
11
|
const resolve_1 = __importDefault(require("eslint-module-utils/resolve"));
|
|
12
|
-
const
|
|
12
|
+
const Debug_1 = require("../Debug");
|
|
13
13
|
const elements = new elements_1.Elements();
|
|
14
14
|
/**
|
|
15
|
-
* Returns the elements matcher based on the ESLint rule context, filtering out invalid descriptors
|
|
16
|
-
* @param
|
|
15
|
+
* Returns the elements matcher based on the ESLint rule context settings already normalized, filtering out invalid descriptors
|
|
16
|
+
* @param settings The ESLint rule context settings normalized
|
|
17
17
|
* @returns The elements matcher
|
|
18
18
|
*/
|
|
19
19
|
function getElementsMatcher(settings) {
|
|
@@ -57,12 +57,17 @@ function getSpecifiers(node) {
|
|
|
57
57
|
function elementDescription(fileName, settings) {
|
|
58
58
|
const matcher = getElementsMatcher(settings);
|
|
59
59
|
const result = matcher.describeElement(fileName);
|
|
60
|
-
(0,
|
|
60
|
+
(0, Debug_1.debugDescription)(result, settings, matcher);
|
|
61
61
|
return result;
|
|
62
62
|
}
|
|
63
63
|
/**
|
|
64
64
|
* Returns the description of a dependency node
|
|
65
|
-
* @param
|
|
65
|
+
* @param options The dependency node info
|
|
66
|
+
* @param options.node The dependency node
|
|
67
|
+
* @param options.kind The kind of the dependency
|
|
68
|
+
* @param options.nodeKind The kind of the node generating the dependency
|
|
69
|
+
* @param fileName The file name (absolute path)
|
|
70
|
+
* @param settings The ESLint rule context settings normalized
|
|
66
71
|
* @param context The ESLint rule context
|
|
67
72
|
* @returns The description of the dependency node
|
|
68
73
|
*/
|
|
@@ -80,10 +85,10 @@ context) {
|
|
|
80
85
|
from: fileName,
|
|
81
86
|
to: resolvedPath || undefined,
|
|
82
87
|
source,
|
|
83
|
-
kind: kind || "value",
|
|
88
|
+
kind: kind || "value",
|
|
84
89
|
nodeKind,
|
|
85
90
|
specifiers: getSpecifiers(node),
|
|
86
91
|
});
|
|
87
|
-
(0,
|
|
92
|
+
(0, Debug_1.debugDescription)(description, settings, matcher);
|
|
88
93
|
return description;
|
|
89
94
|
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { ElementParent, DependencyDescription, ElementDescription, DependencyMatchResult } from "@boundaries/elements";
|
|
2
|
+
/**
|
|
3
|
+
* Replaces all occurrences of a placeholder key in a template string.
|
|
4
|
+
*
|
|
5
|
+
* Placeholders use the `${key}` syntax and optionally support namespacing
|
|
6
|
+
* (for example `${from.type}` or `${dependency.parent.category}`).
|
|
7
|
+
*
|
|
8
|
+
* @param template - Message template where placeholders are replaced.
|
|
9
|
+
* @param key - Placeholder key to replace (without `${}` delimiters).
|
|
10
|
+
* @param value - Value injected in place of the placeholder.
|
|
11
|
+
* @param namespace - Optional namespace prepended to the key before replacing.
|
|
12
|
+
* @returns Template string with the requested placeholder replaced.
|
|
13
|
+
*/
|
|
14
|
+
export declare function replaceObjectValueInLegacyTemplate(template: string, key: string, value: string, namespace?: string | null): string;
|
|
15
|
+
/**
|
|
16
|
+
* Creates the replacement context consumed by legacy `${...}` placeholders.
|
|
17
|
+
*
|
|
18
|
+
* The resulting object normalizes available element information and dependency
|
|
19
|
+
* metadata so templates can use keys consistently regardless of source.
|
|
20
|
+
*
|
|
21
|
+
* @param element - Element or parent element that provides captured values.
|
|
22
|
+
* @param importKind - Dependency kind (`value`, `type`, etc.).
|
|
23
|
+
* @param dependencyMetadata - Extra dependency metadata for full elements.
|
|
24
|
+
* @returns Normalized key/value map used during placeholder replacement.
|
|
25
|
+
*/
|
|
26
|
+
export declare function elementPropertiesToReplaceInLegacyTemplate(element: ElementDescription | ElementParent, importKind: string, dependencyMetadata?: DependencyDescription["dependency"]): {
|
|
27
|
+
type: string;
|
|
28
|
+
internalPath: string;
|
|
29
|
+
source: string;
|
|
30
|
+
module: string;
|
|
31
|
+
importKind: string;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Builds the final custom error message for a dependency violation.
|
|
35
|
+
*
|
|
36
|
+
* This function first resolves legacy `${...}` placeholders (`file`, `from`,
|
|
37
|
+
* `dependency`, `target`, and parent variants) and then evaluates optional
|
|
38
|
+
* Handlebars expressions with the same dependency context.
|
|
39
|
+
*
|
|
40
|
+
* @param template - User-defined message template from rule configuration.
|
|
41
|
+
* @param dependency - Runtime dependency information used by placeholders.
|
|
42
|
+
* @returns Rendered, user-facing error message.
|
|
43
|
+
*/
|
|
44
|
+
export declare function customErrorMessage(template: string, dependency: DependencyDescription, ruleIndex?: number | null, matchResult?: DependencyMatchResult | null): string;
|