@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.
- package/out/foundation/api/Observer.d.ts +30 -0
- package/out/foundation/api/Observer.d.ts.map +1 -1
- package/out/foundation/api/Observer.js +48 -0
- package/out/foundation/api/Observer.js.map +1 -1
- package/out/foundation/component_api/Attribute.d.ts.map +1 -1
- package/out/foundation/component_api/Attribute.js +1 -0
- package/out/foundation/component_api/Attribute.js.map +1 -1
- package/out/foundation/engine/BalancedParser.d.ts +58 -0
- package/out/foundation/engine/BalancedParser.d.ts.map +1 -0
- package/out/foundation/engine/BalancedParser.js +301 -0
- package/out/foundation/engine/BalancedParser.js.map +1 -0
- package/out/foundation/engine/EscapeHandler.d.ts +27 -0
- package/out/foundation/engine/EscapeHandler.d.ts.map +1 -0
- package/out/foundation/engine/EscapeHandler.js +47 -0
- package/out/foundation/engine/EscapeHandler.js.map +1 -0
- package/out/foundation/engine/Expression.d.ts +83 -0
- package/out/foundation/engine/Expression.d.ts.map +1 -0
- package/out/foundation/engine/Expression.js +256 -0
- package/out/foundation/engine/Expression.js.map +1 -0
- package/out/foundation/engine/Rule.d.ts +83 -0
- package/out/foundation/engine/Rule.d.ts.map +1 -0
- package/out/foundation/engine/Rule.js +69 -0
- package/out/foundation/engine/Rule.js.map +1 -0
- package/out/foundation/engine/Scope.d.ts +57 -0
- package/out/foundation/engine/Scope.d.ts.map +1 -0
- package/out/foundation/engine/Scope.js +147 -0
- package/out/foundation/engine/Scope.js.map +1 -0
- package/out/foundation/engine/TemplateEngine.d.ts +79 -0
- package/out/foundation/engine/TemplateEngine.d.ts.map +1 -0
- package/out/foundation/engine/TemplateEngine.js +187 -0
- package/out/foundation/engine/TemplateEngine.js.map +1 -0
- package/out/foundation/engine/TemplateInstance.d.ts +121 -0
- package/out/foundation/engine/TemplateInstance.d.ts.map +1 -0
- package/out/foundation/engine/TemplateInstance.js +255 -0
- package/out/foundation/engine/TemplateInstance.js.map +1 -0
- package/out/foundation/engine/exceptions/TemplateExceptions.d.ts +21 -0
- package/out/foundation/engine/exceptions/TemplateExceptions.d.ts.map +1 -0
- package/out/foundation/engine/exceptions/TemplateExceptions.js +26 -0
- package/out/foundation/engine/exceptions/TemplateExceptions.js.map +1 -0
- package/out/foundation/engine/index.d.ts +18 -0
- package/out/foundation/engine/index.d.ts.map +1 -0
- package/out/foundation/engine/index.js +19 -0
- package/out/foundation/engine/index.js.map +1 -0
- package/out/foundation/engine/rules/attribute/EventRule.d.ts +22 -0
- package/out/foundation/engine/rules/attribute/EventRule.d.ts.map +1 -0
- package/out/foundation/engine/rules/attribute/EventRule.js +129 -0
- package/out/foundation/engine/rules/attribute/EventRule.js.map +1 -0
- package/out/foundation/engine/rules/attribute/InjectionRule.d.ts +20 -0
- package/out/foundation/engine/rules/attribute/InjectionRule.d.ts.map +1 -0
- package/out/foundation/engine/rules/attribute/InjectionRule.js +108 -0
- package/out/foundation/engine/rules/attribute/InjectionRule.js.map +1 -0
- package/out/foundation/engine/rules/attribute/RefRule.d.ts +23 -0
- package/out/foundation/engine/rules/attribute/RefRule.d.ts.map +1 -0
- package/out/foundation/engine/rules/attribute/RefRule.js +98 -0
- package/out/foundation/engine/rules/attribute/RefRule.js.map +1 -0
- package/out/foundation/engine/rules/syntax/ExpressionRule.d.ts +19 -0
- package/out/foundation/engine/rules/syntax/ExpressionRule.d.ts.map +1 -0
- package/out/foundation/engine/rules/syntax/ExpressionRule.js +82 -0
- package/out/foundation/engine/rules/syntax/ExpressionRule.js.map +1 -0
- package/out/foundation/engine/rules/syntax/ForRule.d.ts +19 -0
- package/out/foundation/engine/rules/syntax/ForRule.d.ts.map +1 -0
- package/out/foundation/engine/rules/syntax/ForRule.js +226 -0
- package/out/foundation/engine/rules/syntax/ForRule.js.map +1 -0
- package/out/foundation/engine/rules/syntax/IfRule.d.ts +17 -0
- package/out/foundation/engine/rules/syntax/IfRule.d.ts.map +1 -0
- package/out/foundation/engine/rules/syntax/IfRule.js +220 -0
- package/out/foundation/engine/rules/syntax/IfRule.js.map +1 -0
- package/out/foundation/worker/Router.d.ts.map +1 -1
- package/out/foundation/worker/Router.js.map +1 -1
- package/out/index.d.ts +3 -0
- package/out/index.d.ts.map +1 -1
- package/out/index.js +3 -0
- package/out/index.js.map +1 -1
- package/package.json +1 -1
- package/src/foundation/api/Observer.ts +60 -0
- package/src/foundation/component_api/Attribute.ts +1 -0
- package/src/foundation/engine/BalancedParser.ts +353 -0
- package/src/foundation/engine/EscapeHandler.ts +54 -0
- package/src/foundation/engine/Expression.ts +285 -0
- package/src/foundation/engine/Rule.ts +136 -0
- package/src/foundation/engine/Scope.ts +166 -0
- package/src/foundation/engine/TemplateEngine.ts +243 -0
- package/src/foundation/engine/TemplateInstance.ts +355 -0
- package/src/foundation/engine/exceptions/TemplateExceptions.ts +27 -0
- package/src/foundation/engine/rules/attribute/EventRule.ts +171 -0
- package/src/foundation/engine/rules/attribute/InjectionRule.ts +140 -0
- package/src/foundation/engine/rules/attribute/RefRule.ts +119 -0
- package/src/foundation/engine/rules/syntax/ExpressionRule.ts +102 -0
- package/src/foundation/engine/rules/syntax/ForRule.ts +267 -0
- package/src/foundation/engine/rules/syntax/IfRule.ts +261 -0
- package/src/foundation/worker/Router.ts +1 -1
- package/src/index.ts +9 -0
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
import { SyntaxRule } from '../../Rule.js';
|
|
2
|
+
import type { RuleMatch, RuleResult } from '../../Rule.js';
|
|
3
|
+
import Scope from '../../Scope.js';
|
|
4
|
+
import Expression from '../../Expression.js';
|
|
5
|
+
import BalancedParser from '../../BalancedParser.js';
|
|
6
|
+
import { InvalidTemplateEngineSyntaxException } from '../../exceptions/TemplateExceptions.js';
|
|
7
|
+
import { isObservable } from '../../../api/Observer.js';
|
|
8
|
+
|
|
9
|
+
interface IfChainMatch extends RuleMatch {
|
|
10
|
+
data: {
|
|
11
|
+
chain: Array<{
|
|
12
|
+
type: 'if' | 'elseif' | 'else';
|
|
13
|
+
condition?: string;
|
|
14
|
+
block: string;
|
|
15
|
+
}>;
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* IfRule - обработка @if/@elseif/@else
|
|
21
|
+
*/
|
|
22
|
+
export default class IfRule extends SyntaxRule {
|
|
23
|
+
public readonly name = 'if';
|
|
24
|
+
public readonly priority = 20; // Выполняется раньше @expression
|
|
25
|
+
|
|
26
|
+
public find(template: string): RuleMatch[] {
|
|
27
|
+
const results: RuleMatch[] = [];
|
|
28
|
+
const lowerTemplate = template.toLowerCase();
|
|
29
|
+
let i = 0;
|
|
30
|
+
|
|
31
|
+
while (i < template.length) {
|
|
32
|
+
const idx = lowerTemplate.indexOf('@if', i);
|
|
33
|
+
if (idx === -1) break;
|
|
34
|
+
|
|
35
|
+
// Check for @@ escape
|
|
36
|
+
if (idx > 0 && template[idx - 1] === '@') {
|
|
37
|
+
i = idx + 1;
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Parse the full if/elseif/else chain
|
|
42
|
+
const chain = this.parseIfChain(template, idx);
|
|
43
|
+
if (chain) {
|
|
44
|
+
results.push({
|
|
45
|
+
fullMatch: template.slice(chain.start, chain.end),
|
|
46
|
+
start: chain.start,
|
|
47
|
+
end: chain.end,
|
|
48
|
+
data: { chain: chain.items }
|
|
49
|
+
});
|
|
50
|
+
i = chain.end;
|
|
51
|
+
} else {
|
|
52
|
+
i = idx + 1;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return results;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
private parseIfChain(template: string, startIdx: number): {
|
|
60
|
+
start: number;
|
|
61
|
+
end: number;
|
|
62
|
+
items: Array<{ type: 'if' | 'elseif' | 'else'; condition?: string; block: string }>
|
|
63
|
+
} | null {
|
|
64
|
+
const items: Array<{ type: 'if' | 'elseif' | 'else'; condition?: string; block: string }> = [];
|
|
65
|
+
let pos = startIdx;
|
|
66
|
+
|
|
67
|
+
// Parse @if
|
|
68
|
+
const ifParsed = this.parseConditionBlock(template, pos, '@if');
|
|
69
|
+
if (!ifParsed) return null;
|
|
70
|
+
|
|
71
|
+
items.push({ type: 'if', condition: ifParsed.condition, block: ifParsed.block });
|
|
72
|
+
pos = ifParsed.end;
|
|
73
|
+
|
|
74
|
+
// Parse @elseif/@else chain
|
|
75
|
+
while (pos < template.length) {
|
|
76
|
+
// Skip whitespace
|
|
77
|
+
while (pos < template.length && /\s/.test(template[pos])) {
|
|
78
|
+
pos++;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const remaining = template.slice(pos).toLowerCase();
|
|
82
|
+
|
|
83
|
+
if (remaining.startsWith('@elseif')) {
|
|
84
|
+
const elseifParsed = this.parseConditionBlock(template, pos, '@elseif');
|
|
85
|
+
if (!elseifParsed) break;
|
|
86
|
+
items.push({ type: 'elseif', condition: elseifParsed.condition, block: elseifParsed.block });
|
|
87
|
+
pos = elseifParsed.end;
|
|
88
|
+
} else if (remaining.startsWith('@else') && !remaining.startsWith('@elseif')) {
|
|
89
|
+
const elseParsed = this.parseElseBlock(template, pos);
|
|
90
|
+
if (!elseParsed) break;
|
|
91
|
+
items.push({ type: 'else', block: elseParsed.block });
|
|
92
|
+
pos = elseParsed.end;
|
|
93
|
+
break; // @else is always last
|
|
94
|
+
} else {
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return { start: startIdx, end: pos, items };
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
private parseConditionBlock(template: string, start: number, keyword: string): {
|
|
103
|
+
condition: string;
|
|
104
|
+
block: string;
|
|
105
|
+
end: number;
|
|
106
|
+
} | null {
|
|
107
|
+
let pos = start + keyword.length;
|
|
108
|
+
|
|
109
|
+
// Skip whitespace
|
|
110
|
+
while (pos < template.length && /\s/.test(template[pos])) {
|
|
111
|
+
pos++;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Expect (
|
|
115
|
+
if (template[pos] !== '(') return null;
|
|
116
|
+
|
|
117
|
+
// Parse balanced condition
|
|
118
|
+
const conditionStart = pos + 1;
|
|
119
|
+
pos++;
|
|
120
|
+
let depth = 1;
|
|
121
|
+
|
|
122
|
+
while (pos < template.length && depth > 0) {
|
|
123
|
+
const ch = template[pos];
|
|
124
|
+
if (ch === '"' || ch === "'" || ch === '`') {
|
|
125
|
+
pos = this.skipString(template, pos, ch);
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
if (ch === '(') depth++;
|
|
129
|
+
else if (ch === ')') depth--;
|
|
130
|
+
pos++;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (depth !== 0) return null;
|
|
134
|
+
const condition = template.slice(conditionStart, pos - 1);
|
|
135
|
+
|
|
136
|
+
// Skip whitespace
|
|
137
|
+
while (pos < template.length && /\s/.test(template[pos])) {
|
|
138
|
+
pos++;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Expect {
|
|
142
|
+
if (template[pos] !== '{') return null;
|
|
143
|
+
|
|
144
|
+
// Parse balanced block
|
|
145
|
+
const blockStart = pos + 1;
|
|
146
|
+
pos++;
|
|
147
|
+
depth = 1;
|
|
148
|
+
|
|
149
|
+
while (pos < template.length && depth > 0) {
|
|
150
|
+
const ch = template[pos];
|
|
151
|
+
if (ch === '"' || ch === "'" || ch === '`') {
|
|
152
|
+
pos = this.skipString(template, pos, ch);
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
if (ch === '{') depth++;
|
|
156
|
+
else if (ch === '}') depth--;
|
|
157
|
+
pos++;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (depth !== 0) return null;
|
|
161
|
+
const block = template.slice(blockStart, pos - 1);
|
|
162
|
+
|
|
163
|
+
return { condition, block, end: pos };
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
private parseElseBlock(template: string, start: number): { block: string; end: number } | null {
|
|
167
|
+
let pos = start + 5; // '@else'.length
|
|
168
|
+
|
|
169
|
+
// Skip whitespace
|
|
170
|
+
while (pos < template.length && /\s/.test(template[pos])) {
|
|
171
|
+
pos++;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Expect {
|
|
175
|
+
if (template[pos] !== '{') return null;
|
|
176
|
+
|
|
177
|
+
// Parse balanced block
|
|
178
|
+
const blockStart = pos + 1;
|
|
179
|
+
pos++;
|
|
180
|
+
let depth = 1;
|
|
181
|
+
|
|
182
|
+
while (pos < template.length && depth > 0) {
|
|
183
|
+
const ch = template[pos];
|
|
184
|
+
if (ch === '"' || ch === "'" || ch === '`') {
|
|
185
|
+
pos = this.skipString(template, pos, ch);
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
if (ch === '{') depth++;
|
|
189
|
+
else if (ch === '}') depth--;
|
|
190
|
+
pos++;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (depth !== 0) return null;
|
|
194
|
+
const block = template.slice(blockStart, pos - 1);
|
|
195
|
+
|
|
196
|
+
return { block, end: pos };
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
private skipString(input: string, pos: number, quote: string): number {
|
|
200
|
+
pos++;
|
|
201
|
+
while (pos < input.length) {
|
|
202
|
+
if (input[pos] === '\\') {
|
|
203
|
+
pos += 2;
|
|
204
|
+
continue;
|
|
205
|
+
}
|
|
206
|
+
if (input[pos] === quote) {
|
|
207
|
+
return pos + 1;
|
|
208
|
+
}
|
|
209
|
+
pos++;
|
|
210
|
+
}
|
|
211
|
+
return pos;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
public execute(match: RuleMatch, scope: Scope, engine?: any): RuleResult {
|
|
215
|
+
const chain = (match as IfChainMatch).data.chain;
|
|
216
|
+
const observables: any[] = [];
|
|
217
|
+
|
|
218
|
+
for (const item of chain) {
|
|
219
|
+
if (item.type === 'else') {
|
|
220
|
+
// Process else block
|
|
221
|
+
if (engine) {
|
|
222
|
+
const result = engine.processTemplate(item.block, scope);
|
|
223
|
+
return { output: result.output, observables: [...observables, ...(result.observables || [])] };
|
|
224
|
+
}
|
|
225
|
+
return { output: item.block, observables };
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Evaluate condition
|
|
229
|
+
const expr = new Expression(item.condition!);
|
|
230
|
+
|
|
231
|
+
// Находим Observable в условии
|
|
232
|
+
const conditionObservables = expr.findObservables(scope);
|
|
233
|
+
observables.push(...conditionObservables);
|
|
234
|
+
|
|
235
|
+
const conditionResult = expr.execute(scope);
|
|
236
|
+
|
|
237
|
+
// Check if result is Observable
|
|
238
|
+
if (isObservable(conditionResult)) {
|
|
239
|
+
observables.push(conditionResult);
|
|
240
|
+
const value = conditionResult.getObject?.() ?? conditionResult;
|
|
241
|
+
if (value) {
|
|
242
|
+
if (engine) {
|
|
243
|
+
const result = engine.processTemplate(item.block, scope);
|
|
244
|
+
return { output: result.output, observables: [...observables, ...(result.observables || [])] };
|
|
245
|
+
}
|
|
246
|
+
return { output: item.block, observables };
|
|
247
|
+
}
|
|
248
|
+
} else if (conditionResult) {
|
|
249
|
+
// Condition is truthy
|
|
250
|
+
if (engine) {
|
|
251
|
+
const result = engine.processTemplate(item.block, scope);
|
|
252
|
+
return { output: result.output, observables: [...observables, ...(result.observables || [])] };
|
|
253
|
+
}
|
|
254
|
+
return { output: item.block, observables };
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// No condition matched and no else
|
|
259
|
+
return { output: '', observables };
|
|
260
|
+
}
|
|
261
|
+
}
|
|
@@ -42,13 +42,13 @@ export abstract class Router {
|
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
|
|
46
45
|
public static legacyRouteTo(route: string) {
|
|
47
46
|
const url = new URL(Fetcher.resolveUrl(route));
|
|
48
47
|
if (window.location.pathname !== url.pathname) {
|
|
49
48
|
window.location.replace(url.href);
|
|
50
49
|
}
|
|
51
50
|
}
|
|
51
|
+
|
|
52
52
|
public static tryRouteTo(url: URL, pushState: boolean = true) {
|
|
53
53
|
const urlH = new URL(Fetcher.resolveUrl(url.href));
|
|
54
54
|
try {
|
package/src/index.ts
CHANGED
|
@@ -16,12 +16,21 @@ export { ReComponent, RePage } from './foundation/TripletDecorator.js';
|
|
|
16
16
|
export { default as Fetcher } from './foundation/Fetcher.js';
|
|
17
17
|
export { default as HMLEParser } from './foundation/HMLEParser.js';
|
|
18
18
|
|
|
19
|
+
export * from './foundation/engine/TemplateInstance.js';
|
|
20
|
+
export * from './foundation/engine/TemplateEngine.js';
|
|
21
|
+
|
|
22
|
+
export {
|
|
23
|
+
InvalidDynamicRuleUsage,
|
|
24
|
+
InvalidTemplateEngineSyntaxException
|
|
25
|
+
} from './foundation/engine/exceptions/TemplateExceptions.js';
|
|
26
|
+
|
|
19
27
|
export { Router } from './foundation/worker/Router.js';
|
|
20
28
|
export { default as ServiceWorker } from './foundation/worker/ServiceWorker.js';
|
|
21
29
|
|
|
22
30
|
export * from './foundation/Hosting.js';
|
|
23
31
|
export * from './foundation/Theme.js';
|
|
24
32
|
|
|
33
|
+
|
|
25
34
|
// derive the part of href after the origin (e.g. "/path?query#hash")
|
|
26
35
|
/*export const HOSTING: string = window.location.href.startsWith(window.location.origin)
|
|
27
36
|
? window.location.href.substring(window.location.origin.length)
|