eslint-plugin-complete 1.0.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 (171) hide show
  1. package/LICENSE +9 -0
  2. package/README.md +114 -0
  3. package/dist/comments.d.ts +22 -0
  4. package/dist/comments.d.ts.map +1 -0
  5. package/dist/comments.js +66 -0
  6. package/dist/completeCommon.d.ts +25 -0
  7. package/dist/completeCommon.d.ts.map +1 -0
  8. package/dist/completeCommon.js +53 -0
  9. package/dist/completeSentence.d.ts +9 -0
  10. package/dist/completeSentence.d.ts.map +1 -0
  11. package/dist/completeSentence.js +267 -0
  12. package/dist/configs/recommended.d.ts +3 -0
  13. package/dist/configs/recommended.d.ts.map +1 -0
  14. package/dist/configs/recommended.js +63 -0
  15. package/dist/configs.d.ts +4 -0
  16. package/dist/configs.d.ts.map +1 -0
  17. package/dist/configs.js +4 -0
  18. package/dist/constants.d.ts +8 -0
  19. package/dist/constants.d.ts.map +1 -0
  20. package/dist/constants.js +73 -0
  21. package/dist/format.d.ts +18 -0
  22. package/dist/format.d.ts.map +1 -0
  23. package/dist/format.js +246 -0
  24. package/dist/index.d.ts +60 -0
  25. package/dist/index.d.ts.map +1 -0
  26. package/dist/index.js +49 -0
  27. package/dist/interfaces/MyPluginDocs.d.ts +6 -0
  28. package/dist/interfaces/MyPluginDocs.d.ts.map +1 -0
  29. package/dist/interfaces/MyPluginDocs.js +1 -0
  30. package/dist/jsdoc.d.ts +4 -0
  31. package/dist/jsdoc.d.ts.map +1 -0
  32. package/dist/jsdoc.js +24 -0
  33. package/dist/leadingLineComments.d.ts +32 -0
  34. package/dist/leadingLineComments.d.ts.map +1 -0
  35. package/dist/leadingLineComments.js +77 -0
  36. package/dist/list.d.ts +49 -0
  37. package/dist/list.d.ts.map +1 -0
  38. package/dist/list.js +140 -0
  39. package/dist/rules/complete-sentences-jsdoc.d.ts +4 -0
  40. package/dist/rules/complete-sentences-jsdoc.d.ts.map +1 -0
  41. package/dist/rules/complete-sentences-jsdoc.js +48 -0
  42. package/dist/rules/complete-sentences-line-comments.d.ts +4 -0
  43. package/dist/rules/complete-sentences-line-comments.d.ts.map +1 -0
  44. package/dist/rules/complete-sentences-line-comments.js +88 -0
  45. package/dist/rules/consistent-enum-values.d.ts +2 -0
  46. package/dist/rules/consistent-enum-values.d.ts.map +1 -0
  47. package/dist/rules/consistent-enum-values.js +46 -0
  48. package/dist/rules/consistent-named-tuples.d.ts +2 -0
  49. package/dist/rules/consistent-named-tuples.d.ts.map +1 -0
  50. package/dist/rules/consistent-named-tuples.js +34 -0
  51. package/dist/rules/eqeqeq-fix.d.ts +2 -0
  52. package/dist/rules/eqeqeq-fix.d.ts.map +1 -0
  53. package/dist/rules/eqeqeq-fix.js +173 -0
  54. package/dist/rules/format-jsdoc-comments.d.ts +8 -0
  55. package/dist/rules/format-jsdoc-comments.d.ts.map +1 -0
  56. package/dist/rules/format-jsdoc-comments.js +117 -0
  57. package/dist/rules/format-line-comments.d.ts +8 -0
  58. package/dist/rules/format-line-comments.d.ts.map +1 -0
  59. package/dist/rules/format-line-comments.js +118 -0
  60. package/dist/rules/jsdoc-code-block-language.d.ts +2 -0
  61. package/dist/rules/jsdoc-code-block-language.d.ts.map +1 -0
  62. package/dist/rules/jsdoc-code-block-language.js +52 -0
  63. package/dist/rules/newline-between-switch-case.d.ts +4 -0
  64. package/dist/rules/newline-between-switch-case.d.ts.map +1 -0
  65. package/dist/rules/newline-between-switch-case.js +63 -0
  66. package/dist/rules/no-confusing-set-methods.d.ts +5 -0
  67. package/dist/rules/no-confusing-set-methods.d.ts.map +1 -0
  68. package/dist/rules/no-confusing-set-methods.js +51 -0
  69. package/dist/rules/no-empty-jsdoc.d.ts +2 -0
  70. package/dist/rules/no-empty-jsdoc.d.ts.map +1 -0
  71. package/dist/rules/no-empty-jsdoc.js +45 -0
  72. package/dist/rules/no-empty-line-comments.d.ts +2 -0
  73. package/dist/rules/no-empty-line-comments.d.ts.map +1 -0
  74. package/dist/rules/no-empty-line-comments.js +40 -0
  75. package/dist/rules/no-explicit-array-loops.d.ts +5 -0
  76. package/dist/rules/no-explicit-array-loops.d.ts.map +1 -0
  77. package/dist/rules/no-explicit-array-loops.js +114 -0
  78. package/dist/rules/no-explicit-map-set-loops.d.ts +5 -0
  79. package/dist/rules/no-explicit-map-set-loops.d.ts.map +1 -0
  80. package/dist/rules/no-explicit-map-set-loops.js +74 -0
  81. package/dist/rules/no-for-in.d.ts +2 -0
  82. package/dist/rules/no-for-in.d.ts.map +1 -0
  83. package/dist/rules/no-for-in.js +27 -0
  84. package/dist/rules/no-let-any.d.ts +3 -0
  85. package/dist/rules/no-let-any.d.ts.map +1 -0
  86. package/dist/rules/no-let-any.js +45 -0
  87. package/dist/rules/no-mutable-return.d.ts +5 -0
  88. package/dist/rules/no-mutable-return.d.ts.map +1 -0
  89. package/dist/rules/no-mutable-return.js +63 -0
  90. package/dist/rules/no-number-enums.d.ts +2 -0
  91. package/dist/rules/no-number-enums.d.ts.map +1 -0
  92. package/dist/rules/no-number-enums.js +27 -0
  93. package/dist/rules/no-object-any.d.ts +3 -0
  94. package/dist/rules/no-object-any.d.ts.map +1 -0
  95. package/dist/rules/no-object-any.js +51 -0
  96. package/dist/rules/no-object-methods-with-map-set.d.ts +5 -0
  97. package/dist/rules/no-object-methods-with-map-set.d.ts.map +1 -0
  98. package/dist/rules/no-object-methods-with-map-set.js +84 -0
  99. package/dist/rules/no-string-length-0.d.ts +3 -0
  100. package/dist/rules/no-string-length-0.d.ts.map +1 -0
  101. package/dist/rules/no-string-length-0.js +52 -0
  102. package/dist/rules/no-template-curly-in-string-fix.d.ts +6 -0
  103. package/dist/rules/no-template-curly-in-string-fix.d.ts.map +1 -0
  104. package/dist/rules/no-template-curly-in-string-fix.js +39 -0
  105. package/dist/rules/no-undefined-return-type.d.ts +3 -0
  106. package/dist/rules/no-undefined-return-type.d.ts.map +1 -0
  107. package/dist/rules/no-undefined-return-type.js +40 -0
  108. package/dist/rules/no-unnecessary-assignment.d.ts +5 -0
  109. package/dist/rules/no-unnecessary-assignment.d.ts.map +1 -0
  110. package/dist/rules/no-unnecessary-assignment.js +255 -0
  111. package/dist/rules/no-unsafe-plusplus.d.ts +2 -0
  112. package/dist/rules/no-unsafe-plusplus.d.ts.map +1 -0
  113. package/dist/rules/no-unsafe-plusplus.js +34 -0
  114. package/dist/rules/no-useless-return.d.ts +2 -0
  115. package/dist/rules/no-useless-return.d.ts.map +1 -0
  116. package/dist/rules/no-useless-return.js +347 -0
  117. package/dist/rules/no-void-return-type.d.ts +2 -0
  118. package/dist/rules/no-void-return-type.d.ts.map +1 -0
  119. package/dist/rules/no-void-return-type.js +49 -0
  120. package/dist/rules/prefer-const.d.ts +2 -0
  121. package/dist/rules/prefer-const.d.ts.map +1 -0
  122. package/dist/rules/prefer-const.js +426 -0
  123. package/dist/rules/prefer-plusplus.d.ts +5 -0
  124. package/dist/rules/prefer-plusplus.d.ts.map +1 -0
  125. package/dist/rules/prefer-plusplus.js +49 -0
  126. package/dist/rules/prefer-postfix-plusplus.d.ts +2 -0
  127. package/dist/rules/prefer-postfix-plusplus.d.ts.map +1 -0
  128. package/dist/rules/prefer-postfix-plusplus.js +32 -0
  129. package/dist/rules/prefer-readonly-parameter-types.d.ts +13 -0
  130. package/dist/rules/prefer-readonly-parameter-types.d.ts.map +1 -0
  131. package/dist/rules/prefer-readonly-parameter-types.js +140 -0
  132. package/dist/rules/require-break.d.ts +5 -0
  133. package/dist/rules/require-break.d.ts.map +1 -0
  134. package/dist/rules/require-break.js +76 -0
  135. package/dist/rules/require-capital-const-assertions.d.ts +4 -0
  136. package/dist/rules/require-capital-const-assertions.d.ts.map +1 -0
  137. package/dist/rules/require-capital-const-assertions.js +112 -0
  138. package/dist/rules/require-capital-read-only.d.ts +5 -0
  139. package/dist/rules/require-capital-read-only.d.ts.map +1 -0
  140. package/dist/rules/require-capital-read-only.js +111 -0
  141. package/dist/rules/require-unannotated-const-assertions.d.ts +2 -0
  142. package/dist/rules/require-unannotated-const-assertions.d.ts.map +1 -0
  143. package/dist/rules/require-unannotated-const-assertions.js +27 -0
  144. package/dist/rules/require-variadic-function-argument.d.ts +5 -0
  145. package/dist/rules/require-variadic-function-argument.d.ts.map +1 -0
  146. package/dist/rules/require-variadic-function-argument.js +86 -0
  147. package/dist/rules/strict-array-methods.d.ts +3 -0
  148. package/dist/rules/strict-array-methods.d.ts.map +1 -0
  149. package/dist/rules/strict-array-methods.js +83 -0
  150. package/dist/rules/strict-enums.d.ts +5 -0
  151. package/dist/rules/strict-enums.d.ts.map +1 -0
  152. package/dist/rules/strict-enums.js +445 -0
  153. package/dist/rules/strict-undefined-functions.d.ts +5 -0
  154. package/dist/rules/strict-undefined-functions.d.ts.map +1 -0
  155. package/dist/rules/strict-undefined-functions.js +49 -0
  156. package/dist/rules/strict-void-functions.d.ts +2 -0
  157. package/dist/rules/strict-void-functions.d.ts.map +1 -0
  158. package/dist/rules/strict-void-functions.js +43 -0
  159. package/dist/rules.d.ts +49 -0
  160. package/dist/rules.d.ts.map +1 -0
  161. package/dist/rules.js +85 -0
  162. package/dist/template.d.ts +2 -0
  163. package/dist/template.d.ts.map +1 -0
  164. package/dist/template.js +29 -0
  165. package/dist/typeUtils.d.ts +28 -0
  166. package/dist/typeUtils.d.ts.map +1 -0
  167. package/dist/typeUtils.js +76 -0
  168. package/dist/utils.d.ts +13 -0
  169. package/dist/utils.d.ts.map +1 -0
  170. package/dist/utils.js +54 -0
  171. package/package.json +55 -0
package/LICENSE ADDED
@@ -0,0 +1,9 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright The Complete Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
+
7
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,114 @@
1
+ # eslint-plugin-complete
2
+
3
+ `eslint-plugin-complete` is a collection of miscellaneous [ESLint](https://eslint.org/) rules that can help make your TypeScript code more safe or more strict.
4
+
5
+ If you already have ESLint set up in your project, then you can try enabling the [`complete/recommend`](#configs) config to get all of the goodness from this plugin in your project at once. Alternatively, if you want more control, feel free to enable the specific rules that you need.
6
+
7
+ Alternatively, if you want to get off the ground and running with ESLint + TypeScript in a new project, then you should check out the [`complete-lint`](https://github.com/complete-ts/complete/tree/main/packages/complete-lint) meta-package.
8
+
9
+ ## Install / Usage
10
+
11
+ If you do not want to use the `complete-lint` meta-package, then you can install this plugin manually:
12
+
13
+ - `npm install --save-dev eslint typescript eslint-plugin-complete` (`eslint` and `typescript` are peer-dependencies)
14
+ - TODO
15
+ - Add `"plugin:complete/recommended"` to the `extends` section of your `.eslintrc.cjs` file. (This will automatically add the plugin and add all of the recommended rules.)
16
+ - Alternatively, if you want to only enable some specific rules, then add `"complete"` to the `plugins` section of your `.eslintrc.cjs` file, and then add the specific rules that you want in the `rules` section.
17
+
18
+ ## Configs
19
+
20
+ - `recommended` - Currently, every rule in this plugin is recommended.
21
+
22
+ ## Rules
23
+
24
+ Each rule has emojis denoting:
25
+
26
+ - :white_check_mark: - if it belongs to the `recommended` configuration
27
+ - :wrench: - if some problems reported by the rule are automatically fixable by the `--fix` [command line option](https://eslint.org/docs/latest/user-guide/command-line-interface#fixing-problems)
28
+ - :thought_balloon: - if it requires type information
29
+
30
+ <!-- Do not manually modify the RULES_TABLE section. Instead, run: npm run generate -->
31
+ <!-- RULES_TABLE -->
32
+
33
+ | Name | Description | :white_check_mark: | :wrench: | :thought_balloon: |
34
+ | ----------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | ------------------ | -------- | ----------------- |
35
+ | [`complete/complete-sentences-jsdoc`](docs/rules/complete-sentences-jsdoc.md) | Requires complete sentences for JSDoc comments | :white_check_mark: | | |
36
+ | [`complete/complete-sentences-line-comments`](docs/rules/complete-sentences-line-comments.md) | Requires complete sentences for multi-line leading line comments | :white_check_mark: | | |
37
+ | [`complete/consistent-enum-values`](docs/rules/consistent-enum-values.md) | Requires consistent enum values | :white_check_mark: | | |
38
+ | [`complete/consistent-named-tuples`](docs/rules/consistent-named-tuples.md) | Requires that if one or more tuple elements are named, all of them are named | :white_check_mark: | | |
39
+ | [`complete/eqeqeq-fix`](docs/rules/eqeqeq-fix.md) | Requires the use of `===` and `!==` (and automatically fixes) | :white_check_mark: | :wrench: | |
40
+ | [`complete/format-jsdoc-comments`](docs/rules/format-jsdoc-comments.md) | Disallows `/**` comments longer than N characters and multi-line comments that can be merged together | :white_check_mark: | :wrench: | |
41
+ | [`complete/format-line-comments`](docs/rules/format-line-comments.md) | Disallows `//` comments longer than N characters and multi-line comments that can be merged together | :white_check_mark: | :wrench: | |
42
+ | [`complete/jsdoc-code-block-language`](docs/rules/jsdoc-code-block-language.md) | Requires a language specification for every JSDoc code block | :white_check_mark: | | |
43
+ | [`complete/newline-between-switch-case`](docs/rules/newline-between-switch-case.md) | Requires newlines between switch cases | :white_check_mark: | :wrench: | |
44
+ | [`complete/no-confusing-set-methods`](docs/rules/no-confusing-set-methods.md) | Disallows confusing methods for sets | :white_check_mark: | | :thought_balloon: |
45
+ | [`complete/no-empty-jsdoc`](docs/rules/no-empty-jsdoc.md) | Disallows empty JSDoc comments | :white_check_mark: | :wrench: | |
46
+ | [`complete/no-empty-line-comments`](docs/rules/no-empty-line-comments.md) | Disallows empty line comments | :white_check_mark: | :wrench: | |
47
+ | [`complete/no-explicit-array-loops`](docs/rules/no-explicit-array-loops.md) | Disallows explicit iteration for arrays | :white_check_mark: | :wrench: | :thought_balloon: |
48
+ | [`complete/no-explicit-map-set-loops`](docs/rules/no-explicit-map-set-loops.md) | Disallows explicit iteration for maps and sets | :white_check_mark: | :wrench: | :thought_balloon: |
49
+ | [`complete/no-for-in`](docs/rules/no-for-in.md) | Disallows "for x in y" statements | :white_check_mark: | | |
50
+ | [`complete/no-let-any`](docs/rules/no-let-any.md) | Disallows declaring variables with let that do not have a type | :white_check_mark: | | :thought_balloon: |
51
+ | [`complete/no-mutable-return`](docs/rules/no-mutable-return.md) | Disallows returning mutable arrays, maps, and sets from functions | :white_check_mark: | | :thought_balloon: |
52
+ | [`complete/no-number-enums`](docs/rules/no-number-enums.md) | Disallows number enums | :white_check_mark: | | |
53
+ | [`complete/no-object-any`](docs/rules/no-object-any.md) | Disallows declaring objects and arrays that do not have a type | :white_check_mark: | | :thought_balloon: |
54
+ | [`complete/no-object-methods-with-map-set`](docs/rules/no-object-methods-with-map-set.md) | Disallows using object methods with maps and sets | :white_check_mark: | | :thought_balloon: |
55
+ | [`complete/no-string-length-0`](docs/rules/no-string-length-0.md) | Disallows checking for empty strings via the length method in favor of direct comparison to an empty string | :white_check_mark: | | :thought_balloon: |
56
+ | [`complete/no-template-curly-in-string-fix`](docs/rules/no-template-curly-in-string-fix.md) | Disallows template literal placeholder syntax in regular strings (and automatically fixes) | :white_check_mark: | :wrench: | |
57
+ | [`complete/no-undefined-return-type`](docs/rules/no-undefined-return-type.md) | Disallows `undefined` return types on functions | :white_check_mark: | | :thought_balloon: |
58
+ | [`complete/no-unnecessary-assignment`](docs/rules/no-unnecessary-assignment.md) | Disallows useless assignments | :white_check_mark: | | :thought_balloon: |
59
+ | [`complete/no-unsafe-plusplus`](docs/rules/no-unsafe-plusplus.md) | Disallow unsafe and confusing uses of the "++" and "--" operators | :white_check_mark: | | :thought_balloon: |
60
+ | [`complete/no-useless-return`](docs/rules/no-useless-return.md) | Disallow redundant return statements (with no auto-fixer) | :white_check_mark: | | |
61
+ | [`complete/no-void-return-type`](docs/rules/no-void-return-type.md) | Disallows `void` return types on non-exported functions | :white_check_mark: | :wrench: | |
62
+ | [`complete/prefer-const`](docs/rules/prefer-const.md) | Require `const` declarations for variables that are never reassigned after declared (with no auto-fixer) | :white_check_mark: | | |
63
+ | [`complete/prefer-plusplus`](docs/rules/prefer-plusplus.md) | Require "++" or "--" operators instead of assignment operators where applicable | :white_check_mark: | :wrench: | |
64
+ | [`complete/prefer-postfix-plusplus`](docs/rules/prefer-postfix-plusplus.md) | Require "i++" instead of "++i" | :white_check_mark: | | :thought_balloon: |
65
+ | [`complete/prefer-readonly-parameter-types`](docs/rules/prefer-readonly-parameter-types.md) | Require function parameters to be typed as `readonly` to prevent accidental mutation of inputs | :white_check_mark: | | :thought_balloon: |
66
+ | [`complete/require-break`](docs/rules/require-break.md) | Requires that each case of a switch statement has a `break` statement | :white_check_mark: | | |
67
+ | [`complete/require-capital-const-assertions`](docs/rules/require-capital-const-assertions.md) | Requires a capital letter for named objects and arrays that have a const assertion | :white_check_mark: | :wrench: | |
68
+ | [`complete/require-capital-read-only`](docs/rules/require-capital-read-only.md) | Requires maps/sets/arrays with a capital letter to be read-only | :white_check_mark: | | :thought_balloon: |
69
+ | [`complete/require-unannotated-const-assertions`](docs/rules/require-unannotated-const-assertions.md) | Disallows explicit type annotations for variables that have a const assertion | :white_check_mark: | | |
70
+ | [`complete/require-variadic-function-argument`](docs/rules/require-variadic-function-argument.md) | Requires that variadic functions must be supplied with at least one argument | :white_check_mark: | | :thought_balloon: |
71
+ | [`complete/strict-array-methods`](docs/rules/strict-array-methods.md) | Requires boolean return types on array method functions | :white_check_mark: | | :thought_balloon: |
72
+ | [`complete/strict-enums`](docs/rules/strict-enums.md) | Disallows the usage of unsafe enum patterns | :white_check_mark: | | :thought_balloon: |
73
+ | [`complete/strict-undefined-functions`](docs/rules/strict-undefined-functions.md) | Disallows empty return statements in functions annotated as returning undefined | :white_check_mark: | | :thought_balloon: |
74
+ | [`complete/strict-void-functions`](docs/rules/strict-void-functions.md) | Disallows non-empty return statements in functions annotated as returning void | :white_check_mark: | | |
75
+
76
+ <!-- /RULES_TABLE -->
77
+
78
+ ## Automatic Fixing
79
+
80
+ You probably already use [Prettier](https://prettier.io/), which is helpful to automatically format files. You probably even have your IDE set up to run Prettier every time your save a file. This kind of thing saves you a tremendous amount of time - you can type out a bunch of code completely unformatted, and then press `Ctrl + s` at the end to automatically fix everything. (Alternatively, you could press `Ctrl + shift + f` to format the file without saving it, but it's simpler to just use one hotkey for everything.)
81
+
82
+ In a similar way to Prettier, this ESLint plugin contains several rules that are designed to automatically apply whenever you save the file (like the [`format-jsdoc-comments`](docs/rules/format-jsdoc-comments.md) rule). These rules are "fixers", which are applied when ESLint is executed with the "--fix" flag. So, in the same way that you configure Prettier to run on save, you should also configure `eslint --fix` to run on save.
83
+
84
+ For example, if you use [VSCode](https://code.visualstudio.com/), and you have the [Prettier](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) and the [ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) extensions installed, you can add the following to your repository's `.vscode/settings.json` file:
85
+
86
+ ```jsonc
87
+ {
88
+ // Automatically run the formatter when certain files are saved.
89
+ "[javascript][typescript][javascriptreact][typescriptreact]": {
90
+ "editor.codeActionsOnSave": {
91
+ "source.fixAll.eslint": "explicit",
92
+ },
93
+ "editor.defaultFormatter": "esbenp.prettier-vscode",
94
+ "editor.formatOnSave": true,
95
+ },
96
+ }
97
+ ```
98
+
99
+ ## Comment Formatting
100
+
101
+ For a discussion around comments and the motivations for some of the comment rules in the plugin, see [this page](docs/comments.md).
102
+
103
+ ## Contributing
104
+
105
+ Thanks for helping out with this open-source project!
106
+
107
+ If you are adding a new rule, start by using the `create-rule` script to automate a few things:
108
+
109
+ ```sh
110
+ npm run create-rule foo "This is a description of the foo rule."
111
+ git status # Show what the script did.
112
+ ```
113
+
114
+ Additionally, You can contact me [on Discord](https://discord.gg/KapmKQ2gUD) if you are doing a PR and have questions.
@@ -0,0 +1,22 @@
1
+ import type { TSESLint, TSESTree } from "@typescript-eslint/utils";
2
+ /**
3
+ * Returns false for trailing comments like:
4
+ *
5
+ * ```ts
6
+ * const abc = 123; // Foo
7
+ * ```
8
+ */
9
+ export declare function isCommentOnOwnLine(sourceCode: TSESLint.SourceCode, comment: TSESTree.Comment): boolean;
10
+ export declare function isEnumBlockLabel(text: string): boolean;
11
+ /**
12
+ * A "separator" line is a line with all hyphens like the following:
13
+ *
14
+ * ```ts
15
+ * // ----------------
16
+ * // Getter functions
17
+ * // ----------------
18
+ * ```
19
+ */
20
+ export declare function isSeparatorLine(text: string): boolean;
21
+ export declare function isSpecialComment(text: string): boolean;
22
+ //# sourceMappingURL=comments.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"comments.d.ts","sourceRoot":"","sources":["../src/comments.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAEnE;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,QAAQ,CAAC,UAAU,EAC/B,OAAO,EAAE,QAAQ,CAAC,OAAO,GACxB,OAAO,CAYT;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CA2BtD;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAErD;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CActD"}
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Returns false for trailing comments like:
3
+ *
4
+ * ```ts
5
+ * const abc = 123; // Foo
6
+ * ```
7
+ */
8
+ export function isCommentOnOwnLine(sourceCode, comment) {
9
+ const startLine = comment.loc.start.line;
10
+ const endLine = comment.loc.end.line;
11
+ const previousToken = sourceCode.getTokenBefore(comment);
12
+ const previousTokenEndLine = previousToken === null ? null : previousToken.loc.end.line;
13
+ const nextToken = sourceCode.getTokenAfter(comment);
14
+ const nextTokenStartLine = nextToken === null ? null : nextToken.loc.start.line;
15
+ return startLine !== previousTokenEndLine && endLine !== nextTokenStartLine;
16
+ }
17
+ export function isEnumBlockLabel(text) {
18
+ text = text.trim();
19
+ return (
20
+ // e.g. CollectibleType.SAD_ONION
21
+ /^\w+\.\w+$/.test(text) ||
22
+ // e.g. CollectibleType.SAD_ONION (1)
23
+ /^\w+\.\w+ \(\d+\)$/.test(text) ||
24
+ // e.g. CacheFlag.FIRE_DELAY (1 << 1)
25
+ /^\w+\.\w+ \(\d+ << \d+\)$/.test(text) ||
26
+ // e.g. 1
27
+ /^\d+$/.test(text) ||
28
+ // e.g. 1.0
29
+ /^\d+\.\d+$/.test(text) ||
30
+ // e.g. 1 << 1
31
+ /^\d+ << \d+$/.test(text) ||
32
+ // e.g. 1, 2, 3, 4, 5
33
+ /^\d+, \d+$/.test(text) ||
34
+ /^\d+, \d+, \d+$/.test(text) ||
35
+ /^(?:\d+, ){3}\d+$/.test(text) ||
36
+ /^(?:\d+, ){4}\d+$/.test(text) ||
37
+ // e.g. 1.0, 2.0, 3.0, 4.0, 5.0
38
+ /^\d+\.\d+, \d+\.\d+$/.test(text) ||
39
+ /^(?:\d+\.\d+, ){2}\d+\.\d+$/.test(text) ||
40
+ /^(?:\d+\.\d+, ){3}\d+\.\d+$/.test(text) ||
41
+ /^(?:\d+\.\d+, ){4}\d+\.\d+$/.test(text));
42
+ }
43
+ /**
44
+ * A "separator" line is a line with all hyphens like the following:
45
+ *
46
+ * ```ts
47
+ * // ----------------
48
+ * // Getter functions
49
+ * // ----------------
50
+ * ```
51
+ */
52
+ export function isSeparatorLine(text) {
53
+ return /^\s*-+\s*$/.test(text);
54
+ }
55
+ export function isSpecialComment(text) {
56
+ text = text.trim();
57
+ return (text.startsWith("eslint-") ||
58
+ text.startsWith("prettier-") ||
59
+ text.startsWith("cspell:") ||
60
+ text.startsWith("ts-prune-") || // e.g. ts-prune-ignore-next
61
+ text.startsWith("@ts-") ||
62
+ text.startsWith("TODO:") ||
63
+ text.startsWith("FIXME:") ||
64
+ text === "TODO" ||
65
+ text === "FIXME");
66
+ }
@@ -0,0 +1,25 @@
1
+ export type ReadonlyRecord<K extends string | number | symbol, V> = Readonly<Record<K, V>>;
2
+ /**
3
+ * Helper function to throw an error if the provided value is equal to `undefined`.
4
+ *
5
+ * This is useful to have TypeScript narrow a `T | undefined` value to `T` in a concise way.
6
+ */
7
+ export declare function assertDefined<T>(value: T, ...[msg]: [undefined] extends [T] ? [string] : [
8
+ "The assertion is useless because the provided value does not contain undefined."
9
+ ]): asserts value is Exclude<T, undefined>;
10
+ export declare function capitalizeFirstLetter(string: string): string;
11
+ /**
12
+ * From:
13
+ * https://stackoverflow.com/questions/8334606/check-if-first-letter-of-word-is-a-capital-letter
14
+ */
15
+ export declare function isFirstLetterCapitalized(string: string): boolean;
16
+ /**
17
+ * Helper function to trim a prefix from a string, if it exists. Returns the trimmed string.
18
+ *
19
+ * @param string The string to trim.
20
+ * @param prefix The prefix to trim.
21
+ * @param trimAll Whether to remove multiple instances of the prefix, if they exist. If this is set
22
+ * to true, the prefix must only be a single character.
23
+ */
24
+ export declare function trimPrefix(string: string, prefix: string, trimAll?: boolean): string;
25
+ //# sourceMappingURL=completeCommon.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"completeCommon.d.ts","sourceRoot":"","sources":["../src/completeCommon.ts"],"names":[],"mappings":"AASA,MAAM,MAAM,cAAc,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,GAAG,MAAM,EAAE,CAAC,IAAI,QAAQ,CAC1E,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CACb,CAAC;AAIF;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAC7B,KAAK,EAAE,CAAC,EACR,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,GAC7B,CAAC,MAAM,CAAC,GACR;IACE,iFAAiF;CAClF,GACJ,OAAO,CAAC,KAAK,IAAI,OAAO,CAAC,CAAC,EAAE,SAAS,CAAC,CAIxC;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAU5D;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAEhE;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,CACxB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,OAAO,UAAQ,GACd,MAAM,CAWR"}
@@ -0,0 +1,53 @@
1
+ // We do not want "eslint-plugin-complete" to depend on "complete-common" because it complicates the
2
+ // usage of the plugin inside of the monorepo. Specifically, since we manually copy the compiled
3
+ // output to the monorepo "node_modules" directory, it would cause errors if the "complete-common"
4
+ // directory did not also exist there. To fix this, we could also compile and copy "complete-common"
5
+ // in the build script for this plugin. However, that is undesirable for two reasons:
6
+ // 1) It increases the complexity of the build script.
7
+ // 2) If "complete-common" exists in the monorepo's "node_modules" directory, it can cause bugs due
8
+ // to tooling preferring the "real" directory over the tsconfig "paths" resolution.
9
+ const FIRST_LETTER_CAPITALIZED_REGEX = /^\p{Lu}/u;
10
+ /**
11
+ * Helper function to throw an error if the provided value is equal to `undefined`.
12
+ *
13
+ * This is useful to have TypeScript narrow a `T | undefined` value to `T` in a concise way.
14
+ */
15
+ export function assertDefined(value, ...[msg]) {
16
+ if (value === undefined) {
17
+ throw new TypeError(msg);
18
+ }
19
+ }
20
+ export function capitalizeFirstLetter(string) {
21
+ if (string === "") {
22
+ return string;
23
+ }
24
+ const firstCharacter = string.charAt(0);
25
+ const capitalizedFirstLetter = firstCharacter.toUpperCase();
26
+ const restOfString = string.slice(1);
27
+ return `${capitalizedFirstLetter}${restOfString}`;
28
+ }
29
+ /**
30
+ * From:
31
+ * https://stackoverflow.com/questions/8334606/check-if-first-letter-of-word-is-a-capital-letter
32
+ */
33
+ export function isFirstLetterCapitalized(string) {
34
+ return FIRST_LETTER_CAPITALIZED_REGEX.test(string);
35
+ }
36
+ /**
37
+ * Helper function to trim a prefix from a string, if it exists. Returns the trimmed string.
38
+ *
39
+ * @param string The string to trim.
40
+ * @param prefix The prefix to trim.
41
+ * @param trimAll Whether to remove multiple instances of the prefix, if they exist. If this is set
42
+ * to true, the prefix must only be a single character.
43
+ */
44
+ export function trimPrefix(string, prefix, trimAll = false) {
45
+ if (trimAll) {
46
+ const regExp = new RegExp(`^${prefix}+`, "g");
47
+ return string.replaceAll(regExp, "");
48
+ }
49
+ if (!string.startsWith(prefix)) {
50
+ return string;
51
+ }
52
+ return string.slice(prefix.length);
53
+ }
@@ -0,0 +1,9 @@
1
+ export type CompleteSentenceMessageIds = "missingCapital" | "missingPeriod" | "doublePeriod";
2
+ interface IncompleteSentence {
3
+ sentence: string;
4
+ messageId: CompleteSentenceMessageIds;
5
+ }
6
+ export declare function getIncompleteSentences(text: string): readonly IncompleteSentence[];
7
+ export declare function getSentences(text: string): readonly string[];
8
+ export {};
9
+ //# sourceMappingURL=completeSentence.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"completeSentence.d.ts","sourceRoot":"","sources":["../src/completeSentence.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,0BAA0B,GAClC,gBAAgB,GAChB,eAAe,GACf,cAAc,CAAC;AAEnB,UAAU,kBAAkB;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,0BAA0B,CAAC;CACvC;AAmBD,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,MAAM,GACX,SAAS,kBAAkB,EAAE,CAiC/B;AAwID,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAO5D"}
@@ -0,0 +1,267 @@
1
+ import { isEnumBlockLabel, isSpecialComment } from "./comments.js";
2
+ import { getAdjustedList, reachedNewList } from "./list.js";
3
+ import { hasURL } from "./utils.js";
4
+ /**
5
+ * From:
6
+ * https://stackoverflow.com/questions/23571013/how-to-remove-url-from-a-string-completely-in-javascript
7
+ */
8
+ const FULL_URL_REGEX = /(?:https?|ftp):\/\/[\S\n]+/g;
9
+ /**
10
+ * From:
11
+ * https://stackoverflow.com/questions/11761563/javascript-regexp-for-splitting-text-into-sentences-and-keeping-the-delimiter
12
+ */
13
+ const SENTENCE_REGEX = /(?=[^])(?:\P{Sentence_Terminal}|\p{Sentence_Terminal}(?!['"`\p{Close_Punctuation}\p{Final_Punctuation}\s]))*(?:\p{Sentence_Terminal}+['"`\p{Close_Punctuation}\p{Final_Punctuation}]*|$)/guy;
14
+ const SENTENCE_SEPARATOR_IDENTIFIER = "___sentence_separator_identifier___";
15
+ const IN_LINE_CODE_IDENTIFIER = "___in_line_code_identifier___";
16
+ const LIST_ELEMENT_IDENTIFIER = "___list_element_identifier___";
17
+ export function getIncompleteSentences(text) {
18
+ const incompleteSentences = [];
19
+ const textBlocks = splitOnSpecialText(text);
20
+ for (const textBlock of textBlocks) {
21
+ // Handle text that "spills over" to the next line by simply converting all newlines to spaces.
22
+ const squishedText = textBlock.split("\n").join(" ").trim();
23
+ // Handling all edge cases for "e.g." or "i.e." is very difficult, since sometimes it is correct
24
+ // to put a period after them, and sometimes not. Thus, ignore all text that contains them.
25
+ if (squishedText.includes("e.g.") || squishedText.includes("i.e.")) {
26
+ continue;
27
+ }
28
+ // Whitelist markdown links.
29
+ if (squishedText.endsWith("](")) {
30
+ continue;
31
+ }
32
+ const sentences = getSentences(squishedText);
33
+ const loneSentence = sentences.length === 1;
34
+ for (const sentence of sentences) {
35
+ const messageId = getIncompleteSentenceKind(sentence, loneSentence);
36
+ if (messageId !== undefined) {
37
+ incompleteSentences.push({
38
+ sentence,
39
+ messageId,
40
+ });
41
+ }
42
+ }
43
+ }
44
+ return incompleteSentences;
45
+ }
46
+ /**
47
+ * Before parsing a multi-line string to get the sentences, we first need to mutate the input to
48
+ * handle some problematic situations.
49
+ */
50
+ function splitOnSpecialText(text) {
51
+ // Below, we avoid replacing certain things to an empty string because that can potentially cause
52
+ // subsequent text to be considered to be part of the previous sentence.
53
+ // Remove multi-line code blocks.
54
+ text = text.replaceAll(/```[\S\s]*```/gm, SENTENCE_SEPARATOR_IDENTIFIER);
55
+ // Remove example tag blocks. An example tag might be followed by another tag, so first look for
56
+ // that situation. Then, handle the situation where the example tag is the final tag.
57
+ text = text.replaceAll(
58
+ // We use `[\s\S]` instead of `.` because the latter does not match a new line.
59
+ /@example[\S\s]*?@/gm, `${SENTENCE_SEPARATOR_IDENTIFIER}@`);
60
+ text = text.replaceAll(/@example[\S\s]*/gm, "");
61
+ // Remove see tag blocks. A see tag might be followed by another tag, so first look for that
62
+ // situation. Then, handle the situation where the see tag is the final tag. (This is copy-pasted
63
+ // from the code that handles example tags above.)
64
+ text = text.replaceAll(
65
+ // We use `[\s\S]` instead of `.` because the latter does not match a new line.
66
+ /@see[\S\s]*?@/gm, `${SENTENCE_SEPARATOR_IDENTIFIER}@`);
67
+ text = text.replaceAll(/@see[\S\s]*/gm, "");
68
+ // Replace the link tags with the link text. Note that if we replace them with a sentence
69
+ // separator instead, then the following sentence would fail: Get the name of a peripheral wrapped
70
+ // with {@link peripheral.wrap}.
71
+ // https://regex101.com/r/0u8hQG/1
72
+ // https://jsdoc.app/tags-inline-link.html
73
+ text = text.replaceAll(/\[([^\]]*)]{@link [^ |}]+}|{@link ([^ |}]+)[ |]?}|{@link [^ |}]+[ |]([^}]+)}/gm, "$1$2$3");
74
+ // Remove Markdown headers.
75
+ text = text.replaceAll(/^\n\s*#.*\n\n/gm, SENTENCE_SEPARATOR_IDENTIFIER);
76
+ if (text.trimStart().startsWith("#")) {
77
+ // Also handle if the first line is a Markdown header.
78
+ text = text.replace(/^\s*#.*\n\n/m, SENTENCE_SEPARATOR_IDENTIFIER);
79
+ }
80
+ // Remove pipes (which indicate a Markdown table).
81
+ text = text.replaceAll("|", SENTENCE_SEPARATOR_IDENTIFIER);
82
+ // Handle "blocks" indicated by a double newline. We don't want sentences to be parsed/combined
83
+ // past blocks, so we manually insert a sentence separator.
84
+ text = text.replaceAll("\n\n", `\n${SENTENCE_SEPARATOR_IDENTIFIER}\n`);
85
+ // Handle quoted question marks.
86
+ // e.g. This text contains "???" in the middle.
87
+ text = text.replaceAll(/'\?+'/g, "");
88
+ text = text.replaceAll(/"\?+"/g, "");
89
+ const lines = text.split("\n");
90
+ const newLines = [];
91
+ let insideList;
92
+ for (const [i, originalLine] of lines.entries()) {
93
+ let line = originalLine;
94
+ // Ignore "@type" JSDoc tags, since they contain a code type instead of English text.
95
+ // https://jsdoc.app/tags-type.html
96
+ line = line.replace(/^\s*@type .+$/, SENTENCE_SEPARATOR_IDENTIFIER);
97
+ // Remove any JSDoc tags. (But leave the descriptions following the tags, if any.) "@param" tags
98
+ // are followed by variable names, which will not be part of the sentence.
99
+ line = line.replace(/^\s*@param \w+ /, SENTENCE_SEPARATOR_IDENTIFIER);
100
+ // This is "\S+" instead of "\w+" because we need to match things like "@ts-expect-error".
101
+ line = line.replace(/^\s*@\S+/, SENTENCE_SEPARATOR_IDENTIFIER);
102
+ // Replace any single-line code snippets with custom text. The custom text begins with an
103
+ // underscore, which means that it will count towards the sentence starting with a capital
104
+ // letter. (This is only relevant if the code block is the first word in the sentence.)
105
+ line = line.replaceAll(/`.+`/g, IN_LINE_CODE_IDENTIFIER);
106
+ // Remove any URLs present in the string, as the periods will count as sentence terminators.
107
+ // e.g. "This is my URL: https://stackoverflow."
108
+ line = line.replaceAll(FULL_URL_REGEX, "");
109
+ // Remove the periods from some common abbreviations so that they do not mess up the sentence
110
+ // parsing.
111
+ line = line.replaceAll(/\bDr\.\s+/g, "Dr");
112
+ line = line.replaceAll(/\bJr\.\s+/g, "Jr");
113
+ line = line.replaceAll(/\bMr\.\s+/g, "Mr");
114
+ line = line.replaceAll(/\bMrs\.\s+/g, "Mrs");
115
+ line = line.replaceAll(/\bMs\.\s+/g, "Ms");
116
+ line = line.replaceAll(/\bSr\.\s+/g, "Sr");
117
+ line = line.replaceAll(/\bSt\.\s+/g, "St");
118
+ line = line.replaceAll(/\betc\.\s+/g, "etc");
119
+ // Replace list bullet headers, since they are never part of a sentence. We also need to mark
120
+ // that this sentence is a list element for the purposes of ignoring any incomplete sentences.
121
+ // Doing this allows short lists like:
122
+ // - apple
123
+ // - banana
124
+ const previousLine = lines[i - 1];
125
+ const previousLineWasBlank = previousLine === undefined || previousLine.trim() === "";
126
+ const previousLineEndedInColon = previousLine !== undefined && previousLine.trimEnd().endsWith(":");
127
+ const list = getAdjustedList(line, previousLineWasBlank, previousLineEndedInColon, insideList);
128
+ if (reachedNewList(insideList, list)) {
129
+ // Keep track that we have begun a list (or a new sub-list).
130
+ insideList = list;
131
+ }
132
+ if (list !== undefined) {
133
+ line = line.slice(list.markerSize);
134
+ line = SENTENCE_SEPARATOR_IDENTIFIER + LIST_ELEMENT_IDENTIFIER + line;
135
+ }
136
+ // Split enum block labels.
137
+ if (isEnumBlockLabel(line)) {
138
+ line += SENTENCE_SEPARATOR_IDENTIFIER;
139
+ }
140
+ newLines.push(line);
141
+ }
142
+ const textBlocks = newLines.join("\n").split(SENTENCE_SEPARATOR_IDENTIFIER);
143
+ return textBlocks.filter((textBlock) => !isEnumBlockLabel(textBlock));
144
+ }
145
+ export function getSentences(text) {
146
+ const match = text.match(SENTENCE_REGEX);
147
+ if (match === null) {
148
+ return [];
149
+ }
150
+ return match;
151
+ }
152
+ function getIncompleteSentenceKind(sentence, loneSentence) {
153
+ let text = sentence;
154
+ // Trim the parenthesis surrounding the sentence, if any.
155
+ let textBeforeModifications;
156
+ do {
157
+ textBeforeModifications = text;
158
+ text = text.trim().replace(/^\(*/, "").replace(/\)*$/, "").trim();
159
+ } while (text !== textBeforeModifications);
160
+ // Ignore / whitelist some specific things.
161
+ if (
162
+ // Blank text.
163
+ text === "" ||
164
+ // Sentences that do not contain any letters.
165
+ !/[A-Za-z]/.test(text) ||
166
+ // Sentences with an arrow, like: "Alice --> Bob"
167
+ text.includes("-->") ||
168
+ // Placeholder text.
169
+ text === "n/a" ||
170
+ // Special comments.
171
+ isSpecialComment(text) ||
172
+ // Dates.
173
+ isDate(text) ||
174
+ // URLS.
175
+ hasURL(text) ||
176
+ // Single JSDoc tags.
177
+ /^@\w+$/.test(text) ||
178
+ // Lists.
179
+ text.startsWith(LIST_ELEMENT_IDENTIFIER) ||
180
+ // Code blocks.
181
+ text.includes("```") ||
182
+ // Sentences that end with a number in parenthesis (which indicates some kind of expression).
183
+ // This must check the original text.
184
+ / \(\d+\)$/.test(sentence.trimEnd())) {
185
+ return undefined;
186
+ }
187
+ // First, check for a double period.
188
+ if (text.endsWith("..") && text.length >= 3) {
189
+ const characterBeforePeriods = text.at(-3);
190
+ if (characterBeforePeriods !== ".") {
191
+ return "doublePeriod";
192
+ }
193
+ }
194
+ if (loneSentence &&
195
+ // Single words, double words, and triple words.
196
+ (/^\S+$/.test(text) || /^\S+ \S+$/.test(text) || /^\S+ \S+ \S+$/.test(text))) {
197
+ return undefined;
198
+ }
199
+ if (/^[a-z]/.test(text) && !isCapitalizedWordException(text)) {
200
+ return "missingCapital";
201
+ }
202
+ if (
203
+ // Allow normal end-of-line punctuation.
204
+ !text.endsWith(".") &&
205
+ !text.endsWith("!") &&
206
+ !text.endsWith("?") &&
207
+ // Allow ending with a period inside of a single quote or double quote, since it is implied that
208
+ // this is a fully quoted sentence.
209
+ !text.endsWith('."') &&
210
+ !text.endsWith('!"') &&
211
+ !text.endsWith('?"') &&
212
+ !text.endsWith(".'") &&
213
+ !text.endsWith("!'") &&
214
+ !text.endsWith("?'") &&
215
+ // Allow ending with a colon, since it is implied that there is an example of something on the
216
+ // subsequent block.
217
+ !text.endsWith(":") &&
218
+ // Allow ending with anything if there is a colon in the middle of the sentence, since it is
219
+ // implied that this is an example of something.
220
+ !text.includes(": ")) {
221
+ return "missingPeriod";
222
+ }
223
+ return undefined;
224
+ }
225
+ const CAPITALIZED_WORD_EXCEPTIONS = ["iPad", "iPhone", "iPod"];
226
+ function isCapitalizedWordException(text) {
227
+ return CAPITALIZED_WORD_EXCEPTIONS.some((word) => text.startsWith(word));
228
+ }
229
+ const MONTHS_SET = new Set([
230
+ "January",
231
+ "February",
232
+ "March",
233
+ "April",
234
+ "May",
235
+ "June",
236
+ "July",
237
+ "August",
238
+ "September",
239
+ "October",
240
+ "November",
241
+ "December",
242
+ ]);
243
+ const ORDINALS_SET = new Set(["st", "nd", "rd", "th"]);
244
+ function isDate(text) {
245
+ text = text.trim();
246
+ const match1 = text.match(/^(?<month>\w+) \d+(?<ordinal>\w+)$/);
247
+ if (match1 !== null && match1.groups !== undefined) {
248
+ const { month, ordinal } = match1.groups;
249
+ if (month !== undefined &&
250
+ MONTHS_SET.has(month) &&
251
+ ordinal !== undefined &&
252
+ ORDINALS_SET.has(ordinal)) {
253
+ return true;
254
+ }
255
+ }
256
+ const match2 = text.match(/^(?<month>\w+) \d+(?<ordinal>\w+), \d+$/);
257
+ if (match2 !== null && match2.groups !== undefined) {
258
+ const { month, ordinal } = match2.groups;
259
+ if (month !== undefined &&
260
+ MONTHS_SET.has(month) &&
261
+ ordinal !== undefined &&
262
+ ORDINALS_SET.has(ordinal)) {
263
+ return true;
264
+ }
265
+ }
266
+ return false;
267
+ }
@@ -0,0 +1,3 @@
1
+ import type { TSESLint } from "@typescript-eslint/utils";
2
+ export declare const recommended: TSESLint.FlatConfig.ConfigArray;
3
+ //# sourceMappingURL=recommended.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recommended.d.ts","sourceRoot":"","sources":["../../src/configs/recommended.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAEzD,eAAO,MAAM,WAAW,EAAE,QAAQ,CAAC,UAAU,CAAC,WA2D7C,CAAC"}