fatou-cli 0.9.0 → 0.11.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.
Files changed (3) hide show
  1. package/README.md +1 -1
  2. package/bin/fatou.js +122 -63
  3. package/package.json +9 -9
package/README.md CHANGED
@@ -25,7 +25,7 @@ npx fatou-cli format file.jl
25
25
  fatou parse file.jl # print the CST (stdin if no file)
26
26
  fatou format file.jl # format to stdout (stdin if omitted)
27
27
  fatou format --check path/ # check formatting; non-zero exit if any differ
28
- fatou lint --check path/ # lint
28
+ fatou lint path/ # lint; non-zero exit if any findings
29
29
  fatou lsp # run the language server on stdio
30
30
  ```
31
31
 
package/bin/fatou.js CHANGED
@@ -1,81 +1,140 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- const { execFileSync } = require("node:child_process");
3
+ const { execFileSync, spawnSync } = require("node:child_process");
4
+
5
+ const PACKAGES = {
6
+ "linux-x64-gnu": "@fatou-cli/linux-x64-gnu",
7
+ "linux-arm64-gnu": "@fatou-cli/linux-arm64-gnu",
8
+ "linux-x64-musl": "@fatou-cli/linux-x64-musl",
9
+ "linux-arm64-musl": "@fatou-cli/linux-arm64-musl",
10
+ "darwin-x64": "@fatou-cli/darwin-x64",
11
+ "darwin-arm64": "@fatou-cli/darwin-arm64",
12
+ "win32-x64": "@fatou-cli/win32-x64",
13
+ "win32-arm64": "@fatou-cli/win32-arm64",
14
+ };
4
15
 
5
16
  function detectLibc() {
6
- if (process.platform !== "linux") return null;
7
- try {
8
- const report = process.report.getReport();
9
- return report.header.glibcVersionRuntime ? "gnu" : "musl";
10
- } catch {
11
- return "gnu";
12
- }
17
+ if (process.platform !== "linux") return null;
18
+ try {
19
+ const report = process.report.getReport();
20
+ return report.header.glibcVersionRuntime ? "gnu" : "musl";
21
+ } catch {
22
+ return "gnu";
23
+ }
24
+ }
25
+
26
+ // Candidate platform keys in preference order. On linux the other libc
27
+ // flavor is kept as a fallback: a host can report glibc yet be unable to
28
+ // run generic glibc binaries (NixOS has no loader at the standard path),
29
+ // while the musl build is statically linked and runs anywhere.
30
+ function candidateKeys() {
31
+ const { platform, arch } = process;
32
+ const libc = detectLibc();
33
+ if (!libc) return [`${platform}-${arch}`];
34
+ const other = libc === "gnu" ? "musl" : "gnu";
35
+ return [`${platform}-${arch}-${libc}`, `${platform}-${arch}-${other}`];
13
36
  }
14
37
 
15
- function platformPackage() {
16
- const { platform, arch } = process;
17
- const libc = detectLibc();
38
+ function resolveCandidates() {
39
+ const keys = candidateKeys();
40
+ if (!PACKAGES[keys[0]]) {
41
+ throw new Error(
42
+ `fatou-cli does not ship a prebuilt binary for ${keys[0]}.\n` +
43
+ `Supported platforms: linux (x64/arm64, gnu+musl), darwin (x64/arm64), win32 (x64/arm64).\n` +
44
+ `See https://github.com/jolars/fatou for alternative install methods.`,
45
+ );
46
+ }
47
+ const binaryName = process.platform === "win32" ? "fatou.exe" : "fatou";
48
+ const candidates = [];
49
+ let firstError;
50
+ for (const key of keys) {
51
+ try {
52
+ candidates.push(require.resolve(`${PACKAGES[key]}/${binaryName}`));
53
+ } catch (err) {
54
+ firstError = firstError ?? err;
55
+ }
56
+ }
57
+ if (candidates.length === 0) {
58
+ throw new Error(
59
+ `fatou-cli expected the optional dependency ${PACKAGES[keys[0]]} to be installed, ` +
60
+ `but it could not be resolved.\n` +
61
+ `This usually means npm skipped it (e.g. \`--no-optional\` or a registry/network issue ` +
62
+ `during install). Try reinstalling with optional dependencies enabled.\n` +
63
+ `Original error: ${firstError.message}`,
64
+ );
65
+ }
66
+ return candidates;
67
+ }
18
68
 
19
- const map = {
20
- "linux-x64-gnu": "@fatou-cli/linux-x64-gnu",
21
- "linux-arm64-gnu": "@fatou-cli/linux-arm64-gnu",
22
- "linux-x64-musl": "@fatou-cli/linux-x64-musl",
23
- "linux-arm64-musl": "@fatou-cli/linux-arm64-musl",
24
- "darwin-x64": "@fatou-cli/darwin-x64",
25
- "darwin-arm64": "@fatou-cli/darwin-arm64",
26
- "win32-x64": "@fatou-cli/win32-x64",
27
- "win32-arm64": "@fatou-cli/win32-arm64",
28
- };
69
+ function runnable(binary) {
70
+ const probe = spawnSync(binary, ["--version"], { stdio: "ignore" });
71
+ return probe.error == null && probe.status === 0;
72
+ }
73
+
74
+ // With a single candidate, trust it: probing every invocation would cost an
75
+ // extra process spawn in the common case. Probing is reserved for the
76
+ // unusual setup where both libc flavors are installed side by side.
77
+ function pickBinary(candidates) {
78
+ if (candidates.length === 1) return candidates[0];
79
+ for (const binary of candidates) {
80
+ if (runnable(binary)) return binary;
81
+ }
82
+ return candidates[0];
83
+ }
29
84
 
30
- const key = libc ? `${platform}-${arch}-${libc}` : `${platform}-${arch}`;
31
- return { key, name: map[key] };
85
+ function loaderHint() {
86
+ const libc = detectLibc();
87
+ if (libc !== "gnu") return;
88
+ const muslPackage = PACKAGES[`${process.platform}-${process.arch}-musl`];
89
+ process.stderr.write(
90
+ `The glibc build of fatou cannot run on this system (no standard glibc loader; ` +
91
+ `on NixOS this is expected).\n` +
92
+ `The statically linked musl build works anywhere. Package managers skip it on ` +
93
+ `glibc hosts, so add it explicitly:\n` +
94
+ ` npm: npm install --force ${muslPackage}\n` +
95
+ ` pnpm: pnpm config set supportedArchitectures.libc '["glibc","musl"]' && pnpm install\n` +
96
+ `Or install fatou via other means; ` +
97
+ `see https://github.com/jolars/fatou.\n`,
98
+ );
32
99
  }
33
100
 
34
101
  function resolveBinary() {
35
- const { key, name } = platformPackage();
36
- if (!name) {
37
- throw new Error(
38
- `fatou-cli does not ship a prebuilt binary for ${key}.\n` +
39
- `Supported platforms: linux (x64/arm64, gnu+musl), darwin (x64/arm64), win32 (x64/arm64).\n` +
40
- `See https://github.com/jolars/fatou for alternative install methods.`,
41
- );
42
- }
43
- const binaryName = process.platform === "win32" ? "fatou.exe" : "fatou";
44
- try {
45
- return require.resolve(`${name}/${binaryName}`);
46
- } catch (err) {
47
- throw new Error(
48
- `fatou-cli expected the optional dependency ${name} to be installed, ` +
49
- `but it could not be resolved.\n` +
50
- `This usually means npm skipped it (e.g. \`--no-optional\` or a registry/network issue ` +
51
- `during install). Try reinstalling with optional dependencies enabled.\n` +
52
- `Original error: ${err.message}`,
53
- );
54
- }
102
+ return pickBinary(resolveCandidates());
55
103
  }
56
104
 
57
105
  function main() {
58
- let binary;
59
- try {
60
- binary = resolveBinary();
61
- } catch (err) {
62
- process.stderr.write(`${err.message}\n`);
63
- process.exit(1);
64
- }
106
+ let binary;
107
+ try {
108
+ binary = resolveBinary();
109
+ } catch (err) {
110
+ process.stderr.write(`${err.message}\n`);
111
+ process.exit(1);
112
+ }
65
113
 
66
- try {
67
- execFileSync(binary, process.argv.slice(2), { stdio: "inherit" });
68
- } catch (err) {
69
- if (typeof err.status === "number") {
70
- process.exit(err.status);
71
- }
72
- if (err.signal) {
73
- process.kill(process.pid, err.signal);
74
- return;
75
- }
76
- process.stderr.write(`Failed to execute fatou: ${err.message}\n`);
77
- process.exit(1);
78
- }
114
+ try {
115
+ execFileSync(binary, process.argv.slice(2), { stdio: "inherit" });
116
+ } catch (err) {
117
+ if (typeof err.status === "number") {
118
+ // 127 is the loader stub's exit code on hosts that cannot run the
119
+ // glibc build; probe to distinguish that from fatou itself
120
+ // exiting 127 before hinting.
121
+ if (err.status === 127 && !runnable(binary)) {
122
+ loaderHint();
123
+ }
124
+ process.exit(err.status);
125
+ }
126
+ if (err.signal) {
127
+ process.kill(process.pid, err.signal);
128
+ return;
129
+ }
130
+ // The binary resolved but could not be spawned; a missing dynamic
131
+ // loader surfaces as ENOENT on hosts without NixOS's stub.
132
+ if (err.code === "ENOENT") {
133
+ loaderHint();
134
+ }
135
+ process.stderr.write(`Failed to execute fatou: ${err.message}\n`);
136
+ process.exit(1);
137
+ }
79
138
  }
80
139
 
81
140
  main();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fatou-cli",
3
- "version": "0.9.0",
3
+ "version": "0.11.0",
4
4
  "description": "A language server, formatter, and linter for Julia",
5
5
  "keywords": [
6
6
  "julia",
@@ -28,13 +28,13 @@
28
28
  "node": ">=20"
29
29
  },
30
30
  "optionalDependencies": {
31
- "@fatou-cli/linux-x64-gnu": "0.9.0",
32
- "@fatou-cli/linux-arm64-gnu": "0.9.0",
33
- "@fatou-cli/linux-x64-musl": "0.9.0",
34
- "@fatou-cli/linux-arm64-musl": "0.9.0",
35
- "@fatou-cli/darwin-x64": "0.9.0",
36
- "@fatou-cli/darwin-arm64": "0.9.0",
37
- "@fatou-cli/win32-x64": "0.9.0",
38
- "@fatou-cli/win32-arm64": "0.9.0"
31
+ "@fatou-cli/linux-x64-gnu": "0.11.0",
32
+ "@fatou-cli/linux-arm64-gnu": "0.11.0",
33
+ "@fatou-cli/linux-x64-musl": "0.11.0",
34
+ "@fatou-cli/linux-arm64-musl": "0.11.0",
35
+ "@fatou-cli/darwin-x64": "0.11.0",
36
+ "@fatou-cli/darwin-arm64": "0.11.0",
37
+ "@fatou-cli/win32-x64": "0.11.0",
38
+ "@fatou-cli/win32-arm64": "0.11.0"
39
39
  }
40
40
  }