Last active
March 15, 2023 07:14
-
-
Save ekoneko/846e6c42cca345de78ca1b2c63426a12 to your computer and use it in GitHub Desktop.
A tampermonkey script for translating yapi to typescript and mock fake data
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name YApi to Ts Interface | |
// @namespace http://tampermonkey.net/ | |
// @version 1.0 | |
// @description Generate ts interface or fake data in yapi | |
// @author Eko | |
// @match {HOST}/project/*/interface/api/* | |
// @icon https://www.google.com/s2/favicons?domain=TO_BE_REPLACED | |
// @grant none | |
// ==/UserScript== | |
(async () => { | |
async function loadScripts() { | |
async function loadScripts(src) { | |
return new Promise((resolve, reject) => { | |
const script = document.createElement("script"); | |
script.src = src; | |
script.onload = resolve; | |
script.onerror = reject; | |
document.documentElement.appendChild(script); | |
}); | |
} | |
/** | |
* prettier scripts must be loaded in order | |
*/ | |
await loadScripts("https://unpkg.com/prettier@2/standalone.js"); | |
await loadScripts("https://unpkg.com/prettier@2/parser-typescript.js"); | |
await loadScripts("https://unpkg.com/prettier@2/parser-babel.js"); | |
await loadScripts( | |
"https://cdn.githubraw.com/bcherny/json-schema-to-typescript-browser/master/bundle.js" | |
); | |
const formatWithPrettier = prettier.format.bind(prettier); | |
// standalone requires parsers be explicitly loaded | |
prettier.format = (str, options) => | |
formatWithPrettier( | |
str, | |
Object.assign({}, options, { | |
plugins: Object.assign({}, prettierPlugins, options.plugins), | |
}) | |
); | |
} | |
async function loadProject() { | |
const id = location.pathname.match(/\/project\/(\d+)/)?.[1] ?? null; | |
if (!id) { | |
throw new Error("project id not found") | |
} | |
const res = await fetch(`/api/project/get?id=${id}`) | |
const data = await res.json(); | |
if (!data.data) { | |
throw new Error("fetch failed"); | |
} | |
return data.data; | |
} | |
async function loadApi() { | |
const id = location.pathname.match(/\/api\/(\d+)/)?.[1] ?? null; | |
if (!id) { | |
throw new Error("api id not found") | |
} | |
const res = await fetch( | |
`/api/interface/get?id=${id}` | |
); | |
const data = await res.json(); | |
if (!data.data) { | |
throw new Error("fetch failed"); | |
} | |
return data.data; | |
} | |
function upperCaseFirstLetter(text) { | |
if (!text) { | |
return ''; | |
} | |
const chars = Array.from(text.replace(/[^\w]/g, '')); | |
const name = [chars[0].toUpperCase(), ...chars.slice(1)].join(""); | |
return name; | |
} | |
function getInterfaceName(data, action) { | |
return `${upperCaseFirstLetter(data.method.toLowerCase())}${upperCaseFirstLetter(data.path.split('/').map(upperCaseFirstLetter).join(''))}${action}` | |
} | |
const jsttOptions = { | |
bannerComment: `/** | |
* The content of this file has been generated automatically using json-schema-to-typescript. | |
* DO NOT EDIT IT MANUALLY. Instead, make changes to the source JSONSchema file | |
* and regenerate this file using json-schema-to-typescript. | |
* | |
* API Page: ${location.href} | |
*/`, | |
}; | |
async function getAndTransformData() { | |
const [apiData, projectData] = await Promise.all([ | |
loadApi(), | |
loadProject(), | |
]) | |
const texts = []; | |
let mockContent = | |
`createRule(['${apiData.method}', '${projectData.basepath}${apiData.path}'], function (req, res) { | |
res.send(204); | |
})` | |
if (apiData.res_body_is_json_schema && apiData.res_body_type === "json") { | |
try { | |
const resTs = await window.jstt.compile( | |
JSON.parse(apiData.res_body), | |
getInterfaceName(apiData, 'Response'), | |
jsttOptions | |
); | |
texts.push(resTs); | |
mockContent = mockContent.replace('res.send(204)', `res.send(this.jsf.generate(${apiData.res_body}))`); | |
} catch (err) { console.error(err) } | |
} | |
if (apiData.req_body_is_json_schema && apiData.req_body_type === "json") { | |
try { | |
const reqTs = await window.jstt.compile( | |
JSON.parse(apiData.req_body_other), | |
getInterfaceName(apiData, 'Request'), | |
jsttOptions | |
); | |
texts.push(reqTs); | |
} catch (err) { console.error(err) } | |
} | |
if (texts.length > 0) { | |
const text = texts.join("\n"); | |
const el = document.createElement('div'); | |
const generateTSIElement = document.createElement('div'); | |
generateTSIElement.onclick = () => navigator.clipboard.writeText(text); | |
generateTSIElement.innerHTML = "Copy Typescript Interface"; | |
Object.assign(generateTSIElement.style, { | |
position: "fixed", | |
bottom: "80px", | |
left: "10px", | |
zIndex: 100, | |
padding: "8px 16px", | |
background: "#fff", | |
cursor: "pointer", | |
}); | |
const generateFakeElement = document.createElement('div'); | |
generateFakeElement.onclick = () => navigator.clipboard.writeText(mockContent); | |
generateFakeElement.innerHTML = "Copy fake code"; | |
Object.assign(generateFakeElement.style, { | |
position: "fixed", | |
bottom: "40px", | |
left: "10px", | |
zIndex: 100, | |
padding: "8px 16px", | |
background: "#fff", | |
cursor: "pointer", | |
}); | |
el.appendChild(generateTSIElement); | |
el.appendChild(generateFakeElement); | |
document.body.appendChild(el); | |
console.log("inject button", el); | |
return el; | |
} | |
} | |
await loadScripts(); | |
let elRef; | |
window.history.pushState = new Proxy(window.history.pushState, { | |
apply: (target, thisArg, argArray) => { | |
const response = target.apply(thisArg, argArray); | |
if (elRef && elRef.parentElement) { | |
elRef.parentElement.remove(elRef); | |
} | |
elRef = getAndTransformData(); | |
return response; | |
}, | |
}); | |
getAndTransformData() | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment