From 0f3e397676fa2c7ed48f5ea1d639082284fd2a16 Mon Sep 17 00:00:00 2001 From: Bela VanderVoort Date: Sun, 3 Sep 2023 13:02:29 -0500 Subject: [PATCH] POC for grpc --- Directory.Packages.props | 3 + .../CSharpier.Cli.Tests.csproj | 12 +- Src/CSharpier.Cli.Tests/CliTests.cs | 52 -- Src/CSharpier.Cli.Tests/CsharpierProcess.cs | 59 ++ Src/CSharpier.Cli.Tests/GrpcTests.cs | 47 ++ Src/CSharpier.Cli/CSharpier.Cli.csproj | 7 + Src/CSharpier.Cli/CommandLineOptions.cs | 12 +- Src/CSharpier.Cli/PipingFormatter.cs | 100 ++++ Src/CSharpier.Cli/Program.cs | 106 +--- Src/CSharpier.Cli/ProtoFormatter.cs | 50 ++ Src/CSharpier.Cli/protos/contract.proto | 21 + Src/CSharpier.VSCode/package-lock.json | 544 ++++++++++++++++++ Src/CSharpier.VSCode/package.json | 3 + .../src/CSharpierProcessProto.ts | 90 +++ .../src/CSharpierProcessProvider.ts | 4 + .../src/proto/csharpier.proto | 21 + Src/CSharpier.VSCode/src/proto/csharpier.ts | 21 + .../src/proto/proto/CSharpierService.ts | 68 +++ .../src/proto/proto/FormatFileDto.ts | 11 + .../src/proto/proto/FormatFileResult.ts | 9 + 20 files changed, 1087 insertions(+), 153 deletions(-) create mode 100644 Src/CSharpier.Cli.Tests/CsharpierProcess.cs create mode 100644 Src/CSharpier.Cli.Tests/GrpcTests.cs create mode 100644 Src/CSharpier.Cli/PipingFormatter.cs create mode 100644 Src/CSharpier.Cli/ProtoFormatter.cs create mode 100644 Src/CSharpier.Cli/protos/contract.proto create mode 100644 Src/CSharpier.VSCode/src/CSharpierProcessProto.ts create mode 100644 Src/CSharpier.VSCode/src/proto/csharpier.proto create mode 100644 Src/CSharpier.VSCode/src/proto/csharpier.ts create mode 100644 Src/CSharpier.VSCode/src/proto/proto/CSharpierService.ts create mode 100644 Src/CSharpier.VSCode/src/proto/proto/FormatFileDto.ts create mode 100644 Src/CSharpier.VSCode/src/proto/proto/FormatFileResult.ts diff --git a/Directory.Packages.props b/Directory.Packages.props index 37383771f..63d5c6620 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -10,6 +10,9 @@ + + + diff --git a/Src/CSharpier.Cli.Tests/CSharpier.Cli.Tests.csproj b/Src/CSharpier.Cli.Tests/CSharpier.Cli.Tests.csproj index 8126a8cce..ad8e6ecc2 100644 --- a/Src/CSharpier.Cli.Tests/CSharpier.Cli.Tests.csproj +++ b/Src/CSharpier.Cli.Tests/CSharpier.Cli.Tests.csproj @@ -5,14 +5,14 @@ True - - + + - - - + + + - + diff --git a/Src/CSharpier.Cli.Tests/CliTests.cs b/Src/CSharpier.Cli.Tests/CliTests.cs index 40761786e..d248f08c0 100644 --- a/Src/CSharpier.Cli.Tests/CliTests.cs +++ b/Src/CSharpier.Cli.Tests/CliTests.cs @@ -1,10 +1,7 @@ using System; using System.IO; -using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; -using CliWrap; -using CliWrap.Buffered; using FluentAssertions; using NUnit.Framework; @@ -491,53 +488,4 @@ private void EnsureExists(DirectoryInfo directoryInfo) directoryInfo.Create(); } } - - private class CsharpierProcess - { - private readonly StringBuilder output = new(); - private readonly StringBuilder errorOutput = new(); - private Command command; - - private readonly Encoding encoding = Encoding.UTF8; - - public CsharpierProcess() - { - var path = Path.Combine(Directory.GetCurrentDirectory(), "dotnet-csharpier.dll"); - - this.command = CliWrap.Cli - .Wrap("dotnet") - .WithArguments(path) - .WithWorkingDirectory(testFileDirectory) - .WithValidation(CommandResultValidation.None) - .WithStandardOutputPipe(PipeTarget.ToStringBuilder(this.output, this.encoding)) - .WithStandardErrorPipe(PipeTarget.ToStringBuilder(this.errorOutput, this.encoding)); - } - - public CsharpierProcess WithArguments(string arguments) - { - this.command = this.command.WithArguments(this.command.Arguments + " " + arguments); - return this; - } - - public CsharpierProcess WithPipedInput(string input) - { - this.command = this.command.WithStandardInputPipe( - PipeSource.FromString(input, this.encoding) - ); - - return this; - } - - public async Task ExecuteAsync() - { - var result = await this.command.ExecuteBufferedAsync(this.encoding); - return new ProcessResult( - this.output.ToString(), - this.errorOutput.ToString(), - result.ExitCode - ); - } - - public record ProcessResult(string Output, string ErrorOutput, int ExitCode); - } } diff --git a/Src/CSharpier.Cli.Tests/CsharpierProcess.cs b/Src/CSharpier.Cli.Tests/CsharpierProcess.cs new file mode 100644 index 000000000..a0af4b9c0 --- /dev/null +++ b/Src/CSharpier.Cli.Tests/CsharpierProcess.cs @@ -0,0 +1,59 @@ +namespace CSharpier.Cli.Tests; + +using System.Text; +using CliWrap; +using CliWrap.Buffered; + +public class CsharpierProcess +{ + private static readonly string testFileDirectory = Path.Combine( + Directory.GetCurrentDirectory(), + "TestFiles" + ); + + private readonly StringBuilder output = new(); + private readonly StringBuilder errorOutput = new(); + private Command command; + + private readonly Encoding encoding = Encoding.UTF8; + + public CsharpierProcess() + { + var path = Path.Combine(Directory.GetCurrentDirectory(), "dotnet-csharpier.dll"); + + this.command = Cli + .Wrap("dotnet") + .WithArguments(path) + .WithWorkingDirectory(testFileDirectory) + .WithValidation(CommandResultValidation.None) + .WithStandardOutputPipe(PipeTarget.ToStringBuilder(this.output, this.encoding)) + .WithStandardErrorPipe(PipeTarget.ToStringBuilder(this.errorOutput, this.encoding)); + } + + public CsharpierProcess WithArguments(string arguments) + { + this.command = this.command.WithArguments(this.command.Arguments + " " + arguments); + return this; + } + + public CsharpierProcess WithPipedInput(string input) + { + this.command = this.command.WithStandardInputPipe( + PipeSource.FromString(input, this.encoding) + ); + + return this; + } + + public async Task ExecuteAsync() + { + var result = await this.command.ExecuteBufferedAsync(this.encoding); + return new ProcessResult( + this.output.ToString(), + this.errorOutput.ToString(), + result.ExitCode + ); + } + + public record ProcessResult(string Output, string ErrorOutput, int ExitCode); +} diff --git a/Src/CSharpier.Cli.Tests/GrpcTests.cs b/Src/CSharpier.Cli.Tests/GrpcTests.cs new file mode 100644 index 000000000..34840da3e --- /dev/null +++ b/Src/CSharpier.Cli.Tests/GrpcTests.cs @@ -0,0 +1,47 @@ +namespace CSharpier.Cli.Tests; + +using System.Diagnostics; +using System.Text; +using CSharpierService.Generated; +using FluentAssertions; +using Grpc.Core; +using NUnit.Framework; + +[TestFixture] +public class GrpcTests +{ + // can this used named pipes instead of ports? + // may not be happy in VSCode, see this, and try getting it working in js + // https://gist.github.com/badsyntax/9827722afcb33a4b0e03c809f1aede98 + // also make sure it will work in java + [Test] + public async Task Stuff() + { + var path = Path.Combine(Directory.GetCurrentDirectory(), "dotnet-csharpier.dll"); + + var processStartInfo = new ProcessStartInfo("dotnet", $"{path} --named-pipe") + { + RedirectStandardInput = true, + RedirectStandardOutput = true, + RedirectStandardError = true, + StandardOutputEncoding = Encoding.UTF8, + StandardErrorEncoding = Encoding.UTF8, + UseShellExecute = false, + CreateNoWindow = true + }; + + processStartInfo.EnvironmentVariables["DOTNET_NOLOGO"] = "1"; + var process = new Process { StartInfo = processStartInfo }; + process.Start(); + + var output = await process.StandardOutput.ReadLineAsync(); + + var channel = new Channel("localhost", 50052, ChannelCredentials.Insecure); + var client = new CSharpierService.CSharpierServiceClient(channel); + + var data = new FormatFileDto { FileName = "test.cs", FileContents = "public class TestClass { }"}; + var result = await client.FormatFileAsync(data); + + result.FormattedFile.Should().Be("public class TestClass { }"); + } +} diff --git a/Src/CSharpier.Cli/CSharpier.Cli.csproj b/Src/CSharpier.Cli/CSharpier.Cli.csproj index 485396140..7d552e412 100644 --- a/Src/CSharpier.Cli/CSharpier.Cli.csproj +++ b/Src/CSharpier.Cli/CSharpier.Cli.csproj @@ -12,6 +12,12 @@ + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + @@ -31,6 +37,7 @@ + logo.png diff --git a/Src/CSharpier.Cli/CommandLineOptions.cs b/Src/CSharpier.Cli/CommandLineOptions.cs index 03e2cd242..65e45c012 100644 --- a/Src/CSharpier.Cli/CommandLineOptions.cs +++ b/Src/CSharpier.Cli/CommandLineOptions.cs @@ -25,6 +25,7 @@ internal delegate Task Handler( bool skipWrite, bool writeStdout, bool pipeMultipleFiles, + bool namedPipe, bool noCache, bool noMSBuildCheck, string config, @@ -75,6 +76,11 @@ public static RootCommand Create() new[] { "--pipe-multiple-files" }, "Keep csharpier running so that multiples files can be piped to it via stdin" ), + // TODO this needs a proper name + new Option( + new[] { "--named-pipe" }, + "Keep csharpier running so that multiples files can be piped to it via stdin" + ), new Option( new[] { "--config-path" }, "Path to the CSharpier configuration file" @@ -87,7 +93,11 @@ public static RootCommand Create() { return "--pipe-multiple-files may only be used if you pipe stdin to CSharpier"; } - if (!Console.IsInputRedirected && !cmd.Children.Contains("directoryOrFile")) + if ( + !Console.IsInputRedirected + && !cmd.Children.Contains("directoryOrFile") + && !cmd.Children.Contains("--named-pipe") + ) { return "directoryOrFile is required when not piping stdin to CSharpier"; } diff --git a/Src/CSharpier.Cli/PipingFormatter.cs b/Src/CSharpier.Cli/PipingFormatter.cs new file mode 100644 index 000000000..d29b41d89 --- /dev/null +++ b/Src/CSharpier.Cli/PipingFormatter.cs @@ -0,0 +1,100 @@ +namespace CSharpier.Cli; + +using System.IO.Abstractions; +using System.Text; +using Microsoft.Extensions.Logging; + +public class PipingFormatter +{ + public static async Task PipeMultipleFiles( + SystemConsole console, + ILogger logger, + string? configPath, + CancellationToken cancellationToken + ) + { + using var streamReader = new StreamReader( + Console.OpenStandardInput(), + console.InputEncoding + ); + + var stringBuilder = new StringBuilder(); + string? fileName = null; + + var exitCode = 0; + + while (true) + { + while (true) + { + var value = streamReader.Read(); + if (value == -1) + { + return exitCode; + } + var character = Convert.ToChar(value); + DebugLogger.Log("Got " + character); + if (character == '\u0003') + { + DebugLogger.Log("Got EOF"); + break; + } + + stringBuilder.Append(character); + } + + if (fileName == null) + { + fileName = stringBuilder.ToString(); + stringBuilder.Clear(); + } + else + { + var commandLineOptions = new CommandLineOptions + { + DirectoryOrFilePaths = new[] + { + Path.Combine(Directory.GetCurrentDirectory(), fileName) + }, + OriginalDirectoryOrFilePaths = new[] + { + Path.IsPathRooted(fileName) + ? fileName + : fileName.StartsWith(".") + ? fileName + : "./" + fileName + }, + StandardInFileContents = stringBuilder.ToString(), + Fast = true, + WriteStdout = true, + ConfigPath = configPath + }; + + try + { + var result = await CommandLineFormatter.Format( + commandLineOptions, + new FileSystem(), + console, + logger, + cancellationToken + ); + + console.Write('\u0003'.ToString()); + + if (result != 0) + { + exitCode = result; + } + } + catch (Exception ex) + { + logger.LogError(ex, "Failed!"); + } + + stringBuilder.Clear(); + fileName = null; + } + } + } +} \ No newline at end of file diff --git a/Src/CSharpier.Cli/Program.cs b/Src/CSharpier.Cli/Program.cs index 517d7d29a..f2f9388c4 100644 --- a/Src/CSharpier.Cli/Program.cs +++ b/Src/CSharpier.Cli/Program.cs @@ -18,6 +18,8 @@ public static async Task Main(string[] args) return await rootCommand.InvokeAsync(args); } + // TODO at some point (1.0?) the options should be cleaned up + // and use sub commands public static async Task Run( string[]? directoryOrFile, bool check, @@ -25,6 +27,7 @@ public static async Task Run( bool skipWrite, bool writeStdout, bool pipeMultipleFiles, + bool namedPipe, bool noCache, bool noMSBuildCheck, string configPath, @@ -40,7 +43,12 @@ CancellationToken cancellationToken if (pipeMultipleFiles) { - return await PipeMultipleFiles(console, logger, actualConfigPath, cancellationToken); + return await PipingFormatter.PipeMultipleFiles(console, logger, actualConfigPath, cancellationToken); + } + + if (namedPipe) + { + return await ProtoFormatter.Pipe(console, logger, actualConfigPath, cancellationToken); } var directoryOrFileNotProvided = directoryOrFile is null or { Length: 0 }; @@ -53,7 +61,7 @@ CancellationToken cancellationToken Console.OpenStandardInput(), console.InputEncoding ); - standardInFileContents = await streamReader.ReadToEndAsync(); + standardInFileContents = await streamReader.ReadToEndAsync(cancellationToken); directoryOrFile = new[] { Directory.GetCurrentDirectory() }; originalDirectoryOrFile = new[] { Directory.GetCurrentDirectory() }; @@ -73,7 +81,7 @@ CancellationToken cancellationToken var commandLineOptions = new CommandLineOptions { - DirectoryOrFilePaths = directoryOrFile!.ToArray(), + DirectoryOrFilePaths = directoryOrFile.ToArray(), OriginalDirectoryOrFilePaths = originalDirectoryOrFile!, StandardInFileContents = standardInFileContents, Check = check, @@ -93,94 +101,4 @@ CancellationToken cancellationToken cancellationToken ); } - - private static async Task PipeMultipleFiles( - SystemConsole console, - ILogger logger, - string? configPath, - CancellationToken cancellationToken - ) - { - using var streamReader = new StreamReader( - Console.OpenStandardInput(), - console.InputEncoding - ); - - var stringBuilder = new StringBuilder(); - string? fileName = null; - - var exitCode = 0; - - while (true) - { - while (true) - { - var value = streamReader.Read(); - if (value == -1) - { - return exitCode; - } - var character = Convert.ToChar(value); - if (character == '\u0003') - { - break; - } - - stringBuilder.Append(character); - } - - if (fileName == null) - { - fileName = stringBuilder.ToString(); - stringBuilder.Clear(); - } - else - { - var commandLineOptions = new CommandLineOptions - { - DirectoryOrFilePaths = new[] - { - Path.Combine(Directory.GetCurrentDirectory(), fileName) - }, - OriginalDirectoryOrFilePaths = new[] - { - Path.IsPathRooted(fileName) - ? fileName - : fileName.StartsWith(".") - ? fileName - : "./" + fileName - }, - StandardInFileContents = stringBuilder.ToString(), - Fast = true, - WriteStdout = true, - ConfigPath = configPath - }; - - try - { - var result = await CommandLineFormatter.Format( - commandLineOptions, - new FileSystem(), - console, - logger, - cancellationToken - ); - - console.Write('\u0003'.ToString()); - - if (result != 0) - { - exitCode = result; - } - } - catch (Exception ex) - { - logger.LogError(ex, "Failed!"); - } - - stringBuilder.Clear(); - fileName = null; - } - } - } -} +} \ No newline at end of file diff --git a/Src/CSharpier.Cli/ProtoFormatter.cs b/Src/CSharpier.Cli/ProtoFormatter.cs new file mode 100644 index 000000000..dc5ff3638 --- /dev/null +++ b/Src/CSharpier.Cli/ProtoFormatter.cs @@ -0,0 +1,50 @@ +using Grpc.Core; + +namespace CSharpier.Cli; + +using System.IO.Abstractions; +using CSharpierService.Generated; +using Microsoft.Extensions.Logging; + +public static class ProtoFormatter +{ + public static Task Pipe( + SystemConsole console, + ConsoleLogger logger, + string? actualConfigPath, + CancellationToken cancellationToken + ) + { + // TODO what about properly shutting this down? it seems to happen when the process is killed + var server = new Server + { + Services = { CSharpierService.BindService(new CSharpierServiceImplementation()) }, + // TODO try out named pipes and be sure to test in linux + Ports = { new ServerPort("localhost", 50052, ServerCredentials.Insecure) } + }; + server.Start(); + + logger.LogInformation("Started!!"); + Console.ReadKey(); + + return Task.FromResult(0); + } +} + +public class CSharpierServiceImplementation : CSharpierService.CSharpierServiceBase +{ + public async override Task FormatFile( + FormatFileDto formatFileDto, + ServerCallContext context + ) + { + // TODO what about config file and what not? + // should this be calling the command line formatter? that thing probably does too much at this point + // maybe finding config files should be split out from that + var result = await CodeFormatter.FormatAsync(formatFileDto.FileContents); + + // TODO what about checking if this actually formatted? + // could send back any error messages now + return new FormatFileResult { FormattedFile = result.Code }; + } +} diff --git a/Src/CSharpier.Cli/protos/contract.proto b/Src/CSharpier.Cli/protos/contract.proto new file mode 100644 index 000000000..ddfc449cc --- /dev/null +++ b/Src/CSharpier.Cli/protos/contract.proto @@ -0,0 +1,21 @@ +syntax = "proto3"; + +option csharp_namespace = "CSharpierService.Generated"; + +package proto; + +service CSharpierService +{ + rpc FormatFile(FormatFileDto) returns (FormatFileResult) {} +} + +message FormatFileDto +{ + string FileContents = 1; + string FileName = 2; +} + +message FormatFileResult +{ + string FormattedFile = 1; +} \ No newline at end of file diff --git a/Src/CSharpier.VSCode/package-lock.json b/Src/CSharpier.VSCode/package-lock.json index 0698278ae..1cb57c5bf 100644 --- a/Src/CSharpier.VSCode/package-lock.json +++ b/Src/CSharpier.VSCode/package-lock.json @@ -9,6 +9,8 @@ "version": "1.3.6", "license": "MIT", "devDependencies": { + "@grpc/grpc-js": "^1.9.1", + "@grpc/proto-loader": "^0.7.9", "@types/glob": "7.1.4", "@types/mocha": "9.0.0", "@types/node": "14.x", @@ -37,6 +39,37 @@ "node": ">=10.0.0" } }, + "node_modules/@grpc/grpc-js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.9.1.tgz", + "integrity": "sha512-AvDEPQT4teS+J8++cTE5tku4rYCwpPwPguESJUummLs/Ug/O5Bouofnc1mxaDORmwA9QkrJ+PfRQ1Qs7adQgJg==", + "dev": true, + "dependencies": { + "@grpc/proto-loader": "^0.7.8", + "@types/node": ">=12.12.47" + }, + "engines": { + "node": "^8.13.0 || >=10.10.0" + } + }, + "node_modules/@grpc/proto-loader": { + "version": "0.7.9", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.9.tgz", + "integrity": "sha512-YJsOehVXzgurc+lLAxYnlSMc1p/Gu6VAvnfx0ATi2nzvr0YZcjhmZDeY8SeAKv1M7zE3aEJH0Xo9mK1iZ8GYoQ==", + "dev": true, + "dependencies": { + "lodash.camelcase": "^4.3.0", + "long": "^5.0.0", + "protobufjs": "^7.2.4", + "yargs": "^17.7.2" + }, + "bin": { + "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", @@ -95,6 +128,70 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", + "dev": true + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", + "dev": true + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", + "dev": true + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==", + "dev": true + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "dev": true, + "dependencies": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", + "dev": true + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==", + "dev": true + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", + "dev": true + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", + "dev": true + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", + "dev": true + }, "node_modules/@types/eslint": { "version": "8.2.0", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.2.0.tgz", @@ -407,6 +504,15 @@ "ajv": "^6.9.1" } }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", @@ -708,6 +814,20 @@ "node": ">=6.0" } }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/clone-deep": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", @@ -891,6 +1011,12 @@ "integrity": "sha512-YKaB+t8ul5crdh6OeqT2qXdxJGI0fAYb6/X8pDIyye+c3a7ndOCk5gVeKX+ABwivCGNS56vOAif3TN0qJMpEHw==", "dev": true }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, "node_modules/end-of-stream": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", @@ -1102,6 +1228,15 @@ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", "dev": true }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, "node_modules/get-intrinsic": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", @@ -1318,6 +1453,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -1439,6 +1583,18 @@ "node": ">=6.11.5" } }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", + "dev": true + }, + "node_modules/long": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", + "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==", + "dev": true + }, "node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -1892,6 +2048,30 @@ "node": ">=10.13.0" } }, + "node_modules/protobufjs": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.5.tgz", + "integrity": "sha512-gGXRSXvxQ7UiPgfw8gevrfRWcTlSbOFg+p/N+JVJEK5VhueL2miT6qTymqAmjr1Q5WbOCyJbyrk6JfWKwlFn6A==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", @@ -1988,6 +2168,15 @@ "node": ">= 0.10" } }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/resolve": { "version": "1.20.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", @@ -2231,6 +2420,32 @@ "safe-buffer": "~5.2.0" } }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-final-newline": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", @@ -2717,6 +2932,56 @@ "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==", "dev": true }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -2757,12 +3022,48 @@ "node": ">=4.0" } }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, "node_modules/yauzl": { "version": "2.10.0", "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", @@ -2790,6 +3091,28 @@ "integrity": "sha512-6nFkfkmSeV/rqSaS4oWHgmpnYw194f6hmWF5is6b0J1naJZoiD0NTc9AiUwPHvWsowkjuHErCZT1wa0jg+BLIA==", "dev": true }, + "@grpc/grpc-js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.9.1.tgz", + "integrity": "sha512-AvDEPQT4teS+J8++cTE5tku4rYCwpPwPguESJUummLs/Ug/O5Bouofnc1mxaDORmwA9QkrJ+PfRQ1Qs7adQgJg==", + "dev": true, + "requires": { + "@grpc/proto-loader": "^0.7.8", + "@types/node": ">=12.12.47" + } + }, + "@grpc/proto-loader": { + "version": "0.7.9", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.9.tgz", + "integrity": "sha512-YJsOehVXzgurc+lLAxYnlSMc1p/Gu6VAvnfx0ATi2nzvr0YZcjhmZDeY8SeAKv1M7zE3aEJH0Xo9mK1iZ8GYoQ==", + "dev": true, + "requires": { + "lodash.camelcase": "^4.3.0", + "long": "^5.0.0", + "protobufjs": "^7.2.4", + "yargs": "^17.7.2" + } + }, "@jridgewell/gen-mapping": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", @@ -2839,6 +3162,70 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", + "dev": true + }, + "@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", + "dev": true + }, + "@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", + "dev": true + }, + "@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==", + "dev": true + }, + "@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "dev": true, + "requires": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", + "dev": true + }, + "@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==", + "dev": true + }, + "@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", + "dev": true + }, + "@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", + "dev": true + }, + "@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", + "dev": true + }, "@types/eslint": { "version": "8.2.0", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.2.0.tgz", @@ -3124,6 +3511,12 @@ "dev": true, "requires": {} }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, "ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", @@ -3340,6 +3733,17 @@ "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", "dev": true }, + "cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + } + }, "clone-deep": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", @@ -3478,6 +3882,12 @@ "integrity": "sha512-YKaB+t8ul5crdh6OeqT2qXdxJGI0fAYb6/X8pDIyye+c3a7ndOCk5gVeKX+ABwivCGNS56vOAif3TN0qJMpEHw==", "dev": true }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, "end-of-stream": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", @@ -3643,6 +4053,12 @@ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", "dev": true }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, "get-intrinsic": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", @@ -3793,6 +4209,12 @@ "has": "^1.0.3" } }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, "is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -3886,6 +4308,18 @@ "integrity": "sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw==", "dev": true }, + "lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", + "dev": true + }, + "long": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", + "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==", + "dev": true + }, "lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -4231,6 +4665,26 @@ "integrity": "sha512-9fbDAXSBcc6Bs1mZrDYb3XKzDLm4EXXL9sC1LqKP5rZkT6KRr/rf9amVUcODVXgguK/isJz0d0hP72WeaKWsvA==", "dev": true }, + "protobufjs": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.5.tgz", + "integrity": "sha512-gGXRSXvxQ7UiPgfw8gevrfRWcTlSbOFg+p/N+JVJEK5VhueL2miT6qTymqAmjr1Q5WbOCyJbyrk6JfWKwlFn6A==", + "dev": true, + "requires": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + } + }, "pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", @@ -4306,6 +4760,12 @@ "resolve": "^1.9.0" } }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true + }, "resolve": { "version": "1.20.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", @@ -4464,6 +4924,26 @@ "safe-buffer": "~5.2.0" } }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, "strip-final-newline": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", @@ -4805,6 +5285,43 @@ "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==", "dev": true }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + } + } + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -4836,12 +5353,39 @@ "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", "dev": true }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true + }, "yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, + "yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "requires": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + } + }, + "yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true + }, "yauzl": { "version": "2.10.0", "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", diff --git a/Src/CSharpier.VSCode/package.json b/Src/CSharpier.VSCode/package.json index 146436931..4b1be1a89 100644 --- a/Src/CSharpier.VSCode/package.json +++ b/Src/CSharpier.VSCode/package.json @@ -56,11 +56,14 @@ "vscode:prepublish": "npm run build", "actualBuild": "webpack --env NODE_ENV=production", "build": "rimraf build && npm run actualBuild", + "build:proto": "proto-loader-gen-types --longs=String --enums=String --defaults --oneofs --grpcLib=@grpc/grpc-js --outDir=proto/ proto/csharpier.proto", "start": "rimraf build && webpack --env NODE_ENV=development --watch", "prettier": "prettier ./**/*.{ts,js} --write", "vsix": "vsce package" }, "devDependencies": { + "@grpc/grpc-js": "^1.9.1", + "@grpc/proto-loader": "^0.7.9", "@types/glob": "7.1.4", "@types/mocha": "9.0.0", "@types/node": "14.x", diff --git a/Src/CSharpier.VSCode/src/CSharpierProcessProto.ts b/Src/CSharpier.VSCode/src/CSharpierProcessProto.ts new file mode 100644 index 000000000..15150ca52 --- /dev/null +++ b/Src/CSharpier.VSCode/src/CSharpierProcessProto.ts @@ -0,0 +1,90 @@ +import { ChildProcessWithoutNullStreams, spawn } from "child_process"; +import { Logger } from "./Logger"; +import { ICSharpierProcess } from "./CSharpierProcess"; +import { ProtoGrpcType } from "./proto/csharpier"; +import * as grpc from "@grpc/grpc-js"; +import * as protoLoader from "@grpc/proto-loader"; +import { FormatFileResult } from "./proto/proto/FormatFileResult"; +import * as vscode from "vscode"; +import { TaskDefinition, TaskRevealKind } from "vscode"; +import { CSharpierServiceClient } from "./proto/proto/CSharpierService"; + +export class CSharpierProcessProto implements ICSharpierProcess { + private logger: Logger; + private client: CSharpierServiceClient; + + constructor(logger: Logger, csharpierPath: string, workingDirectory: string) { + this.logger = logger; + + const definition: TaskDefinition = { + type: "string", + }; + + let task = new vscode.Task( + definition, + vscode.TaskScope.Workspace, + "csharpier", + "csharpier", + // TODO use proper path + new vscode.ProcessExecution( + "C:\\projects\\csharpier\\Src\\CSharpier.Cli\\bin\\Debug\\net7.0\\dotnet-csharpier.exe", + ["--named-pipe"], + { + cwd: workingDirectory, + env: { ...process.env, DOTNET_NOLOGO: "1" }, + }, + ), + ); + + task.presentationOptions.reveal = TaskRevealKind.Never; + + vscode.tasks.executeTask(task); + + const host = "0.0.0.0:50052"; + // TODO how do we get this into the build dir? do we need webpack to understand it? + // TODO i had to copy it there after npm run start, otherwise webpack kills it off + const packageDefinition = protoLoader.loadSync(__dirname + "/proto/csharpier.proto"); + const proto = grpc.loadPackageDefinition(packageDefinition) as unknown as ProtoGrpcType; + + this.client = new proto.proto.CSharpierService(host, grpc.credentials.createInsecure()); + const deadline = new Date(); + deadline.setSeconds(deadline.getSeconds() + 5); + this.client.waitForReady(deadline, (error?: Error) => { + if (error) { + this.logger.info(`Client connect error: ${error.message}`); + } else { + this.logger.debug("Warm CSharpier with initial format"); + // warm by formatting a file twice, the 3rd time is when it gets really fast + this.formatFile("public class ClassName { }", "Test.cs").then(() => { + this.formatFile("public class ClassName { }", "Test.cs"); + }); + } + }); + } + + formatFile(content: string, filePath: string): Promise { + // TODO if the client is not connected, then queue these up + return new Promise(resolve => { + this.client.formatFile( + { + FileName: filePath, + FileContents: content, + }, + (error?: grpc.ServiceError | null, serverMessage?: FormatFileResult) => { + if (error) { + this.logger.error(error.message); + resolve(""); + } else if (serverMessage) { + this.logger.debug(serverMessage.FormattedFile); + resolve(serverMessage.FormattedFile!); + } + }, + ); + }); + } + + dispose() { + this.client.close(); + // TODO also kill task? + } +} diff --git a/Src/CSharpier.VSCode/src/CSharpierProcessProvider.ts b/Src/CSharpier.VSCode/src/CSharpierProcessProvider.ts index 62684a856..14a086fe3 100644 --- a/Src/CSharpier.VSCode/src/CSharpierProcessProvider.ts +++ b/Src/CSharpier.VSCode/src/CSharpierProcessProvider.ts @@ -10,6 +10,7 @@ import { CSharpierProcessPipeMultipleFiles } from "./CSharpierProcessPipeMultipl import * as fs from "fs"; import { InstallerService } from "./InstallerService"; import { CustomPathInstaller } from "./CustomPathInstaller"; +import { CSharpierProcessProto } from "./CSharpierProcessProto"; export class CSharpierProcessProvider implements Disposable { warnedForOldVersion = false; @@ -214,6 +215,9 @@ export class CSharpierProcessProvider implements Disposable { this.logger.debug(`Adding new version ${version} process for ${directory}`); + // TODO only for newest version + return new CSharpierProcessProto(this.logger, customPath, directory); + if (semver.lt(version, "0.12.0")) { if (!this.warnedForOldVersion) { window.showInformationMessage( diff --git a/Src/CSharpier.VSCode/src/proto/csharpier.proto b/Src/CSharpier.VSCode/src/proto/csharpier.proto new file mode 100644 index 000000000..95eda80ee --- /dev/null +++ b/Src/CSharpier.VSCode/src/proto/csharpier.proto @@ -0,0 +1,21 @@ +syntax = "proto3"; + +option csharp_namespace = "CSharpierService.Generated"; + +package proto; + +service CSharpierService +{ + rpc FormatFile(FormatFileDto) returns (FormatFileResult) {} +} + +message FormatFileDto +{ + string FileContents = 1; + string FileName = 2; +} + +message FormatFileResult +{ + string FormattedFile = 1; +} diff --git a/Src/CSharpier.VSCode/src/proto/csharpier.ts b/Src/CSharpier.VSCode/src/proto/csharpier.ts new file mode 100644 index 000000000..da9563561 --- /dev/null +++ b/Src/CSharpier.VSCode/src/proto/csharpier.ts @@ -0,0 +1,21 @@ +import type * as grpc from "@grpc/grpc-js"; +import type { MessageTypeDefinition } from "@grpc/proto-loader"; + +import type { + CSharpierServiceClient as _proto_CSharpierServiceClient, + CSharpierServiceDefinition as _proto_CSharpierServiceDefinition, +} from "./proto/CSharpierService"; + +type SubtypeConstructor any, Subtype> = { + new (...args: ConstructorParameters): Subtype; +}; + +export interface ProtoGrpcType { + proto: { + CSharpierService: SubtypeConstructor & { + service: _proto_CSharpierServiceDefinition; + }; + FormatFileDto: MessageTypeDefinition; + FormatFileResult: MessageTypeDefinition; + }; +} diff --git a/Src/CSharpier.VSCode/src/proto/proto/CSharpierService.ts b/Src/CSharpier.VSCode/src/proto/proto/CSharpierService.ts new file mode 100644 index 000000000..ced39df78 --- /dev/null +++ b/Src/CSharpier.VSCode/src/proto/proto/CSharpierService.ts @@ -0,0 +1,68 @@ +// Original file: proto/csharpier.proto + +import type * as grpc from "@grpc/grpc-js"; +import type { MethodDefinition } from "@grpc/proto-loader"; +import type { + FormatFileDto as _proto_FormatFileDto, + FormatFileDto__Output as _proto_FormatFileDto__Output, +} from "../proto/FormatFileDto"; +import type { + FormatFileResult as _proto_FormatFileResult, + FormatFileResult__Output as _proto_FormatFileResult__Output, +} from "../proto/FormatFileResult"; + +export interface CSharpierServiceClient extends grpc.Client { + FormatFile( + argument: _proto_FormatFileDto, + metadata: grpc.Metadata, + options: grpc.CallOptions, + callback: grpc.requestCallback<_proto_FormatFileResult__Output>, + ): grpc.ClientUnaryCall; + FormatFile( + argument: _proto_FormatFileDto, + metadata: grpc.Metadata, + callback: grpc.requestCallback<_proto_FormatFileResult__Output>, + ): grpc.ClientUnaryCall; + FormatFile( + argument: _proto_FormatFileDto, + options: grpc.CallOptions, + callback: grpc.requestCallback<_proto_FormatFileResult__Output>, + ): grpc.ClientUnaryCall; + FormatFile( + argument: _proto_FormatFileDto, + callback: grpc.requestCallback<_proto_FormatFileResult__Output>, + ): grpc.ClientUnaryCall; + formatFile( + argument: _proto_FormatFileDto, + metadata: grpc.Metadata, + options: grpc.CallOptions, + callback: grpc.requestCallback<_proto_FormatFileResult__Output>, + ): grpc.ClientUnaryCall; + formatFile( + argument: _proto_FormatFileDto, + metadata: grpc.Metadata, + callback: grpc.requestCallback<_proto_FormatFileResult__Output>, + ): grpc.ClientUnaryCall; + formatFile( + argument: _proto_FormatFileDto, + options: grpc.CallOptions, + callback: grpc.requestCallback<_proto_FormatFileResult__Output>, + ): grpc.ClientUnaryCall; + formatFile( + argument: _proto_FormatFileDto, + callback: grpc.requestCallback<_proto_FormatFileResult__Output>, + ): grpc.ClientUnaryCall; +} + +export interface CSharpierServiceHandlers extends grpc.UntypedServiceImplementation { + FormatFile: grpc.handleUnaryCall<_proto_FormatFileDto__Output, _proto_FormatFileResult>; +} + +export interface CSharpierServiceDefinition extends grpc.ServiceDefinition { + FormatFile: MethodDefinition< + _proto_FormatFileDto, + _proto_FormatFileResult, + _proto_FormatFileDto__Output, + _proto_FormatFileResult__Output + >; +} diff --git a/Src/CSharpier.VSCode/src/proto/proto/FormatFileDto.ts b/Src/CSharpier.VSCode/src/proto/proto/FormatFileDto.ts new file mode 100644 index 000000000..b4d431379 --- /dev/null +++ b/Src/CSharpier.VSCode/src/proto/proto/FormatFileDto.ts @@ -0,0 +1,11 @@ +// Original file: proto/csharpier.proto + +export interface FormatFileDto { + FileContents?: string; + FileName?: string; +} + +export interface FormatFileDto__Output { + FileContents: string; + FileName: string; +} diff --git a/Src/CSharpier.VSCode/src/proto/proto/FormatFileResult.ts b/Src/CSharpier.VSCode/src/proto/proto/FormatFileResult.ts new file mode 100644 index 000000000..84243124d --- /dev/null +++ b/Src/CSharpier.VSCode/src/proto/proto/FormatFileResult.ts @@ -0,0 +1,9 @@ +// Original file: proto/csharpier.proto + +export interface FormatFileResult { + FormattedFile?: string; +} + +export interface FormatFileResult__Output { + FormattedFile: string; +}