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