<commit_before>const flattenObject = object => {
  if (typeof object !== 'object') {
    return object;
  }
  const flatObject = {};
  for (const key in object) {
    flatObject[key] = object[key];
  }
  for (const key in Object.getOwnPropertyNames(object)) {
    flatObject[key] = object[key];
  }
  return flatObject;
};

class AutoScaledCanvas {
  constructor(element) {
    this.element = element;
  }

  toDataURL(...args) {
    return this.element.toDataURL(...args);
  }

  autoScale() {
    window.autoScaleCanvas(this.element);
  }

  get width() {
    return this.element.width;
  }

  set width(value) {
    this.element.width = value;
    this.autoScale();
    return value;
  }

  get height() {
    return this.element.height;
  }

  set height(value) {
    this.element.height = value;
    this.autoScale();
    return value;
  }
}

const toMessage = result => {
  if (result instanceof Blob) {
    return {
      type: 'blob',
      payload: btoa(result),
    };
  }
  return {
    type: 'json',
    payload: flattenObject(result),
  };
};

const canvas = document.createElement('canvas');
const autoScaledCanvas = new AutoScaledCanvas(canvas);

const targets = {
  canvas: autoScaledCanvas,
  context2D: canvas.getContext('2d'),
};

const constructors = {
  Image,
  Path2D,
};

const populateRefs = arg => {
  if (arg && arg.__ref__) {
    return targets[arg.__ref__];
  }
  return arg;
};

document.body.appendChild(canvas);

function handleMessage(e) {
  const {id, type, payload} = JSON.parse(e.data);
  try {
    switch (type) {
      case 'exec': {
        const {target, method, args} = payload;
        const result = targets[target][method](...args.map(populateRefs));
        const message = toMessage(result);
        postMessage(JSON.stringify({id, ...message}));
        break;
      }
      case 'set': {
        const {target, key, value} = payload;
        targets[target][key] = value;
        break;
      }
      case 'construct': {
        const {constructor, id: target, args = []} = payload;
        const object = new constructors[constructor](...args);
        const message = toMessage({});
        targets[target] = object;
        postMessage(JSON.stringify({id, ...message}));
        break;
      }
      case 'listen': {
        const {types, target} = payload;
        for (const eventType of types) {
          targets[target].addEventListener(eventType, e => {
            const message = toMessage({
              type: 'event',
              payload: {
                type: e.type,
                target: {...flattenObject(targets[target]), '@@WEBVIEW_TARGET': target},
              },
            });
            postMessage(JSON.stringify({id, ...message}));
          });
        }
        break;
      }
    }
  } catch (err) {
    postMessage(
      JSON.stringify({
        id,
        type: 'error',
        payload: {
          message: err.message,
        },
      }),
    );
    document.removeEventListener('message', handleMessage);
  }
}

document.addEventListener('message', handleMessage);<commit_msg>Allow passing array of messages<commit_after>const flattenObject = object => {
  if (typeof object !== 'object') {
    return object;
  }
  const flatObject = {};
  for (const key in object) {
    flatObject[key] = object[key];
  }
  for (const key in Object.getOwnPropertyNames(object)) {
    flatObject[key] = object[key];
  }
  return flatObject;
};

class AutoScaledCanvas {
  constructor(element) {
    this.element = element;
  }

  toDataURL(...args) {
    return this.element.toDataURL(...args);
  }

  autoScale() {
    window.autoScaleCanvas(this.element);
  }

  get width() {
    return this.element.width;
  }

  set width(value) {
    this.element.width = value;
    this.autoScale();
    return value;
  }

  get height() {
    return this.element.height;
  }

  set height(value) {
    this.element.height = value;
    this.autoScale();
    return value;
  }
}

const toMessage = result => {
  if (result instanceof Blob) {
    return {
      type: 'blob',
      payload: btoa(result),
    };
  }
  return {
    type: 'json',
    payload: flattenObject(result),
  };
};

const canvas = document.createElement('canvas');
const autoScaledCanvas = new AutoScaledCanvas(canvas);

const targets = {
  canvas: autoScaledCanvas,
  context2D: canvas.getContext('2d'),
};

const constructors = {
  Image,
  Path2D,
};

const populateRefs = arg => {
  if (arg && arg.__ref__) {
    return targets[arg.__ref__];
  }
  return arg;
};

document.body.appendChild(canvas);

function handleMessage(message) {
  const {id, type, payload} = message;
  switch (type) {
    case 'exec': {
      const {target, method, args} = payload;
      const result = targets[target][method](...args.map(populateRefs));
      const message = toMessage(result);
      postMessage(JSON.stringify({id, ...message}));
      break;
    }
    case 'set': {
      const {target, key, value} = payload;
      targets[target][key] = value;
      break;
    }
    case 'construct': {
      const {constructor, id: target, args = []} = payload;
      const object = new constructors[constructor](...args);
      const message = toMessage({});
      targets[target] = object;
      postMessage(JSON.stringify({id, ...message}));
      break;
    }
    case 'listen': {
      const {types, target} = payload;
      for (const eventType of types) {
        targets[target].addEventListener(eventType, e => {
          const message = toMessage({
            type: 'event',
            payload: {
              type: e.type,
              target: {...flattenObject(targets[target]), '@@WEBVIEW_TARGET': target},
            },
          });
          postMessage(JSON.stringify({id, ...message}));
        });
      }
      break;
    }
  }
}

const handleError = (err, message) => {
  postMessage(
    JSON.stringify({
      id: message.id,
      type: 'error',
      payload: {
        message: err.message,
      },
    }),
  );
  document.removeEventListener('message', handleIncomingMessage);
};

function handleIncomingMessage(e) {
  const data = JSON.parse(e.data);
  if (Array.isArray(data)) {
    for (const message of data) {
      try {
        handleMessage(message);
      } catch (err) {
        handleError(err, message);
      }
    }
  } else {
    try {
      handleMessage(data);
    } catch (err) {
      handleError(err, data);
    }
  }
}

document.addEventListener('message', handleIncomingMessage);
{'fraction_non_alphanumeric': 0.14482438496054464, 'fraction_numerical': 0.0009283614420547734, 'mean_word_length': 2.418297197250132, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 12, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '56241', 'n_tokens_mistral': 1989, 'n_tokens_neox': 1975, 'n_words': 434}