๐Ÿ“ฆ hexojs / hexo

๐Ÿ“„ console.ts ยท 120 lines
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120import Promise from 'bluebird';
import abbrev from 'abbrev';
import type { NodeJSLikeCallback } from '../types';
import type Hexo from '../hexo';

type Option = Partial<{
  usage: string;
  desc: string;
  init: boolean;
  arguments: {
      name: string;
      desc: string;
    }[];
  options: {
    name: string;
    desc: string;
  }[];
}>

interface Args {
  _: string[];
  [key: string]: string | boolean | string[];
}
type AnyFn = (this: Hexo, args: Args, callback?: NodeJSLikeCallback<any>) => any;
interface StoreFunction {
  (this: Hexo, args: Args): Promise<any>;
  desc?: string;
  options?: Option;
}

interface Store {
  [key: string]: StoreFunction
}
interface Alias {
  [abbreviation: string]: string
}

/**
 * The console forms the bridge between Hexo and its users. It registers and describes the available console commands.
 */
class Console {
  public store: Store;
  public alias: Alias;

  constructor() {
    this.store = {};
    this.alias = {};
  }

  /**
   * Get a console plugin function by name
   * @param {String} name - The name of the console plugin
   * @returns {StoreFunction} - The console plugin function
   */
  get(name: string): StoreFunction {
    name = name.toLowerCase();
    return this.store[this.alias[name]];
  }

  list(): Store {
    return this.store;
  }

  /**
   * Register a console plugin
   * @param {String} name - The name of console plugin to be registered
   * @param {String} desc - More detailed information about a console command
   * @param {Option} options - The description of each option of a console command
   * @param {AnyFn} fn - The console plugin to be registered
   */
  register(name: string, fn: AnyFn): void
  register(name: string, desc: string, fn: AnyFn): void
  register(name: string, options: Option, fn: AnyFn): void
  register(name: string, desc: string, options: Option, fn: AnyFn): void
  register(name: string, desc: string | Option | AnyFn, options?: Option | AnyFn, fn?: AnyFn): void {
    if (!name) throw new TypeError('name is required');

    if (!fn) {
      if (options) {
        if (typeof options === 'function') {
          fn = options;

          if (typeof desc === 'object') { // name, options, fn
            options = desc;
            desc = '';
          } else { // name, desc, fn
            options = {};
          }
        } else {
          throw new TypeError('fn must be a function');
        }
      } else {
        // name, fn
        if (typeof desc === 'function') {
          fn = desc;
          options = {};
          desc = '';
        } else {
          throw new TypeError('fn must be a function');
        }
      }
    }

    if (fn.length > 1) {
      fn = Promise.promisify(fn);
    } else {
      fn = Promise.method(fn);
    }

    const c = fn as StoreFunction;
    this.store[name.toLowerCase()] = c;
    c.options = options as Option;
    c.desc = desc as string;

    this.alias = abbrev(Object.keys(this.store));
  }
}

export = Console;