|
| 1 | +"""Collapse redocly's file-named components into the names declared in openapi.yaml.""" |
| 2 | +import json, re, sys |
| 3 | +src, out = sys.argv[1], sys.argv[2] |
| 4 | +d = json.load(open(src)) |
| 5 | +s = d['components']['schemas'] |
| 6 | +P = '#/components/schemas/' |
| 7 | +rename = {} |
| 8 | +# 1. declared alias X -> {$ref: P+F}: move F's body into X |
| 9 | +for k, v in list(s.items()): |
| 10 | + if '.' not in k and isinstance(v, dict) and list(v) == ['$ref'] and v['$ref'].startswith(P): |
| 11 | + f = v['$ref'][len(P):] |
| 12 | + if '.' in f and f not in rename: |
| 13 | + rename[f] = k |
| 14 | +# 2. remaining file-named components get a PascalCase name |
| 15 | +def pascal(f): |
| 16 | + stem = f.removesuffix('.schema') |
| 17 | + return ''.join(w[:1].upper() + w[1:] for w in re.split(r'[-_.]', stem)) |
| 18 | +for k in list(s): |
| 19 | + if '.' in k and k not in rename: |
| 20 | + n = pascal(k) |
| 21 | + assert n not in s and n not in rename.values(), (k, n) |
| 22 | + rename[k] = n |
| 23 | +def walk(o): |
| 24 | + if isinstance(o, dict): |
| 25 | + for key, v in list(o.items()): |
| 26 | + if isinstance(v, str) and v.startswith(P) and v[len(P):] in rename: |
| 27 | + o[key] = P + rename[v[len(P):]] |
| 28 | + else: |
| 29 | + walk(v) |
| 30 | + elif isinstance(o, list): |
| 31 | + for v in o: walk(v) |
| 32 | +new = {} |
| 33 | +for k, v in s.items(): |
| 34 | + if k in rename: continue |
| 35 | + if k in rename.values() and isinstance(v, dict) and list(v) == ['$ref']: |
| 36 | + f = v['$ref'][len(P):]; new[k] = s[f]; continue |
| 37 | + new[k] = v |
| 38 | +for f, n in rename.items(): |
| 39 | + if n not in new: new[n] = s[f] |
| 40 | +d['components']['schemas'] = new |
| 41 | +walk(d) |
| 42 | +txt = json.dumps(d) |
| 43 | +left = re.findall(r'#/components/schemas/([A-Za-z0-9_.-]+)', txt) |
| 44 | +assert not [x for x in left if x not in new], set(x for x in left if x not in new) |
| 45 | +assert not [k for k in new if '.' in k] |
| 46 | +json.dump(d, open(out, 'w'), indent=2) |
| 47 | +print(len(s), '->', len(new), 'schemas;', len([r for r in rename.values() if r not in s]), 'new names:', sorted(r for r in rename.values() if r not in s)) |
0 commit comments