@formspec/eslint-plugin 0.1.0-alpha.3 → 0.1.0-alpha.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +13 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +16 -7
- package/dist/index.js.map +1 -1
- package/dist/rules/constraints/allowed-field-types.d.ts +16 -0
- package/dist/rules/constraints/allowed-field-types.d.ts.map +1 -0
- package/dist/rules/constraints/allowed-field-types.js +132 -0
- package/dist/rules/constraints/allowed-field-types.js.map +1 -0
- package/dist/rules/constraints/allowed-layouts.d.ts +17 -0
- package/dist/rules/constraints/allowed-layouts.d.ts.map +1 -0
- package/dist/rules/constraints/allowed-layouts.js +82 -0
- package/dist/rules/constraints/allowed-layouts.js.map +1 -0
- package/dist/rules/constraints/index.d.ts +9 -0
- package/dist/rules/constraints/index.d.ts.map +1 -0
- package/dist/rules/constraints/index.js +9 -0
- package/dist/rules/constraints/index.js.map +1 -0
- package/package.json +3 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @formspec/eslint-plugin
|
|
3
3
|
*
|
|
4
|
-
* ESLint plugin for FormSpec
|
|
4
|
+
* ESLint plugin for FormSpec type safety and constraint validation.
|
|
5
5
|
*
|
|
6
|
-
* Provides rules to
|
|
7
|
-
* -
|
|
8
|
-
* -
|
|
9
|
-
* -
|
|
10
|
-
* - Conflicting or duplicate decorators
|
|
6
|
+
* Provides rules to:
|
|
7
|
+
* - Catch common mistakes when using FormSpec decorators
|
|
8
|
+
* - Validate Chain DSL usage against project constraints
|
|
9
|
+
* - Ensure forms comply with target environment capabilities
|
|
11
10
|
*/
|
|
12
11
|
import type { TSESLint } from "@typescript-eslint/utils";
|
|
13
12
|
import { decoratorFieldTypeMismatch } from "./rules/decorator-field-type-mismatch.js";
|
|
@@ -17,6 +16,7 @@ import { showwhenSuggestsOptional } from "./rules/showwhen-suggests-optional.js"
|
|
|
17
16
|
import { minMaxValidRange } from "./rules/min-max-valid-range.js";
|
|
18
17
|
import { noConflictingDecorators } from "./rules/no-conflicting-decorators.js";
|
|
19
18
|
import { noDuplicateDecorators } from "./rules/no-duplicate-decorators.js";
|
|
19
|
+
import { allowedFieldTypes, allowedLayouts } from "./rules/constraints/index.js";
|
|
20
20
|
/**
|
|
21
21
|
* The FormSpec ESLint plugin.
|
|
22
22
|
*/
|
|
@@ -46,6 +46,12 @@ declare const plugin: {
|
|
|
46
46
|
readonly "no-duplicate-decorators": TSESLint.RuleModule<"duplicateDecorator", [], unknown, TSESLint.RuleListener> & {
|
|
47
47
|
name: string;
|
|
48
48
|
};
|
|
49
|
+
readonly "constraints-allowed-field-types": TSESLint.RuleModule<"disallowedFieldType", import("./rules/constraints/allowed-field-types.js").Options, unknown, TSESLint.RuleListener> & {
|
|
50
|
+
name: string;
|
|
51
|
+
};
|
|
52
|
+
readonly "constraints-allowed-layouts": TSESLint.RuleModule<"disallowedGroup" | "disallowedConditional", import("./rules/constraints/allowed-layouts.js").Options, unknown, TSESLint.RuleListener> & {
|
|
53
|
+
name: string;
|
|
54
|
+
};
|
|
49
55
|
};
|
|
50
56
|
configs: {
|
|
51
57
|
recommended: TSESLint.FlatConfig.ConfigArray;
|
|
@@ -53,5 +59,5 @@ declare const plugin: {
|
|
|
53
59
|
};
|
|
54
60
|
};
|
|
55
61
|
export default plugin;
|
|
56
|
-
export { decoratorFieldTypeMismatch, enumOptionsMatchType, showwhenFieldExists, showwhenSuggestsOptional, minMaxValidRange, noConflictingDecorators, noDuplicateDecorators, };
|
|
62
|
+
export { decoratorFieldTypeMismatch, enumOptionsMatchType, showwhenFieldExists, showwhenSuggestsOptional, minMaxValidRange, noConflictingDecorators, noDuplicateDecorators, allowedFieldTypes, allowedLayouts, };
|
|
57
63
|
//# 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
|
|
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,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAClE,OAAO,EAAE,uBAAuB,EAAE,MAAM,sCAAsC,CAAC;AAC/E,OAAO,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAC;AAG3E,OAAO,EACL,iBAAiB,EACjB,cAAc,EACf,MAAM,8BAA8B,CAAC;AAkFtC;;GAEG;AACH,QAAA,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAOX,CAAC;AAEF,eAAe,MAAM,CAAC;AAGtB,OAAO,EAEL,0BAA0B,EAC1B,oBAAoB,EACpB,mBAAmB,EACnB,wBAAwB,EACxB,gBAAgB,EAChB,uBAAuB,EACvB,qBAAqB,EAErB,iBAAiB,EACjB,cAAc,GACf,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @formspec/eslint-plugin
|
|
3
3
|
*
|
|
4
|
-
* ESLint plugin for FormSpec
|
|
4
|
+
* ESLint plugin for FormSpec type safety and constraint validation.
|
|
5
5
|
*
|
|
6
|
-
* Provides rules to
|
|
7
|
-
* -
|
|
8
|
-
* -
|
|
9
|
-
* -
|
|
10
|
-
* - Conflicting or duplicate decorators
|
|
6
|
+
* Provides rules to:
|
|
7
|
+
* - Catch common mistakes when using FormSpec decorators
|
|
8
|
+
* - Validate Chain DSL usage against project constraints
|
|
9
|
+
* - Ensure forms comply with target environment capabilities
|
|
11
10
|
*/
|
|
12
11
|
import { decoratorFieldTypeMismatch } from "./rules/decorator-field-type-mismatch.js";
|
|
13
12
|
import { enumOptionsMatchType } from "./rules/enum-options-match-type.js";
|
|
@@ -16,10 +15,13 @@ import { showwhenSuggestsOptional } from "./rules/showwhen-suggests-optional.js"
|
|
|
16
15
|
import { minMaxValidRange } from "./rules/min-max-valid-range.js";
|
|
17
16
|
import { noConflictingDecorators } from "./rules/no-conflicting-decorators.js";
|
|
18
17
|
import { noDuplicateDecorators } from "./rules/no-duplicate-decorators.js";
|
|
18
|
+
// Constraint rules for Chain DSL
|
|
19
|
+
import { allowedFieldTypes, allowedLayouts, } from "./rules/constraints/index.js";
|
|
19
20
|
/**
|
|
20
21
|
* All rules provided by this plugin.
|
|
21
22
|
*/
|
|
22
23
|
const rules = {
|
|
24
|
+
// Decorator DSL rules
|
|
23
25
|
"decorator-field-type-mismatch": decoratorFieldTypeMismatch,
|
|
24
26
|
"enum-options-match-type": enumOptionsMatchType,
|
|
25
27
|
"showwhen-field-exists": showwhenFieldExists,
|
|
@@ -27,6 +29,9 @@ const rules = {
|
|
|
27
29
|
"min-max-valid-range": minMaxValidRange,
|
|
28
30
|
"no-conflicting-decorators": noConflictingDecorators,
|
|
29
31
|
"no-duplicate-decorators": noDuplicateDecorators,
|
|
32
|
+
// Constraint rules for Chain DSL
|
|
33
|
+
"constraints-allowed-field-types": allowedFieldTypes,
|
|
34
|
+
"constraints-allowed-layouts": allowedLayouts,
|
|
30
35
|
};
|
|
31
36
|
/**
|
|
32
37
|
* Plugin metadata.
|
|
@@ -100,5 +105,9 @@ const plugin = {
|
|
|
100
105
|
};
|
|
101
106
|
export default plugin;
|
|
102
107
|
// Named exports for individual rules
|
|
103
|
-
export {
|
|
108
|
+
export {
|
|
109
|
+
// Decorator DSL rules
|
|
110
|
+
decoratorFieldTypeMismatch, enumOptionsMatchType, showwhenFieldExists, showwhenSuggestsOptional, minMaxValidRange, noConflictingDecorators, noDuplicateDecorators,
|
|
111
|
+
// Constraint rules for Chain DSL
|
|
112
|
+
allowedFieldTypes, allowedLayouts, };
|
|
104
113
|
//# 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
|
|
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,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAClE,OAAO,EAAE,uBAAuB,EAAE,MAAM,sCAAsC,CAAC;AAC/E,OAAO,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAC;AAE3E,iCAAiC;AACjC,OAAO,EACL,iBAAiB,EACjB,cAAc,GACf,MAAM,8BAA8B,CAAC;AAEtC;;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,qBAAqB,EAAE,gBAAgB;IACvC,2BAA2B,EAAE,uBAAuB;IACpD,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,+BAA+B,EAAE,OAAO;YACxC,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,+BAA+B,EAAE,OAAO;YACxC,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,gBAAgB,EAChB,uBAAuB,EACvB,qBAAqB;AACrB,iCAAiC;AACjC,iBAAiB,EACjB,cAAc,GACf,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule: constraints/allowed-field-types
|
|
3
|
+
*
|
|
4
|
+
* Validates that field types used in the Chain DSL are allowed by the
|
|
5
|
+
* project's constraint configuration.
|
|
6
|
+
*
|
|
7
|
+
* Works with: field.text(), field.number(), field.boolean(), field.enum(),
|
|
8
|
+
* field.dynamicEnum(), field.dynamicSchema(), field.array(), field.object()
|
|
9
|
+
*/
|
|
10
|
+
import { ESLintUtils } from "@typescript-eslint/utils";
|
|
11
|
+
import { type FieldTypeConstraints } from "@formspec/constraints/browser";
|
|
12
|
+
export type Options = [FieldTypeConstraints];
|
|
13
|
+
export declare const allowedFieldTypes: ESLintUtils.RuleModule<"disallowedFieldType", Options, unknown, ESLintUtils.RuleListener> & {
|
|
14
|
+
name: string;
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=allowed-field-types.d.ts.map
|
|
@@ -0,0 +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;;CAuF5B,CAAC"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule: constraints/allowed-field-types
|
|
3
|
+
*
|
|
4
|
+
* Validates that field types used in the Chain DSL are allowed by the
|
|
5
|
+
* project's constraint configuration.
|
|
6
|
+
*
|
|
7
|
+
* Works with: field.text(), field.number(), field.boolean(), field.enum(),
|
|
8
|
+
* field.dynamicEnum(), field.dynamicSchema(), field.array(), field.object()
|
|
9
|
+
*/
|
|
10
|
+
import { ESLintUtils, AST_NODE_TYPES } from "@typescript-eslint/utils";
|
|
11
|
+
import { getFieldTypeSeverity, } from "@formspec/constraints/browser";
|
|
12
|
+
const createRule = ESLintUtils.RuleCreator((name) => `https://formspec.dev/eslint-plugin/rules/${name}`);
|
|
13
|
+
/**
|
|
14
|
+
* Maps DSL method names to constraint config keys.
|
|
15
|
+
*/
|
|
16
|
+
const METHOD_TO_CONSTRAINT = {
|
|
17
|
+
text: "text",
|
|
18
|
+
number: "number",
|
|
19
|
+
boolean: "boolean",
|
|
20
|
+
enum: "staticEnum",
|
|
21
|
+
dynamicEnum: "dynamicEnum",
|
|
22
|
+
dynamicSchema: "dynamicSchema",
|
|
23
|
+
array: "array",
|
|
24
|
+
arrayWithConfig: "array",
|
|
25
|
+
object: "object",
|
|
26
|
+
objectWithConfig: "object",
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Human-readable names for field types.
|
|
30
|
+
*/
|
|
31
|
+
const FIELD_TYPE_NAMES = {
|
|
32
|
+
text: "text field",
|
|
33
|
+
number: "number field",
|
|
34
|
+
boolean: "boolean field",
|
|
35
|
+
enum: "static enum field",
|
|
36
|
+
dynamicEnum: "dynamic enum field",
|
|
37
|
+
dynamicSchema: "dynamic schema field",
|
|
38
|
+
array: "array field",
|
|
39
|
+
arrayWithConfig: "array field",
|
|
40
|
+
object: "object field",
|
|
41
|
+
objectWithConfig: "object field",
|
|
42
|
+
};
|
|
43
|
+
export const allowedFieldTypes = createRule({
|
|
44
|
+
name: "constraints-allowed-field-types",
|
|
45
|
+
meta: {
|
|
46
|
+
type: "problem",
|
|
47
|
+
docs: {
|
|
48
|
+
description: "Validates that field types are allowed by the project's constraints",
|
|
49
|
+
},
|
|
50
|
+
messages: {
|
|
51
|
+
disallowedFieldType: "{{fieldTypeName}} is not allowed in this project. Field: '{{fieldName}}'",
|
|
52
|
+
},
|
|
53
|
+
schema: [
|
|
54
|
+
{
|
|
55
|
+
type: "object",
|
|
56
|
+
properties: {
|
|
57
|
+
text: { type: "string", enum: ["error", "warn", "off"] },
|
|
58
|
+
number: { type: "string", enum: ["error", "warn", "off"] },
|
|
59
|
+
boolean: { type: "string", enum: ["error", "warn", "off"] },
|
|
60
|
+
staticEnum: { type: "string", enum: ["error", "warn", "off"] },
|
|
61
|
+
dynamicEnum: { type: "string", enum: ["error", "warn", "off"] },
|
|
62
|
+
dynamicSchema: { type: "string", enum: ["error", "warn", "off"] },
|
|
63
|
+
array: { type: "string", enum: ["error", "warn", "off"] },
|
|
64
|
+
object: { type: "string", enum: ["error", "warn", "off"] },
|
|
65
|
+
},
|
|
66
|
+
additionalProperties: false,
|
|
67
|
+
},
|
|
68
|
+
],
|
|
69
|
+
},
|
|
70
|
+
defaultOptions: [{}],
|
|
71
|
+
create(context) {
|
|
72
|
+
const constraints = context.options[0] ?? {};
|
|
73
|
+
return {
|
|
74
|
+
CallExpression(node) {
|
|
75
|
+
// Check for field.xxx() pattern
|
|
76
|
+
if (node.callee.type !== AST_NODE_TYPES.MemberExpression ||
|
|
77
|
+
node.callee.object.type !== AST_NODE_TYPES.Identifier ||
|
|
78
|
+
node.callee.object.name !== "field" ||
|
|
79
|
+
node.callee.property.type !== AST_NODE_TYPES.Identifier) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
const methodName = node.callee.property.name;
|
|
83
|
+
const constraintKey = METHOD_TO_CONSTRAINT[methodName];
|
|
84
|
+
if (!constraintKey) {
|
|
85
|
+
return; // Not a recognized field method
|
|
86
|
+
}
|
|
87
|
+
// Map constraint key to internal field type for severity check
|
|
88
|
+
const fieldTypeMap = {
|
|
89
|
+
text: "text",
|
|
90
|
+
number: "number",
|
|
91
|
+
boolean: "boolean",
|
|
92
|
+
staticEnum: "enum",
|
|
93
|
+
dynamicEnum: "dynamic_enum",
|
|
94
|
+
dynamicSchema: "dynamic_schema",
|
|
95
|
+
array: "array",
|
|
96
|
+
object: "object",
|
|
97
|
+
};
|
|
98
|
+
const internalFieldType = fieldTypeMap[constraintKey];
|
|
99
|
+
const severity = getFieldTypeSeverity(internalFieldType, constraints);
|
|
100
|
+
if (severity === "off") {
|
|
101
|
+
return; // Allowed
|
|
102
|
+
}
|
|
103
|
+
// Extract field name from first argument
|
|
104
|
+
const fieldName = extractFieldName(node.arguments[0]);
|
|
105
|
+
const fieldTypeName = FIELD_TYPE_NAMES[methodName] || `${methodName} field`;
|
|
106
|
+
context.report({
|
|
107
|
+
node: node.callee.property,
|
|
108
|
+
messageId: "disallowedFieldType",
|
|
109
|
+
data: {
|
|
110
|
+
fieldTypeName,
|
|
111
|
+
fieldName,
|
|
112
|
+
},
|
|
113
|
+
});
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
},
|
|
117
|
+
});
|
|
118
|
+
/**
|
|
119
|
+
* Extracts the field name from the first argument of a field.xxx() call.
|
|
120
|
+
*/
|
|
121
|
+
function extractFieldName(arg) {
|
|
122
|
+
if (!arg)
|
|
123
|
+
return "<unknown>";
|
|
124
|
+
if (arg.type === AST_NODE_TYPES.Literal && typeof arg.value === "string") {
|
|
125
|
+
return arg.value;
|
|
126
|
+
}
|
|
127
|
+
if (arg.type === AST_NODE_TYPES.TemplateLiteral && arg.quasis.length === 1) {
|
|
128
|
+
return arg.quasis[0]?.value.cooked ?? "<unknown>";
|
|
129
|
+
}
|
|
130
|
+
return "<dynamic>";
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=allowed-field-types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"allowed-field-types.js","sourceRoot":"","sources":["../../../src/rules/constraints/allowed-field-types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule: constraints/allowed-layouts
|
|
3
|
+
*
|
|
4
|
+
* Validates that layout constructs (group, when/conditionals) used in the
|
|
5
|
+
* Chain DSL are allowed by the project's constraint configuration.
|
|
6
|
+
*
|
|
7
|
+
* Works with: group(), when()
|
|
8
|
+
*/
|
|
9
|
+
import { ESLintUtils } from "@typescript-eslint/utils";
|
|
10
|
+
import { type LayoutConstraints } from "@formspec/constraints/browser";
|
|
11
|
+
type MessageIds = "disallowedGroup" | "disallowedConditional";
|
|
12
|
+
export type Options = [LayoutConstraints];
|
|
13
|
+
export declare const allowedLayouts: ESLintUtils.RuleModule<MessageIds, Options, unknown, ESLintUtils.RuleListener> & {
|
|
14
|
+
name: string;
|
|
15
|
+
};
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=allowed-layouts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"allowed-layouts.d.ts","sourceRoot":"","sources":["../../../src/rules/constraints/allowed-layouts.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,WAAW,EAAkB,MAAM,0BAA0B,CAAC;AAEvE,OAAO,EAAuB,KAAK,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAM5F,KAAK,UAAU,GAAG,iBAAiB,GAAG,uBAAuB,CAAC;AAE9D,MAAM,MAAM,OAAO,GAAG,CAAC,iBAAiB,CAAC,CAAC;AAE1C,eAAO,MAAM,cAAc;;CA6DzB,CAAC"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule: constraints/allowed-layouts
|
|
3
|
+
*
|
|
4
|
+
* Validates that layout constructs (group, when/conditionals) used in the
|
|
5
|
+
* Chain DSL are allowed by the project's constraint configuration.
|
|
6
|
+
*
|
|
7
|
+
* Works with: group(), when()
|
|
8
|
+
*/
|
|
9
|
+
import { ESLintUtils, AST_NODE_TYPES } from "@typescript-eslint/utils";
|
|
10
|
+
import { isLayoutTypeAllowed } from "@formspec/constraints/browser";
|
|
11
|
+
const createRule = ESLintUtils.RuleCreator((name) => `https://formspec.dev/eslint-plugin/rules/${name}`);
|
|
12
|
+
export const allowedLayouts = createRule({
|
|
13
|
+
name: "constraints-allowed-layouts",
|
|
14
|
+
meta: {
|
|
15
|
+
type: "problem",
|
|
16
|
+
docs: {
|
|
17
|
+
description: "Validates that layout constructs (group, conditionals) are allowed by the project's constraints",
|
|
18
|
+
},
|
|
19
|
+
messages: {
|
|
20
|
+
disallowedGroup: "group() is not allowed - visual grouping is not supported in this project{{labelInfo}}",
|
|
21
|
+
disallowedConditional: "when() conditional visibility is not allowed in this project",
|
|
22
|
+
},
|
|
23
|
+
schema: [
|
|
24
|
+
{
|
|
25
|
+
type: "object",
|
|
26
|
+
properties: {
|
|
27
|
+
group: { type: "string", enum: ["error", "warn", "off"] },
|
|
28
|
+
conditionals: { type: "string", enum: ["error", "warn", "off"] },
|
|
29
|
+
maxNestingDepth: { type: "number", minimum: 0 },
|
|
30
|
+
},
|
|
31
|
+
additionalProperties: false,
|
|
32
|
+
},
|
|
33
|
+
],
|
|
34
|
+
},
|
|
35
|
+
defaultOptions: [{}],
|
|
36
|
+
create(context) {
|
|
37
|
+
const constraints = context.options[0] ?? {};
|
|
38
|
+
return {
|
|
39
|
+
CallExpression(node) {
|
|
40
|
+
// Check for group() or when() calls
|
|
41
|
+
if (node.callee.type !== AST_NODE_TYPES.Identifier) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
const functionName = node.callee.name;
|
|
45
|
+
if (functionName === "group") {
|
|
46
|
+
if (!isLayoutTypeAllowed("group", constraints)) {
|
|
47
|
+
const label = extractGroupLabel(node.arguments[0]);
|
|
48
|
+
const labelInfo = label ? ` (label: "${label}")` : "";
|
|
49
|
+
context.report({
|
|
50
|
+
node: node.callee,
|
|
51
|
+
messageId: "disallowedGroup",
|
|
52
|
+
data: { labelInfo },
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
else if (functionName === "when") {
|
|
57
|
+
if (!isLayoutTypeAllowed("conditional", constraints)) {
|
|
58
|
+
context.report({
|
|
59
|
+
node: node.callee,
|
|
60
|
+
messageId: "disallowedConditional",
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
/**
|
|
69
|
+
* Extracts the group label from the first argument of a group() call.
|
|
70
|
+
*/
|
|
71
|
+
function extractGroupLabel(arg) {
|
|
72
|
+
if (!arg)
|
|
73
|
+
return null;
|
|
74
|
+
if (arg.type === AST_NODE_TYPES.Literal && typeof arg.value === "string") {
|
|
75
|
+
return arg.value;
|
|
76
|
+
}
|
|
77
|
+
if (arg.type === AST_NODE_TYPES.TemplateLiteral && arg.quasis.length === 1) {
|
|
78
|
+
return arg.quasis[0]?.value.cooked ?? null;
|
|
79
|
+
}
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=allowed-layouts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"allowed-layouts.js","sourceRoot":"","sources":["../../../src/rules/constraints/allowed-layouts.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Constraint validation rules for FormSpec Chain DSL.
|
|
3
|
+
*
|
|
4
|
+
* These rules validate that FormSpec constructs are allowed by the
|
|
5
|
+
* project's constraint configuration (.formspec.yml).
|
|
6
|
+
*/
|
|
7
|
+
export { allowedFieldTypes } from "./allowed-field-types.js";
|
|
8
|
+
export { allowedLayouts } from "./allowed-layouts.js";
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/rules/constraints/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Constraint validation rules for FormSpec Chain DSL.
|
|
3
|
+
*
|
|
4
|
+
* These rules validate that FormSpec constructs are allowed by the
|
|
5
|
+
* project's constraint configuration (.formspec.yml).
|
|
6
|
+
*/
|
|
7
|
+
export { allowedFieldTypes } from "./allowed-field-types.js";
|
|
8
|
+
export { allowedLayouts } from "./allowed-layouts.js";
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/rules/constraints/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@formspec/eslint-plugin",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.7",
|
|
4
4
|
"description": "ESLint rules for FormSpec decorator DSL type safety",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -15,7 +15,8 @@
|
|
|
15
15
|
"dist"
|
|
16
16
|
],
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@typescript-eslint/utils": "^8.0.0"
|
|
18
|
+
"@typescript-eslint/utils": "^8.0.0",
|
|
19
|
+
"@formspec/constraints": "0.1.0-alpha.7"
|
|
19
20
|
},
|
|
20
21
|
"peerDependencies": {
|
|
21
22
|
"eslint": "^9.0.0",
|