@ts-r.dev/lint 0.0.0-stage → 0.1.0-alpha.1
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 +11 -2
- package/bin/ts-r-lint.js +180 -0
- package/package.json +39 -4
package/README.md
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @ts-r.dev/lint
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
`ts-r-lint`: linter that reads your ESLint, oxlint or Biome config, from [ts-r](https://www.npmjs.com/package/ts-r).
|
|
4
|
+
|
|
5
|
+
```sh
|
|
6
|
+
npm i -D @ts-r.dev/lint
|
|
7
|
+
npx ts-r-lint --help
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
Installs only `ts-r-lint`: npm picks the one `@ts-r.dev/lint-<platform>` optional dependency that matches
|
|
11
|
+
your OS, CPU and libc. The `bin` is a small Node shim that runs the native binary with your arguments and
|
|
12
|
+
exits with its exit code. `TS_R_BIN_DIR=<dir>` makes it run the binaries in `<dir>` instead.
|
package/bin/ts-r-lint.js
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// The npm bin shim of every ts-r package. This file is the `ts-r` package's bin and is copied
|
|
3
|
+
// unchanged into each front package (`@ts-r.dev/run`, `@ts-r.dev/check`, ...) as bin/<binary>.js. What
|
|
4
|
+
// it runs comes from the "ts-r" key of the package's own package.json:
|
|
5
|
+
//
|
|
6
|
+
// { "binary": "ts-r-lint", "platformPrefix": "@ts-r.dev/lint-", "tools": [...], "version": false }
|
|
7
|
+
//
|
|
8
|
+
// It finds the native binary for this OS, CPU and libc in the matching optional dependency
|
|
9
|
+
// (`@ts-r.dev/lint-darwin-arm64`, ...; npm installs only the one whose os/cpu/libc match), runs it
|
|
10
|
+
// with the same arguments and inherited stdio, and exits with its exit code (or its signal).
|
|
11
|
+
// No dependencies, no install scripts; Node >= 18.
|
|
12
|
+
//
|
|
13
|
+
// "tools" (the `ts-r` launcher package only) lists the front packages whose binaries the
|
|
14
|
+
// launcher should find: their platform packages' bin directories go first on PATH.
|
|
15
|
+
// "version": false means the binary has no --version flag, so `--version` is answered here.
|
|
16
|
+
//
|
|
17
|
+
// Overrides: TS_R_BIN_DIR (a directory holding the binaries, e.g. target/release) wins over
|
|
18
|
+
// everything; TS_R_BINARY (a path) replaces the launcher binary in the `ts-r` package.
|
|
19
|
+
'use strict';
|
|
20
|
+
|
|
21
|
+
const { spawnSync } = require('child_process');
|
|
22
|
+
const fs = require('fs');
|
|
23
|
+
const os = require('os');
|
|
24
|
+
const path = require('path');
|
|
25
|
+
|
|
26
|
+
const pkgDir = path.join(__dirname, '..');
|
|
27
|
+
const pkg = require(path.join(pkgDir, 'package.json'));
|
|
28
|
+
// The source tree's npm/ts-r/package.json has no "ts-r" key (build-packages.mjs adds it): run as
|
|
29
|
+
// the launcher there, so `TS_R_BIN_DIR=target/release node npm/ts-r/bin/ts-r.js` works.
|
|
30
|
+
const cfg = pkg['ts-r'] || { binary: 'ts-r', platformPrefix: '@ts-r.dev/cli-', tools: [] };
|
|
31
|
+
|
|
32
|
+
// Node platform key -> npm platform suffix. Keep in sync with TARGETS in
|
|
33
|
+
// npm/scripts/build-packages.mjs (it checks this table).
|
|
34
|
+
const PLATFORMS = {
|
|
35
|
+
'darwin-arm64': 'darwin-arm64',
|
|
36
|
+
'darwin-x64': 'darwin-x64',
|
|
37
|
+
'linux-arm64-gnu': 'linux-arm64-gnu',
|
|
38
|
+
'linux-arm64-musl': 'linux-arm64-musl',
|
|
39
|
+
'linux-x64-gnu': 'linux-x64-gnu',
|
|
40
|
+
'linux-x64-musl': 'linux-x64-musl',
|
|
41
|
+
'win32-arm64': 'win32-arm64-msvc',
|
|
42
|
+
'win32-x64': 'win32-x64-msvc',
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const EXE = process.platform === 'win32' ? '.exe' : '';
|
|
46
|
+
|
|
47
|
+
function isMusl() {
|
|
48
|
+
// glibcVersionRuntime is only reported when Node runs on glibc.
|
|
49
|
+
try {
|
|
50
|
+
const report = process.report && process.report.getReport();
|
|
51
|
+
if (report && report.header) return !report.header.glibcVersionRuntime;
|
|
52
|
+
} catch (_) {
|
|
53
|
+
// Fall through to the ldd check.
|
|
54
|
+
}
|
|
55
|
+
try {
|
|
56
|
+
return fs.readFileSync('/usr/bin/ldd', 'utf8').includes('musl');
|
|
57
|
+
} catch (_) {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function platformKey() {
|
|
63
|
+
const base = `${process.platform}-${process.arch}`;
|
|
64
|
+
if (process.platform !== 'linux') return base;
|
|
65
|
+
return `${base}-${isMusl() ? 'musl' : 'gnu'}`;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Mirrors ts_r_cache::cache_root() so binaries installed into the global cache are found.
|
|
69
|
+
function cacheRoot() {
|
|
70
|
+
const env = process.env;
|
|
71
|
+
if (env.TS_R_CACHE_DIR) return env.TS_R_CACHE_DIR;
|
|
72
|
+
if (env.XDG_CACHE_HOME && path.isAbsolute(env.XDG_CACHE_HOME)) {
|
|
73
|
+
return path.join(env.XDG_CACHE_HOME, 'ts-r');
|
|
74
|
+
}
|
|
75
|
+
if (process.platform === 'win32' && env.LOCALAPPDATA) return path.join(env.LOCALAPPDATA, 'ts-r');
|
|
76
|
+
return path.join(os.homedir(), '.cache', 'ts-r');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// The bin directory of `prefix + platform` resolved from `fromDir`, or null.
|
|
80
|
+
function platformBinDir(prefix, fromDir, key) {
|
|
81
|
+
const suffix = PLATFORMS[key];
|
|
82
|
+
if (!suffix) return null;
|
|
83
|
+
try {
|
|
84
|
+
const json = require.resolve(`${prefix}${suffix}/package.json`, { paths: [fromDir] });
|
|
85
|
+
return path.join(path.dirname(json), 'bin');
|
|
86
|
+
} catch (_) {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function findBinary(key) {
|
|
92
|
+
const name = cfg.binary + EXE;
|
|
93
|
+
const tried = [];
|
|
94
|
+
if (process.env.TS_R_BIN_DIR) {
|
|
95
|
+
const bin = path.join(process.env.TS_R_BIN_DIR, name);
|
|
96
|
+
if (fs.existsSync(bin)) return { bin, tried };
|
|
97
|
+
tried.push(`${bin} (TS_R_BIN_DIR)`);
|
|
98
|
+
}
|
|
99
|
+
if (cfg.binary === 'ts-r' && process.env.TS_R_BINARY) {
|
|
100
|
+
return { bin: process.env.TS_R_BINARY, tried };
|
|
101
|
+
}
|
|
102
|
+
const dir = platformBinDir(cfg.platformPrefix, pkgDir, key);
|
|
103
|
+
if (dir) {
|
|
104
|
+
const bin = path.join(dir, name);
|
|
105
|
+
if (fs.existsSync(bin)) return { bin, tried };
|
|
106
|
+
tried.push(bin);
|
|
107
|
+
} else if (PLATFORMS[key]) {
|
|
108
|
+
tried.push(`the ${cfg.platformPrefix}${PLATFORMS[key]} package (not installed)`);
|
|
109
|
+
}
|
|
110
|
+
const cached = path.join(cacheRoot(), 'bin', pkg.version, name);
|
|
111
|
+
if (fs.existsSync(cached)) return { bin: cached, tried };
|
|
112
|
+
tried.push(cached);
|
|
113
|
+
return { bin: null, tried };
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function fail(key, tried) {
|
|
117
|
+
const lines = [`${cfg.binary}: couldn't find the ${cfg.binary} ${pkg.version} binary for ${key}.`, ' looked for:'];
|
|
118
|
+
for (const t of tried) lines.push(` ${t}`);
|
|
119
|
+
if (PLATFORMS[key]) {
|
|
120
|
+
lines.push(
|
|
121
|
+
'',
|
|
122
|
+
` The optional dependency ${cfg.platformPrefix}${PLATFORMS[key]} should have been installed with ${pkg.name}.`,
|
|
123
|
+
' - If you installed with --no-optional or --omit=optional, reinstall without it.',
|
|
124
|
+
' - If node_modules was copied from another machine, reinstall on this one.',
|
|
125
|
+
);
|
|
126
|
+
} else {
|
|
127
|
+
lines.push('', ` ${key} has no prebuilt binary. Supported: ${Object.keys(PLATFORMS).join(', ')}.`);
|
|
128
|
+
}
|
|
129
|
+
lines.push(' - Or set TS_R_BIN_DIR to a directory with the binaries (cargo build --release).');
|
|
130
|
+
process.stderr.write(lines.join('\n') + '\n');
|
|
131
|
+
process.exit(1);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// PATH for the launcher: the bin dirs of every installed tool, so `ts-r lint` finds ts-r-lint.
|
|
135
|
+
function toolPath(key) {
|
|
136
|
+
const dirs = [];
|
|
137
|
+
for (const front of cfg.tools || []) {
|
|
138
|
+
try {
|
|
139
|
+
const frontJson = require.resolve(`${front}/package.json`, { paths: [pkgDir] });
|
|
140
|
+
const frontPkg = JSON.parse(fs.readFileSync(frontJson, 'utf8'));
|
|
141
|
+
const dir = platformBinDir(frontPkg['ts-r'].platformPrefix, path.dirname(frontJson), key);
|
|
142
|
+
if (dir && fs.existsSync(dir)) dirs.push(dir);
|
|
143
|
+
} catch (_) {
|
|
144
|
+
// Not installed: the launcher reports the missing tool itself.
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
if (process.env.TS_R_BIN_DIR) dirs.unshift(process.env.TS_R_BIN_DIR);
|
|
148
|
+
return dirs;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function main() {
|
|
152
|
+
const args = process.argv.slice(2);
|
|
153
|
+
if (cfg.version === false && args.length === 1 && (args[0] === '--version' || args[0] === '-v')) {
|
|
154
|
+
process.stdout.write(`${cfg.binary} ${pkg.version}\n`);
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
const key = platformKey();
|
|
158
|
+
const { bin, tried } = findBinary(key);
|
|
159
|
+
if (!bin) fail(key, tried);
|
|
160
|
+
|
|
161
|
+
const env = { ...process.env };
|
|
162
|
+
if (cfg.tools) {
|
|
163
|
+
const dirs = toolPath(key);
|
|
164
|
+
const pathKey = Object.keys(env).find((k) => k.toUpperCase() === 'PATH') || 'PATH';
|
|
165
|
+
if (dirs.length) env[pathKey] = dirs.concat(env[pathKey] ? [env[pathKey]] : []).join(path.delimiter);
|
|
166
|
+
}
|
|
167
|
+
const result = spawnSync(bin, args, { stdio: 'inherit', windowsHide: true, env });
|
|
168
|
+
if (result.error) {
|
|
169
|
+
process.stderr.write(`${cfg.binary}: failed to run ${bin}: ${result.error.message}\n`);
|
|
170
|
+
process.exit(1);
|
|
171
|
+
}
|
|
172
|
+
if (result.signal) {
|
|
173
|
+
// Die the same way the binary did, so callers see the signal.
|
|
174
|
+
process.kill(process.pid, result.signal);
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
process.exit(result.status === null ? 1 : result.status);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
main();
|
package/package.json
CHANGED
|
@@ -1,6 +1,41 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ts-r.dev/lint",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.0-alpha.1",
|
|
4
|
+
"description": "ts-r linter that reads your ESLint, oxlint or Biome config. Prebuilt native binary, no install scripts.",
|
|
5
|
+
"license": "MIT OR Apache-2.0",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/Webb-Ventures/typescript-rust.git",
|
|
9
|
+
"directory": "npm"
|
|
10
|
+
},
|
|
11
|
+
"keywords": [
|
|
12
|
+
"typescript",
|
|
13
|
+
"ts-r",
|
|
14
|
+
"lint",
|
|
15
|
+
"rust"
|
|
16
|
+
],
|
|
17
|
+
"bin": {
|
|
18
|
+
"ts-r-lint": "bin/ts-r-lint.js"
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"bin/ts-r-lint.js",
|
|
22
|
+
"README.md"
|
|
23
|
+
],
|
|
24
|
+
"engines": {
|
|
25
|
+
"node": ">=18"
|
|
26
|
+
},
|
|
27
|
+
"optionalDependencies": {
|
|
28
|
+
"@ts-r.dev/lint-darwin-arm64": "0.1.0-alpha.1",
|
|
29
|
+
"@ts-r.dev/lint-darwin-x64": "0.1.0-alpha.1",
|
|
30
|
+
"@ts-r.dev/lint-linux-arm64-gnu": "0.1.0-alpha.1",
|
|
31
|
+
"@ts-r.dev/lint-linux-arm64-musl": "0.1.0-alpha.1",
|
|
32
|
+
"@ts-r.dev/lint-linux-x64-gnu": "0.1.0-alpha.1",
|
|
33
|
+
"@ts-r.dev/lint-linux-x64-musl": "0.1.0-alpha.1",
|
|
34
|
+
"@ts-r.dev/lint-win32-arm64-msvc": "0.1.0-alpha.1",
|
|
35
|
+
"@ts-r.dev/lint-win32-x64-msvc": "0.1.0-alpha.1"
|
|
36
|
+
},
|
|
37
|
+
"ts-r": {
|
|
38
|
+
"binary": "ts-r-lint",
|
|
39
|
+
"platformPrefix": "@ts-r.dev/lint-"
|
|
40
|
+
}
|
|
41
|
+
}
|