fscr 6.2.6 → 7.3.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/README.md +48 -30
- package/dist/index.js +502 -186
- package/dist/lib/auth/auth-conf.js +49 -45
- package/dist/lib/cache/README.md +341 -0
- package/dist/lib/cache/cli.js +152 -0
- package/dist/lib/cache/file-watcher.js +193 -0
- package/dist/lib/cache/index.js +422 -0
- package/dist/lib/cache/monitor.js +224 -0
- package/dist/lib/commands/doctor.js +225 -0
- package/dist/lib/completions/completion.js +342 -0
- package/dist/lib/completions/generator.js +152 -0
- package/dist/lib/completions/scripts/bash.sh +108 -0
- package/dist/lib/completions/scripts/fish.sh +105 -0
- package/dist/lib/completions/scripts/powershell.ps1 +168 -0
- package/dist/lib/completions/scripts/zsh.sh +124 -0
- package/dist/lib/diagnostics/cache.js +121 -0
- package/dist/lib/diagnostics/fileSystem.js +236 -0
- package/dist/lib/diagnostics/gitCheck.js +41 -0
- package/dist/lib/diagnostics/nodeVersion.js +68 -0
- package/dist/lib/diagnostics/packageManager.js +64 -0
- package/dist/lib/diagnostics/performance.js +141 -0
- package/dist/lib/encryption/decryptConfig.js +3 -2
- package/dist/lib/encryption/encryption.js +153 -113
- package/dist/lib/generators/generateFScripts.js +16 -13
- package/dist/lib/generators/generateToc.js +23 -14
- package/dist/lib/generators/index.js +1 -1
- package/dist/lib/git/pub.js +27 -17
- package/dist/lib/git/taskRunner.js +79 -69
- package/dist/lib/git/validateNotDev.js +65 -54
- package/dist/lib/optionList.js +69 -57
- package/dist/lib/parsers/parseScriptsMd.cached.js +208 -0
- package/dist/lib/parsers/parseScriptsMd.js +88 -79
- package/dist/lib/parsers/parseScriptsPackage.js +4 -3
- package/dist/lib/performance/cache.js +199 -0
- package/dist/lib/performance/lazy-loader.js +189 -0
- package/dist/lib/performance/monitor.js +303 -0
- package/dist/lib/plugins/deployment/index.js +113 -0
- package/dist/lib/plugins/hooks.js +17 -0
- package/dist/lib/plugins/loader.js +91 -0
- package/dist/lib/plugins/task-notifier/index.js +72 -0
- package/dist/lib/release/bump.js +50 -45
- package/dist/lib/release/commitWithMessage.js +80 -52
- package/dist/lib/release/publish.js +19 -14
- package/dist/lib/release/pushToGit.js +40 -31
- package/dist/lib/release/releasenotes.js +116 -97
- package/dist/lib/release/seeChangedFiles.js +68 -60
- package/dist/lib/release/sort.js +200 -116
- package/dist/lib/release/tree.js +161 -147
- package/dist/lib/release/validateNotDev.js +52 -44
- package/dist/lib/running/index.js +1 -1
- package/dist/lib/running/runCLICommand.js +41 -31
- package/dist/lib/running/runParallel.js +61 -59
- package/dist/lib/running/runSequence.js +55 -53
- package/dist/lib/startScripts.js +129 -114
- package/dist/lib/taskList.js +97 -90
- package/dist/lib/test-files/.fscripts.md +113 -0
- package/dist/lib/test-files/.fscripts.test.md +103 -0
- package/dist/lib/test-files/.fscriptsb.md +107 -0
- package/dist/lib/test-files/.mdtest.md +40 -0
- package/dist/lib/test-files/consoleSample.js +13 -9
- package/dist/lib/test-files/inputSample.js +17 -14
- package/dist/lib/test-files/testConsole.js +1 -1
- package/dist/lib/test-files/testInput.js +1 -1
- package/dist/lib/upgradePackages.js +56 -46
- package/dist/lib/utils/clear.js +16 -13
- package/dist/lib/utils/console.js +27 -21
- package/dist/lib/utils/encryption.js +55 -13
- package/dist/lib/utils/hash.js +128 -0
- package/dist/lib/utils/helpers.js +153 -142
- package/dist/lib/utils/index.js +1 -1
- package/dist/lib/utils/prompt.js +24 -29
- package/package.json +11 -29
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import fs from 'fs-extra';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Check fscripts.md file
|
|
7
|
+
* @param {Object} options - Check options
|
|
8
|
+
* @returns {Object} Check result
|
|
9
|
+
*/
|
|
10
|
+
export async function checkFScriptsFile(options = {}) {
|
|
11
|
+
const result = {
|
|
12
|
+
name: 'fscripts.md file',
|
|
13
|
+
passed: false,
|
|
14
|
+
warning: false,
|
|
15
|
+
message: '',
|
|
16
|
+
details: {},
|
|
17
|
+
canFix: true,
|
|
18
|
+
fix: null
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
try {
|
|
22
|
+
const fscriptsPath = path.join(process.cwd(), 'fscripts.md');
|
|
23
|
+
|
|
24
|
+
if (await fs.pathExists(fscriptsPath)) {
|
|
25
|
+
const stats = await fs.stat(fscriptsPath);
|
|
26
|
+
result.passed = true;
|
|
27
|
+
result.message = `Found (${formatBytes(stats.size)})`;
|
|
28
|
+
result.details = {
|
|
29
|
+
path: fscriptsPath,
|
|
30
|
+
size: stats.size,
|
|
31
|
+
sizeFormatted: formatBytes(stats.size)
|
|
32
|
+
};
|
|
33
|
+
} else {
|
|
34
|
+
result.passed = false;
|
|
35
|
+
result.message = 'Not found';
|
|
36
|
+
result.canFix = true;
|
|
37
|
+
result.fix = async () => {
|
|
38
|
+
// Create a basic fscripts.md template
|
|
39
|
+
const template = `# Scripts
|
|
40
|
+
|
|
41
|
+
## hello
|
|
42
|
+
Say hello
|
|
43
|
+
|
|
44
|
+
\`\`\`bash
|
|
45
|
+
echo "Hello from FSCR!"
|
|
46
|
+
\`\`\`
|
|
47
|
+
`;
|
|
48
|
+
await fs.writeFile(fscriptsPath, template, 'utf8');
|
|
49
|
+
return 'Created basic fscripts.md template';
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
} catch (error) {
|
|
53
|
+
result.passed = false;
|
|
54
|
+
result.message = `Error checking file: ${error.message}`;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return result;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Check package.json file
|
|
62
|
+
* @param {Object} options - Check options
|
|
63
|
+
* @returns {Object} Check result
|
|
64
|
+
*/
|
|
65
|
+
export async function checkPackageJson(options = {}) {
|
|
66
|
+
const result = {
|
|
67
|
+
name: 'package.json',
|
|
68
|
+
passed: false,
|
|
69
|
+
warning: false,
|
|
70
|
+
message: '',
|
|
71
|
+
details: {},
|
|
72
|
+
canFix: false,
|
|
73
|
+
fix: null
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
try {
|
|
77
|
+
const packagePath = path.join(process.cwd(), 'package.json');
|
|
78
|
+
|
|
79
|
+
if (await fs.pathExists(packagePath)) {
|
|
80
|
+
const packageJson = await fs.readJson(packagePath);
|
|
81
|
+
const fscrVersion = packageJson.version || 'unknown';
|
|
82
|
+
|
|
83
|
+
result.passed = true;
|
|
84
|
+
result.message = `Valid (fsr@${fscrVersion})`;
|
|
85
|
+
result.details = {
|
|
86
|
+
path: packagePath,
|
|
87
|
+
version: fscrVersion,
|
|
88
|
+
name: packageJson.name
|
|
89
|
+
};
|
|
90
|
+
} else {
|
|
91
|
+
result.passed = false;
|
|
92
|
+
result.message = 'Not found';
|
|
93
|
+
result.canFix = false;
|
|
94
|
+
result.fixInstructions = 'package.json is required. Please initialize your project with npm init.';
|
|
95
|
+
}
|
|
96
|
+
} catch (error) {
|
|
97
|
+
result.passed = false;
|
|
98
|
+
result.message = `Invalid or corrupted: ${error.message}`;
|
|
99
|
+
result.canFix = false;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return result;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Check TypeScript installation
|
|
107
|
+
* @param {Object} options - Check options
|
|
108
|
+
* @returns {Object} Check result
|
|
109
|
+
*/
|
|
110
|
+
export async function checkTypeScript(options = {}) {
|
|
111
|
+
const result = {
|
|
112
|
+
name: 'TypeScript',
|
|
113
|
+
passed: false,
|
|
114
|
+
warning: true, // TypeScript is optional
|
|
115
|
+
message: '',
|
|
116
|
+
details: {},
|
|
117
|
+
canFix: true,
|
|
118
|
+
fix: null
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
try {
|
|
122
|
+
const packagePath = path.join(process.cwd(), 'package.json');
|
|
123
|
+
const packageJson = await fs.readJson(packagePath);
|
|
124
|
+
|
|
125
|
+
const hasTypeScript =
|
|
126
|
+
(packageJson.dependencies && packageJson.dependencies.typescript) ||
|
|
127
|
+
(packageJson.devDependencies && packageJson.devDependencies.typescript);
|
|
128
|
+
|
|
129
|
+
if (hasTypeScript) {
|
|
130
|
+
const version =
|
|
131
|
+
(packageJson.dependencies && packageJson.dependencies.typescript) ||
|
|
132
|
+
(packageJson.devDependencies && packageJson.devDependencies.typescript);
|
|
133
|
+
result.passed = true;
|
|
134
|
+
result.warning = false;
|
|
135
|
+
result.message = `Installed (${version})`;
|
|
136
|
+
result.details = {
|
|
137
|
+
version: version
|
|
138
|
+
};
|
|
139
|
+
} else {
|
|
140
|
+
result.passed = false;
|
|
141
|
+
result.warning = true; // It's just a warning, not critical
|
|
142
|
+
result.message = 'Not installed (optional)';
|
|
143
|
+
result.canFix = true;
|
|
144
|
+
result.fix = async () => {
|
|
145
|
+
const { execSync } = await import('child_process');
|
|
146
|
+
execSync('npm install --save-dev typescript', { stdio: 'inherit' });
|
|
147
|
+
return 'Installed TypeScript as dev dependency';
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
} catch (error) {
|
|
151
|
+
result.passed = false;
|
|
152
|
+
result.warning = true;
|
|
153
|
+
result.message = 'Not installed (optional)';
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return result;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Check file permissions
|
|
161
|
+
* @param {Object} options - Check options
|
|
162
|
+
* @returns {Object} Check result
|
|
163
|
+
*/
|
|
164
|
+
export async function checkFilePermissions(options = {}) {
|
|
165
|
+
const result = {
|
|
166
|
+
name: 'File permissions',
|
|
167
|
+
passed: false,
|
|
168
|
+
warning: false,
|
|
169
|
+
message: '',
|
|
170
|
+
details: {},
|
|
171
|
+
canFix: true,
|
|
172
|
+
fix: null
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
try {
|
|
176
|
+
const testFile = path.join(process.cwd(), '.fsr-permission-test');
|
|
177
|
+
|
|
178
|
+
// Test write permission
|
|
179
|
+
try {
|
|
180
|
+
await fs.writeFile(testFile, 'test', 'utf8');
|
|
181
|
+
} catch (writeError) {
|
|
182
|
+
result.passed = false;
|
|
183
|
+
result.message = 'No write access';
|
|
184
|
+
result.canFix = false;
|
|
185
|
+
result.fixInstructions = 'Please check directory permissions and ensure you have write access.';
|
|
186
|
+
return result;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Test read permission
|
|
190
|
+
try {
|
|
191
|
+
await fs.readFile(testFile, 'utf8');
|
|
192
|
+
} catch (readError) {
|
|
193
|
+
result.passed = false;
|
|
194
|
+
result.message = 'No read access';
|
|
195
|
+
result.canFix = false;
|
|
196
|
+
result.fixInstructions = 'Please check directory permissions and ensure you have read access.';
|
|
197
|
+
await fs.remove(testFile).catch(() => {});
|
|
198
|
+
return result;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Clean up test file
|
|
202
|
+
await fs.remove(testFile);
|
|
203
|
+
|
|
204
|
+
result.passed = true;
|
|
205
|
+
result.message = 'Read/write access OK';
|
|
206
|
+
result.details = {
|
|
207
|
+
read: true,
|
|
208
|
+
write: true
|
|
209
|
+
};
|
|
210
|
+
} catch (error) {
|
|
211
|
+
result.passed = false;
|
|
212
|
+
result.message = `Permission check failed: ${error.message}`;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
return result;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Format bytes to human-readable format
|
|
220
|
+
* @param {number} bytes - Number of bytes
|
|
221
|
+
* @returns {string} Formatted string
|
|
222
|
+
*/
|
|
223
|
+
function formatBytes(bytes) {
|
|
224
|
+
if (bytes === 0) return '0 Bytes';
|
|
225
|
+
const k = 1024;
|
|
226
|
+
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
|
|
227
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
228
|
+
return Math.round((bytes / Math.pow(k, i)) * 100) / 100 + ' ' + sizes[i];
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
export default {
|
|
232
|
+
checkFScriptsFile,
|
|
233
|
+
checkPackageJson,
|
|
234
|
+
checkTypeScript,
|
|
235
|
+
checkFilePermissions
|
|
236
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { execSync } from 'child_process';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Check Git installation
|
|
6
|
+
* @param {Object} options - Check options
|
|
7
|
+
* @returns {Object} Check result
|
|
8
|
+
*/
|
|
9
|
+
export async function checkGit(options = {}) {
|
|
10
|
+
const result = {
|
|
11
|
+
name: 'Git',
|
|
12
|
+
passed: false,
|
|
13
|
+
warning: false,
|
|
14
|
+
message: '',
|
|
15
|
+
details: {},
|
|
16
|
+
canFix: false,
|
|
17
|
+
fix: null
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
const version = execSync('git --version', {
|
|
22
|
+
encoding: 'utf8',
|
|
23
|
+
stdio: ['pipe', 'pipe', 'pipe']
|
|
24
|
+
}).trim();
|
|
25
|
+
|
|
26
|
+
result.passed = true;
|
|
27
|
+
result.message = version;
|
|
28
|
+
result.details = {
|
|
29
|
+
version: version
|
|
30
|
+
};
|
|
31
|
+
} catch (error) {
|
|
32
|
+
result.passed = false;
|
|
33
|
+
result.message = 'Not installed';
|
|
34
|
+
result.canFix = false;
|
|
35
|
+
result.fixInstructions = 'Please install Git.\nVisit: https://git-scm.com/downloads';
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return result;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export default checkGit;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { execSync } from 'child_process';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Compare two version strings
|
|
6
|
+
* @param {string} v1 - First version
|
|
7
|
+
* @param {string} v2 - Second version
|
|
8
|
+
* @returns {boolean} True if v1 >= v2
|
|
9
|
+
*/
|
|
10
|
+
function versionGte(v1, v2) {
|
|
11
|
+
const parts1 = v1.split('.').map(Number);
|
|
12
|
+
const parts2 = v2.split('.').map(Number);
|
|
13
|
+
|
|
14
|
+
for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) {
|
|
15
|
+
const p1 = parts1[i] || 0;
|
|
16
|
+
const p2 = parts2[i] || 0;
|
|
17
|
+
|
|
18
|
+
if (p1 > p2) return true;
|
|
19
|
+
if (p1 < p2) return false;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return true; // Equal
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Check Node.js version
|
|
27
|
+
* @param {Object} options - Check options
|
|
28
|
+
* @returns {Object} Check result
|
|
29
|
+
*/
|
|
30
|
+
export async function checkNodeVersion(options = {}) {
|
|
31
|
+
const minVersion = options.minVersion || '18.0.0';
|
|
32
|
+
const result = {
|
|
33
|
+
name: 'Node.js version',
|
|
34
|
+
passed: false,
|
|
35
|
+
warning: false,
|
|
36
|
+
message: '',
|
|
37
|
+
details: {},
|
|
38
|
+
canFix: false,
|
|
39
|
+
fix: null
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
try {
|
|
43
|
+
const currentVersion = process.version.replace('v', '');
|
|
44
|
+
const recommended = minVersion;
|
|
45
|
+
|
|
46
|
+
result.details = {
|
|
47
|
+
current: currentVersion,
|
|
48
|
+
required: `>=${recommended}`
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
if (versionGte(currentVersion, recommended)) {
|
|
52
|
+
result.passed = true;
|
|
53
|
+
result.message = `v${currentVersion} (recommended: >=${recommended})`;
|
|
54
|
+
} else {
|
|
55
|
+
result.passed = false;
|
|
56
|
+
result.message = `v${currentVersion} is below recommended version >=${recommended}`;
|
|
57
|
+
result.canFix = false; // Cannot auto-fix Node.js version
|
|
58
|
+
result.fixInstructions = `Please upgrade Node.js to version ${recommended} or higher.\nVisit: https://nodejs.org/`;
|
|
59
|
+
}
|
|
60
|
+
} catch (error) {
|
|
61
|
+
result.passed = false;
|
|
62
|
+
result.message = `Failed to check Node.js version: ${error.message}`;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return result;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export default checkNodeVersion;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { execSync } from 'child_process';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Check package manager installation
|
|
6
|
+
* @param {Object} options - Check options
|
|
7
|
+
* @returns {Object} Check result
|
|
8
|
+
*/
|
|
9
|
+
export async function checkPackageManager(options = {}) {
|
|
10
|
+
const result = {
|
|
11
|
+
name: 'Package manager',
|
|
12
|
+
passed: false,
|
|
13
|
+
warning: false,
|
|
14
|
+
message: '',
|
|
15
|
+
details: {},
|
|
16
|
+
canFix: false,
|
|
17
|
+
fix: null
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
// Detect which package manager is being used
|
|
22
|
+
let packageManager = 'npm';
|
|
23
|
+
let version = '';
|
|
24
|
+
|
|
25
|
+
// Check for yarn.lock
|
|
26
|
+
try {
|
|
27
|
+
const fs = await import('fs');
|
|
28
|
+
if (fs.existsSync('yarn.lock')) {
|
|
29
|
+
packageManager = 'yarn';
|
|
30
|
+
} else if (fs.existsSync('pnpm-lock.yaml')) {
|
|
31
|
+
packageManager = 'pnpm';
|
|
32
|
+
}
|
|
33
|
+
} catch (err) {
|
|
34
|
+
// Default to npm
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Get version
|
|
38
|
+
try {
|
|
39
|
+
version = execSync(`${packageManager} --version`, {
|
|
40
|
+
encoding: 'utf8',
|
|
41
|
+
stdio: ['pipe', 'pipe', 'pipe']
|
|
42
|
+
}).trim();
|
|
43
|
+
|
|
44
|
+
result.passed = true;
|
|
45
|
+
result.message = `${packageManager} ${version} installed`;
|
|
46
|
+
result.details = {
|
|
47
|
+
manager: packageManager,
|
|
48
|
+
version: version
|
|
49
|
+
};
|
|
50
|
+
} catch (error) {
|
|
51
|
+
result.passed = false;
|
|
52
|
+
result.message = `${packageManager} not found`;
|
|
53
|
+
result.canFix = false;
|
|
54
|
+
result.fixInstructions = `Please install ${packageManager}.\nVisit: https://docs.npmjs.com/downloading-and-installing-node-js-and-npm`;
|
|
55
|
+
}
|
|
56
|
+
} catch (error) {
|
|
57
|
+
result.passed = false;
|
|
58
|
+
result.message = `Failed to check package manager: ${error.message}`;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return result;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export default checkPackageManager;
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { performance } from 'perf_hooks';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Check startup time
|
|
6
|
+
* @param {Object} options - Check options
|
|
7
|
+
* @returns {Object} Check result
|
|
8
|
+
*/
|
|
9
|
+
export async function checkStartupTime(options = {}) {
|
|
10
|
+
const result = {
|
|
11
|
+
name: 'Startup time',
|
|
12
|
+
passed: false,
|
|
13
|
+
warning: false,
|
|
14
|
+
message: '',
|
|
15
|
+
details: {},
|
|
16
|
+
canFix: false,
|
|
17
|
+
fix: null
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
// Calculate startup time from process start
|
|
22
|
+
const startupTime = performance.now();
|
|
23
|
+
const targetTime = 50; // 50ms target
|
|
24
|
+
|
|
25
|
+
result.details = {
|
|
26
|
+
time: startupTime,
|
|
27
|
+
target: targetTime,
|
|
28
|
+
unit: 'ms'
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
if (startupTime <= targetTime) {
|
|
32
|
+
result.passed = true;
|
|
33
|
+
result.message = `${startupTime.toFixed(2)}ms (target: <${targetTime}ms)`;
|
|
34
|
+
} else if (startupTime <= targetTime * 2) {
|
|
35
|
+
result.passed = true;
|
|
36
|
+
result.warning = true;
|
|
37
|
+
result.message = `${startupTime.toFixed(2)}ms (slightly above target of ${targetTime}ms)`;
|
|
38
|
+
} else {
|
|
39
|
+
result.passed = false;
|
|
40
|
+
result.message = `${startupTime.toFixed(2)}ms (target: <${targetTime}ms)`;
|
|
41
|
+
result.fixInstructions = 'Consider clearing cache or reducing number of plugins/hooks.';
|
|
42
|
+
}
|
|
43
|
+
} catch (error) {
|
|
44
|
+
result.passed = false;
|
|
45
|
+
result.message = `Failed to check startup time: ${error.message}`;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return result;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Check memory usage
|
|
53
|
+
* @param {Object} options - Check options
|
|
54
|
+
* @returns {Object} Check result
|
|
55
|
+
*/
|
|
56
|
+
export async function checkMemoryUsage(options = {}) {
|
|
57
|
+
const result = {
|
|
58
|
+
name: 'Memory usage',
|
|
59
|
+
passed: false,
|
|
60
|
+
warning: false,
|
|
61
|
+
message: '',
|
|
62
|
+
details: {},
|
|
63
|
+
canFix: false,
|
|
64
|
+
fix: null
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
try {
|
|
68
|
+
const usage = process.memoryUsage();
|
|
69
|
+
const heapUsedMB = Math.round((usage.heapUsed / 1024 / 1024) * 100) / 100;
|
|
70
|
+
const externalMB = Math.round((usage.external / 1024 / 1024) * 100) / 100;
|
|
71
|
+
const totalMB = heapUsedMB + externalMB;
|
|
72
|
+
const targetMB = 50; // 50MB target
|
|
73
|
+
|
|
74
|
+
result.details = {
|
|
75
|
+
heapUsed: heapUsedMB,
|
|
76
|
+
external: externalMB,
|
|
77
|
+
total: totalMB,
|
|
78
|
+
unit: 'MB',
|
|
79
|
+
raw: usage
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
if (totalMB <= targetMB) {
|
|
83
|
+
result.passed = true;
|
|
84
|
+
result.message = `${totalMB}MB (target: <${targetMB}MB)`;
|
|
85
|
+
} else if (totalMB <= targetMB * 1.5) {
|
|
86
|
+
result.passed = true;
|
|
87
|
+
result.warning = true;
|
|
88
|
+
result.message = `${totalMB}MB (slightly above target of ${targetMB}MB)`;
|
|
89
|
+
} else {
|
|
90
|
+
result.passed = false;
|
|
91
|
+
result.message = `${totalMB}MB (target: <${targetMB}MB)`;
|
|
92
|
+
result.fixInstructions = 'Memory usage is high. Consider optimizing dependencies or clearing cache.';
|
|
93
|
+
}
|
|
94
|
+
} catch (error) {
|
|
95
|
+
result.passed = false;
|
|
96
|
+
result.message = `Failed to check memory usage: ${error.message}`;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return result;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Run performance benchmark
|
|
104
|
+
* @param {Object} options - Benchmark options
|
|
105
|
+
* @returns {Object} Benchmark result
|
|
106
|
+
*/
|
|
107
|
+
export async function runBenchmark(options = {}) {
|
|
108
|
+
const runs = options.runs || 5;
|
|
109
|
+
const results = [];
|
|
110
|
+
|
|
111
|
+
for (let i = 0; i < runs; i++) {
|
|
112
|
+
const start = performance.now();
|
|
113
|
+
|
|
114
|
+
// Simulate a typical FSCR operation (parsing scripts file)
|
|
115
|
+
// In real implementation, this would run actual operations
|
|
116
|
+
await new Promise((resolve) => setTimeout(resolve, 1));
|
|
117
|
+
|
|
118
|
+
const end = performance.now();
|
|
119
|
+
results.push(end - start);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const avg = results.reduce((a, b) => a + b, 0) / results.length;
|
|
123
|
+
const min = Math.min(...results);
|
|
124
|
+
const max = Math.max(...results);
|
|
125
|
+
const median = results.sort((a, b) => a - b)[Math.floor(results.length / 2)];
|
|
126
|
+
|
|
127
|
+
return {
|
|
128
|
+
average: avg,
|
|
129
|
+
median: median,
|
|
130
|
+
min: min,
|
|
131
|
+
max: max,
|
|
132
|
+
runs: runs,
|
|
133
|
+
results: results
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export default {
|
|
138
|
+
checkStartupTime,
|
|
139
|
+
checkMemoryUsage,
|
|
140
|
+
runBenchmark
|
|
141
|
+
};
|