modpack-lock 0.1.0 → 0.1.2

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.
Files changed (3) hide show
  1. package/README.md +16 -12
  2. package/index.js +116 -14
  3. package/package.json +1 -2
package/README.md CHANGED
@@ -41,6 +41,13 @@ Navigate to your Minecraft profile directory (the folder containing `mods`, `res
41
41
  modpack-lock
42
42
  ```
43
43
 
44
+ Flags:
45
+
46
+ - `--dry-run` or `-d`: Print the files that would be scanned, but don't actually scan them
47
+ - `--quiet` or `-q`: Print only errors and warnings
48
+ - `--silent` or `-s`: Print nothing
49
+ - `--gitignore` or `-g`: Print the rules to add to your `.gitignore` file
50
+
44
51
  The script will:
45
52
 
46
53
  1. Scan the `mods`, `resourcepacks`, `datapacks`, and `shaderpacks` directories for `.jar` and `.zip` files
@@ -51,6 +58,7 @@ The script will:
51
58
  Then, commit the `modpack.lock` file to your repository and push it to your remote.
52
59
 
53
60
  > [!TIP]
61
+ >
54
62
  > You can run this script as a pre-commit hook to ensure that the modpack lockfile is up to date before committing your changes to your repository.
55
63
  >
56
64
  > Also, consider adding these rules to your `.gitignore` to ensure you don't commit the modpack contents to your repository, with exceptions for any files that are not Modrinth-hosted:
@@ -71,8 +79,15 @@ The `modpack.lock` file has the following structure:
71
79
 
72
80
  ```json
73
81
  {
74
- "version": "1.0.0",
82
+ "version": "1.0.1",
75
83
  "generated": "2026-01-06T03:00:00.000Z",
84
+ "total": 7,
85
+ "counts": {
86
+ "mods": 1,
87
+ "resourcepacks": 3,
88
+ "datapacks": 1,
89
+ "shaderpacks": 2
90
+ },
76
91
  "dependencies": {
77
92
  "mods": [
78
93
  {
@@ -87,17 +102,6 @@ The `modpack.lock` file has the following structure:
87
102
  }
88
103
  ```
89
104
 
90
- ## Future Plans
91
-
92
- - [ ] Add support for CurseForge
93
- - [ ] Add support for restoring modpack contents using the lockfile
94
- - [ ] Add CLI option for dry-run
95
- - [ ] Add CLI option for verbose output
96
- - [ ] Add CLI option for quiet output
97
- - [ ] Add CLI option for printout of rules to add to .gitignore (the files that are not hosted)
98
-
99
- Feel free to submit a pull request working on any of the above, or open an issue for any feature requests or bug reports.
100
-
101
105
  ## License
102
106
 
103
107
  This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for more details.
package/index.js CHANGED
@@ -4,7 +4,7 @@ import fs from 'fs/promises';
4
4
  import crypto from 'crypto';
5
5
  import path from 'path';
6
6
 
7
- const LOCKFILE_VERSION = '1.0.0';
7
+ const LOCKFILE_VERSION = '1.0.1';
8
8
  const MODPACK_LOCKFILE_NAME = 'modpack.lock';
9
9
  const MODRINTH_API_BASE = 'https://api.modrinth.com/v2';
10
10
  const MODRINTH_VERSION_FILES_ENDPOINT = `${MODRINTH_API_BASE}/version_files`;
@@ -12,6 +12,39 @@ const MODRINTH_VERSION_FILES_ENDPOINT = `${MODRINTH_API_BASE}/version_files`;
12
12
  // Get the workspace root from the current working directory
13
13
  const WORKSPACE_ROOT = process.cwd();
14
14
 
15
+ /**
16
+ * Parse command-line arguments
17
+ */
18
+ function parseArgs() {
19
+ const args = process.argv.slice(2);
20
+ return {
21
+ dryRun: args.includes('--dry-run') || args.includes('-d'),
22
+ quiet: args.includes('--quiet') || args.includes('-q'),
23
+ silent: args.includes('--silent') || args.includes('-s'),
24
+ gitignore: args.includes('--gitignore') || args.includes('-g'),
25
+ };
26
+ }
27
+
28
+ /**
29
+ * Create a logger function that respects quiet mode
30
+ */
31
+ function createLogger(quiet) {
32
+ if (quiet) {
33
+ return () => {}; // No-op function when quiet
34
+ }
35
+ return (...args) => console.log(...args);
36
+ }
37
+
38
+ /**
39
+ * Silence all console.log output
40
+ */
41
+ function silenceConsole() {
42
+ console.log = () => {};
43
+ console.warn = () => {};
44
+ console.error = () => {};
45
+ console.info = () => {};
46
+ }
47
+
15
48
  const DIRECTORIES_TO_SCAN = [
16
49
  { name: 'mods', path: path.join(WORKSPACE_ROOT, 'mods') },
17
50
  { name: 'resourcepacks', path: path.join(WORKSPACE_ROOT, 'resourcepacks') },
@@ -118,6 +151,8 @@ function createEmptyLockfile() {
118
151
  return {
119
152
  version: LOCKFILE_VERSION,
120
153
  generated: new Date().toISOString(),
154
+ total: 0,
155
+ counts: {},
121
156
  dependencies: {},
122
157
  };
123
158
  }
@@ -146,42 +181,99 @@ function createLockfile(fileEntries, versionData) {
146
181
  lockfile.dependencies[fileInfo.category].push(entry);
147
182
  }
148
183
 
184
+ // Calculate counts for each category
185
+ for (const [category, entries] of Object.entries(lockfile.dependencies)) {
186
+ lockfile.counts[category] = entries.length;
187
+ }
188
+
189
+ // Calculate total count
190
+ lockfile.total = fileEntries.length;
191
+
149
192
  return lockfile;
150
193
  }
151
194
 
152
195
  /**
153
196
  * Write lockfile to disk
154
197
  */
155
- async function writeLockfile(lockfile, outputPath) {
198
+ async function writeLockfile(lockfile, outputPath, log) {
156
199
  const content = JSON.stringify(lockfile, null, 2);
157
200
  await fs.writeFile(outputPath, content, 'utf-8');
158
- console.log(`Lockfile written to: ${outputPath}`);
201
+ log(`Lockfile written to: ${outputPath}`);
202
+ }
203
+
204
+ /**
205
+ * Generate .gitignore rules for files not hosted on Modrinth
206
+ */
207
+ function generateGitignoreRules(lockfile) {
208
+ const rules = [];
209
+ const exceptions = [];
210
+
211
+ // Base ignore patterns for each category
212
+ rules.push('mods/*.jar');
213
+ rules.push('resourcepacks/*.zip');
214
+ rules.push('datapacks/*.zip');
215
+ rules.push('shaderpacks/*.zip');
216
+ rules.push('');
217
+ rules.push('## Exceptions');
218
+
219
+ // Find files not hosted on Modrinth
220
+ for (const [category, entries] of Object.entries(lockfile.dependencies)) {
221
+ for (const entry of entries) {
222
+ if (entry.version === null) {
223
+ exceptions.push(`!${entry.path}`);
224
+ }
225
+ }
226
+ }
227
+
228
+ // Add exceptions if any
229
+ if (exceptions.length > 0) {
230
+ rules.push(...exceptions);
231
+ } else {
232
+ rules.push('# No exceptions needed - all files are hosted on Modrinth');
233
+ }
234
+
235
+ return rules.join('\n');
159
236
  }
160
237
 
161
238
  /**
162
239
  * Main execution function
163
240
  */
164
241
  async function main() {
165
- console.log('Scanning directories for modpack files...');
242
+ const config = parseArgs();
243
+ const log = createLogger(config.quiet);
244
+
245
+ if (config.silent) {
246
+ silenceConsole();
247
+ }
248
+
249
+ if (config.dryRun) {
250
+ log('[DRY RUN] Preview mode - no files will be written');
251
+ }
252
+
253
+ log('Scanning directories for modpack files...');
166
254
 
167
255
  // Scan all directories
168
256
  const allFileEntries = [];
169
257
  for (const dirInfo of DIRECTORIES_TO_SCAN) {
170
- console.log(`Scanning ${dirInfo.name}...`);
258
+ log(`Scanning ${dirInfo.name}...`);
171
259
  const fileEntries = await scanDirectory(dirInfo);
172
- console.log(` Found ${fileEntries.length} file(s)`);
260
+ log(` Found ${fileEntries.length} file(s)`);
173
261
  allFileEntries.push(...fileEntries);
174
262
  }
175
263
 
176
264
  if (allFileEntries.length === 0) {
177
- console.log('No files found. Creating empty lockfile.');
265
+ log('No files found. Creating empty lockfile.');
178
266
  const outputPath = path.join(WORKSPACE_ROOT, MODPACK_LOCKFILE_NAME);
179
- await writeLockfile(createEmptyLockfile(), outputPath);
267
+ if (config.dryRun) {
268
+ log(`[DRY RUN] Would write lockfile to: ${outputPath}`);
269
+ } else {
270
+ await writeLockfile(createEmptyLockfile(), outputPath, log);
271
+ }
180
272
  return;
181
273
  }
182
274
 
183
- console.log(`\nTotal files found: ${allFileEntries.length}`);
184
- console.log('\nQuerying Modrinth API...');
275
+ log(`\nTotal files found: ${allFileEntries.length}`);
276
+ log('\nQuerying Modrinth API...');
185
277
 
186
278
  // Extract all hashes
187
279
  const hashes = allFileEntries.map(info => info.hash);
@@ -189,21 +281,31 @@ async function main() {
189
281
  // Query Modrinth API
190
282
  const versionData = await getVersionsFromHashes(hashes);
191
283
 
192
- console.log(`\nFound version information for ${Object.keys(versionData).length} out of ${hashes.length} files`);
284
+ log(`\nFound version information for ${Object.keys(versionData).length} out of ${hashes.length} files`);
193
285
 
194
286
  // Create lockfile
195
287
  const lockfile = createLockfile(allFileEntries, versionData);
196
288
 
197
289
  // Write lockfile
198
290
  const outputPath = path.join(WORKSPACE_ROOT, MODPACK_LOCKFILE_NAME);
199
- await writeLockfile(lockfile, outputPath);
291
+ if (config.dryRun) {
292
+ log(`[DRY RUN] Would write lockfile to: ${outputPath}`);
293
+ } else {
294
+ await writeLockfile(lockfile, outputPath, log);
295
+ }
200
296
 
201
297
  // Summary
202
- console.log('\n=== Summary ===');
298
+ log('\n=== Summary ===');
203
299
  for (const [category, entries] of Object.entries(lockfile.dependencies)) {
204
300
  const withVersion = entries.filter(e => e.version !== null).length;
205
301
  const withoutVersion = entries.length - withVersion;
206
- console.log(`${category}: ${entries.length} file(s) (${withVersion} found on Modrinth, ${withoutVersion} unknown)`);
302
+ log(`${category}: ${entries.length} file(s) (${withVersion} found on Modrinth, ${withoutVersion} unknown)`);
303
+ }
304
+
305
+ // Generate .gitignore rules if requested
306
+ if (config.gitignore) {
307
+ log('\n=== .gitignore Rules ===');
308
+ log(generateGitignoreRules(lockfile));
207
309
  }
208
310
  }
209
311
 
package/package.json CHANGED
@@ -1,8 +1,7 @@
1
1
  {
2
2
  "name": "modpack-lock",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Create a modpack lockfile for files hosted on Modrinth (mods, resource packs, shaders and datapacks)",
5
- "homepage": "https://github.com/nickesc/modpack-lock#readme",
6
5
  "bugs": {
7
6
  "url": "https://github.com/nickesc/modpack-lock/issues"
8
7
  },