eslint-plugin-use-agnostic 1.7.6 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -10,7 +10,7 @@ import {
10
10
  noCommentedDirectiveMessageId,
11
11
  commentedDirectiveVerificationFailedMessageId,
12
12
  commentedDirectiveReactDirectiveFailedMessageId,
13
- importNotStrategizedMessageId,
13
+ // importNotStrategizedMessageId,
14
14
  cantChainImportAcrossEnvironmentsMessageId,
15
15
  skip,
16
16
  } from "../../../_commons/constants/bases.js";
@@ -40,7 +40,7 @@ import {
40
40
  isImportBlocked,
41
41
  makeMessageFromCurrentFileCommentedDirective,
42
42
  findSpecificViolationMessage,
43
- getStrategizedDirective,
43
+ // getStrategizedDirective,
44
44
  addressDirectiveIfAgnosticStrategies,
45
45
  } from "./helpers.js";
46
46
  import { analyzeExportsForReExports } from "./analyze-exports-re.js";
@@ -52,12 +52,13 @@ 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
 
60
- // copied from eXtra JSX (further proving that all core constants and utilities from eXtra JSX should live inside use-agnostic)
61
+ // copied from eXtra JSX (further proving that all core constants and utilities from eXtra JSX should live inside use-agnostic in v2)
61
62
 
62
63
  /**
63
64
  * @type {readonly [".x.jsx", ".x.cjsx", ".x.mjsx", ".x.tsx", ".x.ctsx", ".x.mtsx"]}
@@ -191,13 +192,12 @@ export const currentFileFlow = (context) => {
191
192
  }
192
193
 
193
194
  // NEW
194
- // 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
195
- if (
196
- !(
197
- fileIsRegularJavaScript(context.filename) &&
198
- verifiedCommentedDirective === USE_AGNOSTIC_STRATEGIES
199
- )
200
- )
195
+ const isRegularJavaScriptAgnosticStrategies =
196
+ fileIsRegularJavaScript(context.filename) &&
197
+ verifiedCommentedDirective === USE_AGNOSTIC_STRATEGIES;
198
+
199
+ // 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 (JSX extension still required though)
200
+ if (!isRegularJavaScriptAgnosticStrategies)
201
201
  context.report({
202
202
  loc: highlightFirstLineOfCode(context),
203
203
  messageId: commentedDirectiveReactDirectiveFailedMessageId,
@@ -270,23 +270,29 @@ const importedFileFlow = (context, node) => {
270
270
  (Consequently, details below are currently at the stage of wishful thinking.)
271
271
  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. */
272
272
 
273
- if (importedFileCommentedDirective === USE_AGNOSTIC_STRATEGIES) {
274
- const importingFileCommentedDirective = getStrategizedDirective(
275
- context,
276
- node
277
- );
278
-
279
- if (importingFileCommentedDirective === null) {
280
- context.report({
281
- node,
282
- messageId: importNotStrategizedMessageId,
283
- });
284
- return skipTrue;
285
- }
286
-
287
- // 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.
288
- importedFileCommentedDirective = importingFileCommentedDirective;
289
- }
273
+ // NEW!!
274
+ // No changes anymore. Agnostic Strategies Modules from now on are going to be considered regularly checked module that simply CANNOT be imported anywhere.
275
+
276
+ // if (importedFileCommentedDirective === USE_AGNOSTIC_STRATEGIES) {
277
+ // const importingFileCommentedDirective = getStrategizedDirective(
278
+ // context,
279
+ // node
280
+ // );
281
+
282
+ // if (
283
+ // importingFileCommentedDirective === null &&
284
+ // fileIsExtraJavaScript(context.filename)
285
+ // ) {
286
+ // context.report({
287
+ // node,
288
+ // messageId: importNotStrategizedMessageId,
289
+ // });
290
+ // return skipTrue;
291
+ // }
292
+
293
+ // // 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.
294
+ // importedFileCommentedDirective = importingFileCommentedDirective;
295
+ // }
290
296
 
291
297
  // you never know
292
298
  if (!importedFileSourceCode) {
@@ -311,10 +317,120 @@ const importedFileFlow = (context, node) => {
311
317
  };
312
318
  };
313
319
 
320
+ // NEW!! Currently strictly adapted from importedFileFlow
321
+ /**
322
+ * The `importedFileFlow` adapted for `require` calls to obtain the import file's commented directive.
323
+ * @param {Context} context The ESLint rule's `context` object.
324
+ * @param {CallExpression} node The ESLint `node` of the rule's current traversal.
325
+ * @returns Either an object with `skip: true` to disregard or one with the non-null `importedFileCommentedDirective`. And now with the added results of `analyzeExportsForReExports`.
326
+ */
327
+ const importedFileFlowRequire = (context, node) => {
328
+ const skipTrue = {
329
+ ...skip,
330
+ importedFileCommentedDirective: undefined,
331
+ analyzeExportsForReExportsResults: undefined,
332
+ };
333
+
334
+ if (
335
+ node.callee.type === "Identifier" &&
336
+ node.callee.name === "require" &&
337
+ node.arguments.length === 1 &&
338
+ node.arguments[0].type === "Literal"
339
+ ) {
340
+ const importPath = node.arguments[0].value;
341
+
342
+ if (typeof importPath !== "string") return skipTrue;
343
+
344
+ // finds the full path of the import
345
+ const resolvedImportPath = resolveImportingPath(
346
+ path.dirname(context.filename),
347
+ importPath,
348
+ findUpSync("tsconfig.json", {
349
+ cwd: path.dirname(context.filename),
350
+ }) ?? context.cwd
351
+ );
352
+
353
+ // does not operate on paths it did not resolve
354
+ if (resolvedImportPath === null) return skipTrue;
355
+ // does not operate on non-JS files
356
+ const isImportedFileJS = EXTENSIONS.some((ext) =>
357
+ resolvedImportPath.endsWith(ext)
358
+ );
359
+ if (!isImportedFileJS) return skipTrue;
360
+
361
+ // GETTING THE DIRECTIVE (or lack thereof) OF THE IMPORTED FILE
362
+ let {
363
+ commentedDirective: importedFileCommentedDirective,
364
+ sourceCode: importedFileSourceCode,
365
+ } = getCommentedDirectiveFromImportedModule(resolvedImportPath);
366
+
367
+ // returns early if there is no directive or no valid directive (same, but eventually no directive could have defaults)
368
+ if (!importedFileCommentedDirective) {
369
+ // 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.
370
+
371
+ // console.warn(
372
+ // `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.`
373
+ // ); // The decision not to report has been taken to not inflate the number of warnings.
374
+ return skipTrue;
375
+ }
376
+
377
+ /* GETTING THE CORRECT DIRECTIVE INTERPRETATION OF STRATEGY FOR AGNOSTIC STRATEGIES MODULES IMPORTS.
378
+ 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.
379
+
380
+ 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.
381
+
382
+ (Consequently, details below are currently at the stage of wishful thinking.)
383
+ 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. */
384
+
385
+ // if (importedFileCommentedDirective === USE_AGNOSTIC_STRATEGIES) {
386
+ // const importingFileCommentedDirective = getStrategizedDirective(
387
+ // context,
388
+ // node
389
+ // );
390
+
391
+ // if (
392
+ // importingFileCommentedDirective === null &&
393
+ // fileIsExtraJavaScript(context.filename)
394
+ // ) {
395
+ // context.report({
396
+ // node,
397
+ // messageId: importNotStrategizedMessageId,
398
+ // });
399
+ // return skipTrue;
400
+ // }
401
+
402
+ // // 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.
403
+ // importedFileCommentedDirective = importingFileCommentedDirective;
404
+ // }
405
+
406
+ // you never know
407
+ if (!importedFileSourceCode) {
408
+ console.warn(
409
+ `Somehow, file "${resolvedImportPath}" does not have a SourceCode object obtainable.`
410
+ );
411
+ return {
412
+ skip: undefined,
413
+ importedFileCommentedDirective,
414
+ analyzeExportsForReExportsResults: undefined,
415
+ };
416
+ }
417
+
418
+ const analyzeExportsForReExportsResults = analyzeExportsForReExports(
419
+ importedFileSourceCode
420
+ );
421
+
422
+ return {
423
+ skip: undefined,
424
+ importedFileCommentedDirective,
425
+ analyzeExportsForReExportsResults,
426
+ };
427
+ } else return skipTrue;
428
+ };
429
+
314
430
  /* importsFlow */
315
431
 
316
432
  /**
317
- * The full flow for import traversals to enforce effective directives import rules.
433
+ * The full flow for import traversals to enforce commented directives import rules.
318
434
  * @param {Context} context The ESLint rule's `context` object.
319
435
  * @param {ImportDeclaration} node The ESLint `node` of the rule's current traversal.
320
436
  * @param {CommentedDirective} currentFileCommentedDirective The current file's commented directive.
@@ -329,8 +445,84 @@ export const importsFlow = (context, node, currentFileCommentedDirective) => {
329
445
  if (result.skip) return;
330
446
  const { importedFileCommentedDirective } = result;
331
447
 
332
- // returns early is the current file is an Agnostic Strategies Module
333
- if (currentFileCommentedDirective === USE_AGNOSTIC_STRATEGIES) return;
448
+ // returns early is the current file is an Agnostic Strategies Module // not anymore
449
+ // if (currentFileCommentedDirective === USE_AGNOSTIC_STRATEGIES) return;
450
+
451
+ if (
452
+ isImportBlocked(
453
+ currentFileCommentedDirective,
454
+ importedFileCommentedDirective
455
+ )
456
+ ) {
457
+ context.report({
458
+ node,
459
+ messageId: importBreaksCommentedImportRulesMessageId,
460
+ data: {
461
+ [commentedDirectiveMessage]:
462
+ makeMessageFromCurrentFileCommentedDirective(
463
+ currentFileCommentedDirective
464
+ ),
465
+ [specificViolationMessage]: findSpecificViolationMessage(
466
+ currentFileCommentedDirective,
467
+ importedFileCommentedDirective
468
+ ),
469
+ },
470
+ });
471
+ }
472
+
473
+ if (result.analyzeExportsForReExportsResults) {
474
+ const { reExportsWithSource, reExportsViaLocal } =
475
+ result.analyzeExportsForReExportsResults;
476
+
477
+ // immediately returns if no re-exports are found
478
+ if (reExportsWithSource.length === 0 && reExportsViaLocal.length === 0)
479
+ return;
480
+
481
+ /** @type {Environment} */
482
+ const currentFileEnvironment = currentFileCommentedDirective.split(" ")[1];
483
+ /** @type {Environment} */
484
+ const importedFileEnvironment =
485
+ importedFileCommentedDirective.split(" ")[1];
486
+
487
+ if (
488
+ !environments_allowedChainImportEnvironments[
489
+ currentFileEnvironment
490
+ ].includes(importedFileEnvironment)
491
+ ) {
492
+ context.report({
493
+ node,
494
+ messageId: cantChainImportAcrossEnvironmentsMessageId,
495
+ data: {
496
+ // currentFileEnvironment:
497
+ currentFileEnvironment,
498
+ // importedFileEnvironment:
499
+ importedFileEnvironment,
500
+ },
501
+ });
502
+ }
503
+ }
504
+ };
505
+
506
+ // NEW!! Currently strictly adapted from importsFlow
507
+ /**
508
+ * The `importsFlow` adapted for `require` calls to enforce commented directives import rules.
509
+ * @param {Context} context The ESLint rule's `context` object.
510
+ * @param {CallExpression} node The ESLint `node` of the rule's current traversal.
511
+ * @param {CommentedDirective} currentFileCommentedDirective The current file's commented directive.
512
+ * @returns Early if the flow needs to be interrupted.
513
+ */
514
+ export const importsFlowRequire = (
515
+ context,
516
+ node,
517
+ currentFileCommentedDirective
518
+ ) => {
519
+ const result = importedFileFlowRequire(context, node);
520
+
521
+ if (result.skip) return;
522
+ const { importedFileCommentedDirective } = result;
523
+
524
+ // returns early is the current file is an Agnostic Strategies Module // not anymore
525
+ // if (currentFileCommentedDirective === USE_AGNOSTIC_STRATEGIES) return;
334
526
 
335
527
  if (
336
528
  isImportBlocked(
@@ -354,7 +546,6 @@ export const importsFlow = (context, node, currentFileCommentedDirective) => {
354
546
  });
355
547
  }
356
548
 
357
- // NEW
358
549
  if (result.analyzeExportsForReExportsResults) {
359
550
  const { reExportsWithSource, reExportsViaLocal } =
360
551
  result.analyzeExportsForReExportsResults;
@@ -1,6 +1,6 @@
1
1
  import { getSourceCodeFromFilePath } from "get-sourcecode-from-file-path";
2
2
 
3
- import { exportNotStrategizedMessageId } from "../../../_commons/constants/bases.js";
3
+ // import { exportNotStrategizedMessageId } from "../../../_commons/constants/bases.js";
4
4
  import {
5
5
  USE_AGNOSTIC_STRATEGIES,
6
6
  commentedDirectivesArray,
@@ -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,12 +323,20 @@ export const addressDirectiveIfAgnosticStrategies = (
263
323
 
264
324
  const exportStrategizedDirective = getStrategizedDirective(context, node);
265
325
 
266
- if (exportStrategizedDirective === null) {
267
- context.report({
268
- node,
269
- messageId: exportNotStrategizedMessageId,
270
- });
271
- }
326
+ // NEW!!
327
+ // Now entirely neutralized. Agnostic Strategies Modules are now going to be vetted module just like the others from now on.
328
+ // BUT!!
329
+ // Still acknowledges ongoing strategies since they are indeed still acknowledged, though in a unreliable way, by the eXtra JSX's TypeScript server plugin.
330
+
331
+ // if (
332
+ // exportStrategizedDirective === null &&
333
+ // fileIsExtraJavaScript(context.filename)
334
+ // ) {
335
+ // context.report({
336
+ // node,
337
+ // messageId: exportNotStrategizedMessageId,
338
+ // });
339
+ // }
272
340
 
273
341
  return exportStrategizedDirective; // null indicates failure
274
342
  };
@@ -277,8 +345,8 @@ export const addressDirectiveIfAgnosticStrategies = (
277
345
 
278
346
  /**
279
347
  * Returns a boolean deciding if an imported file's commented directive is incompatible with the current file's commented directive.
280
- * @param {CommentedDirectiveWithoutUseAgnosticStrategies} currentFileCommentedDirective The current file's commented directive.
281
- * @param {CommentedDirectiveWithoutUseAgnosticStrategies} importedFileCommentedDirective The imported file's commented directive.
348
+ * @param {CommentedDirective} currentFileCommentedDirective The current file's commented directive.
349
+ * @param {CommentedDirective} importedFileCommentedDirective The imported file's commented directive.
282
350
  * @returns `true` if the import is blocked, as established in `commentedDirectives_BlockedImports`.
283
351
  */
284
352
  export const isImportBlocked = (
@@ -310,8 +378,8 @@ export const makeMessageFromCurrentFileCommentedDirective = (
310
378
 
311
379
  /**
312
380
  * Finds the `message` for the specific violation of commented directives import rules based on `commentedDirectives_BlockedImports`.
313
- * @param {CommentedDirectiveWithoutUseAgnosticStrategies} currentFileCommentedDirective The current file's commented directive.
314
- * @param {CommentedDirectiveWithoutUseAgnosticStrategies} importedFileCommentedDirective The imported file's commented directive.
381
+ * @param {CommentedDirective} currentFileCommentedDirective The current file's commented directive.
382
+ * @param {CommentedDirective} importedFileCommentedDirective The imported file's commented directive.
315
383
  * @returns The corresponding `message`.
316
384
  */
317
385
  export const findSpecificViolationMessage = (
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-use-agnostic",
3
- "version": "1.7.6",
3
+ "version": "1.8.0",
4
4
  "description": "Highlights problematic server-client imports in projects made with the Fullstack React Architecture.",
5
5
  "keywords": [
6
6
  "eslint",