genomic 4.0.2 → 5.0.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.
- package/README.md +154 -1125
- package/cache/cache-manager.d.ts +60 -0
- package/cache/cache-manager.js +228 -0
- package/cache/types.d.ts +22 -0
- package/esm/cache/cache-manager.js +191 -0
- package/esm/git/git-cloner.js +92 -0
- package/esm/index.js +41 -4
- package/esm/licenses.js +120 -0
- package/esm/scaffolder/index.js +2 -0
- package/esm/scaffolder/template-scaffolder.js +310 -0
- package/esm/scaffolder/types.js +1 -0
- package/esm/template/extract.js +162 -0
- package/esm/template/prompt.js +103 -0
- package/esm/template/replace.js +110 -0
- package/esm/template/templatizer.js +73 -0
- package/esm/template/types.js +1 -0
- package/esm/types.js +1 -0
- package/esm/utils/npm-version-check.js +52 -0
- package/esm/utils/types.js +1 -0
- package/git/git-cloner.d.ts +32 -0
- package/git/git-cloner.js +129 -0
- package/git/types.d.ts +15 -0
- package/index.d.ts +29 -4
- package/index.js +43 -4
- package/licenses-templates/APACHE-2.0.txt +18 -0
- package/licenses-templates/BSD-3-CLAUSE.txt +28 -0
- package/licenses-templates/CLOSED.txt +20 -0
- package/licenses-templates/GPL-3.0.txt +18 -0
- package/licenses-templates/ISC.txt +16 -0
- package/licenses-templates/MIT.txt +22 -0
- package/licenses-templates/MPL-2.0.txt +8 -0
- package/licenses-templates/UNLICENSE.txt +22 -0
- package/licenses.d.ts +18 -0
- package/licenses.js +162 -0
- package/package.json +9 -14
- package/scaffolder/index.d.ts +2 -0
- package/{question → scaffolder}/index.js +1 -0
- package/scaffolder/template-scaffolder.d.ts +91 -0
- package/scaffolder/template-scaffolder.js +347 -0
- package/scaffolder/types.d.ts +191 -0
- package/scaffolder/types.js +2 -0
- package/template/extract.d.ts +7 -0
- package/template/extract.js +198 -0
- package/template/prompt.d.ts +19 -0
- package/template/prompt.js +107 -0
- package/template/replace.d.ts +9 -0
- package/template/replace.js +146 -0
- package/template/templatizer.d.ts +33 -0
- package/template/templatizer.js +110 -0
- package/template/types.d.ts +18 -0
- package/template/types.js +2 -0
- package/types.d.ts +99 -0
- package/types.js +2 -0
- package/utils/npm-version-check.d.ts +17 -0
- package/utils/npm-version-check.js +57 -0
- package/utils/types.d.ts +6 -0
- package/utils/types.js +2 -0
- package/commander.d.ts +0 -21
- package/commander.js +0 -57
- package/esm/commander.js +0 -50
- package/esm/keypress.js +0 -95
- package/esm/prompt.js +0 -1024
- package/esm/question/index.js +0 -1
- package/esm/resolvers/date.js +0 -11
- package/esm/resolvers/git.js +0 -26
- package/esm/resolvers/index.js +0 -103
- package/esm/resolvers/npm.js +0 -24
- package/esm/resolvers/workspace.js +0 -141
- package/esm/utils.js +0 -12
- package/keypress.d.ts +0 -45
- package/keypress.js +0 -99
- package/prompt.d.ts +0 -116
- package/prompt.js +0 -1032
- package/question/index.d.ts +0 -1
- package/question/types.d.ts +0 -65
- package/resolvers/date.d.ts +0 -5
- package/resolvers/date.js +0 -14
- package/resolvers/git.d.ts +0 -11
- package/resolvers/git.js +0 -30
- package/resolvers/index.d.ts +0 -63
- package/resolvers/index.js +0 -111
- package/resolvers/npm.d.ts +0 -10
- package/resolvers/npm.js +0 -28
- package/resolvers/types.d.ts +0 -12
- package/resolvers/workspace.d.ts +0 -6
- package/resolvers/workspace.js +0 -144
- package/utils.d.ts +0 -2
- package/utils.js +0 -16
- /package/{question → cache}/types.js +0 -0
- /package/esm/{question → cache}/types.js +0 -0
- /package/esm/{resolvers → git}/types.js +0 -0
- /package/{resolvers → git}/types.js +0 -0
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.TemplateScaffolder = void 0;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
const cache_manager_1 = require("../cache/cache-manager");
|
|
40
|
+
const git_cloner_1 = require("../git/git-cloner");
|
|
41
|
+
const templatizer_1 = require("../template/templatizer");
|
|
42
|
+
/**
|
|
43
|
+
* High-level orchestrator for template scaffolding operations.
|
|
44
|
+
* Combines CacheManager, GitCloner, and Templatizer into a single, easy-to-use API.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```typescript
|
|
48
|
+
* const scaffolder = new TemplateScaffolder({
|
|
49
|
+
* toolName: 'my-cli',
|
|
50
|
+
* defaultRepo: 'https://github.com/org/templates.git',
|
|
51
|
+
* ttlMs: 7 * 24 * 60 * 60 * 1000, // 1 week
|
|
52
|
+
* });
|
|
53
|
+
*
|
|
54
|
+
* await scaffolder.scaffold({
|
|
55
|
+
* outputDir: './my-project',
|
|
56
|
+
* fromPath: 'starter',
|
|
57
|
+
* answers: { name: 'my-project' },
|
|
58
|
+
* });
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
class TemplateScaffolder {
|
|
62
|
+
config;
|
|
63
|
+
cacheManager;
|
|
64
|
+
gitCloner;
|
|
65
|
+
templatizer;
|
|
66
|
+
constructor(config) {
|
|
67
|
+
if (!config.toolName) {
|
|
68
|
+
throw new Error('TemplateScaffolder requires toolName in config');
|
|
69
|
+
}
|
|
70
|
+
this.config = config;
|
|
71
|
+
this.cacheManager = new cache_manager_1.CacheManager({
|
|
72
|
+
toolName: config.toolName,
|
|
73
|
+
ttl: config.ttlMs,
|
|
74
|
+
baseDir: config.cacheBaseDir,
|
|
75
|
+
});
|
|
76
|
+
this.gitCloner = new git_cloner_1.GitCloner();
|
|
77
|
+
this.templatizer = new templatizer_1.Templatizer();
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Scaffold a new project from a template.
|
|
81
|
+
*
|
|
82
|
+
* Handles both local directories and remote git repositories.
|
|
83
|
+
* For remote repos, caching is used to avoid repeated cloning.
|
|
84
|
+
*
|
|
85
|
+
* @param options - Scaffold options
|
|
86
|
+
* @returns Scaffold result with output path and metadata
|
|
87
|
+
*/
|
|
88
|
+
async scaffold(options) {
|
|
89
|
+
const template = options.template ?? this.config.defaultRepo;
|
|
90
|
+
if (!template) {
|
|
91
|
+
throw new Error('No template specified and no defaultRepo configured. ' +
|
|
92
|
+
'Either pass template in options or set defaultRepo in config.');
|
|
93
|
+
}
|
|
94
|
+
const branch = options.branch ?? this.config.defaultBranch;
|
|
95
|
+
const resolvedTemplate = this.resolveTemplatePath(template);
|
|
96
|
+
if (this.isLocalPath(resolvedTemplate) && fs.existsSync(resolvedTemplate)) {
|
|
97
|
+
return this.scaffoldFromLocal(resolvedTemplate, options);
|
|
98
|
+
}
|
|
99
|
+
return this.scaffoldFromRemote(resolvedTemplate, branch, options);
|
|
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
|
+
const useBoilerplatesConfig = options.useBoilerplatesConfig ?? true;
|
|
121
|
+
if (this.isLocalPath(resolvedTemplate) && fs.existsSync(resolvedTemplate)) {
|
|
122
|
+
return this.inspectLocal(resolvedTemplate, options.fromPath, useBoilerplatesConfig);
|
|
123
|
+
}
|
|
124
|
+
return this.inspectRemote(resolvedTemplate, branch, options.fromPath, useBoilerplatesConfig);
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Read the .boilerplates.json configuration from a template repository root.
|
|
128
|
+
*/
|
|
129
|
+
readBoilerplatesConfig(templateDir) {
|
|
130
|
+
const configPath = path.join(templateDir, '.boilerplates.json');
|
|
131
|
+
if (fs.existsSync(configPath)) {
|
|
132
|
+
try {
|
|
133
|
+
const content = fs.readFileSync(configPath, 'utf-8');
|
|
134
|
+
return JSON.parse(content);
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Read the .boilerplate.json configuration from a boilerplate directory.
|
|
144
|
+
*/
|
|
145
|
+
readBoilerplateConfig(boilerplatePath) {
|
|
146
|
+
const jsonPath = path.join(boilerplatePath, '.boilerplate.json');
|
|
147
|
+
if (fs.existsSync(jsonPath)) {
|
|
148
|
+
try {
|
|
149
|
+
const content = fs.readFileSync(jsonPath, 'utf-8');
|
|
150
|
+
return JSON.parse(content);
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Get the underlying CacheManager instance for advanced cache operations.
|
|
160
|
+
*/
|
|
161
|
+
getCacheManager() {
|
|
162
|
+
return this.cacheManager;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Get the underlying GitCloner instance for advanced git operations.
|
|
166
|
+
*/
|
|
167
|
+
getGitCloner() {
|
|
168
|
+
return this.gitCloner;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Get the underlying Templatizer instance for advanced template operations.
|
|
172
|
+
*/
|
|
173
|
+
getTemplatizer() {
|
|
174
|
+
return this.templatizer;
|
|
175
|
+
}
|
|
176
|
+
inspectLocal(templateDir, fromPath, useBoilerplatesConfig = true) {
|
|
177
|
+
const { fromPath: resolvedFromPath, resolvedTemplatePath } = this.resolveFromPath(templateDir, fromPath, useBoilerplatesConfig);
|
|
178
|
+
const config = this.readBoilerplateConfig(resolvedTemplatePath);
|
|
179
|
+
return {
|
|
180
|
+
templateDir,
|
|
181
|
+
resolvedFromPath,
|
|
182
|
+
resolvedTemplatePath,
|
|
183
|
+
cacheUsed: false,
|
|
184
|
+
cacheExpired: false,
|
|
185
|
+
config,
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
inspectRemote(templateUrl, branch, fromPath, useBoilerplatesConfig = true) {
|
|
189
|
+
const normalizedUrl = this.gitCloner.normalizeUrl(templateUrl);
|
|
190
|
+
const cacheKey = this.cacheManager.createKey(normalizedUrl, branch);
|
|
191
|
+
const expiredMetadata = this.cacheManager.checkExpiration(cacheKey);
|
|
192
|
+
if (expiredMetadata) {
|
|
193
|
+
this.cacheManager.clear(cacheKey);
|
|
194
|
+
}
|
|
195
|
+
let templateDir;
|
|
196
|
+
let cacheUsed = false;
|
|
197
|
+
const cachedPath = this.cacheManager.get(cacheKey);
|
|
198
|
+
if (cachedPath && !expiredMetadata) {
|
|
199
|
+
templateDir = cachedPath;
|
|
200
|
+
cacheUsed = true;
|
|
201
|
+
}
|
|
202
|
+
else {
|
|
203
|
+
const tempDest = path.join(this.cacheManager.getReposDir(), cacheKey);
|
|
204
|
+
this.gitCloner.clone(normalizedUrl, tempDest, {
|
|
205
|
+
branch,
|
|
206
|
+
depth: 1,
|
|
207
|
+
singleBranch: true,
|
|
208
|
+
});
|
|
209
|
+
this.cacheManager.set(cacheKey, tempDest);
|
|
210
|
+
templateDir = tempDest;
|
|
211
|
+
}
|
|
212
|
+
const { fromPath: resolvedFromPath, resolvedTemplatePath } = this.resolveFromPath(templateDir, fromPath, useBoilerplatesConfig);
|
|
213
|
+
const config = this.readBoilerplateConfig(resolvedTemplatePath);
|
|
214
|
+
return {
|
|
215
|
+
templateDir,
|
|
216
|
+
resolvedFromPath,
|
|
217
|
+
resolvedTemplatePath,
|
|
218
|
+
cacheUsed,
|
|
219
|
+
cacheExpired: Boolean(expiredMetadata),
|
|
220
|
+
config,
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
async scaffoldFromLocal(templateDir, options) {
|
|
224
|
+
const { fromPath, resolvedTemplatePath } = this.resolveFromPath(templateDir, options.fromPath, options.useBoilerplatesConfig ?? true);
|
|
225
|
+
const boilerplateConfig = this.readBoilerplateConfig(resolvedTemplatePath);
|
|
226
|
+
const result = await this.templatizer.process(templateDir, options.outputDir, {
|
|
227
|
+
argv: options.answers,
|
|
228
|
+
noTty: options.noTty,
|
|
229
|
+
fromPath,
|
|
230
|
+
prompter: options.prompter,
|
|
231
|
+
});
|
|
232
|
+
return {
|
|
233
|
+
outputDir: result.outputDir,
|
|
234
|
+
cacheUsed: false,
|
|
235
|
+
cacheExpired: false,
|
|
236
|
+
templateDir,
|
|
237
|
+
fromPath,
|
|
238
|
+
questions: boilerplateConfig?.questions,
|
|
239
|
+
answers: result.answers,
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
async scaffoldFromRemote(templateUrl, branch, options) {
|
|
243
|
+
const normalizedUrl = this.gitCloner.normalizeUrl(templateUrl);
|
|
244
|
+
const cacheKey = this.cacheManager.createKey(normalizedUrl, branch);
|
|
245
|
+
const expiredMetadata = this.cacheManager.checkExpiration(cacheKey);
|
|
246
|
+
if (expiredMetadata) {
|
|
247
|
+
this.cacheManager.clear(cacheKey);
|
|
248
|
+
}
|
|
249
|
+
let templateDir;
|
|
250
|
+
let cacheUsed = false;
|
|
251
|
+
const cachedPath = this.cacheManager.get(cacheKey);
|
|
252
|
+
if (cachedPath && !expiredMetadata) {
|
|
253
|
+
templateDir = cachedPath;
|
|
254
|
+
cacheUsed = true;
|
|
255
|
+
}
|
|
256
|
+
else {
|
|
257
|
+
const tempDest = path.join(this.cacheManager.getReposDir(), cacheKey);
|
|
258
|
+
this.gitCloner.clone(normalizedUrl, tempDest, {
|
|
259
|
+
branch,
|
|
260
|
+
depth: 1,
|
|
261
|
+
singleBranch: true,
|
|
262
|
+
});
|
|
263
|
+
this.cacheManager.set(cacheKey, tempDest);
|
|
264
|
+
templateDir = tempDest;
|
|
265
|
+
}
|
|
266
|
+
const { fromPath, resolvedTemplatePath } = this.resolveFromPath(templateDir, options.fromPath, options.useBoilerplatesConfig ?? true);
|
|
267
|
+
const boilerplateConfig = this.readBoilerplateConfig(resolvedTemplatePath);
|
|
268
|
+
const result = await this.templatizer.process(templateDir, options.outputDir, {
|
|
269
|
+
argv: options.answers,
|
|
270
|
+
noTty: options.noTty,
|
|
271
|
+
fromPath,
|
|
272
|
+
prompter: options.prompter,
|
|
273
|
+
});
|
|
274
|
+
return {
|
|
275
|
+
outputDir: result.outputDir,
|
|
276
|
+
cacheUsed,
|
|
277
|
+
cacheExpired: Boolean(expiredMetadata),
|
|
278
|
+
templateDir,
|
|
279
|
+
fromPath,
|
|
280
|
+
questions: boilerplateConfig?.questions,
|
|
281
|
+
answers: result.answers,
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Resolve the fromPath using .boilerplates.json convention.
|
|
286
|
+
*
|
|
287
|
+
* Resolution order:
|
|
288
|
+
* 1. If explicit fromPath is provided and exists, use it directly
|
|
289
|
+
* 2. If useBoilerplatesConfig is true and .boilerplates.json exists with a dir field, prepend it to fromPath
|
|
290
|
+
* 3. Return the fromPath as-is
|
|
291
|
+
*
|
|
292
|
+
* @param templateDir - The template repository root directory
|
|
293
|
+
* @param fromPath - The subdirectory path to resolve
|
|
294
|
+
* @param useBoilerplatesConfig - Whether to use .boilerplates.json for fallback resolution (default: true)
|
|
295
|
+
*/
|
|
296
|
+
resolveFromPath(templateDir, fromPath, useBoilerplatesConfig = true) {
|
|
297
|
+
if (!fromPath) {
|
|
298
|
+
return {
|
|
299
|
+
fromPath: undefined,
|
|
300
|
+
resolvedTemplatePath: templateDir,
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
const directPath = path.isAbsolute(fromPath)
|
|
304
|
+
? fromPath
|
|
305
|
+
: path.join(templateDir, fromPath);
|
|
306
|
+
if (fs.existsSync(directPath) && fs.statSync(directPath).isDirectory()) {
|
|
307
|
+
return {
|
|
308
|
+
fromPath: path.isAbsolute(fromPath) ? path.relative(templateDir, fromPath) : fromPath,
|
|
309
|
+
resolvedTemplatePath: directPath,
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
// Only check .boilerplates.json if useBoilerplatesConfig is true
|
|
313
|
+
if (useBoilerplatesConfig) {
|
|
314
|
+
const rootConfig = this.readBoilerplatesConfig(templateDir);
|
|
315
|
+
if (rootConfig?.dir) {
|
|
316
|
+
const configBasedPath = path.join(templateDir, rootConfig.dir, fromPath);
|
|
317
|
+
if (fs.existsSync(configBasedPath) && fs.statSync(configBasedPath).isDirectory()) {
|
|
318
|
+
return {
|
|
319
|
+
fromPath: path.join(rootConfig.dir, fromPath),
|
|
320
|
+
resolvedTemplatePath: configBasedPath,
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
return {
|
|
326
|
+
fromPath,
|
|
327
|
+
resolvedTemplatePath: path.join(templateDir, fromPath),
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
isLocalPath(value) {
|
|
331
|
+
return (value.startsWith('.') ||
|
|
332
|
+
value.startsWith('/') ||
|
|
333
|
+
value.startsWith('~') ||
|
|
334
|
+
(process.platform === 'win32' && /^[a-zA-Z]:/.test(value)));
|
|
335
|
+
}
|
|
336
|
+
resolveTemplatePath(template) {
|
|
337
|
+
if (this.isLocalPath(template)) {
|
|
338
|
+
if (template.startsWith('~')) {
|
|
339
|
+
const home = process.env.HOME || process.env.USERPROFILE || '';
|
|
340
|
+
return path.join(home, template.slice(1));
|
|
341
|
+
}
|
|
342
|
+
return path.resolve(template);
|
|
343
|
+
}
|
|
344
|
+
return template;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
exports.TemplateScaffolder = TemplateScaffolder;
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { Inquirerer } from 'inquirerer';
|
|
2
|
+
import { Question } from 'inquirerer';
|
|
3
|
+
/**
|
|
4
|
+
* Configuration for TemplateScaffolder instance
|
|
5
|
+
*/
|
|
6
|
+
export interface TemplateScaffolderConfig {
|
|
7
|
+
/**
|
|
8
|
+
* Tool name used for cache directory naming (e.g., 'my-cli' -> ~/.my-cli/cache)
|
|
9
|
+
*/
|
|
10
|
+
toolName: string;
|
|
11
|
+
/**
|
|
12
|
+
* Default template repository URL or path.
|
|
13
|
+
* Used when scaffold() is called without specifying a template.
|
|
14
|
+
*/
|
|
15
|
+
defaultRepo?: string;
|
|
16
|
+
/**
|
|
17
|
+
* Default branch to use when cloning repositories
|
|
18
|
+
*/
|
|
19
|
+
defaultBranch?: string;
|
|
20
|
+
/**
|
|
21
|
+
* Cache time-to-live in milliseconds.
|
|
22
|
+
* Cached templates older than this will be re-cloned.
|
|
23
|
+
* Default: no expiration
|
|
24
|
+
*/
|
|
25
|
+
ttlMs?: number;
|
|
26
|
+
/**
|
|
27
|
+
* Base directory for cache storage.
|
|
28
|
+
* Useful for tests to avoid touching the real home directory.
|
|
29
|
+
*/
|
|
30
|
+
cacheBaseDir?: string;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Options for a single scaffold operation
|
|
34
|
+
*/
|
|
35
|
+
export interface ScaffoldOptions {
|
|
36
|
+
/**
|
|
37
|
+
* Template repository URL, local path, or org/repo shorthand.
|
|
38
|
+
* If not provided, uses the defaultRepo from config.
|
|
39
|
+
*/
|
|
40
|
+
template?: string;
|
|
41
|
+
/**
|
|
42
|
+
* Branch to clone (for remote repositories)
|
|
43
|
+
*/
|
|
44
|
+
branch?: string;
|
|
45
|
+
/**
|
|
46
|
+
* Subdirectory within the template repository to use as the template root.
|
|
47
|
+
* Can be a direct path or a variant name that gets resolved via .boilerplates.json
|
|
48
|
+
*/
|
|
49
|
+
fromPath?: string;
|
|
50
|
+
/**
|
|
51
|
+
* Whether to use .boilerplates.json for path resolution fallback.
|
|
52
|
+
* When true (default), if fromPath doesn't exist directly, the resolver
|
|
53
|
+
* will check .boilerplates.json for a base directory to prepend.
|
|
54
|
+
* When false, .boilerplates.json is ignored and fromPath is used as-is.
|
|
55
|
+
* @default true
|
|
56
|
+
*/
|
|
57
|
+
useBoilerplatesConfig?: boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Output directory for the generated project
|
|
60
|
+
*/
|
|
61
|
+
outputDir: string;
|
|
62
|
+
/**
|
|
63
|
+
* Pre-populated answers to skip prompting for known values
|
|
64
|
+
*/
|
|
65
|
+
answers?: Record<string, any>;
|
|
66
|
+
/**
|
|
67
|
+
* Disable TTY mode for non-interactive environments
|
|
68
|
+
*/
|
|
69
|
+
noTty?: boolean;
|
|
70
|
+
/**
|
|
71
|
+
* Optional Prompter instance to reuse for prompting.
|
|
72
|
+
* If provided, the caller retains ownership and is responsible for closing it.
|
|
73
|
+
* If not provided, a new instance will be created and closed automatically.
|
|
74
|
+
*/
|
|
75
|
+
prompter?: Inquirerer;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Result of a scaffold operation
|
|
79
|
+
*/
|
|
80
|
+
export interface ScaffoldResult {
|
|
81
|
+
/**
|
|
82
|
+
* Path to the generated output directory
|
|
83
|
+
*/
|
|
84
|
+
outputDir: string;
|
|
85
|
+
/**
|
|
86
|
+
* Whether a cached template was used
|
|
87
|
+
*/
|
|
88
|
+
cacheUsed: boolean;
|
|
89
|
+
/**
|
|
90
|
+
* Whether the cache was expired and refreshed
|
|
91
|
+
*/
|
|
92
|
+
cacheExpired: boolean;
|
|
93
|
+
/**
|
|
94
|
+
* Path to the cached/cloned template directory
|
|
95
|
+
*/
|
|
96
|
+
templateDir: string;
|
|
97
|
+
/**
|
|
98
|
+
* The resolved fromPath used for template processing
|
|
99
|
+
*/
|
|
100
|
+
fromPath?: string;
|
|
101
|
+
/**
|
|
102
|
+
* Questions loaded from .boilerplate.json, if any
|
|
103
|
+
*/
|
|
104
|
+
questions?: Question[];
|
|
105
|
+
/**
|
|
106
|
+
* Answers collected during prompting
|
|
107
|
+
*/
|
|
108
|
+
answers: Record<string, any>;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Root configuration for a boilerplates repository.
|
|
112
|
+
* Stored in `.boilerplates.json` at the repository root.
|
|
113
|
+
*/
|
|
114
|
+
export interface BoilerplatesConfig {
|
|
115
|
+
/**
|
|
116
|
+
* Default directory containing boilerplate templates (e.g., "templates", "boilerplates")
|
|
117
|
+
*/
|
|
118
|
+
dir?: string;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Configuration for a single boilerplate template.
|
|
122
|
+
* Stored in `.boilerplate.json` within each template directory.
|
|
123
|
+
*/
|
|
124
|
+
export interface BoilerplateConfig {
|
|
125
|
+
/**
|
|
126
|
+
* Optional type identifier for the boilerplate
|
|
127
|
+
*/
|
|
128
|
+
type?: string;
|
|
129
|
+
/**
|
|
130
|
+
* Questions to prompt the user during scaffolding
|
|
131
|
+
*/
|
|
132
|
+
questions?: Question[];
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Options for inspecting a template without scaffolding.
|
|
136
|
+
* Used to read template metadata before deciding how to handle it.
|
|
137
|
+
*/
|
|
138
|
+
export interface InspectOptions {
|
|
139
|
+
/**
|
|
140
|
+
* Template repository URL, local path, or org/repo shorthand.
|
|
141
|
+
* If not provided, uses the defaultRepo from config.
|
|
142
|
+
*/
|
|
143
|
+
template?: string;
|
|
144
|
+
/**
|
|
145
|
+
* Branch to clone (for remote repositories)
|
|
146
|
+
*/
|
|
147
|
+
branch?: string;
|
|
148
|
+
/**
|
|
149
|
+
* Subdirectory within the template repository to inspect.
|
|
150
|
+
* Can be a direct path or a variant name that gets resolved via .boilerplates.json
|
|
151
|
+
*/
|
|
152
|
+
fromPath?: string;
|
|
153
|
+
/**
|
|
154
|
+
* Whether to use .boilerplates.json for path resolution fallback.
|
|
155
|
+
* When true (default), if fromPath doesn't exist directly, the resolver
|
|
156
|
+
* will check .boilerplates.json for a base directory to prepend.
|
|
157
|
+
* When false, .boilerplates.json is ignored and fromPath is used as-is.
|
|
158
|
+
* @default true
|
|
159
|
+
*/
|
|
160
|
+
useBoilerplatesConfig?: boolean;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Result of inspecting a template.
|
|
164
|
+
* Contains metadata about the template without copying any files.
|
|
165
|
+
*/
|
|
166
|
+
export interface InspectResult {
|
|
167
|
+
/**
|
|
168
|
+
* Path to the cached/cloned template directory
|
|
169
|
+
*/
|
|
170
|
+
templateDir: string;
|
|
171
|
+
/**
|
|
172
|
+
* The resolved fromPath after .boilerplates.json resolution
|
|
173
|
+
*/
|
|
174
|
+
resolvedFromPath?: string;
|
|
175
|
+
/**
|
|
176
|
+
* Full path to the resolved template directory
|
|
177
|
+
*/
|
|
178
|
+
resolvedTemplatePath: string;
|
|
179
|
+
/**
|
|
180
|
+
* Whether a cached template was used
|
|
181
|
+
*/
|
|
182
|
+
cacheUsed: boolean;
|
|
183
|
+
/**
|
|
184
|
+
* Whether the cache was expired and refreshed
|
|
185
|
+
*/
|
|
186
|
+
cacheExpired: boolean;
|
|
187
|
+
/**
|
|
188
|
+
* The .boilerplate.json configuration from the template, if present
|
|
189
|
+
*/
|
|
190
|
+
config: BoilerplateConfig | null;
|
|
191
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { ExtractedVariables } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Extract all variables from a template directory
|
|
4
|
+
* @param templateDir - Path to the template directory
|
|
5
|
+
* @returns Extracted variables including file replacers, content replacers, and project questions
|
|
6
|
+
*/
|
|
7
|
+
export declare function extractVariables(templateDir: string): Promise<ExtractedVariables>;
|