<commit_before>import isPlainObject from 'is-plain-object'
import { List, Map, Record } from 'immutable'

import KeyUtils from '../utils/key-utils'
import Node from './node'

/**
 * Default properties.
 *
 * @type {Object}
 */

const DEFAULTS = {
  data: undefined,
  key: undefined,
  nodes: undefined,
  type: undefined,
}

/**
 * Block.
 *
 * @type {Block}
 */

class Block extends Record(DEFAULTS) {
  /**
   * Create a new `Block` from `attrs`.
   *
   * @param {Object|String|Block} attrs
   * @return {Block}
   */

  static create(attrs = {}) {
    if (Block.isBlock(attrs)) {
      return attrs
    }

    if (typeof attrs === 'string') {
      attrs = { type: attrs }
    }

    if (isPlainObject(attrs)) {
      return Block.fromJSON(attrs)
    }

    throw new Error(
      `\`Block.create\` only accepts objects, strings or blocks, but you passed it: ${attrs}`
    )
  }

  /**
   * Create a list of `Blocks` from `attrs`.
   *
   * @param {Array<Block|Object>|List<Block|Object>} attrs
   * @return {List<Block>}
   */

  static createList(attrs = []) {
    if (List.isList(attrs) || Array.isArray(attrs)) {
      const list = new List(attrs.map(Block.create))
      return list
    }

    throw new Error(
      `\`Block.createList\` only accepts arrays or lists, but you passed it: ${attrs}`
    )
  }

  /**
   * Create a `Block` from a JSON `object`.
   *
   * @param {Object|Block} object
   * @return {Block}
   */

  static fromJSON(object) {
    if (Block.isBlock(object)) {
      return object
    }

    const { data = {}, key = KeyUtils.create(), nodes = [], type } = object

    if (typeof type !== 'string') {
      throw new Error('`Block.fromJSON` requires a `type` string.')
    }

    const block = new Block({
      key,
      type,
      data: Map(data),
      nodes: Node.createList(nodes),
    })

    return block
  }

  /**
   * Check if `any` is a block list.
   *
   * @param {Any} any
   * @return {Boolean}
   */

  static isBlockList(any) {
    return List.isList(any) && any.every(item => Block.isBlock(item))
  }

  /**
   * Return a JSON representation of the block.
   *
   * @param {Object} options
   * @return {Object}
   */

  toJSON(options = {}) {
    const object = {
      object: this.object,
      type: this.type,
      data: this.data.toJSON(),
      nodes: this.nodes.toArray().map(n => n.toJSON(options)),
    }

    if (options.preserveKeys) {
      object.key = this.key
    }

    return object
  }
}

/**
 * Export.
 *
 * @type {Block}
 */

export default Block
<commit_msg>Switched Map to fromJS in order to convert the whole js object (also nested data structures) to immutable (#2619)<commit_after>import isPlainObject from 'is-plain-object'
import { fromJS, List, Record } from 'immutable'

import KeyUtils from '../utils/key-utils'
import Node from './node'

/**
 * Default properties.
 *
 * @type {Object}
 */

const DEFAULTS = {
  data: undefined,
  key: undefined,
  nodes: undefined,
  type: undefined,
}

/**
 * Block.
 *
 * @type {Block}
 */

class Block extends Record(DEFAULTS) {
  /**
   * Create a new `Block` from `attrs`.
   *
   * @param {Object|String|Block} attrs
   * @return {Block}
   */

  static create(attrs = {}) {
    if (Block.isBlock(attrs)) {
      return attrs
    }

    if (typeof attrs === 'string') {
      attrs = { type: attrs }
    }

    if (isPlainObject(attrs)) {
      return Block.fromJSON(attrs)
    }

    throw new Error(
      `\`Block.create\` only accepts objects, strings or blocks, but you passed it: ${attrs}`
    )
  }

  /**
   * Create a list of `Blocks` from `attrs`.
   *
   * @param {Array<Block|Object>|List<Block|Object>} attrs
   * @return {List<Block>}
   */

  static createList(attrs = []) {
    if (List.isList(attrs) || Array.isArray(attrs)) {
      const list = new List(attrs.map(Block.create))
      return list
    }

    throw new Error(
      `\`Block.createList\` only accepts arrays or lists, but you passed it: ${attrs}`
    )
  }

  /**
   * Create a `Block` from a JSON `object`.
   *
   * @param {Object|Block} object
   * @return {Block}
   */

  static fromJSON(object) {
    if (Block.isBlock(object)) {
      return object
    }

    const { data = {}, key = KeyUtils.create(), nodes = [], type } = object

    if (typeof type !== 'string') {
      throw new Error('`Block.fromJSON` requires a `type` string.')
    }

    const block = new Block({
      key,
      type,
      data: fromJS(data),
      nodes: Node.createList(nodes),
    })

    return block
  }

  /**
   * Check if `any` is a block list.
   *
   * @param {Any} any
   * @return {Boolean}
   */

  static isBlockList(any) {
    return List.isList(any) && any.every(item => Block.isBlock(item))
  }

  /**
   * Return a JSON representation of the block.
   *
   * @param {Object} options
   * @return {Object}
   */

  toJSON(options = {}) {
    const object = {
      object: this.object,
      type: this.type,
      data: this.data.toJSON(),
      nodes: this.nodes.toArray().map(n => n.toJSON(options)),
    }

    if (options.preserveKeys) {
      object.key = this.key
    }

    return object
  }
}

/**
 * Export.
 *
 * @type {Block}
 */

export default Block

{'fraction_non_alphanumeric': 0.15341566962562717, 'fraction_numerical': 0.0007719027402547279, 'mean_word_length': 2.3853690398432397, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 13, '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': '5982205', 'n_tokens_mistral': 1760, 'n_tokens_neox': 1739, 'n_words': 460}