symlx 0.1.11 → 0.1.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 +6 -0
- package/dist/lib/bin-targets.js +20 -1
- package/dist/lib/shebang.js +35 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -203,6 +203,7 @@ Current launcher inference:
|
|
|
203
203
|
|
|
204
204
|
- `.js`, `.mjs`, `.cjs` -> Node launcher
|
|
205
205
|
- `.ts`, `.tsx`, `.mts`, `.cts` -> `tsx` launcher
|
|
206
|
+
- if a TypeScript target declares `#!/usr/bin/env node`, symlx fails early and tells you to use `tsx` shebang or remove shebang for launcher inference
|
|
206
207
|
|
|
207
208
|
TypeScript runtime resolution order is:
|
|
208
209
|
|
|
@@ -287,6 +288,11 @@ symlx serve --collision fail
|
|
|
287
288
|
|
|
288
289
|
Install `tsx` in the project or make `tsx` available on `PATH`.
|
|
289
290
|
|
|
291
|
+
## "typescript target uses node shebang and is not directly runnable"
|
|
292
|
+
|
|
293
|
+
- replace shebang with `#!/usr/bin/env tsx`
|
|
294
|
+
- or remove shebang and let symlx infer launcher by file type
|
|
295
|
+
|
|
290
296
|
## "package.json not found"
|
|
291
297
|
|
|
292
298
|
Run in your project root, or pass bins inline/config.
|
package/dist/lib/bin-targets.js
CHANGED
|
@@ -5,8 +5,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.prepareBinTargets = prepareBinTargets;
|
|
7
7
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
8
9
|
const launchers_1 = require("./launchers");
|
|
9
10
|
const shebang_1 = require("./shebang");
|
|
11
|
+
const TYPESCRIPT_TARGET_EXTENSIONS = new Set(['.ts', '.tsx', '.mts', '.cts']);
|
|
10
12
|
function isExecutable(filePath) {
|
|
11
13
|
if (process.platform === 'win32') {
|
|
12
14
|
return true;
|
|
@@ -53,6 +55,17 @@ function addUnsupportedWithoutShebangIssue(issues, name, target, reason) {
|
|
|
53
55
|
hint: 'explicitly specify a shebang at the top of the target file to declare its runner',
|
|
54
56
|
});
|
|
55
57
|
}
|
|
58
|
+
function isTypeScriptTarget(targetPath) {
|
|
59
|
+
return TYPESCRIPT_TARGET_EXTENSIONS.has(node_path_1.default.extname(targetPath).toLowerCase());
|
|
60
|
+
}
|
|
61
|
+
function addInvalidTypeScriptNodeShebangIssue(issues, name, target) {
|
|
62
|
+
issues.push({
|
|
63
|
+
name,
|
|
64
|
+
target,
|
|
65
|
+
reason: 'typescript target uses node shebang and is not directly runnable',
|
|
66
|
+
hint: 'use #!/usr/bin/env tsx or remove shebang to use launcher inference',
|
|
67
|
+
});
|
|
68
|
+
}
|
|
56
69
|
function prepareBinTargets(cwd, bin, options = {}) {
|
|
57
70
|
const currentPath = options.currentPath ?? process.env.PATH;
|
|
58
71
|
const preparedTargets = [];
|
|
@@ -86,7 +99,13 @@ function prepareBinTargets(cwd, bin, options = {}) {
|
|
|
86
99
|
});
|
|
87
100
|
continue;
|
|
88
101
|
}
|
|
89
|
-
|
|
102
|
+
const shebang = (0, shebang_1.readShebang)(target);
|
|
103
|
+
if (shebang) {
|
|
104
|
+
const shebangRuntime = (0, shebang_1.extractShebangRuntime)(shebang);
|
|
105
|
+
if (isTypeScriptTarget(target) && shebangRuntime === 'node') {
|
|
106
|
+
addInvalidTypeScriptNodeShebangIssue(issues, name, target);
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
90
109
|
const executableIssue = ensureExecutable(target, stats.mode);
|
|
91
110
|
if (executableIssue) {
|
|
92
111
|
issues.push({
|
package/dist/lib/shebang.js
CHANGED
|
@@ -4,8 +4,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.readShebang = readShebang;
|
|
7
|
+
exports.extractShebangRuntime = extractShebangRuntime;
|
|
8
|
+
exports.readShebangRuntime = readShebangRuntime;
|
|
7
9
|
exports.hasShebang = hasShebang;
|
|
8
10
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
11
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
9
12
|
function readShebang(filePath) {
|
|
10
13
|
const raw = node_fs_1.default.readFileSync(filePath, 'utf8');
|
|
11
14
|
const firstLine = raw.split(/\r?\n/, 1)[0]?.replace(/^\uFEFF/, '');
|
|
@@ -14,6 +17,38 @@ function readShebang(filePath) {
|
|
|
14
17
|
}
|
|
15
18
|
return firstLine;
|
|
16
19
|
}
|
|
20
|
+
function tokenizeShebangCommand(shebang) {
|
|
21
|
+
return shebang
|
|
22
|
+
.slice(2)
|
|
23
|
+
.trim()
|
|
24
|
+
.split(/\s+/)
|
|
25
|
+
.map((token) => token.replace(/^['"]|['"]$/g, ''))
|
|
26
|
+
.filter(Boolean);
|
|
27
|
+
}
|
|
28
|
+
function extractShebangRuntime(shebang) {
|
|
29
|
+
const tokens = tokenizeShebangCommand(shebang);
|
|
30
|
+
if (tokens.length === 0) {
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
const command = tokens[0];
|
|
34
|
+
const commandBase = node_path_1.default.basename(command).toLowerCase();
|
|
35
|
+
if (commandBase === 'env') {
|
|
36
|
+
// env-style shebangs can include flags before the actual runtime command.
|
|
37
|
+
const runtimeToken = tokens.slice(1).find((token) => !token.startsWith('-'));
|
|
38
|
+
if (!runtimeToken) {
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
return node_path_1.default.basename(runtimeToken).toLowerCase();
|
|
42
|
+
}
|
|
43
|
+
return commandBase;
|
|
44
|
+
}
|
|
45
|
+
function readShebangRuntime(filePath) {
|
|
46
|
+
const shebang = readShebang(filePath);
|
|
47
|
+
if (!shebang) {
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
return extractShebangRuntime(shebang);
|
|
51
|
+
}
|
|
17
52
|
function hasShebang(filePath) {
|
|
18
53
|
return Boolean(readShebang(filePath));
|
|
19
54
|
}
|