text: /**
   * Copyright (c) Facebook, Inc. and its affiliates.
   *
   * This source code is licensed under the MIT license found in the
   * LICENSE file in the root directory of this source tree.
   *
   * @format
   * @flow
   * @emails oncall+draft_js
   *
   * This file is a fork of ContentBlock adding support for nesting references by
   * providing links to children, parent, prevSibling, and nextSibling.
   *
   * This is unstable and not part of the public API and should not be used by
   * production systems. This file may be update/removed without notice.
   */
  
  'use strict';
  
  import type {BlockNode, BlockNodeConfig, BlockNodeKey} from 'BlockNode';
  import type {DraftBlockType} from 'DraftBlockType';
  import type {DraftInlineStyle} from 'DraftInlineStyle';
  
  const CharacterMetadata = require('CharacterMetadata');
  
  const findRangesImmutable = require('findRangesImmutable');
  const Immutable = require('immutable');
  
  const {List, Map, OrderedSet, Record, Repeat} = Immutable;
  
  type ContentBlockNodeConfig = BlockNodeConfig & {
    children?: List<BlockNodeKey>,
    parent?: ?BlockNodeKey,
    prevSibling?: ?BlockNodeKey,
    nextSibling?: ?BlockNodeKey,
    ...
  };
  
  const EMPTY_SET = OrderedSet();
  
  const defaultRecord: ContentBlockNodeConfig = {
    parent: null,
    characterList: List(),
    data: Map(),
    depth: 0,
    key: '',
    text: '',
    type: 'unstyled',
    children: List(),
    prevSibling: null,
    nextSibling: null,
  };
  
  const haveEqualStyle = (
    charA: CharacterMetadata,
    charB: CharacterMetadata,
  ): boolean => charA.getStyle() === charB.getStyle();
  
  const haveEqualEntity = (
    charA: CharacterMetadata,
    charB: CharacterMetadata,
  ): boolean => charA.getEntity() === charB.getEntity();
  
  const decorateCharacterList = (
    config: ContentBlockNodeConfig,
  ): ContentBlockNodeConfig => {
    if (!config) {
      return config;
    }
  
    const {characterList, text} = config;
  
    if (text && !characterList) {
      config.characterList = List(Repeat(CharacterMetadata.EMPTY, text.length));
    }
  
    return config;
  };
  
  class ContentBlockNode extends (Record(defaultRecord): any)
    implements BlockNode {
    constructor(props: ContentBlockNodeConfig = defaultRecord) {
      /* eslint-disable-next-line constructor-super */
      super(decorateCharacterList(props));
    }
  
    getKey(): BlockNodeKey {
      return this.get('key');
    }
  
    getType(): DraftBlockType {
      return this.get('type');
    }
  
    getText(): string {
      return this.get('text');
    }
  
    getCharacterList(): List<CharacterMetadata> {
      return this.get('characterList');
    }
  
    getLength(): number {
      return this.getText().length;
    }
  
    getDepth(): number {
      return this.get('depth');
    }
  
    getData(): Map<any, any> {
      return this.get('data');
    }
  
    getInlineStyleAt(offset: number): DraftInlineStyle {
      const character = this.getCharacterList().get(offset);
      return character ? character.getStyle() : EMPTY_SET;
    }
  
    getEntityAt(offset: number): ?string {
      const character = this.getCharacterList().get(offset);
      return character ? character.getEntity() : null;
    }
  
    getChildKeys(): List<BlockNodeKey> {
      return this.get('children');
    }
  
    getParentKey(): ?BlockNodeKey {
      return this.get('parent');
    }
  
    getPrevSiblingKey(): ?BlockNodeKey {
      return this.get('prevSibling');
    }
  
    getNextSiblingKey(): ?BlockNodeKey {
      return this.get('nextSibling');
    }
  
    findStyleRanges(
      filterFn: (value: CharacterMetadata) => boolean,
      callback: (start: number, end: number) => void,
    ): void {
      findRangesImmutable(
        this.getCharacterList(),
        haveEqualStyle,
        filterFn,
        callback,
      );
    }
  
    findEntityRanges(
      filterFn: (value: CharacterMetadata) => boolean,
      callback: (start: number, end: number) => void,
    ): void {
      findRangesImmutable(
        this.getCharacterList(),
        haveEqualEntity,
        filterFn,
        callback,
      );
    }
  }
  
  module.exports = ContentBlockNode;
  