volaro 0.0.2 → 0.1.0-alpha.3
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.
- package/README.md +114 -22
- package/bin/vl.js +466 -28
- package/compiler/SOURCE_INFO.json +6 -0
- package/compiler/SOURCE_REV +1 -0
- package/compiler/validator/vlcheck/__init__.py +10 -0
- package/compiler/validator/vlcheck/__main__.py +128 -0
- package/compiler/validator/vlcheck/ast_nodes.py +397 -0
- package/compiler/validator/vlcheck/checks.py +1227 -0
- package/compiler/validator/vlcheck/diagnostics.py +88 -0
- package/compiler/validator/vlcheck/lexer.py +343 -0
- package/compiler/validator/vlcheck/parser.py +1638 -0
- package/compiler/validator/vlcheck/project_config.py +97 -0
- package/compiler/validator/vlcheck/resolve.py +849 -0
- package/compiler/validator/vlcheck/test_ids.py +98 -0
- package/compiler/vlbuild/styling/README.md +39 -0
- package/compiler/vlbuild/styling/build-css.mjs +103 -0
- package/compiler/vlbuild/styling/package-lock.json +1254 -0
- package/compiler/vlbuild/styling/package.json +15 -0
- package/compiler/vlbuild/styling/test-build-css.mjs +69 -0
- package/compiler/vlbuild/vlbuild/__init__.py +16 -0
- package/compiler/vlbuild/vlbuild/__main__.py +246 -0
- package/compiler/vlbuild/vlbuild/assets/vlrt.css +165 -0
- package/compiler/vlbuild/vlbuild/assets/vlrt.js +1291 -0
- package/compiler/vlbuild/vlbuild/emit.py +2023 -0
- package/compiler/vlbuild/vlbuild/server_emit.py +1551 -0
- package/compiler/vlbuild/vlbuild/static_assets.py +83 -0
- package/compiler/vlbuild/vlbuild/style_config.py +347 -0
- package/compiler/vlbuild/vlbuild/styling.py +39 -0
- package/examples/station.vl +2 -2
- package/language/crib.md +131 -10
- package/language/spec.md +209 -7
- package/language/supported.md +185 -0
- package/lib/env.js +107 -0
- package/package.json +19 -2
- package/scripts/record-provenance.mjs +51 -0
- package/scripts/selftest.mjs +54 -0
- package/scripts/sync-compiler.sh +52 -0
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"""Shared, read-only versioned project configuration for checker and builder."""
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
import json
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class ConfigError(ValueError):
|
|
8
|
+
def __init__(self, code, path, message):
|
|
9
|
+
self.code, self.path = code, path
|
|
10
|
+
super().__init__(f"{code}: {path}: {message}")
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@dataclass(frozen=True)
|
|
14
|
+
class ProjectConfig:
|
|
15
|
+
emit_ids: bool = True
|
|
16
|
+
path: Path | None = None
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
CONFIG_NAME = "volaro.json"
|
|
20
|
+
LEGACY_CONFIG_NAME = "volara.json"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _legacy_error(target, *, both):
|
|
24
|
+
# The project config was renamed volara.json -> volaro.json. The old name is
|
|
25
|
+
# never read: silently ignoring it would flip a project's emit_ids default,
|
|
26
|
+
# and silently preferring the new name when both exist hides a half-done
|
|
27
|
+
# migration. Both cases fail loudly with the fix in the message.
|
|
28
|
+
if both:
|
|
29
|
+
message = (f"both {CONFIG_NAME} and the legacy {LEGACY_CONFIG_NAME} are "
|
|
30
|
+
f"present; reconcile the settings into {CONFIG_NAME}, then "
|
|
31
|
+
f"remove {LEGACY_CONFIG_NAME} (config was renamed "
|
|
32
|
+
f"{LEGACY_CONFIG_NAME} → {CONFIG_NAME}; the files may differ)")
|
|
33
|
+
else:
|
|
34
|
+
message = (f"rename {LEGACY_CONFIG_NAME} to {CONFIG_NAME}; the old name "
|
|
35
|
+
f"is no longer read (config was renamed {LEGACY_CONFIG_NAME} "
|
|
36
|
+
f"→ {CONFIG_NAME})")
|
|
37
|
+
return ConfigError("E-CONFIG-LEGACY", target, message)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def load_config(source, explicit=None):
|
|
41
|
+
if explicit is not None:
|
|
42
|
+
path = Path(explicit).absolute()
|
|
43
|
+
if path.name == LEGACY_CONFIG_NAME:
|
|
44
|
+
raise _legacy_error(path, both=False)
|
|
45
|
+
else:
|
|
46
|
+
path = None
|
|
47
|
+
start = Path(source).resolve()
|
|
48
|
+
start = start if start.is_dir() else start.parent
|
|
49
|
+
for directory in (start, *start.parents):
|
|
50
|
+
candidate = directory / CONFIG_NAME
|
|
51
|
+
legacy = directory / LEGACY_CONFIG_NAME
|
|
52
|
+
here = candidate.exists() or candidate.is_symlink()
|
|
53
|
+
legacy_here = legacy.exists() or legacy.is_symlink()
|
|
54
|
+
if here and legacy_here:
|
|
55
|
+
raise _legacy_error(legacy, both=True)
|
|
56
|
+
if legacy_here:
|
|
57
|
+
raise _legacy_error(legacy, both=False)
|
|
58
|
+
if here:
|
|
59
|
+
path = candidate
|
|
60
|
+
break
|
|
61
|
+
if (directory / ".git").exists():
|
|
62
|
+
break
|
|
63
|
+
if path is None:
|
|
64
|
+
return ProjectConfig()
|
|
65
|
+
|
|
66
|
+
def pairs(items):
|
|
67
|
+
obj = {}
|
|
68
|
+
for key, value in items:
|
|
69
|
+
if key in obj:
|
|
70
|
+
raise ConfigError("E-CONFIG-JSON", path, "duplicate object key; remove the duplicate")
|
|
71
|
+
obj[key] = value
|
|
72
|
+
return obj
|
|
73
|
+
|
|
74
|
+
try:
|
|
75
|
+
raw = path.read_text(encoding="utf-8")
|
|
76
|
+
except (OSError, UnicodeError) as exc:
|
|
77
|
+
raise ConfigError("E-CONFIG-READ", path, "cannot read UTF-8 configuration") from exc
|
|
78
|
+
try:
|
|
79
|
+
data = json.loads(raw, object_pairs_hook=pairs,
|
|
80
|
+
parse_constant=lambda _: (_ for _ in ()).throw(ValueError()))
|
|
81
|
+
except (ValueError, RecursionError) as exc:
|
|
82
|
+
if isinstance(exc, ConfigError):
|
|
83
|
+
raise
|
|
84
|
+
raise ConfigError("E-CONFIG-JSON", path, "invalid JSON; use a JSON object") from exc
|
|
85
|
+
if not isinstance(data, dict):
|
|
86
|
+
raise ConfigError("E-CONFIG-OPTION", path, "configuration must be an object")
|
|
87
|
+
if type(data.get("schema_version")) is not int or data["schema_version"] != 1:
|
|
88
|
+
raise ConfigError("E-CONFIG-VERSION", path, "schema_version must be integer 1")
|
|
89
|
+
if set(data) - {"schema_version", "testing"}:
|
|
90
|
+
raise ConfigError("E-CONFIG-OPTION", path, "unsupported top-level option")
|
|
91
|
+
testing = data.get("testing", {})
|
|
92
|
+
if not isinstance(testing, dict) or set(testing) - {"emit_ids"}:
|
|
93
|
+
raise ConfigError("E-CONFIG-OPTION", path, "testing supports only emit_ids")
|
|
94
|
+
emit = testing.get("emit_ids", True)
|
|
95
|
+
if type(emit) is not bool:
|
|
96
|
+
raise ConfigError("E-CONFIG-OPTION", path, "testing.emit_ids must be boolean")
|
|
97
|
+
return ProjectConfig(emit, path)
|