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.
- checksums.yaml +7 -0
- data/bin/presently +13 -0
- data/lib/presently/application.rb +104 -0
- data/lib/presently/clock.rb +77 -0
- data/lib/presently/display_view.rb +73 -0
- data/lib/presently/environment/application.rb +62 -0
- data/lib/presently/page.rb +38 -0
- data/lib/presently/page.xrb +31 -0
- data/lib/presently/presentation.rb +72 -0
- data/lib/presently/presentation_controller.rb +181 -0
- data/lib/presently/presenter_view.rb +264 -0
- data/lib/presently/slide.rb +148 -0
- data/lib/presently/slide_view.rb +92 -0
- data/lib/presently/state.rb +66 -0
- data/lib/presently/version.rb +9 -0
- data/lib/presently.rb +9 -0
- data/license.md +21 -0
- data/public/_components/@socketry/syntax/Syntax/CodeElement.js +337 -0
- data/public/_components/@socketry/syntax/Syntax/Errors.js +52 -0
- data/public/_components/@socketry/syntax/Syntax/Language/apache.js +49 -0
- data/public/_components/@socketry/syntax/Syntax/Language/applescript.js +157 -0
- data/public/_components/@socketry/syntax/Syntax/Language/assembly.js +42 -0
- data/public/_components/@socketry/syntax/Syntax/Language/bash-script.js +108 -0
- data/public/_components/@socketry/syntax/Syntax/Language/bash.js +32 -0
- data/public/_components/@socketry/syntax/Syntax/Language/basic.js +232 -0
- data/public/_components/@socketry/syntax/Syntax/Language/c++.js +1 -0
- data/public/_components/@socketry/syntax/Syntax/Language/c.js +1 -0
- data/public/_components/@socketry/syntax/Syntax/Language/clang.js +201 -0
- data/public/_components/@socketry/syntax/Syntax/Language/cpp.js +1 -0
- data/public/_components/@socketry/syntax/Syntax/Language/csharp.js +166 -0
- data/public/_components/@socketry/syntax/Syntax/Language/css.js +244 -0
- data/public/_components/@socketry/syntax/Syntax/Language/diff.js +24 -0
- data/public/_components/@socketry/syntax/Syntax/Language/go.js +135 -0
- data/public/_components/@socketry/syntax/Syntax/Language/haskell.js +110 -0
- data/public/_components/@socketry/syntax/Syntax/Language/html.js +69 -0
- data/public/_components/@socketry/syntax/Syntax/Language/io.js +68 -0
- data/public/_components/@socketry/syntax/Syntax/Language/java.js +134 -0
- data/public/_components/@socketry/syntax/Syntax/Language/javascript.js +89 -0
- data/public/_components/@socketry/syntax/Syntax/Language/json.js +36 -0
- data/public/_components/@socketry/syntax/Syntax/Language/lisp.js +38 -0
- data/public/_components/@socketry/syntax/Syntax/Language/lua.js +87 -0
- data/public/_components/@socketry/syntax/Syntax/Language/markdown.js +112 -0
- data/public/_components/@socketry/syntax/Syntax/Language/nginx.js +37 -0
- data/public/_components/@socketry/syntax/Syntax/Language/objective-c.js +1 -0
- data/public/_components/@socketry/syntax/Syntax/Language/ocaml.js +225 -0
- data/public/_components/@socketry/syntax/Syntax/Language/pascal.js +166 -0
- data/public/_components/@socketry/syntax/Syntax/Language/patch.js +2 -0
- data/public/_components/@socketry/syntax/Syntax/Language/perl5.js +317 -0
- data/public/_components/@socketry/syntax/Syntax/Language/php-script.js +112 -0
- data/public/_components/@socketry/syntax/Syntax/Language/php.js +18 -0
- data/public/_components/@socketry/syntax/Syntax/Language/plain.js +20 -0
- data/public/_components/@socketry/syntax/Syntax/Language/protobuf.js +77 -0
- data/public/_components/@socketry/syntax/Syntax/Language/python.js +208 -0
- data/public/_components/@socketry/syntax/Syntax/Language/ruby.js +124 -0
- data/public/_components/@socketry/syntax/Syntax/Language/scala.js +81 -0
- data/public/_components/@socketry/syntax/Syntax/Language/smalltalk.js +30 -0
- data/public/_components/@socketry/syntax/Syntax/Language/sql.js +865 -0
- data/public/_components/@socketry/syntax/Syntax/Language/super-collider.js +70 -0
- data/public/_components/@socketry/syntax/Syntax/Language/swift.js +176 -0
- data/public/_components/@socketry/syntax/Syntax/Language/xml.js +76 -0
- data/public/_components/@socketry/syntax/Syntax/Language/xrb.js +33 -0
- data/public/_components/@socketry/syntax/Syntax/Language/yaml.js +29 -0
- data/public/_components/@socketry/syntax/Syntax/Language.js +276 -0
- data/public/_components/@socketry/syntax/Syntax/Loader.js +78 -0
- data/public/_components/@socketry/syntax/Syntax/Match.js +546 -0
- data/public/_components/@socketry/syntax/Syntax/Rule.js +306 -0
- data/public/_components/@socketry/syntax/Syntax.js +356 -0
- data/public/_components/@socketry/syntax/bin/syntax-ast.js +42 -0
- data/public/_components/@socketry/syntax/examples/_template.html +53 -0
- data/public/_components/@socketry/syntax/examples/apache.html +72 -0
- data/public/_components/@socketry/syntax/examples/applescript.html +72 -0
- data/public/_components/@socketry/syntax/examples/assembly.html +74 -0
- data/public/_components/@socketry/syntax/examples/bash.html +90 -0
- data/public/_components/@socketry/syntax/examples/basic.html +87 -0
- data/public/_components/@socketry/syntax/examples/c.html +141 -0
- data/public/_components/@socketry/syntax/examples/clang.html +202 -0
- data/public/_components/@socketry/syntax/examples/csharp.html +110 -0
- data/public/_components/@socketry/syntax/examples/css-colors.html +179 -0
- data/public/_components/@socketry/syntax/examples/custom-theme.html +155 -0
- data/public/_components/@socketry/syntax/examples/diff.html +142 -0
- data/public/_components/@socketry/syntax/examples/examples.css +216 -0
- data/public/_components/@socketry/syntax/examples/go.html +413 -0
- data/public/_components/@socketry/syntax/examples/haskell.html +373 -0
- data/public/_components/@socketry/syntax/examples/html.html +316 -0
- data/public/_components/@socketry/syntax/examples/index.html +97 -0
- data/public/_components/@socketry/syntax/examples/io.html +552 -0
- data/public/_components/@socketry/syntax/examples/java.html +786 -0
- data/public/_components/@socketry/syntax/examples/javascript.html +199 -0
- data/public/_components/@socketry/syntax/examples/json.html +150 -0
- data/public/_components/@socketry/syntax/examples/lisp.html +476 -0
- data/public/_components/@socketry/syntax/examples/lua.html +737 -0
- data/public/_components/@socketry/syntax/examples/markdown.html +121 -0
- data/public/_components/@socketry/syntax/examples/mixed.html +306 -0
- data/public/_components/@socketry/syntax/examples/nginx.html +554 -0
- data/public/_components/@socketry/syntax/examples/ocaml.html +596 -0
- data/public/_components/@socketry/syntax/examples/pascal.html +762 -0
- data/public/_components/@socketry/syntax/examples/perl5.html +488 -0
- data/public/_components/@socketry/syntax/examples/php-script.html +142 -0
- data/public/_components/@socketry/syntax/examples/php.html +95 -0
- data/public/_components/@socketry/syntax/examples/plain.html +222 -0
- data/public/_components/@socketry/syntax/examples/protobuf.html +405 -0
- data/public/_components/@socketry/syntax/examples/python.html +82 -0
- data/public/_components/@socketry/syntax/examples/readme.md +79 -0
- data/public/_components/@socketry/syntax/examples/ruby.html +58 -0
- data/public/_components/@socketry/syntax/examples/scala.html +41 -0
- data/public/_components/@socketry/syntax/examples/smalltalk.html +436 -0
- data/public/_components/@socketry/syntax/examples/sql.html +373 -0
- data/public/_components/@socketry/syntax/examples/super-collider.html +55 -0
- data/public/_components/@socketry/syntax/examples/swift.html +176 -0
- data/public/_components/@socketry/syntax/examples/wrap-demo.html +103 -0
- data/public/_components/@socketry/syntax/examples/xml.html +112 -0
- data/public/_components/@socketry/syntax/examples/xrb.html +37 -0
- data/public/_components/@socketry/syntax/examples/yaml.html +72 -0
- data/public/_components/@socketry/syntax/license.md +21 -0
- data/public/_components/@socketry/syntax/package-lock.json +834 -0
- data/public/_components/@socketry/syntax/package.json +43 -0
- data/public/_components/@socketry/syntax/readme.md +162 -0
- data/public/_components/@socketry/syntax/test/Syntax/CodeElement.js +306 -0
- data/public/_components/@socketry/syntax/test/Syntax/ErrorHandling.js +85 -0
- data/public/_components/@socketry/syntax/test/Syntax/Language/apache.js +153 -0
- data/public/_components/@socketry/syntax/test/Syntax/Language/applescript.js +198 -0
- data/public/_components/@socketry/syntax/test/Syntax/Language/assembly.js +209 -0
- data/public/_components/@socketry/syntax/test/Syntax/Language/bash-script.js +225 -0
- data/public/_components/@socketry/syntax/test/Syntax/Language/bash.js +162 -0
- data/public/_components/@socketry/syntax/test/Syntax/Language/basic.js +265 -0
- data/public/_components/@socketry/syntax/test/Syntax/Language/clang.js +390 -0
- data/public/_components/@socketry/syntax/test/Syntax/Language/csharp.js +436 -0
- data/public/_components/@socketry/syntax/test/Syntax/Language/css.js +431 -0
- data/public/_components/@socketry/syntax/test/Syntax/Language/diff.js +206 -0
- data/public/_components/@socketry/syntax/test/Syntax/Language/go.js +386 -0
- data/public/_components/@socketry/syntax/test/Syntax/Language/haskell.js +454 -0
- data/public/_components/@socketry/syntax/test/Syntax/Language/html.js +111 -0
- data/public/_components/@socketry/syntax/test/Syntax/Language/io.js +229 -0
- data/public/_components/@socketry/syntax/test/Syntax/Language/java.js +362 -0
- data/public/_components/@socketry/syntax/test/Syntax/Language/javascript.js +101 -0
- data/public/_components/@socketry/syntax/test/Syntax/Language/json.js +101 -0
- data/public/_components/@socketry/syntax/test/Syntax/Language/lisp.js +224 -0
- data/public/_components/@socketry/syntax/test/Syntax/Language/lua.js +307 -0
- data/public/_components/@socketry/syntax/test/Syntax/Language/markdown.js +163 -0
- data/public/_components/@socketry/syntax/test/Syntax/Language/nginx.js +267 -0
- data/public/_components/@socketry/syntax/test/Syntax/Language/ocaml.js +299 -0
- data/public/_components/@socketry/syntax/test/Syntax/Language/pascal.js +311 -0
- data/public/_components/@socketry/syntax/test/Syntax/Language/perl5.js +333 -0
- data/public/_components/@socketry/syntax/test/Syntax/Language/php-script.js +197 -0
- data/public/_components/@socketry/syntax/test/Syntax/Language/php.js +92 -0
- data/public/_components/@socketry/syntax/test/Syntax/Language/plain.js +327 -0
- data/public/_components/@socketry/syntax/test/Syntax/Language/protobuf.js +294 -0
- data/public/_components/@socketry/syntax/test/Syntax/Language/python.js +213 -0
- data/public/_components/@socketry/syntax/test/Syntax/Language/ruby.js +70 -0
- data/public/_components/@socketry/syntax/test/Syntax/Language/scala.js +75 -0
- data/public/_components/@socketry/syntax/test/Syntax/Language/smalltalk.js +223 -0
- data/public/_components/@socketry/syntax/test/Syntax/Language/sql.js +281 -0
- data/public/_components/@socketry/syntax/test/Syntax/Language/super-collider.js +66 -0
- data/public/_components/@socketry/syntax/test/Syntax/Language/swift.js +71 -0
- data/public/_components/@socketry/syntax/test/Syntax/Language/xml.js +170 -0
- data/public/_components/@socketry/syntax/test/Syntax/Language/xrb.js +57 -0
- data/public/_components/@socketry/syntax/test/Syntax/Language/yaml.js +123 -0
- data/public/_components/@socketry/syntax/test/Syntax/Language.js +62 -0
- data/public/_components/@socketry/syntax/test/Syntax/Match.js +40 -0
- data/public/_components/@socketry/syntax/test/Syntax/Rule.js +251 -0
- data/public/_components/@socketry/syntax/test/Syntax.js +38 -0
- data/public/_components/@socketry/syntax/test/helpers/ast-matcher.js +90 -0
- data/public/_components/@socketry/syntax/themes/base/apache.css +1 -0
- data/public/_components/@socketry/syntax/themes/base/applescript.css +1 -0
- data/public/_components/@socketry/syntax/themes/base/assembly.css +1 -0
- data/public/_components/@socketry/syntax/themes/base/bash.css +1 -0
- data/public/_components/@socketry/syntax/themes/base/basic.css +1 -0
- data/public/_components/@socketry/syntax/themes/base/c.css +1 -0
- data/public/_components/@socketry/syntax/themes/base/clang.css +0 -0
- data/public/_components/@socketry/syntax/themes/base/csharp.css +1 -0
- data/public/_components/@socketry/syntax/themes/base/css.css +22 -0
- data/public/_components/@socketry/syntax/themes/base/diff.css +48 -0
- data/public/_components/@socketry/syntax/themes/base/go.css +1 -0
- data/public/_components/@socketry/syntax/themes/base/haskell.css +1 -0
- data/public/_components/@socketry/syntax/themes/base/html.css +1 -0
- data/public/_components/@socketry/syntax/themes/base/io.css +1 -0
- data/public/_components/@socketry/syntax/themes/base/java.css +1 -0
- data/public/_components/@socketry/syntax/themes/base/javascript.css +1 -0
- data/public/_components/@socketry/syntax/themes/base/json.css +41 -0
- data/public/_components/@socketry/syntax/themes/base/lisp.css +1 -0
- data/public/_components/@socketry/syntax/themes/base/lua.css +1 -0
- data/public/_components/@socketry/syntax/themes/base/markdown.css +16 -0
- data/public/_components/@socketry/syntax/themes/base/nginx.css +1 -0
- data/public/_components/@socketry/syntax/themes/base/ocaml.css +1 -0
- data/public/_components/@socketry/syntax/themes/base/pascal.css +1 -0
- data/public/_components/@socketry/syntax/themes/base/perl5.css +1 -0
- data/public/_components/@socketry/syntax/themes/base/php-script.css +1 -0
- data/public/_components/@socketry/syntax/themes/base/php.css +1 -0
- data/public/_components/@socketry/syntax/themes/base/plain.css +1 -0
- data/public/_components/@socketry/syntax/themes/base/protobuf.css +1 -0
- data/public/_components/@socketry/syntax/themes/base/python.css +1 -0
- data/public/_components/@socketry/syntax/themes/base/ruby.css +23 -0
- data/public/_components/@socketry/syntax/themes/base/scala.css +3 -0
- data/public/_components/@socketry/syntax/themes/base/smalltalk.css +1 -0
- data/public/_components/@socketry/syntax/themes/base/sql.css +1 -0
- data/public/_components/@socketry/syntax/themes/base/super-collider.css +33 -0
- data/public/_components/@socketry/syntax/themes/base/swift.css +1 -0
- data/public/_components/@socketry/syntax/themes/base/syntax.css +63 -0
- data/public/_components/@socketry/syntax/themes/base/xml.css +1 -0
- data/public/_components/@socketry/syntax/themes/base/xrb.css +29 -0
- data/public/_components/@socketry/syntax/themes/base/yaml.css +1 -0
- data/public/_components/@socketry/syntax/themes/theming.md +233 -0
- data/public/_components/@socketry/syntax/update-examples.js +135 -0
- data/public/_static/index.css +593 -0
- data/public/application.js +147 -0
- data/readme.md +69 -0
- data/releases.md +3 -0
- data/templates/code.xrb +12 -0
- data/templates/default.xrb +5 -0
- data/templates/image.xrb +8 -0
- data/templates/section.xrb +5 -0
- data/templates/title.xrb +8 -0
- data/templates/translation.xrb +8 -0
- data/templates/two_column.xrb +8 -0
- metadata +280 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@socketry/syntax",
|
|
3
|
+
"version": "0.3.2",
|
|
4
|
+
"description": "A modern, framework-agnostic syntax highlighter using Web Components",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "Syntax.js",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./Syntax.js",
|
|
9
|
+
"./Match": "./Syntax/Match.js",
|
|
10
|
+
"./Language": "./Syntax/Language.js",
|
|
11
|
+
"./Loader": "./Syntax/Loader.js",
|
|
12
|
+
"./Errors": "./Syntax/Errors.js",
|
|
13
|
+
"./Language/*": "./Syntax/Language/*.js"
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"Syntax.js",
|
|
17
|
+
"Syntax/",
|
|
18
|
+
"styles/",
|
|
19
|
+
"themes/"
|
|
20
|
+
],
|
|
21
|
+
"scripts": {
|
|
22
|
+
"test": "node --test 'test/**/*.js'",
|
|
23
|
+
"format": "prettier --write '**/*.{js,json,md}'",
|
|
24
|
+
"format:check": "prettier --check '**/*.{js,json,md}'"
|
|
25
|
+
},
|
|
26
|
+
"keywords": [
|
|
27
|
+
"syntax",
|
|
28
|
+
"highlighting",
|
|
29
|
+
"web-components",
|
|
30
|
+
"code",
|
|
31
|
+
"highlighter"
|
|
32
|
+
],
|
|
33
|
+
"author": "Samuel G. D. Williams",
|
|
34
|
+
"license": "MIT",
|
|
35
|
+
"repository": {
|
|
36
|
+
"type": "git",
|
|
37
|
+
"url": "https://github.com/socketry/syntax-js.git"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"jsdom": "^25.0.0",
|
|
41
|
+
"prettier": "^3.6.2"
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# @socketry/syntax
|
|
2
|
+
|
|
3
|
+
A modern, framework-agnostic syntax highlighter using Web Components. This is a reimplementation of [jQuery.Syntax](https://github.com/ioquatix/jquery-syntax) without jQuery dependencies.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- 🎨 **Modern Web Components** - Uses autonomous custom elements
|
|
8
|
+
- 📦 **Dynamic Loading** - Loads language definitions on-demand
|
|
9
|
+
- 🔒 **No Dependencies** - Pure JavaScript, no jQuery required
|
|
10
|
+
- 🎯 **Framework Agnostic** - Works with React, Vue, vanilla JS, etc.
|
|
11
|
+
- 🌲 **Clean Architecture** - Well-structured classes with clear responsibilities
|
|
12
|
+
- 🔐 **Private Fields** - Modern JavaScript with proper encapsulation
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install @socketry/syntax
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Usage
|
|
21
|
+
|
|
22
|
+
### Automatic Upgrade
|
|
23
|
+
|
|
24
|
+
The easiest way to use Syntax is to let it automatically upgrade existing `<code>` elements:
|
|
25
|
+
|
|
26
|
+
```html
|
|
27
|
+
<script type="module">
|
|
28
|
+
import Syntax from '@socketry/syntax';
|
|
29
|
+
|
|
30
|
+
// Automatically upgrade all code blocks with language classes
|
|
31
|
+
document.addEventListener('DOMContentLoaded', async function() {
|
|
32
|
+
await Syntax.highlight();
|
|
33
|
+
});
|
|
34
|
+
</script>
|
|
35
|
+
|
|
36
|
+
<!-- Standard code blocks - will be automatically upgraded -->
|
|
37
|
+
<pre><code class="language-javascript">
|
|
38
|
+
const hello = "world";
|
|
39
|
+
console.log(hello);
|
|
40
|
+
</code></pre>
|
|
41
|
+
|
|
42
|
+
<p>Inline code: <code class="language-javascript">const x = 1;</code></p>
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
By default, `Syntax.highlight()` will:
|
|
46
|
+
- Find all `<code>` elements with class names matching `language-*` e.g., `language-javascript`, `language-python`.
|
|
47
|
+
- Replace them with `<syntax-code>` web components.
|
|
48
|
+
- Automatically detect if they're inside `<pre>` tags for proper wrapping behavior.
|
|
49
|
+
|
|
50
|
+
You can customize the selector:
|
|
51
|
+
|
|
52
|
+
```javascript
|
|
53
|
+
// Only upgrade specific elements:
|
|
54
|
+
await Syntax.highlight({
|
|
55
|
+
selector: 'code.highlight'
|
|
56
|
+
});
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Manual Web Components
|
|
60
|
+
|
|
61
|
+
You can also use the `<syntax-code>` web component directly:
|
|
62
|
+
|
|
63
|
+
```html
|
|
64
|
+
<script type="module">
|
|
65
|
+
import {Syntax} from '@socketry/syntax';
|
|
66
|
+
|
|
67
|
+
// Disable automatic upgrade, just register the component:
|
|
68
|
+
await Syntax.highlight({upgradeAll: false});
|
|
69
|
+
</script>
|
|
70
|
+
|
|
71
|
+
<!-- Use the web component directly -->
|
|
72
|
+
<syntax-code language="javascript">
|
|
73
|
+
const hello = "world"; console.log(hello);
|
|
74
|
+
</syntax-code>
|
|
75
|
+
|
|
76
|
+
<!-- Inside a <pre> tag for block display with line wrapping -->
|
|
77
|
+
<pre><syntax-code language="python" wrap>
|
|
78
|
+
def greet(name):
|
|
79
|
+
print(f"Hello, {name}!")
|
|
80
|
+
</syntax-code></pre>
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Programmatic Usage
|
|
84
|
+
|
|
85
|
+
```javascript
|
|
86
|
+
import Syntax from '@socketry/syntax';
|
|
87
|
+
import registerJavaScript from '@socketry/syntax/Language/javascript.js';
|
|
88
|
+
|
|
89
|
+
// Create a Syntax instance
|
|
90
|
+
const syntax = new Syntax();
|
|
91
|
+
registerJavaScript(syntax);
|
|
92
|
+
|
|
93
|
+
// Get the JavaScript language and process code:
|
|
94
|
+
const language = await syntax.getLanguage('javascript');
|
|
95
|
+
const code = 'const x = 10;';
|
|
96
|
+
const html = await language.process(code);
|
|
97
|
+
document.body.appendChild(html);
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### The `wrap` Attribute
|
|
101
|
+
|
|
102
|
+
The `<syntax-code>` element automatically detects whether it's inside a `<pre>` tag:
|
|
103
|
+
|
|
104
|
+
- **Inside `<pre>`**: Sets `wrap` attribute, enables line wrapping with proper indentation.
|
|
105
|
+
- **Standalone**: No `wrap` attribute, uses horizontal scrolling for long lines.
|
|
106
|
+
|
|
107
|
+
You can manually control this:
|
|
108
|
+
|
|
109
|
+
```html
|
|
110
|
+
<!-- Force wrapping even outside <pre> -->
|
|
111
|
+
<syntax-code language="javascript" wrap>
|
|
112
|
+
const reallyLongLine = "This will wrap instead of scroll";
|
|
113
|
+
</syntax-code>
|
|
114
|
+
|
|
115
|
+
<!-- Disable wrapping even inside <pre> -->
|
|
116
|
+
<pre><syntax-code language="javascript">
|
|
117
|
+
const code = "This will scroll horizontally";
|
|
118
|
+
</syntax-code></pre>
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Command Line Tool
|
|
122
|
+
|
|
123
|
+
A simple CLI tool is included to inspect the AST (Abstract Syntax Tree) of parsed code:
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
node bin/syntax-ast.js <language> <code>
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Examples:
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
# Parse JavaScript
|
|
133
|
+
node bin/syntax-ast.js javascript "const x = 1;"
|
|
134
|
+
|
|
135
|
+
# Parse Markdown
|
|
136
|
+
node bin/syntax-ast.js markdown '`inline code`'
|
|
137
|
+
|
|
138
|
+
# Parse Python
|
|
139
|
+
node bin/syntax-ast.js python "def foo(): pass"
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Output shows all matched tokens with their type, position, length, and text:
|
|
143
|
+
|
|
144
|
+
```
|
|
145
|
+
Language: javascript
|
|
146
|
+
Code: "const x = 1;"
|
|
147
|
+
|
|
148
|
+
Matches: 3
|
|
149
|
+
────────────────────────────────────────────────────────────────────────────────
|
|
150
|
+
[keyword] @0..5 (5 chars)
|
|
151
|
+
Text: "const"
|
|
152
|
+
[operator] @8..9 (1 chars)
|
|
153
|
+
Text: "="
|
|
154
|
+
[constant] @10..11 (1 chars)
|
|
155
|
+
Text: "1"
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
This is useful for:
|
|
159
|
+
- Debugging language definitions
|
|
160
|
+
- Understanding how code is tokenized
|
|
161
|
+
- Testing pattern matching
|
|
162
|
+
- Developing new language support
|
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CodeElement Integration Tests
|
|
3
|
+
*
|
|
4
|
+
* Tests the <syntax-code> web component with auto-loading
|
|
5
|
+
*
|
|
6
|
+
* Note: These tests focus on the integration between Syntax.js and Language classes
|
|
7
|
+
* without requiring a full browser environment. Full end-to-end tests with stylesheets
|
|
8
|
+
* and DOM rendering are better suited for browser-based testing.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import {test} from 'node:test';
|
|
12
|
+
import assert from 'node:assert/strict';
|
|
13
|
+
import {JSDOM} from 'jsdom';
|
|
14
|
+
import Syntax from '../../Syntax.js';
|
|
15
|
+
|
|
16
|
+
// Set up JSDOM environment
|
|
17
|
+
const dom = new JSDOM('<!DOCTYPE html><html><body></body></html>', {
|
|
18
|
+
url: 'http://localhost:8000/'
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
global.window = dom.window;
|
|
22
|
+
global.document = dom.window.document;
|
|
23
|
+
global.HTMLElement = dom.window.HTMLElement;
|
|
24
|
+
global.customElements = dom.window.customElements;
|
|
25
|
+
global.CustomEvent = dom.window.CustomEvent;
|
|
26
|
+
|
|
27
|
+
test('Syntax.highlight() registers the web component', async () => {
|
|
28
|
+
// This should register the <syntax-code> element
|
|
29
|
+
await Syntax.highlight({upgradeAll: false});
|
|
30
|
+
|
|
31
|
+
// Verify the element is registered
|
|
32
|
+
const constructor = customElements.get('syntax-code');
|
|
33
|
+
assert.ok(constructor, 'syntax-code element should be registered');
|
|
34
|
+
|
|
35
|
+
// Verify we can create an instance
|
|
36
|
+
const element = new constructor();
|
|
37
|
+
assert.ok(element instanceof HTMLElement);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test('Auto-loading mechanism loads YAML language on demand', async () => {
|
|
41
|
+
const syntax = Syntax.default;
|
|
42
|
+
|
|
43
|
+
// YAML should not be loaded yet
|
|
44
|
+
assert.ok(!syntax.hasLanguage('yaml'), 'YAML should not be loaded initially');
|
|
45
|
+
|
|
46
|
+
// Request the YAML language
|
|
47
|
+
const language = await syntax.getResource('yaml');
|
|
48
|
+
|
|
49
|
+
// Verify it was loaded and cached
|
|
50
|
+
assert.ok(language, 'Language should be loaded');
|
|
51
|
+
assert.equal(language.name, 'yaml', 'Language name should be yaml');
|
|
52
|
+
assert.ok(syntax.hasLanguage('yaml'), 'YAML should now be cached');
|
|
53
|
+
|
|
54
|
+
// Requesting again should return the same instance
|
|
55
|
+
const language2 = await syntax.getResource('yaml');
|
|
56
|
+
assert.equal(language2, language, 'Should return cached instance');
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
test('Auto-loading deduplicates concurrent requests', async () => {
|
|
60
|
+
const syntax = new Syntax();
|
|
61
|
+
|
|
62
|
+
// Make multiple concurrent requests for the same language
|
|
63
|
+
const [lang1, lang2, lang3] = await Promise.all([
|
|
64
|
+
syntax.getResource('python'),
|
|
65
|
+
syntax.getResource('python'),
|
|
66
|
+
syntax.getResource('python')
|
|
67
|
+
]);
|
|
68
|
+
|
|
69
|
+
// All should return the same instance
|
|
70
|
+
assert.equal(
|
|
71
|
+
lang1,
|
|
72
|
+
lang2,
|
|
73
|
+
'Concurrent request 1 and 2 should return same instance'
|
|
74
|
+
);
|
|
75
|
+
assert.equal(
|
|
76
|
+
lang2,
|
|
77
|
+
lang3,
|
|
78
|
+
'Concurrent request 2 and 3 should return same instance'
|
|
79
|
+
);
|
|
80
|
+
assert.equal(lang1.name, 'python');
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
test('Language registration works correctly', async () => {
|
|
84
|
+
const syntax = new Syntax();
|
|
85
|
+
|
|
86
|
+
// Load CSS which uses the register() pattern
|
|
87
|
+
const language = await syntax.getResource('css');
|
|
88
|
+
|
|
89
|
+
// Verify it's registered under the correct name
|
|
90
|
+
assert.ok(syntax.hasLanguage('css'));
|
|
91
|
+
assert.equal(language.name, 'css');
|
|
92
|
+
|
|
93
|
+
// Verify we can process code with it
|
|
94
|
+
const html = await language.process(syntax, 'body { color: red; }');
|
|
95
|
+
assert.ok(html instanceof HTMLElement);
|
|
96
|
+
assert.ok(html.outerHTML.includes('color'));
|
|
97
|
+
assert.ok(html.outerHTML.includes('red'));
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
test('Language.process() with multiple languages', async () => {
|
|
101
|
+
const syntax = Syntax.default;
|
|
102
|
+
|
|
103
|
+
// Load multiple languages
|
|
104
|
+
const python = await syntax.getResource('python');
|
|
105
|
+
const yaml = await syntax.getResource('yaml');
|
|
106
|
+
const css = await syntax.getResource('css');
|
|
107
|
+
|
|
108
|
+
// Process code in each language
|
|
109
|
+
const pythonHtml = await python.process(syntax, 'def hello(): pass');
|
|
110
|
+
const yamlHtml = await yaml.process(syntax, 'key: value');
|
|
111
|
+
const cssHtml = await css.process(syntax, 'a { color: blue; }');
|
|
112
|
+
|
|
113
|
+
// Verify all returned HTML elements
|
|
114
|
+
assert.ok(pythonHtml instanceof HTMLElement);
|
|
115
|
+
assert.ok(yamlHtml instanceof HTMLElement);
|
|
116
|
+
assert.ok(cssHtml instanceof HTMLElement);
|
|
117
|
+
|
|
118
|
+
// Verify they contain the expected content
|
|
119
|
+
assert.ok(pythonHtml.textContent.includes('def'));
|
|
120
|
+
assert.ok(yamlHtml.textContent.includes('key'));
|
|
121
|
+
assert.ok(cssHtml.textContent.includes('color'));
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
test('Error handling for non-existent language', async () => {
|
|
125
|
+
const syntax = new Syntax();
|
|
126
|
+
|
|
127
|
+
// Try to load a language that doesn't exist
|
|
128
|
+
await assert.rejects(
|
|
129
|
+
async () => await syntax.getResource('nonexistent-language-xyz'),
|
|
130
|
+
{
|
|
131
|
+
name: 'LanguageLoadError',
|
|
132
|
+
message: /Failed to load language 'nonexistent-language-xyz'/
|
|
133
|
+
},
|
|
134
|
+
'Should throw LanguageLoadError for non-existent language'
|
|
135
|
+
);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
test('Aliases work correctly', async () => {
|
|
139
|
+
const syntax = new Syntax();
|
|
140
|
+
|
|
141
|
+
// Load bash-script language and check it registered bash-statement too
|
|
142
|
+
const bashScript = await syntax.getResource('bash-script');
|
|
143
|
+
|
|
144
|
+
// bash-statement should also be available (registered by bash-script)
|
|
145
|
+
assert.ok(syntax.hasLanguage('bash-statement'));
|
|
146
|
+
|
|
147
|
+
// Load clang which has multiple aliases
|
|
148
|
+
const clang = await syntax.getResource('clang');
|
|
149
|
+
|
|
150
|
+
// Check aliases
|
|
151
|
+
assert.ok(syntax.hasLanguage('c'));
|
|
152
|
+
assert.ok(syntax.hasLanguage('cpp'));
|
|
153
|
+
assert.ok(syntax.hasLanguage('c++'));
|
|
154
|
+
assert.ok(syntax.hasLanguage('objective-c'));
|
|
155
|
+
|
|
156
|
+
// All aliases should resolve to the same language
|
|
157
|
+
const c = await syntax.getResource('c');
|
|
158
|
+
const cpp = await syntax.getResource('cpp');
|
|
159
|
+
assert.equal(c, clang);
|
|
160
|
+
assert.equal(cpp, clang);
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
test('upgradeAll handles <pre><code> blocks without double-nesting', async () => {
|
|
164
|
+
// Import the upgradeAll function
|
|
165
|
+
const {upgradeAll} = await import('../../Syntax/CodeElement.js');
|
|
166
|
+
|
|
167
|
+
// Create a typical code block structure: <pre><code>
|
|
168
|
+
document.body.innerHTML = `
|
|
169
|
+
<div id="test-container">
|
|
170
|
+
<pre><code class="language-javascript">const x = 1;</code></pre>
|
|
171
|
+
</div>
|
|
172
|
+
`;
|
|
173
|
+
|
|
174
|
+
// Run upgradeAll
|
|
175
|
+
upgradeAll('code[class*="language-"]');
|
|
176
|
+
|
|
177
|
+
const container = document.getElementById('test-container');
|
|
178
|
+
|
|
179
|
+
// Check that the syntax-code element was created
|
|
180
|
+
const syntaxCode = container.querySelector('syntax-code');
|
|
181
|
+
assert.ok(syntaxCode, 'syntax-code element should be created');
|
|
182
|
+
|
|
183
|
+
// Check that syntax-code is INSIDE the <pre> (replacing <code>)
|
|
184
|
+
const pre = container.querySelector('pre');
|
|
185
|
+
assert.ok(pre, '<pre> should still exist in the container');
|
|
186
|
+
assert.equal(
|
|
187
|
+
syntaxCode.parentElement,
|
|
188
|
+
pre,
|
|
189
|
+
'syntax-code should be child of <pre>'
|
|
190
|
+
);
|
|
191
|
+
|
|
192
|
+
// Verify the language was set correctly
|
|
193
|
+
assert.equal(
|
|
194
|
+
syntaxCode.getAttribute('language'),
|
|
195
|
+
'javascript',
|
|
196
|
+
'Language should be set from class name'
|
|
197
|
+
);
|
|
198
|
+
|
|
199
|
+
// Verify the code content is preserved
|
|
200
|
+
assert.equal(
|
|
201
|
+
syntaxCode.textContent.trim(),
|
|
202
|
+
'const x = 1;',
|
|
203
|
+
'Code content should be preserved'
|
|
204
|
+
);
|
|
205
|
+
|
|
206
|
+
// Verify wrap attribute is set (because it's inside <pre>)
|
|
207
|
+
// Note: This happens in connectedCallback, which may not fire in JSDOM
|
|
208
|
+
// We'll just verify structure for now
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
test('upgradeAll can handle standalone <code> blocks with custom selector', async () => {
|
|
212
|
+
const {upgradeAll} = await import('../../Syntax/CodeElement.js');
|
|
213
|
+
|
|
214
|
+
// Create a standalone code block (no <pre> wrapper)
|
|
215
|
+
document.body.innerHTML = `
|
|
216
|
+
<div id="test-container">
|
|
217
|
+
<code class="language-python">print("hello")</code>
|
|
218
|
+
</div>
|
|
219
|
+
`;
|
|
220
|
+
|
|
221
|
+
// For standalone code blocks, use a selector without 'pre >'
|
|
222
|
+
upgradeAll('code[class*="language-"]');
|
|
223
|
+
|
|
224
|
+
const container = document.getElementById('test-container');
|
|
225
|
+
const syntaxCode = container.querySelector('syntax-code');
|
|
226
|
+
|
|
227
|
+
assert.ok(syntaxCode, 'syntax-code element should be created');
|
|
228
|
+
assert.equal(
|
|
229
|
+
syntaxCode.parentElement.tagName,
|
|
230
|
+
'DIV',
|
|
231
|
+
'syntax-code should be child of DIV'
|
|
232
|
+
);
|
|
233
|
+
assert.equal(
|
|
234
|
+
syntaxCode.getAttribute('language'),
|
|
235
|
+
'python',
|
|
236
|
+
'Language should be set'
|
|
237
|
+
);
|
|
238
|
+
assert.equal(
|
|
239
|
+
syntaxCode.textContent.trim(),
|
|
240
|
+
'print("hello")',
|
|
241
|
+
'Code content should be preserved'
|
|
242
|
+
);
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
test('syntax-code behaves semantically like <code> when inline', async () => {
|
|
246
|
+
const {CodeElement} = await import('../../Syntax/CodeElement.js');
|
|
247
|
+
|
|
248
|
+
// Create an inline syntax-code element
|
|
249
|
+
document.body.innerHTML = `
|
|
250
|
+
<p id="test-container">
|
|
251
|
+
Some text <syntax-code language="javascript">const x = 1;</syntax-code> more text.
|
|
252
|
+
</p>
|
|
253
|
+
`;
|
|
254
|
+
|
|
255
|
+
const element = document.querySelector('syntax-code');
|
|
256
|
+
|
|
257
|
+
// Wait for rendering to complete
|
|
258
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
259
|
+
|
|
260
|
+
// Verify it's inline (like <code>) by checking the shadow DOM structure
|
|
261
|
+
const shadowRoot = element.shadowRoot;
|
|
262
|
+
assert.ok(shadowRoot, 'Shadow root should exist');
|
|
263
|
+
|
|
264
|
+
// Should contain a <code> element, not wrapped in <pre>
|
|
265
|
+
const codeElement = shadowRoot.querySelector('code');
|
|
266
|
+
assert.ok(codeElement, 'Shadow DOM should contain <code> element');
|
|
267
|
+
|
|
268
|
+
const preElement = shadowRoot.querySelector('pre');
|
|
269
|
+
assert.equal(preElement, null, 'Shadow DOM should NOT contain <pre> wrapper for inline usage');
|
|
270
|
+
|
|
271
|
+
// The code element should be a direct child of shadow root
|
|
272
|
+
assert.ok(
|
|
273
|
+
Array.from(shadowRoot.children).includes(codeElement),
|
|
274
|
+
'<code> should be direct child of shadow root'
|
|
275
|
+
);
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
test('syntax-code behaves as block when inside <pre>', async () => {
|
|
279
|
+
const {CodeElement} = await import('../../Syntax/CodeElement.js');
|
|
280
|
+
|
|
281
|
+
// Create a block syntax-code element inside <pre>
|
|
282
|
+
document.body.innerHTML = `
|
|
283
|
+
<div id="test-container">
|
|
284
|
+
<pre><syntax-code language="javascript">const x = 1;</syntax-code></pre>
|
|
285
|
+
</div>
|
|
286
|
+
`;
|
|
287
|
+
|
|
288
|
+
const element = document.querySelector('syntax-code');
|
|
289
|
+
|
|
290
|
+
// Wait for rendering to complete
|
|
291
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
292
|
+
|
|
293
|
+
// Check that wrap attribute was set (because it's inside <pre>)
|
|
294
|
+
assert.ok(element.hasAttribute('wrap'), 'wrap attribute should be set when inside <pre>');
|
|
295
|
+
|
|
296
|
+
// After rendering, light DOM is cleared, so check shadow DOM
|
|
297
|
+
const shadowRoot = element.shadowRoot;
|
|
298
|
+
const codeElement = shadowRoot.querySelector('code');
|
|
299
|
+
assert.ok(codeElement, 'Shadow DOM should contain <code> element');
|
|
300
|
+
|
|
301
|
+
// The <code> should be a direct child of shadow root (no <pre> wrapper needed inside)
|
|
302
|
+
assert.ok(
|
|
303
|
+
Array.from(shadowRoot.children).includes(codeElement),
|
|
304
|
+
'<code> should be direct child of shadow root'
|
|
305
|
+
);
|
|
306
|
+
});
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import {test} from 'node:test';
|
|
2
|
+
import assert from 'node:assert';
|
|
3
|
+
|
|
4
|
+
import Syntax from '../../Syntax.js';
|
|
5
|
+
import {Language} from '../../Syntax/Language.js';
|
|
6
|
+
import {
|
|
7
|
+
LanguageNotFoundError,
|
|
8
|
+
RuleApplyError,
|
|
9
|
+
StyleSheetLoadError
|
|
10
|
+
} from '../../Syntax/Errors.js';
|
|
11
|
+
|
|
12
|
+
test('Language.buildTree throws LanguageNotFoundError in strict mode for missing embedded language', async () => {
|
|
13
|
+
const syntax = new Syntax();
|
|
14
|
+
syntax.defaultOptions.strict = true;
|
|
15
|
+
|
|
16
|
+
const lang = new Language('dummy');
|
|
17
|
+
// Rule that embeds a non-existent language
|
|
18
|
+
lang.push({pattern: /x+/, language: 'no-such-language'});
|
|
19
|
+
|
|
20
|
+
await assert.rejects(
|
|
21
|
+
async () => {
|
|
22
|
+
await lang.buildTree(syntax, 'xxx', 0);
|
|
23
|
+
},
|
|
24
|
+
err => err instanceof LanguageNotFoundError
|
|
25
|
+
);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
test('RuleApplyError thrown in strict mode when rule.apply throws', async () => {
|
|
29
|
+
const syntax = new Syntax();
|
|
30
|
+
syntax.defaultOptions.strict = true;
|
|
31
|
+
|
|
32
|
+
const lang = new Language('dummy');
|
|
33
|
+
// Custom rule that throws from apply
|
|
34
|
+
lang.push({
|
|
35
|
+
pattern: /x+/,
|
|
36
|
+
apply() {
|
|
37
|
+
throw new Error('boom');
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
await assert.rejects(
|
|
42
|
+
async () => {
|
|
43
|
+
await lang.getMatches(syntax, 'xxx');
|
|
44
|
+
},
|
|
45
|
+
err => err instanceof RuleApplyError
|
|
46
|
+
);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test('Rule apply failure is ignored (warn) in non-strict mode', async () => {
|
|
50
|
+
const syntax = new Syntax();
|
|
51
|
+
syntax.defaultOptions.strict = false;
|
|
52
|
+
|
|
53
|
+
const lang = new Language('dummy');
|
|
54
|
+
lang.push({
|
|
55
|
+
pattern: /x+/,
|
|
56
|
+
apply() {
|
|
57
|
+
throw new Error('boom');
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
const matches = await lang.getMatches(syntax, 'xxx');
|
|
62
|
+
assert.ok(Array.isArray(matches));
|
|
63
|
+
assert.strictEqual(matches.length, 0);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
test('Stylesheet loader throws StyleSheetLoadError on non-200 response', async () => {
|
|
67
|
+
const syntax = new Syntax();
|
|
68
|
+
// Mock fetch to return 404
|
|
69
|
+
const originalFetch = globalThis.fetch;
|
|
70
|
+
globalThis.fetch = async () => ({
|
|
71
|
+
ok: false,
|
|
72
|
+
status: 404,
|
|
73
|
+
text: async () => ''
|
|
74
|
+
});
|
|
75
|
+
try {
|
|
76
|
+
await assert.rejects(
|
|
77
|
+
async () => {
|
|
78
|
+
await syntax.getStyleSheet('https://example.invalid/missing.css');
|
|
79
|
+
},
|
|
80
|
+
err => err instanceof StyleSheetLoadError
|
|
81
|
+
);
|
|
82
|
+
} finally {
|
|
83
|
+
globalThis.fetch = originalFetch;
|
|
84
|
+
}
|
|
85
|
+
});
|