Skip to content

Commit

Permalink
Add alpha token to autocomplete suggestion of bezier-vscode (#2496)
Browse files Browse the repository at this point in the history
<!--
  How to write a good PR title:
- Follow [the Conventional Commits
specification](https://www.conventionalcommits.org/en/v1.0.0/).
  - Give as much context as necessary and as little as possible
  - Prefix it with [WIP] while it’s a work in progress
-->

## Self Checklist

- [x] I wrote a PR title in **English** and added an appropriate
**label** to the PR.
- [x] I wrote the commit message in **English** and to follow [**the
Conventional Commits
specification**](https://www.conventionalcommits.org/en/v1.0.0/).
- [x] I [added the
**changeset**](https://github.com/changesets/changesets/blob/main/docs/adding-a-changeset.md)
about the changes that needed to be released. (or didn't have to)
- [x] I wrote or updated **documentation** related to the changes. (or
didn't have to)
- [x] I wrote or updated **tests** related to the changes. (or didn't
have to)
- [x] I tested the changes in various browsers. (or didn't have to)
  - Windows: Chrome, Edge, (Optional) Firefox
  - macOS: Chrome, Edge, Safari, (Optional) Firefox

## Related Issue

<!-- Please link to issue if one exists -->

<!-- Fixes #0000 -->

- #2485

## Summary

<!-- Please brief explanation of the changes made -->

- alpha 토큰도 자동완성 추천에 나오도록 합니다. 

## Details

<!-- Please elaborate description of the changes -->

- legacy token, alpha token 별로 `{ category: { [name]: value }` 객체를
assignToTokenMap 함수를 통해 만든 다음에 딥 머지를 했습니다. 이 때 alpha token의 "dimension"
category 는 바뀔 예정이라 제외했습니다.


https://github.com/user-attachments/assets/6c14d51c-9e44-4de7-92c9-419cf933959e





### Breaking change? (Yes/No)

<!-- If Yes, please describe the impact and migration path for users -->

- No

## References

<!-- Please list any other resources or points the reviewer should be
aware of -->

- None
  • Loading branch information
yangwooseong authored Nov 12, 2024
1 parent d3d0acf commit 0c92418
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 44 deletions.
5 changes: 5 additions & 0 deletions .changeset/selfish-ladybugs-reply.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'bezier-vscode': minor
---

Include `alpha` token for autocomplete suggestion.
119 changes: 75 additions & 44 deletions packages/bezier-vscode/src/server.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { tokens as _tokens } from '@channel.io/bezier-tokens'
import { tokens } from '@channel.io/bezier-tokens'
import { tokens as alphaTokens } from '@channel.io/bezier-tokens/alpha'
import {
type CompletionItem,
CompletionItemKind,
Expand All @@ -11,21 +12,56 @@ import {
} from 'vscode-languageserver/node'
import { TextDocument } from 'vscode-languageserver-textdocument'

import { hexToRGBA } from './utils'

const tokens = {
..._tokens.lightTheme,
..._tokens.global,
color: {
..._tokens.lightTheme.color,
..._tokens.global.color,
},
import { deepMerge, hexToRGBA } from './utils'

type TokenValue = string | number
type AlphaTokenValue = Record<string, string | number>
type TokenMap = Record<string, Record<string, TokenValue | AlphaTokenValue>>

const assignToTokenMap = (
target: TokenMap,
source: TokenMap,
transformValue: (v: TokenValue | AlphaTokenValue) => TokenValue = (v) =>
v as TokenValue
) => {
Object.entries(source).forEach(([category, tokenObject]) => {
if (target[category] === undefined) {
target[category] = {}
}
Object.entries(tokenObject).forEach(([name, value]) => {
target[category][name] = transformValue(value)
})
})
}

type TokenGroup = keyof typeof tokens
const alphaTokenMap = {} as TokenMap
const tokenMap = {} as TokenMap

assignToTokenMap(
alphaTokenMap,
alphaTokens.lightTheme,
(v) => (v as AlphaTokenValue).value
)
assignToTokenMap(
alphaTokenMap,
alphaTokens.global,
(v) => (v as AlphaTokenValue).value
)
assignToTokenMap(tokenMap, tokens.lightTheme)
assignToTokenMap(tokenMap, tokens.global)

const allTokenMap = deepMerge(alphaTokenMap, tokenMap) as Record<
| keyof typeof alphaTokens.global
| keyof typeof alphaTokens.lightTheme
| keyof typeof tokens.global
| keyof typeof tokens.lightTheme,
Record<string, string>
>

type TokenGroup = keyof typeof allTokenMap

const completionItemsByTokenGroup = Object.fromEntries(
Object.entries(tokens).map(([groupName, tokenKeyValues]) => {
Object.entries(allTokenMap).map(([groupName, tokenKeyValues]) => {
const completionItems: CompletionItem[] = Object.entries(
tokenKeyValues
).map(([key, value]) => ({
Expand All @@ -51,8 +87,11 @@ const tokenGroupPatterns = {
font: /font:|letter-spacing:|line-height:/,
transition: /transition:/,
opacity: /opacity:/,
shadow: /box-shadow:/,
gradient: /background:|background-image:/,
'z-index': /z-index:/,
} satisfies Record<TokenGroup, RegExp>
// FIXME: delete Exclude when dimension token is removed
} satisfies Record<Exclude<TokenGroup, 'dimension'>, RegExp>

const allCompletionItems = Object.values(completionItemsByTokenGroup).flat()

Expand All @@ -77,6 +116,27 @@ connection.onInitialize(() => {
return result
})

const hasMatchingPattern = (currentText: string): boolean => {
return Object.values(tokenGroupPatterns).some((pattern) =>
pattern.test(currentText)
)
}

const getMatchedCompletionItems = (currentText: string): CompletionItem[] => {
if (!hasMatchingPattern(currentText)) {
return []
}

return Object.entries(tokenGroupPatterns)
.filter(([_, pattern]) => pattern.test(currentText))
.flatMap(
([tokenGroupName]) =>
completionItemsByTokenGroup[
tokenGroupName as keyof typeof tokenGroupPatterns
] ?? []
)
}

// // This handler provides the initial list of the completion items.
connection.onCompletion(
(_textDocumentPosition: TextDocumentPositionParams): CompletionItem[] => {
Expand All @@ -85,8 +145,6 @@ connection.onCompletion(
// info and always provide the same completion items.
const doc = documents.get(_textDocumentPosition.textDocument.uri)

let matchedCompletionItems: CompletionItem[] = []

// if the doc can't be found, return nothing
if (!doc) {
return []
Expand All @@ -97,36 +155,9 @@ connection.onCompletion(
end: { line: _textDocumentPosition.position.line, character: 1000 },
})

if (
Object.values(tokenGroupPatterns).every(
(pattern) => !pattern.test(currentText)
)
) {
return []
}

for (const [tokenGroupName, pattern] of Object.entries(
tokenGroupPatterns
)) {
if (pattern.test(currentText)) {
const currentCompletionItems =
completionItemsByTokenGroup[
tokenGroupName as keyof typeof tokenGroupPatterns
]

matchedCompletionItems = matchedCompletionItems.concat(
currentCompletionItems
)
}
}

// if there were matches above, send them
if (matchedCompletionItems.length > 0) {
return matchedCompletionItems
}
const matchedItems = getMatchedCompletionItems(currentText)

// if there were no matches, send everything
return allCompletionItems
return matchedItems.length > 0 ? matchedItems : allCompletionItems
}
)

Expand Down
23 changes: 23 additions & 0 deletions packages/bezier-vscode/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,26 @@ export const hexToRGBA = (hex: string) => {
}
return `rgba(${r}, ${g}, ${b}, 1)`
}

export const deepMerge = (target: any, source: any) => {
if (!source || !isObject(source)) return target

Object.keys(source).forEach((key) => {
const targetValue = target[key]
const sourceValue = source[key]

if (isObject(targetValue) && isObject(sourceValue)) {
target[key] = deepMerge(Object.assign({}, targetValue), sourceValue)
} else if (Array.isArray(targetValue) && Array.isArray(sourceValue)) {
target[key] = Array.from(new Set([...targetValue, ...sourceValue]))
} else {
target[key] = sourceValue
}
})

return target
}

const isObject = (obj: Object) => {
return obj && typeof obj === 'object' && !Array.isArray(obj)
}

0 comments on commit 0c92418

Please sign in to comment.