API Stability Notice
Macroforge is under active development. The API is not yet stable and may change between versions. Some documentation sections may be outdated.
PositionMapper
macroforge v0.1.42
Bidirectional position mapper for translating between original and expanded source positions. This mapper enables IDE features like error reporting, go-to-definition, and hover to work correctly with macro-expanded code by translating positions between the original source (what the user wrote) and the expanded source (what the compiler sees).
Getting a Mapper
import { NativePlugin, PositionMapper } from "macroforge";
const plugin = new NativePlugin();
const result = plugin.processFile("user.ts", code, { version: "1" });
// Get the mapper for this file
const mapper = plugin.getMapper("user.ts");
if (mapper) {
// Use the mapper...
}Methods
isEmpty()
Check if the mapper has any mappings:
isEmpty(): booleanoriginalToExpanded()
Map a position from original to expanded code:
originalToExpanded(pos: number): numberexpandedToOriginal()
Map a position from expanded to original code:
expandedToOriginal(pos: number): number | nullReturns null if the position is in generated code.
isInGenerated()
Check if a position is in macro-generated code:
isInGenerated(pos: number): booleangeneratedBy()
Get the name of the macro that generated code at a position:
generatedBy(pos: number): string | nullmapSpanToOriginal()
Map a span (range) from expanded to original code:
mapSpanToOriginal(start: number, length: number): SpanResult | null
interface SpanResult {
start: number;
length: number;
}mapSpanToExpanded()
Map a span from original to expanded code:
mapSpanToExpanded(start: number, length: number): SpanResultExample: Error Position Mapping
import { NativePlugin } from "macroforge";
const plugin = new NativePlugin();
function mapError(filepath: string, expandedPos: number, message: string) {
const mapper = plugin.getMapper(filepath);
if (!mapper) return null;
// Check if the error is in generated code
if (mapper.isInGenerated(expandedPos)) {
const macroName = mapper.generatedBy(expandedPos);
return {
message: `Error in code generated by @derive(${macroName}): ${message}`,
// Find the @derive decorator position
position: findDecoratorPosition(filepath)
};
}
// Map to original position
const originalPos = mapper.expandedToOriginal(expandedPos);
if (originalPos !== null) {
return {
message,
position: originalPos
};
}
return null;
}Performance
Position mapping uses binary search with O(log n) complexity:
- Fast lookups even for large files
- Minimal memory overhead
- Thread-safe access