create-harper 0.7.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +4 -1
- package/lib/fs/copyDir.js +1 -1
- package/lib/fs/copyFile.js +3 -9
- package/lib/fs/renameFile.js +18 -0
- package/lib/fs/writeFile.js +20 -0
- package/lib/pkg/packageInformation.js +13 -0
- package/lib/steps/checkForUpdate.js +11 -12
- package/lib/steps/scaffoldProject.js +8 -13
- package/package.json +3 -2
- package/template-react/package.json +0 -1
- package/template-react-ts/package.json +0 -1
- package/template-vanilla/package.json +1 -2
- package/template-vanilla-ts/package.json +1 -2
package/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import * as prompts from '@clack/prompts';
|
|
3
|
+
import path from 'node:path';
|
|
3
4
|
import { helpMessage } from './lib/constants/helpMessage.js';
|
|
4
5
|
import { pkgFromUserAgent } from './lib/pkg/pkgFromUserAgent.js';
|
|
5
6
|
import { checkForUpdate } from './lib/steps/checkForUpdate.js';
|
|
@@ -77,7 +78,9 @@ async function init() {
|
|
|
77
78
|
const { immediate } = immediateResult;
|
|
78
79
|
|
|
79
80
|
// Write out the contents based on all prior steps.
|
|
80
|
-
const
|
|
81
|
+
const cwd = process.cwd();
|
|
82
|
+
const root = path.join(cwd, targetDir);
|
|
83
|
+
scaffoldProject(root, projectName, packageName, template, envVars, excludedFiles);
|
|
81
84
|
|
|
82
85
|
// Log out the next steps.
|
|
83
86
|
showOutro(root, pkgManager, immediate);
|
package/lib/fs/copyDir.js
CHANGED
|
@@ -8,7 +8,7 @@ import { copyFile } from './copyFile.js';
|
|
|
8
8
|
* @param {string} srcDir - The source directory path.
|
|
9
9
|
* @param {string} destDir - The destination directory path.
|
|
10
10
|
* @param {(src: string, dest: string) => boolean} [filter] - An optional filter function that returns true if the file should be included.
|
|
11
|
-
* @param {Record<string, string> | ((content: string,
|
|
11
|
+
* @param {Record<string, string> | ((content: string, targetPath: string) => string)} [substitutions] - A mapping of strings to replace or a function that returns the updated content.
|
|
12
12
|
*/
|
|
13
13
|
export function copyDir(srcDir, destDir, filter, substitutions) {
|
|
14
14
|
fs.mkdirSync(destDir, { recursive: true });
|
package/lib/fs/copyFile.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import colors from 'picocolors';
|
|
3
|
+
import { writeFile } from './writeFile.js';
|
|
3
4
|
|
|
4
5
|
const {
|
|
5
6
|
gray,
|
|
@@ -11,18 +12,11 @@ const {
|
|
|
11
12
|
*
|
|
12
13
|
* @param {string} sourcePath - The path to the source template file.
|
|
13
14
|
* @param {string} targetPath - The path where the processed file will be written.
|
|
14
|
-
* @param {Record<string, string> | ((content: string,
|
|
15
|
+
* @param {Record<string, string> | ((content: string, targetPath: string) => string)} [substitutions] - A mapping of strings to replace or a function that returns the updated content.
|
|
15
16
|
*/
|
|
16
17
|
export function copyFile(sourcePath, targetPath, substitutions) {
|
|
17
18
|
let updatedContent = fs.readFileSync(sourcePath, 'utf-8');
|
|
18
|
-
|
|
19
|
-
updatedContent = substitutions(updatedContent, sourcePath, targetPath);
|
|
20
|
-
} else if (substitutions) {
|
|
21
|
-
for (const variableName in substitutions) {
|
|
22
|
-
updatedContent = updatedContent.replaceAll(variableName, substitutions[variableName]);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
19
|
+
writeFile(targetPath, updatedContent, substitutions);
|
|
25
20
|
|
|
26
21
|
console.log(' + ' + green(targetPath) + gray(' from ' + sourcePath));
|
|
27
|
-
fs.writeFileSync(targetPath, updatedContent);
|
|
28
22
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import colors from 'picocolors';
|
|
3
|
+
|
|
4
|
+
const {
|
|
5
|
+
gray,
|
|
6
|
+
magenta,
|
|
7
|
+
} = colors;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Applies string substitutions and writes the result to a target path.
|
|
11
|
+
*
|
|
12
|
+
* @param {string} sourcePath - The original name of the file or directory.
|
|
13
|
+
* @param {string} targetPath - The new name of the file or directory.
|
|
14
|
+
*/
|
|
15
|
+
export function renameFile(sourcePath, targetPath) {
|
|
16
|
+
console.log(' . ' + magenta(targetPath) + gray(' from ' + sourcePath));
|
|
17
|
+
fs.renameSync(sourcePath, targetPath);
|
|
18
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 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} content - The raw content to write, before optional substitutions.
|
|
8
|
+
* @param {Record<string, string> | ((content: string, targetPath: string) => string)} [substitutions] - A mapping of strings to replace or a function that returns the updated content.
|
|
9
|
+
*/
|
|
10
|
+
export function writeFile(targetPath, content, substitutions) {
|
|
11
|
+
let updatedContent = content;
|
|
12
|
+
if (typeof substitutions === 'function') {
|
|
13
|
+
updatedContent = substitutions(updatedContent, targetPath);
|
|
14
|
+
} else if (substitutions) {
|
|
15
|
+
for (const variableName in substitutions) {
|
|
16
|
+
updatedContent = updatedContent.replaceAll(variableName, substitutions[variableName]);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
fs.writeFileSync(targetPath, updatedContent);
|
|
20
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
|
|
3
|
+
export function getOwnName() {
|
|
4
|
+
const packageContents = fs.readFileSync(new URL('../../package.json', import.meta.url), 'utf-8');
|
|
5
|
+
const packageJSON = packageContents ? JSON.parse(packageContents) : {};
|
|
6
|
+
return packageJSON.name;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function getOwnVersion() {
|
|
10
|
+
const packageContents = fs.readFileSync(new URL('../../package.json', import.meta.url), 'utf-8');
|
|
11
|
+
const packageJSON = packageContents ? JSON.parse(packageContents) : {};
|
|
12
|
+
return packageJSON.version;
|
|
13
|
+
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import spawn from 'cross-spawn';
|
|
2
|
-
import fs from 'node:fs';
|
|
3
2
|
import pc from 'picocolors';
|
|
4
3
|
import { getLatestVersion } from '../pkg/getLatestVersion.js';
|
|
5
4
|
import { isVersionNewer } from '../pkg/isVersionNewer.js';
|
|
5
|
+
import { getOwnName, getOwnVersion } from '../pkg/packageInformation.js';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Checks if a newer version of create-harper is available on npm.
|
|
@@ -11,20 +11,19 @@ import { isVersionNewer } from '../pkg/isVersionNewer.js';
|
|
|
11
11
|
* @returns {Promise<string>} - The current version of the package.
|
|
12
12
|
*/
|
|
13
13
|
export async function checkForUpdate() {
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
|
|
14
|
+
const packageName = getOwnName();
|
|
15
|
+
const packageVersion = getOwnVersion();
|
|
17
16
|
if (process.env.CREATE_HARPER_SKIP_UPDATE) {
|
|
18
|
-
return
|
|
17
|
+
return packageVersion;
|
|
19
18
|
}
|
|
20
19
|
|
|
21
20
|
try {
|
|
22
|
-
const latestVersion = await getLatestVersion(
|
|
21
|
+
const latestVersion = await getLatestVersion(packageName);
|
|
23
22
|
|
|
24
|
-
if (latestVersion && isVersionNewer(latestVersion,
|
|
23
|
+
if (latestVersion && isVersionNewer(latestVersion, packageVersion)) {
|
|
25
24
|
console.log(
|
|
26
25
|
pc.yellow(
|
|
27
|
-
`\nA new version of ${pc.bold(
|
|
26
|
+
`\nA new version of ${pc.bold(packageName)} is available! (${pc.dim(packageVersion)} -> ${
|
|
28
27
|
pc.green(latestVersion)
|
|
29
28
|
})`,
|
|
30
29
|
),
|
|
@@ -32,7 +31,7 @@ export async function checkForUpdate() {
|
|
|
32
31
|
console.log(`Automatically updating to the latest version...\n`);
|
|
33
32
|
|
|
34
33
|
// Clear the npx cache for this package to ensure we get the latest version
|
|
35
|
-
const lsResult = spawn.sync('npm', ['cache', 'npx', 'ls',
|
|
34
|
+
const lsResult = spawn.sync('npm', ['cache', 'npx', 'ls', packageName], {
|
|
36
35
|
encoding: 'utf-8',
|
|
37
36
|
});
|
|
38
37
|
|
|
@@ -43,7 +42,7 @@ export async function checkForUpdate() {
|
|
|
43
42
|
.filter((line) => line.includes(':'))
|
|
44
43
|
.filter((line) => {
|
|
45
44
|
const [, pkgPart] = line.split(':');
|
|
46
|
-
return pkgPart && pkgPart.trim().startsWith(`${
|
|
45
|
+
return pkgPart && pkgPart.trim().startsWith(`${packageName}@`);
|
|
47
46
|
})
|
|
48
47
|
.map((line) => line.split(':')[0].trim());
|
|
49
48
|
|
|
@@ -54,7 +53,7 @@ export async function checkForUpdate() {
|
|
|
54
53
|
}
|
|
55
54
|
}
|
|
56
55
|
|
|
57
|
-
const result = spawn.sync('npx', ['-y', `${
|
|
56
|
+
const result = spawn.sync('npx', ['-y', `${packageName}@latest`, ...process.argv.slice(2)], {
|
|
58
57
|
stdio: 'inherit',
|
|
59
58
|
});
|
|
60
59
|
|
|
@@ -64,5 +63,5 @@ export async function checkForUpdate() {
|
|
|
64
63
|
// Ignore errors, we don't want to block the user if the check fails
|
|
65
64
|
}
|
|
66
65
|
|
|
67
|
-
return
|
|
66
|
+
return packageVersion;
|
|
68
67
|
}
|
|
@@ -7,26 +7,23 @@ import { crawlTemplateDir } from '../fs/crawlTemplateDir.js';
|
|
|
7
7
|
/**
|
|
8
8
|
* Step 6: Create the project structure and files based on the collected information.
|
|
9
9
|
*
|
|
10
|
-
* @param {string}
|
|
10
|
+
* @param {string} root - The root directory for the project.
|
|
11
11
|
* @param {string} projectName - The name of the project.
|
|
12
12
|
* @param {string} packageName - The name for the package.json.
|
|
13
13
|
* @param {string} template - The template name to use.
|
|
14
|
-
* @param {import('./getEnvVars.js').EnvVars} envVars - Environment variables to substitute.
|
|
14
|
+
* @param {import('./getEnvVars.js').EnvVars} [envVars] - Environment variables to substitute.
|
|
15
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.
|
|
17
16
|
*/
|
|
18
|
-
export function scaffoldProject(
|
|
19
|
-
const cwd = process.cwd();
|
|
20
|
-
const root = path.join(cwd, targetDir);
|
|
17
|
+
export function scaffoldProject(root, projectName, packageName, template, envVars, excludedFiles = []) {
|
|
21
18
|
fs.mkdirSync(root, { recursive: true });
|
|
22
19
|
prompts.log.step(`Scaffolding project in ${root}...`);
|
|
23
20
|
|
|
24
21
|
const substitutions = {
|
|
25
|
-
'your-project-name-here': projectName,
|
|
26
|
-
'your-package-name-here': packageName,
|
|
27
|
-
'your-cluster-username-here': envVars
|
|
28
|
-
'your-cluster-password-here': envVars
|
|
29
|
-
'your-fabric.harper.fast-cluster-url-here': envVars.
|
|
22
|
+
'your-project-name-here': projectName || 'your-project-name-here',
|
|
23
|
+
'your-package-name-here': packageName || 'your-package-name-here',
|
|
24
|
+
'your-cluster-username-here': envVars?.username || 'your-cluster-username-here',
|
|
25
|
+
'your-cluster-password-here': envVars?.password || 'your-cluster-password-here',
|
|
26
|
+
'your-fabric.harper.fast-cluster-url-here': envVars?.target || 'your-fabric.harper.fast-cluster-url-here',
|
|
30
27
|
};
|
|
31
28
|
|
|
32
29
|
const templateDir = path.resolve(
|
|
@@ -37,6 +34,4 @@ export function scaffoldProject(targetDir, projectName, packageName, template, e
|
|
|
37
34
|
`template-${template}`,
|
|
38
35
|
);
|
|
39
36
|
crawlTemplateDir(root, templateDir, substitutions, excludedFiles);
|
|
40
|
-
|
|
41
|
-
return root;
|
|
42
37
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-harper",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "HarperDB",
|
|
@@ -31,7 +31,8 @@
|
|
|
31
31
|
"test:coverage": "vitest run --coverage",
|
|
32
32
|
"test:watch": "vitest",
|
|
33
33
|
"templates:apply-shared-templates": "(cd templates-shared && node ./applySharedTemplates.js)",
|
|
34
|
-
"templates:build-studio-templates": "(cd templates-studio && node ./buildStudioTemplates.js)"
|
|
34
|
+
"templates:build-studio-templates": "(cd templates-studio && node ./buildStudioTemplates.js)",
|
|
35
|
+
"templates:publish-studio-templates": "(cd templates-studio && node ./publishStudioTemplates.js)"
|
|
35
36
|
},
|
|
36
37
|
"engines": {
|
|
37
38
|
"node": "^20.19.0 || >=22.12.0"
|