@neonwilderness/moveskins 1.1.3 → 1.2.0
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 +11 -1
- package/dist/index.js +697 -634
- package/package.json +12 -11
- package/skins/skinRegister.json +4 -0
- package/src/_download.js +49 -1
- package/src/_upload.js +34 -12
- package/src/index.js +11 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@neonwilderness/moveskins",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Download/Upload/Compare modified skins for selected aliases on Twoday",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"antville",
|
|
@@ -10,6 +10,9 @@
|
|
|
10
10
|
],
|
|
11
11
|
"license": "MIT",
|
|
12
12
|
"author": "NeonWilderness",
|
|
13
|
+
"bin": {
|
|
14
|
+
"moveskins": "./dist/index.js"
|
|
15
|
+
},
|
|
13
16
|
"files": [
|
|
14
17
|
"dist",
|
|
15
18
|
"skins/skinRegister.json",
|
|
@@ -22,24 +25,22 @@
|
|
|
22
25
|
],
|
|
23
26
|
"type": "module",
|
|
24
27
|
"exports": "./dist/index.js",
|
|
25
|
-
"bin": {
|
|
26
|
-
"moveskins": "./dist/index.js"
|
|
27
|
-
},
|
|
28
28
|
"scripts": {
|
|
29
29
|
"update": "ncu -u && npm i",
|
|
30
30
|
"backup": "node ./src/index --backup --alias=www --from=prod",
|
|
31
31
|
"dev": "vp run node ./src/index.js",
|
|
32
32
|
"build": "vp build",
|
|
33
33
|
"check": "vp check",
|
|
34
|
+
"check:fix": "vp check --fix",
|
|
34
35
|
"create": "node ./src/create --skin=Site.testskin --alias=talkstraight",
|
|
35
36
|
"//": "For compare function, live-server module must be installed globally!",
|
|
36
37
|
"compare": "node ./src/index --compare --alias=help --to=dev && npm run report",
|
|
37
38
|
"compare:blogs": "node ./src/index --compare --alias=foundation:info --to=prod && npm run report",
|
|
38
|
-
"download": "node ./src/index --alias=
|
|
39
|
+
"download": "node ./src/index --alias=www --from=prod --modules",
|
|
39
40
|
"download2": "node ./src/index --alias=info,help --from=prod",
|
|
40
|
-
"download:clean": "node ./src/index --alias=
|
|
41
|
-
"download:core": "node ./src/index --alias=* --from=prod",
|
|
42
|
-
"download:core:clean": "node ./src/index --alias=* --from=prod --clean",
|
|
41
|
+
"download:clean": "node ./src/index --alias=www --from=prod --clean --modules",
|
|
42
|
+
"download:core": "node ./src/index --alias=* --from=prod --modules",
|
|
43
|
+
"download:core:clean": "node ./src/index --alias=* --from=prod --clean --modules",
|
|
43
44
|
"report": "live-server --open=./report.html --quiet",
|
|
44
45
|
"restore": "node ./src/index --backup --alias=www --to=dev",
|
|
45
46
|
"upload": "node ./src/index --alias=neonwilderness --to=dev",
|
|
@@ -51,16 +52,16 @@
|
|
|
51
52
|
"test:ui": "vp test --ui"
|
|
52
53
|
},
|
|
53
54
|
"dependencies": {
|
|
54
|
-
"@neonwilderness/twoday": "^0.
|
|
55
|
+
"@neonwilderness/twoday": "^0.8.0",
|
|
55
56
|
"chalk": "^5.6.2",
|
|
56
57
|
"del": "^8.0.1",
|
|
57
58
|
"dotenv-safe": "^9.1.0",
|
|
58
59
|
"yargs": "^18.0.0"
|
|
59
60
|
},
|
|
60
61
|
"devDependencies": {
|
|
61
|
-
"@vitest/ui": "4.1.
|
|
62
|
+
"@vitest/ui": "4.1.5",
|
|
62
63
|
"slash": "^5.1.0",
|
|
63
|
-
"vite-plus": "^0.1.
|
|
64
|
+
"vite-plus": "^0.1.19"
|
|
64
65
|
},
|
|
65
66
|
"engines": {
|
|
66
67
|
"node": ">=20"
|
package/skins/skinRegister.json
CHANGED
|
@@ -218,5 +218,9 @@
|
|
|
218
218
|
"Site.flagReasons": {
|
|
219
219
|
"title": "Globale Texte für Beitragsmarkierungen",
|
|
220
220
|
"description": "In diesem Systemskin werden die gültigen Beitragsmarkierungsgründe mit ihren jeweiligen Texten in Deutsch (de) und Englisch (en) hinterlegt."
|
|
221
|
+
},
|
|
222
|
+
"Site.adminnavigation": {
|
|
223
|
+
"title": "Navigationsleiste für Site Administratoren",
|
|
224
|
+
"description": "Dieses Skin beinhaltet die zusätzlichen Navigationselemente für Site Administratoren. (z.B. »Einstellungen bearbeiten«, »Skins bearbeiten«, ...)"
|
|
221
225
|
}
|
|
222
226
|
}
|
package/src/_download.js
CHANGED
|
@@ -8,6 +8,28 @@ import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
|
8
8
|
import { resolve } from "node:path";
|
|
9
9
|
import { aliasSkinFolder, skinRegister } from "./_utils.js";
|
|
10
10
|
|
|
11
|
+
const capitalize = (text) => text.charAt(0).toUpperCase() + text.slice(1);
|
|
12
|
+
|
|
13
|
+
const findEmbeddedSkinMacros = async (td, alias, skinContent, skinContainer) => {
|
|
14
|
+
const skinMacros = skinContent.match(/<%\s.*?\.skin name=".*?"\s%>/g);
|
|
15
|
+
if (skinMacros) {
|
|
16
|
+
for (let macro of skinMacros) {
|
|
17
|
+
// example: '<% Site.skin name="legalRefs" %>'
|
|
18
|
+
const s = macro.match(/(\w+)\.skin name="(\w+)"/);
|
|
19
|
+
if (!s) continue;
|
|
20
|
+
const skinName = `${capitalize(s[1])}.${s[2]}`;
|
|
21
|
+
const layoutUrl = await td.getActiveLayoutUrl(alias);
|
|
22
|
+
const { skin } = await td.getSkin({
|
|
23
|
+
name: skinName,
|
|
24
|
+
url: `${layoutUrl}/skins/edit?key=${skinName}`,
|
|
25
|
+
});
|
|
26
|
+
skinContainer[skinName] = skin;
|
|
27
|
+
skinContainer = await findEmbeddedSkinMacros(td, alias, skin, skinContainer);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return skinContainer;
|
|
31
|
+
};
|
|
32
|
+
|
|
11
33
|
/**
|
|
12
34
|
* Downloads all customized skins of one or more aliases and stores them in appropriate
|
|
13
35
|
* subdirectories for subsequent manual edits (or just as backup)
|
|
@@ -22,6 +44,7 @@ const downloadModifiedSkins = async (td, aliases, options) => {
|
|
|
22
44
|
console.log(chalk.green(`\nNow processing alias "${alias}"...`));
|
|
23
45
|
const aliasSkinDir = aliasSkinFolder(alias, options.backup);
|
|
24
46
|
const modifiedSkins = await td.getModifiedSkins(alias);
|
|
47
|
+
let skinContainer = {};
|
|
25
48
|
|
|
26
49
|
if (modifiedSkins.length && !existsSync(aliasSkinDir)) mkdirSync(aliasSkinDir);
|
|
27
50
|
console.log(
|
|
@@ -37,7 +60,32 @@ const downloadModifiedSkins = async (td, aliases, options) => {
|
|
|
37
60
|
const { title, description, skin } = await td.getSkin(modSkin);
|
|
38
61
|
|
|
39
62
|
skinRegister.setData(modSkin.name, title, description);
|
|
40
|
-
|
|
63
|
+
skinContainer[modSkin.name] = skin;
|
|
64
|
+
skinContainer = await findEmbeddedSkinMacros(td, alias, skin, skinContainer);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (options.modules) {
|
|
68
|
+
console.log(chalk.yellow(`Exporting sidebar freetext modules as requested.`));
|
|
69
|
+
const sidebar = await td.getSidebarModules(alias);
|
|
70
|
+
const moduleNames = [...sidebar.sidebar01, ...sidebar.sidebar02];
|
|
71
|
+
for (let module of moduleNames) {
|
|
72
|
+
if (/FreeText\d{2}/.test(module)) {
|
|
73
|
+
console.log(chalk.gray(`Reading sidebar module "${module}".`));
|
|
74
|
+
const { heading, content } = await td.getFreeTextModule(alias, module);
|
|
75
|
+
skinContainer[`Sidebar.${module}`] = `${heading}\n${content}`;
|
|
76
|
+
} else {
|
|
77
|
+
const { skins } = await td.getModuleSkins(alias, module);
|
|
78
|
+
for (let s of skins) {
|
|
79
|
+
const { title, description, skin } = await td.getSkin(s);
|
|
80
|
+
skinRegister.setData(s.name, title, description);
|
|
81
|
+
skinContainer[s.name] = skin;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
for (const [name, content] of Object.entries(skinContainer)) {
|
|
88
|
+
writeFileSync(resolve(aliasSkinDir, `${name}.skin`), content);
|
|
41
89
|
}
|
|
42
90
|
}
|
|
43
91
|
console.log(chalk.green("Download completed."));
|
package/src/_upload.js
CHANGED
|
@@ -35,19 +35,41 @@ const uploadModifiedSkins = async (td, aliases, options) => {
|
|
|
35
35
|
if (!skinFile.endsWith(".skin")) continue;
|
|
36
36
|
if (options.skin && !options.skin.test(skinFile)) continue;
|
|
37
37
|
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
38
|
+
const [hoptype, name] = skinFile.split(".");
|
|
39
|
+
if (hoptype === "Sidebar") {
|
|
40
|
+
const module = readFileSync(resolve(aliasSkinDir, skinFile))
|
|
41
|
+
.toString()
|
|
42
|
+
.replace(/\r\n/g, "\n");
|
|
43
|
+
let splitAt = module.indexOf("\n");
|
|
44
|
+
const heading = module.slice(0, splitAt);
|
|
45
|
+
const content = module.slice(++splitAt);
|
|
46
|
+
console.log(chalk.blue(`Now updating sidebar module ${name} (len=${content.length}).`));
|
|
47
|
+
await td.updateFreeTextModule(alias, name, { heading, content });
|
|
48
|
+
console.log(chalk.green(`Update request completed for module: ${name}`));
|
|
49
|
+
} else {
|
|
50
|
+
const { isValid, prototype } = td.isValidHoptype(skinFile.slice(0, -5));
|
|
51
|
+
if (!isValid) {
|
|
52
|
+
console.log(
|
|
53
|
+
chalk.red(
|
|
54
|
+
`Skipping upload for invalid skin hoptype "${prototype}" (Skin file ${skinFile}).`,
|
|
55
|
+
),
|
|
56
|
+
);
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
const skin = skinRegister.getData(skinFile);
|
|
60
|
+
skin.content = readFileSync(resolve(aliasSkinDir, skinFile))
|
|
61
|
+
.toString()
|
|
62
|
+
.replace(/\r\n/g, "\n");
|
|
42
63
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
64
|
+
console.log(chalk.blue(`Now updating skin ${skin.name} (len=${skin.content.length}).`));
|
|
65
|
+
await td.updateSkin(alias, skin.name, {
|
|
66
|
+
title: skin.title,
|
|
67
|
+
description: skin.description,
|
|
68
|
+
skin: skin.content,
|
|
69
|
+
diff: options.debug,
|
|
70
|
+
});
|
|
71
|
+
console.log(chalk.green(`Update request completed for skin: ${skin.name}`));
|
|
72
|
+
}
|
|
51
73
|
|
|
52
74
|
if (currentSkins.has(skin.name)) currentSkins.delete(skin.name);
|
|
53
75
|
}
|
package/src/index.js
CHANGED
|
@@ -33,6 +33,12 @@ const argv = yargs(process.argv.slice(2)).options({
|
|
|
33
33
|
description: "Skin selection string (regex) to filter the skins to upload",
|
|
34
34
|
type: "string",
|
|
35
35
|
},
|
|
36
|
+
modules: {
|
|
37
|
+
alias: "m",
|
|
38
|
+
description: "Download sidebar module skins/freetext as well",
|
|
39
|
+
default: false,
|
|
40
|
+
type: "boolean",
|
|
41
|
+
},
|
|
36
42
|
backup: {
|
|
37
43
|
alias: "b",
|
|
38
44
|
description: "Backup skins to the local /backup folder to preserve their former status",
|
|
@@ -99,7 +105,10 @@ if (argv.compare) {
|
|
|
99
105
|
const direction = argv.from ? "from" : "to";
|
|
100
106
|
const execTask = argv.from ? downloadModifiedSkins : uploadModifiedSkins;
|
|
101
107
|
|
|
102
|
-
if (action === "down" && argv.clean)
|
|
108
|
+
if (action === "down" && argv.clean) {
|
|
109
|
+
cleanupAliasFolder(aliases, argv.backup);
|
|
110
|
+
console.log(chalk.yellow(`Cleaning target download folder/s for "${aliases}".`));
|
|
111
|
+
}
|
|
103
112
|
|
|
104
113
|
console.log(
|
|
105
114
|
`Start ${action}loading modified skins of alias${aliases.length > 1 ? "es" : ""} ${chalk.yellow(
|
|
@@ -109,6 +118,7 @@ if (argv.compare) {
|
|
|
109
118
|
execTask(td, aliases, {
|
|
110
119
|
backup: argv.backup,
|
|
111
120
|
debug: argv.debug,
|
|
121
|
+
modules: argv.modules,
|
|
112
122
|
skin: argv.skin ? new RegExp(argv.skin) : null,
|
|
113
123
|
});
|
|
114
124
|
}
|