1
0

feat: render a table given a definition

This commit is contained in:
Rokas Puzonas 2022-02-05 18:27:32 +02:00
parent 21714ee614
commit db599fa123
6 changed files with 202 additions and 119 deletions

View File

@ -10,7 +10,8 @@
}
.App {
background-color: #282c34;
background-color: #1E1E1E;
color: #CAD6DC;
min-height: 100vh;
display: flex;
flex-direction: column;

View File

@ -1,15 +1,16 @@
import React, { useState } from 'react';
import './App.css';
import TableMethodCode from './TableMethodCode';
export interface TableDefinition {
names?: string[]
fields?: (string|undefined)[]
widths?: (number|undefined)[]
alighments?: ("left"|"right")[]
}
import TableMethodCodeBlock from './TableMethodCodeBlock';
import { TableDefinition } from './TableMethodGenerator';
import TableRenderer from './TableRenderer';
function App() {
let definition: TableDefinition = {
names: ["Miestas", "Atsakingas", "Vardas", "Adresas", "Metai"],
fields: ["City", "Manager", "Name", "Address", "Year"],
widths: [10, 20, 18, 15, 5],
alignments: ["left", "left", "left", "left", "right"]
}
let data = {
method_name: "PrintLocations",
empty_message: "Nėra",
@ -18,17 +19,23 @@ function App() {
entry_name: "l",
entry_type: "Location",
definition: {
names: ["Miestas", "Atsakingas", "Vardas", "Adresas", "Metai"],
fields: ["City", "Manager", "Name", "Address", "Year"],
widths: [10, 20, 18, 15, 5]
}
definition
};
let test_entries = [
["Alytus", "AlytausMuziejusA", "Jonas Jonaitis", "GatveA", "1999"],
["Alytus", "AlytausMuziejusB", "Ona Onaite", "GatveB", "2018"],
["Kaunas", "KaunasMuziejusC", "Jonas Jonaitis", "GatveC", "2004"],
["Klaipėda", "KlaipėdaMuziejusD", "Ona Onaite", "GatveD", "1988"],
];
return (
<div className="App">
{TableMethodCode(data)}
<main>
<hr />
{TableMethodCodeBlock(data)}
<hr />
<TableRenderer definition={definition} entries={test_entries} />
</main>
</div>
);

View File

@ -1,103 +0,0 @@
import SyntaxHighlighter from 'react-syntax-highlighter';
import { docco } from 'react-syntax-highlighter/dist/esm/styles/hljs';
import { TableDefinition } from './App';
export interface TableMethodGeneratorProps {
definition: TableDefinition
method_name?: string
empty_message?: string
container_type?: string
container_name?: string
entry_type?: string
entry_name?: string
}
function generateTableMethod(props: TableMethodGeneratorProps): string {
const section_names = props.definition.names || []
const method_name = props.method_name || "PrintTable"
if (section_names.length == 0) {
return `static void ${method_name}()\n{\n}`;
}
const empty_message = props.empty_message || "Empty"
const container_name = props.container_name || "container"
const container_type = props.container_type || "Container"
const entry_name = props.entry_name || "e"
const entry_type = props.entry_type || "Entry"
const section_widths = props.definition.widths || []
const section_alignments = props.definition.alighments || []
const section_fields = props.definition.fields || []
// Total width
let total_width = 0
for (let i = 0; i < section_names.length; i++) {
const section = section_names[i]
total_width += section_widths[i] || section.length
}
total_width += 2 + 2;
total_width += 3*(section_names.length-1);
// Table row
let row_components: string[] = []
for (let i = 0; i < section_names.length; i++) {
const section = section_names[i]
const width = section_widths[i] || section.length
const alighment = section_alignments[i] || "right"
if (alighment == "left") {
row_components.push(`{${i},-${width}}`)
} else {
row_components.push(`{${i},${width}}`)
}
}
let table_row = "";
if (row_components.length > 0) {
table_row = "| " + row_components.join(" | ") + " |"
}
// Section names
const joined_names = section_names.map((n) => `"${n}"`).join(", ")
// Section fields
const formatted_fields = []
for (let i = 0; i < section_names.length; i++) {
if (section_fields[i]) {
formatted_fields.push(`${entry_name}.${section_fields[i]}`)
} else {
formatted_fields.push(`"-"`)
}
}
const joined_fields = formatted_fields.join(", ")
// Final code string
return `static void ${method_name}(${container_type} ${container_name})\n{
if (${container_name}.Count == 0)
{
Console.WriteLine("${empty_message}");
return;
}
Console.WriteLine(new string('-', ${total_width}));
Console.WriteLine("${table_row}", ${joined_names});
Console.WriteLine(new string('-', ${total_width}));
for (int i = 0; i < ${container_name}.Count; i++)
{
${entry_type} ${entry_name} = ${container_name}.Get(i);
Console.WriteLine("${table_row}", ${joined_fields});
}
Console.WriteLine(new string('-', ${total_width}));\n}`;
}
function TableMethodCode(props: TableMethodGeneratorProps) {
return (
<div>
<SyntaxHighlighter language="csharp" style={docco}>
{generateTableMethod(props)}
</SyntaxHighlighter>
</div>
)
}
export default TableMethodCode

View File

@ -0,0 +1,16 @@
import { Light as SyntaxHighlighter } from 'react-syntax-highlighter';
import csharp from 'react-syntax-highlighter/dist/esm/languages/hljs/csharp';
import { vs2015 } from 'react-syntax-highlighter/dist/esm/styles/hljs';
import { generate, TableMethodGeneratorOptions } from './TableMethodGenerator';
SyntaxHighlighter.registerLanguage('csharp', csharp);
function TableMethodCodeBlock(props: TableMethodGeneratorOptions) {
return (
<SyntaxHighlighter language="csharp" style={vs2015}>
{generate(props)}
</SyntaxHighlighter>
)
}
export default TableMethodCodeBlock

146
src/TableMethodGenerator.ts Normal file
View File

@ -0,0 +1,146 @@
type Alignment = "left"|"right"
export interface TableDefinition {
names?: string[]
fields?: (string|undefined)[]
widths?: (number|undefined)[]
alignments?: (Alignment|undefined)[]
}
export interface TableMethodGeneratorOptions {
definition: TableDefinition
method_name?: string
empty_message?: string
container_type?: string
container_name?: string
entry_type?: string
entry_name?: string
}
function get_total_width(definition: TableDefinition): number {
let names = definition.names || []
if (names.length == 0) { return 0; }
let total_width = 0
let widths = definition.widths || []
for (let i = 0; i < names.length; i++) {
const name = names[i]
total_width += widths[i] || name.length
}
total_width += 2 + 2;
total_width += 3*(names.length-1);
return total_width;
}
export function generate(options: TableMethodGeneratorOptions): string {
const section_names = options.definition.names || []
const method_name = options.method_name || "PrintTable"
if (section_names.length == 0) {
return `static void ${method_name}()\n{\n}`;
}
const empty_message = options.empty_message || "Empty"
const container_name = options.container_name || "container"
const container_type = options.container_type || "Container"
const entry_name = options.entry_name || "e"
const entry_type = options.entry_type || "Entry"
const section_widths = options.definition.widths || []
const section_alignments = options.definition.alignments || []
const section_fields = options.definition.fields || []
// Total width
const total_width = get_total_width(options.definition)
// Table row
let row_components: string[] = []
for (let i = 0; i < section_names.length; i++) {
const section = section_names[i]
const width = section_widths[i] || section.length
const alighment = section_alignments[i] || "right"
if (alighment == "left") {
row_components.push(`{${i},-${width}}`)
} else {
row_components.push(`{${i},${width}}`)
}
}
let table_row = "";
if (row_components.length > 0) {
table_row = "| " + row_components.join(" | ") + " |"
}
// Section names
const joined_names = section_names.map((n) => `"${n}"`).join(", ")
// Section fields
const formatted_fields = []
for (let i = 0; i < section_names.length; i++) {
if (section_fields[i]) {
formatted_fields.push(`${entry_name}.${section_fields[i]}`)
} else {
formatted_fields.push(`"-"`)
}
}
const joined_fields = formatted_fields.join(", ")
// Final code string
return `static void ${method_name}(${container_type} ${container_name})\n{
if (${container_name}.Count == 0)
{
Console.WriteLine("${empty_message}");
return;
}
Console.WriteLine(new string('-', ${total_width}));
Console.WriteLine("${table_row}", ${joined_names});
Console.WriteLine(new string('-', ${total_width}));
for (int i = 0; i < ${container_name}.Count; i++)
{
${entry_type} ${entry_name} = ${container_name}.Get(i);
Console.WriteLine("${table_row}", ${joined_fields});
}
Console.WriteLine(new string('-', ${total_width}));\n}`;
}
function render_table_row(definition: TableDefinition, entry: string[]): string {
let names = definition.names || []
if (names.length == 0) { return ""; }
const columns: string[] = []
const alighments = definition.alignments || []
const widths = definition.widths || []
for (let i = 0; i < names.length; i++) {
const value = entry[i] || "";
const alighment = alighments[i] || "right"
const width = widths[i] || names[i].length
const filler = " ".repeat(Math.max(width - value.length, 0));
if (alighment == "left") {
columns.push(value + filler);
} else {
columns.push(filler + value);
}
}
return "| " + columns.join(" | ") + " |"
}
export function render_table(definition: TableDefinition, entries: string[][]): string {
if (!definition.names) {return ""; }
const total_width = get_total_width(definition)
const seperator = "-".repeat(total_width)
const lines = []
lines.push(seperator)
lines.push(render_table_row(definition, definition.names))
lines.push(seperator)
for (let i = 0; i < entries.length; i++) {
lines.push(render_table_row(definition, entries[i]))
}
lines.push(seperator)
return lines.join("\n")
}

16
src/TableRenderer.tsx Normal file
View File

@ -0,0 +1,16 @@
import { render_table, TableDefinition } from "./TableMethodGenerator"
export interface TableRendererProps {
definition: TableDefinition,
entries: string[][]
}
function TableRenderer(props: TableRendererProps) {
return (
<pre>
{render_table(props.definition, props.entries)}
</pre>
)
}
export default TableRenderer