eslint-plugin-use-agnostic 0.10.6 → 0.11.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.
package/README.md CHANGED
@@ -74,9 +74,7 @@ With this list established, it thus becomes possible to recognize static import
74
74
 
75
75
  ## Caveats
76
76
 
77
- Only the first line of code in a file is observed for the presence of a directive. If no top-of-the-file directive is present or recognized, the file is considered to not have a directive, defaulting to being understood as a Server Logics Module if it doesn't use a JSX file extension (`.js`, `.ts`) or as a Server Components Module if it does (`.jsx`, `.tsx`).
78
-
79
- 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, since the resolution depends on the `cwd` property from ESLint rules' `context` objects.
77
+ Base url and aliased import paths are currently resolved under the assumption that `process.cwd()` and `context.cwd` have the same value.
80
78
 
81
79
  It is up to you to confirm that your Agnostic Modules are indeed agnostic, meaning that they have neither server- nor client-side code. `eslint-plugin-use-agnostic`, at least at this time, does not do this verification for you.
82
80
 
@@ -102,4 +100,4 @@ But not having a directive to distinguish between 1. non-special Server Modules
102
100
 
103
101
  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.
104
102
 
105
- A lot more 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.
103
+ A lot more needs to be done, and I suspect a lot of it unfortunately can only be optimized deeperly 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,3 +1,6 @@
1
+ import { Linter } from "eslint";
2
+ import tseslint from "typescript-eslint";
3
+
1
4
  /**
2
5
  * @typedef {import('../../../types/_commons/typedefs').Extensions} Extensions
3
6
  */
@@ -117,3 +120,12 @@ export const ARE_NOT_ALLOWED_TO_IMPORT = "are not allowed to import";
117
120
  export const skip = Object.freeze({
118
121
  skip: true,
119
122
  });
123
+
124
+ // common linter for AST retrieval
125
+ export const linter = new Linter();
126
+
127
+ // ESLint configs language options
128
+ export const typeScriptCompatible = Object.freeze({
129
+ // for compatibility with .ts and .tsx
130
+ parser: tseslint.parser,
131
+ });
@@ -7,18 +7,13 @@ import {
7
7
  EXTENSIONS,
8
8
  ARE_NOT_ALLOWED_TO_IMPORT,
9
9
  resolvedDirectives_resolvedModules,
10
+ linter,
11
+ typeScriptCompatible,
10
12
  } from "../constants/bases.js";
11
13
 
12
- import jscommentsConfig from "../../../comments.config.js";
13
-
14
14
  /**
15
- * @typedef {import('../../../types/_commons/typedefs').EffectiveDirective} EffectiveDirective
16
- * @typedef {import('../../../types/_commons/typedefs').CommentedDirective} CommentedDirective
17
- * @typedef {import('../../../types/_commons/typedefs').ResolvedDirectiveWithoutUseAgnosticStrategies} ResolvedDirectiveWithoutUseAgnosticStrategies
18
- * @typedef {import('../../../types/_commons/typedefs').Agnostic20ConfigName} Agnostic20ConfigName
19
- * @typedef {import('../../../types/_commons/typedefs').Directive21ConfigName} Directive21ConfigName
20
- * @typedef {import('../../../types/_commons/typedefs').UseAgnosticConfigName} UseAgnosticConfigName
21
15
  * @typedef {import('../../../types/_commons/typedefs').Context<string, readonly unknown[]>} Context
16
+ * @typedef {import('../../../types/_commons/typedefs').ResolvedDirectiveWithoutUseAgnosticStrategies} ResolvedDirectiveWithoutUseAgnosticStrategies
22
17
  */
23
18
 
24
19
  /**
@@ -43,16 +38,16 @@ const findExistingPath = (basePath) => {
43
38
 
44
39
  /**
45
40
  * Resolves an import path to a filesystem path, handling:
46
- * - Aliases (via tsconfig.json `paths`)
47
- * - Missing extensions (appends .ts, .tsx, etc.)
41
+ * - Base url and aliases (via tsconfig.json `baseUrl` and `paths` compiler options)
42
+ * - Missing extensions (appends `.ts`, `.tsx`, etc.)
48
43
  * - Directory imports (e.g., `./components` → `./components/index.ts`)
49
44
  * @param {string} currentDir The directory of the file containing the import (from `path.dirname(context.filename)`).
50
45
  * @param {string} importPath The import specifier (e.g., `@/components/Button` or `./utils`), from the current node.
51
- * @param {string} cwd The project root (from `context.cwd`). Caveat: only as an assumption currently.
46
+ * @param {string} cwd The project root (from `context.cwd`).
52
47
  * @returns The absolute resolved path or `null` if no path is found.
53
48
  */
54
49
  export const resolveImportPath = (currentDir, importPath, cwd) => {
55
- // Step 1: Resolve baseUrl and aliases (if tsconfig.json `paths` exists)
50
+ // Step 1: Resolves baseUrl and aliases
56
51
  const config = loadConfig(cwd);
57
52
 
58
53
  const resolveTSConfig =
@@ -60,12 +55,12 @@ export const resolveImportPath = (currentDir, importPath, cwd) => {
60
55
  ? createMatchPath(config.absoluteBaseUrl, config.paths)
61
56
  : null;
62
57
 
63
- const aliasedPath = resolveTSConfig
58
+ const baseUrlOrAliasedPath = resolveTSConfig
64
59
  ? resolveTSConfig(importPath, undefined, undefined, EXTENSIONS)
65
60
  : null;
66
61
 
67
- // Step 2: Resolve relative/absolute paths
68
- const basePath = aliasedPath || path.resolve(currentDir, importPath);
62
+ // Step 2: Resolves relative/absolute paths
63
+ const basePath = baseUrlOrAliasedPath || path.resolve(currentDir, importPath);
69
64
 
70
65
  // does not resolve on node_modules
71
66
  if (basePath.includes("node_modules")) return null;
@@ -73,7 +68,7 @@ export const resolveImportPath = (currentDir, importPath, cwd) => {
73
68
  // Case 1: File with extension exists
74
69
  if (path.extname(importPath) && fs.existsSync(basePath)) return basePath;
75
70
 
76
- // Case 2: Try appending extensions
71
+ // Case 2: Tries appending extensions
77
72
  const extensionlessImportPath = findExistingPath(basePath);
78
73
  if (extensionlessImportPath) return extensionlessImportPath;
79
74
 
@@ -85,7 +80,29 @@ export const resolveImportPath = (currentDir, importPath, cwd) => {
85
80
  return null; // not found
86
81
  };
87
82
 
88
- /* getImportedFileFirstLine */
83
+ /* getASTFromResolvedPath */ // for agnostic20
84
+ // Note: For agnostic20, I need the AST so that the directive can be picked up on any line as long as it is the first statement of the file.
85
+
86
+ /**
87
+ * Gets the ESLint-generated Abstract Syntax Tree of a file from its resolved path.
88
+ * @param {string} resolvedPath The resolved path of the file.
89
+ * @returns The ESLint-generated AST (Abstract Syntax Tree) of the file.
90
+ */
91
+ export const getASTFromFilePath = (resolvedPath) => {
92
+ // the raw code of the file at the end of the resolved path
93
+ const text = fs.readFileSync(resolvedPath, "utf8");
94
+ // utilizes linter.verify ...
95
+ linter.verify(text, { languageOptions: typeScriptCompatible });
96
+ // ... to retrieve the raw code as a SourceCode object ...
97
+ const code = linter.getSourceCode();
98
+ // ... from which to extra the ESLint-generated AST
99
+ const ast = code.ast;
100
+
101
+ return ast;
102
+ };
103
+
104
+ /* getImportedFileFirstLine */ // for directive21
105
+ // Note: For directive21, I prioritize reading from the file system for performance, forgoing the retrieval of the source code comments for imported modules, since the Directive-First Architecture imposes that the first line of the file is reserved for its commented directive.
89
106
 
90
107
  /**
91
108
  * Gets the first line of code of the imported module.
@@ -121,9 +138,10 @@ export const highlightFirstLineOfCode = (context) => ({
121
138
  /**
122
139
  * Returns a boolean deciding if an imported file's "resolved" directive is incompatible with the current file's "resolved" directive.
123
140
  * @template {ResolvedDirectiveWithoutUseAgnosticStrategies} T
141
+ * @template {ResolvedDirectiveWithoutUseAgnosticStrategies} U
124
142
  * @param {ResolvedDirectives_BlockedImports<T>} resolvedDirectives_blockedImports The blocked imports object, either for agnostic20 or for directive21.
125
143
  * @param {T} currentFileResolvedDirective The current file's "resolved" directive.
126
- * @param {T} importedFileResolvedDirective The imported file's "resolved" directive.
144
+ * @param {U} importedFileResolvedDirective The imported file's "resolved" directive.
127
145
  * @returns `true` if the import is blocked, as established in respective `resolvedDirectives_blockedImports`.
128
146
  */
129
147
  export const isImportBlocked = (
@@ -142,8 +160,8 @@ export const isImportBlocked = (
142
160
  * Makes the intro for each specific import rule violation messages.
143
161
  * @template {ResolvedDirectiveWithoutUseAgnosticStrategies} T
144
162
  * @template {ResolvedDirectiveWithoutUseAgnosticStrategies} U
145
- * @param {T} currentFileResolvedDirective The current file's "resolved" directive, excluding `"use agnostic strategies"`.
146
- * @param {U} importedFileResolvedDirective The imported file's "resolved" directive, excluding `"use agnostic strategies"`.
163
+ * @param {T} currentFileResolvedDirective The current file's "resolved" directive.
164
+ * @param {U} importedFileResolvedDirective The imported file's "resolved" directive.
147
165
  * @returns "[Current file 'resolved' modules] are not allowed to import [imported file 'resolved' modules]."
148
166
  */
149
167
  export const makeIntroForSpecificViolationMessage = (
@@ -201,9 +219,10 @@ export const makeMessageFromCurrentFileResolvedDirective = (
201
219
  /**
202
220
  * Finds the `message` for the specific violation of "resolved" directives import rules based on `resolvedDirectives_blockedImports`.
203
221
  * @template {ResolvedDirectiveWithoutUseAgnosticStrategies} T
222
+ * @template {ResolvedDirectiveWithoutUseAgnosticStrategies} U
204
223
  * @param {ResolvedDirectives_BlockedImports<T>} resolvedDirectives_blockedImports The blocked imports object, either for agnostic20 or for directive21.
205
- * @param {T} currentFileResolvedDirective The current file's "resolved" directive, excluding `"use agnostic strategies"`.
206
- * @param {T} importedFileResolvedDirective The imported file's "resolved" directive.
224
+ * @param {T} currentFileResolvedDirective The current file's "resolved" directive.
225
+ * @param {U} importedFileResolvedDirective The imported file's "resolved" directive.
207
226
  * @returns The corresponding `message`.
208
227
  */
209
228
  export const findSpecificViolationMessage = (
@@ -54,28 +54,28 @@ export const FUNCTIONS = "functions";
54
54
 
55
55
  // mapping directives with effective directives
56
56
  /** @type {Directives_EffectiveDirectives} */
57
- export const directives_effectiveDirectives = {
58
- [NO_DIRECTIVE]: {
57
+ export const directives_effectiveDirectives = Object.freeze({
58
+ [NO_DIRECTIVE]: Object.freeze({
59
59
  [LOGICS]: USE_SERVER_LOGICS,
60
60
  [COMPONENTS]: USE_SERVER_COMPONENTS,
61
61
  [FUNCTIONS]: null,
62
- },
63
- [USE_SERVER]: {
62
+ }),
63
+ [USE_SERVER]: Object.freeze({
64
64
  [LOGICS]: null,
65
65
  [COMPONENTS]: null,
66
66
  [FUNCTIONS]: USE_SERVER_FUNCTIONS,
67
- },
68
- [USE_CLIENT]: {
67
+ }),
68
+ [USE_CLIENT]: Object.freeze({
69
69
  [LOGICS]: USE_CLIENT_LOGICS,
70
70
  [COMPONENTS]: USE_CLIENT_COMPONENTS,
71
71
  [FUNCTIONS]: null,
72
- },
73
- [USE_AGNOSTIC]: {
72
+ }),
73
+ [USE_AGNOSTIC]: Object.freeze({
74
74
  [LOGICS]: USE_AGNOSTIC_LOGICS,
75
75
  [COMPONENTS]: USE_AGNOSTIC_COMPONENTS,
76
76
  [FUNCTIONS]: null,
77
- },
78
- };
77
+ }),
78
+ });
79
79
 
80
80
  // message placeholders
81
81
  export const currentFileEffectiveDirective = "currentFileEffectiveDirective";
@@ -40,7 +40,7 @@ import {
40
40
  /* currentFileFlow */
41
41
 
42
42
  /**
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.
43
+ * The flow that begins the import rules enforcement rule, retrieving the effective directive of the current file before comparing it to upcoming effective directives of the files it imports.
44
44
  * @param {Context} context The ESLint rule's `context` object.
45
45
  * @returns Either an object with `skip: true` to disregard or one with the non-null `currentFileEffectiveDirective`.
46
46
  */
@@ -9,13 +9,14 @@ import {
9
9
  } from "../constants/bases.js";
10
10
 
11
11
  import {
12
- getImportedFileFirstLine,
13
12
  isImportBlocked as commonsIsImportBlocked,
14
13
  makeMessageFromCurrentFileResolvedDirective,
15
14
  findSpecificViolationMessage as commonsFindSpecificViolationMessage,
15
+ getASTFromFilePath,
16
16
  } from "../../../_commons/utilities/helpers.js";
17
17
 
18
18
  /**
19
+ * @typedef {import('../../../../types/agnostic20/_commons/typedefs.js').AST} AST
19
20
  * @typedef {import('../../../../types/agnostic20/_commons/typedefs.js').Context} Context
20
21
  * @typedef {import('../../../../types/agnostic20/_commons/typedefs.js').Directive} Directive
21
22
  * @typedef {import('../../../../types/agnostic20/_commons/typedefs.js').NoDirective} NoDirective
@@ -23,20 +24,20 @@ import {
23
24
  * @typedef {import('../../../../types/agnostic20/_commons/typedefs.js').EffectiveDirective} EffectiveDirective
24
25
  */
25
26
 
26
- /* getDirectiveFromCurrentModule */
27
+ /* getDirectiveFromModule */
27
28
 
28
29
  /**
29
- * Gets the directive of the current module.
30
+ * Gets the directive of a module from its Abstract Syntax Tree.
30
31
  * - `null` denotes a server-by-default module, ideally a Server Module.
31
32
  * - `'use client'` denotes a Client Module.
32
33
  * - `'use server'` denotes a Server Functions Module.
33
34
  * - `'use agnostic'` denotes an Agnostic Module (formerly Shared Module).
34
- * @param {Context} context The ESLint rule's `context` object.
35
+ * @param {AST} ast The module's AST (Abstract Syntax Tree).
35
36
  * @returns The directive, or lack thereof via `null`. The lack of a directive is considered server-by-default.
36
37
  */
37
- export const getDirectiveFromCurrentModule = (context) => {
38
+ export const getDirectiveFromModule = (ast) => {
38
39
  // the AST body to check for the top-of-the-file directive
39
- const { body } = context.sourceCode.ast;
40
+ const { body } = ast;
40
41
 
41
42
  // the first statement from the source code's Abstract Syntax Tree
42
43
  const firstStatement = body[0];
@@ -52,10 +53,46 @@ export const getDirectiveFromCurrentModule = (context) => {
52
53
  if (value === null) return value;
53
54
 
54
55
  // the value to be exactly 'use client', 'use server' or 'use agnostic' in order not to be considered null by default, or server-by-default
55
- const currentFileDirective =
56
+ const moduleDirective =
56
57
  directivesArray.find((directive) => directive === value) ?? null;
57
58
 
58
- return currentFileDirective;
59
+ return moduleDirective;
60
+ };
61
+
62
+ /* getDirectiveFromCurrentModule */
63
+
64
+ /**
65
+ * Gets the directive of the current module.
66
+ * - `null` denotes a server-by-default module, ideally a Server Module.
67
+ * - `'use client'` denotes a Client Module.
68
+ * - `'use server'` denotes a Server Functions Module.
69
+ * - `'use agnostic'` denotes an Agnostic Module (formerly Shared Module).
70
+ * @param {Context} context The ESLint rule's `context` object.
71
+ * @returns The directive, or lack thereof via `null`. The lack of a directive is considered server-by-default.
72
+ */
73
+ export const getDirectiveFromCurrentModule = (context) => {
74
+ // the AST of the current module
75
+ const ast = context.sourceCode.ast;
76
+
77
+ return getDirectiveFromModule(ast);
78
+ };
79
+
80
+ /* getDirectiveFromImportedModule */
81
+
82
+ /**
83
+ * Gets the directive of the imported module.
84
+ * - `'use client'` denotes a Client Module.
85
+ * - `'use server'` denotes a Server Functions Module.
86
+ * - `'use agnostic'` denotes an Agnostic Module (formerly Shared Module).
87
+ * - `null` denotes a server-by-default module, ideally a Server Module.
88
+ * @param {string} resolvedImportPath The resolved path of the import.
89
+ * @returns The directive, or lack thereof via `null`. The lack of a directive is considered server-by-default.
90
+ */
91
+ export const getDirectiveFromImportedModule = (resolvedImportPath) => {
92
+ // the AST of the imported module
93
+ const ast = getASTFromFilePath(resolvedImportPath);
94
+
95
+ return getDirectiveFromModule(ast);
59
96
  };
60
97
 
61
98
  /* getEffectiveDirective */
@@ -83,38 +120,6 @@ export const getEffectiveDirective = (directive, extension) => {
83
120
  return directives_effectiveDirectives[directive][moduleKind];
84
121
  };
85
122
 
86
- /* getDirectiveFromImportedModule */
87
-
88
- /**
89
- * Gets the directive of the imported module.
90
- * - `'use client'` denotes a Client Module.
91
- * - `'use server'` denotes a Server Functions Module.
92
- * - `'use agnostic'` denotes an Agnostic Module (formerly Shared Module).
93
- * - `null` denotes a server-by-default module, ideally a Server Module.
94
- * @param {string} resolvedImportPath The resolved path of the import.
95
- * @returns The directive, or lack thereof via `null`. The lack of a directive is considered server-by-default.
96
- */
97
- export const getDirectiveFromImportedModule = (resolvedImportPath) => {
98
- // gets the first line of the code of the import
99
- const importedFileFirstLine = getImportedFileFirstLine(resolvedImportPath);
100
-
101
- // verifies that this first line starts with a valid directive, thus excluding comments
102
- const hasAcceptedDirective = directivesArray.some(
103
- (directive) =>
104
- importedFileFirstLine.startsWith(`'${directive}'`) ||
105
- importedFileFirstLine.startsWith(`"${directive}"`)
106
- );
107
-
108
- // applies the correct directive or the lack thereof with null
109
- const importedFileDirective = hasAcceptedDirective
110
- ? directivesArray.find((directive) =>
111
- importedFileFirstLine.includes(directive)
112
- ) ?? null
113
- : null;
114
-
115
- return importedFileDirective;
116
- };
117
-
118
123
  /* isImportBlocked */
119
124
 
120
125
  /**
@@ -1,10 +1,10 @@
1
1
  import { defineConfig } from "eslint/config";
2
- import tseslint from "typescript-eslint";
3
2
 
4
3
  import {
5
4
  agnostic20ConfigName,
6
5
  useAgnosticPluginName,
7
6
  enforceEffectiveDirectivesRuleName,
7
+ typeScriptCompatible,
8
8
  } from "../_commons/constants/bases.js";
9
9
 
10
10
  /**
@@ -26,10 +26,7 @@ export const makeAgnostic20Config = (plugin) => ({
26
26
  [`${useAgnosticPluginName}/${enforceEffectiveDirectivesRuleName}`]:
27
27
  "warn",
28
28
  },
29
- languageOptions: {
30
- // for compatibility with .ts and .tsx
31
- parser: tseslint.parser,
32
- },
29
+ languageOptions: typeScriptCompatible,
33
30
  },
34
31
  ]),
35
32
  });
@@ -12,7 +12,7 @@ import {
12
12
  USE_AGNOSTIC_STRATEGIES as COMMONS_USE_AGNOSTIC_STRATEGIES,
13
13
  } from "../../../_commons/constants/bases.js";
14
14
 
15
- import { makeIntroForSpecificViolationMessage as commonsMakeIntroForSpecificViolationMessage } from "../../../_commons/utilities/helpers.js";
15
+ import { makeIntroForSpecificViolationMessage } from "../../../_commons/utilities/helpers.js";
16
16
 
17
17
  import jscommentsConfig from "../../../../comments.config.js";
18
18
 
@@ -22,6 +22,7 @@ import jscommentsConfig from "../../../../comments.config.js";
22
22
  * @typedef {import('../../../../types/directive21/_commons/typedefs.js').CommentedDirectives} CommentedDirectives
23
23
  * @typedef {import('../../../../types/directive21/_commons/typedefs.js').CommentedStrategy} CommentedStrategy
24
24
  * @typedef {import('../../../../types/directive21/_commons/typedefs.js').CommentedStrategies} CommentedStrategies
25
+ * @typedef {import('../../../../types/directive21/_commons/typedefs.js').CommentStyles} CommentStyles
25
26
  */
26
27
 
27
28
  // commented directives
@@ -56,7 +57,7 @@ export const commentedDirectivesArray = Object.freeze([
56
57
  export const commentedDirectivesSet = new Set(commentedDirectivesArray); // no longer used exported to satisfy static type inference
57
58
 
58
59
  // mapped commented directives to their extension rules
59
- export const commentedDirectives_extensionRules = {
60
+ export const commentedDirectives_extensionRules = Object.freeze({
60
61
  [USE_SERVER_LOGICS]: false, // Must not end with 'x'
61
62
  [USE_CLIENT_LOGICS]: false,
62
63
  [USE_AGNOSTIC_LOGICS]: false,
@@ -67,7 +68,7 @@ export const commentedDirectives_extensionRules = {
67
68
  [USE_CLIENT_CONTEXTS]: true,
68
69
  [USE_AGNOSTIC_CONDITIONS]: true,
69
70
  [USE_AGNOSTIC_STRATEGIES]: null, // Any extension allowed
70
- };
71
+ });
71
72
 
72
73
  // commented strategies
73
74
  export const AT_SERVER_LOGICS = "@serverLogics";
@@ -121,23 +122,31 @@ export const specificFailure = "specificFailure";
121
122
  /* commentedDirectives_4RawImplementations */
122
123
 
123
124
  // all formatting styles as an array of [prefix, quote, suffix]
124
- const commentStyles = [
125
- [`// `, `'`, ``], // V1: `// 'directive'`
126
- [`// `, `"`, ``], // V2: `// "directive"`
127
- [`/* `, `'`, ` */`], // V3: `/* 'directive' */`
128
- [`/* `, `"`, ` */`], // V4: `/* "directive" */`
129
- ]; // further inference optimation can be made but is overkill...
125
+ /** @type {CommentStyles} */
126
+ const commentStyles = Object.freeze([
127
+ Object.freeze([`// `, `'`, ``]), // V1: `// 'directive'`
128
+ Object.freeze([`// `, `"`, ``]), // V2: `// "directive"`
129
+ Object.freeze([`\/\* `, `'`, ` \*\/`]), // V3: `/* 'directive' */`
130
+ Object.freeze([`\/\* `, `"`, ` \*\/`]), // V4: `/* "directive" */`
131
+ ]);
130
132
 
131
133
  /**
132
134
  * Makes the array of all four accepted commented directive implementations on a directive basis.
133
- * @param {CommentedDirective} directive The commented directive.
135
+ * @template {CommentedDirective} T
136
+ * @param {T} directive The commented directive.
134
137
  * @returns The array of formatted commented directives.
135
138
  */
136
- const make4RawImplementations = (directive) =>
137
- commentStyles.map(
138
- ([prefix, quote, suffix]) =>
139
- `${prefix}${quote}${directive}${quote}${suffix}`
140
- ); // ...further inference optimation could be an extra challenge but would probably require TypeScript for comfort
139
+ const make4RawImplementations = (directive) => {
140
+ /** @type {readonly [`// '${T}'`, `// "${T}""`, `\/\* '${T}' \*\/`, `\/\* "${T}"" \*\/`]} */
141
+ const rawImplementations = Object.freeze(
142
+ commentStyles.map(
143
+ ([prefix, quote, suffix]) =>
144
+ `${prefix}${quote}${directive}${quote}${suffix}`
145
+ )
146
+ );
147
+
148
+ return rawImplementations;
149
+ };
141
150
 
142
151
  export const commentedDirectives_4RawImplementations = Object.freeze({
143
152
  [USE_SERVER_LOGICS]: make4RawImplementations(USE_SERVER_LOGICS),
@@ -189,7 +198,7 @@ export const makeBlockedImport = (
189
198
  ) => {
190
199
  return Object.freeze({
191
200
  blockedImport: importedFileCommentedDirective,
192
- message: `${commonsMakeIntroForSpecificViolationMessage(
201
+ message: `${makeIntroForSpecificViolationMessage(
193
202
  currentFileCommentedDirective,
194
203
  importedFileCommentedDirective
195
204
  )} ${
@@ -142,7 +142,7 @@ const importedFileFlow = (context, node) => {
142
142
  /* GETTING THE CORRECT DIRECTIVE INTERPRETATION OF STRATEGY FOR AGNOSTIC STRATEGIES MODULES IMPORTS.
143
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.
144
144
 
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
+ 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.
146
146
 
147
147
  (Consequently, details below are currently at the stage of wishful thinking.)
148
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. */
@@ -11,10 +11,10 @@ import {
11
11
  } from "../constants/bases.js";
12
12
 
13
13
  import {
14
- getImportedFileFirstLine,
15
14
  isImportBlocked as commonsIsImportBlocked,
16
15
  makeMessageFromCurrentFileResolvedDirective,
17
16
  findSpecificViolationMessage as commonsFindSpecificViolationMessage,
17
+ getImportedFileFirstLine,
18
18
  } from "../../../_commons/utilities/helpers.js";
19
19
 
20
20
  /**
@@ -1,10 +1,10 @@
1
1
  import { defineConfig } from "eslint/config";
2
- import tseslint from "typescript-eslint";
3
2
 
4
3
  import {
5
4
  directive21ConfigName,
6
5
  useAgnosticPluginName,
7
6
  enforceCommentedDirectivesRuleName,
7
+ typeScriptCompatible,
8
8
  } from "../_commons/constants/bases.js";
9
9
 
10
10
  /**
@@ -26,10 +26,7 @@ export const makeDirective21Config = (plugin) => ({
26
26
  [`${useAgnosticPluginName}/${enforceCommentedDirectivesRuleName}`]:
27
27
  "warn",
28
28
  },
29
- languageOptions: {
30
- // for compatibility with .ts and .tsx
31
- parser: tseslint.parser,
32
- },
29
+ languageOptions: typeScriptCompatible,
33
30
  },
34
31
  ]),
35
32
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-use-agnostic",
3
- "version": "0.10.6",
3
+ "version": "0.11.0",
4
4
  "description": "Highlights problematic server-client imports in projects made with the Fullstack React Architecture.",
5
5
  "keywords": [
6
6
  "eslint",