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';
function App() {
let [definition, setDefinition] = useState<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 [columns, setColumns] = useState<TableColumns>([
{
name: "Miestas",
field: "City",
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({
definition
});
let [generatorOptions, setGeneratorOptions] = useState<TableMethodGeneratorOptions>({});
const onChange = (e: TableDefinition) => {
definition = e
data.definition = e
setDefinition(e)
setData({...data})
const onChange = (e: TableColumns) => {
columns = e
setColumns(e)
}
return (
<div className="App">
<main>
<TableDefinitionForm value={definition} onChange={onChange} />
<TableDefinitionForm value={columns} onChange={onChange} />
<hr />
{TableMethodCodeBlock(data)}
<TableMethodCodeBlock columns={columns} options={generatorOptions}/>
</main>
</div>
);

View File

@ -1,13 +1,13 @@
import { ChangeEvent, useState } from "react"
import { Alignment, TableDefinition } from "./TableMethodGenerator"
import { Alignment, TableColumn, TableColumns } from "./TableMethodGenerator"
interface TableDefinitionRowProps {
value: Row
onChange?: { (e: Row): void }
interface TableColumnProps {
value: TableColumn
onChange?: { (e: TableColumn): void }
}
function TableDefinitionRow(props: TableDefinitionRowProps) {
function TableDefinitionRow(props: TableColumnProps) {
let [, setName] = useState(props.value.name)
const onChangeName = (e: ChangeEvent<HTMLInputElement>) => {
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>) => {
props.value.alighment = e.target.value as Alignment
setAlignment(props.value.alighment)
props.value.alignment = e.target.value as Alignment
setAlignment(props.value.alignment)
if (props.onChange) {
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.field} onChange={onChangeField} />
<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="left">Left</option>
</select>
@ -58,73 +58,35 @@ function TableDefinitionRow(props: TableDefinitionRowProps) {
}
interface TableDefinitionProps {
value: TableDefinition
onChange?: { (e: TableDefinition): 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
value: TableColumns
onChange?: { (e: TableColumns): void }
}
function TableDefinitionForm(props: TableDefinitionProps) {
let [currentName, setCurrentName] = useState("")
let [rows, setRows] = useState<Row[]>(intoRows(props.value))
let [columns, setColumns] = useState<TableColumns>(props.value)
const addRow = () => {
rows.push({ name: currentName })
columns.push({ name: currentName })
setCurrentName("")
if (props.onChange !== undefined) {
props.onChange(fromRows(rows))
props.onChange(columns)
}
}
const updateRow = (i: number, row: Row) => {
if (row.name === "") {
rows.splice(i, 1)
rows = [...rows]
setRows(rows)
const updateRow = (i: number, column: TableColumn) => {
if (column.name === "") {
columns.splice(i, 1)
columns = [...columns]
setColumns(columns)
} else {
rows = [...rows]
rows[i] = row
setRows(rows)
columns = [...columns]
columns[i] = column
setColumns(columns)
}
if (props.onChange !== undefined) {
props.onChange(fromRows(rows))
props.onChange(columns)
}
}
@ -139,7 +101,7 @@ function TableDefinitionForm(props: TableDefinitionProps) {
/>
<ol>
{
rows.map((item, i) =>
columns.map((item, i) =>
<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 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';
import { generate, TableColumns, TableMethodGeneratorOptions } from './TableMethodGenerator';
SyntaxHighlighter.registerLanguage('csharp', csharp);
function TableMethodCodeBlock(props: TableMethodGeneratorOptions) {
let script = generate(props)
interface Props {
columns: TableColumns
options: TableMethodGeneratorOptions
}
function TableMethodCodeBlock(props: Props) {
let script = generate(props.columns, props.options)
const onClickCopy = () => {
navigator.clipboard.writeText(script)

View File

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

View File

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