xvcl 2.5.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.
Potentially problematic release.
This version of xvcl might be problematic. Click here for more details.
- xvcl-2.5.0/.gitignore +4 -0
- xvcl-2.5.0/.python-version +1 -0
- xvcl-2.5.0/CLAUDE.md +246 -0
- xvcl-2.5.0/LICENSE +21 -0
- xvcl-2.5.0/PKG-INFO +1534 -0
- xvcl-2.5.0/README.md +1510 -0
- xvcl-2.5.0/examples/ipcrypt_deterministic.xvcl +198 -0
- xvcl-2.5.0/examples/ipcrypt_ndx.xvcl +252 -0
- xvcl-2.5.0/examples/ipcrypt_pfx.xvcl +366 -0
- xvcl-2.5.0/pyproject.toml +71 -0
- xvcl-2.5.0/src/xvcl/__init__.py +15 -0
- xvcl-2.5.0/src/xvcl/compiler.py +1381 -0
- xvcl-2.5.0/src/xvcl/py.typed +0 -0
- xvcl-2.5.0/uv.lock +251 -0
- xvcl-2.5.0/xvcl-quick-reference.md +289 -0
xvcl-2.5.0/.gitignore
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.9
|
xvcl-2.5.0/CLAUDE.md
ADDED
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## Project Overview
|
|
6
|
+
|
|
7
|
+
xvcl is a VCL transpiler/preprocessor that extends Fastly VCL with metaprogramming features. It compiles `.xvcl` files (extended VCL source) into standard `.vcl` files (valid Fastly VCL) by processing directives like loops, conditionals, constants, macros, and functions. The output VCL works with Fastly and can be validated/tested with the Falco tool.
|
|
8
|
+
|
|
9
|
+
**Key concept**: xvcl is a build step for VCL. Write enhanced VCL source files, run xvcl, get clean VCL output.
|
|
10
|
+
|
|
11
|
+
## Build and Development Commands
|
|
12
|
+
|
|
13
|
+
### Setup and Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# Install dependencies using uv (preferred) or pip
|
|
17
|
+
uv pip install -e ".[dev]"
|
|
18
|
+
|
|
19
|
+
# Or using pip
|
|
20
|
+
pip install -e ".[dev]"
|
|
21
|
+
|
|
22
|
+
# Run xvcl directly after installation
|
|
23
|
+
xvcl input.xvcl -o output.vcl
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### Development and Testing
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
# Run the compiler directly (during development)
|
|
30
|
+
python -m xvcl.compiler input.xvcl -o output.vcl
|
|
31
|
+
|
|
32
|
+
# Or use uv to run it
|
|
33
|
+
uv run xvcl input.xvcl -o output.vcl
|
|
34
|
+
|
|
35
|
+
# Run with debug mode to trace expansion
|
|
36
|
+
xvcl input.xvcl -o output.vcl --debug
|
|
37
|
+
|
|
38
|
+
# With include paths
|
|
39
|
+
xvcl input.xvcl -o output.vcl -I ./includes -I ./shared
|
|
40
|
+
|
|
41
|
+
# With source maps (adds comments showing where code came from)
|
|
42
|
+
xvcl input.xvcl -o output.vcl --source-maps
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Code Quality
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
# Format code with ruff
|
|
49
|
+
ruff format .
|
|
50
|
+
|
|
51
|
+
# Lint code
|
|
52
|
+
ruff check .
|
|
53
|
+
|
|
54
|
+
# Type check with mypy
|
|
55
|
+
mypy src/xvcl
|
|
56
|
+
|
|
57
|
+
# Fix auto-fixable linting issues
|
|
58
|
+
ruff check --fix .
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Testing Workflow
|
|
62
|
+
|
|
63
|
+
Since xvcl generates VCL, test the generated output:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
# 1. Compile xvcl to vcl
|
|
67
|
+
xvcl example.xvcl -o example.vcl
|
|
68
|
+
|
|
69
|
+
# 2. Validate generated VCL with Falco (if available)
|
|
70
|
+
falco lint example.vcl
|
|
71
|
+
|
|
72
|
+
# 3. Test generated VCL with Falco
|
|
73
|
+
falco test example.vcl
|
|
74
|
+
|
|
75
|
+
# 4. Simulate generated VCL with Falco
|
|
76
|
+
falco simulate example.vcl
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Architecture
|
|
80
|
+
|
|
81
|
+
### Single-File Compiler Design
|
|
82
|
+
|
|
83
|
+
The entire compiler is implemented in `src/xvcl/compiler.py` (~1380 lines). This is intentional - xvcl is a standalone tool with no external dependencies beyond Python stdlib.
|
|
84
|
+
|
|
85
|
+
### Core Components
|
|
86
|
+
|
|
87
|
+
**XVCLCompiler Class** (`src/xvcl/compiler.py`):
|
|
88
|
+
- Main compiler orchestrator
|
|
89
|
+
- Manages state: constants, macros, functions, include tracking, output
|
|
90
|
+
- Multi-pass compilation strategy
|
|
91
|
+
|
|
92
|
+
**Data Structures**:
|
|
93
|
+
- `Macro`: Represents inline macros for zero-overhead text substitution
|
|
94
|
+
- `Function`: Represents user-defined functions that compile to VCL subroutines
|
|
95
|
+
- `SourceLocation`: Tracks file/line for error reporting
|
|
96
|
+
- `PreprocessorError`: Exception with rich context and formatting
|
|
97
|
+
|
|
98
|
+
### Compilation Pipeline (Multi-Pass)
|
|
99
|
+
|
|
100
|
+
The compiler processes xvcl source files in **6 passes**:
|
|
101
|
+
|
|
102
|
+
1. **Pass 1 - Extract Constants**: Parse `#const NAME TYPE = value` declarations and store them. Constants are removed from output and available for template substitution.
|
|
103
|
+
|
|
104
|
+
2. **Pass 2 - Process Includes**: Process `#include "file.xvcl"` directives. Supports include-once semantics (files only included once even if referenced multiple times) and cycle detection. Include path resolution: relative to current file first, then search include paths specified with `-I`.
|
|
105
|
+
|
|
106
|
+
3. **Pass 3 - Extract Inline Macros**: Parse `#inline...#endinline` blocks. Macros are zero-overhead text substitution that expand at compile time. Automatically handles operator precedence by wrapping arguments in parentheses when needed.
|
|
107
|
+
|
|
108
|
+
4. **Pass 4 - Extract Functions**: Parse `#def...#enddef` blocks. Functions compile to VCL subroutines that use global HTTP headers for parameter passing and return values. Supports single return values and tuple returns.
|
|
109
|
+
|
|
110
|
+
5. **Pass 4.5 - Join Multi-line Function Calls**: Normalize multi-line function calls into single lines to simplify pattern matching in the next pass.
|
|
111
|
+
|
|
112
|
+
6. **Pass 5 - Process Directives**: Process `#for` loops, `#if` conditionals, `#let` variable declarations, function calls, macro expansions, and template expressions (`{{expr}}`). This is the main code generation pass.
|
|
113
|
+
|
|
114
|
+
7. **Pass 6 - Generate Function Subroutines**: Append VCL subroutine implementations for all user-defined functions. Each function becomes a VCL subroutine with scope annotations.
|
|
115
|
+
|
|
116
|
+
### Key Implementation Details
|
|
117
|
+
|
|
118
|
+
**Function Compilation Strategy**:
|
|
119
|
+
- Functions are compiled into VCL subroutines with scope annotations (`//@recv, hash, hit, miss, pass, fetch, error, deliver, log`)
|
|
120
|
+
- Parameters are passed via global HTTP headers: `req.http.X-Func-{funcname}-{paramname}`
|
|
121
|
+
- Return values use global headers: `req.http.X-Func-{funcname}-Return` (or `Return0`, `Return1` for tuples)
|
|
122
|
+
- Type conversions are automatic: INTEGER/FLOAT/BOOL converted to/from STRING using `std.itoa()`, `std.atoi()`, `std.atof()`, etc.
|
|
123
|
+
|
|
124
|
+
**Macro Expansion**:
|
|
125
|
+
- Macros expand inline (no function call overhead)
|
|
126
|
+
- Nested macros are supported (up to 10 iterations)
|
|
127
|
+
- Arguments containing operators are automatically wrapped in parentheses to preserve precedence
|
|
128
|
+
- Expansion happens during Pass 5 before other processing
|
|
129
|
+
|
|
130
|
+
**Error Reporting**:
|
|
131
|
+
- Tracks source location (file, line) throughout compilation
|
|
132
|
+
- Shows context lines around errors (3 lines before/after)
|
|
133
|
+
- Provides "did you mean" suggestions for undefined names
|
|
134
|
+
- Color-coded terminal output for readability
|
|
135
|
+
|
|
136
|
+
**Include System**:
|
|
137
|
+
- Include-once semantics prevent duplicate inclusion
|
|
138
|
+
- Circular include detection with stack tracking
|
|
139
|
+
- Path resolution order: relative to current file → include paths (`-I`)
|
|
140
|
+
- Optional source map comments (`--source-maps`) mark included file boundaries
|
|
141
|
+
|
|
142
|
+
## Feature Directives
|
|
143
|
+
|
|
144
|
+
### Constants (`#const`)
|
|
145
|
+
```vcl
|
|
146
|
+
#const MAX_AGE INTEGER = 3600
|
|
147
|
+
#const ORIGIN STRING = "origin.example.com"
|
|
148
|
+
```
|
|
149
|
+
Constants are compile-time values substituted into templates. Type-checked when type is specified.
|
|
150
|
+
|
|
151
|
+
### Template Expressions (`{{expr}}`)
|
|
152
|
+
```vcl
|
|
153
|
+
set req.http.X-Port = "{{PORT}}";
|
|
154
|
+
backend F_{{REGION}}_{{ENV}} { ... }
|
|
155
|
+
```
|
|
156
|
+
Evaluated at compile time using Python's `eval()`. Has access to constants, loop variables, and safe built-ins (`range`, `len`, `str`, `int`, `hex`, `min`, `max`, `abs`).
|
|
157
|
+
|
|
158
|
+
### For Loops (`#for...#endfor`)
|
|
159
|
+
```vcl
|
|
160
|
+
#for i in range(5)
|
|
161
|
+
backend web{{i}} { .host = "web{{i}}.example.com"; }
|
|
162
|
+
#endfor
|
|
163
|
+
```
|
|
164
|
+
Generate repetitive code. Can iterate over ranges or lists.
|
|
165
|
+
|
|
166
|
+
### Conditionals (`#if...#else...#endif`)
|
|
167
|
+
```vcl
|
|
168
|
+
#if PRODUCTION
|
|
169
|
+
set req.http.X-Env = "prod";
|
|
170
|
+
#else
|
|
171
|
+
set req.http.X-Env = "dev";
|
|
172
|
+
#endif
|
|
173
|
+
```
|
|
174
|
+
Conditional compilation based on compile-time conditions.
|
|
175
|
+
|
|
176
|
+
### Variables (`#let`)
|
|
177
|
+
```vcl
|
|
178
|
+
#let timestamp STRING = std.time(now, now);
|
|
179
|
+
```
|
|
180
|
+
Shorthand for `declare local` + `set`. Expands to two VCL statements.
|
|
181
|
+
|
|
182
|
+
### Inline Macros (`#inline...#endinline`)
|
|
183
|
+
```vcl
|
|
184
|
+
#inline normalize_host(host)
|
|
185
|
+
std.tolower(regsub(host, "^www\.", ""))
|
|
186
|
+
#endinline
|
|
187
|
+
```
|
|
188
|
+
Zero-overhead text substitution. Use for simple expressions repeated throughout code.
|
|
189
|
+
|
|
190
|
+
### Functions (`#def...#enddef`)
|
|
191
|
+
```vcl
|
|
192
|
+
#def normalize_path(path STRING) -> STRING
|
|
193
|
+
declare local var.result STRING;
|
|
194
|
+
set var.result = std.tolower(path);
|
|
195
|
+
return var.result;
|
|
196
|
+
#enddef
|
|
197
|
+
```
|
|
198
|
+
Reusable logic that compiles to VCL subroutines. Supports single and tuple returns.
|
|
199
|
+
|
|
200
|
+
### File Includes (`#include`)
|
|
201
|
+
```vcl
|
|
202
|
+
#include "includes/backends.xvcl"
|
|
203
|
+
```
|
|
204
|
+
Include other xvcl files. Include-once semantics and cycle detection.
|
|
205
|
+
|
|
206
|
+
## Code Organization
|
|
207
|
+
|
|
208
|
+
```
|
|
209
|
+
.
|
|
210
|
+
├── src/xvcl/
|
|
211
|
+
│ ├── __init__.py # Package exports (XVCLCompiler, __version__)
|
|
212
|
+
│ └── compiler.py # Single-file compiler implementation (~1380 lines)
|
|
213
|
+
├── pyproject.toml # Project metadata, dependencies, build config
|
|
214
|
+
├── README.md # Comprehensive user documentation with examples
|
|
215
|
+
├── xvcl-quick-reference.md # Quick syntax reference for users
|
|
216
|
+
└── .python-version # Python version (3.9)
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
**No tests directory**: xvcl is tested by compiling example files and validating the generated VCL with Falco. The project relies on Falco for VCL validation rather than unit tests.
|
|
220
|
+
|
|
221
|
+
## Configuration
|
|
222
|
+
|
|
223
|
+
Configured via `pyproject.toml`:
|
|
224
|
+
- **Build system**: Hatchling (PEP 517)
|
|
225
|
+
- **Entry point**: `xvcl` command → `xvcl.compiler:main`
|
|
226
|
+
- **Linting**: Ruff (replaces flake8, isort, pyupgrade)
|
|
227
|
+
- **Type checking**: mypy (lenient config, not strict)
|
|
228
|
+
- **Python version**: 3.9+ required
|
|
229
|
+
|
|
230
|
+
## Integration with Falco
|
|
231
|
+
|
|
232
|
+
xvcl is designed to work with Falco (VCL linter/tester/simulator). Typical workflow:
|
|
233
|
+
|
|
234
|
+
1. Write xvcl source (`.xvcl` files)
|
|
235
|
+
2. Compile with xvcl → generates `.vcl` files
|
|
236
|
+
3. Validate with Falco: `falco lint output.vcl`
|
|
237
|
+
4. Test with Falco: `falco test output.vcl`
|
|
238
|
+
5. Deploy the generated `.vcl` to Fastly
|
|
239
|
+
|
|
240
|
+
## Notes
|
|
241
|
+
|
|
242
|
+
- **No backwards compatibility concerns**: The user has explicitly stated they don't care about backwards compatibility for the VCL preprocessor
|
|
243
|
+
- **Standalone tool**: xvcl has zero external dependencies (only Python stdlib)
|
|
244
|
+
- **Single-file design**: The entire compiler is intentionally in one file for portability
|
|
245
|
+
- **Debug mode**: Always use `--debug` flag when troubleshooting compilation issues
|
|
246
|
+
- **Source maps**: Use `--source-maps` during development to track code origin
|
xvcl-2.5.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Frank Denis
|
|
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.
|