@@ -7,102 +7,39 @@ import ajvErrors from "ajv-errors";
77import { loadJsonStrict } from "./load-json-strict.mjs" ;
88
99const ROOT_DIR = process . cwd ( ) ;
10- const CURRENT_VERSION = ' 1.1.0' ;
11- const EXAMPLES_ROOT = path . join ( ROOT_DIR , ' examples' , `v${ CURRENT_VERSION } ` , ' commercial' ) ;
12- const SCHEMAS_ROOT = path . join ( ROOT_DIR , ' schemas' , `v${ CURRENT_VERSION } ` , ' commercial' ) ;
13- const VERBS = [ ' authorize' , ' checkout' , ' purchase' , ' ship' , ' verify' ] ;
10+ const CURRENT_VERSION = " 1.1.0" ;
11+ const EXAMPLES_ROOT = path . join ( ROOT_DIR , " examples" , `v${ CURRENT_VERSION } ` , " commercial" ) ;
12+ const SCHEMAS_ROOT = path . join ( ROOT_DIR , " schemas" , `v${ CURRENT_VERSION } ` , " commercial" ) ;
13+ const VERBS = [ " authorize" , " checkout" , " purchase" , " ship" , " verify" ] ;
1414
1515const ajv = new Ajv2020 ( { strict : true , allErrors : true , allowUnionTypes : false } ) ;
1616addFormats ( ajv ) ;
1717ajvErrors ( ajv ) ;
1818
19- function assertNoDuplicateObjectKeys ( source , filePath ) {
20- const objectKeySets = [ ] ;
21- let inString = false ;
22- let escape = false ;
23-
24- for ( let index = 0 ; index < source . length ; index += 1 ) {
25- const char = source [ index ] ;
26-
27- if ( inString ) {
28- if ( escape ) {
29- escape = false ;
30- continue ;
31- }
32- if ( char === "\\" ) {
33- escape = true ;
34- continue ;
35- }
36- if ( char === '"' ) inString = false ;
37- continue ;
38- }
39-
40- if ( char === '"' ) {
41- let end = index + 1 ;
42- let stringEscape = false ;
43- while ( end < source . length ) {
44- const nextChar = source [ end ] ;
45- if ( stringEscape ) {
46- stringEscape = false ;
47- } else if ( nextChar === "\\" ) {
48- stringEscape = true ;
49- } else if ( nextChar === '"' ) {
50- break ;
51- }
52- end += 1 ;
53- }
54-
55- const raw = source . slice ( index , end + 1 ) ;
56- let cursor = end + 1 ;
57- while ( cursor < source . length && / \s / . test ( source [ cursor ] ) ) cursor += 1 ;
58- if ( cursor < source . length && source [ cursor ] === ':' && objectKeySets . length > 0 ) {
59- const key = JSON . parse ( raw ) ;
60- const currentKeys = objectKeySets [ objectKeySets . length - 1 ] ;
61- if ( currentKeys . has ( key ) ) {
62- throw new Error ( `${ filePath } contains a duplicate JSON object key: ${ key } ` ) ;
63- }
64- currentKeys . add ( key ) ;
65- }
66-
67- index = end ;
68- continue ;
69- }
70-
71- if ( char === '{' ) objectKeySets . push ( new Set ( ) ) ;
72- if ( char === '}' ) objectKeySets . pop ( ) ;
73- }
74- }
75-
76- async function loadJson ( filePath ) {
77- const source = await fs . readFile ( filePath , 'utf8' ) ;
78- assertNoDuplicateObjectKeys ( source , filePath ) ;
79- return JSON . parse ( source ) ;
80- }
81-
8219async function validateVerb ( verb ) {
83- const requestSchema = await loadJson ( path . join ( SCHEMAS_ROOT , verb , `${ verb } .request.schema.json` ) ) ;
84- const receiptSchema = await loadJson ( path . join ( SCHEMAS_ROOT , verb , `${ verb } .receipt.schema.json` ) ) ;
20+ const requestSchema = await loadJsonStrict ( path . join ( SCHEMAS_ROOT , verb , `${ verb } .request.schema.json` ) ) ;
21+ const receiptSchema = await loadJsonStrict ( path . join ( SCHEMAS_ROOT , verb , `${ verb } .receipt.schema.json` ) ) ;
8522 const validateRequest = ajv . compile ( requestSchema ) ;
8623 const validateReceipt = ajv . compile ( receiptSchema ) ;
8724
88- for ( const group of [ ' valid' , ' invalid' ] ) {
25+ for ( const group of [ " valid" , " invalid" ] ) {
8926 const dir = path . join ( EXAMPLES_ROOT , verb , group ) ;
90- const files = ( await fs . readdir ( dir ) ) . filter ( file => file . endsWith ( ' .json' ) ) . sort ( ) ;
91- const requestFiles = files . filter ( file => file . includes ( ' request' ) ) ;
92- const receiptFiles = files . filter ( file => file . includes ( ' receipt' ) ) ;
27+ const files = ( await fs . readdir ( dir ) ) . filter ( ( file ) => file . endsWith ( " .json" ) ) . sort ( ) ;
28+ const requestFiles = files . filter ( ( file ) => file . includes ( " request" ) ) ;
29+ const receiptFiles = files . filter ( ( file ) => file . includes ( " receipt" ) ) ;
9330 if ( requestFiles . length === 0 || receiptFiles . length === 0 ) {
9431 throw new Error ( `${ verb } ${ group } examples must include both request and receipt cases` ) ;
9532 }
9633 for ( const file of files ) {
97- const data = await loadJson ( path . join ( dir , file ) ) ;
98- const validate = file . includes ( ' request' ) ? validateRequest : validateReceipt ;
34+ const data = await loadJsonStrict ( path . join ( dir , file ) ) ;
35+ const validate = file . includes ( " request" ) ? validateRequest : validateReceipt ;
9936 const ok = validate ( data ) ;
100- if ( group === ' valid' && ! ok ) throw new Error ( `${ file } should be valid: ${ ajv . errorsText ( validate . errors ) } ` ) ;
101- if ( group === ' invalid' && ok ) throw new Error ( `${ file } should be invalid` ) ;
37+ if ( group === " valid" && ! ok ) throw new Error ( `${ file } should be valid: ${ ajv . errorsText ( validate . errors ) } ` ) ;
38+ if ( group === " invalid" && ok ) throw new Error ( `${ file } should be invalid` ) ;
10239 }
10340 }
10441 console . log ( `✅ ${ verb } examples validated.` ) ;
10542}
10643
10744for ( const verb of VERBS ) await validateVerb ( verb ) ;
108- console . log ( ' ✅ All current-line examples validated.' ) ;
45+ console . log ( " ✅ All current-line examples validated." ) ;
0 commit comments