lang-json 1.0.0 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. package/README.md +0 -0
  2. package/babel.config.js +8 -0
  3. package/coverage/clover.xml +6 -0
  4. package/coverage/coverage-final.json +1 -0
  5. package/coverage/lcov-report/base.css +224 -0
  6. package/coverage/lcov-report/block-navigation.js +87 -0
  7. package/coverage/lcov-report/favicon.png +0 -0
  8. package/coverage/lcov-report/index.html +101 -0
  9. package/coverage/lcov-report/prettify.css +1 -0
  10. package/coverage/lcov-report/prettify.js +2 -0
  11. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  12. package/coverage/lcov-report/sorter.js +196 -0
  13. package/dist/esm/src/index.d.ts +18 -0
  14. package/dist/esm/src/index.js +369 -0
  15. package/dist/esm/src/index.js.map +1 -0
  16. package/dist/esm/src/modules/is-this/index.d.ts +136 -0
  17. package/dist/esm/src/modules/is-this/index.js +484 -0
  18. package/dist/esm/src/modules/is-this/index.js.map +1 -0
  19. package/dist/esm/tests/helpers.test.d.ts +1 -0
  20. package/dist/esm/tests/helpers.test.js +284 -0
  21. package/dist/esm/tests/helpers.test.js.map +1 -0
  22. package/dist/esm/tests/index.test.d.ts +1 -0
  23. package/dist/esm/tests/index.test.js +537 -0
  24. package/dist/esm/tests/index.test.js.map +1 -0
  25. package/dist/esm/tests/readme.test.d.ts +1 -0
  26. package/dist/esm/tests/readme.test.js +73 -0
  27. package/dist/esm/tests/readme.test.js.map +1 -0
  28. package/jest.config.ts +212 -0
  29. package/package.json +40 -12
  30. package/src/index.ts +404 -295
  31. package/src/modules/is-this/index.ts +682 -0
  32. package/tests/helpers.test.ts +331 -0
  33. package/tests/index.test.ts +681 -0
  34. package/tests/readme.test.ts +78 -0
  35. package/tsconfig.json +15 -16
  36. package/dist/esm/dump.js +0 -2
  37. package/dist/esm/dump.js.map +0 -1
  38. package/dist/esm/example.d.ts +0 -13
  39. package/dist/esm/example.js +0 -93
  40. package/dist/esm/example.js.map +0 -1
  41. package/dist/esm/index.d.ts +0 -36
  42. package/dist/esm/index.js +0 -326
  43. package/dist/esm/index.js.map +0 -1
  44. package/src/example.ts +0 -116
  45. /package/{dist/esm/dump.d.ts → coverage/lcov.info} +0 -0
package/src/index.ts CHANGED
@@ -1,44 +1,224 @@
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
+ repeat: ([str, times]) => str.repeat(times),
97
+ // Mathematical Helpers
98
+ add: ([a, b]): any => a + b,
99
+ subtract: ([a, b]): any => a - b,
100
+ multiply: ([a, b]): any => a * b,
101
+ divide: ([a, b]): any => a / b,
102
+ modulo: ([a, b]): any => a % b,
103
+ max: ([...args]: any[]): any => Math.max(...args),
104
+ min: ([...args]: any[]): any => Math.min(...args),
105
+ round: ([num]): any => Math.round(num),
106
+ floor: ([num]): any => Math.floor(num),
107
+ ceil: ([num]): any => Math.ceil(num),
108
+
109
+ // Logical Helpers
110
+ if: ([condition, trueValue, falseValue]): any =>
111
+ condition ? trueValue : falseValue,
112
+ and: ([...conditions]: any[]): any => conditions.every(Boolean),
113
+ or: ([...conditions]: any[]): any => conditions.some(Boolean),
114
+ not: ([condition]: any): any => !condition,
115
+
116
+ // Date and Time Helpers
117
+ getCurrentDate: (): any => new Date().toISOString().split("T")[0],
118
+ getCurrentTime: (): any => new Date().toLocaleTimeString(),
119
+
120
+ // Array Helpers
121
+ arrayLength: ([arr]): any => arr.length,
122
+ arrayIncludes: ([arr, item]): any => arr.includes(item),
123
+ arrayJoin: ([arr, separator]): any => arr.join(separator),
124
+ // arrayMap: ([arr, fn]): any => arr.map(fn),
125
+ // arrayFilter: ([arr, fn]): any => arr.filter(fn),
126
+ // arrayReduce: ([arr, fn, initial]): any => arr.reduce(fn, initial),
127
+ uniqueArray: ([arr]): any => [...new Set(arr)],
128
+ flattenArray: ([arr]): any => arr.flat(),
129
+ // arraySort: ([arr, compareFn]): any => arr.sort(compareFn),
130
+ // arrayFind: ([arr, fn]): any => arr.find(fn),
131
+ // arrayEvery: ([arr, fn]): any => arr.every(fn),
132
+ // arraySome: ([arr, fn]): any => arr.some(fn),
133
+
134
+ // Object Helpers
135
+ objectKeys: ([obj]): any => Object.keys(obj),
136
+ objectValues: ([obj]): any => Object.values(obj),
137
+ objectEntries: ([obj]): any => Object.entries(obj),
138
+ objectHasKey: ([obj, key]): any =>
139
+ Object.prototype.hasOwnProperty.call(obj, key),
140
+ mergeObjects: ([obj1, obj2]): any => ({ ...obj1, ...obj2 }),
141
+ deepClone: ([obj]): any => JSON.parse(JSON.stringify(obj)),
142
+ objectFreeze: ([obj]): any => Object.freeze(obj),
143
+ objectMergeDeep: ([obj1, obj2]): any => {
144
+ function mergeDeep(obj1: any, obj2: any): any {
145
+ const result = { ...obj1 };
146
+ for (const key in obj2) {
147
+ if (obj2[key] instanceof Object && !Array.isArray(obj2[key])) {
148
+ result[key] = mergeDeep(obj1[key], obj2[key]); // Use the named function 'mergeDeep'
149
+ } else {
150
+ result[key] = obj2[key];
151
+ }
152
+ }
153
+ return result;
154
+ }
155
+ return mergeDeep(obj1, obj2);
156
+ },
157
+
158
+ // Random Helpers
159
+ randomNumber: ([min, max]): any =>
160
+ Math.floor(Math.random() * (max - min + 1)) + min,
161
+ randomElement: ([arr]): any =>
162
+ arr[Math.floor(Math.random() * arr.length)],
163
+
164
+ // Formatting Helpers
165
+ currency: ([amount, currencySymbol]): any =>
166
+ `${currencySymbol}${amount.toFixed(2)}`,
167
+ percent: ([num]): any => `${(num * 100).toFixed(2)}%`,
168
+
169
+ // Miscellaneous Helpers
170
+ jsonStringify: ([obj]): any => JSON.stringify(obj),
171
+ jsonParse: ([str]): any => JSON.parse(str),
172
+ delay: ([ms]): any => new Promise((resolve) => setTimeout(resolve, ms)),
173
+ noop: (): any => {}, // No operation function
174
+ deepEqual: ([obj1, obj2]): any =>
175
+ JSON.stringify(obj1) === JSON.stringify(obj2), // Deep equality check
176
+
177
+ // Additional String Manipulation Helpers
178
+ snakeToCamel: ([str]): any =>
179
+ str.replace(/([-_]\w)/g, (g: any) => g[1].toUpperCase()),
180
+ camelToSnake: ([str]): any =>
181
+ str.replace(/([a-z])([A-Z])/g, "$1_$2").toLowerCase(),
182
+
183
+ // Additional Array Helpers
184
+ chunkArray: ([arr, size]): any =>
185
+ Array.from({ length: Math.ceil(arr.length / size) }, (_, i) =>
186
+ arr.slice(i * size, i * size + size)
187
+ ),
188
+ shuffleArray: ([arr]): any => arr.sort(() => Math.random() - 0.5),
189
+ removeDuplicates: ([arr]): any =>
190
+ arr.filter((item: any, index: any) => arr.indexOf(item) === index),
191
+
192
+ // Additional Object Helpers
193
+ objectMap: ([obj, fn]): any =>
194
+ Object.fromEntries(
195
+ Object.entries(obj).map(([key, value]) => [key, fn(value)])
196
+ ),
197
+ });
198
+
199
+ this.memory = new MemoryAddresses();
32
200
  }
33
201
 
34
- // Register a custom helper
202
+ // Managing Helpers
35
203
  registerHelper(name: string, fn: HelperFunction) {
36
204
  this.helpers[name] = fn;
37
205
  }
38
206
 
39
- applyTemplate(template: any, data: any): any {
207
+ registerHelpers(helpers: { [key: string]: HelperFunction }) {
208
+ for (const [name, fn] of Object.entries(helpers)) {
209
+ this.registerHelper(name, fn);
210
+ }
211
+ }
212
+
213
+ getHelper(name: string): HelperFunction | undefined {
214
+ return this.lookup(name, this.helpers);
215
+ }
216
+
217
+ applyTemplate(template: any, data: any, innerTemplate?: any): any {
40
218
  if (typeof template === "string") {
41
- return this.proccessHelper(template, data);
219
+ const stringResult = this.processHelper(template, data);
220
+ // console.log({ stringResult });
221
+ return stringResult;
42
222
  } else if (Array.isArray(template)) {
43
223
  return template.map((item, index) =>
44
224
  this.applyTemplate(item, { ...data, currentItem: item, index })
@@ -49,22 +229,17 @@ export class JsonTemplateEngine {
49
229
  if (Object.prototype.hasOwnProperty.call(template, key)) {
50
230
  const value = template[key];
51
231
 
52
- const currentKeyResult = this.proccessHelper(key, data, value);
232
+ const currentKeyResult = this.processHelper(key, data, value);
233
+ // console.log({ currentKeyResult });
53
234
 
54
- if (typeof currentKeyResult === "string") {
235
+ if (isThis.isArrayOrObject(currentKeyResult)) {
236
+ result = this.applyTemplate(currentKeyResult, data);
237
+ } else {
55
238
  if (value) {
56
- result[currentKeyResult] = this.applyTemplate(value, data);
239
+ result[`${currentKeyResult}`] = this.applyTemplate(value, data);
57
240
  } else {
58
241
  result = currentKeyResult;
59
242
  }
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
243
  }
69
244
  }
70
245
  }
@@ -73,286 +248,220 @@ export class JsonTemplateEngine {
73
248
  return template;
74
249
  }
75
250
 
76
- lookup(varPath: string, data: any): any {
251
+ lookup(varPath: string | number, data: any): any {
252
+ // console.log({ varPath });
253
+
77
254
  if (typeof varPath !== "string") return varPath;
78
- let normalizedPath = varPath.replace(/\[(\d+)\]/g, ".$1");
255
+ let normalizedPath = varPath.replace(/\[(\d+)\]|\["(.*?)"\]/g, ".$1$2");
79
256
  if (normalizedPath.startsWith(".")) {
80
257
  normalizedPath = normalizedPath.slice(1);
81
258
  }
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
259
 
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
- }
260
+ let path = normalizedPath.split(".");
261
+ const returnValue = path.reduce((acc, part) => {
262
+ part = part.replace(
263
+ /^(['"])([\s\S]*?)\1$/g,
264
+ (_: any, __: any, innerText: any) => innerText
265
+ );
266
+ // console.log({ path, acc, part });
145
267
 
146
- // helpers
147
- logHelper(varPath: string, data: any, innerTemplate: any) {
148
- const value = this.lookup(varPath, data);
149
- console.log(value);
268
+ return acc?.[part];
269
+ }, data);
270
+ // console.log({ returnValue });
150
271
 
151
- return innerTemplate;
272
+ return returnValue;
152
273
  }
153
274
 
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
- }
275
+ sanitizeArg(arg: any, helperName: any, data: any) {
276
+ const isString = arg.match(/^(['"])([\s\S]*?)\1$/g);
161
277
 
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`);
278
+ if (helperName === "var" && !isString) return arg;
279
+ if (isString) {
280
+ // console.log({ arg, message: "into qoutes string" });
281
+ return arg.replace(
282
+ /^(['"])([\s\S]*?)\1$/g,
283
+ (_: any, __: any, innerText: any) => innerText
284
+ );
166
285
  }
286
+ if (isThis.isNumberString(arg)) {
287
+ // console.log({ arg, message: "into number string" });
167
288
 
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;
289
+ return Number(arg);
219
290
  }
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}`);
291
+ if (isThis.isBooleanString(arg)) {
292
+ return arg === "true";
245
293
  }
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);
294
+ const lookUpValue = this.lookup(arg, data);
295
+ const memoryValue = this.memory.getData(arg);
296
+ // console.log({ lookUpValue, memoryValue, arg });
297
+
298
+ if (!isThis.isNullOrUndefined(memoryValue)) {
299
+ return memoryValue;
278
300
  }
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);
301
+ if (!isThis.isUndefined(lookUpValue)) {
302
+ return lookUpValue;
293
303
  }
294
- return value;
304
+ return arg;
295
305
  }
296
- joinHelper(args: string, data: any) {
297
- const [varPath, separator] = args.split(" ");
298
- const value = this.lookup(varPath, data);
299
306
 
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);
307
+ handleSpitStringArgs(stringArg: string) {
308
+ let currentQuote: string | null = null;
309
+ let result: string[] = [];
310
+ let currentPart = "";
311
+ for (let i = 0; i < stringArg.length; i++) {
312
+ const char = stringArg[i];
313
+
314
+ if (char === " " && currentQuote === null) {
315
+ if (currentPart) {
316
+ result.push(currentPart);
317
+ currentPart = "";
318
+ }
319
+ continue;
320
+ }
308
321
 
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);
322
+ if (char === '"' || char === "'") {
323
+ if (currentQuote === char) {
324
+ currentQuote = null;
325
+ } else if (currentQuote === null) {
326
+ currentQuote = char;
327
+ }
328
+ }
317
329
 
318
- if (!Array.isArray(array)) {
319
- throw new Error(`${arrayPath} is not an array`);
330
+ currentPart += char;
320
331
  }
321
- console.log(innerTemplate);
322
332
 
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));
333
+ if (currentPart) {
334
+ result.push(currentPart);
332
335
  }
333
- return value;
336
+ return result;
334
337
  }
335
- randomHelper(varPath: string, data: any) {
336
- const array = this.lookup(varPath, data);
337
338
 
338
- if (Array.isArray(array)) {
339
- const randomIndex = Math.floor(Math.random() * array.length);
340
- return array[randomIndex];
339
+ processHelperArgs(helperArgs: string, data: any, innerTemplate: any): any {
340
+ const helperArgsMatches = [...helperArgs.matchAll(/\(([^()]+)\)/g)]?.[0];
341
+
342
+ if (helperArgsMatches) {
343
+ const innerString = helperArgsMatches[1];
344
+ const splitedInnerArgs = this.handleSpitStringArgs(innerString);
345
+ const helperName = splitedInnerArgs[0];
346
+ const helperArgsArray = splitedInnerArgs.slice(1);
347
+ const helper = this.getHelper(helperName);
348
+ if (!helper) {
349
+ throw new Error("Missing helper: " + helperName);
350
+ }
351
+ const splittedArgs = helperArgsArray.map((e: any) =>
352
+ this.sanitizeArg(e, helperName, data)
353
+ ) as any[];
354
+ // console.log({ helperName, helperArgs, helperArgsArray, splittedArgs });
355
+ let helperResult = helper(splittedArgs, data, innerTemplate);
356
+ // console.log({ helperResult });
357
+ let memorykey = null;
358
+ if (isThis.isArrayOrObject(helperResult)) {
359
+ memorykey = this.memory.storeData(helperResult);
360
+ }
361
+ const returnValue = helperArgs.replace(
362
+ helperArgsMatches[0],
363
+ memorykey ? memorykey : `"${helperResult}"`
364
+ );
365
+ return this.processHelperArgs(returnValue, data, innerTemplate);
366
+ } else {
367
+ return helperArgs;
341
368
  }
342
- return null;
343
369
  }
344
- reverseHelper(varPath: string, data: any) {
345
- const value = this.lookup(varPath, data);
346
370
 
347
- if (Array.isArray(value)) {
348
- return value.reverse();
349
- } else if (typeof value === "string") {
350
- return value.split("").reverse().join("");
371
+ processHelper(
372
+ string: string,
373
+ data: any,
374
+ innerTemplate?: any,
375
+ stringMatches?: any
376
+ ): any {
377
+ stringMatches = stringMatches
378
+ ? stringMatches
379
+ : [...string.matchAll(/{{#(\w+)\s*([^}]*)}}/g)]?.[0];
380
+
381
+ if (stringMatches) {
382
+ const capturedString = stringMatches[0];
383
+ const helperName = stringMatches[1];
384
+ const helperArgs = stringMatches[2];
385
+ const helper = this.getHelper(helperName);
386
+ if (!helper) {
387
+ throw new Error("Missing helper : " + helperName);
388
+ }
389
+ let splitedArgs = [];
390
+ if (!isThis.isEmptyString(helperArgs)) {
391
+ const processedHelperArgs = this.processHelperArgs(
392
+ helperArgs,
393
+ data,
394
+ innerTemplate
395
+ );
396
+
397
+ splitedArgs = this.handleSpitStringArgs(processedHelperArgs).map(
398
+ (e: any) => this.sanitizeArg(e, helperName, data)
399
+ ) as any[];
400
+ // console.log({
401
+ // string,
402
+ // helperName,
403
+ // helperArgs,
404
+ // processedHelperArgs,
405
+ // splitedArgs,
406
+ // });
407
+ }
408
+
409
+ const helperResult = helper(splitedArgs, data, innerTemplate);
410
+ // console.log({ helperResult });
411
+
412
+ if (isThis.isArrayOrObject(helperResult)) {
413
+ return helperResult;
414
+ }
415
+
416
+ const resultString = string.replace(capturedString, helperResult);
417
+ stringMatches = [...resultString.matchAll(/{{#(\w+)\s*([^}]*)}}/g)]?.[0];
418
+ // console.log({ resultString, stringMatches });
419
+
420
+ if (stringMatches) {
421
+ return this.processHelper(
422
+ resultString,
423
+ data,
424
+ innerTemplate,
425
+ stringMatches
426
+ );
427
+ } else {
428
+ if (
429
+ isThis.isBooleanString(resultString) &&
430
+ isThis.isBoolean(helperResult)
431
+ ) {
432
+ return helperResult;
433
+ }
434
+ if (isThis.isNullString(resultString) && isThis.isNull(helperResult)) {
435
+ return null;
436
+ }
437
+ if (
438
+ isThis.isUndefinedString(resultString) ||
439
+ isThis.isUndefined(helperResult)
440
+ ) {
441
+ return undefined;
442
+ }
443
+ if (
444
+ (isThis.isNumberString(resultString) ||
445
+ isThis.isNumber(helperResult)) &&
446
+ helperResult === parseFloat(resultString)
447
+ ) {
448
+ return helperResult;
449
+ }
450
+ return resultString;
451
+ }
452
+ } else {
453
+ return string;
351
454
  }
352
- return value;
353
- }
354
- existsHelper(varPath: string, data: any) {
355
- const value = this.lookup(varPath, data);
356
- return value !== undefined && value !== null;
357
455
  }
358
456
  }
457
+ // const langJson = new LangJSON();
458
+ // const template = {
459
+ // "{{#loop items.length}}": { name: "{{#var items[(var index)]}}" },
460
+ // };
461
+ // const result = langJson.applyTemplate(template, {
462
+ // items: ["Apple", "Banana", "Grapes"],
463
+ // });
464
+ // const returnValue = {
465
+ // 1: result,
466
+ // };
467
+ // console.log(JSON.stringify(returnValue, null, 2));