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.
- package/README.md +0 -0
- 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 +369 -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 +284 -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/dist/esm/tests/readme.test.d.ts +1 -0
- package/dist/esm/tests/readme.test.js +73 -0
- package/dist/esm/tests/readme.test.js.map +1 -0
- package/jest.config.ts +212 -0
- package/package.json +40 -12
- package/src/index.ts +404 -295
- package/src/modules/is-this/index.ts +682 -0
- package/tests/helpers.test.ts +331 -0
- package/tests/index.test.ts +681 -0
- package/tests/readme.test.ts +78 -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,224 @@
|
|
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
|
+
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
|
-
//
|
202
|
+
// Managing Helpers
|
35
203
|
registerHelper(name: string, fn: HelperFunction) {
|
36
204
|
this.helpers[name] = fn;
|
37
205
|
}
|
38
206
|
|
39
|
-
|
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
|
-
|
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.
|
232
|
+
const currentKeyResult = this.processHelper(key, data, value);
|
233
|
+
// console.log({ currentKeyResult });
|
53
234
|
|
54
|
-
if (
|
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
|
-
|
93
|
-
const
|
94
|
-
|
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;
|
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
|
-
|
147
|
-
|
148
|
-
|
149
|
-
console.log(value);
|
268
|
+
return acc?.[part];
|
269
|
+
}, data);
|
270
|
+
// console.log({ returnValue });
|
150
271
|
|
151
|
-
return
|
272
|
+
return returnValue;
|
152
273
|
}
|
153
274
|
|
154
|
-
|
155
|
-
|
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
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
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
|
-
|
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
|
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
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
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
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
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
|
-
|
319
|
-
throw new Error(`${arrayPath} is not an array`);
|
330
|
+
currentPart += char;
|
320
331
|
}
|
321
|
-
console.log(innerTemplate);
|
322
332
|
|
323
|
-
|
324
|
-
|
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
|
336
|
+
return result;
|
334
337
|
}
|
335
|
-
randomHelper(varPath: string, data: any) {
|
336
|
-
const array = this.lookup(varPath, data);
|
337
338
|
|
338
|
-
|
339
|
-
|
340
|
-
|
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
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
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));
|