@@ -12,19 +12,14 @@ import {
1212import { isAbsoluteUrl , isExternalValue , isRef , refBaseName } from './ref-utils.js' ;
1313import { initRules } from './config/rules.js' ;
1414import { reportUnresolvedRef } from './rules/no-unresolved-refs.js' ;
15- import { dequal , isEmptyObject , isPlainObject , isTruthy } from './utils.js' ;
15+ import { dequal , isPlainObject , isTruthy } from './utils.js' ;
1616import { RemoveUnusedComponents as RemoveUnusedComponentsOas2 } from './decorators/oas2/remove-unused-components.js' ;
1717import { RemoveUnusedComponents as RemoveUnusedComponentsOas3 } from './decorators/oas3/remove-unused-components.js' ;
1818import { NormalizedConfigTypes } from './types/redocly-yaml.js' ;
19- import {
20- mergeExtends ,
21- resolvePreset ,
22- type ResolvedGovernanceConfig ,
23- type Config ,
24- } from './config/index.js' ;
19+ import { mergeExtends , resolvePreset , type Config } from './config/index.js' ;
2520import path from 'path' ;
26- import { defaultPlugin } from './config/builtIn.js' ;
2721
22+ import type { Plugin } from './config/types.js' ;
2823import type { Location } from './ref-utils.js' ;
2924import type { Oas3Visitor , Oas2Visitor } from './visitors.js' ;
3025import type { NormalizedNodeType , NodeType } from './types/index.js' ;
@@ -47,15 +42,15 @@ export type CoreBundleOptions = {
4742 keepUrlRefs ?: boolean ;
4843} ;
4944
50- function bundleExtends ( node : any , ctx : UserContext ) {
45+ function bundleExtends ( { node, ctx , plugins } : { node : any ; ctx : UserContext ; plugins : Plugin [ ] } ) {
5146 if ( ! node . extends ) {
5247 return node ;
5348 }
5449
55- const resolvedExtends = node . extends
50+ const resolvedExtends = ( node . extends || [ ] )
5651 . map ( ( presetItem : string ) => {
5752 if ( ! isAbsoluteUrl ( presetItem ) && ! path . extname ( presetItem ) ) {
58- return resolvePreset ( presetItem , [ defaultPlugin ] ) ; // TODO: implement plugins
53+ return resolvePreset ( presetItem , plugins ) ;
5954 }
6055
6156 const resolvedRef = ctx . resolve ( { $ref : presetItem } ) ;
@@ -66,83 +61,139 @@ function bundleExtends(node: any, ctx: UserContext) {
6661 } )
6762 . filter ( isTruthy ) ;
6863
69- return removeEmptyRules (
70- mergeExtends ( [
71- ...resolvedExtends . map ( ( nested : any ) => bundleExtends ( nested , ctx ) ) ,
72- { ...node , extends : undefined } ,
73- ] )
74- ) ;
64+ return mergeExtends ( [
65+ ...resolvedExtends . map ( ( nested : any ) => bundleExtends ( { node : nested , ctx, plugins } ) ) ,
66+ { ...node , extends : undefined } ,
67+ ] ) ;
7568}
7669
77- const bundleVisitor = ( ) => {
78- const collectedPlugins : string [ ] = [ ] ;
70+ function configBundleVisitor ( plugins : Plugin [ ] ) {
71+ // let rootConfig: RawUniversalConfig | undefined;
72+
73+ return normalizeVisitors (
74+ [
75+ {
76+ severity : 'error' ,
77+ ruleId : 'configBundler' ,
78+ visitor : {
79+ ref : {
80+ leave ( node : OasRef , ctx : UserContext , resolved : ResolveResult < any > ) {
81+ replaceRef ( node , resolved , ctx ) ;
82+ } ,
83+ } ,
84+ ConfigGovernance : {
85+ leave ( node : any , ctx : UserContext ) {
86+ handleNode ( node , ctx ) ;
87+ } ,
88+ } ,
89+ ConfigApisProperties : {
90+ leave ( node : any , ctx : UserContext ) {
91+ // ignore extends from root config if defined in the current node
92+ handleNode ( node , ctx ) ;
93+ } ,
94+ } ,
95+ 'rootRedoclyConfigSchema.scorecard.levels_items' : {
96+ leave ( node : any , ctx : UserContext ) {
97+ handleNode ( node , ctx ) ;
98+ } ,
99+ } ,
100+ ConfigRoot : {
101+ leave ( node : any , ctx : UserContext ) {
102+ if ( node . extends ) {
103+ const bundled = bundleExtends ( { node, ctx, plugins } ) ;
104+ Object . assign ( node , bundled ) ;
105+ delete node . extends ;
106+ }
107+ } ,
108+ } ,
109+ } ,
110+ } ,
111+ ] ,
112+ NormalizedConfigTypes
113+ ) ;
79114
80115 function handleNode ( node : any , ctx : UserContext ) {
81116 if ( node . extends ) {
82- const bundled = bundleExtends ( node , ctx ) ;
117+ const bundled = bundleExtends ( { node, ctx, plugins } ) ;
83118 Object . assign ( node , bundled ) ;
84119 delete node . extends ;
85- collectedPlugins . push ( ...( bundled . plugins as unknown as any [ ] ) ) ;
86- delete bundled . plugins ;
87120 }
88121 }
122+ }
89123
124+ function collectPluginsVisitor ( ) {
125+ const plugins : ( string | Plugin ) [ ] = [ ] ;
90126 return normalizeVisitors (
91127 [
92128 {
93129 severity : 'error' ,
94130 ruleId : 'configBundler' ,
95131 visitor : {
96- ref : {
97- leave ( node : OasRef , ctx : UserContext , resolved : ResolveResult < any > ) {
98- replaceRef ( node , resolved , ctx ) ;
99- } ,
100- } ,
132+ ref : { } ,
101133 ConfigGovernance : {
102134 leave ( node : any , ctx : UserContext ) {
103135 handleNode ( node , ctx ) ;
104136 } ,
105137 } ,
106- ConfigStyleguideList : {
138+ ConfigApisProperties : {
107139 leave ( node : any , ctx : UserContext ) {
108140 handleNode ( node , ctx ) ;
109141 } ,
110- 'rootRedoclyConfigSchema.scorecard.levels_items' : {
111- leave ( node : any , ctx : UserContext ) {
112- handleNode ( node , ctx ) ;
113- } ,
142+ } ,
143+ 'rootRedoclyConfigSchema.scorecard.levels_items' : {
144+ leave ( node : any , ctx : UserContext ) {
145+ handleNode ( node , ctx ) ;
114146 } ,
115-
116- ConfigRoot : {
117- leave ( node : any , ctx : UserContext ) {
118- if ( node . extends ) {
119- const bundled = bundleExtends ( node , ctx ) ;
120- Object . assign ( node , bundled ) ;
121- node . plugins = Array . from (
122- new Set ( [ ...( node . plugins || [ ] ) , ...collectedPlugins ] )
123- ) ;
124- delete node . extends ;
125- }
126- } ,
147+ } ,
148+ ConfigRoot : {
149+ leave ( node : any ) {
150+ if ( ( Array . isArray ( node . plugins ) && node . plugins . length > 0 ) || plugins . length > 0 ) {
151+ node . plugins = [ ...( node . plugins || [ ] ) , ...plugins ] ;
152+ }
127153 } ,
128154 } ,
129155 } ,
130156 } ,
131157 ] ,
132158 NormalizedConfigTypes
133159 ) ;
134- } ;
135160
136- function removeEmptyRules ( config : ResolvedGovernanceConfig ) {
137- // TODO: convert strings to constants
138- return Object . fromEntries (
139- Object . entries ( config ) . filter (
140- ( [ key , value ] ) => ! isEmptyObject ( value ) && key !== 'pluginPaths' && key !== 'extendPaths'
141- )
142- ) ;
161+ function handleNode ( node : any , ctx : UserContext ) {
162+ if ( Array . isArray ( node . plugins ) ) {
163+ plugins . push (
164+ ...node . plugins . map ( ( p : string ) =>
165+ typeof p === 'string' ? path . resolve ( path . dirname ( ctx . location . source . absoluteRef ) , p ) : p
166+ )
167+ ) ;
168+ delete node . plugins ;
169+ }
170+ }
143171}
144172
145- export async function bundleConfig ( document : Document , resolvedRefMap : ResolvedRefMap ) {
173+ export function collectConfigPlugins ( document : Document , resolvedRefMap : ResolvedRefMap ) {
174+ const ctx : BundleContext = {
175+ problems : [ ] ,
176+ oasVersion : SpecVersion . OAS3_0 ,
177+ refTypes : new Map < string , NormalizedNodeType > ( ) ,
178+ visitorsData : { } ,
179+ } ;
180+
181+ walkDocument ( {
182+ document,
183+ rootType : NormalizedConfigTypes . ConfigRoot ,
184+ normalizedVisitors : collectPluginsVisitor ( ) ,
185+ resolvedRefMap,
186+ ctx,
187+ } ) ;
188+
189+ return document . parsed ?? { } ;
190+ }
191+
192+ export function bundleConfig (
193+ document : Document ,
194+ resolvedRefMap : ResolvedRefMap ,
195+ plugins : Plugin [ ]
196+ ) {
146197 const ctx : BundleContext = {
147198 problems : [ ] ,
148199 oasVersion : SpecVersion . OAS3_0 ,
@@ -153,7 +204,7 @@ export async function bundleConfig(document: Document, resolvedRefMap: ResolvedR
153204 walkDocument ( {
154205 document,
155206 rootType : NormalizedConfigTypes . ConfigRoot ,
156- normalizedVisitors : bundleVisitor ( ) ,
207+ normalizedVisitors : configBundleVisitor ( plugins ) ,
157208 resolvedRefMap,
158209 ctx,
159210 } ) ;
0 commit comments