@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.
Files changed (34) hide show
  1. package/README.md +13 -18
  2. package/main.mjs +373 -0
  3. package/package.json +11 -13
  4. package/boilerplate-app/.vscode/boilerplate-app.code-workspace +0 -67
  5. package/boilerplate-app/.vscode/extensions.json +0 -14
  6. package/boilerplate-app/.vscode/settings.json +0 -41
  7. package/boilerplate-app/_editorconfig +0 -10
  8. package/boilerplate-app/_eslintignore +0 -3
  9. package/boilerplate-app/_eslintrc.js +0 -4
  10. package/boilerplate-app/_gitignore +0 -5
  11. package/boilerplate-app/_lintstagedrc.json +0 -8
  12. package/boilerplate-app/_stylelintignore +0 -2
  13. package/boilerplate-app/_stylelintrc.js +0 -3
  14. package/boilerplate-app/index.html +0 -13
  15. package/boilerplate-app/package.json +0 -55
  16. package/boilerplate-app/postcss.config.js +0 -8
  17. package/boilerplate-app/public/favicon.ico +0 -0
  18. package/boilerplate-app/public/site.webmanifest +0 -8
  19. package/boilerplate-app/public/web.config +0 -7
  20. package/boilerplate-app/src/app.css +0 -9
  21. package/boilerplate-app/src/app.ts +0 -5
  22. package/boilerplate-app/src/app.vue +0 -7
  23. package/boilerplate-app/src/main.ts +0 -23
  24. package/boilerplate-app/src/router/index.ts +0 -18
  25. package/boilerplate-app/src/shims-vue.d.ts +0 -7
  26. package/boilerplate-app/src/state/index.ts +0 -1
  27. package/boilerplate-app/src/state/utils/index.ts +0 -1
  28. package/boilerplate-app/src/views/dashboard/index.ts +0 -5
  29. package/boilerplate-app/src/views/dashboard/index.vue +0 -11
  30. package/boilerplate-app/src/vite-env.d.ts +0 -2
  31. package/boilerplate-app/tailwind.config.js +0 -16
  32. package/boilerplate-app/tsconfig.json +0 -29
  33. package/boilerplate-app/vite.config.ts +0 -50
  34. package/index.js +0 -250
package/README.md CHANGED
@@ -1,30 +1,25 @@
1
- # Citrus-Lime UI Library Boilerplate Creation
1
+ # Citrus-Lime UI Library Create Boilerplate Script
2
+
3
+ A create package for initialising Citrus-Lime web apps.
2
4
 
3
5
  ![version](https://img.shields.io/npm/v/@citruslime/create-boilerplate/latest)
4
6
  ![version next](https://img.shields.io/npm/v/@citruslime/create-boilerplate/next)
5
- ![license](https://img.shields.io/npm/l/@citruslime/create-boilerplate)
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
- ⚠️ All of the parameters listed below are required.
13
+ `npm init @citruslime/boilerplate TargetDirectory`
14
+
15
+ or
16
+
17
+ `yarn create @citruslime/boilerplate TargetDirectory`
14
18
 
15
- #### Script signature
16
- ```yarn create @citruslime/boilerplate ScriptTarget PackageName FrontEndPortNumber BackendPortNumber AutoRun```
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
- - **ScriptTarget**
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
- #### Example Script Execution
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.1.2",
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
- "index.js",
18
- "boilerplate-*"
14
+ "main.mjs",
15
+ "template-*"
19
16
  ],
20
- "main": "index.js",
17
+ "main": "main.mjs",
21
18
  "bin": {
22
- "create-boilerplate": "index.js",
23
- "cva": "index.js"
19
+ "create-boilerplate": "main.mjs"
24
20
  },
25
21
  "engines": {
26
- "node": ">=12.0.0"
22
+ "node": ">=14.0.0"
27
23
  },
28
24
  "dependencies": {
29
- "core-js": "3.15.2",
30
- "kolorist": "^1.5.0",
25
+ "kolorist": "^1.5.1",
31
26
  "minimist": "^1.2.5",
32
- "prompts": "^2.4.1"
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,10 +0,0 @@
1
- [*]
2
- indent_style = space
3
- indent_size = 4
4
- end_of_line = lf
5
- charset = utf-8
6
- trim_trailing_whitespace = true
7
- insert_final_newline = true
8
-
9
- [*.css]
10
- indent_style = tab
@@ -1,3 +0,0 @@
1
- dist
2
- node_modules
3
- index.html
@@ -1,4 +0,0 @@
1
- module.exports = {
2
- root: true,
3
- extends: [ './node_modules/@citruslime/ui/dist/.eslintrc.js' ]
4
- };
@@ -1,5 +0,0 @@
1
- node_modules
2
- .DS_Store
3
- dist
4
- dist-ssr
5
- *.local
@@ -1,8 +0,0 @@
1
- {
2
- "./**/*.+(js|ts|vue)": [
3
- "eslint --fix"
4
- ],
5
- "./**/*.css": [
6
- "stylelint --fix"
7
- ]
8
- }
@@ -1,2 +0,0 @@
1
- **/dist
2
- **/node_modules
@@ -1,3 +0,0 @@
1
- module.exports = {
2
- extends: [ './node_modules/@citruslime/ui/dist/.stylelintrc.js' ]
3
- };
@@ -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
- }
@@ -1,8 +0,0 @@
1
- module.exports = {
2
- plugins: {
3
- tailwindcss: {},
4
- autoprefixer: {},
5
- 'postcss-discard-duplicates': {},
6
- 'postcss-combine-media-query': {}
7
- }
8
- };
Binary file
@@ -1,8 +0,0 @@
1
- {
2
- "name": "",
3
- "short_name": "",
4
- "icons": [],
5
- "theme_color": "#637bc6",
6
- "background_color": "#9acd32",
7
- "display": "standalone"
8
- }
@@ -1,7 +0,0 @@
1
- <configuration>
2
- <system.webServer>
3
- <staticContent>
4
- <mimeMap fileExtension="webmanifest" mimeType="application/json" />
5
- </staticContent>
6
- </system.webServer>
7
- </configuration>
@@ -1,9 +0,0 @@
1
- @import '@citruslime/ui/dist/style.css';
2
-
3
- @tailwind base;
4
- @tailwind components;
5
- @tailwind utilities;
6
-
7
- body {
8
- @apply bg-off-white min-h-screen w-full;
9
- }
@@ -1,5 +0,0 @@
1
- import { defineComponent } from 'vue';
2
-
3
- export default defineComponent({
4
- name: 'App'
5
- });
@@ -1,7 +0,0 @@
1
- <script lang="ts" src="./app"></script>
2
-
3
- <style src="./app.css"></style>
4
-
5
- <template>
6
- <router-view />
7
- </template>
@@ -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,7 +0,0 @@
1
- declare module '*.vue' {
2
- import { DefineComponent } from 'vue';
3
-
4
- const component: DefineComponent<Record<string, unknown>, Record<string, unknown>, unknown>;
5
-
6
- export default component;
7
- }
@@ -1 +0,0 @@
1
- export { prefix } from './utils';
@@ -1 +0,0 @@
1
- export const prefix = 'boilerplate-app';
@@ -1,5 +0,0 @@
1
- import { defineComponent } from 'vue';
2
-
3
- export default defineComponent({
4
- name: 'Dashboard'
5
- });
@@ -1,11 +0,0 @@
1
- <script lang="ts" src="."></script>
2
-
3
- <route>
4
- {
5
- path: '/'
6
- }
7
- </route>
8
-
9
- <template>
10
- <div></div>
11
- </template>
@@ -1,2 +0,0 @@
1
- /// <reference types="vite/client" />
2
- /// <reference types="vite-plugin-pages/client" />
@@ -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
- });