Add CLI flags tests
MODIFY
packages/@romejs/cli-diagnostics/DiagnosticsPrinter.ts
packages/@romejs/cli-diagnostics/DiagnosticsPrinter.ts
import {
Diagnostics,
Diagnostic,
- DiagnosticOrigin,
DiagnosticLanguage,
DiagnosticSourceType,
DiagnosticAdvice,
@@ -131,11 +130,11 @@ export default class DiagnosticsPrinter extends Error {
this.reporter = reporter;
this.flags = flags;
- this.readFile = opts.readFile === undefined
- ? readDiagnosticsFileLocal
- : opts.readFile;
+ this.readFile =
+ opts.readFile === undefined ? readDiagnosticsFileLocal : opts.readFile;
this.cwd = cwd === undefined ? createAbsoluteFilePath(process.cwd()) : cwd;
- this.processor = opts.processor === undefined
+ this.processor =
+ opts.processor === undefined
? new DiagnosticsProcessor()
: opts.processor;
@@ -197,8 +196,10 @@ export default class DiagnosticsPrinter extends Error {
}
shouldTruncate(): boolean {
- if (!this.flags.showAllDiagnostics && this.displayedCount >
- this.flags.maxDiagnostics) {
+ if (
+ !this.flags.showAllDiagnostics &&
+ this.displayedCount > this.flags.maxDiagnostics
+ ) {
return true;
} else {
return false;
@@ -253,8 +254,8 @@ export default class DiagnosticsPrinter extends Error {
}
// Match against the supplied grep pattern
- let ignored = diag.description.message.value.toLowerCase().includes(grep) ===
- false;
+ let ignored =
+ diag.description.message.value.toLowerCase().includes(grep) === false;
if (inverseGrep) {
ignored = !ignored;
}
@@ -314,8 +315,10 @@ export default class DiagnosticsPrinter extends Error {
for (const item of advice) {
if (item.type === 'frame') {
const {location} = item;
- if (location.filename !== undefined && location.sourceText ===
- undefined) {
+ if (
+ location.filename !== undefined &&
+ location.sourceText === undefined
+ ) {
deps.push({
type: 'reference',
path: this.createFilePath(location.filename),
@@ -377,18 +380,6 @@ export default class DiagnosticsPrinter extends Error {
}
}
- addDiagnostic(partialDiagnostic: Diagnostic, origin?: DiagnosticOrigin) {
- this.addDiagnostics([partialDiagnostic], origin);
- }
-
- addDiagnostics(partials: Diagnostics, origin?: DiagnosticOrigin) {
- if (partials.length === 0) {
- return;
- }
-
- this.processor.addDiagnostics(partials, origin);
- }
-
print() {
const filteredDiagnostics = this.filterDiagnostics();
this.fetchFileSources(filteredDiagnostics);
@@ -416,11 +407,12 @@ export default class DiagnosticsPrinter extends Error {
let skipFrame = false;
if (start !== undefined && end !== undefined && advice !== undefined) {
adviceLoop: for (const item of advice) {
- if (item.type === 'frame' && item.location.filename === filename &&
- equalPosition(item.location.start, start) && equalPosition(
- item.location.end,
- end,
- )) {
+ if (
+ item.type === 'frame' &&
+ item.location.filename === filename &&
+ equalPosition(item.location.start, start) &&
+ equalPosition(item.location.end, end)
+ ) {
skipFrame = true;
break;
}
@@ -443,8 +435,11 @@ export default class DiagnosticsPrinter extends Error {
mtime: expectedMtime,
} of this.getDependenciesFromDiagnostics([diag])) {
const mtime = this.fileMtimes.get(path);
- if (mtime !== undefined && expectedMtime !== undefined && mtime >
- expectedMtime) {
+ if (
+ mtime !== undefined &&
+ expectedMtime !== undefined &&
+ mtime > expectedMtime
+ ) {
outdatedFiles.add(path);
}
}
@@ -455,21 +450,19 @@ export default class DiagnosticsPrinter extends Error {
const outdatedFilesArr = Array.from(outdatedFiles, (path) => path.join());
if (outdatedFilesArr.length === 1 && outdatedFilesArr[0] === filename) {
- outdatedAdvice.push(
- {
+ outdatedAdvice.push({
type: 'log',
category: 'warn',
- message: 'This file has been changed since the diagnostic was produced and may be out of date',
- },
- );
+ message:
+ 'This file has been changed since the diagnostic was produced and may be out of date',
+ });
} else {
- outdatedAdvice.push(
- {
+ outdatedAdvice.push({
type: 'log',
category: 'warn',
- message: 'This diagnostic may be out of date as it relies on the following files that have been changed since the diagnostic was generated',
- },
- );
+ message:
+ 'This diagnostic may be out of date as it relies on the following files that have been changed since the diagnostic was generated',
+ });
outdatedAdvice.push({
type: 'list',
@@ -522,13 +515,16 @@ export default class DiagnosticsPrinter extends Error {
reporter.spacer();
reporter.info('Why are you seeing this diagnostic?');
reporter.forceSpacer();
- reporter.list(origins.map((origin) => {
+ reporter.list(
+ origins.map((origin) => {
let res = `<emphasis>${origin.category}</emphasis>`;
if (origin.message !== undefined) {
res += `: ${origin.message}`;
}
return res;
- }), {ordered: true});
+ }),
+ {ordered: true},
+ );
}
}
});
@@ -597,11 +593,15 @@ export default class DiagnosticsPrinter extends Error {
}
const pallete = banner.palettes[palleteIndex];
- stream.write(formatAnsi.bgRgb(' ', {
+ stream.write(
+ formatAnsi
+ .bgRgb(' ', {
r: pallete[0],
g: pallete[1],
b: pallete[2],
- }).repeat(times));
+ })
+ .repeat(times),
+ );
}
stream.write('\n');
}
@@ -640,8 +640,9 @@ export default class DiagnosticsPrinter extends Error {
if (this.truncatedCount > 0) {
const {maxDiagnostics} = this.flags;
reporter.warn(
- `Only <number>${maxDiagnostics}</number> errors shown, add the <emphasis>--show-all-diagnostics</emphasis> flag to view the remaining <number>${displayableProblems -
- maxDiagnostics}</number> errors`,
+ `Only <number>${maxDiagnostics}</number> errors shown, add the <emphasis>--show-all-diagnostics</emphasis> flag to view the remaining <number>${
+ displayableProblems - maxDiagnostics
+ }</number> errors`,
);
}
}

ADD
packages/@romejs/cli-flags/Parser.test.ts
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+import {test, TestHelper} from 'rome';
+import Parser from './Parser';
+import {Reporter} from '@romejs/cli-reporter';
+import {Consumer} from '@romejs/consume';
+import {catchDiagnostics} from '@romejs/diagnostics';
+import {printDiagnostics} from '@romejs/cli-diagnostics';
+
+async function testParser<T>(t: TestHelper, {
+ defineFlags,
+ args,
+ callback,
+}: {
+ defineFlags: (consumer: Consumer) => T;
+ args: Array<string>;
+ callback?: (parser: Parser<T>, flags: T) => void;
+}) {
+ const reporter = new Reporter();
+ const stream = reporter.attachCaptureStream();
+
+ const parser = new Parser(reporter, {
+ programName: 'test',
+ defineFlags,
+ }, args);
+
+ const {diagnostics} = await catchDiagnostics(async () => {
+ const flags = await parser.init();
+ t.snapshotNamed('flags', flags);
+ if (callback !== undefined) {
+ callback(parser, flags);
+ }
+ });
+
+ if (diagnostics !== undefined) {
+ printDiagnostics({
+ diagnostics,
+ suppressions: [],
+ printerOptions: {
+ reporter,
+ },
+ });
+ }
+
+ t.snapshotNamed('output', stream.read());
+
+ const helpStream = reporter.attachCaptureStream();
+ await parser.showHelp();
+ t.snapshotNamed('help', helpStream.read());
+}
+
+test('does not allow shorthands', async (t) => {
+ await testParser(t, {
+ defineFlags: () => {},
+ args: ['-f'],
+ });
+});
+
+test('does not allow camel case', async (t) => {
+ await testParser(t, {
+ defineFlags: () => {},
+ args: ['--fooBar'],
+ });
+});
+
+test('flag value equals', async (t) => {
+ await testParser(t, {
+ defineFlags: (c) => {
+ return {
+ name: c.get('name').asString(),
+ };
+ },
+ args: ['--name=sebastian'],
+ });
+});
+
+test('required flag', async (t) => {
+ await testParser(t, {
+ defineFlags: (c) => {
+ return {
+ name: c.get('name').asString(),
+ };
+ },
+ args: ['--name', 'sebastian'],
+ });
+});
+
+test('required flag omitted', async (t) => {
+ await testParser(t, {
+ defineFlags: (c) => {
+ return {
+ name: c.get('name').asString(),
+ };
+ },
+ args: [],
+ });
+});
+
+test('optional flag', async (t) => {
+ await testParser(t, {
+ defineFlags: (c) => {
+ return {
+ name: c.get('name').asStringOrVoid(),
+ };
+ },
+ args: ['--name', 'sebastian'],
+ });
+});
+
+test('optional flag omitted', async (t) => {
+ await testParser(t, {
+ defineFlags: (c) => {
+ return {
+ name: c.get('name').asStringOrVoid(),
+ };
+ },
+ args: [],
+ });
+});
+
+test('flag with description', async (t) => {
+ await testParser(t, {
+ defineFlags: (c) => {
+ return {
+ name: c.get('name', {
+ description: 'the name of the coolest person in the world',
+ }).asStringOrVoid(),
+ };
+ },
+ args: ['--name', 'sebastian'],
+ });
+});
+
+test('optional boolean flag', async (t) => {
+ await testParser(t, {
+ defineFlags: (c) => {
+ return {
+ run: c.get('run').asBooleanOrVoid(),
+ };
+ },
+ args: ['--run'],
+ });
+});
+
+test('optional boolean flag omitted', async (t) => {
+ await testParser(t, {
+ defineFlags: (c) => {
+ return {
+ run: c.get('run').asBooleanOrVoid(),
+ };
+ },
+ args: ['--run'],
+ });
+});
+
+test('required boolean flag', async (t) => {
+ await testParser(t, {
+ defineFlags: (c) => {
+ return {
+ run: c.get('run').asBoolean(),
+ };
+ },
+ args: ['--run'],
+ });
+});
+
+test('required boolean flag omitted', async (t) => {
+ await testParser(t, {
+ defineFlags: (c) => {
+ return {
+ run: c.get('run').asBoolean(),
+ };
+ },
+ args: ['--run'],
+ });
+});
+
+test('flip boolean flag', async (t) => {
+ await testParser(t, {
+ defineFlags: (c) => {
+ return {
+ run: c.get('run').asBoolean(),
+ };
+ },
+ args: ['--no-run'],
+ });
+});

MODIFY
packages/@romejs/cli-flags/Parser.ts
packages/@romejs/cli-flags/Parser.ts
@@ -661,7 +661,6 @@ export default class Parser<T> {
);
} else {
// TODO command name is not sanitized for markup
-
// TODO produce a diagnostic instead
this.reporter.error(
`Unknown command <emphasis>${this.args.join(' ')}</emphasis>. Run --help to see available commands.`,

MODIFY
packages/@romejs/cli-reporter/Reporter.ts
packages/@romejs/cli-reporter/Reporter.ts
@@ -210,6 +210,29 @@ export default class Reporter {
};
}
+ attachCaptureStream(format: ReporterStream['format'] = 'none'): {
+ read: () => string;
+ } {
+ let buff = '';
+
+ this.addStream({
+ format,
+ type: 'all',
+ columns: Reporter.DEFAULT_COLUMNS,
+ unicode: true,
+
+ write(chunk) {
+ buff += chunk;
+ },
+ });
+
+ return {
+ read() {
+ return buff;
+ },
+ };
+ }
+
static fromProcess(opts: ReporterOptions = {}): Reporter {
const reporter = new Reporter({
...opts,

Add CLI flags tests