htvl-lang 0.2.0__py3-none-any.whl
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/__init__.py +44 -0
- htvl/__main__.py +8 -0
- htvl/cli.py +216 -0
- htvl/elements.py +491 -0
- htvl/emitter.py +134 -0
- htvl/errors.py +84 -0
- htvl/lexer.py +204 -0
- htvl/nodes.py +60 -0
- htvl/parser.py +26 -0
- htvl/project.py +183 -0
- htvl/templates.py +55 -0
- htvl/variables.py +53 -0
- htvl/watch.py +170 -0
- htvl_lang-0.2.0.dist-info/METADATA +264 -0
- htvl_lang-0.2.0.dist-info/RECORD +19 -0
- htvl_lang-0.2.0.dist-info/WHEEL +5 -0
- htvl_lang-0.2.0.dist-info/entry_points.txt +2 -0
- htvl_lang-0.2.0.dist-info/licenses/LICENSE +21 -0
- htvl_lang-0.2.0.dist-info/top_level.txt +1 -0
htvl/__init__.py
ADDED
|
@@ -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
|
+
]
|
htvl/__main__.py
ADDED
htvl/cli.py
ADDED
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
"""Command line interface: ``htvl compile``, ``htvl check``, ``htvl new``..."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import sys
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import List, Optional
|
|
9
|
+
|
|
10
|
+
from . import __version__
|
|
11
|
+
from .elements import ELEMENTS
|
|
12
|
+
from .errors import HtvlError
|
|
13
|
+
from .project import compile_project, compile_source
|
|
14
|
+
from .templates import load_templates
|
|
15
|
+
from .variables import VARIABLES
|
|
16
|
+
from .watch import watch_project
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _build_parser() -> argparse.ArgumentParser:
|
|
20
|
+
parser = argparse.ArgumentParser(
|
|
21
|
+
prog="htvl",
|
|
22
|
+
description=(
|
|
23
|
+
"HTVL - a tiny HTML transpiler. Write short tag calls like "
|
|
24
|
+
"$(h 1 '' '' 'Hello' '') in .htvl files and compile them to HTML."
|
|
25
|
+
),
|
|
26
|
+
)
|
|
27
|
+
parser.add_argument(
|
|
28
|
+
"--version", action="version", version=f"htvl {__version__}"
|
|
29
|
+
)
|
|
30
|
+
sub = parser.add_subparsers(dest="command", required=True)
|
|
31
|
+
|
|
32
|
+
compile_cmd = sub.add_parser(
|
|
33
|
+
"compile", help="compile every .htvl/.cal file in a directory"
|
|
34
|
+
)
|
|
35
|
+
compile_cmd.add_argument(
|
|
36
|
+
"path",
|
|
37
|
+
nargs="?",
|
|
38
|
+
default=".",
|
|
39
|
+
help="project directory (default: current directory)",
|
|
40
|
+
)
|
|
41
|
+
compile_cmd.add_argument(
|
|
42
|
+
"-o",
|
|
43
|
+
"--out",
|
|
44
|
+
default="public",
|
|
45
|
+
help="output directory for generated HTML (default: public)",
|
|
46
|
+
)
|
|
47
|
+
compile_cmd.add_argument(
|
|
48
|
+
"--modern",
|
|
49
|
+
action="store_true",
|
|
50
|
+
help=(
|
|
51
|
+
"emit clean HTML: omit empty attributes, escape text and fix "
|
|
52
|
+
"legacy cosmetic quirks (see docs/grammar.md)"
|
|
53
|
+
),
|
|
54
|
+
)
|
|
55
|
+
compile_cmd.add_argument(
|
|
56
|
+
"-q", "--quiet", action="store_true", help="only report errors"
|
|
57
|
+
)
|
|
58
|
+
compile_cmd.add_argument(
|
|
59
|
+
"-w",
|
|
60
|
+
"--watch",
|
|
61
|
+
action="store_true",
|
|
62
|
+
help="keep running and recompile on every change (Ctrl-C to stop)",
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
check_cmd = sub.add_parser(
|
|
66
|
+
"check", help="compile a single file and write the HTML to stdout"
|
|
67
|
+
)
|
|
68
|
+
check_cmd.add_argument("files", nargs="+", help=".htvl files to compile")
|
|
69
|
+
check_cmd.add_argument(
|
|
70
|
+
"--modern",
|
|
71
|
+
action="store_true",
|
|
72
|
+
help="emit clean HTML (see docs/grammar.md)",
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
new_cmd = sub.add_parser("new", help="scaffold a new HTVL project")
|
|
76
|
+
new_cmd.add_argument("name", help="directory name for the new project")
|
|
77
|
+
|
|
78
|
+
sub.add_parser("list", help="list every tag and built-in variable")
|
|
79
|
+
return parser
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def _cmd_compile(args: argparse.Namespace) -> int:
|
|
83
|
+
root = Path(args.path).resolve()
|
|
84
|
+
if not root.is_dir():
|
|
85
|
+
print(f"htvl: error: '{args.path}' is not a directory", file=sys.stderr)
|
|
86
|
+
return 1
|
|
87
|
+
if args.watch:
|
|
88
|
+
return _cmd_watch(args)
|
|
89
|
+
result = compile_project(root, out_dir=args.out, modern=args.modern)
|
|
90
|
+
if not args.quiet:
|
|
91
|
+
for output in result.outputs:
|
|
92
|
+
print(f"htvl: compiled {output.relative_to(root)}")
|
|
93
|
+
if result.copied_assets:
|
|
94
|
+
print(f"htvl: copied assets -> {result.copied_assets.relative_to(root)}")
|
|
95
|
+
if args.modern:
|
|
96
|
+
print("htvl: modern mode: clean, escaped HTML")
|
|
97
|
+
print(f"htvl: {len(result.outputs)} file(s) compiled")
|
|
98
|
+
return 0
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def _cmd_watch(args: argparse.Namespace) -> int:
|
|
102
|
+
root = Path(args.path).resolve()
|
|
103
|
+
|
|
104
|
+
def say(line: str) -> None:
|
|
105
|
+
print(f"htvl: {line}")
|
|
106
|
+
|
|
107
|
+
try:
|
|
108
|
+
watch_project(root, out_dir=args.out, modern=args.modern, printer=say)
|
|
109
|
+
except KeyboardInterrupt:
|
|
110
|
+
print("htvl: stopped")
|
|
111
|
+
return 0
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def _cmd_check(args: argparse.Namespace) -> int:
|
|
115
|
+
for name in args.files:
|
|
116
|
+
path = Path(name)
|
|
117
|
+
templates = load_templates(path.parent / "templates")
|
|
118
|
+
sys.stdout.write(
|
|
119
|
+
compile_source(
|
|
120
|
+
path.read_text(encoding="utf-8"),
|
|
121
|
+
templates,
|
|
122
|
+
modern=args.modern,
|
|
123
|
+
)
|
|
124
|
+
)
|
|
125
|
+
return 0
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
_STARTER_INDEX = """\
|
|
129
|
+
$DOCTYPE_htvl
|
|
130
|
+
$htvl
|
|
131
|
+
$head
|
|
132
|
+
$headtags
|
|
133
|
+
$_head
|
|
134
|
+
$body
|
|
135
|
+
$(nav 'navbar navbar-expand-md bg-dark navbar-dark')
|
|
136
|
+
$(a 'navbar-brand' './' 'Home' '' '' '' '')$_a
|
|
137
|
+
$(ul 'navbar-nav mr-auto')
|
|
138
|
+
$_ul
|
|
139
|
+
$_nav
|
|
140
|
+
|
|
141
|
+
$(div 'container')
|
|
142
|
+
$(h 1 '' '' 'Hello HTVL' '')
|
|
143
|
+
$(p '' '' 'This page was compiled from index.htvl by the HTVL compiler.' '')
|
|
144
|
+
$_p
|
|
145
|
+
$_div
|
|
146
|
+
$_body
|
|
147
|
+
$_htvl
|
|
148
|
+
"""
|
|
149
|
+
|
|
150
|
+
_STARTER_TEMPLATE = """\
|
|
151
|
+
$(title '' 'My HTVL page')
|
|
152
|
+
$meta
|
|
153
|
+
$(link 'stylesheet' 'text/css' './assets/style.css')
|
|
154
|
+
"""
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def _cmd_new(args: argparse.Namespace) -> int:
|
|
158
|
+
root = Path(args.name)
|
|
159
|
+
if root.exists():
|
|
160
|
+
print(f"htvl: error: '{root}' already exists", file=sys.stderr)
|
|
161
|
+
return 1
|
|
162
|
+
(root / "templates").mkdir(parents=True)
|
|
163
|
+
(root / "assets").mkdir(parents=True)
|
|
164
|
+
(root / "index.htvl").write_text(_STARTER_INDEX, encoding="utf-8")
|
|
165
|
+
(root / "templates" / "headtags.htvl").write_text(
|
|
166
|
+
_STARTER_TEMPLATE, encoding="utf-8"
|
|
167
|
+
)
|
|
168
|
+
(root / "assets" / "style.css").write_text(
|
|
169
|
+
"body { font-family: system-ui, sans-serif; }\n", encoding="utf-8"
|
|
170
|
+
)
|
|
171
|
+
print(f"htvl: created project '{root}'")
|
|
172
|
+
print(f"htvl: next: cd {root} && htvl compile")
|
|
173
|
+
return 0
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def _cmd_list(args: argparse.Namespace) -> int:
|
|
177
|
+
print("Tags")
|
|
178
|
+
print("----")
|
|
179
|
+
for name in sorted(ELEMENTS):
|
|
180
|
+
element = ELEMENTS[name]
|
|
181
|
+
print(f" {element.signature}")
|
|
182
|
+
print()
|
|
183
|
+
print("Variables")
|
|
184
|
+
print("---------")
|
|
185
|
+
for name in sorted(VARIABLES):
|
|
186
|
+
value = VARIABLES[name].replace("\n", "\\n")
|
|
187
|
+
if len(value) > 46:
|
|
188
|
+
value = value[:43] + "..."
|
|
189
|
+
print(f" ${name} -> {value}")
|
|
190
|
+
return 0
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
_COMMANDS = {
|
|
194
|
+
"compile": _cmd_compile,
|
|
195
|
+
"check": _cmd_check,
|
|
196
|
+
"new": _cmd_new,
|
|
197
|
+
"list": _cmd_list,
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
def main(argv: Optional[List[str]] = None) -> int:
|
|
202
|
+
parser = _build_parser()
|
|
203
|
+
args = parser.parse_args(argv)
|
|
204
|
+
handler = _COMMANDS[args.command]
|
|
205
|
+
try:
|
|
206
|
+
return handler(args)
|
|
207
|
+
except HtvlError as exc:
|
|
208
|
+
print(f"htvl: error: {exc}", file=sys.stderr)
|
|
209
|
+
return 1
|
|
210
|
+
except OSError as exc:
|
|
211
|
+
print(f"htvl: error: {exc}", file=sys.stderr)
|
|
212
|
+
return 1
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
if __name__ == "__main__": # pragma: no cover
|
|
216
|
+
sys.exit(main())
|