@kong/design-tokens 1.18.3-pr.613.5525a1e.0 → 1.18.3-pr.613.a51766c.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.
@@ -4,7 +4,7 @@ import { KONG_TOKEN_PREFIX, RULE_NAME_PREFIX } from '../../utilities/index.mjs'
4
4
  const { ruleMessages, validateOptions, report } = stylelint.utils
5
5
  const ruleName = `${RULE_NAME_PREFIX}/use-css-token`
6
6
  const messages = ruleMessages(ruleName, {
7
- expected: 'SCSS tokens must be used as fallback values in CSS custom properties. Use format: var(--kui-design-token, $kui-design-token)',
7
+ expected: 'SCSS tokens must be used as fallback values in CSS custom properties. Use format: var(--kui-design-token, $kui-design-token) with exactly one space before the comma and no other spaces.',
8
8
  })
9
9
  const meta = {
10
10
  url: 'https://github.com/Kong/design-tokens/blob/main/stylelint-plugin/README.md',
@@ -33,49 +33,53 @@ const findAllTokenOccurrences = (value, token) => {
33
33
  }
34
34
 
35
35
  // Check if token at given position is properly wrapped in var()
36
+ // Enforces exact format: var(--token, $token) with exactly one space before comma
36
37
  const isTokenProperlyWrapped = (value, tokenIndex, token, cssToken) => {
37
- // Find the var() expression that contains this token
38
- // Look backwards to find the nearest var( before the token
39
- const beforeToken = value.substring(0, tokenIndex)
40
- const varStartIndex = beforeToken.lastIndexOf('var(')
41
-
42
- if (varStartIndex === -1) {
43
- return false
44
- }
38
+ // Use regex to find all var(--token, $token) patterns
39
+ // Escape special regex characters in tokens (though they should only have letters/digits/hyphens)
40
+ const pattern = new RegExp(`var\\(${cssToken}, ${token}\\)`, 'g')
41
+
42
+ console.log(`[DEBUG] Checking token "${token}" at position ${tokenIndex}:`, {
43
+ token,
44
+ tokenIndex,
45
+ cssToken,
46
+ pattern: `var(${cssToken}, ${token})`,
47
+ valueContext: value.substring(Math.max(0, tokenIndex - 50), Math.min(value.length, tokenIndex + token.length + 50)),
48
+ })
49
+
50
+ // Find all matches
51
+ let match
52
+ const matches = []
53
+ while ((match = pattern.exec(value)) !== null) {
54
+ const matchStart = match.index
55
+ const matchEnd = matchStart + match[0].length
56
+ matches.push({
57
+ start: matchStart,
58
+ end: matchEnd,
59
+ match: match[0],
60
+ })
45
61
 
46
- // Find the matching closing parenthesis starting from var(
47
- let parenCount = 0
48
- let searchIndex = varStartIndex
49
- let varEndIndex = -1
50
-
51
- while (searchIndex < value.length) {
52
- const char = value[searchIndex]
53
- if (char === '(') {
54
- parenCount++
55
- } else if (char === ')') {
56
- parenCount--
57
- if (parenCount === 0) {
58
- varEndIndex = searchIndex
59
- break
60
- }
62
+ // Check if our token at tokenIndex is inside this match
63
+ const tokenEndIndex = tokenIndex + token.length
64
+ if (tokenIndex >= matchStart && tokenEndIndex <= matchEnd) {
65
+ console.log(`[DEBUG] Token "${token}" at ${tokenIndex} is properly wrapped in:`, {
66
+ match: match[0],
67
+ matchStart,
68
+ matchEnd,
69
+ tokenIndex,
70
+ tokenEndIndex,
71
+ })
72
+ return true
61
73
  }
62
- searchIndex++
63
74
  }
64
75
 
65
- if (varEndIndex === -1) {
66
- return false
67
- }
76
+ console.log(`[DEBUG] Token "${token}" at ${tokenIndex} is NOT properly wrapped. Found ${matches.length} pattern matches:`, {
77
+ matches,
78
+ tokenIndex,
79
+ tokenEndIndex: tokenIndex + token.length,
80
+ })
68
81
 
69
- // Verify the token is actually inside this var() expression
70
- const tokenEndIndex = tokenIndex + token.length
71
- if (tokenIndex < varStartIndex || tokenEndIndex > varEndIndex) {
72
- return false
73
- }
74
-
75
- // Extract the full var() expression and check if it matches the pattern
76
- const varExpression = value.substring(varStartIndex, varEndIndex + 1)
77
- const expectedPattern = new RegExp(`^var\\(\\s*${cssToken}\\s*,\\s*${token}\\s*\\)$`)
78
- return expectedPattern.test(varExpression)
82
+ return false
79
83
  }
80
84
 
81
85
  const ruleFunction = () => {
@@ -89,6 +93,8 @@ const ruleFunction = () => {
89
93
  postcssRoot.walkDecls((decl) => {
90
94
  const declValue = decl.value
91
95
 
96
+ console.log(`[DEBUG] Checking declaration: ${decl.prop} = "${declValue}"`)
97
+
92
98
  // Extract all SCSS tokens (starting with $kui-)
93
99
  const scssTokenRegex = new RegExp(`\\$${KONG_TOKEN_PREFIX}[a-z0-9-]+`, 'g')
94
100
  const scssTokens = declValue.match(scssTokenRegex)
@@ -101,6 +107,8 @@ const ruleFunction = () => {
101
107
  // Get unique SCSS tokens
102
108
  const uniqueScssTokens = Array.from(new Set(scssTokens))
103
109
 
110
+ console.log(`[DEBUG] Found ${uniqueScssTokens.length} unique SCSS tokens:`, uniqueScssTokens)
111
+
104
112
  // Check if each SCSS token is properly wrapped in var()
105
113
  // Pattern: var(--kui-token-name, $kui-token-name)
106
114
  const improperlyUsedTokens = []
@@ -109,17 +117,23 @@ const ruleFunction = () => {
109
117
  const cssToken = getCssToken(scssToken)
110
118
  const tokenOccurrences = findAllTokenOccurrences(declValue, scssToken)
111
119
 
120
+ console.log(`[DEBUG] Checking token "${scssToken}" (CSS: "${cssToken}") at ${tokenOccurrences.length} occurrence(s):`, tokenOccurrences)
121
+
112
122
  // Check each occurrence to see if it's properly wrapped
113
123
  const hasImproperUsage = tokenOccurrences.some((tokenIndex) => {
114
124
  return !isTokenProperlyWrapped(declValue, tokenIndex, scssToken, cssToken)
115
125
  })
116
126
 
117
127
  if (hasImproperUsage) {
128
+ console.log(`[DEBUG] Token "${scssToken}" has improper usage`)
118
129
  improperlyUsedTokens.push(scssToken)
130
+ } else {
131
+ console.log(`[DEBUG] Token "${scssToken}" is properly used`)
119
132
  }
120
133
  })
121
134
 
122
135
  if (improperlyUsedTokens.length > 0) {
136
+ console.log(`[DEBUG] Reporting ${improperlyUsedTokens.length} improperly used token(s):`, improperlyUsedTokens)
123
137
  // Create fix function
124
138
  const fix = () => {
125
139
  let fixedValue = declValue
@@ -131,15 +145,50 @@ const ruleFunction = () => {
131
145
  const tokenOccurrences = findAllTokenOccurrences(fixedValue, scssToken)
132
146
  const properFormat = `var(${cssToken}, ${scssToken})`
133
147
 
134
- tokenOccurrences.forEach((index) => {
148
+ tokenOccurrences.forEach((tokenIndex) => {
135
149
  // Check if this occurrence is in proper format
136
- if (!isTokenProperlyWrapped(fixedValue, index, scssToken, cssToken)) {
137
- // This occurrence needs to be replaced
138
- replacements.push({
139
- start: index,
140
- end: index + scssToken.length,
141
- replacement: properFormat,
142
- })
150
+ if (!isTokenProperlyWrapped(fixedValue, tokenIndex, scssToken, cssToken)) {
151
+ // Find the var() expression containing this token to replace the whole thing
152
+ const beforeToken = fixedValue.substring(0, tokenIndex)
153
+ const varStartIndex = beforeToken.lastIndexOf('var(')
154
+
155
+ if (varStartIndex === -1) {
156
+ // No var( found, just replace the token with proper format
157
+ replacements.push({
158
+ start: tokenIndex,
159
+ end: tokenIndex + scssToken.length,
160
+ replacement: properFormat,
161
+ })
162
+ return
163
+ }
164
+
165
+ // Find the matching closing parenthesis
166
+ let parenCount = 0
167
+ let searchIndex = varStartIndex
168
+ let varEndIndex = -1
169
+
170
+ while (searchIndex < fixedValue.length) {
171
+ const char = fixedValue[searchIndex]
172
+ if (char === '(') {
173
+ parenCount++
174
+ } else if (char === ')') {
175
+ parenCount--
176
+ if (parenCount === 0) {
177
+ varEndIndex = searchIndex
178
+ break
179
+ }
180
+ }
181
+ searchIndex++
182
+ }
183
+
184
+ if (varEndIndex !== -1) {
185
+ // Replace the entire var() expression
186
+ replacements.push({
187
+ start: varStartIndex,
188
+ end: varEndIndex + 1,
189
+ replacement: properFormat,
190
+ })
191
+ }
143
192
  }
144
193
  })
145
194
  })
@@ -147,8 +196,18 @@ const ruleFunction = () => {
147
196
  // Sort replacements by position (descending) to avoid offset issues
148
197
  replacements.sort((a, b) => b.start - a.start)
149
198
 
199
+ // Remove duplicates (same start position)
200
+ const uniqueReplacements = []
201
+ const seenStarts = new Set()
202
+ replacements.forEach((replacement) => {
203
+ if (!seenStarts.has(replacement.start)) {
204
+ seenStarts.add(replacement.start)
205
+ uniqueReplacements.push(replacement)
206
+ }
207
+ })
208
+
150
209
  // Apply replacements from end to start
151
- replacements.forEach(({ start, end, replacement }) => {
210
+ uniqueReplacements.forEach(({ start, end, replacement }) => {
152
211
  fixedValue = fixedValue.substring(0, start) + replacement + fixedValue.substring(end)
153
212
  })
154
213
 
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Do not edit directly, this file was auto-generated.
3
- * Generated on Mon, 05 Jan 2026 18:35:18 GMT
3
+ * Generated on Mon, 05 Jan 2026 20:37:31 GMT
4
4
  *
5
5
  * Kong Design Tokens
6
6
  * GitHub: https://github.com/Kong/design-tokens
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Do not edit directly, this file was auto-generated.
3
- * Generated on Mon, 05 Jan 2026 18:35:17 GMT
3
+ * Generated on Mon, 05 Jan 2026 20:37:31 GMT
4
4
  *
5
5
  * Kong Design Tokens
6
6
  * GitHub: https://github.com/Kong/design-tokens
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Do not edit directly, this file was auto-generated.
3
- * Generated on Mon, 05 Jan 2026 18:35:17 GMT
3
+ * Generated on Mon, 05 Jan 2026 20:37:31 GMT
4
4
  *
5
5
  * Kong Design Tokens
6
6
  * GitHub: https://github.com/Kong/design-tokens
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Do not edit directly, this file was auto-generated.
3
- * Generated on Mon, 05 Jan 2026 18:35:17 GMT
3
+ * Generated on Mon, 05 Jan 2026 20:37:31 GMT
4
4
  *
5
5
  * Kong Design Tokens
6
6
  * GitHub: https://github.com/Kong/design-tokens
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Do not edit directly, this file was auto-generated.
3
- * Generated on Mon, 05 Jan 2026 18:35:17 GMT
3
+ * Generated on Mon, 05 Jan 2026 20:37:31 GMT
4
4
  *
5
5
  * Kong Design Tokens
6
6
  * GitHub: https://github.com/Kong/design-tokens
@@ -1,6 +1,6 @@
1
1
 
2
2
  // Do not edit directly, this file was auto-generated.
3
- // Generated on Mon, 05 Jan 2026 18:35:18 GMT
3
+ // Generated on Mon, 05 Jan 2026 20:37:31 GMT
4
4
  //
5
5
  // Kong Design Tokens
6
6
  // GitHub: https://github.com/Kong/design-tokens
@@ -1,7 +1,7 @@
1
1
 
2
2
  /**
3
3
  * Do not edit directly, this file was auto-generated.
4
- * Generated on Mon, 05 Jan 2026 18:35:18 GMT
4
+ * Generated on Mon, 05 Jan 2026 20:37:31 GMT
5
5
  *
6
6
  * Kong Design Tokens
7
7
  * GitHub: https://github.com/Kong/design-tokens
@@ -1,6 +1,6 @@
1
1
 
2
2
  // Do not edit directly, this file was auto-generated.
3
- // Generated on Mon, 05 Jan 2026 18:35:18 GMT
3
+ // Generated on Mon, 05 Jan 2026 20:37:31 GMT
4
4
  //
5
5
  // Kong Design Tokens
6
6
  // GitHub: https://github.com/Kong/design-tokens
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kong/design-tokens",
3
- "version": "1.18.3-pr.613.5525a1e.0",
3
+ "version": "1.18.3-pr.613.a51766c.0",
4
4
  "description": "Kong UI Design Tokens and style dictionary",
5
5
  "type": "module",
6
6
  "scripts": {