hyper-html-api 0.8.1 → 0.9.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 (217) hide show
  1. package/README.md +28 -0
  2. package/conformance/MANIFEST.json +2 -2
  3. package/conformance/cases/no-data-list-skipped.expected.json +6 -0
  4. package/conformance/cases/no-data-list-skipped.html +1 -0
  5. package/conformance/cases/no-data-list-skipped.meta +4 -0
  6. package/conformance/cases/no-data-list-skipped.parsed.json +3 -0
  7. package/conformance/cases/no-data-list-skipped.rules +1 -0
  8. package/conformance/cases/no-data-text-projected.expected.json +3 -0
  9. package/conformance/cases/no-data-text-projected.html +1 -0
  10. package/conformance/cases/no-data-text-projected.meta +4 -0
  11. package/conformance/cases/no-data-text-projected.parsed.json +3 -0
  12. package/conformance/cases/no-data-text-projected.rules +1 -0
  13. package/conformance/cases/props-type-is-attribute.expected.json +5 -0
  14. package/conformance/cases/props-type-is-attribute.meta +4 -0
  15. package/conformance/cases/write-attr-app-scheme.after.html +1 -0
  16. package/conformance/cases/write-attr-app-scheme.after.json +3 -0
  17. package/conformance/cases/write-attr-app-scheme.data.json +1 -0
  18. package/conformance/cases/write-attr-app-scheme.html +1 -0
  19. package/conformance/cases/write-attr-app-scheme.meta +4 -0
  20. package/conformance/cases/write-attr-app-scheme.write.json +4 -0
  21. package/conformance/cases/write-attr-href.after.html +1 -0
  22. package/conformance/cases/write-attr-href.after.json +3 -0
  23. package/conformance/cases/write-attr-href.data.json +1 -0
  24. package/conformance/cases/write-attr-href.html +1 -0
  25. package/conformance/cases/write-attr-href.meta +4 -0
  26. package/conformance/cases/write-attr-href.write.json +4 -0
  27. package/conformance/cases/write-checked-false.after.html +1 -0
  28. package/conformance/cases/write-checked-false.after.json +3 -0
  29. package/conformance/cases/write-checked-false.data.json +1 -0
  30. package/conformance/cases/write-checked-false.html +1 -0
  31. package/conformance/cases/write-checked-false.meta +4 -0
  32. package/conformance/cases/write-checked-false.write.json +4 -0
  33. package/conformance/cases/write-checked-true.after.html +1 -0
  34. package/conformance/cases/write-checked-true.after.json +3 -0
  35. package/conformance/cases/write-checked-true.data.json +1 -0
  36. package/conformance/cases/write-checked-true.html +1 -0
  37. package/conformance/cases/write-checked-true.meta +4 -0
  38. package/conformance/cases/write-checked-true.write.json +4 -0
  39. package/conformance/cases/write-crlf-multi.after.html +12 -0
  40. package/conformance/cases/write-crlf-multi.after.json +8 -0
  41. package/conformance/cases/write-crlf-multi.data.json +1 -0
  42. package/conformance/cases/write-crlf-multi.html +12 -0
  43. package/conformance/cases/write-crlf-multi.meta +4 -0
  44. package/conformance/cases/write-crlf-multi.write.json +4 -0
  45. package/conformance/cases/write-fallback-implied.after.html +1 -0
  46. package/conformance/cases/write-fallback-implied.after.json +3 -0
  47. package/conformance/cases/write-fallback-implied.data.json +1 -0
  48. package/conformance/cases/write-fallback-implied.html +1 -0
  49. package/conformance/cases/write-fallback-implied.meta +4 -0
  50. package/conformance/cases/write-fallback-implied.write.json +4 -0
  51. package/conformance/cases/write-flatten.after.html +1 -0
  52. package/conformance/cases/write-flatten.after.json +3 -0
  53. package/conformance/cases/write-flatten.data.json +1 -0
  54. package/conformance/cases/write-flatten.html +1 -0
  55. package/conformance/cases/write-flatten.meta +4 -0
  56. package/conformance/cases/write-flatten.write.json +4 -0
  57. package/conformance/cases/write-list-empty-no-seed.data.json +1 -0
  58. package/conformance/cases/write-list-empty-no-seed.error.json +8 -0
  59. package/conformance/cases/write-list-empty-no-seed.html +1 -0
  60. package/conformance/cases/write-list-empty-no-seed.meta +4 -0
  61. package/conformance/cases/write-list-grow-from-template.after.html +1 -0
  62. package/conformance/cases/write-list-grow-from-template.after.json +5 -0
  63. package/conformance/cases/write-list-grow-from-template.data.json +1 -0
  64. package/conformance/cases/write-list-grow-from-template.html +1 -0
  65. package/conformance/cases/write-list-grow-from-template.meta +4 -0
  66. package/conformance/cases/write-list-grow-from-template.write.json +4 -0
  67. package/conformance/cases/write-list-object-clone.after.html +1 -0
  68. package/conformance/cases/write-list-object-clone.after.json +12 -0
  69. package/conformance/cases/write-list-object-clone.data.json +1 -0
  70. package/conformance/cases/write-list-object-clone.html +1 -0
  71. package/conformance/cases/write-list-object-clone.meta +4 -0
  72. package/conformance/cases/write-list-object-clone.write.json +4 -0
  73. package/conformance/cases/write-list-scalar-grow.after.html +4 -0
  74. package/conformance/cases/write-list-scalar-grow.after.json +7 -0
  75. package/conformance/cases/write-list-scalar-grow.data.json +1 -0
  76. package/conformance/cases/write-list-scalar-grow.html +4 -0
  77. package/conformance/cases/write-list-scalar-grow.meta +4 -0
  78. package/conformance/cases/write-list-scalar-grow.write.json +4 -0
  79. package/conformance/cases/write-list-scalar-shrink.after.html +4 -0
  80. package/conformance/cases/write-list-scalar-shrink.after.json +5 -0
  81. package/conformance/cases/write-list-scalar-shrink.data.json +1 -0
  82. package/conformance/cases/write-list-scalar-shrink.html +4 -0
  83. package/conformance/cases/write-list-scalar-shrink.meta +4 -0
  84. package/conformance/cases/write-list-scalar-shrink.write.json +4 -0
  85. package/conformance/cases/write-list-shrink-zero.after.html +1 -0
  86. package/conformance/cases/write-list-shrink-zero.after.json +3 -0
  87. package/conformance/cases/write-list-shrink-zero.data.json +1 -0
  88. package/conformance/cases/write-list-shrink-zero.html +1 -0
  89. package/conformance/cases/write-list-shrink-zero.meta +4 -0
  90. package/conformance/cases/write-list-shrink-zero.write.json +4 -0
  91. package/conformance/cases/write-no-data-kept.after.html +1 -0
  92. package/conformance/cases/write-no-data-kept.after.json +3 -0
  93. package/conformance/cases/write-no-data-kept.data.json +1 -0
  94. package/conformance/cases/write-no-data-kept.html +1 -0
  95. package/conformance/cases/write-no-data-kept.meta +4 -0
  96. package/conformance/cases/write-no-data-kept.write.json +4 -0
  97. package/conformance/cases/write-no-rules-tag.data.json +1 -0
  98. package/conformance/cases/write-no-rules-tag.error.json +6 -0
  99. package/conformance/cases/write-no-rules-tag.html +1 -0
  100. package/conformance/cases/write-no-rules-tag.meta +4 -0
  101. package/conformance/cases/write-noop.after.html +3 -0
  102. package/conformance/cases/write-noop.after.json +3 -0
  103. package/conformance/cases/write-noop.data.json +1 -0
  104. package/conformance/cases/write-noop.html +3 -0
  105. package/conformance/cases/write-noop.meta +4 -0
  106. package/conformance/cases/write-noop.write.json +4 -0
  107. package/conformance/cases/write-outerhtml-unchanged.after.html +1 -0
  108. package/conformance/cases/write-outerhtml-unchanged.after.json +3 -0
  109. package/conformance/cases/write-outerhtml-unchanged.data.json +1 -0
  110. package/conformance/cases/write-outerhtml-unchanged.html +1 -0
  111. package/conformance/cases/write-outerhtml-unchanged.meta +4 -0
  112. package/conformance/cases/write-outerhtml-unchanged.write.json +4 -0
  113. package/conformance/cases/write-readonly-changed.data.json +1 -0
  114. package/conformance/cases/write-readonly-changed.error.json +6 -0
  115. package/conformance/cases/write-readonly-changed.html +1 -0
  116. package/conformance/cases/write-readonly-changed.meta +4 -0
  117. package/conformance/cases/write-readonly-unchanged.after.html +1 -0
  118. package/conformance/cases/write-readonly-unchanged.after.json +4 -0
  119. package/conformance/cases/write-readonly-unchanged.data.json +1 -0
  120. package/conformance/cases/write-readonly-unchanged.html +1 -0
  121. package/conformance/cases/write-readonly-unchanged.meta +4 -0
  122. package/conformance/cases/write-readonly-unchanged.write.json +4 -0
  123. package/conformance/cases/write-refused-animate.data.json +1 -0
  124. package/conformance/cases/write-refused-animate.error.json +11 -0
  125. package/conformance/cases/write-refused-animate.html +1 -0
  126. package/conformance/cases/write-refused-animate.meta +4 -0
  127. package/conformance/cases/write-refused-attr-name.data.json +1 -0
  128. package/conformance/cases/write-refused-attr-name.error.json +11 -0
  129. package/conformance/cases/write-refused-attr-name.html +1 -0
  130. package/conformance/cases/write-refused-attr-name.meta +4 -0
  131. package/conformance/cases/write-refused-data-url.data.json +1 -0
  132. package/conformance/cases/write-refused-data-url.error.json +11 -0
  133. package/conformance/cases/write-refused-data-url.html +1 -0
  134. package/conformance/cases/write-refused-data-url.meta +4 -0
  135. package/conformance/cases/write-refused-innerhtml.data.json +1 -0
  136. package/conformance/cases/write-refused-innerhtml.error.json +11 -0
  137. package/conformance/cases/write-refused-innerhtml.html +1 -0
  138. package/conformance/cases/write-refused-innerhtml.meta +4 -0
  139. package/conformance/cases/write-refused-javascript-url.data.json +1 -0
  140. package/conformance/cases/write-refused-javascript-url.error.json +11 -0
  141. package/conformance/cases/write-refused-javascript-url.html +1 -0
  142. package/conformance/cases/write-refused-javascript-url.meta +4 -0
  143. package/conformance/cases/write-refused-list-removes-rules-tag.data.json +1 -0
  144. package/conformance/cases/write-refused-list-removes-rules-tag.error.json +11 -0
  145. package/conformance/cases/write-refused-list-removes-rules-tag.html +1 -0
  146. package/conformance/cases/write-refused-list-removes-rules-tag.meta +4 -0
  147. package/conformance/cases/write-refused-multiple.data.json +1 -0
  148. package/conformance/cases/write-refused-multiple.error.json +15 -0
  149. package/conformance/cases/write-refused-multiple.html +1 -0
  150. package/conformance/cases/write-refused-multiple.meta +4 -0
  151. package/conformance/cases/write-refused-onclick.data.json +1 -0
  152. package/conformance/cases/write-refused-onclick.error.json +11 -0
  153. package/conformance/cases/write-refused-onclick.html +1 -0
  154. package/conformance/cases/write-refused-onclick.meta +4 -0
  155. package/conformance/cases/write-refused-rules-tag-ancestor.data.json +1 -0
  156. package/conformance/cases/write-refused-rules-tag-ancestor.error.json +11 -0
  157. package/conformance/cases/write-refused-rules-tag-ancestor.html +1 -0
  158. package/conformance/cases/write-refused-rules-tag-ancestor.meta +4 -0
  159. package/conformance/cases/write-refused-script.data.json +1 -0
  160. package/conformance/cases/write-refused-script.error.json +11 -0
  161. package/conformance/cases/write-refused-script.html +1 -0
  162. package/conformance/cases/write-refused-script.meta +4 -0
  163. package/conformance/cases/write-shape-mismatch.data.json +1 -0
  164. package/conformance/cases/write-shape-mismatch.error.json +12 -0
  165. package/conformance/cases/write-shape-mismatch.html +1 -0
  166. package/conformance/cases/write-shape-mismatch.meta +4 -0
  167. package/conformance/cases/write-text-basic.after.html +3 -0
  168. package/conformance/cases/write-text-basic.after.json +3 -0
  169. package/conformance/cases/write-text-basic.data.json +1 -0
  170. package/conformance/cases/write-text-basic.html +3 -0
  171. package/conformance/cases/write-text-basic.meta +4 -0
  172. package/conformance/cases/write-text-basic.write.json +4 -0
  173. package/conformance/cases/write-text-escape.after.html +1 -0
  174. package/conformance/cases/write-text-escape.after.json +3 -0
  175. package/conformance/cases/write-text-escape.data.json +1 -0
  176. package/conformance/cases/write-text-escape.html +1 -0
  177. package/conformance/cases/write-text-escape.meta +4 -0
  178. package/conformance/cases/write-text-escape.write.json +4 -0
  179. package/conformance/cases/write-text-null-clears.after.html +1 -0
  180. package/conformance/cases/write-text-null-clears.after.json +3 -0
  181. package/conformance/cases/write-text-null-clears.data.json +1 -0
  182. package/conformance/cases/write-text-null-clears.html +1 -0
  183. package/conformance/cases/write-text-null-clears.meta +4 -0
  184. package/conformance/cases/write-text-null-clears.write.json +4 -0
  185. package/conformance/cases/write-type-attribute.after.html +1 -0
  186. package/conformance/cases/write-type-attribute.after.json +3 -0
  187. package/conformance/cases/write-type-attribute.data.json +1 -0
  188. package/conformance/cases/write-type-attribute.html +1 -0
  189. package/conformance/cases/write-type-attribute.meta +4 -0
  190. package/conformance/cases/write-type-attribute.write.json +4 -0
  191. package/conformance/cases/write-unknown-key.data.json +1 -0
  192. package/conformance/cases/write-unknown-key.error.json +11 -0
  193. package/conformance/cases/write-unknown-key.html +3 -0
  194. package/conformance/cases/write-unknown-key.meta +4 -0
  195. package/conformance/cases/write-unmatched.data.json +1 -0
  196. package/conformance/cases/write-unmatched.error.json +14 -0
  197. package/conformance/cases/write-unmatched.html +1 -0
  198. package/conformance/cases/write-unmatched.meta +4 -0
  199. package/conformance/write-policy.json +78 -0
  200. package/dist/hyper-html-api.engine.min.js +1 -1
  201. package/dist/hyper-html-api.min.js +5 -4
  202. package/dist/hyper-html-api.upgrade.min.js +2 -2
  203. package/package.json +4 -3
  204. package/packed-contract.json +1 -1
  205. package/src/adapters/cheerio.js +105 -10
  206. package/src/engine/apply.js +2 -0
  207. package/src/engine/errors.js +25 -0
  208. package/src/engine/index.js +3 -0
  209. package/src/engine/splice.js +118 -0
  210. package/src/engine/write-plan.js +52 -0
  211. package/src/engine/write-policy.js +136 -0
  212. package/src/write.js +29 -0
  213. package/conformance/cases/props-type-is-node-type.expected.json +0 -5
  214. package/conformance/cases/props-type-is-node-type.meta +0 -11
  215. /package/conformance/cases/{props-type-is-node-type.html → props-type-is-attribute.html} +0 -0
  216. /package/conformance/cases/{props-type-is-node-type.parsed.json → props-type-is-attribute.parsed.json} +0 -0
  217. /package/conformance/cases/{props-type-is-node-type.rules → props-type-is-attribute.rules} +0 -0
@@ -0,0 +1 @@
1
+ <script data-rules-name="api" data-rules-version="1">{o:"#h@outerHTML"}</script><h1 id=h>Hi</h1>
@@ -0,0 +1,4 @@
1
+ tier: 1
2
+ face: write
3
+ expect: ok
4
+ note: "@outerHTML" is refused only when it would replace HTML; posting the extraction of the same rule back is a no-op like "@innerHTML".
@@ -0,0 +1,4 @@
1
+ {
2
+ "changed": false,
3
+ "spliced": true
4
+ }
@@ -0,0 +1 @@
1
+ {"t":"Hi","tag":"H2"}
@@ -0,0 +1,6 @@
1
+ {
2
+ "type": "RuleTargetReadOnly",
3
+ "message": "cannot write to read-only DOM property \"tagName\"",
4
+ "status": 500,
5
+ "details": null
6
+ }
@@ -0,0 +1 @@
1
+ <script data-rules-name="api" data-rules-version="1">{t:"#h",tag:"#h@tagName"}</script><h1 id=h>Hi</h1>
@@ -0,0 +1,4 @@
1
+ tier: 1
2
+ face: write
3
+ expect: error
4
+ note: A read-only property write that would change the value is still refused.
@@ -0,0 +1 @@
1
+ <script data-rules-name="api" data-rules-version="1">{t:"#h",tag:"#h@tagName"}</script><h1 id=h>Hi</h1>
@@ -0,0 +1,4 @@
1
+ {
2
+ "t": "Hi",
3
+ "tag": "H1"
4
+ }
@@ -0,0 +1 @@
1
+ {"t":"Hi","tag":"H1"}
@@ -0,0 +1 @@
1
+ <script data-rules-name="api" data-rules-version="1">{t:"#h",tag:"#h@tagName"}</script><h1 id=h>Hi</h1>
@@ -0,0 +1,4 @@
1
+ tier: 1
2
+ face: write
3
+ expect: ok
4
+ note: Posting a read-only property back unchanged is a no-op, so a GET response round-trips.
@@ -0,0 +1,4 @@
1
+ {
2
+ "changed": false,
3
+ "spliced": true
4
+ }
@@ -0,0 +1 @@
1
+ {"v":"javascript:alert(1)"}
@@ -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": "<animate#a>",
8
+ "reason": "inside <animate>, which is not content"
9
+ }
10
+ ]
11
+ }
@@ -0,0 +1 @@
1
+ <script data-rules-name="api" data-rules-version="1">{v:"#a@to"}</script><svg><animate id=a attributeName="href" to="#x"></animate></svg>
@@ -0,0 +1,4 @@
1
+ tier: 1
2
+ face: write
3
+ expect: error
4
+ note: SVG animation elements can retarget href, so writing their to/values is refused like any other refused target.
@@ -0,0 +1 @@
1
+ {"v":"javascript:alert(1)"}
@@ -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": "<a#a>",
8
+ "reason": "attribute name \"href \" is not valid"
9
+ }
10
+ ]
11
+ }
@@ -0,0 +1 @@
1
+ <script data-rules-name="api" data-rules-version="1">{v:"#a@href "}</script><a id=a href="/x">x</a>
@@ -0,0 +1,4 @@
1
+ tier: 1
2
+ face: write
3
+ expect: error
4
+ note: An attribute name with a space in it is not a valid HTML attribute name, so the write is refused rather than serializing a live attribute.
@@ -0,0 +1 @@
1
+ {"h":"data:text/html,x"}
@@ -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": "<a#a>",
8
+ "reason": "\"data:\" URLs are not allowed in \"href\""
9
+ }
10
+ ]
11
+ }
@@ -0,0 +1 @@
1
+ <script data-rules-name="api" data-rules-version="1">{h:"#a@href"}</script><a id=a href="/">x</a>
@@ -0,0 +1,4 @@
1
+ tier: 1
2
+ face: write
3
+ expect: error
4
+ note: A data: URL in a URL attribute is refused.
@@ -0,0 +1 @@
1
+ {"h":"<b>y</b>"}
@@ -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": "<p#p>",
8
+ "reason": "\"@innerHTML\" writes HTML, only text is allowed"
9
+ }
10
+ ]
11
+ }
@@ -0,0 +1 @@
1
+ <script data-rules-name="api" data-rules-version="1">{h:"#p@innerHTML"}</script><p id=p>x</p>
@@ -0,0 +1,4 @@
1
+ tier: 1
2
+ face: write
3
+ expect: error
4
+ note: @innerHTML writes HTML, so the rule form itself is refused.
@@ -0,0 +1 @@
1
+ {"h":" JaVaScRiPt:alert(1)"}
@@ -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": "<a#a>",
8
+ "reason": "\"javascript:\" URLs are not allowed in \"href\""
9
+ }
10
+ ]
11
+ }
@@ -0,0 +1 @@
1
+ <script data-rules-name="api" data-rules-version="1">{h:"#a@href"}</script><a id=a href="/">x</a>
@@ -0,0 +1,4 @@
1
+ tier: 1
2
+ face: write
3
+ expect: error
4
+ note: A javascript: URL is refused even behind leading spaces and mixed case.
@@ -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": "<p>",
8
+ "reason": "removing this would delete the data rules tag"
9
+ }
10
+ ]
11
+ }
@@ -0,0 +1 @@
1
+ <div id=c><p class=r>A</p><p class=r>B<script type="application/json" data-rules-name="api" data-rules-version="1">{r:"#c .r[]"}</script></p></div>
@@ -0,0 +1,4 @@
1
+ tier: 1
2
+ face: write
3
+ expect: error
4
+ note: Shrinking a list to zero rows would remove the row that holds the data rules tag, so it is refused.
@@ -0,0 +1 @@
1
+ {"h":"javascript:1","o":"x"}
@@ -0,0 +1,15 @@
1
+ {
2
+ "type": "WriteRefused",
3
+ "message": "write refused: 2 write(s) broke the content-only policy",
4
+ "status": 400,
5
+ "details": [
6
+ {
7
+ "target": "<a#a>",
8
+ "reason": "\"javascript:\" URLs are not allowed in \"href\""
9
+ },
10
+ {
11
+ "target": "<p#p>",
12
+ "reason": "attribute \"onclick\" can run script"
13
+ }
14
+ ]
15
+ }
@@ -0,0 +1 @@
1
+ <script data-rules-name="api" data-rules-version="1">{h:"#a@href",o:"#p@onclick"}</script><a id=a href="/">x</a><p id=p>y</p>
@@ -0,0 +1,4 @@
1
+ tier: 1
2
+ face: write
3
+ expect: error
4
+ note: One refused body reports every violation, not just the first.
@@ -0,0 +1 @@
1
+ {"h":"alert(1)"}
@@ -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": "<a#a>",
8
+ "reason": "attribute \"onclick\" can run script"
9
+ }
10
+ ]
11
+ }
@@ -0,0 +1 @@
1
+ <script data-rules-name="api" data-rules-version="1">{h:"#a@onclick"}</script><a id=a>x</a>
@@ -0,0 +1,4 @@
1
+ tier: 1
2
+ face: write
3
+ expect: error
4
+ note: An on* attribute write is refused because the attribute can run script.
@@ -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": "a text write here would delete the data rules tag"
9
+ }
10
+ ]
11
+ }
@@ -0,0 +1 @@
1
+ <div id=d><p>x</p><script data-rules-name="api" data-rules-version="1">{t:"#d"}</script></div>
@@ -0,0 +1,4 @@
1
+ tier: 1
2
+ face: write
3
+ expect: error
4
+ note: A write that would delete the data rules tag is refused.
@@ -0,0 +1 @@
1
+ {"c":"alert(1)"}
@@ -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": "<script#s>",
8
+ "reason": "inside <script>, which is not content"
9
+ }
10
+ ]
11
+ }
@@ -0,0 +1 @@
1
+ <script data-rules-name="api" data-rules-version="1">{c:"#s"}</script><script id=s>x</script>
@@ -0,0 +1,4 @@
1
+ tier: 1
2
+ face: write
3
+ expect: error
4
+ note: A text write inside script is refused by the content-only policy.
@@ -0,0 +1 @@
1
+ {"items":"A"}
@@ -0,0 +1,12 @@
1
+ {
2
+ "type": "ShapeMismatch",
3
+ "message": "shape mismatch: 1 field(s) failed validation",
4
+ "status": 400,
5
+ "details": [
6
+ {
7
+ "path": "items",
8
+ "expected": "array",
9
+ "got": "string"
10
+ }
11
+ ]
12
+ }
@@ -0,0 +1 @@
1
+ <script data-rules-name="api" data-rules-version="1">{items:"li[]"}</script><ul><li>A</li></ul>
@@ -0,0 +1,4 @@
1
+ tier: 1
2
+ face: write
3
+ expect: error
4
+ note: A scalar where the rule expects a list is a shape mismatch.
@@ -0,0 +1,3 @@
1
+ <script data-rules-name="api" data-rules-version="1">{title:"h1"}</script>
2
+ <h1 class="x">World</h1>
3
+ <p>&copy;<br/></p>
@@ -0,0 +1,3 @@
1
+ {
2
+ "title": "World"
3
+ }
@@ -0,0 +1 @@
1
+ {"title":"World"}
@@ -0,0 +1,3 @@
1
+ <script data-rules-name="api" data-rules-version="1">{title:"h1"}</script>
2
+ <h1 class='x'>Hello</h1>
3
+ <p>&copy;<br/></p>
@@ -0,0 +1,4 @@
1
+ tier: 1
2
+ face: write
3
+ expect: ok
4
+ note: Scalar text write: the cheapest happy path, pinned as bytes on disk.
@@ -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">{t:"#t"}</script><p id="t">a &lt; b &amp; c</p>
@@ -0,0 +1,3 @@
1
+ {
2
+ "t": "a < b & c"
3
+ }
@@ -0,0 +1 @@
1
+ {"t":"a < b & c"}
@@ -0,0 +1 @@
1
+ <script data-rules-name="api" data-rules-version="1">{t:"#t"}</script><p id=t>x</p>
@@ -0,0 +1,4 @@
1
+ tier: 1
2
+ face: write
3
+ expect: ok
4
+ note: Text is escaped on the way out, so markup in the body stays text.
@@ -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">{t:"#t"}</script><p id="t"></p>
@@ -0,0 +1,3 @@
1
+ {
2
+ "t": ""
3
+ }
@@ -0,0 +1 @@
1
+ {"t":null}
@@ -0,0 +1 @@
1
+ <script data-rules-name="api" data-rules-version="1">{t:"#t"}</script><p id=t>x</p>
@@ -0,0 +1,4 @@
1
+ tier: 1
2
+ face: write
3
+ expect: ok
4
+ note: A null scalar empties the element's text instead of writing "null".
@@ -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">{t:"#i@type"}</script><input id="i" type="email" name="q">
@@ -0,0 +1,3 @@
1
+ {
2
+ "t": "email"
3
+ }
@@ -0,0 +1 @@
1
+ {"t":"email"}
@@ -0,0 +1 @@
1
+ <script data-rules-name="api" data-rules-version="1">{t:"#i@type"}</script><input id=i type=text name=q>
@@ -0,0 +1,4 @@
1
+ tier: 1
2
+ face: write
3
+ expect: ok
4
+ note: "@type" writes the type attribute; the element survives as an input with type="email".
@@ -0,0 +1,4 @@
1
+ {
2
+ "changed": true,
3
+ "spliced": true
4
+ }
@@ -0,0 +1 @@
1
+ {"titel":"x"}
@@ -0,0 +1,11 @@
1
+ {
2
+ "type": "WriteRejected",
3
+ "message": "write rejected: 1 unknown key(s), 0 rule(s) with no matching element",
4
+ "status": 400,
5
+ "details": {
6
+ "unknownKeys": [
7
+ "titel"
8
+ ],
9
+ "unmatched": []
10
+ }
11
+ }
@@ -0,0 +1,3 @@
1
+ <script data-rules-name="api" data-rules-version="1">{title:"h1"}</script>
2
+ <h1 class='x'>Hello</h1>
3
+ <p>&copy;<br/></p>
@@ -0,0 +1,4 @@
1
+ tier: 1
2
+ face: write
3
+ expect: error
4
+ note: A body key the rules do not define is rejected before anything is written.
@@ -0,0 +1 @@
1
+ {"sub":"x"}
@@ -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": "sub",
10
+ "selector": "h2"
11
+ }
12
+ ]
13
+ }
14
+ }
@@ -0,0 +1 @@
1
+ <script data-rules-name="api" data-rules-version="1">{sub:"h2"}</script><p>x</p>
@@ -0,0 +1,4 @@
1
+ tier: 1
2
+ face: write
3
+ expect: error
4
+ note: A scalar rule whose selector matches nothing is rejected.
@@ -0,0 +1,78 @@
1
+ {
2
+ "refusedRuleForms": [
3
+ "innerHTML",
4
+ "outerHTML"
5
+ ],
6
+ "refusedTargets": [
7
+ "script",
8
+ "style",
9
+ "template",
10
+ "noscript",
11
+ "iframe",
12
+ "object",
13
+ "embed",
14
+ "xmp",
15
+ "plaintext",
16
+ "noembed",
17
+ "noframes",
18
+ "meta",
19
+ "link",
20
+ "base",
21
+ "animate",
22
+ "set",
23
+ "animatemotion",
24
+ "animatetransform"
25
+ ],
26
+ "refusedAttributes": [
27
+ "style",
28
+ "srcdoc",
29
+ "is",
30
+ "http-equiv",
31
+ "sandbox",
32
+ "allow",
33
+ "nonce",
34
+ "integrity",
35
+ "charset",
36
+ "htmlclaytoken",
37
+ "htmlclayid",
38
+ "data-rules-name",
39
+ "data-rules-version",
40
+ "clay",
41
+ "contenteditable",
42
+ "no-save",
43
+ "no-snapshot",
44
+ "no-trigger-autosave",
45
+ "no-dirty",
46
+ "no-watch",
47
+ "no-undo",
48
+ "no-data",
49
+ "freeze",
50
+ "editor-ui"
51
+ ],
52
+ "refusedAttributePrefixes": [
53
+ "on"
54
+ ],
55
+ "urlAttributes": [
56
+ "href",
57
+ "src",
58
+ "srcset",
59
+ "action",
60
+ "formaction",
61
+ "poster",
62
+ "cite",
63
+ "data",
64
+ "ping",
65
+ "background",
66
+ "longdesc",
67
+ "usemap",
68
+ "xlink:href",
69
+ "manifest",
70
+ "codebase",
71
+ "icon"
72
+ ],
73
+ "refusedSchemes": [
74
+ "javascript",
75
+ "vbscript",
76
+ "data"
77
+ ]
78
+ }