Skip to content

Commit

Permalink
Print diagnostic errors more gracefully to CLI
Browse files Browse the repository at this point in the history
  • Loading branch information
kevinpschaaf committed Dec 16, 2022
1 parent a4399d1 commit 8d7b0e9
Showing 1 changed file with 70 additions and 65 deletions.
135 changes: 70 additions & 65 deletions packages/labs/cli/src/lib/generate/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,75 +66,80 @@ export const run = async (
},
console: Console
) => {
for (const packageRoot of packages) {
// Ensure separators in input paths are normalized and resolved to absolute
const root = path.normalize(path.resolve(packageRoot)) as AbsolutePath;
const out = path.normalize(path.resolve(outDir)) as AbsolutePath;
const analyzer = createPackageAnalyzer(root, {exclude});
const pkg = analyzer.getPackage();
if (!pkg.packageJson.name) {
throw new Error(
`Package at '${packageRoot}' did not have a name in package.json. The 'gen' command requires that packages have a name.`
);
}
const generatorReferences = [];
for (const name of (frameworkNames ?? []) as FrameworkName[]) {
const framework = frameworkCommands[name];
if (framework == null) {
throw new Error(`No generator exists for framework '${framework}'`);
try {
for (const packageRoot of packages) {
// Ensure separators in input paths are normalized and resolved to absolute
const root = path.normalize(path.resolve(packageRoot)) as AbsolutePath;
const out = path.normalize(path.resolve(outDir)) as AbsolutePath;
const analyzer = createPackageAnalyzer(root, {exclude});
const pkg = analyzer.getPackage();
if (!pkg.packageJson.name) {
throw new Error(
`Package at '${packageRoot}' did not have a name in package.json. The 'gen' command requires that packages have a name.`
);
}
generatorReferences.push(framework);
}
if (manifest) {
generatorReferences.push(manifestCommand);
}
// Optimistically try to import all generators in parallel.
// If any aren't installed we need to ask for permission to install it
// below, but in the common happy case this will do all the loading work.
await Promise.all(
generatorReferences.map(async (ref) => {
const specifier = cli.resolveImportForReference(ref);
if (specifier != null) {
await import(specifier);
const generatorReferences = [];
for (const name of (frameworkNames ?? []) as FrameworkName[]) {
const framework = frameworkCommands[name];
if (framework == null) {
throw new Error(`No generator exists for framework '${framework}'`);
}
generatorReferences.push(framework);
}
if (manifest) {
generatorReferences.push(manifestCommand);
}
// Optimistically try to import all generators in parallel.
// If any aren't installed we need to ask for permission to install it
// below, but in the common happy case this will do all the loading work.
await Promise.all(
generatorReferences.map(async (ref) => {
const specifier = cli.resolveImportForReference(ref);
if (specifier != null) {
await import(specifier);
}
})
);
// Now go through one by one and install any as necessary.
// This must be one by one in case we need to ask for permission.
const generators: GenerateCommand[] = [];
for (const reference of generatorReferences) {
const resolved = await cli.resolveCommandAndMaybeInstallNeededDeps(
reference
);
if (resolved == null) {
throw new Error(`Could not load generator for ${reference.name}`);
}
})
);
// Now go through one by one and install any as necessary.
// This must be one by one in case we need to ask for permission.
const generators: GenerateCommand[] = [];
for (const reference of generatorReferences) {
const resolved = await cli.resolveCommandAndMaybeInstallNeededDeps(
reference
generators.push(resolved as unknown as GenerateCommand);
}
const options = {
package: pkg,
};
const results = await Promise.allSettled(
generators.map(async (generator) => {
// TODO(kschaaf): Add try/catches around each of these operations and
// throw more contextural errors
await writeFileTree(out, await generator.generate(options, console));
})
);
if (resolved == null) {
throw new Error(`Could not load generator for ${reference.name}`);
// `allSettled` will swallow errors, so we need to filter them out of
// the results and throw a new error up the stack describing all the errors
// that happened
const errors = results
.map((r, i) =>
r.status === 'rejected'
? `Error generating '${generators[i].name}' wrapper for package '${packageRoot}': ` +
(r.reason as Error).stack ?? r.reason
: ''
)
.filter((e) => e)
.join('\n');
if (errors.length > 0) {
throw new Error(errors);
}
generators.push(resolved as unknown as GenerateCommand);
}
const options = {
package: pkg,
};
const results = await Promise.allSettled(
generators.map(async (generator) => {
// TODO(kschaaf): Add try/catches around each of these operations and
// throw more contextural errors
await writeFileTree(out, await generator.generate(options, console));
})
);
// `allSettled` will swallow errors, so we need to filter them out of
// the results and throw a new error up the stack describing all the errors
// that happened
const errors = results
.map((r, i) =>
r.status === 'rejected'
? `Error generating '${generators[i].name}' wrapper for package '${packageRoot}': ` +
(r.reason as Error).stack ?? r.reason
: ''
)
.filter((e) => e)
.join('\n');
if (errors.length > 0) {
throw new Error(errors);
}
} catch (e) {
console.error((e as Error).message ?? e);
return 1;
}
};

0 comments on commit 8d7b0e9

Please sign in to comment.