javascript - получить параметры из строки - PullRequest
3 голосов
/ 08 мая 2020

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

const config = {
    name: 'foo',
    lookup: {
        lookup1: 'value1',
    },
    parameters: {
        bar: 'baz',
        test: 'hello',
    },
    actons: [
        {
            type: 'move',
            value: '[parameters(bar)]',
        },
        {
            type: 'tag',
            value: '[parameters(lookup(lookup1))]',
        },
        {
            type: 'date',
            value: '[date(-1, "days")]',
        },
        {
            type: 'tag',
            value: 'Just a normal text value',
        },
        {
            type: 'blabla',
            value: { object: 'also permitted' },
        },
    ],
};

Этот пример показывает некоторые json -значения, которые начинаются с [и заканчиваются на] и имеют некоторую «функцию» между ними. Этот формат фактически украден из того, как Azure RM работает со своими параметрами: https://docs.microsoft.com/en-us/azure/azure-resource-manager/templates/template-parameters

Теперь, что я хочу сделать, это обработать эти функции. На данный момент у меня есть следующие функции: date (), parameters (), concat (), lookup () (но это еще не все). Это единственные функции, которые разрешено выполнять. Вот где возникает мой вопрос.

Моя первая мысль заключалась в том, чтобы удалить начальную и конечную скобки, а затем просто выполнить эту строку с помощью eval (), но это опасно, потому что любой код может существовать между этими скобками.

Так как же тогда решить эту проблему? Я думаю о двух разных способах выполнения sh this (оба в порядке):
1. Как убедиться, что строка содержит только разрешенные функции? Таким образом, я могу безопасно использовать eval () (проверять строку перед выполнением)
2. Как выполнять эти функции из этой строки изнутри . Это важно, потому что функции также могут быть вложенными (см. Пример: parameters(lookup(lookup1)))

1 Ответ

3 голосов
/ 08 мая 2020

Основная идея

Функция разрушения вызывает что-то более безопасное для синтаксического анализа.

Модель (типы TS):

По дизайну только с одним аргументом:

interface Func {
  func: string;
  arg: Func | string;
}

С несколькими аргументами:

interface Func {
  func: string;
  args: Array<Func | string>;
}


Варианты реализации

1. Изменение структуры объекта

Только один аргумент:

{
  func: "paramaters",
  arg: {
    func: "lookup",
    arg: "lookup1"
  }
}

Несколько аргументов:

{
  func: "paramaters",
  args: [{
    func: "lookup",
    args: ["lookup1"]
  }]
}

2. Без изменения структуры, используя JSON.parse:

Используйте тот же подход со строкой JSON.

{
  type: 'move',
  value: "{ \"func\": \"parameters\", \"args\": [ \"bar\" ] }",
},

Таким образом, вы можете получить его с помощью: JSON.parse(actions[0].value).


Запуск функции (JSON опция)

В качестве примера окончательного выполнения у вас может быть словарь разрешенных функций:

const parameters = (...args) => console.log(...args);
const lookup = (arg) => console.warn(arg);

const allowedFunctions = {
  parameters,
  lookup,
};

И некоторые помощники для проверки и запустите их:

const isFunction = (functionCall) =>
  functionCall.hasOwnProperty("func") &&
  functionCall.hasOwnProperty("args") &&
  Array.isArray(functionCall.args);

const runFunction = (functionCall) => {
  const func = allowedFunctions[functionCall.func];
  if (!func) {
    throw new Error(`Unknown function: ${functionCall.func}`);
  } else {
    const args = functionCall.args.map((arg) => {
      if (isFunction(arg)) {
        return runFunction(arg);
      }
      return arg;
    });
    return func.apply(null, args);
  }
};

Таким образом, основной вызов может выглядеть так:

for (const action of actions) {
  if ("string" === typeof action.value) {
    try {
      const value = JSON.parse(action.value);
      if (isFunction(value)) {
        console.log("Function returns:", runFunction(value));
      } else {
        throw new Error("Not a function object");
      }
    } catch (ex) {
      console.error("Not a function or unknown", ex);
    }
  }
}

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...