diff --git a/src/Microsoft.DotNet.Interactive.Jupyter/ConnectJupyterKernel.cs b/src/Microsoft.DotNet.Interactive.Jupyter/ConnectJupyterKernel.cs index 3d03041115..22d3c6dbc4 100644 --- a/src/Microsoft.DotNet.Interactive.Jupyter/ConnectJupyterKernel.cs +++ b/src/Microsoft.DotNet.Interactive.Jupyter/ConnectJupyterKernel.cs @@ -19,8 +19,10 @@ public ConnectJupyterKernel(string connectedKernelName) : base(connectedKernelNa public string InitScript { get; set; } + [JsonPropertyName("url")] public string TargetUrl { get; set; } - + + [JsonPropertyName("bearer")] public bool UseBearerAuth { get; set; } public string Token { get; set; } diff --git a/src/Microsoft.DotNet.Interactive.Jupyter/ConnectJupyterKernelDirective.cs b/src/Microsoft.DotNet.Interactive.Jupyter/ConnectJupyterKernelDirective.cs index 61f852be48..fc932c6bb4 100644 --- a/src/Microsoft.DotNet.Interactive.Jupyter/ConnectJupyterKernelDirective.cs +++ b/src/Microsoft.DotNet.Interactive.Jupyter/ConnectJupyterKernelDirective.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Copyright (c) .NET Foundation and contributors. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. using Microsoft.DotNet.Interactive.Connection; @@ -31,7 +31,10 @@ public ConnectJupyterKernelDirective() : base("jupyter", "Connects a Jupyter ker }; public KernelDirectiveParameter InitScriptParameter { get; } = - new("--init-script", "Script to run on kernel initialization"); + new("--init-script", "Script to run on kernel initialization") + { + TypeHint = "file" + }; public ConnectJupyterKernelDirective AddConnectionOptions(IJupyterKernelConnectionOptions connectionOptions) { diff --git a/src/Microsoft.DotNet.Interactive.Parsing.Tests/PolyglotSyntaxParserTests.DirectiveParameters.cs b/src/Microsoft.DotNet.Interactive.Parsing.Tests/PolyglotSyntaxParserTests.DirectiveParameters.cs index fd7f799814..d7e48a059f 100644 --- a/src/Microsoft.DotNet.Interactive.Parsing.Tests/PolyglotSyntaxParserTests.DirectiveParameters.cs +++ b/src/Microsoft.DotNet.Interactive.Parsing.Tests/PolyglotSyntaxParserTests.DirectiveParameters.cs @@ -299,6 +299,38 @@ public void When_the_value_for_a_required_parameter_is_missing_then_an_error_is_ .Be("Missing value for required parameter '--required'"); } + [Fact] + public void When_a_required_parameter_on_a_subcommand_is_missing_then_an_error_is_produced() + { + var tree = Parse("#!connect jupyter --kernel-spec .net-csharp"); + + tree.RootNode + .GetDiagnostics() + .Should() + .ContainSingle() + .Which + .GetMessage() + .Should() + .Be("Missing required parameter '--kernel-name'"); + } + + [Theory] + [InlineData("#!connect jupyter --kernel-spec .net-csharp --kernel-name")] + [InlineData("#!connect jupyter --kernel-name --kernel-spec .net-csharp")] + public void When_the_value_for_a_required_parameter_on_a_subcommand_is_missing_then_an_error_is_produced(string code) + { + var tree = Parse(code); + + tree.RootNode + .GetDiagnostics() + .Should() + .ContainSingle() + .Which + .GetMessage() + .Should() + .Be("Missing value for required parameter '--kernel-name'"); + } + [Theory] [InlineData(""" "just a JSON string" diff --git a/src/Microsoft.DotNet.Interactive.Parsing.Tests/PolyglotSyntaxParserTests.Subcommands.cs b/src/Microsoft.DotNet.Interactive.Parsing.Tests/PolyglotSyntaxParserTests.Subcommands.cs index d443a9428b..9cada19b8b 100644 --- a/src/Microsoft.DotNet.Interactive.Parsing.Tests/PolyglotSyntaxParserTests.Subcommands.cs +++ b/src/Microsoft.DotNet.Interactive.Parsing.Tests/PolyglotSyntaxParserTests.Subcommands.cs @@ -3,7 +3,6 @@ using System; using System.Linq; -using System.Threading.Tasks; using FluentAssertions; using Microsoft.CodeAnalysis; using Microsoft.DotNet.Interactive.Directives; diff --git a/src/Microsoft.DotNet.Interactive/Directives/KernelActionDirective.cs b/src/Microsoft.DotNet.Interactive/Directives/KernelActionDirective.cs index 8235a04d75..9925fbf591 100644 --- a/src/Microsoft.DotNet.Interactive/Directives/KernelActionDirective.cs +++ b/src/Microsoft.DotNet.Interactive/Directives/KernelActionDirective.cs @@ -11,7 +11,6 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Tags; using Microsoft.DotNet.Interactive.Events; -using Microsoft.DotNet.Interactive.Parsing; namespace Microsoft.DotNet.Interactive.Directives; diff --git a/src/Microsoft.DotNet.Interactive/Parsing/DirectiveNode.cs b/src/Microsoft.DotNet.Interactive/Parsing/DirectiveNode.cs index b0dd8bbdfa..d99fa24aaa 100644 --- a/src/Microsoft.DotNet.Interactive/Parsing/DirectiveNode.cs +++ b/src/Microsoft.DotNet.Interactive/Parsing/DirectiveNode.cs @@ -47,39 +47,9 @@ internal DirectiveNode( if (TryGetDirective(out var directive)) { - foreach (var namedParameter in directive.Parameters) + foreach (var diagnostic in GetDiagnosticsForMissingParameters(directive, this)) { - if (namedParameter.Required) - { - var matchingNodes = ChildNodes.OfType() - .Where(p => p.NameNode is null - ? namedParameter.AllowImplicitName - : p.NameNode?.Text == namedParameter.Name) - .ToArray(); - - if (!matchingNodes.Any()) - { - yield return CreateDiagnostic( - new(PolyglotSyntaxParser.ErrorCodes.MissingRequiredParameter, - "Missing required parameter '{0}'", - DiagnosticSeverity.Error, - namedParameter.Name)); - } - else - { - foreach (var parameterNode in matchingNodes) - { - if (parameterNode.ValueNode is null) - { - yield return CreateDiagnostic( - new(PolyglotSyntaxParser.ErrorCodes.MissingRequiredParameter, - "Missing value for required parameter '{0}'", - DiagnosticSeverity.Error, - namedParameter.Name)); - } - } - } - } + yield return diagnostic; } } @@ -103,6 +73,46 @@ internal DirectiveNode( } } + internal static IEnumerable GetDiagnosticsForMissingParameters( + KernelDirective directive, + SyntaxNode node) + { + foreach (var namedParameter in directive.Parameters) + { + if (namedParameter.Required) + { + var matchingNodes = node.ChildNodes.OfType() + .Where(p => p.NameNode is null + ? namedParameter.AllowImplicitName + : p.NameNode?.Text == namedParameter.Name) + .ToArray(); + + if (!matchingNodes.Any()) + { + yield return node.CreateDiagnostic( + new(PolyglotSyntaxParser.ErrorCodes.MissingRequiredParameter, + "Missing required parameter '{0}'", + DiagnosticSeverity.Error, + namedParameter.Name)); + } + else + { + foreach (var parameterNode in matchingNodes) + { + if (parameterNode.ValueNode is null) + { + yield return node.CreateDiagnostic( + new(PolyglotSyntaxParser.ErrorCodes.MissingRequiredParameter, + "Missing value for required parameter '{0}'", + DiagnosticSeverity.Error, + namedParameter.Name)); + } + } + } + } + } + } + public bool TryGetActionDirective(out KernelActionDirective directive) { if (GetKernelInfo() is { } kernelInfo) diff --git a/src/Microsoft.DotNet.Interactive/Parsing/DirectiveSubcommandNode.cs b/src/Microsoft.DotNet.Interactive/Parsing/DirectiveSubcommandNode.cs index b558d00927..1be773c3f7 100644 --- a/src/Microsoft.DotNet.Interactive/Parsing/DirectiveSubcommandNode.cs +++ b/src/Microsoft.DotNet.Interactive/Parsing/DirectiveSubcommandNode.cs @@ -2,7 +2,9 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. #nullable enable +using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Text; using Microsoft.DotNet.Interactive.Directives; @@ -36,6 +38,22 @@ public void Add(DirectiveParameterValueNode node) HasParameters = true; } + public override IEnumerable GetDiagnostics() + { + foreach (var diagnostic in base.GetDiagnostics()) + { + yield return diagnostic; + } + + if (TryGetSubcommand(out var directive)) + { + foreach (var diagnostic in DirectiveNode.GetDiagnosticsForMissingParameters(directive, this)) + { + yield return diagnostic; + } + } + } + public bool TryGetSubcommand([NotNullWhen(true)] out KernelActionDirective? subcommandDirective) { if (Parent is DirectiveNode parentDirectiveNode)