@asamarts/alint 0.5.12
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 +71 -0
- package/bin/alint.js +42 -0
- package/install.js +176 -0
- package/package.json +47 -0
package/README.md
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# @asamarts/alint
|
|
2
|
+
|
|
3
|
+
npm install path for [alint](https://github.com/asamarts/alint), a
|
|
4
|
+
language-agnostic linter for repository structure, file existence,
|
|
5
|
+
filename conventions, and file content rules.
|
|
6
|
+
|
|
7
|
+
This package downloads and wraps the platform-matched native alint
|
|
8
|
+
binary at install time. The package itself ships **no JavaScript runtime
|
|
9
|
+
behaviour** — it's a thin shim around the same release tarballs the
|
|
10
|
+
`install.sh` and Homebrew paths consume. Same SHA-256 verification, same
|
|
11
|
+
upstream artifacts.
|
|
12
|
+
|
|
13
|
+
## Install
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# project-local
|
|
17
|
+
npm install --save-dev @asamarts/alint
|
|
18
|
+
npx alint check
|
|
19
|
+
|
|
20
|
+
# global (puts `alint` on PATH)
|
|
21
|
+
npm install -g @asamarts/alint
|
|
22
|
+
alint check
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
The npm package version tracks alint releases exactly: `npm install
|
|
26
|
+
@asamarts/alint@0.5.11` downloads alint v0.5.11.
|
|
27
|
+
|
|
28
|
+
## Supported platforms
|
|
29
|
+
|
|
30
|
+
| OS | Architectures |
|
|
31
|
+
|---------|----------------------|
|
|
32
|
+
| Linux | x64, arm64 (musl) |
|
|
33
|
+
| macOS | x64, arm64 |
|
|
34
|
+
| Windows | x64 |
|
|
35
|
+
|
|
36
|
+
For unsupported platforms, install via `cargo install alint`,
|
|
37
|
+
[Homebrew](https://github.com/asamarts/alint#homebrew), or by
|
|
38
|
+
downloading the tarball directly from
|
|
39
|
+
[GitHub Releases](https://github.com/asamarts/alint/releases).
|
|
40
|
+
|
|
41
|
+
## Skipping the postinstall download
|
|
42
|
+
|
|
43
|
+
Set `ALINT_SKIP_INSTALL=1` before `npm install`. The shim will install
|
|
44
|
+
without staging a binary, and `alint` invocations will print a clear
|
|
45
|
+
"binary not found" error pointing at the missing step. Useful for CI
|
|
46
|
+
systems that snapshot `node_modules` and don't want a network hop on
|
|
47
|
+
every restore.
|
|
48
|
+
|
|
49
|
+
## How it works
|
|
50
|
+
|
|
51
|
+
1. `package.json` declares `bin/alint.js` as the npm-exposed bin.
|
|
52
|
+
2. `npm install` runs `install.js` (postinstall):
|
|
53
|
+
- Detects `process.platform` + `process.arch`.
|
|
54
|
+
- Downloads
|
|
55
|
+
`https://github.com/asamarts/alint/releases/download/v<ver>/alint-v<ver>-<target>.tar.gz`
|
|
56
|
+
plus its `.sha256` companion.
|
|
57
|
+
- Verifies SHA-256.
|
|
58
|
+
- Extracts the `alint` (or `alint.exe`) binary into `bin-platform/`.
|
|
59
|
+
3. `bin/alint.js` is invoked when the user runs `alint`. It locates the
|
|
60
|
+
staged binary and spawns it with the original argv.
|
|
61
|
+
|
|
62
|
+
## License
|
|
63
|
+
|
|
64
|
+
Apache-2.0 OR MIT, matching the upstream alint project.
|
|
65
|
+
|
|
66
|
+
## Links
|
|
67
|
+
|
|
68
|
+
- Project: https://github.com/asamarts/alint
|
|
69
|
+
- Releases: https://github.com/asamarts/alint/releases
|
|
70
|
+
- Issues: https://github.com/asamarts/alint/issues
|
|
71
|
+
- Documentation: https://alint.org (when published)
|
package/bin/alint.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// alint npm shim — runtime wrapper.
|
|
3
|
+
//
|
|
4
|
+
// Locates the platform-matched native binary that `install.js`
|
|
5
|
+
// staged under `bin-platform/` at install time, then spawns it
|
|
6
|
+
// with the user's argv. On Unix we'd ideally `execvp` to replace
|
|
7
|
+
// the Node process (zero overhead), but that's not portable to
|
|
8
|
+
// Windows; spawnSync+stdio:inherit is the universal path.
|
|
9
|
+
|
|
10
|
+
'use strict';
|
|
11
|
+
|
|
12
|
+
const path = require('path');
|
|
13
|
+
const fs = require('fs');
|
|
14
|
+
const child_process = require('child_process');
|
|
15
|
+
|
|
16
|
+
const isWindows = process.platform === 'win32';
|
|
17
|
+
const binaryName = isWindows ? 'alint.exe' : 'alint';
|
|
18
|
+
const binaryPath = path.join(__dirname, '..', 'bin-platform', binaryName);
|
|
19
|
+
|
|
20
|
+
if (!fs.existsSync(binaryPath)) {
|
|
21
|
+
process.stderr.write(
|
|
22
|
+
`@asamarts/alint: binary not found at ${binaryPath}\n` +
|
|
23
|
+
` this usually means the postinstall step failed; try:\n` +
|
|
24
|
+
` npm uninstall -g @asamarts/alint && npm install -g @asamarts/alint\n` +
|
|
25
|
+
` or set ALINT_SKIP_INSTALL=0 if your CI suppressed it.\n`,
|
|
26
|
+
);
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const result = child_process.spawnSync(binaryPath, process.argv.slice(2), {
|
|
31
|
+
stdio: 'inherit',
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
if (result.error) {
|
|
35
|
+
process.stderr.write(`@asamarts/alint: failed to spawn ${binaryPath}: ${result.error.message}\n`);
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// `spawnSync` returns null for status when killed by a signal
|
|
40
|
+
// (e.g. user ^C). Forward exit code 130 (SIGINT-conventional) so
|
|
41
|
+
// CI runners interpret it correctly.
|
|
42
|
+
process.exit(result.status === null ? 130 : result.status);
|
package/install.js
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// alint npm shim — postinstall script.
|
|
3
|
+
//
|
|
4
|
+
// Resolves the native alint binary for the running platform/arch
|
|
5
|
+
// from `https://github.com/asamarts/alint/releases/<tag>`, verifies
|
|
6
|
+
// the SHA-256 hash that ships alongside the tarball, extracts the
|
|
7
|
+
// binary, and stages it under `bin-platform/`. The bin shim
|
|
8
|
+
// (`bin/alint.js`) execs that binary at runtime.
|
|
9
|
+
//
|
|
10
|
+
// Mirrors the existing `install.sh` URL conventions exactly so the
|
|
11
|
+
// two install paths download byte-identical tarballs.
|
|
12
|
+
//
|
|
13
|
+
// Skipped during local development checkouts (when this script
|
|
14
|
+
// runs from the alint monorepo's own `npm install`) — the upstream
|
|
15
|
+
// release for the in-flight version may not exist yet.
|
|
16
|
+
|
|
17
|
+
'use strict';
|
|
18
|
+
|
|
19
|
+
const fs = require('fs');
|
|
20
|
+
const path = require('path');
|
|
21
|
+
const https = require('https');
|
|
22
|
+
const crypto = require('crypto');
|
|
23
|
+
const os = require('os');
|
|
24
|
+
const tar = require('tar');
|
|
25
|
+
|
|
26
|
+
const REPO = 'asamarts/alint';
|
|
27
|
+
const PKG_VERSION = require('./package.json').version;
|
|
28
|
+
const VERSION_TAG = `v${PKG_VERSION}`;
|
|
29
|
+
|
|
30
|
+
// Skip when the consumer set ALINT_SKIP_INSTALL=1, e.g. for CI
|
|
31
|
+
// systems that snapshot node_modules and don't want the postinstall
|
|
32
|
+
// network hop. Also skip when running from the alint monorepo's own
|
|
33
|
+
// pnpm/npm install — the marker is the presence of a Cargo.toml two
|
|
34
|
+
// levels up. That keeps `cargo xtask` flows from accidentally trying
|
|
35
|
+
// to download a not-yet-released version of itself.
|
|
36
|
+
function shouldSkip() {
|
|
37
|
+
if (process.env.ALINT_SKIP_INSTALL === '1') {
|
|
38
|
+
return 'ALINT_SKIP_INSTALL=1';
|
|
39
|
+
}
|
|
40
|
+
const monorepoMarker = path.resolve(__dirname, '..', 'Cargo.toml');
|
|
41
|
+
if (fs.existsSync(monorepoMarker)) {
|
|
42
|
+
return 'detected alint monorepo (../Cargo.toml exists)';
|
|
43
|
+
}
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Map Node platform/arch to the alint release-target triple.
|
|
48
|
+
// The list mirrors install.sh and the release.yml build matrix.
|
|
49
|
+
function resolveTarget() {
|
|
50
|
+
const platform = process.platform;
|
|
51
|
+
const arch = process.arch;
|
|
52
|
+
const map = {
|
|
53
|
+
'linux/x64': 'x86_64-unknown-linux-musl',
|
|
54
|
+
'linux/arm64': 'aarch64-unknown-linux-musl',
|
|
55
|
+
'darwin/x64': 'x86_64-apple-darwin',
|
|
56
|
+
'darwin/arm64': 'aarch64-apple-darwin',
|
|
57
|
+
'win32/x64': 'x86_64-pc-windows-msvc',
|
|
58
|
+
};
|
|
59
|
+
const key = `${platform}/${arch}`;
|
|
60
|
+
const target = map[key];
|
|
61
|
+
if (!target) {
|
|
62
|
+
throw new Error(
|
|
63
|
+
`unsupported platform ${platform}/${arch}\n` +
|
|
64
|
+
` supported: ${Object.keys(map).join(', ')}\n` +
|
|
65
|
+
` download manually from https://github.com/${REPO}/releases`,
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
return target;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Follow up to 5 redirects (GitHub Releases hops through S3).
|
|
72
|
+
function fetch(url, redirects = 5) {
|
|
73
|
+
return new Promise((resolve, reject) => {
|
|
74
|
+
const req = https.get(url, (res) => {
|
|
75
|
+
const status = res.statusCode || 0;
|
|
76
|
+
if (status >= 300 && status < 400 && res.headers.location) {
|
|
77
|
+
if (redirects <= 0) {
|
|
78
|
+
reject(new Error(`too many redirects fetching ${url}`));
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
res.resume();
|
|
82
|
+
resolve(fetch(res.headers.location, redirects - 1));
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
if (status !== 200) {
|
|
86
|
+
reject(new Error(`HTTP ${status} fetching ${url}`));
|
|
87
|
+
res.resume();
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
const chunks = [];
|
|
91
|
+
res.on('data', (c) => chunks.push(c));
|
|
92
|
+
res.on('end', () => resolve(Buffer.concat(chunks)));
|
|
93
|
+
res.on('error', reject);
|
|
94
|
+
});
|
|
95
|
+
req.on('error', reject);
|
|
96
|
+
req.setTimeout(30000, () => {
|
|
97
|
+
req.destroy(new Error(`timeout fetching ${url}`));
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function sha256Hex(buf) {
|
|
103
|
+
return crypto.createHash('sha256').update(buf).digest('hex');
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
async function main() {
|
|
107
|
+
const skipReason = shouldSkip();
|
|
108
|
+
if (skipReason) {
|
|
109
|
+
process.stderr.write(`@asamarts/alint: skipping postinstall (${skipReason})\n`);
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const target = resolveTarget();
|
|
114
|
+
const archive = `alint-${VERSION_TAG}-${target}.tar.gz`;
|
|
115
|
+
const baseUrl = `https://github.com/${REPO}/releases/download/${VERSION_TAG}`;
|
|
116
|
+
const tarUrl = `${baseUrl}/${archive}`;
|
|
117
|
+
const shaUrl = `${tarUrl}.sha256`;
|
|
118
|
+
|
|
119
|
+
process.stderr.write(`@asamarts/alint: downloading ${archive}\n`);
|
|
120
|
+
const [tarBuf, shaBuf] = await Promise.all([fetch(tarUrl), fetch(shaUrl)]);
|
|
121
|
+
|
|
122
|
+
// The .sha256 file format mirrors install.sh's expectation:
|
|
123
|
+
// <hex> <filename>\n
|
|
124
|
+
// We verify against the hex column, ignoring the trailing
|
|
125
|
+
// filename column.
|
|
126
|
+
const expectedHash = shaBuf.toString('utf8').trim().split(/\s+/)[0];
|
|
127
|
+
const actualHash = sha256Hex(tarBuf);
|
|
128
|
+
if (expectedHash !== actualHash) {
|
|
129
|
+
throw new Error(
|
|
130
|
+
`SHA-256 mismatch for ${archive}\n` +
|
|
131
|
+
` expected: ${expectedHash}\n` +
|
|
132
|
+
` got: ${actualHash}`,
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
process.stderr.write(`@asamarts/alint: SHA-256 verified\n`);
|
|
136
|
+
|
|
137
|
+
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'alint-npm-'));
|
|
138
|
+
const tarPath = path.join(tmpDir, archive);
|
|
139
|
+
fs.writeFileSync(tarPath, tarBuf);
|
|
140
|
+
|
|
141
|
+
// Tarball layout: alint-<tag>-<target>/alint (or alint.exe).
|
|
142
|
+
// We extract the whole thing under tmp, then move just the
|
|
143
|
+
// binary into ./bin-platform/.
|
|
144
|
+
await tar.x({ file: tarPath, cwd: tmpDir });
|
|
145
|
+
const isWindows = process.platform === 'win32';
|
|
146
|
+
const binaryName = isWindows ? 'alint.exe' : 'alint';
|
|
147
|
+
const extractedDir = path.join(tmpDir, `alint-${VERSION_TAG}-${target}`);
|
|
148
|
+
const sourceBinary = path.join(extractedDir, binaryName);
|
|
149
|
+
if (!fs.existsSync(sourceBinary)) {
|
|
150
|
+
throw new Error(
|
|
151
|
+
`extracted tarball missing expected ${binaryName} at ${sourceBinary}`,
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const destDir = path.join(__dirname, 'bin-platform');
|
|
156
|
+
fs.mkdirSync(destDir, { recursive: true });
|
|
157
|
+
const destBinary = path.join(destDir, binaryName);
|
|
158
|
+
fs.copyFileSync(sourceBinary, destBinary);
|
|
159
|
+
if (!isWindows) {
|
|
160
|
+
fs.chmodSync(destBinary, 0o755);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Clean up scratch dir; ignore failures (tmp is OS-managed).
|
|
164
|
+
try {
|
|
165
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
166
|
+
} catch {
|
|
167
|
+
// ignore — tmp dir is OS-managed
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
process.stderr.write(`@asamarts/alint: installed ${binaryName} for ${target}\n`);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
main().catch((err) => {
|
|
174
|
+
process.stderr.write(`@asamarts/alint: postinstall failed: ${err.message}\n`);
|
|
175
|
+
process.exit(1);
|
|
176
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@asamarts/alint",
|
|
3
|
+
"version": "0.5.12",
|
|
4
|
+
"description": "Language-agnostic linter for repository structure, file existence, filename conventions, and file content rules. This package downloads and wraps the platform-matched native alint binary.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"lint",
|
|
7
|
+
"linter",
|
|
8
|
+
"repository",
|
|
9
|
+
"filename",
|
|
10
|
+
"policy",
|
|
11
|
+
"compliance"
|
|
12
|
+
],
|
|
13
|
+
"homepage": "https://github.com/asamarts/alint",
|
|
14
|
+
"bugs": "https://github.com/asamarts/alint/issues",
|
|
15
|
+
"license": "(Apache-2.0 OR MIT)",
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "https://github.com/asamarts/alint.git",
|
|
19
|
+
"directory": "npm"
|
|
20
|
+
},
|
|
21
|
+
"bin": {
|
|
22
|
+
"alint": "bin/alint.js"
|
|
23
|
+
},
|
|
24
|
+
"files": [
|
|
25
|
+
"install.js",
|
|
26
|
+
"bin/alint.js",
|
|
27
|
+
"README.md"
|
|
28
|
+
],
|
|
29
|
+
"scripts": {
|
|
30
|
+
"postinstall": "node install.js"
|
|
31
|
+
},
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"tar": "^7.4.0"
|
|
34
|
+
},
|
|
35
|
+
"engines": {
|
|
36
|
+
"node": ">=18"
|
|
37
|
+
},
|
|
38
|
+
"os": [
|
|
39
|
+
"linux",
|
|
40
|
+
"darwin",
|
|
41
|
+
"win32"
|
|
42
|
+
],
|
|
43
|
+
"cpu": [
|
|
44
|
+
"x64",
|
|
45
|
+
"arm64"
|
|
46
|
+
]
|
|
47
|
+
}
|