@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.
- package/dist/stylelint-plugin/rules/use-css-token/index.mjs +117 -24
- 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 +4 -4
|
@@ -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
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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(
|
|
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,
|
|
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((
|
|
151
|
+
tokenOccurrences.forEach((tokenIndex) => {
|
|
104
152
|
// Check if this occurrence is in proper format
|
|
105
|
-
if (!isTokenProperlyWrapped(fixedValue,
|
|
106
|
-
//
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
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
|
-
|
|
213
|
+
uniqueReplacements.forEach(({ start, end, replacement }) => {
|
|
121
214
|
fixedValue = fixedValue.substring(0, start) + replacement + fixedValue.substring(end)
|
|
122
215
|
})
|
|
123
216
|
|
package/dist/tokens/js/index.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kong/design-tokens",
|
|
3
|
-
"version": "1.18.3-pr.613.
|
|
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.
|
|
57
|
-
"@commitlint/config-conventional": "^20.
|
|
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.
|
|
129
|
+
"packageManager": "pnpm@10.27.0",
|
|
130
130
|
"engines": {
|
|
131
131
|
"node": ">=20.19.5",
|
|
132
132
|
"pnpm": ">=9.14.4 || >=10.1.0"
|