@formspec/eslint-plugin 0.1.0-alpha.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/README.md +217 -0
  2. package/dist/index.d.ts +57 -0
  3. package/dist/index.d.ts.map +1 -0
  4. package/dist/index.js +104 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/rules/decorator-field-type-mismatch.d.ts +15 -0
  7. package/dist/rules/decorator-field-type-mismatch.d.ts.map +1 -0
  8. package/dist/rules/decorator-field-type-mismatch.js +87 -0
  9. package/dist/rules/decorator-field-type-mismatch.js.map +1 -0
  10. package/dist/rules/enum-options-match-type.d.ts +26 -0
  11. package/dist/rules/enum-options-match-type.d.ts.map +1 -0
  12. package/dist/rules/enum-options-match-type.js +115 -0
  13. package/dist/rules/enum-options-match-type.js.map +1 -0
  14. package/dist/rules/index.d.ts +11 -0
  15. package/dist/rules/index.d.ts.map +1 -0
  16. package/dist/rules/index.js +11 -0
  17. package/dist/rules/index.js.map +1 -0
  18. package/dist/rules/min-max-valid-range.d.ts +26 -0
  19. package/dist/rules/min-max-valid-range.d.ts.map +1 -0
  20. package/dist/rules/min-max-valid-range.js +82 -0
  21. package/dist/rules/min-max-valid-range.js.map +1 -0
  22. package/dist/rules/no-conflicting-decorators.d.ts +19 -0
  23. package/dist/rules/no-conflicting-decorators.d.ts.map +1 -0
  24. package/dist/rules/no-conflicting-decorators.js +76 -0
  25. package/dist/rules/no-conflicting-decorators.js.map +1 -0
  26. package/dist/rules/no-duplicate-decorators.d.ts +19 -0
  27. package/dist/rules/no-duplicate-decorators.d.ts.map +1 -0
  28. package/dist/rules/no-duplicate-decorators.js +74 -0
  29. package/dist/rules/no-duplicate-decorators.js.map +1 -0
  30. package/dist/rules/showwhen-field-exists.d.ts +21 -0
  31. package/dist/rules/showwhen-field-exists.d.ts.map +1 -0
  32. package/dist/rules/showwhen-field-exists.js +68 -0
  33. package/dist/rules/showwhen-field-exists.js.map +1 -0
  34. package/dist/rules/showwhen-suggests-optional.d.ts +19 -0
  35. package/dist/rules/showwhen-suggests-optional.d.ts.map +1 -0
  36. package/dist/rules/showwhen-suggests-optional.js +53 -0
  37. package/dist/rules/showwhen-suggests-optional.js.map +1 -0
  38. package/dist/utils/decorator-utils.d.ts +103 -0
  39. package/dist/utils/decorator-utils.d.ts.map +1 -0
  40. package/dist/utils/decorator-utils.js +222 -0
  41. package/dist/utils/decorator-utils.js.map +1 -0
  42. package/dist/utils/index.d.ts +6 -0
  43. package/dist/utils/index.d.ts.map +1 -0
  44. package/dist/utils/index.js +6 -0
  45. package/dist/utils/index.js.map +1 -0
  46. package/dist/utils/type-utils.d.ts +82 -0
  47. package/dist/utils/type-utils.d.ts.map +1 -0
  48. package/dist/utils/type-utils.js +192 -0
  49. package/dist/utils/type-utils.js.map +1 -0
  50. package/package.json +48 -0
@@ -0,0 +1,11 @@
1
+ /**
2
+ * All FormSpec ESLint rules.
3
+ */
4
+ export { decoratorFieldTypeMismatch } from "./decorator-field-type-mismatch.js";
5
+ export { enumOptionsMatchType } from "./enum-options-match-type.js";
6
+ export { showwhenFieldExists } from "./showwhen-field-exists.js";
7
+ export { showwhenSuggestsOptional } from "./showwhen-suggests-optional.js";
8
+ export { minMaxValidRange } from "./min-max-valid-range.js";
9
+ export { noConflictingDecorators } from "./no-conflicting-decorators.js";
10
+ export { noDuplicateDecorators } from "./no-duplicate-decorators.js";
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/rules/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,0BAA0B,EAAE,MAAM,oCAAoC,CAAC;AAChF,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,wBAAwB,EAAE,MAAM,iCAAiC,CAAC;AAC3E,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AACzE,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Rule: min-max-valid-range
3
+ *
4
+ * Ensures @Min value is less than or equal to @Max value when both are present.
5
+ *
6
+ * Valid:
7
+ * @Min(0)
8
+ * @Max(100)
9
+ * value!: number;
10
+ *
11
+ * @Min(5)
12
+ * @Max(5) // Equal is OK
13
+ * value!: number;
14
+ *
15
+ * Invalid:
16
+ * @Min(100)
17
+ * @Max(50) // Min > Max
18
+ * value!: number;
19
+ */
20
+ import { ESLintUtils } from "@typescript-eslint/utils";
21
+ type MessageIds = "minGreaterThanMax" | "minItemsGreaterThanMaxItems";
22
+ export declare const minMaxValidRange: ESLintUtils.RuleModule<MessageIds, [], unknown, ESLintUtils.RuleListener> & {
23
+ name: string;
24
+ };
25
+ export {};
26
+ //# sourceMappingURL=min-max-valid-range.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"min-max-valid-range.d.ts","sourceRoot":"","sources":["../../src/rules/min-max-valid-range.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAOvD,KAAK,UAAU,GAAG,mBAAmB,GAAG,6BAA6B,CAAC;AAEtE,eAAO,MAAM,gBAAgB;;CAsE3B,CAAC"}
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Rule: min-max-valid-range
3
+ *
4
+ * Ensures @Min value is less than or equal to @Max value when both are present.
5
+ *
6
+ * Valid:
7
+ * @Min(0)
8
+ * @Max(100)
9
+ * value!: number;
10
+ *
11
+ * @Min(5)
12
+ * @Max(5) // Equal is OK
13
+ * value!: number;
14
+ *
15
+ * Invalid:
16
+ * @Min(100)
17
+ * @Max(50) // Min > Max
18
+ * value!: number;
19
+ */
20
+ import { ESLintUtils } from "@typescript-eslint/utils";
21
+ import { findDecorator, getDecoratorLiteralArg } from "../utils/decorator-utils.js";
22
+ const createRule = ESLintUtils.RuleCreator((name) => `https://formspec.dev/eslint-plugin/rules/${name}`);
23
+ export const minMaxValidRange = createRule({
24
+ name: "min-max-valid-range",
25
+ meta: {
26
+ type: "problem",
27
+ docs: {
28
+ description: "Ensures @Min/@Max and @MinItems/@MaxItems have valid ranges",
29
+ },
30
+ messages: {
31
+ minGreaterThanMax: "@Min({{min}}) is greater than @Max({{max}}). Min must be less than or equal to Max.",
32
+ minItemsGreaterThanMaxItems: "@MinItems({{min}}) is greater than @MaxItems({{max}}). MinItems must be less than or equal to MaxItems.",
33
+ },
34
+ schema: [],
35
+ },
36
+ defaultOptions: [],
37
+ create(context) {
38
+ return {
39
+ PropertyDefinition(node) {
40
+ // Check @Min/@Max
41
+ const minDecorator = findDecorator(node, "Min");
42
+ const maxDecorator = findDecorator(node, "Max");
43
+ if (minDecorator && maxDecorator) {
44
+ const minValue = getDecoratorLiteralArg(minDecorator);
45
+ const maxValue = getDecoratorLiteralArg(maxDecorator);
46
+ if (typeof minValue === "number" &&
47
+ typeof maxValue === "number" &&
48
+ minValue > maxValue) {
49
+ context.report({
50
+ node: minDecorator.node,
51
+ messageId: "minGreaterThanMax",
52
+ data: {
53
+ min: String(minValue),
54
+ max: String(maxValue),
55
+ },
56
+ });
57
+ }
58
+ }
59
+ // Check @MinItems/@MaxItems
60
+ const minItemsDecorator = findDecorator(node, "MinItems");
61
+ const maxItemsDecorator = findDecorator(node, "MaxItems");
62
+ if (minItemsDecorator && maxItemsDecorator) {
63
+ const minValue = getDecoratorLiteralArg(minItemsDecorator);
64
+ const maxValue = getDecoratorLiteralArg(maxItemsDecorator);
65
+ if (typeof minValue === "number" &&
66
+ typeof maxValue === "number" &&
67
+ minValue > maxValue) {
68
+ context.report({
69
+ node: minItemsDecorator.node,
70
+ messageId: "minItemsGreaterThanMaxItems",
71
+ data: {
72
+ min: String(minValue),
73
+ max: String(maxValue),
74
+ },
75
+ });
76
+ }
77
+ }
78
+ },
79
+ };
80
+ },
81
+ });
82
+ //# sourceMappingURL=min-max-valid-range.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"min-max-valid-range.js","sourceRoot":"","sources":["../../src/rules/min-max-valid-range.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AAEpF,MAAM,UAAU,GAAG,WAAW,CAAC,WAAW,CACxC,CAAC,IAAI,EAAE,EAAE,CAAC,4CAA4C,IAAI,EAAE,CAC7D,CAAC;AAIF,MAAM,CAAC,MAAM,gBAAgB,GAAG,UAAU,CAAiB;IACzD,IAAI,EAAE,qBAAqB;IAC3B,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACJ,WAAW,EACT,6DAA6D;SAChE;QACD,QAAQ,EAAE;YACR,iBAAiB,EACf,qFAAqF;YACvF,2BAA2B,EACzB,yGAAyG;SAC5G;QACD,MAAM,EAAE,EAAE;KACX;IACD,cAAc,EAAE,EAAE;IAClB,MAAM,CAAC,OAAO;QACZ,OAAO;YACL,kBAAkB,CAAC,IAAI;gBACrB,kBAAkB;gBAClB,MAAM,YAAY,GAAG,aAAa,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;gBAChD,MAAM,YAAY,GAAG,aAAa,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;gBAEhD,IAAI,YAAY,IAAI,YAAY,EAAE,CAAC;oBACjC,MAAM,QAAQ,GAAG,sBAAsB,CAAC,YAAY,CAAC,CAAC;oBACtD,MAAM,QAAQ,GAAG,sBAAsB,CAAC,YAAY,CAAC,CAAC;oBAEtD,IACE,OAAO,QAAQ,KAAK,QAAQ;wBAC5B,OAAO,QAAQ,KAAK,QAAQ;wBAC5B,QAAQ,GAAG,QAAQ,EACnB,CAAC;wBACD,OAAO,CAAC,MAAM,CAAC;4BACb,IAAI,EAAE,YAAY,CAAC,IAAI;4BACvB,SAAS,EAAE,mBAAmB;4BAC9B,IAAI,EAAE;gCACJ,GAAG,EAAE,MAAM,CAAC,QAAQ,CAAC;gCACrB,GAAG,EAAE,MAAM,CAAC,QAAQ,CAAC;6BACtB;yBACF,CAAC,CAAC;oBACL,CAAC;gBACH,CAAC;gBAED,4BAA4B;gBAC5B,MAAM,iBAAiB,GAAG,aAAa,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;gBAC1D,MAAM,iBAAiB,GAAG,aAAa,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;gBAE1D,IAAI,iBAAiB,IAAI,iBAAiB,EAAE,CAAC;oBAC3C,MAAM,QAAQ,GAAG,sBAAsB,CAAC,iBAAiB,CAAC,CAAC;oBAC3D,MAAM,QAAQ,GAAG,sBAAsB,CAAC,iBAAiB,CAAC,CAAC;oBAE3D,IACE,OAAO,QAAQ,KAAK,QAAQ;wBAC5B,OAAO,QAAQ,KAAK,QAAQ;wBAC5B,QAAQ,GAAG,QAAQ,EACnB,CAAC;wBACD,OAAO,CAAC,MAAM,CAAC;4BACb,IAAI,EAAE,iBAAiB,CAAC,IAAI;4BAC5B,SAAS,EAAE,6BAA6B;4BACxC,IAAI,EAAE;gCACJ,GAAG,EAAE,MAAM,CAAC,QAAQ,CAAC;gCACrB,GAAG,EAAE,MAAM,CAAC,QAAQ,CAAC;6BACtB;yBACF,CAAC,CAAC;oBACL,CAAC;gBACH,CAAC;YACH,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC,CAAC"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Rule: no-conflicting-decorators
3
+ *
4
+ * Ensures a field doesn't have decorators that imply conflicting types.
5
+ *
6
+ * Invalid:
7
+ * @Min(0) // Implies number
8
+ * @Placeholder("x") // Implies string
9
+ * field!: string;
10
+ *
11
+ * @MinItems(1) // Implies array
12
+ * @Min(0) // Implies number
13
+ * field!: number[];
14
+ */
15
+ import { ESLintUtils } from "@typescript-eslint/utils";
16
+ export declare const noConflictingDecorators: ESLintUtils.RuleModule<"conflictingDecorators", [], unknown, ESLintUtils.RuleListener> & {
17
+ name: string;
18
+ };
19
+ //# sourceMappingURL=no-conflicting-decorators.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-conflicting-decorators.d.ts","sourceRoot":"","sources":["../../src/rules/no-conflicting-decorators.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAavD,eAAO,MAAM,uBAAuB;;CA6DlC,CAAC"}
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Rule: no-conflicting-decorators
3
+ *
4
+ * Ensures a field doesn't have decorators that imply conflicting types.
5
+ *
6
+ * Invalid:
7
+ * @Min(0) // Implies number
8
+ * @Placeholder("x") // Implies string
9
+ * field!: string;
10
+ *
11
+ * @MinItems(1) // Implies array
12
+ * @Min(0) // Implies number
13
+ * field!: number[];
14
+ */
15
+ import { ESLintUtils } from "@typescript-eslint/utils";
16
+ import { getFormSpecDecorators, DECORATOR_TYPE_HINTS, } from "../utils/decorator-utils.js";
17
+ const createRule = ESLintUtils.RuleCreator((name) => `https://formspec.dev/eslint-plugin/rules/${name}`);
18
+ export const noConflictingDecorators = createRule({
19
+ name: "no-conflicting-decorators",
20
+ meta: {
21
+ type: "problem",
22
+ docs: {
23
+ description: "Ensures a field doesn't have decorators that imply conflicting types",
24
+ },
25
+ messages: {
26
+ conflictingDecorators: "Field has conflicting decorators: @{{decorator1}} implies {{type1}}, but @{{decorator2}} implies {{type2}}",
27
+ },
28
+ schema: [],
29
+ },
30
+ defaultOptions: [],
31
+ create(context) {
32
+ return {
33
+ PropertyDefinition(node) {
34
+ const decorators = getFormSpecDecorators(node);
35
+ if (decorators.length < 2)
36
+ return;
37
+ // Collect type hints from decorators
38
+ const typeHints = [];
39
+ for (const decorator of decorators) {
40
+ // Only process decorators that have type hints
41
+ if (decorator.name in DECORATOR_TYPE_HINTS) {
42
+ const decoratorName = decorator.name;
43
+ const typeHint = DECORATOR_TYPE_HINTS[decoratorName];
44
+ typeHints.push({ decorator: decoratorName, type: typeHint });
45
+ }
46
+ }
47
+ // Check for conflicts
48
+ if (typeHints.length < 2)
49
+ return;
50
+ const firstHint = typeHints[0];
51
+ if (!firstHint)
52
+ return;
53
+ for (let i = 1; i < typeHints.length; i++) {
54
+ const hint = typeHints[i];
55
+ if (!hint)
56
+ continue;
57
+ if (hint.type !== firstHint.type) {
58
+ context.report({
59
+ node: node.key,
60
+ messageId: "conflictingDecorators",
61
+ data: {
62
+ decorator1: firstHint.decorator,
63
+ type1: firstHint.type,
64
+ decorator2: hint.decorator,
65
+ type2: hint.type,
66
+ },
67
+ });
68
+ // Only report once per field
69
+ break;
70
+ }
71
+ }
72
+ },
73
+ };
74
+ },
75
+ });
76
+ //# sourceMappingURL=no-conflicting-decorators.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-conflicting-decorators.js","sourceRoot":"","sources":["../../src/rules/no-conflicting-decorators.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EACL,qBAAqB,EACrB,oBAAoB,GAErB,MAAM,6BAA6B,CAAC;AAErC,MAAM,UAAU,GAAG,WAAW,CAAC,WAAW,CACxC,CAAC,IAAI,EAAE,EAAE,CAAC,4CAA4C,IAAI,EAAE,CAC7D,CAAC;AAIF,MAAM,CAAC,MAAM,uBAAuB,GAAG,UAAU,CAAiB;IAChE,IAAI,EAAE,2BAA2B;IACjC,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACJ,WAAW,EACT,sEAAsE;SACzE;QACD,QAAQ,EAAE;YACR,qBAAqB,EACnB,4GAA4G;SAC/G;QACD,MAAM,EAAE,EAAE;KACX;IACD,cAAc,EAAE,EAAE;IAClB,MAAM,CAAC,OAAO;QACZ,OAAO;YACL,kBAAkB,CAAC,IAAI;gBACrB,MAAM,UAAU,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC;gBAC/C,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC;oBAAE,OAAO;gBAElC,qCAAqC;gBACrC,MAAM,SAAS,GAA0C,EAAE,CAAC;gBAE5D,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;oBACnC,+CAA+C;oBAC/C,IAAI,SAAS,CAAC,IAAI,IAAI,oBAAoB,EAAE,CAAC;wBAC3C,MAAM,aAAa,GAAG,SAAS,CAAC,IAAyB,CAAC;wBAC1D,MAAM,QAAQ,GAAG,oBAAoB,CAAC,aAAa,CAAC,CAAC;wBACrD,SAAS,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,aAAa,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;oBAC/D,CAAC;gBACH,CAAC;gBAED,sBAAsB;gBACtB,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC;oBAAE,OAAO;gBAEjC,MAAM,SAAS,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;gBAC/B,IAAI,CAAC,SAAS;oBAAE,OAAO;gBAEvB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;oBAC1C,MAAM,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;oBAC1B,IAAI,CAAC,IAAI;wBAAE,SAAS;oBAEpB,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC,IAAI,EAAE,CAAC;wBACjC,OAAO,CAAC,MAAM,CAAC;4BACb,IAAI,EAAE,IAAI,CAAC,GAAG;4BACd,SAAS,EAAE,uBAAuB;4BAClC,IAAI,EAAE;gCACJ,UAAU,EAAE,SAAS,CAAC,SAAS;gCAC/B,KAAK,EAAE,SAAS,CAAC,IAAI;gCACrB,UAAU,EAAE,IAAI,CAAC,SAAS;gCAC1B,KAAK,EAAE,IAAI,CAAC,IAAI;6BACjB;yBACF,CAAC,CAAC;wBACH,6BAA6B;wBAC7B,MAAM;oBACR,CAAC;gBACH,CAAC;YACH,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC,CAAC"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Rule: no-duplicate-decorators
3
+ *
4
+ * Ensures a field doesn't have the same decorator applied multiple times.
5
+ *
6
+ * Invalid:
7
+ * @Label("First")
8
+ * @Label("Second") // Duplicate
9
+ * field!: string;
10
+ *
11
+ * @EnumOptions(["a", "b"])
12
+ * @EnumOptions(["x", "y"]) // Duplicate
13
+ * field!: string;
14
+ */
15
+ import { ESLintUtils } from "@typescript-eslint/utils";
16
+ export declare const noDuplicateDecorators: ESLintUtils.RuleModule<"duplicateDecorator", [], unknown, ESLintUtils.RuleListener> & {
17
+ name: string;
18
+ };
19
+ //# sourceMappingURL=no-duplicate-decorators.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-duplicate-decorators.d.ts","sourceRoot":"","sources":["../../src/rules/no-duplicate-decorators.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAyBvD,eAAO,MAAM,qBAAqB;;CA0ChC,CAAC"}
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Rule: no-duplicate-decorators
3
+ *
4
+ * Ensures a field doesn't have the same decorator applied multiple times.
5
+ *
6
+ * Invalid:
7
+ * @Label("First")
8
+ * @Label("Second") // Duplicate
9
+ * field!: string;
10
+ *
11
+ * @EnumOptions(["a", "b"])
12
+ * @EnumOptions(["x", "y"]) // Duplicate
13
+ * field!: string;
14
+ */
15
+ import { ESLintUtils } from "@typescript-eslint/utils";
16
+ import { getFormSpecDecorators } from "../utils/decorator-utils.js";
17
+ const createRule = ESLintUtils.RuleCreator((name) => `https://formspec.dev/eslint-plugin/rules/${name}`);
18
+ /**
19
+ * Decorators that should only appear once per field.
20
+ */
21
+ const SINGLE_USE_DECORATORS = new Set([
22
+ "Label",
23
+ "Placeholder",
24
+ "Optional",
25
+ "Min",
26
+ "Max",
27
+ "MinItems",
28
+ "MaxItems",
29
+ "EnumOptions",
30
+ "Group",
31
+ "ShowWhen",
32
+ ]);
33
+ export const noDuplicateDecorators = createRule({
34
+ name: "no-duplicate-decorators",
35
+ meta: {
36
+ type: "problem",
37
+ docs: {
38
+ description: "Ensures a field doesn't have the same decorator applied multiple times",
39
+ },
40
+ messages: {
41
+ duplicateDecorator: "Duplicate @{{decorator}} decorator. Each decorator should only appear once per field.",
42
+ },
43
+ schema: [],
44
+ },
45
+ defaultOptions: [],
46
+ create(context) {
47
+ return {
48
+ PropertyDefinition(node) {
49
+ const decorators = getFormSpecDecorators(node);
50
+ if (decorators.length < 2)
51
+ return;
52
+ // Track seen decorators
53
+ const seen = new Map();
54
+ for (const decorator of decorators) {
55
+ if (!SINGLE_USE_DECORATORS.has(decorator.name))
56
+ continue;
57
+ if (seen.has(decorator.name)) {
58
+ context.report({
59
+ node: decorator.node,
60
+ messageId: "duplicateDecorator",
61
+ data: {
62
+ decorator: decorator.name,
63
+ },
64
+ });
65
+ }
66
+ else {
67
+ seen.set(decorator.name, true);
68
+ }
69
+ }
70
+ },
71
+ };
72
+ },
73
+ });
74
+ //# sourceMappingURL=no-duplicate-decorators.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-duplicate-decorators.js","sourceRoot":"","sources":["../../src/rules/no-duplicate-decorators.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AAEpE,MAAM,UAAU,GAAG,WAAW,CAAC,WAAW,CACxC,CAAC,IAAI,EAAE,EAAE,CAAC,4CAA4C,IAAI,EAAE,CAC7D,CAAC;AAIF;;GAEG;AACH,MAAM,qBAAqB,GAAG,IAAI,GAAG,CAAC;IACpC,OAAO;IACP,aAAa;IACb,UAAU;IACV,KAAK;IACL,KAAK;IACL,UAAU;IACV,UAAU;IACV,aAAa;IACb,OAAO;IACP,UAAU;CACX,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,qBAAqB,GAAG,UAAU,CAAiB;IAC9D,IAAI,EAAE,yBAAyB;IAC/B,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACJ,WAAW,EACT,wEAAwE;SAC3E;QACD,QAAQ,EAAE;YACR,kBAAkB,EAChB,uFAAuF;SAC1F;QACD,MAAM,EAAE,EAAE;KACX;IACD,cAAc,EAAE,EAAE;IAClB,MAAM,CAAC,OAAO;QACZ,OAAO;YACL,kBAAkB,CAAC,IAAI;gBACrB,MAAM,UAAU,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC;gBAC/C,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC;oBAAE,OAAO;gBAElC,wBAAwB;gBACxB,MAAM,IAAI,GAAG,IAAI,GAAG,EAAmB,CAAC;gBAExC,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;oBACnC,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC;wBAAE,SAAS;oBAEzD,IAAI,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;wBAC7B,OAAO,CAAC,MAAM,CAAC;4BACb,IAAI,EAAE,SAAS,CAAC,IAAI;4BACpB,SAAS,EAAE,oBAAoB;4BAC/B,IAAI,EAAE;gCACJ,SAAS,EAAE,SAAS,CAAC,IAAI;6BAC1B;yBACF,CAAC,CAAC;oBACL,CAAC;yBAAM,CAAC;wBACN,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;oBACjC,CAAC;gBACH,CAAC;YACH,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC,CAAC"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Rule: showwhen-field-exists
3
+ *
4
+ * Ensures @ShowWhen references a field that exists in the same class.
5
+ *
6
+ * Valid:
7
+ * @EnumOptions(["a", "b"])
8
+ * type!: "a" | "b";
9
+ *
10
+ * @ShowWhen({ _predicate: "equals", field: "type", value: "a" })
11
+ * conditionalField?: string;
12
+ *
13
+ * Invalid:
14
+ * @ShowWhen({ _predicate: "equals", field: "nonexistent", value: "x" })
15
+ * field?: string; // "nonexistent" doesn't exist
16
+ */
17
+ import { ESLintUtils } from "@typescript-eslint/utils";
18
+ export declare const showwhenFieldExists: ESLintUtils.RuleModule<"fieldDoesNotExist", [], unknown, ESLintUtils.RuleListener> & {
19
+ name: string;
20
+ };
21
+ //# sourceMappingURL=showwhen-field-exists.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"showwhen-field-exists.d.ts","sourceRoot":"","sources":["../../src/rules/showwhen-field-exists.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,WAAW,EAAkB,MAAM,0BAA0B,CAAC;AAavE,eAAO,MAAM,mBAAmB;;CAqD9B,CAAC"}
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Rule: showwhen-field-exists
3
+ *
4
+ * Ensures @ShowWhen references a field that exists in the same class.
5
+ *
6
+ * Valid:
7
+ * @EnumOptions(["a", "b"])
8
+ * type!: "a" | "b";
9
+ *
10
+ * @ShowWhen({ _predicate: "equals", field: "type", value: "a" })
11
+ * conditionalField?: string;
12
+ *
13
+ * Invalid:
14
+ * @ShowWhen({ _predicate: "equals", field: "nonexistent", value: "x" })
15
+ * field?: string; // "nonexistent" doesn't exist
16
+ */
17
+ import { ESLintUtils, AST_NODE_TYPES } from "@typescript-eslint/utils";
18
+ import { findDecorator, getShowWhenField, getClassPropertyNames, } from "../utils/decorator-utils.js";
19
+ const createRule = ESLintUtils.RuleCreator((name) => `https://formspec.dev/eslint-plugin/rules/${name}`);
20
+ export const showwhenFieldExists = createRule({
21
+ name: "showwhen-field-exists",
22
+ meta: {
23
+ type: "problem",
24
+ docs: {
25
+ description: "Ensures @ShowWhen references a field that exists in the same class",
26
+ },
27
+ messages: {
28
+ fieldDoesNotExist: "@ShowWhen references field '{{referencedField}}' which does not exist in this class",
29
+ },
30
+ schema: [],
31
+ },
32
+ defaultOptions: [],
33
+ create(context) {
34
+ return {
35
+ PropertyDefinition(node) {
36
+ const showWhenDecorator = findDecorator(node, "ShowWhen");
37
+ if (!showWhenDecorator)
38
+ return;
39
+ const referencedField = getShowWhenField(showWhenDecorator);
40
+ if (!referencedField)
41
+ return;
42
+ // Find the parent class
43
+ // PropertyDefinition -> ClassBody -> ClassDeclaration/ClassExpression
44
+ // TypeScript guarantees node.parent is ClassBody for PropertyDefinition
45
+ const classBody = node.parent;
46
+ const classNode = classBody.parent;
47
+ if (classNode.type !== AST_NODE_TYPES.ClassDeclaration &&
48
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- defensive check
49
+ classNode.type !== AST_NODE_TYPES.ClassExpression) {
50
+ return;
51
+ }
52
+ // Get all property names in the class
53
+ const propertyNames = getClassPropertyNames(classNode);
54
+ // Check if the referenced field exists
55
+ if (!propertyNames.has(referencedField)) {
56
+ context.report({
57
+ node: showWhenDecorator.node,
58
+ messageId: "fieldDoesNotExist",
59
+ data: {
60
+ referencedField,
61
+ },
62
+ });
63
+ }
64
+ },
65
+ };
66
+ },
67
+ });
68
+ //# sourceMappingURL=showwhen-field-exists.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"showwhen-field-exists.js","sourceRoot":"","sources":["../../src/rules/showwhen-field-exists.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AACvE,OAAO,EACL,aAAa,EACb,gBAAgB,EAChB,qBAAqB,GACtB,MAAM,6BAA6B,CAAC;AAErC,MAAM,UAAU,GAAG,WAAW,CAAC,WAAW,CACxC,CAAC,IAAI,EAAE,EAAE,CAAC,4CAA4C,IAAI,EAAE,CAC7D,CAAC;AAIF,MAAM,CAAC,MAAM,mBAAmB,GAAG,UAAU,CAAiB;IAC5D,IAAI,EAAE,uBAAuB;IAC7B,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACJ,WAAW,EACT,oEAAoE;SACvE;QACD,QAAQ,EAAE;YACR,iBAAiB,EACf,qFAAqF;SACxF;QACD,MAAM,EAAE,EAAE;KACX;IACD,cAAc,EAAE,EAAE;IAClB,MAAM,CAAC,OAAO;QACZ,OAAO;YACL,kBAAkB,CAAC,IAAI;gBACrB,MAAM,iBAAiB,GAAG,aAAa,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;gBAC1D,IAAI,CAAC,iBAAiB;oBAAE,OAAO;gBAE/B,MAAM,eAAe,GAAG,gBAAgB,CAAC,iBAAiB,CAAC,CAAC;gBAC5D,IAAI,CAAC,eAAe;oBAAE,OAAO;gBAE7B,wBAAwB;gBACxB,sEAAsE;gBACtE,wEAAwE;gBACxE,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC;gBAC9B,MAAM,SAAS,GAAG,SAAS,CAAC,MAAM,CAAC;gBACnC,IACE,SAAS,CAAC,IAAI,KAAK,cAAc,CAAC,gBAAgB;oBAClD,0FAA0F;oBAC1F,SAAS,CAAC,IAAI,KAAK,cAAc,CAAC,eAAe,EACjD,CAAC;oBACD,OAAO;gBACT,CAAC;gBAED,sCAAsC;gBACtC,MAAM,aAAa,GAAG,qBAAqB,CAAC,SAAS,CAAC,CAAC;gBAEvD,uCAAuC;gBACvC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,eAAe,CAAC,EAAE,CAAC;oBACxC,OAAO,CAAC,MAAM,CAAC;wBACb,IAAI,EAAE,iBAAiB,CAAC,IAAI;wBAC5B,SAAS,EAAE,mBAAmB;wBAC9B,IAAI,EAAE;4BACJ,eAAe;yBAChB;qBACF,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC,CAAC"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Rule: showwhen-suggests-optional
3
+ *
4
+ * Suggests that fields with @ShowWhen should be marked as optional (`?`)
5
+ * since they may not be present in the output when the condition is false.
6
+ *
7
+ * Valid:
8
+ * @ShowWhen({ _predicate: "equals", field: "type", value: "a" })
9
+ * conditionalField?: string; // Optional - good
10
+ *
11
+ * Warning:
12
+ * @ShowWhen({ _predicate: "equals", field: "type", value: "a" })
13
+ * conditionalField!: string; // Not optional - may cause issues
14
+ */
15
+ import { ESLintUtils } from "@typescript-eslint/utils";
16
+ export declare const showwhenSuggestsOptional: ESLintUtils.RuleModule<"shouldBeOptional", [], unknown, ESLintUtils.RuleListener> & {
17
+ name: string;
18
+ };
19
+ //# sourceMappingURL=showwhen-suggests-optional.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"showwhen-suggests-optional.d.ts","sourceRoot":"","sources":["../../src/rules/showwhen-suggests-optional.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,WAAW,EAAkB,MAAM,0BAA0B,CAAC;AAUvE,eAAO,MAAM,wBAAwB;;CAqCnC,CAAC"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Rule: showwhen-suggests-optional
3
+ *
4
+ * Suggests that fields with @ShowWhen should be marked as optional (`?`)
5
+ * since they may not be present in the output when the condition is false.
6
+ *
7
+ * Valid:
8
+ * @ShowWhen({ _predicate: "equals", field: "type", value: "a" })
9
+ * conditionalField?: string; // Optional - good
10
+ *
11
+ * Warning:
12
+ * @ShowWhen({ _predicate: "equals", field: "type", value: "a" })
13
+ * conditionalField!: string; // Not optional - may cause issues
14
+ */
15
+ import { ESLintUtils, AST_NODE_TYPES } from "@typescript-eslint/utils";
16
+ import { findDecorator } from "../utils/decorator-utils.js";
17
+ import { isOptionalProperty } from "../utils/type-utils.js";
18
+ const createRule = ESLintUtils.RuleCreator((name) => `https://formspec.dev/eslint-plugin/rules/${name}`);
19
+ export const showwhenSuggestsOptional = createRule({
20
+ name: "showwhen-suggests-optional",
21
+ meta: {
22
+ type: "suggestion",
23
+ docs: {
24
+ description: "Suggests that fields with @ShowWhen should be marked as optional",
25
+ },
26
+ messages: {
27
+ shouldBeOptional: "Field '{{field}}' uses @ShowWhen but is not optional. Consider adding '?' since the field may not be in the output when the condition is false.",
28
+ },
29
+ schema: [],
30
+ },
31
+ defaultOptions: [],
32
+ create(context) {
33
+ return {
34
+ PropertyDefinition(node) {
35
+ const showWhenDecorator = findDecorator(node, "ShowWhen");
36
+ if (!showWhenDecorator)
37
+ return;
38
+ // Check if the field is already optional
39
+ if (isOptionalProperty(node))
40
+ return;
41
+ const fieldName = node.key.type === AST_NODE_TYPES.Identifier ? node.key.name : "<computed>";
42
+ context.report({
43
+ node: node.key,
44
+ messageId: "shouldBeOptional",
45
+ data: {
46
+ field: fieldName,
47
+ },
48
+ });
49
+ },
50
+ };
51
+ },
52
+ });
53
+ //# sourceMappingURL=showwhen-suggests-optional.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"showwhen-suggests-optional.js","sourceRoot":"","sources":["../../src/rules/showwhen-suggests-optional.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AACvE,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAE5D,MAAM,UAAU,GAAG,WAAW,CAAC,WAAW,CACxC,CAAC,IAAI,EAAE,EAAE,CAAC,4CAA4C,IAAI,EAAE,CAC7D,CAAC;AAIF,MAAM,CAAC,MAAM,wBAAwB,GAAG,UAAU,CAAiB;IACjE,IAAI,EAAE,4BAA4B;IAClC,IAAI,EAAE;QACJ,IAAI,EAAE,YAAY;QAClB,IAAI,EAAE;YACJ,WAAW,EACT,kEAAkE;SACrE;QACD,QAAQ,EAAE;YACR,gBAAgB,EACd,iJAAiJ;SACpJ;QACD,MAAM,EAAE,EAAE;KACX;IACD,cAAc,EAAE,EAAE;IAClB,MAAM,CAAC,OAAO;QACZ,OAAO;YACL,kBAAkB,CAAC,IAAI;gBACrB,MAAM,iBAAiB,GAAG,aAAa,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;gBAC1D,IAAI,CAAC,iBAAiB;oBAAE,OAAO;gBAE/B,yCAAyC;gBACzC,IAAI,kBAAkB,CAAC,IAAI,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;gBAE7E,OAAO,CAAC,MAAM,CAAC;oBACb,IAAI,EAAE,IAAI,CAAC,GAAG;oBACd,SAAS,EAAE,kBAAkB;oBAC7B,IAAI,EAAE;wBACJ,KAAK,EAAE,SAAS;qBACjB;iBACF,CAAC,CAAC;YACL,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC,CAAC"}
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Utility functions for working with decorator AST nodes.
3
+ */
4
+ import { TSESTree } from "@typescript-eslint/utils";
5
+ /**
6
+ * Information extracted from a decorator.
7
+ */
8
+ export interface DecoratorInfo {
9
+ /** The decorator name (e.g., "Min", "Label", "EnumOptions") */
10
+ name: string;
11
+ /** The arguments passed to the decorator */
12
+ args: TSESTree.Expression[];
13
+ /** The original decorator node */
14
+ node: TSESTree.Decorator;
15
+ }
16
+ /**
17
+ * FormSpec decorator names that imply specific field types.
18
+ */
19
+ export declare const DECORATOR_TYPE_HINTS: {
20
+ readonly Min: "number";
21
+ readonly Max: "number";
22
+ readonly Placeholder: "string";
23
+ readonly MinItems: "array";
24
+ readonly MaxItems: "array";
25
+ readonly EnumOptions: "enum";
26
+ };
27
+ export type TypeHintDecorator = keyof typeof DECORATOR_TYPE_HINTS;
28
+ /**
29
+ * All known FormSpec decorator names.
30
+ */
31
+ export declare const FORMSPEC_DECORATORS: Set<string>;
32
+ /**
33
+ * Extracts decorator information from a Decorator AST node.
34
+ *
35
+ * Handles both:
36
+ * - `@DecoratorName` (identifier)
37
+ * - `@DecoratorName(args)` (call expression)
38
+ *
39
+ * @param decorator - The decorator AST node
40
+ * @returns Decorator info or null if not a recognized pattern
41
+ */
42
+ export declare function getDecoratorInfo(decorator: TSESTree.Decorator): DecoratorInfo | null;
43
+ /**
44
+ * Finds all decorators on a property definition.
45
+ *
46
+ * @param node - The property definition node
47
+ * @returns Array of decorator info objects for FormSpec decorators
48
+ */
49
+ export declare function getFormSpecDecorators(node: TSESTree.PropertyDefinition): DecoratorInfo[];
50
+ /**
51
+ * Finds a specific decorator by name on a property.
52
+ *
53
+ * @param node - The property definition node
54
+ * @param name - The decorator name to find
55
+ * @returns The decorator info or null if not found
56
+ */
57
+ export declare function findDecorator(node: TSESTree.PropertyDefinition, name: string): DecoratorInfo | null;
58
+ /**
59
+ * Checks if a property has a specific decorator.
60
+ *
61
+ * @param node - The property definition node
62
+ * @param name - The decorator name to check
63
+ * @returns True if the decorator is present
64
+ */
65
+ export declare function hasDecorator(node: TSESTree.PropertyDefinition, name: string): boolean;
66
+ /**
67
+ * Gets the first argument of a decorator as a literal value.
68
+ *
69
+ * @param decorator - The decorator info
70
+ * @returns The literal value or null if not a literal
71
+ */
72
+ export declare function getDecoratorLiteralArg(decorator: DecoratorInfo): unknown;
73
+ /**
74
+ * Gets the first argument of a decorator as an array of values.
75
+ * Used for @EnumOptions(["a", "b", "c"]).
76
+ *
77
+ * @param decorator - The decorator info
78
+ * @returns Array of values or null if not an array expression
79
+ */
80
+ export declare function getDecoratorArrayArg(decorator: DecoratorInfo): unknown[] | null;
81
+ /**
82
+ * Gets the field reference from a @ShowWhen predicate.
83
+ * @ShowWhen({ _predicate: "equals", field: "foo", value: "bar" })
84
+ *
85
+ * @param decorator - The ShowWhen decorator info
86
+ * @returns The field name or null if not found
87
+ */
88
+ export declare function getShowWhenField(decorator: DecoratorInfo): string | null;
89
+ /**
90
+ * Gets the property name from a PropertyDefinition.
91
+ *
92
+ * @param node - The property definition node
93
+ * @returns The property name or null if computed/symbol
94
+ */
95
+ export declare function getPropertyName(node: TSESTree.PropertyDefinition): string | null;
96
+ /**
97
+ * Gets all property names from a class definition.
98
+ *
99
+ * @param classNode - The class declaration/expression node
100
+ * @returns Set of property names
101
+ */
102
+ export declare function getClassPropertyNames(classNode: TSESTree.ClassDeclaration | TSESTree.ClassExpression): Set<string>;
103
+ //# sourceMappingURL=decorator-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decorator-utils.d.ts","sourceRoot":"","sources":["../../src/utils/decorator-utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,QAAQ,EAAkB,MAAM,0BAA0B,CAAC;AAEpE;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,+DAA+D;IAC/D,IAAI,EAAE,MAAM,CAAC;IACb,4CAA4C;IAC5C,IAAI,EAAE,QAAQ,CAAC,UAAU,EAAE,CAAC;IAC5B,kCAAkC;IAClC,IAAI,EAAE,QAAQ,CAAC,SAAS,CAAC;CAC1B;AAED;;GAEG;AACH,eAAO,MAAM,oBAAoB;;;;;;;CAWvB,CAAC;AAEX,MAAM,MAAM,iBAAiB,GAAG,MAAM,OAAO,oBAAoB,CAAC;AAElE;;GAEG;AACH,eAAO,MAAM,mBAAmB,aAY9B,CAAC;AAEH;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,QAAQ,CAAC,SAAS,GAAG,aAAa,GAAG,IAAI,CAyBpF;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,QAAQ,CAAC,kBAAkB,GAChC,aAAa,EAAE,CAejB;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,QAAQ,CAAC,kBAAkB,EACjC,IAAI,EAAE,MAAM,GACX,aAAa,GAAG,IAAI,CAGtB;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,QAAQ,CAAC,kBAAkB,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAErF;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,aAAa,GAAG,OAAO,CAWxE;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,aAAa,GAAG,OAAO,EAAE,GAAG,IAAI,CAgC/E;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,aAAa,GAAG,MAAM,GAAG,IAAI,CAqBxE;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,QAAQ,CAAC,kBAAkB,GAAG,MAAM,GAAG,IAAI,CAQhF;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,QAAQ,CAAC,gBAAgB,GAAG,QAAQ,CAAC,eAAe,GAC9D,GAAG,CAAC,MAAM,CAAC,CAWb"}