.gitignore added
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / enquirer / lib / interpolate.js
diff --git a/.config/coc/extensions/node_modules/coc-prettier/node_modules/enquirer/lib/interpolate.js b/.config/coc/extensions/node_modules/coc-prettier/node_modules/enquirer/lib/interpolate.js
new file mode 100644 (file)
index 0000000..c3d9b3f
--- /dev/null
@@ -0,0 +1,266 @@
+'use strict';
+
+const colors = require('ansi-colors');
+const clean = (str = '') => {
+  return typeof str === 'string' ? str.replace(/^['"]|['"]$/g, '') : '';
+};
+
+/**
+ * This file contains the interpolation and rendering logic for
+ * the Snippet prompt.
+ */
+
+class Item {
+  constructor(token) {
+    this.name = token.key;
+    this.field = token.field || {};
+    this.value = clean(token.initial || this.field.initial || '');
+    this.message = token.message || this.name;
+    this.cursor = 0;
+    this.input = '';
+    this.lines = [];
+  }
+}
+
+const tokenize = async(options = {}, defaults = {}, fn = token => token) => {
+  let unique = new Set();
+  let fields = options.fields || [];
+  let input = options.template;
+  let tabstops = [];
+  let items = [];
+  let keys = [];
+  let line = 1;
+
+  if (typeof input === 'function') {
+    input = await input();
+  }
+
+  let i = -1;
+  let next = () => input[++i];
+  let peek = () => input[i + 1];
+  let push = token => {
+    token.line = line;
+    tabstops.push(token);
+  };
+
+  push({ type: 'bos', value: '' });
+
+  while (i < input.length - 1) {
+    let value = next();
+
+    if (/^[^\S\n ]$/.test(value)) {
+      push({ type: 'text', value });
+      continue;
+    }
+
+    if (value === '\n') {
+      push({ type: 'newline', value });
+      line++;
+      continue;
+    }
+
+    if (value === '\\') {
+      value += next();
+      push({ type: 'text', value });
+      continue;
+    }
+
+    if ((value === '$' || value === '#' || value === '{') && peek() === '{') {
+      let n = next();
+      value += n;
+
+      let token = { type: 'template', open: value, inner: '', close: '', value };
+      let ch;
+
+      while ((ch = next())) {
+        if (ch === '}') {
+          if (peek() === '}') ch += next();
+          token.value += ch;
+          token.close = ch;
+          break;
+        }
+
+        if (ch === ':') {
+          token.initial = '';
+          token.key = token.inner;
+        } else if (token.initial !== void 0) {
+          token.initial += ch;
+        }
+
+        token.value += ch;
+        token.inner += ch;
+      }
+
+      token.template = token.open + (token.initial || token.inner) + token.close;
+      token.key = token.key || token.inner;
+
+      if (defaults.hasOwnProperty(token.key)) {
+        token.initial = defaults[token.key];
+      }
+
+      token = fn(token);
+      push(token);
+
+      keys.push(token.key);
+      unique.add(token.key);
+
+      let item = items.find(item => item.name === token.key);
+      token.field = fields.find(ch => ch.name === token.key);
+
+      if (!item) {
+        item = new Item(token);
+        items.push(item);
+      }
+
+      item.lines.push(token.line - 1);
+      continue;
+    }
+
+    let last = tabstops[tabstops.length - 1];
+    if (last.type === 'text' && last.line === line) {
+      last.value += value;
+    } else {
+      push({ type: 'text', value });
+    }
+  }
+
+  push({ type: 'eos', value: '' });
+  return { input, tabstops, unique, keys, items };
+};
+
+module.exports = async prompt => {
+  let options = prompt.options;
+  let required = new Set(options.required === true ? [] : (options.required || []));
+  let defaults = { ...options.values, ...options.initial };
+  let { tabstops, items, keys } = await tokenize(options, defaults);
+
+  let result = createFn('result', prompt, options);
+  let format = createFn('format', prompt, options);
+  let isValid = createFn('validate', prompt, options, true);
+  let isVal = prompt.isValue.bind(prompt);
+
+  return async(state = {}, submitted = false) => {
+    let index = 0;
+
+    state.required = required;
+    state.items = items;
+    state.keys = keys;
+    state.output = '';
+
+    let validate = async(value, state, item, index) => {
+      let error = await isValid(value, state, item, index);
+      if (error === false) {
+        return 'Invalid field ' + item.name;
+      }
+      return error;
+    };
+
+    for (let token of tabstops) {
+      let value = token.value;
+      let key = token.key;
+
+      if (token.type !== 'template') {
+        if (value) state.output += value;
+        continue;
+      }
+
+      if (token.type === 'template') {
+        let item = items.find(ch => ch.name === key);
+
+        if (options.required === true) {
+          state.required.add(item.name);
+        }
+
+        let val = [item.input, state.values[item.value], item.value, value].find(isVal);
+        let field = item.field || {};
+        let message = field.message || token.inner;
+
+        if (submitted) {
+          let error = await validate(state.values[key], state, item, index);
+          if ((error && typeof error === 'string') || error === false) {
+            state.invalid.set(key, error);
+            continue;
+          }
+
+          state.invalid.delete(key);
+          let res = await result(state.values[key], state, item, index);
+          state.output += colors.unstyle(res);
+          continue;
+        }
+
+        item.placeholder = false;
+
+        let before = value;
+        value = await format(value, state, item, index);
+
+        if (val !== value) {
+          state.values[key] = val;
+          value = prompt.styles.typing(val);
+          state.missing.delete(message);
+
+        } else {
+          state.values[key] = void 0;
+          val = `<${message}>`;
+          value = prompt.styles.primary(val);
+          item.placeholder = true;
+
+          if (state.required.has(key)) {
+            state.missing.add(message);
+          }
+        }
+
+        if (state.missing.has(message) && state.validating) {
+          value = prompt.styles.warning(val);
+        }
+
+        if (state.invalid.has(key) && state.validating) {
+          value = prompt.styles.danger(val);
+        }
+
+        if (index === state.index) {
+          if (before !== value) {
+            value = prompt.styles.underline(value);
+          } else {
+            value = prompt.styles.heading(colors.unstyle(value));
+          }
+        }
+
+        index++;
+      }
+
+      if (value) {
+        state.output += value;
+      }
+    }
+
+    let lines = state.output.split('\n').map(l => ' ' + l);
+    let len = items.length;
+    let done = 0;
+
+    for (let item of items) {
+      if (state.invalid.has(item.name)) {
+        item.lines.forEach(i => {
+          if (lines[i][0] !== ' ') return;
+          lines[i] = state.styles.danger(state.symbols.bullet) + lines[i].slice(1);
+        });
+      }
+
+      if (prompt.isValue(state.values[item.name])) {
+        done++;
+      }
+    }
+
+    state.completed = ((done / len) * 100).toFixed(0);
+    state.output = lines.join('\n');
+    return state.output;
+  };
+};
+
+function createFn(prop, prompt, options, fallback) {
+  return (value, state, item, index) => {
+    if (typeof item.field[prop] === 'function') {
+      return item.field[prop].call(prompt, value, state, item, index);
+    }
+    return [fallback, value].find(v => prompt.isValue(v));
+  };
+}