harttle/liquidjs

Exposing originalError in LiquidError

mohas opened this issue · 2 comments

Hi, in a recent project I'm using liquidjs heavily and this is one of the scenarios that I'm dealing with, I have custom tags and I need to stop render process if some rule breaking errors occur, I have a custom assert tag:

{% assert condition=.... action=... %}

Now, I need any further rendering to stop if condition is falsy also I need to inform the code that called render that what went wrong, so one very intuitive way is to throw a custom error in the assert tag

if(!Boolean(renderedCondition)) throw new AssertTagAssertionErrror('something went wrong', ErrorCodes.Foo)

and in the render:

engine.parseAndRender(template, {}).catch(e => {
   if('originalError' in e && e.originalError instanceof AssertTagAssertionErrror){
      // we know the exact scenario
   }
})

right now the parseAndRender only returns RenderError and originalError while present is protected and private and we don't have access to it in the catch block, we could write a special error code in the message and use that, but it is far from elegant, please provide a way to throw custom known Error types in filters and tags and drops, and catch and identify them when calling render function, thanks

if this is approved and you would like a PR please tell me I'm more than happy to make the changes

Could AssertTagAssertionError inherit from LiquidError instead? Like this..

import { Liquid, Tag, LiquidError } from "liquidjs";

class AssertTagAssertionError extends LiquidError {
  errorCode;

  constructor(err, errorCode, token) {
    super(err, token);
    this.errorCode = errorCode;
  }
}

class AssertTag extends Tag {
  constructor(token, remainTokens, liquid) {
    super(token, remainTokens, liquid);
    // Argument parsing omitted.
  }

  *render(ctx, emitter) {
    // Always throw, for demonstration purposes.
    throw new AssertTagAssertionError("something went wrong", 400, this.token);
  }
}

const liquid = new Liquid();
liquid.registerTag("assert", AssertTag);

liquid.parseAndRender("{% assert foo %}").catch((e) => {
  if (e instanceof AssertTagAssertionError) {
    console.error(e.message, e.errorCode);
  } else {
    throw e;
  }
});

output

something went wrong 400

yes this would be perfect