@reidelsaltres/pureper 0.1.154 → 0.1.156
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/HMLELoader.d.ts +9 -0
- package/out/foundation/HMLELoader.d.ts.map +1 -0
- package/out/foundation/HMLELoader.js +14 -0
- package/out/foundation/HMLELoader.js.map +1 -0
- package/out/foundation/Triplet.d.ts.map +1 -1
- package/out/foundation/Triplet.js +3 -3
- package/out/foundation/Triplet.js.map +1 -1
- package/out/foundation/TripletDecorator.d.ts.map +1 -1
- package/out/foundation/TripletDecorator.js +4 -0
- package/out/foundation/TripletDecorator.js.map +1 -1
- package/out/foundation/component_api/Attribute.d.ts +2 -0
- package/out/foundation/component_api/Attribute.d.ts.map +1 -1
- package/out/foundation/component_api/Attribute.js +6 -0
- package/out/foundation/component_api/Attribute.js.map +1 -1
- package/out/index.d.ts +1 -2
- package/out/index.d.ts.map +1 -1
- package/out/index.js +1 -2
- package/out/index.js.map +1 -1
- package/package.json +1 -1
- package/src/foundation/HMLELoader.ts +18 -0
- package/src/foundation/Triplet.ts +3 -5
- package/src/foundation/TripletDecorator.ts +8 -0
- package/src/foundation/component_api/Attribute.ts +7 -0
- package/src/index.ts +1 -4
- package/src/components/DynamicBlock.ts +0 -25
- package/src/foundation/HMLEParser.md +0 -117
- package/src/foundation/HMLEParserReborn.ts +0 -990
- package/src/foundation/PHTMLParser.ts +0 -231
- package/src/foundation/dynamic/Rule.ts +0 -24
|
@@ -1,231 +0,0 @@
|
|
|
1
|
-
class PHTMLParserRule {
|
|
2
|
-
public pattern: RegExp;
|
|
3
|
-
|
|
4
|
-
// replacer can return either a string replacement OR an object with { text, end }
|
|
5
|
-
// where `end` is a position in the source string just after the consumed range.
|
|
6
|
-
public replacer: (parser: PHTMLParser, match: IArguments, scope?: Record<string, any>) => string | { text: string; end: number };
|
|
7
|
-
|
|
8
|
-
constructor(pattern: RegExp, replacer: (parser: PHTMLParser, match: IArguments, scope?: Record<string, any>) => string | { text: string; end: number }) {
|
|
9
|
-
this.pattern = pattern;
|
|
10
|
-
this.replacer = replacer;
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export default class PHTMLParser {
|
|
15
|
-
// Extracts a balanced block starting from position `start` in `content`.
|
|
16
|
-
// Returns { block, end } where `block` is the content inside braces and `end` is the position after closing brace.
|
|
17
|
-
private static extractBalancedBlock(content: string, start: number): { block: string; end: number } | null {
|
|
18
|
-
if (content[start] !== '{') return null;
|
|
19
|
-
let depth = 1;
|
|
20
|
-
let i = start + 1;
|
|
21
|
-
while (i < content.length && depth > 0) {
|
|
22
|
-
if (content[i] === '{') depth++;
|
|
23
|
-
else if (content[i] === '}') depth--;
|
|
24
|
-
i++;
|
|
25
|
-
}
|
|
26
|
-
if (depth !== 0) return null;
|
|
27
|
-
return { block: content.slice(start + 1, i - 1), end: i };
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// Extracts a balanced parenthesis block starting at `start` (which must be '(')
|
|
31
|
-
private static extractBalancedParens(content: string, start: number): { block: string; end: number } | null {
|
|
32
|
-
if (content[start] !== '(') return null;
|
|
33
|
-
let depth = 1;
|
|
34
|
-
let i = start + 1;
|
|
35
|
-
while (i < content.length && depth > 0) {
|
|
36
|
-
if (content[i] === '(') depth++;
|
|
37
|
-
else if (content[i] === ')') depth--;
|
|
38
|
-
i++;
|
|
39
|
-
}
|
|
40
|
-
if (depth !== 0) return null;
|
|
41
|
-
return { block: content.slice(start + 1, i - 1), end: i };
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// Note: @for handling moved to a rule in `rules` so it can participate in the
|
|
45
|
-
// ordered rules pipeline. The actual exec loop for the for-rule is implemented
|
|
46
|
-
// inside parse() to allow balanced-brace extraction.
|
|
47
|
-
|
|
48
|
-
private static rules: PHTMLParserRule[] = [
|
|
49
|
-
// Rule for nested @for blocks. This rule's replacer computes the
|
|
50
|
-
// replacement for one @for occurrence when given a RegExpExecArray
|
|
51
|
-
// (it expects match.index and match.input to be present so the parser
|
|
52
|
-
// can extract the full balanced block that follows the match).
|
|
53
|
-
new PHTMLParserRule(/@for\s*\(([A-Za-z0-9_$]+)\s+in\s+([A-Za-z0-9_$.]+)\s*\)\s*\{/g,
|
|
54
|
-
(parser, m, scope) => {
|
|
55
|
-
// `m` will be a RegExpExecArray-like object when used by the
|
|
56
|
-
// exec-based loop inside `parse()` so we can treat it accordingly.
|
|
57
|
-
const match = m as any as RegExpExecArray;
|
|
58
|
-
const iterVar = match[1];
|
|
59
|
-
const iterableExpr = match[2];
|
|
60
|
-
const offset = Number(match[match.length - 2]); // offset position
|
|
61
|
-
const input = String(match[match.length - 1]); // source string
|
|
62
|
-
|
|
63
|
-
const blockStart = offset + match[0].length - 1; // position of '{'
|
|
64
|
-
const extracted = PHTMLParser.extractBalancedBlock(input, blockStart);
|
|
65
|
-
if (!extracted) return match[0];
|
|
66
|
-
|
|
67
|
-
const inner = extracted.block;
|
|
68
|
-
const resolved = parser.resolveExpression(iterableExpr, scope);
|
|
69
|
-
const arr = Array.isArray(resolved) ? resolved : [];
|
|
70
|
-
|
|
71
|
-
const resultParts: string[] = [];
|
|
72
|
-
for (const item of arr) {
|
|
73
|
-
const fullScope = Object.assign({}, scope, { [iterVar]: item });
|
|
74
|
-
resultParts.push(parser.parse(inner, fullScope));
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// return both the replacement text and the position after the full balanced block
|
|
78
|
-
return { text: resultParts.join('\n'), end: extracted.end };
|
|
79
|
-
}),
|
|
80
|
-
// Double-paren expression: @(( code )) — use exec+balanced-start extraction
|
|
81
|
-
new PHTMLParserRule(/@\(\(/g, (parser, m, scope) => {
|
|
82
|
-
const match = m as any as RegExpExecArray;
|
|
83
|
-
const offset = Number(match[match.length - 2]);
|
|
84
|
-
const input = String(match[match.length - 1]);
|
|
85
|
-
const blockStart = offset + match[0].length - 1; // points at the inner '('
|
|
86
|
-
|
|
87
|
-
// extract balanced parentheses
|
|
88
|
-
const extracted = PHTMLParser.extractBalancedParens(input, blockStart);
|
|
89
|
-
if (!extracted) return match[0];
|
|
90
|
-
|
|
91
|
-
const code = extracted.block;
|
|
92
|
-
// Evaluate code using parser.variables + local scope
|
|
93
|
-
const ctx = parser.buildContext(scope);
|
|
94
|
-
let result: any;
|
|
95
|
-
try {
|
|
96
|
-
// try to evaluate as expression first
|
|
97
|
-
const fn = new Function('with(this){ return (' + code + '); }');
|
|
98
|
-
result = fn.call(ctx);
|
|
99
|
-
} catch (e) {
|
|
100
|
-
try {
|
|
101
|
-
const fn2 = new Function('with(this){ ' + code + ' }');
|
|
102
|
-
result = fn2.call(ctx);
|
|
103
|
-
} catch (e2) {
|
|
104
|
-
// On error return empty string
|
|
105
|
-
return '';
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// final end should include the outer ')' if present (for @(( ... )) constructs)
|
|
110
|
-
let finalEnd = extracted.end;
|
|
111
|
-
if (input[extracted.end] === ')') finalEnd = extracted.end + 1;
|
|
112
|
-
return { text: parser.stringifyValue(result), end: finalEnd };
|
|
113
|
-
}),
|
|
114
|
-
// Single-paren expression: @( code ) — similar extraction, processed after double-paren rule
|
|
115
|
-
new PHTMLParserRule(/@\(/g, (parser, m, scope) => {
|
|
116
|
-
const match = m as any as RegExpExecArray;
|
|
117
|
-
const offset = Number(match[match.length - 2]);
|
|
118
|
-
const input = String(match[match.length - 1]);
|
|
119
|
-
const blockStart = offset + match[0].length - 1; // points at '('
|
|
120
|
-
|
|
121
|
-
const extracted = PHTMLParser.extractBalancedParens(input, blockStart);
|
|
122
|
-
if (!extracted) return match[0];
|
|
123
|
-
|
|
124
|
-
const code = extracted.block;
|
|
125
|
-
const ctx = parser.buildContext(scope);
|
|
126
|
-
let result: any;
|
|
127
|
-
try {
|
|
128
|
-
const fn = new Function('with(this){ return (' + code + '); }');
|
|
129
|
-
result = fn.call(ctx);
|
|
130
|
-
} catch (e) {
|
|
131
|
-
try {
|
|
132
|
-
const fn2 = new Function('with(this){ ' + code + ' }');
|
|
133
|
-
result = fn2.call(ctx);
|
|
134
|
-
} catch (e2) {
|
|
135
|
-
return '';
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
return { text: parser.stringifyValue(result), end: extracted.end };
|
|
140
|
-
}),
|
|
141
|
-
];
|
|
142
|
-
public variables: Record<string, unknown> = {};
|
|
143
|
-
|
|
144
|
-
public addVariable(name: string, value: unknown): this {
|
|
145
|
-
this.variables[name] = value;
|
|
146
|
-
return this;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
// Resolve a dotted expression against the parser variables and optional local scope.
|
|
150
|
-
// Examples: "subjectChips" -> this.variables.subjectChips
|
|
151
|
-
// "chip.Color" -> scope.chip.Color (if chip exists in scope) or this.variables.chip.Color
|
|
152
|
-
public resolveExpression(expr: string, scope?: Record<string, any>): any {
|
|
153
|
-
const combined = this.buildContext(scope);
|
|
154
|
-
const parts = expr.split('.').map(p => p.trim()).filter(Boolean);
|
|
155
|
-
let cur: any = combined;
|
|
156
|
-
for (const part of parts) {
|
|
157
|
-
if (cur == null) return undefined;
|
|
158
|
-
cur = cur[part];
|
|
159
|
-
}
|
|
160
|
-
return cur;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
// Build execution context that includes prototype methods from scope
|
|
164
|
-
private buildContext(scope?: Record<string, any>): Record<string, any> {
|
|
165
|
-
const ctx: Record<string, any> = Object.assign({}, this.variables);
|
|
166
|
-
if (scope) {
|
|
167
|
-
// Copy own properties
|
|
168
|
-
Object.assign(ctx, scope);
|
|
169
|
-
// Copy prototype methods (for class instances)
|
|
170
|
-
let proto = Object.getPrototypeOf(scope);
|
|
171
|
-
while (proto && proto !== Object.prototype) {
|
|
172
|
-
for (const key of Object.getOwnPropertyNames(proto)) {
|
|
173
|
-
if (key !== 'constructor' && typeof proto[key] === 'function' && !(key in ctx)) {
|
|
174
|
-
ctx[key] = proto[key].bind(scope);
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
proto = Object.getPrototypeOf(proto);
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
return ctx;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
private stringifyValue(val: any): string {
|
|
184
|
-
if (val == null) return '';
|
|
185
|
-
if (typeof val === 'string') return val;
|
|
186
|
-
const str = String(val);
|
|
187
|
-
return str;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
public parse(content: string, scope?: Record<string, any>): string {
|
|
191
|
-
let working = content;
|
|
192
|
-
|
|
193
|
-
for (const rule of PHTMLParser.rules) {
|
|
194
|
-
const pattern = rule.pattern;
|
|
195
|
-
let result = '';
|
|
196
|
-
let lastIndex = 0;
|
|
197
|
-
let match: RegExpExecArray | null;
|
|
198
|
-
|
|
199
|
-
// reset scanning position
|
|
200
|
-
pattern.lastIndex = 0;
|
|
201
|
-
while ((match = pattern.exec(working)) !== null) {
|
|
202
|
-
// append text before this match
|
|
203
|
-
result += working.slice(lastIndex, match.index);
|
|
204
|
-
|
|
205
|
-
// build args array similar to replace(): [...match, offset, input]
|
|
206
|
-
const args = [...match, match.index, working] as any as IArguments;
|
|
207
|
-
const out = rule.replacer(this, args, scope);
|
|
208
|
-
|
|
209
|
-
if (typeof out === 'string') {
|
|
210
|
-
// simple replacement: advance by matched token length
|
|
211
|
-
result += out;
|
|
212
|
-
lastIndex = match.index + match[0].length;
|
|
213
|
-
}
|
|
214
|
-
else {
|
|
215
|
-
// object replacement provides final end index — consume until that position
|
|
216
|
-
result += out.text;
|
|
217
|
-
lastIndex = out.end;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
// make sure regex scanning continues from the correct place
|
|
221
|
-
pattern.lastIndex = lastIndex;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
// append tail and update working
|
|
225
|
-
result += working.slice(lastIndex);
|
|
226
|
-
working = result;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
return working;
|
|
230
|
-
}
|
|
231
|
-
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
export default class Rule {
|
|
2
|
-
public static readonly PREFIX = "@";
|
|
3
|
-
}
|
|
4
|
-
export class RuleFor<T> extends Rule {
|
|
5
|
-
public indexName: string;
|
|
6
|
-
public index: number;
|
|
7
|
-
|
|
8
|
-
public variableName: string;
|
|
9
|
-
public variable: T;
|
|
10
|
-
|
|
11
|
-
public iterableName: string;
|
|
12
|
-
public iterable: Iterable<T>;
|
|
13
|
-
|
|
14
|
-
public constructor(index: number, variable: T, iterable: Iterable<T>) {
|
|
15
|
-
super();
|
|
16
|
-
this.index = index;
|
|
17
|
-
this.variable = variable;
|
|
18
|
-
this.iterable = iterable;
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
export type Expression<T> = () => T;
|
|
22
|
-
export class Scope {
|
|
23
|
-
|
|
24
|
-
}
|