您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
内部使用swagger-ui增强脚本,方便复制url为函数
当前为
- // ==UserScript==
- // @name Swagger Tool DAWN
- // @version 1.0.2
- // @description 内部使用swagger-ui增强脚本,方便复制url为函数
- // @author lixiang
- // @match http://*/swagger-ui.html*
- // @require https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/2.0.4/clipboard.min.js
- // @grant GM_addStyle
- // @run-at document-end
- // @license MIT
- // @namespace https://greasyfork.org/users/559637
- // ==/UserScript==
- // https://developer.chrome.com/extensions/match_patterns
- (async function (open) {
- function splitLast (str) {
- const lastIndex = str.lastIndexOf('/')
- return str.slice(lastIndex + 1)
- }
- function highlight () {
- for (const codeblock of document.getElementsByTagName('code')) {
- hljs.highlightBlock(codeblock)
- }
- }
- function addOutCss (href) {
- var head = document.querySelector('head')
- var link = document.createElement('link')
- link.href = href + ''
- link.rel = 'stylesheet'
- link.type = 'text/css'
- head.appendChild(link)
- }
- function firstUpperCase (str) {
- return str.toLowerCase().replace(/( |^)[a-z]/g, (L) => L.toUpperCase())
- }
- function splitLastSecond (str) {
- const arr = str.split('/')
- return arr[arr.length - 2]
- }
- function toHump (str) {
- if (!str) { return }
- let newStr = ''
- let big = false
- for (const i in str) {
- let s = str[i]
- if (big) {
- s = s.toLocaleUpperCase()
- big = false
- }
- if (s === '_') { big = true } else newStr += s
- }
- return newStr
- }
- function getSelectValue () {
- const selectUrl = document.querySelector('#selectUrl')
- const index = selectUrl.selectedIndex // 序号,取当前选中选项的序号
- const select = selectUrl.options[index].value
- return select
- }
- function getUrlName (url) {
- const type = getSelectValue()
- let urlName = ''
- if (type === 'first') {
- urlName = toHump(splitLast(url))
- } else if (type === 'second') {
- const urlName2 = firstUpperCase(toHump(splitLast(url)))
- const urlName1 = toHump(splitLastSecond(url))
- urlName = urlName1 + urlName2
- }
- return urlName
- }
- function getPrefix () {
- return document.querySelector('#urlPrefix').value ? '/' + document.querySelector('#urlPrefix').value : ''
- }
- function setClipboardDisplay (e) {
- const text = e.text
- document.querySelector('#cliDisplaySpan').textContent = text
- highlight()
- e.clearSelection()
- }
- function addSheet (params) {
- GM_addStyle(
- `
- #cliDisplay .hljs {
- display: block !important;
- overflow-x: auto !important;
- padding: 0.5em !important;
- color: #abb2bf !important;
- background: #282c34 !important;
- }
- #cliDisplay .hljs-comment,
- #cliDisplay .hljs-quote {
- color: #5c6370 !important;
- font-style: italic !important;
- }
- #cliDisplay .hljs-doctag,
- #cliDisplay .hljs-keyword,
- #cliDisplay .hljs-formula {
- color: #c678dd !important;
- }
- #cliDisplay .hljs-section,
- #cliDisplay .hljs-name,
- #cliDisplay .hljs-selector-tag,
- #cliDisplay .hljs-deletion,
- #cliDisplay .hljs-subst {
- color: #e06c75 !important;
- }
- #cliDisplay .hljs-literal {
- color: #56b6c2 !important;
- }
- #cliDisplay .hljs-string,
- #cliDisplay .hljs-regexp,
- #cliDisplay .hljs-addition,
- #cliDisplay .hljs-attribute,
- #cliDisplay .hljs-meta-string {
- color: #98c379 !important;
- }
- #cliDisplay .hljs-built_in,
- #cliDisplay .hljs-class .hljs-title {
- color: #e6c07b !important;
- }
- #cliDisplay .hljs-attr,
- #cliDisplay .hljs-variable,
- #cliDisplay .hljs-template-variable,
- #cliDisplay .hljs-type,
- #cliDisplay .hljs-selector-class,
- #cliDisplay .hljs-selector-attr,
- #cliDisplay .hljs-selector-pseudo,
- #cliDisplay .hljs-number {
- color: #d19a66 !important;
- }
- #cliDisplay .hljs-symbol,
- #cliDisplay .hljs-bullet,
- #cliDisplay .hljs-link,
- #cliDisplay .hljs-meta,
- #cliDisplay .hljs-selector-id,
- #cliDisplay .hljs-title {
- color: #61aeee !important;
- }
- #cliDisplay .hljs-emphasis {
- font-style: italic !important;
- }
- #cliDisplay .hljs-strong {
- font-weight: bold !important;
- }
- #cliDisplay .hljs-link {
- text-decoration: underline !important;
- }
- `
- )
- GM_addStyle(
- `
- ::-webkit-scrollbar {
- width: 6px;
- height: 6px;
- }
- ::-webkit-scrollbar-track {
- border-radius: 3px;
- background: #c678dd57;
- -webkit-box-shadow: inset 0 0 5px rgba(0,0,0,0.08);
- }
- ::-webkit-scrollbar-thumb {
- border-radius: 3px;
- background: rgba(0,0,0,0.12);
- -webkit-box-shadow: inset 0 0 10px rgba(0,0,0,0.2);
- }
- .swagger-section #header {
- position:relative;
- }
- .search_wrapper {
- }
- .setting_card {
- position: absolute;
- background: #fff;
- border: 1px solid rgba(0,0,0,0.2);
- border-radius: 8px;
- box-shadow: 0 1px 2px 0 rgba(60,64,67,.30), 0 2px 6px 2px rgba(60,64,67,.15);
- overflow-x: hidden;
- padding-top: 0;
- height: 120px;
- width: 320px;
- right: 10px;
- top: 60px;
- padding: 10px 10px;
- visibility:hidden;
- z-index:1
- }
- .setting_item {
- padding: 5px 0;
- margin-bottom: 5px;
- border-bottom: 1px solid #f2f2f2;
- }
- .setting_icon {
- position:absolute;
- right:10px;
- top:10px;
- cursor: pointer;
- }
- .setting_icon:hover {
- animation: myRotate 3s linear infinite;
- }
- @keyframes myRotate{
- 0%{ -webkit-transform: rotate(0deg);}
- 50%{ -webkit-transform: rotate(180deg);}
- 100%{ -webkit-transform: rotate(360deg);}
- }
- .card {
- position: relative;
- background: #282c34 !important;
- margin: 1rem 0;
- padding: 1em 1em;
- border-radius: 0.2rem;
- border:none !important;
- max-height: 150px;
- overflow: auto;
- }
- .card:hover {
- box-shadow:2px 2px 9px 0px #1e3b50;
- }
- .header-label {
- color:#666;
- width: 120px;
- display: inline-block;
- }
- select {
- border: 1px solid #ccc;
- padding: 7px 0px;
- border-radius: 3px;
- padding-left: 5px;
- -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
- box-shadow: inset 0 1px 1px rgba(80, 69, 69, 0.075);
- -webkit-transition: border-color ease-in-out 0.15s,
- -webkit-box-shadow ease-in-out 0.15s;
- -o-transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
- transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
- }
- option {
- height: 30px;
- padding: 5px 4px;
- }
- input {
- border: 1px solid #ccc;
- padding: 7px 0px;
- border-radius: 3px;
- padding-left: 5px;
- -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
- box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
- -webkit-transition: border-color ease-in-out 0.15s,
- -webkit-box-shadow ease-in-out 0.15s;
- -o-transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
- transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
- }
- input:focus {
- border-color: #66afe9;
- outline: 0;
- -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075),
- 0 0 8px rgba(102, 175, 233, 0.6);
- box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075),
- 0 0 8px rgba(102, 175, 233, 0.6);
- }
- button {
- display: inline-block;
- position: relative;
- cursor: pointer;
- padding: 7px 4px;
- color: white;
- font-size: 0.7em;
- text-align: center;
- text-decoration: none;
- text-transform: uppercase;
- vertical-align: middle;
- white-space: nowrap;
- outline: none;
- border: none;
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
- border-radius: 2px;
- background-color: #89bf04;
- }
- button + button {
- margin-left: 5px;
- }
- button:hover {
- background-color: #aee032;
- text-decoration: none;
- box-shadow: 0 4px 10px 0px rgba(0, 0, 0, 0.225);
- }
- `)
- }
- function readyAsync () {
- return new Promise((resolve, reject) => {
- XMLHttpRequest.prototype.open = function (method, url, async, user, pass) {
- console.log('XMLHttpRequest.prototype.open -> url', url)
- this.addEventListener('readystatechange', () => {
- }, false)
- let timer = null
- let inited = false
- let myUrl = null
- if (url.includes('api-docs')) {
- myUrl = url
- timer = setInterval(() => {
- if (inited) {
- clearInterval(timer)
- inited = false
- } else {
- const elementArr = document.querySelectorAll('.http_method')
- if (elementArr.length !== 0) {
- if (myUrl.includes('api-docs')) {
- inited = true
- resolve(myUrl)
- }
- }
- }
- }, 1000)
- }
- open.call(this, method, url, async, user, pass)
- }
- })
- }
- function readyAndWatch (func) {
- XMLHttpRequest.prototype.open = function (method, url, async, user, pass) {
- this.addEventListener('readystatechange', () => {
- }, false)
- let timer = null
- let inited = false
- let myUrl = null
- if (url.includes('api-docs')) {
- myUrl = url
- timer = setInterval(() => {
- if (inited) {
- clearInterval(timer)
- inited = false
- } else {
- const elementArr = document.querySelectorAll('.http_method')
- if (elementArr.length !== 0) {
- if (myUrl.includes('api-docs')) {
- console.log('timer -> myUrl', myUrl)
- inited = true
- func(myUrl)
- }
- }
- }
- }, 1000)
- }
- open.call(this, method, url, async, user, pass)
- }
- }
- function getJsonAsync (url) {
- return new Promise((resolve, reject) => {
- const res = fetch(url)
- .then(res => {
- return res.json()
- })
- .catch(e => {
- reject(e)
- })
- res.then(res => {
- const totalRes = res
- resolve(totalRes)
- })
- })
- }
- function createExpand () {
- document.querySelector('#message-bar').insertAdjacentHTML('afterbegin', `
- <button id='collapse'>合起全部</button>
- <button id='expandAll'>展开全部</button>
- `)
- document.querySelector('#collapse').onclick = collapse
- document.querySelector('#expandAll').onclick = expandAll
- function expandAll () {
- const list = document.querySelector('#resources')
- const items = list.children;
- [...items].forEach(li => {
- li.classList.add('active')
- li.querySelector('ul.endpoints').style.display = 'block'
- })
- }
- function collapse () {
- const list = document.querySelector('#resources')
- const items = list.children;
- [...items].forEach(li => {
- li.classList.remove('active')
- li.querySelector('ul.endpoints').style.display = 'none'
- })
- }
- }
- function createCliDisplay () {
- document.querySelector('#message-bar').insertAdjacentHTML('afterbegin',
- `
- <pre class='card' id='cliDisplay'><code class='code javascript' id='cliDisplaySpan'>剪贴板展示</code></pre>
- `
- )
- }
- function createCopyUrlAll (totalRes) {
- const blockArr = document.querySelectorAll('#resources > .resource')
- blockArr.forEach(ele => {
- const button = document.createElement('button')
- button.innerHTML = '复制所有url'
- button.classList.add('copy_url_all')
- ele.querySelector('.heading').children[0].prepend(button)
- const paths = new Set();
- [...ele.querySelector('.endpoints').children].forEach(li => {
- const url = li.querySelector('.path').children[0].innerHTML
- const method = li
- .querySelector('.http_method')
- .children[2].innerHTML.toUpperCase()
- const note = li.querySelector('.markdown').children[0].innerHTML
- const obj = {
- url,
- method,
- note
- }
- const objStr = JSON.stringify(obj)
- paths.add(objStr)
- })
- button.dataset.clipboardText = Array.from(paths).join(';')
- })
- }
- function createCopyUrl () {
- const elementArr = document.querySelectorAll('.endpoint')
- elementArr.forEach(ele => {
- const button = document.createElement('button')
- button.innerHTML = '复制url'
- button.classList.add('copy_url')
- ele.querySelector('.http_method').prepend(button)
- const url = ele.querySelector('.path').children[0].innerHTML
- const method = ele.querySelector('.http_method').children[2].innerHTML.toUpperCase()
- const note = ele.querySelector('.markdown').children[0].innerHTML
- const obj = {
- url,
- method,
- note
- }
- const objStr = JSON.stringify(obj)
- button.dataset.clipboardText = objStr
- })
- }
- function createCopyFunc (totalRes) {
- const elementArr = document.querySelectorAll('.endpoint')
- elementArr.forEach(ele => {
- const button = document.createElement('button')
- button.innerHTML = '复制为async函数'
- button.classList.add('copy_func')
- ele.querySelector('.http_method').prepend(button)
- const url = ele.querySelector('.path').children[0].innerHTML
- const pathRes = totalRes.paths[url].get || totalRes.paths[url].post
- const parameters = pathRes.parameters
- if (!parameters) {
- return
- }
- const parameterLast = parameters[parameters.length - 1]
- let ref
- let comment
- if (parameterLast.in === 'body') {
- if (parameterLast.schema.$ref) {
- ref = splitLast(parameterLast.schema.$ref)
- const definition = totalRes.definitions[ref]
- if (definition) {
- const properties = definition.properties
- const parameters = Object.keys(properties).map(key => {
- const property = properties[key]
- const obj = {}
- obj.name = key
- obj.description = property.description
- obj.type = property.type
- return obj
- })
- comment = parameters.reduce((acc, cur) => {
- if (cur.name == 'token') {
- return acc
- }
- acc = `${acc}
- ${cur.name}:'',//${cur.description} ${cur.type}`
- return acc
- }, '')
- }
- }
- } else {
- comment = parameters.reduce((acc, cur) => {
- if (cur.name == 'token') {
- return acc
- }
- acc = `${acc}
- ${cur.name}:'', //${cur.description} ${cur.type}`
- return acc
- }, '')
- }
- if (!comment) {
- comment = '//无需参数'
- }
- const obj = {
- url,
- comment
- }
- button.dataset.clipboardText = JSON.stringify(obj)
- })
- }
- function createButtonTable (ele) {
- const elementArr = document.querySelectorAll('.endpoint')
- elementArr.forEach(ele => {
- const button = document.createElement('button')
- button.innerHTML = '复制为列表项'
- button.classList.add('copy_table')
- if (ele.querySelector('.description')) {
- ele.querySelector('.description').prepend(button)
- const description = ele.querySelector('.description')
- const div = description.querySelectorAll('div')
- const list = [...div]
- const table = list.reduce((acc, cur) => {
- if (cur.querySelector('.propDesc')) {
- const propName = cur.querySelector('.propName').innerHTML
- const noPropNameList = ['code', 'data', 'message', 'list', 'pageNum', 'pageSize', 'total ']
- if (noPropNameList.includes(propName)) {
- return acc
- }
- const propDesc = cur.querySelector('.propDesc').querySelector('p').innerHTML
- acc = `
- ${acc}
- {
- prop:"${propName}",
- label:"${propDesc}"
- },
- `
- return acc
- } else {
- return acc
- }
- }, '')
- button.dataset.clipboardText = table
- }
- })
- }
- function clipboard () {
- const clipboardUrl = new ClipboardJS('.copy_url', {
- text: function (trigger) {
- const objStr = trigger.dataset.clipboardText
- const obj = JSON.parse(objStr)
- const urlPrefix = getPrefix()
- const urlName = getUrlName(obj.url)
- const url = `export const ${urlName} = data => request('${urlPrefix}${obj.url}', data,"${obj.method}")//${obj.note}`
- return url
- }
- })
- const clipboardUrlAll = new ClipboardJS('.copy_url_all', {
- text: function (trigger) {
- const arr = trigger.dataset.clipboardText.split(';')
- const paths = new Set()
- arr.forEach(objStr => {
- const obj = JSON.parse(objStr)
- const urlPrefix = getPrefix()
- const urlName = getUrlName(obj.url)
- const url = `export const ${urlName} = data => request('${urlPrefix}${obj.url}', data,"${obj.method}")//${obj.note}`
- paths.add(url)
- })
- return Array.from(paths).join('\n')
- }
- })
- const clipboardFunc = new ClipboardJS('.copy_func', {
- text: function (trigger) {
- const objStr = trigger.dataset.clipboardText
- const obj = JSON.parse(objStr)
- const comment = obj.comment
- const asyncName = getUrlName(obj.url)
- const fun = `
- async ${asyncName}Async() {
- let params = {
- ${comment}
- }
- let res = await api.${asyncName}(params)
- },
- `
- return fun
- }
- })
- const clipboardTable = new ClipboardJS('.copy_table', {
- text: function (trigger) {
- const table = trigger.dataset.clipboardText
- return table
- }
- })
- clipboardUrl.on('success', setClipboardDisplay)
- clipboardUrlAll.on('success', setClipboardDisplay)
- clipboardFunc.on('success', setClipboardDisplay)
- clipboardTable.on('success', setClipboardDisplay)
- }
- function createSelect () {
- document.querySelector('.setting_card').insertAdjacentHTML('afterbegin',
- `
- <div class='setting_item'>
- <label for="selectUrl" class='header-label'>url截取范围:</label>
- <select name='selectUrl' id='selectUrl'>
- <option value="first" selected = "selected">最后一级</option>
- <option value="second">最后二级</option>
- </select>
- </div>
- `
- )
- }
- function createInput () {
- document.querySelector('.setting_card').insertAdjacentHTML('afterbegin',
- `
- <div class='setting_item'>
- <label for="prefix" class='header-label'>url前缀:</label>
- <input type="text" id="urlPrefix" name="prefix" placeholder='后端微服务名'>
- </div>
- `
- )
- }
- function createSetting () {
- document.querySelector('#header').insertAdjacentHTML('beforeend',
- `
- <div class='setting_icon'>
- <svg t="1589098334770" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2404" width="35" height="35"><path d="M935.69113 523.130435c0-58.590609 36.797217-108.232348 88.30887-128a513.669565 513.669565 0 0 0-56.097391-135.635478 136.97113 136.97113 0 0 1-181.047652-181.092174A515.962435 515.962435 0 0 0 651.152696 22.26087 137.371826 137.371826 0 0 1 523.130435 110.569739 137.171478 137.171478 0 0 1 395.130435 22.26087a513.669565 513.669565 0 0 0-135.635478 56.141913 137.126957 137.126957 0 0 1-28.093218 152.932174 137.371826 137.371826 0 0 1-152.887652 28.16A510.21913 510.21913 0 0 0 22.26087 395.130435 137.371826 137.371826 0 0 1 110.569739 523.130435c0 58.590609-36.797217 108.232348-88.308869 128a513.669565 513.669565 0 0 0 56.141913 135.635478 136.97113 136.97113 0 0 1 180.980869 181.092174A515.650783 515.650783 0 0 0 395.130435 1024a137.371826 137.371826 0 0 1 128.022261-88.30887c58.590609 0 108.232348 36.797217 128 88.30887a513.669565 513.669565 0 0 0 135.635478-56.097391 137.126957 137.126957 0 0 1 28.093217-152.998957 137.371826 137.371826 0 0 1 152.887652-28.137739A510.21913 510.21913 0 0 0 1024 651.130435a137.171478 137.171478 0 0 1-88.30887-128.022261z m-401.719652 152.442435a141.55687 141.55687 0 1 1 0.111305-283.11374 141.55687 141.55687 0 0 1-0.111305 283.11374z" fill="#2DAA9D" p-id="2405"></path><path d="M754.042435 512c0-34.370783 21.593043-63.510261 51.801043-75.108174a301.345391 301.345391 0 0 0-32.901565-79.560348 80.361739 80.361739 0 0 1-106.22887-106.228869 302.703304 302.703304 0 0 0-79.604869-32.946087A80.584348 80.584348 0 0 1 512 269.957565 80.473043 80.473043 0 0 1 436.891826 218.156522c-27.959652 7.123478-54.761739 18.209391-79.560348 32.946087a80.450783 80.450783 0 0 1-16.473043 89.711304 80.584348 80.584348 0 0 1-89.711305 16.517565A299.341913 299.341913 0 0 0 218.156522 436.891826 80.584348 80.584348 0 0 1 269.957565 512c0 34.370783-21.593043 63.510261-51.801043 75.108174 7.123478 27.959652 18.209391 54.761739 32.946087 79.560348a80.361739 80.361739 0 0 1 106.184348 106.228869 302.525217 302.525217 0 0 0 79.604869 32.946087A80.584348 80.584348 0 0 1 512 754.042435c34.370783 0 63.510261 21.593043 75.108174 51.801043 27.959652-7.123478 54.761739-18.18713 79.560348-32.901565a80.450783 80.450783 0 0 1 16.473043-89.755826 80.584348 80.584348 0 0 1 89.711305-16.517565 299.341913 299.341913 0 0 0 32.990608-79.560348A80.473043 80.473043 0 0 1 754.042435 512z m-235.675826 89.421913a83.033043 83.033043 0 1 1 0.044521-166.066087 83.033043 83.033043 0 0 1-0.044521 166.066087z" fill="#A4E8E1" p-id="2406"></path></svg>
- </div>
- <div class='setting_card'>
- </div>
- `
- )
- document.querySelector('.setting_icon').onclick = changeShow
- let isShow = false
- function changeShow () {
- if (isShow) {
- isShow = false
- document.querySelector('.setting_card').style.visibility = 'hidden'
- } else {
- isShow = true
- document.querySelector('.setting_card').style.visibility = 'visible'
- }
- }
- }
- function createSearch (params) {
- document.querySelector('#header').insertAdjacentHTML('beforeend',
- `
- <div class='search_wrapper'>
- <label for="search" class='header-label'>搜索:</label>
- <input type="text" id="search" name="search" placeholder='输入汉字'>
- </div>
- `
- )
- }
- addSheet()
- async function init (url) {
- const totalRes = await getJsonAsync(url)
- createExpand()
- createSetting()
- createSelect()
- createInput()
- createCliDisplay()
- createCopyFunc(totalRes)
- createCopyUrl()
- createCopyUrlAll()
- createButtonTable()
- clipboard()
- highlight()
- }
- readyAndWatch(init)
- }
- )(XMLHttpRequest.prototype.open)