@dialpad/eslint-plugin-dialtone 1.13.0-next.1 → 1.13.0-next.2

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.
@@ -0,0 +1,104 @@
1
+ /**
2
+ * @fileoverview Detect deprecated `d-stack*` / `d-flow*` sibling-margin classes;
3
+ * recommend `<dt-stack>` with the equivalent `gap` prop.
4
+ */
5
+ 'use strict';
6
+
7
+ // Word boundaries handle responsive prefixes (`md:d-stack16`) and adjacent classes.
8
+ // Capture group 1 is the px size; used to map to the equivalent `<dt-stack>` `gap` token.
9
+ const DEPRECATED_AUTO_SPACING_RE = /\bd-(?:stack|flow)(\d+)\b/;
10
+
11
+ // Same pattern as a quoted string literal anywhere inside a `:class` binding.
12
+ // Scans the whole quoted span so multi-class strings (`'d-ps-relative d-stack2 d-px-0'`)
13
+ // and responsive prefixes (`'md:d-stack16'`) both match.
14
+ const DEPRECATED_IN_BINDING_RE = /['"][^'"]*\bd-(?:stack|flow)\d+\b[^'"]*['"]/;
15
+
16
+ // Mirrors the table in docs/rules/deprecated-stack-flow-classes.md.
17
+ const PX_TO_GAP = {
18
+ 0: '0',
19
+ 1: '1',
20
+ 2: '25',
21
+ 4: '50',
22
+ 6: '75',
23
+ 8: '100',
24
+ 12: '150',
25
+ 16: '200',
26
+ 20: '250',
27
+ 24: '300',
28
+ 32: '400',
29
+ 48: '600',
30
+ 64: '800',
31
+ };
32
+
33
+ function describeMatch(text) {
34
+ const match = DEPRECATED_AUTO_SPACING_RE.exec(text);
35
+ if (!match) return null;
36
+ const px = match[1];
37
+ const gap = PX_TO_GAP[px];
38
+ return { className: match[0], px, gap };
39
+ }
40
+
41
+ /** @type {import('eslint').Rule.RuleModule} */
42
+ module.exports = {
43
+ meta: {
44
+ type: 'suggestion',
45
+ docs: {
46
+ description: 'Detect deprecated `d-stack*` / `d-flow*` sibling-margin utilities; prefer `<dt-stack>` with the equivalent `gap` prop',
47
+ recommended: false,
48
+ url: 'https://github.com/dialpad/dialtone/blob/staging/packages/eslint-plugin-dialtone/docs/rules/deprecated-stack-flow-classes.md',
49
+ },
50
+ fixable: null,
51
+ schema: [],
52
+ messages: {
53
+ preferStack: '`{{className}}` is deprecated. Use `<dt-stack>` with `gap="{{gap}}"` instead.',
54
+ preferStackUnmapped: '`{{className}}` is deprecated. No exact `gap` equivalent for {{px}}px — use the closest `<dt-stack>` `gap` value (see rule docs).',
55
+ preferStackInBinding: '`{{className}}` detected in dynamic `:class` binding. Use `<dt-stack>` with `gap="{{gap}}"`. Manual migration required.',
56
+ preferStackInBindingUnmapped: '`{{className}}` detected in dynamic `:class` binding. No exact `gap` equivalent for {{px}}px — use the closest `<dt-stack>` `gap` value (see rule docs). Manual migration required.',
57
+ },
58
+ },
59
+
60
+ create(context) {
61
+ const sourceCode = context.sourceCode ?? context.getSourceCode();
62
+ const defineTemplateBodyVisitor = sourceCode.parserServices?.defineTemplateBodyVisitor;
63
+ if (!defineTemplateBodyVisitor) return {};
64
+
65
+ return defineTemplateBodyVisitor({
66
+
67
+ VElement(node) {
68
+ const classAttr = node.startTag.attributes.find(
69
+ attr => attr.key && attr.key.name === 'class' && !attr.directive,
70
+ );
71
+
72
+ if (classAttr && classAttr.value && classAttr.value.value) {
73
+ const info = describeMatch(classAttr.value.value);
74
+ if (info) {
75
+ context.report({
76
+ node: classAttr,
77
+ messageId: info.gap ? 'preferStack' : 'preferStackUnmapped',
78
+ data: info,
79
+ });
80
+ }
81
+ }
82
+ },
83
+
84
+ VAttribute(node) {
85
+ if (node.directive &&
86
+ node.key.name.name === 'bind' &&
87
+ node.key.argument?.name === 'class' &&
88
+ node.value) {
89
+ const bindingText = sourceCode.getText(node.value);
90
+ if (DEPRECATED_IN_BINDING_RE.test(bindingText)) {
91
+ const info = describeMatch(bindingText);
92
+ if (info) {
93
+ context.report({
94
+ node: node,
95
+ messageId: info.gap ? 'preferStackInBinding' : 'preferStackInBindingUnmapped',
96
+ data: info,
97
+ });
98
+ }
99
+ }
100
+ }
101
+ },
102
+ });
103
+ },
104
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dialpad/eslint-plugin-dialtone",
3
- "version": "1.13.0-next.1",
3
+ "version": "1.13.0-next.2",
4
4
  "description": "dialtone eslint plugin",
5
5
  "keywords": [
6
6
  "Dialpad",
@@ -29,6 +29,11 @@
29
29
  "name": "Nina Repetto",
30
30
  "email": "nina.repetto@dialpad.com",
31
31
  "url": "https://github.com/ninamarina"
32
+ },
33
+ {
34
+ "name": "Belu Montoya",
35
+ "email": "belu.montoya@dialpad.com",
36
+ "url": "https://github.com/belumontoya"
32
37
  }
33
38
  ],
34
39
  "bugs": {