Skip to content
Merged
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
51 changes: 33 additions & 18 deletions packages/create-gen-app/src/scaffolder/template-scaffolder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,12 +104,13 @@ export class TemplateScaffolder {

const branch = options.branch ?? this.config.defaultBranch;
const resolvedTemplate = this.resolveTemplatePath(template);
const useBoilerplatesConfig = options.useBoilerplatesConfig ?? true;

if (this.isLocalPath(resolvedTemplate) && fs.existsSync(resolvedTemplate)) {
return this.inspectLocal(resolvedTemplate, options.fromPath);
return this.inspectLocal(resolvedTemplate, options.fromPath, useBoilerplatesConfig);
}

return this.inspectRemote(resolvedTemplate, branch, options.fromPath);
return this.inspectRemote(resolvedTemplate, branch, options.fromPath, useBoilerplatesConfig);
}

/**
Expand Down Expand Up @@ -167,11 +168,13 @@ export class TemplateScaffolder {

private inspectLocal(
templateDir: string,
fromPath?: string
fromPath?: string,
useBoilerplatesConfig: boolean = true
): InspectResult {
const { fromPath: resolvedFromPath, resolvedTemplatePath } = this.resolveFromPath(
templateDir,
fromPath
fromPath,
useBoilerplatesConfig
);

const config = this.readBoilerplateConfig(resolvedTemplatePath);
Expand All @@ -189,7 +192,8 @@ export class TemplateScaffolder {
private inspectRemote(
templateUrl: string,
branch: string | undefined,
fromPath?: string
fromPath?: string,
useBoilerplatesConfig: boolean = true
): InspectResult {
const normalizedUrl = this.gitCloner.normalizeUrl(templateUrl);
const cacheKey = this.cacheManager.createKey(normalizedUrl, branch);
Expand Down Expand Up @@ -219,7 +223,8 @@ export class TemplateScaffolder {

const { fromPath: resolvedFromPath, resolvedTemplatePath } = this.resolveFromPath(
templateDir,
fromPath
fromPath,
useBoilerplatesConfig
);

const config = this.readBoilerplateConfig(resolvedTemplatePath);
Expand All @@ -240,7 +245,8 @@ export class TemplateScaffolder {
): Promise<ScaffoldResult> {
const { fromPath, resolvedTemplatePath } = this.resolveFromPath(
templateDir,
options.fromPath
options.fromPath,
options.useBoilerplatesConfig ?? true
);

const boilerplateConfig = this.readBoilerplateConfig(resolvedTemplatePath);
Expand Down Expand Up @@ -296,7 +302,8 @@ export class TemplateScaffolder {

const { fromPath, resolvedTemplatePath } = this.resolveFromPath(
templateDir,
options.fromPath
options.fromPath,
options.useBoilerplatesConfig ?? true
);

const boilerplateConfig = this.readBoilerplateConfig(resolvedTemplatePath);
Expand Down Expand Up @@ -324,12 +331,17 @@ export class TemplateScaffolder {
*
* Resolution order:
* 1. If explicit fromPath is provided and exists, use it directly
* 2. If .boilerplates.json exists with a dir field, prepend it to fromPath
* 2. If useBoilerplatesConfig is true and .boilerplates.json exists with a dir field, prepend it to fromPath
* 3. Return the fromPath as-is
*
* @param templateDir - The template repository root directory
* @param fromPath - The subdirectory path to resolve
* @param useBoilerplatesConfig - Whether to use .boilerplates.json for fallback resolution (default: true)
*/
private resolveFromPath(
templateDir: string,
fromPath?: string
fromPath?: string,
useBoilerplatesConfig: boolean = true
): { fromPath?: string; resolvedTemplatePath: string } {
if (!fromPath) {
return {
Expand All @@ -349,14 +361,17 @@ export class TemplateScaffolder {
};
}

const rootConfig = this.readBoilerplatesConfig(templateDir);
if (rootConfig?.dir) {
const configBasedPath = path.join(templateDir, rootConfig.dir, fromPath);
if (fs.existsSync(configBasedPath) && fs.statSync(configBasedPath).isDirectory()) {
return {
fromPath: path.join(rootConfig.dir, fromPath),
resolvedTemplatePath: configBasedPath,
};
// Only check .boilerplates.json if useBoilerplatesConfig is true
if (useBoilerplatesConfig) {
const rootConfig = this.readBoilerplatesConfig(templateDir);
if (rootConfig?.dir) {
const configBasedPath = path.join(templateDir, rootConfig.dir, fromPath);
if (fs.existsSync(configBasedPath) && fs.statSync(configBasedPath).isDirectory()) {
return {
fromPath: path.join(rootConfig.dir, fromPath),
resolvedTemplatePath: configBasedPath,
};
}
}
}

Expand Down
18 changes: 18 additions & 0 deletions packages/create-gen-app/src/scaffolder/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,15 @@ export interface ScaffoldOptions {
*/
fromPath?: string;

/**
* Whether to use .boilerplates.json for path resolution fallback.
* When true (default), if fromPath doesn't exist directly, the resolver
* will check .boilerplates.json for a base directory to prepend.
* When false, .boilerplates.json is ignored and fromPath is used as-is.
* @default true
*/
useBoilerplatesConfig?: boolean;

/**
* Output directory for the generated project
*/
Expand Down Expand Up @@ -167,6 +176,15 @@ export interface InspectOptions {
* Can be a direct path or a variant name that gets resolved via .boilerplates.json
*/
fromPath?: string;

/**
* Whether to use .boilerplates.json for path resolution fallback.
* When true (default), if fromPath doesn't exist directly, the resolver
* will check .boilerplates.json for a base directory to prepend.
* When false, .boilerplates.json is ignored and fromPath is used as-is.
* @default true
*/
useBoilerplatesConfig?: boolean;
}

/**
Expand Down