eslint-plugin-use-agnostic 0.9.5 → 0.9.7

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 CHANGED
@@ -20,7 +20,7 @@ import { defineConfig, globalIgnores } from "eslint/config";
20
20
  import useAgnostic, {
21
21
  useAgnosticPluginName,
22
22
  agnostic20ConfigName,
23
- } from "eslint-plugin-use-agnostic"; // no declaration file at this time
23
+ } from "eslint-plugin-use-agnostic";
24
24
 
25
25
  export default defineConfig([
26
26
  globalIgnores([".next", ".react-router", "node_modules"]),
@@ -1,3 +1,7 @@
1
+ /**
2
+ * @typedef {import('../../../types/_commons/typedefs').Extensions} Extensions
3
+ */
4
+
1
5
  /* plugin names */
2
6
  // use-agnostic
3
7
  export const useAgnosticPluginName = "use-agnostic";
@@ -45,6 +49,7 @@ export const exportNotStrategized =
45
49
  // all "resolved" directives (from AIA/agnostic20 & DFA/directive21)
46
50
  // - AIA: Agnostic-Included Architecture (agnostic20)
47
51
  // - DFA: Directive-First Architecture (directive21)
52
+ // agnostic20
48
53
  export const USE_SERVER_LOGICS = "use server logics";
49
54
  export const USE_CLIENT_LOGICS = "use client logics";
50
55
  export const USE_AGNOSTIC_LOGICS = "use agnostic logics";
@@ -52,11 +57,13 @@ export const USE_SERVER_COMPONENTS = "use server components";
52
57
  export const USE_CLIENT_COMPONENTS = "use client components";
53
58
  export const USE_AGNOSTIC_COMPONENTS = "use agnostic components";
54
59
  export const USE_SERVER_FUNCTIONS = "use server functions";
60
+ // and directive21
55
61
  export const USE_CLIENT_CONTEXTS = "use client contexts";
56
62
  export const USE_AGNOSTIC_CONDITIONS = "use agnostic conditions";
57
63
  export const USE_AGNOSTIC_STRATEGIES = "use agnostic strategies";
58
64
 
59
65
  // all "resolved" modules (from AIA/agnostic20 & DFA/directive21)
66
+ // agnostic20
60
67
  export const SERVER_LOGICS_MODULE = "Server Logics Module";
61
68
  export const CLIENT_LOGICS_MODULE = "Client Logics Module";
62
69
  export const AGNOSTIC_LOGICS_MODULE = "Agnostic Logics Module";
@@ -64,10 +71,30 @@ export const SERVER_COMPONENTS_MODULE = "Server Components Module";
64
71
  export const CLIENT_COMPONENTS_MODULE = "Client Components Module";
65
72
  export const AGNOSTIC_COMPONENTS_MODULE = "Agnostic Components Module";
66
73
  export const SERVER_FUNCTIONS_MODULE = "Server Functions Module";
74
+ // and directive21
67
75
  export const CLIENT_CONTEXTS_MODULE = "Client Contexts Module";
68
76
  export const AGNOSTIC_CONDITIONS_MODULE = "Agnostic Conditions Module";
69
77
  export const AGNOSTIC_STRATEGIES_MODULE = "Agnostic Strategies Module";
70
78
 
79
+ // all mappings of "resolved" directives with "resolved" modules
80
+ // agnostic20
81
+ export const effectiveDirectives_effectiveModules = Object.freeze({
82
+ [USE_SERVER_LOGICS]: SERVER_LOGICS_MODULE,
83
+ [USE_SERVER_COMPONENTS]: SERVER_COMPONENTS_MODULE,
84
+ [USE_SERVER_FUNCTIONS]: SERVER_FUNCTIONS_MODULE,
85
+ [USE_CLIENT_LOGICS]: CLIENT_LOGICS_MODULE,
86
+ [USE_CLIENT_COMPONENTS]: CLIENT_COMPONENTS_MODULE,
87
+ [USE_AGNOSTIC_LOGICS]: AGNOSTIC_LOGICS_MODULE,
88
+ [USE_AGNOSTIC_COMPONENTS]: AGNOSTIC_COMPONENTS_MODULE,
89
+ });
90
+ // and directive21
91
+ export const commentedDirectives_commentedModules = Object.freeze({
92
+ [USE_CLIENT_CONTEXTS]: CLIENT_CONTEXTS_MODULE,
93
+ [USE_AGNOSTIC_CONDITIONS]: AGNOSTIC_CONDITIONS_MODULE,
94
+ [USE_AGNOSTIC_STRATEGIES]: AGNOSTIC_STRATEGIES_MODULE,
95
+ ...effectiveDirectives_effectiveModules,
96
+ });
97
+
71
98
  // JavaScript/TypeScript extensions
72
99
  export const TSX = ".tsx";
73
100
  export const TS = ".ts";
@@ -77,8 +104,14 @@ export const MJS = ".mjs";
77
104
  export const CJS = ".cjs";
78
105
 
79
106
  // JavaScript/TypeScript extensions array
80
- /** @type {readonly [TSX, TS, JSX, JS, MJS, CJS]} */
107
+ // /** @type {readonly [TSX, TS, JSX, JS, MJS, CJS]} */
108
+ /** @type {Extensions} */
81
109
  export const EXTENSIONS = [TSX, TS, JSX, JS, MJS, CJS]; // In priority order
82
110
 
83
111
  // message strings
84
112
  export const ARE_NOT_ALLOWED_TO_IMPORT = "are not allowed to import";
113
+
114
+ // skipping object for flows
115
+ export const skip = Object.freeze({
116
+ skip: true,
117
+ });
@@ -3,30 +3,23 @@ import path from "path";
3
3
 
4
4
  import { loadConfig, createMatchPath } from "tsconfig-paths";
5
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";
6
+ import { EXTENSIONS, ARE_NOT_ALLOWED_TO_IMPORT } from "../constants/bases.js";
7
+
8
+ /**
9
+ * @typedef {import('../../../types/_commons/typedefs').ResolvedDirective} ResolvedDirective
10
+ * @typedef {import('../../../types/_commons/typedefs').ResolvedDirectives_ResolvedModules} ResolvedDirectives_ResolvedModules
11
+ * @typedef {import('../../../types/_commons/typedefs').CurrentFileResolvedDirective} CurrentFileResolvedDirective
12
+ * @typedef {import('../../../types/_commons/typedefs').Context<string, readonly unknown[]>} Context
13
+ */
14
+
15
+ /**
16
+ * @template {CurrentFileResolvedDirective} T
17
+ * @typedef {import('../../../types/_commons/typedefs').ImportedFileResolvedDirective<T>} ImportedFileResolvedDirective
18
+ */
19
+ /**
20
+ * @template {CurrentFileResolvedDirective} T
21
+ * @typedef {import('../../../types/_commons/typedefs').ResolvedDirectives_BlockedImports<T>} ResolvedDirectives_BlockedImports
22
+ */
30
23
 
31
24
  /* resolveImportPath */
32
25
 
@@ -110,7 +103,7 @@ export const getImportedFileFirstLine = (resolvedImportPath) => {
110
103
 
111
104
  /**
112
105
  * Gets the coordinates for the first line of code of a file.
113
- * @param {import('@typescript-eslint/utils').TSESLint.RuleContext} context An ESLint rule's `context` object.
106
+ * @param {Context} context An ESLint rule's `context` object.
114
107
  * @returns The `context.report` `loc`-compatible coordinates for the first line of code of a file.
115
108
  */
116
109
  export const highlightFirstLineOfCode = (context) => ({
@@ -122,10 +115,11 @@ export const highlightFirstLineOfCode = (context) => ({
122
115
 
123
116
  /**
124
117
  * Returns a boolean deciding if an imported file's "resolved" directive is incompatible with the current file's "resolved" directive.
125
- * @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.
126
- * @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.
127
- * @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.
128
- * @returns Returns `true` if the import is blocked, as established in respective `resolvedDirectives_blockedImports`.
118
+ * @template {CurrentFileResolvedDirective} T
119
+ * @param {ResolvedDirectives_BlockedImports<T>} resolvedDirectives_blockedImports The blocked imports object, either for agnostic20 or for directive21.
120
+ * @param {T} currentFileResolvedDirective The current file's "resolved" directive.
121
+ * @param {ImportedFileResolvedDirective<T>} importedFileResolvedDirective The imported file's "resolved" directive.
122
+ * @returns `true` if the import is blocked, as established in respective `resolvedDirectives_blockedImports`.
129
123
  */
130
124
  export const isImportBlocked = (
131
125
  // 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.
@@ -141,33 +135,35 @@ export const isImportBlocked = (
141
135
 
142
136
  /**
143
137
  * Makes the intro for each specific import rule violation messages.
144
- * @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.
145
- * @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.
146
- * @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.
147
- * @returns Returns "[Current file 'resolved' modules] are not allowed to import [imported file 'resolved' modules]."
138
+ * @template {CurrentFileResolvedDirective} T
139
+ * @param {ResolvedDirectives_ResolvedModules} resolvedDirectives_resolvedModules The resolved modules object, either for agnostic20 or for directive21.
140
+ * @param {CurrentFileResolvedDirective} currentFileResolvedDirective The current file's "resolved" directive.
141
+ * @param {ImportedFileResolvedDirective<T>} importedFileResolvedDirective The imported file's "resolved" directive.
142
+ * @returns "[Current file 'resolved' modules] are not allowed to import [imported file 'resolved' modules]."
148
143
  */
149
144
  export const makeIntroForSpecificViolationMessage = (
150
- resolvedDirectives_ResolvedModules,
145
+ resolvedDirectives_resolvedModules,
151
146
  currentFileResolvedDirective,
152
147
  importedFileResolvedDirective
153
148
  ) =>
154
- `${resolvedDirectives_ResolvedModules[currentFileResolvedDirective]}s ${ARE_NOT_ALLOWED_TO_IMPORT} ${resolvedDirectives_ResolvedModules[importedFileResolvedDirective]}s.`;
149
+ `${resolvedDirectives_resolvedModules[currentFileResolvedDirective]}s ${ARE_NOT_ALLOWED_TO_IMPORT} ${resolvedDirectives_resolvedModules[importedFileResolvedDirective]}s.`;
155
150
 
156
151
  /* makeMessageFromResolvedDirective */
157
152
 
158
153
  /**
159
154
  * Lists in an message the "resolved" modules incompatible with a "resolved" module based on its "resolved" directive.
160
- * @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.
161
- * @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.
162
- * @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.
155
+ * @template {CurrentFileResolvedDirective} T
156
+ * @param {ResolvedDirectives_ResolvedModules} resolvedDirectives_resolvedModules The resolved modules object, either for agnostic20 or for directive21.
157
+ * @param {ResolvedDirectives_BlockedImports<T>} resolvedDirectives_blockedImports The blocked imports object, either for agnostic20 or for directive21.
158
+ * @param {T} resolvedDirective The "resolved" directive of the "resolved" module.
163
159
  * @returns The message listing the incompatible "resolved" modules.
164
160
  */
165
161
  export const makeMessageFromResolvedDirective = (
166
- resolvedDirectives_ResolvedModules,
162
+ resolvedDirectives_resolvedModules,
167
163
  resolvedDirectives_blockedImports,
168
164
  resolvedDirective
169
165
  ) => {
170
- const effectiveModule = resolvedDirectives_ResolvedModules[resolvedDirective];
166
+ const effectiveModule = resolvedDirectives_resolvedModules[resolvedDirective];
171
167
  const effectiveModulesString = effectiveModule + "s"; // plural
172
168
 
173
169
  const blockedImports =
@@ -180,7 +176,7 @@ export const makeMessageFromResolvedDirective = (
180
176
  }
181
177
 
182
178
  const blockedEffectiveModules = blockedImports.map(
183
- (e) => resolvedDirectives_ResolvedModules[e] + "s" // plural
179
+ (e) => resolvedDirectives_resolvedModules[e] + "s" // plural
184
180
  );
185
181
 
186
182
  const blockedEffectiveModulesString =
@@ -197,9 +193,10 @@ export const makeMessageFromResolvedDirective = (
197
193
 
198
194
  /**
199
195
  * Finds the `message` for the specific violation of "resolved" directives import rules based on `resolvedDirectives_blockedImports`.
200
- * @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.
201
- * @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.
202
- * @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.
196
+ * @template {CurrentFileResolvedDirective} T
197
+ * @param {ResolvedDirectives_BlockedImports<T>} resolvedDirectives_blockedImports The blocked imports object, either for agnostic20 or for directive21.
198
+ * @param {T} currentFileResolvedDirective The current file's "resolved" directive.
199
+ * @param {ImportedFileResolvedDirective<T>} importedFileResolvedDirective The imported file's "resolved" directive.
203
200
  * @returns The corresponding `message`.
204
201
  */
205
202
  export const findSpecificViolationMessage = (
@@ -6,17 +6,17 @@ import {
6
6
  USE_CLIENT_COMPONENTS as COMMONS_USE_CLIENT_COMPONENTS,
7
7
  USE_AGNOSTIC_LOGICS as COMMONS_USE_AGNOSTIC_LOGICS,
8
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,
9
+ effectiveDirectives_effectiveModules,
16
10
  } from "../../../_commons/constants/bases.js";
17
11
 
18
12
  import { makeIntroForSpecificViolationMessage as commonsMakeIntroForSpecificViolationMessage } from "../../../_commons/utilities/helpers.js";
19
13
 
14
+ /**
15
+ * @typedef {import('../../../../types/agnostic20/_commons/typedefs.js').Directive} Directive
16
+ * @typedef {import('../../../../types/agnostic20/_commons/typedefs.js').Directives} Directives
17
+ * @typedef {import('../../../../types/agnostic20/_commons/typedefs.js').EffectiveDirective} EffectiveDirective
18
+ */
19
+
20
20
  // directives
21
21
  export const NO_DIRECTIVE = null;
22
22
  export const USE_SERVER = "use server";
@@ -24,11 +24,11 @@ export const USE_CLIENT = "use client";
24
24
  export const USE_AGNOSTIC = "use agnostic";
25
25
 
26
26
  // directives array
27
- /** @type {readonly [USE_SERVER, USE_CLIENT, USE_AGNOSTIC]} */
27
+ /** @type {Directives} */
28
28
  export const directivesArray = [USE_SERVER, USE_CLIENT, USE_AGNOSTIC];
29
29
 
30
30
  // directives set
31
- /** @type {ReadonlySet<USE_SERVER | USE_CLIENT | USE_AGNOSTIC>} */
31
+ /** @type {ReadonlySet<Directive>} */
32
32
  export const directivesSet = new Set(directivesArray); // no longer used exported to satisfy static type inference
33
33
 
34
34
  // effective directives
@@ -40,24 +40,29 @@ export const USE_CLIENT_COMPONENTS = COMMONS_USE_CLIENT_COMPONENTS;
40
40
  export const USE_AGNOSTIC_LOGICS = COMMONS_USE_AGNOSTIC_LOGICS;
41
41
  export const USE_AGNOSTIC_COMPONENTS = COMMONS_USE_AGNOSTIC_COMPONENTS;
42
42
 
43
- // effective modules
44
- const SERVER_LOGICS_MODULE = COMMONS_SERVER_LOGICS_MODULE;
45
- const SERVER_COMPONENTS_MODULE = COMMONS_SERVER_COMPONENTS_MODULE;
46
- const SERVER_FUNCTIONS_MODULE = COMMONS_SERVER_FUNCTIONS_MODULE;
47
- const CLIENT_LOGICS_MODULE = COMMONS_CLIENT_LOGICS_MODULE;
48
- const CLIENT_COMPONENTS_MODULE = COMMONS_CLIENT_COMPONENTS_MODULE;
49
- const AGNOSTIC_LOGICS_MODULE = COMMONS_AGNOSTIC_LOGICS_MODULE;
50
- const AGNOSTIC_COMPONENTS_MODULE = COMMONS_AGNOSTIC_COMPONENTS_MODULE;
51
-
52
- // mapping effective directives with effective modules
53
- export const effectiveDirectives_EffectiveModules = Object.freeze({
54
- [USE_SERVER_LOGICS]: SERVER_LOGICS_MODULE,
55
- [USE_SERVER_COMPONENTS]: SERVER_COMPONENTS_MODULE,
56
- [USE_SERVER_FUNCTIONS]: SERVER_FUNCTIONS_MODULE,
57
- [USE_CLIENT_LOGICS]: CLIENT_LOGICS_MODULE,
58
- [USE_CLIENT_COMPONENTS]: CLIENT_COMPONENTS_MODULE,
59
- [USE_AGNOSTIC_LOGICS]: AGNOSTIC_LOGICS_MODULE,
60
- [USE_AGNOSTIC_COMPONENTS]: AGNOSTIC_COMPONENTS_MODULE,
43
+ // mapping directives with effective directives
44
+ /** @type {Readonly<Record<Directive | null, { logics: EffectiveDirective | null, components: EffectiveDirective | null, functions: EffectiveDirective | null }>>} */
45
+ export const directives_effectiveDirectives = Object.freeze({
46
+ [NO_DIRECTIVE]: {
47
+ logics: USE_SERVER_LOGICS,
48
+ components: USE_SERVER_COMPONENTS,
49
+ functions: null,
50
+ },
51
+ [USE_SERVER]: {
52
+ logics: null,
53
+ components: null,
54
+ functions: USE_SERVER_FUNCTIONS,
55
+ },
56
+ [USE_CLIENT]: {
57
+ logics: USE_CLIENT_LOGICS,
58
+ components: USE_CLIENT_COMPONENTS,
59
+ functions: null,
60
+ },
61
+ [USE_AGNOSTIC]: {
62
+ logics: USE_AGNOSTIC_LOGICS,
63
+ components: USE_AGNOSTIC_COMPONENTS,
64
+ functions: null,
65
+ },
61
66
  });
62
67
 
63
68
  // message placeholders
@@ -70,8 +75,8 @@ export const specificViolationMessage = "specificViolationMessage";
70
75
 
71
76
  /**
72
77
  * Makes the intro for each specific import rule violation messages.
73
- * @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.
74
- * @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
+ * @param {EffectiveDirective} currentFileEffectiveDirective The current file's effective directive.
79
+ * @param {EffectiveDirective} importedFileEffectiveDirective The imported file's effective directive.
75
80
  * @returns "[Current file effective modules] are not allowed to import [imported file effective modules]."
76
81
  */
77
82
  const makeIntroForSpecificViolationMessage = (
@@ -79,7 +84,7 @@ const makeIntroForSpecificViolationMessage = (
79
84
  importedFileEffectiveDirective
80
85
  ) =>
81
86
  commonsMakeIntroForSpecificViolationMessage(
82
- effectiveDirectives_EffectiveModules,
87
+ effectiveDirectives_effectiveModules,
83
88
  currentFileEffectiveDirective,
84
89
  importedFileEffectiveDirective
85
90
  );
@@ -87,7 +92,7 @@ const makeIntroForSpecificViolationMessage = (
87
92
  const SUGGEST_USE_AGNOSTIC =
88
93
  "If the module you're trying to import does not possess any server-side code however, please mark it with this plugin's own and eponymous 'use agnostic' directive to signal its compatibility across all environments.";
89
94
 
90
- export const effectiveDirectives_BlockedImports = Object.freeze({
95
+ export const effectiveDirectives_blockedImports = Object.freeze({
91
96
  [USE_SERVER_LOGICS]: [
92
97
  // USE_SERVER_LOGICS allowed, because Server Logics can compose with one another.
93
98
  // 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.
@@ -16,7 +16,11 @@ import {
16
16
  reExportsFlow,
17
17
  } from "../utilities/flows.js";
18
18
 
19
- /** @type {import('@typescript-eslint/utils').TSESLint.RuleModule<typeof reExportNotSameMessageId | typeof importBreaksEffectiveImportRulesMessageId | typeof useServerJSXMessageId, []>} */
19
+ /**
20
+ * @typedef {import('../../../../types/agnostic20/_commons/typedefs.js').Rule} Rule
21
+ */
22
+
23
+ /** @type {Rule} */
20
24
  const rule = {
21
25
  meta: {
22
26
  type: "problem",
@@ -5,16 +5,10 @@ import {
5
5
  useServerJSXMessageId,
6
6
  importBreaksEffectiveImportRulesMessageId,
7
7
  reExportNotSameMessageId,
8
+ skip,
8
9
  } from "../../../_commons/constants/bases.js";
9
10
  import {
10
11
  USE_SERVER,
11
- USE_SERVER_LOGICS,
12
- USE_SERVER_COMPONENTS,
13
- USE_SERVER_FUNCTIONS,
14
- USE_CLIENT_LOGICS,
15
- USE_CLIENT_COMPONENTS,
16
- USE_AGNOSTIC_LOGICS,
17
- USE_AGNOSTIC_COMPONENTS,
18
12
  // currentFileEffectiveDirective,
19
13
  // importedFileEffectiveDirective,
20
14
  effectiveDirectiveMessage,
@@ -34,14 +28,25 @@ import {
34
28
  findSpecificViolationMessage,
35
29
  } from "./helpers.js";
36
30
 
31
+ /**
32
+ * @typedef {import('../../../../types/agnostic20/_commons/typedefs.js').Context} Context
33
+ * @typedef {import('../../../../types/agnostic20/_commons/typedefs.js').EffectiveDirective} EffectiveDirective
34
+ * @typedef {import('../../../../types/agnostic20/_commons/typedefs.js').ImportDeclaration} ImportDeclaration
35
+ * @typedef {import('../../../../types/agnostic20/_commons/typedefs.js').ExportNamedDeclaration} ExportNamedDeclaration
36
+ * @typedef {import('../../../../types/agnostic20/_commons/typedefs.js').ExportAllDeclaration} ExportAllDeclaration
37
+ */
38
+
37
39
  /* currentFileFlow */
38
40
 
41
+ // {{skip: true; currentFileEffectiveDirective: undefined;} | {skip: undefined; currentFileEffectiveDirective: EffectiveDirective;}}
39
42
  /**
40
43
  * 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.
41
- * @param {Readonly<import('@typescript-eslint/utils').TSESLint.RuleContext<typeof reExportNotSameMessageId | typeof importBreaksEffectiveImportRulesMessageId | typeof useServerJSXMessageId, []>>} context The ESLint rule's `context` object.
42
- * @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;}} Either an object with `skip: true` to disregard or one with the non-null `currentFileEffectiveDirective`.
44
+ * @param {Context} context The ESLint rule's `context` object.
45
+ * @returns Either an object with `skip: true` to disregard or one with the non-null `currentFileEffectiveDirective`.
43
46
  */
44
47
  export const currentFileFlow = (context) => {
48
+ const skipTrue = { ...skip, currentFileEffectiveDirective: undefined };
49
+
45
50
  // GETTING THE EXTENSION OF THE CURRENT FILE
46
51
  const currentFileExtension = path.extname(context.filename);
47
52
 
@@ -53,7 +58,7 @@ export const currentFileFlow = (context) => {
53
58
  console.error(
54
59
  "ERROR. Linted files for this rule should only be in JavaScript (TypeScript)."
55
60
  );
56
- return { skip: true };
61
+ return skipTrue;
57
62
  }
58
63
 
59
64
  /* GETTING THE DIRECTIVE (or lack thereof) OF THE CURRENT FILE */
@@ -68,7 +73,7 @@ export const currentFileFlow = (context) => {
68
73
  loc: highlightFirstLineOfCode(context),
69
74
  messageId: useServerJSXMessageId,
70
75
  });
71
- return { skip: true };
76
+ return skipTrue;
72
77
  }
73
78
 
74
79
  // GETTING THE EFFECTIVE DIRECTIVE OF THE CURRENT FILE
@@ -80,21 +85,24 @@ export const currentFileFlow = (context) => {
80
85
  // fails if one of the seven effective directives has not been obtained
81
86
  if (currentFileEffectiveDirective === null) {
82
87
  console.error("ERROR. Effective directive should never be null.");
83
- return { skip: true };
88
+ return skipTrue;
84
89
  }
85
90
 
86
- return { currentFileEffectiveDirective };
91
+ return { skip: undefined, currentFileEffectiveDirective };
87
92
  };
88
93
 
89
94
  /* importedFileFlow */
90
95
 
96
+ // {{skip: true; importedFileEffectiveDirective: undefined;} | {skip: undefined; importedFileEffectiveDirective: EffectiveDirective;}}
91
97
  /**
92
98
  * The flow that is shared between import and re-export traversals to obtain the import file's effective directive.
93
- * @param {Readonly<import('@typescript-eslint/utils').TSESLint.RuleContext<typeof reExportNotSameMessageId | typeof importBreaksEffectiveImportRulesMessageId | typeof useServerJSXMessageId, []>>} context The ESLint rule's `context` object.
94
- * @param {import('@typescript-eslint/types').TSESTree.ImportDeclaration} node The ESLint `node` of the rule's current traversal.
95
- * @returns {{skip: true; importedFileEffectiveDirective: 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;}} Either an object with `skip: true` to disregard or one with the non-null `importedFileEffectiveDirective`.
99
+ * @param {Context} context The ESLint rule's `context` object.
100
+ * @param {ImportDeclaration} node The ESLint `node` of the rule's current traversal.
101
+ * @returns Either an object with `skip: true` to disregard or one with the non-null `importedFileEffectiveDirective`.
96
102
  */
97
103
  const importedFileFlow = (context, node) => {
104
+ const skipTrue = { ...skip, importedFileEffectiveDirective: undefined };
105
+
98
106
  // finds the full path of the import
99
107
  const resolvedImportPath = resolveImportPath(
100
108
  path.dirname(context.filename),
@@ -103,12 +111,12 @@ const importedFileFlow = (context, node) => {
103
111
  );
104
112
 
105
113
  // does not operate on paths it did not resolve
106
- if (resolvedImportPath === null) return { skip: true };
114
+ if (resolvedImportPath === null) return skipTrue;
107
115
  // does not operate on non-JS files
108
116
  const isImportedFileJS = EXTENSIONS.some((ext) =>
109
117
  resolvedImportPath.endsWith(ext)
110
118
  );
111
- if (!isImportedFileJS) return { skip: true };
119
+ if (!isImportedFileJS) return skipTrue;
112
120
 
113
121
  /* GETTING THE DIRECTIVE (or lack thereof) OF THE IMPORTED FILE */
114
122
  const importedFileDirective =
@@ -124,20 +132,20 @@ const importedFileFlow = (context, node) => {
124
132
  // also fails if one of the seven effective directives has not been obtained
125
133
  if (importedFileEffectiveDirective === null) {
126
134
  console.error("ERROR. Effective directive should never be null.");
127
- return { skip: true };
135
+ return skipTrue;
128
136
  }
129
137
 
130
138
  // For now skipping on both "does not operate" (which should ignore) and "fails" albeit with console.error (which should crash).
131
139
 
132
- return { importedFileEffectiveDirective };
140
+ return { skip: undefined, importedFileEffectiveDirective };
133
141
  };
134
142
 
135
143
  /* importsFlow */
136
144
 
137
145
  /** The full flow for import traversals to enforce effective directives import rules.
138
- * @param {Readonly<import('@typescript-eslint/utils').TSESLint.RuleContext<typeof reExportNotSameMessageId | typeof importBreaksEffectiveImportRulesMessageId | typeof useServerJSXMessageId, []>>} context The ESLint rule's `context` object.
139
- * @param {import('@typescript-eslint/types').TSESTree.ImportDeclaration} node The ESLint `node` of the rule's current traversal.
140
- * @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.
146
+ * @param {Context} context The ESLint rule's `context` object.
147
+ * @param {ImportDeclaration} node The ESLint `node` of the rule's current traversal.
148
+ * @param {EffectiveDirective} currentFileEffectiveDirective The current file's effective directive.
141
149
  * @returns Early if the flow needs to be interrupted.
142
150
  */
143
151
  export const importsFlow = (context, node, currentFileEffectiveDirective) => {
@@ -174,9 +182,9 @@ export const importsFlow = (context, node, currentFileEffectiveDirective) => {
174
182
  /* reExportsFlow */
175
183
 
176
184
  /** The full flow for export traversals, shared between `ExportNamedDeclaration` and `ExportAllDeclaration`, to ensure same effective directive re-exports.
177
- * @param {Readonly<import('@typescript-eslint/utils').TSESLint.RuleContext<typeof reExportNotSameMessageId | typeof importBreaksEffectiveImportRulesMessageId | typeof useServerJSXMessageId, []>>} context The ESLint rule's `context` object.
178
- * @param {import('@typescript-eslint/types').TSESTree.ExportNamedDeclaration | import('@typescript-eslint/types').TSESTree.ExportAllDeclaration} node The ESLint `node` of the rule's current traversal.
179
- * @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.
185
+ * @param {Context} context The ESLint rule's `context` object.
186
+ * @param {ExportNamedDeclaration | ExportAllDeclaration} node The ESLint `node` of the rule's current traversal.
187
+ * @param {EffectiveDirective} currentFileEffectiveDirective The current file's effective directive.
180
188
  * @returns Early if the flow needs to be interrupted.
181
189
  */
182
190
  export const reExportsFlow = (context, node, currentFileEffectiveDirective) => {