vite-file-include 1.0.1 → 1.0.3

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.
Files changed (3) hide show
  1. package/README.md +38 -12
  2. package/package.json +8 -3
  3. package/src/index.js +50 -31
package/README.md CHANGED
@@ -1,23 +1,24 @@
1
- # vite-plugin-file-include
1
+ # vite-file-include
2
2
 
3
- `vite-plugin-file-include` is an advanced Vite plugin designed to facilitate the inclusion of external HTML files, looping through data, and conditional rendering within your HTML files. It is particularly useful for managing repetitive HTML structures in static sites or templating environments.
3
+ `vite-file-include` is an advanced Vite plugin designed to facilitate the inclusion of external HTML files, looping through data, and conditional rendering within your HTML files. It is particularly useful for managing repetitive HTML structures in static sites or templating environments.
4
4
 
5
5
  ## Features
6
6
 
7
7
  - File inclusion with support for nested includes
8
8
  - Looping through data arrays or JSON files
9
- - Conditional rendering
10
- - Caching mechanism for improved performance
9
+ - Conditional rendering
11
10
  - Custom function support for advanced templating
11
+ - Evaluate JavaScript expressions directly in your templates.
12
12
  - Asynchronous file processing
13
13
  - Enhanced error handling and debugging
14
14
 
15
+
15
16
  ## Installation
16
17
 
17
18
  Install the plugin via npm:
18
19
 
19
20
  ```bash
20
- npm install vite-plugin-file-include
21
+ npm install vite-file-include
21
22
  ```
22
23
 
23
24
  ## Configuration
@@ -25,7 +26,7 @@ npm install vite-plugin-file-include
25
26
  To use the plugin, import and configure it in your `vite.config.js`:
26
27
 
27
28
  ```javascript
28
- import fileIncludePlugin from 'vite-plugin-file-include';
29
+ import fileIncludePlugin from 'vite-file-include';
29
30
 
30
31
  export default {
31
32
  plugins: [
@@ -35,7 +36,7 @@ export default {
35
36
  ifPattern: "@@if",
36
37
  baseDir: process.cwd(),
37
38
  context: {},
38
- cacheTimeout: 5000
39
+ customFunctions: {},
39
40
  }),
40
41
  ],
41
42
  };
@@ -48,7 +49,7 @@ export default {
48
49
  - `ifPattern` (default: `@@if`): The pattern used to conditionally render content.
49
50
  - `baseDir` (default: `process.cwd()`): The base directory for resolving paths.
50
51
  - `context` (default: `{}`): An object containing global variables that can be used in includes, loops, and conditionals.
51
- - `cacheTimeout` (default: `5000`): The time (in milliseconds) after which cached content is invalidated.
52
+ - `customFunctions` (default: {}): An object containing custom functions that can be used in your templates.
52
53
 
53
54
  ## Directives
54
55
 
@@ -118,6 +119,35 @@ The `@@if` directive allows conditional rendering based on an expression.
118
119
  }
119
120
  ```
120
121
 
122
+ ## Custom Functions
123
+
124
+ You can define custom functions to use in your templates. These functions are passed to the plugin through the `customFunctions` option:
125
+
126
+ ```javascript
127
+ fileIncludePlugin({
128
+ customFunctions: {
129
+ uppercase: (str) => str.toUpperCase(),
130
+ currentYear: () => new Date().getFullYear()
131
+ }
132
+ })
133
+ ```
134
+
135
+ You can then use these functions in your templates:
136
+
137
+ ```html
138
+ <p>{{ uppercase(name) }}</p>
139
+ <footer>&copy; {{ currentYear() }}</footer>
140
+ ```
141
+
142
+
143
+ ## JavaScript Expressions
144
+
145
+ You can use JavaScript expressions directly in your templates. For example:
146
+
147
+ ```html
148
+ <p>Current Year: {{ new Date().getFullYear() }}</p>
149
+ <p>Uppercase Text: {{ 'John'.toUpperCase() }}</p>
150
+ ```
121
151
 
122
152
  ## Example Usage
123
153
 
@@ -176,10 +206,6 @@ Below is an example of how you might structure your HTML files using the plugin'
176
206
 
177
207
  If there is an error parsing JSON data or including a file, the plugin will log a detailed error message to the console. This helps in debugging while ensuring that your build process continues without interruption.
178
208
 
179
- ## Caching
180
-
181
- The plugin implements a caching mechanism to improve performance, especially for larger projects with many includes. Cached content is automatically invalidated after the specified `cacheTimeout`.
182
-
183
209
  ## License
184
210
 
185
211
  This project is licensed under the MIT License. See the LICENSE file for more details.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vite-file-include",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "A Vite plugin for file inclusion, loops, and conditionals in HTML files",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -15,11 +15,16 @@
15
15
  ],
16
16
  "author": "Ahmed Abdulgid",
17
17
  "license": "MIT",
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "https://github.com/abdulgidcoder/vite-file-includ.git"
21
+ },
18
22
  "peerDependencies": {
19
23
  "vite": "^4.0.0"
20
24
  },
21
25
  "dependencies": {
22
26
  "fs": "0.0.1-security",
23
- "path": "^0.12.7"
27
+ "path": "^0.12.7",
28
+ "vite-file-include": "^1.0.2"
24
29
  }
25
- }
30
+ }
package/src/index.js CHANGED
@@ -1,13 +1,14 @@
1
1
  import fs from "fs";
2
2
  import path from "path";
3
3
 
4
- function fileInclude(options = {}) {
4
+ function fileIncludePlugin(options = {}) {
5
5
  const {
6
6
  includePattern = "@@include",
7
7
  loopPattern = "@@loop",
8
8
  ifPattern = "@@if",
9
9
  baseDir = process.cwd(),
10
10
  context = {},
11
+ customFunctions = {},
11
12
  } = options;
12
13
 
13
14
  return {
@@ -20,7 +21,8 @@ function fileInclude(options = {}) {
20
21
  includePattern,
21
22
  loopPattern,
22
23
  ifPattern,
23
- context
24
+ context,
25
+ customFunctions
24
26
  );
25
27
  },
26
28
 
@@ -32,7 +34,8 @@ function fileInclude(options = {}) {
32
34
  includePattern,
33
35
  loopPattern,
34
36
  ifPattern,
35
- context
37
+ context,
38
+ customFunctions
36
39
  );
37
40
  }
38
41
  return code;
@@ -54,7 +57,8 @@ function processIncludes(
54
57
  includePattern,
55
58
  loopPattern,
56
59
  ifPattern,
57
- context
60
+ context,
61
+ customFunctions
58
62
  ) {
59
63
  content = processIncludesWithPattern(
60
64
  content,
@@ -62,16 +66,18 @@ function processIncludes(
62
66
  includePattern,
63
67
  loopPattern,
64
68
  ifPattern,
65
- context
69
+ context,
70
+ customFunctions
66
71
  );
67
- content = processLoops(content, dir, loopPattern, context);
72
+ content = processLoops(content, dir, loopPattern, context, customFunctions);
68
73
  content = processConditionals(
69
74
  content,
70
75
  dir,
71
76
  ifPattern,
72
77
  includePattern,
73
78
  loopPattern,
74
- context
79
+ context,
80
+ customFunctions
75
81
  );
76
82
 
77
83
  return content;
@@ -83,7 +89,8 @@ function processIncludesWithPattern(
83
89
  includePattern,
84
90
  loopPattern,
85
91
  ifPattern,
86
- context
92
+ context,
93
+ customFunctions
87
94
  ) {
88
95
  const regex = new RegExp(
89
96
  `${includePattern}\\(\\s*['"](.+?)['"]\\s*,?\\s*({[\\s\\S]*?})?\\s*\\);`,
@@ -104,14 +111,19 @@ function processIncludesWithPattern(
104
111
 
105
112
  try {
106
113
  let includedContent = fs.readFileSync(includePath, "utf-8");
107
- includedContent = injectData(includedContent, { ...context, ...data });
114
+ includedContent = injectData(
115
+ includedContent,
116
+ { ...context, ...data },
117
+ customFunctions
118
+ );
108
119
  return processIncludes(
109
120
  includedContent,
110
121
  path.dirname(includePath),
111
122
  includePattern,
112
123
  loopPattern,
113
124
  ifPattern,
114
- context
125
+ context,
126
+ customFunctions
115
127
  );
116
128
  } catch (error) {
117
129
  console.error(`Failed to include file: ${includePath}`);
@@ -120,7 +132,7 @@ function processIncludesWithPattern(
120
132
  });
121
133
  }
122
134
 
123
- function processLoops(content, dir, loopPattern, context) {
135
+ function processLoops(content, dir, loopPattern, context, customFunctions) {
124
136
  const regex = new RegExp(
125
137
  `${loopPattern}\\(\\s*['"](.+?)['"]\\s*,\\s*(\\[[\\s\\S]*?\\]|['"](.+?)['"])\\s*\\);`,
126
138
  "g"
@@ -131,15 +143,12 @@ function processLoops(content, dir, loopPattern, context) {
131
143
  let dataArray = [];
132
144
 
133
145
  try {
134
- // Detect if the second argument is a JSON file path or a JSON array
135
146
  if (
136
147
  jsonArrayOrFilePath.startsWith("[") ||
137
148
  jsonArrayOrFilePath.startsWith("{")
138
149
  ) {
139
- // Handle JSON array or object directly provided in the directive
140
150
  dataArray = JSON.parse(jsonArrayOrFilePath);
141
151
  } else {
142
- // Handle JSON file path
143
152
  const jsonFilePath = path.resolve(
144
153
  dir,
145
154
  jsonArrayOrFilePath.replace(/['"]/g, "")
@@ -154,7 +163,9 @@ function processLoops(content, dir, loopPattern, context) {
154
163
 
155
164
  try {
156
165
  let loopTemplate = fs.readFileSync(loopPath, "utf-8");
157
- return dataArray.map((data) => injectData(loopTemplate, data)).join("");
166
+ return dataArray
167
+ .map((data) => injectData(loopTemplate, data, customFunctions))
168
+ .join("");
158
169
  } catch (error) {
159
170
  console.error(`Failed to include file: ${loopPath}`);
160
171
  return "";
@@ -168,7 +179,8 @@ function processConditionals(
168
179
  ifPattern,
169
180
  includePattern,
170
181
  loopPattern,
171
- context
182
+ context,
183
+ customFunctions
172
184
  ) {
173
185
  const regex = new RegExp(
174
186
  `${ifPattern}\\s*\\(([^)]+)\\)\\s*{([\\s\\S]*?)};\\s*`,
@@ -177,11 +189,7 @@ function processConditionals(
177
189
 
178
190
  return content.replace(regex, (match, condition, body) => {
179
191
  try {
180
- const func = new Function(
181
- "data",
182
- "with (data) { return " + condition + "; }"
183
- );
184
- const result = func(context);
192
+ const result = evaluateCondition(condition, context, customFunctions);
185
193
 
186
194
  if (result) {
187
195
  return processIncludesWithPattern(
@@ -190,7 +198,8 @@ function processConditionals(
190
198
  includePattern,
191
199
  loopPattern,
192
200
  ifPattern,
193
- context
201
+ context,
202
+ customFunctions
194
203
  );
195
204
  }
196
205
 
@@ -203,10 +212,10 @@ function processConditionals(
203
212
  });
204
213
  }
205
214
 
206
- function injectData(content, data) {
215
+ function injectData(content, data, customFunctions = {}) {
207
216
  return content.replace(/\{\{\s*(.*?)\s*\}\}/g, (match, expression) => {
208
217
  try {
209
- const result = evalExpression(expression, data);
218
+ const result = evaluateExpression(expression, data, customFunctions);
210
219
  return result !== undefined ? result : match;
211
220
  } catch (error) {
212
221
  console.error(`Failed to evaluate expression: ${expression}`);
@@ -216,12 +225,22 @@ function injectData(content, data) {
216
225
  });
217
226
  }
218
227
 
219
- function evalExpression(expression, data) {
220
- const func = new Function(
221
- "data",
222
- "with (data) { return " + expression + "; }"
223
- );
224
- return func(data);
228
+ function evaluateExpression(expression, data, customFunctions) {
229
+ // Bind custom functions to the evaluation context
230
+ const context = { ...data, ...customFunctions };
231
+ return new Function(
232
+ "context",
233
+ "with (context) { return " + expression + "; }"
234
+ )(context);
235
+ }
236
+
237
+ function evaluateCondition(condition, context, customFunctions) {
238
+ // Bind custom functions to the evaluation context
239
+ const contextWithFunctions = { ...context, ...customFunctions };
240
+ return new Function(
241
+ "context",
242
+ "with (context) { return " + condition + "; }"
243
+ )(contextWithFunctions);
225
244
  }
226
245
 
227
- export default fileInclude;
246
+ export default fileIncludePlugin;