Skip to content

Commit a2a279f

Browse files
committed
feat chaotic: allow object in root of file
1 parent 9140947 commit a2a279f

File tree

2 files changed

+64
-28
lines changed

2 files changed

+64
-28
lines changed

chaotic/chaotic/front/parser.py

+40-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import contextlib
33
import dataclasses
44
import os
5+
import re
56
from typing import Dict
67
from typing import Generator
78
from typing import List
@@ -13,6 +14,27 @@
1314
from chaotic.front import types
1415

1516

17+
@dataclasses.dataclass(init=False)
18+
class NameMapItem:
19+
pattern: re.Pattern
20+
dest: str # string for str.format()
21+
22+
def __init__(self, data: str):
23+
groups = data.split('=')
24+
if len(groups) != 2:
25+
raise Exception(f'-n arg must contain "=" ({data})')
26+
27+
pattern, dest = groups
28+
self.pattern = re.compile(pattern)
29+
self.dest = dest
30+
31+
def match(self, data: str) -> Optional[str]:
32+
match = self.pattern.fullmatch(data) # pylint: disable=no-member
33+
if match:
34+
return self.dest.format(*match.groups())
35+
return None
36+
37+
1638
@dataclasses.dataclass(frozen=True)
1739
class ParserConfig:
1840
erase_prefix: str
@@ -33,14 +55,17 @@ class ParserError(error.BaseError):
3355

3456
class SchemaParser:
3557
def __init__(
36-
self, *, config: ParserConfig, full_filepath: str, full_vfilepath: str,
58+
self, *, config: ParserConfig,
59+
full_filepath: str, full_vfilepath: str,
60+
plain_object_path_map: List[NameMapItem] = None,
3761
) -> None:
3862
self._config = config
3963
# Full filepath on real filesystem
4064
self.full_filepath: str = full_filepath
4165
# Full filepath on virtual filesystem, used by $ref
4266
self.full_vfilepath: str = full_vfilepath
4367
self._state = ParserState(infile_path='', schemas=dict())
68+
self._plain_object_path_map = plain_object_path_map
4469

4570
def parse_schema(self, infile_path: str, input__: dict) -> None:
4671
self._state.infile_path = ''
@@ -312,7 +337,20 @@ def _make_abs_ref(self, ref: str) -> str:
312337
return self.full_vfilepath + ref
313338
else:
314339
my_ref = '/'.join(self.full_vfilepath.split('/')[:-1])
315-
file, infile = ref.split('#')
340+
if '#' in ref:
341+
file, infile = ref.split('#')
342+
else:
343+
file = ref
344+
if file.startswith('./'):
345+
file = file[2:]
346+
347+
for item in self._plain_object_path_map:
348+
infile = item.match(ref)
349+
if infile is not None:
350+
infile = infile.rstrip('/')
351+
break
352+
if infile is None:
353+
self._raise(f'Invalid ref without in-file path')
316354
out_file = os.path.join(my_ref, file)
317355
# print(f'ref: {out_file} # {infile}')
318356
return out_file + '#' + infile

chaotic/chaotic/main.py

+24-26
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
11
import argparse
2-
import dataclasses
32
import os
43
import pathlib
5-
import re
64
import sys
75
from typing import Any
86
from typing import Callable
97
from typing import Dict
108
from typing import List
11-
from typing import Optional
129

1310
import yaml
1411

@@ -17,27 +14,7 @@
1714
from chaotic.front import parser as front_parser
1815
from chaotic.front import ref_resolver
1916
from chaotic.front import types
20-
21-
22-
@dataclasses.dataclass(init=False)
23-
class NameMapItem:
24-
pattern: re.Pattern
25-
dest: str # string for str.format()
26-
27-
def __init__(self, data: str):
28-
groups = data.split('=')
29-
if len(groups) != 2:
30-
raise Exception(f'-n arg must contain "=" ({data})')
31-
32-
pattern, dest = groups
33-
self.pattern = re.compile(pattern)
34-
self.dest = dest
35-
36-
def match(self, data: str) -> Optional[str]:
37-
match = self.pattern.fullmatch(data) # pylint: disable=no-member
38-
if match:
39-
return self.dest.format(*match.groups())
40-
return None
17+
from chaotic.front.parser import NameMapItem
4118

4219

4320
def parse_args() -> argparse.Namespace:
@@ -60,6 +37,13 @@ def parse_args() -> argparse.Namespace:
6037
help='full filepath to virtual filepath mapping',
6138
)
6239

40+
parser.add_argument(
41+
'--plain-object-path-map',
42+
type=NameMapItem,
43+
action='append',
44+
help='plain object filepath to in-file path',
45+
)
46+
6347
parser.add_argument(
6448
'-u',
6549
'--userver',
@@ -174,9 +158,17 @@ def traverse_dfs(path: str, data: Any):
174158

175159
def extract_schemas_to_scan(
176160
inp: dict, name_map: List[NameMapItem],
161+
fname: str, plain_object_path_map: List[NameMapItem],
177162
) -> Dict[str, Any]:
178163
schemas = []
179164

165+
if plain_object_path_map is not None and ('type' in inp) and inp['type'] == 'object':
166+
for item in plain_object_path_map:
167+
path = item.match(fname)
168+
if path is not None:
169+
schemas.append((path, inp))
170+
return dict(schemas)
171+
180172
gen = traverse_dfs('/', inp)
181173
ok_ = None
182174
while True:
@@ -201,6 +193,7 @@ def read_schemas(
201193
name_map,
202194
file_map,
203195
dependencies: List[types.ResolvedSchemas] = [],
196+
plain_object_path_map: List[NameMapItem] = None,
204197
) -> types.ResolvedSchemas:
205198
config = front_parser.ParserConfig(erase_prefix=erase_path_prefix)
206199
rr = ref_resolver.RefResolver()
@@ -210,11 +203,12 @@ def read_schemas(
210203
with open(fname) as ifile:
211204
data = yaml.load(ifile, Loader=yaml.CLoader)
212205

213-
scan_objects = extract_schemas_to_scan(data, name_map)
206+
scan_objects = extract_schemas_to_scan(data, name_map, fname, plain_object_path_map)
214207

215208
vfilepath = vfilepath_from_filepath(fname, file_map)
216209
parser = front_parser.SchemaParser(
217210
config=config, full_filepath=fname, full_vfilepath=vfilepath,
211+
plain_object_path_map=plain_object_path_map,
218212
)
219213
for path, obj in rr.sort_json_types(
220214
scan_objects, erase_path_prefix,
@@ -246,7 +240,11 @@ def main() -> None:
246240
args = parse_args()
247241

248242
schemas = read_schemas(
249-
args.erase_path_prefix, args.file, args.name_map, args.file_map,
243+
erase_path_prefix=args.erase_path_prefix,
244+
filepaths=args.file,
245+
name_map=args.name_map,
246+
file_map=args.file_map,
247+
plain_object_path_map=args.plain_object_path_map,
250248
)
251249
cpp_name_func = generate_cpp_name_func(
252250
args.name_map, args.erase_path_prefix,

0 commit comments

Comments
 (0)