diff --git a/src/config.ts b/src/config.ts
index ebfdcf9b..cc8c5162 100644
--- a/src/config.ts
+++ b/src/config.ts
@@ -66,6 +66,11 @@ interface ResolvedConfig extends BaseConfig {
* new object.
*/
cache?: Cache;
+
+ /**
+ * A callback for internal warnings or errors (for example, when parsing invalid abbreviation)
+ */
+ warn?: (message: string, err?: Error) => void
}
export type Config = ResolvedConfig & { options: Options };
diff --git a/src/markup/snippets.ts b/src/markup/snippets.ts
index d86d04f0..2f5e94a8 100644
--- a/src/markup/snippets.ts
+++ b/src/markup/snippets.ts
@@ -15,6 +15,7 @@ import type { Config } from '../config.js';
export default function resolveSnippets(abbr: Abbreviation, config: Config): Abbreviation {
const stack: string[] = [];
const reversed = config.options['output.reverseAttributes'];
+ const { warn } = config;
const resolve = (child: AbbreviationNode): Abbreviation | null => {
const snippet = child.name && config.snippets[child.name];
@@ -26,7 +27,15 @@ export default function resolveSnippets(abbr: Abbreviation, config: Config): Abb
return null;
}
- const snippetAbbr = parse(snippet, config);
+ let snippetAbbr: Abbreviation;
+ try {
+ // User may add invlid snippet. In this case, silently bail out
+ snippetAbbr = parse(snippet, config);
+ } catch (err) {
+ warn?.(`Unable to parse "${snippet}" snippet`, err);
+ return null;
+ }
+
stack.push(snippet);
walkResolve(snippetAbbr, resolve, config);
stack.pop();
diff --git a/test/snippets.ts b/test/snippets.ts
index 6b8626f7..d024361a 100644
--- a/test/snippets.ts
+++ b/test/snippets.ts
@@ -14,4 +14,14 @@ describe('Snippets', () => {
it('XSL', () => {
Object.keys(xsl).forEach(k => ok(markup(xsl[k]), k));
});
+
+ it('Invalid snippets', () => {
+ const snippets = {
+ invalid: 'invalid snippet',
+ valid: 'button'
+ }
+
+ const result = expand('invalid+valid', { snippets })
+ equal(result, '\n')
+ });
});