@kong/design-tokens 1.18.2 → 1.18.3-pr.613.0923f40.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.
@@ -1,3 +1,4 @@
1
1
  import useProperToken from './rules/use-proper-token/index.mjs'
2
+ import useCssToken from './rules/use-css-token/index.mjs'
2
3
 
3
- export default [useProperToken]
4
+ export default [useProperToken, useCssToken]
@@ -0,0 +1,198 @@
1
+ import stylelint from 'stylelint'
2
+ import { KONG_TOKEN_PREFIX, RULE_NAME_PREFIX } from '../../utilities/index.mjs'
3
+
4
+ const { ruleMessages, validateOptions, report } = stylelint.utils
5
+ const ruleName = `${RULE_NAME_PREFIX}/use-css-token`
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) with exactly one space before the comma and no other spaces.',
8
+ })
9
+ const meta = {
10
+ url: 'https://github.com/Kong/design-tokens/blob/main/stylelint-plugin/README.md',
11
+ fixable: true,
12
+ }
13
+
14
+ // Convert SCSS token ($kui-token) to CSS token (--kui-token)
15
+ const getCssToken = (scssToken) => {
16
+ const tokenName = scssToken.substring(1) // Remove $
17
+ return `--${tokenName}`
18
+ }
19
+
20
+ // Find all occurrences of a token in a value
21
+ const findAllTokenOccurrences = (value, token) => {
22
+ const occurrences = []
23
+ let searchIndex = 0
24
+ while (true) {
25
+ const index = value.indexOf(token, searchIndex)
26
+ if (index === -1) {
27
+ break
28
+ }
29
+ occurrences.push(index)
30
+ searchIndex = index + 1
31
+ }
32
+ return occurrences
33
+ }
34
+
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
37
+ const isTokenProperlyWrapped = (value, tokenIndex, token, cssToken) => {
38
+ // Calculate exact positions based on enforced format: var(--token, $token)
39
+ // var(-- = 5 chars, token name = cssToken.length - 2, , = 2 chars (comma + space)
40
+ const charactersBack = cssToken.length + 5 // 5 + (cssToken.length - 2) + 2
41
+ const charactersForward = token.length + 1 // token + )
42
+
43
+ const startIndex = tokenIndex - charactersBack
44
+ const endIndex = tokenIndex + charactersForward
45
+
46
+ // Check bounds
47
+ if (startIndex < 0 || endIndex > value.length) {
48
+ return false
49
+ }
50
+
51
+ // Extract the substring that should match the exact pattern
52
+ const substring = value.substring(startIndex, endIndex)
53
+
54
+ // Check if it matches the exact pattern: var(--token, $token)
55
+ const expectedPattern = new RegExp(`^var\\(${cssToken}, ${token}\\)$`)
56
+ return expectedPattern.test(substring)
57
+ }
58
+
59
+ const ruleFunction = () => {
60
+ return (postcssRoot, postcssResult) => {
61
+ const validOptions = validateOptions(postcssResult, ruleName, {})
62
+
63
+ if (!validOptions) {
64
+ return
65
+ }
66
+
67
+ postcssRoot.walkDecls((decl) => {
68
+ const declValue = decl.value
69
+
70
+ // Extract all SCSS tokens (starting with $kui-)
71
+ const scssTokenRegex = new RegExp(`\\$${KONG_TOKEN_PREFIX}[a-z0-9-]+`, 'g')
72
+ const scssTokens = declValue.match(scssTokenRegex)
73
+
74
+ // If no SCSS tokens are used, skip validation
75
+ if (!scssTokens || scssTokens.length === 0) {
76
+ return
77
+ }
78
+
79
+ // Get unique SCSS tokens
80
+ const uniqueScssTokens = Array.from(new Set(scssTokens))
81
+
82
+ // Check if each SCSS token is properly wrapped in var()
83
+ // Pattern: var(--kui-token-name, $kui-token-name)
84
+ const improperlyUsedTokens = []
85
+
86
+ uniqueScssTokens.forEach((scssToken) => {
87
+ const cssToken = getCssToken(scssToken)
88
+ const tokenOccurrences = findAllTokenOccurrences(declValue, scssToken)
89
+
90
+ // Check each occurrence to see if it's properly wrapped
91
+ const hasImproperUsage = tokenOccurrences.some((tokenIndex) => {
92
+ return !isTokenProperlyWrapped(declValue, tokenIndex, scssToken, cssToken)
93
+ })
94
+
95
+ if (hasImproperUsage) {
96
+ improperlyUsedTokens.push(scssToken)
97
+ }
98
+ })
99
+
100
+ if (improperlyUsedTokens.length > 0) {
101
+ // Create fix function
102
+ const fix = () => {
103
+ let fixedValue = declValue
104
+ const replacements = []
105
+
106
+ // First, identify all positions that need to be replaced
107
+ improperlyUsedTokens.forEach((scssToken) => {
108
+ const cssToken = getCssToken(scssToken)
109
+ const tokenOccurrences = findAllTokenOccurrences(fixedValue, scssToken)
110
+ const properFormat = `var(${cssToken}, ${scssToken})`
111
+
112
+ tokenOccurrences.forEach((tokenIndex) => {
113
+ // Check if this occurrence is in proper format
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
+ }
156
+ }
157
+ })
158
+ })
159
+
160
+ // Sort replacements by position (descending) to avoid offset issues
161
+ replacements.sort((a, b) => b.start - a.start)
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
+
173
+ // Apply replacements from end to start
174
+ uniqueReplacements.forEach(({ start, end, replacement }) => {
175
+ fixedValue = fixedValue.substring(0, start) + replacement + fixedValue.substring(end)
176
+ })
177
+
178
+ decl.value = fixedValue
179
+ }
180
+
181
+ report({
182
+ message: messages.expected,
183
+ node: decl,
184
+ result: postcssResult,
185
+ ruleName,
186
+ fix,
187
+ })
188
+ }
189
+ })
190
+ }
191
+ }
192
+
193
+ ruleFunction.ruleName = ruleName
194
+ ruleFunction.messages = messages
195
+ ruleFunction.meta = meta
196
+
197
+ export default stylelint.createPlugin(ruleName, ruleFunction)
198
+
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Do not edit directly, this file was auto-generated.
3
- * Generated on Tue, 25 Nov 2025 21:23:14 GMT
3
+ * Generated on Mon, 05 Jan 2026 19:51:01 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 Tue, 25 Nov 2025 21:23:14 GMT
3
+ * Generated on Mon, 05 Jan 2026 19:51:01 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 Tue, 25 Nov 2025 21:23:14 GMT
3
+ * Generated on Mon, 05 Jan 2026 19:51:01 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 Tue, 25 Nov 2025 21:23:14 GMT
3
+ * Generated on Mon, 05 Jan 2026 19:51:01 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 Tue, 25 Nov 2025 21:23:14 GMT
3
+ * Generated on Mon, 05 Jan 2026 19:51:01 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 Tue, 25 Nov 2025 21:23:14 GMT
3
+ // Generated on Mon, 05 Jan 2026 19:51:01 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 Tue, 25 Nov 2025 21:23:14 GMT
4
+ * Generated on Mon, 05 Jan 2026 19:51:01 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 Tue, 25 Nov 2025 21:23:14 GMT
3
+ // Generated on Mon, 05 Jan 2026 19:51:01 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.2",
3
+ "version": "1.18.3-pr.613.0923f40.0",
4
4
  "description": "Kong UI Design Tokens and style dictionary",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -53,30 +53,30 @@
53
53
  "url": "https://github.com/Kong/design-tokens/issues"
54
54
  },
55
55
  "devDependencies": {
56
- "@commitlint/cli": "^20.1.0",
57
- "@commitlint/config-conventional": "^20.0.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
- "@evilmartians/lefthook": "^2.0.2",
60
- "@kong/eslint-config-kong-ui": "^1.5.6",
59
+ "@evilmartians/lefthook": "^2.0.13",
60
+ "@kong/eslint-config-kong-ui": "^1.6.0",
61
61
  "@semantic-release/changelog": "^6.0.3",
62
62
  "@semantic-release/git": "^10.0.1",
63
- "@vitejs/plugin-vue": "^6.0.1",
63
+ "@vitejs/plugin-vue": "^6.0.3",
64
64
  "chokidar-cli": "^3.0.0",
65
65
  "commitizen": "^4.3.1",
66
66
  "cz-conventional-changelog": "^3.3.0",
67
- "eslint": "^9.39.1",
67
+ "eslint": "^9.39.2",
68
68
  "npm-run-all2": "^8.0.4",
69
- "rimraf": "^6.1.0",
70
- "sass": "^1.93.3",
71
- "semantic-release": "^25.0.1",
69
+ "rimraf": "^6.1.2",
70
+ "sass": "^1.97.1",
71
+ "semantic-release": "^25.0.2",
72
72
  "shx": "^0.4.0",
73
73
  "style-dictionary": "^4.4.0",
74
74
  "typescript": "^5.9.3",
75
- "vite": "^7.1.12",
75
+ "vite": "^7.3.0",
76
76
  "vite-plugin-restart": "^2.0.0",
77
- "vite-plugin-vue-devtools": "^8.0.3",
78
- "vue": "^3.5.22",
79
- "vue-router": "^4.6.3"
77
+ "vite-plugin-vue-devtools": "^8.0.5",
78
+ "vue": "^3.5.26",
79
+ "vue-router": "^4.6.4"
80
80
  },
81
81
  "release": {
82
82
  "branches": [
@@ -126,13 +126,13 @@
126
126
  "jiraAppend": "]"
127
127
  }
128
128
  },
129
- "packageManager": "pnpm@10.20.0",
129
+ "packageManager": "pnpm@10.27.0",
130
130
  "engines": {
131
131
  "node": ">=20.19.5",
132
132
  "pnpm": ">=9.14.4 || >=10.1.0"
133
133
  },
134
134
  "volta": {
135
- "node": "24.11.0"
135
+ "node": "24.12.0"
136
136
  },
137
137
  "pnpm": {
138
138
  "onlyBuiltDependencies": [