@sealcode/sealgen 0.15.59 → 0.15.61
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
import Router from "@koa/router";
|
|
3
3
|
import { BaseContext, Context } from "koa";
|
|
4
4
|
import { Templatable } from "tempstream";
|
|
5
|
-
import { ExtractTail } from "../utils/utils.js";
|
|
6
5
|
import { Mountable } from "./mountable.js";
|
|
7
6
|
export type StatefulPageActionDescription<ActionName> = {
|
|
8
7
|
action: ActionName;
|
|
@@ -22,7 +21,16 @@ export type StateAndMetadata<State, Actions> = {
|
|
|
22
21
|
action_args: null;
|
|
23
22
|
$: Record<string, unknown>;
|
|
24
23
|
};
|
|
25
|
-
export
|
|
24
|
+
export type StatefulPageActionArgument<State extends Record<string, unknown>, Args extends unknown[] = unknown[]> = {
|
|
25
|
+
ctx: BaseContext;
|
|
26
|
+
state: State;
|
|
27
|
+
inputs: Record<string, string>;
|
|
28
|
+
args: Args;
|
|
29
|
+
page: StatefulPage<any, any>;
|
|
30
|
+
};
|
|
31
|
+
export type StatefulPageAction<State extends Record<string, unknown>, Args extends unknown[] = unknown[]> = (obj: StatefulPageActionArgument<State, Args>) => State | Promise<State>;
|
|
32
|
+
export type ExtractStatefulPageActionArgs<X> = X extends StatefulPageAction<any, infer Args> ? Args : never;
|
|
33
|
+
export declare abstract class StatefulPage<State extends Record<string, unknown>, Actions extends Record<string, StatefulPageAction<State>>> extends Mountable {
|
|
26
34
|
abstract actions: Actions;
|
|
27
35
|
abstract getInitialState(ctx: BaseContext): State | Promise<State>;
|
|
28
36
|
abstract render(ctx: BaseContext, state: State, inputs: Record<string, string>): Templatable | Promise<Templatable>;
|
|
@@ -39,12 +47,12 @@ export declare abstract class StatefulPage<State extends Record<string, unknown>
|
|
|
39
47
|
content: string;
|
|
40
48
|
disabled: boolean;
|
|
41
49
|
};
|
|
42
|
-
makeActionURL<ActionName extends keyof Actions>(action_description: StatefulPageActionDescription<ActionName>, ...args:
|
|
43
|
-
makeActionButton<ActionName extends keyof Actions>(_state: State, action_description: StatefulPageActionDescription<ActionName>, ...args:
|
|
50
|
+
makeActionURL<ActionName extends keyof Actions>(action_description: StatefulPageActionDescription<ActionName>, ...args: ExtractStatefulPageActionArgs<Actions[ActionName]>): string;
|
|
51
|
+
makeActionButton<ActionName extends keyof Actions>(_state: State, action_description: StatefulPageActionDescription<ActionName>, ...args: ExtractStatefulPageActionArgs<Actions[ActionName]>): string;
|
|
44
52
|
makeActionCallback<ActionName extends keyof Actions>(action_description: {
|
|
45
53
|
action: ActionName;
|
|
46
54
|
label?: string;
|
|
47
|
-
} | ActionName, ...args:
|
|
55
|
+
} | ActionName, ...args: ExtractStatefulPageActionArgs<Actions[ActionName]>): string;
|
|
48
56
|
rerender(): string;
|
|
49
57
|
preprocessState(values: State): Promise<State>;
|
|
50
58
|
preprocessOverrides(_context: BaseContext, _state: State, values: Record<string, unknown>): Promise<Record<string, unknown>>;
|
|
@@ -176,14 +176,15 @@ class StatefulPage extends Mountable {
|
|
|
176
176
|
router.post(path, async (ctx) => {
|
|
177
177
|
const { action, state, inputs, action_args } = await this.extractState(ctx);
|
|
178
178
|
if (action) {
|
|
179
|
-
const new_state = await this.actions[action](
|
|
179
|
+
const new_state = await this.actions[action]({
|
|
180
180
|
ctx,
|
|
181
181
|
state,
|
|
182
182
|
inputs,
|
|
183
|
-
|
|
183
|
+
args: JSON.parse(
|
|
184
184
|
from_base64(action_args)
|
|
185
|
-
)
|
|
186
|
-
|
|
185
|
+
),
|
|
186
|
+
page: this
|
|
187
|
+
});
|
|
187
188
|
ctx.body = this.render(ctx, new_state, inputs);
|
|
188
189
|
} else {
|
|
189
190
|
ctx.body = this.render(ctx, state, inputs);
|
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
import { tempstream } from "tempstream";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
StatefulPage
|
|
4
|
+
} from "./stateful-page.js";
|
|
3
5
|
describe("stateful page", () => {
|
|
6
|
+
it("has types that allow for extracting action argument types", () => {
|
|
7
|
+
const action = async ({}) => {
|
|
8
|
+
};
|
|
9
|
+
const a = [2];
|
|
10
|
+
});
|
|
4
11
|
it("handles a basic case with action buttons", () => {
|
|
5
12
|
const actions = {
|
|
6
|
-
some_action: async (
|
|
13
|
+
some_action: async ({}) => {
|
|
7
14
|
}
|
|
8
15
|
};
|
|
9
16
|
new class extends StatefulPage {
|
package/package.json
CHANGED
|
@@ -1,17 +1,23 @@
|
|
|
1
1
|
import { BaseContext } from "koa";
|
|
2
2
|
import { Templatable, tempstream } from "tempstream";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
ExtractStatefulPageActionArgs,
|
|
5
|
+
StatefulPage,
|
|
6
|
+
StatefulPageActionArgument,
|
|
7
|
+
} from "./stateful-page.js";
|
|
4
8
|
|
|
5
9
|
describe("stateful page", () => {
|
|
10
|
+
it("has types that allow for extracting action argument types", () => {
|
|
11
|
+
type TestState = {};
|
|
12
|
+
const action = async ({}: StatefulPageActionArgument<TestState, [number]>) => {};
|
|
13
|
+
type Args = ExtractStatefulPageActionArgs<typeof action>;
|
|
14
|
+
const a = [2] as Args; // should not throw a typescript error;
|
|
15
|
+
});
|
|
16
|
+
|
|
6
17
|
it("handles a basic case with action buttons", () => {
|
|
7
18
|
type TestState = {};
|
|
8
19
|
const actions = <const>{
|
|
9
|
-
some_action: async (
|
|
10
|
-
_ctx: BaseContext,
|
|
11
|
-
_state: TestState,
|
|
12
|
-
_inputs: Record<string, unknown>,
|
|
13
|
-
_arg1: number
|
|
14
|
-
) => {},
|
|
20
|
+
some_action: async ({}: StatefulPageActionArgument<TestState, [number]>) => {},
|
|
15
21
|
};
|
|
16
22
|
new (class extends StatefulPage<TestState, typeof actions> {
|
|
17
23
|
actions = actions;
|
|
@@ -5,7 +5,6 @@ import deepmerge, { ArrayMergeOptions } from "deepmerge";
|
|
|
5
5
|
import { BaseContext, Context } from "koa";
|
|
6
6
|
import { Templatable, tempstream } from "tempstream";
|
|
7
7
|
import { from_base64, to_base64 } from "../utils/base64.js";
|
|
8
|
-
import { ExtractTail } from "../utils/utils.js";
|
|
9
8
|
import { Mountable } from "./mountable.js";
|
|
10
9
|
import { isPlainObject } from "is-what";
|
|
11
10
|
|
|
@@ -33,17 +32,32 @@ export type StateAndMetadata<State, Actions> =
|
|
|
33
32
|
$: Record<string, unknown>;
|
|
34
33
|
};
|
|
35
34
|
|
|
35
|
+
export type StatefulPageActionArgument<
|
|
36
|
+
State extends Record<string, unknown>,
|
|
37
|
+
Args extends unknown[] = unknown[]
|
|
38
|
+
> = {
|
|
39
|
+
ctx: BaseContext;
|
|
40
|
+
state: State;
|
|
41
|
+
inputs: Record<string, string>;
|
|
42
|
+
args: Args;
|
|
43
|
+
page: StatefulPage<any, any>;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export type StatefulPageAction<
|
|
47
|
+
State extends Record<string, unknown>,
|
|
48
|
+
Args extends unknown[] = unknown[]
|
|
49
|
+
> = (obj: StatefulPageActionArgument<State, Args>) => State | Promise<State>;
|
|
50
|
+
|
|
51
|
+
export type ExtractStatefulPageActionArgs<X> = X extends StatefulPageAction<
|
|
52
|
+
any,
|
|
53
|
+
infer Args
|
|
54
|
+
>
|
|
55
|
+
? Args
|
|
56
|
+
: never;
|
|
57
|
+
|
|
36
58
|
export abstract class StatefulPage<
|
|
37
59
|
State extends Record<string, unknown>,
|
|
38
|
-
Actions extends Record<
|
|
39
|
-
string,
|
|
40
|
-
(
|
|
41
|
-
ctx: BaseContext,
|
|
42
|
-
state: State,
|
|
43
|
-
inputs: Record<string, string>,
|
|
44
|
-
...args: unknown[]
|
|
45
|
-
) => State | Promise<State>
|
|
46
|
-
>
|
|
60
|
+
Actions extends Record<string, StatefulPageAction<State>>
|
|
47
61
|
> extends Mountable {
|
|
48
62
|
abstract actions: Actions;
|
|
49
63
|
abstract getInitialState(ctx: BaseContext): State | Promise<State>;
|
|
@@ -123,9 +137,7 @@ export abstract class StatefulPage<
|
|
|
123
137
|
|
|
124
138
|
makeActionURL<ActionName extends keyof Actions>(
|
|
125
139
|
action_description: StatefulPageActionDescription<ActionName>,
|
|
126
|
-
...args:
|
|
127
|
-
ExtractTail<ExtractTail<Parameters<Actions[ActionName]>>>
|
|
128
|
-
>
|
|
140
|
+
...args: ExtractStatefulPageActionArgs<Actions[ActionName]>
|
|
129
141
|
) {
|
|
130
142
|
const { action } = this.extractActionAndLabel(action_description);
|
|
131
143
|
return `./?action=${action}&action_args=${encodeURIComponent(
|
|
@@ -137,9 +149,7 @@ export abstract class StatefulPage<
|
|
|
137
149
|
makeActionButton<ActionName extends keyof Actions>(
|
|
138
150
|
_state: State,
|
|
139
151
|
action_description: StatefulPageActionDescription<ActionName>,
|
|
140
|
-
...args:
|
|
141
|
-
ExtractTail<ExtractTail<Parameters<Actions[ActionName]>>>
|
|
142
|
-
>
|
|
152
|
+
...args: ExtractStatefulPageActionArgs<Actions[ActionName]>
|
|
143
153
|
) {
|
|
144
154
|
const { label, content, disabled } =
|
|
145
155
|
this.extractActionAndLabel(action_description);
|
|
@@ -162,9 +172,7 @@ export abstract class StatefulPage<
|
|
|
162
172
|
label?: string;
|
|
163
173
|
}
|
|
164
174
|
| ActionName,
|
|
165
|
-
...args:
|
|
166
|
-
ExtractTail<ExtractTail<Parameters<Actions[ActionName]>>>
|
|
167
|
-
>
|
|
175
|
+
...args: ExtractStatefulPageActionArgs<Actions[ActionName]>
|
|
168
176
|
) {
|
|
169
177
|
return `(()=>{const form = this.closest('form'); form.action='${this.makeActionURL(
|
|
170
178
|
action_description,
|
|
@@ -301,14 +309,15 @@ export abstract class StatefulPage<
|
|
|
301
309
|
const { action, state, inputs, action_args } =
|
|
302
310
|
await this.extractState(ctx);
|
|
303
311
|
if (action) {
|
|
304
|
-
const new_state = await this.actions[action](
|
|
312
|
+
const new_state = await this.actions[action]({
|
|
305
313
|
ctx,
|
|
306
314
|
state,
|
|
307
315
|
inputs,
|
|
308
|
-
|
|
316
|
+
args: JSON.parse(
|
|
309
317
|
from_base64(action_args as string)
|
|
310
|
-
) as unknown[]
|
|
311
|
-
|
|
318
|
+
) as unknown[],
|
|
319
|
+
page: this,
|
|
320
|
+
});
|
|
312
321
|
ctx.body = this.render(ctx, new_state, inputs);
|
|
313
322
|
} else {
|
|
314
323
|
ctx.body = this.render(ctx, state, inputs);
|