@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.
- package/dist/stylelint-plugin/rules/use-css-token/index.mjs +106 -47
- package/dist/tokens/css/custom-properties.css +1 -1
- package/dist/tokens/js/cjs/index.d.ts +1 -1
- package/dist/tokens/js/cjs/index.js +1 -1
- package/dist/tokens/js/index.d.ts +1 -1
- package/dist/tokens/js/index.mjs +1 -1
- package/dist/tokens/less/variables.less +1 -1
- package/dist/tokens/scss/_map.scss +1 -1
- package/dist/tokens/scss/_variables.scss +1 -1
- package/package.json +1 -1
|
@@ -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
|
-
//
|
|
38
|
-
//
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
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
|
-
|
|
66
|
-
|
|
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
|
-
|
|
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((
|
|
148
|
+
tokenOccurrences.forEach((tokenIndex) => {
|
|
135
149
|
// Check if this occurrence is in proper format
|
|
136
|
-
if (!isTokenProperlyWrapped(fixedValue,
|
|
137
|
-
//
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
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
|
-
|
|
210
|
+
uniqueReplacements.forEach(({ start, end, replacement }) => {
|
|
152
211
|
fixedValue = fixedValue.substring(0, start) + replacement + fixedValue.substring(end)
|
|
153
212
|
})
|
|
154
213
|
|
package/dist/tokens/js/index.mjs
CHANGED