hyper-html-api 0.12.0 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/README.md +4 -1
  2. package/conformance/MANIFEST.json +2 -2
  3. package/conformance/cases/all-matches-read-quoted.expected.json +3 -0
  4. package/conformance/cases/all-matches-read-quoted.html +5 -0
  5. package/conformance/cases/all-matches-read-quoted.meta +7 -0
  6. package/conformance/cases/all-matches-read-quoted.parsed.json +3 -0
  7. package/conformance/cases/all-matches-read.expected.json +3 -0
  8. package/conformance/cases/all-matches-read.html +6 -0
  9. package/conformance/cases/all-matches-read.meta +7 -0
  10. package/conformance/cases/all-matches-read.parsed.json +3 -0
  11. package/conformance/cases/stylevar-read.expected.json +12 -0
  12. package/conformance/cases/stylevar-read.html +7 -0
  13. package/conformance/cases/stylevar-read.meta +6 -0
  14. package/conformance/cases/stylevar-read.parsed.json +12 -0
  15. package/conformance/cases/stylevar-read.rules +1 -0
  16. package/conformance/cases/write-all-matches-attr.after.html +1 -0
  17. package/conformance/cases/write-all-matches-attr.after.json +3 -0
  18. package/conformance/cases/write-all-matches-attr.data.json +1 -0
  19. package/conformance/cases/write-all-matches-attr.html +1 -0
  20. package/conformance/cases/write-all-matches-attr.meta +6 -0
  21. package/conformance/cases/write-all-matches-attr.write.json +4 -0
  22. package/conformance/cases/write-all-matches-group.after.html +1 -0
  23. package/conformance/cases/write-all-matches-group.after.json +3 -0
  24. package/conformance/cases/write-all-matches-group.data.json +1 -0
  25. package/conformance/cases/write-all-matches-group.html +1 -0
  26. package/conformance/cases/write-all-matches-group.meta +6 -0
  27. package/conformance/cases/write-all-matches-group.write.json +4 -0
  28. package/conformance/cases/write-all-matches-text.after.html +1 -0
  29. package/conformance/cases/write-all-matches-text.after.json +3 -0
  30. package/conformance/cases/write-all-matches-text.data.json +1 -0
  31. package/conformance/cases/write-all-matches-text.html +1 -0
  32. package/conformance/cases/write-all-matches-text.meta +6 -0
  33. package/conformance/cases/write-all-matches-text.write.json +4 -0
  34. package/conformance/cases/write-all-matches-unmatched.data.json +1 -0
  35. package/conformance/cases/write-all-matches-unmatched.error.json +14 -0
  36. package/conformance/cases/write-all-matches-unmatched.html +1 -0
  37. package/conformance/cases/write-all-matches-unmatched.meta +6 -0
  38. package/conformance/cases/write-refused-raw-style.data.json +1 -0
  39. package/conformance/cases/write-refused-raw-style.error.json +11 -0
  40. package/conformance/cases/write-refused-raw-style.html +1 -0
  41. package/conformance/cases/write-refused-raw-style.meta +4 -0
  42. package/conformance/cases/write-refused-stylevar-values.data.json +1 -0
  43. package/conformance/cases/write-refused-stylevar-values.error.json +43 -0
  44. package/conformance/cases/write-refused-stylevar-values.html +1 -0
  45. package/conformance/cases/write-refused-stylevar-values.meta +5 -0
  46. package/conformance/cases/write-stylevar-clear.after.html +1 -0
  47. package/conformance/cases/write-stylevar-clear.after.json +4 -0
  48. package/conformance/cases/write-stylevar-clear.data.json +1 -0
  49. package/conformance/cases/write-stylevar-clear.html +1 -0
  50. package/conformance/cases/write-stylevar-clear.meta +5 -0
  51. package/conformance/cases/write-stylevar-clear.write.json +4 -0
  52. package/conformance/cases/write-stylevar-set.after.html +2 -0
  53. package/conformance/cases/write-stylevar-set.after.json +5 -0
  54. package/conformance/cases/write-stylevar-set.data.json +1 -0
  55. package/conformance/cases/write-stylevar-set.html +1 -0
  56. package/conformance/cases/write-stylevar-set.meta +6 -0
  57. package/conformance/cases/write-stylevar-set.write.json +4 -0
  58. package/conformance/cases/write-stylevar-unchanged.after.html +1 -0
  59. package/conformance/cases/write-stylevar-unchanged.after.json +3 -0
  60. package/conformance/cases/write-stylevar-unchanged.data.json +1 -0
  61. package/conformance/cases/write-stylevar-unchanged.html +1 -0
  62. package/conformance/cases/write-stylevar-unchanged.meta +5 -0
  63. package/conformance/cases/write-stylevar-unchanged.write.json +4 -0
  64. package/conformance/write-policy.json +23 -1
  65. package/dist/hyper-html-api.engine.esm.js +1 -1
  66. package/dist/hyper-html-api.engine.min.js +1 -1
  67. package/dist/hyper-html-api.min.js +8 -8
  68. package/dist/hyper-html-api.upgrade.min.js +2 -2
  69. package/package.json +4 -3
  70. package/src/engine/apply.js +22 -7
  71. package/src/engine/extract.js +8 -3
  72. package/src/engine/index.js +2 -1
  73. package/src/engine/round-trip.js +14 -1
  74. package/src/engine/rule-syntax.js +13 -3
  75. package/src/engine/style-vars.js +141 -0
  76. package/src/engine/write-plan.js +2 -3
  77. package/src/engine/write-policy.js +60 -0
  78. package/src/page.js +15 -5
  79. package/src/site.js +164 -0
  80. package/src/upgrade/migrate.js +2 -1
  81. package/src/upgrade/run.js +30 -0
  82. package/src/upgrade/shape-match.js +32 -13
  83. package/src/write.js +1 -1
package/README.md CHANGED
@@ -91,7 +91,10 @@ HyperHtmlApi.upgrade.run({ sourceUrl?, dataByName?, fromVersion? })
91
91
 
92
92
  The join is name-match per rules tag: fields present in both carry over, fields
93
93
  only in the old data are discarded (and counted in `summary`), fields only in
94
- the new template keep its defaults, and list counts follow the old data. For
94
+ the new template keep its defaults, and list counts follow the old data. A list
95
+ item is the exception to defaults: it is the owner's own row, so a field the new
96
+ template adds inside a list item starts empty (a list starts with no items)
97
+ instead of taking the value of the template's sample item. For
95
98
  richer migrations (renames, splits, computed fields) the source declares a
96
99
  transform as a non-executing script tag in its own HTML:
97
100
 
@@ -1,6 +1,6 @@
1
1
  {
2
- "engine": "0.11.2",
2
+ "engine": "0.13.0",
3
3
  "cheerio": "1.2.0",
4
- "cases": 77,
4
+ "cases": 89,
5
5
  "note": "Versions the expectations were generated against. Parity means parity with THIS pair; regenerate deliberately, never as a side effect of an install."
6
6
  }
@@ -0,0 +1,3 @@
1
+ {
2
+ "name": "Hyper"
3
+ }
@@ -0,0 +1,5 @@
1
+ <!doctype html><html><body>
2
+ <header><span class="site-name">Hyper</span></header>
3
+ <footer><span class="site-name">Old Hyper</span></footer>
4
+ <script data-rules-name="api" data-rules-version="1">{"name": "span.site-name[*]"}</script>
5
+ </body></html>
@@ -0,0 +1,7 @@
1
+ tier: 1
2
+ face: tag
3
+ token: api
4
+ expect: ok
5
+ skip: htmlclay=all-matches form not ported yet (multi-page sites release 1, step G1)
6
+ note: The [*] marker is not a quote-level token: a strict JSON quoted rule value lands on the
7
+ note: same parse tree as the relaxed unquoted spelling in all-matches-read.
@@ -0,0 +1,3 @@
1
+ {
2
+ "name": "span.site-name[*]"
3
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "name": "Hyper"
3
+ }
@@ -0,0 +1,6 @@
1
+ <!doctype html><html><body>
2
+ <header><span class="site-name">Hyper</span></header>
3
+ <main><h1>Hello</h1></main>
4
+ <footer><span class="site-name">Old Hyper</span></footer>
5
+ <script data-rules-name="api" data-rules-version="1">{name:"span.site-name[*]"}</script>
6
+ </body></html>
@@ -0,0 +1,7 @@
1
+ tier: 1
2
+ face: tag
3
+ token: api
4
+ expect: ok
5
+ skip: htmlclay=all-matches form not ported yet (multi-page sites release 1, step G1)
6
+ note: The [*] marker belongs to the write face: extraction still reports the first match under
7
+ note: an ordinary key, so a [*] rule reads like the same rule without the marker.
@@ -0,0 +1,3 @@
1
+ {
2
+ "name": "span.site-name[*]"
3
+ }
@@ -0,0 +1,12 @@
1
+ {
2
+ "accent": "#3b82f6",
3
+ "gap": "2rem",
4
+ "font": "\"Inter\", sans-serif",
5
+ "quoted": "\"a;b\"",
6
+ "bracketed": "rgb(1 2 3 / 50%)",
7
+ "lower": "red",
8
+ "upper": "blue",
9
+ "empty": "",
10
+ "missing": null,
11
+ "absent": null
12
+ }
@@ -0,0 +1,7 @@
1
+ <!doctype html><html style="color: black; --color-accent: #3b82f6"><body>
2
+ <div id="d" style="--gap:1rem; --gap: 2rem !important; --gap: 3rem"></div>
3
+ <p id="p" style="/* theme */ --font-body: &quot;Inter&quot;, sans-serif"></p>
4
+ <i id="q" style='--q: "a;b"; --r: rgb(1 2 3 / 50%)'></i>
5
+ <b id="c" style="--BG: blue; --bg: red; --empty:"></b>
6
+ <span id="s"></span>
7
+ </body></html>
@@ -0,0 +1,6 @@
1
+ tier: 1
2
+ face: query
3
+ expect: ok
4
+ note: `@--name` reads one custom property from the style attribute. The last declaration wins
5
+ note: unless an earlier one is !important; comments are ignored; names are case sensitive; a
6
+ note: semicolon inside quotes or brackets does not end a declaration; absent reads null.
@@ -0,0 +1,12 @@
1
+ {
2
+ "accent": "html@--color-accent",
3
+ "gap": "#d@--gap",
4
+ "font": "#p@--font-body",
5
+ "quoted": "#q@--q",
6
+ "bracketed": "#q@--r",
7
+ "lower": "#c@--bg",
8
+ "upper": "#c@--BG",
9
+ "empty": "#c@--empty",
10
+ "missing": "#s@--x",
11
+ "absent": "#d@--nope"
12
+ }
@@ -0,0 +1 @@
1
+ {"accent":"html@--color-accent","gap":"#d@--gap","font":"#p@--font-body","quoted":"#q@--q","bracketed":"#q@--r","lower":"#c@--bg","upper":"#c@--BG","empty":"#c@--empty","missing":"#s@--x","absent":"#d@--nope"}
@@ -0,0 +1 @@
1
+ <script data-rules-name="api" data-rules-version="1">{home:"a.home[*]@href"}</script><nav><a class="home" href="/start">Home</a><a class="home" href="/start">About</a></nav>
@@ -0,0 +1,3 @@
1
+ {
2
+ "home": "/start"
3
+ }
@@ -0,0 +1 @@
1
+ {"home":"/start"}
@@ -0,0 +1 @@
1
+ <script data-rules-name="api" data-rules-version="1">{home:"a.home[*]@href"}</script><nav><a class="home" href="/">Home</a><a class="home" href="/about">About</a></nav>
@@ -0,0 +1,6 @@
1
+ tier: 1
2
+ face: write
3
+ expect: ok
4
+ skip: htmlclay=all-matches form not ported yet (multi-page sites release 1, step G1)
5
+ note: The marker goes on the selector, before the @prop separator, and every match's attribute
6
+ note: is written.
@@ -0,0 +1,4 @@
1
+ {
2
+ "changed": true,
3
+ "spliced": true
4
+ }
@@ -0,0 +1 @@
1
+ <script data-rules-name="api" data-rules-version="1">{title:"title, span.site-name[*]"}</script><title>New title</title><header><span class="site-name">New title</span></header><footer><span class="site-name">New title</span></footer>
@@ -0,0 +1,3 @@
1
+ {
2
+ "title": "New title"
3
+ }
@@ -0,0 +1 @@
1
+ {"title":"New title"}
@@ -0,0 +1 @@
1
+ <script data-rules-name="api" data-rules-version="1">{title:"title, span.site-name[*]"}</script><title>Old title</title><header><span class="site-name">Old name</span></header><footer><span class="site-name">Old name</span></footer>
@@ -0,0 +1,6 @@
1
+ tier: 1
2
+ face: write
3
+ expect: ok
4
+ skip: htmlclay=all-matches form not ported yet (multi-page sites release 1, step G1)
5
+ note: The marker does not cover the whole group: it covers only the last selector in it, so
6
+ note: title is written once and both .site-name matches are written.
@@ -0,0 +1,4 @@
1
+ {
2
+ "changed": true,
3
+ "spliced": true
4
+ }
@@ -0,0 +1 @@
1
+ <script data-rules-name="api" data-rules-version="1">{name:"span.site-name[*]"}</script><header><span class="site-name">Hyper</span></header><footer><span class="site-name">Hyper</span></footer>
@@ -0,0 +1,3 @@
1
+ {
2
+ "name": "Hyper"
3
+ }
@@ -0,0 +1 @@
1
+ {"name":"Hyper"}
@@ -0,0 +1 @@
1
+ <script data-rules-name="api" data-rules-version="1">{name:"span.site-name[*]"}</script><header><span class="site-name">Old name</span></header><footer><span class="site-name">Old name</span></footer>
@@ -0,0 +1,6 @@
1
+ tier: 1
2
+ face: write
3
+ expect: ok
4
+ skip: htmlclay=all-matches form not ported yet (multi-page sites release 1, step G1)
5
+ note: A [*] text rule writes every match of its selector, not just the first: this is how a
6
+ note: site's shared value reaches every page element that shows it.
@@ -0,0 +1,4 @@
1
+ {
2
+ "changed": true,
3
+ "spliced": true
4
+ }
@@ -0,0 +1 @@
1
+ {"name":"Hyper"}
@@ -0,0 +1,14 @@
1
+ {
2
+ "type": "WriteRejected",
3
+ "message": "write rejected: 0 unknown key(s), 1 rule(s) with no matching element",
4
+ "status": 400,
5
+ "details": {
6
+ "unknownKeys": [],
7
+ "unmatched": [
8
+ {
9
+ "path": "name",
10
+ "selector": ".missing"
11
+ }
12
+ ]
13
+ }
14
+ }
@@ -0,0 +1 @@
1
+ <script data-rules-name="api" data-rules-version="1">{name:".missing[*]"}</script><header><span class="site-name">Old name</span></header>
@@ -0,0 +1,6 @@
1
+ tier: 1
2
+ face: write
3
+ expect: error
4
+ skip: htmlclay=all-matches form not ported yet (multi-page sites release 1, step G1)
5
+ note: Zero matches is still zero matches: the marker says "all of them", not "at least one",
6
+ note: and the rejection reports the selector without the marker.
@@ -0,0 +1 @@
1
+ {"s":"--x: red"}
@@ -0,0 +1,11 @@
1
+ {
2
+ "type": "WriteRefused",
3
+ "message": "write refused: 1 write(s) broke the content-only policy",
4
+ "status": 400,
5
+ "details": [
6
+ {
7
+ "target": "<div#d>",
8
+ "reason": "attribute \"style\" is not content"
9
+ }
10
+ ]
11
+ }
@@ -0,0 +1 @@
1
+ <script data-rules-name="api" data-rules-version="1">{s:"#d@style"}</script><div id=d style="color: red"></div>
@@ -0,0 +1,4 @@
1
+ tier: 1
2
+ face: write
3
+ expect: error
4
+ note: A raw `@style` write stays refused; only `@--name` reaches the style attribute.
@@ -0,0 +1 @@
1
+ {"a": "Url(https://example.invalid/x)", "b": "red; color: blue", "c": "rgb(1, 2, 3", "d": "\"Inter", "e": "/* c */ red", "f": "red\u0001", "g": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "h": "a)", "i": "<b>"}
@@ -0,0 +1,43 @@
1
+ {
2
+ "type": "WriteRefused",
3
+ "message": "write refused: 9 write(s) broke the content-only policy",
4
+ "status": 400,
5
+ "details": [
6
+ {
7
+ "target": "<div#d>",
8
+ "reason": "\"url()\" is not allowed in a custom property value"
9
+ },
10
+ {
11
+ "target": "<div#d>",
12
+ "reason": "\";\" is not allowed in a custom property value"
13
+ },
14
+ {
15
+ "target": "<div#d>",
16
+ "reason": "a custom property value must close its brackets"
17
+ },
18
+ {
19
+ "target": "<div#d>",
20
+ "reason": "a custom property value must close its quotes"
21
+ },
22
+ {
23
+ "target": "<div#d>",
24
+ "reason": "comments are not allowed in a custom property value"
25
+ },
26
+ {
27
+ "target": "<div#d>",
28
+ "reason": "control characters are not allowed in a custom property value"
29
+ },
30
+ {
31
+ "target": "<div#d>",
32
+ "reason": "custom property values are limited to 200 characters"
33
+ },
34
+ {
35
+ "target": "<div#d>",
36
+ "reason": "\")\" does not close anything in this custom property value"
37
+ },
38
+ {
39
+ "target": "<div#d>",
40
+ "reason": "\"<\" is not allowed in a custom property value"
41
+ }
42
+ ]
43
+ }
@@ -0,0 +1 @@
1
+ <script data-rules-name="api" data-rules-version="1">{a:"#d@--a", b:"#d@--b", c:"#d@--c", d:"#d@--d", e:"#d@--e", f:"#d@--f", g:"#d@--g", h:"#d@--h", i:"#d@--i"}</script><div id=d></div>
@@ -0,0 +1,5 @@
1
+ tier: 1
2
+ face: write
3
+ expect: error
4
+ note: Custom property values that could load a resource, close their declaration, carry markup
5
+ note: or break the attribute are refused, one reason per value, in rule order.
@@ -0,0 +1 @@
1
+ <script data-rules-name="api" data-rules-version="1">{a:"#a@--gap", b:"#b@--gap"}</script><div id="a"></div><div id="b" style=" color: red"></div>
@@ -0,0 +1,4 @@
1
+ {
2
+ "a": null,
3
+ "b": null
4
+ }
@@ -0,0 +1 @@
1
+ {"a":"","b":""}
@@ -0,0 +1 @@
1
+ <script data-rules-name="api" data-rules-version="1">{a:"#a@--gap", b:"#b@--gap"}</script><div id=a style="--gap: 1rem"></div><div id=b style="--gap:1rem; color: red; --gap: 2rem"></div>
@@ -0,0 +1,5 @@
1
+ tier: 1
2
+ face: write
3
+ expect: ok
4
+ note: An empty `@--name` write removes every declaration of the property, and the style
5
+ note: attribute itself once nothing is left in it.
@@ -0,0 +1,4 @@
1
+ {
2
+ "changed": true,
3
+ "spliced": true
4
+ }
@@ -0,0 +1,2 @@
1
+ <!DOCTYPE html><html style="color: black; --color-accent: #3b82f6"><head><script data-rules-name="api" data-rules-version="1">{accent:"html@--color-accent", gap:"#d@--gap", x:"#e@--x"}</script></head><body><div id="d" style="--gap: 2rem"></div><div id="e" style="--x: c !important; color: red"></div>
2
+ </body></html>
@@ -0,0 +1,5 @@
1
+ {
2
+ "accent": "#3b82f6",
3
+ "gap": "2rem",
4
+ "x": "c"
5
+ }
@@ -0,0 +1 @@
1
+ {"accent":" #3b82f6 ","gap":"2rem","x":"c"}
@@ -0,0 +1 @@
1
+ <!doctype html><html style="color: black; --color-accent: red"><head><script data-rules-name="api" data-rules-version="1">{accent:"html@--color-accent", gap:"#d@--gap", x:"#e@--x"}</script></head><body><div id=d></div><div id=e style="--x: a !important; color: red; --x: b"></div></body></html>
@@ -0,0 +1,6 @@
1
+ tier: 1
2
+ face: write
3
+ expect: ok
4
+ note: `@--name` writes rewrite the first declaration in place (keeping !important), drop later
5
+ note: duplicates, append a property not yet present, trim the value, and leave every other
6
+ note: declaration as it was.
@@ -0,0 +1,4 @@
1
+ {
2
+ "changed": true,
3
+ "spliced": false
4
+ }
@@ -0,0 +1 @@
1
+ <script data-rules-name="api" data-rules-version="1">{bg:"#a@--bg"}</script><div id=a style="--bg: url(a.png)"></div>
@@ -0,0 +1,3 @@
1
+ {
2
+ "bg": "url(a.png)"
3
+ }
@@ -0,0 +1 @@
1
+ {"bg":"url(a.png)"}
@@ -0,0 +1 @@
1
+ <script data-rules-name="api" data-rules-version="1">{bg:"#a@--bg"}</script><div id=a style="--bg: url(a.png)"></div>
@@ -0,0 +1,5 @@
1
+ tier: 1
2
+ face: write
3
+ expect: ok
4
+ note: Posting back the value a custom property already has is a no-op, even when the policy
5
+ note: would refuse that value as a new write, so a read posted back unchanged never errors.
@@ -0,0 +1,4 @@
1
+ {
2
+ "changed": false,
3
+ "spliced": true
4
+ }
@@ -75,5 +75,27 @@
75
75
  "javascript",
76
76
  "vbscript",
77
77
  "data"
78
- ]
78
+ ],
79
+ "customPropertyValues": {
80
+ "maxLength": 200,
81
+ "refusedCharacters": [
82
+ ";",
83
+ "{",
84
+ "}",
85
+ "<",
86
+ ">",
87
+ "\\"
88
+ ],
89
+ "refusedFunctions": [
90
+ "url",
91
+ "src",
92
+ "image",
93
+ "image-set",
94
+ "-webkit-image-set",
95
+ "cross-fade",
96
+ "element",
97
+ "expression",
98
+ "paint"
99
+ ]
100
+ }
79
101
  }