Skip to content
Closed
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
5 changes: 2 additions & 3 deletions pgpm/cli/src/commands/init/workspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@ export default async function runWorkspaceSetup(
const answers = await prompter.prompt(argv, workspaceQuestions);
const { cwd = process.cwd() } = argv;
const targetPath = path.join(cwd, sluggify(answers.name));
// Prevent double-echoed keystrokes by closing our prompter before template prompts.
prompter.close();

const templateRepo = (argv.repo as string) ?? DEFAULT_TEMPLATE_REPO;
// Don't set default templatePath - let scaffoldTemplate use metadata-driven resolution
Expand All @@ -52,7 +50,8 @@ export default async function runWorkspaceSetup(
},
toolName: DEFAULT_TEMPLATE_TOOL_NAME,
noTty: Boolean((argv as any).noTty || argv['no-tty'] || process.env.CI === 'true'),
cwd
cwd,
prompter
});

// Check for .motd file and print it, or use default ASCII art
Expand Down
1 change: 1 addition & 0 deletions pgpm/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
"create-gen-app": "^0.6.4",
"csv-to-pg": "^2.0.10",
"glob": "^13.0.0",
"inquirerer": "^2.3.2",
"komoji": "^0.7.11",
"parse-package-name": "^1.0.0",
"pg": "^8.16.3",
Expand Down
117 changes: 0 additions & 117 deletions pgpm/core/src/core/boilerplate-scanner.ts

This file was deleted.

60 changes: 0 additions & 60 deletions pgpm/core/src/core/boilerplate-types.ts

This file was deleted.

69 changes: 51 additions & 18 deletions pgpm/core/src/core/template-scaffold.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,7 @@ import fs from 'fs';
import os from 'os';
import path from 'path';
import { CacheManager, GitCloner, Templatizer } from 'create-gen-app';

import { BoilerplateQuestion } from './boilerplate-types';
import {
readBoilerplateConfig,
readBoilerplatesConfig,
resolveBoilerplateBaseDir,
} from './boilerplate-scanner';
import { Inquirerer, Question } from 'inquirerer';

export type TemplateKind = 'workspace' | 'module';

Expand All @@ -26,6 +20,12 @@ export interface ScaffoldTemplateOptions {
cacheBaseDir?: string;
/** Override the boilerplate directory (e.g., "default", "supabase") */
dir?: string;
/**
* Optional Inquirerer instance to reuse for prompting.
* If provided, the caller retains ownership and is responsible for closing it.
* If not provided, a new instance will be created and closed automatically by create-gen-app.
*/
prompter?: Inquirerer;
}

export interface ScaffoldTemplateResult {
Expand All @@ -34,7 +34,7 @@ export interface ScaffoldTemplateResult {
cachePath?: string;
templateDir: string;
/** Questions loaded from .boilerplate.json, if any */
questions?: BoilerplateQuestion[];
questions?: Question[];
}

export const DEFAULT_TEMPLATE_REPO =
Expand All @@ -50,8 +50,43 @@ const looksLikePath = (value: string): boolean => {
);
};

interface BoilerplatesConfig {
dir?: string;
}

interface BoilerplateConfig {
type?: string;
questions?: Question[];
}

function readBoilerplatesConfig(templateDir: string): BoilerplatesConfig | null {
const configPath = path.join(templateDir, '.boilerplates.json');
if (fs.existsSync(configPath)) {
try {
const content = fs.readFileSync(configPath, 'utf-8');
return JSON.parse(content) as BoilerplatesConfig;
} catch {
return null;
}
}
return null;
}

function readBoilerplateConfig(boilerplatePath: string): BoilerplateConfig | null {
const jsonPath = path.join(boilerplatePath, '.boilerplate.json');
if (fs.existsSync(jsonPath)) {
try {
const content = fs.readFileSync(jsonPath, 'utf-8');
return JSON.parse(content) as BoilerplateConfig;
} catch {
return null;
}
}
return null;
}

/**
* Resolve the template path using the new metadata-driven resolution.
* Resolve the template path using the metadata-driven resolution.
*
* Resolution order:
* 1. If explicit `templatePath` is provided, use it directly
Expand All @@ -65,7 +100,6 @@ const resolveFromPath = (
type: TemplateKind,
dirOverride?: string
): { fromPath: string; resolvedTemplatePath: string } => {
// If explicit templatePath is provided, use it directly
if (templatePath) {
const candidateDir = path.isAbsolute(templatePath)
? templatePath
Expand All @@ -85,12 +119,10 @@ const resolveFromPath = (
};
}

// Try new metadata-driven resolution
const rootConfig = readBoilerplatesConfig(templateDir);
const baseDir = dirOverride ?? rootConfig?.dir;

if (baseDir) {
// New structure: {templateDir}/{baseDir}/{type}
const newStructurePath = path.join(templateDir, baseDir, type);
if (
fs.existsSync(newStructurePath) &&
Expand All @@ -103,7 +135,6 @@ const resolveFromPath = (
}
}

// Fallback to legacy structure: {templateDir}/{type}
const legacyPath = path.join(templateDir, type);
if (fs.existsSync(legacyPath) && fs.statSync(legacyPath).isDirectory()) {
return {
Expand All @@ -112,13 +143,16 @@ const resolveFromPath = (
};
}

// Default fallback
return {
fromPath: type,
resolvedTemplatePath: path.join(templateDir, type),
};
};

/**
* Scaffold a template using create-gen-app components.
* This provides pgpm-specific defaults and path resolution.
*/
export async function scaffoldTemplate(
options: ScaffoldTemplateOptions
): Promise<ScaffoldTemplateResult> {
Expand All @@ -135,13 +169,13 @@ export async function scaffoldTemplate(
cwd,
cacheBaseDir,
dir,
prompter,
} = options;

const resolvedRepo = looksLikePath(templateRepo)
? path.resolve(cwd ?? process.cwd(), templateRepo)
: templateRepo;

// Handle local template directories without caching
if (
looksLikePath(templateRepo) &&
fs.existsSync(resolvedRepo) &&
Expand All @@ -154,13 +188,13 @@ export async function scaffoldTemplate(
dir
);

// Read boilerplate config for questions (create-gen-app now handles .boilerplate.json natively)
const boilerplateConfig = readBoilerplateConfig(resolvedTemplatePath);

await templatizer.process(resolvedRepo, outputDir, {
argv: answers,
noTty,
fromPath,
prompter,
} as any);

return {
Expand All @@ -171,7 +205,6 @@ export async function scaffoldTemplate(
};
}

// Remote repo with caching
const cacheManager = new CacheManager({
toolName,
ttl: cacheTtlMs,
Expand Down Expand Up @@ -216,13 +249,13 @@ export async function scaffoldTemplate(
dir
);

// Read boilerplate config for questions (create-gen-app now handles .boilerplate.json natively)
const boilerplateConfig = readBoilerplateConfig(resolvedTemplatePath);

await templatizer.process(templateDir, outputDir, {
argv: answers,
noTty,
fromPath,
prompter,
} as any);

return {
Expand Down
2 changes: 0 additions & 2 deletions pgpm/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ export * from './resolution/resolve';
export * from './workspace/paths';
export * from './workspace/utils';
export * from './core/template-scaffold';
export * from './core/boilerplate-types';
export * from './core/boilerplate-scanner';

// Export package-files functionality (now integrated into core)
export * from './files';
Expand Down
Loading