Skip to content

Commit

Permalink
feat: add global specification watcher (#220)
Browse files Browse the repository at this point in the history
Co-authored-by: Lukasz Gornicki <[email protected]>
Co-authored-by: Maciej Urbańczyk <[email protected]>
  • Loading branch information
3 people authored Feb 21, 2022
1 parent 663b260 commit 1021b6b
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 6 deletions.
18 changes: 16 additions & 2 deletions src/commands/diff.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import {
DiffOverrideFileError,
DiffOverrideJSONError,
} from '../errors/diff-error';
import { specWatcher, specWatcherParams } from '../globals';
import { watchFlag } from '../flags';

const { readFile } = fs;

Expand All @@ -36,6 +38,7 @@ export default class Diff extends Command {
char: 'o',
description: 'path to JSON file containing the override properties',
}),
watch: watchFlag
};

static args = [
Expand All @@ -59,11 +62,12 @@ export default class Diff extends Command {
const outputFormat = flags['format'];
const outputType = flags['type'];
const overrideFilePath = flags['overrides'];

const watchMode = flags['watch'];
let firstDocument: Specification, secondDocument: Specification;

try {
firstDocument = await load(firstDocumentPath);
enableWatch(watchMode, { spec: firstDocument, handler: this, handlerName: 'diff', docVersion: 'old', label: 'DIFF_OLD' });
} catch (err) {
if (err instanceof SpecificationFileNotFound) {
this.error(
Expand All @@ -79,6 +83,7 @@ export default class Diff extends Command {

try {
secondDocument = await load(secondDocumentPath);
enableWatch(watchMode, { spec: secondDocument, handler: this, handlerName: 'diff', docVersion: 'new', label: 'DIFF_NEW' });
} catch (err) {
if (err instanceof SpecificationFileNotFound) {
this.error(
Expand Down Expand Up @@ -126,7 +131,6 @@ export default class Diff extends Command {
});
}
}

outputJson(diffOutput: AsyncAPIDiff, outputType: string) {
if (outputType === 'breaking') {
this.log(JSON.stringify(diffOutput.breaking(), null, 2));
Expand Down Expand Up @@ -161,3 +165,13 @@ async function readOverrideFile(path: string): Promise<diff.OverrideObject> {
throw new DiffOverrideJSONError();
}
}
/**
* function to enable watchmode.
* The function is abstracted here, to avoid eslint cognitive complexity error.
*/
const enableWatch = (status: boolean, watcher: specWatcherParams) => {
if (status) {
specWatcher(watcher);
}
};

13 changes: 10 additions & 3 deletions src/commands/validate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,31 @@ import * as parser from '@asyncapi/parser';
import Command from '../base';
import { ValidationError } from '../errors/validation-error';
import { load } from '../models/SpecificationFile';
import { specWatcher } from '../globals';
import { watchFlag } from '../flags';

export default class Validate extends Command {
static description = 'validate asyncapi file';

static flags = {
help: flags.help({ char: 'h' })
help: flags.help({ char: 'h' }),
watch: watchFlag
}

static args = [
{ name: 'spec-file', description: 'spec path, url, or context-name', required: false },
]

async run() {
const { args } = this.parse(Validate);
const { args, flags } = this.parse(Validate); // NOSONAR
const filePath = args['spec-file'];

const specFile = await load(filePath);
const watchMode = flags['watch'];

const specFile = await load(filePath);
if (watchMode) {
specWatcher({spec: specFile, handler: this, handlerName: 'validate'});
}
try {
if (specFile.getFilePath()) {
await parser.parse(specFile.text());
Expand Down
6 changes: 6 additions & 0 deletions src/flags.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { flags } from '@oclif/command';

export const watchFlag = flags.boolean({
char: 'w',
description: 'Enable watch mode'
});
50 changes: 50 additions & 0 deletions src/globals.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import chokidar from 'chokidar';
import chalk from 'chalk';
import Command from './base';
import { Specification } from './models/SpecificationFile';

const GreenLog = chalk.hex('#00FF00');
const OrangeLog = chalk.hex('#FFA500');
const CHOKIDAR_CONFIG = {
// awaitWriteFinish: true // Used for large size specification files.

};
const WATCH_MESSAGES = {
logOnStart: (filePath: string) => console.log(GreenLog(`Watching AsyncAPI file at ${filePath}\n`)),
logOnChange: (handlerName: string) => console.log(OrangeLog(`Change detected, running ${handlerName}\n`)),
logOnAutoDisable: (docVersion: 'old' | 'new' | '' = '') => console.log(OrangeLog(`Watch mode for ${docVersion || 'AsyncAPI'} file was not enabled.`), OrangeLog('\nINFO: Watch works only with files from local file system\n'))
};

const CHOKIDAR_INSTANCE_STORE = new Map<string, boolean>();

export type specWatcherParams = {
spec: Specification,
handler: Command,
handlerName: string,
label?: string,
docVersion?: 'old' | 'new';
}

export const specWatcher = (params: specWatcherParams) => {
if (!params.spec.getFilePath()) { return WATCH_MESSAGES.logOnAutoDisable(params.docVersion); }
if (CHOKIDAR_INSTANCE_STORE.get(params.label || '_default')) { return; }

const filePath = params.spec.getFilePath() as string;
try {
WATCH_MESSAGES.logOnStart(filePath);
chokidar
.watch(filePath, CHOKIDAR_CONFIG)
.on('change', async () => {
WATCH_MESSAGES.logOnChange(params.handlerName);
try {
await params.handler.run();
} catch (err) {
await params.handler.catch(err);
}
});
CHOKIDAR_INSTANCE_STORE.set(params.label || '_default', true);
} catch (error) {
console.log(error);
}
};

1 change: 0 additions & 1 deletion test/commands/validate.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import * as path from 'path';
import { expect, test } from '@oclif/test';
import {NO_CONTEXTS_SAVED} from '../../src/errors/context-error';

import TestHelper from '../testHelper';

const testHelper = new TestHelper();
Expand Down

0 comments on commit 1021b6b

Please sign in to comment.