Skip to content

Commit

Permalink
Better error reporting
Browse files Browse the repository at this point in the history
  • Loading branch information
chancancode committed Jun 26, 2021
1 parent 04c4295 commit d0634f1
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 14 deletions.
20 changes: 20 additions & 0 deletions src/bin/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,26 @@ async function main() {
}

main().catch(error => {
if (typeof error === 'string') {
github.setOutput('error', error);
} else if ('message' in error && typeof error.message === 'string') {
if ('stack' in error && typeof error.stack === 'string') {
if (error.stack.includes(error.message)) {
github.setOutput('error', error.stack);
} else {
github.setOutput('error', error.message + '\n' + error.stack);
}
} else {
github.setOutput('error', error.message);
}
} else {
try {
github.setOutput('error', JSON.stringify(error));
} catch {
// ignore
}
}

console.error(error);
process.exit(1);
});
102 changes: 88 additions & 14 deletions src/lib/walker.ts
Original file line number Diff line number Diff line change
@@ -1,41 +1,115 @@
import { Root } from 'mdast';
import { Heading, Root } from 'mdast';
import markdown from 'remark-parse';
import stringify from 'remark-stringify';
import { Option, assert } from 'ts-std';
import unified from 'unified';
import { Node, Parent } from 'unist';
import { VFile } from 'vfile';


type Handler<Options> = (this: Walker<Options>, node: Node) => Option<Node> | Promise<Option<Node>>;

function isParent(node: Node): node is Parent {
return Array.isArray(node.children);
}

const Printer = unified().use(markdown).use(stringify);

export default class Walker<Options> {
private lastNode: Option<Node> = null;
private lastHeading: Option<Heading> = null;

constructor(protected options: Options, protected file: VFile) {}

[key: string]: unknown;

async walk(root: Node): Promise<Root> {
assert(root.type === 'root', `Cannot walk \`${root.type}\` (must be \`root\`)`);

let result = await this.handle(root);
try {
this.lastNode = null;
this.lastHeading = null;

if (Array.isArray(result)) {
assert(result.length === 1, 'Must return a single root node');
result = result[0];
}
let result = await this.handle(root);

if (result) {
assert(result.type === 'root', 'Must return a root');
return result as Root;
} else {
return {
type: 'root',
children: []
};
if (Array.isArray(result)) {
assert(result.length === 1, 'Must return a single root node');
result = result[0];
}

if (result) {
assert(result.type === 'root', 'Must return a root');
return result as Root;
} else {
return {
type: 'root',
children: []
};
}
} catch (error) {
let message: string = 'Encounted an error';

if (this.file.path) {
message += ` while processing ${this.file.path}`;
}

if (this.lastNode?.position) {
let { line, column } = this.lastNode.position.start;
message += ` at L${line}:C${column}`;
}

if (this.lastHeading) {
try {
let heading = Printer.stringify(this.lastHeading);
message += ` (under the section "${heading}")`;
} catch {
// ignore
}
}

if (typeof error === 'string') {
message += `.\nReason:\n${error}`;
} else if ('message' in error && typeof error.message === 'string') {
if ('stack' in error && typeof error.stack === 'string') {
if (error.stack.includes(error.message)) {
message += `.\nReason:\n${error.stack}`;
} else {
message += `.\nReason:\n${error.message}\n${error.stack}`;
}
} else {
message += `.\nReason:\n${error.message}`;
}
}

let reason: Error | string;

if ('stack' in error && typeof error.stack === 'string') {
reason = new Error(message);

if (error.stack.includes(error.message)) {
reason.stack = error.stack.replace(error.message, message);
} else {
reason.stack = error.stack;
}
} else {
reason = message;
}

// upstream type for reason is wrong: should be Error | string
this.file.fail(reason as string, this.lastNode?.position);
} finally {
this.lastNode = null;
this.lastHeading = null;
}
}

protected async handle(node: Node): Promise<Option<Node> | Node[]> {
this.lastNode = node;

if (node.type === 'heading') {
this.lastHeading = node as Heading;
}

let maybeHandler = this[node.type];

if (typeof maybeHandler === 'function') {
Expand Down

0 comments on commit d0634f1

Please sign in to comment.