@pandabox/prettier-plugin
Version:
Prettier plugin for Panda css
162 lines (142 loc) • 5.4 kB
text/typescript
// Adapted from
// https://github.com/yukukotani/eslint-plugin-chakra-ui/blob/dba8a50774e7b133ff9a9d3ae099202ac4d620c4/src/rules/props-order.ts
import type { CssSemanticGroup } from '@pandacss/types'
import type { PluginOptions } from './options'
import { isCssProperty } from '@pandacss/is-valid-prop'
export const defaultGroupNames = [
'System',
'Container',
'Display',
'Visibility',
'Position',
'Transform',
'Flex Layout',
'Grid Layout',
'Layout',
'Border',
'Border Radius',
'Width',
'Height',
'Margin',
'Padding',
'Color',
'Typography',
'Background',
'Shadow',
'Table',
'List',
'Scroll',
'Interactivity',
'Transition',
'Effect',
'Other',
'Conditions',
'Arbitrary conditions',
'Css',
] as const
export type PriorityGroupName = CssSemanticGroup | (typeof defaultGroupNames)[number]
type Priority = Record<PriorityGroupName, number>
export type PriorityGroup = {
name: PriorityGroupName
keys: string[]
priority: Priority[PriorityGroupName]
}
/**
* getPriority returns a number. The smaller is the higher priority.
* Internally, each property should have 2 priorities.
* One is its "group priority", determined by which group property belongs,
* and the other is its "inGroup priority", determined by index in that group.
*/
export function getPropPriority({
key,
config,
priorityGroups,
}: {
key: string
config: PluginOptions
priorityGroups: PriorityGroup[]
}): number {
const { pandaFirstProps: firstProps = [], pandaLastProps: lastProps = [] } = config
const indexInFirstProps = firstProps.indexOf(key)
const indexInLastProps = lastProps.indexOf(key)
const componentSpecificProps = [] as string[]
if (indexInFirstProps !== -1) {
return calcPriorityFromIndex({ type: 'reservedFirstProps', value: indexInFirstProps }, config, priorityGroups)
}
if (indexInLastProps !== -1) {
return calcPriorityFromIndex({ type: 'reservedLastProps', value: indexInLastProps }, config, priorityGroups)
}
if (componentSpecificProps) {
const index = componentSpecificProps.indexOf(key)
if (index !== -1) {
return calcPriorityFromIndex({ type: 'componentSpecificProps', value: index }, config, priorityGroups)
}
}
// Then it can be either `stylePropsPriority` or `otherPropsPriority`
let groupIndex = priorityGroups.findIndex((group) => {
return group.keys.includes(key)
})
// If the property is not in any group but is still a valid CSS prop, it's in the `Other` group
if (groupIndex === -1 && isCssProperty(key)) {
groupIndex = priorityGroups.findIndex((group) => group.name === 'Other')
}
const isStyleProps = groupIndex > -1
if (isStyleProps) {
const keyIndex = priorityGroups[groupIndex].keys.indexOf(key)
return calcPriorityFromIndex({ type: 'styleProps', groupIndex, keyIndex }, config, priorityGroups)
}
return calcPriorityFromIndex({ type: 'otherProps' }, config, priorityGroups)
}
type Index =
| { type: 'reservedFirstProps' | 'componentSpecificProps' | 'reservedLastProps'; value: number }
| { type: 'styleProps'; groupIndex: number; keyIndex: number }
| { type: 'otherProps' }
const calcPriorityFromIndex = (index: Index, config: PluginOptions, priorityGroups: PriorityGroup[]) => {
// This calculates the priority, in which every property has different priority.
// As an exception, non-predefined properties have the same priority.
// They will be treated as "other Props".
// Currently, the priority is determined from the index of the array.
// We assume that the length of each array is at most 100.
// When changing the specification, be sure to check that the stylePropsPriority range does not overlap with others.
// Now its range is 20000 <= x < 30000;
// Perhaps we may want to handle -1 as error in some future.
// Therefore I set the priority to numbers greater than or equal to zero.
const isComponentSpecBeforeStyle = true
const basePriorities = {
firstProps: 0,
styleProps: config.pandaStylePropsFirst ? 20_000 : 45_000,
componentSpecificProps: isComponentSpecBeforeStyle ? 10_000 : 30_000,
otherProps: 40_000,
lastProps: 50_000,
}
switch (index.type) {
case 'reservedFirstProps': {
const groupPriority = basePriorities.firstProps
const InGroupPriority = index.value
return groupPriority + InGroupPriority
}
case 'styleProps': {
const { groupIndex, keyIndex } = index
const basePriority = basePriorities.styleProps
const groupPriority = priorityGroups[groupIndex].priority
const InGroupPriority = keyIndex
// By using the following formula, we can assign a unique priority to each props of style props.
// Justification: Since priorityGroups[**].length is less than 100, there is no duplicate.
return basePriority + groupPriority * 100 + InGroupPriority
}
case 'componentSpecificProps': {
const groupPriority = basePriorities.componentSpecificProps
return groupPriority
}
case 'otherProps': {
const groupPriority = basePriorities.otherProps
// This will always return same priority value. It needs non-priority-based sorting.
return groupPriority
}
case 'reservedLastProps': {
const groupPriority = basePriorities.lastProps
const InGroupPriority = index.value
return groupPriority + InGroupPriority
}
}
}