@@ -21,37 +21,42 @@ function hasData(pathData) {
2121 return Object . keys ( pathData ) . length > 0 ;
2222}
2323
24- function filterPathDataForEnvironment ( pathData , environment ) {
25- const methods = Object . entries ( pathData ) . filter ( isHTTPMethod ) ;
26- const methodsForEnvironment = methods . filter ( ( [ _ , metadata ] ) =>
27- isAvailableInEnvironment ( metadata , environment )
24+ function filterMethodsForEnvironment ( pathData , environment ) {
25+ return Object . fromEntries (
26+ Object . entries ( pathData )
27+ . filter ( isHTTPMethod )
28+ . filter ( ( [ _ , metadata ] ) =>
29+ isAvailableInEnvironment ( metadata , environment )
30+ )
2831 ) ;
29- const methodsChanged = methods . length != methodsForEnvironment . length ;
32+ }
3033
31- if ( methodsForEnvironment . length == 0 ) {
32- // when there are no available methods, drop all other metadata except $ref,
33- // which will be cleaned up later
34- const otherMetadata = Object . entries ( pathData ) . filter (
35- ( d ) => ! isHTTPMethod ( d )
36- ) ;
37- const refsOnly = otherMetadata . filter ( ( m ) => m [ 0 ] === "$ref" ) ;
38- const otherMetadataChanged = otherMetadata . length != refsOnly . length ;
34+ function otherMetadata ( pathData ) {
35+ return Object . fromEntries (
36+ Object . entries ( pathData ) . filter ( ( d ) => ! isHTTPMethod ( d ) )
37+ ) ;
38+ }
3939
40- return [
41- Object . fromEntries ( refsOnly ) ,
42- methodsChanged || otherMetadataChanged ,
43- ] ;
44- }
40+ function refsOnly ( metadata ) {
41+ return Object . fromEntries (
42+ Object . entries ( metadata ) . filter ( ( [ key ] ) => key === "$ref" )
43+ ) ;
44+ }
4545
46- // when there are available methods, return all other metadata
47- const otherMetadata = Object . fromEntries (
48- Object . entries ( pathData ) . filter ( ( d ) => ! isHTTPMethod ( d ) )
46+ function filterPathDataForEnvironment ( pathData , environment ) {
47+ const methodsForEnvironment = filterMethodsForEnvironment (
48+ pathData ,
49+ environment
4950 ) ;
5051
51- return [
52- { ...Object . fromEntries ( methodsForEnvironment ) , ...otherMetadata } ,
53- methodsChanged ,
54- ] ;
52+ if ( Object . keys ( methodsForEnvironment ) . length === 0 ) {
53+ // when there are no available methods, drop all other metadata except
54+ // $ref, which will be cleaned up later
55+ return refsOnly ( otherMetadata ( pathData ) ) ;
56+ }
57+
58+ // when there are available methods, return all other metadata too
59+ return { ...methodsForEnvironment , ...otherMetadata ( pathData ) } ;
5560}
5661
5762// we need to escape routes to match spec refs
@@ -62,16 +67,14 @@ function escapeRoute(route) {
6267
6368function filterPaths ( paths , environment ) {
6469 const filtered = { } ;
65- let pathsChanged = false ;
6670 const removedRoutes = [ ] ;
6771
6872 if ( paths ) {
69- for ( const [ route , metadata ] of Object . entries ( paths ) ) {
70- const [ filteredPathData , changed ] = filterPathDataForEnvironment (
71- metadata ,
73+ for ( const [ route , pathData ] of Object . entries ( paths ) ) {
74+ const filteredPathData = filterPathDataForEnvironment (
75+ pathData ,
7276 environment
7377 ) ;
74- pathsChanged = pathsChanged || changed ;
7578
7679 if ( hasData ( filteredPathData ) ) {
7780 filtered [ route ] = filteredPathData ;
@@ -81,31 +84,21 @@ function filterPaths(paths, environment) {
8184 }
8285 }
8386
84- return [ filtered , pathsChanged , removedRoutes ] ;
87+ return [ filtered , removedRoutes ] ;
8588}
8689
87- function pruneRefs ( spec , allRemovedRoutes ) {
88- const pruned = { } ;
89- let changed = false ;
90-
91- if ( spec . paths ) {
92- for ( const [ route , pathData ] of Object . entries ( spec . paths ) ) {
93- if (
94- Object . hasOwn ( pathData , "$ref" ) &&
95- allRemovedRoutes . has ( pathData [ "$ref" ] )
96- ) {
97- // Drop refs to removed routes
98- changed = true ;
99- continue ;
100- } else {
101- pruned [ route ] = pathData ;
102- }
103- }
104- } else {
105- return [ { } , false ] ;
106- }
90+ function isDanglingRef ( pathData , allRemovedRoutes ) {
91+ return (
92+ Object . hasOwn ( pathData , "$ref" ) && allRemovedRoutes . has ( pathData [ "$ref" ] )
93+ ) ;
94+ }
10795
108- return [ pruned , changed ] ;
96+ function pruneRefs ( paths , allRemovedRoutes ) {
97+ return Object . fromEntries (
98+ Object . entries ( paths ) . filter (
99+ ( [ , pathData ] ) => ! isDanglingRef ( pathData , allRemovedRoutes )
100+ )
101+ ) ;
109102}
110103
111104// js-yaml drops comments on load/dump, so we should capture the leading
@@ -140,9 +133,13 @@ function getYamlFiles(specDir) {
140133}
141134
142135function writeFile ( filePath , fileData ) {
143- if ( fileData . shouldWrite ) {
144- fs . writeFileSync ( filePath , fileData . header + yaml . dump ( fileData . spec ) ) ;
145- }
136+ fs . writeFileSync ( filePath , fileData . header + yaml . dump ( fileData . spec ) ) ;
137+ }
138+
139+ // compare against the original paths to know whether a file needs rewriting,
140+ // instead of threading a "changed" flag through every filtering step
141+ function pathsChanged ( before , after ) {
142+ return JSON . stringify ( before ?? { } ) !== JSON . stringify ( after ) ;
146143}
147144
148145function filterByAvailability ( specDir , environment ) {
@@ -151,9 +148,11 @@ function filterByAvailability(specDir, environment) {
151148 const mapping = { } ;
152149 const allRemovedRoutes = new Set ( ) ;
153150 for ( const file of files ) {
151+ const originalPaths = file . spec . paths ;
152+
154153 // filter methods by x-availability
155- const [ filteredPaths , shouldWrite , removedRoutes ] = filterPaths (
156- file . spec . paths ,
154+ const [ filteredPaths , removedRoutes ] = filterPaths (
155+ originalPaths ,
157156 environment
158157 ) ;
159158 file . spec . paths = filteredPaths ;
@@ -168,24 +167,21 @@ function filterByAvailability(specDir, environment) {
168167 mapping [ file . path ] = {
169168 spec : file . spec ,
170169 header : file . header ,
171- shouldWrite ,
170+ originalPaths ,
172171 } ;
173172 }
174173
175174 // prune dangling refs
176- for ( const [ filePath , fileData ] of Object . entries ( mapping ) ) {
177- const [ prunedPaths , changed ] = pruneRefs ( fileData . spec , allRemovedRoutes ) ;
178-
179- if ( changed ) {
180- mapping [ filePath ] . spec . paths = prunedPaths ;
181- fileData . shouldWrite = true ;
182- }
175+ for ( const fileData of Object . values ( mapping ) ) {
176+ fileData . spec . paths = pruneRefs ( fileData . spec . paths , allRemovedRoutes ) ;
183177 }
184178
185- // write files with updates
186- Object . entries ( mapping ) . forEach ( ( [ filePath , fileData ] ) =>
187- writeFile ( filePath , fileData )
188- ) ;
179+ // write files whose paths actually changed
180+ Object . entries ( mapping ) . forEach ( ( [ filePath , fileData ] ) => {
181+ if ( pathsChanged ( fileData . originalPaths , fileData . spec . paths ) ) {
182+ writeFile ( filePath , fileData ) ;
183+ }
184+ } ) ;
189185}
190186
191187module . exports = {
@@ -196,4 +192,5 @@ module.exports = {
196192 extractHeaderComments,
197193 escapeRoute,
198194 pruneRefs,
195+ pathsChanged,
199196} ;
0 commit comments