tina4-nodejs 3.10.14 → 3.10.16

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/CLAUDE.md CHANGED
@@ -1,10 +1,10 @@
1
- # CLAUDE.md — AI Developer Guide for tina4-nodejs (v3.10.14)
1
+ # CLAUDE.md — AI Developer Guide for tina4-nodejs (v3.10.15)
2
2
 
3
3
  > This file helps AI assistants (Claude, Copilot, Cursor, etc.) understand and work on this codebase effectively.
4
4
 
5
5
  ## What This Project Is
6
6
 
7
- Tina4 for Node.js/TypeScript v3.10.14 — a convention-over-configuration structural paradigm. **Not a framework.** The developer writes TypeScript; Tina4 is invisible infrastructure.
7
+ Tina4 for Node.js/TypeScript v3.10.15 — a convention-over-configuration structural paradigm. **Not a framework.** The developer writes TypeScript; Tina4 is invisible infrastructure.
8
8
 
9
9
  The philosophy: zero ceremony, batteries included, file system as source of truth.
10
10
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tina4-nodejs",
3
- "version": "3.10.14",
3
+ "version": "3.10.16",
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"],
@@ -666,14 +666,45 @@ function parseFilterChain(expr: string): [string, [string, string[]][]] {
666
666
  return [variable, filters];
667
667
  }
668
668
 
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
+
669
689
  function parseArgs(raw: string): string[] {
670
690
  const args: string[] = [];
671
691
  let current = "";
672
692
  let inQuote: string | null = null;
673
693
  let wasQuoted = false;
674
694
  let depth = 0;
695
+ let escaped = false;
675
696
 
676
697
  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
+ }
677
708
  if (inQuote) {
678
709
  if (ch === inQuote) {
679
710
  inQuote = null;
@@ -692,7 +723,7 @@ function parseArgs(raw: string): string[] {
692
723
  if (ch === "(") { depth++; current += ch; continue; }
693
724
  if (ch === ")") { depth--; current += ch; continue; }
694
725
  if (ch === "," && depth === 0) {
695
- args.push(wasQuoted ? current : current.trim());
726
+ args.push(wasQuoted ? processEscapes(current) : current.trim());
696
727
  current = "";
697
728
  wasQuoted = false;
698
729
  continue;
@@ -700,7 +731,7 @@ function parseArgs(raw: string): string[] {
700
731
  current += ch;
701
732
  }
702
733
 
703
- const final = wasQuoted ? current : current.trim();
734
+ const final = wasQuoted ? processEscapes(current) : current.trim();
704
735
  if (final !== "" || wasQuoted) {
705
736
  args.push(final);
706
737
  }
@@ -936,6 +967,9 @@ const BUILTIN_FILTERS: Record<string, FilterFn> = {
936
967
  dump: (v) => JSON.stringify(v),
937
968
  formToken: (v?: unknown) => _generateFormToken(v != null ? String(v) : ""),
938
969
  form_token: (v?: unknown) => _generateFormToken(v != null ? String(v) : ""),
970
+ to_json: (v) => JSON.stringify(v).replace(/</g, "\\u003c").replace(/>/g, "\\u003e").replace(/&/g, "\\u0026"),
971
+ tojson: (v) => JSON.stringify(v).replace(/</g, "\\u003c").replace(/>/g, "\\u003e").replace(/&/g, "\\u0026"),
972
+ js_escape: (v) => String(v).replace(/\\/g, "\\\\").replace(/'/g, "\\'").replace(/"/g, '\\"').replace(/\n/g, "\\n").replace(/\r/g, "\\r"),
939
973
  };
940
974
 
941
975
  // ── Form Token ────────────────────────────────────────────────