@thethracian/oxlint-config 0.2.0 → 0.3.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.
Files changed (279) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/README.md +125 -19
  3. package/dist/codemod-fix/cli.d.ts +3 -0
  4. package/dist/codemod-fix/cli.d.ts.map +1 -0
  5. package/dist/codemod-fix/cli.js +22 -0
  6. package/dist/codemod-fix/cli.js.map +1 -0
  7. package/dist/codemod-fix/index.d.ts +44 -0
  8. package/dist/codemod-fix/index.d.ts.map +1 -0
  9. package/dist/codemod-fix/index.js +110 -0
  10. package/dist/codemod-fix/index.js.map +1 -0
  11. package/dist/codemods/arrow-body-style.d.ts +7 -0
  12. package/dist/codemods/arrow-body-style.d.ts.map +1 -0
  13. package/dist/codemods/arrow-body-style.js +106 -0
  14. package/dist/codemods/arrow-body-style.js.map +1 -0
  15. package/dist/codemods/comment-format.d.ts +24 -0
  16. package/dist/codemods/comment-format.d.ts.map +1 -0
  17. package/dist/codemods/comment-format.js +100 -0
  18. package/dist/codemods/comment-format.js.map +1 -0
  19. package/dist/codemods/explicit-return-types.d.ts +7 -0
  20. package/dist/codemods/explicit-return-types.d.ts.map +1 -0
  21. package/dist/codemods/explicit-return-types.js +350 -0
  22. package/dist/codemods/explicit-return-types.js.map +1 -0
  23. package/dist/codemods/format-file-header.d.ts +7 -0
  24. package/dist/codemods/format-file-header.d.ts.map +1 -0
  25. package/dist/codemods/format-file-header.js +163 -0
  26. package/dist/codemods/format-file-header.js.map +1 -0
  27. package/dist/codemods/format-jsdoc-comments.d.ts +7 -0
  28. package/dist/codemods/format-jsdoc-comments.d.ts.map +1 -0
  29. package/dist/codemods/format-jsdoc-comments.js +129 -0
  30. package/dist/codemods/format-jsdoc-comments.js.map +1 -0
  31. package/dist/codemods/function-declarations.d.ts +7 -0
  32. package/dist/codemods/function-declarations.d.ts.map +1 -0
  33. package/dist/codemods/function-declarations.js +202 -0
  34. package/dist/codemods/function-declarations.js.map +1 -0
  35. package/dist/codemods/inline-export-lists.d.ts +7 -0
  36. package/dist/codemods/inline-export-lists.d.ts.map +1 -0
  37. package/dist/codemods/inline-export-lists.js +168 -0
  38. package/dist/codemods/inline-export-lists.js.map +1 -0
  39. package/dist/codemods/internal-export-docs.d.ts +7 -0
  40. package/dist/codemods/internal-export-docs.d.ts.map +1 -0
  41. package/dist/codemods/internal-export-docs.js +93 -0
  42. package/dist/codemods/internal-export-docs.js.map +1 -0
  43. package/dist/codemods/no-ternary-branch-initializers.d.ts +14 -0
  44. package/dist/codemods/no-ternary-branch-initializers.d.ts.map +1 -0
  45. package/dist/codemods/no-ternary-branch-initializers.js +240 -0
  46. package/dist/codemods/no-ternary-branch-initializers.js.map +1 -0
  47. package/dist/codemods/no-ternary-variable-initializers.d.ts +14 -0
  48. package/dist/codemods/no-ternary-variable-initializers.d.ts.map +1 -0
  49. package/dist/codemods/no-ternary-variable-initializers.js +235 -0
  50. package/dist/codemods/no-ternary-variable-initializers.js.map +1 -0
  51. package/dist/codemods/no-ternary.d.ts +7 -0
  52. package/dist/codemods/no-ternary.d.ts.map +1 -0
  53. package/dist/codemods/no-ternary.js +215 -0
  54. package/dist/codemods/no-ternary.js.map +1 -0
  55. package/dist/codemods/rename-acronyms.d.ts +8 -0
  56. package/dist/codemods/rename-acronyms.d.ts.map +1 -0
  57. package/dist/codemods/rename-acronyms.js +193 -0
  58. package/dist/codemods/rename-acronyms.js.map +1 -0
  59. package/dist/codemods/run.d.ts +2 -0
  60. package/dist/codemods/run.d.ts.map +1 -0
  61. package/dist/codemods/run.js +14 -0
  62. package/dist/codemods/run.js.map +1 -0
  63. package/dist/codemods/sort-imports.d.ts +7 -0
  64. package/dist/codemods/sort-imports.d.ts.map +1 -0
  65. package/dist/codemods/sort-imports.js +235 -0
  66. package/dist/codemods/sort-imports.js.map +1 -0
  67. package/dist/index.d.ts +30 -96
  68. package/dist/index.d.ts.map +1 -1
  69. package/dist/index.js +157 -95
  70. package/dist/index.js.map +1 -1
  71. package/dist/rules/acronym-case.d.ts +7 -3
  72. package/dist/rules/acronym-case.d.ts.map +1 -1
  73. package/dist/rules/acronym-case.js +129 -120
  74. package/dist/rules/acronym-case.js.map +1 -1
  75. package/dist/rules/acronyms-1.d.ts +3 -0
  76. package/dist/rules/acronyms-1.d.ts.map +1 -0
  77. package/dist/rules/acronyms-1.js +407 -0
  78. package/dist/rules/acronyms-1.js.map +1 -0
  79. package/dist/rules/acronyms-2.d.ts +3 -0
  80. package/dist/rules/acronyms-2.d.ts.map +1 -0
  81. package/dist/rules/acronyms-2.js +407 -0
  82. package/dist/rules/acronyms-2.js.map +1 -0
  83. package/dist/rules/acronyms-3.d.ts +3 -0
  84. package/dist/rules/acronyms-3.d.ts.map +1 -0
  85. package/dist/rules/acronyms-3.js +407 -0
  86. package/dist/rules/acronyms-3.js.map +1 -0
  87. package/dist/rules/acronyms-4.d.ts +3 -0
  88. package/dist/rules/acronyms-4.d.ts.map +1 -0
  89. package/dist/rules/acronyms-4.js +377 -0
  90. package/dist/rules/acronyms-4.js.map +1 -0
  91. package/dist/rules/acronyms.d.ts +1 -8
  92. package/dist/rules/acronyms.d.ts.map +1 -1
  93. package/dist/rules/acronyms.js +14 -1578
  94. package/dist/rules/acronyms.js.map +1 -1
  95. package/dist/rules/boolean-prefix.d.ts +11 -2
  96. package/dist/rules/boolean-prefix.d.ts.map +1 -1
  97. package/dist/rules/boolean-prefix.js +95 -59
  98. package/dist/rules/boolean-prefix.js.map +1 -1
  99. package/dist/rules/camel-case-identifiers.d.ts +3 -4
  100. package/dist/rules/camel-case-identifiers.d.ts.map +1 -1
  101. package/dist/rules/camel-case-identifiers.js +59 -40
  102. package/dist/rules/camel-case-identifiers.js.map +1 -1
  103. package/dist/rules/char-class.d.ts +26 -13
  104. package/dist/rules/char-class.d.ts.map +1 -1
  105. package/dist/rules/char-class.js +56 -24
  106. package/dist/rules/char-class.js.map +1 -1
  107. package/dist/rules/diagnostic-guidance.d.ts +91 -0
  108. package/dist/rules/diagnostic-guidance.d.ts.map +1 -0
  109. package/dist/rules/diagnostic-guidance.js +243 -0
  110. package/dist/rules/diagnostic-guidance.js.map +1 -0
  111. package/dist/rules/effect-default-ast.d.ts +89 -0
  112. package/dist/rules/effect-default-ast.d.ts.map +1 -0
  113. package/dist/rules/effect-default-ast.js +208 -0
  114. package/dist/rules/effect-default-ast.js.map +1 -0
  115. package/dist/rules/effect-default-compat-rules.d.ts +76 -0
  116. package/dist/rules/effect-default-compat-rules.d.ts.map +1 -0
  117. package/dist/rules/effect-default-compat-rules.js +270 -0
  118. package/dist/rules/effect-default-compat-rules.js.map +1 -0
  119. package/dist/rules/effect-default-env-rules.d.ts +60 -0
  120. package/dist/rules/effect-default-env-rules.d.ts.map +1 -0
  121. package/dist/rules/effect-default-env-rules.js +259 -0
  122. package/dist/rules/effect-default-env-rules.js.map +1 -0
  123. package/dist/rules/effect-default-fiber-helpers.d.ts +13 -0
  124. package/dist/rules/effect-default-fiber-helpers.d.ts.map +1 -0
  125. package/dist/rules/effect-default-fiber-helpers.js +76 -0
  126. package/dist/rules/effect-default-fiber-helpers.js.map +1 -0
  127. package/dist/rules/effect-default-floating-helpers.d.ts +7 -0
  128. package/dist/rules/effect-default-floating-helpers.d.ts.map +1 -0
  129. package/dist/rules/effect-default-floating-helpers.js +113 -0
  130. package/dist/rules/effect-default-floating-helpers.js.map +1 -0
  131. package/dist/rules/effect-default-helpers.d.ts +8 -32
  132. package/dist/rules/effect-default-helpers.d.ts.map +1 -1
  133. package/dist/rules/effect-default-helpers.js +11 -458
  134. package/dist/rules/effect-default-helpers.js.map +1 -1
  135. package/dist/rules/effect-default-resource-helpers.d.ts +18 -4
  136. package/dist/rules/effect-default-resource-helpers.d.ts.map +1 -1
  137. package/dist/rules/effect-default-resource-helpers.js +30 -13
  138. package/dist/rules/effect-default-resource-helpers.js.map +1 -1
  139. package/dist/rules/effect-default-safety-helpers.d.ts +43 -0
  140. package/dist/rules/effect-default-safety-helpers.d.ts.map +1 -0
  141. package/dist/rules/effect-default-safety-helpers.js +126 -0
  142. package/dist/rules/effect-default-safety-helpers.js.map +1 -0
  143. package/dist/rules/effect-default-scan-helpers.d.ts +43 -0
  144. package/dist/rules/effect-default-scan-helpers.d.ts.map +1 -0
  145. package/dist/rules/effect-default-scan-helpers.js +141 -0
  146. package/dist/rules/effect-default-scan-helpers.js.map +1 -0
  147. package/dist/rules/effect-default-schema-helpers.d.ts +37 -0
  148. package/dist/rules/effect-default-schema-helpers.d.ts.map +1 -0
  149. package/dist/rules/effect-default-schema-helpers.js +104 -0
  150. package/dist/rules/effect-default-schema-helpers.js.map +1 -0
  151. package/dist/rules/effect-default-test-helpers.d.ts +18 -4
  152. package/dist/rules/effect-default-test-helpers.d.ts.map +1 -1
  153. package/dist/rules/effect-default-test-helpers.js +41 -20
  154. package/dist/rules/effect-default-test-helpers.js.map +1 -1
  155. package/dist/rules/effect-default-workflow-helpers.d.ts +91 -0
  156. package/dist/rules/effect-default-workflow-helpers.d.ts.map +1 -0
  157. package/dist/rules/effect-default-workflow-helpers.js +247 -0
  158. package/dist/rules/effect-default-workflow-helpers.js.map +1 -0
  159. package/dist/rules/effect-default.d.ts +1 -1
  160. package/dist/rules/effect-default.d.ts.map +1 -1
  161. package/dist/rules/effect-default.js +198 -637
  162. package/dist/rules/effect-default.js.map +1 -1
  163. package/dist/rules/effect-exported-declarations.d.ts +19 -0
  164. package/dist/rules/effect-exported-declarations.d.ts.map +1 -0
  165. package/dist/rules/effect-exported-declarations.js +237 -0
  166. package/dist/rules/effect-exported-declarations.js.map +1 -0
  167. package/dist/rules/effect-path-options.d.ts +49 -11
  168. package/dist/rules/effect-path-options.d.ts.map +1 -1
  169. package/dist/rules/effect-path-options.js +85 -52
  170. package/dist/rules/effect-path-options.js.map +1 -1
  171. package/dist/rules/effect-rule-aliases.d.ts +55 -0
  172. package/dist/rules/effect-rule-aliases.d.ts.map +1 -0
  173. package/dist/rules/effect-rule-aliases.js +278 -0
  174. package/dist/rules/effect-rule-aliases.js.map +1 -0
  175. package/dist/rules/effect-rule-core.d.ts +46 -24
  176. package/dist/rules/effect-rule-core.d.ts.map +1 -1
  177. package/dist/rules/effect-rule-core.js +263 -303
  178. package/dist/rules/effect-rule-core.js.map +1 -1
  179. package/dist/rules/effect-rule-names.d.ts +12 -3
  180. package/dist/rules/effect-rule-names.d.ts.map +1 -1
  181. package/dist/rules/effect-rule-names.js +15 -3
  182. package/dist/rules/effect-rule-names.js.map +1 -1
  183. package/dist/rules/effect-source-comments.d.ts +7 -0
  184. package/dist/rules/effect-source-comments.d.ts.map +1 -0
  185. package/dist/rules/effect-source-comments.js +227 -0
  186. package/dist/rules/effect-source-comments.js.map +1 -0
  187. package/dist/rules/effect-source-helpers.d.ts +4 -9
  188. package/dist/rules/effect-source-helpers.d.ts.map +1 -1
  189. package/dist/rules/effect-source-helpers.js +7 -333
  190. package/dist/rules/effect-source-helpers.js.map +1 -1
  191. package/dist/rules/effect-source-navigation.d.ts +25 -0
  192. package/dist/rules/effect-source-navigation.d.ts.map +1 -0
  193. package/dist/rules/effect-source-navigation.js +244 -0
  194. package/dist/rules/effect-source-navigation.js.map +1 -0
  195. package/dist/rules/effect-source-scan.d.ts +30 -7
  196. package/dist/rules/effect-source-scan.d.ts.map +1 -1
  197. package/dist/rules/effect-source-scan.js +377 -297
  198. package/dist/rules/effect-source-scan.js.map +1 -1
  199. package/dist/rules/effect-strict-ast-specs.d.ts +8 -0
  200. package/dist/rules/effect-strict-ast-specs.d.ts.map +1 -0
  201. package/dist/rules/effect-strict-ast-specs.js +166 -0
  202. package/dist/rules/effect-strict-ast-specs.js.map +1 -0
  203. package/dist/rules/effect-strict-boundary-helpers.d.ts +25 -0
  204. package/dist/rules/effect-strict-boundary-helpers.d.ts.map +1 -0
  205. package/dist/rules/effect-strict-boundary-helpers.js +127 -0
  206. package/dist/rules/effect-strict-boundary-helpers.js.map +1 -0
  207. package/dist/rules/effect-strict-core-specs.d.ts +8 -0
  208. package/dist/rules/effect-strict-core-specs.d.ts.map +1 -0
  209. package/dist/rules/effect-strict-core-specs.js +334 -0
  210. package/dist/rules/effect-strict-core-specs.js.map +1 -0
  211. package/dist/rules/effect-strict-external-helpers.d.ts +25 -0
  212. package/dist/rules/effect-strict-external-helpers.d.ts.map +1 -0
  213. package/dist/rules/effect-strict-external-helpers.js +87 -0
  214. package/dist/rules/effect-strict-external-helpers.js.map +1 -0
  215. package/dist/rules/effect-strict-helpers.d.ts +75 -33
  216. package/dist/rules/effect-strict-helpers.d.ts.map +1 -1
  217. package/dist/rules/effect-strict-helpers.js +124 -246
  218. package/dist/rules/effect-strict-helpers.js.map +1 -1
  219. package/dist/rules/effect-strict-internals.d.ts +198 -0
  220. package/dist/rules/effect-strict-internals.d.ts.map +1 -0
  221. package/dist/rules/effect-strict-internals.js +477 -0
  222. package/dist/rules/effect-strict-internals.js.map +1 -0
  223. package/dist/rules/effect-strict-segment-helpers.d.ts +79 -0
  224. package/dist/rules/effect-strict-segment-helpers.d.ts.map +1 -0
  225. package/dist/rules/effect-strict-segment-helpers.js +308 -0
  226. package/dist/rules/effect-strict-segment-helpers.js.map +1 -0
  227. package/dist/rules/effect-strict.d.ts +1 -1
  228. package/dist/rules/effect-strict.d.ts.map +1 -1
  229. package/dist/rules/effect-strict.js +10 -661
  230. package/dist/rules/effect-strict.js.map +1 -1
  231. package/dist/rules/max-import-depth.d.ts +2 -2
  232. package/dist/rules/max-import-depth.d.ts.map +1 -1
  233. package/dist/rules/max-import-depth.js +52 -17
  234. package/dist/rules/max-import-depth.js.map +1 -1
  235. package/dist/rules/max-line-length.d.ts +9 -2
  236. package/dist/rules/max-line-length.d.ts.map +1 -1
  237. package/dist/rules/max-line-length.js +62 -7
  238. package/dist/rules/max-line-length.js.map +1 -1
  239. package/dist/rules/no-commented-out-code.d.ts +3 -7
  240. package/dist/rules/no-commented-out-code.d.ts.map +1 -1
  241. package/dist/rules/no-commented-out-code.js +157 -102
  242. package/dist/rules/no-commented-out-code.js.map +1 -1
  243. package/dist/rules/pascal-case-types.d.ts +1 -1
  244. package/dist/rules/pascal-case-types.d.ts.map +1 -1
  245. package/dist/rules/pascal-case-types.js +65 -46
  246. package/dist/rules/pascal-case-types.js.map +1 -1
  247. package/dist/rules/plugin-commented-out-code-rule.d.ts +32 -0
  248. package/dist/rules/plugin-commented-out-code-rule.d.ts.map +1 -0
  249. package/dist/rules/plugin-commented-out-code-rule.js +135 -0
  250. package/dist/rules/plugin-commented-out-code-rule.js.map +1 -0
  251. package/dist/rules/plugin.d.ts +3 -121
  252. package/dist/rules/plugin.d.ts.map +1 -1
  253. package/dist/rules/plugin.js +195 -201
  254. package/dist/rules/plugin.js.map +1 -1
  255. package/dist/rules/private-underscore.d.ts +1 -1
  256. package/dist/rules/private-underscore.d.ts.map +1 -1
  257. package/dist/rules/private-underscore.js +11 -4
  258. package/dist/rules/private-underscore.js.map +1 -1
  259. package/dist/rules/require-file-doc.d.ts +5 -6
  260. package/dist/rules/require-file-doc.d.ts.map +1 -1
  261. package/dist/rules/require-file-doc.js +127 -78
  262. package/dist/rules/require-file-doc.js.map +1 -1
  263. package/dist/rules/require-function-doc-ignored-text.d.ts +7 -0
  264. package/dist/rules/require-function-doc-ignored-text.d.ts.map +1 -0
  265. package/dist/rules/require-function-doc-ignored-text.js +67 -0
  266. package/dist/rules/require-function-doc-ignored-text.js.map +1 -0
  267. package/dist/rules/require-function-doc-local-exports.d.ts +7 -0
  268. package/dist/rules/require-function-doc-local-exports.d.ts.map +1 -0
  269. package/dist/rules/require-function-doc-local-exports.js +114 -0
  270. package/dist/rules/require-function-doc-local-exports.js.map +1 -0
  271. package/dist/rules/require-function-doc.d.ts +3 -18
  272. package/dist/rules/require-function-doc.d.ts.map +1 -1
  273. package/dist/rules/require-function-doc.js +404 -218
  274. package/dist/rules/require-function-doc.js.map +1 -1
  275. package/dist/rules/source-cache.d.ts +19 -0
  276. package/dist/rules/source-cache.d.ts.map +1 -0
  277. package/dist/rules/source-cache.js +63 -0
  278. package/dist/rules/source-cache.js.map +1 -0
  279. package/package.json +15 -10
@@ -1,26 +1,20 @@
1
- import { readFileSync } from 'node:fs';
2
- import { stripComments, stripCommentsAndStrings } from './effect-source-helpers.js';
3
- function readSource(context) {
4
- if (context.sourceCode?.text !== undefined) {
5
- return context.sourceCode.text;
6
- }
7
- if (context.sourceCode?.getText) {
8
- return context.sourceCode.getText();
9
- }
10
- if (!context.filename) {
11
- return '';
12
- }
13
- try {
14
- return readFileSync(context.filename, 'utf-8');
15
- }
16
- catch {
17
- return '';
18
- }
19
- }
20
- function isCodeAt(strippedSource, index) {
21
- return strippedSource[index]?.trim() !== '';
22
- }
23
- function hasPattern(source, patterns) {
1
+ /* -------------------------------------------------------------------------- */
2
+ /* Core runtime for source-backed and AST-backed Effect lint rules. */
3
+ /* -------------------------------------------------------------------------- */
4
+ import { canonicalizeEffectAPIAliases } from './effect-rule-aliases.js';
5
+ import { effectDiagnosticMessage } from './diagnostic-guidance.js';
6
+ import { readCachedSource } from './source-cache.js';
7
+ import { stripCommentsAndStrings } from './effect-source-helpers.js';
8
+ const LINE_START_CACHE_MAX = 256;
9
+ const TOKEN_GATE_CACHE_MAX = 512;
10
+ const CHAR_CODE_NEWLINE = 10;
11
+ const lineStartCache = new Map();
12
+ const globalPatternCache = new WeakMap();
13
+ const tokenGateCache = new WeakMap();
14
+ const sourceTokenPresenceCache = new Map();
15
+ const readSource = (context) => readCachedSource(context);
16
+ const isCodeAt = (strippedSource, index) => strippedSource[index]?.trim() !== '';
17
+ const hasPattern = (source, patterns) => {
24
18
  let strippedSource = undefined;
25
19
  return patterns.some((pattern) => {
26
20
  for (const match of source.matchAll(toGlobalRegExp(pattern))) {
@@ -31,60 +25,113 @@ function hasPattern(source, patterns) {
31
25
  }
32
26
  return false;
33
27
  });
34
- }
35
- function toGlobalRegExp(pattern) {
36
- return new RegExp(pattern.source, pattern.flags.includes('g') ? pattern.flags : `${pattern.flags}g`);
37
- }
38
- function locFromIndex(source, index) {
39
- let line = 1;
40
- let lineStart = 0;
41
- for (let position = 0; position < index; position++) {
42
- if (source.charCodeAt(position) === 10) {
43
- line++;
44
- lineStart = position + 1;
28
+ };
29
+ const toGlobalRegExp = (pattern) => {
30
+ const cachedPattern = globalPatternCache.get(pattern);
31
+ if (cachedPattern !== undefined) {
32
+ return cachedPattern;
33
+ }
34
+ let { flags } = pattern;
35
+ if (!flags.includes('g')) {
36
+ flags = `${flags}g`;
37
+ }
38
+ const globalPattern = new RegExp(pattern.source, flags);
39
+ globalPatternCache.set(pattern, globalPattern);
40
+ return globalPattern;
41
+ };
42
+ const cachedLineStarts = (source) => lineStartCache.get(source);
43
+ const evictFirstLineStart = () => {
44
+ if (lineStartCache.size < LINE_START_CACHE_MAX) {
45
+ return;
46
+ }
47
+ const firstKey = lineStartCache.keys().next().value;
48
+ if (firstKey !== undefined) {
49
+ lineStartCache.delete(firstKey);
50
+ }
51
+ };
52
+ const computeLineStarts = (source) => {
53
+ const starts = [0];
54
+ for (let position = 0; position < source.length; position++) {
55
+ if (source.charCodeAt(position) === CHAR_CODE_NEWLINE) {
56
+ starts.push(position + 1);
45
57
  }
46
58
  }
59
+ return starts;
60
+ };
61
+ const lineStartsFor = (source) => {
62
+ const cachedStarts = cachedLineStarts(source);
63
+ if (cachedStarts !== undefined) {
64
+ return cachedStarts;
65
+ }
66
+ const starts = computeLineStarts(source);
67
+ evictFirstLineStart();
68
+ lineStartCache.set(source, starts);
69
+ return starts;
70
+ };
71
+ const lineIndexFor = (starts, index) => {
72
+ let low = 0;
73
+ let high = starts.length - 1;
74
+ while (low <= high) {
75
+ const middle = (low + high) >> 1;
76
+ const lineStart = starts[middle] ?? 0;
77
+ if (lineStart <= index) {
78
+ low = middle + 1;
79
+ }
80
+ else {
81
+ high = middle - 1;
82
+ }
83
+ }
84
+ return Math.max(0, high);
85
+ };
86
+ const locFromIndex = (source, index) => {
87
+ const starts = lineStartsFor(source);
88
+ const lineIndex = lineIndexFor(starts, index);
89
+ const lineStart = starts[lineIndex] ?? 0;
90
+ const line = lineIndex + 1;
47
91
  return { column: index - lineStart, line };
48
- }
49
- function firstPatternLoc(source, patterns) {
92
+ };
93
+ const firstPatternLOC = (source, patterns) => {
50
94
  let strippedSource = undefined;
51
95
  for (const pattern of patterns) {
52
96
  for (const match of source.matchAll(toGlobalRegExp(pattern))) {
53
97
  strippedSource ??= stripCommentsAndStrings(source);
54
- if (!isCodeAt(strippedSource, match.index)) {
55
- continue;
98
+ if (isCodeAt(strippedSource, match.index)) {
99
+ return locFromIndex(source, match.index);
56
100
  }
57
- return locFromIndex(source, match.index);
58
101
  }
59
102
  }
60
103
  return undefined;
61
- }
62
- function reportPatternMatches(input) {
104
+ };
105
+ const reportPatternMatches = (input) => {
63
106
  const { context, node, source, spec } = input;
107
+ const message = effectDiagnosticMessage(spec.name, spec.message);
64
108
  if (!spec.countPatterns) {
65
109
  context.report({
66
- loc: firstPatternLoc(source, spec.patterns ?? []),
67
- message: spec.message,
110
+ loc: firstPatternLOC(source, spec.patterns ?? []),
111
+ message,
68
112
  node,
69
113
  });
70
114
  return;
71
115
  }
116
+ reportCountedPatternMatches(input, message);
117
+ };
118
+ const reportCountedPatternMatches = (input, message) => {
119
+ const { context, node, source, spec } = input;
72
120
  let strippedSource = undefined;
73
- for (const pattern of spec.countPatterns) {
121
+ for (const pattern of spec.countPatterns ?? []) {
74
122
  for (const match of source.matchAll(toGlobalRegExp(pattern))) {
75
123
  strippedSource ??= stripCommentsAndStrings(source);
76
- if (!isCodeAt(strippedSource, match.index)) {
77
- continue;
124
+ if (isCodeAt(strippedSource, match.index)) {
125
+ context.report({
126
+ loc: locFromIndex(source, match.index),
127
+ message,
128
+ node,
129
+ });
78
130
  }
79
- context.report({
80
- loc: locFromIndex(source, match.index),
81
- message: spec.message,
82
- node,
83
- });
84
131
  }
85
132
  }
86
- }
87
- function checkResultIndex(result) {
133
+ };
134
+ const checkResultIndex = (result) => {
88
135
  if (typeof result === 'number') {
89
136
  return result;
90
137
  }
@@ -92,271 +139,184 @@ function checkResultIndex(result) {
92
139
  return result.index;
93
140
  }
94
141
  return undefined;
95
- }
96
- function isCheckViolation(result) {
97
- return typeof result === 'boolean' ? result : true;
98
- }
99
- function makeProgramRule(spec, options) {
100
- return {
101
- meta: {
102
- schema: options.schema,
103
- type: 'problem',
104
- },
105
- create(context) {
106
- const source = readSource(context);
107
- const astVisitors = spec.ast?.(context, source) ?? {};
108
- return {
109
- ...astVisitors,
110
- Program(node) {
111
- if (source === '') {
112
- return;
113
- }
114
- if (spec.ast && Array.isArray(node.body)) {
115
- return;
116
- }
117
- const canonicalSource = canonicalizeEffectApiAliases(source);
118
- const checkResult = spec.check?.(canonicalSource, context);
119
- if (checkResult !== undefined) {
120
- if (!isCheckViolation(checkResult)) {
121
- return;
122
- }
123
- const index = checkResultIndex(checkResult);
124
- context.report({
125
- loc: index === undefined
126
- ? firstPatternLoc(canonicalSource, spec.patterns ?? [])
127
- : locFromIndex(canonicalSource, index),
128
- message: spec.message,
129
- node,
130
- });
131
- return;
132
- }
133
- if (hasPattern(canonicalSource, spec.patterns ?? [])) {
134
- reportPatternMatches({ context, node, source: canonicalSource, spec });
135
- }
136
- },
137
- };
138
- },
139
- };
140
- }
141
- function makeRules(specs, options = {}) {
142
- return Object.fromEntries(specs.map((spec) => [spec.name, makeProgramRule(spec, options)]));
143
- }
144
- function hasEffectSignal(source) {
145
- const codeOnly = stripCommentsAndStrings(source);
146
- return (hasEffectValueImport(source) ||
147
- effectImportAliases(source).some((alias) => new RegExp(`\\b${escapeRegExp(alias)}\\.`, 'u').test(codeOnly)));
148
- }
149
- const runtimeCallPattern = /\b(?:Effect\.(?:runPromise|runPromiseExit|runSync|runSyncExit|runFork)|[A-Za-z_$][\w$]*Runtime\.runMain)\s*\(/;
150
- const boundaryFilePattern = /(?:^|\/)src\/(?:main|server|cli)\.ts$|\.entry\.ts$/;
151
- const testFilePattern = /\.(?:test|spec)\.tsx?$/;
152
- const ALIAS_CACHE_MAX = 256;
153
- const effectAliasCache = new Map();
154
- const runtimeFunctionAliasCache = new Map();
155
- const canonicalSourceCache = new Map();
156
- function cachedAliases(cache, source) {
157
- const value = cache.get(source);
158
- if (value) {
159
- cache.delete(source);
160
- cache.set(source, value);
161
- }
162
- return value;
163
- }
164
- function cacheAliases(cache, source, value) {
165
- if (cache.size >= ALIAS_CACHE_MAX) {
166
- const firstKey = cache.keys().next().value;
167
- if (firstKey !== undefined) {
168
- cache.delete(firstKey);
169
- }
170
- }
171
- cache.set(source, value);
172
- return value;
173
- }
174
- function escapeRegExp(value) {
175
- return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
176
- }
177
- function hasLocalEffectBinding(source) {
178
- return /\b(?:const|let|var|function|class|namespace)\s+Effect\b/.test(stripCommentsAndStrings(source));
179
- }
180
- function importSpecifierNames(specifier) {
181
- const trimmed = specifier.trim();
182
- if (trimmed.startsWith('type ')) {
183
- return undefined;
184
- }
185
- const parts = trimmed.split(/\s+as\s+/);
186
- const importedName = parts[0]?.trim();
187
- const localName = parts[1]?.trim() ?? importedName;
188
- return importedName && localName ? { importedName, localName } : undefined;
189
- }
190
- function hasAnyEffectImport(source) {
191
- return /(?:^|\n)\s*import(?:\s+type)?(?:[\s\S]*?\s+from\s*)?['"](?:effect(?:\/[^'"]+)?|@effect\/[^'"]+)['"]/.test(stripComments(source));
192
- }
193
- function hasEffectValueImport(source) {
194
- const commentFreeSource = stripComments(source);
195
- for (const match of commentFreeSource.matchAll(/(?:^|\n)\s*import\s+(?!type\b)\s*{([^}]+)}\s*from\s*['"]effect['"]/g)) {
196
- if (match[1]
197
- .split(',')
198
- .some((specifier) => importSpecifierNames(specifier)?.importedName === 'Effect')) {
199
- return true;
200
- }
201
- }
202
- return (/(?:^|\n)\s*import\s+(?!type\b)\*\s+as\s+[A-Za-z_$][\w$]*\s+from\s*['"]effect(?:\/Effect)?['"]/.test(commentFreeSource) || effectFunctionAliases(source, 'Effect').length > 0);
203
- }
204
- function effectImportAliases(source) {
205
- const cachedValue = cachedAliases(effectAliasCache, source);
206
- if (cachedValue) {
207
- return [...cachedValue];
208
- }
209
- const aliases = new Set();
210
- const commentFreeSource = stripComments(source);
211
- for (const match of commentFreeSource.matchAll(/(?:^|\n)\s*import\s+(?!type\b)\s*{([^}]+)}\s*from\s*['"]effect['"]/g)) {
212
- for (const specifier of match[1].split(',')) {
213
- const names = importSpecifierNames(specifier);
214
- if (!names) {
215
- continue;
216
- }
217
- if (names.importedName === 'Effect') {
218
- aliases.add('Effect');
219
- aliases.add(names.localName);
220
- }
221
- }
222
- }
223
- for (const match of commentFreeSource.matchAll(/(?:^|\n)\s*import\s+(?!type\b)\*\s+as\s+([A-Za-z_$][\w$]*)\s+from\s*['"]effect(?:\/Effect)?['"]/g)) {
224
- aliases.add('Effect');
225
- aliases.add(match[1]);
142
+ };
143
+ const isCheckViolation = (result) => {
144
+ if (typeof result === 'boolean') {
145
+ return result;
226
146
  }
227
- if (aliases.size === 0 && !hasAnyEffectImport(source) && !hasLocalEffectBinding(source)) {
228
- aliases.add('Effect');
147
+ return true;
148
+ };
149
+ const cachedSourceTokenPresence = (source) => {
150
+ let tokenPresence = sourceTokenPresenceCache.get(source);
151
+ if (tokenPresence !== undefined) {
152
+ return tokenPresence;
229
153
  }
230
- return [...cacheAliases(effectAliasCache, source, [...aliases])];
231
- }
232
- function effectApiAliases(source, apiName) {
233
- const aliases = new Set();
234
- const commentFreeSource = stripComments(source);
235
- for (const match of commentFreeSource.matchAll(/(?:^|\n)\s*import\s+(?!type\b)\s*{([^}]+)}\s*from\s*['"]effect['"]/g)) {
236
- for (const specifier of match[1].split(',')) {
237
- const names = importSpecifierNames(specifier);
238
- if (names?.importedName === apiName) {
239
- aliases.add(names.localName);
240
- }
154
+ if (sourceTokenPresenceCache.size >= TOKEN_GATE_CACHE_MAX) {
155
+ const firstKey = sourceTokenPresenceCache.keys().next().value;
156
+ if (firstKey !== undefined) {
157
+ sourceTokenPresenceCache.delete(firstKey);
241
158
  }
242
159
  }
243
- for (const match of commentFreeSource.matchAll(new RegExp(`(?:^|\\n)\\s*import\\s+(?!type\\b)\\*\\s+as\\s+([A-Za-z_$][\\w$]*)\\s+from\\s*['"]effect/${escapeRegExp(apiName)}['"]`, 'g'))) {
244
- aliases.add(match[1]);
245
- }
246
- if (aliases.size === 0 && !hasAnyEffectImport(source)) {
247
- aliases.add(apiName);
248
- }
249
- return [...aliases];
250
- }
251
- function effectFunctionAliases(source, moduleName, functionName) {
252
- const aliases = new Set();
253
- const commentFreeSource = stripComments(source);
254
- for (const match of commentFreeSource.matchAll(new RegExp(`(?:^|\\n)\\s*import\\s+(?!type\\b)\\s*{([^}]+)}\\s*from\\s*['"]effect/${escapeRegExp(moduleName)}['"]`, 'g'))) {
255
- for (const specifier of match[1].split(',')) {
256
- const names = importSpecifierNames(specifier);
257
- if (names && (!functionName || names.importedName === functionName)) {
258
- aliases.add(names.localName);
259
- }
260
- }
160
+ tokenPresence = new Map();
161
+ sourceTokenPresenceCache.set(source, tokenPresence);
162
+ return tokenPresence;
163
+ };
164
+ const hasTokenInSourceCached = (source, token) => {
165
+ const tokenPresence = cachedSourceTokenPresence(source);
166
+ const cachedValue = tokenPresence.get(token);
167
+ if (cachedValue !== undefined) {
168
+ return cachedValue;
261
169
  }
262
- return [...aliases];
263
- }
264
- function canonicalImportAliases(source) {
265
- const aliases = new Map();
266
- const commentFreeSource = stripComments(source);
267
- const canonicalNames = new Set([
268
- 'Config',
269
- 'Context',
270
- 'Effect',
271
- 'Fiber',
272
- 'Layer',
273
- 'Queue',
274
- 'Schedule',
275
- 'Schema',
276
- 'Scope',
277
- 'Stream',
278
- 'TestClock',
279
- ]);
280
- for (const match of commentFreeSource.matchAll(/(?:^|\n)\s*import\s+(?!type\b)\s*{([^}]+)}\s*from\s*['"]effect['"]/g)) {
281
- for (const specifier of match[1].split(',')) {
282
- const names = importSpecifierNames(specifier);
283
- const importedName = names?.importedName;
284
- const localName = names?.localName;
285
- if (importedName &&
286
- localName &&
287
- canonicalNames.has(importedName) &&
288
- localName !== importedName) {
289
- aliases.set(localName, importedName);
290
- }
291
- }
170
+ const hasToken = source.includes(token);
171
+ tokenPresence.set(token, hasToken);
172
+ return hasToken;
173
+ };
174
+ const hasAnyToken = (source, tokens) => tokens.some((token) => hasTokenInSourceCached(source, token));
175
+ const cachedTokenGate = (source, tokens) => tokenGateCache.get(tokens)?.get(source);
176
+ const cacheTokenGate = (source, tokens, hasToken) => {
177
+ let sourceCache = tokenGateCache.get(tokens);
178
+ if (!sourceCache) {
179
+ sourceCache = new Map();
180
+ tokenGateCache.set(tokens, sourceCache);
292
181
  }
293
- for (const match of commentFreeSource.matchAll(/(?:^|\n)\s*import\s+(?!type\b)\*\s+as\s+([A-Za-z_$][\w$]*)\s+from\s*['"]effect\/([A-Za-z]+)['"]/g)) {
294
- const [, localName, moduleName] = match;
295
- if (canonicalNames.has(moduleName) && localName !== moduleName) {
296
- aliases.set(localName, moduleName);
182
+ if (sourceCache.size >= TOKEN_GATE_CACHE_MAX) {
183
+ const firstKey = sourceCache.keys().next().value;
184
+ if (firstKey !== undefined) {
185
+ sourceCache.delete(firstKey);
297
186
  }
298
187
  }
299
- return aliases;
300
- }
301
- function canonicalizeEffectApiAliases(source) {
302
- const cachedValue = canonicalSourceCache.get(source);
188
+ sourceCache.set(source, hasToken);
189
+ return hasToken;
190
+ };
191
+ const hasAnyTokenCached = (source, tokens) => {
192
+ const cachedValue = cachedTokenGate(source, tokens);
303
193
  if (cachedValue !== undefined) {
304
- canonicalSourceCache.delete(source);
305
- canonicalSourceCache.set(source, cachedValue);
306
194
  return cachedValue;
307
195
  }
308
- let canonicalSource = source;
309
- for (const [localName, canonicalName] of canonicalImportAliases(source)) {
310
- canonicalSource = canonicalSource.replace(new RegExp(`\\b${escapeRegExp(localName)}\\.`, 'g'), `${canonicalName}.`);
196
+ return cacheTokenGate(source, tokens, hasAnyToken(source, tokens));
197
+ };
198
+ const hasEveryTokenGroup = (source, tokenGroups) => tokenGroups.every((group) => hasAnyTokenCached(source, group));
199
+ const shouldSkipSource = (source, requiredTokens, requiredTokenGroups) => source === '' ||
200
+ Boolean(requiredTokens && !hasAnyTokenCached(source, requiredTokens)) ||
201
+ Boolean(requiredTokenGroups && !hasEveryTokenGroup(source, requiredTokenGroups));
202
+ const checkResultLOC = (source, spec, checkResult) => {
203
+ const index = checkResultIndex(checkResult);
204
+ if (index !== undefined) {
205
+ return locFromIndex(source, index);
311
206
  }
312
- if (canonicalSourceCache.size >= ALIAS_CACHE_MAX) {
313
- const firstKey = canonicalSourceCache.keys().next().value;
314
- if (firstKey !== undefined) {
315
- canonicalSourceCache.delete(firstKey);
207
+ return firstPatternLOC(source, spec.patterns ?? []);
208
+ };
209
+ const reportCheckResult = (context, node, source, spec, checkResult) => {
210
+ context.report({
211
+ loc: checkResultLOC(source, spec, checkResult),
212
+ message: effectDiagnosticMessage(spec.name, spec.message),
213
+ node,
214
+ });
215
+ };
216
+ const guidedContext = (context, spec) => ({
217
+ get filename() {
218
+ return context.filename;
219
+ },
220
+ get options() {
221
+ return context.options;
222
+ },
223
+ report(descriptor) {
224
+ context.report({
225
+ ...descriptor,
226
+ message: effectDiagnosticMessage(spec.name, descriptor.message),
227
+ });
228
+ },
229
+ get sourceCode() {
230
+ return context.sourceCode;
231
+ },
232
+ });
233
+ const runProgramRule = (input) => {
234
+ const { context, node, source, spec } = input;
235
+ const canonicalSource = canonicalizeEffectAPIAliases(source);
236
+ const checkResult = spec.check?.(canonicalSource, context);
237
+ if (checkResult !== undefined) {
238
+ if (!isCheckViolation(checkResult)) {
239
+ return;
316
240
  }
241
+ reportCheckResult(context, node, canonicalSource, spec, checkResult);
242
+ return;
317
243
  }
318
- canonicalSourceCache.set(source, canonicalSource);
319
- return canonicalSource;
320
- }
321
- function effectRuntimeFunctionAliases(source) {
322
- const cachedValue = cachedAliases(runtimeFunctionAliasCache, source);
323
- if (cachedValue) {
324
- return [...cachedValue];
244
+ if (hasPattern(canonicalSource, spec.patterns ?? [])) {
245
+ reportPatternMatches({ context, node, source: canonicalSource, spec });
325
246
  }
326
- const aliases = new Set();
327
- const runtimeNames = new Set([
328
- 'runFork',
329
- 'runPromise',
330
- 'runPromiseExit',
331
- 'runSync',
332
- 'runSyncExit',
333
- ]);
334
- const commentFreeSource = stripComments(source);
335
- for (const match of commentFreeSource.matchAll(/(?:^|\n)\s*import\s*{([^}]+)}\s*from\s*['"]effect\/Effect['"]/g)) {
336
- for (const specifier of match[1].split(',')) {
337
- const names = importSpecifierNames(specifier);
338
- const importedName = names?.importedName;
339
- const localName = names?.localName;
340
- if (importedName && localName && runtimeNames.has(importedName)) {
341
- aliases.add(localName);
247
+ };
248
+ const makeProgramOnlyRule = (spec, options) => {
249
+ const requiredTokens = spec.tokens ?? options.defaultTokens;
250
+ const requiredTokenGroups = spec.tokenGroups;
251
+ const rule = makeASTCapableRule(spec, options);
252
+ return {
253
+ ...rule,
254
+ createOnce(context) {
255
+ let source = '';
256
+ let isSkipped = true;
257
+ return {
258
+ Program(node) {
259
+ if (isSkipped) {
260
+ return;
261
+ }
262
+ runProgramRule({ context, node, source, spec });
263
+ },
264
+ before() {
265
+ source = readSource(context);
266
+ isSkipped = shouldSkipSource(source, requiredTokens, requiredTokenGroups);
267
+ if (isSkipped) {
268
+ return false;
269
+ }
270
+ return undefined;
271
+ },
272
+ };
273
+ },
274
+ };
275
+ };
276
+ const makeASTCapableRule = (spec, options) => {
277
+ const requiredTokens = spec.tokens ?? options.defaultTokens;
278
+ const requiredTokenGroups = spec.tokenGroups;
279
+ const rule = {
280
+ create(context) {
281
+ const source = readSource(context);
282
+ if (shouldSkipSource(source, requiredTokens, requiredTokenGroups)) {
283
+ return {
284
+ Program() { },
285
+ };
342
286
  }
343
- }
344
- }
345
- return [...cacheAliases(runtimeFunctionAliasCache, source, [...aliases])];
346
- }
347
- function hasRuntimeCall(source) {
348
- const code = stripCommentsAndStrings(source);
349
- if (runtimeCallPattern.test(code)) {
350
- return true;
287
+ const astContext = guidedContext(context, spec);
288
+ const astVisitors = spec.ast?.(astContext, source) ?? {};
289
+ return {
290
+ ...astVisitors,
291
+ Program(node) {
292
+ if (spec.ast && Array.isArray(node.body)) {
293
+ return;
294
+ }
295
+ runProgramRule({ context, node, source, spec });
296
+ },
297
+ };
298
+ },
299
+ meta: {
300
+ docs: {
301
+ description: effectDiagnosticMessage(spec.name, spec.message),
302
+ },
303
+ schema: options.schema,
304
+ type: 'problem',
305
+ },
306
+ };
307
+ return rule;
308
+ };
309
+ const makeProgramRule = (spec, options) => {
310
+ if (spec.ast) {
311
+ return makeASTCapableRule(spec, options);
351
312
  }
352
- return (effectImportAliases(source).some((alias) => new RegExp(`\\b${alias}\\.(?:runPromise|runPromiseExit|runSync|runSyncExit|runFork)\\s*\\(`).test(code)) ||
353
- effectRuntimeFunctionAliases(source).some((alias) => new RegExp(`\\b${alias}\\s*\\(`).test(code)));
354
- }
355
- function isBoundaryFile(filename) {
356
- return Boolean(filename && boundaryFilePattern.test(filename));
357
- }
358
- function isTestFile(filename) {
359
- return Boolean(filename && testFilePattern.test(filename));
360
- }
361
- export { hasEffectSignal, effectApiAliases, effectFunctionAliases, effectImportAliases, hasRuntimeCall, isBoundaryFile, isTestFile, makeRules, runtimeCallPattern, };
313
+ return makeProgramOnlyRule(spec, options);
314
+ };
315
+ /**
316
+ * Internal helper exported for package-local composition.
317
+ *
318
+ * @internal
319
+ */
320
+ export const makeRules = (specs, options = {}) => Object.fromEntries(specs.map((spec) => [spec.name, makeProgramRule(spec, options)]));
321
+ export { effectAPIAliases, effectFunctionAliases, effectImportAliases, hasEffectSignal, hasRuntimeCall, isBoundaryFile, isTestFile, runtimeCallPattern, } from './effect-rule-aliases.js';
362
322
  //# sourceMappingURL=effect-rule-core.js.map