@@ -87,11 +87,20 @@ function reportCannotResolvedObject(context: RuleContext) {
8787 } ) ;
8888}
8989
90+ type SchemaKind = "$schema" | "catalog" | "options" ;
91+ const SCHEMA_KINDS : SchemaKind [ ] = [ "$schema" , "options" , "catalog" ] ;
92+
9093/** Get mergeSchemas option */
9194function parseMergeSchemasOption (
9295 option : boolean | string [ ] | undefined ,
93- ) : string [ ] | null {
94- return option === true ? [ "$schema" , "catalog" , "options" ] : option || null ;
96+ ) : SchemaKind [ ] | null {
97+ return option === true
98+ ? SCHEMA_KINDS
99+ : Array . isArray ( option )
100+ ? [ ...( option as SchemaKind [ ] ) ] . sort (
101+ ( a , b ) => SCHEMA_KINDS . indexOf ( a ) - SCHEMA_KINDS . indexOf ( b ) ,
102+ )
103+ : null ;
95104}
96105
97106export default createRule ( "no-invalid" , {
@@ -137,6 +146,8 @@ export default createRule("no-invalid", {
137146 type : "string" ,
138147 enum : [ "$schema" , "catalog" , "options" ] ,
139148 } ,
149+ minItems : 2 ,
150+ uniqueItems : true ,
140151 } ,
141152 ] ,
142153 } ,
@@ -156,6 +167,9 @@ export default createRule("no-invalid", {
156167 : filename ;
157168
158169 const validator = createValidator ( context , relativeFilename ) ;
170+ if ( ! validator ) {
171+ return { } ;
172+ }
159173
160174 let existsExports = false ;
161175 const sourceCode = context . getSourceCode ( ) ;
@@ -167,7 +181,7 @@ export default createRule("no-invalid", {
167181 data : unknown ,
168182 resolveLoc : ( error : ValidateError ) => JSONAST . SourceLocation | null ,
169183 ) {
170- const errors = validator ( data ) ;
184+ const errors = validator ! ( data ) ;
171185 for ( const error of errors ) {
172186 const loc = resolveLoc ( error ) ;
173187
@@ -463,31 +477,80 @@ export default createRule("no-invalid", {
463477 context . options [ 0 ] ?. mergeSchemas ,
464478 ) ;
465479
466- const validators : Validator [ ] = [ ] ;
467- if ( mergeSchemas ) {
468- if ( mergeSchemas . includes ( "$schema" ) ) {
469- validators . push ( ...( get$SchemaValidators ( context ) || [ ] ) ) ;
480+ const validatorsCtx = createValidatorsContext ( context , filename ) ;
481+ if ( mergeSchemas && mergeSchemas . some ( ( kind ) => validatorsCtx [ kind ] ) ) {
482+ const validators : Validator [ ] = [ ] ;
483+ for ( const kind of mergeSchemas ) {
484+ const v = validatorsCtx [ kind ] ;
485+ if ( v ) validators . push ( ...v ) ;
470486 }
471- if ( mergeSchemas . includes ( "options" ) ) {
472- validators . push ( ...( getOptionsValidators ( context , filename ) || [ ] ) ) ;
473- }
474- if ( mergeSchemas . includes ( "catalog" ) ) {
475- validators . push ( ...( getCatalogValidators ( context , filename ) || [ ] ) ) ;
487+ return margeValidators ( validators ) ;
488+ }
489+
490+ const validators =
491+ validatorsCtx . $schema || validatorsCtx . options || validatorsCtx . catalog ;
492+ if ( ! validators ) {
493+ return null ;
494+ }
495+ return margeValidators ( validators ) ;
496+
497+ /** Marge validators */
498+ function margeValidators ( validators : Validator [ ] ) {
499+ return ( data : unknown ) =>
500+ validators . reduce (
501+ ( errors , validator ) => [ ...errors , ...validator ( data ) ] ,
502+ [ ] as ValidateError [ ] ,
503+ ) ;
504+ }
505+ }
506+
507+ /** Creates validators context */
508+ function createValidatorsContext ( context : RuleContext , filename : string ) {
509+ type Cache = { validators : Validator [ ] | null } ;
510+ let $schema : Cache | null = null ;
511+ let options : Cache | null = null ;
512+ let catalog : Cache | null = null ;
513+
514+ /**
515+ * Get a validator. Returns the value of the cache if there is one.
516+ * If there is no cache, cache and return the value obtained from the supplier function
517+ */
518+ function get (
519+ cache : Cache | null ,
520+ setCache : ( c : Cache ) => void ,
521+ supplier : ( ) => Validator [ ] | null ,
522+ ) {
523+ if ( cache ) {
524+ return cache . validators ;
476525 }
477- } else {
478- validators . push (
479- ...( get$SchemaValidators ( context ) ||
480- getOptionsValidators ( context , filename ) ||
481- getCatalogValidators ( context , filename ) ||
482- [ ] ) ,
483- ) ;
526+ const v = supplier ( ) ;
527+ setCache ( { validators : v } ) ;
528+ return v ;
484529 }
485530
486- return ( data : unknown ) =>
487- validators . reduce (
488- ( errors , validator ) => [ ...errors , ...validator ( data ) ] ,
489- [ ] as ValidateError [ ] ,
490- ) ;
531+ return {
532+ get $schema ( ) {
533+ return get (
534+ $schema ,
535+ ( c ) => ( $schema = c ) ,
536+ ( ) => get$SchemaValidators ( context ) ,
537+ ) ;
538+ } ,
539+ get options ( ) {
540+ return get (
541+ options ,
542+ ( c ) => ( options = c ) ,
543+ ( ) => getOptionsValidators ( context , filename ) ,
544+ ) ;
545+ } ,
546+ get catalog ( ) {
547+ return get (
548+ catalog ,
549+ ( c ) => ( catalog = c ) ,
550+ ( ) => getCatalogValidators ( context , filename ) ,
551+ ) ;
552+ } ,
553+ } ;
491554 }
492555 } ,
493556} ) ;
0 commit comments