<commit_before>/*
 * Base class for all Fluent AST nodes.
 *
 * All productions described in the ASDL subclass BaseNode, including Span and
 * Annotation.
 *
 */
export abstract class BaseNode {
  abstract type: string

  [name: string]: unknown;

  equals(other: BaseNode, ignoredFields: Array<string> = ["span"]): boolean {
    const thisKeys = new Set(Object.keys(this));
    const otherKeys = new Set(Object.keys(other));
    if (ignoredFields) {
      for (const fieldName of ignoredFields) {
        thisKeys.delete(fieldName);
        otherKeys.delete(fieldName);
      }
    }
    if (thisKeys.size !== otherKeys.size) {
      return false;
    }
    for (const fieldName of thisKeys) {
      if (!otherKeys.has(fieldName)) {
        return false;
      }
      const thisVal = this[fieldName];
      const otherVal = other[fieldName];
      if (typeof thisVal !== typeof otherVal) {
        return false;
      }
      if (thisVal instanceof Array && otherVal instanceof Array) {
        if (thisVal.length !== otherVal.length) {
          return false;
        }
        for (let i = 0; i < thisVal.length; ++i) {
          if (!scalarsEqual(thisVal[i], otherVal[i], ignoredFields)) {
            return false;
          }
        }
      } else if (!scalarsEqual(thisVal, otherVal, ignoredFields)) {
        return false;
      }
    }
    return true;
  }

  clone(): BaseNode {
    function visit(value: unknown): unknown {
      if (value instanceof BaseNode) {
        return value.clone();
      }
      if (Array.isArray(value)) {
        return value.map(visit);
      }
      return value;
    }
    // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
    const clone = Object.create(this.constructor.prototype) as BaseNode;
    for (const prop of Object.keys(this)) {
      clone[prop] = visit(this[prop]);
    }
    return clone;
  }
}

function scalarsEqual(
  thisVal: unknown,
  otherVal: unknown,
  ignoredFields: Array<string>
): boolean {
  if (thisVal instanceof BaseNode && otherVal instanceof BaseNode) {
    return thisVal.equals(otherVal, ignoredFields);
  }
  return thisVal === otherVal;
}

/*
 * Base class for AST nodes which can have Spans.
 */
export abstract class SyntaxNode extends BaseNode {
  public span?: Span;
<commit_msg>fix(fluent-syntax): Use correct TS type for clone() return (#589)<commit_after>/*
 * Base class for all Fluent AST nodes.
 *
 * All productions described in the ASDL subclass BaseNode, including Span and
 * Annotation.
 *
 */
export abstract class BaseNode {
  abstract type: string

  [name: string]: unknown;

  equals(other: BaseNode, ignoredFields: Array<string> = ["span"]): boolean {
    const thisKeys = new Set(Object.keys(this));
    const otherKeys = new Set(Object.keys(other));
    if (ignoredFields) {
      for (const fieldName of ignoredFields) {
        thisKeys.delete(fieldName);
        otherKeys.delete(fieldName);
      }
    }
    if (thisKeys.size !== otherKeys.size) {
      return false;
    }
    for (const fieldName of thisKeys) {
      if (!otherKeys.has(fieldName)) {
        return false;
      }
      const thisVal = this[fieldName];
      const otherVal = other[fieldName];
      if (typeof thisVal !== typeof otherVal) {
        return false;
      }
      if (thisVal instanceof Array && otherVal instanceof Array) {
        if (thisVal.length !== otherVal.length) {
          return false;
        }
        for (let i = 0; i < thisVal.length; ++i) {
          if (!scalarsEqual(thisVal[i], otherVal[i], ignoredFields)) {
            return false;
          }
        }
      } else if (!scalarsEqual(thisVal, otherVal, ignoredFields)) {
        return false;
      }
    }
    return true;
  }

  clone(): this {
    function visit(value: unknown): unknown {
      if (value instanceof BaseNode) {
        return value.clone();
      }
      if (Array.isArray(value)) {
        return value.map(visit);
      }
      return value;
    }
    // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
    const clone = Object.create(this.constructor.prototype) as this;
    for (const prop of Object.keys(this)) {
      clone[prop] = visit(this[prop]);
    }
    return clone;
  }
}

function scalarsEqual(
  thisVal: unknown,
  otherVal: unknown,
  ignoredFields: Array<string>
): boolean {
  if (thisVal instanceof BaseNode && otherVal instanceof BaseNode) {
    return thisVal.equals(otherVal, ignoredFields);
  }
  return thisVal === otherVal;
}

/*
 * Base class for AST nodes which can have Spans.
 */
export abstract class SyntaxNode extends BaseNode {
  public span?: Span;

{'fraction_non_alphanumeric': 0.11480034722222222, 'fraction_numerical': 0.0010850694444444445, 'mean_word_length': 2.60641627543036, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 7, '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': '4116803', 'n_tokens_mistral': 1371, 'n_tokens_neox': 1352, 'n_words': 384}