Page MenuHomeSealhub

No OneTemporary

diff --git a/src/component-arguments/table.test.ts b/src/component-arguments/table.test.ts
index 0ebca4a..0e39c9e 100644
--- a/src/component-arguments/table.test.ts
+++ b/src/component-arguments/table.test.ts
@@ -1,34 +1,47 @@
import { Table } from "./table.js";
import { Structured } from "./structured.js";
import { List } from "./list.js";
import { ShortText } from "./short-text.js";
import { ExtractParsed } from "./component-argument.js";
+import assert from "assert";
+import { makeSimpleEnglishJDDContext } from "../jdd-context.js";
describe("table argument", () => {
it("properly parses type value", () => {
const table_arg = new Table(
new Structured(<const>{
value: new ShortText().setExampleValues([""]),
tags: new List(new ShortText()),
}),
new Structured({
tags: new List(new ShortText()).setExampleValues([["okazja"]]),
})
);
const table_value = {
rows: [
{ type: "row", cells: [] },
{ type: "header", value: "", tags: [] },
],
} as ExtractParsed<typeof table_arg>;
table_value.rows.map((row) => {
if (row.type == "row") {
row.cells.map((cell) => {
cell.tags.map((tag) => tag); // if the types are written correctly, this will typecheck OK
});
}
});
});
+
+ it("properly respects custom set example value", async () => {
+ const table_arg = new Table(
+ new ShortText(),
+ new ShortText()
+ ).setExampleValues([{ rows: [] }]);
+ assert.deepStrictEqual(
+ await table_arg.getExampleValue(makeSimpleEnglishJDDContext()),
+ { rows: [] }
+ );
+ });
});
diff --git a/src/component-arguments/table.ts b/src/component-arguments/table.ts
index d984202..02a4e79 100644
--- a/src/component-arguments/table.ts
+++ b/src/component-arguments/table.ts
@@ -1,232 +1,237 @@
import { hasShape, predicates } from "@sealcode/ts-predicates";
import { JDDContext } from "../index.js";
import { ComponentArgument } from "./component-argument.js";
import { ContainerArgument } from "./container-argument.js";
type TableHeader<HeaderType> = { type: "header"; header_content: HeaderType };
type TableRegularRow<CellType> = { type: "row"; cells: CellType[] };
export type TableRow<CellType, HeaderType> =
| TableHeader<HeaderType>
| TableRegularRow<CellType>;
export type TableData<CellType, HeaderType> = {
rows: TableRow<CellType, HeaderType>[];
};
export function isTableHeader(x: unknown): x is TableHeader<unknown> {
return hasShape(
{
type: predicates.const("header"),
header_content: predicates.unknown,
},
x
);
}
export function isTableRegularRow<CellType = unknown>(
x: unknown
): x is TableRegularRow<CellType> {
return hasShape(
{
type: predicates.const("row"),
cells: predicates.array(predicates.unknown),
},
x
);
}
export function isTableData<CellType = unknown, HeaderType = unknown>(
x: unknown
): x is TableData<CellType, HeaderType> {
return hasShape(
{
rows: predicates.array(predicates.object),
},
x
);
}
export class Table<CellType, HeaderType> extends ContainerArgument<
TableData<CellType, HeaderType>
> {
constructor(
public header_type: ComponentArgument<HeaderType, unknown, unknown>,
public cell_type: ComponentArgument<CellType, unknown, unknown>
) {
super();
cell_type.parent_argument = this;
header_type.parent_argument = this;
}
getSubArgument(
[_, key, ...rest]: string[],
value: TableData<CellType, HeaderType>
) {
if (isNaN(parseInt(key))) {
return <const>[null, [] as string[], null];
}
const key_n = parseInt(key);
const row = value.rows[key_n];
if (!row) {
return <const>[null, [] as string[], null];
} else if (row.type == "header") {
rest.shift();
return <const>[this.header_type, rest, row.header_content];
} else {
let cell_index = rest.shift();
if (cell_index == "cells") {
cell_index = rest.shift();
}
if (!cell_index) {
throw new Error("Missing cell index");
}
const parsed_cell_index = parseInt(cell_index);
if (isNaN(parsed_cell_index)) {
throw new Error(
`Cell index should be a number, got: ${cell_index}`
);
}
return <const>[this.cell_type, rest, row.cells[parsed_cell_index]];
}
}
getTypeName() {
return "table";
}
async getEmptyValue(context: JDDContext) {
return {
rows: [
{
type: <const>"header",
header_content: await this.header_type.getEmptyValue(
context
),
},
{
type: <const>"row",
cells: [await this.cell_type.getEmptyValue(context)],
},
],
};
}
async getExampleValue(context: JDDContext) {
+ if (this.example_values.length) {
+ return this.example_values[
+ Math.floor(this.example_values.length * Math.random())
+ ];
+ }
const rows = Math.round(Math.random() * 5);
const columns = Math.round(Math.random() * 5);
const result: TableData<CellType, HeaderType> = {
rows: [
{
type: "header",
header_content: await this.header_type.getExampleValue(
context
),
},
],
};
for (let i = 0; i < rows; i++) {
const cells: CellType[] = [];
for (let j = 0; j < columns; j++) {
// eslint-disable-next-line no-await-in-loop
cells.push(await this.cell_type.getExampleValue(context));
}
result.rows.push({ type: "row", cells });
}
return result;
}
countWords(value: TableData<CellType, HeaderType>): number {
let result = 0;
for (let i = 0; i < value.rows.length; i++) {
const row = value.rows[i];
if (isTableHeader(row)) {
result += this.header_type.countWords(row.header_content);
} else {
for (let j = 0; j < row.cells.length; j++) {
result += this.cell_type.countWords(row.cells[j]);
}
}
}
return result;
}
async processAllSubarguments(
context: JDDContext,
input: unknown,
processing_function: (
argument: ComponentArgument<unknown>,
value: unknown
) => Promise<unknown>
) {
if (!hasShape({ rows: predicates.array(predicates.object) }, input)) {
return { rows: [] };
} else {
const result: TableData<CellType, HeaderType> = { rows: [] };
const row_promises = input.rows.map(async (row, row_index) => {
let new_row: TableRow<CellType, HeaderType>;
if (hasShape({ header_content: predicates.unknown }, row)) {
let header_content = (await processing_function(
this.header_type,
row.header_content
)) as HeaderType | HeaderType[] | null;
if (Array.isArray(header_content)) {
header_content = header_content[0];
}
if (header_content == null) {
header_content = await this.header_type.getEmptyValue(
context
);
}
new_row = {
type: "header",
header_content,
};
result.rows[row_index] = new_row;
} else if (
hasShape(
{ cells: predicates.array(predicates.unknown) },
row
)
) {
new_row = {
type: "row",
cells: await Promise.all(
row.cells.map(async (cell) => {
const value = (await processing_function(
this.cell_type,
cell
)) as CellType | CellType[] | null;
if (value === null) {
return this.cell_type.getEmptyValue(
context
);
} else if (Array.isArray(value)) {
return value[0];
} else {
return value;
}
})
),
};
result.rows[row_index] = new_row;
}
});
await Promise.all(row_promises);
return result;
}
}
getColumnsCount(value: TableData<CellType, HeaderType>) {
return (
(
(
value.rows.filter((row) => row.type == "row")[0] as
| TableRegularRow<CellType>
| undefined
)?.cells || []
).length || 1
);
}
}
diff --git a/src/jdd-context.ts b/src/jdd-context.ts
index d2259be..cc10aa9 100644
--- a/src/jdd-context.ts
+++ b/src/jdd-context.ts
@@ -1,87 +1,89 @@
import {
FileManager,
FilePointer,
PathFilePointer,
} from "@sealcode/file-manager";
import type { KoaResponsiveImageRouter } from "koa-responsive-image-router";
import { Renderer, marked } from "marked";
import { FlatTemplatable } from "tempstream";
import { insert_nbsp } from "./utils/insert_nbsp.js";
import { get_hyphenator } from "./hyphenation.js";
import { Token } from "marked";
import slug from "slug";
import { decode } from "html-entities";
import type * as Koa from "koa";
export interface JDDContext {
render_image: (
file_id: FilePointer | string | null,
args: Parameters<KoaResponsiveImageRouter["image"]>[1]
) => FlatTemplatable;
render_markdown: (
language: string,
markdown: string
) => string | Promise<string>;
hyphenate: (language: string, text: string) => Promise<string>;
encode_file: (photo: FilePointer, persistent: boolean) => Promise<string>;
decode_file: (token: string) => Promise<PathFilePointer | null>;
file_manager: FileManager;
language: string;
ctx: Koa.Context;
}
class RendererWithHeadings extends Renderer {
heading(text: string, depth: number): string {
const id = slug(decode(text));
return /* HTML */ ` <h${depth} id="${id}">
<a class="anchor" href="#${id}">
<span class="markdown-header-link"></span>
</a>
${text}
</h${depth}>`;
}
}
export const makeSimpleJDDContext: (
file_manager: FileManager
) => Omit<JDDContext, "language"> = (file_manager) => ({
render_image: async (file) => {
if (typeof file == "string") {
file = await file_manager.fromToken(file);
}
const path = (await file?.getPath()) || "/some-path";
return file ? /* HTML */ `<img src="file://${path}}" />` : "";
},
hyphenate: async (language: string, text: string) => {
const hyphenator = await get_hyphenator(language);
return hyphenator(text);
},
render_markdown: async (language, string) => {
const hyphenator = await get_hyphenator(language);
return string
? marked.parse(insert_nbsp(string), {
walkTokens: (token: Token) => {
if (token.type == "text") {
token.text = hyphenator(token.text as string);
}
},
renderer: new RendererWithHeadings(),
})
: "";
},
encode_file: (photo: FilePointer, persistent: boolean) => {
return photo.save(persistent);
},
decode_file: (token: string) => {
return file_manager.fromToken(token);
},
file_manager,
ctx: {} as unknown as Koa.Context,
});
export const makeSimpleEnglishJDDContext: (
- file_manager: FileManager
-) => JDDContext = (file_manager) => ({
+ file_manager?: FileManager
+) => JDDContext = (
+ file_manager = new FileManager("/tmp", "/uploaded_files")
+) => ({
...makeSimpleJDDContext(file_manager),
language: "en-us",
});

File Metadata

Mime Type
text/x-diff
Expires
Sun, Nov 24, 00:32 (1 d, 17 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
548043
Default Alt Text
(10 KB)

Event Timeline