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,123 @@
1
+ /**
2
+ * Tests for YAML language definition
3
+ */
4
+
5
+ import {test} from 'node:test';
6
+ import assert from 'node:assert';
7
+ import {JSDOM} from 'jsdom';
8
+
9
+ // Setup DOM environment
10
+ const dom = new JSDOM('<!DOCTYPE html><html><body></body></html>');
11
+ global.document = dom.window.document;
12
+
13
+ import Syntax from '../../../Syntax.js';
14
+ import registerYaml from '../../../Syntax/Language/yaml.js';
15
+ import {
16
+ assertToken,
17
+ assertTokenType,
18
+ assertTokenCount,
19
+ getMatchText
20
+ } from '../../helpers/ast-matcher.js';
21
+
22
+ test('YAML language can be registered', async () => {
23
+ const syntax = new Syntax();
24
+ registerYaml(syntax);
25
+ const language = await syntax.getLanguage('yaml');
26
+ assert.ok(language);
27
+ assert.strictEqual(language.name, 'yaml');
28
+ });
29
+
30
+ test('YAML can match comments', async () => {
31
+ const syntax = new Syntax();
32
+ registerYaml(syntax);
33
+ const language = await syntax.getLanguage('yaml');
34
+
35
+ const code = '# This is a comment\nkey: value';
36
+ const matches = await language.getMatches(syntax, code);
37
+
38
+ const commentMatch = assertTokenType(matches, 'comment');
39
+ const text = getMatchText(code, commentMatch);
40
+ assert.ok(text.startsWith('#'));
41
+ });
42
+
43
+ test('YAML can match single-quoted strings', async () => {
44
+ const syntax = new Syntax();
45
+ registerYaml(syntax);
46
+ const language = await syntax.getLanguage('yaml');
47
+
48
+ const code = "message: 'hello world'";
49
+ const matches = await language.getMatches(syntax, code);
50
+
51
+ assertToken(code, matches, 'string', "'hello world'");
52
+ });
53
+
54
+ test('YAML can match double-quoted strings', async () => {
55
+ const syntax = new Syntax();
56
+ registerYaml(syntax);
57
+ const language = await syntax.getLanguage('yaml');
58
+
59
+ const code = 'message: "hello world"';
60
+ const matches = await language.getMatches(syntax, code);
61
+
62
+ assertToken(code, matches, 'string', '"hello world"');
63
+ });
64
+
65
+ test('YAML can match anchors and aliases', async () => {
66
+ const syntax = new Syntax();
67
+ registerYaml(syntax);
68
+ const language = await syntax.getLanguage('yaml');
69
+
70
+ const code = 'anchor: &ref value\nalias: *ref';
71
+ const matches = await language.getMatches(syntax, code);
72
+
73
+ assertToken(code, matches, 'constant', '&ref');
74
+ assertToken(code, matches, 'constant', '*ref');
75
+ });
76
+
77
+ test('YAML can match keys', async () => {
78
+ const syntax = new Syntax();
79
+ registerYaml(syntax);
80
+ const language = await syntax.getLanguage('yaml');
81
+
82
+ const code = 'name: John\nage: 30';
83
+ const matches = await language.getMatches(syntax, code);
84
+
85
+ assertToken(code, matches, 'keyword', 'name');
86
+ assertToken(code, matches, 'keyword', 'age');
87
+ });
88
+
89
+ test('YAML can match URLs', async () => {
90
+ const syntax = new Syntax();
91
+ registerYaml(syntax);
92
+ const language = await syntax.getLanguage('yaml');
93
+
94
+ const code = 'url: https://example.com/path';
95
+ const matches = await language.getMatches(syntax, code);
96
+
97
+ assertToken(code, matches, 'href', 'https://example.com/path');
98
+ });
99
+
100
+ test('YAML can process code to HTML', async () => {
101
+ const syntax = new Syntax();
102
+ registerYaml(syntax);
103
+ const language = await syntax.getLanguage('yaml');
104
+
105
+ const code = 'name: John';
106
+ const html = await language.process(syntax, code);
107
+
108
+ assert.ok(html.innerHTML.includes('keyword'));
109
+ assert.ok(html.innerHTML.includes('name'));
110
+ });
111
+
112
+ test('YAML can build a syntax tree', async () => {
113
+ const syntax = new Syntax();
114
+ registerYaml(syntax);
115
+ const language = await syntax.getLanguage('yaml');
116
+
117
+ const code = 'key: value';
118
+ const tree = await language.buildTree(syntax, code, 0);
119
+
120
+ assert.ok(tree);
121
+ assert.strictEqual(tree.offset, 0);
122
+ assert.strictEqual(tree.length, code.length);
123
+ });
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Tests for Language class
3
+ */
4
+
5
+ import {test} from 'node:test';
6
+ import assert from 'node:assert';
7
+
8
+ import Syntax from '../../Syntax.js';
9
+ import {Language} from '../../Syntax/Language.js';
10
+
11
+ test('Language can be created', () => {
12
+ const language = new Language();
13
+ assert.ok(language);
14
+ assert.strictEqual(language.name, null);
15
+ });
16
+
17
+ test('Language can set name', () => {
18
+ const language = new Language();
19
+ language.name = 'javascript';
20
+ assert.strictEqual(language.name, 'javascript');
21
+ });
22
+
23
+ test('Language can add keyword rules', async () => {
24
+ const syntax = new Syntax();
25
+ const language = new Language();
26
+ const keywords = ['const', 'let', 'var'];
27
+
28
+ language.push(keywords, {type: 'keyword'});
29
+
30
+ // Verify by checking that matches can be found
31
+ const matches = await language.getMatches(syntax, 'const x = 1;');
32
+ assert.ok(matches.length > 0);
33
+ assert.strictEqual(matches[0].expression.type, 'keyword');
34
+ });
35
+
36
+ test('Language can add pattern rules', async () => {
37
+ const syntax = new Syntax();
38
+ const language = new Language();
39
+
40
+ language.push({
41
+ pattern: /\/\/.*$/m,
42
+ type: 'comment'
43
+ });
44
+
45
+ // Verify by checking that matches can be found
46
+ const matches = await language.getMatches(syntax, '// this is a comment');
47
+ assert.ok(matches.length > 0);
48
+ assert.strictEqual(matches[0].expression.type, 'comment');
49
+ });
50
+
51
+ test('Language can get matches from text', async () => {
52
+ const syntax = new Syntax();
53
+ const language = new Language();
54
+ language.push(['const', 'let'], {type: 'keyword'});
55
+
56
+ const code = 'const x = 42;';
57
+ const matches = await language.getMatches(syntax, code);
58
+
59
+ assert.ok(matches.length > 0);
60
+ const keywordMatch = matches.find(m => m.type === 'keyword');
61
+ assert.ok(keywordMatch);
62
+ });
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Tests for Match class
3
+ */
4
+
5
+ import {test} from 'node:test';
6
+ import assert from 'node:assert';
7
+
8
+ import {Match} from '../../Syntax/Match.js';
9
+
10
+ test('Match can be created with string type', () => {
11
+ const match = new Match(0, 5, 'keyword');
12
+ assert.strictEqual(match.offset, 0);
13
+ assert.strictEqual(match.length, 5);
14
+ assert.strictEqual(match.type, 'keyword');
15
+ });
16
+
17
+ test('Match can be created with expression object', () => {
18
+ const expression = {type: 'string', owner: null};
19
+ const match = new Match(10, 8, expression);
20
+ assert.strictEqual(match.offset, 10);
21
+ assert.strictEqual(match.length, 8);
22
+ assert.strictEqual(match.type, 'string');
23
+ assert.strictEqual(match.expression, expression);
24
+ });
25
+
26
+ test('Match stores value', () => {
27
+ const match = new Match(0, 5, 'keyword', 'const');
28
+ assert.strictEqual(match.value, 'const');
29
+ });
30
+
31
+ test('Match calculates endOffset', () => {
32
+ const match = new Match(10, 5, 'keyword');
33
+ assert.strictEqual(match.endOffset, 15);
34
+ });
35
+
36
+ test('Match initializes with empty children array', () => {
37
+ const match = new Match(0, 5, 'keyword');
38
+ assert.ok(Array.isArray(match.children));
39
+ assert.strictEqual(match.children.length, 0);
40
+ });
@@ -0,0 +1,251 @@
1
+ // Test suite for Syntax/Rule.js
2
+ import Rule from '../../Syntax/Rule.js';
3
+ import {test} from 'node:test';
4
+ import assert from 'node:assert';
5
+ import {JSDOM} from 'jsdom';
6
+
7
+ // Setup DOM environment for tests that need document
8
+ const dom = new JSDOM('<!DOCTYPE html><html><body></body></html>');
9
+ global.document = dom.window.document;
10
+
11
+ test('cStyleComment matches C-style comments', () => {
12
+ const input = '/* this is a comment */';
13
+ const match = Rule.cStyleComment.pattern.exec(input);
14
+ assert.ok(match);
15
+ assert.strictEqual(match[0], '/* this is a comment */');
16
+ });
17
+
18
+ test('cStyleComment matches multi-line comments', () => {
19
+ const input = '/* line 1\nline 2\nline 3 */';
20
+ const match = Rule.cStyleComment.pattern.exec(input);
21
+ assert.ok(match);
22
+ assert.strictEqual(match[0], '/* line 1\nline 2\nline 3 */');
23
+ });
24
+
25
+ test('cppStyleComment matches C++-style comments', () => {
26
+ const input = '// this is a comment';
27
+ const match = Rule.cppStyleComment.pattern.exec(input);
28
+ assert.ok(match);
29
+ assert.strictEqual(match[0], '// this is a comment');
30
+ });
31
+
32
+ test('perlStyleComment matches Perl-style comments', () => {
33
+ const input = '# this is a comment';
34
+ const match = Rule.perlStyleComment.pattern.exec(input);
35
+ assert.ok(match);
36
+ assert.strictEqual(match[0], '# this is a comment');
37
+ });
38
+
39
+ test('perlStyleRegularExpression matches Perl regex literals', () => {
40
+ const input = 'x = /test/g ';
41
+ const match = Rule.perlStyleRegularExpression.pattern.exec(input);
42
+ assert.ok(match);
43
+ assert.strictEqual(match[0], '/test/g');
44
+ });
45
+
46
+ test('rubyStyleRegularExpression matches Ruby regex literals', () => {
47
+ const input = 'x = /test/i do';
48
+ const match = Rule.rubyStyleRegularExpression.pattern.exec(input);
49
+ assert.ok(match);
50
+ assert.strictEqual(match[0], '/test/i');
51
+ });
52
+
53
+ test('camelCaseType matches CamelCase types', () => {
54
+ const input = 'MyClass';
55
+ const match = Rule.camelCaseType.pattern.exec(input);
56
+ assert.ok(match);
57
+ assert.strictEqual(match[0], 'MyClass');
58
+ });
59
+
60
+ test('cStyleType matches C-style type names', () => {
61
+ const input = 'size_t';
62
+ const match = Rule.cStyleType.pattern.exec(input);
63
+ assert.ok(match);
64
+ assert.strictEqual(match[0], 'size_t');
65
+ });
66
+
67
+ test('xmlComment matches XML comments', () => {
68
+ const input = '<!-- this is a comment -->';
69
+ const match = Rule.xmlComment.pattern.exec(input);
70
+ assert.ok(match);
71
+ assert.strictEqual(match[0], '<!-- this is a comment -->');
72
+ });
73
+
74
+ test('xmlComment matches HTML entity-encoded comments', () => {
75
+ const input = '&lt;!-- comment --&gt;';
76
+ const match = Rule.xmlComment.pattern.exec(input);
77
+ assert.ok(match);
78
+ assert.strictEqual(match[0], '&lt;!-- comment --&gt;');
79
+ });
80
+
81
+ test('webLink matches HTTP URLs', () => {
82
+ const input = 'Visit https://example.com/path?query=value';
83
+ const match = Rule.webLink.pattern.exec(input);
84
+ assert.ok(match);
85
+ assert.strictEqual(match[0], 'https://example.com/path?query=value');
86
+ });
87
+
88
+ test('webLink matches FTP URLs', () => {
89
+ const input = 'ftp://files.example.com/';
90
+ const match = Rule.webLink.pattern.exec(input);
91
+ assert.ok(match);
92
+ assert.strictEqual(match[0], 'ftp://files.example.com/');
93
+ });
94
+
95
+ test('hexNumber matches hexadecimal numbers', () => {
96
+ const input = 'value = 0xFF00AB';
97
+ const match = Rule.hexNumber.pattern.exec(input);
98
+ assert.ok(match);
99
+ assert.strictEqual(match[0], '0xFF00AB');
100
+ });
101
+
102
+ test('decimalNumber matches integers', () => {
103
+ const input = 'count = 42';
104
+ const match = Rule.decimalNumber.pattern.exec(input);
105
+ assert.ok(match);
106
+ assert.strictEqual(match[0], '42');
107
+ });
108
+
109
+ test('decimalNumber matches floats', () => {
110
+ const input = 'pi = 3.14159';
111
+ const match = Rule.decimalNumber.pattern.exec(input);
112
+ assert.ok(match);
113
+ assert.strictEqual(match[0], '3.14159');
114
+ });
115
+
116
+ test('decimalNumber matches scientific notation', () => {
117
+ const input = 'mass = 6.022e23';
118
+ const match = Rule.decimalNumber.pattern.exec(input);
119
+ assert.ok(match);
120
+ assert.strictEqual(match[0], '6.022e23');
121
+ });
122
+
123
+ test('decimalNumber matches negative numbers', () => {
124
+ const input = 'temp = -273.15';
125
+ const match = Rule.decimalNumber.pattern.exec(input);
126
+ assert.ok(match);
127
+ // Note: The regex has \b at the start, so it won't match the leading -
128
+ // It matches the number part after the minus
129
+ assert.strictEqual(match[0], '273.15');
130
+ });
131
+
132
+ test('doubleQuotedString matches double-quoted strings', () => {
133
+ const input = '"hello world"';
134
+ const match = Rule.doubleQuotedString.pattern.exec(input);
135
+ assert.ok(match);
136
+ assert.strictEqual(match[0], '"hello world"');
137
+ });
138
+
139
+ test('doubleQuotedString matches strings with escaped quotes', () => {
140
+ const input = '"say \\"hello\\""';
141
+ const match = Rule.doubleQuotedString.pattern.exec(input);
142
+ assert.ok(match);
143
+ assert.strictEqual(match[0], '"say \\"hello\\""');
144
+ });
145
+
146
+ test('singleQuotedString matches single-quoted strings', () => {
147
+ const input = "'hello world'";
148
+ const match = Rule.singleQuotedString.pattern.exec(input);
149
+ assert.ok(match);
150
+ assert.strictEqual(match[0], "'hello world'");
151
+ });
152
+
153
+ test('singleQuotedString matches strings with escaped quotes', () => {
154
+ const input = "'it\\'s working'";
155
+ const match = Rule.singleQuotedString.pattern.exec(input);
156
+ assert.ok(match);
157
+ assert.strictEqual(match[0], "'it\\'s working'");
158
+ });
159
+
160
+ test('multiLineDoubleQuotedString matches multi-line strings', () => {
161
+ const input = '"line 1\nline 2"';
162
+ const match = Rule.multiLineDoubleQuotedString.pattern.exec(input);
163
+ assert.ok(match);
164
+ assert.strictEqual(match[0], '"line 1\nline 2"');
165
+ });
166
+
167
+ test('multiLineSingleQuotedString matches multi-line strings', () => {
168
+ const input = "'line 1\nline 2'";
169
+ const match = Rule.multiLineSingleQuotedString.pattern.exec(input);
170
+ assert.ok(match);
171
+ assert.strictEqual(match[0], "'line 1\nline 2'");
172
+ });
173
+
174
+ test('stringEscape matches backslash escapes', () => {
175
+ const input = '\\n';
176
+ const match = Rule.stringEscape.pattern.exec(input);
177
+ assert.ok(match);
178
+ assert.strictEqual(match[0], '\\n');
179
+ });
180
+
181
+ test('stringEscape matches escaped quotes', () => {
182
+ const input = '\\"';
183
+ const match = Rule.stringEscape.pattern.exec(input);
184
+ assert.ok(match);
185
+ assert.strictEqual(match[0], '\\"');
186
+ });
187
+
188
+ test('webLinkProcess creates anchor elements', () => {
189
+ const baseUrl = 'http://docs.example.com/search?q=';
190
+ const process = Rule.webLinkProcess(baseUrl);
191
+
192
+ // Create a mock container and match
193
+ const container = document.createElement('span');
194
+ container.className = 'function';
195
+ container.textContent = 'myFunction';
196
+
197
+ const match = {
198
+ value: 'myFunction',
199
+ expression: {type: 'function'}
200
+ };
201
+
202
+ const result = process(container, match, {});
203
+
204
+ assert.strictEqual(result.tagName, 'A');
205
+ assert.strictEqual(result.className, 'function');
206
+ assert.strictEqual(result.textContent, 'myFunction');
207
+ assert.ok(result.href.includes('docs.example.com'));
208
+ assert.ok(result.href.includes('myFunction'));
209
+ });
210
+
211
+ test('webLinkProcess encodes URLs properly', () => {
212
+ const baseUrl = 'http://docs.example.com/search?q=';
213
+ const process = Rule.webLinkProcess(baseUrl);
214
+
215
+ const container = document.createElement('span');
216
+ container.className = 'function';
217
+ container.textContent = 'my Function';
218
+
219
+ const match = {
220
+ value: 'my Function',
221
+ expression: {type: 'function'}
222
+ };
223
+
224
+ const result = process(container, match, {});
225
+
226
+ // Should encode the space
227
+ assert.ok(result.href.includes('my%20Function'));
228
+ });
229
+
230
+ test('webLinkProcess preserves nested HTML', () => {
231
+ const baseUrl = 'http://docs.example.com/';
232
+ const process = Rule.webLinkProcess(baseUrl);
233
+
234
+ const container = document.createElement('span');
235
+ container.className = 'function';
236
+ container.innerHTML = 'my<span class="highlight">Func</span>tion';
237
+
238
+ const match = {
239
+ value: 'myFunction',
240
+ expression: {type: 'function'}
241
+ };
242
+
243
+ const result = process(container, match, {});
244
+
245
+ assert.strictEqual(result.tagName, 'A');
246
+ assert.strictEqual(
247
+ result.innerHTML,
248
+ 'my<span class="highlight">Func</span>tion'
249
+ );
250
+ assert.strictEqual(result.className, 'function');
251
+ });
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Tests for Syntax class
3
+ */
4
+
5
+ import {test} from 'node:test';
6
+ import assert from 'node:assert';
7
+
8
+ import Syntax from '../Syntax.js';
9
+
10
+ test('Syntax class can be instantiated', () => {
11
+ const syntax = new Syntax();
12
+ assert.ok(syntax instanceof Syntax);
13
+ });
14
+
15
+ test('Syntax.default returns a singleton instance', () => {
16
+ const instance1 = Syntax.default;
17
+ const instance2 = Syntax.default;
18
+ assert.strictEqual(instance1, instance2);
19
+ });
20
+
21
+ test('Syntax can register languages', async () => {
22
+ const syntax = new Syntax();
23
+ const mockLanguage = {type: 'test'};
24
+ syntax.register('test', mockLanguage);
25
+
26
+ assert.strictEqual(await syntax.getLanguage('test'), mockLanguage);
27
+ });
28
+
29
+ test('Syntax can register aliases', async () => {
30
+ const syntax = new Syntax();
31
+ const mockLanguage = {type: 'javascript'};
32
+ syntax.register('javascript', mockLanguage);
33
+ syntax.alias('javascript', ['js', 'jsx']);
34
+
35
+ assert.strictEqual(await syntax.getLanguage('js'), mockLanguage);
36
+ assert.strictEqual(await syntax.getLanguage('jsx'), mockLanguage);
37
+ assert.strictEqual(await syntax.getLanguage('javascript'), mockLanguage);
38
+ });
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Test helpers for AST/token matching
3
+ */
4
+
5
+ import assert from 'node:assert';
6
+
7
+ /**
8
+ * Assert that a specific token type exists in matches at the expected text
9
+ */
10
+ export function assertToken(code, matches, type, expectedText) {
11
+ const match = matches.find(
12
+ m =>
13
+ m.type === type &&
14
+ code.substring(m.offset, m.offset + m.length) === expectedText
15
+ );
16
+ assert.ok(
17
+ match,
18
+ `Expected to find token of type '${type}' with text '${expectedText}'`
19
+ );
20
+ return match;
21
+ }
22
+
23
+ /**
24
+ * Assert that a specific token type exists in matches
25
+ */
26
+ export function assertTokenType(matches, type) {
27
+ const match = matches.find(m => m.type === type);
28
+ assert.ok(match, `Expected to find token of type '${type}'`);
29
+ return match;
30
+ }
31
+
32
+ /**
33
+ * Assert that code contains a token of given type at specific position
34
+ */
35
+ export function assertTokenAt(code, matches, type, expectedText, offset) {
36
+ const match = matches.find(
37
+ m =>
38
+ m.type === type &&
39
+ m.offset === offset &&
40
+ code.substring(m.offset, m.offset + m.length) === expectedText
41
+ );
42
+ assert.ok(
43
+ match,
44
+ `Expected to find token of type '${type}' with text '${expectedText}' at offset ${offset}`
45
+ );
46
+ return match;
47
+ }
48
+
49
+ /**
50
+ * Get all tokens of a specific type from matches
51
+ */
52
+ export function getTokensOfType(matches, type) {
53
+ return matches.filter(m => m.type === type);
54
+ }
55
+
56
+ /**
57
+ * Assert that matches contain at least N tokens of given type
58
+ */
59
+ export function assertTokenCount(matches, type, minCount) {
60
+ const tokens = getTokensOfType(matches, type);
61
+ assert.ok(
62
+ tokens.length >= minCount,
63
+ `Expected at least ${minCount} tokens of type '${type}', found ${tokens.length}`
64
+ );
65
+ return tokens;
66
+ }
67
+
68
+ /**
69
+ * Extract the text content of a match from source code
70
+ */
71
+ export function getMatchText(code, match) {
72
+ return code.substring(match.offset, match.offset + match.length);
73
+ }
74
+
75
+ /**
76
+ * Assert that highlighted HTML output contains expected token classes
77
+ */
78
+ export function assertHTMLContains(html, tokenType, expectedText) {
79
+ const innerHTML = html.innerHTML || html.textContent;
80
+ assert.ok(
81
+ innerHTML.includes(tokenType),
82
+ `Expected HTML to contain token type '${tokenType}'`
83
+ );
84
+ if (expectedText) {
85
+ assert.ok(
86
+ innerHTML.includes(expectedText),
87
+ `Expected HTML to contain text '${expectedText}'`
88
+ );
89
+ }
90
+ }
@@ -0,0 +1 @@
1
+ /* Per-language overrides for Apache (empty by default). */
@@ -0,0 +1 @@
1
+ /* Per-language overrides for AppleScript (empty by default). */
@@ -0,0 +1 @@
1
+ /* Per-language overrides for Assembly (empty by default). */
@@ -0,0 +1 @@
1
+ /* Per-language overrides for Bash (empty by default). */
@@ -0,0 +1 @@
1
+ /* Per-language overrides for BASIC (empty by default). */
@@ -0,0 +1 @@
1
+ /* Per-language overrides for C (empty by default). */
@@ -0,0 +1 @@
1
+ /* Per-language overrides for C# (empty by default). */
@@ -0,0 +1,22 @@
1
+ /* Per-language overrides for CSS (empty by default). */
2
+
3
+ /* Color box styling */
4
+ .colour-box {
5
+ display: inline-block;
6
+ margin: 0 0.2em;
7
+ border: 1px solid #999;
8
+ line-height: 0.9;
9
+ vertical-align: middle;
10
+ }
11
+
12
+ .colour-box .sample {
13
+ display: inline-block;
14
+ width: 0.9em;
15
+ height: 0.9em;
16
+ }
17
+
18
+ @media (prefers-color-scheme: dark) {
19
+ .colour-box {
20
+ border-color: #666;
21
+ }
22
+ }