feat(ecss): finalize independent cascade contract

Add shorthand-aware direct declaration composition, keep the public API consumer-neutral, and record the initial standalone release contract.

Verified: make check; make package-lint.
This commit is contained in:
Kinneyzhang 2026-08-06 23:42:01 +08:00
parent 2f32ca0982
commit 9f6025ee12
5 changed files with 41 additions and 2 deletions

12
CHANGELOG.md Normal file
View File

@ -0,0 +1,12 @@
# Changelog
All notable changes to `ecss` are documented here.
## 0.1.0 (Unreleased)
### Added
- Independent property schemas, generic subjects and adapters, selector parsing and matching, stylesheets, complete cascade ordering, CSS-wide values, custom properties, computed values, diagnostics, and provenance.
- Pure Ebox-neutral public APIs with no TP dependency and no Buffer mutation.
- `ecss-merge-declarations` for shorthand-aware, presence-preserving composition of direct declaration groups.
- Standalone tests and compile, checkdoc, package-lint, and whitespace verification targets.

View File

@ -9,8 +9,9 @@
- `(ecss-schema-set-property SCHEMAS ID)` returns a defensive schema copy.
- `(ecss-schema-set-property-ids SCHEMAS)` returns stable registration order.
- `(ecss-expand-declarations SCHEMAS DECLARATIONS)` validates properties and expands each shorthand once.
- `(ecss-merge-declarations SCHEMAS &rest DECLARATION-GROUPS)` expands and merges groups from left to right. Later groups replace the same longhand, while explicit nil remains a declaration.
A property ID is a symbol containing `/`, such as `ebox/color`. Custom properties need no schema and use `--name` symbols. `initial` is normalized and validated once at schema registration; already computed initial and inherited values do not run the normalizer again.
A property ID is a symbol containing `/`, such as `demo/color`. Custom properties need no schema and use `--name` symbols. `initial` is normalized and validated once at schema registration; already computed initial and inherited values do not run the normalizer again.
## Subjects and selectors

View File

@ -9,8 +9,9 @@
- `(ecss-schema-set-property SCHEMAS ID)` 返回 defensive schema copy。
- `(ecss-schema-set-property-ids SCHEMAS)` 返回稳定注册顺序。
- `(ecss-expand-declarations SCHEMAS DECLARATIONS)` 校验属性并只展开一次 shorthand。
- `(ecss-merge-declarations SCHEMAS &rest DECLARATION-GROUPS)` 按从左到右的优先级展开并合并多组声明;后组覆盖相同 longhand显式 nil 不会被当作缺省。
Property ID 必须是包含 `/` 的 symbol例如 `ebox/color`。Custom property 不需要 schema使用 `--name` symbol。`initial` 在 schema 注册时规范化并校验一次;已计算的 initial/inherited value 不会再次执行 normalizer。
Property ID 必须是包含 `/` 的 symbol例如 `demo/color`。Custom property 不需要 schema使用 `--name` symbol。`initial` 在 schema 注册时规范化并校验一次;已计算的 initial/inherited value 不会再次执行 normalizer。
## Subject 与 selector

View File

@ -268,6 +268,19 @@
(cl-loop for (property value) on declarations by #'cddr
append (ecss--expand-declaration schemas property value)))
;;;###autoload
(defun ecss-merge-declarations (schemas &rest declaration-groups)
"Merge DECLARATION-GROUPS into canonical longhands using SCHEMAS.
Groups are applied from left to right. Later values replace earlier values for
the same expanded longhand, including explicit nil declarations."
(ecss--schema-set-check schemas)
(let (result)
(dolist (declarations declaration-groups result)
(cl-loop for (property value)
on (ecss-expand-declarations schemas declarations) by #'cddr
do (setq result
(plist-put result property (copy-tree value)))))))
(defun ecss-stylesheet-create ()
"Create an empty independent stylesheet."
(ecss--make-stylesheet :rules nil :layers nil :source-order 0))

View File

@ -89,6 +89,18 @@
do (should (ecss--important-p value))
do (should (= (ecss--important-value value) 3)))))
(ert-deftest ecss-cascade-test-merge-declarations-compacts-expanded-longhands ()
"Later declaration groups should replace expanded longhands without loss."
(let ((schemas (ecss-cascade-test--schemas)))
(should
(equal
(ecss-merge-declarations
schemas
'(app/padding 1 app/color "blue")
'(app/padding-left 4 app/color nil))
'(app/padding-top 1 app/padding-right 1
app/padding-bottom 1 app/padding-left 4 app/color nil)))))
(ert-deftest ecss-cascade-test-shorthand-and-longhand-follow-declaration-order ()
(let ((schemas (ecss-cascade-test--schemas))
(subject (ecss-cascade-test--subject)))