@tsparticles/cli 1.6.5 → 1.7.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/dist/create/create.js +4 -0
- package/dist/create/plugin/create-plugin.js +86 -0
- package/dist/create/plugin/plugin.js +58 -0
- package/dist/create/shape/create-shape.js +86 -0
- package/dist/create/shape/shape.js +58 -0
- package/files/create-plugin/README.md +74 -0
- package/files/create-plugin/src/PluginInstance.ts +15 -0
- package/files/create-plugin/src/index.ts +39 -0
- package/files/create-preset/README.md +30 -26
- package/files/create-shape/README.md +75 -0
- package/files/create-shape/src/ShapeDrawer.ts +19 -0
- package/files/create-shape/src/index.ts +9 -0
- package/files/empty-project/package.json +1 -1
- package/package.json +11 -11
- package/src/create/create.ts +5 -0
- package/src/create/plugin/create-plugin.ts +178 -0
- package/src/create/plugin/plugin.ts +65 -0
- package/src/create/shape/create-shape.ts +175 -0
- package/src/create/shape/shape.ts +65 -0
package/dist/create/create.js
CHANGED
|
@@ -2,8 +2,12 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createCommand = void 0;
|
|
4
4
|
const commander_1 = require("commander");
|
|
5
|
+
const plugin_1 = require("./plugin/plugin");
|
|
5
6
|
const preset_1 = require("./preset/preset");
|
|
7
|
+
const shape_1 = require("./shape/shape");
|
|
6
8
|
const createCommand = new commander_1.Command("create");
|
|
7
9
|
exports.createCommand = createCommand;
|
|
8
10
|
createCommand.description("Create a new tsParticles project");
|
|
11
|
+
createCommand.addCommand(plugin_1.pluginCommand);
|
|
9
12
|
createCommand.addCommand(preset_1.presetCommand);
|
|
13
|
+
createCommand.addCommand(shape_1.shapeCommand);
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.createPluginTemplate = void 0;
|
|
7
|
+
const string_utils_1 = require("../../utils/string-utils");
|
|
8
|
+
const template_utils_1 = require("../../utils/template-utils");
|
|
9
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
10
|
+
const path_1 = __importDefault(require("path"));
|
|
11
|
+
/**
|
|
12
|
+
* Updates the index file with the correct function name
|
|
13
|
+
* @param destPath - The path where the project is located
|
|
14
|
+
* @param name - The name of the project
|
|
15
|
+
*/
|
|
16
|
+
async function updateIndexFile(destPath, name) {
|
|
17
|
+
const indexPath = path_1.default.resolve(destPath, "src", "index.ts"), index = await fs_extra_1.default.readFile(indexPath, "utf-8"), capitalizedName = (0, string_utils_1.capitalize)((0, string_utils_1.capitalize)(name, "-"), " "), camelizedName = (0, string_utils_1.camelize)(capitalizedName), indexFunctionRegex = /loadTemplatePlugin/g, replacedFuncText = index.replace(indexFunctionRegex, `load${capitalizedName}Plugin`), indexNameRegex = /"#template#"/g, replacedNameText = replacedFuncText.replace(indexNameRegex, `"${camelizedName}"`);
|
|
18
|
+
await fs_extra_1.default.writeFile(indexPath, replacedNameText);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Updates the plugin package file
|
|
22
|
+
* @param destPath - The path where the project is located
|
|
23
|
+
* @param name - The name of the project
|
|
24
|
+
* @param description - The description of the project
|
|
25
|
+
* @param repoUrl - The repository url
|
|
26
|
+
*/
|
|
27
|
+
async function updatePluginPackageFile(destPath, name, description, repoUrl) {
|
|
28
|
+
const camelizedName = (0, string_utils_1.camelize)((0, string_utils_1.camelize)(name, "-"), " "), dashedName = (0, string_utils_1.dash)(camelizedName);
|
|
29
|
+
(0, template_utils_1.updatePackageFile)(destPath, `"tsparticles-plugin-${dashedName}"`, description, `"tsparticles.plugin.${camelizedName}.min.js"`, repoUrl);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Updates the plugin package dist file
|
|
33
|
+
* @param destPath - The path where the project is located
|
|
34
|
+
* @param name - The name of the project
|
|
35
|
+
* @param description - The description of the project
|
|
36
|
+
* @param repoUrl - The repository url
|
|
37
|
+
*/
|
|
38
|
+
async function updatePluginPackageDistFile(destPath, name, description, repoUrl) {
|
|
39
|
+
const camelizedName = (0, string_utils_1.camelize)((0, string_utils_1.camelize)(name, "-"), " "), dashedName = (0, string_utils_1.dash)(camelizedName);
|
|
40
|
+
(0, template_utils_1.updatePackageDistFile)(destPath, `"tsparticles-plugin-${dashedName}"`, description, `"tsparticles.plugin.${camelizedName}.min.js"`, repoUrl);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Updates the plugin readme file
|
|
44
|
+
* @param destPath - The path where the project is located
|
|
45
|
+
* @param name - The name of the project
|
|
46
|
+
* @param description - The description of the project
|
|
47
|
+
* @param repoUrl - The repository url
|
|
48
|
+
*/
|
|
49
|
+
async function updateReadmeFile(destPath, name, description, repoUrl) {
|
|
50
|
+
const readmePath = path_1.default.resolve(destPath, "README.md"), readme = await fs_extra_1.default.readFile(readmePath, "utf-8"), capitalizedName = (0, string_utils_1.capitalize)((0, string_utils_1.capitalize)(name, "-"), " "), camelizedName = (0, string_utils_1.camelize)(capitalizedName), dashedName = (0, string_utils_1.dash)(camelizedName), readmeDescriptionRegex = /tsParticles Template Plugin/g, replacedDescriptionText = readme.replace(readmeDescriptionRegex, `tsParticles ${description} Plugin`), readmePackageNameRegex = /tsparticles-plugin-template/g, replacedPackageNameText = replacedDescriptionText.replace(readmePackageNameRegex, `tsparticles-plugin-${dashedName}`), readmeFileNameRegex = /tsparticles\.plugin\.template(\.bundle)?\.min\.js/g, replacedFileNameText = replacedPackageNameText.replace(readmeFileNameRegex, `tsparticles.plugin.${camelizedName}$1.min.js`), readmeFunctionNameRegex = /loadTemplatePlugin/g, replacedFunctionNameText = replacedFileNameText.replace(readmeFunctionNameRegex, `load${capitalizedName}Plugin`), readmeMiniDescriptionRegex = /\[tsParticles]\(https:\/\/github.com\/matteobruni\/tsparticles\) additional template plugin\./g, replacedMiniDescriptionText = replacedFunctionNameText.replace(readmeMiniDescriptionRegex, `[tsParticles](https://github.com/matteobruni/tsparticles) additional ${name} plugin.`), readmeUsageRegex = /plugin\.type: "template"/g, replacedUsageText = replacedMiniDescriptionText.replace(readmeUsageRegex, `plugin.type: "${camelizedName}`), sampleImageRegex = /!\[demo]\(https:\/\/raw.githubusercontent.com\/tsparticles\/plugin-template\/main\/images\/sample.png\)/g, repoPath = repoUrl.includes("github.com")
|
|
51
|
+
? repoUrl.substring(repoUrl.indexOf("github.com/") + 11, repoUrl.indexOf(".git"))
|
|
52
|
+
: "tsparticles/plugin-template", replacedText = replacedUsageText.replace(sampleImageRegex, ``);
|
|
53
|
+
await fs_extra_1.default.writeFile(readmePath, replacedText);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Updates the plugin webpack file
|
|
57
|
+
* @param destPath - The path where the project is located
|
|
58
|
+
* @param name - The name of the project
|
|
59
|
+
* @param description - The description of the project
|
|
60
|
+
*/
|
|
61
|
+
async function updatePluginWebpackFile(destPath, name, description) {
|
|
62
|
+
await (0, template_utils_1.updateWebpackFile)(destPath, (0, string_utils_1.camelize)((0, string_utils_1.capitalize)((0, string_utils_1.capitalize)(name, "-"), " ")), `tsParticles ${description} Plugin`, "loadParticlesPlugin");
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Creates the plugin project
|
|
66
|
+
* @param name - The name of the project
|
|
67
|
+
* @param description - The description of the project
|
|
68
|
+
* @param repoUrl - The repository url
|
|
69
|
+
* @param destPath - The path where the project is located
|
|
70
|
+
*/
|
|
71
|
+
async function createPluginTemplate(name, description, repoUrl, destPath) {
|
|
72
|
+
const sourcePath = path_1.default.resolve(__dirname, "..", "..", "..", "files", "create-plugin");
|
|
73
|
+
await (0, template_utils_1.copyEmptyTemplateFiles)(destPath);
|
|
74
|
+
await fs_extra_1.default.copy(sourcePath, destPath, {
|
|
75
|
+
overwrite: true,
|
|
76
|
+
filter: template_utils_1.copyFilter,
|
|
77
|
+
});
|
|
78
|
+
await updateIndexFile(destPath, name);
|
|
79
|
+
await updatePluginPackageFile(destPath, name, description, repoUrl);
|
|
80
|
+
await updatePluginPackageDistFile(destPath, name, description, repoUrl);
|
|
81
|
+
await updateReadmeFile(destPath, name, description, repoUrl);
|
|
82
|
+
await updatePluginWebpackFile(destPath, name, description);
|
|
83
|
+
(0, template_utils_1.runInstall)(destPath);
|
|
84
|
+
(0, template_utils_1.runBuild)(destPath);
|
|
85
|
+
}
|
|
86
|
+
exports.createPluginTemplate = createPluginTemplate;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.pluginCommand = void 0;
|
|
7
|
+
const prompts_1 = __importDefault(require("prompts"));
|
|
8
|
+
const commander_1 = require("commander");
|
|
9
|
+
const string_utils_1 = require("../../utils/string-utils");
|
|
10
|
+
const create_plugin_1 = require("./create-plugin");
|
|
11
|
+
const child_process_1 = require("child_process");
|
|
12
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
13
|
+
const path_1 = __importDefault(require("path"));
|
|
14
|
+
const pluginCommand = new commander_1.Command("plugin");
|
|
15
|
+
exports.pluginCommand = pluginCommand;
|
|
16
|
+
pluginCommand.description("Create a new tsParticles plugin");
|
|
17
|
+
pluginCommand.argument("<destination>", "Destination folder");
|
|
18
|
+
pluginCommand.action(async (destination) => {
|
|
19
|
+
let repoUrl;
|
|
20
|
+
const destPath = path_1.default.resolve(path_1.default.join(process.cwd(), destination)), destExists = await fs_extra_1.default.pathExists(destPath);
|
|
21
|
+
if (destExists) {
|
|
22
|
+
const destContents = await fs_extra_1.default.readdir(destPath), destContentsNoGit = destContents.filter(t => t !== ".git" && t !== ".gitignore");
|
|
23
|
+
if (destContentsNoGit.length) {
|
|
24
|
+
throw new Error("Destination folder already exists and is not empty");
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
await fs_extra_1.default.ensureDir(destPath);
|
|
28
|
+
try {
|
|
29
|
+
repoUrl = (0, child_process_1.execSync)("git config --get remote.origin.url").toString();
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
repoUrl = "";
|
|
33
|
+
}
|
|
34
|
+
const initialName = destPath.split(path_1.default.sep).pop(), questions = [
|
|
35
|
+
{
|
|
36
|
+
type: "text",
|
|
37
|
+
name: "name",
|
|
38
|
+
message: "What is the name of the plugin?",
|
|
39
|
+
validate: (value) => (value ? true : "The name can't be empty"),
|
|
40
|
+
initial: initialName,
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
type: "text",
|
|
44
|
+
name: "description",
|
|
45
|
+
message: "What is the description of the plugin?",
|
|
46
|
+
validate: (value) => (value ? true : "The description can't be empty"),
|
|
47
|
+
initial: (0, string_utils_1.capitalize)(initialName || ""),
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
type: "text",
|
|
51
|
+
name: "repositoryUrl",
|
|
52
|
+
message: "What is the repository URL? (optional)",
|
|
53
|
+
initial: repoUrl.trim(),
|
|
54
|
+
},
|
|
55
|
+
];
|
|
56
|
+
const { name, description, repositoryUrl } = await (0, prompts_1.default)(questions);
|
|
57
|
+
(0, create_plugin_1.createPluginTemplate)(name.trim(), description.trim(), repositoryUrl.trim(), destPath);
|
|
58
|
+
});
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.createShapeTemplate = void 0;
|
|
7
|
+
const string_utils_1 = require("../../utils/string-utils");
|
|
8
|
+
const template_utils_1 = require("../../utils/template-utils");
|
|
9
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
10
|
+
const path_1 = __importDefault(require("path"));
|
|
11
|
+
/**
|
|
12
|
+
* Updates the index file with the correct function name
|
|
13
|
+
* @param destPath - The path where the project is located
|
|
14
|
+
* @param name - The name of the project
|
|
15
|
+
*/
|
|
16
|
+
async function updateIndexFile(destPath, name) {
|
|
17
|
+
const indexPath = path_1.default.resolve(destPath, "src", "index.ts"), index = await fs_extra_1.default.readFile(indexPath, "utf-8"), capitalizedName = (0, string_utils_1.capitalize)((0, string_utils_1.capitalize)(name, "-"), " "), camelizedName = (0, string_utils_1.camelize)(capitalizedName), indexFunctionRegex = /loadTemplateShape/g, replacedFuncText = index.replace(indexFunctionRegex, `load${capitalizedName}Shape`), indexNameRegex = /"#template#"/g, replacedNameText = replacedFuncText.replace(indexNameRegex, `"${camelizedName}"`);
|
|
18
|
+
await fs_extra_1.default.writeFile(indexPath, replacedNameText);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Updates the shape package file
|
|
22
|
+
* @param destPath - The path where the project is located
|
|
23
|
+
* @param name - The name of the project
|
|
24
|
+
* @param description - The description of the project
|
|
25
|
+
* @param repoUrl - The repository url
|
|
26
|
+
*/
|
|
27
|
+
async function updateShapePackageFile(destPath, name, description, repoUrl) {
|
|
28
|
+
const camelizedName = (0, string_utils_1.camelize)((0, string_utils_1.camelize)(name, "-"), " "), dashedName = (0, string_utils_1.dash)(camelizedName);
|
|
29
|
+
(0, template_utils_1.updatePackageFile)(destPath, `"tsparticles-shape-${dashedName}"`, description, `"tsparticles.shape.${camelizedName}.min.js"`, repoUrl);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Updates the shape package dist file
|
|
33
|
+
* @param destPath - The path where the project is located
|
|
34
|
+
* @param name - The name of the project
|
|
35
|
+
* @param description - The description of the project
|
|
36
|
+
* @param repoUrl - The repository url
|
|
37
|
+
*/
|
|
38
|
+
async function updateShapePackageDistFile(destPath, name, description, repoUrl) {
|
|
39
|
+
const camelizedName = (0, string_utils_1.camelize)((0, string_utils_1.camelize)(name, "-"), " "), dashedName = (0, string_utils_1.dash)(camelizedName);
|
|
40
|
+
(0, template_utils_1.updatePackageDistFile)(destPath, `"tsparticles-shape-${dashedName}"`, description, `"tsparticles.shape.${camelizedName}.min.js"`, repoUrl);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Updates the shape readme file
|
|
44
|
+
* @param destPath - The path where the project is located
|
|
45
|
+
* @param name - The name of the project
|
|
46
|
+
* @param description - The description of the project
|
|
47
|
+
* @param repoUrl - The repository url
|
|
48
|
+
*/
|
|
49
|
+
async function updateReadmeFile(destPath, name, description, repoUrl) {
|
|
50
|
+
const readmePath = path_1.default.resolve(destPath, "README.md"), readme = await fs_extra_1.default.readFile(readmePath, "utf-8"), capitalizedName = (0, string_utils_1.capitalize)((0, string_utils_1.capitalize)(name, "-"), " "), camelizedName = (0, string_utils_1.camelize)(capitalizedName), dashedName = (0, string_utils_1.dash)(camelizedName), readmeDescriptionRegex = /tsParticles Template Shape/g, replacedDescriptionText = readme.replace(readmeDescriptionRegex, `tsParticles ${description} Shape`), readmePackageNameRegex = /tsparticles-shape-template/g, replacedPackageNameText = replacedDescriptionText.replace(readmePackageNameRegex, `tsparticles-shape-${dashedName}`), readmeFileNameRegex = /tsparticles\.shape\.template(\.bundle)?\.min\.js/g, replacedFileNameText = replacedPackageNameText.replace(readmeFileNameRegex, `tsparticles.shape.${camelizedName}$1.min.js`), readmeFunctionNameRegex = /loadTemplateShape/g, replacedFunctionNameText = replacedFileNameText.replace(readmeFunctionNameRegex, `load${capitalizedName}Shape`), readmeMiniDescriptionRegex = /\[tsParticles]\(https:\/\/github.com\/matteobruni\/tsparticles\) additional template shape\./g, replacedMiniDescriptionText = replacedFunctionNameText.replace(readmeMiniDescriptionRegex, `[tsParticles](https://github.com/matteobruni/tsparticles) additional ${name} shape.`), readmeUsageRegex = /shape\.type: "template"/g, replacedUsageText = replacedMiniDescriptionText.replace(readmeUsageRegex, `shape.type: "${camelizedName}`), sampleImageRegex = /!\[demo]\(https:\/\/raw.githubusercontent.com\/tsparticles\/shape-template\/main\/images\/sample.png\)/g, repoPath = repoUrl.includes("github.com")
|
|
51
|
+
? repoUrl.substring(repoUrl.indexOf("github.com/") + 11, repoUrl.indexOf(".git"))
|
|
52
|
+
: "tsparticles/shape-template", replacedText = replacedUsageText.replace(sampleImageRegex, ``);
|
|
53
|
+
await fs_extra_1.default.writeFile(readmePath, replacedText);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Updates the shape webpack file
|
|
57
|
+
* @param destPath - The path where the project is located
|
|
58
|
+
* @param name - The name of the project
|
|
59
|
+
* @param description - The description of the project
|
|
60
|
+
*/
|
|
61
|
+
async function updateShapeWebpackFile(destPath, name, description) {
|
|
62
|
+
await (0, template_utils_1.updateWebpackFile)(destPath, (0, string_utils_1.camelize)((0, string_utils_1.capitalize)((0, string_utils_1.capitalize)(name, "-"), " ")), `tsParticles ${description} Shape`, "loadParticlesShape");
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Creates the shape project
|
|
66
|
+
* @param name - The name of the project
|
|
67
|
+
* @param description - The description of the project
|
|
68
|
+
* @param repoUrl - The repository url
|
|
69
|
+
* @param destPath - The path where the project is located
|
|
70
|
+
*/
|
|
71
|
+
async function createShapeTemplate(name, description, repoUrl, destPath) {
|
|
72
|
+
const sourcePath = path_1.default.resolve(__dirname, "..", "..", "..", "files", "create-shape");
|
|
73
|
+
await (0, template_utils_1.copyEmptyTemplateFiles)(destPath);
|
|
74
|
+
await fs_extra_1.default.copy(sourcePath, destPath, {
|
|
75
|
+
overwrite: true,
|
|
76
|
+
filter: template_utils_1.copyFilter,
|
|
77
|
+
});
|
|
78
|
+
await updateIndexFile(destPath, name);
|
|
79
|
+
await updateShapePackageFile(destPath, name, description, repoUrl);
|
|
80
|
+
await updateShapePackageDistFile(destPath, name, description, repoUrl);
|
|
81
|
+
await updateReadmeFile(destPath, name, description, repoUrl);
|
|
82
|
+
await updateShapeWebpackFile(destPath, name, description);
|
|
83
|
+
(0, template_utils_1.runInstall)(destPath);
|
|
84
|
+
(0, template_utils_1.runBuild)(destPath);
|
|
85
|
+
}
|
|
86
|
+
exports.createShapeTemplate = createShapeTemplate;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.shapeCommand = void 0;
|
|
7
|
+
const prompts_1 = __importDefault(require("prompts"));
|
|
8
|
+
const commander_1 = require("commander");
|
|
9
|
+
const string_utils_1 = require("../../utils/string-utils");
|
|
10
|
+
const create_shape_1 = require("./create-shape");
|
|
11
|
+
const child_process_1 = require("child_process");
|
|
12
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
13
|
+
const path_1 = __importDefault(require("path"));
|
|
14
|
+
const shapeCommand = new commander_1.Command("shape");
|
|
15
|
+
exports.shapeCommand = shapeCommand;
|
|
16
|
+
shapeCommand.description("Create a new tsParticles shape");
|
|
17
|
+
shapeCommand.argument("<destination>", "Destination folder");
|
|
18
|
+
shapeCommand.action(async (destination) => {
|
|
19
|
+
let repoUrl;
|
|
20
|
+
const destPath = path_1.default.resolve(path_1.default.join(process.cwd(), destination)), destExists = await fs_extra_1.default.pathExists(destPath);
|
|
21
|
+
if (destExists) {
|
|
22
|
+
const destContents = await fs_extra_1.default.readdir(destPath), destContentsNoGit = destContents.filter(t => t !== ".git" && t !== ".gitignore");
|
|
23
|
+
if (destContentsNoGit.length) {
|
|
24
|
+
throw new Error("Destination folder already exists and is not empty");
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
await fs_extra_1.default.ensureDir(destPath);
|
|
28
|
+
try {
|
|
29
|
+
repoUrl = (0, child_process_1.execSync)("git config --get remote.origin.url").toString();
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
repoUrl = "";
|
|
33
|
+
}
|
|
34
|
+
const initialName = destPath.split(path_1.default.sep).pop(), questions = [
|
|
35
|
+
{
|
|
36
|
+
type: "text",
|
|
37
|
+
name: "name",
|
|
38
|
+
message: "What is the name of the shape?",
|
|
39
|
+
validate: (value) => (value ? true : "The name can't be empty"),
|
|
40
|
+
initial: initialName,
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
type: "text",
|
|
44
|
+
name: "description",
|
|
45
|
+
message: "What is the description of the shape?",
|
|
46
|
+
validate: (value) => (value ? true : "The description can't be empty"),
|
|
47
|
+
initial: (0, string_utils_1.capitalize)(initialName || ""),
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
type: "text",
|
|
51
|
+
name: "repositoryUrl",
|
|
52
|
+
message: "What is the repository URL? (optional)",
|
|
53
|
+
initial: repoUrl.trim(),
|
|
54
|
+
},
|
|
55
|
+
];
|
|
56
|
+
const { name, description, repositoryUrl } = await (0, prompts_1.default)(questions);
|
|
57
|
+
(0, create_shape_1.createShapeTemplate)(name.trim(), description.trim(), repositoryUrl.trim(), destPath);
|
|
58
|
+
});
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
[](https://particles.js.org)
|
|
2
|
+
|
|
3
|
+
# tsParticles Template Plugin
|
|
4
|
+
|
|
5
|
+
[](https://www.jsdelivr.com/package/npm/tsparticles-plugin-template)
|
|
6
|
+
[](https://www.npmjs.com/package/tsparticles-plugin-template)
|
|
7
|
+
[](https://www.npmjs.com/package/tsparticles-plugin-template) [](https://github.com/sponsors/matteobruni)
|
|
8
|
+
|
|
9
|
+
[tsParticles](https://github.com/matteobruni/tsparticles) plugin for particles template.
|
|
10
|
+
|
|
11
|
+
## How to use it
|
|
12
|
+
|
|
13
|
+
### CDN / Vanilla JS / jQuery
|
|
14
|
+
|
|
15
|
+
The CDN/Vanilla version JS has one required file in vanilla configuration:
|
|
16
|
+
|
|
17
|
+
Including the `tsparticles.plugin.template.min.js` file will export the function to load the plugin:
|
|
18
|
+
|
|
19
|
+
```javascript
|
|
20
|
+
loadTemplatePlugin;
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### Usage
|
|
24
|
+
|
|
25
|
+
Once the scripts are loaded you can set up `tsParticles` and the plugin like this:
|
|
26
|
+
|
|
27
|
+
```javascript
|
|
28
|
+
(async () => {
|
|
29
|
+
await loadTemplatePlugin(tsParticles);
|
|
30
|
+
|
|
31
|
+
await tsParticles.load({
|
|
32
|
+
id: "tsparticles",
|
|
33
|
+
options: {
|
|
34
|
+
/* options */
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
})();
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### ESM / CommonJS
|
|
41
|
+
|
|
42
|
+
This package is compatible also with ES or CommonJS modules, firstly this needs to be installed, like this:
|
|
43
|
+
|
|
44
|
+
```shell
|
|
45
|
+
$ npm install tsparticles-plugin-template
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
or
|
|
49
|
+
|
|
50
|
+
```shell
|
|
51
|
+
$ yarn add tsparticles-plugin-template
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Then you need to import it in the app, like this:
|
|
55
|
+
|
|
56
|
+
```javascript
|
|
57
|
+
const { tsParticles } = require("tsparticles-engine");
|
|
58
|
+
const { loadTemplatePlugin } = require("tsparticles-plugin-template");
|
|
59
|
+
|
|
60
|
+
(async () => {
|
|
61
|
+
await loadTemplatePlugin(tsParticles);
|
|
62
|
+
})();
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
or
|
|
66
|
+
|
|
67
|
+
```javascript
|
|
68
|
+
import { tsParticles } from "tsparticles-engine";
|
|
69
|
+
import { loadTemplatePlugin } from "tsparticles-plugin-template";
|
|
70
|
+
|
|
71
|
+
(async () => {
|
|
72
|
+
await loadTemplatePlugin(tsParticles);
|
|
73
|
+
})();
|
|
74
|
+
```
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type Container, type Engine, type IContainerPlugin } from "tsparticles-engine";
|
|
2
|
+
|
|
3
|
+
export class PluginInstance implements IContainerPlugin {
|
|
4
|
+
private readonly _container;
|
|
5
|
+
private readonly _engine;
|
|
6
|
+
|
|
7
|
+
constructor(container: Container, engine: Engine) {
|
|
8
|
+
this._container = container;
|
|
9
|
+
this._engine = engine;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
async init(): Promise<void> {
|
|
13
|
+
// add your plugin initialization here
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { Container, Engine, IPlugin, ISourceOptions, Options } from "tsparticles-engine";
|
|
2
|
+
import { PluginInstance } from "./PluginInstance";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
*/
|
|
6
|
+
class Plugin implements IPlugin {
|
|
7
|
+
readonly id;
|
|
8
|
+
|
|
9
|
+
private readonly _engine;
|
|
10
|
+
|
|
11
|
+
constructor(engine: Engine) {
|
|
12
|
+
this.id = "#template#";
|
|
13
|
+
|
|
14
|
+
this._engine = engine;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
getPlugin(container: Container): PluginInstance {
|
|
18
|
+
return new PluginInstance(container, this._engine);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
loadOptions(_options: Options, _source?: ISourceOptions): void {
|
|
22
|
+
if (!this.needsPlugin()) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Load your options here
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
needsPlugin(_options?: ISourceOptions): boolean {
|
|
30
|
+
return true; // add your condition here
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* @param engine - The engine instance
|
|
36
|
+
*/
|
|
37
|
+
export async function loadTemplatePlugin(engine: Engine): Promise<void> {
|
|
38
|
+
await engine.addPlugin(new Plugin(engine));
|
|
39
|
+
}
|
|
@@ -40,9 +40,11 @@ A bundled script can also be used, this will include every needed plugin needed
|
|
|
40
40
|
Once the scripts are loaded you can set up `tsParticles` like this:
|
|
41
41
|
|
|
42
42
|
```javascript
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
43
|
+
(async () => {
|
|
44
|
+
await tsParticles.load("tsparticles", {
|
|
45
|
+
preset: "template",
|
|
46
|
+
});
|
|
47
|
+
})();
|
|
46
48
|
```
|
|
47
49
|
|
|
48
50
|
#### Customization
|
|
@@ -51,14 +53,16 @@ tsParticles.load("tsparticles", {
|
|
|
51
53
|
You can override all the options defining the properties like in any standard `tsParticles` installation.
|
|
52
54
|
|
|
53
55
|
```javascript
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
56
|
+
(async () => {
|
|
57
|
+
await tsParticles.load("tsparticles", {
|
|
58
|
+
particles: {
|
|
59
|
+
shape: {
|
|
60
|
+
type: "square"
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
preset: "template"
|
|
64
|
+
});
|
|
65
|
+
})();
|
|
62
66
|
```
|
|
63
67
|
|
|
64
68
|
Like in the sample above, the circles will be replaced by squares.
|
|
@@ -71,19 +75,19 @@ This sample uses the class component syntax, but you can use hooks as well (if t
|
|
|
71
75
|
|
|
72
76
|
```javascript
|
|
73
77
|
import Particles from "react-particles";
|
|
74
|
-
import {
|
|
78
|
+
import { Engine } from "tsparticles-engine";
|
|
75
79
|
import { loadTemplatePreset } from "tsparticles-preset-template";
|
|
76
80
|
|
|
77
81
|
export class ParticlesContainer extends React.PureComponent<IProps> {
|
|
78
82
|
// this customizes the component tsParticles installation
|
|
79
|
-
customInit(
|
|
83
|
+
async customInit(engine: Engine) {
|
|
80
84
|
// this adds the preset to tsParticles, you can safely use the
|
|
81
|
-
loadTemplatePreset(
|
|
85
|
+
await loadTemplatePreset(engine);
|
|
82
86
|
}
|
|
83
87
|
|
|
84
88
|
render() {
|
|
85
89
|
const options = {
|
|
86
|
-
preset: "template",
|
|
90
|
+
preset: "template",
|
|
87
91
|
};
|
|
88
92
|
|
|
89
93
|
return <Particles options={options} init={this.customInit} />;
|
|
@@ -100,25 +104,25 @@ _The syntax for `Vue.js 2.x` and `3.x` is the same_
|
|
|
100
104
|
```
|
|
101
105
|
|
|
102
106
|
```js
|
|
103
|
-
function particlesInit(
|
|
104
|
-
|
|
107
|
+
async function particlesInit(engine: Engine) {
|
|
108
|
+
await loadTemplatePreset(main);
|
|
105
109
|
}
|
|
106
110
|
```
|
|
107
111
|
|
|
108
112
|
### Angular
|
|
109
113
|
|
|
110
114
|
```html
|
|
115
|
+
|
|
111
116
|
<ng-particles
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
(particlesInit)="particlesInit($event)"
|
|
117
|
+
[id]="id"
|
|
118
|
+
[options]="particlesOptions"
|
|
119
|
+
[particlesInit]="particlesInit"
|
|
116
120
|
></ng-particles>
|
|
117
121
|
```
|
|
118
122
|
|
|
119
123
|
```ts
|
|
120
|
-
function particlesInit(
|
|
121
|
-
|
|
124
|
+
async function particlesInit(engine: Engine): Promise<void> {
|
|
125
|
+
loadTemplatePreset(engine);
|
|
122
126
|
}
|
|
123
127
|
```
|
|
124
128
|
|
|
@@ -129,12 +133,12 @@ function particlesInit(main: Main): void {
|
|
|
129
133
|
<Particles
|
|
130
134
|
id="tsparticles"
|
|
131
135
|
url="{particlesUrl}"
|
|
132
|
-
|
|
136
|
+
particlesInit="{particlesInit}"
|
|
133
137
|
/>
|
|
134
138
|
```
|
|
135
139
|
|
|
136
140
|
```js
|
|
137
|
-
let
|
|
138
|
-
|
|
141
|
+
let particlesInit = async (engine) => {
|
|
142
|
+
await loadTemplatePreset(engine);
|
|
139
143
|
};
|
|
140
144
|
```
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
[](https://particles.js.org)
|
|
2
|
+
|
|
3
|
+
# tsParticles Template Shape
|
|
4
|
+
|
|
5
|
+
[](https://www.jsdelivr.com/package/npm/tsparticles-shape-template)
|
|
6
|
+
[](https://www.npmjs.com/package/tsparticles-shape-template)
|
|
7
|
+
[](https://www.npmjs.com/package/tsparticles-shape-template) [](https://github.com/sponsors/matteobruni)
|
|
8
|
+
|
|
9
|
+
[tsParticles](https://github.com/matteobruni/tsparticles) additional template shape.
|
|
10
|
+
|
|
11
|
+
## How to use it
|
|
12
|
+
|
|
13
|
+
### CDN / Vanilla JS / jQuery
|
|
14
|
+
|
|
15
|
+
The CDN/Vanilla version JS has one required file in vanilla configuration:
|
|
16
|
+
|
|
17
|
+
Including the `tsparticles.shape.template.min.js` file will export the function to load the shape:
|
|
18
|
+
|
|
19
|
+
```text
|
|
20
|
+
loadTemplateShape
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### Usage
|
|
24
|
+
|
|
25
|
+
Once the scripts are loaded you can set up `tsParticles` and the shape like this:
|
|
26
|
+
|
|
27
|
+
```javascript
|
|
28
|
+
(async () => {
|
|
29
|
+
await loadTemplateShape(tsParticles);
|
|
30
|
+
|
|
31
|
+
await tsParticles.load({
|
|
32
|
+
id: "tsparticles",
|
|
33
|
+
options: {
|
|
34
|
+
/* options */
|
|
35
|
+
/* here you can use particles.shape.type: "template" */
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
})();
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### ESM / CommonJS
|
|
42
|
+
|
|
43
|
+
This package is compatible also with ES or CommonJS modules, firstly this needs to be installed, like this:
|
|
44
|
+
|
|
45
|
+
```shell
|
|
46
|
+
$ npm install tsparticles-shape-template
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
or
|
|
50
|
+
|
|
51
|
+
```shell
|
|
52
|
+
$ yarn add tsparticles-shape-template
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Then you need to import it in the app, like this:
|
|
56
|
+
|
|
57
|
+
```javascript
|
|
58
|
+
const { tsParticles } = require("tsparticles-engine");
|
|
59
|
+
const { loadTemplateShape } = require("tsparticles-shape-template");
|
|
60
|
+
|
|
61
|
+
(async () => {
|
|
62
|
+
await loadTemplateShape(tsParticles);
|
|
63
|
+
})();
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
or
|
|
67
|
+
|
|
68
|
+
```javascript
|
|
69
|
+
import { tsParticles } from "tsparticles-engine";
|
|
70
|
+
import { loadTemplateShape } from "tsparticles-shape-template";
|
|
71
|
+
|
|
72
|
+
(async () => {
|
|
73
|
+
await loadTemplateShape(tsParticles);
|
|
74
|
+
})();
|
|
75
|
+
```
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { IDelta, IShapeDrawer, Particle } from "tsparticles-engine";
|
|
2
|
+
|
|
3
|
+
export class ShapeDrawer implements IShapeDrawer {
|
|
4
|
+
draw(_context: CanvasRenderingContext2D,
|
|
5
|
+
_particle: Particle,
|
|
6
|
+
_radius: number,
|
|
7
|
+
_opacity: number,
|
|
8
|
+
_delta: IDelta,
|
|
9
|
+
_pixelRatio: number): void {
|
|
10
|
+
// draw the particle using the context
|
|
11
|
+
// which is already centered in the particle position
|
|
12
|
+
// colors are already handles, just draw the shape
|
|
13
|
+
// the bounds are -radius to radius
|
|
14
|
+
// delta is the frame time difference between the last frame and this one, in ms, use it for animated shapes
|
|
15
|
+
// pixelRatio is the canvas ratio used by the tsParticles instance, you may need it for density-independent shapes
|
|
16
|
+
// the parameters have an underscore prefix because they're not used in this example
|
|
17
|
+
// the underscore prefix can be removed for used parameters, the unused ones can be removed too
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Engine } from "tsparticles-engine";
|
|
2
|
+
import { ShapeDrawer } from "./ShapeDrawer";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @param engine - the engine instance to load the shape into
|
|
6
|
+
*/
|
|
7
|
+
export async function loadTemplateShape(engine: Engine): Promise<void> {
|
|
8
|
+
await engine.addShape("#template#", new ShapeDrawer());
|
|
9
|
+
}
|
|
@@ -83,7 +83,7 @@
|
|
|
83
83
|
"prettier": "@tsparticles/prettier-config",
|
|
84
84
|
"devDependencies": {
|
|
85
85
|
"@babel/core": "^7.22.5",
|
|
86
|
-
"@tsparticles/cli": "1.
|
|
86
|
+
"@tsparticles/cli": "1.7.0",
|
|
87
87
|
"@tsparticles/eslint-config": "^1.13.0",
|
|
88
88
|
"@tsparticles/prettier-config": "^1.10.0",
|
|
89
89
|
"@tsparticles/tsconfig": "^1.13.0",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tsparticles/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"bin": {
|
|
6
6
|
"tsparticles-cli": "dist/cli.js"
|
|
@@ -10,31 +10,31 @@
|
|
|
10
10
|
},
|
|
11
11
|
"prettier": "@tsparticles/prettier-config",
|
|
12
12
|
"dependencies": {
|
|
13
|
-
"@tsparticles/eslint-config": "^1.
|
|
13
|
+
"@tsparticles/eslint-config": "^1.14.0",
|
|
14
14
|
"@tsparticles/prettier-config": "^1.10.0",
|
|
15
|
-
"@tsparticles/tsconfig": "^1.
|
|
16
|
-
"@tsparticles/webpack-plugin": "^1.
|
|
17
|
-
"@typescript-eslint/eslint-plugin": "^5.60.
|
|
18
|
-
"@typescript-eslint/parser": "^5.60.
|
|
15
|
+
"@tsparticles/tsconfig": "^1.14.0",
|
|
16
|
+
"@tsparticles/webpack-plugin": "^1.16.0",
|
|
17
|
+
"@typescript-eslint/eslint-plugin": "^5.60.1",
|
|
18
|
+
"@typescript-eslint/parser": "^5.60.1",
|
|
19
19
|
"commander": "^11.0.0",
|
|
20
20
|
"eslint": "^8.43.0",
|
|
21
21
|
"eslint-config-prettier": "^8.8.0",
|
|
22
|
-
"eslint-plugin-jsdoc": "^46.2
|
|
22
|
+
"eslint-plugin-jsdoc": "^46.4.2",
|
|
23
23
|
"eslint-plugin-tsdoc": "^0.2.17",
|
|
24
24
|
"fs-extra": "^11.1.1",
|
|
25
25
|
"klaw": "^4.1.0",
|
|
26
|
-
"path-scurry": "^1.
|
|
26
|
+
"path-scurry": "^1.10.0",
|
|
27
27
|
"prettier": "^2.8.8",
|
|
28
28
|
"prompts": "^2.4.2",
|
|
29
29
|
"rimraf": "^5.0.1",
|
|
30
|
-
"typescript": "^5.1.
|
|
31
|
-
"webpack": "^5.
|
|
30
|
+
"typescript": "^5.1.6",
|
|
31
|
+
"webpack": "^5.88.1"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"@types/eslint": "^8.40.2",
|
|
35
35
|
"@types/fs-extra": "^11.0.1",
|
|
36
36
|
"@types/klaw": "^3.0.3",
|
|
37
|
-
"@types/node": "^20.3.
|
|
37
|
+
"@types/node": "^20.3.2",
|
|
38
38
|
"@types/prettier": "^2.7.3",
|
|
39
39
|
"@types/prompts": "^2.4.4"
|
|
40
40
|
},
|
package/src/create/create.ts
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
import { Command } from "commander";
|
|
2
|
+
import { pluginCommand } from "./plugin/plugin";
|
|
2
3
|
import { presetCommand } from "./preset/preset";
|
|
4
|
+
import { shapeCommand } from "./shape/shape";
|
|
3
5
|
|
|
4
6
|
const createCommand = new Command("create");
|
|
5
7
|
|
|
6
8
|
createCommand.description("Create a new tsParticles project");
|
|
9
|
+
|
|
10
|
+
createCommand.addCommand(pluginCommand);
|
|
7
11
|
createCommand.addCommand(presetCommand);
|
|
12
|
+
createCommand.addCommand(shapeCommand);
|
|
8
13
|
|
|
9
14
|
export { createCommand };
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { camelize, capitalize, dash } from "../../utils/string-utils";
|
|
2
|
+
import {
|
|
3
|
+
copyEmptyTemplateFiles,
|
|
4
|
+
copyFilter,
|
|
5
|
+
runBuild,
|
|
6
|
+
runInstall,
|
|
7
|
+
updatePackageDistFile,
|
|
8
|
+
updatePackageFile,
|
|
9
|
+
updateWebpackFile,
|
|
10
|
+
} from "../../utils/template-utils";
|
|
11
|
+
import fs from "fs-extra";
|
|
12
|
+
import path from "path";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Updates the index file with the correct function name
|
|
16
|
+
* @param destPath - The path where the project is located
|
|
17
|
+
* @param name - The name of the project
|
|
18
|
+
*/
|
|
19
|
+
async function updateIndexFile(destPath: string, name: string): Promise<void> {
|
|
20
|
+
const indexPath = path.resolve(destPath, "src", "index.ts"),
|
|
21
|
+
index = await fs.readFile(indexPath, "utf-8"),
|
|
22
|
+
capitalizedName = capitalize(capitalize(name, "-"), " "),
|
|
23
|
+
camelizedName = camelize(capitalizedName),
|
|
24
|
+
indexFunctionRegex = /loadTemplatePlugin/g,
|
|
25
|
+
replacedFuncText = index.replace(indexFunctionRegex, `load${capitalizedName}Plugin`),
|
|
26
|
+
indexNameRegex = /"#template#"/g,
|
|
27
|
+
replacedNameText = replacedFuncText.replace(indexNameRegex, `"${camelizedName}"`);
|
|
28
|
+
|
|
29
|
+
await fs.writeFile(indexPath, replacedNameText);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Updates the plugin package file
|
|
34
|
+
* @param destPath - The path where the project is located
|
|
35
|
+
* @param name - The name of the project
|
|
36
|
+
* @param description - The description of the project
|
|
37
|
+
* @param repoUrl - The repository url
|
|
38
|
+
*/
|
|
39
|
+
async function updatePluginPackageFile(
|
|
40
|
+
destPath: string,
|
|
41
|
+
name: string,
|
|
42
|
+
description: string,
|
|
43
|
+
repoUrl: string
|
|
44
|
+
): Promise<void> {
|
|
45
|
+
const camelizedName = camelize(camelize(name, "-"), " "),
|
|
46
|
+
dashedName = dash(camelizedName);
|
|
47
|
+
|
|
48
|
+
updatePackageFile(
|
|
49
|
+
destPath,
|
|
50
|
+
`"tsparticles-plugin-${dashedName}"`,
|
|
51
|
+
description,
|
|
52
|
+
`"tsparticles.plugin.${camelizedName}.min.js"`,
|
|
53
|
+
repoUrl
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Updates the plugin package dist file
|
|
59
|
+
* @param destPath - The path where the project is located
|
|
60
|
+
* @param name - The name of the project
|
|
61
|
+
* @param description - The description of the project
|
|
62
|
+
* @param repoUrl - The repository url
|
|
63
|
+
*/
|
|
64
|
+
async function updatePluginPackageDistFile(
|
|
65
|
+
destPath: string,
|
|
66
|
+
name: string,
|
|
67
|
+
description: string,
|
|
68
|
+
repoUrl: string
|
|
69
|
+
): Promise<void> {
|
|
70
|
+
const camelizedName = camelize(camelize(name, "-"), " "),
|
|
71
|
+
dashedName = dash(camelizedName);
|
|
72
|
+
|
|
73
|
+
updatePackageDistFile(
|
|
74
|
+
destPath,
|
|
75
|
+
`"tsparticles-plugin-${dashedName}"`,
|
|
76
|
+
description,
|
|
77
|
+
`"tsparticles.plugin.${camelizedName}.min.js"`,
|
|
78
|
+
repoUrl
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Updates the plugin readme file
|
|
84
|
+
* @param destPath - The path where the project is located
|
|
85
|
+
* @param name - The name of the project
|
|
86
|
+
* @param description - The description of the project
|
|
87
|
+
* @param repoUrl - The repository url
|
|
88
|
+
*/
|
|
89
|
+
async function updateReadmeFile(destPath: string, name: string, description: string, repoUrl: string): Promise<void> {
|
|
90
|
+
const readmePath = path.resolve(destPath, "README.md"),
|
|
91
|
+
readme = await fs.readFile(readmePath, "utf-8"),
|
|
92
|
+
capitalizedName = capitalize(capitalize(name, "-"), " "),
|
|
93
|
+
camelizedName = camelize(capitalizedName),
|
|
94
|
+
dashedName = dash(camelizedName),
|
|
95
|
+
readmeDescriptionRegex = /tsParticles Template Plugin/g,
|
|
96
|
+
replacedDescriptionText = readme.replace(readmeDescriptionRegex, `tsParticles ${description} Plugin`),
|
|
97
|
+
readmePackageNameRegex = /tsparticles-plugin-template/g,
|
|
98
|
+
replacedPackageNameText = replacedDescriptionText.replace(
|
|
99
|
+
readmePackageNameRegex,
|
|
100
|
+
`tsparticles-plugin-${dashedName}`
|
|
101
|
+
),
|
|
102
|
+
readmeFileNameRegex = /tsparticles\.plugin\.template(\.bundle)?\.min\.js/g,
|
|
103
|
+
replacedFileNameText = replacedPackageNameText.replace(
|
|
104
|
+
readmeFileNameRegex,
|
|
105
|
+
`tsparticles.plugin.${camelizedName}$1.min.js`
|
|
106
|
+
),
|
|
107
|
+
readmeFunctionNameRegex = /loadTemplatePlugin/g,
|
|
108
|
+
replacedFunctionNameText = replacedFileNameText.replace(
|
|
109
|
+
readmeFunctionNameRegex,
|
|
110
|
+
`load${capitalizedName}Plugin`
|
|
111
|
+
),
|
|
112
|
+
readmeMiniDescriptionRegex =
|
|
113
|
+
/\[tsParticles]\(https:\/\/github.com\/matteobruni\/tsparticles\) additional template plugin\./g,
|
|
114
|
+
replacedMiniDescriptionText = replacedFunctionNameText.replace(
|
|
115
|
+
readmeMiniDescriptionRegex,
|
|
116
|
+
`[tsParticles](https://github.com/matteobruni/tsparticles) additional ${name} plugin.`
|
|
117
|
+
),
|
|
118
|
+
readmeUsageRegex = /plugin\.type: "template"/g,
|
|
119
|
+
replacedUsageText = replacedMiniDescriptionText.replace(readmeUsageRegex, `plugin.type: "${camelizedName}`),
|
|
120
|
+
sampleImageRegex =
|
|
121
|
+
/!\[demo]\(https:\/\/raw.githubusercontent.com\/tsparticles\/plugin-template\/main\/images\/sample.png\)/g,
|
|
122
|
+
repoPath = repoUrl.includes("github.com")
|
|
123
|
+
? repoUrl.substring(repoUrl.indexOf("github.com/") + 11, repoUrl.indexOf(".git"))
|
|
124
|
+
: "tsparticles/plugin-template",
|
|
125
|
+
replacedText = replacedUsageText.replace(
|
|
126
|
+
sampleImageRegex,
|
|
127
|
+
``
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
await fs.writeFile(readmePath, replacedText);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Updates the plugin webpack file
|
|
135
|
+
* @param destPath - The path where the project is located
|
|
136
|
+
* @param name - The name of the project
|
|
137
|
+
* @param description - The description of the project
|
|
138
|
+
*/
|
|
139
|
+
async function updatePluginWebpackFile(destPath: string, name: string, description: string): Promise<void> {
|
|
140
|
+
await updateWebpackFile(
|
|
141
|
+
destPath,
|
|
142
|
+
camelize(capitalize(capitalize(name, "-"), " ")),
|
|
143
|
+
`tsParticles ${description} Plugin`,
|
|
144
|
+
"loadParticlesPlugin"
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Creates the plugin project
|
|
150
|
+
* @param name - The name of the project
|
|
151
|
+
* @param description - The description of the project
|
|
152
|
+
* @param repoUrl - The repository url
|
|
153
|
+
* @param destPath - The path where the project is located
|
|
154
|
+
*/
|
|
155
|
+
export async function createPluginTemplate(
|
|
156
|
+
name: string,
|
|
157
|
+
description: string,
|
|
158
|
+
repoUrl: string,
|
|
159
|
+
destPath: string
|
|
160
|
+
): Promise<void> {
|
|
161
|
+
const sourcePath = path.resolve(__dirname, "..", "..", "..", "files", "create-plugin");
|
|
162
|
+
|
|
163
|
+
await copyEmptyTemplateFiles(destPath);
|
|
164
|
+
|
|
165
|
+
await fs.copy(sourcePath, destPath, {
|
|
166
|
+
overwrite: true,
|
|
167
|
+
filter: copyFilter,
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
await updateIndexFile(destPath, name);
|
|
171
|
+
await updatePluginPackageFile(destPath, name, description, repoUrl);
|
|
172
|
+
await updatePluginPackageDistFile(destPath, name, description, repoUrl);
|
|
173
|
+
await updateReadmeFile(destPath, name, description, repoUrl);
|
|
174
|
+
await updatePluginWebpackFile(destPath, name, description);
|
|
175
|
+
|
|
176
|
+
runInstall(destPath);
|
|
177
|
+
runBuild(destPath);
|
|
178
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import prompts, { type PromptObject } from "prompts";
|
|
2
|
+
import { Command } from "commander";
|
|
3
|
+
import { capitalize } from "../../utils/string-utils";
|
|
4
|
+
import { createPluginTemplate } from "./create-plugin";
|
|
5
|
+
import { execSync } from "child_process";
|
|
6
|
+
import fs from "fs-extra";
|
|
7
|
+
import path from "path";
|
|
8
|
+
|
|
9
|
+
const pluginCommand = new Command("plugin");
|
|
10
|
+
|
|
11
|
+
pluginCommand.description("Create a new tsParticles plugin");
|
|
12
|
+
pluginCommand.argument("<destination>", "Destination folder");
|
|
13
|
+
pluginCommand.action(async (destination: string) => {
|
|
14
|
+
let repoUrl: string;
|
|
15
|
+
|
|
16
|
+
const destPath = path.resolve(path.join(process.cwd(), destination)),
|
|
17
|
+
destExists = await fs.pathExists(destPath);
|
|
18
|
+
|
|
19
|
+
if (destExists) {
|
|
20
|
+
const destContents = await fs.readdir(destPath),
|
|
21
|
+
destContentsNoGit = destContents.filter(t => t !== ".git" && t !== ".gitignore");
|
|
22
|
+
|
|
23
|
+
if (destContentsNoGit.length) {
|
|
24
|
+
throw new Error("Destination folder already exists and is not empty");
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
await fs.ensureDir(destPath);
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
repoUrl = execSync("git config --get remote.origin.url").toString();
|
|
32
|
+
} catch {
|
|
33
|
+
repoUrl = "";
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const initialName = destPath.split(path.sep).pop(),
|
|
37
|
+
questions: PromptObject[] = [
|
|
38
|
+
{
|
|
39
|
+
type: "text",
|
|
40
|
+
name: "name",
|
|
41
|
+
message: "What is the name of the plugin?",
|
|
42
|
+
validate: (value: string) => (value ? true : "The name can't be empty"),
|
|
43
|
+
initial: initialName,
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
type: "text",
|
|
47
|
+
name: "description",
|
|
48
|
+
message: "What is the description of the plugin?",
|
|
49
|
+
validate: (value: string) => (value ? true : "The description can't be empty"),
|
|
50
|
+
initial: capitalize(initialName || ""),
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
type: "text",
|
|
54
|
+
name: "repositoryUrl",
|
|
55
|
+
message: "What is the repository URL? (optional)",
|
|
56
|
+
initial: repoUrl.trim(),
|
|
57
|
+
},
|
|
58
|
+
];
|
|
59
|
+
|
|
60
|
+
const { name, description, repositoryUrl } = await prompts(questions);
|
|
61
|
+
|
|
62
|
+
createPluginTemplate(name.trim(), description.trim(), repositoryUrl.trim(), destPath);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
export { pluginCommand };
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { camelize, capitalize, dash } from "../../utils/string-utils";
|
|
2
|
+
import {
|
|
3
|
+
copyEmptyTemplateFiles,
|
|
4
|
+
copyFilter,
|
|
5
|
+
runBuild,
|
|
6
|
+
runInstall,
|
|
7
|
+
updatePackageDistFile,
|
|
8
|
+
updatePackageFile,
|
|
9
|
+
updateWebpackFile,
|
|
10
|
+
} from "../../utils/template-utils";
|
|
11
|
+
import fs from "fs-extra";
|
|
12
|
+
import path from "path";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Updates the index file with the correct function name
|
|
16
|
+
* @param destPath - The path where the project is located
|
|
17
|
+
* @param name - The name of the project
|
|
18
|
+
*/
|
|
19
|
+
async function updateIndexFile(destPath: string, name: string): Promise<void> {
|
|
20
|
+
const indexPath = path.resolve(destPath, "src", "index.ts"),
|
|
21
|
+
index = await fs.readFile(indexPath, "utf-8"),
|
|
22
|
+
capitalizedName = capitalize(capitalize(name, "-"), " "),
|
|
23
|
+
camelizedName = camelize(capitalizedName),
|
|
24
|
+
indexFunctionRegex = /loadTemplateShape/g,
|
|
25
|
+
replacedFuncText = index.replace(indexFunctionRegex, `load${capitalizedName}Shape`),
|
|
26
|
+
indexNameRegex = /"#template#"/g,
|
|
27
|
+
replacedNameText = replacedFuncText.replace(indexNameRegex, `"${camelizedName}"`);
|
|
28
|
+
|
|
29
|
+
await fs.writeFile(indexPath, replacedNameText);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Updates the shape package file
|
|
34
|
+
* @param destPath - The path where the project is located
|
|
35
|
+
* @param name - The name of the project
|
|
36
|
+
* @param description - The description of the project
|
|
37
|
+
* @param repoUrl - The repository url
|
|
38
|
+
*/
|
|
39
|
+
async function updateShapePackageFile(
|
|
40
|
+
destPath: string,
|
|
41
|
+
name: string,
|
|
42
|
+
description: string,
|
|
43
|
+
repoUrl: string
|
|
44
|
+
): Promise<void> {
|
|
45
|
+
const camelizedName = camelize(camelize(name, "-"), " "),
|
|
46
|
+
dashedName = dash(camelizedName);
|
|
47
|
+
|
|
48
|
+
updatePackageFile(
|
|
49
|
+
destPath,
|
|
50
|
+
`"tsparticles-shape-${dashedName}"`,
|
|
51
|
+
description,
|
|
52
|
+
`"tsparticles.shape.${camelizedName}.min.js"`,
|
|
53
|
+
repoUrl
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Updates the shape package dist file
|
|
59
|
+
* @param destPath - The path where the project is located
|
|
60
|
+
* @param name - The name of the project
|
|
61
|
+
* @param description - The description of the project
|
|
62
|
+
* @param repoUrl - The repository url
|
|
63
|
+
*/
|
|
64
|
+
async function updateShapePackageDistFile(
|
|
65
|
+
destPath: string,
|
|
66
|
+
name: string,
|
|
67
|
+
description: string,
|
|
68
|
+
repoUrl: string
|
|
69
|
+
): Promise<void> {
|
|
70
|
+
const camelizedName = camelize(camelize(name, "-"), " "),
|
|
71
|
+
dashedName = dash(camelizedName);
|
|
72
|
+
|
|
73
|
+
updatePackageDistFile(
|
|
74
|
+
destPath,
|
|
75
|
+
`"tsparticles-shape-${dashedName}"`,
|
|
76
|
+
description,
|
|
77
|
+
`"tsparticles.shape.${camelizedName}.min.js"`,
|
|
78
|
+
repoUrl
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Updates the shape readme file
|
|
84
|
+
* @param destPath - The path where the project is located
|
|
85
|
+
* @param name - The name of the project
|
|
86
|
+
* @param description - The description of the project
|
|
87
|
+
* @param repoUrl - The repository url
|
|
88
|
+
*/
|
|
89
|
+
async function updateReadmeFile(destPath: string, name: string, description: string, repoUrl: string): Promise<void> {
|
|
90
|
+
const readmePath = path.resolve(destPath, "README.md"),
|
|
91
|
+
readme = await fs.readFile(readmePath, "utf-8"),
|
|
92
|
+
capitalizedName = capitalize(capitalize(name, "-"), " "),
|
|
93
|
+
camelizedName = camelize(capitalizedName),
|
|
94
|
+
dashedName = dash(camelizedName),
|
|
95
|
+
readmeDescriptionRegex = /tsParticles Template Shape/g,
|
|
96
|
+
replacedDescriptionText = readme.replace(readmeDescriptionRegex, `tsParticles ${description} Shape`),
|
|
97
|
+
readmePackageNameRegex = /tsparticles-shape-template/g,
|
|
98
|
+
replacedPackageNameText = replacedDescriptionText.replace(
|
|
99
|
+
readmePackageNameRegex,
|
|
100
|
+
`tsparticles-shape-${dashedName}`
|
|
101
|
+
),
|
|
102
|
+
readmeFileNameRegex = /tsparticles\.shape\.template(\.bundle)?\.min\.js/g,
|
|
103
|
+
replacedFileNameText = replacedPackageNameText.replace(
|
|
104
|
+
readmeFileNameRegex,
|
|
105
|
+
`tsparticles.shape.${camelizedName}$1.min.js`
|
|
106
|
+
),
|
|
107
|
+
readmeFunctionNameRegex = /loadTemplateShape/g,
|
|
108
|
+
replacedFunctionNameText = replacedFileNameText.replace(readmeFunctionNameRegex, `load${capitalizedName}Shape`),
|
|
109
|
+
readmeMiniDescriptionRegex =
|
|
110
|
+
/\[tsParticles]\(https:\/\/github.com\/matteobruni\/tsparticles\) additional template shape\./g,
|
|
111
|
+
replacedMiniDescriptionText = replacedFunctionNameText.replace(
|
|
112
|
+
readmeMiniDescriptionRegex,
|
|
113
|
+
`[tsParticles](https://github.com/matteobruni/tsparticles) additional ${name} shape.`
|
|
114
|
+
),
|
|
115
|
+
readmeUsageRegex = /shape\.type: "template"/g,
|
|
116
|
+
replacedUsageText = replacedMiniDescriptionText.replace(readmeUsageRegex, `shape.type: "${camelizedName}`),
|
|
117
|
+
sampleImageRegex =
|
|
118
|
+
/!\[demo]\(https:\/\/raw.githubusercontent.com\/tsparticles\/shape-template\/main\/images\/sample.png\)/g,
|
|
119
|
+
repoPath = repoUrl.includes("github.com")
|
|
120
|
+
? repoUrl.substring(repoUrl.indexOf("github.com/") + 11, repoUrl.indexOf(".git"))
|
|
121
|
+
: "tsparticles/shape-template",
|
|
122
|
+
replacedText = replacedUsageText.replace(
|
|
123
|
+
sampleImageRegex,
|
|
124
|
+
``
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
await fs.writeFile(readmePath, replacedText);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Updates the shape webpack file
|
|
132
|
+
* @param destPath - The path where the project is located
|
|
133
|
+
* @param name - The name of the project
|
|
134
|
+
* @param description - The description of the project
|
|
135
|
+
*/
|
|
136
|
+
async function updateShapeWebpackFile(destPath: string, name: string, description: string): Promise<void> {
|
|
137
|
+
await updateWebpackFile(
|
|
138
|
+
destPath,
|
|
139
|
+
camelize(capitalize(capitalize(name, "-"), " ")),
|
|
140
|
+
`tsParticles ${description} Shape`,
|
|
141
|
+
"loadParticlesShape"
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Creates the shape project
|
|
147
|
+
* @param name - The name of the project
|
|
148
|
+
* @param description - The description of the project
|
|
149
|
+
* @param repoUrl - The repository url
|
|
150
|
+
* @param destPath - The path where the project is located
|
|
151
|
+
*/
|
|
152
|
+
export async function createShapeTemplate(
|
|
153
|
+
name: string,
|
|
154
|
+
description: string,
|
|
155
|
+
repoUrl: string,
|
|
156
|
+
destPath: string
|
|
157
|
+
): Promise<void> {
|
|
158
|
+
const sourcePath = path.resolve(__dirname, "..", "..", "..", "files", "create-shape");
|
|
159
|
+
|
|
160
|
+
await copyEmptyTemplateFiles(destPath);
|
|
161
|
+
|
|
162
|
+
await fs.copy(sourcePath, destPath, {
|
|
163
|
+
overwrite: true,
|
|
164
|
+
filter: copyFilter,
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
await updateIndexFile(destPath, name);
|
|
168
|
+
await updateShapePackageFile(destPath, name, description, repoUrl);
|
|
169
|
+
await updateShapePackageDistFile(destPath, name, description, repoUrl);
|
|
170
|
+
await updateReadmeFile(destPath, name, description, repoUrl);
|
|
171
|
+
await updateShapeWebpackFile(destPath, name, description);
|
|
172
|
+
|
|
173
|
+
runInstall(destPath);
|
|
174
|
+
runBuild(destPath);
|
|
175
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import prompts, { type PromptObject } from "prompts";
|
|
2
|
+
import { Command } from "commander";
|
|
3
|
+
import { capitalize } from "../../utils/string-utils";
|
|
4
|
+
import { createShapeTemplate } from "./create-shape";
|
|
5
|
+
import { execSync } from "child_process";
|
|
6
|
+
import fs from "fs-extra";
|
|
7
|
+
import path from "path";
|
|
8
|
+
|
|
9
|
+
const shapeCommand = new Command("shape");
|
|
10
|
+
|
|
11
|
+
shapeCommand.description("Create a new tsParticles shape");
|
|
12
|
+
shapeCommand.argument("<destination>", "Destination folder");
|
|
13
|
+
shapeCommand.action(async (destination: string) => {
|
|
14
|
+
let repoUrl: string;
|
|
15
|
+
|
|
16
|
+
const destPath = path.resolve(path.join(process.cwd(), destination)),
|
|
17
|
+
destExists = await fs.pathExists(destPath);
|
|
18
|
+
|
|
19
|
+
if (destExists) {
|
|
20
|
+
const destContents = await fs.readdir(destPath),
|
|
21
|
+
destContentsNoGit = destContents.filter(t => t !== ".git" && t !== ".gitignore");
|
|
22
|
+
|
|
23
|
+
if (destContentsNoGit.length) {
|
|
24
|
+
throw new Error("Destination folder already exists and is not empty");
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
await fs.ensureDir(destPath);
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
repoUrl = execSync("git config --get remote.origin.url").toString();
|
|
32
|
+
} catch {
|
|
33
|
+
repoUrl = "";
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const initialName = destPath.split(path.sep).pop(),
|
|
37
|
+
questions: PromptObject[] = [
|
|
38
|
+
{
|
|
39
|
+
type: "text",
|
|
40
|
+
name: "name",
|
|
41
|
+
message: "What is the name of the shape?",
|
|
42
|
+
validate: (value: string) => (value ? true : "The name can't be empty"),
|
|
43
|
+
initial: initialName,
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
type: "text",
|
|
47
|
+
name: "description",
|
|
48
|
+
message: "What is the description of the shape?",
|
|
49
|
+
validate: (value: string) => (value ? true : "The description can't be empty"),
|
|
50
|
+
initial: capitalize(initialName || ""),
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
type: "text",
|
|
54
|
+
name: "repositoryUrl",
|
|
55
|
+
message: "What is the repository URL? (optional)",
|
|
56
|
+
initial: repoUrl.trim(),
|
|
57
|
+
},
|
|
58
|
+
];
|
|
59
|
+
|
|
60
|
+
const { name, description, repositoryUrl } = await prompts(questions);
|
|
61
|
+
|
|
62
|
+
createShapeTemplate(name.trim(), description.trim(), repositoryUrl.trim(), destPath);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
export { shapeCommand };
|