lang-json 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- package/README.md +0 -0
- package/dist/esm/dump.d.ts +0 -0
- package/dist/esm/dump.js +2 -0
- package/dist/esm/dump.js.map +1 -0
- package/dist/esm/example.d.ts +13 -0
- package/dist/esm/example.js +93 -0
- package/dist/esm/example.js.map +1 -0
- package/dist/esm/index.d.ts +36 -0
- package/dist/esm/index.js +326 -0
- package/dist/esm/index.js.map +1 -0
- package/package.json +34 -0
- package/src/example.ts +116 -0
- package/src/index.ts +358 -0
- package/tsconfig.json +17 -0
package/README.md
ADDED
Binary file
|
File without changes
|
package/dist/esm/dump.js
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"dump.js","sourceRoot":"","sources":["../../src/dump.ts"],"names":[],"mappings":""}
|
@@ -0,0 +1,13 @@
|
|
1
|
+
type HelperFunction = (context: any, data: any, engine: JsonTemplateEngine) => any;
|
2
|
+
export declare class JsonTemplateEngine {
|
3
|
+
private helpers;
|
4
|
+
constructor();
|
5
|
+
registerHelper(name: string, fn: HelperFunction): void;
|
6
|
+
applyTemplate(template: any, data: any): any;
|
7
|
+
private replaceVars;
|
8
|
+
private lookup;
|
9
|
+
private eachHelper;
|
10
|
+
private ifHelper;
|
11
|
+
private varHelper;
|
12
|
+
}
|
13
|
+
export {};
|
@@ -0,0 +1,93 @@
|
|
1
|
+
export class JsonTemplateEngine {
|
2
|
+
helpers = {};
|
3
|
+
constructor() {
|
4
|
+
console.log("registering helpers");
|
5
|
+
this.registerHelper("each", this.eachHelper.bind(this));
|
6
|
+
this.registerHelper("if", this.ifHelper.bind(this));
|
7
|
+
this.registerHelper("var", this.varHelper.bind(this));
|
8
|
+
}
|
9
|
+
// Register a custom helper
|
10
|
+
registerHelper(name, fn) {
|
11
|
+
this.helpers[name] = fn;
|
12
|
+
}
|
13
|
+
// Core function to parse and apply template (now fully recursive)
|
14
|
+
applyTemplate(template, data) {
|
15
|
+
console.log("template : ", template);
|
16
|
+
if (typeof template === "string") {
|
17
|
+
console.log("string template");
|
18
|
+
return this.replaceVars(template, data); // Replace string variables (dynamic)
|
19
|
+
}
|
20
|
+
else if (Array.isArray(template)) {
|
21
|
+
console.log("Array template");
|
22
|
+
return template.map((item) => this.applyTemplate(item, data)); // Handle arrays recursively
|
23
|
+
}
|
24
|
+
else if (typeof template === "object") {
|
25
|
+
console.log("object template");
|
26
|
+
const result = {};
|
27
|
+
for (const key in template) {
|
28
|
+
if (key.startsWith("{{#")) {
|
29
|
+
const helperName = key.slice(3, key.indexOf("}}"));
|
30
|
+
const helperArg = key.slice(key.indexOf(" ") + 1, -2).trim();
|
31
|
+
if (this.helpers[helperName]) {
|
32
|
+
const helperFn = this.helpers[helperName];
|
33
|
+
console.log("applying helper", helperName);
|
34
|
+
const helperResult = helperFn(template[key], { ...data, helperArg }, this);
|
35
|
+
console.log("helperRe", helperResult);
|
36
|
+
}
|
37
|
+
}
|
38
|
+
else if (key.includes("{{else}}")) {
|
39
|
+
const elseKey = key.replace("{{else}}", "").trim();
|
40
|
+
result[elseKey] = this.applyTemplate(template[key], data);
|
41
|
+
}
|
42
|
+
else {
|
43
|
+
console.log("going deep down");
|
44
|
+
result[key] = this.applyTemplate(template[key], data);
|
45
|
+
}
|
46
|
+
}
|
47
|
+
return result;
|
48
|
+
}
|
49
|
+
return template;
|
50
|
+
}
|
51
|
+
// Helper function to replace {{var}} with values from data
|
52
|
+
replaceVars(template, data) {
|
53
|
+
if (typeof template === "string") {
|
54
|
+
return template.replace(/{{\s*([\w.]+)\s*}}/g, (match, varPath) => {
|
55
|
+
return this.lookup(varPath, data) || "";
|
56
|
+
});
|
57
|
+
}
|
58
|
+
return template;
|
59
|
+
}
|
60
|
+
// Lookup a variable in data (supports nested keys like 'menu.name')
|
61
|
+
lookup(varPath, data) {
|
62
|
+
console.log("looking up", varPath, data);
|
63
|
+
return varPath.split(".").reduce((acc, part) => acc?.[part], data);
|
64
|
+
}
|
65
|
+
// Each helper {{#each}}
|
66
|
+
eachHelper(context, data, engine) {
|
67
|
+
const array = engine.lookup(data.helperArg, data);
|
68
|
+
if (!Array.isArray(array)) {
|
69
|
+
throw new Error(`${data.helperArg} is not an array`);
|
70
|
+
}
|
71
|
+
// Recursively apply template for each item in the array
|
72
|
+
return array.map((item) => engine.applyTemplate(context, { ...data, ...item }));
|
73
|
+
}
|
74
|
+
// If/else helper {{#if}}
|
75
|
+
ifHelper(context, data, engine) {
|
76
|
+
const condition = engine.lookup(data.helperArg, data);
|
77
|
+
if (condition) {
|
78
|
+
return engine.applyTemplate(context, data);
|
79
|
+
}
|
80
|
+
else {
|
81
|
+
const elseKey = Object.keys(context).find((key) => key.includes("{{else}}"));
|
82
|
+
if (elseKey) {
|
83
|
+
return engine.applyTemplate(context[elseKey.replace("{{else}}", "").trim()], data);
|
84
|
+
}
|
85
|
+
}
|
86
|
+
return null;
|
87
|
+
}
|
88
|
+
// Variable helper {{var}}
|
89
|
+
varHelper(context, data) {
|
90
|
+
return this.lookup(data.helperArg, data);
|
91
|
+
}
|
92
|
+
}
|
93
|
+
//# sourceMappingURL=example.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"example.js","sourceRoot":"","sources":["../../src/example.ts"],"names":[],"mappings":"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"}
|
@@ -0,0 +1,36 @@
|
|
1
|
+
type HelperFunction = (context: any, data: any, innerTemplate: any) => any;
|
2
|
+
export declare class JsonTemplateEngine {
|
3
|
+
helpers: Record<string, HelperFunction>;
|
4
|
+
constructor();
|
5
|
+
registerHelper(name: string, fn: HelperFunction): void;
|
6
|
+
applyTemplate(template: any, data: any): any;
|
7
|
+
lookup(varPath: string, data: any): any;
|
8
|
+
proccessHelper(string: string, data: any, innerTemplate?: any): any;
|
9
|
+
logHelper(varPath: string, data: any, innerTemplate: any): any;
|
10
|
+
varHelper(string: any, data: any): any;
|
11
|
+
lengthHelper(varPath: string, data: any): any;
|
12
|
+
eachHelper(string: any, data: any, innerTemplate: any): any;
|
13
|
+
loopHelper(string: any, data: any, innerTemplate: any): any;
|
14
|
+
ifHelper(condition: string, data: any, innerTemplate: any): boolean;
|
15
|
+
unlessHelper(condition: string, data: any, innerTemplate: any): boolean;
|
16
|
+
withHelper(scopePath: string, data: any, innerTemplate: any): any;
|
17
|
+
setHelper(varName: string, data: any, innerTemplate: any): any;
|
18
|
+
concatHelper(args: string, data: any): any;
|
19
|
+
mathHelper(expression: string, data: any): any;
|
20
|
+
compareHelper(expression: string, data: any): boolean;
|
21
|
+
upperCaseHelper(varPath: string, data: any): any;
|
22
|
+
lowerCaseHelper(varPath: string, data: any): any;
|
23
|
+
jsonStringifyHelper(varPath: string, data: any): any;
|
24
|
+
jsonParseHelper(varPath: string, data: any): any;
|
25
|
+
dateHelper(varPath: string, data: any): any;
|
26
|
+
repeatHelper(args: string, data: any): any;
|
27
|
+
sliceHelper(args: string, data: any): any;
|
28
|
+
joinHelper(args: string, data: any): any;
|
29
|
+
findHelper(args: string, data: any): any;
|
30
|
+
mapHelper(args: string, data: any, innerTemplate: any): any;
|
31
|
+
uniqueHelper(varPath: string, data: any): any;
|
32
|
+
randomHelper(varPath: string, data: any): any;
|
33
|
+
reverseHelper(varPath: string, data: any): any;
|
34
|
+
existsHelper(varPath: string, data: any): boolean;
|
35
|
+
}
|
36
|
+
export {};
|
@@ -0,0 +1,326 @@
|
|
1
|
+
export class JsonTemplateEngine {
|
2
|
+
helpers = {};
|
3
|
+
constructor() {
|
4
|
+
this.registerHelper("each", this.eachHelper.bind(this));
|
5
|
+
this.registerHelper("loop", this.loopHelper.bind(this));
|
6
|
+
this.registerHelper("if", this.ifHelper.bind(this));
|
7
|
+
this.registerHelper("with", this.withHelper.bind(this));
|
8
|
+
this.registerHelper("set", this.setHelper.bind(this));
|
9
|
+
this.registerHelper("unless", this.unlessHelper.bind(this));
|
10
|
+
this.registerHelper("log", this.logHelper.bind(this));
|
11
|
+
this.registerHelper("concat", this.concatHelper.bind(this));
|
12
|
+
this.registerHelper("length", this.lengthHelper.bind(this));
|
13
|
+
this.registerHelper("math", this.mathHelper.bind(this));
|
14
|
+
this.registerHelper("var", this.varHelper.bind(this));
|
15
|
+
this.registerHelper("compare", this.compareHelper.bind(this));
|
16
|
+
this.registerHelper("upperCase", this.upperCaseHelper.bind(this));
|
17
|
+
this.registerHelper("lowerCase", this.lowerCaseHelper.bind(this));
|
18
|
+
this.registerHelper("jsonStringify", this.jsonStringifyHelper.bind(this));
|
19
|
+
this.registerHelper("jsonParse", this.jsonParseHelper.bind(this));
|
20
|
+
this.registerHelper("date", this.dateHelper.bind(this));
|
21
|
+
this.registerHelper("repeat", this.repeatHelper.bind(this));
|
22
|
+
this.registerHelper("slice", this.sliceHelper.bind(this));
|
23
|
+
this.registerHelper("join", this.joinHelper.bind(this));
|
24
|
+
this.registerHelper("find", this.findHelper.bind(this));
|
25
|
+
this.registerHelper("map", this.mapHelper.bind(this));
|
26
|
+
this.registerHelper("unique", this.uniqueHelper.bind(this));
|
27
|
+
this.registerHelper("random", this.randomHelper.bind(this));
|
28
|
+
this.registerHelper("reverse", this.reverseHelper.bind(this));
|
29
|
+
this.registerHelper("exists", this.existsHelper.bind(this));
|
30
|
+
}
|
31
|
+
// Register a custom helper
|
32
|
+
registerHelper(name, fn) {
|
33
|
+
this.helpers[name] = fn;
|
34
|
+
}
|
35
|
+
applyTemplate(template, data) {
|
36
|
+
if (typeof template === "string") {
|
37
|
+
return this.proccessHelper(template, data);
|
38
|
+
}
|
39
|
+
else if (Array.isArray(template)) {
|
40
|
+
return template.map((item, index) => this.applyTemplate(item, { ...data, currentItem: item, index }));
|
41
|
+
}
|
42
|
+
else if (typeof template === "object") {
|
43
|
+
let result = {};
|
44
|
+
for (const key in template) {
|
45
|
+
if (Object.prototype.hasOwnProperty.call(template, key)) {
|
46
|
+
const value = template[key];
|
47
|
+
const currentKeyResult = this.proccessHelper(key, data, value);
|
48
|
+
if (typeof currentKeyResult === "string") {
|
49
|
+
if (value) {
|
50
|
+
result[currentKeyResult] = this.applyTemplate(value, data);
|
51
|
+
}
|
52
|
+
else {
|
53
|
+
result = currentKeyResult;
|
54
|
+
}
|
55
|
+
}
|
56
|
+
else if (Array.isArray(currentKeyResult)) {
|
57
|
+
result = this.applyTemplate(currentKeyResult, data);
|
58
|
+
}
|
59
|
+
else if (typeof currentKeyResult === "object") {
|
60
|
+
result = this.applyTemplate(currentKeyResult, data);
|
61
|
+
}
|
62
|
+
else if (typeof currentKeyResult === "boolean") {
|
63
|
+
if (currentKeyResult) {
|
64
|
+
result = this.applyTemplate(value, data);
|
65
|
+
}
|
66
|
+
}
|
67
|
+
}
|
68
|
+
}
|
69
|
+
return result;
|
70
|
+
}
|
71
|
+
return template;
|
72
|
+
}
|
73
|
+
lookup(varPath, data) {
|
74
|
+
if (typeof varPath !== "string")
|
75
|
+
return varPath;
|
76
|
+
let normalizedPath = varPath.replace(/\[(\d+)\]/g, ".$1");
|
77
|
+
if (normalizedPath.startsWith(".")) {
|
78
|
+
normalizedPath = normalizedPath.slice(1);
|
79
|
+
}
|
80
|
+
const returnValue = normalizedPath.split(".").reduce((acc, part) => {
|
81
|
+
return acc?.[part];
|
82
|
+
}, data);
|
83
|
+
if (returnValue) {
|
84
|
+
return returnValue;
|
85
|
+
}
|
86
|
+
else {
|
87
|
+
return varPath;
|
88
|
+
}
|
89
|
+
}
|
90
|
+
proccessHelper(string, data, innerTemplate) {
|
91
|
+
const helperMatch = string.match(/{{#(\w+)\s+(.*?)}}/);
|
92
|
+
if (helperMatch) {
|
93
|
+
const [helperString, helperName, helperArg] = helperMatch;
|
94
|
+
const helperFn = this.helpers[helperName];
|
95
|
+
if (helperFn) {
|
96
|
+
// Check if there's an inner expression (e.g., compare user.age 30)
|
97
|
+
const innerExpressionMatch = helperArg.match(/\((.*?)\)/);
|
98
|
+
if (innerExpressionMatch) {
|
99
|
+
const innerExpression = innerExpressionMatch[1]; // e.g., 'compare user.age 30'
|
100
|
+
const [innerHelperName, ...innerArgs] = innerExpression.split(" "); // ['compare', 'user.age', '30']
|
101
|
+
const innerHelperFn = this.helpers[innerHelperName];
|
102
|
+
if (innerHelperFn) {
|
103
|
+
// Look up values for arguments, treat them as variables
|
104
|
+
const evaluatedArgs = innerArgs.map((arg) => this.lookup(arg, data) || arg);
|
105
|
+
console.log(evaluatedArgs);
|
106
|
+
// Ensure innerHelperFn can handle an array directly or accept rest parameters
|
107
|
+
const innerResult = innerHelperFn(evaluatedArgs.join(" "), data, innerTemplate);
|
108
|
+
// Apply the outer helper (e.g., ifHelper) with the result of the inner expression
|
109
|
+
const outerResult = helperFn(innerResult, data, innerTemplate);
|
110
|
+
if (typeof outerResult === "string" ||
|
111
|
+
typeof outerResult === "number") {
|
112
|
+
return string.replace(helperString, `${outerResult}`);
|
113
|
+
}
|
114
|
+
else {
|
115
|
+
return outerResult;
|
116
|
+
}
|
117
|
+
}
|
118
|
+
}
|
119
|
+
else {
|
120
|
+
// Handle the normal case where there is no inner expression
|
121
|
+
const result = helperFn(helperArg, data, innerTemplate);
|
122
|
+
if (typeof result === "string" || typeof result === "number") {
|
123
|
+
return string.replace(helperString, `${result}`);
|
124
|
+
}
|
125
|
+
else {
|
126
|
+
return result;
|
127
|
+
}
|
128
|
+
}
|
129
|
+
}
|
130
|
+
}
|
131
|
+
else {
|
132
|
+
return string;
|
133
|
+
}
|
134
|
+
}
|
135
|
+
// helpers
|
136
|
+
logHelper(varPath, data, innerTemplate) {
|
137
|
+
const value = this.lookup(varPath, data);
|
138
|
+
console.log(value);
|
139
|
+
return innerTemplate;
|
140
|
+
}
|
141
|
+
varHelper(string, data) {
|
142
|
+
return this.lookup(string, data);
|
143
|
+
}
|
144
|
+
lengthHelper(varPath, data) {
|
145
|
+
const value = this.lookup(varPath, data);
|
146
|
+
return Array.isArray(value) || typeof value === "string" ? value.length : 0;
|
147
|
+
}
|
148
|
+
eachHelper(string, data, innerTemplate) {
|
149
|
+
const array = this.lookup(string, data);
|
150
|
+
if (!Array.isArray(array)) {
|
151
|
+
throw new Error(`${data.helperArg} is not an array`);
|
152
|
+
}
|
153
|
+
return array.map((item) => this.applyTemplate(innerTemplate, { ...data, item }));
|
154
|
+
}
|
155
|
+
loopHelper(string, data, innerTemplate) {
|
156
|
+
const count = this.lookup(string, data);
|
157
|
+
return Array(+count)
|
158
|
+
.fill(null)
|
159
|
+
.map((item) => this.applyTemplate(innerTemplate, { ...data, item }));
|
160
|
+
}
|
161
|
+
ifHelper(condition, data, innerTemplate) {
|
162
|
+
console.log(condition, data);
|
163
|
+
return !!this.lookup(condition, data);
|
164
|
+
}
|
165
|
+
unlessHelper(condition, data, innerTemplate) {
|
166
|
+
return !!this.lookup(condition, data);
|
167
|
+
}
|
168
|
+
withHelper(scopePath, data, innerTemplate) {
|
169
|
+
const newContext = this.lookup(scopePath, data);
|
170
|
+
return this.applyTemplate(innerTemplate, { ...data, ...newContext });
|
171
|
+
}
|
172
|
+
setHelper(varName, data, innerTemplate) {
|
173
|
+
const [key, valuePath] = varName.split(" ");
|
174
|
+
const value = this.lookup(valuePath, data);
|
175
|
+
return this.applyTemplate(innerTemplate, { ...data, [key]: value });
|
176
|
+
}
|
177
|
+
concatHelper(args, data) {
|
178
|
+
const values = args.split(" ").map((arg) => this.lookup(arg, data) || arg);
|
179
|
+
return values.join(" ");
|
180
|
+
}
|
181
|
+
mathHelper(expression, data) {
|
182
|
+
const [left, operator, right] = expression.split(" ");
|
183
|
+
const leftValue = parseFloat(this.lookup(left, data));
|
184
|
+
const rightValue = parseFloat(this.lookup(right, data));
|
185
|
+
switch (operator) {
|
186
|
+
case "+":
|
187
|
+
return leftValue + rightValue;
|
188
|
+
case "-":
|
189
|
+
return leftValue - rightValue;
|
190
|
+
case "*":
|
191
|
+
return leftValue * rightValue;
|
192
|
+
case "/":
|
193
|
+
return leftValue / rightValue;
|
194
|
+
default:
|
195
|
+
return 0;
|
196
|
+
}
|
197
|
+
}
|
198
|
+
compareHelper(expression, data) {
|
199
|
+
const [left, operator, right] = expression.split(" ");
|
200
|
+
const leftValue = this.lookup(left, data);
|
201
|
+
const rightValue = this.lookup(right, data);
|
202
|
+
switch (operator) {
|
203
|
+
case "==":
|
204
|
+
return leftValue == rightValue;
|
205
|
+
case "===":
|
206
|
+
return leftValue === rightValue;
|
207
|
+
case "!=":
|
208
|
+
return leftValue != rightValue;
|
209
|
+
case "!==":
|
210
|
+
return leftValue !== rightValue;
|
211
|
+
case ">":
|
212
|
+
return leftValue > rightValue;
|
213
|
+
case "<":
|
214
|
+
return leftValue < rightValue;
|
215
|
+
case ">=":
|
216
|
+
return leftValue >= rightValue;
|
217
|
+
case "<=":
|
218
|
+
return leftValue <= rightValue;
|
219
|
+
default:
|
220
|
+
throw new Error(`Unknown operator: ${operator}`);
|
221
|
+
}
|
222
|
+
}
|
223
|
+
upperCaseHelper(varPath, data) {
|
224
|
+
const value = this.lookup(varPath, data);
|
225
|
+
return typeof value === "string" ? value.toUpperCase() : value;
|
226
|
+
}
|
227
|
+
lowerCaseHelper(varPath, data) {
|
228
|
+
const value = this.lookup(varPath, data);
|
229
|
+
return typeof value === "string" ? value.toLowerCase() : value;
|
230
|
+
}
|
231
|
+
jsonStringifyHelper(varPath, data) {
|
232
|
+
const value = this.lookup(varPath, data);
|
233
|
+
return JSON.stringify(value);
|
234
|
+
}
|
235
|
+
jsonParseHelper(varPath, data) {
|
236
|
+
const value = this.lookup(varPath, data);
|
237
|
+
return typeof value === "string" ? JSON.parse(value) : value;
|
238
|
+
}
|
239
|
+
dateHelper(varPath, data) {
|
240
|
+
const dateString = varPath.split(" ");
|
241
|
+
const date = new Date(dateString[0]);
|
242
|
+
return date.toISOString(); // Default format YYYY-MM-DD
|
243
|
+
}
|
244
|
+
repeatHelper(args, data) {
|
245
|
+
const [str, count] = args.split(" ");
|
246
|
+
const repeatData = this.lookup(str, data) || str;
|
247
|
+
const repeatCount = parseInt(count);
|
248
|
+
console.log(repeatCount, repeatData);
|
249
|
+
if (typeof repeatData === "string") {
|
250
|
+
return repeatData.repeat(repeatCount);
|
251
|
+
}
|
252
|
+
else if (typeof repeatData === "object") {
|
253
|
+
return Array(repeatCount).fill(repeatData);
|
254
|
+
}
|
255
|
+
}
|
256
|
+
sliceHelper(args, data) {
|
257
|
+
console.log(args);
|
258
|
+
const [varPath, start, end] = args
|
259
|
+
.split(" ")
|
260
|
+
.map((arg) => this.lookup(arg, data));
|
261
|
+
const value = this.lookup(varPath, data);
|
262
|
+
console.log(start, end, value);
|
263
|
+
if (Array.isArray(value)) {
|
264
|
+
return value.slice(start, end);
|
265
|
+
}
|
266
|
+
else if (typeof value === "string") {
|
267
|
+
return value.slice(start, end);
|
268
|
+
}
|
269
|
+
return value;
|
270
|
+
}
|
271
|
+
joinHelper(args, data) {
|
272
|
+
const [varPath, separator] = args.split(" ");
|
273
|
+
const value = this.lookup(varPath, data);
|
274
|
+
if (Array.isArray(value)) {
|
275
|
+
return value.join(separator);
|
276
|
+
}
|
277
|
+
return value;
|
278
|
+
}
|
279
|
+
findHelper(args, data) {
|
280
|
+
const [arrayPath, property, value] = args.split(" ");
|
281
|
+
const array = this.lookup(arrayPath, data);
|
282
|
+
if (Array.isArray(array)) {
|
283
|
+
return array.find((item) => this.lookup(property, item) === value);
|
284
|
+
}
|
285
|
+
return null;
|
286
|
+
}
|
287
|
+
mapHelper(args, data, innerTemplate) {
|
288
|
+
const [arrayPath] = args.split(" ");
|
289
|
+
const array = this.lookup(arrayPath, data);
|
290
|
+
if (!Array.isArray(array)) {
|
291
|
+
throw new Error(`${arrayPath} is not an array`);
|
292
|
+
}
|
293
|
+
console.log(innerTemplate);
|
294
|
+
return array.map((item) => this.applyTemplate(innerTemplate, { ...data, item }));
|
295
|
+
}
|
296
|
+
uniqueHelper(varPath, data) {
|
297
|
+
const value = this.lookup(varPath, data);
|
298
|
+
if (Array.isArray(value)) {
|
299
|
+
return Array.from(new Set(value));
|
300
|
+
}
|
301
|
+
return value;
|
302
|
+
}
|
303
|
+
randomHelper(varPath, data) {
|
304
|
+
const array = this.lookup(varPath, data);
|
305
|
+
if (Array.isArray(array)) {
|
306
|
+
const randomIndex = Math.floor(Math.random() * array.length);
|
307
|
+
return array[randomIndex];
|
308
|
+
}
|
309
|
+
return null;
|
310
|
+
}
|
311
|
+
reverseHelper(varPath, data) {
|
312
|
+
const value = this.lookup(varPath, data);
|
313
|
+
if (Array.isArray(value)) {
|
314
|
+
return value.reverse();
|
315
|
+
}
|
316
|
+
else if (typeof value === "string") {
|
317
|
+
return value.split("").reverse().join("");
|
318
|
+
}
|
319
|
+
return value;
|
320
|
+
}
|
321
|
+
existsHelper(varPath, data) {
|
322
|
+
const value = this.lookup(varPath, data);
|
323
|
+
return value !== undefined && value !== null;
|
324
|
+
}
|
325
|
+
}
|
326
|
+
//# sourceMappingURL=index.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
{
|
2
|
+
"name": "lang-json",
|
3
|
+
"version": "1.0.0",
|
4
|
+
"description": "A lib for templating json",
|
5
|
+
"main": "dist/esm/index.js",
|
6
|
+
"module": "dist/esm/index.js",
|
7
|
+
"types": "dist/esm/index.d.ts",
|
8
|
+
"type": "module",
|
9
|
+
"scripts": {
|
10
|
+
"build:cjs": "tsc --outDir dist/cjs --module commonjs",
|
11
|
+
"build:esm": "tsc --outDir dist/esm --module esnext",
|
12
|
+
"build": "npm run build:cjs && npm run build:esm",
|
13
|
+
"watch:cjs": "tsc --outDir dist/cjs --module commonjs --watch",
|
14
|
+
"watch:esm": "tsc --outDir dist/esm --module esnext --watch",
|
15
|
+
"watch": "npm run watch:esm & npm run watch:cjs",
|
16
|
+
"publish": "git add . && git commit -m /\"code updated\"/ && git push && npm publish"
|
17
|
+
},
|
18
|
+
"repository": {
|
19
|
+
"type": "git",
|
20
|
+
"url": "https://github.com/devanshdeveloper/json-template.git"
|
21
|
+
},
|
22
|
+
"keywords": [
|
23
|
+
"docx",
|
24
|
+
"utility",
|
25
|
+
"javascript"
|
26
|
+
],
|
27
|
+
"author": "Devansh Khetwani",
|
28
|
+
"license": "MIT",
|
29
|
+
"dependencies": {
|
30
|
+
"typescript": "^5.0.0"
|
31
|
+
},
|
32
|
+
"devDependencies": {
|
33
|
+
}
|
34
|
+
}
|
package/src/example.ts
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
type HelperFunction = (
|
2
|
+
context: any,
|
3
|
+
data: any,
|
4
|
+
engine: JsonTemplateEngine
|
5
|
+
) => any;
|
6
|
+
|
7
|
+
export class JsonTemplateEngine {
|
8
|
+
private helpers: Record<string, HelperFunction> = {};
|
9
|
+
|
10
|
+
constructor() {
|
11
|
+
console.log("registering helpers");
|
12
|
+
this.registerHelper("each", this.eachHelper.bind(this));
|
13
|
+
this.registerHelper("if", this.ifHelper.bind(this));
|
14
|
+
this.registerHelper("var", this.varHelper.bind(this));
|
15
|
+
}
|
16
|
+
|
17
|
+
// Register a custom helper
|
18
|
+
registerHelper(name: string, fn: HelperFunction) {
|
19
|
+
this.helpers[name] = fn;
|
20
|
+
}
|
21
|
+
|
22
|
+
// Core function to parse and apply template (now fully recursive)
|
23
|
+
applyTemplate(template: any, data: any): any {
|
24
|
+
console.log("template : ", template);
|
25
|
+
|
26
|
+
if (typeof template === "string") {
|
27
|
+
console.log("string template");
|
28
|
+
return this.replaceVars(template, data); // Replace string variables (dynamic)
|
29
|
+
} else if (Array.isArray(template)) {
|
30
|
+
console.log("Array template");
|
31
|
+
return template.map((item) => this.applyTemplate(item, data)); // Handle arrays recursively
|
32
|
+
} else if (typeof template === "object") {
|
33
|
+
console.log("object template");
|
34
|
+
const result: any = {};
|
35
|
+
for (const key in template) {
|
36
|
+
if (key.startsWith("{{#")) {
|
37
|
+
const helperName = key.slice(3, key.indexOf("}}"));
|
38
|
+
const helperArg = key.slice(key.indexOf(" ") + 1, -2).trim();
|
39
|
+
|
40
|
+
if (this.helpers[helperName]) {
|
41
|
+
const helperFn = this.helpers[helperName];
|
42
|
+
console.log("applying helper", helperName);
|
43
|
+
const helperResult = helperFn(
|
44
|
+
template[key],
|
45
|
+
{ ...data, helperArg },
|
46
|
+
this
|
47
|
+
);
|
48
|
+
console.log("helperRe", helperResult);
|
49
|
+
}
|
50
|
+
} else if (key.includes("{{else}}")) {
|
51
|
+
const elseKey = key.replace("{{else}}", "").trim();
|
52
|
+
result[elseKey] = this.applyTemplate(template[key], data);
|
53
|
+
} else {
|
54
|
+
console.log("going deep down");
|
55
|
+
result[key] = this.applyTemplate(template[key], data);
|
56
|
+
}
|
57
|
+
}
|
58
|
+
return result;
|
59
|
+
}
|
60
|
+
return template;
|
61
|
+
}
|
62
|
+
|
63
|
+
// Helper function to replace {{var}} with values from data
|
64
|
+
private replaceVars(template: any, data: any): any {
|
65
|
+
if (typeof template === "string") {
|
66
|
+
return template.replace(/{{\s*([\w.]+)\s*}}/g, (match, varPath) => {
|
67
|
+
return this.lookup(varPath, data) || "";
|
68
|
+
});
|
69
|
+
}
|
70
|
+
return template;
|
71
|
+
}
|
72
|
+
|
73
|
+
// Lookup a variable in data (supports nested keys like 'menu.name')
|
74
|
+
private lookup(varPath: string, data: any): any {
|
75
|
+
console.log("looking up", varPath, data);
|
76
|
+
return varPath.split(".").reduce((acc, part) => acc?.[part], data);
|
77
|
+
}
|
78
|
+
|
79
|
+
// Each helper {{#each}}
|
80
|
+
private eachHelper(context: any, data: any, engine: JsonTemplateEngine): any {
|
81
|
+
const array = engine.lookup(data.helperArg, data);
|
82
|
+
if (!Array.isArray(array)) {
|
83
|
+
throw new Error(`${data.helperArg} is not an array`);
|
84
|
+
}
|
85
|
+
|
86
|
+
// Recursively apply template for each item in the array
|
87
|
+
return array.map((item: any) =>
|
88
|
+
engine.applyTemplate(context, { ...data, ...item })
|
89
|
+
);
|
90
|
+
}
|
91
|
+
|
92
|
+
// If/else helper {{#if}}
|
93
|
+
private ifHelper(context: any, data: any, engine: JsonTemplateEngine): any {
|
94
|
+
const condition = engine.lookup(data.helperArg, data);
|
95
|
+
|
96
|
+
if (condition) {
|
97
|
+
return engine.applyTemplate(context, data);
|
98
|
+
} else {
|
99
|
+
const elseKey = Object.keys(context).find((key) =>
|
100
|
+
key.includes("{{else}}")
|
101
|
+
);
|
102
|
+
if (elseKey) {
|
103
|
+
return engine.applyTemplate(
|
104
|
+
context[elseKey.replace("{{else}}", "").trim()],
|
105
|
+
data
|
106
|
+
);
|
107
|
+
}
|
108
|
+
}
|
109
|
+
return null;
|
110
|
+
}
|
111
|
+
|
112
|
+
// Variable helper {{var}}
|
113
|
+
private varHelper(context: any, data: any): any {
|
114
|
+
return this.lookup(data.helperArg, data);
|
115
|
+
}
|
116
|
+
}
|
package/src/index.ts
ADDED
@@ -0,0 +1,358 @@
|
|
1
|
+
type HelperFunction = (context: any, data: any, innerTemplate: any) => any;
|
2
|
+
export class JsonTemplateEngine {
|
3
|
+
helpers: Record<string, HelperFunction> = {};
|
4
|
+
|
5
|
+
constructor() {
|
6
|
+
this.registerHelper("each", this.eachHelper.bind(this));
|
7
|
+
this.registerHelper("loop", this.loopHelper.bind(this));
|
8
|
+
this.registerHelper("if", this.ifHelper.bind(this));
|
9
|
+
this.registerHelper("with", this.withHelper.bind(this));
|
10
|
+
this.registerHelper("set", this.setHelper.bind(this));
|
11
|
+
this.registerHelper("unless", this.unlessHelper.bind(this));
|
12
|
+
this.registerHelper("log", this.logHelper.bind(this));
|
13
|
+
this.registerHelper("concat", this.concatHelper.bind(this));
|
14
|
+
this.registerHelper("length", this.lengthHelper.bind(this));
|
15
|
+
this.registerHelper("math", this.mathHelper.bind(this));
|
16
|
+
this.registerHelper("var", this.varHelper.bind(this));
|
17
|
+
this.registerHelper("compare", this.compareHelper.bind(this));
|
18
|
+
this.registerHelper("upperCase", this.upperCaseHelper.bind(this));
|
19
|
+
this.registerHelper("lowerCase", this.lowerCaseHelper.bind(this));
|
20
|
+
this.registerHelper("jsonStringify", this.jsonStringifyHelper.bind(this));
|
21
|
+
this.registerHelper("jsonParse", this.jsonParseHelper.bind(this));
|
22
|
+
this.registerHelper("date", this.dateHelper.bind(this));
|
23
|
+
this.registerHelper("repeat", this.repeatHelper.bind(this));
|
24
|
+
this.registerHelper("slice", this.sliceHelper.bind(this));
|
25
|
+
this.registerHelper("join", this.joinHelper.bind(this));
|
26
|
+
this.registerHelper("find", this.findHelper.bind(this));
|
27
|
+
this.registerHelper("map", this.mapHelper.bind(this));
|
28
|
+
this.registerHelper("unique", this.uniqueHelper.bind(this));
|
29
|
+
this.registerHelper("random", this.randomHelper.bind(this));
|
30
|
+
this.registerHelper("reverse", this.reverseHelper.bind(this));
|
31
|
+
this.registerHelper("exists", this.existsHelper.bind(this));
|
32
|
+
}
|
33
|
+
|
34
|
+
// Register a custom helper
|
35
|
+
registerHelper(name: string, fn: HelperFunction) {
|
36
|
+
this.helpers[name] = fn;
|
37
|
+
}
|
38
|
+
|
39
|
+
applyTemplate(template: any, data: any): any {
|
40
|
+
if (typeof template === "string") {
|
41
|
+
return this.proccessHelper(template, data);
|
42
|
+
} else if (Array.isArray(template)) {
|
43
|
+
return template.map((item, index) =>
|
44
|
+
this.applyTemplate(item, { ...data, currentItem: item, index })
|
45
|
+
);
|
46
|
+
} else if (typeof template === "object") {
|
47
|
+
let result: any = {};
|
48
|
+
for (const key in template) {
|
49
|
+
if (Object.prototype.hasOwnProperty.call(template, key)) {
|
50
|
+
const value = template[key];
|
51
|
+
|
52
|
+
const currentKeyResult = this.proccessHelper(key, data, value);
|
53
|
+
|
54
|
+
if (typeof currentKeyResult === "string") {
|
55
|
+
if (value) {
|
56
|
+
result[currentKeyResult] = this.applyTemplate(value, data);
|
57
|
+
} else {
|
58
|
+
result = currentKeyResult;
|
59
|
+
}
|
60
|
+
} else if (Array.isArray(currentKeyResult)) {
|
61
|
+
result = this.applyTemplate(currentKeyResult, data);
|
62
|
+
} else if (typeof currentKeyResult === "object") {
|
63
|
+
result = this.applyTemplate(currentKeyResult, data);
|
64
|
+
} else if (typeof currentKeyResult === "boolean") {
|
65
|
+
if (currentKeyResult) {
|
66
|
+
result = this.applyTemplate(value, data);
|
67
|
+
}
|
68
|
+
}
|
69
|
+
}
|
70
|
+
}
|
71
|
+
return result;
|
72
|
+
}
|
73
|
+
return template;
|
74
|
+
}
|
75
|
+
|
76
|
+
lookup(varPath: string, data: any): any {
|
77
|
+
if (typeof varPath !== "string") return varPath;
|
78
|
+
let normalizedPath = varPath.replace(/\[(\d+)\]/g, ".$1");
|
79
|
+
if (normalizedPath.startsWith(".")) {
|
80
|
+
normalizedPath = normalizedPath.slice(1);
|
81
|
+
}
|
82
|
+
const returnValue = normalizedPath.split(".").reduce((acc, part) => {
|
83
|
+
return acc?.[part];
|
84
|
+
}, data);
|
85
|
+
if (returnValue) {
|
86
|
+
return returnValue;
|
87
|
+
} else {
|
88
|
+
return varPath;
|
89
|
+
}
|
90
|
+
}
|
91
|
+
|
92
|
+
proccessHelper(string: string, data: any, innerTemplate?: any) {
|
93
|
+
const helperMatch = string.match(/{{#(\w+)\s+(.*?)}}/);
|
94
|
+
if (helperMatch) {
|
95
|
+
const [helperString, helperName, helperArg] = helperMatch;
|
96
|
+
const helperFn = this.helpers[helperName];
|
97
|
+
if (helperFn) {
|
98
|
+
// Check if there's an inner expression (e.g., compare user.age 30)
|
99
|
+
const innerExpressionMatch = helperArg.match(/\((.*?)\)/);
|
100
|
+
if (innerExpressionMatch) {
|
101
|
+
const innerExpression = innerExpressionMatch[1]; // e.g., 'compare user.age 30'
|
102
|
+
const [innerHelperName, ...innerArgs] = innerExpression.split(" "); // ['compare', 'user.age', '30']
|
103
|
+
const innerHelperFn = this.helpers[innerHelperName];
|
104
|
+
|
105
|
+
if (innerHelperFn) {
|
106
|
+
// Look up values for arguments, treat them as variables
|
107
|
+
const evaluatedArgs = innerArgs.map(
|
108
|
+
(arg) => this.lookup(arg, data) || arg
|
109
|
+
);
|
110
|
+
console.log(evaluatedArgs);
|
111
|
+
|
112
|
+
// Ensure innerHelperFn can handle an array directly or accept rest parameters
|
113
|
+
const innerResult = innerHelperFn(
|
114
|
+
evaluatedArgs.join(" "),
|
115
|
+
data,
|
116
|
+
innerTemplate
|
117
|
+
);
|
118
|
+
|
119
|
+
// Apply the outer helper (e.g., ifHelper) with the result of the inner expression
|
120
|
+
const outerResult = helperFn(innerResult, data, innerTemplate);
|
121
|
+
|
122
|
+
if (
|
123
|
+
typeof outerResult === "string" ||
|
124
|
+
typeof outerResult === "number"
|
125
|
+
) {
|
126
|
+
return string.replace(helperString, `${outerResult}`);
|
127
|
+
} else {
|
128
|
+
return outerResult;
|
129
|
+
}
|
130
|
+
}
|
131
|
+
} else {
|
132
|
+
// Handle the normal case where there is no inner expression
|
133
|
+
const result = helperFn(helperArg, data, innerTemplate);
|
134
|
+
if (typeof result === "string" || typeof result === "number") {
|
135
|
+
return string.replace(helperString, `${result}`);
|
136
|
+
} else {
|
137
|
+
return result;
|
138
|
+
}
|
139
|
+
}
|
140
|
+
}
|
141
|
+
} else {
|
142
|
+
return string;
|
143
|
+
}
|
144
|
+
}
|
145
|
+
|
146
|
+
// helpers
|
147
|
+
logHelper(varPath: string, data: any, innerTemplate: any) {
|
148
|
+
const value = this.lookup(varPath, data);
|
149
|
+
console.log(value);
|
150
|
+
|
151
|
+
return innerTemplate;
|
152
|
+
}
|
153
|
+
|
154
|
+
varHelper(string: any, data: any): any {
|
155
|
+
return this.lookup(string, data);
|
156
|
+
}
|
157
|
+
lengthHelper(varPath: string, data: any) {
|
158
|
+
const value = this.lookup(varPath, data);
|
159
|
+
return Array.isArray(value) || typeof value === "string" ? value.length : 0;
|
160
|
+
}
|
161
|
+
|
162
|
+
eachHelper(string: any, data: any, innerTemplate: any) {
|
163
|
+
const array = this.lookup(string, data);
|
164
|
+
if (!Array.isArray(array)) {
|
165
|
+
throw new Error(`${data.helperArg} is not an array`);
|
166
|
+
}
|
167
|
+
|
168
|
+
return array.map((item: any) =>
|
169
|
+
this.applyTemplate(innerTemplate, { ...data, item })
|
170
|
+
);
|
171
|
+
}
|
172
|
+
loopHelper(string: any, data: any, innerTemplate: any) {
|
173
|
+
const count = this.lookup(string, data);
|
174
|
+
|
175
|
+
return Array(+count)
|
176
|
+
.fill(null)
|
177
|
+
.map((item: any) => this.applyTemplate(innerTemplate, { ...data, item }));
|
178
|
+
}
|
179
|
+
|
180
|
+
ifHelper(condition: string, data: any, innerTemplate: any) {
|
181
|
+
console.log(condition, data);
|
182
|
+
|
183
|
+
return !!this.lookup(condition, data);
|
184
|
+
}
|
185
|
+
unlessHelper(condition: string, data: any, innerTemplate: any) {
|
186
|
+
return !!this.lookup(condition, data);
|
187
|
+
}
|
188
|
+
|
189
|
+
withHelper(scopePath: string, data: any, innerTemplate: any) {
|
190
|
+
const newContext = this.lookup(scopePath, data);
|
191
|
+
return this.applyTemplate(innerTemplate, { ...data, ...newContext });
|
192
|
+
}
|
193
|
+
setHelper(varName: string, data: any, innerTemplate: any) {
|
194
|
+
const [key, valuePath] = varName.split(" ");
|
195
|
+
|
196
|
+
const value = this.lookup(valuePath, data);
|
197
|
+
|
198
|
+
return this.applyTemplate(innerTemplate, { ...data, [key]: value });
|
199
|
+
}
|
200
|
+
concatHelper(args: string, data: any) {
|
201
|
+
const values = args.split(" ").map((arg) => this.lookup(arg, data) || arg);
|
202
|
+
return values.join(" ");
|
203
|
+
}
|
204
|
+
mathHelper(expression: string, data: any) {
|
205
|
+
const [left, operator, right] = expression.split(" ");
|
206
|
+
const leftValue = parseFloat(this.lookup(left, data));
|
207
|
+
const rightValue = parseFloat(this.lookup(right, data));
|
208
|
+
switch (operator) {
|
209
|
+
case "+":
|
210
|
+
return leftValue + rightValue;
|
211
|
+
case "-":
|
212
|
+
return leftValue - rightValue;
|
213
|
+
case "*":
|
214
|
+
return leftValue * rightValue;
|
215
|
+
case "/":
|
216
|
+
return leftValue / rightValue;
|
217
|
+
default:
|
218
|
+
return 0;
|
219
|
+
}
|
220
|
+
}
|
221
|
+
compareHelper(expression: string, data: any) {
|
222
|
+
const [left, operator, right] = expression.split(" ");
|
223
|
+
const leftValue = this.lookup(left, data);
|
224
|
+
const rightValue = this.lookup(right, data);
|
225
|
+
|
226
|
+
switch (operator) {
|
227
|
+
case "==":
|
228
|
+
return leftValue == rightValue;
|
229
|
+
case "===":
|
230
|
+
return leftValue === rightValue;
|
231
|
+
case "!=":
|
232
|
+
return leftValue != rightValue;
|
233
|
+
case "!==":
|
234
|
+
return leftValue !== rightValue;
|
235
|
+
case ">":
|
236
|
+
return leftValue > rightValue;
|
237
|
+
case "<":
|
238
|
+
return leftValue < rightValue;
|
239
|
+
case ">=":
|
240
|
+
return leftValue >= rightValue;
|
241
|
+
case "<=":
|
242
|
+
return leftValue <= rightValue;
|
243
|
+
default:
|
244
|
+
throw new Error(`Unknown operator: ${operator}`);
|
245
|
+
}
|
246
|
+
}
|
247
|
+
upperCaseHelper(varPath: string, data: any) {
|
248
|
+
const value = this.lookup(varPath, data);
|
249
|
+
return typeof value === "string" ? value.toUpperCase() : value;
|
250
|
+
}
|
251
|
+
lowerCaseHelper(varPath: string, data: any) {
|
252
|
+
const value = this.lookup(varPath, data);
|
253
|
+
return typeof value === "string" ? value.toLowerCase() : value;
|
254
|
+
}
|
255
|
+
jsonStringifyHelper(varPath: string, data: any) {
|
256
|
+
const value = this.lookup(varPath, data);
|
257
|
+
return JSON.stringify(value);
|
258
|
+
}
|
259
|
+
jsonParseHelper(varPath: string, data: any) {
|
260
|
+
const value = this.lookup(varPath, data);
|
261
|
+
return typeof value === "string" ? JSON.parse(value) : value;
|
262
|
+
}
|
263
|
+
dateHelper(varPath: string, data: any) {
|
264
|
+
const dateString = varPath.split(" ");
|
265
|
+
const date = new Date(dateString[0]);
|
266
|
+
return date.toISOString(); // Default format YYYY-MM-DD
|
267
|
+
}
|
268
|
+
repeatHelper(args: string, data: any) {
|
269
|
+
const [str, count] = args.split(" ");
|
270
|
+
const repeatData = this.lookup(str, data) || str;
|
271
|
+
const repeatCount = parseInt(count);
|
272
|
+
console.log(repeatCount, repeatData);
|
273
|
+
|
274
|
+
if (typeof repeatData === "string") {
|
275
|
+
return repeatData.repeat(repeatCount);
|
276
|
+
} else if (typeof repeatData === "object") {
|
277
|
+
return Array(repeatCount).fill(repeatData);
|
278
|
+
}
|
279
|
+
}
|
280
|
+
sliceHelper(args: string, data: any) {
|
281
|
+
console.log(args);
|
282
|
+
|
283
|
+
const [varPath, start, end] = args
|
284
|
+
.split(" ")
|
285
|
+
.map((arg) => this.lookup(arg, data));
|
286
|
+
const value = this.lookup(varPath, data);
|
287
|
+
console.log(start, end, value);
|
288
|
+
|
289
|
+
if (Array.isArray(value)) {
|
290
|
+
return value.slice(start, end);
|
291
|
+
} else if (typeof value === "string") {
|
292
|
+
return value.slice(start, end);
|
293
|
+
}
|
294
|
+
return value;
|
295
|
+
}
|
296
|
+
joinHelper(args: string, data: any) {
|
297
|
+
const [varPath, separator] = args.split(" ");
|
298
|
+
const value = this.lookup(varPath, data);
|
299
|
+
|
300
|
+
if (Array.isArray(value)) {
|
301
|
+
return value.join(separator);
|
302
|
+
}
|
303
|
+
return value;
|
304
|
+
}
|
305
|
+
findHelper(args: string, data: any) {
|
306
|
+
const [arrayPath, property, value] = args.split(" ");
|
307
|
+
const array = this.lookup(arrayPath, data);
|
308
|
+
|
309
|
+
if (Array.isArray(array)) {
|
310
|
+
return array.find((item) => this.lookup(property, item) === value);
|
311
|
+
}
|
312
|
+
return null;
|
313
|
+
}
|
314
|
+
mapHelper(args: string, data: any, innerTemplate: any) {
|
315
|
+
const [arrayPath] = args.split(" ");
|
316
|
+
const array = this.lookup(arrayPath, data);
|
317
|
+
|
318
|
+
if (!Array.isArray(array)) {
|
319
|
+
throw new Error(`${arrayPath} is not an array`);
|
320
|
+
}
|
321
|
+
console.log(innerTemplate);
|
322
|
+
|
323
|
+
return array.map((item) =>
|
324
|
+
this.applyTemplate(innerTemplate, { ...data, item })
|
325
|
+
);
|
326
|
+
}
|
327
|
+
uniqueHelper(varPath: string, data: any) {
|
328
|
+
const value = this.lookup(varPath, data);
|
329
|
+
|
330
|
+
if (Array.isArray(value)) {
|
331
|
+
return Array.from(new Set(value));
|
332
|
+
}
|
333
|
+
return value;
|
334
|
+
}
|
335
|
+
randomHelper(varPath: string, data: any) {
|
336
|
+
const array = this.lookup(varPath, data);
|
337
|
+
|
338
|
+
if (Array.isArray(array)) {
|
339
|
+
const randomIndex = Math.floor(Math.random() * array.length);
|
340
|
+
return array[randomIndex];
|
341
|
+
}
|
342
|
+
return null;
|
343
|
+
}
|
344
|
+
reverseHelper(varPath: string, data: any) {
|
345
|
+
const value = this.lookup(varPath, data);
|
346
|
+
|
347
|
+
if (Array.isArray(value)) {
|
348
|
+
return value.reverse();
|
349
|
+
} else if (typeof value === "string") {
|
350
|
+
return value.split("").reverse().join("");
|
351
|
+
}
|
352
|
+
return value;
|
353
|
+
}
|
354
|
+
existsHelper(varPath: string, data: any) {
|
355
|
+
const value = this.lookup(varPath, data);
|
356
|
+
return value !== undefined && value !== null;
|
357
|
+
}
|
358
|
+
}
|
package/tsconfig.json
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
{
|
2
|
+
"compilerOptions": {
|
3
|
+
"target": "ESNext",
|
4
|
+
"module": "ESNext",
|
5
|
+
"lib": ["DOM", "ESNext"],
|
6
|
+
"outDir": "./dist",
|
7
|
+
"declaration": true,
|
8
|
+
"sourceMap": true,
|
9
|
+
"strict": true,
|
10
|
+
"esModuleInterop": true,
|
11
|
+
"skipLibCheck": true,
|
12
|
+
"moduleResolution": "node"
|
13
|
+
},
|
14
|
+
"include": ["src/**/*"],
|
15
|
+
"exclude": ["node_modules", "dist"]
|
16
|
+
}
|
17
|
+
|