@kong/design-tokens 1.18.3-pr.613.b9dd522.0 → 1.18.3-pr.613.e565bb3.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',
@@ -17,11 +17,6 @@ const getCssToken = (scssToken) => {
17
17
  return `--${tokenName}`
18
18
  }
19
19
 
20
- // Create regex pattern to match var(--token, $token) format
21
- const createProperUsagePattern = (cssToken, scssToken) => {
22
- return new RegExp(`var\\(\\s*${cssToken}\\s*,\\s*${scssToken}\\s*\\)`)
23
- }
24
-
25
20
  // Find all occurrences of a token in a value
26
21
  const findAllTokenOccurrences = (value, token) => {
27
22
  const occurrences = []
@@ -38,16 +33,61 @@ const findAllTokenOccurrences = (value, token) => {
38
33
  }
39
34
 
40
35
  // Check if token at given position is properly wrapped in var()
41
- const isTokenProperlyWrapped = (value, tokenIndex, token, pattern) => {
42
- const windowStart = Math.max(0, tokenIndex - 100)
43
- const windowEnd = Math.min(value.length, tokenIndex + token.length + 100)
44
- const context = value.substring(windowStart, windowEnd)
45
- return pattern.test(context)
36
+ // Enforces exact format: var(--token, $token) with exactly one space before comma
37
+ const isTokenProperlyWrapped = (value, tokenIndex, token, cssToken) => {
38
+ // Use regex to find all var(--token, $token) patterns
39
+ // Escape $ in token since it's a special regex character
40
+ const escapedToken = token.replace(/\$/g, '\\$')
41
+ const pattern = new RegExp(`var\\(${cssToken}, ${escapedToken}\\)`, 'g')
42
+
43
+ console.log(`[DEBUG] Checking token "${token}" at position ${tokenIndex}:`, {
44
+ token,
45
+ tokenIndex,
46
+ cssToken,
47
+ escapedToken,
48
+ pattern: `var(${cssToken}, ${escapedToken})`,
49
+ patternSource: pattern.source,
50
+ valueContext: value.substring(Math.max(0, tokenIndex - 50), Math.min(value.length, tokenIndex + token.length + 50)),
51
+ })
52
+
53
+ // Find all matches
54
+ let match
55
+ const matches = []
56
+ while ((match = pattern.exec(value)) !== null) {
57
+ const matchStart = match.index
58
+ const matchEnd = matchStart + match[0].length
59
+ matches.push({
60
+ start: matchStart,
61
+ end: matchEnd,
62
+ match: match[0],
63
+ })
64
+
65
+ // Check if our token at tokenIndex is inside this match
66
+ const tokenEndIndex = tokenIndex + token.length
67
+ if (tokenIndex >= matchStart && tokenEndIndex <= matchEnd) {
68
+ console.log(`[DEBUG] Token "${token}" at ${tokenIndex} is properly wrapped in:`, {
69
+ match: match[0],
70
+ matchStart,
71
+ matchEnd,
72
+ tokenIndex,
73
+ tokenEndIndex,
74
+ })
75
+ return true
76
+ }
77
+ }
78
+
79
+ console.log(`[DEBUG] Token "${token}" at ${tokenIndex} is NOT properly wrapped. Found ${matches.length} pattern matches:`, {
80
+ matches,
81
+ tokenIndex,
82
+ tokenEndIndex: tokenIndex + token.length,
83
+ })
84
+
85
+ return false
46
86
  }
47
87
 
48
88
  const ruleFunction = () => {
49
89
  return (postcssRoot, postcssResult) => {
50
- const validOptions = validateOptions(postcssRoot, ruleName, {})
90
+ const validOptions = validateOptions(postcssResult, ruleName, {})
51
91
 
52
92
  if (!validOptions) {
53
93
  return
@@ -56,6 +96,8 @@ const ruleFunction = () => {
56
96
  postcssRoot.walkDecls((decl) => {
57
97
  const declValue = decl.value
58
98
 
99
+ console.log(`[DEBUG] Checking declaration: ${decl.prop} = "${declValue}"`)
100
+
59
101
  // Extract all SCSS tokens (starting with $kui-)
60
102
  const scssTokenRegex = new RegExp(`\\$${KONG_TOKEN_PREFIX}[a-z0-9-]+`, 'g')
61
103
  const scssTokens = declValue.match(scssTokenRegex)
@@ -68,26 +110,33 @@ const ruleFunction = () => {
68
110
  // Get unique SCSS tokens
69
111
  const uniqueScssTokens = Array.from(new Set(scssTokens))
70
112
 
113
+ console.log(`[DEBUG] Found ${uniqueScssTokens.length} unique SCSS tokens:`, uniqueScssTokens)
114
+
71
115
  // Check if each SCSS token is properly wrapped in var()
72
116
  // Pattern: var(--kui-token-name, $kui-token-name)
73
117
  const improperlyUsedTokens = []
74
118
 
75
119
  uniqueScssTokens.forEach((scssToken) => {
76
120
  const cssToken = getCssToken(scssToken)
77
- const properUsagePattern = createProperUsagePattern(cssToken, scssToken)
78
121
  const tokenOccurrences = findAllTokenOccurrences(declValue, scssToken)
79
122
 
123
+ console.log(`[DEBUG] Checking token "${scssToken}" (CSS: "${cssToken}") at ${tokenOccurrences.length} occurrence(s):`, tokenOccurrences)
124
+
80
125
  // Check each occurrence to see if it's properly wrapped
81
126
  const hasImproperUsage = tokenOccurrences.some((tokenIndex) => {
82
- return !isTokenProperlyWrapped(declValue, tokenIndex, scssToken, properUsagePattern)
127
+ return !isTokenProperlyWrapped(declValue, tokenIndex, scssToken, cssToken)
83
128
  })
84
129
 
85
130
  if (hasImproperUsage) {
131
+ console.log(`[DEBUG] Token "${scssToken}" has improper usage`)
86
132
  improperlyUsedTokens.push(scssToken)
133
+ } else {
134
+ console.log(`[DEBUG] Token "${scssToken}" is properly used`)
87
135
  }
88
136
  })
89
137
 
90
138
  if (improperlyUsedTokens.length > 0) {
139
+ console.log(`[DEBUG] Reporting ${improperlyUsedTokens.length} improperly used token(s):`, improperlyUsedTokens)
91
140
  // Create fix function
92
141
  const fix = () => {
93
142
  let fixedValue = declValue
@@ -96,19 +145,53 @@ const ruleFunction = () => {
96
145
  // First, identify all positions that need to be replaced
97
146
  improperlyUsedTokens.forEach((scssToken) => {
98
147
  const cssToken = getCssToken(scssToken)
99
- const properUsagePattern = createProperUsagePattern(cssToken, scssToken)
100
148
  const tokenOccurrences = findAllTokenOccurrences(fixedValue, scssToken)
101
149
  const properFormat = `var(${cssToken}, ${scssToken})`
102
150
 
103
- tokenOccurrences.forEach((index) => {
151
+ tokenOccurrences.forEach((tokenIndex) => {
104
152
  // Check if this occurrence is in proper format
105
- if (!isTokenProperlyWrapped(fixedValue, index, scssToken, properUsagePattern)) {
106
- // This occurrence needs to be replaced
107
- replacements.push({
108
- start: index,
109
- end: index + scssToken.length,
110
- replacement: properFormat,
111
- })
153
+ if (!isTokenProperlyWrapped(fixedValue, tokenIndex, scssToken, cssToken)) {
154
+ // Find the var() expression containing this token to replace the whole thing
155
+ const beforeToken = fixedValue.substring(0, tokenIndex)
156
+ const varStartIndex = beforeToken.lastIndexOf('var(')
157
+
158
+ if (varStartIndex === -1) {
159
+ // No var( found, just replace the token with proper format
160
+ replacements.push({
161
+ start: tokenIndex,
162
+ end: tokenIndex + scssToken.length,
163
+ replacement: properFormat,
164
+ })
165
+ return
166
+ }
167
+
168
+ // Find the matching closing parenthesis
169
+ let parenCount = 0
170
+ let searchIndex = varStartIndex
171
+ let varEndIndex = -1
172
+
173
+ while (searchIndex < fixedValue.length) {
174
+ const char = fixedValue[searchIndex]
175
+ if (char === '(') {
176
+ parenCount++
177
+ } else if (char === ')') {
178
+ parenCount--
179
+ if (parenCount === 0) {
180
+ varEndIndex = searchIndex
181
+ break
182
+ }
183
+ }
184
+ searchIndex++
185
+ }
186
+
187
+ if (varEndIndex !== -1) {
188
+ // Replace the entire var() expression
189
+ replacements.push({
190
+ start: varStartIndex,
191
+ end: varEndIndex + 1,
192
+ replacement: properFormat,
193
+ })
194
+ }
112
195
  }
113
196
  })
114
197
  })
@@ -116,8 +199,18 @@ const ruleFunction = () => {
116
199
  // Sort replacements by position (descending) to avoid offset issues
117
200
  replacements.sort((a, b) => b.start - a.start)
118
201
 
202
+ // Remove duplicates (same start position)
203
+ const uniqueReplacements = []
204
+ const seenStarts = new Set()
205
+ replacements.forEach((replacement) => {
206
+ if (!seenStarts.has(replacement.start)) {
207
+ seenStarts.add(replacement.start)
208
+ uniqueReplacements.push(replacement)
209
+ }
210
+ })
211
+
119
212
  // Apply replacements from end to start
120
- replacements.forEach(({ start, end, replacement }) => {
213
+ uniqueReplacements.forEach(({ start, end, replacement }) => {
121
214
  fixedValue = fixedValue.substring(0, start) + replacement + fixedValue.substring(end)
122
215
  })
123
216
 
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Do not edit directly, this file was auto-generated.
3
- * Generated on Mon, 05 Jan 2026 16:56:03 GMT
3
+ * Generated on Mon, 05 Jan 2026 20:56:39 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 16:56:03 GMT
3
+ * Generated on Mon, 05 Jan 2026 20:56:39 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 16:56:03 GMT
3
+ * Generated on Mon, 05 Jan 2026 20:56:39 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 16:56:03 GMT
3
+ * Generated on Mon, 05 Jan 2026 20:56:39 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 16:56:03 GMT
3
+ * Generated on Mon, 05 Jan 2026 20:56:39 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 16:56:03 GMT
3
+ // Generated on Mon, 05 Jan 2026 20:56:39 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 16:56:03 GMT
4
+ * Generated on Mon, 05 Jan 2026 20:56:39 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 16:56:03 GMT
3
+ // Generated on Mon, 05 Jan 2026 20:56:39 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.b9dd522.0",
3
+ "version": "1.18.3-pr.613.e565bb3.0",
4
4
  "description": "Kong UI Design Tokens and style dictionary",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -53,8 +53,8 @@
53
53
  "url": "https://github.com/Kong/design-tokens/issues"
54
54
  },
55
55
  "devDependencies": {
56
- "@commitlint/cli": "^20.2.0",
57
- "@commitlint/config-conventional": "^20.2.0",
56
+ "@commitlint/cli": "^20.3.0",
57
+ "@commitlint/config-conventional": "^20.3.0",
58
58
  "@digitalroute/cz-conventional-changelog-for-jira": "^8.0.1",
59
59
  "@evilmartians/lefthook": "^2.0.13",
60
60
  "@kong/eslint-config-kong-ui": "^1.6.0",
@@ -126,7 +126,7 @@
126
126
  "jiraAppend": "]"
127
127
  }
128
128
  },
129
- "packageManager": "pnpm@10.26.2",
129
+ "packageManager": "pnpm@10.27.0",
130
130
  "engines": {
131
131
  "node": ">=20.19.5",
132
132
  "pnpm": ">=9.14.4 || >=10.1.0"