tina4-nodejs 3.13.53 → 3.13.54

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.13.53)
1
+ # CLAUDE.md - AI Developer Guide for tina4-nodejs (v3.13.54)
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.13.53 — The Intelligent Native Application 4ramework. A convention-over-configuration structural paradigm. The developer writes TypeScript; Tina4 is invisible infrastructure.
7
+ Tina4 for Node.js/TypeScript v3.13.54 — The Intelligent Native Application 4ramework. A convention-over-configuration structural paradigm. 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.13.53",
3
+ "version": "3.13.54",
4
4
  "type": "module",
5
5
  "description": "Tina4 for Node.js/TypeScript - 54 built-in features, zero dependencies",
6
6
  "keywords": [
@@ -40,6 +40,7 @@ export {
40
40
  status,
41
41
  Migration,
42
42
  splitStatements,
43
+ parseSetTerm,
43
44
  normalizeQuotes,
44
45
  sortMigrationFiles,
45
46
  shouldSkipCreateTable,
@@ -568,6 +568,27 @@ export function normalizeQuotes(sql: string): string {
568
568
  return sql.replace(SMART_QUOTE_RE, (ch) => SMART_QUOTES[ch]);
569
569
  }
570
570
 
571
+ const SET_TERM_RE = /^SET\s+TERM\s+(\S+)$/i;
572
+
573
+ /**
574
+ * Return the new terminator from a `SET TERM <new> <current>` directive.
575
+ *
576
+ * `SET TERM` is a script-level directive (recognised by isql and other
577
+ * InterBase/Firebird tooling, not run by the engine) that changes the
578
+ * terminator separating statements. Recognising it lets a statement whose own
579
+ * body contains the default `;` terminator — a trigger, stored procedure or
580
+ * `EXECUTE BLOCK` — be kept intact rather than split on those inner `;`. The
581
+ * terminator may be more than one character (e.g. `!!`).
582
+ *
583
+ * @param statement A single, already-trimmed statement.
584
+ * @returns The new terminator, or `null` when `statement` is not a `SET TERM`
585
+ * directive.
586
+ */
587
+ export function parseSetTerm(statement: string): string | null {
588
+ const m = statement.trim().match(SET_TERM_RE);
589
+ return m ? m[1] : null;
590
+ }
591
+
571
592
  /**
572
593
  * Split SQL text into individual statements with a single-pass, quote- and
573
594
  * comment-aware scanner. The split decision is made character by character so
@@ -586,7 +607,11 @@ export function normalizeQuotes(sql: string): string {
586
607
  * - `'…'` single-quoted strings and `"…"` double-quoted identifiers are copied
587
608
  * verbatim, honouring the SQL doubled-quote escape (`''` / `""`); a `;`, `--`
588
609
  * or `/*` inside a literal is data, not a delimiter or comment.
589
- * Mirrors the tina4-python `_split_statements` / tina4-php scanner (parity).
610
+ * - A `SET TERM <new> <current>` directive switches the active terminator and is
611
+ * consumed (never emitted), so a statement whose own body contains the default
612
+ * terminator — a Firebird trigger, stored procedure or `EXECUTE BLOCK` —
613
+ * survives as one. Multi-character terminators (e.g. `!!`) are supported.
614
+ * Mirrors the tina4-python `_split_statements` / tina4-php / tina4-ruby scanner (parity).
590
615
  */
591
616
  export function splitStatements(sql: string, delimiter = ";"): string[] {
592
617
  // Normalize smart/curly quotes to straight ASCII first, so SQL pasted from
@@ -596,7 +621,10 @@ export function splitStatements(sql: string, delimiter = ";"): string[] {
596
621
  const statements: string[] = [];
597
622
  let current = "";
598
623
  const n = sql.length;
599
- const dlen = delimiter.length;
624
+ // Active statement terminator. Starts as the delimiter argument; a SET TERM
625
+ // directive can switch it mid-script (dlen recomputed) so a statement whose
626
+ // own body contains the default terminator stays intact.
627
+ let dlen = delimiter.length;
600
628
  let i = 0;
601
629
  let inDollarBlock = false;
602
630
  let inSlashBlock = false;
@@ -685,12 +713,22 @@ export function splitStatements(sql: string, delimiter = ";"): string[] {
685
713
  continue;
686
714
  }
687
715
 
688
- // Statement delimiter — only reached outside blocks/comments/strings.
716
+ // Statement delimiter — only reached outside blocks/comments/strings. A
717
+ // SET TERM directive switches the active terminator and is consumed (never
718
+ // emitted); any other completed statement is collected.
689
719
  if (dlen > 0 && sql.startsWith(delimiter, i)) {
720
+ i += dlen;
690
721
  const stmt = current.trim();
691
- if (stmt) statements.push(stmt);
692
722
  current = "";
693
- i += dlen;
723
+ if (stmt) {
724
+ const newTerm = parseSetTerm(stmt);
725
+ if (newTerm !== null) {
726
+ delimiter = newTerm;
727
+ dlen = delimiter.length;
728
+ } else {
729
+ statements.push(stmt);
730
+ }
731
+ }
694
732
  continue;
695
733
  }
696
734
 
@@ -698,8 +736,10 @@ export function splitStatements(sql: string, delimiter = ";"): string[] {
698
736
  i += 1;
699
737
  }
700
738
 
739
+ // Trailing statement (may not end with a delimiter). A trailing SET TERM
740
+ // directive is a no-op — consume it, don't emit it.
701
741
  const stmt = current.trim();
702
- if (stmt) statements.push(stmt);
742
+ if (stmt && parseSetTerm(stmt) === null) statements.push(stmt);
703
743
  return statements;
704
744
  }
705
745