tina4-nodejs 3.10.63 → 3.10.65

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tina4-nodejs",
3
- "version": "3.10.63",
3
+ "version": "3.10.65",
4
4
  "type": "module",
5
5
  "description": "Tina4 for Node.js/TypeScript — 54 built-in features, zero dependencies",
6
6
  "keywords": ["tina4", "framework", "web", "api", "orm", "graphql", "websocket", "typescript"],
@@ -133,10 +133,8 @@ async function main(): Promise<void> {
133
133
  }
134
134
  case "console": {
135
135
  const repl = await import("node:repl");
136
- const { loadEnv } = await import("@tina4/core");
137
- const { Router } = await import("@tina4/core");
138
- const { initDatabase, Database } = await import("@tina4/orm");
139
- const { Log } = await import("@tina4/core");
136
+ const { loadEnv, Router, Log } = await import("../../core/src/index.js");
137
+ const { initDatabase, Database } = await import("../../orm/src/index.js");
140
138
 
141
139
  loadEnv();
142
140
 
@@ -20,15 +20,15 @@ export async function runMigrations(migrationDir?: string): Promise<void> {
20
20
  }
21
21
 
22
22
  // Initialise the database so the adapter is available
23
- let initDatabase: typeof import("@tina4/orm").initDatabase;
24
- let ensureMigrationTable: typeof import("@tina4/orm").ensureMigrationTable;
25
- let isMigrationApplied: typeof import("@tina4/orm").isMigrationApplied;
26
- let recordMigration: typeof import("@tina4/orm").recordMigration;
27
- let getNextBatch: typeof import("@tina4/orm").getNextBatch;
28
- let getAdapter: typeof import("@tina4/orm").getAdapter;
23
+ let initDatabase: typeof import("../../../orm/src/index.js").initDatabase;
24
+ let ensureMigrationTable: typeof import("../../../orm/src/index.js").ensureMigrationTable;
25
+ let isMigrationApplied: typeof import("../../../orm/src/index.js").isMigrationApplied;
26
+ let recordMigration: typeof import("../../../orm/src/index.js").recordMigration;
27
+ let getNextBatch: typeof import("../../../orm/src/index.js").getNextBatch;
28
+ let getAdapter: typeof import("../../../orm/src/index.js").getAdapter;
29
29
 
30
30
  try {
31
- const orm = await import("@tina4/orm");
31
+ const orm = await import("../../../orm/src/index.js");
32
32
  initDatabase = orm.initDatabase;
33
33
  ensureMigrationTable = orm.ensureMigrationTable;
34
34
  isMigrationApplied = orm.isMigrationApplied;
@@ -13,13 +13,13 @@ import { resolve } from "node:path";
13
13
  export async function migrateRollback(migrationDir?: string): Promise<void> {
14
14
  const dir = resolve(migrationDir ?? "migrations");
15
15
 
16
- let initDatabase: typeof import("@tina4/orm").initDatabase;
17
- let ensureMigrationTable: typeof import("@tina4/orm").ensureMigrationTable;
18
- let rollbackFn: typeof import("@tina4/orm").rollback;
19
- let getLastBatchMigrations: typeof import("@tina4/orm").getLastBatchMigrations;
16
+ let initDatabase: typeof import("../../../orm/src/index.js").initDatabase;
17
+ let ensureMigrationTable: typeof import("../../../orm/src/index.js").ensureMigrationTable;
18
+ let rollbackFn: typeof import("../../../orm/src/index.js").rollback;
19
+ let getLastBatchMigrations: typeof import("../../../orm/src/index.js").getLastBatchMigrations;
20
20
 
21
21
  try {
22
- const orm = await import("@tina4/orm");
22
+ const orm = await import("../../../orm/src/index.js");
23
23
  initDatabase = orm.initDatabase;
24
24
  ensureMigrationTable = orm.ensureMigrationTable;
25
25
  rollbackFn = orm.rollback;
@@ -10,12 +10,12 @@ import { resolve } from "node:path";
10
10
  export async function migrateStatus(migrationDir?: string): Promise<void> {
11
11
  const dir = resolve(migrationDir ?? "migrations");
12
12
 
13
- let initDatabase: typeof import("@tina4/orm").initDatabase;
14
- let ensureMigrationTable: typeof import("@tina4/orm").ensureMigrationTable;
15
- let statusFn: typeof import("@tina4/orm").status;
13
+ let initDatabase: typeof import("../../../orm/src/index.js").initDatabase;
14
+ let ensureMigrationTable: typeof import("../../../orm/src/index.js").ensureMigrationTable;
15
+ let statusFn: typeof import("../../../orm/src/index.js").status;
16
16
 
17
17
  try {
18
- const orm = await import("@tina4/orm");
18
+ const orm = await import("../../../orm/src/index.js");
19
19
  initDatabase = orm.initDatabase;
20
20
  ensureMigrationTable = orm.ensureMigrationTable;
21
21
  statusFn = orm.status;
@@ -14,10 +14,10 @@ export async function listRoutes(): Promise<void> {
14
14
  process.exit(1);
15
15
  }
16
16
 
17
- let discoverRoutes: typeof import("@tina4/core").discoverRoutes;
17
+ let discoverRoutes: typeof import("../../../core/src/index.js").discoverRoutes;
18
18
 
19
19
  try {
20
- const core = await import("@tina4/core");
20
+ const core = await import("../../../core/src/index.js");
21
21
  discoverRoutes = core.discoverRoutes;
22
22
  } catch {
23
23
  console.error(" Error: @tina4/core is required to list routes.");
@@ -50,22 +50,71 @@ function readFileSafe(filePath: string): string | null {
50
50
  }
51
51
  }
52
52
 
53
- function relativePath(filePath: string): string {
54
- return path.relative(".", filePath);
53
+ function relativePath(filePath: string, root: string = "."): string {
54
+ return path.relative(root, filePath);
55
55
  }
56
56
 
57
57
  // ── Test file detection ─────────────────────────────────────
58
58
 
59
59
  function hasMatchingTest(relPath: string): boolean {
60
- const name = relPath.split('/').pop()?.replace('.ts', '').replace('.js', '') || '';
61
- const patterns = [
62
- `test/${name}.test.ts`,
63
- `test/${name}.test.js`,
64
- `${relPath.replace('.ts', '.test.ts').replace('.js', '.test.js')}`,
65
- `tests/${name}.test.ts`,
66
- `spec/${name}.spec.ts`,
67
- ];
68
- return patterns.some(p => fs.existsSync(p));
60
+ const parts = relPath.split('/');
61
+ const basename = parts[parts.length - 1] || '';
62
+ const name = basename.replace(/\.(ts|js)$/, '');
63
+ // Parent directory name (e.g. "adapters" from "adapters/sqlite.ts")
64
+ const parentModule = parts.length > 1 ? parts[parts.length - 2] : '';
65
+
66
+ // Stage 1: Filename matching — name.test, name.spec, test_name patterns
67
+ const testDirs = ['test', 'tests', 'spec'];
68
+ for (const td of testDirs) {
69
+ const patterns = [
70
+ `${td}/${name}.test.ts`,
71
+ `${td}/${name}.test.js`,
72
+ `${td}/${name}.spec.ts`,
73
+ `${td}/${name}.spec.js`,
74
+ // Also check parent-named tests (test/database.test.ts covers adapters/sqlite.ts)
75
+ ...(parentModule && parentModule !== name ? [
76
+ `${td}/${parentModule}.test.ts`,
77
+ `${td}/${parentModule}.test.js`,
78
+ `${td}/${parentModule}.spec.ts`,
79
+ ] : []),
80
+ ];
81
+ if (patterns.some(p => fs.existsSync(p))) {
82
+ return true;
83
+ }
84
+ }
85
+
86
+ // Build the module import path for content matching
87
+ // e.g. "packages/core/src/metrics.ts" → "metrics" or "src/metrics"
88
+ const pathWithoutExt = relPath.replace(/\.(ts|js)$/, '');
89
+ // Build CamelCase class name from camelCase/kebab module name
90
+ // e.g. "sqlTranslation" → "SqlTranslation", "sql-translation" → "SqlTranslation"
91
+ const className = name
92
+ .replace(/[-_](.)/g, (_, c: string) => c.toUpperCase())
93
+ .replace(/^(.)/, (_, c: string) => c.toUpperCase());
94
+
95
+ // Stage 2+3: Content scan — check if any test file imports or references this module
96
+ for (const td of testDirs) {
97
+ if (!fs.existsSync(td)) continue;
98
+ const testFiles = walkFiles(td, ['.ts', '.js']);
99
+ for (const testFile of testFiles) {
100
+ const content = readFileSafe(testFile);
101
+ if (content === null) continue;
102
+ // Stage 2: import path matching
103
+ if (content.includes(name) && (
104
+ content.includes(`"${name}"`) || content.includes(`'${name}'`) ||
105
+ content.includes(`/${name}"`) || content.includes(`/${name}'`) ||
106
+ content.includes(pathWithoutExt)
107
+ )) {
108
+ return true;
109
+ }
110
+ // Stage 3: class name mention
111
+ if (className !== name && new RegExp(`\\b${className.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\b`).test(content)) {
112
+ return true;
113
+ }
114
+ }
115
+ }
116
+
117
+ return false;
69
118
  }
70
119
 
71
120
  // ── Line counting ────────────────────────────────────────────
@@ -192,7 +241,7 @@ interface FunctionInfo {
192
241
  file?: string;
193
242
  }
194
243
 
195
- function extractFunctions(source: string, filePath: string): FunctionInfo[] {
244
+ function extractFunctions(source: string, filePath: string, root: string = "."): FunctionInfo[] {
196
245
  const functions: FunctionInfo[] = [];
197
246
  const lines = source.split("\n");
198
247
 
@@ -268,7 +317,7 @@ function extractFunctions(source: string, filePath: string): FunctionInfo[] {
268
317
  complexity,
269
318
  loc: funcLoc,
270
319
  args,
271
- file: relativePath(filePath),
320
+ file: relativePath(filePath, root),
272
321
  });
273
322
 
274
323
  break; // Only match first pattern per line
@@ -590,7 +639,7 @@ export function quickMetrics(root: string = "src"): Record<string, any> {
590
639
  totalFunctions += functions;
591
640
 
592
641
  fileDetails.push({
593
- path: relativePath(f),
642
+ path: relativePath(f, rootPath),
594
643
  loc: counts.loc,
595
644
  blank: counts.blank,
596
645
  comment: counts.comment,
@@ -704,7 +753,7 @@ export function fullAnalysis(root: string = "src"): Record<string, any> {
704
753
  const source = readFileSafe(f);
705
754
  if (source === null) continue;
706
755
 
707
- const relPath = relativePath(f);
756
+ const relPath = relativePath(f, rootPath);
708
757
  const lines = source.split("\n");
709
758
  const loc = lines.filter(
710
759
  (l) => l.trim() && !l.trim().startsWith("//")
@@ -722,7 +771,7 @@ export function fullAnalysis(root: string = "src"): Record<string, any> {
722
771
  }
723
772
 
724
773
  // Analyze functions/methods
725
- const fileFunctions = extractFunctions(source, f);
774
+ const fileFunctions = extractFunctions(source, f, rootPath);
726
775
  let fileComplexity = 0;
727
776
 
728
777
  for (const func of fileFunctions) {