@formspec/eslint-plugin 0.1.0-alpha.7 → 0.1.0-alpha.9
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 +32 -12
- package/dist/index.d.ts +12 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -6
- package/dist/index.js.map +1 -1
- package/dist/rules/consistent-constraints.d.ts +22 -0
- package/dist/rules/consistent-constraints.d.ts.map +1 -0
- package/dist/rules/consistent-constraints.js +178 -0
- package/dist/rules/consistent-constraints.js.map +1 -0
- package/dist/rules/constraints/allowed-field-types.d.ts.map +1 -1
- package/dist/rules/constraints/allowed-field-types.js +2 -1
- package/dist/rules/constraints/allowed-field-types.js.map +1 -1
- package/dist/rules/constraints/allowed-layouts.js +1 -0
- package/dist/rules/constraints/allowed-layouts.js.map +1 -1
- package/dist/rules/decorator-allowed-field-types.d.ts +17 -0
- package/dist/rules/decorator-allowed-field-types.d.ts.map +1 -0
- package/dist/rules/decorator-allowed-field-types.js +71 -0
- package/dist/rules/decorator-allowed-field-types.js.map +1 -0
- package/dist/rules/decorator-field-type-mismatch.d.ts +3 -4
- package/dist/rules/decorator-field-type-mismatch.d.ts.map +1 -1
- package/dist/rules/decorator-field-type-mismatch.js +46 -17
- package/dist/rules/decorator-field-type-mismatch.js.map +1 -1
- package/dist/rules/enum-options-match-type.d.ts.map +1 -1
- package/dist/rules/enum-options-match-type.js +2 -2
- package/dist/rules/enum-options-match-type.js.map +1 -1
- package/dist/rules/index.d.ts +3 -1
- package/dist/rules/index.d.ts.map +1 -1
- package/dist/rules/index.js +3 -1
- package/dist/rules/index.js.map +1 -1
- package/dist/rules/no-conflicting-decorators.d.ts +2 -6
- package/dist/rules/no-conflicting-decorators.d.ts.map +1 -1
- package/dist/rules/no-conflicting-decorators.js +2 -6
- package/dist/rules/no-conflicting-decorators.js.map +1 -1
- package/dist/rules/no-duplicate-decorators.d.ts +2 -2
- package/dist/rules/no-duplicate-decorators.d.ts.map +1 -1
- package/dist/rules/no-duplicate-decorators.js +4 -19
- package/dist/rules/no-duplicate-decorators.js.map +1 -1
- package/dist/rules/prefer-custom-decorator.d.ts +22 -0
- package/dist/rules/prefer-custom-decorator.d.ts.map +1 -0
- package/dist/rules/prefer-custom-decorator.js +72 -0
- package/dist/rules/prefer-custom-decorator.js.map +1 -0
- package/dist/rules/showwhen-field-exists.d.ts.map +1 -1
- package/dist/rules/showwhen-field-exists.js.map +1 -1
- package/dist/rules/showwhen-suggests-optional.d.ts.map +1 -1
- package/dist/rules/showwhen-suggests-optional.js.map +1 -1
- package/dist/utils/decorator-utils.d.ts +8 -6
- package/dist/utils/decorator-utils.d.ts.map +1 -1
- package/dist/utils/decorator-utils.js +16 -22
- package/dist/utils/decorator-utils.js.map +1 -1
- package/dist/utils/jsdoc-utils.d.ts +31 -0
- package/dist/utils/jsdoc-utils.d.ts.map +1 -0
- package/dist/utils/jsdoc-utils.js +81 -0
- package/dist/utils/jsdoc-utils.js.map +1 -0
- package/dist/utils/type-utils.d.ts.map +1 -1
- package/dist/utils/type-utils.js +30 -6
- package/dist/utils/type-utils.js.map +1 -1
- package/package.json +3 -2
- package/dist/rules/min-max-valid-range.d.ts +0 -26
- package/dist/rules/min-max-valid-range.d.ts.map +0 -1
- package/dist/rules/min-max-valid-range.js +0 -82
- package/dist/rules/min-max-valid-range.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,3 +1,24 @@
|
|
|
1
|
+
# @your-org/eslint-plugin
|
|
2
|
+
|
|
3
|
+
ESLint rules for working with your schema/constraints.
|
|
4
|
+
|
|
5
|
+
## Rules
|
|
6
|
+
|
|
7
|
+
| Rule name | Description |
|
|
8
|
+
| ----------------------- | --------------------------------------------------------------- |
|
|
9
|
+
| `consistent-constraints` | Enforces consistent min/max and related constraints in schemas. |
|
|
10
|
+
|
|
11
|
+
## Rule details
|
|
12
|
+
|
|
13
|
+
### `consistent-constraints`
|
|
14
|
+
|
|
15
|
+
This rule validates that constraint-related properties (such as minimum and maximum
|
|
16
|
+
values, lengths, or ranges) are used consistently and do not contradict each other.
|
|
17
|
+
|
|
18
|
+
It is intended as a replacement for the now-removed `min-max-valid-range` rule and
|
|
19
|
+
should be enabled wherever constraint consistency needs to be enforced.
|
|
20
|
+
|
|
21
|
+
<!-- Add additional rules and documentation here as needed. -->
|
|
1
22
|
# @formspec/eslint-plugin
|
|
2
23
|
|
|
3
24
|
ESLint plugin for validating FormSpec decorator DSL usage in TypeScript projects. This plugin catches common mistakes by ensuring decorators match their field types and enforcing consistency rules.
|
|
@@ -55,15 +76,15 @@ export default [
|
|
|
55
76
|
|
|
56
77
|
## Rules
|
|
57
78
|
|
|
58
|
-
| Rule
|
|
59
|
-
|
|
60
|
-
| [`decorator-field-type-mismatch`](#decorator-field-type-mismatch) | Ensures decorators are applied to fields with compatible types | error
|
|
61
|
-
| [`enum-options-match-type`](#enum-options-match-type)
|
|
62
|
-
| [`showwhen-field-exists`](#showwhen-field-exists)
|
|
63
|
-
| [`showwhen-suggests-optional`](#showwhen-suggests-optional)
|
|
64
|
-
| [`min-max-valid-range`](#min-max-valid-range)
|
|
65
|
-
| [`no-conflicting-decorators`](#no-conflicting-decorators)
|
|
66
|
-
| [`no-duplicate-decorators`](#no-duplicate-decorators)
|
|
79
|
+
| Rule | Description | Recommended | Strict |
|
|
80
|
+
| ----------------------------------------------------------------- | -------------------------------------------------------------- | ----------- | ------ |
|
|
81
|
+
| [`decorator-field-type-mismatch`](#decorator-field-type-mismatch) | Ensures decorators are applied to fields with compatible types | error | error |
|
|
82
|
+
| [`enum-options-match-type`](#enum-options-match-type) | Ensures @EnumOptions values match the field's union type | error | error |
|
|
83
|
+
| [`showwhen-field-exists`](#showwhen-field-exists) | Ensures @ShowWhen references a field that exists | error | error |
|
|
84
|
+
| [`showwhen-suggests-optional`](#showwhen-suggests-optional) | Suggests @ShowWhen fields should be optional | warn | error |
|
|
85
|
+
| [`min-max-valid-range`](#min-max-valid-range) | Ensures @Min/@Max have valid ranges | error | error |
|
|
86
|
+
| [`no-conflicting-decorators`](#no-conflicting-decorators) | Prevents decorators that imply conflicting types | error | error |
|
|
87
|
+
| [`no-duplicate-decorators`](#no-duplicate-decorators) | Prevents duplicate decorators on the same field | error | error |
|
|
67
88
|
|
|
68
89
|
### decorator-field-type-mismatch
|
|
69
90
|
|
|
@@ -197,6 +218,7 @@ name!: string;
|
|
|
197
218
|
### Recommended
|
|
198
219
|
|
|
199
220
|
Sensible defaults for most projects:
|
|
221
|
+
|
|
200
222
|
- All type safety rules enabled as errors
|
|
201
223
|
- `showwhen-suggests-optional` as warning (not blocking)
|
|
202
224
|
|
|
@@ -207,9 +229,7 @@ All rules enabled as errors for maximum type safety enforcement.
|
|
|
207
229
|
```javascript
|
|
208
230
|
import formspec from "@formspec/eslint-plugin";
|
|
209
231
|
|
|
210
|
-
export default [
|
|
211
|
-
...formspec.configs.strict,
|
|
212
|
-
];
|
|
232
|
+
export default [...formspec.configs.strict];
|
|
213
233
|
```
|
|
214
234
|
|
|
215
235
|
## License
|
package/dist/index.d.ts
CHANGED
|
@@ -13,9 +13,11 @@ import { decoratorFieldTypeMismatch } from "./rules/decorator-field-type-mismatc
|
|
|
13
13
|
import { enumOptionsMatchType } from "./rules/enum-options-match-type.js";
|
|
14
14
|
import { showwhenFieldExists } from "./rules/showwhen-field-exists.js";
|
|
15
15
|
import { showwhenSuggestsOptional } from "./rules/showwhen-suggests-optional.js";
|
|
16
|
-
import {
|
|
16
|
+
import { consistentConstraints } from "./rules/consistent-constraints.js";
|
|
17
17
|
import { noConflictingDecorators } from "./rules/no-conflicting-decorators.js";
|
|
18
18
|
import { noDuplicateDecorators } from "./rules/no-duplicate-decorators.js";
|
|
19
|
+
import { decoratorAllowedFieldTypes } from "./rules/decorator-allowed-field-types.js";
|
|
20
|
+
import { preferCustomDecorator } from "./rules/prefer-custom-decorator.js";
|
|
19
21
|
import { allowedFieldTypes, allowedLayouts } from "./rules/constraints/index.js";
|
|
20
22
|
/**
|
|
21
23
|
* The FormSpec ESLint plugin.
|
|
@@ -25,7 +27,7 @@ declare const plugin: {
|
|
|
25
27
|
name: string;
|
|
26
28
|
};
|
|
27
29
|
rules: {
|
|
28
|
-
readonly "decorator-field-type-mismatch": TSESLint.RuleModule<"
|
|
30
|
+
readonly "decorator-field-type-mismatch": TSESLint.RuleModule<"numericOnNonNumber" | "stringOnNonString", [], unknown, TSESLint.RuleListener> & {
|
|
29
31
|
name: string;
|
|
30
32
|
};
|
|
31
33
|
readonly "enum-options-match-type": TSESLint.RuleModule<"enumOptionsMismatch" | "enumOptionsMissing" | "enumOptionsExtra", [], unknown, TSESLint.RuleListener> & {
|
|
@@ -37,7 +39,7 @@ declare const plugin: {
|
|
|
37
39
|
readonly "showwhen-suggests-optional": TSESLint.RuleModule<"shouldBeOptional", [], unknown, TSESLint.RuleListener> & {
|
|
38
40
|
name: string;
|
|
39
41
|
};
|
|
40
|
-
readonly "
|
|
42
|
+
readonly "consistent-constraints": TSESLint.RuleModule<"minimumGreaterThanMaximum" | "exclusiveMinGreaterOrEqualMax" | "minLengthGreaterThanMaxLength" | "conflictingMinimumBounds" | "conflictingMaximumBounds" | "exclusiveMaxLessOrEqualMin" | "maximumLessOrEqualExclusiveMin" | "duplicateConstraintSource", [], unknown, TSESLint.RuleListener> & {
|
|
41
43
|
name: string;
|
|
42
44
|
};
|
|
43
45
|
readonly "no-conflicting-decorators": TSESLint.RuleModule<"conflictingDecorators", [], unknown, TSESLint.RuleListener> & {
|
|
@@ -46,6 +48,12 @@ declare const plugin: {
|
|
|
46
48
|
readonly "no-duplicate-decorators": TSESLint.RuleModule<"duplicateDecorator", [], unknown, TSESLint.RuleListener> & {
|
|
47
49
|
name: string;
|
|
48
50
|
};
|
|
51
|
+
readonly "decorator-allowed-field-types": TSESLint.RuleModule<"disallowedFieldType", [import("./rules/decorator-allowed-field-types.js").DecoratorAllowedFieldTypesOptions], unknown, TSESLint.RuleListener> & {
|
|
52
|
+
name: string;
|
|
53
|
+
};
|
|
54
|
+
readonly "prefer-custom-decorator": TSESLint.RuleModule<"preferCustomDecorator", [import("./rules/prefer-custom-decorator.js").PreferCustomDecoratorOptions], unknown, TSESLint.RuleListener> & {
|
|
55
|
+
name: string;
|
|
56
|
+
};
|
|
49
57
|
readonly "constraints-allowed-field-types": TSESLint.RuleModule<"disallowedFieldType", import("./rules/constraints/allowed-field-types.js").Options, unknown, TSESLint.RuleListener> & {
|
|
50
58
|
name: string;
|
|
51
59
|
};
|
|
@@ -59,5 +67,5 @@ declare const plugin: {
|
|
|
59
67
|
};
|
|
60
68
|
};
|
|
61
69
|
export default plugin;
|
|
62
|
-
export { decoratorFieldTypeMismatch, enumOptionsMatchType, showwhenFieldExists, showwhenSuggestsOptional,
|
|
70
|
+
export { decoratorFieldTypeMismatch, enumOptionsMatchType, showwhenFieldExists, showwhenSuggestsOptional, consistentConstraints, noConflictingDecorators, noDuplicateDecorators, decoratorAllowedFieldTypes, preferCustomDecorator, allowedFieldTypes, allowedLayouts, };
|
|
63
71
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,0BAA0B,EAAE,MAAM,0CAA0C,CAAC;AACtF,OAAO,EAAE,oBAAoB,EAAE,MAAM,oCAAoC,CAAC;AAC1E,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AACvE,OAAO,EAAE,wBAAwB,EAAE,MAAM,uCAAuC,CAAC;AACjF,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,0BAA0B,EAAE,MAAM,0CAA0C,CAAC;AACtF,OAAO,EAAE,oBAAoB,EAAE,MAAM,oCAAoC,CAAC;AAC1E,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AACvE,OAAO,EAAE,wBAAwB,EAAE,MAAM,uCAAuC,CAAC;AACjF,OAAO,EAAE,qBAAqB,EAAE,MAAM,mCAAmC,CAAC;AAC1E,OAAO,EAAE,uBAAuB,EAAE,MAAM,sCAAsC,CAAC;AAC/E,OAAO,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAC;AAC3E,OAAO,EAAE,0BAA0B,EAAE,MAAM,0CAA0C,CAAC;AACtF,OAAO,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAC;AAG3E,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAoFjF;;GAEG;AACH,QAAA,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAOX,CAAC;AAEF,eAAe,MAAM,CAAC;AAGtB,OAAO,EAEL,0BAA0B,EAC1B,oBAAoB,EACpB,mBAAmB,EACnB,wBAAwB,EACxB,qBAAqB,EACrB,uBAAuB,EACvB,qBAAqB,EACrB,0BAA0B,EAC1B,qBAAqB,EAErB,iBAAiB,EACjB,cAAc,GACf,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -12,11 +12,13 @@ import { decoratorFieldTypeMismatch } from "./rules/decorator-field-type-mismatc
|
|
|
12
12
|
import { enumOptionsMatchType } from "./rules/enum-options-match-type.js";
|
|
13
13
|
import { showwhenFieldExists } from "./rules/showwhen-field-exists.js";
|
|
14
14
|
import { showwhenSuggestsOptional } from "./rules/showwhen-suggests-optional.js";
|
|
15
|
-
import {
|
|
15
|
+
import { consistentConstraints } from "./rules/consistent-constraints.js";
|
|
16
16
|
import { noConflictingDecorators } from "./rules/no-conflicting-decorators.js";
|
|
17
17
|
import { noDuplicateDecorators } from "./rules/no-duplicate-decorators.js";
|
|
18
|
+
import { decoratorAllowedFieldTypes } from "./rules/decorator-allowed-field-types.js";
|
|
19
|
+
import { preferCustomDecorator } from "./rules/prefer-custom-decorator.js";
|
|
18
20
|
// Constraint rules for Chain DSL
|
|
19
|
-
import { allowedFieldTypes, allowedLayouts
|
|
21
|
+
import { allowedFieldTypes, allowedLayouts } from "./rules/constraints/index.js";
|
|
20
22
|
/**
|
|
21
23
|
* All rules provided by this plugin.
|
|
22
24
|
*/
|
|
@@ -26,9 +28,11 @@ const rules = {
|
|
|
26
28
|
"enum-options-match-type": enumOptionsMatchType,
|
|
27
29
|
"showwhen-field-exists": showwhenFieldExists,
|
|
28
30
|
"showwhen-suggests-optional": showwhenSuggestsOptional,
|
|
29
|
-
"
|
|
31
|
+
"consistent-constraints": consistentConstraints,
|
|
30
32
|
"no-conflicting-decorators": noConflictingDecorators,
|
|
31
33
|
"no-duplicate-decorators": noDuplicateDecorators,
|
|
34
|
+
"decorator-allowed-field-types": decoratorAllowedFieldTypes,
|
|
35
|
+
"prefer-custom-decorator": preferCustomDecorator,
|
|
32
36
|
// Constraint rules for Chain DSL
|
|
33
37
|
"constraints-allowed-field-types": allowedFieldTypes,
|
|
34
38
|
"constraints-allowed-layouts": allowedLayouts,
|
|
@@ -64,7 +68,7 @@ const recommendedConfig = [
|
|
|
64
68
|
"@formspec/enum-options-match-type": "error",
|
|
65
69
|
"@formspec/showwhen-field-exists": "error",
|
|
66
70
|
"@formspec/showwhen-suggests-optional": "warn",
|
|
67
|
-
"@formspec/
|
|
71
|
+
"@formspec/consistent-constraints": "error",
|
|
68
72
|
"@formspec/no-conflicting-decorators": "error",
|
|
69
73
|
"@formspec/no-duplicate-decorators": "error",
|
|
70
74
|
},
|
|
@@ -86,7 +90,7 @@ const strictConfig = [
|
|
|
86
90
|
"@formspec/enum-options-match-type": "error",
|
|
87
91
|
"@formspec/showwhen-field-exists": "error",
|
|
88
92
|
"@formspec/showwhen-suggests-optional": "error",
|
|
89
|
-
"@formspec/
|
|
93
|
+
"@formspec/consistent-constraints": "error",
|
|
90
94
|
"@formspec/no-conflicting-decorators": "error",
|
|
91
95
|
"@formspec/no-duplicate-decorators": "error",
|
|
92
96
|
},
|
|
@@ -107,7 +111,7 @@ export default plugin;
|
|
|
107
111
|
// Named exports for individual rules
|
|
108
112
|
export {
|
|
109
113
|
// Decorator DSL rules
|
|
110
|
-
decoratorFieldTypeMismatch, enumOptionsMatchType, showwhenFieldExists, showwhenSuggestsOptional,
|
|
114
|
+
decoratorFieldTypeMismatch, enumOptionsMatchType, showwhenFieldExists, showwhenSuggestsOptional, consistentConstraints, noConflictingDecorators, noDuplicateDecorators, decoratorAllowedFieldTypes, preferCustomDecorator,
|
|
111
115
|
// Constraint rules for Chain DSL
|
|
112
116
|
allowedFieldTypes, allowedLayouts, };
|
|
113
117
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,EAAE,0BAA0B,EAAE,MAAM,0CAA0C,CAAC;AACtF,OAAO,EAAE,oBAAoB,EAAE,MAAM,oCAAoC,CAAC;AAC1E,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AACvE,OAAO,EAAE,wBAAwB,EAAE,MAAM,uCAAuC,CAAC;AACjF,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,EAAE,0BAA0B,EAAE,MAAM,0CAA0C,CAAC;AACtF,OAAO,EAAE,oBAAoB,EAAE,MAAM,oCAAoC,CAAC;AAC1E,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AACvE,OAAO,EAAE,wBAAwB,EAAE,MAAM,uCAAuC,CAAC;AACjF,OAAO,EAAE,qBAAqB,EAAE,MAAM,mCAAmC,CAAC;AAC1E,OAAO,EAAE,uBAAuB,EAAE,MAAM,sCAAsC,CAAC;AAC/E,OAAO,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAC;AAC3E,OAAO,EAAE,0BAA0B,EAAE,MAAM,0CAA0C,CAAC;AACtF,OAAO,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAC;AAE3E,iCAAiC;AACjC,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAEjF;;GAEG;AACH,MAAM,KAAK,GAAG;IACZ,sBAAsB;IACtB,+BAA+B,EAAE,0BAA0B;IAC3D,yBAAyB,EAAE,oBAAoB;IAC/C,uBAAuB,EAAE,mBAAmB;IAC5C,4BAA4B,EAAE,wBAAwB;IACtD,wBAAwB,EAAE,qBAAqB;IAC/C,2BAA2B,EAAE,uBAAuB;IACpD,yBAAyB,EAAE,qBAAqB;IAChD,+BAA+B,EAAE,0BAA0B;IAC3D,yBAAyB,EAAE,qBAAqB;IAEhD,iCAAiC;IACjC,iCAAiC,EAAE,iBAAiB;IACpD,6BAA6B,EAAE,cAAc;CACrC,CAAC;AAEX;;GAEG;AACH,MAAM,IAAI,GAAG;IACX,IAAI,EAAE,yBAAyB;CAChC,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,MAAM,iBAAiB,GAAoC;IACzD;QACE,OAAO,EAAE;YACP,WAAW,EAAE;gBACX,IAAI;gBACJ,KAAK;aACN;SACF;QACD,KAAK,EAAE;YACL,yCAAyC,EAAE,OAAO;YAClD,mCAAmC,EAAE,OAAO;YAC5C,iCAAiC,EAAE,OAAO;YAC1C,sCAAsC,EAAE,MAAM;YAC9C,kCAAkC,EAAE,OAAO;YAC3C,qCAAqC,EAAE,OAAO;YAC9C,mCAAmC,EAAE,OAAO;SAC7C;KACF;CACF,CAAC;AAEF;;GAEG;AACH,MAAM,YAAY,GAAoC;IACpD;QACE,OAAO,EAAE;YACP,WAAW,EAAE;gBACX,IAAI;gBACJ,KAAK;aACN;SACF;QACD,KAAK,EAAE;YACL,yCAAyC,EAAE,OAAO;YAClD,mCAAmC,EAAE,OAAO;YAC5C,iCAAiC,EAAE,OAAO;YAC1C,sCAAsC,EAAE,OAAO;YAC/C,kCAAkC,EAAE,OAAO;YAC3C,qCAAqC,EAAE,OAAO;YAC9C,mCAAmC,EAAE,OAAO;SAC7C;KACF;CACF,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,GAAG;IACb,IAAI;IACJ,KAAK;IACL,OAAO,EAAE;QACP,WAAW,EAAE,iBAAiB;QAC9B,MAAM,EAAE,YAAY;KACrB;CACF,CAAC;AAEF,eAAe,MAAM,CAAC;AAEtB,qCAAqC;AACrC,OAAO;AACL,sBAAsB;AACtB,0BAA0B,EAC1B,oBAAoB,EACpB,mBAAmB,EACnB,wBAAwB,EACxB,qBAAqB,EACrB,uBAAuB,EACvB,qBAAqB,EACrB,0BAA0B,EAC1B,qBAAqB;AACrB,iCAAiC;AACjC,iBAAiB,EACjB,cAAc,GACf,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule: consistent-constraints
|
|
3
|
+
*
|
|
4
|
+
* Ensures constraint decorator pairs have valid ranges and don't conflict:
|
|
5
|
+
* - @Minimum must be <= @Maximum
|
|
6
|
+
* - @ExclusiveMinimum must be < @ExclusiveMaximum
|
|
7
|
+
* - @MinLength must be <= @MaxLength
|
|
8
|
+
* - @Minimum and @ExclusiveMinimum must not both be present
|
|
9
|
+
* - @Maximum and @ExclusiveMaximum must not both be present
|
|
10
|
+
* - @Maximum(n) where n < @Minimum(m) is invalid
|
|
11
|
+
* - @ExclusiveMaximum(n) where n <= @Minimum(m) is invalid
|
|
12
|
+
*
|
|
13
|
+
* Constraints may come from decorators or JSDoc tags. If both a decorator
|
|
14
|
+
* and a JSDoc tag specify the same constraint, that is a lint error.
|
|
15
|
+
*/
|
|
16
|
+
import { ESLintUtils } from "@typescript-eslint/utils";
|
|
17
|
+
type MessageIds = "minimumGreaterThanMaximum" | "exclusiveMinGreaterOrEqualMax" | "minLengthGreaterThanMaxLength" | "conflictingMinimumBounds" | "conflictingMaximumBounds" | "exclusiveMaxLessOrEqualMin" | "maximumLessOrEqualExclusiveMin" | "duplicateConstraintSource";
|
|
18
|
+
export declare const consistentConstraints: ESLintUtils.RuleModule<MessageIds, [], unknown, ESLintUtils.RuleListener> & {
|
|
19
|
+
name: string;
|
|
20
|
+
};
|
|
21
|
+
export {};
|
|
22
|
+
//# sourceMappingURL=consistent-constraints.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consistent-constraints.d.ts","sourceRoot":"","sources":["../../src/rules/consistent-constraints.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAQvD,KAAK,UAAU,GACX,2BAA2B,GAC3B,+BAA+B,GAC/B,+BAA+B,GAC/B,0BAA0B,GAC1B,0BAA0B,GAC1B,4BAA4B,GAC5B,gCAAgC,GAChC,2BAA2B,CAAC;AAYhC,eAAO,MAAM,qBAAqB;;CAyLhC,CAAC"}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule: consistent-constraints
|
|
3
|
+
*
|
|
4
|
+
* Ensures constraint decorator pairs have valid ranges and don't conflict:
|
|
5
|
+
* - @Minimum must be <= @Maximum
|
|
6
|
+
* - @ExclusiveMinimum must be < @ExclusiveMaximum
|
|
7
|
+
* - @MinLength must be <= @MaxLength
|
|
8
|
+
* - @Minimum and @ExclusiveMinimum must not both be present
|
|
9
|
+
* - @Maximum and @ExclusiveMaximum must not both be present
|
|
10
|
+
* - @Maximum(n) where n < @Minimum(m) is invalid
|
|
11
|
+
* - @ExclusiveMaximum(n) where n <= @Minimum(m) is invalid
|
|
12
|
+
*
|
|
13
|
+
* Constraints may come from decorators or JSDoc tags. If both a decorator
|
|
14
|
+
* and a JSDoc tag specify the same constraint, that is a lint error.
|
|
15
|
+
*/
|
|
16
|
+
import { ESLintUtils } from "@typescript-eslint/utils";
|
|
17
|
+
import { findDecorator, getDecoratorLiteralArg } from "../utils/decorator-utils.js";
|
|
18
|
+
import { getJSDocConstraints, findJSDocConstraint } from "../utils/jsdoc-utils.js";
|
|
19
|
+
const createRule = ESLintUtils.RuleCreator((name) => `https://formspec.dev/eslint-plugin/rules/${name}`);
|
|
20
|
+
export const consistentConstraints = createRule({
|
|
21
|
+
name: "consistent-constraints",
|
|
22
|
+
meta: {
|
|
23
|
+
type: "problem",
|
|
24
|
+
docs: {
|
|
25
|
+
description: "Ensures constraint decorator pairs have valid ranges and don't conflict",
|
|
26
|
+
},
|
|
27
|
+
messages: {
|
|
28
|
+
minimumGreaterThanMaximum: "@Minimum({{min}}) is greater than @Maximum({{max}}). Minimum must be less than or equal to Maximum.",
|
|
29
|
+
exclusiveMinGreaterOrEqualMax: "@ExclusiveMinimum({{min}}) must be less than @ExclusiveMaximum({{max}}).",
|
|
30
|
+
minLengthGreaterThanMaxLength: "@MinLength({{min}}) is greater than @MaxLength({{max}}). MinLength must be less than or equal to MaxLength.",
|
|
31
|
+
conflictingMinimumBounds: "Field has both @Minimum and @ExclusiveMinimum. Use only one lower bound constraint.",
|
|
32
|
+
conflictingMaximumBounds: "Field has both @Maximum and @ExclusiveMaximum. Use only one upper bound constraint.",
|
|
33
|
+
exclusiveMaxLessOrEqualMin: "@ExclusiveMaximum({{max}}) must be greater than @Minimum({{min}}).",
|
|
34
|
+
maximumLessOrEqualExclusiveMin: "@Maximum({{max}}) must be greater than @ExclusiveMinimum({{min}}).",
|
|
35
|
+
duplicateConstraintSource: "Constraint '{{name}}' is specified via both a decorator and a TSDoc tag. Use one or the other.",
|
|
36
|
+
},
|
|
37
|
+
schema: [],
|
|
38
|
+
},
|
|
39
|
+
defaultOptions: [],
|
|
40
|
+
create(context) {
|
|
41
|
+
const sourceCode = context.sourceCode;
|
|
42
|
+
return {
|
|
43
|
+
PropertyDefinition(node) {
|
|
44
|
+
const jsdocConstraints = getJSDocConstraints(node, sourceCode);
|
|
45
|
+
// Track which constraints have already been reported as duplicates
|
|
46
|
+
const reportedDuplicates = new Set();
|
|
47
|
+
/**
|
|
48
|
+
* Gets a numeric constraint value from either a decorator or a JSDoc tag.
|
|
49
|
+
* Reports a conflict if both sources provide the same constraint.
|
|
50
|
+
* Returns null if the constraint is absent, ambiguous, or non-numeric.
|
|
51
|
+
*/
|
|
52
|
+
function getConstraintValue(name) {
|
|
53
|
+
const dec = findDecorator(node, name);
|
|
54
|
+
const jsdoc = findJSDocConstraint(jsdocConstraints, name);
|
|
55
|
+
// Conflict: same constraint from both sources
|
|
56
|
+
if (dec && jsdoc) {
|
|
57
|
+
reportedDuplicates.add(name);
|
|
58
|
+
context.report({
|
|
59
|
+
node: dec.node,
|
|
60
|
+
messageId: "duplicateConstraintSource",
|
|
61
|
+
data: { name },
|
|
62
|
+
});
|
|
63
|
+
return null; // Don't validate range when ambiguous
|
|
64
|
+
}
|
|
65
|
+
if (dec) {
|
|
66
|
+
const val = getDecoratorLiteralArg(dec);
|
|
67
|
+
return typeof val === "number" ? { value: val, loc: dec.node.loc } : null;
|
|
68
|
+
}
|
|
69
|
+
if (jsdoc && typeof jsdoc.value === "number") {
|
|
70
|
+
return { value: jsdoc.value, loc: jsdoc.comment.loc };
|
|
71
|
+
}
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Checks whether a constraint is present from either source.
|
|
76
|
+
* Only reports duplicate source if not already reported by getConstraintValue.
|
|
77
|
+
*/
|
|
78
|
+
function hasConstraint(name) {
|
|
79
|
+
const dec = findDecorator(node, name);
|
|
80
|
+
const jsdoc = findJSDocConstraint(jsdocConstraints, name);
|
|
81
|
+
if (dec && jsdoc && !reportedDuplicates.has(name)) {
|
|
82
|
+
reportedDuplicates.add(name);
|
|
83
|
+
context.report({
|
|
84
|
+
node: dec.node,
|
|
85
|
+
messageId: "duplicateConstraintSource",
|
|
86
|
+
data: { name },
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
if (dec)
|
|
90
|
+
return { present: true, loc: dec.node.loc };
|
|
91
|
+
if (jsdoc)
|
|
92
|
+
return { present: true, loc: jsdoc.comment.loc };
|
|
93
|
+
return { present: false, loc: null };
|
|
94
|
+
}
|
|
95
|
+
// Check @Minimum/@Maximum range
|
|
96
|
+
const minimum = getConstraintValue("Minimum");
|
|
97
|
+
const maximum = getConstraintValue("Maximum");
|
|
98
|
+
if (minimum && maximum && minimum.value > maximum.value) {
|
|
99
|
+
context.report({
|
|
100
|
+
loc: minimum.loc,
|
|
101
|
+
messageId: "minimumGreaterThanMaximum",
|
|
102
|
+
data: {
|
|
103
|
+
min: String(minimum.value),
|
|
104
|
+
max: String(maximum.value),
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
// Check @ExclusiveMinimum/@ExclusiveMaximum range
|
|
109
|
+
const exclusiveMin = getConstraintValue("ExclusiveMinimum");
|
|
110
|
+
const exclusiveMax = getConstraintValue("ExclusiveMaximum");
|
|
111
|
+
if (exclusiveMin && exclusiveMax && exclusiveMin.value >= exclusiveMax.value) {
|
|
112
|
+
context.report({
|
|
113
|
+
loc: exclusiveMin.loc,
|
|
114
|
+
messageId: "exclusiveMinGreaterOrEqualMax",
|
|
115
|
+
data: {
|
|
116
|
+
min: String(exclusiveMin.value),
|
|
117
|
+
max: String(exclusiveMax.value),
|
|
118
|
+
},
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
// Check @MinLength/@MaxLength range
|
|
122
|
+
const minLength = getConstraintValue("MinLength");
|
|
123
|
+
const maxLength = getConstraintValue("MaxLength");
|
|
124
|
+
if (minLength && maxLength && minLength.value > maxLength.value) {
|
|
125
|
+
context.report({
|
|
126
|
+
loc: minLength.loc,
|
|
127
|
+
messageId: "minLengthGreaterThanMaxLength",
|
|
128
|
+
data: {
|
|
129
|
+
min: String(minLength.value),
|
|
130
|
+
max: String(maxLength.value),
|
|
131
|
+
},
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
// Check conflicting bound types: @Minimum + @ExclusiveMinimum
|
|
135
|
+
const hasMinimum = hasConstraint("Minimum");
|
|
136
|
+
const hasExclusiveMinimum = hasConstraint("ExclusiveMinimum");
|
|
137
|
+
if (hasMinimum.present && hasExclusiveMinimum.present) {
|
|
138
|
+
context.report({
|
|
139
|
+
loc: hasExclusiveMinimum.loc ?? node.loc,
|
|
140
|
+
messageId: "conflictingMinimumBounds",
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
// Check conflicting bound types: @Maximum + @ExclusiveMaximum
|
|
144
|
+
const hasMaximum = hasConstraint("Maximum");
|
|
145
|
+
const hasExclusiveMaximum = hasConstraint("ExclusiveMaximum");
|
|
146
|
+
if (hasMaximum.present && hasExclusiveMaximum.present) {
|
|
147
|
+
context.report({
|
|
148
|
+
loc: hasExclusiveMaximum.loc ?? node.loc,
|
|
149
|
+
messageId: "conflictingMaximumBounds",
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
// Check @ExclusiveMinimum(m) + @Maximum(n) where n <= m
|
|
153
|
+
if (exclusiveMin && maximum && maximum.value <= exclusiveMin.value) {
|
|
154
|
+
context.report({
|
|
155
|
+
loc: maximum.loc,
|
|
156
|
+
messageId: "maximumLessOrEqualExclusiveMin",
|
|
157
|
+
data: {
|
|
158
|
+
min: String(exclusiveMin.value),
|
|
159
|
+
max: String(maximum.value),
|
|
160
|
+
},
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
// Check @ExclusiveMaximum(n) where n <= @Minimum(m)
|
|
164
|
+
if (minimum && exclusiveMax && exclusiveMax.value <= minimum.value) {
|
|
165
|
+
context.report({
|
|
166
|
+
loc: exclusiveMax.loc,
|
|
167
|
+
messageId: "exclusiveMaxLessOrEqualMin",
|
|
168
|
+
data: {
|
|
169
|
+
min: String(minimum.value),
|
|
170
|
+
max: String(exclusiveMax.value),
|
|
171
|
+
},
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
};
|
|
176
|
+
},
|
|
177
|
+
});
|
|
178
|
+
//# sourceMappingURL=consistent-constraints.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consistent-constraints.js","sourceRoot":"","sources":["../../src/rules/consistent-constraints.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"allowed-field-types.d.ts","sourceRoot":"","sources":["../../../src/rules/constraints/allowed-field-types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,WAAW,EAAkB,MAAM,0BAA0B,CAAC;AAEvE,OAAO,EAEL,KAAK,oBAAoB,EAE1B,MAAM,+BAA+B,CAAC;AAwCvC,MAAM,MAAM,OAAO,GAAG,CAAC,oBAAoB,CAAC,CAAC;AAE7C,eAAO,MAAM,iBAAiB;;
|
|
1
|
+
{"version":3,"file":"allowed-field-types.d.ts","sourceRoot":"","sources":["../../../src/rules/constraints/allowed-field-types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,WAAW,EAAkB,MAAM,0BAA0B,CAAC;AAEvE,OAAO,EAEL,KAAK,oBAAoB,EAE1B,MAAM,+BAA+B,CAAC;AAwCvC,MAAM,MAAM,OAAO,GAAG,CAAC,oBAAoB,CAAC,CAAC;AAE7C,eAAO,MAAM,iBAAiB;;CAsF5B,CAAC"}
|
|
@@ -69,6 +69,7 @@ export const allowedFieldTypes = createRule({
|
|
|
69
69
|
},
|
|
70
70
|
defaultOptions: [{}],
|
|
71
71
|
create(context) {
|
|
72
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- RuleTester may not apply defaultOptions
|
|
72
73
|
const constraints = context.options[0] ?? {};
|
|
73
74
|
return {
|
|
74
75
|
CallExpression(node) {
|
|
@@ -102,7 +103,7 @@ export const allowedFieldTypes = createRule({
|
|
|
102
103
|
}
|
|
103
104
|
// Extract field name from first argument
|
|
104
105
|
const fieldName = extractFieldName(node.arguments[0]);
|
|
105
|
-
const fieldTypeName = FIELD_TYPE_NAMES[methodName]
|
|
106
|
+
const fieldTypeName = FIELD_TYPE_NAMES[methodName] ?? `${methodName} field`;
|
|
106
107
|
context.report({
|
|
107
108
|
node: node.callee.property,
|
|
108
109
|
messageId: "disallowedFieldType",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"allowed-field-types.js","sourceRoot":"","sources":["../../../src/rules/constraints/allowed-field-types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAEvE,OAAO,EACL,oBAAoB,GAGrB,MAAM,+BAA+B,CAAC;AAEvC,MAAM,UAAU,GAAG,WAAW,CAAC,WAAW,CACxC,CAAC,IAAI,EAAE,EAAE,CAAC,4CAA4C,IAAI,EAAE,CAC7D,CAAC;AAIF;;GAEG;AACH,MAAM,oBAAoB,GAA+C;IACvE,IAAI,EAAE,MAAM;IACZ,MAAM,EAAE,QAAQ;IAChB,OAAO,EAAE,SAAS;IAClB,IAAI,EAAE,YAAY;IAClB,WAAW,EAAE,aAAa;IAC1B,aAAa,EAAE,eAAe;IAC9B,KAAK,EAAE,OAAO;IACd,eAAe,EAAE,OAAO;IACxB,MAAM,EAAE,QAAQ;IAChB,gBAAgB,EAAE,QAAQ;CAC3B,CAAC;AAEF;;GAEG;AACH,MAAM,gBAAgB,GAA2B;IAC/C,IAAI,EAAE,YAAY;IAClB,MAAM,EAAE,cAAc;IACtB,OAAO,EAAE,eAAe;IACxB,IAAI,EAAE,mBAAmB;IACzB,WAAW,EAAE,oBAAoB;IACjC,aAAa,EAAE,sBAAsB;IACrC,KAAK,EAAE,aAAa;IACpB,eAAe,EAAE,aAAa;IAC9B,MAAM,EAAE,cAAc;IACtB,gBAAgB,EAAE,cAAc;CACjC,CAAC;AAIF,MAAM,CAAC,MAAM,iBAAiB,GAAG,UAAU,CAAsB;IAC/D,IAAI,EAAE,iCAAiC;IACvC,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACJ,WAAW,
|
|
1
|
+
{"version":3,"file":"allowed-field-types.js","sourceRoot":"","sources":["../../../src/rules/constraints/allowed-field-types.ts"],"names":[],"mappings":"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"}
|
|
@@ -34,6 +34,7 @@ export const allowedLayouts = createRule({
|
|
|
34
34
|
},
|
|
35
35
|
defaultOptions: [{}],
|
|
36
36
|
create(context) {
|
|
37
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- RuleTester may not apply defaultOptions
|
|
37
38
|
const constraints = context.options[0] ?? {};
|
|
38
39
|
return {
|
|
39
40
|
CallExpression(node) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"allowed-layouts.js","sourceRoot":"","sources":["../../../src/rules/constraints/allowed-layouts.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAEvE,OAAO,EAAE,mBAAmB,EAA0B,MAAM,+BAA+B,CAAC;AAE5F,MAAM,UAAU,GAAG,WAAW,CAAC,WAAW,CACxC,CAAC,IAAI,EAAE,EAAE,CAAC,4CAA4C,IAAI,EAAE,CAC7D,CAAC;AAMF,MAAM,CAAC,MAAM,cAAc,GAAG,UAAU,CAAsB;IAC5D,IAAI,EAAE,6BAA6B;IACnC,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACJ,WAAW,EACT,iGAAiG;SACpG;QACD,QAAQ,EAAE;YACR,eAAe,EACb,wFAAwF;YAC1F,qBAAqB,
|
|
1
|
+
{"version":3,"file":"allowed-layouts.js","sourceRoot":"","sources":["../../../src/rules/constraints/allowed-layouts.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule: decorator-allowed-field-types
|
|
3
|
+
*
|
|
4
|
+
* Configurable rule restricting TypeScript field types on decorated properties.
|
|
5
|
+
* Only applies to properties that have at least one FormSpec decorator.
|
|
6
|
+
*
|
|
7
|
+
* Config example:
|
|
8
|
+
* "@formspec/decorator-allowed-field-types": ["error", { allow: ["string", "number", "boolean", "enum"] }]
|
|
9
|
+
*/
|
|
10
|
+
import { ESLintUtils } from "@typescript-eslint/utils";
|
|
11
|
+
export interface DecoratorAllowedFieldTypesOptions {
|
|
12
|
+
allow: string[];
|
|
13
|
+
}
|
|
14
|
+
export declare const decoratorAllowedFieldTypes: ESLintUtils.RuleModule<"disallowedFieldType", [DecoratorAllowedFieldTypesOptions], unknown, ESLintUtils.RuleListener> & {
|
|
15
|
+
name: string;
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=decorator-allowed-field-types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decorator-allowed-field-types.d.ts","sourceRoot":"","sources":["../../src/rules/decorator-allowed-field-types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,WAAW,EAAkB,MAAM,0BAA0B,CAAC;AAUvE,MAAM,WAAW,iCAAiC;IAChD,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,eAAO,MAAM,0BAA0B;;CA+DrC,CAAC"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule: decorator-allowed-field-types
|
|
3
|
+
*
|
|
4
|
+
* Configurable rule restricting TypeScript field types on decorated properties.
|
|
5
|
+
* Only applies to properties that have at least one FormSpec decorator.
|
|
6
|
+
*
|
|
7
|
+
* Config example:
|
|
8
|
+
* "@formspec/decorator-allowed-field-types": ["error", { allow: ["string", "number", "boolean", "enum"] }]
|
|
9
|
+
*/
|
|
10
|
+
import { ESLintUtils, AST_NODE_TYPES } from "@typescript-eslint/utils";
|
|
11
|
+
import { getFormSpecDecorators } from "../utils/decorator-utils.js";
|
|
12
|
+
import { getPropertyType, getFieldTypeCategory } from "../utils/type-utils.js";
|
|
13
|
+
const createRule = ESLintUtils.RuleCreator((name) => `https://formspec.dev/eslint-plugin/rules/${name}`);
|
|
14
|
+
export const decoratorAllowedFieldTypes = createRule({
|
|
15
|
+
name: "decorator-allowed-field-types",
|
|
16
|
+
meta: {
|
|
17
|
+
type: "problem",
|
|
18
|
+
docs: {
|
|
19
|
+
description: "Restricts TypeScript field types on decorated properties to an allowed list",
|
|
20
|
+
},
|
|
21
|
+
messages: {
|
|
22
|
+
disallowedFieldType: "Field '{{field}}' has type '{{actualType}}' (category: {{category}}), which is not in the allowed list: [{{allowed}}]",
|
|
23
|
+
},
|
|
24
|
+
schema: [
|
|
25
|
+
{
|
|
26
|
+
type: "object",
|
|
27
|
+
properties: {
|
|
28
|
+
allow: {
|
|
29
|
+
type: "array",
|
|
30
|
+
items: { type: "string" },
|
|
31
|
+
minItems: 1,
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
required: ["allow"],
|
|
35
|
+
additionalProperties: false,
|
|
36
|
+
},
|
|
37
|
+
],
|
|
38
|
+
},
|
|
39
|
+
defaultOptions: [{ allow: ["string", "number", "boolean", "union"] }],
|
|
40
|
+
create(context, [options]) {
|
|
41
|
+
const services = ESLintUtils.getParserServices(context);
|
|
42
|
+
const checker = services.program.getTypeChecker();
|
|
43
|
+
const allowedSet = new Set(options.allow);
|
|
44
|
+
return {
|
|
45
|
+
PropertyDefinition(node) {
|
|
46
|
+
const decorators = getFormSpecDecorators(node);
|
|
47
|
+
if (decorators.length === 0)
|
|
48
|
+
return;
|
|
49
|
+
const type = getPropertyType(node, services);
|
|
50
|
+
if (!type)
|
|
51
|
+
return;
|
|
52
|
+
const category = getFieldTypeCategory(type, checker);
|
|
53
|
+
if (allowedSet.has(category))
|
|
54
|
+
return;
|
|
55
|
+
const fieldName = node.key.type === AST_NODE_TYPES.Identifier ? node.key.name : "<computed>";
|
|
56
|
+
const actualType = checker.typeToString(type);
|
|
57
|
+
context.report({
|
|
58
|
+
node: node.key,
|
|
59
|
+
messageId: "disallowedFieldType",
|
|
60
|
+
data: {
|
|
61
|
+
field: fieldName,
|
|
62
|
+
actualType,
|
|
63
|
+
category,
|
|
64
|
+
allowed: options.allow.join(", "),
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
//# sourceMappingURL=decorator-allowed-field-types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decorator-allowed-field-types.js","sourceRoot":"","sources":["../../src/rules/decorator-allowed-field-types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AACvE,OAAO,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AACpE,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAE/E,MAAM,UAAU,GAAG,WAAW,CAAC,WAAW,CACxC,CAAC,IAAI,EAAE,EAAE,CAAC,4CAA4C,IAAI,EAAE,CAC7D,CAAC;AAQF,MAAM,CAAC,MAAM,0BAA0B,GAAG,UAAU,CAGlD;IACA,IAAI,EAAE,+BAA+B;IACrC,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACJ,WAAW,EAAE,6EAA6E;SAC3F;QACD,QAAQ,EAAE;YACR,mBAAmB,EACjB,uHAAuH;SAC1H;QACD,MAAM,EAAE;YACN;gBACE,IAAI,EAAE,QAAQ;gBACd,UAAU,EAAE;oBACV,KAAK,EAAE;wBACL,IAAI,EAAE,OAAO;wBACb,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;wBACzB,QAAQ,EAAE,CAAC;qBACZ;iBACF;gBACD,QAAQ,EAAE,CAAC,OAAO,CAAC;gBACnB,oBAAoB,EAAE,KAAK;aAC5B;SACF;KACF;IACD,cAAc,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,CAAC;IACrE,MAAM,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC;QACvB,MAAM,QAAQ,GAAG,WAAW,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC;QACxD,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,cAAc,EAAE,CAAC;QAClD,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAE1C,OAAO;YACL,kBAAkB,CAAC,IAAI;gBACrB,MAAM,UAAU,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC;gBAC/C,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;oBAAE,OAAO;gBAEpC,MAAM,IAAI,GAAG,eAAe,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;gBAC7C,IAAI,CAAC,IAAI;oBAAE,OAAO;gBAElB,MAAM,QAAQ,GAAG,oBAAoB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;gBACrD,IAAI,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC;oBAAE,OAAO;gBAErC,MAAM,SAAS,GACb,IAAI,CAAC,GAAG,CAAC,IAAI,KAAK,cAAc,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC;gBAC7E,MAAM,UAAU,GAAG,OAAO,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;gBAE9C,OAAO,CAAC,MAAM,CAAC;oBACb,IAAI,EAAE,IAAI,CAAC,GAAG;oBACd,SAAS,EAAE,qBAAqB;oBAChC,IAAI,EAAE;wBACJ,KAAK,EAAE,SAAS;wBAChB,UAAU;wBACV,QAAQ;wBACR,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC;qBAClC;iBACF,CAAC,CAAC;YACL,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -2,12 +2,11 @@
|
|
|
2
2
|
* Rule: decorator-field-type-mismatch
|
|
3
3
|
*
|
|
4
4
|
* Ensures FormSpec decorators are applied to fields with compatible types:
|
|
5
|
-
* - @
|
|
6
|
-
* - @
|
|
7
|
-
* - @Placeholder only on string fields
|
|
5
|
+
* - @Minimum/@Maximum/@ExclusiveMinimum/@ExclusiveMaximum only on number fields
|
|
6
|
+
* - @MinLength/@MaxLength/@Pattern only on string fields
|
|
8
7
|
*/
|
|
9
8
|
import { ESLintUtils } from "@typescript-eslint/utils";
|
|
10
|
-
type MessageIds = "
|
|
9
|
+
type MessageIds = "numericOnNonNumber" | "stringOnNonString";
|
|
11
10
|
export declare const decoratorFieldTypeMismatch: ESLintUtils.RuleModule<MessageIds, [], unknown, ESLintUtils.RuleListener> & {
|
|
12
11
|
name: string;
|
|
13
12
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"decorator-field-type-mismatch.d.ts","sourceRoot":"","sources":["../../src/rules/decorator-field-type-mismatch.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"decorator-field-type-mismatch.d.ts","sourceRoot":"","sources":["../../src/rules/decorator-field-type-mismatch.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,WAAW,EAAkB,MAAM,0BAA0B,CAAC;AAiBvE,KAAK,UAAU,GAAG,oBAAoB,GAAG,mBAAmB,CAAC;AAuB7D,eAAO,MAAM,0BAA0B;;CA6FrC,CAAC"}
|