@reidelsaltres/pureper 0.1.156 → 0.1.160

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 (92) hide show
  1. package/out/foundation/api/Observer.d.ts +30 -0
  2. package/out/foundation/api/Observer.d.ts.map +1 -1
  3. package/out/foundation/api/Observer.js +48 -0
  4. package/out/foundation/api/Observer.js.map +1 -1
  5. package/out/foundation/component_api/Attribute.d.ts.map +1 -1
  6. package/out/foundation/component_api/Attribute.js +1 -0
  7. package/out/foundation/component_api/Attribute.js.map +1 -1
  8. package/out/foundation/engine/BalancedParser.d.ts +58 -0
  9. package/out/foundation/engine/BalancedParser.d.ts.map +1 -0
  10. package/out/foundation/engine/BalancedParser.js +301 -0
  11. package/out/foundation/engine/BalancedParser.js.map +1 -0
  12. package/out/foundation/engine/EscapeHandler.d.ts +27 -0
  13. package/out/foundation/engine/EscapeHandler.d.ts.map +1 -0
  14. package/out/foundation/engine/EscapeHandler.js +47 -0
  15. package/out/foundation/engine/EscapeHandler.js.map +1 -0
  16. package/out/foundation/engine/Expression.d.ts +83 -0
  17. package/out/foundation/engine/Expression.d.ts.map +1 -0
  18. package/out/foundation/engine/Expression.js +256 -0
  19. package/out/foundation/engine/Expression.js.map +1 -0
  20. package/out/foundation/engine/Rule.d.ts +83 -0
  21. package/out/foundation/engine/Rule.d.ts.map +1 -0
  22. package/out/foundation/engine/Rule.js +69 -0
  23. package/out/foundation/engine/Rule.js.map +1 -0
  24. package/out/foundation/engine/Scope.d.ts +57 -0
  25. package/out/foundation/engine/Scope.d.ts.map +1 -0
  26. package/out/foundation/engine/Scope.js +147 -0
  27. package/out/foundation/engine/Scope.js.map +1 -0
  28. package/out/foundation/engine/TemplateEngine.d.ts +79 -0
  29. package/out/foundation/engine/TemplateEngine.d.ts.map +1 -0
  30. package/out/foundation/engine/TemplateEngine.js +187 -0
  31. package/out/foundation/engine/TemplateEngine.js.map +1 -0
  32. package/out/foundation/engine/TemplateInstance.d.ts +121 -0
  33. package/out/foundation/engine/TemplateInstance.d.ts.map +1 -0
  34. package/out/foundation/engine/TemplateInstance.js +255 -0
  35. package/out/foundation/engine/TemplateInstance.js.map +1 -0
  36. package/out/foundation/engine/exceptions/TemplateExceptions.d.ts +21 -0
  37. package/out/foundation/engine/exceptions/TemplateExceptions.d.ts.map +1 -0
  38. package/out/foundation/engine/exceptions/TemplateExceptions.js +26 -0
  39. package/out/foundation/engine/exceptions/TemplateExceptions.js.map +1 -0
  40. package/out/foundation/engine/index.d.ts +18 -0
  41. package/out/foundation/engine/index.d.ts.map +1 -0
  42. package/out/foundation/engine/index.js +19 -0
  43. package/out/foundation/engine/index.js.map +1 -0
  44. package/out/foundation/engine/rules/attribute/EventRule.d.ts +22 -0
  45. package/out/foundation/engine/rules/attribute/EventRule.d.ts.map +1 -0
  46. package/out/foundation/engine/rules/attribute/EventRule.js +129 -0
  47. package/out/foundation/engine/rules/attribute/EventRule.js.map +1 -0
  48. package/out/foundation/engine/rules/attribute/InjectionRule.d.ts +20 -0
  49. package/out/foundation/engine/rules/attribute/InjectionRule.d.ts.map +1 -0
  50. package/out/foundation/engine/rules/attribute/InjectionRule.js +108 -0
  51. package/out/foundation/engine/rules/attribute/InjectionRule.js.map +1 -0
  52. package/out/foundation/engine/rules/attribute/RefRule.d.ts +23 -0
  53. package/out/foundation/engine/rules/attribute/RefRule.d.ts.map +1 -0
  54. package/out/foundation/engine/rules/attribute/RefRule.js +98 -0
  55. package/out/foundation/engine/rules/attribute/RefRule.js.map +1 -0
  56. package/out/foundation/engine/rules/syntax/ExpressionRule.d.ts +19 -0
  57. package/out/foundation/engine/rules/syntax/ExpressionRule.d.ts.map +1 -0
  58. package/out/foundation/engine/rules/syntax/ExpressionRule.js +82 -0
  59. package/out/foundation/engine/rules/syntax/ExpressionRule.js.map +1 -0
  60. package/out/foundation/engine/rules/syntax/ForRule.d.ts +19 -0
  61. package/out/foundation/engine/rules/syntax/ForRule.d.ts.map +1 -0
  62. package/out/foundation/engine/rules/syntax/ForRule.js +226 -0
  63. package/out/foundation/engine/rules/syntax/ForRule.js.map +1 -0
  64. package/out/foundation/engine/rules/syntax/IfRule.d.ts +17 -0
  65. package/out/foundation/engine/rules/syntax/IfRule.d.ts.map +1 -0
  66. package/out/foundation/engine/rules/syntax/IfRule.js +220 -0
  67. package/out/foundation/engine/rules/syntax/IfRule.js.map +1 -0
  68. package/out/foundation/worker/Router.d.ts.map +1 -1
  69. package/out/foundation/worker/Router.js.map +1 -1
  70. package/out/index.d.ts +3 -0
  71. package/out/index.d.ts.map +1 -1
  72. package/out/index.js +3 -0
  73. package/out/index.js.map +1 -1
  74. package/package.json +1 -1
  75. package/src/foundation/api/Observer.ts +60 -0
  76. package/src/foundation/component_api/Attribute.ts +1 -0
  77. package/src/foundation/engine/BalancedParser.ts +353 -0
  78. package/src/foundation/engine/EscapeHandler.ts +54 -0
  79. package/src/foundation/engine/Expression.ts +285 -0
  80. package/src/foundation/engine/Rule.ts +136 -0
  81. package/src/foundation/engine/Scope.ts +166 -0
  82. package/src/foundation/engine/TemplateEngine.ts +243 -0
  83. package/src/foundation/engine/TemplateInstance.ts +355 -0
  84. package/src/foundation/engine/exceptions/TemplateExceptions.ts +27 -0
  85. package/src/foundation/engine/rules/attribute/EventRule.ts +171 -0
  86. package/src/foundation/engine/rules/attribute/InjectionRule.ts +140 -0
  87. package/src/foundation/engine/rules/attribute/RefRule.ts +119 -0
  88. package/src/foundation/engine/rules/syntax/ExpressionRule.ts +102 -0
  89. package/src/foundation/engine/rules/syntax/ForRule.ts +267 -0
  90. package/src/foundation/engine/rules/syntax/IfRule.ts +261 -0
  91. package/src/foundation/worker/Router.ts +1 -1
  92. package/src/index.ts +9 -0
@@ -0,0 +1,136 @@
1
+ import Scope from './Scope.js';
2
+ import Expression from './Expression.js';
3
+
4
+ /**
5
+ * RuleMatch - результат поиска Rule в шаблоне
6
+ */
7
+ export interface RuleMatch {
8
+ /** Полное совпадение включая синтаксис Rule */
9
+ fullMatch: string;
10
+ /** Начальная позиция в исходной строке */
11
+ start: number;
12
+ /** Конечная позиция в исходной строке */
13
+ end: number;
14
+ /** Дополнительные данные специфичные для Rule */
15
+ data?: Record<string, any>;
16
+ }
17
+
18
+ /**
19
+ * RuleResult - результат выполнения Rule
20
+ */
21
+ export interface RuleResult {
22
+ /** HTML-результат для замены */
23
+ output: string;
24
+ /** Использованные Observable для отслеживания */
25
+ observables?: any[];
26
+ /** Дочерние Rule (для вложенных структур) */
27
+ children?: Rule[];
28
+ }
29
+
30
+ /**
31
+ * RuleType - тип Rule
32
+ */
33
+ export type RuleType = 'syntax' | 'attribute';
34
+
35
+ /**
36
+ * Rule - базовый абстрактный класс для всех правил шаблонизатора.
37
+ */
38
+ export default abstract class Rule {
39
+ /** Уникальное имя правила */
40
+ public abstract readonly name: string;
41
+
42
+ /** Тип правила: syntax или attribute */
43
+ public abstract readonly type: RuleType;
44
+
45
+ /** Приоритет выполнения (меньше = раньше) */
46
+ public readonly priority: number = 100;
47
+
48
+ /**
49
+ * Найти все вхождения этого Rule в шаблоне.
50
+ * @param template - исходный шаблон
51
+ * @returns массив найденных совпадений
52
+ */
53
+ public abstract find(template: string): RuleMatch[];
54
+
55
+ /**
56
+ * Выполнить Rule и вернуть результат.
57
+ * @param match - найденное совпадение
58
+ * @param scope - текущий Scope
59
+ * @param engine - ссылка на TemplateEngine (для рекурсивной обработки)
60
+ */
61
+ public abstract execute(
62
+ match: RuleMatch,
63
+ scope: Scope,
64
+ engine?: any // TemplateEngine, circular dependency workaround
65
+ ): RuleResult | Promise<RuleResult>;
66
+
67
+ /**
68
+ * Проверить, поддерживает ли Rule Observable значения
69
+ */
70
+ public supportsObservable(): boolean {
71
+ return true;
72
+ }
73
+ }
74
+
75
+ /**
76
+ * SyntaxRule - базовый класс для синтаксических правил.
77
+ * Синтаксические правила могут быть в любом месте шаблона (кроме атрибутов).
78
+ */
79
+ export abstract class SyntaxRule extends Rule {
80
+ public readonly type: RuleType = 'syntax';
81
+ }
82
+
83
+ /**
84
+ * AttributeRule - базовый класс для атрибутивных правил.
85
+ * Атрибутивные правила работают только внутри HTML-тегов.
86
+ */
87
+ export abstract class AttributeRule extends Rule {
88
+ public readonly type: RuleType = 'attribute';
89
+
90
+ /**
91
+ * Получить элемент, к которому применяется атрибут.
92
+ * @param template - шаблон
93
+ * @param attributePosition - позиция атрибута
94
+ * @returns информация об элементе
95
+ */
96
+ protected findParentElement(
97
+ template: string,
98
+ attributePosition: number
99
+ ): { tagName: string; tagStart: number; tagEnd: number } | null {
100
+ // Find opening < before attribute
101
+ let tagStart = attributePosition;
102
+ while (tagStart > 0 && template[tagStart] !== '<') {
103
+ tagStart--;
104
+ }
105
+
106
+ if (template[tagStart] !== '<') {
107
+ return null;
108
+ }
109
+
110
+ // Extract tag name
111
+ let nameEnd = tagStart + 1;
112
+ while (nameEnd < template.length && /[a-zA-Z0-9_-]/.test(template[nameEnd])) {
113
+ nameEnd++;
114
+ }
115
+ const tagName = template.slice(tagStart + 1, nameEnd);
116
+
117
+ // Find closing >
118
+ let tagEnd = attributePosition;
119
+ let inString = false;
120
+ let stringChar = '';
121
+ while (tagEnd < template.length) {
122
+ const ch = template[tagEnd];
123
+ if (!inString && (ch === '"' || ch === "'")) {
124
+ inString = true;
125
+ stringChar = ch;
126
+ } else if (inString && ch === stringChar) {
127
+ inString = false;
128
+ } else if (!inString && ch === '>') {
129
+ break;
130
+ }
131
+ tagEnd++;
132
+ }
133
+
134
+ return { tagName, tagStart, tagEnd: tagEnd + 1 };
135
+ }
136
+ }
@@ -0,0 +1,166 @@
1
+ /**
2
+ * Scope - класс для работы с контекстом переменных и функций.
3
+ * Поддерживает объединение нескольких Scope, извлечение полей из объектов и классов.
4
+ */
5
+ export default class Scope {
6
+ private variables: Record<string, any> = {};
7
+ private readonly debugWarnings: boolean;
8
+
9
+ constructor(options?: { debugWarnings?: boolean }) {
10
+ this.debugWarnings = options?.debugWarnings ?? true;
11
+ }
12
+
13
+ /**
14
+ * Получить все переменные Scope как Record
15
+ */
16
+ public getVariables(): Record<string, any> {
17
+ return { ...this.variables };
18
+ }
19
+
20
+ /**
21
+ * Установить переменную в Scope
22
+ */
23
+ public set(key: string, value: any): void {
24
+ if (this.debugWarnings && key in this.variables) {
25
+ console.warn(`[Scope] Warning: Variable "${key}" is being overwritten`);
26
+ }
27
+ this.variables[key] = value;
28
+ }
29
+
30
+ /**
31
+ * Получить переменную из Scope
32
+ */
33
+ public get(key: string): any {
34
+ return this.variables[key];
35
+ }
36
+
37
+ /**
38
+ * Проверить наличие переменной
39
+ */
40
+ public has(key: string): boolean {
41
+ return key in this.variables;
42
+ }
43
+
44
+ /**
45
+ * Удалить переменную из Scope
46
+ */
47
+ public delete(key: string): boolean {
48
+ if (key in this.variables) {
49
+ delete this.variables[key];
50
+ return true;
51
+ }
52
+ return false;
53
+ }
54
+
55
+ /**
56
+ * Объединить другой Scope или объект в текущий Scope.
57
+ * При конфликте имён выводится предупреждение, последнее значение имеет приоритет.
58
+ */
59
+ public merge(source: Scope | Record<string, any> | object): Scope {
60
+ const sourceVars = source instanceof Scope
61
+ ? source.getVariables()
62
+ : this.extractFromObject(source);
63
+
64
+ for (const [key, value] of Object.entries(sourceVars)) {
65
+ if (this.debugWarnings && key in this.variables) {
66
+ console.warn(`[Scope] Warning: Variable "${key}" conflict during merge, using new value`);
67
+ }
68
+ this.variables[key] = value;
69
+ }
70
+
71
+ return this;
72
+ }
73
+
74
+ /**
75
+ * Создать дочерний (локальный) Scope на основе текущего.
76
+ * Изменения в дочернем Scope не влияют на родительский.
77
+ */
78
+ public createChild(localVariables?: Record<string, any>): Scope {
79
+ const child = new Scope({ debugWarnings: this.debugWarnings });
80
+ child.variables = { ...this.variables };
81
+
82
+ if (localVariables) {
83
+ for (const [key, value] of Object.entries(localVariables)) {
84
+ child.variables[key] = value;
85
+ }
86
+ }
87
+
88
+ return child;
89
+ }
90
+
91
+ /**
92
+ * Извлечь поля и методы из объекта или экземпляра класса.
93
+ * Пропускает нативные DOM/браузерные прототипы.
94
+ */
95
+ public extractFromObject(obj: object): Record<string, any> {
96
+ const ctx: Record<string, any> = {};
97
+
98
+ if (!obj || typeof obj !== 'object') {
99
+ return ctx;
100
+ }
101
+
102
+ // Copy own properties
103
+ for (const key of Object.keys(obj)) {
104
+ ctx[key] = (obj as any)[key];
105
+ }
106
+
107
+ // Copy prototype methods (for class instances)
108
+ let proto = Object.getPrototypeOf(obj);
109
+ while (proto && proto !== Object.prototype) {
110
+ // Avoid copying host (DOM/native) prototype methods which may throw
111
+ const ctorName = proto?.constructor
112
+ ? String(proto.constructor.name ?? '')
113
+ : '';
114
+
115
+ if (/HTMLElement|Element|Node|EventTarget|Window|GlobalThis/i.test(ctorName)) {
116
+ proto = Object.getPrototypeOf(proto);
117
+ continue;
118
+ }
119
+
120
+ for (const key of Object.getOwnPropertyNames(proto)) {
121
+ if (key === 'constructor' || key in ctx) continue;
122
+
123
+ let desc: PropertyDescriptor | undefined;
124
+ try {
125
+ desc = Object.getOwnPropertyDescriptor(proto, key);
126
+ } catch {
127
+ continue;
128
+ }
129
+ if (!desc) continue;
130
+
131
+ // Only bind plain function values — don't copy getters/setters
132
+ if (typeof desc.value === 'function') {
133
+ try {
134
+ ctx[key] = (desc.value as Function).bind(obj);
135
+ } catch {
136
+ continue;
137
+ }
138
+ }
139
+ }
140
+
141
+ proto = Object.getPrototypeOf(proto);
142
+ }
143
+
144
+ return ctx;
145
+ }
146
+
147
+ /**
148
+ * Статический метод для создания Scope из объекта
149
+ */
150
+ public static from(source: object | Record<string, any>, options?: { debugWarnings?: boolean }): Scope {
151
+ const scope = new Scope(options);
152
+ scope.merge(source);
153
+ return scope;
154
+ }
155
+
156
+ /**
157
+ * Статический метод для объединения нескольких Scope/объектов
158
+ */
159
+ public static combine(...sources: (Scope | Record<string, any> | object)[]): Scope {
160
+ const scope = new Scope();
161
+ for (const source of sources) {
162
+ scope.merge(source);
163
+ }
164
+ return scope;
165
+ }
166
+ }
@@ -0,0 +1,243 @@
1
+ import Scope from './Scope.js';
2
+ import Expression from './Expression.js';
3
+ import EscapeHandler from './EscapeHandler.js';
4
+ import TemplateInstance, { TemplateSection } from './TemplateInstance.js';
5
+ import Rule, { RuleMatch, RuleResult, SyntaxRule, AttributeRule } from './Rule.js';
6
+ import Observable from '../api/Observer.js';
7
+
8
+ // Import rules
9
+ import ExpressionRule from './rules/syntax/ExpressionRule.js';
10
+ import IfRule from './rules/syntax/IfRule.js';
11
+ import ForRule from './rules/syntax/ForRule.js';
12
+ import RefRule from './rules/attribute/RefRule.js';
13
+ import EventRule from './rules/attribute/EventRule.js';
14
+ import InjectionRule from './rules/attribute/InjectionRule.js';
15
+
16
+ /**
17
+ * TemplateEngineOptions - настройки TemplateEngine
18
+ */
19
+ export interface TemplateEngineOptions {
20
+ /** Оставлять синтаксис атрибутивных Rule в финальном HTML */
21
+ showAttributeRule?: boolean;
22
+ /** Включить предупреждения отладки */
23
+ debugWarnings?: boolean;
24
+ }
25
+
26
+ /**
27
+ * ProcessResult - результат обработки шаблона
28
+ */
29
+ export interface ProcessResult {
30
+ output: string;
31
+ observables: Observable<any>[];
32
+ sections: TemplateSection[];
33
+ }
34
+
35
+ /**
36
+ * TemplateEngine - главный класс шаблонизатора.
37
+ * Обрабатывает HTML-шаблон с Rule и создаёт TemplateInstance.
38
+ */
39
+ export default class TemplateEngine {
40
+ private readonly scope: Scope;
41
+ private readonly options: TemplateEngineOptions;
42
+ private readonly syntaxRules: SyntaxRule[] = [];
43
+ private readonly attributeRules: AttributeRule[] = [];
44
+
45
+ constructor(scope: Scope | object, options?: TemplateEngineOptions) {
46
+ this.scope = scope instanceof Scope ? scope : Scope.from(scope);
47
+ this.options = {
48
+ showAttributeRule: false,
49
+ debugWarnings: true,
50
+ ...options
51
+ };
52
+
53
+ // Register default rules (sorted by priority)
54
+ this.registerDefaultRules();
55
+ }
56
+
57
+ /**
58
+ * Зарегистрировать стандартные правила
59
+ */
60
+ private registerDefaultRules(): void {
61
+ // Syntax rules
62
+ this.syntaxRules.push(new ForRule());
63
+ this.syntaxRules.push(new IfRule());
64
+ this.syntaxRules.push(new ExpressionRule());
65
+
66
+ // Attribute rules
67
+ this.attributeRules.push(new RefRule());
68
+ this.attributeRules.push(new EventRule());
69
+ this.attributeRules.push(new InjectionRule());
70
+
71
+ // Sort by priority
72
+ this.syntaxRules.sort((a, b) => a.priority - b.priority);
73
+ this.attributeRules.sort((a, b) => a.priority - b.priority);
74
+ }
75
+
76
+ /**
77
+ * Добавить пользовательское правило
78
+ */
79
+ public addRule(rule: Rule): void {
80
+ if (rule.type === 'syntax') {
81
+ this.syntaxRules.push(rule as SyntaxRule);
82
+ this.syntaxRules.sort((a, b) => a.priority - b.priority);
83
+ } else {
84
+ this.attributeRules.push(rule as AttributeRule);
85
+ this.attributeRules.sort((a, b) => a.priority - b.priority);
86
+ }
87
+ }
88
+
89
+ /**
90
+ * Получить Scope
91
+ */
92
+ public getScope(): Scope {
93
+ return this.scope;
94
+ }
95
+
96
+ /**
97
+ * Обработать шаблон и вернуть TemplateInstance
98
+ */
99
+ public parse(template: string): TemplateInstance {
100
+ const result = this.processTemplate(template, this.scope);
101
+ const templateInstance = new TemplateInstance(result.output, this.scope);
102
+
103
+ // Add sections
104
+ for (const section of result.sections) {
105
+ templateInstance.addSection(section);
106
+
107
+ // Track observables
108
+ for (const observable of section.result.observables || []) {
109
+ templateInstance.trackObservable(observable, section, (s) => {
110
+ return this.processTemplate(s.sourceTemplate, this.scope);
111
+ });
112
+ }
113
+ }
114
+
115
+ return templateInstance;
116
+ }
117
+
118
+ /**
119
+ * Обработать шаблон (внутренний метод, используется Rule для рекурсии)
120
+ */
121
+ public processTemplate(template: string, scope: Scope): ProcessResult {
122
+ const allObservables: Observable<any>[] = [];
123
+ const allSections: TemplateSection[] = [];
124
+
125
+ // Step 1: Handle @@ escape sequences
126
+ let processed = EscapeHandler.process(template, (escaped) => {
127
+ let result = escaped;
128
+
129
+ // Step 2: Process syntax rules (in priority order)
130
+ for (const rule of this.syntaxRules) {
131
+ result = this.processRule(rule, result, scope, allObservables, allSections);
132
+ }
133
+
134
+ // Step 3: Process attribute rules
135
+ for (const rule of this.attributeRules) {
136
+ // Skip injection - processed last
137
+ if (rule.name === 'injection') continue;
138
+ result = this.processRule(rule, result, scope, allObservables, allSections);
139
+ }
140
+
141
+ return result;
142
+ });
143
+
144
+ // Step 4: Process injection rules last
145
+ const injectionRule = this.attributeRules.find(r => r.name === 'injection');
146
+ if (injectionRule) {
147
+ processed = this.processRule(injectionRule, processed, scope, allObservables, allSections);
148
+ }
149
+
150
+ // Step 5: Handle showAttributeRule option
151
+ if (!this.options.showAttributeRule) {
152
+ processed = this.removeAttributeSyntax(processed);
153
+ }
154
+
155
+ return {
156
+ output: processed,
157
+ observables: allObservables,
158
+ sections: allSections
159
+ };
160
+ }
161
+
162
+ /**
163
+ * Обработать одно правило
164
+ */
165
+ private processRule(
166
+ rule: Rule,
167
+ template: string,
168
+ scope: Scope,
169
+ observables: Observable<any>[],
170
+ sections: TemplateSection[]
171
+ ): string {
172
+ const matches = rule.find(template);
173
+
174
+ // Sort matches by position (reverse to process from end)
175
+ matches.sort((a, b) => b.start - a.start);
176
+
177
+ let result = template;
178
+
179
+ for (const match of matches) {
180
+ try {
181
+ const ruleResult = rule.execute(match, scope, this) as RuleResult;
182
+
183
+ // Track observables
184
+ if (ruleResult.observables) {
185
+ observables.push(...ruleResult.observables);
186
+ }
187
+
188
+ // Create section
189
+ const section: TemplateSection = {
190
+ rule,
191
+ match,
192
+ result: ruleResult,
193
+ sourceTemplate: match.fullMatch,
194
+ children: [],
195
+ subscriptions: []
196
+ };
197
+ sections.push(section);
198
+
199
+ // Replace in template
200
+ result = result.slice(0, match.start) + ruleResult.output + result.slice(match.end);
201
+
202
+ } catch (error) {
203
+ console.error(`[TemplateEngine] Error processing rule "${rule.name}":`, error);
204
+ // Continue processing other rules
205
+ }
206
+ }
207
+
208
+ return result;
209
+ }
210
+
211
+ /**
212
+ * Удалить синтаксис атрибутивных Rule из финального HTML
213
+ */
214
+ private removeAttributeSyntax(template: string): string {
215
+ // Remove @[ref], @on[...], @injection[...] patterns that weren't processed
216
+ return template
217
+ .replace(/@\[ref\]\s*=\s*["'][^"']*["']/gi, '')
218
+ .replace(/@on\[[a-zA-Z]+\]\s*=\s*["'][^"']*["']/gi, '')
219
+ .replace(/@injection\[(head|tail)\]\s*=\s*["'][^"']*["']/gi, '');
220
+ }
221
+
222
+ /**
223
+ * Статический метод для быстрой обработки
224
+ */
225
+ public static process(template: string, scope: object, options?: TemplateEngineOptions): string {
226
+ const engine = new TemplateEngine(scope, options);
227
+ const TemplateInstance = engine.parse(template);
228
+ return TemplateInstance.getTemplate();
229
+ }
230
+
231
+ /**
232
+ * Создать TemplateInstance из шаблона
233
+ */
234
+ public static create(template: string, scope: object, options?: TemplateEngineOptions): TemplateInstance {
235
+ const engine = new TemplateEngine(scope, options);
236
+ return engine.parse(template);
237
+ }
238
+ }
239
+
240
+ // Re-export useful types
241
+ export { Scope, Expression, TemplateInstance, Rule, SyntaxRule, AttributeRule };
242
+ export { ExpressionRule, IfRule, ForRule, RefRule, EventRule, InjectionRule };
243
+ export * from './exceptions/TemplateExceptions.js';