@o2vend/theme-cli 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.

Potentially problematic release.


This version of @o2vend/theme-cli might be problematic. Click here for more details.

@@ -0,0 +1,169 @@
1
+ /**
2
+ * LiquidJS Engine Setup
3
+ * Configures LiquidJS with all O2VEND filters and custom tags
4
+ */
5
+
6
+ const { Liquid } = require('liquidjs');
7
+ const path = require('path');
8
+ const LiquidHelperService = require('./liquid-filters');
9
+ const fs = require('fs');
10
+
11
+ /**
12
+ * Create and configure LiquidJS engine
13
+ * @param {string} themePath - Path to theme directory
14
+ * @param {Object} options - Engine options
15
+ * @returns {Liquid} Configured LiquidJS engine
16
+ */
17
+ function createLiquidEngine(themePath, options = {}) {
18
+ const {
19
+ cache = false, // Disable cache in dev mode
20
+ extname = '.liquid'
21
+ } = options;
22
+
23
+ // Create Liquid engine
24
+ const liquid = new Liquid({
25
+ root: themePath,
26
+ extname: extname,
27
+ cache: cache,
28
+ strictFilters: false,
29
+ strictVariables: false,
30
+ outputEscape: 'escape',
31
+ ownPropertyOnly: false
32
+ });
33
+
34
+ // Register all filters from LiquidHelperService
35
+ const liquidHelperService = new LiquidHelperService();
36
+ const filters = liquidHelperService.getFilters();
37
+
38
+ Object.keys(filters).forEach(filterName => {
39
+ liquid.registerFilter(filterName, filters[filterName]);
40
+ });
41
+
42
+ // Register custom tags
43
+ registerCustomTags(liquid, themePath);
44
+
45
+ return liquid;
46
+ }
47
+
48
+ /**
49
+ * Register custom Liquid tags (section, hook, schema)
50
+ * @param {Liquid} liquid - LiquidJS engine instance
51
+ * @param {string} themePath - Theme path
52
+ */
53
+ function registerCustomTags(liquid, themePath) {
54
+ // Register section tag
55
+ liquid.registerTag('section', {
56
+ parse: function(tagToken, remainTokens) {
57
+ this.sectionPath = tagToken.args.trim().replace(/^['"]|['"]$/g, '');
58
+ },
59
+ render: async function(scope, hash) {
60
+ const sectionPath = this.sectionPath;
61
+ if (!sectionPath) {
62
+ console.error('[SECTION] No section path provided');
63
+ return '';
64
+ }
65
+
66
+ try {
67
+ const sectionFile = path.join(themePath, 'sections', `${sectionPath}.liquid`);
68
+ if (fs.existsSync(sectionFile)) {
69
+ const sectionContent = fs.readFileSync(sectionFile, 'utf8');
70
+ const scopeContexts = Array.isArray(scope?.contexts) ? scope.contexts : [];
71
+ const primaryScope = scopeContexts.length > 0
72
+ ? scopeContexts[0]
73
+ : (scope?.environments || scope?.context || {});
74
+
75
+ const context = {
76
+ ...primaryScope,
77
+ section: primaryScope.section || {}
78
+ };
79
+
80
+ return await liquid.parseAndRender(sectionContent, context);
81
+ } else {
82
+ console.warn(`[SECTION] Section file not found: ${sectionFile}`);
83
+ return '';
84
+ }
85
+ } catch (error) {
86
+ console.error(`[SECTION] Error rendering section ${sectionPath}:`, error.message);
87
+ return '';
88
+ }
89
+ }
90
+ });
91
+
92
+ // Register hook tag (simplified for CLI - plugins not supported)
93
+ liquid.registerTag('hook', {
94
+ parse: function(tagToken, remainTokens) {
95
+ const args = tagToken.args;
96
+ if (typeof args === 'string') {
97
+ this.hookName = args.trim().replace(/^['"]|['"]$/g, '');
98
+ } else {
99
+ this.hookName = String(args || '').trim().replace(/^['"]|['"]$/g, '');
100
+ }
101
+ },
102
+ render: async function(scope, hash) {
103
+ // In CLI, hooks are not supported (no plugin system)
104
+ // Return empty string
105
+ return '';
106
+ }
107
+ });
108
+
109
+ // Schema tag is handled by LiquidJS as a block tag
110
+ // No special registration needed
111
+ }
112
+
113
+ /**
114
+ * Render template with layout support
115
+ * @param {Liquid} liquid - LiquidJS engine
116
+ * @param {string} templatePath - Template path (relative to theme, e.g., 'templates/index')
117
+ * @param {Object} context - Template context
118
+ * @param {string} themePath - Theme path
119
+ * @returns {Promise<string>} Rendered HTML
120
+ */
121
+ async function renderWithLayout(liquid, templatePath, context, themePath) {
122
+ try {
123
+ const fullTemplatePath = path.join(themePath, `${templatePath}.liquid`);
124
+
125
+ if (!fs.existsSync(fullTemplatePath)) {
126
+ throw new Error(`Template not found: ${fullTemplatePath}`);
127
+ }
128
+
129
+ const templateContent = fs.readFileSync(fullTemplatePath, 'utf-8');
130
+
131
+ // Check for layout directive
132
+ const layoutMatch = templateContent.match(/\{%\s*layout\s+['"](.+?)['"]\s*%\}/);
133
+
134
+ if (layoutMatch) {
135
+ const layoutPath = layoutMatch[1]; // e.g., 'theme'
136
+
137
+ // Remove layout directive from template
138
+ const contentWithoutLayout = templateContent.replace(/\{%\s*layout\s+['"](.+?)['"]\s*%\}/, '').trim();
139
+
140
+ // Render template content first
141
+ const renderedContent = await liquid.parseAndRender(contentWithoutLayout, context);
142
+
143
+ // Render layout with content
144
+ const layoutContext = {
145
+ ...context,
146
+ content: renderedContent
147
+ };
148
+
149
+ const layoutFile = path.join(themePath, 'layout', `${layoutPath}.liquid`);
150
+ if (fs.existsSync(layoutFile)) {
151
+ const layoutContent = fs.readFileSync(layoutFile, 'utf-8');
152
+ return await liquid.parseAndRender(layoutContent, layoutContext);
153
+ } else {
154
+ throw new Error(`Layout not found: ${layoutFile}`);
155
+ }
156
+ } else {
157
+ // No layout directive, render template directly
158
+ return await liquid.parseAndRender(templateContent, context);
159
+ }
160
+ } catch (error) {
161
+ console.error('Error rendering template with layout:', error);
162
+ throw error;
163
+ }
164
+ }
165
+
166
+ module.exports = {
167
+ createLiquidEngine,
168
+ renderWithLayout
169
+ };