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.
- package/babel.config.js +8 -0
- package/coverage/clover.xml +6 -0
- package/coverage/coverage-final.json +1 -0
- package/coverage/lcov-report/base.css +224 -0
- package/coverage/lcov-report/block-navigation.js +87 -0
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +101 -0
- package/coverage/lcov-report/prettify.css +1 -0
- package/coverage/lcov-report/prettify.js +2 -0
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +196 -0
- package/dist/esm/src/index.d.ts +18 -0
- package/dist/esm/src/index.js +415 -0
- package/dist/esm/src/index.js.map +1 -0
- package/dist/esm/src/modules/is-this/index.d.ts +136 -0
- package/dist/esm/src/modules/is-this/index.js +484 -0
- package/dist/esm/src/modules/is-this/index.js.map +1 -0
- package/dist/esm/tests/helpers.test.d.ts +1 -0
- package/dist/esm/tests/helpers.test.js +220 -0
- package/dist/esm/tests/helpers.test.js.map +1 -0
- package/dist/esm/tests/index.test.d.ts +1 -0
- package/dist/esm/tests/index.test.js +537 -0
- package/dist/esm/tests/index.test.js.map +1 -0
- package/jest.config.ts +212 -0
- package/package.json +19 -9
- package/src/index.ts +450 -296
- package/src/modules/is-this/index.ts +682 -0
- package/tests/helpers.test.ts +259 -0
- package/tests/index.test.ts +681 -0
- package/tsconfig.json +15 -16
- package/dist/esm/dump.js +0 -2
- package/dist/esm/dump.js.map +0 -1
- package/dist/esm/example.d.ts +0 -13
- package/dist/esm/example.js +0 -93
- package/dist/esm/example.js.map +0 -1
- package/dist/esm/index.d.ts +0 -36
- package/dist/esm/index.js +0 -326
- package/dist/esm/index.js.map +0 -1
- package/src/example.ts +0 -116
- /package/{dist/esm/dump.d.ts → coverage/lcov.info} +0 -0
package/src/index.ts
CHANGED
@@ -1,44 +1,228 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
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
|
-
|
7
|
-
|
8
|
-
this.
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
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
|
-
//
|
206
|
+
// Managing Helpers
|
35
207
|
registerHelper(name: string, fn: HelperFunction) {
|
36
208
|
this.helpers[name] = fn;
|
37
209
|
}
|
38
210
|
|
39
|
-
|
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
|
-
|
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.
|
236
|
+
const currentKeyResult = this.processHelper(key, data, value);
|
237
|
+
// console.log({ currentKeyResult });
|
53
238
|
|
54
|
-
if (
|
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
|
-
|
261
|
+
|
262
|
+
let path = normalizedPath.split(".");
|
263
|
+
const returnValue = path.reduce((acc, part) => {
|
83
264
|
return acc?.[part];
|
84
265
|
}, data);
|
85
|
-
|
86
|
-
return returnValue;
|
87
|
-
} else {
|
88
|
-
return varPath;
|
89
|
-
}
|
266
|
+
return returnValue;
|
90
267
|
}
|
91
268
|
|
92
|
-
|
93
|
-
|
94
|
-
if (
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
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
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
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
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
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
|
-
|
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
|
-
|
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 (
|
301
|
-
|
323
|
+
if (currentPart) {
|
324
|
+
result.push(currentPart);
|
302
325
|
}
|
303
|
-
return
|
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
|
-
|
310
|
-
|
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
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
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
|
-
|
324
|
-
|
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
|
-
|
331
|
-
|
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
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
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));
|