create-harper 0.0.5 → 0.0.7
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/index.js +8 -0
- package/lib/constants/defaultEnv.js +14 -0
- package/lib/constants/defaultTargetDir.js +4 -0
- package/lib/constants/exampleFiles.js +11 -0
- package/lib/constants/frameworks.js +20 -0
- package/lib/constants/helpMessage.js +5 -0
- package/lib/constants/renameFiles.js +4 -0
- package/lib/constants/templates.js +4 -0
- package/lib/fs/applyAndWriteTemplateFile.js +7 -0
- package/lib/fs/copy.js +6 -0
- package/lib/fs/copyDir.js +6 -0
- package/lib/fs/crawlTemplateDir.js +9 -0
- package/lib/fs/emptyDir.js +5 -0
- package/lib/fs/formatTargetDir.js +6 -0
- package/lib/fs/isEmpty.js +6 -0
- package/lib/install.js +6 -0
- package/lib/pkg/getInstallCommand.js +6 -0
- package/lib/pkg/getLatestVersion.js +20 -0
- package/lib/pkg/getRunCommand.js +7 -0
- package/lib/pkg/isValidPackageName.js +6 -0
- package/lib/pkg/isVersionNewer.js +18 -0
- package/lib/pkg/pkgFromUserAgent.js +6 -0
- package/lib/pkg/toValidPackageName.js +6 -0
- package/lib/run.js +6 -0
- package/lib/start.js +6 -0
- package/lib/steps/checkForUpdate.js +45 -0
- package/lib/steps/getEnvVars.js +13 -5
- package/lib/steps/getExamples.js +5 -4
- package/lib/steps/getImmediate.js +6 -5
- package/lib/steps/getPackageName.js +5 -4
- package/lib/steps/getProjectName.js +5 -4
- package/lib/steps/getTemplate.js +5 -4
- package/lib/steps/handleExistingDir.js +6 -5
- package/lib/steps/helpAgents.js +3 -1
- package/lib/steps/scaffoldProject.js +9 -8
- package/lib/steps/showOutro.js +5 -4
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -4,6 +4,7 @@ import mri from 'mri';
|
|
|
4
4
|
import { helpMessage } from './lib/constants/helpMessage.js';
|
|
5
5
|
import { formatTargetDir } from './lib/fs/formatTargetDir.js';
|
|
6
6
|
import { pkgFromUserAgent } from './lib/pkg/pkgFromUserAgent.js';
|
|
7
|
+
import { checkForUpdate } from './lib/steps/checkForUpdate.js';
|
|
7
8
|
import { getEnvVars } from './lib/steps/getEnvVars.js';
|
|
8
9
|
import { getExamples } from './lib/steps/getExamples.js';
|
|
9
10
|
import { getImmediate } from './lib/steps/getImmediate.js';
|
|
@@ -38,6 +39,13 @@ async function init() {
|
|
|
38
39
|
return;
|
|
39
40
|
}
|
|
40
41
|
|
|
42
|
+
const currentVersion = await checkForUpdate();
|
|
43
|
+
const version = argv.version;
|
|
44
|
+
if (version) {
|
|
45
|
+
console.log(`Current version: ${currentVersion}`);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
41
49
|
const interactive = argInteractive ?? process.stdin.isTTY;
|
|
42
50
|
|
|
43
51
|
// Detect AI agent environment for better agent experience (AX)
|
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default username for the HarperDB cluster.
|
|
3
|
+
* @type {string}
|
|
4
|
+
*/
|
|
1
5
|
export const defaultUsername = 'YOUR_CLUSTER_USERNAME';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Default password for the HarperDB cluster.
|
|
9
|
+
* @type {string}
|
|
10
|
+
*/
|
|
2
11
|
export const defaultPassword = 'YOUR_CLUSTER_PASSWORD';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Default target URL for the HarperDB cluster.
|
|
15
|
+
* @type {string}
|
|
16
|
+
*/
|
|
3
17
|
export const defaultTarget = 'YOUR_FABRIC.HARPER.FAST_CLUSTER_URL_HERE';
|
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {Object} ExampleFile
|
|
3
|
+
* @property {string} label - The display label for the example.
|
|
4
|
+
* @property {string} value - The internal value for the example.
|
|
5
|
+
* @property {string[]} files - The files associated with this example.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* The list of available example files that can be optionally included in the project.
|
|
10
|
+
* @type {ExampleFile[]}
|
|
11
|
+
*/
|
|
1
12
|
export const exampleFiles = [
|
|
2
13
|
{
|
|
3
14
|
label: 'Table schema',
|
|
@@ -7,6 +7,26 @@ const {
|
|
|
7
7
|
yellow,
|
|
8
8
|
} = colors;
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* @typedef {Object} Variant
|
|
12
|
+
* @property {string} name - The internal name of the variant (used for template matching).
|
|
13
|
+
* @property {string} display - The display name of the variant.
|
|
14
|
+
* @property {(str: string | number) => string} color - A function to color the display name.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @typedef {Object} Framework
|
|
19
|
+
* @property {string} name - The internal name of the framework.
|
|
20
|
+
* @property {string} display - The display name of the framework.
|
|
21
|
+
* @property {(str: string | number) => string} color - A function to color the display name.
|
|
22
|
+
* @property {Variant[]} variants - The available variants for this framework.
|
|
23
|
+
* @property {boolean} [hidden] - Whether this framework should be hidden from the main selection.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* The list of supported frameworks and their variants.
|
|
28
|
+
* @type {Framework[]}
|
|
29
|
+
*/
|
|
10
30
|
export const frameworks = [
|
|
11
31
|
{
|
|
12
32
|
name: 'vanilla',
|
|
@@ -6,6 +6,10 @@ const {
|
|
|
6
6
|
yellow,
|
|
7
7
|
} = colors;
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
* The help message displayed when using the --help flag or on invalid input.
|
|
11
|
+
* @type {string}
|
|
12
|
+
*/
|
|
9
13
|
export const helpMessage = `\
|
|
10
14
|
Usage: create-harper [OPTION]... [DIRECTORY]
|
|
11
15
|
|
|
@@ -16,6 +20,7 @@ Options:
|
|
|
16
20
|
-t, --template NAME use a specific template
|
|
17
21
|
-i, --immediate install dependencies and start dev
|
|
18
22
|
--interactive / --no-interactive force interactive / non-interactive mode
|
|
23
|
+
--version print out the version of the create-harper templates
|
|
19
24
|
|
|
20
25
|
Available templates:
|
|
21
26
|
${yellow('vanilla-ts vanilla')}
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { frameworks } from './frameworks.js';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* A list of all available template names derived from the frameworks and their variants.
|
|
5
|
+
* @type {string[]}
|
|
6
|
+
*/
|
|
3
7
|
export const templates = frameworks.map((f) => f.variants.map((v) => v.name)).reduce(
|
|
4
8
|
(a, b) => a.concat(b),
|
|
5
9
|
[],
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Reads a template file, applies string substitutions, and writes the result to a target path.
|
|
5
|
+
*
|
|
6
|
+
* @param {string} targetPath - The path where the processed file will be written.
|
|
7
|
+
* @param {string} templatePath - The path to the source template file.
|
|
8
|
+
* @param {Record<string, string>} substitutions - A mapping of strings to replace in the file content.
|
|
9
|
+
*/
|
|
3
10
|
export function applyAndWriteTemplateFile(targetPath, templatePath, substitutions) {
|
|
4
11
|
let updatedContent = fs.readFileSync(templatePath, 'utf-8');
|
|
5
12
|
for (const variableName in substitutions) {
|
package/lib/fs/copy.js
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import { copyDir } from './copyDir.js';
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Copies a file or directory from source to destination.
|
|
6
|
+
*
|
|
7
|
+
* @param {string} src - The source path.
|
|
8
|
+
* @param {string} dest - The destination path.
|
|
9
|
+
*/
|
|
4
10
|
export function copy(src, dest) {
|
|
5
11
|
const stat = fs.statSync(src);
|
|
6
12
|
if (stat.isDirectory()) {
|
package/lib/fs/copyDir.js
CHANGED
|
@@ -2,6 +2,12 @@ import fs from 'node:fs';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { copy } from './copy.js';
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* Recursively copies a directory from source to destination.
|
|
7
|
+
*
|
|
8
|
+
* @param {string} srcDir - The source directory path.
|
|
9
|
+
* @param {string} destDir - The destination directory path.
|
|
10
|
+
*/
|
|
5
11
|
export function copyDir(srcDir, destDir) {
|
|
6
12
|
fs.mkdirSync(destDir, { recursive: true });
|
|
7
13
|
for (const file of fs.readdirSync(srcDir)) {
|
|
@@ -3,6 +3,15 @@ import path from 'node:path';
|
|
|
3
3
|
import { renameFiles } from '../constants/renameFiles.js';
|
|
4
4
|
import { applyAndWriteTemplateFile } from './applyAndWriteTemplateFile.js';
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* Recursively crawls a template directory and copies files to the target root, applying substitutions and respecting exclusions.
|
|
8
|
+
*
|
|
9
|
+
* @param {string} root - The current target directory.
|
|
10
|
+
* @param {string} dir - The current source directory in the template.
|
|
11
|
+
* @param {Record<string, string>} substitutions - A mapping of strings to replace in file contents.
|
|
12
|
+
* @param {string[]} [excludedFiles] - A list of relative paths to exclude from copying.
|
|
13
|
+
* @param {string} [templateRootDir] - The absolute path to the root of the template directory (internal).
|
|
14
|
+
*/
|
|
6
15
|
export function crawlTemplateDir(root, dir, substitutions, excludedFiles = [], templateRootDir = dir) {
|
|
7
16
|
const files = fs.readdirSync(dir);
|
|
8
17
|
for (const file of files) {
|
package/lib/fs/emptyDir.js
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Removes all files and directories within a directory, except for the .git directory.
|
|
6
|
+
*
|
|
7
|
+
* @param {string} dir - The path to the directory to empty.
|
|
8
|
+
*/
|
|
4
9
|
export function emptyDir(dir) {
|
|
5
10
|
if (!fs.existsSync(dir)) {
|
|
6
11
|
return;
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Formats a target directory string by trimming whitespace and removing trailing slashes.
|
|
3
|
+
*
|
|
4
|
+
* @param {string} targetDir - The raw target directory string.
|
|
5
|
+
* @returns {string} - The formatted target directory string.
|
|
6
|
+
*/
|
|
1
7
|
export function formatTargetDir(targetDir) {
|
|
2
8
|
return targetDir.trim().replace(/\/+$/g, '');
|
|
3
9
|
}
|
package/lib/fs/isEmpty.js
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Checks if a directory is empty or only contains a .git directory.
|
|
5
|
+
*
|
|
6
|
+
* @param {string} path - The path to the directory to check.
|
|
7
|
+
* @returns {boolean} - True if the directory is considered empty, false otherwise.
|
|
8
|
+
*/
|
|
3
9
|
export function isEmpty(path) {
|
|
4
10
|
const files = fs.readdirSync(path);
|
|
5
11
|
return files.length === 0 || (files.length === 1 && files[0] === '.git');
|
package/lib/install.js
CHANGED
|
@@ -2,6 +2,12 @@ import * as prompts from '@clack/prompts';
|
|
|
2
2
|
import { getInstallCommand } from './pkg/getInstallCommand.js';
|
|
3
3
|
import { run } from './run.js';
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* Installs dependencies for the project.
|
|
7
|
+
*
|
|
8
|
+
* @param {string} root - The root directory of the project.
|
|
9
|
+
* @param {string} agent - The package manager agent (e.g., 'npm', 'pnpm', 'yarn', 'bun').
|
|
10
|
+
*/
|
|
5
11
|
export function install(root, agent) {
|
|
6
12
|
if (process.env._HARPER_TEST_CLI) {
|
|
7
13
|
prompts.log.step(
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gets the install command for a given package manager agent.
|
|
3
|
+
*
|
|
4
|
+
* @param {string} agent - The package manager agent (e.g., 'npm', 'pnpm', 'yarn', 'bun').
|
|
5
|
+
* @returns {string[]} - An array containing the command and its arguments.
|
|
6
|
+
*/
|
|
1
7
|
export function getInstallCommand(agent) {
|
|
2
8
|
if (agent === 'yarn') {
|
|
3
9
|
return [agent];
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fetches the latest version of a package from the npm registry.
|
|
3
|
+
*
|
|
4
|
+
* @param {string} packageName - The name of the package to check.
|
|
5
|
+
* @returns {Promise<string | null>} - The latest version string, or null if it could not be fetched.
|
|
6
|
+
*/
|
|
7
|
+
export async function getLatestVersion(packageName) {
|
|
8
|
+
try {
|
|
9
|
+
const response = await fetch(`https://registry.npmjs.org/${packageName}/latest`, {
|
|
10
|
+
signal: AbortSignal.timeout(1000), // 1 second timeout
|
|
11
|
+
});
|
|
12
|
+
if (!response.ok) {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
const data = await response.json();
|
|
16
|
+
return data.version;
|
|
17
|
+
} catch {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
}
|
package/lib/pkg/getRunCommand.js
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gets the run command for a given package manager agent and script name.
|
|
3
|
+
*
|
|
4
|
+
* @param {string} agent - The package manager agent (e.g., 'npm', 'pnpm', 'yarn', 'bun', 'deno').
|
|
5
|
+
* @param {string} script - The name of the script to run.
|
|
6
|
+
* @returns {string[]} - An array containing the command and its arguments.
|
|
7
|
+
*/
|
|
1
8
|
export function getRunCommand(agent, script) {
|
|
2
9
|
switch (agent) {
|
|
3
10
|
case 'yarn':
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checks if a string is a valid npm package name.
|
|
3
|
+
*
|
|
4
|
+
* @param {string} projectName - The name to validate.
|
|
5
|
+
* @returns {boolean} - True if the name is valid, false otherwise.
|
|
6
|
+
*/
|
|
1
7
|
export function isValidPackageName(projectName) {
|
|
2
8
|
return /^(?:@[a-z\d\-*~][a-z\d\-*._~]*\/)?[a-z\d\-~][a-z\d\-._~]*$/.test(
|
|
3
9
|
projectName,
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Simple semver comparison for version strings in the format x.y.z.
|
|
3
|
+
*
|
|
4
|
+
* @param {string} latest - The latest version string.
|
|
5
|
+
* @param {string} current - The current version string.
|
|
6
|
+
* @returns {boolean} - True if the latest version is newer than the current version, false otherwise.
|
|
7
|
+
*/
|
|
8
|
+
export function isVersionNewer(latest, current) {
|
|
9
|
+
const l = latest.split('.').map(x => parseInt(x, 10));
|
|
10
|
+
const c = current.split('.').map(x => parseInt(x, 10));
|
|
11
|
+
|
|
12
|
+
for (let i = 0; i < 3; i++) {
|
|
13
|
+
if (isNaN(l[i]) || isNaN(c[i])) { break; }
|
|
14
|
+
if (l[i] > c[i]) { return true; }
|
|
15
|
+
if (l[i] < c[i]) { return false; }
|
|
16
|
+
}
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parses the package manager name and version from a User-Agent string.
|
|
3
|
+
*
|
|
4
|
+
* @param {string | undefined} userAgent - The User-Agent string (usually from process.env.npm_config_user_agent).
|
|
5
|
+
* @returns {{name: string, version: string} | undefined} - An object with the package manager name and version, or undefined if not provided.
|
|
6
|
+
*/
|
|
1
7
|
export function pkgFromUserAgent(userAgent) {
|
|
2
8
|
if (!userAgent) { return undefined; }
|
|
3
9
|
const pkgSpec = userAgent.split(' ')[0];
|
package/lib/run.js
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import spawn from 'cross-spawn';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Runs a command synchronously using cross-spawn.
|
|
5
|
+
*
|
|
6
|
+
* @param {string[]} commandArgs - An array containing the command and its arguments.
|
|
7
|
+
* @param {import('child_process').SpawnSyncOptions} [options] - Options for the spawn sync process.
|
|
8
|
+
*/
|
|
3
9
|
export function run([command, ...args], options) {
|
|
4
10
|
const { status, error } = spawn.sync(command, args, options);
|
|
5
11
|
if (status != null && status > 0) {
|
package/lib/start.js
CHANGED
|
@@ -2,6 +2,12 @@ import * as prompts from '@clack/prompts';
|
|
|
2
2
|
import { getRunCommand } from './pkg/getRunCommand.js';
|
|
3
3
|
import { run } from './run.js';
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* Starts the development server for the project.
|
|
7
|
+
*
|
|
8
|
+
* @param {string} root - The root directory of the project.
|
|
9
|
+
* @param {string} agent - The package manager agent (e.g., 'npm', 'pnpm', 'yarn', 'bun').
|
|
10
|
+
*/
|
|
5
11
|
export function start(root, agent) {
|
|
6
12
|
if (process.env._HARPER_TEST_CLI) {
|
|
7
13
|
prompts.log.step('Starting dev server... (skipped in test)');
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import spawn from 'cross-spawn';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import pc from 'picocolors';
|
|
4
|
+
import { getLatestVersion } from '../pkg/getLatestVersion.js';
|
|
5
|
+
import { isVersionNewer } from '../pkg/isVersionNewer.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Checks if a newer version of create-harper is available on npm.
|
|
9
|
+
* If a newer version exists, it attempts to re-run the process using npx with the latest version.
|
|
10
|
+
*
|
|
11
|
+
* @returns {Promise<string>} - The current version of the package.
|
|
12
|
+
*/
|
|
13
|
+
export async function checkForUpdate() {
|
|
14
|
+
const pkg = JSON.parse(fs.readFileSync(new URL('../../package.json', import.meta.url), 'utf-8'));
|
|
15
|
+
const currentVersion = pkg.version;
|
|
16
|
+
|
|
17
|
+
if (process.env.CREATE_HARPER_SKIP_UPDATE) {
|
|
18
|
+
return currentVersion;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
try {
|
|
22
|
+
const latestVersion = await getLatestVersion(pkg.name);
|
|
23
|
+
|
|
24
|
+
if (latestVersion && isVersionNewer(latestVersion, currentVersion)) {
|
|
25
|
+
console.log(
|
|
26
|
+
pc.yellow(
|
|
27
|
+
`\n A new version of ${pc.bold(pkg.name)} is available! (${pc.dim(currentVersion)} -> ${
|
|
28
|
+
pc.green(latestVersion)
|
|
29
|
+
})`,
|
|
30
|
+
),
|
|
31
|
+
);
|
|
32
|
+
console.log(` Automatically updating to the latest version...\n`);
|
|
33
|
+
|
|
34
|
+
const result = spawn.sync('npx', [`${pkg.name}@latest`, ...process.argv.slice(2)], {
|
|
35
|
+
stdio: 'inherit',
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
process.exit(result.status ?? 0);
|
|
39
|
+
}
|
|
40
|
+
} catch {
|
|
41
|
+
// Ignore errors, we don't want to block the user if the check fails
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return currentVersion;
|
|
45
|
+
}
|
package/lib/steps/getEnvVars.js
CHANGED
|
@@ -11,11 +11,19 @@ const {
|
|
|
11
11
|
} = colors;
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
|
-
*
|
|
15
|
-
* @
|
|
16
|
-
* @
|
|
17
|
-
* @
|
|
18
|
-
|
|
14
|
+
* @typedef {Object} EnvVars
|
|
15
|
+
* @property {string} [username] - The HarperDB cluster username.
|
|
16
|
+
* @property {string} [target] - The HarperDB cluster URL.
|
|
17
|
+
* @property {string} [password] - The HarperDB cluster password.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Step 5: Get environment variables for the .env file, optionally prompting the user.
|
|
22
|
+
*
|
|
23
|
+
* @param {Record<string, any>} argv - The parsed CLI arguments.
|
|
24
|
+
* @param {boolean} interactive - Whether the CLI is running in interactive mode.
|
|
25
|
+
* @param {string} template - The selected template name.
|
|
26
|
+
* @returns {Promise<{envVars: EnvVars, cancelled: boolean}>} - The environment variables and cancellation status.
|
|
19
27
|
*/
|
|
20
28
|
export async function getEnvVars(argv, interactive, template) {
|
|
21
29
|
const templateDir = path.resolve(
|
package/lib/steps/getExamples.js
CHANGED
|
@@ -5,10 +5,11 @@ import { fileURLToPath } from 'node:url';
|
|
|
5
5
|
import { exampleFiles } from '../constants/exampleFiles.js';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
* Step 5: Choose which
|
|
9
|
-
*
|
|
10
|
-
* @param {
|
|
11
|
-
* @
|
|
8
|
+
* Step 5 (Optional): Choose which example files to include in the project.
|
|
9
|
+
*
|
|
10
|
+
* @param {string} template - The selected template name.
|
|
11
|
+
* @param {boolean} interactive - Whether the CLI is running in interactive mode.
|
|
12
|
+
* @returns {Promise<{excludedFiles: string[], cancelled: boolean}>} - A list of files to exclude based on selection, and cancellation status.
|
|
12
13
|
*/
|
|
13
14
|
export async function getExamples(template, interactive) {
|
|
14
15
|
const templateDir = path.resolve(
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import * as prompts from '@clack/prompts';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Step 5: Ask
|
|
5
|
-
*
|
|
6
|
-
* @param {boolean}
|
|
7
|
-
* @param {
|
|
8
|
-
* @
|
|
4
|
+
* Step 5 (Optional): Ask the user if they want to immediately install dependencies and start the dev server.
|
|
5
|
+
*
|
|
6
|
+
* @param {boolean | undefined} argImmediate - The immediate flag provided via CLI arguments.
|
|
7
|
+
* @param {boolean} interactive - Whether the CLI is running in interactive mode.
|
|
8
|
+
* @param {string} pkgManager - The detected package manager.
|
|
9
|
+
* @returns {Promise<{immediate: boolean, cancelled: boolean}>} - The immediate flag and cancellation status.
|
|
9
10
|
*/
|
|
10
11
|
export async function getImmediate(argImmediate, interactive, pkgManager) {
|
|
11
12
|
let immediate = argImmediate;
|
|
@@ -4,10 +4,11 @@ import { isValidPackageName } from '../pkg/isValidPackageName.js';
|
|
|
4
4
|
import { toValidPackageName } from '../pkg/toValidPackageName.js';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* Step 3: Get package name
|
|
8
|
-
*
|
|
9
|
-
* @param {
|
|
10
|
-
* @
|
|
7
|
+
* Step 3: Get the package name for the new project.
|
|
8
|
+
*
|
|
9
|
+
* @param {string} targetDir - The target directory for the project.
|
|
10
|
+
* @param {boolean} interactive - Whether the CLI is running in interactive mode.
|
|
11
|
+
* @returns {Promise<{packageName: string, cancelled: boolean}>} - The package name and cancellation status.
|
|
11
12
|
*/
|
|
12
13
|
export async function getPackageName(targetDir, interactive) {
|
|
13
14
|
let packageName = path.basename(path.resolve(targetDir));
|
|
@@ -3,10 +3,11 @@ import { defaultTargetDir } from '../constants/defaultTargetDir.js';
|
|
|
3
3
|
import { formatTargetDir } from '../fs/formatTargetDir.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* Step 1: Get project name and target directory
|
|
7
|
-
*
|
|
8
|
-
* @param {
|
|
9
|
-
* @
|
|
6
|
+
* Step 1: Get the project name and target directory from the user or arguments.
|
|
7
|
+
*
|
|
8
|
+
* @param {string | undefined} argTargetDir - The target directory provided via CLI arguments.
|
|
9
|
+
* @param {boolean} interactive - Whether the CLI is running in interactive mode.
|
|
10
|
+
* @returns {Promise<{projectName: string, targetDir: string, cancelled: boolean}>} - The project name, target directory, and cancellation status.
|
|
10
11
|
*/
|
|
11
12
|
export async function getProjectName(argTargetDir, interactive) {
|
|
12
13
|
let targetDir = argTargetDir;
|
package/lib/steps/getTemplate.js
CHANGED
|
@@ -3,10 +3,11 @@ import { frameworks } from '../constants/frameworks.js';
|
|
|
3
3
|
import { templates } from '../constants/templates.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* Step 4: Choose a framework and variant
|
|
7
|
-
*
|
|
8
|
-
* @param {
|
|
9
|
-
* @
|
|
6
|
+
* Step 4: Choose a project template (framework and variant).
|
|
7
|
+
*
|
|
8
|
+
* @param {string | undefined} argTemplate - The template name provided via CLI arguments.
|
|
9
|
+
* @param {boolean} interactive - Whether the CLI is running in interactive mode.
|
|
10
|
+
* @returns {Promise<{template: string, cancelled: boolean}>} - The selected template name and cancellation status.
|
|
10
11
|
*/
|
|
11
12
|
export async function getTemplate(argTemplate, interactive) {
|
|
12
13
|
let template = argTemplate;
|
|
@@ -4,11 +4,12 @@ import { emptyDir } from '../fs/emptyDir.js';
|
|
|
4
4
|
import { isEmpty } from '../fs/isEmpty.js';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* Step 2: Handle directory if
|
|
8
|
-
*
|
|
9
|
-
* @param {
|
|
10
|
-
* @param {boolean}
|
|
11
|
-
* @
|
|
7
|
+
* Step 2: Handle the target directory if it already exists and is not empty.
|
|
8
|
+
*
|
|
9
|
+
* @param {string} targetDir - The path to the target directory.
|
|
10
|
+
* @param {boolean | undefined} argOverwrite - Whether to overwrite the directory, from CLI arguments.
|
|
11
|
+
* @param {boolean} interactive - Whether the CLI is running in interactive mode.
|
|
12
|
+
* @returns {Promise<{cancelled: boolean}>} - An object indicating if the process was cancelled.
|
|
12
13
|
*/
|
|
13
14
|
export async function handleExistingDir(targetDir, argOverwrite, interactive) {
|
|
14
15
|
if (fs.existsSync(targetDir) && !isEmpty(targetDir)) {
|
package/lib/steps/helpAgents.js
CHANGED
|
@@ -3,7 +3,9 @@ import { determineAgent } from '@vercel/detect-agent';
|
|
|
3
3
|
/**
|
|
4
4
|
* Logs out a helpful message if running in an interactive environment for agents to be more likely to use the
|
|
5
5
|
* parameters correctly.
|
|
6
|
-
*
|
|
6
|
+
*
|
|
7
|
+
* @param {boolean} interactive - Whether the CLI is running in interactive mode.
|
|
8
|
+
* @returns {Promise<void>}
|
|
7
9
|
*/
|
|
8
10
|
export async function helpAgents(interactive) {
|
|
9
11
|
const { isAgent } = await determineAgent();
|
|
@@ -5,14 +5,15 @@ import { fileURLToPath } from 'node:url';
|
|
|
5
5
|
import { crawlTemplateDir } from '../fs/crawlTemplateDir.js';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
* Step 6:
|
|
9
|
-
*
|
|
10
|
-
* @param {string}
|
|
11
|
-
* @param {string}
|
|
12
|
-
* @param {string}
|
|
13
|
-
* @param {
|
|
14
|
-
* @param {
|
|
15
|
-
* @
|
|
8
|
+
* Step 6: Create the project structure and files based on the collected information.
|
|
9
|
+
*
|
|
10
|
+
* @param {string} targetDir - The target directory for the project.
|
|
11
|
+
* @param {string} projectName - The name of the project.
|
|
12
|
+
* @param {string} packageName - The name for the package.json.
|
|
13
|
+
* @param {string} template - The template name to use.
|
|
14
|
+
* @param {import('./getEnvVars.js').EnvVars} envVars - Environment variables to substitute.
|
|
15
|
+
* @param {string[]} [excludedFiles] - A list of files to exclude from the template.
|
|
16
|
+
* @returns {string} - The absolute path to the root of the scaffolded project.
|
|
16
17
|
*/
|
|
17
18
|
export function scaffoldProject(targetDir, projectName, packageName, template, envVars, excludedFiles = []) {
|
|
18
19
|
const cwd = process.cwd();
|
package/lib/steps/showOutro.js
CHANGED
|
@@ -6,10 +6,11 @@ import { getRunCommand } from '../pkg/getRunCommand.js';
|
|
|
6
6
|
import { start } from '../start.js';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
|
-
* Step 7:
|
|
10
|
-
*
|
|
11
|
-
* @param {string}
|
|
12
|
-
* @param {
|
|
9
|
+
* Step 7: Display the final message and instructions to the user.
|
|
10
|
+
*
|
|
11
|
+
* @param {string} root - The absolute path to the project root.
|
|
12
|
+
* @param {string} pkgManager - The detected or selected package manager.
|
|
13
|
+
* @param {boolean} immediate - Whether to immediately install and start the project.
|
|
13
14
|
*/
|
|
14
15
|
export function showOutro(root, pkgManager, immediate) {
|
|
15
16
|
if (immediate) {
|