Skip to content

Commit

Permalink
feat: token and recipe analysis (#3035)
Browse files Browse the repository at this point in the history
* wip

* refactor: code and mv to node pkg

* docs: add changeset

* refactor: create reporter package

* fix: recipe and token detection

* refactor: classify pattern

* refactor: add support for output format

* refactor: format

* refactor: support scope and classify global css

* refactor: update tokens

* refactor: slice most used

* refactor: update

* chore: rm unused

* docs: update changeset

* refactor: expose token maps

* refactor: fix typo

---------

Co-authored-by: Alexandre Stahmer <[email protected]>
  • Loading branch information
segunadebayo and astahmer authored Dec 24, 2024
1 parent 552b01c commit fea78c7
Show file tree
Hide file tree
Showing 28 changed files with 6,852 additions and 5,634 deletions.
19 changes: 19 additions & 0 deletions .changeset/nervous-pans-enjoy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
'@pandacss/types': minor
'@pandacss/node': minor
'@pandacss/dev': minor
'@pandacss/reporter': minor
---

Adds support for static analysis of used tokens and recipe variants. It helps to get a birds-eye view of how your design
system is used and answers the following questions:

- What tokens are most used?
- What recipe variants are most used?
- How many hardcoded values vs tokens do we have?

```sh
panda analyze --scope=<token|recipe>
```

> Still work in progress but we're excited to get your feedback!
27 changes: 17 additions & 10 deletions packages/cli/src/cli-main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { findConfig } from '@pandacss/config'
import { colors, logger } from '@pandacss/logger'
import {
PandaContext,
analyzeTokens,
analyze,
buildInfo,
codegen,
cssgen,
Expand All @@ -14,7 +14,6 @@ import {
setupGitIgnore,
setupPostcss,
startProfiling,
writeAnalyzeJSON,
type CssGenOptions,
} from '@pandacss/node'
import { PandaError, compact } from '@pandacss/shared'
Expand Down Expand Up @@ -361,10 +360,14 @@ export async function main() {
.command('analyze [glob]', 'Analyze design token usage in glob')
.option('--outfile [filepath]', 'Output analyze report in JSON')
.option('--silent', "Don't print any logs")
.option('--scope <type>', 'Select analysis scope (token or recipe)')
.option('-c, --config <path>', 'Path to panda config file')
.option('--cwd <cwd>', 'Current working directory', { default: cwd })
.action(async (maybeGlob?: string, flags: AnalyzeCommandFlags = {}) => {
const { silent, config: configPath } = flags
const { silent, config: configPath, scope } = flags

const tokenScope = scope == null || scope === 'token'
const recipeScope = scope == null || scope === 'recipe'

const cwd = resolve(flags.cwd!)

Expand All @@ -378,19 +381,23 @@ export async function main() {
configPath,
})

const result = analyzeTokens(ctx, {
onResult(file) {
logger.info('cli', `Analyzed ${colors.bold(file)}`)
},
})
const result = analyze(ctx)

if (flags?.outfile && typeof flags.outfile === 'string') {
await writeAnalyzeJSON(flags.outfile, result, ctx)
await result.writeReport(flags.outfile)
logger.info('cli', `JSON report saved to ${resolve(flags.outfile)}`)
return
}

logger.info('cli', `Found ${result.propByIndex.size} token used in ${result.derived.byFilePathMaps.size} files`)
if (tokenScope && !ctx.tokens.isEmpty) {
const tokenAnalysis = result.getTokenReport()
logger.info('analyze:tokens', `Token usage report 🎨 \n${tokenAnalysis.formatted}`)
}

if (recipeScope && !ctx.recipes.isEmpty()) {
const recipeAnalysis = result.getRecipeReport()
logger.info('analyze:recipes', `Recipe usage report 🎛️ \n${recipeAnalysis.formatted}`)
}
})

cli
Expand Down
1 change: 1 addition & 0 deletions packages/cli/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export interface AnalyzeCommandFlags {
outfile?: string
cwd?: string
config?: string
scope?: 'token' | 'recipe'
}

export interface DebugCommandFlags {
Expand Down
5 changes: 4 additions & 1 deletion packages/core/src/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,10 @@ export class Context {
recipes: this.recipes,
patterns: this.patterns,
jsx: this.jsx,
syntax: config.syntax,
config: this.config,
tokens: this.tokens,
conditions: this.conditions,
utility: this.utility,
encoder: this.encoder,
tsOptions: this.conf.tsOptions,
join: (...paths: string[]) => paths.join('/'),
Expand Down
4 changes: 4 additions & 0 deletions packages/core/src/recipes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ export class Recipes {

private context!: SerializeContext

get config() {
return this.recipes
}

constructor(private recipes: RecipeRecord = {}) {
this.prune()
}
Expand Down
10 changes: 8 additions & 2 deletions packages/core/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { TokenDictionary } from '@pandacss/token-dictionary'
import type {
Config,
Dict,
Expand All @@ -9,13 +10,15 @@ import type {
TSConfig,
UserConfig,
} from '@pandacss/types'
import type { Conditions } from './conditions'
import type { Context } from './context'
import type { ImportMap } from './import-map'
import type { JsxEngine } from './jsx'
import type { Layers } from './layers'
import type { Patterns } from './patterns'
import type { Recipes } from './recipes'
import type { StyleEncoder } from './style-encoder'
import type { Context } from './context'
import type { Utility } from './utility'

export interface TransformResult {
layer?: string
Expand Down Expand Up @@ -114,9 +117,12 @@ export interface ParserOptions {
hash: HashOptions
imports: ImportMap
jsx: JsxEngine
syntax: Config['syntax']
config: Config
recipes: Recipes
tokens: TokenDictionary
patterns: Patterns
utility: Utility
conditions: Conditions
encoder: StyleEncoder
join: (...paths: string[]) => string
compilerOptions: TSConfig['compilerOptions']
Expand Down
31 changes: 26 additions & 5 deletions packages/core/src/utility.ts
Original file line number Diff line number Diff line change
Expand Up @@ -413,17 +413,24 @@ export class Utility {
return this
}

private getTransformArgs = (raw: string): TransformArgs => {
const token = Object.assign(this.getToken.bind(this), {
private getTokenFn = () => {
return Object.assign(this.getToken.bind(this), {
raw: (path: string) => this.tokens.getByName(path),
})
}

const _colorMix = (value: string) => colorMix(value, token)
resolveColorMix = (value: string) => {
const token = this.getTokenFn()
return colorMix(value, token)
}

private getTransformArgs = (raw: string): TransformArgs => {
return {
token,
token: this.getTokenFn(),
raw,
utils: { colorMix: _colorMix },
utils: {
colorMix: this.resolveColorMix.bind(this),
},
}
}

Expand Down Expand Up @@ -548,4 +555,18 @@ export class Utility {
isDeprecated = (prop: string) => {
return this.deprecated.has(prop)
}

/**
* Returns the token type for a given property
*/
getTokenType = (prop: string) => {
const set = this.types.get(prop)
if (!set) return
for (const type of set) {
const match = type.match(TOKEN_TYPE_PATTERN)
if (match) return match[1]
}
}
}

const TOKEN_TYPE_PATTERN = /type:Tokens\["([^"]+)"\]/
9 changes: 9 additions & 0 deletions packages/extractor/src/box.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,15 @@ export const box = {
return new BoxNodeConditional({ type: 'conditional', whenTrue, whenFalse, node, stack })
},
from: toBoxNode,
objectToMap: (value: Record<string, unknown>, node: Node, stack: Node[]) => {
const map = new Map(
Object.entries(value).map(([k, v]: [string, any]) => {
const boxed = box.from(v, node, stack)
return [k, boxed || null]
}),
)
return new BoxNodeMap({ type: 'map', value: map, node, stack })
},
//
emptyObject: (node: Node, stack: Node[]) => {
return new BoxNodeObject({ type: 'object', value: {}, isEmpty: true, node, stack })
Expand Down
4 changes: 1 addition & 3 deletions packages/node/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@
"dependencies": {
"@pandacss/config": "workspace:*",
"@pandacss/core": "workspace:*",
"@pandacss/extractor": "workspace:*",
"@pandacss/generator": "workspace:*",
"@pandacss/reporter": "workspace:*",
"@pandacss/logger": "workspace:*",
"@pandacss/parser": "workspace:*",
"@pandacss/shared": "workspace:*",
Expand All @@ -49,8 +49,6 @@
"browserslist": "4.23.3",
"chokidar": "3.6.0",
"fast-glob": "3.3.2",
"file-size": "1.0.0",
"filesize": "10.1.6",
"fs-extra": "11.2.0",
"glob-parent": "6.0.2",
"is-glob": "4.0.3",
Expand Down
146 changes: 0 additions & 146 deletions packages/node/src/analyze-tokens.ts

This file was deleted.

Loading

0 comments on commit fea78c7

Please sign in to comment.