@fluojs/react 0.1.0 → 0.2.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.
- package/README.ko.md +629 -16
- package/README.md +644 -25
- package/dist/decorators.d.ts +3 -3
- package/dist/decorators.d.ts.map +1 -1
- package/dist/decorators.js +10 -4
- package/dist/diagnostics.d.ts +110 -0
- package/dist/diagnostics.d.ts.map +1 -0
- package/dist/diagnostics.js +180 -0
- package/dist/error-representation.d.ts +28 -0
- package/dist/error-representation.d.ts.map +1 -0
- package/dist/error-representation.js +28 -0
- package/dist/experimental/rsc-flight-response.d.ts.map +1 -1
- package/dist/experimental/rsc-flight-response.js +2 -6
- package/dist/experimental/server-functions-server.js +1 -1
- package/dist/experimental/server-functions-types.d.ts +1 -1
- package/dist/experimental/server-functions-types.d.ts.map +1 -1
- package/dist/index.d.ts +16 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -1
- package/dist/module.d.ts +8 -2
- package/dist/module.d.ts.map +1 -1
- package/dist/module.js +31 -8
- package/dist/page-catalog.d.ts +29 -0
- package/dist/page-catalog.d.ts.map +1 -0
- package/dist/page-catalog.js +46 -0
- package/dist/page-metadata.d.ts +58 -0
- package/dist/page-metadata.d.ts.map +1 -0
- package/dist/page-metadata.js +139 -0
- package/dist/page-renderer.d.ts +24 -0
- package/dist/page-renderer.d.ts.map +1 -0
- package/dist/page-renderer.js +18 -0
- package/dist/page-result.d.ts +16 -0
- package/dist/page-result.d.ts.map +1 -0
- package/dist/page-result.js +101 -0
- package/dist/render-diagnostics.d.ts +25 -0
- package/dist/render-diagnostics.d.ts.map +1 -0
- package/dist/render-diagnostics.js +94 -0
- package/dist/render-policy-metadata.d.ts +40 -0
- package/dist/render-policy-metadata.d.ts.map +1 -0
- package/dist/render-policy-metadata.js +136 -0
- package/dist/render-policy.d.ts +87 -0
- package/dist/render-policy.d.ts.map +1 -0
- package/dist/render-policy.js +203 -0
- package/dist/render-stream.d.ts +1 -1
- package/dist/render-stream.d.ts.map +1 -1
- package/dist/render-stream.js +80 -15
- package/dist/render.d.ts +12 -3
- package/dist/render.d.ts.map +1 -1
- package/dist/render.js +70 -76
- package/dist/server-entry.d.ts +13 -1
- package/dist/server-entry.d.ts.map +1 -1
- package/dist/server-entry.js +21 -11
- package/dist/typegen-artifact.d.ts +9 -0
- package/dist/typegen-artifact.d.ts.map +1 -0
- package/dist/typegen-artifact.js +116 -0
- package/dist/typegen.d.ts +41 -0
- package/dist/typegen.d.ts.map +1 -0
- package/dist/typegen.js +162 -0
- package/package.json +11 -6
package/dist/render.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createReactRenderDiagnostics } from './render-diagnostics.js';
|
|
1
2
|
import { collectReadableStream, pipeReadableStream, throwIfReactRequestAborted } from './render-stream.js';
|
|
2
3
|
const HTML_CONTENT_TYPE = 'text/html; charset=utf-8';
|
|
3
4
|
|
|
@@ -9,7 +10,7 @@ const HTML_CONTENT_TYPE = 'text/html; charset=utf-8';
|
|
|
9
10
|
|
|
10
11
|
/** Options for rendering a React entry into one fluo response. */
|
|
11
12
|
|
|
12
|
-
/**
|
|
13
|
+
/** Request-scoped fluo context available to page renderers and render policy components. */
|
|
13
14
|
|
|
14
15
|
function applyEntryHeaders(entry, requestContext) {
|
|
15
16
|
for (const [name, value] of Object.entries(entry.headers)) {
|
|
@@ -97,58 +98,6 @@ function createReactDomRenderOptions(options) {
|
|
|
97
98
|
} : {})
|
|
98
99
|
};
|
|
99
100
|
}
|
|
100
|
-
function createRecoverableErrorContext(errorInfo, requestContext) {
|
|
101
|
-
return {
|
|
102
|
-
...(errorInfo !== undefined ? {
|
|
103
|
-
errorInfo
|
|
104
|
-
} : {}),
|
|
105
|
-
request: requestContext.request,
|
|
106
|
-
...(requestContext.requestId !== undefined ? {
|
|
107
|
-
requestId: requestContext.requestId
|
|
108
|
-
} : {})
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
|
-
function reportRecoverableError(entry, requestContext, event) {
|
|
112
|
-
const hook = entry.onRecoverableError;
|
|
113
|
-
if (!hook) {
|
|
114
|
-
return;
|
|
115
|
-
}
|
|
116
|
-
try {
|
|
117
|
-
hook(event.error, createRecoverableErrorContext(event.errorInfo, requestContext));
|
|
118
|
-
} catch (error) {
|
|
119
|
-
if (error instanceof Error) {
|
|
120
|
-
return;
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
function reportRecoverableErrors(entry, requestContext, events) {
|
|
125
|
-
for (const event of events) {
|
|
126
|
-
reportRecoverableError(entry, requestContext, event);
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
async function writeReactStream(plan) {
|
|
130
|
-
const {
|
|
131
|
-
applySuccessMetadata,
|
|
132
|
-
entry,
|
|
133
|
-
pendingRecoverableErrors,
|
|
134
|
-
requestContext,
|
|
135
|
-
stream
|
|
136
|
-
} = plan;
|
|
137
|
-
const responseStream = requestContext.response.stream;
|
|
138
|
-
if (!responseStream) {
|
|
139
|
-
const body = await collectReadableStream(stream, requestContext.request);
|
|
140
|
-
throwIfReactRequestAborted(requestContext.request);
|
|
141
|
-
applySuccessMetadata();
|
|
142
|
-
reportRecoverableErrors(entry, requestContext, pendingRecoverableErrors);
|
|
143
|
-
await requestContext.response.send(body);
|
|
144
|
-
return;
|
|
145
|
-
}
|
|
146
|
-
applySuccessMetadata();
|
|
147
|
-
requestContext.response.committed = true;
|
|
148
|
-
responseStream.flush?.();
|
|
149
|
-
reportRecoverableErrors(entry, requestContext, pendingRecoverableErrors);
|
|
150
|
-
await pipeReadableStream(stream, responseStream, requestContext.request);
|
|
151
|
-
}
|
|
152
101
|
async function defaultRenderToReadableStream(node, options) {
|
|
153
102
|
const {
|
|
154
103
|
renderToReadableStream
|
|
@@ -156,6 +105,32 @@ async function defaultRenderToReadableStream(node, options) {
|
|
|
156
105
|
return renderToReadableStream(node, createReactDomRenderOptions(options));
|
|
157
106
|
}
|
|
158
107
|
|
|
108
|
+
/**
|
|
109
|
+
* Buffers a React server entry without mutating or committing a framework response.
|
|
110
|
+
*
|
|
111
|
+
* @param entry React server entry whose node and hydration assets are rendered.
|
|
112
|
+
* @param requestContext HTTP-owned request and abort surfaces.
|
|
113
|
+
* @param renderToReadableStream Optional Web Streams renderer override.
|
|
114
|
+
* @returns Complete HTML bytes after the render finishes without errors.
|
|
115
|
+
*/
|
|
116
|
+
export async function renderReactServerEntryToBytes(entry, requestContext, renderToReadableStream = defaultRenderToReadableStream) {
|
|
117
|
+
throwIfReactRequestAborted(requestContext.request);
|
|
118
|
+
let hasRenderError = false;
|
|
119
|
+
let renderError;
|
|
120
|
+
const stream = await renderToReadableStream(entry.node, createReactReadableStreamRenderOptions(entry, requestContext, error => {
|
|
121
|
+
if (!hasRenderError) {
|
|
122
|
+
hasRenderError = true;
|
|
123
|
+
renderError = error;
|
|
124
|
+
}
|
|
125
|
+
}));
|
|
126
|
+
const body = await collectReadableStream(stream, requestContext.request);
|
|
127
|
+
throwIfReactRequestAborted(requestContext.request);
|
|
128
|
+
if (hasRenderError) {
|
|
129
|
+
throw renderError;
|
|
130
|
+
}
|
|
131
|
+
return body;
|
|
132
|
+
}
|
|
133
|
+
|
|
159
134
|
/**
|
|
160
135
|
* Renders a React server entry to one fluo HTML response using Web Streams SSR.
|
|
161
136
|
*
|
|
@@ -167,35 +142,54 @@ async function defaultRenderToReadableStream(node, options) {
|
|
|
167
142
|
* @throws RequestAbortedError before buffered responses commit when the request aborts.
|
|
168
143
|
*/
|
|
169
144
|
export async function renderReactResponse(entry, requestContext, options = {}) {
|
|
170
|
-
|
|
145
|
+
const diagnostics = createReactRenderDiagnostics(entry, requestContext);
|
|
171
146
|
const renderToReadableStream = options.renderToReadableStream ?? defaultRenderToReadableStream;
|
|
172
147
|
const pendingRecoverableErrors = [];
|
|
173
148
|
let shellReady = false;
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
149
|
+
let stream;
|
|
150
|
+
try {
|
|
151
|
+
throwIfReactRequestAborted(requestContext.request);
|
|
152
|
+
stream = await renderToReadableStream(entry.node, createReactReadableStreamRenderOptions(entry, requestContext, (error, errorInfo) => {
|
|
153
|
+
const event = errorInfo !== undefined ? {
|
|
154
|
+
error,
|
|
155
|
+
errorInfo
|
|
156
|
+
} : {
|
|
157
|
+
error
|
|
158
|
+
};
|
|
159
|
+
if (shellReady) {
|
|
160
|
+
diagnostics.reportRecoverableError(event);
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
pendingRecoverableErrors.push(event);
|
|
164
|
+
}));
|
|
165
|
+
shellReady = true;
|
|
166
|
+
throwIfReactRequestAborted(requestContext.request);
|
|
167
|
+
} catch (error) {
|
|
168
|
+
throw diagnostics.preservePreCommitShellError(error);
|
|
169
|
+
}
|
|
189
170
|
const applySuccessMetadata = () => {
|
|
190
171
|
options.applySuccessResponseMetadata?.();
|
|
191
172
|
applyEntryStatus(entry, requestContext);
|
|
192
173
|
applyEntryHeaders(entry, requestContext);
|
|
193
174
|
};
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
175
|
+
const responseStream = requestContext.response.stream;
|
|
176
|
+
if (!responseStream) {
|
|
177
|
+
let body;
|
|
178
|
+
try {
|
|
179
|
+
body = await collectReadableStream(stream, requestContext.request);
|
|
180
|
+
throwIfReactRequestAborted(requestContext.request);
|
|
181
|
+
} catch (error) {
|
|
182
|
+
throw diagnostics.preservePreCommitShellError(error);
|
|
183
|
+
}
|
|
184
|
+
applySuccessMetadata();
|
|
185
|
+
diagnostics.reportRecoverableErrors(pendingRecoverableErrors);
|
|
186
|
+
await requestContext.response.send(body);
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
applySuccessMetadata();
|
|
190
|
+
requestContext.response.committed = true;
|
|
191
|
+
responseStream.flush?.();
|
|
192
|
+
diagnostics.reportRecoverableErrors(pendingRecoverableErrors);
|
|
193
|
+
await pipeReadableStream(stream, responseStream, requestContext.request);
|
|
194
|
+
diagnostics.reportRequestAbort();
|
|
201
195
|
}
|
package/dist/server-entry.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import type { FrameworkRequest } from '@fluojs/http';
|
|
1
|
+
import type { FrameworkRequest } from '@fluojs/http/portable';
|
|
2
2
|
import { type ReactNode } from 'react';
|
|
3
|
+
import type { ReactSsrDiagnosticCode, ReactSsrDiagnosticPhase } from './diagnostics.js';
|
|
3
4
|
/** Header values applied before a React server entry starts streaming. */
|
|
4
5
|
export type ReactServerEntryHeaders = Readonly<Record<string, string | readonly string[]>>;
|
|
5
6
|
/** Build-produced asset names mapped to public URLs shared by server render and client hydration. */
|
|
@@ -17,8 +18,12 @@ export type ReactBootstrapScriptDescriptor = {
|
|
|
17
18
|
export type ReactBootstrapAsset = string | ReactBootstrapScriptDescriptor;
|
|
18
19
|
/** Recoverable React render error details reported after the shell can stream. */
|
|
19
20
|
export type ReactRecoverableErrorContext = {
|
|
21
|
+
/** Stable machine-readable diagnostic code for recoverable rendering failures. */
|
|
22
|
+
readonly code: ReactSsrDiagnosticCode;
|
|
20
23
|
/** React-provided error metadata, such as a component stack, when available. */
|
|
21
24
|
readonly errorInfo?: unknown;
|
|
25
|
+
/** Stable SSR lifecycle phase for recoverable rendering failures. */
|
|
26
|
+
readonly phase: ReactSsrDiagnosticPhase;
|
|
22
27
|
/** Framework request being rendered. */
|
|
23
28
|
readonly request: FrameworkRequest;
|
|
24
29
|
/** Adapter-provided request id, when available. */
|
|
@@ -70,6 +75,13 @@ export type ReactServerEntry = {
|
|
|
70
75
|
/** HTTP status to apply before streaming starts. Defaults to the current response status or `200`. */
|
|
71
76
|
readonly status?: number;
|
|
72
77
|
};
|
|
78
|
+
/**
|
|
79
|
+
* Returns whether a value is a React server entry created or branded by the stable SSR seam.
|
|
80
|
+
*
|
|
81
|
+
* @param value Candidate response value.
|
|
82
|
+
* @returns Whether the value carries the React server entry brand.
|
|
83
|
+
*/
|
|
84
|
+
export declare function isReactServerEntry(value: unknown): value is ReactServerEntry;
|
|
73
85
|
/**
|
|
74
86
|
* Creates a runtime-neutral React server entry for streamed HTML rendering.
|
|
75
87
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server-entry.d.ts","sourceRoot":"","sources":["../src/server-entry.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"server-entry.d.ts","sourceRoot":"","sources":["../src/server-entry.ts"],"names":[],"mappings":"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"}
|
package/dist/server-entry.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { registerFrameworkResponseWriter } from '@fluojs/http/internal';
|
|
1
2
|
import { cloneElement, isValidElement } from 'react';
|
|
2
|
-
const
|
|
3
|
+
const serverEntryKey = Symbol.for('fluo.react.serverEntry');
|
|
3
4
|
|
|
4
5
|
/** Header values applied before a React server entry starts streaming. */
|
|
5
6
|
|
|
@@ -17,6 +18,15 @@ const responseWriterKey = Symbol.for('fluo.http.responseWriter');
|
|
|
17
18
|
|
|
18
19
|
/** Runtime-neutral React server entry rendered to streamed HTML by `renderReactResponse(...)`. */
|
|
19
20
|
|
|
21
|
+
/**
|
|
22
|
+
* Returns whether a value is a React server entry created or branded by the stable SSR seam.
|
|
23
|
+
*
|
|
24
|
+
* @param value Candidate response value.
|
|
25
|
+
* @returns Whether the value carries the React server entry brand.
|
|
26
|
+
*/
|
|
27
|
+
export function isReactServerEntry(value) {
|
|
28
|
+
return typeof value === 'object' && value !== null && Reflect.get(value, serverEntryKey) === true;
|
|
29
|
+
}
|
|
20
30
|
function cloneAssetMap(assetMap) {
|
|
21
31
|
const cloned = {};
|
|
22
32
|
Object.setPrototypeOf(cloned, null);
|
|
@@ -111,16 +121,16 @@ export function createReactServerEntry(node, options = {}) {
|
|
|
111
121
|
status: options.status
|
|
112
122
|
} : {})
|
|
113
123
|
};
|
|
114
|
-
Object.defineProperty(entry,
|
|
124
|
+
Object.defineProperty(entry, serverEntryKey, {
|
|
115
125
|
enumerable: false,
|
|
116
|
-
value:
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
126
|
+
value: true
|
|
127
|
+
});
|
|
128
|
+
return registerFrameworkResponseWriter(entry, async context => {
|
|
129
|
+
const {
|
|
130
|
+
renderReactResponse
|
|
131
|
+
} = await import('./render.js');
|
|
132
|
+
await renderReactResponse(entry, context.requestContext, {
|
|
133
|
+
applySuccessResponseMetadata: context.applySuccessResponseMetadata
|
|
134
|
+
});
|
|
124
135
|
});
|
|
125
|
-
return entry;
|
|
126
136
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ReactPageCatalogEntry } from './page-catalog.js';
|
|
2
|
+
/**
|
|
3
|
+
* Parses the route catalog encoded in one canonical generated React page artifact.
|
|
4
|
+
*
|
|
5
|
+
* @param source Generated artifact source to inspect.
|
|
6
|
+
* @returns Parsed catalog entries, or `undefined` when the artifact body is malformed.
|
|
7
|
+
*/
|
|
8
|
+
export declare function parseGeneratedReactPageCatalog(source: string): readonly ReactPageCatalogEntry[] | undefined;
|
|
9
|
+
//# sourceMappingURL=typegen-artifact.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"typegen-artifact.d.ts","sourceRoot":"","sources":["../src/typegen-artifact.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AA4F/D;;;;;GAKG;AACH,wBAAgB,8BAA8B,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,qBAAqB,EAAE,GAAG,SAAS,CAiB3G"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
const JSON_STRING_SOURCE = '"(?:\\\\.|[^"\\\\])*"';
|
|
2
|
+
const PATH_LINE_PATTERN = new RegExp(`^ readonly (${JSON_STRING_SOURCE}): (${JSON_STRING_SOURCE});$`, 'u');
|
|
3
|
+
const PARAM_OPEN_PATTERN = new RegExp(`^ readonly (${JSON_STRING_SOURCE}): \\{$`, 'u');
|
|
4
|
+
const PARAM_LINE_PATTERN = new RegExp(`^ readonly (${JSON_STRING_SOURCE}): string;$`, 'u');
|
|
5
|
+
const PARAM_UNDEFINED_PATTERN = new RegExp(`^ readonly (${JSON_STRING_SOURCE}): undefined;$`, 'u');
|
|
6
|
+
function parseJsonString(value) {
|
|
7
|
+
try {
|
|
8
|
+
const parsed = JSON.parse(value);
|
|
9
|
+
return typeof parsed === 'string' ? parsed : undefined;
|
|
10
|
+
} catch {
|
|
11
|
+
return undefined;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
function readSection(lines, opening, closing) {
|
|
15
|
+
const start = lines.indexOf(opening);
|
|
16
|
+
if (start < 0) {
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
const end = lines.indexOf(closing, start + 1);
|
|
20
|
+
return end < 0 ? undefined : lines.slice(start + 1, end);
|
|
21
|
+
}
|
|
22
|
+
function parsePaths(lines) {
|
|
23
|
+
if (lines.includes('export type ReactPagePathById = Readonly<Record<never, never>>;')) {
|
|
24
|
+
return new Map();
|
|
25
|
+
}
|
|
26
|
+
const section = readSection(lines, 'export interface ReactPagePathById {', '}');
|
|
27
|
+
if (section === undefined || section.length === 0) {
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
const paths = new Map();
|
|
31
|
+
for (const line of section) {
|
|
32
|
+
const match = PATH_LINE_PATTERN.exec(line);
|
|
33
|
+
const id = match?.[1] === undefined ? undefined : parseJsonString(match[1]);
|
|
34
|
+
const path = match?.[2] === undefined ? undefined : parseJsonString(match[2]);
|
|
35
|
+
if (id === undefined || path === undefined || paths.has(id)) {
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
38
|
+
paths.set(id, path);
|
|
39
|
+
}
|
|
40
|
+
return paths;
|
|
41
|
+
}
|
|
42
|
+
function parseParams(lines) {
|
|
43
|
+
if (lines.includes('export type ReactPageParamsById = Readonly<Record<never, never>>;')) {
|
|
44
|
+
return new Map();
|
|
45
|
+
}
|
|
46
|
+
const section = readSection(lines, 'export interface ReactPageParamsById {', '}');
|
|
47
|
+
if (section === undefined || section.length === 0) {
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
const paramsById = new Map();
|
|
51
|
+
for (let index = 0; index < section.length; index += 1) {
|
|
52
|
+
const line = section[index] ?? '';
|
|
53
|
+
const undefinedMatch = PARAM_UNDEFINED_PATTERN.exec(line);
|
|
54
|
+
const undefinedId = undefinedMatch?.[1] === undefined ? undefined : parseJsonString(undefinedMatch[1]);
|
|
55
|
+
if (undefinedId !== undefined) {
|
|
56
|
+
if (paramsById.has(undefinedId)) {
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
59
|
+
paramsById.set(undefinedId, []);
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
const openMatch = PARAM_OPEN_PATTERN.exec(line);
|
|
63
|
+
const id = openMatch?.[1] === undefined ? undefined : parseJsonString(openMatch[1]);
|
|
64
|
+
if (id === undefined || paramsById.has(id)) {
|
|
65
|
+
return undefined;
|
|
66
|
+
}
|
|
67
|
+
const params = [];
|
|
68
|
+
index += 1;
|
|
69
|
+
while (index < section.length && section[index] !== ' };') {
|
|
70
|
+
const paramMatch = PARAM_LINE_PATTERN.exec(section[index] ?? '');
|
|
71
|
+
const param = paramMatch?.[1] === undefined ? undefined : parseJsonString(paramMatch[1]);
|
|
72
|
+
if (param === undefined) {
|
|
73
|
+
return undefined;
|
|
74
|
+
}
|
|
75
|
+
params.push(param);
|
|
76
|
+
index += 1;
|
|
77
|
+
}
|
|
78
|
+
if (section[index] !== ' };' || params.length === 0) {
|
|
79
|
+
return undefined;
|
|
80
|
+
}
|
|
81
|
+
paramsById.set(id, params);
|
|
82
|
+
}
|
|
83
|
+
return paramsById;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Parses the route catalog encoded in one canonical generated React page artifact.
|
|
88
|
+
*
|
|
89
|
+
* @param source Generated artifact source to inspect.
|
|
90
|
+
* @returns Parsed catalog entries, or `undefined` when the artifact body is malformed.
|
|
91
|
+
*/
|
|
92
|
+
export function parseGeneratedReactPageCatalog(source) {
|
|
93
|
+
const lines = source.replaceAll('\r\n', '\n').split('\n');
|
|
94
|
+
const paths = parsePaths(lines);
|
|
95
|
+
const paramsById = parseParams(lines);
|
|
96
|
+
if (paths === undefined || paramsById === undefined || paths.size !== paramsById.size) {
|
|
97
|
+
return undefined;
|
|
98
|
+
}
|
|
99
|
+
const catalog = [];
|
|
100
|
+
for (const [id, path] of paths) {
|
|
101
|
+
const params = paramsById.get(id);
|
|
102
|
+
if (params === undefined) {
|
|
103
|
+
return undefined;
|
|
104
|
+
}
|
|
105
|
+
catalog.push({
|
|
106
|
+
handler: '',
|
|
107
|
+
id,
|
|
108
|
+
kind: 'react-page',
|
|
109
|
+
method: 'GET',
|
|
110
|
+
params,
|
|
111
|
+
path,
|
|
112
|
+
router: ''
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
return catalog;
|
|
116
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { ReactPageCatalogEntry } from './page-catalog.js';
|
|
2
|
+
/** Current schema version embedded in generated React page type artifacts. */
|
|
3
|
+
export declare const REACT_PAGE_TYPEGEN_ARTIFACT_VERSION = 1;
|
|
4
|
+
/** Structural classification of an existing React page type artifact. */
|
|
5
|
+
export type ReactPageTypeArtifactInspection = {
|
|
6
|
+
readonly status: 'malformed';
|
|
7
|
+
} | {
|
|
8
|
+
readonly status: 'unsupported-version';
|
|
9
|
+
readonly version: number;
|
|
10
|
+
} | {
|
|
11
|
+
readonly status: 'valid';
|
|
12
|
+
readonly version: number;
|
|
13
|
+
};
|
|
14
|
+
/** Stable diagnostic codes emitted by React page type generation. */
|
|
15
|
+
export declare const REACT_PAGE_TYPEGEN_ERROR_CODES: {
|
|
16
|
+
readonly VERSIONED_ROUTE_UNSUPPORTED: "react-page-typegen-versioned-route-unsupported";
|
|
17
|
+
};
|
|
18
|
+
/** Diagnostic code emitted by React page type generation. */
|
|
19
|
+
export type ReactPageTypegenErrorCode = (typeof REACT_PAGE_TYPEGEN_ERROR_CODES)[keyof typeof REACT_PAGE_TYPEGEN_ERROR_CODES];
|
|
20
|
+
/** Typed failure raised when a catalog entry cannot be represented by path-only output. */
|
|
21
|
+
export declare class ReactPageTypegenError extends Error {
|
|
22
|
+
readonly routeId: string;
|
|
23
|
+
readonly name = "ReactPageTypegenError";
|
|
24
|
+
readonly code: ReactPageTypegenErrorCode;
|
|
25
|
+
constructor(routeId: string);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Classifies generated React page type source before tooling compares its bytes.
|
|
29
|
+
*
|
|
30
|
+
* @param source Existing artifact source read from disk.
|
|
31
|
+
* @returns Its current, malformed, or unsupported-version structural status.
|
|
32
|
+
*/
|
|
33
|
+
export declare function inspectReactPageTypeArtifact(source: string): ReactPageTypeArtifactInspection;
|
|
34
|
+
/**
|
|
35
|
+
* Generates path-only TypeScript route declarations and href builders from a React page catalog.
|
|
36
|
+
*
|
|
37
|
+
* @param catalog Bootstrap-resolved React page catalog entries.
|
|
38
|
+
* @returns Deterministic TypeScript source for application-owned route tooling.
|
|
39
|
+
*/
|
|
40
|
+
export declare function generateReactPageTypes(catalog: readonly ReactPageCatalogEntry[]): string;
|
|
41
|
+
//# sourceMappingURL=typegen.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"typegen.d.ts","sourceRoot":"","sources":["../src/typegen.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAG/D,8EAA8E;AAC9E,eAAO,MAAM,mCAAmC,IAAI,CAAC;AAMrD,yEAAyE;AACzE,MAAM,MAAM,+BAA+B,GACvC;IAAE,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAA;CAAE,GAChC;IAAE,QAAQ,CAAC,MAAM,EAAE,qBAAqB,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACpE;IAAE,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAE3D,qEAAqE;AACrE,eAAO,MAAM,8BAA8B;;CAEjC,CAAC;AAEX,6DAA6D;AAC7D,MAAM,MAAM,yBAAyB,GAAG,CAAC,OAAO,8BAA8B,CAAC,CAAC,MAAM,OAAO,8BAA8B,CAAC,CAAC;AAE7H,2FAA2F;AAC3F,qBAAa,qBAAsB,SAAQ,KAAK;IAIlC,QAAQ,CAAC,OAAO,EAAE,MAAM;IAHpC,QAAQ,CAAC,IAAI,2BAA2B;IACxC,QAAQ,CAAC,IAAI,EAAE,yBAAyB,CAA8D;gBAEjF,OAAO,EAAE,MAAM;CAGrC;AAED;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAAC,MAAM,EAAE,MAAM,GAAG,+BAA+B,CAuB5F;AAqGD;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,SAAS,qBAAqB,EAAE,GAAG,MAAM,CAqCxF"}
|
package/dist/typegen.js
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { parseGeneratedReactPageCatalog } from './typegen-artifact.js';
|
|
2
|
+
|
|
3
|
+
/** Current schema version embedded in generated React page type artifacts. */
|
|
4
|
+
export const REACT_PAGE_TYPEGEN_ARTIFACT_VERSION = 1;
|
|
5
|
+
const GENERATED_BANNER = `/* Generated by @fluojs/react/typegen. Artifact version: ${REACT_PAGE_TYPEGEN_ARTIFACT_VERSION}. Do not edit manually. */`;
|
|
6
|
+
const GENERATED_FOOTER = '/* End generated @fluojs/react/typegen artifact. */';
|
|
7
|
+
const GENERATED_BANNER_PATTERN = /^\/\* Generated by @fluojs\/react\/typegen\. Artifact version: (0|[1-9][0-9]{0,8})\. Do not edit manually\. \*\/\r?\n/u;
|
|
8
|
+
|
|
9
|
+
/** Structural classification of an existing React page type artifact. */
|
|
10
|
+
|
|
11
|
+
/** Stable diagnostic codes emitted by React page type generation. */
|
|
12
|
+
export const REACT_PAGE_TYPEGEN_ERROR_CODES = {
|
|
13
|
+
VERSIONED_ROUTE_UNSUPPORTED: 'react-page-typegen-versioned-route-unsupported'
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/** Diagnostic code emitted by React page type generation. */
|
|
17
|
+
|
|
18
|
+
/** Typed failure raised when a catalog entry cannot be represented by path-only output. */
|
|
19
|
+
export class ReactPageTypegenError extends Error {
|
|
20
|
+
name = 'ReactPageTypegenError';
|
|
21
|
+
code = REACT_PAGE_TYPEGEN_ERROR_CODES.VERSIONED_ROUTE_UNSUPPORTED;
|
|
22
|
+
constructor(routeId) {
|
|
23
|
+
super(`Versioned React page route "${routeId}" is unsupported by path-only typegen.`);
|
|
24
|
+
this.routeId = routeId;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Classifies generated React page type source before tooling compares its bytes.
|
|
30
|
+
*
|
|
31
|
+
* @param source Existing artifact source read from disk.
|
|
32
|
+
* @returns Its current, malformed, or unsupported-version structural status.
|
|
33
|
+
*/
|
|
34
|
+
export function inspectReactPageTypeArtifact(source) {
|
|
35
|
+
const match = GENERATED_BANNER_PATTERN.exec(source);
|
|
36
|
+
const rawVersion = match?.[1];
|
|
37
|
+
if (rawVersion === undefined) {
|
|
38
|
+
return {
|
|
39
|
+
status: 'malformed'
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
const version = Number(rawVersion);
|
|
43
|
+
if (version !== REACT_PAGE_TYPEGEN_ARTIFACT_VERSION) {
|
|
44
|
+
return {
|
|
45
|
+
status: 'unsupported-version',
|
|
46
|
+
version
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
const normalizedSource = source.replaceAll('\r\n', '\n');
|
|
50
|
+
const parsedCatalog = parseGeneratedReactPageCatalog(normalizedSource);
|
|
51
|
+
if (parsedCatalog === undefined || !normalizedSource.endsWith(`${GENERATED_FOOTER}\n`) || generateReactPageTypes(parsedCatalog) !== normalizedSource) {
|
|
52
|
+
return {
|
|
53
|
+
status: 'malformed'
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
status: 'valid',
|
|
58
|
+
version
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function stringLiteral(value) {
|
|
62
|
+
return JSON.stringify(value);
|
|
63
|
+
}
|
|
64
|
+
function renderPathMap(catalog) {
|
|
65
|
+
if (catalog.length === 0) {
|
|
66
|
+
return ['export type ReactPagePathById = Readonly<Record<never, never>>;'];
|
|
67
|
+
}
|
|
68
|
+
return ['export interface ReactPagePathById {', ...catalog.map(entry => ` readonly ${stringLiteral(entry.id)}: ${stringLiteral(entry.path)};`), '}'];
|
|
69
|
+
}
|
|
70
|
+
function uniqueParams(entry) {
|
|
71
|
+
return [...new Set(entry.params)];
|
|
72
|
+
}
|
|
73
|
+
function renderParamsMap(catalog) {
|
|
74
|
+
if (catalog.length === 0) {
|
|
75
|
+
return ['export type ReactPageParamsById = Readonly<Record<never, never>>;'];
|
|
76
|
+
}
|
|
77
|
+
const lines = ['export interface ReactPageParamsById {'];
|
|
78
|
+
for (const entry of catalog) {
|
|
79
|
+
const params = uniqueParams(entry);
|
|
80
|
+
if (params.length === 0) {
|
|
81
|
+
lines.push(` readonly ${stringLiteral(entry.id)}: undefined;`);
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
lines.push(` readonly ${stringLiteral(entry.id)}: {`);
|
|
85
|
+
lines.push(...params.map(param => ` readonly ${stringLiteral(param)}: string;`));
|
|
86
|
+
lines.push(' };');
|
|
87
|
+
}
|
|
88
|
+
lines.push('}');
|
|
89
|
+
return lines;
|
|
90
|
+
}
|
|
91
|
+
function renderHrefExpression(entry) {
|
|
92
|
+
const params = uniqueParams(entry);
|
|
93
|
+
if (params.length === 0) {
|
|
94
|
+
return stringLiteral(entry.path);
|
|
95
|
+
}
|
|
96
|
+
const paramNames = new Set(params);
|
|
97
|
+
const parts = entry.path.split('/').slice(1).flatMap(segment => {
|
|
98
|
+
const paramName = segment.startsWith(':') ? segment.slice(1) : undefined;
|
|
99
|
+
if (paramName !== undefined && paramNames.has(paramName)) {
|
|
100
|
+
return [stringLiteral('/'), `encodeURIComponent(params[${stringLiteral(paramName)}])`];
|
|
101
|
+
}
|
|
102
|
+
return [stringLiteral(`/${segment}`)];
|
|
103
|
+
});
|
|
104
|
+
return `[${parts.join(', ')}].join('')`;
|
|
105
|
+
}
|
|
106
|
+
function renderParameters(entry, leadingParameter) {
|
|
107
|
+
if (uniqueParams(entry).length === 0) {
|
|
108
|
+
return `(${leadingParameter ?? ''})`;
|
|
109
|
+
}
|
|
110
|
+
const expected = `ReactPageParamsById[${stringLiteral(entry.id)}]`;
|
|
111
|
+
const prefix = leadingParameter === undefined ? '' : `${leadingParameter}, `;
|
|
112
|
+
return `<Actual extends ${expected}>(${prefix}params: Actual & Record<Actual extends ${expected} ? Exclude<keyof Actual, keyof ${expected}> : never, never>)`;
|
|
113
|
+
}
|
|
114
|
+
function renderHref(entry) {
|
|
115
|
+
return `href: ${renderParameters(entry)}: string => ${renderHrefExpression(entry)}`;
|
|
116
|
+
}
|
|
117
|
+
function renderLink(entry) {
|
|
118
|
+
return `link: ${renderParameters(entry)}: ReactPageLinkProps => ({ href: ${renderHrefExpression(entry)} })`;
|
|
119
|
+
}
|
|
120
|
+
function renderNavigation(entry, operation) {
|
|
121
|
+
const parameters = renderParameters(entry, 'navigator: ReactPageNavigator');
|
|
122
|
+
return `${operation}: ${parameters}: void => navigator.${operation}(${renderHrefExpression(entry)})`;
|
|
123
|
+
}
|
|
124
|
+
function renderRoutes(catalog) {
|
|
125
|
+
const lines = ['export const reactPageRoutes = {'];
|
|
126
|
+
for (const entry of catalog) {
|
|
127
|
+
lines.push(` ${stringLiteral(entry.id)}: {`);
|
|
128
|
+
lines.push(` id: ${stringLiteral(entry.id)},`);
|
|
129
|
+
lines.push(` path: ${stringLiteral(entry.path)},`);
|
|
130
|
+
lines.push(` ${renderHref(entry)},`);
|
|
131
|
+
lines.push(` ${renderLink(entry)},`);
|
|
132
|
+
lines.push(` ${renderNavigation(entry, 'push')},`);
|
|
133
|
+
lines.push(` ${renderNavigation(entry, 'replace')},`);
|
|
134
|
+
lines.push(' },');
|
|
135
|
+
}
|
|
136
|
+
lines.push('} as const;');
|
|
137
|
+
return lines;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Generates path-only TypeScript route declarations and href builders from a React page catalog.
|
|
142
|
+
*
|
|
143
|
+
* @param catalog Bootstrap-resolved React page catalog entries.
|
|
144
|
+
* @returns Deterministic TypeScript source for application-owned route tooling.
|
|
145
|
+
*/
|
|
146
|
+
export function generateReactPageTypes(catalog) {
|
|
147
|
+
for (const entry of catalog) {
|
|
148
|
+
if (entry.version !== undefined) {
|
|
149
|
+
throw new ReactPageTypegenError(entry.id);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
const sortedCatalog = [...catalog].sort((left, right) => {
|
|
153
|
+
if (left.id < right.id) {
|
|
154
|
+
return -1;
|
|
155
|
+
}
|
|
156
|
+
if (left.id > right.id) {
|
|
157
|
+
return 1;
|
|
158
|
+
}
|
|
159
|
+
return 0;
|
|
160
|
+
});
|
|
161
|
+
return [GENERATED_BANNER, '', `export type ReactPageRouteId = ${sortedCatalog.length === 0 ? 'never' : sortedCatalog.map(entry => stringLiteral(entry.id)).join(' | ')};`, ...renderPathMap(sortedCatalog), ...renderParamsMap(sortedCatalog), 'export type ReactPagePath<RouteId extends ReactPageRouteId> = ReactPagePathById[RouteId];', 'export type ReactPageParams<RouteId extends ReactPageRouteId> = ReactPageParamsById[RouteId];', '/** Real-anchor props produced by one generated React page route. */', 'export type ReactPageLinkProps = { readonly href: string; };', '/** Minimal HTTP-first router surface consumed by generated push and replace methods. */', 'export interface ReactPageNavigator {', ' readonly push: (href: string) => void;', ' readonly replace: (href: string) => void;', '}', ...renderRoutes(sortedCatalog), 'export type ReactPageRoute = (typeof reactPageRoutes)[ReactPageRouteId];', GENERATED_FOOTER, ''].join('\n');
|
|
162
|
+
}
|
package/package.json
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"runtime-neutral",
|
|
9
9
|
"standard-decorators"
|
|
10
10
|
],
|
|
11
|
-
"version": "0.
|
|
11
|
+
"version": "0.2.0",
|
|
12
12
|
"private": false,
|
|
13
13
|
"license": "MIT",
|
|
14
14
|
"repository": {
|
|
@@ -33,6 +33,10 @@
|
|
|
33
33
|
"types": "./dist/experimental/rsc.d.ts",
|
|
34
34
|
"import": "./dist/experimental/rsc.js"
|
|
35
35
|
},
|
|
36
|
+
"./typegen": {
|
|
37
|
+
"types": "./dist/typegen.d.ts",
|
|
38
|
+
"import": "./dist/typegen.js"
|
|
39
|
+
},
|
|
36
40
|
"./vite": {
|
|
37
41
|
"types": "./dist/vite.d.ts",
|
|
38
42
|
"import": "./dist/vite.js"
|
|
@@ -44,10 +48,10 @@
|
|
|
44
48
|
"dist"
|
|
45
49
|
],
|
|
46
50
|
"dependencies": {
|
|
47
|
-
"@fluojs/core": "^
|
|
48
|
-
"@fluojs/di": "^
|
|
49
|
-
"@fluojs/http": "^
|
|
50
|
-
"@fluojs/runtime": "^
|
|
51
|
+
"@fluojs/core": "^2.0.0",
|
|
52
|
+
"@fluojs/di": "^3.0.0",
|
|
53
|
+
"@fluojs/http": "^3.0.0",
|
|
54
|
+
"@fluojs/runtime": "^3.0.0"
|
|
51
55
|
},
|
|
52
56
|
"peerDependencies": {
|
|
53
57
|
"react": "^18.3.0 || ^19.0.0",
|
|
@@ -56,11 +60,12 @@
|
|
|
56
60
|
"devDependencies": {
|
|
57
61
|
"@types/react": "^19.2.14",
|
|
58
62
|
"@types/react-dom": "^19.2.3",
|
|
59
|
-
"vitest": "^
|
|
63
|
+
"vitest": "^4.1.11"
|
|
60
64
|
},
|
|
61
65
|
"scripts": {
|
|
62
66
|
"prebuild": "node ../../tooling/scripts/clean-dist.mjs",
|
|
63
67
|
"build": "pnpm exec babel src --extensions .ts --ignore 'src/**/*.test.ts' --out-dir dist --config-file ../../tooling/babel/babel.config.cjs && pnpm exec tsc -p tsconfig.build.json",
|
|
68
|
+
"pretest": "pnpm --dir ../.. --filter '@fluojs/react...' build",
|
|
64
69
|
"typecheck": "pnpm exec tsc -p tsconfig.json --noEmit",
|
|
65
70
|
"test": "pnpm exec vitest run -c vitest.config.ts",
|
|
66
71
|
"test:watch": "pnpm exec vitest -c vitest.config.ts"
|