1 | 'use strict';
|
2 |
|
3 | const fs = require('fs');
|
4 | const path = require('path');
|
5 |
|
6 | const CONFIG_FILE_NAME = Symbol('configuration file name');
|
7 | const LOCATIONS = Symbol('configuration file location');
|
8 | const SERIALIZERS = Symbol('configuration file serializers');
|
9 |
|
10 | function suffixPath(configLocation, configFileName) {
|
11 | const suffix = path.sep + configFileName;
|
12 | return configLocation.substr(-suffix.length) !== suffix
|
13 | ? configLocation + suffix
|
14 | : configLocation;
|
15 | }
|
16 |
|
17 | function readJsonOrReturnObject(jsonPath) {
|
18 | try {
|
19 | return JSON.parse(fs.readFileSync(jsonPath));
|
20 | } catch (_error) {
|
21 | return {};
|
22 | }
|
23 | }
|
24 |
|
25 |
|
26 |
|
27 |
|
28 | class ConfigManager {
|
29 | |
30 |
|
31 |
|
32 |
|
33 |
|
34 |
|
35 | constructor(possibleLocations, configFileName) {
|
36 | this[CONFIG_FILE_NAME] = configFileName;
|
37 | this[LOCATIONS] = possibleLocations.filter(possibleLocation => !!possibleLocation);
|
38 | this[SERIALIZERS] = {};
|
39 |
|
40 | if (!this[LOCATIONS].length) {
|
41 | throw new Error('No config location');
|
42 | }
|
43 |
|
44 | this.read();
|
45 | }
|
46 |
|
47 | |
48 |
|
49 |
|
50 |
|
51 |
|
52 |
|
53 |
|
54 | registerConfig(configName, defaultValue, serialize) {
|
55 | if (!this[configName]) {
|
56 | this[configName] = defaultValue || null;
|
57 | }
|
58 |
|
59 | Object.assign(this[SERIALIZERS], {
|
60 | [configName]: serialize
|
61 | });
|
62 |
|
63 | return this[configName];
|
64 | }
|
65 |
|
66 | |
67 |
|
68 |
|
69 |
|
70 |
|
71 | getStatus() {
|
72 | return this[LOCATIONS].filter(configLocation => !!configLocation)
|
73 | .map(configLocation => suffixPath(configLocation, this[CONFIG_FILE_NAME]))
|
74 | .map(configLocation => ({
|
75 | path: configLocation,
|
76 | exists: fs.existsSync(configLocation)
|
77 | }));
|
78 | }
|
79 |
|
80 | |
81 |
|
82 |
|
83 | read() {
|
84 | Object.assign(
|
85 | this,
|
86 | this.getStatus().reduce(
|
87 | (config, file) =>
|
88 | file.exists ? Object.assign(readJsonOrReturnObject(file.path), config) : config,
|
89 | {}
|
90 | )
|
91 | );
|
92 | }
|
93 |
|
94 | |
95 |
|
96 |
|
97 |
|
98 |
|
99 |
|
100 |
|
101 | save(configLocation) {
|
102 | if (!configLocation) {
|
103 | const configStatus = this.getStatus();
|
104 | configLocation = (
|
105 | configStatus.find(loc => loc.exists) || configStatus[configStatus.length - 1]
|
106 | ).path;
|
107 | }
|
108 |
|
109 | const suffix = path.sep + this[CONFIG_FILE_NAME];
|
110 | if (configLocation.substr(-suffix.length) !== suffix) {
|
111 | configLocation += suffix;
|
112 | }
|
113 |
|
114 | return new Promise((resolve, reject) =>
|
115 | fs.writeFile(configLocation, this.toString(), error => {
|
116 | return error ? reject(error) : resolve(configLocation);
|
117 | })
|
118 | );
|
119 | }
|
120 |
|
121 | |
122 |
|
123 |
|
124 |
|
125 |
|
126 | toString() {
|
127 | const serializedConfig = Object.keys(this[SERIALIZERS]).reduce((config, serializerName) => {
|
128 | const serializerFn = this[SERIALIZERS][serializerName];
|
129 | const serialized =
|
130 | typeof serializerFn === 'function'
|
131 | ? serializerFn(this[serializerName])
|
132 | : this[serializerName];
|
133 |
|
134 | return serialized !== null && serialized !== undefined
|
135 | ? Object.assign(config, {
|
136 | [serializerName]: serialized
|
137 | })
|
138 | : config;
|
139 | }, {});
|
140 |
|
141 | return JSON.stringify(serializedConfig, null, '\t');
|
142 | }
|
143 | }
|
144 |
|
145 | module.exports = ConfigManager;
|