Есть ли простой способ получить значение ключа на втором уровне в карте объектов? - PullRequest
0 голосов
/ 12 января 2019

Я пишу несколько Node.js для развертывания AWS CloudFormation Stacks на основе шаблонов YAML, хочу сделать один сценарий универсальным для всех шаблонов и поэтому хочу проанализировать YAML для обнаружения определенных функций, так как это повлияет на вызов API. У меня есть способ конвертировать YAML обратно в JSON, а затем ...

Для целей этого примера я хочу знать, есть ли какие-либо ресурсы IAM (введите, например, «AWS :: IAM :: Role», «AWS :: IAM :: Group»), и есть ли у любого из этих ресурсов явные имена. Я должен указать возможность CAPABILITY_IAM для неназванного ресурса IAM, но нужно использовать CAPABILITY_NAMED_IAM, если у него есть имя.

Я сделал это с .map () и .filter (), когда это массив объектов, но этот формат является картой объектов, так что это не сработает. Кажется, я не могу найти простой «однострочный» способ сделать что-то подобное - возможно, я не знаю правильных поисковых терминов?

Итак, для этого (отредактированного для уменьшения) ввода:

{
  "AWSTemplateFormatVersion": "2010-09-09",
  "Resources": {
    "UnnamedRole": {
      "Type": "AWS::IAM::Role",
      "Properties": {
        "Path": "/"
      }
    },
    "NamedRole": {
      "Type": "AWS::IAM::Role",
      "Properties": {
        "RoleName": "SomeName"
        "Path": "/"
      }
    },
    "IrrelevantNonIAMResource": {
      "Type": "AWS::Lambda::Function",
      "Properties": {
        "FunctionName": "SomeFunction"
      }
    }
  }
}

Итак, первая проблема - в надежде получить этот вывод:

  "Resources": {
    "UnnamedRole": {
      "Type": "AWS::IAM::Role",
      "Needs": "CAPABILITY_IAM"
    },
    "NamedRole": {
      "Type": "AWS::IAM::Role",
      "Needs": "CAPABILITY_NAMED_IAM"
    }
  }

дополнительный кредит !! - ответ одним словом:

  • НЕТ = Ресурсы IAM не найдены, для которых нужна возможность
  • CAPABILITY_IAM = Найден хотя бы один IAM без имени
  • CAPABILITY_NAMED_IAM = Обнаружен хотя бы один IAM с именем -

@ Джеймс попросил код - у меня его нет, поэтому я здесь. Но я хотел получить что-то, что выглядело бы ближе к этому стилю - то, что я использую, чтобы найти связанные домены в Route53, где HostedZones - массив объектов. Ресурсами выше является карта объектов:

let zones = data.HostedZones.filter(z => z.Config.PrivateZone == false)
                            .map(z => ({ Id: z.Id.replace('/hostedzone/',''), Name: z.Name}))
                            .filter(z => z.Name.includes(domainName));

Существует ли подобный короткий синтаксис для выполнения того, что я хочу, в одной длинной строке?

Любая хорошая ссылка на то, где эта тема освещена. Новичок в Node - ничего не смог найти за 2 часа поиска.

Ответы [ 2 ]

0 голосов
/ 12 января 2019

Это можно сделать с помощью функции reduce (кстати, у вас есть ошибка в этой строке "RoleName": "SomeName", она должна заканчиваться ,).

Object.keys(o.Resources).reduce((acc, v) => {
  if (o.Resources[v].Type === "AWS::IAM::Role" && o.Resources[v].Properties.RoleName) {
    acc.Resources[v] = { Type: "AWS::IAM::Role", Needs: "CAPABILITY_NAMED_IAM"}
  } else if (o.Resources[v].Type === "AWS::IAM::Role") {
    acc.Resources[v] = { Type: "AWS::IAM::Role", Needs: "CAPABILITY_IAM" }
  }
  return acc;
}, { Resources: {}});

const o = {
  "AWSTemplateFormatVersion": "2010-09-09",
  "Resources": {
    "UnnamedRole": {
      "Type": "AWS::IAM::Role",
      "Properties": {
        "Path": "/"
      }
    },
    "NamedRole": {
      "Type": "AWS::IAM::Role",
      "Properties": {
        "RoleName": "SomeName",
        "Path": "/"
      }
    },
    "IrrelevantNonIAMResource": {
      "Type": "AWS::Lambda::Function",
      "Properties": {
        "FunctionName": "SomeFunction"
      }
    }
  }
}

const res = Object.keys(o.Resources).reduce((acc, v) => {
  if (o.Resources[v].Type === "AWS::IAM::Role" && o.Resources[v].Properties.RoleName) {
    acc.Resources[v] = { Type: "AWS::IAM::Role", Needs: "CAPABILITY_NAMED_IAM"}
  } else if (o.Resources[v].Type === "AWS::IAM::Role") {
    acc.Resources[v] = { Type: "AWS::IAM::Role", Needs: "CAPABILITY_IAM" }
  }
  return acc;
}, { Resources: {}});

console.log(res);
0 голосов
/ 12 января 2019

хорошо, похоже, что не существует собственного способа сделать то, что вы просите , поэтому забудьте об этом, как о выражениях в одну строку, но (как указано в связанном ответе) вы можете написать свой собственная функция objectMap.

С другой стороны, вы можете использовать некоторые служебные библиотеки, такие как lodash , которые позволят вам сделать что-то вроде того, что вы просите, используя их .chain и .map функции, которые могут перебирать объекты.

Надеюсь, это поможет вам!

...