@adhisang/minecraft-modding-mcp 2.0.0 → 3.0.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 +62 -0
- package/README.md +139 -30
- package/dist/cache-registry.d.ts +95 -0
- package/dist/cache-registry.js +541 -0
- package/dist/cli.js +31 -4
- package/dist/compat-stdio-transport.d.ts +2 -7
- package/dist/compat-stdio-transport.js +12 -154
- package/dist/entry-tools/analyze-mod-service.d.ts +207 -0
- package/dist/entry-tools/analyze-mod-service.js +253 -0
- package/dist/entry-tools/analyze-symbol-service.d.ts +209 -0
- package/dist/entry-tools/analyze-symbol-service.js +304 -0
- package/dist/entry-tools/compare-minecraft-service.d.ts +210 -0
- package/dist/entry-tools/compare-minecraft-service.js +397 -0
- package/dist/entry-tools/entry-tool-schema.d.ts +6 -0
- package/dist/entry-tools/entry-tool-schema.js +10 -0
- package/dist/entry-tools/inspect-minecraft-service.d.ts +1953 -0
- package/dist/entry-tools/inspect-minecraft-service.js +876 -0
- package/dist/entry-tools/manage-cache-service.d.ts +130 -0
- package/dist/entry-tools/manage-cache-service.js +229 -0
- package/dist/entry-tools/request-normalizers.d.ts +10 -0
- package/dist/entry-tools/request-normalizers.js +36 -0
- package/dist/entry-tools/response-contract.d.ts +44 -0
- package/dist/entry-tools/response-contract.js +96 -0
- package/dist/entry-tools/validate-project-service.d.ts +543 -0
- package/dist/entry-tools/validate-project-service.js +381 -0
- package/dist/index.js +495 -42
- package/dist/json-rpc-framing.d.ts +22 -0
- package/dist/json-rpc-framing.js +168 -0
- package/dist/mapping-pipeline-service.js +9 -1
- package/dist/mapping-service.d.ts +9 -0
- package/dist/mapping-service.js +183 -60
- package/dist/minecraft-explorer-service.d.ts +0 -1
- package/dist/minecraft-explorer-service.js +119 -23
- package/dist/mixin-validator.d.ts +24 -2
- package/dist/mixin-validator.js +223 -98
- package/dist/mod-decompile-service.d.ts +5 -0
- package/dist/mod-decompile-service.js +40 -5
- package/dist/mod-remap-service.js +142 -30
- package/dist/path-resolver.js +41 -4
- package/dist/registry-service.d.ts +10 -1
- package/dist/registry-service.js +154 -22
- package/dist/search-hit-accumulator.js +23 -2
- package/dist/source-jar-reader.js +16 -2
- package/dist/source-resolver.js +6 -7
- package/dist/source-service.d.ts +42 -4
- package/dist/source-service.js +781 -127
- package/dist/stdio-supervisor.d.ts +46 -0
- package/dist/stdio-supervisor.js +349 -0
- package/dist/storage/files-repo.d.ts +3 -9
- package/dist/storage/files-repo.js +66 -43
- package/dist/symbols/symbol-extractor.js +6 -4
- package/dist/tool-execution-gate.d.ts +15 -0
- package/dist/tool-execution-gate.js +58 -0
- package/dist/version-diff-service.js +10 -5
- package/dist/version-service.js +7 -2
- package/dist/workspace-mapping-service.js +12 -0
- package/package.json +1 -1
package/dist/mapping-service.js
CHANGED
|
@@ -37,13 +37,21 @@ function addToSetMap(map, key, value) {
|
|
|
37
37
|
map.set(normalizedKey, existing);
|
|
38
38
|
}
|
|
39
39
|
function normalizedVariants(symbol) {
|
|
40
|
-
const variants =
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
40
|
+
const variants = [symbol];
|
|
41
|
+
let dotted;
|
|
42
|
+
if (symbol.includes("/")) {
|
|
43
|
+
dotted = symbol.replace(/\//g, ".");
|
|
44
|
+
if (dotted !== symbol) {
|
|
45
|
+
variants.push(dotted);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
if (symbol.includes(".")) {
|
|
49
|
+
const slashed = symbol.replace(/\./g, "/");
|
|
50
|
+
if (slashed !== symbol && slashed !== dotted) {
|
|
51
|
+
variants.push(slashed);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return variants;
|
|
47
55
|
}
|
|
48
56
|
function simpleName(symbol) {
|
|
49
57
|
const trimmed = symbol.trim();
|
|
@@ -230,12 +238,42 @@ function pairKey(sourceMapping, targetMapping) {
|
|
|
230
238
|
return `${sourceMapping}->${targetMapping}`;
|
|
231
239
|
}
|
|
232
240
|
function parsePairKey(key) {
|
|
233
|
-
const
|
|
241
|
+
const separator = key.indexOf("->");
|
|
242
|
+
const source = separator >= 0 ? key.slice(0, separator) : key;
|
|
243
|
+
const target = separator >= 0 ? key.slice(separator + 2) : "";
|
|
234
244
|
return {
|
|
235
245
|
sourceMapping: source,
|
|
236
246
|
targetMapping: target
|
|
237
247
|
};
|
|
238
248
|
}
|
|
249
|
+
function buildAdjacency(pairs) {
|
|
250
|
+
const adjacency = new Map();
|
|
251
|
+
for (const key of pairs.keys()) {
|
|
252
|
+
const { sourceMapping, targetMapping } = parsePairKey(key);
|
|
253
|
+
let neighbors = adjacency.get(sourceMapping);
|
|
254
|
+
if (!neighbors) {
|
|
255
|
+
neighbors = new Set();
|
|
256
|
+
adjacency.set(sourceMapping, neighbors);
|
|
257
|
+
}
|
|
258
|
+
neighbors.add(targetMapping);
|
|
259
|
+
}
|
|
260
|
+
return new Map([...adjacency.entries()].map(([mapping, neighbors]) => [mapping, [...neighbors]]));
|
|
261
|
+
}
|
|
262
|
+
function buildTargetRecordIndex(pairs) {
|
|
263
|
+
const recordsByTarget = new Map();
|
|
264
|
+
for (const [key, pair] of pairs.entries()) {
|
|
265
|
+
const { targetMapping } = parsePairKey(key);
|
|
266
|
+
let bucket = recordsByTarget.get(targetMapping);
|
|
267
|
+
if (!bucket) {
|
|
268
|
+
bucket = new Map();
|
|
269
|
+
recordsByTarget.set(targetMapping, bucket);
|
|
270
|
+
}
|
|
271
|
+
for (const record of pair.index.records.values()) {
|
|
272
|
+
bucket.set(buildSymbolKey(record), record);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
return new Map([...recordsByTarget.entries()].map(([mapping, records]) => [mapping, [...records.values()]]));
|
|
276
|
+
}
|
|
239
277
|
function ensurePairIndex(indexes, from, to) {
|
|
240
278
|
const key = pairKey(from, to);
|
|
241
279
|
const existing = indexes.get(key);
|
|
@@ -552,38 +590,48 @@ function mappingSourceOrder(priority) {
|
|
|
552
590
|
}
|
|
553
591
|
return ["loom-cache", "maven"];
|
|
554
592
|
}
|
|
555
|
-
function namespacePath(
|
|
593
|
+
function namespacePath(graph, sourceMapping, targetMapping) {
|
|
556
594
|
if (sourceMapping === targetMapping) {
|
|
557
595
|
return [sourceMapping];
|
|
558
596
|
}
|
|
597
|
+
const key = pairKey(sourceMapping, targetMapping);
|
|
598
|
+
if (graph.pathCache.has(key)) {
|
|
599
|
+
return graph.pathCache.get(key);
|
|
600
|
+
}
|
|
601
|
+
const { adjacency } = graph;
|
|
559
602
|
const queue = [sourceMapping];
|
|
603
|
+
let queueIndex = 0;
|
|
560
604
|
const parent = new Map([[sourceMapping, undefined]]);
|
|
561
|
-
while (queue.length
|
|
562
|
-
const current = queue
|
|
605
|
+
while (queueIndex < queue.length) {
|
|
606
|
+
const current = queue[queueIndex];
|
|
607
|
+
queueIndex += 1;
|
|
563
608
|
if (current === targetMapping) {
|
|
564
609
|
break;
|
|
565
610
|
}
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
if (parent.has(
|
|
611
|
+
const neighbors = adjacency.get(current);
|
|
612
|
+
if (!neighbors) {
|
|
613
|
+
continue;
|
|
614
|
+
}
|
|
615
|
+
for (const neighbor of neighbors) {
|
|
616
|
+
if (parent.has(neighbor)) {
|
|
572
617
|
continue;
|
|
573
618
|
}
|
|
574
|
-
parent.set(
|
|
575
|
-
queue.push(
|
|
619
|
+
parent.set(neighbor, current);
|
|
620
|
+
queue.push(neighbor);
|
|
576
621
|
}
|
|
577
622
|
}
|
|
578
623
|
if (!parent.has(targetMapping)) {
|
|
624
|
+
graph.pathCache.set(key, undefined);
|
|
579
625
|
return undefined;
|
|
580
626
|
}
|
|
581
|
-
const
|
|
627
|
+
const reversedPath = [];
|
|
582
628
|
let cursor = targetMapping;
|
|
583
629
|
while (cursor) {
|
|
584
|
-
|
|
630
|
+
reversedPath.push(cursor);
|
|
585
631
|
cursor = parent.get(cursor);
|
|
586
632
|
}
|
|
633
|
+
const path = reversedPath.reverse();
|
|
634
|
+
graph.pathCache.set(key, path);
|
|
587
635
|
return path;
|
|
588
636
|
}
|
|
589
637
|
function pathUsesSource(pairs, path, source) {
|
|
@@ -765,17 +813,7 @@ function applyDisambiguationHints(candidates, disambiguation) {
|
|
|
765
813
|
return filtered;
|
|
766
814
|
}
|
|
767
815
|
function collectTargetRecords(graph, targetMapping) {
|
|
768
|
-
|
|
769
|
-
for (const [key, pair] of graph.pairs.entries()) {
|
|
770
|
-
const parsed = parsePairKey(key);
|
|
771
|
-
if (parsed.targetMapping !== targetMapping) {
|
|
772
|
-
continue;
|
|
773
|
-
}
|
|
774
|
-
for (const record of pair.index.records.values()) {
|
|
775
|
-
merged.set(buildSymbolKey(record), record);
|
|
776
|
-
}
|
|
777
|
-
}
|
|
778
|
-
return [...merged.values()];
|
|
816
|
+
return [...(graph.recordsByTarget.get(targetMapping) ?? [])];
|
|
779
817
|
}
|
|
780
818
|
function normalizeIncludedKinds(inputKinds) {
|
|
781
819
|
const normalized = new Set();
|
|
@@ -823,6 +861,28 @@ function inferAmbiguityReasons(candidates, usedMojangClientMappings) {
|
|
|
823
861
|
}
|
|
824
862
|
return reasons;
|
|
825
863
|
}
|
|
864
|
+
function clampCandidateLimit(limit) {
|
|
865
|
+
if (!Number.isFinite(limit) || limit == null) {
|
|
866
|
+
return MAX_CANDIDATES;
|
|
867
|
+
}
|
|
868
|
+
return Math.max(1, Math.min(MAX_CANDIDATES, Math.trunc(limit)));
|
|
869
|
+
}
|
|
870
|
+
function limitResolutionCandidates(candidates, requestedLimit) {
|
|
871
|
+
const candidateCount = candidates.length;
|
|
872
|
+
const limit = clampCandidateLimit(requestedLimit);
|
|
873
|
+
const limitedCandidates = candidateCount > limit ? candidates.slice(0, limit) : candidates;
|
|
874
|
+
return {
|
|
875
|
+
candidates: limitedCandidates,
|
|
876
|
+
candidateCount,
|
|
877
|
+
...(limitedCandidates.length < candidateCount ? { candidatesTruncated: true } : {})
|
|
878
|
+
};
|
|
879
|
+
}
|
|
880
|
+
function clampRowLimit(limit) {
|
|
881
|
+
if (!Number.isFinite(limit) || limit == null) {
|
|
882
|
+
return undefined;
|
|
883
|
+
}
|
|
884
|
+
return Math.max(1, Math.min(5000, Math.trunc(limit)));
|
|
885
|
+
}
|
|
826
886
|
export class MappingService {
|
|
827
887
|
config;
|
|
828
888
|
versionService;
|
|
@@ -845,7 +905,7 @@ export class MappingService {
|
|
|
845
905
|
}
|
|
846
906
|
});
|
|
847
907
|
}
|
|
848
|
-
const { record: queryRecord, querySymbol } = normalizeQuerySymbol(input);
|
|
908
|
+
const { record: queryRecord, querySymbol } = normalizeQuerySymbol(input, input.signatureMode);
|
|
849
909
|
const sourceMapping = input.sourceMapping;
|
|
850
910
|
const targetMapping = input.targetMapping;
|
|
851
911
|
if (!SUPPORTED_MAPPINGS.has(sourceMapping) || !SUPPORTED_MAPPINGS.has(targetMapping)) {
|
|
@@ -872,18 +932,21 @@ export class MappingService {
|
|
|
872
932
|
matchKind: "exact",
|
|
873
933
|
confidence: 1
|
|
874
934
|
});
|
|
935
|
+
const limited = limitResolutionCandidates([identity], input.maxCandidates);
|
|
875
936
|
return {
|
|
876
937
|
querySymbol,
|
|
877
938
|
mappingContext,
|
|
878
939
|
resolved: true,
|
|
879
940
|
status: "resolved",
|
|
880
941
|
resolvedSymbol: querySymbol,
|
|
881
|
-
candidates:
|
|
942
|
+
candidates: limited.candidates,
|
|
943
|
+
candidateCount: limited.candidateCount,
|
|
944
|
+
candidatesTruncated: limited.candidatesTruncated,
|
|
882
945
|
warnings: []
|
|
883
946
|
};
|
|
884
947
|
}
|
|
885
948
|
const graph = await this.loadGraph(version, priority);
|
|
886
|
-
const path = namespacePath(graph
|
|
949
|
+
const path = namespacePath(graph, sourceMapping, targetMapping);
|
|
887
950
|
if (!path) {
|
|
888
951
|
return {
|
|
889
952
|
querySymbol,
|
|
@@ -891,6 +954,7 @@ export class MappingService {
|
|
|
891
954
|
resolved: false,
|
|
892
955
|
status: "mapping_unavailable",
|
|
893
956
|
candidates: [],
|
|
957
|
+
candidateCount: 0,
|
|
894
958
|
warnings: [
|
|
895
959
|
`No mapping path is available for ${sourceMapping} -> ${targetMapping} on version "${version}".`
|
|
896
960
|
]
|
|
@@ -903,6 +967,7 @@ export class MappingService {
|
|
|
903
967
|
warnings.push(`Disambiguation hints narrowed candidates from ${rawCandidates.length} to ${disambiguatedCandidates.length}.`);
|
|
904
968
|
}
|
|
905
969
|
const candidates = disambiguatedCandidates.map(toResolutionCandidate);
|
|
970
|
+
const limitedCandidates = limitResolutionCandidates(candidates, input.maxCandidates);
|
|
906
971
|
if (queryRecord.kind === "method" &&
|
|
907
972
|
queryRecord.descriptor &&
|
|
908
973
|
pathUsesSource(graph.pairs, path, "mojang-client-mappings") &&
|
|
@@ -925,7 +990,9 @@ export class MappingService {
|
|
|
925
990
|
resolved: status === "resolved",
|
|
926
991
|
status,
|
|
927
992
|
resolvedSymbol: status === "resolved" ? candidates[0] : undefined,
|
|
928
|
-
candidates,
|
|
993
|
+
candidates: limitedCandidates.candidates,
|
|
994
|
+
candidateCount: limitedCandidates.candidateCount,
|
|
995
|
+
candidatesTruncated: limitedCandidates.candidatesTruncated,
|
|
929
996
|
warnings,
|
|
930
997
|
provenance: this.provenanceForPath(graph, path),
|
|
931
998
|
ambiguityReasons
|
|
@@ -963,7 +1030,7 @@ export class MappingService {
|
|
|
963
1030
|
};
|
|
964
1031
|
}
|
|
965
1032
|
const graph = await this.loadGraph(version, priority);
|
|
966
|
-
const path = namespacePath(graph
|
|
1033
|
+
const path = namespacePath(graph, sourceMapping, targetMapping);
|
|
967
1034
|
if (!path) {
|
|
968
1035
|
throw createError({
|
|
969
1036
|
code: ERROR_CODES.MAPPING_UNAVAILABLE,
|
|
@@ -1033,18 +1100,21 @@ export class MappingService {
|
|
|
1033
1100
|
matchKind: "exact",
|
|
1034
1101
|
confidence: 1
|
|
1035
1102
|
});
|
|
1103
|
+
const limited = limitResolutionCandidates([resolvedCandidate], input.maxCandidates);
|
|
1036
1104
|
return {
|
|
1037
1105
|
querySymbol,
|
|
1038
1106
|
mappingContext,
|
|
1039
1107
|
resolved: true,
|
|
1040
1108
|
status: "resolved",
|
|
1041
1109
|
resolvedSymbol: resolvedCandidate,
|
|
1042
|
-
candidates:
|
|
1110
|
+
candidates: limited.candidates,
|
|
1111
|
+
candidateCount: limited.candidateCount,
|
|
1112
|
+
candidatesTruncated: limited.candidatesTruncated,
|
|
1043
1113
|
warnings: []
|
|
1044
1114
|
};
|
|
1045
1115
|
}
|
|
1046
1116
|
const graph = await this.loadGraph(version, priority);
|
|
1047
|
-
const path = namespacePath(graph
|
|
1117
|
+
const path = namespacePath(graph, sourceMapping, targetMapping);
|
|
1048
1118
|
if (!path) {
|
|
1049
1119
|
return {
|
|
1050
1120
|
querySymbol,
|
|
@@ -1052,6 +1122,7 @@ export class MappingService {
|
|
|
1052
1122
|
resolved: false,
|
|
1053
1123
|
status: "mapping_unavailable",
|
|
1054
1124
|
candidates: [],
|
|
1125
|
+
candidateCount: 0,
|
|
1055
1126
|
warnings: [
|
|
1056
1127
|
`No mapping path is available for ${sourceMapping} -> ${targetMapping} on version "${version}".`
|
|
1057
1128
|
]
|
|
@@ -1062,6 +1133,7 @@ export class MappingService {
|
|
|
1062
1133
|
.mapCandidatesAlongPath(graph, path, queryRecord)
|
|
1063
1134
|
.filter((candidate) => candidate.kind === "method");
|
|
1064
1135
|
const candidates = rawCandidates.map(toResolutionCandidate);
|
|
1136
|
+
const limitedCandidates = limitResolutionCandidates(candidates, input.maxCandidates);
|
|
1065
1137
|
const strictCandidates = rawCandidates.filter((candidate) => candidate.descriptor === descriptor);
|
|
1066
1138
|
if (strictCandidates.length === 1) {
|
|
1067
1139
|
const resolved = toResolutionCandidate(strictCandidates[0]);
|
|
@@ -1071,7 +1143,9 @@ export class MappingService {
|
|
|
1071
1143
|
resolved: true,
|
|
1072
1144
|
status: "resolved",
|
|
1073
1145
|
resolvedSymbol: resolved,
|
|
1074
|
-
candidates,
|
|
1146
|
+
candidates: limitedCandidates.candidates,
|
|
1147
|
+
candidateCount: limitedCandidates.candidateCount,
|
|
1148
|
+
candidatesTruncated: limitedCandidates.candidatesTruncated,
|
|
1075
1149
|
warnings,
|
|
1076
1150
|
provenance: this.provenanceForPath(graph, path)
|
|
1077
1151
|
};
|
|
@@ -1083,7 +1157,9 @@ export class MappingService {
|
|
|
1083
1157
|
mappingContext,
|
|
1084
1158
|
resolved: false,
|
|
1085
1159
|
status: "ambiguous",
|
|
1086
|
-
candidates,
|
|
1160
|
+
candidates: limitedCandidates.candidates,
|
|
1161
|
+
candidateCount: limitedCandidates.candidateCount,
|
|
1162
|
+
candidatesTruncated: limitedCandidates.candidatesTruncated,
|
|
1087
1163
|
warnings,
|
|
1088
1164
|
provenance: this.provenanceForPath(graph, path)
|
|
1089
1165
|
};
|
|
@@ -1095,7 +1171,9 @@ export class MappingService {
|
|
|
1095
1171
|
mappingContext,
|
|
1096
1172
|
resolved: false,
|
|
1097
1173
|
status: "mapping_unavailable",
|
|
1098
|
-
candidates,
|
|
1174
|
+
candidates: limitedCandidates.candidates,
|
|
1175
|
+
candidateCount: limitedCandidates.candidateCount,
|
|
1176
|
+
candidatesTruncated: limitedCandidates.candidatesTruncated,
|
|
1099
1177
|
warnings,
|
|
1100
1178
|
provenance: this.provenanceForPath(graph, path)
|
|
1101
1179
|
};
|
|
@@ -1105,7 +1183,9 @@ export class MappingService {
|
|
|
1105
1183
|
mappingContext,
|
|
1106
1184
|
resolved: false,
|
|
1107
1185
|
status: "not_found",
|
|
1108
|
-
candidates,
|
|
1186
|
+
candidates: limitedCandidates.candidates,
|
|
1187
|
+
candidateCount: limitedCandidates.candidateCount,
|
|
1188
|
+
candidatesTruncated: limitedCandidates.candidatesTruncated,
|
|
1109
1189
|
warnings,
|
|
1110
1190
|
provenance: this.provenanceForPath(graph, path)
|
|
1111
1191
|
};
|
|
@@ -1137,6 +1217,19 @@ export class MappingService {
|
|
|
1137
1217
|
const graph = await this.loadGraph(version, priority);
|
|
1138
1218
|
const warnings = [...graph.warnings];
|
|
1139
1219
|
const includeKinds = normalizeIncludedKinds(input.includeKinds);
|
|
1220
|
+
const pathCache = new Map();
|
|
1221
|
+
const resolvePath = (sourceMapping, targetMapping) => {
|
|
1222
|
+
if (sourceMapping === targetMapping) {
|
|
1223
|
+
return [sourceMapping];
|
|
1224
|
+
}
|
|
1225
|
+
const key = pairKey(sourceMapping, targetMapping);
|
|
1226
|
+
if (pathCache.has(key)) {
|
|
1227
|
+
return pathCache.get(key);
|
|
1228
|
+
}
|
|
1229
|
+
const path = namespacePath(graph, sourceMapping, targetMapping);
|
|
1230
|
+
pathCache.set(key, path);
|
|
1231
|
+
return path;
|
|
1232
|
+
};
|
|
1140
1233
|
const classByMapping = {
|
|
1141
1234
|
[classNameMapping]: createClassSymbolRecord(className)
|
|
1142
1235
|
};
|
|
@@ -1144,7 +1237,7 @@ export class MappingService {
|
|
|
1144
1237
|
if (mapping === classNameMapping) {
|
|
1145
1238
|
continue;
|
|
1146
1239
|
}
|
|
1147
|
-
const mapped = this.mapRecordBetweenMappings(graph, classNameMapping, mapping, classByMapping[classNameMapping]);
|
|
1240
|
+
const mapped = this.mapRecordBetweenMappings(graph, classNameMapping, mapping, classByMapping[classNameMapping], resolvePath(classNameMapping, mapping));
|
|
1148
1241
|
if (mapped.length > 1) {
|
|
1149
1242
|
const competing = mapped.slice(0, 5).map((c) => c.symbol);
|
|
1150
1243
|
warnings.push(`Class identity mapping to ${mapping} is ambiguous for "${className}": competing=[${competing.join(", ")}].`);
|
|
@@ -1167,6 +1260,7 @@ export class MappingService {
|
|
|
1167
1260
|
yarn: classByMapping.yarn?.symbol
|
|
1168
1261
|
},
|
|
1169
1262
|
rows: [],
|
|
1263
|
+
rowCount: 0,
|
|
1170
1264
|
warnings
|
|
1171
1265
|
};
|
|
1172
1266
|
}
|
|
@@ -1220,7 +1314,7 @@ export class MappingService {
|
|
|
1220
1314
|
resolved = baseRecord;
|
|
1221
1315
|
}
|
|
1222
1316
|
else {
|
|
1223
|
-
const mapped = this.mapRecordBetweenMappings(graph, baseMapping, mapping, baseRecord);
|
|
1317
|
+
const mapped = this.mapRecordBetweenMappings(graph, baseMapping, mapping, baseRecord, resolvePath(baseMapping, mapping));
|
|
1224
1318
|
let filtered = mapped;
|
|
1225
1319
|
if (baseRecord.kind !== "class" && classIdentity) {
|
|
1226
1320
|
filtered = filtered.filter((candidate) => candidate.owner === classIdentity.symbol);
|
|
@@ -1255,6 +1349,9 @@ export class MappingService {
|
|
|
1255
1349
|
ambiguousRowCount += 1;
|
|
1256
1350
|
}
|
|
1257
1351
|
}
|
|
1352
|
+
const rowCount = rows.length;
|
|
1353
|
+
const rowLimit = clampRowLimit(input.maxRows);
|
|
1354
|
+
const limitedRows = rowLimit != null && rowCount > rowLimit ? rows.slice(0, rowLimit) : rows;
|
|
1258
1355
|
return {
|
|
1259
1356
|
version,
|
|
1260
1357
|
className,
|
|
@@ -1265,7 +1362,9 @@ export class MappingService {
|
|
|
1265
1362
|
intermediary: classByMapping.intermediary?.symbol,
|
|
1266
1363
|
yarn: classByMapping.yarn?.symbol
|
|
1267
1364
|
},
|
|
1268
|
-
rows,
|
|
1365
|
+
rows: limitedRows,
|
|
1366
|
+
rowCount,
|
|
1367
|
+
rowsTruncated: limitedRows.length < rowCount ? true : undefined,
|
|
1269
1368
|
warnings,
|
|
1270
1369
|
ambiguousRowCount: ambiguousRowCount > 0 ? ambiguousRowCount : undefined
|
|
1271
1370
|
};
|
|
@@ -1346,18 +1445,22 @@ export class MappingService {
|
|
|
1346
1445
|
resolved: false,
|
|
1347
1446
|
status: "mapping_unavailable",
|
|
1348
1447
|
candidates: [],
|
|
1448
|
+
candidateCount: 0,
|
|
1349
1449
|
warnings
|
|
1350
1450
|
};
|
|
1351
1451
|
}
|
|
1352
1452
|
const buildOutput = (querySymbol, matched, status) => {
|
|
1353
1453
|
const candidates = matched.map((record) => toResolutionCandidate(toLookupCandidate(record)));
|
|
1454
|
+
const limitedCandidates = limitResolutionCandidates(candidates, input.maxCandidates);
|
|
1354
1455
|
return {
|
|
1355
1456
|
querySymbol,
|
|
1356
1457
|
mappingContext,
|
|
1357
1458
|
resolved: status === "resolved",
|
|
1358
1459
|
status,
|
|
1359
1460
|
resolvedSymbol: status === "resolved" ? candidates[0] : undefined,
|
|
1360
|
-
candidates,
|
|
1461
|
+
candidates: limitedCandidates.candidates,
|
|
1462
|
+
candidateCount: limitedCandidates.candidateCount,
|
|
1463
|
+
candidatesTruncated: limitedCandidates.candidatesTruncated,
|
|
1361
1464
|
warnings
|
|
1362
1465
|
};
|
|
1363
1466
|
};
|
|
@@ -1408,11 +1511,11 @@ export class MappingService {
|
|
|
1408
1511
|
}
|
|
1409
1512
|
return buildOutput(querySymbol, [], "not_found");
|
|
1410
1513
|
}
|
|
1411
|
-
mapRecordBetweenMappings(graph, sourceMapping, targetMapping, record) {
|
|
1514
|
+
mapRecordBetweenMappings(graph, sourceMapping, targetMapping, record, resolvedPath) {
|
|
1412
1515
|
if (sourceMapping === targetMapping) {
|
|
1413
1516
|
return [record];
|
|
1414
1517
|
}
|
|
1415
|
-
const path = namespacePath(graph
|
|
1518
|
+
const path = resolvedPath ?? namespacePath(graph, sourceMapping, targetMapping);
|
|
1416
1519
|
if (!path) {
|
|
1417
1520
|
return [];
|
|
1418
1521
|
}
|
|
@@ -1568,7 +1671,7 @@ export class MappingService {
|
|
|
1568
1671
|
memberRemapAvailable = true;
|
|
1569
1672
|
}
|
|
1570
1673
|
else {
|
|
1571
|
-
const path = namespacePath(graph
|
|
1674
|
+
const path = namespacePath(graph, input.requestedMapping, "obfuscated");
|
|
1572
1675
|
memberRemapAvailable = path != null && path.length > 1;
|
|
1573
1676
|
if (!memberRemapAvailable) {
|
|
1574
1677
|
degradations.push(`No mapping path from ${input.requestedMapping} to obfuscated; member remap will fail.`);
|
|
@@ -1611,6 +1714,9 @@ export class MappingService {
|
|
|
1611
1714
|
version,
|
|
1612
1715
|
priority,
|
|
1613
1716
|
pairs: new Map(),
|
|
1717
|
+
adjacency: new Map(),
|
|
1718
|
+
pathCache: new Map(),
|
|
1719
|
+
recordsByTarget: new Map(),
|
|
1614
1720
|
warnings: [
|
|
1615
1721
|
`Version ${version} is unobfuscated; mapping graph is empty because the runtime already uses deobfuscated names.`
|
|
1616
1722
|
]
|
|
@@ -1620,27 +1726,38 @@ export class MappingService {
|
|
|
1620
1726
|
version,
|
|
1621
1727
|
priority,
|
|
1622
1728
|
pairs: new Map(),
|
|
1729
|
+
adjacency: new Map(),
|
|
1730
|
+
pathCache: new Map(),
|
|
1731
|
+
recordsByTarget: new Map(),
|
|
1623
1732
|
warnings: []
|
|
1624
1733
|
};
|
|
1625
1734
|
const mojangLoad = await this.loadMojangPairs(version);
|
|
1626
1735
|
graph.warnings.push(...mojangLoad.warnings);
|
|
1627
1736
|
this.mergePairs(graph.pairs, mojangLoad.pairs, "mojang-client-mappings", mojangLoad.mappingArtifact);
|
|
1628
1737
|
let tinyLoaded = false;
|
|
1738
|
+
const deferredTinyWarnings = [];
|
|
1629
1739
|
for (const source of mappingSourceOrder(priority)) {
|
|
1630
1740
|
const tinyLoad = source === "loom-cache"
|
|
1631
1741
|
? await this.loadTinyPairsFromLoom(version)
|
|
1632
1742
|
: await this.loadTinyPairsFromMaven(version);
|
|
1633
|
-
graph.warnings.push(...tinyLoad.warnings);
|
|
1634
1743
|
if (tinyLoad.pairs.size === 0) {
|
|
1744
|
+
deferredTinyWarnings.push(...tinyLoad.warnings);
|
|
1635
1745
|
continue;
|
|
1636
1746
|
}
|
|
1637
1747
|
tinyLoaded = true;
|
|
1638
1748
|
this.mergePairs(graph.pairs, tinyLoad.pairs, source, tinyLoad.mappingArtifact);
|
|
1749
|
+
graph.warnings.push(...tinyLoad.warnings);
|
|
1750
|
+
if (deferredTinyWarnings.length > 0) {
|
|
1751
|
+
graph.warnings.push(`Used ${source === "maven" ? "Maven" : "Loom cache"} tiny mappings for "${version}" after an earlier source lookup returned no data.`);
|
|
1752
|
+
}
|
|
1639
1753
|
break;
|
|
1640
1754
|
}
|
|
1641
1755
|
if (!tinyLoaded) {
|
|
1756
|
+
graph.warnings.push(...deferredTinyWarnings);
|
|
1642
1757
|
graph.warnings.push("No intermediary/yarn tiny mappings were found for this version.");
|
|
1643
1758
|
}
|
|
1759
|
+
graph.adjacency = buildAdjacency(graph.pairs);
|
|
1760
|
+
graph.recordsByTarget = buildTargetRecordIndex(graph.pairs);
|
|
1644
1761
|
return graph;
|
|
1645
1762
|
}
|
|
1646
1763
|
mergePairs(target, source, pairSource, mappingArtifact) {
|
|
@@ -1763,31 +1880,37 @@ export class MappingService {
|
|
|
1763
1880
|
async loadTinyPairsFromMaven(version) {
|
|
1764
1881
|
const warnings = [];
|
|
1765
1882
|
const merged = new Map();
|
|
1766
|
-
const attemptedArtifacts = [];
|
|
1767
1883
|
const repos = this.config.sourceRepos;
|
|
1768
1884
|
const intermediaryUrls = [];
|
|
1769
1885
|
const yarnUrls = [];
|
|
1770
|
-
|
|
1771
|
-
|
|
1886
|
+
const repoBases = repos.map((repo) => repo.replace(/\/+$/, ""));
|
|
1887
|
+
const yarnCoordinatesByRepo = await Promise.all(repoBases.map(async (base) => ({
|
|
1888
|
+
base,
|
|
1889
|
+
yarnCoordinates: await this.fetchYarnCoordinates(base, version)
|
|
1890
|
+
})));
|
|
1891
|
+
for (const { base, yarnCoordinates } of yarnCoordinatesByRepo) {
|
|
1772
1892
|
intermediaryUrls.push(`${base}/net/fabricmc/intermediary/${version}/intermediary-${version}-v2.jar`, `${base}/net/fabricmc/intermediary/${version}/intermediary-${version}.jar`);
|
|
1773
|
-
const yarnCoordinates = await this.fetchYarnCoordinates(base, version);
|
|
1774
1893
|
for (const coordinate of yarnCoordinates) {
|
|
1775
1894
|
yarnUrls.push(`${base}/net/fabricmc/yarn/${coordinate}/yarn-${coordinate}-v2.jar`, `${base}/net/fabricmc/yarn/${coordinate}/yarn-${coordinate}.jar`);
|
|
1776
1895
|
}
|
|
1777
1896
|
}
|
|
1778
1897
|
const allUrls = [...intermediaryUrls, ...yarnUrls];
|
|
1779
|
-
|
|
1780
|
-
attemptedArtifacts.push(url);
|
|
1898
|
+
const parsedResults = await Promise.allSettled(allUrls.map(async (url) => {
|
|
1781
1899
|
const downloaded = await downloadToCache(url, defaultDownloadPath(this.config.cacheDir, url), {
|
|
1782
1900
|
fetchFn: this.fetchFn,
|
|
1783
1901
|
retries: this.config.fetchRetries,
|
|
1784
1902
|
timeoutMs: this.config.fetchTimeoutMs
|
|
1785
1903
|
});
|
|
1786
1904
|
if (!downloaded.ok || !downloaded.path) {
|
|
1905
|
+
return undefined;
|
|
1906
|
+
}
|
|
1907
|
+
return this.parseTinyFromJar(downloaded.path);
|
|
1908
|
+
}));
|
|
1909
|
+
for (const result of parsedResults) {
|
|
1910
|
+
if (result.status !== "fulfilled" || !result.value) {
|
|
1787
1911
|
continue;
|
|
1788
1912
|
}
|
|
1789
|
-
const
|
|
1790
|
-
for (const [key, index] of parsed.entries()) {
|
|
1913
|
+
for (const [key, index] of result.value.entries()) {
|
|
1791
1914
|
const existing = merged.get(key);
|
|
1792
1915
|
if (!existing) {
|
|
1793
1916
|
merged.set(key, index);
|
|
@@ -1803,7 +1926,7 @@ export class MappingService {
|
|
|
1803
1926
|
return {
|
|
1804
1927
|
pairs: merged,
|
|
1805
1928
|
warnings,
|
|
1806
|
-
mappingArtifact:
|
|
1929
|
+
mappingArtifact: allUrls[0] ?? "maven:none"
|
|
1807
1930
|
};
|
|
1808
1931
|
}
|
|
1809
1932
|
async parseTinyFromJar(jarPath) {
|