eslint-plugin-use-agnostic 0.9.7 → 0.9.8

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
@@ -10,7 +10,7 @@
10
10
  npm install eslint@^9.0.0 eslint-plugin-use-agnostic --save-dev
11
11
  ```
12
12
 
13
- ## Setup (using TypeScript and the Flat Config)
13
+ ## Setup
14
14
 
15
15
  ```js
16
16
  // eslint.config.js
@@ -20,13 +20,20 @@ import { defineConfig, globalIgnores } from "eslint/config";
20
20
  import useAgnostic, {
21
21
  useAgnosticPluginName,
22
22
  agnostic20ConfigName,
23
+ // enforceEffectiveDirectivesRuleName
23
24
  } from "eslint-plugin-use-agnostic";
24
25
 
25
26
  export default defineConfig([
26
27
  globalIgnores([".next", ".react-router", "node_modules"]),
27
28
  {
28
- // files: ['**/*.js', '**/*.jsx'], // if you're using vanilla JavaScript
29
- files: ["**/*.ts", "**/*.tsx"],
29
+ files: [
30
+ "**/*.tsx",
31
+ "**/*.ts",
32
+ "**/*.jsx",
33
+ "**/*.js",
34
+ "**/*.mjs",
35
+ "**/*.cjs",
36
+ ],
30
37
  plugins: {
31
38
  [useAgnosticPluginName]: useAgnostic,
32
39
  },
@@ -104,7 +104,6 @@ export const MJS = ".mjs";
104
104
  export const CJS = ".cjs";
105
105
 
106
106
  // JavaScript/TypeScript extensions array
107
- // /** @type {readonly [TSX, TS, JSX, JS, MJS, CJS]} */
108
107
  /** @type {Extensions} */
109
108
  export const EXTENSIONS = [TSX, TS, JSX, JS, MJS, CJS]; // In priority order
110
109
 
@@ -6,7 +6,6 @@ import { loadConfig, createMatchPath } from "tsconfig-paths";
6
6
  import { EXTENSIONS, ARE_NOT_ALLOWED_TO_IMPORT } from "../constants/bases.js";
7
7
 
8
8
  /**
9
- * @typedef {import('../../../types/_commons/typedefs').ResolvedDirective} ResolvedDirective
10
9
  * @typedef {import('../../../types/_commons/typedefs').ResolvedDirectives_ResolvedModules} ResolvedDirectives_ResolvedModules
11
10
  * @typedef {import('../../../types/_commons/typedefs').CurrentFileResolvedDirective} CurrentFileResolvedDirective
12
11
  * @typedef {import('../../../types/_commons/typedefs').Context<string, readonly unknown[]>} Context
@@ -148,26 +147,27 @@ export const makeIntroForSpecificViolationMessage = (
148
147
  ) =>
149
148
  `${resolvedDirectives_resolvedModules[currentFileResolvedDirective]}s ${ARE_NOT_ALLOWED_TO_IMPORT} ${resolvedDirectives_resolvedModules[importedFileResolvedDirective]}s.`;
150
149
 
151
- /* makeMessageFromResolvedDirective */
150
+ /* makeMessageFromCurrentFileResolvedDirective */
152
151
 
153
152
  /**
154
153
  * Lists in an message the "resolved" modules incompatible with a "resolved" module based on its "resolved" directive.
155
154
  * @template {CurrentFileResolvedDirective} T
156
155
  * @param {ResolvedDirectives_ResolvedModules} resolvedDirectives_resolvedModules The resolved modules object, either for agnostic20 or for directive21.
157
156
  * @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.
157
+ * @param {T} currentFileResolvedDirective The "resolved" directive of the "resolved" module.
159
158
  * @returns The message listing the incompatible "resolved" modules.
160
159
  */
161
- export const makeMessageFromResolvedDirective = (
160
+ export const makeMessageFromCurrentFileResolvedDirective = (
162
161
  resolvedDirectives_resolvedModules,
163
162
  resolvedDirectives_blockedImports,
164
- resolvedDirective
163
+ currentFileResolvedDirective
165
164
  ) => {
166
- const effectiveModule = resolvedDirectives_resolvedModules[resolvedDirective];
165
+ const effectiveModule =
166
+ resolvedDirectives_resolvedModules[currentFileResolvedDirective];
167
167
  const effectiveModulesString = effectiveModule + "s"; // plural
168
168
 
169
169
  const blockedImports =
170
- resolvedDirectives_blockedImports[resolvedDirective].map(
170
+ resolvedDirectives_blockedImports[currentFileResolvedDirective].map(
171
171
  (e) => e.blockedImport
172
172
  ) || [];
173
173
 
@@ -15,10 +15,11 @@ import { makeIntroForSpecificViolationMessage as commonsMakeIntroForSpecificViol
15
15
  * @typedef {import('../../../../types/agnostic20/_commons/typedefs.js').Directive} Directive
16
16
  * @typedef {import('../../../../types/agnostic20/_commons/typedefs.js').Directives} Directives
17
17
  * @typedef {import('../../../../types/agnostic20/_commons/typedefs.js').EffectiveDirective} EffectiveDirective
18
+ * @typedef {import('../../../../types/agnostic20/_commons/typedefs.js').Directives_EffectiveDirectives} Directives_EffectiveDirectives
18
19
  */
19
20
 
20
21
  // directives
21
- export const NO_DIRECTIVE = null;
22
+ export const NO_DIRECTIVE = "no directive";
22
23
  export const USE_SERVER = "use server";
23
24
  export const USE_CLIENT = "use client";
24
25
  export const USE_AGNOSTIC = "use agnostic";
@@ -40,28 +41,33 @@ export const USE_CLIENT_COMPONENTS = COMMONS_USE_CLIENT_COMPONENTS;
40
41
  export const USE_AGNOSTIC_LOGICS = COMMONS_USE_AGNOSTIC_LOGICS;
41
42
  export const USE_AGNOSTIC_COMPONENTS = COMMONS_USE_AGNOSTIC_COMPONENTS;
42
43
 
44
+ // module kinds
45
+ export const LOGICS = "logics";
46
+ export const COMPONENTS = "components";
47
+ export const FUNCTIONS = "functions";
48
+
43
49
  // mapping directives with effective directives
44
- /** @type {Readonly<Record<Directive | null, { logics: EffectiveDirective | null, components: EffectiveDirective | null, functions: EffectiveDirective | null }>>} */
50
+ /** @type {Directives_EffectiveDirectives} */
45
51
  export const directives_effectiveDirectives = Object.freeze({
46
52
  [NO_DIRECTIVE]: {
47
- logics: USE_SERVER_LOGICS,
48
- components: USE_SERVER_COMPONENTS,
49
- functions: null,
53
+ [LOGICS]: USE_SERVER_LOGICS,
54
+ [COMPONENTS]: USE_SERVER_COMPONENTS,
55
+ [FUNCTIONS]: null,
50
56
  },
51
57
  [USE_SERVER]: {
52
- logics: null,
53
- components: null,
54
- functions: USE_SERVER_FUNCTIONS,
58
+ [LOGICS]: null,
59
+ [COMPONENTS]: null,
60
+ [FUNCTIONS]: USE_SERVER_FUNCTIONS,
55
61
  },
56
62
  [USE_CLIENT]: {
57
- logics: USE_CLIENT_LOGICS,
58
- components: USE_CLIENT_COMPONENTS,
59
- functions: null,
63
+ [LOGICS]: USE_CLIENT_LOGICS,
64
+ [COMPONENTS]: USE_CLIENT_COMPONENTS,
65
+ [FUNCTIONS]: null,
60
66
  },
61
67
  [USE_AGNOSTIC]: {
62
- logics: USE_AGNOSTIC_LOGICS,
63
- components: USE_AGNOSTIC_COMPONENTS,
64
- functions: null,
68
+ [LOGICS]: USE_AGNOSTIC_LOGICS,
69
+ [COMPONENTS]: USE_AGNOSTIC_COMPONENTS,
70
+ [FUNCTIONS]: null,
65
71
  },
66
72
  });
67
73
 
@@ -8,6 +8,7 @@ import {
8
8
  skip,
9
9
  } from "../../../_commons/constants/bases.js";
10
10
  import {
11
+ NO_DIRECTIVE,
11
12
  USE_SERVER,
12
13
  // currentFileEffectiveDirective,
13
14
  // importedFileEffectiveDirective,
@@ -24,7 +25,7 @@ import {
24
25
  getDirectiveFromImportedModule,
25
26
  getEffectiveDirective,
26
27
  isImportBlocked,
27
- makeMessageFromEffectiveDirective,
28
+ makeMessageFromCurrentFileEffectiveDirective,
28
29
  findSpecificViolationMessage,
29
30
  } from "./helpers.js";
30
31
 
@@ -38,7 +39,6 @@ import {
38
39
 
39
40
  /* currentFileFlow */
40
41
 
41
- // {{skip: true; currentFileEffectiveDirective: undefined;} | {skip: undefined; currentFileEffectiveDirective: EffectiveDirective;}}
42
42
  /**
43
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.
44
44
  * @param {Context} context The ESLint rule's `context` object.
@@ -61,8 +61,9 @@ export const currentFileFlow = (context) => {
61
61
  return skipTrue;
62
62
  }
63
63
 
64
- /* GETTING THE DIRECTIVE (or lack thereof) OF THE CURRENT FILE */
65
- const currentFileDirective = getDirectiveFromCurrentModule(context);
64
+ // GETTING THE DIRECTIVE (or lack thereof) OF THE CURRENT FILE
65
+ const currentFileDirective =
66
+ getDirectiveFromCurrentModule(context) ?? NO_DIRECTIVE;
66
67
 
67
68
  // reports if a file marked "use server" has a JSX extension
68
69
  if (
@@ -76,7 +77,7 @@ export const currentFileFlow = (context) => {
76
77
  return skipTrue;
77
78
  }
78
79
 
79
- // GETTING THE EFFECTIVE DIRECTIVE OF THE CURRENT FILE
80
+ // GETTING THE EFFECTIVE DIRECTIVE (no lack thereof) OF THE CURRENT FILE
80
81
  const currentFileEffectiveDirective = getEffectiveDirective(
81
82
  currentFileDirective,
82
83
  currentFileExtension
@@ -93,7 +94,6 @@ export const currentFileFlow = (context) => {
93
94
 
94
95
  /* importedFileFlow */
95
96
 
96
- // {{skip: true; importedFileEffectiveDirective: undefined;} | {skip: undefined; importedFileEffectiveDirective: EffectiveDirective;}}
97
97
  /**
98
98
  * The flow that is shared between import and re-export traversals to obtain the import file's effective directive.
99
99
  * @param {Context} context The ESLint rule's `context` object.
@@ -118,12 +118,14 @@ const importedFileFlow = (context, node) => {
118
118
  );
119
119
  if (!isImportedFileJS) return skipTrue;
120
120
 
121
- /* GETTING THE DIRECTIVE (or lack thereof) OF THE IMPORTED FILE */
121
+ // GETTING THE DIRECTIVE (or lack thereof) OF THE IMPORTED FILE
122
122
  const importedFileDirective =
123
- getDirectiveFromImportedModule(resolvedImportPath);
123
+ getDirectiveFromImportedModule(resolvedImportPath) ?? NO_DIRECTIVE;
124
+
124
125
  // GETTING THE EXTENSION OF THE IMPORTED FILE
125
126
  const importedFileFileExtension = path.extname(resolvedImportPath);
126
- // GETTING THE EFFECTIVE DIRECTIVE OF THE IMPORTED FILE
127
+
128
+ // GETTING THE EFFECTIVE DIRECTIVE (no lack thereof) OF THE IMPORTED FILE
127
129
  const importedFileEffectiveDirective = getEffectiveDirective(
128
130
  importedFileDirective,
129
131
  importedFileFileExtension
@@ -135,7 +137,7 @@ const importedFileFlow = (context, node) => {
135
137
  return skipTrue;
136
138
  }
137
139
 
138
- // For now skipping on both "does not operate" (which should ignore) and "fails" albeit with console.error (which should crash).
140
+ // For now skipping on both "does not operate" (which should ignore) and "fails" (which should crash) albeit with console.error.
139
141
 
140
142
  return { skip: undefined, importedFileEffectiveDirective };
141
143
  };
@@ -167,9 +169,10 @@ export const importsFlow = (context, node, currentFileEffectiveDirective) => {
167
169
  node,
168
170
  messageId: importBreaksEffectiveImportRulesMessageId,
169
171
  data: {
170
- [effectiveDirectiveMessage]: makeMessageFromEffectiveDirective(
171
- currentFileEffectiveDirective
172
- ),
172
+ [effectiveDirectiveMessage]:
173
+ makeMessageFromCurrentFileEffectiveDirective(
174
+ currentFileEffectiveDirective
175
+ ),
173
176
  [specificViolationMessage]: findSpecificViolationMessage(
174
177
  currentFileEffectiveDirective,
175
178
  importedFileEffectiveDirective
@@ -1,15 +1,9 @@
1
1
  import { effectiveDirectives_effectiveModules } from "../../../_commons/constants/bases.js";
2
2
  import {
3
3
  USE_SERVER,
4
- USE_CLIENT,
5
- USE_AGNOSTIC,
6
- USE_SERVER_LOGICS,
7
- USE_SERVER_COMPONENTS,
8
- USE_SERVER_FUNCTIONS,
9
- USE_CLIENT_LOGICS,
10
- USE_CLIENT_COMPONENTS,
11
- USE_AGNOSTIC_LOGICS,
12
- USE_AGNOSTIC_COMPONENTS,
4
+ LOGICS,
5
+ COMPONENTS,
6
+ FUNCTIONS,
13
7
  directivesArray,
14
8
  directives_effectiveDirectives,
15
9
  effectiveDirectives_blockedImports,
@@ -18,13 +12,14 @@ import {
18
12
  import {
19
13
  getImportedFileFirstLine,
20
14
  isImportBlocked as commonsIsImportBlocked,
21
- makeMessageFromResolvedDirective,
15
+ makeMessageFromCurrentFileResolvedDirective,
22
16
  findSpecificViolationMessage as commonsFindSpecificViolationMessage,
23
17
  } from "../../../_commons/utilities/helpers.js";
24
18
 
25
19
  /**
26
20
  * @typedef {import('../../../../types/agnostic20/_commons/typedefs.js').Context} Context
27
21
  * @typedef {import('../../../../types/agnostic20/_commons/typedefs.js').Directive} Directive
22
+ * @typedef {import('../../../../types/agnostic20/_commons/typedefs.js').NoDirective} NoDirective
28
23
  * @typedef {import('../../../../types/agnostic20/_commons/typedefs.js').Extension} Extension
29
24
  * @typedef {import('../../../../types/agnostic20/_commons/typedefs.js').EffectiveDirective} EffectiveDirective
30
25
  */
@@ -75,44 +70,18 @@ export const getDirectiveFromCurrentModule = (context) => {
75
70
  * - `'use client components'` denotes a Client Components Module.
76
71
  * - `'use agnostic logics'` denotes an Agnostic Logics Module.
77
72
  * - `'use agnostic components'` denotes an Agnostic Components Module.
78
- * @param {Directive | null} directive The directive as written on top of the file (`null` if no valid directive).
73
+ * @param {Directive | NoDirective} directive The directive as written on top of the file (`"no directive"` if no valid directive).
79
74
  * @param {Extension} extension The JavaScript (TypeScript) extension of the file.
80
75
  * @returns The effective directive, from which imports rules are applied.
81
76
  */
82
77
  export const getEffectiveDirective = (directive, extension) => {
83
- // I could use a map, but because this is in JS with JSDoc, a manual solution is peculiarly more typesafe.
84
- if (directive === null && !extension.endsWith("x")) return USE_SERVER_LOGICS;
85
- if (directive === null && extension.endsWith("x"))
86
- return USE_SERVER_COMPONENTS;
87
- if (directive === USE_SERVER && !extension.endsWith("x"))
88
- return USE_SERVER_FUNCTIONS;
89
- if (directive === USE_CLIENT && !extension.endsWith("x"))
90
- return USE_CLIENT_LOGICS;
91
- if (directive === USE_CLIENT && extension.endsWith("x"))
92
- return USE_CLIENT_COMPONENTS;
93
- if (directive === USE_AGNOSTIC && !extension.endsWith("x"))
94
- return USE_AGNOSTIC_LOGICS;
95
- if (directive === USE_AGNOSTIC && extension.endsWith("x"))
96
- return USE_AGNOSTIC_COMPONENTS;
97
-
98
- return null; // default error, should be unreachable
99
- };
100
- // directives_effectiveDirectives
101
- /**
102
- * @param {Directive | null} directive
103
- * @param {Extension} extension
104
- * @returns
105
- */
106
- export const trueGetEffectiveDirective = (directive, extension) => {
107
- const type = extension.endsWith("x")
108
- ? "components"
78
+ const moduleKind = extension.endsWith("x")
79
+ ? COMPONENTS
109
80
  : directive === USE_SERVER
110
- ? "functions"
111
- : "logics";
81
+ ? FUNCTIONS
82
+ : LOGICS;
112
83
 
113
- const a = directives_effectiveDirectives[directive];
114
-
115
- return directives_effectiveDirectives[directive]?.[type] ?? null;
84
+ return directives_effectiveDirectives[directive][moduleKind];
116
85
  };
117
86
 
118
87
  /* getDirectiveFromImportedModule */
@@ -165,15 +134,17 @@ export const isImportBlocked = (
165
134
  importedFileEffectiveDirective
166
135
  );
167
136
 
168
- /* makeMessageFromEffectiveDirective */
137
+ /* makeMessageFromCurrentFileEffectiveDirective */
169
138
 
170
139
  /**
171
140
  * Lists in an message the effective modules incompatible with an effective module based on its effective directive.
172
141
  * @param {EffectiveDirective} effectiveDirective The effective directive of the effective module.
173
142
  * @returns The message listing the incompatible effective modules.
174
143
  */
175
- export const makeMessageFromEffectiveDirective = (effectiveDirective) =>
176
- makeMessageFromResolvedDirective(
144
+ export const makeMessageFromCurrentFileEffectiveDirective = (
145
+ effectiveDirective
146
+ ) =>
147
+ makeMessageFromCurrentFileResolvedDirective(
177
148
  effectiveDirectives_effectiveModules,
178
149
  effectiveDirectives_blockedImports,
179
150
  effectiveDirective
@@ -36,7 +36,7 @@ export const USE_AGNOSTIC_STRATEGIES = COMMONS_USE_AGNOSTIC_STRATEGIES;
36
36
 
37
37
  // commented directives array
38
38
  /** @type {CommentedDirectives} */
39
- export const directivesArray = [
39
+ export const commentedDirectivesArray = [
40
40
  USE_SERVER_LOGICS,
41
41
  USE_CLIENT_LOGICS,
42
42
  USE_AGNOSTIC_LOGICS,
@@ -51,7 +51,21 @@ export const directivesArray = [
51
51
 
52
52
  // commented directives set
53
53
  /** @type {ReadonlySet<CommentedDirective>} */
54
- export const directivesSet = new Set(directivesArray); // no longer used exported to satisfy static type inference
54
+ export const commentedDirectivesSet = new Set(commentedDirectivesArray); // no longer used exported to satisfy static type inference
55
+
56
+ // mapped commented directives to their extension rules
57
+ export const commentedDirectives_extensionRules = {
58
+ [USE_SERVER_LOGICS]: false, // Must not end with 'x'
59
+ [USE_CLIENT_LOGICS]: false,
60
+ [USE_AGNOSTIC_LOGICS]: false,
61
+ [USE_SERVER_COMPONENTS]: true, // Must end with 'x'
62
+ [USE_CLIENT_COMPONENTS]: true,
63
+ [USE_AGNOSTIC_COMPONENTS]: true,
64
+ [USE_SERVER_FUNCTIONS]: false,
65
+ [USE_CLIENT_CONTEXTS]: true,
66
+ [USE_AGNOSTIC_CONDITIONS]: true,
67
+ [USE_AGNOSTIC_STRATEGIES]: null, // Any extension allowed
68
+ };
55
69
 
56
70
  // commented strategies
57
71
  export const AT_SERVER_LOGICS = "@serverLogics";
@@ -145,7 +159,6 @@ const _DIRECTIVE_MUST_HAVE_A_JSX_FILE_EXTENSION =
145
159
  "directive must have a JSX file extension";
146
160
 
147
161
  export const commentedDirectives_verificationReports = Object.freeze({
148
- // somehow doing it by hand is better for type inference in raw JS
149
162
  [USE_SERVER_LOGICS]: `${MODULES_MARKED_WITH_THE_} "${USE_SERVER_LOGICS}" ${_DIRECTIVE_MUST_HAVE_A_NON_JSX_FILE_EXTENSION}.`,
150
163
  [USE_CLIENT_LOGICS]: `${MODULES_MARKED_WITH_THE_} "${USE_CLIENT_LOGICS}" ${_DIRECTIVE_MUST_HAVE_A_NON_JSX_FILE_EXTENSION}.`,
151
164
  [USE_AGNOSTIC_LOGICS]: `${MODULES_MARKED_WITH_THE_} "${USE_AGNOSTIC_LOGICS}" ${_DIRECTIVE_MUST_HAVE_A_NON_JSX_FILE_EXTENSION}.`,
@@ -28,7 +28,7 @@ import {
28
28
  getVerifiedCommentedDirective,
29
29
  getCommentedDirectiveFromImportedModule,
30
30
  isImportBlocked,
31
- makeMessageFromCommentedDirective,
31
+ makeMessageFromCurrentFileCommentedDirective,
32
32
  findSpecificViolationMessage,
33
33
  getStrategizedDirective,
34
34
  addressDirectiveIfAgnosticStrategies,
@@ -53,7 +53,7 @@ import {
53
53
  export const currentFileFlow = (context) => {
54
54
  const skipTrue = { ...skip, verifiedCommentedDirective: undefined };
55
55
 
56
- // GETTING THE EXTENSION OF THE CURRENT FILE
56
+ // gets the extension of the current file
57
57
  const currentFileExtension = path.extname(context.filename);
58
58
 
59
59
  // fails if the file is not JavaScript (TypeScript)
@@ -79,6 +79,7 @@ export const currentFileFlow = (context) => {
79
79
  return skipTrue;
80
80
  }
81
81
 
82
+ // verifies the commented directive from the current file
82
83
  const verifiedCommentedDirective = getVerifiedCommentedDirective(
83
84
  commentedDirective,
84
85
  currentFileExtension
@@ -126,7 +127,7 @@ const importedFileFlow = (context, node) => {
126
127
  );
127
128
  if (!isImportedFileJS) return skipTrue;
128
129
 
129
- /* GETTING THE DIRECTIVE (or lack thereof) OF THE IMPORTED FILE */
130
+ // GETTING THE DIRECTIVE (or lack thereof) OF THE IMPORTED FILE
130
131
  let importedFileCommentedDirective =
131
132
  getCommentedDirectiveFromImportedModule(resolvedImportPath);
132
133
 
@@ -141,19 +142,17 @@ const importedFileFlow = (context, node) => {
141
142
  /* GETTING THE CORRECT DIRECTIVE INTERPRETATION OF STRATEGY FOR AGNOSTIC STRATEGIES MODULES IMPORTS.
142
143
  The Directive-First Architecture does not check whether the export and import Strategies are the same at this time, meaning an @clientLogics strategy could be wrongly imported and interpreted as an @serverLogics strategy.
143
144
 
144
- After a short attempt, this feature is currently canceled, mainly since the amount of work it will require will not be able to be transferred in a future where commented strategies will actually be real syntax.
145
+ After a short attempt, the feature to address this (crossingStrategies) is currently canceled, mainly since the amount of work it will require will not be able to be transferred in a future where commented strategies will actually be real syntax.
145
146
 
146
147
  (Consequently, details below are currently at the stage of wishful thinking.)
147
148
  Strategy exports are planned to be linting in the future within their own Agnostic Strategies Modules to ensure they respect import rules within their own scopes. It may also become possible to check whether the export and import Strategies are the same in the future when identifiers are defined and the same, especially for components modules where a convention could be for all non-type exports to be named and PascalCase. */
149
+
148
150
  if (importedFileCommentedDirective === USE_AGNOSTIC_STRATEGIES) {
149
151
  const importingFileCommentedDirective = getStrategizedDirective(
150
152
  context,
151
153
  node
152
154
  );
153
155
 
154
- // FOR NOW, we consider the importingFileCommentedDirective (which is strategized) and the importedFileCommentedDirective (which should be strategized on its own imported file) to be same, given the limitation highlighted above.
155
- importedFileCommentedDirective = importingFileCommentedDirective;
156
-
157
156
  if (importingFileCommentedDirective === null) {
158
157
  context.report({
159
158
  node,
@@ -161,6 +160,9 @@ const importedFileFlow = (context, node) => {
161
160
  });
162
161
  return skipTrue;
163
162
  }
163
+
164
+ // FOR NOW, we consider the importingFileCommentedDirective (which is strategized) and the importedFileCommentedDirective (which should be strategized on its own imported file) to be same, given the limitation highlighted above.
165
+ importedFileCommentedDirective = importingFileCommentedDirective;
164
166
  }
165
167
 
166
168
  return { skip: undefined, importedFileCommentedDirective };
@@ -194,9 +196,10 @@ export const importsFlow = (context, node, currentFileCommentedDirective) => {
194
196
  node,
195
197
  messageId: importBreaksCommentedImportRulesMessageId,
196
198
  data: {
197
- [commentedDirectiveMessage]: makeMessageFromCommentedDirective(
198
- currentFileCommentedDirective
199
- ),
199
+ [commentedDirectiveMessage]:
200
+ makeMessageFromCurrentFileCommentedDirective(
201
+ currentFileCommentedDirective
202
+ ),
200
203
  [specificViolationMessage]: findSpecificViolationMessage(
201
204
  currentFileCommentedDirective,
202
205
  importedFileCommentedDirective
@@ -244,7 +247,9 @@ export const allExportsFlow = (
244
247
  currentFileCommentedDirective
245
248
  );
246
249
 
250
+ // returns early if an address has been made
247
251
  if (!addressedDirective) return;
252
+ // moves on to the re-export check otherwise
248
253
  else currentFileCommentedDirective = addressedDirective;
249
254
 
250
255
  if (currentFileCommentedDirective !== importedFileCommentedDirective) {
@@ -3,18 +3,11 @@ import {
3
3
  commentedDirectives_commentedModules,
4
4
  } from "../../../_commons/constants/bases.js";
5
5
  import {
6
- USE_SERVER_LOGICS,
7
- USE_CLIENT_LOGICS,
8
6
  USE_AGNOSTIC_LOGICS,
9
- USE_SERVER_COMPONENTS,
10
- USE_CLIENT_COMPONENTS,
11
- USE_AGNOSTIC_COMPONENTS,
12
- USE_SERVER_FUNCTIONS,
13
- USE_CLIENT_CONTEXTS,
14
- USE_AGNOSTIC_CONDITIONS,
15
7
  USE_AGNOSTIC_STRATEGIES,
16
- directivesArray,
8
+ commentedDirectivesArray,
17
9
  strategiesArray,
10
+ commentedDirectives_extensionRules,
18
11
  commentedDirectives_4RawImplementations,
19
12
  commentedStrategies_commentedDirectives,
20
13
  commentedDirectives_blockedImports,
@@ -23,7 +16,7 @@ import {
23
16
  import {
24
17
  getImportedFileFirstLine,
25
18
  isImportBlocked as commonsIsImportBlocked,
26
- makeMessageFromResolvedDirective,
19
+ makeMessageFromCurrentFileResolvedDirective,
27
20
  findSpecificViolationMessage as commonsFindSpecificViolationMessage,
28
21
  } from "../../../_commons/utilities/helpers.js";
29
22
 
@@ -124,7 +117,7 @@ export const getCommentedDirectiveFromCurrentModule = (context) => {
124
117
 
125
118
  // certifies the directive or lack thereof from the obtained value
126
119
  const commentedDirective =
127
- directivesArray.find((directive) => directive === value) ?? null;
120
+ commentedDirectivesArray.find((directive) => directive === value) ?? null;
128
121
 
129
122
  return commentedDirective;
130
123
  };
@@ -145,31 +138,17 @@ export const getCommentedDirectiveFromCurrentModule = (context) => {
145
138
  * - `'use agnostic strategies'`: Agnostic Strategies Modules may export JSX.
146
139
  * @param {CommentedDirective} directive The commented directive as written on top of the file (cannot be `null` at that stage).
147
140
  * @param {Extension} extension The JavaScript (TypeScript) extension of the file.
148
- * @returns The verified commented directive, from which imports rules are applied. Returns `null` if the verification failed, upon which an error will be reported depending on the commented directive, since the error logic here is strictly binary.
141
+ * @returns {CommentedDirective | null} The verified commented directive, from which imports rules are applied. Returns `null` if the verification failed, upon which an error will be reported depending on the commented directive, since the error logic here is strictly binary.
149
142
  */
150
143
  export const getVerifiedCommentedDirective = (directive, extension) => {
151
- // I could use a map, but because this is in JS with JSDoc, a manual solution is peculiarly more typesafe.
152
- if (directive === USE_SERVER_LOGICS && !extension.endsWith("x"))
153
- return directive;
154
- if (directive === USE_CLIENT_LOGICS && !extension.endsWith("x"))
155
- return directive;
156
- if (directive === USE_AGNOSTIC_LOGICS && !extension.endsWith("x"))
157
- return directive;
158
- if (directive === USE_SERVER_COMPONENTS && extension.endsWith("x"))
159
- return directive;
160
- if (directive === USE_CLIENT_COMPONENTS && extension.endsWith("x"))
161
- return directive;
162
- if (directive === USE_AGNOSTIC_COMPONENTS && extension.endsWith("x"))
163
- return directive;
164
- if (directive === USE_SERVER_FUNCTIONS && !extension.endsWith("x"))
165
- return directive;
166
- if (directive === USE_CLIENT_CONTEXTS && extension.endsWith("x"))
167
- return directive;
168
- if (directive === USE_AGNOSTIC_CONDITIONS && extension.endsWith("x"))
169
- return directive;
170
- if (directive === USE_AGNOSTIC_STRATEGIES) return directive;
171
-
172
- return null; // verification error
144
+ const rule = commentedDirectives_extensionRules[directive];
145
+ const isExtensionJSX = extension.endsWith("x");
146
+
147
+ if (rule === true && isExtensionJSX) return directive; // requires JSX extension
148
+ if (rule === false && !isExtensionJSX) return directive; // forbids JSX extension
149
+ if (rule === null) return directive; // no extension constraint, specifically for "use agnostic strategies"
150
+
151
+ return null; // verification failed
173
152
  };
174
153
 
175
154
  /* getCommentedDirectiveFromImportedModule */
@@ -197,7 +176,7 @@ export const getCommentedDirectiveFromImportedModule = (resolvedImportPath) => {
197
176
  const importedFileFirstLine = getImportedFileFirstLine(resolvedImportPath);
198
177
 
199
178
  // sees if the first line includes any of the directives and finds the directive that it includes, with USE_AGNOSTIC_LOGICS as a default
200
- const includedDirective = directivesArray.reduce((acc, curr) => {
179
+ const includedDirective = commentedDirectivesArray.reduce((acc, curr) => {
201
180
  if (importedFileFirstLine.includes(curr)) return curr;
202
181
  else return acc;
203
182
  }, USE_AGNOSTIC_LOGICS);
@@ -221,19 +200,23 @@ export const getCommentedDirectiveFromImportedModule = (resolvedImportPath) => {
221
200
  * @returns The interpreted directive, a.k.a. strategized directive, or lack thereof via `null`.
222
201
  */
223
202
  export const getStrategizedDirective = (context, node) => {
203
+ // gets the first nested `/* */` comment inside the node
224
204
  const firstNestedComment = context.sourceCode.getCommentsInside(node)[0];
225
205
 
226
206
  // returns null early if there is no nested comments
227
207
  if (!firstNestedComment) return null;
228
208
 
209
+ // gets and trims the first nested comment raw
229
210
  const rawStrategy = firstNestedComment.value.trim() || "";
230
211
 
212
+ // asserts whether that first nested comment is or isn't a Strategy
231
213
  const strategy =
232
214
  strategiesArray.find((strategy) => strategy === rawStrategy) ?? null;
233
215
 
234
216
  // returns null early if no strategy was identified
235
217
  if (!strategy) return null;
236
218
 
219
+ // maps the strategy to the its relevant directive
237
220
  const commentedDirective = commentedStrategies_commentedDirectives[strategy];
238
221
 
239
222
  return commentedDirective;
@@ -257,15 +240,17 @@ export const isImportBlocked = (
257
240
  importedFileCommentedDirective
258
241
  );
259
242
 
260
- /* makeMessageFromCommentedDirective */
243
+ /* makeMessageFromCurrentFileCommentedDirective */
261
244
 
262
245
  /**
263
246
  * Lists in an message the commented modules incompatible with a commented module based on its commented directive.
264
247
  * @param {CommentedDirective} commentedDirective The commented directive of the commented module.
265
248
  * @returns The message listing the incompatible commented modules.
266
249
  */
267
- export const makeMessageFromCommentedDirective = (commentedDirective) =>
268
- makeMessageFromResolvedDirective(
250
+ export const makeMessageFromCurrentFileCommentedDirective = (
251
+ commentedDirective
252
+ ) =>
253
+ makeMessageFromCurrentFileResolvedDirective(
269
254
  commentedDirectives_commentedModules,
270
255
  commentedDirectives_blockedImports,
271
256
  commentedDirective
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-use-agnostic",
3
- "version": "0.9.7",
3
+ "version": "0.9.8",
4
4
  "description": "Highlights problematic server-client imports in projects made with the Fullstack React Architecture.",
5
5
  "keywords": [
6
6
  "eslint",