forked from Gandi-IDE/gandi-plugins
-
Notifications
You must be signed in to change notification settings - Fork 0
/
plopfile.js
248 lines (229 loc) · 7.6 KB
/
plopfile.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
const fs = require("fs");
const path = require("path");
/**
* Inserts content before the last line of a file.
* @param {string} filePath - The path of the file to insert content into.
* @param {string} contentToInsert - The content to insert.
* @param {number} line
* @returns {void}
*/
function insertContent(filePath, contentToInsert, line) {
try {
// Read the content of the file
let data = fs.readFileSync(filePath, "utf8").toString().split("\n");
const insertIndex = typeof line === "number" ? line : data.length - 2;
data.splice(insertIndex, 0, contentToInsert);
// Write the modified content back to the file
fs.writeFileSync(filePath, data.join("\n"));
} catch (err) {
console.error(err);
}
}
function validateSpinalCaseInput(input) {
const regex = /^([a-z]+(?:-[a-z]+)*)+$/;
return regex.test(input);
}
function spinalToPascal(spinalCaseString) {
// Split the string by hyphens to get an array of words
const words = spinalCaseString.split("-");
// Capitalize the first letter of each word and join them together
const pascalCaseString = words
.map((word) => {
// Capitalize the first letter of each word
return word.charAt(0).toUpperCase() + word.slice(1);
})
.join("");
return pascalCaseString;
}
function spinalToTitleCase(spinalCaseString) {
// Split the string by hyphens to get an array of words
const words = spinalCaseString.split("-");
// Capitalize the first letter of each word and join them together with a space
const titleCaseString = words
.map((word) => {
// Capitalize the first letter of each word and lowercase the rest
return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
})
.join(" ");
return titleCaseString;
}
function hyphenToCamelCase(str) {
return str.replace(/-([a-z])/g, function (match, letter) {
return letter.toUpperCase();
});
}
/**
* Extracts names and links from a string and returns an array of objects.
* @param {string} inputString - The input string containing names and links.
* @returns {Array<{name: string}>} An array of objects containing extracted names and links.
*/
function extractLinks(inputString) {
// Define regular expression pattern to match names and links
var pattern = /(\w+)(?:\((https?:\/\/\S+)?\))?/g;
// Find all matches using regular expression
var matches = inputString.matchAll(pattern);
var result = [];
// Iterate over matches and store names and links as objects in an array
for (var match of matches) {
var name = match[1];
var link = match[2] || null; // Set link to null if it doesn't exist
result.push({
name: name,
link: link,
});
}
return result;
}
const PluginTypeMap = {
"React Component(TS)": "react-ts",
"React Component(JS)": "react-js",
"Function(TS)": "ts",
"Function(JS)": "js",
};
/**
* Plop generator for creating an plugin.
* @param {object} plop - The plop instance.
*/
module.exports = function (plop) {
plop.setGenerator("createPlugin", {
description: "Creating a Plugin",
prompts: [
{
type: "input",
name: "name",
message: "Please enter an plugin name(aaa-bbb): ",
validate: (input) => {
if (!validateSpinalCaseInput(input)) {
return "The name does not meet (aaa-bbb) convention.";
}
const contents = fs.readdirSync("./src/plugins");
const subFolders = contents.filter((item) => {
const itemPath = path.join("./src/plugins", item);
return fs.statSync(itemPath).isDirectory();
});
if (subFolders.includes(input)) {
return "Name check failed due to duplication.";
}
return true;
},
},
{
type: "list",
name: "pluginType",
message: "Please select the implementation method of the plugin: ",
choices: Object.keys(PluginTypeMap),
default: "React Component(TS)",
},
{
type: "input",
name: "description",
message: "Please enter an plugin description: ",
},
{
type: "input",
name: "authors",
message: "Please enter the author's name of the plugin: ",
},
],
actions: function (data) {
const { name, pluginType, description, authors } = data;
const titleName = spinalToTitleCase(name);
const componentName = spinalToPascal(name);
const authorList = extractLinks(authors);
let credits = "";
authorList.forEach((author, index) => {
if (author.link) {
if (index < authorList.length - 1) {
credits += `{
name: "${author.name}",
link: "${author.link}",
},
`;
} else {
credits += `{
name: "${author.name}",
link: "${author.link}",
},`;
}
} else {
if (index < authorList.length - 1) {
credits += `{
name: "${author.name}",
},
`;
} else {
credits += `{
name: "${author.name}",
},`;
}
}
});
const nameKey = name.split("-").length > 1 ? `"${name}"` : name;
try {
const data = fs.readFileSync("./src/plugins/plugins-manager/index.tsx", "utf8");
const lines = data.split("\n");
const lineNumber = lines.findIndex((line) => line.includes("const DEFAULT_INJECT_PLUGINS = ["));
if (lineNumber !== -1) {
insertContent("./src/plugins/plugins-manager/index.tsx", ` "${name}",`, lineNumber + 1);
} else {
console.log("Search string not found in the file: plugins-manager/index.tsx");
}
} catch (err) {
console.error("Error reading file:", err);
}
// Update the entry file.
insertContent(
"./src/plugins-entry.ts",
` ${nameKey}: () => import(/* webpackChunkName: "plugin-${name}" */ "src/plugins/${name}"),`,
);
// Update the manifest.
const pluginsManifestFilePath = "./src/plugins-manifest.ts";
const fileContent = fs.readFileSync(pluginsManifestFilePath, "utf8");
const match = fileContent.match(/export\s+default\s+\{/);
let nextPluginLine = 0;
if (match) {
nextPluginLine = fileContent.substr(0, match.index).split("\n").length - 2;
}
const moduleName = hyphenToCamelCase(name);
insertContent(
pluginsManifestFilePath,
`import ${moduleName} from "src/plugins/${name}/manifest";`,
nextPluginLine,
);
insertContent(pluginsManifestFilePath, ` ${nameKey}: ${moduleName},`);
const actions = [];
if (name) {
actions.push(
{
type: "add",
path: `./src/plugins/${name}/manifest.ts`,
templateFile: "./plugin-template/plugin-manifest.hbs",
data: {
name: titleName,
type: pluginType.startsWith("Function") ? "function" : "component",
description,
credits,
},
transform: (templateContent) => {
return templateContent.replace(/"/g, '"');
},
},
{
type: "add",
path: `./src/plugins/${name}/index.${pluginType.endsWith("(JS)") ? "js" : "ts"}${pluginType.startsWith("React Component") ? "x" : ""}`,
templateFile: `./plugin-template/plugin-index-${PluginTypeMap[pluginType]}.hbs`,
data: {
componentName,
},
},
{
type: "add",
path: `./src/plugins/${name}/styles.less`,
templateFile: "./plugin-template/styles.hbs",
},
);
}
return actions;
},
});
};