apigrip 0.1.0 → 0.2.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.
- package/cli/commands/serve.js +68 -4
- package/package.json +1 -1
- package/server/routes/project.js +4 -0
package/cli/commands/serve.js
CHANGED
|
@@ -1,12 +1,62 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
2
3
|
import { parseSpec } from '../../core/spec-parser.js';
|
|
3
4
|
import { createServer } from '../../server/index.js';
|
|
4
|
-
import {
|
|
5
|
+
import { findProjectForDir } from '../../core/projects-store.js';
|
|
6
|
+
|
|
7
|
+
const ROOT_SPEC_FILES = ['openapi.yaml', 'openapi.yml', 'openapi.json', 'swagger.yaml', 'swagger.yml', 'swagger.json'];
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Quick project resolution for the serve command.
|
|
11
|
+
* Unlike resolveProjectContext, this never does BFS discovery.
|
|
12
|
+
* Only auto-opens cwd if it's a git repo with a root-level spec file.
|
|
13
|
+
*/
|
|
14
|
+
async function resolveServeProject(argv) {
|
|
15
|
+
// 1. Explicit flags take priority
|
|
16
|
+
if (argv.spec) {
|
|
17
|
+
const projectDir = argv.project || process.cwd();
|
|
18
|
+
return { projectDir, specPath: argv.spec };
|
|
19
|
+
}
|
|
20
|
+
if (argv.project) {
|
|
21
|
+
const specPath = findRootSpec(argv.project);
|
|
22
|
+
return { projectDir: argv.project, specPath };
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// 2. Check if cwd is inside a bookmarked project
|
|
26
|
+
const cwd = process.cwd();
|
|
27
|
+
const bookmark = findProjectForDir(cwd);
|
|
28
|
+
if (bookmark) {
|
|
29
|
+
const specPath = bookmark.spec || findRootSpec(bookmark.path);
|
|
30
|
+
return { projectDir: bookmark.path, specPath };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// 3. Only auto-open cwd if it's a git repo with a root-level spec
|
|
34
|
+
const isGitRepo = fs.existsSync(path.join(cwd, '.git'));
|
|
35
|
+
if (isGitRepo) {
|
|
36
|
+
const specPath = findRootSpec(cwd);
|
|
37
|
+
if (specPath) {
|
|
38
|
+
return { projectDir: cwd, specPath };
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// 4. Start without a project — user can open from history in the UI
|
|
43
|
+
return { projectDir: null, specPath: null };
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function findRootSpec(dir) {
|
|
47
|
+
for (const name of ROOT_SPEC_FILES) {
|
|
48
|
+
const p = path.join(dir, name);
|
|
49
|
+
try {
|
|
50
|
+
if (fs.statSync(p).isFile()) return p;
|
|
51
|
+
} catch { /* not found */ }
|
|
52
|
+
}
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
5
55
|
|
|
6
56
|
export async function serveCommand(argv) {
|
|
7
|
-
const { projectDir, specPath } = await
|
|
57
|
+
const { projectDir, specPath } = await resolveServeProject(argv);
|
|
8
58
|
|
|
9
|
-
if (!fs.existsSync(projectDir)) {
|
|
59
|
+
if (projectDir && !fs.existsSync(projectDir)) {
|
|
10
60
|
console.error(`Project directory does not exist: ${projectDir}`);
|
|
11
61
|
process.exitCode = 2;
|
|
12
62
|
return;
|
|
@@ -34,8 +84,11 @@ export async function serveCommand(argv) {
|
|
|
34
84
|
|
|
35
85
|
const { app } = createServer({ projectDir, specPath, spec, noBrowse });
|
|
36
86
|
|
|
37
|
-
app.listen(port, host, () => {
|
|
87
|
+
const server = app.listen(port, host, () => {
|
|
38
88
|
console.log(`Server listening on http://${host}:${port}`);
|
|
89
|
+
if (projectDir) {
|
|
90
|
+
console.log(`Project: ${projectDir}`);
|
|
91
|
+
}
|
|
39
92
|
if (argv.open) {
|
|
40
93
|
import('child_process').then(({ exec }) => {
|
|
41
94
|
const cmd = process.platform === 'darwin' ? 'open' : process.platform === 'win32' ? 'start' : 'xdg-open';
|
|
@@ -43,4 +96,15 @@ export async function serveCommand(argv) {
|
|
|
43
96
|
});
|
|
44
97
|
}
|
|
45
98
|
});
|
|
99
|
+
|
|
100
|
+
server.on('error', (err) => {
|
|
101
|
+
if (err.code === 'EADDRINUSE') {
|
|
102
|
+
console.error(`Error: Port ${port} is already in use. Try --port <number>`);
|
|
103
|
+
} else if (err.code === 'EACCES') {
|
|
104
|
+
console.error(`Error: Permission denied for port ${port}. Try a port above 1024.`);
|
|
105
|
+
} else {
|
|
106
|
+
console.error(`Error starting server: ${err.message}`);
|
|
107
|
+
}
|
|
108
|
+
process.exitCode = 1;
|
|
109
|
+
});
|
|
46
110
|
}
|
package/package.json
CHANGED
package/server/routes/project.js
CHANGED
|
@@ -2,6 +2,7 @@ import { Router } from 'express';
|
|
|
2
2
|
import { getGitInfo } from '../../core/git-info.js';
|
|
3
3
|
import { parseSpec } from '../../core/spec-parser.js';
|
|
4
4
|
import { discoverSpec } from '../../core/spec-discovery.js';
|
|
5
|
+
import { addProject } from '../../core/projects-store.js';
|
|
5
6
|
import { broadcast } from './events.js';
|
|
6
7
|
import path from 'path';
|
|
7
8
|
import fs from 'fs';
|
|
@@ -62,6 +63,9 @@ export function createProjectRoutes(state) {
|
|
|
62
63
|
// Switch project
|
|
63
64
|
state.projectDir = newPath;
|
|
64
65
|
|
|
66
|
+
// Auto-bookmark the project
|
|
67
|
+
try { addProject(newPath); } catch { /* already bookmarked or invalid — ignore */ }
|
|
68
|
+
|
|
65
69
|
// Discover and parse spec
|
|
66
70
|
const specResult = await discoverSpec(newPath);
|
|
67
71
|
state.specPath = specResult?.specPath || null;
|