lang-json 1.0.0 → 1.0.2

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 (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));