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 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(`#compdef apigrip
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
- compadd -a completions
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
  {
@@ -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
- compadd -a completions
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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "apigrip",
3
- "version": "0.5.4",
3
+ "version": "0.6.2",
4
4
  "description": "A spec-first, read-only OpenAPI client for developers",
5
5
  "type": "module",
6
6
  "main": "./lib/index.cjs",