spec-up-t-healthcheck 1.0.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 +216 -0
- package/bin/cli.js +193 -0
- package/bin/demo-html.js +186 -0
- package/bin/simple-test.js +79 -0
- package/lib/checks/external-specs-urls.js +484 -0
- package/lib/checks/gitignore.js +350 -0
- package/lib/checks/package-json.js +518 -0
- package/lib/checks/spec-files.js +263 -0
- package/lib/checks/specsjson.js +361 -0
- package/lib/file-opener.js +127 -0
- package/lib/formatters.js +176 -0
- package/lib/health-check-orchestrator.js +413 -0
- package/lib/health-check-registry.js +396 -0
- package/lib/health-check-utils.js +234 -0
- package/lib/health-checker.js +145 -0
- package/lib/html-formatter.js +626 -0
- package/lib/index.js +123 -0
- package/lib/providers.js +184 -0
- package/lib/web.js +70 -0
- package/package.json +91 -0
|
@@ -0,0 +1,518 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Package.json health check module
|
|
3
|
+
*
|
|
4
|
+
* This module validates the existence and structure of package.json files in
|
|
5
|
+
* specification repositories. It ensures that essential package metadata is
|
|
6
|
+
* present and properly formatted for Node.js compatibility.
|
|
7
|
+
*
|
|
8
|
+
* It also validates spec-up-t specific requirements:
|
|
9
|
+
* - Presence of spec-up-t dependency with correct version range
|
|
10
|
+
* - Required npm scripts from configScriptsKeys
|
|
11
|
+
*
|
|
12
|
+
* @author spec-up-t-healthcheck
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { createHealthCheckResult, createErrorResult } from '../health-check-utils.js';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* The identifier for this health check, used in reports and registries.
|
|
19
|
+
* @type {string}
|
|
20
|
+
*/
|
|
21
|
+
export const CHECK_ID = 'package-json';
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Human-readable name for this health check.
|
|
25
|
+
* @type {string}
|
|
26
|
+
*/
|
|
27
|
+
export const CHECK_NAME = 'Package.json Validation';
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Description of what this health check validates.
|
|
31
|
+
* @type {string}
|
|
32
|
+
*/
|
|
33
|
+
export const CHECK_DESCRIPTION = 'Validates the existence and structure of package.json file';
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Required fields that must be present in a valid package.json file.
|
|
37
|
+
* These fields are essential for proper Node.js package identification.
|
|
38
|
+
* @type {readonly string[]}
|
|
39
|
+
*/
|
|
40
|
+
const REQUIRED_FIELDS = Object.freeze(['name', 'version']);
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Recommended fields that should be present in a well-formed package.json.
|
|
44
|
+
* Missing these fields will generate warnings rather than failures.
|
|
45
|
+
* @type {readonly string[]}
|
|
46
|
+
*/
|
|
47
|
+
const RECOMMENDED_FIELDS = Object.freeze(['description', 'author', 'license']);
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* GitHub URL for the starter pack repository that defines the reference configuration.
|
|
51
|
+
* This is used to fetch the latest recommended spec-up-t version dynamically.
|
|
52
|
+
* @type {string}
|
|
53
|
+
*/
|
|
54
|
+
const STARTER_PACK_PACKAGE_URL = 'https://raw.githubusercontent.com/trustoverip/spec-up-t-starter-pack/main/package.spec-up-t.json';
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* GitHub URL for the config scripts keys that define required npm scripts.
|
|
58
|
+
* This is used to fetch the latest required scripts dynamically.
|
|
59
|
+
* @type {string}
|
|
60
|
+
*/
|
|
61
|
+
const CONFIG_SCRIPTS_URL = 'https://raw.githubusercontent.com/trustoverip/spec-up-t/master/src/install-from-boilerplate/config-scripts-keys.js';
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Cache duration for fetched external configuration (in milliseconds).
|
|
65
|
+
* Set to 1 hour to avoid excessive network requests while keeping data reasonably fresh.
|
|
66
|
+
* @type {number}
|
|
67
|
+
*/
|
|
68
|
+
const CACHE_DURATION = 60 * 60 * 1000; // 1 hour
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* In-memory cache for external configuration data.
|
|
72
|
+
* @type {Object}
|
|
73
|
+
* @private
|
|
74
|
+
*/
|
|
75
|
+
let configCache = {
|
|
76
|
+
starterPackVersion: null,
|
|
77
|
+
configScripts: null,
|
|
78
|
+
lastFetch: 0
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Fetches the latest spec-up-t version from the starter pack repository.
|
|
83
|
+
*
|
|
84
|
+
* This function retrieves the reference package.json from the spec-up-t-starter-pack
|
|
85
|
+
* repository to determine the currently recommended spec-up-t version. Results are
|
|
86
|
+
* cached to minimize network requests.
|
|
87
|
+
*
|
|
88
|
+
* @returns {Promise<string|null>} The spec-up-t version string (e.g., "^1.3.0") or null if fetch fails
|
|
89
|
+
* @private
|
|
90
|
+
*/
|
|
91
|
+
async function fetchStarterPackVersion() {
|
|
92
|
+
const now = Date.now();
|
|
93
|
+
|
|
94
|
+
// Return cached version if still valid
|
|
95
|
+
if (configCache.starterPackVersion && (now - configCache.lastFetch) < CACHE_DURATION) {
|
|
96
|
+
return configCache.starterPackVersion;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
try {
|
|
100
|
+
const response = await fetch(STARTER_PACK_PACKAGE_URL);
|
|
101
|
+
if (!response.ok) {
|
|
102
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const packageData = await response.json();
|
|
106
|
+
const version = packageData?.dependencies?.[`spec-up-t`];
|
|
107
|
+
|
|
108
|
+
if (version) {
|
|
109
|
+
configCache.starterPackVersion = version;
|
|
110
|
+
configCache.lastFetch = now;
|
|
111
|
+
return version;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return null;
|
|
115
|
+
} catch (error) {
|
|
116
|
+
// Return cached version if available, even if expired
|
|
117
|
+
return configCache.starterPackVersion || null;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Fetches the required npm scripts from the config-scripts-keys.js file.
|
|
123
|
+
*
|
|
124
|
+
* This function retrieves the reference configScriptsKeys from the spec-up-t
|
|
125
|
+
* repository to determine which npm scripts should be present. Results are
|
|
126
|
+
* cached to minimize network requests.
|
|
127
|
+
*
|
|
128
|
+
* @returns {Promise<Object|null>} The configScriptsKeys object or null if fetch fails
|
|
129
|
+
* @private
|
|
130
|
+
*/
|
|
131
|
+
async function fetchConfigScriptsKeys() {
|
|
132
|
+
const now = Date.now();
|
|
133
|
+
|
|
134
|
+
// Return cached scripts if still valid
|
|
135
|
+
if (configCache.configScripts && (now - configCache.lastFetch) < CACHE_DURATION) {
|
|
136
|
+
return configCache.configScripts;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
try {
|
|
140
|
+
const response = await fetch(CONFIG_SCRIPTS_URL);
|
|
141
|
+
if (!response.ok) {
|
|
142
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const scriptContent = await response.text();
|
|
146
|
+
|
|
147
|
+
// Extract configScriptsKeys using regex since we're parsing JS, not JSON
|
|
148
|
+
const match = scriptContent.match(/const configScriptsKeys = ({[\s\S]*?});/);
|
|
149
|
+
if (!match) {
|
|
150
|
+
return null;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Convert the JavaScript object literal to JSON
|
|
154
|
+
// This is a simplified parser that handles the specific format used
|
|
155
|
+
const scriptsObj = parseConfigScriptsObject(match[1]);
|
|
156
|
+
|
|
157
|
+
if (scriptsObj) {
|
|
158
|
+
configCache.configScripts = scriptsObj;
|
|
159
|
+
configCache.lastFetch = now;
|
|
160
|
+
return scriptsObj;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return null;
|
|
164
|
+
} catch (error) {
|
|
165
|
+
// Return cached scripts if available, even if expired
|
|
166
|
+
return configCache.configScripts || null;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Parses a JavaScript object literal string into a proper object.
|
|
172
|
+
*
|
|
173
|
+
* This function handles the specific format used in config-scripts-keys.js,
|
|
174
|
+
* extracting key-value pairs from the object literal. It uses a simple
|
|
175
|
+
* regex-based approach suitable for the expected format.
|
|
176
|
+
*
|
|
177
|
+
* @param {string} objStr - The JavaScript object literal string
|
|
178
|
+
* @returns {Object|null} The parsed object or null if parsing fails
|
|
179
|
+
* @private
|
|
180
|
+
*/
|
|
181
|
+
function parseConfigScriptsObject(objStr) {
|
|
182
|
+
try {
|
|
183
|
+
// Extract all key-value pairs from the object literal
|
|
184
|
+
// Handles escaped quotes within string values
|
|
185
|
+
const pairs = objStr.matchAll(/^\s*"([^"]+)":\s*"((?:[^"\\]|\\.)*)"/gm);
|
|
186
|
+
const result = {};
|
|
187
|
+
|
|
188
|
+
for (const match of pairs) {
|
|
189
|
+
// Unescape the captured value to match JSON-parsed strings
|
|
190
|
+
const unescapedValue = match[2].replace(/\\"/g, '"').replace(/\\\\/g, '\\');
|
|
191
|
+
result[match[1]] = unescapedValue;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return Object.keys(result).length > 0 ? result : null;
|
|
195
|
+
} catch (error) {
|
|
196
|
+
return null;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Validates that the spec-up-t dependency is present and has a compatible version.
|
|
202
|
+
*
|
|
203
|
+
* This function checks if:
|
|
204
|
+
* - The spec-up-t dependency exists in package.json
|
|
205
|
+
* - The version range is compatible with the reference version from the starter pack
|
|
206
|
+
*
|
|
207
|
+
* @param {Object} packageData - The parsed package.json data
|
|
208
|
+
* @param {string|null} referenceVersion - The reference version from starter pack
|
|
209
|
+
* @returns {Object} Validation result with status and details
|
|
210
|
+
* @private
|
|
211
|
+
*/
|
|
212
|
+
function validateSpecUpTDependency(packageData, referenceVersion) {
|
|
213
|
+
const dependencies = packageData.dependencies || {};
|
|
214
|
+
const devDependencies = packageData.devDependencies || {};
|
|
215
|
+
const allDeps = { ...dependencies, ...devDependencies };
|
|
216
|
+
|
|
217
|
+
const specUpTVersion = allDeps['spec-up-t'];
|
|
218
|
+
|
|
219
|
+
// Check if spec-up-t dependency exists
|
|
220
|
+
if (!specUpTVersion) {
|
|
221
|
+
return {
|
|
222
|
+
isValid: false,
|
|
223
|
+
severity: 'fail',
|
|
224
|
+
message: 'spec-up-t dependency not found in dependencies or devDependencies',
|
|
225
|
+
details: {
|
|
226
|
+
expectedInDependencies: true,
|
|
227
|
+
foundInDependencies: false
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// If we couldn't fetch the reference version, just verify presence
|
|
233
|
+
if (!referenceVersion) {
|
|
234
|
+
return {
|
|
235
|
+
isValid: true,
|
|
236
|
+
severity: 'warn',
|
|
237
|
+
message: 'spec-up-t dependency found, but could not verify version against starter pack (network issue)',
|
|
238
|
+
details: {
|
|
239
|
+
currentVersion: specUpTVersion,
|
|
240
|
+
referenceVersionUnavailable: true
|
|
241
|
+
}
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// Compare version ranges
|
|
246
|
+
const versionMatch = specUpTVersion === referenceVersion;
|
|
247
|
+
|
|
248
|
+
if (!versionMatch) {
|
|
249
|
+
return {
|
|
250
|
+
isValid: false,
|
|
251
|
+
severity: 'warn',
|
|
252
|
+
message: `spec-up-t version differs from starter pack recommendation`,
|
|
253
|
+
details: {
|
|
254
|
+
currentVersion: specUpTVersion,
|
|
255
|
+
recommendedVersion: referenceVersion,
|
|
256
|
+
starterPackUrl: STARTER_PACK_PACKAGE_URL
|
|
257
|
+
}
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
return {
|
|
262
|
+
isValid: true,
|
|
263
|
+
severity: 'pass',
|
|
264
|
+
message: 'spec-up-t dependency is correctly configured',
|
|
265
|
+
details: {
|
|
266
|
+
currentVersion: specUpTVersion,
|
|
267
|
+
matchesStarterPack: true
|
|
268
|
+
}
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Validates that required npm scripts are present in package.json.
|
|
274
|
+
*
|
|
275
|
+
* This function checks if the required scripts from configScriptsKeys are
|
|
276
|
+
* present in the package.json scripts section. It reports missing scripts
|
|
277
|
+
* and scripts with different implementations.
|
|
278
|
+
*
|
|
279
|
+
* @param {Object} packageData - The parsed package.json data
|
|
280
|
+
* @param {Object|null} configScriptsKeys - The reference scripts from spec-up-t
|
|
281
|
+
* @returns {Object} Validation result with status and details
|
|
282
|
+
* @private
|
|
283
|
+
*/
|
|
284
|
+
function validateScripts(packageData, configScriptsKeys) {
|
|
285
|
+
const packageScripts = packageData.scripts || {};
|
|
286
|
+
|
|
287
|
+
// If we couldn't fetch the reference scripts, skip validation
|
|
288
|
+
if (!configScriptsKeys) {
|
|
289
|
+
return {
|
|
290
|
+
isValid: true,
|
|
291
|
+
severity: 'warn',
|
|
292
|
+
message: 'Could not verify npm scripts against spec-up-t reference (network issue)',
|
|
293
|
+
details: {
|
|
294
|
+
referenceScriptsUnavailable: true,
|
|
295
|
+
scriptCount: Object.keys(packageScripts).length
|
|
296
|
+
}
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
const missingScripts = [];
|
|
301
|
+
const differentScripts = [];
|
|
302
|
+
|
|
303
|
+
// Check each required script
|
|
304
|
+
for (const [scriptName, expectedCommand] of Object.entries(configScriptsKeys)) {
|
|
305
|
+
if (!packageScripts[scriptName]) {
|
|
306
|
+
missingScripts.push(scriptName);
|
|
307
|
+
} else if (packageScripts[scriptName] !== expectedCommand) {
|
|
308
|
+
differentScripts.push({
|
|
309
|
+
name: scriptName,
|
|
310
|
+
current: packageScripts[scriptName],
|
|
311
|
+
expected: expectedCommand
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// Determine severity based on what's missing or different
|
|
317
|
+
if (missingScripts.length > 0) {
|
|
318
|
+
return {
|
|
319
|
+
isValid: false,
|
|
320
|
+
severity: 'fail',
|
|
321
|
+
message: `Missing required npm scripts: ${missingScripts.join(', ')}`,
|
|
322
|
+
details: {
|
|
323
|
+
missingScripts,
|
|
324
|
+
differentScripts: differentScripts.length > 0 ? differentScripts : undefined,
|
|
325
|
+
totalRequired: Object.keys(configScriptsKeys).length,
|
|
326
|
+
configScriptsUrl: CONFIG_SCRIPTS_URL
|
|
327
|
+
}
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
if (differentScripts.length > 0) {
|
|
332
|
+
return {
|
|
333
|
+
isValid: false,
|
|
334
|
+
severity: 'warn',
|
|
335
|
+
message: `Some npm scripts differ from spec-up-t reference: ${differentScripts.map(s => s.name).join(', ')}`,
|
|
336
|
+
details: {
|
|
337
|
+
differentScripts,
|
|
338
|
+
configScriptsUrl: CONFIG_SCRIPTS_URL
|
|
339
|
+
}
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
return {
|
|
344
|
+
isValid: true,
|
|
345
|
+
severity: 'pass',
|
|
346
|
+
message: 'All required npm scripts are present and correct',
|
|
347
|
+
details: {
|
|
348
|
+
scriptCount: Object.keys(packageScripts).length,
|
|
349
|
+
requiredScriptCount: Object.keys(configScriptsKeys).length,
|
|
350
|
+
allScriptsMatch: true
|
|
351
|
+
}
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* Validates the existence and structure of package.json in a repository.
|
|
357
|
+
*
|
|
358
|
+
* This health check ensures that a valid package.json file exists at the repository root
|
|
359
|
+
* and contains the required fields for a proper Node.js package. It checks for the
|
|
360
|
+
* presence of essential metadata and validates JSON structure.
|
|
361
|
+
*
|
|
362
|
+
* The check performs the following validations:
|
|
363
|
+
* - File exists at repository root
|
|
364
|
+
* - File contains valid JSON
|
|
365
|
+
* - Required fields (name, version) are present
|
|
366
|
+
* - Recommended fields are present (warnings if missing)
|
|
367
|
+
* - spec-up-t dependency is present with correct version
|
|
368
|
+
* - Required npm scripts from configScriptsKeys are present
|
|
369
|
+
*
|
|
370
|
+
* @param {import('../providers.js').Provider} provider - The provider instance for file operations
|
|
371
|
+
* @returns {Promise<import('../health-check-utils.js').HealthCheckResult>} The health check result with validation details
|
|
372
|
+
*
|
|
373
|
+
* @example
|
|
374
|
+
* ```javascript
|
|
375
|
+
* const provider = createLocalProvider('/path/to/repo');
|
|
376
|
+
* const result = await checkPackageJson(provider);
|
|
377
|
+
* console.log(result.status); // 'pass', 'fail', or 'warn'
|
|
378
|
+
* ```
|
|
379
|
+
*/
|
|
380
|
+
export async function checkPackageJson(provider) {
|
|
381
|
+
try {
|
|
382
|
+
// Check if package.json exists
|
|
383
|
+
const exists = await provider.fileExists('package.json');
|
|
384
|
+
if (!exists) {
|
|
385
|
+
return createHealthCheckResult(
|
|
386
|
+
CHECK_NAME,
|
|
387
|
+
'fail',
|
|
388
|
+
'package.json not found in repository root'
|
|
389
|
+
);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// Read and parse the package.json file
|
|
393
|
+
const content = await provider.readFile('package.json');
|
|
394
|
+
let packageData;
|
|
395
|
+
|
|
396
|
+
try {
|
|
397
|
+
packageData = JSON.parse(content);
|
|
398
|
+
} catch (parseError) {
|
|
399
|
+
return createHealthCheckResult(
|
|
400
|
+
CHECK_NAME,
|
|
401
|
+
'fail',
|
|
402
|
+
'package.json contains invalid JSON',
|
|
403
|
+
{
|
|
404
|
+
parseError: parseError.message,
|
|
405
|
+
fileContent: content.substring(0, 500) + (content.length > 500 ? '...' : '')
|
|
406
|
+
}
|
|
407
|
+
);
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
// Validate required fields
|
|
411
|
+
const missingRequired = REQUIRED_FIELDS.filter(field =>
|
|
412
|
+
!packageData[field] || (typeof packageData[field] === 'string' && packageData[field].trim() === '')
|
|
413
|
+
);
|
|
414
|
+
|
|
415
|
+
if (missingRequired.length > 0) {
|
|
416
|
+
return createHealthCheckResult(
|
|
417
|
+
CHECK_NAME,
|
|
418
|
+
'fail',
|
|
419
|
+
`Missing required fields: ${missingRequired.join(', ')}`,
|
|
420
|
+
{
|
|
421
|
+
missingRequired,
|
|
422
|
+
presentFields: Object.keys(packageData),
|
|
423
|
+
packageSample: extractPackageSample(packageData)
|
|
424
|
+
}
|
|
425
|
+
);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// Fetch external reference data (with caching)
|
|
429
|
+
const [referenceVersion, configScriptsKeys] = await Promise.all([
|
|
430
|
+
fetchStarterPackVersion(),
|
|
431
|
+
fetchConfigScriptsKeys()
|
|
432
|
+
]);
|
|
433
|
+
|
|
434
|
+
// Validate spec-up-t dependency
|
|
435
|
+
const depValidation = validateSpecUpTDependency(packageData, referenceVersion);
|
|
436
|
+
|
|
437
|
+
// Validate npm scripts
|
|
438
|
+
const scriptsValidation = validateScripts(packageData, configScriptsKeys);
|
|
439
|
+
|
|
440
|
+
// Check for recommended fields (warnings)
|
|
441
|
+
const missingRecommended = RECOMMENDED_FIELDS.filter(field =>
|
|
442
|
+
!packageData[field] || (typeof packageData[field] === 'string' && packageData[field].trim() === '')
|
|
443
|
+
);
|
|
444
|
+
|
|
445
|
+
// Aggregate all validation results
|
|
446
|
+
const details = {
|
|
447
|
+
packageSample: extractPackageSample(packageData),
|
|
448
|
+
hasAllRequired: true,
|
|
449
|
+
missingRecommended,
|
|
450
|
+
fieldCount: Object.keys(packageData).length,
|
|
451
|
+
dependency: depValidation.details,
|
|
452
|
+
scripts: scriptsValidation.details
|
|
453
|
+
};
|
|
454
|
+
|
|
455
|
+
// Determine overall status based on all validations
|
|
456
|
+
const validations = [
|
|
457
|
+
{ severity: missingRecommended.length > 0 ? 'warn' : 'pass', message: missingRecommended.length > 0 ? `Missing recommended fields: ${missingRecommended.join(', ')}` : null },
|
|
458
|
+
{ severity: depValidation.severity, message: depValidation.message },
|
|
459
|
+
{ severity: scriptsValidation.severity, message: scriptsValidation.message }
|
|
460
|
+
];
|
|
461
|
+
|
|
462
|
+
// Priority: fail > warn > pass
|
|
463
|
+
const hasFail = validations.some(v => v.severity === 'fail');
|
|
464
|
+
const hasWarn = validations.some(v => v.severity === 'warn');
|
|
465
|
+
|
|
466
|
+
let overallStatus = 'pass';
|
|
467
|
+
let messages = [];
|
|
468
|
+
|
|
469
|
+
if (hasFail) {
|
|
470
|
+
overallStatus = 'fail';
|
|
471
|
+
messages = validations.filter(v => v.severity === 'fail').map(v => v.message);
|
|
472
|
+
} else if (hasWarn) {
|
|
473
|
+
overallStatus = 'warn';
|
|
474
|
+
messages = validations.filter(v => v.severity === 'warn').map(v => v.message);
|
|
475
|
+
} else {
|
|
476
|
+
messages = ['package.json is valid and well-formed with correct spec-up-t configuration'];
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
return createHealthCheckResult(
|
|
480
|
+
CHECK_NAME,
|
|
481
|
+
overallStatus,
|
|
482
|
+
messages.join('; '),
|
|
483
|
+
details
|
|
484
|
+
);
|
|
485
|
+
|
|
486
|
+
} catch (error) {
|
|
487
|
+
return createErrorResult(CHECK_NAME, error, {
|
|
488
|
+
context: 'checking package.json file',
|
|
489
|
+
provider: provider.type
|
|
490
|
+
});
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
/**
|
|
495
|
+
* Extracts a safe sample of package.json data for reporting purposes.
|
|
496
|
+
*
|
|
497
|
+
* This function creates a sanitized version of package data that can be safely
|
|
498
|
+
* included in health check results without exposing sensitive information.
|
|
499
|
+
*
|
|
500
|
+
* @param {Object} packageData - The parsed package.json data
|
|
501
|
+
* @returns {Object} A sanitized sample of the package data
|
|
502
|
+
* @private
|
|
503
|
+
*/
|
|
504
|
+
function extractPackageSample(packageData) {
|
|
505
|
+
const safeFields = ['name', 'version', 'description', 'author', 'license'];
|
|
506
|
+
const sample = {};
|
|
507
|
+
|
|
508
|
+
for (const field of safeFields) {
|
|
509
|
+
if (packageData[field]) {
|
|
510
|
+
sample[field] = packageData[field];
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
return sample;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
// Export the health check function as default for easy registration
|
|
518
|
+
export default checkPackageJson;
|