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.
|
|
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": "
|
|
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);
|
package/scaffolder/types.d.ts
CHANGED
|
@@ -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
|
+
}
|