@cplieger/deadset-ts 1.2.0 → 2.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/README.md +44 -5
- package/{bin/deadset-ts.ts → dist/bin/deadset-ts.js} +2 -3
- package/dist/bin/node-host.js +74 -0
- package/dist/src/config.js +63 -0
- package/dist/src/discover.js +171 -0
- package/dist/src/host.js +1 -0
- package/dist/src/index.js +6 -0
- package/dist/src/inventory.js +693 -0
- package/dist/src/kinds.js +12 -0
- package/dist/src/paths.js +86 -0
- package/dist/src/position.js +52 -0
- package/dist/src/print.js +56 -0
- package/dist/src/ref.js +117 -0
- package/dist/src/references.js +420 -0
- package/dist/src/resolve.js +482 -0
- package/dist/src/run.js +249 -0
- package/dist/src/schema.js +335 -0
- package/dist/src/scope.js +116 -0
- package/dist/src/session.js +101 -0
- package/dist/src/version.js +7 -0
- package/jsr.json +1 -1
- package/package.json +9 -4
- package/src/host.ts +10 -2
- package/src/index.ts +13 -1
- package/src/inventory.ts +53 -8
- package/src/references.ts +606 -0
- package/src/run.ts +4 -4
- package/src/session.ts +41 -22
- package/src/version.ts +3 -18
- package/bin/deadset-ts.mjs +0 -24
- package/bin/node-host.ts +0 -28
package/src/session.ts
CHANGED
|
@@ -10,8 +10,8 @@ import type {
|
|
|
10
10
|
Symbol as TSSymbol,
|
|
11
11
|
TimingInfo,
|
|
12
12
|
} from "@typescript/native/unstable/sync";
|
|
13
|
-
import {
|
|
14
|
-
import type {
|
|
13
|
+
import { isIdentifier } from "@typescript/native/unstable/ast";
|
|
14
|
+
import type { Node, SourceFile } from "@typescript/native/unstable/ast";
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* The compiler the analysis reads through. It is a client over a protocol to a
|
|
@@ -102,6 +102,25 @@ export interface ProjectView<Brand> {
|
|
|
102
102
|
* resolve.
|
|
103
103
|
*/
|
|
104
104
|
symbolsAt(handles: readonly Handle<Brand>[]): readonly (TSSymbol | undefined)[];
|
|
105
|
+
/**
|
|
106
|
+
* The symbol one node resolves to, asked for that node alone. The accessor behind
|
|
107
|
+
* it takes one identifier and offers no array overload, so it is one round trip per
|
|
108
|
+
* node and it answers only for the residue a batch left unresolved. A node that is
|
|
109
|
+
* not an identifier has no such answer.
|
|
110
|
+
*/
|
|
111
|
+
resolvedSymbolAt(handle: Handle<Brand>): TSSymbol | undefined;
|
|
112
|
+
/**
|
|
113
|
+
* The symbol the value of one shorthand property assignment names, which is the
|
|
114
|
+
* declaration `{ a }` reads; the symbol the property's own name resolves to is the
|
|
115
|
+
* property the literal declares. The handle names the assignment, not its name.
|
|
116
|
+
*/
|
|
117
|
+
shorthandValueAt(handle: Handle<Brand>): TSSymbol | undefined;
|
|
118
|
+
/**
|
|
119
|
+
* The symbol one alias names, one link along: an import or export specifier
|
|
120
|
+
* resolves to the declaration it carries forward, or to the next alias of a chain.
|
|
121
|
+
* `undefined` where the symbol is no alias, or where the alias resolves to nothing.
|
|
122
|
+
*/
|
|
123
|
+
aliasStepOf(symbol: TSSymbol): TSSymbol | undefined;
|
|
105
124
|
/**
|
|
106
125
|
* The node one symbol's declaration handle names, read in this project's program,
|
|
107
126
|
* or `undefined` where this project's program does not hold that file.
|
|
@@ -122,30 +141,18 @@ export interface ProjectView<Brand> {
|
|
|
122
141
|
*/
|
|
123
142
|
export type ProjectVisitor<Result> = <Brand>(project: ProjectView<Brand>) => Result;
|
|
124
143
|
|
|
125
|
-
/**
|
|
126
|
-
* The identifiers of one source file, in source order. A file is the unit a batch
|
|
127
|
-
* resolves: the walk is local to this process and the resolution is not, so one
|
|
128
|
-
* file's identifiers are gathered here and handed to the checker together.
|
|
129
|
-
*/
|
|
130
|
-
export function identifiersOf(file: SourceFile): Identifier[] {
|
|
131
|
-
const found: Identifier[] = [];
|
|
132
|
-
const visit = (node: Node): void => {
|
|
133
|
-
if (node.kind === SyntaxKind.Identifier) {
|
|
134
|
-
found.push(node as Identifier);
|
|
135
|
-
}
|
|
136
|
-
node.forEachChild(visit);
|
|
137
|
-
};
|
|
138
|
-
file.forEachChild(visit);
|
|
139
|
-
return found;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
144
|
function viewOf<Brand>(project: Project): ProjectView<Brand> {
|
|
145
|
+
// The snapshot is never updated, so a project's own file set is the same answer
|
|
146
|
+
// every time it is asked for. It is read once because the question is not free:
|
|
147
|
+
// deciding it consults the metadata of every file the program holds, the compiler's
|
|
148
|
+
// own library files included, and a run asks for the set once per pass.
|
|
149
|
+
let ownFiles: readonly SourceFile[] | undefined;
|
|
143
150
|
return {
|
|
144
151
|
configFile: project.configFileName,
|
|
145
152
|
program: project.program,
|
|
146
153
|
checker: project.checker,
|
|
147
|
-
ownSourceFiles: () =>
|
|
148
|
-
project.program
|
|
154
|
+
ownSourceFiles: () => {
|
|
155
|
+
ownFiles ??= project.program
|
|
149
156
|
.getSourceFileNames()
|
|
150
157
|
// The metadata decides which files belong to the target, and it is read by
|
|
151
158
|
// name. Fetching each file first and filtering afterwards costs one round
|
|
@@ -158,9 +165,21 @@ function viewOf<Brand>(project: Project): ProjectView<Brand> {
|
|
|
158
165
|
);
|
|
159
166
|
})
|
|
160
167
|
.map((name) => project.program.getSourceFile(name))
|
|
161
|
-
.filter((file): file is SourceFile => file !== undefined)
|
|
168
|
+
.filter((file): file is SourceFile => file !== undefined);
|
|
169
|
+
return ownFiles;
|
|
170
|
+
},
|
|
162
171
|
handle: (node) => ({ node }),
|
|
163
172
|
symbolsAt: (handles) => project.checker.getSymbolAtLocation(handles.map(({ node }) => node)),
|
|
173
|
+
resolvedSymbolAt: ({ node }) =>
|
|
174
|
+
isIdentifier(node) ? project.checker.getResolvedSymbol(node) : undefined,
|
|
175
|
+
shorthandValueAt: ({ node }) => project.checker.getShorthandAssignmentValueSymbol(node),
|
|
176
|
+
aliasStepOf: (symbol) => {
|
|
177
|
+
const held = project.checker.getImmediateAliasedSymbol(symbol);
|
|
178
|
+
// An alias that resolves to nothing answers with the checker's own unknown
|
|
179
|
+
// symbol, which declares nothing; a symbol that is no alias answers with
|
|
180
|
+
// nothing at all.
|
|
181
|
+
return held === undefined || held.declarations.length === 0 ? undefined : held;
|
|
182
|
+
},
|
|
164
183
|
declarationAt: (handle) => {
|
|
165
184
|
const node = handle.resolve(project);
|
|
166
185
|
return node === undefined ? undefined : { node };
|
package/src/version.ts
CHANGED
|
@@ -1,22 +1,7 @@
|
|
|
1
|
-
import manifest from "../package.json" with { type: "json" };
|
|
2
|
-
|
|
3
1
|
/**
|
|
4
2
|
* The Contract version this analyzer implements. It is the resolved value of
|
|
5
3
|
* `contract_version` when no configuration source supplies one, and it moves
|
|
6
|
-
* independently of
|
|
4
|
+
* independently of the analyzer's own version, which is the one the host answers
|
|
5
|
+
* from the package the analyzer was installed from.
|
|
7
6
|
*/
|
|
8
|
-
export const CONTRACT_VERSION = "
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* This analyzer's own version, which the published package carries rather than
|
|
12
|
-
* the source: the release pipeline writes the released version into the manifest
|
|
13
|
-
* of the artifact it publishes, so an installed package reports the release it
|
|
14
|
-
* came from while a checkout reports the version the manifest holds in git.
|
|
15
|
-
*
|
|
16
|
-
* It is one function because a version written in more than one place is two
|
|
17
|
-
* facts that can disagree: the version verb, the report envelope and anything
|
|
18
|
-
* else that names this analyzer read this one.
|
|
19
|
-
*/
|
|
20
|
-
export function version(): string {
|
|
21
|
-
return manifest.version;
|
|
22
|
-
}
|
|
7
|
+
export const CONTRACT_VERSION = "2.0.0";
|
package/bin/deadset-ts.mjs
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// Node refuses to strip types from a .ts file under node_modules, so the
|
|
3
|
-
// TypeScript entry cannot start from an install. A load hook scoped to this
|
|
4
|
-
// package's own files supplies the stripped source instead.
|
|
5
|
-
// https://nodejs.org/api/typescript.html#type-stripping-in-dependencies
|
|
6
|
-
import { readFileSync } from "node:fs";
|
|
7
|
-
import { registerHooks, stripTypeScriptTypes } from "node:module";
|
|
8
|
-
|
|
9
|
-
const packageRoot = new URL("../", import.meta.url).href;
|
|
10
|
-
|
|
11
|
-
registerHooks({
|
|
12
|
-
load(url, context, nextLoad) {
|
|
13
|
-
if (!url.startsWith(packageRoot) || !url.endsWith(".ts")) {
|
|
14
|
-
return nextLoad(url, context);
|
|
15
|
-
}
|
|
16
|
-
return {
|
|
17
|
-
format: "module",
|
|
18
|
-
source: stripTypeScriptTypes(readFileSync(new URL(url), "utf8")),
|
|
19
|
-
shortCircuit: true,
|
|
20
|
-
};
|
|
21
|
-
},
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
await import("./deadset-ts.ts");
|
package/bin/node-host.ts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { readdirSync, readFileSync, statSync } from "node:fs";
|
|
2
|
-
import type { DirectoryEntry, Host, PathKind } from "../src/host.ts";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* The filesystem of the platform the command runs on.
|
|
6
|
-
*
|
|
7
|
-
* It is the one module that names the platform: everything the analysis is made of
|
|
8
|
-
* takes the filesystem as a parameter, so a consumer compiling the published
|
|
9
|
-
* sources needs the compiler's types and nothing else.
|
|
10
|
-
*/
|
|
11
|
-
export function nodeHost(): Host {
|
|
12
|
-
return {
|
|
13
|
-
workingDirectory: () => process.cwd(),
|
|
14
|
-
readFile: (path) => readFileSync(path, "utf8"),
|
|
15
|
-
readDirectory: (path): readonly DirectoryEntry[] =>
|
|
16
|
-
readdirSync(path, { withFileTypes: true }).map((entry) => ({
|
|
17
|
-
name: entry.name,
|
|
18
|
-
directory: entry.isDirectory(),
|
|
19
|
-
})),
|
|
20
|
-
kindOf: (path): PathKind => {
|
|
21
|
-
const stat = statSync(path, { throwIfNoEntry: false });
|
|
22
|
-
if (stat === undefined) {
|
|
23
|
-
return "absent";
|
|
24
|
-
}
|
|
25
|
-
return stat.isDirectory() ? "directory" : "file";
|
|
26
|
-
},
|
|
27
|
-
};
|
|
28
|
-
}
|