@tenphi/eslint-plugin-tasty 0.3.1 → 0.4.0

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 (72) hide show
  1. package/dist/config.js +100 -20
  2. package/dist/config.js.map +1 -1
  3. package/dist/configs.js +5 -4
  4. package/dist/configs.js.map +1 -1
  5. package/dist/constants.js +55 -1
  6. package/dist/constants.js.map +1 -1
  7. package/dist/context.js +37 -6
  8. package/dist/context.js.map +1 -1
  9. package/dist/index.js +3 -1
  10. package/dist/index.js.map +1 -1
  11. package/dist/parsers/state-key-parser.js +486 -0
  12. package/dist/parsers/state-key-parser.js.map +1 -0
  13. package/dist/parsers/utils.js +128 -0
  14. package/dist/parsers/utils.js.map +1 -0
  15. package/dist/parsers/value-parser.js +613 -0
  16. package/dist/parsers/value-parser.js.map +1 -0
  17. package/dist/rules/consistent-token-usage.js +20 -19
  18. package/dist/rules/consistent-token-usage.js.map +1 -1
  19. package/dist/rules/known-property.js +31 -30
  20. package/dist/rules/known-property.js.map +1 -1
  21. package/dist/rules/no-duplicate-state.js +12 -11
  22. package/dist/rules/no-duplicate-state.js.map +1 -1
  23. package/dist/rules/no-important.js +12 -11
  24. package/dist/rules/no-important.js.map +1 -1
  25. package/dist/rules/no-nested-selector.js +15 -14
  26. package/dist/rules/no-nested-selector.js.map +1 -1
  27. package/dist/rules/no-nested-state-map.js +19 -18
  28. package/dist/rules/no-nested-state-map.js.map +1 -1
  29. package/dist/rules/no-raw-color-values.js +15 -14
  30. package/dist/rules/no-raw-color-values.js.map +1 -1
  31. package/dist/rules/no-runtime-styles-mutation.js +6 -5
  32. package/dist/rules/no-runtime-styles-mutation.js.map +1 -1
  33. package/dist/rules/no-unknown-state-alias.js +12 -11
  34. package/dist/rules/no-unknown-state-alias.js.map +1 -1
  35. package/dist/rules/prefer-shorthand-property.js +19 -18
  36. package/dist/rules/prefer-shorthand-property.js.map +1 -1
  37. package/dist/rules/require-default-state.js +22 -21
  38. package/dist/rules/require-default-state.js.map +1 -1
  39. package/dist/rules/static-no-dynamic-values.js +7 -6
  40. package/dist/rules/static-no-dynamic-values.js.map +1 -1
  41. package/dist/rules/static-valid-selector.js +1 -1
  42. package/dist/rules/valid-boolean-property.js +19 -18
  43. package/dist/rules/valid-boolean-property.js.map +1 -1
  44. package/dist/rules/valid-color-token.js +33 -21
  45. package/dist/rules/valid-color-token.js.map +1 -1
  46. package/dist/rules/valid-custom-property.js +31 -19
  47. package/dist/rules/valid-custom-property.js.map +1 -1
  48. package/dist/rules/valid-custom-unit.js +12 -16
  49. package/dist/rules/valid-custom-unit.js.map +1 -1
  50. package/dist/rules/valid-directional-modifier.js +21 -20
  51. package/dist/rules/valid-directional-modifier.js.map +1 -1
  52. package/dist/rules/valid-preset.js +5 -2
  53. package/dist/rules/valid-preset.js.map +1 -1
  54. package/dist/rules/valid-radius-shape.js +19 -18
  55. package/dist/rules/valid-radius-shape.js.map +1 -1
  56. package/dist/rules/valid-recipe.js +5 -2
  57. package/dist/rules/valid-recipe.js.map +1 -1
  58. package/dist/rules/valid-state-definition.js +70 -0
  59. package/dist/rules/valid-state-definition.js.map +1 -0
  60. package/dist/rules/valid-state-key.js +39 -102
  61. package/dist/rules/valid-state-key.js.map +1 -1
  62. package/dist/rules/valid-styles-structure.js +39 -38
  63. package/dist/rules/valid-styles-structure.js.map +1 -1
  64. package/dist/rules/valid-sub-element.js +21 -20
  65. package/dist/rules/valid-sub-element.js.map +1 -1
  66. package/dist/rules/valid-transition.js +19 -18
  67. package/dist/rules/valid-transition.js.map +1 -1
  68. package/dist/rules/valid-value.js +115 -64
  69. package/dist/rules/valid-value.js.map +1 -1
  70. package/package.json +1 -8
  71. package/dist/parser.js +0 -46
  72. package/dist/parser.js.map +0 -1
package/dist/config.js CHANGED
@@ -9,7 +9,7 @@ const CONFIG_FILENAMES = [
9
9
  "tasty.config.mjs",
10
10
  "tasty.config.json"
11
11
  ];
12
- let cachedConfig = null;
12
+ const configCache = /* @__PURE__ */ new Map();
13
13
  function findProjectRoot(startDir) {
14
14
  let dir = startDir;
15
15
  while (dir !== dirname(dir)) {
@@ -35,28 +35,74 @@ function findConfigFile(projectRoot) {
35
35
  return null;
36
36
  }
37
37
  function stripComments(source) {
38
- return source.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\/\/[^\n]*/g, "");
38
+ let result = "";
39
+ let i = 0;
40
+ while (i < source.length) {
41
+ const ch = source[i];
42
+ if (ch === "\"" || ch === "'" || ch === "`") {
43
+ result += ch;
44
+ i++;
45
+ while (i < source.length && source[i] !== ch) {
46
+ if (source[i] === "\\") result += source[i++];
47
+ if (i < source.length) result += source[i++];
48
+ }
49
+ if (i < source.length) result += source[i++];
50
+ continue;
51
+ }
52
+ if (ch === "/" && source[i + 1] === "*") {
53
+ i += 2;
54
+ while (i < source.length && !(source[i] === "*" && source[i + 1] === "/")) i++;
55
+ i += 2;
56
+ continue;
57
+ }
58
+ if (ch === "/" && source[i + 1] === "/") {
59
+ while (i < source.length && source[i] !== "\n") i++;
60
+ continue;
61
+ }
62
+ result += source[i++];
63
+ }
64
+ return result;
65
+ }
66
+ function stripImports(source) {
67
+ return source.replace(/^\s*import\s+.*?;\s*$/gm, "");
39
68
  }
40
69
  function extractBalancedBraces(content, start) {
41
70
  if (content[start] !== "{") return null;
42
71
  let depth = 0;
43
72
  for (let i = start; i < content.length; i++) {
44
- if (content[i] === "{") depth++;
45
- else if (content[i] === "}") depth--;
73
+ const ch = content[i];
74
+ if (ch === "\"" || ch === "'" || ch === "`") {
75
+ i++;
76
+ while (i < content.length && content[i] !== ch) {
77
+ if (content[i] === "\\") i++;
78
+ i++;
79
+ }
80
+ continue;
81
+ }
82
+ if (ch === "{") depth++;
83
+ else if (ch === "}") depth--;
46
84
  if (depth === 0) return content.slice(start, i + 1);
47
85
  }
48
86
  return null;
49
87
  }
88
+ function stripTypeScriptSyntax(source) {
89
+ return source.replace(/\bas\s+const\b/g, "").replace(/\bsatisfies\s+[A-Z]\w*(?:<[^>]*>)?/g, "").replace(/\bas\s+[A-Z]\w*(?:<[^>]*>)?/g, "");
90
+ }
50
91
  function loadRawConfig(configPath) {
51
92
  const content = readFileSync(configPath, "utf-8");
52
93
  if (configPath.endsWith(".json")) return JSON.parse(content);
53
- const stripped = stripComments(content);
94
+ const stripped = stripImports(stripComments(content));
54
95
  const match = stripped.match(/export\s+default\s+/);
55
96
  if (match && match.index != null) {
56
97
  const objectStr = extractBalancedBraces(stripped, match.index + match[0].length);
57
- if (objectStr) try {
58
- return new Function(`return (${objectStr})`)();
59
- } catch {}
98
+ if (objectStr) {
99
+ const cleaned = stripTypeScriptSyntax(objectStr);
100
+ try {
101
+ return new Function(`return (${cleaned})`)();
102
+ } catch (err) {
103
+ console.warn(`[eslint-plugin-tasty] Failed to parse config file ${configPath}: ${err instanceof Error ? err.message : err}`);
104
+ }
105
+ }
60
106
  }
61
107
  return {};
62
108
  }
@@ -86,10 +132,17 @@ function mergeConfigs(parent, child) {
86
132
  }
87
133
  function resolveConfigChain(configPath, visited = /* @__PURE__ */ new Set()) {
88
134
  const absPath = resolve(configPath);
89
- if (visited.has(absPath)) return {};
135
+ if (visited.has(absPath)) return {
136
+ config: {},
137
+ chainPaths: []
138
+ };
90
139
  visited.add(absPath);
91
140
  const config = loadRawConfig(absPath);
92
- if (!config.extends) return config;
141
+ const chainPaths = [absPath];
142
+ if (!config.extends) return {
143
+ config,
144
+ chainPaths
145
+ };
93
146
  let parentPath;
94
147
  if (config.extends.startsWith(".") || config.extends.startsWith("/")) parentPath = resolve(dirname(absPath), config.extends);
95
148
  else {
@@ -97,10 +150,20 @@ function resolveConfigChain(configPath, visited = /* @__PURE__ */ new Set()) {
97
150
  if (pkgDir) {
98
151
  const pkgConfig = findConfigFile(pkgDir);
99
152
  if (pkgConfig) parentPath = pkgConfig;
100
- else return config;
101
- } else return config;
153
+ else return {
154
+ config,
155
+ chainPaths
156
+ };
157
+ } else return {
158
+ config,
159
+ chainPaths
160
+ };
102
161
  }
103
- return mergeConfigs(resolveConfigChain(parentPath, visited), config);
162
+ const parentResult = resolveConfigChain(parentPath, visited);
163
+ return {
164
+ config: mergeConfigs(parentResult.config, config),
165
+ chainPaths: [...parentResult.chainPaths, ...chainPaths]
166
+ };
104
167
  }
105
168
  function toResolved(config) {
106
169
  return {
@@ -124,20 +187,37 @@ const DEFAULT_CONFIG = {
124
187
  styles: [],
125
188
  importSources: DEFAULT_IMPORT_SOURCES
126
189
  };
190
+ function getMtimes(paths) {
191
+ const mtimes = /* @__PURE__ */ new Map();
192
+ for (const p of paths) try {
193
+ mtimes.set(p, statSync(p).mtimeMs);
194
+ } catch {
195
+ mtimes.set(p, -1);
196
+ }
197
+ return mtimes;
198
+ }
199
+ function mtimesMatch(cached, current) {
200
+ if (cached.size !== current.size) return false;
201
+ for (const [path, mtime] of cached) if (current.get(path) !== mtime) return false;
202
+ return true;
203
+ }
127
204
  function loadConfig(filePath) {
128
205
  const projectRoot = findProjectRoot(dirname(resolve(filePath)));
129
206
  if (!projectRoot) return DEFAULT_CONFIG;
130
207
  const configFile = findConfigFile(projectRoot);
131
208
  if (!configFile) return DEFAULT_CONFIG;
132
- const currentMtime = statSync(configFile).mtimeMs;
133
- if (cachedConfig) {
134
- if (cachedConfig.mtimes.get(configFile) === currentMtime) return cachedConfig.config;
209
+ const cached = configCache.get(configFile);
210
+ if (cached) {
211
+ const currentMtimes = getMtimes([...cached.fileMtimes.keys()]);
212
+ if (mtimesMatch(cached.fileMtimes, currentMtimes)) return cached.config;
135
213
  }
136
- const resolved = toResolved(resolveConfigChain(configFile));
137
- cachedConfig = {
214
+ const { config: rawConfig, chainPaths } = resolveConfigChain(configFile);
215
+ const resolved = toResolved(rawConfig);
216
+ const fileMtimes = getMtimes(chainPaths);
217
+ configCache.set(configFile, {
138
218
  config: resolved,
139
- mtimes: new Map([[configFile, currentMtime]])
140
- };
219
+ fileMtimes
220
+ });
141
221
  return resolved;
142
222
  }
143
223
 
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","names":[],"sources":["../src/config.ts"],"sourcesContent":["import { existsSync, readFileSync, statSync } from 'fs';\nimport { dirname, join, resolve } from 'path';\nimport type { ResolvedConfig, TastyValidationConfig } from './types.js';\nimport { DEFAULT_IMPORT_SOURCES } from './constants.js';\n\nconst CONFIG_FILENAMES = [\n 'tasty.config.ts',\n 'tasty.config.js',\n 'tasty.config.mjs',\n 'tasty.config.json',\n];\n\ninterface CachedConfig {\n config: ResolvedConfig;\n mtimes: Map<string, number>;\n}\n\nlet cachedConfig: CachedConfig | null = null;\n\nfunction findProjectRoot(startDir: string): string | null {\n let dir = startDir;\n while (dir !== dirname(dir)) {\n if (existsSync(join(dir, 'package.json'))) {\n return dir;\n }\n dir = dirname(dir);\n }\n return null;\n}\n\nfunction resolvePackageDir(\n packageName: string,\n startDir: string,\n): string | null {\n let dir = startDir;\n while (dir !== dirname(dir)) {\n const candidate = join(dir, 'node_modules', ...packageName.split('/'));\n if (\n existsSync(candidate) &&\n existsSync(join(candidate, 'package.json'))\n ) {\n return candidate;\n }\n dir = dirname(dir);\n }\n return null;\n}\n\nfunction findConfigFile(projectRoot: string): string | null {\n for (const name of CONFIG_FILENAMES) {\n const path = join(projectRoot, name);\n if (existsSync(path)) {\n return path;\n }\n }\n return null;\n}\n\nfunction stripComments(source: string): string {\n return source\n .replace(/\\/\\*[\\s\\S]*?\\*\\//g, '')\n .replace(/\\/\\/[^\\n]*/g, '');\n}\n\nfunction extractBalancedBraces(content: string, start: number): string | null {\n if (content[start] !== '{') return null;\n let depth = 0;\n for (let i = start; i < content.length; i++) {\n if (content[i] === '{') depth++;\n else if (content[i] === '}') depth--;\n if (depth === 0) return content.slice(start, i + 1);\n }\n return null;\n}\n\nfunction loadRawConfig(configPath: string): TastyValidationConfig {\n const content = readFileSync(configPath, 'utf-8');\n\n if (configPath.endsWith('.json')) {\n return JSON.parse(content) as TastyValidationConfig;\n }\n\n const stripped = stripComments(content);\n const match = stripped.match(/export\\s+default\\s+/);\n if (match && match.index != null) {\n const braceStart = match.index + match[0].length;\n const objectStr = extractBalancedBraces(stripped, braceStart);\n if (objectStr) {\n try {\n const fn = new Function(`return (${objectStr})`);\n return fn() as TastyValidationConfig;\n } catch {\n // fall through\n }\n }\n }\n\n return {};\n}\n\nfunction mergeConfigs(\n parent: TastyValidationConfig,\n child: TastyValidationConfig,\n): TastyValidationConfig {\n const result: TastyValidationConfig = { ...parent };\n\n const arrayKeys = [\n 'tokens',\n 'units',\n 'funcs',\n 'states',\n 'presets',\n 'recipes',\n 'styles',\n 'importSources',\n ] as const;\n\n for (const key of arrayKeys) {\n const childVal = child[key];\n if (childVal === undefined) continue;\n\n if (childVal === false) {\n (result as Record<string, unknown>)[key] = false;\n continue;\n }\n\n const parentVal = parent[key];\n if (Array.isArray(parentVal) && Array.isArray(childVal)) {\n (result as Record<string, unknown>)[key] = [\n ...new Set([...parentVal, ...childVal]),\n ];\n } else {\n (result as Record<string, unknown>)[key] = childVal;\n }\n }\n\n return result;\n}\n\nfunction resolveConfigChain(\n configPath: string,\n visited = new Set<string>(),\n): TastyValidationConfig {\n const absPath = resolve(configPath);\n if (visited.has(absPath)) return {};\n visited.add(absPath);\n\n const config = loadRawConfig(absPath);\n\n if (!config.extends) return config;\n\n let parentPath: string;\n if (config.extends.startsWith('.') || config.extends.startsWith('/')) {\n parentPath = resolve(dirname(absPath), config.extends);\n } else {\n const pkgDir = resolvePackageDir(config.extends, dirname(absPath));\n if (pkgDir) {\n const pkgConfig = findConfigFile(pkgDir);\n if (pkgConfig) {\n parentPath = pkgConfig;\n } else {\n return config;\n }\n } else {\n return config;\n }\n }\n\n const parentConfig = resolveConfigChain(parentPath, visited);\n return mergeConfigs(parentConfig, config);\n}\n\nfunction toResolved(config: TastyValidationConfig): ResolvedConfig {\n return {\n tokens: config.tokens ?? [],\n units: config.units ?? [],\n funcs: config.funcs ?? [],\n states: config.states ?? [],\n presets: config.presets ?? [],\n recipes: config.recipes ?? [],\n styles: config.styles ?? [],\n importSources: config.importSources ?? DEFAULT_IMPORT_SOURCES,\n };\n}\n\nconst DEFAULT_CONFIG: ResolvedConfig = {\n tokens: [],\n units: [],\n funcs: [],\n states: [],\n presets: [],\n recipes: [],\n styles: [],\n importSources: DEFAULT_IMPORT_SOURCES,\n};\n\nexport function loadConfig(filePath: string): ResolvedConfig {\n const projectRoot = findProjectRoot(dirname(resolve(filePath)));\n if (!projectRoot) return DEFAULT_CONFIG;\n\n const configFile = findConfigFile(projectRoot);\n if (!configFile) return DEFAULT_CONFIG;\n\n const currentMtime = statSync(configFile).mtimeMs;\n\n if (cachedConfig) {\n const cachedMtime = cachedConfig.mtimes.get(configFile);\n if (cachedMtime === currentMtime) {\n return cachedConfig.config;\n }\n }\n\n const rawConfig = resolveConfigChain(configFile);\n const resolved = toResolved(rawConfig);\n\n cachedConfig = {\n config: resolved,\n mtimes: new Map([[configFile, currentMtime]]),\n };\n\n return resolved;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"config.js","names":[],"sources":["../src/config.ts"],"sourcesContent":["import { existsSync, readFileSync, statSync } from 'fs';\nimport { dirname, join, resolve } from 'path';\nimport type { ResolvedConfig, TastyValidationConfig } from './types.js';\nimport { DEFAULT_IMPORT_SOURCES } from './constants.js';\n\nconst CONFIG_FILENAMES = [\n 'tasty.config.ts',\n 'tasty.config.js',\n 'tasty.config.mjs',\n 'tasty.config.json',\n];\n\ninterface CachedConfig {\n config: ResolvedConfig;\n fileMtimes: Map<string, number>;\n}\n\nconst configCache = new Map<string, CachedConfig>();\n\nfunction findProjectRoot(startDir: string): string | null {\n let dir = startDir;\n while (dir !== dirname(dir)) {\n if (existsSync(join(dir, 'package.json'))) {\n return dir;\n }\n dir = dirname(dir);\n }\n return null;\n}\n\nfunction resolvePackageDir(\n packageName: string,\n startDir: string,\n): string | null {\n let dir = startDir;\n while (dir !== dirname(dir)) {\n const candidate = join(dir, 'node_modules', ...packageName.split('/'));\n if (existsSync(candidate) && existsSync(join(candidate, 'package.json'))) {\n return candidate;\n }\n dir = dirname(dir);\n }\n return null;\n}\n\nfunction findConfigFile(projectRoot: string): string | null {\n for (const name of CONFIG_FILENAMES) {\n const path = join(projectRoot, name);\n if (existsSync(path)) {\n return path;\n }\n }\n return null;\n}\n\nfunction stripComments(source: string): string {\n let result = '';\n let i = 0;\n while (i < source.length) {\n const ch = source[i];\n if (ch === '\"' || ch === \"'\" || ch === '`') {\n result += ch;\n i++;\n while (i < source.length && source[i] !== ch) {\n if (source[i] === '\\\\') {\n result += source[i++];\n }\n if (i < source.length) {\n result += source[i++];\n }\n }\n if (i < source.length) {\n result += source[i++];\n }\n continue;\n }\n if (ch === '/' && source[i + 1] === '*') {\n i += 2;\n while (i < source.length && !(source[i] === '*' && source[i + 1] === '/')) {\n i++;\n }\n i += 2;\n continue;\n }\n if (ch === '/' && source[i + 1] === '/') {\n while (i < source.length && source[i] !== '\\n') {\n i++;\n }\n continue;\n }\n result += source[i++];\n }\n return result;\n}\n\nfunction stripImports(source: string): string {\n return source.replace(/^\\s*import\\s+.*?;\\s*$/gm, '');\n}\n\nfunction extractBalancedBraces(content: string, start: number): string | null {\n if (content[start] !== '{') return null;\n let depth = 0;\n for (let i = start; i < content.length; i++) {\n const ch = content[i];\n if (ch === '\"' || ch === \"'\" || ch === '`') {\n i++;\n while (i < content.length && content[i] !== ch) {\n if (content[i] === '\\\\') i++;\n i++;\n }\n continue;\n }\n if (ch === '{') depth++;\n else if (ch === '}') depth--;\n if (depth === 0) return content.slice(start, i + 1);\n }\n return null;\n}\n\nfunction stripTypeScriptSyntax(source: string): string {\n return source\n .replace(/\\bas\\s+const\\b/g, '')\n .replace(/\\bsatisfies\\s+[A-Z]\\w*(?:<[^>]*>)?/g, '')\n .replace(/\\bas\\s+[A-Z]\\w*(?:<[^>]*>)?/g, '');\n}\n\nfunction loadRawConfig(configPath: string): TastyValidationConfig {\n const content = readFileSync(configPath, 'utf-8');\n\n if (configPath.endsWith('.json')) {\n return JSON.parse(content) as TastyValidationConfig;\n }\n\n const stripped = stripImports(stripComments(content));\n const match = stripped.match(/export\\s+default\\s+/);\n if (match && match.index != null) {\n const braceStart = match.index + match[0].length;\n const objectStr = extractBalancedBraces(stripped, braceStart);\n if (objectStr) {\n const cleaned = stripTypeScriptSyntax(objectStr);\n try {\n const fn = new Function(`return (${cleaned})`);\n return fn() as TastyValidationConfig;\n } catch (err) {\n console.warn(\n `[eslint-plugin-tasty] Failed to parse config file ${configPath}: ${err instanceof Error ? err.message : err}`,\n );\n }\n }\n }\n\n return {};\n}\n\nfunction mergeConfigs(\n parent: TastyValidationConfig,\n child: TastyValidationConfig,\n): TastyValidationConfig {\n const result: TastyValidationConfig = { ...parent };\n\n const arrayKeys = [\n 'tokens',\n 'units',\n 'funcs',\n 'states',\n 'presets',\n 'recipes',\n 'styles',\n 'importSources',\n ] as const;\n\n for (const key of arrayKeys) {\n const childVal = child[key];\n if (childVal === undefined) continue;\n\n if (childVal === false) {\n (result as Record<string, unknown>)[key] = false;\n continue;\n }\n\n const parentVal = parent[key];\n if (Array.isArray(parentVal) && Array.isArray(childVal)) {\n (result as Record<string, unknown>)[key] = [\n ...new Set([...parentVal, ...childVal]),\n ];\n } else {\n (result as Record<string, unknown>)[key] = childVal;\n }\n }\n\n return result;\n}\n\ninterface ConfigChainResult {\n config: TastyValidationConfig;\n chainPaths: string[];\n}\n\nfunction resolveConfigChain(\n configPath: string,\n visited = new Set<string>(),\n): ConfigChainResult {\n const absPath = resolve(configPath);\n if (visited.has(absPath)) return { config: {}, chainPaths: [] };\n visited.add(absPath);\n\n const config = loadRawConfig(absPath);\n const chainPaths = [absPath];\n\n if (!config.extends) return { config, chainPaths };\n\n let parentPath: string;\n if (config.extends.startsWith('.') || config.extends.startsWith('/')) {\n parentPath = resolve(dirname(absPath), config.extends);\n } else {\n const pkgDir = resolvePackageDir(config.extends, dirname(absPath));\n if (pkgDir) {\n const pkgConfig = findConfigFile(pkgDir);\n if (pkgConfig) {\n parentPath = pkgConfig;\n } else {\n return { config, chainPaths };\n }\n } else {\n return { config, chainPaths };\n }\n }\n\n const parentResult = resolveConfigChain(parentPath, visited);\n return {\n config: mergeConfigs(parentResult.config, config),\n chainPaths: [...parentResult.chainPaths, ...chainPaths],\n };\n}\n\nfunction toResolved(config: TastyValidationConfig): ResolvedConfig {\n return {\n tokens: config.tokens ?? [],\n units: config.units ?? [],\n funcs: config.funcs ?? [],\n states: config.states ?? [],\n presets: config.presets ?? [],\n recipes: config.recipes ?? [],\n styles: config.styles ?? [],\n importSources: config.importSources ?? DEFAULT_IMPORT_SOURCES,\n };\n}\n\nconst DEFAULT_CONFIG: ResolvedConfig = {\n tokens: [],\n units: [],\n funcs: [],\n states: [],\n presets: [],\n recipes: [],\n styles: [],\n importSources: DEFAULT_IMPORT_SOURCES,\n};\n\nfunction getMtimes(paths: string[]): Map<string, number> {\n const mtimes = new Map<string, number>();\n for (const p of paths) {\n try {\n mtimes.set(p, statSync(p).mtimeMs);\n } catch {\n mtimes.set(p, -1);\n }\n }\n return mtimes;\n}\n\nfunction mtimesMatch(\n cached: Map<string, number>,\n current: Map<string, number>,\n): boolean {\n if (cached.size !== current.size) return false;\n for (const [path, mtime] of cached) {\n if (current.get(path) !== mtime) return false;\n }\n return true;\n}\n\nexport function loadConfig(filePath: string): ResolvedConfig {\n const projectRoot = findProjectRoot(dirname(resolve(filePath)));\n if (!projectRoot) return DEFAULT_CONFIG;\n\n const configFile = findConfigFile(projectRoot);\n if (!configFile) return DEFAULT_CONFIG;\n\n const cached = configCache.get(configFile);\n if (cached) {\n const currentMtimes = getMtimes([...cached.fileMtimes.keys()]);\n if (mtimesMatch(cached.fileMtimes, currentMtimes)) {\n return cached.config;\n }\n }\n\n const { config: rawConfig, chainPaths } = resolveConfigChain(configFile);\n const resolved = toResolved(rawConfig);\n const fileMtimes = getMtimes(chainPaths);\n\n configCache.set(configFile, { config: resolved, fileMtimes });\n\n return resolved;\n}\n"],"mappings":"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"}
package/dist/configs.js CHANGED
@@ -14,13 +14,13 @@ const recommended = {
14
14
  "tasty/valid-radius-shape": "error",
15
15
  "tasty/no-nested-selector": "warn",
16
16
  "tasty/static-no-dynamic-values": "error",
17
- "tasty/static-valid-selector": "error",
18
- "tasty/valid-preset": "error",
19
- "tasty/valid-recipe": "error"
17
+ "tasty/static-valid-selector": "error"
20
18
  };
21
19
  const strict = {
22
20
  ...recommended,
23
21
  "tasty/prefer-shorthand-property": "warn",
22
+ "tasty/valid-preset": "error",
23
+ "tasty/valid-recipe": "error",
24
24
  "tasty/valid-transition": "warn",
25
25
  "tasty/valid-custom-property": "warn",
26
26
  "tasty/no-unknown-state-alias": "warn",
@@ -28,7 +28,8 @@ const strict = {
28
28
  "tasty/no-styles-prop": "warn",
29
29
  "tasty/no-raw-color-values": "warn",
30
30
  "tasty/consistent-token-usage": "warn",
31
- "tasty/no-runtime-styles-mutation": "warn"
31
+ "tasty/no-runtime-styles-mutation": "warn",
32
+ "tasty/valid-state-definition": "warn"
32
33
  };
33
34
 
34
35
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"configs.js","names":[],"sources":["../src/configs.ts"],"sourcesContent":["import type { TSESLint } from '@typescript-eslint/utils';\n\nexport const recommended: TSESLint.SharedConfig.RulesRecord = {\n 'tasty/known-property': 'warn',\n 'tasty/valid-value': 'error',\n 'tasty/valid-color-token': 'error',\n 'tasty/valid-custom-unit': 'error',\n 'tasty/valid-boolean-property': 'error',\n 'tasty/valid-state-key': 'error',\n 'tasty/valid-styles-structure': 'error',\n 'tasty/no-nested-state-map': 'error',\n 'tasty/no-important': 'error',\n 'tasty/valid-sub-element': 'error',\n 'tasty/valid-directional-modifier': 'error',\n 'tasty/valid-radius-shape': 'error',\n 'tasty/no-nested-selector': 'warn',\n 'tasty/static-no-dynamic-values': 'error',\n 'tasty/static-valid-selector': 'error',\n 'tasty/valid-preset': 'error',\n 'tasty/valid-recipe': 'error',\n};\n\nexport const strict: TSESLint.SharedConfig.RulesRecord = {\n ...recommended,\n 'tasty/prefer-shorthand-property': 'warn',\n 'tasty/valid-transition': 'warn',\n 'tasty/valid-custom-property': 'warn',\n 'tasty/no-unknown-state-alias': 'warn',\n 'tasty/no-duplicate-state': 'warn',\n 'tasty/no-styles-prop': 'warn',\n 'tasty/no-raw-color-values': 'warn',\n 'tasty/consistent-token-usage': 'warn',\n 'tasty/no-runtime-styles-mutation': 'warn',\n};\n"],"mappings":";AAEA,MAAa,cAAiD;CAC5D,wBAAwB;CACxB,qBAAqB;CACrB,2BAA2B;CAC3B,2BAA2B;CAC3B,gCAAgC;CAChC,yBAAyB;CACzB,gCAAgC;CAChC,6BAA6B;CAC7B,sBAAsB;CACtB,2BAA2B;CAC3B,oCAAoC;CACpC,4BAA4B;CAC5B,4BAA4B;CAC5B,kCAAkC;CAClC,+BAA+B;CAC/B,sBAAsB;CACtB,sBAAsB;CACvB;AAED,MAAa,SAA4C;CACvD,GAAG;CACH,mCAAmC;CACnC,0BAA0B;CAC1B,+BAA+B;CAC/B,gCAAgC;CAChC,4BAA4B;CAC5B,wBAAwB;CACxB,6BAA6B;CAC7B,gCAAgC;CAChC,oCAAoC;CACrC"}
1
+ {"version":3,"file":"configs.js","names":[],"sources":["../src/configs.ts"],"sourcesContent":["import type { TSESLint } from '@typescript-eslint/utils';\n\nexport const recommended: TSESLint.SharedConfig.RulesRecord = {\n 'tasty/known-property': 'warn',\n 'tasty/valid-value': 'error',\n 'tasty/valid-color-token': 'error',\n 'tasty/valid-custom-unit': 'error',\n 'tasty/valid-boolean-property': 'error',\n 'tasty/valid-state-key': 'error',\n 'tasty/valid-styles-structure': 'error',\n 'tasty/no-nested-state-map': 'error',\n 'tasty/no-important': 'error',\n 'tasty/valid-sub-element': 'error',\n 'tasty/valid-directional-modifier': 'error',\n 'tasty/valid-radius-shape': 'error',\n 'tasty/no-nested-selector': 'warn',\n 'tasty/static-no-dynamic-values': 'error',\n 'tasty/static-valid-selector': 'error',\n};\n\nexport const strict: TSESLint.SharedConfig.RulesRecord = {\n ...recommended,\n 'tasty/prefer-shorthand-property': 'warn',\n 'tasty/valid-preset': 'error',\n 'tasty/valid-recipe': 'error',\n 'tasty/valid-transition': 'warn',\n 'tasty/valid-custom-property': 'warn',\n 'tasty/no-unknown-state-alias': 'warn',\n 'tasty/no-duplicate-state': 'warn',\n 'tasty/no-styles-prop': 'warn',\n 'tasty/no-raw-color-values': 'warn',\n 'tasty/consistent-token-usage': 'warn',\n 'tasty/no-runtime-styles-mutation': 'warn',\n 'tasty/valid-state-definition': 'warn',\n};\n"],"mappings":";AAEA,MAAa,cAAiD;CAC5D,wBAAwB;CACxB,qBAAqB;CACrB,2BAA2B;CAC3B,2BAA2B;CAC3B,gCAAgC;CAChC,yBAAyB;CACzB,gCAAgC;CAChC,6BAA6B;CAC7B,sBAAsB;CACtB,2BAA2B;CAC3B,oCAAoC;CACpC,4BAA4B;CAC5B,4BAA4B;CAC5B,kCAAkC;CAClC,+BAA+B;CAChC;AAED,MAAa,SAA4C;CACvD,GAAG;CACH,mCAAmC;CACnC,sBAAsB;CACtB,sBAAsB;CACtB,0BAA0B;CAC1B,+BAA+B;CAC/B,gCAAgC;CAChC,4BAA4B;CAC5B,wBAAwB;CACxB,6BAA6B;CAC7B,gCAAgC;CAChC,oCAAoC;CACpC,gCAAgC;CACjC"}
package/dist/constants.js CHANGED
@@ -706,7 +706,61 @@ const BUILT_IN_STATE_PREFIXES = new Set([
706
706
  "@keyframes",
707
707
  "@properties"
708
708
  ]);
709
+ /**
710
+ * Known CSS pseudo-classes.
711
+ */
712
+ const KNOWN_PSEUDO_CLASSES = new Set([
713
+ ":hover",
714
+ ":focus",
715
+ ":focus-visible",
716
+ ":focus-within",
717
+ ":active",
718
+ ":visited",
719
+ ":link",
720
+ ":checked",
721
+ ":disabled",
722
+ ":enabled",
723
+ ":empty",
724
+ ":first-child",
725
+ ":last-child",
726
+ ":first-of-type",
727
+ ":last-of-type",
728
+ ":only-child",
729
+ ":only-of-type",
730
+ ":root",
731
+ ":target",
732
+ ":valid",
733
+ ":invalid",
734
+ ":required",
735
+ ":optional",
736
+ ":read-only",
737
+ ":read-write",
738
+ ":placeholder-shown",
739
+ ":autofill",
740
+ ":default",
741
+ ":indeterminate",
742
+ ":in-range",
743
+ ":out-of-range",
744
+ ":any-link",
745
+ ":local-link",
746
+ ":is",
747
+ ":not",
748
+ ":where",
749
+ ":has",
750
+ ":nth-child",
751
+ ":nth-last-child",
752
+ ":nth-of-type",
753
+ ":nth-last-of-type",
754
+ "::before",
755
+ "::after",
756
+ "::placeholder",
757
+ "::selection",
758
+ "::first-line",
759
+ "::first-letter",
760
+ "::marker",
761
+ "::backdrop"
762
+ ]);
709
763
 
710
764
  //#endregion
711
- export { BOOLEAN_TRUE_PROPERTIES, BUILT_IN_STATE_PREFIXES, BUILT_IN_UNITS, CSS_UNITS, DEFAULT_IMPORT_SOURCES, DIRECTIONAL_MODIFIERS, KNOWN_CSS_PROPERTIES, KNOWN_TASTY_PROPERTIES, PRESET_MODIFIERS, RADIUS_SHAPES, SEMANTIC_TRANSITIONS, SHORTHAND_MAPPING, SPECIAL_STYLE_KEYS };
765
+ export { BOOLEAN_TRUE_PROPERTIES, BUILT_IN_STATE_PREFIXES, BUILT_IN_UNITS, CSS_UNITS, DEFAULT_IMPORT_SOURCES, DIRECTIONAL_MODIFIERS, KNOWN_CSS_PROPERTIES, KNOWN_PSEUDO_CLASSES, KNOWN_TASTY_PROPERTIES, PRESET_MODIFIERS, RADIUS_SHAPES, SEMANTIC_TRANSITIONS, SHORTHAND_MAPPING, SPECIAL_STYLE_KEYS };
712
766
  //# sourceMappingURL=constants.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.js","names":[],"sources":["../src/constants.ts"],"sourcesContent":["/**\n * Built-in tasty style properties that are always valid as style keys.\n */\nexport const KNOWN_TASTY_PROPERTIES = new Set([\n 'display',\n 'font',\n 'preset',\n 'hide',\n 'whiteSpace',\n 'opacity',\n 'transition',\n 'gridArea',\n 'order',\n 'gridColumn',\n 'gridRow',\n 'placeSelf',\n 'alignSelf',\n 'justifySelf',\n 'zIndex',\n 'margin',\n 'inset',\n 'position',\n 'padding',\n 'paddingInline',\n 'paddingBlock',\n 'overflow',\n 'scrollbar',\n 'textAlign',\n 'border',\n 'radius',\n 'shadow',\n 'outline',\n 'color',\n 'fill',\n 'fade',\n 'image',\n 'textTransform',\n 'fontWeight',\n 'fontStyle',\n 'width',\n 'height',\n 'flexBasis',\n 'flexGrow',\n 'flexShrink',\n 'flex',\n 'flow',\n 'placeItems',\n 'placeContent',\n 'alignItems',\n 'alignContent',\n 'justifyItems',\n 'justifyContent',\n 'align',\n 'justify',\n 'gap',\n 'columnGap',\n 'rowGap',\n 'gridColumns',\n 'gridRows',\n 'gridTemplate',\n 'gridAreas',\n 'recipe',\n 'textOverflow',\n 'textDecoration',\n 'animation',\n 'cursor',\n 'pointerEvents',\n 'userSelect',\n 'transform',\n 'transformOrigin',\n 'filter',\n 'backdropFilter',\n 'mixBlendMode',\n 'objectFit',\n 'objectPosition',\n 'resize',\n 'appearance',\n 'listStyle',\n 'listStyleType',\n 'content',\n 'boxSizing',\n 'verticalAlign',\n 'wordBreak',\n 'overflowWrap',\n 'hyphens',\n 'tabSize',\n 'direction',\n 'unicodeBidi',\n 'writingMode',\n 'lineClamp',\n 'aspectRatio',\n 'contain',\n 'container',\n 'containerType',\n 'containerName',\n 'interpolateSize',\n 'willChange',\n 'isolation',\n 'touchAction',\n 'scrollBehavior',\n 'scrollSnapType',\n 'scrollSnapAlign',\n 'caretColor',\n 'accentColor',\n 'colorScheme',\n]);\n\n/**\n * Special top-level keys that are valid but not regular style properties.\n */\nexport const SPECIAL_STYLE_KEYS = new Set(['@keyframes', '@properties']);\n\n/**\n * CSS property names (common subset for validation).\n * When a key is camelCase and matches a known CSS property, it's valid.\n */\nexport const KNOWN_CSS_PROPERTIES = new Set([\n 'all',\n 'animation',\n 'animationDelay',\n 'animationDirection',\n 'animationDuration',\n 'animationFillMode',\n 'animationIterationCount',\n 'animationName',\n 'animationPlayState',\n 'animationTimingFunction',\n 'appearance',\n 'aspectRatio',\n 'backdropFilter',\n 'backfaceVisibility',\n 'background',\n 'backgroundAttachment',\n 'backgroundBlendMode',\n 'backgroundClip',\n 'backgroundColor',\n 'backgroundImage',\n 'backgroundOrigin',\n 'backgroundPosition',\n 'backgroundRepeat',\n 'backgroundSize',\n 'blockSize',\n 'border',\n 'borderBlock',\n 'borderBlockColor',\n 'borderBlockEnd',\n 'borderBlockEndColor',\n 'borderBlockEndStyle',\n 'borderBlockEndWidth',\n 'borderBlockStart',\n 'borderBlockStartColor',\n 'borderBlockStartStyle',\n 'borderBlockStartWidth',\n 'borderBlockStyle',\n 'borderBlockWidth',\n 'borderBottom',\n 'borderBottomColor',\n 'borderBottomLeftRadius',\n 'borderBottomRightRadius',\n 'borderBottomStyle',\n 'borderBottomWidth',\n 'borderCollapse',\n 'borderColor',\n 'borderImage',\n 'borderInline',\n 'borderInlineColor',\n 'borderInlineEnd',\n 'borderInlineStart',\n 'borderInlineStyle',\n 'borderInlineWidth',\n 'borderLeft',\n 'borderLeftColor',\n 'borderLeftStyle',\n 'borderLeftWidth',\n 'borderRadius',\n 'borderRight',\n 'borderRightColor',\n 'borderRightStyle',\n 'borderRightWidth',\n 'borderSpacing',\n 'borderStyle',\n 'borderTop',\n 'borderTopColor',\n 'borderTopLeftRadius',\n 'borderTopRightRadius',\n 'borderTopStyle',\n 'borderTopWidth',\n 'borderWidth',\n 'bottom',\n 'boxDecorationBreak',\n 'boxShadow',\n 'boxSizing',\n 'breakAfter',\n 'breakBefore',\n 'breakInside',\n 'captionSide',\n 'caretColor',\n 'clear',\n 'clip',\n 'clipPath',\n 'color',\n 'colorScheme',\n 'columnCount',\n 'columnFill',\n 'columnGap',\n 'columnRule',\n 'columnRuleColor',\n 'columnRuleStyle',\n 'columnRuleWidth',\n 'columnSpan',\n 'columnWidth',\n 'columns',\n 'contain',\n 'containerName',\n 'containerType',\n 'content',\n 'contentVisibility',\n 'counterIncrement',\n 'counterReset',\n 'counterSet',\n 'cursor',\n 'direction',\n 'display',\n 'emptyCells',\n 'filter',\n 'flex',\n 'flexBasis',\n 'flexDirection',\n 'flexFlow',\n 'flexGrow',\n 'flexShrink',\n 'flexWrap',\n 'float',\n 'font',\n 'fontFamily',\n 'fontFeatureSettings',\n 'fontKerning',\n 'fontOpticalSizing',\n 'fontSize',\n 'fontSizeAdjust',\n 'fontStretch',\n 'fontStyle',\n 'fontSynthesis',\n 'fontVariant',\n 'fontVariantAlternates',\n 'fontVariantCaps',\n 'fontVariantEastAsian',\n 'fontVariantLigatures',\n 'fontVariantNumeric',\n 'fontVariantPosition',\n 'fontWeight',\n 'gap',\n 'grid',\n 'gridArea',\n 'gridAutoColumns',\n 'gridAutoFlow',\n 'gridAutoRows',\n 'gridColumn',\n 'gridColumnEnd',\n 'gridColumnStart',\n 'gridRow',\n 'gridRowEnd',\n 'gridRowStart',\n 'gridTemplate',\n 'gridTemplateAreas',\n 'gridTemplateColumns',\n 'gridTemplateRows',\n 'height',\n 'hyphens',\n 'imageRendering',\n 'inlineSize',\n 'inset',\n 'insetBlock',\n 'insetBlockEnd',\n 'insetBlockStart',\n 'insetInline',\n 'insetInlineEnd',\n 'insetInlineStart',\n 'isolation',\n 'justifyContent',\n 'justifyItems',\n 'justifySelf',\n 'left',\n 'letterSpacing',\n 'lineBreak',\n 'lineHeight',\n 'listStyle',\n 'listStyleImage',\n 'listStylePosition',\n 'listStyleType',\n 'margin',\n 'marginBlock',\n 'marginBlockEnd',\n 'marginBlockStart',\n 'marginBottom',\n 'marginInline',\n 'marginInlineEnd',\n 'marginInlineStart',\n 'marginLeft',\n 'marginRight',\n 'marginTop',\n 'maskImage',\n 'maxBlockSize',\n 'maxHeight',\n 'maxInlineSize',\n 'maxWidth',\n 'minBlockSize',\n 'minHeight',\n 'minInlineSize',\n 'minWidth',\n 'mixBlendMode',\n 'objectFit',\n 'objectPosition',\n 'opacity',\n 'order',\n 'orphans',\n 'outline',\n 'outlineColor',\n 'outlineOffset',\n 'outlineStyle',\n 'outlineWidth',\n 'overflow',\n 'overflowAnchor',\n 'overflowWrap',\n 'overflowX',\n 'overflowY',\n 'overscrollBehavior',\n 'padding',\n 'paddingBlock',\n 'paddingBlockEnd',\n 'paddingBlockStart',\n 'paddingBottom',\n 'paddingInline',\n 'paddingInlineEnd',\n 'paddingInlineStart',\n 'paddingLeft',\n 'paddingRight',\n 'paddingTop',\n 'perspective',\n 'perspectiveOrigin',\n 'placeContent',\n 'placeItems',\n 'placeSelf',\n 'pointerEvents',\n 'position',\n 'quotes',\n 'resize',\n 'right',\n 'rotate',\n 'rowGap',\n 'scale',\n 'scrollBehavior',\n 'scrollMargin',\n 'scrollPadding',\n 'scrollSnapAlign',\n 'scrollSnapStop',\n 'scrollSnapType',\n 'scrollbarColor',\n 'scrollbarGutter',\n 'scrollbarWidth',\n 'shapeOutside',\n 'tabSize',\n 'tableLayout',\n 'textAlign',\n 'textAlignLast',\n 'textCombineUpright',\n 'textDecoration',\n 'textDecorationColor',\n 'textDecorationLine',\n 'textDecorationSkipInk',\n 'textDecorationStyle',\n 'textDecorationThickness',\n 'textEmphasis',\n 'textIndent',\n 'textOrientation',\n 'textOverflow',\n 'textRendering',\n 'textShadow',\n 'textTransform',\n 'textUnderlineOffset',\n 'textUnderlinePosition',\n 'textWrap',\n 'top',\n 'touchAction',\n 'transform',\n 'transformOrigin',\n 'transformStyle',\n 'transition',\n 'transitionDelay',\n 'transitionDuration',\n 'transitionProperty',\n 'transitionTimingFunction',\n 'translate',\n 'unicodeBidi',\n 'userSelect',\n 'verticalAlign',\n 'visibility',\n 'whiteSpace',\n 'widows',\n 'width',\n 'willChange',\n 'wordBreak',\n 'wordSpacing',\n 'writingMode',\n 'zIndex',\n]);\n\n/**\n * Built-in custom units recognized by the tasty parser.\n */\nexport const BUILT_IN_UNITS = new Set([\n 'x',\n 'r',\n 'cr',\n 'bw',\n 'ow',\n 'fs',\n 'lh',\n 'sf',\n]);\n\n/**\n * Standard CSS units (always valid).\n */\nexport const CSS_UNITS = new Set([\n 'px',\n 'em',\n 'rem',\n '%',\n 'vw',\n 'vh',\n 'vmin',\n 'vmax',\n 'ch',\n 'ex',\n 'cm',\n 'mm',\n 'in',\n 'pt',\n 'pc',\n 'fr',\n 'deg',\n 'rad',\n 'turn',\n 'grad',\n 's',\n 'ms',\n 'dpi',\n 'dpcm',\n 'dppx',\n 'svw',\n 'svh',\n 'lvw',\n 'lvh',\n 'dvw',\n 'dvh',\n 'cqw',\n 'cqh',\n 'cqi',\n 'cqb',\n 'cqmin',\n 'cqmax',\n 'cap',\n 'ic',\n 'rlh',\n 'vi',\n 'vb',\n]);\n\n/**\n * Properties that accept `true` as a value (means \"use default\").\n */\nexport const BOOLEAN_TRUE_PROPERTIES = new Set([\n 'border',\n 'radius',\n 'padding',\n 'margin',\n 'gap',\n 'fill',\n 'color',\n 'shadow',\n 'outline',\n 'inset',\n 'width',\n 'height',\n 'hide',\n 'preset',\n 'font',\n 'scrollbar',\n]);\n\n/**\n * Directional modifiers and which properties accept them.\n */\nexport const DIRECTIONAL_MODIFIERS: Record<string, Set<string>> = {\n border: new Set(['top', 'right', 'bottom', 'left']),\n radius: new Set([\n 'top',\n 'right',\n 'bottom',\n 'left',\n 'top-left',\n 'top-right',\n 'bottom-left',\n 'bottom-right',\n ]),\n padding: new Set(['top', 'right', 'bottom', 'left']),\n margin: new Set(['top', 'right', 'bottom', 'left']),\n fade: new Set(['top', 'right', 'bottom', 'left']),\n inset: new Set(['top', 'right', 'bottom', 'left']),\n};\n\n/**\n * Valid radius shape keywords.\n */\nexport const RADIUS_SHAPES = new Set(['round', 'ellipse', 'leaf', 'backleaf']);\n\n/**\n * Known semantic transition names.\n */\nexport const SEMANTIC_TRANSITIONS = new Set([\n 'fade',\n 'fill',\n 'border',\n 'radius',\n 'shadow',\n 'preset',\n 'gap',\n 'theme',\n 'color',\n 'outline',\n 'dimension',\n 'flow',\n 'inset',\n]);\n\n/**\n * Mapping of native CSS properties to tasty shorthand alternatives.\n */\nexport const SHORTHAND_MAPPING: Record<\n string,\n { property: string; hint: string }\n> = {\n backgroundColor: { property: 'fill', hint: \"fill: '...'\" },\n borderColor: { property: 'border', hint: \"border: '...'\" },\n borderWidth: { property: 'border', hint: \"border: '...'\" },\n borderStyle: { property: 'border', hint: \"border: '...'\" },\n borderTop: { property: 'border', hint: \"border: '... top'\" },\n borderRight: { property: 'border', hint: \"border: '... right'\" },\n borderBottom: { property: 'border', hint: \"border: '... bottom'\" },\n borderLeft: { property: 'border', hint: \"border: '... left'\" },\n borderRadius: { property: 'radius', hint: \"radius: '...'\" },\n maxWidth: { property: 'width', hint: \"width: 'max ...'\" },\n minWidth: { property: 'width', hint: \"width: 'min ...'\" },\n maxHeight: { property: 'height', hint: \"height: 'max ...'\" },\n minHeight: { property: 'height', hint: \"height: 'min ...'\" },\n flexDirection: { property: 'flow', hint: \"flow: '...'\" },\n flexWrap: { property: 'flow', hint: \"flow: '...'\" },\n flexFlow: { property: 'flow', hint: \"flow: '...'\" },\n gridAutoFlow: { property: 'flow', hint: \"flow: '...'\" },\n outlineOffset: { property: 'outline', hint: \"outline: '... / offset'\" },\n paddingTop: { property: 'padding', hint: \"padding: '... top'\" },\n paddingRight: { property: 'padding', hint: \"padding: '... right'\" },\n paddingBottom: { property: 'padding', hint: \"padding: '... bottom'\" },\n paddingLeft: { property: 'padding', hint: \"padding: '... left'\" },\n marginTop: { property: 'margin', hint: \"margin: '... top'\" },\n marginRight: { property: 'margin', hint: \"margin: '... right'\" },\n marginBottom: { property: 'margin', hint: \"margin: '... bottom'\" },\n marginLeft: { property: 'margin', hint: \"margin: '... left'\" },\n fontSize: { property: 'preset', hint: \"preset: '...'\" },\n fontWeight: {\n property: 'preset',\n hint: \"preset: '... strong' (with strong modifier)\",\n },\n lineHeight: {\n property: 'preset',\n hint: \"preset: '... tight' (with tight modifier)\",\n },\n boxShadow: { property: 'shadow', hint: \"shadow: '...'\" },\n};\n\n/**\n * Known preset modifiers.\n */\nexport const PRESET_MODIFIERS = new Set(['strong', 'italic', 'tight']);\n\n/**\n * Default import sources for tasty.\n */\nexport const DEFAULT_IMPORT_SOURCES = ['@tenphi/tasty', '@tenphi/tasty/static'];\n\n/**\n * Built-in state prefixes that are always valid (not aliases).\n */\nexport const BUILT_IN_STATE_PREFIXES = new Set([\n '@media',\n '@root',\n '@parent',\n '@own',\n '@supports',\n '@starting',\n '@keyframes',\n '@properties',\n]);\n\n/**\n * Known CSS pseudo-classes.\n */\nexport const KNOWN_PSEUDO_CLASSES = new Set([\n ':hover',\n ':focus',\n ':focus-visible',\n ':focus-within',\n ':active',\n ':visited',\n ':link',\n ':checked',\n ':disabled',\n ':enabled',\n ':empty',\n ':first-child',\n ':last-child',\n ':first-of-type',\n ':last-of-type',\n ':only-child',\n ':only-of-type',\n ':root',\n ':target',\n ':valid',\n ':invalid',\n ':required',\n ':optional',\n ':read-only',\n ':read-write',\n ':placeholder-shown',\n ':autofill',\n ':default',\n ':indeterminate',\n ':in-range',\n ':out-of-range',\n ':any-link',\n ':local-link',\n ':is',\n ':not',\n ':where',\n ':has',\n ':nth-child',\n ':nth-last-child',\n ':nth-of-type',\n ':nth-last-of-type',\n '::before',\n '::after',\n '::placeholder',\n '::selection',\n '::first-line',\n '::first-letter',\n '::marker',\n '::backdrop',\n]);\n"],"mappings":";;;;AAGA,MAAa,yBAAyB,IAAI,IAAI;CAC5C;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD,CAAC;;;;AAKF,MAAa,qBAAqB,IAAI,IAAI,CAAC,cAAc,cAAc,CAAC;;;;;AAMxE,MAAa,uBAAuB,IAAI,IAAI;CAC1C;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD,CAAC;;;;AAKF,MAAa,iBAAiB,IAAI,IAAI;CACpC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD,CAAC;;;;AAKF,MAAa,YAAY,IAAI,IAAI;CAC/B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD,CAAC;;;;AAKF,MAAa,0BAA0B,IAAI,IAAI;CAC7C;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD,CAAC;;;;AAKF,MAAa,wBAAqD;CAChE,QAAQ,IAAI,IAAI;EAAC;EAAO;EAAS;EAAU;EAAO,CAAC;CACnD,QAAQ,IAAI,IAAI;EACd;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACD,CAAC;CACF,SAAS,IAAI,IAAI;EAAC;EAAO;EAAS;EAAU;EAAO,CAAC;CACpD,QAAQ,IAAI,IAAI;EAAC;EAAO;EAAS;EAAU;EAAO,CAAC;CACnD,MAAM,IAAI,IAAI;EAAC;EAAO;EAAS;EAAU;EAAO,CAAC;CACjD,OAAO,IAAI,IAAI;EAAC;EAAO;EAAS;EAAU;EAAO,CAAC;CACnD;;;;AAKD,MAAa,gBAAgB,IAAI,IAAI;CAAC;CAAS;CAAW;CAAQ;CAAW,CAAC;;;;AAK9E,MAAa,uBAAuB,IAAI,IAAI;CAC1C;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD,CAAC;;;;AAKF,MAAa,oBAGT;CACF,iBAAiB;EAAE,UAAU;EAAQ,MAAM;EAAe;CAC1D,aAAa;EAAE,UAAU;EAAU,MAAM;EAAiB;CAC1D,aAAa;EAAE,UAAU;EAAU,MAAM;EAAiB;CAC1D,aAAa;EAAE,UAAU;EAAU,MAAM;EAAiB;CAC1D,WAAW;EAAE,UAAU;EAAU,MAAM;EAAqB;CAC5D,aAAa;EAAE,UAAU;EAAU,MAAM;EAAuB;CAChE,cAAc;EAAE,UAAU;EAAU,MAAM;EAAwB;CAClE,YAAY;EAAE,UAAU;EAAU,MAAM;EAAsB;CAC9D,cAAc;EAAE,UAAU;EAAU,MAAM;EAAiB;CAC3D,UAAU;EAAE,UAAU;EAAS,MAAM;EAAoB;CACzD,UAAU;EAAE,UAAU;EAAS,MAAM;EAAoB;CACzD,WAAW;EAAE,UAAU;EAAU,MAAM;EAAqB;CAC5D,WAAW;EAAE,UAAU;EAAU,MAAM;EAAqB;CAC5D,eAAe;EAAE,UAAU;EAAQ,MAAM;EAAe;CACxD,UAAU;EAAE,UAAU;EAAQ,MAAM;EAAe;CACnD,UAAU;EAAE,UAAU;EAAQ,MAAM;EAAe;CACnD,cAAc;EAAE,UAAU;EAAQ,MAAM;EAAe;CACvD,eAAe;EAAE,UAAU;EAAW,MAAM;EAA2B;CACvE,YAAY;EAAE,UAAU;EAAW,MAAM;EAAsB;CAC/D,cAAc;EAAE,UAAU;EAAW,MAAM;EAAwB;CACnE,eAAe;EAAE,UAAU;EAAW,MAAM;EAAyB;CACrE,aAAa;EAAE,UAAU;EAAW,MAAM;EAAuB;CACjE,WAAW;EAAE,UAAU;EAAU,MAAM;EAAqB;CAC5D,aAAa;EAAE,UAAU;EAAU,MAAM;EAAuB;CAChE,cAAc;EAAE,UAAU;EAAU,MAAM;EAAwB;CAClE,YAAY;EAAE,UAAU;EAAU,MAAM;EAAsB;CAC9D,UAAU;EAAE,UAAU;EAAU,MAAM;EAAiB;CACvD,YAAY;EACV,UAAU;EACV,MAAM;EACP;CACD,YAAY;EACV,UAAU;EACV,MAAM;EACP;CACD,WAAW;EAAE,UAAU;EAAU,MAAM;EAAiB;CACzD;;;;AAKD,MAAa,mBAAmB,IAAI,IAAI;CAAC;CAAU;CAAU;CAAQ,CAAC;;;;AAKtE,MAAa,yBAAyB,CAAC,iBAAiB,uBAAuB;;;;AAK/E,MAAa,0BAA0B,IAAI,IAAI;CAC7C;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD,CAAC"}
1
+ {"version":3,"file":"constants.js","names":[],"sources":["../src/constants.ts"],"sourcesContent":["/**\n * Built-in tasty style properties that are always valid as style keys.\n */\nexport const KNOWN_TASTY_PROPERTIES = new Set([\n 'display',\n 'font',\n 'preset',\n 'hide',\n 'whiteSpace',\n 'opacity',\n 'transition',\n 'gridArea',\n 'order',\n 'gridColumn',\n 'gridRow',\n 'placeSelf',\n 'alignSelf',\n 'justifySelf',\n 'zIndex',\n 'margin',\n 'inset',\n 'position',\n 'padding',\n 'paddingInline',\n 'paddingBlock',\n 'overflow',\n 'scrollbar',\n 'textAlign',\n 'border',\n 'radius',\n 'shadow',\n 'outline',\n 'color',\n 'fill',\n 'fade',\n 'image',\n 'textTransform',\n 'fontWeight',\n 'fontStyle',\n 'width',\n 'height',\n 'flexBasis',\n 'flexGrow',\n 'flexShrink',\n 'flex',\n 'flow',\n 'placeItems',\n 'placeContent',\n 'alignItems',\n 'alignContent',\n 'justifyItems',\n 'justifyContent',\n 'align',\n 'justify',\n 'gap',\n 'columnGap',\n 'rowGap',\n 'gridColumns',\n 'gridRows',\n 'gridTemplate',\n 'gridAreas',\n 'recipe',\n 'textOverflow',\n 'textDecoration',\n 'animation',\n 'cursor',\n 'pointerEvents',\n 'userSelect',\n 'transform',\n 'transformOrigin',\n 'filter',\n 'backdropFilter',\n 'mixBlendMode',\n 'objectFit',\n 'objectPosition',\n 'resize',\n 'appearance',\n 'listStyle',\n 'listStyleType',\n 'content',\n 'boxSizing',\n 'verticalAlign',\n 'wordBreak',\n 'overflowWrap',\n 'hyphens',\n 'tabSize',\n 'direction',\n 'unicodeBidi',\n 'writingMode',\n 'lineClamp',\n 'aspectRatio',\n 'contain',\n 'container',\n 'containerType',\n 'containerName',\n 'interpolateSize',\n 'willChange',\n 'isolation',\n 'touchAction',\n 'scrollBehavior',\n 'scrollSnapType',\n 'scrollSnapAlign',\n 'caretColor',\n 'accentColor',\n 'colorScheme',\n]);\n\n/**\n * Special top-level keys that are valid but not regular style properties.\n */\nexport const SPECIAL_STYLE_KEYS = new Set(['@keyframes', '@properties']);\n\n/**\n * CSS property names (common subset for validation).\n * When a key is camelCase and matches a known CSS property, it's valid.\n */\nexport const KNOWN_CSS_PROPERTIES = new Set([\n 'all',\n 'animation',\n 'animationDelay',\n 'animationDirection',\n 'animationDuration',\n 'animationFillMode',\n 'animationIterationCount',\n 'animationName',\n 'animationPlayState',\n 'animationTimingFunction',\n 'appearance',\n 'aspectRatio',\n 'backdropFilter',\n 'backfaceVisibility',\n 'background',\n 'backgroundAttachment',\n 'backgroundBlendMode',\n 'backgroundClip',\n 'backgroundColor',\n 'backgroundImage',\n 'backgroundOrigin',\n 'backgroundPosition',\n 'backgroundRepeat',\n 'backgroundSize',\n 'blockSize',\n 'border',\n 'borderBlock',\n 'borderBlockColor',\n 'borderBlockEnd',\n 'borderBlockEndColor',\n 'borderBlockEndStyle',\n 'borderBlockEndWidth',\n 'borderBlockStart',\n 'borderBlockStartColor',\n 'borderBlockStartStyle',\n 'borderBlockStartWidth',\n 'borderBlockStyle',\n 'borderBlockWidth',\n 'borderBottom',\n 'borderBottomColor',\n 'borderBottomLeftRadius',\n 'borderBottomRightRadius',\n 'borderBottomStyle',\n 'borderBottomWidth',\n 'borderCollapse',\n 'borderColor',\n 'borderImage',\n 'borderInline',\n 'borderInlineColor',\n 'borderInlineEnd',\n 'borderInlineStart',\n 'borderInlineStyle',\n 'borderInlineWidth',\n 'borderLeft',\n 'borderLeftColor',\n 'borderLeftStyle',\n 'borderLeftWidth',\n 'borderRadius',\n 'borderRight',\n 'borderRightColor',\n 'borderRightStyle',\n 'borderRightWidth',\n 'borderSpacing',\n 'borderStyle',\n 'borderTop',\n 'borderTopColor',\n 'borderTopLeftRadius',\n 'borderTopRightRadius',\n 'borderTopStyle',\n 'borderTopWidth',\n 'borderWidth',\n 'bottom',\n 'boxDecorationBreak',\n 'boxShadow',\n 'boxSizing',\n 'breakAfter',\n 'breakBefore',\n 'breakInside',\n 'captionSide',\n 'caretColor',\n 'clear',\n 'clip',\n 'clipPath',\n 'color',\n 'colorScheme',\n 'columnCount',\n 'columnFill',\n 'columnGap',\n 'columnRule',\n 'columnRuleColor',\n 'columnRuleStyle',\n 'columnRuleWidth',\n 'columnSpan',\n 'columnWidth',\n 'columns',\n 'contain',\n 'containerName',\n 'containerType',\n 'content',\n 'contentVisibility',\n 'counterIncrement',\n 'counterReset',\n 'counterSet',\n 'cursor',\n 'direction',\n 'display',\n 'emptyCells',\n 'filter',\n 'flex',\n 'flexBasis',\n 'flexDirection',\n 'flexFlow',\n 'flexGrow',\n 'flexShrink',\n 'flexWrap',\n 'float',\n 'font',\n 'fontFamily',\n 'fontFeatureSettings',\n 'fontKerning',\n 'fontOpticalSizing',\n 'fontSize',\n 'fontSizeAdjust',\n 'fontStretch',\n 'fontStyle',\n 'fontSynthesis',\n 'fontVariant',\n 'fontVariantAlternates',\n 'fontVariantCaps',\n 'fontVariantEastAsian',\n 'fontVariantLigatures',\n 'fontVariantNumeric',\n 'fontVariantPosition',\n 'fontWeight',\n 'gap',\n 'grid',\n 'gridArea',\n 'gridAutoColumns',\n 'gridAutoFlow',\n 'gridAutoRows',\n 'gridColumn',\n 'gridColumnEnd',\n 'gridColumnStart',\n 'gridRow',\n 'gridRowEnd',\n 'gridRowStart',\n 'gridTemplate',\n 'gridTemplateAreas',\n 'gridTemplateColumns',\n 'gridTemplateRows',\n 'height',\n 'hyphens',\n 'imageRendering',\n 'inlineSize',\n 'inset',\n 'insetBlock',\n 'insetBlockEnd',\n 'insetBlockStart',\n 'insetInline',\n 'insetInlineEnd',\n 'insetInlineStart',\n 'isolation',\n 'justifyContent',\n 'justifyItems',\n 'justifySelf',\n 'left',\n 'letterSpacing',\n 'lineBreak',\n 'lineHeight',\n 'listStyle',\n 'listStyleImage',\n 'listStylePosition',\n 'listStyleType',\n 'margin',\n 'marginBlock',\n 'marginBlockEnd',\n 'marginBlockStart',\n 'marginBottom',\n 'marginInline',\n 'marginInlineEnd',\n 'marginInlineStart',\n 'marginLeft',\n 'marginRight',\n 'marginTop',\n 'maskImage',\n 'maxBlockSize',\n 'maxHeight',\n 'maxInlineSize',\n 'maxWidth',\n 'minBlockSize',\n 'minHeight',\n 'minInlineSize',\n 'minWidth',\n 'mixBlendMode',\n 'objectFit',\n 'objectPosition',\n 'opacity',\n 'order',\n 'orphans',\n 'outline',\n 'outlineColor',\n 'outlineOffset',\n 'outlineStyle',\n 'outlineWidth',\n 'overflow',\n 'overflowAnchor',\n 'overflowWrap',\n 'overflowX',\n 'overflowY',\n 'overscrollBehavior',\n 'padding',\n 'paddingBlock',\n 'paddingBlockEnd',\n 'paddingBlockStart',\n 'paddingBottom',\n 'paddingInline',\n 'paddingInlineEnd',\n 'paddingInlineStart',\n 'paddingLeft',\n 'paddingRight',\n 'paddingTop',\n 'perspective',\n 'perspectiveOrigin',\n 'placeContent',\n 'placeItems',\n 'placeSelf',\n 'pointerEvents',\n 'position',\n 'quotes',\n 'resize',\n 'right',\n 'rotate',\n 'rowGap',\n 'scale',\n 'scrollBehavior',\n 'scrollMargin',\n 'scrollPadding',\n 'scrollSnapAlign',\n 'scrollSnapStop',\n 'scrollSnapType',\n 'scrollbarColor',\n 'scrollbarGutter',\n 'scrollbarWidth',\n 'shapeOutside',\n 'tabSize',\n 'tableLayout',\n 'textAlign',\n 'textAlignLast',\n 'textCombineUpright',\n 'textDecoration',\n 'textDecorationColor',\n 'textDecorationLine',\n 'textDecorationSkipInk',\n 'textDecorationStyle',\n 'textDecorationThickness',\n 'textEmphasis',\n 'textIndent',\n 'textOrientation',\n 'textOverflow',\n 'textRendering',\n 'textShadow',\n 'textTransform',\n 'textUnderlineOffset',\n 'textUnderlinePosition',\n 'textWrap',\n 'top',\n 'touchAction',\n 'transform',\n 'transformOrigin',\n 'transformStyle',\n 'transition',\n 'transitionDelay',\n 'transitionDuration',\n 'transitionProperty',\n 'transitionTimingFunction',\n 'translate',\n 'unicodeBidi',\n 'userSelect',\n 'verticalAlign',\n 'visibility',\n 'whiteSpace',\n 'widows',\n 'width',\n 'willChange',\n 'wordBreak',\n 'wordSpacing',\n 'writingMode',\n 'zIndex',\n]);\n\n/**\n * Built-in custom units recognized by the tasty parser.\n */\nexport const BUILT_IN_UNITS = new Set([\n 'x',\n 'r',\n 'cr',\n 'bw',\n 'ow',\n 'fs',\n 'lh',\n 'sf',\n]);\n\n/**\n * Standard CSS units (always valid).\n */\nexport const CSS_UNITS = new Set([\n 'px',\n 'em',\n 'rem',\n '%',\n 'vw',\n 'vh',\n 'vmin',\n 'vmax',\n 'ch',\n 'ex',\n 'cm',\n 'mm',\n 'in',\n 'pt',\n 'pc',\n 'fr',\n 'deg',\n 'rad',\n 'turn',\n 'grad',\n 's',\n 'ms',\n 'dpi',\n 'dpcm',\n 'dppx',\n 'svw',\n 'svh',\n 'lvw',\n 'lvh',\n 'dvw',\n 'dvh',\n 'cqw',\n 'cqh',\n 'cqi',\n 'cqb',\n 'cqmin',\n 'cqmax',\n 'cap',\n 'ic',\n 'rlh',\n 'vi',\n 'vb',\n]);\n\n/**\n * Properties that accept `true` as a value (means \"use default\").\n */\nexport const BOOLEAN_TRUE_PROPERTIES = new Set([\n 'border',\n 'radius',\n 'padding',\n 'margin',\n 'gap',\n 'fill',\n 'color',\n 'shadow',\n 'outline',\n 'inset',\n 'width',\n 'height',\n 'hide',\n 'preset',\n 'font',\n 'scrollbar',\n]);\n\n/**\n * Directional modifiers and which properties accept them.\n */\nexport const DIRECTIONAL_MODIFIERS: Record<string, Set<string>> = {\n border: new Set(['top', 'right', 'bottom', 'left']),\n radius: new Set([\n 'top',\n 'right',\n 'bottom',\n 'left',\n 'top-left',\n 'top-right',\n 'bottom-left',\n 'bottom-right',\n ]),\n padding: new Set(['top', 'right', 'bottom', 'left']),\n margin: new Set(['top', 'right', 'bottom', 'left']),\n fade: new Set(['top', 'right', 'bottom', 'left']),\n inset: new Set(['top', 'right', 'bottom', 'left']),\n};\n\n/**\n * Valid radius shape keywords.\n */\nexport const RADIUS_SHAPES = new Set(['round', 'ellipse', 'leaf', 'backleaf']);\n\n/**\n * Known semantic transition names.\n */\nexport const SEMANTIC_TRANSITIONS = new Set([\n 'fade',\n 'fill',\n 'border',\n 'radius',\n 'shadow',\n 'preset',\n 'gap',\n 'theme',\n 'color',\n 'outline',\n 'dimension',\n 'flow',\n 'inset',\n]);\n\n/**\n * Mapping of native CSS properties to tasty shorthand alternatives.\n */\nexport const SHORTHAND_MAPPING: Record<\n string,\n { property: string; hint: string }\n> = {\n backgroundColor: { property: 'fill', hint: \"fill: '...'\" },\n borderColor: { property: 'border', hint: \"border: '...'\" },\n borderWidth: { property: 'border', hint: \"border: '...'\" },\n borderStyle: { property: 'border', hint: \"border: '...'\" },\n borderTop: { property: 'border', hint: \"border: '... top'\" },\n borderRight: { property: 'border', hint: \"border: '... right'\" },\n borderBottom: { property: 'border', hint: \"border: '... bottom'\" },\n borderLeft: { property: 'border', hint: \"border: '... left'\" },\n borderRadius: { property: 'radius', hint: \"radius: '...'\" },\n maxWidth: { property: 'width', hint: \"width: 'max ...'\" },\n minWidth: { property: 'width', hint: \"width: 'min ...'\" },\n maxHeight: { property: 'height', hint: \"height: 'max ...'\" },\n minHeight: { property: 'height', hint: \"height: 'min ...'\" },\n flexDirection: { property: 'flow', hint: \"flow: '...'\" },\n flexWrap: { property: 'flow', hint: \"flow: '...'\" },\n flexFlow: { property: 'flow', hint: \"flow: '...'\" },\n gridAutoFlow: { property: 'flow', hint: \"flow: '...'\" },\n outlineOffset: { property: 'outline', hint: \"outline: '... / offset'\" },\n paddingTop: { property: 'padding', hint: \"padding: '... top'\" },\n paddingRight: { property: 'padding', hint: \"padding: '... right'\" },\n paddingBottom: { property: 'padding', hint: \"padding: '... bottom'\" },\n paddingLeft: { property: 'padding', hint: \"padding: '... left'\" },\n marginTop: { property: 'margin', hint: \"margin: '... top'\" },\n marginRight: { property: 'margin', hint: \"margin: '... right'\" },\n marginBottom: { property: 'margin', hint: \"margin: '... bottom'\" },\n marginLeft: { property: 'margin', hint: \"margin: '... left'\" },\n fontSize: { property: 'preset', hint: \"preset: '...'\" },\n fontWeight: {\n property: 'preset',\n hint: \"preset: '... strong' (with strong modifier)\",\n },\n lineHeight: {\n property: 'preset',\n hint: \"preset: '... tight' (with tight modifier)\",\n },\n boxShadow: { property: 'shadow', hint: \"shadow: '...'\" },\n};\n\n/**\n * Known preset modifiers.\n */\nexport const PRESET_MODIFIERS = new Set(['strong', 'italic', 'tight']);\n\n/**\n * Default import sources for tasty.\n */\nexport const DEFAULT_IMPORT_SOURCES = ['@tenphi/tasty', '@tenphi/tasty/static'];\n\n/**\n * Built-in state prefixes that are always valid (not aliases).\n */\nexport const BUILT_IN_STATE_PREFIXES = new Set([\n '@media',\n '@root',\n '@parent',\n '@own',\n '@supports',\n '@starting',\n '@keyframes',\n '@properties',\n]);\n\n/**\n * Known CSS pseudo-classes.\n */\nexport const KNOWN_PSEUDO_CLASSES = new Set([\n ':hover',\n ':focus',\n ':focus-visible',\n ':focus-within',\n ':active',\n ':visited',\n ':link',\n ':checked',\n ':disabled',\n ':enabled',\n ':empty',\n ':first-child',\n ':last-child',\n ':first-of-type',\n ':last-of-type',\n ':only-child',\n ':only-of-type',\n ':root',\n ':target',\n ':valid',\n ':invalid',\n ':required',\n ':optional',\n ':read-only',\n ':read-write',\n ':placeholder-shown',\n ':autofill',\n ':default',\n ':indeterminate',\n ':in-range',\n ':out-of-range',\n ':any-link',\n ':local-link',\n ':is',\n ':not',\n ':where',\n ':has',\n ':nth-child',\n ':nth-last-child',\n ':nth-of-type',\n ':nth-last-of-type',\n '::before',\n '::after',\n '::placeholder',\n '::selection',\n '::first-line',\n '::first-letter',\n '::marker',\n '::backdrop',\n]);\n"],"mappings":";;;;AAGA,MAAa,yBAAyB,IAAI,IAAI;CAC5C;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD,CAAC;;;;AAKF,MAAa,qBAAqB,IAAI,IAAI,CAAC,cAAc,cAAc,CAAC;;;;;AAMxE,MAAa,uBAAuB,IAAI,IAAI;CAC1C;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD,CAAC;;;;AAKF,MAAa,iBAAiB,IAAI,IAAI;CACpC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD,CAAC;;;;AAKF,MAAa,YAAY,IAAI,IAAI;CAC/B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;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"}
package/dist/context.js CHANGED
@@ -1,12 +1,33 @@
1
1
  import { DEFAULT_IMPORT_SOURCES } from "./constants.js";
2
2
  import { loadConfig } from "./config.js";
3
+ import { getKeyName } from "./utils.js";
3
4
 
4
5
  //#region src/context.ts
6
+ /**
7
+ * AST selectors that match ObjectExpressions in all known tasty style contexts:
8
+ * call sites, variable declarations, satisfies/as expressions.
9
+ */
10
+ const STYLE_OBJECT_SELECTORS = [
11
+ "CallExpression ObjectExpression",
12
+ "VariableDeclarator > ObjectExpression",
13
+ "VariableDeclarator > TSSatisfiesExpression > ObjectExpression",
14
+ "VariableDeclarator > TSAsExpression > ObjectExpression"
15
+ ];
16
+ /**
17
+ * Creates a record of ESLint listeners that all point to the same handler,
18
+ * one entry per style-object AST selector.
19
+ */
20
+ function styleObjectListeners(handler) {
21
+ const listeners = {};
22
+ for (const selector of STYLE_OBJECT_SELECTORS) listeners[selector] = handler;
23
+ return listeners;
24
+ }
5
25
  const TASTY_FUNCTION_NAMES = new Set([
6
26
  "tasty",
7
27
  "tastyStatic",
8
28
  "useStyles",
9
- "useGlobalStyles"
29
+ "useGlobalStyles",
30
+ "configure"
10
31
  ]);
11
32
  /**
12
33
  * Context tracker for a single file's lint pass.
@@ -49,6 +70,16 @@ var TastyContext = class {
49
70
  return this.getStyleContext(node) !== null;
50
71
  }
51
72
  getStyleContext(node) {
73
+ if (node.type === "ObjectExpression") {
74
+ const parent = node.parent;
75
+ if (parent?.type === "Property" && !parent.computed) {
76
+ const key = getKeyName(parent.key);
77
+ if (key && /^[A-Z]/.test(key)) {
78
+ const grandparent = parent.parent;
79
+ if (grandparent?.type === "ObjectExpression") return this.getStyleContext(grandparent);
80
+ }
81
+ }
82
+ }
52
83
  let current = node;
53
84
  while (current) {
54
85
  if (current.type === "CallExpression") {
@@ -152,10 +183,10 @@ var TastyContext = class {
152
183
  * (i.e., an object where keys are state expressions and values are style values).
153
184
  */
154
185
  isStateMap(node, parentProperty) {
155
- const key = parentProperty.key;
156
- if (key.type !== "Identifier") return false;
157
- if (/^[A-Z]/.test(key.name)) return false;
158
- if (key.name === "@keyframes" || key.name === "@properties") return false;
186
+ const keyName = getKeyName(parentProperty.key);
187
+ if (keyName === null) return false;
188
+ if (/^[A-Z]/.test(keyName)) return false;
189
+ if (keyName === "@keyframes" || keyName === "@properties") return false;
159
190
  return node.properties.some((prop) => {
160
191
  if (prop.type !== "Property") return false;
161
192
  if (prop.key.type === "Literal" && prop.key.value === "") return true;
@@ -197,5 +228,5 @@ var TastyContext = class {
197
228
  };
198
229
 
199
230
  //#endregion
200
- export { TastyContext };
231
+ export { TastyContext, styleObjectListeners };
201
232
  //# sourceMappingURL=context.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"context.js","names":[],"sources":["../src/context.ts"],"sourcesContent":["import type { TSESTree } from '@typescript-eslint/utils';\nimport type { RuleContext } from '@typescript-eslint/utils/ts-eslint';\nimport type { ResolvedConfig } from './types.js';\nimport { loadConfig } from './config.js';\nimport { DEFAULT_IMPORT_SOURCES } from './constants.js';\n\nexport interface TastyImport {\n localName: string;\n importedName: string;\n source: string;\n}\n\nconst TASTY_FUNCTION_NAMES = new Set([\n 'tasty',\n 'tastyStatic',\n 'useStyles',\n 'useGlobalStyles',\n]);\n\n/**\n * Context tracker for a single file's lint pass.\n * Tracks which imports come from tasty and provides\n * helpers to determine if a node is in a tasty style context.\n */\nexport class TastyContext {\n readonly config: ResolvedConfig;\n private imports = new Map<string, TastyImport>();\n private importSources: Set<string>;\n\n constructor(\n private context: RuleContext<string, unknown[]>,\n config?: ResolvedConfig,\n ) {\n this.config = config ?? loadConfig(context.filename);\n this.importSources = new Set([\n ...DEFAULT_IMPORT_SOURCES,\n ...this.config.importSources,\n ]);\n }\n\n trackImport(node: TSESTree.ImportDeclaration): void {\n const source = node.source.value;\n if (!this.importSources.has(source)) return;\n\n for (const specifier of node.specifiers) {\n if (specifier.type === 'ImportSpecifier') {\n const importedName =\n specifier.imported.type === 'Identifier'\n ? specifier.imported.name\n : specifier.imported.value;\n if (TASTY_FUNCTION_NAMES.has(importedName)) {\n this.imports.set(specifier.local.name, {\n localName: specifier.local.name,\n importedName,\n source,\n });\n }\n }\n }\n }\n\n getImport(localName: string): TastyImport | undefined {\n return this.imports.get(localName);\n }\n\n isTastyCall(node: TSESTree.CallExpression): TastyImport | undefined {\n if (node.callee.type !== 'Identifier') return undefined;\n return this.imports.get(node.callee.name);\n }\n\n /**\n * Determines whether an object expression is a tasty style object\n * by walking up the AST to find a recognized call expression.\n */\n isStyleObject(node: TSESTree.ObjectExpression): boolean {\n return this.getStyleContext(node) !== null;\n }\n\n getStyleContext(node: TSESTree.Node): {\n type: 'tasty' | 'tastyStatic' | 'useStyles' | 'useGlobalStyles';\n isStaticCall: boolean;\n isSelectorMode: boolean;\n isExtending: boolean;\n } | null {\n let current: TSESTree.Node | undefined = node;\n\n while (current) {\n if (current.type === 'CallExpression') {\n const imp = this.isTastyCall(current);\n if (!imp) return null;\n\n const name = imp.importedName;\n const isStaticCall = name === 'tastyStatic';\n\n if (name === 'tasty') {\n return this.getTastyCallContext(current, node);\n }\n\n if (name === 'tastyStatic') {\n return this.getTastyStaticCallContext(current, node);\n }\n\n if (name === 'useStyles') {\n if (current.arguments[0] === node) {\n return {\n type: 'useStyles',\n isStaticCall: false,\n isSelectorMode: false,\n isExtending: false,\n };\n }\n }\n\n if (name === 'useGlobalStyles') {\n if (current.arguments[1] === node) {\n return {\n type: 'useGlobalStyles',\n isStaticCall,\n isSelectorMode: true,\n isExtending: false,\n };\n }\n }\n\n return null;\n }\n\n if (this.isStyleVariableDeclaration(current, node)) {\n return {\n type: 'tasty',\n isStaticCall: false,\n isSelectorMode: false,\n isExtending: false,\n };\n }\n\n current = current.parent;\n }\n\n return null;\n }\n\n private isStyleVariableDeclaration(\n current: TSESTree.Node,\n targetNode: TSESTree.Node,\n ): boolean {\n if (current.type !== 'VariableDeclarator' || current.id.type !== 'Identifier') {\n return false;\n }\n\n let init: TSESTree.Node | null | undefined = current.init;\n while (\n init?.type === 'TSAsExpression' ||\n init?.type === 'TSSatisfiesExpression' ||\n init?.type === 'TSTypeAssertion' ||\n init?.type === 'TSNonNullExpression'\n ) {\n init = (init as TSESTree.TSAsExpression).expression;\n }\n\n if (init !== targetNode) return false;\n\n if (/styles?$/i.test(current.id.name)) return true;\n\n if (this.hasStylesTypeAnnotation(current)) return true;\n\n return false;\n }\n\n private hasStylesTypeAnnotation(node: TSESTree.VariableDeclarator): boolean {\n const annotation = node.id.typeAnnotation?.typeAnnotation;\n if (!annotation) return false;\n\n if (\n annotation.type === 'TSTypeReference' &&\n annotation.typeName.type === 'Identifier'\n ) {\n return /^Styles$/i.test(annotation.typeName.name);\n }\n\n return false;\n }\n\n private getTastyCallContext(\n call: TSESTree.CallExpression,\n targetNode: TSESTree.Node,\n ) {\n const args = call.arguments;\n\n // tasty({ styles: { ... } }) or tasty(Component, { styles: { ... } })\n const optionsArg =\n args.length >= 2 && args[0].type !== 'ObjectExpression'\n ? args[1]\n : args[0];\n\n if (\n optionsArg?.type === 'ObjectExpression' &&\n this.isInsideStylesProperty(optionsArg, targetNode)\n ) {\n return {\n type: 'tasty' as const,\n isStaticCall: false,\n isSelectorMode: false,\n isExtending: args.length >= 2 && args[0].type !== 'ObjectExpression',\n };\n }\n\n // Check if inside variants\n if (\n optionsArg?.type === 'ObjectExpression' &&\n this.isInsideVariantsProperty(optionsArg, targetNode)\n ) {\n return {\n type: 'tasty' as const,\n isStaticCall: false,\n isSelectorMode: false,\n isExtending: false,\n };\n }\n\n return null;\n }\n\n private getTastyStaticCallContext(\n call: TSESTree.CallExpression,\n targetNode: TSESTree.Node,\n ) {\n const args = call.arguments;\n\n // tastyStatic({ ... })\n if (args.length === 1 && args[0] === targetNode) {\n return {\n type: 'tastyStatic' as const,\n isStaticCall: true,\n isSelectorMode: false,\n isExtending: false,\n };\n }\n\n // tastyStatic(base, { ... }) or tastyStatic('selector', { ... })\n if (args.length === 2 && args[1] === targetNode) {\n const isSelectorMode = args[0].type === 'Literal';\n return {\n type: 'tastyStatic' as const,\n isStaticCall: true,\n isSelectorMode,\n isExtending: !isSelectorMode,\n };\n }\n\n return null;\n }\n\n private isInsideStylesProperty(\n optionsObj: TSESTree.ObjectExpression,\n targetNode: TSESTree.Node,\n ): boolean {\n for (const prop of optionsObj.properties) {\n if (\n prop.type === 'Property' &&\n prop.key.type === 'Identifier' &&\n prop.key.name === 'styles' &&\n prop.value === targetNode\n ) {\n return true;\n }\n }\n return false;\n }\n\n private isInsideVariantsProperty(\n optionsObj: TSESTree.ObjectExpression,\n targetNode: TSESTree.Node,\n ): boolean {\n for (const prop of optionsObj.properties) {\n if (\n prop.type === 'Property' &&\n prop.key.type === 'Identifier' &&\n prop.key.name === 'variants' &&\n prop.value.type === 'ObjectExpression'\n ) {\n for (const variantProp of prop.value.properties) {\n if (\n variantProp.type === 'Property' &&\n variantProp.value === targetNode\n ) {\n return true;\n }\n }\n }\n }\n return false;\n }\n\n /**\n * Checks if a property value node is a state mapping object\n * (i.e., an object where keys are state expressions and values are style values).\n */\n isStateMap(\n node: TSESTree.ObjectExpression,\n parentProperty: TSESTree.Property,\n ): boolean {\n const key = parentProperty.key;\n if (key.type !== 'Identifier') return false;\n\n // If the key starts with uppercase, it's a sub-element, not a state map\n if (/^[A-Z]/.test(key.name)) return false;\n\n // Special keys are not state maps\n if (key.name === '@keyframes' || key.name === '@properties') return false;\n\n // If the object has keys that look like state expressions, it's a state map\n return node.properties.some((prop) => {\n if (prop.type !== 'Property') return false;\n if (prop.key.type === 'Literal' && prop.key.value === '') return true;\n if (prop.key.type === 'Identifier') return true;\n if (prop.key.type === 'Literal' && typeof prop.key.value === 'string') {\n return true;\n }\n return false;\n });\n }\n\n /**\n * Checks if a key represents a sub-element (starts with uppercase).\n */\n isSubElementKey(key: string): boolean {\n return /^[A-Z]/.test(key);\n }\n\n /**\n * Checks if a key represents a nested selector (starts with &).\n */\n isNestedSelectorKey(key: string): boolean {\n return key.startsWith('&');\n }\n\n /**\n * Checks if a key is a custom CSS property definition ($name or $$name).\n */\n isCustomPropertyKey(key: string): boolean {\n return key.startsWith('$');\n }\n\n /**\n * Checks if a key is a color token definition (#name or ##name).\n */\n isColorTokenKey(key: string): boolean {\n return key.startsWith('#');\n }\n\n /**\n * Checks if a key is a special @ property (@keyframes, @properties).\n */\n isSpecialKey(key: string): boolean {\n return key.startsWith('@');\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"context.js","names":[],"sources":["../src/context.ts"],"sourcesContent":["import type { TSESTree } from '@typescript-eslint/utils';\nimport type { RuleContext } from '@typescript-eslint/utils/ts-eslint';\nimport type { ResolvedConfig } from './types.js';\nimport { loadConfig } from './config.js';\nimport { DEFAULT_IMPORT_SOURCES } from './constants.js';\nimport { getKeyName } from './utils.js';\n\n/**\n * AST selectors that match ObjectExpressions in all known tasty style contexts:\n * call sites, variable declarations, satisfies/as expressions.\n */\nexport const STYLE_OBJECT_SELECTORS = [\n 'CallExpression ObjectExpression',\n 'VariableDeclarator > ObjectExpression',\n 'VariableDeclarator > TSSatisfiesExpression > ObjectExpression',\n 'VariableDeclarator > TSAsExpression > ObjectExpression',\n] as const;\n\n/**\n * Creates a record of ESLint listeners that all point to the same handler,\n * one entry per style-object AST selector.\n */\nexport function styleObjectListeners(\n handler: (node: TSESTree.ObjectExpression) => void,\n): Record<string, (node: TSESTree.ObjectExpression) => void> {\n const listeners: Record<string, (node: TSESTree.ObjectExpression) => void> =\n {};\n for (const selector of STYLE_OBJECT_SELECTORS) {\n listeners[selector] = handler;\n }\n return listeners;\n}\n\nexport interface TastyImport {\n localName: string;\n importedName: string;\n source: string;\n}\n\nconst TASTY_FUNCTION_NAMES = new Set([\n 'tasty',\n 'tastyStatic',\n 'useStyles',\n 'useGlobalStyles',\n 'configure',\n]);\n\n/**\n * Context tracker for a single file's lint pass.\n * Tracks which imports come from tasty and provides\n * helpers to determine if a node is in a tasty style context.\n */\nexport class TastyContext {\n readonly config: ResolvedConfig;\n private imports = new Map<string, TastyImport>();\n private importSources: Set<string>;\n\n constructor(\n private context: RuleContext<string, unknown[]>,\n config?: ResolvedConfig,\n ) {\n this.config = config ?? loadConfig(context.filename);\n this.importSources = new Set([\n ...DEFAULT_IMPORT_SOURCES,\n ...this.config.importSources,\n ]);\n }\n\n trackImport(node: TSESTree.ImportDeclaration): void {\n const source = node.source.value;\n if (!this.importSources.has(source)) return;\n\n for (const specifier of node.specifiers) {\n if (specifier.type === 'ImportSpecifier') {\n const importedName =\n specifier.imported.type === 'Identifier'\n ? specifier.imported.name\n : specifier.imported.value;\n if (TASTY_FUNCTION_NAMES.has(importedName)) {\n this.imports.set(specifier.local.name, {\n localName: specifier.local.name,\n importedName,\n source,\n });\n }\n }\n }\n }\n\n getImport(localName: string): TastyImport | undefined {\n return this.imports.get(localName);\n }\n\n isTastyCall(node: TSESTree.CallExpression): TastyImport | undefined {\n if (node.callee.type !== 'Identifier') return undefined;\n return this.imports.get(node.callee.name);\n }\n\n /**\n * Determines whether an object expression is a tasty style object\n * by walking up the AST to find a recognized call expression.\n */\n isStyleObject(node: TSESTree.ObjectExpression): boolean {\n return this.getStyleContext(node) !== null;\n }\n\n getStyleContext(node: TSESTree.Node): {\n type: 'tasty' | 'tastyStatic' | 'useStyles' | 'useGlobalStyles';\n isStaticCall: boolean;\n isSelectorMode: boolean;\n isExtending: boolean;\n } | null {\n // Sub-element objects inherit their parent style object's context\n if (node.type === 'ObjectExpression') {\n const parent = node.parent;\n if (parent?.type === 'Property' && !parent.computed) {\n const key = getKeyName(parent.key);\n if (key && /^[A-Z]/.test(key)) {\n const grandparent = parent.parent;\n if (grandparent?.type === 'ObjectExpression') {\n return this.getStyleContext(grandparent);\n }\n }\n }\n }\n\n let current: TSESTree.Node | undefined = node;\n\n while (current) {\n if (current.type === 'CallExpression') {\n const imp = this.isTastyCall(current);\n if (!imp) return null;\n\n const name = imp.importedName;\n const isStaticCall = name === 'tastyStatic';\n\n if (name === 'tasty') {\n return this.getTastyCallContext(current, node);\n }\n\n if (name === 'tastyStatic') {\n return this.getTastyStaticCallContext(current, node);\n }\n\n if (name === 'useStyles') {\n if (current.arguments[0] === node) {\n return {\n type: 'useStyles',\n isStaticCall: false,\n isSelectorMode: false,\n isExtending: false,\n };\n }\n }\n\n if (name === 'useGlobalStyles') {\n if (current.arguments[1] === node) {\n return {\n type: 'useGlobalStyles',\n isStaticCall,\n isSelectorMode: true,\n isExtending: false,\n };\n }\n }\n\n return null;\n }\n\n if (this.isStyleVariableDeclaration(current, node)) {\n return {\n type: 'tasty',\n isStaticCall: false,\n isSelectorMode: false,\n isExtending: false,\n };\n }\n\n current = current.parent;\n }\n\n return null;\n }\n\n private isStyleVariableDeclaration(\n current: TSESTree.Node,\n targetNode: TSESTree.Node,\n ): boolean {\n if (\n current.type !== 'VariableDeclarator' ||\n current.id.type !== 'Identifier'\n ) {\n return false;\n }\n\n let init: TSESTree.Node | null | undefined = current.init;\n while (\n init?.type === 'TSAsExpression' ||\n init?.type === 'TSSatisfiesExpression' ||\n init?.type === 'TSTypeAssertion' ||\n init?.type === 'TSNonNullExpression'\n ) {\n init = (init as TSESTree.TSAsExpression).expression;\n }\n\n if (init !== targetNode) return false;\n\n if (/styles?$/i.test(current.id.name)) return true;\n\n if (this.hasStylesTypeAnnotation(current)) return true;\n\n return false;\n }\n\n private hasStylesTypeAnnotation(node: TSESTree.VariableDeclarator): boolean {\n const annotation = node.id.typeAnnotation?.typeAnnotation;\n if (!annotation) return false;\n\n if (\n annotation.type === 'TSTypeReference' &&\n annotation.typeName.type === 'Identifier'\n ) {\n return /^Styles$/i.test(annotation.typeName.name);\n }\n\n return false;\n }\n\n private getTastyCallContext(\n call: TSESTree.CallExpression,\n targetNode: TSESTree.Node,\n ) {\n const args = call.arguments;\n\n // tasty({ styles: { ... } }) or tasty(Component, { styles: { ... } })\n const optionsArg =\n args.length >= 2 && args[0].type !== 'ObjectExpression'\n ? args[1]\n : args[0];\n\n if (\n optionsArg?.type === 'ObjectExpression' &&\n this.isInsideStylesProperty(optionsArg, targetNode)\n ) {\n return {\n type: 'tasty' as const,\n isStaticCall: false,\n isSelectorMode: false,\n isExtending: args.length >= 2 && args[0].type !== 'ObjectExpression',\n };\n }\n\n // Check if inside variants\n if (\n optionsArg?.type === 'ObjectExpression' &&\n this.isInsideVariantsProperty(optionsArg, targetNode)\n ) {\n return {\n type: 'tasty' as const,\n isStaticCall: false,\n isSelectorMode: false,\n isExtending: false,\n };\n }\n\n return null;\n }\n\n private getTastyStaticCallContext(\n call: TSESTree.CallExpression,\n targetNode: TSESTree.Node,\n ) {\n const args = call.arguments;\n\n // tastyStatic({ ... })\n if (args.length === 1 && args[0] === targetNode) {\n return {\n type: 'tastyStatic' as const,\n isStaticCall: true,\n isSelectorMode: false,\n isExtending: false,\n };\n }\n\n // tastyStatic(base, { ... }) or tastyStatic('selector', { ... })\n if (args.length === 2 && args[1] === targetNode) {\n const isSelectorMode = args[0].type === 'Literal';\n return {\n type: 'tastyStatic' as const,\n isStaticCall: true,\n isSelectorMode,\n isExtending: !isSelectorMode,\n };\n }\n\n return null;\n }\n\n private isInsideStylesProperty(\n optionsObj: TSESTree.ObjectExpression,\n targetNode: TSESTree.Node,\n ): boolean {\n for (const prop of optionsObj.properties) {\n if (\n prop.type === 'Property' &&\n prop.key.type === 'Identifier' &&\n prop.key.name === 'styles' &&\n prop.value === targetNode\n ) {\n return true;\n }\n }\n return false;\n }\n\n private isInsideVariantsProperty(\n optionsObj: TSESTree.ObjectExpression,\n targetNode: TSESTree.Node,\n ): boolean {\n for (const prop of optionsObj.properties) {\n if (\n prop.type === 'Property' &&\n prop.key.type === 'Identifier' &&\n prop.key.name === 'variants' &&\n prop.value.type === 'ObjectExpression'\n ) {\n for (const variantProp of prop.value.properties) {\n if (\n variantProp.type === 'Property' &&\n variantProp.value === targetNode\n ) {\n return true;\n }\n }\n }\n }\n return false;\n }\n\n /**\n * Checks if a property value node is a state mapping object\n * (i.e., an object where keys are state expressions and values are style values).\n */\n isStateMap(\n node: TSESTree.ObjectExpression,\n parentProperty: TSESTree.Property,\n ): boolean {\n const keyName = getKeyName(parentProperty.key);\n if (keyName === null) return false;\n\n // If the key starts with uppercase, it's a sub-element, not a state map\n if (/^[A-Z]/.test(keyName)) return false;\n\n // Special keys are not state maps\n if (keyName === '@keyframes' || keyName === '@properties') return false;\n\n // If the object has keys that look like state expressions, it's a state map\n return node.properties.some((prop) => {\n if (prop.type !== 'Property') return false;\n if (prop.key.type === 'Literal' && prop.key.value === '') return true;\n if (prop.key.type === 'Identifier') return true;\n if (prop.key.type === 'Literal' && typeof prop.key.value === 'string') {\n return true;\n }\n return false;\n });\n }\n\n /**\n * Checks if a key represents a sub-element (starts with uppercase).\n */\n isSubElementKey(key: string): boolean {\n return /^[A-Z]/.test(key);\n }\n\n /**\n * Checks if a key represents a nested selector (starts with &).\n */\n isNestedSelectorKey(key: string): boolean {\n return key.startsWith('&');\n }\n\n /**\n * Checks if a key is a custom CSS property definition ($name or $$name).\n */\n isCustomPropertyKey(key: string): boolean {\n return key.startsWith('$');\n }\n\n /**\n * Checks if a key is a color token definition (#name or ##name).\n */\n isColorTokenKey(key: string): boolean {\n return key.startsWith('#');\n }\n\n /**\n * Checks if a key is a special @ property (@keyframes, @properties).\n */\n isSpecialKey(key: string): boolean {\n return key.startsWith('@');\n }\n}\n"],"mappings":"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"}
package/dist/index.js CHANGED
@@ -25,6 +25,7 @@ import no_raw_color_values_default from "./rules/no-raw-color-values.js";
25
25
  import no_styles_prop_default from "./rules/no-styles-prop.js";
26
26
  import consistent_token_usage_default from "./rules/consistent-token-usage.js";
27
27
  import no_runtime_styles_mutation_default from "./rules/no-runtime-styles-mutation.js";
28
+ import valid_state_definition_default from "./rules/valid-state-definition.js";
28
29
  import { recommended, strict } from "./configs.js";
29
30
 
30
31
  //#region src/index.ts
@@ -60,7 +61,8 @@ const plugin = {
60
61
  "no-raw-color-values": no_raw_color_values_default,
61
62
  "no-styles-prop": no_styles_prop_default,
62
63
  "consistent-token-usage": consistent_token_usage_default,
63
- "no-runtime-styles-mutation": no_runtime_styles_mutation_default
64
+ "no-runtime-styles-mutation": no_runtime_styles_mutation_default,
65
+ "valid-state-definition": valid_state_definition_default
64
66
  },
65
67
  configs: {
66
68
  recommended: {