@trackunit/eslint-plugin-trackunit 0.0.2
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/CHANGELOG.md +9 -0
- package/README.md +117 -0
- package/package.json +31 -0
- package/src/index.d.ts +8 -0
- package/src/index.js +20 -0
- package/src/index.js.map +1 -0
- package/src/lib/config/fragments/ignores.d.ts +2 -0
- package/src/lib/config/fragments/ignores.js +18 -0
- package/src/lib/config/fragments/ignores.js.map +1 -0
- package/src/lib/config/fragments/import-rules.d.ts +3 -0
- package/src/lib/config/fragments/import-rules.js +58 -0
- package/src/lib/config/fragments/import-rules.js.map +1 -0
- package/src/lib/config/fragments/jest-overrides.d.ts +2 -0
- package/src/lib/config/fragments/jest-overrides.js +30 -0
- package/src/lib/config/fragments/jest-overrides.js.map +1 -0
- package/src/lib/config/fragments/jsdoc-rules.d.ts +3 -0
- package/src/lib/config/fragments/jsdoc-rules.js +71 -0
- package/src/lib/config/fragments/jsdoc-rules.js.map +1 -0
- package/src/lib/config/fragments/module-boundaries.d.ts +2 -0
- package/src/lib/config/fragments/module-boundaries.js +92 -0
- package/src/lib/config/fragments/module-boundaries.js.map +1 -0
- package/src/lib/config/fragments/react-rules.d.ts +5 -0
- package/src/lib/config/fragments/react-rules.js +137 -0
- package/src/lib/config/fragments/react-rules.js.map +1 -0
- package/src/lib/config/fragments/restricted-imports.d.ts +2 -0
- package/src/lib/config/fragments/restricted-imports.js +58 -0
- package/src/lib/config/fragments/restricted-imports.js.map +1 -0
- package/src/lib/config/fragments/testing-library.d.ts +2 -0
- package/src/lib/config/fragments/testing-library.js +7 -0
- package/src/lib/config/fragments/testing-library.js.map +1 -0
- package/src/lib/config/fragments/typescript-rules.d.ts +2 -0
- package/src/lib/config/fragments/typescript-rules.js +97 -0
- package/src/lib/config/fragments/typescript-rules.js.map +1 -0
- package/src/lib/config/index.d.ts +863 -0
- package/src/lib/config/index.js +10 -0
- package/src/lib/config/index.js.map +1 -0
- package/src/lib/config/plugins.d.ts +90 -0
- package/src/lib/config/plugins.js +44 -0
- package/src/lib/config/plugins.js.map +1 -0
- package/src/lib/config/presets/base.d.ts +265 -0
- package/src/lib/config/presets/base.js +145 -0
- package/src/lib/config/presets/base.js.map +1 -0
- package/src/lib/config/presets/e2e.d.ts +10 -0
- package/src/lib/config/presets/e2e.js +19 -0
- package/src/lib/config/presets/e2e.js.map +1 -0
- package/src/lib/config/presets/public-api.d.ts +147 -0
- package/src/lib/config/presets/public-api.js +62 -0
- package/src/lib/config/presets/public-api.js.map +1 -0
- package/src/lib/config/presets/react.d.ts +598 -0
- package/src/lib/config/presets/react.js +97 -0
- package/src/lib/config/presets/react.js.map +1 -0
- package/src/lib/config/presets/server.d.ts +36 -0
- package/src/lib/config/presets/server.js +37 -0
- package/src/lib/config/presets/server.js.map +1 -0
- package/src/lib/config/utils.d.ts +6 -0
- package/src/lib/config/utils.js +28 -0
- package/src/lib/config/utils.js.map +1 -0
- package/src/lib/config-helpers/create-skip-when.d.ts +35 -0
- package/src/lib/config-helpers/create-skip-when.js +54 -0
- package/src/lib/config-helpers/create-skip-when.js.map +1 -0
- package/src/lib/rules/cva-merge-base-classes-as-array/cva-merge-base-classes-as-array.d.ts +16 -0
- package/src/lib/rules/cva-merge-base-classes-as-array/cva-merge-base-classes-as-array.js +83 -0
- package/src/lib/rules/cva-merge-base-classes-as-array/cva-merge-base-classes-as-array.js.map +1 -0
- package/src/lib/rules/design-guideline-button-icon-size-match/design-guideline-button-icon-size-match.d.ts +4 -0
- package/src/lib/rules/design-guideline-button-icon-size-match/design-guideline-button-icon-size-match.js +297 -0
- package/src/lib/rules/design-guideline-button-icon-size-match/design-guideline-button-icon-size-match.js.map +1 -0
- package/src/lib/rules/no-internal-barrel-files/examples.d.ts +80 -0
- package/src/lib/rules/no-internal-barrel-files/examples.js +84 -0
- package/src/lib/rules/no-internal-barrel-files/examples.js.map +1 -0
- package/src/lib/rules/no-internal-barrel-files/no-internal-barrel-files.d.ts +29 -0
- package/src/lib/rules/no-internal-barrel-files/no-internal-barrel-files.js +178 -0
- package/src/lib/rules/no-internal-barrel-files/no-internal-barrel-files.js.map +1 -0
- package/src/lib/rules/no-internal-graphql-when-tagged-with-gql-public/no-internal-graphql-when-tagged-with-gql-public.d.ts +5 -0
- package/src/lib/rules/no-internal-graphql-when-tagged-with-gql-public/no-internal-graphql-when-tagged-with-gql-public.js +67 -0
- package/src/lib/rules/no-internal-graphql-when-tagged-with-gql-public/no-internal-graphql-when-tagged-with-gql-public.js.map +1 -0
- package/src/lib/rules/no-jest-mock-trackunit-react-core-hooks/no-jest-mock-trackunit-react-core-hooks.d.ts +2 -0
- package/src/lib/rules/no-jest-mock-trackunit-react-core-hooks/no-jest-mock-trackunit-react-core-hooks.js +34 -0
- package/src/lib/rules/no-jest-mock-trackunit-react-core-hooks/no-jest-mock-trackunit-react-core-hooks.js.map +1 -0
- package/src/lib/rules/no-template-strings-in-classname-prop/no-template-strings-in-classname-prop.d.ts +16 -0
- package/src/lib/rules/no-template-strings-in-classname-prop/no-template-strings-in-classname-prop.js +55 -0
- package/src/lib/rules/no-template-strings-in-classname-prop/no-template-strings-in-classname-prop.js.map +1 -0
- package/src/lib/rules/no-typescript-assertion/examples.d.ts +1 -0
- package/src/lib/rules/no-typescript-assertion/examples.js +45 -0
- package/src/lib/rules/no-typescript-assertion/examples.js.map +1 -0
- package/src/lib/rules/no-typescript-assertion/no-typescript-assertion.d.ts +20 -0
- package/src/lib/rules/no-typescript-assertion/no-typescript-assertion.js +83 -0
- package/src/lib/rules/no-typescript-assertion/no-typescript-assertion.js.map +1 -0
- package/src/lib/rules/prefer-destructured-imports/prefer-destructured-imports.d.ts +73 -0
- package/src/lib/rules/prefer-destructured-imports/prefer-destructured-imports.js +333 -0
- package/src/lib/rules/prefer-destructured-imports/prefer-destructured-imports.js.map +1 -0
- package/src/lib/rules/prefer-event-specific-callback-naming/name-suggestion-strategies.d.ts +56 -0
- package/src/lib/rules/prefer-event-specific-callback-naming/name-suggestion-strategies.js +225 -0
- package/src/lib/rules/prefer-event-specific-callback-naming/name-suggestion-strategies.js.map +1 -0
- package/src/lib/rules/prefer-event-specific-callback-naming/prefer-event-specific-callback-naming.d.ts +49 -0
- package/src/lib/rules/prefer-event-specific-callback-naming/prefer-event-specific-callback-naming.js +75 -0
- package/src/lib/rules/prefer-event-specific-callback-naming/prefer-event-specific-callback-naming.js.map +1 -0
- package/src/lib/rules/prefer-event-specific-callback-naming/strategies/string-based.d.ts +32 -0
- package/src/lib/rules/prefer-event-specific-callback-naming/strategies/string-based.js +143 -0
- package/src/lib/rules/prefer-event-specific-callback-naming/strategies/string-based.js.map +1 -0
- package/src/lib/rules/prefer-event-specific-callback-naming/strategies/type-based.d.ts +27 -0
- package/src/lib/rules/prefer-event-specific-callback-naming/strategies/type-based.js +196 -0
- package/src/lib/rules/prefer-event-specific-callback-naming/strategies/type-based.js.map +1 -0
- package/src/lib/rules/prefer-event-specific-callback-naming/utils.d.ts +76 -0
- package/src/lib/rules/prefer-event-specific-callback-naming/utils.js +245 -0
- package/src/lib/rules/prefer-event-specific-callback-naming/utils.js.map +1 -0
- package/src/lib/rules/prefer-field-components/prefer-field-components.d.ts +4 -0
- package/src/lib/rules/prefer-field-components/prefer-field-components.js +289 -0
- package/src/lib/rules/prefer-field-components/prefer-field-components.js.map +1 -0
- package/src/lib/rules/prefer-mouse-event-handler-in-react-props/prefer-mouse-event-handler-in-react-props.d.ts +26 -0
- package/src/lib/rules/prefer-mouse-event-handler-in-react-props/prefer-mouse-event-handler-in-react-props.js +402 -0
- package/src/lib/rules/prefer-mouse-event-handler-in-react-props/prefer-mouse-event-handler-in-react-props.js.map +1 -0
- package/src/lib/rules/require-classname-alternatives/require-classname-alternatives.d.ts +13 -0
- package/src/lib/rules/require-classname-alternatives/require-classname-alternatives.js +271 -0
- package/src/lib/rules/require-classname-alternatives/require-classname-alternatives.js.map +1 -0
- package/src/lib/rules/require-list-item-virtualization-props/require-list-item-virtualization-props.d.ts +15 -0
- package/src/lib/rules/require-list-item-virtualization-props/require-list-item-virtualization-props.js +245 -0
- package/src/lib/rules/require-list-item-virtualization-props/require-list-item-virtualization-props.js.map +1 -0
- package/src/lib/rules/require-optional-prop-initialization/require-optional-prop-initialization.d.ts +17 -0
- package/src/lib/rules/require-optional-prop-initialization/require-optional-prop-initialization.js +133 -0
- package/src/lib/rules/require-optional-prop-initialization/require-optional-prop-initialization.js.map +1 -0
- package/src/lib/rules/require-optional-prop-initialization/suggestion-utils.d.ts +12 -0
- package/src/lib/rules/require-optional-prop-initialization/suggestion-utils.js +128 -0
- package/src/lib/rules/require-optional-prop-initialization/suggestion-utils.js.map +1 -0
- package/src/lib/rules-map.d.ts +66 -0
- package/src/lib/rules-map.js +34 -0
- package/src/lib/rules-map.js.map +1 -0
- package/src/lib/utils/ast-utils.d.ts +85 -0
- package/src/lib/utils/ast-utils.js +530 -0
- package/src/lib/utils/ast-utils.js.map +1 -0
- package/src/lib/utils/classname-utils.d.ts +150 -0
- package/src/lib/utils/classname-utils.js +492 -0
- package/src/lib/utils/classname-utils.js.map +1 -0
- package/src/lib/utils/file-utils.d.ts +14 -0
- package/src/lib/utils/file-utils.js +106 -0
- package/src/lib/utils/file-utils.js.map +1 -0
- package/src/lib/utils/import-utils.d.ts +85 -0
- package/src/lib/utils/import-utils.js +193 -0
- package/src/lib/utils/import-utils.js.map +1 -0
- package/src/lib/utils/nx-utils.d.ts +59 -0
- package/src/lib/utils/nx-utils.js +103 -0
- package/src/lib/utils/nx-utils.js.map +1 -0
- package/src/lib/utils/package-utils.d.ts +38 -0
- package/src/lib/utils/package-utils.js +74 -0
- package/src/lib/utils/package-utils.js.map +1 -0
- package/src/lib/utils/typescript-utils.d.ts +29 -0
- package/src/lib/utils/typescript-utils.js +213 -0
- package/src/lib/utils/typescript-utils.js.map +1 -0
package/src/lib/rules/require-optional-prop-initialization/require-optional-prop-initialization.js
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.requireOptionalPropInitialization = void 0;
|
|
4
|
+
const utils_1 = require("@typescript-eslint/utils");
|
|
5
|
+
const ast_utils_1 = require("../../utils/ast-utils");
|
|
6
|
+
const typescript_utils_1 = require("../../utils/typescript-utils");
|
|
7
|
+
const suggestion_utils_1 = require("./suggestion-utils");
|
|
8
|
+
const createRule = utils_1.ESLintUtils.RuleCreator(name => `https://github.com/trackunit/manager/blob/main/libs/eslint/plugin-trackunit/src/lib/rules/${name}.ts`);
|
|
9
|
+
exports.requireOptionalPropInitialization = createRule({
|
|
10
|
+
name: "require-optional-prop-initialization",
|
|
11
|
+
meta: {
|
|
12
|
+
type: "suggestion",
|
|
13
|
+
docs: {
|
|
14
|
+
description: "Require optional component props to be initialized inside the component",
|
|
15
|
+
},
|
|
16
|
+
hasSuggestions: true,
|
|
17
|
+
schema: [
|
|
18
|
+
{
|
|
19
|
+
type: "object",
|
|
20
|
+
properties: {
|
|
21
|
+
allowNullableObject: { type: "boolean" },
|
|
22
|
+
allowNullableBoolean: { type: "boolean" },
|
|
23
|
+
allowNullableString: { type: "boolean" },
|
|
24
|
+
allowNullableNumber: { type: "boolean" },
|
|
25
|
+
allowNullableEnum: { type: "boolean" },
|
|
26
|
+
allowNullableStringLiteralUnion: { type: "boolean" },
|
|
27
|
+
onlyRequireUsedProps: { type: "boolean" },
|
|
28
|
+
},
|
|
29
|
+
additionalProperties: false,
|
|
30
|
+
},
|
|
31
|
+
],
|
|
32
|
+
messages: {
|
|
33
|
+
requireInitialization: "Optional prop '{{propName}}' should be initialized",
|
|
34
|
+
initializeProp: "{{description}}",
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
defaultOptions: [
|
|
38
|
+
{
|
|
39
|
+
allowNullableObject: true,
|
|
40
|
+
allowNullableBoolean: false,
|
|
41
|
+
allowNullableString: true,
|
|
42
|
+
allowNullableNumber: true,
|
|
43
|
+
allowNullableEnum: false,
|
|
44
|
+
allowNullableStringLiteralUnion: false,
|
|
45
|
+
onlyRequireUsedProps: true,
|
|
46
|
+
},
|
|
47
|
+
],
|
|
48
|
+
create(context, options) {
|
|
49
|
+
const config = options[0];
|
|
50
|
+
// Helper function to check component props
|
|
51
|
+
const checkComponentProps = (functionNode, propsParam) => {
|
|
52
|
+
if (!propsParam) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
let typeAnnotation;
|
|
56
|
+
// Handle both regular parameters (props: Props) and destructured parameters ({prop1, prop2}: Props)
|
|
57
|
+
if (propsParam.type === utils_1.AST_NODE_TYPES.Identifier || propsParam.type === utils_1.AST_NODE_TYPES.ObjectPattern) {
|
|
58
|
+
typeAnnotation = propsParam.typeAnnotation?.typeAnnotation;
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
const optionalProps = (0, typescript_utils_1.getOptionalPropsFromType)(context, typeAnnotation);
|
|
64
|
+
if (optionalProps.length === 0) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
const functionBody = functionNode.body.type === utils_1.AST_NODE_TYPES.BlockStatement ? functionNode.body.body : [];
|
|
68
|
+
optionalProps.forEach(prop => {
|
|
69
|
+
// Check if this prop type is allowed to be nullable based on configuration
|
|
70
|
+
const isAllowed = (prop.type === "object" && config.allowNullableObject === true) ||
|
|
71
|
+
(prop.type === "boolean" && config.allowNullableBoolean === true) ||
|
|
72
|
+
(prop.type === "string" && config.allowNullableString === true) ||
|
|
73
|
+
(prop.type === "number" && config.allowNullableNumber === true) ||
|
|
74
|
+
(prop.type === "enum" && config.allowNullableEnum === true) ||
|
|
75
|
+
(prop.type === "stringLiteral" && config.allowNullableStringLiteralUnion === true) ||
|
|
76
|
+
prop.type === "unknown"; // Always allow unknown types
|
|
77
|
+
if (isAllowed) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
// If onlyRequireUsedProps is enabled, skip unused props
|
|
81
|
+
if (config.onlyRequireUsedProps === true && !(0, ast_utils_1.isParameterUsedInFunction)(context, functionNode, prop.name)) {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
// Skip props that are not explicitly destructured (i.e., captured in rest parameters like ...restOptions)
|
|
85
|
+
// and are not used in the component body - these are just being passed through
|
|
86
|
+
if (!(0, ast_utils_1.isParameterExplicitlyDestructured)(propsParam, prop.name) &&
|
|
87
|
+
!(0, ast_utils_1.isParameterUsedInFunction)(context, functionNode, prop.name)) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
// Skip props that are only used for pass-through to child components (e.g., <Tag color={tagColor} />)
|
|
91
|
+
if ((0, ast_utils_1.isParameterOnlyUsedInJSX)(context, functionNode, prop.name) === true) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
// Check if the prop is initialized in the function body or parameter defaults
|
|
95
|
+
if (!(0, ast_utils_1.isParameterInitialized)(functionBody, prop.name, propsParam)) {
|
|
96
|
+
const isDestructuredParam = propsParam.type === utils_1.AST_NODE_TYPES.ObjectPattern;
|
|
97
|
+
const hasBodyInits = (0, ast_utils_1.hasExistingBodyInitializations)(functionBody);
|
|
98
|
+
const propsParamName = propsParam.type === utils_1.AST_NODE_TYPES.Identifier ? propsParam.name : "props";
|
|
99
|
+
const suggestions = (0, suggestion_utils_1.generateSuggestions)(prop, propsParamName, functionNode, isDestructuredParam, hasBodyInits, propsParam, context);
|
|
100
|
+
// Find the specific property node for more precise reporting
|
|
101
|
+
let reportNode = propsParam;
|
|
102
|
+
if (propsParam.type === utils_1.AST_NODE_TYPES.ObjectPattern) {
|
|
103
|
+
const propProperty = propsParam.properties.find(p => p.type === utils_1.AST_NODE_TYPES.Property &&
|
|
104
|
+
p.key.type === utils_1.AST_NODE_TYPES.Identifier &&
|
|
105
|
+
p.key.name === prop.name);
|
|
106
|
+
if (propProperty && propProperty.type === utils_1.AST_NODE_TYPES.Property) {
|
|
107
|
+
reportNode = propProperty;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
context.report({
|
|
111
|
+
node: reportNode,
|
|
112
|
+
messageId: "requireInitialization",
|
|
113
|
+
data: { propName: prop.name },
|
|
114
|
+
suggest: suggestions,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
};
|
|
119
|
+
return {
|
|
120
|
+
FunctionDeclaration(node) {
|
|
121
|
+
if ((0, ast_utils_1.isReactComponent)(node)) {
|
|
122
|
+
checkComponentProps(node, node.params[0]);
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
ArrowFunctionExpression(node) {
|
|
126
|
+
if ((0, ast_utils_1.isReactComponent)(node)) {
|
|
127
|
+
checkComponentProps(node, node.params[0]);
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
};
|
|
131
|
+
},
|
|
132
|
+
});
|
|
133
|
+
//# sourceMappingURL=require-optional-prop-initialization.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"require-optional-prop-initialization.js","sourceRoot":"","sources":["../../../../../../../../libs/eslint/plugin-trackunit/src/lib/rules/require-optional-prop-initialization/require-optional-prop-initialization.ts"],"names":[],"mappings":"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","sourcesContent":["import { AST_NODE_TYPES, ESLintUtils, TSESTree } from \"@typescript-eslint/utils\";\nimport {\n hasExistingBodyInitializations,\n isParameterExplicitlyDestructured,\n isParameterInitialized,\n isParameterOnlyUsedInJSX,\n isParameterUsedInFunction,\n isReactComponent,\n} from \"../../utils/ast-utils\";\nimport { getOptionalPropsFromType } from \"../../utils/typescript-utils\";\nimport { generateSuggestions, type MessageIds } from \"./suggestion-utils\";\n\nconst createRule = ESLintUtils.RuleCreator(\n name => `https://github.com/trackunit/manager/blob/main/libs/eslint/plugin-trackunit/src/lib/rules/${name}.ts`\n);\n\ntype Options = [\n {\n allowNullableObject?: boolean;\n allowNullableBoolean?: boolean;\n allowNullableString?: boolean;\n allowNullableNumber?: boolean;\n allowNullableEnum?: boolean;\n allowNullableStringLiteralUnion?: boolean;\n onlyRequireUsedProps?: boolean;\n },\n];\n\nexport const requireOptionalPropInitialization = createRule<Options, MessageIds>({\n name: \"require-optional-prop-initialization\",\n meta: {\n type: \"suggestion\",\n docs: {\n description: \"Require optional component props to be initialized inside the component\",\n },\n hasSuggestions: true,\n schema: [\n {\n type: \"object\",\n properties: {\n allowNullableObject: { type: \"boolean\" },\n allowNullableBoolean: { type: \"boolean\" },\n allowNullableString: { type: \"boolean\" },\n allowNullableNumber: { type: \"boolean\" },\n allowNullableEnum: { type: \"boolean\" },\n allowNullableStringLiteralUnion: { type: \"boolean\" },\n onlyRequireUsedProps: { type: \"boolean\" },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n requireInitialization: \"Optional prop '{{propName}}' should be initialized\",\n initializeProp: \"{{description}}\",\n },\n },\n defaultOptions: [\n {\n allowNullableObject: true,\n allowNullableBoolean: false,\n allowNullableString: true,\n allowNullableNumber: true,\n allowNullableEnum: false,\n allowNullableStringLiteralUnion: false,\n onlyRequireUsedProps: true,\n },\n ],\n create(context, options) {\n const config = options[0];\n\n // Helper function to check component props\n const checkComponentProps = (\n functionNode: TSESTree.FunctionDeclaration | TSESTree.ArrowFunctionExpression,\n propsParam: TSESTree.Parameter | undefined\n ) => {\n if (!propsParam) {\n return;\n }\n\n let typeAnnotation: TSESTree.TypeNode | undefined;\n\n // Handle both regular parameters (props: Props) and destructured parameters ({prop1, prop2}: Props)\n if (propsParam.type === AST_NODE_TYPES.Identifier || propsParam.type === AST_NODE_TYPES.ObjectPattern) {\n typeAnnotation = propsParam.typeAnnotation?.typeAnnotation;\n } else {\n return;\n }\n\n const optionalProps = getOptionalPropsFromType(context, typeAnnotation);\n\n if (optionalProps.length === 0) {\n return;\n }\n\n const functionBody = functionNode.body.type === AST_NODE_TYPES.BlockStatement ? functionNode.body.body : [];\n\n optionalProps.forEach(prop => {\n // Check if this prop type is allowed to be nullable based on configuration\n const isAllowed =\n (prop.type === \"object\" && config.allowNullableObject === true) ||\n (prop.type === \"boolean\" && config.allowNullableBoolean === true) ||\n (prop.type === \"string\" && config.allowNullableString === true) ||\n (prop.type === \"number\" && config.allowNullableNumber === true) ||\n (prop.type === \"enum\" && config.allowNullableEnum === true) ||\n (prop.type === \"stringLiteral\" && config.allowNullableStringLiteralUnion === true) ||\n prop.type === \"unknown\"; // Always allow unknown types\n\n if (isAllowed) {\n return;\n }\n\n // If onlyRequireUsedProps is enabled, skip unused props\n if (config.onlyRequireUsedProps === true && !isParameterUsedInFunction(context, functionNode, prop.name)) {\n return;\n }\n\n // Skip props that are not explicitly destructured (i.e., captured in rest parameters like ...restOptions)\n // and are not used in the component body - these are just being passed through\n if (\n !isParameterExplicitlyDestructured(propsParam, prop.name) &&\n !isParameterUsedInFunction(context, functionNode, prop.name)\n ) {\n return;\n }\n\n // Skip props that are only used for pass-through to child components (e.g., <Tag color={tagColor} />)\n if (isParameterOnlyUsedInJSX(context, functionNode, prop.name) === true) {\n return;\n }\n\n // Check if the prop is initialized in the function body or parameter defaults\n if (!isParameterInitialized(functionBody, prop.name, propsParam)) {\n const isDestructuredParam = propsParam.type === AST_NODE_TYPES.ObjectPattern;\n const hasBodyInits = hasExistingBodyInitializations(functionBody);\n const propsParamName = propsParam.type === AST_NODE_TYPES.Identifier ? propsParam.name : \"props\";\n\n const suggestions = generateSuggestions(\n prop,\n propsParamName,\n functionNode,\n isDestructuredParam,\n hasBodyInits,\n propsParam,\n context\n );\n\n // Find the specific property node for more precise reporting\n let reportNode: TSESTree.Node = propsParam;\n if (propsParam.type === AST_NODE_TYPES.ObjectPattern) {\n const propProperty = propsParam.properties.find(\n p =>\n p.type === AST_NODE_TYPES.Property &&\n p.key.type === AST_NODE_TYPES.Identifier &&\n p.key.name === prop.name\n );\n if (propProperty && propProperty.type === AST_NODE_TYPES.Property) {\n reportNode = propProperty;\n }\n }\n\n context.report({\n node: reportNode,\n messageId: \"requireInitialization\",\n data: { propName: prop.name },\n suggest: suggestions,\n });\n }\n });\n };\n\n return {\n FunctionDeclaration(node: TSESTree.FunctionDeclaration) {\n if (isReactComponent(node)) {\n checkComponentProps(node, node.params[0]);\n }\n },\n\n ArrowFunctionExpression(node: TSESTree.ArrowFunctionExpression) {\n if (isReactComponent(node)) {\n checkComponentProps(node, node.params[0]);\n }\n },\n };\n },\n});\n"]}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { TSESLint, TSESTree } from "@typescript-eslint/utils";
|
|
2
|
+
import { OptionalProp } from "../../utils/typescript-utils";
|
|
3
|
+
export type MessageIds = "requireInitialization" | "initializeProp";
|
|
4
|
+
export type SuggestionResult = {
|
|
5
|
+
messageId: MessageIds;
|
|
6
|
+
data?: Record<string, unknown>;
|
|
7
|
+
fix: (fixer: TSESLint.RuleFixer) => TSESLint.RuleFix | Array<TSESLint.RuleFix> | null;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Helper function to generate suggestions for prop initialization
|
|
11
|
+
*/
|
|
12
|
+
export declare const generateSuggestions: (prop: OptionalProp, propsParamName: string, functionNode: TSESTree.FunctionDeclaration | TSESTree.ArrowFunctionExpression, isDestructuredParam: boolean, hasBodyInits: boolean, propsParam: TSESTree.Parameter, _context: TSESLint.RuleContext<string, ReadonlyArray<unknown>>) => Array<SuggestionResult>;
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateSuggestions = void 0;
|
|
4
|
+
const utils_1 = require("@typescript-eslint/utils");
|
|
5
|
+
const ast_utils_1 = require("../../utils/ast-utils");
|
|
6
|
+
/**
|
|
7
|
+
* Helper to find and replace a property in destructuring pattern
|
|
8
|
+
*/
|
|
9
|
+
const createParameterInitializationFix = (propName, value, propsParam) => {
|
|
10
|
+
return (fixer) => {
|
|
11
|
+
if (propsParam.type === utils_1.AST_NODE_TYPES.ObjectPattern) {
|
|
12
|
+
const property = propsParam.properties.find(p => p.type === utils_1.AST_NODE_TYPES.Property && p.key.type === utils_1.AST_NODE_TYPES.Identifier && p.key.name === propName);
|
|
13
|
+
if (property && property.type === utils_1.AST_NODE_TYPES.Property) {
|
|
14
|
+
return fixer.replaceText(property, `${propName} = ${value}`);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return null;
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Helper to create body initialization fix
|
|
22
|
+
*/
|
|
23
|
+
const createBodyInitializationFix = (propName, value, propsParamName, functionBodyStart) => {
|
|
24
|
+
return (fixer) => {
|
|
25
|
+
const destructuringFix = `\n const { ${propName} = ${value} } = ${propsParamName};`;
|
|
26
|
+
return fixer.insertTextAfterRange([functionBodyStart, functionBodyStart + 1], destructuringFix);
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Helper to create a suggestion for a specific value
|
|
31
|
+
*/
|
|
32
|
+
const createSuggestion = (propName, value, displayValue, shouldUseParameterInit, propsParam, propsParamName, functionBodyStart) => {
|
|
33
|
+
let locationSuffix = "";
|
|
34
|
+
let fixFunction;
|
|
35
|
+
if (shouldUseParameterInit) {
|
|
36
|
+
locationSuffix = " in parameter";
|
|
37
|
+
fixFunction = createParameterInitializationFix(propName, value, propsParam);
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
fixFunction = createBodyInitializationFix(propName, value, propsParamName, functionBodyStart);
|
|
41
|
+
}
|
|
42
|
+
return {
|
|
43
|
+
messageId: "initializeProp",
|
|
44
|
+
data: { description: `Initialize '${propName}' to → ${displayValue}${locationSuffix}` },
|
|
45
|
+
fix: fixFunction,
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* Helper to create suggestions for a set of values
|
|
50
|
+
*/
|
|
51
|
+
const createSuggestionsForValues = (propName, values, shouldUseParameterInit, propsParam, propsParamName, functionBodyStart) => {
|
|
52
|
+
return values.map(({ value, display }) => createSuggestion(propName, value, display, shouldUseParameterInit, propsParam, propsParamName, functionBodyStart));
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* Helper function to generate suggestions for prop initialization
|
|
56
|
+
*/
|
|
57
|
+
const generateSuggestions = (prop, propsParamName, functionNode, isDestructuredParam, hasBodyInits, propsParam, _context) => {
|
|
58
|
+
const suggestions = [];
|
|
59
|
+
if (functionNode.body.type !== utils_1.AST_NODE_TYPES.BlockStatement) {
|
|
60
|
+
return suggestions; // Can't suggest for arrow functions without block body
|
|
61
|
+
}
|
|
62
|
+
// Don't offer suggestions for props captured in rest parameters (e.g., ...rest)
|
|
63
|
+
// The developer should manually handle extracting these from the rest object
|
|
64
|
+
if (!(0, ast_utils_1.isParameterExplicitlyDestructured)(propsParam, prop.name)) {
|
|
65
|
+
return suggestions;
|
|
66
|
+
}
|
|
67
|
+
const functionBodyStart = functionNode.body.range[0];
|
|
68
|
+
const MAX_SUGGESTIONS = 5; // Don't overwhelm with too many suggestions
|
|
69
|
+
// Decide where to place the initialization:
|
|
70
|
+
// Since we know the prop is explicitly destructured (early return above handles rest params),
|
|
71
|
+
// we can choose between parameter initialization or body initialization
|
|
72
|
+
const isAlreadyInParameterDestructuring = isDestructuredParam &&
|
|
73
|
+
propsParam.type === utils_1.AST_NODE_TYPES.ObjectPattern &&
|
|
74
|
+
propsParam.properties.some(p => p.type === utils_1.AST_NODE_TYPES.Property && p.key.type === utils_1.AST_NODE_TYPES.Identifier && p.key.name === prop.name);
|
|
75
|
+
const shouldUseParameterInit = isAlreadyInParameterDestructuring || (isDestructuredParam && !hasBodyInits);
|
|
76
|
+
// Boolean suggestions: true, false, and undefined
|
|
77
|
+
if (prop.type === "boolean") {
|
|
78
|
+
const booleanValues = [
|
|
79
|
+
{ value: "true", display: "true" },
|
|
80
|
+
{ value: "false", display: "false" },
|
|
81
|
+
{ value: "undefined", display: "undefined" },
|
|
82
|
+
];
|
|
83
|
+
suggestions.push(...createSuggestionsForValues(prop.name, booleanValues, shouldUseParameterInit, propsParam, propsParamName, functionBodyStart));
|
|
84
|
+
}
|
|
85
|
+
// String literal suggestions: each individual literal (if not too many)
|
|
86
|
+
if (prop.type === "stringLiteral" && prop.stringLiterals.length <= MAX_SUGGESTIONS) {
|
|
87
|
+
const stringLiteralValues = [
|
|
88
|
+
...prop.stringLiterals.map(literal => ({ value: `"${literal}"`, display: `"${literal}"` })),
|
|
89
|
+
{ value: "undefined", display: "undefined" },
|
|
90
|
+
];
|
|
91
|
+
suggestions.push(...createSuggestionsForValues(prop.name, stringLiteralValues, shouldUseParameterInit, propsParam, propsParamName, functionBodyStart));
|
|
92
|
+
}
|
|
93
|
+
// Enum suggestions: each individual enum value (if not too many)
|
|
94
|
+
if (prop.type === "enum" && prop.enumValues.length <= MAX_SUGGESTIONS) {
|
|
95
|
+
const enumValues = [
|
|
96
|
+
...prop.enumValues.map(enumValue => {
|
|
97
|
+
const valueStr = typeof enumValue === "string" ? `"${enumValue}"` : String(enumValue);
|
|
98
|
+
return { value: valueStr, display: valueStr };
|
|
99
|
+
}),
|
|
100
|
+
{ value: "undefined", display: "undefined" },
|
|
101
|
+
];
|
|
102
|
+
suggestions.push(...createSuggestionsForValues(prop.name, enumValues, shouldUseParameterInit, propsParam, propsParamName, functionBodyStart));
|
|
103
|
+
}
|
|
104
|
+
// String type suggestions
|
|
105
|
+
if (prop.type === "string") {
|
|
106
|
+
const stringValues = [
|
|
107
|
+
{ value: '""', display: '""' },
|
|
108
|
+
{ value: "undefined", display: "undefined" },
|
|
109
|
+
];
|
|
110
|
+
suggestions.push(...createSuggestionsForValues(prop.name, stringValues, shouldUseParameterInit, propsParam, propsParamName, functionBodyStart));
|
|
111
|
+
}
|
|
112
|
+
// Number type suggestions
|
|
113
|
+
if (prop.type === "number") {
|
|
114
|
+
const numberValues = [
|
|
115
|
+
{ value: "0", display: "0" },
|
|
116
|
+
{ value: "undefined", display: "undefined" },
|
|
117
|
+
];
|
|
118
|
+
suggestions.push(...createSuggestionsForValues(prop.name, numberValues, shouldUseParameterInit, propsParam, propsParamName, functionBodyStart));
|
|
119
|
+
}
|
|
120
|
+
// Object/unknown type suggestions
|
|
121
|
+
if (prop.type === "object" || prop.type === "unknown") {
|
|
122
|
+
const typeDisplay = prop.type === "unknown" ? "any value" : prop.type;
|
|
123
|
+
suggestions.push(createSuggestion(prop.name, "undefined", `undefined (${typeDisplay})`, shouldUseParameterInit, propsParam, propsParamName, functionBodyStart));
|
|
124
|
+
}
|
|
125
|
+
return suggestions;
|
|
126
|
+
};
|
|
127
|
+
exports.generateSuggestions = generateSuggestions;
|
|
128
|
+
//# sourceMappingURL=suggestion-utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"suggestion-utils.js","sourceRoot":"","sources":["../../../../../../../../libs/eslint/plugin-trackunit/src/lib/rules/require-optional-prop-initialization/suggestion-utils.ts"],"names":[],"mappings":"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","sourcesContent":["import { AST_NODE_TYPES, TSESLint, TSESTree } from \"@typescript-eslint/utils\";\nimport { isParameterExplicitlyDestructured } from \"../../utils/ast-utils\";\nimport { OptionalProp } from \"../../utils/typescript-utils\";\n\nexport type MessageIds = \"requireInitialization\" | \"initializeProp\";\n\nexport type SuggestionResult = {\n messageId: MessageIds;\n data?: Record<string, unknown>;\n fix: (fixer: TSESLint.RuleFixer) => TSESLint.RuleFix | Array<TSESLint.RuleFix> | null;\n};\n\n/**\n * Helper to find and replace a property in destructuring pattern\n */\nconst createParameterInitializationFix = (propName: string, value: string, propsParam: TSESTree.Parameter) => {\n return (fixer: TSESLint.RuleFixer) => {\n if (propsParam.type === AST_NODE_TYPES.ObjectPattern) {\n const property = propsParam.properties.find(\n p => p.type === AST_NODE_TYPES.Property && p.key.type === AST_NODE_TYPES.Identifier && p.key.name === propName\n );\n if (property && property.type === AST_NODE_TYPES.Property) {\n return fixer.replaceText(property, `${propName} = ${value}`);\n }\n }\n return null;\n };\n};\n\n/**\n * Helper to create body initialization fix\n */\nconst createBodyInitializationFix = (\n propName: string,\n value: string,\n propsParamName: string,\n functionBodyStart: number\n) => {\n return (fixer: TSESLint.RuleFixer) => {\n const destructuringFix = `\\n const { ${propName} = ${value} } = ${propsParamName};`;\n return fixer.insertTextAfterRange([functionBodyStart, functionBodyStart + 1], destructuringFix);\n };\n};\n\n/**\n * Helper to create a suggestion for a specific value\n */\nconst createSuggestion = (\n propName: string,\n value: string,\n displayValue: string,\n shouldUseParameterInit: boolean,\n propsParam: TSESTree.Parameter,\n propsParamName: string,\n functionBodyStart: number\n): SuggestionResult => {\n let locationSuffix = \"\";\n let fixFunction: (fixer: TSESLint.RuleFixer) => TSESLint.RuleFix | Array<TSESLint.RuleFix> | null;\n\n if (shouldUseParameterInit) {\n locationSuffix = \" in parameter\";\n fixFunction = createParameterInitializationFix(propName, value, propsParam);\n } else {\n fixFunction = createBodyInitializationFix(propName, value, propsParamName, functionBodyStart);\n }\n\n return {\n messageId: \"initializeProp\",\n data: { description: `Initialize '${propName}' to → ${displayValue}${locationSuffix}` },\n fix: fixFunction,\n };\n};\n\n/**\n * Helper to create suggestions for a set of values\n */\nconst createSuggestionsForValues = (\n propName: string,\n values: Array<{ value: string; display: string }>,\n shouldUseParameterInit: boolean,\n propsParam: TSESTree.Parameter,\n propsParamName: string,\n functionBodyStart: number\n): Array<SuggestionResult> => {\n return values.map(({ value, display }) =>\n createSuggestion(propName, value, display, shouldUseParameterInit, propsParam, propsParamName, functionBodyStart)\n );\n};\n\n/**\n * Helper function to generate suggestions for prop initialization\n */\nexport const generateSuggestions = (\n prop: OptionalProp,\n propsParamName: string,\n functionNode: TSESTree.FunctionDeclaration | TSESTree.ArrowFunctionExpression,\n isDestructuredParam: boolean,\n hasBodyInits: boolean,\n propsParam: TSESTree.Parameter,\n _context: TSESLint.RuleContext<string, ReadonlyArray<unknown>>\n): Array<SuggestionResult> => {\n const suggestions: Array<SuggestionResult> = [];\n\n if (functionNode.body.type !== AST_NODE_TYPES.BlockStatement) {\n return suggestions; // Can't suggest for arrow functions without block body\n }\n\n // Don't offer suggestions for props captured in rest parameters (e.g., ...rest)\n // The developer should manually handle extracting these from the rest object\n if (!isParameterExplicitlyDestructured(propsParam, prop.name)) {\n return suggestions;\n }\n\n const functionBodyStart = functionNode.body.range[0];\n const MAX_SUGGESTIONS = 5; // Don't overwhelm with too many suggestions\n\n // Decide where to place the initialization:\n // Since we know the prop is explicitly destructured (early return above handles rest params),\n // we can choose between parameter initialization or body initialization\n const isAlreadyInParameterDestructuring =\n isDestructuredParam &&\n propsParam.type === AST_NODE_TYPES.ObjectPattern &&\n propsParam.properties.some(\n p => p.type === AST_NODE_TYPES.Property && p.key.type === AST_NODE_TYPES.Identifier && p.key.name === prop.name\n );\n\n const shouldUseParameterInit = isAlreadyInParameterDestructuring || (isDestructuredParam && !hasBodyInits);\n\n // Boolean suggestions: true, false, and undefined\n if (prop.type === \"boolean\") {\n const booleanValues = [\n { value: \"true\", display: \"true\" },\n { value: \"false\", display: \"false\" },\n { value: \"undefined\", display: \"undefined\" },\n ];\n suggestions.push(\n ...createSuggestionsForValues(\n prop.name,\n booleanValues,\n shouldUseParameterInit,\n propsParam,\n propsParamName,\n functionBodyStart\n )\n );\n }\n\n // String literal suggestions: each individual literal (if not too many)\n if (prop.type === \"stringLiteral\" && prop.stringLiterals.length <= MAX_SUGGESTIONS) {\n const stringLiteralValues = [\n ...prop.stringLiterals.map(literal => ({ value: `\"${literal}\"`, display: `\"${literal}\"` })),\n { value: \"undefined\", display: \"undefined\" },\n ];\n suggestions.push(\n ...createSuggestionsForValues(\n prop.name,\n stringLiteralValues,\n shouldUseParameterInit,\n propsParam,\n propsParamName,\n functionBodyStart\n )\n );\n }\n\n // Enum suggestions: each individual enum value (if not too many)\n if (prop.type === \"enum\" && prop.enumValues.length <= MAX_SUGGESTIONS) {\n const enumValues = [\n ...prop.enumValues.map(enumValue => {\n const valueStr = typeof enumValue === \"string\" ? `\"${enumValue}\"` : String(enumValue);\n return { value: valueStr, display: valueStr };\n }),\n { value: \"undefined\", display: \"undefined\" },\n ];\n suggestions.push(\n ...createSuggestionsForValues(\n prop.name,\n enumValues,\n shouldUseParameterInit,\n propsParam,\n propsParamName,\n functionBodyStart\n )\n );\n }\n\n // String type suggestions\n if (prop.type === \"string\") {\n const stringValues = [\n { value: '\"\"', display: '\"\"' },\n { value: \"undefined\", display: \"undefined\" },\n ];\n suggestions.push(\n ...createSuggestionsForValues(\n prop.name,\n stringValues,\n shouldUseParameterInit,\n propsParam,\n propsParamName,\n functionBodyStart\n )\n );\n }\n\n // Number type suggestions\n if (prop.type === \"number\") {\n const numberValues = [\n { value: \"0\", display: \"0\" },\n { value: \"undefined\", display: \"undefined\" },\n ];\n suggestions.push(\n ...createSuggestionsForValues(\n prop.name,\n numberValues,\n shouldUseParameterInit,\n propsParam,\n propsParamName,\n functionBodyStart\n )\n );\n }\n\n // Object/unknown type suggestions\n if (prop.type === \"object\" || prop.type === \"unknown\") {\n const typeDisplay = prop.type === \"unknown\" ? \"any value\" : prop.type;\n suggestions.push(\n createSuggestion(\n prop.name,\n \"undefined\",\n `undefined (${typeDisplay})`,\n shouldUseParameterInit,\n propsParam,\n propsParamName,\n functionBodyStart\n )\n );\n }\n\n return suggestions;\n};\n"]}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { ESLintUtils } from "@typescript-eslint/utils";
|
|
2
|
+
import type { Rule } from "eslint";
|
|
3
|
+
export declare const rulesMap: {
|
|
4
|
+
"cva-merge-base-classes-as-array": ESLintUtils.RuleModule<"stringNeedsArray" | "arrayNeedsSplit", [], unknown, ESLintUtils.RuleListener> & {
|
|
5
|
+
name: string;
|
|
6
|
+
};
|
|
7
|
+
"no-internal-barrel-files": ESLintUtils.RuleModule<"noInternalBarrel", [], unknown, ESLintUtils.RuleListener> & {
|
|
8
|
+
name: string;
|
|
9
|
+
};
|
|
10
|
+
"no-typescript-assertion": {
|
|
11
|
+
meta: Rule.RuleMetaData;
|
|
12
|
+
create: (context: Rule.RuleContext) => Rule.RuleListener;
|
|
13
|
+
};
|
|
14
|
+
"no-internal-graphql-when-tagged-with-gql-public": {
|
|
15
|
+
meta: Rule.RuleMetaData;
|
|
16
|
+
create: (context: Rule.RuleContext) => Rule.RuleListener;
|
|
17
|
+
};
|
|
18
|
+
"design-guideline-button-icon-size-match": ESLintUtils.RuleModule<"incorrectIconSize", [], unknown, ESLintUtils.RuleListener> & {
|
|
19
|
+
name: string;
|
|
20
|
+
};
|
|
21
|
+
"no-template-strings-in-classname-prop": ESLintUtils.RuleModule<"templateStringInClassName", [], unknown, ESLintUtils.RuleListener> & {
|
|
22
|
+
name: string;
|
|
23
|
+
};
|
|
24
|
+
"require-classname-alternatives": ESLintUtils.RuleModule<"bannedClassAutoFix" | "bannedClassSuggest" | "suggestReplacement", [({
|
|
25
|
+
alternatives: Record<string, Array<string>>;
|
|
26
|
+
prefixes?: Array<string>;
|
|
27
|
+
} | undefined)?], unknown, ESLintUtils.RuleListener> & {
|
|
28
|
+
name: string;
|
|
29
|
+
};
|
|
30
|
+
"no-jest-mock-trackunit-react-core-hooks": Rule.RuleModule;
|
|
31
|
+
"prefer-destructured-imports": ESLintUtils.RuleModule<"preferDestructured" | "preferDestructuredGlobal", [({
|
|
32
|
+
packages: Record<string, string>;
|
|
33
|
+
} | undefined)?], unknown, ESLintUtils.RuleListener> & {
|
|
34
|
+
name: string;
|
|
35
|
+
};
|
|
36
|
+
"prefer-mouse-event-handler-in-react-props": ESLintUtils.RuleModule<"suggestMouseEventHandler" | "preferMouseEventHandler", [{
|
|
37
|
+
allowedNames?: ReadonlyArray<string>;
|
|
38
|
+
}], unknown, ESLintUtils.RuleListener> & {
|
|
39
|
+
name: string;
|
|
40
|
+
};
|
|
41
|
+
"prefer-event-specific-callback-naming": ESLintUtils.RuleModule<import("./rules/prefer-event-specific-callback-naming/strategies/string-based").NameBasedMessageIds | import("./rules/prefer-event-specific-callback-naming/strategies/type-based").TypeBasedMessageIds, [{
|
|
42
|
+
allowedNames?: ReadonlyArray<string>;
|
|
43
|
+
events?: ReadonlyArray<string>;
|
|
44
|
+
}], unknown, ESLintUtils.RuleListener> & {
|
|
45
|
+
name: string;
|
|
46
|
+
};
|
|
47
|
+
"require-optional-prop-initialization": ESLintUtils.RuleModule<import("./rules/require-optional-prop-initialization/suggestion-utils").MessageIds, [{
|
|
48
|
+
allowNullableObject?: boolean;
|
|
49
|
+
allowNullableBoolean?: boolean;
|
|
50
|
+
allowNullableString?: boolean;
|
|
51
|
+
allowNullableNumber?: boolean;
|
|
52
|
+
allowNullableEnum?: boolean;
|
|
53
|
+
allowNullableStringLiteralUnion?: boolean;
|
|
54
|
+
onlyRequireUsedProps?: boolean;
|
|
55
|
+
}], unknown, ESLintUtils.RuleListener> & {
|
|
56
|
+
name: string;
|
|
57
|
+
};
|
|
58
|
+
"prefer-field-components": ESLintUtils.RuleModule<"preferFieldComponent", [], unknown, ESLintUtils.RuleListener> & {
|
|
59
|
+
name: string;
|
|
60
|
+
};
|
|
61
|
+
"require-list-item-virtualization-props": ESLintUtils.RuleModule<"requireVirtualizationProps" | "spreadListItemProps" | "useSemanticListItem", [{
|
|
62
|
+
allowCustomComponents?: boolean;
|
|
63
|
+
}], unknown, ESLintUtils.RuleListener> & {
|
|
64
|
+
name: string;
|
|
65
|
+
};
|
|
66
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.rulesMap = void 0;
|
|
4
|
+
const cva_merge_base_classes_as_array_1 = require("./rules/cva-merge-base-classes-as-array/cva-merge-base-classes-as-array");
|
|
5
|
+
const design_guideline_button_icon_size_match_1 = require("./rules/design-guideline-button-icon-size-match/design-guideline-button-icon-size-match");
|
|
6
|
+
const no_internal_barrel_files_1 = require("./rules/no-internal-barrel-files/no-internal-barrel-files");
|
|
7
|
+
const no_internal_graphql_when_tagged_with_gql_public_1 = require("./rules/no-internal-graphql-when-tagged-with-gql-public/no-internal-graphql-when-tagged-with-gql-public");
|
|
8
|
+
const no_jest_mock_trackunit_react_core_hooks_1 = require("./rules/no-jest-mock-trackunit-react-core-hooks/no-jest-mock-trackunit-react-core-hooks");
|
|
9
|
+
const no_template_strings_in_classname_prop_1 = require("./rules/no-template-strings-in-classname-prop/no-template-strings-in-classname-prop");
|
|
10
|
+
const no_typescript_assertion_1 = require("./rules/no-typescript-assertion/no-typescript-assertion");
|
|
11
|
+
const prefer_destructured_imports_1 = require("./rules/prefer-destructured-imports/prefer-destructured-imports");
|
|
12
|
+
const prefer_event_specific_callback_naming_1 = require("./rules/prefer-event-specific-callback-naming/prefer-event-specific-callback-naming");
|
|
13
|
+
const prefer_field_components_1 = require("./rules/prefer-field-components/prefer-field-components");
|
|
14
|
+
const prefer_mouse_event_handler_in_react_props_1 = require("./rules/prefer-mouse-event-handler-in-react-props/prefer-mouse-event-handler-in-react-props");
|
|
15
|
+
const require_classname_alternatives_1 = require("./rules/require-classname-alternatives/require-classname-alternatives");
|
|
16
|
+
const require_list_item_virtualization_props_1 = require("./rules/require-list-item-virtualization-props/require-list-item-virtualization-props");
|
|
17
|
+
const require_optional_prop_initialization_1 = require("./rules/require-optional-prop-initialization/require-optional-prop-initialization");
|
|
18
|
+
exports.rulesMap = {
|
|
19
|
+
"cva-merge-base-classes-as-array": cva_merge_base_classes_as_array_1.cvaMergeBaseClassesAsArray,
|
|
20
|
+
"no-internal-barrel-files": no_internal_barrel_files_1.noInternalBarrelFiles,
|
|
21
|
+
"no-typescript-assertion": no_typescript_assertion_1.noTypescriptAssertion,
|
|
22
|
+
"no-internal-graphql-when-tagged-with-gql-public": no_internal_graphql_when_tagged_with_gql_public_1.noInternalGraphqlWhenTaggedWithGqlPublic,
|
|
23
|
+
"design-guideline-button-icon-size-match": design_guideline_button_icon_size_match_1.designGuidelineButtonIconSizeMatch,
|
|
24
|
+
"no-template-strings-in-classname-prop": no_template_strings_in_classname_prop_1.noTemplateStringsInClassName,
|
|
25
|
+
"require-classname-alternatives": require_classname_alternatives_1.requireClassnameAlternatives,
|
|
26
|
+
"no-jest-mock-trackunit-react-core-hooks": no_jest_mock_trackunit_react_core_hooks_1.noJestMockTrackunitReactCoreHooks,
|
|
27
|
+
"prefer-destructured-imports": prefer_destructured_imports_1.preferDestructuredImports,
|
|
28
|
+
"prefer-mouse-event-handler-in-react-props": prefer_mouse_event_handler_in_react_props_1.preferMouseEventHandlerInReactProps,
|
|
29
|
+
"prefer-event-specific-callback-naming": prefer_event_specific_callback_naming_1.preferEventSpecificCallbackNaming,
|
|
30
|
+
"require-optional-prop-initialization": require_optional_prop_initialization_1.requireOptionalPropInitialization,
|
|
31
|
+
"prefer-field-components": prefer_field_components_1.preferFieldComponents,
|
|
32
|
+
"require-list-item-virtualization-props": require_list_item_virtualization_props_1.requireListItemVirtualizationProps,
|
|
33
|
+
};
|
|
34
|
+
//# sourceMappingURL=rules-map.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rules-map.js","sourceRoot":"","sources":["../../../../../../libs/eslint/plugin-trackunit/src/lib/rules-map.ts"],"names":[],"mappings":";;;AAEA,6HAAqH;AACrH,qJAA6I;AAC7I,wGAAkG;AAClG,6KAAmK;AACnK,qJAA4I;AAC5I,+IAAmI;AACnI,qGAAgG;AAChG,iHAA4G;AAC5G,+IAAwI;AACxI,qGAAgG;AAChG,2JAAkJ;AAClJ,0HAAqH;AACrH,kJAA2I;AAC3I,4IAAsI;AAEzH,QAAA,QAAQ,GAAG;IACtB,iCAAiC,EAAE,4DAA0B;IAC7D,0BAA0B,EAAE,gDAAqB;IACjD,yBAAyB,EAAE,+CAAqB;IAChD,iDAAiD,EAAE,0FAAwC;IAC3F,yCAAyC,EAAE,4EAAkC;IAC7E,uCAAuC,EAAE,oEAA4B;IACrE,gCAAgC,EAAE,6DAA4B;IAC9D,yCAAyC,EAAE,2EAAiC;IAC5E,6BAA6B,EAAE,uDAAyB;IACxD,2CAA2C,EAAE,+EAAmC;IAChF,uCAAuC,EAAE,yEAAiC;IAC1E,sCAAsC,EAAE,wEAAiC;IACzE,yBAAyB,EAAE,+CAAqB;IAChD,wCAAwC,EAAE,2EAAkC;CACsB,CAAC","sourcesContent":["import { ESLintUtils } from \"@typescript-eslint/utils\";\nimport type { Rule } from \"eslint\";\nimport { cvaMergeBaseClassesAsArray } from \"./rules/cva-merge-base-classes-as-array/cva-merge-base-classes-as-array\";\nimport { designGuidelineButtonIconSizeMatch } from \"./rules/design-guideline-button-icon-size-match/design-guideline-button-icon-size-match\";\nimport { noInternalBarrelFiles } from \"./rules/no-internal-barrel-files/no-internal-barrel-files\";\nimport { noInternalGraphqlWhenTaggedWithGqlPublic } from \"./rules/no-internal-graphql-when-tagged-with-gql-public/no-internal-graphql-when-tagged-with-gql-public\";\nimport { noJestMockTrackunitReactCoreHooks } from \"./rules/no-jest-mock-trackunit-react-core-hooks/no-jest-mock-trackunit-react-core-hooks\";\nimport { noTemplateStringsInClassName } from \"./rules/no-template-strings-in-classname-prop/no-template-strings-in-classname-prop\";\nimport { noTypescriptAssertion } from \"./rules/no-typescript-assertion/no-typescript-assertion\";\nimport { preferDestructuredImports } from \"./rules/prefer-destructured-imports/prefer-destructured-imports\";\nimport { preferEventSpecificCallbackNaming } from \"./rules/prefer-event-specific-callback-naming/prefer-event-specific-callback-naming\";\nimport { preferFieldComponents } from \"./rules/prefer-field-components/prefer-field-components\";\nimport { preferMouseEventHandlerInReactProps } from \"./rules/prefer-mouse-event-handler-in-react-props/prefer-mouse-event-handler-in-react-props\";\nimport { requireClassnameAlternatives } from \"./rules/require-classname-alternatives/require-classname-alternatives\";\nimport { requireListItemVirtualizationProps } from \"./rules/require-list-item-virtualization-props/require-list-item-virtualization-props\";\nimport { requireOptionalPropInitialization } from \"./rules/require-optional-prop-initialization/require-optional-prop-initialization\";\n\nexport const rulesMap = {\n \"cva-merge-base-classes-as-array\": cvaMergeBaseClassesAsArray,\n \"no-internal-barrel-files\": noInternalBarrelFiles,\n \"no-typescript-assertion\": noTypescriptAssertion,\n \"no-internal-graphql-when-tagged-with-gql-public\": noInternalGraphqlWhenTaggedWithGqlPublic,\n \"design-guideline-button-icon-size-match\": designGuidelineButtonIconSizeMatch,\n \"no-template-strings-in-classname-prop\": noTemplateStringsInClassName,\n \"require-classname-alternatives\": requireClassnameAlternatives,\n \"no-jest-mock-trackunit-react-core-hooks\": noJestMockTrackunitReactCoreHooks,\n \"prefer-destructured-imports\": preferDestructuredImports,\n \"prefer-mouse-event-handler-in-react-props\": preferMouseEventHandlerInReactProps,\n \"prefer-event-specific-callback-naming\": preferEventSpecificCallbackNaming,\n \"require-optional-prop-initialization\": requireOptionalPropInitialization,\n \"prefer-field-components\": preferFieldComponents,\n \"require-list-item-virtualization-props\": requireListItemVirtualizationProps,\n} satisfies Record<string, Rule.RuleModule | ESLintUtils.RuleModule<string, ReadonlyArray<unknown>>>;\n"]}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { TSESLint, TSESTree } from "@typescript-eslint/utils";
|
|
2
|
+
/**
|
|
3
|
+
* Check if a parameter is explicitly destructured in the parameter list
|
|
4
|
+
* (vs. captured in rest parameters like ...restOptions)
|
|
5
|
+
*/
|
|
6
|
+
export declare const isParameterExplicitlyDestructured: (parameter: TSESTree.Parameter, paramName: string) => boolean;
|
|
7
|
+
/**
|
|
8
|
+
* Check if there are any existing parameter initializations in the function body
|
|
9
|
+
*/
|
|
10
|
+
export declare const hasExistingBodyInitializations: (functionBody: Array<TSESTree.Statement>) => boolean;
|
|
11
|
+
/**
|
|
12
|
+
* Check if a parameter is initialized in the function body or parameter defaults
|
|
13
|
+
*/
|
|
14
|
+
export declare const isParameterInitialized: (functionBody: Array<TSESTree.Statement>, paramName: string, parameter?: TSESTree.Parameter) => boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Check if a parameter is used within the function body
|
|
17
|
+
*/
|
|
18
|
+
export declare const isParameterUsedInFunction: (context: TSESLint.RuleContext<string, ReadonlyArray<unknown>>, functionNode: TSESTree.FunctionDeclaration | TSESTree.ArrowFunctionExpression, paramName: string) => boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Check if a function is likely a React component based on naming and JSX usage
|
|
21
|
+
*/
|
|
22
|
+
export declare const isReactComponent: (node: TSESTree.FunctionDeclaration | TSESTree.ArrowFunctionExpression) => boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Check if a parameter is only used in JSX attributes (pass-through to child components)
|
|
25
|
+
* and nowhere else in the function body
|
|
26
|
+
*/
|
|
27
|
+
export declare const isParameterOnlyUsedInJSX: (context: TSESLint.RuleContext<string, ReadonlyArray<unknown>>, functionNode: TSESTree.FunctionDeclaration | TSESTree.ArrowFunctionExpression, paramName: string) => boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Result of tracing an identifier back to its origin.
|
|
30
|
+
* Used to distinguish between different ways an identifier can come from a function parameter.
|
|
31
|
+
*/
|
|
32
|
+
export type ParameterOriginResult = {
|
|
33
|
+
isFromParameter: true;
|
|
34
|
+
/**
|
|
35
|
+
* How the identifier relates to the parameter:
|
|
36
|
+
* - "direct-parameter": Direct parameter, e.g., `(onClose) => ...`
|
|
37
|
+
* - "destructured-in-signature": Destructured in function signature, e.g., `({ onClose }) => ...`
|
|
38
|
+
* - "destructured-in-body": Destructured in function body, e.g., `const { onClose } = props`
|
|
39
|
+
*/
|
|
40
|
+
originType: "direct-parameter" | "destructured-in-signature" | "destructured-in-body";
|
|
41
|
+
} | {
|
|
42
|
+
isFromParameter: false;
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Checks if an identifier originates from a function parameter.
|
|
46
|
+
* This is a simplified boolean helper that wraps `getIdentifierParameterOrigin`.
|
|
47
|
+
*
|
|
48
|
+
* Use this when you only need to know if an identifier comes from a parameter,
|
|
49
|
+
* without needing to know how it was destructured.
|
|
50
|
+
*
|
|
51
|
+
* @param identifier - The identifier node to check
|
|
52
|
+
* @param context - The ESLint rule context
|
|
53
|
+
* @returns true if the identifier originates from a function parameter
|
|
54
|
+
* @see getIdentifierParameterOrigin for detailed origin information
|
|
55
|
+
*/
|
|
56
|
+
export declare const isIdentifierFromParameter: (identifier: TSESTree.Identifier, context: TSESLint.RuleContext<string, ReadonlyArray<unknown>>) => boolean;
|
|
57
|
+
/**
|
|
58
|
+
* Checks if an identifier's parameter comes from a render prop callback.
|
|
59
|
+
*
|
|
60
|
+
* Render prop pattern: `{callback => <Component onClick={callback} />}`
|
|
61
|
+
*
|
|
62
|
+
* The function detects when:
|
|
63
|
+
* 1. The identifier comes from a parameter
|
|
64
|
+
* 2. That parameter's function is inside a JSXExpressionContainer
|
|
65
|
+
* 3. Which is a child of a JSXElement (render prop pattern)
|
|
66
|
+
*
|
|
67
|
+
* This is used to distinguish between:
|
|
68
|
+
* - React component props: `const Modal = ({ onClose }) => ...` - should be flagged
|
|
69
|
+
* - Render prop callbacks: `<MoreMenu>{close => <MenuItem onClick={close} />}</MoreMenu>` - should NOT be flagged
|
|
70
|
+
*
|
|
71
|
+
* @param identifier - The identifier node to check
|
|
72
|
+
* @param context - The ESLint rule context
|
|
73
|
+
* @returns true if the identifier comes from a render prop callback parameter
|
|
74
|
+
* @example
|
|
75
|
+
* // Render prop callback - returns true
|
|
76
|
+
* <MoreMenu>
|
|
77
|
+
* {close => <MenuItem onClick={close} />}
|
|
78
|
+
* </MoreMenu>
|
|
79
|
+
* // isIdentifierFromRenderPropCallback(close) => true
|
|
80
|
+
* @example
|
|
81
|
+
* // React component prop - returns false
|
|
82
|
+
* const Modal = ({ onClose }) => <button onClick={onClose} />;
|
|
83
|
+
* // isIdentifierFromRenderPropCallback(onClose) => false
|
|
84
|
+
*/
|
|
85
|
+
export declare const isIdentifierFromRenderPropCallback: (identifier: TSESTree.Identifier, context: TSESLint.RuleContext<string, ReadonlyArray<unknown>>) => boolean;
|