Javascript рекурсивный вложенный цикл сравнения - PullRequest
0 голосов
/ 01 июня 2018

Я пытаюсь создать рекурсивную функцию, которая перебирает объект конфигурации, который содержит ключи, которые должны быть установлены, по сравнению с appConfig, который должен соответствовать всем ключам (вложенным) внутри unsetConfig

const _ = window._
const UNSET_CONFIG_VAR = 'UNSET'

let config = {
  logging: {
    hasConsole: UNSET_CONFIG_VAR,
    hasSyslog: UNSET_CONFIG_VAR,
    processName: UNSET_CONFIG_VAR,
    inner: {
      test: UNSET_CONFIG_VAR
    }
  }
}

const unsetConfig = _.clone(config)

function initialize (appConfig) {
  const walkConfig = (currentConfigLevel, previousPaths = []) => {
    for (const [key, value] of Object.entries(currentConfigLevel)) {
      if (_.isObject(value)) {
        previousPaths.push(key)
        walkConfig(currentConfigLevel[key], previousPaths)
      }

      const path = previousPaths.length !== 0 ? previousPaths.join('.') : key

      if (!_.get(appConfig, path)) {
        throw new Error(`Config was missing: ${path}`)
      }
    }
  }

  walkConfig(unsetConfig)
}

initialize({
  logging: {
    hasConsole: true,
    hasSyslog: true,
    processName: true,
    inner: {
      as: true
    }
  }
})
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.10/lodash.min.js"></script>

Ожидается, что будет выдано сообщение об ошибке, как вы можете видеть в функции initialize, клавиша test отсутствует в logging.inner.

Но не выдается никакой ошибки.

Я уже пробовал это в других установках, но я как-то застрял на этом.

1 Ответ

0 голосов
/ 01 июня 2018

Если вы хотите проверить существование значения только по определенному пути, вам нужно использовать только lodash#has.Использование lodash#get приведет к получению значения определенного свойства из определенного пути, но использование такого значения для проверки существования такого пути ненадежно, поскольку это значение может быть ложным.

Кроме того,Аргумент пути, принятый как lodash#has, так и lodash#get, принимает либо строку, либо массив, поэтому вам на самом деле не нужно объединять их из разделителя.Фактически, присоединение к нему таким способом завершается неудачно, когда одно из ваших свойств конфигурации содержит массив.Поскольку запись ключа массива заключена в скобки, например [0] или [1].

function initialize(appConfig) {

  const walkConfig = (config, paths = []) => {
    Object.entries(config).forEach(([key, value]) => {
      let $paths = paths.concat(key);

      if(!_.has(appConfig, $paths)) {
        throw new Error(`Config was missing: ${$paths.join('.')}`);
      }

      if(_.isObject(value)) {
        walkConfig(value, $paths);
      }
    });
  };

  walkConfig(unsetConfig);

}

const { _ } = window;
const UNSET_CONFIG_VAR = 'UNSET'

let config = {
  logging: {
    hasConsole: UNSET_CONFIG_VAR,
    hasSyslog: UNSET_CONFIG_VAR,
    processName: UNSET_CONFIG_VAR,
    inner: {
      test: UNSET_CONFIG_VAR
    }
  }
}

const unsetConfig = _.cloneDeep(config); // Clone inner objects as well

function initialize(appConfig) {
  
  const walkConfig = (config, paths = []) => {
    Object.entries(config).forEach(([key, value]) => {
      let $paths = paths.concat(key);
      
      if(!_.has(appConfig, $paths)) {
        throw new Error(`Config was missing: ${$paths.join('.')}`);
      }
      
      if(_.isObject(value)) {
        walkConfig(value, $paths);
      }
    });
  };
  
  walkConfig(unsetConfig);
  
}

initialize({
  logging: {
    hasConsole: false,
    hasSyslog: true,
    processName: true,
    inner: {
      as: true
    }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>
...