Phil Wolstenholme
Phil Wolstenholme

Reputation: 121

How to return a new instance of a class in JavaScript via Promise.resolve that can be used normally by other code

I'm trying to use this JavaScript class inside Twing 5, which is a JavaScript implementation of the Twig templating language:

class DrupalAttribute extends Map {
  constructor(it) {
    super(it);
  }

  /**
   * @param {...String|Array} args
   * @returns {DrupalAttribute}
   */
  addClass(args) {
    let self = this;
    let values = [];

    for (let i = 0; i < arguments.length; i++) {
      values.push(arguments[i]);
    }

    values.forEach(function (value) {
      if (!Array.isArray(value)) {
        value = [value];
      }

      if (!self.has('class')) {
        self.setAttribute('class', []);
      }

      let classes = self.get('class');

      value.forEach(function (d) {
        if (classes.indexOf(d) < 0) {
          classes.push(d);
        }
      });
    });

    return this;
  }

  removeClass(value) {
    let classes = [];

    if (this.has('class')) {
      classes = this.get('class');
    }

    if (!Array.isArray(value)) {
      value = [value];
    }

    value.forEach(function (v) {
      let index = classes.indexOf(v);

      if (index > -1) {
        classes.splice(index, 1);
      }
    });

    return this;
  }

  hasClass(value) {
    let classes = [];

    if (this.has('class')) {
      classes = this.get('class');
    }

    return (classes.indexOf(value) > -1);
  }

  setAttribute(key, value) {
    this.set(key, value);

    return this;
  }

  removeAttribute(key) {
    this.delete(key);

    return this;
  }

  toString() {
    let result = '';
    let components = [];

    this.forEach(function (value, key) {
      if (Array.isArray(value)) {
        value = value.join(' ');
      }

      components.push([key, '"' + value + '"'].join('='));
    });

    let rendered = components.join(' ');

    if (rendered) {
      result += ' ' + rendered;
    }

    return result;
  }
}

module.exports = DrupalAttribute;

Twing (and Twig) allows us to define our own custom functions, and I'm trying to use the drupal-attribute class as one of these Twi(n)g functions.

Twing 5 switched to an async approach where all functions need to return a resolved Promise object, like this:

const createAttribute = new TwingFunction('create_attribute', () =>
  return Promise.resolve(new drupalAttribute()),
);

This isn't working for me, the create_attribute function is found, but no attributes are output by the function, and if I put a breakpoint in the constructor method it isn't reached.

Earlier versions of Twig (e.g. version 2) were synchronous, and in that version the below Twing function works perfectly, with no other changes:

const createAttribute = new TwingFunction('create_attribute', function() {
  return new drupalAttribute();
});

To me, the only difference seems to be the use of Promise.resolve(new drupalAttribute()) rather than return new drupalAttribute(). Am I doing something wrong here? I don't know much about how classes and promises interact and I'm wondering if resolving rather than returning the class adds an extra layer around the class that stops it being usable?

Upvotes: 0

Views: 822

Answers (0)

Related Questions