From f5109d769dc34eb81c5c77d316184f5f2ae9d135 Mon Sep 17 00:00:00 2001 From: Eason Date: Tue, 16 Dec 2025 09:33:05 +0800 Subject: [PATCH 01/10] Title: Add workspace resolvers for boilerplate defaults add workspace.name, workspace.organization.name, and workspace.license resolvers using repo URL/pkg license fallback ensure workspace name prefers repo slug with package name fallback expand resolver and setFrom tests to cover new workspace keys document workspace resolver list in README --- packages/inquirerer/README.md | 15 +++++++++- .../inquirerer/__tests__/resolvers.test.ts | 22 +++++++++++++++ packages/inquirerer/__tests__/setFrom.test.ts | 28 +++++++++++++++++++ .../inquirerer/src/resolvers/workspace.ts | 26 +++++++++++++++++ 4 files changed, 90 insertions(+), 1 deletion(-) diff --git a/packages/inquirerer/README.md b/packages/inquirerer/README.md index 6538ade..87c6159 100644 --- a/packages/inquirerer/README.md +++ b/packages/inquirerer/README.md @@ -747,6 +747,19 @@ Inquirerer comes with several built-in resolvers ready to use: | `date.now` | ISO timestamp | `"2025-11-23T15:30:45.123Z"` | | `date.timestamp` | Unix timestamp (ms) | `"1732375845123"` | +#### Workspace (nearest package.json) + +| Resolver | Description | Example Output | +|----------|-------------|----------------| +| `workspace.name` | Repo slug from `repository` URL (fallback: `package.json` `name`) | `"dev-utils"` | +| `workspace.repo.name` | Repo name from `repository` URL | `"dev-utils"` | +| `workspace.repo.organization` | Repo org/owner from `repository` URL | `"constructive-io"` | +| `workspace.organization.name` | Alias for `workspace.repo.organization` | `"constructive-io"` | +| `workspace.license` | License field from `package.json` | `"MIT"` | +| `workspace.author` | Author name from `package.json` | `"Constructive"` | +| `workspace.author.name` | Author name from `package.json` | `"Constructive"` | +| `workspace.author.email` | Author email from `package.json` | `"pyramation@constructive.io"` | + ### Priority Order When resolving default values, inquirerer follows this priority: @@ -1047,4 +1060,4 @@ const handler: CommandHandler = async (argv, prompter) => { const cli = new CLI(handler, options); await cli.run(); -``` \ No newline at end of file +``` diff --git a/packages/inquirerer/__tests__/resolvers.test.ts b/packages/inquirerer/__tests__/resolvers.test.ts index 2a13d55..5dbe21a 100644 --- a/packages/inquirerer/__tests__/resolvers.test.ts +++ b/packages/inquirerer/__tests__/resolvers.test.ts @@ -499,13 +499,23 @@ describe('Debug Mode', () => { describe('Workspace Resolvers', () => { it('should have workspace resolvers registered by default', () => { + expect(globalResolverRegistry.has('workspace.name')).toBe(true); expect(globalResolverRegistry.has('workspace.repo.name')).toBe(true); expect(globalResolverRegistry.has('workspace.repo.organization')).toBe(true); + expect(globalResolverRegistry.has('workspace.organization.name')).toBe(true); + expect(globalResolverRegistry.has('workspace.license')).toBe(true); expect(globalResolverRegistry.has('workspace.author')).toBe(true); expect(globalResolverRegistry.has('workspace.author.name')).toBe(true); expect(globalResolverRegistry.has('workspace.author.email')).toBe(true); }); + it('should resolve workspace.name preferring repo name', async () => { + const result = await globalResolverRegistry.resolve('workspace.name'); + + // Repository slug of dev-utils package + expect(result).toBe('dev-utils'); + }); + it('should resolve workspace.repo.name from package.json', async () => { // This test runs from the dev-utils directory which has a package.json with repository const result = await globalResolverRegistry.resolve('workspace.repo.name'); @@ -520,6 +530,18 @@ describe('Workspace Resolvers', () => { expect(result).toBe('constructive-io'); }); + it('should resolve workspace.organization.name from package.json', async () => { + const result = await globalResolverRegistry.resolve('workspace.organization.name'); + + expect(result).toBe('constructive-io'); + }); + + it('should resolve workspace.license from package.json', async () => { + const result = await globalResolverRegistry.resolve('workspace.license'); + + expect(result).toBe('MIT'); + }); + it('should resolve workspace.author from package.json', async () => { const result = await globalResolverRegistry.resolve('workspace.author'); diff --git a/packages/inquirerer/__tests__/setFrom.test.ts b/packages/inquirerer/__tests__/setFrom.test.ts index df5d58b..bbbcace 100644 --- a/packages/inquirerer/__tests__/setFrom.test.ts +++ b/packages/inquirerer/__tests__/setFrom.test.ts @@ -149,6 +149,34 @@ describe('Inquirerer - setFrom feature', () => { expect(result).toEqual({ year: '1967' }); }); + + it('should use workspace resolvers with setFrom', async () => { + const prompter = new Inquirerer({ + input: mockInput, + output: mockOutput, + noTty: true + }); + + const questions: Question[] = [ + { + name: 'repoName', + type: 'text', + setFrom: 'workspace.name' + }, + { + name: 'license', + type: 'text', + setFrom: 'workspace.license' + } + ]; + + const result = await prompter.prompt({}, questions); + + expect(result).toEqual({ + repoName: 'dev-utils', + license: 'MIT' + }); + }); }); describe('setFrom vs defaultFrom behavior', () => { diff --git a/packages/inquirerer/src/resolvers/workspace.ts b/packages/inquirerer/src/resolvers/workspace.ts index e45346e..b8096a7 100644 --- a/packages/inquirerer/src/resolvers/workspace.ts +++ b/packages/inquirerer/src/resolvers/workspace.ts @@ -88,6 +88,18 @@ function parseAuthor(author: string | { name?: string; email?: string; url?: str * These resolve values from the nearest package.json in the current working directory. */ export const workspaceResolvers: ResolverRegistry = { + 'workspace.name': () => { + const pkg = findPackageJsonFromCwd(); + if (!pkg) return undefined; + const url = getRepositoryUrl(pkg); + // Prefer repo slug when repository is set; fall back to package name + if (url) { + const parsed = parseGitHubUrl(url); + if (parsed.name) return parsed.name; + } + return pkg.name; + }, + 'workspace.repo.name': () => { const pkg = findPackageJsonFromCwd(); if (!pkg) return undefined; @@ -104,6 +116,20 @@ export const workspaceResolvers: ResolverRegistry = { return parseGitHubUrl(url).organization; }, + // Alias for repo.organization for template readability + 'workspace.organization.name': () => { + const pkg = findPackageJsonFromCwd(); + if (!pkg) return undefined; + const url = getRepositoryUrl(pkg); + if (!url) return undefined; + return parseGitHubUrl(url).organization; + }, + + 'workspace.license': () => { + const pkg = findPackageJsonFromCwd(); + return pkg?.license; + }, + 'workspace.author': () => { const pkg = findPackageJsonFromCwd(); if (!pkg) return undefined; From a163592139c4b0514b3ed18636ae6e6724f606f6 Mon Sep 17 00:00:00 2001 From: Eason Date: Tue, 16 Dec 2025 10:20:11 +0800 Subject: [PATCH 02/10] Update create-gen-app-test for new pgpm-boilerplates repo/layout point tests, CLI defaults, and dev script to constructive-io/pgpm-boilerplates on main with default/ base path adjust integration helpers to use the new template path and branch; update snapshots for new boilerplate contents refresh docs to reflect the new repo URL and template directory defaults --- packages/create-gen-app-test/README.md | 4 ++-- packages/create-gen-app-test/dev/README.md | 11 +++++------ packages/create-gen-app-test/dev/index.ts | 5 ++--- .../__snapshots__/cached-template.test.ts.snap | 10 ++++++---- .../src/__tests__/cached-template.test.ts | 8 ++++---- .../create-gen-app-test/src/__tests__/cli.test.ts | 3 ++- packages/create-gen-app-test/src/cli.ts | 6 +++--- .../src/test-utils/integration-helpers.ts | 9 +++++++-- 8 files changed, 31 insertions(+), 25 deletions(-) diff --git a/packages/create-gen-app-test/README.md b/packages/create-gen-app-test/README.md index 794a671..291990f 100644 --- a/packages/create-gen-app-test/README.md +++ b/packages/create-gen-app-test/README.md @@ -20,7 +20,7 @@ This package provides functionality to clone and cache template repositories for import { createFromCachedTemplate } from 'create-gen-app-test'; const result = await createFromCachedTemplate({ - templateUrl: 'https://github.com/launchql/pgpm-boilerplates', + templateUrl: 'https://github.com/constructive-io/pgpm-boilerplates', outputDir: './my-new-project', answers: { PROJECT_NAME: 'my-project', @@ -65,7 +65,7 @@ Create project from cached template. The package includes comprehensive integration tests that: -1. Clone real repositories from GitHub (default: https://github.com/launchql/pgpm-boilerplates) +1. Clone real repositories from GitHub (default: https://github.com/constructive-io/pgpm-boilerplates) 2. Cache templates using appstash 3. Process templates with variable replacement 4. Snapshot generated files and package.json files diff --git a/packages/create-gen-app-test/dev/README.md b/packages/create-gen-app-test/dev/README.md index cd4b56d..b77ce49 100644 --- a/packages/create-gen-app-test/dev/README.md +++ b/packages/create-gen-app-test/dev/README.md @@ -25,8 +25,8 @@ pnpm dev --output ./my-generated-template ## What it does -1. **Clones the default repository**: `https://github.com/launchql/pgpm-boilerplates/` (override via `--repo`, select branch via `--branch`) -2. **Lists available templates**: looks for subdirectories inside `--path` (default `.`; typically `module`, `workspace`) +1. **Clones the default repository**: `https://github.com/constructive-io/pgpm-boilerplates/` (override via `--repo`, select branch via `--branch`) +2. **Lists available templates**: looks for subdirectories inside `--path` (default `default`; typically contains `module`, `workspace`) 3. **Prompts for selection**: Uses `inquirerer` to display an interactive list of templates 4. **Processes the template**: - Extracts variables from the selected folder @@ -39,9 +39,9 @@ pnpm dev --output ./my-generated-template Command-line flags override the defaults below (see `dev/index.ts`): -- `--repo` (`-r`): repository URL to clone (default: `https://github.com/launchql/pgpm-boilerplates/`) +- `--repo` (`-r`): repository URL to clone (default: `https://github.com/constructive-io/pgpm-boilerplates/`) - `--branch` (`-b`): branch or tag to checkout -- `--path` (`-p`): directory within the repo to scan for templates (default: `.`) +- `--path` (`-p`): directory within the repo to scan for templates (default: `default`) - `--template` (`-t`): template folder to use (e.g., `module`, `workspace`); if omitted, an interactive list appears - `--output` (`-o`): output directory for generated project (default: `./test-output`) @@ -51,7 +51,7 @@ Command-line flags override the defaults below (see `dev/index.ts`): $ pnpm dev 🚀 create-gen-app development script -Cloning template from https://github.com/launchql/pgpm-boilerplates/... +Cloning template from https://github.com/constructive-io/pgpm-boilerplates/... Found 2 template(s): module, workspace @@ -73,4 +73,3 @@ Extracting template variables... - The temporary clone directory is automatically cleaned up after generation - You can test different templates without affecting your workspace - diff --git a/packages/create-gen-app-test/dev/index.ts b/packages/create-gen-app-test/dev/index.ts index d248d14..d5fd353 100644 --- a/packages/create-gen-app-test/dev/index.ts +++ b/packages/create-gen-app-test/dev/index.ts @@ -5,8 +5,8 @@ import * as path from "path"; import { cloneRepo, extractVariables, promptUser, replaceVariables } from "create-gen-app"; -const DEFAULT_REPO = "https://github.com/launchql/pgpm-boilerplates/"; -const DEFAULT_DIRECTORY = "."; +const DEFAULT_REPO = "https://github.com/constructive-io/pgpm-boilerplates/"; +const DEFAULT_DIRECTORY = "default"; const OUTPUT_DIR = "./test-output"; const argv = minimist(process.argv.slice(2), { @@ -116,4 +116,3 @@ async function main() { main(); - diff --git a/packages/create-gen-app-test/src/__tests__/__snapshots__/cached-template.test.ts.snap b/packages/create-gen-app-test/src/__tests__/__snapshots__/cached-template.test.ts.snap index 03abe40..3fbeabc 100644 --- a/packages/create-gen-app-test/src/__tests__/__snapshots__/cached-template.test.ts.snap +++ b/packages/create-gen-app-test/src/__tests__/__snapshots__/cached-template.test.ts.snap @@ -2,6 +2,7 @@ exports[`cached template integration tests first clone with variable replacement should snapshot created directory structure 1`] = ` [ + ".boilerplate.json", "LICENSE", "README.md", "__tests__/", @@ -21,7 +22,7 @@ exports[`cached template integration tests first clone with variable replacement "description": "Integration test module test", "devDependencies": { "makage": "0.1.8", - "pgsql-test": "^2.14.12", + "pgsql-test": "^2.16.2", }, "homepage": "https://github.com/tester-test/integration-test", "keywords": [], @@ -38,7 +39,7 @@ exports[`cached template integration tests first clone with variable replacement "scripts": { "lint": "eslint . --fix", "test": "jest", - "test:watch": "makage test --watch deploy --ext sql", + "test:watch": "jest --watch", }, "version": "0.0.1", }, @@ -47,6 +48,7 @@ exports[`cached template integration tests first clone with variable replacement exports[`cached template integration tests second clone from cache should snapshot created directory structure from cache 1`] = ` [ + ".boilerplate.json", "LICENSE", "README.md", "__tests__/", @@ -66,7 +68,7 @@ exports[`cached template integration tests second clone from cache should snapsh "description": "Integration test module cached", "devDependencies": { "makage": "0.1.8", - "pgsql-test": "^2.14.12", + "pgsql-test": "^2.16.2", }, "homepage": "https://github.com/tester-cached/integration-cached", "keywords": [], @@ -83,7 +85,7 @@ exports[`cached template integration tests second clone from cache should snapsh "scripts": { "lint": "eslint . --fix", "test": "jest", - "test:watch": "makage test --watch deploy --ext sql", + "test:watch": "jest --watch", }, "version": "0.0.1", }, diff --git a/packages/create-gen-app-test/src/__tests__/cached-template.test.ts b/packages/create-gen-app-test/src/__tests__/cached-template.test.ts index 709709c..b60c9c0 100644 --- a/packages/create-gen-app-test/src/__tests__/cached-template.test.ts +++ b/packages/create-gen-app-test/src/__tests__/cached-template.test.ts @@ -5,7 +5,7 @@ import * as path from 'path'; import { appstash, resolve } from 'appstash'; import { createFromTemplate, CacheManager, GitCloner } from '../index'; -import { buildAnswers, TEST_REPO, TEST_TEMPLATE } from '../test-utils/integration-helpers'; +import { buildAnswers, TEST_REPO, TEST_TEMPLATE_PATH } from '../test-utils/integration-helpers'; const DEFAULT_TEMPLATE_URL = TEST_REPO; @@ -98,7 +98,7 @@ describe('cached template integration tests', () => { answers: buildAnswers('test'), toolName: testCacheTool, noTty: true, - fromPath: TEST_TEMPLATE + fromPath: TEST_TEMPLATE_PATH }); }, 60000); @@ -166,7 +166,7 @@ describe('cached template integration tests', () => { answers: buildAnswers('warmup'), toolName: testCacheTool, noTty: true, - fromPath: TEST_TEMPLATE + fromPath: TEST_TEMPLATE_PATH }); secondOutputDir = fs.mkdtempSync(path.join(os.tmpdir(), 'second-clone-')); @@ -177,7 +177,7 @@ describe('cached template integration tests', () => { answers: buildAnswers('cached'), toolName: testCacheTool, noTty: true, - fromPath: TEST_TEMPLATE + fromPath: TEST_TEMPLATE_PATH }); }, 60000); diff --git a/packages/create-gen-app-test/src/__tests__/cli.test.ts b/packages/create-gen-app-test/src/__tests__/cli.test.ts index 44ef1cf..b6db4d9 100644 --- a/packages/create-gen-app-test/src/__tests__/cli.test.ts +++ b/packages/create-gen-app-test/src/__tests__/cli.test.ts @@ -5,6 +5,7 @@ import { runCli } from "../cli"; import { TEST_BRANCH, TEST_REPO, + TEST_TEMPLATE_DIR, TEST_TEMPLATE, buildAnswers, cleanupWorkspace, @@ -24,7 +25,7 @@ describe("CLI integration via create-gen-app-test harness", () => { "--branch", TEST_BRANCH, "--path", - ".", + TEST_TEMPLATE_DIR, "--template", TEST_TEMPLATE, "--output", diff --git a/packages/create-gen-app-test/src/cli.ts b/packages/create-gen-app-test/src/cli.ts index 131279d..6af1216 100644 --- a/packages/create-gen-app-test/src/cli.ts +++ b/packages/create-gen-app-test/src/cli.ts @@ -9,8 +9,8 @@ import minimist, { ParsedArgs } from "minimist"; import { CacheManager, GitCloner, checkNpmVersion } from "create-gen-app"; import { createFromTemplate } from './index'; -const DEFAULT_REPO = "https://github.com/launchql/pgpm-boilerplates.git"; -const DEFAULT_PATH = "."; +const DEFAULT_REPO = "https://github.com/constructive-io/pgpm-boilerplates.git"; +const DEFAULT_PATH = "default"; const DEFAULT_OUTPUT_FALLBACK = "create-gen-app-output"; const DEFAULT_TOOL_NAME = "create-gen-app-test"; const DEFAULT_TTL = 604800000; // 1 week @@ -18,7 +18,7 @@ const DEFAULT_TTL_DAYS = DEFAULT_TTL / (24 * 60 * 60 * 1000); // Import package.json for version import * as createGenPackageJson from "create-gen-app/package.json"; -const PACKAGE_NAME = createGenPackageJson.name ?? "@launchql/cli"; +const PACKAGE_NAME = createGenPackageJson.name ?? "@constructive/cli"; const PACKAGE_VERSION = createGenPackageJson.version ?? "0.0.0"; const RESERVED_ARG_KEYS = new Set([ diff --git a/packages/create-gen-app-test/src/test-utils/integration-helpers.ts b/packages/create-gen-app-test/src/test-utils/integration-helpers.ts index bf0adcd..bce8dba 100644 --- a/packages/create-gen-app-test/src/test-utils/integration-helpers.ts +++ b/packages/create-gen-app-test/src/test-utils/integration-helpers.ts @@ -4,11 +4,16 @@ import * as path from "path"; export const TEST_REPO = process.env.CREATE_GEN_TEST_REPO ?? - "https://github.com/launchql/pgpm-boilerplates.git"; + "https://github.com/constructive-io/pgpm-boilerplates.git"; export const TEST_BRANCH = - process.env.CREATE_GEN_TEST_BRANCH ?? "license"; + process.env.CREATE_GEN_TEST_BRANCH ?? "main"; +export const TEST_TEMPLATE_DIR = + process.env.CREATE_GEN_TEST_BASE_PATH ?? "default"; export const TEST_TEMPLATE = process.env.CREATE_GEN_TEST_TEMPLATE ?? "module"; +export const TEST_TEMPLATE_PATH = + process.env.CREATE_GEN_TEST_TEMPLATE_PATH ?? + path.join(TEST_TEMPLATE_DIR, TEST_TEMPLATE); export interface TempWorkspace { baseDir: string; From 093284b2dd40f6121c19b3fabd0a963150899be7 Mon Sep 17 00:00:00 2001 From: Eason Date: Tue, 16 Dec 2025 13:12:17 +0800 Subject: [PATCH 03/10] Update PACKAGE_NAME --- packages/create-gen-app-test/src/cli.ts | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/packages/create-gen-app-test/src/cli.ts b/packages/create-gen-app-test/src/cli.ts index 6af1216..2e87259 100644 --- a/packages/create-gen-app-test/src/cli.ts +++ b/packages/create-gen-app-test/src/cli.ts @@ -7,7 +7,7 @@ import { Inquirerer, ListQuestion } from "inquirerer"; import minimist, { ParsedArgs } from "minimist"; import { CacheManager, GitCloner, checkNpmVersion } from "create-gen-app"; -import { createFromTemplate } from './index'; +import { createFromTemplate } from "./index"; const DEFAULT_REPO = "https://github.com/constructive-io/pgpm-boilerplates.git"; const DEFAULT_PATH = "default"; @@ -18,7 +18,7 @@ const DEFAULT_TTL_DAYS = DEFAULT_TTL / (24 * 60 * 60 * 1000); // Import package.json for version import * as createGenPackageJson from "create-gen-app/package.json"; -const PACKAGE_NAME = createGenPackageJson.name ?? "@constructive/cli"; +const PACKAGE_NAME = createGenPackageJson.name ?? "@launchql/cli"; const PACKAGE_VERSION = createGenPackageJson.version ?? "0.0.0"; const RESERVED_ARG_KEYS = new Set([ @@ -134,7 +134,7 @@ export async function runCli( console.warn( `⚠️ Cached template expired (last updated: ${new Date(expiredMetadata.lastUpdated).toLocaleString()})` ); - console.log('Updating cache...'); + console.log("Updating cache..."); cacheManager.clear(cacheKey); } @@ -150,7 +150,7 @@ export async function runCli( gitCloner.clone(normalizedUrl, tempDest, { branch: args.branch, depth: 1 }); cacheManager.set(cacheKey, tempDest); templateDir = tempDest; - console.log('Template cached for future runs'); + console.log("Template cached for future runs"); } try { @@ -209,8 +209,8 @@ export async function runCli( const answerOverrides = extractAnswerOverrides(args); const noTty = Boolean( args["no-tty"] ?? - (args as Record).noTty ?? - (args as Record).tty === false + (args as Record).noTty ?? + (args as Record).tty === false ); // Use the createFromTemplate function which will use the same cache @@ -330,7 +330,9 @@ if (require.main === module) { } function resolveTtlOption(args: ParsedArgs): number | undefined { - const disableTtl = Boolean(args["no-ttl"] ?? (args as Record).noTtl); + const disableTtl = Boolean( + args["no-ttl"] ?? (args as Record).noTtl + ); if (disableTtl) { return undefined; } From 9be6fd0d9206e80ebd9e0ffaf8be19d927f4ff16 Mon Sep 17 00:00:00 2001 From: Eason Date: Tue, 16 Dec 2025 16:49:27 +0800 Subject: [PATCH 04/10] Auto-detect boilerplate base path in create-gen-app test harness Body read .boilerplates.json to pick the default template path (fallback to .) instead of hardcoding default update dev CLI/help text and docs to reflect auto-detected template directory keep repo default pointing at constructive-io/pgpm-boilerplates; tests verified passing after changes --- packages/create-gen-app-test/dev/README.md | 5 ++-- packages/create-gen-app-test/dev/index.ts | 23 ++++++++++++----- packages/create-gen-app-test/src/cli.ts | 30 ++++++++++++++++------ 3 files changed, 41 insertions(+), 17 deletions(-) diff --git a/packages/create-gen-app-test/dev/README.md b/packages/create-gen-app-test/dev/README.md index b77ce49..29e7110 100644 --- a/packages/create-gen-app-test/dev/README.md +++ b/packages/create-gen-app-test/dev/README.md @@ -26,7 +26,7 @@ pnpm dev --output ./my-generated-template ## What it does 1. **Clones the default repository**: `https://github.com/constructive-io/pgpm-boilerplates/` (override via `--repo`, select branch via `--branch`) -2. **Lists available templates**: looks for subdirectories inside `--path` (default `default`; typically contains `module`, `workspace`) +2. **Lists available templates**: looks for subdirectories inside `--path` (auto: uses `.boilerplates.json` `dir` when present, otherwise `.`; typically contains `module`, `workspace`) 3. **Prompts for selection**: Uses `inquirerer` to display an interactive list of templates 4. **Processes the template**: - Extracts variables from the selected folder @@ -41,7 +41,7 @@ Command-line flags override the defaults below (see `dev/index.ts`): - `--repo` (`-r`): repository URL to clone (default: `https://github.com/constructive-io/pgpm-boilerplates/`) - `--branch` (`-b`): branch or tag to checkout -- `--path` (`-p`): directory within the repo to scan for templates (default: `default`) +- `--path` (`-p`): directory within the repo to scan for templates (default: auto-detected from `.boilerplates.json`, else `.`) - `--template` (`-t`): template folder to use (e.g., `module`, `workspace`); if omitted, an interactive list appears - `--output` (`-o`): output directory for generated project (default: `./test-output`) @@ -72,4 +72,3 @@ Extracting template variables... - The `test-output` directory is gitignored - The temporary clone directory is automatically cleaned up after generation - You can test different templates without affecting your workspace - diff --git a/packages/create-gen-app-test/dev/index.ts b/packages/create-gen-app-test/dev/index.ts index d5fd353..dd04505 100644 --- a/packages/create-gen-app-test/dev/index.ts +++ b/packages/create-gen-app-test/dev/index.ts @@ -6,7 +6,6 @@ import * as path from "path"; import { cloneRepo, extractVariables, promptUser, replaceVariables } from "create-gen-app"; const DEFAULT_REPO = "https://github.com/constructive-io/pgpm-boilerplates/"; -const DEFAULT_DIRECTORY = "default"; const OUTPUT_DIR = "./test-output"; const argv = minimist(process.argv.slice(2), { @@ -20,7 +19,6 @@ const argv = minimist(process.argv.slice(2), { string: ["repo", "branch", "path", "template", "output"], default: { repo: DEFAULT_REPO, - path: DEFAULT_DIRECTORY, output: OUTPUT_DIR, }, }); @@ -35,9 +33,23 @@ async function main() { } const tempDir = await cloneRepo(argv.repo, { branch: argv.branch }); - const templateDir = path.join(tempDir, argv.path); + const configPath = path.join(tempDir, ".boilerplates.json"); + const autoDir = + argv.path === undefined && fs.existsSync(configPath) + ? (() => { + try { + const parsed = JSON.parse(fs.readFileSync(configPath, "utf8")); + return typeof parsed?.dir === "string" ? parsed.dir : undefined; + } catch { + return undefined; + } + })() + : undefined; + const effectivePath = argv.path ?? autoDir ?? "."; + + const templateDir = path.join(tempDir, effectivePath); if (!fs.existsSync(templateDir)) { - throw new Error(`Template path "${argv.path}" does not exist in ${argv.repo}`); + throw new Error(`Template path "${effectivePath}" does not exist in ${argv.repo}`); } const folders = fs .readdirSync(templateDir, { withFileTypes: true }) @@ -54,7 +66,7 @@ async function main() { if (selectedFolder) { if (!folders.includes(selectedFolder)) { throw new Error( - `Template "${selectedFolder}" not found in ${argv.repo}${argv.path === "." ? "" : `/${argv.path}`}` + `Template "${selectedFolder}" not found in ${argv.repo}${effectivePath === "." ? "" : `/${effectivePath}`}` ); } } else { @@ -115,4 +127,3 @@ async function main() { } main(); - diff --git a/packages/create-gen-app-test/src/cli.ts b/packages/create-gen-app-test/src/cli.ts index 2e87259..7bdd665 100644 --- a/packages/create-gen-app-test/src/cli.ts +++ b/packages/create-gen-app-test/src/cli.ts @@ -10,7 +10,6 @@ import { CacheManager, GitCloner, checkNpmVersion } from "create-gen-app"; import { createFromTemplate } from "./index"; const DEFAULT_REPO = "https://github.com/constructive-io/pgpm-boilerplates.git"; -const DEFAULT_PATH = "default"; const DEFAULT_OUTPUT_FALLBACK = "create-gen-app-output"; const DEFAULT_TOOL_NAME = "create-gen-app-test"; const DEFAULT_TTL = 604800000; // 1 week @@ -73,7 +72,6 @@ export async function runCli( boolean: ["force", "help", "version", "no-tty", "clear-cache", "no-ttl"], default: { repo: DEFAULT_REPO, - path: DEFAULT_PATH, }, }); @@ -154,13 +152,29 @@ export async function runCli( } try { - const selectionRoot = path.join(templateDir, args.path); + const userProvidedPath = typeof args.path === "string"; + const configPath = path.join(templateDir, ".boilerplates.json"); + const autoDir = + !userProvidedPath && fs.existsSync(configPath) + ? (() => { + try { + const parsed = JSON.parse(fs.readFileSync(configPath, "utf8")); + return typeof parsed?.dir === "string" ? parsed.dir : undefined; + } catch { + return undefined; + } + })() + : undefined; + const effectivePath = + (userProvidedPath ? args.path : undefined) ?? autoDir ?? "."; + + const selectionRoot = path.join(templateDir, effectivePath); if ( !fs.existsSync(selectionRoot) || !fs.statSync(selectionRoot).isDirectory() ) { throw new Error( - `Template path "${args.path}" does not exist in ${args.repo}` + `Template path "${effectivePath}" does not exist in ${args.repo}` ); } @@ -180,7 +194,7 @@ export async function runCli( if (!templates.includes(selectedTemplate)) { throw new Error( `Template "${selectedTemplate}" not found in ${args.repo}${ - args.path === "." ? "" : `/${args.path}` + effectivePath === "." ? "" : `/${effectivePath}` }` ); } @@ -196,9 +210,9 @@ export async function runCli( } const normalizedBasePath = - args.path === "." || args.path === "./" + effectivePath === "." || effectivePath === "./" ? "" - : args.path.replace(/^[./]+/, "").replace(/\/+$/, ""); + : effectivePath.replace(/^[./]+/, "").replace(/\/+$/, ""); const fromPath = normalizedBasePath ? path.join(normalizedBasePath, selectedTemplate) : selectedTemplate; @@ -242,7 +256,7 @@ Usage: Options: -r, --repo Git repository to clone (default: ${DEFAULT_REPO}) -b, --branch Branch to use when cloning - -p, --path Subdirectory that contains templates (default: .) + -p, --path Subdirectory that contains templates (default: auto from .boilerplates.json, else .) -t, --template Template folder to use (will prompt if omitted) -o, --output Output directory (defaults to ./