Skip to content

Commit 2819bde

Browse files
Enhance Rust API Parser with Stable Line IDs (#1)
* formattign changes and "use name = summary" pattern * replaceCratePath utils * split if glob for "use" * checkpoint - do not show internal details such as generated::* * external module reexports being handled better * formatting changes and upgrade version * refactor common logic - re-export refs * processExternalReferences * linedid utils * checkpoint with a bug * new strategy to isolate the Use items - draft * simple Use item - id fix * template looks great * addExternalReferencesIfNotExists improvement * added a case where use item has not been processed yet, so we process it. * parent info missed * format * bug fix for identity * generic args fix * registerExternalItemReference * changelog * collapse rootModule into top-level * replaceSuperPrefix * line id utils added * update function name * stable lineIds updates
1 parent 89d9dec commit 2819bde

23 files changed

Lines changed: 181 additions & 74 deletions

tools/apiview/parsers/rust-api-parser/src/main.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { CodeFile, TokenKind } from "./models/apiview-models";
44
import { Crate, FORMAT_VERSION, Id } from "../rustdoc-types/output/rustdoc-types";
55
import { externalReferencesLines } from "./process-items/utils/externalReexports";
66
import { sortExternalItems } from "./process-items/utils/sorting";
7+
import { updateReviewLinesWithStableLineIds } from "./utils/lineIdUtils";
78

89
let apiJson: Crate;
910
export const processedItems = new Set<number>();
@@ -77,6 +78,8 @@ function buildCodeFile(): CodeFile {
7778

7879
processRootItem(codeFile);
7980
processExternalReferences(codeFile);
81+
82+
updateReviewLinesWithStableLineIds(codeFile.ReviewLines);
8083
return codeFile;
8184
}
8285

tools/apiview/parsers/rust-api-parser/src/process-items/processAssocConst.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { Item } from "../../rustdoc-types/output/rustdoc-types";
33
import { createDocsReviewLines } from "./utils/generateDocReviewLine";
44
import { typeToReviewTokens } from "./utils/typeToReviewTokens";
55
import { isAssocConstItem } from "./utils/typeGuards";
6+
import { lineIdMap } from "../utils/lineIdUtils";
67

78
/**
89
* Processes an associated constant item and returns ReviewLine objects.
@@ -62,5 +63,6 @@ export function processAssocConst(item: Item): ReviewLine[] | null {
6263
});
6364

6465
reviewLines.push(reviewLine);
66+
lineIdMap.set(item.id.toString(), `const_${item.name}`);
6567
return reviewLines;
6668
}

tools/apiview/parsers/rust-api-parser/src/process-items/processAssocType.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { createDocsReviewLines } from "./utils/generateDocReviewLine";
44
import { typeToReviewTokens } from "./utils/typeToReviewTokens";
55
import { isAssocTypeItem } from "./utils/typeGuards";
66
import { createGenericBoundTokens, processGenerics } from "./utils/processGenerics";
7+
import { lineIdMap } from "../utils/lineIdUtils";
78

89
/**
910
* Processes an associated type item and returns ReviewLine objects.
@@ -65,5 +66,6 @@ export function processAssocType(item: Item): ReviewLine[] | null {
6566
});
6667

6768
reviewLines.push(reviewLine);
69+
lineIdMap.set(item.id.toString(), `type_${item.name}`);
6870
return reviewLines;
6971
}

tools/apiview/parsers/rust-api-parser/src/process-items/processConstant.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { Item } from "../../rustdoc-types/output/rustdoc-types";
33
import { createDocsReviewLines } from "./utils/generateDocReviewLine";
44
import { isConstantItem } from "./utils/typeGuards";
55
import { typeToReviewTokens } from "./utils/typeToReviewTokens";
6+
import { lineIdMap } from "../utils/lineIdUtils";
67

78
export function processConstant(item: Item) {
89
if (!isConstantItem(item)) return;
@@ -56,5 +57,6 @@ export function processConstant(item: Item) {
5657
});
5758
}
5859
reviewLines.push(reviewLine);
60+
lineIdMap.set(item.id.toString(), `const_${item.name}`);
5961
return reviewLines;
6062
}

tools/apiview/parsers/rust-api-parser/src/process-items/processEnum.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,14 @@ import { createDocsReviewLines } from "./utils/generateDocReviewLine";
55
import { processGenerics } from "./utils/processGenerics";
66
import { isEnumItem } from "./utils/typeGuards";
77
import { getAPIJson } from "../main";
8+
import { lineIdMap } from "../utils/lineIdUtils";
89

910
export function processEnum(item: Item): ReviewLine[] {
1011
if (!isEnumItem(item)) return [];
1112
const apiJson = getAPIJson();
1213
const reviewLines: ReviewLine[] = item.docs ? createDocsReviewLines(item) : [];
1314

15+
lineIdMap.set(item.id.toString(), `enum_${item.name}`);
1416
// Process derives and impls
1517
let implResult: ImplProcessResult;
1618
if (item.inner.enum.impls) {
@@ -25,7 +27,6 @@ export function processEnum(item: Item): ReviewLine[] {
2527

2628
if (implResult.deriveTokens.length > 0) {
2729
const deriveTokensLine: ReviewLine = {
28-
LineId: item.id.toString() + "_derive",
2930
Tokens: implResult.deriveTokens,
3031
RelatedToLine: item.id.toString(),
3132
};
@@ -67,6 +68,7 @@ export function processEnum(item: Item): ReviewLine[] {
6768
if (item.inner.enum.variants) {
6869
enumLine.Children = item.inner.enum.variants.map((variant: number) => {
6970
const variantItem = apiJson.index[variant];
71+
lineIdMap.set(variantItem.id.toString(), `variant_${variantItem.name}`);
7072
return {
7173
LineId: variantItem.id.toString(),
7274
Tokens: [
@@ -97,5 +99,6 @@ export function processEnum(item: Item): ReviewLine[] {
9799
if (implResult.traitImpls.length > 0) {
98100
reviewLines.push(...implResult.traitImpls);
99101
}
102+
lineIdMap.set(item.id.toString(), `enum_${item.name}`);
100103
return reviewLines;
101104
}

tools/apiview/parsers/rust-api-parser/src/process-items/processExternType.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { ReviewLine, TokenKind } from "../models/apiview-models";
22
import { Item } from "../../rustdoc-types/output/rustdoc-types";
33
import { createDocsReviewLines } from "./utils/generateDocReviewLine";
44
import { isExternTypeItem } from "./utils/typeGuards";
5+
import { lineIdMap } from "../utils/lineIdUtils";
56

67
/**
78
* Processes an extern type item and returns ReviewLine objects.
@@ -40,5 +41,6 @@ export function processExternType(item: Item): ReviewLine[] | null {
4041
});
4142

4243
reviewLines.push(reviewLine);
44+
lineIdMap.set(item.id.toString(), `extern_type_${item.name}`);
4345
return reviewLines;
4446
}

tools/apiview/parsers/rust-api-parser/src/process-items/processFunction.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { createDocsReviewLines } from "./utils/generateDocReviewLine";
44
import { processGenerics } from "./utils/processGenerics";
55
import { isFunctionItem } from "./utils/typeGuards";
66
import { typeToReviewTokens } from "./utils/typeToReviewTokens";
7+
import { lineIdMap } from "../utils/lineIdUtils";
78

89
/**
910
* Processes the function header and adds modifiers and ABI information to the tokens
@@ -175,5 +176,6 @@ export function processFunction(item: Item): ReviewLine[] {
175176
});
176177
}
177178
reviewLines.push(reviewLine);
179+
lineIdMap.set(item.id.toString(), `function_${item.name}`);
178180
return reviewLines;
179181
}

tools/apiview/parsers/rust-api-parser/src/process-items/processImpl.ts

Lines changed: 62 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
import { typeToReviewTokens } from "./utils/typeToReviewTokens";
1313
import { processGenericArgs, processGenerics } from "./utils/processGenerics";
1414
import { getAPIJson } from "../main";
15+
import { lineIdMap } from "../utils/lineIdUtils";
1516

1617
// Interface for the result of processing implementations
1718
export interface ImplProcessResult {
@@ -60,7 +61,7 @@ export function processAutoTraitImpls(impls: number[]): ReviewToken[] {
6061
}
6162

6263
// Process manually implemented trait implementations
63-
function processOtherTraitImpls(impls: number[]): ReviewLine[] {
64+
function processOtherTraitImpls(impls: number[], prefixId: string): ReviewLine[] {
6465
const apiJson = getAPIJson();
6566
const traitImpls = getFilteredImpls(impls, isManualTraitImpl);
6667
return traitImpls.flatMap((implItem) => {
@@ -69,33 +70,35 @@ function processOtherTraitImpls(impls: number[]): ReviewLine[] {
6970
// Get the type that the trait is implemented for
7071
const parentName = typeToReviewTokens(implItem.inner.impl.for);
7172

72-
const implId = implItem.id.toString();
73+
const lineId = implItem.id.toString() + "_" + prefixId;
7374
// Process provided trait methods that are mentioned but not explicitly implemented
7475
const providedTraitMethods: ReviewLine[] = implItem.inner.impl.provided_trait_methods.map(
75-
(method) => ({
76-
LineId: implId + "_impl_" + method,
77-
Tokens: [
78-
{ Kind: TokenKind.Keyword, Value: "pub" },
79-
{ Kind: TokenKind.Keyword, Value: "fn" },
80-
{
81-
Kind: TokenKind.MemberName,
82-
Value: method,
83-
RenderClasses: ["method"],
84-
HasSuffixSpace: false,
85-
},
86-
{ Kind: TokenKind.Punctuation, Value: ";" },
87-
{
88-
Kind: TokenKind.Comment,
89-
Value: "// provided trait method",
90-
HasSuffixSpace: false,
91-
},
92-
],
93-
}),
76+
(method) => {
77+
return {
78+
Tokens: [
79+
{ Kind: TokenKind.Keyword, Value: "pub" },
80+
{ Kind: TokenKind.Keyword, Value: "fn" },
81+
{
82+
Kind: TokenKind.MemberName,
83+
Value: method,
84+
RenderClasses: ["method"],
85+
HasSuffixSpace: false,
86+
},
87+
{ Kind: TokenKind.Punctuation, Value: ";" },
88+
{
89+
Kind: TokenKind.Comment,
90+
Value: "// provided trait method",
91+
HasSuffixSpace: false,
92+
},
93+
],
94+
RelatedToLine: lineId,
95+
};
96+
},
9497
);
9598
const implGenerics = processGenerics(implItem.inner.impl.generics);
9699
// Create the main impl line with trait name and type
97100
const reviewLineForImpl: ReviewLine = {
98-
LineId: implId + "_impl",
101+
LineId: lineId,
99102
Tokens: [
100103
{
101104
Kind: TokenKind.Keyword,
@@ -108,7 +111,7 @@ function processOtherTraitImpls(impls: number[]): ReviewLine[] {
108111
Value: (implItem.inner.impl.is_negative ? "!" : "") + implItem.inner.impl.trait.name,
109112
HasPrefixSpace: true,
110113
HasSuffixSpace: false,
111-
NavigateToId: implId + "_impl",
114+
NavigateToId: lineId,
112115
// Create navigation display name by combining trait and type names
113116
NavigationDisplayName:
114117
implItem.inner.impl.trait.name + "_" + parentName.map((token) => token.Value).join(""),
@@ -132,8 +135,16 @@ function processOtherTraitImpls(impls: number[]): ReviewLine[] {
132135
],
133136
};
134137

138+
lineIdMap.set(
139+
lineId,
140+
prefixId +
141+
reviewLineForImpl.Tokens.map((token) => token.Value)
142+
.join("_")
143+
.replace(/[^a-zA-Z0-9]+/g, ""),
144+
);
145+
135146
const closingLine: ReviewLine = {
136-
RelatedToLine: implItem.id.toString() + "_impl",
147+
RelatedToLine: lineId,
137148
Tokens: [{ Kind: TokenKind.Punctuation, Value: "}" }],
138149
};
139150

@@ -166,6 +177,8 @@ export function processImpl(
166177
| (Item & { inner: { enum: Enum } })
167178
| (Item & { inner: { union: Union } }),
168179
): ImplProcessResult {
180+
const linedId = item.id.toString() + "_impl";
181+
lineIdMap.set(linedId, lineIdMap.get(item.id.toString()) + "_impl");
169182
// Get all implementations associated with this item
170183
const impls = getImplsFromItem(item);
171184

@@ -176,35 +189,35 @@ export function processImpl(
176189
// Process children first to check if they're empty
177190
const children = processImpls(impls).filter((item) => item != null);
178191

179-
// Only create an implBlock if there are children
180-
const implBlock: ReviewLine[] =
181-
children.length === 0
182-
? [] // Empty implBlock if no children
183-
: [
184-
// Create the main implementation line with type name
185-
{
186-
LineId: item.id.toString() + "_impl",
187-
Tokens: [
188-
{ Kind: TokenKind.Keyword, Value: "impl" },
189-
{
190-
Kind: TokenKind.MemberName,
191-
Value: item.name || "null",
192-
RenderClasses: ["interface"],
193-
NavigateToId: item.id.toString() + "_impl",
194-
NavigationDisplayName: item.name || undefined,
195-
},
196-
{ Kind: TokenKind.Punctuation, Value: "{" },
197-
],
198-
Children: children,
199-
},
192+
let implBlock: ReviewLine[] = [];
193+
if (children.length > 0) {
194+
// Only create an implBlock if there are children
195+
implBlock = [
196+
// Create the main implementation line with type name
197+
{
198+
LineId: linedId,
199+
Tokens: [
200+
{ Kind: TokenKind.Keyword, Value: "impl" },
200201
{
201-
RelatedToLine: item.id.toString() + "_impl",
202-
Tokens: [{ Kind: TokenKind.Punctuation, Value: "}" }],
202+
Kind: TokenKind.MemberName,
203+
Value: item.name || "null",
204+
RenderClasses: ["interface"],
205+
NavigateToId: linedId,
206+
NavigationDisplayName: item.name || undefined,
203207
},
204-
];
208+
{ Kind: TokenKind.Punctuation, Value: "{" },
209+
],
210+
Children: children,
211+
},
212+
{
213+
RelatedToLine: linedId,
214+
Tokens: [{ Kind: TokenKind.Punctuation, Value: "}" }],
215+
},
216+
];
217+
}
205218

206219
// Process manual trait implementations (like impl Trait for Type { ... })
207-
const traitImpls = processOtherTraitImpls(impls);
220+
const traitImpls = processOtherTraitImpls(impls, item.name);
208221

209222
return { deriveTokens, implBlock, traitImpls };
210223
}

tools/apiview/parsers/rust-api-parser/src/process-items/processMacro.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { ReviewLine, TokenKind } from "../models/apiview-models";
22
import { Item } from "../../rustdoc-types/output/rustdoc-types";
33
import { createDocsReviewLines } from "./utils/generateDocReviewLine";
44
import { isMacroItem } from "./utils/typeGuards";
5+
import { lineIdMap } from "../utils/lineIdUtils";
56

67
/**
78
* Processes a macro item and returns ReviewLine objects.
@@ -17,18 +18,20 @@ export function processMacro(item: Item): ReviewLine[] | null {
1718
// Split the macro value by newlines
1819
const macroLines = item.inner.macro.split("\n");
1920

21+
const linedId = item.id.toString();
22+
lineIdMap.set(linedId, macroLines[0]);
2023
// Create ReviewLines for each macro line
2124
macroLines.forEach((line, index) => {
2225
const reviewLine: ReviewLine = {
23-
LineId: index === 0 ? item.id.toString() : `${item.id.toString()}_macro_${index}`,
26+
LineId: index === 0 ? linedId : undefined,
2427
Tokens: [
2528
{
2629
Kind: TokenKind.Text,
2730
Value: line,
2831
},
2932
],
3033
// Only additional lines are related to the first line
31-
RelatedToLine: index === 0 ? undefined : item.id.toString(),
34+
RelatedToLine: index === 0 ? undefined : linedId,
3235
};
3336
reviewLines.push(reviewLine);
3437
});

tools/apiview/parsers/rust-api-parser/src/process-items/processModule.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { getAPIJson, processedItems } from "../main";
77
import { getSortedChildIds } from "./utils/sorting";
88
import { processUse } from "./processUse";
99
import { AnnotatedReviewLines } from "./utils/models";
10+
import { lineIdMap } from "../utils/lineIdUtils";
1011

1112
/**
1213
* Processes a module item and adds its documentation to the ReviewLine.
@@ -24,6 +25,7 @@ export function processModule(
2425
const apiJson = getAPIJson();
2526
const isRootModule = item.id === apiJson.root;
2627

28+
lineIdMap.set(item.id.toString(), item.name || "null");
2729
// Create the ReviewLine object
2830
const reviewLine: ReviewLine = {
2931
LineId: item.id.toString(),
@@ -54,6 +56,7 @@ export function processModule(
5456
});
5557
}
5658
fullName += item.name;
59+
lineIdMap.set(item.id.toString(), fullName);
5760
// current module
5861
reviewLine.Tokens.push({
5962
Kind: TokenKind.TypeName,

0 commit comments

Comments
 (0)