@kong/design-tokens 1.18.3-pr.613.5525a1e.0 → 1.18.3-pr.613.969ab5a.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 +72 -49
- 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,27 @@ 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
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
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
|
-
}
|
|
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
|
+
// Find all matches
|
|
44
|
+
let match
|
|
45
|
+
while ((match = pattern.exec(value)) !== null) {
|
|
46
|
+
const matchStart = match.index
|
|
47
|
+
const matchEnd = matchStart + match[0].length
|
|
48
|
+
|
|
49
|
+
// Check if our token at tokenIndex is inside this match
|
|
50
|
+
const tokenEndIndex = tokenIndex + token.length
|
|
51
|
+
if (tokenIndex >= matchStart && tokenEndIndex <= matchEnd) {
|
|
52
|
+
return true
|
|
61
53
|
}
|
|
62
|
-
searchIndex++
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
if (varEndIndex === -1) {
|
|
66
|
-
return false
|
|
67
|
-
}
|
|
68
|
-
|
|
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
54
|
}
|
|
74
55
|
|
|
75
|
-
|
|
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)
|
|
56
|
+
return false
|
|
79
57
|
}
|
|
80
58
|
|
|
81
59
|
const ruleFunction = () => {
|
|
@@ -131,15 +109,50 @@ const ruleFunction = () => {
|
|
|
131
109
|
const tokenOccurrences = findAllTokenOccurrences(fixedValue, scssToken)
|
|
132
110
|
const properFormat = `var(${cssToken}, ${scssToken})`
|
|
133
111
|
|
|
134
|
-
tokenOccurrences.forEach((
|
|
112
|
+
tokenOccurrences.forEach((tokenIndex) => {
|
|
135
113
|
// Check if this occurrence is in proper format
|
|
136
|
-
if (!isTokenProperlyWrapped(fixedValue,
|
|
137
|
-
//
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
114
|
+
if (!isTokenProperlyWrapped(fixedValue, tokenIndex, scssToken, cssToken)) {
|
|
115
|
+
// Find the var() expression containing this token to replace the whole thing
|
|
116
|
+
const beforeToken = fixedValue.substring(0, tokenIndex)
|
|
117
|
+
const varStartIndex = beforeToken.lastIndexOf('var(')
|
|
118
|
+
|
|
119
|
+
if (varStartIndex === -1) {
|
|
120
|
+
// No var( found, just replace the token with proper format
|
|
121
|
+
replacements.push({
|
|
122
|
+
start: tokenIndex,
|
|
123
|
+
end: tokenIndex + scssToken.length,
|
|
124
|
+
replacement: properFormat,
|
|
125
|
+
})
|
|
126
|
+
return
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Find the matching closing parenthesis
|
|
130
|
+
let parenCount = 0
|
|
131
|
+
let searchIndex = varStartIndex
|
|
132
|
+
let varEndIndex = -1
|
|
133
|
+
|
|
134
|
+
while (searchIndex < fixedValue.length) {
|
|
135
|
+
const char = fixedValue[searchIndex]
|
|
136
|
+
if (char === '(') {
|
|
137
|
+
parenCount++
|
|
138
|
+
} else if (char === ')') {
|
|
139
|
+
parenCount--
|
|
140
|
+
if (parenCount === 0) {
|
|
141
|
+
varEndIndex = searchIndex
|
|
142
|
+
break
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
searchIndex++
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (varEndIndex !== -1) {
|
|
149
|
+
// Replace the entire var() expression
|
|
150
|
+
replacements.push({
|
|
151
|
+
start: varStartIndex,
|
|
152
|
+
end: varEndIndex + 1,
|
|
153
|
+
replacement: properFormat,
|
|
154
|
+
})
|
|
155
|
+
}
|
|
143
156
|
}
|
|
144
157
|
})
|
|
145
158
|
})
|
|
@@ -147,8 +160,18 @@ const ruleFunction = () => {
|
|
|
147
160
|
// Sort replacements by position (descending) to avoid offset issues
|
|
148
161
|
replacements.sort((a, b) => b.start - a.start)
|
|
149
162
|
|
|
163
|
+
// Remove duplicates (same start position)
|
|
164
|
+
const uniqueReplacements = []
|
|
165
|
+
const seenStarts = new Set()
|
|
166
|
+
replacements.forEach((replacement) => {
|
|
167
|
+
if (!seenStarts.has(replacement.start)) {
|
|
168
|
+
seenStarts.add(replacement.start)
|
|
169
|
+
uniqueReplacements.push(replacement)
|
|
170
|
+
}
|
|
171
|
+
})
|
|
172
|
+
|
|
150
173
|
// Apply replacements from end to start
|
|
151
|
-
|
|
174
|
+
uniqueReplacements.forEach(({ start, end, replacement }) => {
|
|
152
175
|
fixedValue = fixedValue.substring(0, start) + replacement + fixedValue.substring(end)
|
|
153
176
|
})
|
|
154
177
|
|
package/dist/tokens/js/index.mjs
CHANGED