-
Notifications
You must be signed in to change notification settings - Fork 654
Expand file tree
/
Copy pathvalidator.ts
More file actions
140 lines (120 loc) · 3.64 KB
/
Copy pathvalidator.ts
File metadata and controls
140 lines (120 loc) · 3.64 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
import { assert } from '@metamask/utils';
import type {
ValidatorContext,
ValidatorContextOptions,
ValidatorFix,
ValidatorMeta,
ValidatorReport,
ValidatorSeverity,
} from './validator-types';
import * as defaultValidators from './validators';
import type { SnapFiles, UnvalidatedSnapFiles } from '../types';
export type ValidatorResults = {
files?: SnapFiles;
reports: ValidatorReport[];
};
class Context implements ValidatorContext {
reports: ValidatorReport[] = [];
readonly #options: ValidatorContextOptions = {};
#nextSeverity?: ValidatorSeverity = undefined;
/**
* Construct a new validator context.
*
* @param options - The options for the validator context.
* @param options.exports - Exports detected by evaluating the bundle.
*/
constructor(options: ValidatorContextOptions) {
this.#options = options;
}
/**
* Report a validation error or warning.
*
* @param id - The unique identifier for the report.
* @param message - The message describing the validation issue.
* @param fix - An optional fix function that can be used to automatically
* resolve the issue.
*/
report(id: string, message: string, fix?: ValidatorFix): void {
assert(this.#nextSeverity !== undefined);
this.reports.push({
id,
message,
fix,
severity: this.#nextSeverity,
});
}
prepareForValidator(settings: { severity: ValidatorSeverity }) {
this.#nextSeverity = settings.severity;
}
get hasErrors() {
return this.reports.some((report) => report.severity === 'error');
}
get options() {
return this.#options;
}
}
/**
* Verify that snap files are completely valid.
* First it runs validators on unparsed files to check structure.
* Secondly it runs validators on parsed files to check semantics.
*
* @param files - All files required to run a snap.
* @param rules - Validators to run.
* @param options - Options for the validation.
* @param options.exports - Exports detected by evaluating the bundle.
* @returns The validation results.
*/
// TODO(ritave): snap.manifest.json and package.json should check
// json parsing as well instead of assuming it's
// already parsed
export async function runValidators(
files: UnvalidatedSnapFiles,
rules: ValidatorMeta[] = Object.values(defaultValidators),
options: ValidatorContextOptions = {},
): Promise<ValidatorResults> {
const context = new Context(options);
for (const rule of rules) {
context.prepareForValidator({
severity: rule.severity,
});
await rule.structureCheck?.(files, context);
}
if (context.hasErrors) {
return {
reports: context.reports,
};
}
for (const rule of rules) {
context.prepareForValidator({
severity: rule.severity,
});
await rule.semanticCheck?.(files as SnapFiles, context);
}
return {
files: files as SnapFiles,
reports: context.reports,
};
}
/**
* Check whether a report is fixable.
*
* @param report - The report to check.
* @param errorsOnly - Whether to only consider errors for fixability.
* @returns Whether the report is fixable.
*/
export function isReportFixable(report: ValidatorReport, errorsOnly?: boolean) {
return Boolean(report.fix && (!errorsOnly || report.severity === 'error'));
}
/**
* Get whether any reports has pending fixes.
*
* @param results - Results of the validation run.
* @param errorsOnly - Whether to only consider errors for pending fixes.
* @returns Whether there are fixes pending.
*/
export function hasFixes(
results: ValidatorResults,
errorsOnly?: boolean,
): boolean {
return results.reports.some((report) => isReportFixable(report, errorsOnly));
}