diff --git a/src/InlayHintOptions.php b/src/InlayHintOptions.php index dfd40ca..126f4f0 100644 --- a/src/InlayHintOptions.php +++ b/src/InlayHintOptions.php @@ -7,10 +7,18 @@ use RuntimeException; /** - * Mixins (implemented TS interfaces): WorkDoneProgressOptions, array + * Mixins (implemented TS interfaces): WorkDoneProgressOptions */ class InlayHintOptions { + /** + * The server provides support to resolve additional + * information for an inlay hint item. + * + * @var bool|null + */ + public $resolveProvider; + /** * * @var bool|null @@ -18,10 +26,12 @@ class InlayHintOptions public $workDoneProgress; /** + * @param bool|null $resolveProvider * @param bool|null $workDoneProgress */ - public function __construct(?bool $workDoneProgress = null) + public function __construct(?bool $resolveProvider = null, ?bool $workDoneProgress = null) { + $this->resolveProvider = $resolveProvider; $this->workDoneProgress = $workDoneProgress; } @@ -32,6 +42,7 @@ public function __construct(?bool $workDoneProgress = null) public static function fromArray(array $array, bool $allowUnknownKeys = false) { $map = [ + 'resolveProvider' => ['names' => [], 'iterable' => false], 'workDoneProgress' => ['names' => [], 'iterable' => false], ]; diff --git a/src/InlayHintParams.php b/src/InlayHintParams.php index ceab082..6050ff7 100644 --- a/src/InlayHintParams.php +++ b/src/InlayHintParams.php @@ -7,10 +7,24 @@ use RuntimeException; /** - * Mixins (implemented TS interfaces): WorkDoneProgressParams, array + * Mixins (implemented TS interfaces): WorkDoneProgressParams */ class InlayHintParams { + /** + * The text document. + * + * @var TextDocumentIdentifier + */ + public $textDocument; + + /** + * The document range for which inlay hints should be computed. + * + * @var Range + */ + public $range; + /** * An optional token that a server can use to report work done progress. * @@ -19,10 +33,14 @@ class InlayHintParams public $workDoneToken; /** + * @param TextDocumentIdentifier $textDocument + * @param Range $range * @param int|string|null $workDoneToken */ - public function __construct($workDoneToken = null) + public function __construct(TextDocumentIdentifier $textDocument, Range $range, $workDoneToken = null) { + $this->textDocument = $textDocument; + $this->range = $range; $this->workDoneToken = $workDoneToken; } @@ -33,6 +51,8 @@ public function __construct($workDoneToken = null) public static function fromArray(array $array, bool $allowUnknownKeys = false) { $map = [ + 'textDocument' => ['names' => [TextDocumentIdentifier::class], 'iterable' => false], + 'range' => ['names' => [Range::class], 'iterable' => false], 'workDoneToken' => ['names' => [], 'iterable' => false], ]; diff --git a/src/InlineValueEvaluatableExpression.php b/src/InlineValueEvaluatableExpression.php new file mode 100644 index 0000000..710e273 --- /dev/null +++ b/src/InlineValueEvaluatableExpression.php @@ -0,0 +1,110 @@ +range = $range; + $this->expression = $expression; + } + + /** + * @param array $array + * @return self + */ + public static function fromArray(array $array, bool $allowUnknownKeys = false) + { + $map = [ + 'range' => ['names' => [Range::class], 'iterable' => false], + 'expression' => ['names' => [], 'iterable' => false], + ]; + + foreach ($array as $key => &$value) { + if (!isset($map[$key])) { + if ($allowUnknownKeys) { + unset($array[$key]); + continue; + } + + throw new RuntimeException(sprintf( + 'Parameter "%s" on class "%s" not known, known parameters: "%s"', + $key, + self::class, + implode('", "', array_keys($map)) + )); + } + + // from here we only care about arrays that can be transformed into + // objects + if (!is_array($value)) { + continue; + } + + if (empty($map[$key]['names'])) { + continue; + } + + if ($map[$key]['iterable']) { + $value = array_map(function ($object) use ($map, $key, $allowUnknownKeys) { + if (!is_array($object)) { + return $object; + } + + return self::invokeFromNames($map[$key]['names'], $object, $allowUnknownKeys) ?: $object; + }, $value); + continue; + } + + $names = $map[$key]['names']; + $value = self::invokeFromNames($names, $value, $allowUnknownKeys) ?: $value; + } + + return Invoke::new(self::class, $array); + } + + /** + * @param array $classNames + * @param array $object + */ + private static function invokeFromNames(array $classNames, array $object, bool $allowUnknownKeys): ?object + { + $lastException = null; + foreach ($classNames as $className) { + try { + // @phpstan-ignore-next-line + return call_user_func_array($className . '::fromArray', [$object, $allowUnknownKeys]); + } catch (Exception $exception) { + $lastException = $exception; + continue; + } + } + + throw $lastException; + } + +} \ No newline at end of file diff --git a/src/InlineValueParams.php b/src/InlineValueParams.php new file mode 100644 index 0000000..7e5d836 --- /dev/null +++ b/src/InlineValueParams.php @@ -0,0 +1,133 @@ +textDocument = $textDocument; + $this->range = $range; + $this->context = $context; + $this->workDoneToken = $workDoneToken; + } + + /** + * @param array $array + * @return self + */ + public static function fromArray(array $array, bool $allowUnknownKeys = false) + { + $map = [ + 'textDocument' => ['names' => [TextDocumentIdentifier::class], 'iterable' => false], + 'range' => ['names' => [Range::class], 'iterable' => false], + 'context' => ['names' => [], 'iterable' => false], + 'workDoneToken' => ['names' => [], 'iterable' => false], + ]; + + foreach ($array as $key => &$value) { + if (!isset($map[$key])) { + if ($allowUnknownKeys) { + unset($array[$key]); + continue; + } + + throw new RuntimeException(sprintf( + 'Parameter "%s" on class "%s" not known, known parameters: "%s"', + $key, + self::class, + implode('", "', array_keys($map)) + )); + } + + // from here we only care about arrays that can be transformed into + // objects + if (!is_array($value)) { + continue; + } + + if (empty($map[$key]['names'])) { + continue; + } + + if ($map[$key]['iterable']) { + $value = array_map(function ($object) use ($map, $key, $allowUnknownKeys) { + if (!is_array($object)) { + return $object; + } + + return self::invokeFromNames($map[$key]['names'], $object, $allowUnknownKeys) ?: $object; + }, $value); + continue; + } + + $names = $map[$key]['names']; + $value = self::invokeFromNames($names, $value, $allowUnknownKeys) ?: $value; + } + + return Invoke::new(self::class, $array); + } + + /** + * @param array $classNames + * @param array $object + */ + private static function invokeFromNames(array $classNames, array $object, bool $allowUnknownKeys): ?object + { + $lastException = null; + foreach ($classNames as $className) { + try { + // @phpstan-ignore-next-line + return call_user_func_array($className . '::fromArray', [$object, $allowUnknownKeys]); + } catch (Exception $exception) { + $lastException = $exception; + continue; + } + } + + throw $lastException; + } + +} \ No newline at end of file diff --git a/src/InlineValueRefreshRequest.php b/src/InlineValueRefreshRequest.php new file mode 100644 index 0000000..e34dd9d --- /dev/null +++ b/src/InlineValueRefreshRequest.php @@ -0,0 +1,8 @@ +|null + */ + public $documentSelector; + + /** + * The id used to register the request. The id can be used to deregister + * the request again. See also Registration#id. + * + * @var string|null + */ + public $id; + + /** + * @param bool|null $workDoneProgress + * @param array<(string|array{language:string,scheme:string,pattern:string}|array{language:string,scheme:string,pattern:string}|array{language:string,scheme:string,pattern:string}|array{notebook:string|array{notebookType:string,scheme:string,pattern:string}|array{notebookType:string,scheme:string,pattern:string}|array{notebookType:string,scheme:string,pattern:string},language:string})>|null $documentSelector + * @param string|null $id + */ + public function __construct(?bool $workDoneProgress = null, $documentSelector = null, ?string $id = null) + { + $this->workDoneProgress = $workDoneProgress; + $this->documentSelector = $documentSelector; + $this->id = $id; + } + + /** + * @param array $array + * @return self + */ + public static function fromArray(array $array, bool $allowUnknownKeys = false) + { + $map = [ + 'workDoneProgress' => ['names' => [], 'iterable' => false], + 'documentSelector' => ['names' => [], 'iterable' => false], + 'id' => ['names' => [], 'iterable' => false], + ]; + + foreach ($array as $key => &$value) { + if (!isset($map[$key])) { + if ($allowUnknownKeys) { + unset($array[$key]); + continue; + } + + throw new RuntimeException(sprintf( + 'Parameter "%s" on class "%s" not known, known parameters: "%s"', + $key, + self::class, + implode('", "', array_keys($map)) + )); + } + + // from here we only care about arrays that can be transformed into + // objects + if (!is_array($value)) { + continue; + } + + if (empty($map[$key]['names'])) { + continue; + } + + if ($map[$key]['iterable']) { + $value = array_map(function ($object) use ($map, $key, $allowUnknownKeys) { + if (!is_array($object)) { + return $object; + } + + return self::invokeFromNames($map[$key]['names'], $object, $allowUnknownKeys) ?: $object; + }, $value); + continue; + } + + $names = $map[$key]['names']; + $value = self::invokeFromNames($names, $value, $allowUnknownKeys) ?: $value; + } + + return Invoke::new(self::class, $array); + } + + /** + * @param array $classNames + * @param array $object + */ + private static function invokeFromNames(array $classNames, array $object, bool $allowUnknownKeys): ?object + { + $lastException = null; + foreach ($classNames as $className) { + try { + // @phpstan-ignore-next-line + return call_user_func_array($className . '::fromArray', [$object, $allowUnknownKeys]); + } catch (Exception $exception) { + $lastException = $exception; + continue; + } + } + + throw $lastException; + } + +} \ No newline at end of file diff --git a/src/InlineValueRequest.php b/src/InlineValueRequest.php new file mode 100644 index 0000000..2fea2b8 --- /dev/null +++ b/src/InlineValueRequest.php @@ -0,0 +1,8 @@ +range = $range; + $this->text = $text; + } + + /** + * @param array $array + * @return self + */ + public static function fromArray(array $array, bool $allowUnknownKeys = false) + { + $map = [ + 'range' => ['names' => [Range::class], 'iterable' => false], + 'text' => ['names' => [], 'iterable' => false], + ]; + + foreach ($array as $key => &$value) { + if (!isset($map[$key])) { + if ($allowUnknownKeys) { + unset($array[$key]); + continue; + } + + throw new RuntimeException(sprintf( + 'Parameter "%s" on class "%s" not known, known parameters: "%s"', + $key, + self::class, + implode('", "', array_keys($map)) + )); + } + + // from here we only care about arrays that can be transformed into + // objects + if (!is_array($value)) { + continue; + } + + if (empty($map[$key]['names'])) { + continue; + } + + if ($map[$key]['iterable']) { + $value = array_map(function ($object) use ($map, $key, $allowUnknownKeys) { + if (!is_array($object)) { + return $object; + } + + return self::invokeFromNames($map[$key]['names'], $object, $allowUnknownKeys) ?: $object; + }, $value); + continue; + } + + $names = $map[$key]['names']; + $value = self::invokeFromNames($names, $value, $allowUnknownKeys) ?: $value; + } + + return Invoke::new(self::class, $array); + } + + /** + * @param array $classNames + * @param array $object + */ + private static function invokeFromNames(array $classNames, array $object, bool $allowUnknownKeys): ?object + { + $lastException = null; + foreach ($classNames as $className) { + try { + // @phpstan-ignore-next-line + return call_user_func_array($className . '::fromArray', [$object, $allowUnknownKeys]); + } catch (Exception $exception) { + $lastException = $exception; + continue; + } + } + + throw $lastException; + } + +} \ No newline at end of file diff --git a/src/InlineValueVariableLookup.php b/src/InlineValueVariableLookup.php new file mode 100644 index 0000000..b6b2a5c --- /dev/null +++ b/src/InlineValueVariableLookup.php @@ -0,0 +1,120 @@ +range = $range; + $this->variableName = $variableName; + $this->caseSensitiveLookup = $caseSensitiveLookup; + } + + /** + * @param array $array + * @return self + */ + public static function fromArray(array $array, bool $allowUnknownKeys = false) + { + $map = [ + 'range' => ['names' => [Range::class], 'iterable' => false], + 'variableName' => ['names' => [], 'iterable' => false], + 'caseSensitiveLookup' => ['names' => [], 'iterable' => false], + ]; + + foreach ($array as $key => &$value) { + if (!isset($map[$key])) { + if ($allowUnknownKeys) { + unset($array[$key]); + continue; + } + + throw new RuntimeException(sprintf( + 'Parameter "%s" on class "%s" not known, known parameters: "%s"', + $key, + self::class, + implode('", "', array_keys($map)) + )); + } + + // from here we only care about arrays that can be transformed into + // objects + if (!is_array($value)) { + continue; + } + + if (empty($map[$key]['names'])) { + continue; + } + + if ($map[$key]['iterable']) { + $value = array_map(function ($object) use ($map, $key, $allowUnknownKeys) { + if (!is_array($object)) { + return $object; + } + + return self::invokeFromNames($map[$key]['names'], $object, $allowUnknownKeys) ?: $object; + }, $value); + continue; + } + + $names = $map[$key]['names']; + $value = self::invokeFromNames($names, $value, $allowUnknownKeys) ?: $value; + } + + return Invoke::new(self::class, $array); + } + + /** + * @param array $classNames + * @param array $object + */ + private static function invokeFromNames(array $classNames, array $object, bool $allowUnknownKeys): ?object + { + $lastException = null; + foreach ($classNames as $className) { + try { + // @phpstan-ignore-next-line + return call_user_func_array($className . '::fromArray', [$object, $allowUnknownKeys]); + } catch (Exception $exception) { + $lastException = $exception; + continue; + } + } + + throw $lastException; + } + +} \ No newline at end of file diff --git a/src/ServerCapabilities.php b/src/ServerCapabilities.php index f497d74..866edba 100644 --- a/src/ServerCapabilities.php +++ b/src/ServerCapabilities.php @@ -237,7 +237,7 @@ class ServerCapabilities /** * The server provides inline values. * - * @var bool|mixed|mixed|null + * @var bool|WorkDoneProgressOptions|InlineValueRegistrationOptions|null */ public $inlineValueProvider; @@ -300,7 +300,7 @@ class ServerCapabilities * @param mixed|mixed|null $semanticTokensProvider * @param bool|mixed|mixed|null $monikerProvider * @param bool|mixed|mixed|null $typeHierarchyProvider - * @param bool|mixed|mixed|null $inlineValueProvider + * @param bool|WorkDoneProgressOptions|InlineValueRegistrationOptions|null $inlineValueProvider * @param bool|InlayHintOptions|InlayHintRegistrationOptions|null $inlayHintProvider * @param mixed|mixed|null $diagnosticProvider * @param array{workspaceFolders:WorkspaceFoldersServerCapabilities,fileOperations:FileOperationOptions}|null $workspace @@ -382,7 +382,7 @@ public static function fromArray(array $array, bool $allowUnknownKeys = false) 'semanticTokensProvider' => ['names' => [], 'iterable' => false], 'monikerProvider' => ['names' => [], 'iterable' => false], 'typeHierarchyProvider' => ['names' => [], 'iterable' => false], - 'inlineValueProvider' => ['names' => [], 'iterable' => false], + 'inlineValueProvider' => ['names' => [InlineValueRegistrationOptions::class], 'iterable' => false], 'inlayHintProvider' => ['names' => [InlayHintOptions::class, InlayHintRegistrationOptions::class], 'iterable' => false], 'diagnosticProvider' => ['names' => [], 'iterable' => false], 'workspace' => ['names' => [], 'iterable' => false], diff --git a/src/TextDocumentClientCapabilities.php b/src/TextDocumentClientCapabilities.php index 71adfe6..2683f38 100644 --- a/src/TextDocumentClientCapabilities.php +++ b/src/TextDocumentClientCapabilities.php @@ -204,7 +204,7 @@ class TextDocumentClientCapabilities /** * Capabilities specific to the `textDocument/inlineValue` request. * - * @var mixed|null + * @var array{dynamicRegistration:bool}|null */ public $inlineValue; @@ -250,11 +250,11 @@ class TextDocumentClientCapabilities * @param mixed|null $linkedEditingRange * @param mixed|null $moniker * @param mixed|null $typeHierarchy - * @param mixed|null $inlineValue + * @param array{dynamicRegistration:bool}|null $inlineValue * @param array{dynamicRegistration:bool,resolveSupport:array{properties:array}}|null $inlayHint * @param mixed|null $diagnostic */ - public function __construct(?TextDocumentSyncClientCapabilities $synchronization = null, ?CompletionClientCapabilities $completion = null, ?HoverClientCapabilities $hover = null, ?SignatureHelpClientCapabilities $signatureHelp = null, ?DeclarationClientCapabilities $declaration = null, ?DefinitionClientCapabilities $definition = null, ?TypeDefinitionClientCapabilities $typeDefinition = null, ?ImplementationClientCapabilities $implementation = null, ?ReferenceClientCapabilities $references = null, ?DocumentHighlightClientCapabilities $documentHighlight = null, ?DocumentSymbolClientCapabilities $documentSymbol = null, ?CodeActionClientCapabilities $codeAction = null, ?CodeLensClientCapabilities $codeLens = null, ?DocumentLinkClientCapabilities $documentLink = null, ?DocumentColorClientCapabilities $colorProvider = null, ?DocumentFormattingClientCapabilities $formatting = null, ?DocumentRangeFormattingClientCapabilities $rangeFormatting = null, ?DocumentOnTypeFormattingClientCapabilities $onTypeFormatting = null, ?RenameClientCapabilities $rename = null, ?FoldingRangeClientCapabilities $foldingRange = null, ?SelectionRangeClientCapabilities $selectionRange = null, ?PublishDiagnosticsClientCapabilities $publishDiagnostics = null, $callHierarchy = null, $semanticTokens = null, $linkedEditingRange = null, $moniker = null, $typeHierarchy = null, $inlineValue = null, ?array $inlayHint = null, $diagnostic = null) + public function __construct(?TextDocumentSyncClientCapabilities $synchronization = null, ?CompletionClientCapabilities $completion = null, ?HoverClientCapabilities $hover = null, ?SignatureHelpClientCapabilities $signatureHelp = null, ?DeclarationClientCapabilities $declaration = null, ?DefinitionClientCapabilities $definition = null, ?TypeDefinitionClientCapabilities $typeDefinition = null, ?ImplementationClientCapabilities $implementation = null, ?ReferenceClientCapabilities $references = null, ?DocumentHighlightClientCapabilities $documentHighlight = null, ?DocumentSymbolClientCapabilities $documentSymbol = null, ?CodeActionClientCapabilities $codeAction = null, ?CodeLensClientCapabilities $codeLens = null, ?DocumentLinkClientCapabilities $documentLink = null, ?DocumentColorClientCapabilities $colorProvider = null, ?DocumentFormattingClientCapabilities $formatting = null, ?DocumentRangeFormattingClientCapabilities $rangeFormatting = null, ?DocumentOnTypeFormattingClientCapabilities $onTypeFormatting = null, ?RenameClientCapabilities $rename = null, ?FoldingRangeClientCapabilities $foldingRange = null, ?SelectionRangeClientCapabilities $selectionRange = null, ?PublishDiagnosticsClientCapabilities $publishDiagnostics = null, $callHierarchy = null, $semanticTokens = null, $linkedEditingRange = null, $moniker = null, $typeHierarchy = null, ?array $inlineValue = null, ?array $inlayHint = null, $diagnostic = null) { $this->synchronization = $synchronization; $this->completion = $completion; diff --git a/src/WorkspaceClientCapabilities.php b/src/WorkspaceClientCapabilities.php index 0620dc6..229cd04 100644 --- a/src/WorkspaceClientCapabilities.php +++ b/src/WorkspaceClientCapabilities.php @@ -98,7 +98,7 @@ class WorkspaceClientCapabilities * Capabilities specific to the inline values requests scoped to the * workspace. * - * @var mixed|null + * @var array{refreshSupport:bool}|null */ public $inlineValue; @@ -130,11 +130,11 @@ class WorkspaceClientCapabilities * @param mixed|null $semanticTokens * @param CodeLensWorkspaceClientCapabilities|null $codeLens * @param FileOperationClientCapabilities|null $fileOperations - * @param mixed|null $inlineValue + * @param array{refreshSupport:bool}|null $inlineValue * @param array{refreshSupport:bool}|null $inlayHint * @param mixed|null $diagnostics */ - public function __construct(?bool $applyEdit = null, ?WorkspaceEditClientCapabilities $workspaceEdit = null, ?DidChangeConfigurationClientCapabilities $didChangeConfiguration = null, ?DidChangeWatchedFilesClientCapabilities $didChangeWatchedFiles = null, ?WorkspaceSymbolClientCapabilities $symbol = null, ?ExecuteCommandClientCapabilities $executeCommand = null, ?bool $workspaceFolders = null, ?bool $configuration = null, $semanticTokens = null, ?CodeLensWorkspaceClientCapabilities $codeLens = null, ?FileOperationClientCapabilities $fileOperations = null, $inlineValue = null, ?array $inlayHint = null, $diagnostics = null) + public function __construct(?bool $applyEdit = null, ?WorkspaceEditClientCapabilities $workspaceEdit = null, ?DidChangeConfigurationClientCapabilities $didChangeConfiguration = null, ?DidChangeWatchedFilesClientCapabilities $didChangeWatchedFiles = null, ?WorkspaceSymbolClientCapabilities $symbol = null, ?ExecuteCommandClientCapabilities $executeCommand = null, ?bool $workspaceFolders = null, ?bool $configuration = null, $semanticTokens = null, ?CodeLensWorkspaceClientCapabilities $codeLens = null, ?FileOperationClientCapabilities $fileOperations = null, ?array $inlineValue = null, ?array $inlayHint = null, $diagnostics = null) { $this->applyEdit = $applyEdit; $this->workspaceEdit = $workspaceEdit; diff --git a/ts/nodeMap.ts b/ts/nodeMap.ts index 181e5a0..67b4685 100644 --- a/ts/nodeMap.ts +++ b/ts/nodeMap.ts @@ -58,7 +58,7 @@ export function createNodeMap(nodes: Node[], filter: RegExp = null): NodeMap { return; } - if (node.name.escapedText.toString() === 'InlayHint') { + if (['InlayHint', 'InlineValueText', 'InlineValueVariableLookup', 'InlineValueEvaluatableExpression'].includes(node.name.escapedText.toString())) { if (isTypeLiteralNode(node.type)) { map.typeLiterals.set(node.name.escapedText.toString(), node.type); } diff --git a/ts/phpClass.ts b/ts/phpClass.ts index eac5cfd..7aaa1f8 100644 --- a/ts/phpClass.ts +++ b/ts/phpClass.ts @@ -13,6 +13,7 @@ import { isModuleBlock, isVariableDeclarationList, isVariableDeclaration, + isTypeLiteralNode, isLiteralTypeNode, isTypeNode, forEachChild, @@ -178,6 +179,12 @@ export class PhpClassResolver { const phpClass = new PhpClass(name); type.types.forEach((type: TypeNode) => { + if (isTypeLiteralNode(type)) { + let properties = phpClass.properties; + properties = new Map([...properties, ... this.mapProperties(type.members)]); + phpClass.properties = properties; + return; + } phpClass.mixins.push(this.typeConverter.phpType(type).real); }); diff --git a/ts/transpile.ts b/ts/transpile.ts index 7164084..14a0a20 100644 --- a/ts/transpile.ts +++ b/ts/transpile.ts @@ -21,6 +21,7 @@ const paths: string[] = [ path.resolve(__dirname, '..', 'node_modules', 'vscode-languageserver-protocol', 'lib', 'common', 'protocol.implementation.d.ts'), path.resolve(__dirname, '..', 'node_modules', 'vscode-languageserver-protocol', 'lib', 'common', 'protocol.selectionRange.d.ts'), path.resolve(__dirname, '..', 'node_modules', 'vscode-languageserver-protocol', 'lib', 'common', 'protocol.inlayHint.d.ts'), + path.resolve(__dirname, '..', 'node_modules', 'vscode-languageserver-protocol', 'lib', 'common', 'protocol.inlineValue.d.ts'), path.resolve(__dirname, '..', 'node_modules', 'vscode-languageserver-types', 'lib', 'umd', 'main.d.ts'), path.resolve(__dirname, '..', 'node_modules', 'vscode-languageserver-types', 'lib', 'esm', 'main.d.ts'), path.resolve(__dirname, '../ts/stubs.ts'),