genomic 4.0.2 → 5.0.1
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,110 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import { Transform } from 'stream';
|
|
4
|
+
import { pipeline } from 'stream/promises';
|
|
5
|
+
import { renderLicense, isSupportedLicense, findLicenseAuthor, findLicenseEmail, findLicenseValue, } from '../licenses';
|
|
6
|
+
/**
|
|
7
|
+
* Replace variables in all files in the template directory
|
|
8
|
+
* @param templateDir - Path to the template directory
|
|
9
|
+
* @param outputDir - Path to the output directory
|
|
10
|
+
* @param extractedVariables - Variables extracted from the template
|
|
11
|
+
* @param answers - User answers for variable values
|
|
12
|
+
*/
|
|
13
|
+
export async function replaceVariables(templateDir, outputDir, extractedVariables, answers) {
|
|
14
|
+
if (!fs.existsSync(outputDir)) {
|
|
15
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
16
|
+
}
|
|
17
|
+
await walkAndReplace(templateDir, outputDir, extractedVariables, answers);
|
|
18
|
+
await ensureLicenseFile(outputDir, answers);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Walk through directory and replace variables in files and filenames
|
|
22
|
+
* @param sourceDir - Source directory
|
|
23
|
+
* @param destDir - Destination directory
|
|
24
|
+
* @param extractedVariables - Variables extracted from the template
|
|
25
|
+
* @param answers - User answers for variable values
|
|
26
|
+
* @param sourceRelativePath - Current relative path in source (for recursion)
|
|
27
|
+
* @param destRelativePath - Current relative path in destination (for recursion)
|
|
28
|
+
*/
|
|
29
|
+
async function walkAndReplace(sourceDir, destDir, extractedVariables, answers, sourceRelativePath = '', destRelativePath = '') {
|
|
30
|
+
const currentSource = path.join(sourceDir, sourceRelativePath);
|
|
31
|
+
const entries = fs.readdirSync(currentSource, { withFileTypes: true });
|
|
32
|
+
for (const entry of entries) {
|
|
33
|
+
const sourceEntryPath = path.join(currentSource, entry.name);
|
|
34
|
+
// Skip template configuration files - they should not be copied to output
|
|
35
|
+
if (entry.name === '.boilerplate.json' ||
|
|
36
|
+
entry.name === '.boilerplate.js' ||
|
|
37
|
+
entry.name === '.boilerplates.json') {
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
let newName = entry.name;
|
|
41
|
+
for (const replacer of extractedVariables.fileReplacers) {
|
|
42
|
+
if (answers[replacer.variable] !== undefined) {
|
|
43
|
+
newName = newName.replace(replacer.pattern, String(answers[replacer.variable]));
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
const destEntryPath = path.join(destDir, destRelativePath, newName);
|
|
47
|
+
if (entry.isDirectory()) {
|
|
48
|
+
if (!fs.existsSync(destEntryPath)) {
|
|
49
|
+
fs.mkdirSync(destEntryPath, { recursive: true });
|
|
50
|
+
}
|
|
51
|
+
await walkAndReplace(sourceDir, destDir, extractedVariables, answers, path.join(sourceRelativePath, entry.name), path.join(destRelativePath, newName));
|
|
52
|
+
}
|
|
53
|
+
else if (entry.isFile()) {
|
|
54
|
+
await replaceInFile(sourceEntryPath, destEntryPath, extractedVariables, answers);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
async function ensureLicenseFile(outputDir, answers) {
|
|
59
|
+
const licenseValue = findLicenseValue(answers);
|
|
60
|
+
if (typeof licenseValue !== 'string' || licenseValue.trim() === '') {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
const selectedLicense = licenseValue.trim();
|
|
64
|
+
if (!isSupportedLicense(selectedLicense)) {
|
|
65
|
+
console.warn(`[@genomic/scaffolds] License "${selectedLicense}" is not supported by the built-in templates. Leaving template LICENSE file as-is.`);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
const author = findLicenseAuthor(answers) ?? 'Unknown Author';
|
|
69
|
+
const email = findLicenseEmail(answers) ?? '';
|
|
70
|
+
const content = renderLicense(selectedLicense, {
|
|
71
|
+
author: String(author),
|
|
72
|
+
email: String(email || ''),
|
|
73
|
+
});
|
|
74
|
+
if (!content) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
const licensePath = path.join(outputDir, 'LICENSE');
|
|
78
|
+
fs.mkdirSync(path.dirname(licensePath), { recursive: true });
|
|
79
|
+
fs.writeFileSync(licensePath, content.trimEnd() + '\n', 'utf8');
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Replace variables in a file using streams
|
|
83
|
+
* @param sourcePath - Source file path
|
|
84
|
+
* @param destPath - Destination file path
|
|
85
|
+
* @param extractedVariables - Variables extracted from the template
|
|
86
|
+
* @param answers - User answers for variable values
|
|
87
|
+
*/
|
|
88
|
+
async function replaceInFile(sourcePath, destPath, extractedVariables, answers) {
|
|
89
|
+
const destDir = path.dirname(destPath);
|
|
90
|
+
if (!fs.existsSync(destDir)) {
|
|
91
|
+
fs.mkdirSync(destDir, { recursive: true });
|
|
92
|
+
}
|
|
93
|
+
const replaceTransform = new Transform({
|
|
94
|
+
transform(chunk, _encoding, callback) {
|
|
95
|
+
let content = chunk.toString();
|
|
96
|
+
for (const replacer of extractedVariables.contentReplacers) {
|
|
97
|
+
if (answers[replacer.variable] !== undefined) {
|
|
98
|
+
content = content.replace(replacer.pattern, String(answers[replacer.variable]));
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
callback(null, Buffer.from(content));
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
try {
|
|
105
|
+
await pipeline(fs.createReadStream(sourcePath), replaceTransform, fs.createWriteStream(destPath));
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
fs.copyFileSync(sourcePath, destPath);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import { extractVariables } from './extract';
|
|
4
|
+
import { promptUser } from './prompt';
|
|
5
|
+
import { replaceVariables } from './replace';
|
|
6
|
+
export class Templatizer {
|
|
7
|
+
constructor() {
|
|
8
|
+
// Pure template processor - no configuration needed
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Process a local template directory (extract + prompt + replace)
|
|
12
|
+
* @param templateDir - Local directory path (MUST be local, NOT git URL)
|
|
13
|
+
* @param outputDir - Output directory for generated project
|
|
14
|
+
* @param options - Processing options (argv overrides, noTty, prompter)
|
|
15
|
+
* @returns Processing result
|
|
16
|
+
*/
|
|
17
|
+
async process(templateDir, outputDir, options) {
|
|
18
|
+
this.validateTemplateDir(templateDir);
|
|
19
|
+
// Handle subdirectory within template
|
|
20
|
+
const actualTemplateDir = options?.fromPath
|
|
21
|
+
? path.join(templateDir, options.fromPath)
|
|
22
|
+
: templateDir;
|
|
23
|
+
this.validateTemplateDir(actualTemplateDir);
|
|
24
|
+
// Extract variables
|
|
25
|
+
const variables = await this.extract(actualTemplateDir);
|
|
26
|
+
// Prompt for values (pass through optional prompter)
|
|
27
|
+
const answers = await this.prompt(variables, options?.argv, options?.prompter, options?.noTty);
|
|
28
|
+
// Replace variables
|
|
29
|
+
await this.replace(actualTemplateDir, outputDir, variables, answers);
|
|
30
|
+
return {
|
|
31
|
+
outputDir,
|
|
32
|
+
variables,
|
|
33
|
+
answers,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Extract variables from template directory
|
|
38
|
+
*/
|
|
39
|
+
async extract(templateDir) {
|
|
40
|
+
return extractVariables(templateDir);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Prompt user for variables
|
|
44
|
+
* @param extracted - Extracted variables from template
|
|
45
|
+
* @param argv - Pre-populated answers
|
|
46
|
+
* @param prompter - Optional existing Prompter instance to reuse
|
|
47
|
+
* @param noTty - Whether to disable TTY mode (only used when creating a new prompter)
|
|
48
|
+
*/
|
|
49
|
+
async prompt(extracted, argv, prompter, noTty) {
|
|
50
|
+
return promptUser(extracted, argv ?? {}, prompter, noTty ?? false);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Replace variables in template
|
|
54
|
+
*/
|
|
55
|
+
async replace(templateDir, outputDir, extracted, answers) {
|
|
56
|
+
return replaceVariables(templateDir, outputDir, extracted, answers);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Validate template directory exists and has content
|
|
60
|
+
*/
|
|
61
|
+
validateTemplateDir(templateDir) {
|
|
62
|
+
if (!fs.existsSync(templateDir)) {
|
|
63
|
+
throw new Error(`Template directory does not exist: ${templateDir}`);
|
|
64
|
+
}
|
|
65
|
+
if (!fs.statSync(templateDir).isDirectory()) {
|
|
66
|
+
throw new Error(`Template path is not a directory: ${templateDir}`);
|
|
67
|
+
}
|
|
68
|
+
const entries = fs.readdirSync(templateDir);
|
|
69
|
+
if (entries.length === 0) {
|
|
70
|
+
throw new Error(`Template directory is empty: ${templateDir}`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/esm/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { execSync } from 'child_process';
|
|
2
|
+
/**
|
|
3
|
+
* Check if current package version is outdated compared to npm registry
|
|
4
|
+
* @param packageName - Package name to check
|
|
5
|
+
* @param currentVersion - Current version string
|
|
6
|
+
* @returns Version comparison result
|
|
7
|
+
*/
|
|
8
|
+
export async function checkNpmVersion(packageName, currentVersion) {
|
|
9
|
+
try {
|
|
10
|
+
const latestVersion = execSync(`npm view ${packageName} version`, { encoding: 'utf8', stdio: ['pipe', 'pipe', 'ignore'] }).trim();
|
|
11
|
+
const isOutdated = compareVersions(currentVersion, latestVersion) < 0;
|
|
12
|
+
return {
|
|
13
|
+
currentVersion,
|
|
14
|
+
latestVersion,
|
|
15
|
+
isOutdated,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
catch (error) {
|
|
19
|
+
return {
|
|
20
|
+
currentVersion,
|
|
21
|
+
latestVersion: null,
|
|
22
|
+
isOutdated: false,
|
|
23
|
+
error: error instanceof Error ? error.message : String(error),
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Compare two semver version strings
|
|
29
|
+
* Returns: -1 if v1 < v2, 0 if equal, 1 if v1 > v2
|
|
30
|
+
*/
|
|
31
|
+
export function compareVersions(v1, v2) {
|
|
32
|
+
const parts1 = v1.split('.').map(Number);
|
|
33
|
+
const parts2 = v2.split('.').map(Number);
|
|
34
|
+
for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) {
|
|
35
|
+
const p1 = parts1[i] || 0;
|
|
36
|
+
const p2 = parts2[i] || 0;
|
|
37
|
+
if (p1 < p2)
|
|
38
|
+
return -1;
|
|
39
|
+
if (p1 > p2)
|
|
40
|
+
return 1;
|
|
41
|
+
}
|
|
42
|
+
return 0;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Print version warning to console if outdated
|
|
46
|
+
*/
|
|
47
|
+
export function warnIfOutdated(packageName, result) {
|
|
48
|
+
if (result.isOutdated && result.latestVersion) {
|
|
49
|
+
console.warn(`\n⚠️ New version available: ${result.currentVersion} → ${result.latestVersion}`);
|
|
50
|
+
console.warn(` Run: npm install -g ${packageName}@latest\n`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { GitCloneOptions, GitCloneResult } from './types';
|
|
2
|
+
export declare class GitCloner {
|
|
3
|
+
/**
|
|
4
|
+
* Clone a git repository to a destination
|
|
5
|
+
* @param url - Repository URL (will be normalized)
|
|
6
|
+
* @param destination - Target directory path
|
|
7
|
+
* @param options - Clone options (branch, depth)
|
|
8
|
+
* @returns Clone result with normalized URL and destination
|
|
9
|
+
*/
|
|
10
|
+
clone(url: string, destination: string, options?: GitCloneOptions): GitCloneResult;
|
|
11
|
+
/**
|
|
12
|
+
* Clone to a temporary directory
|
|
13
|
+
* @param url - Repository URL
|
|
14
|
+
* @param options - Clone options
|
|
15
|
+
* @returns Clone result with temp directory path
|
|
16
|
+
*/
|
|
17
|
+
cloneToTemp(url: string, options?: GitCloneOptions): GitCloneResult;
|
|
18
|
+
/**
|
|
19
|
+
* Normalize a URL to git-cloneable format
|
|
20
|
+
* Handles: org/repo -> https://github.com/org/repo.git
|
|
21
|
+
*/
|
|
22
|
+
normalizeUrl(url: string): string;
|
|
23
|
+
/**
|
|
24
|
+
* Validate git URL format
|
|
25
|
+
*/
|
|
26
|
+
validateUrl(url: string): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Remove .git directory from cloned repo
|
|
29
|
+
*/
|
|
30
|
+
removeGitDir(directory: string): void;
|
|
31
|
+
private executeClone;
|
|
32
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
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.GitCloner = void 0;
|
|
37
|
+
const child_process_1 = require("child_process");
|
|
38
|
+
const fs = __importStar(require("fs"));
|
|
39
|
+
const os = __importStar(require("os"));
|
|
40
|
+
const path = __importStar(require("path"));
|
|
41
|
+
class GitCloner {
|
|
42
|
+
/**
|
|
43
|
+
* Clone a git repository to a destination
|
|
44
|
+
* @param url - Repository URL (will be normalized)
|
|
45
|
+
* @param destination - Target directory path
|
|
46
|
+
* @param options - Clone options (branch, depth)
|
|
47
|
+
* @returns Clone result with normalized URL and destination
|
|
48
|
+
*/
|
|
49
|
+
clone(url, destination, options) {
|
|
50
|
+
const normalizedUrl = this.normalizeUrl(url);
|
|
51
|
+
// Clean destination if exists
|
|
52
|
+
if (fs.existsSync(destination)) {
|
|
53
|
+
fs.rmSync(destination, { recursive: true, force: true });
|
|
54
|
+
}
|
|
55
|
+
this.executeClone(normalizedUrl, destination, options);
|
|
56
|
+
this.removeGitDir(destination);
|
|
57
|
+
return {
|
|
58
|
+
destination,
|
|
59
|
+
normalizedUrl,
|
|
60
|
+
branch: options?.branch,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Clone to a temporary directory
|
|
65
|
+
* @param url - Repository URL
|
|
66
|
+
* @param options - Clone options
|
|
67
|
+
* @returns Clone result with temp directory path
|
|
68
|
+
*/
|
|
69
|
+
cloneToTemp(url, options) {
|
|
70
|
+
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'create-gen-'));
|
|
71
|
+
return this.clone(url, tempDir, options);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Normalize a URL to git-cloneable format
|
|
75
|
+
* Handles: org/repo -> https://github.com/org/repo.git
|
|
76
|
+
*/
|
|
77
|
+
normalizeUrl(url) {
|
|
78
|
+
// Already a full URL
|
|
79
|
+
if (url.startsWith('git@') ||
|
|
80
|
+
url.startsWith('https://') ||
|
|
81
|
+
url.startsWith('http://')) {
|
|
82
|
+
return url;
|
|
83
|
+
}
|
|
84
|
+
// org/repo shorthand
|
|
85
|
+
if (/^[\w-]+\/[\w-]+$/.test(url)) {
|
|
86
|
+
return `https://github.com/${url}.git`;
|
|
87
|
+
}
|
|
88
|
+
return url;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Validate git URL format
|
|
92
|
+
*/
|
|
93
|
+
validateUrl(url) {
|
|
94
|
+
const normalized = this.normalizeUrl(url);
|
|
95
|
+
return (normalized.startsWith('git@') ||
|
|
96
|
+
normalized.startsWith('https://') ||
|
|
97
|
+
normalized.startsWith('http://'));
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Remove .git directory from cloned repo
|
|
101
|
+
*/
|
|
102
|
+
removeGitDir(directory) {
|
|
103
|
+
const gitDir = path.join(directory, '.git');
|
|
104
|
+
if (fs.existsSync(gitDir)) {
|
|
105
|
+
fs.rmSync(gitDir, { recursive: true, force: true });
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
executeClone(url, destination, options) {
|
|
109
|
+
const branch = options?.branch;
|
|
110
|
+
const depth = options?.depth ?? 1;
|
|
111
|
+
const singleBranch = options?.singleBranch ?? true;
|
|
112
|
+
const branchArgs = branch ? ` --branch ${branch}` : '';
|
|
113
|
+
const singleBranchArgs = singleBranch ? ' --single-branch' : '';
|
|
114
|
+
const depthArgs = ` --depth ${depth}`;
|
|
115
|
+
const command = `git clone${branchArgs}${singleBranchArgs}${depthArgs} ${url} ${destination}`;
|
|
116
|
+
try {
|
|
117
|
+
(0, child_process_1.execSync)(command, { stdio: 'inherit' });
|
|
118
|
+
}
|
|
119
|
+
catch (error) {
|
|
120
|
+
// Clean up on failure
|
|
121
|
+
if (fs.existsSync(destination)) {
|
|
122
|
+
fs.rmSync(destination, { recursive: true, force: true });
|
|
123
|
+
}
|
|
124
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
125
|
+
throw new Error(`Failed to clone repository: ${errorMessage}`);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
exports.GitCloner = GitCloner;
|
package/git/types.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface GitCloneOptions {
|
|
2
|
+
branch?: string;
|
|
3
|
+
depth?: number;
|
|
4
|
+
singleBranch?: boolean;
|
|
5
|
+
}
|
|
6
|
+
export interface GitCloneResult {
|
|
7
|
+
destination: string;
|
|
8
|
+
normalizedUrl: string;
|
|
9
|
+
branch?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface GitUrlValidation {
|
|
12
|
+
isValid: boolean;
|
|
13
|
+
normalized?: string;
|
|
14
|
+
error?: string;
|
|
15
|
+
}
|
package/index.d.ts
CHANGED
|
@@ -1,4 +1,29 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import { extractVariables } from './template/extract';
|
|
2
|
+
import { promptUser } from './template/prompt';
|
|
3
|
+
import { replaceVariables } from './template/replace';
|
|
4
|
+
import { CreateGenOptions } from './types';
|
|
5
|
+
export * from './cache/cache-manager';
|
|
6
|
+
export * from './cache/types';
|
|
7
|
+
export * from './git/git-cloner';
|
|
8
|
+
export * from './git/types';
|
|
9
|
+
export * from './scaffolder/template-scaffolder';
|
|
10
|
+
export * from './scaffolder/types';
|
|
11
|
+
export * from './template/templatizer';
|
|
12
|
+
export * from './template/types';
|
|
13
|
+
export * from './utils/npm-version-check';
|
|
14
|
+
export * from './utils/types';
|
|
15
|
+
export * from './template/extract';
|
|
16
|
+
export * from './template/prompt';
|
|
17
|
+
export * from './template/replace';
|
|
18
|
+
export * from './types';
|
|
19
|
+
export { extractVariables, promptUser, replaceVariables };
|
|
20
|
+
/**
|
|
21
|
+
* @deprecated This function is deprecated and will be removed in the next major version.
|
|
22
|
+
* Use the modular approach with CacheManager, GitCloner, and Templatizer classes instead.
|
|
23
|
+
* See @genomic/scaffolds-test package for an example of the new orchestration pattern.
|
|
24
|
+
*
|
|
25
|
+
* Create a new project from a template repository
|
|
26
|
+
* @param options - Options for creating the project
|
|
27
|
+
* @returns Path to the generated project
|
|
28
|
+
*/
|
|
29
|
+
export declare function createGen(options: CreateGenOptions): Promise<string>;
|
package/index.js
CHANGED
|
@@ -14,7 +14,46 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
exports.replaceVariables = exports.promptUser = exports.extractVariables = void 0;
|
|
18
|
+
exports.createGen = createGen;
|
|
19
|
+
const inquirerer_1 = require("inquirerer");
|
|
20
|
+
const extract_1 = require("./template/extract");
|
|
21
|
+
Object.defineProperty(exports, "extractVariables", { enumerable: true, get: function () { return extract_1.extractVariables; } });
|
|
22
|
+
const prompt_1 = require("./template/prompt");
|
|
23
|
+
Object.defineProperty(exports, "promptUser", { enumerable: true, get: function () { return prompt_1.promptUser; } });
|
|
24
|
+
const replace_1 = require("./template/replace");
|
|
25
|
+
Object.defineProperty(exports, "replaceVariables", { enumerable: true, get: function () { return replace_1.replaceVariables; } });
|
|
26
|
+
const licenses_1 = require("./licenses");
|
|
27
|
+
// Register the 'licenses' resolver for optionsFrom support
|
|
28
|
+
// This allows boilerplate templates to use: "optionsFrom": "licenses"
|
|
29
|
+
(0, inquirerer_1.registerDefaultResolver)('licenses', () => (0, licenses_1.listSupportedLicenses)());
|
|
30
|
+
// Export new modular classes
|
|
31
|
+
__exportStar(require("./cache/cache-manager"), exports);
|
|
32
|
+
__exportStar(require("./cache/types"), exports);
|
|
33
|
+
__exportStar(require("./git/git-cloner"), exports);
|
|
34
|
+
__exportStar(require("./git/types"), exports);
|
|
35
|
+
__exportStar(require("./scaffolder/template-scaffolder"), exports);
|
|
36
|
+
__exportStar(require("./scaffolder/types"), exports);
|
|
37
|
+
__exportStar(require("./template/templatizer"), exports);
|
|
38
|
+
__exportStar(require("./template/types"), exports);
|
|
39
|
+
__exportStar(require("./utils/npm-version-check"), exports);
|
|
40
|
+
__exportStar(require("./utils/types"), exports);
|
|
41
|
+
// Export template processing functions
|
|
42
|
+
__exportStar(require("./template/extract"), exports);
|
|
43
|
+
__exportStar(require("./template/prompt"), exports);
|
|
44
|
+
__exportStar(require("./template/replace"), exports);
|
|
45
|
+
// Export shared types
|
|
46
|
+
__exportStar(require("./types"), exports);
|
|
47
|
+
/**
|
|
48
|
+
* @deprecated This function is deprecated and will be removed in the next major version.
|
|
49
|
+
* Use the modular approach with CacheManager, GitCloner, and Templatizer classes instead.
|
|
50
|
+
* See @genomic/scaffolds-test package for an example of the new orchestration pattern.
|
|
51
|
+
*
|
|
52
|
+
* Create a new project from a template repository
|
|
53
|
+
* @param options - Options for creating the project
|
|
54
|
+
* @returns Path to the generated project
|
|
55
|
+
*/
|
|
56
|
+
async function createGen(options) {
|
|
57
|
+
throw new Error('createGen() has been deprecated. Please use CacheManager, GitCloner, and Templatizer classes for modular template processing. ' +
|
|
58
|
+
'See @genomic/scaffolds-test package for the new orchestration pattern.');
|
|
59
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
Copyright (c) {{YEAR}} {{AUTHOR}}{{EMAIL_LINE}}
|
|
6
|
+
|
|
7
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
you may not use this file except in compliance with the License.
|
|
9
|
+
You may obtain a copy of the License at
|
|
10
|
+
|
|
11
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
|
|
13
|
+
Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
See the License for the specific language governing permissions and
|
|
17
|
+
limitations under the License.
|
|
18
|
+
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) {{YEAR}} {{AUTHOR}}{{EMAIL_LINE}}
|
|
4
|
+
All rights reserved.
|
|
5
|
+
|
|
6
|
+
Redistribution and use in source and binary forms, with or without
|
|
7
|
+
modification, are permitted provided that the following conditions are met:
|
|
8
|
+
|
|
9
|
+
1. Redistributions of source code must retain the above copyright notice,
|
|
10
|
+
this list of conditions and the following disclaimer.
|
|
11
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
12
|
+
this list of conditions and the following disclaimer in the documentation
|
|
13
|
+
and/or other materials provided with the distribution.
|
|
14
|
+
3. Neither the name of the copyright holder nor the names of its contributors
|
|
15
|
+
may be used to endorse or promote products derived from this software
|
|
16
|
+
without specific prior written permission.
|
|
17
|
+
|
|
18
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
19
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
20
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
21
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
22
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
23
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
24
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
25
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
26
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
27
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
28
|
+
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Copyright (c) {{YEAR}} {{AUTHOR}}{{EMAIL_LINE}}
|
|
2
|
+
|
|
3
|
+
All Rights Reserved.
|
|
4
|
+
|
|
5
|
+
This software and associated documentation files (the "Software") are the
|
|
6
|
+
exclusive property of the copyright holder. No part of the Software may be
|
|
7
|
+
reproduced, distributed, modified, or transmitted in any form or by any means,
|
|
8
|
+
including photocopying, recording, or other electronic or mechanical methods,
|
|
9
|
+
without the prior written permission of the copyright holder.
|
|
10
|
+
|
|
11
|
+
Unauthorized copying, modification, distribution, or use of this Software,
|
|
12
|
+
via any medium, is strictly prohibited.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
16
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
17
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
18
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
19
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
20
|
+
SOFTWARE.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
GNU GENERAL PUBLIC LICENSE
|
|
2
|
+
Version 3, 29 June 2007
|
|
3
|
+
|
|
4
|
+
Copyright (c) {{YEAR}} {{AUTHOR}}{{EMAIL_LINE}}
|
|
5
|
+
|
|
6
|
+
This program is free software: you can redistribute it and/or modify
|
|
7
|
+
it under the terms of the GNU General Public License as published by
|
|
8
|
+
the Free Software Foundation, either version 3 of the License, or
|
|
9
|
+
(at your option) any later version.
|
|
10
|
+
|
|
11
|
+
This program is distributed in the hope that it will be useful,
|
|
12
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
13
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
14
|
+
GNU General Public License for more details.
|
|
15
|
+
|
|
16
|
+
You should have received a copy of the GNU General Public License
|
|
17
|
+
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
18
|
+
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
ISC License
|
|
2
|
+
|
|
3
|
+
Copyright (c) {{YEAR}} {{AUTHOR}}{{EMAIL_LINE}}
|
|
4
|
+
|
|
5
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
6
|
+
purpose with or without fee is hereby granted, provided that the above
|
|
7
|
+
copyright notice and this permission notice appear in all copies.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
10
|
+
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
11
|
+
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
12
|
+
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
13
|
+
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
|
14
|
+
OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
|
15
|
+
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
16
|
+
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) {{YEAR}} {{AUTHOR}}{{EMAIL_LINE}}
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
Mozilla Public License Version 2.0
|
|
2
|
+
|
|
3
|
+
Copyright (c) {{YEAR}} {{AUTHOR}}{{EMAIL_LINE}}
|
|
4
|
+
|
|
5
|
+
This Source Code Form is subject to the terms of the Mozilla Public
|
|
6
|
+
License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
7
|
+
file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
8
|
+
|