@adhisang/minecraft-modding-mcp 3.2.0 → 4.1.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 +72 -0
- package/README.md +52 -32
- package/dist/build-suggested-call.d.ts +29 -0
- package/dist/build-suggested-call.js +58 -0
- package/dist/cache-registry.d.ts +3 -1
- package/dist/cache-registry.js +59 -7
- package/dist/config.d.ts +10 -1
- package/dist/config.js +52 -1
- package/dist/entry-tools/analyze-symbol-service.d.ts +18 -18
- package/dist/entry-tools/analyze-symbol-service.js +13 -2
- package/dist/entry-tools/batch-class-members-service.d.ts +34 -0
- package/dist/entry-tools/batch-class-members-service.js +97 -0
- package/dist/entry-tools/batch-class-source-service.d.ts +37 -0
- package/dist/entry-tools/batch-class-source-service.js +100 -0
- package/dist/entry-tools/batch-mappings-service.d.ts +36 -0
- package/dist/entry-tools/batch-mappings-service.js +66 -0
- package/dist/entry-tools/batch-runner.d.ts +72 -0
- package/dist/entry-tools/batch-runner.js +90 -0
- package/dist/entry-tools/batch-symbol-exists-service.d.ts +46 -0
- package/dist/entry-tools/batch-symbol-exists-service.js +113 -0
- package/dist/entry-tools/compare-minecraft-service.d.ts +6 -6
- package/dist/entry-tools/inspect-minecraft/handlers/artifact.d.ts +5 -0
- package/dist/entry-tools/inspect-minecraft/handlers/artifact.js +83 -0
- package/dist/entry-tools/inspect-minecraft/handlers/class-members.d.ts +6 -0
- package/dist/entry-tools/inspect-minecraft/handlers/class-members.js +80 -0
- package/dist/entry-tools/inspect-minecraft/handlers/class-overview.d.ts +5 -0
- package/dist/entry-tools/inspect-minecraft/handlers/class-overview.js +248 -0
- package/dist/entry-tools/inspect-minecraft/handlers/class-source.d.ts +5 -0
- package/dist/entry-tools/inspect-minecraft/handlers/class-source.js +60 -0
- package/dist/entry-tools/inspect-minecraft/handlers/file.d.ts +5 -0
- package/dist/entry-tools/inspect-minecraft/handlers/file.js +54 -0
- package/dist/entry-tools/inspect-minecraft/handlers/list-files.d.ts +5 -0
- package/dist/entry-tools/inspect-minecraft/handlers/list-files.js +100 -0
- package/dist/entry-tools/inspect-minecraft/handlers/search.d.ts +5 -0
- package/dist/entry-tools/inspect-minecraft/handlers/search.js +155 -0
- package/dist/entry-tools/inspect-minecraft/handlers/versions.d.ts +6 -0
- package/dist/entry-tools/inspect-minecraft/handlers/versions.js +49 -0
- package/dist/entry-tools/inspect-minecraft/internal.d.ts +1042 -0
- package/dist/entry-tools/inspect-minecraft/internal.js +448 -0
- package/dist/entry-tools/inspect-minecraft-service.d.ts +213 -328
- package/dist/entry-tools/inspect-minecraft-service.js +20 -1238
- package/dist/entry-tools/manage-cache-service.d.ts +16 -16
- package/dist/entry-tools/validate-project/cases/access-transformer.d.ts +6 -0
- package/dist/entry-tools/validate-project/cases/access-transformer.js +106 -0
- package/dist/entry-tools/validate-project/cases/access-widener.d.ts +6 -0
- package/dist/entry-tools/validate-project/cases/access-widener.js +86 -0
- package/dist/entry-tools/validate-project/cases/mixin.d.ts +6 -0
- package/dist/entry-tools/validate-project/cases/mixin.js +90 -0
- package/dist/entry-tools/validate-project/cases/project-summary.d.ts +97 -0
- package/dist/entry-tools/validate-project/cases/project-summary.js +346 -0
- package/dist/entry-tools/validate-project/internal.d.ts +135 -0
- package/dist/entry-tools/validate-project/internal.js +287 -0
- package/dist/entry-tools/validate-project-service.d.ts +63 -47
- package/dist/entry-tools/validate-project-service.js +12 -482
- package/dist/entry-tools/verify-mixin-target-service.d.ts +133 -0
- package/dist/entry-tools/verify-mixin-target-service.js +323 -0
- package/dist/error-mapping.d.ts +40 -0
- package/dist/error-mapping.js +139 -0
- package/dist/errors.d.ts +6 -0
- package/dist/errors.js +6 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +170 -1314
- package/dist/lru-list.d.ts +31 -0
- package/dist/lru-list.js +102 -0
- package/dist/mapping/internal-types.d.ts +54 -0
- package/dist/mapping/internal-types.js +14 -0
- package/dist/mapping/loaders/mojang.d.ts +2 -0
- package/dist/mapping/loaders/mojang.js +64 -0
- package/dist/mapping/loaders/tiny-loom.d.ts +2 -0
- package/dist/mapping/loaders/tiny-loom.js +73 -0
- package/dist/mapping/loaders/tiny-maven.d.ts +2 -0
- package/dist/mapping/loaders/tiny-maven.js +104 -0
- package/dist/mapping/loaders/types.d.ts +14 -0
- package/dist/mapping/loaders/types.js +2 -0
- package/dist/mapping/lookup.d.ts +52 -0
- package/dist/mapping/lookup.js +496 -0
- package/dist/mapping/parsers/normalize.d.ts +10 -0
- package/dist/mapping/parsers/normalize.js +52 -0
- package/dist/mapping/parsers/proguard.d.ts +20 -0
- package/dist/mapping/parsers/proguard.js +138 -0
- package/dist/mapping/parsers/symbol-records.d.ts +27 -0
- package/dist/mapping/parsers/symbol-records.js +216 -0
- package/dist/mapping/parsers/tiny.d.ts +9 -0
- package/dist/mapping/parsers/tiny.js +96 -0
- package/dist/mapping/types.d.ts +147 -0
- package/dist/mapping/types.js +2 -0
- package/dist/mapping-pipeline-service.d.ts +10 -1
- package/dist/mapping-pipeline-service.js +16 -3
- package/dist/mapping-service.d.ts +15 -144
- package/dist/mapping-service.js +179 -1119
- package/dist/mixin/access-validators.d.ts +9 -0
- package/dist/mixin/access-validators.js +257 -0
- package/dist/mixin/annotation-validators.d.ts +5 -0
- package/dist/mixin/annotation-validators.js +162 -0
- package/dist/mixin/helpers.d.ts +28 -0
- package/dist/mixin/helpers.js +315 -0
- package/dist/mixin/parsed-validator.d.ts +8 -0
- package/dist/mixin/parsed-validator.js +337 -0
- package/dist/mixin/types.d.ts +208 -0
- package/dist/mixin/types.js +28 -0
- package/dist/mixin-validator.d.ts +9 -201
- package/dist/mixin-validator.js +8 -1005
- package/dist/observability.d.ts +18 -1
- package/dist/observability.js +44 -1
- package/dist/response-utils.d.ts +44 -10
- package/dist/response-utils.js +131 -17
- package/dist/source/access-validate.d.ts +4 -0
- package/dist/source/access-validate.js +254 -0
- package/dist/source/artifact-resolver.d.ts +110 -0
- package/dist/source/artifact-resolver.js +1174 -0
- package/dist/source/cache-metrics.d.ts +26 -0
- package/dist/source/cache-metrics.js +172 -0
- package/dist/source/class-source/members-builder.d.ts +34 -0
- package/dist/source/class-source/members-builder.js +46 -0
- package/dist/source/class-source/snippet-builder.d.ts +19 -0
- package/dist/source/class-source/snippet-builder.js +46 -0
- package/dist/source/class-source-helpers.d.ts +34 -0
- package/dist/source/class-source-helpers.js +140 -0
- package/dist/source/class-source.d.ts +42 -0
- package/dist/source/class-source.js +883 -0
- package/dist/source/descriptor-utils.d.ts +6 -0
- package/dist/source/descriptor-utils.js +37 -0
- package/dist/source/file-access.d.ts +4 -0
- package/dist/source/file-access.js +102 -0
- package/dist/source/indexer.d.ts +82 -0
- package/dist/source/indexer.js +505 -0
- package/dist/source/lifecycle/diff-utils.d.ts +9 -0
- package/dist/source/lifecycle/diff-utils.js +107 -0
- package/dist/source/lifecycle/diff.d.ts +2 -0
- package/dist/source/lifecycle/diff.js +265 -0
- package/dist/source/lifecycle/mapping-helpers.d.ts +22 -0
- package/dist/source/lifecycle/mapping-helpers.js +327 -0
- package/dist/source/lifecycle/runtime-check.d.ts +2 -0
- package/dist/source/lifecycle/runtime-check.js +142 -0
- package/dist/source/lifecycle/trace.d.ts +2 -0
- package/dist/source/lifecycle/trace.js +231 -0
- package/dist/source/lifecycle.d.ts +4 -0
- package/dist/source/lifecycle.js +5 -0
- package/dist/source/search.d.ts +51 -0
- package/dist/source/search.js +676 -0
- package/dist/source/shared-utils.d.ts +6 -0
- package/dist/source/shared-utils.js +55 -0
- package/dist/source/state.d.ts +21 -0
- package/dist/source/state.js +19 -0
- package/dist/source/symbol-resolver.d.ts +3 -0
- package/dist/source/symbol-resolver.js +212 -0
- package/dist/source/validate-mixin/pipeline/mapping-health.d.ts +3 -0
- package/dist/source/validate-mixin/pipeline/mapping-health.js +41 -0
- package/dist/source/validate-mixin/pipeline/parse.d.ts +2 -0
- package/dist/source/validate-mixin/pipeline/parse.js +10 -0
- package/dist/source/validate-mixin/pipeline/resolve.d.ts +3 -0
- package/dist/source/validate-mixin/pipeline/resolve.js +78 -0
- package/dist/source/validate-mixin/pipeline/target-lookup.d.ts +6 -0
- package/dist/source/validate-mixin/pipeline/target-lookup.js +260 -0
- package/dist/source/validate-mixin/pipeline-context.d.ts +72 -0
- package/dist/source/validate-mixin/pipeline-context.js +93 -0
- package/dist/source/validate-mixin.d.ts +22 -0
- package/dist/source/validate-mixin.js +799 -0
- package/dist/source/workspace-target.d.ts +18 -0
- package/dist/source/workspace-target.js +305 -0
- package/dist/source-resolver.d.ts +9 -1
- package/dist/source-resolver.js +14 -6
- package/dist/source-service.d.ts +178 -105
- package/dist/source-service.js +72 -5312
- package/dist/stage-emitter.d.ts +13 -0
- package/dist/stage-emitter.js +30 -0
- package/dist/stdio-supervisor.d.ts +61 -0
- package/dist/stdio-supervisor.js +326 -9
- package/dist/storage/artifacts-repo.d.ts +4 -1
- package/dist/storage/artifacts-repo.js +33 -5
- package/dist/storage/files-repo.d.ts +0 -2
- package/dist/storage/files-repo.js +0 -11
- package/dist/storage/migrations.d.ts +1 -1
- package/dist/storage/migrations.js +10 -2
- package/dist/storage/schema.d.ts +2 -0
- package/dist/storage/schema.js +25 -0
- package/dist/tool-contract-manifest.d.ts +1 -1
- package/dist/tool-contract-manifest.js +23 -6
- package/dist/tool-guidance.d.ts +82 -0
- package/dist/tool-guidance.js +734 -0
- package/dist/tool-schema-registry.d.ts +16 -0
- package/dist/tool-schema-registry.js +37 -0
- package/dist/tool-schemas.d.ts +3518 -0
- package/dist/tool-schemas.js +813 -0
- package/dist/types.d.ts +39 -0
- package/dist/version-service.js +7 -6
- package/dist/workspace-context-cache.d.ts +32 -0
- package/dist/workspace-context-cache.js +66 -0
- package/dist/workspace-mapping-service.d.ts +16 -0
- package/dist/workspace-mapping-service.js +173 -1
- package/docs/README-ja.md +414 -0
- package/docs/examples.md +483 -0
- package/docs/tool-reference.md +459 -0
- package/package.json +5 -2
|
@@ -0,0 +1,496 @@
|
|
|
1
|
+
import { ERROR_CODES, createError } from "../errors.js";
|
|
2
|
+
import { normalizeOptionalProjectPath } from "../gradle-paths.js";
|
|
3
|
+
import { DESCRIPTOR_FALLBACK_CONFIDENCE, MATCH_RANK, MAX_CANDIDATES } from "./internal-types.js";
|
|
4
|
+
import { createClassSymbolRecord, createFieldSymbolRecord, createMethodSymbolRecord, normalizeMappedSymbolOutput, normalizedVariants, simpleName } from "./parsers/symbol-records.js";
|
|
5
|
+
import { pairKey } from "./parsers/normalize.js";
|
|
6
|
+
export { MAX_CANDIDATES };
|
|
7
|
+
export function addCandidates(target, index, symbols, kind, confidence) {
|
|
8
|
+
if (!symbols || symbols.size === 0) {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
const rank = MATCH_RANK[kind];
|
|
12
|
+
for (const key of symbols) {
|
|
13
|
+
const record = index.records.get(key);
|
|
14
|
+
if (!record) {
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
const current = target.get(key);
|
|
18
|
+
if (!current || rank > current.rank || (rank === current.rank && confidence > current.confidence)) {
|
|
19
|
+
target.set(key, {
|
|
20
|
+
key,
|
|
21
|
+
record,
|
|
22
|
+
matchKind: kind,
|
|
23
|
+
confidence,
|
|
24
|
+
rank
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
export function lookupCandidates(index, query) {
|
|
30
|
+
const trimmedQuery = query.symbol.trim();
|
|
31
|
+
const collected = new Map();
|
|
32
|
+
addCandidates(collected, index, index.exact.get(trimmedQuery), "exact", 1);
|
|
33
|
+
for (const variant of normalizedVariants(trimmedQuery)) {
|
|
34
|
+
addCandidates(collected, index, index.normalized.get(variant), "normalized", 0.9);
|
|
35
|
+
}
|
|
36
|
+
if (query.kind === "method" && query.owner && query.descriptor) {
|
|
37
|
+
const descriptorlessKey = `${query.owner}.${query.name}`;
|
|
38
|
+
addCandidates(collected, index, index.exact.get(descriptorlessKey), "normalized", DESCRIPTOR_FALLBACK_CONFIDENCE);
|
|
39
|
+
for (const variant of normalizedVariants(descriptorlessKey)) {
|
|
40
|
+
addCandidates(collected, index, index.normalized.get(variant), "normalized", DESCRIPTOR_FALLBACK_CONFIDENCE);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
const simpleKeys = new Set();
|
|
44
|
+
const shortName = simpleName(trimmedQuery);
|
|
45
|
+
if (shortName) {
|
|
46
|
+
simpleKeys.add(shortName);
|
|
47
|
+
}
|
|
48
|
+
if (query.kind !== "class") {
|
|
49
|
+
simpleKeys.add(query.name);
|
|
50
|
+
}
|
|
51
|
+
if (query.kind === "method" && query.descriptor) {
|
|
52
|
+
simpleKeys.add(`${query.name}${query.descriptor}`);
|
|
53
|
+
}
|
|
54
|
+
for (const key of simpleKeys) {
|
|
55
|
+
addCandidates(collected, index, index.simple.get(key), "simple-name", 0.75);
|
|
56
|
+
}
|
|
57
|
+
return [...collected.values()]
|
|
58
|
+
.sort((left, right) => {
|
|
59
|
+
if (right.confidence !== left.confidence) {
|
|
60
|
+
return right.confidence - left.confidence;
|
|
61
|
+
}
|
|
62
|
+
if (right.rank !== left.rank) {
|
|
63
|
+
return right.rank - left.rank;
|
|
64
|
+
}
|
|
65
|
+
return left.record.symbol.localeCompare(right.record.symbol);
|
|
66
|
+
})
|
|
67
|
+
.slice(0, MAX_CANDIDATES)
|
|
68
|
+
.map(({ record, matchKind, confidence }) => ({
|
|
69
|
+
symbol: record.symbol,
|
|
70
|
+
matchKind,
|
|
71
|
+
confidence,
|
|
72
|
+
kind: record.kind,
|
|
73
|
+
owner: record.owner,
|
|
74
|
+
name: record.name,
|
|
75
|
+
descriptor: record.descriptor
|
|
76
|
+
}));
|
|
77
|
+
}
|
|
78
|
+
export function mappingPriorityFromInput(configPriority, override) {
|
|
79
|
+
if (override === "loom-first" || override === "maven-first") {
|
|
80
|
+
return override;
|
|
81
|
+
}
|
|
82
|
+
return configPriority;
|
|
83
|
+
}
|
|
84
|
+
export function mappingSourceOrder(priority) {
|
|
85
|
+
if (priority === "maven-first") {
|
|
86
|
+
return ["maven", "loom-cache"];
|
|
87
|
+
}
|
|
88
|
+
return ["loom-cache", "maven"];
|
|
89
|
+
}
|
|
90
|
+
export function requiresOnlyObfuscatedMojangGraph(sourceMapping, targetMapping) {
|
|
91
|
+
return sourceMapping !== "intermediary" &&
|
|
92
|
+
sourceMapping !== "yarn" &&
|
|
93
|
+
targetMapping !== "intermediary" &&
|
|
94
|
+
targetMapping !== "yarn";
|
|
95
|
+
}
|
|
96
|
+
export function namespacePath(graph, sourceMapping, targetMapping) {
|
|
97
|
+
if (sourceMapping === targetMapping) {
|
|
98
|
+
return [sourceMapping];
|
|
99
|
+
}
|
|
100
|
+
const key = pairKey(sourceMapping, targetMapping);
|
|
101
|
+
if (graph.pathCache.has(key)) {
|
|
102
|
+
return graph.pathCache.get(key);
|
|
103
|
+
}
|
|
104
|
+
const { adjacency } = graph;
|
|
105
|
+
const queue = [sourceMapping];
|
|
106
|
+
let queueIndex = 0;
|
|
107
|
+
const parent = new Map([[sourceMapping, undefined]]);
|
|
108
|
+
while (queueIndex < queue.length) {
|
|
109
|
+
const current = queue[queueIndex];
|
|
110
|
+
queueIndex += 1;
|
|
111
|
+
if (current === targetMapping) {
|
|
112
|
+
break;
|
|
113
|
+
}
|
|
114
|
+
const neighbors = adjacency.get(current);
|
|
115
|
+
if (!neighbors) {
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
for (const neighbor of neighbors) {
|
|
119
|
+
if (parent.has(neighbor)) {
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
parent.set(neighbor, current);
|
|
123
|
+
queue.push(neighbor);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
if (!parent.has(targetMapping)) {
|
|
127
|
+
graph.pathCache.set(key, undefined);
|
|
128
|
+
return undefined;
|
|
129
|
+
}
|
|
130
|
+
const reversedPath = [];
|
|
131
|
+
let cursor = targetMapping;
|
|
132
|
+
while (cursor) {
|
|
133
|
+
reversedPath.push(cursor);
|
|
134
|
+
cursor = parent.get(cursor);
|
|
135
|
+
}
|
|
136
|
+
const path = reversedPath.reverse();
|
|
137
|
+
graph.pathCache.set(key, path);
|
|
138
|
+
return path;
|
|
139
|
+
}
|
|
140
|
+
export function pathUsesSource(pairs, path, source) {
|
|
141
|
+
for (let index = 0; index < path.length - 1; index += 1) {
|
|
142
|
+
const hop = pairs.get(pairKey(path[index], path[index + 1]));
|
|
143
|
+
if (hop?.source === source) {
|
|
144
|
+
return true;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return false;
|
|
148
|
+
}
|
|
149
|
+
export function pathToTransformChain(path) {
|
|
150
|
+
if (path.length <= 1) {
|
|
151
|
+
return [];
|
|
152
|
+
}
|
|
153
|
+
const transform = [];
|
|
154
|
+
for (let index = 0; index < path.length - 1; index += 1) {
|
|
155
|
+
transform.push(`mapping:${path[index]}->${path[index + 1]}`);
|
|
156
|
+
}
|
|
157
|
+
return transform;
|
|
158
|
+
}
|
|
159
|
+
export function toLookupCandidate(record) {
|
|
160
|
+
return {
|
|
161
|
+
symbol: record.symbol,
|
|
162
|
+
matchKind: "exact",
|
|
163
|
+
confidence: 1,
|
|
164
|
+
kind: record.kind,
|
|
165
|
+
owner: record.owner,
|
|
166
|
+
name: record.name,
|
|
167
|
+
descriptor: record.descriptor
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
export function toSymbolReference(record) {
|
|
171
|
+
return {
|
|
172
|
+
kind: record.kind,
|
|
173
|
+
name: record.kind === "class" ? record.symbol : record.name,
|
|
174
|
+
owner: record.kind === "class" ? undefined : record.owner,
|
|
175
|
+
descriptor: record.kind === "method" ? record.descriptor : undefined,
|
|
176
|
+
symbol: record.symbol
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
export function toResolutionCandidate(candidate) {
|
|
180
|
+
return {
|
|
181
|
+
kind: candidate.kind,
|
|
182
|
+
name: candidate.kind === "class" ? candidate.symbol : candidate.name,
|
|
183
|
+
owner: candidate.kind === "class" ? undefined : candidate.owner,
|
|
184
|
+
descriptor: candidate.kind === "method" ? candidate.descriptor : undefined,
|
|
185
|
+
symbol: candidate.symbol,
|
|
186
|
+
matchKind: candidate.matchKind,
|
|
187
|
+
confidence: candidate.confidence
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
export function invalidInputError(message, details) {
|
|
191
|
+
return createError({
|
|
192
|
+
code: ERROR_CODES.INVALID_INPUT,
|
|
193
|
+
message,
|
|
194
|
+
details
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
export function normalizeMemberName(name) {
|
|
198
|
+
const normalized = name.trim();
|
|
199
|
+
if (!normalized || /[\s./()]/.test(normalized)) {
|
|
200
|
+
throw invalidInputError("name must be a simple member name without separators when kind is field or method.", {
|
|
201
|
+
name
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
return normalized;
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Validate a JVM method descriptor such as `(I)V`, `()Lfoo/Bar;`, `(Lfoo/Bar;[I)V`.
|
|
208
|
+
* Rejects empty strings, missing/mis-positioned parens, empty return type, and invalid base
|
|
209
|
+
* type tokens so "(" or "()" style half-descriptors surface as ERR_INVALID_INPUT instead of
|
|
210
|
+
* being silently accepted.
|
|
211
|
+
*/
|
|
212
|
+
export function normalizeMethodDescriptor(descriptor) {
|
|
213
|
+
const normalized = descriptor?.trim() ?? "";
|
|
214
|
+
if (!normalized) {
|
|
215
|
+
throw invalidInputError("descriptor must be a valid JVM descriptor when kind=method.", {
|
|
216
|
+
descriptor
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
if (!isValidMethodDescriptor(normalized)) {
|
|
220
|
+
throw invalidInputError("descriptor must be a valid JVM descriptor when kind=method.", {
|
|
221
|
+
descriptor
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
return normalized;
|
|
225
|
+
}
|
|
226
|
+
export function isValidMethodDescriptor(descriptor) {
|
|
227
|
+
if (!descriptor.startsWith("("))
|
|
228
|
+
return false;
|
|
229
|
+
const closingIndex = descriptor.indexOf(")");
|
|
230
|
+
if (closingIndex < 0)
|
|
231
|
+
return false;
|
|
232
|
+
const argsSection = descriptor.slice(1, closingIndex);
|
|
233
|
+
const returnSection = descriptor.slice(closingIndex + 1);
|
|
234
|
+
if (returnSection.length === 0)
|
|
235
|
+
return false;
|
|
236
|
+
let cursor = 0;
|
|
237
|
+
while (cursor < argsSection.length) {
|
|
238
|
+
const next = consumeFieldType(argsSection, cursor, /*allowVoid*/ false);
|
|
239
|
+
if (next < 0)
|
|
240
|
+
return false;
|
|
241
|
+
cursor = next;
|
|
242
|
+
}
|
|
243
|
+
const returnEnd = consumeFieldType(returnSection, 0, /*allowVoid*/ true);
|
|
244
|
+
return returnEnd === returnSection.length;
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* JVM specification §4.3.2: "An array type descriptor is valid only if it represents a type
|
|
248
|
+
* with 255 or fewer dimensions." Matches the `multianewarray` / field-signature limit.
|
|
249
|
+
*/
|
|
250
|
+
const JVM_MAX_ARRAY_DIMENSIONS = 255;
|
|
251
|
+
export function consumeFieldType(descriptor, position, allowVoid) {
|
|
252
|
+
// Arrays are handled iteratively so pathological inputs such as `(` + "[".repeat(20000) + `I)V`
|
|
253
|
+
// cannot blow the call stack. After consuming every leading `[`, only the element type token
|
|
254
|
+
// is dispatched through the switch below. Dimensions above the JVM limit are rejected rather
|
|
255
|
+
// than merely accepted as "syntactically valid but semantically absurd" — clients must not be
|
|
256
|
+
// able to push a 20000-dimension descriptor through cache-key construction.
|
|
257
|
+
let cursor = position;
|
|
258
|
+
let arrayDimensions = 0;
|
|
259
|
+
while (cursor < descriptor.length && descriptor[cursor] === "[") {
|
|
260
|
+
cursor += 1;
|
|
261
|
+
arrayDimensions += 1;
|
|
262
|
+
if (arrayDimensions > JVM_MAX_ARRAY_DIMENSIONS)
|
|
263
|
+
return -1;
|
|
264
|
+
}
|
|
265
|
+
if (cursor >= descriptor.length)
|
|
266
|
+
return -1;
|
|
267
|
+
// Void is only valid at the outermost position — inside an array element it is illegal.
|
|
268
|
+
const elementAllowsVoid = cursor === position && allowVoid;
|
|
269
|
+
const token = descriptor[cursor];
|
|
270
|
+
switch (token) {
|
|
271
|
+
case "B":
|
|
272
|
+
case "C":
|
|
273
|
+
case "D":
|
|
274
|
+
case "F":
|
|
275
|
+
case "I":
|
|
276
|
+
case "J":
|
|
277
|
+
case "S":
|
|
278
|
+
case "Z":
|
|
279
|
+
return cursor + 1;
|
|
280
|
+
case "V":
|
|
281
|
+
return elementAllowsVoid ? cursor + 1 : -1;
|
|
282
|
+
case "L": {
|
|
283
|
+
const end = descriptor.indexOf(";", cursor);
|
|
284
|
+
// Reject empty class names like L; and unterminated references.
|
|
285
|
+
if (end < 0 || end === cursor + 1)
|
|
286
|
+
return -1;
|
|
287
|
+
return end + 1;
|
|
288
|
+
}
|
|
289
|
+
default:
|
|
290
|
+
return -1;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
export function normalizeQuerySymbol(input, signatureMode, options) {
|
|
294
|
+
if (input.kind !== "class" && input.kind !== "field" && input.kind !== "method") {
|
|
295
|
+
throw invalidInputError('kind must be one of "class", "field", or "method".', {
|
|
296
|
+
kind: input.kind
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
const normalizedName = input.name?.trim() ?? "";
|
|
300
|
+
if (!normalizedName) {
|
|
301
|
+
throw invalidInputError("name must be a non-empty string.", {
|
|
302
|
+
name: input.name
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
if (input.kind === "class") {
|
|
306
|
+
const owner = input.owner?.trim();
|
|
307
|
+
if (owner) {
|
|
308
|
+
throw invalidInputError("owner is not allowed when kind=class. Use name as FQCN.", {
|
|
309
|
+
owner: input.owner,
|
|
310
|
+
nextAction: 'Provide class as name, e.g. "net.minecraft.server.Main".'
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
if (input.descriptor?.trim()) {
|
|
314
|
+
throw invalidInputError("descriptor is not allowed when kind=class.", {
|
|
315
|
+
descriptor: input.descriptor
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
const className = normalizeMappedSymbolOutput(normalizedName);
|
|
319
|
+
if (!className.includes(".") && !options?.allowShortClassName) {
|
|
320
|
+
throw invalidInputError("name must be a fully qualified class name when kind=class.", {
|
|
321
|
+
name: input.name
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
const record = createClassSymbolRecord(className);
|
|
325
|
+
return {
|
|
326
|
+
record,
|
|
327
|
+
querySymbol: toSymbolReference(record)
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
const owner = normalizeMappedSymbolOutput(input.owner?.trim() ?? "");
|
|
331
|
+
if (!owner) {
|
|
332
|
+
throw invalidInputError("owner is required when kind is field or method.", {
|
|
333
|
+
owner: input.owner,
|
|
334
|
+
kind: input.kind
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
if (input.kind === "field") {
|
|
338
|
+
if (input.descriptor?.trim()) {
|
|
339
|
+
throw invalidInputError("descriptor is not allowed when kind=field.", {
|
|
340
|
+
descriptor: input.descriptor
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
const record = createFieldSymbolRecord(owner, normalizeMemberName(normalizedName));
|
|
344
|
+
return {
|
|
345
|
+
record,
|
|
346
|
+
querySymbol: toSymbolReference(record)
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
let descriptor;
|
|
350
|
+
if (signatureMode === "name-only") {
|
|
351
|
+
// name-only matches by owner+name only; a supplied descriptor is validated (so malformed
|
|
352
|
+
// input still surfaces as ERR_INVALID_INPUT) but discarded afterwards so downstream
|
|
353
|
+
// projection / filtering treats the query as "no descriptor".
|
|
354
|
+
if (input.descriptor?.trim()) {
|
|
355
|
+
normalizeMethodDescriptor(input.descriptor);
|
|
356
|
+
}
|
|
357
|
+
descriptor = "";
|
|
358
|
+
}
|
|
359
|
+
else {
|
|
360
|
+
descriptor = normalizeMethodDescriptor(input.descriptor);
|
|
361
|
+
}
|
|
362
|
+
const record = createMethodSymbolRecord(owner, normalizeMemberName(normalizedName), descriptor);
|
|
363
|
+
return {
|
|
364
|
+
record,
|
|
365
|
+
querySymbol: toSymbolReference(record)
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
export function normalizeOwnerHint(ownerHint) {
|
|
369
|
+
const normalized = ownerHint?.trim();
|
|
370
|
+
if (!normalized) {
|
|
371
|
+
return undefined;
|
|
372
|
+
}
|
|
373
|
+
return normalizeMappedSymbolOutput(normalized);
|
|
374
|
+
}
|
|
375
|
+
export function normalizeDescriptorHint(descriptorHint) {
|
|
376
|
+
const normalized = descriptorHint?.trim();
|
|
377
|
+
return normalized || undefined;
|
|
378
|
+
}
|
|
379
|
+
export function applyDisambiguationHints(candidates, disambiguation) {
|
|
380
|
+
if (!disambiguation || candidates.length <= 1) {
|
|
381
|
+
return candidates;
|
|
382
|
+
}
|
|
383
|
+
let filtered = [...candidates];
|
|
384
|
+
const ownerHint = normalizeOwnerHint(disambiguation.ownerHint);
|
|
385
|
+
if (ownerHint) {
|
|
386
|
+
const ownerMatched = filtered.filter((candidate) => {
|
|
387
|
+
if (candidate.owner) {
|
|
388
|
+
return normalizeMappedSymbolOutput(candidate.owner) === ownerHint;
|
|
389
|
+
}
|
|
390
|
+
const normalizedSymbol = normalizeMappedSymbolOutput(candidate.symbol);
|
|
391
|
+
return normalizedSymbol.startsWith(`${ownerHint}.`);
|
|
392
|
+
});
|
|
393
|
+
if (ownerMatched.length > 0) {
|
|
394
|
+
filtered = ownerMatched;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
const descriptorHint = normalizeDescriptorHint(disambiguation.descriptorHint);
|
|
398
|
+
if (descriptorHint) {
|
|
399
|
+
const descriptorMatched = filtered.filter((candidate) => candidate.descriptor != null && candidate.descriptor === descriptorHint);
|
|
400
|
+
if (descriptorMatched.length > 0) {
|
|
401
|
+
filtered = descriptorMatched;
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
return filtered;
|
|
405
|
+
}
|
|
406
|
+
export function projectLookupCandidateDescriptor(candidate, sourceDescriptor, targetDescriptor) {
|
|
407
|
+
// Tiny mappings preserve method descriptors verbatim, so single-hop tiny paths often
|
|
408
|
+
// return the source descriptor even though the final symbol is already in the target
|
|
409
|
+
// namespace. Multi-hop paths that already produced a target-side descriptor are left
|
|
410
|
+
// unchanged by design.
|
|
411
|
+
if (candidate.kind !== "method" ||
|
|
412
|
+
!candidate.descriptor ||
|
|
413
|
+
!targetDescriptor ||
|
|
414
|
+
candidate.descriptor !== sourceDescriptor) {
|
|
415
|
+
return candidate;
|
|
416
|
+
}
|
|
417
|
+
return {
|
|
418
|
+
...candidate,
|
|
419
|
+
descriptor: targetDescriptor
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
export function effectiveLoomSearchProjectPath(projectPath) {
|
|
423
|
+
return normalizeOptionalProjectPath(projectPath) ?? normalizeOptionalProjectPath(process.cwd());
|
|
424
|
+
}
|
|
425
|
+
export function collectTargetRecords(graph, targetMapping) {
|
|
426
|
+
return [...(graph.recordsByTarget.get(targetMapping) ?? [])];
|
|
427
|
+
}
|
|
428
|
+
export function normalizeIncludedKinds(inputKinds) {
|
|
429
|
+
const normalized = new Set();
|
|
430
|
+
const kinds = inputKinds ?? ["class", "field", "method"];
|
|
431
|
+
for (const kind of kinds) {
|
|
432
|
+
if (kind === "class" || kind === "field" || kind === "method") {
|
|
433
|
+
normalized.add(kind);
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
if (normalized.size === 0) {
|
|
437
|
+
normalized.add("class");
|
|
438
|
+
normalized.add("field");
|
|
439
|
+
normalized.add("method");
|
|
440
|
+
}
|
|
441
|
+
return normalized;
|
|
442
|
+
}
|
|
443
|
+
export function inferAmbiguityReasons(candidates, usedMojangClientMappings) {
|
|
444
|
+
if (candidates.length <= 1) {
|
|
445
|
+
return [];
|
|
446
|
+
}
|
|
447
|
+
const reasons = [];
|
|
448
|
+
const owners = [...new Set(candidates.map((c) => c.owner).filter(Boolean))];
|
|
449
|
+
if (owners.length > 1) {
|
|
450
|
+
reasons.push(`Multiple owner classes matched: ${owners.join(", ")}`);
|
|
451
|
+
}
|
|
452
|
+
const matchKinds = [...new Set(candidates.map((c) => c.matchKind))];
|
|
453
|
+
if (matchKinds.length > 1) {
|
|
454
|
+
reasons.push(`Candidates matched at different precision levels: ${matchKinds.join(", ")}`);
|
|
455
|
+
}
|
|
456
|
+
if (usedMojangClientMappings) {
|
|
457
|
+
const hasDescriptor = candidates.some((c) => c.descriptor);
|
|
458
|
+
const missingDescriptor = candidates.some((c) => !c.descriptor);
|
|
459
|
+
if (hasDescriptor && missingDescriptor) {
|
|
460
|
+
reasons.push("Method descriptor was lost through mojang-client-mappings path, causing broader matching.");
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
if (owners.length <= 1) {
|
|
464
|
+
const descriptors = [...new Set(candidates.map((c) => c.descriptor).filter(Boolean))];
|
|
465
|
+
if (descriptors.length > 1) {
|
|
466
|
+
reasons.push(`Overloaded method: ${descriptors.length} variants`);
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
if (reasons.length === 0) {
|
|
470
|
+
reasons.push(`${candidates.length} candidates matched with similar confidence scores.`);
|
|
471
|
+
}
|
|
472
|
+
return reasons;
|
|
473
|
+
}
|
|
474
|
+
export function clampCandidateLimit(limit) {
|
|
475
|
+
if (!Number.isFinite(limit) || limit == null) {
|
|
476
|
+
return MAX_CANDIDATES;
|
|
477
|
+
}
|
|
478
|
+
return Math.max(1, Math.min(MAX_CANDIDATES, Math.trunc(limit)));
|
|
479
|
+
}
|
|
480
|
+
export function limitResolutionCandidates(candidates, requestedLimit) {
|
|
481
|
+
const candidateCount = candidates.length;
|
|
482
|
+
const limit = clampCandidateLimit(requestedLimit);
|
|
483
|
+
const limitedCandidates = candidateCount > limit ? candidates.slice(0, limit) : candidates;
|
|
484
|
+
return {
|
|
485
|
+
candidates: limitedCandidates,
|
|
486
|
+
candidateCount,
|
|
487
|
+
...(limitedCandidates.length < candidateCount ? { candidatesTruncated: true } : {})
|
|
488
|
+
};
|
|
489
|
+
}
|
|
490
|
+
export function clampRowLimit(limit) {
|
|
491
|
+
if (!Number.isFinite(limit) || limit == null) {
|
|
492
|
+
return undefined;
|
|
493
|
+
}
|
|
494
|
+
return Math.max(1, Math.min(5000, Math.trunc(limit)));
|
|
495
|
+
}
|
|
496
|
+
//# sourceMappingURL=lookup.js.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { SourceMapping } from "../../types.js";
|
|
2
|
+
import type { DirectionIndex, MappingSymbolRecord, PairKey, PairRecord } from "../internal-types.js";
|
|
3
|
+
export declare function pairKey(sourceMapping: SourceMapping, targetMapping: SourceMapping): PairKey;
|
|
4
|
+
export declare function parsePairKey(key: PairKey): {
|
|
5
|
+
sourceMapping: SourceMapping;
|
|
6
|
+
targetMapping: SourceMapping;
|
|
7
|
+
};
|
|
8
|
+
export declare function buildAdjacency(pairs: Map<PairKey, PairRecord>): Map<SourceMapping, SourceMapping[]>;
|
|
9
|
+
export declare function buildTargetRecordIndex(pairs: Map<PairKey, PairRecord>): Map<SourceMapping, MappingSymbolRecord[]>;
|
|
10
|
+
export declare function ensurePairIndex(indexes: Map<PairKey, DirectionIndex>, from: SourceMapping, to: SourceMapping): DirectionIndex;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { buildSymbolKey, createDirectionIndex } from "./symbol-records.js";
|
|
2
|
+
export function pairKey(sourceMapping, targetMapping) {
|
|
3
|
+
return `${sourceMapping}->${targetMapping}`;
|
|
4
|
+
}
|
|
5
|
+
export function parsePairKey(key) {
|
|
6
|
+
const separator = key.indexOf("->");
|
|
7
|
+
const source = separator >= 0 ? key.slice(0, separator) : key;
|
|
8
|
+
const target = separator >= 0 ? key.slice(separator + 2) : "";
|
|
9
|
+
return {
|
|
10
|
+
sourceMapping: source,
|
|
11
|
+
targetMapping: target
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
export function buildAdjacency(pairs) {
|
|
15
|
+
const adjacency = new Map();
|
|
16
|
+
for (const key of pairs.keys()) {
|
|
17
|
+
const { sourceMapping, targetMapping } = parsePairKey(key);
|
|
18
|
+
let neighbors = adjacency.get(sourceMapping);
|
|
19
|
+
if (!neighbors) {
|
|
20
|
+
neighbors = new Set();
|
|
21
|
+
adjacency.set(sourceMapping, neighbors);
|
|
22
|
+
}
|
|
23
|
+
neighbors.add(targetMapping);
|
|
24
|
+
}
|
|
25
|
+
return new Map([...adjacency.entries()].map(([mapping, neighbors]) => [mapping, [...neighbors]]));
|
|
26
|
+
}
|
|
27
|
+
export function buildTargetRecordIndex(pairs) {
|
|
28
|
+
const recordsByTarget = new Map();
|
|
29
|
+
for (const [key, pair] of pairs.entries()) {
|
|
30
|
+
const { targetMapping } = parsePairKey(key);
|
|
31
|
+
let bucket = recordsByTarget.get(targetMapping);
|
|
32
|
+
if (!bucket) {
|
|
33
|
+
bucket = new Map();
|
|
34
|
+
recordsByTarget.set(targetMapping, bucket);
|
|
35
|
+
}
|
|
36
|
+
for (const record of pair.index.records.values()) {
|
|
37
|
+
bucket.set(buildSymbolKey(record), record);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return new Map([...recordsByTarget.entries()].map(([mapping, records]) => [mapping, [...records.values()]]));
|
|
41
|
+
}
|
|
42
|
+
export function ensurePairIndex(indexes, from, to) {
|
|
43
|
+
const key = pairKey(from, to);
|
|
44
|
+
const existing = indexes.get(key);
|
|
45
|
+
if (existing) {
|
|
46
|
+
return existing;
|
|
47
|
+
}
|
|
48
|
+
const created = createDirectionIndex();
|
|
49
|
+
indexes.set(key, created);
|
|
50
|
+
return created;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=normalize.js.map
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { DirectionIndex, PairKey } from "../internal-types.js";
|
|
2
|
+
/** Map of proguard primitive type names to JVM type characters. */
|
|
3
|
+
export declare const PROGUARD_PRIMITIVES: Record<string, string>;
|
|
4
|
+
/**
|
|
5
|
+
* Convert a single proguard type (e.g. "int", "net.minecraft.Foo", "int[][]")
|
|
6
|
+
* to JVM notation (e.g. "I", "Lnet/minecraft/Foo;", "[[I").
|
|
7
|
+
* `classLookup` maps mojang class names → obfuscated class names (for the obfuscated descriptor).
|
|
8
|
+
* Pass `undefined` to skip class name translation (for mojang descriptors).
|
|
9
|
+
*/
|
|
10
|
+
export declare function proguardTypeToJvm(type: string, classLookup: Map<string, string> | undefined): string;
|
|
11
|
+
/**
|
|
12
|
+
* Parse a proguard method signature (after stripLineInfo) into a JVM descriptor.
|
|
13
|
+
* Input format: "returnType methodName(paramType1,paramType2,...)"
|
|
14
|
+
* Returns `{ name, descriptor }` or `undefined` if parsing fails.
|
|
15
|
+
*/
|
|
16
|
+
export declare function parseProguardMethod(value: string, classLookup: Map<string, string> | undefined): {
|
|
17
|
+
name: string;
|
|
18
|
+
descriptor: string;
|
|
19
|
+
} | undefined;
|
|
20
|
+
export declare function parseClientMappings(text: string): Map<PairKey, DirectionIndex>;
|