<commit_before>const { isType, isUserType, isDecodeType } = require('lib/util')
const DecodeStream = require('streams/decode')
const symbols = require('internal/symbols')
const Metadata = require('internal/meta')

module.exports = {
  decode,
  decodeCommon
}

function decode(rstream, typeOrSchema) {
  if (Buffer.isBuffer(rstream)) {
    rstream = new DecodeStream(rstream)
  }

  const meta = new Metadata()
  const value = decodeCommon(rstream, typeOrSchema, meta)

  decode.bytes = meta.bytes
  meta.context = undefined

  return value
}

/**
 * @param {DecodeStream|Buffer} rstream
 * @param {object} schema
 * @param {Metadata} meta
 */
function decodeCommon(rstream, typeOrSchema, meta) {
  if (isType(typeOrSchema)) {
    return typeOrSchema.decode(rstream, meta)
  }

  return decodeSchema(rstream, typeOrSchema, meta)
}

/**
 * @param {DecodeStream} rstream
 * @param {object} schema
 * @param {Metadata} meta
 */
function decodeSchema(rstream, schema, meta) {
  assertSchema(schema)

  const result = Object.create(null)

  if (meta.context === undefined) {
    meta.context = {
      node: result,
      currentNode: result
    }
  } else {
    meta.context.currentNode = result
  }

  const keys = Object.keys(schema)

  for (let i = 0; i < keys.length; ++i) {
    const key = keys[i]
    const type = schema[key]

    if (!isDecodeType(type)) {
      result[key] = decodeSchema(rstream, type, meta)
      continue
    }

    const value = type.decode(rstream, meta)

    if (type[symbols.skip] === true) {
      continue
    }

    result[key] = value
  }<commit_msg>Restore state of `currentNode` after deep user type.<commit_after>const { isType, isUserType, isDecodeType } = require('lib/util')
const DecodeStream = require('streams/decode')
const symbols = require('internal/symbols')
const Metadata = require('internal/meta')

module.exports = {
  decode,
  decodeCommon
}

function decode(rstream, typeOrSchema) {
  if (Buffer.isBuffer(rstream)) {
    rstream = new DecodeStream(rstream)
  }

  const meta = new Metadata()
  const value = decodeCommon(rstream, typeOrSchema, meta)

  decode.bytes = meta.bytes
  meta.context = undefined

  return value
}

/**
 * @param {DecodeStream|Buffer} rstream
 * @param {object} schema
 * @param {Metadata} meta
 */
function decodeCommon(rstream, typeOrSchema, meta) {
  if (isType(typeOrSchema)) {
    return typeOrSchema.decode(rstream, meta)
  }

  return decodeSchema(rstream, typeOrSchema, meta)
}

/**
 * @param {DecodeStream} rstream
 * @param {object} schema
 * @param {Metadata} meta
 */
function decodeSchema(rstream, schema, meta) {
  assertSchema(schema)

  const result = Object.create(null)

  if (meta.context === undefined) {
    meta.context = {
      node: result,
      currentNode: result
    }
  } else {
    meta.context.currentNode = result
  }

  const keys = Object.keys(schema)

  for (let i = 0; i < keys.length; ++i) {
    const key = keys[i]
    const type = schema[key]

    if (!isDecodeType(type)) {
      result[key] = decodeSchema(rstream, type, meta)
      meta.context.currentNode = result
      continue
    }

    const value = type.decode(rstream, meta)

    if (type[symbols.skip] === true) {
      continue
    }

    result[key] = value
  }
{'fraction_non_alphanumeric': 0.12704286154794944, 'fraction_numerical': 0.0006167129201356768, 'mean_word_length': 3.518105849582173, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 3, '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': '1857879', 'n_tokens_mistral': 1058, 'n_tokens_neox': 1030, 'n_words': 255}