bump-cli
Version:
The Bump CLI is used to interact with your API documentation hosted on Bump.sh by using the API of developers.bump.sh
84 lines (83 loc) • 3.29 kB
JavaScript
import { ux } from '@oclif/core';
import { Mutex } from 'async-mutex';
import { watch } from 'node:fs';
import { default as openBrowser } from 'open';
import { fileArg } from '../args.js';
import { BaseCommand } from '../base-command.js';
import { API } from '../definition.js';
import * as flagsBuilder from '../flags.js';
export default class Preview extends BaseCommand {
static args = {
file: fileArg,
};
static description = 'Create a documentation preview from the given file or URL.';
static examples = [
`$ <%= config.bin %> <%= command.id %> FILE
* Your preview is visible at: https://bump.sh/preview/45807371-9a32-48a7-b6e4-1cb7088b5b9b
`,
];
static flags = {
live: flagsBuilder.live({
description: 'Generate a preview each time you save the given file',
}),
open: flagsBuilder.open({
description: 'Open the generated preview URL in your browser',
}),
};
async run() {
const { args, flags } = await this.parse(Preview);
ux.action.start("* Let's render a preview on Bump.sh");
const currentPreview = await this.preview(args.file, flags.open);
if (flags.live) {
await this.waitForChanges(args.file, currentPreview);
}
else {
ux.action.stop();
}
}
async preview(file, open = false, currentPreview = undefined) {
const api = await API.load(file);
const [definition, references] = await api.extractDefinition();
this.d(`${file} looks like an ${api.specName} spec version ${api.version}`);
const request = {
definition,
references,
};
ux.action.status = '...in progress';
const response = currentPreview
? await this.bump.putPreview(currentPreview.id, request)
: await this.bump.postPreview(request);
if (!currentPreview) {
ux.action.status = '...done';
ux.stdout(ux.colorize('green', `Your preview is visible at: ${response.data.public_url} (Expires at ${response.data.expires_at})`));
}
if (open && response.data.public_url) {
await openBrowser(response.data.public_url);
}
return response.data;
}
async waitForChanges(file, preview) {
const mutex = new Mutex();
let currentPreview = preview;
ux.action.status = `Waiting for changes on file ${file}...`;
watch(file, async () => {
if (!mutex.isLocked()) {
const release = await mutex.acquire();
this.preview(file, false, currentPreview)
.then((preview) => {
currentPreview = preview;
ux.stdout(ux.colorize('green', ` ↳ has been updated (Expires at ${preview.expires_at})`));
ux.action.status = `Waiting for changes on file ${file}`;
})
.catch((error) => {
this.warn(error);
})
.finally(() => {
setTimeout(() => {
release();
}, 1000); // Prevent previewing faster than once per second
});
}
});
}
}