wasl-flow 1.0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Ahmad Igbariya
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,128 @@
1
+ # wasl-flow (core)
2
+
3
+ The core package of Wasl Flow. It provides the abstract renderer, shared types, and base content type definition used by all renderers.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install wasl-flow
9
+ # or
10
+ pnpm add wasl-flow
11
+ ```
12
+
13
+ ## What This Package Provides
14
+
15
+ - `AbstractRenderer`: the framework-agnostic renderer and type dispatcher.
16
+ - `AbstractContentTypeDefinition`: a reusable bundle of `type`, `parse`, and `factory`.
17
+ - Core types: `ContentModel`, `ContentModelParser`, `ComponentFactory`, `RenderError`, and `RendererConfiguration`.
18
+
19
+ ## Quick Start
20
+
21
+ Use the core directly when you are building your own renderer or rendering layer.
22
+
23
+ ```ts
24
+ import {
25
+ AbstractContentTypeDefinition,
26
+ AbstractRenderer,
27
+ type ContentModelParser,
28
+ type ComponentFactory,
29
+ type RenderError,
30
+ } from 'wasl-flow';
31
+
32
+ type HeroModel = {
33
+ type: 'hero';
34
+ title: string;
35
+ subtitle?: string;
36
+ };
37
+
38
+ type ButtonModel = {
39
+ type: 'button';
40
+ label: string;
41
+ };
42
+
43
+ class HeroDefinition extends AbstractContentTypeDefinition<HeroModel> {
44
+ constructor() {
45
+ super('hero');
46
+ }
47
+
48
+ parse: ContentModelParser<HeroModel> = model => ({ data: model as HeroModel });
49
+
50
+ factory: ComponentFactory<HeroModel> = ({ model, renderContent }) => {
51
+ const cta = renderContent({ type: 'button', label: 'Get started' }) as string;
52
+ return `<section class="hero"><h1>${model.title}</h1><p>${model.subtitle ?? ''}</p>${cta}</section>`;
53
+ };
54
+ }
55
+
56
+ class ButtonDefinition extends AbstractContentTypeDefinition<ButtonModel> {
57
+ constructor() {
58
+ super('button');
59
+ }
60
+
61
+ parse: ContentModelParser<ButtonModel> = model => ({ data: model as ButtonModel });
62
+
63
+ factory: ComponentFactory<ButtonModel> = ({ model }) => {
64
+ return `<button class="btn">${model.label}</button>`;
65
+ };
66
+ }
67
+
68
+ class HtmlStringRenderer extends AbstractRenderer {
69
+ protected aggregateArrayOutputs(outputs: unknown[]): string {
70
+ return outputs.filter(Boolean).join('');
71
+ }
72
+
73
+ protected renderValidationError(error: RenderError): string {
74
+ return `<pre class="error">${error.type}: ${error.message}</pre>`;
75
+ }
76
+ }
77
+
78
+ const renderer = new HtmlStringRenderer({ showValidationErrors: true });
79
+ renderer.register(new HeroDefinition());
80
+ renderer.register(new ButtonDefinition());
81
+
82
+ const html = renderer.render({
83
+ type: 'hero',
84
+ title: 'Welcome',
85
+ subtitle: 'Build once, render anywhere.',
86
+ });
87
+ ```
88
+
89
+ ## How Rendering Works
90
+
91
+ - The renderer uses `typeField` (default `type`) to find the matching registration.
92
+ - `parse` validates and normalizes the model. Return `{ data, error }` to signal validation failure.
93
+ - `factory` receives the validated `model` and a `renderContent` helper for nested content.
94
+ - Errors are either rendered (when `showValidationErrors` is true) or replaced with `nullValue`.
95
+
96
+ ## Configuration
97
+
98
+ You can configure rendering and safety behavior through `RendererConfiguration`:
99
+
100
+ - `typeField` (default `type`): field name used to identify a model type.
101
+ - `nullValue` (default `null`): value returned when rendering fails or model is null/undefined.
102
+ - `showValidationErrors` (default `false`): render error details instead of `nullValue`.
103
+ - `allowDuplicateRegistrations` (default `false`): allow overrides of existing registrations.
104
+ - `maxRenderDepth` (default `50`): maximum recursive render depth.
105
+ - `maxRenderNodes` (default `1000`): maximum number of nodes per render traversal.
106
+
107
+ ## Errors And Safety Limits
108
+
109
+ Possible render error types are:
110
+
111
+ - `MISSING_TYPE_FIELD`
112
+ - `UNREGISTERED_TYPE`
113
+ - `VALIDATION_ERROR`
114
+ - `FACTORY_ERROR`
115
+ - `RENDER_LIMIT_EXCEEDED`
116
+
117
+ Safety limits guard against infinite recursion and large trees. Cycles are detected by object reference.
118
+
119
+ ## When To Use The Core Directly
120
+
121
+ Use `wasl-flow` directly when you need to build a new framework renderer or you want a custom renderer. Otherwise, use a renderer from `@wasl-flow/*`.
122
+
123
+ ## Related Packages
124
+
125
+ - `@wasl-flow/react`
126
+ - `@wasl-flow/vue`
127
+ - `@wasl-flow/vanilla`
128
+ - `@wasl-flow/jquery`
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ 'use strict';var u=(o=>(o.MISSING_TYPE_FIELD="MISSING_TYPE_FIELD",o.UNREGISTERED_TYPE="UNREGISTERED_TYPE",o.VALIDATION_ERROR="VALIDATION_ERROR",o.FACTORY_ERROR="FACTORY_ERROR",o.RENDER_LIMIT_EXCEEDED="RENDER_LIMIT_EXCEEDED",o))(u||{});var c=50,E=1e3,d=class extends Error{constructor(r){let n;r==="MAX_DEPTH"?n="Maximum render depth exceeded":r==="MAX_NODES"?n="Maximum number of nodes exceeded":n="Circular content reference detected";super(n);this.reason=r;this.name="RenderTraversalError";}},a=class{constructor(e={}){this.entries=new Map;this.config={typeField:"type",nullValue:null,showValidationErrors:false,allowDuplicateRegistrations:false,maxRenderDepth:c,maxRenderNodes:E,...e},this.sanitizeLimitConfiguration();}register(e){let{type:r,parse:n,factory:t}=e;if(this.isRegistered(r)){let o=`${r} is already registered, overriding existing entry with a new one.`;if(!this.config.allowDuplicateRegistrations)throw new Error(`${o} Enable allowDuplicateRegistrations in the renderer configuration to permit overrides.`);console.warn(o);}this.entries.set(r,{parse:n,factory:t});}unregister(e){return this.entries.delete(e)}isRegistered(e){return this.entries.has(e)}getRegisteredTypes(){return Array.from(this.entries.keys())}render(e){return this.renderModel(e,this.createRenderContext())}renderArray(e){return this.renderModelArray(e,this.createRenderContext())}getConfiguration(){return {...this.config}}updateConfiguration(e){this.config={...this.config,...e},this.sanitizeLimitConfiguration();}renderModel(e,r){if(e==null)return this.config.nullValue;let n=false;try{this.enterRenderScope(e,r),n=!0;let t=this.extractType(e);if(!t)return this.handleMissingTypeError(e);let o=this.entries.get(t);if(!o)return this.handleUnregisteredTypeError(t,e);let s=o.parse(e);return s.error?this.handleValidationError(t,e,s.error):this.executeFactory(o,s.data,e,t,r)}catch(t){return this.handleRenderError(t,e)}finally{n&&this.exitRenderScope(e,r);}}handleMissingTypeError(e){let r={type:"MISSING_TYPE_FIELD",message:`Model is missing required type field: ${this.config.typeField}`,model:e,typeField:this.config.typeField};return this.renderErrorOrHide(r)}handleUnregisteredTypeError(e,r){let n={type:"UNREGISTERED_TYPE",message:`No registration found for type: ${e}`,model:r,typeField:this.config.typeField};return this.renderErrorOrHide(n)}handleValidationError(e,r,n){let t={type:"VALIDATION_ERROR",message:`Validation failed for type: ${e}`,model:r,typeField:this.config.typeField,validationError:n};return this.renderErrorOrHide(t)}executeFactory(e,r,n,t,o){let s=i=>Array.isArray(i)?this.renderModelArray(i,o):this.renderModel(i,o);try{return e.factory({model:r,renderContent:s})}catch(i){let R={type:"FACTORY_ERROR",message:`Factory error for type: ${t}`,model:n,typeField:this.config.typeField,originalError:i instanceof Error?i:new Error(String(i))};return this.renderErrorOrHide(R)}}handleRenderError(e,r){if(e instanceof d){let t=this.buildTraversalRenderError(e.reason,r);return this.renderErrorOrHide(t)}let n={type:"FACTORY_ERROR",message:"Unexpected error during rendering",model:r,originalError:e instanceof Error?e:new Error(String(e))};return this.renderErrorOrHide(n)}renderErrorOrHide(e){return this.config.showValidationErrors?this.renderValidationError(e):this.config.nullValue}renderModelArray(e,r){let n=[];for(let t of e)n.push(this.renderModel(t,r));return this.aggregateArrayOutputs(n)}createRenderContext(){return {depth:0,nodeCount:0,ancestors:new Set}}enterRenderScope(e,r){if(r.depth>=this.config.maxRenderDepth)throw new d("MAX_DEPTH");if(r.nodeCount>=this.config.maxRenderNodes)throw new d("MAX_NODES");if(this.isObjectModel(e)){if(r.ancestors.has(e))throw new d("CYCLE");r.ancestors.add(e);}r.depth+=1,r.nodeCount+=1;}exitRenderScope(e,r){r.depth>0&&(r.depth-=1),this.isObjectModel(e)&&r.ancestors.delete(e);}isObjectModel(e){return typeof e=="object"&&e!==null}buildTraversalRenderError(e,r){let n={MAX_DEPTH:"depth",MAX_NODES:"nodes",CYCLE:"cycle"},t={MAX_DEPTH:"Render depth limit exceeded",MAX_NODES:"Render node limit exceeded",CYCLE:"Circular reference detected during rendering"};return {type:"RENDER_LIMIT_EXCEEDED",message:t[e],model:r,typeField:this.config.typeField,limitType:n[e]}}sanitizeLimitConfiguration(){this.config.maxRenderDepth=this.normalizeLimit(this.config.maxRenderDepth,c),this.config.maxRenderNodes=this.normalizeLimit(this.config.maxRenderNodes,E);}normalizeLimit(e,r){return !Number.isFinite(e)||e<=0?r:Math.floor(e)}extractType(e){let r=e[this.config.typeField];return typeof r=="string"?r:null}};var l=class{constructor(e){this.type=e;}};exports.AbstractContentTypeDefinition=l;exports.AbstractRenderer=a;exports.RenderErrorType=u;//# sourceMappingURL=index.js.map
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/types.ts","../src/renderer/AbstractRenderer.ts","../src/renderer/AbstractContentTypeDefinition.ts"],"names":["RenderErrorType","DEFAULT_MAX_RENDER_DEPTH","DEFAULT_MAX_RENDER_NODES","RenderTraversalError","reason","message","AbstractRenderer","config","contentDefinition","type","parse","factory","warning","model","models","newConfig","context","scopeEntered","entry","validationResult","error","validationError","data","renderContent","content","factoryError","traversalRenderError","renderError","outputs","limitMap","messageMap","value","fallback","AbstractContentTypeDefinition"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * @fileoverview Core type definitions for the wasl-flow package.\n * Defines interfaces and types for content models, renderer configuration, and rendering.\n */\n\n/**\n * A content model represents a unit of content to render.\n * Must contain a type-identifying field (configurable via typeField).\n */\nexport interface ContentModel {\n [key: string]: unknown;\n}\n\n/**\n * Configuration options for the renderer.\n */\nexport interface RendererConfiguration {\n /** Field name used to identify the model type (default: 'type') */\n typeField?: string;\n /** Value returned when rendering fails or model is null/undefined */\n nullValue?: unknown;\n /** Show detailed validation errors in development */\n showValidationErrors?: boolean;\n /** Explicitly allow duplicate registrations to overwrite existing entries */\n allowDuplicateRegistrations?: boolean;\n /** Maximum allowed depth when recursively rendering nested models */\n maxRenderDepth?: number;\n /** Maximum number of nodes allowed to be processed in a single render */\n maxRenderNodes?: number;\n}\n\n/**\n * Renderer entry that pairs a parser with a factory for a specific model type.\n */\nexport interface RendererEntry<TModel extends ContentModel = ContentModel> {\n /** Parse function that validates and transforms the model */\n parse: ContentModelParser<TModel>;\n /** Factory function that creates framework-specific output */\n factory: ComponentFactory<TModel>;\n}\n\n/**\n * Props passed to component factories.\n */\nexport interface ComponentProps<TModel extends ContentModel = ContentModel> {\n /** The validated model data */\n model: TModel;\n /** Function to render nested content models */\n renderContent: (content: ContentModel | ContentModel[]) => unknown;\n}\n\n/**\n * Function that parses and validates a content model.\n * @param model - Raw content model to parse\n * @returns Parsed data or validation error\n */\nexport type ContentModelParser<TModel extends ContentModel = ContentModel> = (\n model: ContentModel\n) => { data: TModel; error?: Error };\n\n/**\n * Factory function that produces framework-specific output from validated model data.\n * @param props - Component props including validated model and render function\n * @returns Framework-specific rendered output\n */\nexport type ComponentFactory<TModel extends ContentModel = ContentModel> = (\n props: ComponentProps<TModel>\n) => unknown;\n\n/**\n * Basic renderer interface for framework-specific implementations.\n */\nexport interface Renderer {\n /** Render a single content model */\n render(model: ContentModel): unknown;\n /** Render an array of content models */\n renderArray(models: ContentModel[]): unknown;\n}\n\n/**\n * Error types that can occur during rendering.\n */\nexport enum RenderErrorType {\n MISSING_TYPE_FIELD = 'MISSING_TYPE_FIELD',\n UNREGISTERED_TYPE = 'UNREGISTERED_TYPE',\n VALIDATION_ERROR = 'VALIDATION_ERROR',\n FACTORY_ERROR = 'FACTORY_ERROR',\n RENDER_LIMIT_EXCEEDED = 'RENDER_LIMIT_EXCEEDED',\n}\n\n/**\n * Reasons that a render limit error can occur.\n */\nexport type RenderLimitType = 'depth' | 'nodes' | 'cycle';\n\n/**\n * Detailed error information for debugging failed renders.\n */\nexport interface RenderError {\n /** Type of error that occurred */\n type: RenderErrorType;\n /** Human-readable error message */\n message: string;\n /** The model that failed to render */\n model?: ContentModel;\n /** The type field name that was expected */\n typeField?: string;\n /** Original validation error if applicable */\n validationError?: Error;\n /** Original error thrown by factory if applicable */\n originalError?: Error;\n /** Render traversal limiter that was triggered if applicable */\n limitType?: RenderLimitType;\n}\n\n/**\n * Content type definition that encapsulates type, parser, and factory for registration.\n */\nexport interface ContentTypeDefinition<\n TModel extends ContentModel = ContentModel,\n> extends RendererEntry<TModel> {\n /** The content type this module handles */\n readonly type: string;\n}\n\n/**\n * Complete dynamic content renderer with registration and error handling.\n */\nexport interface DynamicContentRenderer extends Renderer {\n /**\n * Register a content type with its parser and factory.\n * @param input - Type registration containing type, parse, and factory\n */\n register<TModel extends ContentModel>(input: {\n type: string;\n parse: ContentModelParser<TModel>;\n factory: ComponentFactory<TModel>;\n }): void;\n\n /**\n * Unregister a content type.\n * @param type - Type name to unregister\n * @returns True if type was registered and removed\n */\n unregister(type: string): boolean;\n\n /**\n * Check if a content type is registered.\n * @param type - Type name to check\n * @returns True if type is registered\n */\n isRegistered(type: string): boolean;\n\n /**\n * Get all registered type names.\n * @returns Array of registered type names\n */\n getRegisteredTypes(): string[];\n\n /**\n * Get current renderer configuration.\n * @returns Read-only configuration object\n */\n getConfiguration(): Readonly<Required<RendererConfiguration>>;\n\n /**\n * Update renderer configuration.\n * @param newConfig - Partial configuration to merge\n */\n updateConfiguration(newConfig: Partial<RendererConfiguration>): void;\n}\n","/**\n * @fileoverview Abstract renderer implementation providing framework-agnostic content model registration and rendering.\n * This is the core orchestration layer that handles validation, type lookup, and rendering delegation.\n */\n\nimport type {\n ComponentFactory,\n ContentModel,\n ContentModelParser,\n ContentTypeDefinition,\n DynamicContentRenderer,\n RenderError,\n RenderLimitType,\n RendererConfiguration,\n RendererEntry,\n} from '../types';\nimport { RenderErrorType } from '../types';\n\nconst DEFAULT_MAX_RENDER_DEPTH = 50;\nconst DEFAULT_MAX_RENDER_NODES = 1000;\n\ntype TraversalErrorReason = 'MAX_DEPTH' | 'MAX_NODES' | 'CYCLE';\n\ntype RenderContext = {\n depth: number;\n nodeCount: number;\n ancestors: Set<ContentModel>;\n};\n\nclass RenderTraversalError extends Error {\n constructor(readonly reason: TraversalErrorReason) {\n let message: string;\n if (reason === 'MAX_DEPTH') {\n message = 'Maximum render depth exceeded';\n } else if (reason === 'MAX_NODES') {\n message = 'Maximum number of nodes exceeded';\n } else {\n message = 'Circular content reference detected';\n }\n super(message);\n this.name = 'RenderTraversalError';\n }\n}\n\n/**\n * Abstract base class for content model renderers.\n * Provides core functionality for registration, validation, and rendering.\n * Framework-specific renderers should extend this class and implement the abstract methods.\n *\n * @example\n *\n * class MyFrameworkRenderer extends AbstractRenderer {\n * protected aggregateArrayOutputs(outputs: unknown[]) {\n * return outputs.filter(Boolean);\n * }\n *\n * protected renderValidationError(error: RenderError) {\n * return createErrorElement(error);\n * }\n * }\n *\n */\nexport abstract class AbstractRenderer implements DynamicContentRenderer {\n private readonly entries = new Map<string, RendererEntry>();\n private config: Required<RendererConfiguration>;\n\n /**\n * Creates a new renderer with the provided configuration.\n * Sets up default values for typeField, nullValue, and showValidationErrors.\n *\n * @param config - Optional configuration to customize renderer behavior\n */\n constructor(config: RendererConfiguration = {}) {\n this.config = {\n typeField: 'type',\n nullValue: null,\n showValidationErrors: false,\n allowDuplicateRegistrations: false,\n maxRenderDepth: DEFAULT_MAX_RENDER_DEPTH,\n maxRenderNodes: DEFAULT_MAX_RENDER_NODES,\n ...config,\n };\n this.sanitizeLimitConfiguration();\n }\n\n register<TModel extends ContentModel>(contentDefinition: ContentTypeDefinition<TModel>): void {\n const { type, parse, factory } = contentDefinition;\n if (this.isRegistered(type)) {\n const warning = `${type} is already registered, overriding existing entry with a new one.`;\n if (!this.config.allowDuplicateRegistrations) {\n throw new Error(\n `${warning} Enable allowDuplicateRegistrations in the renderer configuration to permit overrides.`\n );\n }\n console.warn(warning);\n }\n this.entries.set(type, {\n parse: parse as unknown as ContentModelParser,\n factory: factory as unknown as ComponentFactory,\n });\n }\n\n unregister(type: string): boolean {\n return this.entries.delete(type);\n }\n\n isRegistered(type: string): boolean {\n return this.entries.has(type);\n }\n\n getRegisteredTypes(): string[] {\n return Array.from(this.entries.keys());\n }\n\n render(model: ContentModel): unknown {\n return this.renderModel(model, this.createRenderContext());\n }\n\n renderArray(models: ContentModel[]): unknown {\n return this.renderModelArray(models, this.createRenderContext());\n }\n\n getConfiguration(): Readonly<Required<RendererConfiguration>> {\n return { ...this.config };\n }\n\n updateConfiguration(newConfig: Partial<RendererConfiguration>): void {\n this.config = { ...this.config, ...newConfig };\n this.sanitizeLimitConfiguration();\n }\n\n private renderModel(model: ContentModel, context: RenderContext): unknown {\n if (model == null) {\n return this.config.nullValue;\n }\n\n let scopeEntered = false;\n\n try {\n this.enterRenderScope(model, context);\n scopeEntered = true;\n\n const type = this.extractType(model);\n if (!type) {\n return this.handleMissingTypeError(model);\n }\n\n const entry = this.entries.get(type);\n if (!entry) {\n return this.handleUnregisteredTypeError(type, model);\n }\n\n const validationResult = entry.parse(model);\n if (validationResult.error) {\n return this.handleValidationError(type, model, validationResult.error);\n }\n\n return this.executeFactory(entry, validationResult.data, model, type, context);\n } catch (error) {\n return this.handleRenderError(error, model);\n } finally {\n if (scopeEntered) {\n this.exitRenderScope(model, context);\n }\n }\n }\n\n private handleMissingTypeError(model: ContentModel): unknown {\n const error: RenderError = {\n type: RenderErrorType.MISSING_TYPE_FIELD,\n message: `Model is missing required type field: ${this.config.typeField}`,\n model,\n typeField: this.config.typeField,\n };\n return this.renderErrorOrHide(error);\n }\n\n private handleUnregisteredTypeError(type: string, model: ContentModel): unknown {\n const error: RenderError = {\n type: RenderErrorType.UNREGISTERED_TYPE,\n message: `No registration found for type: ${type}`,\n model,\n typeField: this.config.typeField,\n };\n return this.renderErrorOrHide(error);\n }\n\n private handleValidationError(\n type: string,\n model: ContentModel,\n validationError: Error\n ): unknown {\n const error: RenderError = {\n type: RenderErrorType.VALIDATION_ERROR,\n message: `Validation failed for type: ${type}`,\n model,\n typeField: this.config.typeField,\n validationError,\n };\n return this.renderErrorOrHide(error);\n }\n\n private executeFactory<TModel extends ContentModel>(\n entry: RendererEntry<TModel>,\n data: TModel,\n model: ContentModel,\n type: string,\n context: RenderContext\n ): unknown {\n const renderContent = (content: ContentModel | ContentModel[]) => {\n if (Array.isArray(content)) {\n return this.renderModelArray(content, context);\n }\n return this.renderModel(content, context);\n };\n\n try {\n return entry.factory({\n model: data,\n renderContent,\n });\n } catch (factoryError) {\n const error: RenderError = {\n type: RenderErrorType.FACTORY_ERROR,\n message: `Factory error for type: ${type}`,\n model,\n typeField: this.config.typeField,\n originalError:\n factoryError instanceof Error ? factoryError : new Error(String(factoryError)),\n };\n return this.renderErrorOrHide(error);\n }\n }\n\n private handleRenderError(error: unknown, model: ContentModel): unknown {\n if (error instanceof RenderTraversalError) {\n const traversalRenderError = this.buildTraversalRenderError(error.reason, model);\n return this.renderErrorOrHide(traversalRenderError);\n }\n\n const renderError: RenderError = {\n type: RenderErrorType.FACTORY_ERROR,\n message: 'Unexpected error during rendering',\n model,\n originalError: error instanceof Error ? error : new Error(String(error)),\n };\n return this.renderErrorOrHide(renderError);\n }\n\n private renderErrorOrHide(error: RenderError): unknown {\n return this.config.showValidationErrors\n ? this.renderValidationError(error)\n : this.config.nullValue;\n }\n\n private renderModelArray(models: ContentModel[], context: RenderContext): unknown {\n const outputs: unknown[] = [];\n for (const model of models) {\n outputs.push(this.renderModel(model, context));\n }\n return this.aggregateArrayOutputs(outputs);\n }\n\n private createRenderContext(): RenderContext {\n return {\n depth: 0,\n nodeCount: 0,\n ancestors: new Set<ContentModel>(),\n };\n }\n\n private enterRenderScope(model: ContentModel, context: RenderContext): void {\n if (context.depth >= this.config.maxRenderDepth) {\n throw new RenderTraversalError('MAX_DEPTH');\n }\n if (context.nodeCount >= this.config.maxRenderNodes) {\n throw new RenderTraversalError('MAX_NODES');\n }\n\n if (this.isObjectModel(model)) {\n if (context.ancestors.has(model)) {\n throw new RenderTraversalError('CYCLE');\n }\n context.ancestors.add(model);\n }\n\n context.depth += 1;\n context.nodeCount += 1;\n }\n\n private exitRenderScope(model: ContentModel, context: RenderContext): void {\n if (context.depth > 0) {\n context.depth -= 1;\n }\n if (this.isObjectModel(model)) {\n context.ancestors.delete(model);\n }\n }\n\n private isObjectModel(model: unknown): model is ContentModel {\n return typeof model === 'object' && model !== null;\n }\n\n private buildTraversalRenderError(\n reason: TraversalErrorReason,\n model: ContentModel\n ): RenderError {\n const limitMap: Record<TraversalErrorReason, RenderLimitType> = {\n MAX_DEPTH: 'depth',\n MAX_NODES: 'nodes',\n CYCLE: 'cycle',\n };\n\n const messageMap: Record<TraversalErrorReason, string> = {\n MAX_DEPTH: 'Render depth limit exceeded',\n MAX_NODES: 'Render node limit exceeded',\n CYCLE: 'Circular reference detected during rendering',\n };\n\n return {\n type: RenderErrorType.RENDER_LIMIT_EXCEEDED,\n message: messageMap[reason],\n model,\n typeField: this.config.typeField,\n limitType: limitMap[reason],\n };\n }\n\n private sanitizeLimitConfiguration(): void {\n this.config.maxRenderDepth = this.normalizeLimit(\n this.config.maxRenderDepth,\n DEFAULT_MAX_RENDER_DEPTH\n );\n this.config.maxRenderNodes = this.normalizeLimit(\n this.config.maxRenderNodes,\n DEFAULT_MAX_RENDER_NODES\n );\n }\n\n private normalizeLimit(value: number, fallback: number): number {\n if (!Number.isFinite(value) || value <= 0) {\n return fallback;\n }\n return Math.floor(value);\n }\n\n /**\n * Extract the type identifier from a content model.\n * Uses the configured typeField to find the type value.\n *\n * @param model - The content model to extract type from\n * @returns The type string or null if not found or invalid\n * @private\n */\n private extractType(model: ContentModel): string | null {\n const type = model[this.config.typeField];\n return typeof type === 'string' ? type : null;\n }\n\n /**\n * Abstract method for aggregating array outputs into framework-specific format.\n * Must be implemented by framework renderers to handle multiple rendered components.\n *\n * @param outputs - Array of rendered outputs from individual models\n * @returns Framework-specific aggregated output (e.g., Fragment, array, etc.)\n * @protected\n */\n protected abstract aggregateArrayOutputs(outputs: unknown[]): unknown;\n\n /**\n * Abstract method for rendering validation errors in development.\n * Must be implemented by framework renderers to provide appropriate error visualization.\n *\n * @param error - The render error to display\n * @returns Framework-specific error output or null if errors should be hidden\n * @protected\n */\n protected abstract renderValidationError(error: RenderError): unknown;\n}\n","import type {\n ComponentFactory,\n ContentModel,\n ContentModelParser,\n ContentTypeDefinition,\n} from '../types';\n\n/**\n * @fileoverview Abstract base class for content type definitions that encapsulate type, parser, and factory.\n * Provides a convenient way to package related content rendering logic into reusable definitions.\n */\n\n/**\n * Abstract base class for content type definitions.\n * Encapsulates a content type with its parser and factory, providing a clean registration interface.\n *\n * @template TModel - The specific content model type this module handles\n *\n * @example\n *\n * class ButtonDefinition extends AbstractContentTypeDefinition<ButtonModel> {\n * parse = (model: ButtonModel) => ({ data: model });\n * factory = ({ model }) => <button>{model.text}</button>;\n *\n * constructor() {\n * super('button');\n * }\n * }\n *\n * renderer.register(new ButtonDefinition());\n *\n */\nexport abstract class AbstractContentTypeDefinition<\n TModel extends ContentModel,\n> implements ContentTypeDefinition<TModel> {\n readonly type: string;\n abstract parse: ContentModelParser<TModel>;\n abstract factory: ComponentFactory<TModel>;\n\n /**\n * Creates a new content type definition with the specified type identifier.\n *\n * @param type - The unique type identifier for this content type definition\n */\n constructor(type: string) {\n this.type = type;\n }\n}\n"]}
package/dist/index.mjs ADDED
@@ -0,0 +1,2 @@
1
+ var u=(o=>(o.MISSING_TYPE_FIELD="MISSING_TYPE_FIELD",o.UNREGISTERED_TYPE="UNREGISTERED_TYPE",o.VALIDATION_ERROR="VALIDATION_ERROR",o.FACTORY_ERROR="FACTORY_ERROR",o.RENDER_LIMIT_EXCEEDED="RENDER_LIMIT_EXCEEDED",o))(u||{});var c=50,E=1e3,d=class extends Error{constructor(r){let n;r==="MAX_DEPTH"?n="Maximum render depth exceeded":r==="MAX_NODES"?n="Maximum number of nodes exceeded":n="Circular content reference detected";super(n);this.reason=r;this.name="RenderTraversalError";}},a=class{constructor(e={}){this.entries=new Map;this.config={typeField:"type",nullValue:null,showValidationErrors:false,allowDuplicateRegistrations:false,maxRenderDepth:c,maxRenderNodes:E,...e},this.sanitizeLimitConfiguration();}register(e){let{type:r,parse:n,factory:t}=e;if(this.isRegistered(r)){let o=`${r} is already registered, overriding existing entry with a new one.`;if(!this.config.allowDuplicateRegistrations)throw new Error(`${o} Enable allowDuplicateRegistrations in the renderer configuration to permit overrides.`);console.warn(o);}this.entries.set(r,{parse:n,factory:t});}unregister(e){return this.entries.delete(e)}isRegistered(e){return this.entries.has(e)}getRegisteredTypes(){return Array.from(this.entries.keys())}render(e){return this.renderModel(e,this.createRenderContext())}renderArray(e){return this.renderModelArray(e,this.createRenderContext())}getConfiguration(){return {...this.config}}updateConfiguration(e){this.config={...this.config,...e},this.sanitizeLimitConfiguration();}renderModel(e,r){if(e==null)return this.config.nullValue;let n=false;try{this.enterRenderScope(e,r),n=!0;let t=this.extractType(e);if(!t)return this.handleMissingTypeError(e);let o=this.entries.get(t);if(!o)return this.handleUnregisteredTypeError(t,e);let s=o.parse(e);return s.error?this.handleValidationError(t,e,s.error):this.executeFactory(o,s.data,e,t,r)}catch(t){return this.handleRenderError(t,e)}finally{n&&this.exitRenderScope(e,r);}}handleMissingTypeError(e){let r={type:"MISSING_TYPE_FIELD",message:`Model is missing required type field: ${this.config.typeField}`,model:e,typeField:this.config.typeField};return this.renderErrorOrHide(r)}handleUnregisteredTypeError(e,r){let n={type:"UNREGISTERED_TYPE",message:`No registration found for type: ${e}`,model:r,typeField:this.config.typeField};return this.renderErrorOrHide(n)}handleValidationError(e,r,n){let t={type:"VALIDATION_ERROR",message:`Validation failed for type: ${e}`,model:r,typeField:this.config.typeField,validationError:n};return this.renderErrorOrHide(t)}executeFactory(e,r,n,t,o){let s=i=>Array.isArray(i)?this.renderModelArray(i,o):this.renderModel(i,o);try{return e.factory({model:r,renderContent:s})}catch(i){let R={type:"FACTORY_ERROR",message:`Factory error for type: ${t}`,model:n,typeField:this.config.typeField,originalError:i instanceof Error?i:new Error(String(i))};return this.renderErrorOrHide(R)}}handleRenderError(e,r){if(e instanceof d){let t=this.buildTraversalRenderError(e.reason,r);return this.renderErrorOrHide(t)}let n={type:"FACTORY_ERROR",message:"Unexpected error during rendering",model:r,originalError:e instanceof Error?e:new Error(String(e))};return this.renderErrorOrHide(n)}renderErrorOrHide(e){return this.config.showValidationErrors?this.renderValidationError(e):this.config.nullValue}renderModelArray(e,r){let n=[];for(let t of e)n.push(this.renderModel(t,r));return this.aggregateArrayOutputs(n)}createRenderContext(){return {depth:0,nodeCount:0,ancestors:new Set}}enterRenderScope(e,r){if(r.depth>=this.config.maxRenderDepth)throw new d("MAX_DEPTH");if(r.nodeCount>=this.config.maxRenderNodes)throw new d("MAX_NODES");if(this.isObjectModel(e)){if(r.ancestors.has(e))throw new d("CYCLE");r.ancestors.add(e);}r.depth+=1,r.nodeCount+=1;}exitRenderScope(e,r){r.depth>0&&(r.depth-=1),this.isObjectModel(e)&&r.ancestors.delete(e);}isObjectModel(e){return typeof e=="object"&&e!==null}buildTraversalRenderError(e,r){let n={MAX_DEPTH:"depth",MAX_NODES:"nodes",CYCLE:"cycle"},t={MAX_DEPTH:"Render depth limit exceeded",MAX_NODES:"Render node limit exceeded",CYCLE:"Circular reference detected during rendering"};return {type:"RENDER_LIMIT_EXCEEDED",message:t[e],model:r,typeField:this.config.typeField,limitType:n[e]}}sanitizeLimitConfiguration(){this.config.maxRenderDepth=this.normalizeLimit(this.config.maxRenderDepth,c),this.config.maxRenderNodes=this.normalizeLimit(this.config.maxRenderNodes,E);}normalizeLimit(e,r){return !Number.isFinite(e)||e<=0?r:Math.floor(e)}extractType(e){let r=e[this.config.typeField];return typeof r=="string"?r:null}};var l=class{constructor(e){this.type=e;}};export{l as AbstractContentTypeDefinition,a as AbstractRenderer,u as RenderErrorType};//# sourceMappingURL=index.mjs.map
2
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/types.ts","../src/renderer/AbstractRenderer.ts","../src/renderer/AbstractContentTypeDefinition.ts"],"names":["RenderErrorType","DEFAULT_MAX_RENDER_DEPTH","DEFAULT_MAX_RENDER_NODES","RenderTraversalError","reason","message","AbstractRenderer","config","contentDefinition","type","parse","factory","warning","model","models","newConfig","context","scopeEntered","entry","validationResult","error","validationError","data","renderContent","content","factoryError","traversalRenderError","renderError","outputs","limitMap","messageMap","value","fallback","AbstractContentTypeDefinition"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * @fileoverview Core type definitions for the wasl-flow package.\n * Defines interfaces and types for content models, renderer configuration, and rendering.\n */\n\n/**\n * A content model represents a unit of content to render.\n * Must contain a type-identifying field (configurable via typeField).\n */\nexport interface ContentModel {\n [key: string]: unknown;\n}\n\n/**\n * Configuration options for the renderer.\n */\nexport interface RendererConfiguration {\n /** Field name used to identify the model type (default: 'type') */\n typeField?: string;\n /** Value returned when rendering fails or model is null/undefined */\n nullValue?: unknown;\n /** Show detailed validation errors in development */\n showValidationErrors?: boolean;\n /** Explicitly allow duplicate registrations to overwrite existing entries */\n allowDuplicateRegistrations?: boolean;\n /** Maximum allowed depth when recursively rendering nested models */\n maxRenderDepth?: number;\n /** Maximum number of nodes allowed to be processed in a single render */\n maxRenderNodes?: number;\n}\n\n/**\n * Renderer entry that pairs a parser with a factory for a specific model type.\n */\nexport interface RendererEntry<TModel extends ContentModel = ContentModel> {\n /** Parse function that validates and transforms the model */\n parse: ContentModelParser<TModel>;\n /** Factory function that creates framework-specific output */\n factory: ComponentFactory<TModel>;\n}\n\n/**\n * Props passed to component factories.\n */\nexport interface ComponentProps<TModel extends ContentModel = ContentModel> {\n /** The validated model data */\n model: TModel;\n /** Function to render nested content models */\n renderContent: (content: ContentModel | ContentModel[]) => unknown;\n}\n\n/**\n * Function that parses and validates a content model.\n * @param model - Raw content model to parse\n * @returns Parsed data or validation error\n */\nexport type ContentModelParser<TModel extends ContentModel = ContentModel> = (\n model: ContentModel\n) => { data: TModel; error?: Error };\n\n/**\n * Factory function that produces framework-specific output from validated model data.\n * @param props - Component props including validated model and render function\n * @returns Framework-specific rendered output\n */\nexport type ComponentFactory<TModel extends ContentModel = ContentModel> = (\n props: ComponentProps<TModel>\n) => unknown;\n\n/**\n * Basic renderer interface for framework-specific implementations.\n */\nexport interface Renderer {\n /** Render a single content model */\n render(model: ContentModel): unknown;\n /** Render an array of content models */\n renderArray(models: ContentModel[]): unknown;\n}\n\n/**\n * Error types that can occur during rendering.\n */\nexport enum RenderErrorType {\n MISSING_TYPE_FIELD = 'MISSING_TYPE_FIELD',\n UNREGISTERED_TYPE = 'UNREGISTERED_TYPE',\n VALIDATION_ERROR = 'VALIDATION_ERROR',\n FACTORY_ERROR = 'FACTORY_ERROR',\n RENDER_LIMIT_EXCEEDED = 'RENDER_LIMIT_EXCEEDED',\n}\n\n/**\n * Reasons that a render limit error can occur.\n */\nexport type RenderLimitType = 'depth' | 'nodes' | 'cycle';\n\n/**\n * Detailed error information for debugging failed renders.\n */\nexport interface RenderError {\n /** Type of error that occurred */\n type: RenderErrorType;\n /** Human-readable error message */\n message: string;\n /** The model that failed to render */\n model?: ContentModel;\n /** The type field name that was expected */\n typeField?: string;\n /** Original validation error if applicable */\n validationError?: Error;\n /** Original error thrown by factory if applicable */\n originalError?: Error;\n /** Render traversal limiter that was triggered if applicable */\n limitType?: RenderLimitType;\n}\n\n/**\n * Content type definition that encapsulates type, parser, and factory for registration.\n */\nexport interface ContentTypeDefinition<\n TModel extends ContentModel = ContentModel,\n> extends RendererEntry<TModel> {\n /** The content type this module handles */\n readonly type: string;\n}\n\n/**\n * Complete dynamic content renderer with registration and error handling.\n */\nexport interface DynamicContentRenderer extends Renderer {\n /**\n * Register a content type with its parser and factory.\n * @param input - Type registration containing type, parse, and factory\n */\n register<TModel extends ContentModel>(input: {\n type: string;\n parse: ContentModelParser<TModel>;\n factory: ComponentFactory<TModel>;\n }): void;\n\n /**\n * Unregister a content type.\n * @param type - Type name to unregister\n * @returns True if type was registered and removed\n */\n unregister(type: string): boolean;\n\n /**\n * Check if a content type is registered.\n * @param type - Type name to check\n * @returns True if type is registered\n */\n isRegistered(type: string): boolean;\n\n /**\n * Get all registered type names.\n * @returns Array of registered type names\n */\n getRegisteredTypes(): string[];\n\n /**\n * Get current renderer configuration.\n * @returns Read-only configuration object\n */\n getConfiguration(): Readonly<Required<RendererConfiguration>>;\n\n /**\n * Update renderer configuration.\n * @param newConfig - Partial configuration to merge\n */\n updateConfiguration(newConfig: Partial<RendererConfiguration>): void;\n}\n","/**\n * @fileoverview Abstract renderer implementation providing framework-agnostic content model registration and rendering.\n * This is the core orchestration layer that handles validation, type lookup, and rendering delegation.\n */\n\nimport type {\n ComponentFactory,\n ContentModel,\n ContentModelParser,\n ContentTypeDefinition,\n DynamicContentRenderer,\n RenderError,\n RenderLimitType,\n RendererConfiguration,\n RendererEntry,\n} from '../types';\nimport { RenderErrorType } from '../types';\n\nconst DEFAULT_MAX_RENDER_DEPTH = 50;\nconst DEFAULT_MAX_RENDER_NODES = 1000;\n\ntype TraversalErrorReason = 'MAX_DEPTH' | 'MAX_NODES' | 'CYCLE';\n\ntype RenderContext = {\n depth: number;\n nodeCount: number;\n ancestors: Set<ContentModel>;\n};\n\nclass RenderTraversalError extends Error {\n constructor(readonly reason: TraversalErrorReason) {\n let message: string;\n if (reason === 'MAX_DEPTH') {\n message = 'Maximum render depth exceeded';\n } else if (reason === 'MAX_NODES') {\n message = 'Maximum number of nodes exceeded';\n } else {\n message = 'Circular content reference detected';\n }\n super(message);\n this.name = 'RenderTraversalError';\n }\n}\n\n/**\n * Abstract base class for content model renderers.\n * Provides core functionality for registration, validation, and rendering.\n * Framework-specific renderers should extend this class and implement the abstract methods.\n *\n * @example\n *\n * class MyFrameworkRenderer extends AbstractRenderer {\n * protected aggregateArrayOutputs(outputs: unknown[]) {\n * return outputs.filter(Boolean);\n * }\n *\n * protected renderValidationError(error: RenderError) {\n * return createErrorElement(error);\n * }\n * }\n *\n */\nexport abstract class AbstractRenderer implements DynamicContentRenderer {\n private readonly entries = new Map<string, RendererEntry>();\n private config: Required<RendererConfiguration>;\n\n /**\n * Creates a new renderer with the provided configuration.\n * Sets up default values for typeField, nullValue, and showValidationErrors.\n *\n * @param config - Optional configuration to customize renderer behavior\n */\n constructor(config: RendererConfiguration = {}) {\n this.config = {\n typeField: 'type',\n nullValue: null,\n showValidationErrors: false,\n allowDuplicateRegistrations: false,\n maxRenderDepth: DEFAULT_MAX_RENDER_DEPTH,\n maxRenderNodes: DEFAULT_MAX_RENDER_NODES,\n ...config,\n };\n this.sanitizeLimitConfiguration();\n }\n\n register<TModel extends ContentModel>(contentDefinition: ContentTypeDefinition<TModel>): void {\n const { type, parse, factory } = contentDefinition;\n if (this.isRegistered(type)) {\n const warning = `${type} is already registered, overriding existing entry with a new one.`;\n if (!this.config.allowDuplicateRegistrations) {\n throw new Error(\n `${warning} Enable allowDuplicateRegistrations in the renderer configuration to permit overrides.`\n );\n }\n console.warn(warning);\n }\n this.entries.set(type, {\n parse: parse as unknown as ContentModelParser,\n factory: factory as unknown as ComponentFactory,\n });\n }\n\n unregister(type: string): boolean {\n return this.entries.delete(type);\n }\n\n isRegistered(type: string): boolean {\n return this.entries.has(type);\n }\n\n getRegisteredTypes(): string[] {\n return Array.from(this.entries.keys());\n }\n\n render(model: ContentModel): unknown {\n return this.renderModel(model, this.createRenderContext());\n }\n\n renderArray(models: ContentModel[]): unknown {\n return this.renderModelArray(models, this.createRenderContext());\n }\n\n getConfiguration(): Readonly<Required<RendererConfiguration>> {\n return { ...this.config };\n }\n\n updateConfiguration(newConfig: Partial<RendererConfiguration>): void {\n this.config = { ...this.config, ...newConfig };\n this.sanitizeLimitConfiguration();\n }\n\n private renderModel(model: ContentModel, context: RenderContext): unknown {\n if (model == null) {\n return this.config.nullValue;\n }\n\n let scopeEntered = false;\n\n try {\n this.enterRenderScope(model, context);\n scopeEntered = true;\n\n const type = this.extractType(model);\n if (!type) {\n return this.handleMissingTypeError(model);\n }\n\n const entry = this.entries.get(type);\n if (!entry) {\n return this.handleUnregisteredTypeError(type, model);\n }\n\n const validationResult = entry.parse(model);\n if (validationResult.error) {\n return this.handleValidationError(type, model, validationResult.error);\n }\n\n return this.executeFactory(entry, validationResult.data, model, type, context);\n } catch (error) {\n return this.handleRenderError(error, model);\n } finally {\n if (scopeEntered) {\n this.exitRenderScope(model, context);\n }\n }\n }\n\n private handleMissingTypeError(model: ContentModel): unknown {\n const error: RenderError = {\n type: RenderErrorType.MISSING_TYPE_FIELD,\n message: `Model is missing required type field: ${this.config.typeField}`,\n model,\n typeField: this.config.typeField,\n };\n return this.renderErrorOrHide(error);\n }\n\n private handleUnregisteredTypeError(type: string, model: ContentModel): unknown {\n const error: RenderError = {\n type: RenderErrorType.UNREGISTERED_TYPE,\n message: `No registration found for type: ${type}`,\n model,\n typeField: this.config.typeField,\n };\n return this.renderErrorOrHide(error);\n }\n\n private handleValidationError(\n type: string,\n model: ContentModel,\n validationError: Error\n ): unknown {\n const error: RenderError = {\n type: RenderErrorType.VALIDATION_ERROR,\n message: `Validation failed for type: ${type}`,\n model,\n typeField: this.config.typeField,\n validationError,\n };\n return this.renderErrorOrHide(error);\n }\n\n private executeFactory<TModel extends ContentModel>(\n entry: RendererEntry<TModel>,\n data: TModel,\n model: ContentModel,\n type: string,\n context: RenderContext\n ): unknown {\n const renderContent = (content: ContentModel | ContentModel[]) => {\n if (Array.isArray(content)) {\n return this.renderModelArray(content, context);\n }\n return this.renderModel(content, context);\n };\n\n try {\n return entry.factory({\n model: data,\n renderContent,\n });\n } catch (factoryError) {\n const error: RenderError = {\n type: RenderErrorType.FACTORY_ERROR,\n message: `Factory error for type: ${type}`,\n model,\n typeField: this.config.typeField,\n originalError:\n factoryError instanceof Error ? factoryError : new Error(String(factoryError)),\n };\n return this.renderErrorOrHide(error);\n }\n }\n\n private handleRenderError(error: unknown, model: ContentModel): unknown {\n if (error instanceof RenderTraversalError) {\n const traversalRenderError = this.buildTraversalRenderError(error.reason, model);\n return this.renderErrorOrHide(traversalRenderError);\n }\n\n const renderError: RenderError = {\n type: RenderErrorType.FACTORY_ERROR,\n message: 'Unexpected error during rendering',\n model,\n originalError: error instanceof Error ? error : new Error(String(error)),\n };\n return this.renderErrorOrHide(renderError);\n }\n\n private renderErrorOrHide(error: RenderError): unknown {\n return this.config.showValidationErrors\n ? this.renderValidationError(error)\n : this.config.nullValue;\n }\n\n private renderModelArray(models: ContentModel[], context: RenderContext): unknown {\n const outputs: unknown[] = [];\n for (const model of models) {\n outputs.push(this.renderModel(model, context));\n }\n return this.aggregateArrayOutputs(outputs);\n }\n\n private createRenderContext(): RenderContext {\n return {\n depth: 0,\n nodeCount: 0,\n ancestors: new Set<ContentModel>(),\n };\n }\n\n private enterRenderScope(model: ContentModel, context: RenderContext): void {\n if (context.depth >= this.config.maxRenderDepth) {\n throw new RenderTraversalError('MAX_DEPTH');\n }\n if (context.nodeCount >= this.config.maxRenderNodes) {\n throw new RenderTraversalError('MAX_NODES');\n }\n\n if (this.isObjectModel(model)) {\n if (context.ancestors.has(model)) {\n throw new RenderTraversalError('CYCLE');\n }\n context.ancestors.add(model);\n }\n\n context.depth += 1;\n context.nodeCount += 1;\n }\n\n private exitRenderScope(model: ContentModel, context: RenderContext): void {\n if (context.depth > 0) {\n context.depth -= 1;\n }\n if (this.isObjectModel(model)) {\n context.ancestors.delete(model);\n }\n }\n\n private isObjectModel(model: unknown): model is ContentModel {\n return typeof model === 'object' && model !== null;\n }\n\n private buildTraversalRenderError(\n reason: TraversalErrorReason,\n model: ContentModel\n ): RenderError {\n const limitMap: Record<TraversalErrorReason, RenderLimitType> = {\n MAX_DEPTH: 'depth',\n MAX_NODES: 'nodes',\n CYCLE: 'cycle',\n };\n\n const messageMap: Record<TraversalErrorReason, string> = {\n MAX_DEPTH: 'Render depth limit exceeded',\n MAX_NODES: 'Render node limit exceeded',\n CYCLE: 'Circular reference detected during rendering',\n };\n\n return {\n type: RenderErrorType.RENDER_LIMIT_EXCEEDED,\n message: messageMap[reason],\n model,\n typeField: this.config.typeField,\n limitType: limitMap[reason],\n };\n }\n\n private sanitizeLimitConfiguration(): void {\n this.config.maxRenderDepth = this.normalizeLimit(\n this.config.maxRenderDepth,\n DEFAULT_MAX_RENDER_DEPTH\n );\n this.config.maxRenderNodes = this.normalizeLimit(\n this.config.maxRenderNodes,\n DEFAULT_MAX_RENDER_NODES\n );\n }\n\n private normalizeLimit(value: number, fallback: number): number {\n if (!Number.isFinite(value) || value <= 0) {\n return fallback;\n }\n return Math.floor(value);\n }\n\n /**\n * Extract the type identifier from a content model.\n * Uses the configured typeField to find the type value.\n *\n * @param model - The content model to extract type from\n * @returns The type string or null if not found or invalid\n * @private\n */\n private extractType(model: ContentModel): string | null {\n const type = model[this.config.typeField];\n return typeof type === 'string' ? type : null;\n }\n\n /**\n * Abstract method for aggregating array outputs into framework-specific format.\n * Must be implemented by framework renderers to handle multiple rendered components.\n *\n * @param outputs - Array of rendered outputs from individual models\n * @returns Framework-specific aggregated output (e.g., Fragment, array, etc.)\n * @protected\n */\n protected abstract aggregateArrayOutputs(outputs: unknown[]): unknown;\n\n /**\n * Abstract method for rendering validation errors in development.\n * Must be implemented by framework renderers to provide appropriate error visualization.\n *\n * @param error - The render error to display\n * @returns Framework-specific error output or null if errors should be hidden\n * @protected\n */\n protected abstract renderValidationError(error: RenderError): unknown;\n}\n","import type {\n ComponentFactory,\n ContentModel,\n ContentModelParser,\n ContentTypeDefinition,\n} from '../types';\n\n/**\n * @fileoverview Abstract base class for content type definitions that encapsulate type, parser, and factory.\n * Provides a convenient way to package related content rendering logic into reusable definitions.\n */\n\n/**\n * Abstract base class for content type definitions.\n * Encapsulates a content type with its parser and factory, providing a clean registration interface.\n *\n * @template TModel - The specific content model type this module handles\n *\n * @example\n *\n * class ButtonDefinition extends AbstractContentTypeDefinition<ButtonModel> {\n * parse = (model: ButtonModel) => ({ data: model });\n * factory = ({ model }) => <button>{model.text}</button>;\n *\n * constructor() {\n * super('button');\n * }\n * }\n *\n * renderer.register(new ButtonDefinition());\n *\n */\nexport abstract class AbstractContentTypeDefinition<\n TModel extends ContentModel,\n> implements ContentTypeDefinition<TModel> {\n readonly type: string;\n abstract parse: ContentModelParser<TModel>;\n abstract factory: ComponentFactory<TModel>;\n\n /**\n * Creates a new content type definition with the specified type identifier.\n *\n * @param type - The unique type identifier for this content type definition\n */\n constructor(type: string) {\n this.type = type;\n }\n}\n"]}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * @fileoverview Main exports for wasl-flow.
3
+ * Provides core types and abstract renderer for framework-agnostic content rendering.
4
+ *
5
+ * This is the main entry point for the package, exporting everything needed to
6
+ * create custom framework renderers or use the core functionality directly.
7
+ */
8
+ export type * from './types';
9
+ export { RenderErrorType } from './types';
10
+ export * from './renderer';
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,mBAAmB,SAAS,CAAC;AAC7B,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC1C,cAAc,YAAY,CAAC"}
@@ -0,0 +1,37 @@
1
+ import type { ComponentFactory, ContentModel, ContentModelParser, ContentTypeDefinition } from '../types';
2
+ /**
3
+ * @fileoverview Abstract base class for content type definitions that encapsulate type, parser, and factory.
4
+ * Provides a convenient way to package related content rendering logic into reusable definitions.
5
+ */
6
+ /**
7
+ * Abstract base class for content type definitions.
8
+ * Encapsulates a content type with its parser and factory, providing a clean registration interface.
9
+ *
10
+ * @template TModel - The specific content model type this module handles
11
+ *
12
+ * @example
13
+ *
14
+ * class ButtonDefinition extends AbstractContentTypeDefinition<ButtonModel> {
15
+ * parse = (model: ButtonModel) => ({ data: model });
16
+ * factory = ({ model }) => <button>{model.text}</button>;
17
+ *
18
+ * constructor() {
19
+ * super('button');
20
+ * }
21
+ * }
22
+ *
23
+ * renderer.register(new ButtonDefinition());
24
+ *
25
+ */
26
+ export declare abstract class AbstractContentTypeDefinition<TModel extends ContentModel> implements ContentTypeDefinition<TModel> {
27
+ readonly type: string;
28
+ abstract parse: ContentModelParser<TModel>;
29
+ abstract factory: ComponentFactory<TModel>;
30
+ /**
31
+ * Creates a new content type definition with the specified type identifier.
32
+ *
33
+ * @param type - The unique type identifier for this content type definition
34
+ */
35
+ constructor(type: string);
36
+ }
37
+ //# sourceMappingURL=AbstractContentTypeDefinition.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AbstractContentTypeDefinition.d.ts","sourceRoot":"","sources":["../../../src/renderer/AbstractContentTypeDefinition.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,gBAAgB,EAChB,YAAY,EACZ,kBAAkB,EAClB,qBAAqB,EACtB,MAAM,UAAU,CAAC;AAElB;;;GAGG;AAEH;;;;;;;;;;;;;;;;;;;GAmBG;AACH,8BAAsB,6BAA6B,CACjD,MAAM,SAAS,YAAY,CAC3B,YAAW,qBAAqB,CAAC,MAAM,CAAC;IACxC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,kBAAkB,CAAC,MAAM,CAAC,CAAC;IAC3C,QAAQ,CAAC,OAAO,EAAE,gBAAgB,CAAC,MAAM,CAAC,CAAC;IAE3C;;;;OAIG;gBACS,IAAI,EAAE,MAAM;CAGzB"}
@@ -0,0 +1,85 @@
1
+ /**
2
+ * @fileoverview Abstract renderer implementation providing framework-agnostic content model registration and rendering.
3
+ * This is the core orchestration layer that handles validation, type lookup, and rendering delegation.
4
+ */
5
+ import type { ContentModel, ContentTypeDefinition, DynamicContentRenderer, RenderError, RendererConfiguration } from '../types';
6
+ /**
7
+ * Abstract base class for content model renderers.
8
+ * Provides core functionality for registration, validation, and rendering.
9
+ * Framework-specific renderers should extend this class and implement the abstract methods.
10
+ *
11
+ * @example
12
+ *
13
+ * class MyFrameworkRenderer extends AbstractRenderer {
14
+ * protected aggregateArrayOutputs(outputs: unknown[]) {
15
+ * return outputs.filter(Boolean);
16
+ * }
17
+ *
18
+ * protected renderValidationError(error: RenderError) {
19
+ * return createErrorElement(error);
20
+ * }
21
+ * }
22
+ *
23
+ */
24
+ export declare abstract class AbstractRenderer implements DynamicContentRenderer {
25
+ private readonly entries;
26
+ private config;
27
+ /**
28
+ * Creates a new renderer with the provided configuration.
29
+ * Sets up default values for typeField, nullValue, and showValidationErrors.
30
+ *
31
+ * @param config - Optional configuration to customize renderer behavior
32
+ */
33
+ constructor(config?: RendererConfiguration);
34
+ register<TModel extends ContentModel>(contentDefinition: ContentTypeDefinition<TModel>): void;
35
+ unregister(type: string): boolean;
36
+ isRegistered(type: string): boolean;
37
+ getRegisteredTypes(): string[];
38
+ render(model: ContentModel): unknown;
39
+ renderArray(models: ContentModel[]): unknown;
40
+ getConfiguration(): Readonly<Required<RendererConfiguration>>;
41
+ updateConfiguration(newConfig: Partial<RendererConfiguration>): void;
42
+ private renderModel;
43
+ private handleMissingTypeError;
44
+ private handleUnregisteredTypeError;
45
+ private handleValidationError;
46
+ private executeFactory;
47
+ private handleRenderError;
48
+ private renderErrorOrHide;
49
+ private renderModelArray;
50
+ private createRenderContext;
51
+ private enterRenderScope;
52
+ private exitRenderScope;
53
+ private isObjectModel;
54
+ private buildTraversalRenderError;
55
+ private sanitizeLimitConfiguration;
56
+ private normalizeLimit;
57
+ /**
58
+ * Extract the type identifier from a content model.
59
+ * Uses the configured typeField to find the type value.
60
+ *
61
+ * @param model - The content model to extract type from
62
+ * @returns The type string or null if not found or invalid
63
+ * @private
64
+ */
65
+ private extractType;
66
+ /**
67
+ * Abstract method for aggregating array outputs into framework-specific format.
68
+ * Must be implemented by framework renderers to handle multiple rendered components.
69
+ *
70
+ * @param outputs - Array of rendered outputs from individual models
71
+ * @returns Framework-specific aggregated output (e.g., Fragment, array, etc.)
72
+ * @protected
73
+ */
74
+ protected abstract aggregateArrayOutputs(outputs: unknown[]): unknown;
75
+ /**
76
+ * Abstract method for rendering validation errors in development.
77
+ * Must be implemented by framework renderers to provide appropriate error visualization.
78
+ *
79
+ * @param error - The render error to display
80
+ * @returns Framework-specific error output or null if errors should be hidden
81
+ * @protected
82
+ */
83
+ protected abstract renderValidationError(error: RenderError): unknown;
84
+ }
85
+ //# sourceMappingURL=AbstractRenderer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AbstractRenderer.d.ts","sourceRoot":"","sources":["../../../src/renderer/AbstractRenderer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAEV,YAAY,EAEZ,qBAAqB,EACrB,sBAAsB,EACtB,WAAW,EAEX,qBAAqB,EAEtB,MAAM,UAAU,CAAC;AA6BlB;;;;;;;;;;;;;;;;;GAiBG;AACH,8BAAsB,gBAAiB,YAAW,sBAAsB;IACtE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAoC;IAC5D,OAAO,CAAC,MAAM,CAAkC;IAEhD;;;;;OAKG;gBACS,MAAM,GAAE,qBAA0B;IAa9C,QAAQ,CAAC,MAAM,SAAS,YAAY,EAAE,iBAAiB,EAAE,qBAAqB,CAAC,MAAM,CAAC,GAAG,IAAI;IAiB7F,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAIjC,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAInC,kBAAkB,IAAI,MAAM,EAAE;IAI9B,MAAM,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO;IAIpC,WAAW,CAAC,MAAM,EAAE,YAAY,EAAE,GAAG,OAAO;IAI5C,gBAAgB,IAAI,QAAQ,CAAC,QAAQ,CAAC,qBAAqB,CAAC,CAAC;IAI7D,mBAAmB,CAAC,SAAS,EAAE,OAAO,CAAC,qBAAqB,CAAC,GAAG,IAAI;IAKpE,OAAO,CAAC,WAAW;IAoCnB,OAAO,CAAC,sBAAsB;IAU9B,OAAO,CAAC,2BAA2B;IAUnC,OAAO,CAAC,qBAAqB;IAe7B,OAAO,CAAC,cAAc;IAgCtB,OAAO,CAAC,iBAAiB;IAezB,OAAO,CAAC,iBAAiB;IAMzB,OAAO,CAAC,gBAAgB;IAQxB,OAAO,CAAC,mBAAmB;IAQ3B,OAAO,CAAC,gBAAgB;IAmBxB,OAAO,CAAC,eAAe;IASvB,OAAO,CAAC,aAAa;IAIrB,OAAO,CAAC,yBAAyB;IAyBjC,OAAO,CAAC,0BAA0B;IAWlC,OAAO,CAAC,cAAc;IAOtB;;;;;;;OAOG;IACH,OAAO,CAAC,WAAW;IAKnB;;;;;;;OAOG;IACH,SAAS,CAAC,QAAQ,CAAC,qBAAqB,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,OAAO;IAErE;;;;;;;OAOG;IACH,SAAS,CAAC,QAAQ,CAAC,qBAAqB,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO;CACtE"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * @fileoverview Renderer exports for wasl-flow.
3
+ *
4
+ * Provides the core abstract renderer and content type definition base classes
5
+ * for building framework-specific renderers.
6
+ */
7
+ export { AbstractRenderer } from './AbstractRenderer';
8
+ export { AbstractContentTypeDefinition } from './AbstractContentTypeDefinition';
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/renderer/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,6BAA6B,EAAE,MAAM,iCAAiC,CAAC"}
@@ -0,0 +1,152 @@
1
+ /**
2
+ * @fileoverview Core type definitions for the wasl-flow package.
3
+ * Defines interfaces and types for content models, renderer configuration, and rendering.
4
+ */
5
+ /**
6
+ * A content model represents a unit of content to render.
7
+ * Must contain a type-identifying field (configurable via typeField).
8
+ */
9
+ export interface ContentModel {
10
+ [key: string]: unknown;
11
+ }
12
+ /**
13
+ * Configuration options for the renderer.
14
+ */
15
+ export interface RendererConfiguration {
16
+ /** Field name used to identify the model type (default: 'type') */
17
+ typeField?: string;
18
+ /** Value returned when rendering fails or model is null/undefined */
19
+ nullValue?: unknown;
20
+ /** Show detailed validation errors in development */
21
+ showValidationErrors?: boolean;
22
+ /** Explicitly allow duplicate registrations to overwrite existing entries */
23
+ allowDuplicateRegistrations?: boolean;
24
+ /** Maximum allowed depth when recursively rendering nested models */
25
+ maxRenderDepth?: number;
26
+ /** Maximum number of nodes allowed to be processed in a single render */
27
+ maxRenderNodes?: number;
28
+ }
29
+ /**
30
+ * Renderer entry that pairs a parser with a factory for a specific model type.
31
+ */
32
+ export interface RendererEntry<TModel extends ContentModel = ContentModel> {
33
+ /** Parse function that validates and transforms the model */
34
+ parse: ContentModelParser<TModel>;
35
+ /** Factory function that creates framework-specific output */
36
+ factory: ComponentFactory<TModel>;
37
+ }
38
+ /**
39
+ * Props passed to component factories.
40
+ */
41
+ export interface ComponentProps<TModel extends ContentModel = ContentModel> {
42
+ /** The validated model data */
43
+ model: TModel;
44
+ /** Function to render nested content models */
45
+ renderContent: (content: ContentModel | ContentModel[]) => unknown;
46
+ }
47
+ /**
48
+ * Function that parses and validates a content model.
49
+ * @param model - Raw content model to parse
50
+ * @returns Parsed data or validation error
51
+ */
52
+ export type ContentModelParser<TModel extends ContentModel = ContentModel> = (model: ContentModel) => {
53
+ data: TModel;
54
+ error?: Error;
55
+ };
56
+ /**
57
+ * Factory function that produces framework-specific output from validated model data.
58
+ * @param props - Component props including validated model and render function
59
+ * @returns Framework-specific rendered output
60
+ */
61
+ export type ComponentFactory<TModel extends ContentModel = ContentModel> = (props: ComponentProps<TModel>) => unknown;
62
+ /**
63
+ * Basic renderer interface for framework-specific implementations.
64
+ */
65
+ export interface Renderer {
66
+ /** Render a single content model */
67
+ render(model: ContentModel): unknown;
68
+ /** Render an array of content models */
69
+ renderArray(models: ContentModel[]): unknown;
70
+ }
71
+ /**
72
+ * Error types that can occur during rendering.
73
+ */
74
+ export declare enum RenderErrorType {
75
+ MISSING_TYPE_FIELD = "MISSING_TYPE_FIELD",
76
+ UNREGISTERED_TYPE = "UNREGISTERED_TYPE",
77
+ VALIDATION_ERROR = "VALIDATION_ERROR",
78
+ FACTORY_ERROR = "FACTORY_ERROR",
79
+ RENDER_LIMIT_EXCEEDED = "RENDER_LIMIT_EXCEEDED"
80
+ }
81
+ /**
82
+ * Reasons that a render limit error can occur.
83
+ */
84
+ export type RenderLimitType = 'depth' | 'nodes' | 'cycle';
85
+ /**
86
+ * Detailed error information for debugging failed renders.
87
+ */
88
+ export interface RenderError {
89
+ /** Type of error that occurred */
90
+ type: RenderErrorType;
91
+ /** Human-readable error message */
92
+ message: string;
93
+ /** The model that failed to render */
94
+ model?: ContentModel;
95
+ /** The type field name that was expected */
96
+ typeField?: string;
97
+ /** Original validation error if applicable */
98
+ validationError?: Error;
99
+ /** Original error thrown by factory if applicable */
100
+ originalError?: Error;
101
+ /** Render traversal limiter that was triggered if applicable */
102
+ limitType?: RenderLimitType;
103
+ }
104
+ /**
105
+ * Content type definition that encapsulates type, parser, and factory for registration.
106
+ */
107
+ export interface ContentTypeDefinition<TModel extends ContentModel = ContentModel> extends RendererEntry<TModel> {
108
+ /** The content type this module handles */
109
+ readonly type: string;
110
+ }
111
+ /**
112
+ * Complete dynamic content renderer with registration and error handling.
113
+ */
114
+ export interface DynamicContentRenderer extends Renderer {
115
+ /**
116
+ * Register a content type with its parser and factory.
117
+ * @param input - Type registration containing type, parse, and factory
118
+ */
119
+ register<TModel extends ContentModel>(input: {
120
+ type: string;
121
+ parse: ContentModelParser<TModel>;
122
+ factory: ComponentFactory<TModel>;
123
+ }): void;
124
+ /**
125
+ * Unregister a content type.
126
+ * @param type - Type name to unregister
127
+ * @returns True if type was registered and removed
128
+ */
129
+ unregister(type: string): boolean;
130
+ /**
131
+ * Check if a content type is registered.
132
+ * @param type - Type name to check
133
+ * @returns True if type is registered
134
+ */
135
+ isRegistered(type: string): boolean;
136
+ /**
137
+ * Get all registered type names.
138
+ * @returns Array of registered type names
139
+ */
140
+ getRegisteredTypes(): string[];
141
+ /**
142
+ * Get current renderer configuration.
143
+ * @returns Read-only configuration object
144
+ */
145
+ getConfiguration(): Readonly<Required<RendererConfiguration>>;
146
+ /**
147
+ * Update renderer configuration.
148
+ * @param newConfig - Partial configuration to merge
149
+ */
150
+ updateConfiguration(newConfig: Partial<RendererConfiguration>): void;
151
+ }
152
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "wasl-flow",
3
+ "version": "1.0.0",
4
+ "description": "Wasl Flow: a framework-agnostic, schema-validated renderer for dynamic content models",
5
+ "license": "MIT",
6
+ "engines": {
7
+ "node": ">=20"
8
+ },
9
+ "author": "Ahmad Igbariya <ahmadigbariya@pm.me>",
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "git+https://gitlab.com/AhmadAboWatan/wasl-flow.git"
13
+ },
14
+ "bugs": {
15
+ "url": "https://gitlab.com/AhmadAboWatan/wasl-flow/-/issues"
16
+ },
17
+ "homepage": "https://gitlab.com/AhmadAboWatan/wasl-flow",
18
+ "keywords": [
19
+ "content-model",
20
+ "content-renderer",
21
+ "cms",
22
+ "dynamic-content",
23
+ "headless",
24
+ "renderer",
25
+ "rendering",
26
+ "schema",
27
+ "typescript",
28
+ "wasl-flow"
29
+ ],
30
+ "main": "dist/index.js",
31
+ "module": "dist/index.mjs",
32
+ "types": "dist/src/index.d.ts",
33
+ "exports": {
34
+ ".": {
35
+ "types": "./dist/src/index.d.ts",
36
+ "import": "./dist/index.mjs",
37
+ "require": "./dist/index.js"
38
+ }
39
+ },
40
+ "files": [
41
+ "dist"
42
+ ],
43
+ "sideEffects": false,
44
+ "scripts": {
45
+ "build": "tsup --config ../../tsup.config.ts",
46
+ "test": "../../node_modules/.bin/jest --config ../../jest.config.js --runTestsByPath src/__tests__/core.test.ts"
47
+ }
48
+ }