@aoelite/refpact-ts 0.0.0-stage → 0.2.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 +38 -2
- package/dist/baseline.d.ts +26 -0
- package/dist/baseline.js +65 -0
- package/dist/core/index.d.ts +88 -0
- package/dist/core/index.js +105 -0
- package/dist/core/model.d.ts +340 -0
- package/dist/core/model.js +1 -0
- package/dist/core/results.d.ts +268 -0
- package/dist/core/results.js +1 -0
- package/dist/core/wasm.d.ts +7 -0
- package/dist/core/wasm.js +67 -0
- package/dist/custom.d.ts +166 -0
- package/dist/custom.js +239 -0
- package/dist/filters.d.ts +73 -0
- package/dist/filters.js +39 -0
- package/dist/frontend/checks.d.ts +15 -0
- package/dist/frontend/checks.js +12 -0
- package/dist/frontend/classic.d.ts +3 -0
- package/dist/frontend/classic.js +105 -0
- package/dist/frontend/compiler.d.ts +93 -0
- package/dist/frontend/compiler.js +116 -0
- package/dist/frontend/components.d.ts +29 -0
- package/dist/frontend/components.js +111 -0
- package/dist/frontend/declarations.d.ts +45 -0
- package/dist/frontend/declarations.js +158 -0
- package/dist/frontend/dependencies.d.ts +53 -0
- package/dist/frontend/dependencies.js +337 -0
- package/dist/frontend/imports.d.ts +149 -0
- package/dist/frontend/imports.js +765 -0
- package/dist/frontend/native.d.ts +3 -0
- package/dist/frontend/native.js +165 -0
- package/dist/frontend/paths.d.ts +10 -0
- package/dist/frontend/paths.js +18 -0
- package/dist/frontend/project.d.ts +118 -0
- package/dist/frontend/project.js +775 -0
- package/dist/group.d.ts +74 -0
- package/dist/group.js +106 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.js +27 -0
- package/dist/items.d.ts +133 -0
- package/dist/items.js +179 -0
- package/dist/layers.d.ts +112 -0
- package/dist/layers.js +215 -0
- package/dist/onion.d.ts +78 -0
- package/dist/onion.js +96 -0
- package/dist/patterns.d.ts +14 -0
- package/dist/patterns.js +15 -0
- package/dist/rules.d.ts +408 -0
- package/dist/rules.js +665 -0
- package/package.json +52 -4
- package/wasm/refpact_core.wasm +0 -0
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { Declaration, Fact, Path } from "../core/index.ts";
|
|
2
|
+
/**
|
|
3
|
+
* The kinds of the references that a `package.json` gives. Only a project that is loaded
|
|
4
|
+
* with `readDependencies` has them.
|
|
5
|
+
*
|
|
6
|
+
* - `dependency`, `dev-dependency`, `peer-dependency` and `optional-dependency`: a package
|
|
7
|
+
* that `dependencies`, `devDependencies`, `peerDependencies` or `optionalDependencies` names.
|
|
8
|
+
* - `transitive-dependency`: a package that the file does not name so, and that one of its
|
|
9
|
+
* `dependencies`, `peerDependencies` or `optionalDependencies` needs.
|
|
10
|
+
* - `transitive-dev-dependency`: a package that only its `devDependencies` need.
|
|
11
|
+
*
|
|
12
|
+
* Each of these references has the properties of its package, when the package is
|
|
13
|
+
* installed: its version and its licence.
|
|
14
|
+
*/
|
|
15
|
+
export declare const DEPENDENCY_KINDS: readonly ["dependency", "dev-dependency", "peer-dependency", "optional-dependency", "transitive-dependency", "transitive-dev-dependency"];
|
|
16
|
+
/** One of {@link DEPENDENCY_KINDS}. */
|
|
17
|
+
export type DependencyKind = (typeof DEPENDENCY_KINDS)[number];
|
|
18
|
+
/** The kinds of the dependencies that a `package.json` names itself. */
|
|
19
|
+
export declare const NAMED_DEPENDENCY_KINDS: readonly string[];
|
|
20
|
+
/**
|
|
21
|
+
* The properties of a reference to an installed package, from its own `package.json`:
|
|
22
|
+
*
|
|
23
|
+
* - `version`: its version, such as `4.17.21`.
|
|
24
|
+
* - `license`: its licence as the file writes it, such as `MIT` or `(MIT OR Apache-2.0)`. A
|
|
25
|
+
* package that names no licence has none.
|
|
26
|
+
*
|
|
27
|
+
* A package that is not installed has neither. Two versions of one package are two
|
|
28
|
+
* references.
|
|
29
|
+
*/
|
|
30
|
+
export declare const PACKAGE_PROPERTIES: readonly ["version", "license"];
|
|
31
|
+
/** The kind of the item that a `package.json` with a name declares: its package. */
|
|
32
|
+
export declare const PACKAGE_ITEM_KIND = "package";
|
|
33
|
+
/** What the `package.json` files of a project give. */
|
|
34
|
+
export interface DependencyFacts {
|
|
35
|
+
/** Each `package.json` as a unit, with the number of its lines. */
|
|
36
|
+
readonly units: readonly {
|
|
37
|
+
readonly path: Path;
|
|
38
|
+
readonly lines: number;
|
|
39
|
+
}[];
|
|
40
|
+
readonly facts: readonly Fact[];
|
|
41
|
+
/** The package that each `package.json` with a name declares. */
|
|
42
|
+
readonly declarations: readonly Declaration[];
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* The dependencies of the `package.json` files that the files of a project belong to. Each
|
|
46
|
+
* `package.json` is a unit under its path from the root, and each dependency is a reference
|
|
47
|
+
* from it to the package, at the line of its key.
|
|
48
|
+
*
|
|
49
|
+
* A package that another `package.json` of the project declares is also a reference to that
|
|
50
|
+
* file. A package that a dependency needs is found in the `node_modules` directories, as
|
|
51
|
+
* Node finds it; one that is not installed is not followed.
|
|
52
|
+
*/
|
|
53
|
+
export declare function dependencyFacts(root: string, files: readonly string[]): DependencyFacts;
|
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The dependencies that the `package.json` files of a project name: each is a reference
|
|
3
|
+
* from the `package.json` to a package, so that a rule can say which package may depend on
|
|
4
|
+
* which. This is the one place that reads `package.json` files.
|
|
5
|
+
*/
|
|
6
|
+
import { existsSync, readFileSync, realpathSync } from "node:fs";
|
|
7
|
+
import path from "node:path";
|
|
8
|
+
import { exportSegment, packageSegment } from "./paths.js";
|
|
9
|
+
/**
|
|
10
|
+
* The kinds of the references that a `package.json` gives. Only a project that is loaded
|
|
11
|
+
* with `readDependencies` has them.
|
|
12
|
+
*
|
|
13
|
+
* - `dependency`, `dev-dependency`, `peer-dependency` and `optional-dependency`: a package
|
|
14
|
+
* that `dependencies`, `devDependencies`, `peerDependencies` or `optionalDependencies` names.
|
|
15
|
+
* - `transitive-dependency`: a package that the file does not name so, and that one of its
|
|
16
|
+
* `dependencies`, `peerDependencies` or `optionalDependencies` needs.
|
|
17
|
+
* - `transitive-dev-dependency`: a package that only its `devDependencies` need.
|
|
18
|
+
*
|
|
19
|
+
* Each of these references has the properties of its package, when the package is
|
|
20
|
+
* installed: its version and its licence.
|
|
21
|
+
*/
|
|
22
|
+
export const DEPENDENCY_KINDS = [
|
|
23
|
+
"dependency",
|
|
24
|
+
"dev-dependency",
|
|
25
|
+
"peer-dependency",
|
|
26
|
+
"optional-dependency",
|
|
27
|
+
"transitive-dependency",
|
|
28
|
+
"transitive-dev-dependency",
|
|
29
|
+
];
|
|
30
|
+
/** The kinds of the dependencies that a `package.json` names itself. */
|
|
31
|
+
export const NAMED_DEPENDENCY_KINDS = ["dependency", "dev-dependency", "peer-dependency", "optional-dependency"];
|
|
32
|
+
/**
|
|
33
|
+
* The properties of a reference to an installed package, from its own `package.json`:
|
|
34
|
+
*
|
|
35
|
+
* - `version`: its version, such as `4.17.21`.
|
|
36
|
+
* - `license`: its licence as the file writes it, such as `MIT` or `(MIT OR Apache-2.0)`. A
|
|
37
|
+
* package that names no licence has none.
|
|
38
|
+
*
|
|
39
|
+
* A package that is not installed has neither. Two versions of one package are two
|
|
40
|
+
* references.
|
|
41
|
+
*/
|
|
42
|
+
export const PACKAGE_PROPERTIES = ["version", "license"];
|
|
43
|
+
/** The kind of the item that a `package.json` with a name declares: its package. */
|
|
44
|
+
export const PACKAGE_ITEM_KIND = "package";
|
|
45
|
+
/** The keys of a `package.json` that name dependencies, with the kind of each. */
|
|
46
|
+
const SECTIONS = [
|
|
47
|
+
["dependencies", "dependency"],
|
|
48
|
+
["devDependencies", "dev-dependency"],
|
|
49
|
+
["peerDependencies", "peer-dependency"],
|
|
50
|
+
["optionalDependencies", "optional-dependency"],
|
|
51
|
+
];
|
|
52
|
+
/** The keys whose packages are needed where the package is installed. */
|
|
53
|
+
const INSTALLED = ["dependencies", "peerDependencies", "optionalDependencies"];
|
|
54
|
+
/**
|
|
55
|
+
* The places of the keys of a JSON text: for each key at the top that has an object, the
|
|
56
|
+
* keys of that object. The key `""` has the keys at the top themselves.
|
|
57
|
+
*/
|
|
58
|
+
function keyPlaces(text) {
|
|
59
|
+
const found = new Map();
|
|
60
|
+
const record = (section, key, place) => {
|
|
61
|
+
const keys = found.get(section) ?? new Map();
|
|
62
|
+
found.set(section, keys);
|
|
63
|
+
if (!keys.has(key)) {
|
|
64
|
+
keys.set(key, place);
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
let depth = 0;
|
|
68
|
+
let section;
|
|
69
|
+
let line = 1;
|
|
70
|
+
let lineStart = 0;
|
|
71
|
+
for (let at = 0; at < text.length; at++) {
|
|
72
|
+
const char = text[at];
|
|
73
|
+
if (char === "\n") {
|
|
74
|
+
line += 1;
|
|
75
|
+
lineStart = at + 1;
|
|
76
|
+
}
|
|
77
|
+
else if (char === "{" || char === "[") {
|
|
78
|
+
depth += 1;
|
|
79
|
+
}
|
|
80
|
+
else if (char === "}" || char === "]") {
|
|
81
|
+
depth -= 1;
|
|
82
|
+
}
|
|
83
|
+
else if (char === '"') {
|
|
84
|
+
let end = at + 1;
|
|
85
|
+
while (end < text.length && text[end] !== '"') {
|
|
86
|
+
end += text[end] === "\\" ? 2 : 1;
|
|
87
|
+
}
|
|
88
|
+
let after = end + 1;
|
|
89
|
+
while (after < text.length && /\s/.test(text[after])) {
|
|
90
|
+
after += 1;
|
|
91
|
+
}
|
|
92
|
+
if (text[after] === ":" && depth <= 2) {
|
|
93
|
+
const key = JSON.parse(text.slice(at, end + 1));
|
|
94
|
+
const place = { line, column: at - lineStart + 1 };
|
|
95
|
+
if (depth === 1) {
|
|
96
|
+
section = key;
|
|
97
|
+
record("", key, place);
|
|
98
|
+
}
|
|
99
|
+
else if (section !== undefined) {
|
|
100
|
+
record(section, key, place);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
at = end;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return found;
|
|
107
|
+
}
|
|
108
|
+
function read(file) {
|
|
109
|
+
if (!existsSync(file)) {
|
|
110
|
+
return undefined;
|
|
111
|
+
}
|
|
112
|
+
const text = readFileSync(file, "utf8");
|
|
113
|
+
let json;
|
|
114
|
+
try {
|
|
115
|
+
json = JSON.parse(text);
|
|
116
|
+
}
|
|
117
|
+
catch (error) {
|
|
118
|
+
throw new Error(`refpact: cannot read ${file}: ${error.message}`);
|
|
119
|
+
}
|
|
120
|
+
const places = keyPlaces(text);
|
|
121
|
+
const name = typeof json["name"] === "string" ? json["name"] : undefined;
|
|
122
|
+
// A `package.json` that has no name and no dependencies, such as one that only sets `"type"`, describes no package.
|
|
123
|
+
if (name === undefined && SECTIONS.every(([section]) => (places.get(section)?.size ?? 0) === 0)) {
|
|
124
|
+
return undefined;
|
|
125
|
+
}
|
|
126
|
+
return { file, name, lines: text.split("\n").length - (text.endsWith("\n") ? 1 : 0), places, namePlace: places.get("")?.get("name") };
|
|
127
|
+
}
|
|
128
|
+
/** Finds the `package.json` that a file belongs to. */
|
|
129
|
+
class Manifests {
|
|
130
|
+
byDirectory = new Map();
|
|
131
|
+
/** The nearest `package.json` that describes a package, in the directory of the file or above it. */
|
|
132
|
+
of(file) {
|
|
133
|
+
return this.inDirectory(path.dirname(file));
|
|
134
|
+
}
|
|
135
|
+
inDirectory(directory) {
|
|
136
|
+
if (this.byDirectory.has(directory)) {
|
|
137
|
+
return this.byDirectory.get(directory);
|
|
138
|
+
}
|
|
139
|
+
const parent = path.dirname(directory);
|
|
140
|
+
const found = read(path.join(directory, "package.json")) ?? (parent === directory ? undefined : this.inDirectory(parent));
|
|
141
|
+
this.byDirectory.set(directory, found);
|
|
142
|
+
return found;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
/** The packages that are installed, as `node_modules` directories have them. */
|
|
146
|
+
class Installed {
|
|
147
|
+
found = new Map();
|
|
148
|
+
read = new Map();
|
|
149
|
+
/** The directory of the package that code in `from` gets for a name, without links; `undefined` when it is not installed. */
|
|
150
|
+
resolve(from, name) {
|
|
151
|
+
const key = `${from}\u0000${name}`;
|
|
152
|
+
if (this.found.has(key)) {
|
|
153
|
+
return this.found.get(key);
|
|
154
|
+
}
|
|
155
|
+
let found;
|
|
156
|
+
for (let directory = from;; directory = path.dirname(directory)) {
|
|
157
|
+
const candidate = path.join(directory, "node_modules", name);
|
|
158
|
+
if (existsSync(path.join(candidate, "package.json"))) {
|
|
159
|
+
found = realpathSync(candidate);
|
|
160
|
+
break;
|
|
161
|
+
}
|
|
162
|
+
if (path.dirname(directory) === directory) {
|
|
163
|
+
break;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
this.found.set(key, found);
|
|
167
|
+
return found;
|
|
168
|
+
}
|
|
169
|
+
/** What the `package.json` of the package in a directory says. */
|
|
170
|
+
package(directory) {
|
|
171
|
+
let found = this.read.get(directory);
|
|
172
|
+
if (found === undefined) {
|
|
173
|
+
let json = {};
|
|
174
|
+
try {
|
|
175
|
+
json = JSON.parse(readFileSync(path.join(directory, "package.json"), "utf8"));
|
|
176
|
+
}
|
|
177
|
+
catch {
|
|
178
|
+
// A package that cannot be read needs nothing that can be followed, and says nothing.
|
|
179
|
+
}
|
|
180
|
+
const needs = INSTALLED.flatMap((key) => {
|
|
181
|
+
const value = json[key];
|
|
182
|
+
return typeof value === "object" && value !== null ? Object.keys(value) : [];
|
|
183
|
+
});
|
|
184
|
+
// An old form of the licence is an object with the name as its `type`.
|
|
185
|
+
const license = json["license"];
|
|
186
|
+
const named = typeof license === "object" && license !== null ? license["type"] : license;
|
|
187
|
+
const properties = {};
|
|
188
|
+
for (const name of PACKAGE_PROPERTIES) {
|
|
189
|
+
const value = name === "license" ? named : json[name];
|
|
190
|
+
if (typeof value === "string") {
|
|
191
|
+
properties[name] = value;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
found = { needs, properties };
|
|
195
|
+
this.read.set(directory, found);
|
|
196
|
+
}
|
|
197
|
+
return found;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* The dependencies of the `package.json` files that the files of a project belong to. Each
|
|
202
|
+
* `package.json` is a unit under its path from the root, and each dependency is a reference
|
|
203
|
+
* from it to the package, at the line of its key.
|
|
204
|
+
*
|
|
205
|
+
* A package that another `package.json` of the project declares is also a reference to that
|
|
206
|
+
* file. A package that a dependency needs is found in the `node_modules` directories, as
|
|
207
|
+
* Node finds it; one that is not installed is not followed.
|
|
208
|
+
*/
|
|
209
|
+
export function dependencyFacts(root, files) {
|
|
210
|
+
const manifests = new Manifests();
|
|
211
|
+
const found = new Map();
|
|
212
|
+
for (const file of files) {
|
|
213
|
+
const manifest = manifests.of(file);
|
|
214
|
+
if (manifest !== undefined) {
|
|
215
|
+
found.set(manifest.file, manifest);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
const unitOf = (manifest) => path.relative(root, manifest.file).split(path.sep);
|
|
219
|
+
const ordered = [...found.values()].sort((a, b) => {
|
|
220
|
+
const [left, right] = [unitOf(a).join("/"), unitOf(b).join("/")];
|
|
221
|
+
return left < right ? -1 : left > right ? 1 : 0;
|
|
222
|
+
});
|
|
223
|
+
const byName = new Map();
|
|
224
|
+
for (const manifest of ordered) {
|
|
225
|
+
if (manifest.name !== undefined && !byName.has(manifest.name)) {
|
|
226
|
+
byName.set(manifest.name, unitOf(manifest));
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
const installed = new Installed();
|
|
230
|
+
const facts = [];
|
|
231
|
+
const declarations = [];
|
|
232
|
+
for (const manifest of ordered) {
|
|
233
|
+
const unit = unitOf(manifest);
|
|
234
|
+
const file = unit.join("/");
|
|
235
|
+
// `at` is the directory of the package, when it is installed.
|
|
236
|
+
const add = (kind, name, place, at, note) => {
|
|
237
|
+
const sibling = byName.get(name);
|
|
238
|
+
const properties = at !== undefined ? installed.package(at).properties : {};
|
|
239
|
+
facts.push({
|
|
240
|
+
unit,
|
|
241
|
+
file,
|
|
242
|
+
line: place.line,
|
|
243
|
+
column: place.column,
|
|
244
|
+
tags: [],
|
|
245
|
+
...(note !== undefined ? { note } : {}),
|
|
246
|
+
what: {
|
|
247
|
+
type: "reference",
|
|
248
|
+
target: [packageSegment(name)],
|
|
249
|
+
aliases: sibling !== undefined && sibling !== unit ? [sibling] : [],
|
|
250
|
+
kind,
|
|
251
|
+
certainty: "exact",
|
|
252
|
+
...(Object.keys(properties).length > 0 ? { properties } : {}),
|
|
253
|
+
},
|
|
254
|
+
});
|
|
255
|
+
};
|
|
256
|
+
if (manifest.name !== undefined && manifest.namePlace !== undefined) {
|
|
257
|
+
declarations.push({
|
|
258
|
+
path: [...unit, exportSegment(manifest.name)],
|
|
259
|
+
name: manifest.name,
|
|
260
|
+
unit,
|
|
261
|
+
file,
|
|
262
|
+
line: manifest.namePlace.line,
|
|
263
|
+
column: manifest.namePlace.column,
|
|
264
|
+
tags: [],
|
|
265
|
+
kind: PACKAGE_ITEM_KIND,
|
|
266
|
+
visibility: "exported",
|
|
267
|
+
relations: [],
|
|
268
|
+
modifiers: [],
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
const named = [];
|
|
272
|
+
for (const [section, kind] of SECTIONS) {
|
|
273
|
+
for (const [name, place] of manifest.places.get(section) ?? []) {
|
|
274
|
+
named.push({ kind, name, place });
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
named.sort((a, b) => a.place.line - b.place.line || a.place.column - b.place.column);
|
|
278
|
+
const directory = path.dirname(manifest.file);
|
|
279
|
+
for (const { kind, name, place } of named) {
|
|
280
|
+
add(kind, name, place, installed.resolve(directory, name));
|
|
281
|
+
}
|
|
282
|
+
// What the dependencies need, on the shortest way first. A package is found on the way
|
|
283
|
+
// that says most: first through what is installed with the package, then through what
|
|
284
|
+
// only its development needs.
|
|
285
|
+
// A package is known by its name and its version: another version of a package that
|
|
286
|
+
// the file names is another package. One that is not installed has no version, and
|
|
287
|
+
// then the name stands for all of them, as the name of the own package does.
|
|
288
|
+
const known = new Set();
|
|
289
|
+
const know = (name, at) => {
|
|
290
|
+
known.add(at !== undefined ? `${name}@${installed.package(at).properties["version"] ?? ""}` : name);
|
|
291
|
+
};
|
|
292
|
+
const isKnown = (name, at) => known.has(name) || known.has(`${name}@${installed.package(at).properties["version"] ?? ""}`);
|
|
293
|
+
for (const { kind, name } of named) {
|
|
294
|
+
if (kind !== "dev-dependency") {
|
|
295
|
+
know(name, installed.resolve(directory, name));
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
if (manifest.name !== undefined) {
|
|
299
|
+
known.add(manifest.name);
|
|
300
|
+
}
|
|
301
|
+
const walk = (development) => {
|
|
302
|
+
const kind = development ? "transitive-dev-dependency" : "transitive-dependency";
|
|
303
|
+
const seen = new Set([realpathSync(directory)]);
|
|
304
|
+
const queue = [];
|
|
305
|
+
for (const { kind: of, name, place } of named) {
|
|
306
|
+
const at = (of === "dev-dependency") === development ? installed.resolve(directory, name) : undefined;
|
|
307
|
+
if (at !== undefined && !seen.has(at)) {
|
|
308
|
+
seen.add(at);
|
|
309
|
+
queue.push({ at, place, through: [name] });
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
for (let next = 0; next < queue.length; next++) {
|
|
313
|
+
const { at, place, through } = queue[next];
|
|
314
|
+
for (const name of installed.package(at).needs) {
|
|
315
|
+
const needed = installed.resolve(at, name);
|
|
316
|
+
if (needed === undefined || seen.has(needed)) {
|
|
317
|
+
continue;
|
|
318
|
+
}
|
|
319
|
+
seen.add(needed);
|
|
320
|
+
if (!isKnown(name, needed)) {
|
|
321
|
+
know(name, needed);
|
|
322
|
+
add(kind, name, place, needed, `through ${through.map((one) => `\`${one}\``).join(", ")}`);
|
|
323
|
+
}
|
|
324
|
+
queue.push({ at: needed, place, through: [...through, name] });
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
};
|
|
328
|
+
walk(false);
|
|
329
|
+
for (const { kind, name } of named) {
|
|
330
|
+
if (kind === "dev-dependency") {
|
|
331
|
+
know(name, installed.resolve(directory, name));
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
walk(true);
|
|
335
|
+
}
|
|
336
|
+
return { units: ordered.map((manifest) => ({ path: unitOf(manifest), lines: manifest.lines })), facts, declarations };
|
|
337
|
+
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import type { Node, SourceFile } from "./compiler.ts";
|
|
2
|
+
import type { DependencyKind } from "./dependencies.ts";
|
|
3
|
+
/** The reference kinds of the TypeScript front end. */
|
|
4
|
+
export declare const KINDS: readonly ["import", "import-type", "dynamic-import", "require", "export-from", "export-type-from", "resolve", "global"];
|
|
5
|
+
/**
|
|
6
|
+
* The kind of a place that asks where a module is and does not load it: `require.resolve("m")`,
|
|
7
|
+
* `import.meta.resolve("m")` and `new URL("./m", import.meta.url)`.
|
|
8
|
+
*/
|
|
9
|
+
export declare const RESOLVE_KIND: Kind;
|
|
10
|
+
/**
|
|
11
|
+
* The kind of a use of a global of the host, such as `process.env` or `fetch(..)`: a name
|
|
12
|
+
* that no file of the project declares and that the ECMAScript library does not declare.
|
|
13
|
+
*/
|
|
14
|
+
export declare const GLOBAL_KIND: Kind;
|
|
15
|
+
/**
|
|
16
|
+
* The kind of a use of a member of a class, an interface or an enum: `order.total`. Only a
|
|
17
|
+
* project that is loaded with `resolveMembers` has this kind.
|
|
18
|
+
*/
|
|
19
|
+
export declare const MEMBER_KIND: Kind;
|
|
20
|
+
/** One of the reference kinds of the TypeScript front end. */
|
|
21
|
+
export type Kind = (typeof KINDS)[number] | "member" | DependencyKind;
|
|
22
|
+
/** One name taken from a module: `a` in `import { a as b } from "m"`. */
|
|
23
|
+
export interface NameUse {
|
|
24
|
+
/** The name as the module exports it. `default` for a default import. */
|
|
25
|
+
readonly exported: string;
|
|
26
|
+
readonly kind: Kind;
|
|
27
|
+
/** The node that carries the position and the symbol. */
|
|
28
|
+
readonly node: Node;
|
|
29
|
+
/**
|
|
30
|
+
* True for a name in the braces of an `import` or an `export ... from`. The symbol of such
|
|
31
|
+
* a name is an alias of the export that the module has under `exported`.
|
|
32
|
+
*/
|
|
33
|
+
readonly specifier?: true;
|
|
34
|
+
}
|
|
35
|
+
/** A local name that stands for a whole module: `ns` in `import * as ns from "m"`. */
|
|
36
|
+
export interface NamespaceBinding {
|
|
37
|
+
readonly local: string;
|
|
38
|
+
readonly node: Node;
|
|
39
|
+
readonly kind: Kind;
|
|
40
|
+
}
|
|
41
|
+
/** One statement or expression that names a module. */
|
|
42
|
+
export interface ModuleUse {
|
|
43
|
+
readonly specifier: string;
|
|
44
|
+
readonly specifierNode: Node;
|
|
45
|
+
/** The node whose position is reported for a use of the module as a whole. */
|
|
46
|
+
readonly at: Node;
|
|
47
|
+
readonly kind: Kind;
|
|
48
|
+
/** True when the construct uses the module as a whole and not only some names of it. */
|
|
49
|
+
readonly whole: boolean;
|
|
50
|
+
readonly names: readonly NameUse[];
|
|
51
|
+
readonly namespace?: NamespaceBinding;
|
|
52
|
+
/** The `require` identifier of a `require("m")` call. It may be a local name, not Node's. */
|
|
53
|
+
readonly requireNode?: Node;
|
|
54
|
+
/**
|
|
55
|
+
* How the code gives the specifier, when it is not one string in the place.
|
|
56
|
+
* - `constant`: the code computes it from strings that are known, and `specifier` is the result.
|
|
57
|
+
* - `pattern`: a part is not known. `specifier` has a `*` for each such part.
|
|
58
|
+
* - `glob`: the argument of `import.meta.glob`, which is a glob pattern.
|
|
59
|
+
* - `unknown`: nothing of it is known. `specifier` is empty.
|
|
60
|
+
*/
|
|
61
|
+
readonly computed?: "constant" | "pattern" | "glob" | "unknown";
|
|
62
|
+
/**
|
|
63
|
+
* The names of constants that the specifier is computed from, each with the name of the
|
|
64
|
+
* declaration that was read. The value holds only when the compiler says that both are
|
|
65
|
+
* one variable.
|
|
66
|
+
*/
|
|
67
|
+
readonly constants?: readonly {
|
|
68
|
+
readonly use: Node;
|
|
69
|
+
readonly declaration: Node;
|
|
70
|
+
}[];
|
|
71
|
+
/** True for `new URL(..)`, which may name a file that is no module, such as an image. */
|
|
72
|
+
readonly asset?: true;
|
|
73
|
+
}
|
|
74
|
+
/** `object.member` or `object.member` in a type, where `object` may be a namespace binding. */
|
|
75
|
+
export interface MemberUse {
|
|
76
|
+
readonly object: Node;
|
|
77
|
+
readonly member: Node;
|
|
78
|
+
readonly objectName: string;
|
|
79
|
+
readonly memberName: string;
|
|
80
|
+
/**
|
|
81
|
+
* For a member of a `const` that stands for a namespace binding, `const f = ns; f.name`: the
|
|
82
|
+
* name of the declaration of the `const`, and the name of the binding in its value.
|
|
83
|
+
* `object` is then the `const` where it is used, and `objectName` is the name of the binding.
|
|
84
|
+
*/
|
|
85
|
+
readonly alias?: {
|
|
86
|
+
readonly declaration: Node;
|
|
87
|
+
readonly of: Node;
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Finds every construct of the file that names a module.
|
|
92
|
+
*
|
|
93
|
+
* `prune` lets the visit leave out nodes, see {@link Mentions}. It must be `false` for a
|
|
94
|
+
* JavaScript file: the compiler makes nodes from the types in JSDoc comments, and such a node
|
|
95
|
+
* is in the text before the node that it belongs to, not in it.
|
|
96
|
+
*/
|
|
97
|
+
export declare function collectModuleUses(sourceFile: SourceFile, prune: boolean): ModuleUse[];
|
|
98
|
+
/** Finds `object.member` where `object` is one of the given local names. */
|
|
99
|
+
export declare function collectMemberUses(sourceFile: SourceFile, locals: ReadonlySet<string>, prune: boolean): MemberUse[];
|
|
100
|
+
/**
|
|
101
|
+
* The names after the dot of each `object.name` of a file, in the order of the text. What a
|
|
102
|
+
* name is a member of depends on the type of the object, which only the compiler knows.
|
|
103
|
+
* Every node of the file is visited.
|
|
104
|
+
*/
|
|
105
|
+
export declare function collectAccesses(sourceFile: SourceFile): Node[];
|
|
106
|
+
/**
|
|
107
|
+
* A name in a file that may be a global: `fetch` in `fetch(..)`, or `process` and its member
|
|
108
|
+
* `env` in `process.env`. Through `globalThis`, `window`, `self` and `global`, the global is
|
|
109
|
+
* the name after the dot: `window.localStorage` is `localStorage`. Only the compiler can tell
|
|
110
|
+
* whether the names are globals: `node` and `through` are the nodes to ask.
|
|
111
|
+
*/
|
|
112
|
+
export interface GlobalUse {
|
|
113
|
+
/** The node that carries the position. */
|
|
114
|
+
readonly at: Node;
|
|
115
|
+
/** The node of the name of the global. */
|
|
116
|
+
readonly node: Node;
|
|
117
|
+
/** The name of the global. */
|
|
118
|
+
readonly name: string;
|
|
119
|
+
/** The member of the global that is used, if any: `env` in `process.env`. */
|
|
120
|
+
readonly member?: string;
|
|
121
|
+
/** `globalThis`, `window`, `self` or `global`, when the global is written as its member. */
|
|
122
|
+
readonly through?: Node;
|
|
123
|
+
/** The shorthand property that the name is, `{ fetch }`: the compiler is asked for its value apart. */
|
|
124
|
+
readonly shorthand?: Node;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* The names in value positions that may be globals, in the order of the text. Types,
|
|
128
|
+
* the names after a dot, JSX tags and the callee of `require(..)` are left out.
|
|
129
|
+
*/
|
|
130
|
+
export declare function collectGlobalUses(sourceFile: SourceFile): GlobalUse[];
|
|
131
|
+
/**
|
|
132
|
+
* The markers that a file can contain: a use of the global `console`, a `debugger`
|
|
133
|
+
* statement, and `unresolved-import`, an import of a relative path, a `paths` alias or a
|
|
134
|
+
* `#name` of `imports` that leads to no file.
|
|
135
|
+
*/
|
|
136
|
+
export declare const MARKERS: readonly ["console", "debugger", "unresolved-import", "computed-import"];
|
|
137
|
+
/** One of {@link MARKERS}. */
|
|
138
|
+
export type MarkerName = (typeof MARKERS)[number];
|
|
139
|
+
/**
|
|
140
|
+
* A place that may be a marker. A `debugger` statement is one. `console.name` is one when
|
|
141
|
+
* `console` is the global, which only the compiler can tell: `object` is the node to ask.
|
|
142
|
+
*/
|
|
143
|
+
export interface MarkerUse {
|
|
144
|
+
readonly marker: MarkerName;
|
|
145
|
+
readonly at: Node;
|
|
146
|
+
readonly object?: Node;
|
|
147
|
+
}
|
|
148
|
+
/** The `debugger` statements of a file, and its `console.name`, in the order of the text. */
|
|
149
|
+
export declare function collectMarkers(sourceFile: SourceFile, prune: boolean): MarkerUse[];
|