proj-flow 0.18.0__py3-none-any.whl → 0.20.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.
Files changed (33) hide show
  1. proj_flow/__init__.py +1 -1
  2. proj_flow/api/makefile.py +1 -1
  3. proj_flow/ext/tools/__init__.py +13 -0
  4. proj_flow/ext/tools/pragma_once.py +40 -0
  5. proj_flow/ext/tools/run_linter.py +228 -0
  6. proj_flow/ext/webidl/__init__.py +12 -0
  7. proj_flow/ext/webidl/base/__init__.py +2 -0
  8. proj_flow/ext/webidl/base/config.py +425 -0
  9. proj_flow/ext/webidl/cli/__init__.py +10 -0
  10. proj_flow/ext/webidl/cli/cmake.py +82 -0
  11. proj_flow/ext/webidl/cli/depfile.py +83 -0
  12. proj_flow/ext/webidl/cli/gen.py +157 -0
  13. proj_flow/ext/webidl/cli/init.py +26 -0
  14. proj_flow/ext/webidl/cli/root.py +12 -0
  15. proj_flow/ext/webidl/cli/updater.py +20 -0
  16. proj_flow/ext/webidl/data/init/flow_webidl.cmake +26 -0
  17. proj_flow/ext/webidl/data/templates/cmake.mustache +45 -0
  18. proj_flow/ext/webidl/data/templates/depfile.mustache +6 -0
  19. proj_flow/ext/webidl/data/templates/partials/cxx/attribute-decl.mustache +1 -0
  20. proj_flow/ext/webidl/data/templates/partials/cxx/in-out.mustache +2 -0
  21. proj_flow/ext/webidl/data/templates/partials/cxx/includes.mustache +6 -0
  22. proj_flow/ext/webidl/data/templates/partials/cxx/operation-decl.mustache +12 -0
  23. proj_flow/ext/webidl/data/templates/partials/cxx/type.mustache +6 -0
  24. proj_flow/ext/webidl/data/types/cxx.json +47 -0
  25. proj_flow/ext/webidl/model/__init__.py +2 -0
  26. proj_flow/ext/webidl/model/ast.py +586 -0
  27. proj_flow/ext/webidl/model/builders.py +230 -0
  28. proj_flow/ext/webidl/registry.py +23 -0
  29. {proj_flow-0.18.0.dist-info → proj_flow-0.20.0.dist-info}/METADATA +2 -1
  30. {proj_flow-0.18.0.dist-info → proj_flow-0.20.0.dist-info}/RECORD +33 -7
  31. {proj_flow-0.18.0.dist-info → proj_flow-0.20.0.dist-info}/WHEEL +0 -0
  32. {proj_flow-0.18.0.dist-info → proj_flow-0.20.0.dist-info}/entry_points.txt +0 -0
  33. {proj_flow-0.18.0.dist-info → proj_flow-0.20.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,230 @@
1
+ # Copyright (c) 2026 Marcin Zdun
2
+ # This code is licensed under MIT license (see LICENSE for details)
3
+
4
+
5
+ import copy
6
+ import json
7
+ from dataclasses import dataclass, field
8
+ from pathlib import Path
9
+ from typing import Any, Callable, cast
10
+
11
+ from pywebidl2 import expr
12
+
13
+ package_root = Path(__file__).parent.parent
14
+
15
+ TR = list[str] | str | None
16
+
17
+
18
+ @dataclass
19
+ class TypeReplacement:
20
+ name: str
21
+ module_or_include: str | None = None
22
+
23
+ @staticmethod
24
+ def load_config(lang: str | None, types: Path | None):
25
+ data = {}
26
+ if lang:
27
+ path = package_root / "data" / "types" / f"{lang}.json"
28
+ with path.open(encoding="utf-8") as lang_file:
29
+ data.update(cast(dict, json.load(lang_file)))
30
+
31
+ if types:
32
+ with types.open(encoding="utf-8") as lang_file:
33
+ all_types_data = cast(dict[str, dict], json.load(lang_file))
34
+ if lang:
35
+ data.update(all_types_data.get(lang, {}))
36
+ else:
37
+ data.update(all_types_data.get("", {}))
38
+
39
+ result: dict[str, TypeReplacement] = {}
40
+ for key, value in data.items():
41
+ if value is None:
42
+ result[key] = TypeReplacement(name=key)
43
+
44
+ elif isinstance(value, str):
45
+ result[key] = TypeReplacement(name=value)
46
+
47
+ elif isinstance(value, list) and len(value) == 2:
48
+ mod, name = value
49
+ if isinstance(name, str) and (mod is None or isinstance(mod, str)):
50
+ result[key] = TypeReplacement(name=name, module_or_include=mod)
51
+
52
+ return result
53
+
54
+
55
+ def visit_flag_extended_attribute(
56
+ name: str, bag: dict[str, Any], attributes: dict[str, expr.ExtendedAttribute]
57
+ ):
58
+ bag[name] = attributes.get(name) != None
59
+
60
+
61
+ def visit_string_extended_attribute(
62
+ name: str, bag: dict[str, Any], attributes: dict[str, expr.ExtendedAttribute]
63
+ ):
64
+ bag[name] = None
65
+ try:
66
+ attr = attributes[name]
67
+ except KeyError:
68
+ return
69
+
70
+ if attr.rhs:
71
+ bag[name] = cast(str, attr.rhs.value)
72
+
73
+
74
+ def flag_extended_attribute(name: str):
75
+ def impl(bag: dict[str, Any], attributes: dict[str, expr.ExtendedAttribute]):
76
+ return visit_flag_extended_attribute(name, bag, attributes)
77
+
78
+ return impl
79
+
80
+
81
+ def string_extended_attribute(name: str):
82
+ def impl(bag: dict[str, Any], attributes: dict[str, expr.ExtendedAttribute]):
83
+ return visit_string_extended_attribute(name, bag, attributes)
84
+
85
+ return impl
86
+
87
+
88
+ ATTR_TYPE = {
89
+ "bool": flag_extended_attribute,
90
+ "str": string_extended_attribute,
91
+ }
92
+
93
+ ExtAttrsVisitor = Callable[[dict[str, Any], dict[str, expr.ExtendedAttribute]], None]
94
+
95
+
96
+ @dataclass
97
+ class ExtAttrsContextBuilder:
98
+ visitors: dict[str, ExtAttrsVisitor] = field(default_factory=dict)
99
+ applies_to_type: bool = False
100
+
101
+ def add_flag(self, name: str):
102
+ self.visitors[name] = flag_extended_attribute(name)
103
+
104
+ def add_string(self, name: str):
105
+ self.visitors[name] = string_extended_attribute(name)
106
+
107
+ def visit(self, bag: dict[str, Any], attributes: dict[str, expr.ExtendedAttribute]):
108
+ for visitor in self.visitors.values():
109
+ visitor(bag, attributes)
110
+
111
+ def merge(self, rhs: "ExtAttrsContextBuilder"):
112
+ left = copy.deepcopy(self.visitors)
113
+ right = copy.deepcopy(rhs.visitors)
114
+ left.update(right)
115
+ return ExtAttrsContextBuilder(
116
+ visitors=left,
117
+ applies_to_type=self.applies_to_type,
118
+ )
119
+
120
+
121
+ class BuilderBuilder:
122
+ tgt: ExtAttrsContextBuilder
123
+
124
+ def __init__(self, applies_to_type: bool = False):
125
+ self.tgt = ExtAttrsContextBuilder(applies_to_type=applies_to_type)
126
+
127
+ def flag(self, name: str):
128
+ self.tgt.add_flag(name)
129
+ return self
130
+
131
+ def string(self, name: str):
132
+ self.tgt.add_string(name)
133
+ return self
134
+
135
+ def build(self):
136
+ return self.tgt
137
+
138
+
139
+ @dataclass
140
+ class ExtAttrsContextBuilders:
141
+ enum: ExtAttrsContextBuilder = field(default_factory=ExtAttrsContextBuilder)
142
+ interface: ExtAttrsContextBuilder = field(default_factory=ExtAttrsContextBuilder)
143
+ attribute: ExtAttrsContextBuilder = field(default_factory=ExtAttrsContextBuilder)
144
+ operation: ExtAttrsContextBuilder = field(default_factory=ExtAttrsContextBuilder)
145
+ return_type: ExtAttrsContextBuilder = field(default_factory=ExtAttrsContextBuilder)
146
+ argument: ExtAttrsContextBuilder = field(default_factory=ExtAttrsContextBuilder)
147
+ type: ExtAttrsContextBuilder = field(default_factory=ExtAttrsContextBuilder)
148
+
149
+ def from_idl(
150
+ self,
151
+ selector: Callable[["ExtAttrsContextBuilders"], ExtAttrsContextBuilder],
152
+ ext_attrs: list[expr.ExtendedAttribute],
153
+ ):
154
+ result: dict[str, Any] = {}
155
+ attributes = {attr.name: attr for attr in ext_attrs}
156
+ builder = selector(self)
157
+ builder.visit(result, attributes)
158
+ if builder.applies_to_type:
159
+ self.type.visit(result, attributes)
160
+ return result
161
+
162
+ def merge(self, rhs: "ExtAttrsContextBuilders"):
163
+ return ExtAttrsContextBuilders(
164
+ enum=self.enum.merge(rhs.enum),
165
+ interface=self.interface.merge(rhs.interface),
166
+ attribute=self.attribute.merge(rhs.attribute),
167
+ operation=self.operation.merge(rhs.operation),
168
+ return_type=self.return_type.merge(rhs.return_type),
169
+ argument=self.argument.merge(rhs.argument),
170
+ type=self.type.merge(rhs.type),
171
+ )
172
+
173
+ @staticmethod
174
+ def from_config(data: dict):
175
+ ext_attrs = cast(dict[str, dict[str, str]], data.get("ext_attrs", {}))
176
+ result = ExtAttrsContextBuilders()
177
+ targets = [
178
+ ("enum", result.enum),
179
+ ("interface", result.interface),
180
+ ("attribute", result.attribute),
181
+ ("operation", result.operation),
182
+ ("return_type", result.return_type),
183
+ ("argument", result.argument),
184
+ ]
185
+ for key, target in targets:
186
+ group = ext_attrs.get(key, {})
187
+ for name, type_name in group.items():
188
+ ctor = ATTR_TYPE.get(type_name)
189
+ if not ctor:
190
+ message = f"unknown user-defined extended attribute `{type_name}' when reading {key}.{name}"
191
+ raise RuntimeError(message)
192
+ target.visitors[name] = ctor(name)
193
+ return result
194
+
195
+ def property_fixup(self, type: dict[str, Any], parent: dict[str, Any]):
196
+ for key in self.type.visitors:
197
+ if key in parent:
198
+ value = parent[key]
199
+ del parent[key]
200
+ if isinstance(value, bool):
201
+ type[key] = cast(bool, type.get(key, False)) or value
202
+ continue
203
+
204
+ if isinstance(value, str):
205
+ type[key] = cast(str, type.get(key, False)) or value
206
+ continue
207
+
208
+ @staticmethod
209
+ def builtin():
210
+ return ExtAttrsContextBuilders(
211
+ attribute=BuilderBuilder().string("default").build(),
212
+ operation=BuilderBuilder()
213
+ .flag("in")
214
+ .flag("out")
215
+ .flag("mutable")
216
+ .flag("throws")
217
+ .build(),
218
+ argument=BuilderBuilder()
219
+ .flag("defaulted")
220
+ .string("default")
221
+ .flag("in")
222
+ .flag("out")
223
+ .build(),
224
+ type=BuilderBuilder()
225
+ .flag("unique")
226
+ .flag("span")
227
+ .flag("nullable")
228
+ .string("key")
229
+ .build(),
230
+ )
@@ -0,0 +1,23 @@
1
+ # Copyright (c) 2026 Marcin Zdun
2
+ # This code is licensed under MIT license (see LICENSE for details)
3
+
4
+ from abc import ABC
5
+ from typing import Any
6
+
7
+ from pywebidl2 import expr
8
+
9
+ from proj_flow.base.registry import Registry
10
+ from proj_flow.ext.webidl.model.ast import MergedDefinitions
11
+
12
+
13
+ class WebIDLVisitor(ABC):
14
+ def on_definitions(self, definitions: MergedDefinitions): ...
15
+
16
+
17
+ class WebIDLCustomExtAttr(ABC):
18
+ def on_attribute(
19
+ self, name: str, ext_attrs: expr.ExtendedAttribute, result: dict[str, Any]
20
+ ): ...
21
+
22
+
23
+ webidl_visitors = Registry[WebIDLVisitor]("WebIDLVisitor")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: proj-flow
3
- Version: 0.18.0
3
+ Version: 0.20.0
4
4
  Summary: C++ project maintenance, automated
5
5
  Project-URL: Changelog, https://github.com/mzdun/proj-flow/blob/main/CHANGELOG.rst
6
6
  Project-URL: Documentation, https://proj-flow.readthedocs.io/en/latest/
@@ -20,6 +20,7 @@ Requires-Python: >=3.10
20
20
  Requires-Dist: argcomplete
21
21
  Requires-Dist: chevron2021
22
22
  Requires-Dist: prompt-toolkit
23
+ Requires-Dist: pywebidl2
23
24
  Requires-Dist: pyyaml
24
25
  Requires-Dist: toml
25
26
  Description-Content-Type: text/markdown
@@ -1,4 +1,4 @@
1
- proj_flow/__init__.py,sha256=NKmPob4vpoR5qg9Iu-9Lgm4XUtGqoXzml3X0ANaL0IM,277
1
+ proj_flow/__init__.py,sha256=JbiePM36-RHE5KsHNVTeW0VHI6mPI0yAPfn8TEJwsXo,277
2
2
  proj_flow/__main__.py,sha256=HUar_qQ9Ndmchmryegtzu__5wukwCLrFN_SGRl5Ol_M,233
3
3
  proj_flow/dependency.py,sha256=CpcnR6El8AO9hlLc9lQtYQADYlkx3GMHlkLYbEAtdMI,4639
4
4
  proj_flow/api/__init__.py,sha256=gV2f6kll_5JXtvkGASvnx7CbOWr34PHOdck-4ce-qEk,378
@@ -7,7 +7,7 @@ proj_flow/api/completers.py,sha256=NapNVu6QAQ_iF6dqcAzOV5kDHKD9MAMVX209Bklq-Mw,2
7
7
  proj_flow/api/ctx.py,sha256=IJu0q0Chivo6b2M4MKkAlV09oi7Cn9VxtDFeAeL_tnc,6646
8
8
  proj_flow/api/env.py,sha256=rbNtMB6bBRhUb6bolNduWVWZ7a5CIsnv8EEZsamT9Ek,12678
9
9
  proj_flow/api/init.py,sha256=p4ZDGfq6fw4bXbJu2iq0vEmVxbS7nALIhZfe-XnEs44,565
10
- proj_flow/api/makefile.py,sha256=AxtGOvmypBtSvoyMEDJq1bGoaVD5yW9YYRZSdunUEeg,3856
10
+ proj_flow/api/makefile.py,sha256=q0fBSsWTWfR5YwunwiRjWJKtiLeHdSKUgUTEgo5I7dE,3863
11
11
  proj_flow/api/release.py,sha256=IM4axJ6dfyilCmpwL_Z8q43XGKsfHaPoMAdqSziwT7s,2810
12
12
  proj_flow/api/step.py,sha256=C6LfjAN5edYjlpkhd6k9eMO9SLfLtyS2ZG1Rg_dLcjg,4926
13
13
  proj_flow/base/__cmake_version__.py,sha256=imja0GnhpBvS8Crz-64eOUKhc4i6FeRrjBGRB68x_p0,239
@@ -46,6 +46,32 @@ proj_flow/ext/python/version.py,sha256=pnyuKATyZwBh1p0gf9KmqbRSZx8hJ5285CiFK_tHE
46
46
  proj_flow/ext/sign/__init__.py,sha256=b9AN1_BalPtVy7YLBjvGhLamTujHEKcZP7npgDDDuSI,4296
47
47
  proj_flow/ext/sign/api.py,sha256=l5SO5RHiHTwxg0aexkGOfApRdojWDcIBY_cfbKSKsC0,2286
48
48
  proj_flow/ext/sign/win32.py,sha256=yMAmO-DdIWZdOi_NxycRym8XM9WIsrWKtFANdIwthJ4,4968
49
+ proj_flow/ext/tools/__init__.py,sha256=m9iJeCkdmrqLjBWNx9hp4o1H2kgzIXpgypHiSf3SzKE,373
50
+ proj_flow/ext/tools/pragma_once.py,sha256=BiNvX5X5pX_bGPZwBaKISlL6KkxJJGWFeZGSO-UDAgo,1218
51
+ proj_flow/ext/tools/run_linter.py,sha256=_EdmTfITc_hwI5hgMc_mKFkbw4unnDGkWaFohs0RDr4,6145
52
+ proj_flow/ext/webidl/__init__.py,sha256=StPcfYM0l6Q3QNoXj5DfDpes6WwvhgfNnARQlhEoZco,316
53
+ proj_flow/ext/webidl/registry.py,sha256=x-UeflSrbUBMCH0nTSjpHisSnxZkQUNWfyXoSlDcavA,585
54
+ proj_flow/ext/webidl/base/__init__.py,sha256=VJs_ODnF7-8DE0MbYKX-Bs-JDNqHgGdMkk2w142bcYQ,101
55
+ proj_flow/ext/webidl/base/config.py,sha256=0r_E6NQldQJZXwL1FrU49WbIE6-y8T9O25mxv0UFgyU,13489
56
+ proj_flow/ext/webidl/cli/__init__.py,sha256=MBNjnuj5X4X-ich2zez3aQTqvEImFwN3nFJPm6SwhdI,402
57
+ proj_flow/ext/webidl/cli/cmake.py,sha256=ytK_eafS6lkH-6xv3LNGGCQ0TO0_hPtDiCQq4msqEP0,2446
58
+ proj_flow/ext/webidl/cli/depfile.py,sha256=XQdPDmxFSSRtm6uUNbX8lleTPXDWbGY-0UQn9jx6Tok,2442
59
+ proj_flow/ext/webidl/cli/gen.py,sha256=zwFVjxFudqADwSJHrjkmoFqSa5eE2-FT2fb_mqedtQM,5468
60
+ proj_flow/ext/webidl/cli/init.py,sha256=zYd1ElULZt_5nJEhvXAKQLQgRCQFSTk8RCKOHCLz1_U,841
61
+ proj_flow/ext/webidl/cli/root.py,sha256=wPznV0XU0UQ2dXrbfP7t5_6v4Uam1R3S0f0xESj_Zns,300
62
+ proj_flow/ext/webidl/cli/updater.py,sha256=usRfIsKkjN4x1FvYMna0EcdJuJha2lkBxQsCR7dF0NU,541
63
+ proj_flow/ext/webidl/data/init/flow_webidl.cmake,sha256=EBqToWUDex1HIcwFKyEo4AkGWORtRUGJd0Z2APIrcN8,876
64
+ proj_flow/ext/webidl/data/templates/cmake.mustache,sha256=tmi7AnnmosDmrPqgL52shkcRCIbs2Ze1fi9NZ8D9NpQ,1205
65
+ proj_flow/ext/webidl/data/templates/depfile.mustache,sha256=rdynmTyn1HhIZCZ9LYfnbkOCJNASeZHlKFfrU4BuaTY,108
66
+ proj_flow/ext/webidl/data/templates/partials/cxx/attribute-decl.mustache,sha256=lbH_9vRK9FuHSx25ScC9F3n11SEGHLwzkKaZpaijNnM,120
67
+ proj_flow/ext/webidl/data/templates/partials/cxx/in-out.mustache,sha256=92Zf2jVQ5LhYRCTt-zpQ9F_cPrrWCnBtIOczj8ZUxAs,120
68
+ proj_flow/ext/webidl/data/templates/partials/cxx/includes.mustache,sha256=FNQ6JRifRJQlpHdQX6NTpI_XTIvtNRLusVlimz18jl0,129
69
+ proj_flow/ext/webidl/data/templates/partials/cxx/operation-decl.mustache,sha256=-g46nh8AGfJwDDl3z0vSvsKmkz8-zbAZy8--jp4K_X4,588
70
+ proj_flow/ext/webidl/data/templates/partials/cxx/type.mustache,sha256=Oc6Dds-Waybwp_uch7Xk373I6VSdBClYfP5Pj4yRHBU,250
71
+ proj_flow/ext/webidl/data/types/cxx.json,sha256=f31q4U2hQIf4RwZylRK__MZroRQKbbQDjud2rwMf2eM,1545
72
+ proj_flow/ext/webidl/model/__init__.py,sha256=VJs_ODnF7-8DE0MbYKX-Bs-JDNqHgGdMkk2w142bcYQ,101
73
+ proj_flow/ext/webidl/model/ast.py,sha256=_CzJPAarYruonVbK6mxfUc7MgFoxFDpXWjX4OEkOp3M,19238
74
+ proj_flow/ext/webidl/model/builders.py,sha256=7MpSJm9NflY1rDbK8msWuKkq3X5jWzUEFCHytOZeKCY,7534
49
75
  proj_flow/flow/__init__.py,sha256=5Zo97zJsR7HMbl64jeMB9PbUuxCxpOlNuLmo3apWSVU,277
50
76
  proj_flow/flow/configs.py,sha256=PQZ5pLPmWwHJtSWmuy04bsnO-VvfWcJyP_UyKjiaG1g,6535
51
77
  proj_flow/flow/layer.py,sha256=IUANtCSOvlfzNSnq0VDdGdaXfB70Yr-rDGFxPDQTmpg,6187
@@ -134,8 +160,8 @@ proj_flow/template/licenses/MIT.mustache,sha256=NncPoQaNsuy-WmRmboik3fyhJJ8m5pc2
134
160
  proj_flow/template/licenses/Unlicense.mustache,sha256=awOCsWJ58m_2kBQwBUGWejVqZm6wuRtCL2hi9rfa0X4,1211
135
161
  proj_flow/template/licenses/WTFPL.mustache,sha256=lvF4V_PrKKfZPa2TC8CZo8tlqaKvs3Bpv9G6XsWWQ4k,483
136
162
  proj_flow/template/licenses/Zlib.mustache,sha256=uIj-mhSjes2HJ3rRapyy2ALflKRz4xQgS4mVM9827C0,868
137
- proj_flow-0.18.0.dist-info/METADATA,sha256=RtXLpv1l2n0-RHGb0o9QHJpG0TFYfo5htPhxYUYNTVE,2980
138
- proj_flow-0.18.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
139
- proj_flow-0.18.0.dist-info/entry_points.txt,sha256=d_OmGKZzpY7FCWz0sZ4wnBAPZC75oMEzTgJZWtpDELo,49
140
- proj_flow-0.18.0.dist-info/licenses/LICENSE,sha256=vpOQJ5QlrTedF3coEWvA4wJzVJH304f66ZitR7Od4iU,1068
141
- proj_flow-0.18.0.dist-info/RECORD,,
163
+ proj_flow-0.20.0.dist-info/METADATA,sha256=1LA8i5cUZclr3qRQEW9fo7XDmBB0_wgSiVJ39Vyn5BI,3005
164
+ proj_flow-0.20.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
165
+ proj_flow-0.20.0.dist-info/entry_points.txt,sha256=d_OmGKZzpY7FCWz0sZ4wnBAPZC75oMEzTgJZWtpDELo,49
166
+ proj_flow-0.20.0.dist-info/licenses/LICENSE,sha256=vpOQJ5QlrTedF3coEWvA4wJzVJH304f66ZitR7Od4iU,1068
167
+ proj_flow-0.20.0.dist-info/RECORD,,