Skip to content

Commit 4d73911

Browse files
committed
Cleaner output approach, with snapshots
1 parent bab11ae commit 4d73911

30 files changed

+383
-291
lines changed

src/commands/config.ts

Lines changed: 23 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { Command } from 'commander';
22
import { CliOptions } from '../types/options.js';
33
import { ConfigInterface, ConfigLocal, isTests } from '@open-audio-stack/core';
44
import { CONFIG_LOCAL_TEST } from '../data/Config.js';
5-
import { withSpinner } from '../utils.js';
5+
import { output, OutputType } from '../utils.js';
66

77
const config: ConfigLocal = new ConfigLocal(isTests() ? CONFIG_LOCAL_TEST : undefined);
88
const program = new Command();
@@ -14,23 +14,17 @@ configCmd
1414
.option('-l, --log', 'Enable logging')
1515
.description('Get a config setting by key')
1616
.action((key: keyof ConfigInterface, options: CliOptions) => {
17-
return withSpinner(
18-
options,
19-
config as any,
20-
`Get config ${String(key)}`,
21-
async () => {
22-
return { key, value: config.get(key) };
23-
},
24-
(result: any, useJson: boolean) => {
25-
if (useJson) {
26-
const obj: any = {};
27-
obj[result.key] = result.value;
28-
console.log(JSON.stringify(obj, null, 2));
29-
} else {
30-
console.log(result.value);
31-
}
32-
},
33-
);
17+
{
18+
const message = `Get config ${String(key)}`;
19+
output(OutputType.START, message, options, config);
20+
try {
21+
const payload = options && options.json ? { key, value: config.get(key) } : String(config.get(key));
22+
output(OutputType.SUCCESS, payload, options, config);
23+
} catch (err: any) {
24+
output(OutputType.ERROR, err, options, config);
25+
process.exit(1);
26+
}
27+
}
3428
});
3529

3630
configCmd
@@ -39,22 +33,16 @@ configCmd
3933
.option('-l, --log', 'Enable logging')
4034
.description('Set a config setting by key and value')
4135
.action((key: keyof ConfigInterface, val: any, options: CliOptions) => {
42-
return withSpinner(
43-
options,
44-
config as any,
45-
`Set config ${String(key)}`,
46-
async () => {
36+
{
37+
const message = `Set config ${String(key)}`;
38+
output(OutputType.START, message, options, config);
39+
try {
4740
const res = config.set(key, val);
48-
return { key, value: res };
49-
},
50-
(result: any, useJson: boolean) => {
51-
if (useJson) {
52-
const obj: any = {};
53-
obj[result.key] = result.value;
54-
console.log(JSON.stringify(obj, null, 2));
55-
} else {
56-
console.log(result.value);
57-
}
58-
},
59-
);
41+
const payload = options && options.json ? { key, value: res } : String(res);
42+
output(OutputType.SUCCESS, payload, options, config);
43+
} catch (err: any) {
44+
output(OutputType.ERROR, err, options, config);
45+
process.exit(1);
46+
}
47+
}
6048
});

src/commands/create.ts

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,26 @@
11
import { Command } from 'commander';
22
import { CliOptions } from '../types/options.js';
33
import { ManagerLocal } from '@open-audio-stack/core';
4-
import { withSpinner } from '../utils.js';
4+
import { output, OutputType } from '../utils.js';
55

66
export function create(command: Command, manager: ManagerLocal) {
77
command
88
.command('create')
99
.option('-j, --json', 'Output results as json')
1010
.option('-l, --log', 'Enable logging')
1111
.description('Create a new package locally')
12-
.action(async (path: string, options: CliOptions) => {
13-
await withSpinner(
14-
options,
15-
manager,
16-
`Create package at ${path}`,
17-
async () => {
18-
const result = await manager.create();
19-
return result;
20-
},
21-
(result: any, useJson: boolean) => {
22-
if (useJson) console.log(JSON.stringify(result, null, 2));
23-
else console.log(result);
24-
},
25-
);
12+
.action(async (options: CliOptions) => {
13+
const message = `Create package`;
14+
output(OutputType.START, message, options, manager);
15+
try {
16+
const result = await manager.create();
17+
// For JSON mode return the object; for textual mode, stringify objects
18+
const payload =
19+
options && options.json ? result : typeof result === 'string' ? result : JSON.stringify(result, null, 2);
20+
output(OutputType.SUCCESS, payload, options, manager);
21+
} catch (err: any) {
22+
output(OutputType.ERROR, err, options, manager);
23+
process.exit(1);
24+
}
2625
});
2726
}

src/commands/filter.ts

Lines changed: 23 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,35 @@
11
import { Command } from 'commander';
22
import { CliOptions } from '../types/options.js';
33
import { ManagerLocal, PackageVersion } from '@open-audio-stack/core';
4-
import { formatOutput, withSpinner } from '../utils.js';
4+
import { formatOutput, output, OutputType } from '../utils.js';
55

66
export function filter(command: Command, manager: ManagerLocal) {
77
command
88
.command('filter <field> <value>')
99
.option('-j, --json', 'Output results as json')
1010
.option('-l, --log', 'Enable logging')
1111
.description('Filter the by field and matching value')
12-
.action((field: keyof PackageVersion, value: string, options: CliOptions) => {
13-
return withSpinner(
14-
options,
15-
manager,
16-
`Filter ${manager.type} by ${String(field)}=${value}`,
17-
async () => {
18-
const predicate = (pkgVersion: PackageVersion) => {
19-
const fieldVal: any = (pkgVersion as any)[field];
20-
if (Array.isArray(fieldVal)) {
21-
return fieldVal.some((v: any) => String(v).toLowerCase() === value.toLowerCase());
22-
}
23-
if (typeof fieldVal === 'string') {
24-
return fieldVal.toLowerCase().includes(value.toLowerCase());
25-
}
26-
if (fieldVal === undefined || fieldVal === null) return false;
27-
return String(fieldVal) === value;
28-
};
29-
return manager.filter(predicate);
30-
},
31-
(result: any, useJson: boolean) => {
32-
if (useJson) console.log(JSON.stringify(result, null, 2));
33-
else console.log(formatOutput(result as any));
34-
},
35-
);
12+
.action(async (field: keyof PackageVersion, value: string, options: CliOptions) => {
13+
const message = `Filter ${manager.type} by ${String(field)}=${value}`;
14+
output(OutputType.START, message, options, manager);
15+
try {
16+
const predicate = (pkgVersion: PackageVersion) => {
17+
const fieldVal: any = pkgVersion[field];
18+
if (Array.isArray(fieldVal)) {
19+
return fieldVal.some((v: any) => String(v).toLowerCase() === value.toLowerCase());
20+
}
21+
if (typeof fieldVal === 'string') {
22+
return fieldVal.toLowerCase().includes(value.toLowerCase());
23+
}
24+
if (fieldVal === undefined || fieldVal === null) return false;
25+
return String(fieldVal) === value;
26+
};
27+
const result = await manager.filter(predicate);
28+
const payload = options && options.json ? result : formatOutput(result);
29+
output(OutputType.SUCCESS, payload, options, manager);
30+
} catch (err: any) {
31+
output(OutputType.ERROR, err, options, manager);
32+
process.exit(1);
33+
}
3634
});
3735
}

src/commands/get.ts

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Command } from 'commander';
22
import { CliOptions } from '../types/options.js';
33
import { inputGetParts, ManagerLocal } from '@open-audio-stack/core';
4-
import { formatOutput, withSpinner } from '../utils.js';
4+
import { formatOutput, output, OutputType } from '../utils.js';
55

66
export function get(command: Command, manager: ManagerLocal) {
77
command
@@ -10,21 +10,20 @@ export function get(command: Command, manager: ManagerLocal) {
1010
.option('-l, --log', 'Enable logging')
1111
.description('Get package metadata from registry')
1212
.action((input: string, options: CliOptions) => {
13-
return withSpinner(
14-
options,
15-
manager,
16-
`Get package ${input}`,
17-
async () => {
18-
const [slug, version] = inputGetParts(input);
19-
const pkg = manager.getPackage(slug);
20-
if (!pkg) throw new Error(`No package found with slug: ${slug}`);
21-
return { pkg, version };
22-
},
23-
(result: any, useJson: boolean) => {
24-
const { pkg, version } = result;
25-
const versions = version ? [version] : Array.from(pkg.versions.keys());
26-
console.log(formatOutput(pkg, versions, useJson));
27-
},
28-
);
13+
const message = `Get package ${input}`;
14+
output(OutputType.START, message, options, manager);
15+
try {
16+
const [slug, version] = inputGetParts(input);
17+
const pkg = manager.getPackage(slug);
18+
if (!pkg) throw new Error(`No package found with slug: ${slug}`);
19+
const payload =
20+
options && options.json
21+
? { pkg, version }
22+
: formatOutput(pkg, version ? [version] : Array.from(pkg.versions.keys()), false);
23+
output(OutputType.SUCCESS, payload, options, manager);
24+
} catch (err: any) {
25+
output(OutputType.ERROR, err, options, manager);
26+
process.exit(1);
27+
}
2928
});
3029
}

src/commands/install.ts

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Command } from 'commander';
22
import { CliOptions } from '../types/options.js';
3-
import { inputGetParts, ManagerLocal, isTests } from '@open-audio-stack/core';
4-
import { withSpinner } from '../utils.js';
3+
import { inputGetParts, ManagerLocal } from '@open-audio-stack/core';
4+
import { output, OutputType } from '../utils.js';
55

66
export function install(command: Command, manager: ManagerLocal) {
77
command
@@ -11,19 +11,18 @@ export function install(command: Command, manager: ManagerLocal) {
1111
.description('Install a package locally by slug/version')
1212
.action(async (input: string, options: CliOptions) => {
1313
const [slug, version] = inputGetParts(input);
14-
await withSpinner(
15-
options,
16-
manager,
17-
`Install ${slug}${version ? `@${version}` : ''}`,
18-
async () => {
19-
await manager.install(slug, version);
20-
return { slug, version: version || null, installed: true, isTests: isTests() };
21-
},
22-
(result: any, useJson: boolean) => {
23-
if (useJson)
24-
console.log(JSON.stringify({ slug: result.slug, version: result.version, installed: true }, null, 2));
25-
else if (result.isTests) console.log(`Installed ${result.slug}${result.version ? `@${result.version}` : ''}`);
26-
},
27-
);
14+
const message = `Install ${slug}${version ? `@${version}` : ''}`;
15+
output(OutputType.START, message, options, manager);
16+
try {
17+
await manager.install(slug, version);
18+
const payload =
19+
options && options.json
20+
? { slug, version: version || null, installed: true }
21+
: `Installed ${slug}${version ? `@${version}` : ''}`;
22+
output(OutputType.SUCCESS, payload, options, manager);
23+
} catch (err: any) {
24+
output(OutputType.ERROR, err, options, manager);
25+
process.exit(1);
26+
}
2827
});
2928
}

src/commands/list.ts

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Command } from 'commander';
22
import { CliOptions } from '../types/options.js';
33
import { ManagerLocal } from '@open-audio-stack/core';
4-
import { formatOutput, withSpinner } from '../utils.js';
4+
import { formatOutput, output, OutputType } from '../utils.js';
55

66
interface ListOptions extends CliOptions {
77
incompatible: boolean;
@@ -17,17 +17,15 @@ export function list(command: Command, manager: ManagerLocal) {
1717
.option('-l, --log', 'Enable logging')
1818
.description('List packages')
1919
.action(async (options: ListOptions) => {
20-
await withSpinner(
21-
options,
22-
manager,
23-
`List ${manager.type}`,
24-
async () => {
25-
return manager.listPackages(options.installed, options.incompatible);
26-
},
27-
(result: any, useJson: boolean) => {
28-
if (useJson) console.log(JSON.stringify(result, null, 2));
29-
else console.log(formatOutput(result as any));
30-
},
31-
);
20+
const message = `List ${manager.type}`;
21+
output(OutputType.START, message, options, manager);
22+
try {
23+
const result = await manager.listPackages(options.installed, options.incompatible);
24+
const payload = options && options.json ? result : formatOutput(result);
25+
output(OutputType.SUCCESS, payload, options, manager);
26+
} catch (err: any) {
27+
output(OutputType.ERROR, err, options, manager);
28+
process.exit(1);
29+
}
3230
});
3331
}

src/commands/open.ts

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,23 @@
11
import { Command } from 'commander';
22
import { CliOptions } from '../types/options.js';
33
import { inputGetParts, ManagerLocal } from '@open-audio-stack/core';
4-
import { withSpinner } from '../utils.js';
4+
import { output, OutputType } from '../utils.js';
55

66
export function open(command: Command, manager: ManagerLocal) {
77
command
88
.command('open <input> [options...]')
99
.option('-l, --log', 'Enable logging')
1010
.description('Open a package by slug/version')
1111
.action(async (input: string, options: string[], cliOptions: CliOptions) => {
12-
await withSpinner(
13-
cliOptions,
14-
manager,
15-
`Open ${input}`,
16-
async () => {
17-
const [slug, version] = inputGetParts(input);
18-
await manager.open(slug, version, options);
19-
return { slug, version };
20-
},
21-
() => {
22-
// open is an action side-effect; no additional output required
23-
},
24-
);
12+
const message = `Open ${input}`;
13+
output(OutputType.START, message, cliOptions, manager);
14+
try {
15+
const [slug, version] = inputGetParts(input);
16+
await manager.open(slug, version, options);
17+
output(OutputType.SUCCESS, `Opened ${input}`, cliOptions, manager);
18+
} catch (err: any) {
19+
output(OutputType.ERROR, err, cliOptions, manager);
20+
process.exit(1);
21+
}
2522
});
2623
}

src/commands/scan.ts

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Command } from 'commander';
22
import { CliOptions } from '../types/options.js';
33
import { ManagerLocal } from '@open-audio-stack/core';
4-
import { withSpinner } from '../utils.js';
4+
import { output, OutputType } from '../utils.js';
55

66
export function scan(command: Command, manager: ManagerLocal) {
77
command
@@ -10,17 +10,16 @@ export function scan(command: Command, manager: ManagerLocal) {
1010
.option('-l, --log', 'Enable logging')
1111
.description('Scan local packages into cache')
1212
.action(async (options: CliOptions) => {
13-
await withSpinner(
14-
options,
15-
manager,
16-
`Scan ${manager.type}`,
17-
async () => {
18-
await manager.scan();
19-
return { type: manager.type, status: 'scan completed' };
20-
},
21-
(result: any, useJson: boolean) => {
22-
if (useJson) console.log(JSON.stringify({ type: result.type, status: result.status }, null, 2));
23-
},
24-
);
13+
const message = `Scan ${manager.type}`;
14+
output(OutputType.START, message, options, manager);
15+
try {
16+
await manager.scan();
17+
// pass an object for JSON output, or a string for textual output
18+
const payload = options && options.json ? { type: manager.type, status: 'scanned' } : `Scanned ${manager.type}`;
19+
output(OutputType.SUCCESS, payload, options, manager);
20+
} catch (err: any) {
21+
output(OutputType.ERROR, err, options, manager);
22+
process.exit(1);
23+
}
2524
});
2625
}

0 commit comments

Comments
 (0)