export function buildClassDefinition()

in apps/vs-code-designer/src/app/utils/unitTests.ts [780:876]


export function buildClassDefinition(className: string, node: any): ClassDefinition {
  // If there's a top-level "description" for the object
  let classDescription: string | null = node.description ? String(node.description) : null;
  if (!classDescription) {
    if (node.nestedTypeProperty === 'object') {
      const skipKeys = ['nestedTypeProperty', 'title', 'description', 'format', 'headers', 'queries', 'tags', 'relativePathParameters'];
      const propertyNames = Object.keys(node).filter((key) => !skipKeys.includes(key));
      classDescription =
        propertyNames.length > 0
          ? `Class for ${className} representing an object with properties.`
          : `Class for ${className} representing an empty object.`;
    } else {
      classDescription = `Class for ${className} representing a ${node.nestedTypeProperty} value.`;
    }
  }

  // We'll collect property info for the current class
  const properties: PropertyDefinition[] = [];

  // We'll collect child classes if we see nested objects (type: "object").
  const children: ClassDefinition[] = [];

  // If this node is an object, it may have sub-fields we need to parse as properties.
  if (node.nestedTypeProperty === 'object') {
    // Create a combined array of keys we need to skip
    const skipKeys = ['nestedTypeProperty', 'title', 'description', 'format', 'headers', 'queries', 'tags', 'relativePathParameters'];

    // For each subfield in node (like "id", "location", "properties", etc.)
    for (const key of Object.keys(node)) {
      // Skip known metadata fields and the newly added keys (headers, queries, relativePathParameters)
      if (skipKeys.includes(key)) {
        continue;
      }

      const subNode = node[key];
      let propName = toPascalCase(key);

      // Handle special characters
      let jsonPropertyName = null;
      if (/[~@]/.test(key)) {
        jsonPropertyName = key.replace(/~1/g, '.');
        propName = toPascalCase(subNode?.title.replace(/[^a-zA-Z0-9]/g, ''));
      }

      // Determine the child's C# type
      let csharpType = mapJsonTypeToCSharp(subNode?.nestedTypeProperty, subNode?.format);
      let isObject = false;

      // If it's an object, we must generate a nested class.
      // We'll do that recursively, then use the generated child's className for this property type.
      if (subNode?.nestedTypeProperty === 'object') {
        isObject = true;
        const childClassName = className + propName; // e.g. "ActionOutputs" -> "ActionOutputsBody"
        const childDef = buildClassDefinition(childClassName, subNode);

        // If there are child properties then use the newly created object, otherwise use JObject
        if (childDef.properties.length > 0) {
          children.push(childDef);
          // The property for this sub-node points to the newly created child's class name
          csharpType = childDef.className;
        }
      }

      // If it's an array, process the array items
      if (subNode?.nestedTypeProperty === 'array') {
        isObject = true;
        const arrayItemNode = subNode['[*]'];
        const arrayItemClassName = subNode?.description ? toPascalCase(subNode?.description.replace(/\s+/g, '')) : ''; // Remove spaces from description
        const arrayItemDef = buildClassDefinition(arrayItemClassName, arrayItemNode);

        // If there are child properties then use the newly created object, otherwise use JObject
        if (arrayItemDef.properties.length > 0) {
          children.push(arrayItemDef);
          // The property for this sub-node points to the newly created child's class name
          csharpType = `List<${arrayItemDef.className}>`;
        }
      }
      // If it's an array, you might want to look at subNode.items.type to refine the list item type.
      // Check if the subNode has a "description" to be used as a doc-comment on the property.
      const subDescription = subNode?.description ? String(subNode.description) : null;
      properties.push({
        propertyName: propName,
        propertyType: csharpType,
        description: subDescription,
        isObject,
        jsonPropertyName,
      });
    }
  }
  // Build the ClassDefinition for the current node
  return {
    className,
    description: classDescription,
    properties,
    children,
  };
}