mirror of
https://github.com/thegeneralist01/twitter-openapi
synced 2026-01-11 15:40:26 +01:00
update builder
Signed-off-by: ふぁ <yuki@yuki0311.com>
This commit is contained in:
parent
c22926614e
commit
3419b5c0ab
19 changed files with 539 additions and 480 deletions
212
tools/build.py
212
tools/build.py
|
|
@ -5,205 +5,55 @@ import yaml
|
|||
import shutil
|
||||
import copy
|
||||
import re
|
||||
|
||||
|
||||
class placeholder_manager:
|
||||
data: dict
|
||||
config: str = "src/config/placeholder.json"
|
||||
|
||||
def __init__(self):
|
||||
with open(self.config, mode="r", encoding="utf-8") as f:
|
||||
self.data = json.load(f)
|
||||
|
||||
def __replace(self, file, old: str, new) -> str:
|
||||
if type(new) is dict:
|
||||
dump = f"'{json.dumps(new)}'"
|
||||
return file.replace(f'"{old}"', dump)
|
||||
else:
|
||||
return file.replace(f"{old}", new)
|
||||
|
||||
def replace(self, file: str) -> str:
|
||||
for prefix in self.data.keys():
|
||||
for key in self.data[prefix]:
|
||||
value = self.data[prefix][key]
|
||||
file = self.__replace(file, f"{{{{{prefix}{key}}}}}", value)
|
||||
return file
|
||||
|
||||
def replace_file(self, file: str, prefix: str) -> str:
|
||||
if self.data.get(prefix, None) is None:
|
||||
return file
|
||||
for key in self.data[prefix].keys():
|
||||
value = self.data[prefix][key]
|
||||
file = self.__replace(file, f"{{{{{key}}}}}", value)
|
||||
return file
|
||||
|
||||
|
||||
def placeholder_to_yaml(obj):
|
||||
if type(obj) is dict:
|
||||
return {
|
||||
"type": "object",
|
||||
"required": [i for i in obj],
|
||||
"properties": {i: placeholder_to_yaml(obj[i]) for i in obj},
|
||||
# "default": {i: placeholder_to_yaml(obj[i]) for i in obj},
|
||||
# "example": {i: placeholder_to_yaml(obj[i]) for i in obj},
|
||||
}
|
||||
elif type(obj) is list:
|
||||
if len(obj) == 0:
|
||||
return {
|
||||
"type": "array",
|
||||
"items": {"type": "object"},
|
||||
# "default": [],
|
||||
# "example": [],
|
||||
}
|
||||
return {
|
||||
"type": "array",
|
||||
"items": placeholder_to_yaml(obj[0]),
|
||||
# "default": placeholder_to_yaml(obj[0]),
|
||||
# "example": placeholder_to_yaml(obj[0]),
|
||||
}
|
||||
elif type(obj) is str:
|
||||
return {"type": "string", "example": obj, "default": obj}
|
||||
elif type(obj) is bool:
|
||||
return {"type": "boolean", "example": obj, "default": obj}
|
||||
elif type(obj) is int:
|
||||
return {"type": "integer", "example": obj, "default": obj}
|
||||
from build_config import Config
|
||||
|
||||
|
||||
print("=== Build Start ===")
|
||||
OUTPUT_DIR = "dist/{0}"
|
||||
INPUT_DIR = "src/openapi"
|
||||
METHODS = ["get", "put", "post", "delete", "options", "head", "patch", "trace"]
|
||||
|
||||
|
||||
config = Config()
|
||||
|
||||
|
||||
try:
|
||||
shutil.rmtree("dist")
|
||||
except:
|
||||
pass
|
||||
|
||||
with open("src/config/variable.json", mode="r", encoding="utf-8") as f:
|
||||
variable = json.load(f)
|
||||
for lang in config.main().keys():
|
||||
dist_replace = lambda x: x.replace(
|
||||
config.INPUT_DIR, config.OUTPUT_DIR.format(lang), 1
|
||||
)
|
||||
|
||||
|
||||
placeholder = placeholder_manager()
|
||||
|
||||
for lang in variable.keys():
|
||||
|
||||
def read(file: str):
|
||||
with open(file, mode="r", encoding="utf-8") as f:
|
||||
return remove(f.read())
|
||||
|
||||
def write(file: str, data: str) -> None:
|
||||
with open(
|
||||
file.replace(INPUT_DIR, OUTPUT_DIR.format(lang), 1),
|
||||
mode="w+",
|
||||
encoding="utf-8",
|
||||
) as f:
|
||||
f.write(data)
|
||||
|
||||
def get_yaml(data, key):
|
||||
return yaml.safe_load(placeholder.replace_file(str(data), key))
|
||||
|
||||
def remove(data):
|
||||
for match in re.findall(r"(\{% (.*?) %\})", data):
|
||||
equation = match[1].split(" ")
|
||||
if equation[0] == "if" and equation[2] == "==":
|
||||
if equation[3] != variable[lang][equation[1]]:
|
||||
data = re.sub(
|
||||
re.escape(match[0]) + "[\s\S]*?" + re.escape("{% endif %}"),
|
||||
"",
|
||||
data,
|
||||
)
|
||||
|
||||
return data
|
||||
|
||||
for dir in glob.glob(os.path.join(INPUT_DIR, "**/")):
|
||||
os.makedirs(dir.replace(INPUT_DIR, OUTPUT_DIR.format(lang), 1), exist_ok=True)
|
||||
|
||||
parameters = read("src/config/parameters.yaml")
|
||||
header = read("src/config/header.yaml")
|
||||
for dir in glob.glob(os.path.join(config.INPUT_DIR, "**/")):
|
||||
os.makedirs(dist_replace(dir), exist_ok=True)
|
||||
|
||||
paths = {}
|
||||
for file in glob.glob(os.path.join(INPUT_DIR, "**/*.yaml")):
|
||||
for file in glob.glob(os.path.join(config.INPUT_DIR, "**/*.yaml")):
|
||||
file = file.replace(os.path.sep, "/")
|
||||
relative = file.replace(INPUT_DIR, "", 1)
|
||||
with open(file, mode="r", encoding="utf-8") as f:
|
||||
load = yaml.safe_load(f)
|
||||
for path in list(load["paths"]):
|
||||
for method in list(load["paths"][path]):
|
||||
for tag in list(load["paths"][path][method].get("tags", ["default"])):
|
||||
key, value = path, load["paths"][path][method]
|
||||
for hook in config.main()[lang]["request"][tag]:
|
||||
key, value = hook.hook(key, value)
|
||||
load["paths"][path][method] = value
|
||||
load["paths"][key] = load["paths"].pop(path)
|
||||
|
||||
load = yaml.safe_load(placeholder.replace(read(file)))
|
||||
escape = path.replace("/", "~1")
|
||||
relative = file.replace(config.INPUT_DIR, "", 1)
|
||||
paths.update({key: {"$ref": f".{relative}#/paths/{escape}"}})
|
||||
|
||||
for key in load["paths"].keys():
|
||||
append = get_yaml(parameters, key.split("/")[-1])
|
||||
param = append["paths"]["/parameters"]
|
||||
for method in load["paths"][key].keys():
|
||||
req = load["paths"][key][method]
|
||||
|
||||
req["parameters"] = req.get("parameters", [])
|
||||
req["parameters"] += param[method].get("parameters", [])
|
||||
|
||||
if param[method].get("requestBody") is not None:
|
||||
req["requestBody"] = param[method].get("requestBody")
|
||||
|
||||
if variable[lang].get(method + "_parameters") == "schema_content":
|
||||
for p_key in placeholder.data[key.split("/")[-1]].keys():
|
||||
if p_key.lower() == "query":
|
||||
continue
|
||||
req["parameters"].append(
|
||||
{
|
||||
"name": p_key.lower(),
|
||||
"in": "query",
|
||||
"required": True,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": placeholder_to_yaml(
|
||||
placeholder.data[key.split("/")[-1]][p_key]
|
||||
),
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
if variable[lang].get(method + "_parameters") == "schema_parameters":
|
||||
for p_key in placeholder.data[key.split("/")[-1]].keys():
|
||||
if p_key.lower() == "query":
|
||||
continue
|
||||
req["parameters"].append(
|
||||
{
|
||||
"name": p_key.lower(),
|
||||
"in": "query",
|
||||
"required": True,
|
||||
"schema": placeholder_to_yaml(
|
||||
placeholder.data[key.split("/")[-1]][p_key]
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
if variable[lang].get(method + "_parameters") == "schema_request_body":
|
||||
data = placeholder.data[key.split("/")[-1]]
|
||||
schema = {i: placeholder_to_yaml(data[i]) for i in data.keys()}
|
||||
|
||||
req["requestBody"] = {
|
||||
"description": key.split("/")[-1] + "body",
|
||||
"required": True,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"properties": schema,
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
append = get_yaml(header, key.split("/")[-1])
|
||||
req = load["paths"][key][method]
|
||||
req["responses"]["200"]["headers"] = append["components"]["headers"]
|
||||
|
||||
escape = key.replace("/", "~1")
|
||||
paths.update({key: {"$ref": f".{relative}#/paths/{escape}"}})
|
||||
write(file, yaml.dump(load))
|
||||
with open(dist_replace(file), mode="w+", encoding="utf-8") as f:
|
||||
f.write(yaml.dump(load))
|
||||
|
||||
file = "src/openapi/openapi-3.0.yaml"
|
||||
data = read(file)
|
||||
with open(file, mode="r", encoding="utf-8") as f:
|
||||
openapi = yaml.safe_load(f)
|
||||
for path in paths:
|
||||
load = yaml.safe_load(placeholder.replace(data))
|
||||
load["paths"] = paths
|
||||
|
||||
write(file, yaml.dump(load))
|
||||
with open(dist_replace(file), mode="w+", encoding="utf-8") as f:
|
||||
f.write(yaml.dump(load))
|
||||
|
||||
print("=== Build End ===")
|
||||
|
|
|
|||
111
tools/build_config.py
Normal file
111
tools/build_config.py
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
from hooks import *
|
||||
|
||||
|
||||
class Config:
|
||||
OUTPUT_DIR = "dist/{0}"
|
||||
INPUT_DIR = "src/openapi"
|
||||
|
||||
def main(self):
|
||||
return {
|
||||
"docs": {
|
||||
"openapi": [AddSecuritySchemesOnSecuritySchemes()],
|
||||
"request": {
|
||||
key: [
|
||||
ReplaceQueryIdPlaceholder(),
|
||||
SetResponsesHeader(),
|
||||
AddParametersOnContent(),
|
||||
]
|
||||
for key in ["default", "user", "userList", "tweet"]
|
||||
}
|
||||
| {
|
||||
"post": [
|
||||
ReplaceQueryIdPlaceholder(),
|
||||
SetResponsesHeader(),
|
||||
AddParametersOnParameters(),
|
||||
],
|
||||
"v1.1": [SetResponsesHeader()],
|
||||
},
|
||||
},
|
||||
"dart": {
|
||||
"openapi": [],
|
||||
"request": {
|
||||
key: [
|
||||
ReplaceQueryIdPlaceholder(),
|
||||
AddSecuritySchemesOnHeader(),
|
||||
SetResponsesHeader(),
|
||||
AddParametersOnParametersAsString(),
|
||||
]
|
||||
for key in ["default", "user", "userList", "tweet"]
|
||||
}
|
||||
| {
|
||||
"post": [
|
||||
ReplaceQueryIdPlaceholder(),
|
||||
AddSecuritySchemesOnHeader(),
|
||||
SetResponsesHeader(),
|
||||
AddParametersOnParametersAsObject(),
|
||||
],
|
||||
"v1.1": [SetResponsesHeader()],
|
||||
},
|
||||
},
|
||||
"typescript": {
|
||||
"openapi": [AddSecuritySchemesOnSecuritySchemes()],
|
||||
"request": {
|
||||
key: [
|
||||
ReplaceQueryIdPlaceholder(),
|
||||
SetResponsesHeader(),
|
||||
AddParametersOnParametersAsString(),
|
||||
]
|
||||
for key in ["default", "user", "userList", "tweet"]
|
||||
}
|
||||
| {
|
||||
"post": [
|
||||
ReplaceQueryIdPlaceholder(),
|
||||
SetResponsesHeader(),
|
||||
AddParametersOnParametersAsObject(),
|
||||
],
|
||||
"v1.1": [SetResponsesHeader()],
|
||||
},
|
||||
},
|
||||
"test": {
|
||||
"openapi": [AddSecuritySchemesOnSecuritySchemes()],
|
||||
"request": {
|
||||
key: [
|
||||
ReplaceQueryIdPlaceholder(),
|
||||
SetResponsesHeader(),
|
||||
AddParametersOnParametersAsString(),
|
||||
]
|
||||
for key in ["default", "user", "userList", "tweet"]
|
||||
}
|
||||
| {
|
||||
"post": [
|
||||
ReplaceQueryIdPlaceholder(),
|
||||
SetResponsesHeader(),
|
||||
AddParametersOnParametersAsString(),
|
||||
],
|
||||
"v1.1": [SetResponsesHeader()],
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
"""
|
||||
"docs": {
|
||||
"header": "securitySchemes",
|
||||
"get_parameters": "schema_content",
|
||||
"post_parameters": "schema_parameters"
|
||||
},
|
||||
"dart": {
|
||||
"header": "parameters",
|
||||
"get_parameters": "string",
|
||||
"post_parameters": "object"
|
||||
},
|
||||
"typescript": {
|
||||
"header": "securitySchemes",
|
||||
"get_parameters": "string",
|
||||
"post_parameters": "object"
|
||||
},
|
||||
"test": {
|
||||
"header": "securitySchemes",
|
||||
"get_parameters": "string",
|
||||
"post_parameters": "string"
|
||||
}
|
||||
"""
|
||||
193
tools/hooks.py
Normal file
193
tools/hooks.py
Normal file
|
|
@ -0,0 +1,193 @@
|
|||
import yaml
|
||||
import json
|
||||
|
||||
|
||||
class HookBase:
|
||||
PLACEHOLDER: dict
|
||||
|
||||
def __init__(self):
|
||||
with open("src/config/placeholder.json", mode="r", encoding="utf-8") as f:
|
||||
self.PLACEHOLDER = json.load(f)
|
||||
|
||||
def placeholder_to_yaml(self, obj, default=False, example=False) -> dict:
|
||||
fn = lambda x: self.placeholder_to_yaml(x, default=default, example=example)
|
||||
if type(obj) is dict:
|
||||
properties = {i: fn(obj[i]) for i in obj}
|
||||
value = {
|
||||
"type": "object",
|
||||
"required": [i for i in obj],
|
||||
"properties": properties,
|
||||
}
|
||||
value.update({"default": properties} if default else {})
|
||||
value.update({"example": properties} if example else {})
|
||||
return value
|
||||
elif type(obj) is list and len(obj) > 0:
|
||||
properties = fn(obj[0])
|
||||
value = {
|
||||
"type": "array",
|
||||
"items": properties,
|
||||
}
|
||||
value.update({"default": [properties]} if default else {})
|
||||
value.update({"example": [properties]} if example else {})
|
||||
return value
|
||||
elif type(obj) is list and len(obj) == 0:
|
||||
value = {
|
||||
"type": "array",
|
||||
"items": {"type": "object"},
|
||||
}
|
||||
value.update({"default": []} if default else {})
|
||||
value.update({"example": []} if example else {})
|
||||
return value
|
||||
elif type(obj) is str:
|
||||
return {"type": "string", "example": obj, "default": obj}
|
||||
elif type(obj) is bool:
|
||||
return {"type": "boolean", "example": obj, "default": obj}
|
||||
elif type(obj) is int:
|
||||
return {"type": "integer", "example": obj, "default": obj}
|
||||
|
||||
def load_component(self, name: str) -> dict:
|
||||
with open(f"src/config/component/{name}.yaml", mode="r", encoding="utf-8") as f:
|
||||
return yaml.safe_load(f)
|
||||
|
||||
|
||||
class OpenapiHookBase(HookBase):
|
||||
def hook(self, value: dict):
|
||||
return value
|
||||
|
||||
|
||||
class RequestHookBase(HookBase):
|
||||
def hook(self, path: str, value: dict):
|
||||
return path, value
|
||||
|
||||
|
||||
class AddSecuritySchemesOnSecuritySchemes(HookBase):
|
||||
def hook(self, value: dict):
|
||||
component = self.load_component("security_schemes")
|
||||
param = component["components"]["securitySchemes"]
|
||||
value["components"]["securitySchemes"].extend(param)
|
||||
return value
|
||||
|
||||
|
||||
class AddSecuritySchemesOnHeader(RequestHookBase):
|
||||
def hook(self, path: str, value: dict):
|
||||
value["parameters"] = value.get("parameters", [])
|
||||
component = self.load_component("security_schemes")
|
||||
param = component["paths"]["/parameters"]["get"]["parameters"]
|
||||
value["parameters"].extend(param)
|
||||
return path, value
|
||||
|
||||
|
||||
class ReplaceQueryIdPlaceholder(RequestHookBase):
|
||||
def hook(self, path: str, value: dict):
|
||||
path_name = path.split("/")[-1]
|
||||
new = self.PLACEHOLDER[path_name]["queryId"]
|
||||
return path.replace(r"{{queryId}}", new), value
|
||||
|
||||
|
||||
class SetResponsesHeader(RequestHookBase):
|
||||
def hook(self, path: str, value: dict):
|
||||
component = self.load_component("response_header")
|
||||
value["responses"]["200"]["headers"] = component["components"]["headers"]
|
||||
return path, value
|
||||
|
||||
|
||||
class AddParametersOnParametersAsString(RequestHookBase):
|
||||
def hook(self, path: str, value: dict):
|
||||
value["parameters"] = value.get("parameters", [])
|
||||
path_name = path.split("/")[-1]
|
||||
for key in self.PLACEHOLDER[path_name].keys():
|
||||
example = json.dumps(self.PLACEHOLDER[path_name][key])
|
||||
value["parameters"].append(
|
||||
{
|
||||
"name": key,
|
||||
"in": "query",
|
||||
"required": True,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"default": example,
|
||||
"example": example,
|
||||
},
|
||||
}
|
||||
)
|
||||
return path, value
|
||||
|
||||
|
||||
class AddParametersOnParametersAsObject(RequestHookBase):
|
||||
def hook(self, path: str, value: dict):
|
||||
value["parameters"] = value.get("parameters", [])
|
||||
path_name = path.split("/")[-1]
|
||||
for key in self.PLACEHOLDER[path_name].keys():
|
||||
example = json.dumps(self.PLACEHOLDER[path_name][key])
|
||||
value["parameters"].append(
|
||||
{
|
||||
"name": key,
|
||||
"in": "query",
|
||||
"required": True,
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"default": example,
|
||||
"example": example,
|
||||
},
|
||||
}
|
||||
)
|
||||
return path, value
|
||||
|
||||
|
||||
class AddParametersOnContent(RequestHookBase):
|
||||
def hook(self, path: str, value: dict):
|
||||
value["parameters"] = value.get("parameters", [])
|
||||
path_name = path.split("/")[-1]
|
||||
for key in self.PLACEHOLDER[path_name].keys():
|
||||
value["parameters"].append(
|
||||
{
|
||||
"name": key,
|
||||
"in": "query",
|
||||
"required": True,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": self.placeholder_to_yaml(
|
||||
self.PLACEHOLDER[path_name][key]
|
||||
),
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
return path, value
|
||||
|
||||
|
||||
class AddParametersOnParameters(RequestHookBase):
|
||||
def hook(self, path: str, value: dict):
|
||||
value["parameters"] = value.get("parameters", [])
|
||||
path_name = path.split("/")[-1]
|
||||
for key in self.PLACEHOLDER[path_name].keys():
|
||||
value["parameters"].append(
|
||||
{
|
||||
"name": key,
|
||||
"in": "query",
|
||||
"required": True,
|
||||
"schema": self.placeholder_to_yaml(
|
||||
self.PLACEHOLDER[path_name][key]
|
||||
),
|
||||
}
|
||||
)
|
||||
return path, value
|
||||
|
||||
|
||||
class AddParametersOnBody(RequestHookBase):
|
||||
def hook(self, path: str, value: dict):
|
||||
value["parameters"] = value.get("parameters", [])
|
||||
path_name = path.split("/")[-1]
|
||||
data = self.PLACEHOLDER[path_name]
|
||||
schema = {i: self.placeholder_to_yaml(data[i]) for i in data.keys()}
|
||||
value["requestBody"] = {
|
||||
"description": "body",
|
||||
"required": True,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"properties": schema,
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
return path, value
|
||||
Loading…
Add table
Add a link
Reference in a new issue