presently 0.1.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 (215) hide show
  1. checksums.yaml +7 -0
  2. data/bin/presently +13 -0
  3. data/lib/presently/application.rb +104 -0
  4. data/lib/presently/clock.rb +77 -0
  5. data/lib/presently/display_view.rb +73 -0
  6. data/lib/presently/environment/application.rb +62 -0
  7. data/lib/presently/page.rb +38 -0
  8. data/lib/presently/page.xrb +31 -0
  9. data/lib/presently/presentation.rb +72 -0
  10. data/lib/presently/presentation_controller.rb +181 -0
  11. data/lib/presently/presenter_view.rb +264 -0
  12. data/lib/presently/slide.rb +148 -0
  13. data/lib/presently/slide_view.rb +92 -0
  14. data/lib/presently/state.rb +66 -0
  15. data/lib/presently/version.rb +9 -0
  16. data/lib/presently.rb +9 -0
  17. data/license.md +21 -0
  18. data/public/_components/@socketry/syntax/Syntax/CodeElement.js +337 -0
  19. data/public/_components/@socketry/syntax/Syntax/Errors.js +52 -0
  20. data/public/_components/@socketry/syntax/Syntax/Language/apache.js +49 -0
  21. data/public/_components/@socketry/syntax/Syntax/Language/applescript.js +157 -0
  22. data/public/_components/@socketry/syntax/Syntax/Language/assembly.js +42 -0
  23. data/public/_components/@socketry/syntax/Syntax/Language/bash-script.js +108 -0
  24. data/public/_components/@socketry/syntax/Syntax/Language/bash.js +32 -0
  25. data/public/_components/@socketry/syntax/Syntax/Language/basic.js +232 -0
  26. data/public/_components/@socketry/syntax/Syntax/Language/c++.js +1 -0
  27. data/public/_components/@socketry/syntax/Syntax/Language/c.js +1 -0
  28. data/public/_components/@socketry/syntax/Syntax/Language/clang.js +201 -0
  29. data/public/_components/@socketry/syntax/Syntax/Language/cpp.js +1 -0
  30. data/public/_components/@socketry/syntax/Syntax/Language/csharp.js +166 -0
  31. data/public/_components/@socketry/syntax/Syntax/Language/css.js +244 -0
  32. data/public/_components/@socketry/syntax/Syntax/Language/diff.js +24 -0
  33. data/public/_components/@socketry/syntax/Syntax/Language/go.js +135 -0
  34. data/public/_components/@socketry/syntax/Syntax/Language/haskell.js +110 -0
  35. data/public/_components/@socketry/syntax/Syntax/Language/html.js +69 -0
  36. data/public/_components/@socketry/syntax/Syntax/Language/io.js +68 -0
  37. data/public/_components/@socketry/syntax/Syntax/Language/java.js +134 -0
  38. data/public/_components/@socketry/syntax/Syntax/Language/javascript.js +89 -0
  39. data/public/_components/@socketry/syntax/Syntax/Language/json.js +36 -0
  40. data/public/_components/@socketry/syntax/Syntax/Language/lisp.js +38 -0
  41. data/public/_components/@socketry/syntax/Syntax/Language/lua.js +87 -0
  42. data/public/_components/@socketry/syntax/Syntax/Language/markdown.js +112 -0
  43. data/public/_components/@socketry/syntax/Syntax/Language/nginx.js +37 -0
  44. data/public/_components/@socketry/syntax/Syntax/Language/objective-c.js +1 -0
  45. data/public/_components/@socketry/syntax/Syntax/Language/ocaml.js +225 -0
  46. data/public/_components/@socketry/syntax/Syntax/Language/pascal.js +166 -0
  47. data/public/_components/@socketry/syntax/Syntax/Language/patch.js +2 -0
  48. data/public/_components/@socketry/syntax/Syntax/Language/perl5.js +317 -0
  49. data/public/_components/@socketry/syntax/Syntax/Language/php-script.js +112 -0
  50. data/public/_components/@socketry/syntax/Syntax/Language/php.js +18 -0
  51. data/public/_components/@socketry/syntax/Syntax/Language/plain.js +20 -0
  52. data/public/_components/@socketry/syntax/Syntax/Language/protobuf.js +77 -0
  53. data/public/_components/@socketry/syntax/Syntax/Language/python.js +208 -0
  54. data/public/_components/@socketry/syntax/Syntax/Language/ruby.js +124 -0
  55. data/public/_components/@socketry/syntax/Syntax/Language/scala.js +81 -0
  56. data/public/_components/@socketry/syntax/Syntax/Language/smalltalk.js +30 -0
  57. data/public/_components/@socketry/syntax/Syntax/Language/sql.js +865 -0
  58. data/public/_components/@socketry/syntax/Syntax/Language/super-collider.js +70 -0
  59. data/public/_components/@socketry/syntax/Syntax/Language/swift.js +176 -0
  60. data/public/_components/@socketry/syntax/Syntax/Language/xml.js +76 -0
  61. data/public/_components/@socketry/syntax/Syntax/Language/xrb.js +33 -0
  62. data/public/_components/@socketry/syntax/Syntax/Language/yaml.js +29 -0
  63. data/public/_components/@socketry/syntax/Syntax/Language.js +276 -0
  64. data/public/_components/@socketry/syntax/Syntax/Loader.js +78 -0
  65. data/public/_components/@socketry/syntax/Syntax/Match.js +546 -0
  66. data/public/_components/@socketry/syntax/Syntax/Rule.js +306 -0
  67. data/public/_components/@socketry/syntax/Syntax.js +356 -0
  68. data/public/_components/@socketry/syntax/bin/syntax-ast.js +42 -0
  69. data/public/_components/@socketry/syntax/examples/_template.html +53 -0
  70. data/public/_components/@socketry/syntax/examples/apache.html +72 -0
  71. data/public/_components/@socketry/syntax/examples/applescript.html +72 -0
  72. data/public/_components/@socketry/syntax/examples/assembly.html +74 -0
  73. data/public/_components/@socketry/syntax/examples/bash.html +90 -0
  74. data/public/_components/@socketry/syntax/examples/basic.html +87 -0
  75. data/public/_components/@socketry/syntax/examples/c.html +141 -0
  76. data/public/_components/@socketry/syntax/examples/clang.html +202 -0
  77. data/public/_components/@socketry/syntax/examples/csharp.html +110 -0
  78. data/public/_components/@socketry/syntax/examples/css-colors.html +179 -0
  79. data/public/_components/@socketry/syntax/examples/custom-theme.html +155 -0
  80. data/public/_components/@socketry/syntax/examples/diff.html +142 -0
  81. data/public/_components/@socketry/syntax/examples/examples.css +216 -0
  82. data/public/_components/@socketry/syntax/examples/go.html +413 -0
  83. data/public/_components/@socketry/syntax/examples/haskell.html +373 -0
  84. data/public/_components/@socketry/syntax/examples/html.html +316 -0
  85. data/public/_components/@socketry/syntax/examples/index.html +97 -0
  86. data/public/_components/@socketry/syntax/examples/io.html +552 -0
  87. data/public/_components/@socketry/syntax/examples/java.html +786 -0
  88. data/public/_components/@socketry/syntax/examples/javascript.html +199 -0
  89. data/public/_components/@socketry/syntax/examples/json.html +150 -0
  90. data/public/_components/@socketry/syntax/examples/lisp.html +476 -0
  91. data/public/_components/@socketry/syntax/examples/lua.html +737 -0
  92. data/public/_components/@socketry/syntax/examples/markdown.html +121 -0
  93. data/public/_components/@socketry/syntax/examples/mixed.html +306 -0
  94. data/public/_components/@socketry/syntax/examples/nginx.html +554 -0
  95. data/public/_components/@socketry/syntax/examples/ocaml.html +596 -0
  96. data/public/_components/@socketry/syntax/examples/pascal.html +762 -0
  97. data/public/_components/@socketry/syntax/examples/perl5.html +488 -0
  98. data/public/_components/@socketry/syntax/examples/php-script.html +142 -0
  99. data/public/_components/@socketry/syntax/examples/php.html +95 -0
  100. data/public/_components/@socketry/syntax/examples/plain.html +222 -0
  101. data/public/_components/@socketry/syntax/examples/protobuf.html +405 -0
  102. data/public/_components/@socketry/syntax/examples/python.html +82 -0
  103. data/public/_components/@socketry/syntax/examples/readme.md +79 -0
  104. data/public/_components/@socketry/syntax/examples/ruby.html +58 -0
  105. data/public/_components/@socketry/syntax/examples/scala.html +41 -0
  106. data/public/_components/@socketry/syntax/examples/smalltalk.html +436 -0
  107. data/public/_components/@socketry/syntax/examples/sql.html +373 -0
  108. data/public/_components/@socketry/syntax/examples/super-collider.html +55 -0
  109. data/public/_components/@socketry/syntax/examples/swift.html +176 -0
  110. data/public/_components/@socketry/syntax/examples/wrap-demo.html +103 -0
  111. data/public/_components/@socketry/syntax/examples/xml.html +112 -0
  112. data/public/_components/@socketry/syntax/examples/xrb.html +37 -0
  113. data/public/_components/@socketry/syntax/examples/yaml.html +72 -0
  114. data/public/_components/@socketry/syntax/license.md +21 -0
  115. data/public/_components/@socketry/syntax/package-lock.json +834 -0
  116. data/public/_components/@socketry/syntax/package.json +43 -0
  117. data/public/_components/@socketry/syntax/readme.md +162 -0
  118. data/public/_components/@socketry/syntax/test/Syntax/CodeElement.js +306 -0
  119. data/public/_components/@socketry/syntax/test/Syntax/ErrorHandling.js +85 -0
  120. data/public/_components/@socketry/syntax/test/Syntax/Language/apache.js +153 -0
  121. data/public/_components/@socketry/syntax/test/Syntax/Language/applescript.js +198 -0
  122. data/public/_components/@socketry/syntax/test/Syntax/Language/assembly.js +209 -0
  123. data/public/_components/@socketry/syntax/test/Syntax/Language/bash-script.js +225 -0
  124. data/public/_components/@socketry/syntax/test/Syntax/Language/bash.js +162 -0
  125. data/public/_components/@socketry/syntax/test/Syntax/Language/basic.js +265 -0
  126. data/public/_components/@socketry/syntax/test/Syntax/Language/clang.js +390 -0
  127. data/public/_components/@socketry/syntax/test/Syntax/Language/csharp.js +436 -0
  128. data/public/_components/@socketry/syntax/test/Syntax/Language/css.js +431 -0
  129. data/public/_components/@socketry/syntax/test/Syntax/Language/diff.js +206 -0
  130. data/public/_components/@socketry/syntax/test/Syntax/Language/go.js +386 -0
  131. data/public/_components/@socketry/syntax/test/Syntax/Language/haskell.js +454 -0
  132. data/public/_components/@socketry/syntax/test/Syntax/Language/html.js +111 -0
  133. data/public/_components/@socketry/syntax/test/Syntax/Language/io.js +229 -0
  134. data/public/_components/@socketry/syntax/test/Syntax/Language/java.js +362 -0
  135. data/public/_components/@socketry/syntax/test/Syntax/Language/javascript.js +101 -0
  136. data/public/_components/@socketry/syntax/test/Syntax/Language/json.js +101 -0
  137. data/public/_components/@socketry/syntax/test/Syntax/Language/lisp.js +224 -0
  138. data/public/_components/@socketry/syntax/test/Syntax/Language/lua.js +307 -0
  139. data/public/_components/@socketry/syntax/test/Syntax/Language/markdown.js +163 -0
  140. data/public/_components/@socketry/syntax/test/Syntax/Language/nginx.js +267 -0
  141. data/public/_components/@socketry/syntax/test/Syntax/Language/ocaml.js +299 -0
  142. data/public/_components/@socketry/syntax/test/Syntax/Language/pascal.js +311 -0
  143. data/public/_components/@socketry/syntax/test/Syntax/Language/perl5.js +333 -0
  144. data/public/_components/@socketry/syntax/test/Syntax/Language/php-script.js +197 -0
  145. data/public/_components/@socketry/syntax/test/Syntax/Language/php.js +92 -0
  146. data/public/_components/@socketry/syntax/test/Syntax/Language/plain.js +327 -0
  147. data/public/_components/@socketry/syntax/test/Syntax/Language/protobuf.js +294 -0
  148. data/public/_components/@socketry/syntax/test/Syntax/Language/python.js +213 -0
  149. data/public/_components/@socketry/syntax/test/Syntax/Language/ruby.js +70 -0
  150. data/public/_components/@socketry/syntax/test/Syntax/Language/scala.js +75 -0
  151. data/public/_components/@socketry/syntax/test/Syntax/Language/smalltalk.js +223 -0
  152. data/public/_components/@socketry/syntax/test/Syntax/Language/sql.js +281 -0
  153. data/public/_components/@socketry/syntax/test/Syntax/Language/super-collider.js +66 -0
  154. data/public/_components/@socketry/syntax/test/Syntax/Language/swift.js +71 -0
  155. data/public/_components/@socketry/syntax/test/Syntax/Language/xml.js +170 -0
  156. data/public/_components/@socketry/syntax/test/Syntax/Language/xrb.js +57 -0
  157. data/public/_components/@socketry/syntax/test/Syntax/Language/yaml.js +123 -0
  158. data/public/_components/@socketry/syntax/test/Syntax/Language.js +62 -0
  159. data/public/_components/@socketry/syntax/test/Syntax/Match.js +40 -0
  160. data/public/_components/@socketry/syntax/test/Syntax/Rule.js +251 -0
  161. data/public/_components/@socketry/syntax/test/Syntax.js +38 -0
  162. data/public/_components/@socketry/syntax/test/helpers/ast-matcher.js +90 -0
  163. data/public/_components/@socketry/syntax/themes/base/apache.css +1 -0
  164. data/public/_components/@socketry/syntax/themes/base/applescript.css +1 -0
  165. data/public/_components/@socketry/syntax/themes/base/assembly.css +1 -0
  166. data/public/_components/@socketry/syntax/themes/base/bash.css +1 -0
  167. data/public/_components/@socketry/syntax/themes/base/basic.css +1 -0
  168. data/public/_components/@socketry/syntax/themes/base/c.css +1 -0
  169. data/public/_components/@socketry/syntax/themes/base/clang.css +0 -0
  170. data/public/_components/@socketry/syntax/themes/base/csharp.css +1 -0
  171. data/public/_components/@socketry/syntax/themes/base/css.css +22 -0
  172. data/public/_components/@socketry/syntax/themes/base/diff.css +48 -0
  173. data/public/_components/@socketry/syntax/themes/base/go.css +1 -0
  174. data/public/_components/@socketry/syntax/themes/base/haskell.css +1 -0
  175. data/public/_components/@socketry/syntax/themes/base/html.css +1 -0
  176. data/public/_components/@socketry/syntax/themes/base/io.css +1 -0
  177. data/public/_components/@socketry/syntax/themes/base/java.css +1 -0
  178. data/public/_components/@socketry/syntax/themes/base/javascript.css +1 -0
  179. data/public/_components/@socketry/syntax/themes/base/json.css +41 -0
  180. data/public/_components/@socketry/syntax/themes/base/lisp.css +1 -0
  181. data/public/_components/@socketry/syntax/themes/base/lua.css +1 -0
  182. data/public/_components/@socketry/syntax/themes/base/markdown.css +16 -0
  183. data/public/_components/@socketry/syntax/themes/base/nginx.css +1 -0
  184. data/public/_components/@socketry/syntax/themes/base/ocaml.css +1 -0
  185. data/public/_components/@socketry/syntax/themes/base/pascal.css +1 -0
  186. data/public/_components/@socketry/syntax/themes/base/perl5.css +1 -0
  187. data/public/_components/@socketry/syntax/themes/base/php-script.css +1 -0
  188. data/public/_components/@socketry/syntax/themes/base/php.css +1 -0
  189. data/public/_components/@socketry/syntax/themes/base/plain.css +1 -0
  190. data/public/_components/@socketry/syntax/themes/base/protobuf.css +1 -0
  191. data/public/_components/@socketry/syntax/themes/base/python.css +1 -0
  192. data/public/_components/@socketry/syntax/themes/base/ruby.css +23 -0
  193. data/public/_components/@socketry/syntax/themes/base/scala.css +3 -0
  194. data/public/_components/@socketry/syntax/themes/base/smalltalk.css +1 -0
  195. data/public/_components/@socketry/syntax/themes/base/sql.css +1 -0
  196. data/public/_components/@socketry/syntax/themes/base/super-collider.css +33 -0
  197. data/public/_components/@socketry/syntax/themes/base/swift.css +1 -0
  198. data/public/_components/@socketry/syntax/themes/base/syntax.css +63 -0
  199. data/public/_components/@socketry/syntax/themes/base/xml.css +1 -0
  200. data/public/_components/@socketry/syntax/themes/base/xrb.css +29 -0
  201. data/public/_components/@socketry/syntax/themes/base/yaml.css +1 -0
  202. data/public/_components/@socketry/syntax/themes/theming.md +233 -0
  203. data/public/_components/@socketry/syntax/update-examples.js +135 -0
  204. data/public/_static/index.css +593 -0
  205. data/public/application.js +147 -0
  206. data/readme.md +69 -0
  207. data/releases.md +3 -0
  208. data/templates/code.xrb +12 -0
  209. data/templates/default.xrb +5 -0
  210. data/templates/image.xrb +8 -0
  211. data/templates/section.xrb +5 -0
  212. data/templates/title.xrb +8 -0
  213. data/templates/translation.xrb +8 -0
  214. data/templates/two_column.xrb +8 -0
  215. metadata +280 -0
@@ -0,0 +1,454 @@
1
+ /**
2
+ * Tests for Haskell language syntax highlighting
3
+ */
4
+
5
+ import {test} from 'node:test';
6
+ import assert from 'node:assert/strict';
7
+ import {JSDOM} from 'jsdom';
8
+ import Syntax from '../../../Syntax.js';
9
+
10
+ // Set up JSDOM
11
+ const dom = new JSDOM('<!DOCTYPE html><html><body></body></html>');
12
+ global.window = dom.window;
13
+ global.document = dom.window.document;
14
+ global.HTMLElement = dom.window.HTMLElement;
15
+ global.customElements = dom.window.customElements;
16
+
17
+ const syntax = new Syntax();
18
+
19
+ test('Haskell language can be registered', async () => {
20
+ const language = await syntax.getResource('haskell');
21
+ assert.ok(language);
22
+ assert.equal(language.name, 'haskell');
23
+ });
24
+
25
+ test('Haskell can match keywords', async () => {
26
+ const language = await syntax.getResource('haskell');
27
+ const code = 'module Main where import Data.List';
28
+ const matches = await language.getMatches(syntax, code);
29
+
30
+ const keywords = matches.filter(m => m.type === 'keyword');
31
+ assert.ok(keywords.some(m => m.value === 'module'));
32
+ assert.ok(keywords.some(m => m.value === 'where'));
33
+ assert.ok(keywords.some(m => m.value === 'import'));
34
+ });
35
+
36
+ test('Haskell can match module declaration', async () => {
37
+ const language = await syntax.getResource('haskell');
38
+ const matches = await language.getMatches(syntax, 'module Main where');
39
+
40
+ const keywords = matches.filter(m => m.type === 'keyword');
41
+ assert.ok(keywords.some(m => m.value === 'module'));
42
+ assert.ok(keywords.some(m => m.value === 'where'));
43
+ });
44
+
45
+ test('Haskell can match import statements', async () => {
46
+ const language = await syntax.getResource('haskell');
47
+ const code = 'import qualified Data.Map as M';
48
+ const matches = await language.getMatches(syntax, code);
49
+
50
+ const keywords = matches.filter(m => m.type === 'keyword');
51
+ assert.ok(keywords.some(m => m.value === 'import'));
52
+ assert.ok(keywords.some(m => m.value === 'qualified'));
53
+ assert.ok(keywords.some(m => m.value === 'as'));
54
+ });
55
+
56
+ test('Haskell can match hiding in imports', async () => {
57
+ const language = await syntax.getResource('haskell');
58
+ const matches = await language.getMatches(
59
+ syntax,
60
+ 'import Data.List hiding (map)'
61
+ );
62
+
63
+ const keywords = matches.filter(m => m.type === 'keyword');
64
+ assert.ok(keywords.some(m => m.value === 'hiding'));
65
+ });
66
+
67
+ test('Haskell can match data declarations', async () => {
68
+ const language = await syntax.getResource('haskell');
69
+ const code = 'data Maybe a = Just a | Nothing';
70
+ const matches = await language.getMatches(syntax, code);
71
+
72
+ const keywords = matches.filter(m => m.type === 'keyword');
73
+ assert.ok(keywords.some(m => m.value === 'data'));
74
+ });
75
+
76
+ test('Haskell can match data family', async () => {
77
+ const language = await syntax.getResource('haskell');
78
+ const matches = await language.getMatches(syntax, 'data family Array e');
79
+
80
+ const keywords = matches.filter(m => m.type === 'keyword');
81
+ assert.ok(keywords.some(m => m.value === 'data family'));
82
+ });
83
+
84
+ test('Haskell can match data instance', async () => {
85
+ const language = await syntax.getResource('haskell');
86
+ const matches = await language.getMatches(
87
+ syntax,
88
+ 'data instance T Int = TInt'
89
+ );
90
+
91
+ const keywords = matches.filter(m => m.type === 'keyword');
92
+ assert.ok(keywords.some(m => m.value === 'data instance'));
93
+ });
94
+
95
+ test('Haskell can match type declarations', async () => {
96
+ const language = await syntax.getResource('haskell');
97
+ const code = 'type String = [Char]';
98
+ const matches = await language.getMatches(syntax, code);
99
+
100
+ const keywords = matches.filter(m => m.type === 'keyword');
101
+ assert.ok(keywords.some(m => m.value === 'type'));
102
+ });
103
+
104
+ test('Haskell can match type family', async () => {
105
+ const language = await syntax.getResource('haskell');
106
+ const matches = await language.getMatches(syntax, 'type family F a');
107
+
108
+ const keywords = matches.filter(m => m.type === 'keyword');
109
+ assert.ok(keywords.some(m => m.value === 'type family'));
110
+ });
111
+
112
+ test('Haskell can match type instance', async () => {
113
+ const language = await syntax.getResource('haskell');
114
+ const matches = await language.getMatches(
115
+ syntax,
116
+ 'type instance F Int = Bool'
117
+ );
118
+
119
+ const keywords = matches.filter(m => m.type === 'keyword');
120
+ assert.ok(keywords.some(m => m.value === 'type instance'));
121
+ });
122
+
123
+ test('Haskell can match newtype declarations', async () => {
124
+ const language = await syntax.getResource('haskell');
125
+ const matches = await language.getMatches(
126
+ syntax,
127
+ 'newtype Identity a = Identity a'
128
+ );
129
+
130
+ const keywords = matches.filter(m => m.type === 'keyword');
131
+ assert.ok(keywords.some(m => m.value === 'newtype'));
132
+ });
133
+
134
+ test('Haskell can match class declarations', async () => {
135
+ const language = await syntax.getResource('haskell');
136
+ const code = 'class Eq a where (==) :: a -> a -> Bool';
137
+ const matches = await language.getMatches(syntax, code);
138
+
139
+ const keywords = matches.filter(m => m.type === 'keyword');
140
+ assert.ok(keywords.some(m => m.value === 'class'));
141
+ assert.ok(keywords.some(m => m.value === 'where'));
142
+ });
143
+
144
+ test('Haskell can match instance declarations', async () => {
145
+ const language = await syntax.getResource('haskell');
146
+ const code = 'instance Eq Int where x == y = ...';
147
+ const matches = await language.getMatches(syntax, code);
148
+
149
+ const keywords = matches.filter(m => m.type === 'keyword');
150
+ assert.ok(keywords.some(m => m.value === 'instance'));
151
+ });
152
+
153
+ test('Haskell can match deriving', async () => {
154
+ const language = await syntax.getResource('haskell');
155
+ const code = 'data Person = Person String Int deriving (Show, Eq)';
156
+ const matches = await language.getMatches(syntax, code);
157
+
158
+ const keywords = matches.filter(m => m.type === 'keyword');
159
+ assert.ok(keywords.some(m => m.value === 'deriving'));
160
+ });
161
+
162
+ test('Haskell can match deriving instance', async () => {
163
+ const language = await syntax.getResource('haskell');
164
+ const matches = await language.getMatches(syntax, 'deriving instance Show a');
165
+
166
+ const keywords = matches.filter(m => m.type === 'keyword');
167
+ assert.ok(keywords.some(m => m.value === 'deriving instance'));
168
+ });
169
+
170
+ test('Haskell can match case expressions', async () => {
171
+ const language = await syntax.getResource('haskell');
172
+ const code = 'case x of Just y -> y; Nothing -> 0';
173
+ const matches = await language.getMatches(syntax, code);
174
+
175
+ const keywords = matches.filter(m => m.type === 'keyword');
176
+ assert.ok(keywords.some(m => m.value === 'case'));
177
+ assert.ok(keywords.some(m => m.value === 'of'));
178
+ });
179
+
180
+ test('Haskell can match if-then-else', async () => {
181
+ const language = await syntax.getResource('haskell');
182
+ const code = 'if x > 0 then 1 else 0';
183
+ const matches = await language.getMatches(syntax, code);
184
+
185
+ const keywords = matches.filter(m => m.type === 'keyword');
186
+ assert.ok(keywords.some(m => m.value === 'if'));
187
+ assert.ok(keywords.some(m => m.value === 'then'));
188
+ assert.ok(keywords.some(m => m.value === 'else'));
189
+ });
190
+
191
+ test('Haskell can match let-in expressions', async () => {
192
+ const language = await syntax.getResource('haskell');
193
+ const code = 'let x = 5 in x + 1';
194
+ const matches = await language.getMatches(syntax, code);
195
+
196
+ const keywords = matches.filter(m => m.type === 'keyword');
197
+ assert.ok(keywords.some(m => m.value === 'let'));
198
+ assert.ok(keywords.some(m => m.value === 'in'));
199
+ });
200
+
201
+ test('Haskell can match do notation', async () => {
202
+ const language = await syntax.getResource('haskell');
203
+ const matches = await language.getMatches(syntax, 'do x <- getLine; return x');
204
+
205
+ const keywords = matches.filter(m => m.type === 'keyword');
206
+ assert.ok(keywords.some(m => m.value === 'do'));
207
+ });
208
+
209
+ test('Haskell can match mdo (recursive do)', async () => {
210
+ const language = await syntax.getResource('haskell');
211
+ const matches = await language.getMatches(
212
+ syntax,
213
+ 'mdo x <- f y; y <- g x; return x'
214
+ );
215
+
216
+ const keywords = matches.filter(m => m.type === 'keyword');
217
+ assert.ok(keywords.some(m => m.value === 'mdo'));
218
+ });
219
+
220
+ test('Haskell can match forall', async () => {
221
+ const language = await syntax.getResource('haskell');
222
+ const matches = await language.getMatches(syntax, 'id :: forall a. a -> a');
223
+
224
+ const keywords = matches.filter(m => m.type === 'keyword');
225
+ assert.ok(keywords.some(m => m.value === 'forall'));
226
+ });
227
+
228
+ test('Haskell can match foreign declarations', async () => {
229
+ const language = await syntax.getResource('haskell');
230
+ const matches = await language.getMatches(
231
+ syntax,
232
+ 'foreign import ccall "sin" c_sin :: Double -> Double'
233
+ );
234
+
235
+ const keywords = matches.filter(m => m.type === 'keyword');
236
+ assert.ok(keywords.some(m => m.value === 'foreign'));
237
+ assert.ok(keywords.some(m => m.value === 'import'));
238
+ });
239
+
240
+ test('Haskell can match infix operators', async () => {
241
+ const language = await syntax.getResource('haskell');
242
+ const code = 'infix 5 +++; infixl 6 ***; infixr 7 ^^^';
243
+ const matches = await language.getMatches(syntax, code);
244
+
245
+ const keywords = matches.filter(m => m.type === 'keyword');
246
+ assert.ok(keywords.some(m => m.value === 'infix'));
247
+ assert.ok(keywords.some(m => m.value === 'infixl'));
248
+ assert.ok(keywords.some(m => m.value === 'infixr'));
249
+ });
250
+
251
+ test('Haskell can match default declarations', async () => {
252
+ const language = await syntax.getResource('haskell');
253
+ const matches = await language.getMatches(syntax, 'default (Int, Double)');
254
+
255
+ const keywords = matches.filter(m => m.type === 'keyword');
256
+ assert.ok(keywords.some(m => m.value === 'default'));
257
+ });
258
+
259
+ test('Haskell can match rec keyword', async () => {
260
+ const language = await syntax.getResource('haskell');
261
+ const matches = await language.getMatches(syntax, 'rec x <- f y');
262
+
263
+ const keywords = matches.filter(m => m.type === 'keyword');
264
+ assert.ok(keywords.some(m => m.value === 'rec'));
265
+ });
266
+
267
+ test('Haskell can match proc (arrows)', async () => {
268
+ const language = await syntax.getResource('haskell');
269
+ const matches = await language.getMatches(
270
+ syntax,
271
+ 'proc x -> returnA -< x + 1'
272
+ );
273
+
274
+ const keywords = matches.filter(m => m.type === 'keyword');
275
+ assert.ok(keywords.some(m => m.value === 'proc'));
276
+ });
277
+
278
+ test('Haskell can match True and False constants', async () => {
279
+ const language = await syntax.getResource('haskell');
280
+ const code = 'x = True; y = False';
281
+ const matches = await language.getMatches(syntax, code);
282
+
283
+ const constants = matches.filter(m => m.type === 'constant');
284
+ assert.ok(constants.some(m => m.value === 'True'));
285
+ assert.ok(constants.some(m => m.value === 'False'));
286
+ });
287
+
288
+ test('Haskell can match type signatures (::)', async () => {
289
+ const language = await syntax.getResource('haskell');
290
+ const matches = await language.getMatches(syntax, 'f :: Int -> String');
291
+
292
+ const operators = matches.filter(m => m.type === 'operator');
293
+ assert.ok(operators.some(m => m.value === '::'));
294
+ });
295
+
296
+ test('Haskell can match function arrow (->)', async () => {
297
+ const language = await syntax.getResource('haskell');
298
+ const matches = await language.getMatches(
299
+ syntax,
300
+ 'f :: Int -> String -> Bool'
301
+ );
302
+
303
+ const operators = matches.filter(m => m.type === 'operator');
304
+ assert.ok(operators.some(m => m.value === '->'));
305
+ });
306
+
307
+ test('Haskell can match bind operator (<-)', async () => {
308
+ const language = await syntax.getResource('haskell');
309
+ const matches = await language.getMatches(syntax, 'x <- getLine');
310
+
311
+ const operators = matches.filter(m => m.type === 'operator');
312
+ assert.ok(operators.some(m => m.value === '<-'));
313
+ });
314
+
315
+ test('Haskell can match arrow operators', async () => {
316
+ const language = await syntax.getResource('haskell');
317
+ const code = 'f -< x; g -<< y';
318
+ const matches = await language.getMatches(syntax, code);
319
+
320
+ const operators = matches.filter(m => m.type === 'operator');
321
+ assert.ok(operators.some(m => m.value === '-<'));
322
+ assert.ok(operators.some(m => m.value === '-<<'));
323
+ });
324
+
325
+ test('Haskell can match pipe operator', async () => {
326
+ const language = await syntax.getResource('haskell');
327
+ const matches = await language.getMatches(
328
+ syntax,
329
+ 'data Either a b = Left a | Right b'
330
+ );
331
+
332
+ const operators = matches.filter(m => m.type === 'operator');
333
+ assert.ok(operators.some(m => m.value === '|'));
334
+ });
335
+
336
+ test('Haskell can match lambda (\\)', async () => {
337
+ const language = await syntax.getResource('haskell');
338
+ const matches = await language.getMatches(syntax, '\\x -> x + 1');
339
+
340
+ const operators = matches.filter(m => m.type === 'operator');
341
+ assert.ok(operators.some(m => m.value === '\\'));
342
+ });
343
+
344
+ test('Haskell can match backtick infix', async () => {
345
+ const language = await syntax.getResource('haskell');
346
+ const matches = await language.getMatches(syntax, 'x `mod` 2');
347
+
348
+ const operators = matches.filter(m => m.type === 'operator');
349
+ assert.ok(operators.some(m => m.value === '`'));
350
+ });
351
+
352
+ test('Haskell can match line comments', async () => {
353
+ const language = await syntax.getResource('haskell');
354
+ const matches = await language.getMatches(syntax, '-- This is a comment');
355
+
356
+ const comments = matches.filter(m => m.type === 'comment');
357
+ assert.ok(comments.length > 0);
358
+ assert.ok(comments[0].value.includes('comment'));
359
+ });
360
+
361
+ test('Haskell can match block comments', async () => {
362
+ const language = await syntax.getResource('haskell');
363
+ const matches = await language.getMatches(
364
+ syntax,
365
+ '{- multi\nline\ncomment -}'
366
+ );
367
+
368
+ const comments = matches.filter(m => m.type === 'comment');
369
+ assert.ok(comments.length > 0);
370
+ assert.ok(comments[0].value.includes('multi'));
371
+ });
372
+
373
+ test('Haskell can match nested block comments', async () => {
374
+ const language = await syntax.getResource('haskell');
375
+ const matches = await language.getMatches(
376
+ syntax,
377
+ '{- outer {- inner -} outer -}'
378
+ );
379
+
380
+ const comments = matches.filter(m => m.type === 'comment');
381
+ assert.ok(comments.length > 0);
382
+ });
383
+
384
+ test('Haskell can match double-quoted strings', async () => {
385
+ const language = await syntax.getResource('haskell');
386
+ const matches = await language.getMatches(syntax, '"Hello, World!"');
387
+
388
+ const strings = matches.filter(m => m.type === 'string');
389
+ assert.ok(strings.some(m => m.value.includes('Hello')));
390
+ });
391
+
392
+ test('Haskell can match single-quoted characters', async () => {
393
+ const language = await syntax.getResource('haskell');
394
+ const matches = await language.getMatches(syntax, "'a'");
395
+
396
+ const strings = matches.filter(m => m.type === 'string');
397
+ assert.ok(strings.length > 0);
398
+ });
399
+
400
+ test('Haskell can match decimal numbers', async () => {
401
+ const language = await syntax.getResource('haskell');
402
+ const matches = await language.getMatches(syntax, 'x = 42; y = 3.14');
403
+
404
+ const numbers = matches.filter(
405
+ m => m.type === 'constant' && /\d/.test(m.value)
406
+ );
407
+ assert.ok(numbers.length > 0);
408
+ });
409
+
410
+ test('Haskell can match hexadecimal numbers', async () => {
411
+ const language = await syntax.getResource('haskell');
412
+ const matches = await language.getMatches(syntax, 'x = 0xFF');
413
+
414
+ const numbers = matches.filter(
415
+ m => m.type === 'constant' && m.value.includes('0x')
416
+ );
417
+ assert.ok(numbers.length > 0);
418
+ });
419
+
420
+ test('Haskell can match CamelCase types', async () => {
421
+ const language = await syntax.getResource('haskell');
422
+ const code = 'data Maybe a = Just a | Nothing';
423
+ const matches = await language.getMatches(syntax, code);
424
+
425
+ const types = matches.filter(m => m.type === 'type' && /^[A-Z]/.test(m.value));
426
+ assert.ok(types.some(m => m.value === 'Maybe'));
427
+ assert.ok(types.some(m => m.value === 'Just'));
428
+ assert.ok(types.some(m => m.value === 'Nothing'));
429
+ });
430
+
431
+ test('Haskell can process complete code to HTML', async () => {
432
+ const language = await syntax.getResource('haskell');
433
+ const code = `module Main where
434
+
435
+ main :: IO ()
436
+ main = putStrLn "Hello, World!"`;
437
+
438
+ const html = await language.process(syntax, code);
439
+ assert.ok(html instanceof HTMLElement);
440
+ const text = html.textContent;
441
+ assert.ok(text.includes('module'));
442
+ assert.ok(text.includes('main'));
443
+ assert.ok(text.includes('Hello'));
444
+ });
445
+
446
+ test('Haskell can build a syntax tree', async () => {
447
+ const language = await syntax.getResource('haskell');
448
+ const code =
449
+ 'factorial :: Int -> Int\nfactorial 0 = 1\nfactorial n = n * factorial (n - 1)';
450
+
451
+ const tree = await language.buildTree(syntax, code, 0);
452
+ assert.ok(tree);
453
+ assert.ok(tree.children.length > 0);
454
+ });
@@ -0,0 +1,111 @@
1
+ import Syntax from '../../../Syntax.js';
2
+ import registerHTML from '../../../Syntax/Language/html.js';
3
+ import registerXML from '../../../Syntax/Language/xml.js';
4
+ import registerJavaScript from '../../../Syntax/Language/javascript.js';
5
+ import registerJSON from '../../../Syntax/Language/json.js';
6
+ import registerCSS from '../../../Syntax/Language/css.js';
7
+ import registerPHPScript from '../../../Syntax/Language/php-script.js';
8
+ import registerRuby from '../../../Syntax/Language/ruby.js';
9
+ import {strictEqual, ok} from 'node:assert';
10
+ import test from 'node:test';
11
+
12
+ async function getLanguage() {
13
+ const syntax = new Syntax();
14
+ registerXML(syntax);
15
+ registerJavaScript(syntax);
16
+ registerJSON(syntax);
17
+ registerCSS(syntax);
18
+ registerPHPScript(syntax);
19
+ registerRuby(syntax);
20
+ registerHTML(syntax);
21
+ return await syntax.getLanguage('html');
22
+ }
23
+
24
+ function typesFrom(matches) {
25
+ return matches.map(m => m.expression.type);
26
+ }
27
+
28
+ test('HTML language can be registered', async () => {
29
+ const language = await getLanguage();
30
+ strictEqual(language.name, 'html');
31
+ });
32
+
33
+ test('HTML: DOCTYPE declaration', async () => {
34
+ const language = await getLanguage();
35
+ const code = '<!DOCTYPE html>';
36
+ const matches = await language.getMatches(Syntax.default, code);
37
+ const types = typesFrom(matches);
38
+ ok(types.includes('doctype'));
39
+ });
40
+
41
+ test('HTML: embedded JavaScript in script tag', async () => {
42
+ const language = await getLanguage();
43
+ const code = '<script type="text/javascript">console.log("test");</script>';
44
+ const matches = await language.getMatches(Syntax.default, code);
45
+ // Should have embedded JavaScript language
46
+ ok(matches.some(m => m.expression && m.expression.language === 'javascript'));
47
+ });
48
+
49
+ test('HTML: embedded JavaScript in script tag without type', async () => {
50
+ const language = await getLanguage();
51
+ const code = '<script>console.log("test");</script>';
52
+ const matches = await language.getMatches(Syntax.default, code);
53
+ // Should have embedded JavaScript language
54
+ ok(matches.some(m => m.expression && m.expression.language === 'javascript'));
55
+ });
56
+
57
+ test('HTML: embedded JSON in importmap', async () => {
58
+ const language = await getLanguage();
59
+ const code = '<script type="importmap">{"imports": {"vue": "/vue.js"}}</script>';
60
+ const matches = await language.getMatches(Syntax.default, code);
61
+ // Should have embedded JSON language
62
+ ok(matches.some(m => m.expression && m.expression.language === 'json'));
63
+ });
64
+
65
+ test('HTML: embedded CSS in style tag', async () => {
66
+ const language = await getLanguage();
67
+ const code = '<style type="text/css">body { color: red; }</style>';
68
+ const matches = await language.getMatches(Syntax.default, code);
69
+ // Should have embedded CSS language
70
+ ok(matches.some(m => m.expression && m.expression.language === 'css'));
71
+ });
72
+
73
+ test('HTML: embedded PHP', async () => {
74
+ const language = await getLanguage();
75
+ const code = '<?php echo "Hello"; ?>';
76
+ const matches = await language.getMatches(Syntax.default, code);
77
+ const types = typesFrom(matches);
78
+ ok(types.includes('keyword') || types.includes('php-tag'));
79
+ });
80
+
81
+ test('HTML: embedded Ruby', async () => {
82
+ const language = await getLanguage();
83
+ const code = '<?rb puts "Hello" ?>';
84
+ const matches = await language.getMatches(Syntax.default, code);
85
+ const types = typesFrom(matches);
86
+ ok(types.includes('keyword') || types.includes('ruby-tag'));
87
+ });
88
+
89
+ test('HTML: ERB-style instructions', async () => {
90
+ const language = await getLanguage();
91
+ const code = '<%= value %>';
92
+ const matches = await language.getMatches(Syntax.default, code);
93
+ const types = typesFrom(matches);
94
+ ok(types.includes('instruction'));
95
+ });
96
+
97
+ test('HTML: percent escapes', async () => {
98
+ const language = await getLanguage();
99
+ const code = 'test%20value';
100
+ const matches = await language.getMatches(Syntax.default, code);
101
+ const types = typesFrom(matches);
102
+ ok(types.includes('percent-escape'));
103
+ });
104
+
105
+ test('HTML: derives from XML for tags', async () => {
106
+ const language = await getLanguage();
107
+ const code = '<div class="test">Hello</div>';
108
+ const matches = await language.getMatches(Syntax.default, code);
109
+ // Should have XML-derived tag matches
110
+ ok(matches.length > 0);
111
+ });