lightningcss 1.33.0-aarch64-linux-gnu → 1.33.0.2-aarch64-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.
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LightningCSS
4
+ # Walks an AST, answering each node with the method named after it and walking through anything
5
+ # nothing answers.
6
+ #
7
+ # class Colors < LightningCSS::Visitor
8
+ # def visit_declaration(node)
9
+ # puts node.value.type if node.property == "color"
10
+ # end
11
+ # end
12
+ #
13
+ # Colors.new.visit(LightningCSS.parse(".a { color: red }"))
14
+ #
15
+ # A rule is answered as one, as in `visit_style_rule` or `visit_media_rule`, since `style`,
16
+ # `nesting`, and `namespace` are also what a selector is made of.
17
+ #
18
+ class Visitor
19
+ #: (LightningCSS::Node | LightningCSS::ParseResult) -> void
20
+ def visit(node)
21
+ node = node.root if node.is_a?(ParseResult)
22
+
23
+ method_name = "visit_#{node.underscored_type}" if node.underscored_type
24
+
25
+ method_name && respond_to?(method_name) ? public_send(method_name, node) : visit_children(node)
26
+
27
+ nil
28
+ end
29
+
30
+ #: (LightningCSS::Node) -> void
31
+ def visit_children(node)
32
+ node.child_nodes.each { |child| visit(child) }
33
+
34
+ nil
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LightningCSS
4
+ class Warning
5
+ attr_reader :message #: String
6
+ attr_reader :type #: String?
7
+ attr_reader :location #: LightningCSS::Location?
8
+
9
+ #: (Hash[String, untyped]) -> LightningCSS::Warning
10
+ def self.from_hash(hash)
11
+ new(
12
+ message: hash.fetch("message"),
13
+ type: hash["type"],
14
+ location: hash["location"] && Location.from_hash(hash["location"])
15
+ )
16
+ end
17
+
18
+ #: (message: String, ?type: String?, ?location: LightningCSS::Location?) -> void
19
+ def initialize(message:, type: nil, location: nil)
20
+ @message = message
21
+ @type = type
22
+ @location = location
23
+
24
+ freeze
25
+ end
26
+
27
+ #: () -> Hash[Symbol, untyped]
28
+ def to_h
29
+ { message: message, type: type, location: location&.to_h }
30
+ end
31
+
32
+ #: () -> String
33
+ def to_s
34
+ location ? "#{message} at #{location}" : message
35
+ end
36
+
37
+ alias to_str to_s
38
+
39
+ #: (untyped) -> bool
40
+ def ==(other)
41
+ case other
42
+ when Warning then to_h == other.to_h
43
+ when String then to_s == other
44
+ else false
45
+ end
46
+ end
47
+
48
+ alias eql? ==
49
+
50
+ #: () -> Integer
51
+ def hash
52
+ to_h.hash
53
+ end
54
+
55
+ #: () -> String
56
+ def inspect
57
+ "#<#{self.class.name} #{to_s.inspect}>"
58
+ end
59
+ end
60
+ end
data/lib/lightningcss.rb CHANGED
@@ -3,6 +3,7 @@
3
3
  require "json"
4
4
 
5
5
  require_relative "lightningcss/version"
6
+ require_relative "lightningcss/location"
6
7
  require_relative "lightningcss/errors"
7
8
  require_relative "lightningcss/backend"
8
9
 
@@ -14,7 +15,11 @@ rescue LoadError
14
15
  end
15
16
 
16
17
  require_relative "lightningcss/options"
18
+ require_relative "lightningcss/warning"
17
19
  require_relative "lightningcss/result"
20
+ require_relative "lightningcss/node"
21
+ require_relative "lightningcss/parse_result"
22
+ require_relative "lightningcss/visitor"
18
23
  require_relative "lightningcss/transformer"
19
24
 
20
25
  # Ruby bindings for Lightning CSS.
@@ -28,14 +33,27 @@ require_relative "lightningcss/transformer"
28
33
  # LightningCSS.transform(".title { color: red }", scope: "[data-scope-abc]").code
29
34
  # #=> ".title[data-scope-abc]{color:red}"
30
35
  #
36
+ # `parse` returns the AST instead, to walk with `LightningCSS::Node` and `LightningCSS::Visitor`:
37
+ #
38
+ # LightningCSS.parse(".a { color: red }").root.every("declaration").first.property
39
+ # #=> "color"
40
+ #
31
41
  # `LightningCSS::Options` is what the options are read by, and `LightningCSS::Transformer` holds a
32
42
  # set of them to reuse across many stylesheets.
43
+ #
33
44
  module LightningCSS
34
45
  #: (String, ?filename: String?, ?minify: bool, ?error_recovery: bool, ?targets: browsers?, ?css_modules: css_modules?, ?scope: String?) -> LightningCSS::Result
35
46
  def self.transform(code, **options)
36
47
  Result.from_json(Backend.transform(code.to_s, Options.serialize(options)))
37
48
  end
38
49
 
50
+ #: (String, ?filename: String?, ?error_recovery: bool) -> LightningCSS::ParseResult
51
+ def self.parse(code, **options)
52
+ serialized = Options.serialize(options, Options::PARSE, "a parse")
53
+
54
+ ParseResult.from_json(Backend.parse(code.to_s, serialized), code.to_s)
55
+ end
56
+
39
57
  #: (String, ?minify: bool, ?error_recovery: bool, ?targets: browsers?, ?css_modules: css_modules?, ?scope: String?) -> LightningCSS::Result
40
58
  def self.bundle(path, **options)
41
59
  serialized = Options.serialize(options, Options::BUNDLE, "a bundle")
data/rust/Cargo.lock CHANGED
@@ -90,6 +90,9 @@ name = "bitflags"
90
90
  version = "2.13.1"
91
91
  source = "registry+https://github.com/rust-lang/crates.io-index"
92
92
  checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da"
93
+ dependencies = [
94
+ "serde_core",
95
+ ]
93
96
 
94
97
  [[package]]
95
98
  name = "bitvec"
@@ -245,6 +248,7 @@ dependencies = [
245
248
  "dtoa-short",
246
249
  "itoa",
247
250
  "phf 0.13.1",
251
+ "serde",
248
252
  "smallvec",
249
253
  ]
250
254
 
@@ -511,6 +515,7 @@ dependencies = [
511
515
  "serde",
512
516
  "serde-content",
513
517
  "smallvec",
518
+ "static-self",
514
519
  ]
515
520
 
516
521
  [[package]]
@@ -599,7 +604,9 @@ dependencies = [
599
604
  "phf_codegen",
600
605
  "precomputed-hash",
601
606
  "rustc-hash",
607
+ "serde",
602
608
  "smallvec",
609
+ "static-self",
603
610
  ]
604
611
 
605
612
  [[package]]
@@ -1002,6 +1009,31 @@ name = "smallvec"
1002
1009
  version = "1.15.2"
1003
1010
  source = "registry+https://github.com/rust-lang/crates.io-index"
1004
1011
  checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90"
1012
+ dependencies = [
1013
+ "serde",
1014
+ ]
1015
+
1016
+ [[package]]
1017
+ name = "static-self"
1018
+ version = "0.1.2"
1019
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1020
+ checksum = "f6635404b73efc136af3a7956e53c53d4f34b2f16c95a15c438929add0f69412"
1021
+ dependencies = [
1022
+ "indexmap",
1023
+ "smallvec",
1024
+ "static-self-derive",
1025
+ ]
1026
+
1027
+ [[package]]
1028
+ name = "static-self-derive"
1029
+ version = "0.1.1"
1030
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1031
+ checksum = "5268c96d4b907c558a9a52d8492522d6c7b559651a5e1d8f2d551e461b9425d5"
1032
+ dependencies = [
1033
+ "proc-macro2",
1034
+ "quote",
1035
+ "syn 1.0.109",
1036
+ ]
1005
1037
 
1006
1038
  [[package]]
1007
1039
  name = "strsim"
data/rust/Cargo.toml CHANGED
@@ -15,7 +15,7 @@ path = "src/lib.rs"
15
15
  crate-type = ["cdylib", "staticlib", "rlib"]
16
16
 
17
17
  [dependencies]
18
- lightningcss = { version = "=1.0.0-alpha.72", features = ["visitor"] }
18
+ lightningcss = { version = "=1.0.0-alpha.72", features = ["visitor", "serde"] }
19
19
  serde = { version = "1", features = ["derive"] }
20
20
  serde_json = "1"
21
21
 
data/rust/src/lib.rs CHANGED
@@ -21,7 +21,7 @@ use lightningcss::bundler::{BundleErrorKind, Bundler, FileProvider};
21
21
  use lightningcss::stylesheet::{MinifyOptions, ParserOptions, PrinterOptions, StyleAttribute, StyleSheet};
22
22
  use lightningcss::visitor::Visit;
23
23
 
24
- use crate::options::{TransformOptions, TransformResult};
24
+ use crate::options::{Diagnostic, ParseResult, TransformOptions, TransformResult};
25
25
  use crate::scope::Scoper;
26
26
 
27
27
  pub const VERSION: &str = env!("GEM_VERSION");
@@ -56,7 +56,7 @@ impl LightningCssResult {
56
56
  fn err(failure: Failure) -> Self {
57
57
  Self {
58
58
  value: ptr::null_mut(),
59
- error: into_c_string(failure.message),
59
+ error: into_c_string(serde_json::to_string(&failure.diagnostic).unwrap_or(failure.diagnostic.message)),
60
60
  code: failure.code,
61
61
  }
62
62
  }
@@ -64,35 +64,35 @@ impl LightningCssResult {
64
64
 
65
65
  pub struct Failure {
66
66
  code: LightningCssErrorCode,
67
- message: String,
67
+ diagnostic: Diagnostic,
68
68
  }
69
69
 
70
70
  impl Failure {
71
- fn parse(message: impl Into<String>) -> Self {
71
+ fn parse(diagnostic: impl Into<Diagnostic>) -> Self {
72
72
  Self {
73
73
  code: LightningCssErrorCode::Parse,
74
- message: message.into(),
74
+ diagnostic: diagnostic.into(),
75
75
  }
76
76
  }
77
77
 
78
- fn option(message: impl Into<String>) -> Self {
78
+ fn option(diagnostic: impl Into<Diagnostic>) -> Self {
79
79
  Self {
80
80
  code: LightningCssErrorCode::Option,
81
- message: message.into(),
81
+ diagnostic: diagnostic.into(),
82
82
  }
83
83
  }
84
84
 
85
- fn bundle(message: impl Into<String>) -> Self {
85
+ fn bundle(diagnostic: impl Into<Diagnostic>) -> Self {
86
86
  Self {
87
87
  code: LightningCssErrorCode::Bundle,
88
- message: message.into(),
88
+ diagnostic: diagnostic.into(),
89
89
  }
90
90
  }
91
91
 
92
- fn internal(message: impl Into<String>) -> Self {
92
+ fn internal(diagnostic: impl Into<Diagnostic>) -> Self {
93
93
  Self {
94
94
  code: LightningCssErrorCode::Internal,
95
- message: message.into(),
95
+ diagnostic: diagnostic.into(),
96
96
  }
97
97
  }
98
98
  }
@@ -125,6 +125,27 @@ unsafe fn borrow_options(pointer: *const c_char) -> Result<TransformOptions, Fai
125
125
  serde_json::from_str(json).map_err(|error| Failure::option(format!("Invalid options: {error}")))
126
126
  }
127
127
 
128
+ fn parse_source<'i>(code: &'i str, options: &TransformOptions) -> Result<ParseResult<StyleSheet<'i>>, Failure> {
129
+ let collected = Arc::new(RwLock::new(Vec::new()));
130
+
131
+ let parser_options = ParserOptions {
132
+ filename: options.filename.clone().unwrap_or_default(),
133
+ error_recovery: options.error_recovery,
134
+ warnings: Some(collected.clone()),
135
+ ..ParserOptions::default()
136
+ };
137
+
138
+ let stylesheet =
139
+ StyleSheet::parse(code, parser_options).map_err(|error| Failure::parse(Diagnostic::from_error(&error)))?;
140
+
141
+ let warnings = collected
142
+ .read()
143
+ .map(|warnings| warnings.iter().map(Diagnostic::from_error).collect())
144
+ .unwrap_or_default();
145
+
146
+ Ok(ParseResult { stylesheet, warnings })
147
+ }
148
+
128
149
  fn transform_source(code: &str, options: &TransformOptions) -> Result<TransformResult, Failure> {
129
150
  let filename = options.filename.clone().unwrap_or_default();
130
151
  let css_modules = match &options.css_modules {
@@ -142,7 +163,8 @@ fn transform_source(code: &str, options: &TransformOptions) -> Result<TransformR
142
163
  ..ParserOptions::default()
143
164
  };
144
165
 
145
- let mut stylesheet = StyleSheet::parse(code, parser_options).map_err(|error| Failure::parse(error.to_string()))?;
166
+ let mut stylesheet =
167
+ StyleSheet::parse(code, parser_options).map_err(|error| Failure::parse(Diagnostic::from_error(&error)))?;
146
168
 
147
169
  if let Some(fragment) = &options.scope {
148
170
  let mut scoper = Scoper::parse(fragment).map_err(Failure::option)?;
@@ -152,16 +174,14 @@ fn transform_source(code: &str, options: &TransformOptions) -> Result<TransformR
152
174
  .map_err(|error| Failure::internal(format!("Failed to scope stylesheet: {error:?}")))?;
153
175
  }
154
176
 
155
- let targets = options.to_targets();
177
+ let targets = options.to_targets().map_err(Failure::option)?;
156
178
 
157
- if options.minify {
158
- stylesheet
159
- .minify(MinifyOptions {
160
- targets,
161
- ..MinifyOptions::default()
162
- })
163
- .map_err(|error| Failure::internal(format!("Failed to minify: {error}")))?;
164
- }
179
+ stylesheet
180
+ .minify(MinifyOptions {
181
+ targets,
182
+ ..MinifyOptions::default()
183
+ })
184
+ .map_err(|error| Failure::internal(format!("Failed to minify: {error}")))?;
165
185
 
166
186
  let printed = stylesheet
167
187
  .to_css(PrinterOptions {
@@ -183,7 +203,7 @@ fn transform_source(code: &str, options: &TransformOptions) -> Result<TransformR
183
203
 
184
204
  let warnings = collected
185
205
  .read()
186
- .map(|warnings| warnings.iter().map(|warning| warning.to_string()).collect())
206
+ .map(|warnings| warnings.iter().map(Diagnostic::from_error).collect())
187
207
  .unwrap_or_default();
188
208
 
189
209
  Ok(TransformResult {
@@ -214,8 +234,8 @@ fn bundle_source(path: &str, options: &TransformOptions) -> Result<TransformResu
214
234
  let mut stylesheet = bundler
215
235
  .bundle(std::path::Path::new(path))
216
236
  .map_err(|error| match &error.kind {
217
- BundleErrorKind::ParserError(_) => Failure::parse(error.to_string()),
218
- _ => Failure::bundle(error.to_string()),
237
+ BundleErrorKind::ParserError(_) => Failure::parse(Diagnostic::from_error(&error)),
238
+ _ => Failure::bundle(Diagnostic::from_error(&error)),
219
239
  })?;
220
240
 
221
241
  if let Some(fragment) = &options.scope {
@@ -226,16 +246,14 @@ fn bundle_source(path: &str, options: &TransformOptions) -> Result<TransformResu
226
246
  .map_err(|error| Failure::internal(format!("Failed to scope stylesheet: {error:?}")))?;
227
247
  }
228
248
 
229
- let targets = options.to_targets();
249
+ let targets = options.to_targets().map_err(Failure::option)?;
230
250
 
231
- if options.minify {
232
- stylesheet
233
- .minify(MinifyOptions {
234
- targets,
235
- ..MinifyOptions::default()
236
- })
237
- .map_err(|error| Failure::internal(format!("Failed to minify: {error}")))?;
238
- }
251
+ stylesheet
252
+ .minify(MinifyOptions {
253
+ targets,
254
+ ..MinifyOptions::default()
255
+ })
256
+ .map_err(|error| Failure::internal(format!("Failed to minify: {error}")))?;
239
257
 
240
258
  let printed = stylesheet
241
259
  .to_css(PrinterOptions {
@@ -254,7 +272,7 @@ fn bundle_source(path: &str, options: &TransformOptions) -> Result<TransformResu
254
272
 
255
273
  let warnings = collected
256
274
  .read()
257
- .map(|warnings| warnings.iter().map(|warning| warning.to_string()).collect())
275
+ .map(|warnings| warnings.iter().map(Diagnostic::from_error).collect())
258
276
  .unwrap_or_default();
259
277
 
260
278
  Ok(TransformResult {
@@ -271,9 +289,10 @@ fn transform_attribute(code: &str, options: &TransformOptions) -> Result<Transfo
271
289
  ..ParserOptions::default()
272
290
  };
273
291
 
274
- let mut attribute = StyleAttribute::parse(code, parser_options).map_err(|error| Failure::parse(error.to_string()))?;
292
+ let mut attribute =
293
+ StyleAttribute::parse(code, parser_options).map_err(|error| Failure::parse(Diagnostic::from_error(&error)))?;
275
294
 
276
- let targets = options.to_targets();
295
+ let targets = options.to_targets().map_err(Failure::option)?;
277
296
 
278
297
  attribute.minify(MinifyOptions {
279
298
  targets,
@@ -295,7 +314,7 @@ fn transform_attribute(code: &str, options: &TransformOptions) -> Result<Transfo
295
314
  })
296
315
  }
297
316
 
298
- fn to_result(outcome: Result<TransformResult, Failure>) -> LightningCssResult {
317
+ fn to_result(outcome: Result<impl serde::Serialize, Failure>) -> LightningCssResult {
299
318
  match outcome {
300
319
  Ok(result) => match serde_json::to_string(&result) {
301
320
  Ok(json) => LightningCssResult::ok(json),
@@ -323,6 +342,21 @@ pub unsafe extern "C" fn lightningcss_transform(
323
342
  to_result(transform_source(code, &options))
324
343
  }
325
344
 
345
+ #[no_mangle]
346
+ pub unsafe extern "C" fn lightningcss_parse(code: *const c_char, options_json: *const c_char) -> LightningCssResult {
347
+ let code = match borrow_str(code, "code") {
348
+ Ok(code) => code,
349
+ Err(failure) => return LightningCssResult::err(failure),
350
+ };
351
+
352
+ let options = match borrow_options(options_json) {
353
+ Ok(options) => options,
354
+ Err(failure) => return LightningCssResult::err(failure),
355
+ };
356
+
357
+ to_result(parse_source(code, &options))
358
+ }
359
+
326
360
  #[no_mangle]
327
361
  pub unsafe extern "C" fn lightningcss_transform_style_attribute(
328
362
  code: *const c_char,
data/rust/src/options.rs CHANGED
@@ -1,6 +1,7 @@
1
1
  use std::collections::HashMap;
2
2
 
3
3
  use lightningcss::css_modules::{Config as CssModulesConfig, Pattern};
4
+ use lightningcss::error::Error;
4
5
  use lightningcss::targets::{Browsers, Targets};
5
6
  use serde::{Deserialize, Serialize};
6
7
 
@@ -10,7 +11,7 @@ pub struct TransformOptions {
10
11
  pub filename: Option<String>,
11
12
  pub minify: bool,
12
13
  pub error_recovery: bool,
13
- pub targets: Option<HashMap<String, u32>>,
14
+ pub targets: Option<HashMap<String, Version>>,
14
15
  pub css_modules: Option<CssModulesOptions>,
15
16
  pub scope: Option<String>,
16
17
  }
@@ -60,16 +61,61 @@ impl CssModulesOptions {
60
61
  }
61
62
  }
62
63
 
64
+ #[derive(Debug, Deserialize)]
65
+ #[serde(untagged)]
66
+ pub enum Version {
67
+ Major(u32),
68
+ Float(f64),
69
+ String(String),
70
+ }
71
+
72
+ impl Version {
73
+ /// Encodes a version the way Lightning CSS reads it, as `major << 16 | minor << 8 | patch`.
74
+ fn encode(&self) -> Option<u32> {
75
+ match self {
76
+ Version::Major(major) => (*major <= 0xffff).then(|| major << 16),
77
+ Version::Float(float) => Self::parse(&float.to_string()),
78
+ Version::String(string) => Self::parse(string),
79
+ }
80
+ }
81
+
82
+ fn parse(version: &str) -> Option<u32> {
83
+ let mut parts = version.trim().split('.');
84
+
85
+ let major: u16 = parts.next()?.parse().ok()?;
86
+ let minor: u8 = parts.next().map_or(Some(0), |part| part.parse().ok())?;
87
+ let patch: u8 = parts.next().map_or(Some(0), |part| part.parse().ok())?;
88
+
89
+ if parts.next().is_some() {
90
+ return None;
91
+ }
92
+
93
+ Some(u32::from(major) << 16 | u32::from(minor) << 8 | u32::from(patch))
94
+ }
95
+
96
+ fn describe(&self) -> String {
97
+ match self {
98
+ Version::Major(major) => major.to_string(),
99
+ Version::Float(float) => float.to_string(),
100
+ Version::String(string) => format!("{string:?}"),
101
+ }
102
+ }
103
+ }
104
+
63
105
  impl TransformOptions {
64
- pub fn to_targets(&self) -> Targets {
106
+ pub fn to_targets(&self) -> Result<Targets, String> {
65
107
  let Some(versions) = &self.targets else {
66
- return Targets::default();
108
+ return Ok(Targets::default());
67
109
  };
68
110
 
69
111
  let mut browsers = Browsers::default();
70
112
 
71
113
  for (name, version) in versions {
72
- let encoded = Some(version << 16);
114
+ let encoded = Some(
115
+ version
116
+ .encode()
117
+ .ok_or_else(|| format!("Invalid version {} for {name} in targets", version.describe()))?,
118
+ );
73
119
 
74
120
  match name.as_str() {
75
121
  "android" => browsers.android = encoded,
@@ -85,14 +131,81 @@ impl TransformOptions {
85
131
  }
86
132
  }
87
133
 
88
- Targets::from(browsers)
134
+ Ok(Targets::from(browsers))
89
135
  }
90
136
  }
91
137
 
138
+ #[derive(Debug, Serialize)]
139
+ pub struct ParseResult<T> {
140
+ pub stylesheet: T,
141
+ pub warnings: Vec<Diagnostic>,
142
+ }
143
+
92
144
  #[derive(Debug, Serialize)]
93
145
  pub struct TransformResult {
94
146
  pub code: String,
95
147
  #[serde(skip_serializing_if = "Option::is_none")]
96
148
  pub exports: Option<HashMap<String, String>>,
97
- pub warnings: Vec<String>,
149
+ pub warnings: Vec<Diagnostic>,
150
+ }
151
+
152
+ #[derive(Debug, Serialize)]
153
+ pub struct Diagnostic {
154
+ pub message: String,
155
+ #[serde(rename = "type", skip_serializing_if = "Option::is_none")]
156
+ pub kind: Option<String>,
157
+ #[serde(skip_serializing_if = "Option::is_none")]
158
+ pub location: Option<Location>,
159
+ }
160
+
161
+ #[derive(Debug, Serialize)]
162
+ pub struct Location {
163
+ pub filename: Option<String>,
164
+ pub line: u32,
165
+ pub column: u32,
166
+ }
167
+
168
+ impl Diagnostic {
169
+ pub fn from_error<T: std::fmt::Display + Serialize>(error: &Error<T>) -> Self {
170
+ Self {
171
+ message: error.kind.to_string(),
172
+ kind: serde_json::to_value(&error.kind).ok().as_ref().and_then(type_of),
173
+ location: error.loc.as_ref().map(|location| Location {
174
+ filename: (!location.filename.is_empty()).then(|| location.filename.clone()),
175
+ line: location.line + 1,
176
+ column: location.column.saturating_sub(1),
177
+ }),
178
+ }
179
+ }
180
+ }
181
+
182
+ impl From<String> for Diagnostic {
183
+ fn from(message: String) -> Self {
184
+ Self {
185
+ message,
186
+ kind: None,
187
+ location: None,
188
+ }
189
+ }
190
+ }
191
+
192
+ impl From<&str> for Diagnostic {
193
+ fn from(message: &str) -> Self {
194
+ Self::from(message.to_string())
195
+ }
196
+ }
197
+
198
+ fn type_of(value: &serde_json::Value) -> Option<String> {
199
+ match value {
200
+ serde_json::Value::String(name) => Some(name.clone()),
201
+ serde_json::Value::Object(fields) => match fields.get("type") {
202
+ Some(serde_json::Value::String(name)) => Some(name.clone()),
203
+ _ if fields.len() == 1 => fields.iter().next().map(|(name, inner)| match inner.get("type") {
204
+ Some(serde_json::Value::String(inner_name)) => inner_name.clone(),
205
+ _ => name.clone(),
206
+ }),
207
+ _ => None,
208
+ },
209
+ _ => None,
210
+ }
98
211
  }
data/rust/src/scope.rs CHANGED
@@ -29,7 +29,8 @@ impl<'i> Scoper<'i> {
29
29
  let list = SelectorList::parse_string_with_options(fragment, ParserOptions::default()).map_err(|error| {
30
30
  format!(
31
31
  "Invalid scope selector {fragment:?} at :{}:{}",
32
- error.location.line, error.location.column
32
+ error.location.line + 1,
33
+ error.location.column
33
34
  )
34
35
  })?;
35
36
 
@@ -6,6 +6,9 @@ module LightningCSS
6
6
  # : (String, String) -> String
7
7
  def transform: (String, String) -> String
8
8
 
9
+ # : (String, String) -> String
10
+ def parse: (String, String) -> String
11
+
9
12
  # : (String, String) -> String
10
13
  def transform_style_attribute: (String, String) -> String
11
14
 
@@ -2,6 +2,15 @@
2
2
 
3
3
  module LightningCSS
4
4
  class Error < StandardError
5
+ attr_reader type: String?
6
+
7
+ attr_reader location: LightningCSS::Location?
8
+
9
+ # : (String) -> instance
10
+ def self.from_json: (String) -> instance
11
+
12
+ # : (?String?, ?type: String?, ?location: LightningCSS::Location?) -> void
13
+ def initialize: (?String?, ?type: String?, ?location: LightningCSS::Location?) -> void
5
14
  end
6
15
 
7
16
  class ParseError < Error
@@ -0,0 +1,26 @@
1
+ # Generated from lib/lightningcss/location.rb with RBS::Inline
2
+
3
+ module LightningCSS
4
+ class Location < Data
5
+ attr_reader filename(): String?
6
+
7
+ attr_reader line(): Integer
8
+
9
+ attr_reader column(): Integer
10
+
11
+ def self.new: (String? filename, Integer line, Integer column) -> instance
12
+ | (filename: String?, line: Integer, column: Integer) -> instance
13
+
14
+ def self.members: () -> [ :filename, :line, :column ]
15
+
16
+ def members: () -> [ :filename, :line, :column ]
17
+ end
18
+
19
+ class Location
20
+ # : (Hash[String, untyped]) -> LightningCSS::Location
21
+ def self.from_hash: (Hash[String, untyped]) -> LightningCSS::Location
22
+
23
+ # : () -> String
24
+ def to_s: () -> String
25
+ end
26
+ end