@server/next 0.27.13 → 0.28.1
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.
- package/index.d.ts +4 -4
- package/index.js +1 -1
- package/package.json +1 -1
- package/src/jsx/jsx-runtime.js +30 -5
- package/src/jsx/jsx-runtime.test.jsx +50 -0
package/index.d.ts
CHANGED
|
@@ -231,10 +231,10 @@ declare class Router<O extends ServerConfig = object> {
|
|
|
231
231
|
patch<Path extends string>(path: Path, options: RouteOptions, ...middleware: Mids<O, Path>): this;
|
|
232
232
|
patch(...middleware: Middleware<O>[]): this;
|
|
233
233
|
patch(options: RouteOptions, ...middleware: Middleware<O>[]): this;
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
234
|
+
delete<Path extends string>(path: Path, ...middleware: Mids<O, Path>): this;
|
|
235
|
+
delete<Path extends string>(path: Path, options: RouteOptions, ...middleware: Mids<O, Path>): this;
|
|
236
|
+
delete(...middleware: Middleware<O>[]): this;
|
|
237
|
+
delete(options: RouteOptions, ...middleware: Middleware<O>[]): this;
|
|
238
238
|
options<Path extends string>(path: Path, ...middleware: Mids<O, Path>): this;
|
|
239
239
|
options<Path extends string>(path: Path, options: RouteOptions, ...mid: Mids<O, Path>): this;
|
|
240
240
|
options(...middleware: Middleware<O>[]): this;
|
package/index.js
CHANGED
|
@@ -1850,7 +1850,7 @@ var Router = class _Router {
|
|
|
1850
1850
|
}
|
|
1851
1851
|
return this.handle("patch", pathOrMid, ...middleware);
|
|
1852
1852
|
}
|
|
1853
|
-
|
|
1853
|
+
delete(pathOrMid, optionsOrMid, ...middleware) {
|
|
1854
1854
|
if (typeof pathOrMid === "string" && isMiddleware(optionsOrMid)) {
|
|
1855
1855
|
return this.handle("delete", pathOrMid, optionsOrMid, ...middleware);
|
|
1856
1856
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@server/next",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.28.1",
|
|
4
4
|
"description": "A fully-fledged web server with routing, file uploads, sessions, static files, schema validation, websockets, testing, etc.",
|
|
5
5
|
"homepage": "https://server-js.com/",
|
|
6
6
|
"repository": "https://github.com/franciscop/server-next.git",
|
package/src/jsx/jsx-runtime.js
CHANGED
|
@@ -40,8 +40,35 @@ const minifyCss = (str) =>
|
|
|
40
40
|
.replace(/(\{) (\w)/g, "$1$2")
|
|
41
41
|
.trim();
|
|
42
42
|
|
|
43
|
+
const isReactElement = (val) =>
|
|
44
|
+
val !== null && typeof val === "object" && "type" in val && "props" in val;
|
|
45
|
+
|
|
46
|
+
const renderChild = (child) => {
|
|
47
|
+
if (!isValidChild(child)) return "";
|
|
48
|
+
if (typeof child === "function") return child();
|
|
49
|
+
if (typeof child === "number") return String(child);
|
|
50
|
+
if (typeof child === "string") return encode(child);
|
|
51
|
+
if (Array.isArray(child)) return child.flat().map(renderChild).join("");
|
|
52
|
+
if (isReactElement(child)) {
|
|
53
|
+
const result = jsx(child.type, child.props || {});
|
|
54
|
+
return typeof result === "function" ? result() : result ?? "";
|
|
55
|
+
}
|
|
56
|
+
return "";
|
|
57
|
+
};
|
|
58
|
+
|
|
43
59
|
const jsx = (tag, { children, ...props }) => {
|
|
44
|
-
if (typeof tag === "function")
|
|
60
|
+
if (typeof tag === "function") {
|
|
61
|
+
const result = tag({ children, ...props });
|
|
62
|
+
if (isReactElement(result)) return jsx(result.type, result.props || {});
|
|
63
|
+
return result ?? (() => "");
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Handle React forwardRef objects: { render: fn }
|
|
67
|
+
if (typeof tag === "object" && tag !== null && typeof tag.render === "function") {
|
|
68
|
+
const result = tag.render({ children, ...props }, null);
|
|
69
|
+
if (isReactElement(result)) return jsx(result.type, result.props || {});
|
|
70
|
+
return result ?? (() => "");
|
|
71
|
+
}
|
|
45
72
|
|
|
46
73
|
if (tag === "script" && children) {
|
|
47
74
|
const src = children;
|
|
@@ -58,11 +85,9 @@ const jsx = (tag, { children, ...props }) => {
|
|
|
58
85
|
}
|
|
59
86
|
|
|
60
87
|
if (!isValidChild(children)) children = [];
|
|
61
|
-
if (typeof children === "string") children = [children];
|
|
62
88
|
|
|
63
|
-
children = (Array.isArray(children) ? children : [children])
|
|
64
|
-
.
|
|
65
|
-
.map((c) => (typeof c === "function" ? c() : encode(c)))
|
|
89
|
+
children = (Array.isArray(children) ? children.flat() : [children])
|
|
90
|
+
.map(renderChild)
|
|
66
91
|
.join("");
|
|
67
92
|
|
|
68
93
|
if (!tag) return () => children;
|
|
@@ -45,3 +45,53 @@ describe("jsx", () => {
|
|
|
45
45
|
);
|
|
46
46
|
});
|
|
47
47
|
});
|
|
48
|
+
|
|
49
|
+
describe("React element interop", () => {
|
|
50
|
+
// Simulate a component built with React's jsx runtime, which returns plain
|
|
51
|
+
// objects { type, props } instead of @server/next functions
|
|
52
|
+
const reactEl = (type, props = {}) => ({ type, props });
|
|
53
|
+
|
|
54
|
+
it("renders a React element returned from a function component", () => {
|
|
55
|
+
const Greeting = () => reactEl("h1", { children: "Hello" });
|
|
56
|
+
expect(<Greeting />).toRender("<h1>Hello</h1>");
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it("renders nested React elements", () => {
|
|
60
|
+
const Card = () =>
|
|
61
|
+
reactEl("div", {
|
|
62
|
+
children: [
|
|
63
|
+
reactEl("h2", { children: "Title" }),
|
|
64
|
+
reactEl("p", { children: "Body" }),
|
|
65
|
+
],
|
|
66
|
+
});
|
|
67
|
+
expect(<Card />).toRender("<div><h2>Title</h2><p>Body</p></div>");
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it("renders React elements as children of a native element", () => {
|
|
71
|
+
const child = reactEl("strong", { children: "bold" });
|
|
72
|
+
expect(<p>{child}</p>).toRender("<p><strong>bold</strong></p>");
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it("renders a mix of React elements and plain strings as children", () => {
|
|
76
|
+
const em = reactEl("em", { children: "world" });
|
|
77
|
+
expect(<p>Hello {em}!</p>).toRender("<p>Hello <em>world</em>!</p>");
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it("renders a React element with attributes", () => {
|
|
81
|
+
const Link = () => reactEl("a", { href: "https://example.com", children: "click" });
|
|
82
|
+
expect(<Link />).toRender(`<a href="https://example.com">click</a>`);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it("renders deeply nested React elements", () => {
|
|
86
|
+
const Deep = () =>
|
|
87
|
+
reactEl("div", {
|
|
88
|
+
children: reactEl("ul", {
|
|
89
|
+
children: [
|
|
90
|
+
reactEl("li", { children: "one" }),
|
|
91
|
+
reactEl("li", { children: "two" }),
|
|
92
|
+
],
|
|
93
|
+
}),
|
|
94
|
+
});
|
|
95
|
+
expect(<Deep />).toRender("<div><ul><li>one</li><li>two</li></ul></div>");
|
|
96
|
+
});
|
|
97
|
+
});
|