@khairold/xml-render 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.
- package/README.md +372 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +41 -0
- package/dist/index.js.map +1 -0
- package/dist/parser.d.ts +129 -0
- package/dist/parser.d.ts.map +1 -0
- package/dist/parser.js +321 -0
- package/dist/parser.js.map +1 -0
- package/dist/react/ErrorBoundary.d.ts +56 -0
- package/dist/react/ErrorBoundary.d.ts.map +1 -0
- package/dist/react/ErrorBoundary.js +69 -0
- package/dist/react/ErrorBoundary.js.map +1 -0
- package/dist/react/XmlRender.d.ts +62 -0
- package/dist/react/XmlRender.d.ts.map +1 -0
- package/dist/react/XmlRender.js +90 -0
- package/dist/react/XmlRender.js.map +1 -0
- package/dist/react/catalog.d.ts +99 -0
- package/dist/react/catalog.d.ts.map +1 -0
- package/dist/react/catalog.js +55 -0
- package/dist/react/catalog.js.map +1 -0
- package/dist/react/context.d.ts +66 -0
- package/dist/react/context.d.ts.map +1 -0
- package/dist/react/context.js +63 -0
- package/dist/react/context.js.map +1 -0
- package/dist/react/index.d.ts +35 -0
- package/dist/react/index.d.ts.map +1 -0
- package/dist/react/index.js +41 -0
- package/dist/react/index.js.map +1 -0
- package/dist/react-native/ErrorBoundary.d.ts +60 -0
- package/dist/react-native/ErrorBoundary.d.ts.map +1 -0
- package/dist/react-native/ErrorBoundary.js +84 -0
- package/dist/react-native/ErrorBoundary.js.map +1 -0
- package/dist/react-native/XmlRender.d.ts +62 -0
- package/dist/react-native/XmlRender.d.ts.map +1 -0
- package/dist/react-native/XmlRender.js +91 -0
- package/dist/react-native/XmlRender.js.map +1 -0
- package/dist/react-native/catalog.d.ts +100 -0
- package/dist/react-native/catalog.d.ts.map +1 -0
- package/dist/react-native/catalog.js +56 -0
- package/dist/react-native/catalog.js.map +1 -0
- package/dist/react-native/context.d.ts +66 -0
- package/dist/react-native/context.d.ts.map +1 -0
- package/dist/react-native/context.js +63 -0
- package/dist/react-native/context.js.map +1 -0
- package/dist/react-native/index.d.ts +35 -0
- package/dist/react-native/index.d.ts.map +1 -0
- package/dist/react-native/index.js +41 -0
- package/dist/react-native/index.js.map +1 -0
- package/dist/registry.d.ts +99 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +93 -0
- package/dist/registry.js.map +1 -0
- package/dist/types.d.ts +436 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +28 -0
- package/dist/types.js.map +1 -0
- package/package.json +60 -0
package/dist/parser.js
ADDED
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Decode basic XML entities
|
|
3
|
+
*/
|
|
4
|
+
function decodeXmlEntities(text) {
|
|
5
|
+
return text
|
|
6
|
+
.replace(/</g, "<")
|
|
7
|
+
.replace(/>/g, ">")
|
|
8
|
+
.replace(/&/g, "&")
|
|
9
|
+
.replace(/"/g, '"');
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Parse attributes from an attribute string
|
|
13
|
+
* Handles both single and double quoted values
|
|
14
|
+
*/
|
|
15
|
+
function parseAttributes(attrString) {
|
|
16
|
+
const attrs = {};
|
|
17
|
+
if (!attrString)
|
|
18
|
+
return attrs;
|
|
19
|
+
// Match key="value" or key='value' patterns
|
|
20
|
+
const pattern = /(\w+)=["']([^"']*)["']/g;
|
|
21
|
+
let match;
|
|
22
|
+
while ((match = pattern.exec(attrString)) !== null) {
|
|
23
|
+
attrs[match[1]] = decodeXmlEntities(match[2]);
|
|
24
|
+
}
|
|
25
|
+
return attrs;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Create a parser instance bound to a registry.
|
|
29
|
+
*
|
|
30
|
+
* The parser recognizes tags defined in the registry and converts them
|
|
31
|
+
* into typed segments. Unknown tags are treated as literal text.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```ts
|
|
35
|
+
* import { z } from 'zod';
|
|
36
|
+
* import { createRegistry, createParser } from '@aura/xml-render';
|
|
37
|
+
*
|
|
38
|
+
* const registry = createRegistry({
|
|
39
|
+
* callout: {
|
|
40
|
+
* schema: z.object({ type: z.enum(['info', 'warning', 'error']) }),
|
|
41
|
+
* hasContent: true,
|
|
42
|
+
* },
|
|
43
|
+
* image: {
|
|
44
|
+
* schema: z.object({ src: z.string(), alt: z.string().optional() }),
|
|
45
|
+
* selfClosing: true,
|
|
46
|
+
* },
|
|
47
|
+
* });
|
|
48
|
+
*
|
|
49
|
+
* const parser = createParser(registry);
|
|
50
|
+
*
|
|
51
|
+
* const segments = parser.parse('Hello <callout type="info">Important!</callout> World');
|
|
52
|
+
* // [
|
|
53
|
+
* // { type: 'text', content: 'Hello ' },
|
|
54
|
+
* // { type: 'callout', content: 'Important!', attributes: { type: 'info' } },
|
|
55
|
+
* // { type: 'text', content: ' World' },
|
|
56
|
+
* // ]
|
|
57
|
+
* ```
|
|
58
|
+
*
|
|
59
|
+
* @param registry - The tag registry to use for parsing
|
|
60
|
+
* @returns A parser instance
|
|
61
|
+
*/
|
|
62
|
+
export function createParser(registry) {
|
|
63
|
+
// Build regex patterns for registered tags
|
|
64
|
+
const tagNames = registry.tagNames;
|
|
65
|
+
// Pattern to match opening tags: <tagname ...> or <tagname ... />
|
|
66
|
+
// Using alternation for exact tag name matching
|
|
67
|
+
const tagNamesPattern = tagNames.map(escapeRegex).join("|");
|
|
68
|
+
const openingTagPattern = new RegExp(`<(${tagNamesPattern})(\\s+[^>]*)?(\\/)?>`, "i");
|
|
69
|
+
/**
|
|
70
|
+
* Create a segment from parsed tag information
|
|
71
|
+
*/
|
|
72
|
+
function createSegment(tagName, attrString, content) {
|
|
73
|
+
const rawAttrs = parseAttributes(attrString);
|
|
74
|
+
const normalizedTagName = tagName.toLowerCase();
|
|
75
|
+
// Validate and transform attributes using registry schema
|
|
76
|
+
const validationResult = registry.validateAttributes(normalizedTagName, rawAttrs);
|
|
77
|
+
return {
|
|
78
|
+
type: normalizedTagName,
|
|
79
|
+
content: decodeXmlEntities(content),
|
|
80
|
+
attributes: validationResult.success
|
|
81
|
+
? validationResult.data
|
|
82
|
+
: rawAttrs,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Add text to segments if non-empty
|
|
87
|
+
*/
|
|
88
|
+
function addTextSegment(segments, text) {
|
|
89
|
+
const trimmed = text;
|
|
90
|
+
if (trimmed) {
|
|
91
|
+
segments.push({
|
|
92
|
+
type: "text",
|
|
93
|
+
content: decodeXmlEntities(trimmed),
|
|
94
|
+
attributes: undefined,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Parse complete text into segments
|
|
100
|
+
*/
|
|
101
|
+
function parse(text) {
|
|
102
|
+
const segments = [];
|
|
103
|
+
let remaining = text;
|
|
104
|
+
let textBuffer = "";
|
|
105
|
+
while (remaining.length > 0) {
|
|
106
|
+
// Check for opening tag
|
|
107
|
+
const openMatch = remaining.match(openingTagPattern);
|
|
108
|
+
if (openMatch) {
|
|
109
|
+
const tagIndex = remaining.indexOf(openMatch[0]);
|
|
110
|
+
if (tagIndex > 0) {
|
|
111
|
+
// Add text before the tag to buffer
|
|
112
|
+
textBuffer += remaining.slice(0, tagIndex);
|
|
113
|
+
remaining = remaining.slice(tagIndex);
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
const tagName = openMatch[1].toLowerCase();
|
|
117
|
+
const attrStr = openMatch[2] || "";
|
|
118
|
+
const isSelfClosing = openMatch[3] === "/" || registry.isSelfClosing(tagName);
|
|
119
|
+
if (isSelfClosing) {
|
|
120
|
+
// Flush text buffer
|
|
121
|
+
if (textBuffer) {
|
|
122
|
+
addTextSegment(segments, textBuffer);
|
|
123
|
+
textBuffer = "";
|
|
124
|
+
}
|
|
125
|
+
// Create segment for self-closing tag
|
|
126
|
+
const segment = createSegment(tagName, attrStr, "");
|
|
127
|
+
segments.push(segment);
|
|
128
|
+
remaining = remaining.slice(openMatch[0].length);
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
// Look for closing tag
|
|
132
|
+
const closingTagPattern = new RegExp(`</${escapeRegex(tagName)}>`, "i");
|
|
133
|
+
const closeMatch = remaining.match(closingTagPattern);
|
|
134
|
+
if (closeMatch) {
|
|
135
|
+
const closeIndex = remaining.indexOf(closeMatch[0]);
|
|
136
|
+
// Flush text buffer
|
|
137
|
+
if (textBuffer) {
|
|
138
|
+
addTextSegment(segments, textBuffer);
|
|
139
|
+
textBuffer = "";
|
|
140
|
+
}
|
|
141
|
+
// Extract content between tags
|
|
142
|
+
const contentStart = openMatch[0].length;
|
|
143
|
+
const content = remaining.slice(contentStart, closeIndex);
|
|
144
|
+
// Create segment
|
|
145
|
+
const segment = createSegment(tagName, attrStr, content);
|
|
146
|
+
segments.push(segment);
|
|
147
|
+
// Move past closing tag
|
|
148
|
+
remaining = remaining.slice(closeIndex + closeMatch[0].length);
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
// No closing tag found - treat as malformed, add as text
|
|
152
|
+
textBuffer += openMatch[0];
|
|
153
|
+
remaining = remaining.slice(openMatch[0].length);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
// No more tags, add rest to text buffer
|
|
158
|
+
textBuffer += remaining;
|
|
159
|
+
remaining = "";
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
// Flush remaining text
|
|
163
|
+
if (textBuffer) {
|
|
164
|
+
addTextSegment(segments, textBuffer);
|
|
165
|
+
}
|
|
166
|
+
return segments;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Create initial parser state for streaming
|
|
170
|
+
*/
|
|
171
|
+
function createState() {
|
|
172
|
+
return {
|
|
173
|
+
buffer: "",
|
|
174
|
+
inComponent: false,
|
|
175
|
+
currentTag: null,
|
|
176
|
+
currentAttrs: "",
|
|
177
|
+
tagStartIndex: 0,
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Parse a streaming chunk with state management
|
|
182
|
+
*/
|
|
183
|
+
function parseChunk(chunk, state) {
|
|
184
|
+
const newState = { ...state };
|
|
185
|
+
newState.buffer += chunk;
|
|
186
|
+
const segments = [];
|
|
187
|
+
let textBuffer = "";
|
|
188
|
+
let remaining = newState.buffer;
|
|
189
|
+
let processedUpTo = 0;
|
|
190
|
+
while (remaining.length > 0) {
|
|
191
|
+
if (newState.inComponent && newState.currentTag) {
|
|
192
|
+
// Look for closing tag
|
|
193
|
+
const closingPattern = new RegExp(`</${escapeRegex(newState.currentTag)}>`, "i");
|
|
194
|
+
const closeMatch = remaining.match(closingPattern);
|
|
195
|
+
if (closeMatch) {
|
|
196
|
+
const closeIndex = remaining.indexOf(closeMatch[0]);
|
|
197
|
+
// We have a complete component
|
|
198
|
+
const content = remaining.slice(0, closeIndex);
|
|
199
|
+
const segment = createSegment(newState.currentTag, newState.currentAttrs, content);
|
|
200
|
+
segments.push(segment);
|
|
201
|
+
// Reset state
|
|
202
|
+
remaining = remaining.slice(closeIndex + closeMatch[0].length);
|
|
203
|
+
processedUpTo = newState.buffer.length - remaining.length;
|
|
204
|
+
newState.inComponent = false;
|
|
205
|
+
newState.currentTag = null;
|
|
206
|
+
newState.currentAttrs = "";
|
|
207
|
+
}
|
|
208
|
+
else {
|
|
209
|
+
// Still waiting for closing tag
|
|
210
|
+
break;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
else {
|
|
214
|
+
// Check for opening tag
|
|
215
|
+
const openMatch = remaining.match(openingTagPattern);
|
|
216
|
+
if (openMatch) {
|
|
217
|
+
const tagIndex = remaining.indexOf(openMatch[0]);
|
|
218
|
+
if (tagIndex > 0) {
|
|
219
|
+
// Text before the tag
|
|
220
|
+
textBuffer += remaining.slice(0, tagIndex);
|
|
221
|
+
remaining = remaining.slice(tagIndex);
|
|
222
|
+
continue;
|
|
223
|
+
}
|
|
224
|
+
// Check if it might be an incomplete tag at the end
|
|
225
|
+
// Only buffer if the potential tag is at the very end and looks incomplete
|
|
226
|
+
if (remaining.endsWith("<") || /^<[^>]*$/.test(remaining)) {
|
|
227
|
+
// Potentially incomplete tag, keep buffering
|
|
228
|
+
break;
|
|
229
|
+
}
|
|
230
|
+
const tagName = openMatch[1].toLowerCase();
|
|
231
|
+
const attrStr = openMatch[2] || "";
|
|
232
|
+
const isSelfClosing = openMatch[3] === "/" ||
|
|
233
|
+
registry.isSelfClosing(tagName);
|
|
234
|
+
if (isSelfClosing) {
|
|
235
|
+
// Flush text buffer
|
|
236
|
+
if (textBuffer) {
|
|
237
|
+
addTextSegment(segments, textBuffer);
|
|
238
|
+
textBuffer = "";
|
|
239
|
+
}
|
|
240
|
+
// Create segment for self-closing tag
|
|
241
|
+
const segment = createSegment(tagName, attrStr, "");
|
|
242
|
+
segments.push(segment);
|
|
243
|
+
remaining = remaining.slice(openMatch[0].length);
|
|
244
|
+
processedUpTo = newState.buffer.length - remaining.length;
|
|
245
|
+
continue;
|
|
246
|
+
}
|
|
247
|
+
// Start of a component tag with content
|
|
248
|
+
if (textBuffer) {
|
|
249
|
+
addTextSegment(segments, textBuffer);
|
|
250
|
+
textBuffer = "";
|
|
251
|
+
}
|
|
252
|
+
newState.inComponent = true;
|
|
253
|
+
newState.currentTag = tagName;
|
|
254
|
+
newState.currentAttrs = attrStr;
|
|
255
|
+
newState.tagStartIndex = processedUpTo;
|
|
256
|
+
remaining = remaining.slice(openMatch[0].length);
|
|
257
|
+
processedUpTo = newState.buffer.length - remaining.length;
|
|
258
|
+
}
|
|
259
|
+
else {
|
|
260
|
+
// No tag found, check for potential incomplete tag at end
|
|
261
|
+
const potentialTagStart = remaining.lastIndexOf("<");
|
|
262
|
+
if (potentialTagStart !== -1 &&
|
|
263
|
+
potentialTagStart > remaining.length - 20) {
|
|
264
|
+
// Might be start of a tag, buffer it
|
|
265
|
+
textBuffer += remaining.slice(0, potentialTagStart);
|
|
266
|
+
remaining = remaining.slice(potentialTagStart);
|
|
267
|
+
break;
|
|
268
|
+
}
|
|
269
|
+
// No tags, all text
|
|
270
|
+
textBuffer += remaining;
|
|
271
|
+
remaining = "";
|
|
272
|
+
processedUpTo = newState.buffer.length;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
// Add remaining text to complete segments if not buffering
|
|
277
|
+
if (!newState.inComponent && textBuffer) {
|
|
278
|
+
addTextSegment(segments, textBuffer);
|
|
279
|
+
textBuffer = "";
|
|
280
|
+
}
|
|
281
|
+
// Update buffer to only contain unprocessed content
|
|
282
|
+
newState.buffer = remaining + textBuffer;
|
|
283
|
+
return {
|
|
284
|
+
segments,
|
|
285
|
+
state: newState,
|
|
286
|
+
isBuffering: newState.inComponent || newState.buffer.length > 0,
|
|
287
|
+
bufferingTag: newState.inComponent
|
|
288
|
+
? newState.currentTag
|
|
289
|
+
: null,
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Finalize parsing, returning any remaining buffered content as text
|
|
294
|
+
*/
|
|
295
|
+
function finalize(state) {
|
|
296
|
+
const segments = [];
|
|
297
|
+
if (state.buffer) {
|
|
298
|
+
// Return buffered content as raw text (malformed component fallback)
|
|
299
|
+
segments.push({
|
|
300
|
+
type: "text",
|
|
301
|
+
content: decodeXmlEntities(state.buffer),
|
|
302
|
+
attributes: undefined,
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
return segments;
|
|
306
|
+
}
|
|
307
|
+
return {
|
|
308
|
+
parse,
|
|
309
|
+
createState,
|
|
310
|
+
parseChunk,
|
|
311
|
+
finalize,
|
|
312
|
+
registry,
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Escape special regex characters in a string
|
|
317
|
+
*/
|
|
318
|
+
function escapeRegex(str) {
|
|
319
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
320
|
+
}
|
|
321
|
+
//# sourceMappingURL=parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parser.js","sourceRoot":"","sources":["../src/parser.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ErrorBoundary Component for React
|
|
3
|
+
*
|
|
4
|
+
* Catches render errors in segment components and displays a fallback UI.
|
|
5
|
+
* Prevents a single segment error from crashing the entire content area.
|
|
6
|
+
*/
|
|
7
|
+
import { Component, type ReactNode, type ErrorInfo } from "react";
|
|
8
|
+
/**
|
|
9
|
+
* Props for the ErrorBoundary component
|
|
10
|
+
*/
|
|
11
|
+
export interface ErrorBoundaryProps {
|
|
12
|
+
/** The child components to render */
|
|
13
|
+
children: ReactNode;
|
|
14
|
+
/** The segment type being rendered (for error messages) */
|
|
15
|
+
segmentType: string;
|
|
16
|
+
/** Optional custom fallback renderer */
|
|
17
|
+
fallback?: (error: Error, segmentType: string) => ReactNode;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* State for the ErrorBoundary component
|
|
21
|
+
*/
|
|
22
|
+
interface ErrorBoundaryState {
|
|
23
|
+
hasError: boolean;
|
|
24
|
+
error: Error | null;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Error boundary component that catches render errors in child components.
|
|
28
|
+
*
|
|
29
|
+
* In development mode, displays a visible error message with segment type and error details.
|
|
30
|
+
* In production mode, renders a minimal hidden fallback to avoid disrupting the UI.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```tsx
|
|
34
|
+
* <ErrorBoundary segmentType="chart">
|
|
35
|
+
* <ChartComponent data={data} />
|
|
36
|
+
* </ErrorBoundary>
|
|
37
|
+
* ```
|
|
38
|
+
*
|
|
39
|
+
* @example With custom fallback
|
|
40
|
+
* ```tsx
|
|
41
|
+
* <ErrorBoundary
|
|
42
|
+
* segmentType="table"
|
|
43
|
+
* fallback={(error, type) => <div>Failed to render {type}: {error.message}</div>}
|
|
44
|
+
* >
|
|
45
|
+
* <TableComponent data={data} />
|
|
46
|
+
* </ErrorBoundary>
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
export declare class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
|
|
50
|
+
constructor(props: ErrorBoundaryProps);
|
|
51
|
+
static getDerivedStateFromError(error: Error): ErrorBoundaryState;
|
|
52
|
+
componentDidCatch(error: Error, errorInfo: ErrorInfo): void;
|
|
53
|
+
render(): ReactNode;
|
|
54
|
+
}
|
|
55
|
+
export {};
|
|
56
|
+
//# sourceMappingURL=ErrorBoundary.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ErrorBoundary.d.ts","sourceRoot":"","sources":["../../src/react/ErrorBoundary.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAc,EAAE,SAAS,EAAE,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAEzE;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,qCAAqC;IACrC,QAAQ,EAAE,SAAS,CAAC;IACpB,2DAA2D;IAC3D,WAAW,EAAE,MAAM,CAAC;IACpB,wCAAwC;IACxC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,KAAK,SAAS,CAAC;CAC7D;AAED;;GAEG;AACH,UAAU,kBAAkB;IAC1B,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;CACrB;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBAAa,aAAc,SAAQ,SAAS,CAC1C,kBAAkB,EAClB,kBAAkB,CACnB;gBACa,KAAK,EAAE,kBAAkB;IAKrC,MAAM,CAAC,wBAAwB,CAAC,KAAK,EAAE,KAAK,GAAG,kBAAkB;IAIjE,iBAAiB,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,GAAG,IAAI;IAS3D,MAAM,IAAI,SAAS;CAiCpB"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* ErrorBoundary Component for React
|
|
4
|
+
*
|
|
5
|
+
* Catches render errors in segment components and displays a fallback UI.
|
|
6
|
+
* Prevents a single segment error from crashing the entire content area.
|
|
7
|
+
*/
|
|
8
|
+
import { Component } from "react";
|
|
9
|
+
/**
|
|
10
|
+
* Error boundary component that catches render errors in child components.
|
|
11
|
+
*
|
|
12
|
+
* In development mode, displays a visible error message with segment type and error details.
|
|
13
|
+
* In production mode, renders a minimal hidden fallback to avoid disrupting the UI.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```tsx
|
|
17
|
+
* <ErrorBoundary segmentType="chart">
|
|
18
|
+
* <ChartComponent data={data} />
|
|
19
|
+
* </ErrorBoundary>
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* @example With custom fallback
|
|
23
|
+
* ```tsx
|
|
24
|
+
* <ErrorBoundary
|
|
25
|
+
* segmentType="table"
|
|
26
|
+
* fallback={(error, type) => <div>Failed to render {type}: {error.message}</div>}
|
|
27
|
+
* >
|
|
28
|
+
* <TableComponent data={data} />
|
|
29
|
+
* </ErrorBoundary>
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export class ErrorBoundary extends Component {
|
|
33
|
+
constructor(props) {
|
|
34
|
+
super(props);
|
|
35
|
+
this.state = { hasError: false, error: null };
|
|
36
|
+
}
|
|
37
|
+
static getDerivedStateFromError(error) {
|
|
38
|
+
return { hasError: true, error };
|
|
39
|
+
}
|
|
40
|
+
componentDidCatch(error, errorInfo) {
|
|
41
|
+
// Log the error for debugging
|
|
42
|
+
console.error(`XmlRender ErrorBoundary: Failed to render segment type "${this.props.segmentType}"`, error, errorInfo.componentStack);
|
|
43
|
+
}
|
|
44
|
+
render() {
|
|
45
|
+
if (this.state.hasError && this.state.error) {
|
|
46
|
+
// Use custom fallback if provided
|
|
47
|
+
if (this.props.fallback) {
|
|
48
|
+
return this.props.fallback(this.state.error, this.props.segmentType);
|
|
49
|
+
}
|
|
50
|
+
// Development: show detailed error info
|
|
51
|
+
if (process.env.NODE_ENV === "development") {
|
|
52
|
+
return (_jsxs("span", { style: {
|
|
53
|
+
display: "inline-block",
|
|
54
|
+
padding: "4px 8px",
|
|
55
|
+
backgroundColor: "#fee2e2",
|
|
56
|
+
border: "1px solid #ef4444",
|
|
57
|
+
borderRadius: "4px",
|
|
58
|
+
color: "#991b1b",
|
|
59
|
+
fontSize: "12px",
|
|
60
|
+
fontFamily: "monospace",
|
|
61
|
+
}, children: ["Error in [", this.props.segmentType, "]: ", this.state.error.message] }));
|
|
62
|
+
}
|
|
63
|
+
// Production: minimal hidden fallback
|
|
64
|
+
return _jsx("span", { style: { display: "none" } });
|
|
65
|
+
}
|
|
66
|
+
return this.props.children;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=ErrorBoundary.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ErrorBoundary.js","sourceRoot":"","sources":["../../src/react/ErrorBoundary.tsx"],"names":[],"mappings":";AAAA;;;;;GAKG;AACH,OAAc,EAAE,SAAS,EAAkC,MAAM,OAAO,CAAC;AAsBzE;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,OAAO,aAAc,SAAQ,SAGlC;IACC,YAAY,KAAyB;QACnC,KAAK,CAAC,KAAK,CAAC,CAAC;QACb,IAAI,CAAC,KAAK,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IAChD,CAAC;IAED,MAAM,CAAC,wBAAwB,CAAC,KAAY;QAC1C,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;IACnC,CAAC;IAED,iBAAiB,CAAC,KAAY,EAAE,SAAoB;QAClD,8BAA8B;QAC9B,OAAO,CAAC,KAAK,CACX,2DAA2D,IAAI,CAAC,KAAK,CAAC,WAAW,GAAG,EACpF,KAAK,EACL,SAAS,CAAC,cAAc,CACzB,CAAC;IACJ,CAAC;IAED,MAAM;QACJ,IAAI,IAAI,CAAC,KAAK,CAAC,QAAQ,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;YAC5C,kCAAkC;YAClC,IAAI,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;gBACxB,OAAO,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;YACvE,CAAC;YAED,wCAAwC;YACxC,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,aAAa,EAAE,CAAC;gBAC3C,OAAO,CACL,gBACE,KAAK,EAAE;wBACL,OAAO,EAAE,cAAc;wBACvB,OAAO,EAAE,SAAS;wBAClB,eAAe,EAAE,SAAS;wBAC1B,MAAM,EAAE,mBAAmB;wBAC3B,YAAY,EAAE,KAAK;wBACnB,KAAK,EAAE,SAAS;wBAChB,QAAQ,EAAE,MAAM;wBAChB,UAAU,EAAE,WAAW;qBACxB,2BAEU,IAAI,CAAC,KAAK,CAAC,WAAW,SAAK,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,IACzD,CACR,CAAC;YACJ,CAAC;YAED,sCAAsC;YACtC,OAAO,eAAM,KAAK,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,GAAI,CAAC;QAC9C,CAAC;QAED,OAAO,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC;IAC7B,CAAC;CACF"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* XmlRender Component for React
|
|
3
|
+
*
|
|
4
|
+
* Renders an array of parsed segments using the component catalog.
|
|
5
|
+
* Each segment is rendered by its corresponding component from the catalog.
|
|
6
|
+
*/
|
|
7
|
+
import { type ReactElement, type ReactNode } from "react";
|
|
8
|
+
import type { TagDefinitions } from "../registry";
|
|
9
|
+
import type { Segments, ParsedSegment } from "../parser";
|
|
10
|
+
import type { Catalog } from "./catalog";
|
|
11
|
+
/**
|
|
12
|
+
* Props for the XmlRender component
|
|
13
|
+
*/
|
|
14
|
+
export interface XmlRenderProps<TDefs extends TagDefinitions> {
|
|
15
|
+
/** Array of parsed segments to render */
|
|
16
|
+
segments: Segments<TDefs>;
|
|
17
|
+
/** Optional fallback renderer for unknown segment types */
|
|
18
|
+
fallback?: (segment: ParsedSegment<TDefs>, index: number) => ReactNode;
|
|
19
|
+
/** Optional catalog override (uses context catalog if not provided) */
|
|
20
|
+
catalog?: Catalog<TDefs>;
|
|
21
|
+
/** Optional custom error fallback renderer */
|
|
22
|
+
errorFallback?: (error: Error, segmentType: string) => ReactNode;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Renders an array of parsed XML segments using the component catalog.
|
|
26
|
+
*
|
|
27
|
+
* Each segment is matched to its corresponding renderer component from the catalog.
|
|
28
|
+
* Text segments use the catalog's text renderer or a default span renderer.
|
|
29
|
+
* Unknown segment types use the fallback prop or render content as plain text.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```tsx
|
|
33
|
+
* import { XmlRender, XmlRenderProvider } from '@aura/xml-render/react';
|
|
34
|
+
* import { createParser } from '@aura/xml-render';
|
|
35
|
+
* import { registry, catalog } from './xml-config';
|
|
36
|
+
*
|
|
37
|
+
* function RichContent({ text }: { text: string }) {
|
|
38
|
+
* const parser = createParser(registry);
|
|
39
|
+
* const segments = parser.parse(text);
|
|
40
|
+
*
|
|
41
|
+
* return (
|
|
42
|
+
* <XmlRenderProvider catalog={catalog}>
|
|
43
|
+
* <XmlRender segments={segments} />
|
|
44
|
+
* </XmlRenderProvider>
|
|
45
|
+
* );
|
|
46
|
+
* }
|
|
47
|
+
* ```
|
|
48
|
+
*
|
|
49
|
+
* @example With custom fallback
|
|
50
|
+
* ```tsx
|
|
51
|
+
* <XmlRender
|
|
52
|
+
* segments={segments}
|
|
53
|
+
* fallback={(segment, index) => (
|
|
54
|
+
* <div className="unknown-segment">
|
|
55
|
+
* Unknown: {segment.type} - {segment.content}
|
|
56
|
+
* </div>
|
|
57
|
+
* )}
|
|
58
|
+
* />
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
export declare function XmlRender<TDefs extends TagDefinitions>({ segments, fallback, catalog: catalogProp, errorFallback, }: XmlRenderProps<TDefs>): ReactElement;
|
|
62
|
+
//# sourceMappingURL=XmlRender.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"XmlRender.d.ts","sourceRoot":"","sources":["../../src/react/XmlRender.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAc,EAAE,KAAK,YAAY,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AACjE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAEzD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGzC;;GAEG;AACH,MAAM,WAAW,cAAc,CAAC,KAAK,SAAS,cAAc;IAC1D,yCAAyC;IACzC,QAAQ,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC1B,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,aAAa,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,SAAS,CAAC;IACvE,uEAAuE;IACvE,OAAO,CAAC,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IACzB,8CAA8C;IAC9C,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,KAAK,SAAS,CAAC;CAClE;AAqED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,wBAAgB,SAAS,CAAC,KAAK,SAAS,cAAc,EAAE,EACtD,QAAQ,EACR,QAAQ,EACR,OAAO,EAAE,WAAW,EACpB,aAAa,GACd,EAAE,cAAc,CAAC,KAAK,CAAC,GAAG,YAAY,CAwBtC"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useXmlRenderContext } from "./context";
|
|
3
|
+
import { ErrorBoundary } from "./ErrorBoundary";
|
|
4
|
+
/**
|
|
5
|
+
* Default text renderer - renders plain text in a span
|
|
6
|
+
*/
|
|
7
|
+
function DefaultTextRenderer({ segment, }) {
|
|
8
|
+
return _jsx("span", { children: segment.content });
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Default fallback renderer for unknown segment types
|
|
12
|
+
*/
|
|
13
|
+
function DefaultFallback({ segment, }) {
|
|
14
|
+
// In development, show a warning; in production, render content as text
|
|
15
|
+
if (process.env.NODE_ENV === "development") {
|
|
16
|
+
console.warn(`XmlRender: No renderer found for segment type "${String(segment.type)}"`);
|
|
17
|
+
}
|
|
18
|
+
return _jsx("span", { children: segment.content });
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Render a single segment using the catalog (without key or ErrorBoundary wrapper)
|
|
22
|
+
*/
|
|
23
|
+
function renderSegmentContent(segment, index, catalog, fallback) {
|
|
24
|
+
const segmentType = segment.type;
|
|
25
|
+
// Handle text segments
|
|
26
|
+
if (segmentType === "text") {
|
|
27
|
+
const TextRenderer = catalog.getTextRenderer();
|
|
28
|
+
if (TextRenderer) {
|
|
29
|
+
return (_jsx(TextRenderer, { segment: segment, index: index }));
|
|
30
|
+
}
|
|
31
|
+
return _jsx(DefaultTextRenderer, { segment: segment });
|
|
32
|
+
}
|
|
33
|
+
// Handle registered tag segments
|
|
34
|
+
const Renderer = catalog.getRenderer(segmentType);
|
|
35
|
+
if (Renderer) {
|
|
36
|
+
return _jsx(Renderer, { segment: segment, index: index });
|
|
37
|
+
}
|
|
38
|
+
// Use fallback for unknown segment types
|
|
39
|
+
if (fallback) {
|
|
40
|
+
return fallback(segment, index);
|
|
41
|
+
}
|
|
42
|
+
return _jsx(DefaultFallback, { segment: segment });
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Renders an array of parsed XML segments using the component catalog.
|
|
46
|
+
*
|
|
47
|
+
* Each segment is matched to its corresponding renderer component from the catalog.
|
|
48
|
+
* Text segments use the catalog's text renderer or a default span renderer.
|
|
49
|
+
* Unknown segment types use the fallback prop or render content as plain text.
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```tsx
|
|
53
|
+
* import { XmlRender, XmlRenderProvider } from '@aura/xml-render/react';
|
|
54
|
+
* import { createParser } from '@aura/xml-render';
|
|
55
|
+
* import { registry, catalog } from './xml-config';
|
|
56
|
+
*
|
|
57
|
+
* function RichContent({ text }: { text: string }) {
|
|
58
|
+
* const parser = createParser(registry);
|
|
59
|
+
* const segments = parser.parse(text);
|
|
60
|
+
*
|
|
61
|
+
* return (
|
|
62
|
+
* <XmlRenderProvider catalog={catalog}>
|
|
63
|
+
* <XmlRender segments={segments} />
|
|
64
|
+
* </XmlRenderProvider>
|
|
65
|
+
* );
|
|
66
|
+
* }
|
|
67
|
+
* ```
|
|
68
|
+
*
|
|
69
|
+
* @example With custom fallback
|
|
70
|
+
* ```tsx
|
|
71
|
+
* <XmlRender
|
|
72
|
+
* segments={segments}
|
|
73
|
+
* fallback={(segment, index) => (
|
|
74
|
+
* <div className="unknown-segment">
|
|
75
|
+
* Unknown: {segment.type} - {segment.content}
|
|
76
|
+
* </div>
|
|
77
|
+
* )}
|
|
78
|
+
* />
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
export function XmlRender({ segments, fallback, catalog: catalogProp, errorFallback, }) {
|
|
82
|
+
// Use provided catalog or get from context
|
|
83
|
+
const contextValue = catalogProp ? null : useXmlRenderContext();
|
|
84
|
+
const catalog = catalogProp ?? contextValue?.catalog;
|
|
85
|
+
if (!catalog) {
|
|
86
|
+
throw new Error("XmlRender requires a catalog prop or must be used within XmlRenderProvider");
|
|
87
|
+
}
|
|
88
|
+
return (_jsx(_Fragment, { children: segments.map((segment, index) => (_jsx(ErrorBoundary, { segmentType: String(segment.type), fallback: errorFallback, children: renderSegmentContent(segment, index, catalog, fallback) }, index))) }));
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=XmlRender.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"XmlRender.js","sourceRoot":"","sources":["../../src/react/XmlRender.tsx"],"names":[],"mappings":";AASA,OAAO,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAEhD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAgBhD;;GAEG;AACH,SAAS,mBAAmB,CAA+B,EACzD,OAAO,GAGR;IACC,OAAO,yBAAO,OAAO,CAAC,OAAO,GAAQ,CAAC;AACxC,CAAC;AAED;;GAEG;AACH,SAAS,eAAe,CAA+B,EACrD,OAAO,GAGR;IACC,wEAAwE;IACxE,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,aAAa,EAAE,CAAC;QAC3C,OAAO,CAAC,IAAI,CACV,kDAAkD,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAC1E,CAAC;IACJ,CAAC;IACD,OAAO,yBAAO,OAAO,CAAC,OAAO,GAAQ,CAAC;AACxC,CAAC;AAED;;GAEG;AACH,SAAS,oBAAoB,CAC3B,OAA6B,EAC7B,KAAa,EACb,OAAuB,EACvB,QAAsE;IAEtE,MAAM,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAEjC,uBAAuB;IACvB,IAAI,WAAW,KAAK,MAAM,EAAE,CAAC;QAC3B,MAAM,YAAY,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;QAC/C,IAAI,YAAY,EAAE,CAAC;YACjB,OAAO,CACL,KAAC,YAAY,IACX,OAAO,EAAE,OAAuC,EAChD,KAAK,EAAE,KAAK,GACZ,CACH,CAAC;QACJ,CAAC;QACD,OAAO,KAAC,mBAAmB,IAAC,OAAO,EAAE,OAAuC,GAAI,CAAC;IACnF,CAAC;IAED,iCAAiC;IACjC,MAAM,QAAQ,GAAG,OAAO,CAAC,WAAW,CAAC,WAA0B,CAAC,CAAC;IACjE,IAAI,QAAQ,EAAE,CAAC;QACb,OAAO,KAAC,QAAQ,IAAC,OAAO,EAAE,OAA4C,EAAE,KAAK,EAAE,KAAK,GAAI,CAAC;IAC3F,CAAC;IAED,yCAAyC;IACzC,IAAI,QAAQ,EAAE,CAAC;QACb,OAAO,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IAClC,CAAC;IAED,OAAO,KAAC,eAAe,IAAC,OAAO,EAAE,OAAO,GAAI,CAAC;AAC/C,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,MAAM,UAAU,SAAS,CAA+B,EACtD,QAAQ,EACR,QAAQ,EACR,OAAO,EAAE,WAAW,EACpB,aAAa,GACS;IACtB,2CAA2C;IAC3C,MAAM,YAAY,GAAG,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,mBAAmB,EAAS,CAAC;IACvE,MAAM,OAAO,GAAG,WAAW,IAAI,YAAY,EAAE,OAAO,CAAC;IAErD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CACb,4EAA4E,CAC7E,CAAC;IACJ,CAAC;IAED,OAAO,CACL,4BACG,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,CAAC,CAChC,KAAC,aAAa,IAEZ,WAAW,EAAE,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EACjC,QAAQ,EAAE,aAAa,YAEtB,oBAAoB,CAAC,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,CAAC,IAJnD,KAAK,CAKI,CACjB,CAAC,GACD,CACJ,CAAC;AACJ,CAAC"}
|