eslint-plugin-use-agnostic 1.7.5 → 1.7.9

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.
@@ -1,6 +1,12 @@
1
1
  export const forAliasVariables = Object.freeze({
2
2
  importsFlow:
3
3
  "The full flow for import traversals to enforce effective directives import rules." /* $COMMENT#JSDOC#FORALIASVARIABLES#IMPORTSFLOW */,
4
+ importsFlowRequire:
5
+ "The `importsFlow` adapted for `require` calls to enforce effective directives import rules." /* $COMMENT#JSDOC#FORALIASVARIABLES#IMPORTSFLOWREQUIRE */,
6
+ importsFlowCommented:
7
+ "The full flow for import traversals to enforce commented directives import rules." /* $COMMENT#JSDOC#FORALIASVARIABLES#IMPORTSFLOWCOMMENTED */,
8
+ importsFlowCommentedRequire:
9
+ "The `importsFlow` adapted for `require` calls to enforce commented directives import rules." /* $COMMENT#JSDOC#FORALIASVARIABLES#IMPORTSFLOWCOMMENTEDREQUIRE */,
4
10
  flowReturnsEarly:
5
11
  "Early if the flow needs to be interrupted." /* $COMMENT#JSDOC#FORALIASVARIABLES#FLOWRETURNSEARLY */,
6
12
  });
@@ -15,8 +15,10 @@ export const jsDocComments = Object.freeze({
15
15
  "$COMMENT#JSDOC#FORCOMPOSEDVARIABLES#LISTSINMESSAGE $COMMENT#JSDOC#FORCOMPOSEDVARIABLES#RESOLVED $COMMENT#JSDOC#FORCOMPOSEDVARIABLES#MODULESINCOMPATIBLE $COMMENT#JSDOC#FORCOMPOSEDVARIABLES#RESOLVED $COMMENT#JSDOC#FORCOMPOSEDVARIABLES#MODULEBASEDON $COMMENT#JSDOC#FORCOMPOSEDVARIABLES#RESOLVED $COMMENT#JSDOC#FORCOMPOSEDVARIABLES#DIRECTIVEPERIOD" /* $COMMENT#JSDOC#DEFINITIONS#MAKEMESSAGEFROMCURRENTFILERESOLVEDDIRECTIVE */,
16
16
  findSpecificViolationMessage:
17
17
  "$COMMENT#JSDOC#FORCOMPOSEDVARIABLES#FINDTHEMESSAGE $COMMENT#JSDOC#FORCOMPOSEDVARIABLES#RESOLVED $COMMENT#JSDOC#FORCOMPOSEDVARIABLES#RULESBASEDON $COMMENT#JSDOC#FORCOMPOSEDVARIABLES#RDBIPERIOD" /* $COMMENT#JSDOC#DEFINITIONS#FINDSPECIFICVIOLATIONMESSAGE */,
18
- walkAST: "Walks an AST with a given callback." /* $COMMENT#JSDOC#DEFINITIONS#WALKAST */,
19
- visitNode: "Recursively visits an AST node with a given callback." /* $COMMENT#JSDOC#DEFINITIONS#VISITNODE */,
18
+ walkAST:
19
+ "Walks an AST with a given callback." /* $COMMENT#JSDOC#DEFINITIONS#WALKAST */,
20
+ visitNode:
21
+ "Recursively visits an AST node with a given callback." /* $COMMENT#JSDOC#DEFINITIONS#VISITNODE */,
20
22
  analyzeExportsForReExports:
21
23
  "Analyzes a source code's exports to detect re-exports." /* $COMMENT#JSDOC#DEFINITIONS#ANALYZEEXPORTSFORREEXPORTS */,
22
24
  agnostic20: Object.freeze({
@@ -44,6 +46,8 @@ export const jsDocComments = Object.freeze({
44
46
  "$COMMENT#JSDOC#FORCOMPOSEDVARIABLES#FLOWTHATBEGINS $COMMENT#JSDOC#FORCOMPOSEDVARIABLES#EFFECTIVE $COMMENT#JSDOC#FORCOMPOSEDVARIABLES#DIRECTIVE $COMMENT#JSDOC#FORCOMPOSEDVARIABLES#OFCURRENTFILE $COMMENT#JSDOC#FORCOMPOSEDVARIABLES#EFFECTIVE $COMMENT#JSDOC#FORCOMPOSEDVARIABLES#DIRECTIVES $COMMENT#JSDOC#FORCOMPOSEDVARIABLES#OFFILESITIMPORTS" /* $COMMENT#JSDOC#DEFINITIONS#AGNOSTIC20#CURRENTFILEFLOW */,
45
47
  importedFileFlow:
46
48
  "$COMMENT#JSDOC#FORCOMPOSEDVARIABLES#FLOWIMPORTREEXPORT $COMMENT#JSDOC#FORCOMPOSEDVARIABLES#EFFECTIVE $COMMENT#JSDOC#FORCOMPOSEDVARIABLES#DIRECTIVEPERIOD" /* $COMMENT#JSDOC#DEFINITIONS#AGNOSTIC20#IMPORTEDFILEFLOW */,
49
+ importedFileFlowRequire:
50
+ "The `importedFileFlow` adapted for `require` calls to obtain the import file's effective directive." /* $COMMENT#JSDOC#DEFINITIONS#AGNOSTIC20#IMPORTEDFILEFLOWREQUIRE */,
47
51
  importsFlow:
48
52
  "JSDOC#FORALIASVARIABLES#IMPORTSFLOW" /* $COMMENT#JSDOC#DEFINITIONS#AGNOSTIC20#IMPORTSFLOW */,
49
53
  reExportsFlow:
@@ -88,6 +92,8 @@ export const jsDocComments = Object.freeze({
88
92
  "$COMMENT#JSDOC#FORCOMPOSEDVARIABLES#FLOWTHATBEGINS $COMMENT#JSDOC#FORCOMPOSEDVARIABLES#VERIFIEDCOMMENTED $COMMENT#JSDOC#FORCOMPOSEDVARIABLES#DIRECTIVE $COMMENT#JSDOC#FORCOMPOSEDVARIABLES#OFCURRENTFILE $COMMENT#JSDOC#FORCOMPOSEDVARIABLES#VERIFIEDCOMMENTED $COMMENT#JSDOC#FORCOMPOSEDVARIABLES#DIRECTIVES $COMMENT#JSDOC#FORCOMPOSEDVARIABLES#OFFILESITIMPORTS" /* $COMMENT#JSDOC#DEFINITIONS#DIRECTIVE21#CURRENTFILEFLOW */,
89
93
  importedFileFlow:
90
94
  "$COMMENT#JSDOC#FORCOMPOSEDVARIABLES#FLOWIMPORTREEXPORT $COMMENT#JSDOC#FORCOMPOSEDVARIABLES#COMMENTED $COMMENT#JSDOC#FORCOMPOSEDVARIABLES#DIRECTIVEPERIOD" /* $COMMENT#JSDOC#DEFINITIONS#DIRECTIVE21#IMPORTEDFILEFLOW */,
95
+ importedFileFlowRequire:
96
+ "The `importedFileFlow` adapted for `require` calls to obtain the import file's commented directive." /* $COMMENT#JSDOC#DEFINITIONS#DIRECTIVE21#IMPORTEDFILEFLOWREQUIRE */,
91
97
  importsFlow:
92
98
  "JSDOC#FORALIASVARIABLES#IMPORTSFLOW" /* $COMMENT#JSDOC#DEFINITIONS#DIRECTIVE21#IMPORTSFLOW */,
93
99
  allExportsFlow:
@@ -130,12 +136,17 @@ export const jsDocComments = Object.freeze({
130
136
  extension:
131
137
  "The JavaScript (TypeScript) extension of the file." /* $COMMENT#JSDOC#PARAMS#EXTENSION */,
132
138
  node: "The ESLint `node` of the rule's current traversal." /* $COMMENT#JSDOC#PARAMS#NODE */,
133
- sourceCodeA: "The `SourceCode` where the AST comes from." /* $COMMENT#JSDOC#PARAMS#SOURCECODEA */,
134
- callback: "The callback that runs during the walk." /* $COMMENT#JSDOC#PARAMS#CALLBACK */,
139
+ sourceCodeA:
140
+ "The `SourceCode` where the AST comes from." /* $COMMENT#JSDOC#PARAMS#SOURCECODEA */,
141
+ callback:
142
+ "The callback that runs during the walk." /* $COMMENT#JSDOC#PARAMS#CALLBACK */,
135
143
  nodeB: "The node being visited." /* $COMMENT#JSDOC#PARAMS#NODEB */,
136
- parent: "The parent of the node being visited." /* $COMMENT#JSDOC#PARAMS#PARENT */,
137
- visitorKeys: "The visitor keys of the node being visited." /* $COMMENT#JSDOC#PARAMS#VISITORKEYS */,
138
- sourceCodeB: "The `SourceCode` to analyze." /* $COMMENT#JSDOC#PARAMS#SOURCECODEB */,
144
+ parent:
145
+ "The parent of the node being visited." /* $COMMENT#JSDOC#PARAMS#PARENT */,
146
+ visitorKeys:
147
+ "The visitor keys of the node being visited." /* $COMMENT#JSDOC#PARAMS#VISITORKEYS */,
148
+ sourceCodeB:
149
+ "The `SourceCode` to analyze." /* $COMMENT#JSDOC#PARAMS#SOURCECODEB */,
139
150
  agnostic20: Object.freeze({
140
151
  currentFileEffectiveDirective:
141
152
  "$COMMENT#JSDOC#FORCOMPOSEDVARIABLES#THECURRENTFILE $COMMENT#JSDOC#FORCOMPOSEDVARIABLES#EFFECTIVE $COMMENT#JSDOC#FORCOMPOSEDVARIABLES#DIRECTIVEPERIOD" /* $COMMENT#JSDOC#PARAMS#AGNOSTIC20#CURRENTFILEEFFECTIVEDIRECTIVE */,
@@ -14,6 +14,7 @@ import {
14
14
  currentFileFlow,
15
15
  importsFlow,
16
16
  reExportsFlow,
17
+ importsFlowRequire,
17
18
  } from "../utilities/flows.js";
18
19
 
19
20
  /**
@@ -54,7 +55,8 @@ Indeed, Server Functions Modules have no business exporting JSX. `,
54
55
  ExportAllDeclaration: (node) =>
55
56
  reExportsFlow(context, node, currentFileEffectiveDirective),
56
57
  // Unlike directive21, no ExportDefaultDeclaration because ExportDefaultDeclaration don't have source. The reason they're addressed in directive21 is specifically for Agnostic Strategies.
57
- // ...but removed because export default can only be
58
+ CallExpression: (node) =>
59
+ importsFlowRequire(context, node, currentFileEffectiveDirective),
58
60
  };
59
61
  },
60
62
  };
@@ -35,6 +35,7 @@ import {
35
35
  * @typedef {import('../../../../types/agnostic20/_commons/typedefs.js').ImportDeclaration} ImportDeclaration
36
36
  * @typedef {import('../../../../types/agnostic20/_commons/typedefs.js').ExportNamedDeclaration} ExportNamedDeclaration
37
37
  * @typedef {import('../../../../types/agnostic20/_commons/typedefs.js').ExportAllDeclaration} ExportAllDeclaration
38
+ * @typedef {import('../../../../types/agnostic20/_commons/typedefs.js').CallExpression} CallExpression
38
39
  */
39
40
 
40
41
  /* currentFileFlow */
@@ -144,6 +145,68 @@ const importedFileFlow = (context, node) => {
144
145
  return { skip: undefined, importedFileEffectiveDirective };
145
146
  };
146
147
 
148
+ // NEW!! Currently strictly adapted from importedFileFlow
149
+ /**
150
+ * The `importedFileFlow` adapted for `require` calls to obtain the import file's effective directive.
151
+ * @param {Context} context The ESLint rule's `context` object.
152
+ * @param {CallExpression} node The ESLint `node` of the rule's current traversal.
153
+ * @returns Either an object with `skip: true` to disregard or one with the non-null `importedFileEffectiveDirective`.
154
+ */
155
+ const importedFileFlowRequire = (context, node) => {
156
+ const skipTrue = { ...skip, importedFileEffectiveDirective: undefined };
157
+
158
+ if (
159
+ node.callee.type === "Identifier" &&
160
+ node.callee.name === "require" &&
161
+ node.arguments.length === 1 &&
162
+ node.arguments[0].type === "Literal"
163
+ ) {
164
+ const importPath = node.arguments[0].value;
165
+
166
+ if (typeof importPath !== "string") return skipTrue;
167
+
168
+ // finds the full path of the import
169
+ const resolvedImportPath = resolveImportingPath(
170
+ path.dirname(context.filename),
171
+ importPath,
172
+ findUpSync("tsconfig.json", {
173
+ cwd: path.dirname(context.filename),
174
+ }) ?? context.cwd
175
+ );
176
+
177
+ // does not operate on paths it did not resolve
178
+ if (resolvedImportPath === null) return skipTrue;
179
+ // does not operate on non-JS files
180
+ const isImportedFileJS = EXTENSIONS.some((ext) =>
181
+ resolvedImportPath.endsWith(ext)
182
+ );
183
+ if (!isImportedFileJS) return skipTrue;
184
+
185
+ // GETTING THE DIRECTIVE (or lack thereof) OF THE IMPORTED FILE
186
+ const importedFileDirective =
187
+ getDirectiveFromImportedModule(resolvedImportPath) ?? NO_DIRECTIVE;
188
+
189
+ // GETTING THE EXTENSION OF THE IMPORTED FILE
190
+ const importedFileFileExtension = path.extname(resolvedImportPath);
191
+
192
+ // GETTING THE EFFECTIVE DIRECTIVE (no lack thereof) OF THE IMPORTED FILE
193
+ const importedFileEffectiveDirective = getEffectiveDirective(
194
+ importedFileDirective,
195
+ importedFileFileExtension
196
+ );
197
+
198
+ // also fails if one of the seven effective directives has not been obtained
199
+ if (importedFileEffectiveDirective === null) {
200
+ console.error("ERROR. Effective directive should never be null.");
201
+ return skipTrue;
202
+ }
203
+
204
+ // For now skipping on both "does not operate" (which should ignore) and "fails" (which should crash) albeit with console.error.
205
+
206
+ return { skip: undefined, importedFileEffectiveDirective };
207
+ } else return skipTrue;
208
+ };
209
+
147
210
  /* importsFlow */
148
211
 
149
212
  /** The full flow for import traversals to enforce effective directives import rules.
@@ -184,6 +247,46 @@ export const importsFlow = (context, node, currentFileEffectiveDirective) => {
184
247
  }
185
248
  };
186
249
 
250
+ // NEW!! Currently strictly adapted from importsFlow
251
+ /** The `importsFlow` adapted for `require` calls to enforce effective directives import rules.
252
+ * @param {Context} context The ESLint rule's `context` object.
253
+ * @param {CallExpression} node The ESLint `node` of the rule's current traversal.
254
+ * @param {EffectiveDirective} currentFileEffectiveDirective The current file's effective directive.
255
+ * @returns Early if the flow needs to be interrupted.
256
+ */
257
+ export const importsFlowRequire = (
258
+ context,
259
+ node,
260
+ currentFileEffectiveDirective
261
+ ) => {
262
+ const result = importedFileFlowRequire(context, node);
263
+
264
+ if (result.skip) return;
265
+ const { importedFileEffectiveDirective } = result;
266
+
267
+ if (
268
+ isImportBlocked(
269
+ currentFileEffectiveDirective,
270
+ importedFileEffectiveDirective
271
+ )
272
+ ) {
273
+ context.report({
274
+ node,
275
+ messageId: importBreaksEffectiveImportRulesMessageId,
276
+ data: {
277
+ [effectiveDirectiveMessage]:
278
+ makeMessageFromCurrentFileEffectiveDirective(
279
+ currentFileEffectiveDirective
280
+ ),
281
+ [specificViolationMessage]: findSpecificViolationMessage(
282
+ currentFileEffectiveDirective,
283
+ importedFileEffectiveDirective
284
+ ),
285
+ },
286
+ });
287
+ }
288
+ };
289
+
187
290
  /* reExportsFlow */
188
291
 
189
292
  /** The full flow for export traversals, shared between `ExportNamedDeclaration` and `ExportAllDeclaration`, to ensure same effective directive re-exports.
@@ -24,6 +24,7 @@ import {
24
24
  currentFileFlow,
25
25
  importsFlow,
26
26
  allExportsFlow,
27
+ importsFlowRequire,
27
28
  } from "../utilities/flows.js";
28
29
 
29
30
  /**
@@ -73,6 +74,8 @@ Please include a Strategy that corresponds to the kind of module this export wou
73
74
  allExportsFlow(context, node, verifiedCommentedDirective),
74
75
  ExportDefaultDeclaration: (node) =>
75
76
  allExportsFlow(context, node, verifiedCommentedDirective),
77
+ CallExpression: (node) =>
78
+ importsFlowRequire(context, node, verifiedCommentedDirective),
76
79
  };
77
80
  },
78
81
  };
@@ -52,11 +52,72 @@ import { analyzeExportsForReExports } from "./analyze-exports-re.js";
52
52
  * @typedef {import('../../../../types/directive21/_commons/typedefs.js').ExportNamedDeclaration} ExportNamedDeclaration
53
53
  * @typedef {import('../../../../types/directive21/_commons/typedefs.js').ExportAllDeclaration} ExportAllDeclaration
54
54
  * @typedef {import('../../../../types/directive21/_commons/typedefs.js').ExportDefaultDeclaration} ExportDefaultDeclaration
55
+ * @typedef {import('../../../../types/directive21/_commons/typedefs.js').CallExpression} CallExpression
55
56
  * @typedef {import('../../../../types/directive21/_commons/typedefs.js').Environment} Environment
56
57
  */
57
58
 
58
59
  /* currentFileFlow */
59
60
 
61
+ // copied from eXtra JSX (further proving that all core constants and utilities from eXtra JSX should live inside use-agnostic in v2)
62
+
63
+ /**
64
+ * @type {readonly [".x.jsx", ".x.cjsx", ".x.mjsx", ".x.tsx", ".x.ctsx", ".x.mtsx"]}
65
+ */
66
+ export const eXtraJsxExtensions = Object.freeze([
67
+ ".x.jsx",
68
+ ".x.cjsx",
69
+ ".x.mjsx",
70
+ ".x.tsx",
71
+ ".x.ctsx",
72
+ ".x.mtsx",
73
+ ]);
74
+
75
+ /**
76
+ * @type {readonly [".x.js", ".x.cjs", ".x.mjs", ".x.ts", ".x.cts", ".x.mts"]}
77
+ */
78
+ export const eXtraJsExtensions = Object.freeze([
79
+ ".x.js",
80
+ ".x.cjs",
81
+ ".x.mjs",
82
+ ".x.ts",
83
+ ".x.cts",
84
+ ".x.mts",
85
+ ]);
86
+
87
+ /**
88
+ * @type {readonly [".x.jsx", ".x.cjsx", ".x.mjsx", ".x.tsx", ".x.ctsx", ".x.mtsx", ".x.js", ".x.cjs", ".x.mjs", ".x.ts", ".x.cts", ".x.mts"]}
89
+ */
90
+ export const extraJavaScriptExtensions = Object.freeze([
91
+ ...eXtraJsxExtensions,
92
+ ...eXtraJsExtensions,
93
+ ]);
94
+
95
+ /**
96
+ * $COMMENT#JSDOC#CORE#DEFS#FILEISANYJAVASCRIPT
97
+ * @param {string} filePath $COMMENT#JSDOC#CORE#PARAMS#FILEPATH
98
+ * @returns $COMMENT#JSDOC#CORE#RETURNS#FILEISANYJAVASCRIPT
99
+ */
100
+ export const fileIsAnyJavaScript = (filePath) =>
101
+ EXTENSIONS.some((e) => filePath.endsWith(e));
102
+
103
+ /**
104
+ * $COMMENT#JSDOC#CORE#DEFS#FILEISEXTRAJAVASCRIPT
105
+ * @param {string} filePath $COMMENT#JSDOC#CORE#PARAMS#FILEPATH
106
+ * @returns $COMMENT#JSDOC#CORE#RETURNS#FILEISEXTRAJAVASCRIPT
107
+ */
108
+ export const fileIsExtraJavaScript = (filePath) =>
109
+ extraJavaScriptExtensions.some((e) => filePath.endsWith(e));
110
+
111
+ /**
112
+ * $COMMENT#JSDOC#CORE#DEFS#FILEISREGULARJAVASCRIPT
113
+ * @param {string} filePath $COMMENT#JSDOC#CORE#PARAMS#FILEPATH
114
+ * @returns $COMMENT#JSDOC#CORE#RETURNS#FILEISREGULARJAVASCRIPT
115
+ */
116
+ export const fileIsRegularJavaScript = (filePath) =>
117
+ fileIsAnyJavaScript(filePath) && !fileIsExtraJavaScript(filePath);
118
+
119
+ //
120
+
60
121
  /**
61
122
  * The flow that begins the import rules enforcement rule, retrieving the verified commented directive of the current file before comparing it to upcoming verified commented directives of the files it imports.
62
123
  * @param {Context} context The ESLint rule's `context` object.
@@ -130,16 +191,24 @@ export const currentFileFlow = (context) => {
130
191
  return { skip: undefined, verifiedCommentedDirective }; // at this time, behaves as if the new implementation didn't exist yet
131
192
  }
132
193
 
133
- context.report({
134
- loc: highlightFirstLineOfCode(context),
135
- messageId: commentedDirectiveReactDirectiveFailedMessageId,
136
- data: {
137
- // verifiedCommentedDirective
138
- verifiedCommentedDirective,
139
- // expectedReactDirectiveAsText
140
- expectedReactDirectiveAsText,
141
- },
142
- });
194
+ // NEW
195
+ // do not report if the module is a non-Extra JavaScript Agnostic Strategies Module, in order to allow them the freedom of doing whatever they want so they can behave in any which way they need to as convention files
196
+ if (
197
+ !(
198
+ fileIsRegularJavaScript(context.filename) &&
199
+ verifiedCommentedDirective === USE_AGNOSTIC_STRATEGIES
200
+ )
201
+ )
202
+ context.report({
203
+ loc: highlightFirstLineOfCode(context),
204
+ messageId: commentedDirectiveReactDirectiveFailedMessageId,
205
+ data: {
206
+ // verifiedCommentedDirective
207
+ verifiedCommentedDirective,
208
+ // expectedReactDirectiveAsText
209
+ expectedReactDirectiveAsText,
210
+ },
211
+ });
143
212
  return skipTrue;
144
213
  }
145
214
 
@@ -208,7 +277,10 @@ const importedFileFlow = (context, node) => {
208
277
  node
209
278
  );
210
279
 
211
- if (importingFileCommentedDirective === null) {
280
+ if (
281
+ importingFileCommentedDirective === null &&
282
+ fileIsExtraJavaScript(context.filename)
283
+ ) {
212
284
  context.report({
213
285
  node,
214
286
  messageId: importNotStrategizedMessageId,
@@ -243,10 +315,120 @@ const importedFileFlow = (context, node) => {
243
315
  };
244
316
  };
245
317
 
318
+ // NEW!! Currently strictly adapted from importedFileFlow
319
+ /**
320
+ * The `importedFileFlow` adapted for `require` calls to obtain the import file's commented directive.
321
+ * @param {Context} context The ESLint rule's `context` object.
322
+ * @param {CallExpression} node The ESLint `node` of the rule's current traversal.
323
+ * @returns Either an object with `skip: true` to disregard or one with the non-null `importedFileCommentedDirective`. And now with the added results of `analyzeExportsForReExports`.
324
+ */
325
+ const importedFileFlowRequire = (context, node) => {
326
+ const skipTrue = {
327
+ ...skip,
328
+ importedFileCommentedDirective: undefined,
329
+ analyzeExportsForReExportsResults: undefined,
330
+ };
331
+
332
+ if (
333
+ node.callee.type === "Identifier" &&
334
+ node.callee.name === "require" &&
335
+ node.arguments.length === 1 &&
336
+ node.arguments[0].type === "Literal"
337
+ ) {
338
+ const importPath = node.arguments[0].value;
339
+
340
+ if (typeof importPath !== "string") return skipTrue;
341
+
342
+ // finds the full path of the import
343
+ const resolvedImportPath = resolveImportingPath(
344
+ path.dirname(context.filename),
345
+ importPath,
346
+ findUpSync("tsconfig.json", {
347
+ cwd: path.dirname(context.filename),
348
+ }) ?? context.cwd
349
+ );
350
+
351
+ // does not operate on paths it did not resolve
352
+ if (resolvedImportPath === null) return skipTrue;
353
+ // does not operate on non-JS files
354
+ const isImportedFileJS = EXTENSIONS.some((ext) =>
355
+ resolvedImportPath.endsWith(ext)
356
+ );
357
+ if (!isImportedFileJS) return skipTrue;
358
+
359
+ // GETTING THE DIRECTIVE (or lack thereof) OF THE IMPORTED FILE
360
+ let {
361
+ commentedDirective: importedFileCommentedDirective,
362
+ sourceCode: importedFileSourceCode,
363
+ } = getCommentedDirectiveFromImportedModule(resolvedImportPath);
364
+
365
+ // returns early if there is no directive or no valid directive (same, but eventually no directive could have defaults)
366
+ if (!importedFileCommentedDirective) {
367
+ // Now silencing the warning as superfluous, in order to not warn on imports of files without a commented directive that are outside of linting range.
368
+
369
+ // console.warn(
370
+ // `WARNING. The imported file ${resolvedImportPath}, whose path has been resolved from ${context.filename}, has no commented directive. It is thus ignored since the report on that circumstance would be available on the imported file itself.`
371
+ // ); // The decision not to report has been taken to not inflate the number of warnings.
372
+ return skipTrue;
373
+ }
374
+
375
+ /* GETTING THE CORRECT DIRECTIVE INTERPRETATION OF STRATEGY FOR AGNOSTIC STRATEGIES MODULES IMPORTS.
376
+ 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.
377
+
378
+ After a short attempt, the feature to address this (crossingStrategies) is currently canceled, mainly due to the exponential complexity provided by the different ways in which exports can be made in JavaScript.
379
+
380
+ (Consequently, details below are currently at the stage of wishful thinking.)
381
+ 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. */
382
+
383
+ if (importedFileCommentedDirective === USE_AGNOSTIC_STRATEGIES) {
384
+ const importingFileCommentedDirective = getStrategizedDirective(
385
+ context,
386
+ node
387
+ );
388
+
389
+ if (
390
+ importingFileCommentedDirective === null &&
391
+ fileIsExtraJavaScript(context.filename)
392
+ ) {
393
+ context.report({
394
+ node,
395
+ messageId: importNotStrategizedMessageId,
396
+ });
397
+ return skipTrue;
398
+ }
399
+
400
+ // 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.
401
+ importedFileCommentedDirective = importingFileCommentedDirective;
402
+ }
403
+
404
+ // you never know
405
+ if (!importedFileSourceCode) {
406
+ console.warn(
407
+ `Somehow, file "${resolvedImportPath}" does not have a SourceCode object obtainable.`
408
+ );
409
+ return {
410
+ skip: undefined,
411
+ importedFileCommentedDirective,
412
+ analyzeExportsForReExportsResults: undefined,
413
+ };
414
+ }
415
+
416
+ const analyzeExportsForReExportsResults = analyzeExportsForReExports(
417
+ importedFileSourceCode
418
+ );
419
+
420
+ return {
421
+ skip: undefined,
422
+ importedFileCommentedDirective,
423
+ analyzeExportsForReExportsResults,
424
+ };
425
+ } else return skipTrue;
426
+ };
427
+
246
428
  /* importsFlow */
247
429
 
248
430
  /**
249
- * The full flow for import traversals to enforce effective directives import rules.
431
+ * The full flow for import traversals to enforce commented directives import rules.
250
432
  * @param {Context} context The ESLint rule's `context` object.
251
433
  * @param {ImportDeclaration} node The ESLint `node` of the rule's current traversal.
252
434
  * @param {CommentedDirective} currentFileCommentedDirective The current file's commented directive.
@@ -286,7 +468,82 @@ export const importsFlow = (context, node, currentFileCommentedDirective) => {
286
468
  });
287
469
  }
288
470
 
289
- // NEW
471
+ if (result.analyzeExportsForReExportsResults) {
472
+ const { reExportsWithSource, reExportsViaLocal } =
473
+ result.analyzeExportsForReExportsResults;
474
+
475
+ // immediately returns if no re-exports are found
476
+ if (reExportsWithSource.length === 0 && reExportsViaLocal.length === 0)
477
+ return;
478
+
479
+ /** @type {Environment} */
480
+ const currentFileEnvironment = currentFileCommentedDirective.split(" ")[1];
481
+ /** @type {Environment} */
482
+ const importedFileEnvironment =
483
+ importedFileCommentedDirective.split(" ")[1];
484
+
485
+ if (
486
+ !environments_allowedChainImportEnvironments[
487
+ currentFileEnvironment
488
+ ].includes(importedFileEnvironment)
489
+ ) {
490
+ context.report({
491
+ node,
492
+ messageId: cantChainImportAcrossEnvironmentsMessageId,
493
+ data: {
494
+ // currentFileEnvironment:
495
+ currentFileEnvironment,
496
+ // importedFileEnvironment:
497
+ importedFileEnvironment,
498
+ },
499
+ });
500
+ }
501
+ }
502
+ };
503
+
504
+ // NEW!! Currently strictly adapted from importsFlow
505
+ /**
506
+ * The `importsFlow` adapted for `require` calls to enforce commented directives import rules.
507
+ * @param {Context} context The ESLint rule's `context` object.
508
+ * @param {CallExpression} node The ESLint `node` of the rule's current traversal.
509
+ * @param {CommentedDirective} currentFileCommentedDirective The current file's commented directive.
510
+ * @returns Early if the flow needs to be interrupted.
511
+ */
512
+ export const importsFlowRequire = (
513
+ context,
514
+ node,
515
+ currentFileCommentedDirective
516
+ ) => {
517
+ const result = importedFileFlowRequire(context, node);
518
+
519
+ if (result.skip) return;
520
+ const { importedFileCommentedDirective } = result;
521
+
522
+ // returns early is the current file is an Agnostic Strategies Module
523
+ if (currentFileCommentedDirective === USE_AGNOSTIC_STRATEGIES) return;
524
+
525
+ if (
526
+ isImportBlocked(
527
+ currentFileCommentedDirective,
528
+ importedFileCommentedDirective
529
+ )
530
+ ) {
531
+ context.report({
532
+ node,
533
+ messageId: importBreaksCommentedImportRulesMessageId,
534
+ data: {
535
+ [commentedDirectiveMessage]:
536
+ makeMessageFromCurrentFileCommentedDirective(
537
+ currentFileCommentedDirective
538
+ ),
539
+ [specificViolationMessage]: findSpecificViolationMessage(
540
+ currentFileCommentedDirective,
541
+ importedFileCommentedDirective
542
+ ),
543
+ },
544
+ });
545
+ }
546
+
290
547
  if (result.analyzeExportsForReExportsResults) {
291
548
  const { reExportsWithSource, reExportsViaLocal } =
292
549
  result.analyzeExportsForReExportsResults;
@@ -245,6 +245,66 @@ export const getStrategizedDirective = (context, node) => {
245
245
 
246
246
  /* addressDirectiveIfAgnosticStrategies */
247
247
 
248
+ // copied from eXtra JSX (further proving that all core constants and utilities from eXtra JSX should live inside use-agnostic in v2)
249
+
250
+ /**
251
+ * @type {readonly [".x.jsx", ".x.cjsx", ".x.mjsx", ".x.tsx", ".x.ctsx", ".x.mtsx"]}
252
+ */
253
+ export const eXtraJsxExtensions = Object.freeze([
254
+ ".x.jsx",
255
+ ".x.cjsx",
256
+ ".x.mjsx",
257
+ ".x.tsx",
258
+ ".x.ctsx",
259
+ ".x.mtsx",
260
+ ]);
261
+
262
+ /**
263
+ * @type {readonly [".x.js", ".x.cjs", ".x.mjs", ".x.ts", ".x.cts", ".x.mts"]}
264
+ */
265
+ export const eXtraJsExtensions = Object.freeze([
266
+ ".x.js",
267
+ ".x.cjs",
268
+ ".x.mjs",
269
+ ".x.ts",
270
+ ".x.cts",
271
+ ".x.mts",
272
+ ]);
273
+
274
+ /**
275
+ * @type {readonly [".x.jsx", ".x.cjsx", ".x.mjsx", ".x.tsx", ".x.ctsx", ".x.mtsx", ".x.js", ".x.cjs", ".x.mjs", ".x.ts", ".x.cts", ".x.mts"]}
276
+ */
277
+ export const extraJavaScriptExtensions = Object.freeze([
278
+ ...eXtraJsxExtensions,
279
+ ...eXtraJsExtensions,
280
+ ]);
281
+
282
+ /**
283
+ * $COMMENT#JSDOC#CORE#DEFS#FILEISANYJAVASCRIPT
284
+ * @param {string} filePath $COMMENT#JSDOC#CORE#PARAMS#FILEPATH
285
+ * @returns $COMMENT#JSDOC#CORE#RETURNS#FILEISANYJAVASCRIPT
286
+ */
287
+ export const fileIsAnyJavaScript = (filePath) =>
288
+ EXTENSIONS.some((e) => filePath.endsWith(e));
289
+
290
+ /**
291
+ * $COMMENT#JSDOC#CORE#DEFS#FILEISEXTRAJAVASCRIPT
292
+ * @param {string} filePath $COMMENT#JSDOC#CORE#PARAMS#FILEPATH
293
+ * @returns $COMMENT#JSDOC#CORE#RETURNS#FILEISEXTRAJAVASCRIPT
294
+ */
295
+ export const fileIsExtraJavaScript = (filePath) =>
296
+ extraJavaScriptExtensions.some((e) => filePath.endsWith(e));
297
+
298
+ /**
299
+ * $COMMENT#JSDOC#CORE#DEFS#FILEISREGULARJAVASCRIPT
300
+ * @param {string} filePath $COMMENT#JSDOC#CORE#PARAMS#FILEPATH
301
+ * @returns $COMMENT#JSDOC#CORE#RETURNS#FILEISREGULARJAVASCRIPT
302
+ */
303
+ export const fileIsRegularJavaScript = (filePath) =>
304
+ fileIsAnyJavaScript(filePath) && !fileIsExtraJavaScript(filePath);
305
+
306
+ //
307
+
248
308
  /**
249
309
  * Verifies the current node's export strategy if the current commented directive is `"use agnostic strategies"` by reporting `exportNotStrategized` in case an export is not strategized in an Agnostic Strategies Module.
250
310
  * @param {Context} context The ESLint rule's `context` object.
@@ -263,7 +323,10 @@ export const addressDirectiveIfAgnosticStrategies = (
263
323
 
264
324
  const exportStrategizedDirective = getStrategizedDirective(context, node);
265
325
 
266
- if (exportStrategizedDirective === null) {
326
+ if (
327
+ exportStrategizedDirective === null &&
328
+ fileIsExtraJavaScript(context.filename)
329
+ ) {
267
330
  context.report({
268
331
  node,
269
332
  messageId: exportNotStrategizedMessageId,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-use-agnostic",
3
- "version": "1.7.5",
3
+ "version": "1.7.9",
4
4
  "description": "Highlights problematic server-client imports in projects made with the Fullstack React Architecture.",
5
5
  "keywords": [
6
6
  "eslint",