@tenphi/eslint-plugin-tasty 0.3.1 → 0.4.1
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/config.js +100 -20
- package/dist/config.js.map +1 -1
- package/dist/configs.js +5 -4
- package/dist/configs.js.map +1 -1
- package/dist/constants.js +67 -2
- package/dist/constants.js.map +1 -1
- package/dist/context.js +40 -7
- package/dist/context.js.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/parsers/state-key-parser.js +486 -0
- package/dist/parsers/state-key-parser.js.map +1 -0
- package/dist/parsers/utils.js +128 -0
- package/dist/parsers/utils.js.map +1 -0
- package/dist/parsers/value-parser.js +613 -0
- package/dist/parsers/value-parser.js.map +1 -0
- package/dist/rules/consistent-token-usage.js +20 -19
- package/dist/rules/consistent-token-usage.js.map +1 -1
- package/dist/rules/known-property.js +31 -30
- package/dist/rules/known-property.js.map +1 -1
- package/dist/rules/no-duplicate-state.js +12 -11
- package/dist/rules/no-duplicate-state.js.map +1 -1
- package/dist/rules/no-important.js +12 -11
- package/dist/rules/no-important.js.map +1 -1
- package/dist/rules/no-nested-selector.js +15 -14
- package/dist/rules/no-nested-selector.js.map +1 -1
- package/dist/rules/no-nested-state-map.js +19 -18
- package/dist/rules/no-nested-state-map.js.map +1 -1
- package/dist/rules/no-raw-color-values.js +15 -14
- package/dist/rules/no-raw-color-values.js.map +1 -1
- package/dist/rules/no-runtime-styles-mutation.js +6 -5
- package/dist/rules/no-runtime-styles-mutation.js.map +1 -1
- package/dist/rules/no-unknown-state-alias.js +12 -11
- package/dist/rules/no-unknown-state-alias.js.map +1 -1
- package/dist/rules/prefer-shorthand-property.js +19 -18
- package/dist/rules/prefer-shorthand-property.js.map +1 -1
- package/dist/rules/require-default-state.js +22 -21
- package/dist/rules/require-default-state.js.map +1 -1
- package/dist/rules/static-no-dynamic-values.js +7 -6
- package/dist/rules/static-no-dynamic-values.js.map +1 -1
- package/dist/rules/static-valid-selector.js +1 -1
- package/dist/rules/valid-boolean-property.js +19 -18
- package/dist/rules/valid-boolean-property.js.map +1 -1
- package/dist/rules/valid-color-token.js +33 -21
- package/dist/rules/valid-color-token.js.map +1 -1
- package/dist/rules/valid-custom-property.js +31 -19
- package/dist/rules/valid-custom-property.js.map +1 -1
- package/dist/rules/valid-custom-unit.js +12 -16
- package/dist/rules/valid-custom-unit.js.map +1 -1
- package/dist/rules/valid-directional-modifier.js +21 -20
- package/dist/rules/valid-directional-modifier.js.map +1 -1
- package/dist/rules/valid-preset.js +5 -2
- package/dist/rules/valid-preset.js.map +1 -1
- package/dist/rules/valid-radius-shape.js +19 -18
- package/dist/rules/valid-radius-shape.js.map +1 -1
- package/dist/rules/valid-recipe.js +5 -2
- package/dist/rules/valid-recipe.js.map +1 -1
- package/dist/rules/valid-state-definition.js +70 -0
- package/dist/rules/valid-state-definition.js.map +1 -0
- package/dist/rules/valid-state-key.js +39 -102
- package/dist/rules/valid-state-key.js.map +1 -1
- package/dist/rules/valid-styles-structure.js +39 -38
- package/dist/rules/valid-styles-structure.js.map +1 -1
- package/dist/rules/valid-sub-element.js +21 -20
- package/dist/rules/valid-sub-element.js.map +1 -1
- package/dist/rules/valid-transition.js +19 -18
- package/dist/rules/valid-transition.js.map +1 -1
- package/dist/rules/valid-value.js +117 -64
- package/dist/rules/valid-value.js.map +1 -1
- package/package.json +1 -8
- package/dist/parser.js +0 -46
- package/dist/parser.js.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createRule } from "../create-rule.js";
|
|
2
|
-
import { TastyContext } from "../context.js";
|
|
3
2
|
import { getKeyName, getStringValue } from "../utils.js";
|
|
3
|
+
import { TastyContext, styleObjectListeners } from "../context.js";
|
|
4
4
|
|
|
5
5
|
//#region src/rules/consistent-token-usage.ts
|
|
6
6
|
const PX_TO_UNIT = {
|
|
@@ -57,28 +57,29 @@ var consistent_token_usage_default = createRule({
|
|
|
57
57
|
}
|
|
58
58
|
});
|
|
59
59
|
}
|
|
60
|
+
function handleStyleObject(node) {
|
|
61
|
+
if (!ctx.isStyleObject(node)) return;
|
|
62
|
+
for (const prop of node.properties) {
|
|
63
|
+
if (prop.type !== "Property" || prop.computed) continue;
|
|
64
|
+
const key = getKeyName(prop.key);
|
|
65
|
+
if (key === null) continue;
|
|
66
|
+
const str = getStringValue(prop.value);
|
|
67
|
+
if (str) {
|
|
68
|
+
checkValue(key, str, prop.value);
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
if (prop.value.type === "ObjectExpression") for (const stateProp of prop.value.properties) {
|
|
72
|
+
if (stateProp.type !== "Property") continue;
|
|
73
|
+
const stateStr = getStringValue(stateProp.value);
|
|
74
|
+
if (stateStr) checkValue(key, stateStr, stateProp.value);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
60
78
|
return {
|
|
61
79
|
ImportDeclaration(node) {
|
|
62
80
|
ctx.trackImport(node);
|
|
63
81
|
},
|
|
64
|
-
|
|
65
|
-
if (!ctx.isStyleObject(node)) return;
|
|
66
|
-
for (const prop of node.properties) {
|
|
67
|
-
if (prop.type !== "Property" || prop.computed) continue;
|
|
68
|
-
const key = getKeyName(prop.key);
|
|
69
|
-
if (key === null) continue;
|
|
70
|
-
const str = getStringValue(prop.value);
|
|
71
|
-
if (str) {
|
|
72
|
-
checkValue(key, str, prop.value);
|
|
73
|
-
continue;
|
|
74
|
-
}
|
|
75
|
-
if (prop.value.type === "ObjectExpression") for (const stateProp of prop.value.properties) {
|
|
76
|
-
if (stateProp.type !== "Property") continue;
|
|
77
|
-
const stateStr = getStringValue(stateProp.value);
|
|
78
|
-
if (stateStr) checkValue(key, stateStr, stateProp.value);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
+
...styleObjectListeners(handleStyleObject)
|
|
82
83
|
};
|
|
83
84
|
}
|
|
84
85
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"consistent-token-usage.js","names":[],"sources":["../../src/rules/consistent-token-usage.ts"],"sourcesContent":["import type { TSESTree } from '@typescript-eslint/utils';\nimport { createRule } from '../create-rule.js';\nimport { TastyContext } from '../context.js';\nimport { getKeyName, getStringValue } from '../utils.js';\n\ntype MessageIds = 'preferToken';\n\nconst PX_TO_UNIT: Record<string, string> = {\n '8px': '1x',\n '16px': '2x',\n '24px': '3x',\n '32px': '4x',\n '40px': '5x',\n '48px': '6x',\n '56px': '7x',\n '64px': '8x',\n};\n\nexport default createRule<[], MessageIds>({\n name: 'consistent-token-usage',\n meta: {\n type: 'suggestion',\n docs: {\n description:\n 'Suggest using design tokens and custom units instead of raw CSS values',\n },\n messages: {\n preferToken: \"Consider using '{{suggestion}}' instead of '{{raw}}'.\",\n },\n schema: [],\n },\n defaultOptions: [],\n create(context) {\n const ctx = new TastyContext(context);\n\n function checkValue(\n property: string,\n value: string,\n node: TSESTree.Node,\n ): void {\n const trimmed = value.trim();\n\n // Check pixel values that map to gap multiples\n if (trimmed in PX_TO_UNIT) {\n context.report({\n node,\n messageId: 'preferToken',\n data: { suggestion: PX_TO_UNIT[trimmed], raw: trimmed },\n });\n return;\n }\n\n // Check 6px in radius context\n if (property === 'radius' && trimmed === '6px') {\n context.report({\n node,\n messageId: 'preferToken',\n data: { suggestion: '1r', raw: '6px' },\n });\n return;\n }\n\n // Check 1px in border context\n if (property === 'border' && trimmed.includes('1px')) {\n context.report({\n node,\n messageId: 'preferToken',\n data: { suggestion: '1bw', raw: '1px' },\n });\n }\n }\n\n
|
|
1
|
+
{"version":3,"file":"consistent-token-usage.js","names":[],"sources":["../../src/rules/consistent-token-usage.ts"],"sourcesContent":["import type { TSESTree } from '@typescript-eslint/utils';\nimport { createRule } from '../create-rule.js';\nimport { TastyContext, styleObjectListeners } from '../context.js';\nimport { getKeyName, getStringValue } from '../utils.js';\n\ntype MessageIds = 'preferToken';\n\nconst PX_TO_UNIT: Record<string, string> = {\n '8px': '1x',\n '16px': '2x',\n '24px': '3x',\n '32px': '4x',\n '40px': '5x',\n '48px': '6x',\n '56px': '7x',\n '64px': '8x',\n};\n\nexport default createRule<[], MessageIds>({\n name: 'consistent-token-usage',\n meta: {\n type: 'suggestion',\n docs: {\n description:\n 'Suggest using design tokens and custom units instead of raw CSS values',\n },\n messages: {\n preferToken: \"Consider using '{{suggestion}}' instead of '{{raw}}'.\",\n },\n schema: [],\n },\n defaultOptions: [],\n create(context) {\n const ctx = new TastyContext(context);\n\n function checkValue(\n property: string,\n value: string,\n node: TSESTree.Node,\n ): void {\n const trimmed = value.trim();\n\n // Check pixel values that map to gap multiples\n if (trimmed in PX_TO_UNIT) {\n context.report({\n node,\n messageId: 'preferToken',\n data: { suggestion: PX_TO_UNIT[trimmed], raw: trimmed },\n });\n return;\n }\n\n // Check 6px in radius context\n if (property === 'radius' && trimmed === '6px') {\n context.report({\n node,\n messageId: 'preferToken',\n data: { suggestion: '1r', raw: '6px' },\n });\n return;\n }\n\n // Check 1px in border context\n if (property === 'border' && trimmed.includes('1px')) {\n context.report({\n node,\n messageId: 'preferToken',\n data: { suggestion: '1bw', raw: '1px' },\n });\n }\n }\n\n function handleStyleObject(node: TSESTree.ObjectExpression) {\n if (!ctx.isStyleObject(node)) return;\n\n for (const prop of node.properties) {\n if (prop.type !== 'Property' || prop.computed) continue;\n\n const key = getKeyName(prop.key);\n if (key === null) continue;\n\n const str = getStringValue(prop.value);\n if (str) {\n checkValue(key, str, prop.value);\n continue;\n }\n\n if (prop.value.type === 'ObjectExpression') {\n for (const stateProp of prop.value.properties) {\n if (stateProp.type !== 'Property') continue;\n const stateStr = getStringValue(stateProp.value);\n if (stateStr) {\n checkValue(key, stateStr, stateProp.value);\n }\n }\n }\n }\n }\n\n return {\n ImportDeclaration(node) {\n ctx.trackImport(node);\n },\n ...styleObjectListeners(handleStyleObject),\n };\n },\n});\n"],"mappings":";;;;;AAOA,MAAM,aAAqC;CACzC,OAAO;CACP,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACT;AAED,qCAAe,WAA2B;CACxC,MAAM;CACN,MAAM;EACJ,MAAM;EACN,MAAM,EACJ,aACE,0EACH;EACD,UAAU,EACR,aAAa,yDACd;EACD,QAAQ,EAAE;EACX;CACD,gBAAgB,EAAE;CAClB,OAAO,SAAS;EACd,MAAM,MAAM,IAAI,aAAa,QAAQ;EAErC,SAAS,WACP,UACA,OACA,MACM;GACN,MAAM,UAAU,MAAM,MAAM;AAG5B,OAAI,WAAW,YAAY;AACzB,YAAQ,OAAO;KACb;KACA,WAAW;KACX,MAAM;MAAE,YAAY,WAAW;MAAU,KAAK;MAAS;KACxD,CAAC;AACF;;AAIF,OAAI,aAAa,YAAY,YAAY,OAAO;AAC9C,YAAQ,OAAO;KACb;KACA,WAAW;KACX,MAAM;MAAE,YAAY;MAAM,KAAK;MAAO;KACvC,CAAC;AACF;;AAIF,OAAI,aAAa,YAAY,QAAQ,SAAS,MAAM,CAClD,SAAQ,OAAO;IACb;IACA,WAAW;IACX,MAAM;KAAE,YAAY;KAAO,KAAK;KAAO;IACxC,CAAC;;EAIN,SAAS,kBAAkB,MAAiC;AAC1D,OAAI,CAAC,IAAI,cAAc,KAAK,CAAE;AAE9B,QAAK,MAAM,QAAQ,KAAK,YAAY;AAClC,QAAI,KAAK,SAAS,cAAc,KAAK,SAAU;IAE/C,MAAM,MAAM,WAAW,KAAK,IAAI;AAChC,QAAI,QAAQ,KAAM;IAElB,MAAM,MAAM,eAAe,KAAK,MAAM;AACtC,QAAI,KAAK;AACP,gBAAW,KAAK,KAAK,KAAK,MAAM;AAChC;;AAGF,QAAI,KAAK,MAAM,SAAS,mBACtB,MAAK,MAAM,aAAa,KAAK,MAAM,YAAY;AAC7C,SAAI,UAAU,SAAS,WAAY;KACnC,MAAM,WAAW,eAAe,UAAU,MAAM;AAChD,SAAI,SACF,YAAW,KAAK,UAAU,UAAU,MAAM;;;;AAOpD,SAAO;GACL,kBAAkB,MAAM;AACtB,QAAI,YAAY,KAAK;;GAEvB,GAAG,qBAAqB,kBAAkB;GAC3C;;CAEJ,CAAC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createRule } from "../create-rule.js";
|
|
2
2
|
import { KNOWN_CSS_PROPERTIES, KNOWN_TASTY_PROPERTIES, SHORTHAND_MAPPING, SPECIAL_STYLE_KEYS } from "../constants.js";
|
|
3
|
-
import { TastyContext } from "../context.js";
|
|
4
3
|
import { getKeyName } from "../utils.js";
|
|
4
|
+
import { TastyContext, styleObjectListeners } from "../context.js";
|
|
5
5
|
|
|
6
6
|
//#region src/rules/known-property.ts
|
|
7
7
|
var known_property_default = createRule({
|
|
@@ -15,39 +15,40 @@ var known_property_default = createRule({
|
|
|
15
15
|
defaultOptions: [],
|
|
16
16
|
create(context) {
|
|
17
17
|
const ctx = new TastyContext(context);
|
|
18
|
+
function handleStyleObject(node) {
|
|
19
|
+
if (!ctx.isStyleObject(node)) return;
|
|
20
|
+
for (const prop of node.properties) {
|
|
21
|
+
if (prop.type !== "Property" || prop.computed) continue;
|
|
22
|
+
const key = getKeyName(prop.key);
|
|
23
|
+
if (key === null) continue;
|
|
24
|
+
if (/^[A-Z]/.test(key)) continue;
|
|
25
|
+
if (key.startsWith("&")) continue;
|
|
26
|
+
if (key.startsWith("@")) continue;
|
|
27
|
+
if (key.startsWith("$")) continue;
|
|
28
|
+
if (key.startsWith("#")) continue;
|
|
29
|
+
if (key.startsWith("--")) continue;
|
|
30
|
+
if (key.startsWith("-")) continue;
|
|
31
|
+
if (KNOWN_TASTY_PROPERTIES.has(key)) continue;
|
|
32
|
+
if (KNOWN_CSS_PROPERTIES.has(key)) continue;
|
|
33
|
+
if (SPECIAL_STYLE_KEYS.has(key)) continue;
|
|
34
|
+
if (key in SHORTHAND_MAPPING) continue;
|
|
35
|
+
if (ctx.config.styles.includes(key)) continue;
|
|
36
|
+
if (prop.value.type === "ObjectExpression" && node.parent?.type === "Property") {
|
|
37
|
+
const parentProp = node.parent;
|
|
38
|
+
if (!parentProp.computed && ctx.isStateMap(node, parentProp)) continue;
|
|
39
|
+
}
|
|
40
|
+
context.report({
|
|
41
|
+
node: prop.key,
|
|
42
|
+
messageId: "unknownProperty",
|
|
43
|
+
data: { name: key }
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
}
|
|
18
47
|
return {
|
|
19
48
|
ImportDeclaration(node) {
|
|
20
49
|
ctx.trackImport(node);
|
|
21
50
|
},
|
|
22
|
-
|
|
23
|
-
if (!ctx.isStyleObject(node)) return;
|
|
24
|
-
for (const prop of node.properties) {
|
|
25
|
-
if (prop.type !== "Property" || prop.computed) continue;
|
|
26
|
-
const key = getKeyName(prop.key);
|
|
27
|
-
if (key === null) continue;
|
|
28
|
-
if (/^[A-Z]/.test(key)) continue;
|
|
29
|
-
if (key.startsWith("&")) continue;
|
|
30
|
-
if (key.startsWith("@")) continue;
|
|
31
|
-
if (key.startsWith("$")) continue;
|
|
32
|
-
if (key.startsWith("#")) continue;
|
|
33
|
-
if (key.startsWith("--")) continue;
|
|
34
|
-
if (key.startsWith("-")) continue;
|
|
35
|
-
if (KNOWN_TASTY_PROPERTIES.has(key)) continue;
|
|
36
|
-
if (KNOWN_CSS_PROPERTIES.has(key)) continue;
|
|
37
|
-
if (SPECIAL_STYLE_KEYS.has(key)) continue;
|
|
38
|
-
if (key in SHORTHAND_MAPPING) continue;
|
|
39
|
-
if (ctx.config.styles.includes(key)) continue;
|
|
40
|
-
if (prop.value.type === "ObjectExpression" && node.parent?.type === "Property") {
|
|
41
|
-
const parentProp = node.parent;
|
|
42
|
-
if (!parentProp.computed && ctx.isStateMap(node, parentProp)) continue;
|
|
43
|
-
}
|
|
44
|
-
context.report({
|
|
45
|
-
node: prop.key,
|
|
46
|
-
messageId: "unknownProperty",
|
|
47
|
-
data: { name: key }
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
+
...styleObjectListeners(handleStyleObject)
|
|
51
52
|
};
|
|
52
53
|
}
|
|
53
54
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"known-property.js","names":[],"sources":["../../src/rules/known-property.ts"],"sourcesContent":["import type { TSESTree } from '@typescript-eslint/utils';\nimport { createRule } from '../create-rule.js';\nimport { TastyContext } from '../context.js';\nimport { getKeyName } from '../utils.js';\nimport {\n KNOWN_TASTY_PROPERTIES,\n KNOWN_CSS_PROPERTIES,\n SPECIAL_STYLE_KEYS,\n SHORTHAND_MAPPING,\n} from '../constants.js';\n\ntype MessageIds = 'unknownProperty';\n\nexport default createRule<[], MessageIds>({\n name: 'known-property',\n meta: {\n type: 'problem',\n docs: {\n description:\n 'Warn when a style property name is not recognized as a valid tasty or CSS property',\n },\n messages: {\n unknownProperty: \"Unknown style property '{{name}}'.\",\n },\n schema: [],\n },\n defaultOptions: [],\n create(context) {\n const ctx = new TastyContext(context);\n\n
|
|
1
|
+
{"version":3,"file":"known-property.js","names":[],"sources":["../../src/rules/known-property.ts"],"sourcesContent":["import type { TSESTree } from '@typescript-eslint/utils';\nimport { createRule } from '../create-rule.js';\nimport { TastyContext, styleObjectListeners } from '../context.js';\nimport { getKeyName } from '../utils.js';\nimport {\n KNOWN_TASTY_PROPERTIES,\n KNOWN_CSS_PROPERTIES,\n SPECIAL_STYLE_KEYS,\n SHORTHAND_MAPPING,\n} from '../constants.js';\n\ntype MessageIds = 'unknownProperty';\n\nexport default createRule<[], MessageIds>({\n name: 'known-property',\n meta: {\n type: 'problem',\n docs: {\n description:\n 'Warn when a style property name is not recognized as a valid tasty or CSS property',\n },\n messages: {\n unknownProperty: \"Unknown style property '{{name}}'.\",\n },\n schema: [],\n },\n defaultOptions: [],\n create(context) {\n const ctx = new TastyContext(context);\n\n function handleStyleObject(node: TSESTree.ObjectExpression) {\n if (!ctx.isStyleObject(node)) return;\n\n for (const prop of node.properties) {\n if (prop.type !== 'Property' || prop.computed) continue;\n\n const key = getKeyName(prop.key);\n if (key === null) continue;\n\n // Sub-element keys (uppercase start)\n if (/^[A-Z]/.test(key)) continue;\n\n // Nested selectors (handled by no-nested-selector)\n if (key.startsWith('&')) continue;\n\n // Special @ keys\n if (key.startsWith('@')) continue;\n\n // Custom CSS property definitions\n if (key.startsWith('$')) continue;\n\n // Color token definitions\n if (key.startsWith('#')) continue;\n\n // CSS custom properties (--foo)\n if (key.startsWith('--')) continue;\n\n // Vendor-prefixed properties (-webkit-*, -moz-*, etc.)\n if (key.startsWith('-')) continue;\n\n // Known tasty property\n if (KNOWN_TASTY_PROPERTIES.has(key)) continue;\n\n // Known CSS property\n if (KNOWN_CSS_PROPERTIES.has(key)) continue;\n\n // Special style keys\n if (SPECIAL_STYLE_KEYS.has(key)) continue;\n\n // Shorthand mappings (reported by prefer-shorthand-property)\n if (key in SHORTHAND_MAPPING) continue;\n\n // Custom styles from config\n if (ctx.config.styles.includes(key)) continue;\n\n // Check if the parent is a state map — state keys are not properties\n if (\n prop.value.type === 'ObjectExpression' &&\n node.parent?.type === 'Property'\n ) {\n const parentProp = node.parent as TSESTree.Property;\n if (!parentProp.computed && ctx.isStateMap(node, parentProp)) {\n continue;\n }\n }\n\n context.report({\n node: prop.key,\n messageId: 'unknownProperty',\n data: { name: key },\n });\n }\n }\n\n return {\n ImportDeclaration(node) {\n ctx.trackImport(node);\n },\n ...styleObjectListeners(handleStyleObject),\n };\n },\n});\n"],"mappings":";;;;;;AAaA,6BAAe,WAA2B;CACxC,MAAM;CACN,MAAM;EACJ,MAAM;EACN,MAAM,EACJ,aACE,sFACH;EACD,UAAU,EACR,iBAAiB,sCAClB;EACD,QAAQ,EAAE;EACX;CACD,gBAAgB,EAAE;CAClB,OAAO,SAAS;EACd,MAAM,MAAM,IAAI,aAAa,QAAQ;EAErC,SAAS,kBAAkB,MAAiC;AAC1D,OAAI,CAAC,IAAI,cAAc,KAAK,CAAE;AAE9B,QAAK,MAAM,QAAQ,KAAK,YAAY;AAClC,QAAI,KAAK,SAAS,cAAc,KAAK,SAAU;IAE/C,MAAM,MAAM,WAAW,KAAK,IAAI;AAChC,QAAI,QAAQ,KAAM;AAGlB,QAAI,SAAS,KAAK,IAAI,CAAE;AAGxB,QAAI,IAAI,WAAW,IAAI,CAAE;AAGzB,QAAI,IAAI,WAAW,IAAI,CAAE;AAGzB,QAAI,IAAI,WAAW,IAAI,CAAE;AAGzB,QAAI,IAAI,WAAW,IAAI,CAAE;AAGzB,QAAI,IAAI,WAAW,KAAK,CAAE;AAG1B,QAAI,IAAI,WAAW,IAAI,CAAE;AAGzB,QAAI,uBAAuB,IAAI,IAAI,CAAE;AAGrC,QAAI,qBAAqB,IAAI,IAAI,CAAE;AAGnC,QAAI,mBAAmB,IAAI,IAAI,CAAE;AAGjC,QAAI,OAAO,kBAAmB;AAG9B,QAAI,IAAI,OAAO,OAAO,SAAS,IAAI,CAAE;AAGrC,QACE,KAAK,MAAM,SAAS,sBACpB,KAAK,QAAQ,SAAS,YACtB;KACA,MAAM,aAAa,KAAK;AACxB,SAAI,CAAC,WAAW,YAAY,IAAI,WAAW,MAAM,WAAW,CAC1D;;AAIJ,YAAQ,OAAO;KACb,MAAM,KAAK;KACX,WAAW;KACX,MAAM,EAAE,MAAM,KAAK;KACpB,CAAC;;;AAIN,SAAO;GACL,kBAAkB,MAAM;AACtB,QAAI,YAAY,KAAK;;GAEvB,GAAG,qBAAqB,kBAAkB;GAC3C;;CAEJ,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createRule } from "../create-rule.js";
|
|
2
|
-
import { TastyContext } from "../context.js";
|
|
3
2
|
import { getKeyName, getStringValue } from "../utils.js";
|
|
3
|
+
import { TastyContext, styleObjectListeners } from "../context.js";
|
|
4
4
|
|
|
5
5
|
//#region src/rules/no-duplicate-state.ts
|
|
6
6
|
var no_duplicate_state_default = createRule({
|
|
@@ -28,20 +28,21 @@ var no_duplicate_state_default = createRule({
|
|
|
28
28
|
else seen.set(key, prop.key);
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
|
+
function handleStyleObject(node) {
|
|
32
|
+
if (!ctx.isStyleObject(node)) return;
|
|
33
|
+
for (const prop of node.properties) {
|
|
34
|
+
if (prop.type !== "Property" || prop.computed) continue;
|
|
35
|
+
const key = getKeyName(prop.key);
|
|
36
|
+
if (key === null) continue;
|
|
37
|
+
if (/^[A-Z@&]/.test(key)) continue;
|
|
38
|
+
if (prop.value.type === "ObjectExpression") checkDuplicates(prop.value);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
31
41
|
return {
|
|
32
42
|
ImportDeclaration(node) {
|
|
33
43
|
ctx.trackImport(node);
|
|
34
44
|
},
|
|
35
|
-
|
|
36
|
-
if (!ctx.isStyleObject(node)) return;
|
|
37
|
-
for (const prop of node.properties) {
|
|
38
|
-
if (prop.type !== "Property" || prop.computed) continue;
|
|
39
|
-
const key = getKeyName(prop.key);
|
|
40
|
-
if (key === null) continue;
|
|
41
|
-
if (/^[A-Z@&]/.test(key)) continue;
|
|
42
|
-
if (prop.value.type === "ObjectExpression") checkDuplicates(prop.value);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
+
...styleObjectListeners(handleStyleObject)
|
|
45
46
|
};
|
|
46
47
|
}
|
|
47
48
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"no-duplicate-state.js","names":[],"sources":["../../src/rules/no-duplicate-state.ts"],"sourcesContent":["import type { TSESTree } from '@typescript-eslint/utils';\nimport { createRule } from '../create-rule.js';\nimport { TastyContext } from '../context.js';\nimport { getKeyName, getStringValue } from '../utils.js';\n\ntype MessageIds = 'duplicateState';\n\nexport default createRule<[], MessageIds>({\n name: 'no-duplicate-state',\n meta: {\n type: 'suggestion',\n docs: {\n description:\n 'Warn when the same state key appears more than once in a style mapping',\n },\n messages: {\n duplicateState: \"Duplicate state key '{{key}}'.\",\n },\n schema: [],\n },\n defaultOptions: [],\n create(context) {\n const ctx = new TastyContext(context);\n\n function checkDuplicates(obj: TSESTree.ObjectExpression): void {\n const seen = new Map<string, TSESTree.Node>();\n\n for (const prop of obj.properties) {\n if (prop.type !== 'Property') continue;\n\n const key = !prop.computed\n ? getKeyName(prop.key)\n : getStringValue(prop.key);\n\n if (key === null) continue;\n\n if (seen.has(key)) {\n context.report({\n node: prop.key,\n messageId: 'duplicateState',\n data: { key },\n });\n } else {\n seen.set(key, prop.key);\n }\n }\n }\n\n
|
|
1
|
+
{"version":3,"file":"no-duplicate-state.js","names":[],"sources":["../../src/rules/no-duplicate-state.ts"],"sourcesContent":["import type { TSESTree } from '@typescript-eslint/utils';\nimport { createRule } from '../create-rule.js';\nimport { TastyContext, styleObjectListeners } from '../context.js';\nimport { getKeyName, getStringValue } from '../utils.js';\n\ntype MessageIds = 'duplicateState';\n\nexport default createRule<[], MessageIds>({\n name: 'no-duplicate-state',\n meta: {\n type: 'suggestion',\n docs: {\n description:\n 'Warn when the same state key appears more than once in a style mapping',\n },\n messages: {\n duplicateState: \"Duplicate state key '{{key}}'.\",\n },\n schema: [],\n },\n defaultOptions: [],\n create(context) {\n const ctx = new TastyContext(context);\n\n function checkDuplicates(obj: TSESTree.ObjectExpression): void {\n const seen = new Map<string, TSESTree.Node>();\n\n for (const prop of obj.properties) {\n if (prop.type !== 'Property') continue;\n\n const key = !prop.computed\n ? getKeyName(prop.key)\n : getStringValue(prop.key);\n\n if (key === null) continue;\n\n if (seen.has(key)) {\n context.report({\n node: prop.key,\n messageId: 'duplicateState',\n data: { key },\n });\n } else {\n seen.set(key, prop.key);\n }\n }\n }\n\n function handleStyleObject(node: TSESTree.ObjectExpression) {\n if (!ctx.isStyleObject(node)) return;\n\n for (const prop of node.properties) {\n if (prop.type !== 'Property' || prop.computed) continue;\n\n const key = getKeyName(prop.key);\n if (key === null) continue;\n\n // Skip sub-elements and special keys\n if (/^[A-Z@&]/.test(key)) continue;\n\n // Check state map objects for duplicates\n if (prop.value.type === 'ObjectExpression') {\n checkDuplicates(prop.value);\n }\n }\n }\n\n return {\n ImportDeclaration(node) {\n ctx.trackImport(node);\n },\n ...styleObjectListeners(handleStyleObject),\n };\n },\n});\n"],"mappings":";;;;;AAOA,iCAAe,WAA2B;CACxC,MAAM;CACN,MAAM;EACJ,MAAM;EACN,MAAM,EACJ,aACE,0EACH;EACD,UAAU,EACR,gBAAgB,kCACjB;EACD,QAAQ,EAAE;EACX;CACD,gBAAgB,EAAE;CAClB,OAAO,SAAS;EACd,MAAM,MAAM,IAAI,aAAa,QAAQ;EAErC,SAAS,gBAAgB,KAAsC;GAC7D,MAAM,uBAAO,IAAI,KAA4B;AAE7C,QAAK,MAAM,QAAQ,IAAI,YAAY;AACjC,QAAI,KAAK,SAAS,WAAY;IAE9B,MAAM,MAAM,CAAC,KAAK,WACd,WAAW,KAAK,IAAI,GACpB,eAAe,KAAK,IAAI;AAE5B,QAAI,QAAQ,KAAM;AAElB,QAAI,KAAK,IAAI,IAAI,CACf,SAAQ,OAAO;KACb,MAAM,KAAK;KACX,WAAW;KACX,MAAM,EAAE,KAAK;KACd,CAAC;QAEF,MAAK,IAAI,KAAK,KAAK,IAAI;;;EAK7B,SAAS,kBAAkB,MAAiC;AAC1D,OAAI,CAAC,IAAI,cAAc,KAAK,CAAE;AAE9B,QAAK,MAAM,QAAQ,KAAK,YAAY;AAClC,QAAI,KAAK,SAAS,cAAc,KAAK,SAAU;IAE/C,MAAM,MAAM,WAAW,KAAK,IAAI;AAChC,QAAI,QAAQ,KAAM;AAGlB,QAAI,WAAW,KAAK,IAAI,CAAE;AAG1B,QAAI,KAAK,MAAM,SAAS,mBACtB,iBAAgB,KAAK,MAAM;;;AAKjC,SAAO;GACL,kBAAkB,MAAM;AACtB,QAAI,YAAY,KAAK;;GAEvB,GAAG,qBAAqB,kBAAkB;GAC3C;;CAEJ,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createRule } from "../create-rule.js";
|
|
2
|
-
import { TastyContext } from "../context.js";
|
|
3
2
|
import { getStringValue } from "../utils.js";
|
|
3
|
+
import { TastyContext, styleObjectListeners } from "../context.js";
|
|
4
4
|
|
|
5
5
|
//#region src/rules/no-important.ts
|
|
6
6
|
var no_important_default = createRule({
|
|
@@ -21,20 +21,21 @@ var no_important_default = createRule({
|
|
|
21
21
|
messageId: "noImportant"
|
|
22
22
|
});
|
|
23
23
|
}
|
|
24
|
+
function handleStyleObject(node) {
|
|
25
|
+
if (!ctx.isStyleObject(node)) return;
|
|
26
|
+
for (const prop of node.properties) {
|
|
27
|
+
if (prop.type !== "Property") continue;
|
|
28
|
+
checkNode(prop.value);
|
|
29
|
+
if (prop.value.type === "ObjectExpression") {
|
|
30
|
+
for (const stateProp of prop.value.properties) if (stateProp.type === "Property") checkNode(stateProp.value);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
24
34
|
return {
|
|
25
35
|
ImportDeclaration(node) {
|
|
26
36
|
ctx.trackImport(node);
|
|
27
37
|
},
|
|
28
|
-
|
|
29
|
-
if (!ctx.isStyleObject(node)) return;
|
|
30
|
-
for (const prop of node.properties) {
|
|
31
|
-
if (prop.type !== "Property") continue;
|
|
32
|
-
checkNode(prop.value);
|
|
33
|
-
if (prop.value.type === "ObjectExpression") {
|
|
34
|
-
for (const stateProp of prop.value.properties) if (stateProp.type === "Property") checkNode(stateProp.value);
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
+
...styleObjectListeners(handleStyleObject)
|
|
38
39
|
};
|
|
39
40
|
}
|
|
40
41
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"no-important.js","names":[],"sources":["../../src/rules/no-important.ts"],"sourcesContent":["import type { TSESTree } from '@typescript-eslint/utils';\nimport { createRule } from '../create-rule.js';\nimport { TastyContext } from '../context.js';\nimport { getStringValue } from '../utils.js';\n\ntype MessageIds = 'noImportant';\n\nexport default createRule<[], MessageIds>({\n name: 'no-important',\n meta: {\n type: 'problem',\n docs: {\n description: 'Disallow !important in tasty style values',\n },\n messages: {\n noImportant:\n 'Do not use !important in tasty styles. The tasty system manages specificity via doubled selectors and state ordering.',\n },\n schema: [],\n },\n defaultOptions: [],\n create(context) {\n const ctx = new TastyContext(context);\n\n function checkNode(node: TSESTree.Node): void {\n const str = getStringValue(node);\n if (str && str.includes('!important')) {\n context.report({ node, messageId: 'noImportant' });\n }\n }\n\n
|
|
1
|
+
{"version":3,"file":"no-important.js","names":[],"sources":["../../src/rules/no-important.ts"],"sourcesContent":["import type { TSESTree } from '@typescript-eslint/utils';\nimport { createRule } from '../create-rule.js';\nimport { TastyContext, styleObjectListeners } from '../context.js';\nimport { getStringValue } from '../utils.js';\n\ntype MessageIds = 'noImportant';\n\nexport default createRule<[], MessageIds>({\n name: 'no-important',\n meta: {\n type: 'problem',\n docs: {\n description: 'Disallow !important in tasty style values',\n },\n messages: {\n noImportant:\n 'Do not use !important in tasty styles. The tasty system manages specificity via doubled selectors and state ordering.',\n },\n schema: [],\n },\n defaultOptions: [],\n create(context) {\n const ctx = new TastyContext(context);\n\n function checkNode(node: TSESTree.Node): void {\n const str = getStringValue(node);\n if (str && str.includes('!important')) {\n context.report({ node, messageId: 'noImportant' });\n }\n }\n\n function handleStyleObject(node: TSESTree.ObjectExpression) {\n if (!ctx.isStyleObject(node)) return;\n\n for (const prop of node.properties) {\n if (prop.type !== 'Property') continue;\n\n checkNode(prop.value);\n\n if (prop.value.type === 'ObjectExpression') {\n for (const stateProp of prop.value.properties) {\n if (stateProp.type === 'Property') {\n checkNode(stateProp.value);\n }\n }\n }\n }\n }\n\n return {\n ImportDeclaration(node) {\n ctx.trackImport(node);\n },\n ...styleObjectListeners(handleStyleObject),\n };\n },\n});\n"],"mappings":";;;;;AAOA,2BAAe,WAA2B;CACxC,MAAM;CACN,MAAM;EACJ,MAAM;EACN,MAAM,EACJ,aAAa,6CACd;EACD,UAAU,EACR,aACE,yHACH;EACD,QAAQ,EAAE;EACX;CACD,gBAAgB,EAAE;CAClB,OAAO,SAAS;EACd,MAAM,MAAM,IAAI,aAAa,QAAQ;EAErC,SAAS,UAAU,MAA2B;GAC5C,MAAM,MAAM,eAAe,KAAK;AAChC,OAAI,OAAO,IAAI,SAAS,aAAa,CACnC,SAAQ,OAAO;IAAE;IAAM,WAAW;IAAe,CAAC;;EAItD,SAAS,kBAAkB,MAAiC;AAC1D,OAAI,CAAC,IAAI,cAAc,KAAK,CAAE;AAE9B,QAAK,MAAM,QAAQ,KAAK,YAAY;AAClC,QAAI,KAAK,SAAS,WAAY;AAE9B,cAAU,KAAK,MAAM;AAErB,QAAI,KAAK,MAAM,SAAS,oBACtB;UAAK,MAAM,aAAa,KAAK,MAAM,WACjC,KAAI,UAAU,SAAS,WACrB,WAAU,UAAU,MAAM;;;;AAOpC,SAAO;GACL,kBAAkB,MAAM;AACtB,QAAI,YAAY,KAAK;;GAEvB,GAAG,qBAAqB,kBAAkB;GAC3C;;CAEJ,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createRule } from "../create-rule.js";
|
|
2
|
-
import { TastyContext } from "../context.js";
|
|
3
2
|
import { getKeyName } from "../utils.js";
|
|
3
|
+
import { TastyContext, styleObjectListeners } from "../context.js";
|
|
4
4
|
|
|
5
5
|
//#region src/rules/no-nested-selector.ts
|
|
6
6
|
var no_nested_selector_default = createRule({
|
|
@@ -14,23 +14,24 @@ var no_nested_selector_default = createRule({
|
|
|
14
14
|
defaultOptions: [],
|
|
15
15
|
create(context) {
|
|
16
16
|
const ctx = new TastyContext(context);
|
|
17
|
+
function handleStyleObject(node) {
|
|
18
|
+
if (!ctx.isStyleObject(node)) return;
|
|
19
|
+
for (const prop of node.properties) {
|
|
20
|
+
if (prop.type !== "Property" || prop.computed) continue;
|
|
21
|
+
const key = getKeyName(prop.key);
|
|
22
|
+
if (key === null) continue;
|
|
23
|
+
if (key.startsWith("&") && !key.startsWith("&::")) context.report({
|
|
24
|
+
node: prop.key,
|
|
25
|
+
messageId: "noNestedSelector",
|
|
26
|
+
data: { key }
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
}
|
|
17
30
|
return {
|
|
18
31
|
ImportDeclaration(node) {
|
|
19
32
|
ctx.trackImport(node);
|
|
20
33
|
},
|
|
21
|
-
|
|
22
|
-
if (!ctx.isStyleObject(node)) return;
|
|
23
|
-
for (const prop of node.properties) {
|
|
24
|
-
if (prop.type !== "Property" || prop.computed) continue;
|
|
25
|
-
const key = getKeyName(prop.key);
|
|
26
|
-
if (key === null) continue;
|
|
27
|
-
if (key.startsWith("&") && !key.startsWith("&::")) context.report({
|
|
28
|
-
node: prop.key,
|
|
29
|
-
messageId: "noNestedSelector",
|
|
30
|
-
data: { key }
|
|
31
|
-
});
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
+
...styleObjectListeners(handleStyleObject)
|
|
34
35
|
};
|
|
35
36
|
}
|
|
36
37
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"no-nested-selector.js","names":[],"sources":["../../src/rules/no-nested-selector.ts"],"sourcesContent":["import type { TSESTree } from '@typescript-eslint/utils';\nimport { createRule } from '../create-rule.js';\nimport { TastyContext } from '../context.js';\nimport { getKeyName } from '../utils.js';\n\ntype MessageIds = 'noNestedSelector';\n\nexport default createRule<[], MessageIds>({\n name: 'no-nested-selector',\n meta: {\n type: 'suggestion',\n docs: {\n description:\n 'Discourage &-prefixed nested selectors in favor of sub-element styling',\n },\n messages: {\n noNestedSelector:\n \"Avoid nested selectors ('{{key}}'). Use sub-element styling with capitalized keys and data-element attributes instead.\",\n },\n schema: [],\n },\n defaultOptions: [],\n create(context) {\n const ctx = new TastyContext(context);\n\n
|
|
1
|
+
{"version":3,"file":"no-nested-selector.js","names":[],"sources":["../../src/rules/no-nested-selector.ts"],"sourcesContent":["import type { TSESTree } from '@typescript-eslint/utils';\nimport { createRule } from '../create-rule.js';\nimport { TastyContext, styleObjectListeners } from '../context.js';\nimport { getKeyName } from '../utils.js';\n\ntype MessageIds = 'noNestedSelector';\n\nexport default createRule<[], MessageIds>({\n name: 'no-nested-selector',\n meta: {\n type: 'suggestion',\n docs: {\n description:\n 'Discourage &-prefixed nested selectors in favor of sub-element styling',\n },\n messages: {\n noNestedSelector:\n \"Avoid nested selectors ('{{key}}'). Use sub-element styling with capitalized keys and data-element attributes instead.\",\n },\n schema: [],\n },\n defaultOptions: [],\n create(context) {\n const ctx = new TastyContext(context);\n\n function handleStyleObject(node: TSESTree.ObjectExpression) {\n if (!ctx.isStyleObject(node)) return;\n\n for (const prop of node.properties) {\n if (prop.type !== 'Property' || prop.computed) continue;\n\n const key = getKeyName(prop.key);\n if (key === null) continue;\n\n if (key.startsWith('&') && !key.startsWith('&::')) {\n context.report({\n node: prop.key,\n messageId: 'noNestedSelector',\n data: { key },\n });\n }\n }\n }\n\n return {\n ImportDeclaration(node) {\n ctx.trackImport(node);\n },\n\n ...styleObjectListeners(handleStyleObject),\n };\n },\n});\n"],"mappings":";;;;;AAOA,iCAAe,WAA2B;CACxC,MAAM;CACN,MAAM;EACJ,MAAM;EACN,MAAM,EACJ,aACE,0EACH;EACD,UAAU,EACR,kBACE,0HACH;EACD,QAAQ,EAAE;EACX;CACD,gBAAgB,EAAE;CAClB,OAAO,SAAS;EACd,MAAM,MAAM,IAAI,aAAa,QAAQ;EAErC,SAAS,kBAAkB,MAAiC;AAC1D,OAAI,CAAC,IAAI,cAAc,KAAK,CAAE;AAE9B,QAAK,MAAM,QAAQ,KAAK,YAAY;AAClC,QAAI,KAAK,SAAS,cAAc,KAAK,SAAU;IAE/C,MAAM,MAAM,WAAW,KAAK,IAAI;AAChC,QAAI,QAAQ,KAAM;AAElB,QAAI,IAAI,WAAW,IAAI,IAAI,CAAC,IAAI,WAAW,MAAM,CAC/C,SAAQ,OAAO;KACb,MAAM,KAAK;KACX,WAAW;KACX,MAAM,EAAE,KAAK;KACd,CAAC;;;AAKR,SAAO;GACL,kBAAkB,MAAM;AACtB,QAAI,YAAY,KAAK;;GAGvB,GAAG,qBAAqB,kBAAkB;GAC3C;;CAEJ,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createRule } from "../create-rule.js";
|
|
2
|
-
import { TastyContext } from "../context.js";
|
|
3
2
|
import { getKeyName } from "../utils.js";
|
|
3
|
+
import { TastyContext, styleObjectListeners } from "../context.js";
|
|
4
4
|
|
|
5
5
|
//#region src/rules/no-nested-state-map.ts
|
|
6
6
|
var no_nested_state_map_default = createRule({
|
|
@@ -14,27 +14,28 @@ var no_nested_state_map_default = createRule({
|
|
|
14
14
|
defaultOptions: [],
|
|
15
15
|
create(context) {
|
|
16
16
|
const ctx = new TastyContext(context);
|
|
17
|
+
function handleStyleObject(node) {
|
|
18
|
+
if (!ctx.isStyleObject(node)) return;
|
|
19
|
+
for (const prop of node.properties) {
|
|
20
|
+
if (prop.type !== "Property" || prop.computed) continue;
|
|
21
|
+
const key = getKeyName(prop.key);
|
|
22
|
+
if (key === null) continue;
|
|
23
|
+
if (/^[A-Z@&]/.test(key)) continue;
|
|
24
|
+
if (prop.value.type !== "ObjectExpression") continue;
|
|
25
|
+
for (const stateProp of prop.value.properties) {
|
|
26
|
+
if (stateProp.type !== "Property") continue;
|
|
27
|
+
if (stateProp.value.type === "ObjectExpression") context.report({
|
|
28
|
+
node: stateProp.value,
|
|
29
|
+
messageId: "nestedStateMap"
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
17
34
|
return {
|
|
18
35
|
ImportDeclaration(node) {
|
|
19
36
|
ctx.trackImport(node);
|
|
20
37
|
},
|
|
21
|
-
|
|
22
|
-
if (!ctx.isStyleObject(node)) return;
|
|
23
|
-
for (const prop of node.properties) {
|
|
24
|
-
if (prop.type !== "Property" || prop.computed) continue;
|
|
25
|
-
const key = getKeyName(prop.key);
|
|
26
|
-
if (key === null) continue;
|
|
27
|
-
if (/^[A-Z@&]/.test(key)) continue;
|
|
28
|
-
if (prop.value.type !== "ObjectExpression") continue;
|
|
29
|
-
for (const stateProp of prop.value.properties) {
|
|
30
|
-
if (stateProp.type !== "Property") continue;
|
|
31
|
-
if (stateProp.value.type === "ObjectExpression") context.report({
|
|
32
|
-
node: stateProp.value,
|
|
33
|
-
messageId: "nestedStateMap"
|
|
34
|
-
});
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
+
...styleObjectListeners(handleStyleObject)
|
|
38
39
|
};
|
|
39
40
|
}
|
|
40
41
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"no-nested-state-map.js","names":[],"sources":["../../src/rules/no-nested-state-map.ts"],"sourcesContent":["import type { TSESTree } from '@typescript-eslint/utils';\nimport { createRule } from '../create-rule.js';\nimport { TastyContext } from '../context.js';\nimport { getKeyName } from '../utils.js';\n\ntype MessageIds = 'nestedStateMap';\n\nexport default createRule<[], MessageIds>({\n name: 'no-nested-state-map',\n meta: {\n type: 'problem',\n docs: {\n description: 'Prevent state mapping objects inside state mapping objects',\n },\n messages: {\n nestedStateMap:\n \"Nested state maps are not allowed. Use combined state keys instead (e.g., 'hovered & pressed').\",\n },\n schema: [],\n },\n defaultOptions: [],\n create(context) {\n const ctx = new TastyContext(context);\n\n
|
|
1
|
+
{"version":3,"file":"no-nested-state-map.js","names":[],"sources":["../../src/rules/no-nested-state-map.ts"],"sourcesContent":["import type { TSESTree } from '@typescript-eslint/utils';\nimport { createRule } from '../create-rule.js';\nimport { TastyContext, styleObjectListeners } from '../context.js';\nimport { getKeyName } from '../utils.js';\n\ntype MessageIds = 'nestedStateMap';\n\nexport default createRule<[], MessageIds>({\n name: 'no-nested-state-map',\n meta: {\n type: 'problem',\n docs: {\n description: 'Prevent state mapping objects inside state mapping objects',\n },\n messages: {\n nestedStateMap:\n \"Nested state maps are not allowed. Use combined state keys instead (e.g., 'hovered & pressed').\",\n },\n schema: [],\n },\n defaultOptions: [],\n create(context) {\n const ctx = new TastyContext(context);\n\n function handleStyleObject(node: TSESTree.ObjectExpression) {\n if (!ctx.isStyleObject(node)) return;\n\n for (const prop of node.properties) {\n if (prop.type !== 'Property' || prop.computed) continue;\n\n const key = getKeyName(prop.key);\n if (key === null) continue;\n\n // Skip sub-elements and special keys\n if (/^[A-Z@&]/.test(key)) continue;\n\n // If value is an object (state map), check for nested objects\n if (prop.value.type !== 'ObjectExpression') continue;\n\n for (const stateProp of prop.value.properties) {\n if (stateProp.type !== 'Property') continue;\n\n if (stateProp.value.type === 'ObjectExpression') {\n context.report({\n node: stateProp.value,\n messageId: 'nestedStateMap',\n });\n }\n }\n }\n }\n\n return {\n ImportDeclaration(node) {\n ctx.trackImport(node);\n },\n ...styleObjectListeners(handleStyleObject),\n };\n },\n});\n"],"mappings":";;;;;AAOA,kCAAe,WAA2B;CACxC,MAAM;CACN,MAAM;EACJ,MAAM;EACN,MAAM,EACJ,aAAa,8DACd;EACD,UAAU,EACR,gBACE,mGACH;EACD,QAAQ,EAAE;EACX;CACD,gBAAgB,EAAE;CAClB,OAAO,SAAS;EACd,MAAM,MAAM,IAAI,aAAa,QAAQ;EAErC,SAAS,kBAAkB,MAAiC;AAC1D,OAAI,CAAC,IAAI,cAAc,KAAK,CAAE;AAE9B,QAAK,MAAM,QAAQ,KAAK,YAAY;AAClC,QAAI,KAAK,SAAS,cAAc,KAAK,SAAU;IAE/C,MAAM,MAAM,WAAW,KAAK,IAAI;AAChC,QAAI,QAAQ,KAAM;AAGlB,QAAI,WAAW,KAAK,IAAI,CAAE;AAG1B,QAAI,KAAK,MAAM,SAAS,mBAAoB;AAE5C,SAAK,MAAM,aAAa,KAAK,MAAM,YAAY;AAC7C,SAAI,UAAU,SAAS,WAAY;AAEnC,SAAI,UAAU,MAAM,SAAS,mBAC3B,SAAQ,OAAO;MACb,MAAM,UAAU;MAChB,WAAW;MACZ,CAAC;;;;AAMV,SAAO;GACL,kBAAkB,MAAM;AACtB,QAAI,YAAY,KAAK;;GAEvB,GAAG,qBAAqB,kBAAkB;GAC3C;;CAEJ,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createRule } from "../create-rule.js";
|
|
2
|
-
import { TastyContext } from "../context.js";
|
|
3
2
|
import { getStringValue } from "../utils.js";
|
|
3
|
+
import { TastyContext, styleObjectListeners } from "../context.js";
|
|
4
4
|
|
|
5
5
|
//#region src/rules/no-raw-color-values.ts
|
|
6
6
|
const HEX_COLOR_REGEX = /#([0-9a-fA-F]{3,8})\b/g;
|
|
@@ -58,23 +58,24 @@ var no_raw_color_values_default = createRule({
|
|
|
58
58
|
data: { func: match[1] }
|
|
59
59
|
});
|
|
60
60
|
}
|
|
61
|
+
function handleStyleObject(node) {
|
|
62
|
+
if (!ctx.isStyleObject(node)) return;
|
|
63
|
+
for (const prop of node.properties) {
|
|
64
|
+
if (prop.type !== "Property") continue;
|
|
65
|
+
const str = getStringValue(prop.value);
|
|
66
|
+
if (str) checkValue(str, prop.value);
|
|
67
|
+
if (prop.value.type === "ObjectExpression") for (const stateProp of prop.value.properties) {
|
|
68
|
+
if (stateProp.type !== "Property") continue;
|
|
69
|
+
const stateStr = getStringValue(stateProp.value);
|
|
70
|
+
if (stateStr) checkValue(stateStr, stateProp.value);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
61
74
|
return {
|
|
62
75
|
ImportDeclaration(node) {
|
|
63
76
|
ctx.trackImport(node);
|
|
64
77
|
},
|
|
65
|
-
|
|
66
|
-
if (!ctx.isStyleObject(node)) return;
|
|
67
|
-
for (const prop of node.properties) {
|
|
68
|
-
if (prop.type !== "Property") continue;
|
|
69
|
-
const str = getStringValue(prop.value);
|
|
70
|
-
if (str) checkValue(str, prop.value);
|
|
71
|
-
if (prop.value.type === "ObjectExpression") for (const stateProp of prop.value.properties) {
|
|
72
|
-
if (stateProp.type !== "Property") continue;
|
|
73
|
-
const stateStr = getStringValue(stateProp.value);
|
|
74
|
-
if (stateStr) checkValue(stateStr, stateProp.value);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
+
...styleObjectListeners(handleStyleObject)
|
|
78
79
|
};
|
|
79
80
|
}
|
|
80
81
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"no-raw-color-values.js","names":[],"sources":["../../src/rules/no-raw-color-values.ts"],"sourcesContent":["import type { TSESTree } from '@typescript-eslint/utils';\nimport { createRule } from '../create-rule.js';\nimport { TastyContext } from '../context.js';\nimport { getStringValue } from '../utils.js';\n\ntype MessageIds = 'rawHexColor' | 'rawColorFunction';\n\nconst HEX_COLOR_REGEX = /#([0-9a-fA-F]{3,8})\\b/g;\nconst COLOR_FUNC_REGEX = /\\b(rgb|rgba|hsl|hsla)\\s*\\(/gi;\n\nexport default createRule<[], MessageIds>({\n name: 'no-raw-color-values',\n meta: {\n type: 'suggestion',\n docs: {\n description: 'Suggest using color tokens instead of raw hex/rgb values',\n },\n messages: {\n rawHexColor: \"Use a color token instead of raw hex color '{{value}}'.\",\n rawColorFunction: 'Use a color token instead of raw {{func}}() color.',\n },\n schema: [],\n },\n defaultOptions: [],\n create(context) {\n const ctx = new TastyContext(context);\n\n function isInTokenDefinition(node: TSESTree.Node): boolean {\n // Check if this is inside a :root or token-defining context\n let current: TSESTree.Node | undefined = node;\n while (current) {\n if (current.type === 'CallExpression') {\n const imp = ctx.isTastyCall(current);\n if (imp && imp.importedName === 'tastyStatic') {\n const firstArg = current.arguments[0];\n const selectorStr = getStringValue(firstArg);\n if (selectorStr === ':root') return true;\n }\n break;\n }\n current = current.parent;\n }\n return false;\n }\n\n function checkValue(value: string, node: TSESTree.Node): void {\n if (isInTokenDefinition(node)) return;\n\n // Check hex colors\n HEX_COLOR_REGEX.lastIndex = 0;\n let match;\n while ((match = HEX_COLOR_REGEX.exec(value)) !== null) {\n const hex = match[1];\n if ([3, 4, 6, 8].includes(hex.length)) {\n context.report({\n node,\n messageId: 'rawHexColor',\n data: { value: match[0] },\n });\n }\n }\n\n // Check color functions\n COLOR_FUNC_REGEX.lastIndex = 0;\n while ((match = COLOR_FUNC_REGEX.exec(value)) !== null) {\n context.report({\n node,\n messageId: 'rawColorFunction',\n data: { func: match[1] },\n });\n }\n }\n\n
|
|
1
|
+
{"version":3,"file":"no-raw-color-values.js","names":[],"sources":["../../src/rules/no-raw-color-values.ts"],"sourcesContent":["import type { TSESTree } from '@typescript-eslint/utils';\nimport { createRule } from '../create-rule.js';\nimport { TastyContext, styleObjectListeners } from '../context.js';\nimport { getStringValue } from '../utils.js';\n\ntype MessageIds = 'rawHexColor' | 'rawColorFunction';\n\nconst HEX_COLOR_REGEX = /#([0-9a-fA-F]{3,8})\\b/g;\nconst COLOR_FUNC_REGEX = /\\b(rgb|rgba|hsl|hsla)\\s*\\(/gi;\n\nexport default createRule<[], MessageIds>({\n name: 'no-raw-color-values',\n meta: {\n type: 'suggestion',\n docs: {\n description: 'Suggest using color tokens instead of raw hex/rgb values',\n },\n messages: {\n rawHexColor: \"Use a color token instead of raw hex color '{{value}}'.\",\n rawColorFunction: 'Use a color token instead of raw {{func}}() color.',\n },\n schema: [],\n },\n defaultOptions: [],\n create(context) {\n const ctx = new TastyContext(context);\n\n function isInTokenDefinition(node: TSESTree.Node): boolean {\n // Check if this is inside a :root or token-defining context\n let current: TSESTree.Node | undefined = node;\n while (current) {\n if (current.type === 'CallExpression') {\n const imp = ctx.isTastyCall(current);\n if (imp && imp.importedName === 'tastyStatic') {\n const firstArg = current.arguments[0];\n const selectorStr = getStringValue(firstArg);\n if (selectorStr === ':root') return true;\n }\n break;\n }\n current = current.parent;\n }\n return false;\n }\n\n function checkValue(value: string, node: TSESTree.Node): void {\n if (isInTokenDefinition(node)) return;\n\n // Check hex colors\n HEX_COLOR_REGEX.lastIndex = 0;\n let match;\n while ((match = HEX_COLOR_REGEX.exec(value)) !== null) {\n const hex = match[1];\n if ([3, 4, 6, 8].includes(hex.length)) {\n context.report({\n node,\n messageId: 'rawHexColor',\n data: { value: match[0] },\n });\n }\n }\n\n // Check color functions\n COLOR_FUNC_REGEX.lastIndex = 0;\n while ((match = COLOR_FUNC_REGEX.exec(value)) !== null) {\n context.report({\n node,\n messageId: 'rawColorFunction',\n data: { func: match[1] },\n });\n }\n }\n\n function handleStyleObject(node: TSESTree.ObjectExpression) {\n if (!ctx.isStyleObject(node)) return;\n\n for (const prop of node.properties) {\n if (prop.type !== 'Property') continue;\n\n const str = getStringValue(prop.value);\n if (str) checkValue(str, prop.value);\n\n if (prop.value.type === 'ObjectExpression') {\n for (const stateProp of prop.value.properties) {\n if (stateProp.type !== 'Property') continue;\n const stateStr = getStringValue(stateProp.value);\n if (stateStr) checkValue(stateStr, stateProp.value);\n }\n }\n }\n }\n\n return {\n ImportDeclaration(node) {\n ctx.trackImport(node);\n },\n ...styleObjectListeners(handleStyleObject),\n };\n },\n});\n"],"mappings":";;;;;AAOA,MAAM,kBAAkB;AACxB,MAAM,mBAAmB;AAEzB,kCAAe,WAA2B;CACxC,MAAM;CACN,MAAM;EACJ,MAAM;EACN,MAAM,EACJ,aAAa,4DACd;EACD,UAAU;GACR,aAAa;GACb,kBAAkB;GACnB;EACD,QAAQ,EAAE;EACX;CACD,gBAAgB,EAAE;CAClB,OAAO,SAAS;EACd,MAAM,MAAM,IAAI,aAAa,QAAQ;EAErC,SAAS,oBAAoB,MAA8B;GAEzD,IAAI,UAAqC;AACzC,UAAO,SAAS;AACd,QAAI,QAAQ,SAAS,kBAAkB;KACrC,MAAM,MAAM,IAAI,YAAY,QAAQ;AACpC,SAAI,OAAO,IAAI,iBAAiB,eAAe;MAC7C,MAAM,WAAW,QAAQ,UAAU;AAEnC,UADoB,eAAe,SAAS,KACxB,QAAS,QAAO;;AAEtC;;AAEF,cAAU,QAAQ;;AAEpB,UAAO;;EAGT,SAAS,WAAW,OAAe,MAA2B;AAC5D,OAAI,oBAAoB,KAAK,CAAE;AAG/B,mBAAgB,YAAY;GAC5B,IAAI;AACJ,WAAQ,QAAQ,gBAAgB,KAAK,MAAM,MAAM,MAAM;IACrD,MAAM,MAAM,MAAM;AAClB,QAAI;KAAC;KAAG;KAAG;KAAG;KAAE,CAAC,SAAS,IAAI,OAAO,CACnC,SAAQ,OAAO;KACb;KACA,WAAW;KACX,MAAM,EAAE,OAAO,MAAM,IAAI;KAC1B,CAAC;;AAKN,oBAAiB,YAAY;AAC7B,WAAQ,QAAQ,iBAAiB,KAAK,MAAM,MAAM,KAChD,SAAQ,OAAO;IACb;IACA,WAAW;IACX,MAAM,EAAE,MAAM,MAAM,IAAI;IACzB,CAAC;;EAIN,SAAS,kBAAkB,MAAiC;AAC1D,OAAI,CAAC,IAAI,cAAc,KAAK,CAAE;AAE9B,QAAK,MAAM,QAAQ,KAAK,YAAY;AAClC,QAAI,KAAK,SAAS,WAAY;IAE9B,MAAM,MAAM,eAAe,KAAK,MAAM;AACtC,QAAI,IAAK,YAAW,KAAK,KAAK,MAAM;AAEpC,QAAI,KAAK,MAAM,SAAS,mBACtB,MAAK,MAAM,aAAa,KAAK,MAAM,YAAY;AAC7C,SAAI,UAAU,SAAS,WAAY;KACnC,MAAM,WAAW,eAAe,UAAU,MAAM;AAChD,SAAI,SAAU,YAAW,UAAU,UAAU,MAAM;;;;AAM3D,SAAO;GACL,kBAAkB,MAAM;AACtB,QAAI,YAAY,KAAK;;GAEvB,GAAG,qBAAqB,kBAAkB;GAC3C;;CAEJ,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createRule } from "../create-rule.js";
|
|
2
|
-
import { TastyContext } from "../context.js";
|
|
3
2
|
import { isStaticValue } from "../utils.js";
|
|
3
|
+
import { TastyContext, styleObjectListeners } from "../context.js";
|
|
4
4
|
|
|
5
5
|
//#region src/rules/no-runtime-styles-mutation.ts
|
|
6
6
|
var no_runtime_styles_mutation_default = createRule({
|
|
@@ -35,14 +35,15 @@ var no_runtime_styles_mutation_default = createRule({
|
|
|
35
35
|
});
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
|
+
function handleStyleObject(node) {
|
|
39
|
+
if (!ctx.isStyleObject(node)) return;
|
|
40
|
+
checkProperties(node);
|
|
41
|
+
}
|
|
38
42
|
return {
|
|
39
43
|
ImportDeclaration(node) {
|
|
40
44
|
ctx.trackImport(node);
|
|
41
45
|
},
|
|
42
|
-
|
|
43
|
-
if (!ctx.isStyleObject(node)) return;
|
|
44
|
-
checkProperties(node);
|
|
45
|
-
}
|
|
46
|
+
...styleObjectListeners(handleStyleObject)
|
|
46
47
|
};
|
|
47
48
|
}
|
|
48
49
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"no-runtime-styles-mutation.js","names":[],"sources":["../../src/rules/no-runtime-styles-mutation.ts"],"sourcesContent":["import type { TSESTree } from '@typescript-eslint/utils';\nimport { createRule } from '../create-rule.js';\nimport { TastyContext } from '../context.js';\nimport { isStaticValue } from '../utils.js';\n\ntype MessageIds = 'dynamicStyleValue';\n\nexport default createRule<[], MessageIds>({\n name: 'no-runtime-styles-mutation',\n meta: {\n type: 'suggestion',\n docs: {\n description: 'Warn when style objects contain runtime-computed values',\n },\n messages: {\n dynamicStyleValue:\n 'Style values should be static. Use modifiers (mods prop), tokens, or CSS custom properties for dynamic behavior.',\n },\n schema: [],\n },\n defaultOptions: [],\n create(context) {\n const ctx = new TastyContext(context);\n\n function checkProperties(node: TSESTree.ObjectExpression): void {\n for (const prop of node.properties) {\n if (prop.type === 'SpreadElement') {\n context.report({ node: prop, messageId: 'dynamicStyleValue' });\n continue;\n }\n\n if (prop.type !== 'Property') continue;\n\n // Skip sub-elements (they contain nested style objects)\n if (\n !prop.computed &&\n prop.key.type === 'Identifier' &&\n /^[A-Z]/.test(prop.key.name)\n ) {\n if (prop.value.type === 'ObjectExpression') {\n checkProperties(prop.value);\n }\n continue;\n }\n\n // Skip @keyframes and @properties\n if (\n !prop.computed &&\n prop.key.type === 'Identifier' &&\n prop.key.name.startsWith('@')\n ) {\n continue;\n }\n\n if (!isStaticValue(prop.value)) {\n context.report({\n node: prop.value,\n messageId: 'dynamicStyleValue',\n });\n }\n }\n }\n\n
|
|
1
|
+
{"version":3,"file":"no-runtime-styles-mutation.js","names":[],"sources":["../../src/rules/no-runtime-styles-mutation.ts"],"sourcesContent":["import type { TSESTree } from '@typescript-eslint/utils';\nimport { createRule } from '../create-rule.js';\nimport { TastyContext, styleObjectListeners } from '../context.js';\nimport { isStaticValue } from '../utils.js';\n\ntype MessageIds = 'dynamicStyleValue';\n\nexport default createRule<[], MessageIds>({\n name: 'no-runtime-styles-mutation',\n meta: {\n type: 'suggestion',\n docs: {\n description: 'Warn when style objects contain runtime-computed values',\n },\n messages: {\n dynamicStyleValue:\n 'Style values should be static. Use modifiers (mods prop), tokens, or CSS custom properties for dynamic behavior.',\n },\n schema: [],\n },\n defaultOptions: [],\n create(context) {\n const ctx = new TastyContext(context);\n\n function checkProperties(node: TSESTree.ObjectExpression): void {\n for (const prop of node.properties) {\n if (prop.type === 'SpreadElement') {\n context.report({ node: prop, messageId: 'dynamicStyleValue' });\n continue;\n }\n\n if (prop.type !== 'Property') continue;\n\n // Skip sub-elements (they contain nested style objects)\n if (\n !prop.computed &&\n prop.key.type === 'Identifier' &&\n /^[A-Z]/.test(prop.key.name)\n ) {\n if (prop.value.type === 'ObjectExpression') {\n checkProperties(prop.value);\n }\n continue;\n }\n\n // Skip @keyframes and @properties\n if (\n !prop.computed &&\n prop.key.type === 'Identifier' &&\n prop.key.name.startsWith('@')\n ) {\n continue;\n }\n\n if (!isStaticValue(prop.value)) {\n context.report({\n node: prop.value,\n messageId: 'dynamicStyleValue',\n });\n }\n }\n }\n\n function handleStyleObject(node: TSESTree.ObjectExpression) {\n if (!ctx.isStyleObject(node)) return;\n checkProperties(node);\n }\n\n return {\n ImportDeclaration(node) {\n ctx.trackImport(node);\n },\n ...styleObjectListeners(handleStyleObject),\n };\n },\n});\n"],"mappings":";;;;;AAOA,yCAAe,WAA2B;CACxC,MAAM;CACN,MAAM;EACJ,MAAM;EACN,MAAM,EACJ,aAAa,2DACd;EACD,UAAU,EACR,mBACE,oHACH;EACD,QAAQ,EAAE;EACX;CACD,gBAAgB,EAAE;CAClB,OAAO,SAAS;EACd,MAAM,MAAM,IAAI,aAAa,QAAQ;EAErC,SAAS,gBAAgB,MAAuC;AAC9D,QAAK,MAAM,QAAQ,KAAK,YAAY;AAClC,QAAI,KAAK,SAAS,iBAAiB;AACjC,aAAQ,OAAO;MAAE,MAAM;MAAM,WAAW;MAAqB,CAAC;AAC9D;;AAGF,QAAI,KAAK,SAAS,WAAY;AAG9B,QACE,CAAC,KAAK,YACN,KAAK,IAAI,SAAS,gBAClB,SAAS,KAAK,KAAK,IAAI,KAAK,EAC5B;AACA,SAAI,KAAK,MAAM,SAAS,mBACtB,iBAAgB,KAAK,MAAM;AAE7B;;AAIF,QACE,CAAC,KAAK,YACN,KAAK,IAAI,SAAS,gBAClB,KAAK,IAAI,KAAK,WAAW,IAAI,CAE7B;AAGF,QAAI,CAAC,cAAc,KAAK,MAAM,CAC5B,SAAQ,OAAO;KACb,MAAM,KAAK;KACX,WAAW;KACZ,CAAC;;;EAKR,SAAS,kBAAkB,MAAiC;AAC1D,OAAI,CAAC,IAAI,cAAc,KAAK,CAAE;AAC9B,mBAAgB,KAAK;;AAGvB,SAAO;GACL,kBAAkB,MAAM;AACtB,QAAI,YAAY,KAAK;;GAEvB,GAAG,qBAAqB,kBAAkB;GAC3C;;CAEJ,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createRule } from "../create-rule.js";
|
|
2
|
-
import { TastyContext } from "../context.js";
|
|
3
2
|
import { getKeyName, getStringValue, isKnownStateAlias } from "../utils.js";
|
|
3
|
+
import { TastyContext, styleObjectListeners } from "../context.js";
|
|
4
4
|
|
|
5
5
|
//#region src/rules/no-unknown-state-alias.ts
|
|
6
6
|
var no_unknown_state_alias_default = createRule({
|
|
@@ -26,20 +26,21 @@ var no_unknown_state_alias_default = createRule({
|
|
|
26
26
|
});
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
|
+
function handleStyleObject(node) {
|
|
30
|
+
if (!ctx.isStyleObject(node)) return;
|
|
31
|
+
if (ctx.config.states.length === 0) return;
|
|
32
|
+
for (const prop of node.properties) {
|
|
33
|
+
if (prop.type !== "Property" || prop.computed) continue;
|
|
34
|
+
const key = getKeyName(prop.key);
|
|
35
|
+
if (key === null || /^[A-Z@&]/.test(key)) continue;
|
|
36
|
+
if (prop.value.type === "ObjectExpression") checkStateKeys(prop.value);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
29
39
|
return {
|
|
30
40
|
ImportDeclaration(node) {
|
|
31
41
|
ctx.trackImport(node);
|
|
32
42
|
},
|
|
33
|
-
|
|
34
|
-
if (!ctx.isStyleObject(node)) return;
|
|
35
|
-
if (ctx.config.states.length === 0) return;
|
|
36
|
-
for (const prop of node.properties) {
|
|
37
|
-
if (prop.type !== "Property" || prop.computed) continue;
|
|
38
|
-
const key = getKeyName(prop.key);
|
|
39
|
-
if (key === null || /^[A-Z@&]/.test(key)) continue;
|
|
40
|
-
if (prop.value.type === "ObjectExpression") checkStateKeys(prop.value);
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
+
...styleObjectListeners(handleStyleObject)
|
|
43
44
|
};
|
|
44
45
|
}
|
|
45
46
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"no-unknown-state-alias.js","names":[],"sources":["../../src/rules/no-unknown-state-alias.ts"],"sourcesContent":["import type { TSESTree } from '@typescript-eslint/utils';\nimport { createRule } from '../create-rule.js';\nimport { TastyContext } from '../context.js';\nimport { getKeyName, getStringValue, isKnownStateAlias } from '../utils.js';\n\ntype MessageIds = 'unknownAlias';\n\nexport default createRule<[], MessageIds>({\n name: 'no-unknown-state-alias',\n meta: {\n type: 'suggestion',\n docs: {\n description:\n \"Warn when a @name state alias is used that isn't in the config\",\n },\n messages: {\n unknownAlias: \"Unknown state alias '{{alias}}'.\",\n },\n schema: [],\n },\n defaultOptions: [],\n create(context) {\n const ctx = new TastyContext(context);\n\n function checkStateKeys(obj: TSESTree.ObjectExpression): void {\n for (const prop of obj.properties) {\n if (prop.type !== 'Property') continue;\n\n const key = !prop.computed\n ? getKeyName(prop.key)\n : getStringValue(prop.key);\n if (key === null || !key.startsWith('@')) continue;\n\n if (!isKnownStateAlias(key, ctx.config)) {\n context.report({\n node: prop.key,\n messageId: 'unknownAlias',\n data: { alias: key },\n });\n }\n }\n }\n\n
|
|
1
|
+
{"version":3,"file":"no-unknown-state-alias.js","names":[],"sources":["../../src/rules/no-unknown-state-alias.ts"],"sourcesContent":["import type { TSESTree } from '@typescript-eslint/utils';\nimport { createRule } from '../create-rule.js';\nimport { TastyContext, styleObjectListeners } from '../context.js';\nimport { getKeyName, getStringValue, isKnownStateAlias } from '../utils.js';\n\ntype MessageIds = 'unknownAlias';\n\nexport default createRule<[], MessageIds>({\n name: 'no-unknown-state-alias',\n meta: {\n type: 'suggestion',\n docs: {\n description:\n \"Warn when a @name state alias is used that isn't in the config\",\n },\n messages: {\n unknownAlias: \"Unknown state alias '{{alias}}'.\",\n },\n schema: [],\n },\n defaultOptions: [],\n create(context) {\n const ctx = new TastyContext(context);\n\n function checkStateKeys(obj: TSESTree.ObjectExpression): void {\n for (const prop of obj.properties) {\n if (prop.type !== 'Property') continue;\n\n const key = !prop.computed\n ? getKeyName(prop.key)\n : getStringValue(prop.key);\n if (key === null || !key.startsWith('@')) continue;\n\n if (!isKnownStateAlias(key, ctx.config)) {\n context.report({\n node: prop.key,\n messageId: 'unknownAlias',\n data: { alias: key },\n });\n }\n }\n }\n\n function handleStyleObject(node: TSESTree.ObjectExpression) {\n if (!ctx.isStyleObject(node)) return;\n\n // Skip if no states configured\n if (ctx.config.states.length === 0) return;\n\n for (const prop of node.properties) {\n if (prop.type !== 'Property' || prop.computed) continue;\n\n // Skip sub-elements and special keys\n const key = getKeyName(prop.key);\n if (key === null || /^[A-Z@&]/.test(key)) continue;\n\n // Check state map objects for unknown aliases\n if (prop.value.type === 'ObjectExpression') {\n checkStateKeys(prop.value);\n }\n }\n }\n\n return {\n ImportDeclaration(node) {\n ctx.trackImport(node);\n },\n ...styleObjectListeners(handleStyleObject),\n };\n },\n});\n"],"mappings":";;;;;AAOA,qCAAe,WAA2B;CACxC,MAAM;CACN,MAAM;EACJ,MAAM;EACN,MAAM,EACJ,aACE,kEACH;EACD,UAAU,EACR,cAAc,oCACf;EACD,QAAQ,EAAE;EACX;CACD,gBAAgB,EAAE;CAClB,OAAO,SAAS;EACd,MAAM,MAAM,IAAI,aAAa,QAAQ;EAErC,SAAS,eAAe,KAAsC;AAC5D,QAAK,MAAM,QAAQ,IAAI,YAAY;AACjC,QAAI,KAAK,SAAS,WAAY;IAE9B,MAAM,MAAM,CAAC,KAAK,WACd,WAAW,KAAK,IAAI,GACpB,eAAe,KAAK,IAAI;AAC5B,QAAI,QAAQ,QAAQ,CAAC,IAAI,WAAW,IAAI,CAAE;AAE1C,QAAI,CAAC,kBAAkB,KAAK,IAAI,OAAO,CACrC,SAAQ,OAAO;KACb,MAAM,KAAK;KACX,WAAW;KACX,MAAM,EAAE,OAAO,KAAK;KACrB,CAAC;;;EAKR,SAAS,kBAAkB,MAAiC;AAC1D,OAAI,CAAC,IAAI,cAAc,KAAK,CAAE;AAG9B,OAAI,IAAI,OAAO,OAAO,WAAW,EAAG;AAEpC,QAAK,MAAM,QAAQ,KAAK,YAAY;AAClC,QAAI,KAAK,SAAS,cAAc,KAAK,SAAU;IAG/C,MAAM,MAAM,WAAW,KAAK,IAAI;AAChC,QAAI,QAAQ,QAAQ,WAAW,KAAK,IAAI,CAAE;AAG1C,QAAI,KAAK,MAAM,SAAS,mBACtB,gBAAe,KAAK,MAAM;;;AAKhC,SAAO;GACL,kBAAkB,MAAM;AACtB,QAAI,YAAY,KAAK;;GAEvB,GAAG,qBAAqB,kBAAkB;GAC3C;;CAEJ,CAAC"}
|