command-line-api
command-line-api copied to clipboard
Question: how could I read a raw json content
I'm trying to read raw JSON text as an option value, but no luck finding an effective way
For example:
[Theory]
[InlineData(@"--raw {""Id"":1,""Name"":""Test""}")]
[InlineData(@"--raw {""""Id"""":1,""""Name"""":""""Test""""}")]
[InlineData(@"--raw '{""Id"":1,""Name"":""Test""}'")]
public void SplitTest(string commandLine)
{
var args = CommandLineStringSplitter.Instance.Split(commandLine).ToArray();
Assert.Equal(2, args.Length);
Assert.Equal("--raw", args[0]);
Assert.Equal(@"{""Id"":1,""Name"":""Test""}", args[1]);
}
All the cases failed, is there a simple way to read raw json text
The string splitter is intended to emulate the behavior of the command line splitter that prepares the arguments passed to Main(string[] args). From a user's perspective, this behavior will vary even further depending on which shell they use, e.g. cmd.exe versus PowerShell will need different approaches for escaping quotes. Throwing JSON into the mix makes things even more complicated and hard for users to understand even assuming they figure out how to escape everything correctly.
There's a related discussion here: #1740. Using the example program from this comment, here's what your examples produce (assuming I got the escaping right):
This is with PowerShell. The first two aren't valid PowerShell and the program never even gets invoked. The last one works because the surrounding single quotes are valid escapes in PowerShell, but CommandLineStringSplitter doesn't take them into account, by design.
In cmd.exe the same command lines do this:
None of these survive as valid JSON.
So I would ask a different question: How do you expect your users to write raw JSON content?
@jonsequitur,
The string splitter is intended to emulate the behavior of the command line splitter that prepares the arguments passed to Main(string[] args)
But it doesn't with respect to escaping of double quotes. I don't know with certainty if the intent of the question is whether the CommandLineSplitter.Split method supports escaping of double quotes in some way, but i tend to belive so; the code in the question showing attempts to find some working escaping scheme for the double quotes implies to me the question is how to escape double quotes as part of argument values so they survive the CommandLineSplitter.Split method. But with respect to escaping double quotes CommandLineSplitter.Split does not emulate the escaping scheme that works in cmd.exe nor that which is working in PS.
Background:
It is possible both in cmd.exe and in Powershell to escape/quote the json string in such a manner that the quotes that form part of the value survive and are passed properly into the args array of the Main method.
Given this very simple console application:
static void Main(string[] args)
{
foreach (var a in args)
Console.WriteLine($">{a}<");
}
entering in a cmd.exe shell:
ConsoleApp1 --raw {\"Id\":1,\"Name\":\"Test\"}
will output:
>--raw<
>{"Id":1,"Name":"Test"}<
Note how the double quotes are surviving. CommandLineSplitter does not emulate this cmd.exe escaping scheme.
And entering in PS:
.\ConsoleApp1 --raw '{\"Id\":1,\"Name\":\"Test\"}'
will again yield the output:
>--raw<
>{"Id":1,"Name":"Test"}<
And CommandLineSplitter does not emulate this PS escaping scheme either.
Keep in mind that during command line invocation of your app, CommandLineStringSplitter is not used.
The main goal of the CommandLineStringSplitter is to support completions and testing, though unless we add several shell-specific implementations, there's no way to accommodate these differences in quote escaping.
If you want to assume that your users will correctly escape JSON in order to pass it to your application, it's more correct to test using a string array, e.g.:
var result = parser.Parse(new string[] { "--raw", @"{""Id"":1,""Name"":""Test""}");
The main goal of the CommandLineStringSplitter is to support completions and testing, though unless we add several shell-specific implementations, there's no way to accommodate these differences in quote escaping.
CommandLineStringSplitter is also used in the Invoke/Parse methods that accept a single string. And it would perhaps be good if the API documentation would make note of the fact that it does not support escaping of double quotes or other characters. Currently, the API documentation for these (extension) methods has only a simple statement: "The command line string input will be split into tokens as if it had been passed on the command line." which omits the fact that there are limits to when this statement is true or not. (Let me know if i should move this to its own topic/issue.)
How do you expect your users to write raw JSON content?
I'm not sure the users would use which shell. For me, I usually use pwsh on windows, sometimes bash on linux.
Wondering if we could provide a cross-shell implementation so that the users could use consistent scripts across different shells
I'm not sure the users would use which shell. For me, I usually use pwsh on windows, sometimes bash on linux.
@WeihanLi Exactly. And each user will need to handle their own shell-specific escaping to successfully pass a raw JSON string on the command line. Any working example will necessarily be shell-specific. Your example test is also shell-specific.
So yes, it might make sense to create different implementations of CommandLineStringSplitter to mimic the behaviors of different shells. I could see this being useful for testing and, in some cases, for completions.
CommandLineStringSplitter is also used in the Invoke/Parse methods that accept a single string.
@elgonzo While CommandLineStringSplitter is used in those Parse and Invoke overloads, the occasions on which someone will call them are necessarily going to be specialized and, as with shells, the escaping is expected to be handled prior to the call to Split.
~Feel free to open another issue for this.~ I went ahead and opened #1758 .