In that component "output-console.component.html (1-90)


@if (dataEntries() && dataEntries().length > 0) {
  <button
    (click)="showRawData.set(!showRawData())"
    mat-flat-button
    color="primary"
  >
    @if (showRawData()) {
      Show Beautified Data
    } @else {
      Show Raw Data
    }
  </button>

  <div class="border bg-body-secondary console">
    <samp>
      @switch (detectedLanguage()) {
        @case ("json") {
          @for (data of parsedJson(); track data) {
            @if (showRawData()) {
              <!-- Show Raw JSON -->
              <pre><code>{{ data | json }}</code></pre>
            } @else {
              <!-- Show Beautified JSON -->
              <div class="json-viewer-item">
                <ngx-json-viewer [json]="data" />
              </div>
            }
          }
        }
        @case ("xml") {
          @for (data of dataEntries(); track data) {
            @if (showRawData()) {
              <!-- Show Raw XML -->
              <pre><code>{{ data }}</code></pre>
            } @else {
              <!-- Show Beautified XML -->
              <pre class="xml-pre">
                <code [highlight]="data | prettyXml" language="xml"></code>
              </pre>
            }
          }
        }
        @case ("csv") {
          @if (showRawData()) {
            <!-- Show Raw CSV -->
            <pre><code>{{ dataEntries().join('\n') }}</code></pre>
          } @else {
            <!-- Beautified CSV with Nested Tables -->
            <table class="table table-striped">
              <thead>
                <tr>
                  @for (header of getCsvHeaders(parsedCsv()[0]); track header) {
                    <th>
                      {{ header }}
                    </th>
                  }
                </tr>
              </thead>
              <tbody>
                @for (row of parsedCsv(); track row) {
                  <tr>
                    @for (
                      header of getCsvHeaders(parsedCsv()[0]);
                      track header
                    ) {
                      <td>
                        @if (isObject(row[header])) {
                          <!-- Render Nested Table -->
                          <div [innerHTML]="getNestedTable(row[header])"></div>
                        } @else {
                          {{ row[header] }}
                        }
                      </td>
                    }
                  </tr>
                }
              </tbody>
            </table>
          }
        }
        @default {
          @for (data of dataEntries(); track data) {
            <pre><code>{{ data }}</code></pre>
          }
        }
      }
    </samp>
  </div>
}


output-console.component.ts (1-155)


import { CommonModule } from '@angular/common';
import {
  ChangeDetectionStrategy,
  Component,
  computed,
  input,
  signal,
} from '@angular/core';
import { Highlight } from 'ngx-highlightjs';
import { HighlightLineNumbers } from 'ngx-highlightjs/line-numbers';
import { PrettyJsonPipe } from '../shared/pipes/pretty-json.pipe';
import { PrettyXmlPipe } from '../shared/pipes/pretty-xml.pipe';
import { NgxJsonViewerModule } from 'ngx-json-viewer';
import Papa from 'papaparse';
import { MatButtonModule } from '@angular/material/button';

@Component({
  selector: 'app-output-console',
  standalone: true,
  imports: [
    CommonModule,
    Highlight,
    PrettyJsonPipe,
    PrettyXmlPipe,
    NgxJsonViewerModule,
    MatButtonModule,
    HighlightLineNumbers,
  ],
  templateUrl: './output-console.component.html',
  styleUrls: ['./output-console.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class OutputConsoleComponent {
  public consoleData = input.required<string[]>();

  public showRawData = signal<boolean>(false);

  public dataEntries = computed(() => {
    let entries: string[] = [];
    for (let dataString of this.consoleData()) {
      entries.push(
        ...dataString
          .split('\n')
          .map((line) => line.trim())
          .filter((line) => line.length > 0),
      );
    }
    return entries;
  });

  public detectedLanguage = computed(() => {
    return this.detectLanguage(this.dataEntries()[0]);
  });

  public parsedJson = computed(() => {
    if (this.detectedLanguage() !== 'json') {
      return [];
    }

    return this.dataEntries().map((dataString) => {
      try {
        return JSON.parse(dataString);
      } catch (e) {
        console.error('JSON Parsing Error:', e);
        return null;
      }
    });
  });

  public parsedCsv = computed(() => {
    if (this.detectedLanguage() !== 'csv') {
      return [];
    }

    let allData = this.dataEntries().join('\n');
    const result = Papa.parse<{ [key: string]: any }>(allData, {
      header: true,
      skipEmptyLines: true,
    });

    return result.data.map((row) => {
      Object.keys(row).forEach((key) => {
        const value = row[key];
        if (typeof value === 'string' && value.trim().startsWith('{')) {
          try {
            row[key] = JSON.parse(value);
          } catch (e) {
            console.warn(`Could not parse JSON in CSV field ${key}:`, e);
          }
        }
      });
      return row;
    });
  });

  public isObject(value: any): boolean {
    return value && typeof value === 'object' && !Array.isArray(value);
  }

  public getCsvValues(row: any): any[] {
    return row ? Object.values(row) : [];
  }

  public getCsvHeaders(row: any): string[] {
    return row ? Object.keys(row) : [];
  }

  public detectLanguage(data: string): 'json' | 'xml' | 'csv' | 'plaintext' {
    data = data.trim();
    try {
      JSON.parse(data);
      return 'json';
    } catch {
      // Not JSON
    }

    if (data.startsWith('<')) {
      return 'xml';
    }

    if (data.includes(',') || data.includes('\n')) {
      return 'csv';
    }

    return 'plaintext';
  }

  public getNestedTable(obj: any): string {
    let table = '<table class="table table-bordered nested-table">';
    table += '<thead><tr>';

    // Generate table headers
    for (const key of Object.keys(obj)) {
      table += `<th>${key}</th>`;
    }

    table += '</tr></thead><tbody><tr>';

    // Generate table cells
    for (const key of Object.keys(obj)) {
      const value = obj[key];
      if (this.isObject(value)) {
        // Recursively generate nested tables
        table += `<td>${this.getNestedTable(value)}</td>`;
      } else {
        table += `<td>${value}</td>`;
      }
    }

    table += '</tr></tbody></table>';

    return table;
  }
}" on the CSV side, let's say that our raw data here "dataEntries().join('\n')" looks like that "id,data
92,{"id":40,"price":21.88284}
11,{"id":48,"price":43.00885}
61,{"id":37,"price":73.32786}
19,{"id":26,"price":20.48498}
39,{"id":89,"price":77.77849}
37,{"id":64,"price":50.54647}
24,{"id":95,"price":46.95316}
44,{"id":35,"price":64.04344}
75,{"id":87,"price":51.85926}
13,{"id":3,"price":62.97069}". When i go from raw to beautify i have this error "output-console.component.ts:88 Could not parse JSON in CSV field data: SyntaxError: Expected ',' or '}' after property value in JSON at position 8 (line 1 column 9)
    at JSON.parse (<anonymous>)
    at output-console.component.ts:86:29
    at Array.forEach (<anonymous>)
    at output-console.component.ts:82:24
    at Array.map (<anonymous>)
    at Object.computation (output-console.component.ts:81:24)
    at Object.producerRecomputeValue (signals.mjs:385:33)
    at producerUpdateValueVersion (signals.mjs:135:10)
    at _OutputConsoleComponent.computed2 [as parsedCsv] (signals.mjs:332:9)
    at OutputConsoleComponent_Conditional_0_Case_7_Conditional_1_Template (output-console.component.html:52:33)"