lightningcss 0.2.2__tar.gz → 0.3.2__tar.gz

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.
@@ -87,6 +87,33 @@ jobs:
87
87
  name: wheels-${{ runner.os }}-${{ matrix.target }}
88
88
  path: dist/*
89
89
 
90
+ test:
91
+ name: Test wheels on ${{ matrix.os }} (${{ matrix.python-version }})
92
+ needs: linux
93
+ runs-on: ${{ matrix.os }}
94
+ strategy:
95
+ matrix:
96
+ os: [ubuntu-latest]
97
+ python-version: ['3.10']
98
+ steps:
99
+ - uses: actions/checkout@v4
100
+ - name: Set up Python ${{ matrix.python-version }}
101
+ uses: actions/setup-python@v5
102
+ with:
103
+ python-version: ${{ matrix.python-version }}
104
+ - name: Download x86_64 wheels
105
+ uses: actions/download-artifact@v4
106
+ with:
107
+ name: wheels-Linux-x86_64
108
+ path: dist
109
+ - name: Install wheel and dependencies
110
+ run: |
111
+ pip install --upgrade pip
112
+ pip install --no-index --find-links=dist lightningcss
113
+ pip install --group dev
114
+ - name: Run tests
115
+ run: pytest
116
+
90
117
  sdist:
91
118
  runs-on: ubuntu-latest
92
119
  steps:
@@ -8,19 +8,19 @@ version = "0.7.8"
8
8
  source = "registry+https://github.com/rust-lang/crates.io-index"
9
9
  checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9"
10
10
  dependencies = [
11
- "getrandom",
11
+ "getrandom 0.2.15",
12
12
  "once_cell",
13
13
  "version_check",
14
14
  ]
15
15
 
16
16
  [[package]]
17
17
  name = "ahash"
18
- version = "0.8.11"
18
+ version = "0.8.12"
19
19
  source = "registry+https://github.com/rust-lang/crates.io-index"
20
- checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
20
+ checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75"
21
21
  dependencies = [
22
22
  "cfg-if",
23
- "getrandom",
23
+ "getrandom 0.3.4",
24
24
  "once_cell",
25
25
  "serde",
26
26
  "version_check",
@@ -75,16 +75,26 @@ dependencies = [
75
75
  "wyz",
76
76
  ]
77
77
 
78
+ [[package]]
79
+ name = "browserslist-data"
80
+ version = "0.1.5"
81
+ source = "registry+https://github.com/rust-lang/crates.io-index"
82
+ checksum = "21d369bf3fe9811518eead42e2cdf9ed9915579242864297689894c0f1089712"
83
+ dependencies = [
84
+ "ahash 0.8.12",
85
+ "chrono",
86
+ ]
87
+
78
88
  [[package]]
79
89
  name = "browserslist-rs"
80
- version = "0.17.0"
90
+ version = "0.19.0"
81
91
  source = "registry+https://github.com/rust-lang/crates.io-index"
82
- checksum = "74c973b79d9b6b89854493185ab760c6ef8e54bcfad10ad4e33991e46b374ac8"
92
+ checksum = "8dd48a6ca358df4f7000e3fb5f08738b1b91a0e5d5f862e2f77b2b14647547f5"
83
93
  dependencies = [
84
- "ahash 0.8.11",
94
+ "ahash 0.8.12",
95
+ "browserslist-data",
85
96
  "chrono",
86
97
  "either",
87
- "indexmap",
88
98
  "itertools 0.13.0",
89
99
  "nom",
90
100
  "serde",
@@ -317,6 +327,18 @@ dependencies = [
317
327
  "wasi",
318
328
  ]
319
329
 
330
+ [[package]]
331
+ name = "getrandom"
332
+ version = "0.3.4"
333
+ source = "registry+https://github.com/rust-lang/crates.io-index"
334
+ checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
335
+ dependencies = [
336
+ "cfg-if",
337
+ "libc",
338
+ "r-efi",
339
+ "wasip2",
340
+ ]
341
+
320
342
  [[package]]
321
343
  name = "hashbrown"
322
344
  version = "0.12.3"
@@ -378,12 +400,6 @@ dependencies = [
378
400
  "serde",
379
401
  ]
380
402
 
381
- [[package]]
382
- name = "indoc"
383
- version = "2.0.6"
384
- source = "registry+https://github.com/rust-lang/crates.io-index"
385
- checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd"
386
-
387
403
  [[package]]
388
404
  name = "itertools"
389
405
  version = "0.10.5"
@@ -432,11 +448,11 @@ checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
432
448
 
433
449
  [[package]]
434
450
  name = "lightningcss"
435
- version = "1.0.0-alpha.65"
451
+ version = "1.0.0-alpha.71"
436
452
  source = "registry+https://github.com/rust-lang/crates.io-index"
437
- checksum = "c84f971730745f4aaac013b6cf4328baf1548efc973c0d95cfd843a3c1ca07af"
453
+ checksum = "cb6314c2f0590ac93c86099b98bb7ba8abcf759bfd89604ffca906472bb54937"
438
454
  dependencies = [
439
- "ahash 0.8.11",
455
+ "ahash 0.8.12",
440
456
  "bitflags",
441
457
  "browserslist-rs",
442
458
  "const-str",
@@ -444,17 +460,18 @@ dependencies = [
444
460
  "cssparser-color",
445
461
  "dashmap",
446
462
  "data-encoding",
447
- "getrandom",
463
+ "getrandom 0.3.4",
448
464
  "indexmap",
449
465
  "itertools 0.10.5",
450
466
  "lazy_static",
451
467
  "lightningcss-derive",
452
468
  "parcel_selectors",
453
469
  "parcel_sourcemap",
454
- "paste",
470
+ "pastey",
455
471
  "pathdiff",
456
472
  "rayon",
457
473
  "serde",
474
+ "serde-content",
458
475
  "smallvec",
459
476
  ]
460
477
 
@@ -498,15 +515,6 @@ version = "2.7.4"
498
515
  source = "registry+https://github.com/rust-lang/crates.io-index"
499
516
  checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
500
517
 
501
- [[package]]
502
- name = "memoffset"
503
- version = "0.9.1"
504
- source = "registry+https://github.com/rust-lang/crates.io-index"
505
- checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
506
- dependencies = [
507
- "autocfg",
508
- ]
509
-
510
518
  [[package]]
511
519
  name = "minimal-lexical"
512
520
  version = "0.2.1"
@@ -546,9 +554,9 @@ checksum = "7f222829ae9293e33a9f5e9f440c6760a3d450a64affe1846486b140db81c1f4"
546
554
 
547
555
  [[package]]
548
556
  name = "parcel_selectors"
549
- version = "0.28.1"
557
+ version = "0.28.2"
550
558
  source = "registry+https://github.com/rust-lang/crates.io-index"
551
- checksum = "dccbc6fb560df303a44e511618256029410efbc87779018f751ef12c488271fe"
559
+ checksum = "54fd03f1ad26cb6b3ec1b7414fa78a3bd639e7dbb421b1a60513c96ce886a196"
552
560
  dependencies = [
553
561
  "bitflags",
554
562
  "cssparser",
@@ -588,10 +596,10 @@ dependencies = [
588
596
  ]
589
597
 
590
598
  [[package]]
591
- name = "paste"
592
- version = "1.0.15"
599
+ name = "pastey"
600
+ version = "0.1.1"
593
601
  source = "registry+https://github.com/rust-lang/crates.io-index"
594
- checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
602
+ checksum = "35fb2e5f958ec131621fdd531e9fc186ed768cbe395337403ae56c17a74c68ec"
595
603
 
596
604
  [[package]]
597
605
  name = "pathdiff"
@@ -694,37 +702,32 @@ dependencies = [
694
702
 
695
703
  [[package]]
696
704
  name = "pyo3"
697
- version = "0.24.0"
705
+ version = "0.28.2"
698
706
  source = "registry+https://github.com/rust-lang/crates.io-index"
699
- checksum = "7f1c6c3591120564d64db2261bec5f910ae454f01def849b9c22835a84695e86"
707
+ checksum = "cf85e27e86080aafd5a22eae58a162e133a589551542b3e5cee4beb27e54f8e1"
700
708
  dependencies = [
701
- "cfg-if",
702
- "indoc",
703
709
  "libc",
704
- "memoffset",
705
710
  "once_cell",
706
711
  "portable-atomic",
707
712
  "pyo3-build-config",
708
713
  "pyo3-ffi",
709
714
  "pyo3-macros",
710
- "unindent",
711
715
  ]
712
716
 
713
717
  [[package]]
714
718
  name = "pyo3-build-config"
715
- version = "0.24.0"
719
+ version = "0.28.2"
716
720
  source = "registry+https://github.com/rust-lang/crates.io-index"
717
- checksum = "e9b6c2b34cf71427ea37c7001aefbaeb85886a074795e35f161f5aecc7620a7a"
721
+ checksum = "8bf94ee265674bf76c09fa430b0e99c26e319c945d96ca0d5a8215f31bf81cf7"
718
722
  dependencies = [
719
- "once_cell",
720
723
  "target-lexicon",
721
724
  ]
722
725
 
723
726
  [[package]]
724
727
  name = "pyo3-ffi"
725
- version = "0.24.0"
728
+ version = "0.28.2"
726
729
  source = "registry+https://github.com/rust-lang/crates.io-index"
727
- checksum = "5507651906a46432cdda02cd02dd0319f6064f1374c9147c45b978621d2c3a9c"
730
+ checksum = "491aa5fc66d8059dd44a75f4580a2962c1862a1c2945359db36f6c2818b748dc"
728
731
  dependencies = [
729
732
  "libc",
730
733
  "pyo3-build-config",
@@ -732,9 +735,9 @@ dependencies = [
732
735
 
733
736
  [[package]]
734
737
  name = "pyo3-macros"
735
- version = "0.24.0"
738
+ version = "0.28.2"
736
739
  source = "registry+https://github.com/rust-lang/crates.io-index"
737
- checksum = "b0d394b5b4fd8d97d48336bb0dd2aebabad39f1d294edd6bcd2cccf2eefe6f42"
740
+ checksum = "f5d671734e9d7a43449f8480f8b38115df67bef8d21f76837fa75ee7aaa5e52e"
738
741
  dependencies = [
739
742
  "proc-macro2",
740
743
  "pyo3-macros-backend",
@@ -744,9 +747,9 @@ dependencies = [
744
747
 
745
748
  [[package]]
746
749
  name = "pyo3-macros-backend"
747
- version = "0.24.0"
750
+ version = "0.28.2"
748
751
  source = "registry+https://github.com/rust-lang/crates.io-index"
749
- checksum = "fd72da09cfa943b1080f621f024d2ef7e2773df7badd51aa30a2be1f8caa7c8e"
752
+ checksum = "22faaa1ce6c430a1f71658760497291065e6450d7b5dc2bcf254d49f66ee700a"
750
753
  dependencies = [
751
754
  "heck",
752
755
  "proc-macro2",
@@ -757,7 +760,7 @@ dependencies = [
757
760
 
758
761
  [[package]]
759
762
  name = "python-lightningcss"
760
- version = "0.2.2"
763
+ version = "0.3.2"
761
764
  dependencies = [
762
765
  "browserslist-rs",
763
766
  "lightningcss",
@@ -773,6 +776,12 @@ dependencies = [
773
776
  "proc-macro2",
774
777
  ]
775
778
 
779
+ [[package]]
780
+ name = "r-efi"
781
+ version = "5.3.0"
782
+ source = "registry+https://github.com/rust-lang/crates.io-index"
783
+ checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
784
+
776
785
  [[package]]
777
786
  name = "radium"
778
787
  version = "0.7.0"
@@ -893,18 +902,37 @@ checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b"
893
902
 
894
903
  [[package]]
895
904
  name = "serde"
896
- version = "1.0.219"
905
+ version = "1.0.228"
906
+ source = "registry+https://github.com/rust-lang/crates.io-index"
907
+ checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
908
+ dependencies = [
909
+ "serde_core",
910
+ "serde_derive",
911
+ ]
912
+
913
+ [[package]]
914
+ name = "serde-content"
915
+ version = "0.1.2"
916
+ source = "registry+https://github.com/rust-lang/crates.io-index"
917
+ checksum = "3753ca04f350fa92d00b6146a3555e63c55388c9ef2e11e09bce2ff1c0b509c6"
918
+ dependencies = [
919
+ "serde",
920
+ ]
921
+
922
+ [[package]]
923
+ name = "serde_core"
924
+ version = "1.0.228"
897
925
  source = "registry+https://github.com/rust-lang/crates.io-index"
898
- checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
926
+ checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
899
927
  dependencies = [
900
928
  "serde_derive",
901
929
  ]
902
930
 
903
931
  [[package]]
904
932
  name = "serde_derive"
905
- version = "1.0.219"
933
+ version = "1.0.228"
906
934
  source = "registry+https://github.com/rust-lang/crates.io-index"
907
- checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
935
+ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
908
936
  dependencies = [
909
937
  "proc-macro2",
910
938
  "quote",
@@ -986,9 +1014,9 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
986
1014
 
987
1015
  [[package]]
988
1016
  name = "target-lexicon"
989
- version = "0.13.2"
1017
+ version = "0.13.5"
990
1018
  source = "registry+https://github.com/rust-lang/crates.io-index"
991
- checksum = "e502f78cdbb8ba4718f566c418c52bc729126ffd16baee5baa718cf25dd5a69a"
1019
+ checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca"
992
1020
 
993
1021
  [[package]]
994
1022
  name = "thiserror"
@@ -1037,12 +1065,6 @@ version = "1.12.0"
1037
1065
  source = "registry+https://github.com/rust-lang/crates.io-index"
1038
1066
  checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
1039
1067
 
1040
- [[package]]
1041
- name = "unindent"
1042
- version = "0.2.4"
1043
- source = "registry+https://github.com/rust-lang/crates.io-index"
1044
- checksum = "7264e107f553ccae879d21fbea1d6724ac785e8c3bfc762137959b5802826ef3"
1045
-
1046
1068
  [[package]]
1047
1069
  name = "uuid"
1048
1070
  version = "1.16.0"
@@ -1067,6 +1089,15 @@ version = "0.11.0+wasi-snapshot-preview1"
1067
1089
  source = "registry+https://github.com/rust-lang/crates.io-index"
1068
1090
  checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
1069
1091
 
1092
+ [[package]]
1093
+ name = "wasip2"
1094
+ version = "1.0.2+wasi-0.2.9"
1095
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1096
+ checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5"
1097
+ dependencies = [
1098
+ "wit-bindgen",
1099
+ ]
1100
+
1070
1101
  [[package]]
1071
1102
  name = "wasm-bindgen"
1072
1103
  version = "0.2.100"
@@ -1204,6 +1235,12 @@ version = "0.52.6"
1204
1235
  source = "registry+https://github.com/rust-lang/crates.io-index"
1205
1236
  checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
1206
1237
 
1238
+ [[package]]
1239
+ name = "wit-bindgen"
1240
+ version = "0.51.0"
1241
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1242
+ checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5"
1243
+
1207
1244
  [[package]]
1208
1245
  name = "wyz"
1209
1246
  version = "0.5.1"
@@ -1215,18 +1252,18 @@ dependencies = [
1215
1252
 
1216
1253
  [[package]]
1217
1254
  name = "zerocopy"
1218
- version = "0.7.35"
1255
+ version = "0.8.42"
1219
1256
  source = "registry+https://github.com/rust-lang/crates.io-index"
1220
- checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
1257
+ checksum = "f2578b716f8a7a858b7f02d5bd870c14bf4ddbbcf3a4c05414ba6503640505e3"
1221
1258
  dependencies = [
1222
1259
  "zerocopy-derive",
1223
1260
  ]
1224
1261
 
1225
1262
  [[package]]
1226
1263
  name = "zerocopy-derive"
1227
- version = "0.7.35"
1264
+ version = "0.8.42"
1228
1265
  source = "registry+https://github.com/rust-lang/crates.io-index"
1229
- checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
1266
+ checksum = "7e6cc098ea4d3bd6246687de65af3f920c430e236bee1e3bf2e441463f08a02f"
1230
1267
  dependencies = [
1231
1268
  "proc-macro2",
1232
1269
  "quote",
@@ -1,7 +1,8 @@
1
1
  [package]
2
2
  name = "python-lightningcss"
3
- version = "0.2.2"
3
+ version = "0.3.2"
4
4
  edition = "2021"
5
+ readme = "README.md"
5
6
 
6
7
  # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7
8
  [lib]
@@ -9,6 +10,6 @@ name = "lightningcss"
9
10
  crate-type = ["cdylib"]
10
11
 
11
12
  [dependencies]
12
- pyo3 = { version = "0.24.0", features = ["extension-module"] }
13
- browserslist-rs = "0.17.0"
14
- lightningcss = { version = "1.0.0-alpha.65", features = ["browserslist"] }
13
+ pyo3 = { version = "0.28.2", features = ["extension-module", "abi3-py37"] }
14
+ browserslist-rs = "0.19.0"
15
+ lightningcss = { version = "1.0.0-alpha.71", features = ["browserslist"] }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lightningcss
3
- Version: 0.2.2
3
+ Version: 0.3.2
4
4
  Classifier: Development Status :: 3 - Alpha
5
5
  Classifier: Intended Audience :: Developers
6
6
  Classifier: License :: OSI Approved :: Apache Software License
@@ -9,12 +9,6 @@ Classifier: Programming Language :: Python :: Implementation :: CPython
9
9
  Classifier: Programming Language :: Python :: Implementation :: PyPy
10
10
  Classifier: Programming Language :: Python :: 3
11
11
  Classifier: Programming Language :: Python :: 3 :: Only
12
- Classifier: Programming Language :: Python :: 3.7
13
- Classifier: Programming Language :: Python :: 3.8
14
- Classifier: Programming Language :: Python :: 3.9
15
- Classifier: Programming Language :: Python :: 3.10
16
- Classifier: Programming Language :: Python :: 3.11
17
- Classifier: Programming Language :: Python :: 3.12
18
12
  Classifier: Topic :: Internet :: WWW/HTTP
19
13
  Classifier: Topic :: Software Development :: Pre-processors
20
14
  License-File: LICENSE
@@ -41,11 +35,15 @@ or webpack](https://lightningcss.dev/docs.html) instead.
41
35
  ## Installation
42
36
 
43
37
  python-lightningcss includes wheels which can be installed for most platforms
44
- using pip: `pip install lightningcss`.
38
+ using pip:
39
+
40
+ $ pip install lightningcss
45
41
 
46
42
  Alternatively, python-lightningcss may be installed directly from source:
47
- `pip install git+https://github.com/pydsigner/python-lightningcss`. This will
48
- require that the Rust toolchain be installed.
43
+
44
+ $ pip install git+https://github.com/pydsigner/python-lightningcss
45
+
46
+ This will require that the Rust toolchain be installed.
49
47
 
50
48
  ## Usage
51
49
 
@@ -53,14 +51,44 @@ require that the Rust toolchain be installed.
53
51
  import lightningcss
54
52
 
55
53
  parser_flags = lightningcss.calc_parser_flags(nesting=True)
54
+
56
55
  input_css = """
57
- a {
58
- padding-left: 0;
59
- padding-right: 0;
60
- padding-top: 5px;
61
- padding-bottom: 5px;
56
+ .navbar {
57
+ margin: 0;
58
+
59
+ a {
60
+ padding-left: 0;
61
+ padding-right: 0;
62
+ padding-top: 5px;
63
+ padding-bottom: 5px;
64
+ }
62
65
  }
63
66
  """
64
- output_css = lightningcss.process_stylesheet(input_css, filename="abc.css", browsers_list=['defaults'])
67
+
68
+ output_css = lightningcss.process_stylesheet(
69
+ input_css,
70
+ filename="abc.css",
71
+ parser_flags = parser_flags,
72
+ browsers_list = ['defaults'],
73
+ minify = True,
74
+ )
65
75
  ```
66
76
 
77
+ The `filename` keyword parameter is only used for displaying error messages from
78
+ the parser. When using `browsers_list`, lightningcss will try to transpile the
79
+ code to be compatible with the specified
80
+ [browserslist target](https://browsersl.ist/).
81
+
82
+ This package also supports creating a CSS bundle where all `@import` rules are
83
+ resolved into a single stylesheet:
84
+
85
+ ```py
86
+ bundled_css = lightningcss.bundle_css(
87
+ "main.css",
88
+ browsers_list = ["defaults"],
89
+ minify = False,
90
+ )
91
+ ```
92
+
93
+ All resources referenced via `@import` are resolved relative to the main file.
94
+
@@ -13,11 +13,15 @@ or webpack](https://lightningcss.dev/docs.html) instead.
13
13
  ## Installation
14
14
 
15
15
  python-lightningcss includes wheels which can be installed for most platforms
16
- using pip: `pip install lightningcss`.
16
+ using pip:
17
+
18
+ $ pip install lightningcss
17
19
 
18
20
  Alternatively, python-lightningcss may be installed directly from source:
19
- `pip install git+https://github.com/pydsigner/python-lightningcss`. This will
20
- require that the Rust toolchain be installed.
21
+
22
+ $ pip install git+https://github.com/pydsigner/python-lightningcss
23
+
24
+ This will require that the Rust toolchain be installed.
21
25
 
22
26
  ## Usage
23
27
 
@@ -25,13 +29,43 @@ require that the Rust toolchain be installed.
25
29
  import lightningcss
26
30
 
27
31
  parser_flags = lightningcss.calc_parser_flags(nesting=True)
32
+
28
33
  input_css = """
29
- a {
30
- padding-left: 0;
31
- padding-right: 0;
32
- padding-top: 5px;
33
- padding-bottom: 5px;
34
+ .navbar {
35
+ margin: 0;
36
+
37
+ a {
38
+ padding-left: 0;
39
+ padding-right: 0;
40
+ padding-top: 5px;
41
+ padding-bottom: 5px;
42
+ }
34
43
  }
35
44
  """
36
- output_css = lightningcss.process_stylesheet(input_css, filename="abc.css", browsers_list=['defaults'])
45
+
46
+ output_css = lightningcss.process_stylesheet(
47
+ input_css,
48
+ filename="abc.css",
49
+ parser_flags = parser_flags,
50
+ browsers_list = ['defaults'],
51
+ minify = True,
52
+ )
37
53
  ```
54
+
55
+ The `filename` keyword parameter is only used for displaying error messages from
56
+ the parser. When using `browsers_list`, lightningcss will try to transpile the
57
+ code to be compatible with the specified
58
+ [browserslist target](https://browsersl.ist/).
59
+
60
+ This package also supports creating a CSS bundle where all `@import` rules are
61
+ resolved into a single stylesheet:
62
+
63
+ ```py
64
+ bundled_css = lightningcss.bundle_css(
65
+ "main.css",
66
+ browsers_list = ["defaults"],
67
+ minify = False,
68
+ )
69
+ ```
70
+
71
+ All resources referenced via `@import` are resolved relative to the main file.
@@ -12,7 +12,7 @@ def calc_parser_flags(
12
12
  deep_selector_combinator: bool = False
13
13
  ) -> ParserFlags:
14
14
  """
15
- Calculates the `parser_flags` argument of `process_stylesheet()`.
15
+ Calculates the `parser_flags` argument of `process_stylesheet()` and `bundle_css()`.
16
16
  """
17
17
 
18
18
  def process_stylesheet(
@@ -42,7 +42,40 @@ def process_stylesheet(
42
42
  :param browsers_list: An optional list of browserslist targets to be used
43
43
  to determine automatic prefixing and transpilation. If it is not
44
44
  specified, no prefixing/transpilation will occur.
45
- :param minify: Is True, the final output will be minified. Otherwise, it
45
+ :param minify: If True, the final output will be minified. Otherwise, it
46
46
  will be pretty-printed.
47
47
  :return: A string containing a processed CSS stylesheet.
48
48
  """
49
+
50
+ def bundle_css(
51
+ path: str,
52
+ /,
53
+ error_recovery: bool = False,
54
+ parser_flags: ParserFlags = ParserFlags(0),
55
+ unused_symbols: set[str] | None = None,
56
+ browsers_list: list[str] | None = None,
57
+ minify: bool = True
58
+ ) -> str:
59
+ """
60
+ Processes the supplied CSS stylesheet file and returns the bundle as a string.
61
+
62
+ Resolves all `@import` rules to create a single CSS bundle. The resources
63
+ referenced via `@import` are resolved relative to the main file.
64
+
65
+ :param path: A string containing the path of the stylesheet file to process.
66
+ :param error_recovery: Whether or not to omit broken CSS rather than
67
+ producing a parse error. Enable with caution!
68
+ :param parser_flags: An optional flag created by `calc_parser_flags()`.
69
+ See that function for more details.
70
+ :param unused_symbols: An optional set of known unused symbols, like
71
+ classnames, ids, or keyframe names, to be removed from the output.
72
+ Note that symbols should be specified in bare form, i.e.
73
+ `unused_symbols={'a', 'b'}`, not `unused_symbols={'.a', '#b'}`, and
74
+ will remove both ids and classes if they share a name. Use with caution!
75
+ :param browsers_list: An optional list of browserslist targets to be used
76
+ to determine automatic prefixing and transpilation. If it is not
77
+ specified, no prefixing/transpilation will occur.
78
+ :param minify: If True, the final output will be minified. Otherwise, it
79
+ will be pretty-printed.
80
+ :return: A string containing the CSS bundle.
81
+ """
@@ -4,6 +4,7 @@ build-backend = "maturin"
4
4
 
5
5
  [project]
6
6
  name = "lightningcss"
7
+ dynamic = ["version"]
7
8
  description = "Python bindings for lightningcss."
8
9
  readme = "README.md"
9
10
  requires-python = ">=3.7"
@@ -21,12 +22,6 @@ classifiers = [
21
22
  "Programming Language :: Python :: Implementation :: PyPy",
22
23
  "Programming Language :: Python :: 3",
23
24
  "Programming Language :: Python :: 3 :: Only",
24
- "Programming Language :: Python :: 3.7",
25
- "Programming Language :: Python :: 3.8",
26
- "Programming Language :: Python :: 3.9",
27
- "Programming Language :: Python :: 3.10",
28
- "Programming Language :: Python :: 3.11",
29
- "Programming Language :: Python :: 3.12",
30
25
  "Topic :: Internet :: WWW/HTTP",
31
26
  "Topic :: Software Development :: Pre-processors",
32
27
  ]
@@ -34,6 +29,10 @@ classifiers = [
34
29
  [project.urls]
35
30
  Source = "https://github.com/pydsigner/python-lightningcss"
36
31
 
32
+ [dependency-groups]
33
+ dev = [
34
+ "pytest>=9.0.2",
35
+ ]
37
36
 
38
37
  [tool.maturin]
39
38
  features = ["pyo3/extension-module"]
@@ -1,10 +1,14 @@
1
1
  use std::collections::HashSet;
2
+ use std::path::Path;
2
3
 
3
- use pyo3::exceptions::PyValueError;
4
+ use pyo3::exceptions::{PyIOError, PyValueError};
4
5
  use pyo3::prelude::*;
5
6
 
6
7
  use browserslist::Error as BrowserslistError;
7
- use lightningcss::stylesheet::{StyleSheet, MinifyOptions, ParserFlags, ParserOptions, PrinterOptions};
8
+ use lightningcss::bundler::{Bundler, FileProvider, BundleErrorKind};
9
+ use lightningcss::stylesheet::{
10
+ MinifyOptions, ParserFlags, ParserOptions, PrinterOptions, StyleSheet,
11
+ };
8
12
  use lightningcss::targets::{Browsers, Targets};
9
13
 
10
14
  /// Processes provided CSS and returns as a string.
@@ -45,7 +49,7 @@ fn process_stylesheet(code: &str,
45
49
 
46
50
  let targets = match mk_targets(browsers_list) {
47
51
  Ok(val) => val,
48
- Err(e) => {return Err(PyValueError::new_err(format!("browsers_list failed validation: {}", e.to_string())))}
52
+ Err(e) => {return Err(PyValueError::new_err(format!("Validation of browsers_list failed: {}", e.to_string())))}
49
53
  };
50
54
  let mut stylesheet = match StyleSheet::parse(code, mk_parser_options(filename, error_recovery, parser_flags)) {
51
55
  Ok(val) => val,
@@ -72,11 +76,11 @@ fn calc_parser_flags(nesting: bool, custom_media: bool, deep_selector_combinator
72
76
  return flags;
73
77
  }
74
78
 
75
- fn mk_parser_options(filename: &str,
76
- error_recovery: bool,
77
- parser_flags: u8) -> ParserOptions {
79
+ fn mk_parser_options<'o, 'i>(filename: &'o str,
80
+ error_recovery: bool,
81
+ parser_flags: u8) -> ParserOptions<'o, 'i> {
78
82
  return ParserOptions {
79
- filename: filename.to_string(),
83
+ filename: filename.into(),
80
84
  error_recovery: error_recovery,
81
85
  flags: ParserFlags::from_bits_truncate(parser_flags),
82
86
  ..Default::default()
@@ -109,11 +113,88 @@ fn mk_printer_options<'a>(targets: &Targets,
109
113
  };
110
114
  }
111
115
 
116
+ /// Bundles a CSS file and returns as a string.
117
+ #[pyfunction]
118
+ #[pyo3(signature = (
119
+ path,
120
+ /,
121
+ error_recovery=false,
122
+ parser_flags=0,
123
+ unused_symbols=None,
124
+ browsers_list=None,
125
+ minify=true,
126
+ ))]
127
+ fn bundle_css(
128
+ path: &str,
129
+ error_recovery: bool,
130
+ parser_flags: u8,
131
+ unused_symbols: Option<HashSet<String>>,
132
+ browsers_list: Option<Vec<String>>,
133
+ minify: bool,
134
+ ) -> PyResult<String> {
135
+ let fs = FileProvider::new();
136
+ let mut bundler = Bundler::new(
137
+ &fs,
138
+ None,
139
+ ParserOptions {
140
+ error_recovery: error_recovery,
141
+ flags: ParserFlags::from_bits_truncate(parser_flags),
142
+ ..Default::default()
143
+ },
144
+ );
145
+
146
+ let mut stylesheet = match bundler.bundle(Path::new(&path)) {
147
+ Ok(s) => s,
148
+ Err(e) => {
149
+ let message = e.to_string();
150
+ match e.kind {
151
+ // Resolver errors, probably related to file I/O
152
+ BundleErrorKind::ResolverError(_) => {
153
+ return Err(PyIOError::new_err(format!("Bundling failed: {}", message)));
154
+ }
155
+ // Parser and logical errors
156
+ _ => {
157
+ return Err(PyValueError::new_err(format!("Bundling failed: {}", message)));
158
+ }
159
+ }
160
+ }
161
+ };
162
+
163
+ let targets = match mk_targets(browsers_list) {
164
+ Ok(val) => val,
165
+ Err(e) => {
166
+ return Err(PyValueError::new_err(format!(
167
+ "browsers_list failed validation: {}",
168
+ e.to_string()
169
+ )))
170
+ }
171
+ };
172
+
173
+ match stylesheet.minify(mk_minify_options(unused_symbols, &targets)) {
174
+ Ok(_) => {}
175
+ Err(e) => {
176
+ return Err(PyValueError::new_err(format!(
177
+ "Minifying stylesheet failed: {}",
178
+ e.to_string()
179
+ )));
180
+ }
181
+ }
182
+ return match stylesheet.to_css(mk_printer_options(&targets, minify)) {
183
+ Ok(val) => Ok(val.code),
184
+ Err(e) => Err(PyValueError::new_err(format!(
185
+ "Printing stylesheet failed: {}",
186
+ e.to_string()
187
+ ))),
188
+ };
189
+ }
190
+
112
191
  /// A python wrapper for core functionality of lightningcss.
113
- #[pymodule]
114
- #[pyo3(name = "lightningcss")]
115
- fn pylightningcss(_py: Python, m: &Bound<'_, PyModule>) -> PyResult<()> {
116
- m.add_function(wrap_pyfunction!(process_stylesheet, m)?)?;
117
- m.add_function(wrap_pyfunction!(calc_parser_flags, m)?)?;
118
- Ok(())
192
+ #[pymodule(name = "lightningcss")]
193
+ mod py_lightningcss {
194
+ #[pymodule_export]
195
+ use super::calc_parser_flags;
196
+ #[pymodule_export]
197
+ use super::process_stylesheet;
198
+ #[pymodule_export]
199
+ use super::bundle_css;
119
200
  }
@@ -0,0 +1,5 @@
1
+ * {
2
+ box-sizing: border-box;
3
+ }
4
+
5
+ something invalid
@@ -0,0 +1,5 @@
1
+ @import "normalize.css" layer(normalize);
2
+
3
+ a {
4
+ color: blue;
5
+ }
@@ -0,0 +1,3 @@
1
+ * {
2
+ box-sizing: border-box;
3
+ }
@@ -0,0 +1,30 @@
1
+ from pathlib import Path
2
+ import pytest
3
+ import lightningcss as lcss
4
+
5
+ TEST_DATA_DIR = Path(__file__).parent / "data"
6
+ MAIN_CSS_PATH = TEST_DATA_DIR / "main.css"
7
+ NORMALIZE_CSS_PATH = TEST_DATA_DIR / "normalize.css"
8
+ MISSING_CSS_PATH = TEST_DATA_DIR / "not-there.css"
9
+ INVALID_CSS_PATH = TEST_DATA_DIR / "invalid.css"
10
+
11
+
12
+ def test_minify():
13
+ expected = "@layer normalize{*{box-sizing:border-box}}a{color:#00f}"
14
+
15
+ result = lcss.bundle_css(str(MAIN_CSS_PATH))
16
+ assert result == expected
17
+
18
+ def test_pretty_print():
19
+ expected = "* {\n box-sizing: border-box;\n}\n"
20
+
21
+ result = lcss.bundle_css(str(NORMALIZE_CSS_PATH), minify=False)
22
+ assert result == expected
23
+
24
+ def test_file_not_found():
25
+ with pytest.raises(OSError):
26
+ lcss.bundle_css(str(MISSING_CSS_PATH))
27
+
28
+ def test_parse_error():
29
+ with pytest.raises(ValueError):
30
+ lcss.bundle_css(str(INVALID_CSS_PATH))
@@ -0,0 +1,33 @@
1
+ import lightningcss as lcss
2
+ import pytest
3
+
4
+
5
+ def test_minify():
6
+ code = ".content { margin-inline: 3vw; padding: 1rem 2rem 1rem 2rem; }"
7
+ expected = ".content{margin-inline:3vw;padding:1rem 2rem}"
8
+
9
+ result = lcss.process_stylesheet(code)
10
+ assert result == expected
11
+
12
+ def test_pretty_print():
13
+ code = ".content { margin: 3vw; }"
14
+ expected = ".content {\n margin: 3vw;\n}\n"
15
+
16
+ result = lcss.process_stylesheet(code, minify=False)
17
+ assert result == expected
18
+
19
+ def test_parse_error():
20
+ code = "img { display: block; } nonsense }{ non-terminated"
21
+
22
+ with pytest.raises(ValueError):
23
+ lcss.process_stylesheet(code)
24
+
25
+ def test_error_recovery():
26
+ code = "img { display: block; } nonsense }{ non-terminated"
27
+ expected = "img{display:block}"
28
+
29
+ with pytest.raises(ValueError):
30
+ lcss.process_stylesheet(code, error_recovery=False)
31
+
32
+ result = lcss.process_stylesheet(code, error_recovery=True)
33
+ assert result == expected
File without changes
File without changes