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.
Files changed (37) hide show
  1. package/README.md +114 -22
  2. package/bin/vl.js +466 -28
  3. package/compiler/SOURCE_INFO.json +6 -0
  4. package/compiler/SOURCE_REV +1 -0
  5. package/compiler/validator/vlcheck/__init__.py +10 -0
  6. package/compiler/validator/vlcheck/__main__.py +128 -0
  7. package/compiler/validator/vlcheck/ast_nodes.py +397 -0
  8. package/compiler/validator/vlcheck/checks.py +1227 -0
  9. package/compiler/validator/vlcheck/diagnostics.py +88 -0
  10. package/compiler/validator/vlcheck/lexer.py +343 -0
  11. package/compiler/validator/vlcheck/parser.py +1638 -0
  12. package/compiler/validator/vlcheck/project_config.py +97 -0
  13. package/compiler/validator/vlcheck/resolve.py +849 -0
  14. package/compiler/validator/vlcheck/test_ids.py +98 -0
  15. package/compiler/vlbuild/styling/README.md +39 -0
  16. package/compiler/vlbuild/styling/build-css.mjs +103 -0
  17. package/compiler/vlbuild/styling/package-lock.json +1254 -0
  18. package/compiler/vlbuild/styling/package.json +15 -0
  19. package/compiler/vlbuild/styling/test-build-css.mjs +69 -0
  20. package/compiler/vlbuild/vlbuild/__init__.py +16 -0
  21. package/compiler/vlbuild/vlbuild/__main__.py +246 -0
  22. package/compiler/vlbuild/vlbuild/assets/vlrt.css +165 -0
  23. package/compiler/vlbuild/vlbuild/assets/vlrt.js +1291 -0
  24. package/compiler/vlbuild/vlbuild/emit.py +2023 -0
  25. package/compiler/vlbuild/vlbuild/server_emit.py +1551 -0
  26. package/compiler/vlbuild/vlbuild/static_assets.py +83 -0
  27. package/compiler/vlbuild/vlbuild/style_config.py +347 -0
  28. package/compiler/vlbuild/vlbuild/styling.py +39 -0
  29. package/examples/station.vl +2 -2
  30. package/language/crib.md +131 -10
  31. package/language/spec.md +209 -7
  32. package/language/supported.md +185 -0
  33. package/lib/env.js +107 -0
  34. package/package.json +19 -2
  35. package/scripts/record-provenance.mjs +51 -0
  36. package/scripts/selftest.mjs +54 -0
  37. 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)