lang-json 1.0.0 → 1.0.1

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 (40) hide show
  1. package/babel.config.js +8 -0
  2. package/coverage/clover.xml +6 -0
  3. package/coverage/coverage-final.json +1 -0
  4. package/coverage/lcov-report/base.css +224 -0
  5. package/coverage/lcov-report/block-navigation.js +87 -0
  6. package/coverage/lcov-report/favicon.png +0 -0
  7. package/coverage/lcov-report/index.html +101 -0
  8. package/coverage/lcov-report/prettify.css +1 -0
  9. package/coverage/lcov-report/prettify.js +2 -0
  10. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  11. package/coverage/lcov-report/sorter.js +196 -0
  12. package/dist/esm/src/index.d.ts +18 -0
  13. package/dist/esm/src/index.js +415 -0
  14. package/dist/esm/src/index.js.map +1 -0
  15. package/dist/esm/src/modules/is-this/index.d.ts +136 -0
  16. package/dist/esm/src/modules/is-this/index.js +484 -0
  17. package/dist/esm/src/modules/is-this/index.js.map +1 -0
  18. package/dist/esm/tests/helpers.test.d.ts +1 -0
  19. package/dist/esm/tests/helpers.test.js +220 -0
  20. package/dist/esm/tests/helpers.test.js.map +1 -0
  21. package/dist/esm/tests/index.test.d.ts +1 -0
  22. package/dist/esm/tests/index.test.js +537 -0
  23. package/dist/esm/tests/index.test.js.map +1 -0
  24. package/jest.config.ts +212 -0
  25. package/package.json +19 -9
  26. package/src/index.ts +450 -296
  27. package/src/modules/is-this/index.ts +682 -0
  28. package/tests/helpers.test.ts +259 -0
  29. package/tests/index.test.ts +681 -0
  30. package/tsconfig.json +15 -16
  31. package/dist/esm/dump.js +0 -2
  32. package/dist/esm/dump.js.map +0 -1
  33. package/dist/esm/example.d.ts +0 -13
  34. package/dist/esm/example.js +0 -93
  35. package/dist/esm/example.js.map +0 -1
  36. package/dist/esm/index.d.ts +0 -36
  37. package/dist/esm/index.js +0 -326
  38. package/dist/esm/index.js.map +0 -1
  39. package/src/example.ts +0 -116
  40. /package/{dist/esm/dump.d.ts → coverage/lcov.info} +0 -0
package/src/index.ts CHANGED
@@ -1,44 +1,228 @@
1
- type HelperFunction = (context: any, data: any, innerTemplate: any) => any;
2
- export class JsonTemplateEngine {
3
- helpers: Record<string, HelperFunction> = {};
1
+ // import isThis from "@devanshdeveloper/is-this";
2
+ import isThis from "./modules/is-this/index";
3
+
4
+ type HelperFunction = (args: any, data: any, innerTemplate: any) => any;
5
+
6
+ class MemoryAddresses {
7
+ private storage: { [key: string]: any } = {};
8
+
9
+ // Helper function to generate a random string key
10
+ private generateKey(length: number = 4): string {
11
+ const chars =
12
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*";
13
+ let key = "";
14
+ for (let i = 0; i < length; i++) {
15
+ key += chars.charAt(Math.floor(Math.random() * chars.length));
16
+ }
17
+ return key;
18
+ }
19
+
20
+ // Store data with a random key
21
+ storeData(data: any): string {
22
+ const key = this.generateKey();
23
+ this.storage[key] = data;
24
+ return key;
25
+ }
26
+
27
+ getData(key: string): any | null {
28
+ return this.storage[key] !== undefined ? this.storage[key] : null;
29
+ }
30
+
31
+ removeData(key: string): void {
32
+ if (this.storage[key]) {
33
+ delete this.storage[key];
34
+ }
35
+ }
36
+ }
4
37
 
38
+ export default class LangJSON {
39
+ helpers: Record<string, HelperFunction> = {};
40
+ private memory: { [key: string]: any } = {};
5
41
  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));
42
+ // Registering Default Helpers
43
+
44
+ this.registerHelpers({
45
+ var: ([string]: any, data: any): any => {
46
+ return this.lookup(string, data);
47
+ },
48
+
49
+ // manupilating helpers
50
+ each: ([arr], data, innerTemplate): any => {
51
+ const result = [];
52
+ for (let i = 0; i < arr.length; i++) {
53
+ const element = arr[i];
54
+ result.push(
55
+ this.applyTemplate(innerTemplate, {
56
+ ...data,
57
+ item: element,
58
+ index: i,
59
+ })
60
+ );
61
+ }
62
+ return result;
63
+ },
64
+
65
+ loop: (number, data, innerTemplate): any => {
66
+ const result = [];
67
+ for (let i = 0; i < number; i++) {
68
+ result.push(
69
+ this.applyTemplate(innerTemplate, {
70
+ ...data,
71
+ index: i,
72
+ })
73
+ );
74
+ }
75
+ return result;
76
+ },
77
+
78
+ // String Helpers
79
+ uppercase: ([str]): any => str.toUpperCase(),
80
+ lowercase: ([str]): any => str.toLowerCase(),
81
+ capitalize: ([str]): any => str.charAt(0).toUpperCase() + str.slice(1),
82
+ trim: ([str]): any => str.trim(),
83
+ substring: ([str, start, length]): any =>
84
+ str.substring(start, start + length),
85
+ concat: ([...args]: any[]): any => args.join(""),
86
+ replace: ([str, search, replacement]): any =>
87
+ str.replace(new RegExp(search, "g"), replacement),
88
+ split: ([str, separator]): any => str.split(separator),
89
+ join: ([arr, separator]): any => arr.join(separator),
90
+ contains: ([str, substring]): any => str.includes(substring),
91
+ length: ([str]): any => str.length,
92
+ startsWith: ([str, prefix]): any => str.startsWith(prefix),
93
+ endsWith: ([str, suffix]): any => str.endsWith(suffix),
94
+ reverseString: ([str]): any => str.split("").reverse().join(""),
95
+ isEmpty: ([str]): any => !str || str.length === 0,
96
+ formatPhoneNumber: ([number]): any =>
97
+ number.replace(/(\d{3})(\d{3})(\d{4})/, "($1) $2-$3"),
98
+ toTitleCase: ([str]): any =>
99
+ str.toLowerCase().replace(/\b\w/g, (char: any) => char.toUpperCase()),
100
+ repeat: ([str, times]) => str.repeat(times),
101
+ // Mathematical Helpers
102
+ add: ([a, b]): any => a + b,
103
+ subtract: ([a, b]): any => a - b,
104
+ multiply: ([a, b]): any => a * b,
105
+ divide: ([a, b]): any => a / b,
106
+ modulo: ([a, b]): any => a % b,
107
+ max: ([...args]: any[]): any => Math.max(...args),
108
+ min: ([...args]: any[]): any => Math.min(...args),
109
+ round: ([num]): any => Math.round(num),
110
+ floor: ([num]): any => Math.floor(num),
111
+ ceil: ([num]): any => Math.ceil(num),
112
+
113
+ // Logical Helpers
114
+ if: ([condition, trueValue, falseValue]): any =>
115
+ condition ? trueValue : falseValue,
116
+ and: ([...conditions]: any[]): any => conditions.every(Boolean),
117
+ or: ([...conditions]: any[]): any => conditions.some(Boolean),
118
+ not: ([condition]: any): any => !condition,
119
+
120
+ // Date and Time Helpers
121
+ getCurrentDate: (): any => new Date().toISOString().split("T")[0],
122
+ getCurrentTime: (): any => new Date().toLocaleTimeString(),
123
+
124
+ // Array Helpers
125
+ arrayLength: ([arr]): any => arr.length,
126
+ arrayIncludes: ([arr, item]): any => arr.includes(item),
127
+ arrayJoin: ([arr, separator]): any => arr.join(separator),
128
+ arrayMap: ([arr, fn]): any => arr.map(fn),
129
+ arrayFilter: ([arr, fn]): any => arr.filter(fn),
130
+ arrayReduce: ([arr, fn, initial]): any => arr.reduce(fn, initial),
131
+ uniqueArray: ([arr]): any => [...new Set(arr)],
132
+ flattenArray: ([arr]): any => arr.flat(),
133
+ arraySort: ([arr, compareFn]): any => arr.sort(compareFn),
134
+ arrayFind: ([arr, fn]): any => arr.find(fn),
135
+ arrayEvery: ([arr, fn]): any => arr.every(fn),
136
+ arraySome: ([arr, fn]): any => arr.some(fn),
137
+
138
+ // Object Helpers
139
+ objectKeys: ([obj]): any => Object.keys(obj),
140
+ objectValues: ([obj]): any => Object.values(obj),
141
+ objectEntries: ([obj]): any => Object.entries(obj),
142
+ objectHasKey: ([obj, key]): any =>
143
+ Object.prototype.hasOwnProperty.call(obj, key),
144
+ mergeObjects: ([obj1, obj2]): any => ({ ...obj1, ...obj2 }),
145
+ deepClone: ([obj]): any => JSON.parse(JSON.stringify(obj)),
146
+ objectFreeze: ([obj]): any => Object.freeze(obj),
147
+ objectMergeDeep: ([obj1, obj2]): any => {
148
+ function mergeDeep(obj1: any, obj2: any): any {
149
+ const result = { ...obj1 };
150
+ for (const key in obj2) {
151
+ if (obj2[key] instanceof Object && !Array.isArray(obj2[key])) {
152
+ result[key] = mergeDeep(obj1[key], obj2[key]); // Use the named function 'mergeDeep'
153
+ } else {
154
+ result[key] = obj2[key];
155
+ }
156
+ }
157
+ return result;
158
+ }
159
+ return mergeDeep(obj1, obj2);
160
+ },
161
+
162
+ // Random Helpers
163
+ randomNumber: ([min, max]): any =>
164
+ Math.floor(Math.random() * (max - min + 1)) + min,
165
+ randomElement: ([arr]): any =>
166
+ arr[Math.floor(Math.random() * arr.length)],
167
+
168
+ // Formatting Helpers
169
+ currency: ([amount, currencySymbol]): any =>
170
+ `${currencySymbol}${amount.toFixed(2)}`,
171
+ percent: ([num]): any => `${(num * 100).toFixed(2)}%`,
172
+
173
+ // Miscellaneous Helpers
174
+ jsonStringify: ([obj]): any => JSON.stringify(obj),
175
+ jsonParse: ([str]): any => JSON.parse(str),
176
+ delay: ([ms]): any => new Promise((resolve) => setTimeout(resolve, ms)),
177
+ noop: (): any => {}, // No operation function
178
+ deepEqual: ([obj1, obj2]): any =>
179
+ JSON.stringify(obj1) === JSON.stringify(obj2), // Deep equality check
180
+
181
+ // Additional String Manipulation Helpers
182
+ snakeToCamel: ([str]): any =>
183
+ str.replace(/([-_]\w)/g, (g: any) => g[1].toUpperCase()),
184
+ camelToSnake: ([str]): any =>
185
+ str.replace(/([a-z])([A-Z])/g, "$1_$2").toLowerCase(),
186
+
187
+ // Additional Array Helpers
188
+ chunkArray: ([arr, size]): any =>
189
+ Array.from({ length: Math.ceil(arr.length / size) }, (_, i) =>
190
+ arr.slice(i * size, i * size + size)
191
+ ),
192
+ shuffleArray: ([arr]): any => arr.sort(() => Math.random() - 0.5),
193
+ removeDuplicates: ([arr]): any =>
194
+ arr.filter((item: any, index: any) => arr.indexOf(item) === index),
195
+
196
+ // Additional Object Helpers
197
+ objectMap: ([obj, fn]): any =>
198
+ Object.fromEntries(
199
+ Object.entries(obj).map(([key, value]) => [key, fn(value)])
200
+ ),
201
+ });
202
+
203
+ this.memory = new MemoryAddresses();
32
204
  }
33
205
 
34
- // Register a custom helper
206
+ // Managing Helpers
35
207
  registerHelper(name: string, fn: HelperFunction) {
36
208
  this.helpers[name] = fn;
37
209
  }
38
210
 
39
- applyTemplate(template: any, data: any): any {
211
+ registerHelpers(helpers: { [key: string]: HelperFunction }) {
212
+ for (const [name, fn] of Object.entries(helpers)) {
213
+ this.registerHelper(name, fn);
214
+ }
215
+ }
216
+
217
+ getHelper(name: string): HelperFunction | undefined {
218
+ return this.lookup(name, this.helpers);
219
+ }
220
+
221
+ applyTemplate(template: any, data: any, innerTemplate?: any): any {
40
222
  if (typeof template === "string") {
41
- return this.proccessHelper(template, data);
223
+ const stringResult = this.processHelper(template, data);
224
+ // console.log({ stringResult });
225
+ return stringResult;
42
226
  } else if (Array.isArray(template)) {
43
227
  return template.map((item, index) =>
44
228
  this.applyTemplate(item, { ...data, currentItem: item, index })
@@ -49,22 +233,17 @@ export class JsonTemplateEngine {
49
233
  if (Object.prototype.hasOwnProperty.call(template, key)) {
50
234
  const value = template[key];
51
235
 
52
- const currentKeyResult = this.proccessHelper(key, data, value);
236
+ const currentKeyResult = this.processHelper(key, data, value);
237
+ // console.log({ currentKeyResult });
53
238
 
54
- if (typeof currentKeyResult === "string") {
239
+ if (isThis.isArrayOrObject(currentKeyResult)) {
240
+ result = this.applyTemplate(currentKeyResult, data);
241
+ } else {
55
242
  if (value) {
56
- result[currentKeyResult] = this.applyTemplate(value, data);
243
+ result[`${currentKeyResult}`] = this.applyTemplate(value, data);
57
244
  } else {
58
245
  result = currentKeyResult;
59
246
  }
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
247
  }
69
248
  }
70
249
  }
@@ -73,286 +252,261 @@ export class JsonTemplateEngine {
73
252
  return template;
74
253
  }
75
254
 
76
- lookup(varPath: string, data: any): any {
255
+ lookup(varPath: string | number, data: any): any {
77
256
  if (typeof varPath !== "string") return varPath;
78
257
  let normalizedPath = varPath.replace(/\[(\d+)\]/g, ".$1");
79
258
  if (normalizedPath.startsWith(".")) {
80
259
  normalizedPath = normalizedPath.slice(1);
81
260
  }
82
- const returnValue = normalizedPath.split(".").reduce((acc, part) => {
261
+
262
+ let path = normalizedPath.split(".");
263
+ const returnValue = path.reduce((acc, part) => {
83
264
  return acc?.[part];
84
265
  }, data);
85
- if (returnValue) {
86
- return returnValue;
87
- } else {
88
- return varPath;
89
- }
266
+ return returnValue;
90
267
  }
91
268
 
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;
269
+ sanitizeArg(arg: any, helperName: any, data: any) {
270
+ if (helperName === "var") return arg;
271
+ if (arg.match(/^(['"])([\s\S]*?)\1$/g)) {
272
+ return arg.replace(
273
+ /^(['"])([\s\S]*?)\1$/g,
274
+ (_: any, __: any, innerText: any) => innerText
275
+ );
143
276
  }
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`);
277
+ if (isThis.isNumberString(arg)) {
278
+ return Number(arg);
166
279
  }
280
+ if (isThis.isBooleanString(arg)) {
281
+ return arg === "true";
282
+ }
283
+ const lookUpValue = this.lookup(arg, data);
284
+ const memoryValue = this.memory.getData(arg);
285
+ // console.log({ lookUpValue, memoryValue, arg });
167
286
 
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);
287
+ if (!isThis.isNullOrUndefined(memoryValue)) {
288
+ return memoryValue;
289
+ }
290
+ if (!isThis.isUndefined(lookUpValue)) {
291
+ return lookUpValue;
292
+ }
293
+ return arg;
187
294
  }
188
295
 
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(" ");
296
+ handleSpitStringArgs(stringArg: string) {
297
+ let currentQuote: string | null = null;
298
+ let result: string[] = [];
299
+ let currentPart = "";
300
+ for (let i = 0; i < stringArg.length; i++) {
301
+ const char = stringArg[i];
302
+
303
+ if (char === " " && currentQuote === null) {
304
+ if (currentPart) {
305
+ result.push(currentPart);
306
+ currentPart = "";
307
+ }
308
+ continue;
309
+ }
195
310
 
196
- const value = this.lookup(valuePath, data);
311
+ if (char === '"' || char === "'") {
312
+ if (currentQuote === char) {
313
+ currentQuote = null;
314
+ } else if (currentQuote === null) {
315
+ currentQuote = char;
316
+ }
317
+ continue;
318
+ }
197
319
 
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);
320
+ currentPart += char;
278
321
  }
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
322
 
300
- if (Array.isArray(value)) {
301
- return value.join(separator);
323
+ if (currentPart) {
324
+ result.push(currentPart);
302
325
  }
303
- return value;
326
+ return result;
304
327
  }
305
- findHelper(args: string, data: any) {
306
- const [arrayPath, property, value] = args.split(" ");
307
- const array = this.lookup(arrayPath, data);
308
328
 
309
- if (Array.isArray(array)) {
310
- return array.find((item) => this.lookup(property, item) === value);
329
+ processHelperArgs(helperArgs: string, data: any, innerTemplate: any): any {
330
+ const helperArgsMatches = [...helperArgs.matchAll(/\(([^()]+)\)/g)]?.[0];
331
+
332
+ if (helperArgsMatches) {
333
+ const innerString = helperArgsMatches[1];
334
+ const splitedInnerArgs = this.handleSpitStringArgs(innerString);
335
+ const helperName = splitedInnerArgs[0];
336
+ const helperArgsArray = splitedInnerArgs.slice(1);
337
+ const helper = this.getHelper(helperName);
338
+ if (!helper) {
339
+ throw new Error("Missing helper: " + helperName);
340
+ }
341
+ const splittedArgs = helperArgsArray.map((e: any) =>
342
+ this.sanitizeArg(e, helperName, data)
343
+ ) as any[];
344
+ let helperResult = helper(splittedArgs, data, innerTemplate);
345
+ // console.log({ helperName, helperArgs, splitedInnerArgs, helperResult });
346
+
347
+ if (isThis.isArrayOrObject(helperResult)) {
348
+ helperResult = this.memory.storeData(helperResult);
349
+ }
350
+ const returnValue = helperArgs.replace(
351
+ helperArgsMatches[0],
352
+ `"${helperResult}"`
353
+ );
354
+ return this.processHelperArgs(returnValue, data, innerTemplate);
355
+ } else {
356
+ return helperArgs;
311
357
  }
312
- return null;
313
358
  }
314
- mapHelper(args: string, data: any, innerTemplate: any) {
315
- const [arrayPath] = args.split(" ");
316
- const array = this.lookup(arrayPath, data);
317
359
 
318
- if (!Array.isArray(array)) {
319
- throw new Error(`${arrayPath} is not an array`);
320
- }
321
- console.log(innerTemplate);
360
+ processHelper(
361
+ string: string,
362
+ data: any,
363
+ innerTemplate?: any,
364
+ stringMatches?: any
365
+ ): any {
366
+ stringMatches = stringMatches
367
+ ? stringMatches
368
+ : [...string.matchAll(/{{#(\w+)\s*([^}]*)}}/g)]?.[0];
369
+
370
+ if (stringMatches) {
371
+ const capturedString = stringMatches[0];
372
+ const helperName = stringMatches[1];
373
+ const helperArgs = stringMatches[2];
374
+ const helper = this.getHelper(helperName);
375
+ if (!helper) {
376
+ throw new Error("Missing helper : " + helperName);
377
+ }
378
+ let splitedArgs = [];
379
+ if (!isThis.isEmptyString(helperArgs)) {
380
+ const processedHelperArgs = this.processHelperArgs(
381
+ helperArgs,
382
+ data,
383
+ innerTemplate
384
+ );
385
+
386
+ splitedArgs = this.handleSpitStringArgs(processedHelperArgs).map(
387
+ (e: any) => this.sanitizeArg(e, helperName, data)
388
+ ) as any[];
389
+ // console.log({
390
+ // string,
391
+ // helperName,
392
+ // helperArgs,
393
+ // processedHelperArgs,
394
+ // splitedArgs,
395
+ // });
396
+ }
322
397
 
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);
398
+ const helperResult = helper(splitedArgs, data, innerTemplate);
399
+ // console.log({ helperResult });
329
400
 
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);
401
+ if (isThis.isArrayOrObject(helperResult)) {
402
+ return helperResult;
403
+ }
346
404
 
347
- if (Array.isArray(value)) {
348
- return value.reverse();
349
- } else if (typeof value === "string") {
350
- return value.split("").reverse().join("");
405
+ const resultString = string.replace(capturedString, helperResult);
406
+ stringMatches = [...resultString.matchAll(/{{#(\w+)\s*([^}]*)}}/g)]?.[0];
407
+ // console.log({ resultString, stringMatches });
408
+
409
+ if (stringMatches) {
410
+ return this.processHelper(
411
+ resultString,
412
+ data,
413
+ innerTemplate,
414
+ stringMatches
415
+ );
416
+ } else {
417
+ if (
418
+ isThis.isBooleanString(resultString) &&
419
+ isThis.isBoolean(helperResult)
420
+ ) {
421
+ return helperResult;
422
+ }
423
+ if (isThis.isNullString(resultString) && isThis.isNull(helperResult)) {
424
+ return null;
425
+ }
426
+ if (
427
+ isThis.isUndefinedString(resultString) ||
428
+ isThis.isUndefined(helperResult)
429
+ ) {
430
+ return undefined;
431
+ }
432
+ if (
433
+ (isThis.isNumberString(resultString) ||
434
+ isThis.isNumber(helperResult)) &&
435
+ helperResult === parseFloat(resultString)
436
+ ) {
437
+ return helperResult;
438
+ }
439
+ return resultString;
440
+ }
441
+ } else {
442
+ return string;
351
443
  }
352
- return value;
353
- }
354
- existsHelper(varPath: string, data: any) {
355
- const value = this.lookup(varPath, data);
356
- return value !== undefined && value !== null;
357
444
  }
358
445
  }
446
+ // const langJson = new LangJSON();
447
+
448
+ // langJson.registerHelpers({
449
+ // upper: ([str]) => str.toUpperCase(),
450
+ // lower: ([str]) => str.toLowerCase(),
451
+ // isTrue: ([arg]) => arg === "true",
452
+ // getLength: ([arr]) => arr.length,
453
+ // });
454
+
455
+ // // Define a complex data structure
456
+ // const data = {
457
+ // user: {
458
+ // name: "Alice",
459
+ // age: 30,
460
+ // roles: ["admin", "editor"],
461
+ // address: {
462
+ // city: "Wonderland",
463
+ // zip: "12345",
464
+ // coordinates: { lat: 51.5074, long: -0.1278 },
465
+ // },
466
+ // preferences: {
467
+ // notifications: { email: true, sms: false },
468
+ // theme: "dark",
469
+ // },
470
+ // },
471
+ // isActive: "true",
472
+ // items: [
473
+ // { id: 1, name: "Item1", description: "First Item" },
474
+ // { id: 2, name: "Item2", description: "Second Item" },
475
+ // { id: 3, name: "Item3", description: "Third Item" },
476
+ // ],
477
+ // };
478
+
479
+ // // // Define a complex template
480
+ // const template = {
481
+ // "{{#upper user.name}}": {
482
+ // age: "{{#var user.age}}",
483
+ // active: "{{#isTrue isActive}}",
484
+ // address: {
485
+ // city: "{{#var user.address.city}}",
486
+ // zip: "{{#var user.address.zip}}",
487
+ // coordinates:
488
+ // "{{#var user.address.coordinates.lat}}, {{#var user.address.coordinates.long}}",
489
+ // },
490
+ // roles: {
491
+ // "{{#arrayJoin (var user.roles) ', '}}": {
492
+ // roleCount: "{{#getLength user.roles}}",
493
+ // roleList: "{{#var user.roles[0]}} and {{#var user.roles[1]}}",
494
+ // },
495
+ // },
496
+ // items: "{{#repeat (concat 'Item: ' (var items[0].name) ' ') 3}}",
497
+ // preferences: {
498
+ // theme: "{{#var user.preferences.theme}}",
499
+ // notificationStatus: {
500
+ // email: "{{#var user.preferences.notifications.email}}",
501
+ // sms: "{{#var user.preferences.notifications.sms}}",
502
+ // },
503
+ // },
504
+ // },
505
+ // };
506
+
507
+ // const result = langJson.applyTemplate(template, data);
508
+
509
+ // const returnValue = {
510
+ // 1: result,
511
+ // };
512
+ // console.log(JSON.stringify({ returnValue }, null, 2));