summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Williamson <mike@zwobble.org>2024-02-17 13:36:21 +0000
committerMichael Williamson <mike@zwobble.org>2024-02-17 13:36:21 +0000
commit2ab691683d81b1481f68d19295f6ba86f02fdd3a (patch)
treed903cda7ea366883a727eb521eecb02a9587a873
parent318145ae7e4cdc02e418f25032159fa40cd47a19 (diff)
Support attributes in HTML paths in style mappings
-rw-r--r--NEWS4
-rw-r--r--README.md6
-rw-r--r--lib/style-reader.js48
-rw-r--r--test/style-reader.tests.js14
4 files changed, 60 insertions, 12 deletions
diff --git a/NEWS b/NEWS
index 9fc29b3..70baaf5 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,7 @@
+# 1.7.0
+
+* Support attributes in HTML paths in style mappings.
+
# 1.6.0
* Add transformDocument to the TypeScript declarations.
diff --git a/README.md b/README.md
index b167336..7144c72 100644
--- a/README.md
+++ b/README.md
@@ -805,6 +805,12 @@ append a dot followed by the name of the class:
h1.section-title
```
+To add an attribute, use square brackets similarly to a CSS attribute selector:
+
+```
+p[lang="fr"]
+```
+
To require that an element is fresh, use `:fresh`:
```
diff --git a/lib/style-reader.js b/lib/style-reader.js
index 07521ad..38202f9 100644
--- a/lib/style-reader.js
+++ b/lib/style-reader.js
@@ -57,12 +57,13 @@ function documentMatcherRule() {
runRule
);
- var styleIdRule = lop.rules.then(
- classRule,
- function(styleId) {
- return {styleId: styleId};
- }
- );
+ var styleIdRule = lop.rules.sequence(
+ lop.rules.tokenOfType("dot"),
+ lop.rules.sequence.cut(),
+ lop.rules.sequence.capture(identifierRule)
+ ).map(function(styleId) {
+ return {styleId: styleId};
+ });
var styleNameMatcherRule = lop.rules.firstOf("style name matcher",
lop.rules.then(
@@ -234,15 +235,19 @@ function htmlPathRule() {
var styleElementRule = lop.rules.sequence(
capture(tagNamesRule),
- capture(lop.rules.zeroOrMore(classRule)),
+ capture(lop.rules.zeroOrMore(attributeOrClassRule)),
capture(freshRule),
capture(separatorRule)
- ).map(function(tagName, classNames, fresh, separator) {
+ ).map(function(tagName, attributesList, fresh, separator) {
var attributes = {};
var options = {};
- if (classNames.length > 0) {
- attributes["class"] = classNames.join(" ");
- }
+ attributesList.forEach(function(attribute) {
+ if (attribute.append && attributes[attribute.name]) {
+ attributes[attribute.name] += " " + attribute.value;
+ } else {
+ attributes[attribute.name] = attribute.value;
+ }
+ });
if (fresh) {
options.fresh = true;
}
@@ -293,11 +298,30 @@ function decodeEscapeSequences(value) {
});
}
+var attributeRule = lop.rules.sequence(
+ lop.rules.tokenOfType("open-square-bracket"),
+ lop.rules.sequence.cut(),
+ lop.rules.sequence.capture(identifierRule),
+ lop.rules.tokenOfType("equals"),
+ lop.rules.sequence.capture(stringRule),
+ lop.rules.tokenOfType("close-square-bracket")
+).map(function(name, value) {
+ return {name: name, value: value, append: false};
+});
+
var classRule = lop.rules.sequence(
lop.rules.tokenOfType("dot"),
lop.rules.sequence.cut(),
lop.rules.sequence.capture(identifierRule)
-).head();
+).map(function(className) {
+ return {name: "class", value: className, append: true};
+});
+
+var attributeOrClassRule = lop.rules.firstOf(
+ "attribute or class",
+ attributeRule,
+ classRule
+);
function parseString(rule, string) {
var tokens = tokenise(string);
diff --git a/test/style-reader.tests.js b/test/style-reader.tests.js
index b77ce7e..93ddc79 100644
--- a/test/style-reader.tests.js
+++ b/test/style-reader.tests.js
@@ -54,6 +54,20 @@ test('styleReader.readHtmlPath', {
assertHtmlPath("p.tip.help", expected);
},
+ 'reads attribute on element': function() {
+ var expected = htmlPaths.elements([
+ htmlPaths.element("p", {"lang": "fr"})
+ ]);
+ assertHtmlPath("p[lang='fr']", expected);
+ },
+
+ 'reads multiple attributes on element': function() {
+ var expected = htmlPaths.elements([
+ htmlPaths.element("p", {"lang": "fr", "data-x": "y"})
+ ]);
+ assertHtmlPath("p[lang='fr'][data-x='y']", expected);
+ },
+
'reads when element must be fresh': function() {
var expected = htmlPaths.elements([
htmlPaths.element("p", {}, {"fresh": true})