From eb4397618709186c109400448c6043b728217dc3 Mon Sep 17 00:00:00 2001
From: Isaac Muse <faceless.shop@gmail.com>
Date: Sun, 24 May 2026 07:25:14 -0600
Subject: [PATCH] Merge commit from fork

* Fix inefficient attribute pattern

Found by @mauriceng98

* Fix lint
---
 docs/src/markdown/about/changelog.md |  4 ++++
 pyproject.toml                       |  4 ++--
 soupsieve/__meta__.py                |  2 +-
 soupsieve/css_parser.py              |  2 +-
 tests/test_extra/test_attribute.py   | 22 ++++++++++++++++++++++
 5 files changed, 30 insertions(+), 4 deletions(-)

Index: soupsieve-2.6/pyproject.toml
===================================================================
--- soupsieve-2.6.orig/pyproject.toml
+++ soupsieve-2.6/pyproject.toml
@@ -54,7 +54,7 @@ include = [
     "/tests/**/*.py",
     "/.pyspelling.yml",
     "/.coveragerc",
-    "/mkdocs.yml"
+    "/zensical.yml"
 ]
 
 [tool.mypy]
Index: soupsieve-2.6/soupsieve/css_parser.py
===================================================================
--- soupsieve-2.6.orig/soupsieve/css_parser.py
+++ soupsieve-2.6/soupsieve/css_parser.py
@@ -108,7 +108,7 @@ IDENTIFIER = fr'''
 # `nth` content
 NTH = fr'(?:[-+])?(?:[0-9]+n?|n)(?:(?<=n){WSC}*(?:[-+]){WSC}*(?:[0-9]+))?'
 # Value: quoted string or identifier
-VALUE = fr'''(?:"(?:\\(?:.|{NEWLINE})|[^\\"\r\n\f]+)*?"|'(?:\\(?:.|{NEWLINE})|[^\\'\r\n\f]+)*?'|{IDENTIFIER})'''
+VALUE = fr'''(?:"(?:\\(?:.|{NEWLINE})|[^\\"\r\n\f])*?"|'(?:\\(?:.|{NEWLINE})|[^\\'\r\n\f])*?'|{IDENTIFIER})'''
 # Attribute value comparison. `!=` is handled special as it is non-standard.
 ATTR = fr'(?:{WSC}*(?P<cmp>[!~^|*$]?=){WSC}*(?P<value>{VALUE})(?:{WSC}*(?P<case>[is]))?)?{WSC}*'
 
Index: soupsieve-2.6/tests/test_extra/test_attribute.py
===================================================================
--- soupsieve-2.6.orig/tests/test_extra/test_attribute.py
+++ soupsieve-2.6/tests/test_extra/test_attribute.py
@@ -62,3 +62,25 @@ class TestAttribute(util.TestCase):
         self.assertEqual(e.context, '[\\]!=D4XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n^')
         self.assertEqual(e.line, 1)
         self.assertEqual(e.col, 1)
+
+    def test_bad_attribute_unclused(self):
+        """Test bad attribute fails for syntax error, not timeout error."""
+
+        import signal
+
+        def timeout_handler(signum, frame):
+            raise TimeoutError
+
+        signal.signal(signal.SIGALRM, timeout_handler)
+        signal.alarm(3)
+
+        passed = False
+        try:
+            with self.assertRaises(sv.SelectorSyntaxError):
+                sv.compile('[a="' + ('x' * 300))
+            passed = True
+        except TimeoutError:
+            pass
+        finally:
+            signal.alarm(0)
+        self.assertTrue(passed)
