@coherent.js/express 1.0.0-beta.5 → 1.0.0-beta.6
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/dist/index.cjs +2 -170
- package/dist/index.cjs.map +3 -3
- package/dist/index.js +1 -167
- package/dist/index.js.map +3 -3
- package/package.json +2 -2
- package/types/index.d.ts +36 -4
package/dist/index.cjs
CHANGED
|
@@ -24,171 +24,11 @@ __export(index_exports, {
|
|
|
24
24
|
setupCoherent: () => setupCoherent
|
|
25
25
|
});
|
|
26
26
|
module.exports = __toCommonJS(index_exports);
|
|
27
|
-
|
|
28
|
-
// ../core/src/index.js
|
|
29
|
-
var scopeCounter = { value: 0 };
|
|
30
|
-
function generateScopeId() {
|
|
31
|
-
return `coh-${scopeCounter.value++}`;
|
|
32
|
-
}
|
|
33
|
-
function scopeCSS(css, scopeId) {
|
|
34
|
-
if (!css || typeof css !== "string") return css;
|
|
35
|
-
return css.replace(/([^{}]*)\s*{/g, (match, selector) => {
|
|
36
|
-
const selectors = selector.split(",").map((s) => {
|
|
37
|
-
const trimmed = s.trim();
|
|
38
|
-
if (!trimmed) return s;
|
|
39
|
-
if (trimmed.includes(":")) {
|
|
40
|
-
return trimmed.replace(/([^:]+)(:.*)?/, `$1[${scopeId}]$2`);
|
|
41
|
-
}
|
|
42
|
-
return `${trimmed}[${scopeId}]`;
|
|
43
|
-
});
|
|
44
|
-
return `${selectors.join(", ")} {`;
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
|
-
function applyScopeToElement(element, scopeId) {
|
|
48
|
-
if (typeof element === "string" || typeof element === "number" || !element) {
|
|
49
|
-
return element;
|
|
50
|
-
}
|
|
51
|
-
if (Array.isArray(element)) {
|
|
52
|
-
return element.map((item) => applyScopeToElement(item, scopeId));
|
|
53
|
-
}
|
|
54
|
-
if (typeof element === "object") {
|
|
55
|
-
const scoped = {};
|
|
56
|
-
for (const [tagName, props] of Object.entries(element)) {
|
|
57
|
-
if (typeof props === "object" && props !== null) {
|
|
58
|
-
const scopedProps = { ...props };
|
|
59
|
-
scopedProps[scopeId] = "";
|
|
60
|
-
if (scopedProps.children) {
|
|
61
|
-
scopedProps.children = applyScopeToElement(scopedProps.children, scopeId);
|
|
62
|
-
}
|
|
63
|
-
scoped[tagName] = scopedProps;
|
|
64
|
-
} else {
|
|
65
|
-
scoped[tagName] = props;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
return scoped;
|
|
69
|
-
}
|
|
70
|
-
return element;
|
|
71
|
-
}
|
|
72
|
-
function escapeHtml(text) {
|
|
73
|
-
if (typeof text !== "string") return text;
|
|
74
|
-
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
75
|
-
}
|
|
76
|
-
function isTrustedContent(value) {
|
|
77
|
-
return value && typeof value === "object" && value.__trusted === true && typeof value.__html === "string";
|
|
78
|
-
}
|
|
79
|
-
function isVoidElement(tagName) {
|
|
80
|
-
const voidElements = /* @__PURE__ */ new Set([
|
|
81
|
-
"area",
|
|
82
|
-
"base",
|
|
83
|
-
"br",
|
|
84
|
-
"col",
|
|
85
|
-
"embed",
|
|
86
|
-
"hr",
|
|
87
|
-
"img",
|
|
88
|
-
"input",
|
|
89
|
-
"link",
|
|
90
|
-
"meta",
|
|
91
|
-
"param",
|
|
92
|
-
"source",
|
|
93
|
-
"track",
|
|
94
|
-
"wbr"
|
|
95
|
-
]);
|
|
96
|
-
return voidElements.has(tagName.toLowerCase());
|
|
97
|
-
}
|
|
98
|
-
function formatAttributes(attrs) {
|
|
99
|
-
if (!attrs || typeof attrs !== "object") return "";
|
|
100
|
-
return Object.entries(attrs).filter(([, value]) => value !== null && value !== void 0 && value !== false).map(([key, value]) => {
|
|
101
|
-
if (typeof value === "function") {
|
|
102
|
-
value = value();
|
|
103
|
-
}
|
|
104
|
-
const attrName = key === "className" ? "class" : key;
|
|
105
|
-
if (value === true) return attrName;
|
|
106
|
-
return `${attrName}="${escapeHtml(String(value))}"`;
|
|
107
|
-
}).join(" ");
|
|
108
|
-
}
|
|
109
|
-
function renderRaw(obj) {
|
|
110
|
-
if (obj === null || obj === void 0) return "";
|
|
111
|
-
if (typeof obj === "string" || typeof obj === "number") return escapeHtml(String(obj));
|
|
112
|
-
if (Array.isArray(obj)) return obj.map(renderRaw).join("");
|
|
113
|
-
if (typeof obj === "function") {
|
|
114
|
-
const result = obj(renderRaw);
|
|
115
|
-
return renderRaw(result);
|
|
116
|
-
}
|
|
117
|
-
if (typeof obj !== "object") return escapeHtml(String(obj));
|
|
118
|
-
if (obj.text !== void 0) {
|
|
119
|
-
return escapeHtml(String(obj.text));
|
|
120
|
-
}
|
|
121
|
-
for (const [tagName, props] of Object.entries(obj)) {
|
|
122
|
-
if (typeof props === "object" && props !== null) {
|
|
123
|
-
const { children, text, ...attributes } = props;
|
|
124
|
-
const attrsStr = formatAttributes(attributes);
|
|
125
|
-
const openTag = attrsStr ? `<${tagName} ${attrsStr}>` : `<${tagName}>`;
|
|
126
|
-
if (isVoidElement(tagName)) {
|
|
127
|
-
return openTag.replace(">", " />");
|
|
128
|
-
}
|
|
129
|
-
let content = "";
|
|
130
|
-
if (text !== void 0) {
|
|
131
|
-
if (isTrustedContent(text)) {
|
|
132
|
-
content = text.__html;
|
|
133
|
-
} else {
|
|
134
|
-
content = escapeHtml(String(text));
|
|
135
|
-
}
|
|
136
|
-
} else if (children) {
|
|
137
|
-
content = renderRaw(children);
|
|
138
|
-
}
|
|
139
|
-
return `${openTag}${content}</${tagName}>`;
|
|
140
|
-
} else if (typeof props === "string") {
|
|
141
|
-
const content = isTrustedContent(props) ? props.__html : escapeHtml(props);
|
|
142
|
-
return isVoidElement(tagName) ? `<${tagName} />` : `<${tagName}>${content}</${tagName}>`;
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
return "";
|
|
146
|
-
}
|
|
147
|
-
function render(obj, options = {}) {
|
|
148
|
-
const { scoped = false } = options;
|
|
149
|
-
if (scoped) {
|
|
150
|
-
return renderScopedComponent(obj);
|
|
151
|
-
}
|
|
152
|
-
return renderRaw(obj);
|
|
153
|
-
}
|
|
154
|
-
function renderScopedComponent(component) {
|
|
155
|
-
const scopeId = generateScopeId();
|
|
156
|
-
function processScopedElement(element) {
|
|
157
|
-
if (!element || typeof element !== "object") {
|
|
158
|
-
return element;
|
|
159
|
-
}
|
|
160
|
-
if (Array.isArray(element)) {
|
|
161
|
-
return element.map(processScopedElement);
|
|
162
|
-
}
|
|
163
|
-
const result = {};
|
|
164
|
-
for (const [tagName, props] of Object.entries(element)) {
|
|
165
|
-
if (tagName === "style" && typeof props === "object" && props.text) {
|
|
166
|
-
result[tagName] = {
|
|
167
|
-
...props,
|
|
168
|
-
text: scopeCSS(props.text, scopeId)
|
|
169
|
-
};
|
|
170
|
-
} else if (typeof props === "object" && props !== null) {
|
|
171
|
-
const scopedProps = { ...props };
|
|
172
|
-
if (scopedProps.children) {
|
|
173
|
-
scopedProps.children = processScopedElement(scopedProps.children);
|
|
174
|
-
}
|
|
175
|
-
result[tagName] = scopedProps;
|
|
176
|
-
} else {
|
|
177
|
-
result[tagName] = props;
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
return result;
|
|
181
|
-
}
|
|
182
|
-
const processedComponent = processScopedElement(component);
|
|
183
|
-
const scopedComponent = applyScopeToElement(processedComponent, scopeId);
|
|
184
|
-
return renderRaw(scopedComponent);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
// src/index.js
|
|
27
|
+
var import_core = require("@coherent.js/core");
|
|
188
28
|
function expressEngine() {
|
|
189
29
|
return (filePath, options, callback) => {
|
|
190
30
|
try {
|
|
191
|
-
const html = render(options);
|
|
31
|
+
const html = (0, import_core.render)(options);
|
|
192
32
|
callback(null, html);
|
|
193
33
|
} catch (_error) {
|
|
194
34
|
callback(_error);
|
|
@@ -204,12 +44,4 @@ function setupCoherent(app) {
|
|
|
204
44
|
expressEngine,
|
|
205
45
|
setupCoherent
|
|
206
46
|
});
|
|
207
|
-
/**
|
|
208
|
-
* Coherent.js - Object-Based Rendering Framework
|
|
209
|
-
* A pure JavaScript framework for server-side rendering using natural object syntax
|
|
210
|
-
*
|
|
211
|
-
* @version 2.0.0
|
|
212
|
-
* @author Coherent Framework Team
|
|
213
|
-
* @license MIT
|
|
214
|
-
*/
|
|
215
47
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../src/index.js"
|
|
4
|
-
"sourcesContent": ["// src/express/index.js\nimport { render } from '../../core/src/index.js';\n\nexport function expressEngine() {\n return (filePath, options, callback) => {\n try {\n // options contains the Coherent object structure\n const html = render(options);\n callback(null, html);\n } catch (_error) {\n callback(_error);\n }\n };\n}\n\n// Helper for Express apps\nexport function setupCoherent(app) {\n app.engine('coherent', expressEngine());\n app.set('view engine', 'coherent');\n}\n", "/**\n * Coherent.js - Object-Based Rendering Framework\n * A pure JavaScript framework for server-side rendering using natural object syntax\n *\n * @version 2.0.0\n * @author Coherent Framework Team\n * @license MIT\n */\n\n// Performance monitoring\nimport { performanceMonitor } from './performance/monitor.js';\n\n// Component system imports\nimport {\n withState,\n withStateUtils,\n createStateManager,\n createComponent,\n defineComponent,\n registerComponent,\n getComponent,\n getRegisteredComponents,\n lazy,\n isLazy,\n evaluateLazy\n} from './components/component-system.js';\n\n// Component lifecycle imports\nimport {\n ComponentLifecycle,\n LIFECYCLE_PHASES,\n withLifecycle,\n createLifecycleHooks,\n useHooks,\n componentUtils as lifecycleUtils\n} from './components/lifecycle.js';\n\n// Object factory imports\nimport {\n createElement,\n createTextNode,\n h\n} from './core/object-factory.js';\n\n// Component cache imports\nimport {\n ComponentCache,\n createComponentCache,\n memoize\n} from './performance/component-cache.js';\n\n// Error boundary imports\nimport {\n createErrorBoundary,\n createErrorFallback,\n withErrorBoundary,\n createAsyncErrorBoundary,\n GlobalErrorHandler,\n createGlobalErrorHandler\n} from './components/error-boundary.js';\n\n// CSS Scoping System (similar to Angular View Encapsulation)\nconst scopeCounter = { value: 0 };\n\nfunction generateScopeId() {\n return `coh-${scopeCounter.value++}`;\n}\n\nfunction scopeCSS(css, scopeId) {\n if (!css || typeof css !== 'string') return css;\n\n // Add scope attribute to all selectors\n return css\n .replace(/([^{}]*)\\s*{/g, (match, selector) => {\n // Handle multiple selectors separated by commas\n const selectors = selector.split(',').map(s => {\n const trimmed = s.trim();\n if (!trimmed) return s;\n\n // Handle pseudo-selectors and complex selectors\n if (trimmed.includes(':')) {\n return trimmed.replace(/([^:]+)(:.*)?/, `$1[${scopeId}]$2`);\n }\n\n // Simple selector scoping\n return `${trimmed}[${scopeId}]`;\n });\n\n return `${selectors.join(', ')} {`;\n });\n}\n\nfunction applyScopeToElement(element, scopeId) {\n if (typeof element === 'string' || typeof element === 'number' || !element) {\n return element;\n }\n\n if (Array.isArray(element)) {\n return element.map(item => applyScopeToElement(item, scopeId));\n }\n\n if (typeof element === 'object') {\n const scoped = {};\n\n for (const [tagName, props] of Object.entries(element)) {\n if (typeof props === 'object' && props !== null) {\n const scopedProps = { ...props };\n\n // Add scope attribute to the element\n scopedProps[scopeId] = '';\n\n // Recursively scope children\n if (scopedProps.children) {\n scopedProps.children = applyScopeToElement(scopedProps.children, scopeId);\n }\n\n scoped[tagName] = scopedProps;\n } else {\n // For simple text content elements, keep them as is\n // Don't add scope attributes to text-only elements\n scoped[tagName] = props;\n }\n }\n\n return scoped;\n }\n\n return element;\n}\n\n// Core HTML utilities\nfunction escapeHtml(text) {\n if (typeof text !== 'string') return text;\n return text\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''');\n}\n\n/**\n * Mark content as safe/trusted to skip HTML escaping\n * USE WITH EXTREME CAUTION - only for developer-controlled content\n * NEVER use with user input!\n *\n * @param {string} content - Trusted content (e.g., inline scripts/styles)\n * @returns {Object} Marked safe content\n */\nexport function dangerouslySetInnerContent(content) {\n return {\n __html: content,\n __trusted: true\n };\n}\n\n/**\n * Check if content is marked as safe\n */\nfunction isTrustedContent(value) {\n return value && typeof value === 'object' && value.__trusted === true && typeof value.__html === 'string';\n}\n\nfunction isVoidElement(tagName) {\n const voidElements = new Set([\n 'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input',\n 'link', 'meta', 'param', 'source', 'track', 'wbr'\n ]);\n return voidElements.has(tagName.toLowerCase());\n}\n\nfunction formatAttributes(attrs) {\n if (!attrs || typeof attrs !== 'object') return '';\n\n return Object.entries(attrs)\n .filter(([, value]) => value !== null && value !== undefined && value !== false)\n .map(([key, value]) => {\n // Execute functions to get the actual value\n if (typeof value === 'function') {\n value = value();\n }\n\n // Convert className to class\n const attrName = key === 'className' ? 'class' : key;\n if (value === true) return attrName;\n return `${attrName}=\"${escapeHtml(String(value))}\"`;\n })\n .join(' ');\n}\n\n// Internal raw rendering (no encapsulation) - used by scoped renderer\nfunction renderRaw(obj) {\n if (obj === null || obj === undefined) return '';\n if (typeof obj === 'string' || typeof obj === 'number') return escapeHtml(String(obj));\n if (Array.isArray(obj)) return obj.map(renderRaw).join('');\n\n // Handle functions (like context providers)\n if (typeof obj === 'function') {\n const result = obj(renderRaw);\n return renderRaw(result);\n }\n\n if (typeof obj !== 'object') return escapeHtml(String(obj));\n\n // Handle text content\n if (obj.text !== undefined) {\n return escapeHtml(String(obj.text));\n }\n\n // Handle HTML elements\n for (const [tagName, props] of Object.entries(obj)) {\n if (typeof props === 'object' && props !== null) {\n const { children, text, ...attributes } = props;\n const attrsStr = formatAttributes(attributes);\n const openTag = attrsStr ? `<${tagName} ${attrsStr}>` : `<${tagName}>`;\n\n if (isVoidElement(tagName)) {\n return openTag.replace('>', ' />');\n }\n\n let content = '';\n if (text !== undefined) {\n // Check if content is explicitly marked as trusted\n if (isTrustedContent(text)) {\n content = text.__html;\n } else {\n content = escapeHtml(String(text));\n }\n } else if (children) {\n content = renderRaw(children);\n }\n\n return `${openTag}${content}</${tagName}>`;\n } else if (typeof props === 'string') {\n // Simple text content - always escape unless explicitly marked as trusted\n const content = isTrustedContent(props) ? props.__html : escapeHtml(props);\n return isVoidElement(tagName) ? `<${tagName} />` : `<${tagName}>${content}</${tagName}>`;\n }\n }\n\n return '';\n}\n\n// Main rendering function\nexport function render(obj, options = {}) {\n const { scoped = false } = options;\n\n // Scoped mode - use CSS encapsulation\n if (scoped) {\n return renderScopedComponent(obj);\n }\n\n // Default: unscoped rendering\n return renderRaw(obj);\n}\n\n// Internal: Scoped rendering with CSS encapsulation\nfunction renderScopedComponent(component) {\n const scopeId = generateScopeId();\n\n // Handle style elements specially\n function processScopedElement(element) {\n if (!element || typeof element !== 'object') {\n return element;\n }\n\n if (Array.isArray(element)) {\n return element.map(processScopedElement);\n }\n\n const result = {};\n\n for (const [tagName, props] of Object.entries(element)) {\n if (tagName === 'style' && typeof props === 'object' && props.text) {\n // Scope CSS within style tags\n result[tagName] = {\n ...props,\n text: scopeCSS(props.text, scopeId)\n };\n } else if (typeof props === 'object' && props !== null) {\n // Recursively process children\n const scopedProps = { ...props };\n if (scopedProps.children) {\n scopedProps.children = processScopedElement(scopedProps.children);\n }\n result[tagName] = scopedProps;\n } else {\n result[tagName] = props;\n }\n }\n\n return result;\n }\n\n // First process styles, then apply scope attributes\n const processedComponent = processScopedElement(component);\n const scopedComponent = applyScopeToElement(processedComponent, scopeId);\n\n return renderRaw(scopedComponent);\n}\n\n// Component system - Re-export from component-system for unified API\nexport {\n withState,\n withStateUtils,\n createStateManager,\n createComponent,\n defineComponent,\n registerComponent,\n getComponent,\n getRegisteredComponents,\n lazy,\n isLazy,\n evaluateLazy\n} from './components/component-system.js';\n\n// Component lifecycle exports\nexport {\n ComponentLifecycle,\n LIFECYCLE_PHASES,\n withLifecycle,\n createLifecycleHooks,\n useHooks,\n componentUtils as lifecycleUtils\n} from './components/lifecycle.js';\n\n// Object factory exports\nexport {\n createElement,\n createTextNode,\n h\n} from './core/object-factory.js';\n\n// Component cache exports\nexport {\n ComponentCache,\n createComponentCache,\n memoize\n} from './performance/component-cache.js';\n\n// Error boundaries\nexport {\n createErrorBoundary,\n createErrorFallback,\n withErrorBoundary,\n createAsyncErrorBoundary,\n GlobalErrorHandler,\n createGlobalErrorHandler\n} from './components/error-boundary.js';\n\n// Simple memoization\nconst memoCache = new Map();\n\nexport function memo(component, keyGenerator) {\n return function MemoizedComponent(props = {}) {\n const key = keyGenerator ? keyGenerator(props) : JSON.stringify(props);\n\n if (memoCache.has(key)) {\n return memoCache.get(key);\n }\n\n const result = component(props);\n memoCache.set(key, result);\n\n // Simple cache cleanup - keep only last 100 items\n if (memoCache.size > 100) {\n const firstKey = memoCache.keys().next().value;\n memoCache.delete(firstKey);\n }\n\n return result;\n };\n}\n\n// Utility functions\nexport function validateComponent(obj) {\n if (!obj || typeof obj !== 'object') {\n throw new Error('Component must be an object');\n }\n return true;\n}\n\nexport function isCoherentObject(obj) {\n return obj && typeof obj === 'object' && !Array.isArray(obj);\n}\n\nexport function deepClone(obj) {\n if (obj === null || typeof obj !== 'object') return obj;\n if (obj instanceof Date) return new Date(obj);\n if (Array.isArray(obj)) return obj.map(deepClone);\n\n const cloned = {};\n for (const [key, value] of Object.entries(obj)) {\n cloned[key] = deepClone(value);\n }\n return cloned;\n}\n\n// Version info\nexport const VERSION = '2.0.0';\n\n// Performance monitoring export\nexport { performanceMonitor };\n\n// Shadow DOM exports\nexport { shadowDOM };\n\n// Import Shadow DOM functionality\nimport * as shadowDOM from './shadow-dom.js';\n\n// Event system imports and exports\nimport eventSystemDefault, {\n EventBus,\n createEventBus,\n globalEventBus,\n emit,\n emitSync,\n on,\n once,\n off,\n registerAction,\n handleAction,\n DOMEventIntegration,\n globalDOMIntegration,\n initializeDOMIntegration,\n withEventBus,\n withEventState,\n createActionHandlers,\n createEventHandlers,\n createEventComponent\n} from './events/index.js';\n\nexport {\n eventSystemDefault as eventSystem,\n EventBus,\n createEventBus,\n globalEventBus,\n emit,\n emitSync,\n on,\n once,\n off,\n registerAction,\n handleAction,\n DOMEventIntegration,\n globalDOMIntegration,\n initializeDOMIntegration,\n withEventBus,\n withEventState,\n createActionHandlers,\n createEventHandlers,\n createEventComponent\n};\n\n// Note: Forms have been moved to @coherent.js/forms package\n\n// Default export\nconst coherent = {\n // Core rendering\n render,\n\n // Shadow DOM (client-side only)\n shadowDOM,\n\n // Component system\n createComponent,\n defineComponent,\n registerComponent,\n getComponent,\n getRegisteredComponents,\n lazy,\n isLazy,\n evaluateLazy,\n\n // Component lifecycle\n ComponentLifecycle,\n LIFECYCLE_PHASES,\n withLifecycle,\n createLifecycleHooks,\n useHooks,\n lifecycleUtils,\n\n // Object factory\n createElement,\n createTextNode,\n h,\n\n // Component cache\n ComponentCache,\n createComponentCache,\n memoize,\n\n // State management\n withState,\n withStateUtils,\n createStateManager,\n memo,\n\n // Error boundaries\n createErrorBoundary,\n createErrorFallback,\n withErrorBoundary,\n createAsyncErrorBoundary,\n GlobalErrorHandler,\n createGlobalErrorHandler,\n\n // Event system\n eventSystem: eventSystemDefault,\n emit,\n emitSync,\n on,\n once,\n off,\n registerAction,\n handleAction,\n withEventBus,\n withEventState,\n\n // Utilities\n validateComponent,\n isCoherentObject,\n deepClone,\n escapeHtml,\n performanceMonitor,\n VERSION\n};\n\nexport default coherent;\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA
|
|
3
|
+
"sources": ["../src/index.js"],
|
|
4
|
+
"sourcesContent": ["// src/express/index.js\nimport { render } from '@coherent.js/core';\n\nexport function expressEngine() {\n return (filePath, options, callback) => {\n try {\n // options contains the Coherent object structure\n const html = render(options);\n callback(null, html);\n } catch (_error) {\n callback(_error);\n }\n };\n}\n\n// Helper for Express apps\nexport function setupCoherent(app) {\n app.engine('coherent', expressEngine());\n app.set('view engine', 'coherent');\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,kBAAuB;AAEhB,SAAS,gBAAgB;AAC5B,SAAO,CAAC,UAAU,SAAS,aAAa;AACpC,QAAI;AAEA,YAAM,WAAO,oBAAO,OAAO;AAC3B,eAAS,MAAM,IAAI;AAAA,IACvB,SAAS,QAAQ;AACb,eAAS,MAAM;AAAA,IACnB;AAAA,EACJ;AACJ;AAGO,SAAS,cAAc,KAAK;AAC/B,MAAI,OAAO,YAAY,cAAc,CAAC;AACtC,MAAI,IAAI,eAAe,UAAU;AACrC;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/index.js
CHANGED
|
@@ -1,163 +1,5 @@
|
|
|
1
|
-
// ../core/src/index.js
|
|
2
|
-
var scopeCounter = { value: 0 };
|
|
3
|
-
function generateScopeId() {
|
|
4
|
-
return `coh-${scopeCounter.value++}`;
|
|
5
|
-
}
|
|
6
|
-
function scopeCSS(css, scopeId) {
|
|
7
|
-
if (!css || typeof css !== "string") return css;
|
|
8
|
-
return css.replace(/([^{}]*)\s*{/g, (match, selector) => {
|
|
9
|
-
const selectors = selector.split(",").map((s) => {
|
|
10
|
-
const trimmed = s.trim();
|
|
11
|
-
if (!trimmed) return s;
|
|
12
|
-
if (trimmed.includes(":")) {
|
|
13
|
-
return trimmed.replace(/([^:]+)(:.*)?/, `$1[${scopeId}]$2`);
|
|
14
|
-
}
|
|
15
|
-
return `${trimmed}[${scopeId}]`;
|
|
16
|
-
});
|
|
17
|
-
return `${selectors.join(", ")} {`;
|
|
18
|
-
});
|
|
19
|
-
}
|
|
20
|
-
function applyScopeToElement(element, scopeId) {
|
|
21
|
-
if (typeof element === "string" || typeof element === "number" || !element) {
|
|
22
|
-
return element;
|
|
23
|
-
}
|
|
24
|
-
if (Array.isArray(element)) {
|
|
25
|
-
return element.map((item) => applyScopeToElement(item, scopeId));
|
|
26
|
-
}
|
|
27
|
-
if (typeof element === "object") {
|
|
28
|
-
const scoped = {};
|
|
29
|
-
for (const [tagName, props] of Object.entries(element)) {
|
|
30
|
-
if (typeof props === "object" && props !== null) {
|
|
31
|
-
const scopedProps = { ...props };
|
|
32
|
-
scopedProps[scopeId] = "";
|
|
33
|
-
if (scopedProps.children) {
|
|
34
|
-
scopedProps.children = applyScopeToElement(scopedProps.children, scopeId);
|
|
35
|
-
}
|
|
36
|
-
scoped[tagName] = scopedProps;
|
|
37
|
-
} else {
|
|
38
|
-
scoped[tagName] = props;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
return scoped;
|
|
42
|
-
}
|
|
43
|
-
return element;
|
|
44
|
-
}
|
|
45
|
-
function escapeHtml(text) {
|
|
46
|
-
if (typeof text !== "string") return text;
|
|
47
|
-
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
48
|
-
}
|
|
49
|
-
function isTrustedContent(value) {
|
|
50
|
-
return value && typeof value === "object" && value.__trusted === true && typeof value.__html === "string";
|
|
51
|
-
}
|
|
52
|
-
function isVoidElement(tagName) {
|
|
53
|
-
const voidElements = /* @__PURE__ */ new Set([
|
|
54
|
-
"area",
|
|
55
|
-
"base",
|
|
56
|
-
"br",
|
|
57
|
-
"col",
|
|
58
|
-
"embed",
|
|
59
|
-
"hr",
|
|
60
|
-
"img",
|
|
61
|
-
"input",
|
|
62
|
-
"link",
|
|
63
|
-
"meta",
|
|
64
|
-
"param",
|
|
65
|
-
"source",
|
|
66
|
-
"track",
|
|
67
|
-
"wbr"
|
|
68
|
-
]);
|
|
69
|
-
return voidElements.has(tagName.toLowerCase());
|
|
70
|
-
}
|
|
71
|
-
function formatAttributes(attrs) {
|
|
72
|
-
if (!attrs || typeof attrs !== "object") return "";
|
|
73
|
-
return Object.entries(attrs).filter(([, value]) => value !== null && value !== void 0 && value !== false).map(([key, value]) => {
|
|
74
|
-
if (typeof value === "function") {
|
|
75
|
-
value = value();
|
|
76
|
-
}
|
|
77
|
-
const attrName = key === "className" ? "class" : key;
|
|
78
|
-
if (value === true) return attrName;
|
|
79
|
-
return `${attrName}="${escapeHtml(String(value))}"`;
|
|
80
|
-
}).join(" ");
|
|
81
|
-
}
|
|
82
|
-
function renderRaw(obj) {
|
|
83
|
-
if (obj === null || obj === void 0) return "";
|
|
84
|
-
if (typeof obj === "string" || typeof obj === "number") return escapeHtml(String(obj));
|
|
85
|
-
if (Array.isArray(obj)) return obj.map(renderRaw).join("");
|
|
86
|
-
if (typeof obj === "function") {
|
|
87
|
-
const result = obj(renderRaw);
|
|
88
|
-
return renderRaw(result);
|
|
89
|
-
}
|
|
90
|
-
if (typeof obj !== "object") return escapeHtml(String(obj));
|
|
91
|
-
if (obj.text !== void 0) {
|
|
92
|
-
return escapeHtml(String(obj.text));
|
|
93
|
-
}
|
|
94
|
-
for (const [tagName, props] of Object.entries(obj)) {
|
|
95
|
-
if (typeof props === "object" && props !== null) {
|
|
96
|
-
const { children, text, ...attributes } = props;
|
|
97
|
-
const attrsStr = formatAttributes(attributes);
|
|
98
|
-
const openTag = attrsStr ? `<${tagName} ${attrsStr}>` : `<${tagName}>`;
|
|
99
|
-
if (isVoidElement(tagName)) {
|
|
100
|
-
return openTag.replace(">", " />");
|
|
101
|
-
}
|
|
102
|
-
let content = "";
|
|
103
|
-
if (text !== void 0) {
|
|
104
|
-
if (isTrustedContent(text)) {
|
|
105
|
-
content = text.__html;
|
|
106
|
-
} else {
|
|
107
|
-
content = escapeHtml(String(text));
|
|
108
|
-
}
|
|
109
|
-
} else if (children) {
|
|
110
|
-
content = renderRaw(children);
|
|
111
|
-
}
|
|
112
|
-
return `${openTag}${content}</${tagName}>`;
|
|
113
|
-
} else if (typeof props === "string") {
|
|
114
|
-
const content = isTrustedContent(props) ? props.__html : escapeHtml(props);
|
|
115
|
-
return isVoidElement(tagName) ? `<${tagName} />` : `<${tagName}>${content}</${tagName}>`;
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
return "";
|
|
119
|
-
}
|
|
120
|
-
function render(obj, options = {}) {
|
|
121
|
-
const { scoped = false } = options;
|
|
122
|
-
if (scoped) {
|
|
123
|
-
return renderScopedComponent(obj);
|
|
124
|
-
}
|
|
125
|
-
return renderRaw(obj);
|
|
126
|
-
}
|
|
127
|
-
function renderScopedComponent(component) {
|
|
128
|
-
const scopeId = generateScopeId();
|
|
129
|
-
function processScopedElement(element) {
|
|
130
|
-
if (!element || typeof element !== "object") {
|
|
131
|
-
return element;
|
|
132
|
-
}
|
|
133
|
-
if (Array.isArray(element)) {
|
|
134
|
-
return element.map(processScopedElement);
|
|
135
|
-
}
|
|
136
|
-
const result = {};
|
|
137
|
-
for (const [tagName, props] of Object.entries(element)) {
|
|
138
|
-
if (tagName === "style" && typeof props === "object" && props.text) {
|
|
139
|
-
result[tagName] = {
|
|
140
|
-
...props,
|
|
141
|
-
text: scopeCSS(props.text, scopeId)
|
|
142
|
-
};
|
|
143
|
-
} else if (typeof props === "object" && props !== null) {
|
|
144
|
-
const scopedProps = { ...props };
|
|
145
|
-
if (scopedProps.children) {
|
|
146
|
-
scopedProps.children = processScopedElement(scopedProps.children);
|
|
147
|
-
}
|
|
148
|
-
result[tagName] = scopedProps;
|
|
149
|
-
} else {
|
|
150
|
-
result[tagName] = props;
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
return result;
|
|
154
|
-
}
|
|
155
|
-
const processedComponent = processScopedElement(component);
|
|
156
|
-
const scopedComponent = applyScopeToElement(processedComponent, scopeId);
|
|
157
|
-
return renderRaw(scopedComponent);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
1
|
// src/index.js
|
|
2
|
+
import { render } from "@coherent.js/core";
|
|
161
3
|
function expressEngine() {
|
|
162
4
|
return (filePath, options, callback) => {
|
|
163
5
|
try {
|
|
@@ -176,12 +18,4 @@ export {
|
|
|
176
18
|
expressEngine,
|
|
177
19
|
setupCoherent
|
|
178
20
|
};
|
|
179
|
-
/**
|
|
180
|
-
* Coherent.js - Object-Based Rendering Framework
|
|
181
|
-
* A pure JavaScript framework for server-side rendering using natural object syntax
|
|
182
|
-
*
|
|
183
|
-
* @version 2.0.0
|
|
184
|
-
* @author Coherent Framework Team
|
|
185
|
-
* @license MIT
|
|
186
|
-
*/
|
|
187
21
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["
|
|
4
|
-
"sourcesContent": ["/**\n * Coherent.js - Object-Based Rendering Framework\n * A pure JavaScript framework for server-side rendering using natural object syntax\n *\n * @version 2.0.0\n * @author Coherent Framework Team\n * @license MIT\n */\n\n// Performance monitoring\nimport { performanceMonitor } from './performance/monitor.js';\n\n// Component system imports\nimport {\n withState,\n withStateUtils,\n createStateManager,\n createComponent,\n defineComponent,\n registerComponent,\n getComponent,\n getRegisteredComponents,\n lazy,\n isLazy,\n evaluateLazy\n} from './components/component-system.js';\n\n// Component lifecycle imports\nimport {\n ComponentLifecycle,\n LIFECYCLE_PHASES,\n withLifecycle,\n createLifecycleHooks,\n useHooks,\n componentUtils as lifecycleUtils\n} from './components/lifecycle.js';\n\n// Object factory imports\nimport {\n createElement,\n createTextNode,\n h\n} from './core/object-factory.js';\n\n// Component cache imports\nimport {\n ComponentCache,\n createComponentCache,\n memoize\n} from './performance/component-cache.js';\n\n// Error boundary imports\nimport {\n createErrorBoundary,\n createErrorFallback,\n withErrorBoundary,\n createAsyncErrorBoundary,\n GlobalErrorHandler,\n createGlobalErrorHandler\n} from './components/error-boundary.js';\n\n// CSS Scoping System (similar to Angular View Encapsulation)\nconst scopeCounter = { value: 0 };\n\nfunction generateScopeId() {\n return `coh-${scopeCounter.value++}`;\n}\n\nfunction scopeCSS(css, scopeId) {\n if (!css || typeof css !== 'string') return css;\n\n // Add scope attribute to all selectors\n return css\n .replace(/([^{}]*)\\s*{/g, (match, selector) => {\n // Handle multiple selectors separated by commas\n const selectors = selector.split(',').map(s => {\n const trimmed = s.trim();\n if (!trimmed) return s;\n\n // Handle pseudo-selectors and complex selectors\n if (trimmed.includes(':')) {\n return trimmed.replace(/([^:]+)(:.*)?/, `$1[${scopeId}]$2`);\n }\n\n // Simple selector scoping\n return `${trimmed}[${scopeId}]`;\n });\n\n return `${selectors.join(', ')} {`;\n });\n}\n\nfunction applyScopeToElement(element, scopeId) {\n if (typeof element === 'string' || typeof element === 'number' || !element) {\n return element;\n }\n\n if (Array.isArray(element)) {\n return element.map(item => applyScopeToElement(item, scopeId));\n }\n\n if (typeof element === 'object') {\n const scoped = {};\n\n for (const [tagName, props] of Object.entries(element)) {\n if (typeof props === 'object' && props !== null) {\n const scopedProps = { ...props };\n\n // Add scope attribute to the element\n scopedProps[scopeId] = '';\n\n // Recursively scope children\n if (scopedProps.children) {\n scopedProps.children = applyScopeToElement(scopedProps.children, scopeId);\n }\n\n scoped[tagName] = scopedProps;\n } else {\n // For simple text content elements, keep them as is\n // Don't add scope attributes to text-only elements\n scoped[tagName] = props;\n }\n }\n\n return scoped;\n }\n\n return element;\n}\n\n// Core HTML utilities\nfunction escapeHtml(text) {\n if (typeof text !== 'string') return text;\n return text\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''');\n}\n\n/**\n * Mark content as safe/trusted to skip HTML escaping\n * USE WITH EXTREME CAUTION - only for developer-controlled content\n * NEVER use with user input!\n *\n * @param {string} content - Trusted content (e.g., inline scripts/styles)\n * @returns {Object} Marked safe content\n */\nexport function dangerouslySetInnerContent(content) {\n return {\n __html: content,\n __trusted: true\n };\n}\n\n/**\n * Check if content is marked as safe\n */\nfunction isTrustedContent(value) {\n return value && typeof value === 'object' && value.__trusted === true && typeof value.__html === 'string';\n}\n\nfunction isVoidElement(tagName) {\n const voidElements = new Set([\n 'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input',\n 'link', 'meta', 'param', 'source', 'track', 'wbr'\n ]);\n return voidElements.has(tagName.toLowerCase());\n}\n\nfunction formatAttributes(attrs) {\n if (!attrs || typeof attrs !== 'object') return '';\n\n return Object.entries(attrs)\n .filter(([, value]) => value !== null && value !== undefined && value !== false)\n .map(([key, value]) => {\n // Execute functions to get the actual value\n if (typeof value === 'function') {\n value = value();\n }\n\n // Convert className to class\n const attrName = key === 'className' ? 'class' : key;\n if (value === true) return attrName;\n return `${attrName}=\"${escapeHtml(String(value))}\"`;\n })\n .join(' ');\n}\n\n// Internal raw rendering (no encapsulation) - used by scoped renderer\nfunction renderRaw(obj) {\n if (obj === null || obj === undefined) return '';\n if (typeof obj === 'string' || typeof obj === 'number') return escapeHtml(String(obj));\n if (Array.isArray(obj)) return obj.map(renderRaw).join('');\n\n // Handle functions (like context providers)\n if (typeof obj === 'function') {\n const result = obj(renderRaw);\n return renderRaw(result);\n }\n\n if (typeof obj !== 'object') return escapeHtml(String(obj));\n\n // Handle text content\n if (obj.text !== undefined) {\n return escapeHtml(String(obj.text));\n }\n\n // Handle HTML elements\n for (const [tagName, props] of Object.entries(obj)) {\n if (typeof props === 'object' && props !== null) {\n const { children, text, ...attributes } = props;\n const attrsStr = formatAttributes(attributes);\n const openTag = attrsStr ? `<${tagName} ${attrsStr}>` : `<${tagName}>`;\n\n if (isVoidElement(tagName)) {\n return openTag.replace('>', ' />');\n }\n\n let content = '';\n if (text !== undefined) {\n // Check if content is explicitly marked as trusted\n if (isTrustedContent(text)) {\n content = text.__html;\n } else {\n content = escapeHtml(String(text));\n }\n } else if (children) {\n content = renderRaw(children);\n }\n\n return `${openTag}${content}</${tagName}>`;\n } else if (typeof props === 'string') {\n // Simple text content - always escape unless explicitly marked as trusted\n const content = isTrustedContent(props) ? props.__html : escapeHtml(props);\n return isVoidElement(tagName) ? `<${tagName} />` : `<${tagName}>${content}</${tagName}>`;\n }\n }\n\n return '';\n}\n\n// Main rendering function\nexport function render(obj, options = {}) {\n const { scoped = false } = options;\n\n // Scoped mode - use CSS encapsulation\n if (scoped) {\n return renderScopedComponent(obj);\n }\n\n // Default: unscoped rendering\n return renderRaw(obj);\n}\n\n// Internal: Scoped rendering with CSS encapsulation\nfunction renderScopedComponent(component) {\n const scopeId = generateScopeId();\n\n // Handle style elements specially\n function processScopedElement(element) {\n if (!element || typeof element !== 'object') {\n return element;\n }\n\n if (Array.isArray(element)) {\n return element.map(processScopedElement);\n }\n\n const result = {};\n\n for (const [tagName, props] of Object.entries(element)) {\n if (tagName === 'style' && typeof props === 'object' && props.text) {\n // Scope CSS within style tags\n result[tagName] = {\n ...props,\n text: scopeCSS(props.text, scopeId)\n };\n } else if (typeof props === 'object' && props !== null) {\n // Recursively process children\n const scopedProps = { ...props };\n if (scopedProps.children) {\n scopedProps.children = processScopedElement(scopedProps.children);\n }\n result[tagName] = scopedProps;\n } else {\n result[tagName] = props;\n }\n }\n\n return result;\n }\n\n // First process styles, then apply scope attributes\n const processedComponent = processScopedElement(component);\n const scopedComponent = applyScopeToElement(processedComponent, scopeId);\n\n return renderRaw(scopedComponent);\n}\n\n// Component system - Re-export from component-system for unified API\nexport {\n withState,\n withStateUtils,\n createStateManager,\n createComponent,\n defineComponent,\n registerComponent,\n getComponent,\n getRegisteredComponents,\n lazy,\n isLazy,\n evaluateLazy\n} from './components/component-system.js';\n\n// Component lifecycle exports\nexport {\n ComponentLifecycle,\n LIFECYCLE_PHASES,\n withLifecycle,\n createLifecycleHooks,\n useHooks,\n componentUtils as lifecycleUtils\n} from './components/lifecycle.js';\n\n// Object factory exports\nexport {\n createElement,\n createTextNode,\n h\n} from './core/object-factory.js';\n\n// Component cache exports\nexport {\n ComponentCache,\n createComponentCache,\n memoize\n} from './performance/component-cache.js';\n\n// Error boundaries\nexport {\n createErrorBoundary,\n createErrorFallback,\n withErrorBoundary,\n createAsyncErrorBoundary,\n GlobalErrorHandler,\n createGlobalErrorHandler\n} from './components/error-boundary.js';\n\n// Simple memoization\nconst memoCache = new Map();\n\nexport function memo(component, keyGenerator) {\n return function MemoizedComponent(props = {}) {\n const key = keyGenerator ? keyGenerator(props) : JSON.stringify(props);\n\n if (memoCache.has(key)) {\n return memoCache.get(key);\n }\n\n const result = component(props);\n memoCache.set(key, result);\n\n // Simple cache cleanup - keep only last 100 items\n if (memoCache.size > 100) {\n const firstKey = memoCache.keys().next().value;\n memoCache.delete(firstKey);\n }\n\n return result;\n };\n}\n\n// Utility functions\nexport function validateComponent(obj) {\n if (!obj || typeof obj !== 'object') {\n throw new Error('Component must be an object');\n }\n return true;\n}\n\nexport function isCoherentObject(obj) {\n return obj && typeof obj === 'object' && !Array.isArray(obj);\n}\n\nexport function deepClone(obj) {\n if (obj === null || typeof obj !== 'object') return obj;\n if (obj instanceof Date) return new Date(obj);\n if (Array.isArray(obj)) return obj.map(deepClone);\n\n const cloned = {};\n for (const [key, value] of Object.entries(obj)) {\n cloned[key] = deepClone(value);\n }\n return cloned;\n}\n\n// Version info\nexport const VERSION = '2.0.0';\n\n// Performance monitoring export\nexport { performanceMonitor };\n\n// Shadow DOM exports\nexport { shadowDOM };\n\n// Import Shadow DOM functionality\nimport * as shadowDOM from './shadow-dom.js';\n\n// Event system imports and exports\nimport eventSystemDefault, {\n EventBus,\n createEventBus,\n globalEventBus,\n emit,\n emitSync,\n on,\n once,\n off,\n registerAction,\n handleAction,\n DOMEventIntegration,\n globalDOMIntegration,\n initializeDOMIntegration,\n withEventBus,\n withEventState,\n createActionHandlers,\n createEventHandlers,\n createEventComponent\n} from './events/index.js';\n\nexport {\n eventSystemDefault as eventSystem,\n EventBus,\n createEventBus,\n globalEventBus,\n emit,\n emitSync,\n on,\n once,\n off,\n registerAction,\n handleAction,\n DOMEventIntegration,\n globalDOMIntegration,\n initializeDOMIntegration,\n withEventBus,\n withEventState,\n createActionHandlers,\n createEventHandlers,\n createEventComponent\n};\n\n// Note: Forms have been moved to @coherent.js/forms package\n\n// Default export\nconst coherent = {\n // Core rendering\n render,\n\n // Shadow DOM (client-side only)\n shadowDOM,\n\n // Component system\n createComponent,\n defineComponent,\n registerComponent,\n getComponent,\n getRegisteredComponents,\n lazy,\n isLazy,\n evaluateLazy,\n\n // Component lifecycle\n ComponentLifecycle,\n LIFECYCLE_PHASES,\n withLifecycle,\n createLifecycleHooks,\n useHooks,\n lifecycleUtils,\n\n // Object factory\n createElement,\n createTextNode,\n h,\n\n // Component cache\n ComponentCache,\n createComponentCache,\n memoize,\n\n // State management\n withState,\n withStateUtils,\n createStateManager,\n memo,\n\n // Error boundaries\n createErrorBoundary,\n createErrorFallback,\n withErrorBoundary,\n createAsyncErrorBoundary,\n GlobalErrorHandler,\n createGlobalErrorHandler,\n\n // Event system\n eventSystem: eventSystemDefault,\n emit,\n emitSync,\n on,\n once,\n off,\n registerAction,\n handleAction,\n withEventBus,\n withEventState,\n\n // Utilities\n validateComponent,\n isCoherentObject,\n deepClone,\n escapeHtml,\n performanceMonitor,\n VERSION\n};\n\nexport default coherent;\n", "// src/express/index.js\nimport { render } from '../../core/src/index.js';\n\nexport function expressEngine() {\n return (filePath, options, callback) => {\n try {\n // options contains the Coherent object structure\n const html = render(options);\n callback(null, html);\n } catch (_error) {\n callback(_error);\n }\n };\n}\n\n// Helper for Express apps\nexport function setupCoherent(app) {\n app.engine('coherent', expressEngine());\n app.set('view engine', 'coherent');\n}\n"],
|
|
5
|
-
"mappings": ";
|
|
3
|
+
"sources": ["../src/index.js"],
|
|
4
|
+
"sourcesContent": ["// src/express/index.js\nimport { render } from '@coherent.js/core';\n\nexport function expressEngine() {\n return (filePath, options, callback) => {\n try {\n // options contains the Coherent object structure\n const html = render(options);\n callback(null, html);\n } catch (_error) {\n callback(_error);\n }\n };\n}\n\n// Helper for Express apps\nexport function setupCoherent(app) {\n app.engine('coherent', expressEngine());\n app.set('view engine', 'coherent');\n}\n"],
|
|
5
|
+
"mappings": ";AACA,SAAS,cAAc;AAEhB,SAAS,gBAAgB;AAC5B,SAAO,CAAC,UAAU,SAAS,aAAa;AACpC,QAAI;AAEA,YAAM,OAAO,OAAO,OAAO;AAC3B,eAAS,MAAM,IAAI;AAAA,IACvB,SAAS,QAAQ;AACb,eAAS,MAAM;AAAA,IACnB;AAAA,EACJ;AACJ;AAGO,SAAS,cAAc,KAAK;AAC/B,MAAI,OAAO,YAAY,cAAc,CAAC;AACtC,MAAI,IAAI,eAAe,UAAU;AACrC;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coherent.js/express",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.6",
|
|
4
4
|
"description": "Express adapter for Coherent.js",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.cjs",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
},
|
|
29
29
|
"peerDependencies": {
|
|
30
30
|
"express": ">=4.18.0 < 6.0.0",
|
|
31
|
-
"@coherent.js/core": "1.0.0-beta.
|
|
31
|
+
"@coherent.js/core": "1.0.0-beta.6"
|
|
32
32
|
},
|
|
33
33
|
"publishConfig": {
|
|
34
34
|
"access": "public"
|
package/types/index.d.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import { Application, RequestHandler, Request, Response, NextFunction } from 'express';
|
|
9
|
-
import { CoherentNode } from '@coherent/core';
|
|
9
|
+
import { CoherentNode, RenderOptions } from '@coherent.js/core';
|
|
10
10
|
|
|
11
11
|
// ============================================================================
|
|
12
12
|
// Express Engine Types
|
|
@@ -45,7 +45,7 @@ export interface CoherentExpressOptions {
|
|
|
45
45
|
viewsDirectory?: string;
|
|
46
46
|
cache?: boolean;
|
|
47
47
|
development?: boolean;
|
|
48
|
-
renderOptions?: {
|
|
48
|
+
renderOptions?: RenderOptions & {
|
|
49
49
|
pretty?: boolean;
|
|
50
50
|
doctype?: string;
|
|
51
51
|
compileDebug?: boolean;
|
|
@@ -55,7 +55,7 @@ export interface CoherentExpressOptions {
|
|
|
55
55
|
|
|
56
56
|
/** Express application with Coherent.js support */
|
|
57
57
|
export interface CoherentExpressApplication extends Application {
|
|
58
|
-
renderCoherent(view: CoherentNode, options?:
|
|
58
|
+
renderCoherent(view: CoherentNode, options?: RenderOptions): void;
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
/** Enhanced Express request with Coherent.js utilities */
|
|
@@ -66,7 +66,7 @@ export interface CoherentRequest extends Request {
|
|
|
66
66
|
|
|
67
67
|
/** Enhanced Express response with Coherent.js utilities */
|
|
68
68
|
export interface CoherentResponse extends Response {
|
|
69
|
-
renderCoherent(component: CoherentNode, options?:
|
|
69
|
+
renderCoherent(component: CoherentNode, options?: RenderOptions): void;
|
|
70
70
|
sendComponent<P = any>(component: (props: P) => CoherentNode, props?: P): void;
|
|
71
71
|
streamComponent<P = any>(component: (props: P) => CoherentNode, props?: P): void;
|
|
72
72
|
}
|
|
@@ -78,6 +78,24 @@ export interface CoherentResponse extends Response {
|
|
|
78
78
|
/** Coherent middleware factory */
|
|
79
79
|
export type CoherentMiddleware = (options?: CoherentExpressOptions) => RequestHandler;
|
|
80
80
|
|
|
81
|
+
/**
|
|
82
|
+
* Create middleware that enables Coherent.js rendering on Express responses.
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* ```typescript
|
|
86
|
+
* import express from 'express';
|
|
87
|
+
* import { coherentMiddleware } from '@coherent.js/express';
|
|
88
|
+
*
|
|
89
|
+
* const app = express();
|
|
90
|
+
* app.use(coherentMiddleware({ development: true }));
|
|
91
|
+
*
|
|
92
|
+
* app.get('/', (req, res) => {
|
|
93
|
+
* res.renderCoherent({ div: { text: 'Hello World' } });
|
|
94
|
+
* });
|
|
95
|
+
* ```
|
|
96
|
+
*/
|
|
97
|
+
export function coherentMiddleware(options?: CoherentExpressOptions): RequestHandler;
|
|
98
|
+
|
|
81
99
|
/** Component rendering middleware options */
|
|
82
100
|
export interface ComponentMiddlewareOptions {
|
|
83
101
|
componentDirectory?: string;
|
|
@@ -208,6 +226,18 @@ export function ssrMiddleware(config?: SSRConfig): RequestHandler;
|
|
|
208
226
|
/** Development middleware with HMR */
|
|
209
227
|
export function devMiddleware(options?: DevServerOptions & HMRConfig): RequestHandler;
|
|
210
228
|
|
|
229
|
+
/**
|
|
230
|
+
* Render a CoherentNode to HTML string.
|
|
231
|
+
*
|
|
232
|
+
* @example
|
|
233
|
+
* ```typescript
|
|
234
|
+
* import { renderComponent } from '@coherent.js/express';
|
|
235
|
+
*
|
|
236
|
+
* const html = renderComponent({ div: { text: 'Hello' } });
|
|
237
|
+
* ```
|
|
238
|
+
*/
|
|
239
|
+
export function renderComponent(component: CoherentNode, options?: RenderOptions): string;
|
|
240
|
+
|
|
211
241
|
// ============================================================================
|
|
212
242
|
// Utility Functions
|
|
213
243
|
// ============================================================================
|
|
@@ -236,12 +266,14 @@ declare const coherentExpress: {
|
|
|
236
266
|
setupCoherent: typeof setupCoherent;
|
|
237
267
|
createComponentRoute: typeof createComponentRoute;
|
|
238
268
|
coherentStatic: typeof coherentStatic;
|
|
269
|
+
coherentMiddleware: typeof coherentMiddleware;
|
|
239
270
|
componentMiddleware: typeof componentMiddleware;
|
|
240
271
|
ssrMiddleware: typeof ssrMiddleware;
|
|
241
272
|
devMiddleware: typeof devMiddleware;
|
|
242
273
|
createCoherentApp: typeof createCoherentApp;
|
|
243
274
|
registerRoutes: typeof registerRoutes;
|
|
244
275
|
createErrorHandler: typeof createErrorHandler;
|
|
276
|
+
renderComponent: typeof renderComponent;
|
|
245
277
|
};
|
|
246
278
|
|
|
247
279
|
export default coherentExpress;
|