Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 101 additions & 0 deletions packages/cli/src/glob.rescript.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import chokidar from 'chokidar';
import * as fs from 'fs';
import * as path from 'path';
import * as os from 'os';

/** Uses chokidar to collect files matching a glob pattern (same as CLI) */
function getMatchedFiles(pattern: string): Promise<string[]> {
return new Promise((resolve) => {
const files: string[] = [];
const watcher = chokidar.watch(pattern, { persistent: false });
watcher.on('add', (filePath) => files.push(filePath));
watcher.on('ready', () => {
watcher.close();
resolve(files);
});
});
}

describe('srcDir glob pattern matching', () => {
let testDir: string;
let srcDir: string;
let testsDir: string;

beforeEach(() => {
// Create a temporary directory structure
testDir = fs.mkdtempSync(path.join(os.tmpdir(), 'pgtyped-test-'));
srcDir = path.join(testDir, 'src');
testsDir = path.join(testDir, '__tests__');

// Create directories
fs.mkdirSync(srcDir, { recursive: true });
fs.mkdirSync(testsDir, { recursive: true });
fs.mkdirSync(path.join(srcDir, 'queries'), { recursive: true });
fs.mkdirSync(path.join(testsDir, 'queries'), { recursive: true });

// Create test SQL files
fs.writeFileSync(
path.join(srcDir, 'queries', 'users.sql'),
'/* @name GetUsers */\nSELECT * FROM users;',
);
fs.writeFileSync(
path.join(testsDir, 'queries', 'test.sql'),
'/* @name GetTestData */\nSELECT * FROM test_data;',
);
});

afterEach(() => {
// Cleanup
fs.rmSync(testDir, { recursive: true, force: true });
});

test('simple srcDir pattern finds SQL files', async () => {
const srcDirPattern = path.join(testDir, 'src');
const include = '**/*.sql';
const pattern = `${srcDirPattern}/**/${include}`;

const files = await getMatchedFiles(pattern);
expect(files.length).toBe(1);
expect(files[0]).toContain('users.sql');
});

test('parentheses extglob syntax (src|__tests__) finds files in both directories', async () => {
const srcDirPattern = `${testDir}/(src|__tests__)`;
const include = '**/*.sql';
const pattern = `${srcDirPattern}/**/${include}`;

const files = await getMatchedFiles(pattern);
expect(files.length).toBe(2);
});

test('brace syntax {src,__tests__} finds files in both directories', async () => {
const srcDirPattern = `${testDir}/{src,__tests__}`;
const include = '**/*.sql';
const pattern = `${srcDirPattern}/**/${include}`;

const files = await getMatchedFiles(pattern);
expect(files.length).toBe(2);
});

test('srcDir with embedded wildcards (src|__tests__)/**/* works', async () => {
// The user's config had srcDir: "./(src|__tests__)/**/*"
const srcDirWithWildcard = `${testDir}/(src|__tests__)/**/*`;
const include = '**/*.sql';
const pattern = `${srcDirWithWildcard}/**/${include}`;

const files = await getMatchedFiles(pattern);
expect(files.length).toBe(2);
});

test('empty directory returns empty array without error', async () => {
const emptyDir = path.join(testDir, 'empty');
fs.mkdirSync(emptyDir, { recursive: true });

const srcDirPattern = emptyDir;
const include = '**/*.sql';
const pattern = `${srcDirPattern}/**/${include}`;

const files = await getMatchedFiles(pattern);
expect(files.length).toBe(0);
});
});
20 changes: 16 additions & 4 deletions packages/cli/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import { startup } from 'pgtyped-rescript-query';
import { AsyncQueue } from '@pgtyped/wire';
import chokidar from 'chokidar';
import { globSync } from 'glob';
import nun from 'nunjucks';
import yargs from 'yargs';
import { hideBin } from 'yargs/helpers';
Expand All @@ -17,6 +16,19 @@ import WorkerPool from 'piscina';

nun.configure({ autoescape: false });

/** Uses chokidar to collect files matching a glob pattern */
function getMatchedFiles(pattern: string): Promise<string[]> {
return new Promise((resolve) => {
const files: string[] = [];
const watcher = chokidar.watch(pattern, { persistent: false });
watcher.on('add', (filePath) => files.push(filePath));
watcher.on('ready', () => {
watcher.close();
resolve(files);
});
});
}

interface TransformJob {
files: string[];
transform: TransformConfig;
Expand Down Expand Up @@ -113,10 +125,10 @@ async function main(
.on('change', cb);
} else {
/**
* If the user didn't provide the -f paramter, we're using the list of files we got from glob.
* If he did, we're using glob file list to detect if his provided file should be used with this transform.
* If the user didn't provide the -f parameter, we're using the list of files we got from chokidar.
* If he did, we're using the file list to detect if his provided file should be used with this transform.
*/
let fileList = globSync(pattern);
let fileList = await getMatchedFiles(pattern);
if (fileOverride) {
fileList = fileList.includes(fileOverride) ? [fileOverride] : [];
if (fileList.length > 0) {
Expand Down