htvl-lang 0.2.0__tar.gz
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.
- htvl_lang-0.2.0/LICENSE +21 -0
- htvl_lang-0.2.0/PKG-INFO +264 -0
- htvl_lang-0.2.0/README.md +233 -0
- htvl_lang-0.2.0/htvl/__init__.py +44 -0
- htvl_lang-0.2.0/htvl/__main__.py +8 -0
- htvl_lang-0.2.0/htvl/cli.py +216 -0
- htvl_lang-0.2.0/htvl/elements.py +491 -0
- htvl_lang-0.2.0/htvl/emitter.py +134 -0
- htvl_lang-0.2.0/htvl/errors.py +84 -0
- htvl_lang-0.2.0/htvl/lexer.py +204 -0
- htvl_lang-0.2.0/htvl/nodes.py +60 -0
- htvl_lang-0.2.0/htvl/parser.py +26 -0
- htvl_lang-0.2.0/htvl/project.py +183 -0
- htvl_lang-0.2.0/htvl/templates.py +55 -0
- htvl_lang-0.2.0/htvl/variables.py +53 -0
- htvl_lang-0.2.0/htvl/watch.py +170 -0
- htvl_lang-0.2.0/htvl_lang.egg-info/PKG-INFO +264 -0
- htvl_lang-0.2.0/htvl_lang.egg-info/SOURCES.txt +36 -0
- htvl_lang-0.2.0/htvl_lang.egg-info/dependency_links.txt +1 -0
- htvl_lang-0.2.0/htvl_lang.egg-info/entry_points.txt +2 -0
- htvl_lang-0.2.0/htvl_lang.egg-info/requires.txt +4 -0
- htvl_lang-0.2.0/htvl_lang.egg-info/top_level.txt +1 -0
- htvl_lang-0.2.0/pyproject.toml +47 -0
- htvl_lang-0.2.0/setup.cfg +4 -0
- htvl_lang-0.2.0/tests/test_cli.py +56 -0
- htvl_lang-0.2.0/tests/test_elements.py +103 -0
- htvl_lang-0.2.0/tests/test_emitter.py +81 -0
- htvl_lang-0.2.0/tests/test_golden.py +16 -0
- htvl_lang-0.2.0/tests/test_lexer.py +94 -0
- htvl_lang-0.2.0/tests/test_modern.py +130 -0
- htvl_lang-0.2.0/tests/test_packaging.py +87 -0
- htvl_lang-0.2.0/tests/test_parser.py +42 -0
- htvl_lang-0.2.0/tests/test_playground_lib.py +127 -0
- htvl_lang-0.2.0/tests/test_project.py +60 -0
- htvl_lang-0.2.0/tests/test_pygments_htvl.py +109 -0
- htvl_lang-0.2.0/tests/test_templates.py +49 -0
- htvl_lang-0.2.0/tests/test_variables.py +39 -0
- htvl_lang-0.2.0/tests/test_watch.py +219 -0
htvl_lang-0.2.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2020-2026 Nicholas Rotich and HTVL contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
htvl_lang-0.2.0/PKG-INFO
ADDED
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: htvl-lang
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: HTVL - a tiny HTML transpiler: write .htvl files, get HTML.
|
|
5
|
+
Author: Nicholas Rotich, HTVL contributors
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/moinonin/htvl
|
|
8
|
+
Project-URL: Repository, https://github.com/moinonin/htvl
|
|
9
|
+
Project-URL: Bug Tracker, https://github.com/moinonin/htvl/issues
|
|
10
|
+
Project-URL: Changelog, https://github.com/moinonin/htvl/releases
|
|
11
|
+
Keywords: html,transpiler,static-site,compiler,dsl
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Topic :: Software Development :: Compilers
|
|
23
|
+
Classifier: Topic :: Text Processing :: Markup :: HTML
|
|
24
|
+
Requires-Python: >=3.10
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
License-File: LICENSE
|
|
27
|
+
Provides-Extra: dev
|
|
28
|
+
Requires-Dist: pytest>=7; extra == "dev"
|
|
29
|
+
Requires-Dist: pygments>=2.10; extra == "dev"
|
|
30
|
+
Dynamic: license-file
|
|
31
|
+
|
|
32
|
+
# HTVL — a tiny HTML transpiler
|
|
33
|
+
|
|
34
|
+
[](https://github.com/moinonin/htvl/actions/workflows/tests.yml)
|
|
35
|
+
|
|
36
|
+
Write short tag calls in `.htvl` files, get plain HTML out. No build step, no
|
|
37
|
+
dependencies, no framework — just a small, well-tested compiler you can read
|
|
38
|
+
in an afternoon.
|
|
39
|
+
|
|
40
|
+
```text
|
|
41
|
+
$(h 1 '' '' 'Hello HTVL' '')
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
compiles to
|
|
45
|
+
|
|
46
|
+
```html
|
|
47
|
+
<h1 class="" id="" style="">Hello HTVL</h1>
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Install
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
pip install . # from a clone of this repository
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
or run it straight from the checkout with zero installation:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
python3 -m htvl compile
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Python 3.10+, standard library only.
|
|
63
|
+
|
|
64
|
+
## Quickstart
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
htvl new mysite # scaffold: index.htvl, templates/, assets/
|
|
68
|
+
cd mysite
|
|
69
|
+
htvl compile # writes public/index.html and copies assets/
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
A minimal project:
|
|
73
|
+
|
|
74
|
+
```text
|
|
75
|
+
mysite/
|
|
76
|
+
├── index.htvl
|
|
77
|
+
├── templates/
|
|
78
|
+
│ └── headtags.htvl
|
|
79
|
+
└── assets/
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
`index.htvl`:
|
|
83
|
+
|
|
84
|
+
```text
|
|
85
|
+
$DOCTYPE_htvl
|
|
86
|
+
$htvl
|
|
87
|
+
$head
|
|
88
|
+
$headtags
|
|
89
|
+
$_head
|
|
90
|
+
$body
|
|
91
|
+
$(nav 'navbar navbar-expand-md bg-dark navbar-dark')
|
|
92
|
+
$(a 'navbar-brand' './' 'Home' '' '' '' '')$_a
|
|
93
|
+
$(ul 'navbar-nav')
|
|
94
|
+
$_ul
|
|
95
|
+
$_nav
|
|
96
|
+
|
|
97
|
+
$(div 'container')
|
|
98
|
+
$(h 1 '' '' 'Hello HTVL' '')
|
|
99
|
+
$(p '' '' 'This page was compiled by the HTVL compiler.' '')
|
|
100
|
+
$_p
|
|
101
|
+
$_div
|
|
102
|
+
$_body
|
|
103
|
+
$_htvl
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
`templates/headtags.htvl`:
|
|
107
|
+
|
|
108
|
+
```text
|
|
109
|
+
$(title '' 'My HTVL page')
|
|
110
|
+
$meta
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Then `htvl compile` produces `public/index.html`.
|
|
114
|
+
|
|
115
|
+
## Commands
|
|
116
|
+
|
|
117
|
+
| Command | What it does |
|
|
118
|
+
| --- | --- |
|
|
119
|
+
| `htvl compile [path] [-o DIR] [--modern] [-w]` | Compile every `.htvl` file in `path` (default `.`) into `public/`; `.cal` files become CGI scripts in `cal/`; `assets/` is copied automatically. `--modern` emits clean, escaped HTML; `-w`/`--watch` keeps running and recompiles on change. |
|
|
120
|
+
| `htvl check FILE... [--modern]` | Compile a single file to stdout — great for scripting and debugging. |
|
|
121
|
+
| `htvl new NAME` | Scaffold a new project. |
|
|
122
|
+
| `htvl list` | Print every tag signature and built-in variable. |
|
|
123
|
+
|
|
124
|
+
### Legacy vs modern output
|
|
125
|
+
|
|
126
|
+
The default output is byte-identical to the original 2020 compiler (empty
|
|
127
|
+
attributes and all, guarded by `tests/test_golden.py`). For new projects, pass
|
|
128
|
+
`--modern` to get clean HTML: empty attributes omitted, text escaped, no
|
|
129
|
+
cosmetic quirks. Same source files, same line structure — only the rendering
|
|
130
|
+
changes:
|
|
131
|
+
|
|
132
|
+
```text
|
|
133
|
+
$(div 'container') legacy: <div class="container" id="" style="">
|
|
134
|
+
modern: <div class="container">
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Watch mode
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
htvl compile --watch # or: htvl compile -w
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Compiles once, then keeps the output up to date as you edit:
|
|
144
|
+
|
|
145
|
+
```text
|
|
146
|
+
htvl: compiled public/index.html
|
|
147
|
+
htvl: copied assets -> public/assets
|
|
148
|
+
htvl: watching '/sites/mysite' (Ctrl-C to stop)
|
|
149
|
+
htvl: compiled public/index.html <- you saved index.htvl
|
|
150
|
+
htvl: removed public/index.html <- you deleted index.htvl
|
|
151
|
+
htvl: stopped
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Edits are incremental: changing `index.htvl` recompiles that file, changing
|
|
155
|
+
anything in `templates/` rebuilds the project, changing `assets/` re-copies
|
|
156
|
+
it, and deleting a source removes its output. A broken edit (an unknown tag,
|
|
157
|
+
say) is reported but does not stop the watcher — fix the file and it picks up
|
|
158
|
+
where it left off. No dependencies: it polls the filesystem a few times a
|
|
159
|
+
second.
|
|
160
|
+
|
|
161
|
+
Errors include the file, line and column, e.g.
|
|
162
|
+
`htvl: error: unknown tag 'dvi' (line 12). Run 'htvl list' to see every available tag.`
|
|
163
|
+
|
|
164
|
+
## The language
|
|
165
|
+
|
|
166
|
+
* `$(tag 'arg' ...)` — tag calls, arguments are quoted strings (or bare words),
|
|
167
|
+
nesting allowed: `$(link stylesheet 'text/css' $(bsCdn '4.3.1'))`
|
|
168
|
+
* `$name` — variables such as `$head`, `$_a`, `$meta`, and your own templates
|
|
169
|
+
(`$headtags`)
|
|
170
|
+
* `$_name` — explicit closing tags
|
|
171
|
+
* One source line = one output line; your indentation is your HTML's
|
|
172
|
+
indentation.
|
|
173
|
+
|
|
174
|
+
The full reference — every tag signature, the variables, templates, CGI
|
|
175
|
+
support — is in [docs/grammar.md](https://github.com/moinonin/htvl/blob/master/docs/grammar.md).
|
|
176
|
+
|
|
177
|
+
### Editor support
|
|
178
|
+
|
|
179
|
+
* **VS Code** — the extension lives in [`editors/vscode/`](https://github.com/moinonin/htvl/blob/master/editors/vscode):
|
|
180
|
+
```bash
|
|
181
|
+
cd editors/vscode
|
|
182
|
+
npx @vscode/vsce package && code --install-extension htvl-*.vsix
|
|
183
|
+
```
|
|
184
|
+
It highlights tag calls, variables (`$head`, `$_a`), quoted/bare arguments,
|
|
185
|
+
nested calls and HTML comments, and it is set up for comment blocks and
|
|
186
|
+
indentation-based folding.
|
|
187
|
+
* **Anything Pygments-based** (Sphinx, MkDocs, code renderers) — a Pygments
|
|
188
|
+
lexer ships in [`extras/pygments_htvl.py`](https://github.com/moinonin/htvl/blob/master/extras/pygments_htvl.py):
|
|
189
|
+
```python
|
|
190
|
+
from pygments.lexers import LEXERS
|
|
191
|
+
LEXERS["htvl"] = (
|
|
192
|
+
"pygments_htvl", "HTVL", ("htvl",), ("*.htvl", "*.cal"), ()
|
|
193
|
+
)
|
|
194
|
+
```
|
|
195
|
+
Both are covered by the test suite.
|
|
196
|
+
|
|
197
|
+
### Try it in the browser
|
|
198
|
+
|
|
199
|
+
[`playground/`](https://github.com/moinonin/htvl/blob/master/playground) is a fully static, server-free playground: the
|
|
200
|
+
page loads the **real Python compiler** compiled to WebAssembly with
|
|
201
|
+
[Pyodide](https://pyodide.org) and compiles as you type, with a legacy/modern
|
|
202
|
+
toggle. Open it from any static host:
|
|
203
|
+
|
|
204
|
+
```bash
|
|
205
|
+
python3 -m http.server 8000 --directory playground
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## Using it as a library
|
|
209
|
+
|
|
210
|
+
```python
|
|
211
|
+
from htvl import compile_source
|
|
212
|
+
|
|
213
|
+
html = compile_source("$(h 1 '' '' 'Hello' ')\n")
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
## About this repository
|
|
217
|
+
|
|
218
|
+
HTVL started in 2020 as a two-line obfuscated bash script that generated HTML
|
|
219
|
+
by `eval`-ing heredocs, complete with a 90-day trial timer that required
|
|
220
|
+
`sudo`. That prototype is preserved untouched in [`legacy/`](https://github.com/moinonin/htvl/blob/master/legacy) — see
|
|
221
|
+
[`legacy/README.original.md`](https://github.com/moinonin/htvl/blob/master/legacy/README.original.md) for the original
|
|
222
|
+
documentation — together with a
|
|
223
|
+
[de-obfuscated copy of its compiler](https://github.com/moinonin/htvl/blob/master/docs/recovered-legacy-compiler.sh) that
|
|
224
|
+
serves as the authoritative definition of the grammar.
|
|
225
|
+
|
|
226
|
+
This repository is the second act: the same language, reimplemented in Python
|
|
227
|
+
as a readable, testable, dependency-free compiler:
|
|
228
|
+
|
|
229
|
+
* `htvl/lexer.py` → `htvl/parser.py` → `htvl/elements.py` →
|
|
230
|
+
`htvl/emitter.py` — a classic tokenize / parse / render pipeline you can
|
|
231
|
+
actually read
|
|
232
|
+
* the trial timer, the `sudo` asset copy and the silent failure modes are
|
|
233
|
+
gone; errors now name the line and column
|
|
234
|
+
* `tests/test_golden.py` proves the port reproduces the original 2020 output
|
|
235
|
+
**byte for byte**, so existing `.htvl` files and `templates/*.sh` keep
|
|
236
|
+
working unchanged
|
|
237
|
+
|
|
238
|
+
### Development
|
|
239
|
+
|
|
240
|
+
```bash
|
|
241
|
+
pip install -e ".[dev]" # compiler + pytest + pygments (for the lexer tests)
|
|
242
|
+
python3 -m pytest # 136 tests, including the golden test
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
CI runs the suite on every push and PR: all supported Python versions
|
|
246
|
+
(3.10–3.13) on Linux, spot-checks on macOS and Windows, and a packaging job
|
|
247
|
+
that builds a wheel, installs it, and compiles a scaffolded project
|
|
248
|
+
(`.github/workflows/tests.yml`).
|
|
249
|
+
|
|
250
|
+
Release notes for v0.2.0 are in [docs/releases/v0.2.0.md](https://github.com/moinonin/htvl/blob/master/docs/releases/v0.2.0.md).
|
|
251
|
+
|
|
252
|
+
### Roadmap
|
|
253
|
+
|
|
254
|
+
* an opt-in `--modern` mode that fixes the documented `[legacy]` output
|
|
255
|
+
quirks (no empty attributes, proper escaping, real `role` support)
|
|
256
|
+
* ~~watch mode and incremental builds~~ — **done in v0.2.0** (`htvl compile --watch`)
|
|
257
|
+
* ~~syntax highlighting for `.htvl` files~~ — **done in v0.2.0** (VS Code
|
|
258
|
+
extension in `editors/vscode/`, Pygments lexer in `extras/`)
|
|
259
|
+
* ~~a playground on the documentation site~~ — **done in v0.2.0**
|
|
260
|
+
(`playground/`, the real compiler running in-browser via Pyodide)
|
|
261
|
+
|
|
262
|
+
## License
|
|
263
|
+
|
|
264
|
+
MIT — see [LICENSE](https://github.com/moinonin/htvl/blob/master/LICENSE).
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
# HTVL — a tiny HTML transpiler
|
|
2
|
+
|
|
3
|
+
[](https://github.com/moinonin/htvl/actions/workflows/tests.yml)
|
|
4
|
+
|
|
5
|
+
Write short tag calls in `.htvl` files, get plain HTML out. No build step, no
|
|
6
|
+
dependencies, no framework — just a small, well-tested compiler you can read
|
|
7
|
+
in an afternoon.
|
|
8
|
+
|
|
9
|
+
```text
|
|
10
|
+
$(h 1 '' '' 'Hello HTVL' '')
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
compiles to
|
|
14
|
+
|
|
15
|
+
```html
|
|
16
|
+
<h1 class="" id="" style="">Hello HTVL</h1>
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Install
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
pip install . # from a clone of this repository
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
or run it straight from the checkout with zero installation:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
python3 -m htvl compile
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Python 3.10+, standard library only.
|
|
32
|
+
|
|
33
|
+
## Quickstart
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
htvl new mysite # scaffold: index.htvl, templates/, assets/
|
|
37
|
+
cd mysite
|
|
38
|
+
htvl compile # writes public/index.html and copies assets/
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
A minimal project:
|
|
42
|
+
|
|
43
|
+
```text
|
|
44
|
+
mysite/
|
|
45
|
+
├── index.htvl
|
|
46
|
+
├── templates/
|
|
47
|
+
│ └── headtags.htvl
|
|
48
|
+
└── assets/
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
`index.htvl`:
|
|
52
|
+
|
|
53
|
+
```text
|
|
54
|
+
$DOCTYPE_htvl
|
|
55
|
+
$htvl
|
|
56
|
+
$head
|
|
57
|
+
$headtags
|
|
58
|
+
$_head
|
|
59
|
+
$body
|
|
60
|
+
$(nav 'navbar navbar-expand-md bg-dark navbar-dark')
|
|
61
|
+
$(a 'navbar-brand' './' 'Home' '' '' '' '')$_a
|
|
62
|
+
$(ul 'navbar-nav')
|
|
63
|
+
$_ul
|
|
64
|
+
$_nav
|
|
65
|
+
|
|
66
|
+
$(div 'container')
|
|
67
|
+
$(h 1 '' '' 'Hello HTVL' '')
|
|
68
|
+
$(p '' '' 'This page was compiled by the HTVL compiler.' '')
|
|
69
|
+
$_p
|
|
70
|
+
$_div
|
|
71
|
+
$_body
|
|
72
|
+
$_htvl
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
`templates/headtags.htvl`:
|
|
76
|
+
|
|
77
|
+
```text
|
|
78
|
+
$(title '' 'My HTVL page')
|
|
79
|
+
$meta
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Then `htvl compile` produces `public/index.html`.
|
|
83
|
+
|
|
84
|
+
## Commands
|
|
85
|
+
|
|
86
|
+
| Command | What it does |
|
|
87
|
+
| --- | --- |
|
|
88
|
+
| `htvl compile [path] [-o DIR] [--modern] [-w]` | Compile every `.htvl` file in `path` (default `.`) into `public/`; `.cal` files become CGI scripts in `cal/`; `assets/` is copied automatically. `--modern` emits clean, escaped HTML; `-w`/`--watch` keeps running and recompiles on change. |
|
|
89
|
+
| `htvl check FILE... [--modern]` | Compile a single file to stdout — great for scripting and debugging. |
|
|
90
|
+
| `htvl new NAME` | Scaffold a new project. |
|
|
91
|
+
| `htvl list` | Print every tag signature and built-in variable. |
|
|
92
|
+
|
|
93
|
+
### Legacy vs modern output
|
|
94
|
+
|
|
95
|
+
The default output is byte-identical to the original 2020 compiler (empty
|
|
96
|
+
attributes and all, guarded by `tests/test_golden.py`). For new projects, pass
|
|
97
|
+
`--modern` to get clean HTML: empty attributes omitted, text escaped, no
|
|
98
|
+
cosmetic quirks. Same source files, same line structure — only the rendering
|
|
99
|
+
changes:
|
|
100
|
+
|
|
101
|
+
```text
|
|
102
|
+
$(div 'container') legacy: <div class="container" id="" style="">
|
|
103
|
+
modern: <div class="container">
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Watch mode
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
htvl compile --watch # or: htvl compile -w
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Compiles once, then keeps the output up to date as you edit:
|
|
113
|
+
|
|
114
|
+
```text
|
|
115
|
+
htvl: compiled public/index.html
|
|
116
|
+
htvl: copied assets -> public/assets
|
|
117
|
+
htvl: watching '/sites/mysite' (Ctrl-C to stop)
|
|
118
|
+
htvl: compiled public/index.html <- you saved index.htvl
|
|
119
|
+
htvl: removed public/index.html <- you deleted index.htvl
|
|
120
|
+
htvl: stopped
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Edits are incremental: changing `index.htvl` recompiles that file, changing
|
|
124
|
+
anything in `templates/` rebuilds the project, changing `assets/` re-copies
|
|
125
|
+
it, and deleting a source removes its output. A broken edit (an unknown tag,
|
|
126
|
+
say) is reported but does not stop the watcher — fix the file and it picks up
|
|
127
|
+
where it left off. No dependencies: it polls the filesystem a few times a
|
|
128
|
+
second.
|
|
129
|
+
|
|
130
|
+
Errors include the file, line and column, e.g.
|
|
131
|
+
`htvl: error: unknown tag 'dvi' (line 12). Run 'htvl list' to see every available tag.`
|
|
132
|
+
|
|
133
|
+
## The language
|
|
134
|
+
|
|
135
|
+
* `$(tag 'arg' ...)` — tag calls, arguments are quoted strings (or bare words),
|
|
136
|
+
nesting allowed: `$(link stylesheet 'text/css' $(bsCdn '4.3.1'))`
|
|
137
|
+
* `$name` — variables such as `$head`, `$_a`, `$meta`, and your own templates
|
|
138
|
+
(`$headtags`)
|
|
139
|
+
* `$_name` — explicit closing tags
|
|
140
|
+
* One source line = one output line; your indentation is your HTML's
|
|
141
|
+
indentation.
|
|
142
|
+
|
|
143
|
+
The full reference — every tag signature, the variables, templates, CGI
|
|
144
|
+
support — is in [docs/grammar.md](https://github.com/moinonin/htvl/blob/master/docs/grammar.md).
|
|
145
|
+
|
|
146
|
+
### Editor support
|
|
147
|
+
|
|
148
|
+
* **VS Code** — the extension lives in [`editors/vscode/`](https://github.com/moinonin/htvl/blob/master/editors/vscode):
|
|
149
|
+
```bash
|
|
150
|
+
cd editors/vscode
|
|
151
|
+
npx @vscode/vsce package && code --install-extension htvl-*.vsix
|
|
152
|
+
```
|
|
153
|
+
It highlights tag calls, variables (`$head`, `$_a`), quoted/bare arguments,
|
|
154
|
+
nested calls and HTML comments, and it is set up for comment blocks and
|
|
155
|
+
indentation-based folding.
|
|
156
|
+
* **Anything Pygments-based** (Sphinx, MkDocs, code renderers) — a Pygments
|
|
157
|
+
lexer ships in [`extras/pygments_htvl.py`](https://github.com/moinonin/htvl/blob/master/extras/pygments_htvl.py):
|
|
158
|
+
```python
|
|
159
|
+
from pygments.lexers import LEXERS
|
|
160
|
+
LEXERS["htvl"] = (
|
|
161
|
+
"pygments_htvl", "HTVL", ("htvl",), ("*.htvl", "*.cal"), ()
|
|
162
|
+
)
|
|
163
|
+
```
|
|
164
|
+
Both are covered by the test suite.
|
|
165
|
+
|
|
166
|
+
### Try it in the browser
|
|
167
|
+
|
|
168
|
+
[`playground/`](https://github.com/moinonin/htvl/blob/master/playground) is a fully static, server-free playground: the
|
|
169
|
+
page loads the **real Python compiler** compiled to WebAssembly with
|
|
170
|
+
[Pyodide](https://pyodide.org) and compiles as you type, with a legacy/modern
|
|
171
|
+
toggle. Open it from any static host:
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
python3 -m http.server 8000 --directory playground
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## Using it as a library
|
|
178
|
+
|
|
179
|
+
```python
|
|
180
|
+
from htvl import compile_source
|
|
181
|
+
|
|
182
|
+
html = compile_source("$(h 1 '' '' 'Hello' ')\n")
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## About this repository
|
|
186
|
+
|
|
187
|
+
HTVL started in 2020 as a two-line obfuscated bash script that generated HTML
|
|
188
|
+
by `eval`-ing heredocs, complete with a 90-day trial timer that required
|
|
189
|
+
`sudo`. That prototype is preserved untouched in [`legacy/`](https://github.com/moinonin/htvl/blob/master/legacy) — see
|
|
190
|
+
[`legacy/README.original.md`](https://github.com/moinonin/htvl/blob/master/legacy/README.original.md) for the original
|
|
191
|
+
documentation — together with a
|
|
192
|
+
[de-obfuscated copy of its compiler](https://github.com/moinonin/htvl/blob/master/docs/recovered-legacy-compiler.sh) that
|
|
193
|
+
serves as the authoritative definition of the grammar.
|
|
194
|
+
|
|
195
|
+
This repository is the second act: the same language, reimplemented in Python
|
|
196
|
+
as a readable, testable, dependency-free compiler:
|
|
197
|
+
|
|
198
|
+
* `htvl/lexer.py` → `htvl/parser.py` → `htvl/elements.py` →
|
|
199
|
+
`htvl/emitter.py` — a classic tokenize / parse / render pipeline you can
|
|
200
|
+
actually read
|
|
201
|
+
* the trial timer, the `sudo` asset copy and the silent failure modes are
|
|
202
|
+
gone; errors now name the line and column
|
|
203
|
+
* `tests/test_golden.py` proves the port reproduces the original 2020 output
|
|
204
|
+
**byte for byte**, so existing `.htvl` files and `templates/*.sh` keep
|
|
205
|
+
working unchanged
|
|
206
|
+
|
|
207
|
+
### Development
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
pip install -e ".[dev]" # compiler + pytest + pygments (for the lexer tests)
|
|
211
|
+
python3 -m pytest # 136 tests, including the golden test
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
CI runs the suite on every push and PR: all supported Python versions
|
|
215
|
+
(3.10–3.13) on Linux, spot-checks on macOS and Windows, and a packaging job
|
|
216
|
+
that builds a wheel, installs it, and compiles a scaffolded project
|
|
217
|
+
(`.github/workflows/tests.yml`).
|
|
218
|
+
|
|
219
|
+
Release notes for v0.2.0 are in [docs/releases/v0.2.0.md](https://github.com/moinonin/htvl/blob/master/docs/releases/v0.2.0.md).
|
|
220
|
+
|
|
221
|
+
### Roadmap
|
|
222
|
+
|
|
223
|
+
* an opt-in `--modern` mode that fixes the documented `[legacy]` output
|
|
224
|
+
quirks (no empty attributes, proper escaping, real `role` support)
|
|
225
|
+
* ~~watch mode and incremental builds~~ — **done in v0.2.0** (`htvl compile --watch`)
|
|
226
|
+
* ~~syntax highlighting for `.htvl` files~~ — **done in v0.2.0** (VS Code
|
|
227
|
+
extension in `editors/vscode/`, Pygments lexer in `extras/`)
|
|
228
|
+
* ~~a playground on the documentation site~~ — **done in v0.2.0**
|
|
229
|
+
(`playground/`, the real compiler running in-browser via Pyodide)
|
|
230
|
+
|
|
231
|
+
## License
|
|
232
|
+
|
|
233
|
+
MIT — see [LICENSE](https://github.com/moinonin/htvl/blob/master/LICENSE).
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"""HTVL - a tiny HTML transpiler.
|
|
2
|
+
|
|
3
|
+
Public API::
|
|
4
|
+
|
|
5
|
+
from htvl import compile_source, compile_file, compile_project
|
|
6
|
+
|
|
7
|
+
html = compile_source("$(h 1 '' '' 'Hello' '')")
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
from .emitter import Emitter, emit
|
|
13
|
+
from .errors import (
|
|
14
|
+
HtvlArityError,
|
|
15
|
+
HtvlError,
|
|
16
|
+
HtvlSyntaxError,
|
|
17
|
+
HtvlUnknownTagError,
|
|
18
|
+
HtvlUnknownVariableError,
|
|
19
|
+
)
|
|
20
|
+
from .parser import parse
|
|
21
|
+
from .project import (
|
|
22
|
+
CompileResult,
|
|
23
|
+
compile_file,
|
|
24
|
+
compile_project,
|
|
25
|
+
compile_source,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
__version__ = "0.2.0"
|
|
29
|
+
|
|
30
|
+
__all__ = [
|
|
31
|
+
"__version__",
|
|
32
|
+
"compile_source",
|
|
33
|
+
"compile_file",
|
|
34
|
+
"compile_project",
|
|
35
|
+
"CompileResult",
|
|
36
|
+
"parse",
|
|
37
|
+
"emit",
|
|
38
|
+
"Emitter",
|
|
39
|
+
"HtvlError",
|
|
40
|
+
"HtvlSyntaxError",
|
|
41
|
+
"HtvlUnknownTagError",
|
|
42
|
+
"HtvlUnknownVariableError",
|
|
43
|
+
"HtvlArityError",
|
|
44
|
+
]
|