tina4-nodejs 3.10.16 → 3.10.17
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/package.json +1 -1
- package/packages/frond/src/engine.ts +19 -42
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tina4-nodejs",
|
|
3
|
-
"version": "3.10.
|
|
3
|
+
"version": "3.10.17",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "This is not a framework. Tina4 for Node.js/TypeScript — zero deps, 38 built-in features.",
|
|
6
6
|
"keywords": ["tina4", "framework", "web", "api", "orm", "graphql", "websocket", "typescript"],
|
|
@@ -136,7 +136,9 @@ function resolveVar(expr: string, context: Record<string, unknown>): unknown {
|
|
|
136
136
|
}
|
|
137
137
|
|
|
138
138
|
// Dotted path with bracket access — split on . and [...] but not . inside parentheses
|
|
139
|
+
// Track which parts came from bracket access (need variable resolution)
|
|
139
140
|
const parts: string[] = [];
|
|
141
|
+
const fromBracket: boolean[] = [];
|
|
140
142
|
{
|
|
141
143
|
let current = "";
|
|
142
144
|
let depth = 0;
|
|
@@ -152,27 +154,30 @@ function resolveVar(expr: string, context: Record<string, unknown>): unknown {
|
|
|
152
154
|
if (ch === '(') { depth++; current += ch; continue; }
|
|
153
155
|
if (ch === ')') { depth--; current += ch; continue; }
|
|
154
156
|
if (ch === '.' && depth === 0) {
|
|
155
|
-
if (current) parts.push(current);
|
|
157
|
+
if (current) { parts.push(current); fromBracket.push(false); }
|
|
156
158
|
current = "";
|
|
157
159
|
continue;
|
|
158
160
|
}
|
|
159
161
|
if (ch === '[' && depth === 0) {
|
|
160
|
-
if (current) parts.push(current);
|
|
162
|
+
if (current) { parts.push(current); fromBracket.push(false); }
|
|
161
163
|
current = "";
|
|
162
164
|
const end = expr.indexOf(']', i + 1);
|
|
163
165
|
if (end !== -1) {
|
|
164
166
|
parts.push(expr.slice(i + 1, end));
|
|
167
|
+
fromBracket.push(true);
|
|
165
168
|
i = end;
|
|
166
169
|
}
|
|
167
170
|
continue;
|
|
168
171
|
}
|
|
169
172
|
current += ch;
|
|
170
173
|
}
|
|
171
|
-
if (current) parts.push(current);
|
|
174
|
+
if (current) { parts.push(current); fromBracket.push(false); }
|
|
172
175
|
}
|
|
173
176
|
|
|
174
177
|
let value: unknown = context;
|
|
175
|
-
for (
|
|
178
|
+
for (let pi = 0; pi < parts.length; pi++) {
|
|
179
|
+
const part = parts[pi];
|
|
180
|
+
const isBracket = fromBracket[pi];
|
|
176
181
|
if (value === null || value === undefined) return null;
|
|
177
182
|
|
|
178
183
|
// Check for method call: name(args)
|
|
@@ -206,10 +211,13 @@ function resolveVar(expr: string, context: Record<string, unknown>): unknown {
|
|
|
206
211
|
const asNum = parseInt(part, 10);
|
|
207
212
|
if (!isNaN(asNum) && String(asNum) === part) {
|
|
208
213
|
key = asNum;
|
|
209
|
-
} else {
|
|
210
|
-
//
|
|
214
|
+
} else if (isBracket) {
|
|
215
|
+
// Only resolve as a variable from context for bracket-derived parts
|
|
211
216
|
const resolved = context[part];
|
|
212
217
|
key = resolved !== undefined ? String(resolved) : part;
|
|
218
|
+
} else {
|
|
219
|
+
// Dot-derived parts or root — use the part name directly as the key
|
|
220
|
+
key = part;
|
|
213
221
|
}
|
|
214
222
|
}
|
|
215
223
|
|
|
@@ -666,45 +674,14 @@ function parseFilterChain(expr: string): [string, [string, string[]][]] {
|
|
|
666
674
|
return [variable, filters];
|
|
667
675
|
}
|
|
668
676
|
|
|
669
|
-
function processEscapes(s: string): string {
|
|
670
|
-
let out = "";
|
|
671
|
-
for (let i = 0; i < s.length; i++) {
|
|
672
|
-
if (s[i] === "\\" && i + 1 < s.length) {
|
|
673
|
-
const nxt = s[i + 1];
|
|
674
|
-
switch (nxt) {
|
|
675
|
-
case "n": out += "\n"; i++; break;
|
|
676
|
-
case "t": out += "\t"; i++; break;
|
|
677
|
-
case "\\": out += "\\"; i++; break;
|
|
678
|
-
case "'": out += "'"; i++; break;
|
|
679
|
-
case '"': out += '"'; i++; break;
|
|
680
|
-
default: out += "\\"; break;
|
|
681
|
-
}
|
|
682
|
-
} else {
|
|
683
|
-
out += s[i];
|
|
684
|
-
}
|
|
685
|
-
}
|
|
686
|
-
return out;
|
|
687
|
-
}
|
|
688
|
-
|
|
689
677
|
function parseArgs(raw: string): string[] {
|
|
690
678
|
const args: string[] = [];
|
|
691
679
|
let current = "";
|
|
692
680
|
let inQuote: string | null = null;
|
|
693
681
|
let wasQuoted = false;
|
|
694
682
|
let depth = 0;
|
|
695
|
-
let escaped = false;
|
|
696
683
|
|
|
697
684
|
for (const ch of raw) {
|
|
698
|
-
if (escaped) {
|
|
699
|
-
current += ch;
|
|
700
|
-
escaped = false;
|
|
701
|
-
continue;
|
|
702
|
-
}
|
|
703
|
-
if (ch === "\\" && inQuote) {
|
|
704
|
-
current += ch;
|
|
705
|
-
escaped = true;
|
|
706
|
-
continue;
|
|
707
|
-
}
|
|
708
685
|
if (inQuote) {
|
|
709
686
|
if (ch === inQuote) {
|
|
710
687
|
inQuote = null;
|
|
@@ -723,7 +700,7 @@ function parseArgs(raw: string): string[] {
|
|
|
723
700
|
if (ch === "(") { depth++; current += ch; continue; }
|
|
724
701
|
if (ch === ")") { depth--; current += ch; continue; }
|
|
725
702
|
if (ch === "," && depth === 0) {
|
|
726
|
-
args.push(wasQuoted ?
|
|
703
|
+
args.push(wasQuoted ? current : current.trim());
|
|
727
704
|
current = "";
|
|
728
705
|
wasQuoted = false;
|
|
729
706
|
continue;
|
|
@@ -731,7 +708,7 @@ function parseArgs(raw: string): string[] {
|
|
|
731
708
|
current += ch;
|
|
732
709
|
}
|
|
733
710
|
|
|
734
|
-
const final = wasQuoted ?
|
|
711
|
+
const final = wasQuoted ? current : current.trim();
|
|
735
712
|
if (final !== "" || wasQuoted) {
|
|
736
713
|
args.push(final);
|
|
737
714
|
}
|
|
@@ -967,9 +944,9 @@ const BUILTIN_FILTERS: Record<string, FilterFn> = {
|
|
|
967
944
|
dump: (v) => JSON.stringify(v),
|
|
968
945
|
formToken: (v?: unknown) => _generateFormToken(v != null ? String(v) : ""),
|
|
969
946
|
form_token: (v?: unknown) => _generateFormToken(v != null ? String(v) : ""),
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
js_escape: (v) => String(v).replace(/\\/g, "\\\\").replace(/'/g, "\\'").replace(/"/g, '\\"').replace(/\n/g, "\\n").replace(/\r/g, "\\r"),
|
|
947
|
+
tojson: (v, indent) => indent !== undefined ? JSON.stringify(v, null, parseInt(String(indent), 10)) : JSON.stringify(v),
|
|
948
|
+
to_json: (v, indent) => indent !== undefined ? JSON.stringify(v, null, parseInt(String(indent), 10)) : JSON.stringify(v),
|
|
949
|
+
js_escape: (v) => String(v).replace(/\\/g, "\\\\").replace(/'/g, "\\'").replace(/"/g, '\\"').replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t"),
|
|
973
950
|
};
|
|
974
951
|
|
|
975
952
|
// ── Form Token ────────────────────────────────────────────────
|