@cplieger/deadset-ts 4.0.0 → 5.0.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 +68 -50
- package/dist/bin/component-mapper.js +5 -0
- package/dist/bin/mapper-connection.js +101 -0
- package/dist/bin/node-host.js +24 -2
- package/dist/src/analysis.js +230 -37
- package/dist/src/component-files.js +612 -0
- package/dist/src/component-layer.js +132 -0
- package/dist/src/config.js +9 -2
- package/dist/src/configuration-files.js +186 -0
- package/dist/src/conformance-record.js +2 -2
- package/dist/src/convention-rows.js +383 -0
- package/dist/src/conventions.js +456 -0
- package/dist/src/dependencies.js +30 -3
- package/dist/src/discover.js +11 -4
- package/dist/src/emit-map.js +72 -0
- package/dist/src/entry-point-gaps.js +81 -35
- package/dist/src/entry-points.js +47 -32
- package/dist/src/exempt.js +11 -3
- package/dist/src/findings/completion.js +19 -29
- package/dist/src/findings/emitters.js +22 -1
- package/dist/src/findings/unused-declarations.js +7 -2
- package/dist/src/graph.js +13 -5
- package/dist/src/inventory.js +4 -2
- package/dist/src/kinds.js +2 -2
- package/dist/src/manifest.js +37 -11
- package/dist/src/matrix.js +21 -13
- package/dist/src/partial.js +3 -1
- package/dist/src/pnpm-workspace.js +120 -0
- package/dist/src/position.js +17 -2
- package/dist/src/print.js +2 -0
- package/dist/src/references.js +209 -30
- package/dist/src/report.js +26 -6
- package/dist/src/reporters/annotations.js +10 -3
- package/dist/src/reporters/template.js +6 -3
- package/dist/src/resolve.js +31 -6
- package/dist/src/roots.js +37 -8
- package/dist/src/run.js +13 -3
- package/dist/src/schema.js +4 -2
- package/dist/src/session.js +141 -34
- package/dist/src/setup-failure.js +23 -0
- package/dist/src/source-files.js +4 -61
- package/dist/src/sweep.js +4 -2
- package/dist/src/template-field.js +38 -6
- package/dist/src/test-support.js +59 -0
- package/dist/src/type-errors.js +252 -0
- package/dist/src/type-query-alias.js +92 -0
- package/dist/src/verbs/analyze.js +24 -4
- package/dist/src/verbs/explain.js +4 -1
- package/dist/src/verbs/print-projects.js +17 -56
- package/dist/src/verbs/print-retained.js +7 -2
- package/dist/src/verbs/print-roots.js +7 -2
- package/dist/src/version-range.js +255 -0
- package/dist/src/version.js +1 -1
- package/dist/src/workspace-manifests.js +68 -0
- package/dist/src/workspace-programs.js +342 -0
- package/dist/src/workspace-resolution.js +307 -0
- package/dist/src/workspace-run.js +75 -0
- package/dist/src/workspace.js +358 -0
- package/jsr.json +1 -1
- package/package.json +2 -1
- package/src/analysis.ts +395 -71
- package/src/component-files.ts +718 -0
- package/src/component-layer.ts +160 -0
- package/src/config.ts +11 -2
- package/src/configuration-files.ts +235 -0
- package/src/conformance-record.ts +2 -2
- package/src/convention-rows.ts +440 -0
- package/src/conventions.ts +640 -0
- package/src/dependencies.ts +36 -2
- package/src/discover.ts +11 -7
- package/src/emit-map.ts +93 -0
- package/src/entry-point-gaps.ts +92 -38
- package/src/entry-points.ts +66 -36
- package/src/exempt.ts +21 -3
- package/src/findings/completion.ts +24 -33
- package/src/findings/emitters.ts +32 -1
- package/src/findings/unused-declarations.ts +9 -2
- package/src/graph.ts +15 -4
- package/src/host.ts +23 -0
- package/src/index.ts +1 -1
- package/src/inventory.ts +13 -2
- package/src/kinds.ts +2 -2
- package/src/manifest.ts +47 -14
- package/src/matrix.ts +43 -15
- package/src/partial.ts +6 -1
- package/src/pnpm-workspace.ts +135 -0
- package/src/position.ts +23 -2
- package/src/print.ts +2 -0
- package/src/references.ts +227 -28
- package/src/report.ts +56 -6
- package/src/reporters/annotations.ts +12 -3
- package/src/reporters/template.ts +6 -3
- package/src/resolve.ts +59 -6
- package/src/roots.ts +60 -9
- package/src/run.ts +15 -5
- package/src/schema.ts +4 -2
- package/src/session.ts +218 -37
- package/src/setup-failure.ts +39 -0
- package/src/source-files.ts +4 -66
- package/src/sweep.ts +9 -2
- package/src/template-field.ts +42 -7
- package/src/test-support.ts +77 -0
- package/src/type-errors.ts +340 -0
- package/src/type-query-alias.ts +133 -0
- package/src/verbs/analyze.ts +38 -4
- package/src/verbs/explain.ts +4 -1
- package/src/verbs/print-projects.ts +17 -69
- package/src/verbs/print-retained.ts +7 -2
- package/src/verbs/print-roots.ts +7 -2
- package/src/verbs/verb.ts +6 -3
- package/src/version-range.ts +309 -0
- package/src/version.ts +1 -1
- package/src/workspace-manifests.ts +100 -0
- package/src/workspace-programs.ts +486 -0
- package/src/workspace-resolution.ts +393 -0
- package/src/workspace-run.ts +148 -0
- package/src/workspace.ts +463 -0
package/README.md
CHANGED
|
@@ -2,13 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/@cplieger/deadset-ts) [](https://jsr.io/@cplieger/deadset-ts)
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
deadset-ts finds dead code in TypeScript projects, down to class members, type members and dead stores inside functions, and writes a report your CI can fail on.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
It reads your `tsconfig.json` projects, `allowJs` JavaScript and Vue, Svelte and Astro scripts included, with the type information of TypeScript 7.1.0-dev.20261003.1, its one dependency. Your project keeps its own TypeScript version. A type error under that version skips the function or statement that holds it. deadset-ts reports and never edits your code. It is pre-release, tested only on Linux, needs Node.js 24 or later and is licensed under GPL-3.0-or-later.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
## Why use it
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
deadset-ts is built for a CI gate on dead code. Each finding names code to delete, an `export` to drop or a setting to fix.
|
|
12
|
+
|
|
13
|
+
- It reports unused exports, files and dependencies, and unused members of classes, interfaces, type aliases, enums and namespaces, private and static included.
|
|
14
|
+
- Inside a function, it reports unused parameters and results, unreachable statements and cases, and dead stores.
|
|
15
|
+
- It reports an `export` only its own file uses, and declarations that only reference each other.
|
|
16
|
+
- It keeps what decorators, reflective lookups, `JSON.stringify` and the frameworks, containers, serializers and templates you name in `deadset.json` use.
|
|
17
|
+
- The same tree gives the same report, and a baseline keyed on code and symbol survives moved lines.
|
|
18
|
+
- It writes text, JSON, GitHub annotations, SARIF 2.1.0 or a custom template.
|
|
19
|
+
|
|
20
|
+
Consider [Knip](https://knip.dev) if you want issues fixed with `--fix`, plugins for over 100 tools, or MDX files checked.
|
|
12
21
|
|
|
13
22
|
## Install
|
|
14
23
|
|
|
@@ -20,74 +29,83 @@ npx jsr add -D @cplieger/deadset-ts
|
|
|
20
29
|
npx @cplieger/deadset-ts version
|
|
21
30
|
```
|
|
22
31
|
|
|
23
|
-
The npm package carries the command and the library as JavaScript that the compiler emits at publish, so `npx deadset-ts` and `import("@cplieger/deadset-ts")` both run on plain Node.js 24 or later, with no loader and no flag. It carries the TypeScript source as well, which is what a TypeScript consumer's own compiler resolves. That consumer sets `allowImportingTsExtensions`, because the source names each import with its `.ts` extension. The JSR package ships source only, and Deno compiles it: a Deno program imports and type-checks the library, but the compiler's synchronous session does not open under Deno, so running an analysis needs Node.
|
|
24
|
-
|
|
25
32
|
## Usage
|
|
26
33
|
|
|
34
|
+
Create a `deadset.json` at the project root that says whether the project is an `application` or a `library`, then run `analyze`. A run reads every `tsconfig` project under that folder, project references included, and reports a declaration only when it is dead in all of them.
|
|
35
|
+
|
|
27
36
|
```sh
|
|
28
|
-
|
|
37
|
+
echo '{ "target": { "kind": "application" } }' > deadset.json
|
|
38
|
+
npx @cplieger/deadset-ts analyze --report=deadset-report.json
|
|
29
39
|
```
|
|
30
40
|
|
|
31
|
-
`
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
41
|
+
`analyze` writes the JSON report to `deadset-report.json` and a text rendering beside it as `deadset-report.json.txt`. Take this `src/greet.ts`, where the rest of the project calls only `greet` and `Counter.increment`:
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
export function greet(name: string): string {
|
|
45
|
+
return `hello ${name}`;
|
|
46
|
+
}
|
|
47
|
+
export function farewell(name: string): string {
|
|
48
|
+
return `bye ${name}`;
|
|
49
|
+
}
|
|
50
|
+
export class Counter {
|
|
51
|
+
private count = 0;
|
|
52
|
+
increment(): void {
|
|
53
|
+
this.count += 1;
|
|
54
|
+
}
|
|
55
|
+
reset(): void {
|
|
56
|
+
this.count = 0;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
```
|
|
49
60
|
|
|
50
|
-
|
|
61
|
+
The text rendering lists three findings:
|
|
51
62
|
|
|
52
|
-
|
|
63
|
+
```text
|
|
64
|
+
src/greet.ts:4:17: function farewell: exported function has no reference in the target and none from any loaded consumer [certain] (DS1001)
|
|
65
|
+
src/greet.ts:8:11: class-member Counter.count: member Counter.count is written at 2 positions and never read [certain] (DS1301)
|
|
66
|
+
src/greet.ts:12:3: method Counter.reset: method has no reference in the target [certain] (DS1003)
|
|
67
|
+
summary: 3 findings (0 allow, 0 warn, 3 deny), 6 deletable lines, 0 suppressions in effect, 0 reasons recorded, 0 stale suppressions, 0 pending, 0 omitted
|
|
68
|
+
```
|
|
53
69
|
|
|
54
|
-
The
|
|
70
|
+
The run exits 1 because the report holds a finding at `deny` severity, and 0 when it holds none. Three common next steps:
|
|
55
71
|
|
|
56
|
-
- `
|
|
57
|
-
- `
|
|
58
|
-
-
|
|
72
|
+
- Add `--format=sarif` or `--format=github` for a SARIF file or GitHub workflow annotations. Naming any format turns off the default text rendering, so add `--format=text` as well to keep it.
|
|
73
|
+
- Run `npx @cplieger/deadset-ts explain --why=farewell` to see why one declaration is reported, retained, held by an unanswered question, live or dead.
|
|
74
|
+
- Add `--baseline-write=deadset-baseline.json` to record today's findings. Later runs fail on a new finding and on a baseline row whose finding has gone. To keep one declaration, put `// deadset:ignore DS1001 -- <reason>` on the line above it.
|
|
59
75
|
|
|
60
|
-
|
|
76
|
+
[Commands and exit codes](docs/commands.md) covers every verb and option, and [Configuration](docs/configuration.md) covers every setting.
|
|
61
77
|
|
|
62
|
-
|
|
63
|
-
- `DirectoryEntry`, `PathKind`: one entry of a directory read, and what one path names.
|
|
78
|
+
## API
|
|
64
79
|
|
|
65
|
-
|
|
80
|
+
The package exports the command line as a function, and the helpers that spell the positions and symbol references in a report.
|
|
66
81
|
|
|
67
|
-
- `
|
|
68
|
-
- `
|
|
69
|
-
- `
|
|
70
|
-
- `
|
|
82
|
+
- `run` runs the command line and returns its exit code, without exiting the process. `Writer` is its output stream, and `SETTING_OPTIONS` maps each option to the setting it sets.
|
|
83
|
+
- `Host`, `DirectoryEntry` and `PathKind` describe the filesystem, working directory and version a run reads.
|
|
84
|
+
- `renderPosition`, `positionKey`, `byPosition`, `PositionError` and `Position` render and order positions.
|
|
85
|
+
- `renderRef`, `nameComponent`, `computedComponent`, `isRef`, `REF_EXPRESSIONS`, `Module`, `Component`, `Fragment` and `DependencySection` spell stable symbol references.
|
|
86
|
+
- `DECLINED_CONVENTIONS` and `DeclinedConvention` list the entry-point conventions of other tools the analysis does not read.
|
|
87
|
+
- `CONTRACT_VERSION` is the version of the [deadset Contract](https://github.com/cplieger/deadset-spec) this analyzer implements.
|
|
71
88
|
|
|
72
|
-
|
|
89
|
+
A TypeScript caller that imports the source sets `allowImportingTsExtensions`, because each import in it ends in `.ts`. [Using deadset-ts as a library](docs/library.md) covers the packages and in-process runs, and [JSR](https://jsr.io/@cplieger/deadset-ts/doc) has the full reference.
|
|
73
90
|
|
|
74
|
-
|
|
75
|
-
- `nameComponent(name)`, `computedComponent(text)`: the canonical spelling of one component of that reference, from a declared name or from a computed key.
|
|
76
|
-
- `isRef(value)`: whether one string is a reference of this language's grammar.
|
|
77
|
-
- `REF_EXPRESSIONS`: one regular expression per form the grammar defines.
|
|
78
|
-
- `Module`, `Component`, `Fragment`, `DependencySection`: the module half of a reference, one component of its fragment, what the fragment names, and the manifest section a dependency was declared in.
|
|
91
|
+
## Related projects
|
|
79
92
|
|
|
80
|
-
|
|
93
|
+
deadset-ts implements the [deadset Contract](https://github.com/cplieger/deadset-spec), which fixes the issue codes, the report schema and the exit codes. It passes every fixture of the Contract's conformance corpus except one reflective-lookup fixture, the gap [`conformance.json`](conformance.json) declares.
|
|
81
94
|
|
|
82
|
-
-
|
|
95
|
+
- [deadset-go](https://github.com/cplieger/deadset-go) is the same analysis for Go modules.
|
|
96
|
+
- [deadset](https://github.com/cplieger/deadset) runs both analyzers as one command and merges their reports, resolving the edges between Go and TypeScript code.
|
|
83
97
|
|
|
84
|
-
|
|
98
|
+
## Documentation
|
|
85
99
|
|
|
86
|
-
-
|
|
100
|
+
- [Commands and exit codes](docs/commands.md) lists every verb, option, rendering and exit code.
|
|
101
|
+
- [Configuration](docs/configuration.md) lists every setting, the suppression files and the scope document.
|
|
102
|
+
- [How deadset-ts works](docs/how-it-works.md) explains the projects it loads, the roots it starts from and what it holds back.
|
|
103
|
+
- [Using deadset-ts as a library](docs/library.md) covers the npm and JSR packages and running the analyzer in-process.
|
|
104
|
+
- [Batch-cap calibration](docs/batch-cap-calibration.md) is the measurement behind the batch size of the reference pass.
|
|
87
105
|
|
|
88
106
|
## Contributing
|
|
89
107
|
|
|
90
|
-
See [CONTRIBUTING.md](
|
|
108
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
91
109
|
|
|
92
110
|
## Disclaimer
|
|
93
111
|
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The content mapper the compiler runs for component files: JSON-RPC 2.0 messages, each
|
|
3
|
+
* framed by a `Content-Length` header, over the process's standard streams. It answers
|
|
4
|
+
* `transform` with {@link componentModule} and keeps no state between requests.
|
|
5
|
+
* The protocol is the compiler's own:
|
|
6
|
+
* https://github.com/microsoft/TypeScript/blob/f9f8d01292562242b6e7c7142e46ed7e470926f9/tsc/internal/contentmapper/hostimpl.go
|
|
7
|
+
*/
|
|
8
|
+
import { componentModule } from "../src/component-files.js";
|
|
9
|
+
/** The JSON-RPC code of a method this mapper does not serve. */
|
|
10
|
+
const METHOD_NOT_FOUND = -32601;
|
|
11
|
+
/** The JSON-RPC code of a request whose parameters are not the protocol's. */
|
|
12
|
+
const INVALID_PARAMS = -32602;
|
|
13
|
+
const HEADER_END = new Uint8Array([0x0d, 0x0a, 0x0d, 0x0a]);
|
|
14
|
+
/** The offset of `needle` in `bytes` at or after `from`, or -1. */
|
|
15
|
+
function indexOf(bytes, needle, from) {
|
|
16
|
+
outer: for (let at = from; at + needle.length <= bytes.length; at += 1) {
|
|
17
|
+
for (let index = 0; index < needle.length; index += 1) {
|
|
18
|
+
if (bytes[at + index] !== needle[index]) {
|
|
19
|
+
continue outer;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return at;
|
|
23
|
+
}
|
|
24
|
+
return -1;
|
|
25
|
+
}
|
|
26
|
+
/** The answer to one message, or undefined for a notification, which takes none. */
|
|
27
|
+
function answer(message) {
|
|
28
|
+
if (message.id === undefined) {
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
const reply = (result) => ({ jsonrpc: "2.0", id: message.id, result });
|
|
32
|
+
const fail = (code, text) => ({
|
|
33
|
+
jsonrpc: "2.0",
|
|
34
|
+
id: message.id,
|
|
35
|
+
error: { code, message: text },
|
|
36
|
+
});
|
|
37
|
+
switch (message.method) {
|
|
38
|
+
case "initialize":
|
|
39
|
+
return reply({ positionEncoding: "utf-16", diagnosticSource: "deadset-ts" });
|
|
40
|
+
case "openProject":
|
|
41
|
+
return reply({});
|
|
42
|
+
case "closeProject":
|
|
43
|
+
return reply(null);
|
|
44
|
+
case "transform": {
|
|
45
|
+
const content = typeof message.params === "object" && message.params !== null
|
|
46
|
+
? message.params.content
|
|
47
|
+
: undefined;
|
|
48
|
+
if (typeof content !== "string") {
|
|
49
|
+
return fail(INVALID_PARAMS, "transform: params.content is not a string");
|
|
50
|
+
}
|
|
51
|
+
const module = componentModule(content);
|
|
52
|
+
return reply({ text: module.text, extension: module.extension, mappings: module.mappings });
|
|
53
|
+
}
|
|
54
|
+
default:
|
|
55
|
+
return fail(METHOD_NOT_FOUND, `no method ${JSON.stringify(message.method)}`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* A connection over one byte stream. A message whose body is not JSON is answered with
|
|
60
|
+
* nothing, because it carries no id to answer to.
|
|
61
|
+
*/
|
|
62
|
+
export function mapperConnection(write) {
|
|
63
|
+
const encoder = new TextEncoder();
|
|
64
|
+
const decoder = new TextDecoder();
|
|
65
|
+
let pending = new Uint8Array(0);
|
|
66
|
+
return {
|
|
67
|
+
receive(chunk) {
|
|
68
|
+
const joined = new Uint8Array(pending.length + chunk.length);
|
|
69
|
+
joined.set(pending);
|
|
70
|
+
joined.set(chunk, pending.length);
|
|
71
|
+
pending = joined;
|
|
72
|
+
for (;;) {
|
|
73
|
+
const headerEnd = indexOf(pending, HEADER_END, 0);
|
|
74
|
+
if (headerEnd < 0) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
const header = decoder.decode(pending.subarray(0, headerEnd));
|
|
78
|
+
const length = Number(/content-length:\s*(\d+)/iu.exec(header)?.[1] ?? "0");
|
|
79
|
+
const bodyStart = headerEnd + HEADER_END.length;
|
|
80
|
+
if (pending.length < bodyStart + length) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
const body = decoder.decode(pending.subarray(bodyStart, bodyStart + length));
|
|
84
|
+
pending = pending.slice(bodyStart + length);
|
|
85
|
+
let message;
|
|
86
|
+
try {
|
|
87
|
+
message = JSON.parse(body);
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
const reply = answer(message);
|
|
93
|
+
if (reply !== undefined) {
|
|
94
|
+
const bytes = encoder.encode(JSON.stringify(reply));
|
|
95
|
+
write(encoder.encode(`Content-Length: ${String(bytes.length)}\r\n\r\n`));
|
|
96
|
+
write(bytes);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
}
|
package/dist/bin/node-host.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { randomBytes } from "node:crypto";
|
|
2
|
-
import { closeSync, fchmodSync, fsyncSync, openSync, readdirSync, readFileSync, renameSync, rmSync, statSync, writeSync, } from "node:fs";
|
|
3
|
-
import {
|
|
2
|
+
import { closeSync, fchmodSync, fsyncSync, mkdtempSync, openSync, readdirSync, readFileSync, realpathSync, renameSync, rmSync, statSync, writeSync, } from "node:fs";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { basename, dirname, extname, join } from "node:path";
|
|
4
5
|
import { fileURLToPath } from "node:url";
|
|
5
6
|
/** The name the manifest of this package declares. */
|
|
6
7
|
const PACKAGE_NAME = "@cplieger/deadset-ts";
|
|
@@ -75,6 +76,24 @@ function writeAtomically(path, pieces) {
|
|
|
75
76
|
throw error;
|
|
76
77
|
}
|
|
77
78
|
}
|
|
79
|
+
/** A new directory under the platform's temporary directory. */
|
|
80
|
+
function temporaryDirectory() {
|
|
81
|
+
const path = mkdtempSync(join(tmpdir(), "deadset-ts-mapper-"));
|
|
82
|
+
return {
|
|
83
|
+
path,
|
|
84
|
+
remove: () => {
|
|
85
|
+
rmSync(path, { recursive: true, force: true });
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* The mapper beside this file, in the same form: the emitted tree runs the emitted
|
|
91
|
+
* mapper and a checkout runs the source through the runtime's own type stripping.
|
|
92
|
+
*/
|
|
93
|
+
function componentMapperCommand() {
|
|
94
|
+
const here = fileURLToPath(import.meta.url);
|
|
95
|
+
return [process.execPath, join(dirname(here), `component-mapper${extname(here)}`)];
|
|
96
|
+
}
|
|
78
97
|
/**
|
|
79
98
|
* The filesystem of the platform the command runs on, and the version of the
|
|
80
99
|
* package it was installed from.
|
|
@@ -98,10 +117,13 @@ export function nodeHost() {
|
|
|
98
117
|
}
|
|
99
118
|
return stat.isDirectory() ? "directory" : "file";
|
|
100
119
|
},
|
|
120
|
+
realPath: (path) => realpathSync(path),
|
|
101
121
|
analyzerVersion: () => {
|
|
102
122
|
found ??= readVersion();
|
|
103
123
|
return found;
|
|
104
124
|
},
|
|
105
125
|
writeDocument: writeAtomically,
|
|
126
|
+
temporaryDirectory,
|
|
127
|
+
componentMapperCommand,
|
|
106
128
|
};
|
|
107
129
|
}
|