pgflow 0.1.1 → 0.1.2

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.
@@ -0,0 +1,4 @@
1
+ import { type Command } from 'commander';
2
+ declare const _default: (program: Command) => void;
3
+ export default _default;
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/compile/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,WAAW,CAAC;kCAkChB,OAAO;AAAhC,wBA4EE"}
@@ -0,0 +1,133 @@
1
+ import chalk from 'chalk';
2
+ import { intro, log, spinner, note } from '@clack/prompts';
3
+ import path from 'path';
4
+ import fs from 'fs';
5
+ import { spawn } from 'child_process';
6
+ import { fileURLToPath } from 'url';
7
+ // Get the directory name in ES modules
8
+ const __filename = fileURLToPath(import.meta.url);
9
+ const __dirname = path.dirname(__filename);
10
+ /**
11
+ * Formats a command and its arguments for display with syntax highlighting
12
+ * Each argument is displayed on a separate line for better readability
13
+ */
14
+ function formatCommand(command, args) {
15
+ const cmd = chalk.cyan(command);
16
+ const formattedArgs = args.map((arg) => {
17
+ // Highlight import map and file paths differently
18
+ if (arg.startsWith('--import-map=')) {
19
+ const [flag, value] = arg.split('=');
20
+ return ` ${chalk.yellow(flag)}=${chalk.green(value)}`;
21
+ }
22
+ else if (arg.startsWith('--')) {
23
+ return ` ${chalk.yellow(arg)}`;
24
+ }
25
+ else if (arg.endsWith('.ts') || arg.endsWith('.json')) {
26
+ return ` ${chalk.green(arg)}`;
27
+ }
28
+ return ` ${chalk.white(arg)}`;
29
+ });
30
+ return `$ ${cmd}\n${formattedArgs.join('\n')}`;
31
+ }
32
+ export default (program) => {
33
+ program
34
+ .command('compile')
35
+ .description('Compiles a TypeScript-defined flow into SQL migration')
36
+ .argument('<flowPath>', 'Path to the flow TypeScript file')
37
+ .option('--deno-json <denoJsonPath>', 'Path to deno.json with valid importMap')
38
+ .action(async (flowPath, options) => {
39
+ intro('pgflow - Compile Flow to SQL');
40
+ try {
41
+ // Resolve paths
42
+ const resolvedFlowPath = path.resolve(process.cwd(), flowPath);
43
+ // Only resolve denoJsonPath if it's provided
44
+ let resolvedDenoJsonPath;
45
+ if (options.denoJson) {
46
+ resolvedDenoJsonPath = path.resolve(process.cwd(), options.denoJson);
47
+ // Validate deno.json path if provided
48
+ if (!fs.existsSync(resolvedDenoJsonPath)) {
49
+ log.error(`deno.json file not found: ${resolvedDenoJsonPath}`);
50
+ process.exit(1);
51
+ }
52
+ }
53
+ // Validate flow path
54
+ if (!fs.existsSync(resolvedFlowPath)) {
55
+ log.error(`Flow file not found: ${resolvedFlowPath}`);
56
+ process.exit(1);
57
+ }
58
+ // Find the internal_compile.ts script
59
+ const internalCompileScript = path.resolve(__dirname, '../../../deno/internal_compile.ts');
60
+ // Create migrations directory if it doesn't exist
61
+ const migrationsDir = path.resolve(process.cwd(), 'migrations');
62
+ if (!fs.existsSync(migrationsDir)) {
63
+ fs.mkdirSync(migrationsDir, { recursive: true });
64
+ log.info(`Created migrations directory: ${migrationsDir}`);
65
+ }
66
+ // Generate timestamp for migration file
67
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '_');
68
+ const migrationFileName = `pgflow_${timestamp}.sql`;
69
+ const migrationFilePath = path.join(migrationsDir, migrationFileName);
70
+ // Run the compilation
71
+ const s = spinner();
72
+ s.start(`Compiling flow: ${path.basename(resolvedFlowPath)}`);
73
+ const compiledSql = await runDenoCompilation(internalCompileScript, resolvedFlowPath, resolvedDenoJsonPath);
74
+ // Write the SQL to a migration file
75
+ fs.writeFileSync(migrationFilePath, compiledSql);
76
+ s.stop(`Successfully compiled flow to SQL`);
77
+ log.success(`Migration file created: ${migrationFilePath}`);
78
+ }
79
+ catch (error) {
80
+ log.error(`Compilation failed: ${error instanceof Error ? error.message : String(error)}`);
81
+ process.exit(1);
82
+ }
83
+ });
84
+ };
85
+ /**
86
+ * Runs the Deno compilation script and returns the compiled SQL
87
+ */
88
+ async function runDenoCompilation(scriptPath, flowPath, denoJsonPath) {
89
+ return new Promise((resolve, reject) => {
90
+ // Validate input paths
91
+ if (!scriptPath) {
92
+ return reject(new Error('Internal script path is required'));
93
+ }
94
+ if (!flowPath) {
95
+ return reject(new Error('Flow path is required'));
96
+ }
97
+ // Build the command arguments array
98
+ const args = ['run', '--allow-read', '--allow-net', '--allow-env'];
99
+ // Only add the import-map argument if denoJsonPath is provided and valid
100
+ if (denoJsonPath && typeof denoJsonPath === 'string') {
101
+ args.push(`--import-map=${denoJsonPath}`);
102
+ }
103
+ // Add the script path and flow path
104
+ args.push(scriptPath, flowPath);
105
+ // Log the command for debugging with colored output
106
+ note(formatCommand('deno', args), 'Compile in Deno');
107
+ const deno = spawn('deno', args);
108
+ let stdout = '';
109
+ let stderr = '';
110
+ deno.stdout.on('data', (data) => {
111
+ stdout += data.toString();
112
+ });
113
+ deno.stderr.on('data', (data) => {
114
+ stderr += data.toString();
115
+ });
116
+ deno.on('close', (code) => {
117
+ if (code === 0) {
118
+ if (stdout.trim().length === 0) {
119
+ reject(new Error('Compilation produced no output'));
120
+ }
121
+ else {
122
+ resolve(stdout);
123
+ }
124
+ }
125
+ else {
126
+ reject(new Error(`Deno process exited with code ${code}${stderr ? `\n${stderr}` : ''}`));
127
+ }
128
+ });
129
+ deno.on('error', (err) => {
130
+ reject(new Error(`Failed to start Deno process: ${err.message}. Make sure Deno is installed.`));
131
+ });
132
+ });
133
+ }
package/dist/index.js CHANGED
@@ -4,6 +4,7 @@ import { fileURLToPath } from 'url';
4
4
  import { readFileSync } from 'fs';
5
5
  import { dirname, join } from 'path';
6
6
  import installCommand from './commands/install/index.js';
7
+ import compileCommand from './commands/compile/index.js';
7
8
  // Create a function to handle errors
8
9
  const errorHandler = (error) => {
9
10
  console.error('Error:', error instanceof Error ? error.message : String(error));
@@ -38,7 +39,31 @@ program
38
39
  }
39
40
  throw err;
40
41
  });
42
+ // Register commands
41
43
  installCommand(program);
44
+ compileCommand(program);
45
+ import chalk from 'chalk';
46
+ // Tokyo Night inspired colors
47
+ // const p = chalk.hex('#7aa2f7'); // blue-violet
48
+ const g = chalk.hex('#9ece6a'); // vibrant green
49
+ const f = chalk.hex('#bb9af7'); // light purple/pink
50
+ const l = chalk.hex('#2ac3de'); // bright teal/cyan
51
+ // const o = chalk.hex('#ff9e64'); // orange
52
+ // const w = chalk.hex('#f7768e'); // magenta/pink
53
+ const banner = [
54
+ ` ${l('__ _')} `,
55
+ ` ${g('_ __ __ _')} ${l('/ _| | _____ __')} `,
56
+ ` ${g("| '_ \\ / _'")} ${l('| |_| |/ _ \\ \\ /\\ / /')} `,
57
+ ` ${g('| |_) | (_|')} ${l('| _| | (_) \\ V V /')} `,
58
+ ` ${g('| .__/ \\__,')} ${l('|_| |_|\\___/ \\_/\\_/')} `,
59
+ ` ${g('|_| |___/')}`,
60
+ ``,
61
+ ` ${f('Postgres-native Workflow Engine')}`,
62
+ ].join('\n');
63
+ console.log(banner);
64
+ console.log();
65
+ console.log();
66
+ console.log();
42
67
  // Use a promise-aware approach to parse arguments
43
68
  async function main() {
44
69
  try {
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pgflow",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "typings": "./dist/index.d.ts",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pgflow",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "typings": "./dist/index.d.ts",
@@ -24,7 +24,7 @@
24
24
  "chalk": "^5.4.1",
25
25
  "commander": "^13.1.0",
26
26
  "toml-patch": "^0.2.3",
27
- "@pgflow/core": "0.1.1"
27
+ "@pgflow/core": "0.1.2"
28
28
  },
29
29
  "publishConfig": {
30
30
  "access": "public",