@deplens/core 0.1.2 → 0.1.4
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/README.md +77 -0
- package/package.json +1 -1
- package/src/inspect.mjs +176 -72
package/README.md
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# @deplens/core
|
|
2
|
+
|
|
3
|
+
Programmatic API for inspecting installed packages: runtime exports, parsed type signatures, and JSDoc.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm i @deplens/core
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```js
|
|
14
|
+
import { runInspect } from "@deplens/core";
|
|
15
|
+
|
|
16
|
+
const output = await runInspect({
|
|
17
|
+
target: "ai",
|
|
18
|
+
showTypes: true,
|
|
19
|
+
filter: "generate",
|
|
20
|
+
resolveFrom: process.cwd()
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
console.log(output);
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
`runInspect` returns a string **when no custom writers are provided**. If you pass `write` or `writeError`, it will stream to those instead.
|
|
27
|
+
|
|
28
|
+
## Options
|
|
29
|
+
|
|
30
|
+
- `target` (string, required): package name or import path (e.g. `react`, `next/server`)
|
|
31
|
+
- `filter` (string): substring filter for export names
|
|
32
|
+
- `showTypes` (boolean): include type signatures from `.d.ts`
|
|
33
|
+
- `kind` (string[]): filter by export kind (`function`, `class`, `object`, `constant`)
|
|
34
|
+
- `depth` (number): object inspection depth (0–5)
|
|
35
|
+
- `resolveFrom` (string): base directory for module resolution
|
|
36
|
+
- `cwd` (string): working directory for the inspection
|
|
37
|
+
- `write` (function): output sink (defaults to collecting and returning a string)
|
|
38
|
+
- `writeError` (function): error output sink
|
|
39
|
+
|
|
40
|
+
JSDoc options:
|
|
41
|
+
|
|
42
|
+
- `jsdoc` (string): `off` | `compact` | `full`
|
|
43
|
+
- `jsdocOutput` (string): `off` | `section` | `inline` | `only`
|
|
44
|
+
- `jsdocQuery` (object):
|
|
45
|
+
- `symbols`: string or string[]
|
|
46
|
+
- `sections`: `summary` | `params` | `returns` | `tags`
|
|
47
|
+
- `tags.include` / `tags.exclude`: string[]
|
|
48
|
+
- `mode`: `compact` | `full`
|
|
49
|
+
- `maxLen`: number
|
|
50
|
+
- `truncate`: `none` | `sentence` | `word`
|
|
51
|
+
|
|
52
|
+
Example: JSDoc focused on params/returns
|
|
53
|
+
|
|
54
|
+
```js
|
|
55
|
+
await runInspect({
|
|
56
|
+
target: "ai",
|
|
57
|
+
showTypes: true,
|
|
58
|
+
jsdocOutput: "section",
|
|
59
|
+
jsdocQuery: {
|
|
60
|
+
symbols: "generateText",
|
|
61
|
+
sections: ["params", "returns"],
|
|
62
|
+
tags: { include: ["param", "returns"] },
|
|
63
|
+
mode: "compact",
|
|
64
|
+
truncate: "sentence",
|
|
65
|
+
maxLen: 220
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Notes
|
|
71
|
+
|
|
72
|
+
- JSDoc is extracted from `.d.ts` declarations, not runtime JS.
|
|
73
|
+
- `--resolve-from` is essential in monorepos to avoid false negatives.
|
|
74
|
+
|
|
75
|
+
## License
|
|
76
|
+
|
|
77
|
+
MIT
|
package/package.json
CHANGED
package/src/inspect.mjs
CHANGED
|
@@ -135,7 +135,34 @@ async function resolveTargetModule(target, cwd, resolveFrom) {
|
|
|
135
135
|
return { resolved: null, resolveCwd: baseDir, resolver: null }
|
|
136
136
|
}
|
|
137
137
|
|
|
138
|
-
function
|
|
138
|
+
function findPackageJsonFromPath(startPath) {
|
|
139
|
+
if (!startPath) return null
|
|
140
|
+
let dir = path.dirname(startPath)
|
|
141
|
+
for (let i = 0; i < 10; i++) {
|
|
142
|
+
const candidate = path.join(dir, "package.json")
|
|
143
|
+
if (fs.existsSync(candidate)) return candidate
|
|
144
|
+
const parent = path.dirname(dir)
|
|
145
|
+
if (parent === dir) break
|
|
146
|
+
dir = parent
|
|
147
|
+
}
|
|
148
|
+
return null
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function findPackageJsonInNodeModules(startDir, basePkg) {
|
|
152
|
+
if (!startDir || !basePkg) return null
|
|
153
|
+
const segments = basePkg.split("/")
|
|
154
|
+
let dir = path.resolve(startDir)
|
|
155
|
+
while (true) {
|
|
156
|
+
const candidate = path.join(dir, "node_modules", ...segments, "package.json")
|
|
157
|
+
if (fs.existsSync(candidate)) return candidate
|
|
158
|
+
const parent = path.dirname(dir)
|
|
159
|
+
if (parent === dir) break
|
|
160
|
+
dir = parent
|
|
161
|
+
}
|
|
162
|
+
return null
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function resolvePackageInfo(basePkg, require, resolveFrom, resolvedPath) {
|
|
139
166
|
let pkgPath
|
|
140
167
|
let pkgDir
|
|
141
168
|
try {
|
|
@@ -157,6 +184,30 @@ function resolvePackageInfo(basePkg, require) {
|
|
|
157
184
|
} catch (err) {}
|
|
158
185
|
}
|
|
159
186
|
|
|
187
|
+
if (!pkgPath && resolveFrom && basePkg) {
|
|
188
|
+
const fallback = findPackageJsonInNodeModules(resolveFrom, basePkg)
|
|
189
|
+
if (fallback) {
|
|
190
|
+
pkgPath = fallback
|
|
191
|
+
pkgDir = path.dirname(fallback)
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
if (!pkgPath && resolvedPath) {
|
|
196
|
+
const fallback = findPackageJsonFromPath(resolvedPath)
|
|
197
|
+
if (fallback) {
|
|
198
|
+
pkgPath = fallback
|
|
199
|
+
pkgDir = path.dirname(fallback)
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (resolveFrom && basePkg) {
|
|
204
|
+
const rootCandidate = findPackageJsonInNodeModules(resolveFrom, basePkg)
|
|
205
|
+
if (rootCandidate && rootCandidate !== pkgPath) {
|
|
206
|
+
pkgPath = rootCandidate
|
|
207
|
+
pkgDir = path.dirname(rootCandidate)
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
160
211
|
if (!pkgPath || !fs.existsSync(pkgPath)) return null
|
|
161
212
|
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"))
|
|
162
213
|
return { pkg, pkgPath, pkgDir }
|
|
@@ -267,6 +318,29 @@ function resolveTypesFile(pkg, pkgDir, subpath) {
|
|
|
267
318
|
}
|
|
268
319
|
}
|
|
269
320
|
|
|
321
|
+
if (!fs.existsSync(dtsPath)) {
|
|
322
|
+
const altDir = path.dirname(dtsPath)
|
|
323
|
+
const altCandidates = [
|
|
324
|
+
"types.d.ts",
|
|
325
|
+
"types.d.mts",
|
|
326
|
+
"types.d.cts",
|
|
327
|
+
"index.d.ts",
|
|
328
|
+
"index.d.mts",
|
|
329
|
+
"index.d.cts",
|
|
330
|
+
]
|
|
331
|
+
for (const candidate of altCandidates) {
|
|
332
|
+
const altPath = path.join(altDir, candidate)
|
|
333
|
+
if (fs.existsSync(altPath)) {
|
|
334
|
+
dtsPath = altPath
|
|
335
|
+
typesFile = path.relative(pkgDir, altPath)
|
|
336
|
+
if (!source || source === "exports" || source === "package") {
|
|
337
|
+
source = "fallback"
|
|
338
|
+
}
|
|
339
|
+
break
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
270
344
|
return { typesFile, dtsPath, source }
|
|
271
345
|
}
|
|
272
346
|
|
|
@@ -585,6 +659,12 @@ export async function runInspect(options) {
|
|
|
585
659
|
const resolution = await resolveTargetModule(target, baseCwd, resolveFrom)
|
|
586
660
|
const resolveCwd = resolution.resolveCwd || baseCwd
|
|
587
661
|
const require = createRequire(resolveCwd ? path.join(resolveCwd, "noop.js") : import.meta.url)
|
|
662
|
+
const resolvedPath = resolution.resolved
|
|
663
|
+
const entrypointPath =
|
|
664
|
+
typeof resolvedPath === "string" && resolvedPath.startsWith("file://")
|
|
665
|
+
? fileURLToPath(resolvedPath)
|
|
666
|
+
: resolvedPath
|
|
667
|
+
const entrypointExists = entrypointPath ? fs.existsSync(entrypointPath) : false
|
|
588
668
|
|
|
589
669
|
const flags = []
|
|
590
670
|
if (filter) flags.push(`Filtro: "${filter}"`)
|
|
@@ -606,7 +686,9 @@ export async function runInspect(options) {
|
|
|
606
686
|
|
|
607
687
|
const basePkg = getPackageName(target)
|
|
608
688
|
const subpath = getPackageSubpath(target)
|
|
609
|
-
const pkgInfo = basePkg
|
|
689
|
+
const pkgInfo = basePkg
|
|
690
|
+
? resolvePackageInfo(basePkg, require, resolveFrom || baseCwd || process.cwd(), entrypointPath)
|
|
691
|
+
: null
|
|
610
692
|
const pkg = pkgInfo?.pkg
|
|
611
693
|
const pkgDir = pkgInfo?.pkgDir
|
|
612
694
|
|
|
@@ -673,9 +755,18 @@ export async function runInspect(options) {
|
|
|
673
755
|
typeInfoRaw = parseDtsFile(dtsPath, null)
|
|
674
756
|
}
|
|
675
757
|
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
758
|
+
let moduleNamespace = {}
|
|
759
|
+
let moduleDescriptors = {}
|
|
760
|
+
let allExports = []
|
|
761
|
+
const runtimeAvailable = Boolean(entrypointExists)
|
|
762
|
+
if (!runtimeAvailable) {
|
|
763
|
+
log(`\n⚠️ Entrypoint not found on disk; runtime exports skipped.`)
|
|
764
|
+
} else {
|
|
765
|
+
const { module: loadedNamespace } = await loadModuleExports(entrypointPath, require, pkg)
|
|
766
|
+
moduleNamespace = loadedNamespace
|
|
767
|
+
moduleDescriptors = Object.getOwnPropertyDescriptors(moduleNamespace)
|
|
768
|
+
allExports = Object.keys(moduleDescriptors)
|
|
769
|
+
}
|
|
679
770
|
|
|
680
771
|
// Lógica de Filtro
|
|
681
772
|
let finalList = allExports
|
|
@@ -700,67 +791,74 @@ export async function runInspect(options) {
|
|
|
700
791
|
constants: [],
|
|
701
792
|
}
|
|
702
793
|
|
|
703
|
-
|
|
704
|
-
const
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
794
|
+
if (runtimeAvailable) {
|
|
795
|
+
for (const key of finalList) {
|
|
796
|
+
const descriptor = moduleDescriptors[key]
|
|
797
|
+
if (!descriptor) continue
|
|
798
|
+
if (descriptor.get || descriptor.set) {
|
|
799
|
+
categorized.objects.push(key)
|
|
800
|
+
continue
|
|
801
|
+
}
|
|
802
|
+
const value = descriptor.value
|
|
803
|
+
const type = typeof value
|
|
712
804
|
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
805
|
+
if (type === "function") {
|
|
806
|
+
// Distinguir class vs function
|
|
807
|
+
if (isProbablyClass(value)) {
|
|
808
|
+
categorized.classes.push(key)
|
|
809
|
+
} else {
|
|
810
|
+
categorized.functions.push(key)
|
|
811
|
+
}
|
|
812
|
+
} else if (type === "object" && value !== null) {
|
|
813
|
+
categorized.objects.push(key)
|
|
814
|
+
} else if (type === "string" || type === "number" || type === "boolean") {
|
|
815
|
+
categorized.constants.push(key)
|
|
717
816
|
} else {
|
|
718
|
-
categorized.
|
|
817
|
+
categorized.primitives.push(key)
|
|
719
818
|
}
|
|
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
819
|
}
|
|
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
820
|
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
821
|
+
// Prefer class from type info when available
|
|
822
|
+
if (typeInfoRaw && Object.keys(typeInfoRaw.classes).length > 0) {
|
|
823
|
+
const classNames = new Set(Object.keys(typeInfoRaw.classes))
|
|
824
|
+
categorized.functions = categorized.functions.filter((name) => {
|
|
825
|
+
if (classNames.has(name)) {
|
|
826
|
+
categorized.classes.push(name)
|
|
827
|
+
return false
|
|
828
|
+
}
|
|
829
|
+
return true
|
|
830
|
+
})
|
|
748
831
|
}
|
|
749
832
|
|
|
750
|
-
//
|
|
751
|
-
|
|
752
|
-
const
|
|
753
|
-
|
|
754
|
-
|
|
833
|
+
// Apply kind filter if specified
|
|
834
|
+
if (kindFilter && kindFilter.length > 0) {
|
|
835
|
+
const kindMap = {
|
|
836
|
+
function: "functions",
|
|
837
|
+
class: "classes",
|
|
838
|
+
object: "objects",
|
|
839
|
+
constant: "constants",
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
// Keep only the requested kinds
|
|
843
|
+
for (const [key, value] of Object.entries(categorized)) {
|
|
844
|
+
const shouldKeep = Object.entries(kindMap).some(
|
|
845
|
+
([kind, catKey]) => kindFilter.includes(kind) && catKey === key,
|
|
846
|
+
)
|
|
847
|
+
if (!shouldKeep) {
|
|
848
|
+
categorized[key] = []
|
|
849
|
+
}
|
|
755
850
|
}
|
|
756
|
-
}
|
|
757
851
|
|
|
758
|
-
|
|
759
|
-
|
|
852
|
+
// Update finalList to only include filtered kinds
|
|
853
|
+
finalList = [...categorized.functions, ...categorized.classes, ...categorized.objects, ...categorized.constants]
|
|
854
|
+
}
|
|
760
855
|
}
|
|
761
856
|
|
|
762
857
|
// Mostrar exports categorizados
|
|
763
858
|
if (jsdocOutput !== "only") {
|
|
859
|
+
if (!runtimeAvailable) {
|
|
860
|
+
log(`\nℹ️ Runtime exports unavailable. Use --types to inspect type exports.`)
|
|
861
|
+
}
|
|
764
862
|
log(`\n🔑 Exports Encontrados (${finalList.length} total):`)
|
|
765
863
|
|
|
766
864
|
if (categorized.functions.length > 0) {
|
|
@@ -808,7 +906,9 @@ export async function runInspect(options) {
|
|
|
808
906
|
|
|
809
907
|
// === MELHORIA 5: Mostrar assinaturas de funções ===
|
|
810
908
|
if (jsdocOutput !== "only") {
|
|
811
|
-
if (!
|
|
909
|
+
if (!runtimeAvailable) {
|
|
910
|
+
// Skip runtime-only signature/default export hints when entrypoint is missing
|
|
911
|
+
} else if (!showTypes && categorized.functions.length > 0 && categorized.functions.length <= 15) {
|
|
812
912
|
log(`\n✍️ Function Signatures:`)
|
|
813
913
|
for (const fname of categorized.functions) {
|
|
814
914
|
const descriptor = moduleDescriptors[fname]
|
|
@@ -822,13 +922,15 @@ export async function runInspect(options) {
|
|
|
822
922
|
}
|
|
823
923
|
|
|
824
924
|
// Default export handling
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
925
|
+
if (runtimeAvailable) {
|
|
926
|
+
const defaultDescriptor = moduleDescriptors.default
|
|
927
|
+
if (defaultDescriptor && (!filter || "default".includes(filter))) {
|
|
928
|
+
const defaultValue = defaultDescriptor.get || defaultDescriptor.set ? undefined : defaultDescriptor.value
|
|
929
|
+
const defaultType = typeof defaultValue
|
|
930
|
+
log(`\n📦 Default Export: ${defaultType}`)
|
|
931
|
+
if (defaultType === "function" && defaultValue && defaultValue.length !== undefined) {
|
|
932
|
+
log(` Parameters: ${defaultValue.length}`)
|
|
933
|
+
}
|
|
832
934
|
}
|
|
833
935
|
}
|
|
834
936
|
}
|
|
@@ -995,17 +1097,19 @@ export async function runInspect(options) {
|
|
|
995
1097
|
...Object.keys(typeInfo.enums),
|
|
996
1098
|
...Object.keys(typeInfo.namespaces),
|
|
997
1099
|
])
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1100
|
+
if (runtimeAvailable) {
|
|
1101
|
+
const runtimeNames = new Set(allExports)
|
|
1102
|
+
const runtimeOnly = [...runtimeNames].filter((name) => !typeExportNames.has(name))
|
|
1103
|
+
const typesOnly = [...typeExportNames].filter((name) => !runtimeNames.has(name))
|
|
1104
|
+
|
|
1105
|
+
if (runtimeOnly.length > 0 || typesOnly.length > 0) {
|
|
1106
|
+
log(`\n ⚖️ Runtime/Types Mismatch:`)
|
|
1107
|
+
if (runtimeOnly.length > 0) {
|
|
1108
|
+
log(` Runtime only: ${runtimeOnly.slice(0, 10).join(", ")}`)
|
|
1109
|
+
}
|
|
1110
|
+
if (typesOnly.length > 0) {
|
|
1111
|
+
log(` Types only: ${typesOnly.slice(0, 10).join(", ")}`)
|
|
1112
|
+
}
|
|
1009
1113
|
}
|
|
1010
1114
|
}
|
|
1011
1115
|
|