@aetherframework/template-engine 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 +21 -0
- package/README.md +662 -0
- package/examples/basic-usage.js +217 -0
- package/examples/dist/basic-usage-result.html +31 -0
- package/examples/dist/layout-example-result.html +210 -0
- package/examples/dist/templates/layouts/main.aether +58 -0
- package/examples/dist/templates/pages/home.aether +116 -0
- package/examples/layout-example.js +404 -0
- package/examples/ssr-example.js +180 -0
- package/index.js +179 -0
- package/package.json +42 -0
- package/src/core/CacheManager.js +245 -0
- package/src/core/EngineRegistry.js +148 -0
- package/src/core/ModeManager.js +231 -0
- package/src/core/TemplateEngineFactory.js +373 -0
- package/src/engines/AetherEngine.js +582 -0
- package/src/engines/BaseEngine.js +101 -0
- package/src/engines/SSRModeEngine.js +139 -0
- package/src/engines/TemplateModeEngine.js +320 -0
- package/src/utils/ConfigLoader.js +279 -0
- package/src/utils/ErrorHandler.js +276 -0
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license MIT
|
|
3
|
+
* Copyright (c) 2026-present AetherFramework Contributors.
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
* @module @aetherframework/template-engine/src/core/ModeManager
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Mode Manager - Manages rendering modes (SSR/Template)
|
|
9
|
+
*/
|
|
10
|
+
class ModeManager {
|
|
11
|
+
constructor(options = {}) {
|
|
12
|
+
this.options = {
|
|
13
|
+
defaultMode: options.defaultMode || 'template',
|
|
14
|
+
supportedModes: ['ssr', 'template', 'disabled'],
|
|
15
|
+
...options
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
this.currentMode = this.options.defaultMode;
|
|
19
|
+
this.modes = new Map();
|
|
20
|
+
|
|
21
|
+
// Initialize modes
|
|
22
|
+
this.initializeModes();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Initialize supported modes
|
|
27
|
+
* @private
|
|
28
|
+
*/
|
|
29
|
+
initializeModes() {
|
|
30
|
+
// SSR Mode
|
|
31
|
+
this.modes.set('ssr', {
|
|
32
|
+
name: 'ssr',
|
|
33
|
+
description: 'Server-Side Rendering mode',
|
|
34
|
+
features: ['hydration', 'seo-friendly', 'fast-initial-load'],
|
|
35
|
+
renderer: null // Will be set when SSR engine is loaded
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
// Template Mode
|
|
39
|
+
this.modes.set('template', {
|
|
40
|
+
name: 'template',
|
|
41
|
+
description: 'Template rendering mode',
|
|
42
|
+
features: ['fast-render', 'caching', 'layout-support'],
|
|
43
|
+
renderer: null // Will be set when Template engine is loaded
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
// Disabled Mode (fallback)
|
|
47
|
+
this.modes.set('disabled', {
|
|
48
|
+
name: 'disabled',
|
|
49
|
+
description: 'Disabled mode - returns raw template',
|
|
50
|
+
features: ['no-processing', 'fallback'],
|
|
51
|
+
renderer: this.getDisabledRenderer()
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Set current rendering mode
|
|
57
|
+
* @param {string} mode - Mode name ('ssr', 'template', or 'disabled')
|
|
58
|
+
* @returns {ModeManager} This instance for chaining
|
|
59
|
+
*/
|
|
60
|
+
setMode(mode) {
|
|
61
|
+
if (!this.modes.has(mode)) {
|
|
62
|
+
throw new Error(`Unsupported mode: ${mode}. Supported modes: ${Array.from(this.modes.keys()).join(', ')}`);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
this.currentMode = mode;
|
|
66
|
+
console.log(`🔄 Mode changed to: ${mode}`);
|
|
67
|
+
return this;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Get current mode
|
|
72
|
+
* @returns {string} Current mode name
|
|
73
|
+
*/
|
|
74
|
+
getMode() {
|
|
75
|
+
return this.currentMode;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Get available modes
|
|
80
|
+
* @returns {Array} List of available modes
|
|
81
|
+
*/
|
|
82
|
+
getAvailableModes() {
|
|
83
|
+
return Array.from(this.modes.keys());
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Get mode information
|
|
88
|
+
* @param {string} mode - Mode name
|
|
89
|
+
* @returns {Object} Mode information
|
|
90
|
+
*/
|
|
91
|
+
getModeInfo(mode) {
|
|
92
|
+
return this.modes.get(mode) || null;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Get renderer for current mode
|
|
97
|
+
* @returns {Function} Renderer function
|
|
98
|
+
*/
|
|
99
|
+
getRenderer() {
|
|
100
|
+
const modeInfo = this.modes.get(this.currentMode);
|
|
101
|
+
if (!modeInfo || !modeInfo.renderer) {
|
|
102
|
+
throw new Error(`No renderer available for mode: ${this.currentMode}`);
|
|
103
|
+
}
|
|
104
|
+
return modeInfo.renderer;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Get SSR renderer
|
|
109
|
+
* @returns {Function} SSR renderer function
|
|
110
|
+
*/
|
|
111
|
+
getSSRRenderer() {
|
|
112
|
+
const ssrMode = this.modes.get('ssr');
|
|
113
|
+
if (!ssrMode || !ssrMode.renderer) {
|
|
114
|
+
throw new Error('SSR renderer not available. Make sure SSR engine is registered.');
|
|
115
|
+
}
|
|
116
|
+
return ssrMode.renderer;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Get template renderer
|
|
121
|
+
* @returns {Function} Template renderer function
|
|
122
|
+
*/
|
|
123
|
+
getTemplateRenderer() {
|
|
124
|
+
const templateMode = this.modes.get('template');
|
|
125
|
+
if (!templateMode || !templateMode.renderer) {
|
|
126
|
+
throw new Error('Template renderer not available. Make sure Template engine is registered.');
|
|
127
|
+
}
|
|
128
|
+
return templateMode.renderer;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Get disabled mode renderer (fallback)
|
|
133
|
+
* @returns {Function} Disabled mode renderer
|
|
134
|
+
*/
|
|
135
|
+
getDisabledRenderer() {
|
|
136
|
+
return (template, data) => {
|
|
137
|
+
// Simple renderer that returns template as-is
|
|
138
|
+
if (typeof template === 'string') {
|
|
139
|
+
return Promise.resolve(template);
|
|
140
|
+
}
|
|
141
|
+
return Promise.resolve(String(template));
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Register a renderer for a specific mode
|
|
147
|
+
* @param {string} mode - Mode name
|
|
148
|
+
* @param {Function} renderer - Renderer function
|
|
149
|
+
* @returns {ModeManager} This instance for chaining
|
|
150
|
+
*/
|
|
151
|
+
registerRenderer(mode, renderer) {
|
|
152
|
+
if (!this.modes.has(mode)) {
|
|
153
|
+
throw new Error(`Cannot register renderer for unknown mode: ${mode}`);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
this.modes.get(mode).renderer = renderer;
|
|
157
|
+
console.log(`✅ Renderer registered for mode: ${mode}`);
|
|
158
|
+
return this;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Register an adapter for mode switching
|
|
163
|
+
* @param {Object} adapter - Mode adapter
|
|
164
|
+
* @returns {ModeManager} This instance for chaining
|
|
165
|
+
*/
|
|
166
|
+
registerAdapter(adapter) {
|
|
167
|
+
if (!adapter || typeof adapter !== 'object') {
|
|
168
|
+
throw new Error('Adapter must be an object');
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (!adapter.name) {
|
|
172
|
+
throw new Error('Adapter must have a name property');
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (!adapter.supportedModes || !Array.isArray(adapter.supportedModes)) {
|
|
176
|
+
throw new Error('Adapter must have supportedModes array');
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Register adapter for each supported mode
|
|
180
|
+
adapter.supportedModes.forEach(mode => {
|
|
181
|
+
if (this.modes.has(mode)) {
|
|
182
|
+
const modeInfo = this.modes.get(mode);
|
|
183
|
+
modeInfo.adapter = adapter;
|
|
184
|
+
console.log(`✅ Adapter "${adapter.name}" registered for mode: ${mode}`);
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
return this;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* List registered adapters
|
|
193
|
+
* @returns {Array} List of adapter names
|
|
194
|
+
*/
|
|
195
|
+
listAdapters() {
|
|
196
|
+
const adapters = new Set();
|
|
197
|
+
for (const [mode, modeInfo] of this.modes) {
|
|
198
|
+
if (modeInfo.adapter) {
|
|
199
|
+
adapters.add(modeInfo.adapter.name);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return Array.from(adapters);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Get mode statistics
|
|
207
|
+
* @returns {Object} Mode statistics
|
|
208
|
+
*/
|
|
209
|
+
getStats() {
|
|
210
|
+
const stats = {
|
|
211
|
+
currentMode: this.currentMode,
|
|
212
|
+
availableModes: this.getAvailableModes(),
|
|
213
|
+
adapters: this.listAdapters(),
|
|
214
|
+
modes: {}
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
for (const [name, modeInfo] of this.modes) {
|
|
218
|
+
stats.modes[name] = {
|
|
219
|
+
name: modeInfo.name,
|
|
220
|
+
description: modeInfo.description,
|
|
221
|
+
hasRenderer: !!modeInfo.renderer,
|
|
222
|
+
hasAdapter: !!modeInfo.adapter,
|
|
223
|
+
features: modeInfo.features || []
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
return stats;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
export default ModeManager;
|
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license MIT
|
|
3
|
+
* Copyright (c) 2026-present AetherFramework Contributors.
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
* @module @aetherframework/template-engine/src/core/TemplateEngineFactory
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Template Engine Factory - Core factory class for creating and managing template engines
|
|
10
|
+
* Supports factory pattern with multiple rendering modes (SSR/Template)
|
|
11
|
+
*/
|
|
12
|
+
import EngineRegistry from './EngineRegistry.js';
|
|
13
|
+
import ModeManager from './ModeManager.js';
|
|
14
|
+
import CacheManager from './CacheManager.js';
|
|
15
|
+
import ConfigLoader from '../utils/ConfigLoader.js';
|
|
16
|
+
import ErrorHandler from '../utils/ErrorHandler.js';
|
|
17
|
+
|
|
18
|
+
class TemplateEngineFactory {
|
|
19
|
+
constructor(options = {}) {
|
|
20
|
+
// Load configuration from environment variables
|
|
21
|
+
this.config = {
|
|
22
|
+
// Mode selection: 'ssr' or 'template'
|
|
23
|
+
mode: process.env.TEMPLATE_ENGINE_MODE || options.mode || 'template',
|
|
24
|
+
|
|
25
|
+
// Default engine to use
|
|
26
|
+
defaultEngine: process.env.TEMPLATE_ENGINE || options.defaultEngine || 'aether',
|
|
27
|
+
|
|
28
|
+
// Cache configuration
|
|
29
|
+
cacheEnabled: process.env.CACHE_ENABLED !== 'false' && (options.cacheEnabled !== false),
|
|
30
|
+
cacheTTL: parseInt(process.env.CACHE_TTL) || options.cacheTTL || 300000, // 5 minutes
|
|
31
|
+
|
|
32
|
+
// Template directory
|
|
33
|
+
templateDir: process.env.TEMPLATE_DIR || options.templateDir || './templates',
|
|
34
|
+
|
|
35
|
+
// Debug mode
|
|
36
|
+
debug: process.env.NODE_ENV === 'development' || options.debug || false,
|
|
37
|
+
|
|
38
|
+
// Merge with user options
|
|
39
|
+
...options
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
// Initialize core components
|
|
43
|
+
this.registry = new EngineRegistry();
|
|
44
|
+
this.modeManager = new ModeManager(this.config);
|
|
45
|
+
this.cacheManager = new CacheManager(this.config);
|
|
46
|
+
|
|
47
|
+
// Track initialization state
|
|
48
|
+
this.initialized = false;
|
|
49
|
+
|
|
50
|
+
console.log(`🚀 Template Engine Factory created in ${this.config.mode} mode`);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Initialize the factory and register engines
|
|
55
|
+
* This method should be called before using the factory
|
|
56
|
+
* @returns {Promise<TemplateEngineFactory>} This factory instance for chaining
|
|
57
|
+
*/
|
|
58
|
+
async initialize() {
|
|
59
|
+
if (this.initialized) {
|
|
60
|
+
return this;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
try {
|
|
64
|
+
// Initialize built-in engines
|
|
65
|
+
await this.initializeEngines();
|
|
66
|
+
|
|
67
|
+
this.initialized = true;
|
|
68
|
+
console.log(`✅ Template Engine Factory initialized in ${this.config.mode} mode`);
|
|
69
|
+
|
|
70
|
+
return this;
|
|
71
|
+
} catch (error) {
|
|
72
|
+
console.error('❌ Factory initialization failed:', error.message);
|
|
73
|
+
throw error;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Initialize built-in engines
|
|
79
|
+
* @private
|
|
80
|
+
*/
|
|
81
|
+
async initializeEngines() {
|
|
82
|
+
try {
|
|
83
|
+
// Import and register Aether Engine (your custom syntax)
|
|
84
|
+
const { default: AetherEngine } = await import('./../engines/AetherEngine.js');
|
|
85
|
+
this.registerEngine('aether', new AetherEngine(this.config));
|
|
86
|
+
console.log('✅ Aether engine registered');
|
|
87
|
+
|
|
88
|
+
// Import and register SSR Mode Engine
|
|
89
|
+
const { default: SSRModeEngine } = await import('./../engines/SSRModeEngine.js');
|
|
90
|
+
this.registerEngine('ssr-mode', new SSRModeEngine(this.config));
|
|
91
|
+
console.log('✅ SSR Mode engine registered');
|
|
92
|
+
|
|
93
|
+
// Import and register Template Mode Engine
|
|
94
|
+
const { default: TemplateModeEngine } = await import('./../engines/TemplateModeEngine.js');
|
|
95
|
+
this.registerEngine('template-mode', new TemplateModeEngine(this.config));
|
|
96
|
+
console.log('✅ Template Mode engine registered');
|
|
97
|
+
|
|
98
|
+
} catch (error) {
|
|
99
|
+
console.error('❌ Engine initialization failed:', error.message);
|
|
100
|
+
throw error;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Register a template engine
|
|
106
|
+
* @param {string} name - Engine name
|
|
107
|
+
* @param {BaseEngine} engine - Engine instance
|
|
108
|
+
* @returns {TemplateEngineFactory} This factory instance for chaining
|
|
109
|
+
*/
|
|
110
|
+
registerEngine(name, engine) {
|
|
111
|
+
this.registry.register(name, engine);
|
|
112
|
+
return this;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Get engine by name
|
|
117
|
+
* @param {string} name - Engine name
|
|
118
|
+
* @returns {BaseEngine} Engine instance
|
|
119
|
+
*/
|
|
120
|
+
getEngine(name) {
|
|
121
|
+
return this.registry.get(name);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Create a renderer with specific engine
|
|
126
|
+
* @param {string} engineName - Engine name
|
|
127
|
+
* @param {Object} options - Engine options
|
|
128
|
+
* @returns {Object} Renderer instance
|
|
129
|
+
*/
|
|
130
|
+
createRenderer(engineName = this.config.defaultEngine, options = {}) {
|
|
131
|
+
if (!this.initialized) {
|
|
132
|
+
throw new Error('Factory must be initialized before creating a renderer. Call factory.initialize() first.');
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const engine = this.getEngine(engineName);
|
|
136
|
+
if (!engine) {
|
|
137
|
+
throw new Error(`Engine "${engineName}" not found. Available: ${this.registry.listEngines().join(', ')}`);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Initialize engine if needed
|
|
141
|
+
if (!engine.initialized) {
|
|
142
|
+
engine.initialize(options);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Store references to avoid context issues
|
|
146
|
+
const cacheManager = this.cacheManager;
|
|
147
|
+
const modeManager = this.modeManager;
|
|
148
|
+
const config = this.config;
|
|
149
|
+
const factory = this; // Store factory reference
|
|
150
|
+
|
|
151
|
+
return {
|
|
152
|
+
engine,
|
|
153
|
+
engineName,
|
|
154
|
+
cache: cacheManager,
|
|
155
|
+
options: { ...config, ...options },
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Render template with data
|
|
159
|
+
* @param {string|Function} template - Template content or name
|
|
160
|
+
* @param {Object} data - Template data
|
|
161
|
+
* @param {Object} renderOptions - Render options
|
|
162
|
+
* @returns {Promise<string>} Rendered HTML
|
|
163
|
+
*/
|
|
164
|
+
async render(template, data = {}, renderOptions = {}) {
|
|
165
|
+
const startTime = Date.now();
|
|
166
|
+
const mode = config.mode;
|
|
167
|
+
|
|
168
|
+
// Generate cache key
|
|
169
|
+
const cacheKey = config.cacheEnabled
|
|
170
|
+
? `${mode}:${engineName}:${typeof template === 'string' ? template : 'function'}:${JSON.stringify(data)}`
|
|
171
|
+
: null;
|
|
172
|
+
|
|
173
|
+
// Check cache
|
|
174
|
+
if (cacheKey && cacheManager.has(cacheKey)) {
|
|
175
|
+
const cached = cacheManager.get(cacheKey);
|
|
176
|
+
if (Date.now() - cached.timestamp < config.cacheTTL) {
|
|
177
|
+
console.log(`📦 Cache hit for key: ${cacheKey.substring(0, 50)}...`);
|
|
178
|
+
return cached.html;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
let html;
|
|
183
|
+
try {
|
|
184
|
+
// Render based on mode
|
|
185
|
+
if (mode === 'ssr') {
|
|
186
|
+
// FIX: Use factory.getEngine instead of this.engine.getEngine
|
|
187
|
+
const ssrEngine = factory.getEngine('ssr-mode'); // Fixed line 179
|
|
188
|
+
if (!ssrEngine) {
|
|
189
|
+
throw new Error('SSR engine not found. Make sure SSRModeEngine is registered.');
|
|
190
|
+
}
|
|
191
|
+
html = await ssrEngine.render(template, data, {
|
|
192
|
+
...renderOptions,
|
|
193
|
+
engine: engineName
|
|
194
|
+
});
|
|
195
|
+
} else if (mode === 'template') {
|
|
196
|
+
// Use template mode engine
|
|
197
|
+
html = await engine.render(template, data, renderOptions);
|
|
198
|
+
} else {
|
|
199
|
+
throw new Error(`Unsupported mode: ${mode}`);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Cache result
|
|
203
|
+
if (cacheKey && config.cacheEnabled) {
|
|
204
|
+
cacheManager.set(cacheKey, {
|
|
205
|
+
html,
|
|
206
|
+
timestamp: Date.now(),
|
|
207
|
+
mode,
|
|
208
|
+
engine: engineName,
|
|
209
|
+
renderTime: Date.now() - startTime
|
|
210
|
+
});
|
|
211
|
+
console.log(`💾 Cached result for key: ${cacheKey.substring(0, 50)}...`);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
return html;
|
|
215
|
+
|
|
216
|
+
} catch (error) {
|
|
217
|
+
// Enhanced error handling
|
|
218
|
+
const errorContext = {
|
|
219
|
+
template: typeof template === 'string' ? template.substring(0, 100) + '...' : 'Function',
|
|
220
|
+
engine: engineName,
|
|
221
|
+
mode: mode,
|
|
222
|
+
data: Object.keys(data)
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
const handledError = ErrorHandler.handle(error, errorContext);
|
|
226
|
+
|
|
227
|
+
// Fallback to default mode if configured
|
|
228
|
+
if (renderOptions.fallbackOnError !== false && mode !== 'template') {
|
|
229
|
+
console.warn(`⚠️ Render failed in ${mode} mode, falling back to template mode`);
|
|
230
|
+
// FIX: Use factory.getEngine instead of this.engine.getEngine
|
|
231
|
+
const fallbackEngine = factory.getEngine('template-mode'); // Fixed line 219
|
|
232
|
+
return fallbackEngine.render(template, data, renderOptions);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
throw handledError;
|
|
236
|
+
}
|
|
237
|
+
},
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Compile template for reuse
|
|
241
|
+
* @param {string} template - Template content
|
|
242
|
+
* @param {Object} compileOptions - Compile options
|
|
243
|
+
* @returns {Function} Compiled function
|
|
244
|
+
*/
|
|
245
|
+
compile(template, compileOptions = {}) {
|
|
246
|
+
return engine.compile(template, compileOptions);
|
|
247
|
+
},
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Clear engine cache
|
|
251
|
+
*/
|
|
252
|
+
clearCache() {
|
|
253
|
+
engine.clearCache();
|
|
254
|
+
cacheManager.clear();
|
|
255
|
+
}
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Set rendering mode
|
|
261
|
+
* @param {string} mode - 'ssr' or 'template'
|
|
262
|
+
* @returns {TemplateEngineFactory} This factory instance for chaining
|
|
263
|
+
*/
|
|
264
|
+
setMode(mode) {
|
|
265
|
+
if (!['ssr', 'template'].includes(mode)) {
|
|
266
|
+
throw new Error(`Invalid mode: ${mode}. Must be 'ssr' or 'template'`);
|
|
267
|
+
}
|
|
268
|
+
this.config.mode = mode;
|
|
269
|
+
console.log(`🔄 Rendering mode changed to: ${mode}`);
|
|
270
|
+
return this;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Get current mode
|
|
275
|
+
* @returns {string} Current mode
|
|
276
|
+
*/
|
|
277
|
+
getMode() {
|
|
278
|
+
return this.config.mode;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Render with auto-detected engine and mode
|
|
283
|
+
* @param {string} template - Template content or name
|
|
284
|
+
* @param {Object} data - Template data
|
|
285
|
+
* @param {Object} options - Render options
|
|
286
|
+
* @returns {Promise<string>} Rendered HTML
|
|
287
|
+
*/
|
|
288
|
+
async renderAuto(template, data = {}, options = {}) {
|
|
289
|
+
const mode = this.getMode();
|
|
290
|
+
const engineName = this.detectEngine(template, options);
|
|
291
|
+
const renderer = this.createRenderer(engineName, options);
|
|
292
|
+
return renderer.render(template, data, options);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Auto-detect engine based on template content
|
|
297
|
+
* @param {string} template - Template content or file path
|
|
298
|
+
* @param {Object} options - Detection options
|
|
299
|
+
* @returns {string} Engine name
|
|
300
|
+
*/
|
|
301
|
+
detectEngine(template, options = {}) {
|
|
302
|
+
// Check by file extension
|
|
303
|
+
if (template.includes('.')) {
|
|
304
|
+
const ext = template.split('.').pop().toLowerCase();
|
|
305
|
+
const extensionMap = {
|
|
306
|
+
'aether': 'aether',
|
|
307
|
+
'html': 'aether',
|
|
308
|
+
'htm': 'aether'
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
if (extensionMap[ext] && this.registry.has(extensionMap[ext])) {
|
|
312
|
+
return extensionMap[ext];
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// Check by template syntax
|
|
317
|
+
if (typeof template === 'string') {
|
|
318
|
+
// Your custom syntax detection
|
|
319
|
+
if (template.includes('@yield') || template.includes('@section') || template.includes('@extends')) {
|
|
320
|
+
return 'aether';
|
|
321
|
+
} else if (template.includes('{{#') || template.includes('{{/')) {
|
|
322
|
+
return 'aether'; // Fallback to Aether for handlebars-like syntax
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
return options.engine || this.config.defaultEngine;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Get list of available engines
|
|
331
|
+
* @returns {Array} List of engine names
|
|
332
|
+
*/
|
|
333
|
+
listEngines() {
|
|
334
|
+
return this.registry.listEngines();
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* Get engine information
|
|
339
|
+
* @param {string} name - Engine name
|
|
340
|
+
* @returns {Object} Engine metadata
|
|
341
|
+
*/
|
|
342
|
+
getEngineInfo(name) {
|
|
343
|
+
const engine = this.getEngine(name);
|
|
344
|
+
return engine ? engine.getMetadata() : null;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Clear all caches
|
|
349
|
+
*/
|
|
350
|
+
clearAllCaches() {
|
|
351
|
+
this.cacheManager.clear();
|
|
352
|
+
this.registry.clearCaches();
|
|
353
|
+
console.log('🗑️ All caches cleared');
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Get factory statistics
|
|
358
|
+
* @returns {Object} Statistics
|
|
359
|
+
*/
|
|
360
|
+
getStats() {
|
|
361
|
+
return {
|
|
362
|
+
mode: this.getMode(),
|
|
363
|
+
engines: this.listEngines(),
|
|
364
|
+
cacheSize: this.cacheManager.size(),
|
|
365
|
+
cacheEnabled: this.config.cacheEnabled,
|
|
366
|
+
cacheTTL: this.config.cacheTTL,
|
|
367
|
+
templateDir: this.config.templateDir,
|
|
368
|
+
debug: this.config.debug
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
export default TemplateEngineFactory;
|