ocean-engine-doc-maker.user.js 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. // ==UserScript==
  2. // @name OceanEngine Document Maker
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.0
  5. // @description Translate document to enumeration and type defintion
  6. // @author You
  7. // @match https://open.oceanengine.com/labels/7/docs/*
  8. // @grant GM_setClipboard
  9. // @run-at document-start
  10. // ==/UserScript==
  11. (function() {
  12. 'use strict';
  13. const convertType = (type) => {
  14. const isList = type.endsWith('[]')
  15. if (isList) type = type.substring(0, type.length - 2)
  16. switch (type.toLowerCase()) {
  17. case 'float': type = 'Float'; break
  18. case 'double': type = 'Double'; break
  19. case 'number':
  20. case 'int':
  21. case 'long':
  22. case 'integer': type = 'Long'; break
  23. case 'boolean': type = 'Boolean'; break
  24. case 'string': type = 'String'; break
  25. case 'json':
  26. case 'object': type = 'Object'; break
  27. }
  28. if (isList) type = `List<${type}>`
  29. return type
  30. }
  31. const parseName = (childNodes) => {
  32. if (!childNodes) return
  33. for (const node of childNodes) {
  34. if (node.nodeType === Node.TEXT_NODE) {
  35. const text = node.textContent.trim()
  36. if (text) return text
  37. }
  38. }
  39. }
  40. const parseRow = (row) => {
  41. const tds = row.querySelectorAll('td')
  42. const name = parseName(tds[0].querySelector('div')?.childNodes)
  43. if (!name) return ''
  44. const optional = tds[0].querySelector('span.tag')?.innerText?.trim() !== '必填'
  45. const type = tds[1].innerText.trim()
  46. const comment = tds[2].innerText.trim()
  47. return ` val ${name.replace(/\n/g, '')}: ${convertType(type)}${optional ? '? = null' : ''}, // ${comment.replace(/\n/g, ' ')}\n`
  48. }
  49. const parseRows = (rows) => {
  50. if (!rows.length) return
  51. let content = `data class Foo (\n`
  52. rows.forEach(row => {
  53. content += parseRow(row)
  54. })
  55. content += ')'
  56. return content
  57. }
  58. const parseTable = (table, selector, result) => {
  59. result.innerText = parseRows(table.querySelectorAll(selector))
  60. result.style.display = ''
  61. GM_setClipboard(result.innerText)
  62. }
  63. const ENUM_HINT = '允许值'
  64. const processEnumerationNode = (node) => {
  65. if (node.nodeType === Node.ELEMENT_NODE && node.tagName === 'CODE') {
  66. if (node.previousSibling?.tagName !== 'BR') node.parentNode.insertBefore(document.createElement('br'), node)
  67. node.innerText = node.innerText.replace(/"|'/g, '')
  68. } else if (node.nodeType === Node.TEXT_NODE && node.previousSibling?.tagName === 'CODE') {
  69. const comment = node.textContent.trim().replace(/、|,|,$/g, '')
  70. node.textContent = comment ? `,\u00A0//\u00A0${comment}` : ','
  71. }
  72. }
  73. const formatEnumerations = (table) => {
  74. table.querySelectorAll('tr > td:nth-child(3) > div').forEach(div => {
  75. if (div.innerText?.includes(ENUM_HINT)) {
  76. // 提示模式 允许值:blahblah
  77. let started = false
  78. let node = div.childNodes[0]
  79. while (node) {
  80. if (started) {
  81. processEnumerationNode(node)
  82. } else if (node.nodeType === Node.TEXT_NODE && node.textContent.includes(ENUM_HINT)) {
  83. started = true
  84. }
  85. node = node.nextSibling
  86. }
  87. } else {
  88. // 行首模式
  89. let node = div.querySelector('br + code')
  90. if (node?.previousSibling?.tagName !== 'BR') return
  91. while (node) {
  92. processEnumerationNode(node)
  93. node = node.nextSibling
  94. }
  95. }
  96. })
  97. }
  98. const createButton = (table) => {
  99. if (table.dataset.done) return
  100. table.dataset.done = true
  101. formatEnumerations(table)
  102. const levels = Array.from(table.querySelectorAll('tr')).reduce((s, row) => {
  103. if (row.className) s.add(row.className)
  104. return s
  105. }, new Set())
  106. const container = document.createElement('div')
  107. const result = document.createElement('pre')
  108. result.style.display = 'none'
  109. table.parentNode.insertBefore(container, table)
  110. table.parentNode.insertBefore(result, table)
  111. const addBtn = (level) => {
  112. const btn = document.createElement('button')
  113. btn.append(document.createTextNode(level))
  114. btn.addEventListener('click', () => parseTable(table, `tbody > tr.${level}`, result))
  115. container.append(btn)
  116. }
  117. for (const level of levels.values()) addBtn(level)
  118. }
  119. const ob = new MutationObserver(mutations => {
  120. mutations.forEach(({ target }) => {
  121. if (target?.tagName === 'DIV' && target?.classList?.contains('doc-content-body')) {
  122. target.querySelectorAll('table').forEach(createButton)
  123. }
  124. })
  125. })
  126. ob.observe(document.body, { subtree: true, childList: true })
  127. })();