Page MenuHomeSealhub

No OneTemporary

diff --git a/src/component-arguments/component-argument.ts b/src/component-arguments/component-argument.ts
index 1627bb1..e8beed9 100644
--- a/src/component-arguments/component-argument.ts
+++ b/src/component-arguments/component-argument.ts
@@ -1,109 +1,89 @@
import { JDDContext, List } from "../index.js";
export type ExtractComponentArgumentValue<C> = C extends List<infer S>
? S[]
: C extends ComponentArgument<infer T>
? T
: never;
export type ExtractStructuredComponentArgumentsParsed<C> = {
[property in keyof C]: ExtractComponentArgumentValue<C[property]>;
};
export type ExtractStructuredComponentArgumentsStorage<C> = {
[property in keyof C]: ExtractStorage<C[property]>;
};
export type ExtractStructuredComponentArgumentsReceived<C> = {
[property in keyof C]: ExtractReceived<C[property]>;
};
-export type ExtractStructuredComponentArgumentsFormdata<C> = {
- [property in keyof C]: ExtractFormData<C[property]>;
-};
-
export type ExtractParsed<C> = C extends ComponentArgument<infer T> ? T : never;
export type ExtractStorage<C> = C extends ComponentArgument<infer _, infer T>
? T
: never;
export type ExtractReceived<C> = C extends ComponentArgument<
infer _,
infer __,
infer T
>
? T
: never;
-export type ExtractFormData<C> = C extends ComponentArgument<
- infer _,
- infer __,
- infer ___,
- infer T
->
- ? T
- : never;
export abstract class ComponentArgument<
ParsedType,
StorageType = ParsedType,
- ReceivedDataType = StorageType,
- FormDataType extends Record<string, unknown> | string =
- | Record<string, unknown>
- | string
+ ReceivedDataType = StorageType
> {
public example_values: ParsedType[] = [];
public parent_argument: ComponentArgument<unknown> | null = null;
abstract getTypeName(): string;
abstract getEmptyValue(): ParsedType;
abstract countWords(value: ParsedType): number;
abstract getSubArgument(
key: string,
value: ParsedType
): ComponentArgument<unknown> | null;
// Received - what we get on the server side when receiveing the request
// Parsed - the useful form of the value, ready for processing
// Storage - how it's represented when storing in a JSON form
// Formdata - how it's represented when it needs to be sent to the server
abstract receivedToParsed(
context: JDDContext,
value: ReceivedDataType
): Promise<ParsedType | ParsedType[]>;
abstract parsedToStorage(
context: JDDContext,
value: ParsedType
): Promise<StorageType>;
abstract storageToParsed(
context: JDDContext,
value: StorageType
): Promise<ParsedType>;
- abstract parsedToFormData(
- context: JDDContext,
- value: ParsedType
- ): Promise<FormDataType>;
-
getExampleValue(_context: JDDContext): Promise<ParsedType> | ParsedType {
return this.example_values[
Math.floor(this.example_values.length * Math.random())
];
}
setExampleValues(values: ParsedType[]): this {
this.example_values = values;
return this;
}
hasParent(type: string) {
let parent = this.parent_argument;
while (parent) {
if (parent.getTypeName() == type) {
return true;
}
parent = parent.parent_argument;
}
return false;
}
}
diff --git a/src/component-arguments/container-argument.ts b/src/component-arguments/container-argument.ts
index 120d784..7c26e88 100644
--- a/src/component-arguments/container-argument.ts
+++ b/src/component-arguments/container-argument.ts
@@ -1,60 +1,47 @@
import { JDDContext } from "../jdd-context.js";
import { ComponentArgument } from "./component-argument.js";
export abstract class ContainerArgument<
P,
S = P,
- R = P,
- F extends Record<string, unknown> | string =
- | Record<string, unknown>
- | string
-> extends ComponentArgument<P, S, R, F> {
+ R = P
+> extends ComponentArgument<P, S, R> {
abstract processAllSubarguments(
context: JDDContext,
values: unknown,
processing_function: (
argument: ComponentArgument<unknown>,
value: unknown
) => Promise<unknown>
): unknown;
async receivedToParsed(context: JDDContext, value: R): Promise<P> {
return this.processAllSubarguments(
context,
value,
(argument: ComponentArgument<unknown>, value: unknown) => {
return argument.receivedToParsed(context, value);
}
) as P;
}
async parsedToStorage(context: JDDContext, value: P): Promise<S> {
return this.processAllSubarguments(
context,
value,
(argument: ComponentArgument<unknown>, value: unknown) => {
return argument.parsedToStorage(context, value);
}
) as S;
}
async storageToParsed(context: JDDContext, value: S): Promise<P> {
return this.processAllSubarguments(
context,
value,
(argument: ComponentArgument<unknown>, value: unknown) => {
return argument.storageToParsed(context, value);
}
) as P;
}
-
- async parsedToFormData(context: JDDContext, value: P): Promise<F> {
- return this.processAllSubarguments(
- context,
- value,
- (argument: ComponentArgument<unknown>, value: unknown) => {
- return argument.parsedToFormData(context, value);
- }
- ) as F;
- }
}
diff --git a/src/component-arguments/file.ts b/src/component-arguments/file.ts
index 6193323..1555cc9 100644
--- a/src/component-arguments/file.ts
+++ b/src/component-arguments/file.ts
@@ -1,82 +1,81 @@
import { JDDContext } from "../index.js";
import { ComponentArgument } from "./component-argument.js";
import { FilePointer } from "@sealcode/file-manager";
type FileReceivedType = {
old: FilePointer | null;
new: FilePointer[] | FilePointer | null;
};
type FileFormDataType = {
old: string | null;
new?: unknown; // the browser will take care of setting a value to thag attribute via html input, we don't need to model this
};
export class File extends ComponentArgument<
FilePointer | null,
string | null,
- FileReceivedType,
- FileFormDataType
+ FileReceivedType
> {
constructor() {
super();
}
getTypeName() {
return "file";
}
getEmptyValue() {
return null;
}
getSubArgument() {
return null;
}
async getExampleValue(_context: JDDContext): Promise<FilePointer | null> {
return null;
}
countWords(): number {
return 0;
}
async receivedToParsed(_context: JDDContext, value: FileReceivedType) {
if (value.new && Array.isArray(value.new)) {
if (value.new.length == 0) {
return value.old || null;
} else if (value.new.length == 1) {
await value.new[0].save(true);
return value.new[0];
} else {
await Promise.all(value.new.map((f) => f.save(true)));
return value.new;
}
} else {
return value.old || null;
}
}
async parsedToStorage(_context: JDDContext, value: FilePointer | null) {
if (!value) {
return null;
}
await value.save(true);
return value.token;
}
async storageToParsed(
context: JDDContext,
value: string | null
): Promise<FilePointer | null> {
return value ? context.file_manager.fromToken(value) : null;
}
async parsedToFormData(
_context: JDDContext,
value: FilePointer | null
): Promise<FileFormDataType> {
return { old: value?.token || null };
}
}
diff --git a/src/component-arguments/list.test.ts b/src/component-arguments/list.test.ts
new file mode 100644
index 0000000..58d64a3
--- /dev/null
+++ b/src/component-arguments/list.test.ts
@@ -0,0 +1,8 @@
+import { Image } from "./image.js";
+import { List } from "./list.js";
+
+describe("list", () => {
+ it("allows for creating a list of images", () => {
+ new List(new Image());
+ });
+});
diff --git a/src/component-arguments/list.ts b/src/component-arguments/list.ts
index 669385a..becdcb9 100644
--- a/src/component-arguments/list.ts
+++ b/src/component-arguments/list.ts
@@ -1,91 +1,94 @@
import { is, predicates } from "@sealcode/ts-predicates";
import { JDDContext } from "../index.js";
import { MaybePromise } from "../utils/util-types.js";
-import { ComponentArgument, ExtractStorage } from "./component-argument.js";
+import { ComponentArgument, ExtractParsed } from "./component-argument.js";
import { ContainerArgument } from "./container-argument.js";
-export class List<T, TS = ExtractStorage<T>> extends ContainerArgument<
- Array<T>,
- Array<TS>
-> {
+export class List<
+ T extends ComponentArgument<unknown>
+> extends ContainerArgument<ExtractParsed<T>[], unknown, unknown> {
constructor(
- public item_type: ComponentArgument<T>,
+ public item_type: ComponentArgument<ExtractParsed<T>, unknown, unknown>,
public example_count: number | null = null
) {
super();
item_type.parent_argument = this;
}
getTypeName() {
return "list";
}
getEmptyValue() {
return [];
}
getSubArgument(key: string) {
if (isNaN(parseInt(key))) {
return null;
}
return this.item_type;
}
getExampleCount() {
if (this.example_count === null) {
return Math.floor(Math.random() * 5);
} else {
return this.example_count;
}
}
async getExampleValue(context: JDDContext) {
if (this.example_values.length) {
return super.getExampleValue(context);
} else {
const count = this.getExampleCount();
- const result = [] as Array<MaybePromise<T>>;
+ const result = [] as Array<MaybePromise<ExtractParsed<T>>>;
for (let i = 0; i < count; i++) {
- result.push(this.item_type.getExampleValue(context));
+ result.push(
+ this.item_type.getExampleValue(context) as Promise<
+ ExtractParsed<T>
+ >
+ );
}
- return (await Promise.all(result)) as Array<T>;
+ return await Promise.all(result);
}
}
- countWords(value: Array<T>): number {
+ countWords(value: Array<ExtractParsed<T>>): number {
return value.reduce(
(acc, item) => acc + this.item_type.countWords(item),
0
);
}
async processAllSubarguments(
_context: JDDContext,
values: unknown,
processing_function: (
argument: ComponentArgument<unknown>,
value: unknown
) => Promise<unknown>
): Promise<T[] | null> {
if (
!is(values, predicates.array(predicates.object)) &&
!is(values, predicates.object)
) {
throw new Error(`Not a list or object: ${values as string}`);
}
const values_array = Array.isArray(values)
? values
: Object.values(values);
let array_result = (await Promise.all(
values_array.map(async (value) => {
const result = await processing_function(this.item_type, value);
return result;
})
)) as Array<T | T[] | null>;
if (this.item_type.getTypeName() != "list") {
array_result = array_result.flat() as T[];
}
const result = array_result.filter((e) => e !== null) as T[];
return result;
}
}
diff --git a/src/component.ts b/src/component.ts
index fbc3803..868d138 100644
--- a/src/component.ts
+++ b/src/component.ts
@@ -1,165 +1,146 @@
import { FlatTemplatable } from "tempstream";
import {
ComponentArgument,
- ExtractStructuredComponentArgumentsFormdata,
ExtractStructuredComponentArgumentsParsed,
ExtractStructuredComponentArgumentsReceived,
ExtractStructuredComponentArgumentsStorage,
JDDContext,
} from "./index.js";
export interface ComponentConstructor<
A extends Record<string, ComponentArgument<unknown>> = Record<
string,
ComponentArgument<unknown>
>
> {
new (): Component<A>;
}
export type EarlyAsset = (
| { type: "script" | "style"; url: string; integrity?: string }
| { type: "script" | "style"; content: string }
) & { identity: string }; // identity key will be used for deduplication
export abstract class Component<
ArgumentsT extends Record<string, ComponentArgument<unknown>> = Record<
string,
ComponentArgument<unknown>
>
> {
abstract getArguments(): ArgumentsT;
abstract toHTML(
args: ExtractStructuredComponentArgumentsParsed<ArgumentsT>,
context: JDDContext
): FlatTemplatable;
async getEarlyAssets(
_args: ExtractStructuredComponentArgumentsParsed<ArgumentsT>,
_context: JDDContext
): Promise<EarlyAsset[]> {
return [];
}
countWords(args: Record<string, unknown>): number {
return Object.entries(args).reduce((acc, [arg_name, value]) => {
const arg = this.getArguments()[arg_name];
if (!arg) {
console.warn(
`Arguemnt ${arg_name} was not found in the component`
);
return acc + 0;
}
return acc + arg.countWords(value);
}, 0);
}
async getExampleValues(
context: JDDContext
): Promise<ExtractStructuredComponentArgumentsParsed<ArgumentsT>> {
return Object.fromEntries(
await Promise.all(
Object.entries(this.getArguments()).map(
async ([key, value]) => [
key,
await value.getExampleValue(context),
]
)
)
) as ExtractStructuredComponentArgumentsParsed<ArgumentsT>;
}
async convertReceivedValuesToParsed(
context: JDDContext,
values: ExtractStructuredComponentArgumentsReceived<ArgumentsT>
): Promise<ExtractStructuredComponentArgumentsParsed<ArgumentsT>> {
const args = this.getArguments();
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
return Object.fromEntries(
await Promise.all(
Object.entries(values).map(async ([key, value]) => {
return [
key,
await args[key].receivedToParsed(context, value),
];
})
)
);
}
async convertParsedToStorage(
context: JDDContext,
values: ExtractStructuredComponentArgumentsParsed<ArgumentsT>
): Promise<ExtractStructuredComponentArgumentsStorage<ArgumentsT>> {
const args = this.getArguments();
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
return Object.fromEntries(
await Promise.all(
Object.entries(values).map(async ([key, value]) => {
return [
key,
await args[key].parsedToStorage(context, value),
];
})
)
);
}
async convertStorageToParsed(
context: JDDContext,
values: ExtractStructuredComponentArgumentsStorage<ArgumentsT>
): Promise<ExtractStructuredComponentArgumentsParsed<ArgumentsT>> {
const args = this.getArguments();
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
return Object.fromEntries(
await Promise.all(
Object.entries(values).map(async ([key, value]) => {
return [
key,
await args[key].storageToParsed(context, value),
];
})
)
);
}
- async convertParsedToFormdata(
- context: JDDContext,
- values: ExtractStructuredComponentArgumentsParsed<ArgumentsT>
- ): Promise<ExtractStructuredComponentArgumentsFormdata<ArgumentsT>> {
- const args = this.getArguments();
- // eslint-disable-next-line @typescript-eslint/no-unsafe-return
- return Object.fromEntries(
- await Promise.all(
- Object.entries(values).map(async ([key, value]) => {
- return [
- key,
- await args[key].parsedToFormData(context, value),
- ];
- })
- )
- );
- }
-
getArgumentAtPath(
argument_path: string[],
values: ExtractStructuredComponentArgumentsParsed<ArgumentsT>
): ComponentArgument<unknown> | null {
argument_path = [...argument_path];
if (argument_path.length == 0) {
return null;
}
let argument: ComponentArgument<unknown> | null =
this.getArguments()[argument_path.shift() as string];
if (argument_path.length == 0) {
return argument;
}
do {
argument = argument.getSubArgument(
argument_path.shift() as string,
values
);
} while (argument_path.length && argument !== null);
return argument;
}
}

File Metadata

Mime Type
text/x-diff
Expires
Sat, Nov 8, 12:33 (15 h, 11 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1034581
Default Alt Text
(15 KB)

Event Timeline