@dep-radius/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.
Files changed (157) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +48 -0
  3. package/dist/analyze/brief.d.ts +18 -0
  4. package/dist/analyze/brief.d.ts.map +1 -0
  5. package/dist/analyze/brief.js +89 -0
  6. package/dist/analyze/verdict.d.ts +16 -0
  7. package/dist/analyze/verdict.d.ts.map +1 -0
  8. package/dist/analyze/verdict.js +134 -0
  9. package/dist/context.d.ts +4 -0
  10. package/dist/context.d.ts.map +1 -0
  11. package/dist/context.js +36 -0
  12. package/dist/debug.d.ts +2 -0
  13. package/dist/debug.d.ts.map +1 -0
  14. package/dist/debug.js +130 -0
  15. package/dist/index.d.ts +9 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +8 -0
  18. package/dist/infra/cache.d.ts +18 -0
  19. package/dist/infra/cache.d.ts.map +1 -0
  20. package/dist/infra/cache.js +66 -0
  21. package/dist/infra/hash.d.ts +4 -0
  22. package/dist/infra/hash.d.ts.map +1 -0
  23. package/dist/infra/hash.js +18 -0
  24. package/dist/infra/http.d.ts +24 -0
  25. package/dist/infra/http.d.ts.map +1 -0
  26. package/dist/infra/http.js +44 -0
  27. package/dist/infra/limit.d.ts +4 -0
  28. package/dist/infra/limit.d.ts.map +1 -0
  29. package/dist/infra/limit.js +34 -0
  30. package/dist/infra/log.d.ts +8 -0
  31. package/dist/infra/log.d.ts.map +1 -0
  32. package/dist/infra/log.js +13 -0
  33. package/dist/inventory/installed.d.ts +15 -0
  34. package/dist/inventory/installed.d.ts.map +1 -0
  35. package/dist/inventory/installed.js +241 -0
  36. package/dist/inventory/lockfiles/bun.d.ts +3 -0
  37. package/dist/inventory/lockfiles/bun.d.ts.map +1 -0
  38. package/dist/inventory/lockfiles/bun.js +24 -0
  39. package/dist/inventory/lockfiles/npm.d.ts +3 -0
  40. package/dist/inventory/lockfiles/npm.d.ts.map +1 -0
  41. package/dist/inventory/lockfiles/npm.js +29 -0
  42. package/dist/inventory/lockfiles/pnpm.d.ts +3 -0
  43. package/dist/inventory/lockfiles/pnpm.d.ts.map +1 -0
  44. package/dist/inventory/lockfiles/pnpm.js +84 -0
  45. package/dist/inventory/lockfiles/types.d.ts +9 -0
  46. package/dist/inventory/lockfiles/types.d.ts.map +1 -0
  47. package/dist/inventory/lockfiles/types.js +1 -0
  48. package/dist/inventory/lockfiles/yarn.d.ts +3 -0
  49. package/dist/inventory/lockfiles/yarn.d.ts.map +1 -0
  50. package/dist/inventory/lockfiles/yarn.js +46 -0
  51. package/dist/inventory/manifests.d.ts +9 -0
  52. package/dist/inventory/manifests.d.ts.map +1 -0
  53. package/dist/inventory/manifests.js +135 -0
  54. package/dist/inventory/specifiers.d.ts +8 -0
  55. package/dist/inventory/specifiers.d.ts.map +1 -0
  56. package/dist/inventory/specifiers.js +53 -0
  57. package/dist/labels.d.ts +2 -0
  58. package/dist/labels.d.ts.map +1 -0
  59. package/dist/labels.js +18 -0
  60. package/dist/model.d.ts +276 -0
  61. package/dist/model.d.ts.map +1 -0
  62. package/dist/model.js +2 -0
  63. package/dist/notes/changelog.d.ts +11 -0
  64. package/dist/notes/changelog.d.ts.map +1 -0
  65. package/dist/notes/changelog.js +60 -0
  66. package/dist/notes/collect.d.ts +13 -0
  67. package/dist/notes/collect.d.ts.map +1 -0
  68. package/dist/notes/collect.js +225 -0
  69. package/dist/notes/entries.d.ts +3 -0
  70. package/dist/notes/entries.d.ts.map +1 -0
  71. package/dist/notes/entries.js +209 -0
  72. package/dist/notes/github.d.ts +25 -0
  73. package/dist/notes/github.d.ts.map +1 -0
  74. package/dist/notes/github.js +132 -0
  75. package/dist/notes/match.d.ts +13 -0
  76. package/dist/notes/match.d.ts.map +1 -0
  77. package/dist/notes/match.js +75 -0
  78. package/dist/notes/repo-url.d.ts +9 -0
  79. package/dist/notes/repo-url.d.ts.map +1 -0
  80. package/dist/notes/repo-url.js +46 -0
  81. package/dist/options.d.ts +53 -0
  82. package/dist/options.d.ts.map +1 -0
  83. package/dist/options.js +27 -0
  84. package/dist/registry/candidates.d.ts +24 -0
  85. package/dist/registry/candidates.d.ts.map +1 -0
  86. package/dist/registry/candidates.js +139 -0
  87. package/dist/registry/npmrc.d.ts +13 -0
  88. package/dist/registry/npmrc.d.ts.map +1 -0
  89. package/dist/registry/npmrc.js +99 -0
  90. package/dist/registry/packument.d.ts +34 -0
  91. package/dist/registry/packument.d.ts.map +1 -0
  92. package/dist/registry/packument.js +85 -0
  93. package/dist/registry/tar.d.ts +2 -0
  94. package/dist/registry/tar.d.ts.map +1 -0
  95. package/dist/registry/tar.js +75 -0
  96. package/dist/registry/tarball.d.ts +16 -0
  97. package/dist/registry/tarball.d.ts.map +1 -0
  98. package/dist/registry/tarball.js +59 -0
  99. package/dist/render/groups.d.ts +16 -0
  100. package/dist/render/groups.d.ts.map +1 -0
  101. package/dist/render/groups.js +105 -0
  102. package/dist/render/index.d.ts +2 -0
  103. package/dist/render/index.d.ts.map +1 -0
  104. package/dist/render/index.js +3 -0
  105. package/dist/render/json.d.ts +119 -0
  106. package/dist/render/json.d.ts.map +1 -0
  107. package/dist/render/json.js +130 -0
  108. package/dist/render/limits.d.ts +3 -0
  109. package/dist/render/limits.d.ts.map +1 -0
  110. package/dist/render/limits.js +25 -0
  111. package/dist/render/markdown.d.ts +3 -0
  112. package/dist/render/markdown.d.ts.map +1 -0
  113. package/dist/render/markdown.js +62 -0
  114. package/dist/run.d.ts +10 -0
  115. package/dist/run.d.ts.map +1 -0
  116. package/dist/run.js +218 -0
  117. package/dist/surface/analyze.d.ts +13 -0
  118. package/dist/surface/analyze.d.ts.map +1 -0
  119. package/dist/surface/analyze.js +166 -0
  120. package/dist/surface/delta.d.ts +5 -0
  121. package/dist/surface/delta.d.ts.map +1 -0
  122. package/dist/surface/delta.js +173 -0
  123. package/dist/surface/entries.d.ts +16 -0
  124. package/dist/surface/entries.d.ts.map +1 -0
  125. package/dist/surface/entries.js +187 -0
  126. package/dist/surface/extract.d.ts +15 -0
  127. package/dist/surface/extract.d.ts.map +1 -0
  128. package/dist/surface/extract.js +460 -0
  129. package/dist/surface/signature.d.ts +6 -0
  130. package/dist/surface/signature.d.ts.map +1 -0
  131. package/dist/surface/signature.js +229 -0
  132. package/dist/surface/vfs-host.d.ts +5 -0
  133. package/dist/surface/vfs-host.d.ts.map +1 -0
  134. package/dist/surface/vfs-host.js +54 -0
  135. package/dist/symbol-path.d.ts +28 -0
  136. package/dist/symbol-path.d.ts.map +1 -0
  137. package/dist/symbol-path.js +223 -0
  138. package/dist/usage/files.d.ts +18 -0
  139. package/dist/usage/files.d.ts.map +1 -0
  140. package/dist/usage/files.js +83 -0
  141. package/dist/usage/link.d.ts +23 -0
  142. package/dist/usage/link.d.ts.map +1 -0
  143. package/dist/usage/link.js +588 -0
  144. package/dist/usage/opaque.d.ts +7 -0
  145. package/dist/usage/opaque.d.ts.map +1 -0
  146. package/dist/usage/opaque.js +193 -0
  147. package/dist/usage/parse.d.ts +73 -0
  148. package/dist/usage/parse.d.ts.map +1 -0
  149. package/dist/usage/parse.js +608 -0
  150. package/dist/usage/resolve-local.d.ts +35 -0
  151. package/dist/usage/resolve-local.d.ts.map +1 -0
  152. package/dist/usage/resolve-local.js +340 -0
  153. package/dist/usage/scan.d.ts +4 -0
  154. package/dist/usage/scan.d.ts.map +1 -0
  155. package/dist/usage/scan.js +92 -0
  156. package/package.json +79 -0
  157. package/schema/brief-v1.schema.json +319 -0
@@ -0,0 +1,229 @@
1
+ import ts from "typescript";
2
+ import { sha1 } from "../infra/hash.js";
3
+ // Bump when a normalization changes: the cache key carries it, so old surfaces are never compared
4
+ // with new ones.
5
+ export const ALGO = 8;
6
+ const FLAGS = ts.TypeFormatFlags.NoTruncation |
7
+ ts.TypeFormatFlags.UseAliasDefinedOutsideCurrentScope |
8
+ ts.TypeFormatFlags.WriteArrowStyleSignature |
9
+ ts.TypeFormatFlags.OmitParameterModifiers |
10
+ ts.TypeFormatFlags.WriteTypeArgumentsOfSignature;
11
+ const MAX_LEN = 3000;
12
+ export function typeText(checker, type, typeParams = []) {
13
+ let s = checker.typeToString(type, undefined, FLAGS);
14
+ s = renameTypeParams(s, typeParams);
15
+ return normalizeTypeText(s);
16
+ }
17
+ // Parameter names are dropped (renaming one breaks nobody) and type parameters are renamed by
18
+ // position, so `<T>(value: T) => T` and `<U>(v: U) => U` print the same.
19
+ export function signatureText(checker, sig) {
20
+ const tps = sig.getTypeParameters() ?? [];
21
+ const names = tps.map((tp) => tp.symbol?.name ?? "T");
22
+ const tpText = tps.map((tp, i) => {
23
+ const c = tp.getConstraint();
24
+ return c ? `$T${i} extends ${typeText(checker, c, names)}` : `$T${i}`;
25
+ });
26
+ const params = sig.getParameters().map((p) => {
27
+ const decl = p.valueDeclaration;
28
+ const type = decl
29
+ ? checker.getTypeOfSymbolAtLocation(p, decl)
30
+ : checker.getTypeOfSymbol(p);
31
+ const rest = !!decl?.dotDotDotToken;
32
+ const optional = !!decl && (!!decl.questionToken || !!decl.initializer);
33
+ return `${rest ? "..." : ""}${typeText(checker, type, names)}${optional ? "?" : ""}`;
34
+ });
35
+ const ret = typeText(checker, checker.getReturnTypeOfSignature(sig), names);
36
+ const out = `${tpText.length > 0 ? `<${tpText.join(", ")}>` : ""}(${params.join(", ")}) => ${ret}`;
37
+ return out.length > MAX_LEN ? `#${sha1(out)}` : out;
38
+ }
39
+ function renameTypeParams(s, names) {
40
+ let out = s;
41
+ names.forEach((n, i) => {
42
+ if (!n || n.startsWith("$T"))
43
+ return;
44
+ out = out.replace(new RegExp(`(?<![\\w$.])${n.replace(/[$]/g, "\\$")}(?![\\w$])`, "g"), `$T${i}`);
45
+ });
46
+ return out;
47
+ }
48
+ export function normalizeTypeText(input) {
49
+ let s = stripQualifiers(input.replace(/import\("[^"]*"\)\./g, ""))
50
+ .replace(/\s+/g, " ")
51
+ .replace(/;\s*}/g, " }")
52
+ .trim();
53
+ s = sortOperands(s);
54
+ return s.length > MAX_LEN ? `#${sha1(s)}` : s;
55
+ }
56
+ // `ui.Component` and `Component` are the same type printed
57
+ // through two import styles; the qualifier follows how a declaration file imports, not the API.
58
+ function stripQualifiers(s) {
59
+ let out = "";
60
+ let inStr;
61
+ for (let i = 0; i < s.length; i++) {
62
+ const ch = s[i];
63
+ if (inStr) {
64
+ out += ch;
65
+ if (ch === inStr && s[i - 1] !== "\\")
66
+ inStr = undefined;
67
+ continue;
68
+ }
69
+ if (ch === '"' || ch === "'" || ch === "`") {
70
+ inStr = ch;
71
+ out += ch;
72
+ continue;
73
+ }
74
+ const m = /^[A-Za-z_$][\w$]*\.(?=[A-Za-z_$])/.exec(s.slice(i));
75
+ const prev = s[i - 1];
76
+ if (m && (prev === undefined || !/[\w$.]/.test(prev))) {
77
+ // drop every qualifier in a row: a.b.C -> C
78
+ let j = i + m[0].length;
79
+ for (let n = /^[A-Za-z_$][\w$]*\.(?=[A-Za-z_$])/.exec(s.slice(j)); n; n = /^[A-Za-z_$][\w$]*\.(?=[A-Za-z_$])/.exec(s.slice(j)))
80
+ j += n[0].length;
81
+ i = j - 1;
82
+ continue;
83
+ }
84
+ out += ch;
85
+ }
86
+ return out;
87
+ }
88
+ // Union and intersection members print in type-id order, which moves when unrelated code changes.
89
+ // Sort them at every bracket depth.
90
+ function sortOperands(s) {
91
+ // `error?: string | undefined` inside an object type: the label is not a union member
92
+ const label = /^((?:readonly\s+)?(?:[\w$]+|"[^"]*"|'[^']*'|\[[^\]]*\])\??:\s*)/.exec(s);
93
+ if (label?.[1])
94
+ return label[1] + sortOperands(s.slice(label[1].length));
95
+ const parts = splitTop(s, ["|", "&"]);
96
+ if (parts.items.length > 1) {
97
+ const op = parts.op;
98
+ return parts.items
99
+ .map((p) => sortOperands(p.trim()))
100
+ .sort()
101
+ .join(` ${op} `);
102
+ }
103
+ let out = "";
104
+ let i = 0;
105
+ while (i < s.length) {
106
+ const ch = s[i];
107
+ if (ch === "(" || ch === "<" || ch === "[" || ch === "{") {
108
+ const close = matching(s, i);
109
+ if (close < 0)
110
+ return s;
111
+ const inner = s.slice(i + 1, close);
112
+ out +=
113
+ ch +
114
+ splitSeparators(inner)
115
+ .map((seg) => {
116
+ const lead = seg.match(/^\s*/)?.[0] ?? "";
117
+ const trail = seg.slice(lead.length).match(/\s*[,;]?\s*$/)?.[0] ?? "";
118
+ return (lead +
119
+ sortOperands(seg.slice(lead.length, seg.length - trail.length)) +
120
+ trail);
121
+ })
122
+ .join("") +
123
+ s[close];
124
+ i = close + 1;
125
+ }
126
+ else {
127
+ out += ch;
128
+ i++;
129
+ }
130
+ }
131
+ return out;
132
+ }
133
+ // "a, B<c, d>; e" -> ["a, ", "B<c, d>; ", "e"]: separators at depth zero only, kept on their segment
134
+ function splitSeparators(s) {
135
+ const out = [];
136
+ let depth = 0;
137
+ let inStr;
138
+ let cur = "";
139
+ for (let i = 0; i < s.length; i++) {
140
+ const ch = s[i];
141
+ cur += ch;
142
+ if (inStr) {
143
+ if (ch === inStr && s[i - 1] !== "\\")
144
+ inStr = undefined;
145
+ continue;
146
+ }
147
+ if (ch === '"' || ch === "'" || ch === "`")
148
+ inStr = ch;
149
+ else if ("(<[{".includes(ch))
150
+ depth++;
151
+ else if (")]}".includes(ch) || (ch === ">" && s[i - 1] !== "="))
152
+ depth--;
153
+ else if (depth === 0 && (ch === "," || ch === ";")) {
154
+ out.push(cur);
155
+ cur = "";
156
+ }
157
+ }
158
+ if (cur)
159
+ out.push(cur);
160
+ return out;
161
+ }
162
+ function splitTop(s, ops) {
163
+ let depth = 0;
164
+ let inStr;
165
+ const items = [];
166
+ let cur = "";
167
+ let op;
168
+ for (let i = 0; i < s.length; i++) {
169
+ const ch = s[i];
170
+ if (inStr) {
171
+ cur += ch;
172
+ if (ch === inStr && s[i - 1] !== "\\")
173
+ inStr = undefined;
174
+ continue;
175
+ }
176
+ if (ch === '"' || ch === "'" || ch === "`") {
177
+ inStr = ch;
178
+ cur += ch;
179
+ continue;
180
+ }
181
+ if ("(<[{".includes(ch))
182
+ depth++;
183
+ else if (")>]}".includes(ch) && !(ch === ">" && s[i - 1] === "="))
184
+ depth--;
185
+ if (depth === 0 && ops.includes(ch) && s[i + 1] !== ch && s[i - 1] !== ch) {
186
+ if (op && op !== ch)
187
+ return { items: [s] };
188
+ op = ch;
189
+ items.push(cur);
190
+ cur = "";
191
+ continue;
192
+ }
193
+ cur += ch;
194
+ }
195
+ items.push(cur);
196
+ return items.length > 1 ? { items, op: op } : { items: [s] };
197
+ }
198
+ function matching(s, open) {
199
+ const pairs = {
200
+ "(": ")",
201
+ "<": ">",
202
+ "[": "]",
203
+ "{": "}",
204
+ };
205
+ const stack = [];
206
+ let inStr;
207
+ for (let i = open; i < s.length; i++) {
208
+ const ch = s[i];
209
+ if (inStr) {
210
+ if (ch === inStr && s[i - 1] !== "\\")
211
+ inStr = undefined;
212
+ continue;
213
+ }
214
+ if (ch === '"' || ch === "'" || ch === "`") {
215
+ inStr = ch;
216
+ continue;
217
+ }
218
+ if (pairs[ch])
219
+ stack.push(pairs[ch]);
220
+ else if (ch === ">" && s[i - 1] === "=")
221
+ continue;
222
+ else if (ch === stack[stack.length - 1]) {
223
+ stack.pop();
224
+ if (stack.length === 0)
225
+ return i;
226
+ }
227
+ }
228
+ return -1;
229
+ }
@@ -0,0 +1,5 @@
1
+ import ts from "typescript";
2
+ export declare const PKG_ROOT = "/pkg";
3
+ export declare function createVfsHost(files: Map<string, Buffer>): ts.CompilerHost;
4
+ export declare function libPath(name: string): string;
5
+ //# sourceMappingURL=vfs-host.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vfs-host.d.ts","sourceRoot":"","sources":["../../src/surface/vfs-host.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,MAAM,YAAY,CAAA;AAE3B,eAAO,MAAM,QAAQ,SAAS,CAAA;AAO9B,wBAAgB,aAAa,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,EAAE,CAAC,YAAY,CAiDzE;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE5C"}
@@ -0,0 +1,54 @@
1
+ import { dirname, join } from "node:path";
2
+ import { existsSync, readFileSync } from "node:fs";
3
+ import ts from "typescript";
4
+ export const PKG_ROOT = "/pkg";
5
+ const libDir = dirname(ts.getDefaultLibFilePath({}));
6
+ const libSources = new Map();
7
+ // A compiler host that sees the tarball's declarations under /pkg and the TypeScript lib files the
8
+ // tool itself bundles, nothing else: the user's node_modules can never change a surface.
9
+ export function createVfsHost(files) {
10
+ const texts = new Map();
11
+ const dirs = new Set([PKG_ROOT]);
12
+ for (const [rel, buf] of files) {
13
+ const abs = `${PKG_ROOT}/${rel}`;
14
+ texts.set(abs, buf.toString("utf8"));
15
+ let d = dirname(abs);
16
+ while (d.startsWith(PKG_ROOT) && !dirs.has(d)) {
17
+ dirs.add(d);
18
+ d = dirname(d);
19
+ }
20
+ }
21
+ const isLib = (f) => f.startsWith(libDir);
22
+ return {
23
+ getSourceFile(fileName, languageVersion) {
24
+ if (isLib(fileName)) {
25
+ let sf = libSources.get(fileName);
26
+ if (!sf && existsSync(fileName)) {
27
+ sf = ts.createSourceFile(fileName, readFileSync(fileName, "utf8"), languageVersion, false);
28
+ libSources.set(fileName, sf);
29
+ }
30
+ return sf;
31
+ }
32
+ const text = texts.get(fileName);
33
+ return text === undefined
34
+ ? undefined
35
+ : ts.createSourceFile(fileName, text, languageVersion, false);
36
+ },
37
+ getDefaultLibFileName: (o) => ts.getDefaultLibFilePath(o),
38
+ getDefaultLibLocation: () => libDir,
39
+ writeFile: () => { },
40
+ getCurrentDirectory: () => PKG_ROOT,
41
+ getCanonicalFileName: (f) => f,
42
+ useCaseSensitiveFileNames: () => true,
43
+ getNewLine: () => "\n",
44
+ fileExists: (f) => texts.has(f) || (isLib(f) && existsSync(f)),
45
+ readFile: (f) => texts.get(f) ??
46
+ (isLib(f) && existsSync(f) ? readFileSync(f, "utf8") : undefined),
47
+ directoryExists: (d) => dirs.has(d.replace(/\/$/, "")) || isLib(d) || d === libDir,
48
+ getDirectories: () => [],
49
+ realpath: (p) => p,
50
+ };
51
+ }
52
+ export function libPath(name) {
53
+ return join(libDir, name);
54
+ }
@@ -0,0 +1,28 @@
1
+ import type { CanonPath, ChainSeg, RawRef, Surface } from "./model.ts";
2
+ export interface Seg {
3
+ name: string;
4
+ sep: "." | "#";
5
+ }
6
+ export declare function entryPrefix(pkg: string, entry: string): string;
7
+ export declare function formatPath(pkg: string, entry: string, segs: Seg[]): CanonPath;
8
+ export declare function parsePath(path: CanonPath): {
9
+ prefix: string;
10
+ segs: Seg[];
11
+ };
12
+ export declare function lastName(path: CanonPath): string;
13
+ export declare function isNamespaceAlias(imported: string, called: boolean): boolean;
14
+ export declare function effectiveChain(ref: RawRef): {
15
+ segs: ChainSeg[];
16
+ startsCalled: boolean;
17
+ };
18
+ export interface Resolution {
19
+ paths: CanonPath[];
20
+ unresolvedTail: string[];
21
+ missingHead: boolean;
22
+ }
23
+ export declare function resolveRef(surface: Surface, ref: RawRef): Resolution;
24
+ export declare function level0Names(ref: RawRef): {
25
+ strong: string[];
26
+ weak: string[];
27
+ };
28
+ //# sourceMappingURL=symbol-path.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"symbol-path.d.ts","sourceRoot":"","sources":["../src/symbol-path.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,SAAS,EACT,QAAQ,EACR,MAAM,EACN,OAAO,EAER,MAAM,YAAY,CAAA;AAQnB,MAAM,WAAW,GAAG;IAClB,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,GAAG,GAAG,GAAG,CAAA;CACf;AAED,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAE9D;AAED,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,SAAS,CAM7E;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,SAAS,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,GAAG,EAAE,CAAA;CAAE,CAgB1E;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,CAGhD;AAID,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,OAAO,CAE3E;AAGD,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG;IAC3C,IAAI,EAAE,QAAQ,EAAE,CAAA;IAChB,YAAY,EAAE,OAAO,CAAA;CACtB,CAaA;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,SAAS,EAAE,CAAA;IAElB,cAAc,EAAE,MAAM,EAAE,CAAA;IAExB,WAAW,EAAE,OAAO,CAAA;CACrB;AAQD,wBAAgB,UAAU,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,UAAU,CA+IpE;AAID,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG;IAAE,MAAM,EAAE,MAAM,EAAE,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,CAa7E"}
@@ -0,0 +1,223 @@
1
+ export function entryPrefix(pkg, entry) {
2
+ return entry === "." ? pkg : `${pkg}${entry.slice(1)}`;
3
+ }
4
+ export function formatPath(pkg, entry, segs) {
5
+ let out = `${entryPrefix(pkg, entry)}:`;
6
+ segs.forEach((s, i) => {
7
+ out += i === 0 ? s.name : `${s.sep}${s.name}`;
8
+ });
9
+ return out;
10
+ }
11
+ export function parsePath(path) {
12
+ const colon = path.indexOf(":", path.startsWith("@") ? path.indexOf("/") : 0);
13
+ const prefix = path.slice(0, colon);
14
+ const rest = path.slice(colon + 1);
15
+ const segs = [];
16
+ let sep = ".";
17
+ let cur = "";
18
+ for (const ch of rest) {
19
+ if (ch === "." || ch === "#") {
20
+ if (cur)
21
+ segs.push({ name: cur, sep });
22
+ sep = ch;
23
+ cur = "";
24
+ }
25
+ else
26
+ cur += ch;
27
+ }
28
+ if (cur)
29
+ segs.push({ name: cur, sep });
30
+ return { prefix, segs };
31
+ }
32
+ export function lastName(path) {
33
+ const segs = parsePath(path).segs;
34
+ return segs[segs.length - 1]?.name ?? "";
35
+ }
36
+ // A short or default named import that is not itself called is almost always a namespace alias:
37
+ // `import { v } from "lib"; v.object()`. Called, it is a function: `import { fr } from "lib/locales"; fr()`.
38
+ export function isNamespaceAlias(imported, called) {
39
+ return !called && (imported === "default" || imported.length <= 2);
40
+ }
41
+ // The chain as seen from the package's entry module, before any surface is known.
42
+ export function effectiveChain(ref) {
43
+ const b = ref.binding;
44
+ let segs;
45
+ if (b.kind === "named") {
46
+ segs = isNamespaceAlias(b.imported, ref.callSelf)
47
+ ? [...ref.chain]
48
+ : [{ name: b.imported, call: ref.callSelf }, ...ref.chain];
49
+ }
50
+ else {
51
+ segs = [...ref.chain];
52
+ }
53
+ segs = segs.filter((s, i) => !(i === 0 && s.name === "default"));
54
+ const startsCalled = b.kind !== "named" && ref.callSelf;
55
+ return { segs, startsCalled };
56
+ }
57
+ const MAX_HOPS = 6;
58
+ // Level 1: walk a usage chain through a surface. `v.email().max(254)` from "lib" resolves to
59
+ // lib:email, then through its return type to lib:EmailSchema#max.
60
+ export function resolveRef(surface, ref) {
61
+ // the surface's own name: @types/lib answers for code that imports "lib"
62
+ const prefix = entryPrefix(surface.pkg, ref.entry);
63
+ const out = { paths: [], unresolvedTail: [], missingHead: false };
64
+ if (ref.binding.kind === "derived") {
65
+ if (!ref.origin) {
66
+ out.unresolvedTail = ref.chain.map((s) => s.name);
67
+ return out;
68
+ }
69
+ // walk the construction, then the reads: only the reads are this site's own paths
70
+ const o = ref.origin;
71
+ const base = resolveRef(surface, {
72
+ ...ref,
73
+ binding: o.binding,
74
+ entry: o.entry,
75
+ chain: o.chain,
76
+ callSelf: o.callSelf,
77
+ origin: undefined,
78
+ });
79
+ const full = resolveRef(surface, {
80
+ ...ref,
81
+ binding: o.binding,
82
+ entry: o.entry,
83
+ chain: [
84
+ ...o.chain.map((s, i) => i === o.chain.length - 1 && ref.callSelf ? { ...s, call: true } : s),
85
+ ...ref.chain,
86
+ ],
87
+ callSelf: o.chain.length === 0 ? o.callSelf || ref.callSelf : o.callSelf,
88
+ origin: undefined,
89
+ });
90
+ // the walk is sequential, so the construction's paths are a prefix of the full walk
91
+ const prefixLen = base.paths.every((p, i) => full.paths[i] === p)
92
+ ? base.paths.length
93
+ : 0;
94
+ return {
95
+ paths: full.paths.slice(prefixLen),
96
+ unresolvedTail: full.unresolvedTail,
97
+ missingHead: false,
98
+ };
99
+ }
100
+ const entry = surface.entries[ref.entry];
101
+ if (!entry) {
102
+ out.missingHead = true;
103
+ out.unresolvedTail = ref.chain.map((s) => s.name);
104
+ return out;
105
+ }
106
+ const sym = (p) => {
107
+ let s = surface.symbols[p];
108
+ for (let i = 0; i < 5 && s?.aliasOf; i++) {
109
+ const next = surface.symbols[s.aliasOf];
110
+ if (!next)
111
+ break;
112
+ s = next;
113
+ }
114
+ return s;
115
+ };
116
+ const modulePath = `${prefix}:`;
117
+ const lookup = (cur, name) => cur.kind === "ns"
118
+ ? cur.base.endsWith(":")
119
+ ? `${cur.base}${name}`
120
+ : `${cur.base}.${name}`
121
+ : `${cur.path}#${name}`;
122
+ const b = ref.binding;
123
+ let cursor = { kind: "ns", base: modulePath };
124
+ let segs;
125
+ let startCall = false;
126
+ if (b.kind === "named") {
127
+ if (isNamespaceAlias(b.imported, ref.callSelf) &&
128
+ !surface.symbols[`${modulePath}${b.imported}`])
129
+ segs = [...ref.chain];
130
+ else
131
+ segs = [{ name: b.imported, call: ref.callSelf }, ...ref.chain];
132
+ }
133
+ else if (b.kind === "default") {
134
+ // ESM default export, else CommonJS interop hands over the module itself
135
+ const d = surface.symbols[`${modulePath}default`];
136
+ if (d)
137
+ segs = [{ name: "default", call: ref.callSelf }, ...ref.chain];
138
+ else {
139
+ segs = [...ref.chain];
140
+ startCall = ref.callSelf;
141
+ }
142
+ }
143
+ else {
144
+ segs = [...ref.chain];
145
+ startCall = ref.callSelf;
146
+ }
147
+ if (startCall) {
148
+ const self = surface.symbols[modulePath];
149
+ if (!self) {
150
+ out.unresolvedTail = segs.map((s) => s.name);
151
+ return out;
152
+ }
153
+ out.paths.push(modulePath);
154
+ cursor = self.returns
155
+ ? { kind: "type", path: self.returns }
156
+ : self.instanceOf
157
+ ? { kind: "type", path: self.instanceOf }
158
+ : undefined;
159
+ }
160
+ else if (segs.length === 0) {
161
+ return out;
162
+ }
163
+ let hops = 0;
164
+ for (let i = 0; i < segs.length; i++) {
165
+ const seg = segs[i];
166
+ if (!cursor || hops++ >= MAX_HOPS) {
167
+ out.unresolvedTail.push(...segs.slice(i).map((s) => s.name));
168
+ break;
169
+ }
170
+ const path = lookup(cursor, seg.name);
171
+ const raw = surface.symbols[path];
172
+ const found = sym(path);
173
+ if (!raw || !found) {
174
+ if (i === 0 && !startCall)
175
+ out.missingHead = true;
176
+ out.unresolvedTail.push(...segs.slice(i).map((s) => s.name));
177
+ break;
178
+ }
179
+ out.paths.push(path);
180
+ if (raw.aliasOf && found.path !== path)
181
+ out.paths.push(found.path);
182
+ if (found.kind === "namespace") {
183
+ cursor = { kind: "ns", base: found.path };
184
+ continue;
185
+ }
186
+ if (seg.call || seg.construct) {
187
+ const next = seg.construct
188
+ ? (found.instanceOf ?? found.returns)
189
+ : found.returns;
190
+ cursor = next ? { kind: "type", path: next } : undefined;
191
+ continue;
192
+ }
193
+ if (found.kind === "class" || found.kind === "enum")
194
+ cursor = { kind: "ns", base: found.path };
195
+ else if (found.kind === "interface" || found.kind === "type")
196
+ cursor = { kind: "type", path: found.path };
197
+ else if (found.instanceOf)
198
+ cursor = { kind: "type", path: found.instanceOf };
199
+ else
200
+ cursor =
201
+ found.kind === "variable" ? { kind: "ns", base: found.path } : undefined;
202
+ }
203
+ return out;
204
+ }
205
+ // Strong: segments up to and including the first call. Weak: what follows, and everything on a
206
+ // derived value or on the result of calling the package itself (`createApp().use`).
207
+ export function level0Names(ref) {
208
+ if (ref.binding.kind === "derived")
209
+ return { strong: [], weak: ref.chain.map((s) => s.name) };
210
+ const { segs, startsCalled } = effectiveChain(ref);
211
+ const strong = [];
212
+ const weak = [];
213
+ let called = startsCalled;
214
+ for (const s of segs) {
215
+ if (called)
216
+ weak.push(s.name);
217
+ else
218
+ strong.push(s.name);
219
+ if (s.call)
220
+ called = true;
221
+ }
222
+ return { strong, weak };
223
+ }
@@ -0,0 +1,18 @@
1
+ export declare const SOURCE_EXT: RegExp;
2
+ export declare const STYLE_EXT: RegExp;
3
+ export interface SourceText {
4
+ rel: string;
5
+ blocks: {
6
+ text: string;
7
+ lineOffset: number;
8
+ kind: "ts" | "tsx" | "js" | "jsx";
9
+ }[];
10
+ }
11
+ export type Skip = {
12
+ rel: string;
13
+ reason: "generated" | "too-large";
14
+ };
15
+ export declare function isScannable(rel: string): boolean;
16
+ export declare function skippedByLocation(rel: string): boolean;
17
+ export declare function readSource(root: string, rel: string): Promise<SourceText | Skip>;
18
+ //# sourceMappingURL=files.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../../src/usage/files.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,UAAU,QAA0C,CAAA;AACjE,eAAO,MAAM,SAAS,QAA4C,CAAA;AAElE,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAA;IAEX,MAAM,EAAE;QACN,IAAI,EAAE,MAAM,CAAA;QACZ,UAAU,EAAE,MAAM,CAAA;QAClB,IAAI,EAAE,IAAI,GAAG,KAAK,GAAG,IAAI,GAAG,KAAK,CAAA;KAClC,EAAE,CAAA;CACJ;AAED,MAAM,MAAM,IAAI,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,WAAW,GAAG,WAAW,CAAA;CAAE,CAAA;AAIrE,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAIhD;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAQtD;AAED,wBAAsB,UAAU,CAC9B,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CA+C5B"}
@@ -0,0 +1,83 @@
1
+ import { join } from "node:path";
2
+ import { readFile } from "node:fs/promises";
3
+ import { SKIP_DIRS } from "../inventory/manifests.js";
4
+ export const SOURCE_EXT = /\.(?:[cm]?[jt]sx?|vue|svelte|astro)$/i;
5
+ export const STYLE_EXT = /\.(?:css|scss|sass|less|pcss|postcss)$/i;
6
+ const MAX_BYTES = 1_500_000;
7
+ export function isScannable(rel) {
8
+ if (!SOURCE_EXT.test(rel))
9
+ return false;
10
+ const segs = rel.split("/");
11
+ return !segs.slice(0, -1).some((s) => SKIP_DIRS.has(s));
12
+ }
13
+ export function skippedByLocation(rel) {
14
+ return (SOURCE_EXT.test(rel) &&
15
+ rel
16
+ .split("/")
17
+ .slice(0, -1)
18
+ .some((s) => SKIP_DIRS.has(s) && s !== "node_modules"));
19
+ }
20
+ export async function readSource(root, rel) {
21
+ const buf = await readFile(join(root, rel));
22
+ if (buf.byteLength > MAX_BYTES)
23
+ return { rel, reason: "too-large" };
24
+ const text = buf.toString("utf8");
25
+ if (looksMinified(text))
26
+ return { rel, reason: "generated" };
27
+ const lower = rel.toLowerCase();
28
+ if (lower.endsWith(".vue") || lower.endsWith(".svelte")) {
29
+ const blocks = [];
30
+ const re = /<script\b([^>]*)>([\s\S]*?)<\/script>/gi;
31
+ for (let m = re.exec(text); m; m = re.exec(text)) {
32
+ const attrs = m[1] ?? "";
33
+ const body = m[2] ?? "";
34
+ const start = m.index + m[0].indexOf(">") + 1;
35
+ const ts = /\blang\s*=\s*["']?(ts|tsx)/i.test(attrs);
36
+ blocks.push({
37
+ text: body,
38
+ lineOffset: lineOf(text, start) - 1,
39
+ kind: ts ? "ts" : "js",
40
+ });
41
+ }
42
+ return { rel, blocks };
43
+ }
44
+ if (lower.endsWith(".astro")) {
45
+ const blocks = [];
46
+ const fm = /^---\r?\n([\s\S]*?)\r?\n---/.exec(text);
47
+ if (fm?.[1] !== undefined)
48
+ blocks.push({ text: fm[1], lineOffset: 1, kind: "ts" });
49
+ const re = /<script\b[^>]*>([\s\S]*?)<\/script>/gi;
50
+ for (let m = re.exec(text); m; m = re.exec(text)) {
51
+ const start = m.index + m[0].indexOf(">") + 1;
52
+ blocks.push({
53
+ text: m[1] ?? "",
54
+ lineOffset: lineOf(text, start) - 1,
55
+ kind: "ts",
56
+ });
57
+ }
58
+ return { rel, blocks };
59
+ }
60
+ const kind = /\.[cm]?tsx$/i.test(lower)
61
+ ? "tsx"
62
+ : /\.[cm]?ts$/i.test(lower)
63
+ ? "ts"
64
+ : /\.jsx$/i.test(lower)
65
+ ? "jsx"
66
+ : "js";
67
+ return { rel, blocks: [{ text, lineOffset: 0, kind }] };
68
+ }
69
+ function lineOf(text, index) {
70
+ let line = 1;
71
+ for (let i = 0; i < index; i++)
72
+ if (text.charCodeAt(i) === 10)
73
+ line++;
74
+ return line;
75
+ }
76
+ // Bundles and minified output have very long lines; reading them as source would invent usage.
77
+ function looksMinified(text) {
78
+ if (text.length < 5000)
79
+ return false;
80
+ const lines = text.split("\n");
81
+ const long = lines.filter((l) => l.length > 1000).length;
82
+ return long > 0 && text.length / lines.length > 300;
83
+ }
@@ -0,0 +1,23 @@
1
+ import type { FileFacts } from "./parse.ts";
2
+ import type { LocalResolver } from "./resolve-local.ts";
3
+ import type { BlindSpotKind, ChainSeg, Counted, Inventory, OpaqueKind, RawRef, RefOrigin, Site, UsageMap } from "../model.ts";
4
+ export interface LinkInput {
5
+ root: string;
6
+ facts: Map<string, FileFacts>;
7
+ resolver: LocalResolver;
8
+ inventory: Inventory;
9
+ globalSkipped: Site[];
10
+ }
11
+ interface Acc {
12
+ refs: RawRef[];
13
+ blind: Map<BlindSpotKind, Site[]>;
14
+ opaque: Map<OpaqueKind, Site[]>;
15
+ proxied: boolean;
16
+ }
17
+ export declare function link(input: LinkInput): Promise<UsageMap & {
18
+ acc: Map<string, Acc>;
19
+ }>;
20
+ export declare function extendOrigin(origin: RefOrigin, chain: ChainSeg[], callSelf: boolean): RefOrigin;
21
+ export declare function counted<K extends string>(m: Map<K, Site[]>): Counted<K>[];
22
+ export {};
23
+ //# sourceMappingURL=link.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"link.d.ts","sourceRoot":"","sources":["../../src/usage/link.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAsB,MAAM,YAAY,CAAA;AAC/D,OAAO,KAAK,EAAE,aAAa,EAAU,MAAM,oBAAoB,CAAA;AAC/D,OAAO,KAAK,EAEV,aAAa,EACb,QAAQ,EACR,OAAO,EAEP,SAAS,EACT,UAAU,EAEV,MAAM,EACN,SAAS,EACT,IAAI,EACJ,QAAQ,EACT,MAAM,aAAa,CAAA;AAoBpB,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;IAC7B,QAAQ,EAAE,aAAa,CAAA;IACvB,SAAS,EAAE,SAAS,CAAA;IACpB,aAAa,EAAE,IAAI,EAAE,CAAA;CACtB;AAED,UAAU,GAAG;IACX,IAAI,EAAE,MAAM,EAAE,CAAA;IACd,KAAK,EAAE,GAAG,CAAC,aAAa,EAAE,IAAI,EAAE,CAAC,CAAA;IACjC,MAAM,EAAE,GAAG,CAAC,UAAU,EAAE,IAAI,EAAE,CAAC,CAAA;IAC/B,OAAO,EAAE,OAAO,CAAA;CACjB;AAED,wBAAsB,IAAI,CACxB,KAAK,EAAE,SAAS,GACf,OAAO,CAAC,QAAQ,GAAG;IAAE,GAAG,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;CAAE,CAAC,CA2mB/C;AAyBD,wBAAgB,YAAY,CAC1B,MAAM,EAAE,SAAS,EACjB,KAAK,EAAE,QAAQ,EAAE,EACjB,QAAQ,EAAE,OAAO,GAChB,SAAS,CASX;AAED,wBAAgB,OAAO,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,EAAE,CASzE"}