lightningcss 0.1.0-arm-linux-gnu
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.
- checksums.yaml +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +231 -0
- data/ext/lightningcss/extconf.rb +112 -0
- data/ext/lightningcss/include/lightningcss.h +28 -0
- data/ext/lightningcss/lightningcss.c +101 -0
- data/lib/lightningcss/3.2/lightningcss.so +0 -0
- data/lib/lightningcss/3.3/lightningcss.so +0 -0
- data/lib/lightningcss/3.4/lightningcss.so +0 -0
- data/lib/lightningcss/4.0/lightningcss.so +0 -0
- data/lib/lightningcss/backend.rb +36 -0
- data/lib/lightningcss/errors.rb +8 -0
- data/lib/lightningcss/options.rb +82 -0
- data/lib/lightningcss/result.rb +57 -0
- data/lib/lightningcss/transformer.rb +56 -0
- data/lib/lightningcss/version.rb +5 -0
- data/lib/lightningcss.rb +60 -0
- data/licenses/README.md +12 -0
- data/licenses/lightningcss-MPL-2.0.txt +373 -0
- data/lightningcss.gemspec +43 -0
- data/rust/Cargo.lock +1283 -0
- data/rust/Cargo.toml +24 -0
- data/rust/build.rs +15 -0
- data/rust/cbindgen.toml +23 -0
- data/rust/rustfmt.toml +3 -0
- data/rust/src/lib.rs +308 -0
- data/rust/src/options.rs +98 -0
- data/rust/src/scope.rs +63 -0
- data/sig/lightningcss/backend.rbs +26 -0
- data/sig/lightningcss/errors.rbs +15 -0
- data/sig/lightningcss/options.rbs +38 -0
- data/sig/lightningcss/result.rbs +34 -0
- data/sig/lightningcss/transformer.rbs +39 -0
- data/sig/lightningcss/types.rbs +26 -0
- data/sig/lightningcss/version.rbs +5 -0
- data/sig/lightningcss.rbs +31 -0
- metadata +86 -0
data/rust/Cargo.toml
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
[workspace]
|
|
2
|
+
|
|
3
|
+
[package]
|
|
4
|
+
name = "lightningcss-ffi"
|
|
5
|
+
version = "0.1.0"
|
|
6
|
+
edition = "2021"
|
|
7
|
+
authors = ["Marco Roth <marco.roth@intergga.ch>"]
|
|
8
|
+
description = "C FFI bindings for Lightning CSS, used by the lightningcss gem"
|
|
9
|
+
license = "MIT"
|
|
10
|
+
repository = "https://github.com/marcoroth/lightningcss-ruby"
|
|
11
|
+
publish = false
|
|
12
|
+
|
|
13
|
+
[lib]
|
|
14
|
+
name = "lightningcss_ffi"
|
|
15
|
+
path = "src/lib.rs"
|
|
16
|
+
crate-type = ["cdylib", "staticlib", "rlib"]
|
|
17
|
+
|
|
18
|
+
[dependencies]
|
|
19
|
+
lightningcss = { version = "1.0.0-alpha.68", features = ["visitor"] }
|
|
20
|
+
serde = { version = "1", features = ["derive"] }
|
|
21
|
+
serde_json = "1"
|
|
22
|
+
|
|
23
|
+
[build-dependencies]
|
|
24
|
+
cbindgen = "0.28"
|
data/rust/build.rs
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
use std::env;
|
|
2
|
+
use std::path::PathBuf;
|
|
3
|
+
|
|
4
|
+
fn main() {
|
|
5
|
+
let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
|
|
6
|
+
let header_path = PathBuf::from(&crate_dir).join("../ext/lightningcss/include/lightningcss.h");
|
|
7
|
+
|
|
8
|
+
if let Ok(bindings) = cbindgen::generate(&crate_dir) {
|
|
9
|
+
if let Some(parent) = header_path.parent() {
|
|
10
|
+
let _ = std::fs::create_dir_all(parent);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
bindings.write_to_file(&header_path);
|
|
14
|
+
}
|
|
15
|
+
}
|
data/rust/cbindgen.toml
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
language = "C"
|
|
2
|
+
header = """/* Generated by cbindgen — do not edit manually */
|
|
3
|
+
|
|
4
|
+
#include <stdbool.h>
|
|
5
|
+
#include <stdint.h>
|
|
6
|
+
#include <stddef.h>"""
|
|
7
|
+
include_guard = "LIGHTNINGCSS_H"
|
|
8
|
+
no_includes = true
|
|
9
|
+
|
|
10
|
+
[export]
|
|
11
|
+
include = [
|
|
12
|
+
"LightningCssResult",
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
[enum]
|
|
16
|
+
rename_variants = "ScreamingSnakeCase"
|
|
17
|
+
prefix_with_name = true
|
|
18
|
+
|
|
19
|
+
[fn]
|
|
20
|
+
sort_by = "None"
|
|
21
|
+
|
|
22
|
+
[parse]
|
|
23
|
+
parse_deps = false
|
data/rust/rustfmt.toml
ADDED
data/rust/src/lib.rs
ADDED
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
//! C FFI bindings for Lightning CSS.
|
|
2
|
+
//!
|
|
3
|
+
//! # Safety
|
|
4
|
+
//!
|
|
5
|
+
//! Every function here requires that pointer arguments are valid, NUL-terminated C strings unless
|
|
6
|
+
//! documented as nullable. Returned pointers are owned by the caller and must be released with
|
|
7
|
+
//! `lightningcss_string_free` or `lightningcss_result_free`.
|
|
8
|
+
|
|
9
|
+
#![allow(clippy::missing_safety_doc)]
|
|
10
|
+
|
|
11
|
+
mod options;
|
|
12
|
+
mod scope;
|
|
13
|
+
|
|
14
|
+
use std::collections::HashMap;
|
|
15
|
+
use std::ffi::{CStr, CString};
|
|
16
|
+
use std::os::raw::c_char;
|
|
17
|
+
use std::ptr;
|
|
18
|
+
use std::sync::{Arc, RwLock};
|
|
19
|
+
|
|
20
|
+
use lightningcss::bundler::{Bundler, FileProvider};
|
|
21
|
+
use lightningcss::stylesheet::{MinifyOptions, ParserOptions, PrinterOptions, StyleAttribute, StyleSheet};
|
|
22
|
+
use lightningcss::visitor::Visit;
|
|
23
|
+
|
|
24
|
+
use crate::options::{TransformOptions, TransformResult};
|
|
25
|
+
use crate::scope::Scoper;
|
|
26
|
+
|
|
27
|
+
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
|
|
28
|
+
|
|
29
|
+
#[repr(C)]
|
|
30
|
+
pub struct LightningCssResult {
|
|
31
|
+
pub value: *mut c_char,
|
|
32
|
+
pub error: *mut c_char,
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
impl LightningCssResult {
|
|
36
|
+
fn ok(value: String) -> Self {
|
|
37
|
+
Self {
|
|
38
|
+
value: into_c_string(value),
|
|
39
|
+
error: ptr::null_mut(),
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
fn err(message: impl AsRef<str>) -> Self {
|
|
44
|
+
Self {
|
|
45
|
+
value: ptr::null_mut(),
|
|
46
|
+
error: into_c_string(message.as_ref()),
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
fn into_c_string(value: impl Into<Vec<u8>>) -> *mut c_char {
|
|
52
|
+
CString::new(value).unwrap_or_default().into_raw()
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
unsafe fn borrow_str<'a>(pointer: *const c_char, label: &str) -> Result<&'a str, String> {
|
|
56
|
+
if pointer.is_null() {
|
|
57
|
+
return Err(format!("{label} is null"));
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
CStr::from_ptr(pointer)
|
|
61
|
+
.to_str()
|
|
62
|
+
.map_err(|error| format!("Invalid UTF-8 in {label}: {error}"))
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
unsafe fn borrow_options(pointer: *const c_char) -> Result<TransformOptions, String> {
|
|
66
|
+
if pointer.is_null() {
|
|
67
|
+
return Ok(TransformOptions::default());
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
let json = borrow_str(pointer, "options")?;
|
|
71
|
+
|
|
72
|
+
if json.trim().is_empty() {
|
|
73
|
+
return Ok(TransformOptions::default());
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
serde_json::from_str(json).map_err(|error| format!("Invalid options: {error}"))
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
fn transform_source(code: &str, options: &TransformOptions) -> Result<TransformResult, String> {
|
|
80
|
+
let filename = options.filename.clone().unwrap_or_default();
|
|
81
|
+
let css_modules = match &options.css_modules {
|
|
82
|
+
Some(modules) => Some(modules.to_config()?),
|
|
83
|
+
None => None,
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
let collected = Arc::new(RwLock::new(Vec::new()));
|
|
87
|
+
|
|
88
|
+
let parser_options = ParserOptions {
|
|
89
|
+
filename: filename.clone(),
|
|
90
|
+
css_modules,
|
|
91
|
+
error_recovery: options.error_recovery,
|
|
92
|
+
warnings: Some(collected.clone()),
|
|
93
|
+
..ParserOptions::default()
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
let mut stylesheet = StyleSheet::parse(code, parser_options).map_err(|error| error.to_string())?;
|
|
97
|
+
|
|
98
|
+
if let Some(fragment) = &options.scope {
|
|
99
|
+
let mut scoper = Scoper::parse(fragment)?;
|
|
100
|
+
|
|
101
|
+
stylesheet
|
|
102
|
+
.visit(&mut scoper)
|
|
103
|
+
.map_err(|error| format!("Failed to scope stylesheet: {error:?}"))?;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
let targets = options.to_targets();
|
|
107
|
+
|
|
108
|
+
if options.minify {
|
|
109
|
+
stylesheet
|
|
110
|
+
.minify(MinifyOptions {
|
|
111
|
+
targets,
|
|
112
|
+
..MinifyOptions::default()
|
|
113
|
+
})
|
|
114
|
+
.map_err(|error| format!("Failed to minify: {error}"))?;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
let printed = stylesheet
|
|
118
|
+
.to_css(PrinterOptions {
|
|
119
|
+
minify: options.minify,
|
|
120
|
+
source_map: None,
|
|
121
|
+
project_root: None,
|
|
122
|
+
targets,
|
|
123
|
+
analyze_dependencies: None,
|
|
124
|
+
pseudo_classes: None,
|
|
125
|
+
})
|
|
126
|
+
.map_err(|error| format!("Failed to print: {error}"))?;
|
|
127
|
+
|
|
128
|
+
let exports = printed.exports.map(|exports| {
|
|
129
|
+
exports
|
|
130
|
+
.into_iter()
|
|
131
|
+
.map(|(local, export)| (local, export.name))
|
|
132
|
+
.collect::<HashMap<String, String>>()
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
let warnings = collected
|
|
136
|
+
.read()
|
|
137
|
+
.map(|warnings| warnings.iter().map(|warning| warning.to_string()).collect())
|
|
138
|
+
.unwrap_or_default();
|
|
139
|
+
|
|
140
|
+
Ok(TransformResult {
|
|
141
|
+
code: printed.code,
|
|
142
|
+
exports,
|
|
143
|
+
warnings,
|
|
144
|
+
})
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
fn bundle_source(path: &str, options: &TransformOptions) -> Result<TransformResult, String> {
|
|
148
|
+
let css_modules = match &options.css_modules {
|
|
149
|
+
Some(modules) => Some(modules.to_config()?),
|
|
150
|
+
None => None,
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
let parser_options = ParserOptions {
|
|
154
|
+
css_modules,
|
|
155
|
+
error_recovery: options.error_recovery,
|
|
156
|
+
..ParserOptions::default()
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
let provider = FileProvider::new();
|
|
160
|
+
let mut bundler = Bundler::new(&provider, None, parser_options);
|
|
161
|
+
|
|
162
|
+
let mut stylesheet = bundler
|
|
163
|
+
.bundle(std::path::Path::new(path))
|
|
164
|
+
.map_err(|error| error.to_string())?;
|
|
165
|
+
|
|
166
|
+
if let Some(fragment) = &options.scope {
|
|
167
|
+
let mut scoper = Scoper::parse(fragment)?;
|
|
168
|
+
|
|
169
|
+
stylesheet
|
|
170
|
+
.visit(&mut scoper)
|
|
171
|
+
.map_err(|error| format!("Failed to scope stylesheet: {error:?}"))?;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
let targets = options.to_targets();
|
|
175
|
+
|
|
176
|
+
if options.minify {
|
|
177
|
+
stylesheet
|
|
178
|
+
.minify(MinifyOptions {
|
|
179
|
+
targets,
|
|
180
|
+
..MinifyOptions::default()
|
|
181
|
+
})
|
|
182
|
+
.map_err(|error| format!("Failed to minify: {error}"))?;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
let printed = stylesheet
|
|
186
|
+
.to_css(PrinterOptions {
|
|
187
|
+
minify: options.minify,
|
|
188
|
+
targets,
|
|
189
|
+
..PrinterOptions::default()
|
|
190
|
+
})
|
|
191
|
+
.map_err(|error| format!("Failed to print: {error}"))?;
|
|
192
|
+
|
|
193
|
+
Ok(TransformResult {
|
|
194
|
+
code: printed.code,
|
|
195
|
+
exports: None,
|
|
196
|
+
warnings: Vec::new(),
|
|
197
|
+
})
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
fn transform_attribute(code: &str, options: &TransformOptions) -> Result<TransformResult, String> {
|
|
201
|
+
let parser_options = ParserOptions {
|
|
202
|
+
filename: options.filename.clone().unwrap_or_default(),
|
|
203
|
+
error_recovery: options.error_recovery,
|
|
204
|
+
..ParserOptions::default()
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
let mut attribute = StyleAttribute::parse(code, parser_options).map_err(|error| error.to_string())?;
|
|
208
|
+
|
|
209
|
+
let targets = options.to_targets();
|
|
210
|
+
|
|
211
|
+
attribute.minify(MinifyOptions {
|
|
212
|
+
targets,
|
|
213
|
+
..MinifyOptions::default()
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
let printed = attribute
|
|
217
|
+
.to_css(PrinterOptions {
|
|
218
|
+
minify: options.minify,
|
|
219
|
+
targets,
|
|
220
|
+
..PrinterOptions::default()
|
|
221
|
+
})
|
|
222
|
+
.map_err(|error| format!("Failed to print: {error}"))?;
|
|
223
|
+
|
|
224
|
+
Ok(TransformResult {
|
|
225
|
+
code: printed.code,
|
|
226
|
+
exports: None,
|
|
227
|
+
warnings: Vec::new(),
|
|
228
|
+
})
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
fn to_result(outcome: Result<TransformResult, String>) -> LightningCssResult {
|
|
232
|
+
match outcome {
|
|
233
|
+
Ok(result) => match serde_json::to_string(&result) {
|
|
234
|
+
Ok(json) => LightningCssResult::ok(json),
|
|
235
|
+
Err(error) => LightningCssResult::err(format!("Failed to serialize result: {error}")),
|
|
236
|
+
},
|
|
237
|
+
Err(message) => LightningCssResult::err(message),
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
#[no_mangle]
|
|
242
|
+
pub unsafe extern "C" fn lightningcss_transform(
|
|
243
|
+
code: *const c_char,
|
|
244
|
+
options_json: *const c_char,
|
|
245
|
+
) -> LightningCssResult {
|
|
246
|
+
let code = match borrow_str(code, "code") {
|
|
247
|
+
Ok(code) => code,
|
|
248
|
+
Err(message) => return LightningCssResult::err(message),
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
let options = match borrow_options(options_json) {
|
|
252
|
+
Ok(options) => options,
|
|
253
|
+
Err(message) => return LightningCssResult::err(message),
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
to_result(transform_source(code, &options))
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
#[no_mangle]
|
|
260
|
+
pub unsafe extern "C" fn lightningcss_transform_style_attribute(
|
|
261
|
+
code: *const c_char,
|
|
262
|
+
options_json: *const c_char,
|
|
263
|
+
) -> LightningCssResult {
|
|
264
|
+
let code = match borrow_str(code, "code") {
|
|
265
|
+
Ok(code) => code,
|
|
266
|
+
Err(message) => return LightningCssResult::err(message),
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
let options = match borrow_options(options_json) {
|
|
270
|
+
Ok(options) => options,
|
|
271
|
+
Err(message) => return LightningCssResult::err(message),
|
|
272
|
+
};
|
|
273
|
+
|
|
274
|
+
to_result(transform_attribute(code, &options))
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
#[no_mangle]
|
|
278
|
+
pub unsafe extern "C" fn lightningcss_bundle(path: *const c_char, options_json: *const c_char) -> LightningCssResult {
|
|
279
|
+
let path = match borrow_str(path, "path") {
|
|
280
|
+
Ok(path) => path,
|
|
281
|
+
Err(message) => return LightningCssResult::err(message),
|
|
282
|
+
};
|
|
283
|
+
|
|
284
|
+
let options = match borrow_options(options_json) {
|
|
285
|
+
Ok(options) => options,
|
|
286
|
+
Err(message) => return LightningCssResult::err(message),
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
to_result(bundle_source(path, &options))
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
#[no_mangle]
|
|
293
|
+
pub unsafe extern "C" fn lightningcss_version() -> *mut c_char {
|
|
294
|
+
into_c_string(VERSION)
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
#[no_mangle]
|
|
298
|
+
pub unsafe extern "C" fn lightningcss_string_free(value: *mut c_char) {
|
|
299
|
+
if !value.is_null() {
|
|
300
|
+
drop(CString::from_raw(value));
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
#[no_mangle]
|
|
305
|
+
pub unsafe extern "C" fn lightningcss_result_free(result: LightningCssResult) {
|
|
306
|
+
lightningcss_string_free(result.value);
|
|
307
|
+
lightningcss_string_free(result.error);
|
|
308
|
+
}
|
data/rust/src/options.rs
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
use std::collections::HashMap;
|
|
2
|
+
|
|
3
|
+
use lightningcss::css_modules::{Config as CssModulesConfig, Pattern};
|
|
4
|
+
use lightningcss::targets::{Browsers, Targets};
|
|
5
|
+
use serde::{Deserialize, Serialize};
|
|
6
|
+
|
|
7
|
+
#[derive(Debug, Default, Deserialize)]
|
|
8
|
+
#[serde(default, deny_unknown_fields)]
|
|
9
|
+
pub struct TransformOptions {
|
|
10
|
+
pub filename: Option<String>,
|
|
11
|
+
pub minify: bool,
|
|
12
|
+
pub error_recovery: bool,
|
|
13
|
+
pub targets: Option<HashMap<String, u32>>,
|
|
14
|
+
pub css_modules: Option<CssModulesOptions>,
|
|
15
|
+
pub scope: Option<String>,
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
#[derive(Debug, Deserialize)]
|
|
19
|
+
#[serde(default, deny_unknown_fields)]
|
|
20
|
+
pub struct CssModulesOptions {
|
|
21
|
+
pub pattern: Option<String>,
|
|
22
|
+
pub dashed_idents: bool,
|
|
23
|
+
pub animation: bool,
|
|
24
|
+
pub grid: bool,
|
|
25
|
+
pub container: bool,
|
|
26
|
+
pub custom_idents: bool,
|
|
27
|
+
pub pure: bool,
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
impl Default for CssModulesOptions {
|
|
31
|
+
fn default() -> Self {
|
|
32
|
+
Self {
|
|
33
|
+
pattern: None,
|
|
34
|
+
dashed_idents: false,
|
|
35
|
+
animation: true,
|
|
36
|
+
grid: true,
|
|
37
|
+
container: true,
|
|
38
|
+
custom_idents: true,
|
|
39
|
+
pure: false,
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
impl CssModulesOptions {
|
|
45
|
+
pub fn to_config(&self) -> Result<CssModulesConfig, String> {
|
|
46
|
+
let pattern = match &self.pattern {
|
|
47
|
+
Some(pattern) => Pattern::parse(pattern).map_err(|_| format!("Invalid CSS modules pattern {pattern:?}"))?,
|
|
48
|
+
None => Pattern::default(),
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
Ok(CssModulesConfig {
|
|
52
|
+
pattern,
|
|
53
|
+
dashed_idents: self.dashed_idents,
|
|
54
|
+
animation: self.animation,
|
|
55
|
+
grid: self.grid,
|
|
56
|
+
container: self.container,
|
|
57
|
+
custom_idents: self.custom_idents,
|
|
58
|
+
pure: self.pure,
|
|
59
|
+
})
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
impl TransformOptions {
|
|
64
|
+
pub fn to_targets(&self) -> Targets {
|
|
65
|
+
let Some(versions) = &self.targets else {
|
|
66
|
+
return Targets::default();
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
let mut browsers = Browsers::default();
|
|
70
|
+
|
|
71
|
+
for (name, version) in versions {
|
|
72
|
+
let encoded = Some(version << 16);
|
|
73
|
+
|
|
74
|
+
match name.as_str() {
|
|
75
|
+
"android" => browsers.android = encoded,
|
|
76
|
+
"chrome" => browsers.chrome = encoded,
|
|
77
|
+
"edge" => browsers.edge = encoded,
|
|
78
|
+
"firefox" => browsers.firefox = encoded,
|
|
79
|
+
"ie" => browsers.ie = encoded,
|
|
80
|
+
"ios_saf" | "ios" => browsers.ios_saf = encoded,
|
|
81
|
+
"opera" => browsers.opera = encoded,
|
|
82
|
+
"safari" => browsers.safari = encoded,
|
|
83
|
+
"samsung" => browsers.samsung = encoded,
|
|
84
|
+
_ => {}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
Targets::from(browsers)
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
#[derive(Debug, Serialize)]
|
|
93
|
+
pub struct TransformResult {
|
|
94
|
+
pub code: String,
|
|
95
|
+
#[serde(skip_serializing_if = "Option::is_none")]
|
|
96
|
+
pub exports: Option<HashMap<String, String>>,
|
|
97
|
+
pub warnings: Vec<String>,
|
|
98
|
+
}
|
data/rust/src/scope.rs
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
//! Confining a stylesheet's selectors to a scope.
|
|
2
|
+
//!
|
|
3
|
+
//! The scope is given as a selector fragment, which is appended to what each rule already matches.
|
|
4
|
+
//! `parcel_selectors` stores a selector in reverse match order, so `Selector::append` lands the
|
|
5
|
+
//! fragment in the last compound and before any pseudo-element, which is where a scope belongs:
|
|
6
|
+
//!
|
|
7
|
+
//! .card .title -> .card .title[data-herb-scope-abc]
|
|
8
|
+
//! .item::before -> .item[data-herb-scope-abc]::before
|
|
9
|
+
//!
|
|
10
|
+
//! A fragment is anything that parses as one compound selector, so an attribute and a `:where()`
|
|
11
|
+
//! carrying its own alternatives are both expressible.
|
|
12
|
+
|
|
13
|
+
use std::convert::Infallible;
|
|
14
|
+
|
|
15
|
+
use lightningcss::selector::{Component, Selector, SelectorList};
|
|
16
|
+
use lightningcss::stylesheet::ParserOptions;
|
|
17
|
+
use lightningcss::traits::ParseWithOptions;
|
|
18
|
+
use lightningcss::visit_types;
|
|
19
|
+
use lightningcss::visitor::{VisitTypes, Visitor};
|
|
20
|
+
|
|
21
|
+
pub struct Scoper<'i> {
|
|
22
|
+
components: Vec<Component<'i>>,
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
impl<'i> Scoper<'i> {
|
|
26
|
+
pub fn parse(fragment: &'i str) -> Result<Self, String> {
|
|
27
|
+
let list = SelectorList::parse_string_with_options(fragment, ParserOptions::default()).map_err(|error| {
|
|
28
|
+
format!(
|
|
29
|
+
"Invalid scope selector {fragment:?} at :{}:{}",
|
|
30
|
+
error.location.line, error.location.column
|
|
31
|
+
)
|
|
32
|
+
})?;
|
|
33
|
+
|
|
34
|
+
let selector = list
|
|
35
|
+
.0
|
|
36
|
+
.first()
|
|
37
|
+
.ok_or_else(|| format!("Scope selector {fragment:?} is empty"))?;
|
|
38
|
+
|
|
39
|
+
if list.0.len() > 1 {
|
|
40
|
+
return Err(format!("Scope selector {fragment:?} has to be a single selector"));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
Ok(Self {
|
|
44
|
+
components: selector.iter_raw_match_order().cloned().collect(),
|
|
45
|
+
})
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
impl<'i> Visitor<'i> for Scoper<'i> {
|
|
50
|
+
type Error = Infallible;
|
|
51
|
+
|
|
52
|
+
fn visit_types(&self) -> VisitTypes {
|
|
53
|
+
visit_types!(SELECTORS)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
fn visit_selector(&mut self, selector: &mut Selector<'i>) -> Result<(), Self::Error> {
|
|
57
|
+
for component in &self.components {
|
|
58
|
+
selector.append(component.clone());
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
Ok(())
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Generated from lib/lightningcss/backend.rb with RBS::Inline
|
|
2
|
+
|
|
3
|
+
module LightningCSS
|
|
4
|
+
module Backend
|
|
5
|
+
module Unavailable
|
|
6
|
+
# : (String, String) -> String
|
|
7
|
+
def transform: (String, String) -> String
|
|
8
|
+
|
|
9
|
+
# : (String, String) -> String
|
|
10
|
+
def transform_style_attribute: (String, String) -> String
|
|
11
|
+
|
|
12
|
+
# : (String, String) -> String
|
|
13
|
+
def bundle: (String, String) -> String
|
|
14
|
+
|
|
15
|
+
# : () -> String
|
|
16
|
+
def version: () -> String
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
# : (Symbol?) -> bot
|
|
21
|
+
def unavailable: (Symbol?) -> bot
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
extend Unavailable
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Generated from lib/lightningcss/options.rb with RBS::Inline
|
|
2
|
+
|
|
3
|
+
module LightningCSS
|
|
4
|
+
# The options a call was given, on their way to the native library.
|
|
5
|
+
#
|
|
6
|
+
# Lightning CSS reads them as JSON, so this is where a Ruby hash becomes one, and where an option
|
|
7
|
+
# nobody knows is refused. Refusing early is the point: an option the native side does not read
|
|
8
|
+
# would otherwise be accepted and quietly do nothing.
|
|
9
|
+
#
|
|
10
|
+
# LightningCSS::Options.new(minify: true).to_json #=> "{\"minify\":true}"
|
|
11
|
+
class Options
|
|
12
|
+
KNOWN: Array[Symbol]
|
|
13
|
+
|
|
14
|
+
STYLE_ATTRIBUTE: Array[Symbol]
|
|
15
|
+
|
|
16
|
+
attr_reader to_h: Hash[Symbol, untyped]
|
|
17
|
+
|
|
18
|
+
# : (Hash[Symbol, untyped], ?allowed: Array[Symbol], ?subject: String) -> String
|
|
19
|
+
def self.serialize: (Hash[Symbol, untyped], ?allowed: Array[Symbol], ?subject: String) -> String
|
|
20
|
+
|
|
21
|
+
# : (?allowed: Array[Symbol], ?subject: String, **untyped) -> void
|
|
22
|
+
def initialize: (?allowed: Array[Symbol], ?subject: String, **untyped) -> void
|
|
23
|
+
|
|
24
|
+
# : (?untyped) -> String
|
|
25
|
+
def to_json: (?untyped) -> String
|
|
26
|
+
|
|
27
|
+
# : () -> String
|
|
28
|
+
def inspect: () -> String
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
# : (Array[Symbol], Array[Symbol], String) -> void
|
|
33
|
+
def validate!: (Array[Symbol], Array[Symbol], String) -> void
|
|
34
|
+
|
|
35
|
+
# : (Hash[Symbol, untyped]) -> Hash[Symbol, untyped]
|
|
36
|
+
def normalize: (Hash[Symbol, untyped]) -> Hash[Symbol, untyped]
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Generated from lib/lightningcss/result.rb with RBS::Inline
|
|
2
|
+
|
|
3
|
+
module LightningCSS
|
|
4
|
+
# What a transform produced.
|
|
5
|
+
#
|
|
6
|
+
# `exports` is only filled in when the stylesheet was compiled as a CSS module, and maps every
|
|
7
|
+
# name as it was written to the name it was compiled to. A transform that was not asked for a
|
|
8
|
+
# CSS module has none, and neither does a style attribute, which has no names to compile.
|
|
9
|
+
#
|
|
10
|
+
# `warnings` holds what Lightning CSS understood well enough to keep but not well enough to act
|
|
11
|
+
# on, which is everything it would otherwise have dropped without saying so.
|
|
12
|
+
class Result
|
|
13
|
+
attr_reader code: String
|
|
14
|
+
|
|
15
|
+
attr_reader exports: Hash[String, String]?
|
|
16
|
+
|
|
17
|
+
attr_reader warnings: Array[String]
|
|
18
|
+
|
|
19
|
+
# : (String) -> LightningCSS::Result
|
|
20
|
+
def self.from_json: (String) -> LightningCSS::Result
|
|
21
|
+
|
|
22
|
+
# : (code: String, warnings: Array[String], ?exports: Hash[String, String]?) -> void
|
|
23
|
+
def initialize: (code: String, warnings: Array[String], ?exports: Hash[String, String]?) -> void
|
|
24
|
+
|
|
25
|
+
# : () -> bool
|
|
26
|
+
def warnings?: () -> bool
|
|
27
|
+
|
|
28
|
+
# : () -> String
|
|
29
|
+
def to_s: () -> String
|
|
30
|
+
|
|
31
|
+
# : () -> String
|
|
32
|
+
def inspect: () -> String
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Generated from lib/lightningcss/transformer.rb with RBS::Inline
|
|
2
|
+
|
|
3
|
+
module LightningCSS
|
|
4
|
+
# A set of options to transform many stylesheets with.
|
|
5
|
+
#
|
|
6
|
+
# transformer = LightningCSS::Transformer.new(minify: true, targets: { chrome: 100 })
|
|
7
|
+
#
|
|
8
|
+
# transformer.transform(".a { color: red }").code
|
|
9
|
+
# transformer.transform(".b { color: red }", scope: "[data-scope-abc]").code
|
|
10
|
+
#
|
|
11
|
+
# Options given to a call are merged over the ones it was built with, so the ones that belong to
|
|
12
|
+
# the project are written once and the ones that belong to a single stylesheet travel with it.
|
|
13
|
+
class Transformer
|
|
14
|
+
attr_reader options: Hash[Symbol, untyped]
|
|
15
|
+
|
|
16
|
+
# : (?filename: String?, ?minify: bool, ?error_recovery: bool, ?targets: browsers?, ?css_modules: css_modules?, ?scope: String?) -> void
|
|
17
|
+
def initialize: (?filename: String?, ?minify: bool, ?error_recovery: bool, ?targets: browsers?, ?css_modules: css_modules?, ?scope: String?) -> void
|
|
18
|
+
|
|
19
|
+
# : (String, ?filename: String?, ?minify: bool, ?error_recovery: bool, ?targets: browsers?, ?css_modules: css_modules?, ?scope: String?) -> LightningCSS::Result
|
|
20
|
+
def transform: (String, ?filename: String?, ?minify: bool, ?error_recovery: bool, ?targets: browsers?, ?css_modules: css_modules?, ?scope: String?) -> LightningCSS::Result
|
|
21
|
+
|
|
22
|
+
alias call transform
|
|
23
|
+
|
|
24
|
+
# : (String, ?filename: String?, ?minify: bool, ?error_recovery: bool, ?targets: browsers?, ?css_modules: css_modules?, ?scope: String?) -> LightningCSS::Result
|
|
25
|
+
def bundle: (String, ?filename: String?, ?minify: bool, ?error_recovery: bool, ?targets: browsers?, ?css_modules: css_modules?, ?scope: String?) -> LightningCSS::Result
|
|
26
|
+
|
|
27
|
+
# : (String, ?filename: String?, ?minify: bool, ?error_recovery: bool, ?targets: browsers?) -> LightningCSS::Result
|
|
28
|
+
def transform_style_attribute: (String, ?filename: String?, ?minify: bool, ?error_recovery: bool, ?targets: browsers?) -> LightningCSS::Result
|
|
29
|
+
|
|
30
|
+
# : (String, ?filename: String?, ?error_recovery: bool, ?targets: browsers?, ?css_modules: css_modules?, ?scope: String?) -> String
|
|
31
|
+
def minify: (String, ?filename: String?, ?error_recovery: bool, ?targets: browsers?, ?css_modules: css_modules?, ?scope: String?) -> String
|
|
32
|
+
|
|
33
|
+
# : (?filename: String?, ?minify: bool, ?error_recovery: bool, ?targets: browsers?, ?css_modules: css_modules?, ?scope: String?) -> LightningCSS::Transformer
|
|
34
|
+
def with: (?filename: String?, ?minify: bool, ?error_recovery: bool, ?targets: browsers?, ?css_modules: css_modules?, ?scope: String?) -> LightningCSS::Transformer
|
|
35
|
+
|
|
36
|
+
# : () -> String
|
|
37
|
+
def inspect: () -> String
|
|
38
|
+
end
|
|
39
|
+
end
|