lightningcss 1.33.0.1-arm-linux-gnu → 1.33.0.2-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 +4 -4
- data/README.md +44 -5
- data/ext/lightningcss/lightningcss.c +2 -2
- 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/errors.rb +22 -1
- data/lib/lightningcss/location.rb +21 -0
- data/lib/lightningcss/parse_result.rb +4 -4
- data/lib/lightningcss/result.rb +4 -4
- data/lib/lightningcss/version.rb +1 -1
- data/lib/lightningcss/warning.rb +60 -0
- data/lib/lightningcss.rb +2 -0
- data/rust/src/lib.rs +37 -38
- data/rust/src/options.rs +114 -7
- data/rust/src/scope.rs +2 -1
- data/sig/lightningcss/errors.rbs +9 -0
- data/sig/lightningcss/location.rbs +26 -0
- data/sig/lightningcss/parse_result.rbs +3 -3
- data/sig/lightningcss/result.rbs +3 -3
- data/sig/lightningcss/types.rbs +12 -10
- data/sig/lightningcss/warning.rbs +36 -0
- metadata +6 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5e39ac08bd6aa2cddde39814ee33d33e4f93aed2d42ebba1b26bfbbe762263ad
|
|
4
|
+
data.tar.gz: '090e13ec9176bfb0e3f33b38b329e508258357bffaac40bdd8010766b7f928aa'
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1259d0850b3ba1263611a438ead3d90ac26ba35dc3a009c8187d16f44f9df3cc8865a2d053da01500148d821dce361d7e7395ddae8ae860c972338b6e2785290
|
|
7
|
+
data.tar.gz: 9fea6113eaab9550d06211fa958d0053a67b2510318944c4f515ca2c4efe84725183dbfe6f88ee7da51688b4e3ee12a4229f5ff3bee36734c60a5560c9d2ec4a
|
data/README.md
CHANGED
|
@@ -57,13 +57,25 @@ LightningCSS.minify(".a { color: #ff0000 }")
|
|
|
57
57
|
|
|
58
58
|
#### Targeting browsers
|
|
59
59
|
|
|
60
|
-
Give the browsers you support, each
|
|
60
|
+
Give the browsers you support, each with the oldest version you support. Anything they cannot read is lowered, with the original kept after it so that a browser which understands it still wins.
|
|
61
61
|
|
|
62
62
|
```ruby
|
|
63
63
|
LightningCSS.transform(".a { color: lab(50% 40 59) }", targets: { chrome: 80 }, minify: true).code
|
|
64
64
|
#=> ".a{color:#bf5702;color:lab(50% 40 59)}"
|
|
65
65
|
```
|
|
66
66
|
|
|
67
|
+
A version is an `Integer` for a major version, or a `Float` or `String` for a minor or patch release. Several features first shipped in a minor Safari release, so the minor version can change the output.
|
|
68
|
+
|
|
69
|
+
```ruby
|
|
70
|
+
LightningCSS.transform(".a { color: oklch(60% .2 30) }", targets: { safari: 15 }, minify: true).code
|
|
71
|
+
#=> ".a{color:lab(51.6908% 61.9679 48.0969)}"
|
|
72
|
+
|
|
73
|
+
LightningCSS.transform(".a { color: oklch(60% .2 30) }", targets: { safari: "15.4" }, minify: true).code
|
|
74
|
+
#=> ".a{color:oklch(60% .2 30)}"
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Prefer a `String` for a minor version above 9, since `16.10` as a `Float` is `16.1`.
|
|
78
|
+
|
|
67
79
|
#### Bundling
|
|
68
80
|
|
|
69
81
|
`bundle` resolves the `@import` statements a stylesheet was written with by reading the files they name, so it takes a path on disk to the entry stylesheet.
|
|
@@ -83,7 +95,7 @@ result.exports
|
|
|
83
95
|
#=> {"application" => "_8Z4fiW_application"}
|
|
84
96
|
|
|
85
97
|
result.warnings.first
|
|
86
|
-
#=> "'deep' is not recognized as a valid pseudo-class. ... at app/assets/stylesheets/layout.css:
|
|
98
|
+
#=> "'deep' is not recognized as a valid pseudo-class. ... at app/assets/stylesheets/layout.css:1:9"
|
|
87
99
|
```
|
|
88
100
|
|
|
89
101
|
#### CSS modules
|
|
@@ -271,7 +283,7 @@ It answers `call` as well, so it can be handed to anything expecting something c
|
|
|
271
283
|
| `filename` | `String` | The name to use in errors and warnings. |
|
|
272
284
|
| `minify` | `bool` | Whether to print the result as small as it goes. |
|
|
273
285
|
| `error_recovery` | `bool` | Whether to carry on past a rule it cannot read. Off by default, so such a rule raises. |
|
|
274
|
-
| `targets` | `Hash` | The browsers being compiled for, each
|
|
286
|
+
| `targets` | `Hash` | The browsers being compiled for, each with the oldest version supported. |
|
|
275
287
|
| `css_modules` | `bool`, `Hash` | Whether to compile as a CSS module, and how. |
|
|
276
288
|
| `scope` | `String` | A selector fragment to narrow every rule by. |
|
|
277
289
|
|
|
@@ -325,13 +337,40 @@ result = LightningCSS.transform(".a:deep(.b) { color: red }", minify: true)
|
|
|
325
337
|
result.warnings?
|
|
326
338
|
#=> true
|
|
327
339
|
|
|
328
|
-
result.warnings.first
|
|
329
|
-
#=> "'deep' is not recognized as a valid pseudo-class. Did you mean '::deep' (pseudo-element) or is this a typo? at :
|
|
340
|
+
result.warnings.first.to_s
|
|
341
|
+
#=> "'deep' is not recognized as a valid pseudo-class. Did you mean '::deep' (pseudo-element) or is this a typo? at :1:9"
|
|
330
342
|
|
|
331
343
|
result.code
|
|
332
344
|
#=> ".a:deep(.b){color:red}"
|
|
333
345
|
```
|
|
334
346
|
|
|
347
|
+
### Locations
|
|
348
|
+
|
|
349
|
+
A warning is a `LightningCSS::Warning` with a `message`, a `type`, and a `location`, the same as a diagnostic in Prism or Herb. A `LightningCSS::Error` carries the same `type` and `location`, and keeps the location in its message.
|
|
350
|
+
|
|
351
|
+
A `LightningCSS::Location` counts lines from 1 and columns from 0, the same as Prism, Herb, and Yerba, and prints the way an editor reads it:
|
|
352
|
+
|
|
353
|
+
```ruby
|
|
354
|
+
css = ".a { color: red; }\n.b, { color: blue; }\n"
|
|
355
|
+
|
|
356
|
+
begin
|
|
357
|
+
LightningCSS.transform(css, filename: "main.css")
|
|
358
|
+
rescue LightningCSS::ParseError => error
|
|
359
|
+
error.message #=> "Invalid empty selector at main.css:2:5"
|
|
360
|
+
error.type #=> "SelectorError"
|
|
361
|
+
error.location #=> #<data LightningCSS::Location filename="main.css", line=2, column=4>
|
|
362
|
+
end
|
|
363
|
+
|
|
364
|
+
warning = LightningCSS.transform(css, filename: "main.css", error_recovery: true).warnings.first
|
|
365
|
+
|
|
366
|
+
warning.message #=> "Invalid empty selector"
|
|
367
|
+
warning.type #=> "SelectorError"
|
|
368
|
+
warning.location.line #=> 2
|
|
369
|
+
warning.to_s #=> "Invalid empty selector at main.css:2:5"
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
A warning converts to the string it always was wherever a `String` is expected and is equal to it, so `warnings.include?("...")` still works. An error without a location, such as an `OptionError`, has `nil` for `type` and `location`.
|
|
373
|
+
|
|
335
374
|
### Development
|
|
336
375
|
|
|
337
376
|
The gem is a C extension over a Rust crate. `rust/` builds a static library and generates the C header with [cbindgen](https://github.com/mozilla/cbindgen), `ext/lightningcss/` wraps it, and `lib/` is the Ruby API over that.
|
|
@@ -43,12 +43,12 @@ static VALUE error_class_for(enum LightningCssErrorCode code) {
|
|
|
43
43
|
|
|
44
44
|
static VALUE unwrap(struct LightningCssResult result) {
|
|
45
45
|
if (result.error) {
|
|
46
|
-
VALUE
|
|
46
|
+
VALUE payload = make_utf8_string(result.error);
|
|
47
47
|
VALUE error_class = error_class_for(result.code);
|
|
48
48
|
|
|
49
49
|
lightningcss_result_free(result);
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
rb_exc_raise(rb_funcall(error_class, rb_intern("from_json"), 1, payload));
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
if (!result.value) {
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
data/lib/lightningcss/errors.rb
CHANGED
|
@@ -1,7 +1,28 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module LightningCSS
|
|
4
|
-
class Error < StandardError
|
|
4
|
+
class Error < StandardError
|
|
5
|
+
attr_reader :type #: String?
|
|
6
|
+
attr_reader :location #: LightningCSS::Location?
|
|
7
|
+
|
|
8
|
+
#: (String) -> instance
|
|
9
|
+
def self.from_json(payload)
|
|
10
|
+
parsed = JSON.parse(payload)
|
|
11
|
+
location = parsed["location"] && Location.from_hash(parsed["location"])
|
|
12
|
+
message = parsed.fetch("message")
|
|
13
|
+
|
|
14
|
+
new(location ? "#{message} at #{location}" : message, type: parsed["type"], location: location)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
#: (?String?, ?type: String?, ?location: LightningCSS::Location?) -> void
|
|
18
|
+
def initialize(message = nil, type: nil, location: nil)
|
|
19
|
+
super(message)
|
|
20
|
+
|
|
21
|
+
@type = type
|
|
22
|
+
@location = location
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
5
26
|
class ParseError < Error; end
|
|
6
27
|
class OptionError < Error; end
|
|
7
28
|
class BundleError < Error; end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module LightningCSS
|
|
4
|
+
Location = Data.define(
|
|
5
|
+
:filename, #: String?
|
|
6
|
+
:line, #: Integer
|
|
7
|
+
:column #: Integer
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
class Location
|
|
11
|
+
#: (Hash[String, untyped]) -> LightningCSS::Location
|
|
12
|
+
def self.from_hash(hash)
|
|
13
|
+
new(filename: hash["filename"], line: hash.fetch("line"), column: hash.fetch("column"))
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
#: () -> String
|
|
17
|
+
def to_s
|
|
18
|
+
"#{filename}:#{line}:#{column + 1}"
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -9,7 +9,7 @@ module LightningCSS
|
|
|
9
9
|
class ParseResult
|
|
10
10
|
attr_reader :source #: String?
|
|
11
11
|
attr_reader :stylesheet #: Hash[String, untyped]
|
|
12
|
-
attr_reader :warnings #: Array[
|
|
12
|
+
attr_reader :warnings #: Array[LightningCSS::Warning]
|
|
13
13
|
|
|
14
14
|
#: (String, ?String?) -> LightningCSS::ParseResult
|
|
15
15
|
def self.from_json(payload, source = nil)
|
|
@@ -18,11 +18,11 @@ module LightningCSS
|
|
|
18
18
|
new(
|
|
19
19
|
source: source,
|
|
20
20
|
stylesheet: parsed.fetch("stylesheet"),
|
|
21
|
-
warnings: parsed.fetch("warnings")
|
|
21
|
+
warnings: parsed.fetch("warnings").map { |warning| Warning.from_hash(warning) }
|
|
22
22
|
)
|
|
23
23
|
end
|
|
24
24
|
|
|
25
|
-
#: (stylesheet: Hash[String, untyped], warnings: Array[
|
|
25
|
+
#: (stylesheet: Hash[String, untyped], warnings: Array[LightningCSS::Warning], ?source: String?) -> void
|
|
26
26
|
def initialize(stylesheet:, warnings:, source: nil)
|
|
27
27
|
@source = source
|
|
28
28
|
@stylesheet = stylesheet.freeze
|
|
@@ -44,7 +44,7 @@ module LightningCSS
|
|
|
44
44
|
#: () -> String
|
|
45
45
|
def inspect
|
|
46
46
|
parts = ["rules=#{stylesheet.fetch("rules").length}"]
|
|
47
|
-
parts << "warnings=#{warnings.inspect}" if warnings?
|
|
47
|
+
parts << "warnings=#{warnings.map(&:to_s).inspect}" if warnings?
|
|
48
48
|
|
|
49
49
|
"#<#{self.class.name} #{parts.join(" ")}>"
|
|
50
50
|
end
|
data/lib/lightningcss/result.rb
CHANGED
|
@@ -13,7 +13,7 @@ module LightningCSS
|
|
|
13
13
|
class Result
|
|
14
14
|
attr_reader :code #: String
|
|
15
15
|
attr_reader :exports #: Hash[String, String]?
|
|
16
|
-
attr_reader :warnings #: Array[
|
|
16
|
+
attr_reader :warnings #: Array[LightningCSS::Warning]
|
|
17
17
|
|
|
18
18
|
#: (String) -> LightningCSS::Result
|
|
19
19
|
def self.from_json(payload)
|
|
@@ -22,11 +22,11 @@ module LightningCSS
|
|
|
22
22
|
new(
|
|
23
23
|
code: parsed.fetch("code"),
|
|
24
24
|
exports: parsed["exports"],
|
|
25
|
-
warnings: parsed.fetch("warnings")
|
|
25
|
+
warnings: parsed.fetch("warnings").map { |warning| Warning.from_hash(warning) }
|
|
26
26
|
)
|
|
27
27
|
end
|
|
28
28
|
|
|
29
|
-
#: (code: String, warnings: Array[
|
|
29
|
+
#: (code: String, warnings: Array[LightningCSS::Warning], ?exports: Hash[String, String]?) -> void
|
|
30
30
|
def initialize(code:, warnings:, exports: nil)
|
|
31
31
|
@code = code
|
|
32
32
|
@exports = exports
|
|
@@ -49,7 +49,7 @@ module LightningCSS
|
|
|
49
49
|
def inspect
|
|
50
50
|
parts = ["code=#{code.inspect}"]
|
|
51
51
|
parts << "exports=#{exports.inspect}" if exports
|
|
52
|
-
parts << "warnings=#{warnings.inspect}" if warnings?
|
|
52
|
+
parts << "warnings=#{warnings.map(&:to_s).inspect}" if warnings?
|
|
53
53
|
|
|
54
54
|
"#<#{self.class.name} #{parts.join(" ")}>"
|
|
55
55
|
end
|
data/lib/lightningcss/version.rb
CHANGED
|
@@ -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,6 +15,7 @@ rescue LoadError
|
|
|
14
15
|
end
|
|
15
16
|
|
|
16
17
|
require_relative "lightningcss/options"
|
|
18
|
+
require_relative "lightningcss/warning"
|
|
17
19
|
require_relative "lightningcss/result"
|
|
18
20
|
require_relative "lightningcss/node"
|
|
19
21
|
require_relative "lightningcss/parse_result"
|
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::{ParseResult, 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
|
-
|
|
67
|
+
diagnostic: Diagnostic,
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
impl Failure {
|
|
71
|
-
fn parse(
|
|
71
|
+
fn parse(diagnostic: impl Into<Diagnostic>) -> Self {
|
|
72
72
|
Self {
|
|
73
73
|
code: LightningCssErrorCode::Parse,
|
|
74
|
-
|
|
74
|
+
diagnostic: diagnostic.into(),
|
|
75
75
|
}
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
-
fn option(
|
|
78
|
+
fn option(diagnostic: impl Into<Diagnostic>) -> Self {
|
|
79
79
|
Self {
|
|
80
80
|
code: LightningCssErrorCode::Option,
|
|
81
|
-
|
|
81
|
+
diagnostic: diagnostic.into(),
|
|
82
82
|
}
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
-
fn bundle(
|
|
85
|
+
fn bundle(diagnostic: impl Into<Diagnostic>) -> Self {
|
|
86
86
|
Self {
|
|
87
87
|
code: LightningCssErrorCode::Bundle,
|
|
88
|
-
|
|
88
|
+
diagnostic: diagnostic.into(),
|
|
89
89
|
}
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
-
fn internal(
|
|
92
|
+
fn internal(diagnostic: impl Into<Diagnostic>) -> Self {
|
|
93
93
|
Self {
|
|
94
94
|
code: LightningCssErrorCode::Internal,
|
|
95
|
-
|
|
95
|
+
diagnostic: diagnostic.into(),
|
|
96
96
|
}
|
|
97
97
|
}
|
|
98
98
|
}
|
|
@@ -135,11 +135,12 @@ fn parse_source<'i>(code: &'i str, options: &TransformOptions) -> Result<ParseRe
|
|
|
135
135
|
..ParserOptions::default()
|
|
136
136
|
};
|
|
137
137
|
|
|
138
|
-
let stylesheet =
|
|
138
|
+
let stylesheet =
|
|
139
|
+
StyleSheet::parse(code, parser_options).map_err(|error| Failure::parse(Diagnostic::from_error(&error)))?;
|
|
139
140
|
|
|
140
141
|
let warnings = collected
|
|
141
142
|
.read()
|
|
142
|
-
.map(|warnings| warnings.iter().map(
|
|
143
|
+
.map(|warnings| warnings.iter().map(Diagnostic::from_error).collect())
|
|
143
144
|
.unwrap_or_default();
|
|
144
145
|
|
|
145
146
|
Ok(ParseResult { stylesheet, warnings })
|
|
@@ -162,7 +163,8 @@ fn transform_source(code: &str, options: &TransformOptions) -> Result<TransformR
|
|
|
162
163
|
..ParserOptions::default()
|
|
163
164
|
};
|
|
164
165
|
|
|
165
|
-
let mut stylesheet =
|
|
166
|
+
let mut stylesheet =
|
|
167
|
+
StyleSheet::parse(code, parser_options).map_err(|error| Failure::parse(Diagnostic::from_error(&error)))?;
|
|
166
168
|
|
|
167
169
|
if let Some(fragment) = &options.scope {
|
|
168
170
|
let mut scoper = Scoper::parse(fragment).map_err(Failure::option)?;
|
|
@@ -172,16 +174,14 @@ fn transform_source(code: &str, options: &TransformOptions) -> Result<TransformR
|
|
|
172
174
|
.map_err(|error| Failure::internal(format!("Failed to scope stylesheet: {error:?}")))?;
|
|
173
175
|
}
|
|
174
176
|
|
|
175
|
-
let targets = options.to_targets()
|
|
177
|
+
let targets = options.to_targets().map_err(Failure::option)?;
|
|
176
178
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
.map_err(|error| Failure::internal(format!("Failed to minify: {error}")))?;
|
|
184
|
-
}
|
|
179
|
+
stylesheet
|
|
180
|
+
.minify(MinifyOptions {
|
|
181
|
+
targets,
|
|
182
|
+
..MinifyOptions::default()
|
|
183
|
+
})
|
|
184
|
+
.map_err(|error| Failure::internal(format!("Failed to minify: {error}")))?;
|
|
185
185
|
|
|
186
186
|
let printed = stylesheet
|
|
187
187
|
.to_css(PrinterOptions {
|
|
@@ -203,7 +203,7 @@ fn transform_source(code: &str, options: &TransformOptions) -> Result<TransformR
|
|
|
203
203
|
|
|
204
204
|
let warnings = collected
|
|
205
205
|
.read()
|
|
206
|
-
.map(|warnings| warnings.iter().map(
|
|
206
|
+
.map(|warnings| warnings.iter().map(Diagnostic::from_error).collect())
|
|
207
207
|
.unwrap_or_default();
|
|
208
208
|
|
|
209
209
|
Ok(TransformResult {
|
|
@@ -234,8 +234,8 @@ fn bundle_source(path: &str, options: &TransformOptions) -> Result<TransformResu
|
|
|
234
234
|
let mut stylesheet = bundler
|
|
235
235
|
.bundle(std::path::Path::new(path))
|
|
236
236
|
.map_err(|error| match &error.kind {
|
|
237
|
-
BundleErrorKind::ParserError(_) => Failure::parse(error
|
|
238
|
-
_ => Failure::bundle(error
|
|
237
|
+
BundleErrorKind::ParserError(_) => Failure::parse(Diagnostic::from_error(&error)),
|
|
238
|
+
_ => Failure::bundle(Diagnostic::from_error(&error)),
|
|
239
239
|
})?;
|
|
240
240
|
|
|
241
241
|
if let Some(fragment) = &options.scope {
|
|
@@ -246,16 +246,14 @@ fn bundle_source(path: &str, options: &TransformOptions) -> Result<TransformResu
|
|
|
246
246
|
.map_err(|error| Failure::internal(format!("Failed to scope stylesheet: {error:?}")))?;
|
|
247
247
|
}
|
|
248
248
|
|
|
249
|
-
let targets = options.to_targets()
|
|
249
|
+
let targets = options.to_targets().map_err(Failure::option)?;
|
|
250
250
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
.map_err(|error| Failure::internal(format!("Failed to minify: {error}")))?;
|
|
258
|
-
}
|
|
251
|
+
stylesheet
|
|
252
|
+
.minify(MinifyOptions {
|
|
253
|
+
targets,
|
|
254
|
+
..MinifyOptions::default()
|
|
255
|
+
})
|
|
256
|
+
.map_err(|error| Failure::internal(format!("Failed to minify: {error}")))?;
|
|
259
257
|
|
|
260
258
|
let printed = stylesheet
|
|
261
259
|
.to_css(PrinterOptions {
|
|
@@ -274,7 +272,7 @@ fn bundle_source(path: &str, options: &TransformOptions) -> Result<TransformResu
|
|
|
274
272
|
|
|
275
273
|
let warnings = collected
|
|
276
274
|
.read()
|
|
277
|
-
.map(|warnings| warnings.iter().map(
|
|
275
|
+
.map(|warnings| warnings.iter().map(Diagnostic::from_error).collect())
|
|
278
276
|
.unwrap_or_default();
|
|
279
277
|
|
|
280
278
|
Ok(TransformResult {
|
|
@@ -291,9 +289,10 @@ fn transform_attribute(code: &str, options: &TransformOptions) -> Result<Transfo
|
|
|
291
289
|
..ParserOptions::default()
|
|
292
290
|
};
|
|
293
291
|
|
|
294
|
-
let mut attribute =
|
|
292
|
+
let mut attribute =
|
|
293
|
+
StyleAttribute::parse(code, parser_options).map_err(|error| Failure::parse(Diagnostic::from_error(&error)))?;
|
|
295
294
|
|
|
296
|
-
let targets = options.to_targets()
|
|
295
|
+
let targets = options.to_targets().map_err(Failure::option)?;
|
|
297
296
|
|
|
298
297
|
attribute.minify(MinifyOptions {
|
|
299
298
|
targets,
|
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,
|
|
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(
|
|
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,14 @@ impl TransformOptions {
|
|
|
85
131
|
}
|
|
86
132
|
}
|
|
87
133
|
|
|
88
|
-
Targets::from(browsers)
|
|
134
|
+
Ok(Targets::from(browsers))
|
|
89
135
|
}
|
|
90
136
|
}
|
|
91
137
|
|
|
92
138
|
#[derive(Debug, Serialize)]
|
|
93
139
|
pub struct ParseResult<T> {
|
|
94
140
|
pub stylesheet: T,
|
|
95
|
-
pub warnings: Vec<
|
|
141
|
+
pub warnings: Vec<Diagnostic>,
|
|
96
142
|
}
|
|
97
143
|
|
|
98
144
|
#[derive(Debug, Serialize)]
|
|
@@ -100,5 +146,66 @@ pub struct TransformResult {
|
|
|
100
146
|
pub code: String,
|
|
101
147
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
102
148
|
pub exports: Option<HashMap<String, String>>,
|
|
103
|
-
pub warnings: Vec<
|
|
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
|
+
}
|
|
104
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,
|
|
32
|
+
error.location.line + 1,
|
|
33
|
+
error.location.column
|
|
33
34
|
)
|
|
34
35
|
})?;
|
|
35
36
|
|
data/sig/lightningcss/errors.rbs
CHANGED
|
@@ -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
|
|
@@ -10,13 +10,13 @@ module LightningCSS
|
|
|
10
10
|
|
|
11
11
|
attr_reader stylesheet: Hash[String, untyped]
|
|
12
12
|
|
|
13
|
-
attr_reader warnings: Array[
|
|
13
|
+
attr_reader warnings: Array[LightningCSS::Warning]
|
|
14
14
|
|
|
15
15
|
# : (String, ?String?) -> LightningCSS::ParseResult
|
|
16
16
|
def self.from_json: (String, ?String?) -> LightningCSS::ParseResult
|
|
17
17
|
|
|
18
|
-
# : (stylesheet: Hash[String, untyped], warnings: Array[
|
|
19
|
-
def initialize: (stylesheet: Hash[String, untyped], warnings: Array[
|
|
18
|
+
# : (stylesheet: Hash[String, untyped], warnings: Array[LightningCSS::Warning], ?source: String?) -> void
|
|
19
|
+
def initialize: (stylesheet: Hash[String, untyped], warnings: Array[LightningCSS::Warning], ?source: String?) -> void
|
|
20
20
|
|
|
21
21
|
# : () -> LightningCSS::Node
|
|
22
22
|
def root: () -> LightningCSS::Node
|
data/sig/lightningcss/result.rbs
CHANGED
|
@@ -14,13 +14,13 @@ module LightningCSS
|
|
|
14
14
|
|
|
15
15
|
attr_reader exports: Hash[String, String]?
|
|
16
16
|
|
|
17
|
-
attr_reader warnings: Array[
|
|
17
|
+
attr_reader warnings: Array[LightningCSS::Warning]
|
|
18
18
|
|
|
19
19
|
# : (String) -> LightningCSS::Result
|
|
20
20
|
def self.from_json: (String) -> LightningCSS::Result
|
|
21
21
|
|
|
22
|
-
# : (code: String, warnings: Array[
|
|
23
|
-
def initialize: (code: String, warnings: Array[
|
|
22
|
+
# : (code: String, warnings: Array[LightningCSS::Warning], ?exports: Hash[String, String]?) -> void
|
|
23
|
+
def initialize: (code: String, warnings: Array[LightningCSS::Warning], ?exports: Hash[String, String]?) -> void
|
|
24
24
|
|
|
25
25
|
# : () -> bool
|
|
26
26
|
def warnings?: () -> bool
|
data/sig/lightningcss/types.rbs
CHANGED
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
# Note: This file is hand written, `rbs-inline` does not generate this file.
|
|
2
2
|
|
|
3
3
|
module LightningCSS
|
|
4
|
+
type version = Integer | Float | String
|
|
5
|
+
|
|
4
6
|
type browsers = {
|
|
5
|
-
?android:
|
|
6
|
-
?chrome:
|
|
7
|
-
?edge:
|
|
8
|
-
?firefox:
|
|
9
|
-
?ie:
|
|
10
|
-
?ios:
|
|
11
|
-
?ios_saf:
|
|
12
|
-
?opera:
|
|
13
|
-
?safari:
|
|
14
|
-
?samsung:
|
|
7
|
+
?android: version,
|
|
8
|
+
?chrome: version,
|
|
9
|
+
?edge: version,
|
|
10
|
+
?firefox: version,
|
|
11
|
+
?ie: version,
|
|
12
|
+
?ios: version,
|
|
13
|
+
?ios_saf: version,
|
|
14
|
+
?opera: version,
|
|
15
|
+
?safari: version,
|
|
16
|
+
?samsung: version
|
|
15
17
|
}
|
|
16
18
|
|
|
17
19
|
type css_modules = bool | {
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Generated from lib/lightningcss/warning.rb with RBS::Inline
|
|
2
|
+
|
|
3
|
+
module LightningCSS
|
|
4
|
+
class Warning
|
|
5
|
+
attr_reader message: String
|
|
6
|
+
|
|
7
|
+
attr_reader type: String?
|
|
8
|
+
|
|
9
|
+
attr_reader location: LightningCSS::Location?
|
|
10
|
+
|
|
11
|
+
# : (Hash[String, untyped]) -> LightningCSS::Warning
|
|
12
|
+
def self.from_hash: (Hash[String, untyped]) -> LightningCSS::Warning
|
|
13
|
+
|
|
14
|
+
# : (message: String, ?type: String?, ?location: LightningCSS::Location?) -> void
|
|
15
|
+
def initialize: (message: String, ?type: String?, ?location: LightningCSS::Location?) -> void
|
|
16
|
+
|
|
17
|
+
# : () -> Hash[Symbol, untyped]
|
|
18
|
+
def to_h: () -> Hash[Symbol, untyped]
|
|
19
|
+
|
|
20
|
+
# : () -> String
|
|
21
|
+
def to_s: () -> String
|
|
22
|
+
|
|
23
|
+
alias to_str to_s
|
|
24
|
+
|
|
25
|
+
# : (untyped) -> bool
|
|
26
|
+
def ==: (untyped) -> bool
|
|
27
|
+
|
|
28
|
+
alias eql? ==
|
|
29
|
+
|
|
30
|
+
# : () -> Integer
|
|
31
|
+
def hash: () -> Integer
|
|
32
|
+
|
|
33
|
+
# : () -> String
|
|
34
|
+
def inspect: () -> String
|
|
35
|
+
end
|
|
36
|
+
end
|
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: 1.33.0.
|
|
4
|
+
version: 1.33.0.2
|
|
5
5
|
platform: arm-linux-gnu
|
|
6
6
|
authors:
|
|
7
7
|
- Marco Roth
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-10-
|
|
11
|
+
date: 2026-10-14 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.
|
|
@@ -30,6 +30,7 @@ files:
|
|
|
30
30
|
- lib/lightningcss/4.0/lightningcss.so
|
|
31
31
|
- lib/lightningcss/backend.rb
|
|
32
32
|
- lib/lightningcss/errors.rb
|
|
33
|
+
- lib/lightningcss/location.rb
|
|
33
34
|
- lib/lightningcss/node.rb
|
|
34
35
|
- lib/lightningcss/options.rb
|
|
35
36
|
- lib/lightningcss/parse_result.rb
|
|
@@ -37,6 +38,7 @@ files:
|
|
|
37
38
|
- lib/lightningcss/transformer.rb
|
|
38
39
|
- lib/lightningcss/version.rb
|
|
39
40
|
- lib/lightningcss/visitor.rb
|
|
41
|
+
- lib/lightningcss/warning.rb
|
|
40
42
|
- licenses/README.md
|
|
41
43
|
- licenses/lightningcss-MPL-2.0.txt
|
|
42
44
|
- lightningcss.gemspec
|
|
@@ -51,6 +53,7 @@ files:
|
|
|
51
53
|
- sig/lightningcss.rbs
|
|
52
54
|
- sig/lightningcss/backend.rbs
|
|
53
55
|
- sig/lightningcss/errors.rbs
|
|
56
|
+
- sig/lightningcss/location.rbs
|
|
54
57
|
- sig/lightningcss/node.rbs
|
|
55
58
|
- sig/lightningcss/options.rbs
|
|
56
59
|
- sig/lightningcss/parse_result.rbs
|
|
@@ -59,6 +62,7 @@ files:
|
|
|
59
62
|
- sig/lightningcss/types.rbs
|
|
60
63
|
- sig/lightningcss/version.rbs
|
|
61
64
|
- sig/lightningcss/visitor.rbs
|
|
65
|
+
- sig/lightningcss/warning.rbs
|
|
62
66
|
homepage: https://github.com/marcoroth/lightningcss-ruby
|
|
63
67
|
licenses:
|
|
64
68
|
- MIT
|