lucy-cli 0.8.2 โ†’ 0.9.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/src/helpers.ts CHANGED
@@ -1,15 +1,14 @@
1
1
  import chalk from 'chalk';
2
- import { join } from 'path';
3
2
  import { simpleGit } from 'simple-git';
4
- import fs from 'fs/promises';
5
3
  import { spawnSync } from 'child_process';
6
4
  // https://www.sergevandenoever.nl/run-gulp4-tasks-programatically-from-node/
7
5
  import path from 'path';
8
6
  import { fileURLToPath } from 'url';
9
7
  import { ModuleSettings, ProjectSettings } from '.';
10
8
  import { exec } from 'child_process';
9
+ import os from 'os';
11
10
 
12
- import { blue, green, orange, red } from './index.js';
11
+ import { blue, green, orange, red, yellow, magenta } from './index.js';
13
12
 
14
13
  export async function installPackages(wixPackages: Record<string, string>, devPackages: Record<string, string>, cwd: string, locked: boolean ) {
15
14
  if (locked) console.log("๐Ÿ•" + blue.underline(` => Installing & version locked packages!`));
@@ -83,19 +82,84 @@ export async function runGulp(moduleSettings: ModuleSettings, projectSettings: P
83
82
  /**
84
83
  * Clean up and run a command before exiting the process.
85
84
  */
86
- export function handleExit() {
85
+ export function cleanupWatchers() {
86
+ console.log(`๐Ÿงน ${magenta.underline('Cleaning up Watchman watchers...')}`);
87
87
  const cwd = process.cwd();
88
- const command = `watchman watch-del '${cwd}'`;
89
-
90
- console.log("๐Ÿ•" + blue.underline(' => Cleaning up...'));
88
+ const command = `watchman watch-del "${cwd}"`; // Adjust for Windows paths
91
89
  exec(command, (error, stdout, stderr) => {
92
90
  if (error) {
93
- console.error(`๐Ÿ’ฉ Failed to run cleanup: ${error.message}`);
91
+ console.error(`๐Ÿ’ฉ ${red.underline('Failed to run cleanup:')} ${orange(error.message)}`);
94
92
  return;
95
93
  }
96
94
  if (stderr) {
97
- console.error(`โš ๏ธ Watchman stderr: ${stderr}`);
95
+ console.error(`โš ๏ธ ${yellow.underline('Watchman stderr:')} ${stderr}`);
98
96
  }
99
- console.log(`โœ… Watchman cleanup success: ${stdout}`);
97
+ console.log(`โœ… ${green.underline('Watchman cleanup success:')} ${stdout}`);
100
98
  });
101
99
  }
100
+
101
+ /**
102
+ * Kill all processes matching a specific substring in their command, with a fallback for Windows.
103
+ * @param {string} processPattern - The substring to match (e.g., "wix:dev" or "@wix/cli/bin/wix.cjs").
104
+ */
105
+ export function killAllProcesses(processPattern: string) {
106
+ const isWindows = os.platform() === 'win32';
107
+ const command = isWindows
108
+ ? `tasklist /FI "IMAGENAME eq node.exe" /FO CSV | findstr "${processPattern}"` // Adjust for Node.js processes
109
+ : `ps -eo pid,command | grep "${processPattern}" | grep -v grep`;
110
+
111
+ exec(command, (error, stdout, stderr) => {
112
+ if (error) {
113
+ console.error(`๐Ÿ’ฉ ${red.underline('Failed to find processes:')} ${orange(error.message)}`);
114
+ return;
115
+ }
116
+ if (stderr) {
117
+ console.error(`โš ๏ธ ${yellow.underline('Error output:')} ${stderr}`);
118
+ }
119
+ if (!stdout.trim()) {
120
+ console.log(`โ„น๏ธ ${blue.underline(`No processes found matching pattern:`)} ${orange(processPattern)}`);
121
+ return;
122
+ }
123
+
124
+ console.log(`๐Ÿ“ ${magenta.underline('Found matching processes:')}\n${stdout}`);
125
+ const lines = stdout.trim().split('\n');
126
+ const pids = isWindows
127
+ ? lines.map(line => line.match(/"(\d+)"/)?.[1]) // Extract PID from Windows tasklist output
128
+ : lines.map(line => line.trim().split(/\s+/)[0]).filter(pid => !isNaN(Number(pid)));
129
+
130
+ pids.forEach(pid => {
131
+ if (!pid) return;
132
+ try {
133
+ const killCommand = isWindows
134
+ ? `taskkill /PID ${pid} /T /F` // Forcefully terminate the process on Windows
135
+ : `kill -SIGTERM ${pid}`;
136
+
137
+ exec(killCommand, (killError) => {
138
+ if (killError) {
139
+ console.error(`โš ๏ธ ${yellow.underline('Failed to kill process with PID')} ${orange(pid)}: ${red(killError.message)}`);
140
+ } else {
141
+ console.log(`โœ… ${green.underline('Killed process with PID:')} ${orange(pid)}`);
142
+ }
143
+ });
144
+
145
+ // Schedule SIGKILL fallback for non-Windows platforms
146
+ if (!isWindows) {
147
+ setTimeout(() => {
148
+ try {
149
+ process.kill(parseInt(pid, 10), 'SIGKILL');
150
+ console.log(`๐Ÿ”ช ${red.underline('Sent SIGKILL to process with PID:')} ${orange(pid)} (fallback).`);
151
+ } catch (killError: any) {
152
+ if (killError.code === 'ESRCH') {
153
+ console.log(`โœ… ${green.underline('Process with PID')} ${orange(pid)} ${green.underline('already terminated.')}`);
154
+ } else {
155
+ console.error(`โš ๏ธ ${yellow.underline('Failed to send SIGKILL to process with PID')} ${orange(pid)}: ${red(killError.message)}`);
156
+ }
157
+ }
158
+ }, 10000);
159
+ }
160
+ } catch (err: any) {
161
+ console.error(`โš ๏ธ ${yellow.underline('Failed to kill process with PID')} ${orange(pid)}: ${red(err.message)}`);
162
+ }
163
+ });
164
+ });
165
+ }
package/src/index.ts CHANGED
@@ -11,8 +11,9 @@ import fs from 'fs/promises';
11
11
 
12
12
  import { init } from './init.js';
13
13
  import { sync } from './sync.js';
14
- import { runGulp, installPackages, handleExit } from './helpers.js';
14
+ import { runGulp, installPackages, killAllProcesses, cleanupWatchers } from './helpers.js';
15
15
  import { prepare } from './prepare.js';
16
+ import { spawnSync } from 'child_process';
16
17
 
17
18
  export type LucySettings = {
18
19
  modules: {
@@ -70,10 +71,50 @@ const __filename = fileURLToPath(import.meta.url);
70
71
  // eslint-disable-next-line @typescript-eslint/naming-convention
71
72
  const __dirname = dirname(__filename);
72
73
 
74
+ // const cwd = process.cwd();
75
+ // const command = `watchman watch-del '${cwd}'`;
76
+ // killAllProcesses('@wix/cli/bin/wix.cjs'); // Matches processes running the Wix CLI
77
+ // killAllProcesses('wix:dev');
78
+
79
+
80
+ process.on('exit', (code) => {
81
+ killAllProcesses('@wix/cli/bin/wix.cjs'); // Matches processes running the Wix CLI
82
+ killAllProcesses('wix:dev');
83
+ cleanupWatchers();
84
+ console.log(`๐Ÿšช ${magenta.underline('Process exiting with code:')} ${orange(code)}`);
85
+ });
86
+
73
87
  process.on('SIGINT', () => {
74
- console.log("๐Ÿ• Received Ctrl+C, cleaning up...");
75
- handleExit();
76
- process.exit(); // Exit the process explicitly
88
+ console.log(`๐Ÿ• ${green.underline('Received Ctrl+C (SIGINT), cleaning up...')}`);
89
+ killAllProcesses('@wix/cli/bin/wix.cjs'); // Matches processes running the Wix CLI
90
+ killAllProcesses('wix:dev');
91
+ cleanupWatchers();
92
+ process.exit(); // Exit explicitly after handling
93
+ });
94
+
95
+ process.on('SIGTERM', () => {
96
+ console.log(`๐Ÿ›‘ ${red.underline('Received termination signal (SIGTERM), cleaning up...')}`);
97
+ killAllProcesses('@wix/cli/bin/wix.cjs'); // Matches processes running the Wix CLI
98
+ killAllProcesses('wix:dev');
99
+ cleanupWatchers();
100
+ process.exit(); // Exit explicitly after handling
101
+ });
102
+
103
+ process.on('uncaughtException', (error) => {
104
+ console.error(`๐Ÿ’ฅ ${red.underline('Uncaught Exception:')}`, error);
105
+ killAllProcesses('@wix/cli/bin/wix.cjs'); // Matches processes running the Wix CLI
106
+ killAllProcesses('wix:dev');
107
+ cleanupWatchers();
108
+ process.exit(1); // Exit with an error code
109
+ });
110
+
111
+ process.on('unhandledRejection', (reason, promise) => {
112
+ console.error(`๐Ÿšจ ${yellow.underline('Unhandled Rejection at:')} ${orange(promise)}`);
113
+ console.error(`๐Ÿšจ ${red.underline('Reason:')} ${reason}`); cleanupWatchers();
114
+ killAllProcesses('@wix/cli/bin/wix.cjs'); // Matches processes running the Wix CLI
115
+ killAllProcesses('wix:dev');
116
+ cleanupWatchers();
117
+ process.exit(1); // Exit with an error code
77
118
  });
78
119
 
79
120
  /**
@@ -113,6 +154,7 @@ async function main(): Promise<void> {
113
154
  console.log("๐Ÿฆฎ " + magenta.bold('sync') + " : Synchronizes the database (not Implemented)");
114
155
  console.log("๐Ÿฆฎ " + magenta.bold('install') + " : Installs all Wix npm packages listed in the 'lucy.json' file in the project directory.");
115
156
  console.log("๐Ÿฆฎ " + magenta.bold('fix') + " : Runs a fix command to resolve common issues in development or production settings.");
157
+ console.log("๐Ÿฆฎ " + magenta.bold('docs') + " : Generates documentation for the project.");
116
158
  console.log("\nOptions:");
117
159
  console.log("๐Ÿฆฎ " + magenta.bold('-h, help') + " : Displays this help message.");
118
160
  console.log("๐Ÿฆฎ " + magenta.bold('-v, version') + " : Displays the current version of Lucy CLI as defined in the projectโ€™s package.json.");
@@ -189,6 +231,14 @@ async function main(): Promise<void> {
189
231
  }
190
232
 
191
233
 
234
+ if(moduleSettings.args.includes('docs')){
235
+ const res = spawnSync('yarn docs', { shell: true, stdio: 'inherit' });
236
+ if (res.error) {
237
+ return console.log((`๐Ÿ’ฉ ${red.underline.bold("=> Failed to install dev packages =>")} ${orange(res.error.message)}`));
238
+ }
239
+ return console.log("๐Ÿ•" + blue.underline(` => Docs generated!`));
240
+ }
241
+
192
242
  if(moduleSettings.args.includes('prepare')){
193
243
  await prepare( moduleSettings, projectSettings);
194
244
 
package/src/settings.json CHANGED
@@ -12,33 +12,39 @@
12
12
  "initialized": false,
13
13
  "wixPackages": {},
14
14
  "devPackages": {
15
- "@wix/cli": "latest",
15
+ "@eslint/js": "^9.15.0",
16
16
  "@styled/typescript-styled-plugin": "^1.0.1",
17
- "@total-typescript/ts-reset": "0.6.1",
18
- "@types/jest": "^29.5.3",
19
- "@types/node": "22.9.0",
20
- "@types/react": "^18.2.21",
21
- "@typescript-eslint/parser": "8.14.0",
22
- "@typescript-eslint/utils": "8.14.0",
23
- "@wix/eslint-plugin-cli": "latest",
24
- "cypress": "13.15.2",
25
- "cypress-cloud": "^1.9.3",
26
- "esbuild": "0.24.0",
27
- "eslint": "9.14.0",
28
- "eslint-plugin-import": "^2.27.5",
29
- "eslint-plugin-jsdoc": "50.5.0",
17
+ "@total-typescript/ts-reset": "^0.6.1",
18
+ "@types/jest": "^29.5.14",
19
+ "@types/node": "^22.9.1",
20
+ "@types/nodemailer": "^6.4.17",
21
+ "@types/react": "^18.3.12",
22
+ "@typescript-eslint/eslint-plugin": "^8.15.0",
23
+ "@typescript-eslint/parser": "^8.15.0",
24
+ "@typescript-eslint/utils": "^8.15.0",
25
+ "@wix/cli": "^1.1.52",
26
+ "@wix/eslint-plugin-cli": "^1.0.2",
27
+ "cypress": "^13.16.0",
28
+ "cypress-cloud": "^1.11.0",
29
+ "esbuild": "^0.24.0",
30
+ "eslint": "^9.15.0",
31
+ "eslint-plugin-import": "^2.31.0",
32
+ "eslint-plugin-jsdoc": "^50.5.0",
30
33
  "eslint-plugin-named-import-spacing": "^1.0.3",
31
- "eslint-plugin-neverthrow": "^1.1.4",
32
- "eslint-plugin-simple-import-sort": "12.1.1",
33
- "jest": "^29.6.1",
34
- "prettier": "^3.0.3",
35
- "sass": "^1.65.1",
36
- "ts-jest": "^29.1.1",
37
- "ts-node": "^10.9.1",
38
- "tsx": "4.19.2",
39
- "typedoc": "0.26.11",
40
- "typedoc-theme-hierarchy": "5.0.3",
41
- "typescript": "^5.1.6",
34
+ "eslint-plugin-simple-import-sort": "^12.1.1",
35
+ "jest": "^29.7.0",
36
+ "prettier": "^3.3.3",
37
+ "react": "^18.3.1",
38
+ "sass": "^1.81.0",
39
+ "ts-jest": "^29.2.5",
40
+ "ts-node": "^10.9.2",
41
+ "tsx": "^4.19.2",
42
+ "typedoc": "^0.26.11",
43
+ "typedoc-plugin-merge-modules": "^6.0.3",
44
+ "typedoc-plugin-zod": "^1.3.0",
45
+ "typedoc-theme-hierarchy": "^5.0.3",
46
+ "typescript": "5.6.3",
47
+ "typescript-eslint": "^8.15.0",
42
48
  "typescript-eslint-language-service": "^5.0.5"
43
49
  },
44
50
  "scripts": {
package/src/types.d.ts CHANGED
@@ -4,4 +4,5 @@ declare module 'gulp-foreach';
4
4
  declare module 'gulp-string-replace';
5
5
  declare module 'gulp-wait';
6
6
  declare module 'gulp-jest';
7
- declare module 'gulp-flatmap';
7
+ declare module 'gulp-flatmap';
8
+ declare module 'gulp-swc';
@@ -1,108 +0,0 @@
1
- module.exports = {
2
- extends: ['eslint:recommended', 'plugin:import/recommended', 'plugin:jsdoc/recommended', 'plugin:@typescript-eslint/recommended', 'plugin:@wix/cli/recommended'],
3
- plugins: ['simple-import-sort', 'eslint-plugin-named-import-spacing', '@typescript-eslint'],
4
- parser: '@typescript-eslint/parser',
5
- parserOptions: {
6
- ecmaVersion: 2021,
7
- },
8
- ignorePatterns: ['src/**/*', 'typescript/types/backend/**/*', 'typescript/types/pages/**/*', 'typescript/types/public/**/*', 'typescript/types/node/**/*', '.wix/**/*', 'coverage/**/*', 'docs/**/*'],
9
- rules: {
10
- 'no-static-block': 'error',
11
- quotes: [2, 'single', { 'avoidEscape': true, 'allowTemplateLiterals': true }],
12
- curly: ['error', 'multi-line'],
13
- 'simple-import-sort/imports': 'error',
14
- 'simple-import-sort/exports': 'error',
15
- indent: ['error', 'tab'],
16
- 'no-tabs': 0,
17
- 'semi-style': ['error', 'last'],
18
- semi: [2, 'always'],
19
- 'object-curly-spacing': ['error', 'always'],
20
- 'space-in-parens': ['error', 'never'],
21
- 'newline-before-return': 'error',
22
- 'space-before-blocks': ['error', { functions: 'always', keywords: 'never', classes: 'always' }],
23
- 'comma-spacing': ['error', { before: false, after: true }],
24
- 'no-multi-spaces': ['error'],
25
- 'import/newline-after-import': ['error', { count: 1 }],
26
- 'named-import-spacing/named-import-spacing': 2,
27
- 'no-unused-vars': 'warn',
28
- 'import/no-unresolved': [0],
29
- 'no-forbidden-relative-imports': [0],
30
- '@typescript-eslint/triple-slash-reference': 'off',
31
- '@typescript-eslint/member-ordering': [
32
- 'error',
33
- { classes: ['constructor', 'private-instance-field', 'protected-instance-field', 'public-instance-field', 'public-instance-method', 'private-instance-method'] }
34
- ],
35
- '@typescript-eslint/naming-convention': [
36
- 'error',
37
- {
38
- selector: ['variable', 'function'],
39
- format: ['camelCase'],
40
- leadingUnderscore: 'allow'
41
- },
42
- {
43
- selector: ['objectLiteralProperty'],
44
- format: null,
45
- leadingUnderscore: 'allow'
46
- },
47
- {
48
- selector: 'memberLike',
49
- modifiers: ['private'],
50
- format: ['camelCase'],
51
- leadingUnderscore: 'require'
52
- },
53
- {
54
- selector: 'memberLike',
55
- modifiers: ['protected'],
56
- format: ['camelCase'],
57
- leadingUnderscore: 'require'
58
- },
59
- {
60
- selector: 'memberLike',
61
- modifiers: ['public'],
62
- format: ['camelCase'],
63
- leadingUnderscore: 'forbid'
64
- },
65
- {
66
- selector: ['parameterProperty', 'parameter'],
67
- format: ['camelCase'],
68
- leadingUnderscore: 'forbid'
69
- },
70
- {
71
- selector: 'default',
72
- format: ['UPPER_CASE'],
73
- leadingUnderscore: 'forbid',
74
- trailingUnderscore: 'forbid',
75
- custom: {
76
- regex: '^[A-Z_]+$',
77
- match: true
78
- }
79
- },
80
- {
81
- selector: 'typeLike',
82
- format: ['PascalCase']
83
- },
84
- // Custom rule added
85
- {
86
- selector: 'function',
87
- format: ['UPPER_CASE']
88
- }
89
- ],
90
- },
91
- overrides: [
92
- {
93
- files: ['**/*.tsx', '**/*.ts'],
94
- rules: {
95
- 'no-static-block': 'error'
96
- }
97
- }
98
- ],
99
- root: true,
100
- env: {
101
- es6: true,
102
- browser: true,
103
- node: true
104
- },
105
- globals: {
106
- $w: 'readonly'
107
- }
108
- };