@tsparticles/cli-create-utils 4.0.0-beta.12 → 4.0.0-beta.16
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/CHANGELOG.md +12 -0
- package/LICENSE +21 -0
- package/README.md +36 -35
- package/dist/create-project.d.ts +18 -0
- package/dist/create-project.js +1022 -0
- package/dist/file-utils.d.ts +7 -0
- package/dist/file-utils.js +13 -3
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/prompt-utils.d.ts +27 -0
- package/dist/prompt-utils.js +50 -0
- package/dist/template-utils.d.ts +11 -18
- package/dist/template-utils.js +52 -82
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/files/empty-project/package.dist.json +1 -1
- package/files/empty-project/package.json +5 -5
- package/package.json +34 -31
- package/src/create-project.ts +1154 -0
- package/src/file-utils.ts +19 -4
- package/src/index.ts +2 -0
- package/src/prompt-utils.ts +89 -0
- package/src/template-utils.ts +66 -102
- package/.cache/eslint/.eslintcache +0 -1
package/src/file-utils.ts
CHANGED
|
@@ -4,6 +4,8 @@ import { existsSync } from "node:fs";
|
|
|
4
4
|
import { lookpath } from "lookpath";
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
|
|
7
|
+
const jsonIndentation = 2;
|
|
8
|
+
|
|
7
9
|
export interface ReplaceTokensOptions {
|
|
8
10
|
path: string;
|
|
9
11
|
tokens: ReplaceTokensData[];
|
|
@@ -14,6 +16,8 @@ export interface ReplaceTokensData {
|
|
|
14
16
|
to: string;
|
|
15
17
|
}
|
|
16
18
|
|
|
19
|
+
export type JsonUpdater<T> = (data: T) => T;
|
|
20
|
+
|
|
17
21
|
/**
|
|
18
22
|
*
|
|
19
23
|
* @param options -
|
|
@@ -42,6 +46,18 @@ export async function replaceTokensInFile(options: ReplaceTokensOptions): Promis
|
|
|
42
46
|
await replaceTokensInFiles([options]);
|
|
43
47
|
}
|
|
44
48
|
|
|
49
|
+
/**
|
|
50
|
+
* Updates a JSON file preserving standard indentation.
|
|
51
|
+
* @param filePath - The JSON file path
|
|
52
|
+
* @param updater - The updater callback
|
|
53
|
+
*/
|
|
54
|
+
export async function updateJsonFile<T>(filePath: string, updater: JsonUpdater<T>): Promise<void> {
|
|
55
|
+
const data = JSON.parse(await readFile(filePath, "utf-8")) as T,
|
|
56
|
+
updatedData = updater(data);
|
|
57
|
+
|
|
58
|
+
await writeFile(filePath, `${JSON.stringify(updatedData, undefined, jsonIndentation)}\n`);
|
|
59
|
+
}
|
|
60
|
+
|
|
45
61
|
/**
|
|
46
62
|
*
|
|
47
63
|
* @param destination -
|
|
@@ -73,15 +89,14 @@ export async function getRepositoryUrl(): Promise<string> {
|
|
|
73
89
|
return "";
|
|
74
90
|
}
|
|
75
91
|
|
|
76
|
-
return new Promise<string>(
|
|
92
|
+
return new Promise<string>(resolve => {
|
|
77
93
|
exec("git config --get remote.origin.url", (error, stdout) => {
|
|
78
94
|
if (error) {
|
|
79
|
-
|
|
80
|
-
|
|
95
|
+
resolve("");
|
|
81
96
|
return;
|
|
82
97
|
}
|
|
83
98
|
|
|
84
|
-
resolve(stdout);
|
|
99
|
+
resolve(stdout.trim());
|
|
85
100
|
});
|
|
86
101
|
});
|
|
87
102
|
}
|
package/src/index.ts
CHANGED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { getDestinationDir, getRepositoryUrl } from "./file-utils.js";
|
|
2
|
+
import prompts, { type PromptObject } from "prompts";
|
|
3
|
+
import { capitalize } from "./string-utils.js";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
|
|
6
|
+
export interface ISelectChoice<T extends string> {
|
|
7
|
+
title: string;
|
|
8
|
+
value: T;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface IProjectPromptOptions<T extends string = string> {
|
|
12
|
+
destination: string;
|
|
13
|
+
nameLabel: string;
|
|
14
|
+
select?: {
|
|
15
|
+
choices: ISelectChoice<T>[];
|
|
16
|
+
initial: T;
|
|
17
|
+
message: string;
|
|
18
|
+
name: string;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface IProjectPromptResult<T extends string = string> {
|
|
23
|
+
description: string;
|
|
24
|
+
destinationPath: string;
|
|
25
|
+
name: string;
|
|
26
|
+
repositoryUrl: string;
|
|
27
|
+
type: T | undefined;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Prompts for common project creation data.
|
|
32
|
+
* @param options - Prompt options
|
|
33
|
+
* @returns Prompt result with normalized values
|
|
34
|
+
*/
|
|
35
|
+
export async function promptProjectData<T extends string = string>(
|
|
36
|
+
options: IProjectPromptOptions<T>,
|
|
37
|
+
): Promise<IProjectPromptResult<T>> {
|
|
38
|
+
const destinationPath = await getDestinationDir(options.destination),
|
|
39
|
+
repositoryUrl = await getRepositoryUrl(),
|
|
40
|
+
initialName = destinationPath.split(path.sep).pop() ?? "",
|
|
41
|
+
questions: PromptObject[] = [
|
|
42
|
+
{
|
|
43
|
+
type: "text",
|
|
44
|
+
name: "name",
|
|
45
|
+
message: `What is the name of the ${options.nameLabel}?`,
|
|
46
|
+
validate: (value: string) => (value ? true : "The name can't be empty"),
|
|
47
|
+
initial: initialName,
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
type: "text",
|
|
51
|
+
name: "description",
|
|
52
|
+
message: `What is the description of the ${options.nameLabel}?`,
|
|
53
|
+
validate: (value: string) => (value ? true : "The description can't be empty"),
|
|
54
|
+
initial: capitalize(initialName),
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
initial: repositoryUrl,
|
|
58
|
+
message: "What is the repository URL? (optional)",
|
|
59
|
+
name: "repositoryUrl",
|
|
60
|
+
type: "text",
|
|
61
|
+
},
|
|
62
|
+
];
|
|
63
|
+
|
|
64
|
+
if (options.select) {
|
|
65
|
+
questions.push({
|
|
66
|
+
type: "select",
|
|
67
|
+
name: options.select.name,
|
|
68
|
+
message: options.select.message,
|
|
69
|
+
choices: options.select.choices,
|
|
70
|
+
initial: options.select.choices.findIndex(t => t.value === options.select?.initial),
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const answers = (await prompts(questions)) as {
|
|
75
|
+
[key: string]: unknown;
|
|
76
|
+
description: string;
|
|
77
|
+
name: string;
|
|
78
|
+
repositoryUrl: string;
|
|
79
|
+
},
|
|
80
|
+
type = options.select ? (answers[options.select.name] as T | undefined) : undefined;
|
|
81
|
+
|
|
82
|
+
return {
|
|
83
|
+
description: answers.description.trim(),
|
|
84
|
+
destinationPath,
|
|
85
|
+
name: answers.name.trim(),
|
|
86
|
+
repositoryUrl: answers.repositoryUrl.trim(),
|
|
87
|
+
type,
|
|
88
|
+
};
|
|
89
|
+
}
|
package/src/template-utils.ts
CHANGED
|
@@ -1,50 +1,52 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import * as childProcess from "node:child_process";
|
|
2
|
+
import * as fsPromises from "node:fs/promises";
|
|
3
|
+
import { replaceTokensInFile, updateJsonFile } from "./file-utils.js";
|
|
3
4
|
import { lookpath } from "lookpath";
|
|
4
5
|
import path from "node:path";
|
|
5
|
-
|
|
6
|
+
|
|
7
|
+
export interface IProjectMetadata {
|
|
8
|
+
description: string;
|
|
9
|
+
directory: string;
|
|
10
|
+
packageName: string;
|
|
11
|
+
repoUrl: string;
|
|
12
|
+
unpkgFileName: string;
|
|
13
|
+
}
|
|
6
14
|
|
|
7
15
|
/**
|
|
8
16
|
* Updates the package.json file
|
|
9
17
|
* @param destPath - The path where the package.json file is located
|
|
10
|
-
* @param
|
|
11
|
-
* @param description - The description of the package
|
|
12
|
-
* @param fileName - The name of the output file
|
|
13
|
-
* @param repoUrl - The repository URL
|
|
18
|
+
* @param metadata - The project metadata used for updates
|
|
14
19
|
*/
|
|
15
|
-
export async function updatePackageFile(
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
export async function updatePackageFile(destPath: string, metadata: IProjectMetadata): Promise<void> {
|
|
21
|
+
await updateJsonFile<Record<string, unknown>>(path.join(destPath, "package.json"), data => {
|
|
22
|
+
const publishConfig = (data["publishConfig"] ?? {}) as Record<string, unknown>;
|
|
23
|
+
|
|
24
|
+
return {
|
|
25
|
+
...data,
|
|
26
|
+
name: metadata.packageName,
|
|
27
|
+
description: metadata.description,
|
|
28
|
+
repository: {
|
|
29
|
+
type: "git",
|
|
30
|
+
url: `git+${metadata.repoUrl}`,
|
|
31
|
+
directory: metadata.directory,
|
|
32
|
+
},
|
|
33
|
+
bugs: {
|
|
34
|
+
url: metadata.repoUrl.replace(/\.git$/, "/issues"),
|
|
35
|
+
},
|
|
36
|
+
publishConfig: {
|
|
37
|
+
...publishConfig,
|
|
38
|
+
access: "public",
|
|
39
|
+
},
|
|
40
|
+
private: undefined,
|
|
41
|
+
};
|
|
42
|
+
});
|
|
43
|
+
|
|
22
44
|
await replaceTokensInFile({
|
|
23
45
|
path: path.join(destPath, "package.json"),
|
|
24
46
|
tokens: [
|
|
25
|
-
{
|
|
26
|
-
from: /"tsParticles empty template"/g,
|
|
27
|
-
to: `"${description}"`,
|
|
28
|
-
},
|
|
29
47
|
{
|
|
30
48
|
from: /"tsparticles.empty.template.min.js"/g,
|
|
31
|
-
to: `"${
|
|
32
|
-
},
|
|
33
|
-
{
|
|
34
|
-
from: /\s{4}"private": true,\r?\n?/g,
|
|
35
|
-
to: "",
|
|
36
|
-
},
|
|
37
|
-
{
|
|
38
|
-
from: /"@tsparticles\/empty-template"/g,
|
|
39
|
-
to: `"${packageName}"`,
|
|
40
|
-
},
|
|
41
|
-
{
|
|
42
|
-
from: /"url": "git\+https:\/\/github\.com\/tsparticles\/empty-template\.git"/g,
|
|
43
|
-
to: `"url": "git+${repoUrl}"`,
|
|
44
|
-
},
|
|
45
|
-
{
|
|
46
|
-
from: /"url": "https:\/\/github\.com\/tsparticles\/empty-template\/issues"/g,
|
|
47
|
-
to: `"url": "${repoUrl.replace(".git", "/issues")}"`,
|
|
49
|
+
to: `"${metadata.unpkgFileName}"`,
|
|
48
50
|
},
|
|
49
51
|
],
|
|
50
52
|
});
|
|
@@ -53,76 +55,38 @@ export async function updatePackageFile(
|
|
|
53
55
|
/**
|
|
54
56
|
* Updates the package.dist.json file with the new project name and description
|
|
55
57
|
* @param destPath - The path where the package.dist.json file is located
|
|
56
|
-
* @param
|
|
57
|
-
* @param description - The description of the package
|
|
58
|
-
* @param fileName - The name of the output file
|
|
59
|
-
* @param repoUrl - The url of the repository
|
|
58
|
+
* @param metadata - The project metadata used for updates
|
|
60
59
|
*/
|
|
61
|
-
export async function updatePackageDistFile(
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
{
|
|
84
|
-
from: /"@tsparticles\/empty-template"/g,
|
|
85
|
-
to: `"${packageName}"`,
|
|
86
|
-
},
|
|
87
|
-
{
|
|
88
|
-
from: /"url": "git\+https:\/\/github\.com\/tsparticles\/empty-template\.git"/g,
|
|
89
|
-
to: `"url": "git+${repoUrl}"`,
|
|
90
|
-
},
|
|
91
|
-
{
|
|
92
|
-
from: /"url": "https:\/\/github\.com\/tsparticles\/empty-template\/issues"/g,
|
|
93
|
-
to: `"url": "${repoUrl.replace(".git", "/issues")}"`,
|
|
94
|
-
},
|
|
95
|
-
],
|
|
60
|
+
export async function updatePackageDistFile(destPath: string, metadata: IProjectMetadata): Promise<void> {
|
|
61
|
+
await updateJsonFile<Record<string, unknown>>(path.join(destPath, "package.dist.json"), data => {
|
|
62
|
+
const publishConfig = (data["publishConfig"] ?? {}) as Record<string, unknown>;
|
|
63
|
+
|
|
64
|
+
return {
|
|
65
|
+
...data,
|
|
66
|
+
name: metadata.packageName,
|
|
67
|
+
description: metadata.description,
|
|
68
|
+
repository: {
|
|
69
|
+
type: "git",
|
|
70
|
+
url: `git+${metadata.repoUrl}`,
|
|
71
|
+
directory: metadata.directory,
|
|
72
|
+
},
|
|
73
|
+
bugs: {
|
|
74
|
+
url: metadata.repoUrl.replace(/\.git$/, "/issues"),
|
|
75
|
+
},
|
|
76
|
+
publishConfig: {
|
|
77
|
+
...publishConfig,
|
|
78
|
+
access: "public",
|
|
79
|
+
},
|
|
80
|
+
private: undefined,
|
|
81
|
+
};
|
|
96
82
|
});
|
|
97
|
-
}
|
|
98
83
|
|
|
99
|
-
/**
|
|
100
|
-
* Updates the webpack file with the new project name and description
|
|
101
|
-
* @param destPath - The path where the project will be created
|
|
102
|
-
* @param name - The name of the project
|
|
103
|
-
* @param description - The description of the project
|
|
104
|
-
* @param fnName - The name of the function to load the template
|
|
105
|
-
*/
|
|
106
|
-
export async function updateWebpackFile(
|
|
107
|
-
destPath: string,
|
|
108
|
-
name: string,
|
|
109
|
-
description: string,
|
|
110
|
-
fnName: string,
|
|
111
|
-
): Promise<void> {
|
|
112
84
|
await replaceTokensInFile({
|
|
113
|
-
path: path.join(destPath, "
|
|
85
|
+
path: path.join(destPath, "package.dist.json"),
|
|
114
86
|
tokens: [
|
|
115
87
|
{
|
|
116
|
-
from: /"
|
|
117
|
-
to: `"${
|
|
118
|
-
},
|
|
119
|
-
{
|
|
120
|
-
from: /"empty"/g,
|
|
121
|
-
to: `"${name}"`,
|
|
122
|
-
},
|
|
123
|
-
{
|
|
124
|
-
from: /loadParticlesTemplate/g,
|
|
125
|
-
to: fnName,
|
|
88
|
+
from: /"tsparticles.empty.template.min.js"/g,
|
|
89
|
+
to: `"${metadata.unpkgFileName}"`,
|
|
126
90
|
},
|
|
127
91
|
],
|
|
128
92
|
});
|
|
@@ -133,7 +97,7 @@ export async function updateWebpackFile(
|
|
|
133
97
|
* @param destPath - The path where the project will be created
|
|
134
98
|
*/
|
|
135
99
|
export async function copyEmptyTemplateFiles(destPath: string): Promise<void> {
|
|
136
|
-
await cp(path.join(__dirname, "..", "files", "empty-project"), destPath, {
|
|
100
|
+
await fsPromises.cp(path.join(__dirname, "..", "files", "empty-project"), destPath, {
|
|
137
101
|
recursive: true,
|
|
138
102
|
force: true,
|
|
139
103
|
filter: copyFilter,
|
|
@@ -159,7 +123,7 @@ export async function runInstall(destPath: string): Promise<void> {
|
|
|
159
123
|
}
|
|
160
124
|
|
|
161
125
|
return new Promise((resolve, reject) => {
|
|
162
|
-
exec(
|
|
126
|
+
childProcess.exec(
|
|
163
127
|
"npm install",
|
|
164
128
|
{
|
|
165
129
|
cwd: destPath,
|
|
@@ -187,7 +151,7 @@ export async function runBuild(destPath: string): Promise<void> {
|
|
|
187
151
|
}
|
|
188
152
|
|
|
189
153
|
return new Promise((resolve, reject) => {
|
|
190
|
-
exec(
|
|
154
|
+
childProcess.exec(
|
|
191
155
|
"npm run build",
|
|
192
156
|
{
|
|
193
157
|
cwd: destPath,
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
[{"/Users/matteo/Projects/GitHub/tsparticles/tsparticles/cli/commands/create-utils/src/file-utils.ts":"1","/Users/matteo/Projects/GitHub/tsparticles/tsparticles/cli/commands/create-utils/src/index.ts":"2","/Users/matteo/Projects/GitHub/tsparticles/tsparticles/cli/commands/create-utils/src/string-utils.ts":"3","/Users/matteo/Projects/GitHub/tsparticles/tsparticles/cli/commands/create-utils/src/template-utils.ts":"4"},{"size":2011,"mtime":1777824895206,"results":"5","hashOfConfig":"6"},{"size":105,"mtime":1777824895206,"results":"7","hashOfConfig":"6"},{"size":1382,"mtime":1777824895206,"results":"8","hashOfConfig":"6"},{"size":5115,"mtime":1777824895207,"results":"9","hashOfConfig":"6"},{"filePath":"10","messages":"11","suppressedMessages":"12","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"1n6spun",{"filePath":"13","messages":"14","suppressedMessages":"15","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16","messages":"17","suppressedMessages":"18","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19","messages":"20","suppressedMessages":"21","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"/Users/matteo/Projects/GitHub/tsparticles/tsparticles/cli/commands/create-utils/src/file-utils.ts",[],[],"/Users/matteo/Projects/GitHub/tsparticles/tsparticles/cli/commands/create-utils/src/index.ts",[],[],"/Users/matteo/Projects/GitHub/tsparticles/tsparticles/cli/commands/create-utils/src/string-utils.ts",[],[],"/Users/matteo/Projects/GitHub/tsparticles/tsparticles/cli/commands/create-utils/src/template-utils.ts",[],[]]
|