@gordon.gan/specflow 1.3.1-beta → 1.3.2-beta
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 +1 -1
- package/dist/core/opener-launch.d.ts +6 -5
- package/dist/core/opener-launch.js +56 -12
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -124,7 +124,7 @@ npm install -g @gordon.gan/specflow
|
|
|
124
124
|
npm install -g github:Gordon-Gan-Jiang/specflow
|
|
125
125
|
|
|
126
126
|
# 验证
|
|
127
|
-
specflow --version # 以 npm / package.json 为准(当前 1.3.
|
|
127
|
+
specflow --version # 以 npm / package.json 为准(当前 1.3.2-beta)
|
|
128
128
|
specflow --help
|
|
129
129
|
```
|
|
130
130
|
|
|
@@ -5,14 +5,15 @@ export interface OpenerSpawnPlan {
|
|
|
5
5
|
readonly args: string[];
|
|
6
6
|
readonly options: SpawnSyncOptions;
|
|
7
7
|
}
|
|
8
|
+
export declare function selectWindowsOpenerPath(output: string): string | null;
|
|
8
9
|
/**
|
|
9
10
|
* Build spawn argv for launching a workspace-file opener.
|
|
10
11
|
*
|
|
11
|
-
* On Windows, Cursor/VS Code ship as `*.cmd` shims.
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
12
|
+
* On Windows, Cursor/VS Code normally ship as `*.cmd` shims. Resolve the shim
|
|
13
|
+
* to an absolute path first: invoking a bare command while cwd is a project
|
|
14
|
+
* can make the shim resolve its own relative Cursor.exe path from the project.
|
|
15
|
+
* Batch shims run through cmd.exe; native executables run directly.
|
|
15
16
|
*/
|
|
16
|
-
export declare function buildOpenerSpawn(opener: OpenerDefinition, workspacePath: string, primaryPath: string, platform?: NodeJS.Platform, comSpec?: string): OpenerSpawnPlan;
|
|
17
|
+
export declare function buildOpenerSpawn(opener: OpenerDefinition, workspacePath: string, primaryPath: string, platform?: NodeJS.Platform, comSpec?: string, resolvedPath?: string): OpenerSpawnPlan;
|
|
17
18
|
export declare function isOpenerAvailable(opener: OpenerDefinition): boolean;
|
|
18
19
|
export declare function launchOpener(opener: OpenerDefinition, workspacePath: string, primaryPath: string): void;
|
|
@@ -1,13 +1,36 @@
|
|
|
1
1
|
import { spawnSync } from 'node:child_process';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
export function selectWindowsOpenerPath(output) {
|
|
4
|
+
return (output
|
|
5
|
+
.split(/\r?\n/)
|
|
6
|
+
.map((candidate) => candidate.trim())
|
|
7
|
+
.find((candidate) => /\.(?:cmd|bat|exe)$/i.test(candidate)) ?? null);
|
|
8
|
+
}
|
|
9
|
+
function resolveWindowsOpenerPath(opener) {
|
|
10
|
+
for (const suffix of ['.cmd', '.bat', '.exe']) {
|
|
11
|
+
const result = spawnSync('where.exe', [`${opener.command}${suffix}`], {
|
|
12
|
+
encoding: 'utf8',
|
|
13
|
+
shell: false,
|
|
14
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
15
|
+
});
|
|
16
|
+
if (result.status === 0) {
|
|
17
|
+
const executablePath = selectWindowsOpenerPath(result.stdout ?? '');
|
|
18
|
+
if (executablePath) {
|
|
19
|
+
return executablePath;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
2
25
|
/**
|
|
3
26
|
* Build spawn argv for launching a workspace-file opener.
|
|
4
27
|
*
|
|
5
|
-
* On Windows, Cursor/VS Code ship as `*.cmd` shims.
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
28
|
+
* On Windows, Cursor/VS Code normally ship as `*.cmd` shims. Resolve the shim
|
|
29
|
+
* to an absolute path first: invoking a bare command while cwd is a project
|
|
30
|
+
* can make the shim resolve its own relative Cursor.exe path from the project.
|
|
31
|
+
* Batch shims run through cmd.exe; native executables run directly.
|
|
9
32
|
*/
|
|
10
|
-
export function buildOpenerSpawn(opener, workspacePath, primaryPath, platform = process.platform, comSpec = process.env.ComSpec || 'cmd.exe') {
|
|
33
|
+
export function buildOpenerSpawn(opener, workspacePath, primaryPath, platform = process.platform, comSpec = process.env.ComSpec || 'cmd.exe', resolvedPath) {
|
|
11
34
|
const baseOptions = {
|
|
12
35
|
cwd: primaryPath,
|
|
13
36
|
shell: false,
|
|
@@ -20,27 +43,48 @@ export function buildOpenerSpawn(opener, workspacePath, primaryPath, platform =
|
|
|
20
43
|
options: baseOptions,
|
|
21
44
|
};
|
|
22
45
|
}
|
|
23
|
-
|
|
24
|
-
|
|
46
|
+
if (!resolvedPath) {
|
|
47
|
+
throw new Error(`Could not resolve '${opener.command}.cmd' or '${opener.command}.exe' on PATH.`);
|
|
48
|
+
}
|
|
49
|
+
const executablePath = path.win32.normalize(resolvedPath);
|
|
50
|
+
const extension = path.win32.extname(executablePath).toLowerCase();
|
|
51
|
+
const shimOptions = {
|
|
52
|
+
...baseOptions,
|
|
53
|
+
// Cursor's .cmd shim derives Cursor.exe from its own directory.
|
|
54
|
+
cwd: path.win32.dirname(executablePath),
|
|
55
|
+
};
|
|
56
|
+
if (extension === '.exe') {
|
|
57
|
+
return {
|
|
58
|
+
command: executablePath,
|
|
59
|
+
args: [workspacePath],
|
|
60
|
+
options: shimOptions,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
// cmd.exe's /s removes the outer pair of quotes. Supply that pair explicitly
|
|
64
|
+
// so the batch-file path and workspace path retain their independent quotes.
|
|
65
|
+
const commandLine = `""${executablePath.replace(/"/g, '""')}" "${workspacePath.replace(/"/g, '""')}""`;
|
|
25
66
|
return {
|
|
26
67
|
command: comSpec,
|
|
27
|
-
args: ['/d', '/s', '/c',
|
|
68
|
+
args: ['/d', '/s', '/c', commandLine],
|
|
28
69
|
options: {
|
|
29
|
-
...
|
|
70
|
+
...shimOptions,
|
|
30
71
|
windowsVerbatimArguments: true,
|
|
31
72
|
},
|
|
32
73
|
};
|
|
33
74
|
}
|
|
34
75
|
export function isOpenerAvailable(opener) {
|
|
35
|
-
|
|
36
|
-
|
|
76
|
+
if (process.platform === 'win32') {
|
|
77
|
+
return resolveWindowsOpenerPath(opener) !== null;
|
|
78
|
+
}
|
|
79
|
+
const result = spawnSync('which', [opener.command], {
|
|
37
80
|
stdio: 'ignore',
|
|
38
81
|
shell: false,
|
|
39
82
|
});
|
|
40
83
|
return result.status === 0;
|
|
41
84
|
}
|
|
42
85
|
export function launchOpener(opener, workspacePath, primaryPath) {
|
|
43
|
-
const
|
|
86
|
+
const resolvedPath = process.platform === 'win32' ? resolveWindowsOpenerPath(opener) : undefined;
|
|
87
|
+
const plan = buildOpenerSpawn(opener, workspacePath, primaryPath, process.platform, process.env.ComSpec || 'cmd.exe', resolvedPath ?? undefined);
|
|
44
88
|
const child = spawnSync(plan.command, plan.args, plan.options);
|
|
45
89
|
if (child.error) {
|
|
46
90
|
throw child.error;
|
package/package.json
CHANGED