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
package/README.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
(In progress...)
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
// plugin name
|
|
2
|
+
export const useAgnosticPluginName = "use-agnostic";
|
|
3
|
+
|
|
4
|
+
/* config names */
|
|
5
|
+
// agnostic20
|
|
6
|
+
export const agnostic20ConfigName = "agnostic20";
|
|
7
|
+
// directive21
|
|
8
|
+
export const directive21ConfigName = "directive21";
|
|
9
|
+
|
|
10
|
+
/* rule names */
|
|
11
|
+
// agnostic20
|
|
12
|
+
export const enforceEffectiveDirectivesRuleName =
|
|
13
|
+
"enforce-effective-directives-import-rules";
|
|
14
|
+
// directive21
|
|
15
|
+
export const enforceCommentedDirectivesRuleName =
|
|
16
|
+
"enforce-commented-directives-import-rules";
|
|
17
|
+
|
|
18
|
+
/* messageIds */
|
|
19
|
+
export const reExportNotSameMessageId = "re-export-not-same-directive";
|
|
20
|
+
// agnostic20
|
|
21
|
+
export const importBreaksEffectiveImportRulesMessageId =
|
|
22
|
+
"import-breaks-effective-directive-import-rule";
|
|
23
|
+
export const useServerJSXMessageId = "use-server-has-jsx-extension";
|
|
24
|
+
// directive21
|
|
25
|
+
export const importBreaksCommentedImportRulesMessageId =
|
|
26
|
+
"import-breaks-commented-directive-import-rule";
|
|
27
|
+
export const noCommentedDirective = "no-commented-directive-detected";
|
|
28
|
+
export const commentedDirectiveVerificationFailed =
|
|
29
|
+
"commented-directive-verification-failed";
|
|
30
|
+
export const importNotStrategized =
|
|
31
|
+
"import-from-use-agnostic-strategies-not-strategized";
|
|
32
|
+
export const exportNotStrategized =
|
|
33
|
+
"export-from-use-agnostic-strategies-not-strategized";
|
|
34
|
+
|
|
35
|
+
// all "resolved" directives (from AIA/agnostic20 & DFA/directive21)
|
|
36
|
+
export const USE_SERVER_LOGICS = "use server logics";
|
|
37
|
+
export const USE_CLIENT_LOGICS = "use client logics";
|
|
38
|
+
export const USE_AGNOSTIC_LOGICS = "use agnostic logics";
|
|
39
|
+
export const USE_SERVER_COMPONENTS = "use server components";
|
|
40
|
+
export const USE_CLIENT_COMPONENTS = "use client components";
|
|
41
|
+
export const USE_AGNOSTIC_COMPONENTS = "use agnostic components";
|
|
42
|
+
export const USE_SERVER_FUNCTIONS = "use server functions";
|
|
43
|
+
export const USE_CLIENT_CONTEXTS = "use client contexts";
|
|
44
|
+
export const USE_AGNOSTIC_CONDITIONS = "use agnostic conditions";
|
|
45
|
+
export const USE_AGNOSTIC_STRATEGIES = "use agnostic strategies";
|
|
46
|
+
|
|
47
|
+
// all "resolved" modules (from AIA/agnostic20 & DFA/directive21)
|
|
48
|
+
export const SERVER_LOGICS_MODULE = "Server Logics Module";
|
|
49
|
+
export const CLIENT_LOGICS_MODULE = "Client Logics Module";
|
|
50
|
+
export const AGNOSTIC_LOGICS_MODULE = "Agnostic Logics Module";
|
|
51
|
+
export const SERVER_COMPONENTS_MODULE = "Server Components Module";
|
|
52
|
+
export const CLIENT_COMPONENTS_MODULE = "Client Components Module";
|
|
53
|
+
export const AGNOSTIC_COMPONENTS_MODULE = "Agnostic Components Module";
|
|
54
|
+
export const SERVER_FUNCTIONS_MODULE = "Server Functions Module";
|
|
55
|
+
export const CLIENT_CONTEXTS_MODULE = "Client Contexts Module";
|
|
56
|
+
export const AGNOSTIC_CONDITIONS_MODULE = "Agnostic Conditions Module";
|
|
57
|
+
export const AGNOSTIC_STRATEGIES_MODULE = "Agnostic Strategies Module";
|
|
58
|
+
|
|
59
|
+
/* from the resolveImportPath utility */
|
|
60
|
+
|
|
61
|
+
export const TSX = ".tsx";
|
|
62
|
+
export const TS = ".ts";
|
|
63
|
+
export const JSX = ".jsx";
|
|
64
|
+
export const JS = ".js";
|
|
65
|
+
export const MJS = ".mjs";
|
|
66
|
+
export const CJS = ".cjs";
|
|
67
|
+
|
|
68
|
+
export const EXTENSIONS = [TSX, TS, JSX, JS, MJS, CJS]; // In priority order
|
|
69
|
+
|
|
70
|
+
/* from the isImportBlocked utility */
|
|
71
|
+
|
|
72
|
+
export const ARE_NOT_ALLOWED_TO_IMPORT = "are not allowed to import";
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
|
|
4
|
+
import { loadConfig, createMatchPath } from "tsconfig-paths";
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
USE_SERVER_LOGICS,
|
|
8
|
+
USE_CLIENT_LOGICS,
|
|
9
|
+
USE_AGNOSTIC_LOGICS,
|
|
10
|
+
USE_SERVER_COMPONENTS,
|
|
11
|
+
USE_CLIENT_COMPONENTS,
|
|
12
|
+
USE_AGNOSTIC_COMPONENTS,
|
|
13
|
+
USE_SERVER_FUNCTIONS,
|
|
14
|
+
USE_CLIENT_CONTEXTS,
|
|
15
|
+
USE_AGNOSTIC_CONDITIONS,
|
|
16
|
+
USE_AGNOSTIC_STRATEGIES,
|
|
17
|
+
SERVER_LOGICS_MODULE,
|
|
18
|
+
CLIENT_LOGICS_MODULE,
|
|
19
|
+
AGNOSTIC_LOGICS_MODULE,
|
|
20
|
+
SERVER_COMPONENTS_MODULE,
|
|
21
|
+
CLIENT_COMPONENTS_MODULE,
|
|
22
|
+
AGNOSTIC_COMPONENTS_MODULE,
|
|
23
|
+
SERVER_FUNCTIONS_MODULE,
|
|
24
|
+
CLIENT_CONTEXTS_MODULE,
|
|
25
|
+
AGNOSTIC_CONDITIONS_MODULE,
|
|
26
|
+
AGNOSTIC_STRATEGIES_MODULE,
|
|
27
|
+
EXTENSIONS,
|
|
28
|
+
ARE_NOT_ALLOWED_TO_IMPORT,
|
|
29
|
+
} from "../constants/bases.js";
|
|
30
|
+
|
|
31
|
+
/* resolveImportPath */
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Resolves an import path to a filesystem path, handling:
|
|
35
|
+
* - Aliases (via tsconfig.json `paths`)
|
|
36
|
+
* - Missing extensions (appends .ts, .tsx, etc.)
|
|
37
|
+
* - Directory imports (e.g., `./components` → `./components/index.ts`)
|
|
38
|
+
* @param {string} currentDir Directory of the file containing the import (from `path.dirname(context.filename)`).
|
|
39
|
+
* @param {string} importPath The import specifier (e.g., `@/components/Button` or `./utils`), from the current node.
|
|
40
|
+
* @param {string} cwd Project root (from `context.cwd`). Caveat: only as an assumption currently.
|
|
41
|
+
* @returns {string | null} Absolute resolved path or `null` if not found.
|
|
42
|
+
*/
|
|
43
|
+
export const resolveImportPath = (currentDir, importPath, cwd) => {
|
|
44
|
+
// --- Step 1: Resolve aliases (if tsconfig.json `paths` exists) ---
|
|
45
|
+
const config = loadConfig(cwd);
|
|
46
|
+
|
|
47
|
+
const resolveTSConfig =
|
|
48
|
+
config.resultType === "success"
|
|
49
|
+
? createMatchPath(config.absoluteBaseUrl, config.paths)
|
|
50
|
+
: null;
|
|
51
|
+
|
|
52
|
+
const aliasedPath = resolveTSConfig
|
|
53
|
+
? resolveTSConfig(importPath, undefined, undefined, EXTENSIONS)
|
|
54
|
+
: null;
|
|
55
|
+
|
|
56
|
+
// --- Step 2: Resolve relative/absolute paths ---
|
|
57
|
+
const basePath = aliasedPath || path.resolve(currentDir, importPath);
|
|
58
|
+
|
|
59
|
+
// does not resolve on node_modules
|
|
60
|
+
if (basePath.includes("node_modules")) return null;
|
|
61
|
+
|
|
62
|
+
// Case 1: File with extension exists
|
|
63
|
+
if (path.extname(importPath) && fs.existsSync(basePath)) return basePath;
|
|
64
|
+
|
|
65
|
+
// Case 2: Try appending extensions
|
|
66
|
+
for (const ext of EXTENSIONS) {
|
|
67
|
+
const fullPath = `${basePath}${ext}`;
|
|
68
|
+
if (fs.existsSync(fullPath)) return fullPath;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Case 3: Directory import (e.g., `./components` → `./components/index.ts`)
|
|
72
|
+
const indexPath = path.join(basePath, "index");
|
|
73
|
+
for (const ext of EXTENSIONS) {
|
|
74
|
+
const fullPath = `${indexPath}${ext}`;
|
|
75
|
+
if (fs.existsSync(fullPath)) return fullPath;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return null; // Not found
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
/* getImportedFileFirstLine */
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Gets the first line of code of the imported module.
|
|
85
|
+
* @param {string} resolvedImportPath The resolved path of the imported module.
|
|
86
|
+
* @returns {string} Returns the first line of the imported module.
|
|
87
|
+
*/
|
|
88
|
+
export const getImportedFileFirstLine = (resolvedImportPath) => {
|
|
89
|
+
// gets the code of the import
|
|
90
|
+
const importedFileContent = fs.readFileSync(resolvedImportPath, "utf8");
|
|
91
|
+
// gets the first line of the code of the import
|
|
92
|
+
const importedFileFirstLine = importedFileContent
|
|
93
|
+
.trim()
|
|
94
|
+
.split("\n")[0]
|
|
95
|
+
.trim(); // the line itself needs to be trimmed too
|
|
96
|
+
|
|
97
|
+
return importedFileFirstLine;
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
/* isImportBlocked */
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Returns a boolean deciding if an imported file's "resolved" directive is incompatible with the current file's "resolved" directive.
|
|
104
|
+
* @param {Readonly<{"use server logics": {blockedImport: string; message: string;}[]; "use client logics": {blockedImport: string; message: string;}[]; "use agnostic logics": {blockedImport: string; message: string;}[]; "use server components": {blockedImport: string; message: string;}[]; "use client components": {blockedImport: string; message: string;}[]; "use agnostic components": {blockedImport: string; message: string;}[]; "use server functions": {blockedImport: string; message: string;}[]; "use client contexts"?: {blockedImport: string; message: string;}[]; "use agnostic conditions"?: {blockedImport: string; message: string;}[]; "use agnostic strategies"?: {blockedImport: string; message: string;}[];}>} resolvedDirectives_blockedImports The blocked imports object, either for agnostic20 or for directive21.
|
|
105
|
+
* @param {USE_SERVER_LOGICS | USE_CLIENT_LOGICS | USE_AGNOSTIC_LOGICS | USE_SERVER_COMPONENTS | USE_CLIENT_COMPONENTS | USE_AGNOSTIC_COMPONENTS | USE_SERVER_FUNCTIONS | USE_CLIENT_CONTEXTS | USE_AGNOSTIC_CONDITIONS | USE_AGNOSTIC_STRATEGIES} currentFileResolvedDirective The current file's "resolved" directive.
|
|
106
|
+
* @param {USE_SERVER_LOGICS | USE_CLIENT_LOGICS | USE_AGNOSTIC_LOGICS | USE_SERVER_COMPONENTS | USE_CLIENT_COMPONENTS | USE_AGNOSTIC_COMPONENTS | USE_SERVER_FUNCTIONS | USE_CLIENT_CONTEXTS | USE_AGNOSTIC_CONDITIONS} importedFileResolvedDirective The imported file's "resolved" directive.
|
|
107
|
+
* @returns {boolean} Returns `true` if the import is blocked, as established in respective `resolvedDirectives_blockedImports`.
|
|
108
|
+
*/
|
|
109
|
+
export const isImportBlocked = (
|
|
110
|
+
// Note: "Blocked" here is preferred over "not allowed" because a specific message will be shared for each of the blocked situations, explaining their reasons and the solutions needed.
|
|
111
|
+
resolvedDirectives_blockedImports,
|
|
112
|
+
currentFileResolvedDirective,
|
|
113
|
+
importedFileResolvedDirective,
|
|
114
|
+
) =>
|
|
115
|
+
resolvedDirectives_blockedImports[currentFileResolvedDirective]
|
|
116
|
+
.map((e) => e.blockedImport)
|
|
117
|
+
.includes(importedFileResolvedDirective);
|
|
118
|
+
|
|
119
|
+
/* makeIntroForSpecificViolationMessage */
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Makes the intro for each specific import rule violation messages.
|
|
123
|
+
* @param {Readonly<{"use server logics": SERVER_LOGICS_MODULE; "use client logics": CLIENT_LOGICS_MODULE; "use agnostic logics": AGNOSTIC_LOGICS_MODULE; "use server components": SERVER_COMPONENTS_MODULE; "use client components": CLIENT_COMPONENTS_MODULE; "use agnostic components": AGNOSTIC_COMPONENTS_MODULE; "use server functions": SERVER_FUNCTIONS_MODULE; "use client contexts": CLIENT_CONTEXTS_MODULE; "use agnostic conditions": AGNOSTIC_CONDITIONS_MODULE; "use agnostic strategies": AGNOSTIC_STRATEGIES_MODULE;}>} resolvedDirectives_ResolvedModules The resolved modules object, either for agnostic20 or for directive21.
|
|
124
|
+
* @param {USE_SERVER_LOGICS | USE_CLIENT_LOGICS | USE_AGNOSTIC_LOGICS | USE_SERVER_COMPONENTS | USE_CLIENT_COMPONENTS | USE_AGNOSTIC_COMPONENTS | USE_SERVER_FUNCTIONS | USE_CLIENT_CONTEXTS | USE_AGNOSTIC_CONDITIONS | USE_AGNOSTIC_STRATEGIES} currentFileResolvedDirective The current file's "resolved" directive.
|
|
125
|
+
* @param {USE_SERVER_LOGICS | USE_CLIENT_LOGICS | USE_AGNOSTIC_LOGICS | USE_SERVER_COMPONENTS | USE_CLIENT_COMPONENTS | USE_AGNOSTIC_COMPONENTS | USE_SERVER_FUNCTIONS | USE_CLIENT_CONTEXTS | USE_AGNOSTIC_CONDITIONS} importedFileResolvedDirective The imported file's "resolved" directive.
|
|
126
|
+
* @returns {string} Returns "[Current file 'resolved' modules] are not allowed to import [imported file 'resolved' modules]".
|
|
127
|
+
*/
|
|
128
|
+
export const makeIntroForSpecificViolationMessage = (
|
|
129
|
+
resolvedDirectives_ResolvedModules,
|
|
130
|
+
currentFileResolvedDirective,
|
|
131
|
+
importedFileResolvedDirective,
|
|
132
|
+
) =>
|
|
133
|
+
`${resolvedDirectives_ResolvedModules[currentFileResolvedDirective]}s ${ARE_NOT_ALLOWED_TO_IMPORT} ${resolvedDirectives_ResolvedModules[importedFileResolvedDirective]}s.`;
|
|
134
|
+
|
|
135
|
+
/* makeMessageFromResolvedDirective */
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Lists in an message the "resolved" modules incompatible with a "resolved" module based on its "resolved" directive.
|
|
139
|
+
* @param {Readonly<{"use server logics": SERVER_LOGICS_MODULE; "use client logics": CLIENT_LOGICS_MODULE; "use agnostic logics": AGNOSTIC_LOGICS_MODULE; "use server components": SERVER_COMPONENTS_MODULE; "use client components": CLIENT_COMPONENTS_MODULE; "use agnostic components": AGNOSTIC_COMPONENTS_MODULE; "use server functions": SERVER_FUNCTIONS_MODULE; "use client contexts": CLIENT_CONTEXTS_MODULE; "use agnostic conditions": AGNOSTIC_CONDITIONS_MODULE; "use agnostic strategies": AGNOSTIC_STRATEGIES_MODULE;}>} resolvedDirectives_ResolvedModules The resolved modules object, either for agnostic20 or for directive21.
|
|
140
|
+
* @param {Readonly<{"use server logics": {blockedImport: string; message: string;}[]; "use client logics": {blockedImport: string; message: string;}[]; "use agnostic logics": {blockedImport: string; message: string;}[]; "use server components": {blockedImport: string; message: string;}[]; "use client components": {blockedImport: string; message: string;}[]; "use agnostic components": {blockedImport: string; message: string;}[]; "use server functions": {blockedImport: string; message: string;}[]; "use client contexts"?: {blockedImport: string; message: string;}[]; "use agnostic conditions"?: {blockedImport: string; message: string;}[]; "use agnostic strategies"?: {blockedImport: string; message: string;}[];}>} resolvedDirectives_blockedImports The blocked imports object, either for agnostic20 or for directive21.
|
|
141
|
+
* @param {USE_SERVER_LOGICS | USE_CLIENT_LOGICS | USE_AGNOSTIC_LOGICS | USE_SERVER_COMPONENTS | USE_CLIENT_COMPONENTS | USE_AGNOSTIC_COMPONENTS | USE_SERVER_FUNCTIONS | USE_CLIENT_CONTEXTS | USE_AGNOSTIC_CONDITIONS | USE_AGNOSTIC_STRATEGIES} resolvedDirective The "resolved" directive of the "resolved" module.
|
|
142
|
+
* @returns {string} The message listing the incompatible "resolved" modules.
|
|
143
|
+
*/
|
|
144
|
+
export const makeMessageFromResolvedDirective = (
|
|
145
|
+
resolvedDirectives_ResolvedModules,
|
|
146
|
+
resolvedDirectives_blockedImports,
|
|
147
|
+
resolvedDirective,
|
|
148
|
+
) => {
|
|
149
|
+
const effectiveModule = resolvedDirectives_ResolvedModules[resolvedDirective];
|
|
150
|
+
const effectiveModulesString = effectiveModule + "s"; // plural
|
|
151
|
+
|
|
152
|
+
const blockedImports =
|
|
153
|
+
resolvedDirectives_blockedImports[resolvedDirective].map(
|
|
154
|
+
(e) => e.blockedImport,
|
|
155
|
+
) || [];
|
|
156
|
+
|
|
157
|
+
if (blockedImports.length === 0) {
|
|
158
|
+
return `${effectiveModulesString} are not restricted from importing any modules.`;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const blockedEffectiveModules = blockedImports.map(
|
|
162
|
+
(e) => resolvedDirectives_ResolvedModules[e] + "s", // plural
|
|
163
|
+
);
|
|
164
|
+
|
|
165
|
+
const blockedEffectiveModulesString =
|
|
166
|
+
blockedEffectiveModules.length === 1
|
|
167
|
+
? blockedEffectiveModules[0]
|
|
168
|
+
: blockedEffectiveModules.slice(0, -1).join(", ") +
|
|
169
|
+
", or " +
|
|
170
|
+
blockedEffectiveModules.slice(-1);
|
|
171
|
+
|
|
172
|
+
return `${effectiveModulesString} ${ARE_NOT_ALLOWED_TO_IMPORT} ${blockedEffectiveModulesString}.`;
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
/* findSpecificViolationMessage */
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Finds the `message` for the specific violation of "resolved" directives import rules based on `resolvedDirectives_blockedImports`.
|
|
179
|
+
* @param {Readonly<{"use server logics": {blockedImport: string; message: string;}[]; "use client logics": {blockedImport: string; message: string;}[]; "use agnostic logics": {blockedImport: string; message: string;}[]; "use server components": {blockedImport: string; message: string;}[]; "use client components": {blockedImport: string; message: string;}[]; "use agnostic components": {blockedImport: string; message: string;}[]; "use server functions": {blockedImport: string; message: string;}[]; "use client contexts"?: {blockedImport: string; message: string;}[]; "use agnostic conditions"?: {blockedImport: string; message: string;}[]; "use agnostic strategies"?: {blockedImport: string; message: string;}[];}>} resolvedDirectives_blockedImports The blocked imports object, either for agnostic20 or for directive21.
|
|
180
|
+
* @param {USE_SERVER_LOGICS | USE_CLIENT_LOGICS | USE_AGNOSTIC_LOGICS | USE_SERVER_COMPONENTS | USE_CLIENT_COMPONENTS | USE_AGNOSTIC_COMPONENTS | USE_SERVER_FUNCTIONS | USE_CLIENT_CONTEXTS | USE_AGNOSTIC_CONDITIONS | USE_AGNOSTIC_STRATEGIES} currentFileResolvedDirective The current file's "resolved" directive.
|
|
181
|
+
* @param {USE_SERVER_LOGICS | USE_CLIENT_LOGICS | USE_AGNOSTIC_LOGICS | USE_SERVER_COMPONENTS | USE_CLIENT_COMPONENTS | USE_AGNOSTIC_COMPONENTS | USE_SERVER_FUNCTIONS | USE_CLIENT_CONTEXTS | USE_AGNOSTIC_CONDITIONS} importedFileResolvedDirective The imported file's "resolved" directive.
|
|
182
|
+
* @returns {string} The corresponding `message`.
|
|
183
|
+
*/
|
|
184
|
+
export const findSpecificViolationMessage = (
|
|
185
|
+
resolvedDirectives_blockedImports,
|
|
186
|
+
currentFileResolvedDirective,
|
|
187
|
+
importedFileResolvedDirective,
|
|
188
|
+
) =>
|
|
189
|
+
resolvedDirectives_blockedImports[currentFileResolvedDirective].find(
|
|
190
|
+
(e) => e.blockedImport === importedFileResolvedDirective,
|
|
191
|
+
).message;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { defineConfig } from "eslint/config";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
agnostic20ConfigName,
|
|
5
|
+
useAgnosticPluginName,
|
|
6
|
+
enforceEffectiveDirectivesRuleName,
|
|
7
|
+
} from "../_commons/constants/bases.js";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Makes the agnostic20 config for the use-agnostic ESLint plugin.
|
|
11
|
+
*/
|
|
12
|
+
export const makeAgnostic20Config = (plugin) => ({
|
|
13
|
+
[agnostic20ConfigName]: defineConfig([
|
|
14
|
+
{
|
|
15
|
+
plugins: {
|
|
16
|
+
[useAgnosticPluginName]: plugin,
|
|
17
|
+
},
|
|
18
|
+
rules: {
|
|
19
|
+
[`${useAgnosticPluginName}/${enforceEffectiveDirectivesRuleName}`]:
|
|
20
|
+
"warn",
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
]),
|
|
24
|
+
});
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
import {
|
|
2
|
+
USE_SERVER_LOGICS as COMMONS_USE_SERVER_LOGICS,
|
|
3
|
+
USE_SERVER_COMPONENTS as COMMONS_USE_SERVER_COMPONENTS,
|
|
4
|
+
USE_SERVER_FUNCTIONS as COMMONS_USE_SERVER_FUNCTIONS,
|
|
5
|
+
USE_CLIENT_LOGICS as COMMONS_USE_CLIENT_LOGICS,
|
|
6
|
+
USE_CLIENT_COMPONENTS as COMMONS_USE_CLIENT_COMPONENTS,
|
|
7
|
+
USE_AGNOSTIC_LOGICS as COMMONS_USE_AGNOSTIC_LOGICS,
|
|
8
|
+
USE_AGNOSTIC_COMPONENTS as COMMONS_USE_AGNOSTIC_COMPONENTS,
|
|
9
|
+
SERVER_LOGICS_MODULE as COMMONS_SERVER_LOGICS_MODULE,
|
|
10
|
+
SERVER_COMPONENTS_MODULE as COMMONS_SERVER_COMPONENTS_MODULE,
|
|
11
|
+
SERVER_FUNCTIONS_MODULE as COMMONS_SERVER_FUNCTIONS_MODULE,
|
|
12
|
+
CLIENT_LOGICS_MODULE as COMMONS_CLIENT_LOGICS_MODULE,
|
|
13
|
+
CLIENT_COMPONENTS_MODULE as COMMONS_CLIENT_COMPONENTS_MODULE,
|
|
14
|
+
AGNOSTIC_LOGICS_MODULE as COMMONS_AGNOSTIC_LOGICS_MODULE,
|
|
15
|
+
AGNOSTIC_COMPONENTS_MODULE as COMMONS_AGNOSTIC_COMPONENTS_MODULE,
|
|
16
|
+
} from "../../_commons/constants/bases.js";
|
|
17
|
+
|
|
18
|
+
import { makeIntroForSpecificViolationMessage as commonsMakeIntroForSpecificViolationMessage } from "../../_commons/utilities/helpers.js";
|
|
19
|
+
|
|
20
|
+
// directives
|
|
21
|
+
export const NO_DIRECTIVE = null;
|
|
22
|
+
export const USE_SERVER = "use server";
|
|
23
|
+
export const USE_CLIENT = "use client";
|
|
24
|
+
export const USE_AGNOSTIC = "use agnostic";
|
|
25
|
+
|
|
26
|
+
// effective directives
|
|
27
|
+
export const USE_SERVER_LOGICS = COMMONS_USE_SERVER_LOGICS;
|
|
28
|
+
export const USE_SERVER_COMPONENTS = COMMONS_USE_SERVER_COMPONENTS;
|
|
29
|
+
export const USE_SERVER_FUNCTIONS = COMMONS_USE_SERVER_FUNCTIONS;
|
|
30
|
+
export const USE_CLIENT_LOGICS = COMMONS_USE_CLIENT_LOGICS;
|
|
31
|
+
export const USE_CLIENT_COMPONENTS = COMMONS_USE_CLIENT_COMPONENTS;
|
|
32
|
+
export const USE_AGNOSTIC_LOGICS = COMMONS_USE_AGNOSTIC_LOGICS;
|
|
33
|
+
export const USE_AGNOSTIC_COMPONENTS = COMMONS_USE_AGNOSTIC_COMPONENTS;
|
|
34
|
+
|
|
35
|
+
// effective modules
|
|
36
|
+
const SERVER_LOGICS_MODULE = COMMONS_SERVER_LOGICS_MODULE;
|
|
37
|
+
const SERVER_COMPONENTS_MODULE = COMMONS_SERVER_COMPONENTS_MODULE;
|
|
38
|
+
const SERVER_FUNCTIONS_MODULE = COMMONS_SERVER_FUNCTIONS_MODULE;
|
|
39
|
+
const CLIENT_LOGICS_MODULE = COMMONS_CLIENT_LOGICS_MODULE;
|
|
40
|
+
const CLIENT_COMPONENTS_MODULE = COMMONS_CLIENT_COMPONENTS_MODULE;
|
|
41
|
+
const AGNOSTIC_LOGICS_MODULE = COMMONS_AGNOSTIC_LOGICS_MODULE;
|
|
42
|
+
const AGNOSTIC_COMPONENTS_MODULE = COMMONS_AGNOSTIC_COMPONENTS_MODULE;
|
|
43
|
+
|
|
44
|
+
// mapping effective directives with effective modules
|
|
45
|
+
export const effectiveDirectives_EffectiveModules = Object.freeze({
|
|
46
|
+
[USE_SERVER_LOGICS]: SERVER_LOGICS_MODULE,
|
|
47
|
+
[USE_SERVER_COMPONENTS]: SERVER_COMPONENTS_MODULE,
|
|
48
|
+
[USE_SERVER_FUNCTIONS]: SERVER_FUNCTIONS_MODULE,
|
|
49
|
+
[USE_CLIENT_LOGICS]: CLIENT_LOGICS_MODULE,
|
|
50
|
+
[USE_CLIENT_COMPONENTS]: CLIENT_COMPONENTS_MODULE,
|
|
51
|
+
[USE_AGNOSTIC_LOGICS]: AGNOSTIC_LOGICS_MODULE,
|
|
52
|
+
[USE_AGNOSTIC_COMPONENTS]: AGNOSTIC_COMPONENTS_MODULE,
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
// message placeholders
|
|
56
|
+
|
|
57
|
+
export const currentFileEffectiveDirective = "currentFileEffectiveDirective";
|
|
58
|
+
export const importedFileEffectiveDirective = "importedFileEffectiveDirective";
|
|
59
|
+
export const effectiveDirectiveMessage = "effectiveDirectiveMessage";
|
|
60
|
+
export const specificViolationMessage = "specificViolationMessage";
|
|
61
|
+
|
|
62
|
+
/* from the getDirectiveFromCurrentModule utility */
|
|
63
|
+
|
|
64
|
+
export const directivesSet = new Set([USE_SERVER, USE_CLIENT, USE_AGNOSTIC]);
|
|
65
|
+
|
|
66
|
+
/* from the getDirectiveFromImportedModule utility */
|
|
67
|
+
|
|
68
|
+
export const directivesArray = Array.from(directivesSet);
|
|
69
|
+
|
|
70
|
+
/* from the isImportBlocked utility */
|
|
71
|
+
|
|
72
|
+
/* effectiveDirectives_BlockedImports */
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Makes the intro for each specific import rule violation messages.
|
|
76
|
+
* @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.
|
|
77
|
+
* @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.
|
|
78
|
+
* @returns {string} Returns "[Current file effective modules] are not allowed to import [imported file effective modules]".
|
|
79
|
+
*/
|
|
80
|
+
const makeIntroForSpecificViolationMessage = (
|
|
81
|
+
currentFileEffectiveDirective,
|
|
82
|
+
importedFileEffectiveDirective
|
|
83
|
+
) =>
|
|
84
|
+
commonsMakeIntroForSpecificViolationMessage(
|
|
85
|
+
effectiveDirectives_EffectiveModules,
|
|
86
|
+
currentFileEffectiveDirective,
|
|
87
|
+
importedFileEffectiveDirective
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
export const effectiveDirectives_BlockedImports = Object.freeze({
|
|
91
|
+
[USE_SERVER_LOGICS]: [
|
|
92
|
+
// USE_SERVER_LOGICS allowed, because Server Logics can compose with one another.
|
|
93
|
+
// USE_SERVER_COMPONENTS allowed, because Server Components are OK to be composed with Server Logics as long as the Server Logics Module, by convention, does not export React components.
|
|
94
|
+
// USE_SERVER_FUNCTIONS allowed, because as Server Functions can import one another, it is only natural that they could compose through Server Logics.
|
|
95
|
+
{
|
|
96
|
+
blockedImport: USE_CLIENT_LOGICS,
|
|
97
|
+
message: `${makeIntroForSpecificViolationMessage(
|
|
98
|
+
USE_SERVER_LOGICS,
|
|
99
|
+
USE_CLIENT_LOGICS
|
|
100
|
+
)} Client logic should never leak to the server.`,
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
blockedImport: USE_CLIENT_COMPONENTS,
|
|
104
|
+
message: `${makeIntroForSpecificViolationMessage(
|
|
105
|
+
USE_SERVER_LOGICS,
|
|
106
|
+
USE_CLIENT_COMPONENTS
|
|
107
|
+
)} Client Components cannot be tinkered with on the server.`,
|
|
108
|
+
},
|
|
109
|
+
// USE_AGNOSTIC_LOGICS allowed, because Agnostic Logic can run safely on the server just like it can on the client.
|
|
110
|
+
// USE_AGNOSTIC_COMPONENTS allowed, because Agnostic Components can be composed with Logics on the server just like they can on the client, again, as long at the Server Logics Module, by convention, does not export React components.
|
|
111
|
+
],
|
|
112
|
+
[USE_SERVER_COMPONENTS]: [
|
|
113
|
+
// USE_SERVER_LOGICS allowed, because logic from the server can safely support Server Components.
|
|
114
|
+
// USE_SERVER_COMPONENTS allowed, because Server Components can compose with one another, assuming thanks to the inclusion of the 'use agnostic' directive that they are actual Server Components.
|
|
115
|
+
// USE_SERVER_FUNCTIONS allowed, because as Server Components Modules can import Client Components, they are able to pass them Server Functions as props as well, even though indeed Server Components Modules can make their own Server Functions through inline 'use server' directives.
|
|
116
|
+
{
|
|
117
|
+
blockedImport: USE_CLIENT_LOGICS,
|
|
118
|
+
message: `${makeIntroForSpecificViolationMessage(
|
|
119
|
+
USE_SERVER_COMPONENTS,
|
|
120
|
+
USE_CLIENT_LOGICS
|
|
121
|
+
)} Client logic should never leak to the server.`,
|
|
122
|
+
},
|
|
123
|
+
// USE_CLIENT_COMPONENTS allowed, because Client Components can be nested inside Server Components either to wrap some of the tree with client state accessible through child Client Components and pass through Server Components, or to create client boundaries when the root of the application is planted on the server.
|
|
124
|
+
// USE_AGNOSTIC_LOGICS allowed, because Agnostic Logic can run safely on the server just like it can on the client.
|
|
125
|
+
// USE_AGNOSTIC_COMPONENTS allowed, because Agnostic Components can render safely on the server just like they can on the client.
|
|
126
|
+
],
|
|
127
|
+
[USE_SERVER_FUNCTIONS]: [
|
|
128
|
+
// USE_SERVER_LOGICS allowed, because logic from the server can safely support Server Functions.
|
|
129
|
+
{
|
|
130
|
+
blockedImport: USE_SERVER_COMPONENTS,
|
|
131
|
+
message: `${makeIntroForSpecificViolationMessage(
|
|
132
|
+
USE_SERVER_FUNCTIONS,
|
|
133
|
+
USE_SERVER_COMPONENTS
|
|
134
|
+
)} Server Functions have no business working with React Components.`,
|
|
135
|
+
},
|
|
136
|
+
// USE_SERVER_FUNCTIONS allowed, because even though Server Functions don't need to import one another and the same results can be generated via Server Logic alone for the outcome of a single Server Function, a rational use case could be found for composing Server Functions with one another either today or in the future.
|
|
137
|
+
{
|
|
138
|
+
blockedImport: USE_CLIENT_LOGICS,
|
|
139
|
+
message: `${makeIntroForSpecificViolationMessage(
|
|
140
|
+
USE_SERVER_FUNCTIONS,
|
|
141
|
+
USE_CLIENT_LOGICS
|
|
142
|
+
)} Client logic should never leak to the server.`,
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
blockedImport: USE_CLIENT_COMPONENTS,
|
|
146
|
+
message: `${makeIntroForSpecificViolationMessage(
|
|
147
|
+
USE_SERVER_FUNCTIONS,
|
|
148
|
+
USE_CLIENT_COMPONENTS
|
|
149
|
+
)} Server Functions have no business working with React Components.`,
|
|
150
|
+
},
|
|
151
|
+
// USE_AGNOSTIC_LOGICS allowed, because Agnostic Logic can run safely on the server just like it can on the client.
|
|
152
|
+
{
|
|
153
|
+
blockedImport: USE_AGNOSTIC_COMPONENTS,
|
|
154
|
+
message: `${makeIntroForSpecificViolationMessage(
|
|
155
|
+
USE_SERVER_FUNCTIONS,
|
|
156
|
+
USE_AGNOSTIC_COMPONENTS
|
|
157
|
+
)} Server Functions have no business working with React Components.`,
|
|
158
|
+
},
|
|
159
|
+
],
|
|
160
|
+
[USE_CLIENT_LOGICS]: [
|
|
161
|
+
{
|
|
162
|
+
blockedImport: USE_SERVER_LOGICS,
|
|
163
|
+
message: `${makeIntroForSpecificViolationMessage(
|
|
164
|
+
USE_CLIENT_LOGICS,
|
|
165
|
+
USE_SERVER_LOGICS
|
|
166
|
+
)} Server logic should never leak to the client.`,
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
blockedImport: USE_SERVER_COMPONENTS,
|
|
170
|
+
message: `${makeIntroForSpecificViolationMessage(
|
|
171
|
+
USE_CLIENT_LOGICS,
|
|
172
|
+
USE_SERVER_COMPONENTS
|
|
173
|
+
)} Server Components cannot be thinkered with on the client.`,
|
|
174
|
+
},
|
|
175
|
+
// USE_SERVER_FUNCTIONS allowed, because it is technically feasible to tinker with a Client Component within a Client Logics Module and attach to said Client Component a Server Function to be triggered on the client.
|
|
176
|
+
// USE_CLIENT_LOGICS allowed, because Client Logics can compose with one another.
|
|
177
|
+
// USE_CLIENT_COMPONENTS allowed, because Client Components are OK to be composed with Client Logics as long as the Client Logics Module, by convention, does not export React components.
|
|
178
|
+
// USE_AGNOSTIC_LOGICS allowed, because Agnostic Logic can run safely on the client just like it can on the server.
|
|
179
|
+
// USE_AGNOSTIC_COMPONENTS allowed, because Agnostic Components can be composed with Logics on the client just like they can on the server, again, as long at the Client Logics Module, by convention, does not export React components.
|
|
180
|
+
],
|
|
181
|
+
[USE_CLIENT_COMPONENTS]: [
|
|
182
|
+
{
|
|
183
|
+
blockedImport: USE_SERVER_LOGICS,
|
|
184
|
+
message: `${makeIntroForSpecificViolationMessage(
|
|
185
|
+
USE_CLIENT_COMPONENTS,
|
|
186
|
+
USE_SERVER_LOGICS
|
|
187
|
+
)} Server logic should never leak to the client.`,
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
blockedImport: USE_SERVER_COMPONENTS,
|
|
191
|
+
message: `${makeIntroForSpecificViolationMessage(
|
|
192
|
+
USE_CLIENT_COMPONENTS,
|
|
193
|
+
USE_SERVER_COMPONENTS
|
|
194
|
+
)} Server Components may only pass through Client Components through the children prop within Server Components Modules.`,
|
|
195
|
+
},
|
|
196
|
+
// USE_SERVER_FUNCTIONS allowed, because Server Functions are specifically triggered by Client Components.
|
|
197
|
+
// USE_CLIENT_LOGICS allowed, because logic from the client can safely support Client Components.
|
|
198
|
+
// USE_CLIENT_COMPONENTS allowed, because Client Components can compose with one another.
|
|
199
|
+
// USE_AGNOSTIC_LOGICS allowed, because Agnostic Logic can run safely on the client just like it can on the server.
|
|
200
|
+
// USE_AGNOSTIC_COMPONENTS allowed, because Agnostic Components can render safely on the client just like they can on the server.
|
|
201
|
+
],
|
|
202
|
+
[USE_AGNOSTIC_LOGICS]: [
|
|
203
|
+
{
|
|
204
|
+
blockedImport: USE_SERVER_LOGICS,
|
|
205
|
+
message: `${makeIntroForSpecificViolationMessage(
|
|
206
|
+
USE_AGNOSTIC_LOGICS,
|
|
207
|
+
USE_SERVER_LOGICS
|
|
208
|
+
)} Server Logic cannot run in both the server and the client.`,
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
blockedImport: USE_SERVER_COMPONENTS,
|
|
212
|
+
message: `${makeIntroForSpecificViolationMessage(
|
|
213
|
+
USE_AGNOSTIC_LOGICS,
|
|
214
|
+
USE_SERVER_COMPONENTS
|
|
215
|
+
)} Server Components cannot be tinkered with on both the server and the client.`,
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
blockedImport: USE_SERVER_FUNCTIONS,
|
|
219
|
+
message: `${makeIntroForSpecificViolationMessage(
|
|
220
|
+
USE_AGNOSTIC_LOGICS,
|
|
221
|
+
USE_SERVER_FUNCTIONS
|
|
222
|
+
)} Though Server Functions can be tinkered with on the server and on the client, use cases on both environments are not compatible.`,
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
blockedImport: USE_CLIENT_LOGICS,
|
|
226
|
+
message: `${makeIntroForSpecificViolationMessage(
|
|
227
|
+
USE_AGNOSTIC_LOGICS,
|
|
228
|
+
USE_CLIENT_LOGICS
|
|
229
|
+
)} Client Logic cannot run in both the server and the client.`,
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
blockedImport: USE_CLIENT_COMPONENTS,
|
|
233
|
+
message: `${makeIntroForSpecificViolationMessage(
|
|
234
|
+
USE_AGNOSTIC_LOGICS,
|
|
235
|
+
USE_CLIENT_COMPONENTS
|
|
236
|
+
)} Client Components cannot be tinkered with on both the server and the client.`,
|
|
237
|
+
},
|
|
238
|
+
// USE_AGNOSTIC_LOGICS allowed, because Agnostic Logics can compose with one another.
|
|
239
|
+
// USE_AGNOSTIC_COMPONENTS allowed, because Agnostic Components can be composed with Logics agnostically as long as the Agnostic Logics Module, by convention, does not export React components.
|
|
240
|
+
],
|
|
241
|
+
[USE_AGNOSTIC_COMPONENTS]: [
|
|
242
|
+
{
|
|
243
|
+
blockedImport: USE_SERVER_LOGICS,
|
|
244
|
+
message: `${makeIntroForSpecificViolationMessage(
|
|
245
|
+
USE_AGNOSTIC_COMPONENTS,
|
|
246
|
+
USE_SERVER_LOGICS
|
|
247
|
+
)} Server Logic cannot run in both the server and the client.`,
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
blockedImport: USE_SERVER_COMPONENTS,
|
|
251
|
+
message: `${makeIntroForSpecificViolationMessage(
|
|
252
|
+
USE_AGNOSTIC_COMPONENTS,
|
|
253
|
+
USE_SERVER_COMPONENTS
|
|
254
|
+
)} Unlike Client Components, Server Components cannot make silos of their own once on the client, and can therefore not be executed from the client.`,
|
|
255
|
+
},
|
|
256
|
+
// USE_SERVER_FUNCTIONS allowed, because as Agnostic Components Modules can import Client Components, they are able to pass them Server Functions as props as well.
|
|
257
|
+
{
|
|
258
|
+
blockedImport: USE_CLIENT_LOGICS,
|
|
259
|
+
message: `${makeIntroForSpecificViolationMessage(
|
|
260
|
+
USE_AGNOSTIC_COMPONENTS,
|
|
261
|
+
USE_CLIENT_LOGICS
|
|
262
|
+
)} Client Logic cannot run in both the server and the client.`,
|
|
263
|
+
},
|
|
264
|
+
// USE_CLIENT_COMPONENTS allowed, because Client Components can be nested inside Agnostic Components either to wrap some of the tree with client state accessible through child Client Components and pass through Server Components (if still on the Server Tree), or to create client boundaries when the root of the application is planted on the server.
|
|
265
|
+
// USE_AGNOSTIC_LOGICS allowed, because environment-agnostic logic can safely support Agnostic Components.
|
|
266
|
+
// USE_AGNOSTIC_COMPONENTS allowed, because Agnostic Components can compose with one another.
|
|
267
|
+
],
|
|
268
|
+
});
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import {
|
|
2
|
+
reExportNotSameMessageId,
|
|
3
|
+
importBreaksEffectiveImportRulesMessageId,
|
|
4
|
+
useServerJSXMessageId,
|
|
5
|
+
} from "../../_commons/constants/bases.js";
|
|
6
|
+
import {
|
|
7
|
+
currentFileEffectiveDirective,
|
|
8
|
+
importedFileEffectiveDirective,
|
|
9
|
+
effectiveDirectiveMessage,
|
|
10
|
+
specificViolationMessage,
|
|
11
|
+
} from "../constants/bases.js";
|
|
12
|
+
|
|
13
|
+
import {
|
|
14
|
+
currentFileFlow,
|
|
15
|
+
importsFlow,
|
|
16
|
+
reExportsFlow,
|
|
17
|
+
} from "../utilities/flows.js";
|
|
18
|
+
|
|
19
|
+
/** @type {import('@typescript-eslint/utils').TSESLint.RuleModule<typeof reExportNotSameMessageId | typeof importBreaksEffectiveImportRulesMessageId | typeof useServerJSXMessageId, []>} */
|
|
20
|
+
const rule = {
|
|
21
|
+
meta: {
|
|
22
|
+
type: "problem",
|
|
23
|
+
docs: {
|
|
24
|
+
description:
|
|
25
|
+
"Enforces import rules based on the file's effective directive. ",
|
|
26
|
+
},
|
|
27
|
+
schema: [],
|
|
28
|
+
// currentFileEffectiveDirective, importedFileEffectiveDirective, effectiveDirectiveMessage, specificViolationMessage
|
|
29
|
+
messages: {
|
|
30
|
+
[reExportNotSameMessageId]: `The effective directives of this file and this re-export are dissimilar.
|
|
31
|
+
Here, "{{ ${currentFileEffectiveDirective} }}" and "{{ ${importedFileEffectiveDirective} }}" are not the same. Please re-export only from modules that have the same effective directive as the current module. `,
|
|
32
|
+
[importBreaksEffectiveImportRulesMessageId]: `{{ ${effectiveDirectiveMessage} }}
|
|
33
|
+
In this case, {{ ${specificViolationMessage} }} `,
|
|
34
|
+
[useServerJSXMessageId]: `Modules marked with the 'use server' directive are not allowed to have JSX file extensions.
|
|
35
|
+
Indeed, Server Functions Modules have no business exporting JSX. `,
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
create: (context) => {
|
|
39
|
+
const result = currentFileFlow(context);
|
|
40
|
+
|
|
41
|
+
if (result.skip) return {};
|
|
42
|
+
const { currentFileEffectiveDirective } = result;
|
|
43
|
+
|
|
44
|
+
return {
|
|
45
|
+
ImportDeclaration: (node) =>
|
|
46
|
+
importsFlow(context, node, currentFileEffectiveDirective),
|
|
47
|
+
ExportNamedDeclaration: (node) =>
|
|
48
|
+
reExportsFlow(context, node, currentFileEffectiveDirective),
|
|
49
|
+
ExportAllDeclaration: (node) =>
|
|
50
|
+
reExportsFlow(context, node, currentFileEffectiveDirective),
|
|
51
|
+
};
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export default rule; // enforce-effective-directives-import-rules
|