eslint-plugin-flawless 0.1.6 → 0.1.7
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 +11 -11
- package/dist/index.d.mts +20 -4
- package/dist/index.mjs +78 -16
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -176,17 +176,17 @@ pnpm eslint-docs
|
|
|
176
176
|
💭
|
|
177
177
|
Requires [type information](https://typescript-eslint.io/linting/typed-linting).
|
|
178
178
|
|
|
179
|
-
| Name | Description
|
|
180
|
-
| :-------------------------------------------------------------------------------------------- |
|
|
181
|
-
| [jsx-shorthand-boolean](src/rules/jsx-shorthand-boolean/documentation.md) | Disallow shorthand boolean JSX attributes
|
|
182
|
-
| [jsx-shorthand-fragment](src/rules/jsx-shorthand-fragment/documentation.md) |
|
|
183
|
-
| [naming-convention](src/rules/naming-convention/documentation.md) | Enforce naming conventions for everything across a codebase
|
|
184
|
-
| [no-unnecessary-use-callback](src/rules/no-unnecessary-use-callback/documentation.md) | Disallow unnecessary usage of 'useCallback'
|
|
185
|
-
| [no-unnecessary-use-memo](src/rules/no-unnecessary-use-memo/documentation.md) | Disallow unnecessary usage of 'useMemo'
|
|
186
|
-
| [prefer-destructuring-assignment](src/rules/prefer-destructuring-assignment/documentation.md) | Enforce destructuring assignment for component props
|
|
187
|
-
| [purity](src/rules/purity/documentation.md) | Disallow impure calls such as `math.random` or `os.clock` during render
|
|
188
|
-
| [toml-sort-keys](src/rules/toml-sort-keys/documentation.md) | Enforce a configured sort order for TOML keys and tables
|
|
189
|
-
| [yaml-block-key-blank-lines](src/rules/yaml-block-key-blank-lines/documentation.md) | Enforce blank lines around top-level YAML block collection keys
|
|
179
|
+
| Name | Description | 🔧 | 💭 |
|
|
180
|
+
| :-------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------- | :-- | :-- |
|
|
181
|
+
| [jsx-shorthand-boolean](src/rules/jsx-shorthand-boolean/documentation.md) | Disallow shorthand boolean JSX attributes | 🔧 | |
|
|
182
|
+
| [jsx-shorthand-fragment](src/rules/jsx-shorthand-fragment/documentation.md) | Enforce a consistent fragment form: the shorthand `<>...</>` or a named fragment | 🔧 | |
|
|
183
|
+
| [naming-convention](src/rules/naming-convention/documentation.md) | Enforce naming conventions for everything across a codebase | | 💭 |
|
|
184
|
+
| [no-unnecessary-use-callback](src/rules/no-unnecessary-use-callback/documentation.md) | Disallow unnecessary usage of 'useCallback' | | |
|
|
185
|
+
| [no-unnecessary-use-memo](src/rules/no-unnecessary-use-memo/documentation.md) | Disallow unnecessary usage of 'useMemo' | | |
|
|
186
|
+
| [prefer-destructuring-assignment](src/rules/prefer-destructuring-assignment/documentation.md) | Enforce destructuring assignment for component props | 🔧 | |
|
|
187
|
+
| [purity](src/rules/purity/documentation.md) | Disallow impure calls such as `math.random` or `os.clock` during render | | |
|
|
188
|
+
| [toml-sort-keys](src/rules/toml-sort-keys/documentation.md) | Enforce a configured sort order for TOML keys and tables | 🔧 | |
|
|
189
|
+
| [yaml-block-key-blank-lines](src/rules/yaml-block-key-blank-lines/documentation.md) | Enforce blank lines around top-level YAML block collection keys | 🔧 | |
|
|
190
190
|
|
|
191
191
|
<!-- end auto-generated rules list -->
|
|
192
192
|
|
package/dist/index.d.mts
CHANGED
|
@@ -9,7 +9,23 @@ interface PluginDocumentation {
|
|
|
9
9
|
}
|
|
10
10
|
//#endregion
|
|
11
11
|
//#region src/rules/jsx-shorthand-fragment/rule.d.ts
|
|
12
|
-
|
|
12
|
+
declare const MESSAGE_ID_NAMED = "useNamedFragment";
|
|
13
|
+
declare const MESSAGE_ID_SHORTHAND = "useShorthandFragment";
|
|
14
|
+
type MessageIds$3 = typeof MESSAGE_ID_NAMED | typeof MESSAGE_ID_SHORTHAND;
|
|
15
|
+
interface JsxShorthandFragmentOptions {
|
|
16
|
+
/**
|
|
17
|
+
* The identifier used for the named fragment element in `"element"` mode
|
|
18
|
+
* (e.g. `"Fragment"` or `"React.Fragment"`). Defaults to `"Fragment"`.
|
|
19
|
+
*/
|
|
20
|
+
readonly fragmentName?: string;
|
|
21
|
+
/**
|
|
22
|
+
* Which form to enforce: `"syntax"` (shorthand `<>...</>`, the default) or
|
|
23
|
+
* `"element"` (a named fragment such as `<Fragment>...</Fragment>`).
|
|
24
|
+
*/
|
|
25
|
+
readonly mode?: Mode;
|
|
26
|
+
}
|
|
27
|
+
type Options$3 = [JsxShorthandFragmentOptions?];
|
|
28
|
+
type Mode = "element" | "syntax";
|
|
13
29
|
//#endregion
|
|
14
30
|
//#region src/rules/naming-convention/utils/enums.d.ts
|
|
15
31
|
declare const Selector: {
|
|
@@ -166,7 +182,7 @@ declare const plugin: {
|
|
|
166
182
|
"jsx-shorthand-boolean": TSESLint.RuleModule<"setAttributeValue", [], PluginDocumentation, TSESLint.RuleListener> & {
|
|
167
183
|
name: string;
|
|
168
184
|
};
|
|
169
|
-
"jsx-shorthand-fragment": TSESLint.RuleModule<
|
|
185
|
+
"jsx-shorthand-fragment": TSESLint.RuleModule<MessageIds$3, Options$3, PluginDocumentation, TSESLint.RuleListener> & {
|
|
170
186
|
name: string;
|
|
171
187
|
};
|
|
172
188
|
"naming-convention": TSESLint.RuleModule<MessageIds$2, Options$2, PluginDocumentation, TSESLint.RuleListener> & {
|
|
@@ -207,7 +223,7 @@ declare const _default: {
|
|
|
207
223
|
"jsx-shorthand-boolean": import("${configDir}").RuleModule<"setAttributeValue", [], PluginDocumentation, import("${configDir}").RuleListener> & {
|
|
208
224
|
name: string;
|
|
209
225
|
};
|
|
210
|
-
"jsx-shorthand-fragment": import("${configDir}").RuleModule<
|
|
226
|
+
"jsx-shorthand-fragment": import("${configDir}").RuleModule<MessageIds$3, Options$3, PluginDocumentation, import("${configDir}").RuleListener> & {
|
|
211
227
|
name: string;
|
|
212
228
|
};
|
|
213
229
|
"naming-convention": import("${configDir}").RuleModule<MessageIds$2, Options$2, PluginDocumentation, import("${configDir}").RuleListener> & {
|
|
@@ -245,7 +261,7 @@ declare const _default: {
|
|
|
245
261
|
"jsx-shorthand-boolean": import("${configDir}").RuleModule<"setAttributeValue", [], PluginDocumentation, import("${configDir}").RuleListener> & {
|
|
246
262
|
name: string;
|
|
247
263
|
};
|
|
248
|
-
"jsx-shorthand-fragment": import("${configDir}").RuleModule<
|
|
264
|
+
"jsx-shorthand-fragment": import("${configDir}").RuleModule<MessageIds$3, Options$3, PluginDocumentation, import("${configDir}").RuleListener> & {
|
|
249
265
|
name: string;
|
|
250
266
|
};
|
|
251
267
|
"naming-convention": import("${configDir}").RuleModule<MessageIds$2, Options$2, PluginDocumentation, import("${configDir}").RuleListener> & {
|
package/dist/index.mjs
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { RuleCreator, getParserServices } from "@typescript-eslint/utils/eslint-utils";
|
|
2
|
+
import { ASTUtils, AST_NODE_TYPES, ESLintUtils, TSESLint } from "@typescript-eslint/utils";
|
|
2
3
|
import { DefinitionType, ImplicitLibVariable, PatternVisitor, ScopeType, Visitor } from "@typescript-eslint/scope-manager";
|
|
3
4
|
import { requiresQuoting } from "@typescript-eslint/type-utils";
|
|
4
|
-
import { ASTUtils, AST_NODE_TYPES, ESLintUtils, TSESLint } from "@typescript-eslint/utils";
|
|
5
5
|
import assert from "node:assert";
|
|
6
6
|
import * as core from "@eslint-react/core";
|
|
7
7
|
import { findVariable } from "@typescript-eslint/utils/ast-utils";
|
|
8
8
|
import { getStaticTOMLValue } from "toml-eslint-parser";
|
|
9
9
|
//#region package.json
|
|
10
10
|
var name = "eslint-plugin-flawless";
|
|
11
|
-
var version = "0.1.
|
|
11
|
+
var version = "0.1.7";
|
|
12
12
|
var repository = {
|
|
13
13
|
"url": "git+https://github.com/christopher-buss/eslint-plugin-flawless.git",
|
|
14
14
|
"type": "git"
|
|
@@ -36,8 +36,8 @@ function createEslintRule(rule) {
|
|
|
36
36
|
//#endregion
|
|
37
37
|
//#region src/rules/jsx-shorthand-boolean/rule.ts
|
|
38
38
|
const RULE_NAME$8 = "jsx-shorthand-boolean";
|
|
39
|
-
const MESSAGE_ID$
|
|
40
|
-
const messages$8 = { [MESSAGE_ID$
|
|
39
|
+
const MESSAGE_ID$3 = "setAttributeValue";
|
|
40
|
+
const messages$8 = { [MESSAGE_ID$3]: "Set an explicit value for boolean attribute '{{name}}'." };
|
|
41
41
|
function create$8(context) {
|
|
42
42
|
const { sourceCode } = context;
|
|
43
43
|
return { JSXAttribute(node) {
|
|
@@ -45,7 +45,7 @@ function create$8(context) {
|
|
|
45
45
|
context.report({
|
|
46
46
|
data: { name: sourceCode.getText(node.name) },
|
|
47
47
|
fix: (fixer) => fixer.insertTextAfter(node.name, "={true}"),
|
|
48
|
-
messageId: MESSAGE_ID$
|
|
48
|
+
messageId: MESSAGE_ID$3,
|
|
49
49
|
node
|
|
50
50
|
});
|
|
51
51
|
} };
|
|
@@ -70,23 +70,79 @@ const jsxShorthandBoolean = createEslintRule({
|
|
|
70
70
|
//#endregion
|
|
71
71
|
//#region src/rules/jsx-shorthand-fragment/rule.ts
|
|
72
72
|
const RULE_NAME$7 = "jsx-shorthand-fragment";
|
|
73
|
-
const
|
|
73
|
+
const MESSAGE_ID_NAMED = "useNamedFragment";
|
|
74
|
+
const MESSAGE_ID_SHORTHAND = "useShorthandFragment";
|
|
75
|
+
const DEFAULT_MODE = "syntax";
|
|
74
76
|
const DEFAULT_FRAGMENT_NAME = "Fragment";
|
|
75
|
-
const messages$7 = {
|
|
77
|
+
const messages$7 = {
|
|
78
|
+
[MESSAGE_ID_NAMED]: "Use the '{{name}}' component instead of fragment shorthand syntax.",
|
|
79
|
+
[MESSAGE_ID_SHORTHAND]: "Use the fragment shorthand syntax '<>...</>' instead of the '{{name}}' component."
|
|
80
|
+
};
|
|
76
81
|
const schema$2 = [{
|
|
77
|
-
|
|
78
|
-
|
|
82
|
+
additionalProperties: false,
|
|
83
|
+
properties: {
|
|
84
|
+
fragmentName: {
|
|
85
|
+
description: "The identifier to use for the named fragment element in \"element\" mode.",
|
|
86
|
+
type: "string"
|
|
87
|
+
},
|
|
88
|
+
mode: {
|
|
89
|
+
description: "Which form to enforce: \"syntax\" (shorthand `<>...</>`, default) or \"element\" (a named fragment).",
|
|
90
|
+
enum: ["element", "syntax"],
|
|
91
|
+
type: "string"
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
type: "object"
|
|
79
95
|
}];
|
|
96
|
+
/**
|
|
97
|
+
* Flattens a JSX element name into a dotted string, e.g. `Fragment` or
|
|
98
|
+
* `React.Fragment`. Returns `null` for namespaced names (`<a:b>`) which cannot
|
|
99
|
+
* be a fragment.
|
|
100
|
+
*
|
|
101
|
+
* @param node - The JSX element name node.
|
|
102
|
+
* @returns The dotted name, or `null` when it is not a plain identifier chain.
|
|
103
|
+
*/
|
|
104
|
+
function jsxNameToString(node) {
|
|
105
|
+
if (node.type === AST_NODE_TYPES.JSXIdentifier) return node.name;
|
|
106
|
+
if (node.type === AST_NODE_TYPES.JSXMemberExpression) {
|
|
107
|
+
const object = jsxNameToString(node.object);
|
|
108
|
+
if (object === null) return null;
|
|
109
|
+
return `${object}.${node.property.name}`;
|
|
110
|
+
}
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
80
113
|
function create$7(context) {
|
|
81
|
-
const
|
|
82
|
-
|
|
114
|
+
const options = context.options[0] ?? {};
|
|
115
|
+
const mode = options.mode ?? DEFAULT_MODE;
|
|
116
|
+
const fragmentName = options.fragmentName ?? DEFAULT_FRAGMENT_NAME;
|
|
117
|
+
if (mode === "element") return { JSXFragment(node) {
|
|
83
118
|
const { closingFragment, openingFragment } = node;
|
|
119
|
+
context.report({
|
|
120
|
+
data: { name: fragmentName },
|
|
121
|
+
fix: (fixer) => {
|
|
122
|
+
return [fixer.replaceText(openingFragment, `<${fragmentName}>`), fixer.replaceText(closingFragment, `</${fragmentName}>`)];
|
|
123
|
+
},
|
|
124
|
+
messageId: MESSAGE_ID_NAMED,
|
|
125
|
+
node
|
|
126
|
+
});
|
|
127
|
+
} };
|
|
128
|
+
const namedFragments = /* @__PURE__ */ new Set([
|
|
129
|
+
"Fragment",
|
|
130
|
+
fragmentName,
|
|
131
|
+
"React.Fragment"
|
|
132
|
+
]);
|
|
133
|
+
return { JSXElement(node) {
|
|
134
|
+
const { openingElement } = node;
|
|
135
|
+
const name = jsxNameToString(openingElement.name);
|
|
136
|
+
if (name === null || !namedFragments.has(name)) return;
|
|
137
|
+
if (openingElement.attributes.length > 0) return;
|
|
84
138
|
context.report({
|
|
85
139
|
data: { name },
|
|
86
140
|
fix: (fixer) => {
|
|
87
|
-
|
|
141
|
+
const { closingElement } = node;
|
|
142
|
+
if (closingElement === null) return fixer.replaceText(node, "<></>");
|
|
143
|
+
return [fixer.replaceText(openingElement, "<>"), fixer.replaceText(closingElement, "</>")];
|
|
88
144
|
},
|
|
89
|
-
messageId:
|
|
145
|
+
messageId: MESSAGE_ID_SHORTHAND,
|
|
90
146
|
node
|
|
91
147
|
});
|
|
92
148
|
} };
|
|
@@ -94,11 +150,17 @@ function create$7(context) {
|
|
|
94
150
|
const jsxShorthandFragment = createEslintRule({
|
|
95
151
|
name: RULE_NAME$7,
|
|
96
152
|
create: create$7,
|
|
97
|
-
defaultOptions: [
|
|
153
|
+
defaultOptions: [{
|
|
154
|
+
fragmentName: DEFAULT_FRAGMENT_NAME,
|
|
155
|
+
mode: DEFAULT_MODE
|
|
156
|
+
}],
|
|
98
157
|
meta: {
|
|
99
|
-
defaultOptions: [
|
|
158
|
+
defaultOptions: [{
|
|
159
|
+
fragmentName: DEFAULT_FRAGMENT_NAME,
|
|
160
|
+
mode: DEFAULT_MODE
|
|
161
|
+
}],
|
|
100
162
|
docs: {
|
|
101
|
-
description: "
|
|
163
|
+
description: "Enforce a consistent fragment form: the shorthand `<>...</>` or a named fragment",
|
|
102
164
|
recommended: false,
|
|
103
165
|
requiresTypeChecking: false
|
|
104
166
|
},
|