cyclops-infobook-html 5.0.0 → 5.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/README.md +35 -14
- package/bin/compress-icons.d.ts +2 -0
- package/bin/compress-icons.js +82 -0
- package/bin/convert-pom-to-modpack.d.ts +2 -0
- package/bin/convert-pom-to-modpack.js +96 -0
- package/bin/generate-icons.d.ts +2 -0
- package/bin/generate-icons.js +103 -0
- package/bin/generate-infobook-html.js +60 -16
- package/bin/generate-mod-metadata.js +62 -16
- package/index.d.ts +25 -23
- package/index.js +39 -24
- package/lib/icon/IconsCompressor.d.ts +18 -0
- package/lib/icon/IconsCompressor.js +112 -0
- package/lib/icon/IconsGenerator.d.ts +150 -0
- package/lib/icon/IconsGenerator.js +683 -0
- package/lib/infobook/FileWriter.d.ts +3 -4
- package/lib/infobook/FileWriter.js +15 -7
- package/lib/infobook/IFileWriter.d.ts +2 -3
- package/lib/infobook/IInfoAppendix.d.ts +3 -3
- package/lib/infobook/IInfoBook.d.ts +2 -4
- package/lib/infobook/IInfoSection.d.ts +1 -1
- package/lib/infobook/IInfobookPlugin.d.ts +5 -5
- package/lib/infobook/InfoBookInitializer.d.ts +7 -9
- package/lib/infobook/InfoBookInitializer.js +11 -3
- package/lib/infobook/appendix/IInfoBookAppendixHandler.d.ts +2 -2
- package/lib/infobook/appendix/InfoBookAppendixAd.d.ts +3 -3
- package/lib/infobook/appendix/InfoBookAppendixAd.js +17 -4
- package/lib/infobook/appendix/InfoBookAppendixHandlerAbstractRecipe.d.ts +12 -14
- package/lib/infobook/appendix/InfoBookAppendixHandlerAbstractRecipe.js +51 -10
- package/lib/infobook/appendix/InfoBookAppendixHandlerAdvancementRewards.d.ts +3 -3
- package/lib/infobook/appendix/InfoBookAppendixHandlerAdvancementRewards.js +15 -6
- package/lib/infobook/appendix/InfoBookAppendixHandlerCraftingRecipe.d.ts +6 -5
- package/lib/infobook/appendix/InfoBookAppendixHandlerCraftingRecipe.js +14 -5
- package/lib/infobook/appendix/InfoBookAppendixHandlerImage.d.ts +3 -3
- package/lib/infobook/appendix/InfoBookAppendixHandlerImage.js +14 -6
- package/lib/infobook/appendix/InfoBookAppendixHandlerKeybinding.d.ts +3 -3
- package/lib/infobook/appendix/InfoBookAppendixHandlerKeybinding.js +13 -4
- package/lib/infobook/appendix/InfoBookAppendixHandlerSmeltingRecipe.d.ts +6 -5
- package/lib/infobook/appendix/InfoBookAppendixHandlerSmeltingRecipe.js +13 -4
- package/lib/infobook/appendix/InfoBookAppendixHandlerTextfield.d.ts +3 -3
- package/lib/infobook/appendix/InfoBookAppendixHandlerTextfield.js +13 -6
- package/lib/infobook/appendix/InfoBookAppendixTagIndex.d.ts +4 -4
- package/lib/infobook/appendix/InfoBookAppendixTagIndex.js +12 -3
- package/lib/modloader/ModLoader.d.ts +15 -5
- package/lib/modloader/ModLoader.js +189 -86
- package/lib/modloader/PomConverter.d.ts +19 -0
- package/lib/modloader/PomConverter.js +138 -0
- package/lib/parse/XmlInfoBookParser.d.ts +5 -7
- package/lib/parse/XmlInfoBookParser.js +42 -9
- package/lib/resource/ResourceHandler.d.ts +7 -13
- package/lib/resource/ResourceHandler.js +16 -11
- package/lib/resource/ResourceLoader.d.ts +4 -5
- package/lib/resource/ResourceLoader.js +54 -44
- package/lib/serialize/HtmlInfoBookSerializer.d.ts +10 -16
- package/lib/serialize/HtmlInfoBookSerializer.js +102 -91
- package/package.json +35 -25
|
@@ -1,18 +1,62 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
36
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
37
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
38
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
39
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
40
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
41
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
45
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
46
|
+
};
|
|
2
47
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
48
|
exports.ModLoader = void 0;
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
const
|
|
49
|
+
const node_child_process_1 = require("node:child_process");
|
|
50
|
+
const node_fs_1 = require("node:fs");
|
|
51
|
+
const fs = __importStar(require("node:fs"));
|
|
52
|
+
const Path = __importStar(require("node:path"));
|
|
53
|
+
const node_path_1 = require("node:path");
|
|
54
|
+
const node_util_1 = require("node:util");
|
|
55
|
+
const mvn_artifact_download_1 = __importDefault(require("mvn-artifact-download"));
|
|
9
56
|
const ncp_1 = require("ncp");
|
|
10
|
-
const node_fetch_1 = require("node-fetch");
|
|
11
|
-
const
|
|
12
|
-
const rimraf = require("rimraf");
|
|
13
|
-
const util_1 = require("util");
|
|
57
|
+
const node_fetch_1 = __importDefault(require("node-fetch"));
|
|
58
|
+
const rimraf_1 = __importDefault(require("rimraf"));
|
|
14
59
|
const yauzl_1 = require("yauzl");
|
|
15
|
-
const Path = require("path");
|
|
16
60
|
/**
|
|
17
61
|
* Takes care of installing Forge, installing mods, starting a Forge server, and fetching metadata.
|
|
18
62
|
*/
|
|
@@ -33,7 +77,7 @@ class ModLoader {
|
|
|
33
77
|
* Download and install Forge.
|
|
34
78
|
*/
|
|
35
79
|
installForge() {
|
|
36
|
-
return
|
|
80
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
37
81
|
if (!fs.existsSync(this.path)) {
|
|
38
82
|
yield fs.promises.mkdir(this.path);
|
|
39
83
|
}
|
|
@@ -42,65 +86,77 @@ class ModLoader {
|
|
|
42
86
|
// Download Forge installer
|
|
43
87
|
process.stdout.write('Downloading Forge...\n');
|
|
44
88
|
const forgeInstaller = `https://files.minecraftforge.net/maven/net/minecraftforge/forge/${this.versionMinecraft}-${this.loader.versionForge}/forge-${this.versionMinecraft}-${this.loader.versionForge}-installer.jar`;
|
|
45
|
-
const res = yield node_fetch_1.default(forgeInstaller);
|
|
89
|
+
const res = yield (0, node_fetch_1.default)(forgeInstaller);
|
|
46
90
|
if (!res.ok) {
|
|
47
91
|
throw new Error(`Failed to fetch (${res.statusText}): ${forgeInstaller}`);
|
|
48
92
|
}
|
|
49
|
-
installerFile =
|
|
50
|
-
|
|
51
|
-
|
|
93
|
+
installerFile = (0, node_path_1.join)(this.path, 'forge-installer.jar');
|
|
94
|
+
const forgeBuffer = yield res.buffer();
|
|
95
|
+
yield new Promise((resolve, reject) => fs.writeFile(installerFile, forgeBuffer, (err) => {
|
|
96
|
+
if (err) {
|
|
97
|
+
reject(err);
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
resolve();
|
|
101
|
+
}
|
|
52
102
|
}));
|
|
53
103
|
// Install Forge
|
|
54
104
|
process.stdout.write('Installing Forge...\n');
|
|
55
|
-
yield new Promise(
|
|
105
|
+
yield new Promise(resolve => (0, node_child_process_1.exec)(`cd ${this.path} && java -jar forge-installer.jar --installServer`).on('exit', resolve));
|
|
56
106
|
}
|
|
57
107
|
else {
|
|
58
108
|
// Download NeoForge installer
|
|
59
109
|
process.stdout.write('Downloading NeoForge...\n');
|
|
60
110
|
const installer = `https://maven.neoforged.net/releases/net/neoforged/neoforge/${this.loader.versionNeoForge}/neoforge-${this.loader.versionNeoForge}-installer.jar`;
|
|
61
|
-
const res = yield node_fetch_1.default(installer);
|
|
111
|
+
const res = yield (0, node_fetch_1.default)(installer);
|
|
62
112
|
if (!res.ok) {
|
|
63
113
|
throw new Error(`Failed to fetch (${res.statusText}): ${installer}`);
|
|
64
114
|
}
|
|
65
|
-
installerFile =
|
|
66
|
-
|
|
67
|
-
|
|
115
|
+
installerFile = (0, node_path_1.join)(this.path, 'neoforge-installer.jar');
|
|
116
|
+
const neoBuffer = yield res.buffer();
|
|
117
|
+
yield new Promise((resolve, reject) => fs.writeFile(installerFile, neoBuffer, (err) => {
|
|
118
|
+
if (err) {
|
|
119
|
+
reject(err);
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
resolve();
|
|
123
|
+
}
|
|
68
124
|
}));
|
|
69
125
|
// Install Forge
|
|
70
126
|
process.stdout.write('Installing NeoForge...\n');
|
|
71
|
-
yield new Promise(
|
|
127
|
+
yield new Promise(resolve => (0, node_child_process_1.exec)(`cd ${this.path} && java -jar neoforge-installer.jar --installServer`).on('exit', resolve));
|
|
72
128
|
}
|
|
73
129
|
// Wait a bit, because otherwise some files don't exist yet (while they should...)
|
|
74
130
|
process.stdout.write('Wait a bit after mod loader installation...\n');
|
|
75
|
-
yield new Promise(
|
|
131
|
+
yield new Promise(resolve => setTimeout(resolve, 10000));
|
|
76
132
|
// Cleanup
|
|
77
133
|
process.stdout.write('Cleaning up...\n');
|
|
78
134
|
yield fs.promises.unlink(installerFile);
|
|
79
|
-
yield fs.promises.unlink(installerFile
|
|
135
|
+
yield fs.promises.unlink(`${installerFile}.log`);
|
|
80
136
|
});
|
|
81
137
|
}
|
|
82
138
|
/**
|
|
83
139
|
* Accept the Minecraft EULA
|
|
84
140
|
*/
|
|
85
141
|
acceptEula() {
|
|
86
|
-
return
|
|
142
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
87
143
|
process.stdout.write('Accepting EULA...\n');
|
|
88
|
-
yield fs.promises.writeFile(
|
|
144
|
+
yield fs.promises.writeFile((0, node_path_1.join)(this.path, 'eula.txt'), 'eula=true');
|
|
89
145
|
});
|
|
90
146
|
}
|
|
91
147
|
/**
|
|
92
148
|
* @returns {boolean} If mods are installed.
|
|
93
149
|
*/
|
|
94
150
|
areModsInstalled() {
|
|
95
|
-
return fs.existsSync(
|
|
151
|
+
return fs.existsSync((0, node_path_1.join)(this.path, 'mods'));
|
|
96
152
|
}
|
|
97
153
|
/**
|
|
98
154
|
* Download and install mods.
|
|
99
155
|
*/
|
|
100
156
|
installMods() {
|
|
101
|
-
return
|
|
157
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
102
158
|
process.stdout.write('Downloading mods...\n');
|
|
103
|
-
const modsDir =
|
|
159
|
+
const modsDir = (0, node_path_1.join)(this.path, 'mods');
|
|
104
160
|
if (!fs.existsSync(modsDir)) {
|
|
105
161
|
yield fs.promises.mkdir(modsDir);
|
|
106
162
|
}
|
|
@@ -109,15 +165,22 @@ class ModLoader {
|
|
|
109
165
|
const fileName = `${mod.artifact}-${mod.version}.jar`;
|
|
110
166
|
process.stdout.write(` - ${fileName} from CurseForge...\n`);
|
|
111
167
|
const url = `https://minecraft.curseforge.com/api/maven/${mod.project}/${mod.artifact
|
|
112
|
-
.
|
|
168
|
+
.replaceAll('-', '/')}/${fileName}`;
|
|
113
169
|
yield this.downloadFile(url, fileName, modsDir);
|
|
114
170
|
}
|
|
115
171
|
else if (mod.type === 'maven') {
|
|
116
172
|
process.stdout.write(` - ${mod.artifact} from ${mod.repo}...\n`);
|
|
117
|
-
|
|
173
|
+
let name;
|
|
174
|
+
if (mod.headers && Object.keys(mod.headers).length > 0) {
|
|
175
|
+
// Authenticated download: construct URL manually and use fetch with headers
|
|
176
|
+
name = yield this.downloadMavenArtifact(mod.artifact, mod.repo, modsDir, mod.headers);
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
name = yield (0, mvn_artifact_download_1.default)(mod.artifact, modsDir, mod.repo);
|
|
180
|
+
}
|
|
118
181
|
// Rename file if needed
|
|
119
182
|
if ('name' in mod) {
|
|
120
|
-
fs.renameSync(name,
|
|
183
|
+
fs.renameSync(name, (0, node_path_1.join)(modsDir, mod.name));
|
|
121
184
|
}
|
|
122
185
|
}
|
|
123
186
|
else if (mod.type === 'raw') {
|
|
@@ -125,33 +188,72 @@ class ModLoader {
|
|
|
125
188
|
yield this.downloadFile(mod.url, mod.name, modsDir);
|
|
126
189
|
}
|
|
127
190
|
else {
|
|
128
|
-
throw new Error(
|
|
191
|
+
throw new Error(`Unknown mod type ${mod.type}`);
|
|
129
192
|
}
|
|
130
193
|
}
|
|
131
194
|
});
|
|
132
195
|
}
|
|
133
|
-
downloadFile(url, fileName, modsDir) {
|
|
134
|
-
return
|
|
135
|
-
const response = yield node_fetch_1.default(url);
|
|
196
|
+
downloadFile(url, fileName, modsDir, headers) {
|
|
197
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
198
|
+
const response = yield (0, node_fetch_1.default)(url, headers ? { headers } : undefined);
|
|
136
199
|
if (response.status !== 200) {
|
|
137
|
-
throw new Error(response.statusText
|
|
200
|
+
throw new Error(`${response.statusText} on ${url}`);
|
|
138
201
|
}
|
|
139
202
|
yield new Promise((resolve, reject) => {
|
|
140
203
|
response.body
|
|
141
204
|
.on('error', reject)
|
|
142
205
|
.on('end', resolve)
|
|
143
|
-
.pipe(fs.createWriteStream(
|
|
206
|
+
.pipe(fs.createWriteStream((0, node_path_1.join)(modsDir, fileName)));
|
|
144
207
|
});
|
|
145
208
|
});
|
|
146
209
|
}
|
|
210
|
+
/**
|
|
211
|
+
* Download a Maven artifact by constructing the repository URL manually.
|
|
212
|
+
* This is used for authenticated repositories where custom headers are needed.
|
|
213
|
+
* @param artifact The Maven artifact coordinates (groupId:artifactId:version[:classifier]).
|
|
214
|
+
* @param repoUrl The base URL of the Maven repository.
|
|
215
|
+
* @param modsDir The directory to save the downloaded file.
|
|
216
|
+
* @param headers Optional HTTP headers (e.g., Authorization).
|
|
217
|
+
* @returns The full path to the downloaded file.
|
|
218
|
+
*/
|
|
219
|
+
downloadMavenArtifact(artifact, repoUrl, modsDir, headers) {
|
|
220
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
221
|
+
const parts = artifact.split(':');
|
|
222
|
+
if (parts.length < 3) {
|
|
223
|
+
throw new Error(`Invalid Maven artifact: ${artifact}. Expected format: groupId:artifactId:version[:classifier]`);
|
|
224
|
+
}
|
|
225
|
+
const [groupId, artifactId, version, classifier] = parts;
|
|
226
|
+
const groupPath = groupId.replaceAll('.', '/');
|
|
227
|
+
const suffix = classifier ? `-${classifier}` : '';
|
|
228
|
+
const fileName = `${artifactId}-${version}${suffix}.jar`;
|
|
229
|
+
const base = repoUrl.endsWith('/') ? repoUrl : `${repoUrl}/`;
|
|
230
|
+
const url = `${base}${groupPath}/${artifactId}/${version}/${fileName}`;
|
|
231
|
+
// Expand environment variable placeholders in header values (e.g. ${GITHUB_TOKEN})
|
|
232
|
+
const resolvedHeaders = {};
|
|
233
|
+
if (headers) {
|
|
234
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
235
|
+
resolvedHeaders[key] = value.replaceAll(/\$\{([^}]+)\}/gu, (fullMatch, name) => {
|
|
236
|
+
const envValue = process.env[name];
|
|
237
|
+
if (envValue === undefined) {
|
|
238
|
+
process.stderr.write(`Warning: environment variable '${name}' is not set; the request header '${key}' may be invalid\n`);
|
|
239
|
+
return fullMatch;
|
|
240
|
+
}
|
|
241
|
+
return envValue;
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
yield this.downloadFile(url, fileName, modsDir, resolvedHeaders);
|
|
246
|
+
return (0, node_path_1.join)(modsDir, fileName);
|
|
247
|
+
});
|
|
248
|
+
}
|
|
147
249
|
/**
|
|
148
250
|
* Start the server and execute a command to dump all registries
|
|
149
251
|
*/
|
|
150
252
|
startServer() {
|
|
151
|
-
return
|
|
253
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
152
254
|
// Start the Forge server
|
|
153
255
|
process.stdout.write('Starting server...\n');
|
|
154
|
-
const proc =
|
|
256
|
+
const proc = (0, node_child_process_1.exec)(`cd ${this.path} && ./run.sh nogui`);
|
|
155
257
|
// Ignore stdout: proc.stdout.pipe(process.stdout);
|
|
156
258
|
proc.stderr.pipe(process.stderr);
|
|
157
259
|
const onDone = new Promise((resolve, reject) => {
|
|
@@ -160,14 +262,14 @@ class ModLoader {
|
|
|
160
262
|
resolve();
|
|
161
263
|
}
|
|
162
264
|
else {
|
|
163
|
-
reject('Server closed with non-zero exit code');
|
|
265
|
+
reject(new Error('Server closed with non-zero exit code'));
|
|
164
266
|
}
|
|
165
267
|
});
|
|
166
268
|
proc.addListener('error', reject);
|
|
167
269
|
});
|
|
168
270
|
// Once the loading is complete, send our command and stop the server
|
|
169
271
|
proc.stdout.on('data', (line) => {
|
|
170
|
-
if (line.
|
|
272
|
+
if (line.includes('Done') && line.includes('For help, type "help"')) {
|
|
171
273
|
process.stdout.write('Dumping registries...\n');
|
|
172
274
|
this.sendCommand(proc, '/cyclopscore dumpregistries');
|
|
173
275
|
this.sendCommand(proc, '/stop');
|
|
@@ -182,29 +284,29 @@ class ModLoader {
|
|
|
182
284
|
* @param {string} command A command.
|
|
183
285
|
*/
|
|
184
286
|
sendCommand(proc, command) {
|
|
185
|
-
proc.stdin.write(command
|
|
287
|
+
proc.stdin.write(`${command}\n`);
|
|
186
288
|
}
|
|
187
289
|
/**
|
|
188
290
|
* Copy the resulting registry files to a target path.
|
|
189
291
|
* @param {string} target A target path.
|
|
190
292
|
*/
|
|
191
293
|
copyRegistries(target) {
|
|
192
|
-
return
|
|
294
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
193
295
|
process.stdout.write('Copying registries...\n');
|
|
194
|
-
if (!fs.existsSync(
|
|
195
|
-
yield fs.promises.mkdir(
|
|
296
|
+
if (!fs.existsSync((0, node_path_1.join)(this.path, 'cyclops_registries'))) {
|
|
297
|
+
yield fs.promises.mkdir((0, node_path_1.join)(this.path, 'cyclops_registries'));
|
|
196
298
|
}
|
|
197
|
-
yield
|
|
299
|
+
yield (0, node_util_1.promisify)(ncp_1.ncp)((0, node_path_1.join)(this.path, 'cyclops_registries'), target);
|
|
198
300
|
});
|
|
199
301
|
}
|
|
200
302
|
/**
|
|
201
303
|
* Extract the Minecraft assets from the server jar
|
|
202
304
|
*/
|
|
203
305
|
extractMinecraftAssets() {
|
|
204
|
-
return
|
|
306
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
205
307
|
process.stdout.write('Extracting minecraft assets...\n');
|
|
206
|
-
if (!fs.existsSync(
|
|
207
|
-
yield fs.promises.mkdir(
|
|
308
|
+
if (!fs.existsSync((0, node_path_1.join)(this.path, 'mc_assets'))) {
|
|
309
|
+
yield fs.promises.mkdir((0, node_path_1.join)(this.path, 'mc_assets'));
|
|
208
310
|
}
|
|
209
311
|
// Find Minecraft jar
|
|
210
312
|
let jar = null;
|
|
@@ -213,14 +315,14 @@ class ModLoader {
|
|
|
213
315
|
if (dir.indexOf('-') > 0) {
|
|
214
316
|
for (const file of yield fs.promises.readdir(Path.join(subPath, dir))) {
|
|
215
317
|
if (file.startsWith('server') && file.endsWith('extra.jar')) {
|
|
216
|
-
jar =
|
|
318
|
+
jar = (0, node_path_1.join)(subPath, dir, file);
|
|
217
319
|
}
|
|
218
320
|
}
|
|
219
321
|
}
|
|
220
322
|
}
|
|
221
323
|
// Error if no jar was found
|
|
222
324
|
if (!jar) {
|
|
223
|
-
throw new Error(
|
|
325
|
+
throw new Error(`Could not find a valid minecraft server in ${this.path}`);
|
|
224
326
|
}
|
|
225
327
|
// Unzip the jar
|
|
226
328
|
process.stdout.write(`Extracting Minecraft jar...\n`);
|
|
@@ -231,16 +333,16 @@ class ModLoader {
|
|
|
231
333
|
* Extract assets from all mod jars
|
|
232
334
|
*/
|
|
233
335
|
extractModsAssets() {
|
|
234
|
-
return
|
|
336
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
235
337
|
process.stdout.write('Extracting mod assets...\n');
|
|
236
|
-
if (!fs.existsSync(
|
|
237
|
-
yield fs.promises.mkdir(
|
|
338
|
+
if (!fs.existsSync((0, node_path_1.join)(this.path, 'mod_assets'))) {
|
|
339
|
+
yield fs.promises.mkdir((0, node_path_1.join)(this.path, 'mod_assets'));
|
|
238
340
|
}
|
|
239
341
|
// Loop over all mods
|
|
240
|
-
const modsDir =
|
|
342
|
+
const modsDir = (0, node_path_1.join)(this.path, 'mods');
|
|
241
343
|
for (const mod of yield fs.promises.readdir(modsDir)) {
|
|
242
344
|
if (mod.endsWith('.jar')) {
|
|
243
|
-
const modFile =
|
|
345
|
+
const modFile = (0, node_path_1.join)(modsDir, mod);
|
|
244
346
|
process.stdout.write(` - ${mod}...\n`);
|
|
245
347
|
yield this.extractModAssets(modFile);
|
|
246
348
|
}
|
|
@@ -252,9 +354,9 @@ class ModLoader {
|
|
|
252
354
|
* @param {string} modFile A mod file path.
|
|
253
355
|
*/
|
|
254
356
|
extractModAssets(modFile) {
|
|
255
|
-
return
|
|
357
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
256
358
|
const zipFile = yield new Promise((resolve, reject) => {
|
|
257
|
-
yauzl_1.open(modFile, { lazyEntries: true, autoClose: true }, (e, f) => {
|
|
359
|
+
(0, yauzl_1.open)(modFile, { lazyEntries: true, autoClose: true }, (e, f) => {
|
|
258
360
|
if (e) {
|
|
259
361
|
reject(e);
|
|
260
362
|
}
|
|
@@ -262,33 +364,34 @@ class ModLoader {
|
|
|
262
364
|
});
|
|
263
365
|
});
|
|
264
366
|
zipFile.readEntry();
|
|
265
|
-
zipFile.on('error',
|
|
367
|
+
zipFile.on('error', e => process.stdout.write(String(e)));
|
|
266
368
|
zipFile.on('entry', (entry) => {
|
|
267
369
|
if (entry.fileName.endsWith('/')) {
|
|
268
370
|
// Directory
|
|
269
371
|
zipFile.readEntry();
|
|
270
372
|
}
|
|
271
|
-
else {
|
|
373
|
+
else if (entry.fileName.startsWith('assets/') || entry.fileName.startsWith('data/')) {
|
|
272
374
|
// File
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
});
|
|
375
|
+
const prefix = entry.fileName.startsWith('assets/') ? 7 : 5;
|
|
376
|
+
const targetFile = (0, node_path_1.join)(this.path, 'mod_assets', entry.fileName.slice(prefix, entry.fileName.length));
|
|
377
|
+
const targetDir = (0, node_path_1.dirname)(targetFile);
|
|
378
|
+
void this.ensureDirExists(targetDir).then(() => {
|
|
379
|
+
zipFile.openReadStream(entry, (e, readStream) => {
|
|
380
|
+
if (e) {
|
|
381
|
+
throw e;
|
|
382
|
+
}
|
|
383
|
+
readStream.pipe((0, node_fs_1.createWriteStream)(targetFile));
|
|
384
|
+
readStream.on('end', () => zipFile.readEntry());
|
|
284
385
|
});
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
386
|
+
}).catch((e) => {
|
|
387
|
+
throw e;
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
else {
|
|
391
|
+
zipFile.readEntry();
|
|
289
392
|
}
|
|
290
393
|
});
|
|
291
|
-
yield new Promise(
|
|
394
|
+
yield new Promise(resolve => zipFile.on('end', resolve));
|
|
292
395
|
});
|
|
293
396
|
}
|
|
294
397
|
/**
|
|
@@ -296,36 +399,36 @@ class ModLoader {
|
|
|
296
399
|
* @param {string} target A target path.
|
|
297
400
|
*/
|
|
298
401
|
copyModAssets(target) {
|
|
299
|
-
return
|
|
402
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
300
403
|
process.stdout.write('Copying mod assets...\n');
|
|
301
|
-
yield
|
|
404
|
+
yield (0, node_util_1.promisify)(ncp_1.ncp)((0, node_path_1.join)(this.path, 'mod_assets'), target);
|
|
302
405
|
});
|
|
303
406
|
}
|
|
304
407
|
/**
|
|
305
408
|
* Remove the server files.
|
|
306
409
|
*/
|
|
307
410
|
removeServer() {
|
|
308
|
-
return
|
|
309
|
-
yield
|
|
411
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
412
|
+
yield (0, node_util_1.promisify)(rimraf_1.default)(this.path);
|
|
310
413
|
});
|
|
311
414
|
}
|
|
312
415
|
/**
|
|
313
416
|
* Remove the mod directory.
|
|
314
417
|
*/
|
|
315
418
|
removeMods() {
|
|
316
|
-
return
|
|
317
|
-
yield
|
|
419
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
420
|
+
yield (0, node_util_1.promisify)(rimraf_1.default)((0, node_path_1.join)(this.path, 'mods'));
|
|
318
421
|
});
|
|
319
422
|
}
|
|
320
423
|
ensureDirExists(path) {
|
|
321
|
-
return
|
|
322
|
-
const segments = path.
|
|
424
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
425
|
+
const segments = path.slice(this.path.length, this.path.length + path.length).split(node_path_1.sep);
|
|
323
426
|
for (let i = 1; i <= segments.length; i++) {
|
|
324
|
-
const subPath =
|
|
427
|
+
const subPath = (0, node_path_1.join)(this.path, segments.slice(0, i).join(node_path_1.sep));
|
|
325
428
|
try {
|
|
326
429
|
yield fs.promises.stat(subPath);
|
|
327
430
|
}
|
|
328
|
-
catch (
|
|
431
|
+
catch (_a) {
|
|
329
432
|
yield fs.promises.mkdir(subPath);
|
|
330
433
|
}
|
|
331
434
|
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface IModpackMod {
|
|
2
|
+
type: 'maven';
|
|
3
|
+
artifact: string;
|
|
4
|
+
repo: string;
|
|
5
|
+
headers?: Record<string, string>;
|
|
6
|
+
}
|
|
7
|
+
export interface IModpackJson {
|
|
8
|
+
minecraft: string;
|
|
9
|
+
neoforge?: string;
|
|
10
|
+
forge?: string;
|
|
11
|
+
mods: IModpackMod[];
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Convert a Maven pom.xml (and optional settings.xml) into a modpack.json object.
|
|
15
|
+
* @param pomXml The contents of the pom.xml file.
|
|
16
|
+
* @param settingsXml The contents of the settings.xml file, or undefined.
|
|
17
|
+
* @returns The generated modpack.json object.
|
|
18
|
+
*/
|
|
19
|
+
export declare function convertPomToModpack(pomXml: string, settingsXml: string | undefined): Promise<IModpackJson>;
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.convertPomToModpack = convertPomToModpack;
|
|
13
|
+
const node_util_1 = require("node:util");
|
|
14
|
+
const xml2js_1 = require("xml2js");
|
|
15
|
+
const parseStringPromise = (0, node_util_1.promisify)(xml2js_1.parseString);
|
|
16
|
+
/** Default Maven repository URL, used when no settings.xml is provided. */
|
|
17
|
+
const DEFAULT_MAVEN_REPO = 'https://repo.maven.apache.org/maven2';
|
|
18
|
+
/**
|
|
19
|
+
* Convert a Maven pom.xml (and optional settings.xml) into a modpack.json object.
|
|
20
|
+
* @param pomXml The contents of the pom.xml file.
|
|
21
|
+
* @param settingsXml The contents of the settings.xml file, or undefined.
|
|
22
|
+
* @returns The generated modpack.json object.
|
|
23
|
+
*/
|
|
24
|
+
function convertPomToModpack(pomXml, settingsXml) {
|
|
25
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
26
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
|
|
27
|
+
const pomDoc = (yield parseStringPromise(pomXml));
|
|
28
|
+
const project = pomDoc.project;
|
|
29
|
+
// Extract Minecraft version from the project <version>
|
|
30
|
+
const minecraftVersion = project.version[0];
|
|
31
|
+
// Extract NeoForge/Forge version from <properties>
|
|
32
|
+
let neoforgeVersion;
|
|
33
|
+
let forgeVersion;
|
|
34
|
+
if ((_a = project.properties) === null || _a === void 0 ? void 0 : _a[0]) {
|
|
35
|
+
const props = project.properties[0];
|
|
36
|
+
if (props['neoforge.version']) {
|
|
37
|
+
neoforgeVersion = props['neoforge.version'][0];
|
|
38
|
+
}
|
|
39
|
+
if (props['forge.version']) {
|
|
40
|
+
forgeVersion = props['forge.version'][0];
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
// Parse settings.xml if provided
|
|
44
|
+
const activeProfileIds = new Set();
|
|
45
|
+
const repoMap = new Map();
|
|
46
|
+
const serverMap = new Map();
|
|
47
|
+
if (settingsXml) {
|
|
48
|
+
const settingsDoc = (yield parseStringPromise(settingsXml));
|
|
49
|
+
const settings = settingsDoc.settings;
|
|
50
|
+
// Collect active profile IDs
|
|
51
|
+
if ((_c = (_b = settings.activeProfiles) === null || _b === void 0 ? void 0 : _b[0]) === null || _c === void 0 ? void 0 : _c.activeProfile) {
|
|
52
|
+
for (const id of settings.activeProfiles[0].activeProfile) {
|
|
53
|
+
activeProfileIds.add(id);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
// Collect repositories from active profiles
|
|
57
|
+
if ((_e = (_d = settings.profiles) === null || _d === void 0 ? void 0 : _d[0]) === null || _e === void 0 ? void 0 : _e.profile) {
|
|
58
|
+
for (const profile of settings.profiles[0].profile) {
|
|
59
|
+
const profileId = profile.id[0];
|
|
60
|
+
if (!activeProfileIds.has(profileId)) {
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
if ((_g = (_f = profile.repositories) === null || _f === void 0 ? void 0 : _f[0]) === null || _g === void 0 ? void 0 : _g.repository) {
|
|
64
|
+
for (const repo of profile.repositories[0].repository) {
|
|
65
|
+
const repoId = repo.id[0];
|
|
66
|
+
const repoUrl = repo.url[0].replace(/\/$/u, '');
|
|
67
|
+
repoMap.set(repoId, { id: repoId, url: repoUrl });
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
// Collect server credentials
|
|
73
|
+
if ((_j = (_h = settings.servers) === null || _h === void 0 ? void 0 : _h[0]) === null || _j === void 0 ? void 0 : _j.server) {
|
|
74
|
+
for (const server of settings.servers[0].server) {
|
|
75
|
+
const serverId = server.id[0];
|
|
76
|
+
const username = (_k = server.username) === null || _k === void 0 ? void 0 : _k[0];
|
|
77
|
+
const password = (_l = server.password) === null || _l === void 0 ? void 0 : _l[0];
|
|
78
|
+
serverMap.set(serverId, { id: serverId, username, password });
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
// Collect dependencies from pom.xml
|
|
83
|
+
const mods = [];
|
|
84
|
+
if ((_o = (_m = project.dependencies) === null || _m === void 0 ? void 0 : _m[0]) === null || _o === void 0 ? void 0 : _o.dependency) {
|
|
85
|
+
const repos = [...repoMap.values()];
|
|
86
|
+
for (const dep of project.dependencies[0].dependency) {
|
|
87
|
+
const groupId = dep.groupId[0];
|
|
88
|
+
const artifactId = dep.artifactId[0];
|
|
89
|
+
const version = dep.version[0];
|
|
90
|
+
const classifier = (_p = dep.classifier) === null || _p === void 0 ? void 0 : _p[0];
|
|
91
|
+
const artifact = classifier ?
|
|
92
|
+
`${groupId}:${artifactId}:${version}:${classifier}` :
|
|
93
|
+
`${groupId}:${artifactId}:${version}`;
|
|
94
|
+
// Determine repo: use the first active repo as default
|
|
95
|
+
const repo = (_q = repos[0]) !== null && _q !== void 0 ? _q : { id: 'central', url: DEFAULT_MAVEN_REPO };
|
|
96
|
+
const mod = {
|
|
97
|
+
type: 'maven',
|
|
98
|
+
artifact,
|
|
99
|
+
repo: repo.url,
|
|
100
|
+
};
|
|
101
|
+
// If the repo has a server entry with credentials, add auth headers
|
|
102
|
+
const server = serverMap.get(repo.id);
|
|
103
|
+
if (server === null || server === void 0 ? void 0 : server.password) {
|
|
104
|
+
// If the password is an environment variable placeholder (e.g. ${GITHUB_TOKEN}),
|
|
105
|
+
// use Bearer authentication to avoid having to base64-encode at generation time.
|
|
106
|
+
const passwordIsPlaceholder = /^\$\{[^}]+\}$/u.test(server.password);
|
|
107
|
+
const authHeaders = {};
|
|
108
|
+
if (passwordIsPlaceholder) {
|
|
109
|
+
authHeaders.Authorization = `Bearer ${server.password}`;
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
// Literal credentials: encode as Basic auth
|
|
113
|
+
const credentials = Buffer
|
|
114
|
+
.from(`${(_r = server.username) !== null && _r !== void 0 ? _r : 'token'}:${server.password}`)
|
|
115
|
+
.toString('base64');
|
|
116
|
+
authHeaders.Authorization = `Basic ${credentials}`;
|
|
117
|
+
}
|
|
118
|
+
mod.headers = authHeaders;
|
|
119
|
+
}
|
|
120
|
+
mods.push(mod);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
// Build the modpack.json output
|
|
124
|
+
const modpack = {
|
|
125
|
+
minecraft: minecraftVersion,
|
|
126
|
+
mods,
|
|
127
|
+
};
|
|
128
|
+
if (neoforgeVersion) {
|
|
129
|
+
modpack.neoforge = neoforgeVersion;
|
|
130
|
+
}
|
|
131
|
+
else if (forgeVersion) {
|
|
132
|
+
modpack.forge = forgeVersion;
|
|
133
|
+
}
|
|
134
|
+
// Reorder so minecraft/neoforge/forge come before mods
|
|
135
|
+
return Object.assign(Object.assign(Object.assign({ minecraft: modpack.minecraft }, (modpack.neoforge ? { neoforge: modpack.neoforge } : {})), (modpack.forge ? { forge: modpack.forge } : {})), { mods: modpack.mods });
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=PomConverter.js.map
|