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,431 @@
1
+ // test/Syntax/Language/css.js
2
+ // Tests for CSS language highlighting
3
+
4
+ import {test} from 'node:test';
5
+ import assert from 'node:assert';
6
+ import {JSDOM} from 'jsdom';
7
+
8
+ // Setup DOM environment
9
+ const dom = new JSDOM('<!DOCTYPE html><html><body></body></html>');
10
+ global.document = dom.window.document;
11
+
12
+ import Syntax from '../../../Syntax.js';
13
+ import registerCSS from '../../../Syntax/Language/css.js';
14
+
15
+ test('CSS language is registered', async () => {
16
+ const syntax = new Syntax();
17
+ registerCSS(syntax);
18
+ const language = await syntax.getLanguage('css');
19
+ assert.ok(language, 'CSS language should be registered');
20
+ assert.strictEqual(language.name, 'css');
21
+ });
22
+
23
+ test('selectors - element', async () => {
24
+ const syntax = new Syntax();
25
+ registerCSS(syntax);
26
+ const language = await syntax.getLanguage('css');
27
+ const code = 'div { color: red; }';
28
+ const matches = await language.getMatches(syntax, code);
29
+
30
+ const selectors = matches.filter(m => m.type === 'selector');
31
+ assert.ok(selectors.length > 0, 'Should find selector');
32
+ });
33
+
34
+ test('selectors - class', async () => {
35
+ const syntax = new Syntax();
36
+ registerCSS(syntax);
37
+ const language = await syntax.getLanguage('css');
38
+ const code = '.my-class { color: red; }';
39
+ const matches = await language.getMatches(syntax, code);
40
+
41
+ const selectors = matches.filter(m => m.type === 'selector');
42
+ assert.ok(selectors.length > 0, 'Should find class selector');
43
+ });
44
+
45
+ test('selectors - id', async () => {
46
+ const syntax = new Syntax();
47
+ registerCSS(syntax);
48
+ const language = await syntax.getLanguage('css');
49
+ const code = '#my-id { color: red; }';
50
+ const matches = await language.getMatches(syntax, code);
51
+
52
+ const selectors = matches.filter(m => m.type === 'selector');
53
+ assert.ok(selectors.length > 0, 'Should find id selector');
54
+ });
55
+
56
+ test('selectors - attribute', async () => {
57
+ const syntax = new Syntax();
58
+ registerCSS(syntax);
59
+ const language = await syntax.getLanguage('css');
60
+ const code = '[data-value="test"] { color: red; }';
61
+ const matches = await language.getMatches(syntax, code);
62
+
63
+ const selectors = matches.filter(m => m.type === 'selector');
64
+ assert.ok(selectors.length > 0, 'Should find attribute selector');
65
+ });
66
+
67
+ test('selectors - pseudo-class', async () => {
68
+ const syntax = new Syntax();
69
+ registerCSS(syntax);
70
+ const language = await syntax.getLanguage('css');
71
+ const code = 'a:hover { color: blue; }';
72
+ const matches = await language.getMatches(syntax, code);
73
+
74
+ const selectors = matches.filter(m => m.type === 'selector');
75
+ assert.ok(selectors.length > 0, 'Should find pseudo-class selector');
76
+ });
77
+
78
+ test('properties and values', async () => {
79
+ const syntax = new Syntax();
80
+ registerCSS(syntax);
81
+ const language = await syntax.getLanguage('css');
82
+ const code = 'div { color: red; }';
83
+ const matches = await language.getMatches(syntax, code);
84
+
85
+ const properties = matches.filter(m => m.type === 'property');
86
+ const values = matches.filter(m => m.type === 'value');
87
+
88
+ assert.ok(properties.length > 0, 'Should find property');
89
+ assert.ok(values.length > 0, 'Should find value');
90
+ });
91
+
92
+ test('color - named color', async () => {
93
+ const syntax = new Syntax();
94
+ registerCSS(syntax);
95
+ const language = await syntax.getLanguage('css');
96
+ const code = 'div { color: AliceBlue; }';
97
+ const matches = await language.getMatches(syntax, code);
98
+
99
+ const colors = matches.filter(m => m.type === 'color');
100
+ assert.ok(colors.length > 0, 'Should find named color');
101
+ });
102
+
103
+ test('color - hex short', async () => {
104
+ const syntax = new Syntax();
105
+ registerCSS(syntax);
106
+ const language = await syntax.getLanguage('css');
107
+ const code = 'div { color: #fff; }';
108
+ const matches = await language.getMatches(syntax, code);
109
+
110
+ const colors = matches.filter(m => m.type === 'color');
111
+ assert.ok(colors.length > 0, 'Should find hex color');
112
+ });
113
+
114
+ test('color - hex long', async () => {
115
+ const syntax = new Syntax();
116
+ registerCSS(syntax);
117
+ const language = await syntax.getLanguage('css');
118
+ const code = 'div { color: #ffffff; }';
119
+ const matches = await language.getMatches(syntax, code);
120
+
121
+ const colors = matches.filter(m => m.type === 'color');
122
+ assert.ok(colors.length > 0, 'Should find hex color');
123
+ });
124
+
125
+ test('color - rgb', async () => {
126
+ const syntax = new Syntax();
127
+ registerCSS(syntax);
128
+ const language = await syntax.getLanguage('css');
129
+ const code = 'div { color: rgb(255, 0, 0); }';
130
+ const matches = await language.getMatches(syntax, code);
131
+
132
+ const colors = matches.filter(m => m.type === 'color');
133
+ assert.ok(colors.length > 0, 'Should find rgb color');
134
+ });
135
+
136
+ test('color - rgba', async () => {
137
+ const syntax = new Syntax();
138
+ registerCSS(syntax);
139
+ const language = await syntax.getLanguage('css');
140
+ const code = 'div { color: rgba(255, 0, 0, 0.5); }';
141
+ const matches = await language.getMatches(syntax, code);
142
+
143
+ const colors = matches.filter(m => m.type === 'color');
144
+ assert.ok(colors.length > 0, 'Should find rgba color');
145
+ });
146
+
147
+ test('color - hsl', async () => {
148
+ const syntax = new Syntax();
149
+ registerCSS(syntax);
150
+ const language = await syntax.getLanguage('css');
151
+ const code = 'div { color: hsl(120, 100%, 50%); }';
152
+ const matches = await language.getMatches(syntax, code);
153
+
154
+ const colors = matches.filter(m => m.type === 'color');
155
+ assert.ok(colors.length > 0, 'Should find hsl color');
156
+ });
157
+
158
+ test('color - hsla', async () => {
159
+ const syntax = new Syntax();
160
+ registerCSS(syntax);
161
+ const language = await syntax.getLanguage('css');
162
+ const code = 'div { color: hsla(120, 100%, 50%, 0.5); }';
163
+ const matches = await language.getMatches(syntax, code);
164
+
165
+ const colors = matches.filter(m => m.type === 'color');
166
+ assert.ok(colors.length > 0, 'Should find hsla color');
167
+ });
168
+
169
+ test('comments - single line', async () => {
170
+ const syntax = new Syntax();
171
+ registerCSS(syntax);
172
+ const language = await syntax.getLanguage('css');
173
+ const code = '/* This is a comment */';
174
+ const matches = await language.getMatches(syntax, code);
175
+
176
+ const comments = matches.filter(m => m.type === 'comment');
177
+ assert.ok(comments.length > 0, 'Should find comment');
178
+ });
179
+
180
+ test('comments - multiline', async () => {
181
+ const syntax = new Syntax();
182
+ registerCSS(syntax);
183
+ const language = await syntax.getLanguage('css');
184
+ const code = `/* This is
185
+ a multiline
186
+ comment */`;
187
+ const matches = await language.getMatches(syntax, code);
188
+
189
+ const comments = matches.filter(m => m.type === 'comment');
190
+ assert.ok(comments.length > 0, 'Should find multiline comment');
191
+ });
192
+
193
+ test('strings - single quoted', async () => {
194
+ const syntax = new Syntax();
195
+ registerCSS(syntax);
196
+ const language = await syntax.getLanguage('css');
197
+ const code = "content: 'hello';";
198
+ const matches = await language.getMatches(syntax, code);
199
+
200
+ const strings = matches.filter(m => m.type === 'string');
201
+ assert.ok(strings.length > 0, 'Should find single quoted string');
202
+ });
203
+
204
+ test('strings - double quoted', async () => {
205
+ const syntax = new Syntax();
206
+ registerCSS(syntax);
207
+ const language = await syntax.getLanguage('css');
208
+ const code = 'content: "hello";';
209
+ const matches = await language.getMatches(syntax, code);
210
+
211
+ const strings = matches.filter(m => m.type === 'string');
212
+ assert.ok(strings.length > 0, 'Should find double quoted string');
213
+ });
214
+
215
+ test('functions - url', async () => {
216
+ const syntax = new Syntax();
217
+ registerCSS(syntax);
218
+ const language = await syntax.getLanguage('css');
219
+ const code = 'background: url(image.png);';
220
+ const matches = await language.getMatches(syntax, code);
221
+
222
+ const functions = matches.filter(m => m.type === 'function');
223
+ assert.ok(functions.length > 0, 'Should find url function');
224
+ });
225
+
226
+ test('functions - calc', async () => {
227
+ const syntax = new Syntax();
228
+ registerCSS(syntax);
229
+ const language = await syntax.getLanguage('css');
230
+ const code = 'width: calc(100% - 20px);';
231
+ const matches = await language.getMatches(syntax, code);
232
+
233
+ const functions = matches.filter(m => m.type === 'function');
234
+ assert.ok(functions.length > 0, 'Should find calc function');
235
+ });
236
+
237
+ test('media query', async () => {
238
+ const syntax = new Syntax();
239
+ registerCSS(syntax);
240
+ const language = await syntax.getLanguage('css');
241
+ const code = '@media screen and (max-width: 600px) { .class { color: red; } }';
242
+ const matches = await language.getMatches(syntax, code);
243
+
244
+ assert.ok(matches.length > 0, 'Should parse media query');
245
+ });
246
+
247
+ test('multiple properties', async () => {
248
+ const syntax = new Syntax();
249
+ registerCSS(syntax);
250
+ const language = await syntax.getLanguage('css');
251
+ const code = `div {
252
+ color: red;
253
+ background-color: blue;
254
+ margin: 10px;
255
+ padding: 5px;
256
+ }`;
257
+ const matches = await language.getMatches(syntax, code);
258
+
259
+ const properties = matches.filter(m => m.type === 'property');
260
+ assert.ok(properties.length >= 4, 'Should find multiple properties');
261
+ });
262
+
263
+ test('complex selector', async () => {
264
+ const syntax = new Syntax();
265
+ registerCSS(syntax);
266
+ const language = await syntax.getLanguage('css');
267
+ const code = 'div.class#id[attr="value"]:hover > span { color: red; }';
268
+ const matches = await language.getMatches(syntax, code);
269
+
270
+ const selectors = matches.filter(m => m.type === 'selector');
271
+ assert.ok(selectors.length > 0, 'Should parse complex selector');
272
+ });
273
+
274
+ test('vendor prefixes', async () => {
275
+ const syntax = new Syntax();
276
+ registerCSS(syntax);
277
+ const language = await syntax.getLanguage('css');
278
+ const code = 'div { -webkit-transform: rotate(45deg); }';
279
+ const matches = await language.getMatches(syntax, code);
280
+
281
+ const properties = matches.filter(m => m.type === 'property');
282
+ assert.ok(properties.length > 0, 'Should find vendor prefixed property');
283
+ });
284
+
285
+ test('keyframes', async () => {
286
+ const syntax = new Syntax();
287
+ registerCSS(syntax);
288
+ const language = await syntax.getLanguage('css');
289
+ const code = '@keyframes slide { from { left: 0; } to { left: 100px; } }';
290
+ const matches = await language.getMatches(syntax, code);
291
+
292
+ assert.ok(matches.length > 0, 'Should parse keyframes');
293
+ });
294
+
295
+ test('color box - color matches have process function', async () => {
296
+ const syntax = new Syntax();
297
+ registerCSS(syntax);
298
+ const language = await syntax.getLanguage('css');
299
+
300
+ const code = 'div { color: #ff0000; }';
301
+ const matches = await language.getMatches(syntax, code);
302
+
303
+ const colorMatches = matches.filter(m => m.type === 'color');
304
+ assert.ok(colorMatches.length > 0, 'Should find color matches');
305
+
306
+ // Check that at least one color match has a process function
307
+ const matchWithProcess = colorMatches.find(
308
+ m => m.expression && m.expression.process
309
+ );
310
+ assert.ok(matchWithProcess, 'Color match should have process function');
311
+ assert.strictEqual(
312
+ typeof matchWithProcess.expression.process,
313
+ 'function',
314
+ 'Process should be a function'
315
+ );
316
+ });
317
+
318
+ test('color box - process function creates colour-box element', async () => {
319
+ const syntax = new Syntax();
320
+ registerCSS(syntax);
321
+ const language = await syntax.getLanguage('css');
322
+
323
+ const code = 'div { color: #ff0000; }';
324
+ const matches = await language.getMatches(syntax, code);
325
+
326
+ const colorMatch = matches.find(
327
+ m => m.type === 'color' && m.expression && m.expression.process
328
+ );
329
+ assert.ok(colorMatch, 'Should find color match with process function');
330
+
331
+ // Create a test element
332
+ const element = document.createElement('span');
333
+ element.textContent = '#ff0000';
334
+
335
+ // Call the process function
336
+ const result = colorMatch.expression.process(element, colorMatch);
337
+
338
+ // Verify the color box was created
339
+ assert.strictEqual(result, element, 'Should return the element');
340
+ const colourBox = element.querySelector('.colour-box');
341
+ assert.ok(colourBox, 'Should create colour-box element');
342
+
343
+ const sample = colourBox.querySelector('.sample');
344
+ assert.ok(sample, 'Should create sample element inside colour-box');
345
+ assert.strictEqual(
346
+ sample.style.backgroundColor,
347
+ 'rgb(255, 0, 0)',
348
+ 'Should set backgroundColor to the color value'
349
+ );
350
+ });
351
+
352
+ test('color box - handles named colors', async () => {
353
+ const syntax = new Syntax();
354
+ registerCSS(syntax);
355
+ const language = await syntax.getLanguage('css');
356
+
357
+ const code = 'div { color: AliceBlue; }';
358
+ const matches = await language.getMatches(syntax, code);
359
+
360
+ const colorMatch = matches.find(
361
+ m => m.type === 'color' && m.expression && m.expression.process
362
+ );
363
+ assert.ok(colorMatch, 'Should find color match with process function');
364
+
365
+ const element = document.createElement('span');
366
+ element.textContent = 'AliceBlue';
367
+
368
+ colorMatch.expression.process(element, colorMatch);
369
+
370
+ const sample = element.querySelector('.sample');
371
+ assert.ok(sample, 'Should create sample element for named color');
372
+ assert.strictEqual(
373
+ sample.style.backgroundColor,
374
+ 'aliceblue',
375
+ 'Should set backgroundColor to named color'
376
+ );
377
+ });
378
+
379
+ test('color box - handles rgba colors', async () => {
380
+ const syntax = new Syntax();
381
+ registerCSS(syntax);
382
+ const language = await syntax.getLanguage('css');
383
+
384
+ const code = 'div { color: rgba(255, 0, 0, 0.5); }';
385
+ const matches = await language.getMatches(syntax, code);
386
+
387
+ const colorMatch = matches.find(
388
+ m => m.type === 'color' && m.expression && m.expression.process
389
+ );
390
+ assert.ok(colorMatch, 'Should find color match with process function');
391
+
392
+ const element = document.createElement('span');
393
+ element.textContent = 'rgba(255, 0, 0, 0.5)';
394
+
395
+ colorMatch.expression.process(element, colorMatch);
396
+
397
+ const sample = element.querySelector('.sample');
398
+ assert.ok(sample, 'Should create sample element for rgba color');
399
+ assert.strictEqual(
400
+ sample.style.backgroundColor,
401
+ 'rgba(255, 0, 0, 0.5)',
402
+ 'Should set backgroundColor to rgba value'
403
+ );
404
+ });
405
+
406
+ test('color box - returns element unchanged if no textContent', async () => {
407
+ const syntax = new Syntax();
408
+ registerCSS(syntax);
409
+ const language = await syntax.getLanguage('css');
410
+
411
+ const code = 'div { color: #ff0000; }';
412
+ const matches = await language.getMatches(syntax, code);
413
+
414
+ const colorMatch = matches.find(
415
+ m => m.type === 'color' && m.expression && m.expression.process
416
+ );
417
+ assert.ok(colorMatch, 'Should find color match with process function');
418
+
419
+ const element = document.createElement('span');
420
+ // No textContent set
421
+
422
+ const result = colorMatch.expression.process(element, colorMatch);
423
+
424
+ assert.strictEqual(result, element, 'Should return the element');
425
+ const colourBox = element.querySelector('.colour-box');
426
+ assert.strictEqual(
427
+ colourBox,
428
+ null,
429
+ 'Should not create colour-box if no textContent'
430
+ );
431
+ });
@@ -0,0 +1,206 @@
1
+ /**
2
+ * Tests for Diff 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('Diff language can be registered', async () => {
20
+ const language = await syntax.getResource('diff');
21
+ assert.ok(language);
22
+ assert.equal(language.name, 'diff');
23
+ });
24
+
25
+ test('Diff can be registered with patch alias', async () => {
26
+ const diff = await syntax.getResource('diff');
27
+ const patch = await syntax.getResource('patch');
28
+ assert.equal(diff, patch);
29
+ });
30
+
31
+ test('Diff can match added file headers (+++)', async () => {
32
+ const language = await syntax.getResource('diff');
33
+ const matches = await language.getMatches(syntax, '+++ b/file.txt');
34
+ assert.ok(matches.length > 0);
35
+ const match = matches.find(m => m.type === 'add');
36
+ assert.ok(match);
37
+ assert.equal(match.value, '+++ b/file.txt');
38
+ });
39
+
40
+ test('Diff can match removed file headers (---)', async () => {
41
+ const language = await syntax.getResource('diff');
42
+ const matches = await language.getMatches(syntax, '--- a/file.txt');
43
+ assert.ok(matches.length > 0);
44
+ const match = matches.find(m => m.type === 'del');
45
+ assert.ok(match);
46
+ assert.equal(match.value, '--- a/file.txt');
47
+ });
48
+
49
+ test('Diff can match chunk headers (@@)', async () => {
50
+ const language = await syntax.getResource('diff');
51
+ const matches = await language.getMatches(syntax, '@@ -1,3 +1,4 @@');
52
+ assert.ok(matches.length > 0);
53
+ const match = matches.find(m => m.type === 'offset');
54
+ assert.ok(match);
55
+ assert.equal(match.value, '@@ -1,3 +1,4 @@');
56
+ });
57
+
58
+ test('Diff can match chunk headers with context', async () => {
59
+ const language = await syntax.getResource('diff');
60
+ const matches = await language.getMatches(
61
+ syntax,
62
+ '@@ -10,7 +10,8 @@ function test() {'
63
+ );
64
+ assert.ok(matches.length > 0);
65
+ const match = matches.find(m => m.type === 'offset');
66
+ assert.ok(match);
67
+ assert.ok(match.value.includes('@@'));
68
+ });
69
+
70
+ test('Diff can match inserted lines', async () => {
71
+ const language = await syntax.getResource('diff');
72
+ const matches = await language.getMatches(syntax, '+This line was added');
73
+ assert.ok(matches.length > 0);
74
+ const match = matches.find(m => m.type === 'insert');
75
+ assert.ok(match);
76
+ assert.equal(match.value, '+This line was added');
77
+ });
78
+
79
+ test('Diff can match removed lines', async () => {
80
+ const language = await syntax.getResource('diff');
81
+ const matches = await language.getMatches(syntax, '-This line was removed');
82
+ assert.ok(matches.length > 0);
83
+ const match = matches.find(m => m.type === 'remove');
84
+ assert.ok(match);
85
+ assert.equal(match.value, '-This line was removed');
86
+ });
87
+
88
+ test('Diff does not match +++ as insert', async () => {
89
+ const language = await syntax.getResource('diff');
90
+ const matches = await language.getMatches(syntax, '+++ b/file.txt');
91
+ const insert = matches.find(m => m.type === 'insert');
92
+ assert.ok(!insert, 'Should not match +++ as insert');
93
+ const add = matches.find(m => m.type === 'add');
94
+ assert.ok(add, 'Should match +++ as add');
95
+ });
96
+
97
+ test('Diff does not match --- as remove', async () => {
98
+ const language = await syntax.getResource('diff');
99
+ const matches = await language.getMatches(syntax, '--- a/file.txt');
100
+ const remove = matches.find(m => m.type === 'remove');
101
+ assert.ok(!remove, 'Should not match --- as remove');
102
+ const del = matches.find(m => m.type === 'del');
103
+ assert.ok(del, 'Should match --- as del');
104
+ });
105
+
106
+ test('Diff can process complete diff to HTML', async () => {
107
+ const language = await syntax.getResource('diff');
108
+ const diff = `--- a/test.js
109
+ +++ b/test.js
110
+ @@ -1,3 +1,4 @@
111
+ function hello() {
112
+ - console.log("old");
113
+ + console.log("new");
114
+ + return true;
115
+ }`;
116
+
117
+ const html = await language.process(syntax, diff);
118
+ assert.ok(html instanceof HTMLElement);
119
+ const text = html.textContent;
120
+ assert.ok(text.includes('hello'));
121
+ assert.ok(text.includes('old'));
122
+ assert.ok(text.includes('new'));
123
+ });
124
+
125
+ test('Diff highlights file headers correctly', async () => {
126
+ const language = await syntax.getResource('diff');
127
+ const diff = `--- a/README.md
128
+ +++ b/README.md`;
129
+
130
+ const html = await language.process(syntax, diff);
131
+ const htmlStr = html.innerHTML;
132
+ assert.ok(htmlStr.includes('del'));
133
+ assert.ok(htmlStr.includes('add'));
134
+ assert.ok(htmlStr.includes('README.md'));
135
+ });
136
+
137
+ test('Diff highlights multiple chunks', async () => {
138
+ const language = await syntax.getResource('diff');
139
+ const diff = `@@ -1,2 +1,2 @@
140
+ -old line 1
141
+ +new line 1
142
+ @@ -10,2 +10,3 @@
143
+ context
144
+ +added line`;
145
+
146
+ const html = await language.process(syntax, diff);
147
+ const htmlStr = html.innerHTML;
148
+ assert.ok(htmlStr.includes('offset'));
149
+ assert.ok(htmlStr.includes('remove'));
150
+ assert.ok(htmlStr.includes('insert'));
151
+ });
152
+
153
+ test('Diff can build a syntax tree', async () => {
154
+ const language = await syntax.getResource('diff');
155
+ const diff = `--- a/file.txt
156
+ +++ b/file.txt
157
+ @@ -1 +1 @@
158
+ -old
159
+ +new`;
160
+
161
+ const tree = await language.buildTree(syntax, diff, 0);
162
+ assert.ok(tree);
163
+ assert.ok(tree.children.length > 0);
164
+ });
165
+
166
+ test('Diff handles empty lines correctly', async () => {
167
+ const language = await syntax.getResource('diff');
168
+ const diff = ` unchanged line
169
+ +added line
170
+ another unchanged`;
171
+
172
+ const html = await language.process(syntax, diff);
173
+ const text = html.textContent;
174
+ assert.ok(text.includes('unchanged'));
175
+ assert.ok(text.includes('added'));
176
+ });
177
+
178
+ test('Diff handles context lines (no prefix)', async () => {
179
+ const language = await syntax.getResource('diff');
180
+ const matches = await language.getMatches(syntax, ' context line');
181
+ // Context lines (starting with space) should not have special highlighting
182
+ const specialMatches = matches.filter(m =>
183
+ ['insert', 'remove', 'add', 'del', 'offset'].includes(m.type)
184
+ );
185
+ assert.equal(specialMatches.length, 0);
186
+ });
187
+
188
+ test('Diff processes realistic git diff', async () => {
189
+ const language = await syntax.getResource('diff');
190
+ const diff = `diff --git a/src/main.js b/src/main.js
191
+ index 1234567..abcdefg 100644
192
+ --- a/src/main.js
193
+ +++ b/src/main.js
194
+ @@ -15,6 +15,7 @@ function initialize() {
195
+ config.load();
196
+ database.connect();
197
+ + logger.init();
198
+ server.start();
199
+ }`;
200
+
201
+ const html = await language.process(syntax, diff);
202
+ assert.ok(html instanceof HTMLElement);
203
+ const htmlStr = html.innerHTML;
204
+ assert.ok(htmlStr.includes('main.js'));
205
+ assert.ok(htmlStr.includes('initialize'));
206
+ });