-
-
Notifications
You must be signed in to change notification settings - Fork 138
/
glee.ts
245 lines (216 loc) · 8.18 KB
/
glee.ts
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
import { promises as fPromises } from 'fs';
import Command from '../../core/base';
import path, { resolve, join } from 'path';
import fs from 'fs-extra';
import { Specification, load } from '../../core/models/SpecificationFile';
import yaml from 'js-yaml';
import { prompt } from 'inquirer';
// eslint-disable-next-line
// @ts-ignore
import Generator from '@asyncapi/generator';
import { cyan, gray } from 'picocolors';
import { gleeFlags } from '../../core/flags/new/glee.flags';
export const successMessage = (projectName: string) =>
`🎉 Your Glee project has been successfully created!
⏩ Next steps: follow the instructions ${cyan('below')} to manage your project:
cd ${projectName}\t\t ${gray('# Navigate to the project directory')}
npm install\t\t ${gray('# Install the project dependencies')}
npm run dev\t\t ${gray('# Start the project in development mode')}
You can also open the project in your favourite editor and start tweaking it.
`;
const errorMessages = {
alreadyExists: (projectName: string) =>
`Unable to create the project because the directory "${cyan(projectName)}" already exists at "${process.cwd()}/${projectName}".
To specify a different name for the new project, please run the command below with a unique project name:
${gray('asyncapi new glee --name ') + gray(projectName) + gray('-1')}`,
};
export default class NewGlee extends Command {
static description = 'Creates a new Glee project';
protected commandName = 'glee';
static readonly successMessage = successMessage;
static readonly errorMessages = errorMessages;
static flags = gleeFlags();
async getFilteredServers(serversObject: any) {
console.log({ serversObject });
const servers = Object.keys(serversObject);
const localServers = await prompt([
{
name: 'LOCAL_SERVERS',
message:
'Select all of the servers that you want glee to set up and run a server for (local servers):',
type: 'checkbox',
choices() {
return servers;
},
},
]);
return servers.filter(
(server) => !localServers.LOCAL_SERVERS.includes(server)
);
}
async createTemporaryFile(
asyncapiInput: Specification,
filteredRemoteServers: string[],
file: any
) {
const asyncapiObject = asyncapiInput.toJson();
asyncapiObject['x-remoteServers'] = filteredRemoteServers;
delete asyncapiObject.filePath;
delete asyncapiObject.kind;
const updatedAsyncApiContent = yaml.dump(asyncapiObject, {
lineWidth: -1,
});
const currentFileDirectory = path.join(__dirname, file);
fs.writeFileSync(currentFileDirectory, updatedAsyncApiContent);
return { currentFileDirectory, updatedAsyncApiContent };
}
async validateFile(file: any, projectName: any, PROJECT_DIRECTORY: any) {
try {
const validExtensions = ['.yaml', '.yml', '.json'];
const fileExtension = path.extname(file);
if (!validExtensions.includes(fileExtension)) {
throw new Error(
'CLI Support only yml, yaml, and json extension for file'
);
}
if (
fs.existsSync(PROJECT_DIRECTORY) &&
fs.readdirSync(PROJECT_DIRECTORY).length > 0
) {
throw new Error(errorMessages.alreadyExists(projectName));
}
} catch (error: any) {
this.log(error.message);
}
}
async handleGenerateProjectWithFile(
file: any,
CURRENT_GLEE_TEMPLATE: any,
projectName: string,
forceWrite: boolean
) {
const PROJECT_DIRECTORY = path.join(process.cwd(), projectName);
await this.validateFile(file, projectName, PROJECT_DIRECTORY);
try {
console.log(file);
const asyncapiInput = (await load(file)) || (await load());
console.log(asyncapiInput);
const serversObject = asyncapiInput.toJson()?.servers;
let filteredRemoteServers: any[] = [];
if (serversObject) {
filteredRemoteServers = await this.getFilteredServers(serversObject);
}
const temporaryFileDirectory = 'asyncapi.yaml';
const { currentFileDirectory, updatedAsyncApiContent } =
await this.createTemporaryFile(
asyncapiInput,
filteredRemoteServers,
temporaryFileDirectory
);
const generator = new Generator(
CURRENT_GLEE_TEMPLATE,
PROJECT_DIRECTORY,
{ forceWrite }
);
await generator.generateFromString(updatedAsyncApiContent);
fs.unlinkSync(currentFileDirectory);
this.log(
`Success! Created ${projectName} at ${PROJECT_DIRECTORY}\n\nNext steps:\n\n cd ${projectName}\n npm install --ignore-scripts\n\nImplement the function in functions and auth folder and run the project with:\n npm run dev`
);
} catch (err: any) {
switch (err.code) {
case 'EACCES':
this.error(
`Unable to create the project. We tried to access the "${PROJECT_DIRECTORY}" directory but it was not possible due to file access permissions. Please check the write permissions of your current working directory ("${process.cwd()}").`
);
break;
case 'EPERM':
this.error(
`Unable to create the project. We tried to create the "${PROJECT_DIRECTORY}" directory but the operation requires elevated privileges. Please check the privileges for your current user.`
);
break;
default:
this.error(
`Unable to create the project. Please check the following message for further info about the error:\n\n${err}`
);
}
}
}
async run() {
const { flags } = await this.parse(NewGlee); // NOSONAR
const {
name: projectName,
template: templateName,
file,
'force-write': forceWrite,
} = flags;
const PROJECT_DIRECTORY = join(process.cwd(), projectName);
const GLEE_TEMPLATES_DIRECTORY = resolve(
__dirname,
'../../../assets/create-glee-app/templates/',
templateName
);
const CURRENT_GLEE_TEMPLATE =
'https://github.com/KhudaDad414/glee-generator-template';
if (file && templateName && templateName !== 'default') {
this.error('You cannot use both --t and --f in the same command.');
}
if (file) {
console.log('file running');
await this.handleGenerateProjectWithFile(
file,
CURRENT_GLEE_TEMPLATE,
projectName,
forceWrite
);
this.specFile = await load(flags.file);
this.metricsMetadata.template = flags.template;
} else {
try {
await fPromises.mkdir(PROJECT_DIRECTORY);
} catch (err: any) {
switch (err.code) {
case 'EEXIST':
this.error(errorMessages.alreadyExists(projectName));
break;
case 'EACCES':
this.error(
`Unable to create the project. We tried to access the "${PROJECT_DIRECTORY}" directory but it was not possible due to file access permissions. Please check the write permissions of your current working directory ("${process.cwd()}").`
);
break;
case 'EPERM':
this.error(
`Unable to create the project. We tried to create the "${PROJECT_DIRECTORY}" directory but the operation requires elevated privileges. Please check the privileges for your current user.`
);
break;
default:
this.error(
`Unable to create the project. Please check the following message for further info about the error:\n\n${err}`
);
}
}
try {
await fs.copy(GLEE_TEMPLATES_DIRECTORY, PROJECT_DIRECTORY);
await fPromises.rename(
`${PROJECT_DIRECTORY}/env`,
`${PROJECT_DIRECTORY}/.env`
);
await fPromises.rename(
`${PROJECT_DIRECTORY}/gitignore`,
`${PROJECT_DIRECTORY}/.gitignore`
);
await fPromises.rename(
`${PROJECT_DIRECTORY}/README-template.md`,
`${PROJECT_DIRECTORY}/README.md`
);
this.log(successMessage(projectName));
} catch (err) {
this.error(
`Unable to create the project. Please check the following message for further info about the error:\n\n${err}`
);
}
this.specFile = await load(`${GLEE_TEMPLATES_DIRECTORY}/asyncapi.yaml`);
this.metricsMetadata.template = flags.template;
}
}
}