|
| 1 | +# Support `@try` and `@catch` flow controls for error handling: Draft 1 |
| 2 | + |
| 3 | +*[(Issue)](https://github.com/sass/sass/issues/2619)* |
| 4 | + |
| 5 | +## Table of Contents |
| 6 | + |
| 7 | +## Background |
| 8 | + |
| 9 | +> This section is non-normative. |
| 10 | +
|
| 11 | +In many situations, particularly when writing tests, it's useful to catch error |
| 12 | +and warning messages without breaking compilation. By adding `@try` and `@catch` |
| 13 | +at-rules similar to other control-flow syntax, authors will have more control |
| 14 | +over error handling, and the ability to test for error-cases. |
| 15 | + |
| 16 | +Many large Sass projects currently use wrapper functions and mixins to catch and |
| 17 | +manage errors, with a parameter to toggle between throwing or returning the |
| 18 | +error message. But that relies on the special error handling to be built into |
| 19 | +every individual function or mixin that might error. By adding global controls, |
| 20 | +error-handling can happen either where the error is generated, or where it is |
| 21 | +defined. |
| 22 | + |
| 23 | +## Summary |
| 24 | + |
| 25 | +> This section is non-normative. |
| 26 | +
|
| 27 | +This proposal defines a pair of new at-rule directives that must be used |
| 28 | +together as a form of control. The `@try { ... } @catch { ... }` syntax captures |
| 29 | +any thrown output (error or warning messages) from inside the `@try` block, and |
| 30 | +allows the parser to continue compilation. The `@catch` block executes whenever |
| 31 | +an error or warning has been captured, allowing authors to determine how the |
| 32 | +error should be processed. |
| 33 | + |
| 34 | +```scss |
| 35 | +@try { |
| 36 | + $test: my.function('bad arg'); |
| 37 | +} @catch $error { |
| 38 | + @include true.assert-equal( |
| 39 | + $error, |
| 40 | + "'bad arg' is not a valid argument for 'function'" |
| 41 | + ); |
| 42 | +} |
| 43 | +``` |
| 44 | + |
| 45 | +## Syntax |
| 46 | + |
| 47 | +<x><pre> |
| 48 | +**TryCatchRule** ::= '@try' '{' |
| 49 | +  TryStatements |
| 50 | +  '}' '@catch' exceptionVar? '{' |
| 51 | +  CatchStatements |
| 52 | +  '}' |
| 53 | +**exceptionVar** ::= '$' Identifier |
| 54 | +</pre></x> |
| 55 | + |
| 56 | +## Semantics |
| 57 | + |
| 58 | +To execute a `TryCatchRule` `rule`: |
| 59 | + |
| 60 | +* Let `exceptions` |
| 61 | + |
| 62 | +* Execute the contents `try` of `rule`'s `TryStatements` |
| 63 | + |
| 64 | + * If an `@error` or `@warn` rule `throw` is encountered: |
| 65 | + |
| 66 | + * Let `exception` be a map with the same identifier as `exceptionVar`, |
| 67 | + a 'name' `throw`s at-rule |
| 68 | + |
| 69 | + > Currently either `@error` or `@warn` |
| 70 | +
|
| 71 | + * Let `message` be the value of the `throw`'s `expression` |
| 72 | + |
| 73 | + * If `name` is `@error`, ignore any remaining statements in `try` |
| 74 | + |
| 75 | + * Otherwise complete compilation of the `TryStatements` |
| 76 | + |
| 77 | + * If `exceptionVar` is defined |
| 78 | + |
| 79 | + * Let `exception` be a map variable with the same name as `exceptionVar`'s |
| 80 | + identifier. |
| 81 | + |
| 82 | + * Let `exception` have a key 'name' with the value of `name` |
| 83 | + |
| 84 | + * Let `exception` have a key 'messsage' with the value of `message` |
| 85 | + |
| 86 | + > assign `message` to identifier `catchMessage`... |
| 87 | +
|
| 88 | + > Execute the contents of `rule`'s `CatchStatements` with `catchMessage` and |
| 89 | + > `catchType`... |
| 90 | +
|
| 91 | + * Otherwise, ignore the remainder of the `TryCatchRule` |
| 92 | + |
0 commit comments