lightningcss 0.1.0 → 0.2.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.
- checksums.yaml +4 -4
- data/README.md +14 -0
- data/ext/lightningcss/extconf.rb +14 -3
- data/ext/lightningcss/include/lightningcss.h +11 -0
- data/ext/lightningcss/lightningcss.c +47 -17
- data/lib/lightningcss/backend.rb +5 -0
- data/lib/lightningcss/options.rb +13 -5
- data/lib/lightningcss/transformer.rb +1 -1
- data/lib/lightningcss/version.rb +1 -1
- data/lib/lightningcss.rb +7 -5
- data/lightningcss.gemspec +1 -1
- data/rust/Cargo.lock +1 -1
- data/rust/Cargo.toml +1 -1
- data/rust/build.rs +40 -0
- data/rust/cbindgen.toml +1 -0
- data/rust/src/lib.rs +109 -37
- data/rust/src/scope.rs +4 -2
- data/sig/lightningcss/backend.rbs +3 -0
- data/sig/lightningcss/options.rbs +6 -4
- data/sig/lightningcss/transformer.rbs +2 -2
- data/sig/lightningcss.rbs +3 -3
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0bf26de1f9cfbbb2f49f77242f9597c790753ee59f0d570a9a7a42af2786f546
|
|
4
|
+
data.tar.gz: 41dcbf4cbdce9e38934fe52b8e594e07cb6c1aa771739309388891597b6f32f8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b77a36fd6862d5bcb82d70660ed9a03bbeba0bfa9e817bc223d82670e4a47a159112f0b9956782c320df18835b7e4d011e7f32f4fecd571780ca0607c108744c
|
|
7
|
+
data.tar.gz: 531fa107ef8aceb5f33fb2da0d23c58a621428d8ddee329bc1d18a4bfc82d04759eec41bbb88d5cb048c16d3ef52f27ff236f1debf7898073f861954720d41bf
|
data/README.md
CHANGED
|
@@ -62,6 +62,20 @@ LightningCSS.transform(".a { color: lab(50% 40 59) }", targets: { chrome: 80 },
|
|
|
62
62
|
LightningCSS.bundle("app/assets/stylesheets/application.css", minify: true).code
|
|
63
63
|
```
|
|
64
64
|
|
|
65
|
+
A bundle names every file it reads by the path it read it from, so it takes no `filename` and says so when given one.
|
|
66
|
+
|
|
67
|
+
It answers the same result a transform does. Every warning names the file it came from, and compiling as a CSS module renames the names in every file it read while exporting the ones the entry wrote. A file it imported is hashed on its own, so its names never collide with the entry's.
|
|
68
|
+
|
|
69
|
+
```ruby
|
|
70
|
+
result = LightningCSS.bundle("app/assets/stylesheets/application.css", css_modules: true)
|
|
71
|
+
|
|
72
|
+
result.exports
|
|
73
|
+
#=> {"application" => "_8Z4fiW_application"}
|
|
74
|
+
|
|
75
|
+
result.warnings.first
|
|
76
|
+
#=> "'deep' is not recognized as a valid pseudo-class. ... at app/assets/stylesheets/layout.css:0:9"
|
|
77
|
+
```
|
|
78
|
+
|
|
65
79
|
#### CSS modules
|
|
66
80
|
|
|
67
81
|
Compiling as a CSS module renames every class, id, `@keyframes`, and custom identifier, and reports what each name became.
|
data/ext/lightningcss/extconf.rb
CHANGED
|
@@ -65,12 +65,12 @@ if target_platform
|
|
|
65
65
|
|
|
66
66
|
system("rustup target add #{target_platform}") || warn("lightningcss: Failed to add Rust target #{target_platform}")
|
|
67
67
|
|
|
68
|
-
cargo_args = "--release --target #{target_platform}"
|
|
68
|
+
cargo_args = "--release --locked --target #{target_platform}"
|
|
69
69
|
lib_dir = File.join(target_dir, target_platform, "release")
|
|
70
70
|
else
|
|
71
71
|
puts "lightningcss: Compiling Rust library for native platform..."
|
|
72
72
|
|
|
73
|
-
cargo_args = "--release"
|
|
73
|
+
cargo_args = "--release --locked"
|
|
74
74
|
lib_dir = File.join(target_dir, "release")
|
|
75
75
|
end
|
|
76
76
|
|
|
@@ -84,7 +84,18 @@ end
|
|
|
84
84
|
|
|
85
85
|
static_lib = File.join(lib_dir, "liblightningcss_ffi.a")
|
|
86
86
|
|
|
87
|
-
|
|
87
|
+
developing = File.exist?(File.join(root_dir, ".git"))
|
|
88
|
+
|
|
89
|
+
if File.exist?(static_lib) && !developing
|
|
90
|
+
vendored = File.join(ext_dir, "liblightningcss_ffi.a")
|
|
91
|
+
|
|
92
|
+
FileUtils.cp(static_lib, vendored)
|
|
93
|
+
FileUtils.rm_rf(target_dir)
|
|
94
|
+
|
|
95
|
+
puts "lightningcss: Static library vendored at #{vendored}, Rust build directory removed"
|
|
96
|
+
|
|
97
|
+
$LDFLAGS << " #{vendored}"
|
|
98
|
+
elsif File.exist?(static_lib)
|
|
88
99
|
puts "lightningcss: Static library found at #{static_lib}"
|
|
89
100
|
|
|
90
101
|
$LDFLAGS << " #{static_lib}"
|
|
@@ -7,9 +7,18 @@
|
|
|
7
7
|
#ifndef LIGHTNINGCSS_H
|
|
8
8
|
#define LIGHTNINGCSS_H
|
|
9
9
|
|
|
10
|
+
typedef enum LightningCssErrorCode {
|
|
11
|
+
LIGHTNING_CSS_ERROR_CODE_NONE = 0,
|
|
12
|
+
LIGHTNING_CSS_ERROR_CODE_PARSE,
|
|
13
|
+
LIGHTNING_CSS_ERROR_CODE_OPTION,
|
|
14
|
+
LIGHTNING_CSS_ERROR_CODE_BUNDLE,
|
|
15
|
+
LIGHTNING_CSS_ERROR_CODE_INTERNAL,
|
|
16
|
+
} LightningCssErrorCode;
|
|
17
|
+
|
|
10
18
|
typedef struct LightningCssResult {
|
|
11
19
|
char *value;
|
|
12
20
|
char *error;
|
|
21
|
+
enum LightningCssErrorCode code;
|
|
13
22
|
} LightningCssResult;
|
|
14
23
|
|
|
15
24
|
struct LightningCssResult lightningcss_transform(const char *code, const char *options_json);
|
|
@@ -21,6 +30,8 @@ struct LightningCssResult lightningcss_bundle(const char *path, const char *opti
|
|
|
21
30
|
|
|
22
31
|
char *lightningcss_version(void);
|
|
23
32
|
|
|
33
|
+
char *lightningcss_lightningcss_version(void);
|
|
34
|
+
|
|
24
35
|
void lightningcss_string_free(char *value);
|
|
25
36
|
|
|
26
37
|
void lightningcss_result_free(struct LightningCssResult result);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#include <ruby.h>
|
|
2
2
|
#include <ruby/encoding.h>
|
|
3
|
+
#include <ruby/thread.h>
|
|
3
4
|
#include "include/lightningcss.h"
|
|
4
5
|
|
|
5
6
|
static VALUE rb_mLightningCSS;
|
|
@@ -9,6 +10,15 @@ static VALUE rb_eParseError;
|
|
|
9
10
|
static VALUE rb_eOptionError;
|
|
10
11
|
static VALUE rb_eBundleError;
|
|
11
12
|
|
|
13
|
+
typedef struct LightningCssResult (*lightningcss_function)(const char *, const char *);
|
|
14
|
+
|
|
15
|
+
struct call_arguments {
|
|
16
|
+
lightningcss_function function;
|
|
17
|
+
const char *input;
|
|
18
|
+
const char *options;
|
|
19
|
+
struct LightningCssResult result;
|
|
20
|
+
};
|
|
21
|
+
|
|
12
22
|
static VALUE make_utf8_string(const char *cstring) {
|
|
13
23
|
return rb_enc_str_new_cstr(cstring, rb_utf8_encoding());
|
|
14
24
|
}
|
|
@@ -22,26 +32,19 @@ static VALUE take_utf8_string(char *cstring) {
|
|
|
22
32
|
return string;
|
|
23
33
|
}
|
|
24
34
|
|
|
25
|
-
static VALUE error_class_for(
|
|
26
|
-
|
|
27
|
-
return
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
return rb_eBundleError;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
if (strstr(message, "Invalid scope selector") || strstr(message, "Scope selector")) {
|
|
35
|
-
return rb_eOptionError;
|
|
35
|
+
static VALUE error_class_for(enum LightningCssErrorCode code) {
|
|
36
|
+
switch (code) {
|
|
37
|
+
case LIGHTNING_CSS_ERROR_CODE_PARSE: return rb_eParseError;
|
|
38
|
+
case LIGHTNING_CSS_ERROR_CODE_OPTION: return rb_eOptionError;
|
|
39
|
+
case LIGHTNING_CSS_ERROR_CODE_BUNDLE: return rb_eBundleError;
|
|
40
|
+
default: return rb_eError;
|
|
36
41
|
}
|
|
37
|
-
|
|
38
|
-
return rb_eParseError;
|
|
39
42
|
}
|
|
40
43
|
|
|
41
44
|
static VALUE unwrap(struct LightningCssResult result) {
|
|
42
45
|
if (result.error) {
|
|
43
46
|
VALUE message = make_utf8_string(result.error);
|
|
44
|
-
VALUE error_class = error_class_for(result.
|
|
47
|
+
VALUE error_class = error_class_for(result.code);
|
|
45
48
|
|
|
46
49
|
lightningcss_result_free(result);
|
|
47
50
|
|
|
@@ -61,22 +64,42 @@ static VALUE unwrap(struct LightningCssResult result) {
|
|
|
61
64
|
return value;
|
|
62
65
|
}
|
|
63
66
|
|
|
67
|
+
static void *without_gvl(void *data) {
|
|
68
|
+
struct call_arguments *arguments = (struct call_arguments *) data;
|
|
69
|
+
|
|
70
|
+
arguments->result = arguments->function(arguments->input, arguments->options);
|
|
71
|
+
|
|
72
|
+
return NULL;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
static VALUE call(lightningcss_function function, VALUE input, VALUE options) {
|
|
76
|
+
struct call_arguments arguments;
|
|
77
|
+
|
|
78
|
+
arguments.function = function;
|
|
79
|
+
arguments.input = StringValueCStr(input);
|
|
80
|
+
arguments.options = StringValueCStr(options);
|
|
81
|
+
|
|
82
|
+
rb_thread_call_without_gvl(without_gvl, &arguments, NULL, NULL);
|
|
83
|
+
|
|
84
|
+
return unwrap(arguments.result);
|
|
85
|
+
}
|
|
86
|
+
|
|
64
87
|
static VALUE rb_transform(VALUE self, VALUE code, VALUE options) {
|
|
65
88
|
(void) self;
|
|
66
89
|
|
|
67
|
-
return
|
|
90
|
+
return call(lightningcss_transform, code, options);
|
|
68
91
|
}
|
|
69
92
|
|
|
70
93
|
static VALUE rb_transform_style_attribute(VALUE self, VALUE code, VALUE options) {
|
|
71
94
|
(void) self;
|
|
72
95
|
|
|
73
|
-
return
|
|
96
|
+
return call(lightningcss_transform_style_attribute, code, options);
|
|
74
97
|
}
|
|
75
98
|
|
|
76
99
|
static VALUE rb_bundle(VALUE self, VALUE path, VALUE options) {
|
|
77
100
|
(void) self;
|
|
78
101
|
|
|
79
|
-
return
|
|
102
|
+
return call(lightningcss_bundle, path, options);
|
|
80
103
|
}
|
|
81
104
|
|
|
82
105
|
static VALUE rb_native_version(VALUE self) {
|
|
@@ -85,6 +108,12 @@ static VALUE rb_native_version(VALUE self) {
|
|
|
85
108
|
return take_utf8_string(lightningcss_version());
|
|
86
109
|
}
|
|
87
110
|
|
|
111
|
+
static VALUE rb_lightningcss_version(VALUE self) {
|
|
112
|
+
(void) self;
|
|
113
|
+
|
|
114
|
+
return take_utf8_string(lightningcss_lightningcss_version());
|
|
115
|
+
}
|
|
116
|
+
|
|
88
117
|
void Init_lightningcss(void) {
|
|
89
118
|
rb_mLightningCSS = rb_define_module("LightningCSS");
|
|
90
119
|
rb_mBackend = rb_define_module_under(rb_mLightningCSS, "Backend");
|
|
@@ -98,4 +127,5 @@ void Init_lightningcss(void) {
|
|
|
98
127
|
rb_define_singleton_method(rb_mBackend, "transform_style_attribute", rb_transform_style_attribute, 2);
|
|
99
128
|
rb_define_singleton_method(rb_mBackend, "bundle", rb_bundle, 2);
|
|
100
129
|
rb_define_singleton_method(rb_mBackend, "version", rb_native_version, 0);
|
|
130
|
+
rb_define_singleton_method(rb_mBackend, "lightningcss_version", rb_lightningcss_version, 0);
|
|
101
131
|
}
|
data/lib/lightningcss/backend.rb
CHANGED
data/lib/lightningcss/options.rb
CHANGED
|
@@ -26,15 +26,23 @@ module LightningCSS
|
|
|
26
26
|
:targets
|
|
27
27
|
].freeze #: Array[Symbol]
|
|
28
28
|
|
|
29
|
+
BUNDLE = [
|
|
30
|
+
:minify,
|
|
31
|
+
:error_recovery,
|
|
32
|
+
:targets,
|
|
33
|
+
:css_modules,
|
|
34
|
+
:scope
|
|
35
|
+
].freeze #: Array[Symbol]
|
|
36
|
+
|
|
29
37
|
attr_reader :to_h #: Hash[Symbol, untyped]
|
|
30
38
|
|
|
31
|
-
#: (Hash[Symbol, untyped], ?
|
|
32
|
-
def self.serialize(options, allowed
|
|
33
|
-
new(
|
|
39
|
+
#: (Hash[Symbol, untyped], ?Array[Symbol], ?String) -> String
|
|
40
|
+
def self.serialize(options, allowed = KNOWN, subject = "a transform")
|
|
41
|
+
new(options, allowed, subject).to_json
|
|
34
42
|
end
|
|
35
43
|
|
|
36
|
-
#: (?
|
|
37
|
-
def initialize(allowed
|
|
44
|
+
#: (Hash[Symbol, untyped], ?Array[Symbol], ?String) -> void
|
|
45
|
+
def initialize(options, allowed = KNOWN, subject = "a transform")
|
|
38
46
|
given = options.transform_keys(&:to_sym)
|
|
39
47
|
|
|
40
48
|
validate!(given.keys, allowed, subject)
|
|
@@ -28,7 +28,7 @@ module LightningCSS
|
|
|
28
28
|
|
|
29
29
|
alias call transform
|
|
30
30
|
|
|
31
|
-
#: (String, ?
|
|
31
|
+
#: (String, ?minify: bool, ?error_recovery: bool, ?targets: browsers?, ?css_modules: css_modules?, ?scope: String?) -> LightningCSS::Result
|
|
32
32
|
def bundle(path, **overrides)
|
|
33
33
|
LightningCSS.bundle(path, **options, **overrides)
|
|
34
34
|
end
|
data/lib/lightningcss/version.rb
CHANGED
data/lib/lightningcss.rb
CHANGED
|
@@ -36,14 +36,16 @@ module LightningCSS
|
|
|
36
36
|
Result.from_json(Backend.transform(code.to_s, Options.serialize(options)))
|
|
37
37
|
end
|
|
38
38
|
|
|
39
|
-
#: (String, ?
|
|
39
|
+
#: (String, ?minify: bool, ?error_recovery: bool, ?targets: browsers?, ?css_modules: css_modules?, ?scope: String?) -> LightningCSS::Result
|
|
40
40
|
def self.bundle(path, **options)
|
|
41
|
-
|
|
41
|
+
serialized = Options.serialize(options, Options::BUNDLE, "a bundle")
|
|
42
|
+
|
|
43
|
+
Result.from_json(Backend.bundle(path.to_s, serialized))
|
|
42
44
|
end
|
|
43
45
|
|
|
44
46
|
#: (String, ?filename: String?, ?minify: bool, ?error_recovery: bool, ?targets: browsers?) -> LightningCSS::Result
|
|
45
47
|
def self.transform_style_attribute(code, **options)
|
|
46
|
-
serialized = Options.serialize(options,
|
|
48
|
+
serialized = Options.serialize(options, Options::STYLE_ATTRIBUTE, "a style attribute")
|
|
47
49
|
|
|
48
50
|
Result.from_json(Backend.transform_style_attribute(code.to_s, serialized))
|
|
49
51
|
end
|
|
@@ -54,7 +56,7 @@ module LightningCSS
|
|
|
54
56
|
end
|
|
55
57
|
|
|
56
58
|
#: () -> String
|
|
57
|
-
def self.
|
|
58
|
-
Backend.
|
|
59
|
+
def self.lightningcss_version
|
|
60
|
+
Backend.lightningcss_version
|
|
59
61
|
end
|
|
60
62
|
end
|
data/lightningcss.gemspec
CHANGED
|
@@ -11,7 +11,7 @@ Gem::Specification.new do |spec|
|
|
|
11
11
|
spec.summary = "An extremely fast CSS parser, transformer, bundler, and minifier."
|
|
12
12
|
spec.description = "Ruby bindings for Lightning CSS, an extremely fast CSS parser, transformer, bundler, and minifier."
|
|
13
13
|
spec.homepage = "https://github.com/marcoroth/lightningcss-ruby"
|
|
14
|
-
spec.
|
|
14
|
+
spec.licenses = ["MIT", "MPL-2.0"]
|
|
15
15
|
spec.required_ruby_version = ">= 3.2.0"
|
|
16
16
|
spec.require_paths = ["lib"]
|
|
17
17
|
|
data/rust/Cargo.lock
CHANGED
data/rust/Cargo.toml
CHANGED
data/rust/build.rs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
use std::env;
|
|
2
|
+
use std::fs;
|
|
2
3
|
use std::path::PathBuf;
|
|
3
4
|
|
|
4
5
|
fn main() {
|
|
@@ -12,4 +13,43 @@ fn main() {
|
|
|
12
13
|
|
|
13
14
|
bindings.write_to_file(&header_path);
|
|
14
15
|
}
|
|
16
|
+
|
|
17
|
+
let lock_path = PathBuf::from(&crate_dir).join("Cargo.lock");
|
|
18
|
+
|
|
19
|
+
println!("cargo:rerun-if-changed={}", lock_path.display());
|
|
20
|
+
|
|
21
|
+
println!(
|
|
22
|
+
"cargo:rerun-if-changed={}",
|
|
23
|
+
PathBuf::from(&crate_dir).join("src").display()
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
println!(
|
|
27
|
+
"cargo:rerun-if-changed={}",
|
|
28
|
+
PathBuf::from(&crate_dir).join("cbindgen.toml").display()
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
println!(
|
|
32
|
+
"cargo:rustc-env=LIGHTNINGCSS_VERSION={}",
|
|
33
|
+
locked_version(&lock_path, "lightningcss")
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
fn locked_version(lock_path: &PathBuf, package: &str) -> String {
|
|
38
|
+
let Ok(lock) = fs::read_to_string(lock_path) else {
|
|
39
|
+
return "unknown".to_string();
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
let mut lines = lock.lines();
|
|
43
|
+
|
|
44
|
+
while let Some(line) = lines.next() {
|
|
45
|
+
if line.trim() != format!("name = \"{package}\"") {
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if let Some(version) = lines.next().and_then(|next| next.trim().strip_prefix("version = ")) {
|
|
50
|
+
return version.trim_matches('"').to_string();
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
"unknown".to_string()
|
|
15
55
|
}
|
data/rust/cbindgen.toml
CHANGED
data/rust/src/lib.rs
CHANGED
|
@@ -17,7 +17,7 @@ use std::os::raw::c_char;
|
|
|
17
17
|
use std::ptr;
|
|
18
18
|
use std::sync::{Arc, RwLock};
|
|
19
19
|
|
|
20
|
-
use lightningcss::bundler::{Bundler, FileProvider};
|
|
20
|
+
use lightningcss::bundler::{BundleErrorKind, Bundler, FileProvider};
|
|
21
21
|
use lightningcss::stylesheet::{MinifyOptions, ParserOptions, PrinterOptions, StyleAttribute, StyleSheet};
|
|
22
22
|
use lightningcss::visitor::Visit;
|
|
23
23
|
|
|
@@ -25,11 +25,23 @@ use crate::options::{TransformOptions, TransformResult};
|
|
|
25
25
|
use crate::scope::Scoper;
|
|
26
26
|
|
|
27
27
|
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
|
|
28
|
+
pub const LIGHTNINGCSS_VERSION: &str = env!("LIGHTNINGCSS_VERSION");
|
|
29
|
+
|
|
30
|
+
#[repr(C)]
|
|
31
|
+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
32
|
+
pub enum LightningCssErrorCode {
|
|
33
|
+
None = 0,
|
|
34
|
+
Parse,
|
|
35
|
+
Option,
|
|
36
|
+
Bundle,
|
|
37
|
+
Internal,
|
|
38
|
+
}
|
|
28
39
|
|
|
29
40
|
#[repr(C)]
|
|
30
41
|
pub struct LightningCssResult {
|
|
31
42
|
pub value: *mut c_char,
|
|
32
43
|
pub error: *mut c_char,
|
|
44
|
+
pub code: LightningCssErrorCode,
|
|
33
45
|
}
|
|
34
46
|
|
|
35
47
|
impl LightningCssResult {
|
|
@@ -37,13 +49,50 @@ impl LightningCssResult {
|
|
|
37
49
|
Self {
|
|
38
50
|
value: into_c_string(value),
|
|
39
51
|
error: ptr::null_mut(),
|
|
52
|
+
code: LightningCssErrorCode::None,
|
|
40
53
|
}
|
|
41
54
|
}
|
|
42
55
|
|
|
43
|
-
fn err(
|
|
56
|
+
fn err(failure: Failure) -> Self {
|
|
44
57
|
Self {
|
|
45
58
|
value: ptr::null_mut(),
|
|
46
|
-
error: into_c_string(message
|
|
59
|
+
error: into_c_string(failure.message),
|
|
60
|
+
code: failure.code,
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
pub struct Failure {
|
|
66
|
+
code: LightningCssErrorCode,
|
|
67
|
+
message: String,
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
impl Failure {
|
|
71
|
+
fn parse(message: impl Into<String>) -> Self {
|
|
72
|
+
Self {
|
|
73
|
+
code: LightningCssErrorCode::Parse,
|
|
74
|
+
message: message.into(),
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
fn option(message: impl Into<String>) -> Self {
|
|
79
|
+
Self {
|
|
80
|
+
code: LightningCssErrorCode::Option,
|
|
81
|
+
message: message.into(),
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
fn bundle(message: impl Into<String>) -> Self {
|
|
86
|
+
Self {
|
|
87
|
+
code: LightningCssErrorCode::Bundle,
|
|
88
|
+
message: message.into(),
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
fn internal(message: impl Into<String>) -> Self {
|
|
93
|
+
Self {
|
|
94
|
+
code: LightningCssErrorCode::Internal,
|
|
95
|
+
message: message.into(),
|
|
47
96
|
}
|
|
48
97
|
}
|
|
49
98
|
}
|
|
@@ -52,17 +101,17 @@ fn into_c_string(value: impl Into<Vec<u8>>) -> *mut c_char {
|
|
|
52
101
|
CString::new(value).unwrap_or_default().into_raw()
|
|
53
102
|
}
|
|
54
103
|
|
|
55
|
-
unsafe fn borrow_str<'a>(pointer: *const c_char, label: &str) -> Result<&'a str,
|
|
104
|
+
unsafe fn borrow_str<'a>(pointer: *const c_char, label: &str) -> Result<&'a str, Failure> {
|
|
56
105
|
if pointer.is_null() {
|
|
57
|
-
return Err(format!("{label} is null"));
|
|
106
|
+
return Err(Failure::internal(format!("{label} is null")));
|
|
58
107
|
}
|
|
59
108
|
|
|
60
109
|
CStr::from_ptr(pointer)
|
|
61
110
|
.to_str()
|
|
62
|
-
.map_err(|error| format!("Invalid UTF-8 in {label}: {error}"))
|
|
111
|
+
.map_err(|error| Failure::internal(format!("Invalid UTF-8 in {label}: {error}")))
|
|
63
112
|
}
|
|
64
113
|
|
|
65
|
-
unsafe fn borrow_options(pointer: *const c_char) -> Result<TransformOptions,
|
|
114
|
+
unsafe fn borrow_options(pointer: *const c_char) -> Result<TransformOptions, Failure> {
|
|
66
115
|
if pointer.is_null() {
|
|
67
116
|
return Ok(TransformOptions::default());
|
|
68
117
|
}
|
|
@@ -73,13 +122,13 @@ unsafe fn borrow_options(pointer: *const c_char) -> Result<TransformOptions, Str
|
|
|
73
122
|
return Ok(TransformOptions::default());
|
|
74
123
|
}
|
|
75
124
|
|
|
76
|
-
serde_json::from_str(json).map_err(|error| format!("Invalid options: {error}"))
|
|
125
|
+
serde_json::from_str(json).map_err(|error| Failure::option(format!("Invalid options: {error}")))
|
|
77
126
|
}
|
|
78
127
|
|
|
79
|
-
fn transform_source(code: &str, options: &TransformOptions) -> Result<TransformResult,
|
|
128
|
+
fn transform_source(code: &str, options: &TransformOptions) -> Result<TransformResult, Failure> {
|
|
80
129
|
let filename = options.filename.clone().unwrap_or_default();
|
|
81
130
|
let css_modules = match &options.css_modules {
|
|
82
|
-
Some(modules) => Some(modules.to_config()?),
|
|
131
|
+
Some(modules) => Some(modules.to_config().map_err(Failure::option)?),
|
|
83
132
|
None => None,
|
|
84
133
|
};
|
|
85
134
|
|
|
@@ -93,14 +142,14 @@ fn transform_source(code: &str, options: &TransformOptions) -> Result<TransformR
|
|
|
93
142
|
..ParserOptions::default()
|
|
94
143
|
};
|
|
95
144
|
|
|
96
|
-
let mut stylesheet = StyleSheet::parse(code, parser_options).map_err(|error| error.to_string())?;
|
|
145
|
+
let mut stylesheet = StyleSheet::parse(code, parser_options).map_err(|error| Failure::parse(error.to_string()))?;
|
|
97
146
|
|
|
98
147
|
if let Some(fragment) = &options.scope {
|
|
99
|
-
let mut scoper = Scoper::parse(fragment)?;
|
|
148
|
+
let mut scoper = Scoper::parse(fragment).map_err(Failure::option)?;
|
|
100
149
|
|
|
101
150
|
stylesheet
|
|
102
151
|
.visit(&mut scoper)
|
|
103
|
-
.map_err(|error| format!("Failed to scope stylesheet: {error:?}"))?;
|
|
152
|
+
.map_err(|error| Failure::internal(format!("Failed to scope stylesheet: {error:?}")))?;
|
|
104
153
|
}
|
|
105
154
|
|
|
106
155
|
let targets = options.to_targets();
|
|
@@ -111,7 +160,7 @@ fn transform_source(code: &str, options: &TransformOptions) -> Result<TransformR
|
|
|
111
160
|
targets,
|
|
112
161
|
..MinifyOptions::default()
|
|
113
162
|
})
|
|
114
|
-
.map_err(|error| format!("Failed to minify: {error}"))?;
|
|
163
|
+
.map_err(|error| Failure::internal(format!("Failed to minify: {error}")))?;
|
|
115
164
|
}
|
|
116
165
|
|
|
117
166
|
let printed = stylesheet
|
|
@@ -123,7 +172,7 @@ fn transform_source(code: &str, options: &TransformOptions) -> Result<TransformR
|
|
|
123
172
|
analyze_dependencies: None,
|
|
124
173
|
pseudo_classes: None,
|
|
125
174
|
})
|
|
126
|
-
.map_err(|error| format!("Failed to print: {error}"))?;
|
|
175
|
+
.map_err(|error| Failure::internal(format!("Failed to print: {error}")))?;
|
|
127
176
|
|
|
128
177
|
let exports = printed.exports.map(|exports| {
|
|
129
178
|
exports
|
|
@@ -144,31 +193,37 @@ fn transform_source(code: &str, options: &TransformOptions) -> Result<TransformR
|
|
|
144
193
|
})
|
|
145
194
|
}
|
|
146
195
|
|
|
147
|
-
fn bundle_source(path: &str, options: &TransformOptions) -> Result<TransformResult,
|
|
196
|
+
fn bundle_source(path: &str, options: &TransformOptions) -> Result<TransformResult, Failure> {
|
|
148
197
|
let css_modules = match &options.css_modules {
|
|
149
|
-
Some(modules) => Some(modules.to_config()?),
|
|
198
|
+
Some(modules) => Some(modules.to_config().map_err(Failure::option)?),
|
|
150
199
|
None => None,
|
|
151
200
|
};
|
|
152
201
|
|
|
202
|
+
let provider = FileProvider::new();
|
|
203
|
+
let collected = Arc::new(RwLock::new(Vec::new()));
|
|
204
|
+
|
|
153
205
|
let parser_options = ParserOptions {
|
|
154
206
|
css_modules,
|
|
155
207
|
error_recovery: options.error_recovery,
|
|
208
|
+
warnings: Some(collected.clone()),
|
|
156
209
|
..ParserOptions::default()
|
|
157
210
|
};
|
|
158
211
|
|
|
159
|
-
let provider = FileProvider::new();
|
|
160
212
|
let mut bundler = Bundler::new(&provider, None, parser_options);
|
|
161
213
|
|
|
162
214
|
let mut stylesheet = bundler
|
|
163
215
|
.bundle(std::path::Path::new(path))
|
|
164
|
-
.map_err(|error| error.
|
|
216
|
+
.map_err(|error| match &error.kind {
|
|
217
|
+
BundleErrorKind::ParserError(_) => Failure::parse(error.to_string()),
|
|
218
|
+
_ => Failure::bundle(error.to_string()),
|
|
219
|
+
})?;
|
|
165
220
|
|
|
166
221
|
if let Some(fragment) = &options.scope {
|
|
167
|
-
let mut scoper = Scoper::parse(fragment)?;
|
|
222
|
+
let mut scoper = Scoper::parse(fragment).map_err(Failure::option)?;
|
|
168
223
|
|
|
169
224
|
stylesheet
|
|
170
225
|
.visit(&mut scoper)
|
|
171
|
-
.map_err(|error| format!("Failed to scope stylesheet: {error:?}"))?;
|
|
226
|
+
.map_err(|error| Failure::internal(format!("Failed to scope stylesheet: {error:?}")))?;
|
|
172
227
|
}
|
|
173
228
|
|
|
174
229
|
let targets = options.to_targets();
|
|
@@ -179,7 +234,7 @@ fn bundle_source(path: &str, options: &TransformOptions) -> Result<TransformResu
|
|
|
179
234
|
targets,
|
|
180
235
|
..MinifyOptions::default()
|
|
181
236
|
})
|
|
182
|
-
.map_err(|error| format!("Failed to minify: {error}"))?;
|
|
237
|
+
.map_err(|error| Failure::internal(format!("Failed to minify: {error}")))?;
|
|
183
238
|
}
|
|
184
239
|
|
|
185
240
|
let printed = stylesheet
|
|
@@ -188,23 +243,35 @@ fn bundle_source(path: &str, options: &TransformOptions) -> Result<TransformResu
|
|
|
188
243
|
targets,
|
|
189
244
|
..PrinterOptions::default()
|
|
190
245
|
})
|
|
191
|
-
.map_err(|error| format!("Failed to print: {error}"))?;
|
|
246
|
+
.map_err(|error| Failure::internal(format!("Failed to print: {error}")))?;
|
|
247
|
+
|
|
248
|
+
let exports = printed.exports.map(|exports| {
|
|
249
|
+
exports
|
|
250
|
+
.into_iter()
|
|
251
|
+
.map(|(local, export)| (local, export.name))
|
|
252
|
+
.collect::<HashMap<String, String>>()
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
let warnings = collected
|
|
256
|
+
.read()
|
|
257
|
+
.map(|warnings| warnings.iter().map(|warning| warning.to_string()).collect())
|
|
258
|
+
.unwrap_or_default();
|
|
192
259
|
|
|
193
260
|
Ok(TransformResult {
|
|
194
261
|
code: printed.code,
|
|
195
|
-
exports
|
|
196
|
-
warnings
|
|
262
|
+
exports,
|
|
263
|
+
warnings,
|
|
197
264
|
})
|
|
198
265
|
}
|
|
199
266
|
|
|
200
|
-
fn transform_attribute(code: &str, options: &TransformOptions) -> Result<TransformResult,
|
|
267
|
+
fn transform_attribute(code: &str, options: &TransformOptions) -> Result<TransformResult, Failure> {
|
|
201
268
|
let parser_options = ParserOptions {
|
|
202
269
|
filename: options.filename.clone().unwrap_or_default(),
|
|
203
270
|
error_recovery: options.error_recovery,
|
|
204
271
|
..ParserOptions::default()
|
|
205
272
|
};
|
|
206
273
|
|
|
207
|
-
let mut attribute = StyleAttribute::parse(code, parser_options).map_err(|error| error.to_string())?;
|
|
274
|
+
let mut attribute = StyleAttribute::parse(code, parser_options).map_err(|error| Failure::parse(error.to_string()))?;
|
|
208
275
|
|
|
209
276
|
let targets = options.to_targets();
|
|
210
277
|
|
|
@@ -219,7 +286,7 @@ fn transform_attribute(code: &str, options: &TransformOptions) -> Result<Transfo
|
|
|
219
286
|
targets,
|
|
220
287
|
..PrinterOptions::default()
|
|
221
288
|
})
|
|
222
|
-
.map_err(|error| format!("Failed to print: {error}"))?;
|
|
289
|
+
.map_err(|error| Failure::internal(format!("Failed to print: {error}")))?;
|
|
223
290
|
|
|
224
291
|
Ok(TransformResult {
|
|
225
292
|
code: printed.code,
|
|
@@ -228,13 +295,13 @@ fn transform_attribute(code: &str, options: &TransformOptions) -> Result<Transfo
|
|
|
228
295
|
})
|
|
229
296
|
}
|
|
230
297
|
|
|
231
|
-
fn to_result(outcome: Result<TransformResult,
|
|
298
|
+
fn to_result(outcome: Result<TransformResult, Failure>) -> LightningCssResult {
|
|
232
299
|
match outcome {
|
|
233
300
|
Ok(result) => match serde_json::to_string(&result) {
|
|
234
301
|
Ok(json) => LightningCssResult::ok(json),
|
|
235
|
-
Err(error) => LightningCssResult::err(format!("Failed to serialize result: {error}")),
|
|
302
|
+
Err(error) => LightningCssResult::err(Failure::internal(format!("Failed to serialize result: {error}"))),
|
|
236
303
|
},
|
|
237
|
-
Err(
|
|
304
|
+
Err(failure) => LightningCssResult::err(failure),
|
|
238
305
|
}
|
|
239
306
|
}
|
|
240
307
|
|
|
@@ -245,12 +312,12 @@ pub unsafe extern "C" fn lightningcss_transform(
|
|
|
245
312
|
) -> LightningCssResult {
|
|
246
313
|
let code = match borrow_str(code, "code") {
|
|
247
314
|
Ok(code) => code,
|
|
248
|
-
Err(
|
|
315
|
+
Err(failure) => return LightningCssResult::err(failure),
|
|
249
316
|
};
|
|
250
317
|
|
|
251
318
|
let options = match borrow_options(options_json) {
|
|
252
319
|
Ok(options) => options,
|
|
253
|
-
Err(
|
|
320
|
+
Err(failure) => return LightningCssResult::err(failure),
|
|
254
321
|
};
|
|
255
322
|
|
|
256
323
|
to_result(transform_source(code, &options))
|
|
@@ -263,12 +330,12 @@ pub unsafe extern "C" fn lightningcss_transform_style_attribute(
|
|
|
263
330
|
) -> LightningCssResult {
|
|
264
331
|
let code = match borrow_str(code, "code") {
|
|
265
332
|
Ok(code) => code,
|
|
266
|
-
Err(
|
|
333
|
+
Err(failure) => return LightningCssResult::err(failure),
|
|
267
334
|
};
|
|
268
335
|
|
|
269
336
|
let options = match borrow_options(options_json) {
|
|
270
337
|
Ok(options) => options,
|
|
271
|
-
Err(
|
|
338
|
+
Err(failure) => return LightningCssResult::err(failure),
|
|
272
339
|
};
|
|
273
340
|
|
|
274
341
|
to_result(transform_attribute(code, &options))
|
|
@@ -278,12 +345,12 @@ pub unsafe extern "C" fn lightningcss_transform_style_attribute(
|
|
|
278
345
|
pub unsafe extern "C" fn lightningcss_bundle(path: *const c_char, options_json: *const c_char) -> LightningCssResult {
|
|
279
346
|
let path = match borrow_str(path, "path") {
|
|
280
347
|
Ok(path) => path,
|
|
281
|
-
Err(
|
|
348
|
+
Err(failure) => return LightningCssResult::err(failure),
|
|
282
349
|
};
|
|
283
350
|
|
|
284
351
|
let options = match borrow_options(options_json) {
|
|
285
352
|
Ok(options) => options,
|
|
286
|
-
Err(
|
|
353
|
+
Err(failure) => return LightningCssResult::err(failure),
|
|
287
354
|
};
|
|
288
355
|
|
|
289
356
|
to_result(bundle_source(path, &options))
|
|
@@ -294,6 +361,11 @@ pub unsafe extern "C" fn lightningcss_version() -> *mut c_char {
|
|
|
294
361
|
into_c_string(VERSION)
|
|
295
362
|
}
|
|
296
363
|
|
|
364
|
+
#[no_mangle]
|
|
365
|
+
pub unsafe extern "C" fn lightningcss_lightningcss_version() -> *mut c_char {
|
|
366
|
+
into_c_string(LIGHTNINGCSS_VERSION)
|
|
367
|
+
}
|
|
368
|
+
|
|
297
369
|
#[no_mangle]
|
|
298
370
|
pub unsafe extern "C" fn lightningcss_string_free(value: *mut c_char) {
|
|
299
371
|
if !value.is_null() {
|
data/rust/src/scope.rs
CHANGED
|
@@ -4,8 +4,10 @@
|
|
|
4
4
|
//! `parcel_selectors` stores a selector in reverse match order, so `Selector::append` lands the
|
|
5
5
|
//! fragment in the last compound and before any pseudo-element, which is where a scope belongs:
|
|
6
6
|
//!
|
|
7
|
-
//!
|
|
8
|
-
//!
|
|
7
|
+
//! ```text
|
|
8
|
+
//! .card .title -> .card .title[data-herb-scope-abc]
|
|
9
|
+
//! .item::before -> .item[data-herb-scope-abc]::before
|
|
10
|
+
//! ```
|
|
9
11
|
//!
|
|
10
12
|
//! A fragment is anything that parses as one compound selector, so an attribute and a `:where()`
|
|
11
13
|
//! carrying its own alternatives are both expressible.
|
|
@@ -13,13 +13,15 @@ module LightningCSS
|
|
|
13
13
|
|
|
14
14
|
STYLE_ATTRIBUTE: Array[Symbol]
|
|
15
15
|
|
|
16
|
+
BUNDLE: Array[Symbol]
|
|
17
|
+
|
|
16
18
|
attr_reader to_h: Hash[Symbol, untyped]
|
|
17
19
|
|
|
18
|
-
# : (Hash[Symbol, untyped], ?
|
|
19
|
-
def self.serialize: (Hash[Symbol, untyped], ?
|
|
20
|
+
# : (Hash[Symbol, untyped], ?Array[Symbol], ?String) -> String
|
|
21
|
+
def self.serialize: (Hash[Symbol, untyped], ?Array[Symbol], ?String) -> String
|
|
20
22
|
|
|
21
|
-
# : (?
|
|
22
|
-
def initialize: (?
|
|
23
|
+
# : (Hash[Symbol, untyped], ?Array[Symbol], ?String) -> void
|
|
24
|
+
def initialize: (Hash[Symbol, untyped], ?Array[Symbol], ?String) -> void
|
|
23
25
|
|
|
24
26
|
# : (?untyped) -> String
|
|
25
27
|
def to_json: (?untyped) -> String
|
|
@@ -21,8 +21,8 @@ module LightningCSS
|
|
|
21
21
|
|
|
22
22
|
alias call transform
|
|
23
23
|
|
|
24
|
-
# : (String, ?
|
|
25
|
-
def bundle: (String, ?
|
|
24
|
+
# : (String, ?minify: bool, ?error_recovery: bool, ?targets: browsers?, ?css_modules: css_modules?, ?scope: String?) -> LightningCSS::Result
|
|
25
|
+
def bundle: (String, ?minify: bool, ?error_recovery: bool, ?targets: browsers?, ?css_modules: css_modules?, ?scope: String?) -> LightningCSS::Result
|
|
26
26
|
|
|
27
27
|
# : (String, ?filename: String?, ?minify: bool, ?error_recovery: bool, ?targets: browsers?) -> LightningCSS::Result
|
|
28
28
|
def transform_style_attribute: (String, ?filename: String?, ?minify: bool, ?error_recovery: bool, ?targets: browsers?) -> LightningCSS::Result
|
data/sig/lightningcss.rbs
CHANGED
|
@@ -17,8 +17,8 @@ module LightningCSS
|
|
|
17
17
|
# : (String, ?filename: String?, ?minify: bool, ?error_recovery: bool, ?targets: browsers?, ?css_modules: css_modules?, ?scope: String?) -> LightningCSS::Result
|
|
18
18
|
def self.transform: (String, ?filename: String?, ?minify: bool, ?error_recovery: bool, ?targets: browsers?, ?css_modules: css_modules?, ?scope: String?) -> LightningCSS::Result
|
|
19
19
|
|
|
20
|
-
# : (String, ?
|
|
21
|
-
def self.bundle: (String, ?
|
|
20
|
+
# : (String, ?minify: bool, ?error_recovery: bool, ?targets: browsers?, ?css_modules: css_modules?, ?scope: String?) -> LightningCSS::Result
|
|
21
|
+
def self.bundle: (String, ?minify: bool, ?error_recovery: bool, ?targets: browsers?, ?css_modules: css_modules?, ?scope: String?) -> LightningCSS::Result
|
|
22
22
|
|
|
23
23
|
# : (String, ?filename: String?, ?minify: bool, ?error_recovery: bool, ?targets: browsers?) -> LightningCSS::Result
|
|
24
24
|
def self.transform_style_attribute: (String, ?filename: String?, ?minify: bool, ?error_recovery: bool, ?targets: browsers?) -> LightningCSS::Result
|
|
@@ -27,5 +27,5 @@ module LightningCSS
|
|
|
27
27
|
def self.minify: (String, ?filename: String?, ?error_recovery: bool, ?targets: browsers?, ?css_modules: css_modules?, ?scope: String?) -> String
|
|
28
28
|
|
|
29
29
|
# : () -> String
|
|
30
|
-
def self.
|
|
30
|
+
def self.lightningcss_version: () -> String
|
|
31
31
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: lightningcss
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Marco Roth
|
|
@@ -52,6 +52,7 @@ files:
|
|
|
52
52
|
homepage: https://github.com/marcoroth/lightningcss-ruby
|
|
53
53
|
licenses:
|
|
54
54
|
- MIT
|
|
55
|
+
- MPL-2.0
|
|
55
56
|
metadata:
|
|
56
57
|
homepage_uri: https://github.com/marcoroth/lightningcss-ruby
|
|
57
58
|
source_code_uri: https://github.com/marcoroth/lightningcss-ruby
|