// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using System.Collections.Generic;
using System.Text.Json;
namespace autoShell.Generators;
///
/// Represents a parsed action definition from a .pas.json schema file.
///
internal class ActionDefinition
{
public string ActionName { get; set; }
public string TypeName { get; set; }
public List Parameters { get; set; } = [];
}
///
/// Represents a single parameter field within an action definition.
///
internal class ParameterDefinition
{
public string JsonName { get; set; }
public string CSharpName { get; set; }
public string CSharpType { get; set; }
public bool IsOptional { get; set; }
public string DefaultValue { get; set; }
}
///
/// Parses .pas.json schema files to extract action definitions with their parameter types.
///
internal static class SchemaParser
{
///
/// Parses a .pas.json file and returns all action definitions found.
///
public static List Parse(string json)
{
var actions = new List();
using var doc = JsonDocument.Parse(json);
var root = doc.RootElement;
if (!root.TryGetProperty("types", out var types))
{
return actions;
}
foreach (var typeProp in types.EnumerateObject())
{
var actionDef = TryParseActionType(typeProp);
if (actionDef != null)
{
actions.Add(actionDef);
}
}
return actions;
}
private static ActionDefinition TryParseActionType(JsonProperty typeProp)
{
var typeObj = typeProp.Value;
// Navigate: type.fields.actionName.type.typeEnum[0]
if (!typeObj.TryGetProperty("type", out var typeInfo))
{
return null;
}
if (!typeInfo.TryGetProperty("fields", out var fields))
{
return null;
}
if (!fields.TryGetProperty("actionName", out var actionNameField))
{
return null;
}
if (!actionNameField.TryGetProperty("type", out var actionNameType))
{
return null;
}
if (!actionNameType.TryGetProperty("typeEnum", out var typeEnum))
{
return null;
}
if (typeEnum.GetArrayLength() == 0)
{
return null;
}
string actionName = typeEnum[0].GetString();
if (string.IsNullOrEmpty(actionName))
{
return null;
}
var def = new ActionDefinition
{
ActionName = actionName,
TypeName = ToPascalCase(actionName) + "Params"
};
// Navigate: type.fields.parameters.type.fields
if (fields.TryGetProperty("parameters", out var parametersField) &&
parametersField.TryGetProperty("type", out var parametersType) &&
parametersType.TryGetProperty("fields", out var paramFields))
{
foreach (var paramProp in paramFields.EnumerateObject())
{
var paramDef = ParseParameter(paramProp);
if (paramDef != null)
{
def.Parameters.Add(paramDef);
}
}
}
return def;
}
private static ParameterDefinition ParseParameter(JsonProperty paramProp)
{
string jsonName = paramProp.Name;
var paramType = paramProp.Value;
if (!paramType.TryGetProperty("type", out var typeInfo))
{
return null;
}
bool isOptional = false;
if (paramType.TryGetProperty("optional", out var optionalProp))
{
isOptional = optionalProp.GetBoolean();
}
string csharpType = ResolveCSharpType(typeInfo, out bool isNullable);
isOptional = isOptional || isNullable;
string defaultValue = GetDefaultValue(csharpType, isOptional);
return new ParameterDefinition
{
JsonName = jsonName,
CSharpName = ToPascalCase(jsonName),
CSharpType = isOptional && IsValueType(csharpType) ? csharpType + "?" : csharpType,
IsOptional = isOptional,
DefaultValue = defaultValue
};
}
private static string ResolveCSharpType(JsonElement typeInfo, out bool isNullable)
{
isNullable = false;
// Simple type: { "type": "number" }
if (typeInfo.TryGetProperty("type", out var simpleType))
{
string typeStr = simpleType.GetString();
return typeStr switch
{
"number" => "int",
"boolean" => "bool",
"string" => "string",
"string-union" => "string",
"type-union" => ResolveTypeUnion(typeInfo, out isNullable),
"array" => ResolveArrayType(typeInfo),
"type-reference" => "string",
"object" => "string",
_ => "string",
};
}
return "string";
}
private static string ResolveArrayType(JsonElement typeInfo)
{
if (typeInfo.TryGetProperty("elementType", out var elementType))
{
string elementCSharpType = ResolveCSharpType(elementType, out _);
return elementCSharpType + "[]";
}
return "string[]";
}
private static string ResolveTypeUnion(JsonElement typeInfo, out bool isNullable)
{
isNullable = false;
if (!typeInfo.TryGetProperty("types", out var unionTypes))
{
return "string";
}
string resolvedType = "string";
foreach (var unionMember in unionTypes.EnumerateArray())
{
if (unionMember.TryGetProperty("type", out var memberType))
{
string memberTypeStr = memberType.GetString();
if (memberTypeStr == "undefined" || memberTypeStr == "null")
{
isNullable = true;
}
else
{
resolvedType = ResolveCSharpType(unionMember, out _);
}
}
}
return resolvedType;
}
private static bool IsValueType(string csharpType)
{
return csharpType == "int" || csharpType == "bool" || csharpType == "double";
}
private static string GetDefaultValue(string csharpType, bool isOptional)
{
if (isOptional)
{
return "null";
}
if (csharpType.EndsWith("[]"))
{
return "null";
}
return csharpType switch
{
"int" => "0",
"bool" => "false",
"double" => "0.0",
"string" => "\"\"",
_ => "\"\"",
};
}
private static string ToPascalCase(string name)
{
return string.IsNullOrEmpty(name) ? name : char.ToUpperInvariant(name[0]) + name.Substring(1);
}
}