@deplens/core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +19 -0
- package/src/inspect.mjs +1041 -0
- package/src/parse-dts.mjs +416 -0
package/src/inspect.mjs
ADDED
|
@@ -0,0 +1,1041 @@
|
|
|
1
|
+
// inspect.mjs
|
|
2
|
+
import { createRequire } from "module"
|
|
3
|
+
import fs from "fs"
|
|
4
|
+
import path from "path"
|
|
5
|
+
import { fileURLToPath, pathToFileURL } from "url"
|
|
6
|
+
import fg from "fast-glob"
|
|
7
|
+
import { resolve as importMetaResolve } from "import-meta-resolve"
|
|
8
|
+
import { parseDtsFile } from "./parse-dts.mjs"
|
|
9
|
+
|
|
10
|
+
function getPackageName(target) {
|
|
11
|
+
if (!target) return target
|
|
12
|
+
if (target.startsWith("@")) {
|
|
13
|
+
const parts = target.split("/")
|
|
14
|
+
return parts.length >= 2 ? `${parts[0]}/${parts[1]}` : target
|
|
15
|
+
}
|
|
16
|
+
return target.split("/")[0]
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function getPackageSubpath(target) {
|
|
20
|
+
if (!target) return null
|
|
21
|
+
const base = getPackageName(target)
|
|
22
|
+
if (!base) return null
|
|
23
|
+
if (target === base) return null
|
|
24
|
+
const prefix = `${base}/`
|
|
25
|
+
return target.startsWith(prefix) ? target.slice(prefix.length) : null
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async function findWorkspaceRoot(startDir) {
|
|
29
|
+
if (!startDir) return null
|
|
30
|
+
let dir = path.resolve(startDir)
|
|
31
|
+
while (true) {
|
|
32
|
+
const pkgPath = path.join(dir, "package.json")
|
|
33
|
+
if (fs.existsSync(pkgPath)) {
|
|
34
|
+
try {
|
|
35
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"))
|
|
36
|
+
if (pkg?.workspaces) return { dir, pkg }
|
|
37
|
+
} catch (e) {}
|
|
38
|
+
}
|
|
39
|
+
const parent = path.dirname(dir)
|
|
40
|
+
if (parent === dir) break
|
|
41
|
+
dir = parent
|
|
42
|
+
}
|
|
43
|
+
return null
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async function listWorkspacePackageDirs(rootDir, workspaces, targetPackage) {
|
|
47
|
+
const patterns = Array.isArray(workspaces) ? workspaces : workspaces?.packages
|
|
48
|
+
if (!Array.isArray(patterns) || patterns.length === 0) return []
|
|
49
|
+
const dirs = []
|
|
50
|
+
const target = getPackageName(targetPackage)
|
|
51
|
+
|
|
52
|
+
for (const pattern of patterns) {
|
|
53
|
+
if (!pattern) continue
|
|
54
|
+
const normalized = String(pattern).replace(/\\/g, "/").replace(/\/?$/, "/")
|
|
55
|
+
const globPattern = `${normalized}package.json`
|
|
56
|
+
const matches =
|
|
57
|
+
typeof Bun !== "undefined" && Bun.Glob
|
|
58
|
+
? await Array.fromAsync(
|
|
59
|
+
new Bun.Glob(globPattern).scan({
|
|
60
|
+
cwd: rootDir,
|
|
61
|
+
absolute: false,
|
|
62
|
+
onlyFiles: true,
|
|
63
|
+
followSymlinks: false,
|
|
64
|
+
dot: false,
|
|
65
|
+
}),
|
|
66
|
+
)
|
|
67
|
+
: await fg(globPattern, {
|
|
68
|
+
cwd: rootDir,
|
|
69
|
+
onlyFiles: true,
|
|
70
|
+
dot: false,
|
|
71
|
+
followSymbolicLinks: false,
|
|
72
|
+
})
|
|
73
|
+
for (const match of matches) {
|
|
74
|
+
const pkgPath = path.join(rootDir, match)
|
|
75
|
+
try {
|
|
76
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"))
|
|
77
|
+
const depTables = [
|
|
78
|
+
pkg?.dependencies,
|
|
79
|
+
pkg?.devDependencies,
|
|
80
|
+
pkg?.peerDependencies,
|
|
81
|
+
pkg?.optionalDependencies,
|
|
82
|
+
]
|
|
83
|
+
const hasTarget =
|
|
84
|
+
Boolean(target) &&
|
|
85
|
+
depTables.some((deps) => deps && Object.prototype.hasOwnProperty.call(deps, target))
|
|
86
|
+
if (hasTarget) {
|
|
87
|
+
dirs.push(path.dirname(pkgPath))
|
|
88
|
+
}
|
|
89
|
+
} catch (e) {}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return dirs
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
async function resolveTargetModule(target, cwd, resolveFrom) {
|
|
97
|
+
const baseDir = resolveFrom || cwd
|
|
98
|
+
if (!baseDir) return { resolved: null, resolveCwd: baseDir, resolver: null }
|
|
99
|
+
|
|
100
|
+
const tryResolve = async (dir) => {
|
|
101
|
+
if (!dir) return null
|
|
102
|
+
if (typeof Bun !== "undefined" && Bun.resolve) {
|
|
103
|
+
try {
|
|
104
|
+
const resolved = await Bun.resolve(target, dir)
|
|
105
|
+
return { resolved, resolver: "bun", resolveCwd: dir }
|
|
106
|
+
} catch (e) {}
|
|
107
|
+
}
|
|
108
|
+
try {
|
|
109
|
+
const parentUrl = pathToFileURL(path.join(dir, "noop.js")).href
|
|
110
|
+
const resolvedUrl = await importMetaResolve(target, parentUrl)
|
|
111
|
+
const resolvedPath = resolvedUrl.startsWith("file://") ? fileURLToPath(resolvedUrl) : resolvedUrl
|
|
112
|
+
return { resolved: resolvedPath, resolver: "import-meta-resolve", resolveCwd: dir }
|
|
113
|
+
} catch (e) {}
|
|
114
|
+
try {
|
|
115
|
+
const req = createRequire(path.join(dir, "noop.js"))
|
|
116
|
+
const resolved = req.resolve(target)
|
|
117
|
+
return { resolved, resolver: "require", resolveCwd: dir }
|
|
118
|
+
} catch (e) {
|
|
119
|
+
return null
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const direct = await tryResolve(baseDir)
|
|
124
|
+
if (direct) return direct
|
|
125
|
+
|
|
126
|
+
const workspace = await findWorkspaceRoot(baseDir)
|
|
127
|
+
if (workspace?.pkg?.workspaces) {
|
|
128
|
+
const dirs = await listWorkspacePackageDirs(workspace.dir, workspace.pkg.workspaces, target)
|
|
129
|
+
for (const dir of dirs) {
|
|
130
|
+
const resolved = await tryResolve(dir)
|
|
131
|
+
if (resolved) return resolved
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return { resolved: null, resolveCwd: baseDir, resolver: null }
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function resolvePackageInfo(basePkg, require) {
|
|
139
|
+
let pkgPath
|
|
140
|
+
let pkgDir
|
|
141
|
+
try {
|
|
142
|
+
pkgPath = require.resolve(`${basePkg}/package.json`)
|
|
143
|
+
pkgDir = path.dirname(pkgPath)
|
|
144
|
+
} catch (e) {
|
|
145
|
+
try {
|
|
146
|
+
const mainPath = require.resolve(basePkg)
|
|
147
|
+
let dir = path.dirname(mainPath)
|
|
148
|
+
for (let i = 0; i < 5; i++) {
|
|
149
|
+
const candidate = path.join(dir, "package.json")
|
|
150
|
+
if (fs.existsSync(candidate)) {
|
|
151
|
+
pkgPath = candidate
|
|
152
|
+
pkgDir = dir
|
|
153
|
+
break
|
|
154
|
+
}
|
|
155
|
+
dir = path.dirname(dir)
|
|
156
|
+
}
|
|
157
|
+
} catch (err) {}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (!pkgPath || !fs.existsSync(pkgPath)) return null
|
|
161
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"))
|
|
162
|
+
return { pkg, pkgPath, pkgDir }
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function resolveTypesFromExportEntry(entry) {
|
|
166
|
+
if (!entry) return null
|
|
167
|
+
if (typeof entry === "string") return entry
|
|
168
|
+
if (typeof entry === "object") {
|
|
169
|
+
if (typeof entry.types === "string") return entry.types
|
|
170
|
+
for (const key of ["import", "require", "default"]) {
|
|
171
|
+
if (typeof entry[key] === "string") return entry[key]
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return null
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function coerceTypesPath(typesPath) {
|
|
178
|
+
if (!typesPath) return typesPath
|
|
179
|
+
if (typesPath.endsWith(".d.ts") || typesPath.endsWith(".d.cts") || typesPath.endsWith(".d.mts")) {
|
|
180
|
+
return typesPath
|
|
181
|
+
}
|
|
182
|
+
if (typesPath.endsWith(".mjs")) return typesPath.replace(/\.mjs$/, ".d.mts")
|
|
183
|
+
if (typesPath.endsWith(".cjs")) return typesPath.replace(/\.cjs$/, ".d.cts")
|
|
184
|
+
if (typesPath.endsWith(".js")) return typesPath.replace(/\.js$/, ".d.ts")
|
|
185
|
+
return typesPath
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function resolveTypesFile(pkg, pkgDir, subpath) {
|
|
189
|
+
if (!pkg || !pkgDir) return { typesFile: null, dtsPath: null, source: null }
|
|
190
|
+
let typesFile = null
|
|
191
|
+
let source = null
|
|
192
|
+
|
|
193
|
+
if (pkg.exports) {
|
|
194
|
+
let entry = null
|
|
195
|
+
if (subpath) {
|
|
196
|
+
const key = subpath.startsWith(".") ? subpath : `./${subpath}`
|
|
197
|
+
if (typeof pkg.exports === "object") {
|
|
198
|
+
entry = pkg.exports[key]
|
|
199
|
+
}
|
|
200
|
+
} else if (typeof pkg.exports === "string") {
|
|
201
|
+
entry = pkg.exports
|
|
202
|
+
} else if (typeof pkg.exports === "object") {
|
|
203
|
+
entry = pkg.exports["."] ?? pkg.exports["./"]
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const typesFromExport = resolveTypesFromExportEntry(entry)
|
|
207
|
+
if (typesFromExport) {
|
|
208
|
+
typesFile = coerceTypesPath(typesFromExport)
|
|
209
|
+
source = "exports"
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (!typesFile) {
|
|
214
|
+
typesFile = pkg.types || pkg.typings || null
|
|
215
|
+
if (typesFile) source = "package"
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
if (!typesFile) {
|
|
219
|
+
const candidates = [
|
|
220
|
+
"dist/index.d.ts",
|
|
221
|
+
"dist/index.d.cts",
|
|
222
|
+
"dist/index.d.mts",
|
|
223
|
+
"lib/index.d.ts",
|
|
224
|
+
"lib/index.d.cts",
|
|
225
|
+
"lib/index.d.mts",
|
|
226
|
+
"index.d.ts",
|
|
227
|
+
"index.d.cts",
|
|
228
|
+
"index.d.mts",
|
|
229
|
+
"types/index.d.ts",
|
|
230
|
+
]
|
|
231
|
+
for (const candidate of candidates) {
|
|
232
|
+
const candidatePath = path.resolve(pkgDir, candidate)
|
|
233
|
+
if (fs.existsSync(candidatePath)) {
|
|
234
|
+
typesFile = candidate
|
|
235
|
+
source = "fallback"
|
|
236
|
+
break
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
if (!typesFile) {
|
|
242
|
+
return { typesFile: null, dtsPath: null, source: null }
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
const resolved = path.isAbsolute(typesFile) ? typesFile : path.resolve(pkgDir, typesFile)
|
|
246
|
+
let dtsPath = resolved
|
|
247
|
+
if (!fs.existsSync(dtsPath)) {
|
|
248
|
+
const mapped = coerceTypesPath(dtsPath)
|
|
249
|
+
if (mapped !== dtsPath && fs.existsSync(mapped)) {
|
|
250
|
+
dtsPath = mapped
|
|
251
|
+
} else {
|
|
252
|
+
const replacements = [".d.ts", ".d.cts", ".d.mts"]
|
|
253
|
+
for (const ext of replacements) {
|
|
254
|
+
if (dtsPath.endsWith(ext)) continue
|
|
255
|
+
const candidate = `${dtsPath}${ext}`
|
|
256
|
+
if (fs.existsSync(candidate)) {
|
|
257
|
+
dtsPath = candidate
|
|
258
|
+
break
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
if (!fs.existsSync(dtsPath) && dtsPath.endsWith(".d.ts")) {
|
|
262
|
+
const ctsPath = dtsPath.replace(".d.ts", ".d.cts")
|
|
263
|
+
const mtsPath = dtsPath.replace(".d.ts", ".d.mts")
|
|
264
|
+
if (fs.existsSync(ctsPath)) dtsPath = ctsPath
|
|
265
|
+
else if (fs.existsSync(mtsPath)) dtsPath = mtsPath
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
return { typesFile, dtsPath, source }
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
function normalizeCjsExports(exportsValue) {
|
|
274
|
+
if (exportsValue === null || exportsValue === undefined) {
|
|
275
|
+
return { default: exportsValue }
|
|
276
|
+
}
|
|
277
|
+
if (typeof exportsValue === "object" || typeof exportsValue === "function") {
|
|
278
|
+
return { ...exportsValue, default: exportsValue }
|
|
279
|
+
}
|
|
280
|
+
return { default: exportsValue }
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
function detectModuleFormat(resolvedPath, pkg) {
|
|
284
|
+
const ext = path.extname(resolvedPath)
|
|
285
|
+
if (ext === ".cjs" || ext === ".cts") return "cjs"
|
|
286
|
+
if (ext === ".mjs" || ext === ".mts") return "esm"
|
|
287
|
+
if (pkg?.type === "module") return "esm"
|
|
288
|
+
return "cjs"
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
function isProbablyClass(fn) {
|
|
292
|
+
if (typeof fn !== "function") return false
|
|
293
|
+
const source = Function.prototype.toString.call(fn)
|
|
294
|
+
if (source.startsWith("class ")) return true
|
|
295
|
+
if (fn.prototype) {
|
|
296
|
+
const protoProps = Object.getOwnPropertyNames(fn.prototype).filter((p) => p !== "constructor")
|
|
297
|
+
if (protoProps.length > 0) return true
|
|
298
|
+
}
|
|
299
|
+
return false
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
async function loadModuleExports(resolvedPath, require, pkg) {
|
|
303
|
+
const format = detectModuleFormat(resolvedPath, pkg)
|
|
304
|
+
if (format === "cjs") {
|
|
305
|
+
const mod = require(resolvedPath)
|
|
306
|
+
return { module: normalizeCjsExports(mod), format }
|
|
307
|
+
}
|
|
308
|
+
const mod = await import(pathToFileURL(resolvedPath).href)
|
|
309
|
+
return { module: mod, format }
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
function buildSymbolMatcher(symbols, fallbackFilter) {
|
|
313
|
+
const patterns = []
|
|
314
|
+
const addPattern = (value) => {
|
|
315
|
+
if (!value) return
|
|
316
|
+
if (value.startsWith("/") && value.endsWith("/") && value.length > 2) {
|
|
317
|
+
try {
|
|
318
|
+
patterns.push({ type: "regex", value: new RegExp(value.slice(1, -1), "i") })
|
|
319
|
+
return
|
|
320
|
+
} catch (e) {
|
|
321
|
+
patterns.push({ type: "substring", value: value.toLowerCase() })
|
|
322
|
+
return
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
if (value.includes("*")) {
|
|
326
|
+
const escaped = value.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*")
|
|
327
|
+
patterns.push({ type: "regex", value: new RegExp(`^${escaped}$`, "i") })
|
|
328
|
+
return
|
|
329
|
+
}
|
|
330
|
+
patterns.push({ type: "substring", value: value.toLowerCase() })
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
if (Array.isArray(symbols)) {
|
|
334
|
+
symbols.forEach(addPattern)
|
|
335
|
+
} else if (typeof symbols === "string") {
|
|
336
|
+
addPattern(symbols)
|
|
337
|
+
} else if (fallbackFilter) {
|
|
338
|
+
addPattern(fallbackFilter)
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
if (patterns.length === 0) return null
|
|
342
|
+
return (name) => {
|
|
343
|
+
const lower = name.toLowerCase()
|
|
344
|
+
return patterns.some((pattern) => {
|
|
345
|
+
if (pattern.type === "regex") return pattern.value.test(name)
|
|
346
|
+
return lower.includes(pattern.value)
|
|
347
|
+
})
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
function truncateSummary(text, mode, maxLen, truncateMode) {
|
|
352
|
+
if (!text) return ""
|
|
353
|
+
const normalized = text.replace(/\s+/g, " ").trim()
|
|
354
|
+
if (truncateMode === "none") return normalized
|
|
355
|
+
const limit = typeof maxLen === "number" ? maxLen : mode === "compact" ? 240 : 1200
|
|
356
|
+
if (normalized.length <= limit) return normalized
|
|
357
|
+
if (truncateMode === "sentence") {
|
|
358
|
+
const slice = normalized.slice(0, limit)
|
|
359
|
+
const lastPeriod = Math.max(slice.lastIndexOf("."), slice.lastIndexOf("!"), slice.lastIndexOf("?"))
|
|
360
|
+
if (lastPeriod > 40) {
|
|
361
|
+
return `${slice.slice(0, lastPeriod + 1)}`
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
if (truncateMode === "word") {
|
|
365
|
+
const slice = normalized.slice(0, limit)
|
|
366
|
+
const lastSpace = slice.lastIndexOf(" ")
|
|
367
|
+
if (lastSpace > 40) {
|
|
368
|
+
return `${slice.slice(0, lastSpace)}...`
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
return `${normalized.slice(0, Math.max(0, limit - 3))}...`
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
function formatJsdocEntry(name, doc, options) {
|
|
375
|
+
const mode = options.mode || "compact"
|
|
376
|
+
const truncateMode = options.truncate || "word"
|
|
377
|
+
const maxLen = options.maxLen
|
|
378
|
+
const sections = options.sections && options.sections.length > 0 ? options.sections : ["summary", "tags"]
|
|
379
|
+
const includeTags = options.tags?.include || null
|
|
380
|
+
const excludeTags = options.tags?.exclude || null
|
|
381
|
+
|
|
382
|
+
const summary = truncateSummary(doc.summary || "", mode, maxLen, truncateMode)
|
|
383
|
+
const tags = doc.tags || {}
|
|
384
|
+
const tagLines = []
|
|
385
|
+
|
|
386
|
+
const addTag = (tagName, values) => {
|
|
387
|
+
if (!values || values.length === 0) {
|
|
388
|
+
tagLines.push(`@${tagName}`)
|
|
389
|
+
return
|
|
390
|
+
}
|
|
391
|
+
for (const value of values) {
|
|
392
|
+
tagLines.push(value ? `@${tagName} ${value}` : `@${tagName}`)
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
const wantParams = sections.includes("params")
|
|
397
|
+
const wantReturns = sections.includes("returns")
|
|
398
|
+
const wantTags = sections.includes("tags")
|
|
399
|
+
|
|
400
|
+
if (wantParams) {
|
|
401
|
+
if (tags.param) addTag("param", tags.param)
|
|
402
|
+
}
|
|
403
|
+
if (wantReturns) {
|
|
404
|
+
if (tags.returns) addTag("returns", tags.returns)
|
|
405
|
+
if (tags.return) addTag("return", tags.return)
|
|
406
|
+
}
|
|
407
|
+
if (wantTags) {
|
|
408
|
+
for (const [tagName, values] of Object.entries(tags)) {
|
|
409
|
+
if (tagName === "param" || tagName === "returns" || tagName === "return") continue
|
|
410
|
+
if (includeTags && !includeTags.includes(tagName)) continue
|
|
411
|
+
if (excludeTags && excludeTags.includes(tagName)) continue
|
|
412
|
+
if (mode === "compact" && !includeTags && !excludeTags) {
|
|
413
|
+
if (!["deprecated", "since", "experimental"].includes(tagName)) continue
|
|
414
|
+
}
|
|
415
|
+
addTag(tagName, values)
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
const parts = []
|
|
420
|
+
if (sections.includes("summary") && summary) {
|
|
421
|
+
parts.push(summary)
|
|
422
|
+
}
|
|
423
|
+
if (tagLines.length > 0) {
|
|
424
|
+
parts.push(tagLines.join("; "))
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
return `${name}: ${parts.join(" | ")}`.trim()
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
function filterTypeInfo(typeInfo, filter, kindFilter) {
|
|
431
|
+
if (!typeInfo) return null
|
|
432
|
+
const includeName = (name) => !filter || name.toLowerCase().includes(filter)
|
|
433
|
+
const allow = (kind) => !kindFilter || kindFilter.length === 0 || kindFilter.includes(kind)
|
|
434
|
+
const includeExtras = !kindFilter || kindFilter.length === 0
|
|
435
|
+
|
|
436
|
+
const filtered = {
|
|
437
|
+
functions: {},
|
|
438
|
+
interfaces: {},
|
|
439
|
+
types: {},
|
|
440
|
+
classes: {},
|
|
441
|
+
enums: {},
|
|
442
|
+
namespaces: {},
|
|
443
|
+
defaults: [],
|
|
444
|
+
jsdoc: {},
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
if (allow("function")) {
|
|
448
|
+
for (const [name, info] of Object.entries(typeInfo.functions)) {
|
|
449
|
+
if (includeName(name)) filtered.functions[name] = info
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
if (allow("interface")) {
|
|
454
|
+
for (const [name, props] of Object.entries(typeInfo.interfaces)) {
|
|
455
|
+
if (includeName(name)) filtered.interfaces[name] = props
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
if (allow("type")) {
|
|
460
|
+
for (const [name, def] of Object.entries(typeInfo.types)) {
|
|
461
|
+
if (includeName(name)) filtered.types[name] = def
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
if (allow("class")) {
|
|
466
|
+
for (const [name, info] of Object.entries(typeInfo.classes)) {
|
|
467
|
+
if (includeName(name)) filtered.classes[name] = info
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
if (includeExtras) {
|
|
472
|
+
for (const [name, members] of Object.entries(typeInfo.enums || {})) {
|
|
473
|
+
if (includeName(name)) filtered.enums[name] = members
|
|
474
|
+
}
|
|
475
|
+
for (const [name, value] of Object.entries(typeInfo.namespaces || {})) {
|
|
476
|
+
if (includeName(name)) filtered.namespaces[name] = value
|
|
477
|
+
}
|
|
478
|
+
filtered.defaults = (typeInfo.defaults || []).filter((value) => includeName("default") || includeName(value))
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
if (typeInfo.jsdoc) {
|
|
482
|
+
for (const [name, doc] of Object.entries(typeInfo.jsdoc)) {
|
|
483
|
+
if (includeName(name)) filtered.jsdoc[name] = doc
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
return filtered
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
// Helper function to inspect object properties recursively
|
|
491
|
+
function inspectObject(obj, currentDepth = 0, maxDepth = 1, indent = " ") {
|
|
492
|
+
if (currentDepth >= maxDepth || obj === null || obj === undefined) {
|
|
493
|
+
return []
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
const lines = []
|
|
497
|
+
try {
|
|
498
|
+
const descriptors = Object.getOwnPropertyDescriptors(obj)
|
|
499
|
+
const keys = Object.keys(descriptors).slice(0, 10) // Limit to first 10 properties
|
|
500
|
+
for (const key of keys) {
|
|
501
|
+
try {
|
|
502
|
+
const descriptor = descriptors[key]
|
|
503
|
+
if (descriptor.get || descriptor.set) {
|
|
504
|
+
lines.push(`${indent.repeat(currentDepth + 1)}${key}: <getter>`)
|
|
505
|
+
continue
|
|
506
|
+
}
|
|
507
|
+
const value = descriptor.value
|
|
508
|
+
const type = typeof value
|
|
509
|
+
const prefix = indent.repeat(currentDepth + 1)
|
|
510
|
+
|
|
511
|
+
if (type === "function") {
|
|
512
|
+
const paramCount = value.length
|
|
513
|
+
lines.push(`${prefix}${key}(${paramCount} param${paramCount !== 1 ? "s" : ""})`)
|
|
514
|
+
} else if (type === "object" && value !== null) {
|
|
515
|
+
lines.push(`${prefix}${key}: {object}`)
|
|
516
|
+
if (currentDepth + 1 < maxDepth) {
|
|
517
|
+
lines.push(...inspectObject(value, currentDepth + 1, maxDepth, indent))
|
|
518
|
+
}
|
|
519
|
+
} else {
|
|
520
|
+
const valStr = type === "string" ? `"${String(value).substring(0, 30)}"` : String(value).substring(0, 30)
|
|
521
|
+
lines.push(`${prefix}${key}: ${valStr}`)
|
|
522
|
+
}
|
|
523
|
+
} catch (e) {
|
|
524
|
+
// Skip properties that throw on access
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
const totalKeys = Object.keys(descriptors).length
|
|
528
|
+
if (totalKeys > 10) {
|
|
529
|
+
lines.push(`${indent.repeat(currentDepth + 1)}... and ${totalKeys - 10} more`)
|
|
530
|
+
}
|
|
531
|
+
} catch (e) {
|
|
532
|
+
// Skip if object is not enumerable
|
|
533
|
+
}
|
|
534
|
+
return lines
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
export async function runInspect(options) {
|
|
538
|
+
const collect = !options?.write && !options?.writeError
|
|
539
|
+
const output = collect ? [] : null
|
|
540
|
+
const write = options?.write
|
|
541
|
+
const writeError = options?.writeError ?? options?.write
|
|
542
|
+
|
|
543
|
+
const log = (line = "") => {
|
|
544
|
+
if (collect) output.push(String(line))
|
|
545
|
+
else if (write) write(String(line))
|
|
546
|
+
}
|
|
547
|
+
const logErr = (line = "") => {
|
|
548
|
+
if (collect) output.push(String(line))
|
|
549
|
+
else if (writeError) writeError(String(line))
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
const target = options?.target
|
|
553
|
+
const filter = options?.filter ? options.filter.toLowerCase() : null
|
|
554
|
+
const showTypes = Boolean(options?.showTypes)
|
|
555
|
+
const jsdocModeRaw = options?.jsdoc ? String(options.jsdoc).toLowerCase() : null
|
|
556
|
+
const jsdocQuery = options?.jsdocQuery || null
|
|
557
|
+
const jsdocOutputRaw = options?.jsdocOutput ? String(options.jsdocOutput).toLowerCase() : null
|
|
558
|
+
const jsdocOutput = jsdocOutputRaw || (jsdocQuery ? "section" : "off")
|
|
559
|
+
const wantJsdoc = jsdocOutput !== "off"
|
|
560
|
+
const jsdocMode =
|
|
561
|
+
showTypes || wantJsdoc ? (jsdocQuery?.mode || jsdocModeRaw || "compact") : "off"
|
|
562
|
+
const kindFilter = Array.isArray(options?.kind)
|
|
563
|
+
? options.kind.map((k) => String(k).trim().toLowerCase())
|
|
564
|
+
: null
|
|
565
|
+
let depth = typeof options?.depth === "number" ? options.depth : 1
|
|
566
|
+
if (isNaN(depth) || depth < 0 || depth > 5) depth = 1
|
|
567
|
+
|
|
568
|
+
if (!target) {
|
|
569
|
+
logErr(
|
|
570
|
+
"Uso: node inspect.mjs <pacote> [filtro] [--filter VALUE] [--types] [--jsdoc off|compact|full] [--jsdoc-output off|section|inline|only] [--jsdoc-symbol NAME|glob|/re/] [--jsdoc-sections summary,params,returns,tags] [--jsdoc-tags t1,t2] [--jsdoc-tags-exclude t1,t2] [--jsdoc-truncate none|sentence|word] [--jsdoc-max-len N] [--kind function,class,...] [--depth N] [--resolve-from DIR]",
|
|
571
|
+
)
|
|
572
|
+
return collect ? output.join("\n") : ""
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
const baseCwd = options?.cwd
|
|
576
|
+
const resolveFrom = options?.resolveFrom
|
|
577
|
+
? path.resolve(baseCwd || process.cwd(), options.resolveFrom)
|
|
578
|
+
: baseCwd
|
|
579
|
+
if (baseCwd) {
|
|
580
|
+
try {
|
|
581
|
+
process.chdir(baseCwd)
|
|
582
|
+
} catch (e) {}
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
const resolution = await resolveTargetModule(target, baseCwd, resolveFrom)
|
|
586
|
+
const resolveCwd = resolution.resolveCwd || baseCwd
|
|
587
|
+
const require = createRequire(resolveCwd ? path.join(resolveCwd, "noop.js") : import.meta.url)
|
|
588
|
+
|
|
589
|
+
const flags = []
|
|
590
|
+
if (filter) flags.push(`Filtro: "${filter}"`)
|
|
591
|
+
if (kindFilter) flags.push(`Kind: ${kindFilter.join(",")}`)
|
|
592
|
+
if (showTypes || wantJsdoc) flags.push("Type Analysis")
|
|
593
|
+
if (jsdocOutput !== "off") flags.push(`JSDoc: ${jsdocMode}`)
|
|
594
|
+
if (depth > 1) flags.push(`Depth: ${depth}`)
|
|
595
|
+
|
|
596
|
+
const flagsStr = flags.length > 0 ? ` (${flags.join(" | ")})` : ""
|
|
597
|
+
log(`🔍 Target: ${target}${flagsStr}`)
|
|
598
|
+
|
|
599
|
+
try {
|
|
600
|
+
if (!resolution.resolved) {
|
|
601
|
+
logErr(`\n❌ Erro: Não foi possível resolver '${target}'`)
|
|
602
|
+
logErr(`ResolveFrom: ${resolveFrom || baseCwd || "unknown"}`)
|
|
603
|
+
logErr(`Certifique-se que '${target}' está instalado e é um caminho válido.`)
|
|
604
|
+
return collect ? output.join("\n") : ""
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
const basePkg = getPackageName(target)
|
|
608
|
+
const subpath = getPackageSubpath(target)
|
|
609
|
+
const pkgInfo = basePkg ? resolvePackageInfo(basePkg, require) : null
|
|
610
|
+
const pkg = pkgInfo?.pkg
|
|
611
|
+
const pkgDir = pkgInfo?.pkgDir
|
|
612
|
+
|
|
613
|
+
log(`\n🧭 Resolution:`)
|
|
614
|
+
log(` ResolveFrom: ${resolveFrom || baseCwd || "unknown"}`)
|
|
615
|
+
log(` Entrypoint: ${resolution.resolved}`)
|
|
616
|
+
if (resolution.resolver) {
|
|
617
|
+
log(` Resolver: ${resolution.resolver}`)
|
|
618
|
+
}
|
|
619
|
+
if (pkgDir) {
|
|
620
|
+
log(` PackageRoot: ${pkgDir}`)
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
let dtsPath
|
|
624
|
+
let typesFile
|
|
625
|
+
let typesSource
|
|
626
|
+
|
|
627
|
+
if (pkg) {
|
|
628
|
+
log(`\n📄 Package Info:`)
|
|
629
|
+
log(` Name: ${pkg.name || basePkg}`)
|
|
630
|
+
log(` Version: ${pkg.version || "Unknown"}`)
|
|
631
|
+
if (pkg.description) {
|
|
632
|
+
log(` Description: ${pkg.description}`)
|
|
633
|
+
}
|
|
634
|
+
if (pkg.license) {
|
|
635
|
+
log(` License: ${pkg.license}`)
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
const typesResolution = resolveTypesFile(pkg, pkgDir, subpath)
|
|
639
|
+
typesFile = typesResolution.typesFile
|
|
640
|
+
dtsPath = typesResolution.dtsPath
|
|
641
|
+
typesSource = typesResolution.source
|
|
642
|
+
|
|
643
|
+
if (typesFile) {
|
|
644
|
+
const sourceLabel = typesSource ? ` (${typesSource})` : ""
|
|
645
|
+
const existsLabel = dtsPath && fs.existsSync(dtsPath) ? "" : " (missing)"
|
|
646
|
+
log(` Types: ${typesFile}${sourceLabel}${existsLabel}`)
|
|
647
|
+
} else {
|
|
648
|
+
log(` Types: Not found`)
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
// === Mostrar subpath exports ===
|
|
652
|
+
if (pkg.exports && typeof pkg.exports === "object") {
|
|
653
|
+
const exportEntries = Object.entries(pkg.exports)
|
|
654
|
+
if (exportEntries.length > 0) {
|
|
655
|
+
log(`\n🚪 Subpath Exports (${exportEntries.length} available):`)
|
|
656
|
+
for (const [pathKey, value] of exportEntries.slice(0, 10)) {
|
|
657
|
+
if (typeof value === "string") {
|
|
658
|
+
log(` ${pathKey} → ${value}`)
|
|
659
|
+
} else if (value && typeof value === "object") {
|
|
660
|
+
const targets = Object.keys(value).join(", ")
|
|
661
|
+
log(` ${pathKey} → { ${targets} }`)
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
if (exportEntries.length > 10) {
|
|
665
|
+
log(` ... and ${exportEntries.length - 10} more`)
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
let typeInfoRaw = null
|
|
672
|
+
if ((showTypes || wantJsdoc) && dtsPath && fs.existsSync(dtsPath)) {
|
|
673
|
+
typeInfoRaw = parseDtsFile(dtsPath, null)
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
const { module: moduleNamespace } = await loadModuleExports(resolution.resolved, require, pkg)
|
|
677
|
+
const moduleDescriptors = Object.getOwnPropertyDescriptors(moduleNamespace)
|
|
678
|
+
const allExports = Object.keys(moduleDescriptors)
|
|
679
|
+
|
|
680
|
+
// Lógica de Filtro
|
|
681
|
+
let finalList = allExports
|
|
682
|
+
if (filter) {
|
|
683
|
+
finalList = allExports.filter((key) => key.toLowerCase().includes(filter))
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
// Se a lista for muito grande e não tiver filtro, avisa e corta
|
|
687
|
+
const LIMIT = 100
|
|
688
|
+
if (!filter && finalList.length > LIMIT) {
|
|
689
|
+
log(`\n⚠️ Módulo exporta ${finalList.length} itens. Mostrando os primeiros ${LIMIT}...`)
|
|
690
|
+
log(`DICA: Use o parâmetro 'filter' para encontrar o que procura.`)
|
|
691
|
+
finalList = finalList.slice(0, LIMIT)
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
// === MELHORIA 2: Categorizar exports por tipo ===
|
|
695
|
+
const categorized = {
|
|
696
|
+
functions: [],
|
|
697
|
+
classes: [],
|
|
698
|
+
objects: [],
|
|
699
|
+
primitives: [],
|
|
700
|
+
constants: [],
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
for (const key of finalList) {
|
|
704
|
+
const descriptor = moduleDescriptors[key]
|
|
705
|
+
if (!descriptor) continue
|
|
706
|
+
if (descriptor.get || descriptor.set) {
|
|
707
|
+
categorized.objects.push(key)
|
|
708
|
+
continue
|
|
709
|
+
}
|
|
710
|
+
const value = descriptor.value
|
|
711
|
+
const type = typeof value
|
|
712
|
+
|
|
713
|
+
if (type === "function") {
|
|
714
|
+
// Distinguir class vs function
|
|
715
|
+
if (isProbablyClass(value)) {
|
|
716
|
+
categorized.classes.push(key)
|
|
717
|
+
} else {
|
|
718
|
+
categorized.functions.push(key)
|
|
719
|
+
}
|
|
720
|
+
} else if (type === "object" && value !== null) {
|
|
721
|
+
categorized.objects.push(key)
|
|
722
|
+
} else if (type === "string" || type === "number" || type === "boolean") {
|
|
723
|
+
categorized.constants.push(key)
|
|
724
|
+
} else {
|
|
725
|
+
categorized.primitives.push(key)
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
// Prefer class from type info when available
|
|
730
|
+
if (typeInfoRaw && Object.keys(typeInfoRaw.classes).length > 0) {
|
|
731
|
+
const classNames = new Set(Object.keys(typeInfoRaw.classes))
|
|
732
|
+
categorized.functions = categorized.functions.filter((name) => {
|
|
733
|
+
if (classNames.has(name)) {
|
|
734
|
+
categorized.classes.push(name)
|
|
735
|
+
return false
|
|
736
|
+
}
|
|
737
|
+
return true
|
|
738
|
+
})
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
// Apply kind filter if specified
|
|
742
|
+
if (kindFilter && kindFilter.length > 0) {
|
|
743
|
+
const kindMap = {
|
|
744
|
+
function: "functions",
|
|
745
|
+
class: "classes",
|
|
746
|
+
object: "objects",
|
|
747
|
+
constant: "constants",
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
// Keep only the requested kinds
|
|
751
|
+
for (const [key, value] of Object.entries(categorized)) {
|
|
752
|
+
const shouldKeep = Object.entries(kindMap).some(([kind, catKey]) => kindFilter.includes(kind) && catKey === key)
|
|
753
|
+
if (!shouldKeep) {
|
|
754
|
+
categorized[key] = []
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
// Update finalList to only include filtered kinds
|
|
759
|
+
finalList = [...categorized.functions, ...categorized.classes, ...categorized.objects, ...categorized.constants]
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
// Mostrar exports categorizados
|
|
763
|
+
if (jsdocOutput !== "only") {
|
|
764
|
+
log(`\n🔑 Exports Encontrados (${finalList.length} total):`)
|
|
765
|
+
|
|
766
|
+
if (categorized.functions.length > 0) {
|
|
767
|
+
log(`\n 📘 Functions (${categorized.functions.length}):`)
|
|
768
|
+
log(` ${categorized.functions.join(", ")}`)
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
if (categorized.classes.length > 0) {
|
|
772
|
+
log(`\n 🏛️ Classes (${categorized.classes.length}):`)
|
|
773
|
+
log(` ${categorized.classes.join(", ")}`)
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
if (categorized.objects.length > 0) {
|
|
777
|
+
log(`\n 📦 Objects/Namespaces (${categorized.objects.length}):`)
|
|
778
|
+
log(` ${categorized.objects.join(", ")}`)
|
|
779
|
+
|
|
780
|
+
// If depth > 0, show object contents
|
|
781
|
+
if (depth > 0 && categorized.objects.length <= 10) {
|
|
782
|
+
log(`\n 📦 Object Contents (depth: ${depth}):`)
|
|
783
|
+
for (const objName of categorized.objects) {
|
|
784
|
+
log(`\n ${objName}:`)
|
|
785
|
+
const descriptor = moduleDescriptors[objName]
|
|
786
|
+
if (!descriptor || descriptor.get || descriptor.set) {
|
|
787
|
+
log(` ${objName}: <getter>`)
|
|
788
|
+
continue
|
|
789
|
+
}
|
|
790
|
+
const objValue = descriptor.value
|
|
791
|
+
const lines = inspectObject(objValue, 0, depth, " ")
|
|
792
|
+
lines.forEach((line) => log(` ${line}`))
|
|
793
|
+
}
|
|
794
|
+
} else if (depth > 0 && categorized.objects.length > 10) {
|
|
795
|
+
log(`\n ℹ️ Too many objects to show contents. Use 'filter' to narrow down.`)
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
if (categorized.constants.length > 0) {
|
|
800
|
+
log(`\n 🔢 Constants (${categorized.constants.length}):`)
|
|
801
|
+
log(` ${categorized.constants.join(", ")}`)
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
if (finalList.length === 0) {
|
|
805
|
+
log("Nenhum export corresponde ao filtro.")
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
// === MELHORIA 5: Mostrar assinaturas de funções ===
|
|
810
|
+
if (jsdocOutput !== "only") {
|
|
811
|
+
if (!showTypes && categorized.functions.length > 0 && categorized.functions.length <= 15) {
|
|
812
|
+
log(`\n✍️ Function Signatures:`)
|
|
813
|
+
for (const fname of categorized.functions) {
|
|
814
|
+
const descriptor = moduleDescriptors[fname]
|
|
815
|
+
const fn = descriptor?.value
|
|
816
|
+
if (typeof fn === "function") {
|
|
817
|
+
const paramCount = fn.length
|
|
818
|
+
const params = paramCount === 0 ? "" : paramCount === 1 ? "1 param" : `${paramCount} params`
|
|
819
|
+
log(` ${fname}(${params})`)
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
// Default export handling
|
|
825
|
+
const defaultDescriptor = moduleDescriptors.default
|
|
826
|
+
if (defaultDescriptor && (!filter || "default".includes(filter))) {
|
|
827
|
+
const defaultValue = defaultDescriptor.get || defaultDescriptor.set ? undefined : defaultDescriptor.value
|
|
828
|
+
const defaultType = typeof defaultValue
|
|
829
|
+
log(`\n📦 Default Export: ${defaultType}`)
|
|
830
|
+
if (defaultType === "function" && defaultValue && defaultValue.length !== undefined) {
|
|
831
|
+
log(` Parameters: ${defaultValue.length}`)
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
// === NEW: Parse .d.ts file if --types flag is present ===
|
|
837
|
+
if (showTypes || wantJsdoc) {
|
|
838
|
+
if (dtsPath && fs.existsSync(dtsPath)) {
|
|
839
|
+
if (jsdocOutput !== "only") {
|
|
840
|
+
log(`\n🔬 Type Definitions Analysis:`)
|
|
841
|
+
log(` Source: ${path.basename(dtsPath)}`)
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
const typeInfo = filterTypeInfo(typeInfoRaw, filter, kindFilter)
|
|
845
|
+
|
|
846
|
+
if (typeInfo) {
|
|
847
|
+
if (jsdocOutput !== "only") {
|
|
848
|
+
// Show function signatures with full type info
|
|
849
|
+
if (Object.keys(typeInfo.functions).length > 0) {
|
|
850
|
+
log(`\n 📘 Function Type Signatures:`)
|
|
851
|
+
for (const [name, info] of Object.entries(typeInfo.functions)) {
|
|
852
|
+
log(` ${name}(${info.params}): ${info.returnType}`)
|
|
853
|
+
if (jsdocOutput === "inline" && typeInfo.jsdoc?.[name]) {
|
|
854
|
+
const entry = formatJsdocEntry(name, typeInfo.jsdoc[name], {
|
|
855
|
+
mode: jsdocMode,
|
|
856
|
+
truncate: jsdocQuery?.truncate,
|
|
857
|
+
maxLen: jsdocQuery?.maxLen,
|
|
858
|
+
sections: jsdocQuery?.sections,
|
|
859
|
+
tags: jsdocQuery?.tags,
|
|
860
|
+
})
|
|
861
|
+
log(` ↳ ${entry}`)
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
// Show interfaces
|
|
867
|
+
if (Object.keys(typeInfo.interfaces).length > 0) {
|
|
868
|
+
log(`\n 📋 Interfaces:`)
|
|
869
|
+
for (const [name, props] of Object.entries(typeInfo.interfaces)) {
|
|
870
|
+
log(` interface ${name} {`)
|
|
871
|
+
props.forEach((prop) => log(` ${prop}`))
|
|
872
|
+
if (props.length === 5) {
|
|
873
|
+
log(` ... (truncated)`)
|
|
874
|
+
}
|
|
875
|
+
log(` }`)
|
|
876
|
+
if (jsdocOutput === "inline" && typeInfo.jsdoc?.[name]) {
|
|
877
|
+
const entry = formatJsdocEntry(name, typeInfo.jsdoc[name], {
|
|
878
|
+
mode: jsdocMode,
|
|
879
|
+
truncate: jsdocQuery?.truncate,
|
|
880
|
+
maxLen: jsdocQuery?.maxLen,
|
|
881
|
+
sections: jsdocQuery?.sections,
|
|
882
|
+
tags: jsdocQuery?.tags,
|
|
883
|
+
})
|
|
884
|
+
log(` ↳ ${entry}`)
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
// Show type aliases
|
|
890
|
+
if (Object.keys(typeInfo.types).length > 0) {
|
|
891
|
+
log(`\n 📝 Type Aliases:`)
|
|
892
|
+
for (const [name, definition] of Object.entries(typeInfo.types)) {
|
|
893
|
+
const shortDef = definition.length > 80 ? definition.substring(0, 80) + "..." : definition
|
|
894
|
+
log(` type ${name} = ${shortDef}`)
|
|
895
|
+
if (jsdocOutput === "inline" && typeInfo.jsdoc?.[name]) {
|
|
896
|
+
const entry = formatJsdocEntry(name, typeInfo.jsdoc[name], {
|
|
897
|
+
mode: jsdocMode,
|
|
898
|
+
truncate: jsdocQuery?.truncate,
|
|
899
|
+
maxLen: jsdocQuery?.maxLen,
|
|
900
|
+
sections: jsdocQuery?.sections,
|
|
901
|
+
tags: jsdocQuery?.tags,
|
|
902
|
+
})
|
|
903
|
+
log(` ↳ ${entry}`)
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
// Show class inheritance
|
|
909
|
+
if (Object.keys(typeInfo.classes).length > 0) {
|
|
910
|
+
log(`\n 🏛️ Class Definitions:`)
|
|
911
|
+
for (const [name, extendsClass] of Object.entries(typeInfo.classes)) {
|
|
912
|
+
const inheritance = extendsClass ? ` extends ${extendsClass}` : ""
|
|
913
|
+
log(` class ${name}${inheritance}`)
|
|
914
|
+
if (jsdocOutput === "inline" && typeInfo.jsdoc?.[name]) {
|
|
915
|
+
const entry = formatJsdocEntry(name, typeInfo.jsdoc[name], {
|
|
916
|
+
mode: jsdocMode,
|
|
917
|
+
truncate: jsdocQuery?.truncate,
|
|
918
|
+
maxLen: jsdocQuery?.maxLen,
|
|
919
|
+
sections: jsdocQuery?.sections,
|
|
920
|
+
tags: jsdocQuery?.tags,
|
|
921
|
+
})
|
|
922
|
+
log(` ↳ ${entry}`)
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
if (Object.keys(typeInfo.enums).length > 0) {
|
|
928
|
+
log(`\n 🧾 Enums:`)
|
|
929
|
+
for (const [name, members] of Object.entries(typeInfo.enums)) {
|
|
930
|
+
const preview = members.length > 0 ? ` = [${members.join(", ")}]` : ""
|
|
931
|
+
log(` enum ${name}${preview}`)
|
|
932
|
+
if (jsdocOutput === "inline" && typeInfo.jsdoc?.[name]) {
|
|
933
|
+
const entry = formatJsdocEntry(name, typeInfo.jsdoc[name], {
|
|
934
|
+
mode: jsdocMode,
|
|
935
|
+
truncate: jsdocQuery?.truncate,
|
|
936
|
+
maxLen: jsdocQuery?.maxLen,
|
|
937
|
+
sections: jsdocQuery?.sections,
|
|
938
|
+
tags: jsdocQuery?.tags,
|
|
939
|
+
})
|
|
940
|
+
log(` ↳ ${entry}`)
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
if (Object.keys(typeInfo.namespaces).length > 0) {
|
|
946
|
+
log(`\n 📦 Namespaces:`)
|
|
947
|
+
for (const name of Object.keys(typeInfo.namespaces)) {
|
|
948
|
+
log(` namespace ${name}`)
|
|
949
|
+
if (jsdocOutput === "inline" && typeInfo.jsdoc?.[name]) {
|
|
950
|
+
const entry = formatJsdocEntry(name, typeInfo.jsdoc[name], {
|
|
951
|
+
mode: jsdocMode,
|
|
952
|
+
truncate: jsdocQuery?.truncate,
|
|
953
|
+
maxLen: jsdocQuery?.maxLen,
|
|
954
|
+
sections: jsdocQuery?.sections,
|
|
955
|
+
tags: jsdocQuery?.tags,
|
|
956
|
+
})
|
|
957
|
+
log(` ↳ ${entry}`)
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
if (typeInfo.defaults.length > 0) {
|
|
963
|
+
log(`\n 📦 Default Exports:`)
|
|
964
|
+
typeInfo.defaults.slice(0, 5).forEach((value) => log(` default = ${value}`))
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
if (wantJsdoc && jsdocMode !== "off" && typeInfo.jsdoc && Object.keys(typeInfo.jsdoc).length > 0) {
|
|
969
|
+
const symbolMatcher = buildSymbolMatcher(jsdocQuery?.symbols, filter)
|
|
970
|
+
const entries = Object.entries(typeInfo.jsdoc)
|
|
971
|
+
.filter(([name]) => (symbolMatcher ? symbolMatcher(name) : true))
|
|
972
|
+
.slice(0, 50)
|
|
973
|
+
|
|
974
|
+
if (entries.length > 0) {
|
|
975
|
+
log(`\n 📚 JSDoc:`)
|
|
976
|
+
for (const [name, doc] of entries) {
|
|
977
|
+
const entry = formatJsdocEntry(name, doc, {
|
|
978
|
+
mode: jsdocMode,
|
|
979
|
+
truncate: jsdocQuery?.truncate,
|
|
980
|
+
maxLen: jsdocQuery?.maxLen,
|
|
981
|
+
sections: jsdocQuery?.sections,
|
|
982
|
+
tags: jsdocQuery?.tags,
|
|
983
|
+
})
|
|
984
|
+
log(` ${entry}`)
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
if (jsdocOutput !== "only") {
|
|
990
|
+
const typeExportNames = new Set([
|
|
991
|
+
...Object.keys(typeInfo.functions),
|
|
992
|
+
...Object.keys(typeInfo.interfaces),
|
|
993
|
+
...Object.keys(typeInfo.types),
|
|
994
|
+
...Object.keys(typeInfo.classes),
|
|
995
|
+
...Object.keys(typeInfo.enums),
|
|
996
|
+
...Object.keys(typeInfo.namespaces),
|
|
997
|
+
])
|
|
998
|
+
const runtimeNames = new Set(allExports)
|
|
999
|
+
const runtimeOnly = [...runtimeNames].filter((name) => !typeExportNames.has(name))
|
|
1000
|
+
const typesOnly = [...typeExportNames].filter((name) => !runtimeNames.has(name))
|
|
1001
|
+
|
|
1002
|
+
if (runtimeOnly.length > 0 || typesOnly.length > 0) {
|
|
1003
|
+
log(`\n ⚖️ Runtime/Types Mismatch:`)
|
|
1004
|
+
if (runtimeOnly.length > 0) {
|
|
1005
|
+
log(` Runtime only: ${runtimeOnly.slice(0, 10).join(", ")}`)
|
|
1006
|
+
}
|
|
1007
|
+
if (typesOnly.length > 0) {
|
|
1008
|
+
log(` Types only: ${typesOnly.slice(0, 10).join(", ")}`)
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
if (
|
|
1013
|
+
Object.keys(typeInfo.functions).length === 0 &&
|
|
1014
|
+
Object.keys(typeInfo.interfaces).length === 0 &&
|
|
1015
|
+
Object.keys(typeInfo.types).length === 0 &&
|
|
1016
|
+
Object.keys(typeInfo.classes).length === 0 &&
|
|
1017
|
+
Object.keys(typeInfo.enums).length === 0 &&
|
|
1018
|
+
Object.keys(typeInfo.namespaces).length === 0 &&
|
|
1019
|
+
typeInfo.defaults.length === 0
|
|
1020
|
+
) {
|
|
1021
|
+
log(` ⚠️ No type definitions found for filtered exports`)
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
} else {
|
|
1025
|
+
if (jsdocOutput !== "only") {
|
|
1026
|
+
log(` ⚠️ Could not parse type definitions`)
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
} else {
|
|
1030
|
+
if (jsdocOutput !== "only") {
|
|
1031
|
+
log(`\n⚠️ Type definitions not available for this package`)
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
} catch (e) {
|
|
1036
|
+
logErr(`\n❌ Erro: ${e.message}`)
|
|
1037
|
+
logErr(`Certifique-se que '${target}' está instalado e é um caminho válido.`)
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
return collect ? output.join("\n") : ""
|
|
1041
|
+
}
|