@citruslime/create-boilerplate 0.1.2 → 1.0.0-beta.11
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/README.md +13 -18
- package/main.mjs +373 -0
- package/package.json +11 -13
- package/boilerplate-app/.vscode/boilerplate-app.code-workspace +0 -67
- package/boilerplate-app/.vscode/extensions.json +0 -14
- package/boilerplate-app/.vscode/settings.json +0 -41
- package/boilerplate-app/_editorconfig +0 -10
- package/boilerplate-app/_eslintignore +0 -3
- package/boilerplate-app/_eslintrc.js +0 -4
- package/boilerplate-app/_gitignore +0 -5
- package/boilerplate-app/_lintstagedrc.json +0 -8
- package/boilerplate-app/_stylelintignore +0 -2
- package/boilerplate-app/_stylelintrc.js +0 -3
- package/boilerplate-app/index.html +0 -13
- package/boilerplate-app/package.json +0 -55
- package/boilerplate-app/postcss.config.js +0 -8
- package/boilerplate-app/public/favicon.ico +0 -0
- package/boilerplate-app/public/site.webmanifest +0 -8
- package/boilerplate-app/public/web.config +0 -7
- package/boilerplate-app/src/app.css +0 -9
- package/boilerplate-app/src/app.ts +0 -5
- package/boilerplate-app/src/app.vue +0 -7
- package/boilerplate-app/src/main.ts +0 -23
- package/boilerplate-app/src/router/index.ts +0 -18
- package/boilerplate-app/src/shims-vue.d.ts +0 -7
- package/boilerplate-app/src/state/index.ts +0 -1
- package/boilerplate-app/src/state/utils/index.ts +0 -1
- package/boilerplate-app/src/views/dashboard/index.ts +0 -5
- package/boilerplate-app/src/views/dashboard/index.vue +0 -11
- package/boilerplate-app/src/vite-env.d.ts +0 -2
- package/boilerplate-app/tailwind.config.js +0 -16
- package/boilerplate-app/tsconfig.json +0 -29
- package/boilerplate-app/vite.config.ts +0 -50
- package/index.js +0 -250
package/README.md
CHANGED
|
@@ -1,30 +1,25 @@
|
|
|
1
|
-
# Citrus-Lime UI Library Boilerplate
|
|
1
|
+
# Citrus-Lime UI Library Create Boilerplate Script
|
|
2
|
+
|
|
3
|
+
A create package for initialising Citrus-Lime web apps.
|
|
2
4
|
|
|
3
5
|

|
|
4
6
|

|
|
5
|
-

|
|
6
7
|
|
|
7
8
|
- ⚡ [NPM Package](https://www.npmjs.com/package/@citruslime/create-boilerplate)
|
|
8
9
|
- 📖 [Documentation & API](https://uilibrary.citruslime.com)
|
|
9
10
|
- 📌 [Citrus-Lime Ltd](https://www.citruslime.com)
|
|
10
11
|
|
|
11
|
-
## Running the script
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
`npm init @citruslime/boilerplate TargetDirectory`
|
|
14
|
+
|
|
15
|
+
or
|
|
16
|
+
|
|
17
|
+
`yarn create @citruslime/boilerplate TargetDirectory`
|
|
14
18
|
|
|
15
|
-
|
|
16
|
-
|
|
19
|
+
- **TargetDirectory**
|
|
20
|
+
- A relative folder path for the script to create the boilerplate app
|
|
21
|
+
- *Optional* - will be prompted for, if not provided
|
|
17
22
|
|
|
18
|
-
|
|
19
|
-
- _A relative folder path for the script to create the boilerplate app_
|
|
20
|
-
- **PackageName**
|
|
21
|
-
- _Using a lower-kebab-cased naming convention_
|
|
22
|
-
- **FrontEndPortNumber**
|
|
23
|
-
- _The port in which the vite app will run_
|
|
24
|
-
- **BackendPortNumber**
|
|
25
|
-
- _The port in which the API project which drives the front-end api will run_
|
|
26
|
-
- **AutoRun**
|
|
27
|
-
- `true|false` _Run the app immediately after creating it_
|
|
23
|
+
e.g.
|
|
28
24
|
|
|
29
|
-
|
|
30
|
-
```yarn create @citruslime/boilerplate ./ui/customer app-customer-ui 3001 44531 true```
|
|
25
|
+
`yarn create @citruslime/boilerplate ./ui/customer`
|
package/main.mjs
ADDED
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { execSync } from 'child_process';
|
|
4
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, rmSync, statSync, writeFileSync } from 'fs';
|
|
5
|
+
import { dirname, join } from 'path';
|
|
6
|
+
import { fileURLToPath } from 'url';
|
|
7
|
+
|
|
8
|
+
import { lightBlue, green, red } from 'kolorist';
|
|
9
|
+
import parseArgs from 'minimist';
|
|
10
|
+
import prompts from 'prompts';
|
|
11
|
+
|
|
12
|
+
const argv = parseArgs(process.argv.slice(2));
|
|
13
|
+
const cwd = process.cwd();
|
|
14
|
+
|
|
15
|
+
const placeholdersToReplace = {
|
|
16
|
+
/* eslint-disable @typescript-eslint/naming-convention */
|
|
17
|
+
'[[PACKAGE_NAME]]': '',
|
|
18
|
+
'[[REPOSITORY_ROOT]]': '',
|
|
19
|
+
'[[BACKEND_PORT]]': 0,
|
|
20
|
+
'[[FRONTEND_PORT]]': 0,
|
|
21
|
+
'/* eslint-disable array-bracket-spacing */': '',
|
|
22
|
+
'/* eslint-enable array-bracket-spacing */': ''
|
|
23
|
+
/* eslint-enable @typescript-eslint/naming-convention */
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const filesToRename = {
|
|
27
|
+
/* eslint-disable @typescript-eslint/naming-convention */
|
|
28
|
+
_gitignore: '.gitignore',
|
|
29
|
+
_editorconfig: '.editorconfig',
|
|
30
|
+
_eslintignore: '.eslintignore',
|
|
31
|
+
'_eslintrc.js': '.eslintrc.js',
|
|
32
|
+
'_lintstagedrc.json': '.lintstagedrc.json',
|
|
33
|
+
_stylelintignore: '.stylelintignore',
|
|
34
|
+
'_stylelintrc.js': '.stylelintrc.js',
|
|
35
|
+
'template.code-workspace': 'citrus-lime.code-workspace'
|
|
36
|
+
/* eslint-enable @typescript-eslint/naming-convention */
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const dependenciesToInstall = [
|
|
40
|
+
{
|
|
41
|
+
name: '@citruslime/ui'
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
name: '@vueuse/core'
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
name: 'flatpickr'
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
name: 'pinia'
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
name: 'pinia-plugin-persistedstate'
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
name: 'vue',
|
|
57
|
+
next: true
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
name: 'vue-i18n',
|
|
61
|
+
next: true
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
name: 'vue-router',
|
|
65
|
+
next: true
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
name: '@citruslime/config',
|
|
69
|
+
dev: true
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
name: '@citruslime/theme',
|
|
73
|
+
dev: true
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
name: '@types/node',
|
|
77
|
+
dev: true
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
name: '@vitejs/plugin-vue',
|
|
81
|
+
dev: true
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
name: '@iconify/vue',
|
|
85
|
+
dev: true
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
name: '@vue/compiler-sfc',
|
|
89
|
+
dev: true
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
name: 'husky',
|
|
93
|
+
dev: true
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
name: 'lint-staged',
|
|
97
|
+
dev: true
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
name: 'typescript',
|
|
101
|
+
dev: true
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
name: 'unplugin-vue-components',
|
|
105
|
+
dev: true
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
name: 'vite',
|
|
109
|
+
dev: true
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
name: 'vite-plugin-mkcert',
|
|
113
|
+
dev: true
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
name: 'vite-plugin-pages',
|
|
117
|
+
dev: true
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
name: 'vue-tsc',
|
|
121
|
+
dev: true
|
|
122
|
+
}
|
|
123
|
+
];
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Initialise the new package.
|
|
127
|
+
*/
|
|
128
|
+
async function init () {
|
|
129
|
+
let packageDir = argv._[0];
|
|
130
|
+
|
|
131
|
+
const {
|
|
132
|
+
packageName,
|
|
133
|
+
empty,
|
|
134
|
+
packageManager,
|
|
135
|
+
rootDir,
|
|
136
|
+
frontendPort,
|
|
137
|
+
backendPort
|
|
138
|
+
} = await prompts([
|
|
139
|
+
{
|
|
140
|
+
type: 'text',
|
|
141
|
+
name: 'packageName',
|
|
142
|
+
message: 'Enter a package name:',
|
|
143
|
+
validate: (value) => /^(?:@[a-z0-9-*~][a-z0-9-*._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/.test(value)
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
type: packageDir ? null : 'text',
|
|
147
|
+
name: 'packageDir',
|
|
148
|
+
message: 'Enter a directory for the package:',
|
|
149
|
+
onState: (state) => packageDir = state.value
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
type: () => !existsSync(packageDir) || readdirSync(packageDir).length === 0 ? null : 'confirm',
|
|
153
|
+
name: 'empty',
|
|
154
|
+
message: () => `${packageDir === '.' ? 'Current directory' : `Target directory "${packageDir}"`} is not empty. Remove existing files and continue?`
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
type (_, { empty }) {
|
|
158
|
+
if (empty === false) {
|
|
159
|
+
cancel();
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return null;
|
|
163
|
+
},
|
|
164
|
+
name: 'emptyConfirmation'
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
type: 'select',
|
|
168
|
+
name: 'packageManager',
|
|
169
|
+
message: 'Select a package manager:',
|
|
170
|
+
choices: [
|
|
171
|
+
{
|
|
172
|
+
title: 'yarn',
|
|
173
|
+
value: 'yarn'
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
title: 'npm',
|
|
177
|
+
value: 'npm'
|
|
178
|
+
}
|
|
179
|
+
],
|
|
180
|
+
initial: 0
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
type: 'text',
|
|
184
|
+
name: 'rootDir',
|
|
185
|
+
message: 'Enter the relative path to the root of the repository:',
|
|
186
|
+
validate: (value) => value && value?.trim() !== ''
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
type: 'number',
|
|
190
|
+
name: 'frontendPort',
|
|
191
|
+
message: 'Enter the port for the dev server to run on:'
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
type: 'text',
|
|
195
|
+
name: 'backendPort',
|
|
196
|
+
message: 'Enter the port that the backend server runs on:'
|
|
197
|
+
}
|
|
198
|
+
], {
|
|
199
|
+
onCancel: () => cancel()
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
print(lightBlue('Initialising package...'), true);
|
|
203
|
+
|
|
204
|
+
setReplacements(packageName, rootDir, frontendPort, backendPort);
|
|
205
|
+
prepareDir(join(cwd, packageDir), empty);
|
|
206
|
+
copyTemplate(packageDir);
|
|
207
|
+
|
|
208
|
+
process.chdir(packageDir);
|
|
209
|
+
installDependencies(packageManager);
|
|
210
|
+
|
|
211
|
+
print(green(`Package ${packageName} has been successfully initialised in ${packageDir}.`), true);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Set the dynamic values for the file renaming and placeholder replacements.
|
|
216
|
+
*
|
|
217
|
+
* @param {string} packageName The name of the package being created.
|
|
218
|
+
* @param {string} rootDir The relative path of the root of the repository.
|
|
219
|
+
* @param {number} frontendPort The port that the frontend dev server will run on.
|
|
220
|
+
* @param {number} backendPort The port that the backend server runs on.
|
|
221
|
+
*/
|
|
222
|
+
function setReplacements (packageName, rootDir, frontendPort, backendPort) {
|
|
223
|
+
filesToRename['template.code-workspace'] = `${packageName}.code-workspace`;
|
|
224
|
+
|
|
225
|
+
placeholdersToReplace['[[PACKAGE_NAME]]'] = packageName;
|
|
226
|
+
placeholdersToReplace['[[REPOSITORY_ROOT]]'] = rootDir;
|
|
227
|
+
placeholdersToReplace['[[FRONTEND_PORT]]'] = frontendPort;
|
|
228
|
+
placeholdersToReplace['[[BACKEND_PORT]]'] = backendPort;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Prepares the directory for the new package to be created in.
|
|
233
|
+
*
|
|
234
|
+
* @param {string} path The path of the directory to be prepared.
|
|
235
|
+
* @param {boolean} empty If the current contents needs to be emptied.
|
|
236
|
+
*/
|
|
237
|
+
function prepareDir (path, empty) {
|
|
238
|
+
if (empty) {
|
|
239
|
+
const options = {
|
|
240
|
+
recursive: true,
|
|
241
|
+
force: true
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
print(lightBlue('Emptying directory...'), true);
|
|
245
|
+
|
|
246
|
+
forEachInDir(path, (item) => rmSync(join(path, item), options));
|
|
247
|
+
}
|
|
248
|
+
else if (!existsSync(path)) {
|
|
249
|
+
print(lightBlue('Creating directory...'), true);
|
|
250
|
+
|
|
251
|
+
mkdirSync(path);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Copies the template directory into the new package directory.
|
|
257
|
+
*
|
|
258
|
+
* @param {string} packageDir The directory of the new package.
|
|
259
|
+
*/
|
|
260
|
+
function copyTemplate (packageDir) {
|
|
261
|
+
const codeDir = fileURLToPath(dirname(import.meta.url));
|
|
262
|
+
const templateDir = join(codeDir, 'template');
|
|
263
|
+
|
|
264
|
+
forEachInDir(templateDir, (item) => copy(templateDir, packageDir, item));
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Copies a file or directory from one location to another.
|
|
269
|
+
*
|
|
270
|
+
* @param {string} source The path of the item to copy.
|
|
271
|
+
* @param {string} destination The path of the new item.
|
|
272
|
+
* @param {string} item The item to copy.
|
|
273
|
+
*/
|
|
274
|
+
function copy (source, destination, item) {
|
|
275
|
+
const sourceItem = join(source, item);
|
|
276
|
+
const info = statSync(sourceItem);
|
|
277
|
+
|
|
278
|
+
if (info.isDirectory()) {
|
|
279
|
+
const destinationDir = join(destination, item);
|
|
280
|
+
|
|
281
|
+
mkdirSync(destinationDir, { recursive: true });
|
|
282
|
+
|
|
283
|
+
forEachInDir(sourceItem, (item) => copy(sourceItem, destinationDir, item));
|
|
284
|
+
}
|
|
285
|
+
else {
|
|
286
|
+
const destinationFile = filesToRename[item] ? join(destination, filesToRename[item]) : join(destination, item);
|
|
287
|
+
const options = {
|
|
288
|
+
encoding: 'utf-8'
|
|
289
|
+
};
|
|
290
|
+
|
|
291
|
+
print(lightBlue(`Copying ${item}...`), true);
|
|
292
|
+
|
|
293
|
+
let contents = readFileSync(sourceItem, options);
|
|
294
|
+
|
|
295
|
+
for (const [
|
|
296
|
+
key,
|
|
297
|
+
value
|
|
298
|
+
] of Object.entries(placeholdersToReplace)) {
|
|
299
|
+
contents = contents.replace(key, value);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
writeFileSync(destinationFile, contents, options);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Installs the required dependencies for the template.
|
|
308
|
+
*
|
|
309
|
+
* @param {string} packageManager The package manager to use.
|
|
310
|
+
*/
|
|
311
|
+
function installDependencies (packageManager) {
|
|
312
|
+
const prefix = `${packageManager} ${packageManager === 'yarn' ? 'add' : 'install'}`;
|
|
313
|
+
|
|
314
|
+
print(lightBlue('Installing dev dependencies...'), true);
|
|
315
|
+
|
|
316
|
+
let devDependencies = '';
|
|
317
|
+
for (const dependency of dependenciesToInstall.filter(d => d.dev)) {
|
|
318
|
+
devDependencies += `${dependency.name}${dependency.next ? '@next' : '@latest'} `;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
print(lightBlue('Installing dependencies...'), true);
|
|
322
|
+
|
|
323
|
+
let dependencies = '';
|
|
324
|
+
for (const dependency of dependenciesToInstall.filter(d => !d.dev)) {
|
|
325
|
+
dependencies += `${dependency.name}${dependency.next ? '@next' : '@latest'} `;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
execSync(`${prefix} -D ${devDependencies}`);
|
|
329
|
+
execSync(`${prefix} ${dependencies}`);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Calls the callback for each item in a directory.
|
|
334
|
+
*
|
|
335
|
+
* @param {string} dir The directory to loop-through the contents of.
|
|
336
|
+
* @param {function(string): void} callback The callback to provide with each item.
|
|
337
|
+
*/
|
|
338
|
+
function forEachInDir (dir, callback) {
|
|
339
|
+
const items = readdirSync(dir);
|
|
340
|
+
|
|
341
|
+
for (const item of items) {
|
|
342
|
+
callback(item);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* Throws an error to indicate that the current operation has been cancelled.
|
|
348
|
+
*/
|
|
349
|
+
function cancel () {
|
|
350
|
+
throw new Error('Operation was cancelled.');
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* Prints a message to the console.
|
|
355
|
+
*
|
|
356
|
+
* @param {string} message The message to display.
|
|
357
|
+
* @param {boolean} clearPrevious Whether to clear the previous line before displaying the new one.
|
|
358
|
+
*/
|
|
359
|
+
function print (message, clearPrevious = false) {
|
|
360
|
+
if (clearPrevious) {
|
|
361
|
+
process.stdout.clearLine();
|
|
362
|
+
process.stdout.cursorTo(0);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
process.stdout.write(message);
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
try {
|
|
369
|
+
await init();
|
|
370
|
+
}
|
|
371
|
+
catch (e) {
|
|
372
|
+
print(red(e.message));
|
|
373
|
+
}
|
package/package.json
CHANGED
|
@@ -1,34 +1,32 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@citruslime/create-boilerplate",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0-beta.11",
|
|
4
4
|
"author": {
|
|
5
5
|
"name": "Citrus-Lime Ltd",
|
|
6
6
|
"url": "https://citruslime.com"
|
|
7
7
|
},
|
|
8
8
|
"license": "MIT",
|
|
9
9
|
"homepage": "https://uilibrary.citruslime.com/",
|
|
10
|
-
"repository": {
|
|
11
|
-
"url": "https://dev.azure.com/citruslime/FutureEcommerce/_git/CitrusLime.VueUiLibrary?version=GBrelease"
|
|
12
|
-
},
|
|
13
10
|
"publishConfig": {
|
|
14
11
|
"access": "public"
|
|
15
12
|
},
|
|
16
13
|
"files": [
|
|
17
|
-
"
|
|
18
|
-
"
|
|
14
|
+
"main.mjs",
|
|
15
|
+
"template-*"
|
|
19
16
|
],
|
|
20
|
-
"main": "
|
|
17
|
+
"main": "main.mjs",
|
|
21
18
|
"bin": {
|
|
22
|
-
"create-boilerplate": "
|
|
23
|
-
"cva": "index.js"
|
|
19
|
+
"create-boilerplate": "main.mjs"
|
|
24
20
|
},
|
|
25
21
|
"engines": {
|
|
26
|
-
"node": ">=
|
|
22
|
+
"node": ">=14.0.0"
|
|
27
23
|
},
|
|
28
24
|
"dependencies": {
|
|
29
|
-
"
|
|
30
|
-
"kolorist": "^1.5.0",
|
|
25
|
+
"kolorist": "^1.5.1",
|
|
31
26
|
"minimist": "^1.2.5",
|
|
32
|
-
"prompts": "^2.4.
|
|
27
|
+
"prompts": "^2.4.2"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@types/prompts": "^2.0.14"
|
|
33
31
|
}
|
|
34
32
|
}
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"folders": [
|
|
3
|
-
{
|
|
4
|
-
"name": "Root",
|
|
5
|
-
"path": ".."
|
|
6
|
-
},
|
|
7
|
-
{
|
|
8
|
-
"name": "Hooks",
|
|
9
|
-
"path": "../../.husky"
|
|
10
|
-
}
|
|
11
|
-
],
|
|
12
|
-
"settings": {
|
|
13
|
-
"[css]": {
|
|
14
|
-
"editor.insertSpaces": false
|
|
15
|
-
},
|
|
16
|
-
"css.validate": false,
|
|
17
|
-
"diffEditor.ignoreTrimWhitespace": false,
|
|
18
|
-
"editor.codeActionsOnSave": {
|
|
19
|
-
"source.organizeImports": false
|
|
20
|
-
},
|
|
21
|
-
"editor.defaultFormatter": "dbaeumer.vscode-eslint",
|
|
22
|
-
"editor.detectIndentation": false,
|
|
23
|
-
"editor.formatOnSave": true,
|
|
24
|
-
"editor.linkedEditing": true,
|
|
25
|
-
"eslint.alwaysShowStatus": true,
|
|
26
|
-
"eslint.validate": [
|
|
27
|
-
"html",
|
|
28
|
-
"javascript",
|
|
29
|
-
"typescript",
|
|
30
|
-
"vue"
|
|
31
|
-
],
|
|
32
|
-
"files.encoding": "utf8",
|
|
33
|
-
"files.eol": "\n",
|
|
34
|
-
"files.exclude": {
|
|
35
|
-
"node_modules": true
|
|
36
|
-
},
|
|
37
|
-
"files.trimTrailingWhitespace": true,
|
|
38
|
-
"git.autofetch": true,
|
|
39
|
-
"git.autofetchPeriod": 60,
|
|
40
|
-
"git.enableSmartCommit": true,
|
|
41
|
-
"git.pruneOnFetch": true,
|
|
42
|
-
"npm-intellisense.scanDevDependencies": true,
|
|
43
|
-
"npm-intellisense.showBuildInLibs": true,
|
|
44
|
-
"tailwindCSS.includeLanguages": {
|
|
45
|
-
"vue": "html"
|
|
46
|
-
},
|
|
47
|
-
"typescript.preferences.quoteStyle": "single",
|
|
48
|
-
"typescript.tsdk": "node_modules\\typescript\\lib",
|
|
49
|
-
"typescript.updateImportsOnFileMove.enabled": "always",
|
|
50
|
-
"volar.tsPlugin": true,
|
|
51
|
-
"volar.tsPluginStatus": false
|
|
52
|
-
},
|
|
53
|
-
"extensions": {
|
|
54
|
-
"recommendations": [
|
|
55
|
-
"johnsoncodehk.volar",
|
|
56
|
-
"dbaeumer.vscode-eslint",
|
|
57
|
-
"stylelint.vscode-stylelint",
|
|
58
|
-
"bradlc.vscode-tailwindcss",
|
|
59
|
-
"adrianwilczynski.csharp-to-typescript",
|
|
60
|
-
"eamodio.gitlens",
|
|
61
|
-
"ms-vsliveshare.vsliveshare",
|
|
62
|
-
"christian-kohler.npm-intellisense",
|
|
63
|
-
"kevinmcgowan.typescriptimport",
|
|
64
|
-
"editorconfig.editorconfig"
|
|
65
|
-
]
|
|
66
|
-
}
|
|
67
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"recommendations": [
|
|
3
|
-
"johnsoncodehk.volar",
|
|
4
|
-
"dbaeumer.vscode-eslint",
|
|
5
|
-
"stylelint.vscode-stylelint",
|
|
6
|
-
"bradlc.vscode-tailwindcss",
|
|
7
|
-
"adrianwilczynski.csharp-to-typescript",
|
|
8
|
-
"eamodio.gitlens",
|
|
9
|
-
"ms-vsliveshare.vsliveshare",
|
|
10
|
-
"christian-kohler.npm-intellisense",
|
|
11
|
-
"kevinmcgowan.typescriptimport",
|
|
12
|
-
"editorconfig.editorconfig"
|
|
13
|
-
]
|
|
14
|
-
}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"[css]": {
|
|
3
|
-
"editor.insertSpaces": false
|
|
4
|
-
},
|
|
5
|
-
"css.validate": false,
|
|
6
|
-
"diffEditor.ignoreTrimWhitespace": false,
|
|
7
|
-
"editor.codeActionsOnSave": {
|
|
8
|
-
"source.organizeImports": false
|
|
9
|
-
},
|
|
10
|
-
"editor.defaultFormatter": "dbaeumer.vscode-eslint",
|
|
11
|
-
"editor.detectIndentation": false,
|
|
12
|
-
"editor.formatOnSave": true,
|
|
13
|
-
"editor.linkedEditing": true,
|
|
14
|
-
"eslint.alwaysShowStatus": true,
|
|
15
|
-
"eslint.validate": [
|
|
16
|
-
"html",
|
|
17
|
-
"javascript",
|
|
18
|
-
"typescript",
|
|
19
|
-
"vue"
|
|
20
|
-
],
|
|
21
|
-
"files.encoding": "utf8",
|
|
22
|
-
"files.eol": "\n",
|
|
23
|
-
"files.exclude": {
|
|
24
|
-
"node_modules": true
|
|
25
|
-
},
|
|
26
|
-
"files.trimTrailingWhitespace": true,
|
|
27
|
-
"git.autofetch": true,
|
|
28
|
-
"git.autofetchPeriod": 60,
|
|
29
|
-
"git.enableSmartCommit": true,
|
|
30
|
-
"git.pruneOnFetch": true,
|
|
31
|
-
"npm-intellisense.scanDevDependencies": true,
|
|
32
|
-
"npm-intellisense.showBuildInLibs": true,
|
|
33
|
-
"tailwindCSS.includeLanguages": {
|
|
34
|
-
"vue": "html"
|
|
35
|
-
},
|
|
36
|
-
"typescript.preferences.quoteStyle": "single",
|
|
37
|
-
"typescript.tsdk": "node_modules\\typescript\\lib",
|
|
38
|
-
"typescript.updateImportsOnFileMove.enabled": "always",
|
|
39
|
-
"volar.tsPlugin": true,
|
|
40
|
-
"volar.tsPluginStatus": false
|
|
41
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8" />
|
|
5
|
-
<link rel="icon" href="/favicon.ico" />
|
|
6
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
|
-
<title>boilerplate-app</title>
|
|
8
|
-
</head>
|
|
9
|
-
<body>
|
|
10
|
-
<div id="app"></div>
|
|
11
|
-
<script type="module" src="/src/main.ts"></script>
|
|
12
|
-
</body>
|
|
13
|
-
</html>
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "boilerplate-app",
|
|
3
|
-
"version": "0.0.0",
|
|
4
|
-
"private": true,
|
|
5
|
-
"scripts": {
|
|
6
|
-
"dev": "vite",
|
|
7
|
-
"build": "vue-tsc --noEmit && vite build",
|
|
8
|
-
"serve": "vite preview",
|
|
9
|
-
"lint": "eslint . --ext .js,.ts,.vue --fix && stylelint ./**/*.css --fix",
|
|
10
|
-
"pre-commit-lint": "yarn lint-staged",
|
|
11
|
-
"prepare": "cd .. && husky install"
|
|
12
|
-
},
|
|
13
|
-
"dependencies": {
|
|
14
|
-
"@citruslime/ui": "^1.1.3",
|
|
15
|
-
"@harlem/core": "^1.3.2",
|
|
16
|
-
"@harlem/plugin-devtools": "^1.3.2",
|
|
17
|
-
"@harlem/plugin-storage": "^1.3.2",
|
|
18
|
-
"vue": "^3.1.4",
|
|
19
|
-
"vue-router": "^4.0.10"
|
|
20
|
-
},
|
|
21
|
-
"devDependencies": {
|
|
22
|
-
"@iconify/json": "^1.1.376",
|
|
23
|
-
"@tailwindcss/forms": "^0.3.3",
|
|
24
|
-
"@typescript-eslint/eslint-plugin": "^4.28.3",
|
|
25
|
-
"@typescript-eslint/parser": "^4.28.3",
|
|
26
|
-
"@vitejs/plugin-vue": "^1.2.5",
|
|
27
|
-
"@vue/compiler-sfc": "^3.1.4",
|
|
28
|
-
"@vue/eslint-config-typescript": "^7.0.0",
|
|
29
|
-
"autoprefixer": "^10.3.1",
|
|
30
|
-
"eslint": "^7.30.0",
|
|
31
|
-
"eslint-plugin-import": "^2.23.4",
|
|
32
|
-
"eslint-plugin-jsdoc": "^35.4.3",
|
|
33
|
-
"eslint-plugin-vue": "^7.13.0",
|
|
34
|
-
"husky": "^7.0.1",
|
|
35
|
-
"lint-staged": "^11.0.1",
|
|
36
|
-
"postcss": "^8.3.5",
|
|
37
|
-
"postcss-combine-media-query": "^1.0.1",
|
|
38
|
-
"postcss-discard-duplicates": "^5.0.1",
|
|
39
|
-
"stylelint": "^13.13.1",
|
|
40
|
-
"stylelint-config-idiomatic-order": "^8.1.0",
|
|
41
|
-
"stylelint-config-standard": "^22.0.0",
|
|
42
|
-
"stylelint-group-selectors": "^1.0.8",
|
|
43
|
-
"stylelint-high-performance-animation": "^1.5.2",
|
|
44
|
-
"stylelint-order": "^4.1.0",
|
|
45
|
-
"tailwindcss": "^2.2.4",
|
|
46
|
-
"typescript": "^4.3.5",
|
|
47
|
-
"typescript-vue-plugin": "^0.26.2",
|
|
48
|
-
"vite": "^2.4.2",
|
|
49
|
-
"vite-plugin-components": "^0.13.0",
|
|
50
|
-
"vite-plugin-icons": "^0.6.5",
|
|
51
|
-
"vite-plugin-mkcert": "^1.3.2",
|
|
52
|
-
"vite-plugin-pages": "^0.15.0",
|
|
53
|
-
"vue-tsc": "^0.2.1"
|
|
54
|
-
}
|
|
55
|
-
}
|
|
Binary file
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import citrusLimeUi from '@citruslime/ui';
|
|
2
|
-
import harlem from '@harlem/core';
|
|
3
|
-
import createDevtoolsPlugin from '@harlem/plugin-devtools';
|
|
4
|
-
import createStoragePlugin from '@harlem/plugin-storage';
|
|
5
|
-
import { createApp } from 'vue';
|
|
6
|
-
|
|
7
|
-
import app from './app.vue';
|
|
8
|
-
import router from './router';
|
|
9
|
-
import { prefix } from './state';
|
|
10
|
-
|
|
11
|
-
createApp(app)
|
|
12
|
-
.use(router)
|
|
13
|
-
.use(citrusLimeUi)
|
|
14
|
-
.use(harlem, {
|
|
15
|
-
plugins: [
|
|
16
|
-
createDevtoolsPlugin(),
|
|
17
|
-
createStoragePlugin('*', {
|
|
18
|
-
type: 'local',
|
|
19
|
-
prefix
|
|
20
|
-
})
|
|
21
|
-
]
|
|
22
|
-
})
|
|
23
|
-
.mount('#app');
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import generatedRoutes from 'virtual:generated-pages';
|
|
2
|
-
import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router';
|
|
3
|
-
|
|
4
|
-
export const routes: RouteRecordRaw[] = [
|
|
5
|
-
...generatedRoutes,
|
|
6
|
-
{
|
|
7
|
-
name: 'not-found',
|
|
8
|
-
path: '/:pathMatch(.*)*',
|
|
9
|
-
redirect: '/'
|
|
10
|
-
}
|
|
11
|
-
];
|
|
12
|
-
|
|
13
|
-
const router = createRouter({
|
|
14
|
-
history: createWebHashHistory(),
|
|
15
|
-
routes
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
export default router;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { prefix } from './utils';
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export const prefix = 'boilerplate-app';
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
module.exports = {
|
|
2
|
-
mode: 'jit',
|
|
3
|
-
presets: [ require('@citruslime/ui/dist/theme') ],
|
|
4
|
-
purge: [
|
|
5
|
-
'./index.html',
|
|
6
|
-
'./src/**/*.{vue,js,ts,jsx,tsx}'
|
|
7
|
-
],
|
|
8
|
-
darkMode: false,
|
|
9
|
-
theme: {
|
|
10
|
-
extend: {}
|
|
11
|
-
},
|
|
12
|
-
variants: {
|
|
13
|
-
extend: {}
|
|
14
|
-
},
|
|
15
|
-
plugins: []
|
|
16
|
-
};
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "esnext",
|
|
4
|
-
"module": "esnext",
|
|
5
|
-
"moduleResolution": "node",
|
|
6
|
-
"strict": true,
|
|
7
|
-
"sourceMap": true,
|
|
8
|
-
"resolveJsonModule": true,
|
|
9
|
-
"esModuleInterop": true,
|
|
10
|
-
"isolatedModules": true,
|
|
11
|
-
"lib": [
|
|
12
|
-
"esnext",
|
|
13
|
-
"dom"
|
|
14
|
-
],
|
|
15
|
-
"types": [
|
|
16
|
-
"vite/client"
|
|
17
|
-
],
|
|
18
|
-
"plugins": [
|
|
19
|
-
{
|
|
20
|
-
"name": "typescript-vue-plugin"
|
|
21
|
-
}
|
|
22
|
-
]
|
|
23
|
-
},
|
|
24
|
-
"include": [
|
|
25
|
-
"src/**/*.ts",
|
|
26
|
-
"src/**/*.d.ts",
|
|
27
|
-
"src/**/*.vue"
|
|
28
|
-
]
|
|
29
|
-
}
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import path from 'path';
|
|
2
|
-
|
|
3
|
-
import vue from '@vitejs/plugin-vue';
|
|
4
|
-
import { defineConfig } from 'vite';
|
|
5
|
-
import components from 'vite-plugin-components';
|
|
6
|
-
import icons, { ViteIconsResolver } from 'vite-plugin-icons';
|
|
7
|
-
import mkcert from 'vite-plugin-mkcert';
|
|
8
|
-
import pages from 'vite-plugin-pages';
|
|
9
|
-
|
|
10
|
-
export default defineConfig({
|
|
11
|
-
plugins: [
|
|
12
|
-
vue(),
|
|
13
|
-
pages({
|
|
14
|
-
pagesDir: 'src/views',
|
|
15
|
-
extensions: [ 'vue' ]
|
|
16
|
-
}),
|
|
17
|
-
components({
|
|
18
|
-
customComponentResolvers: [ ViteIconsResolver({
|
|
19
|
-
componentPrefix: ''
|
|
20
|
-
}) ]
|
|
21
|
-
}),
|
|
22
|
-
icons(),
|
|
23
|
-
mkcert()
|
|
24
|
-
],
|
|
25
|
-
define: {
|
|
26
|
-
/* eslint-disable @typescript-eslint/naming-convention */
|
|
27
|
-
__VUE_I18N_FULL_INSTALL__: true,
|
|
28
|
-
__VUE_I18N_LEGACY_API__: false,
|
|
29
|
-
__INTLIFY_PROD_DEVTOOLS__: false
|
|
30
|
-
/* eslint-enable @typescript-eslint/naming-convention */
|
|
31
|
-
},
|
|
32
|
-
resolve: {
|
|
33
|
-
alias: {
|
|
34
|
-
'@': path.resolve(__dirname, 'src'),
|
|
35
|
-
'vue-i18n': 'vue-i18n/dist/vue-i18n.runtime.esm-bundler.js'
|
|
36
|
-
}
|
|
37
|
-
},
|
|
38
|
-
server: {
|
|
39
|
-
open: true,
|
|
40
|
-
https: true,
|
|
41
|
-
port: 9999999999,
|
|
42
|
-
proxy: {
|
|
43
|
-
'/api': {
|
|
44
|
-
target: 'https://localhost:[[PORTNUMBERBACKEND]]',
|
|
45
|
-
secure: false,
|
|
46
|
-
rewrite: (path) => path.replace('/api', '')
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
});
|
package/index.js
DELETED
|
@@ -1,250 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/* eslint-disable indent, array-bracket-newline, array-bracket-spacing, space-before-function-paren, brace-style, eol-last, jsdoc/require-jsdoc */
|
|
4
|
-
require('core-js/features/string/replace-all');
|
|
5
|
-
|
|
6
|
-
const { execSync } = require('child_process');
|
|
7
|
-
const fs = require('fs');
|
|
8
|
-
const path = require('path');
|
|
9
|
-
|
|
10
|
-
const {
|
|
11
|
-
green,
|
|
12
|
-
bold,
|
|
13
|
-
lightCyan,
|
|
14
|
-
red
|
|
15
|
-
} = require('kolorist');
|
|
16
|
-
const argv = require('minimist')(process.argv.slice(2));
|
|
17
|
-
|
|
18
|
-
const cwd = process.cwd();
|
|
19
|
-
|
|
20
|
-
const renameFiles = {
|
|
21
|
-
_gitignore: '.gitignore', // eslint-disable-line @typescript-eslint/naming-convention
|
|
22
|
-
_editorconfig: '.editorconfig', // eslint-disable-line @typescript-eslint/naming-convention
|
|
23
|
-
_eslintignore: '.eslintignore', // eslint-disable-line @typescript-eslint/naming-convention
|
|
24
|
-
'_eslintrc.js': '.eslintrc.js', // eslint-disable-line @typescript-eslint/naming-convention
|
|
25
|
-
'_lintstagedrc.json': '.lintstagedrc.json', // eslint-disable-line @typescript-eslint/naming-convention
|
|
26
|
-
_stylelintignore: '.stylelintignore', // eslint-disable-line @typescript-eslint/naming-convention
|
|
27
|
-
'_stylelintrc.js': '.stylelintrc.js', // eslint-disable-line @typescript-eslint/naming-convention
|
|
28
|
-
'boilerplate-app.code-workspace': '' // eslint-disable-line @typescript-eslint/naming-convention,
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
const boilerplateAppText = 'boilerplate-app';
|
|
32
|
-
|
|
33
|
-
const fsOptions = {
|
|
34
|
-
encoding: 'utf-8'
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
let root;
|
|
38
|
-
let targetDir;
|
|
39
|
-
let packageName;
|
|
40
|
-
let portFrontend;
|
|
41
|
-
let portBackend;
|
|
42
|
-
let autoRun;
|
|
43
|
-
|
|
44
|
-
async function init() {
|
|
45
|
-
targetDir = argv._[0];
|
|
46
|
-
packageName = argv._[1];
|
|
47
|
-
portFrontend = argv._[2];
|
|
48
|
-
portBackend = argv._[3];
|
|
49
|
-
autoRun = argv._[4];
|
|
50
|
-
|
|
51
|
-
const pkgManager = /yarn/.test(process.env.npm_execpath) ? 'yarn' : 'error';
|
|
52
|
-
|
|
53
|
-
testScriptParams(targetDir, packageName, pkgManager, portFrontend, portBackend, autoRun);
|
|
54
|
-
|
|
55
|
-
const packageNameStylised = packageName.split('-')
|
|
56
|
-
.map(e => e.charAt(0).toUpperCase() + e.toLowerCase().slice(1))
|
|
57
|
-
.join(' ');
|
|
58
|
-
|
|
59
|
-
root = path.join(cwd, targetDir);
|
|
60
|
-
|
|
61
|
-
if (!fs.existsSync(root)) {
|
|
62
|
-
fs.mkdirSync(root);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
emptyDir(root);
|
|
66
|
-
|
|
67
|
-
console.log(`\n\n${lightCyan('Scaffolding project in ' + root + ' ...')}`);
|
|
68
|
-
|
|
69
|
-
const templateDir = path.join(__dirname, boilerplateAppText);
|
|
70
|
-
|
|
71
|
-
renameFiles['boilerplate-app.code-workspace'] = 'boilerplate-app.code-workspace';
|
|
72
|
-
|
|
73
|
-
copyFilesToTarget(templateDir, packageNameStylised);
|
|
74
|
-
ensureFilesDoNotContainBoilerplateData(templateDir);
|
|
75
|
-
runShelledScripts();
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
function runShelledScripts() {
|
|
79
|
-
const execCmd = `echo "\n\n${bold(green('Finishing installing project ...'))}"
|
|
80
|
-
cd ${targetDir}
|
|
81
|
-
echo "${lightCyan('Running yarn ...')}"
|
|
82
|
-
yarn install
|
|
83
|
-
echo "${lightCyan('Preparing project ...')}"
|
|
84
|
-
yarn prepare
|
|
85
|
-
${autoRun === 'true' ? `echo "${lightCyan('Running project in development environment ...')}"` : ''}
|
|
86
|
-
${autoRun === 'true' ? 'yarn dev' : ''}
|
|
87
|
-
`;
|
|
88
|
-
|
|
89
|
-
try {
|
|
90
|
-
execSync(execCmd, { shell: 'powershell.exe', stdio: 'inherit' });
|
|
91
|
-
console.log(`\n\n${bold(green('Task Complete.'))}`);
|
|
92
|
-
}
|
|
93
|
-
catch (err) {
|
|
94
|
-
console.log(`\n\n${bold(red('Task Failed.'))}`);
|
|
95
|
-
|
|
96
|
-
console.log(`\n\nStatus Code: ${err.status} with '${err.message}'`);
|
|
97
|
-
|
|
98
|
-
console.log(`\nerror : ${err}`);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
function copyFilesToTarget(templateDir, packageNameStylised) {
|
|
103
|
-
const files = fs.readdirSync(templateDir);
|
|
104
|
-
for (const file of files) {
|
|
105
|
-
if (file === 'index.html') {
|
|
106
|
-
writeIndexHtml(templateDir, root, file, packageNameStylised);
|
|
107
|
-
} else if (file === 'vite.config.ts') {
|
|
108
|
-
writeViteConfig(templateDir, root, file, portFrontend, portBackend);
|
|
109
|
-
} else {
|
|
110
|
-
write(templateDir, root, file, null);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
function writeIndexHtml(templateDir, root, file, packageNameStylised) {
|
|
116
|
-
let fileContent = fs.readFileSync(path.join(templateDir, file), fsOptions);
|
|
117
|
-
|
|
118
|
-
fileContent = fileContent.replace(boilerplateAppText, packageNameStylised);
|
|
119
|
-
|
|
120
|
-
write(templateDir, root, file, fileContent);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
function writeViteConfig(templateDir, root, file, portFrontend, portBackend) {
|
|
124
|
-
let fileContent = fs.readFileSync(path.join(templateDir, file), fsOptions);
|
|
125
|
-
|
|
126
|
-
fileContent = fileContent.replace(9999999999, portFrontend)
|
|
127
|
-
.replace('[[PORTNUMBERBACKEND]]', portBackend);
|
|
128
|
-
|
|
129
|
-
write(templateDir, root, file, fileContent);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
function write(templateDir, root, file, content) {
|
|
133
|
-
const targetPath = renameFiles[file] ?
|
|
134
|
-
path.join(root, renameFiles[file]) :
|
|
135
|
-
path.join(root, file);
|
|
136
|
-
if (content) {
|
|
137
|
-
fs.writeFileSync(targetPath, content);
|
|
138
|
-
} else {
|
|
139
|
-
copy(path.join(templateDir, file), targetPath);
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
function copy(src, dest) {
|
|
144
|
-
const stat = fs.statSync(src);
|
|
145
|
-
if (stat.isDirectory()) {
|
|
146
|
-
copyDir(src, dest);
|
|
147
|
-
} else {
|
|
148
|
-
fs.copyFileSync(src, dest);
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
function testScriptParams(targetDir, packageName, pkgManager, portFrontend, portBackend, autoRun) {
|
|
153
|
-
if (!targetDir) {
|
|
154
|
-
throw new Error(red('✖') + ' Missing target directory');
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
if (!packageName || !isValidPackageName(packageName)) {
|
|
158
|
-
throw new Error(red('✖') + ' A valid, hyphenated, lowercase project name (e.g. "lowercase-hyphenated-project-name") argument must be provided.');
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
if (pkgManager === 'error') {
|
|
162
|
-
throw new Error(red('✖') + ' The init script must be executed using yarn.');
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
if (!portFrontend || isNaN(Number(portFrontend))) {
|
|
166
|
-
throw new Error(red('✖') + ' The front-end port parameter is required and must be a number.');
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
if (!portBackend || isNaN(Number(portBackend))) {
|
|
170
|
-
throw new Error(red('✖') + ' The back-end port parameter is required and must be a number.');
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
let arBool = (autoRun.toString().toLowerCase() === 'true' ?
|
|
174
|
-
true :
|
|
175
|
-
(autoRun.toString().toLowerCase() === 'false' ?
|
|
176
|
-
false :
|
|
177
|
-
'')
|
|
178
|
-
);
|
|
179
|
-
if (typeof arBool !== 'boolean') {
|
|
180
|
-
throw new Error(red('✖') + ' The autoRun parameter must be present and a boolean value.');
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
function isValidPackageName(projectName) {
|
|
185
|
-
return /^(?:@[a-z0-9-*~][a-z0-9-*._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/.test(
|
|
186
|
-
projectName
|
|
187
|
-
);
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
function copyDir(srcDir, destDir) {
|
|
191
|
-
fs.mkdirSync(destDir, { recursive: true });
|
|
192
|
-
for (const file of fs.readdirSync(srcDir)) {
|
|
193
|
-
const srcFile = path.resolve(srcDir, file);
|
|
194
|
-
const destFile = path.resolve(destDir, file);
|
|
195
|
-
copy(srcFile, destFile);
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
function emptyDir(dir) {
|
|
200
|
-
if (!fs.existsSync(dir)) {
|
|
201
|
-
return;
|
|
202
|
-
}
|
|
203
|
-
for (const file of fs.readdirSync(dir)) {
|
|
204
|
-
const abs = path.resolve(dir, file);
|
|
205
|
-
// baseline is Node 12 so can't use rmSync :(
|
|
206
|
-
if (fs.lstatSync(abs).isDirectory()) {
|
|
207
|
-
emptyDir(abs);
|
|
208
|
-
fs.rmdirSync(abs);
|
|
209
|
-
} else {
|
|
210
|
-
fs.unlinkSync(abs);
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
function getFilesInFlatArray(path) {
|
|
216
|
-
const files = [];
|
|
217
|
-
for (const file of fs.readdirSync(path)) {
|
|
218
|
-
const fullPath = path + '/' + file;
|
|
219
|
-
if (fs.lstatSync(fullPath).isDirectory()) getFilesInFlatArray(fullPath).forEach(x => files.push(file + '/' + x));
|
|
220
|
-
else files.push(file);
|
|
221
|
-
}
|
|
222
|
-
return files;
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
function ensureFilesDoNotContainBoilerplateData() {
|
|
226
|
-
const files = getFilesInFlatArray(root);
|
|
227
|
-
|
|
228
|
-
for (const filePath of files) {
|
|
229
|
-
let oldFilePath = path.join(root, filePath);
|
|
230
|
-
let newFilePath = path.join(root, filePath);
|
|
231
|
-
|
|
232
|
-
if (!fs.lstatSync(oldFilePath).isDirectory()) {
|
|
233
|
-
if (newFilePath.indexOf(boilerplateAppText) > -1) {
|
|
234
|
-
newFilePath = newFilePath.replace(boilerplateAppText, packageName);
|
|
235
|
-
fs.renameSync(oldFilePath, newFilePath);
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
let fileContent = fs.readFileSync(newFilePath, fsOptions);
|
|
239
|
-
if (fileContent && typeof fileContent === 'string') {
|
|
240
|
-
fileContent = fileContent.replaceAll(boilerplateAppText, packageName);
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
fs.writeFileSync(newFilePath, fileContent);
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
init().catch((e) => {
|
|
249
|
-
console.error(e);
|
|
250
|
-
});
|