@kong/spec-renderer 1.111.2 → 1.111.3-pr.942.0eceead.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/README.md +11 -0
- package/dist/cli/commands/preview.js +106 -0
- package/dist/cli/commands/preview.js.map +1 -0
- package/dist/cli/find-open-port.js +27 -0
- package/dist/cli/find-open-port.js.map +1 -0
- package/dist/cli/index.js +56 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/parse-int-flag.js +28 -0
- package/dist/cli/parse-int-flag.js.map +1 -0
- package/dist/cli/preview-page/client.js +36 -0
- package/dist/cli/preview-page/client.js.map +1 -0
- package/dist/cli/preview-page/index.html +38 -0
- package/dist/cli/resolve-render-options.js +36 -0
- package/dist/cli/resolve-render-options.js.map +1 -0
- package/dist/cli/resolve-spec-source.js +20 -0
- package/dist/cli/resolve-spec-source.js.map +1 -0
- package/dist/cli/server.js +137 -0
- package/dist/cli/server.js.map +1 -0
- package/dist/cli/spec-source.js +23 -0
- package/dist/cli/spec-source.js.map +1 -0
- package/dist/cli/ui.js +90 -0
- package/dist/cli/ui.js.map +1 -0
- package/package.json +34 -80
package/README.md
CHANGED
|
@@ -15,6 +15,7 @@ An online API specification editor is available at [api-documentation.dev](https
|
|
|
15
15
|
- [Example for html/script](#-example-for-htmlscript)
|
|
16
16
|
- [Props](#props)
|
|
17
17
|
- [v-model](#v-model)
|
|
18
|
+
- [CLI](#cli)
|
|
18
19
|
- [Contributing & Local Development](#contributing--local-development)
|
|
19
20
|
- [Development Sandbox](#development-sandbox)
|
|
20
21
|
- [Build and Preview the Development Sandbox](#build-and-preview-the-development-sandbox)
|
|
@@ -225,6 +226,16 @@ As of now only `SpecRenderer` as single component is supported for this. Let us
|
|
|
225
226
|
|
|
226
227
|
[Check out the `SpecRendererProps` interface](./src/types/spec-renderer.ts) for all props valid for the `SpecRenderer` component.
|
|
227
228
|
|
|
229
|
+
## CLI
|
|
230
|
+
|
|
231
|
+
Preview a local OpenAPI or AsyncAPI spec, rendered with this package's own UI, right on your machine - no host app or project setup required. The preview reloads automatically when you save changes to the spec file.
|
|
232
|
+
|
|
233
|
+
```sh
|
|
234
|
+
npx @kong/spec-renderer preview ./openapi.yaml
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
See the [CLI docs](./cli/README.md) for full usage, flags, and troubleshooting.
|
|
238
|
+
|
|
228
239
|
## Contributing & Local Development
|
|
229
240
|
|
|
230
241
|
To get started, install the package dependencies
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import pc from 'picocolors';
|
|
3
|
+
import { watch } from 'chokidar';
|
|
4
|
+
import open from 'open';
|
|
5
|
+
import { loadSpecSource } from '../spec-source.js';
|
|
6
|
+
import { resolveRenderOptions } from '../resolve-render-options.js';
|
|
7
|
+
import { findOpenPort } from '../find-open-port.js';
|
|
8
|
+
import { startPreviewServer } from '../server.js';
|
|
9
|
+
import { info, printPreviewBanner } from '../ui.js';
|
|
10
|
+
const DEFAULT_PORT = 4757;
|
|
11
|
+
/**
|
|
12
|
+
* Runs the `preview` command: loads the spec, starts the local preview
|
|
13
|
+
* server, watches the spec file for changes (when it's a local file), and
|
|
14
|
+
* opens the browser.
|
|
15
|
+
*
|
|
16
|
+
* Resolves once the server is up; the process is kept alive by the running
|
|
17
|
+
* server and, when applicable, the file watcher.
|
|
18
|
+
*/
|
|
19
|
+
export async function runPreviewCommand(specArg, flags) {
|
|
20
|
+
const source = await loadSpecSource(specArg);
|
|
21
|
+
let specText = source.text;
|
|
22
|
+
const requestedPort = await findOpenPort(flags.port ?? DEFAULT_PORT);
|
|
23
|
+
const previewServer = await startPreviewServer({
|
|
24
|
+
port: requestedPort,
|
|
25
|
+
getSpecText: () => specText,
|
|
26
|
+
config: resolveRenderOptions(flags),
|
|
27
|
+
});
|
|
28
|
+
// Use the port the server actually bound to, not the requested one - they
|
|
29
|
+
// differ when the requested port is `0` (OS picks any free port).
|
|
30
|
+
const url = `http://localhost:${previewServer.port}`;
|
|
31
|
+
const isWatching = source.watch && !!source.watchPath;
|
|
32
|
+
printPreviewBanner([
|
|
33
|
+
{ label: 'Spec', value: specArg },
|
|
34
|
+
{ label: 'URL', value: pc.bold(pc.underline(url)) },
|
|
35
|
+
{ label: 'Reload', value: isWatching ? pc.green('watching for changes') : pc.yellow('not available (remote URL)') },
|
|
36
|
+
]);
|
|
37
|
+
console.log();
|
|
38
|
+
info('Press Ctrl+C to stop');
|
|
39
|
+
let watcher;
|
|
40
|
+
if (source.watch && source.watchPath) {
|
|
41
|
+
const watchPath = source.watchPath;
|
|
42
|
+
// Guards against a slower, now-stale read completing after a newer one -
|
|
43
|
+
// e.g. two rapid saves in quick succession - and clobbering fresher content.
|
|
44
|
+
let latestChangeToken = 0;
|
|
45
|
+
watcher = watch(watchPath, {
|
|
46
|
+
// Some editors/tools write a file's contents in multiple chunks before
|
|
47
|
+
// the save is complete; without this, a `change` event can fire mid-write
|
|
48
|
+
// and be read as truncated/invalid content, surfacing a bogus parse error
|
|
49
|
+
// for what was actually a valid save.
|
|
50
|
+
awaitWriteFinish: {
|
|
51
|
+
stabilityThreshold: 200,
|
|
52
|
+
pollInterval: 20,
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
watcher.on('change', () => {
|
|
56
|
+
const changeToken = ++latestChangeToken;
|
|
57
|
+
readFile(watchPath, 'utf-8')
|
|
58
|
+
.then((text) => {
|
|
59
|
+
if (changeToken !== latestChangeToken) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
specText = text;
|
|
63
|
+
previewServer.broadcastReload();
|
|
64
|
+
console.log(`${pc.magenta('↻')} Spec changed, reloading preview...`);
|
|
65
|
+
})
|
|
66
|
+
.catch((readError) => {
|
|
67
|
+
console.error(`${pc.red('✖')} Failed to reload spec: ${readError instanceof Error ? readError.message : String(readError)}`);
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
watcher.on('unlink', () => {
|
|
71
|
+
console.error(`${pc.red('✖')} Spec file was deleted or moved - live reload has stopped. The preview will keep showing its last-known content.`);
|
|
72
|
+
});
|
|
73
|
+
watcher.on('error', (watchError) => {
|
|
74
|
+
console.error(`${pc.red('✖')} File watcher error: ${watchError instanceof Error ? watchError.message : String(watchError)}`);
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
let isShuttingDown = false;
|
|
78
|
+
const shutdown = () => {
|
|
79
|
+
if (isShuttingDown) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
isShuttingDown = true;
|
|
83
|
+
void Promise.resolve(watcher?.close())
|
|
84
|
+
.then(() => previewServer.close())
|
|
85
|
+
.catch((shutdownError) => {
|
|
86
|
+
console.error(`${pc.red('✖')} Error during shutdown: ${shutdownError instanceof Error ? shutdownError.message : String(shutdownError)}`);
|
|
87
|
+
})
|
|
88
|
+
.finally(() => process.exit(0));
|
|
89
|
+
};
|
|
90
|
+
// Registered before opening the browser so the server/watcher always have a
|
|
91
|
+
// clean shutdown path via Ctrl+C, even if the browser launch below fails.
|
|
92
|
+
process.on('SIGINT', shutdown);
|
|
93
|
+
process.on('SIGTERM', shutdown);
|
|
94
|
+
if (flags.open !== false) {
|
|
95
|
+
try {
|
|
96
|
+
await open(url);
|
|
97
|
+
}
|
|
98
|
+
catch (openError) {
|
|
99
|
+
// Opening the browser is a convenience, not essential to the preview
|
|
100
|
+
// working - warn and keep the server/watcher running rather than
|
|
101
|
+
// failing the whole command.
|
|
102
|
+
console.error(`${pc.red('✖')} Failed to open the browser automatically: ${openError instanceof Error ? openError.message : String(openError)}`);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=preview.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preview.js","sourceRoot":"","sources":["../../../cli/commands/preview.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { createServer } from 'node:net';
|
|
2
|
+
/**
|
|
3
|
+
* Checks whether a port is free to bind on the local host by briefly binding
|
|
4
|
+
* to it and releasing it.
|
|
5
|
+
*/
|
|
6
|
+
export function isPortFree(port) {
|
|
7
|
+
return new Promise((resolve) => {
|
|
8
|
+
const server = createServer();
|
|
9
|
+
server.once('error', () => resolve(false));
|
|
10
|
+
server.once('listening', () => server.close(() => resolve(true)));
|
|
11
|
+
server.listen(port);
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Finds the first free port starting at `startPort`, checking up to
|
|
16
|
+
* `maxAttempts` consecutive ports.
|
|
17
|
+
*/
|
|
18
|
+
export async function findOpenPort(startPort, checkIsPortFree = isPortFree, maxAttempts = 10) {
|
|
19
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
20
|
+
const candidate = startPort + attempt;
|
|
21
|
+
if (await checkIsPortFree(candidate)) {
|
|
22
|
+
return candidate;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
throw new Error(`Could not find an open port after checking ${maxAttempts} ports starting at ${startPort}`);
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=find-open-port.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"find-open-port.js","sourceRoot":"","sources":["../../cli/find-open-port.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAEvC;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,IAAY;IACrC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,MAAM,GAAG,YAAY,EAAE,CAAA;QAE7B,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAA;QAC1C,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QACjE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;IACrB,CAAC,CAAC,CAAA;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,SAAiB,EACjB,kBAAsD,UAAU,EAChE,WAAW,GAAG,EAAE;IAEhB,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,GAAG,WAAW,EAAE,OAAO,EAAE,EAAE,CAAC;QACvD,MAAM,SAAS,GAAG,SAAS,GAAG,OAAO,CAAA;QAErC,IAAI,MAAM,eAAe,CAAC,SAAS,CAAC,EAAE,CAAC;YACrC,OAAO,SAAS,CAAA;QAClB,CAAC;IACH,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,8CAA8C,WAAW,sBAAsB,SAAS,EAAE,CAAC,CAAA;AAC7G,CAAC"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
3
|
+
import { dirname, join } from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import { Command, Option } from 'commander';
|
|
6
|
+
import { runPreviewCommand } from './commands/preview.js';
|
|
7
|
+
import { error as printError } from './ui.js';
|
|
8
|
+
import { parseIntFlag } from './parse-int-flag.js';
|
|
9
|
+
// The CLI isn't versioned independently - it always reports the package's
|
|
10
|
+
// own version, which is what actually gets published/installed.
|
|
11
|
+
const currentDir = dirname(fileURLToPath(import.meta.url));
|
|
12
|
+
const packageJsonPath = join(currentDir, '..', '..', 'package.json');
|
|
13
|
+
const { version } = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
|
|
14
|
+
const program = new Command();
|
|
15
|
+
program
|
|
16
|
+
.name('kong-spec-renderer')
|
|
17
|
+
.description('Preview a local OpenAPI/AsyncAPI spec using @kong/spec-renderer')
|
|
18
|
+
.version(version, '-V, --version', 'output the current version');
|
|
19
|
+
program
|
|
20
|
+
.command('preview')
|
|
21
|
+
.description('Render a spec file or URL in a local preview server, reloading when the file changes')
|
|
22
|
+
.argument('<spec>', 'path to a local spec file, or a URL to a remote spec')
|
|
23
|
+
.option('--port <port>', 'port to run the preview server on', parseIntFlag('--port', { max: 65535 }))
|
|
24
|
+
.option('--no-open', 'do not automatically open the preview in a browser')
|
|
25
|
+
.option('--hide-internal', 'hide internal operations from the table of contents')
|
|
26
|
+
.option('--hide-deprecated', 'hide deprecated operations from the table of contents')
|
|
27
|
+
.option('--hide-schemas', 'hide schemas (models) from the table of contents')
|
|
28
|
+
.option('--hide-try-it', 'hide the "Try it" UI')
|
|
29
|
+
.option('--hide-insomnia-try-it', 'hide the "Insomnia" option within the "Try it" UI')
|
|
30
|
+
.option('--with-credentials', 'send credentials when resolving external (http) $refs within the spec')
|
|
31
|
+
.option('--max-expanded-depth <depth>', 'maximum depth to expand nested schema properties by default', parseIntFlag('--max-expanded-depth'))
|
|
32
|
+
.option('--verbose', 'log spec parsing stages to the browser console, for troubleshooting (alias: --trace-parsing)')
|
|
33
|
+
.addOption(new Option('--trace-parsing', 'alias for --verbose').hideHelp())
|
|
34
|
+
.option('--no-content-scrolling', 'navigate between operations/schemas one at a time instead of scrolling through them continuously')
|
|
35
|
+
.option('--no-custom-server-url', 'do not let the preview add a custom server URL to the servers list')
|
|
36
|
+
.option('--show-navigation-buttons', 'show prev/next buttons at the bottom of each operation - useful with --no-content-scrolling')
|
|
37
|
+
.option('--hide-download-button', 'hide the spec download button')
|
|
38
|
+
.option('--enable-operation-links', 'show a permalink icon on each operation that copies its URL to the clipboard')
|
|
39
|
+
.option('--hide-powered-by', 'hide the "Powered by" branding in the table of contents')
|
|
40
|
+
.option('--path <path>', 'open the preview at a specific operation/schema path, e.g. /pets/{id}')
|
|
41
|
+
.action(async (spec, raw) => {
|
|
42
|
+
const flags = {
|
|
43
|
+
...raw,
|
|
44
|
+
allowContentScrolling: raw.contentScrolling,
|
|
45
|
+
currentPath: raw.path,
|
|
46
|
+
};
|
|
47
|
+
try {
|
|
48
|
+
await runPreviewCommand(spec, flags);
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
printError(error instanceof Error ? error.message : String(error));
|
|
52
|
+
process.exitCode = 1;
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
await program.parseAsync(process.argv);
|
|
56
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../cli/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { InvalidArgumentError } from 'commander';
|
|
2
|
+
/**
|
|
3
|
+
* Builds a commander option parser for a non-negative integer flag.
|
|
4
|
+
*
|
|
5
|
+
* Throws a commander `InvalidArgumentError` for non-numeric or out-of-range
|
|
6
|
+
* input, which commander turns into a clean CLI error - rather than letting
|
|
7
|
+
* `Number.parseInt` silently produce `NaN` (which `??` does not treat as
|
|
8
|
+
* nullish, and which `JSON.stringify` silently serializes to `null`).
|
|
9
|
+
*/
|
|
10
|
+
export function parseIntFlag(flagName, options = {}) {
|
|
11
|
+
return (value) => {
|
|
12
|
+
// `Number.parseInt` stops at the first non-digit rather than requiring
|
|
13
|
+
// the whole string to be numeric (e.g. `parseInt('5000abc', 10) === 5000`,
|
|
14
|
+
// `parseInt('2.9', 10) === 2`) - reject anything that isn't purely
|
|
15
|
+
// digits up front so trailing garbage or a decimal point can't silently
|
|
16
|
+
// produce a value the user never typed.
|
|
17
|
+
if (!/^\d+$/.test(value.trim())) {
|
|
18
|
+
const bound = options.max === undefined ? '' : ` up to ${options.max}`;
|
|
19
|
+
throw new InvalidArgumentError(`${flagName} must be a non-negative integer${bound}.`);
|
|
20
|
+
}
|
|
21
|
+
const parsed = Number.parseInt(value, 10);
|
|
22
|
+
if (options.max !== undefined && parsed > options.max) {
|
|
23
|
+
throw new InvalidArgumentError(`${flagName} must be a non-negative integer up to ${options.max}.`);
|
|
24
|
+
}
|
|
25
|
+
return parsed;
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=parse-int-flag.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse-int-flag.js","sourceRoot":"","sources":["../../cli/parse-int-flag.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAA;AAOhD;;;;;;;GAOG;AACH,MAAM,UAAU,YAAY,CAAC,QAAgB,EAAE,UAA+B,EAAE;IAC9E,OAAO,CAAC,KAAa,EAAU,EAAE;QAC/B,uEAAuE;QACvE,2EAA2E;QAC3E,mEAAmE;QACnE,wEAAwE;QACxE,wCAAwC;QACxC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;YAChC,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,OAAO,CAAC,GAAG,EAAE,CAAA;YAEtE,MAAM,IAAI,oBAAoB,CAAC,GAAG,QAAQ,kCAAkC,KAAK,GAAG,CAAC,CAAA;QACvF,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC,CAAA;QAEzC,IAAI,OAAO,CAAC,GAAG,KAAK,SAAS,IAAI,MAAM,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;YACtD,MAAM,IAAI,oBAAoB,CAAC,GAAG,QAAQ,yCAAyC,OAAO,CAAC,GAAG,GAAG,CAAC,CAAA;QACpG,CAAC;QAED,OAAO,MAAM,CAAA;IACf,CAAC,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
async function loadAndApply() {
|
|
2
|
+
const el = document.getElementById('preview');
|
|
3
|
+
if (!el) {
|
|
4
|
+
return;
|
|
5
|
+
}
|
|
6
|
+
const [specResponse, configResponse] = await Promise.all([fetch('/spec'), fetch('/config')]);
|
|
7
|
+
const spec = await specResponse.text();
|
|
8
|
+
const config = await configResponse.json();
|
|
9
|
+
el.spec = spec;
|
|
10
|
+
for (const [key, value] of Object.entries(config)) {
|
|
11
|
+
el[key] = value;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
void loadAndApply();
|
|
15
|
+
const RECONNECT_DELAY_MS = 1000;
|
|
16
|
+
/**
|
|
17
|
+
* Connects the reload-signal WebSocket, reconnecting after a delay if the
|
|
18
|
+
* connection drops (e.g. the CLI process restarted, or the machine slept)
|
|
19
|
+
* so live-reload keeps working without requiring a manual page refresh.
|
|
20
|
+
*/
|
|
21
|
+
function connect() {
|
|
22
|
+
const protocol = location.protocol === 'https:' ? 'wss' : 'ws';
|
|
23
|
+
const socket = new WebSocket(`${protocol}://${location.host}`);
|
|
24
|
+
socket.addEventListener('message', (event) => {
|
|
25
|
+
const message = JSON.parse(event.data);
|
|
26
|
+
if (message.type === 'reload') {
|
|
27
|
+
location.reload();
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
socket.addEventListener('close', () => {
|
|
31
|
+
setTimeout(connect, RECONNECT_DELAY_MS);
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
connect();
|
|
35
|
+
export {};
|
|
36
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../../cli/preview-page/client.ts"],"names":[],"mappings":"AAKA,KAAK,UAAU,YAAY;IACzB,MAAM,EAAE,GAAG,QAAQ,CAAC,cAAc,CAAC,SAAS,CAA0B,CAAA;IAEtE,IAAI,CAAC,EAAE,EAAE,CAAC;QACR,OAAM;IACR,CAAC;IAED,MAAM,CAAC,YAAY,EAAE,cAAc,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAA;IAC5F,MAAM,IAAI,GAAG,MAAM,YAAY,CAAC,IAAI,EAAE,CAAA;IACtC,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,IAAI,EAA6B,CAAA;IAErE,EAAE,CAAC,IAAI,GAAG,IAAI,CAAA;IAEd,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAClD,EAAE,CAAC,GAAG,CAAC,GAAG,KAAK,CAAA;IACjB,CAAC;AACH,CAAC;AAED,KAAK,YAAY,EAAE,CAAA;AAEnB,MAAM,kBAAkB,GAAG,IAAI,CAAA;AAE/B;;;;GAIG;AACH,SAAS,OAAO;IACd,MAAM,QAAQ,GAAG,QAAQ,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAA;IAC9D,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,GAAG,QAAQ,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAA;IAE9D,MAAM,CAAC,gBAAgB,CAAC,SAAS,EAAE,CAAC,KAAK,EAAE,EAAE;QAC3C,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAc,CAAqB,CAAA;QAEpE,IAAI,OAAO,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC9B,QAAQ,CAAC,MAAM,EAAE,CAAA;QACnB,CAAC;IACH,CAAC,CAAC,CAAA;IAEF,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE;QACpC,UAAU,CAAC,OAAO,EAAE,kBAAkB,CAAC,CAAA;IACzC,CAAC,CAAC,CAAA;AACJ,CAAC;AAED,OAAO,EAAE,CAAA"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="utf-8" />
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
7
|
+
<title>Spec Preview - @kong/spec-renderer</title>
|
|
8
|
+
<link rel="stylesheet" href="/assets/spec-renderer.css" />
|
|
9
|
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
10
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
11
|
+
<link
|
|
12
|
+
href="https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&family=JetBrains+Mono:ital,wght@0,100..800;1,100..800&display=swap"
|
|
13
|
+
rel="stylesheet">
|
|
14
|
+
<style>
|
|
15
|
+
html,
|
|
16
|
+
body {
|
|
17
|
+
margin: 0;
|
|
18
|
+
height: 100%;
|
|
19
|
+
font-family: 'Inter', Roboto, Helvetica, sans-serif;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
kong-spec-renderer {
|
|
23
|
+
display: block;
|
|
24
|
+
height: 100dvh;
|
|
25
|
+
}
|
|
26
|
+
</style>
|
|
27
|
+
</head>
|
|
28
|
+
|
|
29
|
+
<body>
|
|
30
|
+
<kong-spec-renderer id="preview"></kong-spec-renderer>
|
|
31
|
+
<script type="module">
|
|
32
|
+
import {registerKongSpecRenderer} from '/assets/kong-spec-renderer.web-component.es.js'
|
|
33
|
+
registerKongSpecRenderer()
|
|
34
|
+
</script>
|
|
35
|
+
<script type="module" src="/client.js"></script>
|
|
36
|
+
</body>
|
|
37
|
+
|
|
38
|
+
</html>
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Maps parsed `preview` CLI flags to the `SpecRendererProps` subset the preview
|
|
3
|
+
* page renders with.
|
|
4
|
+
*
|
|
5
|
+
* `navigationType` and `controlAddressBar` are always hardcoded - the CLI, not
|
|
6
|
+
* the user, owns the single-page preview environment those props govern.
|
|
7
|
+
* `showPoweredBy` defaults to `true` here even though the component prop
|
|
8
|
+
* itself defaults to `false` - the CLI wants branding visible unless a user
|
|
9
|
+
* opts out with `--hide-powered-by`. `hideNavigationButtons` defaults to
|
|
10
|
+
* `true` (hidden), matching the component's own default, and only flips to
|
|
11
|
+
* `false` when `--show-navigation-buttons` is explicitly passed - mainly
|
|
12
|
+
* useful alongside `--no-content-scrolling`, where the prev/next buttons are
|
|
13
|
+
* otherwise the only in-page way to move between operations.
|
|
14
|
+
*/
|
|
15
|
+
export function resolveRenderOptions(flags) {
|
|
16
|
+
return {
|
|
17
|
+
hideInternal: flags.hideInternal ?? false,
|
|
18
|
+
hideDeprecated: flags.hideDeprecated ?? false,
|
|
19
|
+
hideSchemas: flags.hideSchemas ?? false,
|
|
20
|
+
hideTryIt: flags.hideTryIt ?? false,
|
|
21
|
+
hideInsomniaTryIt: flags.hideInsomniaTryIt ?? false,
|
|
22
|
+
...(flags.maxExpandedDepth === undefined ? {} : { maxExpandedDepth: flags.maxExpandedDepth }),
|
|
23
|
+
traceParsing: (flags.verbose ?? false) || (flags.traceParsing ?? false),
|
|
24
|
+
withCredentials: flags.withCredentials ?? false,
|
|
25
|
+
allowContentScrolling: flags.allowContentScrolling ?? true,
|
|
26
|
+
allowCustomServerUrl: flags.customServerUrl ?? true,
|
|
27
|
+
hideNavigationButtons: !(flags.showNavigationButtons ?? false),
|
|
28
|
+
hideDownloadButton: flags.hideDownloadButton ?? false,
|
|
29
|
+
enableOperationLinks: flags.enableOperationLinks ?? false,
|
|
30
|
+
showPoweredBy: !flags.hidePoweredBy,
|
|
31
|
+
navigationType: 'path',
|
|
32
|
+
controlAddressBar: true,
|
|
33
|
+
...(flags.currentPath === undefined ? {} : { currentPath: flags.currentPath }),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=resolve-render-options.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve-render-options.js","sourceRoot":"","sources":["../../cli/resolve-render-options.ts"],"names":[],"mappings":"AAoDA;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,oBAAoB,CAAC,KAAsB;IACzD,OAAO;QACL,YAAY,EAAE,KAAK,CAAC,YAAY,IAAI,KAAK;QACzC,cAAc,EAAE,KAAK,CAAC,cAAc,IAAI,KAAK;QAC7C,WAAW,EAAE,KAAK,CAAC,WAAW,IAAI,KAAK;QACvC,SAAS,EAAE,KAAK,CAAC,SAAS,IAAI,KAAK;QACnC,iBAAiB,EAAE,KAAK,CAAC,iBAAiB,IAAI,KAAK;QACnD,GAAG,CAAC,KAAK,CAAC,gBAAgB,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,gBAAgB,EAAE,KAAK,CAAC,gBAAgB,EAAE,CAAC;QAC7F,YAAY,EAAE,CAAC,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,IAAI,KAAK,CAAC;QACvE,eAAe,EAAE,KAAK,CAAC,eAAe,IAAI,KAAK;QAC/C,qBAAqB,EAAE,KAAK,CAAC,qBAAqB,IAAI,IAAI;QAC1D,oBAAoB,EAAE,KAAK,CAAC,eAAe,IAAI,IAAI;QACnD,qBAAqB,EAAE,CAAC,CAAC,KAAK,CAAC,qBAAqB,IAAI,KAAK,CAAC;QAC9D,kBAAkB,EAAE,KAAK,CAAC,kBAAkB,IAAI,KAAK;QACrD,oBAAoB,EAAE,KAAK,CAAC,oBAAoB,IAAI,KAAK;QACzD,aAAa,EAAE,CAAC,KAAK,CAAC,aAAa;QACnC,cAAc,EAAE,MAAM;QACtB,iBAAiB,EAAE,IAAI;QACvB,GAAG,CAAC,KAAK,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,KAAK,CAAC,WAAW,EAAE,CAAC;KAC/E,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Classifies a CLI spec argument as a local file path or a remote URL.
|
|
3
|
+
*
|
|
4
|
+
* Only `http:`/`https:` URLs are treated as remote sources; anything else
|
|
5
|
+
* (including a value that isn't a valid URL at all) is treated as a local
|
|
6
|
+
* file path.
|
|
7
|
+
*/
|
|
8
|
+
export function resolveSpecSource(arg) {
|
|
9
|
+
try {
|
|
10
|
+
const url = new URL(arg);
|
|
11
|
+
if (url.protocol === 'http:' || url.protocol === 'https:') {
|
|
12
|
+
return { kind: 'url', value: arg };
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
// Not a parseable URL - fall through to treating it as a file path.
|
|
17
|
+
}
|
|
18
|
+
return { kind: 'file', value: arg };
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=resolve-spec-source.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve-spec-source.js","sourceRoot":"","sources":["../../cli/resolve-spec-source.ts"],"names":[],"mappings":"AAMA;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,GAAW;IAC3C,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAA;QACxB,IAAI,GAAG,CAAC,QAAQ,KAAK,OAAO,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;YAC1D,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,CAAA;QACpC,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,oEAAoE;IACtE,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,CAAA;AACrC,CAAC"}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { createServer as createHttpServer } from 'node:http';
|
|
2
|
+
import { readFile } from 'node:fs/promises';
|
|
3
|
+
import { dirname, extname, join, relative } from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import { WebSocketServer } from 'ws';
|
|
6
|
+
const currentDir = dirname(fileURLToPath(import.meta.url));
|
|
7
|
+
// The preview server ships inside the package's own dist/ output (dist/cli/server.js),
|
|
8
|
+
// so the already-built web-component bundle sits one directory up.
|
|
9
|
+
const DEFAULT_DIST_DIR = dirname(currentDir);
|
|
10
|
+
const DEFAULT_PREVIEW_PAGE_DIR = join(currentDir, 'preview-page');
|
|
11
|
+
const CONTENT_TYPES = {
|
|
12
|
+
'.js': 'text/javascript',
|
|
13
|
+
'.mjs': 'text/javascript',
|
|
14
|
+
'.css': 'text/css',
|
|
15
|
+
'.map': 'application/json',
|
|
16
|
+
'.wasm': 'application/wasm',
|
|
17
|
+
'.json': 'application/json',
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Resolves an `/assets/*` request path against `distDir`, returning
|
|
21
|
+
* `undefined` if the path would escape it.
|
|
22
|
+
*
|
|
23
|
+
* The web-component bundle is code-split (syntax-highlighting language
|
|
24
|
+
* grammars/themes, etc.), so the browser fetches an open-ended set of
|
|
25
|
+
* relatively-imported chunk files from `dist/` at runtime - not just the
|
|
26
|
+
* entry bundle and its stylesheet.
|
|
27
|
+
*/
|
|
28
|
+
function resolveDistAsset(distDir, requestPath) {
|
|
29
|
+
const candidate = join(distDir, requestPath);
|
|
30
|
+
if (relative(distDir, candidate).startsWith('..')) {
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
return candidate;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Starts the CLI's local preview server: a minimal static file server for the
|
|
37
|
+
* preview page and the package's own built web-component assets, plus a
|
|
38
|
+
* WebSocket channel used to tell the page to reload when the watched spec
|
|
39
|
+
* file changes.
|
|
40
|
+
*/
|
|
41
|
+
export async function startPreviewServer(options) {
|
|
42
|
+
const distDir = options.distDir ?? DEFAULT_DIST_DIR;
|
|
43
|
+
const previewPageDir = options.previewPageDir ?? DEFAULT_PREVIEW_PAGE_DIR;
|
|
44
|
+
const server = createHttpServer((req, res) => {
|
|
45
|
+
void handleRequest(req.url, options, distDir, previewPageDir).then(({ status, body, contentType }) => {
|
|
46
|
+
res.writeHead(status, contentType ? { 'content-type': contentType } : undefined);
|
|
47
|
+
res.end(body);
|
|
48
|
+
}).catch((error) => {
|
|
49
|
+
res.writeHead(500, { 'content-type': 'text/plain' });
|
|
50
|
+
res.end(`Internal server error: ${error instanceof Error ? error.message : String(error)}`);
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
const wss = new WebSocketServer({ server });
|
|
54
|
+
// Without an 'error' listener, a failed listen() (e.g. EADDRINUSE from a
|
|
55
|
+
// TOCTOU race against find-open-port.ts's earlier probe) throws and crashes
|
|
56
|
+
// the process instead of rejecting cleanly through the CLI's own error path.
|
|
57
|
+
// `ws`'s WebSocketServer re-emits the underlying http.Server's 'error' event
|
|
58
|
+
// on itself, so the listener has to guard `wss`, not just `server` - an
|
|
59
|
+
// unhandled 'error' on the WebSocketServer instance crashes just the same.
|
|
60
|
+
await new Promise((resolve, reject) => {
|
|
61
|
+
const onListenError = (error) => reject(error);
|
|
62
|
+
server.once('error', onListenError);
|
|
63
|
+
wss.once('error', onListenError);
|
|
64
|
+
server.listen(options.port, () => {
|
|
65
|
+
server.off('error', onListenError);
|
|
66
|
+
wss.off('error', onListenError);
|
|
67
|
+
resolve();
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
// A runtime error after startup (e.g. a transient socket error) should be
|
|
71
|
+
// logged, not left to crash the process as an unhandled 'error' event.
|
|
72
|
+
server.on('error', (error) => {
|
|
73
|
+
console.error(`Preview server error: ${error instanceof Error ? error.message : String(error)}`);
|
|
74
|
+
});
|
|
75
|
+
wss.on('error', (error) => {
|
|
76
|
+
console.error(`Preview server error: ${error instanceof Error ? error.message : String(error)}`);
|
|
77
|
+
});
|
|
78
|
+
const address = server.address();
|
|
79
|
+
// `address()` returns a string for a Unix socket/pipe, never the case here
|
|
80
|
+
// since we always listen on a numeric port - but guard rather than assume.
|
|
81
|
+
const port = typeof address === 'object' && address !== null ? address.port : options.port;
|
|
82
|
+
return {
|
|
83
|
+
server,
|
|
84
|
+
port,
|
|
85
|
+
broadcastReload: () => {
|
|
86
|
+
const message = JSON.stringify({ type: 'reload' });
|
|
87
|
+
for (const client of wss.clients) {
|
|
88
|
+
if (client.readyState === client.OPEN) {
|
|
89
|
+
client.send(message);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
close: () => new Promise((resolve, reject) => {
|
|
94
|
+
// wss.close()/server.close() only invoke their callback once every
|
|
95
|
+
// connection has ended on its own - with a preview tab left open,
|
|
96
|
+
// that never happens. Force-terminate everything so shutdown is prompt
|
|
97
|
+
// regardless of what's still connected.
|
|
98
|
+
for (const client of wss.clients) {
|
|
99
|
+
client.terminate();
|
|
100
|
+
}
|
|
101
|
+
server.closeAllConnections();
|
|
102
|
+
wss.close(() => {
|
|
103
|
+
server.close((error) => error ? reject(error) : resolve());
|
|
104
|
+
});
|
|
105
|
+
}),
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
async function handleRequest(url, options, distDir, previewPageDir) {
|
|
109
|
+
if (url === '/spec') {
|
|
110
|
+
return { status: 200, body: options.getSpecText(), contentType: 'text/plain; charset=utf-8' };
|
|
111
|
+
}
|
|
112
|
+
if (url === '/config') {
|
|
113
|
+
return { status: 200, body: JSON.stringify(options.config), contentType: 'application/json' };
|
|
114
|
+
}
|
|
115
|
+
if (url === '/' || url === '/index.html') {
|
|
116
|
+
const body = await readFile(join(previewPageDir, 'index.html'), 'utf-8');
|
|
117
|
+
return { status: 200, body, contentType: 'text/html; charset=utf-8' };
|
|
118
|
+
}
|
|
119
|
+
if (url === '/client.js') {
|
|
120
|
+
const body = await readFile(join(previewPageDir, 'client.js'));
|
|
121
|
+
return { status: 200, body, contentType: 'text/javascript' };
|
|
122
|
+
}
|
|
123
|
+
if (url?.startsWith('/assets/')) {
|
|
124
|
+
const assetPath = resolveDistAsset(distDir, url.slice('/assets/'.length));
|
|
125
|
+
if (assetPath) {
|
|
126
|
+
try {
|
|
127
|
+
const body = await readFile(assetPath);
|
|
128
|
+
return { status: 200, body, contentType: CONTENT_TYPES[extname(assetPath)] ?? 'application/octet-stream' };
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
// Fall through to 404 below - e.g. the file doesn't exist.
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return { status: 404, body: 'Not found', contentType: 'text/plain' };
|
|
136
|
+
}
|
|
137
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../cli/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
|
+
import { resolveSpecSource } from './resolve-spec-source.js';
|
|
4
|
+
/**
|
|
5
|
+
* Reads a spec's text from either a local file or a remote URL.
|
|
6
|
+
*
|
|
7
|
+
* Local files are watchable for live-reload; remote URLs are fetched once
|
|
8
|
+
* and are not watched (there is no local file to observe for changes).
|
|
9
|
+
*/
|
|
10
|
+
export async function loadSpecSource(arg) {
|
|
11
|
+
const source = resolveSpecSource(arg);
|
|
12
|
+
if (source.kind === 'file') {
|
|
13
|
+
const watchPath = resolve(source.value);
|
|
14
|
+
const text = await readFile(watchPath, 'utf-8');
|
|
15
|
+
return { text, watch: true, watchPath };
|
|
16
|
+
}
|
|
17
|
+
const response = await fetch(source.value);
|
|
18
|
+
if (!response.ok) {
|
|
19
|
+
throw new Error(`Failed to fetch spec from ${source.value}: ${response.status} ${response.statusText}`);
|
|
20
|
+
}
|
|
21
|
+
return { text: await response.text(), watch: false };
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=spec-source.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spec-source.js","sourceRoot":"","sources":["../../cli/spec-source.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAC3C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAA;AAU5D;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,GAAW;IAC9C,MAAM,MAAM,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAA;IAErC,IAAI,MAAM,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QAC3B,MAAM,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;QACvC,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC,CAAA;QAE/C,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,CAAA;IACzC,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;IAE1C,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,6BAA6B,MAAM,CAAC,KAAK,KAAK,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAA;IACzG,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAA;AACtD,CAAC"}
|
package/dist/cli/ui.js
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import pc from 'picocolors';
|
|
2
|
+
const BOX_TITLE = 'Kong Spec Renderer - Preview';
|
|
3
|
+
// Caps the box at a width that fits comfortably in a typical terminal - a
|
|
4
|
+
// long spec path/URL wraps onto continuation lines instead of pushing the
|
|
5
|
+
// box wider than the terminal, which breaks the border rendering.
|
|
6
|
+
const MAX_CONTENT_WIDTH = 96;
|
|
7
|
+
// eslint-disable-next-line no-control-regex -- matches ANSI SGR escape codes, which are control characters by definition
|
|
8
|
+
const ANSI_PATTERN = /\x1B\[[0-9;]*m/g;
|
|
9
|
+
/** Visible length of a string, ignoring ANSI color escape codes. */
|
|
10
|
+
export function visibleLength(text) {
|
|
11
|
+
return text.replace(ANSI_PATTERN, '').length;
|
|
12
|
+
}
|
|
13
|
+
/** Strips ANSI color escape codes from a string. */
|
|
14
|
+
function stripAnsi(text) {
|
|
15
|
+
return text.replace(ANSI_PATTERN, '');
|
|
16
|
+
}
|
|
17
|
+
/** Hard-wraps plain text into chunks of at most `width` characters. */
|
|
18
|
+
function wrapPlain(text, width) {
|
|
19
|
+
if (text.length <= width) {
|
|
20
|
+
return [text];
|
|
21
|
+
}
|
|
22
|
+
const chunks = [];
|
|
23
|
+
for (let i = 0; i < text.length; i += width) {
|
|
24
|
+
chunks.push(text.slice(i, i + width));
|
|
25
|
+
}
|
|
26
|
+
return chunks;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Builds the lines of a bordered summary box (spec source, URL, live-reload
|
|
30
|
+
* status), aligned by visible length.
|
|
31
|
+
*
|
|
32
|
+
* `value` may contain ANSI color codes - widths are computed from visible
|
|
33
|
+
* length so colored values don't throw off the box's alignment. A value
|
|
34
|
+
* longer than fits within `maxContentWidth` wraps onto continuation lines;
|
|
35
|
+
* since wrapping a colored value risks splitting mid-escape-sequence, an
|
|
36
|
+
* over-long value wraps as plain text instead (long values are spec paths/
|
|
37
|
+
* URLs, which aren't colored today anyway). Split out from
|
|
38
|
+
* `printPreviewBanner` so the alignment math is unit-testable without
|
|
39
|
+
* capturing console output or mocking terminal width.
|
|
40
|
+
*/
|
|
41
|
+
export function buildBannerLines(rows, maxContentWidth = MAX_CONTENT_WIDTH) {
|
|
42
|
+
const labelWidth = Math.max(...rows.map((row) => row.label.length));
|
|
43
|
+
const valueWidth = Math.max(20, maxContentWidth - labelWidth - 2);
|
|
44
|
+
const wrappedRows = rows.map((row) => ({
|
|
45
|
+
label: row.label,
|
|
46
|
+
valueLines: visibleLength(row.value) <= valueWidth
|
|
47
|
+
? [row.value]
|
|
48
|
+
: wrapPlain(stripAnsi(row.value), valueWidth),
|
|
49
|
+
}));
|
|
50
|
+
const contentWidth = Math.max(BOX_TITLE.length, ...wrappedRows.flatMap((row) => row.valueLines.map((line) => labelWidth + 2 + visibleLength(line))));
|
|
51
|
+
const horizontal = '─'.repeat(contentWidth + 2);
|
|
52
|
+
const lines = [
|
|
53
|
+
pc.cyan(`┌${horizontal}┐`),
|
|
54
|
+
`${pc.cyan('│')} ${pc.bold(BOX_TITLE.padEnd(contentWidth))} ${pc.cyan('│')}`,
|
|
55
|
+
pc.cyan(`├${horizontal}┤`),
|
|
56
|
+
];
|
|
57
|
+
for (const row of wrappedRows) {
|
|
58
|
+
row.valueLines.forEach((line, index) => {
|
|
59
|
+
const label = index === 0 ? row.label.padEnd(labelWidth) : ' '.repeat(labelWidth);
|
|
60
|
+
const padding = ' '.repeat(contentWidth - labelWidth - 2 - visibleLength(line));
|
|
61
|
+
lines.push(`${pc.cyan('│')} ${pc.dim(label)} ${line}${padding} ${pc.cyan('│')}`);
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
lines.push(pc.cyan(`└${horizontal}┘`));
|
|
65
|
+
return lines;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* The box's content width, capped to the actual terminal width when known
|
|
69
|
+
* (interactive terminals report `process.stdout.columns`; piped/non-TTY
|
|
70
|
+
* output does not, so `MAX_CONTENT_WIDTH` is used as a sane default).
|
|
71
|
+
*/
|
|
72
|
+
function terminalAwareMaxWidth() {
|
|
73
|
+
const terminalWidth = process.stdout.columns;
|
|
74
|
+
if (!terminalWidth) {
|
|
75
|
+
return MAX_CONTENT_WIDTH;
|
|
76
|
+
}
|
|
77
|
+
// Leave room for the box's own border/padding characters (`│ ` + ` │`).
|
|
78
|
+
return Math.max(20, Math.min(MAX_CONTENT_WIDTH, terminalWidth - 4));
|
|
79
|
+
}
|
|
80
|
+
/** Prints a bordered summary box for the running preview server. */
|
|
81
|
+
export function printPreviewBanner(rows) {
|
|
82
|
+
for (const line of buildBannerLines(rows, terminalAwareMaxWidth())) {
|
|
83
|
+
console.log(line);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
export const success = (message) => console.log(`${pc.green('✔')} ${message}`);
|
|
87
|
+
export const info = (message) => console.log(`${pc.cyan('i')} ${message}`);
|
|
88
|
+
export const warn = (message) => console.log(`${pc.yellow('⚠')} ${pc.yellow(message)}`);
|
|
89
|
+
export const error = (message) => console.error(`${pc.red('✖')} ${pc.red(message)}`);
|
|
90
|
+
//# sourceMappingURL=ui.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui.js","sourceRoot":"","sources":["../../cli/ui.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kong/spec-renderer",
|
|
3
|
-
"version": "1.111.
|
|
3
|
+
"version": "1.111.3-pr.942.0eceead.0",
|
|
4
4
|
"description": "Kong's open-source spec renderer",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "./dist/kong-spec-renderer.cjs",
|
|
8
8
|
"module": "./dist/kong-spec-renderer.es.js",
|
|
9
|
+
"bin": {
|
|
10
|
+
"kong-spec-renderer": "./dist/cli/index.js"
|
|
11
|
+
},
|
|
9
12
|
"files": [
|
|
10
13
|
"dist"
|
|
11
14
|
],
|
|
@@ -29,26 +32,6 @@
|
|
|
29
32
|
"publishConfig": {
|
|
30
33
|
"access": "public"
|
|
31
34
|
},
|
|
32
|
-
"scripts": {
|
|
33
|
-
"dev": "cross-env USE_SANDBOX=true vite",
|
|
34
|
-
"build": "pnpm run typecheck && pnpm run build:package && pnpm run build:webcomponent && pnpm run build:types && pnpm run build:aliases",
|
|
35
|
-
"build:package": "vite build -m production",
|
|
36
|
-
"build:webcomponent": "cross-env VITE_AS_WEB_COMPONENT='true' vite build -m production",
|
|
37
|
-
"build:types": "vue-tsc -p './tsconfig.build.json' --emitDeclarationOnly",
|
|
38
|
-
"build:aliases": "tsc-alias -p './tsconfig.build.json'",
|
|
39
|
-
"build:analyzer": "BUILD_VISUALIZER='true' vite build -m production",
|
|
40
|
-
"build:sandbox": "cross-env USE_SANDBOX=true vite build -m production",
|
|
41
|
-
"preview": "pnpm run build:sandbox && cross-env USE_SANDBOX=true vite preview",
|
|
42
|
-
"typecheck": "vue-tsc -p './tsconfig.build.json' --noEmit",
|
|
43
|
-
"stylelint": "stylelint --allow-empty-input './src/**/*.{css,scss,vue}'",
|
|
44
|
-
"stylelint:fix": "stylelint --allow-empty-input './src/**/*.{css,scss,sass,vue}' --fix",
|
|
45
|
-
"lint": "eslint",
|
|
46
|
-
"lint:fix": "eslint --fix",
|
|
47
|
-
"test": "cross-env FORCE_COLOR=1 vitest run",
|
|
48
|
-
"test:open": "cross-env FORCE_COLOR=1 vitest --ui",
|
|
49
|
-
"semantic-release": "semantic-release",
|
|
50
|
-
"commit": "cz"
|
|
51
|
-
},
|
|
52
35
|
"peerDependencies": {
|
|
53
36
|
"vue": ">= 3.3.13 < 4"
|
|
54
37
|
},
|
|
@@ -65,13 +48,18 @@
|
|
|
65
48
|
"@stoplight/yaml": "^4.3.0",
|
|
66
49
|
"@vueuse/core": "^14.3.0",
|
|
67
50
|
"allof-merge": "^0.6.8",
|
|
51
|
+
"chokidar": "^5.0.0",
|
|
52
|
+
"commander": "^15.0.0",
|
|
68
53
|
"flatted": "^3.4.2",
|
|
69
54
|
"form-urlencoded": "^6.1.7",
|
|
70
55
|
"httpsnippet": "^3.0.10",
|
|
71
56
|
"lodash-es": "^4.18.1",
|
|
72
57
|
"markdown-it": "^14.3.0",
|
|
58
|
+
"open": "^11.0.0",
|
|
59
|
+
"picocolors": "^1.1.1",
|
|
73
60
|
"sanitize-html": "^2.17.6",
|
|
74
|
-
"shiki": "^3.23.0"
|
|
61
|
+
"shiki": "^3.23.0",
|
|
62
|
+
"ws": "^8.21.1"
|
|
75
63
|
},
|
|
76
64
|
"resolutions": {
|
|
77
65
|
"openapi3-ts": "4.6.0"
|
|
@@ -93,6 +81,7 @@
|
|
|
93
81
|
"@types/markdown-it": "^14.1.2",
|
|
94
82
|
"@types/node": "^24.13.3",
|
|
95
83
|
"@types/sanitize-html": "^2.16.1",
|
|
84
|
+
"@types/ws": "^8.18.1",
|
|
96
85
|
"@vitejs/plugin-vue": "^6.0.8",
|
|
97
86
|
"@vitest/ui": "^3.2.7",
|
|
98
87
|
"@vue/test-utils": "^2.4.11",
|
|
@@ -130,62 +119,6 @@
|
|
|
130
119
|
"vue-router": "^4.6.4",
|
|
131
120
|
"vue-tsc": "^3.3.7"
|
|
132
121
|
},
|
|
133
|
-
"pnpm": {
|
|
134
|
-
"onlyBuiltDependencies": [
|
|
135
|
-
"@evilmartians/lefthook",
|
|
136
|
-
"@parcel/watcher",
|
|
137
|
-
"esbuild",
|
|
138
|
-
"vue-demi"
|
|
139
|
-
],
|
|
140
|
-
"overrides": {
|
|
141
|
-
"openapi3-ts": "4.6.0",
|
|
142
|
-
"jsonpath-plus@<10.3.0": ">=10.4.0",
|
|
143
|
-
"elliptic@<=6.6.0": ">=6.6.1",
|
|
144
|
-
"@babel/helpers@<8.0.0": ">=8.0.0",
|
|
145
|
-
"cross-spawn@>=7.0.0 <7.0.5": ">=7.0.6",
|
|
146
|
-
"brace-expansion@>=1.0.0 <=1.1.11": ">=2.1.1",
|
|
147
|
-
"brace-expansion@>=2.0.0 <=2.0.1": ">=2.0.2",
|
|
148
|
-
"brace-expansion@<=5.0.7": ">=5.0.8",
|
|
149
|
-
"pbkdf2@<=3.1.2": ">=3.1.6",
|
|
150
|
-
"sha.js@<=2.4.11": ">=2.4.12",
|
|
151
|
-
"cipher-base@<=1.0.4": ">=1.0.7",
|
|
152
|
-
"glob@>=10.2.0 <10.5.0": ">=13.0.6",
|
|
153
|
-
"diff@>=4.0.0 <4.0.4": ">=4.0.4",
|
|
154
|
-
"@isaacs/brace-expansion@<=5.0.0": ">=5.0.1",
|
|
155
|
-
"mdast-util-to-hast@>=13.0.0 <13.2.1": ">=13.2.1",
|
|
156
|
-
"qs@>=6.7.0 <=6.15.1": ">=6.15.3",
|
|
157
|
-
"bn.js@>=5.0.0 <5.2.3": ">=5.2.5",
|
|
158
|
-
"bn.js@<4.12.3": ">=5.2.5",
|
|
159
|
-
"rollup@>=4.0.0 <4.59.0": ">=4.62.2",
|
|
160
|
-
"minimatch@<10.2.3": ">=10.2.5",
|
|
161
|
-
"ajv@<6.14.0": "^6.15.0",
|
|
162
|
-
"immutable@>=5.0.0 <5.1.8": ">=5.1.9",
|
|
163
|
-
"flatted@<=3.4.1": ">=3.4.2",
|
|
164
|
-
"undici@<6.24.0": ">=8.5.0",
|
|
165
|
-
"handlebars@>=4.0.0 <4.7.9": ">=4.7.9",
|
|
166
|
-
"picomatch@<2.3.2": ">=4.0.5",
|
|
167
|
-
"lodash-es@<=4.17.23": ">=4.18.0",
|
|
168
|
-
"lodash@<=4.17.23": ">=4.18.0",
|
|
169
|
-
"yaml@>=2.0.0 <2.8.3": ">=2.9.0",
|
|
170
|
-
"fast-uri@<=3.1.1": ">=3.1.4",
|
|
171
|
-
"fast-uri@>=4.0.0 <=4.1.0": ">=4.1.1",
|
|
172
|
-
"uuid@<11.1.1": ">=11.1.1",
|
|
173
|
-
"vitest@<3.2.6": ">=3.2.7",
|
|
174
|
-
"js-cookie@<=3.0.5": ">=3.0.8",
|
|
175
|
-
"tmp@<0.2.6": ">=0.2.7",
|
|
176
|
-
"esbuild@>=0.27.3 <0.28.1": ">=0.28.1",
|
|
177
|
-
"sanitize-html@=2.17.3": ">=2.17.6",
|
|
178
|
-
"ws@>=8.0.0 <8.21.0": ">=8.21.1",
|
|
179
|
-
"form-data@>=4.0.0 <4.0.6": ">=4.0.6",
|
|
180
|
-
"vite@>=7.0.0 <=7.3.4": ">=7.3.6",
|
|
181
|
-
"@babel/core@<8.0.0": ">=8.0.1",
|
|
182
|
-
"markdown-it@<=14.1.1": ">=14.2.0",
|
|
183
|
-
"linkify-it@<=5.0.0": ">=5.0.2",
|
|
184
|
-
"js-yaml@>=4.0.0 <=4.1.1": ">=4.3.0",
|
|
185
|
-
"js-yaml@>=5.0.0 <=5.2.1": ">=5.2.2",
|
|
186
|
-
"undici@>=7.0.0 <7.28.0": ">=7.28.0"
|
|
187
|
-
}
|
|
188
|
-
},
|
|
189
122
|
"repository": {
|
|
190
123
|
"type": "git",
|
|
191
124
|
"url": "git+https://github.com/Kong/spec-renderer.git"
|
|
@@ -252,5 +185,26 @@
|
|
|
252
185
|
"jiraAppend": "]"
|
|
253
186
|
}
|
|
254
187
|
},
|
|
255
|
-
"
|
|
256
|
-
|
|
188
|
+
"scripts": {
|
|
189
|
+
"dev": "cross-env USE_SANDBOX=true vite",
|
|
190
|
+
"build": "pnpm run typecheck && pnpm run build:package && pnpm run build:webcomponent && pnpm run build:types && pnpm run build:aliases && pnpm run build:cli",
|
|
191
|
+
"build:package": "vite build -m production",
|
|
192
|
+
"build:webcomponent": "cross-env VITE_AS_WEB_COMPONENT='true' vite build -m production",
|
|
193
|
+
"build:types": "vue-tsc -p './tsconfig.build.json' --emitDeclarationOnly",
|
|
194
|
+
"build:aliases": "tsc-alias -p './tsconfig.build.json'",
|
|
195
|
+
"build:cli": "tsc -p './tsconfig.cli.build.json' && node ./scripts/build-cli-assets.js",
|
|
196
|
+
"build:analyzer": "BUILD_VISUALIZER='true' vite build -m production",
|
|
197
|
+
"build:sandbox": "cross-env USE_SANDBOX=true vite build -m production",
|
|
198
|
+
"preview": "pnpm run build:sandbox && cross-env USE_SANDBOX=true vite preview",
|
|
199
|
+
"typecheck": "vue-tsc -p './tsconfig.build.json' --noEmit && pnpm run typecheck:cli",
|
|
200
|
+
"typecheck:cli": "tsc -p './tsconfig.cli.json' --noEmit",
|
|
201
|
+
"stylelint": "stylelint --allow-empty-input './src/**/*.{css,scss,vue}'",
|
|
202
|
+
"stylelint:fix": "stylelint --allow-empty-input './src/**/*.{css,scss,sass,vue}' --fix",
|
|
203
|
+
"lint": "eslint",
|
|
204
|
+
"lint:fix": "eslint --fix",
|
|
205
|
+
"test": "cross-env FORCE_COLOR=1 vitest run",
|
|
206
|
+
"test:open": "cross-env FORCE_COLOR=1 vitest --ui",
|
|
207
|
+
"semantic-release": "semantic-release",
|
|
208
|
+
"commit": "cz"
|
|
209
|
+
}
|
|
210
|
+
}
|