ranger-compiler 3.5.0 → 3.5.2

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 (338) hide show
  1. package/CHANGELOG.md +1160 -19
  2. package/LICENSE +3 -1
  3. package/README.md +124 -29
  4. package/dist/Lang.rgr +1188 -290
  5. package/dist/api.d.ts +2343 -879
  6. package/dist/api.js +79924 -56922
  7. package/dist/lib/JSON.rgr +102 -91
  8. package/dist/lib/Shell.rgr +4 -4
  9. package/dist/lib/apple/AppleToolchain.rgr +4 -4
  10. package/dist/lib/apple/README.md +5 -4
  11. package/dist/lib/apple/apple_test.rgr +1 -1
  12. package/dist/lib/core/README.md +1 -1
  13. package/dist/lib/evg/EVG.rgr +12 -0
  14. package/dist/lib/evg/EVGA11yFromTree.rgr +302 -0
  15. package/dist/lib/evg/EVGA11yTree.rgr +894 -0
  16. package/dist/lib/evg/EVGBox.rgr +267 -0
  17. package/dist/lib/evg/EVGBoxShorthandTest.rgr +220 -0
  18. package/dist/lib/evg/EVGCodepoint.rgr +316 -0
  19. package/dist/lib/evg/EVGColor.rgr +700 -0
  20. package/dist/lib/evg/EVGCommands.rgr +177 -0
  21. package/dist/lib/evg/EVGComponent.rgr +331 -0
  22. package/dist/lib/evg/EVGComponentTest.rgr +387 -0
  23. package/dist/lib/evg/EVGConnector.rgr +541 -0
  24. package/dist/lib/evg/EVGConnectorTest.rgr +306 -0
  25. package/dist/lib/evg/EVGDisplayList.rgr +4186 -0
  26. package/dist/lib/evg/EVGEasing.rgr +370 -0
  27. package/dist/lib/evg/EVGEffectTest.rgr +253 -0
  28. package/dist/lib/evg/EVGElement.rgr +4914 -0
  29. package/dist/lib/evg/EVGFixedTest.rgr +289 -0
  30. package/dist/lib/evg/EVGFlexRulesTest.rgr +317 -0
  31. package/dist/lib/evg/EVGFlexWrapTest.rgr +246 -0
  32. package/dist/lib/evg/EVGFling.rgr +244 -0
  33. package/dist/lib/evg/EVGFocus.rgr +400 -0
  34. package/dist/lib/evg/EVGFocusTest.rgr +399 -0
  35. package/dist/lib/evg/EVGGradient.rgr +322 -0
  36. package/dist/lib/evg/EVGGrapheme.rgr +190 -0
  37. package/dist/lib/evg/EVGGrid.rgr +975 -0
  38. package/dist/lib/evg/EVGHitTest.rgr +208 -0
  39. package/dist/lib/evg/EVGHoles.rgr +294 -0
  40. package/dist/lib/evg/EVGHostMeasurerTest.rgr +281 -0
  41. package/dist/lib/evg/EVGHostTextMeasurer.rgr +331 -0
  42. package/dist/lib/evg/EVGHostTree.rgr +834 -0
  43. package/dist/lib/evg/EVGHostTreeTest.rgr +447 -0
  44. package/dist/lib/evg/EVGImageDecode.rgr +117 -0
  45. package/dist/lib/evg/EVGImageMeasurer.rgr +86 -0
  46. package/dist/lib/evg/EVGInspect.rgr +883 -0
  47. package/dist/lib/evg/EVGInvalidateTest.rgr +432 -0
  48. package/dist/lib/evg/EVGJsonTest.rgr +535 -0
  49. package/dist/lib/evg/EVGLayout.rgr +4220 -0
  50. package/dist/lib/evg/EVGMeasure.rgr +1267 -0
  51. package/dist/lib/evg/EVGOverlayTest.rgr +626 -0
  52. package/dist/lib/evg/EVGPatch.rgr +1721 -0
  53. package/dist/lib/evg/EVGPatchTest.rgr +692 -0
  54. package/dist/lib/evg/EVGPopoverTest.rgr +395 -0
  55. package/dist/lib/evg/EVGReconcile.rgr +226 -0
  56. package/dist/lib/evg/EVGReconcileTest.rgr +421 -0
  57. package/dist/lib/evg/EVGReject.rgr +126 -0
  58. package/dist/lib/evg/EVGRelayoutTest.rgr +375 -0
  59. package/dist/lib/evg/EVGRtlLayoutTest.rgr +319 -0
  60. package/dist/lib/evg/EVGRuler.rgr +232 -0
  61. package/dist/lib/evg/EVGRulerTest.rgr +172 -0
  62. package/dist/lib/evg/EVGSelectChrome.rgr +178 -0
  63. package/dist/lib/evg/EVGStyleCacheTest.rgr +419 -0
  64. package/dist/lib/evg/EVGStyleSheet.rgr +2148 -0
  65. package/dist/lib/evg/EVGStyleStateTest.rgr +407 -0
  66. package/dist/lib/evg/EVGStyleVarTest.rgr +471 -0
  67. package/dist/lib/evg/EVGText.rgr +105 -0
  68. package/dist/lib/evg/EVGTextEngine.rgr +536 -0
  69. package/dist/lib/evg/EVGTextMeasurer.rgr +720 -0
  70. package/dist/lib/evg/EVGTimingTest.rgr +1417 -0
  71. package/dist/lib/evg/EVGToolbar.rgr +1369 -0
  72. package/dist/lib/evg/EVGTransition.rgr +728 -0
  73. package/dist/lib/evg/EVGTreeJson.rgr +721 -0
  74. package/dist/lib/evg/EVGUnit.rgr +554 -0
  75. package/dist/lib/evg/EVGViewportUnitTest.rgr +236 -0
  76. package/dist/lib/evg/EvgApp.rgr +189 -0
  77. package/dist/lib/evg/EvgBitmapTracer.rgr +4277 -0
  78. package/dist/lib/evg/EvgBitmapTracerTest.rgr +2119 -0
  79. package/dist/lib/evg/EvgHost.rgr +451 -0
  80. package/dist/lib/evg/EvgTest.rgr +91 -0
  81. package/dist/lib/evg/EvgTraceColor.rgr +236 -0
  82. package/dist/lib/evg/EvgTraceCurve.rgr +648 -0
  83. package/dist/lib/evg/EvgTraceFit.rgr +767 -0
  84. package/dist/lib/evg/EvgTracePath.rgr +435 -0
  85. package/dist/lib/evg/EvgTraceTypes.rgr +559 -0
  86. package/dist/lib/evg/EvgViewport.rgr +313 -0
  87. package/dist/lib/evg/FxDemoDoc.rgr +185 -0
  88. package/dist/lib/evg/HOSTS.md +227 -0
  89. package/dist/lib/evg/ISSUES.md +835 -0
  90. package/dist/lib/evg/PLAN_ACCESSIBILITY.md +650 -0
  91. package/dist/lib/evg/PLAN_CSS_LAYOUT_AND_FONTS.md +1124 -0
  92. package/dist/lib/evg/PLAN_EFFECTS.md +431 -0
  93. package/dist/lib/evg/PLAN_EVG.md +518 -0
  94. package/dist/lib/evg/PLAN_EVG_RENDERER.md +1674 -0
  95. package/dist/lib/evg/PLAN_INSPECTOR.md +788 -0
  96. package/dist/lib/evg/PLAN_LINKS_AND_FORMS.md +157 -0
  97. package/dist/lib/evg/PLAN_NATIVE_HOSTS.md +671 -0
  98. package/dist/lib/evg/PLAN_VECTOR_IR.md +664 -0
  99. package/dist/lib/evg/PLAN_VIEW_TRANSFORM.md +322 -0
  100. package/dist/lib/evg/PathBuilder.rgr +333 -0
  101. package/dist/lib/evg/README.md +1236 -0
  102. package/dist/lib/evg/SPEC.md +1252 -0
  103. package/dist/lib/evg/SVGPathParser.rgr +1199 -0
  104. package/dist/lib/evg/SvgParser.rgr +1736 -0
  105. package/dist/lib/evg/TODO_EVG_RENDERER.md +595 -0
  106. package/dist/lib/evg/VectorShapes.rgr +331 -0
  107. package/dist/lib/evg/VectorStroke.rgr +107 -0
  108. package/dist/lib/evg/VectorViewBox.rgr +380 -0
  109. package/dist/lib/evg/agent/README.md +290 -0
  110. package/dist/lib/evg/agent/evg_agent.rgr +899 -0
  111. package/dist/lib/evg/agent/fixtures/broken.evg.json +7 -0
  112. package/dist/lib/evg/agent/fixtures/card.evg.json +9 -0
  113. package/dist/lib/evg/agent/fixtures/connector.css +63 -0
  114. package/dist/lib/evg/agent/fixtures/connector.evg.json +14 -0
  115. package/dist/lib/evg/agent/fixtures/drawn.evg.json +129 -0
  116. package/dist/lib/evg/agent/fixtures/gradient.evg.json +4 -0
  117. package/dist/lib/evg/agent/fixtures/popover.css +99 -0
  118. package/dist/lib/evg/agent/fixtures/popover.evg.json +30 -0
  119. package/dist/lib/evg/agent/roundtrip.sh +74 -0
  120. package/dist/lib/evg/agent/smoke.sh +230 -0
  121. package/dist/lib/evg/android/README.md +97 -0
  122. package/dist/lib/evg/android/androidstubs/AndroidStubs.kt +175 -0
  123. package/dist/lib/evg/android/androidstubs/Annotation.kt +10 -0
  124. package/dist/lib/evg/android/androidstubs/App.kt +30 -0
  125. package/dist/lib/evg/android/androidstubs/Content.kt +41 -0
  126. package/dist/lib/evg/android/androidstubs/ContentRes.kt +12 -0
  127. package/dist/lib/evg/android/androidstubs/InputMethod.kt +46 -0
  128. package/dist/lib/evg/android/androidstubs/Net.kt +6 -0
  129. package/dist/lib/evg/android/androidstubs/Os.kt +30 -0
  130. package/dist/lib/evg/android/androidstubs/Util.kt +15 -0
  131. package/dist/lib/evg/android/androidstubs/View.kt +113 -0
  132. package/dist/lib/evg/android/androidstubs/Widget.kt +16 -0
  133. package/dist/lib/evg/android/src/android/kotlin/fi/ranger/evg/AndroidEvgSurface.kt +323 -0
  134. package/dist/lib/evg/android/src/android/kotlin/fi/ranger/evg/AndroidTextMeasurer.kt +56 -0
  135. package/dist/lib/evg/android/src/android/kotlin/fi/ranger/evg/RippleEffect.kt +262 -0
  136. package/dist/lib/evg/android/src/awt/kotlin/fi/ranger/evg/AwtEvgSurface.kt +238 -0
  137. package/dist/lib/evg/android/src/awt/kotlin/fi/ranger/evg/AwtTextMeasurer.kt +85 -0
  138. package/dist/lib/evg/android/src/main/kotlin/fi/ranger/evg/EvgEngineThread.kt +115 -0
  139. package/dist/lib/evg/android/src/main/kotlin/fi/ranger/evg/EvgPainter.kt +231 -0
  140. package/dist/lib/evg/android/src/main/kotlin/fi/ranger/evg/EvgSurface.kt +117 -0
  141. package/dist/lib/evg/android/src/main/kotlin/fi/ranger/evg/RecordingSurface.kt +94 -0
  142. package/dist/lib/evg/apple/README.md +128 -0
  143. package/dist/lib/evg/apple/Sources/CoreGraphicsEvgSurface.swift +329 -0
  144. package/dist/lib/evg/apple/Sources/CoreTextMeasurer.swift +70 -0
  145. package/dist/lib/evg/apple/Sources/EvgEngineQueue.swift +105 -0
  146. package/dist/lib/evg/apple/Sources/EvgPainter.swift +225 -0
  147. package/dist/lib/evg/apple/Sources/EvgSurface.swift +163 -0
  148. package/dist/lib/evg/apple/Sources/RecordingSurface.swift +110 -0
  149. package/dist/lib/evg/bench/EvgLayoutBench.rgr +34 -0
  150. package/dist/lib/evg/bench/README.md +64 -0
  151. package/dist/lib/evg/bench/layout-bench.mjs +316 -0
  152. package/dist/lib/evg/bench/layout-cases.mjs +510 -0
  153. package/dist/lib/evg/bench/layout-conformance.mjs +254 -0
  154. package/dist/lib/evg/bin/.gitignore +17 -0
  155. package/dist/lib/evg/evg_test.rgr +313 -0
  156. package/dist/lib/evg/gl/README.md +198 -0
  157. package/dist/lib/evg/gl/a11y-paint-check.mjs +73 -0
  158. package/dist/lib/evg/gl/blur-check.mjs +399 -0
  159. package/dist/lib/evg/gl/boxmodel.json +1 -0
  160. package/dist/lib/evg/gl/demo.html +46 -0
  161. package/dist/lib/evg/gl/effect-presets.css +285 -0
  162. package/dist/lib/evg/gl/effect-presets.js +63 -0
  163. package/dist/lib/evg/gl/effect-shots.mjs +135 -0
  164. package/dist/lib/evg/gl/evg-a11y.js +566 -0
  165. package/dist/lib/evg/gl/evg-binary.js +160 -0
  166. package/dist/lib/evg/gl/evg-engine.js +296 -0
  167. package/dist/lib/evg/gl/evg-fx.js +237 -0
  168. package/dist/lib/evg/gl/evg-gestures.js +209 -0
  169. package/dist/lib/evg/gl/evg-list.js +167 -0
  170. package/dist/lib/evg/gl/evg-measure.js +186 -0
  171. package/dist/lib/evg/gl/evg-textinput.js +303 -0
  172. package/dist/lib/evg/gl/evg-view.js +144 -0
  173. package/dist/lib/evg/gl/evg-webgl.js +3942 -0
  174. package/dist/lib/evg/gl/fx-check.mjs +998 -0
  175. package/dist/lib/evg/gl/fx-demo.html +166 -0
  176. package/dist/lib/evg/gl/fx-demo.js +2 -0
  177. package/dist/lib/evg/gl/fx-serve.mjs +47 -0
  178. package/dist/lib/evg/gl/gestures-check.mjs +189 -0
  179. package/dist/lib/evg/gl/list-binary-check.mjs +152 -0
  180. package/dist/lib/evg/gl/measure-check.mjs +135 -0
  181. package/dist/lib/evg/gl/rotation-check.mjs +207 -0
  182. package/dist/lib/evg/gl/shift-check.mjs +113 -0
  183. package/dist/lib/evg/gl/stroke-check.mjs +168 -0
  184. package/dist/lib/evg/gl/text-snap-check.mjs +139 -0
  185. package/dist/lib/evg/gl/view-check.mjs +343 -0
  186. package/dist/lib/evg/gl/view-policy-check.mjs +184 -0
  187. package/dist/lib/evg/html/evg-dom.js +318 -0
  188. package/dist/lib/evg/html/evg-html.js +600 -0
  189. package/dist/lib/evg/inspect/README.md +415 -0
  190. package/dist/lib/evg/inspect/browser-smoke.mjs +115 -0
  191. package/dist/lib/evg/inspect/evg-inspect.js +947 -0
  192. package/dist/lib/evg/inspect/shots/css.png +0 -0
  193. package/dist/lib/evg/inspect/shots/dashboard.png +0 -0
  194. package/dist/lib/evg/inspect/shots/pptx-slide.png +0 -0
  195. package/dist/lib/evg/inspect/shots/state.png +0 -0
  196. package/dist/lib/evg/inspect/shots.mjs +226 -0
  197. package/dist/lib/evg/oracle/css-blur.json +576 -0
  198. package/dist/lib/evg/oracle/css-box.json +157 -0
  199. package/dist/lib/evg/oracle/css-timing.json +709 -0
  200. package/dist/lib/evg/oracle/css_blur_oracle.mjs +529 -0
  201. package/dist/lib/evg/oracle/css_box_oracle.mjs +106 -0
  202. package/dist/lib/evg/oracle/css_timing_oracle.mjs +389 -0
  203. package/dist/lib/evg/original/EVGColor.clj +310 -0
  204. package/dist/lib/evg/original/EVGColorContext.rgr +178 -0
  205. package/dist/lib/evg/original/SVGPath.rgr +627 -0
  206. package/dist/lib/evg/original/Vec2.crgr +103 -0
  207. package/dist/lib/evg/ranger.json +9 -0
  208. package/dist/lib/evg/showcase/README.md +246 -0
  209. package/dist/lib/evg/showcase/assets/emblem.svg +30 -0
  210. package/dist/lib/evg/showcase/assets/rosette.svg +22 -0
  211. package/dist/lib/evg/showcase/build.mjs +651 -0
  212. package/dist/lib/evg/showcase/pages/album.tsx +30 -0
  213. package/dist/lib/evg/showcase/pages/boxmodel.tsx +37 -0
  214. package/dist/lib/evg/showcase/pages/cards.tsx +41 -0
  215. package/dist/lib/evg/showcase/pages/chart_api.tsx +170 -0
  216. package/dist/lib/evg/showcase/pages/charts.tsx +219 -0
  217. package/dist/lib/evg/showcase/pages/drawing.tsx +160 -0
  218. package/dist/lib/evg/showcase/pages/emoji.tsx +91 -0
  219. package/dist/lib/evg/showcase/pages/flex.tsx +46 -0
  220. package/dist/lib/evg/showcase/pages/more.tsx +332 -0
  221. package/dist/lib/evg/showcase/pages/plots.tsx +262 -0
  222. package/dist/lib/evg/showcase/pages/svg.tsx +63 -0
  223. package/dist/lib/evg/showcase/pages/tables.tsx +209 -0
  224. package/dist/lib/evg/showcase/pages/typography.tsx +43 -0
  225. package/dist/lib/evg/showcase/pages/units.tsx +35 -0
  226. package/dist/lib/evg/showcase/pages/variants.tsx +233 -0
  227. package/dist/lib/evg/showcase/pages/vector.tsx +75 -0
  228. package/dist/lib/evg/showcase/pages/views.tsx +223 -0
  229. package/dist/lib/evg/showcase/tests/chart_api_smoke.mjs +339 -0
  230. package/dist/lib/evg/showcase/tests/gl_smoke.mjs +125 -0
  231. package/dist/lib/evg/showcase/themes/chart_api-default.css +15 -0
  232. package/dist/lib/evg/showcase/themes/charts-default.css +29 -0
  233. package/dist/lib/evg/showcase/themes/drawing-default.css +35 -0
  234. package/dist/lib/evg/showcase/themes/more-default.css +128 -0
  235. package/dist/lib/evg/showcase/themes/plots-default.css +18 -0
  236. package/dist/lib/evg/showcase/themes/showcase.css +508 -0
  237. package/dist/lib/evg/showcase/themes/tables-default.css +123 -0
  238. package/dist/lib/evg/showcase/themes/variants-default.css +15 -0
  239. package/dist/lib/evg/showcase/themes/views-default.css +15 -0
  240. package/dist/lib/evg/tools/bench_vs_potrace.mjs +290 -0
  241. package/dist/lib/evg/tools/evg_image_tool.rgr +488 -0
  242. package/dist/lib/evg/tools/evg_trace_bench.rgr +114 -0
  243. package/dist/lib/evg/tools/evg_trace_cli.rgr +662 -0
  244. package/dist/lib/evg/tools/evg_trace_cpp_bench.rgr +83 -0
  245. package/dist/lib/evg/tools/run_trace_bench.sh +74 -0
  246. package/dist/lib/evg/tools/run_trace_cli_smoke.sh +128 -0
  247. package/dist/lib/evg/web/responsive/EvgResponsiveCheck.rgr +271 -0
  248. package/dist/lib/evg/web/responsive/EvgResponsiveDemo.rgr +531 -0
  249. package/dist/lib/evg/web/responsive/README.md +97 -0
  250. package/dist/lib/evg/web/responsive/build.mjs +90 -0
  251. package/dist/lib/evg/web/responsive/dom-check.mjs +169 -0
  252. package/dist/lib/evg/web/responsive/index.html +177 -0
  253. package/dist/lib/evg/web/responsive/smoke.mjs +221 -0
  254. package/dist/lib/evg/web/tools/assets-client.mjs +95 -0
  255. package/dist/lib/evg/web/tools/boot-bench.mjs +189 -0
  256. package/dist/lib/evg/web/tools/inline-assets.mjs +119 -0
  257. package/dist/lib/evg/web/tools/minify.mjs +60 -0
  258. package/dist/lib/evg/web/tracer/build.mjs +87 -0
  259. package/dist/lib/evg/web/tracer/index.html +2805 -0
  260. package/dist/lib/evg/web/tracer/sample.png +0 -0
  261. package/dist/lib/evg/web/tracer/smoke.mjs +1162 -0
  262. package/dist/lib/evgr/Cargo.lock +21 -0
  263. package/dist/lib/evgr/Cargo.toml +19 -0
  264. package/dist/lib/evgr/README.md +140 -0
  265. package/dist/lib/evgr/bench/NativeBench.rgr +246 -0
  266. package/dist/lib/evgr/bench/compare.mjs +252 -0
  267. package/dist/lib/evgr/bench/speed.mjs +277 -0
  268. package/dist/lib/evgr/bin/.gitignore +3 -0
  269. package/dist/lib/evgr/src/bin/bench.rs +106 -0
  270. package/dist/lib/evgr/src/bin/smoke.rs +13 -0
  271. package/dist/lib/evgr/src/grid.rs +730 -0
  272. package/dist/lib/evgr/src/lib.rs +1003 -0
  273. package/dist/lib/evgr/src/style.rs +468 -0
  274. package/dist/lib/evgr/src/text.rs +83 -0
  275. package/dist/lib/image/BitReader.rgr +171 -0
  276. package/dist/lib/image/Buffer.rgr +173 -0
  277. package/dist/lib/image/DCT.rgr +283 -0
  278. package/dist/lib/image/Deflate.rgr +339 -0
  279. package/dist/lib/image/HuffmanDecoder.rgr +181 -0
  280. package/dist/lib/image/ImageBuffer.rgr +706 -0
  281. package/dist/lib/image/JPEGDecoder.rgr +808 -0
  282. package/dist/lib/image/PNGDecoder.rgr +544 -0
  283. package/dist/lib/image/PNGEncoder.rgr +388 -0
  284. package/dist/lib/image/PPMImage.rgr +224 -0
  285. package/dist/lib/image/ProgressiveJPEGDecoder.rgr +1154 -0
  286. package/dist/lib/image/README.md +33 -0
  287. package/dist/lib/image/RasterBuffer.rgr +294 -0
  288. package/dist/lib/image/VP8BoolDecoder.rgr +163 -0
  289. package/dist/lib/image/WebPDecoder.rgr +433 -0
  290. package/dist/lib/image/WebPLossless.rgr +1035 -0
  291. package/dist/lib/image/WebPLossy.rgr +1929 -0
  292. package/dist/lib/image/ranger.json +9 -0
  293. package/dist/lib/image/testdata/webp/anim_2f_24x16.webp +0 -0
  294. package/dist/lib/image/testdata/webp/fixtures.txt +33 -0
  295. package/dist/lib/image/testdata/webp/gen_fixtures.py +261 -0
  296. package/dist/lib/image/testdata/webp/ll_1x1.webp +0 -0
  297. package/dist/lib/image/testdata/webp/ll_alpha_29x21.webp +0 -0
  298. package/dist/lib/image/testdata/webp/ll_gradient_64x64.webp +0 -0
  299. package/dist/lib/image/testdata/webp/ll_meta_32x32.webp +0 -0
  300. package/dist/lib/image/testdata/webp/ll_noise_17x9.webp +0 -0
  301. package/dist/lib/image/testdata/webp/ll_pal11_23x11.webp +0 -0
  302. package/dist/lib/image/testdata/webp/ll_pal2_19x7.webp +0 -0
  303. package/dist/lib/image/testdata/webp/ll_pal40_16x16.webp +0 -0
  304. package/dist/lib/image/testdata/webp/ll_pal4_13x5.webp +0 -0
  305. package/dist/lib/image/testdata/webp/ll_photo_40x30.webp +0 -0
  306. package/dist/lib/image/testdata/webp/ll_predictors_64x32.webp +0 -0
  307. package/dist/lib/image/testdata/webp/ly_1x1.webp +0 -0
  308. package/dist/lib/image/testdata/webp/ly_alph_raw_f0_21x13.webp +0 -0
  309. package/dist/lib/image/testdata/webp/ly_alph_raw_f1_21x13.webp +0 -0
  310. package/dist/lib/image/testdata/webp/ly_alph_raw_f2_21x13.webp +0 -0
  311. package/dist/lib/image/testdata/webp/ly_alph_raw_f3_21x13.webp +0 -0
  312. package/dist/lib/image/testdata/webp/ly_alph_vp8l_f0_21x13.webp +0 -0
  313. package/dist/lib/image/testdata/webp/ly_alph_vp8l_f1_21x13.webp +0 -0
  314. package/dist/lib/image/testdata/webp/ly_alph_vp8l_f2_21x13.webp +0 -0
  315. package/dist/lib/image/testdata/webp/ly_alph_vp8l_f3_21x13.webp +0 -0
  316. package/dist/lib/image/testdata/webp/ly_alpha_33x17.webp +0 -0
  317. package/dist/lib/image/testdata/webp/ly_exif_15x11.webp +0 -0
  318. package/dist/lib/image/testdata/webp/ly_i16_96x80.webp +0 -0
  319. package/dist/lib/image/testdata/webp/ly_nofilter_24x20.webp +0 -0
  320. package/dist/lib/image/testdata/webp/ly_odd_17x9.webp +0 -0
  321. package/dist/lib/image/testdata/webp/ly_photo_48x40.webp +0 -0
  322. package/dist/lib/image/testdata/webp/ly_q100_20x18.webp +0 -0
  323. package/dist/lib/image/testdata/webp/ly_sharp_40x36.webp +0 -0
  324. package/dist/lib/image/testdata/webp/ly_simple_filter_33x31.webp +0 -0
  325. package/dist/lib/image/testdata/webp/ly_vpx_parts8_37x45.webp +0 -0
  326. package/dist/lib/image/testdata/webp/ly_vpx_skip_96x80.webp +0 -0
  327. package/dist/lib/image/tests/WebPDecodeTool.rgr +81 -0
  328. package/dist/lib/image/tests/WebPDecoderTest.rgr +1162 -0
  329. package/dist/lib/image/tests/run_webp_tests.sh +39 -0
  330. package/dist/lib/rust/RsJson.rgr +468 -0
  331. package/dist/lib/rust/RsPrelude.rgr +1663 -0
  332. package/dist/lib/shell_test.rgr +7 -7
  333. package/dist/lib/stdlib.rgr +21 -5
  334. package/dist/lib/zip/ranger.json +6 -0
  335. package/dist/rgrc.js +87318 -67610
  336. package/package.json +1010 -1040
  337. package/dist/README.md +0 -117
  338. package/dist/package.json +0 -47
@@ -0,0 +1,692 @@
1
+ ; SPDX-License-Identifier: MIT
2
+
3
+ ; ==============================================================================
4
+ ; EVGPatchTest — an edit that cannot be undone is a bug, not a feature
5
+ ; ==============================================================================
6
+ ;
7
+ ; `EVGPatch` makes one promise that everything above it relies on: after
8
+ ; `apply` and then `rollback`, the tree is what it was. Most of this file is
9
+ ; that promise, asked of each kind of op, because the ways it can be broken are
10
+ ; all quiet — a value restored but its inline flag left set, a subtree put back
11
+ ; one index over, a rejected op that already wrote half of itself.
12
+ ;
13
+ ; The last test is the one that guards the file's own structure: every property
14
+ ; name `kindOf` admits must be readable and clearable, or the "an op that
15
+ ; cannot be inverted does not apply" rule has a hole in exactly the place
16
+ ; nobody looks.
17
+ ;
18
+ ; npm run evg:patch:test
19
+ ; ==============================================================================
20
+
21
+ Import "EVGPatch.rgr"
22
+ Import "EVGCodepoint.rgr"
23
+ Import "EVGTreeJson.rgr"
24
+ Import "EVGElement.rgr"
25
+ Import "EVGInspect.rgr"
26
+ Import "EVGReject.rgr"
27
+
28
+ class EVGPatchTest {
29
+ def passed:int 0
30
+ def failed:int 0
31
+
32
+ sfn m@(main):void () {
33
+ def t (new EVGPatchTest())
34
+ t.run()
35
+ }
36
+
37
+ fn ok:void (what:string cond:boolean) {
38
+ if cond {
39
+ passed = (passed + 1)
40
+ print (" PASS " + what)
41
+ } {
42
+ failed = (failed + 1)
43
+ print (" FAIL " + what)
44
+ }
45
+ }
46
+
47
+ fn same:void (what:string got:string want:string) {
48
+ def hit:boolean (got == want)
49
+ if hit {
50
+ passed = (passed + 1)
51
+ print (" PASS " + what)
52
+ } {
53
+ failed = (failed + 1)
54
+ print (((((" FAIL " + what) + " — got \"") + got) + "\" want \"") + (want + "\""))
55
+ }
56
+ }
57
+
58
+ ; --- a tree to edit -------------------------------------------------------
59
+ ;
60
+ ; 0 root, a column
61
+ ; 0/0 card
62
+ ; 0/0/0 title (span, "Orders")
63
+ ; 0/k:side an aside, keyed — so the keyed path is exercised too
64
+
65
+ fn build:EVGElement () {
66
+ def root:EVGElement (EVGElement.createDiv())
67
+ root.className = "page"
68
+ def card:EVGElement (EVGElement.createDiv())
69
+ card.className = "card"
70
+ def title:EVGElement (EVGElement.createSpan())
71
+ title.textContent = "Orders"
72
+ card.addChild(title)
73
+ root.addChild(card)
74
+ def side:EVGElement (EVGElement.createDiv())
75
+ side.key = "side"
76
+ root.addChild(side)
77
+ return root
78
+ }
79
+
80
+ fn ops:[EVGPatchOp] () {
81
+ def a:[EVGPatchOp]
82
+ return a
83
+ }
84
+
85
+ ; --- set-prop -------------------------------------------------------------
86
+
87
+ fn testSetProp:void () {
88
+ print ""
89
+ print "-- set-prop"
90
+ def root:EVGElement (this.build())
91
+ def p (new EVGPatch())
92
+ def list:[EVGPatchOp] (this.ops())
93
+ push list (EVGPatchOp.setProp("0/0" "background-color" "#ff0000"))
94
+ def r:EVGPatchResult (p.apply(root list))
95
+ this.ok("it applied" r.ok)
96
+ this.ok("one op" (r.applied == 1))
97
+ def card:EVGElement (itemAt root.children 0)
98
+ this.ok("the colour is set" card.backgroundColor.isSet)
99
+ this.ok("and marked inline" (card.hasInline("background-color")))
100
+ this.ok("one inverse recorded" ((array_length r.inverse) == 1))
101
+
102
+ p.rollback(root)
103
+ this.ok("rollback unset it again" (card.backgroundColor.isSet == false))
104
+ this.ok("and unmarked it" ((card.hasInline("background-color")) == false))
105
+ }
106
+
107
+ fn testSetPropOverExisting:void () {
108
+ print ""
109
+ print "-- set-prop over a value that was already there"
110
+ def root:EVGElement (this.build())
111
+ def card:EVGElement (itemAt root.children 0)
112
+ card.setAttribute("width" "300px")
113
+ card.markInline("width")
114
+ def before:string (EVGPatch.readProp(card "width"))
115
+ def p (new EVGPatch())
116
+ def list:[EVGPatchOp] (this.ops())
117
+ push list (EVGPatchOp.setProp("0/0" "width" "50%"))
118
+ def r:EVGPatchResult (p.apply(root list))
119
+ this.ok("it applied" r.ok)
120
+ this.same("the new width" (EVGPatch.readProp(card "width")) "50%")
121
+ p.rollback(root)
122
+ this.same("rollback put the old one back" (EVGPatch.readProp(card "width")) before)
123
+ this.ok("and it is still inline, as it was" (card.hasInline("width")))
124
+ }
125
+
126
+ ; An id is the one thing on a node that nothing paints and everything else
127
+ ; depends on: the hit test answers with it, and an app turns it into an
128
+ ; event. It round-trips like any other edit, and it refuses to name two
129
+ ; nodes the same, because a press can only reach one of them.
130
+ fn testSetId:void () {
131
+ print ""
132
+ print "-- set-id"
133
+ def root:EVGElement (this.build())
134
+ def p (new EVGPatch())
135
+ def list:[EVGPatchOp] (this.ops())
136
+ push list (EVGPatchOp.setId("0/0" "nav.map"))
137
+ def r:EVGPatchResult (p.apply(root list))
138
+ this.ok("it applied" r.ok)
139
+ def card:EVGElement (itemAt root.children 0)
140
+ this.same("the node is named" card.id "nav.map")
141
+ p.rollback(root)
142
+ this.same("rollback takes the name off again" card.id "")
143
+ }
144
+
145
+ fn testDuplicateId:void () {
146
+ print ""
147
+ print "-- two nodes, one id"
148
+ def root:EVGElement (this.build())
149
+ def p (new EVGPatch())
150
+ def list:[EVGPatchOp] (this.ops())
151
+ push list (EVGPatchOp.setId("0/0" "nav.map"))
152
+ push list (EVGPatchOp.setId("0/k:side" "nav.map"))
153
+ def r:EVGPatchResult (p.apply(root list))
154
+ this.ok("the batch is refused" (r.ok == false))
155
+ this.ok("the reason names the node that has it" ((indexOf (r.reason()) "0/0") >= 0))
156
+ def card:EVGElement (itemAt root.children 0)
157
+ this.same("and nothing landed" card.id "")
158
+ }
159
+
160
+ fn testUnknownProperty:void () {
161
+ print ""
162
+ print "-- a property the engine does not implement"
163
+ def root:EVGElement (this.build())
164
+ def p (new EVGPatch())
165
+ def list:[EVGPatchOp] (this.ops())
166
+ push list (EVGPatchOp.setProp("0/0" "aspect-ratio" "16/9"))
167
+ def r:EVGPatchResult (p.apply(root list))
168
+ this.ok("it was rejected" (r.ok == false))
169
+ this.ok("nothing applied" (r.applied == 0))
170
+ this.ok("with a reason" ((strlen (r.reason())) > 0))
171
+ def card:EVGElement (itemAt root.children 0)
172
+ this.ok("and nothing was marked inline" ((card.hasInline("aspect-ratio")) == false))
173
+ }
174
+
175
+ fn testValueTheEngineRejects:void () {
176
+ print ""
177
+ print "-- a known property, a value it cannot read"
178
+ def root:EVGElement (this.build())
179
+ def card:EVGElement (itemAt root.children 0)
180
+ card.setAttribute("width" "300px")
181
+ card.markInline("width")
182
+ def p (new EVGPatch())
183
+ def list:[EVGPatchOp] (this.ops())
184
+ push list (EVGPatchOp.setProp("0/0" "width" "banana"))
185
+ def r:EVGPatchResult (p.apply(root list))
186
+ this.ok("it was rejected" (r.ok == false))
187
+ this.same("and the old width survived" (EVGPatch.readProp(card "width")) "300px")
188
+ }
189
+
190
+ fn testNoSuchNode:void () {
191
+ print ""
192
+ print "-- an address that is not there"
193
+ def root:EVGElement (this.build())
194
+ def p (new EVGPatch())
195
+ def list:[EVGPatchOp] (this.ops())
196
+ push list (EVGPatchOp.setProp("0/9/4" "color" "#000000"))
197
+ def r:EVGPatchResult (p.apply(root list))
198
+ this.ok("it was rejected" (r.ok == false))
199
+ this.ok("the reason names the path" ((indexOf (r.reason()) "0/9/4") >= 0))
200
+ }
201
+
202
+ ; --- all or nothing -------------------------------------------------------
203
+
204
+ fn testAllOrNothing:void () {
205
+ print ""
206
+ print "-- a bad op in the middle of a good batch"
207
+ def root:EVGElement (this.build())
208
+ def card:EVGElement (itemAt root.children 0)
209
+ def title:EVGElement (itemAt card.children 0)
210
+ def p (new EVGPatch())
211
+ def list:[EVGPatchOp] (this.ops())
212
+ push list (EVGPatchOp.setProp("0/0" "background-color" "#ff0000"))
213
+ push list (EVGPatchOp.setText("0/0/0" "Invoices"))
214
+ push list (EVGPatchOp.setProp("0/0" "aspect-ratio" "16/9"))
215
+ push list (EVGPatchOp.setProp("0/0" "color" "#00ff00"))
216
+ def r:EVGPatchResult (p.apply(root list))
217
+ this.ok("the batch failed" (r.ok == false))
218
+ this.ok("and reports nothing applied" (r.applied == 0))
219
+ this.ok("the colour from op 0 is gone" (card.backgroundColor.isSet == false))
220
+ this.same("and the text from op 1 is back" title.textContent "Orders")
221
+ }
222
+
223
+ ; --- set-text -------------------------------------------------------------
224
+
225
+ fn testSetText:void () {
226
+ print ""
227
+ print "-- set-text"
228
+ def root:EVGElement (this.build())
229
+ def card:EVGElement (itemAt root.children 0)
230
+ def title:EVGElement (itemAt card.children 0)
231
+ def p (new EVGPatch())
232
+ def list:[EVGPatchOp] (this.ops())
233
+ push list (EVGPatchOp.setText("0/0/0" "Invoices"))
234
+ def r:EVGPatchResult (p.apply(root list))
235
+ this.ok("it applied" r.ok)
236
+ this.same("the new text" title.textContent "Invoices")
237
+ p.rollback(root)
238
+ this.same("rollback restored it" title.textContent "Orders")
239
+ }
240
+
241
+ fn testSetTextOnAParent:void () {
242
+ print ""
243
+ print "-- set-text where there are children to lose"
244
+ def root:EVGElement (this.build())
245
+ def p (new EVGPatch())
246
+ def list:[EVGPatchOp] (this.ops())
247
+ push list (EVGPatchOp.setText("0/0" "nope"))
248
+ def r:EVGPatchResult (p.apply(root list))
249
+ this.ok("it was rejected" (r.ok == false))
250
+ }
251
+
252
+ ; --- insert / remove / move -----------------------------------------------
253
+
254
+ fn testInsert:void () {
255
+ print ""
256
+ print "-- insert"
257
+ def root:EVGElement (this.build())
258
+ def card:EVGElement (itemAt root.children 0)
259
+ def p (new EVGPatch())
260
+ def list:[EVGPatchOp] (this.ops())
261
+ push list (EVGPatchOp.insertNode("0/0" 0 "span"))
262
+ def r:EVGPatchResult (p.apply(root list))
263
+ this.ok("it applied" r.ok)
264
+ this.ok("the card has two children" ((array_length card.children) == 2))
265
+ def first:EVGElement (itemAt card.children 0)
266
+ this.same("the new one is first" first.tagName "span")
267
+ p.rollback(root)
268
+ this.ok("rollback took it out" ((array_length card.children) == 1))
269
+ def back:EVGElement (itemAt card.children 0)
270
+ this.same("leaving the original" back.textContent "Orders")
271
+ }
272
+
273
+ ; A CONTROL, not an empty box. A switch is a track with a thumb in it, so
274
+ ; an insert that can only carry one tag makes an agent build one out of a
275
+ ; dozen ops — and a dozen ops is how a screen ends up with a drawing of a
276
+ ; switch rather than a switch.
277
+ fn testInsertSubtree:void () {
278
+ print ""
279
+ print "-- insert a whole subtree"
280
+ def root:EVGElement (this.build())
281
+ def card:EVGElement (itemAt root.children 0)
282
+ def track:EVGElement (EVGElement.createDiv())
283
+ track.className = "ui-switch-track"
284
+ def thumb:EVGElement (EVGElement.createDiv())
285
+ thumb.className = "ui-switch-thumb"
286
+ track.addChild(thumb)
287
+ def p (new EVGPatch())
288
+ def list:[EVGPatchOp] (this.ops())
289
+ push list (EVGPatchOp.insertTree("0/0" 0 track))
290
+ def r:EVGPatchResult (p.apply(root list))
291
+ this.ok("it applied" r.ok)
292
+ def first:EVGElement (itemAt card.children 0)
293
+ this.same("the subtree went in whole" first.className "ui-switch-track")
294
+ this.ok("with what was inside it" ((array_length first.children) == 1))
295
+ p.rollback(root)
296
+ this.ok("rollback takes the whole thing out again" ((array_length card.children) == 1))
297
+ }
298
+
299
+ fn testInsertUnknownTag:void () {
300
+ print ""
301
+ print "-- insert of something that is not an element"
302
+ def root:EVGElement (this.build())
303
+ def p (new EVGPatch())
304
+ def list:[EVGPatchOp] (this.ops())
305
+ push list (EVGPatchOp.insertNode("0/0" 0 "marquee"))
306
+ def r:EVGPatchResult (p.apply(root list))
307
+ this.ok("it was rejected" (r.ok == false))
308
+ }
309
+
310
+ fn testRemoveAndRestore:void () {
311
+ print ""
312
+ print "-- remove, and put it back with its subtree"
313
+ def root:EVGElement (this.build())
314
+ def p (new EVGPatch())
315
+ def list:[EVGPatchOp] (this.ops())
316
+ push list (EVGPatchOp.removeNode("0/0"))
317
+ def r:EVGPatchResult (p.apply(root list))
318
+ this.ok("it applied" r.ok)
319
+ this.ok("the root has one child left" ((array_length root.children) == 1))
320
+ def left:EVGElement (itemAt root.children 0)
321
+ this.same("and it is the keyed one" left.key "side")
322
+
323
+ p.rollback(root)
324
+ this.ok("rollback gave the card back" ((array_length root.children) == 2))
325
+ def card:EVGElement (itemAt root.children 0)
326
+ this.same("in its old place" card.className "card")
327
+ this.ok("with its child" ((array_length card.children) == 1))
328
+ def title:EVGElement (itemAt card.children 0)
329
+ this.same("and its text" title.textContent "Orders")
330
+ }
331
+
332
+ fn testRemoveRoot:void () {
333
+ print ""
334
+ print "-- remove of the root"
335
+ def root:EVGElement (this.build())
336
+ def p (new EVGPatch())
337
+ def list:[EVGPatchOp] (this.ops())
338
+ push list (EVGPatchOp.removeNode("0"))
339
+ def r:EVGPatchResult (p.apply(root list))
340
+ this.ok("it was rejected" (r.ok == false))
341
+ }
342
+
343
+ fn testKeyedPath:void () {
344
+ print ""
345
+ print "-- a keyed address"
346
+ def root:EVGElement (this.build())
347
+ def side:EVGElement (itemAt root.children 1)
348
+ def p (new EVGPatch())
349
+ def list:[EVGPatchOp] (this.ops())
350
+ push list (EVGPatchOp.setProp("0/k:side" "width" "120px"))
351
+ def r:EVGPatchResult (p.apply(root list))
352
+ this.ok("it applied" r.ok)
353
+ this.same("to the keyed node" (EVGPatch.readProp(side "width")) "120px")
354
+ p.rollback(root)
355
+ this.same("and rolled back" (EVGPatch.readProp(side "width")) "")
356
+ }
357
+
358
+ fn testMove:void () {
359
+ print ""
360
+ print "-- move"
361
+ def root:EVGElement (this.build())
362
+ def card:EVGElement (itemAt root.children 0)
363
+ def side:EVGElement (itemAt root.children 1)
364
+ def p (new EVGPatch())
365
+ def list:[EVGPatchOp] (this.ops())
366
+ push list (EVGPatchOp.move("0/0/0" "0/k:side" 0))
367
+ def r:EVGPatchResult (p.apply(root list))
368
+ this.ok("it applied" r.ok)
369
+ this.ok("the card lost its child" ((array_length card.children) == 0))
370
+ this.ok("the aside gained one" ((array_length side.children) == 1))
371
+ p.rollback(root)
372
+ this.ok("rollback moved it home" ((array_length card.children) == 1))
373
+ this.ok("and emptied the aside" ((array_length side.children) == 0))
374
+ def title:EVGElement (itemAt card.children 0)
375
+ this.same("the same node" title.textContent "Orders")
376
+ }
377
+
378
+ fn testMoveIntoItself:void () {
379
+ print ""
380
+ print "-- move of a node into its own subtree"
381
+ def root:EVGElement (this.build())
382
+ def p (new EVGPatch())
383
+ def list:[EVGPatchOp] (this.ops())
384
+ push list (EVGPatchOp.move("0/0" "0/0/0" 0))
385
+ def r:EVGPatchResult (p.apply(root list))
386
+ this.ok("it was rejected" (r.ok == false))
387
+ def card:EVGElement (itemAt root.children 0)
388
+ this.ok("and the card still has its child" ((array_length card.children) == 1))
389
+ }
390
+
391
+ ; --- the table's own invariant --------------------------------------------
392
+ ;
393
+ ; Every name `kindOf` admits has to be answerable by `readProp` and
394
+ ; `clearProp`. A name in one list and not the others is the failure mode
395
+ ; this file exists to make loud: it would present as "this property is
396
+ ; patchable" followed by an undo that silently does nothing.
397
+
398
+ fn testTableIsWhole:void () {
399
+ print ""
400
+ print "-- the patchable set answers in all three places"
401
+ def list:[string] (EVGPatch.patchableNames())
402
+ def admitted:int 0
403
+ def clearable:int 0
404
+ def i:int 0
405
+ while (i < (array_length list)) {
406
+ def name:string (itemAt list i)
407
+ if (EVGPatch.readable(name)) {
408
+ admitted = (admitted + 1)
409
+ } {
410
+ print (" kindOf does not admit " + name)
411
+ }
412
+ def el:EVGElement (EVGElement.createDiv())
413
+ if (EVGPatch.clearProp(el name)) {
414
+ clearable = (clearable + 1)
415
+ } {
416
+ print (" clearProp cannot clear " + name)
417
+ }
418
+ i = (i + 1)
419
+ }
420
+ def n:int (array_length list)
421
+ this.ok("every name is admitted" (admitted == n))
422
+ this.ok("every name is clearable" (clearable == n))
423
+ }
424
+
425
+ fn testClearedIsWhatAFreshElementSays:void () {
426
+ print ""
427
+ print "-- clearing restores what a fresh element reads"
428
+ def list:[string] (EVGPatch.patchableNames())
429
+ def matched:int 0
430
+ def i:int 0
431
+ while (i < (array_length list)) {
432
+ def name:string (itemAt list i)
433
+ def fresh:EVGElement (EVGElement.createDiv())
434
+ def want:string (EVGPatch.readProp(fresh name))
435
+ def used:EVGElement (EVGElement.createDiv())
436
+ used.setAttribute(name "10px")
437
+ def cleared:boolean (EVGPatch.clearProp(used name))
438
+ def got:string (EVGPatch.readProp(used name))
439
+ if (got == want) {
440
+ matched = (matched + 1)
441
+ } {
442
+ print ((((" " + name) + ": cleared to \"") + got) + (("\" but fresh reads \"" + want) + "\""))
443
+ }
444
+ i = (i + 1)
445
+ }
446
+ this.ok("all of them" (matched == (array_length list)))
447
+ }
448
+
449
+ fn testNotPatchable:void () {
450
+ print ""
451
+ print "-- a name nothing here can read"
452
+ this.ok("aspect-ratio is not patchable" ((EVGPatch.readable("aspect-ratio")) == false))
453
+ this.ok("width is" (EVGPatch.readable("width")))
454
+ this.ok("camelCase finds it too" (EVGPatch.readable("minWidth")))
455
+ this.ok("and class is an alias for class-name" (EVGPatch.readable("class")))
456
+ }
457
+
458
+
459
+ ; --- the document format --------------------------------------------------
460
+ ;
461
+ ; Round-trip is the only claim worth testing here: write, read, write, and
462
+ ; the two texts are the same. It catches a property the writer emits and
463
+ ; the reader ignores, and a reader that quietly builds the wrong tag, both
464
+ ; of which otherwise show up much later as a document that drifts a little
465
+ ; every time it is saved.
466
+
467
+ fn testRoundTrip:void () {
468
+ print ""
469
+ print "-- write, read, write"
470
+ def root:EVGElement (this.build())
471
+ def card:EVGElement (itemAt root.children 0)
472
+ card.setAttribute("background-color" "#ff0000")
473
+ card.markInline("background-color")
474
+ card.setAttribute("width" "320px")
475
+ card.markInline("width")
476
+ def once:string (EVGTreeJson.toText(root))
477
+ def back@(optional):EVGElement (EVGTreeJson.fromText(once))
478
+ this.ok("it read back" ((null? back) == false))
479
+ if (null? back) {
480
+ return
481
+ }
482
+ def again:EVGElement (unwrap back)
483
+ def twice:string (EVGTreeJson.toText(again))
484
+ this.same("the two texts agree" twice once)
485
+ def readCard:EVGElement (itemAt again.children 0)
486
+ ; the reader's canonical form is what setAttribute takes back, which is rgb()
487
+ this.same("the colour survived" (EVGPatch.readProp(readCard "background-color")) "rgb(255,0,0)")
488
+ this.same("the width survived" (EVGPatch.readProp(readCard "width")) "320px")
489
+ this.same("the class survived" readCard.className "card")
490
+ def readTitle:EVGElement (itemAt readCard.children 0)
491
+ this.same("the text survived" readTitle.textContent "Orders")
492
+ this.same("and the tag" readTitle.tagName "span")
493
+ def readSide:EVGElement (itemAt again.children 1)
494
+ this.same("as did the key" readSide.key "side")
495
+ }
496
+
497
+ ; WHAT A NODE IS survives the file. A document that cannot say "this is a
498
+ ; switch" leaves everything downstream guessing from the shape, and a
499
+ ; control drawn out of boxes is exactly the same shape as a real one.
500
+ fn testMeaningRoundTrip:void () {
501
+ print ""
502
+ print "-- what a node IS, written and read"
503
+ def root:EVGElement (this.build())
504
+ def card:EVGElement (itemAt root.children 0)
505
+ card.role = "switch"
506
+ card.a11yLabel = "Wi-Fi"
507
+ card.a11yChecked = 2
508
+ def kid:EVGElement (itemAt card.children 0)
509
+ kid.a11yHidden = true
510
+ def once:string (EVGTreeJson.toText(root))
511
+ this.ok("the role is in the file" ((indexOf once "\"role\":\"switch\"") >= 0))
512
+ def back@(optional):EVGElement (EVGTreeJson.fromText(once))
513
+ this.ok("it read back" ((null? back) == false))
514
+ if (null? back) {
515
+ return
516
+ }
517
+ def again:EVGElement (unwrap back)
518
+ def readCard:EVGElement (itemAt again.children 0)
519
+ this.same("the role survived" readCard.role "switch")
520
+ this.same("the name survived" readCard.a11yLabel "Wi-Fi")
521
+ this.ok("the state survived" (readCard.a11yChecked == 2))
522
+ def readKid:EVGElement (itemAt readCard.children 0)
523
+ this.ok("a part stays hidden from a reader" readKid.a11yHidden)
524
+ this.same("the two texts agree" (EVGTreeJson.toText(again)) once)
525
+ }
526
+
527
+ fn testDefaultsAreNotWritten:void () {
528
+ print ""
529
+ print "-- a fresh tree says almost nothing"
530
+ def plain:EVGElement (EVGElement.createDiv())
531
+ def text:string (EVGTreeJson.toText(plain))
532
+ this.ok("no props block" ((indexOf text "props") < 0))
533
+ this.ok("but it has its tag" ((indexOf text "\"tag\":\"div\"") >= 0))
534
+ }
535
+
536
+ ; A document an agent wrote by hand. Anything that is not ASCII arrives as
537
+ ; `\uXXXX` — that is what every JSON writer emits — and the reader used to
538
+ ; drop the backslash and keep the four hex digits, so a middot reached the
539
+ ; screen as the literal text `u00b7`. It reads as a broken font, which is
540
+ ; the wrong thing to go looking at.
541
+ fn testUnicodeEscapes:void () {
542
+ print ""
543
+ print "-- \\uXXXX, including a surrogate pair"
544
+ def json:string "{\"evg\":1,\"root\":{\"tag\":\"div\",\"children\":[{\"tag\":\"span\",\"text\":\"7h \\u00b7 42m \\u203a \\ud83d\\ude00\"}]}}"
545
+ def back@(optional):EVGElement (EVGTreeJson.fromText(json))
546
+ this.ok("it read" ((null? back) == false))
547
+ if (null? back) {
548
+ return
549
+ }
550
+ def tree:EVGElement (unwrap back)
551
+ def label:EVGElement (itemAt tree.children 0)
552
+ def want:string ((((("7h " + (EVGCodepoint.toStr(183))) + " 42m ") + (EVGCodepoint.toStr(8250))) + " ") + (EVGCodepoint.toStr(128512)))
553
+ this.same("every escape became its character" label.textContent want)
554
+ ; And it survives the way back out, which is where a half-decoded
555
+ ; string would show up as mojibake instead of a missing character.
556
+ def again@(optional):EVGElement (EVGTreeJson.fromText((EVGTreeJson.toText(tree))))
557
+ if (null? again) {
558
+ this.ok("it wrote back" false)
559
+ return
560
+ }
561
+ def back2:EVGElement (unwrap again)
562
+ def label2:EVGElement (itemAt back2.children 0)
563
+ this.same("and the round trip" label2.textContent want)
564
+ }
565
+
566
+ ; A malformed escape is not a crash and not a silent drop: it stays as it
567
+ ; was written, so the mistake is visible in the document that has it.
568
+ fn testBadEscape:void () {
569
+ print ""
570
+ print "-- an escape that is not one"
571
+ def json:string "{\"evg\":1,\"root\":{\"tag\":\"div\",\"children\":[{\"tag\":\"span\",\"text\":\"half \\u00zz\"}]}}"
572
+ def back@(optional):EVGElement (EVGTreeJson.fromText(json))
573
+ this.ok("it still read" ((null? back) == false))
574
+ if (null? back) {
575
+ return
576
+ }
577
+ def tree:EVGElement (unwrap back)
578
+ def kid:EVGElement (itemAt tree.children 0)
579
+ this.same("and kept what was written" kid.textContent "half u00zz")
580
+ }
581
+
582
+ fn testTextWithQuotes:void () {
583
+ print ""
584
+ print "-- text that needs escaping"
585
+ def root:EVGElement (EVGElement.createDiv())
586
+ def label:EVGElement (EVGElement.createSpan())
587
+ label.textContent = "a \"quoted\" line\nand a second"
588
+ root.addChild(label)
589
+ def text:string (EVGTreeJson.toText(root))
590
+ def back@(optional):EVGElement (EVGTreeJson.fromText(text))
591
+ this.ok("it read back" ((null? back) == false))
592
+ if (null? back) {
593
+ return
594
+ }
595
+ def again:EVGElement (unwrap back)
596
+ def readLabel:EVGElement (itemAt again.children 0)
597
+ this.same("the text came through" readLabel.textContent label.textContent)
598
+ }
599
+
600
+ fn testPatchThenSave:void () {
601
+ print ""
602
+ print "-- an edit survives being written down"
603
+ def root:EVGElement (this.build())
604
+ def p (new EVGPatch())
605
+ def list:[EVGPatchOp] (this.ops())
606
+ push list (EVGPatchOp.setProp("0/0" "padding-left" "16px"))
607
+ push list (EVGPatchOp.setText("0/0/0" "Invoices"))
608
+ def r:EVGPatchResult (p.apply(root list))
609
+ this.ok("the patch applied" r.ok)
610
+ def saved:string (EVGTreeJson.toText(root))
611
+ def back@(optional):EVGElement (EVGTreeJson.fromText(saved))
612
+ this.ok("it read back" ((null? back) == false))
613
+ if (null? back) {
614
+ return
615
+ }
616
+ def again:EVGElement (unwrap back)
617
+ def readCard:EVGElement (itemAt again.children 0)
618
+ this.same("the padding is in the file" (EVGPatch.readProp(readCard "padding-left")) "16px")
619
+ def readTitle:EVGElement (itemAt readCard.children 0)
620
+ this.same("and so is the text" readTitle.textContent "Invoices")
621
+ }
622
+
623
+ fn testNotThisFormat:void () {
624
+ print ""
625
+ print "-- something that is not a document"
626
+ def back@(optional):EVGElement (EVGTreeJson.fromText("[1,2,3]"))
627
+ this.ok("nothing came back" (null? back))
628
+ }
629
+
630
+
631
+ ; The bug this guards: `EVGBox` keeps the authored unit and the px layout
632
+ ; resolves from it, and reading the px gave "0.00px" for a padding that had
633
+ ; just been set — so the inverse restored a number nobody wrote.
634
+ fn testBoxSidesReadWhatWasWritten:void () {
635
+ print ""
636
+ print "-- a box side, before anything is laid out"
637
+ def root:EVGElement (this.build())
638
+ def card:EVGElement (itemAt root.children 0)
639
+ def p (new EVGPatch())
640
+ def list:[EVGPatchOp] (this.ops())
641
+ push list (EVGPatchOp.setProp("0/0" "padding-left" "16px"))
642
+ push list (EVGPatchOp.setProp("0/0" "margin-top" "2em"))
643
+ def r:EVGPatchResult (p.apply(root list))
644
+ this.ok("it applied" r.ok)
645
+ this.same("the padding reads as written" (EVGPatch.readProp(card "padding-left")) "16px")
646
+ this.same("and the margin keeps its unit" (EVGPatch.readProp(card "margin-top")) "2em")
647
+ p.rollback(root)
648
+ this.same("rollback clears the padding" (EVGPatch.readProp(card "padding-left")) "")
649
+ this.same("and the margin" (EVGPatch.readProp(card "margin-top")) "")
650
+ }
651
+
652
+ fn run:void () {
653
+ print "=== EVGPatch: every edit carries its own undo ==="
654
+ this.testSetProp()
655
+ this.testSetPropOverExisting()
656
+ this.testSetId()
657
+ this.testDuplicateId()
658
+ this.testUnknownProperty()
659
+ this.testValueTheEngineRejects()
660
+ this.testNoSuchNode()
661
+ this.testAllOrNothing()
662
+ this.testSetText()
663
+ this.testSetTextOnAParent()
664
+ this.testInsert()
665
+ this.testInsertSubtree()
666
+ this.testMeaningRoundTrip()
667
+ this.testInsertUnknownTag()
668
+ this.testRemoveAndRestore()
669
+ this.testRemoveRoot()
670
+ this.testKeyedPath()
671
+ this.testMove()
672
+ this.testMoveIntoItself()
673
+ this.testTableIsWhole()
674
+ this.testClearedIsWhatAFreshElementSays()
675
+ this.testNotPatchable()
676
+ this.testBoxSidesReadWhatWasWritten()
677
+ this.testRoundTrip()
678
+ this.testDefaultsAreNotWritten()
679
+ this.testTextWithQuotes()
680
+ this.testUnicodeEscapes()
681
+ this.testBadEscape()
682
+ this.testPatchThenSave()
683
+ this.testNotThisFormat()
684
+ print ""
685
+ print (("passed = " + (to_string passed)) + (" failed = " + (to_string failed)))
686
+ if (failed > 0) {
687
+ print "FAILURES"
688
+ } {
689
+ print "ALL PASS"
690
+ }
691
+ }
692
+ }