eslint-plugin-use-agnostic 0.1.0
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 +1 -0
- package/library/_commons/constants/bases.js +72 -0
- package/library/_commons/utilities/helpers.js +191 -0
- package/library/agnostic20/config.js +24 -0
- package/library/agnostic20/constants/bases.js +268 -0
- package/library/agnostic20/rules/import-rules-enforcement.js +55 -0
- package/library/agnostic20/utilities/flows.js +212 -0
- package/library/agnostic20/utilities/helpers.js +186 -0
- package/library/directive21/config.js +24 -0
- package/library/directive21/constants/bases.js +460 -0
- package/library/directive21/rules/import-rules-enforcement.js +67 -0
- package/library/directive21/utilities/flows.js +268 -0
- package/library/directive21/utilities/helpers.js +291 -0
- package/library/index.js +42 -0
- package/package.json +43 -0
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import path from "path";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
EXTENSIONS,
|
|
5
|
+
useServerJSXMessageId,
|
|
6
|
+
importBreaksEffectiveImportRulesMessageId,
|
|
7
|
+
reExportNotSameMessageId,
|
|
8
|
+
} from "../../_commons/constants/bases.js";
|
|
9
|
+
import {
|
|
10
|
+
USE_SERVER_LOGICS,
|
|
11
|
+
USE_SERVER_COMPONENTS,
|
|
12
|
+
USE_SERVER_FUNCTIONS,
|
|
13
|
+
USE_CLIENT_LOGICS,
|
|
14
|
+
USE_CLIENT_COMPONENTS,
|
|
15
|
+
USE_AGNOSTIC_LOGICS,
|
|
16
|
+
USE_AGNOSTIC_COMPONENTS,
|
|
17
|
+
// currentFileEffectiveDirective,
|
|
18
|
+
// importedFileEffectiveDirective,
|
|
19
|
+
effectiveDirectiveMessage,
|
|
20
|
+
specificViolationMessage,
|
|
21
|
+
} from "../constants/bases.js";
|
|
22
|
+
|
|
23
|
+
import { resolveImportPath } from "../../_commons/utilities/helpers.js";
|
|
24
|
+
import {
|
|
25
|
+
getDirectiveFromCurrentModule,
|
|
26
|
+
getDirectiveFromImportedModule,
|
|
27
|
+
getEffectiveDirective,
|
|
28
|
+
isImportBlocked,
|
|
29
|
+
makeMessageFromEffectiveDirective,
|
|
30
|
+
findSpecificViolationMessage,
|
|
31
|
+
} from "./helpers.js";
|
|
32
|
+
|
|
33
|
+
/* currentFileFlow */
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* The flow that begins the import rules enforcement rule, retrieving the valid directive of the current file before comparing it to upcoming valid directives of the files it imports.
|
|
37
|
+
* @param {Readonly<import('@typescript-eslint/utils').TSESLint.RuleContext<typeof reExportNotSameMessageId | typeof importBreaksEffectiveImportRulesMessageId | typeof useServerJSXMessageId, []>>} context The ESLint rule's `context` object.
|
|
38
|
+
* @returns {{skip: true; currentFileEffectiveDirective: undefined;} | {skip: undefined; currentFileEffectiveDirective: USE_SERVER_LOGICS | USE_SERVER_COMPONENTS | USE_SERVER_FUNCTIONS | USE_CLIENT_LOGICS | USE_CLIENT_COMPONENTS | USE_AGNOSTIC_LOGICS | USE_AGNOSTIC_COMPONENTS;}} Returns either an object with `skip: true` to disregard or one with the non-null `currentFileEffectiveDirective`.
|
|
39
|
+
*/
|
|
40
|
+
export const currentFileFlow = (context) => {
|
|
41
|
+
// GETTING THE EXTENSION OF THE CURRENT FILE
|
|
42
|
+
const currentFileExtension = path.extname(context.filename);
|
|
43
|
+
|
|
44
|
+
// fails if the file is not JavaScript (TypeScript)
|
|
45
|
+
const iscurrentFileJS = EXTENSIONS.some(
|
|
46
|
+
(ext) => currentFileExtension === ext
|
|
47
|
+
);
|
|
48
|
+
if (!iscurrentFileJS) {
|
|
49
|
+
console.error(
|
|
50
|
+
"ERROR. Linted files for this rule should only be in JavaScript (TypeScript)."
|
|
51
|
+
);
|
|
52
|
+
return { skip: true };
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/* GETTING THE DIRECTIVE (or lack thereof) OF THE CURRENT FILE */
|
|
56
|
+
const currentFileDirective = getDirectiveFromCurrentModule(context);
|
|
57
|
+
|
|
58
|
+
// reports if a file marked "use server" has a JSX extension
|
|
59
|
+
if (
|
|
60
|
+
currentFileDirective === "use server" &&
|
|
61
|
+
currentFileExtension.endsWith("x")
|
|
62
|
+
) {
|
|
63
|
+
context.report({
|
|
64
|
+
loc: {
|
|
65
|
+
start: { line: 1, column: 0 },
|
|
66
|
+
end: { line: 1, column: context.sourceCode.lines[0].length },
|
|
67
|
+
},
|
|
68
|
+
messageId: useServerJSXMessageId,
|
|
69
|
+
});
|
|
70
|
+
return { skip: true };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// GETTING THE EFFECTIVE DIRECTIVE OF THE CURRENT FILE
|
|
74
|
+
const currentFileEffectiveDirective = getEffectiveDirective(
|
|
75
|
+
currentFileDirective,
|
|
76
|
+
currentFileExtension
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
// fails if one of the seven effective directives has not been obtained
|
|
80
|
+
if (currentFileEffectiveDirective === null) {
|
|
81
|
+
console.error("ERROR. Effective directive should never be null.");
|
|
82
|
+
return { skip: true };
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return {
|
|
86
|
+
currentFileEffectiveDirective,
|
|
87
|
+
};
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
/* importedFileFlow */
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* The flow that is shared between import and re-export traversals to obtain the import file's effective directive.
|
|
94
|
+
* @param {string} currentDir Directory of the file containing the import (from `path.dirname(context.filename)`).
|
|
95
|
+
* @param {string} importPath The import specifier (e.g., `@/components/Button` or `./utils`).
|
|
96
|
+
* @param {string} cwd Project root (from `context.cwd`). Caveat: only as an assumption currently.
|
|
97
|
+
* @param {Readonly<import('@typescript-eslint/utils').TSESLint.RuleContext<typeof reExportNotSameMessageId | typeof importBreaksEffectiveImportRulesMessageId | typeof useServerJSXMessageId, []>>} context The ESLint rule's `context` object.
|
|
98
|
+
* @param {import('@typescript-eslint/types').TSESTree.ImportDeclaration} node The ESLint `node` of the rule's current traversal.
|
|
99
|
+
* @returns {{skip: true; importedFileEffectiveDirective: undefined; resolvedImportPath: undefined;} | {skip: undefined; importedFileEffectiveDirective: USE_SERVER_LOGICS | USE_SERVER_COMPONENTS | USE_SERVER_FUNCTIONS | USE_CLIENT_LOGICS | USE_CLIENT_COMPONENTS | USE_AGNOSTIC_LOGICS | USE_AGNOSTIC_COMPONENTS; resolvedImportPath: string;}} Returns either an object with `skip: true` to disregard or one with the non-null `importedFileEffectiveDirective`.
|
|
100
|
+
*/
|
|
101
|
+
const importedFileFlow = (context, node) => {
|
|
102
|
+
// finds the full path of the import
|
|
103
|
+
const resolvedImportPath = resolveImportPath(
|
|
104
|
+
path.dirname(context.filename),
|
|
105
|
+
node.source.value,
|
|
106
|
+
context.cwd
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
// does not operate on paths it did not resolve
|
|
110
|
+
if (resolvedImportPath === null) return { skip: true };
|
|
111
|
+
// does not operate on non-JS files
|
|
112
|
+
const isImportedFileJS = EXTENSIONS.some((ext) =>
|
|
113
|
+
resolvedImportPath.endsWith(ext)
|
|
114
|
+
);
|
|
115
|
+
if (!isImportedFileJS) return { skip: true };
|
|
116
|
+
|
|
117
|
+
/* GETTING THE DIRECTIVE (or lack thereof) OF THE IMPORTED FILE */
|
|
118
|
+
const importedFileDirective =
|
|
119
|
+
getDirectiveFromImportedModule(resolvedImportPath);
|
|
120
|
+
// GETTING THE EXTENSION OF THE IMPORTED FILE
|
|
121
|
+
const importedFileFileExtension = path.extname(resolvedImportPath);
|
|
122
|
+
// GETTING THE EFFECTIVE DIRECTIVE OF THE IMPORTED FILE
|
|
123
|
+
const importedFileEffectiveDirective = getEffectiveDirective(
|
|
124
|
+
importedFileDirective,
|
|
125
|
+
importedFileFileExtension
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
// also fails if one of the seven effective directives has not been obtained
|
|
129
|
+
if (importedFileEffectiveDirective === null) {
|
|
130
|
+
console.error("ERROR. Effective directive should never be null.");
|
|
131
|
+
return { skip: true };
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// For now skipping on both "does not operate" (which should ignore) and "fails" albeit with console.error (which should crash).
|
|
135
|
+
|
|
136
|
+
return {
|
|
137
|
+
importedFileEffectiveDirective,
|
|
138
|
+
};
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
/* importsFlow */
|
|
142
|
+
|
|
143
|
+
/** The full flow for import traversals to enforce effective directives import rules.
|
|
144
|
+
* @param {Readonly<import('@typescript-eslint/utils').TSESLint.RuleContext<typeof reExportNotSameMessageId | typeof importBreaksEffectiveImportRulesMessageId | typeof useServerJSXMessageId, []>>} context The ESLint rule's `context` object.
|
|
145
|
+
* @param {import('@typescript-eslint/types').TSESTree.ImportDeclaration} node The ESLint `node` of the rule's current traversal.
|
|
146
|
+
* @param {USE_SERVER_LOGICS | USE_SERVER_COMPONENTS | USE_SERVER_FUNCTIONS | USE_CLIENT_LOGICS | USE_CLIENT_COMPONENTS | USE_AGNOSTIC_LOGICS | USE_AGNOSTIC_COMPONENTS} currentFileEffectiveDirective The current file's effective directive.
|
|
147
|
+
* @returns Returns early if the flow needs to be interrupted.
|
|
148
|
+
*/
|
|
149
|
+
export const importsFlow = (context, node, currentFileEffectiveDirective) => {
|
|
150
|
+
// does not operate on `import type`
|
|
151
|
+
if (node.importKind === "type") return;
|
|
152
|
+
|
|
153
|
+
const result = importedFileFlow(context, node);
|
|
154
|
+
|
|
155
|
+
if (result.skip) return;
|
|
156
|
+
const { importedFileEffectiveDirective } = result;
|
|
157
|
+
|
|
158
|
+
if (
|
|
159
|
+
isImportBlocked(
|
|
160
|
+
currentFileEffectiveDirective,
|
|
161
|
+
importedFileEffectiveDirective
|
|
162
|
+
)
|
|
163
|
+
) {
|
|
164
|
+
context.report({
|
|
165
|
+
node,
|
|
166
|
+
messageId: importBreaksEffectiveImportRulesMessageId,
|
|
167
|
+
data: {
|
|
168
|
+
[effectiveDirectiveMessage]: makeMessageFromEffectiveDirective(
|
|
169
|
+
currentFileEffectiveDirective
|
|
170
|
+
),
|
|
171
|
+
[specificViolationMessage]: findSpecificViolationMessage(
|
|
172
|
+
currentFileEffectiveDirective,
|
|
173
|
+
importedFileEffectiveDirective
|
|
174
|
+
),
|
|
175
|
+
},
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
/* reExportsFlow */
|
|
181
|
+
|
|
182
|
+
/** The full flow for export traversals, shared between `ExportNamedDeclaration` and `ExportAllDeclaration`, to ensure same effective directive re-exports.
|
|
183
|
+
* @param {Readonly<import('@typescript-eslint/utils').TSESLint.RuleContext<typeof reExportNotSameMessageId | typeof importBreaksEffectiveImportRulesMessageId | typeof useServerJSXMessageId, []>>} context The ESLint rule's `context` object.
|
|
184
|
+
* @param {import('@typescript-eslint/types').TSESTree.ExportNamedDeclaration | import('@typescript-eslint/types').TSESTree.ExportAllDeclaration} node The ESLint `node` of the rule's current traversal.
|
|
185
|
+
* @param {USE_SERVER_LOGICS | USE_SERVER_COMPONENTS | USE_SERVER_FUNCTIONS | USE_CLIENT_LOGICS | USE_CLIENT_COMPONENTS | USE_AGNOSTIC_LOGICS | USE_AGNOSTIC_COMPONENTS} currentFileEffectiveDirective The current file's effective directive.
|
|
186
|
+
* @returns Returns early if the flow needs to be interrupted.
|
|
187
|
+
*/
|
|
188
|
+
export const reExportsFlow = (context, node, currentFileEffectiveDirective) => {
|
|
189
|
+
// does not operate on `export type`
|
|
190
|
+
if (node.exportKind === "type") return;
|
|
191
|
+
|
|
192
|
+
// does not operate on internal exports
|
|
193
|
+
if (node.source === null) return;
|
|
194
|
+
|
|
195
|
+
const result = importedFileFlow(context, node);
|
|
196
|
+
|
|
197
|
+
if (result.skip) return;
|
|
198
|
+
const { importedFileEffectiveDirective } = result;
|
|
199
|
+
|
|
200
|
+
if (currentFileEffectiveDirective !== importedFileEffectiveDirective) {
|
|
201
|
+
context.report({
|
|
202
|
+
node,
|
|
203
|
+
messageId: reExportNotSameMessageId,
|
|
204
|
+
data: {
|
|
205
|
+
// currentFileEffectiveDirective
|
|
206
|
+
currentFileEffectiveDirective,
|
|
207
|
+
// importedFileEffectiveDirective
|
|
208
|
+
importedFileEffectiveDirective,
|
|
209
|
+
},
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
};
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import {
|
|
2
|
+
useServerJSXMessageId,
|
|
3
|
+
importBreaksEffectiveImportRulesMessageId,
|
|
4
|
+
reExportNotSameMessageId,
|
|
5
|
+
TSX,
|
|
6
|
+
TS,
|
|
7
|
+
JSX,
|
|
8
|
+
JS,
|
|
9
|
+
MJS,
|
|
10
|
+
CJS,
|
|
11
|
+
} from "../../_commons/constants/bases.js";
|
|
12
|
+
import {
|
|
13
|
+
NO_DIRECTIVE,
|
|
14
|
+
USE_SERVER,
|
|
15
|
+
USE_CLIENT,
|
|
16
|
+
USE_AGNOSTIC,
|
|
17
|
+
USE_SERVER_LOGICS,
|
|
18
|
+
USE_SERVER_COMPONENTS,
|
|
19
|
+
USE_SERVER_FUNCTIONS,
|
|
20
|
+
USE_CLIENT_LOGICS,
|
|
21
|
+
USE_CLIENT_COMPONENTS,
|
|
22
|
+
USE_AGNOSTIC_LOGICS,
|
|
23
|
+
USE_AGNOSTIC_COMPONENTS,
|
|
24
|
+
effectiveDirectives_EffectiveModules,
|
|
25
|
+
directivesSet,
|
|
26
|
+
directivesArray,
|
|
27
|
+
effectiveDirectives_BlockedImports,
|
|
28
|
+
} from "../constants/bases.js";
|
|
29
|
+
|
|
30
|
+
import {
|
|
31
|
+
getImportedFileFirstLine,
|
|
32
|
+
isImportBlocked as commonsIsImportBlocked,
|
|
33
|
+
makeMessageFromResolvedDirective,
|
|
34
|
+
findSpecificViolationMessage as commonsFindSpecificViolationMessage,
|
|
35
|
+
} from "../../_commons/utilities/helpers.js";
|
|
36
|
+
|
|
37
|
+
/* getDirectiveFromCurrentModule */
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Gets the directive of the current module.
|
|
41
|
+
* - `null` denotes a server-by-default module, ideally a Server Module.
|
|
42
|
+
* - `'use client'` denotes a Client Module.
|
|
43
|
+
* - `'use server'` denotes a Server Functions Module.
|
|
44
|
+
* - `'use agnostic'` denotes an Agnostic Module (formerly Shared Module).
|
|
45
|
+
* @param {Readonly<import('@typescript-eslint/utils').TSESLint.RuleContext<typeof reExportNotSameMessageId | typeof importBreaksEffectiveImportRulesMessageId | typeof useServerJSXMessageId, []>>} context The ESLint rule's `context` object.
|
|
46
|
+
* @returns {NO_DIRECTIVE | USE_SERVER | USE_CLIENT | USE_AGNOSTIC} The directive, or lack thereof via `null`. The lack of a directive is considered server-by-default.
|
|
47
|
+
*/
|
|
48
|
+
export const getDirectiveFromCurrentModule = (context) => {
|
|
49
|
+
// the AST body to check for the top-of-the-file directive
|
|
50
|
+
const { body } = context.sourceCode.ast;
|
|
51
|
+
|
|
52
|
+
// the first statement from the source code's Abstract Syntax Tree
|
|
53
|
+
const firstStatement = body[0];
|
|
54
|
+
|
|
55
|
+
// the value of that first statement or null
|
|
56
|
+
const value =
|
|
57
|
+
firstStatement?.type === "ExpressionStatement" &&
|
|
58
|
+
firstStatement.expression?.type === "Literal"
|
|
59
|
+
? firstStatement.expression.value
|
|
60
|
+
: null;
|
|
61
|
+
|
|
62
|
+
// considers early a null value as the absence of a directive
|
|
63
|
+
if (value === null) return value;
|
|
64
|
+
|
|
65
|
+
// the value to be exactly 'use client', 'use server' or 'use agnostic' in order not to be considered null by default, or server-by-default
|
|
66
|
+
const currentFileDirective = directivesSet.has(value) ? value : null;
|
|
67
|
+
|
|
68
|
+
return currentFileDirective;
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
/* getEffectiveDirective */
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Gets the effective directive of a module, based on the combination of its directive (or lack thereof) and its extension (depending on whether it ends with 'x' for JSX).
|
|
75
|
+
* - `'use server logics'` denotes a Server Logics Module.
|
|
76
|
+
* - `'use server components'` denotes a Server Components Module.
|
|
77
|
+
* - `'use server functions'` denotes a Server Functions Module.
|
|
78
|
+
* - `'use client logics'` denotes a Client Logics Module.
|
|
79
|
+
* - `'use client components'` denotes a Client Components Module.
|
|
80
|
+
* - `'use agnostic logics'` denotes an Agnostic Logics Module.
|
|
81
|
+
* - `'use agnostic components'` denotes an Agnostic Components Module.
|
|
82
|
+
* @param {NO_DIRECTIVE | USE_SERVER | USE_CLIENT | USE_AGNOSTIC} directive The directive as written on top of the file (`null` if no valid directive).
|
|
83
|
+
* @param {TSX | TS | JSX | JS | MJS | CJS} extension The JavaScript (TypeScript) extension of the file.
|
|
84
|
+
* @returns {USE_SERVER_LOGICS | USE_SERVER_COMPONENTS | USE_SERVER_FUNCTIONS | USE_CLIENT_LOGICS | USE_CLIENT_COMPONENTS | USE_AGNOSTIC_LOGICS | USE_AGNOSTIC_COMPONENTS | null} The effective directive, from which imports rules are applied.
|
|
85
|
+
*/
|
|
86
|
+
export const getEffectiveDirective = (directive, extension) => {
|
|
87
|
+
// I could use a map, but because this is in JS with JSDoc, a manual solution is peculiarly more typesafe.
|
|
88
|
+
if (directive === NO_DIRECTIVE && !extension.endsWith("x"))
|
|
89
|
+
return USE_SERVER_LOGICS;
|
|
90
|
+
if (directive === NO_DIRECTIVE && extension.endsWith("x"))
|
|
91
|
+
return USE_SERVER_COMPONENTS;
|
|
92
|
+
if (directive === USE_SERVER && !extension.endsWith("x"))
|
|
93
|
+
return USE_SERVER_FUNCTIONS;
|
|
94
|
+
if (directive === USE_CLIENT && !extension.endsWith("x"))
|
|
95
|
+
return USE_CLIENT_LOGICS;
|
|
96
|
+
if (directive === USE_CLIENT && extension.endsWith("x"))
|
|
97
|
+
return USE_CLIENT_COMPONENTS;
|
|
98
|
+
if (directive === USE_AGNOSTIC && !extension.endsWith("x"))
|
|
99
|
+
return USE_AGNOSTIC_LOGICS;
|
|
100
|
+
if (directive === USE_AGNOSTIC && extension.endsWith("x"))
|
|
101
|
+
return USE_AGNOSTIC_COMPONENTS;
|
|
102
|
+
|
|
103
|
+
return null; // default error, should be unreachable
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
/* getDirectiveFromImportedModule */
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Gets the directive of the imported module.
|
|
110
|
+
* - `'use client'` denotes a Client Module.
|
|
111
|
+
* - `'use server'` denotes a Server Functions Module.
|
|
112
|
+
* - `'use agnostic'` denotes an Agnostic Module (formerly Shared Module).
|
|
113
|
+
* - `null` denotes a server-by-default module, ideally a Server Module.
|
|
114
|
+
* @param {string} resolvedImportPath The resolved path of the import.
|
|
115
|
+
* @returns {USE_SERVER | USE_CLIENT | USE_AGNOSTIC | NO_DIRECTIVE} The directive, or lack thereof via `null`. The lack of a directive is considered server-by-default.
|
|
116
|
+
*/
|
|
117
|
+
export const getDirectiveFromImportedModule = (resolvedImportPath) => {
|
|
118
|
+
// gets the first line of the code of the import
|
|
119
|
+
const importedFileFirstLine = getImportedFileFirstLine(resolvedImportPath);
|
|
120
|
+
|
|
121
|
+
// verifies that this first line starts with a valid directive, thus excluding comments
|
|
122
|
+
const hasAcceptedDirective = directivesArray.some(
|
|
123
|
+
(directive) =>
|
|
124
|
+
importedFileFirstLine.startsWith(`'${directive}'`) ||
|
|
125
|
+
importedFileFirstLine.startsWith(`"${directive}"`)
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
// applies the correct directive or the lack thereof with null
|
|
129
|
+
const importedFileDirective = hasAcceptedDirective
|
|
130
|
+
? directivesArray.find((directive) =>
|
|
131
|
+
importedFileFirstLine.includes(directive)
|
|
132
|
+
) ?? null
|
|
133
|
+
: null;
|
|
134
|
+
|
|
135
|
+
return importedFileDirective;
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
/* isImportBlocked */
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Returns a boolean deciding if an imported file's effective directive is incompatible with the current file's effective directive.
|
|
142
|
+
* @param {USE_SERVER_LOGICS | USE_SERVER_COMPONENTS | USE_SERVER_FUNCTIONS | USE_CLIENT_LOGICS | USE_CLIENT_COMPONENTS | USE_AGNOSTIC_LOGICS | USE_AGNOSTIC_COMPONENTS} currentFileEffectiveDirective The current file's effective directive.
|
|
143
|
+
* @param {USE_SERVER_LOGICS | USE_SERVER_COMPONENTS | USE_SERVER_FUNCTIONS | USE_CLIENT_LOGICS | USE_CLIENT_COMPONENTS | USE_AGNOSTIC_LOGICS | USE_AGNOSTIC_COMPONENTS} importedFileEffectiveDirective The imported file's effective directive.
|
|
144
|
+
* @returns {boolean} Returns `true` if the import is blocked, as established in `effectiveDirectives_BlockedImports`.
|
|
145
|
+
*/
|
|
146
|
+
export const isImportBlocked = (
|
|
147
|
+
currentFileEffectiveDirective,
|
|
148
|
+
importedFileEffectiveDirective
|
|
149
|
+
) =>
|
|
150
|
+
commonsIsImportBlocked(
|
|
151
|
+
effectiveDirectives_BlockedImports,
|
|
152
|
+
currentFileEffectiveDirective,
|
|
153
|
+
importedFileEffectiveDirective
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
/* makeMessageFromEffectiveDirective */
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Lists in an message the effective modules incompatible with an effective module based on its effective directive.
|
|
160
|
+
* @param {USE_SERVER_LOGICS | USE_SERVER_COMPONENTS | USE_SERVER_FUNCTIONS | USE_CLIENT_LOGICS | USE_CLIENT_COMPONENTS | USE_AGNOSTIC_LOGICS | USE_AGNOSTIC_COMPONENTS} effectiveDirective The effective directive of the effective module.
|
|
161
|
+
* @returns {string} The message listing the incompatible effective modules.
|
|
162
|
+
*/
|
|
163
|
+
export const makeMessageFromEffectiveDirective = (effectiveDirective) =>
|
|
164
|
+
makeMessageFromResolvedDirective(
|
|
165
|
+
effectiveDirectives_EffectiveModules,
|
|
166
|
+
effectiveDirectives_BlockedImports,
|
|
167
|
+
effectiveDirective
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
/* findSpecificViolationMessage */
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Finds the `message` for the specific violation of effective directives import rules based on `effectiveDirectives_BlockedImports`.
|
|
174
|
+
* @param {USE_SERVER_LOGICS | USE_SERVER_COMPONENTS | USE_SERVER_FUNCTIONS | USE_CLIENT_LOGICS | USE_CLIENT_COMPONENTS | USE_AGNOSTIC_LOGICS | USE_AGNOSTIC_COMPONENTS} currentFileEffectiveDirective The current file's effective directive.
|
|
175
|
+
* @param {USE_SERVER_LOGICS | USE_SERVER_COMPONENTS | USE_SERVER_FUNCTIONS | USE_CLIENT_LOGICS | USE_CLIENT_COMPONENTS | USE_AGNOSTIC_LOGICS | USE_AGNOSTIC_COMPONENTS} importedFileEffectiveDirective The imported file's effective directive.
|
|
176
|
+
* @returns {string} The corresponding `message`.
|
|
177
|
+
*/
|
|
178
|
+
export const findSpecificViolationMessage = (
|
|
179
|
+
currentFileEffectiveDirective,
|
|
180
|
+
importedFileEffectiveDirective
|
|
181
|
+
) =>
|
|
182
|
+
commonsFindSpecificViolationMessage(
|
|
183
|
+
effectiveDirectives_BlockedImports,
|
|
184
|
+
currentFileEffectiveDirective,
|
|
185
|
+
importedFileEffectiveDirective
|
|
186
|
+
);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { defineConfig } from "eslint/config";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
directive21ConfigName,
|
|
5
|
+
useAgnosticPluginName,
|
|
6
|
+
enforceCommentedDirectivesRuleName,
|
|
7
|
+
} from "../_commons/constants/bases.js";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Makes the directive21 config for the use-agnostic ESLint plugin.
|
|
11
|
+
*/
|
|
12
|
+
export const makeDirective21Config = (plugin) => ({
|
|
13
|
+
[directive21ConfigName]: defineConfig([
|
|
14
|
+
{
|
|
15
|
+
plugins: {
|
|
16
|
+
[useAgnosticPluginName]: plugin,
|
|
17
|
+
},
|
|
18
|
+
rules: {
|
|
19
|
+
[`${useAgnosticPluginName}/${enforceCommentedDirectivesRuleName}`]:
|
|
20
|
+
"warn",
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
]),
|
|
24
|
+
});
|