urtext 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/LICENSE +21 -0
- package/README.md +229 -0
- package/dist/analyze/blast-radius.d.ts +28 -0
- package/dist/analyze/blast-radius.js +163 -0
- package/dist/analyze/canonical.d.ts +27 -0
- package/dist/analyze/canonical.js +74 -0
- package/dist/analyze/citations.d.ts +256 -0
- package/dist/analyze/citations.js +945 -0
- package/dist/analyze/effects.d.ts +15 -0
- package/dist/analyze/effects.js +255 -0
- package/dist/analyze/fact.d.ts +42 -0
- package/dist/analyze/fact.js +46 -0
- package/dist/analyze/guards.d.ts +70 -0
- package/dist/analyze/guards.js +211 -0
- package/dist/analyze/index.d.ts +26 -0
- package/dist/analyze/index.js +52 -0
- package/dist/analyze/program.d.ts +15 -0
- package/dist/analyze/program.js +229 -0
- package/dist/analyze/surface.d.ts +48 -0
- package/dist/analyze/surface.js +396 -0
- package/dist/bin.d.ts +2 -0
- package/dist/bin.js +12 -0
- package/dist/cli.d.ts +110 -0
- package/dist/cli.js +502 -0
- package/dist/extract/diff.d.ts +35 -0
- package/dist/extract/diff.js +116 -0
- package/dist/extract/git.d.ts +12 -0
- package/dist/extract/git.js +247 -0
- package/dist/extract/index.d.ts +4 -0
- package/dist/extract/index.js +57 -0
- package/dist/extract/intent.d.ts +64 -0
- package/dist/extract/intent.js +238 -0
- package/dist/extract/scope.d.ts +160 -0
- package/dist/extract/scope.js +284 -0
- package/dist/extract/symbols.d.ts +24 -0
- package/dist/extract/symbols.js +230 -0
- package/dist/interpret/client.d.ts +27 -0
- package/dist/interpret/client.js +80 -0
- package/dist/interpret/index.d.ts +41 -0
- package/dist/interpret/index.js +86 -0
- package/dist/interpret/prompt.d.ts +23 -0
- package/dist/interpret/prompt.js +128 -0
- package/dist/interpret/schema.d.ts +74 -0
- package/dist/interpret/schema.js +103 -0
- package/dist/report/conceal.d.ts +63 -0
- package/dist/report/conceal.js +129 -0
- package/dist/report/coverage.d.ts +43 -0
- package/dist/report/coverage.js +56 -0
- package/dist/report/html.d.ts +4 -0
- package/dist/report/html.js +634 -0
- package/dist/report/markdown.d.ts +2 -0
- package/dist/report/markdown.js +168 -0
- package/dist/report/model.d.ts +303 -0
- package/dist/report/model.js +289 -0
- package/dist/report/pdf.d.ts +2 -0
- package/dist/report/pdf.js +217 -0
- package/dist/report/terminal.d.ts +2 -0
- package/dist/report/terminal.js +206 -0
- package/dist/report/write.d.ts +105 -0
- package/dist/report/write.js +160 -0
- package/dist/score/index.d.ts +94 -0
- package/dist/score/index.js +572 -0
- package/dist/score/reach.d.ts +126 -0
- package/dist/score/reach.js +320 -0
- package/dist/score/reconcile.d.ts +52 -0
- package/dist/score/reconcile.js +208 -0
- package/dist/types.d.ts +221 -0
- package/dist/types.js +10 -0
- package/fonts/DejaVuSans-Bold.ttf +0 -0
- package/fonts/DejaVuSans-Oblique.ttf +0 -0
- package/fonts/DejaVuSans.ttf +0 -0
- package/fonts/DejaVuSansMono.ttf +0 -0
- package/fonts/LICENSE +187 -0
- package/package.json +44 -0
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { blastRadiusAnalyzer } from "./blast-radius.js";
|
|
2
|
+
import { citationsAnalyzer } from "./citations.js";
|
|
3
|
+
import { effectsAnalyzer } from "./effects.js";
|
|
4
|
+
import { guardsAnalyzer } from "./guards.js";
|
|
5
|
+
import { surfaceAnalyzer } from "./surface.js";
|
|
6
|
+
export { detectEffects, effectsAnalyzer } from "./effects.js";
|
|
7
|
+
export { collectGuards, guardsAnalyzer } from "./guards.js";
|
|
8
|
+
export { exportedSignatures, surfaceAnalyzer } from "./surface.js";
|
|
9
|
+
export { countReferences, blastRadiusAnalyzer } from "./blast-radius.js";
|
|
10
|
+
export { citationsAnalyzer, makeCitationsAnalyzer } from "./citations.js";
|
|
11
|
+
export { createProgramAt, listTypeScriptFilesAt } from "./program.js";
|
|
12
|
+
export { makeFact } from "./fact.js";
|
|
13
|
+
export const ANALYZERS = [
|
|
14
|
+
effectsAnalyzer,
|
|
15
|
+
guardsAnalyzer,
|
|
16
|
+
surfaceAnalyzer,
|
|
17
|
+
blastRadiusAnalyzer,
|
|
18
|
+
citationsAnalyzer,
|
|
19
|
+
];
|
|
20
|
+
/**
|
|
21
|
+
* Runs every analyzer and returns the facts from the ones that succeeded.
|
|
22
|
+
*
|
|
23
|
+
* `Promise.allSettled`, not `Promise.all`: one compiler-API or git failure
|
|
24
|
+
* used to discard every analyzer's facts and exit non-zero, so a single
|
|
25
|
+
* unreadable revision turned a review with three real findings into no
|
|
26
|
+
* review at all. A degraded review beats no review — but only if the
|
|
27
|
+
* degradation is visible, which is what `onFailure` is for. Callers that
|
|
28
|
+
* pass no handler get the facts and no indication anything was lost, so
|
|
29
|
+
* anything user-facing should pass one.
|
|
30
|
+
*/
|
|
31
|
+
export async function runAnalyzers(changeset, ctx, analyzers = ANALYZERS, onFailure) {
|
|
32
|
+
const results = await Promise.allSettled(analyzers.map((a) => a(changeset, ctx)));
|
|
33
|
+
const facts = [];
|
|
34
|
+
results.forEach((result, i) => {
|
|
35
|
+
if (result.status === "fulfilled") {
|
|
36
|
+
facts.push(...result.value);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const reason = result.reason;
|
|
40
|
+
onFailure?.({
|
|
41
|
+
// An anonymous arrow assigned to a typed const takes the binding's
|
|
42
|
+
// name (NamedEvaluation of the variable declaration), so `.name` is
|
|
43
|
+
// "surfaceAnalyzer" rather than "" for every analyzer declared that
|
|
44
|
+
// way. The one a factory returns states its name outright instead,
|
|
45
|
+
// because a transform that renames shadowed bindings would otherwise
|
|
46
|
+
// rewrite it — see `makeCitationsAnalyzer` in `./citations.ts`.
|
|
47
|
+
analyzer: analyzers[i].name || `analyzer #${i + 1}`,
|
|
48
|
+
message: reason instanceof Error ? reason.message : String(reason),
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
return facts;
|
|
52
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import ts from "typescript";
|
|
2
|
+
/**
|
|
3
|
+
* Repo-relative TypeScript source paths at a revision. Declaration files are
|
|
4
|
+
* excluded: they contribute no analyzable implementation and inflate the
|
|
5
|
+
* program.
|
|
6
|
+
*/
|
|
7
|
+
export declare function listTypeScriptFilesAt(root: string, rev: string): Promise<string[]>;
|
|
8
|
+
/**
|
|
9
|
+
* Build a program over a git revision. For WORKTREE this is equivalent to
|
|
10
|
+
* reading from disk; for a commit, file contents come from git, so a
|
|
11
|
+
* "before" side can be type-checked without touching the working tree.
|
|
12
|
+
*/
|
|
13
|
+
export declare function createProgramAt(root: string, rev: string): Promise<ts.Program>;
|
|
14
|
+
/** Repo-relative path for a program source file. */
|
|
15
|
+
export declare function relativePathOf(root: string, sf: ts.SourceFile): string;
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { isAbsolute, join, relative, resolve } from "node:path";
|
|
3
|
+
import ts from "typescript";
|
|
4
|
+
import { git, readAt } from "../extract/git.js";
|
|
5
|
+
import { isTypeScriptFile } from "../extract/symbols.js";
|
|
6
|
+
import { WORKTREE } from "../types.js";
|
|
7
|
+
/**
|
|
8
|
+
* Any TypeScript file at all, declaration files included — the read-into-the-
|
|
9
|
+
* host filter, wider than `isTypeScriptFile` (which picks program *roots*):
|
|
10
|
+
* an ambient `.d.ts` is part of a revision's type surface and must stay
|
|
11
|
+
* readable and resolvable without being a root. All four implementation
|
|
12
|
+
* extensions and all three declaration flavours end in one of these.
|
|
13
|
+
*/
|
|
14
|
+
const TS_SOURCE = /\.(?:ts|tsx|mts|cts)$/;
|
|
15
|
+
const CASE_SENSITIVE = ts.sys.useCaseSensitiveFileNames;
|
|
16
|
+
/**
|
|
17
|
+
* Key for a path that is stable across separators and filesystem casing.
|
|
18
|
+
*
|
|
19
|
+
* TypeScript normalizes every path it hands the host to forward slashes, so
|
|
20
|
+
* a map keyed on Windows `join()` output would never be hit and every source
|
|
21
|
+
* file would come back undefined. One shared implementation, because the
|
|
22
|
+
* host and the map builder disagreeing is precisely the kind of silent miss
|
|
23
|
+
* that would leave the program empty rather than failing.
|
|
24
|
+
*/
|
|
25
|
+
function canonicalPath(root, fileName) {
|
|
26
|
+
const abs = isAbsolute(fileName) ? fileName : resolve(root, fileName);
|
|
27
|
+
const slashed = abs.split("\\").join("/").replace(/\/+$/, "");
|
|
28
|
+
return CASE_SENSITIVE ? slashed : slashed.toLowerCase();
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Every repo-relative path tracked at a revision, minus anything under
|
|
32
|
+
* node_modules: an installed dependency is toolchain, is served from disk by
|
|
33
|
+
* the compiler host, and is not a function of the revision even on the rare
|
|
34
|
+
* repository that commits it.
|
|
35
|
+
*/
|
|
36
|
+
async function listPathsAt(root, rev) {
|
|
37
|
+
const out = rev === WORKTREE
|
|
38
|
+
? await git(["ls-files", "--cached", "--others", "--exclude-standard"], root)
|
|
39
|
+
: await git(["ls-tree", "-r", "--name-only", rev], root);
|
|
40
|
+
const seen = new Set();
|
|
41
|
+
for (const line of out.split("\n")) {
|
|
42
|
+
const path = line.trim();
|
|
43
|
+
if (!path || path.split("/").includes("node_modules"))
|
|
44
|
+
continue;
|
|
45
|
+
seen.add(path);
|
|
46
|
+
}
|
|
47
|
+
return [...seen];
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Repo-relative TypeScript source paths at a revision. Declaration files are
|
|
51
|
+
* excluded: they contribute no analyzable implementation and inflate the
|
|
52
|
+
* program.
|
|
53
|
+
*/
|
|
54
|
+
export async function listTypeScriptFilesAt(root, rev) {
|
|
55
|
+
return (await listPathsAt(root, rev)).filter(isTypeScriptFile);
|
|
56
|
+
}
|
|
57
|
+
/** The repo's compiler options, or defaults when it has no usable tsconfig. */
|
|
58
|
+
function compilerOptions(root) {
|
|
59
|
+
const fallback = {
|
|
60
|
+
target: ts.ScriptTarget.ES2022,
|
|
61
|
+
module: ts.ModuleKind.ESNext,
|
|
62
|
+
moduleResolution: ts.ModuleResolutionKind.Bundler,
|
|
63
|
+
strict: true,
|
|
64
|
+
skipLibCheck: true,
|
|
65
|
+
noEmit: true,
|
|
66
|
+
allowJs: false,
|
|
67
|
+
};
|
|
68
|
+
// Deliberately not ts.findConfigFile: that walks up past the repository
|
|
69
|
+
// root and would silently adopt an unrelated ancestor's tsconfig (a real
|
|
70
|
+
// hazard for repos created under a temp or home directory).
|
|
71
|
+
const configPath = join(root, "tsconfig.json");
|
|
72
|
+
if (!ts.sys.fileExists(configPath))
|
|
73
|
+
return fallback;
|
|
74
|
+
const read = ts.readConfigFile(configPath, ts.sys.readFile);
|
|
75
|
+
if (read.error || !read.config)
|
|
76
|
+
return fallback;
|
|
77
|
+
const parsed = ts.parseJsonConfigFileContent(read.config, ts.sys, root);
|
|
78
|
+
// We type-check, never build. Emit-shaped options are dropped rather than
|
|
79
|
+
// merely overridden so that `composite`/`incremental` cannot make the
|
|
80
|
+
// program try to write or read a build-info file.
|
|
81
|
+
const { composite: _composite, incremental: _incremental, tsBuildInfoFile: _tsBuildInfoFile, ...options } = parsed.options;
|
|
82
|
+
return { ...options, noEmit: true, skipLibCheck: true };
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* A CompilerHost whose repository files come from a git revision rather than
|
|
86
|
+
* disk. Library files (lib.es2022.d.ts and friends) and anything under
|
|
87
|
+
* node_modules still come from the filesystem — they are part of the
|
|
88
|
+
* toolchain, not the repository under review.
|
|
89
|
+
*/
|
|
90
|
+
function hostFor(root, contents, directories) {
|
|
91
|
+
const canonicalRoot = canonical(root);
|
|
92
|
+
return {
|
|
93
|
+
getSourceFile(fileName, languageVersion) {
|
|
94
|
+
const text = contents.get(canonical(fileName)) ?? readToolchainFile(fileName);
|
|
95
|
+
if (text === undefined)
|
|
96
|
+
return undefined;
|
|
97
|
+
return ts.createSourceFile(fileName, text, languageVersion, true);
|
|
98
|
+
},
|
|
99
|
+
getDefaultLibFileName: (o) => ts.getDefaultLibFilePath(o),
|
|
100
|
+
writeFile: () => undefined,
|
|
101
|
+
getCurrentDirectory: () => root,
|
|
102
|
+
getCanonicalFileName: (f) => (CASE_SENSITIVE ? f : f.toLowerCase()),
|
|
103
|
+
useCaseSensitiveFileNames: () => CASE_SENSITIVE,
|
|
104
|
+
getNewLine: () => "\n",
|
|
105
|
+
fileExists(f) {
|
|
106
|
+
if (isSubject(f))
|
|
107
|
+
return contents.has(canonical(f));
|
|
108
|
+
return ts.sys.fileExists(f);
|
|
109
|
+
},
|
|
110
|
+
readFile(f) {
|
|
111
|
+
if (isSubject(f))
|
|
112
|
+
return contents.get(canonical(f));
|
|
113
|
+
return ts.sys.readFile(f);
|
|
114
|
+
},
|
|
115
|
+
directoryExists(d) {
|
|
116
|
+
if (isSubject(d))
|
|
117
|
+
return directories.has(canonical(d));
|
|
118
|
+
return ts.sys.directoryExists(d);
|
|
119
|
+
},
|
|
120
|
+
getDirectories(d) {
|
|
121
|
+
if (!isSubject(d))
|
|
122
|
+
return ts.sys.getDirectories(d);
|
|
123
|
+
const prefix = `${canonical(d)}/`;
|
|
124
|
+
const names = new Set();
|
|
125
|
+
for (const dir of directories) {
|
|
126
|
+
if (!dir.startsWith(prefix))
|
|
127
|
+
continue;
|
|
128
|
+
const rest = dir.slice(prefix.length);
|
|
129
|
+
if (rest && !rest.includes("/"))
|
|
130
|
+
names.add(rest);
|
|
131
|
+
}
|
|
132
|
+
return [...names];
|
|
133
|
+
},
|
|
134
|
+
};
|
|
135
|
+
function canonical(fileName) {
|
|
136
|
+
return canonicalPath(root, fileName);
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* True for paths that belong to the repository under review, i.e. whose
|
|
140
|
+
* content is a function of the revision. Dependencies are excluded: an
|
|
141
|
+
* installed package is toolchain, and its tree is not stored in git.
|
|
142
|
+
*/
|
|
143
|
+
function isSubject(fileName) {
|
|
144
|
+
const path = canonical(fileName);
|
|
145
|
+
if (path === canonicalRoot)
|
|
146
|
+
return false; // the root itself always exists
|
|
147
|
+
if (!path.startsWith(`${canonicalRoot}/`))
|
|
148
|
+
return false;
|
|
149
|
+
return !path
|
|
150
|
+
.slice(canonicalRoot.length + 1)
|
|
151
|
+
.split("/")
|
|
152
|
+
.includes("node_modules");
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Read a file that is *not* subject to the revision. A repository file
|
|
156
|
+
* absent from `contents` genuinely does not exist at this revision and must
|
|
157
|
+
* NOT be served from the working tree — that is exactly how a "before"
|
|
158
|
+
* program would silently type-check current code and report confident
|
|
159
|
+
* nonsense under a `verified` badge.
|
|
160
|
+
*/
|
|
161
|
+
function readToolchainFile(fileName) {
|
|
162
|
+
if (isSubject(fileName))
|
|
163
|
+
return undefined;
|
|
164
|
+
const abs = isAbsolute(fileName) ? fileName : resolve(root, fileName);
|
|
165
|
+
try {
|
|
166
|
+
return readFileSync(abs, "utf8");
|
|
167
|
+
}
|
|
168
|
+
catch {
|
|
169
|
+
return undefined;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Build a program over a git revision. For WORKTREE this is equivalent to
|
|
175
|
+
* reading from disk; for a commit, file contents come from git, so a
|
|
176
|
+
* "before" side can be type-checked without touching the working tree.
|
|
177
|
+
*/
|
|
178
|
+
export async function createProgramAt(root, rev) {
|
|
179
|
+
const options = compilerOptions(root);
|
|
180
|
+
// Sources, plus the manifests module resolution consults. A package.json
|
|
181
|
+
// is what tells the compiler whether a directory is ESM or CommonJS under
|
|
182
|
+
// node16/nodenext; without it every relative import in such a repo is
|
|
183
|
+
// resolved under the wrong module format, which is the silent kind of
|
|
184
|
+
// wrongness this host exists to avoid. They come from the revision like
|
|
185
|
+
// any other repository file.
|
|
186
|
+
const paths = (await listPathsAt(root, rev)).filter((p) => TS_SOURCE.test(p) || p === "package.json" || p.endsWith("/package.json"));
|
|
187
|
+
// Reading a commit's files means one `git show` per file. Done serially
|
|
188
|
+
// that is a subprocess round-trip per file and dominates the build on any
|
|
189
|
+
// sizeable repository, so read a few at a time — but collect into a
|
|
190
|
+
// position-indexed array, because the program's root order must not depend
|
|
191
|
+
// on which read happened to finish first.
|
|
192
|
+
const texts = new Array(paths.length);
|
|
193
|
+
let cursor = 0;
|
|
194
|
+
const workers = Array.from({ length: Math.min(8, paths.length) }, async () => {
|
|
195
|
+
while (cursor < paths.length) {
|
|
196
|
+
const i = cursor++;
|
|
197
|
+
texts[i] = await readAt(root, rev, paths[i]);
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
await Promise.all(workers);
|
|
201
|
+
const contents = new Map();
|
|
202
|
+
const directories = new Set();
|
|
203
|
+
const rootNames = [];
|
|
204
|
+
for (const [i, p] of paths.entries()) {
|
|
205
|
+
const text = texts[i];
|
|
206
|
+
if (text === null)
|
|
207
|
+
continue; // absent at this revision; not an error here
|
|
208
|
+
const abs = join(root, p);
|
|
209
|
+
const key = canonicalPath(root, abs);
|
|
210
|
+
contents.set(key, text);
|
|
211
|
+
// Only implementation sources are program roots. Declaration files and
|
|
212
|
+
// manifests stay readable and resolvable — an ambient .d.ts is part of
|
|
213
|
+
// the revision's type surface — without inflating the program.
|
|
214
|
+
if (isTypeScriptFile(p))
|
|
215
|
+
rootNames.push(abs);
|
|
216
|
+
const segments = key.split("/");
|
|
217
|
+
for (let i = segments.length - 1; i > 0; i--) {
|
|
218
|
+
const dir = segments.slice(0, i).join("/");
|
|
219
|
+
if (directories.has(dir))
|
|
220
|
+
break;
|
|
221
|
+
directories.add(dir);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
return ts.createProgram(rootNames, options, hostFor(root, contents, directories));
|
|
225
|
+
}
|
|
226
|
+
/** Repo-relative path for a program source file. */
|
|
227
|
+
export function relativePathOf(root, sf) {
|
|
228
|
+
return relative(root, sf.fileName).split("\\").join("/");
|
|
229
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import ts from "typescript";
|
|
2
|
+
import type { Analyzer } from "../types.js";
|
|
3
|
+
/**
|
|
4
|
+
* A stored signature beyond this length is truncated when a fact records
|
|
5
|
+
* it, so that one enormous type — a huge object literal, or a union with
|
|
6
|
+
* many members — cannot flood a fact with a single string. The marker
|
|
7
|
+
* makes the cut visible: a reader must be able to tell the text was cut,
|
|
8
|
+
* not mistake it for the whole type. Exported for
|
|
9
|
+
* `test/comment-contract.test.ts`, which derives part of its forbidden set
|
|
10
|
+
* from it.
|
|
11
|
+
*
|
|
12
|
+
* Applied at the fact-emission boundary, not inside `exportedSignatures`:
|
|
13
|
+
* the true, uncut text has to exist long enough for its code-point length
|
|
14
|
+
* to be recorded beside the capped text (`beforeChars`/`afterChars` in the
|
|
15
|
+
* fact's detail), because the renderer's own length marker states that
|
|
16
|
+
* true length — a length measured after this cap asserted a false size
|
|
17
|
+
* for exactly the long-literal class the marker exists for.
|
|
18
|
+
*/
|
|
19
|
+
export declare const MAX_SIGNATURE_LENGTH = 400;
|
|
20
|
+
/**
|
|
21
|
+
* Matches the marker `truncateSignature` appends. Exported for the render
|
|
22
|
+
* layer (`../score/index.ts`), which drops the marker before applying its
|
|
23
|
+
* own, shorter middle-truncation — the render marker states the true
|
|
24
|
+
* length, and keeping both would leave this one's tail fragment inside
|
|
25
|
+
* the rendered text.
|
|
26
|
+
*/
|
|
27
|
+
export declare const SIGNATURE_TRUNCATION_MARKER: RegExp;
|
|
28
|
+
/**
|
|
29
|
+
* Exported name → printed type, for one file in a program. `undefined` when
|
|
30
|
+
* the program has no such source file: that is an unreadable file, not a
|
|
31
|
+
* file with no exports, and the two must not be conflated. Returning an
|
|
32
|
+
* empty map for a missing before-side file would make every export of the
|
|
33
|
+
* after-side file read as `export_added` — absence treated as evidence,
|
|
34
|
+
* one level up from the file-read rule the other analyzers follow.
|
|
35
|
+
*
|
|
36
|
+
* The printed text is the *full* signature, uncapped: `surfaceAnalyzer`
|
|
37
|
+
* measures its true length and applies `truncateSignature` when it stores
|
|
38
|
+
* the text on a fact, and truncating here instead would destroy the length
|
|
39
|
+
* before anything could record it.
|
|
40
|
+
*/
|
|
41
|
+
export declare function exportedSignatures(program: ts.Program, root: string, path: string): Map<string, string> | undefined;
|
|
42
|
+
/**
|
|
43
|
+
* Reports changes to a file's public contract: exports added, exports
|
|
44
|
+
* removed, and exports whose type signature changed. A changed signature is
|
|
45
|
+
* the class of change that breaks callers without breaking the build at the
|
|
46
|
+
* point of change, which is why it ranks above an added export.
|
|
47
|
+
*/
|
|
48
|
+
export declare const surfaceAnalyzer: Analyzer;
|