lightningcss 0.1.1-x86_64-linux-gnu → 0.2.0-x86_64-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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a31e0134417336ea23e7b77bce94afcf4575099402dea938d25acf44a5b2a2c8
4
- data.tar.gz: d397464d5c09dad2e61daf7860a80043302e10961a4dd945e6204041b5bd9fd6
3
+ metadata.gz: 60b9bf5ff6f7226f2deb903411280800ba1bb5e4d270fd32cc7c28ae23f82e54
4
+ data.tar.gz: 3199cdeaca6c86296bd0d05c7350d450694e00c71d26a72a9cfe70acbc71e249
5
5
  SHA512:
6
- metadata.gz: 9107d3e0bdb0eb491451820b314dcf87df50401b482c84e870b12b7e77b3d3a750e881a027d5b7efb50749681280e7c8dcf16a481f10bb93f175648365741c62
7
- data.tar.gz: ea0cbbfb82490f5c5d811d014b840cd3bba1d45e3b4a64b522ba27e71b57d583d9c96014457edf32989ba96716786b03aba56c952084911bcbd1c58b5c23d8ef
6
+ metadata.gz: 562c17a0bedbc7c0c971b20df9da6352b108b1607321f9ada7021c6d696515e8a371003a78ed90b4bd69fd60c01b6027016414f834cb5d5e27206a5e6b4c57e3
7
+ data.tar.gz: e0b92d822c7244d589aa00c021338c27455cbaf845494eeac942a01a29e8c346b47141d7a87c752337d2a52152a51a5332fbcf1277deabc7873492b4da211e3f
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.
@@ -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
- if File.exist?(static_lib)
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);
@@ -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(const char *message) {
26
- if (strstr(message, "Invalid options") || strstr(message, "Invalid CSS modules pattern")) {
27
- return rb_eOptionError;
28
- }
29
-
30
- if (strstr(message, "os error") || strstr(message, "No such file")) {
31
- return rb_eBundleError;
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;
32
41
  }
33
-
34
- if (strstr(message, "Invalid scope selector") || strstr(message, "Scope selector")) {
35
- return rb_eOptionError;
36
- }
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.error);
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 unwrap(lightningcss_transform(StringValueCStr(code), StringValueCStr(options)));
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 unwrap(lightningcss_transform_style_attribute(StringValueCStr(code), StringValueCStr(options)));
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 unwrap(lightningcss_bundle(StringValueCStr(path), StringValueCStr(options)));
102
+ return call(lightningcss_bundle, path, options);
80
103
  }
81
104
 
82
105
  static VALUE rb_native_version(VALUE self) {
Binary file
Binary file
Binary file
Binary file
@@ -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], ?allowed: Array[Symbol], ?subject: String) -> String
32
- def self.serialize(options, allowed: KNOWN, subject: "a transform")
33
- new(allowed: allowed, subject: subject, **options).to_json
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
- #: (?allowed: Array[Symbol], ?subject: String, **untyped) -> void
37
- def initialize(allowed: KNOWN, subject: "a transform", **options)
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, ?filename: String?, ?minify: bool, ?error_recovery: bool, ?targets: browsers?, ?css_modules: css_modules?, ?scope: String?) -> LightningCSS::Result
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module LightningCSS
4
- VERSION = "0.1.1"
4
+ VERSION = "0.2.0"
5
5
  end
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, ?filename: String?, ?minify: bool, ?error_recovery: bool, ?targets: browsers?, ?css_modules: css_modules?, ?scope: String?) -> LightningCSS::Result
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
- Result.from_json(Backend.bundle(path.to_s, Options.serialize(options)))
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, allowed: Options::STYLE_ATTRIBUTE, subject: "a style attribute")
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
data/rust/Cargo.lock CHANGED
@@ -527,7 +527,7 @@ dependencies = [
527
527
 
528
528
  [[package]]
529
529
  name = "lightningcss-ffi"
530
- version = "0.1.1"
530
+ version = "0.2.0"
531
531
  dependencies = [
532
532
  "cbindgen",
533
533
  "lightningcss",
data/rust/Cargo.toml CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [package]
4
4
  name = "lightningcss-ffi"
5
- version = "0.1.1"
5
+ version = "0.2.0"
6
6
  edition = "2021"
7
7
  authors = ["Marco Roth <marco.roth@intergga.ch>"]
8
8
  description = "C FFI bindings for Lightning CSS, used by the lightningcss gem"
data/rust/build.rs CHANGED
@@ -18,6 +18,16 @@ fn main() {
18
18
 
19
19
  println!("cargo:rerun-if-changed={}", lock_path.display());
20
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
+
21
31
  println!(
22
32
  "cargo:rustc-env=LIGHTNINGCSS_VERSION={}",
23
33
  locked_version(&lock_path, "lightningcss")
data/rust/cbindgen.toml CHANGED
@@ -10,6 +10,7 @@ no_includes = true
10
10
  [export]
11
11
  include = [
12
12
  "LightningCssResult",
13
+ "LightningCssErrorCode",
13
14
  ]
14
15
 
15
16
  [enum]
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
 
@@ -27,10 +27,21 @@ use crate::scope::Scoper;
27
27
  pub const VERSION: &str = env!("CARGO_PKG_VERSION");
28
28
  pub const LIGHTNINGCSS_VERSION: &str = env!("LIGHTNINGCSS_VERSION");
29
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
+ }
39
+
30
40
  #[repr(C)]
31
41
  pub struct LightningCssResult {
32
42
  pub value: *mut c_char,
33
43
  pub error: *mut c_char,
44
+ pub code: LightningCssErrorCode,
34
45
  }
35
46
 
36
47
  impl LightningCssResult {
@@ -38,13 +49,50 @@ impl LightningCssResult {
38
49
  Self {
39
50
  value: into_c_string(value),
40
51
  error: ptr::null_mut(),
52
+ code: LightningCssErrorCode::None,
41
53
  }
42
54
  }
43
55
 
44
- fn err(message: impl AsRef<str>) -> Self {
56
+ fn err(failure: Failure) -> Self {
45
57
  Self {
46
58
  value: ptr::null_mut(),
47
- error: into_c_string(message.as_ref()),
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(),
48
96
  }
49
97
  }
50
98
  }
@@ -53,17 +101,17 @@ fn into_c_string(value: impl Into<Vec<u8>>) -> *mut c_char {
53
101
  CString::new(value).unwrap_or_default().into_raw()
54
102
  }
55
103
 
56
- unsafe fn borrow_str<'a>(pointer: *const c_char, label: &str) -> Result<&'a str, String> {
104
+ unsafe fn borrow_str<'a>(pointer: *const c_char, label: &str) -> Result<&'a str, Failure> {
57
105
  if pointer.is_null() {
58
- return Err(format!("{label} is null"));
106
+ return Err(Failure::internal(format!("{label} is null")));
59
107
  }
60
108
 
61
109
  CStr::from_ptr(pointer)
62
110
  .to_str()
63
- .map_err(|error| format!("Invalid UTF-8 in {label}: {error}"))
111
+ .map_err(|error| Failure::internal(format!("Invalid UTF-8 in {label}: {error}")))
64
112
  }
65
113
 
66
- unsafe fn borrow_options(pointer: *const c_char) -> Result<TransformOptions, String> {
114
+ unsafe fn borrow_options(pointer: *const c_char) -> Result<TransformOptions, Failure> {
67
115
  if pointer.is_null() {
68
116
  return Ok(TransformOptions::default());
69
117
  }
@@ -74,13 +122,13 @@ unsafe fn borrow_options(pointer: *const c_char) -> Result<TransformOptions, Str
74
122
  return Ok(TransformOptions::default());
75
123
  }
76
124
 
77
- 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}")))
78
126
  }
79
127
 
80
- fn transform_source(code: &str, options: &TransformOptions) -> Result<TransformResult, String> {
128
+ fn transform_source(code: &str, options: &TransformOptions) -> Result<TransformResult, Failure> {
81
129
  let filename = options.filename.clone().unwrap_or_default();
82
130
  let css_modules = match &options.css_modules {
83
- Some(modules) => Some(modules.to_config()?),
131
+ Some(modules) => Some(modules.to_config().map_err(Failure::option)?),
84
132
  None => None,
85
133
  };
86
134
 
@@ -94,14 +142,14 @@ fn transform_source(code: &str, options: &TransformOptions) -> Result<TransformR
94
142
  ..ParserOptions::default()
95
143
  };
96
144
 
97
- 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()))?;
98
146
 
99
147
  if let Some(fragment) = &options.scope {
100
- let mut scoper = Scoper::parse(fragment)?;
148
+ let mut scoper = Scoper::parse(fragment).map_err(Failure::option)?;
101
149
 
102
150
  stylesheet
103
151
  .visit(&mut scoper)
104
- .map_err(|error| format!("Failed to scope stylesheet: {error:?}"))?;
152
+ .map_err(|error| Failure::internal(format!("Failed to scope stylesheet: {error:?}")))?;
105
153
  }
106
154
 
107
155
  let targets = options.to_targets();
@@ -112,7 +160,7 @@ fn transform_source(code: &str, options: &TransformOptions) -> Result<TransformR
112
160
  targets,
113
161
  ..MinifyOptions::default()
114
162
  })
115
- .map_err(|error| format!("Failed to minify: {error}"))?;
163
+ .map_err(|error| Failure::internal(format!("Failed to minify: {error}")))?;
116
164
  }
117
165
 
118
166
  let printed = stylesheet
@@ -124,7 +172,7 @@ fn transform_source(code: &str, options: &TransformOptions) -> Result<TransformR
124
172
  analyze_dependencies: None,
125
173
  pseudo_classes: None,
126
174
  })
127
- .map_err(|error| format!("Failed to print: {error}"))?;
175
+ .map_err(|error| Failure::internal(format!("Failed to print: {error}")))?;
128
176
 
129
177
  let exports = printed.exports.map(|exports| {
130
178
  exports
@@ -145,31 +193,37 @@ fn transform_source(code: &str, options: &TransformOptions) -> Result<TransformR
145
193
  })
146
194
  }
147
195
 
148
- fn bundle_source(path: &str, options: &TransformOptions) -> Result<TransformResult, String> {
196
+ fn bundle_source(path: &str, options: &TransformOptions) -> Result<TransformResult, Failure> {
149
197
  let css_modules = match &options.css_modules {
150
- Some(modules) => Some(modules.to_config()?),
198
+ Some(modules) => Some(modules.to_config().map_err(Failure::option)?),
151
199
  None => None,
152
200
  };
153
201
 
202
+ let provider = FileProvider::new();
203
+ let collected = Arc::new(RwLock::new(Vec::new()));
204
+
154
205
  let parser_options = ParserOptions {
155
206
  css_modules,
156
207
  error_recovery: options.error_recovery,
208
+ warnings: Some(collected.clone()),
157
209
  ..ParserOptions::default()
158
210
  };
159
211
 
160
- let provider = FileProvider::new();
161
212
  let mut bundler = Bundler::new(&provider, None, parser_options);
162
213
 
163
214
  let mut stylesheet = bundler
164
215
  .bundle(std::path::Path::new(path))
165
- .map_err(|error| error.to_string())?;
216
+ .map_err(|error| match &error.kind {
217
+ BundleErrorKind::ParserError(_) => Failure::parse(error.to_string()),
218
+ _ => Failure::bundle(error.to_string()),
219
+ })?;
166
220
 
167
221
  if let Some(fragment) = &options.scope {
168
- let mut scoper = Scoper::parse(fragment)?;
222
+ let mut scoper = Scoper::parse(fragment).map_err(Failure::option)?;
169
223
 
170
224
  stylesheet
171
225
  .visit(&mut scoper)
172
- .map_err(|error| format!("Failed to scope stylesheet: {error:?}"))?;
226
+ .map_err(|error| Failure::internal(format!("Failed to scope stylesheet: {error:?}")))?;
173
227
  }
174
228
 
175
229
  let targets = options.to_targets();
@@ -180,7 +234,7 @@ fn bundle_source(path: &str, options: &TransformOptions) -> Result<TransformResu
180
234
  targets,
181
235
  ..MinifyOptions::default()
182
236
  })
183
- .map_err(|error| format!("Failed to minify: {error}"))?;
237
+ .map_err(|error| Failure::internal(format!("Failed to minify: {error}")))?;
184
238
  }
185
239
 
186
240
  let printed = stylesheet
@@ -189,23 +243,35 @@ fn bundle_source(path: &str, options: &TransformOptions) -> Result<TransformResu
189
243
  targets,
190
244
  ..PrinterOptions::default()
191
245
  })
192
- .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();
193
259
 
194
260
  Ok(TransformResult {
195
261
  code: printed.code,
196
- exports: None,
197
- warnings: Vec::new(),
262
+ exports,
263
+ warnings,
198
264
  })
199
265
  }
200
266
 
201
- fn transform_attribute(code: &str, options: &TransformOptions) -> Result<TransformResult, String> {
267
+ fn transform_attribute(code: &str, options: &TransformOptions) -> Result<TransformResult, Failure> {
202
268
  let parser_options = ParserOptions {
203
269
  filename: options.filename.clone().unwrap_or_default(),
204
270
  error_recovery: options.error_recovery,
205
271
  ..ParserOptions::default()
206
272
  };
207
273
 
208
- 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()))?;
209
275
 
210
276
  let targets = options.to_targets();
211
277
 
@@ -220,7 +286,7 @@ fn transform_attribute(code: &str, options: &TransformOptions) -> Result<Transfo
220
286
  targets,
221
287
  ..PrinterOptions::default()
222
288
  })
223
- .map_err(|error| format!("Failed to print: {error}"))?;
289
+ .map_err(|error| Failure::internal(format!("Failed to print: {error}")))?;
224
290
 
225
291
  Ok(TransformResult {
226
292
  code: printed.code,
@@ -229,13 +295,13 @@ fn transform_attribute(code: &str, options: &TransformOptions) -> Result<Transfo
229
295
  })
230
296
  }
231
297
 
232
- fn to_result(outcome: Result<TransformResult, String>) -> LightningCssResult {
298
+ fn to_result(outcome: Result<TransformResult, Failure>) -> LightningCssResult {
233
299
  match outcome {
234
300
  Ok(result) => match serde_json::to_string(&result) {
235
301
  Ok(json) => LightningCssResult::ok(json),
236
- Err(error) => LightningCssResult::err(format!("Failed to serialize result: {error}")),
302
+ Err(error) => LightningCssResult::err(Failure::internal(format!("Failed to serialize result: {error}"))),
237
303
  },
238
- Err(message) => LightningCssResult::err(message),
304
+ Err(failure) => LightningCssResult::err(failure),
239
305
  }
240
306
  }
241
307
 
@@ -246,12 +312,12 @@ pub unsafe extern "C" fn lightningcss_transform(
246
312
  ) -> LightningCssResult {
247
313
  let code = match borrow_str(code, "code") {
248
314
  Ok(code) => code,
249
- Err(message) => return LightningCssResult::err(message),
315
+ Err(failure) => return LightningCssResult::err(failure),
250
316
  };
251
317
 
252
318
  let options = match borrow_options(options_json) {
253
319
  Ok(options) => options,
254
- Err(message) => return LightningCssResult::err(message),
320
+ Err(failure) => return LightningCssResult::err(failure),
255
321
  };
256
322
 
257
323
  to_result(transform_source(code, &options))
@@ -264,12 +330,12 @@ pub unsafe extern "C" fn lightningcss_transform_style_attribute(
264
330
  ) -> LightningCssResult {
265
331
  let code = match borrow_str(code, "code") {
266
332
  Ok(code) => code,
267
- Err(message) => return LightningCssResult::err(message),
333
+ Err(failure) => return LightningCssResult::err(failure),
268
334
  };
269
335
 
270
336
  let options = match borrow_options(options_json) {
271
337
  Ok(options) => options,
272
- Err(message) => return LightningCssResult::err(message),
338
+ Err(failure) => return LightningCssResult::err(failure),
273
339
  };
274
340
 
275
341
  to_result(transform_attribute(code, &options))
@@ -279,12 +345,12 @@ pub unsafe extern "C" fn lightningcss_transform_style_attribute(
279
345
  pub unsafe extern "C" fn lightningcss_bundle(path: *const c_char, options_json: *const c_char) -> LightningCssResult {
280
346
  let path = match borrow_str(path, "path") {
281
347
  Ok(path) => path,
282
- Err(message) => return LightningCssResult::err(message),
348
+ Err(failure) => return LightningCssResult::err(failure),
283
349
  };
284
350
 
285
351
  let options = match borrow_options(options_json) {
286
352
  Ok(options) => options,
287
- Err(message) => return LightningCssResult::err(message),
353
+ Err(failure) => return LightningCssResult::err(failure),
288
354
  };
289
355
 
290
356
  to_result(bundle_source(path, &options))
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
- //! .card .title -> .card .title[data-herb-scope-abc]
8
- //! .item::before -> .item[data-herb-scope-abc]::before
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], ?allowed: Array[Symbol], ?subject: String) -> String
19
- def self.serialize: (Hash[Symbol, untyped], ?allowed: Array[Symbol], ?subject: String) -> String
20
+ # : (Hash[Symbol, untyped], ?Array[Symbol], ?String) -> String
21
+ def self.serialize: (Hash[Symbol, untyped], ?Array[Symbol], ?String) -> String
20
22
 
21
- # : (?allowed: Array[Symbol], ?subject: String, **untyped) -> void
22
- def initialize: (?allowed: Array[Symbol], ?subject: String, **untyped) -> void
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, ?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
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, ?filename: String?, ?minify: bool, ?error_recovery: bool, ?targets: browsers?, ?css_modules: css_modules?, ?scope: String?) -> LightningCSS::Result
21
- def self.bundle: (String, ?filename: String?, ?minify: bool, ?error_recovery: bool, ?targets: browsers?, ?css_modules: css_modules?, ?scope: String?) -> LightningCSS::Result
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
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lightningcss
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: x86_64-linux-gnu
6
6
  authors:
7
7
  - Marco Roth
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-08-24 00:00:00.000000000 Z
11
+ date: 2026-08-30 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Ruby bindings for Lightning CSS, an extremely fast CSS parser, transformer,
14
14
  bundler, and minifier.