genomic 4.0.1 → 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.
Files changed (92) hide show
  1. package/README.md +153 -1127
  2. package/cache/cache-manager.d.ts +60 -0
  3. package/cache/cache-manager.js +228 -0
  4. package/cache/types.d.ts +22 -0
  5. package/esm/cache/cache-manager.js +191 -0
  6. package/esm/git/git-cloner.js +92 -0
  7. package/esm/index.js +41 -4
  8. package/esm/licenses.js +120 -0
  9. package/esm/scaffolder/index.js +2 -0
  10. package/esm/scaffolder/template-scaffolder.js +310 -0
  11. package/esm/scaffolder/types.js +1 -0
  12. package/esm/template/extract.js +162 -0
  13. package/esm/template/prompt.js +103 -0
  14. package/esm/template/replace.js +110 -0
  15. package/esm/template/templatizer.js +73 -0
  16. package/esm/template/types.js +1 -0
  17. package/esm/types.js +1 -0
  18. package/esm/utils/npm-version-check.js +52 -0
  19. package/esm/utils/types.js +1 -0
  20. package/git/git-cloner.d.ts +32 -0
  21. package/git/git-cloner.js +129 -0
  22. package/git/types.d.ts +15 -0
  23. package/index.d.ts +29 -4
  24. package/index.js +43 -4
  25. package/licenses-templates/APACHE-2.0.txt +18 -0
  26. package/licenses-templates/BSD-3-CLAUSE.txt +28 -0
  27. package/licenses-templates/CLOSED.txt +20 -0
  28. package/licenses-templates/GPL-3.0.txt +18 -0
  29. package/licenses-templates/ISC.txt +16 -0
  30. package/licenses-templates/MIT.txt +22 -0
  31. package/licenses-templates/MPL-2.0.txt +8 -0
  32. package/licenses-templates/UNLICENSE.txt +22 -0
  33. package/licenses.d.ts +18 -0
  34. package/licenses.js +162 -0
  35. package/package.json +9 -14
  36. package/scaffolder/index.d.ts +2 -0
  37. package/{question → scaffolder}/index.js +1 -0
  38. package/scaffolder/template-scaffolder.d.ts +91 -0
  39. package/scaffolder/template-scaffolder.js +347 -0
  40. package/scaffolder/types.d.ts +191 -0
  41. package/scaffolder/types.js +2 -0
  42. package/template/extract.d.ts +7 -0
  43. package/template/extract.js +198 -0
  44. package/template/prompt.d.ts +19 -0
  45. package/template/prompt.js +107 -0
  46. package/template/replace.d.ts +9 -0
  47. package/template/replace.js +146 -0
  48. package/template/templatizer.d.ts +33 -0
  49. package/template/templatizer.js +110 -0
  50. package/template/types.d.ts +18 -0
  51. package/template/types.js +2 -0
  52. package/types.d.ts +99 -0
  53. package/types.js +2 -0
  54. package/utils/npm-version-check.d.ts +17 -0
  55. package/utils/npm-version-check.js +57 -0
  56. package/utils/types.d.ts +6 -0
  57. package/utils/types.js +2 -0
  58. package/commander.d.ts +0 -21
  59. package/commander.js +0 -57
  60. package/esm/commander.js +0 -50
  61. package/esm/keypress.js +0 -95
  62. package/esm/prompt.js +0 -1024
  63. package/esm/question/index.js +0 -1
  64. package/esm/resolvers/date.js +0 -11
  65. package/esm/resolvers/git.js +0 -26
  66. package/esm/resolvers/index.js +0 -103
  67. package/esm/resolvers/npm.js +0 -24
  68. package/esm/resolvers/workspace.js +0 -141
  69. package/esm/utils.js +0 -12
  70. package/keypress.d.ts +0 -45
  71. package/keypress.js +0 -99
  72. package/prompt.d.ts +0 -116
  73. package/prompt.js +0 -1032
  74. package/question/index.d.ts +0 -1
  75. package/question/types.d.ts +0 -65
  76. package/resolvers/date.d.ts +0 -5
  77. package/resolvers/date.js +0 -14
  78. package/resolvers/git.d.ts +0 -11
  79. package/resolvers/git.js +0 -30
  80. package/resolvers/index.d.ts +0 -63
  81. package/resolvers/index.js +0 -111
  82. package/resolvers/npm.d.ts +0 -10
  83. package/resolvers/npm.js +0 -28
  84. package/resolvers/types.d.ts +0 -12
  85. package/resolvers/workspace.d.ts +0 -6
  86. package/resolvers/workspace.js +0 -144
  87. package/utils.d.ts +0 -2
  88. package/utils.js +0 -16
  89. /package/{question → cache}/types.js +0 -0
  90. /package/esm/{question → cache}/types.js +0 -0
  91. /package/esm/{resolvers → git}/types.js +0 -0
  92. /package/{resolvers → git}/types.js +0 -0
@@ -0,0 +1,60 @@
1
+ import { AppStashResult } from 'appstash';
2
+ import { CacheManagerConfig, CacheMetadata, CacheEntryInfo } from './types';
3
+ export declare class CacheManager {
4
+ private config;
5
+ private dirs;
6
+ private reposDir;
7
+ private metadataDir;
8
+ constructor(config: CacheManagerConfig);
9
+ /**
10
+ * Public accessor for the repos cache directory path.
11
+ */
12
+ getReposDir(): string;
13
+ /**
14
+ * Public accessor for the metadata cache directory path.
15
+ */
16
+ getMetadataDir(): string;
17
+ /**
18
+ * Public accessor for resolved appstash directories.
19
+ */
20
+ getAppstashDirs(): AppStashResult;
21
+ /**
22
+ * Get cached directory path if exists and not expired
23
+ * Returns null if not cached or expired
24
+ */
25
+ get(key: string): string | null;
26
+ /**
27
+ * Store directory in cache with metadata
28
+ * Does NOT perform cloning - just registers the directory
29
+ */
30
+ set(key: string, sourcePath: string): string;
31
+ /**
32
+ * Check if cache entry is expired based on TTL
33
+ * Returns null if no metadata or not expired, returns metadata if expired
34
+ */
35
+ checkExpiration(key: string): CacheMetadata | null;
36
+ /**
37
+ * Clear specific cache entry
38
+ */
39
+ clear(key: string): void;
40
+ /**
41
+ * Clear all cache entries
42
+ */
43
+ clearAll(): void;
44
+ /**
45
+ * List all cache entries with expiration status
46
+ */
47
+ listAll(): CacheEntryInfo[];
48
+ /**
49
+ * Get metadata for a cache entry
50
+ */
51
+ getMetadata(key: string): CacheMetadata | null;
52
+ /**
53
+ * Create a cache key from identifier (e.g., git URL + branch)
54
+ */
55
+ createKey(identifier: string, variant?: string): string;
56
+ private ensureDirectories;
57
+ private isExpired;
58
+ private getCachePath;
59
+ private getMetadataPath;
60
+ }
@@ -0,0 +1,228 @@
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.CacheManager = void 0;
37
+ const crypto = __importStar(require("crypto"));
38
+ const fs = __importStar(require("fs"));
39
+ const path = __importStar(require("path"));
40
+ const appstash_1 = require("appstash");
41
+ class CacheManager {
42
+ config;
43
+ dirs;
44
+ reposDir;
45
+ metadataDir;
46
+ constructor(config) {
47
+ // Validate required toolName
48
+ if (!config.toolName) {
49
+ throw new Error('CacheManager requires toolName parameter');
50
+ }
51
+ this.config = {
52
+ toolName: config.toolName,
53
+ baseDir: config.baseDir,
54
+ ttl: config.ttl,
55
+ dirs: config.dirs,
56
+ };
57
+ this.dirs =
58
+ config.dirs ??
59
+ (0, appstash_1.appstash)(this.config.toolName, {
60
+ ensure: true,
61
+ baseDir: this.config.baseDir,
62
+ });
63
+ this.reposDir = (0, appstash_1.resolve)(this.dirs, 'cache', 'repos');
64
+ this.metadataDir = (0, appstash_1.resolve)(this.dirs, 'cache', 'metadata');
65
+ this.ensureDirectories();
66
+ }
67
+ /**
68
+ * Public accessor for the repos cache directory path.
69
+ */
70
+ getReposDir() {
71
+ return this.reposDir;
72
+ }
73
+ /**
74
+ * Public accessor for the metadata cache directory path.
75
+ */
76
+ getMetadataDir() {
77
+ return this.metadataDir;
78
+ }
79
+ /**
80
+ * Public accessor for resolved appstash directories.
81
+ */
82
+ getAppstashDirs() {
83
+ return this.dirs;
84
+ }
85
+ /**
86
+ * Get cached directory path if exists and not expired
87
+ * Returns null if not cached or expired
88
+ */
89
+ get(key) {
90
+ const cachePath = this.getCachePath(key);
91
+ if (!fs.existsSync(cachePath)) {
92
+ return null;
93
+ }
94
+ // Check expiration - if expired, return null
95
+ const expired = this.checkExpiration(key);
96
+ if (expired) {
97
+ return null;
98
+ }
99
+ return cachePath;
100
+ }
101
+ /**
102
+ * Store directory in cache with metadata
103
+ * Does NOT perform cloning - just registers the directory
104
+ */
105
+ set(key, sourcePath) {
106
+ const cachePath = this.getCachePath(key);
107
+ // Write metadata with current timestamp
108
+ const metadata = {
109
+ key,
110
+ identifier: sourcePath,
111
+ lastUpdated: Date.now(),
112
+ };
113
+ fs.writeFileSync(this.getMetadataPath(key), JSON.stringify(metadata, null, 2));
114
+ return cachePath;
115
+ }
116
+ /**
117
+ * Check if cache entry is expired based on TTL
118
+ * Returns null if no metadata or not expired, returns metadata if expired
119
+ */
120
+ checkExpiration(key) {
121
+ const metadata = this.getMetadata(key);
122
+ if (!metadata) {
123
+ return null;
124
+ }
125
+ if (this.isExpired(metadata)) {
126
+ return metadata;
127
+ }
128
+ return null;
129
+ }
130
+ /**
131
+ * Clear specific cache entry
132
+ */
133
+ clear(key) {
134
+ const cachePath = this.getCachePath(key);
135
+ const metadataPath = this.getMetadataPath(key);
136
+ if (fs.existsSync(cachePath)) {
137
+ fs.rmSync(cachePath, { recursive: true, force: true });
138
+ }
139
+ if (fs.existsSync(metadataPath)) {
140
+ fs.rmSync(metadataPath, { force: true });
141
+ }
142
+ }
143
+ /**
144
+ * Clear all cache entries
145
+ */
146
+ clearAll() {
147
+ if (fs.existsSync(this.reposDir)) {
148
+ fs.rmSync(this.reposDir, { recursive: true, force: true });
149
+ fs.mkdirSync(this.reposDir, { recursive: true });
150
+ }
151
+ if (fs.existsSync(this.metadataDir)) {
152
+ fs.rmSync(this.metadataDir, { recursive: true, force: true });
153
+ fs.mkdirSync(this.metadataDir, { recursive: true });
154
+ }
155
+ }
156
+ /**
157
+ * List all cache entries with expiration status
158
+ */
159
+ listAll() {
160
+ if (!fs.existsSync(this.metadataDir)) {
161
+ return [];
162
+ }
163
+ const results = [];
164
+ const files = fs.readdirSync(this.metadataDir);
165
+ for (const file of files) {
166
+ if (!file.endsWith('.json')) {
167
+ continue;
168
+ }
169
+ const metadataPath = path.join(this.metadataDir, file);
170
+ try {
171
+ const metadata = JSON.parse(fs.readFileSync(metadataPath, 'utf-8'));
172
+ results.push({
173
+ ...metadata,
174
+ path: this.getCachePath(metadata.key),
175
+ expired: this.isExpired(metadata),
176
+ });
177
+ }
178
+ catch {
179
+ // Skip corrupted metadata
180
+ }
181
+ }
182
+ return results;
183
+ }
184
+ /**
185
+ * Get metadata for a cache entry
186
+ */
187
+ getMetadata(key) {
188
+ const metadataPath = this.getMetadataPath(key);
189
+ if (!fs.existsSync(metadataPath)) {
190
+ return null;
191
+ }
192
+ try {
193
+ return JSON.parse(fs.readFileSync(metadataPath, 'utf-8'));
194
+ }
195
+ catch {
196
+ return null;
197
+ }
198
+ }
199
+ /**
200
+ * Create a cache key from identifier (e.g., git URL + branch)
201
+ */
202
+ createKey(identifier, variant) {
203
+ const input = variant ? `${identifier}#${variant}` : identifier;
204
+ return crypto.createHash('md5').update(input).digest('hex');
205
+ }
206
+ ensureDirectories() {
207
+ if (!fs.existsSync(this.reposDir)) {
208
+ fs.mkdirSync(this.reposDir, { recursive: true });
209
+ }
210
+ if (!fs.existsSync(this.metadataDir)) {
211
+ fs.mkdirSync(this.metadataDir, { recursive: true });
212
+ }
213
+ }
214
+ isExpired(metadata) {
215
+ if (!this.config.ttl) {
216
+ return false;
217
+ }
218
+ const age = Date.now() - metadata.lastUpdated;
219
+ return age > this.config.ttl;
220
+ }
221
+ getCachePath(key) {
222
+ return path.join(this.reposDir, key);
223
+ }
224
+ getMetadataPath(key) {
225
+ return path.join(this.metadataDir, `${key}.json`);
226
+ }
227
+ }
228
+ exports.CacheManager = CacheManager;
@@ -0,0 +1,22 @@
1
+ import { AppStashResult } from 'appstash';
2
+ export interface CacheManagerConfig {
3
+ toolName: string;
4
+ baseDir?: string;
5
+ ttl?: number;
6
+ /**
7
+ * Optional pre-resolved appstash directories owned by the caller.
8
+ * When provided, CacheManager will use these instead of creating its own.
9
+ */
10
+ dirs?: AppStashResult;
11
+ }
12
+ export interface CacheMetadata {
13
+ key: string;
14
+ identifier: string;
15
+ variant?: string;
16
+ lastUpdated: number;
17
+ source?: string;
18
+ }
19
+ export interface CacheEntryInfo extends CacheMetadata {
20
+ path: string;
21
+ expired: boolean;
22
+ }
@@ -0,0 +1,191 @@
1
+ import * as crypto from 'crypto';
2
+ import * as fs from 'fs';
3
+ import * as path from 'path';
4
+ import { appstash, resolve as resolveAppstash } from 'appstash';
5
+ export class CacheManager {
6
+ config;
7
+ dirs;
8
+ reposDir;
9
+ metadataDir;
10
+ constructor(config) {
11
+ // Validate required toolName
12
+ if (!config.toolName) {
13
+ throw new Error('CacheManager requires toolName parameter');
14
+ }
15
+ this.config = {
16
+ toolName: config.toolName,
17
+ baseDir: config.baseDir,
18
+ ttl: config.ttl,
19
+ dirs: config.dirs,
20
+ };
21
+ this.dirs =
22
+ config.dirs ??
23
+ appstash(this.config.toolName, {
24
+ ensure: true,
25
+ baseDir: this.config.baseDir,
26
+ });
27
+ this.reposDir = resolveAppstash(this.dirs, 'cache', 'repos');
28
+ this.metadataDir = resolveAppstash(this.dirs, 'cache', 'metadata');
29
+ this.ensureDirectories();
30
+ }
31
+ /**
32
+ * Public accessor for the repos cache directory path.
33
+ */
34
+ getReposDir() {
35
+ return this.reposDir;
36
+ }
37
+ /**
38
+ * Public accessor for the metadata cache directory path.
39
+ */
40
+ getMetadataDir() {
41
+ return this.metadataDir;
42
+ }
43
+ /**
44
+ * Public accessor for resolved appstash directories.
45
+ */
46
+ getAppstashDirs() {
47
+ return this.dirs;
48
+ }
49
+ /**
50
+ * Get cached directory path if exists and not expired
51
+ * Returns null if not cached or expired
52
+ */
53
+ get(key) {
54
+ const cachePath = this.getCachePath(key);
55
+ if (!fs.existsSync(cachePath)) {
56
+ return null;
57
+ }
58
+ // Check expiration - if expired, return null
59
+ const expired = this.checkExpiration(key);
60
+ if (expired) {
61
+ return null;
62
+ }
63
+ return cachePath;
64
+ }
65
+ /**
66
+ * Store directory in cache with metadata
67
+ * Does NOT perform cloning - just registers the directory
68
+ */
69
+ set(key, sourcePath) {
70
+ const cachePath = this.getCachePath(key);
71
+ // Write metadata with current timestamp
72
+ const metadata = {
73
+ key,
74
+ identifier: sourcePath,
75
+ lastUpdated: Date.now(),
76
+ };
77
+ fs.writeFileSync(this.getMetadataPath(key), JSON.stringify(metadata, null, 2));
78
+ return cachePath;
79
+ }
80
+ /**
81
+ * Check if cache entry is expired based on TTL
82
+ * Returns null if no metadata or not expired, returns metadata if expired
83
+ */
84
+ checkExpiration(key) {
85
+ const metadata = this.getMetadata(key);
86
+ if (!metadata) {
87
+ return null;
88
+ }
89
+ if (this.isExpired(metadata)) {
90
+ return metadata;
91
+ }
92
+ return null;
93
+ }
94
+ /**
95
+ * Clear specific cache entry
96
+ */
97
+ clear(key) {
98
+ const cachePath = this.getCachePath(key);
99
+ const metadataPath = this.getMetadataPath(key);
100
+ if (fs.existsSync(cachePath)) {
101
+ fs.rmSync(cachePath, { recursive: true, force: true });
102
+ }
103
+ if (fs.existsSync(metadataPath)) {
104
+ fs.rmSync(metadataPath, { force: true });
105
+ }
106
+ }
107
+ /**
108
+ * Clear all cache entries
109
+ */
110
+ clearAll() {
111
+ if (fs.existsSync(this.reposDir)) {
112
+ fs.rmSync(this.reposDir, { recursive: true, force: true });
113
+ fs.mkdirSync(this.reposDir, { recursive: true });
114
+ }
115
+ if (fs.existsSync(this.metadataDir)) {
116
+ fs.rmSync(this.metadataDir, { recursive: true, force: true });
117
+ fs.mkdirSync(this.metadataDir, { recursive: true });
118
+ }
119
+ }
120
+ /**
121
+ * List all cache entries with expiration status
122
+ */
123
+ listAll() {
124
+ if (!fs.existsSync(this.metadataDir)) {
125
+ return [];
126
+ }
127
+ const results = [];
128
+ const files = fs.readdirSync(this.metadataDir);
129
+ for (const file of files) {
130
+ if (!file.endsWith('.json')) {
131
+ continue;
132
+ }
133
+ const metadataPath = path.join(this.metadataDir, file);
134
+ try {
135
+ const metadata = JSON.parse(fs.readFileSync(metadataPath, 'utf-8'));
136
+ results.push({
137
+ ...metadata,
138
+ path: this.getCachePath(metadata.key),
139
+ expired: this.isExpired(metadata),
140
+ });
141
+ }
142
+ catch {
143
+ // Skip corrupted metadata
144
+ }
145
+ }
146
+ return results;
147
+ }
148
+ /**
149
+ * Get metadata for a cache entry
150
+ */
151
+ getMetadata(key) {
152
+ const metadataPath = this.getMetadataPath(key);
153
+ if (!fs.existsSync(metadataPath)) {
154
+ return null;
155
+ }
156
+ try {
157
+ return JSON.parse(fs.readFileSync(metadataPath, 'utf-8'));
158
+ }
159
+ catch {
160
+ return null;
161
+ }
162
+ }
163
+ /**
164
+ * Create a cache key from identifier (e.g., git URL + branch)
165
+ */
166
+ createKey(identifier, variant) {
167
+ const input = variant ? `${identifier}#${variant}` : identifier;
168
+ return crypto.createHash('md5').update(input).digest('hex');
169
+ }
170
+ ensureDirectories() {
171
+ if (!fs.existsSync(this.reposDir)) {
172
+ fs.mkdirSync(this.reposDir, { recursive: true });
173
+ }
174
+ if (!fs.existsSync(this.metadataDir)) {
175
+ fs.mkdirSync(this.metadataDir, { recursive: true });
176
+ }
177
+ }
178
+ isExpired(metadata) {
179
+ if (!this.config.ttl) {
180
+ return false;
181
+ }
182
+ const age = Date.now() - metadata.lastUpdated;
183
+ return age > this.config.ttl;
184
+ }
185
+ getCachePath(key) {
186
+ return path.join(this.reposDir, key);
187
+ }
188
+ getMetadataPath(key) {
189
+ return path.join(this.metadataDir, `${key}.json`);
190
+ }
191
+ }
@@ -0,0 +1,92 @@
1
+ import { execSync } from 'child_process';
2
+ import * as fs from 'fs';
3
+ import * as os from 'os';
4
+ import * as path from 'path';
5
+ export class GitCloner {
6
+ /**
7
+ * Clone a git repository to a destination
8
+ * @param url - Repository URL (will be normalized)
9
+ * @param destination - Target directory path
10
+ * @param options - Clone options (branch, depth)
11
+ * @returns Clone result with normalized URL and destination
12
+ */
13
+ clone(url, destination, options) {
14
+ const normalizedUrl = this.normalizeUrl(url);
15
+ // Clean destination if exists
16
+ if (fs.existsSync(destination)) {
17
+ fs.rmSync(destination, { recursive: true, force: true });
18
+ }
19
+ this.executeClone(normalizedUrl, destination, options);
20
+ this.removeGitDir(destination);
21
+ return {
22
+ destination,
23
+ normalizedUrl,
24
+ branch: options?.branch,
25
+ };
26
+ }
27
+ /**
28
+ * Clone to a temporary directory
29
+ * @param url - Repository URL
30
+ * @param options - Clone options
31
+ * @returns Clone result with temp directory path
32
+ */
33
+ cloneToTemp(url, options) {
34
+ const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'create-gen-'));
35
+ return this.clone(url, tempDir, options);
36
+ }
37
+ /**
38
+ * Normalize a URL to git-cloneable format
39
+ * Handles: org/repo -> https://github.com/org/repo.git
40
+ */
41
+ normalizeUrl(url) {
42
+ // Already a full URL
43
+ if (url.startsWith('git@') ||
44
+ url.startsWith('https://') ||
45
+ url.startsWith('http://')) {
46
+ return url;
47
+ }
48
+ // org/repo shorthand
49
+ if (/^[\w-]+\/[\w-]+$/.test(url)) {
50
+ return `https://github.com/${url}.git`;
51
+ }
52
+ return url;
53
+ }
54
+ /**
55
+ * Validate git URL format
56
+ */
57
+ validateUrl(url) {
58
+ const normalized = this.normalizeUrl(url);
59
+ return (normalized.startsWith('git@') ||
60
+ normalized.startsWith('https://') ||
61
+ normalized.startsWith('http://'));
62
+ }
63
+ /**
64
+ * Remove .git directory from cloned repo
65
+ */
66
+ removeGitDir(directory) {
67
+ const gitDir = path.join(directory, '.git');
68
+ if (fs.existsSync(gitDir)) {
69
+ fs.rmSync(gitDir, { recursive: true, force: true });
70
+ }
71
+ }
72
+ executeClone(url, destination, options) {
73
+ const branch = options?.branch;
74
+ const depth = options?.depth ?? 1;
75
+ const singleBranch = options?.singleBranch ?? true;
76
+ const branchArgs = branch ? ` --branch ${branch}` : '';
77
+ const singleBranchArgs = singleBranch ? ' --single-branch' : '';
78
+ const depthArgs = ` --depth ${depth}`;
79
+ const command = `git clone${branchArgs}${singleBranchArgs}${depthArgs} ${url} ${destination}`;
80
+ try {
81
+ execSync(command, { stdio: 'inherit' });
82
+ }
83
+ catch (error) {
84
+ // Clean up on failure
85
+ if (fs.existsSync(destination)) {
86
+ fs.rmSync(destination, { recursive: true, force: true });
87
+ }
88
+ const errorMessage = error instanceof Error ? error.message : String(error);
89
+ throw new Error(`Failed to clone repository: ${errorMessage}`);
90
+ }
91
+ }
92
+ }
package/esm/index.js CHANGED
@@ -1,4 +1,41 @@
1
- export * from './commander';
2
- export * from './prompt';
3
- export * from './question';
4
- export * from './resolvers';
1
+ import { registerDefaultResolver } from 'inquirerer';
2
+ import { extractVariables } from './template/extract';
3
+ import { promptUser } from './template/prompt';
4
+ import { replaceVariables } from './template/replace';
5
+ import { listSupportedLicenses } from './licenses';
6
+ // Register the 'licenses' resolver for optionsFrom support
7
+ // This allows boilerplate templates to use: "optionsFrom": "licenses"
8
+ registerDefaultResolver('licenses', () => listSupportedLicenses());
9
+ // Export new modular classes
10
+ export * from './cache/cache-manager';
11
+ export * from './cache/types';
12
+ export * from './git/git-cloner';
13
+ export * from './git/types';
14
+ export * from './scaffolder/template-scaffolder';
15
+ export * from './scaffolder/types';
16
+ export * from './template/templatizer';
17
+ export * from './template/types';
18
+ export * from './utils/npm-version-check';
19
+ export * from './utils/types';
20
+ // Export template processing functions
21
+ export * from './template/extract';
22
+ export * from './template/prompt';
23
+ export * from './template/replace';
24
+ // Export shared types
25
+ export * from './types';
26
+ // DEPRECATED: Legacy exports for backward compatibility (will be removed in future)
27
+ // Use CacheManager, GitCloner, and Templatizer classes instead
28
+ export { extractVariables, promptUser, replaceVariables };
29
+ /**
30
+ * @deprecated This function is deprecated and will be removed in the next major version.
31
+ * Use the modular approach with CacheManager, GitCloner, and Templatizer classes instead.
32
+ * See @genomic/scaffolds-test package for an example of the new orchestration pattern.
33
+ *
34
+ * Create a new project from a template repository
35
+ * @param options - Options for creating the project
36
+ * @returns Path to the generated project
37
+ */
38
+ export async function createGen(options) {
39
+ throw new Error('createGen() has been deprecated. Please use CacheManager, GitCloner, and Templatizer classes for modular template processing. ' +
40
+ 'See @genomic/scaffolds-test package for the new orchestration pattern.');
41
+ }