perf: expose subject-local selector proofs

This commit is contained in:
Kinneyzhang 2026-08-25 17:16:55 +08:00
parent 1275322d6c
commit db071d7768
3 changed files with 35 additions and 2 deletions

View File

@ -14,12 +14,12 @@ test: clean
compile: clean
$(EMACS) -Q --batch $(LOADPATH) \
--eval '(setq byte-compile-error-on-warn t)' \
--eval '(setq byte-compile-error-on-warn t byte-compile-warnings (quote (not obsolete)))' \
-f batch-byte-compile $(SRC)
compile-all: clean
$(EMACS) -Q --batch $(LOADPATH) \
--eval '(setq byte-compile-error-on-warn t)' \
--eval '(setq byte-compile-error-on-warn t byte-compile-warnings (quote (not obsolete)))' \
-f batch-byte-compile $(SRC) $(TESTS)
checkdoc:

View File

@ -485,6 +485,24 @@ an alist. PARENT and CHILDREN establish its initial tree position."
(let ((ast (if (stringp selector) (ecss-selector-parse selector) selector)))
(ecss--copy-boundary-data (ecss--validate-selector ast))))
(defun ecss--selector-subject-local-p (selector)
"Return non-nil when validated SELECTOR reads only its subject."
(pcase (car selector)
((or :universal :type :id :class :state :attr) t)
((or :and :list :is :where :not)
(cl-every #'ecss--selector-subject-local-p (cdr selector)))
(_ nil)))
;;;###autoload
(defun ecss-selector-subject-local-p (selector)
"Return non-nil when SELECTOR depends only on the matched subject.
Subject-local selectors may inspect type, id, classes, attributes, states,
and local logical combinations such as `:is' and `:not'. Selectors involving
ancestors, children, or siblings return nil. Invalid selectors signal
`ecss-invalid-selector'."
(ecss--selector-subject-local-p (ecss-selector-normalize selector)))
(defun ecss--subject-attribute-cell (subject adapter name)
"Return SUBJECT attribute NAME through ADAPTER."
(assoc name (ecss--adapter-call adapter 'attributes subject)))

View File

@ -151,6 +151,21 @@
(should-error (ecss-selector-normalize '(:unknown value))
:type 'ecss-invalid-selector))
(ert-deftest ecss-selector-test-reports-subject-local-dependencies ()
"Selector dependency classification distinguishes tree-sensitive forms."
(dolist (selector
'("*" ".card" "button#save.primary[role=submit]:active"
"button:is(.primary, [role=submit])"
".card:not(.disabled)" ".card, #fallback"))
(should (ecss-selector-subject-local-p selector)))
(dolist (selector
'("section .card" "section > .card" ".active + .target"
".active ~ .target" "section:has(.card)"))
(should-not (ecss-selector-subject-local-p selector)))
(should-not (ecss-selector-subject-local-p '(:anchor)))
(should-error (ecss-selector-subject-local-p '(:unknown value))
:type 'ecss-invalid-selector))
(ert-deftest ecss-selector-test-comments-escapes-and-quoted-attributes ()
(let ((subject (ecss-subject-create
:type "div" :classes '("card" "a:b")