From 2f2b83c132de28f518be2eaca3fb7720f88c1e38 Mon Sep 17 00:00:00 2001 From: podhmo Date: Sun, 27 Nov 2016 00:38:36 +0900 Subject: [PATCH] with deref, not expanded as possible --- Makefile | 4 ++- example5.rst | 22 ++++++++++--- examples/deref/main.yaml | 6 +++- examples/deref/swagger-bundler.ini | 4 +-- examples/swagger-bundler.ini | 2 +- swagger_bundler/context.py | 5 ++- swagger_bundler/langhelpers.py | 18 ++++++++++- swagger_bundler/postscript.py | 52 ++++++++++++++++++++++-------- 8 files changed, 89 insertions(+), 24 deletions(-) diff --git a/Makefile b/Makefile index 5788f0b..86c74f5 100644 --- a/Makefile +++ b/Makefile @@ -130,5 +130,7 @@ example5: cat .tmp/03* | gsed 's/^/ /g' >> example5.rst rm -r .tmp -.PHONY: example +examples: example example2 example3 example4 example5 + +.PHONY: examples .PHONY: watch updatespec test regenerate diff --git a/example5.rst b/example5.rst index 1333864..f1e7dfd 100644 --- a/example5.rst +++ b/example5.rst @@ -36,10 +36,10 @@ # or # a/b/c/d.py:function_name compose = - bundle = + bundle = swagger_bundler.postscript:deref_support_for_extra_file add_namespace = validate = - load = swagger_bundler.postscript:deref_support_for_extra_file + load = @@ -93,10 +93,14 @@ deref/main.yaml - x.yaml as X definitions: - foo: + group: $ref: "./group/group.yaml#/definitions/group" color: $ref: "group/group.yaml#/definitions/color" + rgb: + $ref: "color/rgb.yaml#/definitions/color" + cmyk: + $ref: "color/cmyk.yaml#/definitions/color" deref/x.yaml @@ -120,7 +124,7 @@ deref/x.yaml - M - Y - K - foo: + group: type: string enum: - A @@ -132,3 +136,13 @@ deref/x.yaml - r - g - b + rgb: + $ref: '#/definitions/color' + cmyk: + x-conflicted: color/cmyk.yaml#/definitions/color + type: string + enum: + - C + - M + - Y + - K diff --git a/examples/deref/main.yaml b/examples/deref/main.yaml index aa34a2d..f5c4286 100644 --- a/examples/deref/main.yaml +++ b/examples/deref/main.yaml @@ -2,7 +2,11 @@ x-bundler-compose: - x.yaml as X definitions: - foo: + group: $ref: "./group/group.yaml#/definitions/group" color: $ref: "group/group.yaml#/definitions/color" + rgb: + $ref: "color/rgb.yaml#/definitions/color" + cmyk: + $ref: "color/cmyk.yaml#/definitions/color" diff --git a/examples/deref/swagger-bundler.ini b/examples/deref/swagger-bundler.ini index be4faa4..550ae89 100644 --- a/examples/deref/swagger-bundler.ini +++ b/examples/deref/swagger-bundler.ini @@ -14,7 +14,7 @@ exposed = x-bundler-exposed # or # a/b/c/d.py:function_name compose = -bundle = +bundle = swagger_bundler.postscript:deref_support_for_extra_file add_namespace = validate = -load = swagger_bundler.postscript:deref_support_for_extra_file \ No newline at end of file +load = \ No newline at end of file diff --git a/examples/swagger-bundler.ini b/examples/swagger-bundler.ini index 081a8d8..d857365 100644 --- a/examples/swagger-bundler.ini +++ b/examples/swagger-bundler.ini @@ -14,6 +14,6 @@ exposed = x-bundler-exposed # or # a/b/c/d.py:function_name compose = -bundle = +bundle = swagger_bundler.postscript:deref_support_for_extra_file add_namespace = validate = diff --git a/swagger_bundler/context.py b/swagger_bundler/context.py index fe49eba..9b29e5c 100644 --- a/swagger_bundler/context.py +++ b/swagger_bundler/context.py @@ -182,6 +182,10 @@ def options(self): def identifier(self): return self.resolver.identifier + @property + def ns(self): + return self.resolver.ns + def _on_load_failure(self, src, e=None): if e is not None: sys.stderr.write("{}: {}\n".format(type(e), e)) @@ -229,7 +233,6 @@ def make_subcontext(self, src, data=None): exposed_list = subcontext.detector.detect_exposed() new_compose_target_list = [c for c in subcontext.detector.detect_compose() if c in exposed_list] subcontext.detector.update_compose(new_compose_target_list) - return subcontext def make_subcontext_from_port(self, port): diff --git a/swagger_bundler/langhelpers.py b/swagger_bundler/langhelpers.py index 73dd49c..0e584d1 100644 --- a/swagger_bundler/langhelpers.py +++ b/swagger_bundler/langhelpers.py @@ -4,4 +4,20 @@ def titleize(s): if not s: return s else: - return "{}{}".format(s[0].title(), s[1:]) + return "{}{}".format(s[0].upper(), s[1:]) + + +def untitlize(s): + """FooBar -> fooBar""" + if not s: + return s + else: + return "{}{}".format(s[0].lower(), s[1:]) + + +def guess_name(s, ns): + yield s + if ns: + unprefixed = s[len(ns):] + yield unprefixed + yield untitlize(unprefixed) diff --git a/swagger_bundler/postscript.py b/swagger_bundler/postscript.py index ddd6e6f..372f12c 100644 --- a/swagger_bundler/postscript.py +++ b/swagger_bundler/postscript.py @@ -5,7 +5,7 @@ import copy from collections import deque from collections import OrderedDict -from .langhelpers import titleize +from .langhelpers import titleize, guess_name from . import highlight @@ -22,7 +22,7 @@ def echo(ctx, data, *args, **kwargs): _rx_cache = {} -def deref_support_for_extra_file(ctx, data, *args, targets=tuple(["definitions", "paths", "responses"]), **kwargs): +def deref_support_for_extra_file(ctx, rootdata, *args, targets=tuple(["definitions", "paths", "responses"]), **kwargs): cache_k = tuple(targets) if cache_k not in _rx_cache: _rx_cache[cache_k] = re.compile("#/({})/".format("|".join(targets))) @@ -33,39 +33,65 @@ def deref_support_for_extra_file(ctx, data, *args, targets=tuple(["definitions", # path :: (/)* # section :: 'definitions' | 'paths' | 'responses' - def deref(d, ctx, i): + def deref(d, ctx, paths): if "$ref" not in d: - return d, i + return d, paths try: m = separator_rx.search(d["$ref"]) if m is None: highlight.show_on_warning("invalid ref: {}\n".format(d["$ref"])) - return d, i + return d, paths # plain ref if m.start() == 0: - return d, i + return d, paths # with extra path path = d["$ref"][:m.start()] section = m.group(1) name = d["$ref"][m.end():] subctx = ctx.make_subcontext(path) - return deref(subctx.data[section][name], ctx=subctx, i=i + 1) + + # gueesing key (this is heuristic) + section_store = subctx.data[section] + for guessed in guess_name(name, subctx.ns): + if guessed in section_store: + paths.append((section, name)) + return deref(section_store[guessed], ctx=subctx, paths=paths) + highlight.show_on_warning("not found ref: {}\n".format(d["$ref"])) + return d, paths except (IndexError, ValueError) as e: highlight.show_on_warning(str(e)) def on_ref_found(d): - data, i = deref(d, ctx, 0) - if i > 0: - d.pop("$ref") - d.update(data) + data, paths = deref(d, ctx, []) + if paths: + original_ref = d.pop("$ref") + section, name = paths[-1] + + d["$ref"] = "#/{}/{}".format(section, name) + if section not in rootdata: + rootdata[section] = OrderedDict() + + if name not in rootdata[section]: + rootdata[section][name] = data + elif d == rootdata[section][name]: + d.pop("$ref") + d.update(data) + else: + refpath = "#/{}/{}".format(section, name) + if rootdata[section][name] != data: + d["x-conflicted"] = original_ref + msg = "{} is conflicted. (where file={!r} ref={!r})".format(refpath, ctx.path, original_ref) + highlight.show_on_warning(msg) + d.pop("$ref") + d.update(data) w = LooseDictWalker(on_container=on_ref_found) q = ["$ref"] for section in targets: - if section in data: - w.walk(q, data[section]) + if section in rootdata: + w.walk(q, rootdata[section]) def add_responses_default(ctx, data, *args, **kwargs):