create-gen-app 0.7.0 → 0.8.0

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.
@@ -62,6 +62,30 @@ export class TemplateScaffolder {
62
62
  }
63
63
  return this.scaffoldFromRemote(resolvedTemplate, branch, options);
64
64
  }
65
+ /**
66
+ * Inspect a template without scaffolding.
67
+ * Clones/caches the template and reads its .boilerplate.json configuration
68
+ * without copying any files to an output directory.
69
+ *
70
+ * This is useful for metadata-driven workflows where you need to know
71
+ * the template's type or other configuration before deciding how to handle it.
72
+ *
73
+ * @param options - Inspect options
74
+ * @returns Inspect result with template metadata
75
+ */
76
+ inspect(options) {
77
+ const template = options.template ?? this.config.defaultRepo;
78
+ if (!template) {
79
+ throw new Error('No template specified and no defaultRepo configured. ' +
80
+ 'Either pass template in options or set defaultRepo in config.');
81
+ }
82
+ const branch = options.branch ?? this.config.defaultBranch;
83
+ const resolvedTemplate = this.resolveTemplatePath(template);
84
+ if (this.isLocalPath(resolvedTemplate) && fs.existsSync(resolvedTemplate)) {
85
+ return this.inspectLocal(resolvedTemplate, options.fromPath);
86
+ }
87
+ return this.inspectRemote(resolvedTemplate, branch, options.fromPath);
88
+ }
65
89
  /**
66
90
  * Read the .boilerplates.json configuration from a template repository root.
67
91
  */
@@ -112,6 +136,53 @@ export class TemplateScaffolder {
112
136
  getTemplatizer() {
113
137
  return this.templatizer;
114
138
  }
139
+ inspectLocal(templateDir, fromPath) {
140
+ const { fromPath: resolvedFromPath, resolvedTemplatePath } = this.resolveFromPath(templateDir, fromPath);
141
+ const config = this.readBoilerplateConfig(resolvedTemplatePath);
142
+ return {
143
+ templateDir,
144
+ resolvedFromPath,
145
+ resolvedTemplatePath,
146
+ cacheUsed: false,
147
+ cacheExpired: false,
148
+ config,
149
+ };
150
+ }
151
+ inspectRemote(templateUrl, branch, fromPath) {
152
+ const normalizedUrl = this.gitCloner.normalizeUrl(templateUrl);
153
+ const cacheKey = this.cacheManager.createKey(normalizedUrl, branch);
154
+ const expiredMetadata = this.cacheManager.checkExpiration(cacheKey);
155
+ if (expiredMetadata) {
156
+ this.cacheManager.clear(cacheKey);
157
+ }
158
+ let templateDir;
159
+ let cacheUsed = false;
160
+ const cachedPath = this.cacheManager.get(cacheKey);
161
+ if (cachedPath && !expiredMetadata) {
162
+ templateDir = cachedPath;
163
+ cacheUsed = true;
164
+ }
165
+ else {
166
+ const tempDest = path.join(this.cacheManager.getReposDir(), cacheKey);
167
+ this.gitCloner.clone(normalizedUrl, tempDest, {
168
+ branch,
169
+ depth: 1,
170
+ singleBranch: true,
171
+ });
172
+ this.cacheManager.set(cacheKey, tempDest);
173
+ templateDir = tempDest;
174
+ }
175
+ const { fromPath: resolvedFromPath, resolvedTemplatePath } = this.resolveFromPath(templateDir, fromPath);
176
+ const config = this.readBoilerplateConfig(resolvedTemplatePath);
177
+ return {
178
+ templateDir,
179
+ resolvedFromPath,
180
+ resolvedTemplatePath,
181
+ cacheUsed,
182
+ cacheExpired: Boolean(expiredMetadata),
183
+ config,
184
+ };
185
+ }
115
186
  async scaffoldFromLocal(templateDir, options) {
116
187
  const { fromPath, resolvedTemplatePath } = this.resolveFromPath(templateDir, options.fromPath);
117
188
  const boilerplateConfig = this.readBoilerplateConfig(resolvedTemplatePath);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-gen-app",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "author": "Constructive <developers@constructive.io>",
5
5
  "description": "Clone and customize template repositories with variable replacement",
6
6
  "main": "index.js",
@@ -36,5 +36,5 @@
36
36
  "makage": "0.1.8"
37
37
  },
38
38
  "keywords": [],
39
- "gitHead": "a4a39f0cf2bc5a9e36801ea67b4f1ae9c3cf5faa"
39
+ "gitHead": "9ab0a7a8b90ccedd5f9bbde7dcdaef424c7f5acd"
40
40
  }
@@ -1,7 +1,7 @@
1
1
  import { CacheManager } from '../cache/cache-manager';
2
2
  import { GitCloner } from '../git/git-cloner';
3
3
  import { Templatizer } from '../template/templatizer';
4
- import { TemplateScaffolderConfig, ScaffoldOptions, ScaffoldResult, BoilerplatesConfig, BoilerplateConfig } from './types';
4
+ import { TemplateScaffolderConfig, ScaffoldOptions, ScaffoldResult, BoilerplatesConfig, BoilerplateConfig, InspectOptions, InspectResult } from './types';
5
5
  /**
6
6
  * High-level orchestrator for template scaffolding operations.
7
7
  * Combines CacheManager, GitCloner, and Templatizer into a single, easy-to-use API.
@@ -37,6 +37,18 @@ export declare class TemplateScaffolder {
37
37
  * @returns Scaffold result with output path and metadata
38
38
  */
39
39
  scaffold(options: ScaffoldOptions): Promise<ScaffoldResult>;
40
+ /**
41
+ * Inspect a template without scaffolding.
42
+ * Clones/caches the template and reads its .boilerplate.json configuration
43
+ * without copying any files to an output directory.
44
+ *
45
+ * This is useful for metadata-driven workflows where you need to know
46
+ * the template's type or other configuration before deciding how to handle it.
47
+ *
48
+ * @param options - Inspect options
49
+ * @returns Inspect result with template metadata
50
+ */
51
+ inspect(options: InspectOptions): InspectResult;
40
52
  /**
41
53
  * Read the .boilerplates.json configuration from a template repository root.
42
54
  */
@@ -57,6 +69,8 @@ export declare class TemplateScaffolder {
57
69
  * Get the underlying Templatizer instance for advanced template operations.
58
70
  */
59
71
  getTemplatizer(): Templatizer;
72
+ private inspectLocal;
73
+ private inspectRemote;
60
74
  private scaffoldFromLocal;
61
75
  private scaffoldFromRemote;
62
76
  /**
@@ -98,6 +98,30 @@ class TemplateScaffolder {
98
98
  }
99
99
  return this.scaffoldFromRemote(resolvedTemplate, branch, options);
100
100
  }
101
+ /**
102
+ * Inspect a template without scaffolding.
103
+ * Clones/caches the template and reads its .boilerplate.json configuration
104
+ * without copying any files to an output directory.
105
+ *
106
+ * This is useful for metadata-driven workflows where you need to know
107
+ * the template's type or other configuration before deciding how to handle it.
108
+ *
109
+ * @param options - Inspect options
110
+ * @returns Inspect result with template metadata
111
+ */
112
+ inspect(options) {
113
+ const template = options.template ?? this.config.defaultRepo;
114
+ if (!template) {
115
+ throw new Error('No template specified and no defaultRepo configured. ' +
116
+ 'Either pass template in options or set defaultRepo in config.');
117
+ }
118
+ const branch = options.branch ?? this.config.defaultBranch;
119
+ const resolvedTemplate = this.resolveTemplatePath(template);
120
+ if (this.isLocalPath(resolvedTemplate) && fs.existsSync(resolvedTemplate)) {
121
+ return this.inspectLocal(resolvedTemplate, options.fromPath);
122
+ }
123
+ return this.inspectRemote(resolvedTemplate, branch, options.fromPath);
124
+ }
101
125
  /**
102
126
  * Read the .boilerplates.json configuration from a template repository root.
103
127
  */
@@ -148,6 +172,53 @@ class TemplateScaffolder {
148
172
  getTemplatizer() {
149
173
  return this.templatizer;
150
174
  }
175
+ inspectLocal(templateDir, fromPath) {
176
+ const { fromPath: resolvedFromPath, resolvedTemplatePath } = this.resolveFromPath(templateDir, fromPath);
177
+ const config = this.readBoilerplateConfig(resolvedTemplatePath);
178
+ return {
179
+ templateDir,
180
+ resolvedFromPath,
181
+ resolvedTemplatePath,
182
+ cacheUsed: false,
183
+ cacheExpired: false,
184
+ config,
185
+ };
186
+ }
187
+ inspectRemote(templateUrl, branch, fromPath) {
188
+ const normalizedUrl = this.gitCloner.normalizeUrl(templateUrl);
189
+ const cacheKey = this.cacheManager.createKey(normalizedUrl, branch);
190
+ const expiredMetadata = this.cacheManager.checkExpiration(cacheKey);
191
+ if (expiredMetadata) {
192
+ this.cacheManager.clear(cacheKey);
193
+ }
194
+ let templateDir;
195
+ let cacheUsed = false;
196
+ const cachedPath = this.cacheManager.get(cacheKey);
197
+ if (cachedPath && !expiredMetadata) {
198
+ templateDir = cachedPath;
199
+ cacheUsed = true;
200
+ }
201
+ else {
202
+ const tempDest = path.join(this.cacheManager.getReposDir(), cacheKey);
203
+ this.gitCloner.clone(normalizedUrl, tempDest, {
204
+ branch,
205
+ depth: 1,
206
+ singleBranch: true,
207
+ });
208
+ this.cacheManager.set(cacheKey, tempDest);
209
+ templateDir = tempDest;
210
+ }
211
+ const { fromPath: resolvedFromPath, resolvedTemplatePath } = this.resolveFromPath(templateDir, fromPath);
212
+ const config = this.readBoilerplateConfig(resolvedTemplatePath);
213
+ return {
214
+ templateDir,
215
+ resolvedFromPath,
216
+ resolvedTemplatePath,
217
+ cacheUsed,
218
+ cacheExpired: Boolean(expiredMetadata),
219
+ config,
220
+ };
221
+ }
151
222
  async scaffoldFromLocal(templateDir, options) {
152
223
  const { fromPath, resolvedTemplatePath } = this.resolveFromPath(templateDir, options.fromPath);
153
224
  const boilerplateConfig = this.readBoilerplateConfig(resolvedTemplatePath);
@@ -123,3 +123,53 @@ export interface BoilerplateConfig {
123
123
  */
124
124
  questions?: Question[];
125
125
  }
126
+ /**
127
+ * Options for inspecting a template without scaffolding.
128
+ * Used to read template metadata before deciding how to handle it.
129
+ */
130
+ export interface InspectOptions {
131
+ /**
132
+ * Template repository URL, local path, or org/repo shorthand.
133
+ * If not provided, uses the defaultRepo from config.
134
+ */
135
+ template?: string;
136
+ /**
137
+ * Branch to clone (for remote repositories)
138
+ */
139
+ branch?: string;
140
+ /**
141
+ * Subdirectory within the template repository to inspect.
142
+ * Can be a direct path or a variant name that gets resolved via .boilerplates.json
143
+ */
144
+ fromPath?: string;
145
+ }
146
+ /**
147
+ * Result of inspecting a template.
148
+ * Contains metadata about the template without copying any files.
149
+ */
150
+ export interface InspectResult {
151
+ /**
152
+ * Path to the cached/cloned template directory
153
+ */
154
+ templateDir: string;
155
+ /**
156
+ * The resolved fromPath after .boilerplates.json resolution
157
+ */
158
+ resolvedFromPath?: string;
159
+ /**
160
+ * Full path to the resolved template directory
161
+ */
162
+ resolvedTemplatePath: string;
163
+ /**
164
+ * Whether a cached template was used
165
+ */
166
+ cacheUsed: boolean;
167
+ /**
168
+ * Whether the cache was expired and refreshed
169
+ */
170
+ cacheExpired: boolean;
171
+ /**
172
+ * The .boilerplate.json configuration from the template, if present
173
+ */
174
+ config: BoilerplateConfig | null;
175
+ }