molex-env 0.3.1 → 0.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -14
- package/index.d.ts +134 -0
- package/package.json +46 -35
- package/src/index.js +27 -26
- package/src/lib/apply.js +61 -75
- package/src/lib/cast.js +133 -124
- package/src/lib/core.js +161 -148
- package/src/lib/errors.js +66 -98
- package/src/lib/files.js +35 -36
- package/src/lib/parser.js +96 -115
- package/src/lib/schema.js +48 -59
- package/src/lib/utils.js +19 -21
- package/src/lib/watch.js +128 -110
package/src/lib/watch.js
CHANGED
|
@@ -1,110 +1,128 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const fs = require('fs');
|
|
4
|
-
const path = require('path');
|
|
5
|
-
const { resolveFiles } = require('./files');
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
{
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
if (
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
const
|
|
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
|
-
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const { resolveFiles } = require('./files');
|
|
6
|
+
|
|
7
|
+
const DEBOUNCE_MS = 50;
|
|
8
|
+
|
|
9
|
+
/* ------------------------------------------------------------------ */
|
|
10
|
+
/* Helpers */
|
|
11
|
+
/* ------------------------------------------------------------------ */
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Serialize a value for comparison (handles Date and objects).
|
|
15
|
+
* @param {any} val
|
|
16
|
+
* @returns {string}
|
|
17
|
+
*/
|
|
18
|
+
function serialize(val)
|
|
19
|
+
{
|
|
20
|
+
if (val instanceof Date) return val.toISOString();
|
|
21
|
+
return JSON.stringify(val);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Detect which keys changed between two config snapshots.
|
|
26
|
+
* @param {object} previous
|
|
27
|
+
* @param {object} current
|
|
28
|
+
* @returns {{key: string, old: any, new: any}[]}
|
|
29
|
+
*/
|
|
30
|
+
function detectChanges(previous, current)
|
|
31
|
+
{
|
|
32
|
+
const changes = [];
|
|
33
|
+
for (const key of Object.keys(current))
|
|
34
|
+
{
|
|
35
|
+
if (serialize(previous[key]) !== serialize(current[key]))
|
|
36
|
+
{
|
|
37
|
+
changes.push({ key, old: previous[key], new: current[key] });
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return changes;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Log detected changes to console.
|
|
45
|
+
* @param {{key: string, old: any, new: any}[]} changes
|
|
46
|
+
*/
|
|
47
|
+
function logChanges(changes)
|
|
48
|
+
{
|
|
49
|
+
if (!changes.length) return;
|
|
50
|
+
console.log('[molex-env] Config reloaded - changes detected:');
|
|
51
|
+
for (const { key, old, new: val } of changes)
|
|
52
|
+
{
|
|
53
|
+
console.log(` ${key}: ${old} → ${val}`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/* ------------------------------------------------------------------ */
|
|
58
|
+
/* Public API */
|
|
59
|
+
/* ------------------------------------------------------------------ */
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Watch resolved .menv files and reload on changes.
|
|
63
|
+
* @param {object} options
|
|
64
|
+
* @param {(err: Error|null, result?: object) => void} onChange
|
|
65
|
+
* @param {(options: object) => object} load
|
|
66
|
+
* @returns {{close: () => void}}
|
|
67
|
+
*/
|
|
68
|
+
function watch(options, onChange, load)
|
|
69
|
+
{
|
|
70
|
+
if (typeof onChange !== 'function') throw new Error('onChange callback is required');
|
|
71
|
+
if (typeof load !== 'function') throw new Error('load function is required');
|
|
72
|
+
|
|
73
|
+
const files = resolveFiles(options);
|
|
74
|
+
const cwd = options.cwd || process.cwd();
|
|
75
|
+
const basenames = new Set(files.map((f) => path.basename(f)));
|
|
76
|
+
const watchers = [];
|
|
77
|
+
let timer = null;
|
|
78
|
+
let previousConfig = null;
|
|
79
|
+
|
|
80
|
+
const reload = () =>
|
|
81
|
+
{
|
|
82
|
+
if (timer) clearTimeout(timer);
|
|
83
|
+
timer = setTimeout(() =>
|
|
84
|
+
{
|
|
85
|
+
try
|
|
86
|
+
{
|
|
87
|
+
const result = load({ ...options, debug: false });
|
|
88
|
+
|
|
89
|
+
if (options.debug && previousConfig)
|
|
90
|
+
{
|
|
91
|
+
logChanges(detectChanges(previousConfig, result.parsed));
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
previousConfig = { ...result.parsed };
|
|
95
|
+
onChange(null, result);
|
|
96
|
+
} catch (err)
|
|
97
|
+
{
|
|
98
|
+
onChange(err);
|
|
99
|
+
}
|
|
100
|
+
}, DEBOUNCE_MS);
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
// Watch existing files
|
|
104
|
+
for (const filePath of files)
|
|
105
|
+
{
|
|
106
|
+
if (!fs.existsSync(filePath)) continue;
|
|
107
|
+
watchers.push(fs.watch(filePath, reload));
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Watch directory for new files matching expected names
|
|
111
|
+
if (options.watchMissing !== false)
|
|
112
|
+
{
|
|
113
|
+
watchers.push(fs.watch(cwd, (_event, filename) =>
|
|
114
|
+
{
|
|
115
|
+
if (filename && basenames.has(filename)) reload();
|
|
116
|
+
}));
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return {
|
|
120
|
+
close()
|
|
121
|
+
{
|
|
122
|
+
watchers.forEach((w) => w.close());
|
|
123
|
+
watchers.length = 0;
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
module.exports = { watch };
|