typewritingclass-compiler 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -4
- package/package.json +12 -3
- package/src/index.ts +1 -114
- package/src/loadTheme.ts +116 -0
package/README.md
CHANGED
|
@@ -31,15 +31,12 @@ import 'virtual:twc.css'
|
|
|
31
31
|
```ts
|
|
32
32
|
twcPlugin({
|
|
33
33
|
strict: true, // Error on dynamic values not wrapped with dynamic() (default: true)
|
|
34
|
-
theme: { // Custom theme input
|
|
35
|
-
colors: { brand: { 500: '#6366f1' } },
|
|
36
|
-
},
|
|
37
34
|
})
|
|
38
35
|
```
|
|
39
36
|
|
|
40
37
|
## How it works
|
|
41
38
|
|
|
42
|
-
1. **Static analysis** — the Rust extractor scans TS/JS files for `cx()`, `when()`, and utility calls
|
|
39
|
+
1. **Static analysis** — the Rust extractor scans TS/JS files for `tw`, `cx()`, `when()`, and utility calls
|
|
43
40
|
2. **CSS generation** — extracted rules are compiled into deterministic class names and CSS declarations
|
|
44
41
|
3. **Code transform** — utility call sites are replaced with the generated class name strings
|
|
45
42
|
4. **Virtual module** — `virtual:twc.css` aggregates all extracted CSS, respecting `@layer` ordering
|
package/package.json
CHANGED
|
@@ -1,18 +1,27 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "typewritingclass-compiler",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"type": "module",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "https://github.com/corysimmons/typewritingclass",
|
|
8
|
+
"directory": "packages/typewritingclass-compiler"
|
|
9
|
+
},
|
|
5
10
|
"exports": {
|
|
6
11
|
".": {
|
|
7
12
|
"types": "./src/index.ts",
|
|
8
13
|
"default": "./src/index.ts"
|
|
14
|
+
},
|
|
15
|
+
"./loadTheme": {
|
|
16
|
+
"types": "./src/loadTheme.ts",
|
|
17
|
+
"default": "./src/loadTheme.ts"
|
|
9
18
|
}
|
|
10
19
|
},
|
|
11
20
|
"files": [
|
|
12
21
|
"src"
|
|
13
22
|
],
|
|
14
23
|
"napi": {
|
|
15
|
-
"name": "
|
|
24
|
+
"name": "index",
|
|
16
25
|
"triples": {}
|
|
17
26
|
},
|
|
18
27
|
"peerDependencies": {
|
|
@@ -20,7 +29,7 @@
|
|
|
20
29
|
},
|
|
21
30
|
"dependencies": {
|
|
22
31
|
"magic-string": "^0.30.21",
|
|
23
|
-
"typewritingclass": "0.2.
|
|
32
|
+
"typewritingclass": "0.2.2"
|
|
24
33
|
},
|
|
25
34
|
"devDependencies": {
|
|
26
35
|
"@types/node": "^25.2.2",
|
package/src/index.ts
CHANGED
|
@@ -3,6 +3,7 @@ import MagicString from 'magic-string'
|
|
|
3
3
|
import { createRequire } from 'module'
|
|
4
4
|
import { resolve, dirname } from 'path'
|
|
5
5
|
import { fileURLToPath } from 'url'
|
|
6
|
+
import { loadTheme } from './loadTheme.ts'
|
|
6
7
|
|
|
7
8
|
// Load native addon
|
|
8
9
|
const require = createRequire(import.meta.url)
|
|
@@ -146,117 +147,3 @@ export default function twcPlugin(options?: TwcPluginOptions): Plugin {
|
|
|
146
147
|
}
|
|
147
148
|
}
|
|
148
149
|
|
|
149
|
-
/**
|
|
150
|
-
* Load theme data from the typewritingclass package.
|
|
151
|
-
* This dynamically imports the theme modules so values come from the TS source,
|
|
152
|
-
* not hardcoded in the compiler.
|
|
153
|
-
*/
|
|
154
|
-
async function loadTheme(): Promise<import('../index.d.ts').ThemeInput> {
|
|
155
|
-
// Import all theme modules from the TS package
|
|
156
|
-
const [colorsModule, spacingModule, typographyModule, sizesModule, shadowsModule, bordersModule] =
|
|
157
|
-
await Promise.all([
|
|
158
|
-
import('typewritingclass/theme/colors'),
|
|
159
|
-
import('typewritingclass/theme'),
|
|
160
|
-
import('typewritingclass/theme/typography'),
|
|
161
|
-
import('typewritingclass/theme/sizes'),
|
|
162
|
-
import('typewritingclass/theme/shadows'),
|
|
163
|
-
import('typewritingclass/theme/borders'),
|
|
164
|
-
])
|
|
165
|
-
|
|
166
|
-
// Build color scales map
|
|
167
|
-
const colorScaleNames = [
|
|
168
|
-
'slate', 'gray', 'zinc', 'neutral', 'stone', 'red', 'orange', 'amber',
|
|
169
|
-
'yellow', 'lime', 'green', 'emerald', 'teal', 'cyan', 'sky', 'blue',
|
|
170
|
-
'indigo', 'violet', 'purple', 'fuchsia', 'pink', 'rose',
|
|
171
|
-
]
|
|
172
|
-
const colors: Record<string, Record<string, string>> = {}
|
|
173
|
-
for (const name of colorScaleNames) {
|
|
174
|
-
const scale = (colorsModule as Record<string, any>)[name]
|
|
175
|
-
if (scale && typeof scale === 'object') {
|
|
176
|
-
colors[name] = {}
|
|
177
|
-
for (const [shade, hex] of Object.entries(scale)) {
|
|
178
|
-
colors[name][String(shade)] = hex as string
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
// Named colors
|
|
184
|
-
const namedColors: Record<string, string> = {
|
|
185
|
-
white: colorsModule.white,
|
|
186
|
-
black: colorsModule.black,
|
|
187
|
-
transparent: colorsModule.transparent,
|
|
188
|
-
currentColor: colorsModule.currentColor,
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
// Spacing scale
|
|
192
|
-
const { spacing: spacingNs } = spacingModule as any
|
|
193
|
-
const spacing: Record<string, string> = {}
|
|
194
|
-
if (spacingNs && spacingNs.spacingScale) {
|
|
195
|
-
for (const [key, val] of Object.entries(spacingNs.spacingScale)) {
|
|
196
|
-
spacing[String(key)] = val as string
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
// Text sizes
|
|
201
|
-
const textSizeNames = ['xs', 'sm', 'base', 'lg', 'xl', '_2xl', '_3xl', '_4xl', '_5xl', '_6xl', '_7xl', '_8xl', '_9xl']
|
|
202
|
-
const textSizes: Record<string, { fontSize: string; lineHeight: string }> = {}
|
|
203
|
-
for (const name of textSizeNames) {
|
|
204
|
-
const token = (typographyModule as Record<string, any>)[name]
|
|
205
|
-
if (token && typeof token === 'object' && 'fontSize' in token) {
|
|
206
|
-
textSizes[name] = { fontSize: token.fontSize, lineHeight: token.lineHeight }
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
// Font weights
|
|
211
|
-
const weightNames = ['thin', 'extralight', 'light', 'normal', 'medium', 'semibold', 'bold', 'extrabold', 'black_']
|
|
212
|
-
const fontWeights: Record<string, string> = {}
|
|
213
|
-
for (const name of weightNames) {
|
|
214
|
-
const val = (typographyModule as Record<string, any>)[name]
|
|
215
|
-
if (typeof val === 'string') {
|
|
216
|
-
fontWeights[name] = val
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
// Border radii
|
|
221
|
-
const radiusNames = ['none', 'sm', 'DEFAULT', 'md', 'lg', 'xl', '_2xl', '_3xl', 'full']
|
|
222
|
-
const radii: Record<string, string> = {}
|
|
223
|
-
for (const name of radiusNames) {
|
|
224
|
-
const val = (bordersModule as Record<string, any>)[name]
|
|
225
|
-
if (typeof val === 'string') {
|
|
226
|
-
radii[name] = val
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
// Shadows
|
|
231
|
-
const shadowNames = ['sm', 'DEFAULT', 'md', 'lg', 'xl', '_2xl', 'inner', 'none']
|
|
232
|
-
const shadows: Record<string, string> = {}
|
|
233
|
-
for (const name of shadowNames) {
|
|
234
|
-
const val = (shadowsModule as Record<string, any>)[name]
|
|
235
|
-
if (typeof val === 'string') {
|
|
236
|
-
shadows[name] = val
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
// Sizes
|
|
241
|
-
const sizeNames = ['full', 'screen', 'screenH', 'min', 'max', 'fit', 'auto']
|
|
242
|
-
const sizes: Record<string, string> = {}
|
|
243
|
-
for (const name of sizeNames) {
|
|
244
|
-
const val = (sizesModule as Record<string, any>)[name]
|
|
245
|
-
if (typeof val === 'string') {
|
|
246
|
-
sizes[name] = val
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
return {
|
|
251
|
-
colors: JSON.stringify(colors),
|
|
252
|
-
namedColors: JSON.stringify(namedColors),
|
|
253
|
-
spacing: JSON.stringify(spacing),
|
|
254
|
-
textSizes: JSON.stringify(textSizes),
|
|
255
|
-
fontWeights: JSON.stringify(fontWeights),
|
|
256
|
-
radii: JSON.stringify(radii),
|
|
257
|
-
shadows: JSON.stringify(shadows),
|
|
258
|
-
sizes: JSON.stringify(sizes),
|
|
259
|
-
defaultRadius: radii['DEFAULT'] ?? '0.25rem',
|
|
260
|
-
defaultShadow: shadows['DEFAULT'] ?? '0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)',
|
|
261
|
-
}
|
|
262
|
-
}
|
package/src/loadTheme.ts
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import type { ThemeInput } from '../index.d.ts'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Load theme data from the typewritingclass package.
|
|
5
|
+
* This dynamically imports the theme modules so values come from the TS source,
|
|
6
|
+
* not hardcoded in the compiler.
|
|
7
|
+
*/
|
|
8
|
+
export async function loadTheme(): Promise<ThemeInput> {
|
|
9
|
+
// Import all theme modules from the TS package
|
|
10
|
+
const [colorsModule, spacingModule, typographyModule, sizesModule, shadowsModule, bordersModule] =
|
|
11
|
+
await Promise.all([
|
|
12
|
+
import('typewritingclass/theme/colors'),
|
|
13
|
+
import('typewritingclass/theme'),
|
|
14
|
+
import('typewritingclass/theme/typography'),
|
|
15
|
+
import('typewritingclass/theme/sizes'),
|
|
16
|
+
import('typewritingclass/theme/shadows'),
|
|
17
|
+
import('typewritingclass/theme/borders'),
|
|
18
|
+
])
|
|
19
|
+
|
|
20
|
+
// Build color scales map
|
|
21
|
+
const colorScaleNames = [
|
|
22
|
+
'slate', 'gray', 'zinc', 'neutral', 'stone', 'red', 'orange', 'amber',
|
|
23
|
+
'yellow', 'lime', 'green', 'emerald', 'teal', 'cyan', 'sky', 'blue',
|
|
24
|
+
'indigo', 'violet', 'purple', 'fuchsia', 'pink', 'rose',
|
|
25
|
+
]
|
|
26
|
+
const colors: Record<string, Record<string, string>> = {}
|
|
27
|
+
for (const name of colorScaleNames) {
|
|
28
|
+
const scale = (colorsModule as Record<string, any>)[name]
|
|
29
|
+
if (scale && typeof scale === 'object') {
|
|
30
|
+
colors[name] = {}
|
|
31
|
+
for (const [shade, hex] of Object.entries(scale)) {
|
|
32
|
+
colors[name][String(shade)] = hex as string
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Named colors
|
|
38
|
+
const namedColors: Record<string, string> = {
|
|
39
|
+
white: colorsModule.white,
|
|
40
|
+
black: colorsModule.black,
|
|
41
|
+
transparent: colorsModule.transparent,
|
|
42
|
+
currentColor: colorsModule.currentColor,
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Spacing scale
|
|
46
|
+
const { spacing: spacingNs } = spacingModule as any
|
|
47
|
+
const spacing: Record<string, string> = {}
|
|
48
|
+
if (spacingNs && spacingNs.spacingScale) {
|
|
49
|
+
for (const [key, val] of Object.entries(spacingNs.spacingScale)) {
|
|
50
|
+
spacing[String(key)] = val as string
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Text sizes
|
|
55
|
+
const textSizeNames = ['xs', 'sm', 'base', 'lg', 'xl', '_2xl', '_3xl', '_4xl', '_5xl', '_6xl', '_7xl', '_8xl', '_9xl']
|
|
56
|
+
const textSizes: Record<string, { fontSize: string; lineHeight: string }> = {}
|
|
57
|
+
for (const name of textSizeNames) {
|
|
58
|
+
const token = (typographyModule as Record<string, any>)[name]
|
|
59
|
+
if (token && typeof token === 'object' && 'fontSize' in token) {
|
|
60
|
+
textSizes[name] = { fontSize: token.fontSize, lineHeight: token.lineHeight }
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Font weights
|
|
65
|
+
const weightNames = ['thin', 'extralight', 'light', 'normal', 'medium', 'semibold', 'bold', 'extrabold', 'black_']
|
|
66
|
+
const fontWeights: Record<string, string> = {}
|
|
67
|
+
for (const name of weightNames) {
|
|
68
|
+
const val = (typographyModule as Record<string, any>)[name]
|
|
69
|
+
if (typeof val === 'string') {
|
|
70
|
+
fontWeights[name] = val
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Border radii
|
|
75
|
+
const radiusNames = ['none', 'sm', 'DEFAULT', 'md', 'lg', 'xl', '_2xl', '_3xl', 'full']
|
|
76
|
+
const radii: Record<string, string> = {}
|
|
77
|
+
for (const name of radiusNames) {
|
|
78
|
+
const val = (bordersModule as Record<string, any>)[name]
|
|
79
|
+
if (typeof val === 'string') {
|
|
80
|
+
radii[name] = val
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Shadows
|
|
85
|
+
const shadowNames = ['sm', 'DEFAULT', 'md', 'lg', 'xl', '_2xl', 'inner', 'none']
|
|
86
|
+
const shadows: Record<string, string> = {}
|
|
87
|
+
for (const name of shadowNames) {
|
|
88
|
+
const val = (shadowsModule as Record<string, any>)[name]
|
|
89
|
+
if (typeof val === 'string') {
|
|
90
|
+
shadows[name] = val
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Sizes
|
|
95
|
+
const sizeNames = ['full', 'screen', 'screenH', 'min', 'max', 'fit', 'auto']
|
|
96
|
+
const sizes: Record<string, string> = {}
|
|
97
|
+
for (const name of sizeNames) {
|
|
98
|
+
const val = (sizesModule as Record<string, any>)[name]
|
|
99
|
+
if (typeof val === 'string') {
|
|
100
|
+
sizes[name] = val
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return {
|
|
105
|
+
colors: JSON.stringify(colors),
|
|
106
|
+
namedColors: JSON.stringify(namedColors),
|
|
107
|
+
spacing: JSON.stringify(spacing),
|
|
108
|
+
textSizes: JSON.stringify(textSizes),
|
|
109
|
+
fontWeights: JSON.stringify(fontWeights),
|
|
110
|
+
radii: JSON.stringify(radii),
|
|
111
|
+
shadows: JSON.stringify(shadows),
|
|
112
|
+
sizes: JSON.stringify(sizes),
|
|
113
|
+
defaultRadius: radii['DEFAULT'] ?? '0.25rem',
|
|
114
|
+
defaultShadow: shadows['DEFAULT'] ?? '0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)',
|
|
115
|
+
}
|
|
116
|
+
}
|