forked from Azure/azure-sdk-tools
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathprocessImpl.ts
More file actions
223 lines (205 loc) · 7.88 KB
/
processImpl.ts
File metadata and controls
223 lines (205 loc) · 7.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
import { ReviewLine, TokenKind, ReviewToken } from "../models/apiview-models";
import { Enum, Item, Struct, Union } from "../../rustdoc-types/output/rustdoc-types";
import { processItem } from "./processItem";
import { isImplItem } from "./utils/typeGuards";
import {
isAutoDerivedImpl,
isManualTraitImpl,
isInherentImpl,
getImplsFromItem,
ImplItem,
} from "./utils/implTypeGuards";
import { typeToReviewTokens } from "./utils/typeToReviewTokens";
import { processGenericArgs, processGenerics } from "./utils/processGenerics";
import { getAPIJson } from "../main";
import { lineIdMap } from "../utils/lineIdUtils";
// Interface for the result of processing implementations
export interface ImplProcessResult {
deriveTokens: ReviewToken[]; // Auto-derived trait implementations (#[derive(...)])
implBlock: ReviewLine[]; // Inherent implementations (impl Type { ... })
traitImpls: ReviewLine[]; // Manual trait implementations (impl Trait for Type { ... })
}
// Helper function to map impl IDs to their items and filter by type
function getFilteredImpls<T extends ImplItem>(
impls: number[],
filterFn: (item: ImplItem) => boolean,
): T[] {
const apiJson = getAPIJson();
return impls
.map((implId) => apiJson.index[implId] as ImplItem)
.filter((item) => isImplItem(item) && filterFn(item)) as T[];
}
// Process automatically derived trait implementations
export function processAutoTraitImpls(impls: number[]): ReviewToken[] {
const traitItems = getFilteredImpls(impls, isAutoDerivedImpl);
// Get all traits that have been derived
const traits = traitItems.map<ReviewToken>((item) => ({
Kind: TokenKind.MemberName,
Value: item.inner.impl.trait!.name,
HasSuffixSpace: false,
}));
if (!traits.length) return [];
// Build the complete derive attribute with all derived traits
return [
// Start of the derive attribute
{ Kind: TokenKind.Punctuation, Value: "#[", HasSuffixSpace: false },
{ Kind: TokenKind.Keyword, Value: "derive", HasSuffixSpace: false },
{ Kind: TokenKind.Punctuation, Value: "(", HasSuffixSpace: false },
// Add each trait name with commas between them
...traits.flatMap((token, index) => [
token,
...(index < traits.length - 1 ? [{ Kind: TokenKind.Punctuation, Value: "," }] : []),
]),
// Close the derive attribute
{ Kind: TokenKind.Punctuation, Value: ")]" },
{ Kind: TokenKind.Punctuation, Value: "\n", HasSuffixSpace: false },
];
}
// Process manually implemented trait implementations
function processOtherTraitImpls(impls: number[], prefixId: string): ReviewLine[] {
const apiJson = getAPIJson();
const traitImpls = getFilteredImpls(impls, isManualTraitImpl);
return traitImpls.flatMap((implItem) => {
if (!implItem.inner.impl.trait) return [];
// Get the type that the trait is implemented for
const parentName = typeToReviewTokens(implItem.inner.impl.for);
const lineId = implItem.id.toString() + "_" + prefixId;
// Process provided trait methods that are mentioned but not explicitly implemented
const providedTraitMethods: ReviewLine[] = implItem.inner.impl.provided_trait_methods.map(
(method) => {
return {
Tokens: [
{ Kind: TokenKind.Keyword, Value: "pub" },
{ Kind: TokenKind.Keyword, Value: "fn" },
{
Kind: TokenKind.MemberName,
Value: method,
RenderClasses: ["method"],
HasSuffixSpace: false,
},
{ Kind: TokenKind.Punctuation, Value: ";" },
{
Kind: TokenKind.Comment,
Value: "// provided trait method",
HasSuffixSpace: false,
},
],
RelatedToLine: lineId,
};
},
);
const implGenerics = processGenerics(implItem.inner.impl.generics);
// Create the main impl line with trait name and type
const reviewLineForImpl: ReviewLine = {
LineId: lineId,
Tokens: [
{
Kind: TokenKind.Keyword,
Value: (implItem.inner.impl.is_unsafe ? "unsafe " : "") + "impl",
HasSuffixSpace: false,
},
...implGenerics.params,
{
Kind: TokenKind.MemberName,
Value: (implItem.inner.impl.is_negative ? "!" : "") + implItem.inner.impl.trait.name,
HasPrefixSpace: true,
HasSuffixSpace: false,
NavigateToId: lineId,
// Create navigation display name by combining trait and type names
NavigationDisplayName:
implItem.inner.impl.trait.name + "_" + parentName.map((token) => token.Value).join(""),
RenderClasses: ["interface"],
},
// Add any generic arguments the trait might have
...processGenericArgs(implItem.inner.impl.trait.args),
{ Kind: TokenKind.Punctuation, Value: "for", HasPrefixSpace: true },
// Add the type the trait is implemented for
...parentName,
...implGenerics.wherePredicates,
{ Kind: TokenKind.Punctuation, Value: "{", HasPrefixSpace: true },
],
// Add both implemented methods and provided methods as children
Children: [
...implItem.inner.impl.items
.map((item) => processItem(apiJson.index[item]))
.filter((item) => item != null)
.flat(),
...providedTraitMethods,
],
};
lineIdMap.set(
lineId,
prefixId +
reviewLineForImpl.Tokens.map((token) => token.Value)
.join("_")
.replace(/[^a-zA-Z0-9]+/g, ""),
);
const closingLine: ReviewLine = {
RelatedToLine: lineId,
Tokens: [{ Kind: TokenKind.Punctuation, Value: "}" }],
};
return [reviewLineForImpl, closingLine];
});
}
// Process inherent implementations
function processImpls(impls: number[]): ReviewLine[] {
const apiJson = getAPIJson();
const inherentImpls = getFilteredImpls(impls, isInherentImpl);
return (
inherentImpls
// Process each implementation's items and flatten the results
.flatMap((implItem) =>
implItem.inner.impl.items
// Process each item within the impl
.map((item) => processItem(apiJson.index[item]))
// Flatten nested arrays
.flat(),
)
);
}
// Main function to process implementations for a given item
export function processImpl(
item:
| (Item & { inner: { struct: Struct } })
| (Item & { inner: { enum: Enum } })
| (Item & { inner: { union: Union } }),
): ImplProcessResult {
const linedId = item.id.toString() + "_impl";
lineIdMap.set(linedId, lineIdMap.get(item.id.toString()) + "_impl");
// Get all implementations associated with this item
const impls = getImplsFromItem(item);
// Process auto-derived trait implementations (like #[derive(Debug, Clone)])
const deriveTokens = processAutoTraitImpls(impls);
// Process inherent method implementations (like impl Type { fn method() {} })
// Process children first to check if they're empty
const children = processImpls(impls).filter((item) => item != null);
let implBlock: ReviewLine[] = [];
if (children.length > 0) {
// Only create an implBlock if there are children
implBlock = [
// Create the main implementation line with type name
{
LineId: linedId,
Tokens: [
{ Kind: TokenKind.Keyword, Value: "impl" },
{
Kind: TokenKind.MemberName,
Value: item.name || "unknown_impl",
RenderClasses: ["interface"],
NavigateToId: linedId,
NavigationDisplayName: item.name || undefined,
},
{ Kind: TokenKind.Punctuation, Value: "{" },
],
Children: children,
},
{
RelatedToLine: linedId,
Tokens: [{ Kind: TokenKind.Punctuation, Value: "}" }],
},
];
}
// Process manual trait implementations (like impl Trait for Type { ... })
const traitImpls = processOtherTraitImpls(impls, item.name);
return { deriveTokens, implBlock, traitImpls };
}