apigrip 0.5.4 → 0.6.2
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/cli/index.js +115 -7
- package/completions/_apigrip +7 -2
- package/package.json +1 -1
package/cli/index.js
CHANGED
|
@@ -2,6 +2,112 @@
|
|
|
2
2
|
import yargs from 'yargs';
|
|
3
3
|
import { hideBin } from 'yargs/helpers';
|
|
4
4
|
|
|
5
|
+
const METHODS = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'];
|
|
6
|
+
|
|
7
|
+
// Intercept --get-yargs-completions before yargs to provide dynamic completions
|
|
8
|
+
const rawArgs = process.argv.slice(2);
|
|
9
|
+
const compIdx = rawArgs.indexOf('--get-yargs-completions');
|
|
10
|
+
if (compIdx !== -1) {
|
|
11
|
+
const args = rawArgs.slice(compIdx + 1); // [apigrip, cmd, ...rest]
|
|
12
|
+
const cmd = args[1] || '';
|
|
13
|
+
const prevArg = args[args.length - 2] || '';
|
|
14
|
+
const cmdsWithMethod = ['send', 'curl', 'show', 'last'];
|
|
15
|
+
let handled = false;
|
|
16
|
+
|
|
17
|
+
// Extract --project <name> or --spec <path> from args to resolve the right project
|
|
18
|
+
function getArgValue(flag) {
|
|
19
|
+
const idx = args.indexOf(flag);
|
|
20
|
+
return (idx !== -1 && idx + 1 < args.length) ? args[idx + 1] : null;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Resolve project dir from --project name, --spec path, or cwd
|
|
24
|
+
async function resolveProjectDir() {
|
|
25
|
+
const { loadProjects, findProjectForDir } = await import('../core/projects-store.js');
|
|
26
|
+
const projectName = getArgValue('--project');
|
|
27
|
+
const specFlag = getArgValue('--spec');
|
|
28
|
+
if (specFlag) {
|
|
29
|
+
const { dirname } = await import('node:path');
|
|
30
|
+
return getArgValue('--project')
|
|
31
|
+
? loadProjects().find(p => p.name === projectName)?.path || process.cwd()
|
|
32
|
+
: dirname(specFlag);
|
|
33
|
+
}
|
|
34
|
+
if (projectName) {
|
|
35
|
+
const match = loadProjects().find(p => p.name === projectName);
|
|
36
|
+
if (match) return match.path;
|
|
37
|
+
}
|
|
38
|
+
const cwdMatch = findProjectForDir(process.cwd());
|
|
39
|
+
return cwdMatch ? cwdMatch.path : process.cwd();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Discover and parse spec, returning endpoints
|
|
43
|
+
async function resolveEndpoints() {
|
|
44
|
+
const { discoverSpec } = await import('../core/spec-discovery.js');
|
|
45
|
+
const { parseSpec, extractEndpoints } = await import('../core/spec-parser.js');
|
|
46
|
+
const projectDir = await resolveProjectDir();
|
|
47
|
+
const specFlag = getArgValue('--spec');
|
|
48
|
+
const specPath = specFlag || (await discoverSpec(projectDir))?.specPath;
|
|
49
|
+
if (!specPath) return [];
|
|
50
|
+
const spec = await parseSpec(specPath);
|
|
51
|
+
return extractEndpoints(spec);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
try {
|
|
55
|
+
// --project <TAB> → bookmarked project names
|
|
56
|
+
if (prevArg === '--project') {
|
|
57
|
+
const { loadProjects } = await import('../core/projects-store.js');
|
|
58
|
+
const projects = loadProjects();
|
|
59
|
+
projects.forEach(p => console.log(p.name));
|
|
60
|
+
handled = true;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// -e / --env <TAB> → environment names
|
|
64
|
+
if (!handled && (prevArg === '--env' || prevArg === '-e')) {
|
|
65
|
+
const { loadEnvironments } = await import('../core/env-resolver.js');
|
|
66
|
+
const projectDir = await resolveProjectDir();
|
|
67
|
+
const envData = loadEnvironments(projectDir);
|
|
68
|
+
Object.keys(envData.environments || {}).forEach(n => console.log(n));
|
|
69
|
+
handled = true;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// --tag <TAB> → tag names from spec
|
|
73
|
+
if (!handled && prevArg === '--tag') {
|
|
74
|
+
const endpoints = await resolveEndpoints();
|
|
75
|
+
const tags = new Set();
|
|
76
|
+
endpoints.forEach(e => (e.tags || []).forEach(t => tags.add(t)));
|
|
77
|
+
tags.forEach(t => console.log(t));
|
|
78
|
+
handled = true;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Commands with <method> <path>: complete methods, then endpoint paths
|
|
82
|
+
// Use pattern matching (not positional counting) to handle interspersed options
|
|
83
|
+
if (!handled && cmdsWithMethod.includes(cmd)) {
|
|
84
|
+
const currentWord = args[args.length - 1] || '';
|
|
85
|
+
// If user is typing an option flag, let yargs handle it
|
|
86
|
+
if (!currentWord.startsWith('-')) {
|
|
87
|
+
// Look at all args except the current word being completed
|
|
88
|
+
const prior = args.slice(2, -1);
|
|
89
|
+
const methodArg = prior.find(a => METHODS.includes(a.toUpperCase()));
|
|
90
|
+
const pathArg = prior.find(a => a.startsWith('/'));
|
|
91
|
+
|
|
92
|
+
if (!methodArg) {
|
|
93
|
+
METHODS.forEach(m => console.log(m));
|
|
94
|
+
handled = true;
|
|
95
|
+
} else if (!pathArg) {
|
|
96
|
+
const endpoints = await resolveEndpoints();
|
|
97
|
+
const method = methodArg.toUpperCase();
|
|
98
|
+
const filtered = endpoints.filter(e => e.method === method);
|
|
99
|
+
filtered.forEach(e => console.log(e.path));
|
|
100
|
+
handled = true;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
} catch {
|
|
105
|
+
// Silently fall through to yargs defaults
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (handled) process.exit(0);
|
|
109
|
+
}
|
|
110
|
+
|
|
5
111
|
// Register commands
|
|
6
112
|
const cli = yargs(hideBin(process.argv))
|
|
7
113
|
.scriptName('apigrip')
|
|
@@ -130,17 +236,19 @@ const cli = yargs(hideBin(process.argv))
|
|
|
130
236
|
}, (argv) => {
|
|
131
237
|
const shell = argv.shell || (process.env.SHELL || '').split('/').pop() || 'bash';
|
|
132
238
|
if (shell === 'zsh') {
|
|
133
|
-
console.log(
|
|
134
|
-
|
|
135
|
-
_apigrip() {
|
|
136
|
-
local completions
|
|
239
|
+
console.log(`_apigrip() {
|
|
240
|
+
local -a completions
|
|
137
241
|
completions=("\${(@f)$(apigrip --get-yargs-completions "\${words[@]}" 2>/dev/null)}")
|
|
138
|
-
|
|
242
|
+
local -a stripped
|
|
243
|
+
local c
|
|
244
|
+
for c in "\${completions[@]}"; do
|
|
245
|
+
stripped+=("\${c%%:*}")
|
|
246
|
+
done
|
|
247
|
+
compadd -a stripped
|
|
139
248
|
}
|
|
140
249
|
|
|
141
|
-
_apigrip`);
|
|
250
|
+
compdef _apigrip apigrip`);
|
|
142
251
|
} else {
|
|
143
|
-
// Let yargs generate bash completions by re-running with --get-yargs-completions
|
|
144
252
|
console.log(`###-begin-apigrip-completions-###
|
|
145
253
|
_apigrip_yargs_completions()
|
|
146
254
|
{
|
package/completions/_apigrip
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
#compdef apigrip
|
|
2
2
|
|
|
3
3
|
_apigrip() {
|
|
4
|
-
local completions
|
|
4
|
+
local -a completions
|
|
5
5
|
completions=("${(@f)$(apigrip --get-yargs-completions "${words[@]}" 2>/dev/null)}")
|
|
6
|
-
|
|
6
|
+
local -a stripped
|
|
7
|
+
local c
|
|
8
|
+
for c in "${completions[@]}"; do
|
|
9
|
+
stripped+=("${c%%:*}")
|
|
10
|
+
done
|
|
11
|
+
compadd -a stripped
|
|
7
12
|
}
|
|
8
13
|
|
|
9
14
|
_apigrip
|