modcrawl 0.0.0-stage → 0.9.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 SirCesarium
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,302 @@
1
- # Temporary Holding Version
1
+ # modcrawl
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ [![Crates.io](https://img.shields.io/crates/v/modcrawl?style=flat-square)](https://crates.io/crates/modcrawl)
4
+ [![CI](https://img.shields.io/github/actions/workflow/status/SirCesarium/modcrawl/ci.yml?branch=main&style=flat-square)](https://github.com/SirCesarium/modcrawl/actions)
5
+ [![License](https://img.shields.io/github/license/SirCesarium/modcrawl?style=flat-square)]()
6
+
7
+ Detect, inspect, and analyze Minecraft mods and plugins from JARs.
8
+
9
+ ```bash
10
+ modcrawl type MyMod.jar # → Fabric
11
+ modcrawl metadata MyMod.jar # mod name, version, authors, license
12
+ modcrawl metadata MyMod.jar --json # same, as JSON
13
+ modcrawl deps MyMod.jar # dependencies with version ranges
14
+ modcrawl deps MyMod.jar --include-jar-in-jar # include embedded JARs
15
+ modcrawl classes MyMod.jar # list .class files
16
+ modcrawl grep "func_" MyMod.jar # search constant pool
17
+ modcrawl mixins MyMod.jar # extract @Mixin targets
18
+ modcrawl dupes a.jar b.jar c.jar # find duplicate classes
19
+ ```
20
+
21
+ ```bash
22
+ cat *.jar | modcrawl type # detect many at once
23
+ modcrawl deps *.jar # per-file, continues on error
24
+ modcrawl grep "net/minecraft/world" *.jar --quiet # which mods reference a class
25
+ modcrawl mixins *.jar --quiet # which jars have mixins
26
+ modcrawl dupes *.jar --json # JSON of all class dupes
27
+ ```
28
+
29
+ ## How it works
30
+
31
+ Inspects the ZIP entries inside a JAR without extracting. Picks the first matching sentinel file (Paper > Bukkit > NeoForge > Forge mods.toml > Forge mcmod.info > Fabric), then parses the corresponding metadata file and extracts dependency declarations.
32
+
33
+ ## Supported loaders
34
+
35
+ | Loader | Sentinel file | Metadata format |
36
+ |--------|---------------|-----------------|
37
+ | Fabric | `fabric.mod.json` | JSON |
38
+ | Forge (mods.toml) | `META-INF/mods.toml` | TOML |
39
+ | NeoForge | `META-INF/neoforge.mods.toml` | TOML |
40
+ | Forge (mcmod.info) | `mcmod.info` | JSON |
41
+ | Bukkit / Spigot | `plugin.yml` | YAML |
42
+ | Paper | `paper-plugin.yml` | YAML |
43
+
44
+ Adding a new loader means one new module implementing `ModHandler` and a single `register()` call — no core changes.
45
+
46
+ ## Install
47
+
48
+ ```bash
49
+ cargo install modcrawl
50
+ ```
51
+
52
+ Or download a prebuilt binary from [GitHub Releases](https://github.com/SirCesarium/modcrawl/releases) — the `modcrawl.h` header is shipped as a standalone asset (not inside archives).
53
+
54
+ ## Library
55
+
56
+ ```bash
57
+ cargo add modcrawl --no-default-features
58
+ ```
59
+
60
+ ```rust
61
+ use modcrawl::core::identify::identify;
62
+ use modcrawl::core::metadata::read_metadata;
63
+ use modcrawl::core::dep::analyze;
64
+
65
+ let mod_type = identify("MyMod.jar".as_ref())?;
66
+
67
+ let meta = read_metadata("MyMod.jar".as_ref())?;
68
+ println!("{meta}"); // human-readable
69
+ println!("{}", serde_json::to_string(&meta)?); // JSON
70
+
71
+ let report = analyze("MyMod.jar".as_ref(), false)?; // exclude jar-in-jar
72
+ for dep in &report.dependencies {
73
+ println!(" {} {}", dep.kind.marker(), dep.name);
74
+ }
75
+ ```
76
+
77
+ Reader variants for in-memory buffers:
78
+
79
+ ```rust
80
+ use std::io::Cursor;
81
+ use modcrawl::core::identify::identify_reader;
82
+ use modcrawl::core::metadata::read_metadata_reader;
83
+ use modcrawl::core::dep::analyze_reader;
84
+
85
+ let data = std::fs::read("MyMod.jar")?;
86
+ let mut cursor = Cursor::new(&data[..]);
87
+ let mod_type = identify_reader(&mut cursor)?;
88
+ ```
89
+
90
+ ## Dependency analysis
91
+
92
+ Dependencies are deduplicated by name. When the same dependency appears with different kinds (e.g. `depends` + `recommends`), the higher-priority kind wins:
93
+
94
+ Required > LoadBefore > Optional > Recommended > Suggested
95
+
96
+ Jar-in-jar entries (`META-INF/jars/*.jar`) are always scanned internally. If a dependency matches a bundled JAR's filename, it's removed from the external dependency list. The `--include-jar-in-jar` flag controls whether the jar-in-jar section appears in the output.
97
+
98
+ ## FFI / C bindings
99
+
100
+ Every core function is exposed as a C-compatible export:
101
+
102
+ | Function | Returns |
103
+ |----------|---------|
104
+ | `modcrawl_identify(path)` | Type string |
105
+ | `modcrawl_identify_bytes(data, len)` | Type string |
106
+ | `modcrawl_metadata(path)` | Human-readable metadata |
107
+ | `modcrawl_metadata_json(path)` | JSON metadata |
108
+ | `modcrawl_metadata_bytes(data, len)` | Human-readable metadata |
109
+ | `modcrawl_metadata_json_bytes(data, len)` | JSON metadata |
110
+ | `modcrawl_deps(path, include_jij)` | Human-readable deps |
111
+ | `modcrawl_deps_json(path, include_jij)` | JSON deps |
112
+ | `modcrawl_deps_bytes(data, len, include_jij)` | Human-readable deps |
113
+ | `modcrawl_deps_json_bytes(data, len, include_jij)` | JSON deps |
114
+ | `modcrawl_classes_json(path)` | JSON list of .class files |
115
+ | `modcrawl_grep_json(path, pattern)` | JSON grep matches |
116
+ | `modcrawl_mixins_json(path)` | JSON list of mixin targets |
117
+ | `modcrawl_dupes_json(paths)` | JSON list of duplicate classes |
118
+ | `modcrawl_free_string(s)` | — (frees returned strings) |
119
+
120
+ The classes, grep, mixins and dupes exports require the `classfile` feature,
121
+ which every published library is built with. `modcrawl_dupes_json` takes a
122
+ null-terminated `char *const *paths` — the canonical call passes a
123
+ `char *paths[]` array:
124
+
125
+ ```c
126
+ #include "modcrawl.h"
127
+
128
+ char *type = modcrawl_identify("/path/to/MyMod.jar");
129
+ if (type) {
130
+ printf("Type: %s\n", type);
131
+ modcrawl_free_string(type);
132
+ }
133
+
134
+ // Metadata as JSON
135
+ char *json = modcrawl_metadata_json("/path/to/MyMod.jar");
136
+ if (json) {
137
+ printf("%s\n", json);
138
+ modcrawl_free_string(json);
139
+ }
140
+
141
+ // Duplicate classes across JARs
142
+ char *paths[] = {"/path/to/a.jar", "/path/to/b.jar", NULL};
143
+ char *dupes = modcrawl_dupes_json(paths);
144
+ if (dupes) {
145
+ printf("%s\n", dupes);
146
+ modcrawl_free_string(dupes);
147
+ }
148
+ ```
149
+
150
+ ### Contract
151
+
152
+ - **Ownership**: every string-returning function hands you a null-terminated C
153
+ string that must be freed with `modcrawl_free_string` — never with `free()`,
154
+ the allocation belongs to Rust's allocator. Passing `NULL` to
155
+ `modcrawl_free_string` is a no-op.
156
+ - **Errors**: `NULL` means an error occurred, and the reason is printed to
157
+ stderr. A zero-length buffer is also an error.
158
+ - **Interior NULs**: mod metadata can legally contain a NUL character. These
159
+ are replaced with U+FFFD so a crafted JAR can never turn a successful parse
160
+ into an error return.
161
+ - **Paths**: `modcrawl_dupes_json` requires valid UTF-8 paths; one that is not
162
+ is an error, not a silently skipped JAR.
163
+ - **Thread safety**: every function may be called concurrently from any thread.
164
+ - **Panics**: contained. A panic inside the parser is reported on stderr and
165
+ surfaces as `NULL` instead of aborting your process.
166
+
167
+ ### Using the header
168
+
169
+ The `modcrawl.h` header ships as a release asset and inside every library
170
+ archive. It compiles as both C and C++, and is generated by
171
+ [cbindgen](https://github.com/mozilla/cbindgen) from `cbindgen.toml`:
172
+
173
+ ```bash
174
+ cbindgen --config cbindgen.toml --crate modcrawl --output modcrawl.h
175
+ ```
176
+
177
+ CI verifies on every push that the header compiles as C and C++ with
178
+ `-Wall -Wextra -Werror`, that it matches the symbols each library actually
179
+ exports, and that a C smoke test runs end to end (`tests/ffi/smoke.c`).
180
+
181
+ **The header describes a default-features build.** If you compile the crate
182
+ yourself with `--no-default-features`, the `classfile` feature (and with it
183
+ `modcrawl_classes_json`, `modcrawl_grep_json`, `modcrawl_mixins_json` and
184
+ `modcrawl_dupes_json`) is compiled out — the library exports 11 symbols while
185
+ the header declares 15. Every library we publish is built with the default
186
+ features, so this only bites source builds; CI pins the contract so it cannot
187
+ drift silently.
188
+
189
+ One packaging note: the musl libraries ship a **static library only**
190
+ (`libmodcrawl.a`). Rust drops the cdylib on static-by-default targets and the
191
+ musl toolchain used in CI cannot link a shared object. Every other ABI ships
192
+ both a static and a shared library.
193
+
194
+ ## CLI reference
195
+
196
+ | Command | Alias | What |
197
+ |---------|-------|------|
198
+ | `type` | `t`, `ty` | Detect mod/plugin type |
199
+ | `metadata` | `meta`, `md` | Read mod metadata (human or `-j` JSON) |
200
+ | `dep` | `d`, `deps`, `dependencies` | Analyze dependencies (`-j` JSON, `--include-jar-in-jar`/`--jij`) |
201
+ | `classes` | `c`, `cls` | List `.class` files with Java version and access flags |
202
+ | `grep` | `g`, `search` | Search constant pool strings across all `.class` files |
203
+ | `mixins` | `m`, `mixin` | Extract `@Mixin` targets from class-level annotations |
204
+ | `dupes` | `dp`, `duplicate` | Find duplicate `.class` entries across multiple JARs |
205
+
206
+ ### `type`
207
+
208
+ Reads from stdin when given no file arguments. Stdin can be raw ZIP bytes (detects EOCD boundaries for `cat *.jar`) or newline-separated file paths.
209
+
210
+ ### `metadata`
211
+
212
+ Takes one or more JAR paths. Multi-file output prefixes each result with the filename. `--json` / `-j` for compact JSON (one line per file).
213
+
214
+ ### `dep` / `deps`
215
+
216
+ Takes one or more JAR paths. `--json` / `-j` for pretty-printed JSON. `--include-jar-in-jar` / `--jij` to show embedded JARs. Bundled dependencies are always filtered out of the external dependency list regardless of this flag.
217
+
218
+ ### `classes` (requires `classfile` feature)
219
+
220
+ Lists every `.class` file inside a JAR with its Java version and access flags.
221
+
222
+ ```
223
+ $ modcrawl classes MyMod.jar
224
+ mezz/jei/JustEnoughItems.class Java 8 public
225
+ mezz/jei/color/ColorGetter.class Java 8 public final
226
+ ```
227
+
228
+ `--json` / `-j` for machine-readable output.
229
+
230
+ ### `grep` (requires `classfile` feature)
231
+
232
+ Searches the **constant pool** of every `.class` file inside a JAR — no decompilation needed. Finds class references, method calls, field accesses, annotations, and raw UTF-8 strings.
233
+
234
+ ```
235
+ $ modcrawl grep "func_186724_a" MyMod.jar
236
+ mezz/jei/color/ColorGetter.class:
237
+ Utf8: "(Lnet/minecraft/world/IBlockAccess;...)I"
238
+ MethodRef: "net/minecraft/client/renderer/color/BlockColors.func_186724_a:..."
239
+
240
+ $ modcrawl grep "net/minecraft/world" *.jar --quiet
241
+ jei_1.12.2-4.16.1.1013.jar:
242
+ mezz/jei/color/ColorGetter.class
243
+ mezz/jei/plugins/vanilla/anvil/AnvilRecipeMaker.class
244
+ ```
245
+
246
+ Useful for crash investigation: find which mod references an obfuscated function or class without opening a single JAR.
247
+
248
+ Flags: `--quiet` / `-q` (only show class file names), `--json` / `-j` (JSON output).
249
+
250
+ ### `mixins` (requires `classfile` feature)
251
+
252
+ Extracts `@Mixin` targets from SpongePowered mixin annotations at the class level. Parses `RuntimeVisibleAnnotations` / `RuntimeInvisibleAnnotations` attributes and resolves both `value` (Class ref) and `targets` (String ref) element pairs — no decompilation needed.
253
+
254
+ ```
255
+ $ modcrawl mixins MyMod.jar
256
+ some/mod/mixin/ExampleMixin.class ->
257
+ net/minecraft/world/entity/player/Player
258
+ another/mod/mixin/TitleScreenMixin.class ->
259
+ net/minecraft/client/gui/screens/TitleScreen
260
+ ```
261
+
262
+ `--quiet` / `-q` (only show mixin class names), `--json` / `-j` (JSON output).
263
+
264
+ ### `dupes` (requires `classfile` feature)
265
+
266
+ Finds `.class` files that appear in more than one JAR — useful for detecting classpath conflicts between mods. Uses zip entry listing only, no classfile parsing needed.
267
+
268
+ By default, output is grouped by conflict pair (two JARs that share classes):
269
+
270
+ ```
271
+ $ modcrawl dupes a.jar b.jar c.jar
272
+ ── Classpath Conflicts ──
273
+
274
+ a.jar
275
+ b.jar
276
+ ── 3 shared classes ──
277
+ com/example/SomeClass.class
278
+ com/example/OtherClass.class
279
+ com/example/ThirdClass.class
280
+ ```
281
+
282
+ `--by-class` / `-b` groups by class instead (legacy format), showing how many JARs each class appears in:
283
+
284
+ ```
285
+ $ modcrawl dupes a.jar b.jar c.jar --by-class
286
+ com/example/SomeClass.class (in 2 JARs)
287
+ a.jar
288
+ b.jar
289
+ ```
290
+
291
+ `--count` / `-c` shows only a summary:
292
+
293
+ ```
294
+ $ modcrawl dupes *.jar --count
295
+ Found 42 duplicate classes across 15 JAR files.
296
+ ```
297
+
298
+ `--json` / `-j` for machine-readable output. Combine with `--count` for a compact JSON summary.
299
+
300
+ ## License
301
+
302
+ MIT
package/modcrawl.d.ts ADDED
@@ -0,0 +1,131 @@
1
+ /* tslint:disable */
2
+ /* eslint-disable */
3
+
4
+ /**
5
+ * List all .class files from a ZIP/JAR byte buffer, returning JSON.
6
+ *
7
+ * # Errors
8
+ *
9
+ * Returns a JS exception when the JAR is invalid.
10
+ */
11
+ export function classes_json(data: Uint8Array): string;
12
+
13
+ /**
14
+ * Analyze dependencies from a ZIP/JAR byte buffer, returning JSON.
15
+ *
16
+ * `include_jij` controls whether embedded JAR-in-JAR entries appear in
17
+ * the output.
18
+ *
19
+ * # Errors
20
+ *
21
+ * Returns a JS exception when the JAR is invalid or cannot be parsed.
22
+ */
23
+ export function deps_json(data: Uint8Array, include_jij: boolean): string;
24
+
25
+ /**
26
+ * Find duplicate class entries across multiple ZIP/JAR byte buffers,
27
+ * returning JSON.
28
+ *
29
+ * `names` and `jars` are parallel arrays: `names[i]` labels `jars[i]`.
30
+ *
31
+ * # Errors
32
+ *
33
+ * Returns a JS exception when any buffer is not a valid ZIP archive, or
34
+ * when the arrays differ in length.
35
+ */
36
+ export function dupes_json(names: string[], jars: Array<any>): string;
37
+
38
+ /**
39
+ * Search the constant pool of all .class files in a ZIP/JAR byte buffer,
40
+ * returning JSON.
41
+ *
42
+ * # Errors
43
+ *
44
+ * Returns a JS exception when the JAR is invalid.
45
+ */
46
+ export function grep_json(data: Uint8Array, pattern: string): string;
47
+
48
+ /**
49
+ * Detect the mod/plugin type from a ZIP/JAR byte buffer.
50
+ *
51
+ * # Errors
52
+ *
53
+ * Returns a JS exception when the data is not a valid ZIP archive.
54
+ */
55
+ export function identify(data: Uint8Array): string;
56
+
57
+ /**
58
+ * Read and parse metadata from a ZIP/JAR byte buffer, returning JSON.
59
+ *
60
+ * # Errors
61
+ *
62
+ * Returns a JS exception when the JAR is invalid or its metadata cannot
63
+ * be parsed.
64
+ */
65
+ export function metadata_json(data: Uint8Array): string;
66
+
67
+ /**
68
+ * Extract mixin targets from a ZIP/JAR byte buffer, returning JSON.
69
+ *
70
+ * # Errors
71
+ *
72
+ * Returns a JS exception when the JAR is invalid.
73
+ */
74
+ export function mixins_json(data: Uint8Array): string;
75
+
76
+ export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
77
+
78
+ export interface InitOutput {
79
+ readonly memory: WebAssembly.Memory;
80
+ readonly classes_json: (a: number, b: number) => [number, number, number, number];
81
+ readonly deps_json: (a: number, b: number, c: number) => [number, number, number, number];
82
+ readonly dupes_json: (a: number, b: number, c: any) => [number, number, number, number];
83
+ readonly grep_json: (a: number, b: number, c: number, d: number) => [number, number, number, number];
84
+ readonly identify: (a: number, b: number) => [number, number, number, number];
85
+ readonly metadata_json: (a: number, b: number) => [number, number, number, number];
86
+ readonly mixins_json: (a: number, b: number) => [number, number, number, number];
87
+ readonly modcrawl_classes_json: (a: number) => number;
88
+ readonly modcrawl_deps: (a: number, b: number) => number;
89
+ readonly modcrawl_deps_bytes: (a: number, b: number, c: number) => number;
90
+ readonly modcrawl_deps_json_bytes: (a: number, b: number, c: number) => number;
91
+ readonly modcrawl_dupes_json: (a: number) => number;
92
+ readonly modcrawl_free_string: (a: number) => void;
93
+ readonly modcrawl_grep_json: (a: number, b: number) => number;
94
+ readonly modcrawl_identify: (a: number) => number;
95
+ readonly modcrawl_identify_bytes: (a: number, b: number) => number;
96
+ readonly modcrawl_metadata_bytes: (a: number, b: number) => number;
97
+ readonly modcrawl_metadata_json_bytes: (a: number, b: number) => number;
98
+ readonly modcrawl_metadata: (a: number) => number;
99
+ readonly modcrawl_metadata_json: (a: number) => number;
100
+ readonly modcrawl_mixins_json: (a: number) => number;
101
+ readonly modcrawl_deps_json: (a: number, b: number) => number;
102
+ readonly __wbindgen_malloc: (a: number, b: number) => number;
103
+ readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
104
+ readonly __wbindgen_externrefs: WebAssembly.Table;
105
+ readonly __externref_table_dealloc: (a: number) => void;
106
+ readonly __wbindgen_free: (a: number, b: number, c: number) => void;
107
+ readonly __externref_table_alloc: () => number;
108
+ readonly __wbindgen_start: () => void;
109
+ }
110
+
111
+ export type SyncInitInput = BufferSource | WebAssembly.Module;
112
+
113
+ /**
114
+ * Instantiates the given `module`, which can either be bytes or
115
+ * a precompiled `WebAssembly.Module`.
116
+ *
117
+ * @param {{ module: SyncInitInput }} module - Passing `SyncInitInput` directly is deprecated.
118
+ *
119
+ * @returns {InitOutput}
120
+ */
121
+ export function initSync(module: { module: SyncInitInput } | SyncInitInput): InitOutput;
122
+
123
+ /**
124
+ * If `module_or_path` is {RequestInfo} or {URL}, makes a request and
125
+ * for everything else, calls `WebAssembly.instantiate` directly.
126
+ *
127
+ * @param {{ module_or_path: InitInput | Promise<InitInput> }} module_or_path - Passing `InitInput` directly is deprecated.
128
+ *
129
+ * @returns {Promise<InitOutput>}
130
+ */
131
+ export default function __wbg_init (module_or_path?: { module_or_path: InitInput | Promise<InitInput> } | InitInput | Promise<InitInput>): Promise<InitOutput>;
package/modcrawl.js ADDED
@@ -0,0 +1,499 @@
1
+ /* @ts-self-types="./modcrawl.d.ts" */
2
+
3
+ /**
4
+ * List all .class files from a ZIP/JAR byte buffer, returning JSON.
5
+ *
6
+ * # Errors
7
+ *
8
+ * Returns a JS exception when the JAR is invalid.
9
+ * @param {Uint8Array} data
10
+ * @returns {string}
11
+ */
12
+ export function classes_json(data) {
13
+ let deferred3_0;
14
+ let deferred3_1;
15
+ try {
16
+ const ptr0 = passArray8ToWasm0(data, wasm.__wbindgen_malloc);
17
+ const len0 = WASM_VECTOR_LEN;
18
+ const ret = wasm.classes_json(ptr0, len0);
19
+ var ptr2 = ret[0];
20
+ var len2 = ret[1];
21
+ if (ret[3]) {
22
+ ptr2 = 0; len2 = 0;
23
+ throw takeFromExternrefTable0(ret[2]);
24
+ }
25
+ deferred3_0 = ptr2;
26
+ deferred3_1 = len2;
27
+ return getStringFromWasm0(ptr2, len2);
28
+ } finally {
29
+ wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);
30
+ }
31
+ }
32
+
33
+ /**
34
+ * Analyze dependencies from a ZIP/JAR byte buffer, returning JSON.
35
+ *
36
+ * `include_jij` controls whether embedded JAR-in-JAR entries appear in
37
+ * the output.
38
+ *
39
+ * # Errors
40
+ *
41
+ * Returns a JS exception when the JAR is invalid or cannot be parsed.
42
+ * @param {Uint8Array} data
43
+ * @param {boolean} include_jij
44
+ * @returns {string}
45
+ */
46
+ export function deps_json(data, include_jij) {
47
+ let deferred3_0;
48
+ let deferred3_1;
49
+ try {
50
+ const ptr0 = passArray8ToWasm0(data, wasm.__wbindgen_malloc);
51
+ const len0 = WASM_VECTOR_LEN;
52
+ const ret = wasm.deps_json(ptr0, len0, include_jij);
53
+ var ptr2 = ret[0];
54
+ var len2 = ret[1];
55
+ if (ret[3]) {
56
+ ptr2 = 0; len2 = 0;
57
+ throw takeFromExternrefTable0(ret[2]);
58
+ }
59
+ deferred3_0 = ptr2;
60
+ deferred3_1 = len2;
61
+ return getStringFromWasm0(ptr2, len2);
62
+ } finally {
63
+ wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);
64
+ }
65
+ }
66
+
67
+ /**
68
+ * Find duplicate class entries across multiple ZIP/JAR byte buffers,
69
+ * returning JSON.
70
+ *
71
+ * `names` and `jars` are parallel arrays: `names[i]` labels `jars[i]`.
72
+ *
73
+ * # Errors
74
+ *
75
+ * Returns a JS exception when any buffer is not a valid ZIP archive, or
76
+ * when the arrays differ in length.
77
+ * @param {string[]} names
78
+ * @param {Array<any>} jars
79
+ * @returns {string}
80
+ */
81
+ export function dupes_json(names, jars) {
82
+ let deferred3_0;
83
+ let deferred3_1;
84
+ try {
85
+ const ptr0 = passArrayJsValueToWasm0(names, wasm.__wbindgen_malloc);
86
+ const len0 = WASM_VECTOR_LEN;
87
+ const ret = wasm.dupes_json(ptr0, len0, jars);
88
+ var ptr2 = ret[0];
89
+ var len2 = ret[1];
90
+ if (ret[3]) {
91
+ ptr2 = 0; len2 = 0;
92
+ throw takeFromExternrefTable0(ret[2]);
93
+ }
94
+ deferred3_0 = ptr2;
95
+ deferred3_1 = len2;
96
+ return getStringFromWasm0(ptr2, len2);
97
+ } finally {
98
+ wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);
99
+ }
100
+ }
101
+
102
+ /**
103
+ * Search the constant pool of all .class files in a ZIP/JAR byte buffer,
104
+ * returning JSON.
105
+ *
106
+ * # Errors
107
+ *
108
+ * Returns a JS exception when the JAR is invalid.
109
+ * @param {Uint8Array} data
110
+ * @param {string} pattern
111
+ * @returns {string}
112
+ */
113
+ export function grep_json(data, pattern) {
114
+ let deferred4_0;
115
+ let deferred4_1;
116
+ try {
117
+ const ptr0 = passArray8ToWasm0(data, wasm.__wbindgen_malloc);
118
+ const len0 = WASM_VECTOR_LEN;
119
+ const ptr1 = passStringToWasm0(pattern, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
120
+ const len1 = WASM_VECTOR_LEN;
121
+ const ret = wasm.grep_json(ptr0, len0, ptr1, len1);
122
+ var ptr3 = ret[0];
123
+ var len3 = ret[1];
124
+ if (ret[3]) {
125
+ ptr3 = 0; len3 = 0;
126
+ throw takeFromExternrefTable0(ret[2]);
127
+ }
128
+ deferred4_0 = ptr3;
129
+ deferred4_1 = len3;
130
+ return getStringFromWasm0(ptr3, len3);
131
+ } finally {
132
+ wasm.__wbindgen_free(deferred4_0, deferred4_1, 1);
133
+ }
134
+ }
135
+
136
+ /**
137
+ * Detect the mod/plugin type from a ZIP/JAR byte buffer.
138
+ *
139
+ * # Errors
140
+ *
141
+ * Returns a JS exception when the data is not a valid ZIP archive.
142
+ * @param {Uint8Array} data
143
+ * @returns {string}
144
+ */
145
+ export function identify(data) {
146
+ let deferred3_0;
147
+ let deferred3_1;
148
+ try {
149
+ const ptr0 = passArray8ToWasm0(data, wasm.__wbindgen_malloc);
150
+ const len0 = WASM_VECTOR_LEN;
151
+ const ret = wasm.identify(ptr0, len0);
152
+ var ptr2 = ret[0];
153
+ var len2 = ret[1];
154
+ if (ret[3]) {
155
+ ptr2 = 0; len2 = 0;
156
+ throw takeFromExternrefTable0(ret[2]);
157
+ }
158
+ deferred3_0 = ptr2;
159
+ deferred3_1 = len2;
160
+ return getStringFromWasm0(ptr2, len2);
161
+ } finally {
162
+ wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);
163
+ }
164
+ }
165
+
166
+ /**
167
+ * Read and parse metadata from a ZIP/JAR byte buffer, returning JSON.
168
+ *
169
+ * # Errors
170
+ *
171
+ * Returns a JS exception when the JAR is invalid or its metadata cannot
172
+ * be parsed.
173
+ * @param {Uint8Array} data
174
+ * @returns {string}
175
+ */
176
+ export function metadata_json(data) {
177
+ let deferred3_0;
178
+ let deferred3_1;
179
+ try {
180
+ const ptr0 = passArray8ToWasm0(data, wasm.__wbindgen_malloc);
181
+ const len0 = WASM_VECTOR_LEN;
182
+ const ret = wasm.metadata_json(ptr0, len0);
183
+ var ptr2 = ret[0];
184
+ var len2 = ret[1];
185
+ if (ret[3]) {
186
+ ptr2 = 0; len2 = 0;
187
+ throw takeFromExternrefTable0(ret[2]);
188
+ }
189
+ deferred3_0 = ptr2;
190
+ deferred3_1 = len2;
191
+ return getStringFromWasm0(ptr2, len2);
192
+ } finally {
193
+ wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);
194
+ }
195
+ }
196
+
197
+ /**
198
+ * Extract mixin targets from a ZIP/JAR byte buffer, returning JSON.
199
+ *
200
+ * # Errors
201
+ *
202
+ * Returns a JS exception when the JAR is invalid.
203
+ * @param {Uint8Array} data
204
+ * @returns {string}
205
+ */
206
+ export function mixins_json(data) {
207
+ let deferred3_0;
208
+ let deferred3_1;
209
+ try {
210
+ const ptr0 = passArray8ToWasm0(data, wasm.__wbindgen_malloc);
211
+ const len0 = WASM_VECTOR_LEN;
212
+ const ret = wasm.mixins_json(ptr0, len0);
213
+ var ptr2 = ret[0];
214
+ var len2 = ret[1];
215
+ if (ret[3]) {
216
+ ptr2 = 0; len2 = 0;
217
+ throw takeFromExternrefTable0(ret[2]);
218
+ }
219
+ deferred3_0 = ptr2;
220
+ deferred3_1 = len2;
221
+ return getStringFromWasm0(ptr2, len2);
222
+ } finally {
223
+ wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);
224
+ }
225
+ }
226
+ function __wbg_get_imports() {
227
+ const import0 = {
228
+ __proto__: null,
229
+ __wbg_Error_30c8987f7c2ed4e2: function(arg0, arg1) {
230
+ const ret = Error(getStringFromWasm0(arg0, arg1));
231
+ return ret;
232
+ },
233
+ __wbg___wbindgen_string_get_0380ccaa2f57f0d9: function(arg0, arg1) {
234
+ const obj = arg1;
235
+ const ret = typeof(obj) === 'string' ? obj : undefined;
236
+ var ptr1 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
237
+ var len1 = WASM_VECTOR_LEN;
238
+ getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
239
+ getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
240
+ },
241
+ __wbg___wbindgen_throw_41e9ee4f547fc59a: function(arg0, arg1) {
242
+ throw new Error(getStringFromWasm0(arg0, arg1));
243
+ },
244
+ __wbg_get_unchecked_288889d017702237: function(arg0, arg1) {
245
+ const ret = arg0[arg1 >>> 0];
246
+ return ret;
247
+ },
248
+ __wbg_length_7f3c00c40364105e: function(arg0) {
249
+ const ret = arg0.length;
250
+ return ret;
251
+ },
252
+ __wbg_length_d4bdea10311bd9cf: function(arg0) {
253
+ const ret = arg0.length;
254
+ return ret;
255
+ },
256
+ __wbg_new_1dbf7428bba60a42: function(arg0) {
257
+ const ret = new Uint8Array(arg0);
258
+ return ret;
259
+ },
260
+ __wbg_prototypesetcall_bc27214492979395: function(arg0, arg1, arg2) {
261
+ Uint8Array.prototype.set.call(getArrayU8FromWasm0(arg0, arg1), arg2);
262
+ },
263
+ __wbindgen_init_externref_table: function() {
264
+ const table = wasm.__wbindgen_externrefs;
265
+ const offset = table.grow(4);
266
+ table.set(0, undefined);
267
+ table.set(offset + 0, undefined);
268
+ table.set(offset + 1, null);
269
+ table.set(offset + 2, true);
270
+ table.set(offset + 3, false);
271
+ },
272
+ };
273
+ return {
274
+ __proto__: null,
275
+ "./modcrawl_bg.js": import0,
276
+ };
277
+ }
278
+
279
+ function addToExternrefTable0(obj) {
280
+ const idx = wasm.__externref_table_alloc();
281
+ wasm.__wbindgen_externrefs.set(idx, obj);
282
+ return idx;
283
+ }
284
+
285
+ function getArrayU8FromWasm0(ptr, len) {
286
+ ptr = ptr >>> 0;
287
+ return getUint8ArrayMemory0().subarray(ptr / 1, ptr / 1 + len);
288
+ }
289
+
290
+ let cachedDataViewMemory0 = null;
291
+ function getDataViewMemory0() {
292
+ if (cachedDataViewMemory0 === null || cachedDataViewMemory0.buffer.detached === true || (cachedDataViewMemory0.buffer.detached === undefined && cachedDataViewMemory0.buffer !== wasm.memory.buffer)) {
293
+ cachedDataViewMemory0 = new DataView(wasm.memory.buffer);
294
+ }
295
+ return cachedDataViewMemory0;
296
+ }
297
+
298
+ function getStringFromWasm0(ptr, len) {
299
+ return decodeText(ptr >>> 0, len);
300
+ }
301
+
302
+ let cachedUint8ArrayMemory0 = null;
303
+ function getUint8ArrayMemory0() {
304
+ if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) {
305
+ cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer);
306
+ }
307
+ return cachedUint8ArrayMemory0;
308
+ }
309
+
310
+ function isLikeNone(x) {
311
+ return x === undefined || x === null;
312
+ }
313
+
314
+ function passArray8ToWasm0(arg, malloc) {
315
+ const ptr = malloc(arg.length * 1, 1) >>> 0;
316
+ getUint8ArrayMemory0().set(arg, ptr / 1);
317
+ WASM_VECTOR_LEN = arg.length;
318
+ return ptr;
319
+ }
320
+
321
+ function passArrayJsValueToWasm0(array, malloc) {
322
+ const ptr = malloc(array.length * 4, 4) >>> 0;
323
+ for (let i = 0; i < array.length; i++) {
324
+ const add = addToExternrefTable0(array[i]);
325
+ getDataViewMemory0().setUint32(ptr + 4 * i, add, true);
326
+ }
327
+ WASM_VECTOR_LEN = array.length;
328
+ return ptr;
329
+ }
330
+
331
+ function passStringToWasm0(arg, malloc, realloc) {
332
+ if (realloc === undefined) {
333
+ const buf = cachedTextEncoder.encode(arg);
334
+ const ptr = malloc(buf.length, 1) >>> 0;
335
+ getUint8ArrayMemory0().subarray(ptr, ptr + buf.length).set(buf);
336
+ WASM_VECTOR_LEN = buf.length;
337
+ return ptr;
338
+ }
339
+
340
+ let len = arg.length;
341
+ let ptr = malloc(len, 1) >>> 0;
342
+
343
+ const mem = getUint8ArrayMemory0();
344
+
345
+ let offset = 0;
346
+
347
+ for (; offset < len; offset++) {
348
+ const code = arg.charCodeAt(offset);
349
+ if (code > 0x7F) break;
350
+ mem[ptr + offset] = code;
351
+ }
352
+ if (offset !== len) {
353
+ if (offset !== 0) {
354
+ arg = arg.slice(offset);
355
+ }
356
+ ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0;
357
+ const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len);
358
+ const ret = cachedTextEncoder.encodeInto(arg, view);
359
+
360
+ offset += ret.written;
361
+ ptr = realloc(ptr, len, offset, 1) >>> 0;
362
+ }
363
+
364
+ WASM_VECTOR_LEN = offset;
365
+ return ptr;
366
+ }
367
+
368
+ function takeFromExternrefTable0(idx) {
369
+ const value = wasm.__wbindgen_externrefs.get(idx);
370
+ wasm.__externref_table_dealloc(idx);
371
+ return value;
372
+ }
373
+
374
+ let cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
375
+ cachedTextDecoder.decode();
376
+ const MAX_SAFARI_DECODE_BYTES = 2146435072;
377
+ let numBytesDecoded = 0;
378
+ function decodeText(ptr, len) {
379
+ numBytesDecoded += len;
380
+ if (numBytesDecoded >= MAX_SAFARI_DECODE_BYTES) {
381
+ cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
382
+ cachedTextDecoder.decode();
383
+ numBytesDecoded = len;
384
+ }
385
+ return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len));
386
+ }
387
+
388
+ const cachedTextEncoder = new TextEncoder();
389
+
390
+ if (!('encodeInto' in cachedTextEncoder)) {
391
+ cachedTextEncoder.encodeInto = function (arg, view) {
392
+ const buf = cachedTextEncoder.encode(arg);
393
+ view.set(buf);
394
+ return {
395
+ read: arg.length,
396
+ written: buf.length
397
+ };
398
+ };
399
+ }
400
+
401
+ let WASM_VECTOR_LEN = 0;
402
+
403
+ let wasmModule, wasmInstance, wasm;
404
+ function __wbg_finalize_init(instance, module) {
405
+ wasmInstance = instance;
406
+ wasm = instance.exports;
407
+ wasmModule = module;
408
+ cachedDataViewMemory0 = null;
409
+ cachedUint8ArrayMemory0 = null;
410
+ wasm.__wbindgen_start();
411
+ return wasm;
412
+ }
413
+
414
+ async function __wbg_load(module, imports) {
415
+ if (typeof Response === 'function' && module instanceof Response) {
416
+ if (!module.ok) {
417
+ throw new Error(`failed to fetch Wasm: ${module.status} ${module.statusText} fetching '${module.url}'`);
418
+ }
419
+
420
+ if (typeof WebAssembly.instantiateStreaming === 'function') {
421
+ try {
422
+ return await WebAssembly.instantiateStreaming(module, imports);
423
+ } catch (e) {
424
+ const validResponse = expectedResponseType(module.type);
425
+
426
+ if (validResponse && module.headers.get('Content-Type') !== 'application/wasm') {
427
+ console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve Wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n", e);
428
+
429
+ } else { throw e; }
430
+ }
431
+ }
432
+
433
+ const bytes = await module.arrayBuffer();
434
+ return await WebAssembly.instantiate(bytes, imports);
435
+ } else {
436
+ const instance = await WebAssembly.instantiate(module, imports);
437
+
438
+ if (instance instanceof WebAssembly.Instance) {
439
+ return { instance, module };
440
+ } else {
441
+ return instance;
442
+ }
443
+ }
444
+
445
+ function expectedResponseType(type) {
446
+ switch (type) {
447
+ case 'basic': case 'cors': case 'default': return true;
448
+ }
449
+ return false;
450
+ }
451
+ }
452
+
453
+ function initSync(module) {
454
+ if (wasm !== undefined) return wasm;
455
+
456
+
457
+ if (module !== undefined) {
458
+ if (Object.getPrototypeOf(module) === Object.prototype) {
459
+ ({module} = module)
460
+ } else {
461
+ console.warn('using deprecated parameters for `initSync()`; pass a single object instead')
462
+ }
463
+ }
464
+
465
+ const imports = __wbg_get_imports();
466
+ if (!(module instanceof WebAssembly.Module)) {
467
+ module = new WebAssembly.Module(module);
468
+ }
469
+ const instance = new WebAssembly.Instance(module, imports);
470
+ return __wbg_finalize_init(instance, module);
471
+ }
472
+
473
+ async function __wbg_init(module_or_path) {
474
+ if (wasm !== undefined) return wasm;
475
+
476
+
477
+ if (module_or_path !== undefined) {
478
+ if (Object.getPrototypeOf(module_or_path) === Object.prototype) {
479
+ ({module_or_path} = module_or_path)
480
+ } else {
481
+ console.warn('using deprecated parameters for the initialization function; pass a single object instead')
482
+ }
483
+ }
484
+
485
+ if (module_or_path === undefined) {
486
+ module_or_path = new URL('modcrawl_bg.wasm', import.meta.url);
487
+ }
488
+ const imports = __wbg_get_imports();
489
+
490
+ if (typeof module_or_path === 'string' || (typeof Request === 'function' && module_or_path instanceof Request) || (typeof URL === 'function' && module_or_path instanceof URL)) {
491
+ module_or_path = fetch(module_or_path);
492
+ }
493
+
494
+ const { instance, module } = await __wbg_load(await module_or_path, imports);
495
+
496
+ return __wbg_finalize_init(instance, module);
497
+ }
498
+
499
+ export { initSync, __wbg_init as default };
Binary file
package/package.json CHANGED
@@ -1,6 +1,29 @@
1
1
  {
2
2
  "name": "modcrawl",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "type": "module",
4
+ "description": "Detect, inspect, and analyze Minecraft mods and plugins from JAR files",
5
+ "version": "0.9.1",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/SirCesarium/modcrawl"
10
+ },
11
+ "files": [
12
+ "modcrawl_bg.wasm",
13
+ "modcrawl.js",
14
+ "modcrawl.d.ts"
15
+ ],
16
+ "main": "modcrawl.js",
17
+ "homepage": "https://github.com/SirCesarium/modcrawl",
18
+ "types": "modcrawl.d.ts",
19
+ "sideEffects": [
20
+ "./snippets/*"
21
+ ],
22
+ "keywords": [
23
+ "minecraft",
24
+ "mod",
25
+ "analyzer",
26
+ "loaders",
27
+ "forge"
28
+ ]
29
+ }