tsdoc.ts 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. import fs from 'fs'
  2. import { strict as assert } from 'node:assert'
  3. import { parseArgs } from 'node:util'
  4. import stringify from 'json-stringify-safe'
  5. import { writeToDisk } from './helpers'
  6. const args = parseArgs({
  7. options: {
  8. input: {
  9. type: 'string',
  10. },
  11. output: {
  12. type: 'string',
  13. short: 'n',
  14. },
  15. },
  16. })
  17. assert(args.values.input, 'input is required')
  18. assert(args.values.output, 'output is required')
  19. dereference({ input: args.values.input!, output: args.values.output! })
  20. interface KV {
  21. [key: string]: any
  22. }
  23. async function dereference({ input, output }: { input: string; output: string }) {
  24. console.log('input', input)
  25. const specRaw = fs.readFileSync(input, 'utf8')
  26. const spec = JSON.parse(specRaw)
  27. const kv = chilrenReducer({}, spec)
  28. // console.log('kv', kv)
  29. const dereferenced = dereferenceReducer(spec, kv)
  30. // console.log('dereferenced', dereferenced)
  31. await writeToDisk(output, stringify(dereferenced, null, 2))
  32. // console.log('JSON.stringify(dereferenced)', JSON.stringify(spec))
  33. }
  34. function chilrenReducer(acc: KV, child: any): KV {
  35. if (!!child.children) {
  36. child.children.forEach((x: any) => chilrenReducer(acc, x))
  37. }
  38. const { id }: { id: string } = child
  39. acc[id] = { ...child }
  40. return acc
  41. }
  42. // Recurse through all children, and if the `type.type` == 'reference'
  43. // then it will add a key "dereferecnced" to the object.
  44. function dereferenceReducer(child: any, kv: KV) {
  45. if (!!child.children) {
  46. child.children.forEach((x: any) => dereferenceReducer(x, kv))
  47. }
  48. if (!!child.signatures) {
  49. child.signatures.forEach((x: any) => dereferenceReducer(x, kv))
  50. }
  51. if (!!child.parameters) {
  52. child.parameters.forEach((x: any) => dereferenceReducer(x, kv))
  53. }
  54. if (
  55. !!child.type &&
  56. !!child.type.declaration &&
  57. !!child.type.declaration.children &&
  58. child.type.type === 'reflection'
  59. ) {
  60. child.type.declaration.children.forEach((x: any) => dereferenceReducer(x, kv))
  61. }
  62. const final = { ...child }
  63. if (
  64. // For now I can only dereference parameters
  65. // because anything else is producing an error when saving to file:
  66. // TypeError: Converting circular structure to JSON
  67. final.kindString === 'Parameter' &&
  68. final.type?.type === 'reference' &&
  69. final.type?.id
  70. ) {
  71. const dereferenced = kv[final.type.id]
  72. final.type.dereferenced = dereferenced || {}
  73. return final
  74. } else if (
  75. final.kindString === 'Property' &&
  76. final.type?.type === 'reference' &&
  77. final.type?.id
  78. ) {
  79. const dereferenced = kv[final.type.id]
  80. final.type.dereferenced = dereferenced || {}
  81. return final
  82. } else if (final.kindString === 'Type alias' && final.type?.type === 'union') {
  83. // handles union types that contain nested references
  84. // by replacing the reference in-place
  85. final.type.types = final.type.types.map((item: any) => {
  86. return item.type === 'reference' ? kv[item.id] : item
  87. })
  88. return final
  89. } else {
  90. return final
  91. }
  92. }