@@ -11,6 +11,7 @@ class ConfigFilesHelper
1111 protected string $ packageRoot ;
1212 protected bool $ publishedIsFile = false ;
1313 protected bool $ packageIsFile = false ;
14+ protected ?string $ defaultConfigFile = null ;
1415 private array $ configFiles = [];
1516
1617 public function __construct (
@@ -24,6 +25,11 @@ public function __construct(
2425 $ this ->initializeConfigFiles ();
2526 }
2627
28+ public function setDefaultConfigFile (string $ configFile ): void
29+ {
30+ $ this ->defaultConfigFile = $ configFile ;
31+ }
32+
2733 protected function initializeConfigFiles (): void
2834 {
2935 if ($ this ->configFiles !== []) {
@@ -60,13 +66,139 @@ public function readPublishedFile(string $path): ?string
6066 return $ this ->context ->readFile ($ this ->context ->relativePath ($ absolutePath ));
6167 }
6268
69+ public function configKeyHasValue (string $ key , mixed $ expectedValue , ?string $ path = null ): bool
70+ {
71+ $ target = $ this ->resolveConfigFileArgument ($ path );
72+
73+ if ($ target === null ) {
74+ return false ;
75+ }
76+
77+ $ config = $ this ->loadPublishedConfig ($ target );
78+
79+ if ($ config === null ) {
80+ return false ;
81+ }
82+
83+ $ current = $ this ->getConfigValueByKey ($ config , $ key );
84+
85+ if ($ current === null ) {
86+ return false ;
87+ }
88+
89+ if (is_array ($ current )) {
90+ if (is_array ($ expectedValue )) {
91+ foreach ($ expectedValue as $ value ) {
92+ if (! in_array ($ value , $ current , true )) {
93+ return false ;
94+ }
95+ }
96+
97+ return true ;
98+ }
99+
100+ return in_array ($ expectedValue , $ current , true );
101+ }
102+
103+ return $ current === $ expectedValue ;
104+ }
105+
63106 public function writePublishedFile (string $ path , string $ contents ): bool
64107 {
65108 $ absolutePath = $ this ->resolvePublishedPath ($ path );
66109
67110 return $ this ->context ->writeFile ($ this ->context ->relativePath ($ absolutePath ), $ contents );
68111 }
69112
113+ public function updateConfigKeyValue (string $ key , mixed $ newValue , ?string $ path = null ): bool
114+ {
115+ $ target = $ this ->resolveConfigFileArgument ($ path );
116+
117+ if ($ target === null ) {
118+ return false ;
119+ }
120+
121+ if (is_string ($ newValue ) && $ this ->configKeyHasValue ($ key , $ newValue , $ target )) {
122+ return false ;
123+ }
124+
125+ $ contents = $ this ->readPublishedFile ($ target );
126+
127+ if ($ contents === null ) {
128+ return false ;
129+ }
130+
131+ $ changed = false ;
132+ $ pattern = '/(?P<prefix>(["\"]) ' .preg_quote ($ key , '/ ' ).'\2\s*=>\s*)(?P<value>(?:[^,\r\n\/]|\/(?!\/))+)(?P<suffix>,?[ \t]*(?:\/\/[^\r\n]*)?)/ ' ;
133+
134+ $ updated = preg_replace_callback (
135+ $ pattern ,
136+ function (array $ matches ) use ($ newValue , &$ changed ) {
137+ $ existing = trim ($ matches ['value ' ]);
138+ $ quote = $ existing [0 ] ?? null ;
139+
140+ if (is_string ($ newValue )) {
141+ $ preferredQuote = ($ quote === "' " || $ quote === '" ' ) ? $ quote : "' " ;
142+ $ replacement = $ this ->exportStringValue ($ newValue , $ preferredQuote );
143+ } else {
144+ $ replacement = $ this ->exportValue ($ newValue );
145+ }
146+
147+ if ($ replacement === $ existing ) {
148+ return $ matches [0 ];
149+ }
150+
151+ $ changed = true ;
152+
153+ return $ matches ['prefix ' ].$ replacement .$ matches ['suffix ' ];
154+ },
155+ $ contents ,
156+ 1
157+ );
158+
159+ if ($ updated === null || ! $ changed ) {
160+ return false ;
161+ }
162+
163+ return $ this ->writePublishedFile ($ target , $ updated );
164+ }
165+
166+ public function commentOutConfigValue (string $ valueExpression , ?string $ path = null ): bool
167+ {
168+ $ target = $ this ->resolveConfigFileArgument ($ path );
169+
170+ if ($ target === null ) {
171+ return false ;
172+ }
173+
174+ $ contents = $ this ->readPublishedFile ($ target );
175+
176+ if ($ contents === null ) {
177+ return false ;
178+ }
179+
180+ $ pattern = '~^[\t ]* ' .preg_quote ($ valueExpression , '~ ' ).'([\t ]*,?[\t ]*)\r?$~m ' ;
181+
182+ $ updated = preg_replace_callback (
183+ $ pattern ,
184+ function (array $ matches ) use ($ valueExpression ) {
185+ $ position = strpos ($ matches [0 ], $ valueExpression );
186+ $ indentation = $ position === false ? '' : substr ($ matches [0 ], 0 , $ position );
187+
188+ return $ indentation .'// ' .$ valueExpression .$ matches [1 ];
189+ },
190+ $ contents ,
191+ 1 ,
192+ $ count
193+ );
194+
195+ if ($ updated === null || $ count === 0 ) {
196+ return false ;
197+ }
198+
199+ return $ this ->writePublishedFile ($ target , $ updated );
200+ }
201+
70202 public function loadPublishedConfig (string $ path ): ?array
71203 {
72204 return $ this ->loadConfigArray ($ this ->resolvePublishedPath ($ path ));
@@ -824,6 +956,49 @@ protected function normalizePath(string $path): string
824956 return rtrim (str_replace ('\\' , '/ ' , $ path ), '/ ' );
825957 }
826958
959+ protected function resolveConfigFileArgument (?string $ path ): ?string
960+ {
961+ if ($ path !== null ) {
962+ return $ path ;
963+ }
964+
965+ return $ this ->defaultConfigFile ;
966+ }
967+
968+ protected function getConfigValueByKey (array $ config , string $ key ): mixed
969+ {
970+ if ($ key === '' ) {
971+ return null ;
972+ }
973+
974+ $ segments = explode ('. ' , $ key );
975+ $ current = $ config ;
976+
977+ foreach ($ segments as $ segment ) {
978+ if (! is_array ($ current ) || ! array_key_exists ($ segment , $ current )) {
979+ return null ;
980+ }
981+
982+ $ current = $ current [$ segment ];
983+ }
984+
985+ return $ current ;
986+ }
987+
988+ protected function exportStringValue (string $ value , string $ quote ): string
989+ {
990+ if ($ quote === '" ' ) {
991+ return '" ' .addcslashes ($ value , "\\\"$ " ).'" ' ;
992+ }
993+
994+ return '\'' . addcslashes ($ value , "\\' " ) . '\'' ;
995+ }
996+
997+ protected function exportValue (mixed $ value ): string
998+ {
999+ return var_export ($ value , true );
1000+ }
1001+
8271002 protected function calculateMissingKeys (array $ packageKeys , array $ publishedKeys ): array
8281003 {
8291004 $ missingKeys = array_values (array_diff ($ packageKeys , $ publishedKeys ));
0 commit comments