Skip to content

Commit 8472753

Browse files
committed
feat: parser api and units option
1 parent 8116ed6 commit 8472753

File tree

4 files changed

+62
-22
lines changed

4 files changed

+62
-22
lines changed

src/tasty/parser/ast.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,11 @@ export type StyleToken = RawStyleToken & {
44
children?: StyleToken[];
55
};
66

7-
const COLOR_FUNCTIONS = ['rgb', 'rgba', 'hsl', 'hsla'];
7+
const COLOR_FUNCTIONS = ['rgb', 'rgba', 'hsl', 'hsla', 'lch', 'oklch'];
88

9+
/**
10+
* Create an AST from a flat array of style tokens.
11+
*/
912
export function createAST(
1013
tokens: StyleToken[],
1114
startIndex = 0,

src/tasty/parser/index.ts

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,36 @@
1-
export function parseStyle(val) {}
1+
import { tokenize } from './tokenizer';
2+
import { renderStyleTokens, CustomUnitMap } from './renderer';
3+
import { createAST, StyleToken } from './ast';
4+
5+
interface StyleParserProps {
6+
units: CustomUnitMap;
7+
}
8+
9+
export function CreateStyleParser({ units }: StyleParserProps) {
10+
return {
11+
parse(value) {
12+
return createAST(tokenize(value));
13+
},
14+
render(tokens) {
15+
return renderStyleTokens(tokens, { units });
16+
},
17+
excludeMods(tokens: StyleToken[], allMods: string[]) {
18+
const mods: string[] = [];
19+
20+
for (let i = 0; i < tokens.length; i++) {
21+
const token = tokens[i];
22+
23+
if (token.type === 'text') {
24+
const mod = token.value;
25+
26+
if (allMods.includes(mod)) {
27+
mods.push(mod);
28+
tokens.splice(i--, 1);
29+
}
30+
}
31+
}
32+
33+
return mods;
34+
},
35+
};
36+
}

src/tasty/parser/renderer.ts

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,11 @@
11
import { StyleToken } from './ast';
22

3-
export const CUSTOM_UNITS: Record<string, string | ((key: string) => string)> =
4-
{
5-
r: 'var(--radius)',
6-
bw: 'var(--border-width)',
7-
ow: 'var(--outline-width)',
8-
x: 'var(--gap)',
9-
fs: 'var(--font-size)',
10-
lh: 'var(--line-height)',
11-
rp: 'var(--rem-pixel)',
12-
gp: 'var(--column-gap)',
13-
};
14-
15-
export function renderCustomUnit(token: StyleToken) {
16-
const converter =
17-
CUSTOM_UNITS[token.unit as unknown as keyof typeof CUSTOM_UNITS];
3+
export type CustomUnitMap = Record<string, string | ((key: string) => string)>;
4+
5+
export function renderCustomUnit(token: StyleToken, units?: CustomUnitMap) {
6+
units = units || {};
7+
8+
const converter = token.unit ? units[token.unit] : undefined;
189

1910
if (!converter) {
2011
return token.value;
@@ -33,18 +24,24 @@ export function renderCustomUnit(token: StyleToken) {
3324

3425
const INSTANT_VALUES = [')', ','];
3526

36-
export function renderStyleTokens(tokens: StyleToken[]) {
27+
/**
28+
* Render a style tokens to a string.
29+
*/
30+
export function renderStyleTokens(
31+
tokens: StyleToken[],
32+
{ units }: { units?: CustomUnitMap } = {},
33+
) {
3734
let result = '';
3835

3936
tokens.forEach((token) => {
4037
if (INSTANT_VALUES.includes(token.value)) {
4138
result += token.value;
4239
} else if (token.type === 'func') {
4340
result += token.children
44-
? `${token.value}(${renderStyleTokens(token.children)})`
41+
? `${token.value}(${renderStyleTokens(token.children, units)})`
4542
: '';
4643
} else if (token.type === 'value') {
47-
result += renderCustomUnit(token);
44+
result += renderCustomUnit(token, units);
4845
} else if (token.type === 'property') {
4946
result += `var(--${token.value.slice(1)})`;
5047
} else {

src/tasty/parser/tokenizer.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,10 @@ const TOKEN_MAP = [
2929
'space',
3030
];
3131

32-
export function tokenize(value: string) {
32+
/**
33+
* Tokenize a style value into a flat array of tokens.
34+
*/
35+
export function tokenize(value: string): RawStyleToken[] {
3336
value = value.trim();
3437

3538
if (!value) {
@@ -69,5 +72,7 @@ export function tokenize(value: string) {
6972
CACHE.set(value, tokens);
7073
}
7174

72-
return CACHE.get(value);
75+
const cachedTokens = CACHE.get(value);
76+
77+
return cachedTokens ? cachedTokens : [];
7378
}

0 commit comments

Comments
 (0)