1
0

refactor: adjust how table definitions are stored

This commit is contained in:
Rokas Puzonas 2022-02-07 22:57:17 +02:00
parent 8460dd5f9a
commit 55c1483052
5 changed files with 119 additions and 145 deletions

View File

@ -5,30 +5,52 @@ import TableMethodCodeBlock from './TableMethodCodeBlock';
import { TableDefinition } from './TableMethodGenerator'; import { TableDefinition } from './TableMethodGenerator';
function App() { function App() {
let [definition, setDefinition] = useState<TableDefinition>({ let [columns, setColumns] = useState<TableColumns>([
names: ["Miestas", "Atsakingas", "Vardas", "Adresas", "Metai"], {
fields: ["City", "Manager", "Name", "Address", "Year"], name: "Miestas",
widths: [10, 20, 18, 15, 5], field: "City",
alignments: ["left", "left", "left", "left", "right"] width: 10,
}) alignment: "left"
},
{
name: "Atsakingas",
field: "Manager",
width: 20,
alignment: "left"
},
{
name: "Vardas",
field: "Name",
width: 18,
alignment: "left"
},
{
name: "Address",
field: "Adress",
width: 15,
alignment: "left"
},
{
name: "Metai",
field: "Year",
width: 5,
alignment: "right"
}
])
let [data, setData] = useState({ let [generatorOptions, setGeneratorOptions] = useState<TableMethodGeneratorOptions>({});
definition
});
const onChange = (e: TableDefinition) => { const onChange = (e: TableColumns) => {
definition = e columns = e
data.definition = e setColumns(e)
setDefinition(e)
setData({...data})
} }
return ( return (
<div className="App"> <div className="App">
<main> <main>
<TableDefinitionForm value={definition} onChange={onChange} /> <TableDefinitionForm value={columns} onChange={onChange} />
<hr /> <hr />
{TableMethodCodeBlock(data)} <TableMethodCodeBlock columns={columns} options={generatorOptions}/>
</main> </main>
</div> </div>
); );

View File

@ -1,13 +1,13 @@
import { ChangeEvent, useState } from "react" import { ChangeEvent, useState } from "react"
import { Alignment, TableDefinition } from "./TableMethodGenerator" import { Alignment, TableColumn, TableColumns } from "./TableMethodGenerator"
interface TableDefinitionRowProps { interface TableColumnProps {
value: Row value: TableColumn
onChange?: { (e: Row): void } onChange?: { (e: TableColumn): void }
} }
function TableDefinitionRow(props: TableDefinitionRowProps) { function TableDefinitionRow(props: TableColumnProps) {
let [, setName] = useState(props.value.name) let [, setName] = useState(props.value.name)
const onChangeName = (e: ChangeEvent<HTMLInputElement>) => { const onChangeName = (e: ChangeEvent<HTMLInputElement>) => {
props.value.name = e.target.value props.value.name = e.target.value
@ -35,10 +35,10 @@ function TableDefinitionRow(props: TableDefinitionRowProps) {
} }
} }
let [, setAlignment] = useState(props.value.alighment) let [, setAlignment] = useState(props.value.alignment)
const onChangeAlignment = (e: ChangeEvent<HTMLSelectElement>) => { const onChangeAlignment = (e: ChangeEvent<HTMLSelectElement>) => {
props.value.alighment = e.target.value as Alignment props.value.alignment = e.target.value as Alignment
setAlignment(props.value.alighment) setAlignment(props.value.alignment)
if (props.onChange) { if (props.onChange) {
props.onChange(props.value) props.onChange(props.value)
} }
@ -49,7 +49,7 @@ function TableDefinitionRow(props: TableDefinitionRowProps) {
<input type="text" value={props.value.name} onChange={onChangeName} /> <input type="text" value={props.value.name} onChange={onChangeName} />
<input type="text" value={props.value.field} onChange={onChangeField} /> <input type="text" value={props.value.field} onChange={onChangeField} />
<input type="number" value={props.value.width || props.value.name.length} onChange={onChangeWidth}/> <input type="number" value={props.value.width || props.value.name.length} onChange={onChangeWidth}/>
<select value={props.value.alighment} onChange={onChangeAlignment}> <select value={props.value.alignment} onChange={onChangeAlignment}>
<option value="right">Right</option> <option value="right">Right</option>
<option value="left">Left</option> <option value="left">Left</option>
</select> </select>
@ -58,73 +58,35 @@ function TableDefinitionRow(props: TableDefinitionRowProps) {
} }
interface TableDefinitionProps { interface TableDefinitionProps {
value: TableDefinition value: TableColumns
onChange?: { (e: TableDefinition): void } onChange?: { (e: TableColumns): void }
}
interface Row {
name: string
width?: number
field?: string
alighment?: Alignment
}
function intoRows(definition: TableDefinition): Row[] {
const rows: Row[] = []
if (definition.names !== undefined) {
for (let i = 0; i < definition.names.length; i++) {
rows.push({
name: definition.names[i],
width: (definition.widths || [])[i],
field: (definition.fields || [])[i],
alighment: (definition.alignments || [])[i],
})
}
}
return rows
}
function fromRows(rows: Row[]): TableDefinition {
const definition: TableDefinition = {
names: [],
widths: [],
fields: [],
alignments: []
}
for (const row of rows) {
(definition.names as string[]).push(row.name);
(definition.widths as (number|undefined)[]).push(row.width);
(definition.fields as (string|undefined)[]).push(row.field);
(definition.alignments as (Alignment|undefined)[]).push(row.alighment);
}
return definition
} }
function TableDefinitionForm(props: TableDefinitionProps) { function TableDefinitionForm(props: TableDefinitionProps) {
let [currentName, setCurrentName] = useState("") let [currentName, setCurrentName] = useState("")
let [rows, setRows] = useState<Row[]>(intoRows(props.value)) let [columns, setColumns] = useState<TableColumns>(props.value)
const addRow = () => { const addRow = () => {
rows.push({ name: currentName }) columns.push({ name: currentName })
setCurrentName("") setCurrentName("")
if (props.onChange !== undefined) { if (props.onChange !== undefined) {
props.onChange(fromRows(rows)) props.onChange(columns)
} }
} }
const updateRow = (i: number, row: Row) => { const updateRow = (i: number, column: TableColumn) => {
if (row.name === "") { if (column.name === "") {
rows.splice(i, 1) columns.splice(i, 1)
rows = [...rows] columns = [...columns]
setRows(rows) setColumns(columns)
} else { } else {
rows = [...rows] columns = [...columns]
rows[i] = row columns[i] = column
setRows(rows) setColumns(columns)
} }
if (props.onChange !== undefined) { if (props.onChange !== undefined) {
props.onChange(fromRows(rows)) props.onChange(columns)
} }
} }
@ -139,7 +101,7 @@ function TableDefinitionForm(props: TableDefinitionProps) {
/> />
<ol> <ol>
{ {
rows.map((item, i) => columns.map((item, i) =>
<TableDefinitionRow key={i} value={item} onChange={(e) => updateRow(i, e)}/> <TableDefinitionRow key={i} value={item} onChange={(e) => updateRow(i, e)}/>
) )
} }

View File

@ -1,12 +1,17 @@
import { Light as SyntaxHighlighter } from 'react-syntax-highlighter'; import { Light as SyntaxHighlighter } from 'react-syntax-highlighter';
import csharp from 'react-syntax-highlighter/dist/esm/languages/hljs/csharp'; import csharp from 'react-syntax-highlighter/dist/esm/languages/hljs/csharp';
import { vs2015 } from 'react-syntax-highlighter/dist/esm/styles/hljs'; import { vs2015 } from 'react-syntax-highlighter/dist/esm/styles/hljs';
import { generate, TableMethodGeneratorOptions } from './TableMethodGenerator'; import { generate, TableColumns, TableMethodGeneratorOptions } from './TableMethodGenerator';
SyntaxHighlighter.registerLanguage('csharp', csharp); SyntaxHighlighter.registerLanguage('csharp', csharp);
function TableMethodCodeBlock(props: TableMethodGeneratorOptions) { interface Props {
let script = generate(props) columns: TableColumns
options: TableMethodGeneratorOptions
}
function TableMethodCodeBlock(props: Props) {
let script = generate(props.columns, props.options)
const onClickCopy = () => { const onClickCopy = () => {
navigator.clipboard.writeText(script) navigator.clipboard.writeText(script)

View File

@ -1,15 +1,15 @@
export type Alignment = "left"|"right" export type Alignment = "left"|"right"
export interface TableDefinition { export interface TableColumn {
names?: string[] name: string
fields?: (string|undefined)[] field?: string
widths?: (number|undefined)[] width?: number
alignments?: (Alignment|undefined)[] alignment?: Alignment
} }
export interface TableMethodGeneratorOptions { export type TableColumns = TableColumn[]
definition: TableDefinition
export interface TableMethodGeneratorOptions {
method_name?: string method_name?: string
empty_message?: string empty_message?: string
@ -19,26 +19,21 @@ export interface TableMethodGeneratorOptions {
entry_name?: string entry_name?: string
} }
function get_total_width(definition: TableDefinition): number { function get_total_width(columns: TableColumns): number {
let names = definition.names || [] let total_width = 0;
if (names.length === 0) { return 0; }
let total_width = 0 for (const column of columns) {
let widths = definition.widths || [] total_width += column.width || column.name.length
for (let i = 0; i < names.length; i++) {
const name = names[i]
total_width += widths[i] || name.length
} }
total_width += 2 + 2; total_width += 2 + 2;
total_width += 3*(names.length-1); total_width += 3*(columns.length-1);
return total_width; return total_width;
} }
export function generate(options: TableMethodGeneratorOptions): string { export function generate(columns: TableColumns, options: TableMethodGeneratorOptions): string {
const section_names = options.definition.names || []
const method_name = options.method_name || "PrintTable" const method_name = options.method_name || "PrintTable"
if (section_names.length === 0) { if (columns.length === 0) {
return `static void ${method_name}()\n{\n}`; return `static void ${method_name}()\n{\n}`;
} }
@ -47,19 +42,15 @@ export function generate(options: TableMethodGeneratorOptions): string {
const container_type = options.container_type || "Container" const container_type = options.container_type || "Container"
const entry_name = options.entry_name || "e" const entry_name = options.entry_name || "e"
const entry_type = options.entry_type || "Entry" 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 // Total width
const total_width = get_total_width(options.definition) const total_width = get_total_width(columns)
// Table row // Table row
let row_components: string[] = [] let row_components: string[] = []
for (let i = 0; i < section_names.length; i++) { for (let i = 0; i < columns.length; i++) {
const section = section_names[i] const width = columns[i].width || columns[i].name.length
const width = section_widths[i] || section.length const alighment = columns[i].alignment || "right"
const alighment = section_alignments[i] || "right"
if (alighment === "left") { if (alighment === "left") {
row_components.push(`{${i},-${width}}`) row_components.push(`{${i},-${width}}`)
} else { } else {
@ -67,24 +58,19 @@ export function generate(options: TableMethodGeneratorOptions): string {
} }
} }
let table_row = ""; const table_row = "| " + row_components.join(" | ") + " |"
if (row_components.length > 0) {
table_row = "| " + row_components.join(" | ") + " |"
}
// Section names // Section names
const joined_names = section_names.map((n) => `"${n}"`).join(", ") const joined_names = columns.map((c) => `"${c.name}"`).join(", ")
// Section fields // Section fields
const formatted_fields = [] const joined_fields = columns.map((column) => {
for (let i = 0; i < section_names.length; i++) { if (column.field) {
if (section_fields[i]) { return `${entry_name}.${column.field}`
formatted_fields.push(`${entry_name}.${section_fields[i]}`)
} else { } else {
formatted_fields.push(`"-"`) return `"-"`
} }
} }).join(", ")
const joined_fields = formatted_fields.join(", ")
// Final code string // Final code string
return `static void ${method_name}(${container_type} ${container_name})\n{ return `static void ${method_name}(${container_type} ${container_name})\n{
@ -105,40 +91,39 @@ export function generate(options: TableMethodGeneratorOptions): string {
Console.WriteLine(new string('-', ${total_width}));\n}`; Console.WriteLine(new string('-', ${total_width}));\n}`;
} }
function render_table_row(definition: TableDefinition, entry: string[]): string { function render_table_row(columns: TableColumns, entry: (string|undefined)[]): string {
let names = definition.names || [] if (columns.length === 0) { return "" }
if (names.length === 0) { return ""; }
const columns: string[] = [] let formated_cells = []
const alighments = definition.alignments || [] for (let i = 0; i < columns.length; i++) {
const widths = definition.widths || [] const alighment = columns[i].alignment || "right"
for (let i = 0; i < names.length; i++) { const width = columns[i].width || columns[i].name.length
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)); const value = entry[i] || "";
if (alighment === "left") { const filler = " ".repeat(Math.max(width - value.length, 0));
columns.push(value + filler); if (alighment === "left") {
} else { formated_cells.push(value + filler);
columns.push(filler + value); } else {
} formated_cells.push(filler + value);
}
} }
return "| " + columns.join(" | ") + " |"
return "| " + formated_cells.join(" | ") + " |"
} }
export function render_table(definition: TableDefinition, entries: string[][]): string { export function render_table(columns: TableColumns, entries: string[][]): string {
if (!definition.names) {return ""; } if (columns.length === 0) { return "" }
const total_width = get_total_width(definition) const total_width = get_total_width(columns)
const seperator = "-".repeat(total_width) const seperator = "-".repeat(total_width)
const column_names = columns.map((column) => column.name)
const lines = [] const lines = []
lines.push(seperator) lines.push(seperator)
lines.push(render_table_row(definition, definition.names)) lines.push(render_table_row(columns, column_names))
lines.push(seperator) lines.push(seperator)
for (let i = 0; i < entries.length; i++) { for (let i = 0; i < entries.length; i++) {
lines.push(render_table_row(definition, entries[i])) lines.push(render_table_row(columns, entries[i]))
} }
lines.push(seperator) lines.push(seperator)

View File

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