-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathaddon.ts
112 lines (103 loc) · 3.69 KB
/
addon.ts
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
import winston from "winston";
import {AppContext} from "./app";
import * as fs from "fs";
import npm from "npm";
import * as http from "http";
import {isDebug} from "./helpers";
import {createLogger} from "./logger";
type FunctionTypes = {
'BEFORE_CONFIG': (ctx: { logger: winston.Logger }) => Promise<void>;
'BEFORE_DB': (ctx: { logger: winston.Logger, appConfig: any }) => Promise<void>;
'BEFORE_ENGINE': (ctx: AppContext) => Promise<void>;
'BEFORE_SECURITY': (ctx: AppContext) => Promise<void>;
'BEFORE_ROUTES': (ctx: AppContext) => Promise<void>;
'BEFORE_SERVER': (ctx: AppContext) => Promise<void>;
'BOOT': (ctx: AppContext, srv: http.Server) => Promise<void>;
'EXIT': (ctx: AppContext) => Promise<void>;
}
export type Moment = keyof FunctionTypes;
export type AddonSteps = {
[key in Moment]: FunctionTypes[key];
};
export type Addon = {
name: string,
briefName?: string,
author?: string,
version?: string,
disabled?: boolean,
steps: AddonSteps,
}
async function initNpm() {
await npm.load();
npm.config.set('save', false);
npm.config.set('save-dev', false);
}
// Installs dependencies written in libraries.txt
async function installLibs(logger: winston.Logger, libs: { [key: string]: string }) {
const libsArray = Object.keys(libs).map((key) => key + '@' + libs[key]);
logger.info(`Installing ${libsArray.join(', ')}`);
await new Promise((resolve, reject) => {
npm.commands.install(libsArray, (err) => {
if (err) {
reject(err);
} else {
resolve(true);
}
});
});
}
// Load addons
export default async function (logger: winston.Logger) {
// Load NPM client
await initNpm();
const addons: Addon[] = [];
// Loop addon dirs
for (const dir of (
// Directories array
fs.readdirSync(__dirname + '/addons')
.map((dir) => __dirname + '/addons/' + dir)
.filter((file) => fs.existsSync(file + '/index.js'))
)) {
if (dir.endsWith('example_addon')) {
// Skip default example addon
continue;
}
logger.info(`Loading addon from ${dir}`);
if (fs.existsSync(dir + '/libraries.txt')) {
await installLibs(logger, (
// Libraries mapped
fs.readFileSync(dir + '/libraries.txt', 'utf8')
.split('\n')
.filter((lib) => lib.includes("="))
.map((lib) => lib.split('='))
.reduce((acc, [name, version]) => {
acc[name] = version.replace('\r', '');
return acc;
}, {} as { [key: string]: string })
));
}
const addon = require(dir + '/index.js').default as Addon;
if (!addon.disabled) {
addons.push(addon);
const { name, author, version } = addon;
logger.info(`Loaded addon ${name}${author ? ` by ${author}` : ``}${version ? ` (v${version})` : ``}`);
}
}
return <T extends keyof FunctionTypes>(step: T, ctx: any, ...args: any[]) => {
if (isDebug()) {
logger.info(`Running step ${step}`);
}
addons
.filter((addon) => addon.steps[step])
.forEach(addon => {
const f = addon.steps[step];
// Make temporary duplicate
const ctxAddon = { ...ctx };
if (ctxAddon.logger) {
// Make custom logger for each addon
ctxAddon.logger = createLogger({ label: addon.briefName ?? addon.name });
}
f.apply(f, [ctxAddon, ...args])
});
}
}