@thestarweb/star-framework-app-web 0.1.0

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 (147) hide show
  1. package/dist/browser/index.js +8 -0
  2. package/dist/browser/index.js.map +1 -0
  3. package/dist/cli/dev-server.js +64 -0
  4. package/dist/cli/dev-server.js.map +1 -0
  5. package/dist/cli/index.js +117 -0
  6. package/dist/cli/index.js.map +1 -0
  7. package/dist/cli/types.js +2 -0
  8. package/dist/cli/types.js.map +1 -0
  9. package/dist/cli-helper.js +2 -0
  10. package/dist/cli-helper.js.map +1 -0
  11. package/dist/index.js +14 -0
  12. package/dist/index.js.map +1 -0
  13. package/dist/interceptor/index.js +26 -0
  14. package/dist/interceptor/index.js.map +1 -0
  15. package/dist/interceptor/middleware-to-interceptor/index.js +32 -0
  16. package/dist/interceptor/middleware-to-interceptor/index.js.map +1 -0
  17. package/dist/interceptor/middleware-to-interceptor/mock-res.js +241 -0
  18. package/dist/interceptor/middleware-to-interceptor/mock-res.js.map +1 -0
  19. package/dist/interceptor/middleware-to-interceptor/mook-req.js +180 -0
  20. package/dist/interceptor/middleware-to-interceptor/mook-req.js.map +1 -0
  21. package/dist/interceptor/types.js +6 -0
  22. package/dist/interceptor/types.js.map +1 -0
  23. package/dist/params/index.js +10 -0
  24. package/dist/params/index.js.map +1 -0
  25. package/dist/request/index.js +46 -0
  26. package/dist/request/index.js.map +1 -0
  27. package/dist/return-types/index.js +2 -0
  28. package/dist/return-types/index.js.map +1 -0
  29. package/dist/return-types/response-with-meta.js +25 -0
  30. package/dist/return-types/response-with-meta.js.map +1 -0
  31. package/dist/route/index.js +20 -0
  32. package/dist/route/index.js.map +1 -0
  33. package/dist/route/types.js +17 -0
  34. package/dist/route/types.js.map +1 -0
  35. package/dist/runtime/index.js +84 -0
  36. package/dist/runtime/index.js.map +1 -0
  37. package/dist/runtime/type.js +11 -0
  38. package/dist/runtime/type.js.map +1 -0
  39. package/dist/server/body/helper.js +118 -0
  40. package/dist/server/body/helper.js.map +1 -0
  41. package/dist/server/body/json.js +211 -0
  42. package/dist/server/body/json.js.map +1 -0
  43. package/dist/server/body/types.js +6 -0
  44. package/dist/server/body/types.js.map +1 -0
  45. package/dist/server/dump-api-type.js +59 -0
  46. package/dist/server/dump-api-type.js.map +1 -0
  47. package/dist/server/index.js +103 -0
  48. package/dist/server/index.js.map +1 -0
  49. package/dist/server/types.js +8 -0
  50. package/dist/server/types.js.map +1 -0
  51. package/dist/server/utils/pass-through-readable.js +13 -0
  52. package/dist/server/utils/pass-through-readable.js.map +1 -0
  53. package/dist/view/const.js +2 -0
  54. package/dist/view/const.js.map +1 -0
  55. package/dist/view/data-context/conetext.js +70 -0
  56. package/dist/view/data-context/conetext.js.map +1 -0
  57. package/dist/view/data-context/index.js +13 -0
  58. package/dist/view/data-context/index.js.map +1 -0
  59. package/dist/view/html/create-element.js +20 -0
  60. package/dist/view/html/create-element.js.map +1 -0
  61. package/dist/view/html/index.js +4 -0
  62. package/dist/view/html/index.js.map +1 -0
  63. package/dist/view/html/parse-html-to-v-dom.js +317 -0
  64. package/dist/view/html/parse-html-to-v-dom.js.map +1 -0
  65. package/dist/view/html/render-v-dom-to-string.js +46 -0
  66. package/dist/view/html/render-v-dom-to-string.js.map +1 -0
  67. package/dist/view/html/types.js +21 -0
  68. package/dist/view/html/types.js.map +1 -0
  69. package/dist/view/index.js +7 -0
  70. package/dist/view/index.js.map +1 -0
  71. package/dist/view/layout.js +24 -0
  72. package/dist/view/layout.js.map +1 -0
  73. package/dist/view/render/html-render.js +21 -0
  74. package/dist/view/render/html-render.js.map +1 -0
  75. package/dist/view/render/index.js +3 -0
  76. package/dist/view/render/index.js.map +1 -0
  77. package/dist/view/render/render.js +183 -0
  78. package/dist/view/render/render.js.map +1 -0
  79. package/dist/view/render/sf-v-dom-render.js +40 -0
  80. package/dist/view/render/sf-v-dom-render.js.map +1 -0
  81. package/dist/view/types.js +10 -0
  82. package/dist/view/types.js.map +1 -0
  83. package/dist/view/utils/find-route-dom.js +22 -0
  84. package/dist/view/utils/find-route-dom.js.map +1 -0
  85. package/dist/view/utils/get-render/client.js +77 -0
  86. package/dist/view/utils/get-render/client.js.map +1 -0
  87. package/dist/view/utils/get-render/common.js +87 -0
  88. package/dist/view/utils/get-render/common.js.map +1 -0
  89. package/dist/view/utils/get-render/index.js +4 -0
  90. package/dist/view/utils/get-render/index.js.map +1 -0
  91. package/dist/view/utils/get-render/server.js +60 -0
  92. package/dist/view/utils/get-render/server.js.map +1 -0
  93. package/dist/view/utils/index.js +3 -0
  94. package/dist/view/utils/index.js.map +1 -0
  95. package/dist/view/view.js +10 -0
  96. package/dist/view/view.js.map +1 -0
  97. package/package.json +41 -0
  98. package/resource/default-index.html +11 -0
  99. package/src/browser/index.ts +7 -0
  100. package/src/cli/dev-server.ts +66 -0
  101. package/src/cli/index.ts +122 -0
  102. package/src/cli/types.ts +7 -0
  103. package/src/cli-helper.ts +5 -0
  104. package/src/index.ts +24 -0
  105. package/src/interceptor/index.ts +26 -0
  106. package/src/interceptor/middleware-to-interceptor/index.ts +29 -0
  107. package/src/interceptor/middleware-to-interceptor/mock-res.ts +255 -0
  108. package/src/interceptor/middleware-to-interceptor/mook-req.ts +218 -0
  109. package/src/interceptor/types.ts +7 -0
  110. package/src/params/index.ts +12 -0
  111. package/src/request/index.ts +65 -0
  112. package/src/return-types/index.ts +1 -0
  113. package/src/return-types/response-with-meta.ts +17 -0
  114. package/src/route/index.ts +43 -0
  115. package/src/route/types.ts +11 -0
  116. package/src/server/body/helper.ts +110 -0
  117. package/src/server/body/json.ts +217 -0
  118. package/src/server/body/types.ts +6 -0
  119. package/src/server/dump-api-type.ts +64 -0
  120. package/src/server/index.ts +113 -0
  121. package/src/server/types.ts +11 -0
  122. package/src/server/utils/pass-through-readable.ts +10 -0
  123. package/src/view/const.ts +1 -0
  124. package/src/view/data-context/conetext.ts +59 -0
  125. package/src/view/data-context/index.ts +18 -0
  126. package/src/view/html/create-element.ts +20 -0
  127. package/src/view/html/index.ts +3 -0
  128. package/src/view/html/parse-html-to-v-dom.ts +348 -0
  129. package/src/view/html/render-v-dom-to-string.ts +79 -0
  130. package/src/view/html/types.ts +32 -0
  131. package/src/view/index.ts +6 -0
  132. package/src/view/layout.ts +20 -0
  133. package/src/view/render/html-render.ts +21 -0
  134. package/src/view/render/index.ts +2 -0
  135. package/src/view/render/render.ts +225 -0
  136. package/src/view/render/sf-v-dom-render.ts +34 -0
  137. package/src/view/types.ts +18 -0
  138. package/src/view/utils/find-route-dom.ts +19 -0
  139. package/src/view/utils/get-render/client.ts +76 -0
  140. package/src/view/utils/get-render/common.ts +113 -0
  141. package/src/view/utils/get-render/index.ts +3 -0
  142. package/src/view/utils/get-render/server.ts +71 -0
  143. package/src/view/utils/index.ts +2 -0
  144. package/src/view/view.ts +7 -0
  145. package/test/body.test.ts +29 -0
  146. package/tsconfig.build.json +9 -0
  147. package/tsconfig.json +8 -0
@@ -0,0 +1,217 @@
1
+ import {
2
+ ParamType,
3
+ ParamTypeEnum,
4
+ } from "@thestarweb/star-framework-param-helper";
5
+ import { mergeUint8Array, ReaderHelper } from "./helper.js";
6
+ import { bodyParse } from "./types.js";
7
+
8
+ const charCodeQuote = '"'.charCodeAt(0);
9
+ const charCodeOpenCornerBracket = "[".charCodeAt(0);
10
+ const charCodeCloseCornerBracket = "]".charCodeAt(0);
11
+ const charCodeOpenCurlyBracket = "{".charCodeAt(0);
12
+ const charCodeCloseCurlyBracket = "}".charCodeAt(0);
13
+ const charCodeReverseSlash = "\\".charCodeAt(0);
14
+ const charCodeTab = "\t".charCodeAt(0);
15
+ const charCodeReturn = "\r".charCodeAt(0);
16
+ const charCodeNewLine = "\n".charCodeAt(0);
17
+ const charCodeSpace = " ".charCodeAt(0);
18
+ const charCodesSkip = [
19
+ charCodeTab,
20
+ charCodeReturn,
21
+ charCodeNewLine,
22
+ charCodeSpace,
23
+ ];
24
+ const charCodeR = "r".charCodeAt(0);
25
+ const charCodeN = "n".charCodeAt(0);
26
+ const charCodeT = "t".charCodeAt(0);
27
+ const charCodeU = "u".charCodeAt(0);
28
+ const charCodeF = "f".charCodeAt(0);
29
+ const charCode0 = "0".charCodeAt(0);
30
+ const charCode9 = "9".charCodeAt(0);
31
+ const charCodeDot = ".".charCodeAt(0);
32
+ const charCodeComma = ",".charCodeAt(0);
33
+ const charCodeColon = ":".charCodeAt(0);
34
+ const decoder = new TextDecoder();
35
+
36
+ let defAny: ParamType = { type: ParamTypeEnum.Any };
37
+ export const JSONBody: bodyParse = (headrer, targetType) => {
38
+ if (headrer["content-type"]?.startsWith("application/json")) {
39
+ return (stream) => {
40
+ const helper = new ReaderHelper(stream);
41
+ function charError(char: number, expectation?: string[]) {
42
+ throw new Error(
43
+ `unexpectation ${String.fromCharCode(char)}(char code ${char})${expectation ? `, expectation ${expectation.join(",")}` : ""}, at ${helper.totalIndex}`,
44
+ );
45
+ }
46
+ async function match(head: string, find: string) {
47
+ const dataString = await helper.readAsString(find.length, decoder);
48
+ if (dataString !== find) {
49
+ throw new Error(
50
+ `unexpectation ${head}${dataString}, expectation ${head}${find})}, at ${helper.totalIndex}`,
51
+ );
52
+ }
53
+ }
54
+ async function readString() {
55
+ const strings: string[] = [];
56
+ let loop = true;
57
+ while (loop) {
58
+ await helper.streamReadUntil((buff) => {
59
+ for (var i = 0; i < buff.length; i++) {
60
+ const item = buff[i];
61
+ if (item == charCodeQuote) {
62
+ strings.push(
63
+ decoder.decode(buff.subarray(0, i), { stream: true }),
64
+ );
65
+ loop = false;
66
+ return i + 1;
67
+ }
68
+ if (item === charCodeReverseSlash) {
69
+ strings.push(
70
+ decoder.decode(buff.subarray(0, i), { stream: true }),
71
+ );
72
+ return i + 1;
73
+ }
74
+ }
75
+ strings.push(decoder.decode(buff, { stream: true }));
76
+ return -1;
77
+ });
78
+ if (loop) {
79
+ const char = await helper.readChar();
80
+ switch (char) {
81
+ case charCodeReverseSlash:
82
+ strings.push("\\");
83
+ break;
84
+
85
+ case charCodeT:
86
+ strings.push("\t");
87
+ break;
88
+ case charCodeR:
89
+ strings.push("\r");
90
+ break;
91
+ case charCodeN:
92
+ strings.push("\n");
93
+ break;
94
+
95
+ case charCodeU:
96
+ // t = charCodeReturn;
97
+ throw new Error("暂时不支持\\u编码");
98
+ break;
99
+ default:
100
+ charError(char, ["r", "n", "t", "\\"]);
101
+ }
102
+ }
103
+ }
104
+ return strings.join("");
105
+ }
106
+ async function readArray(targetType: ParamType, path: string[]) {
107
+ let t: ParamType | ParamType[] = defAny;
108
+ if (targetType.type == ParamTypeEnum.Array) {
109
+ t = targetType.items;
110
+ }
111
+ const res = [];
112
+
113
+ await helper.skipChar(charCodesSkip);
114
+ if ((await helper.viewChar()) === charCodeCloseCornerBracket) {
115
+ await helper.readChar();
116
+ return [];
117
+ }
118
+ while (true) {
119
+ const ret = await start(Array.isArray(t) ? t[res.length] : t, [
120
+ ...path,
121
+ `${res.length}`,
122
+ ]);
123
+ res.push(ret);
124
+ await helper.skipChar(charCodesSkip);
125
+ const nextChar = await helper.readChar();
126
+ if (nextChar === charCodeCloseCornerBracket) {
127
+ return res;
128
+ }
129
+ if (nextChar != charCodeComma) {
130
+ charError(nextChar, [",", "]"]);
131
+ }
132
+ }
133
+ }
134
+ async function readObject(targetType: ParamType, path: string[]) {
135
+ const obj: any = {};
136
+ let needComma = false;
137
+ while (true) {
138
+ await helper.skipChar(charCodesSkip);
139
+ const char = await helper.readChar();
140
+ if (char == charCodeCloseCurlyBracket) {
141
+ return obj;
142
+ }
143
+ if (needComma) {
144
+ if (char === charCodeComma) {
145
+ needComma = false;
146
+ } else {
147
+ charError(char, [",", "}"]);
148
+ }
149
+ } else {
150
+ if (char === charCodeQuote) {
151
+ const key = await readString();
152
+ await helper.skipChar(charCodesSkip);
153
+
154
+ const char = await helper.readChar();
155
+ if (char !== charCodeColon) charError(char, [":"]);
156
+ obj[key] = await start(defAny, [...path, key]);
157
+ needComma = true;
158
+ } else {
159
+ charError(char, ['"', "}"]);
160
+ }
161
+ }
162
+ }
163
+ }
164
+ async function start(
165
+ targetType: ParamType,
166
+ path: string[] = [],
167
+ endFlag?: number,
168
+ ): Promise<any> {
169
+ await helper.skipChar(charCodesSkip);
170
+ const char = await helper.readChar();
171
+ switch (char) {
172
+ case charCodeQuote:
173
+ return await readString();
174
+ case charCodeOpenCornerBracket:
175
+ return await readArray(targetType, path);
176
+ case charCodeOpenCurlyBracket:
177
+ return await readObject(targetType, path);
178
+
179
+ case charCodeN: {
180
+ await match("n", "ull");
181
+ return null;
182
+ }
183
+ case charCodeT:
184
+ await match("t", "rue");
185
+ return true;
186
+ case charCodeF:
187
+ await match("f", "alse");
188
+ return false;
189
+ default:
190
+ if (char >= charCode0 && char <= charCode9) {
191
+ const text = [String.fromCharCode(char)];
192
+ const hasDot = false;
193
+ await helper.streamReadUntil((arr) => {
194
+ for (let i = 0; i < arr.length; i++) {
195
+ const item = arr[i];
196
+ if (item >= charCode0 && item <= charCode9) {
197
+ continue;
198
+ }
199
+ if (arr[i] === charCodeDot && !hasDot) {
200
+ continue;
201
+ }
202
+ text.push(decoder.decode(arr.subarray(0, i)));
203
+ return i;
204
+ }
205
+ text.push(decoder.decode(arr));
206
+ return -1;
207
+ }, false);
208
+ return parseFloat(text.join(""));
209
+ }
210
+ charError(char, ["{", "[", '"', "null", "true", "false", "number"]);
211
+ }
212
+ }
213
+ return start(targetType);
214
+ };
215
+ }
216
+ return null;
217
+ };
@@ -0,0 +1,6 @@
1
+ import { ParamType } from "@thestarweb/star-framework-param-helper";
2
+
3
+ export type bodyParse = (
4
+ header: Record<string, any>,
5
+ paramType: ParamType,
6
+ ) => ((stream: ReadableStream<Uint8Array>) => Promise<any>) | null;
@@ -0,0 +1,64 @@
1
+ import { getConfig } from "@thestarweb/star-framework-cli";
2
+ import { getFlatRoute } from "../route/index.js";
3
+ import { dirname, relative } from "path";
4
+ import { writeFile } from "fs/promises";
5
+ import { paramMeta } from "../params/index.js";
6
+ import { dumpTSType } from "@thestarweb/star-framework-param-helper";
7
+
8
+ export async function dumpRouteType(file: string, obj: object) {
9
+ const routes = getFlatRoute(obj);
10
+ const config = getConfig()!;
11
+ const data = [];
12
+ let rPath = relative(dirname(file), config.entry).replaceAll("\\", "/");
13
+ if (!rPath.startsWith(".")) {
14
+ rPath = `./${rPath}`;
15
+ }
16
+ data.push(`import App from ${JSON.stringify(rPath)};`);
17
+ data.push(`declare module '@thestarweb/star-framework-app-web'{`);
18
+ data.push(`\tinterface ProjectApi{`);
19
+ Object.keys(routes).forEach((type) => {
20
+ if (type === "__SF:NotFind") return;
21
+ data.push(`\t\t${type}:{`);
22
+ routes[type as keyof typeof routes]!.forEach((meta, path) => {
23
+ if (!meta.finalRoute) return;
24
+ data.push(`\t\t\t${JSON.stringify(path)}:{`);
25
+ const { obj, propertyKey } = meta.finalRoute;
26
+ if (typeof (obj as any)[propertyKey] === "function") {
27
+ data.push(`\t\t\t\tprop:{`);
28
+ const param = paramMeta.getParamMetadata(
29
+ meta.finalRoute.obj,
30
+ meta.finalRoute.propertyKey,
31
+ );
32
+ if (param.types.body) {
33
+ data.push(
34
+ `\t\t\t\t\tbody${param.types.body.required ? "" : "?"}:${dumpTSType(param.types.body.type)},`,
35
+ );
36
+ }
37
+ if (param.types.query) {
38
+ data.push(
39
+ `\t\t\t\t\tquery${param.types.query.required ? "" : "?"}:${dumpTSType(param.types.query.type)},`,
40
+ );
41
+ }
42
+ if (param.types.header) {
43
+ data.push(
44
+ `\t\t\t\t\theader${param.types.header.required ? "" : "?"}:${dumpTSType(param.types.header.type)},`,
45
+ );
46
+ }
47
+ data.push(`\t\t\t\t},`);
48
+ data.push(
49
+ `\t\t\t\treturn:ReturnType<App${meta.allRoute.map((r) => `[${JSON.stringify(r.propertyKey)}]`).join("")}>`,
50
+ );
51
+ } else {
52
+ data.push(`\t\t\t\tprop:{},`);
53
+ data.push(
54
+ `\t\t\t\treturn:App${meta.allRoute.map((r) => `[${JSON.stringify(r.propertyKey)}]`).join("")}`,
55
+ );
56
+ }
57
+ data.push(`\t\t\t},`);
58
+ });
59
+ data.push(`\t\t}`);
60
+ });
61
+ data.push(`\t}`);
62
+ data.push(`}`);
63
+ await writeFile(file, data.join("\n"));
64
+ }
@@ -0,0 +1,113 @@
1
+ import { PassThrough, Readable } from "stream";
2
+ import { parse } from "qs";
3
+ import { paramMeta } from "../params/index.js";
4
+ import { ResponseWithMeta } from "../return-types/index.js";
5
+ import { PassThroughReadable } from "./utils/pass-through-readable.js";
6
+ import { getInterceptors, Interceptor } from "../interceptor/index.js";
7
+ import { parseRoute } from "../route/index.js";
8
+ import { createServerRender } from "../view/utils/index.js";
9
+ import { CallProp } from "./types.js";
10
+ import {
11
+ ServerInstance,
12
+ ServerRuntimeContext,
13
+ } from "@thestarweb/star-framework-web-runtime-node";
14
+ import { Method } from "../route/types.js";
15
+ import { JSONBody } from "./body/json.js";
16
+
17
+ export function createServerFactory(object: any) {
18
+ const handles = [JSONBody];
19
+ return (context: ServerRuntimeContext) => {
20
+ const routes = parseRoute(object);
21
+ const serverRender = createServerRender(context);
22
+ const ins: ServerInstance = {
23
+ async onRequert(method, url, reqHeader, rawBody, context) {
24
+ const urlObj =
25
+ typeof url === "string" ? new URL(url, "http://127.0.0.1/") : url;
26
+ const route = routes(method as Method, urlObj.pathname);
27
+
28
+ const interceptors: Interceptor[] = route.allRoute.flatMap((info) =>
29
+ getInterceptors(info.obj),
30
+ );
31
+
32
+ interceptors.unshift(serverRender);
33
+
34
+ let body: any = null;
35
+ let call: (
36
+ prop: CallProp,
37
+ ) => ResponseWithMeta | Promise<ResponseWithMeta> = () =>
38
+ new ResponseWithMeta(null, { code: 404 });
39
+
40
+ if (route.finalRoute) {
41
+ const { obj, propertyKey } = route.finalRoute;
42
+
43
+ interceptors.push(...getInterceptors(obj, propertyKey));
44
+
45
+ if (typeof (obj as any)[propertyKey] === "function") {
46
+ const paramType = paramMeta.getParamMetadata(obj, propertyKey);
47
+ if (paramType.types.body) {
48
+ for (const h of handles) {
49
+ const handle = h(reqHeader, paramType.types.body.type);
50
+ if (handle) {
51
+ body = await handle(rawBody);
52
+ break;
53
+ }
54
+ }
55
+ }
56
+
57
+ call = async (req: CallProp) => {
58
+ const rawData = await paramMeta.call(obj, propertyKey, req);
59
+ return ResponseWithMeta.isResponseWithMeta(rawData)
60
+ ? rawData
61
+ : new ResponseWithMeta(rawData);
62
+ };
63
+ } else {
64
+ call = () => new ResponseWithMeta((obj as any)[propertyKey]);
65
+ }
66
+ }
67
+
68
+ const handle = interceptors.reduceRight<
69
+ (prop: CallProp) => ResponseWithMeta | Promise<ResponseWithMeta>
70
+ >((next, handle) => (req) => handle(req, next), call);
71
+ const {
72
+ data,
73
+ code = 200,
74
+ header = {},
75
+ } = await handle({
76
+ body,
77
+ header: reqHeader,
78
+ query: parse(urlObj.search),
79
+ url: urlObj,
80
+ method: method as Method,
81
+ route,
82
+ });
83
+ let res: ReadableStream | Readable | null;
84
+ if (data instanceof ReadableStream) {
85
+ res = data;
86
+ } else if (data instanceof TransformStream) {
87
+ res = data.readable;
88
+ } else if (data instanceof Readable) {
89
+ res = data;
90
+ } else if (data instanceof PassThrough) {
91
+ res = new PassThroughReadable(data);
92
+ } else if (data === null || typeof data === "undefined") {
93
+ res = null;
94
+ } else if (header["content-type"]?.includes?.("text")) {
95
+ res = Readable.from(data?.toString() || "");
96
+ } else {
97
+ if (!header["content-type"]) {
98
+ header["content-type"] = "application/json";
99
+ }
100
+ res = Readable.from(JSON.stringify(data));
101
+ }
102
+ return {
103
+ code,
104
+ header,
105
+ res,
106
+ };
107
+ },
108
+ // @ts-ignore
109
+ _rawObject: object,
110
+ };
111
+ return ins;
112
+ };
113
+ }
@@ -0,0 +1,11 @@
1
+ import { paramMeta } from "../params/index.js";
2
+ import { RouteType } from "../route/index.js";
3
+ import { Method } from "../route/types.js";
4
+
5
+ export type CallProp<M extends Method = Method> = Parameters<
6
+ typeof paramMeta.call
7
+ >[2] & {
8
+ url: URL;
9
+ method: M;
10
+ route: RouteType<M>;
11
+ };
@@ -0,0 +1,10 @@
1
+ import { PassThrough, Readable } from "stream";
2
+
3
+ export class PassThroughReadable extends Readable {
4
+ constructor(private readonly p: PassThrough) {
5
+ super();
6
+ }
7
+ _read(size: number): void {
8
+ return this.p.read(size);
9
+ }
10
+ }
@@ -0,0 +1 @@
1
+ export const routeTagName = "sf-route";
@@ -0,0 +1,59 @@
1
+ export class SFDataContext<T> {
2
+ private constructor(private _root: SFRawDataContext<T>) {}
3
+ get value() {
4
+ return this._root.value;
5
+ }
6
+ private callbacks = new Set<(newValue: T) => void>();
7
+ private children = new Set<SFDataContext<T>>();
8
+ fock() {
9
+ return this._root.createChild();
10
+ }
11
+ watch(callback: (newValue: T) => void, updateNow = false) {
12
+ if (this.callbacks.size === 0)
13
+ // @ts-ignore 2341
14
+ this._root.children.add(this);
15
+ this.callbacks.add(callback);
16
+ if (updateNow) callback(this.value);
17
+ }
18
+ distory() {
19
+ this._root.distoryChild(this);
20
+ }
21
+ }
22
+ export class SFRawDataContext<T> {
23
+ constructor(private _value: T) {}
24
+ get value() {
25
+ return this._value;
26
+ }
27
+ update(newValue: T) {
28
+ this._value = newValue;
29
+ const called = new Set();
30
+ this.children.forEach((i) => {
31
+ (i as any).callbacks.forEach((c: any) => {
32
+ if (!called.has(c)) {
33
+ called.add(c);
34
+ c(newValue);
35
+ }
36
+ });
37
+ });
38
+ }
39
+ private children = new Set<SFDataContext<T>>();
40
+ createChild() {
41
+ const child: SFDataContext<T> =
42
+ // @ts-ignore
43
+ new SFDataContext(this);
44
+ return child;
45
+ }
46
+ distoryChild(child: SFDataContext<T>) {
47
+ this.children.delete(child);
48
+ }
49
+ }
50
+ export function forkDataContextRecord<T extends Record<keyof T, any>>(
51
+ data: T,
52
+ ): T {
53
+ return Object.fromEntries(
54
+ Object.entries(data).map(([k, context]) => [
55
+ k,
56
+ context instanceof SFDataContext ? context.fock() : context,
57
+ ]),
58
+ ) as T;
59
+ }
@@ -0,0 +1,18 @@
1
+ import { SFWebRequest } from "../../request/index.js";
2
+ import { RouteType } from "../../route/index.js";
3
+ import { SFDataContext } from "./conetext.js";
4
+ export * from "./conetext.js";
5
+ export interface SystemRenderDataContext {
6
+ route: SFDataContext<RouteType<"GET">>;
7
+ request: SFWebRequest;
8
+ baseUrl: string;
9
+ }
10
+ export interface UserRenderDataContext extends Record<
11
+ string,
12
+ SFDataContext<any>
13
+ > {}
14
+
15
+ export interface RenderDataContext {
16
+ system: SystemRenderDataContext;
17
+ user: UserRenderDataContext;
18
+ }
@@ -0,0 +1,20 @@
1
+ import { HTMLVElement, HTMLVNode, VNodeType } from "./types.js";
2
+
3
+ export function createElement(
4
+ type: string,
5
+ prop: any,
6
+ ...children: (HTMLVNode | HTMLVNode[])[]
7
+ ): HTMLVElement {
8
+ return {
9
+ type: VNodeType.Element,
10
+ tagName: type,
11
+ attributes: prop,
12
+ children: children.flat(),
13
+ };
14
+ }
15
+ export function createDoctypeElement(): HTMLVNode {
16
+ return {
17
+ type: VNodeType.Outher,
18
+ text: "<!DOCTYPE html>",
19
+ };
20
+ }
@@ -0,0 +1,3 @@
1
+ export { renderVDomToString } from "./render-v-dom-to-string.js";
2
+ export { parseHtmlToVDom } from "./parse-html-to-v-dom.js";
3
+ export * from "./create-element.js";