@plumeria/eslint-plugin 18.5.3 → 19.0.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.
package/README.md CHANGED
@@ -21,6 +21,7 @@ The `plugin:@plumeria/recommended` config enables the following:
21
21
  - `@plumeria/format-properties`: **warn**
22
22
  - `@plumeria/validate-values`: **warn**
23
23
  - `@plumeria/validate-pseudos`: **error**
24
+ - `@plumeria/validate-at-rules`: **error**
24
25
 
25
26
  ```js
26
27
  import plumeria from '@plumeria/eslint-plugin';
@@ -148,6 +149,10 @@ Validates CSS property values for correctness. Only standard CSS properties are
148
149
 
149
150
  Validates CSS pseudo-classes and pseudo-elements inside `css.create()`. It checks for typos and structural correctness and supports validation of computed keys when TypeScript is available.
150
151
 
152
+ ### validate-at-rules
153
+
154
+ Validates at-rules inside `css.create()`. It accepts `@media`, `@container`, `@supports`, `@layer`, and `@scope`, and supports validation of computed keys when TypeScript is available.
155
+
151
156
  ## Optional rules
152
157
 
153
158
  These rules are not enabled by `plumeria.configs.recommended`. Enable only the
package/dist/index.js CHANGED
@@ -16,6 +16,7 @@ const sort_properties_1 = require("./rules/sort-properties");
16
16
  const format_properties_1 = require("./rules/format-properties");
17
17
  const validate_values_1 = require("./rules/validate-values");
18
18
  const validate_pseudos_1 = require("./rules/validate-pseudos");
19
+ const validate_at_rules_1 = require("./rules/validate-at-rules");
19
20
  const rules = {
20
21
  'props-require-import': props_require_import_1.propsRequireImport,
21
22
  'expand-border-shorthands': expand_border_shorthands_1.expandBorderShorthands,
@@ -34,6 +35,7 @@ const rules = {
34
35
  'format-properties': format_properties_1.formatProperties,
35
36
  'validate-values': validate_values_1.validateValues,
36
37
  'validate-pseudos': validate_pseudos_1.validatePseudos,
38
+ 'validate-at-rules': validate_at_rules_1.validateAtRules,
37
39
  };
38
40
  const configs = {
39
41
  recommended: {
@@ -57,6 +59,7 @@ const configs = {
57
59
  '@plumeria/format-properties': 'warn',
58
60
  '@plumeria/validate-values': 'warn',
59
61
  '@plumeria/validate-pseudos': 'error',
62
+ '@plumeria/validate-at-rules': 'error',
60
63
  },
61
64
  },
62
65
  };
@@ -0,0 +1,3 @@
1
+ import { Rule } from 'eslint';
2
+ export declare function isValidAtRule(rule: string): boolean;
3
+ export declare const validateAtRules: Rule.RuleModule;
@@ -0,0 +1,111 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.validateAtRules = void 0;
4
+ exports.isValidAtRule = isValidAtRule;
5
+ const utils_1 = require("@typescript-eslint/utils");
6
+ const styleObject_1 = require("../util/styleObject");
7
+ const VALID_AT_RULES = [
8
+ '@media ',
9
+ '@container ',
10
+ '@supports ',
11
+ '@layer ',
12
+ '@scope ',
13
+ ];
14
+ function isValidAtRule(rule) {
15
+ return VALID_AT_RULES.some((prefix) => rule.startsWith(prefix) && rule.length > prefix.length);
16
+ }
17
+ exports.validateAtRules = {
18
+ meta: {
19
+ type: 'problem',
20
+ docs: {
21
+ description: 'Validate at-rules inside css.create.',
22
+ },
23
+ messages: {
24
+ invalidAtRule: 'Invalid at-rule: "{{ rule }}".',
25
+ },
26
+ schema: [],
27
+ },
28
+ create(context) {
29
+ const plumeriaAliases = {};
30
+ const parserServices = context.sourceCode.parserServices;
31
+ const checker = parserServices?.program?.getTypeChecker();
32
+ function getKeyString(node) {
33
+ if (node.type === utils_1.TSESTree.AST_NODE_TYPES.Literal &&
34
+ typeof node.value === 'string') {
35
+ return node.value;
36
+ }
37
+ if (checker && parserServices?.esTreeNodeToTSNodeMap) {
38
+ try {
39
+ const tsNode = parserServices.esTreeNodeToTSNodeMap.get(node);
40
+ const type = checker.getTypeAtLocation(tsNode);
41
+ if (type.isStringLiteral())
42
+ return type.value;
43
+ }
44
+ catch (error) {
45
+ }
46
+ }
47
+ return null;
48
+ }
49
+ function checkProperties(node) {
50
+ for (const prop of node.properties) {
51
+ if (prop.type !== utils_1.TSESTree.AST_NODE_TYPES.Property)
52
+ continue;
53
+ const key = getKeyString(prop.key);
54
+ if (key?.startsWith('@') && !isValidAtRule(key)) {
55
+ context.report({
56
+ node: prop.key,
57
+ messageId: 'invalidAtRule',
58
+ data: { rule: key },
59
+ });
60
+ }
61
+ if (prop.value.type === utils_1.TSESTree.AST_NODE_TYPES.ObjectExpression) {
62
+ checkProperties(prop.value);
63
+ }
64
+ }
65
+ }
66
+ return {
67
+ ImportDeclaration(node) {
68
+ if (node.source.value !== '@plumeria/core')
69
+ return;
70
+ node.specifiers.forEach((specifier) => {
71
+ if (specifier.type ===
72
+ utils_1.TSESTree.AST_NODE_TYPES.ImportNamespaceSpecifier ||
73
+ specifier.type === utils_1.TSESTree.AST_NODE_TYPES.ImportDefaultSpecifier) {
74
+ plumeriaAliases[specifier.local.name] = 'NAMESPACE';
75
+ }
76
+ else {
77
+ const importedName = specifier.imported.type === utils_1.TSESTree.AST_NODE_TYPES.Identifier
78
+ ? specifier.imported.name
79
+ : String(specifier.imported.value);
80
+ plumeriaAliases[specifier.local.name] = importedName;
81
+ }
82
+ });
83
+ },
84
+ CallExpression(node) {
85
+ let isCssCreate = false;
86
+ if (node.callee.type === utils_1.TSESTree.AST_NODE_TYPES.MemberExpression &&
87
+ node.callee.object.type === utils_1.TSESTree.AST_NODE_TYPES.Identifier &&
88
+ plumeriaAliases[node.callee.object.name] === 'NAMESPACE' &&
89
+ node.callee.property.type === utils_1.TSESTree.AST_NODE_TYPES.Identifier &&
90
+ node.callee.property.name === 'create') {
91
+ isCssCreate = true;
92
+ }
93
+ else if (node.callee.type === utils_1.TSESTree.AST_NODE_TYPES.Identifier &&
94
+ plumeriaAliases[node.callee.name] === 'create') {
95
+ isCssCreate = true;
96
+ }
97
+ if (!isCssCreate ||
98
+ node.arguments[0]?.type !== utils_1.TSESTree.AST_NODE_TYPES.ObjectExpression) {
99
+ return;
100
+ }
101
+ for (const prop of node.arguments[0].properties) {
102
+ if (prop.type !== utils_1.TSESTree.AST_NODE_TYPES.Property)
103
+ continue;
104
+ const style = (0, styleObject_1.styleObjectFromValue)(prop.value);
105
+ if (style)
106
+ checkProperties(style);
107
+ }
108
+ },
109
+ };
110
+ },
111
+ };
package/oxlint.json CHANGED
@@ -22,6 +22,7 @@
22
22
  "@plumeria/sort-properties": "warn",
23
23
  "@plumeria/format-properties": "warn",
24
24
  "@plumeria/validate-values": "warn",
25
- "@plumeria/validate-pseudos": "error"
25
+ "@plumeria/validate-pseudos": "error",
26
+ "@plumeria/validate-at-rules": "error"
26
27
  }
27
28
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plumeria/eslint-plugin",
3
- "version": "18.5.3",
3
+ "version": "19.0.0",
4
4
  "description": "Plumeria ESLint plugin",
5
5
  "author": "Refirst 11",
6
6
  "license": "MIT",