Skip to content

Commit 46e6ded

Browse files
committed
auth support including arrays
1 parent 191a4de commit 46e6ded

File tree

1 file changed

+163
-120
lines changed

1 file changed

+163
-120
lines changed

src/features/auth.ts

Lines changed: 163 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,14 @@ import { findHoverMatchesInDoc } from "@src/support/doc";
66
import { detectedRange, detectInDoc } from "@src/support/parser";
77
import { wordMatchRegex } from "@src/support/patterns";
88
import { facade, relativeMarkdownLink } from "@src/support/util";
9+
import { AutocompleteParsingResult } from "@src/types";
910
import * as vscode from "vscode";
1011
import {
1112
CompletionProvider,
1213
FeatureTag,
1314
HoverProvider,
1415
LinkProvider,
16+
ValidDetectParamTypes,
1517
} from "..";
1618

1719
const toFind: FeatureTag = [
@@ -40,85 +42,151 @@ const toFind: FeatureTag = [
4042
},
4143
];
4244

45+
const analyzeParam = (
46+
param:
47+
| AutocompleteParsingResult.StringValue
48+
| AutocompleteParsingResult.ArrayValue
49+
| string,
50+
item: AutocompleteParsingResult.ContextValue,
51+
index: number,
52+
):
53+
| { missingReason: "not_found" | "wrong_model" | "ignored" }
54+
| {
55+
policies: AuthItem[];
56+
values: AutocompleteParsingResult.StringValue[] | { value: string }[];
57+
missingReason: null;
58+
} => {
59+
if (item.type !== "methodCall" || !item.methodName || index !== 0) {
60+
return {
61+
missingReason: "ignored",
62+
};
63+
}
64+
65+
let values = [];
66+
67+
if (typeof param === "string") {
68+
values.push({
69+
value: param,
70+
});
71+
} else if (param.type === "array") {
72+
values.push(
73+
...param.children
74+
.map((child) => {
75+
if (child.value.type === "string") {
76+
return child.value;
77+
}
78+
79+
return null;
80+
})
81+
.filter((v) => v !== null),
82+
);
83+
} else {
84+
values.push(param);
85+
}
86+
87+
values = values.filter((value) => value.value !== "");
88+
89+
if (values.length === 0) {
90+
return {
91+
missingReason: "not_found",
92+
};
93+
}
94+
95+
const policies = values
96+
.map((value) => getPolicies().items[value.value])
97+
.flat();
98+
99+
if (["has"].includes(item.methodName)) {
100+
return {
101+
policies,
102+
values,
103+
missingReason: null,
104+
};
105+
}
106+
107+
if (item.arguments.children.length < 2) {
108+
// We don't have a second argument, just ignore it for now
109+
return {
110+
missingReason: "ignored",
111+
};
112+
}
113+
114+
// @ts-ignore
115+
const nextArg = item.arguments.children[1].children[0];
116+
let classArg: string | null = null;
117+
118+
if (nextArg.type === "array") {
119+
classArg = nextArg.children[0]?.value?.className;
120+
} else {
121+
classArg = nextArg?.className;
122+
}
123+
124+
if (!classArg) {
125+
// If it's not a class we can even identify, just ignore it
126+
return {
127+
missingReason: "ignored",
128+
};
129+
}
130+
131+
const found = policies.find((items) => items.model === classArg);
132+
133+
if (!found) {
134+
return {
135+
missingReason: "wrong_model",
136+
};
137+
}
138+
139+
return {
140+
policies: [found],
141+
values,
142+
missingReason: null,
143+
};
144+
};
145+
43146
export const linkProvider: LinkProvider = (doc: vscode.TextDocument) => {
44-
return detectInDoc<vscode.DocumentLink, "string">(
147+
return detectInDoc<vscode.DocumentLink, ValidDetectParamTypes>(
45148
doc,
46149
toFind,
47150
getPolicies,
48151
({ param, item, index }) => {
49-
const policy = getPolicies().items[param.value];
50-
51-
if (!policy || policy.length === 0) {
52-
return null;
53-
}
54-
55-
if (item.type !== "methodCall" || !item.methodName || index !== 0) {
56-
return null;
57-
}
58-
59-
if (["has"].includes(item.methodName)) {
60-
return formattedLink(policy, param);
61-
}
62-
63-
if (item.arguments.children.length < 2) {
64-
// We don't have a second argument, just ignore it for now
65-
return null;
66-
}
67-
68-
// @ts-ignore
69-
const nextArg = item.arguments.children[1].children[0];
70-
const classArg = nextArg?.className;
152+
const result = analyzeParam(param, item, index);
71153

72-
if (!classArg) {
73-
// If it's not a class we can even identify, just ignore it
154+
if (result.missingReason) {
74155
return null;
75156
}
76157

77-
const found = policy.find((item) => item.model === classArg);
78-
79-
if (!found) {
158+
if (result.policies.length > 1) {
159+
// We can't link to multiple policies, just ignore it
80160
return null;
81161
}
82162

83-
return formattedLink([found], param);
163+
return result.policies
164+
.map((item) => {
165+
return result.values
166+
.map(
167+
(
168+
param:
169+
| AutocompleteParsingResult.StringValue
170+
| { value: string },
171+
) => {
172+
return new vscode.DocumentLink(
173+
detectedRange(
174+
param as AutocompleteParsingResult.StringValue,
175+
),
176+
vscode.Uri.file(item.uri).with({
177+
fragment: `L${item.line}`,
178+
}),
179+
);
180+
},
181+
)
182+
.flat();
183+
})
184+
.flat();
84185
},
186+
["array", "string"],
85187
);
86188
};
87189

88-
const formattedLink = (items: AuthItem[], param: any) => {
89-
return items.map((item) => {
90-
return new vscode.DocumentLink(
91-
detectedRange(param),
92-
vscode.Uri.file(item.uri).with({
93-
fragment: `L${item.line}`,
94-
}),
95-
);
96-
});
97-
};
98-
99-
const formattedHover = (items: AuthItem[]) => {
100-
const text = items.map((item) => {
101-
if (item.policy) {
102-
return [
103-
"`" + item.policy + "`",
104-
relativeMarkdownLink(
105-
vscode.Uri.file(item.uri).with({
106-
fragment: `L${item.line}`,
107-
}),
108-
),
109-
].join("\n\n");
110-
}
111-
112-
return relativeMarkdownLink(
113-
vscode.Uri.file(item.uri).with({
114-
fragment: `L${item.line}`,
115-
}),
116-
);
117-
});
118-
119-
return new vscode.Hover(new vscode.MarkdownString(text.join("\n\n")));
120-
};
121-
122190
export const hoverProvider: HoverProvider = (
123191
doc: vscode.TextDocument,
124192
pos: vscode.Position,
@@ -129,42 +197,36 @@ export const hoverProvider: HoverProvider = (
129197
toFind,
130198
getPolicies,
131199
(match, { index, item }) => {
132-
const items = getPolicies().items[match];
133-
134-
if (!items || items.length === 0) {
135-
return null;
136-
}
200+
const result = analyzeParam(match, item, index);
137201

138-
if (item.type !== "methodCall" || !item.methodName || index !== 0) {
202+
if (result.missingReason) {
139203
return null;
140204
}
141205

142-
if (["has"].includes(item.methodName)) {
143-
return formattedHover(items);
144-
}
145-
146-
if (item.arguments.children.length < 2) {
147-
// We don't have a second argument, just ignore it for now
148-
return null;
149-
}
150-
151-
// @ts-ignore
152-
const nextArg = item.arguments.children[1].children[0];
153-
const classArg = nextArg?.className;
154-
155-
if (!classArg) {
156-
// If it's not a class we can even identify, just ignore it
157-
return null;
158-
}
159-
160-
const found = items.find((item) => item.model === classArg);
161-
162-
if (!found) {
163-
return null;
164-
}
206+
const text = result.policies.map((item) => {
207+
if (item.policy) {
208+
return [
209+
"`" + item.policy + "`",
210+
relativeMarkdownLink(
211+
vscode.Uri.file(item.uri).with({
212+
fragment: `L${item.line}`,
213+
}),
214+
),
215+
].join("\n\n");
216+
}
217+
218+
return relativeMarkdownLink(
219+
vscode.Uri.file(item.uri).with({
220+
fragment: `L${item.line}`,
221+
}),
222+
);
223+
});
165224

166-
return formattedHover([found]);
225+
return new vscode.Hover(
226+
new vscode.MarkdownString(text.join("\n\n")),
227+
);
167228
},
229+
["array", "string"],
168230
);
169231
};
170232

@@ -176,13 +238,13 @@ export const diagnosticProvider = (
176238
toFind,
177239
getPolicies,
178240
({ param, item, index }) => {
179-
if (item.type !== "methodCall" || !item.methodName || index !== 0) {
241+
const result = analyzeParam(param, item, index);
242+
243+
if (result.missingReason === null || param.value === "") {
180244
return null;
181245
}
182246

183-
const policy = getPolicies().items[param.value];
184-
185-
if (!policy) {
247+
if (result.missingReason === "not_found") {
186248
return notFound(
187249
"Policy",
188250
param.value,
@@ -191,37 +253,18 @@ export const diagnosticProvider = (
191253
);
192254
}
193255

194-
if (["has"].includes(item.methodName)) {
195-
return null;
196-
}
197-
198-
if (item.arguments.children.length < 2) {
199-
// We don't have a second argument, just ignore it for now
200-
return null;
201-
}
202-
203-
// @ts-ignore
204-
const nextArg = item.arguments.children[1].children[0];
205-
const classArg = nextArg?.className;
206-
207-
if (!classArg) {
208-
// If it's not a class we can even identify, just ignore it
209-
return null;
210-
}
211-
212-
const found = policy.find((item) => item.model === classArg);
213-
214-
if (!found) {
256+
if (result.missingReason === "wrong_model") {
215257
return notFound(
216258
"Policy/Model match",
217-
classArg,
259+
param.value,
218260
detectedRange(param),
219261
"auth",
220262
);
221263
}
222264

223265
return null;
224266
},
267+
["array", "string"],
225268
);
226269
};
227270

@@ -241,7 +284,7 @@ export const completionProvider: CompletionProvider = {
241284
return [];
242285
}
243286

244-
if (result.paramCount() > 0) {
287+
if (result.paramIndex() > 0) {
245288
return [];
246289
}
247290

0 commit comments

Comments
 (0)