@cobalt-ui/plugin-ts
Advanced tools
Comparing version 0.4.1 to 0.5.0
# @cobalt-ui/plugin-ts | ||
## 0.5.0 | ||
### Minor Changes | ||
- 9e80004: Breaking change: improve and normalize transform API | ||
- 9e80004: Fix bugs, improve plugin | ||
### Patch Changes | ||
- Updated dependencies [9e80004] | ||
- @cobalt-ui/utils@0.5.0 | ||
## 0.4.1 | ||
@@ -4,0 +16,0 @@ |
@@ -6,4 +6,4 @@ import type { ParsedToken, Plugin } from '@cobalt-ui/core'; | ||
/** modify values */ | ||
transformValue?: (token: ParsedToken) => string; | ||
transform?: (token: ParsedToken, mode?: string) => string; | ||
} | ||
export default function ts(options?: Options): Plugin; |
@@ -0,58 +1,76 @@ | ||
import { Indenter, objKey } from '@cobalt-ui/utils'; | ||
/** escape values with strings if necessary */ | ||
function esc(value) { | ||
return String(Number(value)) === value ? value : `'${value}'`; | ||
} | ||
export default function ts(options) { | ||
let filename = options?.filename || './index.ts'; | ||
let transformer = options?.transformValue; | ||
function printTokensExport(schemaTokens) { | ||
let code = 'export const tokens = '; | ||
// objectify | ||
let code = ['export const tokens = {']; | ||
const i = new Indenter(); | ||
// reconstruct object | ||
const tokens = {}; | ||
for (const token of schemaTokens) { | ||
const groups = token.id.split('.'); | ||
const localID = groups.pop(); | ||
let lastToken = tokens; | ||
for (const group of groups) { | ||
if (!tokens[group]) | ||
tokens[group] = {}; | ||
lastToken = tokens[group]; | ||
const keys = token.id.split('.'); | ||
let node = tokens; | ||
for (let n = 0; n < keys.length; n++) { | ||
if (n === keys.length - 1) { | ||
node[keys[n]] = (typeof options?.transform === 'function' && options?.transform(token)) || token.$value; | ||
} | ||
else { | ||
if (!node[keys[n]]) | ||
node[keys[n]] = {}; | ||
} | ||
node = node[keys[n]]; | ||
} | ||
lastToken[localID] = transformer ? transformer(token) : token.$value; | ||
} | ||
code += JSON.stringify(tokens, undefined, 2); | ||
code += ';\n'; | ||
return code; | ||
// print string from object | ||
function printObject(obj, lv = 1) { | ||
if (!obj || typeof obj !== 'object') | ||
return; | ||
for (const [k, v] of Object.entries(obj)) { | ||
if (v && typeof v === 'object') { | ||
code.push(i.indent(`${objKey(k)}: {`, lv)); | ||
printObject(v, lv + 1); | ||
code.push(i.indent('},', lv)); | ||
} | ||
else { | ||
code.push(i.indent(`${objKey(k)}: ${esc(v)},`, lv)); | ||
} | ||
} | ||
} | ||
printObject(tokens); | ||
code.push('};', ''); | ||
return code.join('\n'); | ||
} | ||
function printTokensFlatExport(schemaTokens) { | ||
let code = ['export const tokensFlat = {']; | ||
const i = new Indenter(); | ||
for (const token of schemaTokens) { | ||
code.push(i.indent(`${objKey(token.id)}: ${esc((typeof options?.transform === 'function' && options?.transform(token)) || token.$value)},`, 1)); | ||
} | ||
code.push('};', ''); | ||
return code.join('\n'); | ||
} | ||
function printModesExport(schemaTokens) { | ||
let code = 'export const modes = '; | ||
// objectify | ||
let tokens = {}; | ||
let code = ['export const modes = {']; | ||
for (const token of schemaTokens) { | ||
if (!token.$extensions || !token.$extensions.mode) | ||
continue; | ||
const groups = token.id.split('.'); | ||
const localID = groups.pop(); | ||
let lastToken = tokens; | ||
for (const group of groups) { | ||
if (!tokens[group]) | ||
tokens[group] = {}; | ||
lastToken = tokens[group]; | ||
const i = new Indenter(); | ||
code.push(i.indent(`${objKey(token.id)}: {`, 1)); | ||
for (const [modeName, modeVal] of Object.entries(token.$extensions.mode)) { | ||
code.push(i.indent(`${objKey(modeName)}: ${esc((typeof options?.transform === 'function' && options?.transform(token, modeName)) || modeVal)},`, 2)); | ||
} | ||
lastToken[localID] = {}; | ||
for (const [k, v] of Object.entries(token.$extensions.mode)) { | ||
lastToken[localID][k] = transformer ? transformer(token) : v; | ||
} | ||
code.push(i.indent('},', 1)); | ||
} | ||
code += JSON.stringify(tokens, undefined, 2); | ||
code += ';\n'; | ||
return code; | ||
code.push('};', ''); | ||
return code.join('\n'); | ||
} | ||
function printAltFunction() { | ||
return `/** Get mode value */ | ||
export function getMode<T = string>(tokenID: keyof TokensFlat, mode: string): T { | ||
let defaultVal = tokens; | ||
let modeVal = modes; | ||
for (const next of tokenID.split('.')) { | ||
defaultVal = defaultVal[next]; | ||
if (modeVal[next] !== undefined) modeVal = modeVal[next]; | ||
} | ||
return (modeVal && modeVal[mode]) || defaultVal; | ||
}`; | ||
export function mode(tokenID: keyof typeof modes, modeName: keyof typeof modes[typeof tokenID]): typeof modes[typeof tokenID] { | ||
return modes[tokenID][modeName] as any; | ||
} | ||
`; | ||
} | ||
@@ -62,7 +80,7 @@ return { | ||
async build({ tokens }) { | ||
let code = [printTokensExport(tokens), printModesExport(tokens), printAltFunction()]; | ||
let code = [printTokensExport(tokens), printTokensFlatExport(tokens), printModesExport(tokens), printAltFunction()]; | ||
return [ | ||
{ | ||
filename, | ||
contents: code.join('\n\n'), | ||
contents: `${code.join('\n').trim()}\n`, | ||
}, | ||
@@ -69,0 +87,0 @@ ]; |
{ | ||
"name": "@cobalt-ui/plugin-ts", | ||
"description": "Generate TypeScript from your design tokens schema (requires @cobalt-ui/cli)", | ||
"version": "0.4.1", | ||
"version": "0.5.0", | ||
"author": { | ||
@@ -20,11 +20,16 @@ "name": "Drew Powers", | ||
"dependencies": { | ||
"@cobalt-ui/utils": "^0.4.0" | ||
"@cobalt-ui/utils": "^0.5.0" | ||
}, | ||
"devDependencies": { | ||
"@cobalt-ui/core": "^0.6.1" | ||
"@cobalt-ui/cli": "^0.5.2", | ||
"@cobalt-ui/core": "^0.6.2", | ||
"execa": "^6.1.0", | ||
"typescript": "^4.8.4", | ||
"vitest": "^0.24.0" | ||
}, | ||
"scripts": { | ||
"build": "tsc", | ||
"dev": "tsc -w" | ||
"dev": "tsc -w", | ||
"test": "vitest run" | ||
} | ||
} |
@@ -12,2 +12,3 @@ # @cobalt-ui/plugin-ts | ||
import ts from '@cobalt-ui/plugin-ts'; | ||
import better from 'better-color-tools'; | ||
@@ -21,4 +22,9 @@ /** @type import('@cobalt-ui/core').Config */ | ||
/** modify values */ | ||
transformValue(value, token) { | ||
return value; | ||
transform(token, mode) { | ||
// convert colors to P3 | ||
switch (token.$type) { | ||
case 'color': { | ||
return better.from(token.$value).p3; | ||
} | ||
} | ||
}, | ||
@@ -29,9 +35,1 @@ }), | ||
``` | ||
## Tools | ||
When you import your generated TypeScript, you’ll find more than just your tokens—you’ll find some handy utilities in there as well. | ||
### Color | ||
TODO |
105
src/index.ts
@@ -1,2 +0,3 @@ | ||
import type { BuildResult, ParsedToken, Plugin } from '@cobalt-ui/core'; | ||
import type {BuildResult, ParsedToken, Plugin} from '@cobalt-ui/core'; | ||
import {Indenter, objKey} from '@cobalt-ui/utils'; | ||
@@ -7,53 +8,76 @@ export interface Options { | ||
/** modify values */ | ||
transformValue?: (token: ParsedToken) => string; | ||
transform?: (token: ParsedToken, mode?: string) => string; | ||
} | ||
/** escape values with strings if necessary */ | ||
function esc(value: any): string { | ||
return String(Number(value)) === value ? value : `'${value}'`; | ||
} | ||
export default function ts(options?: Options): Plugin { | ||
let filename = options?.filename || './index.ts'; | ||
let transformer = options?.transformValue; | ||
function printTokensExport(schemaTokens: ParsedToken[]): string { | ||
let code = 'export const tokens = '; | ||
let code = ['export const tokens = {']; | ||
const i = new Indenter(); | ||
// objectify | ||
// reconstruct object | ||
const tokens: Record<string, any> = {}; | ||
for (const token of schemaTokens) { | ||
const groups = token.id.split('.'); | ||
const localID = groups.pop() as string; | ||
let lastToken = tokens; | ||
for (const group of groups) { | ||
if (!tokens[group]) tokens[group] = {}; | ||
lastToken = tokens[group]; | ||
const keys = token.id.split('.'); | ||
let node = tokens; | ||
for (let n = 0; n < keys.length; n++) { | ||
if (n === keys.length - 1) { | ||
node[keys[n]] = (typeof options?.transform === 'function' && options?.transform(token)) || token.$value; | ||
} else { | ||
if (!node[keys[n]]) node[keys[n]] = {}; | ||
} | ||
node = node[keys[n]]; | ||
} | ||
lastToken[localID] = transformer ? transformer(token) : token.$value; | ||
} | ||
code += JSON.stringify(tokens, undefined, 2); | ||
code += ';\n'; | ||
return code; | ||
// print string from object | ||
function printObject(obj: any, lv = 1): void { | ||
if (!obj || typeof obj !== 'object') return; | ||
for (const [k, v] of Object.entries(obj)) { | ||
if (v && typeof v === 'object') { | ||
code.push(i.indent(`${objKey(k)}: {`, lv)); | ||
printObject(v, lv + 1); | ||
code.push(i.indent('},', lv)); | ||
} else { | ||
code.push(i.indent(`${objKey(k)}: ${esc(v)},`, lv)); | ||
} | ||
} | ||
} | ||
printObject(tokens); | ||
code.push('};', ''); | ||
return code.join('\n'); | ||
} | ||
function printTokensFlatExport(schemaTokens: ParsedToken[]): string { | ||
let code = ['export const tokensFlat = {']; | ||
const i = new Indenter(); | ||
for (const token of schemaTokens) { | ||
code.push(i.indent(`${objKey(token.id)}: ${esc((typeof options?.transform === 'function' && options?.transform(token)) || token.$value)},`, 1)); | ||
} | ||
code.push('};', ''); | ||
return code.join('\n'); | ||
} | ||
function printModesExport(schemaTokens: ParsedToken[]): string { | ||
let code = 'export const modes = '; | ||
let code = ['export const modes = {']; | ||
// objectify | ||
let tokens: Record<string, any> = {}; | ||
for (const token of schemaTokens) { | ||
if (!token.$extensions || !token.$extensions.mode) continue; | ||
const groups = token.id.split('.'); | ||
const localID = groups.pop() as string; | ||
let lastToken = tokens; | ||
for (const group of groups) { | ||
if (!tokens[group]) tokens[group] = {}; | ||
lastToken = tokens[group]; | ||
const i = new Indenter(); | ||
code.push(i.indent(`${objKey(token.id)}: {`, 1)); | ||
for (const [modeName, modeVal] of Object.entries(token.$extensions.mode)) { | ||
code.push(i.indent(`${objKey(modeName)}: ${esc((typeof options?.transform === 'function' && options?.transform(token, modeName)) || modeVal)},`, 2)); | ||
} | ||
lastToken[localID] = {}; | ||
for (const [k, v] of Object.entries(token.$extensions.mode)) { | ||
lastToken[localID][k] = transformer ? transformer(token) : v; | ||
} | ||
code.push(i.indent('},', 1)); | ||
} | ||
code += JSON.stringify(tokens, undefined, 2); | ||
code += ';\n'; | ||
return code; | ||
code.push('};', ''); | ||
return code.join('\n'); | ||
} | ||
@@ -63,21 +87,16 @@ | ||
return `/** Get mode value */ | ||
export function getMode<T = string>(tokenID: keyof TokensFlat, mode: string): T { | ||
let defaultVal = tokens; | ||
let modeVal = modes; | ||
for (const next of tokenID.split('.')) { | ||
defaultVal = defaultVal[next]; | ||
if (modeVal[next] !== undefined) modeVal = modeVal[next]; | ||
export function mode(tokenID: keyof typeof modes, modeName: keyof typeof modes[typeof tokenID]): typeof modes[typeof tokenID] { | ||
return modes[tokenID][modeName] as any; | ||
} | ||
`; | ||
} | ||
return (modeVal && modeVal[mode]) || defaultVal; | ||
}`; | ||
} | ||
return { | ||
name: '@cobalt-ui/plugin-ts', | ||
async build({ tokens }): Promise<BuildResult[]> { | ||
let code = [printTokensExport(tokens), printModesExport(tokens), printAltFunction()]; | ||
async build({tokens}): Promise<BuildResult[]> { | ||
let code = [printTokensExport(tokens), printTokensFlatExport(tokens), printModesExport(tokens), printAltFunction()]; | ||
return [ | ||
{ | ||
filename, | ||
contents: code.join('\n\n'), | ||
contents: `${code.join('\n').trim()}\n`, | ||
}, | ||
@@ -84,0 +103,0 @@ ]; |
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
24761
13
595
5
33
1
+ Added@cobalt-ui/utils@0.5.3(transitive)
- Removed@cobalt-ui/utils@0.4.0(transitive)
Updated@cobalt-ui/utils@^0.5.0