Page Menu
Home
Sealhub
Search
Configure Global Search
Log In
Files
F996028
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
10 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/src/component-arguments/component-argument.ts b/src/component-arguments/component-argument.ts
index e8beed9..4d3fe7c 100644
--- a/src/component-arguments/component-argument.ts
+++ b/src/component-arguments/component-argument.ts
@@ -1,89 +1,90 @@
-import { JDDContext, List } from "../index.js";
-
-export type ExtractComponentArgumentValue<C> = C extends List<infer S>
- ? S[]
- : C extends ComponentArgument<infer T>
- ? T
- : never;
+import { JDDContext } from "../index.js";
+import { List } from "./list.js";
export type ExtractStructuredComponentArgumentsParsed<C> = {
- [property in keyof C]: ExtractComponentArgumentValue<C[property]>;
+ [property in keyof C]: ExtractParsed<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 ExtractParsed<C> = C extends ComponentArgument<infer T> ? T : never;
+export type ExtractParsed<C> = C extends List<infer T>
+ ? T[]
+ : C extends ComponentArgument<infer T2>
+ ? T2
+ : 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 abstract class ComponentArgument<
ParsedType,
StorageType = ParsedType,
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>;
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/list.test.ts b/src/component-arguments/list.test.ts
index 58d64a3..556f466 100644
--- a/src/component-arguments/list.test.ts
+++ b/src/component-arguments/list.test.ts
@@ -1,8 +1,15 @@
+import { ExtractParsed } from "./component-argument.js";
import { Image } from "./image.js";
import { List } from "./list.js";
describe("list", () => {
it("allows for creating a list of images", () => {
new List(new Image());
});
+
+ it("properly parses list arguments", () => {
+ const images_arg = new List(new Image());
+ const images = [] as ExtractParsed<typeof images_arg>;
+ images.map((e) => e?.file_manager); // if the types are right, this should typecheck OK
+ });
});
diff --git a/src/component-arguments/list.ts b/src/component-arguments/list.ts
index becdcb9..5ed4382 100644
--- a/src/component-arguments/list.ts
+++ b/src/component-arguments/list.ts
@@ -1,94 +1,90 @@
import { is, predicates } from "@sealcode/ts-predicates";
-import { JDDContext } from "../index.js";
import { MaybePromise } from "../utils/util-types.js";
-import { ComponentArgument, ExtractParsed } from "./component-argument.js";
+import { ComponentArgument } from "./component-argument.js";
import { ContainerArgument } from "./container-argument.js";
+import { JDDContext } from "../jdd-context.js";
-export class List<
- T extends ComponentArgument<unknown>
-> extends ContainerArgument<ExtractParsed<T>[], unknown, unknown> {
+export class List<T> extends ContainerArgument<T[], unknown, unknown> {
constructor(
- public item_type: ComponentArgument<ExtractParsed<T>, unknown, unknown>,
+ public item_type: ComponentArgument<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) {
+ async getExampleValue(context: JDDContext): Promise<T[]> {
if (this.example_values.length) {
return super.getExampleValue(context);
} else {
const count = this.getExampleCount();
- const result = [] as Array<MaybePromise<ExtractParsed<T>>>;
+ const result = [] as Array<MaybePromise<T>>;
for (let i = 0; i < count; i++) {
result.push(
- this.item_type.getExampleValue(context) as Promise<
- ExtractParsed<T>
- >
+ this.item_type.getExampleValue(context) as Promise<T>
);
}
return await Promise.all(result);
}
}
- countWords(value: Array<ExtractParsed<T>>): number {
+ countWords(value: Array<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-arguments/structured.ts b/src/component-arguments/structured.ts
index 58254de..07be295 100644
--- a/src/component-arguments/structured.ts
+++ b/src/component-arguments/structured.ts
@@ -1,137 +1,137 @@
import { is, predicates } from "@sealcode/ts-predicates";
import { JDDContext } from "../index.js";
import {
ComponentArgument,
- ExtractComponentArgumentValue,
+ ExtractParsed,
ExtractStorage,
} from "./component-argument.js";
import { ContainerArgument } from "./container-argument.js";
export class Structured<
T extends Record<string, ComponentArgument<unknown>>
> extends ContainerArgument<
{
- [property in keyof T]: ExtractComponentArgumentValue<T[property]>;
+ [property in keyof T]: ExtractParsed<T[property]>;
},
{
[property in keyof T]: ExtractStorage<T[property]>;
}
> {
constructor(public structure: T) {
super();
Object.values(structure).forEach((arg) => (arg.parent_argument = this));
}
getTypeName() {
return "structured";
}
getSubArgument(key: string) {
return this.structure[key] || null;
}
countWords(value: {
- [property in keyof T]: ExtractComponentArgumentValue<T[property]>;
+ [property in keyof T]: ExtractParsed<T[property]>;
}): number {
return Object.entries(value).reduce((acc, [key, val]) => {
if (!this.structure[key]) {
console.warn(`Key ${key} doesn't exist in structured argument`);
return acc + 0;
}
return acc + this.structure[key].countWords(val);
}, 0);
}
getEmptyValue() {
return Object.fromEntries(
Object.entries(this.structure).map(([name, arg]) => [
name,
arg.getEmptyValue(),
])
) as {
- [property in keyof T]: ExtractComponentArgumentValue<T[property]>;
+ [property in keyof T]: ExtractParsed<T[property]>;
};
}
async getExampleValue(context: JDDContext) {
return Object.fromEntries(
await Promise.all(
Object.entries(this.structure).map(async ([name, arg]) => [
name,
await arg.getExampleValue(context),
])
)
) as {
- [property in keyof T]: ExtractComponentArgumentValue<T[property]>;
+ [property in keyof T]: ExtractParsed<T[property]>;
};
}
async processAllSubarguments<
SingleObject extends {
- [property in keyof T]: ExtractComponentArgumentValue<T[property]>;
+ [property in keyof T]: ExtractParsed<T[property]>;
}
>(
_context: JDDContext,
input: unknown,
processing_function: (
argument: ComponentArgument<unknown>,
value: unknown
) => Promise<unknown>
): Promise<SingleObject | SingleObject[] | null> {
if (!is(input, predicates.object)) {
throw new Error(`Not an object: ${input as string}`);
}
const result: Record<string, unknown> = {};
await Promise.all(
Object.entries(input).map(async ([obj_key, obj_value]) => {
const nested_arg_type: ComponentArgument<unknown> =
this.structure[obj_key];
if (!nested_arg_type) {
return [obj_key, null];
}
const new_value = await processing_function(
nested_arg_type,
obj_value
);
result[obj_key] = new_value;
})
);
// if we're in a list and any of the values return an array, we will multiply the object
if (this.hasParent("list")) {
const keys_with_unexpected_arrays = Object.entries(result)
.filter(([key, value]) => {
const nested_arg_type: ComponentArgument<unknown> =
this.structure[key];
return (
nested_arg_type.getTypeName() !== "list" &&
Array.isArray(value)
);
})
.map(([key]) => key);
if (keys_with_unexpected_arrays.length > 1) {
throw new Error(
"Multiplying on more than one field at the same time is not implemented yet"
);
}
if (keys_with_unexpected_arrays.length == 1) {
const key = keys_with_unexpected_arrays[0];
const old_result = result;
const array = old_result[key];
if (!Array.isArray(array)) {
throw new Error("expected an array");
}
return array.map((value: unknown) => ({
...old_result,
[key]: value,
})) as SingleObject[];
} else {
return result as SingleObject;
}
} else {
return result as SingleObject;
}
}
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Tue, Dec 24, 07:37 (1 d, 3 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
557039
Default Alt Text
(10 KB)
Attached To
Mode
R130 jdd
Attached
Detach File
Event Timeline
Log In to Comment