diff --git a/src/completion/Registry.ts b/src/completion/Registry.ts index aa42a9a1..6fa1bca2 100644 --- a/src/completion/Registry.ts +++ b/src/completion/Registry.ts @@ -82,6 +82,22 @@ export default class Registry implements vscode.CompletionItemProvider { ); }; + const hasClassExtends = (classExtends: FeatureTagParam["classExtends"]) => { + if (typeof classExtends === "undefined" || classExtends === null) { + return true; + } + + return parseResult.isClassDefinitionExtends(classExtends); + }; + + const hasMethodDefinition = (methodDefinitions: FeatureTagParam["methodDefinition"]) => { + if (typeof methodDefinitions === "undefined" || methodDefinitions === null) { + return true; + } + + return parseResult.isMethodDefinition(methodDefinitions); + }; + const isArgumentIndex = ( argumentIndex: number | number[] | undefined, ) => { @@ -118,7 +134,9 @@ export default class Registry implements vscode.CompletionItemProvider { hasClass(tag.class) && hasFunc(tag.method) && isArgumentIndex(tag.argumentIndex) && - isNamedArg(tag.argumentName), + isNamedArg(tag.argumentName) && + hasClassExtends(tag.classExtends) && + hasMethodDefinition(tag.methodDefinition), ); }) || null ); diff --git a/src/completion/Validation.ts b/src/completion/Validation.ts index 04e3cee2..1660d617 100644 --- a/src/completion/Validation.ts +++ b/src/completion/Validation.ts @@ -123,7 +123,10 @@ export default class Validation implements CompletionProvider { argumentIndex: 0, }, { - classExtends: "Illuminate\\Foundation\\Http\\FormRequest", + classExtends: [ + "Illuminate\\Foundation\\Http\\FormRequest", + "Livewire\\Form", + ], methodDefinition: "rules", }, ]; @@ -144,9 +147,7 @@ export default class Validation implements CompletionProvider { return this.validatorValidation(document, position, result) || []; } - // TODO: Deal with FormRequest@rules method - - return []; + return this.handleFormRequestRulesMethod(document, position, result); } private handleValidateMethod( @@ -182,6 +183,18 @@ export default class Validation implements CompletionProvider { } } + private handleFormRequestRulesMethod( + document: vscode.TextDocument, + position: vscode.Position, + result: AutocompleteResult, + ): vscode.CompletionItem[] { + if (result.fillingInArrayKey()) { + return []; + } + + return this.getRules(document, position); + } + private getRules( document: vscode.TextDocument, position: vscode.Position, diff --git a/src/index.d.ts b/src/index.d.ts index dbc537e8..b3045abe 100644 --- a/src/index.d.ts +++ b/src/index.d.ts @@ -51,7 +51,7 @@ interface FeatureTagParam { argumentName?: string | string[]; classDefinition?: string; methodDefinition?: string; - classExtends?: string; + classExtends?: string | string[]; classImplements?: string; argumentIndex?: number | number[]; } diff --git a/src/parser/AutocompleteResult.ts b/src/parser/AutocompleteResult.ts index d7c251be..9e333c73 100644 --- a/src/parser/AutocompleteResult.ts +++ b/src/parser/AutocompleteResult.ts @@ -33,6 +33,14 @@ export default class AutocompleteResult { } public fillingInArrayKey(): boolean { + if (this.result.type === "array") { + // I'm not sure if this is enough to determine + // if we're filling in a rules array key but I don't + // have better idea at this moment :/ + return this.result.parent?.type !== "array_item" + && this.result.autocompletingKey; + } + return this.param()?.autocompletingKey ?? false; } @@ -65,6 +73,46 @@ export default class AutocompleteResult { ); } + public isClassDefinitionExtends(classNames: string | string[]) { + classNames = Array.isArray(classNames) ? classNames : [classNames]; + + let check = false; + + this.loop((context) => { + if (classNames.some((className: string) => { + return (context as AutocompleteParsingResult.ClassDefinition).extends === className; + })) { + check = true; + + return false; + } + + return true; + }); + + return check; + } + + public isMethodDefinition(methodNames: string | string[]) { + methodNames = Array.isArray(methodNames) ? methodNames : [methodNames]; + + let check = false; + + this.loop((context) => { + if (methodNames.some((methodName: string) => { + return (context as AutocompleteParsingResult.MethodDefinition).methodName === methodName; + })) { + check = true; + + return false; + } + + return true; + }); + + return check; + } + public func() { // @ts-ignore return this.result.methodName ?? null; diff --git a/src/types.ts b/src/types.ts index a4419bab..c3e8052f 100644 --- a/src/types.ts +++ b/src/types.ts @@ -45,6 +45,7 @@ export namespace AutocompleteParsingResult { type: "array"; parent: ContextValue | null; children: ArrayItem[]; + autocompletingKey: boolean; } export interface Assignment {