Setting the file. One moment.
Setup Verification · Wix Replatform · wix/skills · Skills Docs
ContentsBack to the top of the page lib/setup-verification.js
lib/ setup-verification.js
JavaScript · 102 lines · 4 KB
14
// severe a given issue is) any item with a missing/non-string id or a duplicate of an id
15 // already seen. Duplicate ids are dropped from the returned list entirely, never silently
16 // treated as "one occurrence satisfies both".
17 function normalizeIds ( items , { onMissing , onDuplicate }) {
18 const ids = [];
19 const seen = new Set ();
20 for ( const item of items) {
21 const id = item && item.id;
22 if ( ! id || typeof id !== 'string' ) {
23 onMissing (item);
24 continue ;
25 }
26 if (seen. has (id)) {
27 onDuplicate (id);
28 continue ;
29 }
30 seen. add (id);
31 ids. push (id);
32 }
33 return ids;
34 }
35
36 // A plan with no genuinely usable `steps` array (missing entirely, not an array, or the
37 // plan itself isn't an object) can never be treated as "zero requirements" — that would let
38 // a malformed plan vacuously satisfy an empty receipt. Reject it outright instead.
39 function validatePlanShape ( plan ) {
40 if ( ! plan || typeof plan !== 'object' || ! Array. isArray (plan.steps)) {
41 return { ok: false , reasons: [ 'plan_missing_or_invalid' ], stepIds: [] };
42 }
43 const reasons = [];
44 if (plan.schemaVersion !== SCHEMA_VERSION ) reasons. push ( 'plan_schema_version_mismatch' );
45 const stepIds = normalizeIds (plan.steps, {
46 onMissing : () => reasons. push ( 'plan_step_missing_id' ),
47 onDuplicate : ( id ) => reasons. push ( `plan_duplicate_step_id:${ id }` ),
48 });
49 return { ok: reasons. length === 0 , reasons, stepIds };
50 }
51
52 function validateSetupVerification ({ verification , plan , planDigest }) {
53 if ( ! verification || typeof verification !== 'object' ) {
54 return { ok: false , reasons: [ 'missing_or_invalid_verification' ] };
55 }
56
57 const reasons = [];
58
59 if (verification.schemaVersion !== SCHEMA_VERSION ) {
60 reasons. push ( 'schema_version_mismatch' );
61 }
62 if ( ! Array. isArray (verification.requirements)) {
63 return { ok: false , reasons: [ ... reasons, 'missing_requirements_array' ] };
64 }
65
66 const planShape = validatePlanShape (plan);
67 if (planShape.reasons. includes ( 'plan_missing_or_invalid' )) {
68 // No usable plan to compare coverage against at all — never fall back to "nothing was
69 // required, so an empty receipt counts as full coverage".
70 return { ok: false , reasons: [ ... reasons, ... planShape.reasons] };
71 }
72 reasons. push ( ... planShape.reasons);
73
74 const nonPassed = verification.requirements. filter (( requirement ) => ! requirement || requirement.status !== 'passed' );
75 for ( const requirement of nonPassed) {
76 reasons. push ( `non_passed_requirement:${ ( requirement && requirement . id ) || 'unknown'}` );
77 }
78
79 const verifiedIds = normalizeIds (verification.requirements, {
80 onMissing : () => reasons. push ( 'verification_requirement_missing_id' ),
81 onDuplicate : ( id ) => reasons. push ( `duplicate_verification_requirement:${ id }` ),
82 });
83
84 const planIdSet = new Set (planShape.stepIds);
85 const verifiedIdSet = new Set (verifiedIds);
86 for ( const id of planIdSet) {
87 if ( ! verifiedIdSet. has (id)) reasons. push ( `missing_requirement:${ id }` );
88 }
89 for ( const id of verifiedIdSet) {
90 if ( ! planIdSet. has (id)) reasons. push ( `unexpected_requirement:${ id }` );
91 }
92
93 if ( ! planDigest) {
94 reasons. push ( 'plan_digest_unavailable' );
95 } else if (verification.planDigest !== planDigest) {
96 reasons. push ( 'plan_digest_mismatch' );
97 }
98
99 return { ok: reasons. length === 0 , reasons };
100 }
101
102 module . exports = { SCHEMA_VERSION, validatePlanShape, validateSetupVerification };