home
readme
diff
tree
note
docs
0commit 9f7ae2da7f08cbd42be7564b57bf21a0a8d17760
1Author: Mason Wright <mason@lakefox.net>
2Date: Sat Nov 22 15:05:40 2025 -0700
3
4 CSS selectors pass all tests
5
6diff --git a/Makefile b/Makefile
7index 76a1577..474cc43 100755
8--- a/Makefile
9+++ b/Makefile
10@@ -1,8 +1,8 @@
11 # --- Variables ---
12-CCFLAGS = -Wall -Wextra -std=c++2b -g
13+CCFLAGS = -Wall -Wextra -std=c++2b -g -O0 -fsanitize=address,undefined -fno-omit-frame-pointer
14 CC = clang++
15
16-.PHONY: all clean docs serve all_tests
17+.PHONY: all clean all_tests
18
19 all: main
20
21@@ -18,8 +18,6 @@ build/grim.o: src/grim.cc include/grim.h | build
22 build/parser.o: src/parser.cc include/parser.h | build
23 ${CC} ${CCFLAGS} -Iinclude/ -c src/parser.cc -o build/parser.o
24
25-
26-
27 # --- Tests ---
28
29 all_tests: build/html_node_test build/css_selector_test build/html_parser_test build/query_select_test
30@@ -50,6 +48,14 @@ build/query_select_test: tests/query_select.cc build/grim.o build/parser.o build
31 build/catch.o: ./include/catch_amalgamated.cpp ./include/catch_amalgamated.hpp | build
32 ${CC} ${CCFLAGS} -Iinclude/ -c include/catch_amalgamated.cpp -o build/catch.o
33
34+# --- Playground ---
35+build/parseselectorparts_playground: playground/parseselectorparts.cc build/grim.o build/parser.o | build
36+ ${CC} ${CCFLAGS} -Iinclude/ playground/parseselectorparts.cc build/grim.o build/parser.o -o build/parseselectorparts_playground
37+
38+build/testselector_playground: playground/testselector.cc build/grim.o build/parser.o | build
39+ ${CC} ${CCFLAGS} -Iinclude/ playground/testselector.cc build/grim.o build/parser.o -o build/testselector_playground
40+
41+
42 # --- Prebuild ---
43
44 # use to prebuild the master.css
45@@ -59,36 +65,3 @@ build/catch.o: ./include/catch_amalgamated.cpp ./include/catch_amalgamated.hpp |
46
47 clean:
48 rm -f main build/*.o
49-
50-MD_FILES := $(shell find docs/content -name "*.md")
51-HTML_FILES := $(MD_FILES:docs/content/%.md=docs/dist/%.html)
52-
53-docs: $(HTML_FILES)
54- @printf "\
55-<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
56-<rss version=\"2.0\">\n\
57- <channel>\n\
58- <title>Grim Git Feed</title>\n\
59- <link>https://grimui.com</link>\n\
60- <description>A feed of recent commits.</description>\n\
61- <language>en-us</language>\n\
62- <pubDate>" > docs/dist/rss.xml
63- date -R >> docs/dist/rss.xml
64- @printf "</pubDate>\n" >> docs/dist/rss.xml
65- git log --pretty=format:'<item><title>%s</title><guid isPermaLink="false">%H</guid><author>%ae (%an)</author><pubDate>%aI</pubDate><description><![CDATA[<p><strong>Author:</strong> %an</p><p><strong>Commit:</strong> %H</p><p>%b</p><p style="white-space: pre;">%N</p>]]></description></item>' --date=iso >> docs/dist/rss.xml
66- @printf "\
67- </channel>\n\
68-</rss>" >> docs/dist/rss.xml
69-
70-# See 080f729 note for the template command
71-docs/dist/%.html: docs/content/%.md docs/components/navbar.html
72- pandoc $< | template docs/components/navbar.html --stdin docs/template.html > $@
73-
74-# Will want to move to groff for docs
75-# groff -Thtml -man
76-
77-serve:
78- cd docs/dist && python3 -m http.server 8000
79-
80-man:
81- @man -l docs/manpage/grim.3
82diff --git a/docs/components/navbar.html b/docs/components/navbar.html
83deleted file mode 100755
84index daf8399..0000000
85--- a/docs/components/navbar.html
86+++ /dev/null
87@@ -1,32 +0,0 @@
88-<aside style="min-width: 200px">
89- <img src="/logo.webp"/ width="150px">
90- <ul>
91- <li>
92- <strong><a href="/">Home</a></strong>
93- </li>
94- </ul>
95- <details open>
96- <summary>Links</summary>
97- <ul>
98- <li><a href="sftp://share@grimui.com">Source</a></li>
99- <li><a href="https://web.libera.chat/gamja/?autojoin=#grim">IRC</a>
100- <li><a href="/rss.xml">RSS</a>
101- </ul>
102- </details>
103- <details open>
104- <summary>Feature Support</summary>
105- <ul>
106- <li><a href="/features/supported-css-selectors.html">CSS Selectors</a></li>
107- <li><a href="/features/supported-html-tags.html">HTML Tags</a></li>
108- <li><a href="/features/supported-dom-apis.html">DOM APIs</a></li>
109- </ul>
110- </details>
111- <details open>
112- <summary>About</summary>
113- <ul>
114- <li><a href="/about/general.html">General</a></li>
115- <li><a href="/about/parsing.html">Parsing</a></li>
116- <li><a href="/about/events.html">Events</a></li>
117- </ul>
118- </details>
119-</aside>
120diff --git a/docs/content/features/supported-css-selectors.md b/docs/content/features/supported-css-selectors.md
121deleted file mode 100755
122index 00ceea9..0000000
123--- a/docs/content/features/supported-css-selectors.md
124+++ /dev/null
125@@ -1,239 +0,0 @@
126-# Supported Selectors
127-
128-## Support
129-* (\*) parsing supported, not implemented
130-* \(X\) fully supported, implemented
131-* (/) No support planned
132-
133-## Selectors
134-| Name | Support | Test Case | Section | Test File |
135-|-|-|-|-| - |
136-| Type | X | testSelector | testSelector can match a element given it's tagName | tests/css_selector.cc |
137-| Attribute | X | testSelector | testSelector can match a element by it's attributes only | tests/css_selector.cc |
138-| ID | X | testSelector | testSelector can match a element by it's id only | tests/css_selector.cc |
139-| Class | X | testSelector | testSelector can match a element by it's class and not match on a non class | tests/css_selector.cc |
140-| Universal | X | testSelector | testSelector can match a universal selector | tests/css_selector.cc |
141-| Nesting | X | parseCSS can parse a CSS sheet, parseCSS can parse multiple selectors nested | parseCSS can parse a nested CSS rule without a &, parseCSS can parse a the parent of a nested CSS rule, parseCSS can parse a nested CSS rule with a pseudo element, parseCSS can parse a parent CSS rule with a property in between sub-classes, multi selector test | tests/css_parser.cc |
142-| & Nesting | X | parseCSS can parse a CSS sheet, parseCSS can parse multiple selectors nested | parseCSS can parse a nested CSS rule without a &, parseCSS can parse a the parent of a nested CSS rule, parseCSS can parse a nested CSS rule with a pseudo element, parseCSS can parse a double nested CSS rule with a pseudo element and &, parseCSS can parse a nested CSS rule with a &, parseCSS can parse a parent CSS rule with a property in between sub-classes, multi selector test | tests/css_parser.cc |
143-
144-## Combinator
145-| Name | Support | Test Case | Section | Test File |
146-|-|-|-|-| - |
147-| Child Combinator | X | testSelector | testSelector can match a child combinator | tests/css_selector.cc |
148-| Next-Sibling Combinator | X | testSelector | testSelector can match a next sibling combinator | tests/css_selector.cc |
149-| Descendant Combinator | X | testSelector | testSelector can match a descendant combinator | tests/css_selector.cc |
150-| Subsequent-Sibling Combinator | X | testSelector | testSelector can match a subsequent-sibling combinator | tests/css_selector.cc |
151-
152-## Pseudo Classes
153-| Name | Support | Test Case | Section | Test File | Note |
154-|-|-|-|-| - | - |
155-| :active | | | | | Will be added when links are|
156-| :any-link | | | | | Will be added when links are|
157-| :autofill | | | | | Will be added when inputs are added |
158-| :buffering | | | | | Videos are not currently supported |
159-| :checked | X | testSelector | testSelector can match a element with a pseudo class | tests/css_selector.cc | |
160-| :default | | | | | Will be added when inputs are added |
161-| :defined | | | | | |
162-| :dir() | | | | | |
163-| :disabled | X | testSelector | testSelector can match a element with a pseudo class | tests/css_selector.cc | |
164-| :empty | | | | | Will be added when inputs are added |
165-| :enabled | X | testSelector | testSelector can match a element with a pseudo class | tests/css_selector.cc | |
166-| :first | / | | | | Will not be supported, currently there are no plans to support printing |
167-| :first-child | X | testSelector | testSelector can match a element with first-child | tests/css_selector.cc | |
168-| :first-of-type | X | testSelector | testSelector can match a element with first-of-type | tests/css_selector.cc | |
169-| :focus | | | | | |
170-| :focus-visible | | | | | |
171-| :focus-within | | | | | |
172-| :fullscreen | | | | | Videos are not currently supported |
173-| :future | | | | | |
174-| :has-slotted | | | | | |
175-| :has() | X | testSelector | testSelector can match a :has() selector with a child combinator, testSelector can match a :has() selector with a next-sibling combinator, testSelector can match a :has() selector with a subsequent-sibling combinator, testSelector can match a :has() selector with a decendent combinator | tests/css_selector.cc | |
176-| :host | | | | | |
177-| :host-context() | | | | | |
178-| :host() | | | | | |
179-| :hover | | | | | |
180-| :in-range | | | | | Will be added when inputs are added |
181-| :indeterminate | | | | | Will be added when inputs are added |
182-| :invalid | | | | | Will be added when inputs are added |
183-| :is() | X | testSelector | testSelector can match :is() selectors | tests/css_selector.cc | |
184-| :lang() | | | | | |
185-| :last-child | X | testSelector | testSelector can match a element with last-child | tests/css_selector.cc | |
186-| :last-of-type | X | testSelector | testSelector can match a element with last-of-type | tests/css_selector.cc | |
187-| :left | / | | | | Will not be supported, currently there are no plans to support printing |
188-| :local-link | / | | | | Doesn't make sense to add because all links will be local |
189-| :modal | | | | | |
190-| :muted | | | | | Videos are not currently supported |
191-| :not() | X | testSelector | testSelector can match :not() selectors | tests/css_selector.cc | |
192-| :nth-child() | X | testSelector | testSelector can match a :nth-child(even\|odd), testSelector can match a :nth-child(A), testSelector can match a :nth-child(An), testSelector can match a :nth-child(An+B), testSelector can match a :nth-child(An+B of type), testSelector can match a :nth-child(n+B), testSelector can match a :nth-child(A of type), testSelector can match a :nth-child(An of type), testSelector can match a :nth-child(n+B of type) | tests/css_selector.cc | when A is 0 it is changed to a 1, the only case this will cause breaking behavior is if you are trying :nth-child(0n+B) which is the same as calling :nth-child(B). This behavior applies to all nth-*|
193-| :nth-last-child() | X | testSelector | testSelector can match a :nth-last-child(even\|odd), testSelector can match a :nth-last-child(A), testSelector can match a :nth-last-child(An), testSelector can match a :nth-last-child(An+B), testSelector can match a :nth-last-child(n+B), testSelector can match a :nth-last-child(An+B of type), testSelector can match a :nth-last-child(A of type), testSelector can match a :nth-last-child(An of type), testSelector can match a :nth-last-child(n+B of type) | tests/css_selector.cc | |
194-| :nth-last-of-type() | X | testSelector | testSelector can match a :nth-last-of-type(even\|odd), testSelector can match a :nth-last-of-type(A), testSelector can match a :nth-last-of-type(An), testSelector can match a :nth-last-of-type(An+B), testSelector can match a :nth-last-of-type(n+B), | tests/css_selector.cc | |
195-| :nth-of-type() | X | testSelector | testSelector can match a :nth-of-type(even\|odd), testSelector can match a :nth-of-type(A), testSelector can match a :nth-of-type(An), testSelector can match a :nth-of-type(An+B), testSelector can match a :nth-of-type(n+B), | tests/css_selector.cc | |
196-| :only-child | X | testSelector | testSelector can match :only-child | tests/css_selector.cc | |
197-| :only-of-type | X | testSelector | testSelector can match :only-of-type | tests/css_selector.cc | |
198-| :open | | | | | |
199-| :optional | | | | | |
200-| :out-of-range | | | | | Will be added when inputs are added |
201-| :past | | | | | |
202-| :paused | | | | | Videos are not currently supported |
203-| :picture-in-picture | | | | | Videos are not currently supported |
204-| :placeholder-shown | | | | | Will be added when inputs are added |
205-| :playing | | | | | Videos are not currently supported |
206-| :popover-open | | | | | |
207-| :read-only | X | testSelector | testSelector can match :read-only normal element, testSelector can match :read-only on a radio input, testSelector can match :read-only on a readonly text input, testSelector can match :read-only on a disabled text input, testSelector can match :read-only on a readonly textarea, testSelector can match :read-only on a disabled textarea | tests/css_selector.cc | |
208-| :read-write | X | testSelector | testSelector can match :read-write on a text input, testSelector can match :read-write on a textarea, testSelector can match :read-write on a contenteditable div | tests/css_selector.cc | |
209-| :required | X | testSelector | testSelector can match a element with a pseudo class | tests/css_selector.cc | |
210-| :right | / | | | | Will not be supported, currently there are no plans to support printing |
211-| :root | X | testSelector | testSelector can match :root | tests/css_selector.cc | |
212-| :scope | | | | | |
213-| :seeking | | | | | Videos are not currently supported |
214-| :stalled | | | | | Video and Audio are not currently supported |
215-| :state() | | | | | Shadow DOM |
216-| :target | | | | | |
217-| :target-current | | | | | |
218-| :target-within | | | | | |
219-| :user-invalid | | | | | |
220-| :user-valid | | | | | |
221-| :valid | | | | | |
222-| :visited | | | | | |
223-| :volume-locked | | | | | Video and Audio are not currently supported |
224-| :where() | X | testSelector |testSelector can match :where() selectors | tests/css_selector.cc | |
225-## Pseudo Elements
226-
227-## At-rules
228-| Name | Support | Test Case | Section | Test File | Note |
229-|-|-|-|-|-|-|
230-| @charset | / |||| UTF-8/ASCII are the only encodings supported |
231-| @color-profile | / |||| Too new to support |
232-| @container ||||||
233-| @counter-style ||||||
234-| @font-face ||||||
235-| @font-feature-values ||||||
236-| @swash | / |||| Subset of @font-feature-values |
237-| @annotation | / |||| Subset of @font-feature-values |
238-| @ornaments | / |||| Subset of @font-feature-values |
239-| @stylistic | / |||| Subset of @font-feature-values |
240-| @styleset | / |||| Subset of @font-feature-values |
241-| @character-varient | / |||| Subset of @font-feature-values |
242-| @font-palette-values ||||||
243-| @import ||||| Parsed where the first argument after @import is the url and the last non parenthesized value if present is the layer name. Inbetween the url and the layer is the media queries. |
244-| @keyframes ||||||
245-| @layer ||||| Currently setting the layer order via @layer l1, l2; is not supported |
246-| @media ||||||
247-| @namespace ||||||
248-| @page | / |||| Will not be supported, currently there are no plans to support printing |
249-| @position-try ||||| Use this document to check support of features |
250-| @property ||||||
251-| @scope ||||| Implementing this would cause some overhead |
252-| @starting-style ||||||
253-| @supports | / |||| Use this document to check support of features |
254-| @view-transition ||||| This is useful but will not be implemented until later |
255-## Functions
256-## Types
257-| Name | Support | Values | Note |
258-|-|-|-|-|
259-| AnyHover | X | None, Hover | |
260-| AnyPointer | X | None, Fine, Coarse | |
261-| Orientation | X | Landscape, Portrait | |
262-| ColorScheme | X | Light, Dark | |
263-| Contrast | X | NoPreference, More, Less | |
264-| ReducedMotion | X | NoPreference, Reduce | |
265-| ReducedTranparency | X | NoPreference, Reduce | |
266-| Update | X | Fast, Slow | |
267-
268-## Descriptors
269-| Name | Support | Used by | Note |
270-|-|-|-|-|
271-| style | | @container | |
272-| scroll-state | @container | | |
273-| container | | @container | | Computed using the overall container via window properties (orientation: landscape) and the content-box (min-width: 300px). Supports aspect-ratio, height, orientation, width |
274-
275-## Media Queries
276-| Name | Support | Usage | Note |
277-|-|-|-|-|
278-| any-hover | X | window.setMouse(AnyPointer::Fine) | Will be set to AnyHover::Hover if AnyPointer is not AnyPointer::None, default AnyHover::Hover |
279-| any-pointer | X | window.setMouse(AnyPointer::Coarse) | Default AnyPointer::Fine |
280-| aspect-ratio | X | window.getAspectRatio() | Derived from width and height, returned as a double |
281-| color | * | | All colors are stored as RGBA values |
282-| color-gamut | * | | Only matches on "srgb" |
283-| color-index | * | | Only matches on 0 |
284-| device-posture | * | | Only matches on "continuous" |
285-| display-mode | * | | All applications will be "standalone" |
286-| dynamic-range | * | | Only matches on "standard" |
287-| forced-colors | * | | Only matches on "none" |
288-| grid | * | | Only matches on 0 |
289-| height | X | window.setHeight(int) | Supports height, min-height, max-height |
290-| hover | X | window.setMouse(AnyPointer::Fine) | Will match any-hover |
291-| inverted-colors | * | | Only matches on "none" |
292-| monochrome | * | | Only matches on 0 |
293-| orientation | X | window.setOrientation(Orientation::Portrait) | Defaults to Orientation::Landscape |
294-| overflow-block | * | | Only matches on "scroll" |
295-| overflow-inline | * | | Only matches on "scroll" |
296-| pointer | X | window.setMouse(AnyPointer) | Will match any-pointer |
297-| prefers-color-scheme | X | window.setColorScheme(ColorScheme::Dark) | Defaults to ColorScheme::Light |
298-| prefers-contrast | X | window.setContrast(Contrast::Less) | Defaults to ColorScheme::NoPreference |
299-| prefers-reduced-motion | X | window.setReducedMotion(ReducedMotion::Reduce) | Defaults to ReducedMotion::NoPreference |
300-| prefers-reduced-transparency | X | window.setReducedTransparency(ReducedTransparency::Reduce) | Defaults to ReducedTransparency::NoPreference |
301-| resolution | X | window.setResolution(int) | Defaults to 72dpi, accepts a int in dpi |
302-| scripting | / | | Not needed |
303-| update | X | window.setUpdate(Update::Slow) | Defaults to Update::Fast |
304-| video-dynamic-range | * | | Only matches on "standard" |
305-| width | X | window.setWidth(int) | Supports width, min-width, max-width |
306-
307-## Colors
308-| Name | Support | Usage | Note |
309-|-|-|-|-|
310-| rgb | X | rgb(0-255, 0-255, 0-255) | You may use spaces instead of commas |
311-| rgba | X | rgba(0-255, 0-255, 0-255 / 0-100%) | The alpha value MUST be a perent ranging from 0-100. You may also use spaces instead of commas |
312-| hsl | X | hsl(0-360deg, 0-100%, 0-100%) | You may use spaces instead of commas |
313-| hsla | X | hsla(0-360deg, 0-100%, 0-100% / 0-100%) | The alpha value MUST be a perent ranging from 0-100. You may also use spaces instead of commas |
314-| hwb | / | | Use alternative color definition |
315-| lab | / | | Use alternative color definition |
316-| lch | / | | Use alternative color definition |
317-| oklab | / | | Use alternative color definition |
318-| oklch | / | | Use alternative color definition |
319-| color-mix | / | | Use alternative color definition |
320-
321-## Types
322-| Name | Support | Usage | Note |
323-|-|-|-|-|
324-| <absolute-size> | X | xx-small, x-small, small, medium, large, x-large, xx-large, xxx-large | Based off of relative EM value |
325-| <alpha-value> | | | |
326-| <angle-percentage> | | | |
327-| <angle> | | | |
328-| <baseline-position> | X | baseline, first baseline, last baseline | Singular baseline computes to first baseline |
329-| <basic-shape> | / | | Will be impleamented in the future |
330-| <blend-mode> | / | | Will be impleamented in the future |
331-| <box-edge> | X | content-box, padding-box, border-box, margin-box, fill-box, stroke-box, view-box | |
332-| <calc-keyword> | X | calc(<number>, <dimention>, <percentage>, <function>) | |
333-| <color> | X | | See Colors |
334-| <content-distribution> | X | space-between, space-around, space-evenly, stretch | |
335-| <centent-position> | X | center, start, end, flex-start, flex-end | |
336-| <dimension> | X | px, rem, pt, ms, s, hz | |
337-| <display-box> | X | contents, none | |
338-| <display-inside> | X | flow, flow-root, table, flex, grid, ruby | |
339-| <display-internal> | X | table-row-group, table-header-group, table-footer-group, table-row, table-cell, table-column-group, table-column, table-caption, ruby-base, ruby-text, ruby-base-container, ruby-text-container | |
340-| <display-legacy> | X | inline-block, inline-table, inline-flex, inline-grid | |
341-| <display-listitem> | X | <display-outside>, flow, flow-root, list-item | |
342-| <display-outside> | X | block, inline, run-in | |
343-| <easing-function> | | <linear-easing-function>, linear, ease, ease-in, ease-out, ease-in-out, <cubic-bezier-function>, step-start, step-end, <steps-function>, jump-start, jump-end, jump-none, jump-both, start, end | |
344-| <filter-function> | X | <blur>, <brightness>, <contrast>, <drop-shadow>, <gray-scale>, <hue-rotate>, <invert>, <opactity>, <sepia>, <saturate> | |
345-| <frequency-percentage> | X | <frequency>, <percentage> | |
346-| <frequency> | X | kHz, Khz, KHz, KHZ, hz, Hz, HZ, hZ | |
347-| <generic-family> | X | serif, sans-serif, monospace, cursive, fantasy, system-ui, ui-serif, ui-sans-serif, ui-monospace, ui-rounded, math, fangsong | |
348-| <gradient> | X | <linear-gradient>, <repeating-linear-gradient>, <radial-gradient>, <repeating-radial-gradient>, <position> | |
349-| <side-or-corner> | / | | Use <position> instead |
350-| <position> | X | top, left, bottom, right, center | |
351-| <shape> | X | circle, ellipse | |
352-| <hex-color> | X | #RGB, #RGBA, #RRGGBB, #RRGGBBAA | |
353-| <hue-interpolation-method> | shorter hue, longer hue, increasing hue, decreasing hue | |
354-| <hue> | | <number>, <angle> | |
355-| <image> | | <url>, <image>, <image-set>, <cross-fade>, <element>, <gradient> | |
356-| <integer> | | | |
357-| <length-percentage> | | | |
358-| <length> |
359-| <>
360-
361-## Other
362-| Name | Support | Usage | Note |
363-|-|-|-|-|
364-| Variables | X | --<name> | |
365diff --git a/docs/content/index.md b/docs/content/index.md
366deleted file mode 100755
367index 06e37bb..0000000
368--- a/docs/content/index.md
369+++ /dev/null
370@@ -1,31 +0,0 @@
371-# Getting Started
372-
373-## Cloning
374-
375-```sh
376-git clone https://grimui.com/grim.git
377-```
378-
379-
380-## Installing
381-
382-### Adding to a project
383-```sh
384-cd my_project/
385-git submodule add https://grimui.com/grim.git
386-```
387-
388-### Including
389-```c++
390-#include "grim.h";
391-```
392-
393-```sh
394-clang++ -Igrim/include grim/build/grim.o
395-```
396-
397-### Make
398-```sh
399-cd grim
400-make all
401-```
402diff --git a/docs/manpage/grim.html b/docs/manpage/grim.html
403deleted file mode 100755
404index e69de29..0000000
405diff --git a/docs/template.html b/docs/template.html
406deleted file mode 100755
407index 3c56f6a..0000000
408--- a/docs/template.html
409+++ /dev/null
410@@ -1,37 +0,0 @@
411-<!DOCTYPE html>
412-<html lang="en">
413- <head>
414- <meta charset="UTF-8" />
415- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
416- <title>Grim</title>
417- <meta name="description" content="Grim is a new implementation of HTML/CSS/DOM API.">
418- <style>
419-body {
420- margin-bottom: 100px;
421-}
422-table {
423- width: 100%%;
424- border-collapse: collapse;
425-}
426-th,
427-td {
428- text-align: center;
429- border: 1px solid #ddd;
430- padding: 8px;
431-}
432-th {
433- background-color: #f2f2f2;
434-}
435- </style>
436- </head>
437- <body>
438- <main style="margin: 0 4rem 0 4rem">
439- <div style="display: flex; gap: 1rem">
440- %s
441- <div style="width: 100%%">
442- <section>%s</section>
443- </div>
444- </div>
445- </main>
446- </body>
447-</html>
448diff --git a/include/grim.h b/include/grim.h
449index 4fd2493..4a4dd77 100755
450--- a/include/grim.h
451+++ b/include/grim.h
452@@ -130,6 +130,7 @@ class Node {
453 Node* createElement(std::string name);
454
455 void setAttribute(const std::string& name, const std::string& value);
456+ void deleteAttribute(const std::string& name);
457 std::optional<Attribute> getAttribute(const std::string& name) const;
458
459 const std::unordered_map<std::string, std::string>& getAttributes() const;
460@@ -218,7 +219,7 @@ enum class KeyType : short {
461
462 enum class UnitType : short {
463 // Color
464- HEX, RGB, RGBA, HSL,
465+ TEST, HEX, RGB, RGBA, HSL,
466 // Logic
467 AND, OR, NOT, ONLY, COMMA,
468 // Length
469@@ -297,7 +298,7 @@ enum class UnitType : short {
470 SKEW, SKEWX, SKEWY,
471
472 // Keyword
473- PRINT, SCREEN, TOKEN, FUNC, GROUP, NO_SUPPORT, IMAGE
474+ PRINT, SCREEN, TOKEN, FUNC, GROUP, NO_SUPPORT, IMAGE, STRING
475 };
476
477 // 4 bytes
478@@ -307,6 +308,7 @@ union UnitValue {
479 unsigned int UINT;
480 float FLOAT;
481 bool BOOL;
482+ char CHAR;
483 };
484
485 // 6 bytes
486@@ -324,18 +326,17 @@ class Style {
487 public:
488 Window* window;
489
490- std::unordered_map<std::string, std::vector<size_t>> basemap;
491- std::vector<int> indexes;
492+ std::unordered_map<std::string, std::vector<size_t>> basemap{};
493
494 StyleType type;
495 std::string name;
496- std::vector<std::vector<std::string>> selector;
497+ std::vector<std::vector<std::string>> selector{};
498
499- std::unordered_map<KeyType, std::vector<Unit>> properties;
500- std::unordered_map<std::string, std::vector<Unit>> variables;
501+ std::unordered_map<KeyType, std::vector<Unit>> properties{};
502+ std::unordered_map<std::string, std::vector<Unit>> variables{};
503
504 // Nesting
505- std::vector<Style> children;
506+ std::vector<Style> children{};
507
508 // Functions
509 void addChild(Style s);
510diff --git a/docs/content/adding/adding-css-properties.3 b/man/adding-css-properties.3
511similarity index 100%
512rename from docs/content/adding/adding-css-properties.3
513rename to man/adding-css-properties.3
514diff --git a/docs/manpage/grim.3 b/man/grim.3
515similarity index 100%
516rename from docs/manpage/grim.3
517rename to man/grim.3
518diff --git a/docs/content/features/supported-css-selectors.1 b/man/supported-css-selectors.1
519similarity index 100%
520rename from docs/content/features/supported-css-selectors.1
521rename to man/supported-css-selectors.1
522diff --git a/playground/parseselectorparts.cc b/playground/parseselectorparts.cc
523new file mode 100644
524index 0000000..ba0065d
525--- /dev/null
526+++ b/playground/parseselectorparts.cc
527@@ -0,0 +1,12 @@
528+#include "../include/grim.h"
529+#include "../include/parser.h"
530+#include <string>
531+#include <vector>
532+#include <iostream>
533+
534+int main() {
535+ std::vector<std::vector<std::string>> parts = parseSelectorParts("2n + 3");
536+
537+ std::cout << std::stoi(parts[0][0].substr(0,parts[0][0].length()-1)) << std::endl;
538+}
539+
540diff --git a/playground/testselector.cc b/playground/testselector.cc
541new file mode 100644
542index 0000000..db55f05
543--- /dev/null
544+++ b/playground/testselector.cc
545@@ -0,0 +1,45 @@
546+#include "../include/grim.h"
547+#include "../include/parser.h"
548+#include <string>
549+#include <sstream>
550+#include <vector>
551+#include <iostream>
552+
553+int main() {
554+ std::string html = "<!DOCTYPE html>"
555+ "<html>"
556+ "<head>"
557+ "<title>This is a simple test</title>"
558+ "<link rel=\"stylesheet\" href=\'/style.css\'/>"
559+ "</head>"
560+ "<body>"
561+ "<h1 id=\"h1Tag\">Header</h1>"
562+ "<p id=\"paragraph\" class=\"class1 class2\">This is some text for a simple test</p>"
563+ "<div contenteditable=\"true\">"
564+ "<p>this is a only child</p>"
565+ "</div>"
566+ "<input type=\"text\" checked required/>"
567+ "<ul>"
568+ "<li>one</li>"
569+ "<li>two</li>"
570+ "<li>three</li>"
571+ "<li>four</li>"
572+ "</ul>"
573+ "<input type=\"radio\" checked required/>"
574+ "<input type=\"text\" readonly/>"
575+ "<input type=\"text\" disabled/>"
576+ "<textarea></textarea>"
577+ "<textarea readonly></textarea>"
578+ "<textarea disabled></textarea>"
579+ "</body>"
580+ "</html>";
581+
582+
583+ std::stringstream ss(html);
584+ Node document = parseHTML(ss);
585+
586+
587+ auto li = document.children[0]->children[1]->children[4]->children[3].get();
588+
589+ std::cout << testSelector(li, parseSelectorParts(":nth-last-child(even)")) << std::endl;
590+}
591diff --git a/src/grim.cc b/src/grim.cc
592index 05133af..832596b 100755
593--- a/src/grim.cc
594+++ b/src/grim.cc
595@@ -106,6 +106,10 @@ void Node::setAttribute(const std::string& name, const std::string& value) {
596 attributes[name] = value;
597 }
598
599+void Node::deleteAttribute(const std::string& name) {
600+ attributes.erase(name);
601+}
602+
603 std::optional<Attribute> Node::getAttribute(const std::string& name) const {
604 // First check in the user set attributes
605 auto it = attributes.find(name);
606@@ -561,21 +565,29 @@ std::vector<std::vector<std::string>> parseSelectorParts(std::string_view select
607 for (size_t i = start; i < end; i++) {
608 char s = selector[i];
609 if (s == '\'') s = '"';
610- if (s == '(' || s == '[' || s == '{') {
611- if (!current.empty()) {
612+
613+ if ((s == '(' || s == '[' || s == '{')) {
614+ if (!current.empty() && nesting == 0) {
615 buffer.push_back(current);
616 current.clear();
617 }
618+
619+ current.push_back(s);
620 nesting++;
621+ continue;
622 }
623
624- if (s == ')' || s == ']' || s == '}') {
625- current.push_back(s);
626- buffer.push_back(current);
627- current.clear();
628+ if ((s == ')' || s == ']' || s == '}')) {
629 nesting--;
630+ current.push_back(s);
631+ if (!current.empty() && nesting == 0) {
632+
633+ buffer.push_back(current);
634+ current.clear();
635+ }
636 continue;
637 } else {
638+
639 if (nesting > 0) {
640 current.push_back(s);
641 continue;
642@@ -588,6 +600,7 @@ std::vector<std::vector<std::string>> parseSelectorParts(std::string_view select
643 } else {
644 if (!current.empty()) {
645 buffer.push_back(current);
646+ buffer.push_back(" ");
647 current.clear();
648 }
649 }
650@@ -604,8 +617,14 @@ std::vector<std::vector<std::string>> parseSelectorParts(std::string_view select
651 buffer.push_back(current);
652 current.clear();
653 }
654- buffer.push_back("");
655- buffer.back() += s;
656+ // A few lines above we add a empty space when the next char is not a space
657+ // and the current is not empty. This is to create the decendant combinator
658+ // but if one of the symbols in the statement are folling then we need to replace
659+ // the empty space with the correct combinator
660+ if (buffer.size() == 0) {
661+ buffer.push_back("");
662+ }
663+ buffer.back() = s;
664 } else if (s == ':' || s == '#' || s == '.') {
665 if (i < end-1 && selector[i+1] == ':') continue;
666 if (!current.empty()) {
667@@ -791,8 +810,8 @@ bool testSelector(Node* node, std::vector<std::vector<std::string>> selector) {
668 // This is setup code for the rest of the process
669 // parts is the part of the selector that applies to
670 // the current node: If we had div > h1 we would get
671- // "h1" and the div part would be stored in trimmed.
672- // then the symbol we split at is symbol. See below
673+ // "h1" and the div part would be stored in "trimmed".
674+ // then the symbol we split at is "symbol". See below
675 for (int i = selector[0].size()-1; i >= 0; i--) {
676 std::string part = selector[0][i];
677 if (symbolFound) {
678@@ -812,7 +831,7 @@ bool testSelector(Node* node, std::vector<std::vector<std::string>> selector) {
679 // trimmed = {"div"}
680 // parts = {"h1"}
681 // symbol = ">"
682-
683+
684 // matched is true here because the node matching logic
685 // returns if matched is false
686 bool matched = true;
687@@ -847,7 +866,8 @@ bool testSelector(Node* node, std::vector<std::vector<std::string>> selector) {
688
689 // Find the index of the child relative to it's parent
690
691- // the children variable is the PARENTS CHILDREN the the current node's children
692+ // the children variable is the PARENTS CHILDREN not the current node's children
693+ // aka siblings
694 // if you want those, node->children
695 const std::vector<std::unique_ptr<Node>>& children = (node->parent != nullptr) ? node->parent->children : EMPTY_NODE_CHILDREN_VECTOR;
696 size_t childIndex = 0;
697@@ -869,25 +889,25 @@ bool testSelector(Node* node, std::vector<std::vector<std::string>> selector) {
698
699 // Add the auto pseudo classes like first-child/last-child
700 if (childIndex == 0) {
701- attrs.push_back("first-child");
702+ attributes["first-child"] = "true";
703 }
704 if (childIndex == children.size()-1) {
705- attrs.push_back("last-child");
706+ attributes["last-child"] = "true";
707 }
708 if (childTypeIndex == 0) {
709- attrs.push_back("first-of-type");
710+ attributes["first-of-type"] = "true";
711 }
712 if (childTypeIndex == childTypeCount-1) {
713- attrs.push_back("last-of-type");
714+ attributes["last-of-type"] = "true";
715 }
716 if (childIndex == 0 && children.size() == 1) {
717- attrs.push_back("only-child");
718+ attributes["only-child"] = "true";
719 }
720 if (childTypeIndex == 0 && childTypeCount == 1) {
721- attrs.push_back("only-of-type");
722+ attributes["only-of-type"] = "true";
723 }
724 if (tagName == "html") {
725- attrs.push_back("root");
726+ attributes["root"] = "true";
727 }
728
729 if (tagName == "input") {
730@@ -898,27 +918,27 @@ bool testSelector(Node* node, std::vector<std::vector<std::string>> selector) {
731 || type == "password" || type == "date" || type == "month" || type == "week"
732 || type == "time" || type == "datetime-local" || type == "number") {
733 if (readonly || disabled) {
734- attrs.push_back("read-only");
735+ attributes["read-only"] = "true";
736 } else {
737- attrs.push_back("read-write");
738+ attributes["read-write"] = "true";
739 }
740 } else {
741- attrs.push_back("read-only");
742+ attributes["read-only"] = "true";
743 }
744 } else if (tagName == "textarea") {
745 bool readonly = attributes.find("readonly") != attributes.end();
746 bool disabled = attributes.find("disabled") != attributes.end();
747 if (readonly || disabled) {
748- attrs.push_back("read-only");
749+ attributes["read-only"] = "true";
750 } else {
751- attrs.push_back("read-write");
752+ attributes["read-write"] = "true";
753 }
754 } else {
755 std::string contentEditable = attributes["contenteditable"];
756 if (contentEditable == "true") {
757- attrs.push_back("read-write");
758+ attributes["read-write"] = "true";
759 } else {
760- attrs.push_back("read-only");
761+ attributes["read-only"] = "true";
762 }
763 }
764
765@@ -948,6 +968,8 @@ bool testSelector(Node* node, std::vector<std::vector<std::string>> selector) {
766 // as parseSelectorParts converts any attribute
767 // without a ending ) to [name]:
768 // See tests/css_selector.cc for examples
769+ // For CSS selectors like :checked that are also attributes, they
770+ // are matched at the last else of the next block
771 bool found = false;
772
773 p.erase(0,1);
774@@ -961,31 +983,34 @@ bool testSelector(Node* node, std::vector<std::vector<std::string>> selector) {
775 matched = found;
776 } // !TODO: Need a case for : , this will run the :has... logic
777 else if (p[0] == ':') {
778- if (p.starts_with(":is(")) {
779- std::string value = p.substr(4,p.length()-5);
780- matched = testSelector(node, parseSelectorParts(value));
781- } else if (p.starts_with(":where(")) {
782+
783+ // need to get the ext one and shave off 1,-1
784+
785+ std::vector<std::vector<std::string>> next;
786+ if (i+1 < parts.size()) {
787+ next = parseSelectorParts(parts[i+1].substr(1,parts[i+1].length()-2));
788+ }
789+
790+ if (p.starts_with(":is")) {
791+ matched = testSelector(node, next);
792+ } else if (p.starts_with(":where")) {
793 // Per specification where and is differ in specificity only
794 // however, grim does not support specificity
795 // https://developer.mozilla.org/en-US/docs/Web/CSS/:is#difference_between_is_and_where
796- std::string value = p.substr(7,p.length()-8);
797- matched = testSelector(node, parseSelectorParts(value));
798- } else if (p.starts_with(":not(")) {
799- std::string value = p.substr(5,p.length()-6);
800+ matched = testSelector(node, next);
801+ } else if (p.starts_with(":not")) {
802 // Just inverts the output of testSelector
803- matched = !testSelector(node, parseSelectorParts(value));
804- } else if (p.starts_with(":has(")) {
805+ matched = !testSelector(node, next);
806+ } else if (p.starts_with(":has")) {
807 // +------------------------------------------------------+
808 // |(jhsfk) Has selection |
809 // +------------------------------------------------------+
810 // We have to do a little work to get :has working
811 // once we parse the inner parts of the selector,
812 // we need to find what the selector is targeting
813- std::string value = p.substr(5,p.length()-6);
814- auto innerParts = parseSelectorParts(value);
815 bool found = false;
816
817- for (auto ip : innerParts) {
818+ for (auto ip : next) {
819 // if the selector was :has(+ p, div, > video)
820 // ip contains each comma seperated value like {"+", "p"}
821 // these differ from how we parse the parts below
822@@ -1078,95 +1103,92 @@ bool testSelector(Node* node, std::vector<std::vector<std::string>> selector) {
823 // Instead of moving these up a layer I'm putting them
824 // here because most selectors will not be "nth-" so why
825 // check against every case
826- std::string pattern;
827 bool last = false;
828 bool ofType = false;
829- if (p.starts_with(":nth-child")) {
830- pattern = p.substr(11, p.length()-12);
831- } else if (p.starts_with(":nth-last-child(")) {
832+ if (p == ":nth-last-child") {
833 last = true;
834- pattern = p.substr(16,p.length()-17);
835- } else if (p.starts_with(":nth-of-type(")) {
836+ } else if (p == ":nth-of-type") {
837 ofType = true;
838- pattern = p.substr(13,p.length()-14);
839- } else if (p.starts_with(":nth-last-of-type(")) {
840+ } else if (p == ":nth-last-of-type") {
841 ofType = true;
842 last = true;
843- pattern = p.substr(18, p.length()-19);
844 }
845 // +------------------------------------------------------+
846 // |Parsing the pattern |
847 // +------------------------------------------------------+
848- // If you look closely these are reversed
849- // its because the vector index starts with 0
850- // and CSS starts with 1
851- if (pattern == "even") {
852- if (childIndex%2 == 1) {
853- matched = true;
854- } else {
855- matched = false;
856- }
857- } else
858- if (pattern == "odd") {
859- if (childIndex%2 == 0) {
860- matched = true;
861- } else {
862- matched = false;
863- }
864- } else {
865- // loop through
866- // first check if theres a symbol before any 0-9
867- // go until n is found (if there is a n)
868- // then find another symbol or "of"
869- // if symbol find numbers
870- // then of get that.
871- // the of syntax can be used to make nth-of-type as well
872- bool negFound = false;
873- bool negative = false;
874- bool Afound = false;
875- bool nfound = false;
876- int A = 0;
877- int B = 0;
878- char symbol = '+';
879- bool symbolFound = false;
880- std::string ofSelector = "";
881-
882- for (size_t i = 0; i < pattern.length(); i++) {
883- if (!std::isspace(pattern[i])) {
884- if (pattern[i] == '-' && !negFound) {
885- negFound = true;
886- negative = true;
887- } else if (pattern[i] == '+' && !negFound) {
888+
889+ // loop through
890+ // first check if theres a symbol before any 0-9
891+ // go until n is found (if there is a n)
892+ // then find another symbol or "of"
893+ // if symbol find numbers
894+ // then of get that.
895+ // the of syntax can be used to make nth-of-type as well
896+ bool negFound = false;
897+ bool negative = false;
898+ bool Afound = false;
899+ bool nfound = false;
900+ int A = 0;
901+ int B = 0;
902+ char symbol = '+';
903+ bool symbolFound = false;
904+ bool isBool = false;
905+ bool isEven = false;
906+ std::string ofSelector = "";
907+
908+ std::string pattern = parts[i+1].substr(1,parts[i+1].length()-2);
909+
910+ std::cout << "################################" << std::endl;
911+ std::cout << pattern << std::endl;
912+
913+ for (size_t i = 0; i < pattern.length(); i++) {
914+ if (!std::isspace(pattern[i])) {
915+ if (pattern[i] == '-' && !negFound) {
916+ negFound = true;
917+ negative = true;
918+ } else if (pattern[i] == '+' && !negFound) {
919+ negFound = true;
920+ } else if (pattern[i] == 'e' && !nfound && !Afound && pattern.substr(i, 4) == "even") {
921+ i += 4;
922+ isEven = true;
923+ Afound = true;
924+ nfound = true;
925+ isBool = true;
926+ } else if (pattern[i] == 'o' && !nfound && !Afound && pattern.substr(i, 3) == "odd") {
927+ i += 3;
928+ isEven = false;
929+ Afound = true;
930+ nfound = true;
931+ isBool = true;
932+ } else if (pattern[i] == 'n' && !nfound && !Afound ) {
933+ nfound = true;
934+ // At n stop adding to A
935+ Afound = true;
936+ negFound = true;
937+ } else if (Afound && nfound && !symbolFound && (pattern[i] == '-' || pattern[i] == '+')) {
938+ symbol = pattern[i];
939+ symbolFound = true;
940+ } else if (pattern[i]-'0' < 10) {
941 negFound = true;
942- } else if (pattern[i] == 'n' && !nfound && !Afound ) {
943- nfound = true;
944- // At n stop adding to A
945- Afound = true;
946- negFound = true;
947- } else if (Afound && nfound && !symbolFound && (pattern[i] == '-' || pattern[i] == '+')) {
948- symbol = pattern[i];
949- symbolFound = true;
950- } else if (pattern[i]-'0' < 10) {
951- negFound = true;
952- if (!Afound && !nfound) {
953- A *= 10;
954- A += (pattern[i]-'0');
955- } else if (nfound && symbolFound && Afound) {
956- B *= 10;
957- B += (pattern[i]-'0');
958- }
959- } else {
960- ofSelector += pattern[i];
961- }
962+ if (!Afound && !nfound) {
963+ A *= 10;
964+ A += (pattern[i]-'0');
965+ } else if (nfound && symbolFound && Afound) {
966+ B *= 10;
967+ B += (pattern[i]-'0');
968+ }
969+ } else {
970+ ofSelector += pattern[i];
971 }
972 }
973+ }
974
975- if (negative) {
976- A *= -1;
977- }
978- if (symbol == '-') {
979- B *= -1;
980- }
981+ if (negative) {
982+ A *= -1;
983+ }
984+ if (symbol == '-') {
985+ B *= -1;
986+ }
987
988 // Now we have:
989 // polarity of A: negative
990@@ -1183,87 +1205,114 @@ bool testSelector(Node* node, std::vector<std::vector<std::string>> selector) {
991 // +------------------------------------------------------+
992 // |Finding the index of node |
993 // +------------------------------------------------------+
994- int index = 0;
995- // We have the index of the current element (childIndex)
996- // if ofSelector is "" we can use it if not we need to run
997- // testSelector on all children until we find it
998- // and if "last" we need to do it in reverse
999- //
1000- // If the nth child selector has -of-type we need to add of+tagname
1001- // the of is added because thats how the parser parses the rest of them
1002- if (ofType) {
1003- ofSelector = "of"+tagName;
1004- }
1005+ int index = 0;
1006+ // We have the index of the current element (childIndex)
1007+ // if ofSelector is "" we can use it if not we need to run
1008+ // testSelector on all children until we find it
1009+ // and if "last" we need to do it in reverse
1010+ //
1011+ // If the nth child selector has -of-type we need to add of+tagname
1012+ // the of is added because thats how the parser parses the rest of them
1013+ if (ofType) {
1014+ ofSelector = "of"+tagName;
1015+ }
1016
1017- if (ofSelector == "") {
1018- if (last) {
1019- // If we are checking from the back we need to invert the
1020- // childIndex
1021- index = children.size() - 1 - childIndex;
1022- } else {
1023- index = childIndex;
1024- }
1025+ if (ofSelector == "") {
1026+ if (last) {
1027+ // If we are checking from the back we need to invert the
1028+ // childIndex
1029+ index = children.size() - 1 - childIndex;
1030+ if (isBool) {
1031+ index--;
1032+ }
1033 } else {
1034- // Parse the of selector
1035- auto pOS = parseSelectorParts(ofSelector.substr(2));
1036- if (testSelector(node, pOS)) {
1037- if (last) {
1038- // Reverse through the siblings
1039- for (size_t i = children.size() - 1; i >= 0; i--) {
1040- Node* child_ptr = children[i].get();
1041- if (child_ptr != node) {
1042- if (testSelector(child_ptr, pOS)) {
1043- // if the selector matches the ofSelector add one
1044- index++;
1045- }
1046- } else {
1047- // We are at the pointer address of the target node
1048- break;
1049+ index = childIndex;
1050+ }
1051+ } else {
1052+ std::cout << "Has of: " << ofSelector << std::endl;
1053+ // Parse the of selector
1054+ auto pOS = parseSelectorParts(ofSelector.substr(2));
1055+ if (testSelector(node, pOS)) {
1056+ if (last) {
1057+ // Reverse through the siblings
1058+ for (size_t i = children.size() - 1; i >= 0; i--) {
1059+ Node* child_ptr = children[i].get();
1060+ if (child_ptr != node) {
1061+ if (testSelector(child_ptr, pOS)) {
1062+ // if the selector matches the ofSelector add one
1063+ index++;
1064 }
1065+ } else {
1066+ // We are at the pointer address of the target node
1067+ break;
1068 }
1069- } else {
1070- for (size_t i = 0; i < children.size(); i++) {
1071- Node* child_ptr = children[i].get();
1072- if (child_ptr != node) {
1073- if (testSelector(child_ptr, pOS)) {
1074- // if the selector matches the ofSelector add one
1075- index++;
1076- }
1077- } else {
1078- // We are at the pointer address of the target node
1079- break;
1080+ }
1081+ if (isBool) {
1082+ index--;
1083+ }
1084+ } else {
1085+ for (size_t i = 0; i < children.size(); i++) {
1086+ Node* child_ptr = children[i].get();
1087+ if (child_ptr != node) {
1088+ if (testSelector(child_ptr, pOS)) {
1089+ // if the selector matches the ofSelector add one
1090+ index++;
1091 }
1092+ } else {
1093+ // We are at the pointer address of the target node
1094+ break;
1095 }
1096 }
1097- } else {
1098- // the target node doesn't match the of selector then it can not
1099- // be a match so return false no need to set matched to false and continue
1100- return false;
1101 }
1102+ } else {
1103+ // the target node doesn't match the of selector then it can not
1104+ // be a match so return false no need to set matched to false and continue
1105+ return false;
1106 }
1107+ }
1108
1109- // Add one to index because CSS starts at 1
1110- index++;
1111- // Now we have the index of the node and we can compute if its a match
1112- // this is done by calculating the An+B
1113- // The An+B is calculated based on two things
1114- // n must be >= 0
1115- // n cannot be a float
1116- // so we solve for n with (index-B)/A then we check those two conditions
1117- // if nfound is false and A != 0 then we can just compare the two numbers
1118-
1119- // Given n+B A is implicitly 1, this will fail if A is set to 0
1120- if (A == 0) {
1121- A = 1;
1122+ // Add one to index because CSS starts at 1
1123+ index++;
1124+// Now we have the index of the node and we can compute if its a match
1125+// this is done by calculating the An+B
1126+// The An+B is calculated based on two things
1127+// n must be >= 0
1128+// n cannot be a float
1129+// so we solve for n with (index-B)/A then we check those two conditions
1130+// if nfound is false and A != 0 then we can just compare the two numbers
1131+
1132+ // Given n+B A is implicitly 1, this will fail if A is set to 0
1133+ if (A == 0) {
1134+ A = 1;
1135+ }
1136+
1137+ std::cout << "A: " << A << std::endl;
1138+ std::cout << "B: " << B << std::endl;
1139+ std::cout << "Sym: " << symbol << std::endl;
1140+ std::cout << "OF: " << ofSelector << std::endl;
1141+ std::cout << "Index: " << index << std::endl;
1142+
1143+ if (isBool) {
1144+ if (isEven) {
1145+ matched = index%2 == 0;
1146+ } else {
1147+ matched = index%2 != 0;
1148 }
1149+ } else {
1150 if (!nfound) {
1151 matched = A == index;
1152 } else {
1153 matched = (index-B)/A >= 0 && (index-B)%A == 0;
1154 }
1155-
1156 }
1157+ } else {
1158+ // Here we didn't get a hit on any function selector, so we can assume its probally a attribute selector like focus or :checked
1159+
1160+ p.erase(0,1);
1161+
1162+ matched = attributes[p] == "true";
1163 }
1164+
1165 // If there are any pseudo elements we will just skip them
1166 // with the transformers being replaced with pseudo elements
1167 // we won't know all of them. Will need to have a function to strip
1168diff --git a/src/parser.cc b/src/parser.cc
1169index 3cff12a..5b750e1 100755
1170--- a/src/parser.cc
1171+++ b/src/parser.cc
1172@@ -96,6 +96,10 @@ std::unordered_map<std::string, std::string> parseAttributes(std::string_view to
1173 }
1174 }
1175
1176+ if (trimmedValue.length() == 0) {
1177+ trimmedValue = "true";
1178+ }
1179+
1180 attrs[trimmedName] = trimmedValue;
1181 }
1182 }
1183@@ -1369,6 +1373,15 @@ std::vector<Unit> getUnit(std::string value) {
1184 buffer.clear();
1185 }
1186
1187+ } else if (inQuotes) {
1188+ if (v == '"') continue;
1189+ Unit u;
1190+ u.type = UnitType::STRING;
1191+ UnitValue uv;
1192+ uv.CHAR = v;
1193+ u.value = uv;
1194+
1195+ units.push_back(u);
1196 } else {
1197 buffer.push_back(v);
1198 }
1199@@ -1385,11 +1398,9 @@ Style parseCSS(std::istream& inputStream) {
1200 // nowhitespace: value(can have whitespace); = property
1201 // a selector name is anything before a { up to a ; or a }
1202 std::vector<Style*> stack;
1203+ Style root{};
1204+ Style* current = &root;
1205
1206- // change to a stack based tree
1207-
1208- Style current{};
1209- stack.push_back(¤t);
1210 // how to handle @import
1211
1212 std::string buffer;
1213@@ -1424,7 +1435,7 @@ Style parseCSS(std::istream& inputStream) {
1214 // Parse the selector into its parts
1215 std::vector<std::vector<std::string>> parts = parseSelectorParts(buffer);
1216
1217- if (current.selector.size() > 0) {
1218+ if (current->selector.size() > 0) {
1219 // To be able to handle a substitution with a parent that has h1, h2
1220 // we need to rebuild the selector so we can add new copies
1221 std::vector<std::vector<std::string>> subd;
1222@@ -1446,11 +1457,11 @@ Style parseCSS(std::istream& inputStream) {
1223 // Child: [[& .class, &, &]]
1224 // Result: [[h1 .class, h1, h1]]
1225 // [[h2 .class, h2, h2]]
1226- for (size_t e = 0; e < current.selector.size(); e++) {
1227+ for (size_t e = 0; e < current->selector.size(); e++) {
1228 std::vector<std::string> temp;
1229 for (size_t f = 0; f < parts[i].size(); f++) {
1230 if (parts[i][f] == "&") {
1231- for (auto p : current.selector[e]) {
1232+ for (auto p : current->selector[e]) {
1233 temp.push_back(p);
1234 }
1235 } else {
1236@@ -1468,18 +1479,19 @@ Style parseCSS(std::istream& inputStream) {
1237 parts = subd;
1238 }
1239
1240- // Find who the parent is
1241+ stack.push_back(current);
1242+
1243 Style newSheet{};
1244 newSheet.selector = parts;
1245- current.addChild(newSheet);
1246+ current->addChild(newSheet);
1247
1248- current = current.children.back();
1249+ current = ¤t->children.back();
1250
1251 // here we need to take the selector (buffer)
1252 // and find out what type it is. Also need to manage the nesting
1253 if (parts[0][0][0] == '@') {
1254 if (parts[0][0] == "@container") {
1255- current.type = StyleType::CONTAINER;
1256+ current->type = StyleType::CONTAINER;
1257 bool hasName = false;
1258 if (parts[0].size() >= 3) {
1259 // @container not (width < 400px)
1260@@ -1487,7 +1499,7 @@ Style parseCSS(std::istream& inputStream) {
1261 // @container (width > 400px) or|and (height > 400px)
1262 if (parts[0].size() >= 5) {
1263 if (parts[0][5] != "and" || parts[0][5] != "or") {
1264- current.name = parts[0][2];
1265+ current->name = parts[0][2];
1266 hasName = true;
1267 }
1268 }
1269@@ -1496,56 +1508,55 @@ Style parseCSS(std::istream& inputStream) {
1270 // If a name is present then remove the name and tag from the selector
1271 // else just remove the @container
1272 if (hasName) {
1273- current.selector[0] = std::vector<std::string>(current.selector[0].begin() + 3, current.selector[0].end());
1274+ current->selector[0] = std::vector<std::string>(current->selector[0].begin() + 3, current->selector[0].end());
1275 } else {
1276- current.selector[0] = std::vector<std::string>(current.selector[0].begin() + 1, current.selector[0].end());
1277+ current->selector[0] = std::vector<std::string>(current->selector[0].begin() + 1, current->selector[0].end());
1278 }
1279 } else if (parts[0][0] == "@counter-style") {
1280- current.name = parts[0][2];
1281- current.type = StyleType::COUNTER;
1282+ current->name = parts[0][2];
1283+ current->type = StyleType::COUNTER;
1284 } else if (parts[0][0] == "@font-face") {
1285- current.type = StyleType::FONTFACE;
1286+ current->type = StyleType::FONTFACE;
1287 } else if (parts[0][0] == "@font-feature") {
1288- current.type = StyleType::FONTFEATURE;
1289+ current->type = StyleType::FONTFEATURE;
1290 } else if (parts[0][0] == "@swash") {
1291- current.type = StyleType::SWASH;
1292+ current->type = StyleType::SWASH;
1293 } else if (parts[0][0] == "@annotation") {
1294- current.type = StyleType::ANNOTATION;
1295+ current->type = StyleType::ANNOTATION;
1296 } else if (parts[0][0] == "@ornaments") {
1297- current.type = StyleType::ORNAMENTS;
1298+ current->type = StyleType::ORNAMENTS;
1299 } else if (parts[0][0] == "@stylistic") {
1300- current.type = StyleType::STYLISTIC;
1301+ current->type = StyleType::STYLISTIC;
1302 } else if (parts[0][0] == "@styleset") {
1303- current.type = StyleType::STYLESET;
1304+ current->type = StyleType::STYLESET;
1305 } else if (parts[0][0] == "@character-varient") {
1306- current.type = StyleType::CHARACTERVARIANT;
1307+ current->type = StyleType::CHARACTERVARIANT;
1308 } else if (parts[0][0] == "@font-palette-values") {
1309- current.type = StyleType::FONTPALETTEVALUES;
1310- current.name = parts[0][2];
1311+ current->type = StyleType::FONTPALETTEVALUES;
1312+ current->name = parts[0][2];
1313 } else if (parts[0][0] == "@keyframes") {
1314- current.type = StyleType::KEYFRAMES;
1315- current.name = parts[0][2];
1316+ current->type = StyleType::KEYFRAMES;
1317+ current->name = parts[0][2];
1318 } else if (parts[0][0] == "@layer") {
1319- current.type = StyleType::LAYER;
1320+ current->type = StyleType::LAYER;
1321 } else if (parts[0][0] == "@media") {
1322- current.type = StyleType::MEDIA;
1323+ current->type = StyleType::MEDIA;
1324 } else if (parts[0][0] == "@property") {
1325- current.type = StyleType::PROPERTY;
1326- current.name = parts[0][2];
1327+ current->type = StyleType::PROPERTY;
1328+ current->name = parts[0][2];
1329 } else if (parts[0][0] == "@starting-style") {
1330- current.type = StyleType::STARTINGSTYLE;
1331+ current->type = StyleType::STARTINGSTYLE;
1332 }
1333 } else {
1334- current.type = StyleType::STYLE;
1335+ current->type = StyleType::STYLE;
1336 }
1337
1338
1339 buffer.clear();
1340 } else if (ch == '}') {
1341
1342-
1343- if (stack.size() > 0) {
1344- current = *stack.back();
1345+ if (!stack.empty()) {
1346+ current = stack.back();
1347 stack.pop_back();
1348 }
1349
1350@@ -1573,7 +1584,7 @@ Style parseCSS(std::istream& inputStream) {
1351
1352 }
1353
1354- current.children.push_back(inlineRule);
1355+ current->addChild(inlineRule);
1356
1357 } else {
1358 // end of a style property
1359@@ -1599,7 +1610,7 @@ Style parseCSS(std::istream& inputStream) {
1360 }
1361
1362 if (key.length() > 2 && key[0] == '-' && key[1] == '-') {
1363- current.variables[key] = getUnit(value);
1364+ current->variables[key] = getUnit(value);
1365 } else {
1366 KeyType keyENUM;
1367
1368@@ -1608,7 +1619,7 @@ Style parseCSS(std::istream& inputStream) {
1369 } else {
1370 std::cout << "Invalid property name: " << key << std::endl;
1371 }
1372- current.properties[keyENUM] = getUnit(value);
1373+ current->properties[keyENUM] = getUnit(value);
1374 }
1375 }
1376 buffer.clear();
1377@@ -1616,6 +1627,8 @@ Style parseCSS(std::istream& inputStream) {
1378 buffer.push_back(ch);
1379 }
1380 }
1381+
1382+ return root;
1383 }
1384
1385 std::unordered_map<KeyType, std::vector<Unit>> parseCSSInline(std::string inlineStyles) {
1386diff --git a/tests/css_parser.cc b/tests/css_parser.cc
1387index 9150bc3..1f8a086 100755
1388--- a/tests/css_parser.cc
1389+++ b/tests/css_parser.cc
1390@@ -30,16 +30,39 @@ void compareStyle(std::string selector, std::unordered_map<KeyType, std::vector<
1391 }
1392 }
1393
1394+ size_t n = 0;
1395 for (auto p : props) {
1396- std::vector<Unit> f = p.second;
1397- std::vector<Unit> s = style.properties[p.first];
1398+ std::vector<Unit> propsV = p.second;
1399+ std::vector<Unit> styleV = style.properties[p.first];
1400
1401- REQUIRE(f.size() == s.size());
1402+ REQUIRE(propsV.size() == styleV.size());
1403+ INFO("----");
1404+ INFO(n);
1405+ INFO("--");
1406+
1407+ for (size_t i = 0; i < propsV.size(); i++) {
1408+ INFO(i);
1409+
1410+ REQUIRE(propsV[i].type == styleV[i].type);
1411
1412- for (size_t i = 0; i < f.size(); i++) {
1413- REQUIRE(f[i].type == s[i].type);
1414 }
1415+ n++;
1416+ }
1417+}
1418+
1419+std::vector<Unit> buildString(Unit start, std::string value) {
1420+ std::vector<Unit> units;
1421+ units.push_back(start);
1422+
1423+ for (size_t i = 0; i < value.length(); i++) {
1424+ Unit u;
1425+ u.type = UnitType::STRING;
1426+ UnitValue uv;
1427+ uv.CHAR = value[i];
1428+ u.value = uv;
1429+ units.push_back(u);
1430 }
1431+ return units;
1432 }
1433
1434 void compareInlineStyles(std::string style, std::unordered_map<KeyType, std::vector<Unit>> targetProps) {
1435@@ -124,136 +147,140 @@ html#nested {
1436 Style style = parseCSS(inputFile);
1437
1438 SECTION("parseCSS can parse simple CSS rules") {
1439+ UnitValue uv;
1440+ uv.UINT = 0xff0000;
1441+
1442 compareStyle("h1", {
1443- {"color", "red"}
1444- }, handler.root.children[0],
1445- SheetType::STYLE
1446+ {KeyType::COLOR, {{UnitType::HEX, uv}}}
1447+ }, style.children[0],
1448+ StyleType::STYLE
1449 );
1450 }
1451
1452-
1453 SECTION("parseCSS can parse a CSS rule with a child combinator") {
1454+ UnitValue uv;
1455+ uv.UINT = 0x800080;
1456 compareStyle("h1 > #id", {
1457- {"background", "purple"}
1458- }, handler.root.children[1],
1459- SheetType::STYLE
1460+ {KeyType::BACKGROUND, {{UnitType::HEX, uv}}}
1461+ }, style.children[1],
1462+ StyleType::STYLE
1463 );
1464 }
1465
1466 SECTION("parseCSS can parse a CSS rule with a pseudo class") {
1467+ UnitValue uv1;
1468+ UnitValue uv2;
1469+ uv2.FLOAT = 1;
1470+ UnitValue uv3;
1471+ uv3.FLOAT = 100;
1472+ UnitValue uv4;
1473+ uv4.FLOAT = 20;
1474 compareStyle("div:checked", {
1475- {"display", "flex"},
1476- {"margin", "1px 100% 20vh"}
1477- }, handler.root.children[2],
1478- SheetType::STYLE
1479+ {KeyType::DISPLAY, {{UnitType::FLEX, uv1}}},
1480+ {KeyType::MARGIN, {{UnitType::PX, uv2},{UnitType::PERCENT, uv3},{UnitType::VH, uv4}}}
1481+ }, style.children[2],
1482+ StyleType::STYLE
1483 );
1484 }
1485
1486 SECTION("parseCSS can parse a the parent of a nested CSS rule") {
1487+ Unit u;
1488+ u.type = UnitType::URL;
1489+ UnitValue uv;
1490+ uv.INT = 19;
1491+ u.value = uv;
1492 compareStyle("html#nested", {
1493- {"background", "url(\"https://example.com\")"},
1494- }, handler.root.children[3],
1495- SheetType::STYLE
1496+ {KeyType::BACKGROUND, buildString(u,"https://example.com")},
1497+ }, style.children[3],
1498+ StyleType::STYLE
1499 );
1500 }
1501
1502 SECTION("parseCSS can parse a nested CSS rule without a &") {
1503 // "html#nested h1[value=\"nested\"]"
1504 // Child of html#nested
1505+ UnitValue uv;
1506+ uv.UINT = 0xff0000;
1507 compareStyle("h1[value=\"nested\"]", {
1508- {"color", "red"},
1509- }, handler.root.children[3].children[0],
1510- SheetType::STYLE
1511+ {KeyType::COLOR, {{UnitType::HEX, uv}}},
1512+ }, style.children[3].children[0],
1513+ StyleType::STYLE
1514 );
1515 }
1516
1517 SECTION("parseCSS can parse a nested CSS rule with a &") {
1518 // TODO: With nested &, they will have to be computed at testSelector
1519 // | but the tree structure still works because the parent selector must still match
1520+ UnitValue uv;
1521 compareStyle("html#nested.class", {
1522- {"border", "none"},
1523- }, handler.root.children[3].children[1],
1524- SheetType::STYLE
1525+ {KeyType::BORDER, {{UnitType::NONE,uv}}},
1526+ }, style.children[3].children[1],
1527+ StyleType::STYLE
1528 );
1529 }
1530
1531 SECTION("parseCSS can parse a parent CSS rule with a property in between sub-classes") {
1532+ UnitValue uv1;
1533+ uv1.FLOAT = 90;
1534+ UnitValue uv2;
1535+ UnitValue uv3;
1536+ uv3.FLOAT = 1;
1537+ UnitValue uv4;
1538+ uv4.UINT = 0xffc107;
1539+ UnitValue uv5;
1540+ uv5.UINT = 0x000000;
1541+ UnitValue uv6;
1542+ uv6.FLOAT = 10;
1543+ UnitValue uv7;
1544+ uv7.FLOAT = 2;
1545 compareStyle(".notice", {
1546- {"width", "90%"},
1547- {"justify-content", "center"},
1548- {"border-radius", "1rem"},
1549- {"border", "black solid 2px"},
1550- {"background-color", "#ffc107"},
1551- {"color", "black"},
1552- {"padding", "1rem"},
1553- {"font-size", "10px"}
1554- }, handler.root.children[4],
1555- SheetType::STYLE
1556+ {KeyType::WIDTH, {{UnitType::PERCENT, uv1}}},
1557+ {KeyType::JUSTIFY_CONTENT, {{UnitType::CENTER, uv2}}},
1558+ {KeyType::BORDER_RADIUS, {{UnitType::REM, uv3}}},
1559+ {KeyType::BORDER, {{UnitType::COLOR, uv5},{UnitType::SOLID, uv2}, {UnitType::PX, uv7}}},
1560+ {KeyType::BACKGROUND_COLOR, {{UnitType::COLOR, uv4}}},
1561+ {KeyType::COLOR, {{UnitType::COLOR, uv5}}},
1562+ {KeyType::PADDING, {{UnitType::REM, uv3}}},
1563+ {KeyType::FONT_SIZE, {{UnitType::PX, uv6}}}
1564+ }, style.children[4],
1565+ StyleType::STYLE
1566 );
1567 }
1568
1569 SECTION("parseCSS can parse a nested CSS rule with a pseudo element") {
1570+ Unit u1;
1571+ u1.type = UnitType::STRING;
1572+ UnitValue uv1;
1573+ uv1.CHAR = 'i';
1574+ u1.value = uv1;
1575+ Unit u2;
1576+ u2.type = UnitType::STRING;
1577+ UnitValue uv2;
1578+ uv2.CHAR = ' ';
1579+ u2.value = uv2;
1580 compareStyle(".notice-heading::before", {
1581- {"content", "\"i \""},
1582- }, handler.root.children[4].children[0],
1583- SheetType::STYLE
1584+ {KeyType::CONTENT, {u1,u2}},
1585+ }, style.children[4].children[0],
1586+ StyleType::STYLE
1587 );
1588 }
1589
1590 SECTION("parseCSS can parse a nested CSS rule with a &") {
1591+ UnitValue uv1;
1592+ uv1.UINT = 0xd81b60;
1593+ UnitValue uv2;
1594+ uv2.UINT = 0xffffff;
1595 compareStyle(".notice.warning", {
1596- {"background-color", "#d81b60"},
1597- {"border-color", "#d81b60"},
1598- {"color", "white"},
1599- }, handler.root.children[4].children[1],
1600- SheetType::STYLE
1601+ {KeyType::BACKGROUND_COLOR, {{UnitType::COLOR, uv1}}},
1602+ {KeyType::BORDER_COLOR, {{UnitType::COLOR, uv1}}},
1603+ {KeyType::COLOR, {{UnitType::COLOR, uv2}}},
1604+ }, style.children[4].children[1],
1605+ StyleType::STYLE
1606 );
1607 }
1608
1609-
1610-
1611 }
1612-
1613-TEST_CASE("parseCSS can parse multiple selectors nested") {
1614- std::string cssContent = R"~~~(
1615-div, .class1 {
1616- .class2 {
1617- background: red;
1618- }
1619- &.class3 {
1620- background: orange;
1621- }
1622-}
1623-)~~~";
1624-
1625- std::istringstream inputFile(cssContent);
1626-
1627- Window window;
1628- window.CSS.parseStream(inputFile);
1629-
1630- StyleHandler handler = window.CSS;
1631- SECTION("multi selector test") {
1632- // This is written kinda weird but it's correct because the CSS above compiles into:
1633- // div .class2 && .class1 .class2
1634- // So [0] should only be .class2 becuse if we are going through the tree the node has already matched on
1635- // div, .class1
1636- // Then the second case is different because we care about the order they are matched in due to &
1637- // So we fully compile the selector
1638- compareStyle(".class2", {
1639- {"background", "red"}
1640- }, handler.root.children[0].children[0],
1641- SheetType::STYLE
1642- );
1643- compareStyle("div.class3, .class1.class3", {
1644- {"background", "orange"}
1645- }, handler.root.children[0].children[1],
1646- SheetType::STYLE
1647- );
1648- }
1649-
1650-}
1651-
1652-
1653+/*
1654 TEST_CASE("parseCSSInline can parse inline styles") {
1655 SECTION("parseCSSInline can parse a single property with a ending ;") {
1656 std::string inlineStyles = "background: yellow;";
1657@@ -285,4 +312,4 @@ TEST_CASE("parseCSSInline can parse inline styles") {
1658 {"font-size", "10px"},
1659 });
1660 }
1661-}
1662+}*/
1663diff --git a/tests/css_selector.cc b/tests/css_selector.cc
1664index 669a079..518c553 100755
1665--- a/tests/css_selector.cc
1666+++ b/tests/css_selector.cc
1667@@ -77,7 +77,7 @@ TEST_CASE( "CSS Selection", "[css]" ) {
1668 };
1669 }
1670 SECTION("parseSelectorParts can parse a selector with a decendent combinator") {
1671- checkSelectorParts("div h1", {{"div", "h1"}});
1672+ checkSelectorParts("div h1", {{"div", " ", "h1"}});
1673 BENCHMARK("div h1") {
1674 return parseSelectorParts("div h1");
1675 };
1676@@ -110,7 +110,7 @@ TEST_CASE( "CSS Selection", "[css]" ) {
1677 checkSelectorParts("h1::before", {{"h1",":before"}});
1678 }
1679 }
1680-/*
1681+
1682 TEST_CASE("testSelector", "[CSS]") {
1683 std::string html = "<!DOCTYPE html>"
1684 "<html>"
1685@@ -142,57 +142,57 @@ TEST_CASE("testSelector", "[CSS]") {
1686
1687
1688 std::stringstream ss(html);
1689- std::unique_ptr<Node> document = parseHTML(ss);
1690+ Node document = parseHTML(ss);
1691
1692 SECTION("testSelector can match a element given it's tagName") {
1693- auto html = document->children[0].get();
1694+ auto html = document.children[0].get();
1695 REQUIRE(testSelector(html, parseSelectorParts("html")));
1696 REQUIRE_FALSE(testSelector(html, parseSelectorParts("h1")));
1697 }
1698 SECTION("testSelector can match a element by it's attributes only") {
1699- auto link = document->children[0]->children[0]->children[1].get();
1700+ auto link = document.children[0]->children[0]->children[1].get();
1701 REQUIRE(testSelector(link, parseSelectorParts("[rel=\"stylesheet\"]")));
1702 }
1703 SECTION("testSelector can match a element by it's attributes and tagName") {
1704- auto link = document->children[0]->children[0]->children[1].get();
1705+ auto link = document.children[0]->children[0]->children[1].get();
1706 REQUIRE(testSelector(link, parseSelectorParts("link[rel=\"stylesheet\"]")));
1707 REQUIRE_FALSE(testSelector(link, parseSelectorParts("title[rel=\"stylesheet\"]")));
1708 }
1709 SECTION("testSelector can match a element by it's id only") {
1710- auto h1 = document->children[0]->children[1]->children[0].get();
1711+ auto h1 = document.children[0]->children[1]->children[0].get();
1712 REQUIRE(testSelector(h1, parseSelectorParts("#h1Tag")));
1713 }
1714 SECTION("testSelector can match a element by it's id and tagName") {
1715- auto h1 = document->children[0]->children[1]->children[0].get();
1716+ auto h1 = document.children[0]->children[1]->children[0].get();
1717 REQUIRE(testSelector(h1, parseSelectorParts("h1#h1Tag")));
1718 }
1719 SECTION("testSelector can match a element by it's class and not matach on a non class") {
1720- auto p = document->children[0]->children[1]->children[1].get();
1721+ auto p = document.children[0]->children[1]->children[1].get();
1722 REQUIRE(testSelector(p, parseSelectorParts(".class1")));
1723 REQUIRE_FALSE(testSelector(p, parseSelectorParts(".class3")));
1724 }
1725 SECTION("testSelector can match a child combinator") {
1726- auto h1 = document->children[0]->children[1]->children[0].get();
1727+ auto h1 = document.children[0]->children[1]->children[0].get();
1728 REQUIRE(testSelector(h1, parseSelectorParts("body > h1")));
1729 REQUIRE_FALSE(testSelector(h1, parseSelectorParts("html > h1")));
1730 }
1731 SECTION("testSelector can match a next sibling combinator") {
1732- auto p = document->children[0]->children[1]->children[1].get();
1733+ auto p = document.children[0]->children[1]->children[1].get();
1734 REQUIRE(testSelector(p, parseSelectorParts("h1 + p")));
1735 REQUIRE_FALSE(testSelector(p, parseSelectorParts("h1 + div")));
1736 }
1737 SECTION("testSelector can match a descendant combinator") {
1738- auto p = document->children[0]->children[1]->children[1].get();
1739+ auto p = document.children[0]->children[1]->children[1].get();
1740 REQUIRE(testSelector(p, parseSelectorParts("body p")));
1741 REQUIRE_FALSE(testSelector(p, parseSelectorParts("h1 p")));
1742 }
1743 SECTION("testSelector can match a subsequent-sibling combinator") {
1744- auto p = document->children[0]->children[1]->children[1].get();
1745+ auto p = document.children[0]->children[1]->children[1].get();
1746 REQUIRE(testSelector(p, parseSelectorParts("h1 ~ p")));
1747 REQUIRE_FALSE(testSelector(p, parseSelectorParts("div ~ p")));
1748 }
1749 SECTION("testSelector can match a element with a pseudo class") {
1750- auto input = document->children[0]->children[1]->children[3].get();
1751+ auto input = document.children[0]->children[1]->children[3].get();
1752 // While not all pseudo classes are defined here, any that are defined
1753 // with a attribute will match: ie <input disabled>
1754 REQUIRE(testSelector(input, parseSelectorParts("input:required")));
1755@@ -200,33 +200,33 @@ TEST_CASE("testSelector", "[CSS]") {
1756 REQUIRE_FALSE(testSelector(input, parseSelectorParts("input:enabled")));
1757 }
1758 SECTION("testSelector can match a element with first-child") {
1759- auto h1 = document->children[0]->children[1]->children[0].get();
1760+ auto h1 = document.children[0]->children[1]->children[0].get();
1761 REQUIRE(testSelector(h1, parseSelectorParts(":first-child")));
1762 }
1763 SECTION("testSelector can match a element with first-of-type") {
1764- auto h1 = document->children[0]->children[1]->children[0].get();
1765+ auto h1 = document.children[0]->children[1]->children[0].get();
1766 REQUIRE(testSelector(h1, parseSelectorParts(":first-of-type")));
1767
1768- auto li = document->children[0]->children[1]->children[4]->children[0].get();
1769+ auto li = document.children[0]->children[1]->children[4]->children[0].get();
1770 REQUIRE(testSelector(li, parseSelectorParts(":first-of-type")));
1771 }
1772 SECTION("testSelector can match a element with last-child") {
1773- auto textarea = document->children[0]->children[1]->children[10].get();
1774+ auto textarea = document.children[0]->children[1]->children[10].get();
1775 REQUIRE(testSelector(textarea, parseSelectorParts(":last-child")));
1776 }
1777 SECTION("testSelector can match a element with last-of-type") {
1778- auto h1 = document->children[0]->children[1]->children[0].get();
1779+ auto h1 = document.children[0]->children[1]->children[0].get();
1780 // There is only one h1
1781 REQUIRE(testSelector(h1, parseSelectorParts(":last-of-type")));
1782
1783- auto li = document->children[0]->children[1]->children[4]->children[0].get();
1784+ auto li = document.children[0]->children[1]->children[4]->children[0].get();
1785 REQUIRE_FALSE(testSelector(li, parseSelectorParts(":last-of-type")));
1786
1787- li = document->children[0]->children[1]->children[4]->children[3].get();
1788+ li = document.children[0]->children[1]->children[4]->children[3].get();
1789 REQUIRE(testSelector(li, parseSelectorParts(":last-of-type")));
1790 }
1791 SECTION("testselector can match multiple selectors") {
1792- auto textarea = document->children[0]->children[1]->children[10].get();
1793+ auto textarea = document.children[0]->children[1]->children[10].get();
1794 // should only match on :last-child
1795 REQUIRE(testSelector(textarea, parseSelectorParts("h1, h1 ~p, :last-child")));
1796 REQUIRE_FALSE(testSelector(textarea, parseSelectorParts("h1, h1 ~p, :first-child")));
1797@@ -241,22 +241,22 @@ TEST_CASE("testSelector", "[CSS]") {
1798 };
1799 }
1800 SECTION("testSelector can match :is() selectors") {
1801- auto input = document->children[0]->children[1]->children[3].get();
1802+ auto input = document.children[0]->children[1]->children[3].get();
1803 REQUIRE(testSelector(input, parseSelectorParts(":is(h1, input, div)")));
1804 REQUIRE_FALSE(testSelector(input, parseSelectorParts(":is(h1, html, div)")));
1805 }
1806 SECTION("testSelector can match :where() selectors") {
1807- auto input = document->children[0]->children[1]->children[3].get();
1808+ auto input = document.children[0]->children[1]->children[3].get();
1809 REQUIRE(testSelector(input, parseSelectorParts(":where(h1, input, div)")));
1810 REQUIRE_FALSE(testSelector(input, parseSelectorParts(":where(h1, html, div)")));
1811 }
1812 SECTION("testSelector can match :not() selectors") {
1813- auto input = document->children[0]->children[1]->children[3].get();
1814+ auto input = document.children[0]->children[1]->children[3].get();
1815 REQUIRE(testSelector(input, parseSelectorParts(":not(h1, html, div)")));
1816 REQUIRE_FALSE(testSelector(input, parseSelectorParts(":not(h1, input, div)")));
1817 }
1818 SECTION("testSelector can match nested :not(:is()) selectors") {
1819- auto input = document->children[0]->children[1]->children[3].get();
1820+ auto input = document.children[0]->children[1]->children[3].get();
1821 REQUIRE(testSelector(input, parseSelectorParts(":not(:is(h1, html, div))")));
1822 REQUIRE_FALSE(testSelector(input, parseSelectorParts(":not(:is(h1, input, div))")));
1823
1824@@ -265,12 +265,12 @@ TEST_CASE("testSelector", "[CSS]") {
1825 };
1826 }
1827 SECTION("testSelector can match a :has() selector with a child combinator") {
1828- auto body = document->children[0]->children[1].get();
1829+ auto body = document.children[0]->children[1].get();
1830 REQUIRE(testSelector(body, parseSelectorParts("body:has(> h1)")));
1831 REQUIRE_FALSE(testSelector(body, parseSelectorParts("body:has(> h1:required)")));
1832 }
1833 SECTION("testSelector can match a :has() selector with a next-sibling combinator") {
1834- auto h1 = document->children[0]->children[1]->children[0].get();
1835+ auto h1 = document.children[0]->children[1]->children[0].get();
1836 REQUIRE(testSelector(h1, parseSelectorParts("h1:has(+ p)")));
1837 REQUIRE_FALSE(testSelector(h1, parseSelectorParts("h1:has(+ p:required)")));
1838
1839@@ -280,7 +280,7 @@ TEST_CASE("testSelector", "[CSS]") {
1840 };
1841 }
1842 SECTION("testSelector can match a :has() selector with a subsequent-sibling combinator") {
1843- auto h1 = document->children[0]->children[1]->children[0].get();
1844+ auto h1 = document.children[0]->children[1]->children[0].get();
1845 REQUIRE(testSelector(h1, parseSelectorParts("h1:has(~ input)")));
1846 REQUIRE_FALSE(testSelector(h1, parseSelectorParts("h1:has(~ p:required)")));
1847
1848@@ -291,7 +291,7 @@ TEST_CASE("testSelector", "[CSS]") {
1849 }
1850
1851 SECTION("testSelector can match a :has() selector with a decendent combinator") {
1852- auto html = document->children[0].get();
1853+ auto html = document.children[0].get();
1854 REQUIRE(testSelector(html, parseSelectorParts("html:has(input)")));
1855 REQUIRE_FALSE(testSelector(html, parseSelectorParts("html:has(p:required)")));
1856
1857@@ -302,7 +302,7 @@ TEST_CASE("testSelector", "[CSS]") {
1858 }
1859
1860 SECTION("testSelector can match a :is():has(:where()) selector") {
1861- auto html = document->children[0].get();
1862+ auto html = document.children[0].get();
1863 REQUIRE(testSelector(html, parseSelectorParts(":is(html, div, p):has(:where(html, input:checked, input))")));
1864 REQUIRE_FALSE(testSelector(html, parseSelectorParts(":is(body, div, p):has(:where(html, input:checked, input))")));
1865
1866@@ -314,14 +314,14 @@ TEST_CASE("testSelector", "[CSS]") {
1867 // |(d678a) Nth child selection |
1868 // +------------------------------------------------------+
1869 SECTION("testSelector can match a :nth-child(even|odd)") {
1870- auto li = document->children[0]->children[1]->children[4]->children[1].get();
1871+ auto li = document.children[0]->children[1]->children[4]->children[1].get();
1872 REQUIRE(testSelector(li, parseSelectorParts(":nth-child(even)")));
1873 REQUIRE(testSelector(li, parseSelectorParts("li:nth-child(even)")));
1874 REQUIRE_FALSE(testSelector(li, parseSelectorParts("li:nth-child(odd)")));
1875 }
1876
1877 SECTION("testSelector can match a :nth-child(A)") {
1878- auto li = document->children[0]->children[1]->children[4]->children[1].get();
1879+ auto li = document.children[0]->children[1]->children[4]->children[1].get();
1880 REQUIRE(testSelector(li, parseSelectorParts(":nth-child(2)")));
1881 REQUIRE(testSelector(li, parseSelectorParts("li:nth-child(2)")));
1882 REQUIRE_FALSE(testSelector(li, parseSelectorParts("li:nth-child(1)")));
1883@@ -332,7 +332,7 @@ TEST_CASE("testSelector", "[CSS]") {
1884 }
1885
1886 SECTION("testSelector can match a :nth-child(An)") {
1887- auto li = document->children[0]->children[1]->children[4]->children[1].get();
1888+ auto li = document.children[0]->children[1]->children[4]->children[1].get();
1889 REQUIRE(testSelector(li, parseSelectorParts(":nth-child(2n)")));
1890 REQUIRE(testSelector(li, parseSelectorParts("li:nth-child(2n)")));
1891 REQUIRE_FALSE(testSelector(li, parseSelectorParts("li:nth-child(3n)")));
1892@@ -343,7 +343,7 @@ TEST_CASE("testSelector", "[CSS]") {
1893 }
1894
1895 SECTION("testSelector can match a :nth-child(An+B)") {
1896- auto li = document->children[0]->children[1]->children[4]->children[2].get();
1897+ auto li = document.children[0]->children[1]->children[4]->children[2].get();
1898 REQUIRE(testSelector(li, parseSelectorParts(":nth-child(2n+1)")));
1899 REQUIRE(testSelector(li, parseSelectorParts("li:nth-child(2n+1)")));
1900 REQUIRE_FALSE(testSelector(li, parseSelectorParts("li:nth-child(3n+1)")));
1901@@ -354,7 +354,7 @@ TEST_CASE("testSelector", "[CSS]") {
1902 }
1903
1904 SECTION("testSelector can match a :nth-child(n+B)") {
1905- auto li = document->children[0]->children[1]->children[4]->children[0].get();
1906+ auto li = document.children[0]->children[1]->children[4]->children[0].get();
1907 REQUIRE(testSelector(li, parseSelectorParts(":nth-child(n+1)")));
1908 REQUIRE(testSelector(li, parseSelectorParts("li:nth-child(n-3)")));
1909 REQUIRE_FALSE(testSelector(li, parseSelectorParts("li:nth-child(n+2)")));
1910@@ -365,14 +365,14 @@ TEST_CASE("testSelector", "[CSS]") {
1911 }
1912
1913 SECTION("testSelector can match a :nth-child(An+B of type)") {
1914- auto li = document->children[0]->children[1]->children[4]->children[2].get();
1915+ auto li = document.children[0]->children[1]->children[4]->children[2].get();
1916 REQUIRE(testSelector(li, parseSelectorParts(":nth-child(2n+1 of li)")));
1917 REQUIRE_FALSE(testSelector(li, parseSelectorParts(":nth-child(2n+1 of ul)")));
1918 REQUIRE_FALSE(testSelector(li, parseSelectorParts(":nth-child(3n+1 of li)")));
1919 }
1920
1921 SECTION("testSelector can match a :nth-child(A of type)") {
1922- auto li = document->children[0]->children[1]->children[4]->children[1].get();
1923+ auto li = document.children[0]->children[1]->children[4]->children[1].get();
1924 REQUIRE(testSelector(li, parseSelectorParts(":nth-child(2 of li)")));
1925 REQUIRE(testSelector(li, parseSelectorParts("li:nth-child(2 of li)")));
1926 REQUIRE_FALSE(testSelector(li, parseSelectorParts("li:nth-child(2 of ul)")));
1927@@ -383,7 +383,7 @@ TEST_CASE("testSelector", "[CSS]") {
1928 }
1929
1930 SECTION("testSelector can match a :nth-child(An of type)") {
1931- auto li = document->children[0]->children[1]->children[4]->children[1].get();
1932+ auto li = document.children[0]->children[1]->children[4]->children[1].get();
1933 REQUIRE(testSelector(li, parseSelectorParts(":nth-child(2n of li)")));
1934 REQUIRE(testSelector(li, parseSelectorParts("li:nth-child(2n of li)")));
1935 REQUIRE_FALSE(testSelector(li, parseSelectorParts("li:nth-child(2n of ul)")));
1936@@ -394,7 +394,7 @@ TEST_CASE("testSelector", "[CSS]") {
1937 }
1938
1939 SECTION("testSelector can match a :nth-child(n+B of type)") {
1940- auto li = document->children[0]->children[1]->children[4]->children[0].get();
1941+ auto li = document.children[0]->children[1]->children[4]->children[0].get();
1942 REQUIRE(testSelector(li, parseSelectorParts(":nth-child(n+1 of li)")));
1943 REQUIRE(testSelector(li, parseSelectorParts("li:nth-child(n-3 of li)")));
1944 REQUIRE_FALSE(testSelector(li, parseSelectorParts("li:nth-child(n+1 of ul)")));
1945@@ -407,14 +407,14 @@ TEST_CASE("testSelector", "[CSS]") {
1946 // |Nth last child |
1947 // +------------------------------------------------------+
1948 SECTION("testSelector can match a :nth-last-child(even|odd)") {
1949- auto li = document->children[0]->children[1]->children[4]->children[3].get();
1950+ auto li = document.children[0]->children[1]->children[4]->children[3].get();
1951 REQUIRE(testSelector(li, parseSelectorParts(":nth-last-child(even)")));
1952 REQUIRE(testSelector(li, parseSelectorParts("li:nth-last-child(even)")));
1953 REQUIRE_FALSE(testSelector(li, parseSelectorParts("li:nth-last-child(odd)")));
1954 }
1955
1956 SECTION("testSelector can match a :nth-last-child(A)") {
1957- auto li = document->children[0]->children[1]->children[4]->children[2].get();
1958+ auto li = document.children[0]->children[1]->children[4]->children[2].get();
1959 REQUIRE(testSelector(li, parseSelectorParts(":nth-last-child(2)")));
1960 REQUIRE(testSelector(li, parseSelectorParts("li:nth-last-child(2)")));
1961 REQUIRE_FALSE(testSelector(li, parseSelectorParts("li:nth-last-child(1)")));
1962@@ -425,7 +425,7 @@ TEST_CASE("testSelector", "[CSS]") {
1963 }
1964
1965 SECTION("testSelector can match a :nth-last-child(An)") {
1966- auto li = document->children[0]->children[1]->children[4]->children[2].get();
1967+ auto li = document.children[0]->children[1]->children[4]->children[2].get();
1968 REQUIRE(testSelector(li, parseSelectorParts(":nth-last-child(2n)")));
1969 REQUIRE(testSelector(li, parseSelectorParts("li:nth-last-child(2n)")));
1970 REQUIRE_FALSE(testSelector(li, parseSelectorParts("li:nth-last-child(3n)")));
1971@@ -436,7 +436,7 @@ TEST_CASE("testSelector", "[CSS]") {
1972 }
1973
1974 SECTION("testSelector can match a :nth-last-child(An+B)") {
1975- auto li = document->children[0]->children[1]->children[4]->children[1].get();
1976+ auto li = document.children[0]->children[1]->children[4]->children[1].get();
1977 REQUIRE(testSelector(li, parseSelectorParts(":nth-last-child(2n+1)")));
1978 REQUIRE(testSelector(li, parseSelectorParts("li:nth-last-child(2n+1)")));
1979 REQUIRE_FALSE(testSelector(li, parseSelectorParts("li:nth-last-child(3n+1)")));
1980@@ -447,7 +447,7 @@ TEST_CASE("testSelector", "[CSS]") {
1981 }
1982
1983 SECTION("testSelector can match a :nth-last-child(n+B)") {
1984- auto li = document->children[0]->children[1]->children[4]->children[3].get();
1985+ auto li = document.children[0]->children[1]->children[4]->children[3].get();
1986 REQUIRE(testSelector(li, parseSelectorParts(":nth-last-child(n+1)")));
1987 REQUIRE(testSelector(li, parseSelectorParts("li:nth-last-child(n-3)")));
1988 REQUIRE_FALSE(testSelector(li, parseSelectorParts("li:nth-last-child(n+2)")));
1989@@ -458,14 +458,14 @@ TEST_CASE("testSelector", "[CSS]") {
1990 }
1991
1992 SECTION("testSelector can match a :nth-last-child(An+B of type)") {
1993- auto li = document->children[0]->children[1]->children[4]->children[1].get();
1994+ auto li = document.children[0]->children[1]->children[4]->children[1].get();
1995 REQUIRE(testSelector(li, parseSelectorParts(":nth-last-child(2n+1 of li)")));
1996 REQUIRE_FALSE(testSelector(li, parseSelectorParts(":nth-last-child(2n+1 of ul)")));
1997 REQUIRE_FALSE(testSelector(li, parseSelectorParts(":nth-last-child(3n+1 of li)")));
1998 }
1999
2000 SECTION("testSelector can match a :nth-last-child(A of type)") {
2001- auto li = document->children[0]->children[1]->children[4]->children[2].get();
2002+ auto li = document.children[0]->children[1]->children[4]->children[2].get();
2003 REQUIRE(testSelector(li, parseSelectorParts(":nth-last-child(2 of li)")));
2004 REQUIRE(testSelector(li, parseSelectorParts("li:nth-last-child(2 of li)")));
2005 REQUIRE_FALSE(testSelector(li, parseSelectorParts("li:nth-last-child(2 of ul)")));
2006@@ -476,7 +476,7 @@ TEST_CASE("testSelector", "[CSS]") {
2007 }
2008
2009 SECTION("testSelector can match a :nth-last-child(An of type)") {
2010- auto li = document->children[0]->children[1]->children[4]->children[2].get();
2011+ auto li = document.children[0]->children[1]->children[4]->children[2].get();
2012 REQUIRE(testSelector(li, parseSelectorParts(":nth-last-child(2n of li)")));
2013 REQUIRE(testSelector(li, parseSelectorParts("li:nth-last-child(2n of li)")));
2014 REQUIRE_FALSE(testSelector(li, parseSelectorParts("li:nth-last-child(2n of ul)")));
2015@@ -487,7 +487,7 @@ TEST_CASE("testSelector", "[CSS]") {
2016 }
2017
2018 SECTION("testSelector can match a :nth-last-child(n+B of type)") {
2019- auto li = document->children[0]->children[1]->children[4]->children[3].get();
2020+ auto li = document.children[0]->children[1]->children[4]->children[3].get();
2021 REQUIRE(testSelector(li, parseSelectorParts(":nth-last-child(n+1 of li)")));
2022 REQUIRE(testSelector(li, parseSelectorParts("li:nth-last-child(n-3 of li)")));
2023 REQUIRE_FALSE(testSelector(li, parseSelectorParts("li:nth-last-child(n+1 of ul)")));
2024@@ -500,14 +500,14 @@ TEST_CASE("testSelector", "[CSS]") {
2025 // |Nth last of type |
2026 // +------------------------------------------------------+
2027 SECTION("testSelector can match a :nth-last-of-type(even|odd)") {
2028- auto li = document->children[0]->children[1]->children[4]->children[3].get();
2029+ auto li = document.children[0]->children[1]->children[4]->children[3].get();
2030 REQUIRE(testSelector(li, parseSelectorParts(":nth-last-of-type(even)")));
2031 REQUIRE(testSelector(li, parseSelectorParts("li:nth-last-of-type(even)")));
2032 REQUIRE_FALSE(testSelector(li, parseSelectorParts("li:nth-last-of-type(odd)")));
2033 }
2034
2035 SECTION("testSelector can match a :nth-last-of-type(A)") {
2036- auto li = document->children[0]->children[1]->children[4]->children[2].get();
2037+ auto li = document.children[0]->children[1]->children[4]->children[2].get();
2038 REQUIRE(testSelector(li, parseSelectorParts(":nth-last-of-type(2)")));
2039 REQUIRE(testSelector(li, parseSelectorParts("li:nth-last-of-type(2)")));
2040 REQUIRE_FALSE(testSelector(li, parseSelectorParts("li:nth-last-of-type(1)")));
2041@@ -518,7 +518,7 @@ TEST_CASE("testSelector", "[CSS]") {
2042 }
2043
2044 SECTION("testSelector can match a :nth-last-of-type(An)") {
2045- auto li = document->children[0]->children[1]->children[4]->children[2].get();
2046+ auto li = document.children[0]->children[1]->children[4]->children[2].get();
2047 REQUIRE(testSelector(li, parseSelectorParts(":nth-last-of-type(2n)")));
2048 REQUIRE(testSelector(li, parseSelectorParts("li:nth-last-of-type(2n)")));
2049 REQUIRE_FALSE(testSelector(li, parseSelectorParts("li:nth-last-of-type(3n)")));
2050@@ -529,7 +529,7 @@ TEST_CASE("testSelector", "[CSS]") {
2051 }
2052
2053 SECTION("testSelector can match a :nth-last-of-type(An+B)") {
2054- auto li = document->children[0]->children[1]->children[4]->children[1].get();
2055+ auto li = document.children[0]->children[1]->children[4]->children[1].get();
2056 REQUIRE(testSelector(li, parseSelectorParts(":nth-last-of-type(2n+1)")));
2057 REQUIRE(testSelector(li, parseSelectorParts("li:nth-last-of-type(2n+1)")));
2058 REQUIRE_FALSE(testSelector(li, parseSelectorParts("li:nth-last-of-type(3n+1)")));
2059@@ -540,7 +540,7 @@ TEST_CASE("testSelector", "[CSS]") {
2060 }
2061
2062 SECTION("testSelector can match a :nth-last-of-type(n+B)") {
2063- auto li = document->children[0]->children[1]->children[4]->children[3].get();
2064+ auto li = document.children[0]->children[1]->children[4]->children[3].get();
2065 REQUIRE(testSelector(li, parseSelectorParts(":nth-last-of-type(n+1)")));
2066 REQUIRE(testSelector(li, parseSelectorParts("li:nth-last-of-type(n-3)")));
2067 REQUIRE_FALSE(testSelector(li, parseSelectorParts("li:nth-last-of-type(n+2)")));
2068@@ -555,14 +555,14 @@ TEST_CASE("testSelector", "[CSS]") {
2069 // +------------------------------------------------------+
2070
2071 SECTION("testSelector can match a :nth-of-type(even|odd)") {
2072- auto li = document->children[0]->children[1]->children[4]->children[1].get();
2073+ auto li = document.children[0]->children[1]->children[4]->children[1].get();
2074 REQUIRE(testSelector(li, parseSelectorParts(":nth-of-type(even)")));
2075 REQUIRE(testSelector(li, parseSelectorParts("li:nth-of-type(even)")));
2076 REQUIRE_FALSE(testSelector(li, parseSelectorParts("li:nth-of-type(odd)")));
2077 }
2078
2079 SECTION("testSelector can match a :nth-of-type(A)") {
2080- auto li = document->children[0]->children[1]->children[4]->children[1].get();
2081+ auto li = document.children[0]->children[1]->children[4]->children[1].get();
2082 REQUIRE(testSelector(li, parseSelectorParts(":nth-of-type(2)")));
2083 REQUIRE(testSelector(li, parseSelectorParts("li:nth-of-type(2)")));
2084 REQUIRE_FALSE(testSelector(li, parseSelectorParts("li:nth-of-type(1)")));
2085@@ -573,7 +573,7 @@ TEST_CASE("testSelector", "[CSS]") {
2086 }
2087
2088 SECTION("testSelector can match a :nth-of-type(An)") {
2089- auto li = document->children[0]->children[1]->children[4]->children[1].get();
2090+ auto li = document.children[0]->children[1]->children[4]->children[1].get();
2091 REQUIRE(testSelector(li, parseSelectorParts(":nth-of-type(2n)")));
2092 REQUIRE(testSelector(li, parseSelectorParts("li:nth-of-type(2n)")));
2093 REQUIRE_FALSE(testSelector(li, parseSelectorParts("li:nth-of-type(3n)")));
2094@@ -584,7 +584,7 @@ TEST_CASE("testSelector", "[CSS]") {
2095 }
2096
2097 SECTION("testSelector can match a :nth-of-type(An+B)") {
2098- auto li = document->children[0]->children[1]->children[4]->children[2].get();
2099+ auto li = document.children[0]->children[1]->children[4]->children[2].get();
2100 REQUIRE(testSelector(li, parseSelectorParts(":nth-of-type(2n+1)")));
2101 REQUIRE(testSelector(li, parseSelectorParts("li:nth-of-type(2n+1)")));
2102 REQUIRE_FALSE(testSelector(li, parseSelectorParts("li:nth-of-type(3n+1)")));
2103@@ -595,7 +595,7 @@ TEST_CASE("testSelector", "[CSS]") {
2104 }
2105
2106 SECTION("testSelector can match a :nth-of-type(n+B)") {
2107- auto li = document->children[0]->children[1]->children[4]->children[0].get();
2108+ auto li = document.children[0]->children[1]->children[4]->children[0].get();
2109 REQUIRE(testSelector(li, parseSelectorParts(":nth-of-type(n+1)")));
2110 REQUIRE(testSelector(li, parseSelectorParts("li:nth-of-type(n-3)")));
2111 REQUIRE_FALSE(testSelector(li, parseSelectorParts("li:nth-of-type(n+2)")));
2112@@ -608,26 +608,26 @@ TEST_CASE("testSelector", "[CSS]") {
2113 // | Only child |
2114 // +------------------------------------------------------+
2115 SECTION("testselector can match :only-child") {
2116- auto p = document->children[0]->children[1]->children[2]->children[0].get();
2117+ auto p = document.children[0]->children[1]->children[2]->children[0].get();
2118
2119 REQUIRE(testSelector(p, parseSelectorParts(":only-child")));
2120 }
2121
2122 SECTION("testselector can match :only-of-type") {
2123- auto h1 = document->children[0]->children[1]->children[0].get();
2124+ auto h1 = document.children[0]->children[1]->children[0].get();
2125
2126 REQUIRE(testSelector(h1, parseSelectorParts(":only-of-type")));
2127 }
2128
2129 SECTION("testSelector can match :root") {
2130- auto html = document->children[0].get();
2131+ auto html = document.children[0].get();
2132 REQUIRE(testSelector(html, parseSelectorParts(":root")));
2133 }
2134
2135 // +------------------------------------------------------+
2136 // | Input checkes |
2137 // +------------------------------------------------------+
2138- "<body>"
2139+/* "<body>"
2140 "<h1 id=\"h1Tag\">Header</h1>"
2141 "<p id=\"paragraph\" class=\"class1 class2\">This is some text for a simple test</p>"
2142 "<div contenteditable=\"true\">"
2143@@ -647,55 +647,54 @@ TEST_CASE("testSelector", "[CSS]") {
2144 "<textarea readonly></textarea>"
2145 "<textarea disabled></textarea>"
2146 "</body>"
2147-
2148+*/
2149 SECTION("testSelector can match :read-only normal element") {
2150- auto p = document->children[0]->children[1]->children[1].get();
2151+ auto p = document.children[0]->children[1]->children[1].get();
2152 REQUIRE(testSelector(p, parseSelectorParts("p:read-only")));
2153 }
2154 SECTION("testSelector can match :read-write on a text input") {
2155- auto input = document->children[0]->children[1]->children[3].get();
2156+ auto input = document.children[0]->children[1]->children[3].get();
2157 REQUIRE(testSelector(input, parseSelectorParts("input[type=\"text\"]:read-write")));
2158 }
2159 SECTION("testSelector can match :read-only on a radio input") {
2160- auto input = document->children[0]->children[1]->children[5].get();
2161+ auto input = document.children[0]->children[1]->children[5].get();
2162 REQUIRE(testSelector(input, parseSelectorParts("input[type=\"radio\"]:read-only")));
2163 REQUIRE_FALSE(testSelector(input, parseSelectorParts("input[type=\"radio\"]:read-write")));
2164 }
2165 SECTION("testSelector can match :read-only on a readonly text input") {
2166- auto input = document->children[0]->children[1]->children[6].get();
2167+ auto input = document.children[0]->children[1]->children[6].get();
2168 REQUIRE(testSelector(input, parseSelectorParts("input[type=\"text\"]:read-only")));
2169 }
2170 SECTION("testSelector can match :read-only on a disabled text input") {
2171- auto input = document->children[0]->children[1]->children[7].get();
2172+ auto input = document.children[0]->children[1]->children[7].get();
2173 REQUIRE(testSelector(input, parseSelectorParts("input[type=\"text\"]:read-only")));
2174 REQUIRE(testSelector(input, parseSelectorParts("input[type=\"text\"]:disabled")));
2175 }
2176 SECTION("testSelector can match :read-write on a textarea") {
2177- auto textarea = document->children[0]->children[1]->children[8].get();
2178+ auto textarea = document.children[0]->children[1]->children[8].get();
2179 REQUIRE(testSelector(textarea, parseSelectorParts(":read-write")));
2180 }
2181 SECTION("testSelector can match :read-only on a readonly textarea") {
2182- auto textarea = document->children[0]->children[1]->children[9].get();
2183+ auto textarea = document.children[0]->children[1]->children[9].get();
2184 REQUIRE(testSelector(textarea, parseSelectorParts(":read-only")));
2185 }
2186 SECTION("testSelector can match :read-only on a disabled textarea") {
2187- auto textarea = document->children[0]->children[1]->children[10].get();
2188+ auto textarea = document.children[0]->children[1]->children[10].get();
2189 REQUIRE(testSelector(textarea, parseSelectorParts(":read-only")));
2190 }
2191 SECTION("testSelector can match :read-write on a contenteditable div") {
2192- auto div = document->children[0]->children[1]->children[2].get();
2193+ auto div = document.children[0]->children[1]->children[2].get();
2194 REQUIRE(testSelector(div, parseSelectorParts(":read-write")));
2195 }
2196 // +------------------------------------------------------+
2197 // | Universal selector |
2198 // +------------------------------------------------------+
2199 SECTION("testSelector can match a universal selector") {
2200- auto div = document->children[0]->children[1]->children[2].get();
2201+ auto div = document.children[0]->children[1]->children[2].get();
2202 REQUIRE(testSelector(div, parseSelectorParts("*")));
2203 REQUIRE(testSelector(div, parseSelectorParts("h1, *")));
2204 }
2205 // make for:
2206 // pseudo elements
2207- // *
2208 }
2209-*/
2210+