free-swagger-userscript
Version:
free-swagger for tampermonkey
255 lines (242 loc) • 6.27 kB
JavaScript
import Vue from "vue";
import { Message } from "element-ui";
import { copyMessage } from "@/utils/dom-utils";
import { defaults, flattenDeep, groupBy } from "lodash-es";
import {
default as freeSwaggerCore,
jsTemplate,
tsTemplate,
compileInterfaces,
compileJsDocTypedefs,
} from "free-swagger-core";
import { retry } from "@/utils";
import { option, generate } from "json-schema-faker";
const STORAGE_KEY = "SWAGGER-USERSCRIPT";
const SUCCESS_CODE = "200";
export const state = new Vue({
data() {
return {
url: "",
dialog: false,
key: "",
currentApi: {
key: "",
path: "",
method: "",
collection: {
controller: {},
operationId: "",
},
},
storage: {
jsTemplate,
tsTemplate,
jsDoc: true,
interface: false,
typedef: false,
recursive: false,
exportLanguage: "js",
currentLanguage: "js",
},
isNewUi: null,
swagger: null,
parsedSwagger: null, // 解析所有 ref 后的 swagger 对象
};
},
computed: {
options() {
if (!this.swagger) return [];
const options = [];
const paths = this.swagger.paths;
Object.keys(paths).forEach((path) => {
Object.keys(paths[path]).forEach((method) => {
const { tags, summary, description, operationId } = paths[path][
method
];
options.push({
path,
method,
key: `${method} ${path} ${summary}`,
tag: tags[tags.length - 1],
collection: {
controller: tags[tags.length - 1],
summary,
description,
operationId,
},
});
});
});
// 根据 Tags 分组排序
return flattenDeep(Object.values(groupBy(options, (o) => o.tag)));
},
},
watch: {
storage: {
handler(newVal) {
localStorage.setItem(STORAGE_KEY, JSON.stringify(newVal));
},
deep: true,
},
},
created() {
const storage = localStorage.getItem(STORAGE_KEY)
? JSON.parse(localStorage.getItem(STORAGE_KEY))
: {};
this.storage = defaults(storage, this.storage, (oldVal, newVal) => {
if (oldVal === "") return newVal;
});
retry({
cb: () => {
// 新 UI(bytedance only)
if (window.SwaggerBootstrapUi) {
this.isNewUi = true;
} else if (window.ui) {
// 老 UI
this.isNewUi = false;
}
},
endCondition: () => this.isNewUi != null,
});
},
});
// 复制单个接口的所有 interface/typedef
export const handleCopyType = async (
path = state.currentApi.path,
method = state.currentApi.method,
source = state.swagger
) => {
try {
if (!path) {
throw new Error("请选择 path");
}
const storage = state.storage;
const isJS = storage.currentLanguage === "js";
const isTS = storage.currentLanguage === "ts";
const codeFragment = await freeSwaggerCore(
{
source,
lang: storage.currentLanguage,
jsDoc: storage.jsDoc,
typedef: isJS,
interface: isTS,
recursive: storage.recursive,
templateFunction: eval(isJS ? storage.jsTemplate : storage.tsTemplate),
},
path,
method
);
if (!codeFragment) {
Message.warning("没有可生成的类型代码");
return;
}
copyMessage(codeFragment);
} catch (e) {
Message.error("复制失败:请检查选择的 api 或模版");
console.log(e);
}
};
export const handleCopyApi = async (
path = state.currentApi.path,
method = state.currentApi.method,
source = state.swagger
) => {
try {
if (!path) {
throw new Error();
}
const storage = state.storage;
const codeFragment = await freeSwaggerCore(
{
source,
lang: storage.currentLanguage,
jsDoc: storage.jsDoc,
templateFunction: eval(
storage.currentLanguage === "js"
? storage.jsTemplate
: storage.tsTemplate
),
},
path,
method
);
copyMessage(codeFragment);
} catch (e) {
Message.error("复制失败:请检查选择的 api 或模版");
console.log(e);
}
};
export const handleCopyPath = (
path = state.currentApi.path,
method = state.currentApi.method
) => {
try {
// /pet/{petId}/uploadImage -> /pet/:petId/uploadImage
const formattedPath = path.replace(/{(.*?)}/g, ":$1");
copyMessage(`"${formattedPath}" /* ${method.toUpperCase()} */`);
} catch (e) {
Message.error("复制失败:请检查选择的 api 或模版");
console.log(e);
}
};
export const handleCopyFake = (
path = state.currentApi.path,
method = state.currentApi.method,
parsedSwagger = state.parsedSwagger
) => {
option({
useExamplesValue: true,
useDefaultValue: true,
alwaysFakeOptionals: true,
refDepthMax: 2,
maxItems: 1,
failOnInvalidTypes: false,
});
try {
let mockSchema;
const schema =
parsedSwagger.paths[path][method].responses?.[SUCCESS_CODE]?.schema;
if (schema) {
mockSchema = generate(schema);
if (mockSchema.code) mockSchema.code = SUCCESS_CODE;
} else {
mockSchema = {
code: SUCCESS_CODE,
msg: "ok",
data: {},
};
}
copyMessage(mockSchema);
} catch (e) {
console.log(e);
Message.error("复制失败:请检查选择的 api 或模版");
}
};
// 复制全量/单个 interface
export const handleCopyInterface = async (
source = state.swagger,
url = state.url,
interfaceName
) => {
try {
const { code } = await compileInterfaces({ source, interfaceName, url });
copyMessage(code);
} catch (e) {
console.log(e);
Message.error("复制失败:请检查选择的 api");
}
};
// 复制全量/单个 typedef
export const handleCopyJsDocTypeDef = async (
source = state.swagger,
url = state.url,
interfaceName
) => {
try {
const { code } = await compileJsDocTypedefs({ source, interfaceName, url });
copyMessage(code);
} catch (e) {
console.log(e);
Message.error("复制失败:请检查选择的 api");
}
};