@tenphi/tasty 0.1.0

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.
Files changed (359) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +236 -0
  3. package/dist/_virtual/_rolldown/runtime.mjs +7 -0
  4. package/dist/chunks/cacheKey.d.ts +1 -0
  5. package/dist/chunks/cacheKey.js +70 -0
  6. package/dist/chunks/cacheKey.js.map +1 -0
  7. package/dist/chunks/cacheKey.mjs +70 -0
  8. package/dist/chunks/cacheKey.mjs.map +1 -0
  9. package/dist/chunks/definitions.d.ts +37 -0
  10. package/dist/chunks/definitions.js +260 -0
  11. package/dist/chunks/definitions.js.map +1 -0
  12. package/dist/chunks/definitions.mjs +260 -0
  13. package/dist/chunks/definitions.mjs.map +1 -0
  14. package/dist/chunks/index.d.ts +3 -0
  15. package/dist/chunks/renderChunk.d.ts +2 -0
  16. package/dist/chunks/renderChunk.js +61 -0
  17. package/dist/chunks/renderChunk.js.map +1 -0
  18. package/dist/chunks/renderChunk.mjs +61 -0
  19. package/dist/chunks/renderChunk.mjs.map +1 -0
  20. package/dist/config.d.ts +279 -0
  21. package/dist/config.js +400 -0
  22. package/dist/config.js.map +1 -0
  23. package/dist/config.mjs +231 -0
  24. package/dist/config.mjs.map +1 -0
  25. package/dist/css-writer.d.mts +45 -0
  26. package/dist/css-writer.mjs +74 -0
  27. package/dist/css-writer.mjs.map +1 -0
  28. package/dist/debug.d.ts +204 -0
  29. package/dist/debug.js +733 -0
  30. package/dist/debug.js.map +1 -0
  31. package/dist/extractor.d.mts +24 -0
  32. package/dist/extractor.mjs +150 -0
  33. package/dist/extractor.mjs.map +1 -0
  34. package/dist/hooks/index.d.ts +5 -0
  35. package/dist/hooks/useGlobalStyles.d.ts +27 -0
  36. package/dist/hooks/useGlobalStyles.js +56 -0
  37. package/dist/hooks/useGlobalStyles.js.map +1 -0
  38. package/dist/hooks/useKeyframes.d.ts +56 -0
  39. package/dist/hooks/useKeyframes.js +54 -0
  40. package/dist/hooks/useKeyframes.js.map +1 -0
  41. package/dist/hooks/useProperty.d.ts +79 -0
  42. package/dist/hooks/useProperty.js +91 -0
  43. package/dist/hooks/useProperty.js.map +1 -0
  44. package/dist/hooks/useRawCSS.d.ts +53 -0
  45. package/dist/hooks/useRawCSS.js +28 -0
  46. package/dist/hooks/useRawCSS.js.map +1 -0
  47. package/dist/hooks/useStyles.d.ts +40 -0
  48. package/dist/hooks/useStyles.js +169 -0
  49. package/dist/hooks/useStyles.js.map +1 -0
  50. package/dist/index.d.ts +38 -0
  51. package/dist/index.js +30 -0
  52. package/dist/injector/index.d.ts +157 -0
  53. package/dist/injector/index.js +154 -0
  54. package/dist/injector/index.js.map +1 -0
  55. package/dist/injector/injector.d.ts +139 -0
  56. package/dist/injector/injector.js +404 -0
  57. package/dist/injector/injector.js.map +1 -0
  58. package/dist/injector/injector.mjs +404 -0
  59. package/dist/injector/injector.mjs.map +1 -0
  60. package/dist/injector/sheet-manager.d.ts +127 -0
  61. package/dist/injector/sheet-manager.js +714 -0
  62. package/dist/injector/sheet-manager.js.map +1 -0
  63. package/dist/injector/sheet-manager.mjs +714 -0
  64. package/dist/injector/sheet-manager.mjs.map +1 -0
  65. package/dist/injector/types.d.mts +18 -0
  66. package/dist/injector/types.d.ts +135 -0
  67. package/dist/keyframes/index.js +206 -0
  68. package/dist/keyframes/index.js.map +1 -0
  69. package/dist/keyframes/index.mjs +156 -0
  70. package/dist/keyframes/index.mjs.map +1 -0
  71. package/dist/parser/classify.js +319 -0
  72. package/dist/parser/classify.js.map +1 -0
  73. package/dist/parser/classify.mjs +319 -0
  74. package/dist/parser/classify.mjs.map +1 -0
  75. package/dist/parser/const.js +33 -0
  76. package/dist/parser/const.js.map +1 -0
  77. package/dist/parser/const.mjs +33 -0
  78. package/dist/parser/const.mjs.map +1 -0
  79. package/dist/parser/lru.js +109 -0
  80. package/dist/parser/lru.js.map +1 -0
  81. package/dist/parser/lru.mjs +109 -0
  82. package/dist/parser/lru.mjs.map +1 -0
  83. package/dist/parser/parser.d.ts +25 -0
  84. package/dist/parser/parser.js +116 -0
  85. package/dist/parser/parser.js.map +1 -0
  86. package/dist/parser/parser.mjs +116 -0
  87. package/dist/parser/parser.mjs.map +1 -0
  88. package/dist/parser/tokenizer.js +69 -0
  89. package/dist/parser/tokenizer.js.map +1 -0
  90. package/dist/parser/tokenizer.mjs +69 -0
  91. package/dist/parser/tokenizer.mjs.map +1 -0
  92. package/dist/parser/types.d.mts +37 -0
  93. package/dist/parser/types.d.ts +46 -0
  94. package/dist/parser/types.js +46 -0
  95. package/dist/parser/types.js.map +1 -0
  96. package/dist/parser/types.mjs +46 -0
  97. package/dist/parser/types.mjs.map +1 -0
  98. package/dist/pipeline/conditions.js +377 -0
  99. package/dist/pipeline/conditions.js.map +1 -0
  100. package/dist/pipeline/conditions.mjs +377 -0
  101. package/dist/pipeline/conditions.mjs.map +1 -0
  102. package/dist/pipeline/exclusive.d.ts +1 -0
  103. package/dist/pipeline/exclusive.js +231 -0
  104. package/dist/pipeline/exclusive.js.map +1 -0
  105. package/dist/pipeline/exclusive.mjs +231 -0
  106. package/dist/pipeline/exclusive.mjs.map +1 -0
  107. package/dist/pipeline/index.d.ts +53 -0
  108. package/dist/pipeline/index.js +641 -0
  109. package/dist/pipeline/index.js.map +1 -0
  110. package/dist/pipeline/index.mjs +635 -0
  111. package/dist/pipeline/index.mjs.map +1 -0
  112. package/dist/pipeline/materialize.js +821 -0
  113. package/dist/pipeline/materialize.js.map +1 -0
  114. package/dist/pipeline/materialize.mjs +821 -0
  115. package/dist/pipeline/materialize.mjs.map +1 -0
  116. package/dist/pipeline/parseStateKey.d.ts +1 -0
  117. package/dist/pipeline/parseStateKey.js +418 -0
  118. package/dist/pipeline/parseStateKey.js.map +1 -0
  119. package/dist/pipeline/parseStateKey.mjs +418 -0
  120. package/dist/pipeline/parseStateKey.mjs.map +1 -0
  121. package/dist/pipeline/simplify.js +557 -0
  122. package/dist/pipeline/simplify.js.map +1 -0
  123. package/dist/pipeline/simplify.mjs +557 -0
  124. package/dist/pipeline/simplify.mjs.map +1 -0
  125. package/dist/plugins/index.d.ts +2 -0
  126. package/dist/plugins/okhsl-plugin.d.ts +35 -0
  127. package/dist/plugins/okhsl-plugin.js +371 -0
  128. package/dist/plugins/okhsl-plugin.js.map +1 -0
  129. package/dist/plugins/okhsl-plugin.mjs +345 -0
  130. package/dist/plugins/okhsl-plugin.mjs.map +1 -0
  131. package/dist/plugins/types.d.mts +49 -0
  132. package/dist/plugins/types.d.ts +69 -0
  133. package/dist/properties/index.js +158 -0
  134. package/dist/properties/index.js.map +1 -0
  135. package/dist/properties/index.mjs +141 -0
  136. package/dist/properties/index.mjs.map +1 -0
  137. package/dist/states/index.d.ts +45 -0
  138. package/dist/states/index.js +389 -0
  139. package/dist/states/index.js.map +1 -0
  140. package/dist/states/index.mjs +161 -0
  141. package/dist/states/index.mjs.map +1 -0
  142. package/dist/static/index.d.ts +5 -0
  143. package/dist/static/index.js +5 -0
  144. package/dist/static/tastyStatic.d.ts +46 -0
  145. package/dist/static/tastyStatic.js +31 -0
  146. package/dist/static/tastyStatic.js.map +1 -0
  147. package/dist/static/types.d.ts +49 -0
  148. package/dist/static/types.js +24 -0
  149. package/dist/static/types.js.map +1 -0
  150. package/dist/styles/align.d.ts +15 -0
  151. package/dist/styles/align.js +14 -0
  152. package/dist/styles/align.js.map +1 -0
  153. package/dist/styles/align.mjs +14 -0
  154. package/dist/styles/align.mjs.map +1 -0
  155. package/dist/styles/border.d.ts +25 -0
  156. package/dist/styles/border.js +114 -0
  157. package/dist/styles/border.js.map +1 -0
  158. package/dist/styles/border.mjs +114 -0
  159. package/dist/styles/border.mjs.map +1 -0
  160. package/dist/styles/color.d.ts +14 -0
  161. package/dist/styles/color.js +23 -0
  162. package/dist/styles/color.js.map +1 -0
  163. package/dist/styles/color.mjs +23 -0
  164. package/dist/styles/color.mjs.map +1 -0
  165. package/dist/styles/createStyle.js +77 -0
  166. package/dist/styles/createStyle.js.map +1 -0
  167. package/dist/styles/createStyle.mjs +77 -0
  168. package/dist/styles/createStyle.mjs.map +1 -0
  169. package/dist/styles/dimension.js +97 -0
  170. package/dist/styles/dimension.js.map +1 -0
  171. package/dist/styles/dimension.mjs +97 -0
  172. package/dist/styles/dimension.mjs.map +1 -0
  173. package/dist/styles/display.d.ts +37 -0
  174. package/dist/styles/display.js +67 -0
  175. package/dist/styles/display.js.map +1 -0
  176. package/dist/styles/display.mjs +67 -0
  177. package/dist/styles/display.mjs.map +1 -0
  178. package/dist/styles/fade.d.ts +15 -0
  179. package/dist/styles/fade.js +58 -0
  180. package/dist/styles/fade.js.map +1 -0
  181. package/dist/styles/fade.mjs +58 -0
  182. package/dist/styles/fade.mjs.map +1 -0
  183. package/dist/styles/fill.d.ts +44 -0
  184. package/dist/styles/fill.js +51 -0
  185. package/dist/styles/fill.js.map +1 -0
  186. package/dist/styles/fill.mjs +51 -0
  187. package/dist/styles/fill.mjs.map +1 -0
  188. package/dist/styles/flow.d.ts +16 -0
  189. package/dist/styles/flow.js +12 -0
  190. package/dist/styles/flow.js.map +1 -0
  191. package/dist/styles/flow.mjs +12 -0
  192. package/dist/styles/flow.mjs.map +1 -0
  193. package/dist/styles/gap.d.ts +31 -0
  194. package/dist/styles/gap.js +37 -0
  195. package/dist/styles/gap.js.map +1 -0
  196. package/dist/styles/gap.mjs +37 -0
  197. package/dist/styles/gap.mjs.map +1 -0
  198. package/dist/styles/height.d.ts +17 -0
  199. package/dist/styles/height.js +20 -0
  200. package/dist/styles/height.js.map +1 -0
  201. package/dist/styles/height.mjs +20 -0
  202. package/dist/styles/height.mjs.map +1 -0
  203. package/dist/styles/index.d.ts +2 -0
  204. package/dist/styles/index.js +9 -0
  205. package/dist/styles/index.js.map +1 -0
  206. package/dist/styles/index.mjs +9 -0
  207. package/dist/styles/index.mjs.map +1 -0
  208. package/dist/styles/inset.d.ts +50 -0
  209. package/dist/styles/inset.js +142 -0
  210. package/dist/styles/inset.js.map +1 -0
  211. package/dist/styles/inset.mjs +142 -0
  212. package/dist/styles/inset.mjs.map +1 -0
  213. package/dist/styles/justify.d.ts +15 -0
  214. package/dist/styles/justify.js +14 -0
  215. package/dist/styles/justify.js.map +1 -0
  216. package/dist/styles/justify.mjs +14 -0
  217. package/dist/styles/justify.mjs.map +1 -0
  218. package/dist/styles/list.d.ts +16 -0
  219. package/dist/styles/list.js +98 -0
  220. package/dist/styles/list.js.map +1 -0
  221. package/dist/styles/margin.d.ts +28 -0
  222. package/dist/styles/margin.js +96 -0
  223. package/dist/styles/margin.js.map +1 -0
  224. package/dist/styles/margin.mjs +96 -0
  225. package/dist/styles/margin.mjs.map +1 -0
  226. package/dist/styles/outline.d.ts +29 -0
  227. package/dist/styles/outline.js +65 -0
  228. package/dist/styles/outline.js.map +1 -0
  229. package/dist/styles/outline.mjs +65 -0
  230. package/dist/styles/outline.mjs.map +1 -0
  231. package/dist/styles/padding.d.ts +28 -0
  232. package/dist/styles/padding.js +96 -0
  233. package/dist/styles/padding.js.map +1 -0
  234. package/dist/styles/padding.mjs +96 -0
  235. package/dist/styles/padding.mjs.map +1 -0
  236. package/dist/styles/predefined.d.ts +74 -0
  237. package/dist/styles/predefined.js +241 -0
  238. package/dist/styles/predefined.js.map +1 -0
  239. package/dist/styles/predefined.mjs +232 -0
  240. package/dist/styles/predefined.mjs.map +1 -0
  241. package/dist/styles/preset.d.ts +47 -0
  242. package/dist/styles/preset.js +126 -0
  243. package/dist/styles/preset.js.map +1 -0
  244. package/dist/styles/preset.mjs +126 -0
  245. package/dist/styles/preset.mjs.map +1 -0
  246. package/dist/styles/radius.d.ts +14 -0
  247. package/dist/styles/radius.js +51 -0
  248. package/dist/styles/radius.js.map +1 -0
  249. package/dist/styles/radius.mjs +51 -0
  250. package/dist/styles/radius.mjs.map +1 -0
  251. package/dist/styles/scrollbar.d.ts +21 -0
  252. package/dist/styles/scrollbar.js +105 -0
  253. package/dist/styles/scrollbar.js.map +1 -0
  254. package/dist/styles/scrollbar.mjs +105 -0
  255. package/dist/styles/scrollbar.mjs.map +1 -0
  256. package/dist/styles/shadow.d.ts +14 -0
  257. package/dist/styles/shadow.js +24 -0
  258. package/dist/styles/shadow.js.map +1 -0
  259. package/dist/styles/shadow.mjs +24 -0
  260. package/dist/styles/shadow.mjs.map +1 -0
  261. package/dist/styles/styledScrollbar.d.ts +47 -0
  262. package/dist/styles/styledScrollbar.js +38 -0
  263. package/dist/styles/styledScrollbar.js.map +1 -0
  264. package/dist/styles/styledScrollbar.mjs +38 -0
  265. package/dist/styles/styledScrollbar.mjs.map +1 -0
  266. package/dist/styles/transition.d.ts +14 -0
  267. package/dist/styles/transition.js +138 -0
  268. package/dist/styles/transition.js.map +1 -0
  269. package/dist/styles/transition.mjs +138 -0
  270. package/dist/styles/transition.mjs.map +1 -0
  271. package/dist/styles/types.d.mts +492 -0
  272. package/dist/styles/types.d.ts +496 -0
  273. package/dist/styles/width.d.ts +17 -0
  274. package/dist/styles/width.js +20 -0
  275. package/dist/styles/width.js.map +1 -0
  276. package/dist/styles/width.mjs +20 -0
  277. package/dist/styles/width.mjs.map +1 -0
  278. package/dist/tasty.d.ts +983 -0
  279. package/dist/tasty.js +191 -0
  280. package/dist/tasty.js.map +1 -0
  281. package/dist/tokens/typography.d.ts +19 -0
  282. package/dist/tokens/typography.js +237 -0
  283. package/dist/tokens/typography.js.map +1 -0
  284. package/dist/types.d.ts +182 -0
  285. package/dist/utils/cache-wrapper.js +26 -0
  286. package/dist/utils/cache-wrapper.js.map +1 -0
  287. package/dist/utils/cache-wrapper.mjs +26 -0
  288. package/dist/utils/cache-wrapper.mjs.map +1 -0
  289. package/dist/utils/case-converter.js +8 -0
  290. package/dist/utils/case-converter.js.map +1 -0
  291. package/dist/utils/case-converter.mjs +8 -0
  292. package/dist/utils/case-converter.mjs.map +1 -0
  293. package/dist/utils/colors.d.ts +5 -0
  294. package/dist/utils/colors.js +9 -0
  295. package/dist/utils/colors.js.map +1 -0
  296. package/dist/utils/dotize.d.ts +26 -0
  297. package/dist/utils/dotize.js +122 -0
  298. package/dist/utils/dotize.js.map +1 -0
  299. package/dist/utils/filter-base-props.d.ts +15 -0
  300. package/dist/utils/filter-base-props.js +45 -0
  301. package/dist/utils/filter-base-props.js.map +1 -0
  302. package/dist/utils/get-display-name.d.ts +7 -0
  303. package/dist/utils/get-display-name.js +10 -0
  304. package/dist/utils/get-display-name.js.map +1 -0
  305. package/dist/utils/hsl-to-rgb.js +38 -0
  306. package/dist/utils/hsl-to-rgb.js.map +1 -0
  307. package/dist/utils/hsl-to-rgb.mjs +38 -0
  308. package/dist/utils/hsl-to-rgb.mjs.map +1 -0
  309. package/dist/utils/is-dev-env.js +19 -0
  310. package/dist/utils/is-dev-env.js.map +1 -0
  311. package/dist/utils/is-dev-env.mjs +19 -0
  312. package/dist/utils/is-dev-env.mjs.map +1 -0
  313. package/dist/utils/merge-styles.d.ts +7 -0
  314. package/dist/utils/merge-styles.js +146 -0
  315. package/dist/utils/merge-styles.js.map +1 -0
  316. package/dist/utils/merge-styles.mjs +146 -0
  317. package/dist/utils/merge-styles.mjs.map +1 -0
  318. package/dist/utils/mod-attrs.d.ts +8 -0
  319. package/dist/utils/mod-attrs.js +21 -0
  320. package/dist/utils/mod-attrs.js.map +1 -0
  321. package/dist/utils/okhsl-to-rgb.js +296 -0
  322. package/dist/utils/okhsl-to-rgb.js.map +1 -0
  323. package/dist/utils/okhsl-to-rgb.mjs +296 -0
  324. package/dist/utils/okhsl-to-rgb.mjs.map +1 -0
  325. package/dist/utils/process-tokens.d.ts +31 -0
  326. package/dist/utils/process-tokens.js +171 -0
  327. package/dist/utils/process-tokens.js.map +1 -0
  328. package/dist/utils/process-tokens.mjs +28 -0
  329. package/dist/utils/process-tokens.mjs.map +1 -0
  330. package/dist/utils/resolve-recipes.d.ts +17 -0
  331. package/dist/utils/resolve-recipes.js +143 -0
  332. package/dist/utils/resolve-recipes.js.map +1 -0
  333. package/dist/utils/resolve-recipes.mjs +143 -0
  334. package/dist/utils/resolve-recipes.mjs.map +1 -0
  335. package/dist/utils/string.js +8 -0
  336. package/dist/utils/string.js.map +1 -0
  337. package/dist/utils/string.mjs +8 -0
  338. package/dist/utils/string.mjs.map +1 -0
  339. package/dist/utils/styles.d.mts +18 -0
  340. package/dist/utils/styles.d.ts +183 -0
  341. package/dist/utils/styles.js +585 -0
  342. package/dist/utils/styles.js.map +1 -0
  343. package/dist/utils/styles.mjs +346 -0
  344. package/dist/utils/styles.mjs.map +1 -0
  345. package/dist/utils/typography.d.ts +36 -0
  346. package/dist/utils/typography.js +53 -0
  347. package/dist/utils/typography.js.map +1 -0
  348. package/dist/utils/warnings.d.ts +16 -0
  349. package/dist/utils/warnings.js +16 -0
  350. package/dist/utils/warnings.js.map +1 -0
  351. package/dist/zero/babel.d.mts +108 -0
  352. package/dist/zero/babel.mjs +282 -0
  353. package/dist/zero/babel.mjs.map +1 -0
  354. package/dist/zero/index.d.mts +3 -0
  355. package/dist/zero/index.mjs +4 -0
  356. package/dist/zero/next.d.mts +60 -0
  357. package/dist/zero/next.mjs +78 -0
  358. package/dist/zero/next.mjs.map +1 -0
  359. package/package.json +127 -0
@@ -0,0 +1,557 @@
1
+ import { Lru } from "../parser/lru.js";
2
+ import { falseCondition, getConditionUniqueId, trueCondition } from "./conditions.js";
3
+
4
+ //#region src/pipeline/simplify.ts
5
+ /**
6
+ * Condition Simplification Engine
7
+ *
8
+ * Simplifies condition trees by applying boolean algebra rules,
9
+ * detecting contradictions, merging ranges, and deduplicating terms.
10
+ *
11
+ * This is critical for:
12
+ * 1. Detecting invalid combinations (A & !A → FALSE)
13
+ * 2. Reducing CSS output size
14
+ * 3. Producing cleaner selectors
15
+ */
16
+ const simplifyCache = new Lru(5e3);
17
+ /**
18
+ * Simplify a condition tree aggressively.
19
+ *
20
+ * This applies all possible simplification rules:
21
+ * - Boolean algebra (identity, annihilator, idempotent, absorption)
22
+ * - Contradiction detection (A & !A → FALSE)
23
+ * - Tautology detection (A | !A → TRUE)
24
+ * - Range intersection for numeric queries
25
+ * - Attribute value conflict detection
26
+ * - Deduplication and sorting
27
+ */
28
+ function simplifyCondition(node) {
29
+ const key = getConditionUniqueId(node);
30
+ const cached = simplifyCache.get(key);
31
+ if (cached) return cached;
32
+ const result = simplifyInner(node);
33
+ simplifyCache.set(key, result);
34
+ return result;
35
+ }
36
+ function simplifyInner(node) {
37
+ if (node.kind === "true" || node.kind === "false") return node;
38
+ if (node.kind === "state") return node;
39
+ if (node.kind === "compound") {
40
+ const simplifiedChildren = node.children.map((c) => simplifyInner(c));
41
+ if (node.operator === "AND") return simplifyAnd(simplifiedChildren);
42
+ else return simplifyOr(simplifiedChildren);
43
+ }
44
+ return node;
45
+ }
46
+ function simplifyAnd(children) {
47
+ let terms = [];
48
+ for (const child of children) {
49
+ if (child.kind === "false") return falseCondition();
50
+ if (child.kind === "true") continue;
51
+ if (child.kind === "compound" && child.operator === "AND") terms.push(...child.children);
52
+ else terms.push(child);
53
+ }
54
+ if (terms.length === 0) return trueCondition();
55
+ if (terms.length === 1) return terms[0];
56
+ if (hasContradiction(terms)) return falseCondition();
57
+ if (hasRangeContradiction(terms)) return falseCondition();
58
+ if (hasAttributeConflict(terms)) return falseCondition();
59
+ if (hasContainerStyleConflict(terms)) return falseCondition();
60
+ terms = removeImpliedNegations(terms);
61
+ terms = deduplicateTerms(terms);
62
+ terms = mergeRanges(terms);
63
+ terms = sortTerms(terms);
64
+ terms = applyAbsorptionAnd(terms);
65
+ if (terms.length === 0) return trueCondition();
66
+ if (terms.length === 1) return terms[0];
67
+ return {
68
+ kind: "compound",
69
+ operator: "AND",
70
+ children: terms
71
+ };
72
+ }
73
+ function simplifyOr(children) {
74
+ let terms = [];
75
+ for (const child of children) {
76
+ if (child.kind === "true") return trueCondition();
77
+ if (child.kind === "false") continue;
78
+ if (child.kind === "compound" && child.operator === "OR") terms.push(...child.children);
79
+ else terms.push(child);
80
+ }
81
+ if (terms.length === 0) return falseCondition();
82
+ if (terms.length === 1) return terms[0];
83
+ if (hasTautology(terms)) return trueCondition();
84
+ terms = deduplicateTerms(terms);
85
+ terms = sortTerms(terms);
86
+ terms = applyAbsorptionOr(terms);
87
+ if (terms.length === 0) return falseCondition();
88
+ if (terms.length === 1) return terms[0];
89
+ return {
90
+ kind: "compound",
91
+ operator: "OR",
92
+ children: terms
93
+ };
94
+ }
95
+ /**
96
+ * Check if any term contradicts another (A & !A)
97
+ */
98
+ function hasContradiction(terms) {
99
+ const uniqueIds = /* @__PURE__ */ new Set();
100
+ for (const term of terms) {
101
+ if (term.kind !== "state") continue;
102
+ const id = term.uniqueId;
103
+ const negatedId = term.negated ? id.slice(1) : `!${id}`;
104
+ if (uniqueIds.has(negatedId)) return true;
105
+ uniqueIds.add(id);
106
+ }
107
+ return false;
108
+ }
109
+ /**
110
+ * Check for tautologies (A | !A)
111
+ */
112
+ function hasTautology(terms) {
113
+ const uniqueIds = /* @__PURE__ */ new Set();
114
+ for (const term of terms) {
115
+ if (term.kind !== "state") continue;
116
+ const id = term.uniqueId;
117
+ const negatedId = term.negated ? id.slice(1) : `!${id}`;
118
+ if (uniqueIds.has(negatedId)) return true;
119
+ uniqueIds.add(id);
120
+ }
121
+ return false;
122
+ }
123
+ /**
124
+ * Check for range contradictions in media/container queries
125
+ * e.g., @media(w < 400px) & @media(w > 800px) → FALSE
126
+ *
127
+ * Also handles negated conditions:
128
+ * - Single-bound negations are inverted (not (w < 600px) → w >= 600px)
129
+ * - Range negations create excluded ranges that are checked against positive bounds
130
+ */
131
+ function hasRangeContradiction(terms) {
132
+ const mediaByDim = /* @__PURE__ */ new Map();
133
+ const containerByDim = /* @__PURE__ */ new Map();
134
+ for (const term of terms) {
135
+ if (term.kind !== "state") continue;
136
+ if (term.type === "media" && term.subtype === "dimension") {
137
+ const key = term.dimension || "width";
138
+ if (!mediaByDim.has(key)) mediaByDim.set(key, {
139
+ positive: [],
140
+ negated: []
141
+ });
142
+ const group = mediaByDim.get(key);
143
+ if (term.negated) group.negated.push(term);
144
+ else group.positive.push(term);
145
+ }
146
+ if (term.type === "container" && term.subtype === "dimension") {
147
+ const key = `${term.containerName || "_"}:${term.dimension || "width"}`;
148
+ if (!containerByDim.has(key)) containerByDim.set(key, {
149
+ positive: [],
150
+ negated: []
151
+ });
152
+ const group = containerByDim.get(key);
153
+ if (term.negated) group.negated.push(term);
154
+ else group.positive.push(term);
155
+ }
156
+ }
157
+ for (const group of mediaByDim.values()) if (rangesAreImpossibleWithNegations(group.positive, group.negated)) return true;
158
+ for (const group of containerByDim.values()) if (rangesAreImpossibleWithNegations(group.positive, group.negated)) return true;
159
+ return false;
160
+ }
161
+ /**
162
+ * Check if conditions are impossible, including negated conditions.
163
+ *
164
+ * For negated single-bound conditions:
165
+ * not (w < 600px) → w >= 600px (inverted to lower bound)
166
+ * not (w >= 800px) → w < 800px (inverted to upper bound)
167
+ *
168
+ * For negated range conditions:
169
+ * not (400px <= w < 800px) → excludes [400, 800)
170
+ * If the effective bounds fall entirely within an excluded range, it's impossible.
171
+ */
172
+ function rangesAreImpossibleWithNegations(positive, negated) {
173
+ const bounds = computeEffectiveBounds(positive);
174
+ const excludedRanges = [];
175
+ for (const cond of negated) {
176
+ const hasLower = cond.lowerBound?.valueNumeric != null;
177
+ const hasUpper = cond.upperBound?.valueNumeric != null;
178
+ if (hasLower && hasUpper) excludedRanges.push({
179
+ lower: cond.lowerBound.valueNumeric,
180
+ lowerInclusive: cond.lowerBound.inclusive,
181
+ upper: cond.upperBound.valueNumeric,
182
+ upperInclusive: cond.upperBound.inclusive
183
+ });
184
+ else if (hasUpper) {
185
+ const value = cond.upperBound.valueNumeric;
186
+ const inclusive = !cond.upperBound.inclusive;
187
+ if (bounds.lowerBound === null || value > bounds.lowerBound) {
188
+ bounds.lowerBound = value;
189
+ bounds.lowerInclusive = inclusive;
190
+ } else if (value === bounds.lowerBound && !inclusive) bounds.lowerInclusive = false;
191
+ } else if (hasLower) {
192
+ const value = cond.lowerBound.valueNumeric;
193
+ const inclusive = !cond.lowerBound.inclusive;
194
+ if (bounds.upperBound === null || value < bounds.upperBound) {
195
+ bounds.upperBound = value;
196
+ bounds.upperInclusive = inclusive;
197
+ } else if (value === bounds.upperBound && !inclusive) bounds.upperInclusive = false;
198
+ }
199
+ }
200
+ if (bounds.lowerBound !== null && bounds.upperBound !== null) {
201
+ if (bounds.lowerBound > bounds.upperBound) return true;
202
+ if (bounds.lowerBound === bounds.upperBound && (!bounds.lowerInclusive || !bounds.upperInclusive)) return true;
203
+ }
204
+ if (bounds.lowerBound !== null && bounds.upperBound !== null && excludedRanges.length > 0) {
205
+ for (const excluded of excludedRanges) if (boundsWithinExcludedRange(bounds, excluded)) return true;
206
+ }
207
+ return false;
208
+ }
209
+ /**
210
+ * Compute effective bounds from positive (non-negated) conditions
211
+ */
212
+ function computeEffectiveBounds(conditions) {
213
+ let lowerBound = null;
214
+ let lowerInclusive = false;
215
+ let upperBound = null;
216
+ let upperInclusive = false;
217
+ for (const cond of conditions) {
218
+ if (cond.lowerBound?.valueNumeric != null) {
219
+ const value = cond.lowerBound.valueNumeric;
220
+ const inclusive = cond.lowerBound.inclusive;
221
+ if (lowerBound === null || value > lowerBound) {
222
+ lowerBound = value;
223
+ lowerInclusive = inclusive;
224
+ } else if (value === lowerBound && !inclusive) lowerInclusive = false;
225
+ }
226
+ if (cond.upperBound?.valueNumeric != null) {
227
+ const value = cond.upperBound.valueNumeric;
228
+ const inclusive = cond.upperBound.inclusive;
229
+ if (upperBound === null || value < upperBound) {
230
+ upperBound = value;
231
+ upperInclusive = inclusive;
232
+ } else if (value === upperBound && !inclusive) upperInclusive = false;
233
+ }
234
+ }
235
+ return {
236
+ lowerBound,
237
+ lowerInclusive,
238
+ upperBound,
239
+ upperInclusive
240
+ };
241
+ }
242
+ /**
243
+ * Check if effective bounds fall entirely within an excluded range.
244
+ *
245
+ * For example:
246
+ * Effective: [400, 800)
247
+ * Excluded: [400, 800)
248
+ * → bounds fall entirely within excluded range → impossible
249
+ */
250
+ function boundsWithinExcludedRange(bounds, excluded) {
251
+ if (bounds.lowerBound === null || bounds.upperBound === null) return false;
252
+ let lowerOk = false;
253
+ if (bounds.lowerBound > excluded.lower) lowerOk = true;
254
+ else if (bounds.lowerBound === excluded.lower) lowerOk = excluded.lowerInclusive || !bounds.lowerInclusive;
255
+ let upperOk = false;
256
+ if (bounds.upperBound < excluded.upper) upperOk = true;
257
+ else if (bounds.upperBound === excluded.upper) upperOk = excluded.upperInclusive || !bounds.upperInclusive;
258
+ return lowerOk && upperOk;
259
+ }
260
+ /**
261
+ * Check for attribute value conflicts
262
+ * e.g., [data-theme="dark"] & [data-theme="light"] → FALSE
263
+ * e.g., [data-theme="dark"] & ![data-theme] → FALSE
264
+ */
265
+ function hasAttributeConflict(terms) {
266
+ const modifiersByAttr = /* @__PURE__ */ new Map();
267
+ for (const term of terms) {
268
+ if (term.kind !== "state" || term.type !== "modifier") continue;
269
+ const attr = term.attribute;
270
+ if (!modifiersByAttr.has(attr)) modifiersByAttr.set(attr, {
271
+ positive: [],
272
+ negated: []
273
+ });
274
+ const group = modifiersByAttr.get(attr);
275
+ if (term.negated) group.negated.push(term);
276
+ else group.positive.push(term);
277
+ }
278
+ for (const [_attr, group] of modifiersByAttr) {
279
+ const positiveValues = group.positive.filter((m) => m.value !== void 0).map((m) => m.value);
280
+ if (new Set(positiveValues).size > 1) return true;
281
+ const hasPositiveValue = group.positive.some((m) => m.value !== void 0);
282
+ const hasNegatedBoolean = group.negated.some((m) => m.value === void 0);
283
+ if (hasPositiveValue && hasNegatedBoolean) return true;
284
+ for (const pos of group.positive) if (pos.value !== void 0) {
285
+ for (const neg of group.negated) if (neg.value === pos.value) return true;
286
+ }
287
+ }
288
+ return false;
289
+ }
290
+ /**
291
+ * Check for container style query conflicts
292
+ * e.g., style(--variant: danger) & style(--variant: success) → FALSE
293
+ * e.g., style(--variant: danger) & not style(--variant) → FALSE
294
+ */
295
+ function hasContainerStyleConflict(terms) {
296
+ const styleByProp = /* @__PURE__ */ new Map();
297
+ for (const term of terms) {
298
+ if (term.kind !== "state" || term.type !== "container" || term.subtype !== "style") continue;
299
+ const key = `${term.containerName || "_"}:${term.property}`;
300
+ if (!styleByProp.has(key)) styleByProp.set(key, {
301
+ positive: [],
302
+ negated: []
303
+ });
304
+ const group = styleByProp.get(key);
305
+ if (term.negated) group.negated.push(term);
306
+ else group.positive.push(term);
307
+ }
308
+ for (const [, group] of styleByProp) {
309
+ const positiveValues = group.positive.filter((c) => c.propertyValue !== void 0).map((c) => c.propertyValue);
310
+ if (new Set(positiveValues).size > 1) return true;
311
+ const hasPositiveValue = group.positive.some((c) => c.propertyValue !== void 0);
312
+ const hasNegatedExistence = group.negated.some((c) => c.propertyValue === void 0);
313
+ if (hasPositiveValue && hasNegatedExistence) return true;
314
+ for (const pos of group.positive) if (pos.propertyValue !== void 0) {
315
+ for (const neg of group.negated) if (neg.propertyValue === pos.propertyValue) return true;
316
+ }
317
+ }
318
+ return false;
319
+ }
320
+ /**
321
+ * Remove negations that are implied by positive terms.
322
+ *
323
+ * Key optimizations:
324
+ * 1. style(--variant: danger) implies NOT style(--variant: success)
325
+ * → If we have style(--variant: danger) & not style(--variant: success),
326
+ * the negation is redundant and can be removed.
327
+ *
328
+ * 2. [data-theme="dark"] implies NOT [data-theme="light"]
329
+ * → Same logic for attribute selectors.
330
+ *
331
+ * This produces cleaner CSS:
332
+ * Before: @container style(--variant: danger) and (not style(--variant: success))
333
+ * After: @container style(--variant: danger)
334
+ */
335
+ function removeImpliedNegations(terms) {
336
+ const positiveContainerStyles = /* @__PURE__ */ new Map();
337
+ const positiveModifiers = /* @__PURE__ */ new Map();
338
+ for (const term of terms) {
339
+ if (term.kind !== "state" || term.negated) continue;
340
+ if (term.type === "container" && term.subtype === "style") {
341
+ const key = `${term.containerName || "_"}:${term.property}`;
342
+ if (term.propertyValue !== void 0) positiveContainerStyles.set(key, term.propertyValue);
343
+ }
344
+ if (term.type === "modifier" && term.value !== void 0) positiveModifiers.set(term.attribute, term.value);
345
+ }
346
+ return terms.filter((term) => {
347
+ if (term.kind !== "state" || !term.negated) return true;
348
+ if (term.type === "container" && term.subtype === "style") {
349
+ const key = `${term.containerName || "_"}:${term.property}`;
350
+ const positiveValue = positiveContainerStyles.get(key);
351
+ if (positiveValue !== void 0) {
352
+ if (term.propertyValue === void 0) return true;
353
+ if (term.propertyValue !== positiveValue) return false;
354
+ }
355
+ }
356
+ if (term.type === "modifier") {
357
+ const positiveValue = positiveModifiers.get(term.attribute);
358
+ if (positiveValue !== void 0 && term.value !== void 0) {
359
+ if (term.value !== positiveValue) return false;
360
+ }
361
+ }
362
+ return true;
363
+ });
364
+ }
365
+ function deduplicateTerms(terms) {
366
+ const seen = /* @__PURE__ */ new Set();
367
+ const result = [];
368
+ for (const term of terms) {
369
+ const id = getConditionUniqueId(term);
370
+ if (!seen.has(id)) {
371
+ seen.add(id);
372
+ result.push(term);
373
+ }
374
+ }
375
+ return result;
376
+ }
377
+ /**
378
+ * Merge compatible range conditions
379
+ * e.g., @media(w >= 400px) & @media(w <= 800px) → @media(400px <= w <= 800px)
380
+ */
381
+ function mergeRanges(terms) {
382
+ const mediaByDim = /* @__PURE__ */ new Map();
383
+ const containerByDim = /* @__PURE__ */ new Map();
384
+ terms.forEach((term, index) => {
385
+ if (term.kind !== "state") return;
386
+ if (term.type === "media" && term.subtype === "dimension" && !term.negated) {
387
+ const key = term.dimension || "width";
388
+ if (!mediaByDim.has(key)) mediaByDim.set(key, {
389
+ conditions: [],
390
+ indices: []
391
+ });
392
+ const group = mediaByDim.get(key);
393
+ group.conditions.push(term);
394
+ group.indices.push(index);
395
+ }
396
+ if (term.type === "container" && term.subtype === "dimension" && !term.negated) {
397
+ const key = `${term.containerName || "_"}:${term.dimension || "width"}`;
398
+ if (!containerByDim.has(key)) containerByDim.set(key, {
399
+ conditions: [],
400
+ indices: []
401
+ });
402
+ const group = containerByDim.get(key);
403
+ group.conditions.push(term);
404
+ group.indices.push(index);
405
+ }
406
+ });
407
+ const indicesToRemove = /* @__PURE__ */ new Set();
408
+ const mergedTerms = [];
409
+ for (const [_dim, group] of mediaByDim) if (group.conditions.length > 1) {
410
+ const merged = mergeMediaRanges(group.conditions);
411
+ if (merged) {
412
+ group.indices.forEach((i) => indicesToRemove.add(i));
413
+ mergedTerms.push(merged);
414
+ }
415
+ }
416
+ for (const [, group] of containerByDim) if (group.conditions.length > 1) {
417
+ const merged = mergeContainerRanges(group.conditions);
418
+ if (merged) {
419
+ group.indices.forEach((i) => indicesToRemove.add(i));
420
+ mergedTerms.push(merged);
421
+ }
422
+ }
423
+ const result = [];
424
+ terms.forEach((term, index) => {
425
+ if (!indicesToRemove.has(index)) result.push(term);
426
+ });
427
+ result.push(...mergedTerms);
428
+ return result;
429
+ }
430
+ function mergeMediaRanges(conditions) {
431
+ if (conditions.length === 0) return null;
432
+ let lowerBound;
433
+ let upperBound;
434
+ for (const cond of conditions) {
435
+ if (cond.lowerBound) {
436
+ if (!lowerBound || (cond.lowerBound.valueNumeric ?? -Infinity) > (lowerBound.valueNumeric ?? -Infinity)) lowerBound = cond.lowerBound;
437
+ }
438
+ if (cond.upperBound) {
439
+ if (!upperBound || (cond.upperBound.valueNumeric ?? Infinity) < (upperBound.valueNumeric ?? Infinity)) upperBound = cond.upperBound;
440
+ }
441
+ }
442
+ const base = conditions[0];
443
+ const merged = {
444
+ kind: "state",
445
+ type: "media",
446
+ subtype: "dimension",
447
+ negated: false,
448
+ raw: buildMergedRaw(base.dimension || "width", lowerBound, upperBound),
449
+ uniqueId: "",
450
+ dimension: base.dimension,
451
+ lowerBound,
452
+ upperBound
453
+ };
454
+ const parts = [
455
+ "media",
456
+ "dim",
457
+ merged.dimension
458
+ ];
459
+ if (lowerBound) {
460
+ parts.push(lowerBound.inclusive ? ">=" : ">");
461
+ parts.push(lowerBound.value);
462
+ }
463
+ if (upperBound) {
464
+ parts.push(upperBound.inclusive ? "<=" : "<");
465
+ parts.push(upperBound.value);
466
+ }
467
+ merged.uniqueId = parts.join(":");
468
+ return merged;
469
+ }
470
+ function mergeContainerRanges(conditions) {
471
+ if (conditions.length === 0) return null;
472
+ let lowerBound;
473
+ let upperBound;
474
+ for (const cond of conditions) {
475
+ if (cond.lowerBound) {
476
+ if (!lowerBound || (cond.lowerBound.valueNumeric ?? -Infinity) > (lowerBound.valueNumeric ?? -Infinity)) lowerBound = cond.lowerBound;
477
+ }
478
+ if (cond.upperBound) {
479
+ if (!upperBound || (cond.upperBound.valueNumeric ?? Infinity) < (upperBound.valueNumeric ?? Infinity)) upperBound = cond.upperBound;
480
+ }
481
+ }
482
+ const base = conditions[0];
483
+ const merged = {
484
+ kind: "state",
485
+ type: "container",
486
+ subtype: "dimension",
487
+ negated: false,
488
+ raw: buildMergedRaw(base.dimension || "width", lowerBound, upperBound),
489
+ uniqueId: "",
490
+ containerName: base.containerName,
491
+ dimension: base.dimension,
492
+ lowerBound,
493
+ upperBound
494
+ };
495
+ const parts = [
496
+ "container",
497
+ "dim",
498
+ merged.containerName || "_",
499
+ merged.dimension
500
+ ];
501
+ if (lowerBound) {
502
+ parts.push(lowerBound.inclusive ? ">=" : ">");
503
+ parts.push(lowerBound.value);
504
+ }
505
+ if (upperBound) {
506
+ parts.push(upperBound.inclusive ? "<=" : "<");
507
+ parts.push(upperBound.value);
508
+ }
509
+ merged.uniqueId = parts.join(":");
510
+ return merged;
511
+ }
512
+ function buildMergedRaw(dimension, lowerBound, upperBound) {
513
+ if (lowerBound && upperBound) {
514
+ const lowerOp = lowerBound.inclusive ? "<=" : "<";
515
+ const upperOp = upperBound.inclusive ? "<=" : "<";
516
+ return `@media(${lowerBound.value} ${lowerOp} ${dimension} ${upperOp} ${upperBound.value})`;
517
+ } else if (upperBound) return `@media(${dimension} ${upperBound.inclusive ? "<=" : "<"} ${upperBound.value})`;
518
+ else if (lowerBound) return `@media(${dimension} ${lowerBound.inclusive ? ">=" : ">"} ${lowerBound.value})`;
519
+ return "@media()";
520
+ }
521
+ function sortTerms(terms) {
522
+ return [...terms].sort((a, b) => {
523
+ const idA = getConditionUniqueId(a);
524
+ const idB = getConditionUniqueId(b);
525
+ return idA.localeCompare(idB);
526
+ });
527
+ }
528
+ /**
529
+ * Apply absorption law for AND: A & (A | B) → A
530
+ */
531
+ function applyAbsorptionAnd(terms) {
532
+ const simpleIds = /* @__PURE__ */ new Set();
533
+ for (const term of terms) if (term.kind !== "compound") simpleIds.add(getConditionUniqueId(term));
534
+ return terms.filter((term) => {
535
+ if (term.kind === "compound" && term.operator === "OR") {
536
+ for (const child of term.children) if (simpleIds.has(getConditionUniqueId(child))) return false;
537
+ }
538
+ return true;
539
+ });
540
+ }
541
+ /**
542
+ * Apply absorption law for OR: A | (A & B) → A
543
+ */
544
+ function applyAbsorptionOr(terms) {
545
+ const simpleIds = /* @__PURE__ */ new Set();
546
+ for (const term of terms) if (term.kind !== "compound") simpleIds.add(getConditionUniqueId(term));
547
+ return terms.filter((term) => {
548
+ if (term.kind === "compound" && term.operator === "AND") {
549
+ for (const child of term.children) if (simpleIds.has(getConditionUniqueId(child))) return false;
550
+ }
551
+ return true;
552
+ });
553
+ }
554
+
555
+ //#endregion
556
+ export { simplifyCondition };
557
+ //# sourceMappingURL=simplify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"simplify.js","names":[],"sources":["../../src/pipeline/simplify.ts"],"sourcesContent":["/**\n * Condition Simplification Engine\n *\n * Simplifies condition trees by applying boolean algebra rules,\n * detecting contradictions, merging ranges, and deduplicating terms.\n *\n * This is critical for:\n * 1. Detecting invalid combinations (A & !A → FALSE)\n * 2. Reducing CSS output size\n * 3. Producing cleaner selectors\n */\n\nimport { Lru } from '../parser/lru';\n\nimport type {\n ConditionNode,\n ContainerCondition,\n MediaCondition,\n ModifierCondition,\n NumericBound} from './conditions';\nimport {\n falseCondition,\n getConditionUniqueId,\n trueCondition,\n} from './conditions';\n\n// ============================================================================\n// Caching\n// ============================================================================\n\nconst simplifyCache = new Lru<string, ConditionNode>(5000);\n\n// ============================================================================\n// Main Simplify Function\n// ============================================================================\n\n/**\n * Simplify a condition tree aggressively.\n *\n * This applies all possible simplification rules:\n * - Boolean algebra (identity, annihilator, idempotent, absorption)\n * - Contradiction detection (A & !A → FALSE)\n * - Tautology detection (A | !A → TRUE)\n * - Range intersection for numeric queries\n * - Attribute value conflict detection\n * - Deduplication and sorting\n */\nexport function simplifyCondition(node: ConditionNode): ConditionNode {\n // Check cache\n const key = getConditionUniqueId(node);\n const cached = simplifyCache.get(key);\n if (cached) {\n return cached;\n }\n\n const result = simplifyInner(node);\n\n // Cache result\n simplifyCache.set(key, result);\n\n return result;\n}\n\n/**\n * Clear the simplify cache (for testing)\n */\nexport function clearSimplifyCache(): void {\n simplifyCache.clear();\n}\n\n// ============================================================================\n// Inner Simplification\n// ============================================================================\n\nfunction simplifyInner(node: ConditionNode): ConditionNode {\n // Base cases\n if (node.kind === 'true' || node.kind === 'false') {\n return node;\n }\n\n // State conditions - return as-is (they're already leaf nodes)\n if (node.kind === 'state') {\n return node;\n }\n\n // Compound conditions - recursively simplify\n if (node.kind === 'compound') {\n // First, recursively simplify all children\n const simplifiedChildren = node.children.map((c) => simplifyInner(c));\n\n // Then apply compound-specific simplifications\n if (node.operator === 'AND') {\n return simplifyAnd(simplifiedChildren);\n } else {\n return simplifyOr(simplifiedChildren);\n }\n }\n\n return node;\n}\n\n// ============================================================================\n// AND Simplification\n// ============================================================================\n\nfunction simplifyAnd(children: ConditionNode[]): ConditionNode {\n let terms: ConditionNode[] = [];\n\n // Flatten nested ANDs and handle TRUE/FALSE\n for (const child of children) {\n if (child.kind === 'false') {\n // AND with FALSE → FALSE\n return falseCondition();\n }\n if (child.kind === 'true') {\n // AND with TRUE → skip (identity)\n continue;\n }\n if (child.kind === 'compound' && child.operator === 'AND') {\n // Flatten nested AND\n terms.push(...child.children);\n } else {\n terms.push(child);\n }\n }\n\n // Empty → TRUE\n if (terms.length === 0) {\n return trueCondition();\n }\n\n // Single term → return it\n if (terms.length === 1) {\n return terms[0];\n }\n\n // Check for contradictions\n if (hasContradiction(terms)) {\n return falseCondition();\n }\n\n // Check for range contradictions in media/container queries\n if (hasRangeContradiction(terms)) {\n return falseCondition();\n }\n\n // Check for attribute value conflicts\n if (hasAttributeConflict(terms)) {\n return falseCondition();\n }\n\n // Check for container style query conflicts\n if (hasContainerStyleConflict(terms)) {\n return falseCondition();\n }\n\n // Remove redundant negations implied by positive terms\n // e.g., style(--variant: danger) implies NOT style(--variant: success)\n // and style(--variant: danger) implies style(--variant) (existence)\n terms = removeImpliedNegations(terms);\n\n // Deduplicate (by uniqueId)\n terms = deduplicateTerms(terms);\n\n // Try to merge numeric ranges\n terms = mergeRanges(terms);\n\n // Sort for canonical form\n terms = sortTerms(terms);\n\n // Apply absorption: A & (A | B) → A\n terms = applyAbsorptionAnd(terms);\n\n if (terms.length === 0) {\n return trueCondition();\n }\n if (terms.length === 1) {\n return terms[0];\n }\n\n return {\n kind: 'compound',\n operator: 'AND',\n children: terms,\n };\n}\n\n// ============================================================================\n// OR Simplification\n// ============================================================================\n\nfunction simplifyOr(children: ConditionNode[]): ConditionNode {\n let terms: ConditionNode[] = [];\n\n // Flatten nested ORs and handle TRUE/FALSE\n for (const child of children) {\n if (child.kind === 'true') {\n // OR with TRUE → TRUE\n return trueCondition();\n }\n if (child.kind === 'false') {\n // OR with FALSE → skip (identity)\n continue;\n }\n if (child.kind === 'compound' && child.operator === 'OR') {\n // Flatten nested OR\n terms.push(...child.children);\n } else {\n terms.push(child);\n }\n }\n\n // Empty → FALSE\n if (terms.length === 0) {\n return falseCondition();\n }\n\n // Single term → return it\n if (terms.length === 1) {\n return terms[0];\n }\n\n // Check for tautologies (A | !A)\n if (hasTautology(terms)) {\n return trueCondition();\n }\n\n // Deduplicate\n terms = deduplicateTerms(terms);\n\n // Sort for canonical form\n terms = sortTerms(terms);\n\n // Apply absorption: A | (A & B) → A\n terms = applyAbsorptionOr(terms);\n\n if (terms.length === 0) {\n return falseCondition();\n }\n if (terms.length === 1) {\n return terms[0];\n }\n\n return {\n kind: 'compound',\n operator: 'OR',\n children: terms,\n };\n}\n\n// ============================================================================\n// Contradiction Detection\n// ============================================================================\n\n/**\n * Check if any term contradicts another (A & !A)\n */\nfunction hasContradiction(terms: ConditionNode[]): boolean {\n const uniqueIds = new Set<string>();\n\n for (const term of terms) {\n if (term.kind !== 'state') continue;\n\n const id = term.uniqueId;\n // Check if negation exists\n const negatedId = term.negated ? id.slice(1) : `!${id}`;\n\n if (uniqueIds.has(negatedId)) {\n return true;\n }\n uniqueIds.add(id);\n }\n\n return false;\n}\n\n/**\n * Check for tautologies (A | !A)\n */\nfunction hasTautology(terms: ConditionNode[]): boolean {\n const uniqueIds = new Set<string>();\n\n for (const term of terms) {\n if (term.kind !== 'state') continue;\n\n const id = term.uniqueId;\n const negatedId = term.negated ? id.slice(1) : `!${id}`;\n\n if (uniqueIds.has(negatedId)) {\n return true;\n }\n uniqueIds.add(id);\n }\n\n return false;\n}\n\n// ============================================================================\n// Range Contradiction Detection\n// ============================================================================\n\n/**\n * Effective bounds computed from conditions (including negated single-bound conditions)\n */\ninterface EffectiveBounds {\n lowerBound: number | null;\n lowerInclusive: boolean;\n upperBound: number | null;\n upperInclusive: boolean;\n}\n\n/**\n * Excluded range from a negated range condition\n */\ninterface ExcludedRange {\n lower: number;\n lowerInclusive: boolean;\n upper: number;\n upperInclusive: boolean;\n}\n\n/**\n * Check for range contradictions in media/container queries\n * e.g., @media(w < 400px) & @media(w > 800px) → FALSE\n *\n * Also handles negated conditions:\n * - Single-bound negations are inverted (not (w < 600px) → w >= 600px)\n * - Range negations create excluded ranges that are checked against positive bounds\n */\nfunction hasRangeContradiction(terms: ConditionNode[]): boolean {\n // Group by dimension, separating positive and negated conditions\n const mediaByDim = new Map<\n string,\n { positive: MediaCondition[]; negated: MediaCondition[] }\n >();\n const containerByDim = new Map<\n string,\n { positive: ContainerCondition[]; negated: ContainerCondition[] }\n >();\n\n for (const term of terms) {\n if (term.kind !== 'state') continue;\n\n if (term.type === 'media' && term.subtype === 'dimension') {\n const key = term.dimension || 'width';\n if (!mediaByDim.has(key)) {\n mediaByDim.set(key, { positive: [], negated: [] });\n }\n const group = mediaByDim.get(key)!;\n if (term.negated) {\n group.negated.push(term);\n } else {\n group.positive.push(term);\n }\n }\n\n if (term.type === 'container' && term.subtype === 'dimension') {\n const key = `${term.containerName || '_'}:${term.dimension || 'width'}`;\n if (!containerByDim.has(key)) {\n containerByDim.set(key, { positive: [], negated: [] });\n }\n const group = containerByDim.get(key)!;\n if (term.negated) {\n group.negated.push(term);\n } else {\n group.positive.push(term);\n }\n }\n }\n\n // Check each dimension group for impossible ranges\n for (const group of mediaByDim.values()) {\n if (rangesAreImpossibleWithNegations(group.positive, group.negated)) {\n return true;\n }\n }\n\n for (const group of containerByDim.values()) {\n if (rangesAreImpossibleWithNegations(group.positive, group.negated)) {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Check if conditions are impossible, including negated conditions.\n *\n * For negated single-bound conditions:\n * not (w < 600px) → w >= 600px (inverted to lower bound)\n * not (w >= 800px) → w < 800px (inverted to upper bound)\n *\n * For negated range conditions:\n * not (400px <= w < 800px) → excludes [400, 800)\n * If the effective bounds fall entirely within an excluded range, it's impossible.\n */\nfunction rangesAreImpossibleWithNegations(\n positive: (MediaCondition | ContainerCondition)[],\n negated: (MediaCondition | ContainerCondition)[],\n): boolean {\n // Start with bounds from positive conditions\n const bounds = computeEffectiveBounds(positive);\n\n // Apply inverted bounds from single-bound negated conditions\n // and collect excluded ranges from range negated conditions\n const excludedRanges: ExcludedRange[] = [];\n\n for (const cond of negated) {\n const hasLower = cond.lowerBound?.valueNumeric != null;\n const hasUpper = cond.upperBound?.valueNumeric != null;\n\n if (hasLower && hasUpper) {\n // Range negation: not (lower <= w < upper) excludes [lower, upper)\n excludedRanges.push({\n lower: cond.lowerBound!.valueNumeric!,\n lowerInclusive: cond.lowerBound!.inclusive,\n upper: cond.upperBound!.valueNumeric!,\n upperInclusive: cond.upperBound!.inclusive,\n });\n } else if (hasUpper) {\n // not (w < upper) → w >= upper (becomes lower bound)\n // not (w <= upper) → w > upper (becomes lower bound, exclusive)\n const value = cond.upperBound!.valueNumeric!;\n const inclusive = !cond.upperBound!.inclusive; // flip inclusivity\n\n if (bounds.lowerBound === null || value > bounds.lowerBound) {\n bounds.lowerBound = value;\n bounds.lowerInclusive = inclusive;\n } else if (value === bounds.lowerBound && !inclusive) {\n bounds.lowerInclusive = false;\n }\n } else if (hasLower) {\n // not (w >= lower) → w < lower (becomes upper bound)\n // not (w > lower) → w <= lower (becomes upper bound, inclusive)\n const value = cond.lowerBound!.valueNumeric!;\n const inclusive = !cond.lowerBound!.inclusive; // flip inclusivity\n\n if (bounds.upperBound === null || value < bounds.upperBound) {\n bounds.upperBound = value;\n bounds.upperInclusive = inclusive;\n } else if (value === bounds.upperBound && !inclusive) {\n bounds.upperInclusive = false;\n }\n }\n }\n\n // Check if effective bounds are impossible on their own\n if (bounds.lowerBound !== null && bounds.upperBound !== null) {\n if (bounds.lowerBound > bounds.upperBound) {\n return true;\n }\n if (\n bounds.lowerBound === bounds.upperBound &&\n (!bounds.lowerInclusive || !bounds.upperInclusive)\n ) {\n return true;\n }\n }\n\n // Check if effective bounds fall entirely within any excluded range\n if (\n bounds.lowerBound !== null &&\n bounds.upperBound !== null &&\n excludedRanges.length > 0\n ) {\n for (const excluded of excludedRanges) {\n if (boundsWithinExcludedRange(bounds, excluded)) {\n return true;\n }\n }\n }\n\n return false;\n}\n\n/**\n * Compute effective bounds from positive (non-negated) conditions\n */\nfunction computeEffectiveBounds(\n conditions: (MediaCondition | ContainerCondition)[],\n): EffectiveBounds {\n let lowerBound: number | null = null;\n let lowerInclusive = false;\n let upperBound: number | null = null;\n let upperInclusive = false;\n\n for (const cond of conditions) {\n if (cond.lowerBound?.valueNumeric != null) {\n const value = cond.lowerBound.valueNumeric;\n const inclusive = cond.lowerBound.inclusive;\n\n if (lowerBound === null || value > lowerBound) {\n lowerBound = value;\n lowerInclusive = inclusive;\n } else if (value === lowerBound && !inclusive) {\n lowerInclusive = false;\n }\n }\n\n if (cond.upperBound?.valueNumeric != null) {\n const value = cond.upperBound.valueNumeric;\n const inclusive = cond.upperBound.inclusive;\n\n if (upperBound === null || value < upperBound) {\n upperBound = value;\n upperInclusive = inclusive;\n } else if (value === upperBound && !inclusive) {\n upperInclusive = false;\n }\n }\n }\n\n return { lowerBound, lowerInclusive, upperBound, upperInclusive };\n}\n\n/**\n * Check if effective bounds fall entirely within an excluded range.\n *\n * For example:\n * Effective: [400, 800)\n * Excluded: [400, 800)\n * → bounds fall entirely within excluded range → impossible\n */\nfunction boundsWithinExcludedRange(\n bounds: EffectiveBounds,\n excluded: ExcludedRange,\n): boolean {\n if (bounds.lowerBound === null || bounds.upperBound === null) {\n return false;\n }\n\n // Check if bounds.lower >= excluded.lower\n let lowerOk = false;\n if (bounds.lowerBound > excluded.lower) {\n lowerOk = true;\n } else if (bounds.lowerBound === excluded.lower) {\n // If excluded includes lower, and bounds includes or excludes lower, it's within\n // If excluded excludes lower, bounds must also exclude it to be within\n lowerOk = excluded.lowerInclusive || !bounds.lowerInclusive;\n }\n\n // Check if bounds.upper <= excluded.upper\n let upperOk = false;\n if (bounds.upperBound < excluded.upper) {\n upperOk = true;\n } else if (bounds.upperBound === excluded.upper) {\n // If excluded includes upper, and bounds includes or excludes upper, it's within\n // If excluded excludes upper, bounds must also exclude it to be within\n upperOk = excluded.upperInclusive || !bounds.upperInclusive;\n }\n\n return lowerOk && upperOk;\n}\n\n// ============================================================================\n// Attribute Conflict Detection\n// ============================================================================\n\n/**\n * Check for attribute value conflicts\n * e.g., [data-theme=\"dark\"] & [data-theme=\"light\"] → FALSE\n * e.g., [data-theme=\"dark\"] & ![data-theme] → FALSE\n */\nfunction hasAttributeConflict(terms: ConditionNode[]): boolean {\n // Group modifiers by attribute\n const modifiersByAttr = new Map<\n string,\n { positive: ModifierCondition[]; negated: ModifierCondition[] }\n >();\n\n for (const term of terms) {\n if (term.kind !== 'state' || term.type !== 'modifier') continue;\n\n const attr = term.attribute;\n if (!modifiersByAttr.has(attr)) {\n modifiersByAttr.set(attr, { positive: [], negated: [] });\n }\n\n const group = modifiersByAttr.get(attr)!;\n if (term.negated) {\n group.negated.push(term);\n } else {\n group.positive.push(term);\n }\n }\n\n // Check each attribute for conflicts\n for (const [_attr, group] of modifiersByAttr) {\n // Multiple different values for same attribute in positive → conflict\n const positiveValues = group.positive\n .filter((m) => m.value !== undefined)\n .map((m) => m.value);\n const uniquePositiveValues = new Set(positiveValues);\n if (uniquePositiveValues.size > 1) {\n return true;\n }\n\n // Positive value + negated boolean for same attribute → conflict\n // e.g., [data-theme=\"dark\"] & ![data-theme]\n const hasPositiveValue = group.positive.some((m) => m.value !== undefined);\n const hasNegatedBoolean = group.negated.some((m) => m.value === undefined);\n if (hasPositiveValue && hasNegatedBoolean) {\n return true;\n }\n\n // Positive boolean + negated value (same value) → tautology not conflict\n // But positive value + negated same value → conflict\n for (const pos of group.positive) {\n if (pos.value !== undefined) {\n for (const neg of group.negated) {\n if (neg.value === pos.value) {\n return true; // [data-x=\"y\"] & ![data-x=\"y\"]\n }\n }\n }\n }\n }\n\n return false;\n}\n\n// ============================================================================\n// Container Style Query Conflict Detection\n// ============================================================================\n\n/**\n * Check for container style query conflicts\n * e.g., style(--variant: danger) & style(--variant: success) → FALSE\n * e.g., style(--variant: danger) & not style(--variant) → FALSE\n */\nfunction hasContainerStyleConflict(terms: ConditionNode[]): boolean {\n // Group container style queries by property (and container name)\n const styleByProp = new Map<\n string,\n { positive: ContainerCondition[]; negated: ContainerCondition[] }\n >();\n\n for (const term of terms) {\n if (\n term.kind !== 'state' ||\n term.type !== 'container' ||\n term.subtype !== 'style'\n )\n continue;\n\n const key = `${term.containerName || '_'}:${term.property}`;\n if (!styleByProp.has(key)) {\n styleByProp.set(key, { positive: [], negated: [] });\n }\n\n const group = styleByProp.get(key)!;\n if (term.negated) {\n group.negated.push(term);\n } else {\n group.positive.push(term);\n }\n }\n\n // Check each property for conflicts\n for (const [, group] of styleByProp) {\n // Multiple different values for same property in positive → conflict\n // e.g., style(--variant: danger) & style(--variant: success)\n const positiveValues = group.positive\n .filter((c) => c.propertyValue !== undefined)\n .map((c) => c.propertyValue);\n const uniquePositiveValues = new Set(positiveValues);\n if (uniquePositiveValues.size > 1) {\n return true;\n }\n\n // Positive value + negated existence → conflict\n // e.g., style(--variant: danger) & not style(--variant)\n const hasPositiveValue = group.positive.some(\n (c) => c.propertyValue !== undefined,\n );\n const hasNegatedExistence = group.negated.some(\n (c) => c.propertyValue === undefined,\n );\n if (hasPositiveValue && hasNegatedExistence) {\n return true;\n }\n\n // Positive value + negated same value → conflict\n // e.g., style(--variant: danger) & not style(--variant: danger)\n for (const pos of group.positive) {\n if (pos.propertyValue !== undefined) {\n for (const neg of group.negated) {\n if (neg.propertyValue === pos.propertyValue) {\n return true;\n }\n }\n }\n }\n }\n\n return false;\n}\n\n// ============================================================================\n// Implied Negation Removal\n// ============================================================================\n\n/**\n * Remove negations that are implied by positive terms.\n *\n * Key optimizations:\n * 1. style(--variant: danger) implies NOT style(--variant: success)\n * → If we have style(--variant: danger) & not style(--variant: success),\n * the negation is redundant and can be removed.\n *\n * 2. [data-theme=\"dark\"] implies NOT [data-theme=\"light\"]\n * → Same logic for attribute selectors.\n *\n * This produces cleaner CSS:\n * Before: @container style(--variant: danger) and (not style(--variant: success))\n * After: @container style(--variant: danger)\n */\nfunction removeImpliedNegations(terms: ConditionNode[]): ConditionNode[] {\n // Build sets of positive container style properties with specific values\n const positiveContainerStyles = new Map<string, string | undefined>();\n // key: \"containerName:property\", value: propertyValue (or undefined for existence)\n\n // Build sets of positive modifier attributes with specific values\n const positiveModifiers = new Map<string, string | undefined>();\n // key: \"attribute\", value: value (or undefined for boolean)\n\n for (const term of terms) {\n if (term.kind !== 'state' || term.negated) continue;\n\n if (term.type === 'container' && term.subtype === 'style') {\n const key = `${term.containerName || '_'}:${term.property}`;\n // Only track if we have a specific value (not just existence check)\n if (term.propertyValue !== undefined) {\n positiveContainerStyles.set(key, term.propertyValue);\n }\n }\n\n if (term.type === 'modifier' && term.value !== undefined) {\n positiveModifiers.set(term.attribute, term.value);\n }\n }\n\n // Filter out redundant negations\n return terms.filter((term) => {\n if (term.kind !== 'state' || !term.negated) return true;\n\n // Check container style negations\n if (term.type === 'container' && term.subtype === 'style') {\n const key = `${term.containerName || '_'}:${term.property}`;\n const positiveValue = positiveContainerStyles.get(key);\n\n if (positiveValue !== undefined) {\n // We have a positive style(--prop: X) for this property\n\n if (term.propertyValue === undefined) {\n // Negating existence: not style(--prop)\n // But we have style(--prop: X), which implies existence → contradiction\n // This should have been caught by hasContainerStyleConflict\n return true;\n }\n\n if (term.propertyValue !== positiveValue) {\n // Negating a different value: not style(--prop: Y)\n // We have style(--prop: X), which implies not style(--prop: Y)\n // → This negation is redundant!\n return false;\n }\n }\n }\n\n // Check modifier negations\n if (term.type === 'modifier') {\n const positiveValue = positiveModifiers.get(term.attribute);\n\n if (positiveValue !== undefined && term.value !== undefined) {\n // We have [attr=\"X\"] and this is not [attr=\"Y\"]\n if (term.value !== positiveValue) {\n // [attr=\"X\"] implies not [attr=\"Y\"] → redundant\n return false;\n }\n }\n }\n\n return true;\n });\n}\n\n// ============================================================================\n// Deduplication\n// ============================================================================\n\nfunction deduplicateTerms(terms: ConditionNode[]): ConditionNode[] {\n const seen = new Set<string>();\n const result: ConditionNode[] = [];\n\n for (const term of terms) {\n const id = getConditionUniqueId(term);\n if (!seen.has(id)) {\n seen.add(id);\n result.push(term);\n }\n }\n\n return result;\n}\n\n// ============================================================================\n// Range Merging\n// ============================================================================\n\n/**\n * Merge compatible range conditions\n * e.g., @media(w >= 400px) & @media(w <= 800px) → @media(400px <= w <= 800px)\n */\nfunction mergeRanges(terms: ConditionNode[]): ConditionNode[] {\n // Group media conditions by dimension\n const mediaByDim = new Map<\n string,\n { conditions: MediaCondition[]; indices: number[] }\n >();\n const containerByDim = new Map<\n string,\n { conditions: ContainerCondition[]; indices: number[] }\n >();\n\n terms.forEach((term, index) => {\n if (term.kind !== 'state') return;\n\n if (\n term.type === 'media' &&\n term.subtype === 'dimension' &&\n !term.negated\n ) {\n const key = term.dimension || 'width';\n if (!mediaByDim.has(key)) {\n mediaByDim.set(key, { conditions: [], indices: [] });\n }\n const group = mediaByDim.get(key)!;\n group.conditions.push(term);\n group.indices.push(index);\n }\n\n if (\n term.type === 'container' &&\n term.subtype === 'dimension' &&\n !term.negated\n ) {\n const key = `${term.containerName || '_'}:${term.dimension || 'width'}`;\n if (!containerByDim.has(key)) {\n containerByDim.set(key, { conditions: [], indices: [] });\n }\n const group = containerByDim.get(key)!;\n group.conditions.push(term);\n group.indices.push(index);\n }\n });\n\n // Track indices to remove\n const indicesToRemove = new Set<number>();\n const mergedTerms: ConditionNode[] = [];\n\n // Merge media conditions\n for (const [_dim, group] of mediaByDim) {\n if (group.conditions.length > 1) {\n const merged = mergeMediaRanges(group.conditions);\n if (merged) {\n group.indices.forEach((i) => indicesToRemove.add(i));\n mergedTerms.push(merged);\n }\n }\n }\n\n // Merge container conditions\n for (const [, group] of containerByDim) {\n if (group.conditions.length > 1) {\n const merged = mergeContainerRanges(group.conditions);\n if (merged) {\n group.indices.forEach((i) => indicesToRemove.add(i));\n mergedTerms.push(merged);\n }\n }\n }\n\n // Build result\n const result: ConditionNode[] = [];\n terms.forEach((term, index) => {\n if (!indicesToRemove.has(index)) {\n result.push(term);\n }\n });\n result.push(...mergedTerms);\n\n return result;\n}\n\nfunction mergeMediaRanges(conditions: MediaCondition[]): MediaCondition | null {\n if (conditions.length === 0) return null;\n\n let lowerBound: NumericBound | undefined;\n let upperBound: NumericBound | undefined;\n\n for (const cond of conditions) {\n if (cond.lowerBound) {\n if (\n !lowerBound ||\n (cond.lowerBound.valueNumeric ?? -Infinity) >\n (lowerBound.valueNumeric ?? -Infinity)\n ) {\n lowerBound = cond.lowerBound;\n }\n }\n if (cond.upperBound) {\n if (\n !upperBound ||\n (cond.upperBound.valueNumeric ?? Infinity) <\n (upperBound.valueNumeric ?? Infinity)\n ) {\n upperBound = cond.upperBound;\n }\n }\n }\n\n const base = conditions[0];\n\n // Build a merged condition\n const merged: MediaCondition = {\n kind: 'state',\n type: 'media',\n subtype: 'dimension',\n negated: false,\n raw: buildMergedRaw(base.dimension || 'width', lowerBound, upperBound),\n uniqueId: '', // Will be recalculated\n dimension: base.dimension,\n lowerBound,\n upperBound,\n };\n\n // Recalculate uniqueId\n const parts = ['media', 'dim', merged.dimension];\n if (lowerBound) {\n parts.push(lowerBound.inclusive ? '>=' : '>');\n parts.push(lowerBound.value);\n }\n if (upperBound) {\n parts.push(upperBound.inclusive ? '<=' : '<');\n parts.push(upperBound.value);\n }\n merged.uniqueId = parts.join(':');\n\n return merged;\n}\n\nfunction mergeContainerRanges(\n conditions: ContainerCondition[],\n): ContainerCondition | null {\n if (conditions.length === 0) return null;\n\n let lowerBound: NumericBound | undefined;\n let upperBound: NumericBound | undefined;\n\n for (const cond of conditions) {\n if (cond.lowerBound) {\n if (\n !lowerBound ||\n (cond.lowerBound.valueNumeric ?? -Infinity) >\n (lowerBound.valueNumeric ?? -Infinity)\n ) {\n lowerBound = cond.lowerBound;\n }\n }\n if (cond.upperBound) {\n if (\n !upperBound ||\n (cond.upperBound.valueNumeric ?? Infinity) <\n (upperBound.valueNumeric ?? Infinity)\n ) {\n upperBound = cond.upperBound;\n }\n }\n }\n\n const base = conditions[0];\n\n const merged: ContainerCondition = {\n kind: 'state',\n type: 'container',\n subtype: 'dimension',\n negated: false,\n raw: buildMergedRaw(base.dimension || 'width', lowerBound, upperBound),\n uniqueId: '', // Will be recalculated\n containerName: base.containerName,\n dimension: base.dimension,\n lowerBound,\n upperBound,\n };\n\n // Recalculate uniqueId\n const name = merged.containerName || '_';\n const parts = ['container', 'dim', name, merged.dimension];\n if (lowerBound) {\n parts.push(lowerBound.inclusive ? '>=' : '>');\n parts.push(lowerBound.value);\n }\n if (upperBound) {\n parts.push(upperBound.inclusive ? '<=' : '<');\n parts.push(upperBound.value);\n }\n merged.uniqueId = parts.join(':');\n\n return merged;\n}\n\nfunction buildMergedRaw(\n dimension: string,\n lowerBound?: NumericBound,\n upperBound?: NumericBound,\n): string {\n if (lowerBound && upperBound) {\n const lowerOp = lowerBound.inclusive ? '<=' : '<';\n const upperOp = upperBound.inclusive ? '<=' : '<';\n return `@media(${lowerBound.value} ${lowerOp} ${dimension} ${upperOp} ${upperBound.value})`;\n } else if (upperBound) {\n const op = upperBound.inclusive ? '<=' : '<';\n return `@media(${dimension} ${op} ${upperBound.value})`;\n } else if (lowerBound) {\n const op = lowerBound.inclusive ? '>=' : '>';\n return `@media(${dimension} ${op} ${lowerBound.value})`;\n }\n return '@media()';\n}\n\n// ============================================================================\n// Sorting\n// ============================================================================\n\nfunction sortTerms(terms: ConditionNode[]): ConditionNode[] {\n return [...terms].sort((a, b) => {\n const idA = getConditionUniqueId(a);\n const idB = getConditionUniqueId(b);\n return idA.localeCompare(idB);\n });\n}\n\n// ============================================================================\n// Absorption\n// ============================================================================\n\n/**\n * Apply absorption law for AND: A & (A | B) → A\n */\nfunction applyAbsorptionAnd(terms: ConditionNode[]): ConditionNode[] {\n // Collect all unique IDs of simple terms\n const simpleIds = new Set<string>();\n for (const term of terms) {\n if (term.kind !== 'compound') {\n simpleIds.add(getConditionUniqueId(term));\n }\n }\n\n // Filter out OR terms that are absorbed\n return terms.filter((term) => {\n if (term.kind === 'compound' && term.operator === 'OR') {\n // If any child of this OR is in simpleIds, absorb the whole OR\n for (const child of term.children) {\n if (simpleIds.has(getConditionUniqueId(child))) {\n return false; // Absorb\n }\n }\n }\n return true;\n });\n}\n\n/**\n * Apply absorption law for OR: A | (A & B) → A\n */\nfunction applyAbsorptionOr(terms: ConditionNode[]): ConditionNode[] {\n // Collect all unique IDs of simple terms\n const simpleIds = new Set<string>();\n for (const term of terms) {\n if (term.kind !== 'compound') {\n simpleIds.add(getConditionUniqueId(term));\n }\n }\n\n // Filter out AND terms that are absorbed\n return terms.filter((term) => {\n if (term.kind === 'compound' && term.operator === 'AND') {\n // If any child of this AND is in simpleIds, absorb the whole AND\n for (const child of term.children) {\n if (simpleIds.has(getConditionUniqueId(child))) {\n return false; // Absorb\n }\n }\n }\n return true;\n });\n}\n"],"mappings":"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"}