eslint-plugin-use-agnostic 0.9.0 → 0.9.1

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
@@ -85,7 +85,7 @@ Only the first line of code in a file is observed for the presence of a directiv
85
85
 
86
86
  Aliased import paths are resolved only if your ESLint config file and your `tsconfig.json` file are in the same directory. (At least to my knowledge.)
87
87
 
88
- It is up to you to confirm that your Agnostic Modules are indeed agnostic, meaning that they do not have neither server- nor client-side code. `eslint-plugin-use-agnostic`, at least at this time, does not do this verification for you.
88
+ It is up to you to confirm that your Agnostic Modules are indeed agnostic, meaning that they do have neither server- nor client-side code. `eslint-plugin-use-agnostic`, at least at this time, does not do this verification for you.
89
89
 
90
90
  It is also up to you to ensure, as outlined above, that **you do not mix** exporting React components with exporting other logics within the same module. Separating exporting React components from their own modules ending with a JSX extension, from other logics from modules that don't end with a JSX extension, is crucial for distinguishing between Logics Modules and Components Modules.
91
91
 
@@ -109,4 +109,4 @@ But not having a directive to distinguish between 1. non-special Server Modules
109
109
 
110
110
  This is what the 'use agnostic' directive solves. It clearly marks a module to be an Agnostic Module. And if a module that used to lack a directive can now be marked as an Agnostic Module, this allows modules without a directive to finally, truly be Server Modules by default. And eslint-plugin-use-agnostic can work from there.
111
111
 
112
- A lot more work needs to be done, and a lot of it unfortunately can only be optimized deeper into React's innerworkings. But if the introduction of 'use agnostic' can already create such powerful static analysis, imagine what it could produce if only it were incorporated into React as an official directive of the Fullstack React Architecture.
112
+ A lot more work has to be done, and a lot of it unfortunately can only be optimized deeper into React's innerworkings. But if the introduction of 'use agnostic' can already create such powerful static analysis, imagine what it could produce if only it were incorporated into React as an official directive of the Fullstack React Architecture.
@@ -1,7 +1,7 @@
1
1
  /* plugin names */
2
2
  // use-agnostic
3
3
  export const useAgnosticPluginName = "use-agnostic";
4
- // crossingStrategies
4
+ // crossingStrategies (canceled)
5
5
  export const strategiesPluginName = "strategies";
6
6
 
7
7
  /* config names */
@@ -18,7 +18,7 @@ export const enforceEffectiveDirectivesRuleName =
18
18
  export const enforceCommentedDirectivesRuleName =
19
19
  "enforce-commented-directives-import-rules";
20
20
 
21
- // crossingStrategies
21
+ // crossingStrategies (canceled)
22
22
  export const verifySpecifierImportRuleName =
23
23
  "verify-specifier-import-export-same-strategy";
24
24
  export const verifyDefaultImportRuleName =
@@ -44,6 +44,8 @@ export const exportNotStrategized =
44
44
  "export-from-use-agnostic-strategies-not-strategized";
45
45
 
46
46
  // all "resolved" directives (from AIA/agnostic20 & DFA/directive21)
47
+ // - AIA: Agnostic-Included Architecture (agnostic20)
48
+ // - DFA: Directive-First Architecture (directive21)
47
49
  export const USE_SERVER_LOGICS = "use server logics";
48
50
  export const USE_CLIENT_LOGICS = "use client logics";
49
51
  export const USE_AGNOSTIC_LOGICS = "use agnostic logics";
@@ -97,6 +97,18 @@ export const getImportedFileFirstLine = (resolvedImportPath) => {
97
97
  return importedFileFirstLine;
98
98
  };
99
99
 
100
+ /* highlightFirstLineOfCode */
101
+
102
+ /**
103
+ * Gets the coordinates for the first line of code of a file.
104
+ * @param {import('@typescript-eslint/utils').TSESLint.RuleContext} context An ESLint rule's `context` object.
105
+ * @returns The `context.report` `loc`-compatible coordinates for the first line of code of a file.
106
+ */
107
+ export const highlightFirstLineOfCode = (context) => ({
108
+ start: { line: 1, column: 0 },
109
+ end: { line: 1, column: context.sourceCode.lines[0].length },
110
+ });
111
+
100
112
  /* isImportBlocked */
101
113
 
102
114
  /**
@@ -110,7 +122,7 @@ export const isImportBlocked = (
110
122
  // 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
123
  resolvedDirectives_blockedImports,
112
124
  currentFileResolvedDirective,
113
- importedFileResolvedDirective,
125
+ importedFileResolvedDirective
114
126
  ) =>
115
127
  resolvedDirectives_blockedImports[currentFileResolvedDirective]
116
128
  .map((e) => e.blockedImport)
@@ -123,12 +135,12 @@ export const isImportBlocked = (
123
135
  * @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
136
  * @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
137
  * @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]".
138
+ * @returns {string} Returns "[Current file 'resolved' modules] are not allowed to import [imported file 'resolved' modules]."
127
139
  */
128
140
  export const makeIntroForSpecificViolationMessage = (
129
141
  resolvedDirectives_ResolvedModules,
130
142
  currentFileResolvedDirective,
131
- importedFileResolvedDirective,
143
+ importedFileResolvedDirective
132
144
  ) =>
133
145
  `${resolvedDirectives_ResolvedModules[currentFileResolvedDirective]}s ${ARE_NOT_ALLOWED_TO_IMPORT} ${resolvedDirectives_ResolvedModules[importedFileResolvedDirective]}s.`;
134
146
 
@@ -144,14 +156,14 @@ export const makeIntroForSpecificViolationMessage = (
144
156
  export const makeMessageFromResolvedDirective = (
145
157
  resolvedDirectives_ResolvedModules,
146
158
  resolvedDirectives_blockedImports,
147
- resolvedDirective,
159
+ resolvedDirective
148
160
  ) => {
149
161
  const effectiveModule = resolvedDirectives_ResolvedModules[resolvedDirective];
150
162
  const effectiveModulesString = effectiveModule + "s"; // plural
151
163
 
152
164
  const blockedImports =
153
165
  resolvedDirectives_blockedImports[resolvedDirective].map(
154
- (e) => e.blockedImport,
166
+ (e) => e.blockedImport
155
167
  ) || [];
156
168
 
157
169
  if (blockedImports.length === 0) {
@@ -159,7 +171,7 @@ export const makeMessageFromResolvedDirective = (
159
171
  }
160
172
 
161
173
  const blockedEffectiveModules = blockedImports.map(
162
- (e) => resolvedDirectives_ResolvedModules[e] + "s", // plural
174
+ (e) => resolvedDirectives_ResolvedModules[e] + "s" // plural
163
175
  );
164
176
 
165
177
  const blockedEffectiveModulesString =
@@ -184,8 +196,8 @@ export const makeMessageFromResolvedDirective = (
184
196
  export const findSpecificViolationMessage = (
185
197
  resolvedDirectives_blockedImports,
186
198
  currentFileResolvedDirective,
187
- importedFileResolvedDirective,
199
+ importedFileResolvedDirective
188
200
  ) =>
189
201
  resolvedDirectives_blockedImports[currentFileResolvedDirective].find(
190
- (e) => e.blockedImport === importedFileResolvedDirective,
202
+ (e) => e.blockedImport === importedFileResolvedDirective
191
203
  ).message;
@@ -65,6 +65,7 @@ export const directivesSet = new Set([USE_SERVER, USE_CLIENT, USE_AGNOSTIC]);
65
65
 
66
66
  /* from the getDirectiveFromImportedModule utility */
67
67
 
68
+ /** @type {readonly [USE_SERVER, USE_CLIENT, USE_AGNOSTIC]} */
68
69
  export const directivesArray = Array.from(directivesSet);
69
70
 
70
71
  /* from the isImportBlocked utility */
@@ -75,7 +76,7 @@ export const directivesArray = Array.from(directivesSet);
75
76
  * Makes the intro for each specific import rule violation messages.
76
77
  * @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
78
  * @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
+ * @returns {string} Returns "[Current file effective modules] are not allowed to import [imported file effective modules]."
79
80
  */
80
81
  const makeIntroForSpecificViolationMessage = (
81
82
  currentFileEffectiveDirective,
@@ -20,7 +20,10 @@ import {
20
20
  specificViolationMessage,
21
21
  } from "../constants/bases.js";
22
22
 
23
- import { resolveImportPath } from "../../../_commons/utilities/helpers.js";
23
+ import {
24
+ resolveImportPath,
25
+ highlightFirstLineOfCode,
26
+ } from "../../../_commons/utilities/helpers.js";
24
27
  import {
25
28
  getDirectiveFromCurrentModule,
26
29
  getDirectiveFromImportedModule,
@@ -61,10 +64,7 @@ export const currentFileFlow = (context) => {
61
64
  currentFileExtension.endsWith("x")
62
65
  ) {
63
66
  context.report({
64
- loc: {
65
- start: { line: 1, column: 0 },
66
- end: { line: 1, column: context.sourceCode.lines[0].length },
67
- },
67
+ loc: highlightFirstLineOfCode(context),
68
68
  messageId: useServerJSXMessageId,
69
69
  });
70
70
  return { skip: true };
@@ -91,9 +91,6 @@ export const currentFileFlow = (context) => {
91
91
 
92
92
  /**
93
93
  * The flow that is shared between import and re-export traversals to obtain the import file's effective directive.
94
- * @param {string} currentDir Directory of the file containing the import (from `path.dirname(context.filename)`).
95
- * @param {string} importPath The import specifier (e.g., `@/components/Button` or `./utils`).
96
- * @param {string} cwd Project root (from `context.cwd`). Caveat: only as an assumption currently.
97
94
  * @param {Readonly<import('@typescript-eslint/utils').TSESLint.RuleContext<typeof reExportNotSameMessageId | typeof importBreaksEffectiveImportRulesMessageId | typeof useServerJSXMessageId, []>>} context The ESLint rule's `context` object.
98
95
  * @param {import('@typescript-eslint/types').TSESTree.ImportDeclaration} node The ESLint `node` of the rule's current traversal.
99
96
  * @returns {{skip: true; importedFileEffectiveDirective: undefined; resolvedImportPath: undefined;} | {skip: undefined; importedFileEffectiveDirective: USE_SERVER_LOGICS | USE_SERVER_COMPONENTS | USE_SERVER_FUNCTIONS | USE_CLIENT_LOGICS | USE_CLIENT_COMPONENTS | USE_AGNOSTIC_LOGICS | USE_AGNOSTIC_COMPONENTS; resolvedImportPath: string;}} Returns either an object with `skip: true` to disregard or one with the non-null `importedFileEffectiveDirective`.
@@ -202,9 +199,9 @@ export const reExportsFlow = (context, node, currentFileEffectiveDirective) => {
202
199
  node,
203
200
  messageId: reExportNotSameMessageId,
204
201
  data: {
205
- // currentFileEffectiveDirective
202
+ // currentFileEffectiveDirective:
206
203
  currentFileEffectiveDirective,
207
- // importedFileEffectiveDirective
204
+ // importedFileEffectiveDirective:
208
205
  importedFileEffectiveDirective,
209
206
  },
210
207
  });
@@ -9,6 +9,8 @@ import {
9
9
 
10
10
  /**
11
11
  * Makes the agnostic20 config for the use-agnostic ESLint plugin.
12
+ * @param {import('eslint').ESLint.Plugin} plugin The use-agnostic ESLint plugin itself.
13
+ * @returns The agnostic20 config's name as a key and its config as its value.
12
14
  */
13
15
  export const makeAgnostic20Config = (plugin) => ({
14
16
  [agnostic20ConfigName]: defineConfig([
@@ -86,27 +86,29 @@ export const directivesSet = new Set([
86
86
 
87
87
  /* from the getCommentedDirectiveFromImportedModule utility */
88
88
 
89
+ /** @type {readonly [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]} */
89
90
  export const directivesArray = Array.from(directivesSet);
90
91
 
91
92
  /* commentedDirectives_4RawImplementations */
92
93
 
93
- // make all four accepted commented directive implementations
94
- const makeRawCommentedDirectiveV1of4 = (directive) => `// '${directive}'`;
95
- const makeRawCommentedDirectiveV2of4 = (directive) => `// "${directive}"`;
96
- const makeRawCommentedDirectiveV3of4 = (directive) => `/* '${directive}' */`;
97
- const makeRawCommentedDirectiveV4of4 = (directive) => `/* "${directive}" */`;
94
+ // all formatting styles as an array of [prefix, quote, suffix]
95
+ const commentStyles = [
96
+ [`// `, `'`, ``], // V1: `// 'directive'`
97
+ [`// `, `"`, ``], // V2: `// "directive"`
98
+ [`/* `, `'`, ` */`], // V3: `/* 'directive' */`
99
+ [`/* `, `"`, ` */`], // V4: `/* "directive" */`
100
+ ];
98
101
 
99
102
  /**
100
103
  * Makes the array of all four accepted commented directive implementations on a directive basis.
101
- * @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} directive
102
- * @returns
104
+ * @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} directive The commented directive.
105
+ * @returns {string[]} The array of formatted commented directives.
103
106
  */
104
- const make4RawImplementations = (directive) => [
105
- makeRawCommentedDirectiveV1of4(directive),
106
- makeRawCommentedDirectiveV2of4(directive),
107
- makeRawCommentedDirectiveV3of4(directive),
108
- makeRawCommentedDirectiveV4of4(directive),
109
- ];
107
+ const make4RawImplementations = (directive) =>
108
+ commentStyles.map(
109
+ ([prefix, quote, suffix]) =>
110
+ `${prefix}${quote}${directive}${quote}${suffix}`
111
+ );
110
112
 
111
113
  // mapped commented directives to their 4 raw implementations
112
114
  export const commentedDirectives_4RawImplementations = Object.freeze({
@@ -152,7 +154,7 @@ export const commentedStrategies_CommentedDirectives = Object.freeze({
152
154
  * Makes the intro for each specific import rule violation messages.
153
155
  * @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} currentFileCommentedDirective The current file's commented directive.
154
156
  * @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} importedFileCommentedDirective The imported file's commented directive.
155
- * @returns {string} Returns "[Current file commented modules] are not allowed to import [imported file commented modules]".
157
+ * @returns {string} Returns "[Current file commented modules] are not allowed to import [imported file commented modules]."
156
158
  */
157
159
  const makeIntroForSpecificViolationMessage = (
158
160
  currentFileCommentedDirective,
@@ -28,7 +28,10 @@ import {
28
28
  specificFailure,
29
29
  } from "../constants/bases.js";
30
30
 
31
- import { resolveImportPath } from "../../../_commons/utilities/helpers.js";
31
+ import {
32
+ resolveImportPath,
33
+ highlightFirstLineOfCode,
34
+ } from "../../../_commons/utilities/helpers.js";
32
35
  import {
33
36
  getCommentedDirectiveFromCurrentModule,
34
37
  getVerifiedCommentedDirective,
@@ -37,6 +40,7 @@ import {
37
40
  makeMessageFromCommentedDirective,
38
41
  findSpecificViolationMessage,
39
42
  getStrategizedDirective,
43
+ addressDirectiveIfAgnosticStrategies,
40
44
  } from "./helpers.js";
41
45
 
42
46
  /* currentFileFlow */
@@ -67,10 +71,7 @@ export const currentFileFlow = (context) => {
67
71
  // reports if there is no directive or no valid directive (same, but eventually no directive could have defaults)
68
72
  if (!commentedDirective) {
69
73
  context.report({
70
- loc: {
71
- start: { line: 1, column: 0 },
72
- end: { line: 1, column: context.sourceCode.lines[0].length },
73
- },
74
+ loc: highlightFirstLineOfCode(context),
74
75
  messageId: noCommentedDirective,
75
76
  });
76
77
  return { skip: true };
@@ -84,10 +85,7 @@ export const currentFileFlow = (context) => {
84
85
  // reports if the verification failed
85
86
  if (!verifiedCommentedDirective) {
86
87
  context.report({
87
- loc: {
88
- start: { line: 1, column: 0 },
89
- end: { line: 1, column: context.sourceCode.lines[0].length },
90
- },
88
+ loc: highlightFirstLineOfCode(context),
91
89
  messageId: commentedDirectiveVerificationFailed,
92
90
  data: {
93
91
  [specificFailure]:
@@ -139,10 +137,11 @@ const importedFileFlow = (context, node) => {
139
137
  }
140
138
 
141
139
  /* GETTING THE CORRECT DIRECTIVE INTERPRETATION OF STRATEGY FOR AGNOSTIC STRATEGIES MODULES IMPORTS.
142
- (The Directive-First Architecture does not check whether the export and import Strategies are the same at this time, meaning a @clientLogics strategy could be wrongly imported and interpreted as a @serverLogics strategy.
140
+ (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
141
 
144
- After a short attempt, this feature is currently cancelled, 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.
142
+ 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
143
 
144
+ // (Consequently, details below are currently at the stage of wishful thinking.)
146
145
  However, 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 to for all non-type export to be named and PascalCase.) */
147
146
  if (importedFileCommentedDirective === USE_AGNOSTIC_STRATEGIES) {
148
147
  const importingFileCommentedDirective = getStrategizedDirective(
@@ -222,27 +221,29 @@ export const allExportsFlow = (
222
221
  // does not operate on `export type`
223
222
  if (node.exportKind === "type") return;
224
223
 
225
- if (node.source) {
224
+ // regular exports scenarios
225
+ if (!node.source) {
226
+ addressDirectiveIfAgnosticStrategies(
227
+ context,
228
+ node,
229
+ currentFileCommentedDirective
230
+ );
231
+ }
232
+ // re-exports scenarios
233
+ else {
226
234
  const result = importedFileFlow(context, node);
227
235
 
228
236
  if (result.skip) return;
229
237
  const { importedFileCommentedDirective } = result;
230
238
 
231
- // ignores if this is NOT an Agnostic Strategies Module
232
- // verifies current node export strategy if "use agnostic strategies"
233
- if (currentFileCommentedDirective === USE_AGNOSTIC_STRATEGIES) {
234
- const exportStrategizedDirective = getStrategizedDirective(context, node);
235
-
236
- if (exportStrategizedDirective === null) {
237
- context.report({
238
- node,
239
- messageId: exportNotStrategized,
240
- });
241
- return;
242
- }
239
+ const addressedDirective = addressDirectiveIfAgnosticStrategies(
240
+ context,
241
+ node,
242
+ currentFileCommentedDirective
243
+ );
243
244
 
244
- currentFileCommentedDirective = exportStrategizedDirective;
245
- }
245
+ if (!addressedDirective) return;
246
+ else currentFileCommentedDirective = addressedDirective;
246
247
 
247
248
  if (currentFileCommentedDirective !== importedFileCommentedDirective) {
248
249
  context.report({
@@ -255,24 +256,6 @@ export const allExportsFlow = (
255
256
  importedFileCommentedDirective,
256
257
  },
257
258
  });
258
- return;
259
- }
260
- } else {
261
- // ignores if this is NOT an Agnostic Strategies Module
262
- // verifies current node export strategy if "use agnostic strategies"
263
- if (currentFileCommentedDirective === USE_AGNOSTIC_STRATEGIES) {
264
- const exportStrategizedDirective = getStrategizedDirective(context, node);
265
-
266
- if (exportStrategizedDirective === null) {
267
- context.report({
268
- node,
269
- messageId: exportNotStrategized,
270
- });
271
- return;
272
- }
273
-
274
- // just to emphasize that this is the same short flow from above
275
- currentFileCommentedDirective = exportStrategizedDirective;
276
259
  }
277
260
  }
278
261
  };
@@ -190,9 +190,11 @@ export const getCommentedDirectiveFromImportedModule = (resolvedImportPath) => {
190
190
  const importedFileFirstLine = getImportedFileFirstLine(resolvedImportPath);
191
191
 
192
192
  // sees if the first line includes any of the directives and finds the directive that it includes
193
+ /** @type {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 | ""} */
193
194
  let includedDirective = "";
194
- const lengthOne = directivesArray.length;
195
- for (let i = 0; i < lengthOne; i++) {
195
+ const firstLength = directivesArray.length;
196
+
197
+ for (let i = 0; i < firstLength; i++) {
196
198
  const directive = directivesArray[i];
197
199
  if (importedFileFirstLine.includes(directive)) {
198
200
  includedDirective = directive;
@@ -203,12 +205,14 @@ export const getCommentedDirectiveFromImportedModule = (resolvedImportPath) => {
203
205
  // returns null early if there is none of the directives in the first line
204
206
  if (includedDirective === "") return null;
205
207
 
208
+ /** @type {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 | ""} */
206
209
  let importFileDirective = "";
207
- const lengthTwo =
208
- // sucks for that any but, I'm working in JS here
209
- commentedDirectives_4RawImplementations[includedDirective].length;
210
- for (let i = 0; i < lengthTwo; i++) {
211
- const raw = commentedDirectives_4RawImplementations[includedDirective][i];
210
+ const rawImplementations =
211
+ commentedDirectives_4RawImplementations[includedDirective];
212
+ const secondLength = rawImplementations.length;
213
+
214
+ for (let i = 0; i < secondLength; i++) {
215
+ const raw = rawImplementations[i];
212
216
  if (raw === importedFileFirstLine) {
213
217
  importFileDirective = includedDirective;
214
218
  break;
@@ -289,3 +293,33 @@ export const findSpecificViolationMessage = (
289
293
  currentFileCommentedDirective,
290
294
  importedFileCommentedDirective
291
295
  );
296
+
297
+ /* addressDirectiveIfAgnosticStrategies */
298
+
299
+ /**
300
+ * Verifies the current node's export strategy if `"use agnostic strategies"` by reporting `exportNotStrategized` in case an export is not strategized in an Agnostic Strategies Module.
301
+ * @param {Readonly<import('@typescript-eslint/utils').TSESLint.RuleContext<typeof reExportNotSameMessageId | typeof importBreaksCommentedImportRulesMessageId | typeof noCommentedDirective | typeof commentedDirectiveVerificationFailed | typeof importNotStrategized | typeof exportNotStrategized, []>>} context The ESLint rule's `context` object.
302
+ * @param {import('@typescript-eslint/types').TSESTree.ExportNamedDeclaration | import('@typescript-eslint/types').TSESTree.ExportAllDeclaration | import('@typescript-eslint/types').TSESTree.ExportDefaultDeclaration} node The ESLint `node` of the rule's current traversal.
303
+ * @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} currentFileCommentedDirective The current file's commented directive.
304
+ * @returns The commented directive, the addressed strategy (as a commented directive) or null in case of failure.
305
+ */
306
+ export const addressDirectiveIfAgnosticStrategies = (
307
+ context,
308
+ node,
309
+ currentFileCommentedDirective
310
+ ) => {
311
+ // ignores if not addressing an Agnostic Strategies Module
312
+ if (currentFileCommentedDirective !== USE_AGNOSTIC_STRATEGIES)
313
+ return currentFileCommentedDirective;
314
+
315
+ const exportStrategizedDirective = getStrategizedDirective(context, node);
316
+
317
+ if (exportStrategizedDirective === null) {
318
+ context.report({
319
+ node,
320
+ messageId: exportNotStrategized,
321
+ });
322
+ }
323
+
324
+ return exportStrategizedDirective; // null indicates failure
325
+ };
@@ -9,6 +9,8 @@ import {
9
9
 
10
10
  /**
11
11
  * Makes the directive21 config for the use-agnostic ESLint plugin.
12
+ * @param {import('eslint').ESLint.Plugin} plugin The use-agnostic ESLint plugin itself.
13
+ * @returns The directive21 config's name as a key and its config as its value.
12
14
  */
13
15
  export const makeDirective21Config = (plugin) => ({
14
16
  [directive21ConfigName]: defineConfig([
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-use-agnostic",
3
- "version": "0.9.0",
3
+ "version": "0.9.1",
4
4
  "description": "Highlights problematic server-client imports in projects made with the Fullstack React Architecture.",
5
5
  "keywords": [
6
6
  "eslint",