@adhisang/minecraft-modding-mcp 5.0.0 → 6.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 +55 -0
- package/dist/access-widener-parser.d.ts +1 -0
- package/dist/access-widener-parser.js +6 -3
- package/dist/cache-registry.js +35 -31
- package/dist/config.js +1 -1
- package/dist/decompiler/vineflower.js +8 -2
- package/dist/entry-tools/analyze-mod-service.js +2 -1
- package/dist/entry-tools/analyze-symbol-service.js +18 -9
- package/dist/entry-tools/batch-class-members-service.d.ts +2 -0
- package/dist/entry-tools/batch-class-members-service.js +1 -0
- package/dist/entry-tools/compare-minecraft-service.js +1 -1
- package/dist/entry-tools/inspect-minecraft/handlers/class-members.js +2 -1
- package/dist/entry-tools/inspect-minecraft/handlers/file.js +26 -1
- package/dist/entry-tools/inspect-minecraft/handlers/versions.js +2 -1
- package/dist/entry-tools/inspect-minecraft/internal.js +2 -0
- package/dist/entry-tools/response-contract.d.ts +2 -0
- package/dist/entry-tools/response-contract.js +2 -2
- package/dist/entry-tools/validate-project/cases/project-summary.js +30 -12
- package/dist/entry-tools/validate-project-service.d.ts +4 -4
- package/dist/entry-tools/verify-mixin-target-service.js +7 -7
- package/dist/index.js +21 -16
- package/dist/java-process.js +1 -1
- package/dist/json-rpc-framing.d.ts +4 -0
- package/dist/json-rpc-framing.js +23 -1
- package/dist/mapping/internal-types.d.ts +17 -0
- package/dist/mapping/loaders/tiny-maven.js +46 -20
- package/dist/mapping/lookup.d.ts +12 -1
- package/dist/mapping/lookup.js +53 -1
- package/dist/mapping-service.js +37 -22
- package/dist/minecraft-explorer-service.js +2 -1
- package/dist/mixin/annotation-validators.js +21 -3
- package/dist/mixin/parsed-validator.js +1 -0
- package/dist/mixin-parser.js +71 -3
- package/dist/mod-decompile-service.d.ts +2 -0
- package/dist/mod-decompile-service.js +19 -2
- package/dist/mod-remap-service.js +6 -5
- package/dist/mojang-tiny-mapping-service.js +5 -2
- package/dist/nbt/java-nbt-codec.js +40 -16
- package/dist/nbt/json-patch.js +51 -12
- package/dist/nbt/typed-json.d.ts +1 -0
- package/dist/nbt/typed-json.js +12 -2
- package/dist/nbt/types.d.ts +2 -2
- package/dist/path-converter.js +10 -3
- package/dist/registry-service.d.ts +2 -0
- package/dist/registry-service.js +16 -1
- package/dist/repo-downloader.js +4 -3
- package/dist/source/artifact-resolver.js +1 -1
- package/dist/source/class-source/members-builder.d.ts +26 -0
- package/dist/source/class-source/members-builder.js +31 -4
- package/dist/source/class-source/snippet-builder.js +6 -0
- package/dist/source/class-source-helpers.d.ts +4 -4
- package/dist/source/class-source-helpers.js +12 -11
- package/dist/source/class-source.d.ts +19 -0
- package/dist/source/class-source.js +87 -26
- package/dist/source/file-access.js +3 -2
- package/dist/source/indexer.js +24 -7
- package/dist/source/lifecycle/mapping-helpers.js +28 -3
- package/dist/source/lifecycle/runtime-check.js +20 -6
- package/dist/source/member-pattern.d.ts +16 -0
- package/dist/source/member-pattern.js +27 -0
- package/dist/source/search.js +23 -8
- package/dist/source/validate-mixin/pipeline/resolve.js +23 -3
- package/dist/source/workspace-target.js +2 -1
- package/dist/source-resolver.js +2 -2
- package/dist/source-service.d.ts +8 -4
- package/dist/source-service.js +9 -1
- package/dist/stdio-supervisor.d.ts +2 -2
- package/dist/stdio-supervisor.js +29 -9
- package/dist/storage/db.js +24 -1
- package/dist/storage/files-repo.d.ts +3 -0
- package/dist/storage/files-repo.js +43 -37
- package/dist/storage/symbols-repo.d.ts +9 -0
- package/dist/storage/symbols-repo.js +47 -19
- package/dist/symbols/symbol-extractor.js +1 -1
- package/dist/tool-guidance.d.ts +2 -1
- package/dist/tool-guidance.js +27 -2
- package/dist/tool-schemas.d.ts +15 -4
- package/dist/tool-schemas.js +102 -97
- package/dist/warning-details.d.ts +12 -0
- package/dist/warning-details.js +17 -0
- package/dist/workspace-mapping-service.js +9 -0
- package/docs/tool-reference.md +23 -0
- package/package.json +1 -1
|
@@ -454,7 +454,7 @@ export declare const validateProjectSchema: z.ZodEffects<z.ZodObject<{
|
|
|
454
454
|
reportMode: "full" | "summary-first" | "compact";
|
|
455
455
|
treatInfoAsWarning: boolean;
|
|
456
456
|
includeIssues: boolean;
|
|
457
|
-
task: "project-summary" | "mixin" | "access-
|
|
457
|
+
task: "project-summary" | "mixin" | "access-transformer" | "access-widener";
|
|
458
458
|
subject: {
|
|
459
459
|
kind: "workspace";
|
|
460
460
|
projectPath: string;
|
|
@@ -510,7 +510,7 @@ export declare const validateProjectSchema: z.ZodEffects<z.ZodObject<{
|
|
|
510
510
|
include?: string[] | undefined;
|
|
511
511
|
atNamespace?: "obfuscated" | "mojang" | "srg" | undefined;
|
|
512
512
|
}, {
|
|
513
|
-
task: "project-summary" | "mixin" | "access-
|
|
513
|
+
task: "project-summary" | "mixin" | "access-transformer" | "access-widener";
|
|
514
514
|
subject: {
|
|
515
515
|
kind: "workspace";
|
|
516
516
|
projectPath: string;
|
|
@@ -580,7 +580,7 @@ export declare const validateProjectSchema: z.ZodEffects<z.ZodObject<{
|
|
|
580
580
|
reportMode: "full" | "summary-first" | "compact";
|
|
581
581
|
treatInfoAsWarning: boolean;
|
|
582
582
|
includeIssues: boolean;
|
|
583
|
-
task: "project-summary" | "mixin" | "access-
|
|
583
|
+
task: "project-summary" | "mixin" | "access-transformer" | "access-widener";
|
|
584
584
|
subject: {
|
|
585
585
|
kind: "workspace";
|
|
586
586
|
projectPath: string;
|
|
@@ -636,7 +636,7 @@ export declare const validateProjectSchema: z.ZodEffects<z.ZodObject<{
|
|
|
636
636
|
include?: string[] | undefined;
|
|
637
637
|
atNamespace?: "obfuscated" | "mojang" | "srg" | undefined;
|
|
638
638
|
}, {
|
|
639
|
-
task: "project-summary" | "mixin" | "access-
|
|
639
|
+
task: "project-summary" | "mixin" | "access-transformer" | "access-widener";
|
|
640
640
|
subject: {
|
|
641
641
|
kind: "workspace";
|
|
642
642
|
projectPath: string;
|
|
@@ -5,7 +5,7 @@ import { suggestSimilar } from "../mixin-validator.js";
|
|
|
5
5
|
export const VERIFY_MIXIN_TARGET_OFF = process.env.VERIFY_MIXIN_TARGET_OFF === "1";
|
|
6
6
|
const ACCESSOR_NAME_RE = /^(get|set|is)([A-Z]\w*)$/;
|
|
7
7
|
const INVOKER_NAME_RE = /^(invoke|call)([A-Z]\w*)$/;
|
|
8
|
-
function decodeAccessFlags(flags) {
|
|
8
|
+
function decodeAccessFlags(flags, kind) {
|
|
9
9
|
const labels = [];
|
|
10
10
|
if (flags == null) {
|
|
11
11
|
return labels;
|
|
@@ -23,9 +23,9 @@ function decodeAccessFlags(flags) {
|
|
|
23
23
|
if ((flags & 0x0020) !== 0)
|
|
24
24
|
labels.push("synchronized");
|
|
25
25
|
if ((flags & 0x0040) !== 0)
|
|
26
|
-
labels.push("volatile");
|
|
26
|
+
labels.push(kind === "method" ? "bridge" : "volatile");
|
|
27
27
|
if ((flags & 0x0080) !== 0)
|
|
28
|
-
labels.push("transient");
|
|
28
|
+
labels.push(kind === "method" ? "varargs" : "transient");
|
|
29
29
|
if ((flags & 0x0100) !== 0)
|
|
30
30
|
labels.push("native");
|
|
31
31
|
if ((flags & 0x0400) !== 0)
|
|
@@ -137,11 +137,11 @@ function deriveVisibility(accessFlags) {
|
|
|
137
137
|
return "private";
|
|
138
138
|
return "package-private";
|
|
139
139
|
}
|
|
140
|
-
function buildMatch(member) {
|
|
140
|
+
function buildMatch(member, kind) {
|
|
141
141
|
return {
|
|
142
142
|
name: member.name,
|
|
143
143
|
descriptor: member.jvmDescriptor,
|
|
144
|
-
accessFlags: decodeAccessFlags(member.accessFlags),
|
|
144
|
+
accessFlags: decodeAccessFlags(member.accessFlags, kind),
|
|
145
145
|
javaSignature: member.javaSignature,
|
|
146
146
|
...(member.sourceLine ? { sourceLine: member.sourceLine } : {})
|
|
147
147
|
};
|
|
@@ -267,7 +267,7 @@ export class VerifyMixinTargetService {
|
|
|
267
267
|
if (member.descriptor) {
|
|
268
268
|
const descriptorHits = exactNameHits.filter((m) => m.jvmDescriptor === member.descriptor);
|
|
269
269
|
if (descriptorHits.length > 0) {
|
|
270
|
-
matches = descriptorHits.map(buildMatch);
|
|
270
|
+
matches = descriptorHits.map((m) => buildMatch(m, member.kind));
|
|
271
271
|
}
|
|
272
272
|
else {
|
|
273
273
|
matches = [];
|
|
@@ -279,7 +279,7 @@ export class VerifyMixinTargetService {
|
|
|
279
279
|
}
|
|
280
280
|
}
|
|
281
281
|
else {
|
|
282
|
-
matches = exactNameHits.map(buildMatch);
|
|
282
|
+
matches = exactNameHits.map((m) => buildMatch(m, member.kind));
|
|
283
283
|
}
|
|
284
284
|
if (matches.length === 0 && candidates.length === 0) {
|
|
285
285
|
const suggestions = suggestSimilar(memberName, allMemberNames);
|
package/dist/index.js
CHANGED
|
@@ -15,7 +15,7 @@ import { remapModJar } from "./mod-remap-service.js";
|
|
|
15
15
|
import { registerResources } from "./resources.js";
|
|
16
16
|
import { SourceService } from "./source-service.js";
|
|
17
17
|
import { ToolExecutionGate } from "./tool-execution-gate.js";
|
|
18
|
-
import { classifyWarnings } from "./warning-details.js";
|
|
18
|
+
import { capWarningDetailsForSummary, classifyWarnings } from "./warning-details.js";
|
|
19
19
|
import { WorkspaceMappingService } from "./workspace-mapping-service.js";
|
|
20
20
|
import { InspectMinecraftService, inspectMinecraftSchema, inspectMinecraftShape } from "./entry-tools/inspect-minecraft-service.js";
|
|
21
21
|
import { AnalyzeSymbolService, analyzeSymbolSchema, analyzeSymbolShape } from "./entry-tools/analyze-symbol-service.js";
|
|
@@ -90,7 +90,7 @@ server.validateToolInput = async (_tool, args) => args;
|
|
|
90
90
|
// server.tool() but appends a note steering agents to the entry tools first.
|
|
91
91
|
// Entry tools, batch tools, and the NBT/runtime utilities (which have no entry
|
|
92
92
|
// equivalent) keep their plain descriptions via server.tool().
|
|
93
|
-
const EXPERT_TOOL_NOTE = " Expert
|
|
93
|
+
const EXPERT_TOOL_NOTE = " Expert tool: prefer the entry tools (inspect-minecraft, analyze-symbol, compare-minecraft, analyze-mod, validate-project) first.";
|
|
94
94
|
const expertTool = ((name, description, ...rest) => server.tool(name, description + EXPERT_TOOL_NOTE, ...rest));
|
|
95
95
|
const config = loadConfig();
|
|
96
96
|
const nbtLimits = {
|
|
@@ -385,18 +385,23 @@ async function runTool(tool, rawInput, schema, action) {
|
|
|
385
385
|
if (DETAIL_ENABLED_TOOL_NAMES.has(tool)) {
|
|
386
386
|
projectedResult = projectByDetail(tool, projectedResult, effectiveDetail, shapeInput.include);
|
|
387
387
|
}
|
|
388
|
-
// Entry, expert, and batch tools
|
|
388
|
+
// Entry, expert, and batch tools report the applied detail/include shape in meta.
|
|
389
|
+
// detailApplied is omitted when it matches the tool's default to keep responses lean.
|
|
390
|
+
const defaultDetail = ENTRY_TOOL_NAMES.has(tool)
|
|
391
|
+
? "summary"
|
|
392
|
+
: DEFAULT_DETAIL_BY_TOOL[tool] ?? "summary";
|
|
389
393
|
const entryMeta = ENTRY_TOOL_NAMES.has(tool) ||
|
|
390
394
|
DETAIL_ENABLED_TOOL_NAMES.has(tool) ||
|
|
391
395
|
BATCH_DETAIL_TOOL_NAMES.has(tool)
|
|
392
396
|
? buildEntryToolMeta({
|
|
393
397
|
detail: effectiveDetail,
|
|
398
|
+
defaultDetail,
|
|
394
399
|
include: shapeInput.include.size > 0 ? [...shapeInput.include] : undefined
|
|
395
400
|
})
|
|
396
401
|
: undefined;
|
|
397
402
|
const durationMs = Date.now() - startedAt;
|
|
398
403
|
sourceService.recordToolCall(tool, durationMs);
|
|
399
|
-
const warningDetails = classifyWarnings(warnings);
|
|
404
|
+
const warningDetails = capWarningDetailsForSummary(classifyWarnings(warnings), effectiveDetail === "summary");
|
|
400
405
|
return objectResult({
|
|
401
406
|
result: projectedResult,
|
|
402
407
|
meta: {
|
|
@@ -405,7 +410,7 @@ async function runTool(tool, rawInput, schema, action) {
|
|
|
405
410
|
requestId,
|
|
406
411
|
tool,
|
|
407
412
|
durationMs,
|
|
408
|
-
warnings,
|
|
413
|
+
...(warnings.length > 0 ? { warnings } : {}),
|
|
409
414
|
...(warningDetails.length > 0 ? { warningDetails } : {})
|
|
410
415
|
}
|
|
411
416
|
});
|
|
@@ -450,8 +455,7 @@ async function runTool(tool, rawInput, schema, action) {
|
|
|
450
455
|
const errorMeta = {
|
|
451
456
|
requestId,
|
|
452
457
|
tool,
|
|
453
|
-
durationMs: errorDurationMs
|
|
454
|
-
warnings: []
|
|
458
|
+
durationMs: errorDurationMs
|
|
455
459
|
};
|
|
456
460
|
applyErrorMetaExtensions(errorMeta, caughtError);
|
|
457
461
|
return objectResult({
|
|
@@ -467,7 +471,7 @@ expertTool("list-versions", "List available Minecraft versions from Mojang manif
|
|
|
467
471
|
registerToolSchema("list-versions", listVersionsSchema);
|
|
468
472
|
server.tool("inspect-minecraft", "Top-level workflow tool for version discovery, artifact resolution, class inspection, source search, file reads, and file listings.", inspectMinecraftShape, { readOnlyHint: true }, async (args) => runTool("inspect-minecraft", args, inspectMinecraftSchema, async (input) => inspectMinecraftService.execute(input)));
|
|
469
473
|
registerToolSchema("inspect-minecraft", inspectMinecraftSchema);
|
|
470
|
-
server.tool("analyze-symbol", "Top-level workflow tool for symbol existence, mapping, lifecycle
|
|
474
|
+
server.tool("analyze-symbol", "Top-level workflow tool for symbol existence, mapping, lifecycle, workspace analysis, and API overview. subject.kind='symbol' auto-detects class/field/method from the selector.", analyzeSymbolShape, { readOnlyHint: true }, async (args) => runTool("analyze-symbol", args, analyzeSymbolSchema, async (input) => analyzeSymbolService.execute(input)));
|
|
471
475
|
registerToolSchema("analyze-symbol", analyzeSymbolSchema);
|
|
472
476
|
server.tool("compare-minecraft", "Top-level workflow tool for version comparisons, class diffs, registry diffs, and migration overviews.", compareMinecraftShape, { readOnlyHint: true }, async (args) => runTool("compare-minecraft", args, compareMinecraftSchema, async (input) => compareMinecraftService.execute(input)));
|
|
473
477
|
registerToolSchema("compare-minecraft", compareMinecraftSchema);
|
|
@@ -497,16 +501,16 @@ if (!VERIFY_MIXIN_TARGET_OFF) {
|
|
|
497
501
|
registerToolSchema("verify-mixin-target", verifyMixinTargetSchema);
|
|
498
502
|
}
|
|
499
503
|
if (!BATCH_TOOLS_OFF) {
|
|
500
|
-
server.tool("batch-class-source", "Batch
|
|
504
|
+
server.tool("batch-class-source", "Batch get-class-source for many classes sharing one resolved artifact; returns per-entry status plus aggregate summary. Not read-only: per-entry outputFile writes to disk.", batchClassSourceShape, { readOnlyHint: false }, async (args) => runTool("batch-class-source", args, batchClassSourceSchema, async (input) => batchClassSourceService.execute(input)));
|
|
501
505
|
registerToolSchema("batch-class-source", batchClassSourceSchema);
|
|
502
|
-
server.tool("batch-class-members", "Batch
|
|
506
|
+
server.tool("batch-class-members", "Batch get-class-members for many classes sharing one resolved artifact; returns per-entry status plus aggregate summary.", batchClassMembersShape, { readOnlyHint: true }, async (args) => runTool("batch-class-members", args, batchClassMembersSchema, async (input) => batchClassMembersService.execute(input)));
|
|
503
507
|
registerToolSchema("batch-class-members", batchClassMembersSchema);
|
|
504
|
-
server.tool("batch-symbol-exists", "Batch
|
|
508
|
+
server.tool("batch-symbol-exists", "Batch check-symbol-exists for many symbols against one shared Minecraft version (target.kind=version or workspace only).", batchSymbolExistsShape, { readOnlyHint: true }, async (args) => runTool("batch-symbol-exists", args, batchSymbolExistsSchema, async (input) => batchSymbolExistsService.execute(input)));
|
|
505
509
|
registerToolSchema("batch-symbol-exists", batchSymbolExistsSchema);
|
|
506
|
-
server.tool("batch-mappings", "Batch mapping
|
|
510
|
+
server.tool("batch-mappings", "Batch find-mapping: resolve many symbols across mapping namespaces with one shared Minecraft version.", batchMappingsShape, { readOnlyHint: true }, async (args) => runTool("batch-mappings", args, batchMappingsSchema, async (input) => batchMappingsService.execute(input)));
|
|
507
511
|
registerToolSchema("batch-mappings", batchMappingsSchema);
|
|
508
512
|
}
|
|
509
|
-
expertTool("resolve-artifact", "Resolve source artifact
|
|
513
|
+
expertTool("resolve-artifact", "Resolve a source artifact and return artifact metadata. For target.kind=jar, only <basename>-sources.jar is auto-adopted.", resolveArtifactShape, { readOnlyHint: true }, async (args) => runTool("resolve-artifact", args, resolveArtifactSchema, async (input) => sourceService.resolveArtifact({
|
|
510
514
|
target: input.target,
|
|
511
515
|
mapping: input.mapping,
|
|
512
516
|
sourcePriority: input.sourcePriority,
|
|
@@ -532,7 +536,7 @@ expertTool("find-class", "Resolve a simple or qualified class name to fully-qual
|
|
|
532
536
|
limit: input.limit
|
|
533
537
|
})));
|
|
534
538
|
registerToolSchema("find-class", findClassSchema);
|
|
535
|
-
expertTool("get-class-source", "Get Java source for a class
|
|
539
|
+
expertTool("get-class-source", "Get Java source for a class. Default mode=metadata returns a symbol outline only; pass mode=snippet or mode=full to read source text. Not read-only: outputFile writes to disk.", getClassSourceShape, { readOnlyHint: false }, async (args) => runTool("get-class-source", args, getClassSourceSchema, async (input) => {
|
|
536
540
|
const normalizedTarget = normalizeSourceLookupTarget(input.target);
|
|
537
541
|
return sourceService.getClassSource({
|
|
538
542
|
className: input.className,
|
|
@@ -555,7 +559,7 @@ expertTool("get-class-source", "Get Java source for a class by target ({ kind: '
|
|
|
555
559
|
});
|
|
556
560
|
}));
|
|
557
561
|
registerToolSchema("get-class-source", getClassSourceSchema);
|
|
558
|
-
expertTool("get-class-members", "Get fields/methods/constructors for one class from binary bytecode
|
|
562
|
+
expertTool("get-class-members", "Get fields/methods/constructors for one class from binary bytecode.", getClassMembersShape, { readOnlyHint: true }, async (args) => runTool("get-class-members", args, getClassMembersSchema, async (input) => {
|
|
559
563
|
const normalizedTarget = normalizeSourceLookupTarget(input.target);
|
|
560
564
|
return sourceService.getClassMembers({
|
|
561
565
|
className: input.className,
|
|
@@ -569,6 +573,7 @@ expertTool("get-class-members", "Get fields/methods/constructors for one class f
|
|
|
569
573
|
includeInherited: input.includeInherited,
|
|
570
574
|
memberPattern: input.memberPattern,
|
|
571
575
|
maxMembers: input.maxMembers,
|
|
576
|
+
projection: input.projection,
|
|
572
577
|
cursor: input.cursor,
|
|
573
578
|
projectPath: input.projectPath,
|
|
574
579
|
gradleUserHome: input.gradleUserHome,
|
|
@@ -657,7 +662,7 @@ expertTool("find-mapping", "Find symbol mapping candidates between namespaces us
|
|
|
657
662
|
maxCandidates: input.maxCandidates
|
|
658
663
|
})));
|
|
659
664
|
registerToolSchema("find-mapping", findMappingSchema);
|
|
660
|
-
expertTool("resolve-method-mapping-exact", "Strict
|
|
665
|
+
expertTool("resolve-method-mapping-exact", "Strict variant of find-mapping(kind=method, signatureMode=exact): requires a COMPLETE descriptor projection and returns mapping_unavailable when any descriptor class reference cannot be projected. Prefer find-mapping unless you need that guarantee.", resolveMethodMappingExactShape, { readOnlyHint: true }, async (args) => runTool("resolve-method-mapping-exact", args, resolveMethodMappingExactSchema, async (input) => sourceService.resolveMethodMappingExact({
|
|
661
666
|
version: input.version,
|
|
662
667
|
name: input.name,
|
|
663
668
|
owner: input.owner,
|
package/dist/java-process.js
CHANGED
|
@@ -9,6 +9,9 @@ export declare function encodeJsonRpcMessage(message: JSONRPCMessage, mode: Conc
|
|
|
9
9
|
export declare class JsonRpcFrameReader {
|
|
10
10
|
private mode;
|
|
11
11
|
private buffer;
|
|
12
|
+
private pendingChunks;
|
|
13
|
+
private pendingBytes;
|
|
14
|
+
private awaitedFrameEnd;
|
|
12
15
|
get currentMode(): FramingMode;
|
|
13
16
|
reset(): void;
|
|
14
17
|
clear(): void;
|
|
@@ -16,6 +19,7 @@ export declare class JsonRpcFrameReader {
|
|
|
16
19
|
onFrame: (frame: ParsedJsonRpcFrame) => void;
|
|
17
20
|
onError: (error: Error) => void;
|
|
18
21
|
}): void;
|
|
22
|
+
private canCompleteFrame;
|
|
19
23
|
private detectMode;
|
|
20
24
|
private readLineDelimitedMessage;
|
|
21
25
|
private readContentLengthMessage;
|
package/dist/json-rpc-framing.js
CHANGED
|
@@ -25,21 +25,35 @@ export function encodeJsonRpcMessage(message, mode) {
|
|
|
25
25
|
export class JsonRpcFrameReader {
|
|
26
26
|
mode = "unknown";
|
|
27
27
|
buffer = Buffer.alloc(0);
|
|
28
|
+
pendingChunks = [];
|
|
29
|
+
pendingBytes = 0;
|
|
30
|
+
awaitedFrameEnd = -1;
|
|
28
31
|
get currentMode() {
|
|
29
32
|
return this.mode;
|
|
30
33
|
}
|
|
31
34
|
reset() {
|
|
32
35
|
this.mode = "unknown";
|
|
36
|
+
this.awaitedFrameEnd = -1;
|
|
33
37
|
}
|
|
34
38
|
clear() {
|
|
35
39
|
this.mode = "unknown";
|
|
36
40
|
this.buffer = Buffer.alloc(0);
|
|
41
|
+
this.pendingChunks = [];
|
|
42
|
+
this.pendingBytes = 0;
|
|
43
|
+
this.awaitedFrameEnd = -1;
|
|
37
44
|
}
|
|
38
45
|
processChunk(chunk, handlers) {
|
|
39
46
|
if (chunk.length === 0) {
|
|
40
47
|
return;
|
|
41
48
|
}
|
|
42
|
-
this.
|
|
49
|
+
this.pendingChunks.push(chunk);
|
|
50
|
+
this.pendingBytes += chunk.length;
|
|
51
|
+
if (!this.canCompleteFrame(chunk)) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
this.buffer = Buffer.concat([this.buffer, ...this.pendingChunks]);
|
|
55
|
+
this.pendingChunks = [];
|
|
56
|
+
this.pendingBytes = 0;
|
|
43
57
|
while (true) {
|
|
44
58
|
try {
|
|
45
59
|
if (this.mode === "unknown") {
|
|
@@ -71,6 +85,12 @@ export class JsonRpcFrameReader {
|
|
|
71
85
|
}
|
|
72
86
|
}
|
|
73
87
|
}
|
|
88
|
+
canCompleteFrame(chunk) {
|
|
89
|
+
if (this.mode === "content-length" && this.awaitedFrameEnd >= 0) {
|
|
90
|
+
return this.buffer.length + this.pendingBytes >= this.awaitedFrameEnd;
|
|
91
|
+
}
|
|
92
|
+
return chunk.includes(0x0a);
|
|
93
|
+
}
|
|
74
94
|
detectMode() {
|
|
75
95
|
while (this.buffer.length > 0) {
|
|
76
96
|
if (this.buffer[0] === 0x0a) {
|
|
@@ -124,6 +144,7 @@ export class JsonRpcFrameReader {
|
|
|
124
144
|
}
|
|
125
145
|
}
|
|
126
146
|
readContentLengthMessage() {
|
|
147
|
+
this.awaitedFrameEnd = -1;
|
|
127
148
|
const headerBoundary = findHeaderBoundary(this.buffer);
|
|
128
149
|
if (!headerBoundary) {
|
|
129
150
|
return undefined;
|
|
@@ -158,6 +179,7 @@ export class JsonRpcFrameReader {
|
|
|
158
179
|
const messageStart = headerBoundary.index + headerBoundary.delimiterBytes;
|
|
159
180
|
const frameEnd = messageStart + contentLength;
|
|
160
181
|
if (this.buffer.length < frameEnd) {
|
|
182
|
+
this.awaitedFrameEnd = frameEnd;
|
|
161
183
|
return undefined;
|
|
162
184
|
}
|
|
163
185
|
const body = this.buffer.subarray(messageStart, frameEnd).toString("utf8");
|
|
@@ -20,6 +20,18 @@ export type DirectionIndex = {
|
|
|
20
20
|
simple: Map<string, Set<string>>;
|
|
21
21
|
records: Map<string, MappingSymbolRecord>;
|
|
22
22
|
};
|
|
23
|
+
/**
|
|
24
|
+
* O(1) exact-lookup index over a single target namespace's records, used by
|
|
25
|
+
* existence checks. `byKey` is keyed by `kind|owner|name` (owner empty for
|
|
26
|
+
* classes, which key on their FQCN symbol); `classBySimpleName` resolves the
|
|
27
|
+
* auto-class short-name path. Values are arrays so callers can still tell a
|
|
28
|
+
* unique match (resolved) from multiple (ambiguous).
|
|
29
|
+
*/
|
|
30
|
+
export type ExactRecordIndex = {
|
|
31
|
+
byKey: Map<string, MappingSymbolRecord[]>;
|
|
32
|
+
classBySimpleName: Map<string, MappingSymbolRecord[]>;
|
|
33
|
+
membersByOwner: Map<string, MappingSymbolRecord[]>;
|
|
34
|
+
};
|
|
23
35
|
export type MappingLookupSource = "loom-cache" | "maven" | "mojang-client-mappings";
|
|
24
36
|
export type PairRecord = {
|
|
25
37
|
index: DirectionIndex;
|
|
@@ -50,6 +62,11 @@ export type LoadedGraph = {
|
|
|
50
62
|
adjacency: Map<import("../types.js").SourceMapping, import("../types.js").SourceMapping[]>;
|
|
51
63
|
pathCache: Map<PairKey, import("../types.js").SourceMapping[] | undefined>;
|
|
52
64
|
recordsByTarget: Map<import("../types.js").SourceMapping, MappingSymbolRecord[]>;
|
|
65
|
+
/**
|
|
66
|
+
* Graph-scoped, lazily-built exact-lookup indexes keyed by target namespace.
|
|
67
|
+
* Populated on first existence check for a namespace; dies with graph eviction.
|
|
68
|
+
*/
|
|
69
|
+
exactRecordIndex: Map<import("../types.js").SourceMapping, ExactRecordIndex>;
|
|
53
70
|
/**
|
|
54
71
|
* Graph-scoped cache of class-to-class descriptor projections, keyed by
|
|
55
72
|
* `path.join(">") + NUL + internalName`. Value is the projected internal name,
|
|
@@ -53,36 +53,62 @@ export async function loadTinyPairsFromMaven(deps, version) {
|
|
|
53
53
|
const warnings = [];
|
|
54
54
|
const merged = new Map();
|
|
55
55
|
const repos = deps.config.sourceRepos;
|
|
56
|
-
const
|
|
57
|
-
const yarnUrls = [];
|
|
56
|
+
const attemptedUrls = [];
|
|
58
57
|
const repoBases = repos.map((repo) => repo.replace(/\/+$/, ""));
|
|
59
58
|
const yarnCoordinatesByRepo = await Promise.all(repoBases.map(async (base) => ({
|
|
60
59
|
base,
|
|
61
60
|
yarnCoordinates: await fetchYarnCoordinates(deps.fetchFn, base, version)
|
|
62
61
|
})));
|
|
62
|
+
const tryUrls = async (urls) => {
|
|
63
|
+
for (const url of urls) {
|
|
64
|
+
attemptedUrls.push(url);
|
|
65
|
+
try {
|
|
66
|
+
const downloaded = await downloadToCache(url, defaultDownloadPath(deps.config.cacheDir, url), {
|
|
67
|
+
fetchFn: deps.fetchFn,
|
|
68
|
+
retries: deps.config.fetchRetries,
|
|
69
|
+
timeoutMs: deps.config.fetchTimeoutMs
|
|
70
|
+
});
|
|
71
|
+
if (!downloaded.ok || !downloaded.path) {
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
const parsed = await parseTinyFromJar(downloaded.path);
|
|
75
|
+
if (parsed.size > 0) {
|
|
76
|
+
return parsed;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
// try the next candidate URL
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return undefined;
|
|
84
|
+
};
|
|
85
|
+
let intermediaryParsed;
|
|
86
|
+
let yarnParsed;
|
|
63
87
|
for (const { base, yarnCoordinates } of yarnCoordinatesByRepo) {
|
|
64
|
-
|
|
88
|
+
if (!intermediaryParsed) {
|
|
89
|
+
intermediaryParsed = await tryUrls([
|
|
90
|
+
`${base}/net/fabricmc/intermediary/${version}/intermediary-${version}-v2.jar`,
|
|
91
|
+
`${base}/net/fabricmc/intermediary/${version}/intermediary-${version}.jar`
|
|
92
|
+
]);
|
|
93
|
+
}
|
|
65
94
|
for (const coordinate of yarnCoordinates) {
|
|
66
|
-
|
|
95
|
+
if (yarnParsed) {
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
yarnParsed = await tryUrls([
|
|
99
|
+
`${base}/net/fabricmc/yarn/${coordinate}/yarn-${coordinate}-v2.jar`,
|
|
100
|
+
`${base}/net/fabricmc/yarn/${coordinate}/yarn-${coordinate}.jar`
|
|
101
|
+
]);
|
|
67
102
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
const parsedResults = await Promise.allSettled(allUrls.map(async (url) => {
|
|
71
|
-
const downloaded = await downloadToCache(url, defaultDownloadPath(deps.config.cacheDir, url), {
|
|
72
|
-
fetchFn: deps.fetchFn,
|
|
73
|
-
retries: deps.config.fetchRetries,
|
|
74
|
-
timeoutMs: deps.config.fetchTimeoutMs
|
|
75
|
-
});
|
|
76
|
-
if (!downloaded.ok || !downloaded.path) {
|
|
77
|
-
return undefined;
|
|
103
|
+
if (intermediaryParsed && yarnParsed) {
|
|
104
|
+
break;
|
|
78
105
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
if (result.status !== "fulfilled" || !result.value) {
|
|
106
|
+
}
|
|
107
|
+
for (const parsed of [intermediaryParsed, yarnParsed]) {
|
|
108
|
+
if (!parsed) {
|
|
83
109
|
continue;
|
|
84
110
|
}
|
|
85
|
-
for (const [key, index] of
|
|
111
|
+
for (const [key, index] of parsed.entries()) {
|
|
86
112
|
const existing = merged.get(key);
|
|
87
113
|
if (!existing) {
|
|
88
114
|
merged.set(key, index);
|
|
@@ -98,7 +124,7 @@ export async function loadTinyPairsFromMaven(deps, version) {
|
|
|
98
124
|
return {
|
|
99
125
|
pairs: merged,
|
|
100
126
|
warnings,
|
|
101
|
-
mappingArtifact:
|
|
127
|
+
mappingArtifact: attemptedUrls[0] ?? "maven:none"
|
|
102
128
|
};
|
|
103
129
|
}
|
|
104
130
|
//# sourceMappingURL=tiny-maven.js.map
|
package/dist/mapping/lookup.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { MappingSourcePriority, SourceMapping } from "../types.js";
|
|
2
|
-
import type { CandidateAccumulator, DirectionIndex, LoadedGraph, MappingLookupSource, MappingSymbolRecord, MatchRankKey, PairKey, PairRecord } from "./internal-types.js";
|
|
2
|
+
import type { CandidateAccumulator, DirectionIndex, ExactRecordIndex, LoadedGraph, MappingLookupSource, MappingSymbolRecord, MatchRankKey, PairKey, PairRecord } from "./internal-types.js";
|
|
3
3
|
import { MAX_CANDIDATES } from "./internal-types.js";
|
|
4
4
|
import type { ClassApiMatrixKind, DescriptorProjection, MappingLookupCandidate, ResolutionCandidate, SymbolQueryInput, SymbolReference } from "./types.js";
|
|
5
5
|
export type { DescriptorProjection };
|
|
@@ -41,6 +41,17 @@ export declare function applyDisambiguationHints(candidates: MappingLookupCandid
|
|
|
41
41
|
export declare function projectLookupCandidateDescriptor(candidate: MappingLookupCandidate, sourceDescriptor: string, targetDescriptor: string | undefined): MappingLookupCandidate;
|
|
42
42
|
export declare function effectiveLoomSearchProjectPath(projectPath: string | undefined): string | undefined;
|
|
43
43
|
export declare function collectTargetRecords(graph: LoadedGraph, targetMapping: SourceMapping): MappingSymbolRecord[];
|
|
44
|
+
/**
|
|
45
|
+
* Lazily build (and memoize on the graph) an O(1) exact-lookup index for a
|
|
46
|
+
* target namespace. Classes key on their FQCN symbol (owner left empty) and are
|
|
47
|
+
* additionally indexed by simple name for the auto-class short-name path;
|
|
48
|
+
* fields/methods key on `kind|owner|name`.
|
|
49
|
+
*/
|
|
50
|
+
export declare function collectExactRecordIndex(graph: LoadedGraph, targetMapping: SourceMapping): ExactRecordIndex;
|
|
51
|
+
export declare function lookupExactClassBySymbol(index: ExactRecordIndex, symbol: string): MappingSymbolRecord[];
|
|
52
|
+
export declare function lookupExactMembersByOwner(index: ExactRecordIndex, owner: string): MappingSymbolRecord[];
|
|
53
|
+
export declare function lookupExactClassBySimpleName(index: ExactRecordIndex, name: string): MappingSymbolRecord[];
|
|
54
|
+
export declare function lookupExactMembers(index: ExactRecordIndex, kind: "field" | "method", owner: string, name: string): MappingSymbolRecord[];
|
|
44
55
|
export declare function normalizeIncludedKinds(inputKinds: ClassApiMatrixKind[] | undefined): Set<ClassApiMatrixKind>;
|
|
45
56
|
export declare function inferAmbiguityReasons(candidates: ResolutionCandidate[], usedMojangClientMappings: boolean): string[];
|
|
46
57
|
export declare function clampCandidateLimit(limit: number | undefined): number;
|
package/dist/mapping/lookup.js
CHANGED
|
@@ -429,7 +429,59 @@ export function effectiveLoomSearchProjectPath(projectPath) {
|
|
|
429
429
|
return normalizeOptionalProjectPath(projectPath) ?? normalizeOptionalProjectPath(process.cwd());
|
|
430
430
|
}
|
|
431
431
|
export function collectTargetRecords(graph, targetMapping) {
|
|
432
|
-
return
|
|
432
|
+
return graph.recordsByTarget.get(targetMapping) ?? [];
|
|
433
|
+
}
|
|
434
|
+
function exactRecordKey(kind, owner, name) {
|
|
435
|
+
return `${kind}|${owner}|${name}`;
|
|
436
|
+
}
|
|
437
|
+
/**
|
|
438
|
+
* Lazily build (and memoize on the graph) an O(1) exact-lookup index for a
|
|
439
|
+
* target namespace. Classes key on their FQCN symbol (owner left empty) and are
|
|
440
|
+
* additionally indexed by simple name for the auto-class short-name path;
|
|
441
|
+
* fields/methods key on `kind|owner|name`.
|
|
442
|
+
*/
|
|
443
|
+
export function collectExactRecordIndex(graph, targetMapping) {
|
|
444
|
+
const cached = graph.exactRecordIndex.get(targetMapping);
|
|
445
|
+
if (cached) {
|
|
446
|
+
return cached;
|
|
447
|
+
}
|
|
448
|
+
const byKey = new Map();
|
|
449
|
+
const classBySimpleName = new Map();
|
|
450
|
+
const membersByOwner = new Map();
|
|
451
|
+
const push = (map, key, record) => {
|
|
452
|
+
const bucket = map.get(key);
|
|
453
|
+
if (bucket) {
|
|
454
|
+
bucket.push(record);
|
|
455
|
+
}
|
|
456
|
+
else {
|
|
457
|
+
map.set(key, [record]);
|
|
458
|
+
}
|
|
459
|
+
};
|
|
460
|
+
for (const record of collectTargetRecords(graph, targetMapping)) {
|
|
461
|
+
if (record.kind === "class") {
|
|
462
|
+
push(byKey, exactRecordKey("class", "", record.symbol), record);
|
|
463
|
+
push(classBySimpleName, record.name, record);
|
|
464
|
+
}
|
|
465
|
+
else {
|
|
466
|
+
push(byKey, exactRecordKey(record.kind, record.owner ?? "", record.name), record);
|
|
467
|
+
push(membersByOwner, record.owner ?? "", record);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
const index = { byKey, classBySimpleName, membersByOwner };
|
|
471
|
+
graph.exactRecordIndex.set(targetMapping, index);
|
|
472
|
+
return index;
|
|
473
|
+
}
|
|
474
|
+
export function lookupExactClassBySymbol(index, symbol) {
|
|
475
|
+
return index.byKey.get(exactRecordKey("class", "", symbol)) ?? [];
|
|
476
|
+
}
|
|
477
|
+
export function lookupExactMembersByOwner(index, owner) {
|
|
478
|
+
return index.membersByOwner.get(owner) ?? [];
|
|
479
|
+
}
|
|
480
|
+
export function lookupExactClassBySimpleName(index, name) {
|
|
481
|
+
return index.classBySimpleName.get(name) ?? [];
|
|
482
|
+
}
|
|
483
|
+
export function lookupExactMembers(index, kind, owner, name) {
|
|
484
|
+
return index.byKey.get(exactRecordKey(kind, owner, name)) ?? [];
|
|
433
485
|
}
|
|
434
486
|
export function normalizeIncludedKinds(inputKinds) {
|
|
435
487
|
const normalized = new Set();
|