kensington-eslint-plugin 0.3.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kensington-eslint-plugin",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "ESLint rules for kensington signal correctness",
5
5
  "type": "module",
6
6
  "main": "index.js",
package/rules/_utils.js CHANGED
@@ -89,6 +89,28 @@ export function getObjectNames(context) {
89
89
  return context.options[0]?.objectNames ?? context.settings?.kensington?.objectNames;
90
90
  }
91
91
 
92
+ // Default set of attribute namespaces — kebab prefixes whose hyphenated
93
+ // children form an unbounded, namespaced family (data-*, aria-*). Mirrors the
94
+ // Kensington `additionalNamespaces` defaults.
95
+ export const DEFAULT_NAMESPACES = ['data', 'aria'];
96
+
97
+ // Standard rule schema entry for the `namespaces` option.
98
+ export const namespacesSchema = {
99
+ type: 'array',
100
+ items: { type: 'string' },
101
+ uniqueItems: true,
102
+ };
103
+
104
+ // Resolve `namespaces` from per-rule options first, then from plugin-level
105
+ // settings (`settings.kensington.namespaces`), then from `DEFAULT_NAMESPACES`.
106
+ export function getNamespaces(context) {
107
+ return (
108
+ context.options[0]?.namespaces
109
+ ?? context.settings?.kensington?.namespaces
110
+ ?? DEFAULT_NAMESPACES
111
+ );
112
+ }
113
+
92
114
  // Returns the property key as a string, or null if computed/unrecognised.
93
115
  export function getPropertyKey(prop) {
94
116
  if (prop.type !== 'Property') { return null; }
@@ -1,29 +1,37 @@
1
- import { getTagAttrsObject, getPropertyKey, normalizeAttrName, kebabToCamel, isValidIdentifier, getObjectNames, objectNamesSchema } from './_utils.js';
1
+ import { getTagAttrsObject, getPropertyKey, normalizeAttrName, kebabToCamel, isValidIdentifier, getObjectNames, getNamespaces, objectNamesSchema, namespacesSchema } from './_utils.js';
2
2
 
3
- // When two or more attribute keys share the same kebab-case prefix (e.g.
4
- // hxGet/hxTrigger/hxTarget or dataPageContent/dataPageNav), prefer the nested
5
- // object form: `hx: { get: ..., trigger: ..., target: ... }`.
3
+ // When two or more attribute keys share the same namespace prefix (data-*,
4
+ // aria-*, hx-*, etc.), prefer the nested object form. The default namespace
5
+ // list is ['data', 'aria']; override via the `namespaces` option or
6
+ // plugin-level `settings.kensington.namespaces`. The rule does NOT fire for
7
+ // multi-word HTML/SVG attribute names that happen to share a word (e.g.
8
+ // strokeWidth + strokeLinecap are separate attributes, not a "stroke
9
+ // namespace").
6
10
 
7
11
  export default {
8
12
  meta: {
9
13
  type: 'suggestion',
10
14
  fixable: 'code',
11
15
  docs: {
12
- description: 'prefer nested object form for attributes sharing a kebab-case prefix',
16
+ description: 'prefer nested object form for attributes sharing a namespace prefix',
13
17
  },
14
18
  schema: [{
15
19
  type: 'object',
16
- properties: { objectNames: objectNamesSchema },
20
+ properties: {
21
+ objectNames: objectNamesSchema,
22
+ namespaces: namespacesSchema,
23
+ },
17
24
  additionalProperties: false,
18
25
  }],
19
26
  messages: {
20
- preferNested: 'Attributes sharing the `{{prefix}}-` prefix should be nested under a single `{{prefix}}` key.',
27
+ preferNested: 'Attributes sharing the `{{prefix}}-` namespace should be nested under a single `{{prefix}}` key.',
21
28
  },
22
29
  },
23
30
 
24
31
  create(context) {
25
32
  const sourceCode = context.sourceCode;
26
33
  const objectNames = getObjectNames(context);
34
+ const namespaces = new Set(getNamespaces(context));
27
35
 
28
36
  return {
29
37
  CallExpression(node) {
@@ -40,6 +48,7 @@ export default {
40
48
  if (hy === -1) { continue; }
41
49
  const prefix = kebab.slice(0, hy);
42
50
  if (!isValidIdentifier(prefix)) { continue; }
51
+ if (!namespaces.has(prefix)) { continue; }
43
52
  if (!groups.has(prefix)) { groups.set(prefix, []); }
44
53
  groups.get(prefix).push({ prop, remainder: kebab.slice(hy + 1) });
45
54
  }