@ape-egg/vibe-compiler 4.0.0 → 4.1.1
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/native/vibe-compiler-darwin-arm64 +0 -0
- package/native/vibe-compiler-linux-x64 +0 -0
- package/package.json +1 -1
- package/src/Cargo.lock +1 -1
- package/src/Cargo.toml +1 -1
- package/src/compiler/compile.rs +85 -0
- package/src/config.rs +5 -0
- package/src/main.rs +7 -0
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ape-egg/vibe-compiler",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.1.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Optional Rust compiler for Vibe — pre-renders, inlines components, and optimizes iterations. The runtime never needs it.",
|
|
6
6
|
"homepage": "https://vibe.korte.kim",
|
package/src/Cargo.lock
CHANGED
package/src/Cargo.toml
CHANGED
package/src/compiler/compile.rs
CHANGED
|
@@ -62,6 +62,53 @@ pub(crate) fn atomic_write(path: &Path, contents: &str) -> std::io::Result<()> {
|
|
|
62
62
|
// Can be used as class (.vibe-fouc) or attribute ([vibe-fouc])
|
|
63
63
|
const FOUC_CLASS_OR_ATTR: &str = "vibe-fouc";
|
|
64
64
|
|
|
65
|
+
// vibe's own CSS, emitted inline into every compiled page's <head> so it
|
|
66
|
+
// applies at parse time regardless of which stylesheets the consumer links.
|
|
67
|
+
// The rules are EXTRACTED from vibe.css itself at build time — the file
|
|
68
|
+
// (shipped as a sibling package in every layout, and next to this source in
|
|
69
|
+
// the repo) is the single source of truth; no CSS text lives here to drift.
|
|
70
|
+
// Split on the optional marker into two sheets:
|
|
71
|
+
// - the cover half is load-bearing and always emitted: [vibe-staged] gates
|
|
72
|
+
// route/key remount staging on every page, and the fouc/animation rules
|
|
73
|
+
// cover pages that keep the marker (--fouc-as-is);
|
|
74
|
+
// - the layout half is vibe's base styling (layout-transparent component
|
|
75
|
+
// wrappers), skipped by disableVibeCss.
|
|
76
|
+
// Comments and newlines are stripped at emission: style content survives
|
|
77
|
+
// minification verbatim, so the emitted form must already be newline-free.
|
|
78
|
+
const VIBE_CSS_FILE: &str = include_str!("../../../vibe/vibe.css");
|
|
79
|
+
// The marker literal is the one string shared with the file (and the vite
|
|
80
|
+
// plugin) — scripts/check-release.js holds it in lockstep.
|
|
81
|
+
const VIBE_CSS_OPTIONAL_MARKER: &str =
|
|
82
|
+
"/* vibe:optional — everything below is skipped by disableVibeCss */";
|
|
83
|
+
|
|
84
|
+
fn strip_css_comments(css: &str) -> String {
|
|
85
|
+
let mut out = String::with_capacity(css.len());
|
|
86
|
+
let mut rest = css;
|
|
87
|
+
while let Some(start) = rest.find("/*") {
|
|
88
|
+
out.push_str(&rest[..start]);
|
|
89
|
+
rest = match rest[start..].find("*/") {
|
|
90
|
+
Some(end) => &rest[start + end + 2..],
|
|
91
|
+
None => "",
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
out.push_str(rest);
|
|
95
|
+
out
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
fn single_line_css(css: &str) -> String {
|
|
99
|
+
strip_css_comments(css)
|
|
100
|
+
.split_whitespace()
|
|
101
|
+
.collect::<Vec<_>>()
|
|
102
|
+
.join(" ")
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
fn vibe_css_sheets() -> (String, String) {
|
|
106
|
+
let (cover, layout) = VIBE_CSS_FILE
|
|
107
|
+
.split_once(VIBE_CSS_OPTIONAL_MARKER)
|
|
108
|
+
.expect("vibe.css lost its optional marker");
|
|
109
|
+
(single_line_css(cover), single_line_css(layout))
|
|
110
|
+
}
|
|
111
|
+
|
|
65
112
|
const MIRROR_EXTENSIONS: &[&str] = &[
|
|
66
113
|
"css", "js",
|
|
67
114
|
// Fonts
|
|
@@ -246,6 +293,34 @@ fn remove_fouc_prevention(html: String) -> String {
|
|
|
246
293
|
result
|
|
247
294
|
}
|
|
248
295
|
|
|
296
|
+
/// Inject vibe's CSS right after <head> — ahead of consumer stylesheets, so
|
|
297
|
+
/// their equal-specificity overrides still win the cascade. Idempotent
|
|
298
|
+
/// (recompiles and already-covered sources pass through); fragments without a
|
|
299
|
+
/// <head> are not pages and are left untouched. The cover sheet always emits;
|
|
300
|
+
/// the layout sheet honors disableVibeCss.
|
|
301
|
+
pub fn inject_vibe_css(html: String, disable_vibe_css: bool) -> String {
|
|
302
|
+
if html.contains("data-vibe-cover") {
|
|
303
|
+
return html;
|
|
304
|
+
}
|
|
305
|
+
let open_end = match html.find("<head") {
|
|
306
|
+
Some(at) => match html[at..].find('>') {
|
|
307
|
+
Some(close) => at + close + 1,
|
|
308
|
+
None => return html,
|
|
309
|
+
},
|
|
310
|
+
None => return html,
|
|
311
|
+
};
|
|
312
|
+
let (cover_css, layout_css) = vibe_css_sheets();
|
|
313
|
+
let mut style = format!("<style data-vibe-cover>{}</style>", cover_css);
|
|
314
|
+
if !disable_vibe_css {
|
|
315
|
+
style.push_str(&format!("<style data-vibe-css>{}</style>", layout_css));
|
|
316
|
+
}
|
|
317
|
+
let mut result = String::with_capacity(html.len() + style.len());
|
|
318
|
+
result.push_str(&html[..open_end]);
|
|
319
|
+
result.push_str(&style);
|
|
320
|
+
result.push_str(&html[open_end..]);
|
|
321
|
+
result
|
|
322
|
+
}
|
|
323
|
+
|
|
249
324
|
#[derive(Error, Debug)]
|
|
250
325
|
pub enum CompileError {
|
|
251
326
|
#[error("Source directory not found: {0}")]
|
|
@@ -1454,6 +1529,9 @@ impl Compiler {
|
|
|
1454
1529
|
output = remove_fouc_prevention(output);
|
|
1455
1530
|
}
|
|
1456
1531
|
|
|
1532
|
+
// vibe's CSS rides every compiled page, present at parse time
|
|
1533
|
+
output = inject_vibe_css(output, self.config.disable_vibe_css);
|
|
1534
|
+
|
|
1457
1535
|
// Write to output
|
|
1458
1536
|
let output_path = self.get_output_path(path, relative_path)?;
|
|
1459
1537
|
atomic_write(&output_path, &output).map_err(|e| CompileError::WriteError {
|
|
@@ -1739,6 +1817,9 @@ impl Compiler {
|
|
|
1739
1817
|
} else {
|
|
1740
1818
|
shell_processed
|
|
1741
1819
|
};
|
|
1820
|
+
// Same sheets the page pipeline emits — the shell serves every route,
|
|
1821
|
+
// and [vibe-staged] gates its remount staging.
|
|
1822
|
+
let shell_html = inject_vibe_css(shell_html, self.config.disable_vibe_css);
|
|
1742
1823
|
let shell_path = self.config.output.join("index.html");
|
|
1743
1824
|
atomic_write(&shell_path, &shell_html).map_err(|e| CompileError::WriteError {
|
|
1744
1825
|
path: shell_path.display().to_string(),
|
|
@@ -2825,6 +2906,7 @@ mod tests {
|
|
|
2825
2906
|
iterations_as_is: false,
|
|
2826
2907
|
no_clean: false,
|
|
2827
2908
|
fouc_as_is: false,
|
|
2909
|
+
disable_vibe_css: false,
|
|
2828
2910
|
spa: true,
|
|
2829
2911
|
working_dir: dir.clone(),
|
|
2830
2912
|
};
|
|
@@ -2913,6 +2995,7 @@ mod tests {
|
|
|
2913
2995
|
iterations_as_is: false,
|
|
2914
2996
|
no_clean: false,
|
|
2915
2997
|
fouc_as_is: false,
|
|
2998
|
+
disable_vibe_css: false,
|
|
2916
2999
|
spa: true,
|
|
2917
3000
|
working_dir: dir.clone(),
|
|
2918
3001
|
};
|
|
@@ -3025,6 +3108,7 @@ mod tests {
|
|
|
3025
3108
|
iterations_as_is: false,
|
|
3026
3109
|
no_clean: false,
|
|
3027
3110
|
fouc_as_is: false,
|
|
3111
|
+
disable_vibe_css: false,
|
|
3028
3112
|
spa: true,
|
|
3029
3113
|
working_dir: dir.clone(),
|
|
3030
3114
|
};
|
|
@@ -3096,6 +3180,7 @@ mod tests {
|
|
|
3096
3180
|
iterations_as_is: false,
|
|
3097
3181
|
no_clean: false,
|
|
3098
3182
|
fouc_as_is: false,
|
|
3183
|
+
disable_vibe_css: false,
|
|
3099
3184
|
spa: false,
|
|
3100
3185
|
working_dir: dir.clone(),
|
|
3101
3186
|
};
|
package/src/config.rs
CHANGED
|
@@ -48,6 +48,8 @@ pub struct VibeCompilerConfig {
|
|
|
48
48
|
pub no_clean: bool,
|
|
49
49
|
#[serde(default)]
|
|
50
50
|
pub fouc_as_is: bool,
|
|
51
|
+
#[serde(default)]
|
|
52
|
+
pub disable_vibe_css: bool,
|
|
51
53
|
#[serde(default, deserialize_with = "deserialize_spa")]
|
|
52
54
|
pub spa: bool,
|
|
53
55
|
}
|
|
@@ -121,6 +123,7 @@ impl Default for VibeCompilerConfig {
|
|
|
121
123
|
iterations_as_is: false,
|
|
122
124
|
no_clean: false,
|
|
123
125
|
fouc_as_is: false,
|
|
126
|
+
disable_vibe_css: false,
|
|
124
127
|
spa: false,
|
|
125
128
|
}
|
|
126
129
|
}
|
|
@@ -147,6 +150,7 @@ pub struct Config {
|
|
|
147
150
|
pub iterations_as_is: bool,
|
|
148
151
|
pub no_clean: bool,
|
|
149
152
|
pub fouc_as_is: bool,
|
|
153
|
+
pub disable_vibe_css: bool,
|
|
150
154
|
pub spa: bool,
|
|
151
155
|
pub working_dir: PathBuf,
|
|
152
156
|
}
|
|
@@ -209,6 +213,7 @@ impl Config {
|
|
|
209
213
|
iterations_as_is: config.iterations_as_is,
|
|
210
214
|
no_clean: config.no_clean,
|
|
211
215
|
fouc_as_is: config.fouc_as_is,
|
|
216
|
+
disable_vibe_css: config.disable_vibe_css,
|
|
212
217
|
spa: config.spa,
|
|
213
218
|
working_dir,
|
|
214
219
|
}
|
package/src/main.rs
CHANGED
|
@@ -89,6 +89,10 @@ struct Args {
|
|
|
89
89
|
#[arg(long, name = "fouc-as-is")]
|
|
90
90
|
fouc_as_is: bool,
|
|
91
91
|
|
|
92
|
+
/// Skip emitting vibe's optional layout CSS (the cover rules always emit)
|
|
93
|
+
#[arg(long, name = "disable-vibe-css")]
|
|
94
|
+
disable_vibe_css: bool,
|
|
95
|
+
|
|
92
96
|
/// Compile the pages tree to SPA output: fragments + route table + shell
|
|
93
97
|
#[arg(long)]
|
|
94
98
|
spa: bool,
|
|
@@ -171,6 +175,9 @@ fn main() {
|
|
|
171
175
|
if args.fouc_as_is {
|
|
172
176
|
config.fouc_as_is = true;
|
|
173
177
|
}
|
|
178
|
+
if args.disable_vibe_css {
|
|
179
|
+
config.disable_vibe_css = true;
|
|
180
|
+
}
|
|
174
181
|
if args.spa {
|
|
175
182
|
overrides.spa = !original_spa;
|
|
176
183
|
config.spa = true;
|