@mp-consulting/homebridge-ui-kit 1.1.1 → 1.2.1

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.
@@ -0,0 +1,152 @@
1
+ #!/usr/bin/env node
2
+ // mp-ui-kit-copy — copies the UI kit's dist/ files (kit.css, kit.js, ai.css)
3
+ // into a plugin's custom UI folder. Zero dependencies.
4
+ //
5
+ // mp-ui-kit-copy → <cwd>/homebridge-ui/public/lib/
6
+ // mp-ui-kit-copy --dest <dir> → <dir> (relative to the current directory)
7
+ // mp-ui-kit-copy --vendor → also Bootstrap / Bootstrap Icons from the
8
+ // plugin's node_modules (lib/ + lib/fonts/)
9
+
10
+ import {
11
+ copyFileSync, existsSync, mkdirSync, readdirSync, readFileSync, realpathSync, statSync, writeFileSync,
12
+ } from 'fs';
13
+ import { createRequire } from 'module';
14
+ import { basename, dirname, join, relative, resolve } from 'path';
15
+ import { fileURLToPath, pathToFileURL } from 'url';
16
+
17
+ const distDir = join(dirname(fileURLToPath(import.meta.url)), '..', 'dist');
18
+
19
+ export const DEFAULT_DEST = join('homebridge-ui', 'public', 'lib');
20
+
21
+ // Same layout the plugins' former `copy:ui-assets` scripts produced.
22
+ const VENDOR = [
23
+ {
24
+ pkg: 'bootstrap',
25
+ files: [
26
+ ['dist/css/bootstrap.min.css', '.'],
27
+ ['dist/js/bootstrap.bundle.min.js', '.'],
28
+ ],
29
+ },
30
+ {
31
+ pkg: 'bootstrap-icons',
32
+ files: [
33
+ ['font/bootstrap-icons.min.css', '.'],
34
+ ['font/fonts/bootstrap-icons.woff', 'fonts'],
35
+ ['font/fonts/bootstrap-icons.woff2', 'fonts'],
36
+ ],
37
+ },
38
+ ];
39
+
40
+ // The plugin UI does not serve source maps, so drop the references to them.
41
+ const SOURCE_MAP = /^\s*\/[*/]# sourceMappingURL=.*$/gm;
42
+
43
+ function findPackage(cwd, pkg) {
44
+ try {
45
+ const require = createRequire(join(cwd, 'package.json'));
46
+ return dirname(require.resolve(`${pkg}/package.json`));
47
+ } catch {
48
+ const local = join(cwd, 'node_modules', pkg);
49
+ return existsSync(local) ? local : null;
50
+ }
51
+ }
52
+
53
+ /**
54
+ * Copies the kit into `dest` (default `<cwd>/homebridge-ui/public/lib`).
55
+ * Returns the list of written file paths.
56
+ */
57
+ export function copyAssets({ cwd = process.cwd(), dest, vendor = false, log = () => {} } = {}) {
58
+ const target = resolve(cwd, dest || DEFAULT_DEST);
59
+ mkdirSync(target, { recursive: true });
60
+ const written = [];
61
+
62
+ for (const name of readdirSync(distDir)) {
63
+ const from = join(distDir, name);
64
+ if (!statSync(from).isFile()) { continue; }
65
+ copyFileSync(from, join(target, name));
66
+ written.push(join(target, name));
67
+ }
68
+
69
+ if (vendor) {
70
+ for (const { pkg, files } of VENDOR) {
71
+ const root = findPackage(cwd, pkg);
72
+ if (!root) {
73
+ log(`- ${pkg} is not installed; skipped`);
74
+ continue;
75
+ }
76
+ for (const [rel, sub] of files) {
77
+ const from = join(root, rel);
78
+ if (!existsSync(from)) {
79
+ log(`- ${pkg}/${rel} not found; skipped`);
80
+ continue;
81
+ }
82
+ const dir = join(target, sub);
83
+ mkdirSync(dir, { recursive: true });
84
+ const to = join(dir, basename(rel));
85
+ if (/\.(css|js)$/.test(rel)) {
86
+ writeFileSync(to, readFileSync(from, 'utf8').replace(SOURCE_MAP, ''));
87
+ } else {
88
+ copyFileSync(from, to);
89
+ }
90
+ written.push(to);
91
+ }
92
+ }
93
+ }
94
+
95
+ return written;
96
+ }
97
+
98
+ function parseArgs(argv) {
99
+ const opts = { vendor: false, help: false };
100
+ for (let i = 0; i < argv.length; i += 1) {
101
+ const arg = argv[i];
102
+ if (arg === '--dest') {
103
+ opts.dest = argv[i + 1];
104
+ i += 1;
105
+ if (!opts.dest) { throw new Error('--dest needs a directory'); }
106
+ } else if (arg.startsWith('--dest=')) {
107
+ opts.dest = arg.slice('--dest='.length);
108
+ } else if (arg === '--vendor') {
109
+ opts.vendor = true;
110
+ } else if (arg === '--help' || arg === '-h') {
111
+ opts.help = true;
112
+ } else {
113
+ throw new Error(`unknown option ${arg}`);
114
+ }
115
+ }
116
+ return opts;
117
+ }
118
+
119
+ const USAGE = `Usage: mp-ui-kit-copy [--dest <dir>] [--vendor]
120
+
121
+ Copies @mp-consulting/homebridge-ui-kit's dist/ (kit.css, kit.js, ai.css)
122
+ into ${DEFAULT_DEST}/ of the current directory.
123
+
124
+ --dest <dir> copy into <dir> instead (relative to the current directory)
125
+ --vendor also copy bootstrap.min.css, bootstrap.bundle.min.js,
126
+ bootstrap-icons.min.css and fonts/ from your node_modules
127
+ -h, --help show this help`;
128
+
129
+ function isMain() {
130
+ if (!process.argv[1]) { return false; }
131
+ try {
132
+ return import.meta.url === pathToFileURL(realpathSync(process.argv[1])).href;
133
+ } catch {
134
+ return false;
135
+ }
136
+ }
137
+
138
+ if (isMain()) {
139
+ try {
140
+ const opts = parseArgs(process.argv.slice(2));
141
+ if (opts.help) {
142
+ console.log(USAGE);
143
+ } else {
144
+ const cwd = process.cwd();
145
+ const written = copyAssets({ ...opts, cwd, log: msg => console.log(msg) });
146
+ for (const file of written) { console.log(`✓ ${relative(cwd, file)}`); }
147
+ }
148
+ } catch (err) {
149
+ console.error(`mp-ui-kit-copy: ${err.message}\n\n${USAGE}`);
150
+ process.exit(1);
151
+ }
152
+ }