@sealcode/sealgen 0.2.1 → 0.3.2

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.
Files changed (146) hide show
  1. package/.eslintrc.js +1 -0
  2. package/@types/build.d.ts +1 -0
  3. package/@types/cli.d.ts +2 -0
  4. package/@types/forms/controls/checkboxed-list-input.d.ts +16 -0
  5. package/@types/forms/controls/controls.d.ts +9 -0
  6. package/@types/forms/controls/dropdown.d.ts +20 -0
  7. package/@types/forms/controls/editable-collection-subset.d.ts +21 -0
  8. package/@types/forms/controls/form-control.d.ts +8 -0
  9. package/@types/forms/controls/form-field-control.d.ts +13 -0
  10. package/@types/forms/controls/form-header.d.ts +9 -0
  11. package/@types/forms/controls/form-paragraph.d.ts +7 -0
  12. package/@types/forms/controls/frame.d.ts +17 -0
  13. package/@types/forms/controls/simple-input.d.ts +28 -0
  14. package/@types/forms/controls.d.ts +0 -0
  15. package/@types/forms/field.d.ts +42 -0
  16. package/@types/forms/form-fields-list.d.ts +4 -0
  17. package/@types/forms/form.d.ts +42 -0
  18. package/@types/forms/validator.d.ts +3 -0
  19. package/@types/index.d.ts +15 -2
  20. package/@types/page/access-control.d.ts +6 -0
  21. package/@types/page/list.d.ts +59 -0
  22. package/@types/page/page.d.ts +26 -0
  23. package/@types/page/props-parser.d.ts +20 -0
  24. package/@types/run.d.ts +0 -0
  25. package/@types/templates/page.d.ts +1 -1
  26. package/@types/utils/natural-numbers.d.ts +1 -0
  27. package/@types/utils/sleep.d.ts +1 -0
  28. package/@types/utils/url-with-new-params.d.ts +2 -0
  29. package/@types/utils/utils.d.ts +9 -0
  30. package/@types/utils/walk.d.ts +1 -1
  31. package/lib/build.js +116 -0
  32. package/lib/build.js.map +1 -0
  33. package/lib/cli.js +30 -0
  34. package/lib/cli.js.map +1 -0
  35. package/lib/find-scss-includes.js +2 -1
  36. package/lib/find-scss-includes.js.map +1 -1
  37. package/lib/forms/controls/checkboxed-list-input.js +43 -0
  38. package/lib/forms/controls/checkboxed-list-input.js.map +1 -0
  39. package/lib/forms/controls/controls.js +22 -0
  40. package/lib/forms/controls/controls.js.map +1 -0
  41. package/lib/forms/controls/dropdown.js +40 -0
  42. package/lib/forms/controls/dropdown.js.map +1 -0
  43. package/lib/forms/controls/editable-collection-subset.js +73 -0
  44. package/lib/forms/controls/editable-collection-subset.js.map +1 -0
  45. package/lib/forms/controls/form-control.js +7 -0
  46. package/lib/forms/controls/form-control.js.map +1 -0
  47. package/lib/forms/controls/form-field-control.js +22 -0
  48. package/lib/forms/controls/form-field-control.js.map +1 -0
  49. package/lib/forms/controls/form-header.js +18 -0
  50. package/lib/forms/controls/form-header.js.map +1 -0
  51. package/lib/forms/controls/form-paragraph.js +16 -0
  52. package/lib/forms/controls/form-paragraph.js.map +1 -0
  53. package/lib/forms/controls/frame.js +29 -0
  54. package/lib/forms/controls/frame.js.map +1 -0
  55. package/lib/forms/controls/simple-input.js +50 -0
  56. package/lib/forms/controls/simple-input.js.map +1 -0
  57. package/lib/forms/controls.js +1 -0
  58. package/lib/forms/controls.js.map +1 -0
  59. package/lib/forms/field.js +80 -0
  60. package/lib/forms/field.js.map +1 -0
  61. package/lib/forms/form-fields-list.js +10 -0
  62. package/lib/forms/form-fields-list.js.map +1 -0
  63. package/lib/forms/form.js +162 -0
  64. package/lib/forms/form.js.map +1 -0
  65. package/lib/forms/validator.js +11 -0
  66. package/lib/forms/validator.js.map +1 -0
  67. package/lib/generate-routes.js +11 -4
  68. package/lib/generate-routes.js.map +1 -1
  69. package/lib/index.js +18 -25
  70. package/lib/index.js.map +1 -1
  71. package/lib/page/access-control.js +20 -0
  72. package/lib/page/access-control.js.map +1 -0
  73. package/lib/page/list.js +148 -0
  74. package/lib/page/list.js.map +1 -0
  75. package/lib/page/page.js +20 -0
  76. package/lib/page/page.js.map +1 -0
  77. package/lib/page/props-parser.js +74 -0
  78. package/lib/page/props-parser.js.map +1 -0
  79. package/lib/run.js +1 -0
  80. package/lib/run.js.map +1 -0
  81. package/lib/templates/form.js +10 -5
  82. package/lib/templates/form.js.map +1 -1
  83. package/lib/templates/list.js +3 -3
  84. package/lib/templates/list.js.map +1 -1
  85. package/lib/templates/page.js +5 -4
  86. package/lib/templates/page.js.map +1 -1
  87. package/lib/utils/escape-url-params.js +1 -0
  88. package/lib/utils/escape-url-params.js.map +1 -1
  89. package/lib/utils/list-collections.js +1 -1
  90. package/lib/utils/list-collections.js.map +1 -1
  91. package/lib/utils/natural-numbers.js +10 -0
  92. package/lib/utils/natural-numbers.js.map +1 -0
  93. package/lib/utils/sleep.js +8 -0
  94. package/lib/utils/sleep.js.map +1 -0
  95. package/lib/utils/url-with-new-params.js +12 -0
  96. package/lib/utils/url-with-new-params.js.map +1 -0
  97. package/lib/utils/utils.js +19 -0
  98. package/lib/utils/utils.js.map +1 -0
  99. package/lib/utils/walk.js +4 -4
  100. package/lib/utils/walk.js.map +1 -1
  101. package/package.json +17 -4
  102. package/src/build.ts +92 -0
  103. package/src/cli.ts +34 -0
  104. package/src/find-scss-includes.ts +3 -2
  105. package/src/forms/controls/checkboxed-list-input.ts +50 -0
  106. package/src/forms/controls/controls.ts +9 -0
  107. package/src/forms/controls/dropdown.ts +57 -0
  108. package/src/forms/controls/editable-collection-subset.ts +91 -0
  109. package/src/forms/controls/form-control.ts +13 -0
  110. package/src/forms/controls/form-field-control.ts +39 -0
  111. package/src/forms/controls/form-header.ts +16 -0
  112. package/src/forms/controls/form-paragraph.ts +11 -0
  113. package/src/forms/controls/frame.ts +26 -0
  114. package/src/forms/controls/simple-input.ts +73 -0
  115. package/src/forms/controls.ts +0 -0
  116. package/src/forms/field.ts +119 -0
  117. package/src/forms/form-fields-list.ts +7 -0
  118. package/src/forms/form.ts +242 -0
  119. package/src/forms/forms.scss +18 -0
  120. package/src/forms/validator.ts +10 -0
  121. package/src/generate-routes.ts +12 -9
  122. package/src/index.ts +15 -28
  123. package/src/page/access-control.ts +18 -0
  124. package/src/page/list.ts +214 -0
  125. package/src/page/page.ts +31 -0
  126. package/src/page/props-parser.ts +99 -0
  127. package/src/run.ts +0 -0
  128. package/src/templates/form.ts +10 -5
  129. package/src/templates/list.ts +3 -3
  130. package/src/templates/page.ts +6 -6
  131. package/src/utils/escape-url-params.ts +1 -0
  132. package/src/utils/list-collections.ts +2 -2
  133. package/src/utils/natural-numbers.ts +5 -0
  134. package/src/utils/sleep.ts +3 -0
  135. package/src/utils/url-with-new-params.ts +9 -0
  136. package/src/utils/utils.ts +10 -0
  137. package/src/utils/walk.ts +2 -2
  138. package/tsconfig.json +5 -2
  139. package/.log/ti-101379.log +0 -524
  140. package/.log/ti-131883.log +0 -505
  141. package/.log/ti-13490.log +0 -652
  142. package/.log/ti-138140.log +0 -505
  143. package/.log/ti-138288.log +0 -526
  144. package/.log/ti-46589.log +0 -675
  145. package/.log/tsserver.log +0 -1666
  146. package/src/tsconfig.json +0 -18
@@ -0,0 +1,214 @@
1
+ import { BaseContext } from "koa";
2
+ import { Collection, CollectionItem } from "sealious";
3
+ import { Templatable, tempstream } from "tempstream";
4
+ import { peopleWhoCan } from "./access-control";
5
+ import { Page } from "./page";
6
+ import { predicates, ShapeToType } from "@sealcode/ts-predicates";
7
+ import { PagePropsParser } from "./props-parser";
8
+ import { FormFieldControl } from "../forms/controls/controls";
9
+ import { FormField } from "../forms/field";
10
+ import { FormData } from "../forms/form";
11
+ import { FormFieldsList } from "../forms/form-fields-list";
12
+ import { naturalNumbers, UrlWithNewParams } from "../utils/utils";
13
+
14
+ export const BasePagePropsShape = <const>{};
15
+ export type BasePageProps = ShapeToType<typeof BasePagePropsShape>;
16
+
17
+ export const BaseListPagePropsShape = <const>{
18
+ page: predicates.number,
19
+ itemsPerPage: predicates.number,
20
+ };
21
+ export type BaseListPageProps = ShapeToType<typeof BaseListPagePropsShape>;
22
+ export const BaseListPageDefaultProps = { page: 1, itemsPerPage: 25 };
23
+
24
+ export type PropsErrors<PropsType> = Partial<Record<keyof PropsType, string>>;
25
+
26
+ export abstract class ListPage<
27
+ ItemType,
28
+ PropsType extends BaseListPageProps = BaseListPageProps
29
+ > extends Page {
30
+ abstract getItems(
31
+ ctx: BaseContext,
32
+ props: PropsType
33
+ ): Promise<{ items: ItemType[] }>;
34
+ abstract getTotalPages(ctx: BaseContext, props: PropsType): Promise<number>;
35
+ abstract renderItem(ctx: BaseContext, item: ItemType): Promise<Templatable>;
36
+ abstract propsParser: PagePropsParser<PropsType>;
37
+
38
+ filterFields: FormField<keyof PropsType>[] = [];
39
+ filterControls: FormFieldControl[] = [];
40
+
41
+ renderListContainer(_: BaseContext, content: Templatable): Templatable {
42
+ return tempstream`<div>${content}</div>`;
43
+ }
44
+
45
+ async validateProps(
46
+ ctx: BaseContext,
47
+ props: PropsType
48
+ ): Promise<{ valid: boolean; errors: PropsErrors<PropsType> }> {
49
+ const errors: PropsErrors<PropsType> = {};
50
+ let has_errors = false;
51
+ const promises = [];
52
+ for (const [key, value] of Object.entries(props)) {
53
+ const field = FormFieldsList.getField(this.filterFields, key);
54
+ if (field) {
55
+ promises.push(
56
+ field._validate(ctx, value).then(({ valid, message }) => {
57
+ if (!valid) {
58
+ has_errors = true;
59
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
60
+ errors[key as keyof PropsType] = message;
61
+ }
62
+ })
63
+ );
64
+ }
65
+ }
66
+ await Promise.all(promises);
67
+ return { valid: has_errors, errors };
68
+ }
69
+
70
+ async getProps(ctx: BaseContext): Promise<{
71
+ parsed_props: PropsType;
72
+ errors: PropsErrors<PropsType>;
73
+ raw_props: PropsType;
74
+ }> {
75
+ const raw_props = this.propsParser.decode(ctx);
76
+ const parsed_props = { ...raw_props };
77
+ const { errors } = await this.validateProps(ctx, parsed_props);
78
+ for (const prop_name in errors) {
79
+ const default_value = this.propsParser.getDefaultValue(prop_name);
80
+ if (default_value !== undefined) {
81
+ parsed_props[prop_name] = default_value;
82
+ } else {
83
+ delete parsed_props[prop_name];
84
+ }
85
+ }
86
+ return { parsed_props, errors, raw_props };
87
+ }
88
+
89
+ async render(ctx: BaseContext) {
90
+ const { parsed_props, errors, raw_props } = await this.getProps(ctx);
91
+
92
+ return tempstream`${this.renderPagination(ctx, parsed_props)}
93
+ ${this.renderFilters(ctx, parsed_props, raw_props, errors)}
94
+ ${this.getItems(ctx, parsed_props).then(({ items }) =>
95
+ this.renderListContainer(
96
+ ctx,
97
+ items.map((item) => this.renderItem(ctx, item))
98
+ )
99
+ )}`;
100
+ }
101
+
102
+ async renderPagination(ctx: BaseContext, props: PropsType) {
103
+ const totalIems = await this.getTotalPages(ctx, props);
104
+ const currentPage = props.page;
105
+
106
+ return tempstream/* HTML */ `<center>
107
+ ${currentPage > 1
108
+ ? this.renderPageButton(ctx, 1, "Pierwsza strona")
109
+ : ""}
110
+ ${currentPage > 1
111
+ ? this.renderPageButton(
112
+ ctx,
113
+ currentPage - 1,
114
+ "Poprzednia strona"
115
+ )
116
+ : ""}
117
+
118
+ <select onchange="if (this.value) Turbo.visit(this.value)">
119
+ ${Array.from(
120
+ naturalNumbers(1, await this.getTotalPages(ctx, props))
121
+ ).map(
122
+ (n) => /* HTML */ `<option
123
+ value="${UrlWithNewParams(
124
+ ctx,
125
+ //eslint-disable-next-line @typescript-eslint/consistent-type-assertions
126
+ this.propsParser.overwriteProp(ctx, {
127
+ page: n,
128
+ } as Partial<PropsType>)
129
+ )}"
130
+ ${currentPage === n ? "selected" : ""}
131
+ >
132
+ ${n}
133
+ </option>`
134
+ )}
135
+ </select>
136
+ ${currentPage < totalIems
137
+ ? this.renderPageButton(ctx, currentPage + 1, "Następna strona")
138
+ : ""}
139
+ ${currentPage < totalIems
140
+ ? this.renderPageButton(ctx, totalIems, "Ostatnia strona")
141
+ : ""}
142
+ </center>`;
143
+ }
144
+
145
+ private renderPageButton(ctx: BaseContext, page: number, text: string) {
146
+ return /* HTML */ `<a
147
+ href="${UrlWithNewParams(
148
+ ctx,
149
+ //eslint-disable-next-line @typescript-eslint/consistent-type-assertions
150
+ this.propsParser.overwriteProp(ctx, {
151
+ page,
152
+ } as Partial<PropsType>)
153
+ )}"
154
+ >${text}</a
155
+ >`;
156
+ }
157
+
158
+ renderFilters(
159
+ ctx: BaseContext,
160
+ parsed_props: PropsType, // parsed props don't include wrong values
161
+ raw_props: PropsType,
162
+ errors: PropsErrors<PropsType>
163
+ ) {
164
+ return tempstream/* HTML */ `<form method="GET">
165
+ ${this.propsParser.makeHiddenInputs(parsed_props, [
166
+ "page",
167
+ ...this.filterFields.map((f) => f.name),
168
+ ])}
169
+ ${this.filterControls.map((control) =>
170
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
171
+ control.render(ctx, this.filterFields, {
172
+ values: parsed_props,
173
+ raw_values: raw_props,
174
+ errors,
175
+ messages: [],
176
+ } as FormData)
177
+ )}
178
+ </form>`;
179
+ }
180
+ }
181
+
182
+ export abstract class SealiousItemListPage<
183
+ C extends Collection,
184
+ PageProps extends BaseListPageProps = BaseListPageProps
185
+ > extends ListPage<CollectionItem<C>, PageProps> {
186
+ constructor(public collection: C) {
187
+ super();
188
+ }
189
+
190
+ async getTotalPages(ctx: BaseContext, props: PageProps) {
191
+ const { items } = await this.collection.list(ctx.$context).fetch();
192
+ return Math.ceil(items.length / props.itemsPerPage);
193
+ }
194
+
195
+ async getItems(ctx: BaseContext, props: PageProps) {
196
+ return {
197
+ items: (
198
+ await this.collection
199
+ .list(ctx.$context)
200
+ .paginate({ items: props.itemsPerPage, page: props.page })
201
+ .fetch()
202
+ ).items,
203
+ };
204
+ }
205
+
206
+ async renderItem(
207
+ _: BaseContext,
208
+ item: CollectionItem<C>
209
+ ): Promise<Templatable> {
210
+ return `<div>${item.id}</div>`;
211
+ }
212
+
213
+ canAccess = peopleWhoCan("list", this.collection);
214
+ }
@@ -0,0 +1,31 @@
1
+ import Router from "@koa/router";
2
+ import { BaseContext } from "koa";
3
+
4
+ import { Templatable, tempstream } from "tempstream";
5
+
6
+ export type PageErrorMessage = { type: "access" | "internal"; message: string };
7
+
8
+ export interface Mountable {
9
+ mount: (router: Router, path: string) => void;
10
+ canAccess: (ctx: BaseContext) => Promise<{ canAccess: boolean; message: string }>;
11
+ renderError(ctx: BaseContext, error: PageErrorMessage): Promise<Templatable>;
12
+ }
13
+
14
+ export abstract class Page implements Mountable {
15
+ mount(router: Router, path: string) {
16
+ router.get(path, async (ctx) => {
17
+ ctx.body = await this.render(ctx);
18
+ });
19
+ }
20
+
21
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
22
+ async canAccess(_: BaseContext) {
23
+ return { canAccess: true, message: "" };
24
+ }
25
+
26
+ async renderError(_: BaseContext, error: PageErrorMessage) {
27
+ return tempstream/* HTML */ `<div>${error.message}</div>`;
28
+ }
29
+
30
+ public abstract render(ctx: BaseContext): Promise<Templatable>;
31
+ }
@@ -0,0 +1,99 @@
1
+ import {
2
+ hasShape,
3
+ predicates,
4
+ Shape,
5
+ ShapeToType,
6
+ } from "@sealcode/ts-predicates";
7
+
8
+ import { BaseContext } from "koa";
9
+ import merge from "merge";
10
+ import { BasePageProps } from "./list";
11
+
12
+ export type EncodedProps = Record<string, unknown>;
13
+
14
+ // the intention here is to sometime in the future be able to store multiple frames on one document, so props for each frame will be in a different namespace, and parsers are going to help with that
15
+
16
+ function parseStringValues<TheShape extends Shape>(
17
+ shape: TheShape,
18
+ values: Record<string, string>
19
+ ): ShapeToType<TheShape> {
20
+ const result: Record<string, unknown> = {};
21
+ for (const [key, value] of Object.entries(values)) {
22
+ if (!(key in shape)) {
23
+ continue;
24
+ }
25
+ const predicate = shape[key];
26
+ if (predicate == predicates.number) {
27
+ result[key] = parseFloat(value);
28
+ } else {
29
+ result[key] = value;
30
+ }
31
+ }
32
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
33
+ return result as ShapeToType<TheShape>;
34
+ }
35
+
36
+ export abstract class PagePropsParser<PropsType extends BasePageProps> {
37
+ abstract decode(ctx: BaseContext): PropsType;
38
+ abstract encode(props: PropsType): EncodedProps;
39
+ abstract getHTMLInputName(prop_name: string): string;
40
+
41
+ constructor(
42
+ public propsShape: Shape,
43
+ public defaultValues: Partial<PropsType>
44
+ ) {}
45
+
46
+ overwriteProp(
47
+ ctx: BaseContext,
48
+ new_props: Partial<PropsType>
49
+ ): EncodedProps {
50
+ const result = {};
51
+ merge.recursive(result, this.decode(ctx), new_props);
52
+ return result;
53
+ }
54
+
55
+ makeHiddenInputs(values: PropsType, fields_to_skip: string[]): string {
56
+ return Object.entries(values)
57
+ .filter(([key]) => !fields_to_skip.includes(key))
58
+ .map(
59
+ ([key, value]: [string, string | number]) =>
60
+ /* HTML */ `<input
61
+ type="hidden"
62
+ name="${key}"
63
+ value="${value}"
64
+ />`
65
+ )
66
+ .join(" ");
67
+ }
68
+
69
+ getDefaultValue<Key extends keyof PropsType>(
70
+ key: Key
71
+ ): PropsType[Key] | undefined {
72
+ return this.defaultValues[key];
73
+ }
74
+ }
75
+
76
+ export class AllQueryParams<
77
+ PropsType extends BasePageProps
78
+ > extends PagePropsParser<PropsType> {
79
+ decode(ctx: BaseContext): PropsType {
80
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
81
+ const query = parseStringValues(this.propsShape, {
82
+ ...this.defaultValues,
83
+ ...ctx.query,
84
+ } as unknown as Record<string, string>);
85
+ if (!hasShape(this.propsShape, query)) {
86
+ throw new Error("Wrong props shape");
87
+ }
88
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
89
+ return query as PropsType;
90
+ }
91
+
92
+ encode(props: PropsType): Record<string, unknown> {
93
+ return props;
94
+ }
95
+
96
+ getHTMLInputName(prop_name: string): string {
97
+ return prop_name;
98
+ }
99
+ }
package/src/run.ts ADDED
File without changes
@@ -6,11 +6,16 @@ export async function formTemplate(
6
6
  ): Promise<string> {
7
7
  const rel = curryImportPath(newfilefullpath);
8
8
  return `import { BaseContext } from "koa";
9
- import {Users} from "${rel("src/back/collections/collections")}";
10
- import { FormHeader, SimpleInput } from "${rel("src/back/forms/controls")}";
11
- import { FormField } from "${rel("src/back/forms/field")}";
12
- import Form, { FormData } from "${rel("src/back/forms/form")}";
13
- import { collectionFieldValidator } from "${rel("src/back/forms/validator")}";
9
+ import {
10
+ Form,
11
+ FormData,
12
+ FormHeader,
13
+ SimpleInput,
14
+ FormField,
15
+ collectionFieldValidator,
16
+ } from "@sealcode/sealgen";
17
+
18
+ import { Users } from "${rel("src/back/collections/collections")}";
14
19
  import html from "${rel("src/back/html")}";
15
20
 
16
21
  export const actionName = "${action_name}";
@@ -22,7 +22,7 @@ export const listTemplate = async (
22
22
  collection[0].toLocaleUpperCase() + collection.slice(1);
23
23
  const rel = curryImportPath(newfilefullpath);
24
24
  return `import { BaseContext } from "koa";
25
- import { CollectionItem, Middlewares } from "sealious";
25
+ import { CollectionItem } from "sealious";
26
26
  import { tempstream } from "tempstream";
27
27
  import { ${uppercase_collection} } from "${rel(
28
28
  "src/back/collections/collections"
@@ -33,8 +33,8 @@ import {
33
33
  BaseListPageProps,
34
34
  BaseListPagePropsShape,
35
35
  SealiousItemListPage,
36
- } from "${rel("src/back/page/list.ts")}";
37
- import { AllQueryParams } from "${rel("src/back/page/props-parser.ts")}";
36
+ AllQueryParams,
37
+ } from "@sealcode/sealgen";
38
38
 
39
39
  export const actionName = "${action_name}";
40
40
 
@@ -1,24 +1,24 @@
1
- import { importPath } from "../utils/import-path";
2
-
1
+ import { curryImportPath } from "../utils/import-path";
3
2
  export async function pageTemplate(
4
3
  action_name: string,
5
- fullpath: string
4
+ newfilefullpath: string
6
5
  ): Promise<string> {
6
+ const rel = curryImportPath(newfilefullpath);
7
7
  return `import { BaseContext } from "koa";
8
8
  import { tempstream } from "tempstream";
9
- import { Page } from "${importPath(fullpath, "src/back/page/page")}";
9
+ import { Page } from "@sealcode/sealgen";
10
+ import html from "${rel("src/back/html")}";
10
11
 
11
12
  export const actionName = "${action_name}";
12
13
 
13
14
  export default new (class ${action_name}Page extends Page {
14
-
15
15
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
16
16
  async canAccess(_: BaseContext) {
17
17
  return { canAccess: true, message: "" };
18
18
  }
19
19
 
20
20
  async render(ctx: BaseContext) {
21
- return tempstream/* HTML */ \`<div></div>\`;
21
+ return html(ctx, "${action_name}", tempstream/* HTML */ \`<div></div>\`);
22
22
  }
23
23
  })();
24
24
  `;
@@ -2,6 +2,7 @@ export function escape_url_params(url: string): string {
2
2
  return url
3
3
  .split("/")
4
4
  .map((e) => (e.startsWith(":") ? `[${e.slice(1)}]` : e))
5
+ .filter((e) => e != "")
5
6
  .join("/");
6
7
  }
7
8
 
@@ -1,9 +1,9 @@
1
1
  import _locreq from "locreq";
2
- import { walk } from "./walk";
2
+ import { walkDir } from "./walk";
3
3
  const target_locreq = _locreq(process.cwd());
4
4
 
5
5
  export async function listCollections(): Promise<string[]> {
6
- const files = await walk(target_locreq.resolve("src/back/collections"));
6
+ const files = await walkDir(target_locreq.resolve("src/back/collections"));
7
7
  return files
8
8
  .filter(
9
9
  (f) =>
@@ -0,0 +1,5 @@
1
+ export function* naturalNumbers(min: number, max: number) {
2
+ for (let i = min; i <= max; i++) {
3
+ yield i;
4
+ }
5
+ }
@@ -0,0 +1,3 @@
1
+ export async function sleep(time: number) {
2
+ return new Promise((resolve) => setTimeout(resolve, time));
3
+ }
@@ -0,0 +1,9 @@
1
+ import { BaseContext } from "koa";
2
+ import qs from "qs";
3
+
4
+ export function UrlWithNewParams(
5
+ ctx: BaseContext,
6
+ query_params: Record<string, unknown>
7
+ ): string {
8
+ return `${ctx.path}?${qs.stringify(query_params)}`;
9
+ }
@@ -0,0 +1,10 @@
1
+ export type Awaited<T> = T extends Promise<infer U> ? U : T;
2
+ export type UnwrapArray<T> = T extends Array<infer U> ? U : T;
3
+
4
+ export { sleep } from "./sleep";
5
+ export { naturalNumbers } from "./natural-numbers";
6
+ export { UrlWithNewParams } from "./url-with-new-params";
7
+ export { exec } from "./exec";
8
+ export { importPath, curryImportPath } from "./import-path";
9
+ export { listCollections } from "./list-collections";
10
+ export { walkDir } from "./walk";
package/src/utils/walk.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { promises as fs } from "fs";
2
2
  import { resolve } from "path";
3
3
 
4
- export async function walk(dir: string): Promise<string[]> {
4
+ export async function walkDir(dir: string): Promise<string[]> {
5
5
  const entries = await fs.readdir(dir);
6
6
  let ret: string[] = [];
7
7
  for (const entry of entries) {
@@ -11,7 +11,7 @@ export async function walk(dir: string): Promise<string[]> {
11
11
 
12
12
  if (info.isDirectory()) {
13
13
  // eslint-disable-next-line no-await-in-loop
14
- ret = [...ret, ...(await walk(fullpath))];
14
+ ret = [...ret, ...(await walkDir(fullpath))];
15
15
  } else {
16
16
  ret = [...ret, fullpath];
17
17
  }
package/tsconfig.json CHANGED
@@ -14,8 +14,11 @@
14
14
  "allowJs": true,
15
15
  "declarationDir": "@types",
16
16
  "resolveJsonModule": true,
17
- "sourceMap": true
17
+ "sourceMap": true,
18
+ "allowSyntheticDefaultImports": true,
19
+ "keyofStringsOnly": true,
20
+ "skipLibCheck": true
18
21
  },
19
22
  "include": ["src/**/*"],
20
- "exclude": ["src/**/*.test.ts"]
23
+ "exclude": ["src/**/*.test.ts", "node_modules/**"]
21
24
  }