envschema-dsl 0.1.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.
Files changed (28) hide show
  1. envschema_dsl-0.1.0/PKG-INFO +197 -0
  2. envschema_dsl-0.1.0/README.md +173 -0
  3. envschema_dsl-0.1.0/pyproject.toml +45 -0
  4. envschema_dsl-0.1.0/src/envschema/__init__.py +23 -0
  5. envschema_dsl-0.1.0/src/envschema/ast.py +108 -0
  6. envschema_dsl-0.1.0/src/envschema/cli.py +244 -0
  7. envschema_dsl-0.1.0/src/envschema/env_file.py +63 -0
  8. envschema_dsl-0.1.0/src/envschema/expander.py +80 -0
  9. envschema_dsl-0.1.0/src/envschema/generators/__init__.py +0 -0
  10. envschema_dsl-0.1.0/src/envschema/generators/env_example.py +84 -0
  11. envschema_dsl-0.1.0/src/envschema/generators/pydantic_gen.py +4 -0
  12. envschema_dsl-0.1.0/src/envschema/generators/python/__init__.py +0 -0
  13. envschema_dsl-0.1.0/src/envschema/generators/python/dataclasses_gen.py +144 -0
  14. envschema_dsl-0.1.0/src/envschema/generators/python/pydantic_v2.py +111 -0
  15. envschema_dsl-0.1.0/src/envschema/generators/registry.py +92 -0
  16. envschema_dsl-0.1.0/src/envschema/generators/resolve.py +38 -0
  17. envschema_dsl-0.1.0/src/envschema/generators/ts/__init__.py +0 -0
  18. envschema_dsl-0.1.0/src/envschema/generators/ts/interface.py +81 -0
  19. envschema_dsl-0.1.0/src/envschema/generators/ts/zod_v4.py +119 -0
  20. envschema_dsl-0.1.0/src/envschema/generators/typescript.py +4 -0
  21. envschema_dsl-0.1.0/src/envschema/grammar.lark +108 -0
  22. envschema_dsl-0.1.0/src/envschema/lsp.py +253 -0
  23. envschema_dsl-0.1.0/src/envschema/parser.py +387 -0
  24. envschema_dsl-0.1.0/src/envschema/presets/node.js.schema +8 -0
  25. envschema_dsl-0.1.0/src/envschema/presets/vite.schema +7 -0
  26. envschema_dsl-0.1.0/src/envschema/presets_manager.py +100 -0
  27. envschema_dsl-0.1.0/src/envschema/py.typed +0 -0
  28. envschema_dsl-0.1.0/src/envschema/validator.py +327 -0
@@ -0,0 +1,197 @@
1
+ Metadata-Version: 2.4
2
+ Name: envschema-dsl
3
+ Version: 0.1.0
4
+ Summary: DSL for typed .env files — schema, validation, codegen
5
+ Keywords: env,dotenv,schema,validation,codegen,typescript,pydantic,zod
6
+ Author: nike4192
7
+ Author-email: nike4192 <nike4192@outlook.com>
8
+ License-Expression: MIT
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Programming Language :: Python :: 3.12
13
+ Classifier: Topic :: Software Development :: Code Generators
14
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
15
+ Requires-Dist: lark>=1.2
16
+ Requires-Dist: click>=8.0
17
+ Requires-Dist: pygls>=2.1.1
18
+ Requires-Dist: pytest>=8.0 ; extra == 'dev'
19
+ Requires-Python: >=3.12
20
+ Project-URL: Homepage, https://github.com/envschema/envschema
21
+ Project-URL: Repository, https://github.com/envschema/envschema
22
+ Provides-Extra: dev
23
+ Description-Content-Type: text/markdown
24
+
25
+ # envschema
26
+
27
+ DSL for typed `.env` files — schema, validation, codegen.
28
+
29
+ ## Install
30
+
31
+ ```bash
32
+ pip install envschema
33
+ # or
34
+ uv add envschema
35
+ ```
36
+
37
+ ## Quick Start
38
+
39
+ Create a `.env.schema` file:
40
+
41
+ ```python
42
+ # Database
43
+ DB_HOST str @required
44
+ DB_PORT port = 5432
45
+ DB_PASSWORD str @secret @required
46
+ DB_NAME str = "myapp"
47
+
48
+ # App
49
+ NODE_ENV enum("development", "production", "test") = "development"
50
+ PORT int = 3000 : 0 < x < 65535
51
+ DEBUG bool = false
52
+ CORS_ORIGIN str[] = "http://localhost:3000"
53
+ API_KEY str @required : len(x) >= 32
54
+ ```
55
+
56
+ Validate your `.env` file:
57
+
58
+ ```bash
59
+ envschema validate .env.schema --env .env
60
+ ```
61
+
62
+ ```
63
+ ✓ DB_HOST = db.example.com
64
+ ✓ DB_PORT = 5432
65
+ ✓ DB_PASSWORD = ***
66
+ ✓ NODE_ENV = development
67
+ ✓ PORT = 3000
68
+ ✗ API_KEY — validation failed: len(x) >= 32 (x='short')
69
+ ⚠ UNKNOWN_VAR — not defined in schema
70
+
71
+ Result: 5 OK, 1 errors, 1 warnings
72
+ ```
73
+
74
+ Generate code:
75
+
76
+ ```bash
77
+ envschema generate .env.schema -t ts # TypeScript interface
78
+ envschema generate .env.schema -t zod # Zod v4 schema
79
+ envschema generate .env.schema -t pydantic # Pydantic BaseSettings
80
+ envschema generate .env.schema -t dataclasses # Python dataclass (no deps)
81
+ envschema generate .env.schema -t env-example # .env.example
82
+ ```
83
+
84
+ ## Features
85
+
86
+ ### Types
87
+
88
+ ```python
89
+ HOST str = "localhost" # string
90
+ PORT int = 3000 # integer
91
+ RATIO float = 0.5 # float
92
+ DEBUG bool = false # boolean
93
+ API_PORT port = 8080 # port (int 1-65535)
94
+ BASE_URL url # URL (any scheme://)
95
+ ADMIN_EMAIL email # email
96
+ DATA_DIR path = "/var/data" # filesystem path
97
+ NODE_ENV enum("dev", "prod") # enum
98
+ HOSTS str[] # array (comma-separated)
99
+ ```
100
+
101
+ Type inference from defaults — `PORT = 3000` is inferred as `int`.
102
+
103
+ ### Decorators
104
+
105
+ ```python
106
+ DB_HOST str @required # must be set
107
+ DB_PASSWORD str @secret @required # hidden in output
108
+ LOG_LEVEL str @description("Logging level") # description
109
+ ```
110
+
111
+ ### Inline Validation
112
+
113
+ Python expressions with `x` as the value:
114
+
115
+ ```python
116
+ PORT int = 3000 : 0 < x < 65535
117
+ API_KEY str @required : len(x) >= 32
118
+ RATE_LIMIT int = 100 : 0 < x < 10000
119
+ ```
120
+
121
+ ### Block Syntax
122
+
123
+ For complex variables:
124
+
125
+ ```python
126
+ DATABASE_URL {
127
+ type = url
128
+ description = "PostgreSQL connection string"
129
+ @secret
130
+ @required
131
+ validate = "x.startswith('postgres://')"
132
+ }
133
+ ```
134
+
135
+ ### Type Aliases
136
+
137
+ ```python
138
+ type LogLevel = enum("error", "warn", "info", "debug")
139
+ type ExtendedEnv = NodeEnv + enum("local")
140
+
141
+ LOG_LEVEL LogLevel = "warn"
142
+ ```
143
+
144
+ ### Presets
145
+
146
+ ```python
147
+ #include <node.js> # built-in preset (NODE_ENV, PORT, HOST)
148
+ #include <vite> # VITE_* variables
149
+ #include "shared.schema" # local file
150
+
151
+ APP_NAME str = "myapp"
152
+ ```
153
+
154
+ ```bash
155
+ envschema presets list # list available presets
156
+ envschema presets load directus # download from registry
157
+ ```
158
+
159
+ ### Wildcard Expansion
160
+
161
+ ```python
162
+ AUTH_PROVIDERS str[] = "google,github"
163
+
164
+ AUTH_{AUTH_PROVIDERS}_DRIVER str @required
165
+ AUTH_{AUTH_PROVIDERS}_CLIENT_ID str @secret @required
166
+ AUTH_{AUTH_PROVIDERS}_CLIENT_SECRET str @secret @required
167
+ ```
168
+
169
+ Expands to `AUTH_GOOGLE_DRIVER`, `AUTH_GITHUB_DRIVER`, etc.
170
+ Default filter: `upper`. Custom: `{AUTH_PROVIDERS|lower}`.
171
+
172
+ ## CLI
173
+
174
+ ```bash
175
+ envschema parse <file> # parse and display AST
176
+ envschema parse <file> --json # output as JSON
177
+ envschema validate <schema> --env <env> # validate .env against schema
178
+ envschema generate <schema> -t <target> # generate code
179
+ envschema generators list # list available targets
180
+ envschema presets list # list presets
181
+ envschema presets load <name> # download preset
182
+ envschema lsp # start LSP server (stdio)
183
+ ```
184
+
185
+ ## VS Code Extension
186
+
187
+ ```bash
188
+ cd editors/vscode/envschema
189
+ npx @vscode/vsce package --allow-missing-repository
190
+ cursor --install-extension envschema-0.1.0.vsix
191
+ ```
192
+
193
+ Provides syntax highlighting for `.env.schema` files.
194
+
195
+ ## License
196
+
197
+ MIT
@@ -0,0 +1,173 @@
1
+ # envschema
2
+
3
+ DSL for typed `.env` files — schema, validation, codegen.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ pip install envschema
9
+ # or
10
+ uv add envschema
11
+ ```
12
+
13
+ ## Quick Start
14
+
15
+ Create a `.env.schema` file:
16
+
17
+ ```python
18
+ # Database
19
+ DB_HOST str @required
20
+ DB_PORT port = 5432
21
+ DB_PASSWORD str @secret @required
22
+ DB_NAME str = "myapp"
23
+
24
+ # App
25
+ NODE_ENV enum("development", "production", "test") = "development"
26
+ PORT int = 3000 : 0 < x < 65535
27
+ DEBUG bool = false
28
+ CORS_ORIGIN str[] = "http://localhost:3000"
29
+ API_KEY str @required : len(x) >= 32
30
+ ```
31
+
32
+ Validate your `.env` file:
33
+
34
+ ```bash
35
+ envschema validate .env.schema --env .env
36
+ ```
37
+
38
+ ```
39
+ ✓ DB_HOST = db.example.com
40
+ ✓ DB_PORT = 5432
41
+ ✓ DB_PASSWORD = ***
42
+ ✓ NODE_ENV = development
43
+ ✓ PORT = 3000
44
+ ✗ API_KEY — validation failed: len(x) >= 32 (x='short')
45
+ ⚠ UNKNOWN_VAR — not defined in schema
46
+
47
+ Result: 5 OK, 1 errors, 1 warnings
48
+ ```
49
+
50
+ Generate code:
51
+
52
+ ```bash
53
+ envschema generate .env.schema -t ts # TypeScript interface
54
+ envschema generate .env.schema -t zod # Zod v4 schema
55
+ envschema generate .env.schema -t pydantic # Pydantic BaseSettings
56
+ envschema generate .env.schema -t dataclasses # Python dataclass (no deps)
57
+ envschema generate .env.schema -t env-example # .env.example
58
+ ```
59
+
60
+ ## Features
61
+
62
+ ### Types
63
+
64
+ ```python
65
+ HOST str = "localhost" # string
66
+ PORT int = 3000 # integer
67
+ RATIO float = 0.5 # float
68
+ DEBUG bool = false # boolean
69
+ API_PORT port = 8080 # port (int 1-65535)
70
+ BASE_URL url # URL (any scheme://)
71
+ ADMIN_EMAIL email # email
72
+ DATA_DIR path = "/var/data" # filesystem path
73
+ NODE_ENV enum("dev", "prod") # enum
74
+ HOSTS str[] # array (comma-separated)
75
+ ```
76
+
77
+ Type inference from defaults — `PORT = 3000` is inferred as `int`.
78
+
79
+ ### Decorators
80
+
81
+ ```python
82
+ DB_HOST str @required # must be set
83
+ DB_PASSWORD str @secret @required # hidden in output
84
+ LOG_LEVEL str @description("Logging level") # description
85
+ ```
86
+
87
+ ### Inline Validation
88
+
89
+ Python expressions with `x` as the value:
90
+
91
+ ```python
92
+ PORT int = 3000 : 0 < x < 65535
93
+ API_KEY str @required : len(x) >= 32
94
+ RATE_LIMIT int = 100 : 0 < x < 10000
95
+ ```
96
+
97
+ ### Block Syntax
98
+
99
+ For complex variables:
100
+
101
+ ```python
102
+ DATABASE_URL {
103
+ type = url
104
+ description = "PostgreSQL connection string"
105
+ @secret
106
+ @required
107
+ validate = "x.startswith('postgres://')"
108
+ }
109
+ ```
110
+
111
+ ### Type Aliases
112
+
113
+ ```python
114
+ type LogLevel = enum("error", "warn", "info", "debug")
115
+ type ExtendedEnv = NodeEnv + enum("local")
116
+
117
+ LOG_LEVEL LogLevel = "warn"
118
+ ```
119
+
120
+ ### Presets
121
+
122
+ ```python
123
+ #include <node.js> # built-in preset (NODE_ENV, PORT, HOST)
124
+ #include <vite> # VITE_* variables
125
+ #include "shared.schema" # local file
126
+
127
+ APP_NAME str = "myapp"
128
+ ```
129
+
130
+ ```bash
131
+ envschema presets list # list available presets
132
+ envschema presets load directus # download from registry
133
+ ```
134
+
135
+ ### Wildcard Expansion
136
+
137
+ ```python
138
+ AUTH_PROVIDERS str[] = "google,github"
139
+
140
+ AUTH_{AUTH_PROVIDERS}_DRIVER str @required
141
+ AUTH_{AUTH_PROVIDERS}_CLIENT_ID str @secret @required
142
+ AUTH_{AUTH_PROVIDERS}_CLIENT_SECRET str @secret @required
143
+ ```
144
+
145
+ Expands to `AUTH_GOOGLE_DRIVER`, `AUTH_GITHUB_DRIVER`, etc.
146
+ Default filter: `upper`. Custom: `{AUTH_PROVIDERS|lower}`.
147
+
148
+ ## CLI
149
+
150
+ ```bash
151
+ envschema parse <file> # parse and display AST
152
+ envschema parse <file> --json # output as JSON
153
+ envschema validate <schema> --env <env> # validate .env against schema
154
+ envschema generate <schema> -t <target> # generate code
155
+ envschema generators list # list available targets
156
+ envschema presets list # list presets
157
+ envschema presets load <name> # download preset
158
+ envschema lsp # start LSP server (stdio)
159
+ ```
160
+
161
+ ## VS Code Extension
162
+
163
+ ```bash
164
+ cd editors/vscode/envschema
165
+ npx @vscode/vsce package --allow-missing-repository
166
+ cursor --install-extension envschema-0.1.0.vsix
167
+ ```
168
+
169
+ Provides syntax highlighting for `.env.schema` files.
170
+
171
+ ## License
172
+
173
+ MIT
@@ -0,0 +1,45 @@
1
+ [project]
2
+ name = "envschema-dsl"
3
+ version = "0.1.0"
4
+ description = "DSL for typed .env files — schema, validation, codegen"
5
+ readme = "README.md"
6
+ license = "MIT"
7
+ authors = [
8
+ { name = "nike4192", email = "nike4192@outlook.com" }
9
+ ]
10
+ requires-python = ">=3.12"
11
+ keywords = ["env", "dotenv", "schema", "validation", "codegen", "typescript", "pydantic", "zod"]
12
+ classifiers = [
13
+ "Development Status :: 3 - Alpha",
14
+ "Intended Audience :: Developers",
15
+ "License :: OSI Approved :: MIT License",
16
+ "Programming Language :: Python :: 3.12",
17
+ "Topic :: Software Development :: Code Generators",
18
+ "Topic :: Software Development :: Libraries :: Python Modules",
19
+ ]
20
+ dependencies = [
21
+ "lark>=1.2",
22
+ "click>=8.0",
23
+ "pygls>=2.1.1",
24
+ ]
25
+
26
+ [project.optional-dependencies]
27
+ dev = [
28
+ "pytest>=8.0",
29
+ ]
30
+
31
+ [project.urls]
32
+ Homepage = "https://github.com/envschema/envschema"
33
+ Repository = "https://github.com/envschema/envschema"
34
+
35
+ [project.scripts]
36
+ envschema = "envschema.cli:cli"
37
+
38
+ [tool.uv.build-backend]
39
+ module-name = "envschema"
40
+ # PyPI name: envschema-dsl (envschema was taken)
41
+ # Import: from envschema import ...
42
+
43
+ [build-system]
44
+ requires = ["uv_build>=0.11.3,<0.12.0"]
45
+ build-backend = "uv_build"
@@ -0,0 +1,23 @@
1
+ """EnvSchema — DSL for typed .env files."""
2
+
3
+ from .ast import (
4
+ ArrayType, Comment, Decorator, EnumType, Expansion, Include,
5
+ Schema, SimpleType, TypeAlias, TypeRef, UnionType, Variable,
6
+ )
7
+ from .parser import parse, parse_file
8
+
9
+ __all__ = [
10
+ "ArrayType",
11
+ "Comment",
12
+ "Decorator",
13
+ "EnumType",
14
+ "Include",
15
+ "Schema",
16
+ "SimpleType",
17
+ "TypeAlias",
18
+ "TypeRef",
19
+ "UnionType",
20
+ "Variable",
21
+ "parse",
22
+ "parse_file",
23
+ ]
@@ -0,0 +1,108 @@
1
+ """AST node definitions for EnvSchema DSL."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass, field
6
+ from enum import Enum
7
+
8
+
9
+ class SimpleType(Enum):
10
+ STR = "str"
11
+ INT = "int"
12
+ FLOAT = "float"
13
+ BOOL = "bool"
14
+ PORT = "port"
15
+ URL = "url"
16
+ EMAIL = "email"
17
+ PATH = "path"
18
+
19
+
20
+ @dataclass
21
+ class EnumType:
22
+ values: list[str]
23
+
24
+
25
+ @dataclass
26
+ class TypeRef:
27
+ """Reference to a named type (from type alias or preset)."""
28
+ name: str
29
+
30
+
31
+ @dataclass
32
+ class UnionType:
33
+ """Union of types: TypeA + TypeB."""
34
+ types: list[SimpleType | EnumType | TypeRef]
35
+
36
+
37
+ @dataclass
38
+ class ArrayType:
39
+ element_type: SimpleType | EnumType | TypeRef
40
+
41
+
42
+ @dataclass
43
+ class Decorator:
44
+ name: str
45
+ arg: str | None = None
46
+
47
+
48
+ @dataclass
49
+ class Expansion:
50
+ """Wildcard expansion marker — {PROVIDERS} or {PROVIDERS|upper}."""
51
+ source: str # Variable name to expand from (e.g., "PROVIDERS")
52
+ filter: str | None = None # Optional filter (e.g., "upper")
53
+
54
+
55
+ @dataclass
56
+ class Include:
57
+ """#include directive."""
58
+ target: str # preset name or file path
59
+ is_local: bool = False # True for "path", False for <preset>
60
+ line: int | None = None
61
+
62
+
63
+ @dataclass
64
+ class TypeAlias:
65
+ """type Name = expr."""
66
+ name: str
67
+ value: SimpleType | EnumType | TypeRef | UnionType
68
+ line: int | None = None
69
+
70
+
71
+ @dataclass
72
+ class Variable:
73
+ name: str
74
+ type: SimpleType | EnumType | ArrayType | TypeRef | None = None
75
+ default: str | int | float | bool | None = None
76
+ decorators: list[Decorator] = field(default_factory=list)
77
+ validation: str | None = None
78
+ expansion: Expansion | None = None
79
+ line: int | None = None
80
+
81
+ @property
82
+ def is_required(self) -> bool:
83
+ return any(d.name == "required" for d in self.decorators)
84
+
85
+ @property
86
+ def is_secret(self) -> bool:
87
+ return any(d.name == "secret" for d in self.decorators)
88
+
89
+
90
+ @dataclass
91
+ class Comment:
92
+ text: str
93
+ line: int | None = None
94
+
95
+
96
+ @dataclass
97
+ class Schema:
98
+ variables: list[Variable] = field(default_factory=list)
99
+ comments: list[Comment] = field(default_factory=list)
100
+ includes: list[Include] = field(default_factory=list)
101
+ type_aliases: list[TypeAlias] = field(default_factory=list)
102
+
103
+ def resolve_type(self, name: str) -> SimpleType | EnumType | UnionType | None:
104
+ """Look up a type alias by name."""
105
+ for alias in self.type_aliases:
106
+ if alias.name == name:
107
+ return alias.value
108
+ return None