typewritingclass-compiler 0.1.0
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 +62 -0
- package/package.json +34 -0
- package/src/css.rs +32 -0
- package/src/extractor.rs +898 -0
- package/src/hash.rs +103 -0
- package/src/index.ts +262 -0
- package/src/lib.rs +143 -0
- package/src/modifiers.rs +50 -0
- package/src/style_rule.rs +72 -0
- package/src/theme.rs +86 -0
- package/src/utilities.rs +381 -0
package/README.md
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# typewritingclass-compiler
|
|
2
|
+
|
|
3
|
+
Rust-powered compiler and Vite plugin for Typewriting Class. Statically analyzes TypeScript source files, extracts CSS at build time, and replaces utility calls with generated class names — producing zero-runtime CSS output.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
bun add -d typewritingclass-compiler
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Vite Plugin
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
// vite.config.ts
|
|
15
|
+
import { defineConfig } from 'vite'
|
|
16
|
+
import twcPlugin from 'typewritingclass-compiler'
|
|
17
|
+
|
|
18
|
+
export default defineConfig({
|
|
19
|
+
plugins: [twcPlugin()],
|
|
20
|
+
})
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Then import the virtual CSS module:
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
import 'virtual:twc.css'
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Options
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
twcPlugin({
|
|
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
|
+
})
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## How it works
|
|
41
|
+
|
|
42
|
+
1. **Static analysis** — the Rust extractor scans TS/JS files for `cx()`, `when()`, and utility calls
|
|
43
|
+
2. **CSS generation** — extracted rules are compiled into deterministic class names and CSS declarations
|
|
44
|
+
3. **Code transform** — utility call sites are replaced with the generated class name strings
|
|
45
|
+
4. **Virtual module** — `virtual:twc.css` aggregates all extracted CSS, respecting `@layer` ordering
|
|
46
|
+
5. **Dynamic fallback** — values that can't be statically resolved fall back to runtime CSS custom properties
|
|
47
|
+
|
|
48
|
+
## Strict mode
|
|
49
|
+
|
|
50
|
+
Strict mode (default) requires dynamic values to be explicitly wrapped with `dynamic()`. This makes the boundary between static and runtime CSS explicit. Set `strict: false` to allow implicit dynamic values.
|
|
51
|
+
|
|
52
|
+
## Exports
|
|
53
|
+
|
|
54
|
+
| Export | Description |
|
|
55
|
+
|---|---|
|
|
56
|
+
| `default` | Vite plugin factory |
|
|
57
|
+
| `nativeTransform` | Core transform function (Rust via NAPI) |
|
|
58
|
+
| `generateCss` | CSS aggregation utility |
|
|
59
|
+
| `ThemeInput` | Theme configuration type |
|
|
60
|
+
| `TransformOutput` | Transform result type |
|
|
61
|
+
| `ExtractedRule` | Individual extracted rule type |
|
|
62
|
+
| `Diagnostic` | Compiler diagnostic type |
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "typewritingclass-compiler",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"exports": {
|
|
6
|
+
".": {
|
|
7
|
+
"types": "./src/index.ts",
|
|
8
|
+
"default": "./src/index.ts"
|
|
9
|
+
}
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"src"
|
|
13
|
+
],
|
|
14
|
+
"napi": {
|
|
15
|
+
"name": "typewritingclass-compiler-native",
|
|
16
|
+
"triples": {}
|
|
17
|
+
},
|
|
18
|
+
"peerDependencies": {
|
|
19
|
+
"vite": "^6.0.0"
|
|
20
|
+
},
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"magic-string": "^0.30.21",
|
|
23
|
+
"typewritingclass": "0.2.0"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@types/node": "^25.2.2",
|
|
27
|
+
"typescript": "^5.7.3",
|
|
28
|
+
"vite": "^6.0.0"
|
|
29
|
+
},
|
|
30
|
+
"scripts": {
|
|
31
|
+
"build:native": "napi build --release",
|
|
32
|
+
"build:native:debug": "napi build"
|
|
33
|
+
}
|
|
34
|
+
}
|
package/src/css.rs
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
use crate::style_rule::StyleRule;
|
|
2
|
+
|
|
3
|
+
/// Render a single rule to CSS text (without @layer wrapper)
|
|
4
|
+
pub fn render_rule(class_name: &str, rule: &StyleRule) -> String {
|
|
5
|
+
let decls: String = rule
|
|
6
|
+
.declarations
|
|
7
|
+
.iter()
|
|
8
|
+
.map(|(prop, val)| format!(" {}: {};", prop, val))
|
|
9
|
+
.collect::<Vec<_>>()
|
|
10
|
+
.join("\n");
|
|
11
|
+
|
|
12
|
+
let mut selector = format!(".{}", class_name);
|
|
13
|
+
for s in &rule.selectors {
|
|
14
|
+
selector.push_str(s);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
let mut css = format!("{} {{\n{}\n}}", selector, decls);
|
|
18
|
+
|
|
19
|
+
for mq in &rule.media_queries {
|
|
20
|
+
css = format!("@media {} {{\n{}\n}}", mq, css);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
css
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/// Join multiple CSS rules into a single stylesheet.
|
|
27
|
+
pub fn wrap_in_layer(rules_css: &[String]) -> String {
|
|
28
|
+
if rules_css.is_empty() {
|
|
29
|
+
return String::new();
|
|
30
|
+
}
|
|
31
|
+
rules_css.join("\n\n")
|
|
32
|
+
}
|