@trustme24/flext 1.10.0 → 1.10.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.
@@ -6,3 +6,4 @@ export { default as math } from './math';
6
6
  export { default as media } from './media';
7
7
  export { default as number } from './number';
8
8
  export { default as put } from './put';
9
+ export { default as string } from './string';
@@ -0,0 +1,5 @@
1
+ export declare function op(state: any): any[] | boolean;
2
+ export declare function json(state: any): any[];
3
+ export declare function check(state: any): boolean;
4
+ declare const _default: any;
5
+ export default _default;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trustme24/flext",
3
- "version": "1.10.0",
3
+ "version": "1.10.2",
4
4
  "description": "A Powerful Templating Engine",
5
5
  "keywords": ["templates", "templating engine", "modular templates", "handlebars"],
6
6
  "type": "module",
@@ -16,7 +16,7 @@
16
16
  },
17
17
  "scripts": {
18
18
  "start:test-app": "cd test/app && npm run test-app",
19
- "build:types": "tsc && tsc-alias",
19
+ "build:types": "tsc -p src/tsconfig.json && tsc-alias -p src/tsconfig.json",
20
20
  "build:css": "tailwindcss -i ./src/index.css -o ./dist/index.css --minify",
21
21
  "build-only": "bin/build.mjs && npm run build:types && npm run build:css",
22
22
  "build": "npm run build-only && vitest run",
@@ -26,7 +26,8 @@
26
26
  "prepare": "npm run build"
27
27
  },
28
28
  "files": [
29
- "dist/"
29
+ "dist/",
30
+ "src/"
30
31
  ],
31
32
  "author": "Kenny Romanov",
32
33
  "license": "MIT",
@@ -36,11 +37,11 @@
36
37
  "@babel/preset-env": "^7.29.0",
37
38
  "@babel/preset-typescript": "^7.28.5",
38
39
  "@handlebars/parser": "^2.2.2",
39
- "@tailwindcss/cli": "^4.1.18",
40
- "@types/node": "^25.2.0",
41
- "esbuild": "^0.27.2",
40
+ "@tailwindcss/cli": "^4.2.0",
41
+ "@types/node": "^25.3.0",
42
+ "esbuild": "^0.27.3",
42
43
  "esbuild-plugin-import-glob": "^0.1.1",
43
- "tailwindcss": "^4.1.18",
44
+ "tailwindcss": "^4.2.0",
44
45
  "tsc-alias": "^1.8.16",
45
46
  "typescript": "^5.9.3",
46
47
  "vitest": "^4.0.18"
package/src/env.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ declare module '*.css' {
2
+ const content: string
3
+ export default content
4
+ }
package/src/errors.ts ADDED
@@ -0,0 +1,51 @@
1
+
2
+ // Base Errors
3
+
4
+ export class BaseThrowable extends Error {
5
+ public name = 'BaseThrowable';
6
+
7
+ constructor(message: string, stack?: string|null) {
8
+ super(message);
9
+ if (stack) this.stack = stack;
10
+ }
11
+ }
12
+
13
+ export class BaseWarning extends BaseThrowable {
14
+ public name = 'BaseWarning';
15
+ }
16
+
17
+ export class BaseError extends BaseThrowable {
18
+ public name = 'BaseError';
19
+ }
20
+
21
+
22
+ // Specific Errors
23
+
24
+ export class PotentialLoopError extends BaseError {
25
+ public name = 'PotentialLoopError';
26
+
27
+ constructor(message: string = 'Potential loop detected: This might me an internal issue', stack?: string|null) {
28
+ super(message, stack);
29
+ }
30
+ }
31
+
32
+
33
+ // Template Errors
34
+
35
+ export class TemplateError extends BaseError {
36
+ public name = 'TemplateError';
37
+ }
38
+
39
+ export class TemplateSyntaxError extends TemplateError {
40
+ public name = 'TemplateSyntaxError';
41
+ }
42
+
43
+ export class TemplateDataValidationError extends TemplateError {
44
+ public name = 'TemplateDataValidationError';
45
+ declare public fieldName: string;
46
+
47
+ constructor(message: string = 'The entered data is invalid: This might me an internal issue', fieldName?: string|null) {
48
+ super(message);
49
+ if (fieldName) this.fieldName = fieldName;
50
+ }
51
+ }
package/src/index.css ADDED
@@ -0,0 +1 @@
1
+ @import "tailwindcss" source(".");
package/src/index.ts ADDED
@@ -0,0 +1,418 @@
1
+ import { AST } from '@handlebars/parser';
2
+ import { Obj, Macro, Field, FieldType, FieldValue, FieldValueOption, DataModel, DataModelNode, MetadataModelNode, CollectorFilterHandler, GetTemplateAstHandler, GetTemplateTitleHandler, GetTemplateMacroHandler } from '@/types';
3
+ import { BaseThrowable, BaseWarning, BaseError, PotentialLoopError, TemplateError, TemplateSyntaxError, TemplateDataValidationError } from '@/errors';
4
+ import * as types from '@/types';
5
+ import * as lib from '@/lib';
6
+ import * as errors from '@/errors';
7
+ import * as modules from './modules';
8
+
9
+
10
+ // Constants
11
+
12
+ export const DEFAULT_HELPER_NAME = '__default';
13
+
14
+ export const DEFAULT_MODEL_DEPTH = 10;
15
+
16
+
17
+ // Classes
18
+
19
+ export class SimpleFlext {
20
+ declare public ast: AST.Program;
21
+ declare public data: types.Obj;
22
+ declare public helpers: types.Obj;
23
+ public onGetProcessed: types.GetProcessedTemplateHandler = defaultGetProcessed;
24
+ public onGetAst: types.GetTemplateAstHandler = lib.getAst;
25
+
26
+ constructor(val: string|null = null, data: types.Obj = {}, helpers: types.Obj = {}) {
27
+ if (val) this.setTemplate(val);
28
+ this.setData({ ...this.data, ...data });
29
+ this.setHelpers({ ...this.helpers, ...helpers});
30
+ }
31
+
32
+ public setTemplate(val: string): this {
33
+
34
+ // Clearing the data
35
+
36
+ this.data = {};
37
+ this.helpers = {};
38
+
39
+
40
+ // Getting the AST
41
+
42
+ const template = this.onGetProcessed(val);
43
+
44
+ this.ast = this.onGetAst(template);
45
+
46
+
47
+ return this;
48
+ }
49
+
50
+ public setData(val: types.Obj): this {
51
+ this.data = val;
52
+ return this;
53
+ }
54
+
55
+ public setHelpers(val: types.Obj): this {
56
+ this.helpers = val;
57
+ return this;
58
+ }
59
+
60
+ public addHelper(name: string, val: any): this {
61
+ this.helpers[name] = val;
62
+ return this;
63
+ }
64
+
65
+ public setOnGetProcessed(val: types.GetProcessedTemplateHandler): this {
66
+ this.onGetProcessed = val;
67
+ return this;
68
+ }
69
+
70
+ public setOnGetAst(val: types.GetTemplateAstHandler): this {
71
+ this.onGetAst = val;
72
+ return this;
73
+ }
74
+
75
+ public getHtml(data?: types.Obj | null, helpers?: types.Obj | null): string {
76
+ const template = lib.getTemplate(this.ast);
77
+
78
+
79
+ // Doing some checks
80
+
81
+ if (!template)
82
+ throw new errors.BaseError('Flext: Unable to get HTML: No template');
83
+
84
+
85
+ return lib.getHtml(
86
+ template,
87
+ data ?? this.data,
88
+ helpers ?? this.helpers,
89
+ );
90
+ }
91
+
92
+ public async getCss(data?: types.Obj | null, options: types.Obj = {}): Promise<string> {
93
+ const template = lib.getTemplate(this.ast);
94
+ const helpersObj = options?.helpers ?? {};
95
+ const helpers = { ...this.helpers, ...helpersObj };
96
+
97
+
98
+ // Doing some checks
99
+
100
+ if (!template)
101
+ throw new errors.BaseError('Flext: Unable to get CSS: No template');
102
+
103
+
104
+ return await lib.getCss(
105
+ template,
106
+ data ?? this.data,
107
+ { ...options, helpers },
108
+ );
109
+ }
110
+
111
+ public get html(): string {
112
+ return this.getHtml();
113
+ }
114
+ }
115
+
116
+ export class Flext extends SimpleFlext {
117
+ declare public version: string;
118
+ declare public lang: string;
119
+ declare public title: string;
120
+ declare public timeZone: string;
121
+ declare public lineHeight: number;
122
+ declare public assets: types.Obj<Blob>;
123
+ declare public fields: types.Field[];
124
+ public onGetTitle: types.GetTemplateTitleHandler = lib.getHtmlH1;
125
+ public onGetMacro: types.GetTemplateMacroHandler = lib.getMacros;
126
+
127
+ constructor(val: string|null = null, data: types.Obj = {}, helpers: types.Obj = {}) {
128
+ super(null, data, helpers);
129
+
130
+ if (val) this.setTemplate(val);
131
+ this.setData({ ...this.data, ...data });
132
+ this.setHelpers({ ...this.helpers, ...helpers});
133
+ }
134
+
135
+ public useModule(...val: string[]): this {
136
+ for (const name of val)
137
+ this.addModule(name, modules[name]);
138
+
139
+ return this;
140
+ }
141
+
142
+ public setTemplate(val: string): this {
143
+
144
+ // Setting the template
145
+
146
+ super.setTemplate(val);
147
+
148
+
149
+ // Defining the variables
150
+
151
+ const [ titleStr ] = this.onGetTitle(this.ast);
152
+
153
+ const macros = this.onGetMacro(this.ast);
154
+
155
+
156
+ // Defining the functions
157
+
158
+ const getAll = (..._val: string[]): types.Macro[] | null => macros?.filter(m => lib.inarr(m?.name, ..._val)) ?? null;
159
+
160
+ const get = (_val: string): string|null => {
161
+ const [ macro ] = getAll(_val);
162
+ const [ param ] = macro?.params ?? [];
163
+
164
+ return param?.value ?? null;
165
+ };
166
+
167
+
168
+ // Getting the data
169
+
170
+ const version = get('v');
171
+ const lang = get('lang');
172
+ const title = get('title');
173
+ const timeZone = get('timeZone');
174
+ const modulesMacros = getAll('use');
175
+ const lineHeight = get('lineHeight');
176
+ const optionMacros = getAll('option');
177
+ const fieldMacros = getAll('group', 'field');
178
+
179
+
180
+ // Getting the fields
181
+
182
+ const fieldValueOptions = optionMacros?.map(lib.macroToFieldValueOption) ?? null;
183
+ const fields = fieldMacros?.map(lib.macroToField) ?? [];
184
+
185
+ lib.applyValueOptionsToFields(fieldValueOptions, fields);
186
+ lib.applyAbsoluteOrderToFields(fields);
187
+
188
+
189
+ // Getting the field groups
190
+
191
+ const fieldGroups = fields.filter(f => f?.extra?.macroName === 'group');
192
+
193
+ for (const fieldGroup of fieldGroups)
194
+ fieldGroup.type = 'object';
195
+
196
+
197
+ // Setting the data
198
+
199
+ if (version)
200
+ this.setVersion(version);
201
+
202
+ if (lang)
203
+ this.setLang(lang);
204
+
205
+ if (title || titleStr)
206
+ this.setTitle(title ?? lib.ensureTitle(titleStr));
207
+
208
+ if (timeZone)
209
+ this.setTimeZone(timeZone);
210
+
211
+ if (lineHeight)
212
+ this.setLineHeight(Number(lineHeight));
213
+
214
+ if (fields && fields?.length)
215
+ this.setFields(fields);
216
+
217
+
218
+ // Using the modules
219
+
220
+ const moduleNames = modulesMacros.map(lib.macroToModuleNames).flat();
221
+
222
+ this.useModule(...moduleNames);
223
+
224
+
225
+ return this;
226
+ }
227
+
228
+ public setVersion(val: string): this {
229
+ this.version = val;
230
+ return this;
231
+ }
232
+
233
+ public setLang(val: string): this {
234
+ this.lang = val;
235
+ return this;
236
+ }
237
+
238
+ public setTitle(val: string): this {
239
+ this.title = val;
240
+ return this;
241
+ }
242
+
243
+ public setTimeZone(val: string): this {
244
+ this.timeZone = val;
245
+ return this;
246
+ }
247
+
248
+ public setLineHeight(val: number): this {
249
+ this.lineHeight = val;
250
+ return this;
251
+ }
252
+
253
+ public setAssets(val: types.Obj<Blob>): this {
254
+ this.assets = val;
255
+ return this;
256
+ }
257
+
258
+ public addAsset(name: string, val: Blob): this {
259
+ this.assets[name] = val;
260
+ return this;
261
+ }
262
+
263
+ public setFields(val: types.Field[]): this {
264
+ this.fields = val;
265
+ return this;
266
+ }
267
+
268
+ public addModule(name: string, val: any): this {
269
+ const helpers = val?.helpers ?? {};
270
+
271
+
272
+ // Iterating for each helper
273
+
274
+ for (const helperName in helpers) {
275
+ if (!lib.has(helpers, helperName)) continue;
276
+
277
+
278
+ // Getting the data
279
+
280
+ const handle = helpers[helperName];
281
+
282
+ const isDefault = helperName === DEFAULT_HELPER_NAME;
283
+
284
+
285
+ // Adding the helper
286
+
287
+ const flext = this;
288
+
289
+ const helper = function (...args1: any[]): any {
290
+ const args = args1?.slice(0, -1) ?? [];
291
+ const options = args1[args1.length - 1] ?? {};
292
+ const namedArgs = options?.hash ?? {};
293
+ // @ts-ignore
294
+ const self = this;
295
+ const getContent = () => options?.fn(self) ?? null;
296
+
297
+ return handle({ flext, args, options, namedArgs, self, getContent });
298
+ }
299
+
300
+ if (isDefault)
301
+ this.addHelper(name, helper);
302
+ else
303
+ this.addHelper(name + ':' + helperName, helper);
304
+ }
305
+
306
+
307
+ return this;
308
+ }
309
+
310
+ public setOnGetTitle(val: types.GetTemplateTitleHandler): this {
311
+ this.onGetTitle = val;
312
+ return this;
313
+ }
314
+
315
+ public setOnGetMacro(val: types.GetTemplateMacroHandler): this {
316
+ this.onGetMacro = val;
317
+ return this;
318
+ }
319
+
320
+ public getDataModel(depth: number = DEFAULT_MODEL_DEPTH): types.MetadataModelNode[] {
321
+
322
+ // Defining the functions
323
+
324
+ /**
325
+ * TODO: kr: Costyl: Detects if it is a helper call (like 'put:noColor')
326
+ */
327
+ const isHelper = (node: types.DataModelNode): boolean => {
328
+ for (const helperName in this.helpers) {
329
+ if (!lib.has(this.helpers, helperName))
330
+ continue;
331
+ else if (node?.name === helperName)
332
+ return true;
333
+ }
334
+
335
+ return false;
336
+ }
337
+
338
+ /**
339
+ * TODO: kr: Costyl: Filters the helper calls (like 'put:noColor')
340
+ */
341
+ const isValid = (node: types.DataModelNode): boolean => !isHelper(node);
342
+
343
+ const dataModelNodeToMetadata = (node: types.DataModelNode): types.MetadataModelNode => lib.dataModelNodeToMetadata(node, this.fields, {}, depth);
344
+
345
+
346
+ // Getting the nodes
347
+
348
+ const model = lib.getDataModel(this.ast);
349
+ const nodes: types.DataModelNode[] = model?.$ ?? [];
350
+
351
+
352
+ return nodes.filter(isValid).map(dataModelNodeToMetadata);
353
+ }
354
+
355
+ public getValidationErrors(data?: types.Obj | null, depth: number = DEFAULT_MODEL_DEPTH): errors.TemplateDataValidationError[] {
356
+ return lib.getTemplateValidationErrorsByMetadata(data ?? this.data, this.model, depth);
357
+ }
358
+
359
+ public getIsValid(data?: types.Obj | null, depth: number = DEFAULT_MODEL_DEPTH): boolean {
360
+ const errors = this.getValidationErrors(data ?? this.data, depth);
361
+ return !errors?.length;
362
+ }
363
+
364
+ public get model(): types.MetadataModelNode[] {
365
+ return this.getDataModel();
366
+ }
367
+
368
+ public get validationErrors(): errors.TemplateDataValidationError[] {
369
+ return this.getValidationErrors();
370
+ }
371
+
372
+ public get errors(): errors.BaseError[] {
373
+ return this.validationErrors;
374
+ }
375
+
376
+ public get isValid(): boolean {
377
+ return this.getIsValid();
378
+ }
379
+ }
380
+
381
+
382
+ // Functions
383
+
384
+ export function defaultGetProcessed(val: string): string {
385
+ return val;
386
+ }
387
+
388
+
389
+ export default Flext;
390
+
391
+ export {
392
+ Obj,
393
+ Macro,
394
+ Field,
395
+ FieldType,
396
+ FieldValue,
397
+ FieldValueOption,
398
+ DataModel,
399
+ DataModelNode,
400
+ MetadataModelNode,
401
+ CollectorFilterHandler,
402
+ GetTemplateAstHandler,
403
+ GetTemplateTitleHandler,
404
+ GetTemplateMacroHandler,
405
+
406
+ BaseThrowable,
407
+ BaseWarning,
408
+ BaseError,
409
+ PotentialLoopError,
410
+ TemplateError,
411
+ TemplateSyntaxError,
412
+ TemplateDataValidationError,
413
+
414
+ types,
415
+ lib,
416
+ errors,
417
+ modules,
418
+ };