@neonwilderness/moveskins 1.4.0 → 1.4.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.
- package/CHANGELOG.md +6 -1
- package/package.json +1 -1
- package/src/_compare.js +24 -31
- package/src/_download.js +12 -12
- package/src/_upload.js +18 -26
- package/src/_utils.js +15 -25
- package/src/create.js +18 -20
- package/src/images.js +15 -14
- package/src/index.js +57 -57
- package/src/template.html +6 -9
package/CHANGELOG.md
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.4.1 (11.05.2026)
|
|
4
|
+
|
|
5
|
+
- Integrate .oxlint and .oxfmt configs into vite.config.js file
|
|
6
|
+
- Run vp check:fix to finally apply formatting rules
|
|
7
|
+
|
|
3
8
|
## 1.4.0 (07.05.2026)
|
|
4
9
|
|
|
5
10
|
- Add --layout CLI param string to address different Twoday layouts for up-/downloads
|
|
6
11
|
|
|
7
12
|
## 1.3.0 (02.05.2026)
|
|
8
13
|
|
|
9
|
-
- Add --toolbar CLI switch to additionally download 3 related modToolbar skins
|
|
14
|
+
- Add --toolbar CLI switch to additionally download 3 related modToolbar skins
|
|
10
15
|
|
|
11
16
|
## 1.2.0 (25.04.2026)
|
|
12
17
|
|
package/package.json
CHANGED
package/src/_compare.js
CHANGED
|
@@ -1,18 +1,20 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
|
+
|
|
1
4
|
/**
|
|
2
5
|
* Compare
|
|
3
6
|
* =======
|
|
4
7
|
*
|
|
5
8
|
*/
|
|
6
|
-
import chalk from
|
|
7
|
-
|
|
8
|
-
import {
|
|
9
|
-
import { aliasSkinFolder, getLocalSkins, skinRegister, splitAliases } from "./_utils.js";
|
|
9
|
+
import chalk from 'chalk';
|
|
10
|
+
|
|
11
|
+
import { aliasSkinFolder, getLocalSkins, skinRegister, splitAliases } from './_utils.js';
|
|
10
12
|
|
|
11
13
|
const classToColor = {
|
|
12
|
-
different:
|
|
13
|
-
identical:
|
|
14
|
-
new:
|
|
15
|
-
untouched:
|
|
14
|
+
different: 'cyan',
|
|
15
|
+
identical: 'grey',
|
|
16
|
+
new: 'green',
|
|
17
|
+
untouched: 'grey'
|
|
16
18
|
};
|
|
17
19
|
|
|
18
20
|
/**
|
|
@@ -36,28 +38,24 @@ const skinsByName = (skinA, skinB) => {
|
|
|
36
38
|
const compareLocalToRemoteSkins = async (td, aliases) => {
|
|
37
39
|
const alpineView = { aliases: [] };
|
|
38
40
|
try {
|
|
39
|
-
if (typeof aliases ===
|
|
41
|
+
if (typeof aliases === 'string') aliases = [aliases];
|
|
40
42
|
|
|
41
43
|
await td.login();
|
|
42
44
|
|
|
43
45
|
for (let alias of aliases) {
|
|
44
|
-
let aliasView = { header:
|
|
46
|
+
let aliasView = { header: '', skins: [] };
|
|
45
47
|
let localAlias = alias;
|
|
46
48
|
let remoteAlias = alias;
|
|
47
|
-
if (alias.includes(
|
|
49
|
+
if (alias.includes(':')) [localAlias, remoteAlias] = splitAliases(alias, ':');
|
|
48
50
|
aliasView.header = `Now comparing local alias "${localAlias}" to remote ${td.platform.toUpperCase()} alias "${remoteAlias}@${td.fullDomain}" [${new Date().toLocaleString()}] ...`;
|
|
49
51
|
console.log(chalk.green(`\n${aliasView.header}`));
|
|
50
|
-
aliasView.header = aliasView.header
|
|
51
|
-
.replace("local", "<ins>local</ins>")
|
|
52
|
-
.replace("remote", "<del>remote</del>");
|
|
52
|
+
aliasView.header = aliasView.header.replace('local', '<ins>local</ins>').replace('remote', '<del>remote</del>');
|
|
53
53
|
|
|
54
54
|
const aliasSkinDir = aliasSkinFolder(localAlias, false);
|
|
55
55
|
const localSkinData = getLocalSkins(localAlias, false)
|
|
56
56
|
.map((skinFile) => {
|
|
57
57
|
const localSkin = skinRegister.getData(skinFile);
|
|
58
|
-
localSkin.skin = readFileSync(resolve(aliasSkinDir, skinFile))
|
|
59
|
-
.toString()
|
|
60
|
-
.replace(/\r\n/g, "\n");
|
|
58
|
+
localSkin.skin = readFileSync(resolve(aliasSkinDir, skinFile)).toString().replace(/\r\n/g, '\n');
|
|
61
59
|
return localSkin;
|
|
62
60
|
})
|
|
63
61
|
.sort(skinsByName);
|
|
@@ -85,7 +83,7 @@ const compareLocalToRemoteSkins = async (td, aliases) => {
|
|
|
85
83
|
if (lName === rName) {
|
|
86
84
|
console.log(chalk.white(`Processing skin ${chalk.italic(lName)}`));
|
|
87
85
|
let skinDiff = td.diffSkin(lName, remoteSkinData[r], localSkinData[l]);
|
|
88
|
-
skinView.class = skinDiff.skinChanged ?
|
|
86
|
+
skinView.class = skinDiff.skinChanged ? 'different' : 'identical';
|
|
89
87
|
skinView.open = skinDiff.skinChanged;
|
|
90
88
|
skinView.text = `${skinDiff.skinName} is ${skinView.class}.`;
|
|
91
89
|
skinView.results = skinDiff.results;
|
|
@@ -94,12 +92,12 @@ const compareLocalToRemoteSkins = async (td, aliases) => {
|
|
|
94
92
|
} else {
|
|
95
93
|
if (lName < rName) {
|
|
96
94
|
skinView.text = `Local skin ${lName} missing on remote. Will be created upon update!`;
|
|
97
|
-
skinView.class =
|
|
95
|
+
skinView.class = 'new';
|
|
98
96
|
l++;
|
|
99
97
|
} else {
|
|
100
98
|
// lName > rName
|
|
101
99
|
skinView.text = `Remote skin ${rName} without local counterpart. Will remain untouched upon update!`;
|
|
102
|
-
skinView.class =
|
|
100
|
+
skinView.class = 'untouched';
|
|
103
101
|
r++;
|
|
104
102
|
}
|
|
105
103
|
console.log(chalk[classToColor[skinView.class]](skinView.text));
|
|
@@ -109,21 +107,16 @@ const compareLocalToRemoteSkins = async (td, aliases) => {
|
|
|
109
107
|
alpineView.aliases.push(aliasView);
|
|
110
108
|
}
|
|
111
109
|
|
|
110
|
+
writeFileSync(resolve(process.cwd(), './src/template.json'), JSON.stringify(alpineView, null, 2));
|
|
111
|
+
const alpineTemplate = readFileSync(resolve(process.cwd(), './src/template.html')).toString().trim();
|
|
112
112
|
writeFileSync(
|
|
113
|
-
resolve(process.cwd(),
|
|
114
|
-
JSON.stringify(alpineView, null, 2)
|
|
115
|
-
);
|
|
116
|
-
const alpineTemplate = readFileSync(resolve(process.cwd(), "./src/template.html"))
|
|
117
|
-
.toString()
|
|
118
|
-
.trim();
|
|
119
|
-
writeFileSync(
|
|
120
|
-
resolve(process.cwd(), "./report.html"),
|
|
121
|
-
alpineTemplate.replace("$$templateJSON", `(${JSON.stringify(alpineView, null, 2)})`),
|
|
113
|
+
resolve(process.cwd(), './report.html'),
|
|
114
|
+
alpineTemplate.replace('$$templateJSON', `(${JSON.stringify(alpineView, null, 2)})`)
|
|
122
115
|
);
|
|
123
116
|
|
|
124
|
-
console.log(chalk.green(
|
|
117
|
+
console.log(chalk.green('Local/Remote comparison completed.'));
|
|
125
118
|
} catch (e) {
|
|
126
|
-
console.log(chalk.red(`Error while comparing skins: ${e}`));
|
|
119
|
+
console.log(chalk.red(`Error while comparing skins: ${e.toString()}`));
|
|
127
120
|
}
|
|
128
121
|
};
|
|
129
122
|
|
package/src/_download.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
|
+
|
|
1
4
|
/**
|
|
2
5
|
* Download
|
|
3
6
|
* ========
|
|
4
7
|
*
|
|
5
8
|
*/
|
|
6
|
-
import chalk from
|
|
7
|
-
|
|
8
|
-
import {
|
|
9
|
-
import { aliasSkinFolder, skinRegister } from "./_utils.js";
|
|
9
|
+
import chalk from 'chalk';
|
|
10
|
+
|
|
11
|
+
import { aliasSkinFolder, skinRegister } from './_utils.js';
|
|
10
12
|
|
|
11
13
|
const capitalize = (text) => text.charAt(0).toUpperCase() + text.slice(1);
|
|
12
14
|
|
|
@@ -21,7 +23,7 @@ const findEmbeddedSkinMacros = async (td, alias, skinContent, skinContainer) =>
|
|
|
21
23
|
const layoutUrl = await td.getActiveLayoutUrl(alias);
|
|
22
24
|
const { skin } = await td.getSkin({
|
|
23
25
|
name: skinName,
|
|
24
|
-
url: `${layoutUrl}/skins/edit?key=${skinName}
|
|
26
|
+
url: `${layoutUrl}/skins/edit?key=${skinName}`
|
|
25
27
|
});
|
|
26
28
|
skinContainer[skinName] = skin;
|
|
27
29
|
skinContainer = await findEmbeddedSkinMacros(td, alias, skin, skinContainer);
|
|
@@ -54,9 +56,7 @@ const downloadModifiedSkins = async (td, aliases, options) => {
|
|
|
54
56
|
|
|
55
57
|
if (modifiedSkins.length && !existsSync(aliasSkinDir)) mkdirSync(aliasSkinDir);
|
|
56
58
|
console.log(
|
|
57
|
-
chalk.yellow(
|
|
58
|
-
`${alias} has ${modifiedSkins.length} modified skin${modifiedSkins.length !== 1 ? "s" : ""}`,
|
|
59
|
-
),
|
|
59
|
+
chalk.yellow(`${alias} has ${modifiedSkins.length} modified skin${modifiedSkins.length !== 1 ? 's' : ''}`)
|
|
60
60
|
);
|
|
61
61
|
if (options.skin) console.log(chalk.yellow(`Filtering skins for ${options.skin}.`));
|
|
62
62
|
|
|
@@ -92,12 +92,12 @@ const downloadModifiedSkins = async (td, aliases, options) => {
|
|
|
92
92
|
|
|
93
93
|
if (options.toolbar) {
|
|
94
94
|
const layoutUrl = await td.getActiveLayoutUrl(alias);
|
|
95
|
-
for (const s of [
|
|
95
|
+
for (const s of ['Main', 'DropDowns', 'Closed']) {
|
|
96
96
|
const name = `Site.modToolbar${s}`;
|
|
97
97
|
console.log(chalk.gray(`Reading "${name}".`));
|
|
98
98
|
const { title, description, skin } = await td.getSkin({
|
|
99
99
|
name,
|
|
100
|
-
url: `${layoutUrl}/skins/edit?key=${name}
|
|
100
|
+
url: `${layoutUrl}/skins/edit?key=${name}`
|
|
101
101
|
});
|
|
102
102
|
skinRegister.setData(name, title, description);
|
|
103
103
|
skinContainer[name] = skin;
|
|
@@ -108,9 +108,9 @@ const downloadModifiedSkins = async (td, aliases, options) => {
|
|
|
108
108
|
writeFileSync(resolve(aliasSkinDir, `${name}.skin`), content);
|
|
109
109
|
}
|
|
110
110
|
}
|
|
111
|
-
console.log(chalk.green(
|
|
111
|
+
console.log(chalk.green('Download completed.'));
|
|
112
112
|
} catch (e) {
|
|
113
|
-
console.log(chalk.red(`Error while downloading skins: ${e}`));
|
|
113
|
+
console.log(chalk.red(`Error while downloading skins: ${e.toString()}`));
|
|
114
114
|
} finally {
|
|
115
115
|
skinRegister.store();
|
|
116
116
|
}
|
package/src/_upload.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
|
+
|
|
1
4
|
/**
|
|
2
5
|
* Upload
|
|
3
6
|
* ======
|
|
4
7
|
*
|
|
5
8
|
*/
|
|
6
|
-
import chalk from
|
|
7
|
-
|
|
8
|
-
import {
|
|
9
|
-
import { aliasSkinFolder, getLocalSkins, skinRegister } from "./_utils.js";
|
|
9
|
+
import chalk from 'chalk';
|
|
10
|
+
|
|
11
|
+
import { aliasSkinFolder, getLocalSkins, skinRegister } from './_utils.js';
|
|
10
12
|
|
|
11
13
|
/**
|
|
12
14
|
* Uploads all local skins of selected aliases to the target platform
|
|
@@ -29,7 +31,7 @@ const uploadModifiedSkins = async (td, aliases, options) => {
|
|
|
29
31
|
const localSkinFiles = getLocalSkins(alias, options.backup);
|
|
30
32
|
console.log(
|
|
31
33
|
chalk.yellow(`${alias} has ${localSkinFiles.length} local skins. `) +
|
|
32
|
-
chalk.red(`${localSkinFiles.length === 0 ?
|
|
34
|
+
chalk.red(`${localSkinFiles.length === 0 ? 'Got nothing to do!' : ''}`)
|
|
33
35
|
);
|
|
34
36
|
if (options.skin) console.log(chalk.yellow(`Filtering skins for ${options.skin}.`));
|
|
35
37
|
|
|
@@ -38,15 +40,13 @@ const uploadModifiedSkins = async (td, aliases, options) => {
|
|
|
38
40
|
const aliasSkinDir = aliasSkinFolder(alias, options.backup);
|
|
39
41
|
|
|
40
42
|
for (let skinFile of localSkinFiles) {
|
|
41
|
-
if (!skinFile.endsWith(
|
|
43
|
+
if (!skinFile.endsWith('.skin')) continue;
|
|
42
44
|
if (options.skin && !options.skin.test(skinFile)) continue;
|
|
43
45
|
|
|
44
|
-
const [hoptype, name] = skinFile.split(
|
|
45
|
-
if (hoptype ===
|
|
46
|
-
const module = readFileSync(resolve(aliasSkinDir, skinFile))
|
|
47
|
-
|
|
48
|
-
.replace(/\r\n/g, "\n");
|
|
49
|
-
let splitAt = module.indexOf("\n");
|
|
46
|
+
const [hoptype, name] = skinFile.split('.');
|
|
47
|
+
if (hoptype === 'Sidebar') {
|
|
48
|
+
const module = readFileSync(resolve(aliasSkinDir, skinFile)).toString().replace(/\r\n/g, '\n');
|
|
49
|
+
let splitAt = module.indexOf('\n');
|
|
50
50
|
const heading = module.slice(0, splitAt);
|
|
51
51
|
const content = module.slice(++splitAt);
|
|
52
52
|
console.log(chalk.blue(`Now updating sidebar module ${name} (len=${content.length}).`));
|
|
@@ -55,24 +55,18 @@ const uploadModifiedSkins = async (td, aliases, options) => {
|
|
|
55
55
|
} else {
|
|
56
56
|
const { isValid, prototype } = td.isValidHoptype(skinFile.slice(0, -5));
|
|
57
57
|
if (!isValid) {
|
|
58
|
-
console.log(
|
|
59
|
-
chalk.red(
|
|
60
|
-
`Skipping upload for invalid skin hoptype "${prototype}" (Skin file ${skinFile}).`,
|
|
61
|
-
),
|
|
62
|
-
);
|
|
58
|
+
console.log(chalk.red(`Skipping upload for invalid skin hoptype "${prototype}" (Skin file ${skinFile}).`));
|
|
63
59
|
continue;
|
|
64
60
|
}
|
|
65
61
|
const skin = skinRegister.getData(skinFile);
|
|
66
|
-
skin.content = readFileSync(resolve(aliasSkinDir, skinFile))
|
|
67
|
-
.toString()
|
|
68
|
-
.replace(/\r\n/g, "\n");
|
|
62
|
+
skin.content = readFileSync(resolve(aliasSkinDir, skinFile)).toString().replace(/\r\n/g, '\n');
|
|
69
63
|
|
|
70
64
|
console.log(chalk.blue(`Now updating skin ${skin.name} (len=${skin.content.length}).`));
|
|
71
65
|
await td.updateSkin(alias, skin.name, {
|
|
72
66
|
title: skin.title,
|
|
73
67
|
description: skin.description,
|
|
74
68
|
skin: skin.content,
|
|
75
|
-
diff: options.debug
|
|
69
|
+
diff: options.debug
|
|
76
70
|
});
|
|
77
71
|
console.log(chalk.green(`Update request completed for skin: ${skin.name}`));
|
|
78
72
|
}
|
|
@@ -81,15 +75,13 @@ const uploadModifiedSkins = async (td, aliases, options) => {
|
|
|
81
75
|
}
|
|
82
76
|
|
|
83
77
|
if (currentSkins.size > 0) {
|
|
84
|
-
console.log(
|
|
85
|
-
chalk.blue(`\nFollowing skins exist on "${alias}" and were not touched by this upload:`),
|
|
86
|
-
);
|
|
78
|
+
console.log(chalk.blue(`\nFollowing skins exist on "${alias}" and were not touched by this upload:`));
|
|
87
79
|
currentSkins.forEach((skinName) => console.log(`--> ${chalk.blue(skinName)}`));
|
|
88
80
|
}
|
|
89
81
|
}
|
|
90
|
-
console.log(chalk.green(
|
|
82
|
+
console.log(chalk.green('Upload completed.'));
|
|
91
83
|
} catch (e) {
|
|
92
|
-
console.log(chalk.red(`Error while uploading skins: ${e}`));
|
|
84
|
+
console.log(chalk.red(`Error while uploading skins: ${e.toString()}`));
|
|
93
85
|
}
|
|
94
86
|
};
|
|
95
87
|
|
package/src/_utils.js
CHANGED
|
@@ -1,23 +1,22 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync, readdirSync } from 'node:fs';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
|
+
|
|
1
4
|
/**
|
|
2
5
|
* Utility functions
|
|
3
6
|
* =================
|
|
4
7
|
*
|
|
5
8
|
*/
|
|
6
|
-
import { deleteSync } from
|
|
7
|
-
import { existsSync, readFileSync, writeFileSync, readdirSync } from "node:fs";
|
|
8
|
-
import { resolve } from "node:path";
|
|
9
|
+
import { deleteSync } from 'del';
|
|
9
10
|
|
|
10
11
|
// Read centrally stored skin header data (name => title, description)
|
|
11
|
-
const skinsFolder = resolve(process.cwd(),
|
|
12
|
-
const backupFolder = resolve(process.cwd(),
|
|
13
|
-
const pathToRegister = resolve(skinsFolder,
|
|
12
|
+
const skinsFolder = resolve(process.cwd(), 'skins');
|
|
13
|
+
const backupFolder = resolve(process.cwd(), 'backup');
|
|
14
|
+
const pathToRegister = resolve(skinsFolder, 'skinRegister.json');
|
|
14
15
|
const skinRegister = {
|
|
15
16
|
data: undefined,
|
|
16
17
|
hasChanged: false,
|
|
17
18
|
load() {
|
|
18
|
-
this.data = existsSync(pathToRegister)
|
|
19
|
-
? JSON.parse(readFileSync(pathToRegister).toString())
|
|
20
|
-
: {};
|
|
19
|
+
this.data = existsSync(pathToRegister) ? JSON.parse(readFileSync(pathToRegister).toString()) : {};
|
|
21
20
|
return this.data;
|
|
22
21
|
},
|
|
23
22
|
store() {
|
|
@@ -27,17 +26,17 @@ const skinRegister = {
|
|
|
27
26
|
}
|
|
28
27
|
},
|
|
29
28
|
hasData(skinName) {
|
|
30
|
-
if (typeof this.data ===
|
|
29
|
+
if (typeof this.data === 'undefined') this.load();
|
|
31
30
|
return this.data.hasOwnProperty(skinName);
|
|
32
31
|
},
|
|
33
32
|
getData(skinFileOrName) {
|
|
34
|
-
const name = skinFileOrName.endsWith(
|
|
33
|
+
const name = skinFileOrName.endsWith('.skin')
|
|
35
34
|
? skinFileOrName.substr(0, skinFileOrName.length - 5)
|
|
36
35
|
: skinFileOrName;
|
|
37
36
|
if (this.hasData(name)) {
|
|
38
37
|
const { title, description } = this.data[name];
|
|
39
38
|
return { name, title, description };
|
|
40
|
-
} else return { name, title: name, description:
|
|
39
|
+
} else return { name, title: name, description: '' };
|
|
41
40
|
},
|
|
42
41
|
setData(skinName, title, description) {
|
|
43
42
|
if (!this.hasData(skinName)) {
|
|
@@ -47,7 +46,7 @@ const skinRegister = {
|
|
|
47
46
|
},
|
|
48
47
|
deleteData(skinName) {
|
|
49
48
|
if (this.hasData(skinName)) delete this.data[skinName];
|
|
50
|
-
}
|
|
49
|
+
}
|
|
51
50
|
};
|
|
52
51
|
|
|
53
52
|
/**
|
|
@@ -65,7 +64,7 @@ const aliasSkinFolder = (alias, isBackup) => resolve(isBackup ? backupFolder : s
|
|
|
65
64
|
*/
|
|
66
65
|
const cleanupAliasFolder = (aliases, isBackup) => {
|
|
67
66
|
try {
|
|
68
|
-
deleteSync(aliases.map((alias) => resolve(aliasSkinFolder(alias, isBackup),
|
|
67
|
+
deleteSync(aliases.map((alias) => resolve(aliasSkinFolder(alias, isBackup), '*.skin')));
|
|
69
68
|
} catch (err) {
|
|
70
69
|
console.log(`cleanupAliasFolder ended with error: ${err.toString()}.`);
|
|
71
70
|
process.exit(1);
|
|
@@ -79,9 +78,7 @@ const cleanupAliasFolder = (aliases, isBackup) => {
|
|
|
79
78
|
*/
|
|
80
79
|
const getLocalSkins = (alias, isBackup) => {
|
|
81
80
|
const aliasSkinDir = aliasSkinFolder(alias, isBackup);
|
|
82
|
-
return existsSync(aliasSkinDir)
|
|
83
|
-
? readdirSync(aliasSkinDir).filter((file) => file.endsWith(".skin"))
|
|
84
|
-
: [];
|
|
81
|
+
return existsSync(aliasSkinDir) ? readdirSync(aliasSkinDir).filter((file) => file.endsWith('.skin')) : [];
|
|
85
82
|
};
|
|
86
83
|
|
|
87
84
|
/**
|
|
@@ -97,11 +94,4 @@ const splitAliases = (aliases, delimiter) => {
|
|
|
97
94
|
.map((alias) => alias.toLowerCase());
|
|
98
95
|
};
|
|
99
96
|
|
|
100
|
-
export {
|
|
101
|
-
pathToRegister,
|
|
102
|
-
skinRegister,
|
|
103
|
-
aliasSkinFolder,
|
|
104
|
-
cleanupAliasFolder,
|
|
105
|
-
getLocalSkins,
|
|
106
|
-
splitAliases,
|
|
107
|
-
};
|
|
97
|
+
export { pathToRegister, skinRegister, aliasSkinFolder, cleanupAliasFolder, getLocalSkins, splitAliases };
|
package/src/create.js
CHANGED
|
@@ -1,65 +1,63 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
|
|
4
|
+
import * as Twoday from '@neonwilderness/twoday';
|
|
5
|
+
import chalk from 'chalk';
|
|
1
6
|
/**
|
|
2
7
|
* Creates a new skin locally
|
|
3
8
|
*/
|
|
4
|
-
import yargs from
|
|
5
|
-
|
|
6
|
-
import
|
|
7
|
-
import path from "node:path";
|
|
8
|
-
import * as Twoday from "@neonwilderness/twoday";
|
|
9
|
-
import { skinRegister } from "./_utils.js";
|
|
9
|
+
import yargs from 'yargs/yargs';
|
|
10
|
+
|
|
11
|
+
import { skinRegister } from './_utils.js';
|
|
10
12
|
const argv = yargs(process.argv.slice(2)).argv;
|
|
11
13
|
|
|
12
14
|
// Validates script param --alias (blog name/alias)
|
|
13
15
|
if (!argv.alias) {
|
|
14
|
-
console.log(chalk.red(
|
|
16
|
+
console.log(chalk.red('Error: You must specify a blogname alias with --alias={alias} !!'));
|
|
15
17
|
process.exit(1);
|
|
16
18
|
}
|
|
17
19
|
const alias = argv.alias.trim().toLowerCase();
|
|
18
20
|
|
|
19
21
|
// Validates script param --skin (skin name to be created)
|
|
20
22
|
if (!argv.skin) {
|
|
21
|
-
console.log(
|
|
22
|
-
|
|
23
|
-
);
|
|
24
|
-
console.log(chalk.blue("Example: node ./src/create --alias=info --skin=Site.mynewskin"));
|
|
23
|
+
console.log(chalk.red('Error: You must specify a skin name to be created with --skin={skinname} !!'));
|
|
24
|
+
console.log(chalk.blue('Example: node ./src/create --alias=info --skin=Site.mynewskin'));
|
|
25
25
|
process.exit(1);
|
|
26
26
|
}
|
|
27
27
|
const skinName = argv.skin;
|
|
28
28
|
|
|
29
29
|
// Validates skin name syntax (must have 2 strings around a dot)
|
|
30
|
-
const nameParts = skinName.split(
|
|
30
|
+
const nameParts = skinName.split('.').reduce((all, part) => {
|
|
31
31
|
if (part.trim().length) all.push(part);
|
|
32
32
|
return all;
|
|
33
33
|
}, []);
|
|
34
34
|
if (nameParts.length !== 2) {
|
|
35
35
|
console.log(chalk.red(`Error: Wrong skin name syntax "${skinName}" !!`));
|
|
36
|
-
console.log(chalk.blue(
|
|
36
|
+
console.log(chalk.blue('Use skin name syntax: --skin={hoptype}.{name}'));
|
|
37
37
|
process.exit(1);
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
// Main async function to validate hoptype, register the skin and create the physical skin file
|
|
41
41
|
(async () => {
|
|
42
42
|
try {
|
|
43
|
-
const td = new Twoday.Twoday(
|
|
43
|
+
const td = new Twoday.Twoday('prod');
|
|
44
44
|
const { valid, prototype, _name } = await td.isValidHoptype(skinName);
|
|
45
45
|
|
|
46
46
|
if (!valid) {
|
|
47
|
-
console.log(
|
|
48
|
-
chalk.red(`Error: Sorry, there is no Hoptype "${prototype}" in the Twoday code base!!`),
|
|
49
|
-
);
|
|
47
|
+
console.log(chalk.red(`Error: Sorry, there is no Hoptype "${prototype}" in the Twoday code base!!`));
|
|
50
48
|
process.exit(1);
|
|
51
49
|
}
|
|
52
50
|
|
|
53
51
|
skinRegister.load();
|
|
54
|
-
const newSkin =
|
|
52
|
+
const newSkin = '(new skin)';
|
|
55
53
|
skinRegister.setData(skinName, `${skinName} ${newSkin}`, `${newSkin}`);
|
|
56
54
|
skinRegister.store();
|
|
57
55
|
|
|
58
|
-
const dir = path.resolve(process.cwd(),
|
|
56
|
+
const dir = path.resolve(process.cwd(), 'skins', alias);
|
|
59
57
|
if (!fs.existsSync(dir)) fs.mkdirSync(dir);
|
|
60
58
|
fs.writeFileSync(path.resolve(dir, `${skinName}.skin`), `<p><!-- ${newSkin} --></p>\n`);
|
|
61
59
|
console.log(chalk.green(`New skin "${skinName}" successfully established in /skins/${alias}.`));
|
|
62
60
|
} catch (e) {
|
|
63
|
-
console.log(chalk.red(`An error occured while creating the new skin "${skinName}": ${e}`));
|
|
61
|
+
console.log(chalk.red(`An error occured while creating the new skin "${skinName}": ${e.toString()}`));
|
|
64
62
|
}
|
|
65
63
|
})();
|
package/src/images.js
CHANGED
|
@@ -1,24 +1,25 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
|
|
4
|
+
import * as Twoday from '@neonwilderness/twoday';
|
|
5
|
+
import chalk from 'chalk';
|
|
6
|
+
import { config } from 'dotenv-safe';
|
|
1
7
|
/**
|
|
2
8
|
* Upload /skins/{alias}/images items to create layout images
|
|
3
9
|
*/
|
|
4
|
-
import yargs from
|
|
5
|
-
import chalk from "chalk";
|
|
6
|
-
import fs from "node:fs";
|
|
7
|
-
import path from "node:path";
|
|
8
|
-
import * as Twoday from "@neonwilderness/twoday";
|
|
9
|
-
import { config } from "dotenv-safe";
|
|
10
|
+
import yargs from 'yargs/yargs';
|
|
10
11
|
config();
|
|
11
12
|
const argv = yargs(process.argv.slice(2)).argv;
|
|
12
13
|
|
|
13
14
|
// Validates script param --alias (blog name/alias)
|
|
14
15
|
if (!argv.alias) {
|
|
15
|
-
console.log(chalk.red(
|
|
16
|
+
console.log(chalk.red('Error: You must specify a blogname alias with --alias={alias} !!'));
|
|
16
17
|
process.exit(1);
|
|
17
18
|
}
|
|
18
19
|
const alias = argv.alias.trim().toLowerCase();
|
|
19
20
|
|
|
20
|
-
if (!argv.to || (argv.to !==
|
|
21
|
-
console.log(
|
|
21
|
+
if (!argv.to || (argv.to !== 'dev' && argv.to !== 'prod')) {
|
|
22
|
+
console.log('Error: You must specify a target platform with --to=dev|prod');
|
|
22
23
|
process.exit(1);
|
|
23
24
|
}
|
|
24
25
|
const platform = argv.to.toLowerCase();
|
|
@@ -28,7 +29,7 @@ const platform = argv.to.toLowerCase();
|
|
|
28
29
|
const td = new Twoday.Twoday(platform);
|
|
29
30
|
await td.login();
|
|
30
31
|
|
|
31
|
-
const imageFolder = path.resolve(process.cwd(),
|
|
32
|
+
const imageFolder = path.resolve(process.cwd(), 'skins', alias, 'images');
|
|
32
33
|
if (!fs.existsSync(imageFolder)) {
|
|
33
34
|
console.log(chalk.red(`Error: image folder for alias ${alias} does not exist!!`));
|
|
34
35
|
process.exit(1);
|
|
@@ -37,18 +38,18 @@ const platform = argv.to.toLowerCase();
|
|
|
37
38
|
const images = fs.readdirSync(imageFolder);
|
|
38
39
|
let uploaded = 0;
|
|
39
40
|
for (const image of images) {
|
|
40
|
-
const [name, _ext] = image.split(
|
|
41
|
-
if (name.startsWith(
|
|
41
|
+
const [name, _ext] = image.split('.');
|
|
42
|
+
if (name.startsWith('_')) continue;
|
|
42
43
|
const imgID = await td.createImage(alias, {
|
|
43
44
|
alias: name,
|
|
44
|
-
path: path.resolve(imageFolder, image)
|
|
45
|
+
path: path.resolve(imageFolder, image)
|
|
45
46
|
});
|
|
46
47
|
uploaded++;
|
|
47
48
|
console.log(chalk.green(`New image "${image}" =>${imgID} saved.`));
|
|
48
49
|
}
|
|
49
50
|
console.log(chalk.blue(`${uploaded} images uploaded to alias "${alias}".`));
|
|
50
51
|
} catch (e) {
|
|
51
|
-
console.log(chalk.red(`Error while creating images for alias "${alias}": ${e}`));
|
|
52
|
+
console.log(chalk.red(`Error while creating images for alias "${alias}": ${e.toString()}`));
|
|
52
53
|
} finally {
|
|
53
54
|
await td.logout();
|
|
54
55
|
}
|
package/src/index.js
CHANGED
|
@@ -11,127 +11,127 @@
|
|
|
11
11
|
* An Alias of * is equal to the core Twoday blogs: www,info,help,top
|
|
12
12
|
* User/Psw in .env file needs to have admin rights on the selected alias(es) or it won't work!
|
|
13
13
|
*/
|
|
14
|
-
import yargs from
|
|
14
|
+
import yargs from 'yargs/yargs';
|
|
15
15
|
const argv = yargs(process.argv.slice(2)).options({
|
|
16
16
|
from: {
|
|
17
|
-
alias:
|
|
17
|
+
alias: 'f',
|
|
18
18
|
description: 'Platform where to download the skins from: "dev" or "prod"',
|
|
19
|
-
type:
|
|
19
|
+
type: 'string'
|
|
20
20
|
},
|
|
21
21
|
to: {
|
|
22
|
-
alias:
|
|
22
|
+
alias: 't',
|
|
23
23
|
description: 'Platform where to compare or upload the skins to: "dev" or "prod"',
|
|
24
|
-
type:
|
|
24
|
+
type: 'string'
|
|
25
25
|
},
|
|
26
26
|
alias: {
|
|
27
|
-
alias:
|
|
28
|
-
description:
|
|
29
|
-
type:
|
|
27
|
+
alias: 'a',
|
|
28
|
+
description: 'One or more alias blog name/s delimited by comma (no space)',
|
|
29
|
+
type: 'string'
|
|
30
30
|
},
|
|
31
31
|
skin: {
|
|
32
|
-
alias:
|
|
33
|
-
description:
|
|
34
|
-
type:
|
|
32
|
+
alias: 's',
|
|
33
|
+
description: 'Skin selection string (regex) to filter the skins to upload',
|
|
34
|
+
type: 'string'
|
|
35
35
|
},
|
|
36
36
|
layout: {
|
|
37
|
-
alias:
|
|
38
|
-
description:
|
|
37
|
+
alias: 'l',
|
|
38
|
+
description: 'Uses this layout name for all subsequent actions',
|
|
39
39
|
default: '',
|
|
40
|
-
type:
|
|
40
|
+
type: 'string'
|
|
41
41
|
},
|
|
42
42
|
modules: {
|
|
43
|
-
alias:
|
|
44
|
-
description:
|
|
43
|
+
alias: 'm',
|
|
44
|
+
description: 'Download sidebar module skins/freetext as well',
|
|
45
45
|
default: false,
|
|
46
|
-
type:
|
|
46
|
+
type: 'boolean'
|
|
47
47
|
},
|
|
48
48
|
toolbar: {
|
|
49
|
-
description:
|
|
49
|
+
description: 'Download modToolbar skins, too',
|
|
50
50
|
default: false,
|
|
51
|
-
type:
|
|
51
|
+
type: 'boolean'
|
|
52
52
|
},
|
|
53
53
|
backup: {
|
|
54
|
-
alias:
|
|
55
|
-
description:
|
|
56
|
-
type:
|
|
54
|
+
alias: 'b',
|
|
55
|
+
description: 'Backup skins to the local /backup folder to preserve their former status',
|
|
56
|
+
type: 'boolean'
|
|
57
57
|
},
|
|
58
58
|
clean: {
|
|
59
59
|
default: false,
|
|
60
|
-
description:
|
|
61
|
-
|
|
62
|
-
type: "boolean",
|
|
60
|
+
description: 'Cleanup (delete) the alias local skin directory to remove potential old files before new download',
|
|
61
|
+
type: 'boolean'
|
|
63
62
|
},
|
|
64
63
|
compare: {
|
|
65
64
|
default: false,
|
|
66
|
-
description:
|
|
67
|
-
type:
|
|
65
|
+
description: 'Compare the local alias skin directory to a remote location (prod/dev)',
|
|
66
|
+
type: 'boolean'
|
|
68
67
|
},
|
|
69
68
|
debug: {
|
|
70
69
|
default: false,
|
|
71
|
-
description:
|
|
72
|
-
type:
|
|
73
|
-
}
|
|
70
|
+
description: 'Issue more logging messages and diff analysis (for upload function)',
|
|
71
|
+
type: 'boolean'
|
|
72
|
+
}
|
|
74
73
|
}).argv;
|
|
75
|
-
import
|
|
76
|
-
import
|
|
77
|
-
import {
|
|
78
|
-
|
|
79
|
-
import {
|
|
80
|
-
import {
|
|
81
|
-
import {
|
|
74
|
+
import * as Twoday from '@neonwilderness/twoday';
|
|
75
|
+
import chalk from 'chalk';
|
|
76
|
+
import { config } from 'dotenv-safe';
|
|
77
|
+
|
|
78
|
+
import { compareLocalToRemoteSkins } from './_compare.js';
|
|
79
|
+
import { downloadModifiedSkins } from './_download.js';
|
|
80
|
+
import { uploadModifiedSkins } from './_upload.js';
|
|
81
|
+
import { cleanupAliasFolder, splitAliases } from './_utils.js';
|
|
82
82
|
config();
|
|
83
83
|
|
|
84
84
|
if (!argv.from && !argv.to) {
|
|
85
|
-
console.log(
|
|
85
|
+
console.log('Desired action must be specified with --from=dev|prod or --to=dev|prod');
|
|
86
86
|
process.exit(1);
|
|
87
87
|
}
|
|
88
88
|
if (argv.from && argv.to) {
|
|
89
|
-
console.log(
|
|
89
|
+
console.log('You cannot specify --from=dev|prod AND --to=dev|prod in one run');
|
|
90
90
|
process.exit(1);
|
|
91
91
|
}
|
|
92
92
|
if (argv.compare && !argv.to) {
|
|
93
|
-
console.log(
|
|
93
|
+
console.log('You must specify a target platform with --to=dev|prod when comparing skins');
|
|
94
94
|
process.exit(1);
|
|
95
95
|
}
|
|
96
96
|
if (!argv.alias) {
|
|
97
|
-
console.log(
|
|
97
|
+
console.log('You must specify the desired alias(es) with --alias=name1[,name2,...] OR --alias=*');
|
|
98
98
|
process.exit(1);
|
|
99
99
|
}
|
|
100
100
|
const platform = (argv.from || argv.to).toLowerCase();
|
|
101
101
|
const td = new Twoday.Twoday(platform, { delay: 100 });
|
|
102
102
|
|
|
103
|
-
const core = [
|
|
104
|
-
const aliases = argv.alias ===
|
|
103
|
+
const core = ['www', 'info', 'help', 'top'];
|
|
104
|
+
const aliases = argv.alias === '*' ? core : splitAliases(argv.alias, ',');
|
|
105
105
|
|
|
106
106
|
if (argv.compare) {
|
|
107
|
-
if (aliases.length === 1 && aliases[0].includes(
|
|
107
|
+
if (aliases.length === 1 && aliases[0].includes(':'))
|
|
108
108
|
console.log(
|
|
109
|
-
`Start comparing local skin files of alias${aliases.length > 1 ?
|
|
110
|
-
aliases.join(
|
|
111
|
-
)} to ${chalk.green(td.fullDomain)}
|
|
109
|
+
`Start comparing local skin files of alias${aliases.length > 1 ? 'es' : ''} ${chalk.yellow(
|
|
110
|
+
aliases.join(', ')
|
|
111
|
+
)} to ${chalk.green(td.fullDomain)}...`
|
|
112
112
|
);
|
|
113
|
-
compareLocalToRemoteSkins(td, aliases);
|
|
113
|
+
await compareLocalToRemoteSkins(td, aliases);
|
|
114
114
|
} else {
|
|
115
|
-
const action = argv.from ?
|
|
116
|
-
const direction = argv.from ?
|
|
115
|
+
const action = argv.from ? 'down' : 'up';
|
|
116
|
+
const direction = argv.from ? 'from' : 'to';
|
|
117
117
|
const execTask = argv.from ? downloadModifiedSkins : uploadModifiedSkins;
|
|
118
118
|
|
|
119
|
-
if (action ===
|
|
119
|
+
if (action === 'down' && argv.clean) {
|
|
120
120
|
cleanupAliasFolder(aliases, argv.backup);
|
|
121
|
-
console.log(chalk.yellow(`Cleaning target download folder/s for "${aliases}".`));
|
|
121
|
+
console.log(chalk.yellow(`Cleaning target download folder/s for "${aliases.join(', ')}".`));
|
|
122
122
|
}
|
|
123
123
|
|
|
124
124
|
console.log(
|
|
125
|
-
`Start ${action}loading modified skins of alias${aliases.length > 1 ?
|
|
126
|
-
aliases.join(
|
|
127
|
-
)} ${direction} remote ${chalk.green(td.fullDomain)}
|
|
125
|
+
`Start ${action}loading modified skins of alias${aliases.length > 1 ? 'es' : ''} ${chalk.yellow(
|
|
126
|
+
aliases.join(', ')
|
|
127
|
+
)} ${direction} remote ${chalk.green(td.fullDomain)}...`
|
|
128
128
|
);
|
|
129
|
-
execTask(td, aliases, {
|
|
129
|
+
await execTask(td, aliases, {
|
|
130
130
|
backup: argv.backup,
|
|
131
131
|
debug: argv.debug,
|
|
132
132
|
layout: argv.layout,
|
|
133
133
|
modules: argv.modules,
|
|
134
134
|
skin: argv.skin ? new RegExp(argv.skin) : null,
|
|
135
|
-
toolbar: argv.toolbar
|
|
135
|
+
toolbar: argv.toolbar
|
|
136
136
|
});
|
|
137
137
|
}
|
package/src/template.html
CHANGED
|
@@ -28,11 +28,11 @@
|
|
|
28
28
|
text-align: center;
|
|
29
29
|
}
|
|
30
30
|
del::before {
|
|
31
|
-
content:
|
|
31
|
+
content: '–';
|
|
32
32
|
background: #fdb9c1;
|
|
33
33
|
}
|
|
34
34
|
ins::before {
|
|
35
|
-
content:
|
|
35
|
+
content: '+';
|
|
36
36
|
background: #abf2bc;
|
|
37
37
|
}
|
|
38
38
|
h3 {
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
display: inline-block;
|
|
51
51
|
background: #ddd;
|
|
52
52
|
font-size: 11px;
|
|
53
|
-
content:
|
|
53
|
+
content: 'Skin';
|
|
54
54
|
margin-right: 0.5rem;
|
|
55
55
|
padding: 2px 4px;
|
|
56
56
|
line-height: 1rem;
|
|
@@ -109,10 +109,7 @@
|
|
|
109
109
|
<div class="resultbox" x-show="skin.open && skin.results.length">
|
|
110
110
|
<template x-for="(result, ir) in skin.results" :key="ir">
|
|
111
111
|
<div class="result">
|
|
112
|
-
<div
|
|
113
|
-
:style="{ color: result.itemChanged ? '#e53935' : '#bdbdbd' }"
|
|
114
|
-
x-text="result.text"
|
|
115
|
-
></div>
|
|
112
|
+
<div :style="{ color: result.itemChanged ? '#e53935' : '#bdbdbd' }" x-text="result.text"></div>
|
|
116
113
|
<div class="diffs" x-html="result.diffs.replace(/\n/g, '<br>')"></div>
|
|
117
114
|
</div>
|
|
118
115
|
</template>
|
|
@@ -123,8 +120,8 @@
|
|
|
123
120
|
</template>
|
|
124
121
|
|
|
125
122
|
<script>
|
|
126
|
-
document.addEventListener(
|
|
127
|
-
Alpine.data(
|
|
123
|
+
document.addEventListener('alpine:init', () => {
|
|
124
|
+
Alpine.data('diffResults', () => $$templateJSON);
|
|
128
125
|
});
|
|
129
126
|
</script>
|
|
130
127
|
<script defer src="https://unpkg.com/alpinejs@latest"></script>
|