-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
40 changed files
with
5,437 additions
and
222 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
dist/ |
Binary file not shown.
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
yarnPath: .yarn/releases/yarn-4.1.1.cjs | ||
nodeLinker: node-modules |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
#!/usr/bin/env node | ||
|
||
import { run } from '../dist/index.js'; | ||
|
||
run().catch((e) => { | ||
console.error(e); | ||
process.exit(1); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
{ | ||
"name": "cli", | ||
"version": "0.0.0", | ||
"private": true, | ||
"description": "Generate theme typings for autocomplete", | ||
"type": "module", | ||
"main": "dist/cjs/index.cjs", | ||
"module": "dist/esm/index.mjs", | ||
"types": "dist/types/index.d.ts", | ||
"scripts": { | ||
"build": "rm -rf dist && tsup src --format esm --shims", | ||
"check:type": "tsc --noEmit" | ||
}, | ||
"dependencies": { | ||
"bundle-n-require": "^1.0.1", | ||
"chokidar": "^3.5.3", | ||
"cli-welcome": "^2.2.2", | ||
"commander": "^11.0.0", | ||
"ora": "^7.0.1", | ||
"prettier": "^3.0.2", | ||
"update-notifier": "^6.0.2" | ||
}, | ||
"bin": "bin/index.js", | ||
"devDependencies": { | ||
"@types/ora": "^3.2.0", | ||
"@types/update-notifier": "6.0.4", | ||
"tsup": "^8.0.2", | ||
"typescript": "5.2.2" | ||
}, | ||
"packageManager": "yarn@4.1.1" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import type { ThemeKeyOptions } from './create-theme-typings-interface.js'; | ||
|
||
export const themeKeyConfiguration: ThemeKeyOptions[] = [ | ||
{ key: 'colors', maxScanDepth: 3 }, | ||
{ key: 'radii' }, | ||
{ key: 'sizes', maxScanDepth: 2 }, | ||
{ key: 'space', flatMap: (value) => [value, `-${value}`] }, | ||
]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
import { isObject } from './utils/is-object.js'; | ||
import { extractPropertyKeys } from './extract-property-keys.js'; | ||
import { extractPropertyPaths, printUnionMap } from './extract-property-paths.js'; | ||
import { extractSemanticTokenKeys } from './extract-semantic-token-keys.js'; | ||
|
||
export interface ThemeKeyOptions { | ||
/** | ||
* Property key in the theme object | ||
* @example colors | ||
*/ | ||
key: string; | ||
/** | ||
* Maximum extraction level | ||
* @example | ||
* union: gray.500 | ||
* level: 1---|2--| | ||
* @default 3 | ||
*/ | ||
maxScanDepth?: number; | ||
/** | ||
* Pass a function to filter extracted values | ||
* @example | ||
* Exclude numeric index values from `breakpoints` | ||
* @default () => true | ||
*/ | ||
filter?: (value: string) => boolean; | ||
|
||
/** | ||
* Pass a function to flatMap extracted values | ||
* @default value => value | ||
*/ | ||
flatMap?: (value: string) => string | string[]; | ||
} | ||
|
||
export type TypingsTemplate = 'default' | 'augmentation'; | ||
|
||
export interface CreateThemeTypingsInterfaceOptions { | ||
config: ThemeKeyOptions[]; | ||
strictComponentTypes?: boolean; | ||
format?: boolean; | ||
strictTokenTypes?: boolean; | ||
template?: TypingsTemplate; | ||
} | ||
|
||
function applyThemeTypingTemplate(typingContent: string, template: TypingsTemplate) { | ||
switch (template) { | ||
case 'augmentation': | ||
return `// regenerate by running | ||
// npx @chakra-ui/cli tokens path/to/your/theme.(js|ts) --template augmentation --out path/to/this/file | ||
import { BaseThemeTypings } from "@chakra-ui/styled-system"; | ||
declare module "@chakra-ui/styled-system" { | ||
export interface CustomThemeTypings extends BaseThemeTypings { | ||
${typingContent} | ||
} | ||
} | ||
`; | ||
case 'default': | ||
default: | ||
return `// regenerate by running | ||
// npx @chakra-ui/cli tokens path/to/your/theme.(js|ts) | ||
import { BaseThemeTypings } from "./shared.types.js" | ||
export interface ThemeTypings extends BaseThemeTypings { | ||
${typingContent} | ||
} | ||
`; | ||
} | ||
} | ||
|
||
export async function createThemeTypingsInterface( | ||
theme: Record<string, unknown>, | ||
{ config }: CreateThemeTypingsInterfaceOptions, | ||
) { | ||
const unions = config.reduce( | ||
(allUnions, { key, maxScanDepth, filter = () => true, flatMap = (value) => value }) => { | ||
const target = theme[key]; | ||
|
||
allUnions[key] = []; | ||
|
||
if (isObject(target) || Array.isArray(target)) { | ||
allUnions[key] = extractPropertyPaths(target, maxScanDepth).filter(filter).flatMap(flatMap); | ||
} | ||
|
||
if (isObject(theme.semanticTokens)) { | ||
const semanticTokenKeys = extractSemanticTokenKeys(theme, key) | ||
.filter(filter) | ||
.flatMap(flatMap); | ||
|
||
allUnions[key].push(...semanticTokenKeys); | ||
} | ||
|
||
return allUnions; | ||
}, | ||
{} as Record<string, string[]>, | ||
); | ||
|
||
const typography = extractPropertyKeys(theme, 'typography'); | ||
|
||
const typingContent = `${printUnionMap( | ||
{ ...unions, typography }, | ||
(targetKey) => targetKey === 'conditions', | ||
)}`; | ||
|
||
return applyThemeTypingTemplate(typingContent, 'default'); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import { isColorHue } from "./utils/is-color-hue.js" | ||
import { isObject } from "./utils/is-object.js" | ||
|
||
/** | ||
* Extract color scheme names | ||
* by validating that every property of type ColorHue is in the object | ||
*/ | ||
export function extractColorSchemeTypes(theme: Record<string, unknown>) { | ||
const { colors } = theme | ||
if (!isObject(colors)) { | ||
return [] | ||
} | ||
|
||
return Object.entries(colors).reduce( | ||
(acc: string[], [colorName, colorValues]) => { | ||
if (isColorHue(colorValues)) { | ||
acc.push(colorName) | ||
} | ||
|
||
return acc | ||
}, | ||
[], | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
import { isObject } from "./utils/is-object.js" | ||
import { printUnionMap } from "./extract-property-paths.js" | ||
|
||
interface ComponentType extends Record<string, string[]> { | ||
sizes: string[] | ||
variants: string[] | ||
} | ||
|
||
export function extractComponentTypes(theme: Record<string, unknown>) { | ||
const components = theme.components | ||
if (!isObject(components)) { | ||
return {} | ||
} | ||
|
||
return Object.entries(components).reduce( | ||
(allDefs, [componentName, definition]) => { | ||
if (definition) { | ||
allDefs[componentName] = { | ||
sizes: Object.keys(definition.sizes ?? {}), | ||
variants: Object.keys(definition.variants ?? {}), | ||
} | ||
} | ||
|
||
return allDefs | ||
}, | ||
{} as Record<string, ComponentType>, | ||
) | ||
} | ||
|
||
function esc(name: string) { | ||
return name.match(/^[a-zA-Z0-9\-_]+$/) ? name : `"${name}"` | ||
} | ||
|
||
export function printComponentTypes( | ||
componentTypes: Record<string, ComponentType>, | ||
strict = false, | ||
) { | ||
const types = Object.entries(componentTypes) | ||
.map( | ||
([componentName, unions]) => | ||
`${esc(componentName)}: { | ||
${printUnionMap(unions, strict)} | ||
}`, | ||
) | ||
.join(`\n`) | ||
|
||
return `components: { | ||
${types} | ||
} | ||
` | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import { isObject } from "./utils/is-object.js" | ||
|
||
/** | ||
* Extract textStyles keys | ||
*/ | ||
export function extractPropertyKeys( | ||
theme: Record<string, unknown>, | ||
themePropertyName: string, | ||
) { | ||
const themeProperty = theme[themePropertyName] | ||
if (!isObject(themeProperty)) { | ||
return [] | ||
} | ||
|
||
return Object.keys(themeProperty) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import { isObject } from "./utils/is-object.js" | ||
import { printUnionType } from "./utils/print-union-type.js" | ||
|
||
/** | ||
* @example | ||
* { colors: ['red.500', 'green.500'] } => `colors: "red.500" | "green.500"` | ||
*/ | ||
export function printUnionMap( | ||
unions: Record<string, string[]>, | ||
strict: boolean | ((targetKey: string) => boolean) = false, | ||
) { | ||
return Object.entries(unions) | ||
.sort(([a], [b]) => a.localeCompare(b)) | ||
.map(([targetKey, union]) => { | ||
const isStrict = typeof strict === "function" ? strict(targetKey) : strict | ||
return `${targetKey}: ${printUnionType(union, isStrict)};` | ||
}) | ||
.join("\n") | ||
} | ||
|
||
/** | ||
* Extract recursively all property paths with a max depth | ||
*/ | ||
export function extractPropertyPaths(target: unknown, maxDepth = 3) { | ||
if ((!isObject(target) && !Array.isArray(target)) || !maxDepth) { | ||
return [] | ||
} | ||
|
||
return Object.entries(target).reduce((allPropertyPaths, [key, value]) => { | ||
if (isObject(value)) { | ||
extractPropertyPaths(value, maxDepth - 1).forEach((childKey) => | ||
// e.g. gray.500 | ||
allPropertyPaths.push(`${key}.${childKey}`), | ||
) | ||
} else { | ||
// e.g. transparent | ||
allPropertyPaths.push(key) | ||
} | ||
|
||
return allPropertyPaths | ||
}, [] as string[]) | ||
} |
Oops, something went wrong.