diff --git a/README.md b/README.md index cc1e078..4b6e7be 100644 --- a/README.md +++ b/README.md @@ -95,7 +95,7 @@ result.exports #=> {"application" => "_8Z4fiW_application"} result.warnings.first -#=> "'deep' is not recognized as a valid pseudo-class. ... at app/assets/stylesheets/layout.css:0:9" +#=> "'deep' is not recognized as a valid pseudo-class. ... at app/assets/stylesheets/layout.css:1:9" ``` #### CSS modules @@ -338,7 +338,7 @@ result.warnings? #=> true result.warnings.first -#=> "'deep' is not recognized as a valid pseudo-class. Did you mean '::deep' (pseudo-element) or is this a typo? at :0:9" +#=> "'deep' is not recognized as a valid pseudo-class. Did you mean '::deep' (pseudo-element) or is this a typo? at :1:9" result.code #=> ".a:deep(.b){color:red}" diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 2cf295b..98964cf 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -18,6 +18,7 @@ use std::ptr; use std::sync::{Arc, RwLock}; use lightningcss::bundler::{BundleErrorKind, Bundler, FileProvider}; +use lightningcss::error::Error; use lightningcss::stylesheet::{MinifyOptions, ParserOptions, PrinterOptions, StyleAttribute, StyleSheet}; use lightningcss::visitor::Visit; @@ -67,6 +68,13 @@ pub struct Failure { message: String, } +fn describe(error: &Error) -> String { + match &error.loc { + Some(loc) => format!("{} at {}:{}:{}", error.kind, loc.filename, loc.line + 1, loc.column), + None => error.kind.to_string(), + } +} + impl Failure { fn parse(message: impl Into) -> Self { Self { @@ -135,11 +143,11 @@ fn parse_source<'i>(code: &'i str, options: &TransformOptions) -> Result Result Result Result Failure::parse(error.to_string()), - _ => Failure::bundle(error.to_string()), + BundleErrorKind::ParserError(_) => Failure::parse(describe(&error)), + _ => Failure::bundle(describe(&error)), })?; if let Some(fragment) = &options.scope { @@ -270,7 +278,7 @@ fn bundle_source(path: &str, options: &TransformOptions) -> Result Result Scoper<'i> { let list = SelectorList::parse_string_with_options(fragment, ParserOptions::default()).map_err(|error| { format!( "Invalid scope selector {fragment:?} at :{}:{}", - error.location.line, error.location.column + error.location.line + 1, + error.location.column ) })?; diff --git a/rust/tests/transform_test.rs b/rust/tests/transform_test.rs index 8fb77e2..1380aa0 100644 --- a/rust/tests/transform_test.rs +++ b/rust/tests/transform_test.rs @@ -119,7 +119,7 @@ fn transform_answers_an_error_for_css_it_could_not_read() { assert_eq!( answer, - Err("Expected identifier in class selector, got WhiteSpace(\" \") at :0:2".to_string()) + Err("Expected identifier in class selector, got WhiteSpace(\" \") at :1:2".to_string()) ); } diff --git a/test/lightningcss/bundle_test.rb b/test/lightningcss/bundle_test.rb index 384c561..0b97a3e 100644 --- a/test/lightningcss/bundle_test.rb +++ b/test/lightningcss/bundle_test.rb @@ -10,7 +10,7 @@ class BundleTest < Minitest::Spec BROKEN = File.expand_path("../fixtures/bundle/broken.css", __dir__) UNREADABLE = File.expand_path("../fixtures/bundle/nested/broken.css", __dir__) IMPORTED = File.expand_path("../fixtures/bundle/nested/warned.css", __dir__) - WARNING = "'deep' is not recognized as a valid pseudo-class. Did you mean '::deep' (pseudo-element) or is this a typo? at #{IMPORTED}:0:9".freeze + WARNING = "'deep' is not recognized as a valid pseudo-class. Did you mean '::deep' (pseudo-element) or is this a typo? at #{IMPORTED}:1:9".freeze test "resolves the imports a stylesheet was written with, in the order it imported them" do code = LightningCSS.bundle(ENTRY, minify: true).code @@ -83,7 +83,7 @@ class BundleTest < Minitest::Spec test "raises a parse error for CSS it could not read, wherever it imported it from" do error = assert_raises(LightningCSS::ParseError) { LightningCSS.bundle(BROKEN) } - assert_equal "Invalid empty selector at #{UNREADABLE}:0:1", error.message + assert_equal "Invalid empty selector at #{UNREADABLE}:1:1", error.message end test "refuses a filename, naming every file it reads by the path it read it from" do diff --git a/test/lightningcss/errors_test.rb b/test/lightningcss/errors_test.rb index e2c1473..0ff97af 100644 --- a/test/lightningcss/errors_test.rb +++ b/test/lightningcss/errors_test.rb @@ -7,13 +7,27 @@ class ErrorsTest < Minitest::Spec test "raises on CSS it cannot parse" do error = assert_raises(LightningCSS::ParseError) { LightningCSS.transform(". { color: red }") } - assert_equal 'Expected identifier in class selector, got WhiteSpace(" ") at :0:2', error.message + assert_equal 'Expected identifier in class selector, got WhiteSpace(" ") at :1:2', error.message end test "says where it could not parse" do error = assert_raises(LightningCSS::ParseError) { LightningCSS.transform("!!! { color: red }") } - assert_equal "Invalid empty selector at :0:1", error.message + assert_equal "Invalid empty selector at :1:1", error.message + end + + test "counts lines from 1 and columns from 1" do + css = ".a { color: red; }\n.b, { color: blue; }\n" + error = assert_raises(LightningCSS::ParseError) { LightningCSS.transform(css, filename: "main.css") } + + assert_equal "Invalid empty selector at main.css:2:5", error.message + end + + test "counts the lines of a warning from 1" do + css = ".a { color: red; }\n.b, { color: blue; }\n" + warnings = LightningCSS.transform(css, filename: "main.css", error_recovery: true).warnings + + assert_equal ["Invalid empty selector at main.css:2:5"], warnings end test "closes an unclosed block the way a browser does" do diff --git a/test/lightningcss/parse_test.rb b/test/lightningcss/parse_test.rb index 7edd503..e73b9ba 100644 --- a/test/lightningcss/parse_test.rb +++ b/test/lightningcss/parse_test.rb @@ -38,7 +38,7 @@ class ParseTest < Minitest::Spec test "raises on a stylesheet it cannot read" do error = assert_raises(LightningCSS::ParseError) { LightningCSS.parse(". { color: red }") } - assert_equal 'Expected identifier in class selector, got WhiteSpace(" ") at :0:2', error.message + assert_equal 'Expected identifier in class selector, got WhiteSpace(" ") at :1:2', error.message end test "recovers when asked to" do diff --git a/test/lightningcss/scope_test.rb b/test/lightningcss/scope_test.rb index 145a5fc..b5459bd 100644 --- a/test/lightningcss/scope_test.rb +++ b/test/lightningcss/scope_test.rb @@ -60,7 +60,7 @@ def scoped(source, fragment = "[s]") test "refuses a fragment that is not a selector" do error = assert_raises(LightningCSS::OptionError) { scoped(".a { color: red }", "((") } - assert_equal 'Invalid scope selector "((" at :0:1', error.message + assert_equal 'Invalid scope selector "((" at :1:1', error.message end test "refuses a fragment carrying more than one selector" do diff --git a/test/lightningcss/style_attribute_test.rb b/test/lightningcss/style_attribute_test.rb index ea8fa53..599f4f1 100644 --- a/test/lightningcss/style_attribute_test.rb +++ b/test/lightningcss/style_attribute_test.rb @@ -37,7 +37,7 @@ class StyleAttributeTest < Minitest::Spec LightningCSS.transform_style_attribute(".a { color: red }") end - assert_equal "Unexpected token Delim('.') at :0:1", error.message + assert_equal "Unexpected token Delim('.') at :1:1", error.message end test "has no names to compile, so it reports no exports" do diff --git a/test/lightningcss/warnings_test.rb b/test/lightningcss/warnings_test.rb index d474e57..38f9f3e 100644 --- a/test/lightningcss/warnings_test.rb +++ b/test/lightningcss/warnings_test.rb @@ -5,7 +5,7 @@ module LightningCSS class WarningsTest < Minitest::Spec DEEP = ".a:deep(.b) { color: red }" - WARNING = "'deep' is not recognized as a valid pseudo-class. Did you mean '::deep' (pseudo-element) or is this a typo? at :0:9" + WARNING = "'deep' is not recognized as a valid pseudo-class. Did you mean '::deep' (pseudo-element) or is this a typo? at :1:9" test "reports what it kept but did not understand" do result = LightningCSS.transform(DEEP, minify: true)