@tinybirdco/sdk 0.0.8 → 0.0.9

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.
Files changed (37) hide show
  1. package/dist/cli/commands/init.d.ts.map +1 -1
  2. package/dist/cli/commands/init.js +301 -205
  3. package/dist/cli/commands/init.js.map +1 -1
  4. package/dist/cli/commands/init.test.js +67 -93
  5. package/dist/cli/commands/init.test.js.map +1 -1
  6. package/dist/cli/config.d.ts +3 -7
  7. package/dist/cli/config.d.ts.map +1 -1
  8. package/dist/cli/config.js +9 -20
  9. package/dist/cli/config.js.map +1 -1
  10. package/dist/cli/config.test.js +11 -29
  11. package/dist/cli/config.test.js.map +1 -1
  12. package/dist/cli/git.d.ts +5 -0
  13. package/dist/cli/git.d.ts.map +1 -1
  14. package/dist/cli/git.js +15 -0
  15. package/dist/cli/git.js.map +1 -1
  16. package/dist/cli/index.js +42 -25
  17. package/dist/cli/index.js.map +1 -1
  18. package/dist/cli/utils/package-manager.d.ts +9 -0
  19. package/dist/cli/utils/package-manager.d.ts.map +1 -1
  20. package/dist/cli/utils/package-manager.js +130 -35
  21. package/dist/cli/utils/package-manager.js.map +1 -1
  22. package/dist/cli/utils/package-manager.test.js +124 -32
  23. package/dist/cli/utils/package-manager.test.js.map +1 -1
  24. package/dist/codegen/index.d.ts +4 -0
  25. package/dist/codegen/index.d.ts.map +1 -1
  26. package/dist/codegen/index.js +92 -0
  27. package/dist/codegen/index.js.map +1 -1
  28. package/package.json +1 -1
  29. package/src/cli/commands/init.test.ts +67 -107
  30. package/src/cli/commands/init.ts +350 -218
  31. package/src/cli/config.test.ts +12 -42
  32. package/src/cli/config.ts +9 -23
  33. package/src/cli/git.ts +15 -0
  34. package/src/cli/index.ts +46 -27
  35. package/src/cli/utils/package-manager.test.ts +165 -33
  36. package/src/cli/utils/package-manager.ts +133 -30
  37. package/src/codegen/index.ts +115 -0
@@ -3,42 +3,145 @@
3
3
  */
4
4
 
5
5
  import { existsSync, readFileSync } from "node:fs";
6
- import { join } from "node:path";
6
+ import { dirname, join, resolve } from "node:path";
7
7
 
8
- /**
9
- * Detect package manager and return the appropriate run command
10
- */
11
- export function detectPackageManagerRunCmd(cwd: string = process.cwd()): string {
12
- // Check lockfiles first (most reliable)
13
- if (existsSync(join(cwd, "pnpm-lock.yaml"))) {
14
- return "pnpm";
8
+ export type PackageManager = "pnpm" | "yarn" | "bun" | "npm";
9
+ const TINYBIRD_SDK_PACKAGE = "@tinybirdco/sdk";
10
+
11
+ function detectPackageManagerFromLockfile(dir: string): PackageManager | undefined {
12
+ if (existsSync(join(dir, "pnpm-lock.yaml"))) return "pnpm";
13
+ if (existsSync(join(dir, "yarn.lock"))) return "yarn";
14
+ if (existsSync(join(dir, "bun.lockb"))) return "bun";
15
+ if (existsSync(join(dir, "package-lock.json"))) return "npm";
16
+ return undefined;
17
+ }
18
+
19
+ function detectPackageManagerFromWorkspace(dir: string): PackageManager | undefined {
20
+ if (existsSync(join(dir, "pnpm-workspace.yaml"))) return "pnpm";
21
+ if (existsSync(join(dir, "pnpm-workspace.yml"))) return "pnpm";
22
+ return undefined;
23
+ }
24
+
25
+ function detectPackageManagerFromPackageJson(
26
+ dir: string
27
+ ): PackageManager | undefined {
28
+ const packageJsonPath = join(dir, "package.json");
29
+ if (!existsSync(packageJsonPath)) return undefined;
30
+ try {
31
+ const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
32
+ const pm = packageJson.packageManager;
33
+ if (typeof pm !== "string") return undefined;
34
+ if (pm.startsWith("pnpm")) return "pnpm";
35
+ if (pm.startsWith("yarn")) return "yarn";
36
+ if (pm.startsWith("bun")) return "bun";
37
+ if (pm.startsWith("npm")) return "npm";
38
+ } catch {
39
+ return undefined;
15
40
  }
16
- if (existsSync(join(cwd, "yarn.lock"))) {
17
- return "yarn";
41
+ return undefined;
42
+ }
43
+
44
+ function getSearchDirs(start: string): string[] {
45
+ const dirs: string[] = [];
46
+ let current = resolve(start);
47
+ while (true) {
48
+ dirs.push(current);
49
+ const parent = dirname(current);
50
+ if (parent === current) break;
51
+ current = parent;
52
+ }
53
+ return dirs;
54
+ }
55
+
56
+ function findNearestPackageJson(start: string): string | undefined {
57
+ for (const dir of getSearchDirs(start)) {
58
+ const packageJsonPath = join(dir, "package.json");
59
+ if (existsSync(packageJsonPath)) return packageJsonPath;
18
60
  }
19
- if (existsSync(join(cwd, "bun.lockb"))) {
20
- return "bun run";
61
+ return undefined;
62
+ }
63
+
64
+ export function getPackageManagerRunCmd(packageManager: PackageManager): string {
65
+ switch (packageManager) {
66
+ case "pnpm":
67
+ return "pnpm run";
68
+ case "yarn":
69
+ return "yarn";
70
+ case "bun":
71
+ return "bun run";
72
+ case "npm":
73
+ default:
74
+ return "npm run";
75
+ }
76
+ }
77
+
78
+ export function getPackageManagerInstallCmd(
79
+ packageManager: PackageManager
80
+ ): string {
81
+ switch (packageManager) {
82
+ case "pnpm":
83
+ return "pnpm install";
84
+ case "yarn":
85
+ return "yarn install";
86
+ case "bun":
87
+ return "bun install";
88
+ case "npm":
89
+ default:
90
+ return "npm install";
21
91
  }
22
- if (existsSync(join(cwd, "package-lock.json"))) {
23
- return "npm run";
92
+ }
93
+
94
+ /**
95
+ * Detect package manager (npm, pnpm, yarn, or bun)
96
+ */
97
+ export function detectPackageManager(cwd: string = process.cwd()): PackageManager {
98
+ for (const dir of getSearchDirs(cwd)) {
99
+ const fromLockfile = detectPackageManagerFromLockfile(dir);
100
+ if (fromLockfile) return fromLockfile;
101
+
102
+ const fromWorkspace = detectPackageManagerFromWorkspace(dir);
103
+ if (fromWorkspace) return fromWorkspace;
104
+
105
+ const fromPackageJson = detectPackageManagerFromPackageJson(dir);
106
+ if (fromPackageJson) return fromPackageJson;
24
107
  }
25
108
 
26
- // Check packageManager field in package.json
27
- const packageJsonPath = join(cwd, "package.json");
28
- if (existsSync(packageJsonPath)) {
29
- try {
30
- const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
31
- const pm = packageJson.packageManager;
32
- if (typeof pm === "string") {
33
- if (pm.startsWith("pnpm")) return "pnpm";
34
- if (pm.startsWith("yarn")) return "yarn";
35
- if (pm.startsWith("bun")) return "bun run";
36
- }
37
- } catch {
38
- // Ignore parse errors
39
- }
109
+ return "npm";
110
+ }
111
+
112
+ export function detectPackageManagerInstallCmd(
113
+ cwd: string = process.cwd()
114
+ ): string {
115
+ return getPackageManagerInstallCmd(detectPackageManager(cwd));
116
+ }
117
+
118
+ export function hasTinybirdSdkDependency(cwd: string = process.cwd()): boolean {
119
+ const packageJsonPath = findNearestPackageJson(cwd);
120
+ if (!packageJsonPath) return false;
121
+
122
+ try {
123
+ const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
124
+ const dependencyFields = [
125
+ packageJson.dependencies,
126
+ packageJson.devDependencies,
127
+ packageJson.peerDependencies,
128
+ packageJson.optionalDependencies,
129
+ ];
130
+
131
+ return dependencyFields.some(
132
+ (deps) =>
133
+ deps &&
134
+ typeof deps === "object" &&
135
+ Object.prototype.hasOwnProperty.call(deps, TINYBIRD_SDK_PACKAGE)
136
+ );
137
+ } catch {
138
+ return false;
40
139
  }
140
+ }
41
141
 
42
- // Default to npm
43
- return "npm run";
142
+ /**
143
+ * Detect package manager and return the appropriate run command
144
+ */
145
+ export function detectPackageManagerRunCmd(cwd: string = process.cwd()): string {
146
+ return getPackageManagerRunCmd(detectPackageManager(cwd));
44
147
  }
@@ -20,6 +20,9 @@ export function generateDatasourceCode(ds: DatasourceInfo): string {
20
20
  const typeName = toPascalCase(ds.name);
21
21
  const lines: string[] = [];
22
22
 
23
+ // Check if any columns have jsonpath set
24
+ const hasJsonpath = ds.columns.some((col) => col.jsonpath);
25
+
23
26
  // JSDoc comment
24
27
  if (ds.description) {
25
28
  lines.push("/**");
@@ -33,6 +36,11 @@ export function generateDatasourceCode(ds: DatasourceInfo): string {
33
36
  lines.push(` description: "${escapeString(ds.description)}",`);
34
37
  }
35
38
 
39
+ // Add jsonPaths: false if no columns use jsonpath
40
+ if (!hasJsonpath) {
41
+ lines.push(" jsonPaths: false,");
42
+ }
43
+
36
44
  // Schema
37
45
  lines.push(" schema: {");
38
46
  for (const col of ds.columns) {
@@ -382,3 +390,110 @@ export function generateAllFiles(
382
390
  pipeCount: pipes.length,
383
391
  };
384
392
  }
393
+
394
+ /**
395
+ * Generate a single combined tinybird.ts file with all definitions
396
+ */
397
+ export function generateCombinedFile(
398
+ datasources: DatasourceInfo[],
399
+ pipes: PipeInfo[]
400
+ ): string {
401
+ const lines: string[] = [
402
+ "/**",
403
+ " * Tinybird Definitions",
404
+ " *",
405
+ " * This file contains all datasource and endpoint definitions.",
406
+ " * Generated from existing workspace resources.",
407
+ " */",
408
+ "",
409
+ ];
410
+
411
+ // Build imports
412
+ const sdkImports: string[] = ["createTinybirdClient", "t"];
413
+
414
+ if (datasources.length > 0) {
415
+ sdkImports.push("defineDatasource", "engine", "type InferRow");
416
+ }
417
+
418
+ const hasMaterialized = pipes.some((p) => p.type === "materialized");
419
+ const hasCopy = pipes.some((p) => p.type === "copy");
420
+ const hasEndpoint = pipes.some((p) => p.type === "endpoint");
421
+ const hasPlainPipe = pipes.some((p) => p.type === "pipe");
422
+ const hasParams = pipes.some(
423
+ (p) => p.params.length > 0 && p.type !== "materialized" && p.type !== "copy"
424
+ );
425
+
426
+ if (pipes.length > 0) {
427
+ sdkImports.push("node");
428
+ }
429
+ if (hasParams) {
430
+ sdkImports.push("p");
431
+ }
432
+ if (hasEndpoint) {
433
+ sdkImports.push("defineEndpoint", "type InferParams", "type InferOutputRow");
434
+ }
435
+ if (hasMaterialized) {
436
+ sdkImports.push("defineMaterializedView");
437
+ }
438
+ if (hasCopy) {
439
+ sdkImports.push("defineCopyPipe");
440
+ }
441
+ if (hasPlainPipe) {
442
+ sdkImports.push("definePipe");
443
+ }
444
+
445
+ lines.push(`import {`);
446
+ lines.push(` ${sdkImports.join(",\n ")},`);
447
+ lines.push(`} from "@tinybirdco/sdk";`);
448
+ lines.push("");
449
+
450
+ // Datasources section
451
+ if (datasources.length > 0) {
452
+ lines.push("// ============================================================================");
453
+ lines.push("// Datasources");
454
+ lines.push("// ============================================================================");
455
+ lines.push("");
456
+
457
+ for (const ds of datasources) {
458
+ lines.push(generateDatasourceCode(ds));
459
+ lines.push("");
460
+ }
461
+ }
462
+
463
+ // Pipes/Endpoints section
464
+ if (pipes.length > 0) {
465
+ lines.push("// ============================================================================");
466
+ lines.push("// Endpoints");
467
+ lines.push("// ============================================================================");
468
+ lines.push("");
469
+
470
+ for (const pipe of pipes) {
471
+ lines.push(generatePipeCode(pipe));
472
+ lines.push("");
473
+ }
474
+ }
475
+
476
+ // Client section
477
+ lines.push("// ============================================================================");
478
+ lines.push("// Client");
479
+ lines.push("// ============================================================================");
480
+ lines.push("");
481
+
482
+ const dsNames =
483
+ datasources.length > 0
484
+ ? datasources.map((ds) => toCamelCase(ds.name)).join(", ")
485
+ : "";
486
+ const endpoints = pipes.filter((p) => p.type === "endpoint");
487
+ const pipeNames =
488
+ endpoints.length > 0
489
+ ? endpoints.map((p) => toCamelCase(p.name)).join(", ")
490
+ : "";
491
+
492
+ lines.push("export const tinybird = createTinybirdClient({");
493
+ lines.push(` datasources: { ${dsNames} },`);
494
+ lines.push(` pipes: { ${pipeNames} },`);
495
+ lines.push("});");
496
+ lines.push("");
497
+
498
+ return lines.join("\n");
499
+ }