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